1 Introduction

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

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

References:

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

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

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

# Tables/exports
library(gt)
library(writexl)

# ---------- Output folders ----------
BASE_OUT <- "TCR_analysis-12-01-2026"
DIRS <- list(
  base      = BASE_OUT,
  tables    = file.path(BASE_OUT, "Tables"),
  figures   = file.path(BASE_OUT, "Figures"),
  clonality = file.path(BASE_OUT, "Clonality_Analysis"),
  cl_fig    = file.path(BASE_OUT, "Clonality_Analysis", "Figures"),
  cl_tab    = file.path(BASE_OUT, "Clonality_Analysis", "Tables"),
  phylo     = file.path(BASE_OUT, "Phylogeny"),
  objects   = file.path(BASE_OUT, "Seurat_Objects")
)

invisible(lapply(DIRS, dir.create, showWarnings = FALSE, recursive = TRUE))

# ---------- knitr: save ALL chunk figures into Figures/knitr-* automatically ----------
knitr::opts_chunk$set(
  fig.path = file.path(DIRS$figures, "knitr-"),
  dpi = 300,
  fig.width = 8,
  fig.height = 5,
  message = FALSE,
  warning = FALSE
)

# Helper to save ggplots with consistent dimensions
save_plot <- function(p, filename, w = 11, h = 6.5, dpi = 300) {
  ggsave(filename = filename, plot = p, width = w, height = h, dpi = dpi, limitsize = FALSE)
}

cat("Created output folders under:", BASE_OUT, "\n")
Created output folders under: TCR_analysis-12-01-2026 

2 Load Seurat Object


#Load Seurat Object merged from cell lines and a control(PBMC) after filtration
All_samples_Merged <- readRDS("../../0-Seurat_RDS_Final_OBJECT/All_samples_Merged_with_Renamed_Clusters_final-26-10-2025.rds")

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

3 Load contigs

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

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

-make a list in the R environment.

3.1 Create display_sample column for uniform naming

# Create a new metadata column for plotting with simplified sample names
All_samples_Merged$display_sample <- All_samples_Merged$orig.ident

# Rename L3_B and L4_B to L3 and L4
All_samples_Merged$display_sample <- gsub("^L3_B$", "L3", All_samples_Merged$display_sample)
All_samples_Merged$display_sample <- gsub("^L4_B$", "L4", All_samples_Merged$display_sample)

# Rename PBMC to CD4T_lab
All_samples_Merged$display_sample <- gsub("^PBMC$", "CD4T_lab", All_samples_Merged$display_sample)

4 Combining Contigs into Clones

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

4.1 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", "L4", "L5", "L6", "L7"),
  removeNA = FALSE,
  removeMulti = FALSE,
  filterMulti = FALSE
)

combined.TCR_with_PBMC <- combineTCR(
  contig_list_with_PBMC,
  samples = c("L1", "L2", "L3", "L4", "L5", "L6", "L7", "CD4T_lab"),
  removeNA = FALSE,
  removeMulti = FALSE,
  filterMulti = FALSE
)

# Ensure output dirs exist
dir.create(BASE_OUT, showWarnings = FALSE, recursive = TRUE)

exportClones(combined.TCR,
             write.file = TRUE,
             dir = BASE_OUT,
             file.name = "clones.csv")

exportClones(combined.TCR_with_PBMC,
             write.file = TRUE,
             dir = BASE_OUT,
             file.name = "clones_with_PBMC.csv")

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

write.csv(combined_TCR_df,
          file = file.path(DIRS$tables, "combined_TCR.csv"),
          row.names = FALSE)

write.csv(combined_TCR_with_PBMC_df,
          file = file.path(DIRS$tables, "combined_TCR_with_PBMC.csv"),
          row.names = FALSE)

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

4.2 Write the fasta file for phylogeny


dir.create(DIRS$phylo, showWarnings = FALSE, recursive = TRUE)

# Alpha FASTA
alpha_fasta_file <- file.path(DIRS$phylo, "cdr3_alpha_sequences.fasta")
fa <- file(alpha_fasta_file, open = "w")
for (i in seq_len(nrow(combined_TCR_with_PBMC_df))) {
  if (!is.na(combined_TCR_with_PBMC_df$cdr3_nt1[i])) {
    writeLines(paste0(">", combined_TCR_with_PBMC_df$sample[i], "_alpha_", i), fa)
    writeLines(combined_TCR_with_PBMC_df$cdr3_nt1[i], fa)
  }
}
close(fa)

# Beta FASTA
beta_fasta_file <- file.path(DIRS$phylo, "cdr3_beta_sequences.fasta")
fb <- file(beta_fasta_file, open = "w")
for (i in seq_len(nrow(combined_TCR_with_PBMC_df))) {
  if (!is.na(combined_TCR_with_PBMC_df$cdr3_nt2[i])) {
    writeLines(paste0(">", combined_TCR_with_PBMC_df$sample[i], "_beta_", i), fb)
    writeLines(combined_TCR_with_PBMC_df$cdr3_nt2[i], fb)
  }
}
close(fb)

cat("Alpha FASTA:", alpha_fasta_file, "\n")
Alpha FASTA: TCR_analysis-12-01-2026/Phylogeny/cdr3_alpha_sequences.fasta 
cat("Beta  FASTA:", beta_fasta_file, "\n")
Beta  FASTA: TCR_analysis-12-01-2026/Phylogeny/cdr3_beta_sequences.fasta 

5 Basic Clonal Visualizations

5.1 clonalQuant: Quantifying Unique Clones

p_cq1 <- clonalQuant(combined.TCR, cloneCall="strict", chain="both", scale=TRUE)
p_cq2 <- clonalQuant(combined.TCR_with_PBMC, cloneCall="strict", chain="both", scale=TRUE)
p_cq3 <- clonalQuant(combined.TCR, cloneCall="strict", chain="both", scale=FALSE)
p_cq4 <- clonalQuant(combined.TCR_with_PBMC, cloneCall="strict", chain="both", scale=FALSE)

print(p_cq1); save_plot(p_cq1, file.path(DIRS$figures, "clonalQuant_combined_scaleTRUE.pdf"), 10, 5)

print(p_cq2); save_plot(p_cq2, file.path(DIRS$figures, "clonalQuant_withPBMC_scaleTRUE.pdf"), 10, 5)

print(p_cq3); save_plot(p_cq3, file.path(DIRS$figures, "clonalQuant_combined_scaleFALSE.pdf"), 10, 5)

print(p_cq4); save_plot(p_cq4, file.path(DIRS$figures, "clonalQuant_withPBMC_scaleFALSE.pdf"), 10, 5)

5.2 clonalAbundance: Distribution of Clones by Size

p_ca1 <- clonalAbundance(combined.TCR_with_PBMC, cloneCall="gene", palette="Zissou 1", scale=FALSE)
p_ca2 <- clonalAbundance(combined.TCR_with_PBMC, cloneCall="gene", palette="Zissou 1", scale=TRUE)
p_ca3 <- clonalAbundance(combined.TCR, cloneCall="gene", scale=FALSE)
p_ca4 <- clonalAbundance(combined.TCR, cloneCall="gene", scale=TRUE)

print(p_ca1); save_plot(p_ca1, file.path(DIRS$figures, "clonalAbundance_withPBMC_scaleFALSE.pdf"), 10, 5)

print(p_ca2); save_plot(p_ca2, file.path(DIRS$figures, "clonalAbundance_withPBMC_scaleTRUE.pdf"), 10, 5)

print(p_ca3); save_plot(p_ca3, file.path(DIRS$figures, "clonalAbundance_combined_scaleFALSE.pdf"), 10, 5)

print(p_ca4); save_plot(p_ca4, file.path(DIRS$figures, "clonalAbundance_combined_scaleTRUE.pdf"), 10, 5)

5.3 clonalLength (kept as in your script; knitr will auto-save figures)

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

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

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

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


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

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

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

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


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

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

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

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

5.4 clonalCompare: Clonal Dynamics Between Categorical Variables

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

print(p_cc1); save_plot(p_cc1, file.path(DIRS$figures, "clonalCompare_L1_L2_alluvial.pdf"), 12, 5)

print(p_cc2); save_plot(p_cc2, file.path(DIRS$figures, "clonalCompare_L3_L4_alluvial.pdf"), 12, 5)

print(p_cc3); save_plot(p_cc3, file.path(DIRS$figures, "clonalCompare_L5_L6_L7_alluvial.pdf"), 12, 5)

# clonalCompare

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

print(p_cc_all1); save_plot(p_cc_all1, file.path(DIRS$figures, "clonalCompare_all_withPBMC_alluvial.pdf"), 16, 5)

print(p_cc_all2); save_plot(p_cc_all2, file.path(DIRS$figures, "clonalCompare_all_celllines_alluvial.pdf"), 16, 5)

5.5 clonalScatter: Scatterplot of Two Variables (knitr will auto-save)

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

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

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

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

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

6 Visualizing Clonal Dynamics

6.1 clonalHomeostasis: Examining Clonal Space

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

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

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



clonalHomeostasis(combined.TCR, cloneCall="gene",
                  cloneSize = c("Minor" = 1, "Major" = 10, "Dominant" = Inf))

NA
NA

6.2 clonalHomeostasis: Examining Clonal Space

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

