Introduction

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.

Load libraries

Load Seurat Object

1. Load contigs

Provide one local Cell Ranger `filtered_contig_annotations.csv` file for each sample. The source expects data frames named L1, L2, L3_B, L4_B, L5, L6, L7, and PBMC. Replace the `path/to/...` placeholders with your own paths. The original network locations were machine-specific and are not included.

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


contig_list <- list(L1, L2, L3_B, L4_B,L5,L6, L7)
contig_list_with_PBMC <- list(L1, L2, L3_B, L4_B,L5,L6, L7, PBMC)

combined.TCR <- combineTCR(contig_list,
                           samples = c("L1", "L2", "L3_B", "L4_B", "L5", "L6", "L7"),
                           removeNA = FALSE,
                           removeMulti = FALSE,
                           filterMulti = FALSE)

combined.TCR_with_PBMC <- combineTCR(contig_list_with_PBMC, 
                           samples = c("L1", "L2", "L3_B", "L4_B", "L5", "L6", "L7", 
                                       "PBMC"),
                           removeNA = FALSE, 
                           removeMulti = FALSE, 
                           filterMulti = FALSE)

#  exportClones(combined.TCR, 
#               write.file = TRUE,
#               dir = "../TCR_Analysis/",
#              file.name = "clones.csv")
# 
# exportClones(combined.TCR_with_PBMC, 
#              write.file = TRUE,
#              dir = "../TCR_Analysis/",
#              file.name = "clones_with_PBMC.csv")

head(combined.TCR_with_PBMC[[1]])
NA

3. Basic Clonal Visualizations

3.1. clonalQuant

#clonalQuant

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



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


clonalQuant(combined.TCR, cloneCall = "gene", group.by = "sample", scale = TRUE)


clonalQuant(combined.TCR_with_PBMC, cloneCall = "gene", group.by = "sample", scale = TRUE)

NA
NA

3.2 clonalAbundance

#clonalAbundance

clonalAbundance(combined.TCR_with_PBMC, 
                cloneCall = "gene",  palette = "Zissou 1",
                scale = FALSE)+ 
  scale_fill_manual(values = hcl.colors(8,"geyser"))

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

3.3 clonalLength

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

clonalLength(combined.TCR_with_PBMC, 
             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) 

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

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

3.4 clonalCompare

# clonalCompare


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


clonalCompare(combined.TCR_with_PBMC, 
                  top.clones = 10, 
                  samples = c("L3_B", "L4_B"), 
                  cloneCall="aa", 
                  graph = "alluvial")


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



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


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


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


clonalCompare(combined.TCR_with_PBMC, 
                  top.clones = 10, 
                  samples = c("L1", "L2", "L3_B", "L4_B", "L5", "L6", "L7", "PBMC"), 
                  cloneCall="aa", 
                  graph = "alluvial")


# clonalCompare(combined.TCR_with_PBMC, 
#               top.clones = 10,
#               highlight.clones = c("CVVSDNTGGFKTIF_CASSVRRERANTGELFF", "NA_CASSVRRERANTGELFF"),
#               relabel.clones = TRUE,
#               samples = c("L1", "L2"), 
#               cloneCall="aa", 
#               graph = "alluvial")
# 
# 
# clonalCompare(combined.TCR_with_PBMC, clones = c("CVVSDNTGGFKTIF_CASSVRRERANTGELFF", "NA_CASSVRRERANTGELFF"),
#     relabel.clones = TRUE, samples = c("L1", "L2"), cloneCall = "aa", graph = "alluvial")

3.5 clonalScatter

#clonalScatter

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



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


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


clonalScatter(combined.TCR_with_PBMC, 
              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

# Visualizing Clonal Dynamics

# clonalHomeostasis

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



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

4.2 clonalProportion

# clonalProportion

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




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

NA
NA
NA

5. Summarizing Repertoires

Saved-output note: the embedded `percentAA()` and `positionalEntropy()` output records repeated "Warning: invalid factor level, NA generated" messages. Those cached outputs are not revalidated here.

# Summarizing Repertoires

#percentAA

percentAA(combined.TCR, 
          chain = "TRB", 
          aa.length = 20)
Warning: invalid factor level, NA generatedWarning: invalid factor level, NA generatedWarning: invalid factor level, NA generatedWarning: invalid factor level, NA generatedWarning: invalid factor level, NA generatedWarning: invalid factor level, NA generated

# positionalEntropy
# We can also quantify the level of entropy/diversity across amino acid residues along the cdr3 sequence. positionalEntropy() combines the quantification by residue of percentAA() with the diversity calls in clonalDiversity().
# 
# method
# 
# “shannon” - Shannon Diversity
# “inv.simpson” - Inverse Simpson Diversity
# “norm.entropy” - Normalized Entropy

positionalEntropy(combined.TCR_with_PBMC, 
                  chain = "TRB", 
                  aa.length = 20)
Warning: invalid factor level, NA generatedWarning: invalid factor level, NA generatedWarning: invalid factor level, NA generatedWarning: invalid factor level, NA generatedWarning: invalid factor level, NA generatedWarning: invalid factor level, NA generated

# positionalProperty
# Like positionalEntropy(), we can also examine a series of amino acid properties along the cdr3 sequences using positionalProperty(). Important differences from the above function for positionalProperty() is dropping NA values as they would void the mean calculation. positionalProperty() also display a ribbon with the 95% confidence interval surrounding the mean value for the selected properties.
# 
# method
# 
# “Atchley” - Atchley Factors
# “Kidera” - Kidera Factors
# “stScales” - stScales Vectors
# “tScales” - tScales Vectors
# “VHSE” - Vectors of Hydrophobic, Steric, and Electronic properties

# positionalProperty(combined.TCR_with_PBMC[c(1,2)], 
#                   chain = "TRB", 
#                   aa.length = 20, 
#                   method = "Atchley") + 
#   scale_color_manual(values = hcl.colors(5, "inferno")[c(2,4)])
# 
# positionalProperty(combined.TCR_with_PBMC[c(3,4)], 
#                   chain = "TRB", 
#                   aa.length = 20, 
#                   method = "Atchley") + 
#   scale_color_manual(values = hcl.colors(5, "inferno")[c(2,4)])
# 
# positionalProperty(combined.TCR_with_PBMC[c(5,6)], 
#                   chain = "TRB", 
#                   aa.length = 20, 
#                   method = "Atchley") + 
#   scale_color_manual(values = hcl.colors(5, "inferno")[c(2,4)])
# 
# positionalProperty(combined.TCR_with_PBMC[c(5,7)], 
#                   chain = "TRB", 
#                   aa.length = 20, 
#                   method = "Atchley") + 
#   scale_color_manual(values = hcl.colors(5, "inferno")[c(2,4)])
# 
# 
# positionalProperty(combined.TCR_with_PBMC[c(6,7)], 
#                   chain = "TRB", 
#                   aa.length = 20, 
#                   method = "Atchley") + 
#   scale_color_manual(values = hcl.colors(5, "inferno")[c(2,4)])
# 
# positionalProperty(combined.TCR_with_PBMC[c(5,6,7)], 
#                   chain = "TRB", 
#                   aa.length = 20, 
#                   method = "Atchley") + 
#   scale_color_manual(values = hcl.colors(5, "inferno")[c(2,4)])


# vizGenes
# A visualization of the relative usage of genes of the TCR or BCR, using vizGenes(). There is some functional crossover between vizGenes() and two functions below called percentGenes() and percentVJ(). But vizGenes() is more adaptable to allow for comparisons across chains, scaling, etc.

vizGenes(combined.TCR_with_PBMC, 
         x.axis = "TRBV",
         y.axis = NULL,
         plot = "barplot",  
         scale = TRUE)




vizGenes(combined.TCR_with_PBMC, 
        x.axis = "TRAV",
        y.axis = NULL,
        plot = "barplot",  
        scale = TRUE)



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


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


# 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", 
         scale = FALSE)



# percentGenes
# Quantify the proportion of V or J gene usage with percentGenes(). Like percentAA(), we select the chain of interest and then indicate the gene of interest with the gene parameter. Two major limitations of percentGenes() are, 1) the function quantifies only V or J genes, and 2) the quantification of the genes are limited to all the V or J genes seen across the samples, not all possible V or J genes.

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


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



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


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



# 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")


percentVJ(combined.TCR_with_PBMC, 
          chain = "TRA")



# percentKmer
# Another quantification of the composition of the CDR3 sequence is to define motifs by sliding across the amino acid or nucleotide sequences at set intervals resulting in substrings or kmers.
# 
# motif.length
# 
# Numerical value for the length of the kmer.
# top.motifs
# 
# Display the most variable genes determined by mean absolute deviation (MAD).
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)

NA
NA
NA
NA
NA
NA
NA
NA
NA

6. Comparing Clonal Diversity and Overlap

# clonalDiversity


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


#clonalSizeDistribution


