1. Introduction

Single-cell sequencing is an emerging technology in the field of immunology and oncology that allows researchers to couple RNA quantification and other modalities, like immune cell receptor profiling at the level of an individual cell. A number of workflows and software packages have been created to process and analyze single-cell transcriptomic data. These packages allow users to take the vast dimensionality of the data generated in single-cell-based experiments and distill the data into novel insights. Unlike the transcriptomic field, there is a lack of options for software that allow for single-cell immune receptor profiling. Enabling users to easily combine RNA and immune profiling, the scRepertoire framework supports use of 10x, single-cell clonal formats and interaction with popular R-based single-cell data pipelines.

scRepertoire is designed to take filter contig outputs from the 10x Genomics Cell Ranger pipeline, process that data to assign clonotype based on two TCR or Ig chains and analyze the clonotype dynamics. The latter can be separated into 1) clonotype-only analysis functions, such as unique clonotypes or clonal space quantification, and 2) interaction with mRNA expression data using Seurat or SingleCellExperiment packages.

References:

Prerequisite: Ensure the All_samples_Merged Seurat object is loaded into your R environment before running the chunks below.

1.1 Load libraries

library(Seurat)
library(SeuratObject)
library(SeuratObject)
library(SeuratData)
library(patchwork)
library(dplyr)
library(ggplot2)
library(tidyverse)
library(rmarkdown)
library(tinytex)
library(grid)
library(cowplot)
library(presto)

#TCR Analysis
library(scRepertoire)
library(SingleCellExperiment)
library(circlize)
library(scales)

1.2 Load Seurat Object

All_samples_Merged
An object of class Seurat 
62900 features across 49305 samples within 6 assays 
Active assay: RNA (36601 features, 0 variable features)
 2 layers present: data, counts
 5 other assays present: ADT, prediction.score.celltype.l1, prediction.score.celltype.l2, prediction.score.celltype.l3, SCT
 5 dimensional reductions calculated: integrated_dr, ref.umap, pca, umap, harmony

1.3. Load contigs

scRepertoire functions using the filtered_contig_annotations.csv output from the 10x Genomics Cell Ranger. This file is located in the ./outs/ directory of the VDJ alignment folder. To generate a list of contigs to use for scRepertoire:

- load the filtered_contig_annotations.csv for each of the samples.

- make a list in the R environment.

2. Combining Contigs into Clones

There are varying definitions of clones in the literature. For the purposes of scRepertoire, we define a clone as cells with shared/trackable complementarity-determining region 3 (CDR3) sequences. Within this definition, one might use amino acid (aa) sequences of one or both chains to define a clone. Alternatively, we could use nucleotide (nt) or the V(D)JC genes (genes) to define a clone. The latter, genes, would be a more permissive definition of “clones,” as multiple amino acid or nucleotide sequences can result from the same gene combination. Another option to define a clone is the use of the V(D)JC and nucleotide sequence (strict). scRepertoire allows for the use of all these definitions of clones and enables users to select both or individual chains to examine.

2.1 Combining Contigs into Clones

exportClones(combined.TCR,
              write.file = TRUE,
              dir = "TCR_analysis-7-11-2025/",
             file.name = "clones.csv")

exportClones(combined.TCR_with_PBMC,
             write.file = TRUE,
             dir = "TCR_analysis-7-11-2025/",
             file.name = "clones_with_PBMC.csv")

head(combined.TCR[[1]])

head(combined.TCR_with_PBMC[[1]])

# Combine all data frames in the list into a single data frame
combined_TCR_df <- do.call(rbind, combined.TCR)

# Write the combined data frame to a CSV file
write.csv(combined_TCR_df, file = "TCR_analysis-7-11-2025/combined_TCR.csv", row.names = FALSE)


# Combine all data frames in the list into a single data frame
combined_TCR_with_PBMC_df <- do.call(rbind, combined.TCR_with_PBMC)

# Write the combined data frame to a CSV file
write.csv(combined_TCR_with_PBMC_df, file = "TCR_analysis-7-11-2025/combined_TCR_with_PBMC.csv", row.names = FALSE)

2.2 Write the fasta file for phylogeny


# Define the FASTA file for alpha chains
alpha_fasta_file <- "TCR_analysis-7-11-2025/Phylogeny/cdr3_alpha_sequences.fasta"

# Open a connection to the file
f <- file(alpha_fasta_file, open = "w")

# Loop through the data frame
for (i in seq_len(nrow(combined_TCR_with_PBMC_df))) {
  if (!is.na(combined_TCR_with_PBMC_df$cdr3_nt1[i])) {
    # Write the header and sequence
    writeLines(paste0(">", combined_TCR_df$sample[i], "_alpha"), f)
    writeLines(combined_TCR_df$cdr3_nt1[i], f)
  }
}

# Close the connection
close(f)

cat("Alpha chain FASTA file created at:", alpha_fasta_file, "\n")
Alpha chain FASTA file created at: TCR_analysis-7-11-2025/Phylogeny/cdr3_alpha_sequences.fasta 
# Define the FASTA file for beta chains
beta_fasta_file <- "TCR_analysis-7-11-2025/Phylogeny/cdr3_beta_sequences.fasta"

# Open a connection to the file
f <- file(beta_fasta_file, open = "w")

# Loop through the data frame
for (i in seq_len(nrow(combined_TCR_with_PBMC_df))) {
  if (!is.na(combined_TCR_with_PBMC_df$cdr3_nt2[i])) {
    # Write the header and sequence
    writeLines(paste0(">", combined_TCR_with_PBMC_df$sample[i], "_beta"), f)
    writeLines(combined_TCR_df$cdr3_nt2[i], f)
  }
}

# Close the connection
close(f)

cat("Beta chain FASTA file created at:", beta_fasta_file, "\n")
Beta chain FASTA file created at: TCR_analysis-7-11-2025/Phylogeny/cdr3_beta_sequences.fasta 

3. Basic Clonal Visualizations

3.1. clonalQuant: Quantifying Unique Clones

#clonalQuant
 clonalQuant(combined.TCR, 
            cloneCall="strict", 
            chain = "both", 
            scale = TRUE)



clonalQuant(combined.TCR_with_PBMC, 
            cloneCall="strict", 
            chain = "both", 
            scale = TRUE)

NA
NA
NA

3.2 clonalAbundance: Distribution of Clones by Size

#clonalAbundance

clonalAbundance(combined.TCR_with_PBMC, 
                cloneCall = "gene",  palette = "Zissou 1",
                scale = FALSE)

  
clonalAbundance(combined.TCR_with_PBMC, 
                cloneCall = "gene", palette = "Zissou 1",
                scale = TRUE)




clonalAbundance(combined.TCR, 
                cloneCall = "gene",  
                scale = FALSE)

 

clonalAbundance(combined.TCR, 
                cloneCall = "gene", 
                scale = TRUE)

3.3 clonalLength: Distribution of Sequence Lengths

#clonalLength
clonalLength(combined.TCR_with_PBMC, 
             cloneCall="nt", 
             chain = "both") 


clonalLength(combined.TCR_with_PBMC, 
             cloneCall="aa", 
             chain = "both") 


clonalLength(combined.TCR, 
             cloneCall="nt", 
             chain = "both") 


clonalLength(combined.TCR, 
             cloneCall="aa", 
             chain = "both") 




#TRA
clonalLength(combined.TCR_with_PBMC, 
             cloneCall="nt", 
             chain = "TRA", 
             scale = TRUE) 


clonalLength(combined.TCR_with_PBMC, 
             cloneCall="aa", 
             chain = "TRA", 
             scale = TRUE) 


clonalLength(combined.TCR, 
             cloneCall="nt", 
             chain = "TRA",  
             scale = TRUE) 


clonalLength(combined.TCR, 
             cloneCall="aa", 
             chain = "TRA", 
             scale = TRUE) 



#TRB
clonalLength(combined.TCR_with_PBMC, 
             cloneCall="nt", 
             chain = "TRB", 
             scale = TRUE) 


clonalLength(combined.TCR_with_PBMC, 
             cloneCall="aa", 
             chain = "TRB", 
             scale = TRUE) 


clonalLength(combined.TCR, 
             cloneCall="nt", 
             chain = "TRB",  
             scale = TRUE) 


clonalLength(combined.TCR, 
             cloneCall="aa", 
             chain = "TRB", 
             scale = TRUE) 

NA
NA

3.5 clonalCompare: Clonal Dynamics Between Categorical Variables

# clonalCompare
clonalCompare(combined.TCR, 
                  top.clones = 10, 
                  samples = c("L1", "L2"), 
                  cloneCall="aa", 
                  graph = "alluvial")


clonalCompare(combined.TCR, 
                  top.clones = 10, 
                  samples = c("L3", "L4"), 
                  cloneCall="aa", 
                  graph = "alluvial")


clonalCompare(combined.TCR, 
                  top.clones = 10, 
                  samples = c("L5", "L6","L7"), 
                  cloneCall="aa", 
                  graph = "alluvial")


clonalCompare(combined.TCR, 
                  top.clones = 10, 
                  samples = c("L5","L6"), 
                  cloneCall="aa", 
                  graph = "alluvial")


clonalCompare(combined.TCR, 
                  top.clones = 10, 
                  samples = c("L5","L7"), 
                  cloneCall="aa", 
                  graph = "alluvial")


clonalCompare(combined.TCR, 
                  top.clones = 10, 
                  samples = c("L6","L7"), 
                  cloneCall="aa", 
                  graph = "alluvial")


clonalCompare(combined.TCR, 
                  top.clones = 10, 
                  samples = c("L1", "L2", "L3", "L4", "L5", "L6", "L7", "PBMC"), 
                  cloneCall="aa", 
                  graph = "alluvial")



clonalCompare(combined.TCR, 
                  top.clones = 10, 
                  samples = c("L1", "L2", "L3", "L4", "L5", "L6", "L7"), 
                  cloneCall="aa", 
                  graph = "alluvial")

3.6 clonalScatter: Scatterplot of Two Variables

#clonalScatter

clonalScatter(combined.TCR, 
              cloneCall ="gene", 
              x.axis = "L1", 
              y.axis = "L2",
              dot.size = "total",
              graph = "proportion")



clonalScatter(combined.TCR, 
              cloneCall ="gene", 
              x.axis = "L3", 
              y.axis = "L4",
              dot.size = "total",
              graph = "proportion")


clonalScatter(combined.TCR, 
              cloneCall ="gene", 
              x.axis = "L5", 
              y.axis = "L6",
              dot.size = "total",
              graph = "proportion")


clonalScatter(combined.TCR, 
              cloneCall ="gene", 
              x.axis = "L5", 
              y.axis = "L7",
              dot.size = "total",
              graph = "proportion")


clonalScatter(combined.TCR_with_PBMC, 
              cloneCall ="gene", 
              x.axis = "L6", 
              y.axis = "L7",
              dot.size = "total",
              graph = "proportion")

4. Visualizing Clonal Dynamics

4.1 clonalHomeostasis: Examining Clonal Space

# Visualizing Clonal Dynamics

# clonalHomeostasis

clonalHomeostasis(combined.TCR, 
                  cloneCall = "gene")



