Setup

library(ithi.utils)
load_base_libs()

library(methods)
library(factoextra)

library(ithi.meta)
library(ithi.figures)
library(ithi.utils)
library(ithi.seq)
library(ithi.clones)
library(ithi.supp)
ihc_table_path <- snakemake@input$ihc_table
neoediting_outdir <- snakemake@input$neoediting_outdir
snv_cluster_files <- snakemake@input$snv_cluster_files
clone_tree_file <- snakemake@input$clone_tree_file
clone_branch_length_file <- snakemake@input$clone_branch_length_file
clone_prevalence_file <- snakemake@input$clone_prevalence_file
remixt_ploidy_file <- snakemake@input$remixt_cellularity_ploidy_file
master_variant_file <- snakemake@input$snv_table

db_path <- snakemake@params$db
annotation_colours <- ithi.figures::get_annotation_colours()
ihc_table <- fread(ihc_table_path)
master_variant_table <- read_variant_file(master_variant_file, db_path)

tree_branch_data <- read_clone_tree_data(clone_tree_file, clone_branch_length_file, 
    clone_prevalence_file, db_path)

neoediting_res <- supp_neoediting(neoediting_outdir, ihc_table, db_path, tree_branch_data, 
    wtfilter = TRUE, full_epitopes = FALSE, snv_cluster_files = snv_cluster_files)

Analysis

We need to answer 2 questions:

  • Do whole-genome duplicated (or high ploidy) samples have a higher number/proportion of subclonal mutations?
  • Do whole-genome duplicated (or high ploidy) samples have a higher number/proportion of subclonal neoepitope-generating mutations?

WGD

To examine this, we’ll consider ploidy. Under WGD, the ploidy of a tumour sample should be approximately 4.

remixt_ploidy <- read.table(remixt_ploidy_file, row.names = 1, header = TRUE, 
    stringsAsFactors = FALSE)

remixt_ploidy <- remixt_ploidy %>% rownames_to_column(var = "voa")
remixt_ploidy$patient_id <- ithi.meta::factor_id(remixt_ploidy$patient_id, type = "patient_id", 
    db_path)
remixt_ploidy$condensed_id <- ithi.meta::map_id(remixt_ploidy$voa, from = "voa", 
    to = "condensed_id", db_path)

Subclonal mutations

We’ll address the first bullet point here.

Inclusion/exclusion criteria:

  • When calling clonality/subclonality, we exclude mutations that cannot be unambiguously assigned to a clone in the clonal phylogeny (according to maximum likelihood, see STAR Methods).
## This should be refactored into a package
get_annotated_snvs <- function(snv_cluster_files, tree_branch_data) {
    snv_cluster_patients <- as.list(stringr::str_extract(snv_cluster_files, 
        "(?<=patient_)[0-9]+"))
    snv_cluster <- plyr::rbind.fill(lapply(seq_along(snv_cluster_files), function(i) {
        f <- snv_cluster_files[[i]]
        patient_id <- snv_cluster_patients[[i]]
        snv_cluster <- ithi.clones::read_snv_cluster(f, clone_branch_length_file, 
            db_path)
        return(snv_cluster)
    }))
    trees <- lapply(tree_branch_data, function(x) x$tree)
    branch_lengths <- plyr::rbind.fill(lapply(tree_branch_data, function(x) x$branch_dat))
    snv_cluster <- plyr::join(snv_cluster, branch_lengths)
    patients <- unique(unlist(snv_cluster_patients))
    root_data <- plyr::rbind.fill(lapply(patients, function(pat) {
        tree <- trees[[as.character(pat)]]
        ancestors <- ithi.supp:::find_ancestors(tree)
        plyr::rbind.fill(lapply(ancestors, function(x) {
            data.frame(label = x, patient_id = pat)
        }))
    }))
    root_data$node_type <- "root"
    root_data$patient_id <- as.numeric(as.character(root_data$patient_id))
    snv_cluster_annotated <- plyr::join(snv_cluster, root_data, type = "left") %>% 
        plyr::rename(c(chrom = "Chromosome", ref = "Reference", alt = "Variant", 
            coord = "Start"))
    return(snv_cluster_annotated)
}
snvs_annotated <- get_annotated_snvs(snv_cluster_files, tree_branch_data)
snvs_annotated_filtered <- subset(snvs_annotated, !is.na(node))
snvs_annotated_filtered$node_type[is.na(snvs_annotated_filtered$node_type)] <- "subclonal"
master_variant_present <- subset(master_variant_table, is_present == 1)

snvs_annotated_filtered_renamed <- snvs_annotated_filtered %>% plyr::rename(c(Chromosome = "chrom", 
    Start = "coord", Reference = "ref", Variant = "alt"))

master_variant_annotated <- merge(master_variant_present, snvs_annotated_filtered_renamed, 
    by = c("patient_id", "chrom", "coord", "ref", "alt"))

Ok, now we can do the counting.

node_type_snv_count <- master_variant_annotated %>% group_by(patient_id, sample_key, 
    condensed_id, node_type) %>% summarise(num_snv = n())

subclonal_snv_proportions <- node_type_snv_count %>% group_by(patient_id, sample_key, 
    condensed_id) %>% summarise(snv_subclonal_prop = num_snv[node_type == "subclonal"]/sum(num_snv), 
    snv_subclonal_num = num_snv[node_type == "subclonal"])
subclonal_snv_proportions$patient_id <- ithi.meta::factor_id(subclonal_snv_proportions$patient_id, 
    type = "patient_id", db_path)

subclonal_snv_ploidy <- subclonal_snv_proportions %>% as.data.frame %>% plyr::join(remixt_ploidy %>% 
    as.data.frame)
subclonal_snv_ploidy_melted <- melt(subclonal_snv_ploidy, id.vars = c("patient_id", 
    "condensed_id", "psi", "Cellularity"), measure.vars = c("snv_subclonal_prop", 
    "snv_subclonal_num"), variable.name = "measure", value.name = "value")

pvals <- ithi.utils::compute_pvals_subsets(subclonal_snv_ploidy_melted, facet_vars = c("measure"), 
    formula = ~psi + value, corfun = cor.test, method = "spearman")

p <- ggplot(subclonal_snv_ploidy_melted, aes(x = psi, y = value)) + geom_point(aes(colour = patient_id)) + 
    theme_bw() + theme_Publication() + theme_nature() + scale_colour_manual(values = annotation_colours$patient_id) + 
    xlab("Ploidy") + ylab("Subclonal SNVs") + facet_wrap(~measure, scales = "free") + 
    geom_text(data = pvals, aes(x = Inf, y = Inf, label = p.value.text), hjust = 1.1, 
        vjust = 1.5, size = 2.5, parse = TRUE)

p

So no, we don’t see a higher proportion/number of subclonal SNVs in samples with higher ploidy. Given the amount of effort taken to incorporate copy number/ploidy in the clonality model, this is not entirely surprising.

Subclonal neoepitope-generating mutations

Next, we’ll address the second bullet point.

subclonal_neoediting_ploidy <- plyr::join(remixt_ploidy, neoediting_res$subclonal_rates %>% 
    plyr::rename(c(sample_key = "condensed_id")), by = c("condensed_id", "patient_id"))
clonal_neoediting_ploidy <- plyr::join(remixt_ploidy, neoediting_res$clonal_rates %>% 
    plyr::rename(c(sample_key = "condensed_id")), by = c("condensed_id", "patient_id"))

subclonal_neoediting_ploidy$epitope_rate <- with(subclonal_neoediting_ploidy, 
    nepitopes/ntotal)
clonal_neoediting_ploidy$epitope_rate <- with(clonal_neoediting_ploidy, nepitopes/ntotal)
subclonal_neoediting_ploidy_melted <- melt(subclonal_neoediting_ploidy, id.vars = c("patient_id", 
    "condensed_id", "psi", "Cellularity"), measure.vars = c("nepitopes", "epitope_rate"), 
    variable.name = "measure", value.name = "value")

pvals <- ithi.utils::compute_pvals_subsets(subclonal_neoediting_ploidy_melted, 
    facet_vars = c("measure"), formula = ~psi + value, corfun = cor.test, method = "spearman")

p1 <- ggplot(subclonal_neoediting_ploidy_melted, aes(x = psi, y = value)) + 
    geom_point(aes(colour = patient_id)) + theme_bw() + theme_Publication() + 
    theme_nature() + scale_colour_manual(values = annotation_colours$patient_id) + 
    xlab("Ploidy") + ylab("Number of subclonal neoepitopes") + facet_wrap(~measure, 
    scales = "free") + geom_text(data = pvals, aes(x = Inf, y = Inf, label = p.value.text), 
    hjust = 1.1, vjust = 1.5, size = 2.5, parse = TRUE)