clonalSizeDistribution(combined.TCR_with_PBMC, 
                       cloneCall = "aa", 
                       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

Before running this section, assign a compatible Seurat object to `scRep_example`. The source later uses `sample`, `orig.ident`, `seurat_clusters`, `cell_line`, active identities, and a `umap` reduction. The warning below was captured from the earlier lookup `get(data("All_samples_Merged"))`, which reported "data set 'All_samples_Merged' not found". It does not establish a successful object load. The saved single-cell plots remain gallery references until the required object is supplied and the sections are rerun.


# Combining Clones and Single-Cell Objects

#Getting a sample of a Seurat object
# The saved attempt could not find a packaged data set named All_samples_Merged.
# Supply a compatible Seurat object as scRep_example before running this section.
if (!exists("scRep_example", inherits = TRUE)) {
  stop("Assign a compatible Seurat object to scRep_example before running this section.")
}
Warning: data set 'All_samples_Merged' not found
#Define color palette 
colorblind_vector <- hcl.colors(n=7, palette = "inferno", fixup = TRUE)


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

DimPlot(scRep_example, group.by = "cloneSize")


DimPlot(scRep_example, group.by = "cloneSize") +
    scale_color_manual(values=rev(colorblind_vector[c(1,3,4,5,6)]))

NA
NA

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", 
              freq.cutpoint = 1, 
              bins = 10, 
              facet.by = "Patient_origin") + 
              guides(color = "none")


#clonalNetwork
#ggraph needs to be loaded due to issues with ggplot
library(ggraph)

Attaching package: 'ggraph'

The following object is masked from 'package:sp':

    geometry
clonalNetwork(scRep_example, 
              reduction = "umap", 
              group.by = "seurat_clusters",
              filter.clones = NULL,
              filter.identity = NULL,
              cloneCall = "aa")



#Examining Cluster 3 only
clonalNetwork(scRep_example, 
              reduction = "umap", 
              group.by = "seurat_clusters",
              filter.identity = 8,
              cloneCall = "aa")



shared.clones <- clonalNetwork(scRep_example, 
                               reduction = "umap", 
                               group.by = "seurat_clusters",
                               cloneCall = "aa", 
                               exportClones = TRUE)
head(shared.clones)


scRep_example <- highlightClones(scRep_example, 
                    cloneCall= "aa", 
                    sequence = c("CATGPNGSSNTGKLIF;CALSNNARLMF_CSATTGFYGYTF", 
                                 "CAYSESGGSNYKLTF_CSALAGGYTDTQYF",
                                 "CLVGETGRRALTF_CSARGDRGQPQHF",
                                 "CLVGETGRRALTF_CSARGDRGQPQHF;CATSDFKQVSNQPQHF",
                                 "CATGPNGSSNTGKLIF_CSATTGFYGYTF",
                                 "NA_CSARGDRGQPQHF"
                                 
                                 
                                 
                                 
                                 ))

Seurat::DimPlot(scRep_example, group.by = "highlight") + 
  ggplot2::theme(plot.title = element_blank())



#clonalOccupy
clonalOccupy(scRep_example, 
              x.axis = "seurat_clusters")



clonalOccupy(scRep_example, 
                     x.axis = "ident", 
                     proportion = TRUE, 
                     label = FALSE)

# alluvialClones


# scRep_example$Patient_origin <- substr(scRep_example$orig.ident, 8,8)
# 
# alluvialClones(scRep_example, 
#                cloneCall = "aa", 
#                y.axes = c("Patient_origin", "orig.ident", "Cell_line_Immunophenotype"), 
#                color = c("CATGPNGSSNTGKLIF;CALSNNARLMF_CSATTGFYGYTF", 
#                                  "CAYSESGGSNYKLTF_CSALAGGYTDTQYF",
#                                  "CLVGETGRRALTF_CSARGDRGQPQHF",
#                                  "CLVGETGRRALTF_CSARGDRGQPQHF;CATSDFKQVSNQPQHF",
#                                  "CATGPNGSSNTGKLIF_CSATTGFYGYTF",
#                                  "NA_CSARGDRGQPQHF")) + 
#     scale_fill_manual(values = c("grey", colorblind_vector[3]))
# 
# 
# 
# alluvialClones(scRep_example, 
#                    cloneCall = "gene", 
#                    y.axes = c("Patient_origin", "orig.ident", "Cell_line_Immunophenotype"), 
#                    color = "ident") 



#getCirclize

library(circlize)
========================================
circlize version 0.4.16
CRAN page: https://cran.r-project.org/package=circlize
Github page: https://github.com/jokergoo/circlize
Documentation: https://jokergoo.github.io/circlize_book/book/

If you use it in published research, please cite:
Gu, Z. circlize implements and enhances circular visualization
  in R. Bioinformatics 2014.

This message can be suppressed by:
  suppressPackageStartupMessages(library(circlize))
========================================
library(scales)

Attaching package: 'scales'

The following object is masked from 'package:purrr':

    discard

The following object is masked from 'package:readr':

    col_factor
circles <- getCirclize(scRep_example, 
                       group.by = "seurat_clusters")

#Just assigning the normal colors to each cluster
grid.cols <- hue_pal()(length(unique(scRep_example$seurat_clusters)))
names(grid.cols) <- unique(scRep_example$seurat_clusters)

#Graphing the chord diagram
chordDiagram(circles, self.link = 1, grid.col = grid.cols)








circles <- getCirclize(scRep_example, group.by = "cell_line", proportion = TRUE)

grid.cols <- scales::hue_pal()(length(unique(scRep_example@active.ident)))
names(grid.cols) <- levels(scRep_example@active.ident)

chordDiagram(circles, 
             self.link = 1, 
             grid.col = grid.cols, 
             directional = 1, 
             direction.type =  "arrows",
             link.arr.type = "big.arrow")