clonalHomeostasis(combined.TCR, 
                  cloneCall = "gene",
                  cloneSize = c(Rare = 0.001, Small = 0.01, Medium = 0.1, Large = 0.3, Hyperexpanded =1))



clonalHomeostasis(combined.TCR, 
                  cloneCall = "gene",
                  cloneSize = c(Rare = 0.1, Small = 1, Medium = 10, Large = 30, Hyperexpanded =100))

4.2 clonalProportion: Examining Space Occupied by Ranks of Clones

# clonalProportion

clonalProportion(combined.TCR, 
                 cloneCall = "gene") 


clonalProportion(combined.TCR, 
                 cloneCall = "nt",
                 clonalSplit = c(1, 5, 10, 100, 1000, 10000)) 



clonalProportion(combined.TCR, 
                 cloneCall = "nt",
                 clonalSplit = c(10, 100, 1000, 10000, 30000, 100000)) 

NA
NA

5. Summarizing Repertoires

# Summarizing Repertoires

# positionalEntropy

positionalEntropy(combined.TCR, 
                  chain = "TRB", 
                  aa.length = 20)


positionalEntropy(combined.TCR_with_PBMC, 
                  chain = "TRB", 
                  aa.length = 20)




# positionalProperty

positionalProperty(combined.TCR[c(1,2)], 
                  chain = "TRB", 
                  aa.length = 20, 
                  method = "atchleyFactors") + 
  scale_color_manual(values = hcl.colors(5, "inferno")[c(2,4)])



# percentGeneUsage
vizGenes(combined.TCR, 
         x.axis = "TRBV",
         y.axis = NULL,
         plot = "barplot",  
         summary.fun = "proportion")


vizGenes(combined.TCR_with_PBMC, 
         x.axis = "TRBV",
         y.axis = NULL,
         plot = "barplot",  
         summary.fun = "proportion")



vizGenes(combined.TCR, 
        x.axis = "TRAV",
        y.axis = NULL,
        plot = "barplot",  
        summary.fun = "proportion")


vizGenes(combined.TCR_with_PBMC, 
        x.axis = "TRAV",
        y.axis = NULL,
        plot = "barplot",  
        summary.fun = "proportion")


vizGenes(combined.TCR[c(1,2,3,4,5,6,7)], 
         x.axis = "TRBV",
         y.axis = "TRBJ",
         plot = "heatmap",  
          summary.fun = "percent")


vizGenes(combined.TCR[c(1,2,3,4,5,6,7)], 
         x.axis = "TRAV",
         y.axis = "TRAJ",
         plot = "heatmap",  
          summary.fun = "percent")


# For the P17 patient samples, what if we are interested in chain pairings, we can look at TRBV and TRAV at the same time using them as inputs to x.axis and y.axis.
vizGenes(combined.TCR[c(1,2)], 
         x.axis = "TRBV",
         y.axis = "TRAV",
         plot = "heatmap", 
          summary.fun = "percent")


# percentGenes: Quantifying Single Gene Usage
percentGenes(combined.TCR_with_PBMC, 
             chain = "TRB", 
             gene = "Vgene",
              summary.fun = "percent")


percentGenes(combined.TCR_with_PBMC, 
             chain = "TRA", 
             gene = "Vgene",
              summary.fun = "percent")


percentGenes(combined.TCR_with_PBMC, 
             chain = "TRB", 
             gene = "Jgene")


percentGenes(combined.TCR_with_PBMC, 
             chain = "TRA", 
             gene = "Jgene",
              summary.fun = "percent")



# percentVJ
# Quantify the proportion of V and J gene usage with percentVJ(). Like percentGenes(), this function will quantify the percentage of V and J paired together across individual repertoires. The output can be visualized using a heatmap or as input for further dimensional reduction.

percentVJ(combined.TCR_with_PBMC, 
          chain = "TRB",
           summary.fun = "percent")


percentVJ(combined.TCR_with_PBMC, 
          chain = "TRA",
           summary.fun = "percent")


# percentKmer

percentKmer(combined.TCR_with_PBMC, 
            cloneCall = "aa",
            chain = "TRB", 
            motif.length = 3, 
            top.motifs = 25)


percentKmer(combined.TCR_with_PBMC, 
            cloneCall = "aa",
            chain = "TRA", 
            motif.length = 3, 
            top.motifs = 25)


percentKmer(combined.TCR_with_PBMC, 
            cloneCall = "nt",
            chain = "TRB", 
            motif.length = 3, 
            top.motifs = 25)


percentKmer(combined.TCR_with_PBMC, 
            cloneCall = "nt",
            chain = "TRA", 
            motif.length = 3, 
            top.motifs = 25)

6. Comparing Clonal Diversity and Overlap

# clonalDiversity


clonalDiversity(combined.TCR_with_PBMC, 
                cloneCall = "gene")


clonalDiversity(combined.TCR, 
                cloneCall = "gene")


#clonalSizeDistribution


clonalSizeDistribution(combined.TCR_with_PBMC, 
                       cloneCall = "aa", 
                       method= "ward.D2")


clonalSizeDistribution(combined.TCR_with_PBMC, 
                       cloneCall = "nt", 
                       method= "ward.D2")


#clonalOverlap

clonalOverlap(combined.TCR_with_PBMC, 
              cloneCall = "strict", 
              method = "morisita")



clonalOverlap(combined.TCR_with_PBMC, 
              cloneCall = "strict", 
              method = "raw")

7. Combining Clones and Single-Cell Objects


# Combining Clones and Single-Cell Objects

#Getting a sample of a Seurat object
TCR <- get(data("All_samples_Merged"))


#Define color palette 
colorblind_vector <- hcl.colors(n=7, palette = "inferno", fixup = TRUE)


TCR <- combineExpression(combined.TCR_with_PBMC, 
                                   TCR, 
                                   cloneCall="gene", 
                                   group.by = "sample", 
                                   proportion = FALSE, 
                                   cloneSize=c(Single=1, Small=5, Medium=20, Large=100,Hyperexpanded=500))



DimPlot(subset(TCR, !is.na(cloneSize)), 
        group.by = "cloneSize", 
        reduction = "umap")


DimPlot(TCR, group.by = "cloneSize", reduction = "umap") +
    scale_color_manual(values=rev(colorblind_vector[c(1,3,4,5,6)]))
Error in data.frame(..., check.names = FALSE) : 
  arguments imply differing number of rows: 49305, 32343

8. Visualizations for Single-Cell Objects


# Visualizations for Single-Cell Objects
# clonalOverlay

#Adding patient information
scRep_example$Patient_origin <- substr(scRep_example$orig.ident, 1,3)

clonalOverlay(scRep_example, 
              reduction = "umap", 
              cutpoint = 1, 
              bins = 10, 
              facet.by = "Patient_origin") + 
              guides(color = "none")