p1

Thus, higher ploidy is not significantly associated with a higher subclonal neoepitope load or proportion.

clonal_neoediting_ploidy_melted <- melt(clonal_neoediting_ploidy, id.vars = c("patient_id", 
    "condensed_id", "psi", "Cellularity"), measure.vars = c("nepitopes", "epitope_rate"), 
    variable.name = "measure", value.name = "value")

pvals <- ithi.utils::compute_pvals_subsets(clonal_neoediting_ploidy_melted, 
    facet_vars = c("measure"), formula = ~psi + value, corfun = cor.test, method = "spearman")

p2 <- ggplot(clonal_neoediting_ploidy_melted, aes(x = psi, y = value)) + geom_point(aes(colour = patient_id)) + 
    theme_bw() + theme_Publication() + theme_nature() + scale_colour_manual(values = annotation_colours$patient_id) + 
    xlab("Ploidy") + ylab("Number of subclonal neoepitopes") + facet_wrap(~measure, 
    scales = "free") + geom_text(data = pvals, aes(x = Inf, y = Inf, label = p.value.text), 
    hjust = 1.1, vjust = 1.5, size = 2.5, parse = TRUE)

p2

Just for fun, we did this for clonal neoepitopes too – same result.

What about subclonal obs/exp neoepitope rates (i.e. the immunoediting indices)?

corres <- with(subclonal_neoediting_ploidy, cor.test(psi, expratio/obsratio, 
    method = "spearman"))
eq <- substitute(italic(P) == p, list(p = format(corres$p.value, digits = 3)))

p1 <- ggplot(subclonal_neoediting_ploidy, aes(x = psi, y = expratio/obsratio)) + 
    geom_point(aes(colour = patient_id)) + theme_bw() + theme_Publication() + 
    theme_nature() + scale_colour_manual(values = annotation_colours$patient_id) + 
    xlab("Ploidy") + ylab("E_i (subclonal)") + annotate("text", x = Inf, y = Inf, 
    parse = TRUE, hjust = 1, vjust = 1, label = as.character(as.expression(eq)))

p1

corres <- with(clonal_neoediting_ploidy, cor.test(psi, expratio/obsratio, method = "spearman"))
eq <- substitute(italic(P) == p, list(p = format(corres$p.value, digits = 3)))

p2 <- ggplot(clonal_neoediting_ploidy, aes(x = psi, y = expratio/obsratio)) + 
    geom_point(aes(colour = patient_id)) + theme_bw() + theme_Publication() + 
    theme_nature() + scale_colour_manual(values = annotation_colours$patient_id) + 
    xlab("Ploidy") + ylab("E_i (clonal)") + annotate("text", x = Inf, y = Inf, 
    parse = TRUE, hjust = 1, vjust = 1, label = as.character(as.expression(eq)))

p2

Again, no significant correlations. Now, to hammer it home, let’s add ploidy and cellularity into the neoepitope elimination model.

The base model is:

mod <- glmer(expratio/obsratio ~ E_CD8_rescaled + (1 | patient_id), data = subset(subclonal_neoediting_ploidy, 
    !is.na(E_CD8_density)), family = Gamma(link = "log"))
summod <- summary(mod)
summod
Generalized linear mixed model fit by maximum likelihood (Laplace
  Approximation) [glmerMod]
 Family: Gamma  ( log )
Formula: expratio/obsratio ~ E_CD8_rescaled + (1 | patient_id)
   Data: subset(subclonal_neoediting_ploidy, !is.na(E_CD8_density))

     AIC      BIC   logLik deviance df.resid 
   -42.3    -34.7     25.2    -50.3       46 

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-1.7552 -0.5698 -0.1755  0.5849  1.5509 

Random effects:
 Groups     Name        Variance Std.Dev.
 patient_id (Intercept) 0.02454  0.1567  
 Residual               0.01552  0.1246  
Number of obs: 50, groups:  patient_id, 12

Fixed effects:
               Estimate Std. Error t value Pr(>|z|)    
(Intercept)      0.1079     0.1000   1.079    0.281    
E_CD8_rescaled   0.4505     0.1140   3.953 7.72e-05 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
            (Intr)
E_CD8_rscld -0.198
# pval <- unname(summod$coefficients[,4][2])

Now adding ploidy and cellularity as fixed effects:

mod <- glmer(expratio/obsratio ~ E_CD8_rescaled + psi + Cellularity + (1 | patient_id), 
    data = subset(subclonal_neoediting_ploidy, !is.na(E_CD8_density)), family = Gamma(link = "log"))
summod <- summary(mod)
summod
Generalized linear mixed model fit by maximum likelihood (Laplace
  Approximation) [glmerMod]
 Family: Gamma  ( log )
Formula: expratio/obsratio ~ E_CD8_rescaled + psi + Cellularity + (1 |  
    patient_id)
   Data: subset(subclonal_neoediting_ploidy, !is.na(E_CD8_density))

     AIC      BIC   logLik deviance df.resid 
   -45.3    -33.9     28.7    -57.3       44 

Scaled residuals: 
     Min       1Q   Median       3Q      Max 
-1.79148 -0.58635 -0.07179  0.62726  1.53538 

Random effects:
 Groups     Name        Variance Std.Dev.
 patient_id (Intercept) 0.02424  0.1557  
 Residual               0.01365  0.1168  
Number of obs: 50, groups:  patient_id, 12

Fixed effects:
                Estimate Std. Error t value Pr(>|z|)    
(Intercept)     0.005927   0.147842   0.040 0.968020    
E_CD8_rescaled  0.384110   0.108387   3.544 0.000394 ***
psi            -0.010788   0.032369  -0.333 0.738924    
Cellularity     0.252936   0.093255   2.712 0.006682 ** 
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
            (Intr) E_CD8_ psi   
E_CD8_rscld -0.026              
psi         -0.651 -0.021       
Cellularity -0.377 -0.240  0.074
# pval <- unname(summod$coefficients[,4][2])

The p-value = 3.94305310^{-4} for the epithelial CD8+ TIL density effect remains significant. Ploidy and cellularity are not significant effects. As a sanity check, we make sure that the beta (coefficient) for E_CD8_rescaled remains the same sign in both cases, which it does.