NA
NA
NA
NA
LS0tCnRpdGxlOiAiVENSIEFuYWx5c2lzIgphdXRob3I6ICJOYXNpciBNYWhtb29kIEFiYmFzaSIKZGF0ZTogIjIwMjQtMDQtMTkiCm91dHB1dDoKICBodG1sX25vdGVib29rOiAKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfY29sbGFwc2VkOiB0cnVlCiAgICB0aGVtZTogZGFya2x5CiAgIAotLS0KCj4gKipTdGF0dXM6IHBhcnRpYWwgcmVmZXJlbmNlIG9ubHkuKiogVGhpcyBIVE1MIGNvbnRhaW5zIDUxIHNhdmVkIHBsb3RzLCBub3QgdmVyaWZpZWQgcmVydW5zLiBSZXByb2R1Y3Rpb24gbmVlZHMgZWlnaHQgQ2VsbCBSYW5nZXIgY29udGlnIGZpbGVzIGFuZCBhIGNvbXBhdGlibGUgU2V1cmF0IG9iamVjdCwgbm9uZSBpbmNsdWRlZCBoZXJlLiBTaXggb3V0cHV0IGJsb2NrcyBjb250YWluIG9ubHkgTkEuIFNhdmVkIG91dHB1dCBhbHNvIHJlY29yZHMgaW52YWxpZCBmYWN0b3IgbGV2ZWxzLCB0aGUgbWlzc2luZyBgQWxsX3NhbXBsZXNfTWVyZ2VkYCBkYXRhc2V0LCBhbmQgc2l4IG5vbi1maW5pdGUgcm93cyByZW1vdmVkIGJ5IGEgYm94cGxvdDsgYWZmZWN0ZWQgcGFuZWxzIGFyZSB1bnZlcmlmaWVkLgoKIyBJbnRyb2R1Y3Rpb24KCioqc2NSZXBlcnRvaXJlIGlzIGRlc2lnbmVkIHRvIHRha2UgZmlsdGVyIGNvbnRpZyBvdXRwdXRzIGZyb20gdGhlIDEweCBHZW5vbWljcyBDZWxsIFJhbmdlciBwaXBlbGluZSwgcHJvY2VzcyB0aGF0IGRhdGEgdG8gYXNzaWduIGNsb25vdHlwZSBiYXNlZCBvbiB0d28gVENSIG9yIElnIGNoYWlucyBhbmQgYW5hbHl6ZSB0aGUgY2xvbm90eXBlIGR5bmFtaWNzLiBUaGUgbGF0dGVyIGNhbiBiZSBzZXBhcmF0ZWQgaW50byAxKSBjbG9ub3R5cGUtb25seSBhbmFseXNpcyBmdW5jdGlvbnMsIHN1Y2ggYXMgdW5pcXVlIGNsb25vdHlwZXMgb3IgY2xvbmFsIHNwYWNlIHF1YW50aWZpY2F0aW9uLCBhbmQgMikgaW50ZXJhY3Rpb24gd2l0aCBtUk5BIGV4cHJlc3Npb24gZGF0YSB1c2luZyBTZXVyYXQgb3IgU2luZ2xlQ2VsbEV4cGVyaW1lbnQgcGFja2FnZXMuKioKCiMgTG9hZCBsaWJyYXJpZXMKCmBgYHtyIGxpYnJhcmllcywgaW5jbHVkZT1GQUxTRX0KCmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KFNldXJhdE9iamVjdCkKbGlicmFyeShTZXVyYXRPYmplY3QpCmxpYnJhcnkoU2V1cmF0RGF0YSkKCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KEF6aW11dGgpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkocm1hcmtkb3duKQpsaWJyYXJ5KHRpbnl0ZXgpCgpsaWJyYXJ5KGdyaWQpCmxpYnJhcnkoY293cGxvdCkKbGlicmFyeShwcmVzdG8pCiNUQ1IgQW5hbHlzaXMKbGlicmFyeShzY1JlcGVydG9pcmUpCmxpYnJhcnkoU2luZ2xlQ2VsbEV4cGVyaW1lbnQpCgpsaWJyYXJ5KGNpcmNsaXplKQpsaWJyYXJ5KHNjYWxlcykKYGBgCgojIExvYWQgU2V1cmF0IE9iamVjdAoKYGBge3IgbG9hZF9zZXVyYXQsIGluY2x1ZGU9RkFMU0V9CgojTG9hZCBTZXVyYXQgT2JqZWN0IG1lcmdlZCBmcm9tIGNlbGwgbGluZXMgYW5kIGEgY29udHJvbChQQk1DKSBhZnRlciBmaWx0cmF0aW9uCiMgVGhpcyBvYmplY3QgaXMgbm90IGluY2x1ZGVkLiBSZXBsYWNlIHRoZSBwbGFjZWhvbGRlciB3aXRoIHlvdXIgbG9jYWwgbWVyZ2VkIFNldXJhdCBSb2JqIGZpbGUuCm1lcmdlZF9zZXVyYXRfb2JqZWN0X3BhdGggPC0gInBhdGgvdG8veW91cl9tZXJnZWRfc2V1cmF0X29iamVjdC5Sb2JqIgppZiAoIWZpbGUuZXhpc3RzKG1lcmdlZF9zZXVyYXRfb2JqZWN0X3BhdGgpKSB7CiAgc3RvcCgiU2V0IG1lcmdlZF9zZXVyYXRfb2JqZWN0X3BhdGggdG8gdGhlIGxvY2FsIFNldXJhdCBvYmplY3QgYmVmb3JlIHJ1bm5pbmcuIikKfQpsb2FkKG1lcmdlZF9zZXVyYXRfb2JqZWN0X3BhdGgpCgpgYGAKCiMgMS4gTG9hZCBjb250aWdzCgpQcm92aWRlIG9uZSBsb2NhbCBDZWxsIFJhbmdlciBgZmlsdGVyZWRfY29udGlnX2Fubm90YXRpb25zLmNzdmAgZmlsZSBmb3IgZWFjaCBsaXN0ZWQgc2FtcGxlLiBUaGUgY29kZSBiZWxvdyBleHBlY3RzIGRhdGEgZnJhbWVzIG5hbWVkIEwxLCBMMiwgTDNfQiwgTDRfQiwgTDUsIEw2LCBMNywgYW5kIFBCTUMuIFJlcGxhY2UgdGhlIGBwYXRoL3RvLy4uLmAgcGxhY2Vob2xkZXJzIHdpdGggeW91ciBvd24gcGF0aHMuIFRoZSBvcmlnaW5hbCBuZXR3b3JrIGxvY2F0aW9ucyB3ZXJlIG1hY2hpbmUtc3BlY2lmaWMgYW5kIGFyZSBub3QgaW5jbHVkZWQuCgoKKipzY1JlcGVydG9pcmUgZnVuY3Rpb25zIHVzaW5nIHRoZSBmaWx0ZXJlZF9jb250aWdfYW5ub3RhdGlvbnMuY3N2IG91dHB1dCBmcm9tIHRoZSAxMHggR2Vub21pY3MgQ2VsbCBSYW5nZXIuIFRoaXMgZmlsZSBpcyBsb2NhdGVkIGluIHRoZSAuL291dHMvIGRpcmVjdG9yeSBvZiB0aGUgVkRKIGFsaWdubWVudCBmb2xkZXIuIFRvIGdlbmVyYXRlIGEgbGlzdCBvZiBjb250aWdzIHRvIHVzZSBmb3Igc2NSZXBlcnRvaXJlOioqCgotICAgbG9hZCB0aGUgZmlsdGVyZWRfY29udGlnX2Fubm90YXRpb25zLmNzdiBmb3IgZWFjaCBvZiB0aGUgc2FtcGxlcy4KCi0gICBtYWtlIGEgbGlzdCBpbiB0aGUgUiBlbnZpcm9ubWVudC4KCgpgYGB7ciBUQ1IsIGluY2x1ZGU9RkFMU0V9CgpMMSA8LSByZWFkLmNzdigicGF0aC90by9MMS9maWx0ZXJlZF9jb250aWdfYW5ub3RhdGlvbnMuY3N2IikKTDIgPC0gcmVhZC5jc3YoInBhdGgvdG8vTDIvZmlsdGVyZWRfY29udGlnX2Fubm90YXRpb25zLmNzdiIpCkwzX0IgPC0gcmVhZC5jc3YoInBhdGgvdG8vTDNfQi9maWx0ZXJlZF9jb250aWdfYW5ub3RhdGlvbnMuY3N2IikKTDRfQiA8LSByZWFkLmNzdigicGF0aC90by9MNF9CL2ZpbHRlcmVkX2NvbnRpZ19hbm5vdGF0aW9ucy5jc3YiKQpMNSA8LSByZWFkLmNzdigicGF0aC90by9MNS9maWx0ZXJlZF9jb250aWdfYW5ub3RhdGlvbnMuY3N2IikKTDYgPC0gcmVhZC5jc3YoInBhdGgvdG8vTDYvZmlsdGVyZWRfY29udGlnX2Fubm90YXRpb25zLmNzdiIpCkw3IDwtIHJlYWQuY3N2KCJwYXRoL3RvL0w3L2ZpbHRlcmVkX2NvbnRpZ19hbm5vdGF0aW9ucy5jc3YiKQpQQk1DIDwtIHJlYWQuY3N2KCJwYXRoL3RvL1BCTUMvZmlsdGVyZWRfY29udGlnX2Fubm90YXRpb25zLmNzdiIpCgpgYGAKCgojIDIuIENvbWJpbmluZyBDb250aWdzIGludG8gQ2xvbmVzCmBgYHtyIGNvbWJpbmVkVENSLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD02fQoKY29udGlnX2xpc3QgPC0gbGlzdChMMSwgTDIsIEwzX0IsIEw0X0IsTDUsTDYsIEw3KQpjb250aWdfbGlzdF93aXRoX1BCTUMgPC0gbGlzdChMMSwgTDIsIEwzX0IsIEw0X0IsTDUsTDYsIEw3LCBQQk1DKQoKY29tYmluZWQuVENSIDwtIGNvbWJpbmVUQ1IoY29udGlnX2xpc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZXMgPSBjKCJMMSIsICJMMiIsICJMM19CIiwgIkw0X0IiLCAiTDUiLCAiTDYiLCAiTDciKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVtb3ZlTkEgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVtb3ZlTXVsdGkgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyTXVsdGkgPSBGQUxTRSkKCmNvbWJpbmVkLlRDUl93aXRoX1BCTUMgPC0gY29tYmluZVRDUihjb250aWdfbGlzdF93aXRoX1BCTUMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGVzID0gYygiTDEiLCAiTDIiLCAiTDNfQiIsICJMNF9CIiwgIkw1IiwgIkw2IiwgIkw3IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQQk1DIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbW92ZU5BID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICByZW1vdmVNdWx0aSA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyTXVsdGkgPSBGQUxTRSkKCiMgIGV4cG9ydENsb25lcyhjb21iaW5lZC5UQ1IsIAojICAgICAgICAgICAgICAgd3JpdGUuZmlsZSA9IFRSVUUsCiMgICAgICAgICAgICAgICBkaXIgPSAiLi4vVENSX0FuYWx5c2lzLyIsCiMgICAgICAgICAgICAgIGZpbGUubmFtZSA9ICJjbG9uZXMuY3N2IikKIyAKIyBleHBvcnRDbG9uZXMoY29tYmluZWQuVENSX3dpdGhfUEJNQywgCiMgICAgICAgICAgICAgIHdyaXRlLmZpbGUgPSBUUlVFLAojICAgICAgICAgICAgICBkaXIgPSAiLi4vVENSX0FuYWx5c2lzLyIsCiMgICAgICAgICAgICAgIGZpbGUubmFtZSA9ICJjbG9uZXNfd2l0aF9QQk1DLmNzdiIpCgpoZWFkKGNvbWJpbmVkLlRDUl93aXRoX1BCTUNbWzFdXSkKCmBgYAojIDMuIEJhc2ljIENsb25hbCBWaXN1YWxpemF0aW9ucwoKIyMgMy4xLiBjbG9uYWxRdWFudApgYGB7ciBDbG9uYWwtVmlzdWFsaXphdGlvbiwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9Nn0KI2Nsb25hbFF1YW50CiBjbG9uYWxRdWFudChjb21iaW5lZC5UQ1IsIAogICAgICAgICAgICBjbG9uZUNhbGw9InN0cmljdCIsIAogICAgICAgICAgICBjaGFpbiA9ICJib3RoIiwgCiAgICAgICAgICAgIHNjYWxlID0gVFJVRSkKCgpjbG9uYWxRdWFudChjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCAKICAgICAgICAgICAgY2xvbmVDYWxsPSJzdHJpY3QiLCAKICAgICAgICAgICAgY2hhaW4gPSAiYm90aCIsIAogICAgICAgICAgICBzY2FsZSA9IFRSVUUpCgpjbG9uYWxRdWFudChjb21iaW5lZC5UQ1IsIGNsb25lQ2FsbCA9ICJnZW5lIiwgZ3JvdXAuYnkgPSAic2FtcGxlIiwgc2NhbGUgPSBUUlVFKQoKY2xvbmFsUXVhbnQoY29tYmluZWQuVENSX3dpdGhfUEJNQywgY2xvbmVDYWxsID0gImdlbmUiLCBncm91cC5ieSA9ICJzYW1wbGUiLCBzY2FsZSA9IFRSVUUpCmBgYAojIyAzLjIgY2xvbmFsQWJ1bmRhbmNlCmBgYHtyIFYyLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD02fQojY2xvbmFsQWJ1bmRhbmNlCgpjbG9uYWxBYnVuZGFuY2UoY29tYmluZWQuVENSX3dpdGhfUEJNQywgCiAgICAgICAgICAgICAgICBjbG9uZUNhbGwgPSAiZ2VuZSIsICBwYWxldHRlID0gIlppc3NvdSAxIiwKICAgICAgICAgICAgICAgIHNjYWxlID0gRkFMU0UpKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBoY2wuY29sb3JzKDgsImdleXNlciIpKQoKY2xvbmFsQWJ1bmRhbmNlKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgICAgY2xvbmVDYWxsID0gImdlbmUiLCBwYWxldHRlID0gIlppc3NvdSAxIiwKICAgICAgICAgICAgICAgIHNjYWxlID0gVFJVRSkKYGBgCiMjIDMuMyBjbG9uYWxMZW5ndGgKYGBge3IgVjMsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTZ9CiNjbG9uYWxMZW5ndGgKY2xvbmFsTGVuZ3RoKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgY2xvbmVDYWxsPSJudCIsIAogICAgICAgICAgICAgY2hhaW4gPSAiYm90aCIpIAoKY2xvbmFsTGVuZ3RoKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgY2xvbmVDYWxsPSJhYSIsIAogICAgICAgICAgICAgY2hhaW4gPSAiYm90aCIpIAojVFJBCmNsb25hbExlbmd0aChjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCAKICAgICAgICAgICAgIGNsb25lQ2FsbD0ibnQiLCAKICAgICAgICAgICAgIGNoYWluID0gIlRSQSIsIAogICAgICAgICAgICAgc2NhbGUgPSBUUlVFKSAKCmNsb25hbExlbmd0aChjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCAKICAgICAgICAgICAgIGNsb25lQ2FsbD0iYWEiLCAKICAgICAgICAgICAgIGNoYWluID0gIlRSQSIsIAogICAgICAgICAgICAgc2NhbGUgPSBUUlVFKSAKCiNUUkIKY2xvbmFsTGVuZ3RoKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgY2xvbmVDYWxsPSJudCIsIAogICAgICAgICAgICAgY2hhaW4gPSAiVFJCIiwgCiAgICAgICAgICAgICBzY2FsZSA9IFRSVUUpIAoKY2xvbmFsTGVuZ3RoKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgY2xvbmVDYWxsPSJhYSIsIAogICAgICAgICAgICAgY2hhaW4gPSAiVFJCIiwgCiAgICAgICAgICAgICBzY2FsZSA9IFRSVUUpIApgYGAKIyMgMy40IGNsb25hbENvbXBhcmUKYGBge3IgVjQsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTZ9CiMgY2xvbmFsQ29tcGFyZQpjbG9uYWxDb21wYXJlKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgICAgICB0b3AuY2xvbmVzID0gMTAsIAogICAgICAgICAgICAgICAgICBzYW1wbGVzID0gYygiTDEiLCAiTDIiKSwgCiAgICAgICAgICAgICAgICAgIGNsb25lQ2FsbD0iYWEiLCAKICAgICAgICAgICAgICAgICAgZ3JhcGggPSAiYWxsdXZpYWwiKQoKY2xvbmFsQ29tcGFyZShjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCAKICAgICAgICAgICAgICAgICAgdG9wLmNsb25lcyA9IDEwLCAKICAgICAgICAgICAgICAgICAgc2FtcGxlcyA9IGMoIkwzX0IiLCAiTDRfQiIpLCAKICAgICAgICAgICAgICAgICAgY2xvbmVDYWxsPSJhYSIsIAogICAgICAgICAgICAgICAgICBncmFwaCA9ICJhbGx1dmlhbCIpCgpjbG9uYWxDb21wYXJlKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgICAgICB0b3AuY2xvbmVzID0gMTAsIAogICAgICAgICAgICAgICAgICBzYW1wbGVzID0gYygiTDUiLCAiTDYiLCJMNyIpLCAKICAgICAgICAgICAgICAgICAgY2xvbmVDYWxsPSJhYSIsIAogICAgICAgICAgICAgICAgICBncmFwaCA9ICJhbGx1dmlhbCIpCgpjbG9uYWxDb21wYXJlKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgICAgICB0b3AuY2xvbmVzID0gMTAsIAogICAgICAgICAgICAgICAgICBzYW1wbGVzID0gYygiTDUiLCJMNiIpLCAKICAgICAgICAgICAgICAgICAgY2xvbmVDYWxsPSJhYSIsIAogICAgICAgICAgICAgICAgICBncmFwaCA9ICJhbGx1dmlhbCIpCgpjbG9uYWxDb21wYXJlKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgICAgICB0b3AuY2xvbmVzID0gMTAsIAogICAgICAgICAgICAgICAgICBzYW1wbGVzID0gYygiTDUiLCJMNyIpLCAKICAgICAgICAgICAgICAgICAgY2xvbmVDYWxsPSJhYSIsIAogICAgICAgICAgICAgICAgICBncmFwaCA9ICJhbGx1dmlhbCIpCgpjbG9uYWxDb21wYXJlKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgICAgICB0b3AuY2xvbmVzID0gMTAsIAogICAgICAgICAgICAgICAgICBzYW1wbGVzID0gYygiTDYiLCJMNyIpLCAKICAgICAgICAgICAgICAgICAgY2xvbmVDYWxsPSJhYSIsIAogICAgICAgICAgICAgICAgICBncmFwaCA9ICJhbGx1dmlhbCIpCgpjbG9uYWxDb21wYXJlKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgICAgICB0b3AuY2xvbmVzID0gMTAsIAogICAgICAgICAgICAgICAgICBzYW1wbGVzID0gYygiTDEiLCAiTDIiLCAiTDNfQiIsICJMNF9CIiwgIkw1IiwgIkw2IiwgIkw3IiwgIlBCTUMiKSwgCiAgICAgICAgICAgICAgICAgIGNsb25lQ2FsbD0iYWEiLCAKICAgICAgICAgICAgICAgICAgZ3JhcGggPSAiYWxsdXZpYWwiKQoKIyBjbG9uYWxDb21wYXJlKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAojICAgICAgICAgICAgICAgdG9wLmNsb25lcyA9IDEwLAojICAgICAgICAgICAgICAgaGlnaGxpZ2h0LmNsb25lcyA9IGMoIkNWVlNETlRHR0ZLVElGX0NBU1NWUlJFUkFOVEdFTEZGIiwgIk5BX0NBU1NWUlJFUkFOVEdFTEZGIiksCiMgICAgICAgICAgICAgICByZWxhYmVsLmNsb25lcyA9IFRSVUUsCiMgICAgICAgICAgICAgICBzYW1wbGVzID0gYygiTDEiLCAiTDIiKSwgCiMgICAgICAgICAgICAgICBjbG9uZUNhbGw9ImFhIiwgCiMgICAgICAgICAgICAgICBncmFwaCA9ICJhbGx1dmlhbCIpCiMgCiMgCiMgY2xvbmFsQ29tcGFyZShjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCBjbG9uZXMgPSBjKCJDVlZTRE5UR0dGS1RJRl9DQVNTVlJSRVJBTlRHRUxGRiIsICJOQV9DQVNTVlJSRVJBTlRHRUxGRiIpLAojICAgICByZWxhYmVsLmNsb25lcyA9IFRSVUUsIHNhbXBsZXMgPSBjKCJMMSIsICJMMiIpLCBjbG9uZUNhbGwgPSAiYWEiLCBncmFwaCA9ICJhbGx1dmlhbCIpCgpgYGAKIyMgMy41IGNsb25hbFNjYXR0ZXIKYGBge3IgVjUsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTZ9CiNjbG9uYWxTY2F0dGVyCgpjbG9uYWxTY2F0dGVyKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgIGNsb25lQ2FsbCA9ImdlbmUiLCAKICAgICAgICAgICAgICB4LmF4aXMgPSAiTDEiLCAKICAgICAgICAgICAgICB5LmF4aXMgPSAiTDIiLAogICAgICAgICAgICAgIGRvdC5zaXplID0gInRvdGFsIiwKICAgICAgICAgICAgICBncmFwaCA9ICJwcm9wb3J0aW9uIikKCgpjbG9uYWxTY2F0dGVyKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgIGNsb25lQ2FsbCA9ImdlbmUiLCAKICAgICAgICAgICAgICB4LmF4aXMgPSAiTDNfQiIsIAogICAgICAgICAgICAgIHkuYXhpcyA9ICJMNF9CIiwKICAgICAgICAgICAgICBkb3Quc2l6ZSA9ICJ0b3RhbCIsCiAgICAgICAgICAgICAgZ3JhcGggPSAicHJvcG9ydGlvbiIpCgpjbG9uYWxTY2F0dGVyKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgIGNsb25lQ2FsbCA9ImdlbmUiLCAKICAgICAgICAgICAgICB4LmF4aXMgPSAiTDUiLCAKICAgICAgICAgICAgICB5LmF4aXMgPSAiTDYiLAogICAgICAgICAgICAgIGRvdC5zaXplID0gInRvdGFsIiwKICAgICAgICAgICAgICBncmFwaCA9ICJwcm9wb3J0aW9uIikKCmNsb25hbFNjYXR0ZXIoY29tYmluZWQuVENSX3dpdGhfUEJNQywgCiAgICAgICAgICAgICAgY2xvbmVDYWxsID0iZ2VuZSIsIAogICAgICAgICAgICAgIHguYXhpcyA9ICJMNSIsIAogICAgICAgICAgICAgIHkuYXhpcyA9ICJMNyIsCiAgICAgICAgICAgICAgZG90LnNpemUgPSAidG90YWwiLAogICAgICAgICAgICAgIGdyYXBoID0gInByb3BvcnRpb24iKQoKY2xvbmFsU2NhdHRlcihjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCAKICAgICAgICAgICAgICBjbG9uZUNhbGwgPSJnZW5lIiwgCiAgICAgICAgICAgICAgeC5heGlzID0gIkw2IiwgCiAgICAgICAgICAgICAgeS5heGlzID0gIkw3IiwKICAgICAgICAgICAgICBkb3Quc2l6ZSA9ICJ0b3RhbCIsCiAgICAgICAgICAgICAgZ3JhcGggPSAicHJvcG9ydGlvbiIpCmBgYAojIDQuIFZpc3VhbGl6aW5nIENsb25hbCBEeW5hbWljcwoKIyMgNC4xIGNsb25hbEhvbWVvc3Rhc2lzCmBgYHtyIFY2LCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD02fQojIFZpc3VhbGl6aW5nIENsb25hbCBEeW5hbWljcwoKIyBjbG9uYWxIb21lb3N0YXNpcwoKY2xvbmFsSG9tZW9zdGFzaXMoY29tYmluZWQuVENSX3dpdGhfUEJNQywgCiAgICAgICAgICAgICAgICAgIGNsb25lQ2FsbCA9ICJnZW5lIikKCgpjbG9uYWxIb21lb3N0YXNpcyhjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCAKICAgICAgICAgICAgICAgICAgY2xvbmVDYWxsID0gImdlbmUiLAogICAgICAgICAgICAgICAgICBjbG9uZVNpemUgPSBjKFJhcmUgPSAwLjAwMSwgU21hbGwgPSAwLjAxLCBNZWRpdW0gPSAwLjEsIExhcmdlID0gMC4zLCBIeXBlcmV4cGFuZGVkID0xKSkKCmBgYAojIyA0LjIgY2xvbmFsUHJvcG9ydGlvbgpgYGB7ciBTdGF0cywgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9Nn0KIyBjbG9uYWxQcm9wb3J0aW9uCgpjbG9uYWxQcm9wb3J0aW9uKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgICAgIGNsb25lQ2FsbCA9ICJnZW5lIikgCgpjbG9uYWxQcm9wb3J0aW9uKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgICAgIGNsb25lQ2FsbCA9ICJudCIsCiAgICAgICAgICAgICAgICAgY2xvbmFsU3BsaXQgPSBjKDEsIDUsIDEwLCAxMDAsIDEwMDAsIDEwMDAwKSkgCmBgYAojIDUuIFN1bW1hcml6aW5nIFJlcGVydG9pcmVzCgpTYXZlZC1vdXRwdXQgbm90ZTogdGhlIGVtYmVkZGVkIGBwZXJjZW50QUEoKWAgYW5kIGBwb3NpdGlvbmFsRW50cm9weSgpYCBvdXRwdXQgcmVjb3JkcyByZXBlYXRlZCAiV2FybmluZzogaW52YWxpZCBmYWN0b3IgbGV2ZWwsIE5BIGdlbmVyYXRlZCIgbWVzc2FnZXMuIFRob3NlIGNhY2hlZCBvdXRwdXRzIGFyZSBub3QgcmV2YWxpZGF0ZWQgaGVyZS4KCmBgYHtyIERFLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD02fQojIFN1bW1hcml6aW5nIFJlcGVydG9pcmVzCgojcGVyY2VudEFBCgpwZXJjZW50QUEoY29tYmluZWQuVENSLCAKICAgICAgICAgIGNoYWluID0gIlRSQiIsIAogICAgICAgICAgYWEubGVuZ3RoID0gMjApCgojIHBvc2l0aW9uYWxFbnRyb3B5CiMgV2UgY2FuIGFsc28gcXVhbnRpZnkgdGhlIGxldmVsIG9mIGVudHJvcHkvZGl2ZXJzaXR5IGFjcm9zcyBhbWlubyBhY2lkIHJlc2lkdWVzIGFsb25nIHRoZSBjZHIzIHNlcXVlbmNlLiBwb3NpdGlvbmFsRW50cm9weSgpIGNvbWJpbmVzIHRoZSBxdWFudGlmaWNhdGlvbiBieSByZXNpZHVlIG9mIHBlcmNlbnRBQSgpIHdpdGggdGhlIGRpdmVyc2l0eSBjYWxscyBpbiBjbG9uYWxEaXZlcnNpdHkoKS4KIyAKIyBtZXRob2QKIyAKIyDigJxzaGFubm9u4oCdIC0gU2hhbm5vbiBEaXZlcnNpdHkKIyDigJxpbnYuc2ltcHNvbuKAnSAtIEludmVyc2UgU2ltcHNvbiBEaXZlcnNpdHkKIyDigJxub3JtLmVudHJvcHnigJ0gLSBOb3JtYWxpemVkIEVudHJvcHkKCnBvc2l0aW9uYWxFbnRyb3B5KGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgICAgICBjaGFpbiA9ICJUUkIiLCAKICAgICAgICAgICAgICAgICAgYWEubGVuZ3RoID0gMjApCgoKIyBwb3NpdGlvbmFsUHJvcGVydHkKIyBMaWtlIHBvc2l0aW9uYWxFbnRyb3B5KCksIHdlIGNhbiBhbHNvIGV4YW1pbmUgYSBzZXJpZXMgb2YgYW1pbm8gYWNpZCBwcm9wZXJ0aWVzIGFsb25nIHRoZSBjZHIzIHNlcXVlbmNlcyB1c2luZyBwb3NpdGlvbmFsUHJvcGVydHkoKS4gSW1wb3J0YW50IGRpZmZlcmVuY2VzIGZyb20gdGhlIGFib3ZlIGZ1bmN0aW9uIGZvciBwb3NpdGlvbmFsUHJvcGVydHkoKSBpcyBkcm9wcGluZyBOQSB2YWx1ZXMgYXMgdGhleSB3b3VsZCB2b2lkIHRoZSBtZWFuIGNhbGN1bGF0aW9uLiBwb3NpdGlvbmFsUHJvcGVydHkoKSBhbHNvIGRpc3BsYXkgYSByaWJib24gd2l0aCB0aGUgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgc3Vycm91bmRpbmcgdGhlIG1lYW4gdmFsdWUgZm9yIHRoZSBzZWxlY3RlZCBwcm9wZXJ0aWVzLgojIAojIG1ldGhvZAojIAojIOKAnEF0Y2hsZXnigJ0gLSBBdGNobGV5IEZhY3RvcnMKIyDigJxLaWRlcmHigJ0gLSBLaWRlcmEgRmFjdG9ycwojIOKAnHN0U2NhbGVz4oCdIC0gc3RTY2FsZXMgVmVjdG9ycwojIOKAnHRTY2FsZXPigJ0gLSB0U2NhbGVzIFZlY3RvcnMKIyDigJxWSFNF4oCdIC0gVmVjdG9ycyBvZiBIeWRyb3Bob2JpYywgU3RlcmljLCBhbmQgRWxlY3Ryb25pYyBwcm9wZXJ0aWVzCgojIHBvc2l0aW9uYWxQcm9wZXJ0eShjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DW2MoMSwyKV0sIAojICAgICAgICAgICAgICAgICAgIGNoYWluID0gIlRSQiIsIAojICAgICAgICAgICAgICAgICAgIGFhLmxlbmd0aCA9IDIwLCAKIyAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAiQXRjaGxleSIpICsgCiMgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gaGNsLmNvbG9ycyg1LCAiaW5mZXJubyIpW2MoMiw0KV0pCiMgCiMgcG9zaXRpb25hbFByb3BlcnR5KGNvbWJpbmVkLlRDUl93aXRoX1BCTUNbYygzLDQpXSwgCiMgICAgICAgICAgICAgICAgICAgY2hhaW4gPSAiVFJCIiwgCiMgICAgICAgICAgICAgICAgICAgYWEubGVuZ3RoID0gMjAsIAojICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJBdGNobGV5IikgKyAKIyAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBoY2wuY29sb3JzKDUsICJpbmZlcm5vIilbYygyLDQpXSkKIyAKIyBwb3NpdGlvbmFsUHJvcGVydHkoY29tYmluZWQuVENSX3dpdGhfUEJNQ1tjKDUsNildLCAKIyAgICAgICAgICAgICAgICAgICBjaGFpbiA9ICJUUkIiLCAKIyAgICAgICAgICAgICAgICAgICBhYS5sZW5ndGggPSAyMCwgCiMgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gIkF0Y2hsZXkiKSArIAojICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGhjbC5jb2xvcnMoNSwgImluZmVybm8iKVtjKDIsNCldKQojIAojIHBvc2l0aW9uYWxQcm9wZXJ0eShjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DW2MoNSw3KV0sIAojICAgICAgICAgICAgICAgICAgIGNoYWluID0gIlRSQiIsIAojICAgICAgICAgICAgICAgICAgIGFhLmxlbmd0aCA9IDIwLCAKIyAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAiQXRjaGxleSIpICsgCiMgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gaGNsLmNvbG9ycyg1LCAiaW5mZXJubyIpW2MoMiw0KV0pCiMgCiMgCiMgcG9zaXRpb25hbFByb3BlcnR5KGNvbWJpbmVkLlRDUl93aXRoX1BCTUNbYyg2LDcpXSwgCiMgICAgICAgICAgICAgICAgICAgY2hhaW4gPSAiVFJCIiwgCiMgICAgICAgICAgICAgICAgICAgYWEubGVuZ3RoID0gMjAsIAojICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJBdGNobGV5IikgKyAKIyAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBoY2wuY29sb3JzKDUsICJpbmZlcm5vIilbYygyLDQpXSkKIyAKIyBwb3NpdGlvbmFsUHJvcGVydHkoY29tYmluZWQuVENSX3dpdGhfUEJNQ1tjKDUsNiw3KV0sIAojICAgICAgICAgICAgICAgICAgIGNoYWluID0gIlRSQiIsIAojICAgICAgICAgICAgICAgICAgIGFhLmxlbmd0aCA9IDIwLCAKIyAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAiQXRjaGxleSIpICsgCiMgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gaGNsLmNvbG9ycyg1LCAiaW5mZXJubyIpW2MoMiw0KV0pCgoKIyB2aXpHZW5lcwojIEEgdmlzdWFsaXphdGlvbiBvZiB0aGUgcmVsYXRpdmUgdXNhZ2Ugb2YgZ2VuZXMgb2YgdGhlIFRDUiBvciBCQ1IsIHVzaW5nIHZpekdlbmVzKCkuIFRoZXJlIGlzIHNvbWUgZnVuY3Rpb25hbCBjcm9zc292ZXIgYmV0d2VlbiB2aXpHZW5lcygpIGFuZCB0d28gZnVuY3Rpb25zIGJlbG93IGNhbGxlZCBwZXJjZW50R2VuZXMoKSBhbmQgcGVyY2VudFZKKCkuIEJ1dCB2aXpHZW5lcygpIGlzIG1vcmUgYWRhcHRhYmxlIHRvIGFsbG93IGZvciBjb21wYXJpc29ucyBhY3Jvc3MgY2hhaW5zLCBzY2FsaW5nLCBldGMuCgp2aXpHZW5lcyhjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCAKICAgICAgICAgeC5heGlzID0gIlRSQlYiLAogICAgICAgICB5LmF4aXMgPSBOVUxMLAogICAgICAgICBwbG90ID0gImJhcnBsb3QiLCAgCiAgICAgICAgIHNjYWxlID0gVFJVRSkKCnZpekdlbmVzKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgIHguYXhpcyA9ICJUUkFWIiwKICAgICAgICB5LmF4aXMgPSBOVUxMLAogICAgICAgIHBsb3QgPSAiYmFycGxvdCIsICAKICAgICAgICBzY2FsZSA9IFRSVUUpCgp2aXpHZW5lcyhjb21iaW5lZC5UQ1JbYygxLDIsMyw0LDUsNiw3KV0sIAogICAgICAgICB4LmF4aXMgPSAiVFJCViIsCiAgICAgICAgIHkuYXhpcyA9ICJUUkJKIiwKICAgICAgICAgcGxvdCA9ICJoZWF0bWFwIiwgIAogICAgICAgICBzY2FsZSA9IFRSVUUpCgp2aXpHZW5lcyhjb21iaW5lZC5UQ1JbYygxLDIsMyw0LDUsNiw3KV0sIAogICAgICAgICB4LmF4aXMgPSAiVFJBViIsCiAgICAgICAgIHkuYXhpcyA9ICJUUkFKIiwKICAgICAgICAgcGxvdCA9ICJoZWF0bWFwIiwgIAogICAgICAgICBzY2FsZSA9IFRSVUUpCgojIEZvciB0aGUgUDE3IHBhdGllbnQgc2FtcGxlcywgd2hhdCBpZiB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBjaGFpbiBwYWlyaW5ncywgd2UgY2FuIGxvb2sgYXQgVFJCViBhbmQgVFJBViBhdCB0aGUgc2FtZSB0aW1lIHVzaW5nIHRoZW0gYXMgaW5wdXRzIHRvIHguYXhpcyBhbmQgeS5heGlzLgp2aXpHZW5lcyhjb21iaW5lZC5UQ1JbYygxLDIpXSwgCiAgICAgICAgIHguYXhpcyA9ICJUUkJWIiwKICAgICAgICAgeS5heGlzID0gIlRSQVYiLAogICAgICAgICBwbG90ID0gImhlYXRtYXAiLCAKICAgICAgICAgc2NhbGUgPSBGQUxTRSkKIyBwZXJjZW50R2VuZXMKIyBRdWFudGlmeSB0aGUgcHJvcG9ydGlvbiBvZiBWIG9yIEogZ2VuZSB1c2FnZSB3aXRoIHBlcmNlbnRHZW5lcygpLiBMaWtlIHBlcmNlbnRBQSgpLCB3ZSBzZWxlY3QgdGhlIGNoYWluIG9mIGludGVyZXN0IGFuZCB0aGVuIGluZGljYXRlIHRoZSBnZW5lIG9mIGludGVyZXN0IHdpdGggdGhlIGdlbmUgcGFyYW1ldGVyLiBUd28gbWFqb3IgbGltaXRhdGlvbnMgb2YgcGVyY2VudEdlbmVzKCkgYXJlLCAxKSB0aGUgZnVuY3Rpb24gcXVhbnRpZmllcyBvbmx5IFYgb3IgSiBnZW5lcywgYW5kIDIpIHRoZSBxdWFudGlmaWNhdGlvbiBvZiB0aGUgZ2VuZXMgYXJlIGxpbWl0ZWQgdG8gYWxsIHRoZSBWIG9yIEogZ2VuZXMgc2VlbiBhY3Jvc3MgdGhlIHNhbXBsZXMsIG5vdCBhbGwgcG9zc2libGUgViBvciBKIGdlbmVzLgoKcGVyY2VudEdlbmVzKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgY2hhaW4gPSAiVFJCIiwgCiAgICAgICAgICAgICBnZW5lID0gIlZnZW5lIikKCnBlcmNlbnRHZW5lcyhjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCAKICAgICAgICAgICAgIGNoYWluID0gIlRSQSIsIAogICAgICAgICAgICAgZ2VuZSA9ICJWZ2VuZSIpCgpwZXJjZW50R2VuZXMoY29tYmluZWQuVENSX3dpdGhfUEJNQywgCiAgICAgICAgICAgICBjaGFpbiA9ICJUUkIiLCAKICAgICAgICAgICAgIGdlbmUgPSAiSmdlbmUiKQoKcGVyY2VudEdlbmVzKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgY2hhaW4gPSAiVFJBIiwgCiAgICAgICAgICAgICBnZW5lID0gIkpnZW5lIikKCgojIHBlcmNlbnRWSgojIFF1YW50aWZ5IHRoZSBwcm9wb3J0aW9uIG9mIFYgYW5kIEogZ2VuZSB1c2FnZSB3aXRoIHBlcmNlbnRWSigpLiBMaWtlIHBlcmNlbnRHZW5lcygpLCB0aGlzIGZ1bmN0aW9uIHdpbGwgcXVhbnRpZnkgdGhlIHBlcmNlbnRhZ2Ugb2YgViBhbmQgSiBwYWlyZWQgdG9nZXRoZXIgYWNyb3NzIGluZGl2aWR1YWwgcmVwZXJ0b2lyZXMuIFRoZSBvdXRwdXQgY2FuIGJlIHZpc3VhbGl6ZWQgdXNpbmcgYSBoZWF0bWFwIG9yIGFzIGlucHV0IGZvciBmdXJ0aGVyIGRpbWVuc2lvbmFsIHJlZHVjdGlvbi4KCnBlcmNlbnRWSihjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCAKICAgICAgICAgIGNoYWluID0gIlRSQiIpCgpwZXJjZW50VkooY29tYmluZWQuVENSX3dpdGhfUEJNQywgCiAgICAgICAgICBjaGFpbiA9ICJUUkEiKQoKIyBwZXJjZW50S21lcgojIEFub3RoZXIgcXVhbnRpZmljYXRpb24gb2YgdGhlIGNvbXBvc2l0aW9uIG9mIHRoZSBDRFIzIHNlcXVlbmNlIGlzIHRvIGRlZmluZSBtb3RpZnMgYnkgc2xpZGluZyBhY3Jvc3MgdGhlIGFtaW5vIGFjaWQgb3IgbnVjbGVvdGlkZSBzZXF1ZW5jZXMgYXQgc2V0IGludGVydmFscyByZXN1bHRpbmcgaW4gc3Vic3RyaW5ncyBvciBrbWVycy4KIyAKIyBtb3RpZi5sZW5ndGgKIyAKIyBOdW1lcmljYWwgdmFsdWUgZm9yIHRoZSBsZW5ndGggb2YgdGhlIGttZXIuCiMgdG9wLm1vdGlmcwojIAojIERpc3BsYXkgdGhlIG1vc3QgdmFyaWFibGUgZ2VuZXMgZGV0ZXJtaW5lZCBieSBtZWFuIGFic29sdXRlIGRldmlhdGlvbiAoTUFEKS4KcGVyY2VudEttZXIoY29tYmluZWQuVENSX3dpdGhfUEJNQywgCiAgICAgICAgICAgIGNsb25lQ2FsbCA9ICJhYSIsCiAgICAgICAgICAgIGNoYWluID0gIlRSQiIsIAogICAgICAgICAgICBtb3RpZi5sZW5ndGggPSAzLCAKICAgICAgICAgICAgdG9wLm1vdGlmcyA9IDI1KQoKcGVyY2VudEttZXIoY29tYmluZWQuVENSX3dpdGhfUEJNQywgCiAgICAgICAgICAgIGNsb25lQ2FsbCA9ICJhYSIsCiAgICAgICAgICAgIGNoYWluID0gIlRSQSIsIAogICAgICAgICAgICBtb3RpZi5sZW5ndGggPSAzLCAKICAgICAgICAgICAgdG9wLm1vdGlmcyA9IDI1KQoKcGVyY2VudEttZXIoY29tYmluZWQuVENSX3dpdGhfUEJNQywgCiAgICAgICAgICAgIGNsb25lQ2FsbCA9ICJudCIsCiAgICAgICAgICAgIGNoYWluID0gIlRSQiIsIAogICAgICAgICAgICBtb3RpZi5sZW5ndGggPSAzLCAKICAgICAgICAgICAgdG9wLm1vdGlmcyA9IDI1KQoKcGVyY2VudEttZXIoY29tYmluZWQuVENSX3dpdGhfUEJNQywgCiAgICAgICAgICAgIGNsb25lQ2FsbCA9ICJudCIsCiAgICAgICAgICAgIGNoYWluID0gIlRSQSIsIAogICAgICAgICAgICBtb3RpZi5sZW5ndGggPSAzLCAKICAgICAgICAgICAgdG9wLm1vdGlmcyA9IDI1KQpgYGAKIyA2LiBDb21wYXJpbmcgQ2xvbmFsIERpdmVyc2l0eSBhbmQgT3ZlcmxhcApgYGB7ciBjbG9uYWxEaXZlcnNpdHksIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTZ9CiMgY2xvbmFsRGl2ZXJzaXR5CgoKY2xvbmFsRGl2ZXJzaXR5KGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgICAgY2xvbmVDYWxsID0gImdlbmUiKQoKI2Nsb25hbFNpemVEaXN0cmlidXRpb24KCgpjbG9uYWxTaXplRGlzdHJpYnV0aW9uKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgICAgICAgICAgIGNsb25lQ2FsbCA9ICJhYSIsIAogICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZD0gIndhcmQuRDIiKQoKCgojY2xvbmFsT3ZlcmxhcAoKY2xvbmFsT3ZlcmxhcChjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCAKICAgICAgICAgICAgICBjbG9uZUNhbGwgPSAic3RyaWN0IiwgCiAgICAgICAgICAgICAgbWV0aG9kID0gIm1vcmlzaXRhIikKCgpjbG9uYWxPdmVybGFwKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIAogICAgICAgICAgICAgIGNsb25lQ2FsbCA9ICJzdHJpY3QiLCAKICAgICAgICAgICAgICBtZXRob2QgPSAicmF3IikKYGBgCiMgNy4gQ29tYmluaW5nIENsb25lcyBhbmQgU2luZ2xlLUNlbGwgT2JqZWN0cwoKQmVmb3JlIHJ1bm5pbmcgdGhpcyBzZWN0aW9uLCBhc3NpZ24gYSBjb21wYXRpYmxlIFNldXJhdCBvYmplY3QgdG8gYHNjUmVwX2V4YW1wbGVgLiBUaGUgc291cmNlIGxhdGVyIHVzZXMgYHNhbXBsZWAsIGBvcmlnLmlkZW50YCwgYHNldXJhdF9jbHVzdGVyc2AsIGBjZWxsX2xpbmVgLCBhY3RpdmUgaWRlbnRpdGllcywgYW5kIGEgYHVtYXBgIHJlZHVjdGlvbi4KClNhdmVkLW91dHB1dCBub3RlOiB0aGUgd2FybmluZyBiZWxvdyB3YXMgY2FwdHVyZWQgZnJvbSB0aGUgZWFybGllciBsb29rdXAgYGdldChkYXRhKCJBbGxfc2FtcGxlc19NZXJnZWQiKSlgLCB3aGljaCByZXBvcnRlZCAiZGF0YSBzZXQgJ0FsbF9zYW1wbGVzX01lcmdlZCcgbm90IGZvdW5kIi4gVGhhdCB3YXJuaW5nIGRvZXMgbm90IGVzdGFibGlzaCBhIHN1Y2Nlc3NmdWwgb2JqZWN0IGxvYWQuIFRoZSBzYXZlZCBzaW5nbGUtY2VsbCBwbG90cyByZW1haW4gZ2FsbGVyeSByZWZlcmVuY2VzIHVudGlsIHRoZSByZXF1aXJlZCBvYmplY3QgaXMgc3VwcGxpZWQgYW5kIHRoZSBzZWN0aW9ucyBhcmUgcmVydW4uCgpgYGB7ciBTQywgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9Nn0KCiMgQ29tYmluaW5nIENsb25lcyBhbmQgU2luZ2xlLUNlbGwgT2JqZWN0cwoKI0dldHRpbmcgYSBzYW1wbGUgb2YgYSBTZXVyYXQgb2JqZWN0CiMgVGhlIHNhdmVkIGF0dGVtcHQgY291bGQgbm90IGZpbmQgYSBwYWNrYWdlZCBkYXRhIHNldCBuYW1lZCBBbGxfc2FtcGxlc19NZXJnZWQuCiMgU3VwcGx5IGEgY29tcGF0aWJsZSBTZXVyYXQgb2JqZWN0IGFzIHNjUmVwX2V4YW1wbGUgYmVmb3JlIHJ1bm5pbmcgdGhpcyBzZWN0aW9uLgppZiAoIWV4aXN0cygic2NSZXBfZXhhbXBsZSIsIGluaGVyaXRzID0gVFJVRSkpIHsKICBzdG9wKCJBc3NpZ24gYSBjb21wYXRpYmxlIFNldXJhdCBvYmplY3QgdG8gc2NSZXBfZXhhbXBsZSBiZWZvcmUgcnVubmluZyB0aGlzIHNlY3Rpb24uIikKfQoKCiNEZWZpbmUgY29sb3IgcGFsZXR0ZSAKY29sb3JibGluZF92ZWN0b3IgPC0gaGNsLmNvbG9ycyhuPTcsIHBhbGV0dGUgPSAiaW5mZXJubyIsIGZpeHVwID0gVFJVRSkKCgpzY1JlcF9leGFtcGxlIDwtIGNvbWJpbmVFeHByZXNzaW9uKGNvbWJpbmVkLlRDUiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NSZXBfZXhhbXBsZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xvbmVDYWxsPSJnZW5lIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAuYnkgPSAic2FtcGxlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvcG9ydGlvbiA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbG9uZVNpemU9YyhTaW5nbGU9MSwgU21hbGw9NSwgTWVkaXVtPTIwLCBMYXJnZT0xMDAsIEh5cGVyZXhwYW5kZWQ9NTAwKSkKCkRpbVBsb3Qoc2NSZXBfZXhhbXBsZSwgZ3JvdXAuYnkgPSAiY2xvbmVTaXplIikKCkRpbVBsb3Qoc2NSZXBfZXhhbXBsZSwgZ3JvdXAuYnkgPSAiY2xvbmVTaXplIikgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1yZXYoY29sb3JibGluZF92ZWN0b3JbYygxLDMsNCw1LDYpXSkpCgoKYGBgCiMgOC4gVmlzdWFsaXphdGlvbnMgZm9yIFNpbmdsZS1DZWxsIE9iamVjdHMKYGBge3IgVl9zYywgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9Nn0KCiMgVmlzdWFsaXphdGlvbnMgZm9yIFNpbmdsZS1DZWxsIE9iamVjdHMKIyBjbG9uYWxPdmVybGF5CgojQWRkaW5nIHBhdGllbnQgaW5mb3JtYXRpb24Kc2NSZXBfZXhhbXBsZSRQYXRpZW50X29yaWdpbiA8LSBzdWJzdHIoc2NSZXBfZXhhbXBsZSRvcmlnLmlkZW50LCAxLDMpCgpjbG9uYWxPdmVybGF5KHNjUmVwX2V4YW1wbGUsIAogICAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwgCiAgICAgICAgICAgICAgZnJlcS5jdXRwb2ludCA9IDEsIAogICAgICAgICAgICAgIGJpbnMgPSAxMCwgCiAgICAgICAgICAgICAgZmFjZXQuYnkgPSAiUGF0aWVudF9vcmlnaW4iKSArIAogICAgICAgICAgICAgIGd1aWRlcyhjb2xvciA9ICJub25lIikKCiNjbG9uYWxOZXR3b3JrCiNnZ3JhcGggbmVlZHMgdG8gYmUgbG9hZGVkIGR1ZSB0byBpc3N1ZXMgd2l0aCBnZ3Bsb3QKbGlicmFyeShnZ3JhcGgpCgpjbG9uYWxOZXR3b3JrKHNjUmVwX2V4YW1wbGUsIAogICAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwgCiAgICAgICAgICAgICAgZ3JvdXAuYnkgPSAic2V1cmF0X2NsdXN0ZXJzIiwKICAgICAgICAgICAgICBmaWx0ZXIuY2xvbmVzID0gTlVMTCwKICAgICAgICAgICAgICBmaWx0ZXIuaWRlbnRpdHkgPSBOVUxMLAogICAgICAgICAgICAgIGNsb25lQ2FsbCA9ICJhYSIpCgoKI0V4YW1pbmluZyBDbHVzdGVyIDMgb25seQpjbG9uYWxOZXR3b3JrKHNjUmVwX2V4YW1wbGUsIAogICAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwgCiAgICAgICAgICAgICAgZ3JvdXAuYnkgPSAic2V1cmF0X2NsdXN0ZXJzIiwKICAgICAgICAgICAgICBmaWx0ZXIuaWRlbnRpdHkgPSA4LAogICAgICAgICAgICAgIGNsb25lQ2FsbCA9ICJhYSIpCgoKc2hhcmVkLmNsb25lcyA8LSBjbG9uYWxOZXR3b3JrKHNjUmVwX2V4YW1wbGUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVkdWN0aW9uID0gInVtYXAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVycyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbG9uZUNhbGwgPSAiYWEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cG9ydENsb25lcyA9IFRSVUUpCmhlYWQoc2hhcmVkLmNsb25lcykKCgpzY1JlcF9leGFtcGxlIDwtIGhpZ2hsaWdodENsb25lcyhzY1JlcF9leGFtcGxlLCAKICAgICAgICAgICAgICAgICAgICBjbG9uZUNhbGw9ICJhYSIsIAogICAgICAgICAgICAgICAgICAgIHNlcXVlbmNlID0gYygiQ0FUR1BOR1NTTlRHS0xJRjtDQUxTTk5BUkxNRl9DU0FUVEdGWUdZVEYiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNBWVNFU0dHU05ZS0xURl9DU0FMQUdHWVREVFFZRiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDTFZHRVRHUlJBTFRGX0NTQVJHRFJHUVBRSEYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ0xWR0VUR1JSQUxURl9DU0FSR0RSR1FQUUhGO0NBVFNERktRVlNOUVBRSEYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ0FUR1BOR1NTTlRHS0xJRl9DU0FUVEdGWUdZVEYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTkFfQ1NBUkdEUkdRUFFIRiIpKQoKU2V1cmF0OjpEaW1QbG90KHNjUmVwX2V4YW1wbGUsIGdyb3VwLmJ5ID0gImhpZ2hsaWdodCIpICsgCiAgZ2dwbG90Mjo6dGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKCiNjbG9uYWxPY2N1cHkKY2xvbmFsT2NjdXB5KHNjUmVwX2V4YW1wbGUsIAogICAgICAgICAgICAgIHguYXhpcyA9ICJzZXVyYXRfY2x1c3RlcnMiKQoKY2xvbmFsT2NjdXB5KHNjUmVwX2V4YW1wbGUsIAogICAgICAgICAgICAgICAgICAgICB4LmF4aXMgPSAiaWRlbnQiLCAKICAgICAgICAgICAgICAgICAgICAgcHJvcG9ydGlvbiA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IEZBTFNFKQojIGFsbHV2aWFsQ2xvbmVzCgojIHNjUmVwX2V4YW1wbGUkUGF0aWVudF9vcmlnaW4gPC0gc3Vic3RyKHNjUmVwX2V4YW1wbGUkb3JpZy5pZGVudCwgOCw4KQojIAojIGFsbHV2aWFsQ2xvbmVzKHNjUmVwX2V4YW1wbGUsIAojICAgICAgICAgICAgICAgIGNsb25lQ2FsbCA9ICJhYSIsIAojICAgICAgICAgICAgICAgIHkuYXhlcyA9IGMoIlBhdGllbnRfb3JpZ2luIiwgIm9yaWcuaWRlbnQiLCAiQ2VsbF9saW5lX0ltbXVub3BoZW5vdHlwZSIpLCAKIyAgICAgICAgICAgICAgICBjb2xvciA9IGMoIkNBVEdQTkdTU05UR0tMSUY7Q0FMU05OQVJMTUZfQ1NBVFRHRllHWVRGIiwgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNBWVNFU0dHU05ZS0xURl9DU0FMQUdHWVREVFFZRiIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNMVkdFVEdSUkFMVEZfQ1NBUkdEUkdRUFFIRiIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNMVkdFVEdSUkFMVEZfQ1NBUkdEUkdRUFFIRjtDQVRTREZLUVZTTlFQUUhGIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ0FUR1BOR1NTTlRHS0xJRl9DU0FUVEdGWUdZVEYiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOQV9DU0FSR0RSR1FQUUhGIikpICsgCiMgICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImdyZXkiLCBjb2xvcmJsaW5kX3ZlY3RvclszXSkpCiMgCiMgCiMgCiMgYWxsdXZpYWxDbG9uZXMoc2NSZXBfZXhhbXBsZSwgCiMgICAgICAgICAgICAgICAgICAgIGNsb25lQ2FsbCA9ICJnZW5lIiwgCiMgICAgICAgICAgICAgICAgICAgIHkuYXhlcyA9IGMoIlBhdGllbnRfb3JpZ2luIiwgIm9yaWcuaWRlbnQiLCAiQ2VsbF9saW5lX0ltbXVub3BoZW5vdHlwZSIpLCAKIyAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiaWRlbnQiKSAKCgoKbGlicmFyeShjaXJjbGl6ZSkKbGlicmFyeShzY2FsZXMpCgpjaXJjbGVzIDwtIGdldENpcmNsaXplKHNjUmVwX2V4YW1wbGUsIAogICAgICAgICAgICAgICAgICAgICAgIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVycyIpCgojSnVzdCBhc3NpZ25pbmcgdGhlIG5vcm1hbCBjb2xvcnMgdG8gZWFjaCBjbHVzdGVyCmdyaWQuY29scyA8LSBodWVfcGFsKCkobGVuZ3RoKHVuaXF1ZShzY1JlcF9leGFtcGxlJHNldXJhdF9jbHVzdGVycykpKQpuYW1lcyhncmlkLmNvbHMpIDwtIHVuaXF1ZShzY1JlcF9leGFtcGxlJHNldXJhdF9jbHVzdGVycykKCiNHcmFwaGluZyB0aGUgY2hvcmQgZGlhZ3JhbQpjaG9yZERpYWdyYW0oY2lyY2xlcywgc2VsZi5saW5rID0gMSwgZ3JpZC5jb2wgPSBncmlkLmNvbHMpCgoKY2lyY2xlcyA8LSBnZXRDaXJjbGl6ZShzY1JlcF9leGFtcGxlLCBncm91cC5ieSA9ICJjZWxsX2xpbmUiLCBwcm9wb3J0aW9uID0gVFJVRSkKCmdyaWQuY29scyA8LSBzY2FsZXM6Omh1ZV9wYWwoKShsZW5ndGgodW5pcXVlKHNjUmVwX2V4YW1wbGVAYWN0aXZlLmlkZW50KSkpCm5hbWVzKGdyaWQuY29scykgPC0gbGV2ZWxzKHNjUmVwX2V4YW1wbGVAYWN0aXZlLmlkZW50KQoKY2hvcmREaWFncmFtKGNpcmNsZXMsIAogICAgICAgICAgICAgc2VsZi5saW5rID0gMSwgCiAgICAgICAgICAgICBncmlkLmNvbCA9IGdyaWQuY29scywgCiAgICAgICAgICAgICBkaXJlY3Rpb25hbCA9IDEsIAogICAgICAgICAgICAgZGlyZWN0aW9uLnR5cGUgPSAgImFycm93cyIsCiAgICAgICAgICAgICBsaW5rLmFyci50eXBlID0gImJpZy5hcnJvdyIpCmBgYA==