clonalHomeostasis(combined.TCR, cloneCall="aa",
                  cloneSize=c("Minor"=1, "Major"=10, "Dominant"=Inf))

6.3 clonalProportion: Examining Space Occupied by Ranks of Clones

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

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

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

7 Summarizing Repertoires

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


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

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


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

7.1 percentGeneUsage

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

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


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

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


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

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


vizGenes(combined.TCR[c(1,2)], x.axis="TRBV", y.axis="TRAV", plot="heatmap", summary.fun="percent")

vizGenes(combined.TCR[c(3,4)], x.axis="TRBV", y.axis="TRAV", plot="heatmap", summary.fun="percent")

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

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

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

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

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

# percentGenes: Quantifying Single Gene Usage
percentGenes(combined.TCR, chain = "TRB", gene = "Vgene")

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

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

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

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

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

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

# percentKmer

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

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

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

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

8 Comparing Clonal Diversity and Overlap


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

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

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

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

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

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


#clonalOverlap

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

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

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

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


clonalRarefaction(combined.TCR, plot.type=1, hill.numbers=0, n.boots=2)

clonalRarefaction(combined.TCR_with_PBMC, plot.type=1, hill.numbers=0, n.boots=2)


clonalRarefaction(combined.TCR, plot.type=2, hill.numbers=0, n.boots=2)

clonalRarefaction(combined.TCR_with_PBMC, plot.type=2, hill.numbers=0, n.boots=2)


clonalRarefaction(combined.TCR, plot.type=3, hill.numbers=0, n.boots=2)

clonalRarefaction(combined.TCR_with_PBMC, plot.type=3, hill.numbers=0, n.boots=2)


clonalRarefaction(combined.TCR, plot.type=1, hill.numbers=1, n.boots=2)

clonalRarefaction(combined.TCR_with_PBMC, plot.type=1, hill.numbers=1, n.boots=2)


clonalRarefaction(combined.TCR,
                  plot.type = 3,
                  hill.numbers = 0,
                  n.boots = 2)


clonalRarefaction(combined.TCR_with_PBMC,
                  plot.type = 3,
                  hill.numbers = 0,
                  n.boots = 2)

# Rarefaction using Shannon Diversity (q = 1)
clonalRarefaction(combined.TCR,
                  plot.type = 1,
                  hill.numbers = 1,
                  n.boots = 2)


clonalRarefaction(combined.TCR_with_PBMC,
                  plot.type = 1,
                  hill.numbers = 1,
                  n.boots = 2)

9 save the TCR object for future Use

  saveRDS(All_samples_Merged, file = "TCR_analysis-12-01-2026/Seurat_Objects/TCR_Seurat_with_cloneSize_20_12_2026_finalized.rds")