LS0tCnRpdGxlOiAiV2hvbGUgZ2Vub21lIGR1cGxpY2F0aW9uIgotLS0KICAgICAgICAgICAgICAgICAgICAgICAgYGBge3IsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgojIyMjIyMjIyBTbmFrZW1ha2UgaGVhZGVyICMjIyMjIyMjCmxpYnJhcnkobWV0aG9kcykKU25ha2VtYWtlIDwtIHNldENsYXNzKAogICAgIlNuYWtlbWFrZSIsCiAgICBzbG90cyA9IGMoCiAgICAgICAgaW5wdXQgPSAibGlzdCIsCiAgICAgICAgb3V0cHV0ID0gImxpc3QiLAogICAgICAgIHBhcmFtcyA9ICJsaXN0IiwKICAgICAgICB3aWxkY2FyZHMgPSAibGlzdCIsCiAgICAgICAgdGhyZWFkcyA9ICJudW1lcmljIiwKICAgICAgICBsb2cgPSAibGlzdCIsCiAgICAgICAgcmVzb3VyY2VzID0gImxpc3QiLAogICAgICAgIGNvbmZpZyA9ICJsaXN0IiwKICAgICAgICBydWxlID0gImNoYXJhY3RlciIKICAgICkKKQpzbmFrZW1ha2UgPC0gU25ha2VtYWtlKAogICAgaW5wdXQgPSBsaXN0KCcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9jbG9uZXMvdHJlZV9kYXRhLnRzdicsICdub3RlYm9va3Mvd2hvbGVfZ2Vub21lX2R1cGxpY2F0aW9uLlJtZCcsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9paGNfdGFibGUudHN2JywgJy9zaGFobGFiL2FtY3BoZXJzb24vcHJvamVjdHMvaXRoMy9pdGgzL25vdGVib29rcy9iZXNwb2tlL2l0aF9zbnZzLnRzdicsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9jbG9uZXMvc252X2NsdXN0ZXIvcGF0aWVudF8xLnRzdicsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9jbG9uZXMvc252X2NsdXN0ZXIvcGF0aWVudF8yLnRzdicsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9jbG9uZXMvc252X2NsdXN0ZXIvcGF0aWVudF8zLnRzdicsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9jbG9uZXMvc252X2NsdXN0ZXIvcGF0aWVudF80LnRzdicsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9jbG9uZXMvc252X2NsdXN0ZXIvcGF0aWVudF83LnRzdicsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9jbG9uZXMvc252X2NsdXN0ZXIvcGF0aWVudF85LnRzdicsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9jbG9uZXMvc252X2NsdXN0ZXIvcGF0aWVudF8xMC50c3YnLCAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvY2xvbmVzL3Nudl9jbHVzdGVyL3BhdGllbnRfMTEudHN2JywgJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3RhYmxlcy9ydW4yL2Nsb25lcy9zbnZfY2x1c3Rlci9wYXRpZW50XzEyLnRzdicsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9jbG9uZXMvc252X2NsdXN0ZXIvcGF0aWVudF8xMy50c3YnLCAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvY2xvbmVzL3Nudl9jbHVzdGVyL3BhdGllbnRfMTQudHN2JywgJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3RhYmxlcy9ydW4yL2Nsb25lcy9zbnZfY2x1c3Rlci9wYXRpZW50XzE1LnRzdicsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9jbG9uZXMvc252X2NsdXN0ZXIvcGF0aWVudF8xNi50c3YnLCAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvY2xvbmVzL3Nudl9jbHVzdGVyL3BhdGllbnRfMTcudHN2JywgJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3RhYmxlcy9ydW4yL2Nsb25lcy9icmFuY2hfZGF0YS50c3YnLCAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvbmVvZWRpdGluZy9ydW42JywgJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3RhYmxlcy9ydW4yL2Nsb25lcy9jbG9uZV9kYXRhLnRzdicsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9yZW1peHRfY2VsbHVsYXJpdHlfcGxvaWR5LnRzdicsICJjbG9uZV90cmVlX2ZpbGUiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3RhYmxlcy9ydW4yL2Nsb25lcy90cmVlX2RhdGEudHN2JywgIm5vdGVib29rIiA9ICdub3RlYm9va3Mvd2hvbGVfZ2Vub21lX2R1cGxpY2F0aW9uLlJtZCcsICJpaGNfdGFibGUiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3RhYmxlcy9ydW4yL2loY190YWJsZS50c3YnLCAic252X3RhYmxlIiA9ICcvc2hhaGxhYi9hbWNwaGVyc29uL3Byb2plY3RzL2l0aDMvaXRoMy9ub3RlYm9va3MvYmVzcG9rZS9pdGhfc252cy50c3YnLCAic252X2NsdXN0ZXJfZmlsZXMiID0gYygnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvY2xvbmVzL3Nudl9jbHVzdGVyL3BhdGllbnRfMS50c3YnLCAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvY2xvbmVzL3Nudl9jbHVzdGVyL3BhdGllbnRfMi50c3YnLCAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvY2xvbmVzL3Nudl9jbHVzdGVyL3BhdGllbnRfMy50c3YnLCAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvY2xvbmVzL3Nudl9jbHVzdGVyL3BhdGllbnRfNC50c3YnLCAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvY2xvbmVzL3Nudl9jbHVzdGVyL3BhdGllbnRfNy50c3YnLCAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvY2xvbmVzL3Nudl9jbHVzdGVyL3BhdGllbnRfOS50c3YnLCAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvY2xvbmVzL3Nudl9jbHVzdGVyL3BhdGllbnRfMTAudHN2JywgJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3RhYmxlcy9ydW4yL2Nsb25lcy9zbnZfY2x1c3Rlci9wYXRpZW50XzExLnRzdicsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9jbG9uZXMvc252X2NsdXN0ZXIvcGF0aWVudF8xMi50c3YnLCAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvY2xvbmVzL3Nudl9jbHVzdGVyL3BhdGllbnRfMTMudHN2JywgJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3RhYmxlcy9ydW4yL2Nsb25lcy9zbnZfY2x1c3Rlci9wYXRpZW50XzE0LnRzdicsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9jbG9uZXMvc252X2NsdXN0ZXIvcGF0aWVudF8xNS50c3YnLCAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvY2xvbmVzL3Nudl9jbHVzdGVyL3BhdGllbnRfMTYudHN2JywgJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3RhYmxlcy9ydW4yL2Nsb25lcy9zbnZfY2x1c3Rlci9wYXRpZW50XzE3LnRzdicpLCAiY2xvbmVfYnJhbmNoX2xlbmd0aF9maWxlIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9jbG9uZXMvYnJhbmNoX2RhdGEudHN2JywgImNsb25lX3ByZXZhbGVuY2VfZmlsZSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvY2xvbmVzL2Nsb25lX2RhdGEudHN2JywgIm5lb2VkaXRpbmdfb3V0ZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9uZW9lZGl0aW5nL3J1bjYnLCAicmVtaXh0X2NlbGx1bGFyaXR5X3Bsb2lkeV9maWxlIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9yZW1peHRfY2VsbHVsYXJpdHlfcGxvaWR5LnRzdicpLAogICAgb3V0cHV0ID0gbGlzdCgnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvcmV2aWV3L25vdGVib29rcy9ydW4yL3dob2xlX2dlbm9tZV9kdXBsaWNhdGlvbi5uYi5odG1sJyksCiAgICBwYXJhbXMgPSBsaXN0KCcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvbWV0YWRhdGEvZGIvaW1tdW5lX3Byb2plY3Quc3FsaXRlMycsICd3Z2RfYW5hbHlzaXMnLCAiZGIiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9tZXRhZGF0YS9kYi9pbW11bmVfcHJvamVjdC5zcWxpdGUzJywgIm5hbWUiID0gJ3dnZF9hbmFseXNpcycpLAogICAgd2lsZGNhcmRzID0gbGlzdCgpLAogICAgdGhyZWFkcyA9IDEsCiAgICBsb2cgPSBsaXN0KCcvc2hhaGxhYi9hbHpoYW5nL2NsdXN0dG1wL3BhcGVycmV2aWV3Mi9ub3RlYm9va3Mvd2dkX2FuYWx5c2lzLmxvZycpLAogICAgcmVzb3VyY2VzID0gbGlzdCgpLAogICAgY29uZmlnID0gbGlzdCgiaXRoX3N0YXRzIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9pdGhfc3RhdGlzdGljcy50c3YnLCAicmVmc2VxX2dlbmVfZmlsZSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9kYXRhL2dlbm9tZS9oZzE5L3JlZnNlcV9nZW5lcy5iZWQnLCAieGNyX3RhYmxlIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi94Y3JfdGFibGUudHN2JywgIm1tY3RtX2ZpbmFsX3BhdGllbnRfZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcmVzdWx0cy9tbWN0bV9yZXN1bHRzL2l0aF9ieS1wYXRpZW50X3dpdGgtb3YnLCAibmFub3N0cmluZ19kYXRhIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcmVzdWx0cy9uYW5vc3RyaW5nX3Jlc3VsdHMvaXRoX2Z1bGwvcWMvbGltbWFfcXVhbnRpbGUvbm9ybWFsaXplZF9leHByZXNzaW9uX3ZvYV9sYWJlbHNfZmlsdGVyZWQudHN2JywgIm5lb2VkaXRpbmdfb3V0ZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9uZW9lZGl0aW5nL3J1bjYnLCAiY29weW51bWJlcl90YWJsZSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9kYXRhL2l0aGkvbWFzdGVyX2NvcHludW1iZXJfZmlsZS50c3YnLCAiYmNyX2RpdmVyc2l0eSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvbWl4Y3IvbWl4Y3JfcnVucy9pdGhfMV8yXzMvbWl4Y3I1L3Bvc3Rwcm9jZXNzL0lHSC9wb3N0ZmlsdGVyX2RpdmVyc2l0eV9zdGF0cy9kaXZlcnNpdHkuc3RyaWN0LnJlc2FtcGxlZC50eHQnLCAiaGVfcmVzdWx0c19kaXIiID0gJy9zaGFobGFiL2FsemhhbmcvZGF0YS9pdGhpL2Zpbm5fcmVzdWx0cy9oZV9vdXRwdXRfTm92MjknLCAiYXJyYXlfZXhwcmVzc2lvbl9maWxlIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvZGF0YS9leHByZXNzaW9uL2FycmF5L2dlbmVfZXhwcnNfcm1hX2JhdGNoX2NvcnJlY3RlZC50eHQnLCAic252X2NsdXN0ZXJfZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9jbG9uZXMvc252X2NsdXN0ZXInLCAidGlsc19mb3JfY2x1c3RlciIgPSBjKCdFX0NEOF9kZW5zaXR5JywgJ0VfQ0Q0X2RlbnNpdHknLCAnRV9DRDIwX2RlbnNpdHknLCAnRV9QbGFzbWFfZGVuc2l0eScsICdTX0NEOF9kZW5zaXR5JywgJ1NfQ0Q0X2RlbnNpdHknLCAnU19DRDIwX2RlbnNpdHknLCAnU19QbGFzbWFfZGVuc2l0eScpLCAidG90YWxfdGlsdHlwZXMiID0gYygnVF9DRDhfZGVuc2l0eScsICdUX0NENF9kZW5zaXR5JywgJ1RfQ0QyMF9kZW5zaXR5JywgJ1RfUGxhc21hX2RlbnNpdHknKSwgImxvZ2RpciIgPSAnL3NoYWhsYWIvYWx6aGFuZy9jbHVzdHRtcC9wYXBlcnJldmlldzInLCAiaXRoX2ljZ2NfYmMiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3RhYmxlcy9ydW4yL2l0aF9pY2djX21lcmdlZF9iYy50c3YnLCAicGF0aWVudHNfZm9yX2Nsb25hbCIgPSBjKDEsIDIsIDMsIDQsIDcsIDksIDEwLCAxMSwgMTIsIDEzLCAxNCwgMTUsIDE2LCAxNyksICJ2YXJpYWJpbGl0eV90eXBlIiA9ICdzdGFiaWxpemUnLCAidGFibGVfZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy9yZXZpZXcvdGFibGVzL3J1bjInLCAiZGIiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9tZXRhZGF0YS9kYi9pbW11bmVfcHJvamVjdC5zcWxpdGUzJywgInNudl90YWJsZSIgPSAnL3NoYWhsYWIvYW1jcGhlcnNvbi9wcm9qZWN0cy9pdGgzL2l0aDMvbm90ZWJvb2tzL2Jlc3Bva2UvaXRoX3NudnMudHN2JywgImVwaXRvcGVzX3VuaXF1ZV9maWx0ZXJlZCIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvZXBpdG9wZXNfdW5pcXVlX2ZpbHRlcmVkLnRzdicsICJiZW5jaG1hcmtkaXIiID0gJy9zaGFobGFiL2FsemhhbmcvYmVuY2htYXJrcy9wYXBlcnJldmlldzInLCAidGlsY2x1c3Rlcl9zdXBlcnZpc2VkX2lweW5iIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmV2aWV3L2lweS90aWxjbHVzdGVyX3N1cGVydmlzZWRtdWx0aWNsYXNzLmlweW5iJywgImltYWdlX3N1bW1hcnkiID0gJy9zaGFobGFiL2FsemhhbmcvZGF0YS9pdGhpL3l1YW5faGVjcl9pbWFnZV9yZXN1bHRzLmNzdicsICJpaGNfZmVhdHVyZXNfb3V0cHV0IiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy9pbnRlcm1lZGlhdGVzL3J1bjIvaWhjX2ZlYXR1cmVzX291dHB1dC50eHQnLCAiY2xvbmVfYnJhbmNoX2xlbmd0aHMiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3RhYmxlcy9ydW4yL2Nsb25lcy9icmFuY2hfZGF0YS50c3YnLCAiZGlzdGFuY2VfbWV0aG9kIiA9ICdob3JuJywgImNsb25lX3ByZXZhbGVuY2VzIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9jbG9uZXMvY2xvbmVfZGF0YS50c3YnLCAidGlsX2NsdXN0ZXJzX291dHB1dCIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvaW50ZXJtZWRpYXRlcy9ydW4yL3RpbF9jbHVzdGVyc19vdXRwdXQudHh0JywgInR1bW91cl9wdXJpdHkiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3RhYmxlcy9ydW4yL3R1bW91cl9wdXJpdHkudHN2JywgInByZXZhbGVuY2VfdGhyZXNob2xkIiA9IDAuMDEsICJub3RlYm9va19kaXIiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3Jldmlldy9ub3RlYm9va3MvcnVuMicsICJzb21hdGljX2NvZGluZ19yZXN1bHRfZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9zb21hdGljX2NvZGluZ192YXJpYW50cycsICJpbWFnZV9zdW1tYXJ5MiIgPSAnL3NoYWhsYWIvYWx6aGFuZy9kYXRhL2l0aGkveXVhbl9oZWNyX2ltYWdlX3Jlc3VsdHNfMi5jc3YnLCAia25vd25fc3VidHlwZXNfYXJyYXkiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9kYXRhL2V4cHJlc3Npb24vYXJyYXkvc3VidHlwZXMva25vd25fc3VidHlwZXMudHN2JywgIml0aF9zdGF0X3R5cGVzIiA9IGMoJ2VudHJvcHknLCAncG9zdHByb2Nlc3NlZF9kaXZlcmdlbmNlJywgJ2NvbWJpbmVkX2l0aF9ub3JtYWxpemVkJywgJ3Byb3BvcnRpb25fc3ViY2xvbmFsJyksICJuYW5vc3RyaW5nX2Fubm90YXRpb25zIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvZGF0YS9leHByZXNzaW9uL25hbm9zdHJpbmcvcGFuY2FuY2VyX2Fubm90YXRpb25zLnRzdicsICJpaGNfdGFibGUiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3RhYmxlcy9ydW4yL2loY190YWJsZS50c3YnLCAiaWdwYXJ0aXRpb25fb3V0ZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9pZ3BhcnRpdGlvbi9ydW4yMicsICJhbGxfdGlsdHlwZXMiID0gYygnVF9DRDhfZGVuc2l0eScsICdUX0NENF9kZW5zaXR5JywgJ1RfQ0QyMF9kZW5zaXR5JywgJ1RfUGxhc21hX2RlbnNpdHknLCAnRV9DRDhfZGVuc2l0eScsICdFX0NENF9kZW5zaXR5JywgJ0VfQ0QyMF9kZW5zaXR5JywgJ0VfUGxhc21hX2RlbnNpdHknLCAnU19DRDhfZGVuc2l0eScsICdTX0NENF9kZW5zaXR5JywgJ1NfQ0QyMF9kZW5zaXR5JywgJ1NfUGxhc21hX2RlbnNpdHknKSwgInJlbWl4dF9jZWxsdWxhcml0eV9wbG9pZHkiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3RhYmxlcy9ydW4yL3JlbWl4dF9jZWxsdWxhcml0eV9wbG9pZHkudHN2JywgImJyZWFrcG9pbnRfdGFibGUiID0gJy9zaGFobGFiL2FtY3BoZXJzb24vcHJvamVjdHMvaXRoMy9pdGgzL25vdGVib29rcy9iZXNwb2tlL2l0aF9icmVha3BvaW50cy50c3YnLCAiY2xvbGFfcmVzdWx0X2ZpbGUiID0gJy9zaGFobGFiL2FsemhhbmcvcGlwZWxpbmVfb3V0cHV0cy9pdGhfaW1tdW5lL2Nsb2xhL3J1bjQvY2xvbGFfY29uZGVuc2VkX3Jlc3VsdHMvYmV0YS9jbG9sYV9yZXN1bHRzLnRzdicsICJjbG9uZV90cmVlcyIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvY2xvbmVzL3RyZWVfZGF0YS50c3YnLCAicm9vbmV5X211dHNpZ2N2X2ZpbGUiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9leHRlcm5hbC9vdGhlcl9wYXBlcnMvbW1jNi54bHN4JywgIm1vbHN1YnR5cGVzIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9tb2xzdWJ0eXBlcy50c3YnLCAiZmlubmhlX3BpcGVsaW5lX3Jlc3VsdHNfZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9maW5uaGUvcnVuMScsICJpY2djX3NwZWNpbWVuIiA9ICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvSUNHQy9zcGVjaW1lbi50c3YnLCAiaWNnY19zdWJ0eXBlcyIgPSAnL3NoYWhsYWIvYWx6aGFuZy9kYXRhL0lDR0MvaWNnY19wcmltYXJ5X3R1bW91cl9zdWJ0eXBlcy50c3YnLCAidGNyX2RpdmVyc2l0eSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvbWl4Y3IvbWl4Y3JfcnVucy9pdGhfMV8yXzMvbWl4Y3I1L3Bvc3Rwcm9jZXNzL1RSQi9wb3N0ZmlsdGVyX2RpdmVyc2l0eV9zdGF0cy9kaXZlcnNpdHkuc3RyaWN0LnJlc2FtcGxlZC50eHQnLCAidGlsc19mb3JfdmFyaWFiaWxpdHkiID0gYygnVF9DRDhfZGVuc2l0eScsICdUX0NENF9kZW5zaXR5JywgJ1RfQ0QyMF9kZW5zaXR5JywgJ1RfUGxhc21hX2RlbnNpdHknKSksCiAgICBydWxlID0gJ3dnZF9hbmFseXNpcycKKQojIyMjIyMjIyBPcmlnaW5hbCBzY3JpcHQgIyMjIyMjIyMjCgogICAgICAgICAgICAgICAgICAgICAgICBgYGAKCgojIyBTZXR1cAoKYGBge3IgZ2xvYmFsX2NodW5rX29wdGlvbnMsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgdGlkeT1UUlVFLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBjYWNoZT1UUlVFKSAjY2FjaGU9VFJVRQpgYGAKCmBgYHtyfQpsaWJyYXJ5KGl0aGkudXRpbHMpCmxvYWRfYmFzZV9saWJzKCkKCmxpYnJhcnkobWV0aG9kcykKbGlicmFyeShmYWN0b2V4dHJhKQoKbGlicmFyeShpdGhpLm1ldGEpCmxpYnJhcnkoaXRoaS5maWd1cmVzKQpsaWJyYXJ5KGl0aGkudXRpbHMpCmxpYnJhcnkoaXRoaS5zZXEpCmxpYnJhcnkoaXRoaS5jbG9uZXMpCmxpYnJhcnkoaXRoaS5zdXBwKQpgYGAKCmBgYHtyfQppaGNfdGFibGVfcGF0aCA8LSBzbmFrZW1ha2VAaW5wdXQkaWhjX3RhYmxlCm5lb2VkaXRpbmdfb3V0ZGlyIDwtIHNuYWtlbWFrZUBpbnB1dCRuZW9lZGl0aW5nX291dGRpcgpzbnZfY2x1c3Rlcl9maWxlcyA8LSBzbmFrZW1ha2VAaW5wdXQkc252X2NsdXN0ZXJfZmlsZXMKY2xvbmVfdHJlZV9maWxlIDwtIHNuYWtlbWFrZUBpbnB1dCRjbG9uZV90cmVlX2ZpbGUKY2xvbmVfYnJhbmNoX2xlbmd0aF9maWxlIDwtIHNuYWtlbWFrZUBpbnB1dCRjbG9uZV9icmFuY2hfbGVuZ3RoX2ZpbGUKY2xvbmVfcHJldmFsZW5jZV9maWxlIDwtIHNuYWtlbWFrZUBpbnB1dCRjbG9uZV9wcmV2YWxlbmNlX2ZpbGUKcmVtaXh0X3Bsb2lkeV9maWxlIDwtIHNuYWtlbWFrZUBpbnB1dCRyZW1peHRfY2VsbHVsYXJpdHlfcGxvaWR5X2ZpbGUKbWFzdGVyX3ZhcmlhbnRfZmlsZSA8LSBzbmFrZW1ha2VAaW5wdXQkc252X3RhYmxlCgpkYl9wYXRoIDwtIHNuYWtlbWFrZUBwYXJhbXMkZGIKYGBgCgpgYGB7cn0KYW5ub3RhdGlvbl9jb2xvdXJzIDwtIGl0aGkuZmlndXJlczo6Z2V0X2Fubm90YXRpb25fY29sb3VycygpCmloY190YWJsZSA8LSBmcmVhZChpaGNfdGFibGVfcGF0aCkKbWFzdGVyX3ZhcmlhbnRfdGFibGUgPC0gcmVhZF92YXJpYW50X2ZpbGUobWFzdGVyX3ZhcmlhbnRfZmlsZSwgZGJfcGF0aCkKCnRyZWVfYnJhbmNoX2RhdGEgPC0gcmVhZF9jbG9uZV90cmVlX2RhdGEoY2xvbmVfdHJlZV9maWxlLCBjbG9uZV9icmFuY2hfbGVuZ3RoX2ZpbGUsIGNsb25lX3ByZXZhbGVuY2VfZmlsZSwgZGJfcGF0aCkKCm5lb2VkaXRpbmdfcmVzIDwtIHN1cHBfbmVvZWRpdGluZyhuZW9lZGl0aW5nX291dGRpciwgaWhjX3RhYmxlLCBkYl9wYXRoLCB0cmVlX2JyYW5jaF9kYXRhLCB3dGZpbHRlciA9IFRSVUUsIGZ1bGxfZXBpdG9wZXMgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzbnZfY2x1c3Rlcl9maWxlcyA9IHNudl9jbHVzdGVyX2ZpbGVzKQpgYGAKCiMjIEFuYWx5c2lzCgpXZSBuZWVkIHRvIGFuc3dlciAyIHF1ZXN0aW9uczoKCiogRG8gd2hvbGUtZ2Vub21lIGR1cGxpY2F0ZWQgKG9yIGhpZ2ggcGxvaWR5KSBzYW1wbGVzIGhhdmUgYSBoaWdoZXIgbnVtYmVyL3Byb3BvcnRpb24gb2Ygc3ViY2xvbmFsIG11dGF0aW9ucz8KKiBEbyB3aG9sZS1nZW5vbWUgZHVwbGljYXRlZCAob3IgaGlnaCBwbG9pZHkpIHNhbXBsZXMgaGF2ZSBhIGhpZ2hlciBudW1iZXIvcHJvcG9ydGlvbiBvZiBzdWJjbG9uYWwgbmVvZXBpdG9wZS1nZW5lcmF0aW5nIG11dGF0aW9ucz8KCiMjIyBXR0QKClRvIGV4YW1pbmUgdGhpcywgd2UnbGwgY29uc2lkZXIgcGxvaWR5LiBVbmRlciBXR0QsIHRoZSBwbG9pZHkgb2YgYSB0dW1vdXIgc2FtcGxlIHNob3VsZCBiZSBhcHByb3hpbWF0ZWx5IDQuIAoKYGBge3J9CnJlbWl4dF9wbG9pZHkgPC0gcmVhZC50YWJsZShyZW1peHRfcGxvaWR5X2ZpbGUsIHJvdy5uYW1lcyA9IDEsIGhlYWRlciA9IFRSVUUsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKCnJlbWl4dF9wbG9pZHkgPC0gcmVtaXh0X3Bsb2lkeSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJ2b2EiKQpyZW1peHRfcGxvaWR5JHBhdGllbnRfaWQgPC0gaXRoaS5tZXRhOjpmYWN0b3JfaWQocmVtaXh0X3Bsb2lkeSRwYXRpZW50X2lkLCB0eXBlID0gInBhdGllbnRfaWQiLCBkYl9wYXRoKQpyZW1peHRfcGxvaWR5JGNvbmRlbnNlZF9pZCA8LSBpdGhpLm1ldGE6Om1hcF9pZChyZW1peHRfcGxvaWR5JHZvYSwgZnJvbSA9ICJ2b2EiLCB0byA9ICJjb25kZW5zZWRfaWQiLCBkYl9wYXRoKQpgYGAKCiMjIyMgU3ViY2xvbmFsIG11dGF0aW9ucwoKV2UnbGwgYWRkcmVzcyB0aGUgZmlyc3QgYnVsbGV0IHBvaW50IGhlcmUuCgpJbmNsdXNpb24vZXhjbHVzaW9uIGNyaXRlcmlhOiAKCiogV2hlbiBjYWxsaW5nIGNsb25hbGl0eS9zdWJjbG9uYWxpdHksIHdlIGV4Y2x1ZGUgbXV0YXRpb25zIHRoYXQgY2Fubm90IGJlIHVuYW1iaWd1b3VzbHkgYXNzaWduZWQgdG8gYSBjbG9uZSBpbiB0aGUgY2xvbmFsIHBoeWxvZ2VueSAoYWNjb3JkaW5nIHRvIG1heGltdW0gbGlrZWxpaG9vZCwgc2VlIFNUQVIgTWV0aG9kcykuIAoKYGBge3J9CiMjIFRoaXMgc2hvdWxkIGJlIHJlZmFjdG9yZWQgaW50byBhIHBhY2thZ2UKZ2V0X2Fubm90YXRlZF9zbnZzIDwtIGZ1bmN0aW9uKHNudl9jbHVzdGVyX2ZpbGVzLCB0cmVlX2JyYW5jaF9kYXRhKSB7CiAgc252X2NsdXN0ZXJfcGF0aWVudHMgPC0gYXMubGlzdChzdHJpbmdyOjpzdHJfZXh0cmFjdChzbnZfY2x1c3Rlcl9maWxlcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiKD88PXBhdGllbnRfKVswLTldKyIpKQogIHNudl9jbHVzdGVyIDwtIHBseXI6OnJiaW5kLmZpbGwobGFwcGx5KHNlcV9hbG9uZyhzbnZfY2x1c3Rlcl9maWxlcyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKGkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGYgPC0gc252X2NsdXN0ZXJfZmlsZXNbW2ldXQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0aWVudF9pZCA8LSBzbnZfY2x1c3Rlcl9wYXRpZW50c1tbaV1dCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzbnZfY2x1c3RlciA8LSBpdGhpLmNsb25lczo6cmVhZF9zbnZfY2x1c3RlcihmLCBjbG9uZV9icmFuY2hfbGVuZ3RoX2ZpbGUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGJfcGF0aCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybihzbnZfY2x1c3RlcikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KSkKICB0cmVlcyA8LSBsYXBwbHkodHJlZV9icmFuY2hfZGF0YSwgZnVuY3Rpb24oeCkgeCR0cmVlKQogIGJyYW5jaF9sZW5ndGhzIDwtIHBseXI6OnJiaW5kLmZpbGwobGFwcGx5KHRyZWVfYnJhbmNoX2RhdGEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHgkYnJhbmNoX2RhdCkpCiAgc252X2NsdXN0ZXIgPC0gcGx5cjo6am9pbihzbnZfY2x1c3RlciwgYnJhbmNoX2xlbmd0aHMpCiAgcGF0aWVudHMgPC0gdW5pcXVlKHVubGlzdChzbnZfY2x1c3Rlcl9wYXRpZW50cykpCiAgcm9vdF9kYXRhIDwtIHBseXI6OnJiaW5kLmZpbGwobGFwcGx5KHBhdGllbnRzLCBmdW5jdGlvbihwYXQpIHsKICAgIHRyZWUgPC0gdHJlZXNbW2FzLmNoYXJhY3RlcihwYXQpXV0KICAgIGFuY2VzdG9ycyA8LSBpdGhpLnN1cHA6OjpmaW5kX2FuY2VzdG9ycyh0cmVlKQogICAgcGx5cjo6cmJpbmQuZmlsbChsYXBwbHkoYW5jZXN0b3JzLCBmdW5jdGlvbih4KSB7CiAgICAgIGRhdGEuZnJhbWUobGFiZWwgPSB4LCBwYXRpZW50X2lkID0gcGF0KQogICAgfSkpCiAgfSkpCiAgcm9vdF9kYXRhJG5vZGVfdHlwZSA8LSAicm9vdCIKICByb290X2RhdGEkcGF0aWVudF9pZCA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3Rlcihyb290X2RhdGEkcGF0aWVudF9pZCkpCiAgc252X2NsdXN0ZXJfYW5ub3RhdGVkIDwtIHBseXI6OmpvaW4oc252X2NsdXN0ZXIsIHJvb3RfZGF0YSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJsZWZ0IikgJT4lIHBseXI6OnJlbmFtZShjKGNocm9tID0gIkNocm9tb3NvbWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVmID0gIlJlZmVyZW5jZSIsIGFsdCA9ICJWYXJpYW50IiwgY29vcmQgPSAiU3RhcnQiKSkKICByZXR1cm4oc252X2NsdXN0ZXJfYW5ub3RhdGVkKQp9CmBgYAoKYGBge3J9CnNudnNfYW5ub3RhdGVkIDwtIGdldF9hbm5vdGF0ZWRfc252cyhzbnZfY2x1c3Rlcl9maWxlcywgdHJlZV9icmFuY2hfZGF0YSkKYGBgCgpgYGB7cn0Kc252c19hbm5vdGF0ZWRfZmlsdGVyZWQgPC0gc3Vic2V0KHNudnNfYW5ub3RhdGVkLCAhaXMubmEobm9kZSkpCnNudnNfYW5ub3RhdGVkX2ZpbHRlcmVkJG5vZGVfdHlwZVtpcy5uYShzbnZzX2Fubm90YXRlZF9maWx0ZXJlZCRub2RlX3R5cGUpXSA8LSAic3ViY2xvbmFsIgpgYGAKCmBgYHtyfQptYXN0ZXJfdmFyaWFudF9wcmVzZW50IDwtIHN1YnNldChtYXN0ZXJfdmFyaWFudF90YWJsZSwgaXNfcHJlc2VudCA9PSAxKQoKc252c19hbm5vdGF0ZWRfZmlsdGVyZWRfcmVuYW1lZCA8LSBzbnZzX2Fubm90YXRlZF9maWx0ZXJlZCAlPiUgcGx5cjo6cmVuYW1lKGMoJ0Nocm9tb3NvbWUnPSdjaHJvbScsICdTdGFydCc9J2Nvb3JkJywgJ1JlZmVyZW5jZSc9J3JlZicsICdWYXJpYW50Jz0nYWx0JykpCgptYXN0ZXJfdmFyaWFudF9hbm5vdGF0ZWQgPC0gbWVyZ2UobWFzdGVyX3ZhcmlhbnRfcHJlc2VudCwgc252c19hbm5vdGF0ZWRfZmlsdGVyZWRfcmVuYW1lZCwgYnkgPSBjKCJwYXRpZW50X2lkIiwgImNocm9tIiwgImNvb3JkIiwgInJlZiIsICJhbHQiKSkKYGBgCgpPaywgbm93IHdlIGNhbiBkbyB0aGUgY291bnRpbmcuIAoKYGBge3J9Cm5vZGVfdHlwZV9zbnZfY291bnQgPC0gbWFzdGVyX3ZhcmlhbnRfYW5ub3RhdGVkICU+JSBncm91cF9ieShwYXRpZW50X2lkLCBzYW1wbGVfa2V5LCBjb25kZW5zZWRfaWQsIG5vZGVfdHlwZSkgJT4lIHN1bW1hcmlzZShudW1fc252PW4oKSkKCnN1YmNsb25hbF9zbnZfcHJvcG9ydGlvbnMgPC0gbm9kZV90eXBlX3Nudl9jb3VudCAlPiUgZ3JvdXBfYnkocGF0aWVudF9pZCwgc2FtcGxlX2tleSwgY29uZGVuc2VkX2lkKSAlPiUgc3VtbWFyaXNlKHNudl9zdWJjbG9uYWxfcHJvcD1udW1fc252W25vZGVfdHlwZSA9PSAic3ViY2xvbmFsIl0vc3VtKG51bV9zbnYpLCBzbnZfc3ViY2xvbmFsX251bSA9IG51bV9zbnZbbm9kZV90eXBlID09ICJzdWJjbG9uYWwiXSkKYGBgCgpgYGB7cn0Kc3ViY2xvbmFsX3Nudl9wcm9wb3J0aW9ucyRwYXRpZW50X2lkIDwtIGl0aGkubWV0YTo6ZmFjdG9yX2lkKHN1YmNsb25hbF9zbnZfcHJvcG9ydGlvbnMkcGF0aWVudF9pZCwgdHlwZSA9ICJwYXRpZW50X2lkIiwgZGJfcGF0aCkKCnN1YmNsb25hbF9zbnZfcGxvaWR5IDwtIHN1YmNsb25hbF9zbnZfcHJvcG9ydGlvbnMgJT4lIGFzLmRhdGEuZnJhbWUgJT4lIHBseXI6OmpvaW4ocmVtaXh0X3Bsb2lkeSAlPiUgYXMuZGF0YS5mcmFtZSkKYGBgCgpgYGB7cn0Kc3ViY2xvbmFsX3Nudl9wbG9pZHlfbWVsdGVkIDwtIG1lbHQoc3ViY2xvbmFsX3Nudl9wbG9pZHksIGlkLnZhcnMgPSBjKCJwYXRpZW50X2lkIiwgImNvbmRlbnNlZF9pZCIsICJwc2kiLCAiQ2VsbHVsYXJpdHkiKSwgbWVhc3VyZS52YXJzID0gYygic252X3N1YmNsb25hbF9wcm9wIiwgInNudl9zdWJjbG9uYWxfbnVtIiksIHZhcmlhYmxlLm5hbWUgPSAibWVhc3VyZSIsIHZhbHVlLm5hbWUgPSAidmFsdWUiKQoKcHZhbHMgPC0gaXRoaS51dGlsczo6Y29tcHV0ZV9wdmFsc19zdWJzZXRzKHN1YmNsb25hbF9zbnZfcGxvaWR5X21lbHRlZCwgZmFjZXRfdmFycyA9IGMoIm1lYXN1cmUiKSwgZm9ybXVsYSA9IH4gcHNpICsgdmFsdWUsIGNvcmZ1biA9IGNvci50ZXN0LCBtZXRob2QgPSAic3BlYXJtYW4iKQoKcCA8LSBnZ3Bsb3Qoc3ViY2xvbmFsX3Nudl9wbG9pZHlfbWVsdGVkLCBhZXMoeD1wc2ksIHk9dmFsdWUpKSArIGdlb21fcG9pbnQoYWVzKGNvbG91cj1wYXRpZW50X2lkKSkgKyB0aGVtZV9idygpICsgdGhlbWVfUHVibGljYXRpb24oKSArIAogIHRoZW1lX25hdHVyZSgpICsgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBhbm5vdGF0aW9uX2NvbG91cnMkcGF0aWVudF9pZCkgKyB4bGFiKCJQbG9pZHkiKSArIHlsYWIoIlN1YmNsb25hbCBTTlZzIikgKyAKICBmYWNldF93cmFwKH4gbWVhc3VyZSwgc2NhbGVzID0gImZyZWUiKSArIGdlb21fdGV4dChkYXRhPXB2YWxzLCBhZXMoeD1JbmYsIHk9SW5mLCBsYWJlbD1wLnZhbHVlLnRleHQpLCBoanVzdD0xLjEsIHZqdXN0PTEuNSxzaXplPTIuNSxwYXJzZT1UUlVFKQoKcApgYGAKClNvIG5vLCB3ZSBkb24ndCBzZWUgYSBoaWdoZXIgcHJvcG9ydGlvbi9udW1iZXIgb2Ygc3ViY2xvbmFsIFNOVnMgaW4gc2FtcGxlcyB3aXRoIGhpZ2hlciBwbG9pZHkuIEdpdmVuIHRoZSBhbW91bnQgb2YgZWZmb3J0IHRha2VuIHRvIGluY29ycG9yYXRlIGNvcHkgbnVtYmVyL3Bsb2lkeSBpbiB0aGUgY2xvbmFsaXR5IG1vZGVsLCB0aGlzIGlzIG5vdCBlbnRpcmVseSBzdXJwcmlzaW5nLiAKCiMjIyMgU3ViY2xvbmFsIG5lb2VwaXRvcGUtZ2VuZXJhdGluZyBtdXRhdGlvbnMKCk5leHQsIHdlJ2xsIGFkZHJlc3MgdGhlIHNlY29uZCBidWxsZXQgcG9pbnQuIAoKYGBge3J9CnN1YmNsb25hbF9uZW9lZGl0aW5nX3Bsb2lkeSA8LSBwbHlyOjpqb2luKHJlbWl4dF9wbG9pZHksIG5lb2VkaXRpbmdfcmVzJHN1YmNsb25hbF9yYXRlcyAlPiUgcGx5cjo6cmVuYW1lKGMoJ3NhbXBsZV9rZXknPSdjb25kZW5zZWRfaWQnKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gYygiY29uZGVuc2VkX2lkIiwgInBhdGllbnRfaWQiKSkKY2xvbmFsX25lb2VkaXRpbmdfcGxvaWR5IDwtIHBseXI6OmpvaW4ocmVtaXh0X3Bsb2lkeSwgbmVvZWRpdGluZ19yZXMkY2xvbmFsX3JhdGVzICU+JSBwbHlyOjpyZW5hbWUoYygnc2FtcGxlX2tleSc9J2NvbmRlbnNlZF9pZCcpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSBjKCJjb25kZW5zZWRfaWQiLCAicGF0aWVudF9pZCIpKQoKc3ViY2xvbmFsX25lb2VkaXRpbmdfcGxvaWR5JGVwaXRvcGVfcmF0ZSA8LSB3aXRoKHN1YmNsb25hbF9uZW9lZGl0aW5nX3Bsb2lkeSwgbmVwaXRvcGVzL250b3RhbCkKY2xvbmFsX25lb2VkaXRpbmdfcGxvaWR5JGVwaXRvcGVfcmF0ZSA8LSB3aXRoKGNsb25hbF9uZW9lZGl0aW5nX3Bsb2lkeSwgbmVwaXRvcGVzL250b3RhbCkKYGBgCgpgYGB7cn0Kc3ViY2xvbmFsX25lb2VkaXRpbmdfcGxvaWR5X21lbHRlZCA8LSBtZWx0KHN1YmNsb25hbF9uZW9lZGl0aW5nX3Bsb2lkeSwgaWQudmFycyA9IGMoInBhdGllbnRfaWQiLCAiY29uZGVuc2VkX2lkIiwgInBzaSIsICJDZWxsdWxhcml0eSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhc3VyZS52YXJzID0gYygibmVwaXRvcGVzIiwgImVwaXRvcGVfcmF0ZSIpLCB2YXJpYWJsZS5uYW1lID0gIm1lYXN1cmUiLCB2YWx1ZS5uYW1lID0gInZhbHVlIikKCnB2YWxzIDwtIGl0aGkudXRpbHM6OmNvbXB1dGVfcHZhbHNfc3Vic2V0cyhzdWJjbG9uYWxfbmVvZWRpdGluZ19wbG9pZHlfbWVsdGVkLCBmYWNldF92YXJzID0gYygibWVhc3VyZSIpLCBmb3JtdWxhID0gfiBwc2kgKyB2YWx1ZSwgY29yZnVuID0gY29yLnRlc3QsIG1ldGhvZCA9ICJzcGVhcm1hbiIpCgpwMSA8LSBnZ3Bsb3Qoc3ViY2xvbmFsX25lb2VkaXRpbmdfcGxvaWR5X21lbHRlZCwgYWVzKHg9cHNpLCB5PXZhbHVlKSkgKyBnZW9tX3BvaW50KGFlcyhjb2xvdXI9cGF0aWVudF9pZCkpICsgdGhlbWVfYncoKSArIHRoZW1lX1B1YmxpY2F0aW9uKCkgKyAKICB0aGVtZV9uYXR1cmUoKSArIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYW5ub3RhdGlvbl9jb2xvdXJzJHBhdGllbnRfaWQpICsgeGxhYigiUGxvaWR5IikgKyB5bGFiKCJOdW1iZXIgb2Ygc3ViY2xvbmFsIG5lb2VwaXRvcGVzIikgKwogIGZhY2V0X3dyYXAofiBtZWFzdXJlLCBzY2FsZXMgPSAiZnJlZSIpICsgZ2VvbV90ZXh0KGRhdGE9cHZhbHMsIGFlcyh4PUluZiwgeT1JbmYsIGxhYmVsPXAudmFsdWUudGV4dCksIGhqdXN0PTEuMSwgdmp1c3Q9MS41LHNpemU9Mi41LHBhcnNlPVRSVUUpCgpwMSAKYGBgCgpUaHVzLCBoaWdoZXIgcGxvaWR5IGlzIG5vdCBzaWduaWZpY2FudGx5IGFzc29jaWF0ZWQgd2l0aCBhIGhpZ2hlciBzdWJjbG9uYWwgbmVvZXBpdG9wZSBsb2FkIG9yIHByb3BvcnRpb24uIAoKYGBge3J9CmNsb25hbF9uZW9lZGl0aW5nX3Bsb2lkeV9tZWx0ZWQgPC0gbWVsdChjbG9uYWxfbmVvZWRpdGluZ19wbG9pZHksIGlkLnZhcnMgPSBjKCJwYXRpZW50X2lkIiwgImNvbmRlbnNlZF9pZCIsICJwc2kiLCAiQ2VsbHVsYXJpdHkiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lYXN1cmUudmFycyA9IGMoIm5lcGl0b3BlcyIsICJlcGl0b3BlX3JhdGUiKSwgdmFyaWFibGUubmFtZSA9ICJtZWFzdXJlIiwgdmFsdWUubmFtZSA9ICJ2YWx1ZSIpCgpwdmFscyA8LSBpdGhpLnV0aWxzOjpjb21wdXRlX3B2YWxzX3N1YnNldHMoY2xvbmFsX25lb2VkaXRpbmdfcGxvaWR5X21lbHRlZCwgZmFjZXRfdmFycyA9IGMoIm1lYXN1cmUiKSwgZm9ybXVsYSA9IH4gcHNpICsgdmFsdWUsIGNvcmZ1biA9IGNvci50ZXN0LCBtZXRob2QgPSAic3BlYXJtYW4iKQoKcDIgPC0gZ2dwbG90KGNsb25hbF9uZW9lZGl0aW5nX3Bsb2lkeV9tZWx0ZWQsIGFlcyh4PXBzaSwgeT12YWx1ZSkpICsgZ2VvbV9wb2ludChhZXMoY29sb3VyPXBhdGllbnRfaWQpKSArIHRoZW1lX2J3KCkgKyB0aGVtZV9QdWJsaWNhdGlvbigpICsgCiAgdGhlbWVfbmF0dXJlKCkgKyBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGFubm90YXRpb25fY29sb3VycyRwYXRpZW50X2lkKSArIHhsYWIoIlBsb2lkeSIpICsgeWxhYigiTnVtYmVyIG9mIHN1YmNsb25hbCBuZW9lcGl0b3BlcyIpICsKICBmYWNldF93cmFwKH4gbWVhc3VyZSwgc2NhbGVzID0gImZyZWUiKSArIGdlb21fdGV4dChkYXRhPXB2YWxzLCBhZXMoeD1JbmYsIHk9SW5mLCBsYWJlbD1wLnZhbHVlLnRleHQpLCBoanVzdD0xLjEsIHZqdXN0PTEuNSxzaXplPTIuNSxwYXJzZT1UUlVFKQoKcDIKYGBgCgpKdXN0IGZvciBmdW4sIHdlIGRpZCB0aGlzIGZvciBjbG9uYWwgbmVvZXBpdG9wZXMgdG9vIC0tIHNhbWUgcmVzdWx0LiAKCldoYXQgYWJvdXQgc3ViY2xvbmFsIG9icy9leHAgbmVvZXBpdG9wZSByYXRlcyAoaS5lLiB0aGUgaW1tdW5vZWRpdGluZyBpbmRpY2VzKT8gCgpgYGB7cn0KY29ycmVzIDwtIHdpdGgoc3ViY2xvbmFsX25lb2VkaXRpbmdfcGxvaWR5LCBjb3IudGVzdChwc2ksIGV4cHJhdGlvL29ic3JhdGlvLCBtZXRob2QgPSAic3BlYXJtYW4iKSkKZXEgPC0gc3Vic3RpdHV0ZShpdGFsaWMoUCk9PXAsIGxpc3QocD1mb3JtYXQoY29ycmVzJHAudmFsdWUsIGRpZ2l0cyA9IDMpKSkKCnAxIDwtIGdncGxvdChzdWJjbG9uYWxfbmVvZWRpdGluZ19wbG9pZHksIGFlcyh4PXBzaSwgeT1leHByYXRpby9vYnNyYXRpbykpICsgZ2VvbV9wb2ludChhZXMoY29sb3VyPXBhdGllbnRfaWQpKSArIHRoZW1lX2J3KCkgKyB0aGVtZV9QdWJsaWNhdGlvbigpICsgCiAgdGhlbWVfbmF0dXJlKCkgKyBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGFubm90YXRpb25fY29sb3VycyRwYXRpZW50X2lkKSArIHhsYWIoIlBsb2lkeSIpICsgeWxhYigiRV9pIChzdWJjbG9uYWwpIikgKwogIGFubm90YXRlKCd0ZXh0JywgeCA9IEluZiwgeSA9IEluZiwgcGFyc2UgPSBUUlVFLCBoanVzdCA9IDEsIHZqdXN0ID0gMSwgbGFiZWwgPSBhcy5jaGFyYWN0ZXIoYXMuZXhwcmVzc2lvbihlcSkpKQoKcDEgCmBgYAoKYGBge3J9CmNvcnJlcyA8LSB3aXRoKGNsb25hbF9uZW9lZGl0aW5nX3Bsb2lkeSwgY29yLnRlc3QocHNpLCBleHByYXRpby9vYnNyYXRpbywgbWV0aG9kID0gInNwZWFybWFuIikpCmVxIDwtIHN1YnN0aXR1dGUoaXRhbGljKFApPT1wLCBsaXN0KHA9Zm9ybWF0KGNvcnJlcyRwLnZhbHVlLCBkaWdpdHMgPSAzKSkpCgpwMiA8LSBnZ3Bsb3QoY2xvbmFsX25lb2VkaXRpbmdfcGxvaWR5LCBhZXMoeD1wc2ksIHk9ZXhwcmF0aW8vb2JzcmF0aW8pKSArIGdlb21fcG9pbnQoYWVzKGNvbG91cj1wYXRpZW50X2lkKSkgKyB0aGVtZV9idygpICsgdGhlbWVfUHVibGljYXRpb24oKSArIAogIHRoZW1lX25hdHVyZSgpICsgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBhbm5vdGF0aW9uX2NvbG91cnMkcGF0aWVudF9pZCkgKyB4bGFiKCJQbG9pZHkiKSArIHlsYWIoIkVfaSAoY2xvbmFsKSIpICsKICBhbm5vdGF0ZSgndGV4dCcsIHggPSBJbmYsIHkgPSBJbmYsIHBhcnNlID0gVFJVRSwgaGp1c3QgPSAxLCB2anVzdCA9IDEsIGxhYmVsID0gYXMuY2hhcmFjdGVyKGFzLmV4cHJlc3Npb24oZXEpKSkKCnAyIApgYGAKCkFnYWluLCBubyBzaWduaWZpY2FudCBjb3JyZWxhdGlvbnMuIE5vdywgdG8gaGFtbWVyIGl0IGhvbWUsIGxldCdzIGFkZCBwbG9pZHkgYW5kIGNlbGx1bGFyaXR5IGludG8gdGhlIG5lb2VwaXRvcGUgZWxpbWluYXRpb24gbW9kZWwuIAoKVGhlIGJhc2UgbW9kZWwgaXM6CgpgYGB7cn0KbW9kIDwtIGdsbWVyKGV4cHJhdGlvL29ic3JhdGlvIH4gRV9DRDhfcmVzY2FsZWQgKyAoMSB8IHBhdGllbnRfaWQpLCBkYXRhPXN1YnNldChzdWJjbG9uYWxfbmVvZWRpdGluZ19wbG9pZHksICFpcy5uYShFX0NEOF9kZW5zaXR5KSksIGZhbWlseSA9IEdhbW1hKGxpbms9ImxvZyIpKQpzdW1tb2QgPC0gc3VtbWFyeShtb2QpCnN1bW1vZAojcHZhbCA8LSB1bm5hbWUoc3VtbW9kJGNvZWZmaWNpZW50c1ssNF1bMl0pCmBgYAoKTm93IGFkZGluZyBwbG9pZHkgYW5kIGNlbGx1bGFyaXR5IGFzIGZpeGVkIGVmZmVjdHM6CgpgYGB7cn0KbW9kIDwtIGdsbWVyKGV4cHJhdGlvL29ic3JhdGlvIH4gRV9DRDhfcmVzY2FsZWQgKyBwc2kgKyBDZWxsdWxhcml0eSArICgxIHwgcGF0aWVudF9pZCksIGRhdGE9c3Vic2V0KHN1YmNsb25hbF9uZW9lZGl0aW5nX3Bsb2lkeSwgIWlzLm5hKEVfQ0Q4X2RlbnNpdHkpKSwgZmFtaWx5ID0gR2FtbWEobGluaz0ibG9nIikpCnN1bW1vZCA8LSBzdW1tYXJ5KG1vZCkKc3VtbW9kCiNwdmFsIDwtIHVubmFtZShzdW1tb2QkY29lZmZpY2llbnRzWyw0XVsyXSkKYGBgCgoKVGhlIHAtdmFsdWUgPSBgciB1bm5hbWUoc3VtbW9kJGNvZWZmaWNpZW50c1ssNF1bMl0pYCBmb3IgdGhlIGVwaXRoZWxpYWwgQ0Q4KyBUSUwgZGVuc2l0eSBlZmZlY3QgcmVtYWlucyBzaWduaWZpY2FudC4gUGxvaWR5IGFuZCBjZWxsdWxhcml0eSBhcmUgbm90IHNpZ25pZmljYW50IGVmZmVjdHMuIEFzIGEgc2FuaXR5IGNoZWNrLCB3ZSBtYWtlIHN1cmUgdGhhdCB0aGUgYmV0YSAoY29lZmZpY2llbnQpIGZvciBFX0NEOF9yZXNjYWxlZCByZW1haW5zIHRoZSBzYW1lIHNpZ24gaW4gYm90aCBjYXNlcywgd2hpY2ggaXQgZG9lcy4gCgo=