Error in clonalOverlay(scRep_example, reduction = "umap", cutpoint = 1,  : 
  If filtering the data using a cutpoint, ensure the cut.category correspond to a variable in the meta data.

9. Quantifying Clonal Bias

# # StartracDiversity # From the excellent work by Lei Zhang, et al., the authors introduce new methods for looking at clones by cellular origins and cluster identification. Their STARTRAC software has been adapted to work with scRepertoire and please read and cite their excellent work. # # In order to use the StartracDiversity() function, you will need to include the product of the combinedExpression() function. The second requirement is a column header in the meta data of the Seurat object that has tissue of origin. In the example data, type corresponds to the column “Type”, which includes the “P” and “T” classifiers. The indices can be subsetted for a specific patient or examined overall using the by variable. Importantly, the function uses only the strict definition of a clone of the VDJC genes and the CDR3 nucleotide sequence. # # The indices output includes: # # expa - Clonal Expansion # migr - Cross-tissue Migration # tran - State Transition



StartracDiversity(scRep_example, 
                  type = "Patient_origin",
                  group.by = "cell_line")


StartracDiversity(scRep_example, 
                  type = "cell_line",
                  group.by = "cell_line")

10. clonalBias



clonalBias(scRep_example, 
           cloneCall = "aa", 
           split.by = "cell_line", 
           group.by = "seurat_clusters",
           n.boots = 10, 
           min.expand =5)
LS0tCnRpdGxlOiAiVENSIEFuYWx5c2lzLTctMTEtMjAyNSIKYXV0aG9yOiBOYXNpciBNYWhtb29kIEFiYmFzaQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICAjIHBkZl9kb2N1bWVudDogZGVmYXVsdAogICMgd29yZF9kb2N1bWVudDogZGVmYXVsdAogICMgaHRtbF9kb2N1bWVudDogZGVmYXVsdAogICNybWRmb3JtYXRzOjpyZWFkdGhlZG93bgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdG9jX2NvbGxhcHNlZDogdHJ1ZQotLS0KCgojICoqMS4gSW50cm9kdWN0aW9uKioKClNpbmdsZS1jZWxsIHNlcXVlbmNpbmcgaXMgYW4gZW1lcmdpbmcgdGVjaG5vbG9neSBpbiB0aGUgZmllbGQgb2YgaW1tdW5vbG9neSBhbmQgb25jb2xvZ3kgdGhhdCBhbGxvd3MgcmVzZWFyY2hlcnMgdG8gY291cGxlIFJOQSBxdWFudGlmaWNhdGlvbiBhbmQgb3RoZXIgbW9kYWxpdGllcywgbGlrZSBpbW11bmUgY2VsbCByZWNlcHRvciBwcm9maWxpbmcgYXQgdGhlIGxldmVsIG9mIGFuIGluZGl2aWR1YWwgY2VsbC4gQSBudW1iZXIgb2Ygd29ya2Zsb3dzIGFuZCBzb2Z0d2FyZSBwYWNrYWdlcyBoYXZlIGJlZW4gY3JlYXRlZCB0byBwcm9jZXNzIGFuZCBhbmFseXplIHNpbmdsZS1jZWxsIHRyYW5zY3JpcHRvbWljIGRhdGEuIFRoZXNlIHBhY2thZ2VzIGFsbG93IHVzZXJzIHRvIHRha2UgdGhlIHZhc3QgZGltZW5zaW9uYWxpdHkgb2YgdGhlIGRhdGEgZ2VuZXJhdGVkIGluIHNpbmdsZS1jZWxsLWJhc2VkIGV4cGVyaW1lbnRzIGFuZCBkaXN0aWxsIHRoZSBkYXRhIGludG8gbm92ZWwgaW5zaWdodHMuIFVubGlrZSB0aGUgdHJhbnNjcmlwdG9taWMgZmllbGQsIHRoZXJlIGlzIGEgbGFjayBvZiBvcHRpb25zIGZvciBzb2Z0d2FyZSB0aGF0IGFsbG93IGZvciBzaW5nbGUtY2VsbCBpbW11bmUgcmVjZXB0b3IgcHJvZmlsaW5nLiBFbmFibGluZyB1c2VycyB0byBlYXNpbHkgY29tYmluZSBSTkEgYW5kIGltbXVuZSBwcm9maWxpbmcsIHRoZSBzY1JlcGVydG9pcmUgZnJhbWV3b3JrIHN1cHBvcnRzIHVzZSBvZiAxMHgsIHNpbmdsZS1jZWxsIGNsb25hbCBmb3JtYXRzIGFuZCBpbnRlcmFjdGlvbiB3aXRoIHBvcHVsYXIgUi1iYXNlZCBzaW5nbGUtY2VsbCBkYXRhIHBpcGVsaW5lcy4KCnNjUmVwZXJ0b2lyZSBpcyBkZXNpZ25lZCB0byB0YWtlIGZpbHRlciBjb250aWcgb3V0cHV0cyBmcm9tIHRoZSAxMHggR2Vub21pY3MgQ2VsbCBSYW5nZXIgcGlwZWxpbmUsIHByb2Nlc3MgdGhhdCBkYXRhIHRvIGFzc2lnbiBjbG9ub3R5cGUgYmFzZWQgb24gdHdvIFRDUiBvciBJZyBjaGFpbnMgYW5kIGFuYWx5emUgdGhlIGNsb25vdHlwZSBkeW5hbWljcy4gVGhlIGxhdHRlciBjYW4gYmUgc2VwYXJhdGVkIGludG8gMSkgY2xvbm90eXBlLW9ubHkgYW5hbHlzaXMgZnVuY3Rpb25zLCBzdWNoIGFzIHVuaXF1ZSBjbG9ub3R5cGVzIG9yIGNsb25hbCBzcGFjZSBxdWFudGlmaWNhdGlvbiwgYW5kIDIpIGludGVyYWN0aW9uIHdpdGggbVJOQSBleHByZXNzaW9uIGRhdGEgdXNpbmcgU2V1cmF0IG9yIFNpbmdsZUNlbGxFeHBlcmltZW50IHBhY2thZ2VzLgoKKipSZWZlcmVuY2VzOioqCgotIFtzY1JlcGVydG9pcmUgVmlnbmV0dGVdKGh0dHBzOi8vd3d3LmJpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvcmVsZWFzZS9iaW9jL3ZpZ25ldHRlcy9zY1JlcGVydG9pcmUvaW5zdC9kb2MvdmlnbmV0dGUuaHRtbCkgIAotIFtCb3JjaC5kZXYgc2NSZXBlcnRvaXJlXShodHRwczovL3d3dy5ib3JjaC5kZXYvdXBsb2Fkcy9zY3JlcGVydG9pcmUvKQoKCgoqKlByZXJlcXVpc2l0ZToqKiBFbnN1cmUgdGhlIGBBbGxfc2FtcGxlc19NZXJnZWRgIFNldXJhdCBvYmplY3QgaXMgbG9hZGVkIGludG8geW91ciBSIGVudmlyb25tZW50IGJlZm9yZSBydW5uaW5nIHRoZSBjaHVua3MgYmVsb3cuCgojIyAxLjEgTG9hZCBsaWJyYXJpZXMKYGBge3J9CmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KFNldXJhdE9iamVjdCkKbGlicmFyeShTZXVyYXRPYmplY3QpCmxpYnJhcnkoU2V1cmF0RGF0YSkKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkocm1hcmtkb3duKQpsaWJyYXJ5KHRpbnl0ZXgpCmxpYnJhcnkoZ3JpZCkKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KHByZXN0bykKCiNUQ1IgQW5hbHlzaXMKbGlicmFyeShzY1JlcGVydG9pcmUpCmxpYnJhcnkoU2luZ2xlQ2VsbEV4cGVyaW1lbnQpCmxpYnJhcnkoY2lyY2xpemUpCmxpYnJhcnkoc2NhbGVzKQpgYGAKCiMjIDEuMiAgTG9hZCBTZXVyYXQgT2JqZWN0CmBgYHtyfQoKI0xvYWQgU2V1cmF0IE9iamVjdCBtZXJnZWQgZnJvbSBjZWxsIGxpbmVzIGFuZCBhIGNvbnRyb2woUEJNQykgYWZ0ZXIgZmlsdHJhdGlvbgpBbGxfc2FtcGxlc19NZXJnZWQgPC0gcmVhZFJEUygiLi4vMC1TZXVyYXRfUkRTX09CSkVDVF9GSU5BTC9BbGxfc2FtcGxlc19NZXJnZWRfd2l0aF9SZW5hbWVkX0NsdXN0ZXJzX2ZpbmFsLTI2LTEwLTIwMjUucmRzIikKCkFsbF9zYW1wbGVzX01lcmdlZApgYGAKCiMjIDEuMy4gTG9hZCBjb250aWdzCgpzY1JlcGVydG9pcmUgZnVuY3Rpb25zIHVzaW5nIHRoZSBmaWx0ZXJlZF9jb250aWdfYW5ub3RhdGlvbnMuY3N2IG91dHB1dCBmcm9tIHRoZSAxMHggR2Vub21pY3MgQ2VsbCBSYW5nZXIuIFRoaXMgZmlsZSBpcyBsb2NhdGVkIGluIHRoZSAuL291dHMvIGRpcmVjdG9yeSBvZiB0aGUgVkRKIGFsaWdubWVudCBmb2xkZXIuIFRvIGdlbmVyYXRlIGEgbGlzdCBvZiBjb250aWdzIHRvIHVzZSBmb3Igc2NSZXBlcnRvaXJlOgoKKiotICAgbG9hZCB0aGUgZmlsdGVyZWRfY29udGlnX2Fubm90YXRpb25zLmNzdiBmb3IgZWFjaCBvZiB0aGUgc2FtcGxlcy4qKgoKKiotICAgbWFrZSBhIGxpc3QgaW4gdGhlIFIgZW52aXJvbm1lbnQuKioKCgpgYGB7ciBUQ1IsIGluY2x1ZGU9RkFMU0V9CgpMMSA8LSByZWFkLmNzdigiL3J1bi91c2VyLzEwMDAvZ3Zmcy9zbWItc2hhcmU6c2VydmVyPTEwLjE0NC4xNDIuMTMxLHNoYXJlPWNvbW11bi9OYXNpci9BbGxfRGF0YV9TUy9BdWRyZXlfR3Jvcy9DZWxsUmFuZ2VyL0wxL291dHMvcGVyX3NhbXBsZV9vdXRzL0wxL3Zkal90L2ZpbHRlcmVkX2NvbnRpZ19hbm5vdGF0aW9ucy5jc3YiKQpMMiA8LSByZWFkLmNzdigiL3J1bi91c2VyLzEwMDAvZ3Zmcy9zbWItc2hhcmU6c2VydmVyPTEwLjE0NC4xNDIuMTMxLHNoYXJlPWNvbW11bi9OYXNpci9BbGxfRGF0YV9TUy9BdWRyZXlfR3Jvcy9DZWxsUmFuZ2VyL0wyL291dHMvcGVyX3NhbXBsZV9vdXRzL0wyL3Zkal90L2ZpbHRlcmVkX2NvbnRpZ19hbm5vdGF0aW9ucy5jc3YiKQpMMyA8LSByZWFkLmNzdigiL3J1bi91c2VyLzEwMDAvZ3Zmcy9zbWItc2hhcmU6c2VydmVyPTEwLjE0NC4xNDIuMTMxLHNoYXJlPWNvbW11bi9OYXNpci9BbGxfRGF0YV9TUy9BdWRyZXlfR3Jvcy9DZWxsUmFuZ2VyL0wzX0NJVEVfQi8vb3V0cy9wZXJfc2FtcGxlX291dHMvTDNfQ0lURV9CLy92ZGpfdC9maWx0ZXJlZF9jb250aWdfYW5ub3RhdGlvbnMuY3N2IikKTDQgPC0gcmVhZC5jc3YoIi9ydW4vdXNlci8xMDAwL2d2ZnMvc21iLXNoYXJlOnNlcnZlcj0xMC4xNDQuMTQyLjEzMSxzaGFyZT1jb21tdW4vTmFzaXIvQWxsX0RhdGFfU1MvQXVkcmV5X0dyb3MvQ2VsbFJhbmdlci9MNF9CL291dHMvcGVyX3NhbXBsZV9vdXRzL0w0X0IvL3Zkal90L2ZpbHRlcmVkX2NvbnRpZ19hbm5vdGF0aW9ucy5jc3YiKQpMNSA8LSByZWFkLmNzdigiL3J1bi91c2VyLzEwMDAvZ3Zmcy9zbWItc2hhcmU6c2VydmVyPTEwLjE0NC4xNDIuMTMxLHNoYXJlPWNvbW11bi9OYXNpci9BbGxfRGF0YV9TUy9BdWRyZXlfR3Jvcy9DZWxsUmFuZ2VyL0w1L291dHMvcGVyX3NhbXBsZV9vdXRzL0w1L3Zkal90L2ZpbHRlcmVkX2NvbnRpZ19hbm5vdGF0aW9ucy5jc3YiKQpMNiA8LSByZWFkLmNzdigiL3J1bi91c2VyLzEwMDAvZ3Zmcy9zbWItc2hhcmU6c2VydmVyPTEwLjE0NC4xNDIuMTMxLHNoYXJlPWNvbW11bi9OYXNpci9BbGxfRGF0YV9TUy9BdWRyZXlfR3Jvcy9DZWxsUmFuZ2VyL0w2X0NJVEUvL291dHMvcGVyX3NhbXBsZV9vdXRzL0w2X0NJVEUvL3Zkal90L2ZpbHRlcmVkX2NvbnRpZ19hbm5vdGF0aW9ucy5jc3YiKQpMNyA8LSByZWFkLmNzdigiL3J1bi91c2VyLzEwMDAvZ3Zmcy9zbWItc2hhcmU6c2VydmVyPTEwLjE0NC4xNDIuMTMxLHNoYXJlPWNvbW11bi9OYXNpci9BbGxfRGF0YV9TUy9BdWRyZXlfR3Jvcy9DZWxsUmFuZ2VyL0w3L291dHMvcGVyX3NhbXBsZV9vdXRzL0w3L3Zkal90L2ZpbHRlcmVkX2NvbnRpZ19hbm5vdGF0aW9ucy5jc3YiKQpQQk1DIDwtIHJlYWQuY3N2KCIvcnVuL3VzZXIvMTAwMC9ndmZzL3NtYi1zaGFyZTpzZXJ2ZXI9MTAuMTQ0LjE0Mi4xMzEsc2hhcmU9Y29tbXVuL05hc2lyL0FsbF9EYXRhX1NTL0F1ZHJleV9Hcm9zL0NlbGxSYW5nZXIvUEJNQy9vdXRzL3Blcl9zYW1wbGVfb3V0cy9QQk1DL3Zkal90L2ZpbHRlcmVkX2NvbnRpZ19hbm5vdGF0aW9ucy5jc3YiKQoKYGBgCgojICoqMi4gQ29tYmluaW5nIENvbnRpZ3MgaW50byBDbG9uZXMqKgoKVGhlcmUgYXJlIHZhcnlpbmcgZGVmaW5pdGlvbnMgb2YgY2xvbmVzIGluIHRoZSBsaXRlcmF0dXJlLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHNjUmVwZXJ0b2lyZSwgd2UgZGVmaW5lIGEgY2xvbmUgYXMgY2VsbHMgd2l0aCBzaGFyZWQvdHJhY2thYmxlIGNvbXBsZW1lbnRhcml0eS1kZXRlcm1pbmluZyByZWdpb24gMyAoQ0RSMykgc2VxdWVuY2VzLiBXaXRoaW4gdGhpcyBkZWZpbml0aW9uLCBvbmUgbWlnaHQgdXNlIGFtaW5vIGFjaWQgKGFhKSBzZXF1ZW5jZXMgb2Ygb25lIG9yIGJvdGggY2hhaW5zIHRvIGRlZmluZSBhIGNsb25lLiBBbHRlcm5hdGl2ZWx5LCB3ZSBjb3VsZCB1c2UgbnVjbGVvdGlkZSAobnQpIG9yIHRoZSBWKEQpSkMgZ2VuZXMgKGdlbmVzKSB0byBkZWZpbmUgYSBjbG9uZS4gVGhlIGxhdHRlciwgZ2VuZXMsIHdvdWxkIGJlIGEgbW9yZSBwZXJtaXNzaXZlIGRlZmluaXRpb24gb2Yg4oCcY2xvbmVzLOKAnSBhcyBtdWx0aXBsZSBhbWlubyBhY2lkIG9yIG51Y2xlb3RpZGUgc2VxdWVuY2VzIGNhbiByZXN1bHQgZnJvbSB0aGUgc2FtZSBnZW5lIGNvbWJpbmF0aW9uLiBBbm90aGVyIG9wdGlvbiB0byBkZWZpbmUgYSBjbG9uZSBpcyB0aGUgdXNlIG9mIHRoZSBWKEQpSkMgYW5kIG51Y2xlb3RpZGUgc2VxdWVuY2UgKHN0cmljdCkuIHNjUmVwZXJ0b2lyZSBhbGxvd3MgZm9yIHRoZSB1c2Ugb2YgYWxsIHRoZXNlIGRlZmluaXRpb25zIG9mIGNsb25lcyBhbmQgZW5hYmxlcyB1c2VycyB0byBzZWxlY3QgYm90aCBvciBpbmRpdmlkdWFsIGNoYWlucyB0byBleGFtaW5lLgoKIyMgMi4xIENvbWJpbmluZyBDb250aWdzIGludG8gQ2xvbmVzCmBgYHtyIGNvbWJpbmVkVENSLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD02fQoKY29udGlnX2xpc3QgPC0gbGlzdChMMSwgTDIsIEwzLCBMNCxMNSxMNiwgTDcpCmNvbnRpZ19saXN0X3dpdGhfUEJNQyA8LSBsaXN0KEwxLCBMMiwgTDMsIEw0LEw1LEw2LCBMNywgUEJNQykKCmNvbWJpbmVkLlRDUiA8LSBjb21iaW5lVENSKGNvbnRpZ19saXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGVzID0gYygiTDEiLCAiTDIiLCAiTDMiLCAiTDQiLCAiTDUiLCAiTDYiLCAiTDciKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVtb3ZlTkEgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVtb3ZlTXVsdGkgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyTXVsdGkgPSBGQUxTRSkKCmNvbWJpbmVkLlRDUl93aXRoX1BCTUMgPC0gY29tYmluZVRDUihjb250aWdfbGlzdF93aXRoX1BCTUMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGVzID0gYygiTDEiLCAiTDIiLCAiTDMiLCAiTDQiLCAiTDUiLCAiTDYiLCAiTDciLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBCTUMiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVtb3ZlTkEgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbW92ZU11bHRpID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXJNdWx0aSA9IEZBTFNFKQoKIGV4cG9ydENsb25lcyhjb21iaW5lZC5UQ1IsCiAgICAgICAgICAgICAgd3JpdGUuZmlsZSA9IFRSVUUsCiAgICAgICAgICAgICAgZGlyID0gIlRDUl9hbmFseXNpcy03LTExLTIwMjUvIiwKICAgICAgICAgICAgIGZpbGUubmFtZSA9ICJjbG9uZXMuY3N2IikKCmV4cG9ydENsb25lcyhjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLAogICAgICAgICAgICAgd3JpdGUuZmlsZSA9IFRSVUUsCiAgICAgICAgICAgICBkaXIgPSAiVENSX2FuYWx5c2lzLTctMTEtMjAyNS8iLAogICAgICAgICAgICAgZmlsZS5uYW1lID0gImNsb25lc193aXRoX1BCTUMuY3N2IikKCmhlYWQoY29tYmluZWQuVENSW1sxXV0pCmhlYWQoY29tYmluZWQuVENSX3dpdGhfUEJNQ1tbMV1dKQoKIyBDb21iaW5lIGFsbCBkYXRhIGZyYW1lcyBpbiB0aGUgbGlzdCBpbnRvIGEgc2luZ2xlIGRhdGEgZnJhbWUKY29tYmluZWRfVENSX2RmIDwtIGRvLmNhbGwocmJpbmQsIGNvbWJpbmVkLlRDUikKCiMgV3JpdGUgdGhlIGNvbWJpbmVkIGRhdGEgZnJhbWUgdG8gYSBDU1YgZmlsZQp3cml0ZS5jc3YoY29tYmluZWRfVENSX2RmLCBmaWxlID0gIlRDUl9hbmFseXNpcy03LTExLTIwMjUvY29tYmluZWRfVENSLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQoKCiMgQ29tYmluZSBhbGwgZGF0YSBmcmFtZXMgaW4gdGhlIGxpc3QgaW50byBhIHNpbmdsZSBkYXRhIGZyYW1lCmNvbWJpbmVkX1RDUl93aXRoX1BCTUNfZGYgPC0gZG8uY2FsbChyYmluZCwgY29tYmluZWQuVENSX3dpdGhfUEJNQykKCiMgV3JpdGUgdGhlIGNvbWJpbmVkIGRhdGEgZnJhbWUgdG8gYSBDU1YgZmlsZQp3cml0ZS5jc3YoY29tYmluZWRfVENSX3dpdGhfUEJNQ19kZiwgZmlsZSA9ICJUQ1JfYW5hbHlzaXMtNy0xMS0yMDI1L2NvbWJpbmVkX1RDUl93aXRoX1BCTUMuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCmBgYAoKIyMgMi4yIFdyaXRlIHRoZSBmYXN0YSBmaWxlIGZvciBwaHlsb2dlbnkKYGBge3IgcGh5bG9nZW5leUZpbGVzLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD02fQoKIyAjIERlZmluZSB0aGUgRkFTVEEgZmlsZSBmb3IgYWxwaGEgY2hhaW5zCiMgYWxwaGFfZmFzdGFfZmlsZSA8LSAiVENSX2FuYWx5c2lzLTctMTEtMjAyNS9QaHlsb2dlbnkvY2RyM19hbHBoYV9zZXF1ZW5jZXMuZmFzdGEiCiMgCiMgIyBPcGVuIGEgY29ubmVjdGlvbiB0byB0aGUgZmlsZQojIGYgPC0gZmlsZShhbHBoYV9mYXN0YV9maWxlLCBvcGVuID0gInciKQojIAojICMgTG9vcCB0aHJvdWdoIHRoZSBkYXRhIGZyYW1lCiMgZm9yIChpIGluIHNlcV9sZW4obnJvdyhjb21iaW5lZF9UQ1Jfd2l0aF9QQk1DX2RmKSkpIHsKIyAgIGlmICghaXMubmEoY29tYmluZWRfVENSX3dpdGhfUEJNQ19kZiRjZHIzX250MVtpXSkpIHsKIyAgICAgIyBXcml0ZSB0aGUgaGVhZGVyIGFuZCBzZXF1ZW5jZQojICAgICB3cml0ZUxpbmVzKHBhc3RlMCgiPiIsIGNvbWJpbmVkX1RDUl9kZiRzYW1wbGVbaV0sICJfYWxwaGEiKSwgZikKIyAgICAgd3JpdGVMaW5lcyhjb21iaW5lZF9UQ1JfZGYkY2RyM19udDFbaV0sIGYpCiMgICB9CiMgfQojIAojICMgQ2xvc2UgdGhlIGNvbm5lY3Rpb24KIyBjbG9zZShmKQojIAojIGNhdCgiQWxwaGEgY2hhaW4gRkFTVEEgZmlsZSBjcmVhdGVkIGF0OiIsIGFscGhhX2Zhc3RhX2ZpbGUsICJcbiIpCiMgCiMgCiMgIyBEZWZpbmUgdGhlIEZBU1RBIGZpbGUgZm9yIGJldGEgY2hhaW5zCiMgYmV0YV9mYXN0YV9maWxlIDwtICJUQ1JfYW5hbHlzaXMtNy0xMS0yMDI1L1BoeWxvZ2VueS9jZHIzX2JldGFfc2VxdWVuY2VzLmZhc3RhIgojIAojICMgT3BlbiBhIGNvbm5lY3Rpb24gdG8gdGhlIGZpbGUKIyBmIDwtIGZpbGUoYmV0YV9mYXN0YV9maWxlLCBvcGVuID0gInciKQojIAojICMgTG9vcCB0aHJvdWdoIHRoZSBkYXRhIGZyYW1lCiMgZm9yIChpIGluIHNlcV9sZW4obnJvdyhjb21iaW5lZF9UQ1Jfd2l0aF9QQk1DX2RmKSkpIHsKIyAgIGlmICghaXMubmEoY29tYmluZWRfVENSX3dpdGhfUEJNQ19kZiRjZHIzX250MltpXSkpIHsKIyAgICAgIyBXcml0ZSB0aGUgaGVhZGVyIGFuZCBzZXF1ZW5jZQojICAgICB3cml0ZUxpbmVzKHBhc3RlMCgiPiIsIGNvbWJpbmVkX1RDUl93aXRoX1BCTUNfZGYkc2FtcGxlW2ldLCAiX2JldGEiKSwgZikKIyAgICAgd3JpdGVMaW5lcyhjb21iaW5lZF9UQ1JfZGYkY2RyM19udDJbaV0sIGYpCiMgICB9CiMgfQojIAojICMgQ2xvc2UgdGhlIGNvbm5lY3Rpb24KIyBjbG9zZShmKQojIAojIGNhdCgiQmV0YSBjaGFpbiBGQVNUQSBmaWxlIGNyZWF0ZWQgYXQ6IiwgYmV0YV9mYXN0YV9maWxlLCAiXG4iKQpgYGAKCgoKIyAqKjMuIEJhc2ljIENsb25hbCBWaXN1YWxpemF0aW9ucyoqCgojIyAzLjEuIGNsb25hbFF1YW50OiBRdWFudGlmeWluZyBVbmlxdWUgQ2xvbmVzCmBgYHtyIENsb25hbC1WaXN1YWxpemF0aW9uLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD04fQojY2xvbmFsUXVhbnQKIGNsb25hbFF1YW50KGNvbWJpbmVkLlRDUiwgCiAgICAgICAgICAgIGNsb25lQ2FsbD0ic3RyaWN0IiwgCiAgICAgICAgICAgIGNoYWluID0gImJvdGgiLCAKICAgICAgICAgICAgc2NhbGUgPSBUUlVFKQoKCmNsb25hbFF1YW50KGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICBjbG9uZUNhbGw9InN0cmljdCIsIAogICAgICAgICAgICBjaGFpbiA9ICJib3RoIiwgCiAgICAgICAgICAgIHNjYWxlID0gVFJVRSkKYGBgCgojIyAzLjIgY2xvbmFsQWJ1bmRhbmNlOiBEaXN0cmlidXRpb24gb2YgQ2xvbmVzIGJ5IFNpemUKYGBge3IgVjIsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTh9CiNjbG9uYWxBYnVuZGFuY2UKCmNsb25hbEFidW5kYW5jZShjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCAKICAgICAgICAgICAgICAgIGNsb25lQ2FsbCA9ICJnZW5lIiwgIHBhbGV0dGUgPSAiWmlzc291IDEiLAogICAgICAgICAgICAgICAgc2NhbGUgPSBGQUxTRSkKICAKY2xvbmFsQWJ1bmRhbmNlKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgICAgY2xvbmVDYWxsID0gImdlbmUiLCBwYWxldHRlID0gIlppc3NvdSAxIiwKICAgICAgICAgICAgICAgIHNjYWxlID0gVFJVRSkKCgoKY2xvbmFsQWJ1bmRhbmNlKGNvbWJpbmVkLlRDUiwgCiAgICAgICAgICAgICAgICBjbG9uZUNhbGwgPSAiZ2VuZSIsICAKICAgICAgICAgICAgICAgIHNjYWxlID0gRkFMU0UpCiAKCmNsb25hbEFidW5kYW5jZShjb21iaW5lZC5UQ1IsIAogICAgICAgICAgICAgICAgY2xvbmVDYWxsID0gImdlbmUiLCAKICAgICAgICAgICAgICAgIHNjYWxlID0gVFJVRSkKYGBgCiMjIDMuMyBjbG9uYWxMZW5ndGg6IERpc3RyaWJ1dGlvbiBvZiBTZXF1ZW5jZSBMZW5ndGhzCmBgYHtyIFYzLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMn0KI2Nsb25hbExlbmd0aApjbG9uYWxMZW5ndGgoY29tYmluZWQuVENSX3dpdGhfUEJNQywgCiAgICAgICAgICAgICBjbG9uZUNhbGw9Im50IiwgCiAgICAgICAgICAgICBjaGFpbiA9ICJib3RoIikgCgpjbG9uYWxMZW5ndGgoY29tYmluZWQuVENSX3dpdGhfUEJNQywgCiAgICAgICAgICAgICBjbG9uZUNhbGw9ImFhIiwgCiAgICAgICAgICAgICBjaGFpbiA9ICJib3RoIikgCgpjbG9uYWxMZW5ndGgoY29tYmluZWQuVENSLCAKICAgICAgICAgICAgIGNsb25lQ2FsbD0ibnQiLCAKICAgICAgICAgICAgIGNoYWluID0gImJvdGgiKSAKCmNsb25hbExlbmd0aChjb21iaW5lZC5UQ1IsIAogICAgICAgICAgICAgY2xvbmVDYWxsPSJhYSIsIAogICAgICAgICAgICAgY2hhaW4gPSAiYm90aCIpIAoKCgojVFJBCmNsb25hbExlbmd0aChjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCAKICAgICAgICAgICAgIGNsb25lQ2FsbD0ibnQiLCAKICAgICAgICAgICAgIGNoYWluID0gIlRSQSIsIAogICAgICAgICAgICAgc2NhbGUgPSBUUlVFKSAKCmNsb25hbExlbmd0aChjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCAKICAgICAgICAgICAgIGNsb25lQ2FsbD0iYWEiLCAKICAgICAgICAgICAgIGNoYWluID0gIlRSQSIsIAogICAgICAgICAgICAgc2NhbGUgPSBUUlVFKSAKCmNsb25hbExlbmd0aChjb21iaW5lZC5UQ1IsIAogICAgICAgICAgICAgY2xvbmVDYWxsPSJudCIsIAogICAgICAgICAgICAgY2hhaW4gPSAiVFJBIiwgIAogICAgICAgICAgICAgc2NhbGUgPSBUUlVFKSAKCmNsb25hbExlbmd0aChjb21iaW5lZC5UQ1IsIAogICAgICAgICAgICAgY2xvbmVDYWxsPSJhYSIsIAogICAgICAgICAgICAgY2hhaW4gPSAiVFJBIiwgCiAgICAgICAgICAgICBzY2FsZSA9IFRSVUUpIAoKCiNUUkIKY2xvbmFsTGVuZ3RoKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgY2xvbmVDYWxsPSJudCIsIAogICAgICAgICAgICAgY2hhaW4gPSAiVFJCIiwgCiAgICAgICAgICAgICBzY2FsZSA9IFRSVUUpIAoKY2xvbmFsTGVuZ3RoKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgY2xvbmVDYWxsPSJhYSIsIAogICAgICAgICAgICAgY2hhaW4gPSAiVFJCIiwgCiAgICAgICAgICAgICBzY2FsZSA9IFRSVUUpIAoKY2xvbmFsTGVuZ3RoKGNvbWJpbmVkLlRDUiwgCiAgICAgICAgICAgICBjbG9uZUNhbGw9Im50IiwgCiAgICAgICAgICAgICBjaGFpbiA9ICJUUkIiLCAgCiAgICAgICAgICAgICBzY2FsZSA9IFRSVUUpIAoKY2xvbmFsTGVuZ3RoKGNvbWJpbmVkLlRDUiwgCiAgICAgICAgICAgICBjbG9uZUNhbGw9ImFhIiwgCiAgICAgICAgICAgICBjaGFpbiA9ICJUUkIiLCAKICAgICAgICAgICAgIHNjYWxlID0gVFJVRSkgCmBgYAojIyAzLjUgY2xvbmFsQ29tcGFyZTogQ2xvbmFsIER5bmFtaWNzIEJldHdlZW4gQ2F0ZWdvcmljYWwgVmFyaWFibGVzCmBgYHtyIFY0LCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMn0KIyBjbG9uYWxDb21wYXJlCmNsb25hbENvbXBhcmUoY29tYmluZWQuVENSLCAKICAgICAgICAgICAgICAgICAgdG9wLmNsb25lcyA9IDEwLCAKICAgICAgICAgICAgICAgICAgc2FtcGxlcyA9IGMoIkwxIiwgIkwyIiksIAogICAgICAgICAgICAgICAgICBjbG9uZUNhbGw9ImFhIiwgCiAgICAgICAgICAgICAgICAgIGdyYXBoID0gImFsbHV2aWFsIikKCmNsb25hbENvbXBhcmUoY29tYmluZWQuVENSLCAKICAgICAgICAgICAgICAgICAgdG9wLmNsb25lcyA9IDEwLCAKICAgICAgICAgICAgICAgICAgc2FtcGxlcyA9IGMoIkwzIiwgIkw0IiksIAogICAgICAgICAgICAgICAgICBjbG9uZUNhbGw9ImFhIiwgCiAgICAgICAgICAgICAgICAgIGdyYXBoID0gImFsbHV2aWFsIikKCmNsb25hbENvbXBhcmUoY29tYmluZWQuVENSLCAKICAgICAgICAgICAgICAgICAgdG9wLmNsb25lcyA9IDEwLCAKICAgICAgICAgICAgICAgICAgc2FtcGxlcyA9IGMoIkw1IiwgIkw2IiwiTDciKSwgCiAgICAgICAgICAgICAgICAgIGNsb25lQ2FsbD0iYWEiLCAKICAgICAgICAgICAgICAgICAgZ3JhcGggPSAiYWxsdXZpYWwiKQoKY2xvbmFsQ29tcGFyZShjb21iaW5lZC5UQ1IsIAogICAgICAgICAgICAgICAgICB0b3AuY2xvbmVzID0gMTAsIAogICAgICAgICAgICAgICAgICBzYW1wbGVzID0gYygiTDUiLCJMNiIpLCAKICAgICAgICAgICAgICAgICAgY2xvbmVDYWxsPSJhYSIsIAogICAgICAgICAgICAgICAgICBncmFwaCA9ICJhbGx1dmlhbCIpCgpjbG9uYWxDb21wYXJlKGNvbWJpbmVkLlRDUiwgCiAgICAgICAgICAgICAgICAgIHRvcC5jbG9uZXMgPSAxMCwgCiAgICAgICAgICAgICAgICAgIHNhbXBsZXMgPSBjKCJMNSIsIkw3IiksIAogICAgICAgICAgICAgICAgICBjbG9uZUNhbGw9ImFhIiwgCiAgICAgICAgICAgICAgICAgIGdyYXBoID0gImFsbHV2aWFsIikKCmNsb25hbENvbXBhcmUoY29tYmluZWQuVENSLCAKICAgICAgICAgICAgICAgICAgdG9wLmNsb25lcyA9IDEwLCAKICAgICAgICAgICAgICAgICAgc2FtcGxlcyA9IGMoIkw2IiwiTDciKSwgCiAgICAgICAgICAgICAgICAgIGNsb25lQ2FsbD0iYWEiLCAKICAgICAgICAgICAgICAgICAgZ3JhcGggPSAiYWxsdXZpYWwiKQoKY2xvbmFsQ29tcGFyZShjb21iaW5lZC5UQ1IsIAogICAgICAgICAgICAgICAgICB0b3AuY2xvbmVzID0gMTAsIAogICAgICAgICAgICAgICAgICBzYW1wbGVzID0gYygiTDEiLCAiTDIiLCAiTDMiLCAiTDQiLCAiTDUiLCAiTDYiLCAiTDciLCAiUEJNQyIpLCAKICAgICAgICAgICAgICAgICAgY2xvbmVDYWxsPSJhYSIsIAogICAgICAgICAgICAgICAgICBncmFwaCA9ICJhbGx1dmlhbCIpCgoKY2xvbmFsQ29tcGFyZShjb21iaW5lZC5UQ1IsIAogICAgICAgICAgICAgICAgICB0b3AuY2xvbmVzID0gMTAsIAogICAgICAgICAgICAgICAgICBzYW1wbGVzID0gYygiTDEiLCAiTDIiLCAiTDMiLCAiTDQiLCAiTDUiLCAiTDYiLCAiTDciKSwgCiAgICAgICAgICAgICAgICAgIGNsb25lQ2FsbD0iYWEiLCAKICAgICAgICAgICAgICAgICAgZ3JhcGggPSAiYWxsdXZpYWwiKQpgYGAKIyMgMy42IGNsb25hbFNjYXR0ZXI6IFNjYXR0ZXJwbG90IG9mIFR3byBWYXJpYWJsZXMKYGBge3IgVjUsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTZ9CiNjbG9uYWxTY2F0dGVyCgpjbG9uYWxTY2F0dGVyKGNvbWJpbmVkLlRDUiwgCiAgICAgICAgICAgICAgY2xvbmVDYWxsID0iZ2VuZSIsIAogICAgICAgICAgICAgIHguYXhpcyA9ICJMMSIsIAogICAgICAgICAgICAgIHkuYXhpcyA9ICJMMiIsCiAgICAgICAgICAgICAgZG90LnNpemUgPSAidG90YWwiLAogICAgICAgICAgICAgIGdyYXBoID0gInByb3BvcnRpb24iKQoKCmNsb25hbFNjYXR0ZXIoY29tYmluZWQuVENSLCAKICAgICAgICAgICAgICBjbG9uZUNhbGwgPSJnZW5lIiwgCiAgICAgICAgICAgICAgeC5heGlzID0gIkwzIiwgCiAgICAgICAgICAgICAgeS5heGlzID0gIkw0IiwKICAgICAgICAgICAgICBkb3Quc2l6ZSA9ICJ0b3RhbCIsCiAgICAgICAgICAgICAgZ3JhcGggPSAicHJvcG9ydGlvbiIpCgpjbG9uYWxTY2F0dGVyKGNvbWJpbmVkLlRDUiwgCiAgICAgICAgICAgICAgY2xvbmVDYWxsID0iZ2VuZSIsIAogICAgICAgICAgICAgIHguYXhpcyA9ICJMNSIsIAogICAgICAgICAgICAgIHkuYXhpcyA9ICJMNiIsCiAgICAgICAgICAgICAgZG90LnNpemUgPSAidG90YWwiLAogICAgICAgICAgICAgIGdyYXBoID0gInByb3BvcnRpb24iKQoKY2xvbmFsU2NhdHRlcihjb21iaW5lZC5UQ1IsIAogICAgICAgICAgICAgIGNsb25lQ2FsbCA9ImdlbmUiLCAKICAgICAgICAgICAgICB4LmF4aXMgPSAiTDUiLCAKICAgICAgICAgICAgICB5LmF4aXMgPSAiTDciLAogICAgICAgICAgICAgIGRvdC5zaXplID0gInRvdGFsIiwKICAgICAgICAgICAgICBncmFwaCA9ICJwcm9wb3J0aW9uIikKCmNsb25hbFNjYXR0ZXIoY29tYmluZWQuVENSX3dpdGhfUEJNQywgCiAgICAgICAgICAgICAgY2xvbmVDYWxsID0iZ2VuZSIsIAogICAgICAgICAgICAgIHguYXhpcyA9ICJMNiIsIAogICAgICAgICAgICAgIHkuYXhpcyA9ICJMNyIsCiAgICAgICAgICAgICAgZG90LnNpemUgPSAidG90YWwiLAogICAgICAgICAgICAgIGdyYXBoID0gInByb3BvcnRpb24iKQpgYGAKIyAqKjQuIFZpc3VhbGl6aW5nIENsb25hbCBEeW5hbWljcyoqCgojIyA0LjEgY2xvbmFsSG9tZW9zdGFzaXM6IEV4YW1pbmluZyBDbG9uYWwgU3BhY2UKYGBge3IgVjYsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTZ9CiMgVmlzdWFsaXppbmcgQ2xvbmFsIER5bmFtaWNzCgojIGNsb25hbEhvbWVvc3Rhc2lzCgpjbG9uYWxIb21lb3N0YXNpcyhjb21iaW5lZC5UQ1IsIAogICAgICAgICAgICAgICAgICBjbG9uZUNhbGwgPSAiZ2VuZSIpCgoKY2xvbmFsSG9tZW9zdGFzaXMoY29tYmluZWQuVENSLCAKICAgICAgICAgICAgICAgICAgY2xvbmVDYWxsID0gImdlbmUiLAogICAgICAgICAgICAgICAgICBjbG9uZVNpemUgPSBjKFJhcmUgPSAwLjAwMSwgU21hbGwgPSAwLjAxLCBNZWRpdW0gPSAwLjEsIExhcmdlID0gMC4zLCBIeXBlcmV4cGFuZGVkID0xKSkKCgpjbG9uYWxIb21lb3N0YXNpcyhjb21iaW5lZC5UQ1IsIAogICAgICAgICAgICAgICAgICBjbG9uZUNhbGwgPSAiZ2VuZSIsCiAgICAgICAgICAgICAgICAgIGNsb25lU2l6ZSA9IGMoUmFyZSA9IDAuMSwgU21hbGwgPSAxLCBNZWRpdW0gPSAxMCwgTGFyZ2UgPSAzMCwgSHlwZXJleHBhbmRlZCA9MTAwKSkKCmBgYAojIyA0LjIgY2xvbmFsUHJvcG9ydGlvbjogRXhhbWluaW5nIFNwYWNlIE9jY3VwaWVkIGJ5IFJhbmtzIG9mIENsb25lcwpgYGB7ciBTdGF0cywgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MjF9CiMgY2xvbmFsUHJvcG9ydGlvbgoKY2xvbmFsUHJvcG9ydGlvbihjb21iaW5lZC5UQ1IsIAogICAgICAgICAgICAgICAgIGNsb25lQ2FsbCA9ICJnZW5lIikgCgpjbG9uYWxQcm9wb3J0aW9uKGNvbWJpbmVkLlRDUiwgCiAgICAgICAgICAgICAgICAgY2xvbmVDYWxsID0gIm50IiwKICAgICAgICAgICAgICAgICBjbG9uYWxTcGxpdCA9IGMoMSwgNSwgMTAsIDEwMCwgMTAwMCwgMTAwMDApKSAKCgpjbG9uYWxQcm9wb3J0aW9uKGNvbWJpbmVkLlRDUiwgCiAgICAgICAgICAgICAgICAgY2xvbmVDYWxsID0gIm50IiwKICAgICAgICAgICAgICAgICBjbG9uYWxTcGxpdCA9IGMoMTAsIDEwMCwgMTAwMCwgMTAwMDAsIDMwMDAwLCAxMDAwMDApKSAKCgpgYGAKIyAqKjUuIFN1bW1hcml6aW5nIFJlcGVydG9pcmVzKioKYGBge3IgREUsIGZpZy5oZWlnaHQ9MTgsIGZpZy53aWR0aD0yMn0KIyBTdW1tYXJpemluZyBSZXBlcnRvaXJlcwoKIyBwb3NpdGlvbmFsRW50cm9weQoKcG9zaXRpb25hbEVudHJvcHkoY29tYmluZWQuVENSLCAKICAgICAgICAgICAgICAgICAgY2hhaW4gPSAiVFJCIiwgCiAgICAgICAgICAgICAgICAgIGFhLmxlbmd0aCA9IDIwKQoKcG9zaXRpb25hbEVudHJvcHkoY29tYmluZWQuVENSX3dpdGhfUEJNQywgCiAgICAgICAgICAgICAgICAgIGNoYWluID0gIlRSQiIsIAogICAgICAgICAgICAgICAgICBhYS5sZW5ndGggPSAyMCkKCgoKIyBwb3NpdGlvbmFsUHJvcGVydHkKCnBvc2l0aW9uYWxQcm9wZXJ0eShjb21iaW5lZC5UQ1JbYygxLDIpXSwgCiAgICAgICAgICAgICAgICAgIGNoYWluID0gIlRSQiIsIAogICAgICAgICAgICAgICAgICBhYS5sZW5ndGggPSAyMCwgCiAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJhdGNobGV5RmFjdG9ycyIpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGhjbC5jb2xvcnMoNSwgImluZmVybm8iKVtjKDIsNCldKQoKCiMgcGVyY2VudEdlbmVVc2FnZQp2aXpHZW5lcyhjb21iaW5lZC5UQ1IsIAogICAgICAgICB4LmF4aXMgPSAiVFJCViIsCiAgICAgICAgIHkuYXhpcyA9IE5VTEwsCiAgICAgICAgIHBsb3QgPSAiYmFycGxvdCIsICAKICAgICAgICAgc3VtbWFyeS5mdW4gPSAicHJvcG9ydGlvbiIpCgp2aXpHZW5lcyhjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCAKICAgICAgICAgeC5heGlzID0gIlRSQlYiLAogICAgICAgICB5LmF4aXMgPSBOVUxMLAogICAgICAgICBwbG90ID0gImJhcnBsb3QiLCAgCiAgICAgICAgIHN1bW1hcnkuZnVuID0gInByb3BvcnRpb24iKQoKCnZpekdlbmVzKGNvbWJpbmVkLlRDUiwgCiAgICAgICAgeC5heGlzID0gIlRSQVYiLAogICAgICAgIHkuYXhpcyA9IE5VTEwsCiAgICAgICAgcGxvdCA9ICJiYXJwbG90IiwgIAogICAgICAgIHN1bW1hcnkuZnVuID0gInByb3BvcnRpb24iKQoKdml6R2VuZXMoY29tYmluZWQuVENSX3dpdGhfUEJNQywgCiAgICAgICAgeC5heGlzID0gIlRSQVYiLAogICAgICAgIHkuYXhpcyA9IE5VTEwsCiAgICAgICAgcGxvdCA9ICJiYXJwbG90IiwgIAogICAgICAgIHN1bW1hcnkuZnVuID0gInByb3BvcnRpb24iKQoKdml6R2VuZXMoY29tYmluZWQuVENSW2MoMSwyLDMsNCw1LDYsNyldLCAKICAgICAgICAgeC5heGlzID0gIlRSQlYiLAogICAgICAgICB5LmF4aXMgPSAiVFJCSiIsCiAgICAgICAgIHBsb3QgPSAiaGVhdG1hcCIsICAKICAgICAgICAgIHN1bW1hcnkuZnVuID0gInBlcmNlbnQiKQoKdml6R2VuZXMoY29tYmluZWQuVENSW2MoMSwyLDMsNCw1LDYsNyldLCAKICAgICAgICAgeC5heGlzID0gIlRSQVYiLAogICAgICAgICB5LmF4aXMgPSAiVFJBSiIsCiAgICAgICAgIHBsb3QgPSAiaGVhdG1hcCIsICAKICAgICAgICAgIHN1bW1hcnkuZnVuID0gInBlcmNlbnQiKQoKIyBGb3IgdGhlIFAxNyBwYXRpZW50IHNhbXBsZXMsIHdoYXQgaWYgd2UgYXJlIGludGVyZXN0ZWQgaW4gY2hhaW4gcGFpcmluZ3MsIHdlIGNhbiBsb29rIGF0IFRSQlYgYW5kIFRSQVYgYXQgdGhlIHNhbWUgdGltZSB1c2luZyB0aGVtIGFzIGlucHV0cyB0byB4LmF4aXMgYW5kIHkuYXhpcy4Kdml6R2VuZXMoY29tYmluZWQuVENSW2MoMSwyKV0sIAogICAgICAgICB4LmF4aXMgPSAiVFJCViIsCiAgICAgICAgIHkuYXhpcyA9ICJUUkFWIiwKICAgICAgICAgcGxvdCA9ICJoZWF0bWFwIiwgCiAgICAgICAgICBzdW1tYXJ5LmZ1biA9ICJwZXJjZW50IikKCiMgcGVyY2VudEdlbmVzOiBRdWFudGlmeWluZyBTaW5nbGUgR2VuZSBVc2FnZQpwZXJjZW50R2VuZXMoY29tYmluZWQuVENSX3dpdGhfUEJNQywgCiAgICAgICAgICAgICBjaGFpbiA9ICJUUkIiLCAKICAgICAgICAgICAgIGdlbmUgPSAiVmdlbmUiLAogICAgICAgICAgICAgIHN1bW1hcnkuZnVuID0gInBlcmNlbnQiKQoKcGVyY2VudEdlbmVzKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgY2hhaW4gPSAiVFJBIiwgCiAgICAgICAgICAgICBnZW5lID0gIlZnZW5lIiwKICAgICAgICAgICAgICBzdW1tYXJ5LmZ1biA9ICJwZXJjZW50IikKCnBlcmNlbnRHZW5lcyhjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCAKICAgICAgICAgICAgIGNoYWluID0gIlRSQiIsIAogICAgICAgICAgICAgZ2VuZSA9ICJKZ2VuZSIpCgpwZXJjZW50R2VuZXMoY29tYmluZWQuVENSX3dpdGhfUEJNQywgCiAgICAgICAgICAgICBjaGFpbiA9ICJUUkEiLCAKICAgICAgICAgICAgIGdlbmUgPSAiSmdlbmUiLAogICAgICAgICAgICAgIHN1bW1hcnkuZnVuID0gInBlcmNlbnQiKQoKCiMgcGVyY2VudFZKCiMgUXVhbnRpZnkgdGhlIHByb3BvcnRpb24gb2YgViBhbmQgSiBnZW5lIHVzYWdlIHdpdGggcGVyY2VudFZKKCkuIExpa2UgcGVyY2VudEdlbmVzKCksIHRoaXMgZnVuY3Rpb24gd2lsbCBxdWFudGlmeSB0aGUgcGVyY2VudGFnZSBvZiBWIGFuZCBKIHBhaXJlZCB0b2dldGhlciBhY3Jvc3MgaW5kaXZpZHVhbCByZXBlcnRvaXJlcy4gVGhlIG91dHB1dCBjYW4gYmUgdmlzdWFsaXplZCB1c2luZyBhIGhlYXRtYXAgb3IgYXMgaW5wdXQgZm9yIGZ1cnRoZXIgZGltZW5zaW9uYWwgcmVkdWN0aW9uLgoKcGVyY2VudFZKKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgY2hhaW4gPSAiVFJCIiwKICAgICAgICAgICBzdW1tYXJ5LmZ1biA9ICJwZXJjZW50IikKCnBlcmNlbnRWSihjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCAKICAgICAgICAgIGNoYWluID0gIlRSQSIsCiAgICAgICAgICAgc3VtbWFyeS5mdW4gPSAicGVyY2VudCIpCgojIHBlcmNlbnRLbWVyCgpwZXJjZW50S21lcihjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCAKICAgICAgICAgICAgY2xvbmVDYWxsID0gImFhIiwKICAgICAgICAgICAgY2hhaW4gPSAiVFJCIiwgCiAgICAgICAgICAgIG1vdGlmLmxlbmd0aCA9IDMsIAogICAgICAgICAgICB0b3AubW90aWZzID0gMjUpCgpwZXJjZW50S21lcihjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCAKICAgICAgICAgICAgY2xvbmVDYWxsID0gImFhIiwKICAgICAgICAgICAgY2hhaW4gPSAiVFJBIiwgCiAgICAgICAgICAgIG1vdGlmLmxlbmd0aCA9IDMsIAogICAgICAgICAgICB0b3AubW90aWZzID0gMjUpCgpwZXJjZW50S21lcihjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCAKICAgICAgICAgICAgY2xvbmVDYWxsID0gIm50IiwKICAgICAgICAgICAgY2hhaW4gPSAiVFJCIiwgCiAgICAgICAgICAgIG1vdGlmLmxlbmd0aCA9IDMsIAogICAgICAgICAgICB0b3AubW90aWZzID0gMjUpCgpwZXJjZW50S21lcihjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCAKICAgICAgICAgICAgY2xvbmVDYWxsID0gIm50IiwKICAgICAgICAgICAgY2hhaW4gPSAiVFJBIiwgCiAgICAgICAgICAgIG1vdGlmLmxlbmd0aCA9IDMsIAogICAgICAgICAgICB0b3AubW90aWZzID0gMjUpCmBgYAojICoqNi4gQ29tcGFyaW5nIENsb25hbCBEaXZlcnNpdHkgYW5kIE92ZXJsYXAqKgpgYGB7ciBjbG9uYWxEaXZlcnNpdHksIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTZ9CiMgY2xvbmFsRGl2ZXJzaXR5CgoKY2xvbmFsRGl2ZXJzaXR5KGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgICAgY2xvbmVDYWxsID0gImdlbmUiKQoKY2xvbmFsRGl2ZXJzaXR5KGNvbWJpbmVkLlRDUiwgCiAgICAgICAgICAgICAgICBjbG9uZUNhbGwgPSAiZ2VuZSIpCgojY2xvbmFsU2l6ZURpc3RyaWJ1dGlvbgoKCmNsb25hbFNpemVEaXN0cmlidXRpb24oY29tYmluZWQuVENSX3dpdGhfUEJNQywgCiAgICAgICAgICAgICAgICAgICAgICAgY2xvbmVDYWxsID0gImFhIiwgCiAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kPSAid2FyZC5EMiIpCgpjbG9uYWxTaXplRGlzdHJpYnV0aW9uKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgICAgICAgICAgIGNsb25lQ2FsbCA9ICJudCIsIAogICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZD0gIndhcmQuRDIiKQoKI2Nsb25hbE92ZXJsYXAKCmNsb25hbE92ZXJsYXAoY29tYmluZWQuVENSX3dpdGhfUEJNQywgCiAgICAgICAgICAgICAgY2xvbmVDYWxsID0gInN0cmljdCIsIAogICAgICAgICAgICAgIG1ldGhvZCA9ICJtb3Jpc2l0YSIpCgoKY2xvbmFsT3ZlcmxhcChjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCAKICAgICAgICAgICAgICBjbG9uZUNhbGwgPSAic3RyaWN0IiwgCiAgICAgICAgICAgICAgbWV0aG9kID0gInJhdyIpCmBgYAoKIyAqKjcuIENvbWJpbmluZyBDbG9uZXMgYW5kIFNpbmdsZS1DZWxsIE9iamVjdHMqKgpgYGB7ciBTQywgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CgojIENvbWJpbmluZyBDbG9uZXMgYW5kIFNpbmdsZS1DZWxsIE9iamVjdHMKCiNHZXR0aW5nIGEgc2FtcGxlIG9mIGEgU2V1cmF0IG9iamVjdApUQ1IgPC0gZ2V0KGRhdGEoIkFsbF9zYW1wbGVzX01lcmdlZCIpKQoKCiNEZWZpbmUgY29sb3IgcGFsZXR0ZSAKY29sb3JibGluZF92ZWN0b3IgPC0gaGNsLmNvbG9ycyhuPTcsIHBhbGV0dGUgPSAiaW5mZXJubyIsIGZpeHVwID0gVFJVRSkKCgpUQ1IgPC0gY29tYmluZUV4cHJlc3Npb24oY29tYmluZWQuVENSX3dpdGhfUEJNQywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVENSLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbG9uZUNhbGw9ImdlbmUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cC5ieSA9ICJzYW1wbGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9wb3J0aW9uID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsb25lU2l6ZT1jKFNpbmdsZT0xLCBTbWFsbD01LCBNZWRpdW09MjAsIExhcmdlPTEwMCxIeXBlcmV4cGFuZGVkPTUwMCkpCgoKCkRpbVBsb3Qoc3Vic2V0KFRDUiwgIWlzLm5hKGNsb25lU2l6ZSkpLCAKICAgICAgICBncm91cC5ieSA9ICJjbG9uZVNpemUiLCAKICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIpCgojIERpbVBsb3QoVENSLCBncm91cC5ieSA9ICJjbG9uZVNpemUiLCByZWR1Y3Rpb24gPSAidW1hcCIpICsKIyAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1yZXYoY29sb3JibGluZF92ZWN0b3JbYygxLDMsNCw1LDYpXSkpCiMgCiMgVENSJENUZ2VuZQojIAojIAojICNEZWZpbmUgY29sb3IgcGFsZXR0ZSAKIyBjb2xvcmJsaW5kX3ZlY3RvciA8LSBoY2wuY29sb3JzKG49OSwgcGFsZXR0ZSA9ICJpbmZlcm5vIiwgZml4dXAgPSBUUlVFKQojIAojIFNldXJhdDo6RGltUGxvdChUQ1IsIGdyb3VwLmJ5ID0gImNsb25lU2l6ZSIsIHJlZHVjdGlvbiA9ICJ1bWFwIikgKwojICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPXJldihjb2xvcmJsaW5kX3ZlY3RvcltjKDEsMyw0LDUsNyldKSkKYGBgCiMgKio4LiBWaXN1YWxpemF0aW9ucyBmb3IgU2luZ2xlLUNlbGwgT2JqZWN0cyoqCmBgYHtyIFZfc2MsIGZpZy5oZWlnaHQ9MTQsIGZpZy53aWR0aD0xOH0KCiMgVmlzdWFsaXphdGlvbnMgZm9yIFNpbmdsZS1DZWxsIE9iamVjdHMKIyBjbG9uYWxPdmVybGF5CgojQWRkaW5nIHBhdGllbnQgaW5mb3JtYXRpb24Kc2NSZXBfZXhhbXBsZSRQYXRpZW50X29yaWdpbiA8LSBzdWJzdHIoc2NSZXBfZXhhbXBsZSRvcmlnLmlkZW50LCAxLDMpCgpjbG9uYWxPdmVybGF5KHNjUmVwX2V4YW1wbGUsIAogICAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwgCiAgICAgICAgICAgICAgY3V0cG9pbnQgPSAxLCAKICAgICAgICAgICAgICBiaW5zID0gMTAsIAogICAgICAgICAgICAgIGZhY2V0LmJ5ID0gIlBhdGllbnRfb3JpZ2luIikgKyAKICAgICAgICAgICAgICBndWlkZXMoY29sb3IgPSAibm9uZSIpCgoKCmNsb25hbE92ZXJsYXkoc2NSZXBfZXhhbXBsZSwgCiAgICAgICAgICAgICAgcmVkdWN0aW9uID0gInVtYXAiLCAKICAgICAgICAgICAgICBjdXRwb2ludCA9IDEsIAogICAgICAgICAgICAgIGJpbnMgPSAxMCwgCiAgICAgICAgICAgICAgZmFjZXQuYnkgPSAiY2VsbF9saW5lIikgKyAKICAgICAgICAgICAgICBndWlkZXMoY29sb3IgPSAibm9uZSIpCgojY2xvbmFsTmV0d29yawojZ2dyYXBoIG5lZWRzIHRvIGJlIGxvYWRlZCBkdWUgdG8gaXNzdWVzIHdpdGggZ2dwbG90CmxpYnJhcnkoZ2dyYXBoKQoKY2xvbmFsTmV0d29yayhzY1JlcF9leGFtcGxlLCAKICAgICAgICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsIAogICAgICAgICAgICAgIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVycyIsCiAgICAgICAgICAgICAgZmlsdGVyLmNsb25lcyA9IE5VTEwsCiAgICAgICAgICAgICAgZmlsdGVyLmlkZW50aXR5ID0gTlVMTCwKICAgICAgICAgICAgICBjbG9uZUNhbGwgPSAiYWEiKQoKCiNFeGFtaW5pbmcgQ2x1c3RlciAzIG9ubHkKY2xvbmFsTmV0d29yayhzY1JlcF9leGFtcGxlLCAKICAgICAgICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsIAogICAgICAgICAgICAgIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVycyIsCiAgICAgICAgICAgICAgZmlsdGVyLmlkZW50aXR5ID0gOCwKICAgICAgICAgICAgICBjbG9uZUNhbGwgPSAiYWEiKQoKCnNoYXJlZC5jbG9uZXMgPC0gY2xvbmFsTmV0d29yayhzY1JlcF9leGFtcGxlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cC5ieSA9ICJzZXVyYXRfY2x1c3RlcnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xvbmVDYWxsID0gImFhIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHBvcnRDbG9uZXMgPSBUUlVFKQpoZWFkKHNoYXJlZC5jbG9uZXMpCgoKc2NSZXBfZXhhbXBsZSA8LSBoaWdobGlnaHRDbG9uZXMoc2NSZXBfZXhhbXBsZSwgCiAgICAgICAgICAgICAgICAgICAgY2xvbmVDYWxsPSAiYWEiLCAKICAgICAgICAgICAgICAgICAgICBzZXF1ZW5jZSA9IGMoIkNBVEdQTkdTU05UR0tMSUY7Q0FMU05OQVJMTUZfQ1NBVFRHRllHWVRGIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDQVlTRVNHR1NOWUtMVEZfQ1NBTEFHR1lURFRRWUYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ0xWR0VUR1JSQUxURl9DU0FSR0RSR1FQUUhGIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNMVkdFVEdSUkFMVEZfQ1NBUkdEUkdRUFFIRjtDQVRTREZLUVZTTlFQUUhGIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNBVEdQTkdTU05UR0tMSUZfQ1NBVFRHRllHWVRGIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5BX0NTQVJHRFJHUVBRSEYiKSkKClNldXJhdDo6RGltUGxvdChzY1JlcF9leGFtcGxlLCBncm91cC5ieSA9ICJoaWdobGlnaHQiLCByZWR1Y3Rpb24gPSAidW1hcCIpICsgCiAgZ2dwbG90Mjo6dGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKCiNjbG9uYWxPY2N1cHkKY2xvbmFsT2NjdXB5KHNjUmVwX2V4YW1wbGUsIAogICAgICAgICAgICAgIHguYXhpcyA9ICJzZXVyYXRfY2x1c3RlcnMiKQoKY2xvbmFsT2NjdXB5KHNjUmVwX2V4YW1wbGUsIAogICAgICAgICAgICAgICAgICAgICB4LmF4aXMgPSAiaWRlbnQiLCAKICAgICAgICAgICAgICAgICAgICAgcHJvcG9ydGlvbiA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IEZBTFNFKQojIGFsbHV2aWFsQ2xvbmVzCgojIHNjUmVwX2V4YW1wbGUkUGF0aWVudF9vcmlnaW4gPC0gc3Vic3RyKHNjUmVwX2V4YW1wbGUkb3JpZy5pZGVudCwgOCw4KQojIAojIGFsbHV2aWFsQ2xvbmVzKHNjUmVwX2V4YW1wbGUsIAojICAgICAgICAgICAgICAgIGNsb25lQ2FsbCA9ICJhYSIsIAojICAgICAgICAgICAgICAgIHkuYXhlcyA9IGMoIlBhdGllbnRfb3JpZ2luIiwgIm9yaWcuaWRlbnQiLCAiQ2VsbF9saW5lX0ltbXVub3BoZW5vdHlwZSIpLCAKIyAgICAgICAgICAgICAgICBjb2xvciA9IGMoIkNBVEdQTkdTU05UR0tMSUY7Q0FMU05OQVJMTUZfQ1NBVFRHRllHWVRGIiwgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNBWVNFU0dHU05ZS0xURl9DU0FMQUdHWVREVFFZRiIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNMVkdFVEdSUkFMVEZfQ1NBUkdEUkdRUFFIRiIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNMVkdFVEdSUkFMVEZfQ1NBUkdEUkdRUFFIRjtDQVRTREZLUVZTTlFQUUhGIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ0FUR1BOR1NTTlRHS0xJRl9DU0FUVEdGWUdZVEYiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOQV9DU0FSR0RSR1FQUUhGIikpICsgCiMgICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImdyZXkiLCBjb2xvcmJsaW5kX3ZlY3RvclszXSkpCiMgCiMgCiMgCiMgYWxsdXZpYWxDbG9uZXMoc2NSZXBfZXhhbXBsZSwgCiMgICAgICAgICAgICAgICAgICAgIGNsb25lQ2FsbCA9ICJnZW5lIiwgCiMgICAgICAgICAgICAgICAgICAgIHkuYXhlcyA9IGMoIlBhdGllbnRfb3JpZ2luIiwgIm9yaWcuaWRlbnQiLCAiQ2VsbF9saW5lX0ltbXVub3BoZW5vdHlwZSIpLCAKIyAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiaWRlbnQiKSAKCgoKbGlicmFyeShjaXJjbGl6ZSkKbGlicmFyeShzY2FsZXMpCgpjaXJjbGVzIDwtIGdldENpcmNsaXplKHNjUmVwX2V4YW1wbGUsIAogICAgICAgICAgICAgICAgICAgICAgIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVycyIpCgojSnVzdCBhc3NpZ25pbmcgdGhlIG5vcm1hbCBjb2xvcnMgdG8gZWFjaCBjbHVzdGVyCmdyaWQuY29scyA8LSBodWVfcGFsKCkobGVuZ3RoKHVuaXF1ZShzY1JlcF9leGFtcGxlJHNldXJhdF9jbHVzdGVycykpKQpuYW1lcyhncmlkLmNvbHMpIDwtIHVuaXF1ZShzY1JlcF9leGFtcGxlJHNldXJhdF9jbHVzdGVycykKCiNHcmFwaGluZyB0aGUgY2hvcmQgZGlhZ3JhbQpjaG9yZERpYWdyYW0oY2lyY2xlcywgc2VsZi5saW5rID0gMSwgZ3JpZC5jb2wgPSBncmlkLmNvbHMpCgoKY2lyY2xlcyA8LSBnZXRDaXJjbGl6ZShzY1JlcF9leGFtcGxlLCBncm91cC5ieSA9ICJjZWxsX2xpbmUiKQoKZ3JpZC5jb2xzIDwtIHNjYWxlczo6aHVlX3BhbCgpKGxlbmd0aCh1bmlxdWUoc2NSZXBfZXhhbXBsZUBhY3RpdmUuaWRlbnQpKSkKbmFtZXMoZ3JpZC5jb2xzKSA8LSBsZXZlbHMoc2NSZXBfZXhhbXBsZUBhY3RpdmUuaWRlbnQpCgpjaG9yZERpYWdyYW0oY2lyY2xlcywgCiAgICAgICAgICAgICBzZWxmLmxpbmsgPSAxLCAKICAgICAgICAgICAgIGdyaWQuY29sID0gZ3JpZC5jb2xzKQoKYGBgCgoKCiMgKio5LiBRdWFudGlmeWluZyBDbG9uYWwgQmlhcyoqCgoqKiMgIyBTdGFydHJhY0RpdmVyc2l0eQojIEZyb20gdGhlIGV4Y2VsbGVudCB3b3JrIGJ5IExlaSBaaGFuZywgZXQgYWwuLCB0aGUgYXV0aG9ycyBpbnRyb2R1Y2UgbmV3IG1ldGhvZHMgZm9yIGxvb2tpbmcgYXQgY2xvbmVzIGJ5IGNlbGx1bGFyIG9yaWdpbnMgYW5kIGNsdXN0ZXIgaWRlbnRpZmljYXRpb24uIFRoZWlyIFNUQVJUUkFDIHNvZnR3YXJlIGhhcyBiZWVuIGFkYXB0ZWQgdG8gd29yayB3aXRoIHNjUmVwZXJ0b2lyZSBhbmQgcGxlYXNlIHJlYWQgYW5kIGNpdGUgdGhlaXIgZXhjZWxsZW50IHdvcmsuCiMgCiMgSW4gb3JkZXIgdG8gdXNlIHRoZSBTdGFydHJhY0RpdmVyc2l0eSgpIGZ1bmN0aW9uLCB5b3Ugd2lsbCBuZWVkIHRvIGluY2x1ZGUgdGhlIHByb2R1Y3Qgb2YgdGhlIGNvbWJpbmVkRXhwcmVzc2lvbigpIGZ1bmN0aW9uLiBUaGUgc2Vjb25kIHJlcXVpcmVtZW50IGlzIGEgY29sdW1uIGhlYWRlciBpbiB0aGUgbWV0YSBkYXRhIG9mIHRoZSBTZXVyYXQgb2JqZWN0IHRoYXQgaGFzIHRpc3N1ZSBvZiBvcmlnaW4uIEluIHRoZSBleGFtcGxlIGRhdGEsIHR5cGUgY29ycmVzcG9uZHMgdG8gdGhlIGNvbHVtbiDigJxUeXBl4oCdLCB3aGljaCBpbmNsdWRlcyB0aGUg4oCcUOKAnSBhbmQg4oCcVOKAnSBjbGFzc2lmaWVycy4gVGhlIGluZGljZXMgY2FuIGJlIHN1YnNldHRlZCBmb3IgYSBzcGVjaWZpYyBwYXRpZW50IG9yIGV4YW1pbmVkIG92ZXJhbGwgdXNpbmcgdGhlIGJ5IHZhcmlhYmxlLiBJbXBvcnRhbnRseSwgdGhlIGZ1bmN0aW9uIHVzZXMgb25seSB0aGUgc3RyaWN0IGRlZmluaXRpb24gb2YgYSBjbG9uZSBvZiB0aGUgVkRKQyBnZW5lcyBhbmQgdGhlIENEUjMgbnVjbGVvdGlkZSBzZXF1ZW5jZS4KIyAKIyBUaGUgaW5kaWNlcyBvdXRwdXQgaW5jbHVkZXM6CiMgCiMgZXhwYSAtIENsb25hbCBFeHBhbnNpb24KIyBtaWdyIC0gQ3Jvc3MtdGlzc3VlIE1pZ3JhdGlvbgojIHRyYW4gLSBTdGF0ZSBUcmFuc2l0aW9uCioqCgoKYGBge3IgUXVhdGlmeSwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CgoKU3RhcnRyYWNEaXZlcnNpdHkoc2NSZXBfZXhhbXBsZSwgCiAgICAgICAgICAgICAgICAgIHR5cGUgPSAiUGF0aWVudF9vcmlnaW4iLAogICAgICAgICAgICAgICAgICBncm91cC5ieSA9ICJjZWxsX2xpbmUiKQoKClN0YXJ0cmFjRGl2ZXJzaXR5KHNjUmVwX2V4YW1wbGUsIAogICAgICAgICAgICAgICAgICB0eXBlID0gImNlbGxfbGluZSIsCiAgICAgICAgICAgICAgICAgIGdyb3VwLmJ5ID0gImNlbGxfbGluZSIpCgoKYGBgCiMgKioxMC4gY2xvbmFsQmlhcyoqCmBgYHtyIFF1YXRpZnkyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMn0KCgpjbG9uYWxCaWFzKHNjUmVwX2V4YW1wbGUsIAogICAgICAgICAgIGNsb25lQ2FsbCA9ICJhYSIsIAogICAgICAgICAgIHNwbGl0LmJ5ID0gImNlbGxfbGluZSIsIAogICAgICAgICAgIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVycyIsCiAgICAgICAgICAgbi5ib290cyA9IDEwLCAKICAgICAgICAgICBtaW4uZXhwYW5kID01KQoKYGBg