Status: partial reference only.
This HTML contains 51 saved plots, not verified reruns. Reproduction needs eight Cell Ranger contig files and a compatible Seurat object, none included here. Six output blocks contain only NA. Saved output also records invalid factor levels, the missing All_samples_Merged dataset, and six non-finite rows removed by a boxplot; affected panels are unverified.
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:
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==