LS0tCnRpdGxlOiAiVENSIEFuYWx5c2lzLTE5LTEyLTIwMjZfVmlzdWFsaXphdGlvbiIKYXV0aG9yOiBOYXNpciBNYWhtb29kIEFiYmFzaQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgY3NzOiBzdHlsZS5jc3MKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogdHJ1ZQogICAgdGhlbWU6IGpvdXJuYWwKLS0tCgojICoqSW50cm9kdWN0aW9uKioKClNpbmdsZS1jZWxsIHNlcXVlbmNpbmcgaXMgYW4gZW1lcmdpbmcgdGVjaG5vbG9neSBpbiB0aGUgZmllbGQgb2YgaW1tdW5vbG9neSBhbmQgb25jb2xvZ3kgdGhhdCBhbGxvd3MgcmVzZWFyY2hlcnMgdG8gY291cGxlIFJOQSBxdWFudGlmaWNhdGlvbiBhbmQgb3RoZXIgbW9kYWxpdGllcywgbGlrZSBpbW11bmUgY2VsbCByZWNlcHRvciBwcm9maWxpbmcgYXQgdGhlIGxldmVsIG9mIGFuIGluZGl2aWR1YWwgY2VsbC4gQSBudW1iZXIgb2Ygd29ya2Zsb3dzIGFuZCBzb2Z0d2FyZSBwYWNrYWdlcyBoYXZlIGJlZW4gY3JlYXRlZCB0byBwcm9jZXNzIGFuZCBhbmFseXplIHNpbmdsZS1jZWxsIHRyYW5zY3JpcHRvbWljIGRhdGEuIFRoZXNlIHBhY2thZ2VzIGFsbG93IHVzZXJzIHRvIHRha2UgdGhlIHZhc3QgZGltZW5zaW9uYWxpdHkgb2YgdGhlIGRhdGEgZ2VuZXJhdGVkIGluIHNpbmdsZS1jZWxsLWJhc2VkIGV4cGVyaW1lbnRzIGFuZCBkaXN0aWxsIHRoZSBkYXRhIGludG8gbm92ZWwgaW5zaWdodHMuIFVubGlrZSB0aGUgdHJhbnNjcmlwdG9taWMgZmllbGQsIHRoZXJlIGlzIGEgbGFjayBvZiBvcHRpb25zIGZvciBzb2Z0d2FyZSB0aGF0IGFsbG93IGZvciBzaW5nbGUtY2VsbCBpbW11bmUgcmVjZXB0b3IgcHJvZmlsaW5nLiBFbmFibGluZyB1c2VycyB0byBlYXNpbHkgY29tYmluZSBSTkEgYW5kIGltbXVuZSBwcm9maWxpbmcsIHRoZSBzY1JlcGVydG9pcmUgZnJhbWV3b3JrIHN1cHBvcnRzIHVzZSBvZiAxMHgsIHNpbmdsZS1jZWxsIGNsb25hbCBmb3JtYXRzIGFuZCBpbnRlcmFjdGlvbiB3aXRoIHBvcHVsYXIgUi1iYXNlZCBzaW5nbGUtY2VsbCBkYXRhIHBpcGVsaW5lcy4KCnNjUmVwZXJ0b2lyZSBpcyBkZXNpZ25lZCB0byB0YWtlIGZpbHRlciBjb250aWcgb3V0cHV0cyBmcm9tIHRoZSAxMHggR2Vub21pY3MgQ2VsbCBSYW5nZXIgcGlwZWxpbmUsIHByb2Nlc3MgdGhhdCBkYXRhIHRvIGFzc2lnbiBjbG9ub3R5cGUgYmFzZWQgb24gdHdvIFRDUiBvciBJZyBjaGFpbnMgYW5kIGFuYWx5emUgdGhlIGNsb25vdHlwZSBkeW5hbWljcy4gVGhlIGxhdHRlciBjYW4gYmUgc2VwYXJhdGVkIGludG8gMSkgY2xvbm90eXBlLW9ubHkgYW5hbHlzaXMgZnVuY3Rpb25zLCBzdWNoIGFzIHVuaXF1ZSBjbG9ub3R5cGVzIG9yIGNsb25hbCBzcGFjZSBxdWFudGlmaWNhdGlvbiwgYW5kIDIpIGludGVyYWN0aW9uIHdpdGggbVJOQSBleHByZXNzaW9uIGRhdGEgdXNpbmcgU2V1cmF0IG9yIFNpbmdsZUNlbGxFeHBlcmltZW50IHBhY2thZ2VzLgoKKipSZWZlcmVuY2VzOioqCgotIFtzY1JlcGVydG9pcmUgVmlnbmV0dGVdKGh0dHBzOi8vd3d3LmJpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvcmVsZWFzZS9iaW9jL3ZpZ25ldHRlL3NjUmVwZXJ0b2lyZS9pbnN0L2RvYy92aWduZXR0ZS5odG1sKQotIFtCb3JjaC5kZXYgc2NSZXBlcnRvaXJlXShodHRwczovL3d3dy5ib3JjaC5kZXYvdXBsb2Fkcy9zY3JlcGVydG9pcmUvKQoKKipQcmVyZXF1aXNpdGU6KiogRW5zdXJlIHRoZSBgQWxsX3NhbXBsZXNfTWVyZ2VkYCBTZXVyYXQgb2JqZWN0IGlzIGxvYWRlZCBpbnRvIHlvdXIgUiBlbnZpcm9ubWVudCBiZWZvcmUgcnVubmluZyB0aGUgY2h1bmtzIGJlbG93LgojIyBMb2FkIGxpYnJhcmllcwpgYGB7cn0KIyBDb3JlCmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KFNldXJhdE9iamVjdCkKbGlicmFyeShTZXVyYXREYXRhKQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShybWFya2Rvd24pCmxpYnJhcnkodGlueXRleCkKbGlicmFyeShncmlkKQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkocHJlc3RvKQoKIyBUQ1IgQW5hbHlzaXMKbGlicmFyeShzY1JlcGVydG9pcmUpCmxpYnJhcnkoU2luZ2xlQ2VsbEV4cGVyaW1lbnQpCmxpYnJhcnkoY2lyY2xpemUpCmxpYnJhcnkoc2NhbGVzKQoKIyBUYWJsZXMvZXhwb3J0cwpsaWJyYXJ5KGd0KQpsaWJyYXJ5KHdyaXRleGwpCgojIC0tLS0tLS0tLS0gT3V0cHV0IGZvbGRlcnMgLS0tLS0tLS0tLQpCQVNFX09VVCA8LSAiVENSX2FuYWx5c2lzLTEyLTAxLTIwMjYiCkRJUlMgPC0gbGlzdCgKICBiYXNlICAgICAgPSBCQVNFX09VVCwKICB0YWJsZXMgICAgPSBmaWxlLnBhdGgoQkFTRV9PVVQsICJUYWJsZXMiKSwKICBmaWd1cmVzICAgPSBmaWxlLnBhdGgoQkFTRV9PVVQsICJGaWd1cmVzIiksCiAgY2xvbmFsaXR5ID0gZmlsZS5wYXRoKEJBU0VfT1VULCAiQ2xvbmFsaXR5X0FuYWx5c2lzIiksCiAgY2xfZmlnICAgID0gZmlsZS5wYXRoKEJBU0VfT1VULCAiQ2xvbmFsaXR5X0FuYWx5c2lzIiwgIkZpZ3VyZXMiKSwKICBjbF90YWIgICAgPSBmaWxlLnBhdGgoQkFTRV9PVVQsICJDbG9uYWxpdHlfQW5hbHlzaXMiLCAiVGFibGVzIiksCiAgcGh5bG8gICAgID0gZmlsZS5wYXRoKEJBU0VfT1VULCAiUGh5bG9nZW55IiksCiAgb2JqZWN0cyAgID0gZmlsZS5wYXRoKEJBU0VfT1VULCAiU2V1cmF0X09iamVjdHMiKQopCgppbnZpc2libGUobGFwcGx5KERJUlMsIGRpci5jcmVhdGUsIHNob3dXYXJuaW5ncyA9IEZBTFNFLCByZWN1cnNpdmUgPSBUUlVFKSkKCiMgLS0tLS0tLS0tLSBrbml0cjogc2F2ZSBBTEwgY2h1bmsgZmlndXJlcyBpbnRvIEZpZ3VyZXMva25pdHItKiBhdXRvbWF0aWNhbGx5IC0tLS0tLS0tLS0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGZpZy5wYXRoID0gZmlsZS5wYXRoKERJUlMkZmlndXJlcywgImtuaXRyLSIpLAogIGRwaSA9IDMwMCwKICBmaWcud2lkdGggPSA4LAogIGZpZy5oZWlnaHQgPSA1LAogIG1lc3NhZ2UgPSBGQUxTRSwKICB3YXJuaW5nID0gRkFMU0UKKQoKIyBIZWxwZXIgdG8gc2F2ZSBnZ3Bsb3RzIHdpdGggY29uc2lzdGVudCBkaW1lbnNpb25zCnNhdmVfcGxvdCA8LSBmdW5jdGlvbihwLCBmaWxlbmFtZSwgdyA9IDExLCBoID0gNi41LCBkcGkgPSAzMDApIHsKICBnZ3NhdmUoZmlsZW5hbWUgPSBmaWxlbmFtZSwgcGxvdCA9IHAsIHdpZHRoID0gdywgaGVpZ2h0ID0gaCwgZHBpID0gZHBpLCBsaW1pdHNpemUgPSBGQUxTRSkKfQoKY2F0KCJDcmVhdGVkIG91dHB1dCBmb2xkZXJzIHVuZGVyOiIsIEJBU0VfT1VULCAiXG4iKQpgYGAKCiMgICBMb2FkIFNldXJhdCBPYmplY3QKYGBge3J9CgojTG9hZCBTZXVyYXQgT2JqZWN0IG1lcmdlZCBmcm9tIGNlbGwgbGluZXMgYW5kIGEgY29udHJvbChQQk1DKSBhZnRlciBmaWx0cmF0aW9uCkFsbF9zYW1wbGVzX01lcmdlZCA8LSByZWFkUkRTKCIuLi8uLi8wLVNldXJhdF9SRFNfRmluYWxfT0JKRUNUL0FsbF9zYW1wbGVzX01lcmdlZF93aXRoX1JlbmFtZWRfQ2x1c3RlcnNfZmluYWwtMjYtMTAtMjAyNS5yZHMiKQoKQWxsX3NhbXBsZXNfTWVyZ2VkCmBgYAoKIyAgTG9hZCBjb250aWdzCgpzY1JlcGVydG9pcmUgZnVuY3Rpb25zIHVzaW5nIHRoZSBmaWx0ZXJlZF9jb250aWdfYW5ub3RhdGlvbnMuY3N2IG91dHB1dCBmcm9tIHRoZSAxMHggR2Vub21pY3MgQ2VsbCBSYW5nZXIuIFRoaXMgZmlsZSBpcyBsb2NhdGVkIGluIHRoZSAuL291dHMvIGRpcmVjdG9yeSBvZiB0aGUgVkRKIGFsaWdubWVudCBmb2xkZXIuIFRvIGdlbmVyYXRlIGEgbGlzdCBvZiBjb250aWdzIHRvIHVzZSBmb3Igc2NSZXBlcnRvaXJlOgoKKiotbG9hZCB0aGUgZmlsdGVyZWRfY29udGlnX2Fubm90YXRpb25zLmNzdiBmb3IgZWFjaCBvZiB0aGUgc2FtcGxlcy4qKgoKKiotbWFrZSBhIGxpc3QgaW4gdGhlIFIgZW52aXJvbm1lbnQuKioKCgpgYGB7ciBUQ1IsIGluY2x1ZGU9RkFMU0V9CkwxIDwtIHJlYWQuY3N2KCIvcnVuL3VzZXIvMTAwMC9ndmZzL3NtYi1zaGFyZTpzZXJ2ZXI9MTAuMTQ0LjE0Mi4xMzEsc2hhcmU9Y29tbXVuL05hc2lyL0FsbF9EYXRhX1NTL0F1ZHJleV9Hcm9zL0NlbGxSYW5nZXIvTDEvb3V0cy9wZXJfc2FtcGxlX291dHMvTDEvdmRqX3QvZmlsdGVyZWRfY29udGlnX2Fubm90YXRpb25zLmNzdiIpCkwyIDwtIHJlYWQuY3N2KCIvcnVuL3VzZXIvMTAwMC9ndmZzL3NtYi1zaGFyZTpzZXJ2ZXI9MTAuMTQ0LjE0Mi4xMzEsc2hhcmU9Y29tbXVuL05hc2lyL0FsbF9EYXRhX1NTL0F1ZHJleV9Hcm9zL0NlbGxSYW5nZXIvTDIvb3V0cy9wZXJfc2FtcGxlX291dHMvTDIvdmRqX3QvZmlsdGVyZWRfY29udGlnX2Fubm90YXRpb25zLmNzdiIpCkwzX0IgPC0gcmVhZC5jc3YoIi9ydW4vdXNlci8xMDAwL2d2ZnMvc21iLXNoYXJlOnNlcnZlcj0xMC4xNDQuMTQyLjEzMSxzaGFyZT1jb21tdW4vTmFzaXIvQWxsX0RhdGFfU1MvQXVkcmV5X0dyb3MvQ2VsbFJhbmdlci9MM19DSVRFX0IvL291dHMvcGVyX3NhbXBsZV9vdXRzL0wzX0NJVEVfQi8vdmRqX3QvZmlsdGVyZWRfY29udGlnX2Fubm90YXRpb25zLmNzdiIpCkw0X0IgPC0gcmVhZC5jc3YoIi9ydW4vdXNlci8xMDAwL2d2ZnMvc21iLXNoYXJlOnNlcnZlcj0xMC4xNDQuMTQyLjEzMSxzaGFyZT1jb21tdW4vTmFzaXIvQWxsX0RhdGFfU1MvQXVkcmV5X0dyb3MvQ2VsbFJhbmdlci9MNF9CL291dHMvcGVyX3NhbXBsZV9vdXRzL0w0X0IvL3Zkal90L2ZpbHRlcmVkX2NvbnRpZ19hbm5vdGF0aW9ucy5jc3YiKQpMNSA8LSByZWFkLmNzdigiL3J1bi91c2VyLzEwMDAvZ3Zmcy9zbWItc2hhcmU6c2VydmVyPTEwLjE0NC4xNDIuMTMxLHNoYXJlPWNvbW11bi9OYXNpci9BbGxfRGF0YV9TUy9BdWRyZXlfR3Jvcy9DZWxsUmFuZ2VyL0w1L291dHMvcGVyX3NhbXBsZV9vdXRzL0w1L3Zkal90L2ZpbHRlcmVkX2NvbnRpZ19hbm5vdGF0aW9ucy5jc3YiKQpMNiA8LSByZWFkLmNzdigiL3J1bi91c2VyLzEwMDAvZ3Zmcy9zbWItc2hhcmU6c2VydmVyPTEwLjE0NC4xNDIuMTMxLHNoYXJlPWNvbW11bi9OYXNpci9BbGxfRGF0YV9TUy9BdWRyZXlfR3Jvcy9DZWxsUmFuZ2VyL0w2X0NJVEUvL291dHMvcGVyX3NhbXBsZV9vdXRzL0w2X0NJVEUvL3Zkal90L2ZpbHRlcmVkX2NvbnRpZ19hbm5vdGF0aW9ucy5jc3YiKQpMNyA8LSByZWFkLmNzdigiL3J1bi91c2VyLzEwMDAvZ3Zmcy9zbWItc2hhcmU6c2VydmVyPTEwLjE0NC4xNDIuMTMxLHNoYXJlPWNvbW11bi9OYXNpci9BbGxfRGF0YV9TUy9BdWRyZXlfR3Jvcy9DZWxsUmFuZ2VyL0w3L291dHMvcGVyX3NhbXBsZV9vdXRzL0w3L3Zkal90L2ZpbHRlcmVkX2NvbnRpZ19hbm5vdGF0aW9ucy5jc3YiKQpQQk1DIDwtIHJlYWQuY3N2KCIvcnVuL3VzZXIvMTAwMC9ndmZzL3NtYi1zaGFyZTpzZXJ2ZXI9MTAuMTQ0LjE0Mi4xMzEsc2hhcmU9Y29tbXVuL05hc2lyL0FsbF9EYXRhX1NTL0F1ZHJleV9Hcm9zL0NlbGxSYW5nZXIvUEJNQy9vdXRzL3Blcl9zYW1wbGVfb3V0cy9QQk1DL3Zkal90L2ZpbHRlcmVkX2NvbnRpZ19hbm5vdGF0aW9ucy5jc3YiKQoKYGBgCgojIyBDcmVhdGUgZGlzcGxheV9zYW1wbGUgY29sdW1uIGZvciB1bmlmb3JtIG5hbWluZwpgYGB7cn0KIyBDcmVhdGUgYSBuZXcgbWV0YWRhdGEgY29sdW1uIGZvciBwbG90dGluZyB3aXRoIHNpbXBsaWZpZWQgc2FtcGxlIG5hbWVzCkFsbF9zYW1wbGVzX01lcmdlZCRkaXNwbGF5X3NhbXBsZSA8LSBBbGxfc2FtcGxlc19NZXJnZWQkb3JpZy5pZGVudAoKIyBSZW5hbWUgTDNfQiBhbmQgTDRfQiB0byBMMyBhbmQgTDQKQWxsX3NhbXBsZXNfTWVyZ2VkJGRpc3BsYXlfc2FtcGxlIDwtIGdzdWIoIl5MM19CJCIsICJMMyIsIEFsbF9zYW1wbGVzX01lcmdlZCRkaXNwbGF5X3NhbXBsZSkKQWxsX3NhbXBsZXNfTWVyZ2VkJGRpc3BsYXlfc2FtcGxlIDwtIGdzdWIoIl5MNF9CJCIsICJMNCIsIEFsbF9zYW1wbGVzX01lcmdlZCRkaXNwbGF5X3NhbXBsZSkKCiMgUmVuYW1lIFBCTUMgdG8gQ0Q0VF9sYWIKQWxsX3NhbXBsZXNfTWVyZ2VkJGRpc3BsYXlfc2FtcGxlIDwtIGdzdWIoIl5QQk1DJCIsICJDRDRUX2xhYiIsIEFsbF9zYW1wbGVzX01lcmdlZCRkaXNwbGF5X3NhbXBsZSkKYGBgCgoKIyAqKkNvbWJpbmluZyBDb250aWdzIGludG8gQ2xvbmVzKioKClRoZXJlIGFyZSB2YXJ5aW5nIGRlZmluaXRpb25zIG9mIGNsb25lcyBpbiB0aGUgbGl0ZXJhdHVyZS4gRm9yIHRoZSBwdXJwb3NlcyBvZiBzY1JlcGVydG9pcmUsIHdlIGRlZmluZSBhIGNsb25lIGFzIGNlbGxzIHdpdGggc2hhcmVkL3RyYWNrYWJsZSBjb21wbGVtZW50YXJpdHktZGV0ZXJtaW5pbmcgcmVnaW9uIDMgKENEUjMpIHNlcXVlbmNlcy4gV2l0aGluIHRoaXMgZGVmaW5pdGlvbiwgb25lIG1pZ2h0IHVzZSBhbWlubyBhY2lkIChhYSkgc2VxdWVuY2VzIG9mIG9uZSBvciBib3RoIGNoYWlucyB0byBkZWZpbmUgYSBjbG9uZS4gQWx0ZXJuYXRpdmVseSwgd2UgY291bGQgdXNlIG51Y2xlb3RpZGUgKG50KSBvciB0aGUgVihEKUpDIGdlbmVzIChnZW5lcykgdG8gZGVmaW5lIGEgY2xvbmUuIFRoZSBsYXR0ZXIsIGdlbmVzLCB3b3VsZCBiZSBhIG1vcmUgcGVybWlzc2l2ZSBkZWZpbml0aW9uIG9mIOKAnGNsb25lcyzigJ0gYXMgbXVsdGlwbGUgYW1pbm8gYWNpZCBvciBudWNsZW90aWRlIHNlcXVlbmNlcyBjYW4gcmVzdWx0IGZyb20gdGhlIHNhbWUgZ2VuZSBjb21iaW5hdGlvbi4gQW5vdGhlciBvcHRpb24gdG8gZGVmaW5lIGEgY2xvbmUgaXMgdGhlIHVzZSBvZiB0aGUgVihEKUpDIGFuZCBudWNsZW90aWRlIHNlcXVlbmNlIChzdHJpY3QpLiBzY1JlcGVydG9pcmUgYWxsb3dzIGZvciB0aGUgdXNlIG9mIGFsbCB0aGVzZSBkZWZpbml0aW9ucyBvZiBjbG9uZXMgYW5kIGVuYWJsZXMgdXNlcnMgdG8gc2VsZWN0IGJvdGggb3IgaW5kaXZpZHVhbCBjaGFpbnMgdG8gZXhhbWluZS4KCiMjIENvbWJpbmluZyBDb250aWdzIGludG8gQ2xvbmVzCmBgYHtyIGNvbWJpbmVkVENSLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD02fQoKY29udGlnX2xpc3QgPC0gbGlzdChMMSwgTDIsIEwzX0IsIEw0X0IsIEw1LCBMNiwgTDcpCmNvbnRpZ19saXN0X3dpdGhfUEJNQyA8LSBsaXN0KEwxLCBMMiwgTDNfQiwgTDRfQiwgTDUsIEw2LCBMNywgUEJNQykKCmNvbWJpbmVkLlRDUiA8LSBjb21iaW5lVENSKAogIGNvbnRpZ19saXN0LAogIHNhbXBsZXMgPSBjKCJMMSIsICJMMiIsICJMMyIsICJMNCIsICJMNSIsICJMNiIsICJMNyIpLAogIHJlbW92ZU5BID0gRkFMU0UsCiAgcmVtb3ZlTXVsdGkgPSBGQUxTRSwKICBmaWx0ZXJNdWx0aSA9IEZBTFNFCikKCmNvbWJpbmVkLlRDUl93aXRoX1BCTUMgPC0gY29tYmluZVRDUigKICBjb250aWdfbGlzdF93aXRoX1BCTUMsCiAgc2FtcGxlcyA9IGMoIkwxIiwgIkwyIiwgIkwzIiwgIkw0IiwgIkw1IiwgIkw2IiwgIkw3IiwgIkNENFRfbGFiIiksCiAgcmVtb3ZlTkEgPSBGQUxTRSwKICByZW1vdmVNdWx0aSA9IEZBTFNFLAogIGZpbHRlck11bHRpID0gRkFMU0UKKQoKIyBFbnN1cmUgb3V0cHV0IGRpcnMgZXhpc3QKZGlyLmNyZWF0ZShCQVNFX09VVCwgc2hvd1dhcm5pbmdzID0gRkFMU0UsIHJlY3Vyc2l2ZSA9IFRSVUUpCgpleHBvcnRDbG9uZXMoY29tYmluZWQuVENSLAogICAgICAgICAgICAgd3JpdGUuZmlsZSA9IFRSVUUsCiAgICAgICAgICAgICBkaXIgPSBCQVNFX09VVCwKICAgICAgICAgICAgIGZpbGUubmFtZSA9ICJjbG9uZXMuY3N2IikKCmV4cG9ydENsb25lcyhjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLAogICAgICAgICAgICAgd3JpdGUuZmlsZSA9IFRSVUUsCiAgICAgICAgICAgICBkaXIgPSBCQVNFX09VVCwKICAgICAgICAgICAgIGZpbGUubmFtZSA9ICJjbG9uZXNfd2l0aF9QQk1DLmNzdiIpCgojIENvbWJpbmUgYWxsIGRhdGEgZnJhbWVzIGluIHRoZSBsaXN0IGludG8gYSBzaW5nbGUgZGF0YSBmcmFtZQpjb21iaW5lZF9UQ1JfZGYgPC0gZG8uY2FsbChyYmluZCwgY29tYmluZWQuVENSKQpjb21iaW5lZF9UQ1Jfd2l0aF9QQk1DX2RmIDwtIGRvLmNhbGwocmJpbmQsIGNvbWJpbmVkLlRDUl93aXRoX1BCTUMpCgp3cml0ZS5jc3YoY29tYmluZWRfVENSX2RmLAogICAgICAgICAgZmlsZSA9IGZpbGUucGF0aChESVJTJHRhYmxlcywgImNvbWJpbmVkX1RDUi5jc3YiKSwKICAgICAgICAgIHJvdy5uYW1lcyA9IEZBTFNFKQoKd3JpdGUuY3N2KGNvbWJpbmVkX1RDUl93aXRoX1BCTUNfZGYsCiAgICAgICAgICBmaWxlID0gZmlsZS5wYXRoKERJUlMkdGFibGVzLCAiY29tYmluZWRfVENSX3dpdGhfUEJNQy5jc3YiKSwKICAgICAgICAgIHJvdy5uYW1lcyA9IEZBTFNFKQoKaGVhZChjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DW10pWzFdCmBgYAoKIyMgIFdyaXRlIHRoZSBmYXN0YSBmaWxlIGZvciBwaHlsb2dlbnkKYGBge3IgcGh5bG9nZW5leUZpbGVzLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD02fQoKZGlyLmNyZWF0ZShESVJTJHBoeWxvLCBzaG93V2FybmluZ3MgPSBGQUxTRSwgcmVjdXJzaXZlID0gVFJVRSkKCiMgQWxwaGEgRkFTVEEKYWxwaGFfZmFzdGFfZmlsZSA8LSBmaWxlLnBhdGgoRElSUyRwaHlsbywgImNkcjNfYWxwaGFfc2VxdWVuY2VzLmZhc3RhIikKZmEgPC0gZmlsZShhbHBoYV9mYXN0YV9maWxlLCBvcGVuID0gInciKQpmb3IgKGkgaW4gc2VxX2xlbihucm93KGNvbWJpbmVkX1RDUl93aXRoX1BCTUNfZGYpKSkgewogIGlmICghaXMubmEoY29tYmluZWRfVENSX3dpdGhfUEJNQ19kZiRjZHIzX250MVtpXSkpIHsKICAgIHdyaXRlTGluZXMocGFzdGUwKCI+IiwgY29tYmluZWRfVENSX3dpdGhfUEJNQ19kZiRzYW1wbGVbaV0sICJfYWxwaGFfIiwgaSksIGZhKQogICAgd3JpdGVMaW5lcyhjb21iaW5lZF9UQ1Jfd2l0aF9QQk1DX2RmJGNkcjNfbnQxW2ldLCBmYSkKICB9Cn0KY2xvc2UoZmEpCgojIEJldGEgRkFTVEEKYmV0YV9mYXN0YV9maWxlIDwtIGZpbGUucGF0aChESVJTJHBoeWxvLCAiY2RyM19iZXRhX3NlcXVlbmNlcy5mYXN0YSIpCmZiIDwtIGZpbGUoYmV0YV9mYXN0YV9maWxlLCBvcGVuID0gInciKQpmb3IgKGkgaW4gc2VxX2xlbihucm93KGNvbWJpbmVkX1RDUl93aXRoX1BCTUNfZGYpKSkgewogIGlmICghaXMubmEoY29tYmluZWRfVENSX3dpdGhfUEJNQ19kZiRjZHIzX250MltpXSkpIHsKICAgIHdyaXRlTGluZXMocGFzdGUwKCI+IiwgY29tYmluZWRfVENSX3dpdGhfUEJNQ19kZiRzYW1wbGVbaV0sICJfYmV0YV8iLCBpKSwgZmIpCiAgICB3cml0ZUxpbmVzKGNvbWJpbmVkX1RDUl93aXRoX1BCTUNfZGYkY2RyM19udDJbaV0sIGZiKQogIH0KfQpjbG9zZShmYikKCmNhdCgiQWxwaGEgRkFTVEE6IiwgYWxwaGFfZmFzdGFfZmlsZSwgIlxuIikKY2F0KCJCZXRhICBGQVNUQToiLCBiZXRhX2Zhc3RhX2ZpbGUsICJcbiIpCmBgYAoKCgojICAqKkJhc2ljIENsb25hbCBWaXN1YWxpemF0aW9ucyoqCgojIyAgY2xvbmFsUXVhbnQ6IFF1YW50aWZ5aW5nIFVuaXF1ZSBDbG9uZXMKYGBge3IgQ2xvbmFsLVZpc3VhbGl6YXRpb24sIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTh9CnBfY3ExIDwtIGNsb25hbFF1YW50KGNvbWJpbmVkLlRDUiwgY2xvbmVDYWxsPSJzdHJpY3QiLCBjaGFpbj0iYm90aCIsIHNjYWxlPVRSVUUpCnBfY3EyIDwtIGNsb25hbFF1YW50KGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIGNsb25lQ2FsbD0ic3RyaWN0IiwgY2hhaW49ImJvdGgiLCBzY2FsZT1UUlVFKQpwX2NxMyA8LSBjbG9uYWxRdWFudChjb21iaW5lZC5UQ1IsIGNsb25lQ2FsbD0ic3RyaWN0IiwgY2hhaW49ImJvdGgiLCBzY2FsZT1GQUxTRSkKcF9jcTQgPC0gY2xvbmFsUXVhbnQoY29tYmluZWQuVENSX3dpdGhfUEJNQywgY2xvbmVDYWxsPSJzdHJpY3QiLCBjaGFpbj0iYm90aCIsIHNjYWxlPUZBTFNFKQoKcHJpbnQocF9jcTEpOyBzYXZlX3Bsb3QocF9jcTEsIGZpbGUucGF0aChESVJTJGZpZ3VyZXMsICJjbG9uYWxRdWFudF9jb21iaW5lZF9zY2FsZVRSVUUucGRmIiksIDEwLCA1KQpwcmludChwX2NxMik7IHNhdmVfcGxvdChwX2NxMiwgZmlsZS5wYXRoKERJUlMkZmlndXJlcywgImNsb25hbFF1YW50X3dpdGhQQk1DX3NjYWxlVFJVRS5wZGYiKSwgMTAsIDUpCnByaW50KHBfY3EzKTsgc2F2ZV9wbG90KHBfY3EzLCBmaWxlLnBhdGgoRElSUyRmaWd1cmVzLCAiY2xvbmFsUXVhbnRfY29tYmluZWRfc2NhbGVGQUxTRS5wZGYiKSwgMTAsIDUpCnByaW50KHBfY3E0KTsgc2F2ZV9wbG90KHBfY3E0LCBmaWxlLnBhdGgoRElSUyRmaWd1cmVzLCAiY2xvbmFsUXVhbnRfd2l0aFBCTUNfc2NhbGVGQUxTRS5wZGYiKSwgMTAsIDUpCmBgYAoKIyMgIGNsb25hbEFidW5kYW5jZTogRGlzdHJpYnV0aW9uIG9mIENsb25lcyBieSBTaXplCmBgYHtyIFYyLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD04fQpwX2NhMSA8LSBjbG9uYWxBYnVuZGFuY2UoY29tYmluZWQuVENSX3dpdGhfUEJNQywgY2xvbmVDYWxsPSJnZW5lIiwgcGFsZXR0ZT0iWmlzc291IDEiLCBzY2FsZT1GQUxTRSkKcF9jYTIgPC0gY2xvbmFsQWJ1bmRhbmNlKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIGNsb25lQ2FsbD0iZ2VuZSIsIHBhbGV0dGU9Ilppc3NvdSAxIiwgc2NhbGU9VFJVRSkKcF9jYTMgPC0gY2xvbmFsQWJ1bmRhbmNlKGNvbWJpbmVkLlRDUiwgY2xvbmVDYWxsPSJnZW5lIiwgc2NhbGU9RkFMU0UpCnBfY2E0IDwtIGNsb25hbEFidW5kYW5jZShjb21iaW5lZC5UQ1IsIGNsb25lQ2FsbD0iZ2VuZSIsIHNjYWxlPVRSVUUpCgpwcmludChwX2NhMSk7IHNhdmVfcGxvdChwX2NhMSwgZmlsZS5wYXRoKERJUlMkZmlndXJlcywgImNsb25hbEFidW5kYW5jZV93aXRoUEJNQ19zY2FsZUZBTFNFLnBkZiIpLCAxMCwgNSkKcHJpbnQocF9jYTIpOyBzYXZlX3Bsb3QocF9jYTIsIGZpbGUucGF0aChESVJTJGZpZ3VyZXMsICJjbG9uYWxBYnVuZGFuY2Vfd2l0aFBCTUNfc2NhbGVUUlVFLnBkZiIpLCAxMCwgNSkKcHJpbnQocF9jYTMpOyBzYXZlX3Bsb3QocF9jYTMsIGZpbGUucGF0aChESVJTJGZpZ3VyZXMsICJjbG9uYWxBYnVuZGFuY2VfY29tYmluZWRfc2NhbGVGQUxTRS5wZGYiKSwgMTAsIDUpCnByaW50KHBfY2E0KTsgc2F2ZV9wbG90KHBfY2E0LCBmaWxlLnBhdGgoRElSUyRmaWd1cmVzLCAiY2xvbmFsQWJ1bmRhbmNlX2NvbWJpbmVkX3NjYWxlVFJVRS5wZGYiKSwgMTAsIDUpCmBgYAoKIyMgIGNsb25hbExlbmd0aCAoa2VwdCBhcyBpbiB5b3VyIHNjcmlwdDsga25pdHIgd2lsbCBhdXRvLXNhdmUgZmlndXJlcykKYGBge3IgVjMsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTh9CmNsb25hbExlbmd0aChjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCBjbG9uZUNhbGw9Im50IiwgY2hhaW49ImJvdGgiKQpjbG9uYWxMZW5ndGgoY29tYmluZWQuVENSX3dpdGhfUEJNQywgY2xvbmVDYWxsPSJhYSIsIGNoYWluPSJib3RoIikKY2xvbmFsTGVuZ3RoKGNvbWJpbmVkLlRDUiwgY2xvbmVDYWxsPSJudCIsIGNoYWluPSJib3RoIikKY2xvbmFsTGVuZ3RoKGNvbWJpbmVkLlRDUiwgY2xvbmVDYWxsPSJhYSIsIGNoYWluPSJib3RoIikKCmNsb25hbExlbmd0aChjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCBjbG9uZUNhbGw9Im50IiwgY2hhaW49IlRSQSIsIHNjYWxlPVRSVUUpCmNsb25hbExlbmd0aChjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCBjbG9uZUNhbGw9ImFhIiwgY2hhaW49IlRSQSIsIHNjYWxlPVRSVUUpCmNsb25hbExlbmd0aChjb21iaW5lZC5UQ1IsIGNsb25lQ2FsbD0ibnQiLCBjaGFpbj0iVFJBIiwgc2NhbGU9VFJVRSkKY2xvbmFsTGVuZ3RoKGNvbWJpbmVkLlRDUiwgY2xvbmVDYWxsPSJhYSIsIGNoYWluPSJUUkEiLCBzY2FsZT1UUlVFKQoKY2xvbmFsTGVuZ3RoKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIGNsb25lQ2FsbD0ibnQiLCBjaGFpbj0iVFJCIiwgc2NhbGU9VFJVRSkKY2xvbmFsTGVuZ3RoKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIGNsb25lQ2FsbD0iYWEiLCBjaGFpbj0iVFJCIiwgc2NhbGU9VFJVRSkKY2xvbmFsTGVuZ3RoKGNvbWJpbmVkLlRDUiwgY2xvbmVDYWxsPSJudCIsIGNoYWluPSJUUkIiLCBzY2FsZT1UUlVFKQpjbG9uYWxMZW5ndGgoY29tYmluZWQuVENSLCBjbG9uZUNhbGw9ImFhIiwgY2hhaW49IlRSQiIsIHNjYWxlPVRSVUUpCgpgYGAKCiMjICBjbG9uYWxDb21wYXJlOiBDbG9uYWwgRHluYW1pY3MgQmV0d2VlbiBDYXRlZ29yaWNhbCBWYXJpYWJsZXMKYGBge3IgVjQsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTh9CnBfY2MxIDwtIGNsb25hbENvbXBhcmUoY29tYmluZWQuVENSLCB0b3AuY2xvbmVzPTEwLCBzYW1wbGVzPWMoIkwxIiwiTDIiKSwgY2xvbmVDYWxsPSJhYSIsIGdyYXBoPSJhbGx1dmlhbCIpCnBfY2MyIDwtIGNsb25hbENvbXBhcmUoY29tYmluZWQuVENSLCB0b3AuY2xvbmVzPTEwLCBzYW1wbGVzPWMoIkwzIiwiTDQiKSwgY2xvbmVDYWxsPSJhYSIsIGdyYXBoPSJhbGx1dmlhbCIpCnBfY2MzIDwtIGNsb25hbENvbXBhcmUoY29tYmluZWQuVENSLCB0b3AuY2xvbmVzPTEwLCBzYW1wbGVzPWMoIkw1IiwiTDYiLCJMNyIpLCBjbG9uZUNhbGw9ImFhIiwgZ3JhcGg9ImFsbHV2aWFsIikKCnByaW50KHBfY2MxKTsgc2F2ZV9wbG90KHBfY2MxLCBmaWxlLnBhdGgoRElSUyRmaWd1cmVzLCAiY2xvbmFsQ29tcGFyZV9MMV9MMl9hbGx1dmlhbC5wZGYiKSwgMTIsIDUpCnByaW50KHBfY2MyKTsgc2F2ZV9wbG90KHBfY2MyLCBmaWxlLnBhdGgoRElSUyRmaWd1cmVzLCAiY2xvbmFsQ29tcGFyZV9MM19MNF9hbGx1dmlhbC5wZGYiKSwgMTIsIDUpCnByaW50KHBfY2MzKTsgc2F2ZV9wbG90KHBfY2MzLCBmaWxlLnBhdGgoRElSUyRmaWd1cmVzLCAiY2xvbmFsQ29tcGFyZV9MNV9MNl9MN19hbGx1dmlhbC5wZGYiKSwgMTIsIDUpCmBgYAoKYGBge3IgLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD0xNn0KIyBjbG9uYWxDb21wYXJlCgpwX2NjX2FsbDEgPC0gY2xvbmFsQ29tcGFyZShjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLAogICAgICAgICAgICAgICAgICAgICAgICAgICB0b3AuY2xvbmVzPTEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGVzPWMoIkwxIiwiTDIiLCJMMyIsIkw0IiwiTDUiLCJMNiIsIkw3IiwiQ0Q0VF9sYWIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xvbmVDYWxsPSJhYSIsIGdyYXBoPSJhbGx1dmlhbCIpCnBfY2NfYWxsMiA8LSBjbG9uYWxDb21wYXJlKGNvbWJpbmVkLlRDUiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9wLmNsb25lcz0xMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlcz1jKCJMMSIsIkwyIiwiTDMiLCJMNCIsIkw1IiwiTDYiLCJMNyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBjbG9uZUNhbGw9ImFhIiwgZ3JhcGg9ImFsbHV2aWFsIikKCnByaW50KHBfY2NfYWxsMSk7IHNhdmVfcGxvdChwX2NjX2FsbDEsIGZpbGUucGF0aChESVJTJGZpZ3VyZXMsICJjbG9uYWxDb21wYXJlX2FsbF93aXRoUEJNQ19hbGx1dmlhbC5wZGYiKSwgMTYsIDUpCnByaW50KHBfY2NfYWxsMik7IHNhdmVfcGxvdChwX2NjX2FsbDIsIGZpbGUucGF0aChESVJTJGZpZ3VyZXMsICJjbG9uYWxDb21wYXJlX2FsbF9jZWxsbGluZXNfYWxsdXZpYWwucGRmIiksIDE2LCA1KQpgYGAKCgojIyAgY2xvbmFsU2NhdHRlcjogU2NhdHRlcnBsb3Qgb2YgVHdvIFZhcmlhYmxlcyAoa25pdHIgd2lsbCBhdXRvLXNhdmUpCmBgYHtyICwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9Nn0KY2xvbmFsU2NhdHRlcihjb21iaW5lZC5UQ1IsIGNsb25lQ2FsbD0iZ2VuZSIsIHguYXhpcz0iTDEiLCB5LmF4aXM9IkwyIiwgZG90LnNpemU9InRvdGFsIiwgZ3JhcGg9InByb3BvcnRpb24iKQpjbG9uYWxTY2F0dGVyKGNvbWJpbmVkLlRDUiwgY2xvbmVDYWxsPSJnZW5lIiwgeC5heGlzPSJMMyIsIHkuYXhpcz0iTDQiLCBkb3Quc2l6ZT0idG90YWwiLCBncmFwaD0icHJvcG9ydGlvbiIpCmNsb25hbFNjYXR0ZXIoY29tYmluZWQuVENSLCBjbG9uZUNhbGw9ImdlbmUiLCB4LmF4aXM9Ikw1IiwgeS5heGlzPSJMNiIsIGRvdC5zaXplPSJ0b3RhbCIsIGdyYXBoPSJwcm9wb3J0aW9uIikKY2xvbmFsU2NhdHRlcihjb21iaW5lZC5UQ1IsIGNsb25lQ2FsbD0iZ2VuZSIsIHguYXhpcz0iTDUiLCB5LmF4aXM9Ikw3IiwgZG90LnNpemU9InRvdGFsIiwgZ3JhcGg9InByb3BvcnRpb24iKQpjbG9uYWxTY2F0dGVyKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIGNsb25lQ2FsbD0iZ2VuZSIsIHguYXhpcz0iTDYiLCB5LmF4aXM9Ikw3IiwgZG90LnNpemU9InRvdGFsIiwgZ3JhcGg9InByb3BvcnRpb24iKQpgYGAKCgojICoqVmlzdWFsaXppbmcgQ2xvbmFsIER5bmFtaWNzKioKCiMjICBjbG9uYWxIb21lb3N0YXNpczogRXhhbWluaW5nIENsb25hbCBTcGFjZQpgYGB7ciAsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTh9CmNsb25hbEhvbWVvc3Rhc2lzKGNvbWJpbmVkLlRDUiwgY2xvbmVDYWxsPSJnZW5lIikKY2xvbmFsSG9tZW9zdGFzaXMoY29tYmluZWQuVENSLCBjbG9uZUNhbGw9ImdlbmUiLAogICAgICAgICAgICAgICAgICBjbG9uZVNpemU9YyhSYXJlPTAuMDAxLFNtYWxsPTAuMDEsTWVkaXVtPTAuMSxMYXJnZT0wLjMsSHlwZXJleHBhbmRlZD0xKSkKY2xvbmFsSG9tZW9zdGFzaXMoY29tYmluZWQuVENSLCBjbG9uZUNhbGw9ImdlbmUiLAogICAgICAgICAgICAgICAgICBjbG9uZVNpemU9YyhSYXJlPTAuMDEsIFNtYWxsPTAuMSwgTWVkaXVtPTEsIExhcmdlPTUsIEh5cGVyZXhwYW5kZWQ9MjApKQoKCmNsb25hbEhvbWVvc3Rhc2lzKGNvbWJpbmVkLlRDUiwgY2xvbmVDYWxsPSJnZW5lIiwKICAgICAgICAgICAgICAgICAgY2xvbmVTaXplID0gYygiTWlub3IiID0gMSwgIk1ham9yIiA9IDEwLCAiRG9taW5hbnQiID0gSW5mKSkKCgpgYGAKCiMjICBjbG9uYWxIb21lb3N0YXNpczogRXhhbWluaW5nIENsb25hbCBTcGFjZQpgYGB7ciAsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTh9CmNsb25hbEhvbWVvc3Rhc2lzKGNvbWJpbmVkLlRDUiwgY2xvbmVDYWxsPSJhYSIsICAgICAjIENoYW5nZWQgZnJvbSAiZ2VuZSIKICAgICAgICAgICAgICAgICAgY2xvbmVTaXplPWMoUmFyZT0wLjAwMSxTbWFsbD0wLjAxLE1lZGl1bT0wLjEsTGFyZ2U9MC4zLEh5cGVyZXhwYW5kZWQ9MSkpCmNsb25hbEhvbWVvc3Rhc2lzKGNvbWJpbmVkLlRDUiwgY2xvbmVDYWxsPSJhYSIsCiAgICAgICAgICAgICAgICAgIGNsb25lU2l6ZT1jKCJNaW5vciI9MSwgIk1ham9yIj0xMCwgIkRvbWluYW50Ij1JbmYpKQoKYGBgCgojIyAgY2xvbmFsUHJvcG9ydGlvbjogRXhhbWluaW5nIFNwYWNlIE9jY3VwaWVkIGJ5IFJhbmtzIG9mIENsb25lcwpgYGB7ciBTdGF0cywgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MjF9CmNsb25hbFByb3BvcnRpb24oY29tYmluZWQuVENSLCBjbG9uZUNhbGw9ImdlbmUiKQpjbG9uYWxQcm9wb3J0aW9uKGNvbWJpbmVkLlRDUiwgY2xvbmVDYWxsPSJudCIsIGNsb25hbFNwbGl0PWMoMSw1LDEwLDEwMCwxMDAwLDEwMDAwKSkKY2xvbmFsUHJvcG9ydGlvbihjb21iaW5lZC5UQ1IsIGNsb25lQ2FsbD0ibnQiLCBjbG9uYWxTcGxpdD1jKDEwLDEwMCwxMDAwLDEwMDAwLDMwMDAwLDEwMDAwMCkpCmBgYAoKCgojICoqU3VtbWFyaXppbmcgUmVwZXJ0b2lyZXMqKgpgYGB7ciBERSwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CnBlcmNlbnRBQShjb21iaW5lZC5UQ1IsIGNoYWluPSJUUkIiLCBhYS5sZW5ndGg9MjApCgpwb3NpdGlvbmFsRW50cm9weShjb21iaW5lZC5UQ1IsIGNoYWluPSJUUkIiLCBhYS5sZW5ndGg9MjApCnBvc2l0aW9uYWxFbnRyb3B5KGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIGNoYWluPSJUUkIiLCBhYS5sZW5ndGg9MjApCgpwb3NpdGlvbmFsUHJvcGVydHkoY29tYmluZWQuVENSW2MoMSwyKV0sIGNoYWluPSJUUkIiLCBhYS5sZW5ndGg9MjAsIG1ldGhvZD0iYXRjaGxleUZhY3RvcnMiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1oY2wuY29sb3JzKDUsICJpbmZlcm5vIilbYygyLDQpXSkKCmBgYAoKCiMjIHBlcmNlbnRHZW5lVXNhZ2UKCmBgYHtyLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD00fQojIHBlcmNlbnRHZW5lVXNhZ2UKdml6R2VuZXMoY29tYmluZWQuVENSLCB4LmF4aXM9IlRSQlYiLCB5LmF4aXM9TlVMTCwgcGxvdD0iYmFycGxvdCIsIHN1bW1hcnkuZnVuPSJwcm9wb3J0aW9uIikKdml6R2VuZXMoY29tYmluZWQuVENSLCB4LmF4aXM9IlRSQVYiLCB5LmF4aXM9TlVMTCwgcGxvdD0iYmFycGxvdCIsIHN1bW1hcnkuZnVuPSJwcm9wb3J0aW9uIikKCmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fQoKdml6R2VuZXMoY29tYmluZWQuVENSX3dpdGhfUEJNQywgeC5heGlzPSJUUkJWIiwgeS5heGlzPU5VTEwsIHBsb3Q9ImJhcnBsb3QiLCBzdW1tYXJ5LmZ1bj0icHJvcG9ydGlvbiIpCnZpekdlbmVzKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIHguYXhpcz0iVFJBViIsIHkuYXhpcz1OVUxMLCBwbG90PSJiYXJwbG90Iiwgc3VtbWFyeS5mdW49InByb3BvcnRpb24iKQoKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTE0fQoKdml6R2VuZXMoY29tYmluZWQuVENSW2MoMSwyLDMsNCw1LDYsNyldLCB4LmF4aXM9IlRSQlYiLCB5LmF4aXM9IlRSQkoiLCBwbG90PSJoZWF0bWFwIiwgc3VtbWFyeS5mdW49InBlcmNlbnQiKQp2aXpHZW5lcyhjb21iaW5lZC5UQ1JbYygxLDIsMyw0LDUsNiw3KV0sIHguYXhpcz0iVFJBViIsIHkuYXhpcz0iVFJBSiIsIHBsb3Q9ImhlYXRtYXAiLCBzdW1tYXJ5LmZ1bj0icGVyY2VudCIpCgpgYGAKCgpgYGB7ciwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OH0KCnZpekdlbmVzKGNvbWJpbmVkLlRDUltjKDEsMildLCB4LmF4aXM9IlRSQlYiLCB5LmF4aXM9IlRSQVYiLCBwbG90PSJoZWF0bWFwIiwgc3VtbWFyeS5mdW49InBlcmNlbnQiKQp2aXpHZW5lcyhjb21iaW5lZC5UQ1JbYygzLDQpXSwgeC5heGlzPSJUUkJWIiwgeS5heGlzPSJUUkFWIiwgcGxvdD0iaGVhdG1hcCIsIHN1bW1hcnkuZnVuPSJwZXJjZW50IikKdml6R2VuZXMoY29tYmluZWQuVENSW2MoNSw2LDcpXSwgeC5heGlzPSJUUkJWIiwgeS5heGlzPSJUUkFWIiwgcGxvdD0iaGVhdG1hcCIsIHN1bW1hcnkuZnVuPSJwZXJjZW50IikKYGBgCgoKCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD02fQojIHBlcmNlbnRHZW5lczogUXVhbnRpZnlpbmcgU2luZ2xlIEdlbmUgVXNhZ2UKcGVyY2VudEdlbmVzKGNvbWJpbmVkLlRDUiwgY2hhaW49IlRSQiIsIGdlbmU9IlZnZW5lIiwgc3VtbWFyeS5mdW49InBlcmNlbnQiKQpwZXJjZW50R2VuZXMoY29tYmluZWQuVENSLCBjaGFpbj0iVFJBIiwgZ2VuZT0iVmdlbmUiLCBzdW1tYXJ5LmZ1bj0icGVyY2VudCIpCnBlcmNlbnRHZW5lcyhjb21iaW5lZC5UQ1IsIGNoYWluPSJUUkIiLCBnZW5lPSJKZ2VuZSIpCnBlcmNlbnRHZW5lcyhjb21iaW5lZC5UQ1IsIGNoYWluPSJUUkEiLCBnZW5lPSJKZ2VuZSIsIHN1bW1hcnkuZnVuPSJwZXJjZW50IikKYGBgCgoKYGBge3IsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTZ9CiMgcGVyY2VudEdlbmVzOiBRdWFudGlmeWluZyBTaW5nbGUgR2VuZSBVc2FnZQpwZXJjZW50R2VuZXMoY29tYmluZWQuVENSLCBjaGFpbiA9ICJUUkIiLCBnZW5lID0gIlZnZW5lIikKcGVyY2VudEdlbmVzKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIGNoYWluID0gIlRSQSIsIGdlbmUgPSAiVmdlbmUiLHN1bW1hcnkuZnVuID0gInBlcmNlbnQiKQpwZXJjZW50R2VuZXMoY29tYmluZWQuVENSX3dpdGhfUEJNQywgY2hhaW4gPSAiVFJCIiwgZ2VuZSA9ICJKZ2VuZSIpCnBlcmNlbnRHZW5lcyhjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCBjaGFpbiA9ICJUUkEiLCBnZW5lID0gIkpnZW5lIixzdW1tYXJ5LmZ1biA9ICJwZXJjZW50IikKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD0yMCwgZmlnLndpZHRoPTI0fQojIHBlcmNlbnRWSgojIFF1YW50aWZ5IHRoZSBwcm9wb3J0aW9uIG9mIFYgYW5kIEogZ2VuZSB1c2FnZSB3aXRoIHBlcmNlbnRWSigpLiBMaWtlIHBlcmNlbnRHZW5lcygpLCB0aGlzIGZ1bmN0aW9uIHdpbGwgcXVhbnRpZnkgdGhlIHBlcmNlbnRhZ2Ugb2YgViBhbmQgSiBwYWlyZWQgdG9nZXRoZXIgYWNyb3NzIGluZGl2aWR1YWwgcmVwZXJ0b2lyZXMuIFRoZSBvdXRwdXQgY2FuIGJlIHZpc3VhbGl6ZWQgdXNpbmcgYSBoZWF0bWFwIG9yIGFzIGlucHV0IGZvciBmdXJ0aGVyIGRpbWVuc2lvbmFsIHJlZHVjdGlvbi4KCnBlcmNlbnRWSihjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCBjaGFpbj0iVFJCIiwgc3VtbWFyeS5mdW49InBlcmNlbnQiKQpwZXJjZW50VkooY29tYmluZWQuVENSX3dpdGhfUEJNQywgY2hhaW49IlRSQSIsIHN1bW1hcnkuZnVuPSJwZXJjZW50IikKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9Nn0KIyBwZXJjZW50S21lcgoKcGVyY2VudEttZXIoY29tYmluZWQuVENSX3dpdGhfUEJNQywgY2xvbmVDYWxsPSJhYSIsIGNoYWluPSJUUkIiLCBtb3RpZi5sZW5ndGg9MywgdG9wLm1vdGlmcz0yNSkKcGVyY2VudEttZXIoY29tYmluZWQuVENSX3dpdGhfUEJNQywgY2xvbmVDYWxsPSJhYSIsIGNoYWluPSJUUkEiLCBtb3RpZi5sZW5ndGg9MywgdG9wLm1vdGlmcz0yNSkKcGVyY2VudEttZXIoY29tYmluZWQuVENSX3dpdGhfUEJNQywgY2xvbmVDYWxsPSJudCIsIGNoYWluPSJUUkIiLCBtb3RpZi5sZW5ndGg9MywgdG9wLm1vdGlmcz0yNSkKcGVyY2VudEttZXIoY29tYmluZWQuVENSX3dpdGhfUEJNQywgY2xvbmVDYWxsPSJudCIsIGNoYWluPSJUUkEiLCBtb3RpZi5sZW5ndGg9MywgdG9wLm1vdGlmcz0yNSkKYGBgCgoKIyAqKkNvbXBhcmluZyBDbG9uYWwgRGl2ZXJzaXR5IGFuZCBPdmVybGFwKioKYGBge3IgY2xvbmFsRGl2ZXJzaXR5LCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD02fQoKIyBjbG9uYWxEaXZlcnNpdHkKY2xvbmFsRGl2ZXJzaXR5KGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIGNsb25lQ2FsbD0iZ2VuZSIpCmNsb25hbERpdmVyc2l0eShjb21iaW5lZC5UQ1IsIGNsb25lQ2FsbD0iZ2VuZSIpCmBgYAoKCmBgYHtyICwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9Nn0KI2Nsb25hbFNpemVEaXN0cmlidXRpb24KY2xvbmFsU2l6ZURpc3RyaWJ1dGlvbihjb21iaW5lZC5UQ1IsIGNsb25lQ2FsbD0iYWEiLCBtZXRob2Q9IndhcmQuRDIiKQpjbG9uYWxTaXplRGlzdHJpYnV0aW9uKGNvbWJpbmVkLlRDUiwgY2xvbmVDYWxsPSJudCIsIG1ldGhvZD0id2FyZC5EMiIpCmNsb25hbFNpemVEaXN0cmlidXRpb24oY29tYmluZWQuVENSX3dpdGhfUEJNQywgY2xvbmVDYWxsPSJhYSIsIG1ldGhvZD0id2FyZC5EMiIpCmNsb25hbFNpemVEaXN0cmlidXRpb24oY29tYmluZWQuVENSX3dpdGhfUEJNQywgY2xvbmVDYWxsPSJudCIsIG1ldGhvZD0id2FyZC5EMiIpCmBgYAoKYGBge3IgLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD02fQoKI2Nsb25hbE92ZXJsYXAKCmNsb25hbE92ZXJsYXAoY29tYmluZWQuVENSX3dpdGhfUEJNQywgY2xvbmVDYWxsPSJzdHJpY3QiLCBtZXRob2Q9Im1vcmlzaXRhIikKY2xvbmFsT3ZlcmxhcChjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCBjbG9uZUNhbGw9InN0cmljdCIsIG1ldGhvZD0icmF3IikKY2xvbmFsT3ZlcmxhcChjb21iaW5lZC5UQ1IsIGNsb25lQ2FsbD0ic3RyaWN0IiwgbWV0aG9kPSJtb3Jpc2l0YSIpCmNsb25hbE92ZXJsYXAoY29tYmluZWQuVENSLCBjbG9uZUNhbGw9InN0cmljdCIsIG1ldGhvZD0icmF3IikKYGBgCgoKYGBge3IgY2xvbmFsUmFyZWZhY3Rpb24sIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTZ9CgpjbG9uYWxSYXJlZmFjdGlvbihjb21iaW5lZC5UQ1IsIHBsb3QudHlwZT0xLCBoaWxsLm51bWJlcnM9MCwgbi5ib290cz0yKQpjbG9uYWxSYXJlZmFjdGlvbihjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCBwbG90LnR5cGU9MSwgaGlsbC5udW1iZXJzPTAsIG4uYm9vdHM9MikKCmNsb25hbFJhcmVmYWN0aW9uKGNvbWJpbmVkLlRDUiwgcGxvdC50eXBlPTIsIGhpbGwubnVtYmVycz0wLCBuLmJvb3RzPTIpCmNsb25hbFJhcmVmYWN0aW9uKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsIHBsb3QudHlwZT0yLCBoaWxsLm51bWJlcnM9MCwgbi5ib290cz0yKQoKY2xvbmFsUmFyZWZhY3Rpb24oY29tYmluZWQuVENSLCBwbG90LnR5cGU9MywgaGlsbC5udW1iZXJzPTAsIG4uYm9vdHM9MikKY2xvbmFsUmFyZWZhY3Rpb24oY29tYmluZWQuVENSX3dpdGhfUEJNQywgcGxvdC50eXBlPTMsIGhpbGwubnVtYmVycz0wLCBuLmJvb3RzPTIpCgpjbG9uYWxSYXJlZmFjdGlvbihjb21iaW5lZC5UQ1IsIHBsb3QudHlwZT0xLCBoaWxsLm51bWJlcnM9MSwgbi5ib290cz0yKQpjbG9uYWxSYXJlZmFjdGlvbihjb21iaW5lZC5UQ1Jfd2l0aF9QQk1DLCBwbG90LnR5cGU9MSwgaGlsbC5udW1iZXJzPTEsIG4uYm9vdHM9MikKCmBgYAoKYGBge3IgLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD02fQoKY2xvbmFsUmFyZWZhY3Rpb24oY29tYmluZWQuVENSLAogICAgICAgICAgICAgICAgICBwbG90LnR5cGUgPSAzLAogICAgICAgICAgICAgICAgICBoaWxsLm51bWJlcnMgPSAwLAogICAgICAgICAgICAgICAgICBuLmJvb3RzID0gMikKCmNsb25hbFJhcmVmYWN0aW9uKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsCiAgICAgICAgICAgICAgICAgIHBsb3QudHlwZSA9IDMsCiAgICAgICAgICAgICAgICAgIGhpbGwubnVtYmVycyA9IDAsCiAgICAgICAgICAgICAgICAgIG4uYm9vdHMgPSAyKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD02fQojIFJhcmVmYWN0aW9uIHVzaW5nIFNoYW5ub24gRGl2ZXJzaXR5IChxID0gMSkKY2xvbmFsUmFyZWZhY3Rpb24oY29tYmluZWQuVENSLAogICAgICAgICAgICAgICAgICBwbG90LnR5cGUgPSAxLAogICAgICAgICAgICAgICAgICBoaWxsLm51bWJlcnMgPSAxLAogICAgICAgICAgICAgICAgICBuLmJvb3RzID0gMikKCmNsb25hbFJhcmVmYWN0aW9uKGNvbWJpbmVkLlRDUl93aXRoX1BCTUMsCiAgICAgICAgICAgICAgICAgIHBsb3QudHlwZSA9IDEsCiAgICAgICAgICAgICAgICAgIGhpbGwubnVtYmVycyA9IDEsCiAgICAgICAgICAgICAgICAgIG4uYm9vdHMgPSAyKQpgYGAKCgoKCiMgKipzYXZlIHRoZSBUQ1Igb2JqZWN0IGZvciBmdXR1cmUgVXNlKioKYGBge3J9CiAgc2F2ZVJEUyhBbGxfc2FtcGxlc19NZXJnZWQsIGZpbGUgPSAiVENSX2FuYWx5c2lzLTEyLTAxLTIwMjYvU2V1cmF0X09iamVjdHMvVENSX1NldXJhdF93aXRoX2Nsb25lU2l6ZV8yMF8xMl8yMDI2X2ZpbmFsaXplZC5yZHMiKQpgYGAKCgoKCgoKCg==