Setup

library(ithi.utils)
load_base_libs()
library(ithi.meta)
library(ithi.figures)
library(ithi.expr)
library(ithi.external)
library(ithi.lohhla)
lohhla_icgc_outdir <- snakemake@input$lohhla_icgc_outdir
ith_icgc_bc_file <- snakemake@input$ith_icgc_bc
icgc_specimen_file <- snakemake@input$icgc_specimen
nanostring_annotations_path <- snakemake@input$nanostring_annotations
icgc_subtype_file <- snakemake@input$icgc_subtypes
icgc_expr_mat_file <- snakemake@input$icgc_expr_mat

lohhla_tcga_outdir <- snakemake@input$lohhla_tcga_outdir
tcga_ov_annotation_file <- snakemake@input$tcga_ov_annotations
nmf_subtype_file <- snakemake@input$array_nmf_subtypes
tcga_paper_subtype_file <- snakemake@input$tcga_paper_subtypes_raw
tcga_paper_silhouette_file <- snakemake@input$tcga_paper_subtypes_possilhouette
tcga_ov_bam_dir <- snakemake@input$tcga_ov_bam_dir
tcga_nonstd_expr_mat_file <- snakemake@input$tcga_nonstd_expr

db_path <- snakemake@params$db
supportive_site_threshold <- as.numeric(snakemake@params$lohhla_supportive_site_threshold)
mismatch_site_threshold <- as.numeric(snakemake@params$lohhla_mismatch_site_threshold)
icgc_specimen <- fread(icgc_specimen_file)
ith_icgc_bc <- fread(ith_icgc_bc_file)
icgc_subtypes <- fread(icgc_subtype_file)
icgc_expr_mat <- fread(icgc_expr_mat_file)

nmf_subtypes <- read_tcga_nmf_subtypes(nmf_subtype_file)
tcga_paper_subtypes <- read_tcga_paper_subtypes(tcga_paper_subtype_file, tcga_paper_silhouette_file)
tcga_nonstd_expr_mat <- fread(tcga_nonstd_expr_mat_file)

Read 0.0% of 570 rows
Read 570 rows and 12439 (of 12439) columns from 0.112 GB file in 00:00:06
tcga_ov_annotations <- fread(tcga_ov_annotation_file)

nanostring_labels <- fread(nanostring_annotations_path)
nanostring_labels_modified <- read_nanostring_labels_modified(nanostring_annotations_path)

tcga_bam_manifest <- create_bam_manifest(tcga_ov_bam_dir, ucec_format = FALSE, 
    local = FALSE)

Here we’re going to run LOHHLA on ICGC and TCGA.

A few things to note:

  • ICGC is lower sequencing depth
  • TCGA-OV was the earliest TCGA study and is not as high-quality as the studies after it – comparisons may need to be taken with a pinch of salt

ICGC

icgc_hlaloss_table <- extract_lohhla_table(lohhla_icgc_outdir)
icgc_loss_table <- construct_loss_table(icgc_hlaloss_table, type = "ICGC", supportive_site_threshold = supportive_site_threshold, 
    mismatch_site_threshold = mismatch_site_threshold)
icgc_loss_summarized <- summarize_loss_table(icgc_loss_table, type = "ICGC")
table(icgc_loss_summarized$loh)

FALSE  TRUE 
   36    17 

vs. Molecular subtypes

icgc_loss_summarized_subtypes <- merge(icgc_loss_summarized, icgc_subtypes, 
    by.x = c("sample_key"), by.y = c("icgc_donor_id"))

with(icgc_loss_summarized_subtypes, table(loh, subtype))
       subtype
loh     C1 C2 C4 C5
  FALSE 14 10  8  3
  TRUE   9  3  2  2
with(icgc_loss_summarized_subtypes, table(loh, nmf_subtype))
       nmf_subtype
loh     C1 C2 C4 C5
  FALSE 12  6  6 12
  TRUE   9  3  0  4
fisher.test(with(icgc_loss_summarized_subtypes, table(loh, nmf_subtype %in% 
    c("C1", "C2"))))

    Fisher's Exact Test for Count Data

data:  
p-value = 0.1311
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
  0.7111636 14.9334176
sample estimates:
odds ratio 
  2.938272 

Missing samples

subset(icgc_subtypes, icgc_donor_id %in% c("DO46388", "DO46390", "DO46571"))

The other 4 samples have no suitable HLA alleles (i.e. they’re homozygous at all 3 HLA loci). These 3 samples had the error that is due to no reads mapping to one of the alleles. If these samples are true ‘LOH’, their molecular subtype assignments are not surprising in light of the previous results – 2/3 are C1 samples, by either classification.

vs. Expression patterns

Batch corrected file with our cohort

icgc_pathway_matrix <- ithi.expr::create_pathway_matrix(ith_icgc_bc, nanostring_labels, 
    db_path, convert_ids = FALSE, summary_method = "arithmetic_mean")

icgc_pathway_matrix_summarized <- summarize_expression_by_patient(icgc_pathway_matrix, 
    icgc_specimen)

icgc_pathway_df <- icgc_pathway_matrix_summarized %>% tibble::column_to_rownames(var = "Name") %>% 
    as.matrix %>% melt %>% plyr::rename(c(Var1 = "pathway", Var2 = "sample_key", 
    value = "mean_expr"))
icgc_loss_summarized_expr <- merge(icgc_loss_summarized, icgc_pathway_df)
df <- icgc_loss_summarized_expr  # %>% subset(pathway %in% c('T-Cell Functions', 'B-Cell Functions', 'Cytotoxicity'))

pvals <- compute_pvals_subsets(df, facet_vars = c("pathway"), corfun = wilcox.test, 
    formula = mean_expr ~ loh)

ggplot(df, aes(x = loh, y = mean_expr)) + geom_boxplot(outlier.size = -1) + 
    geom_jitter(position = position_jitter(width = 0.2, height = 0), alpha = 0.5) + 
    theme_bw() + facet_wrap(~pathway, scales = "free", ncol = 3) + theme_Publication() + 
    theme_nature() + geom_text(data = pvals, aes(x = Inf, y = Inf, label = p.value.text), 
    hjust = 1.1, vjust = 1.5, size = 2.5, parse = TRUE)

We can see a trend, but it’s not significant – likely due to sample size (see first section for sample size numbers).

So we see a tendency towards higher T-cell-associated gene expression among samples with LOHHLA, though this is not significant.

TCGA

At the moment I’m only using those samples for which we have ploidy/cellularity predictions from ASCAT from Nicolai Birkbak – that was from an older version of ASCAT, etc.

I still have to run the newer ASCAT pipeline – ran into a few problems with time earlier that I’ll probably have to resolve by making the ASCAT package more efficient. Got halfway through this then got sidetracked by other analysis …

So these results are really on about 2/3 to 3/4 of the TCGA-OV cohort.

tcga_hlaloss_table <- extract_lohhla_table(lohhla_tcga_outdir)
tcga_hlaloss_table$tcga_sample_id <- stringr::str_extract(tcga_hlaloss_table$region, 
    "TCGA\\-[0-9A-Z]{2}\\-[0-9A-Z]{4}")
tcga_hlaloss_table$analyte_type <- stringr::str_extract(tcga_hlaloss_table$region, 
    "(?<=TCGA\\-[0-9A-Z]{2}\\-[0-9A-Z]{4}\\-[0-9A-Z]{3}\\-[0-9A-Z]{2})[A-Z]")
# tcga_hlaloss_table <- subset(tcga_hlaloss_table, analyte_type == 'D')
hist(tcga_hlaloss_table$HLA_type1copyNum_withBAF, breaks = 30)

hist(tcga_hlaloss_table$HLA_type2copyNum_withBAF, breaks = 30)

Prevalence of HLA loss

By sample key

tcga_loss_table <- construct_loss_table(tcga_hlaloss_table, type = "TCGA", supportive_site_threshold = supportive_site_threshold, 
    mismatch_site_threshold = mismatch_site_threshold)
max_plate <- tcga_loss_table %>% group_by(tcga_sample_id) %>% summarise(max_plate = max(as.numeric(plate)))
tcga_loss_table <- tcga_loss_table %>% plyr::join(max_plate)
tcga_loss_table <- subset(tcga_loss_table, as.numeric(plate) == max_plate)

tcga_loss_summarized <- summarize_loss_table(tcga_loss_table, type = "TCGA")

Comparison with molecular subtypes

tcga_manifest_data <- tcga_bam_manifest %>% subset(specimen_type == "diseased", 
    select = c(center, patient, barcode, sample_key, short_barcode))

nmf_subtypes_merged <- Reduce(function(x, y) plyr::join(x, y, type = "full"), 
    list(nmf_subtypes, tcga_manifest_data, tcga_paper_subtypes)) %>% plyr::rename(c(subtype = "nmf_subtype", 
    secondary = "nmf_secondary_subtype")) %>% subset(select = -c(tcga_sample_id))
# nmf_subtypes_merged_noduplicates <-
# nmf_subtypes_merged[!duplicated(nmf_subtypes_merged$short_barcode),]
nmf_subtypes_merged$tcga_sample_id <- nmf_subtypes_merged$patient
nmf_subtypes_merged_noduplicates <- nmf_subtypes_merged
nmf_subtypes_merged_noduplicates <- subset(nmf_subtypes_merged_noduplicates, 
    !is.na(sample_key)) %>% subset(select = -c(barcode, sample_key, center)) %>% 
    unique
nmf_subtypes_merged_noduplicates <- nmf_subtypes_merged_noduplicates[!duplicated(nmf_subtypes_merged_noduplicates$patient), 
    ]
tcga_loss_summarized$analysis_center <- str_extract(tcga_loss_summarized$sample_key, 
    "(Non\\-)?Broad")

tcga_loss_annotated <- Reduce(function(x, y) plyr::join(x, y, type = "full"), 
    list(tcga_loss_summarized %>% as.data.frame, tcga_ov_annotations, nmf_subtypes_merged_noduplicates))

Subtypes from Yikan’s table

with(tcga_loss_annotated, table(MolecularSubtype, loss))
                loss
MolecularSubtype FALSE TRUE
  Differentiated    61    0
  Immunoreactive    61    3
  Mesenchymal       66    0
  Proliferative     65    2
with(tcga_loss_annotated, table(MolecularSubtype, loss))/rowSums(with(tcga_loss_annotated, 
    table(MolecularSubtype, loss)))
                loss
MolecularSubtype      FALSE       TRUE
  Differentiated 1.00000000 0.00000000
  Immunoreactive 0.95312500 0.04687500
  Mesenchymal    1.00000000 0.00000000
  Proliferative  0.97014925 0.02985075
fisher.test(with(tcga_loss_annotated, table(MolecularSubtype %in% c("Immunoreactive", 
    "Mesenchymal"), loss)))

    Fisher's Exact Test for Count Data

data:  
p-value = 0.3547
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
  0.3061054 32.8301221
sample estimates:
odds ratio 
  2.708565 
with(tcga_loss_annotated, table(MolecularSubtype, loh))
                loh
MolecularSubtype FALSE TRUE
  Differentiated    41   20
  Immunoreactive    45   19
  Mesenchymal       44   22
  Proliferative     45   22
with(tcga_loss_annotated, table(MolecularSubtype, loh))/rowSums(with(tcga_loss_annotated, 
    table(MolecularSubtype, loh)))
                loh
MolecularSubtype     FALSE      TRUE
  Differentiated 0.6721311 0.3278689
  Immunoreactive 0.7031250 0.2968750
  Mesenchymal    0.6666667 0.3333333
  Proliferative  0.6716418 0.3283582

NMF-inferred subtypes

## Not technically a primary site filter here -- this is just a simple Wang
## et al. filter
filter_primary <- FALSE

dat <- tcga_loss_annotated

if (filter_primary) {
    dat <- dat %>% subset(!is.na(MolecularSubtype))
}
with(dat, table(nmf_subtype, loss))
           loss
nmf_subtype FALSE TRUE
         C1    62    0
         C2    97    3
         C4   101    0
         C5    94    2
with(dat, table(nmf_subtype, loss))/rowSums(with(dat, table(nmf_subtype, loss)))
           loss
nmf_subtype      FALSE       TRUE
         C1 1.00000000 0.00000000
         C2 0.97000000 0.03000000
         C4 1.00000000 0.00000000
         C5 0.97916667 0.02083333
with(dat, table(nmf_subtype, loh))
           loh
nmf_subtype FALSE TRUE
         C1    42   20
         C2    72   28
         C4    73   28
         C5    63   33
with(dat, table(nmf_subtype, loh))/rowSums(with(dat, table(nmf_subtype, loh)))
           loh
nmf_subtype     FALSE      TRUE
         C1 0.6774194 0.3225806
         C2 0.7200000 0.2800000
         C4 0.7227723 0.2772277
         C5 0.6562500 0.3437500
with(dat %>% subset(sil_width > 0), table(nmf_subtype, loss))
           loss
nmf_subtype FALSE TRUE
         C1    62    0
         C2    88    3
         C4    68    0
         C5    65    2
with(dat %>% subset(sil_width > 0), table(nmf_subtype, loss))/rowSums(with(dat %>% 
    subset(sil_width > 0), table(nmf_subtype, loss)))
           loss
nmf_subtype      FALSE       TRUE
         C1 1.00000000 0.00000000
         C2 0.96703297 0.03296703
         C4 1.00000000 0.00000000
         C5 0.97014925 0.02985075
with(dat %>% subset(sil_width > 0), table(nmf_subtype, loh))
           loh
nmf_subtype FALSE TRUE
         C1    42   20
         C2    64   27
         C4    48   20
         C5    45   22
with(dat %>% subset(sil_width > 0), table(nmf_subtype, loh))/rowSums(with(dat %>% 
    subset(sil_width > 0), table(nmf_subtype, loh)))
           loh
nmf_subtype     FALSE      TRUE
         C1 0.6774194 0.3225806
         C2 0.7032967 0.2967033
         C4 0.7058824 0.2941176
         C5 0.6716418 0.3283582

Expression differences between NMF-annotated subtypes

tcga_nonstd_expr_df <- tcga_nonstd_expr_mat %>% as.data.frame %>% tibble::column_to_rownames("tcga_sample_id") %>% 
    t %>% as.data.frame %>% tibble::rownames_to_column("Name")
tcga_pathway_matrix_amean <- ithi.expr::create_pathway_matrix(tcga_nonstd_expr_df, 
    nanostring_labels_modified, db_path, convert_ids = FALSE, summary_method = "arithmetic_mean")
tcga_pathway_matrix_gmean <- ithi.expr::create_pathway_matrix(tcga_nonstd_expr_df, 
    nanostring_labels_modified, db_path, convert_ids = FALSE, summary_method = "geometric_mean")

tcga_pathway_matrix_nano <- tcga_pathway_matrix_amean[setdiff(rownames(tcga_pathway_matrix_amean), 
    "Rooney_Cytotoxicity"), ]
tcga_pathway_matrix_rooney <- tcga_pathway_matrix_gmean["Rooney_Cytotoxicity", 
    , drop = FALSE]

tcga_pathway_matrix <- rbind(tcga_pathway_matrix_nano, tcga_pathway_matrix_rooney)

tcga_pathway_df <- tcga_pathway_matrix %>% as.matrix %>% melt %>% plyr::rename(c(Var2 = "short_barcode", 
    Var1 = "pathway", value = "expr"))
tcga_pathway_df_annotated <- plyr::join(tcga_pathway_df, nmf_subtypes_merged_noduplicates)
p <- ggplot(tcga_pathway_df_annotated, aes(x = nmf_subtype, y = expr)) + geom_boxplot() + 
    theme_bw() + theme_Publication() + theme_nature() + facet_wrap(~pathway, 
    scales = "free", ncol = 2)

p

C5 is clearly the lowest, below C4.

Expression difference between LOH and non-LOH samples

tcga_pathway_loss <- tcga_pathway_df_annotated %>% as.data.frame %>% plyr::join(tcga_loss_annotated)
df <- tcga_pathway_loss %>% subset(!is.na(loh))
df$center <- str_extract(df$tcga_sample_id, "(?<=\\-)[0-9A-Z]{2}(?=\\-)")

pvals <- ithi.utils::compute_pvals_subsets(df, facet_vars = c("pathway"), formula = expr ~ 
    loh, corfun = wilcox.test)

p <- ggplot(df, aes(x = loh, y = expr)) + geom_boxplot() + theme_bw() + theme_Publication() + 
    theme_nature() + facet_wrap(~pathway, scales = "free", ncol = 2) + 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

I also did this with TCGA’s RNA-seq data in another file and found nothing.

By center

df_subset <- subset(df, pathway == "Rooney_Cytotoxicity" & !is.na(loh) & !is.na(center))

pvals <- ithi.utils::compute_pvals_subsets(df_subset, facet_vars = c("center"), 
    formula = expr ~ loh, corfun = wilcox.test)

p <- ggplot(df_subset, aes(x = loh, y = expr)) + geom_boxplot(outlier.size = -1) + 
    geom_jitter(position = position_jitter(width = 0.2, height = 0), alpha = 0.5) + 
    theme_bw() + theme_Publication() + theme_nature() + facet_wrap(~center, 
    scales = "free", ncol = 2) + geom_text(data = pvals, aes(x = Inf, y = Inf, 
    label = p.value.text), hjust = 1.1, vjust = 1.5, size = 2.5, parse = TRUE)

table(df_subset$center)

04 09 10 13 20 23 24 25 29 30 31 36 42 57 59 61 
26 15  9 75  9 29 60 12 35  6  3 14  7  3  3 47 
p

The UPenn center shows something, but the other 2 big ones – Broad and MSKCC – do not.

TCGA-annotated subtypes

with(dat %>% subset(paper_pos_silhouette), table(tcga_paper_subtype, loss))
                  loss
tcga_paper_subtype FALSE TRUE
    Differentiated    61    0
    Immunoreactive    60    3
    Mesenchymal       66    0
    Proliferative     65    2
with(dat %>% subset(paper_pos_silhouette), table(tcga_paper_subtype, loss))/rowSums(with(dat %>% 
    subset(paper_pos_silhouette), table(tcga_paper_subtype, loss)))
                  loss
tcga_paper_subtype      FALSE       TRUE
    Differentiated 1.00000000 0.00000000
    Immunoreactive 0.95238095 0.04761905
    Mesenchymal    1.00000000 0.00000000
    Proliferative  0.97014925 0.02985075
with(dat %>% subset(paper_pos_silhouette), table(tcga_paper_subtype, loh))
                  loh
tcga_paper_subtype FALSE TRUE
    Differentiated    41   20
    Immunoreactive    44   19
    Mesenchymal       45   21
    Proliferative     45   22
with(dat %>% subset(paper_pos_silhouette), table(tcga_paper_subtype, loh))/rowSums(with(dat %>% 
    subset(paper_pos_silhouette), table(tcga_paper_subtype, loh)))
                  loh
tcga_paper_subtype     FALSE      TRUE
    Differentiated 0.6721311 0.3278689
    Immunoreactive 0.6984127 0.3015873
    Mesenchymal    0.6818182 0.3181818
    Proliferative  0.6716418 0.3283582

Comparison with foldback inversion/HRD subtypes

with(dat, table(Subgroup, loss))
              loss
Subgroup       FALSE TRUE
  FBI-AMP High   140    2
  FBI-AMP Low    161    1
  No AMP          54    2
with(dat, table(Subgroup, loh))
              loh
Subgroup       FALSE TRUE
  FBI-AMP High    98   44
  FBI-AMP Low    111   51
  No AMP          41   15

Not really any difference betwen foldback subsets in terms of this.

LS0tCnRpdGxlOiAiTE9ISExBIC0tIGV4dGVybmFsIGRhdGFzZXRzIgotLS0KICAgICAgICAgICAgICAgICAgICAgICAgYGBge3IsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgojIyMjIyMjIyBTbmFrZW1ha2UgaGVhZGVyICMjIyMjIyMjCmxpYnJhcnkobWV0aG9kcykKU25ha2VtYWtlIDwtIHNldENsYXNzKAogICAgIlNuYWtlbWFrZSIsCiAgICBzbG90cyA9IGMoCiAgICAgICAgaW5wdXQgPSAibGlzdCIsCiAgICAgICAgb3V0cHV0ID0gImxpc3QiLAogICAgICAgIHBhcmFtcyA9ICJsaXN0IiwKICAgICAgICB3aWxkY2FyZHMgPSAibGlzdCIsCiAgICAgICAgdGhyZWFkcyA9ICJudW1lcmljIiwKICAgICAgICBsb2cgPSAibGlzdCIsCiAgICAgICAgcmVzb3VyY2VzID0gImxpc3QiLAogICAgICAgIGNvbmZpZyA9ICJsaXN0IiwKICAgICAgICBydWxlID0gImNoYXJhY3RlciIKICAgICkKKQpzbmFrZW1ha2UgPC0gU25ha2VtYWtlKAogICAgaW5wdXQgPSBsaXN0KCcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvSUNHQy9PVkFVX2V4cHJfbWF0cml4LnRzdicsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvZGF0YS9leHByZXNzaW9uL2FycmF5L3N1YnR5cGVzL25tZl9zdWJ0eXBlcy50eHQnLCAnL3NoYWhsYWIvYWx6aGFuZy9kYXRhL1RDR0EvdGNnYV9vdl9hbm5vdGF0aW9uX3N1cDEzLnR4dCcsICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9sb2hobGEvcnVuMV9pY2djJywgJy9zaGFobGFiL2FsemhhbmcvZGF0YS9UQ0dBL1RDR0FfNDg5X1VFLms0LnR4dCcsICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvSUNHQy9zcGVjaW1lbi50c3YnLCAnL3NoYWhsYWIvYXJjaGl2ZS9pbW11bmVfcHJvamVjdC9UQ0dBLU9WL2JhbScsICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvVENHQS9UQ0dBXzQ4OV9VRS5rNC5wb3NTaWxob3VldHRlLnR4dCcsICdub3RlYm9va3MvbG9oaGxhX3RjZ2FfaWNnYy5SbWQnLCAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2RhdGEvZXhwcmVzc2lvbi9uYW5vc3RyaW5nL3BhbmNhbmNlcl9hbm5vdGF0aW9ucy50c3YnLCAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvbG9oaGxhL3J1bjhfdGNnYScsICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvVENHQS9leHByX21hdHJpeF9ub3JtYWxpemVfbm9kdXBsaWNhdGVzLnRzdicsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9pdGhfaWNnY19tZXJnZWRfYmMudHN2JywgJy9zaGFobGFiL2FsemhhbmcvZGF0YS9JQ0dDL2ljZ2NfcHJpbWFyeV90dW1vdXJfc3VidHlwZXMudHN2JywgImljZ2NfZXhwcl9tYXQiID0gJy9zaGFobGFiL2FsemhhbmcvZGF0YS9JQ0dDL09WQVVfZXhwcl9tYXRyaXgudHN2JywgImFycmF5X25tZl9zdWJ0eXBlcyIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2RhdGEvZXhwcmVzc2lvbi9hcnJheS9zdWJ0eXBlcy9ubWZfc3VidHlwZXMudHh0JywgInRjZ2Ffb3ZfYW5ub3RhdGlvbnMiID0gJy9zaGFobGFiL2FsemhhbmcvZGF0YS9UQ0dBL3RjZ2Ffb3ZfYW5ub3RhdGlvbl9zdXAxMy50eHQnLCAibG9oaGxhX2ljZ2Nfb3V0ZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9sb2hobGEvcnVuMV9pY2djJywgInRjZ2FfcGFwZXJfc3VidHlwZXNfcmF3IiA9ICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvVENHQS9UQ0dBXzQ4OV9VRS5rNC50eHQnLCAiaWNnY19zcGVjaW1lbiIgPSAnL3NoYWhsYWIvYWx6aGFuZy9kYXRhL0lDR0Mvc3BlY2ltZW4udHN2JywgInRjZ2Ffb3ZfYmFtX2RpciIgPSAnL3NoYWhsYWIvYXJjaGl2ZS9pbW11bmVfcHJvamVjdC9UQ0dBLU9WL2JhbScsICJ0Y2dhX3BhcGVyX3N1YnR5cGVzX3Bvc3NpbGhvdWV0dGUiID0gJy9zaGFobGFiL2FsemhhbmcvZGF0YS9UQ0dBL1RDR0FfNDg5X1VFLms0LnBvc1NpbGhvdWV0dGUudHh0JywgIm5vdGVib29rIiA9ICdub3RlYm9va3MvbG9oaGxhX3RjZ2FfaWNnYy5SbWQnLCAibmFub3N0cmluZ19hbm5vdGF0aW9ucyIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2RhdGEvZXhwcmVzc2lvbi9uYW5vc3RyaW5nL3BhbmNhbmNlcl9hbm5vdGF0aW9ucy50c3YnLCAibG9oaGxhX3RjZ2Ffb3V0ZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9sb2hobGEvcnVuOF90Y2dhJywgInRjZ2Ffbm9uc3RkX2V4cHIiID0gJy9zaGFobGFiL2FsemhhbmcvZGF0YS9UQ0dBL2V4cHJfbWF0cml4X25vcm1hbGl6ZV9ub2R1cGxpY2F0ZXMudHN2JywgIml0aF9pY2djX2JjIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9pdGhfaWNnY19tZXJnZWRfYmMudHN2JywgImljZ2Nfc3VidHlwZXMiID0gJy9zaGFobGFiL2FsemhhbmcvZGF0YS9JQ0dDL2ljZ2NfcHJpbWFyeV90dW1vdXJfc3VidHlwZXMudHN2JyksCiAgICBvdXRwdXQgPSBsaXN0KCcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy9yZXZpZXcvbm90ZWJvb2tzL3J1bjIvbG9oaGxhX3RjZ2FfaWNnYy5uYi5odG1sJyksCiAgICBwYXJhbXMgPSBsaXN0KDkwLjAsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvbWV0YWRhdGEvZGIvaW1tdW5lX3Byb2plY3Quc3FsaXRlMycsIDUuMCwgJ2xvaGhsYV9leHRlcm5hbF9hbmFseXNpcycsICJsb2hobGFfc3VwcG9ydGl2ZV9zaXRlX3RocmVzaG9sZCIgPSA5MC4wLCAiZGIiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9tZXRhZGF0YS9kYi9pbW11bmVfcHJvamVjdC5zcWxpdGUzJywgImxvaGhsYV9taXNtYXRjaF9zaXRlX3RocmVzaG9sZCIgPSA1LjAsICJuYW1lIiA9ICdsb2hobGFfZXh0ZXJuYWxfYW5hbHlzaXMnKSwKICAgIHdpbGRjYXJkcyA9IGxpc3QoKSwKICAgIHRocmVhZHMgPSAxLAogICAgbG9nID0gbGlzdCgnL3NoYWhsYWIvYWx6aGFuZy9jbHVzdHRtcC9wYXBlcnJldmlldzIvbm90ZWJvb2tzL2xvaGhsYV9leHRlcm5hbF9hbmFseXNpcy5sb2cnKSwKICAgIHJlc291cmNlcyA9IGxpc3QoKSwKICAgIGNvbmZpZyA9IGxpc3QoImxvaGhsYV9zdXBwb3J0aXZlX3NpdGVfdGhyZXNob2xkIiA9IDkwLjAsICJhcnJheV9ubWZfc3VidHlwZXMiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9kYXRhL2V4cHJlc3Npb24vYXJyYXkvc3VidHlwZXMvbm1mX3N1YnR5cGVzLnR4dCcsICJwYXRpZW50c19mb3JfY2xvbmFsIiA9IGMoMSwgMiwgMywgNCwgNywgOSwgMTAsIDExLCAxMiwgMTMsIDE0LCAxNSwgMTYsIDE3KSwgImJjcl9kaXZlcnNpdHkiID0gJy9zaGFobGFiL2FsemhhbmcvcGlwZWxpbmVfb3V0cHV0cy9pdGhfaW1tdW5lL21peGNyL21peGNyX3J1bnMvaXRoXzFfMl8zL21peGNyNS9wb3N0cHJvY2Vzcy9JR0gvcG9zdGZpbHRlcl9kaXZlcnNpdHlfc3RhdHMvZGl2ZXJzaXR5LnN0cmljdC5yZXNhbXBsZWQudHh0JywgInNudl90YWJsZSIgPSAnL3NoYWhsYWIvYW1jcGhlcnNvbi9wcm9qZWN0cy9pdGgzL2l0aDMvbm90ZWJvb2tzL2Jlc3Bva2UvaXRoX3NudnMudHN2JywgIm1tY3RtX2ZpbmFsX3BhdGllbnRfZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcmVzdWx0cy9tbWN0bV9yZXN1bHRzL2l0aF9ieS1wYXRpZW50X3dpdGgtb3YnLCAidGNyX2RpdmVyc2l0eSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvbWl4Y3IvbWl4Y3JfcnVucy9pdGhfMV8yXzMvbWl4Y3I1L3Bvc3Rwcm9jZXNzL1RSQi9wb3N0ZmlsdGVyX2RpdmVyc2l0eV9zdGF0cy9kaXZlcnNpdHkuc3RyaWN0LnJlc2FtcGxlZC50eHQnLCAiY2xvbGFfcmVzdWx0X2ZpbGUiID0gJy9zaGFobGFiL2FsemhhbmcvcGlwZWxpbmVfb3V0cHV0cy9pdGhfaW1tdW5lL2Nsb2xhL3J1bjQvY2xvbGFfY29uZGVuc2VkX3Jlc3VsdHMvYmV0YS9jbG9sYV9yZXN1bHRzLnRzdicsICJyb29uZXlfbXV0c2lnY3ZfZmlsZSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2V4dGVybmFsL290aGVyX3BhcGVycy9tbWM2Lnhsc3gnLCAiZXBpdG9wZXNfdW5pcXVlX2ZpbHRlcmVkIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9lcGl0b3Blc191bmlxdWVfZmlsdGVyZWQudHN2JywgInRvdGFsX3RpbHR5cGVzIiA9IGMoJ1RfQ0Q4X2RlbnNpdHknLCAnVF9DRDRfZGVuc2l0eScsICdUX0NEMjBfZGVuc2l0eScsICdUX1BsYXNtYV9kZW5zaXR5JyksICJjb3B5bnVtYmVyX3RhYmxlIiA9ICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvaXRoaS9tYXN0ZXJfY29weW51bWJlcl9maWxlLnRzdicsICJ4Y3JfdGFibGUiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3RhYmxlcy9ydW4yL3hjcl90YWJsZS50c3YnLCAiaXRoX3N0YXRzIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9pdGhfc3RhdGlzdGljcy50c3YnLCAidGNnYV9ub25zdGRfZXhwciIgPSAnL3NoYWhsYWIvYWx6aGFuZy9kYXRhL1RDR0EvZXhwcl9tYXRyaXhfbm9ybWFsaXplX25vZHVwbGljYXRlcy50c3YnLCAiaWdwYXJ0aXRpb25fb3V0ZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9pZ3BhcnRpdGlvbi9ydW4yMicsICJhbGxfdGlsdHlwZXMiID0gYygnVF9DRDhfZGVuc2l0eScsICdUX0NENF9kZW5zaXR5JywgJ1RfQ0QyMF9kZW5zaXR5JywgJ1RfUGxhc21hX2RlbnNpdHknLCAnRV9DRDhfZGVuc2l0eScsICdFX0NENF9kZW5zaXR5JywgJ0VfQ0QyMF9kZW5zaXR5JywgJ0VfUGxhc21hX2RlbnNpdHknLCAnU19DRDhfZGVuc2l0eScsICdTX0NENF9kZW5zaXR5JywgJ1NfQ0QyMF9kZW5zaXR5JywgJ1NfUGxhc21hX2RlbnNpdHknKSwgInNudl9jbHVzdGVyX2RpciIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvY2xvbmVzL3Nudl9jbHVzdGVyJywgImljZ2NfZXhwcl9tYXQiID0gJy9zaGFobGFiL2FsemhhbmcvZGF0YS9JQ0dDL09WQVVfZXhwcl9tYXRyaXgudHN2JywgImxvaGhsYV9pY2djX291dGRpciIgPSAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvbG9oaGxhL3J1bjFfaWNnYycsICJicmVha3BvaW50X3RhYmxlIiA9ICcvc2hhaGxhYi9hbWNwaGVyc29uL3Byb2plY3RzL2l0aDMvaXRoMy9ub3RlYm9va3MvYmVzcG9rZS9pdGhfYnJlYWtwb2ludHMudHN2JywgImhlX3Jlc3VsdHNfZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvaXRoaS9maW5uX3Jlc3VsdHMvaGVfb3V0cHV0X05vdjI5JywgInR1bW91cl9wdXJpdHkiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3RhYmxlcy9ydW4yL3R1bW91cl9wdXJpdHkudHN2JywgImxvaGhsYV9taXNtYXRjaF9zaXRlX3RocmVzaG9sZCIgPSA1LjAsICJ0Y2dhX292X2JhbV9kaXIiID0gJy9zaGFobGFiL2FyY2hpdmUvaW1tdW5lX3Byb2plY3QvVENHQS1PVi9iYW0nLCAicHJldmFsZW5jZV90aHJlc2hvbGQiID0gMC4wMSwgImltYWdlX3N1bW1hcnkyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvaXRoaS95dWFuX2hlY3JfaW1hZ2VfcmVzdWx0c18yLmNzdicsICJkaXN0YW5jZV9tZXRob2QiID0gJ2hvcm4nLCAiZmlubmhlX3BpcGVsaW5lX3Jlc3VsdHNfZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9maW5uaGUvcnVuMScsICJub3RlYm9va19kaXIiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3Jldmlldy9ub3RlYm9va3MvcnVuMicsICJzb21hdGljX2NvZGluZ19yZXN1bHRfZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9zb21hdGljX2NvZGluZ192YXJpYW50cycsICJ0YWJsZV9kaXIiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3Jldmlldy90YWJsZXMvcnVuMicsICJyZWZzZXFfZ2VuZV9maWxlIiA9ICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvZ2Vub21lL2hnMTkvcmVmc2VxX2dlbmVzLmJlZCcsICJpdGhfc3RhdF90eXBlcyIgPSBjKCdlbnRyb3B5JywgJ3Bvc3Rwcm9jZXNzZWRfZGl2ZXJnZW5jZScsICdjb21iaW5lZF9pdGhfbm9ybWFsaXplZCcsICdwcm9wb3J0aW9uX3N1YmNsb25hbCcpLCAicmVtaXh0X2NlbGx1bGFyaXR5X3Bsb2lkeSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvcmVtaXh0X2NlbGx1bGFyaXR5X3Bsb2lkeS50c3YnLCAibG9nZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL2NsdXN0dG1wL3BhcGVycmV2aWV3MicsICJ0Y2dhX292X2Fubm90YXRpb25zIiA9ICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvVENHQS90Y2dhX292X2Fubm90YXRpb25fc3VwMTMudHh0JywgImloY19mZWF0dXJlc19vdXRwdXQiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL2ludGVybWVkaWF0ZXMvcnVuMi9paGNfZmVhdHVyZXNfb3V0cHV0LnR4dCcsICJtb2xzdWJ0eXBlcyIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvbW9sc3VidHlwZXMudHN2JywgImNsb25lX3ByZXZhbGVuY2VzIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9jbG9uZXMvY2xvbmVfZGF0YS50c3YnLCAiYXJyYXlfZXhwcmVzc2lvbl9maWxlIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvZGF0YS9leHByZXNzaW9uL2FycmF5L2dlbmVfZXhwcnNfcm1hX2JhdGNoX2NvcnJlY3RlZC50eHQnLCAiYmVuY2htYXJrZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL2JlbmNobWFya3MvcGFwZXJyZXZpZXcyJywgImNsb25lX2JyYW5jaF9sZW5ndGhzIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9jbG9uZXMvYnJhbmNoX2RhdGEudHN2JywgIm5hbm9zdHJpbmdfYW5ub3RhdGlvbnMiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9kYXRhL2V4cHJlc3Npb24vbmFub3N0cmluZy9wYW5jYW5jZXJfYW5ub3RhdGlvbnMudHN2JywgImxvaGhsYV90Y2dhX291dGRpciIgPSAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvbG9oaGxhL3J1bjhfdGNnYScsICJ0aWxzX2Zvcl9jbHVzdGVyIiA9IGMoJ0VfQ0Q4X2RlbnNpdHknLCAnRV9DRDRfZGVuc2l0eScsICdFX0NEMjBfZGVuc2l0eScsICdFX1BsYXNtYV9kZW5zaXR5JywgJ1NfQ0Q4X2RlbnNpdHknLCAnU19DRDRfZGVuc2l0eScsICdTX0NEMjBfZGVuc2l0eScsICdTX1BsYXNtYV9kZW5zaXR5JyksICJpdGhfaWNnY19iYyIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvaXRoX2ljZ2NfbWVyZ2VkX2JjLnRzdicsICJpbWFnZV9zdW1tYXJ5IiA9ICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvaXRoaS95dWFuX2hlY3JfaW1hZ2VfcmVzdWx0cy5jc3YnLCAiaWhjX3RhYmxlIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9paGNfdGFibGUudHN2JywgImRiIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvbWV0YWRhdGEvZGIvaW1tdW5lX3Byb2plY3Quc3FsaXRlMycsICJrbm93bl9zdWJ0eXBlc19hcnJheSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2RhdGEvZXhwcmVzc2lvbi9hcnJheS9zdWJ0eXBlcy9rbm93bl9zdWJ0eXBlcy50c3YnLCAidGlsY2x1c3Rlcl9zdXBlcnZpc2VkX2lweW5iIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmV2aWV3L2lweS90aWxjbHVzdGVyX3N1cGVydmlzZWRtdWx0aWNsYXNzLmlweW5iJywgInRjZ2FfcGFwZXJfc3VidHlwZXNfcmF3IiA9ICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvVENHQS9UQ0dBXzQ4OV9VRS5rNC50eHQnLCAibmVvZWRpdGluZ19vdXRkaXIiID0gJy9zaGFobGFiL2FsemhhbmcvcGlwZWxpbmVfb3V0cHV0cy9pdGhfaW1tdW5lL25lb2VkaXRpbmcvcnVuNicsICJjbG9uZV90cmVlcyIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvY2xvbmVzL3RyZWVfZGF0YS50c3YnLCAidGNnYV9wYXBlcl9zdWJ0eXBlc19wb3NzaWxob3VldHRlIiA9ICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvVENHQS9UQ0dBXzQ4OV9VRS5rNC5wb3NTaWxob3VldHRlLnR4dCcsICJ0aWxzX2Zvcl92YXJpYWJpbGl0eSIgPSBjKCdUX0NEOF9kZW5zaXR5JywgJ1RfQ0Q0X2RlbnNpdHknLCAnVF9DRDIwX2RlbnNpdHknLCAnVF9QbGFzbWFfZGVuc2l0eScpLCAidGlsX2NsdXN0ZXJzX291dHB1dCIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvaW50ZXJtZWRpYXRlcy9ydW4yL3RpbF9jbHVzdGVyc19vdXRwdXQudHh0JywgImljZ2Nfc3BlY2ltZW4iID0gJy9zaGFobGFiL2FsemhhbmcvZGF0YS9JQ0dDL3NwZWNpbWVuLnRzdicsICJpY2djX3N1YnR5cGVzIiA9ICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvSUNHQy9pY2djX3ByaW1hcnlfdHVtb3VyX3N1YnR5cGVzLnRzdicsICJuYW5vc3RyaW5nX2RhdGEiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9yZXN1bHRzL25hbm9zdHJpbmdfcmVzdWx0cy9pdGhfZnVsbC9xYy9saW1tYV9xdWFudGlsZS9ub3JtYWxpemVkX2V4cHJlc3Npb25fdm9hX2xhYmVsc19maWx0ZXJlZC50c3YnLCAidmFyaWFiaWxpdHlfdHlwZSIgPSAnc3RhYmlsaXplJyksCiAgICBydWxlID0gJ2xvaGhsYV9leHRlcm5hbF9hbmFseXNpcycKKQojIyMjIyMjIyBPcmlnaW5hbCBzY3JpcHQgIyMjIyMjIyMjCgogICAgICAgICAgICAgICAgICAgICAgICBgYGAKCgojIyBTZXR1cAoKYGBge3IgZ2xvYmFsX2NodW5rX29wdGlvbnMsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgdGlkeT1UUlVFLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBjYWNoZT1UUlVFKSAjY2FjaGU9VFJVRQpgYGAKCmBgYHtyfQpsaWJyYXJ5KGl0aGkudXRpbHMpCmxvYWRfYmFzZV9saWJzKCkKbGlicmFyeShpdGhpLm1ldGEpCmxpYnJhcnkoaXRoaS5maWd1cmVzKQpsaWJyYXJ5KGl0aGkuZXhwcikKbGlicmFyeShpdGhpLmV4dGVybmFsKQpsaWJyYXJ5KGl0aGkubG9oaGxhKQpgYGAKCmBgYHtyfQpsb2hobGFfaWNnY19vdXRkaXIgPC0gc25ha2VtYWtlQGlucHV0JGxvaGhsYV9pY2djX291dGRpcgppdGhfaWNnY19iY19maWxlIDwtIHNuYWtlbWFrZUBpbnB1dCRpdGhfaWNnY19iYwppY2djX3NwZWNpbWVuX2ZpbGUgPC0gc25ha2VtYWtlQGlucHV0JGljZ2Nfc3BlY2ltZW4KbmFub3N0cmluZ19hbm5vdGF0aW9uc19wYXRoIDwtIHNuYWtlbWFrZUBpbnB1dCRuYW5vc3RyaW5nX2Fubm90YXRpb25zCmljZ2Nfc3VidHlwZV9maWxlIDwtIHNuYWtlbWFrZUBpbnB1dCRpY2djX3N1YnR5cGVzCmljZ2NfZXhwcl9tYXRfZmlsZSA8LSBzbmFrZW1ha2VAaW5wdXQkaWNnY19leHByX21hdAoKbG9oaGxhX3RjZ2Ffb3V0ZGlyIDwtIHNuYWtlbWFrZUBpbnB1dCRsb2hobGFfdGNnYV9vdXRkaXIKdGNnYV9vdl9hbm5vdGF0aW9uX2ZpbGUgPC0gc25ha2VtYWtlQGlucHV0JHRjZ2Ffb3ZfYW5ub3RhdGlvbnMKbm1mX3N1YnR5cGVfZmlsZSA8LSBzbmFrZW1ha2VAaW5wdXQkYXJyYXlfbm1mX3N1YnR5cGVzCnRjZ2FfcGFwZXJfc3VidHlwZV9maWxlIDwtIHNuYWtlbWFrZUBpbnB1dCR0Y2dhX3BhcGVyX3N1YnR5cGVzX3Jhdwp0Y2dhX3BhcGVyX3NpbGhvdWV0dGVfZmlsZSA8LSBzbmFrZW1ha2VAaW5wdXQkdGNnYV9wYXBlcl9zdWJ0eXBlc19wb3NzaWxob3VldHRlCnRjZ2Ffb3ZfYmFtX2RpciA8LSBzbmFrZW1ha2VAaW5wdXQkdGNnYV9vdl9iYW1fZGlyCnRjZ2Ffbm9uc3RkX2V4cHJfbWF0X2ZpbGUgPC0gc25ha2VtYWtlQGlucHV0JHRjZ2Ffbm9uc3RkX2V4cHIKCmRiX3BhdGggPC0gc25ha2VtYWtlQHBhcmFtcyRkYgpzdXBwb3J0aXZlX3NpdGVfdGhyZXNob2xkIDwtIGFzLm51bWVyaWMoc25ha2VtYWtlQHBhcmFtcyRsb2hobGFfc3VwcG9ydGl2ZV9zaXRlX3RocmVzaG9sZCkKbWlzbWF0Y2hfc2l0ZV90aHJlc2hvbGQgPC0gYXMubnVtZXJpYyhzbmFrZW1ha2VAcGFyYW1zJGxvaGhsYV9taXNtYXRjaF9zaXRlX3RocmVzaG9sZCkKYGBgCgpgYGB7cn0KaWNnY19zcGVjaW1lbiA8LSBmcmVhZChpY2djX3NwZWNpbWVuX2ZpbGUpCml0aF9pY2djX2JjIDwtIGZyZWFkKGl0aF9pY2djX2JjX2ZpbGUpCmljZ2Nfc3VidHlwZXMgPC0gZnJlYWQoaWNnY19zdWJ0eXBlX2ZpbGUpCmljZ2NfZXhwcl9tYXQgPC0gZnJlYWQoaWNnY19leHByX21hdF9maWxlKQoKbm1mX3N1YnR5cGVzIDwtIHJlYWRfdGNnYV9ubWZfc3VidHlwZXMobm1mX3N1YnR5cGVfZmlsZSkKdGNnYV9wYXBlcl9zdWJ0eXBlcyA8LSByZWFkX3RjZ2FfcGFwZXJfc3VidHlwZXModGNnYV9wYXBlcl9zdWJ0eXBlX2ZpbGUsIHRjZ2FfcGFwZXJfc2lsaG91ZXR0ZV9maWxlKQp0Y2dhX25vbnN0ZF9leHByX21hdCA8LSBmcmVhZCh0Y2dhX25vbnN0ZF9leHByX21hdF9maWxlKQp0Y2dhX292X2Fubm90YXRpb25zIDwtIGZyZWFkKHRjZ2Ffb3ZfYW5ub3RhdGlvbl9maWxlKQoKbmFub3N0cmluZ19sYWJlbHMgPC0gZnJlYWQobmFub3N0cmluZ19hbm5vdGF0aW9uc19wYXRoKQpuYW5vc3RyaW5nX2xhYmVsc19tb2RpZmllZCA8LSByZWFkX25hbm9zdHJpbmdfbGFiZWxzX21vZGlmaWVkKG5hbm9zdHJpbmdfYW5ub3RhdGlvbnNfcGF0aCkKCnRjZ2FfYmFtX21hbmlmZXN0IDwtIGNyZWF0ZV9iYW1fbWFuaWZlc3QodGNnYV9vdl9iYW1fZGlyLCB1Y2VjX2Zvcm1hdCA9IEZBTFNFLCBsb2NhbCA9IEZBTFNFKQpgYGAKCgpIZXJlIHdlJ3JlIGdvaW5nIHRvIHJ1biBMT0hITEEgb24gSUNHQyBhbmQgVENHQS4gCgpBIGZldyB0aGluZ3MgdG8gbm90ZToKCiogSUNHQyBpcyBsb3dlciBzZXF1ZW5jaW5nIGRlcHRoCiogVENHQS1PViB3YXMgdGhlIGVhcmxpZXN0IFRDR0Egc3R1ZHkgYW5kIGlzIG5vdCBhcyBoaWdoLXF1YWxpdHkgYXMgdGhlIHN0dWRpZXMgYWZ0ZXIgaXQgLS0gY29tcGFyaXNvbnMgbWF5IG5lZWQgdG8gYmUgdGFrZW4gd2l0aCBhIHBpbmNoIG9mIHNhbHQKCiMjIElDR0MKCmBgYHtyfQppY2djX2hsYWxvc3NfdGFibGUgPC0gZXh0cmFjdF9sb2hobGFfdGFibGUobG9oaGxhX2ljZ2Nfb3V0ZGlyKQpgYGAKCmBgYHtyfQppY2djX2xvc3NfdGFibGUgPC0gY29uc3RydWN0X2xvc3NfdGFibGUoaWNnY19obGFsb3NzX3RhYmxlLCB0eXBlID0gIklDR0MiLCBzdXBwb3J0aXZlX3NpdGVfdGhyZXNob2xkID0gc3VwcG9ydGl2ZV9zaXRlX3RocmVzaG9sZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pc21hdGNoX3NpdGVfdGhyZXNob2xkID0gbWlzbWF0Y2hfc2l0ZV90aHJlc2hvbGQpCmljZ2NfbG9zc19zdW1tYXJpemVkIDwtIHN1bW1hcml6ZV9sb3NzX3RhYmxlKGljZ2NfbG9zc190YWJsZSwgdHlwZSA9ICJJQ0dDIikKYGBgCgpgYGB7cn0KdGFibGUoaWNnY19sb3NzX3N1bW1hcml6ZWQkbG9oKQpgYGAKCiMjIyB2cy4gTW9sZWN1bGFyIHN1YnR5cGVzCgpgYGB7cn0KaWNnY19sb3NzX3N1bW1hcml6ZWRfc3VidHlwZXMgPC0gbWVyZ2UoaWNnY19sb3NzX3N1bW1hcml6ZWQsIGljZ2Nfc3VidHlwZXMsIGJ5LnggPSBjKCJzYW1wbGVfa2V5IiksIGJ5LnkgPSBjKCJpY2djX2Rvbm9yX2lkIikpCgp3aXRoKGljZ2NfbG9zc19zdW1tYXJpemVkX3N1YnR5cGVzLCB0YWJsZShsb2gsIHN1YnR5cGUpKQoKd2l0aChpY2djX2xvc3Nfc3VtbWFyaXplZF9zdWJ0eXBlcywgdGFibGUobG9oLCBubWZfc3VidHlwZSkpCgpmaXNoZXIudGVzdCh3aXRoKGljZ2NfbG9zc19zdW1tYXJpemVkX3N1YnR5cGVzLCB0YWJsZShsb2gsIG5tZl9zdWJ0eXBlICVpbiUgYygiQzEiLCAiQzIiKSkpKQpgYGAKCiMjIyMgTWlzc2luZyBzYW1wbGVzCgpgYGB7cn0Kc3Vic2V0KGljZ2Nfc3VidHlwZXMsIGljZ2NfZG9ub3JfaWQgJWluJSBjKCJETzQ2Mzg4IiwgIkRPNDYzOTAiLCAiRE80NjU3MSIpKQpgYGAKClRoZSBvdGhlciA0IHNhbXBsZXMgaGF2ZSBubyBzdWl0YWJsZSBITEEgYWxsZWxlcyAoaS5lLiB0aGV5J3JlIGhvbW96eWdvdXMgYXQgYWxsIDMgSExBIGxvY2kpLiBUaGVzZSAzIHNhbXBsZXMgaGFkIHRoZSBlcnJvciB0aGF0IGlzIGR1ZSB0byBubyByZWFkcyBtYXBwaW5nIHRvIG9uZSBvZiB0aGUgYWxsZWxlcy4gSWYgdGhlc2Ugc2FtcGxlcyBhcmUgdHJ1ZSAnTE9IJywgdGhlaXIgbW9sZWN1bGFyIHN1YnR5cGUgYXNzaWdubWVudHMgYXJlIG5vdCBzdXJwcmlzaW5nIGluIGxpZ2h0IG9mIHRoZSBwcmV2aW91cyByZXN1bHRzIC0tIDIvMyBhcmUgQzEgc2FtcGxlcywgYnkgZWl0aGVyIGNsYXNzaWZpY2F0aW9uLiAKCiMjIyB2cy4gRXhwcmVzc2lvbiBwYXR0ZXJucwoKIyMjIyBCYXRjaCBjb3JyZWN0ZWQgZmlsZSB3aXRoIG91ciBjb2hvcnQKCmBgYHtyfQppY2djX3BhdGh3YXlfbWF0cml4IDwtIGl0aGkuZXhwcjo6Y3JlYXRlX3BhdGh3YXlfbWF0cml4KGl0aF9pY2djX2JjLCBuYW5vc3RyaW5nX2xhYmVscywgZGJfcGF0aCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnZlcnRfaWRzID0gRkFMU0UsIHN1bW1hcnlfbWV0aG9kID0gImFyaXRobWV0aWNfbWVhbiIpCgppY2djX3BhdGh3YXlfbWF0cml4X3N1bW1hcml6ZWQgPC0gc3VtbWFyaXplX2V4cHJlc3Npb25fYnlfcGF0aWVudChpY2djX3BhdGh3YXlfbWF0cml4LCBpY2djX3NwZWNpbWVuKQoKaWNnY19wYXRod2F5X2RmIDwtIGljZ2NfcGF0aHdheV9tYXRyaXhfc3VtbWFyaXplZCAlPiUgdGliYmxlOjpjb2x1bW5fdG9fcm93bmFtZXModmFyID0gIk5hbWUiKSAlPiUgYXMubWF0cml4ICU+JSBtZWx0ICU+JQogIHBseXI6OnJlbmFtZShjKCdWYXIxJz0ncGF0aHdheScsICdWYXIyJz0nc2FtcGxlX2tleScsICd2YWx1ZSc9J21lYW5fZXhwcicpKQpgYGAKCmBgYHtyfQppY2djX2xvc3Nfc3VtbWFyaXplZF9leHByIDwtIG1lcmdlKGljZ2NfbG9zc19zdW1tYXJpemVkLCBpY2djX3BhdGh3YXlfZGYpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQgPSAxMiwgZmlnLndpZHRoID0gN30KZGYgPC0gaWNnY19sb3NzX3N1bW1hcml6ZWRfZXhwciMgJT4lIHN1YnNldChwYXRod2F5ICVpbiUgYygiVC1DZWxsIEZ1bmN0aW9ucyIsICJCLUNlbGwgRnVuY3Rpb25zIiwgIkN5dG90b3hpY2l0eSIpKQoKcHZhbHMgPC0gY29tcHV0ZV9wdmFsc19zdWJzZXRzKGRmLCBmYWNldF92YXJzID0gYygicGF0aHdheSIpLCBjb3JmdW4gPSB3aWxjb3gudGVzdCwgZm9ybXVsYSA9IG1lYW5fZXhwciB+IGxvaCkKCmdncGxvdChkZiwgYWVzKHg9bG9oLCB5ID0gbWVhbl9leHByKSkgKyBnZW9tX2JveHBsb3Qob3V0bGllci5zaXplID0gLTEpICsgZ2VvbV9qaXR0ZXIocG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIod2lkdGggPSAwLjIsIGhlaWdodCA9IDApLCBhbHBoYSA9IDAuNSkgKwogIHRoZW1lX2J3KCkgKyBmYWNldF93cmFwKH4gcGF0aHdheSwgc2NhbGVzID0gImZyZWUiLCBuY29sID0gMykgKyAKICB0aGVtZV9QdWJsaWNhdGlvbigpICsgdGhlbWVfbmF0dXJlKCkgKyBnZW9tX3RleHQoZGF0YT1wdmFscywgYWVzKHg9SW5mLCB5PUluZiwgbGFiZWw9cC52YWx1ZS50ZXh0KSwgaGp1c3Q9MS4xLCB2anVzdD0xLjUsc2l6ZT0yLjUscGFyc2U9VFJVRSkKYGBgCgoKV2UgY2FuIHNlZSBhIHRyZW5kLCBidXQgaXQncyBub3Qgc2lnbmlmaWNhbnQgLS0gbGlrZWx5IGR1ZSB0byBzYW1wbGUgc2l6ZSAoc2VlIGZpcnN0IHNlY3Rpb24gZm9yIHNhbXBsZSBzaXplIG51bWJlcnMpLiAKClNvIHdlIHNlZSBhIHRlbmRlbmN5IHRvd2FyZHMgaGlnaGVyIFQtY2VsbC1hc3NvY2lhdGVkIGdlbmUgZXhwcmVzc2lvbiBhbW9uZyBzYW1wbGVzIHdpdGggTE9ISExBLCB0aG91Z2ggdGhpcyBpcyBub3Qgc2lnbmlmaWNhbnQuIAoKCiMjIFRDR0EKCkF0IHRoZSBtb21lbnQgSSdtIG9ubHkgdXNpbmcgdGhvc2Ugc2FtcGxlcyBmb3Igd2hpY2ggd2UgaGF2ZSBwbG9pZHkvY2VsbHVsYXJpdHkgcHJlZGljdGlvbnMgZnJvbSBBU0NBVCBmcm9tIE5pY29sYWkgQmlya2JhayAtLSB0aGF0IHdhcyBmcm9tIGFuIG9sZGVyIHZlcnNpb24gb2YgQVNDQVQsIGV0Yy4gCgpJIHN0aWxsIGhhdmUgdG8gcnVuIHRoZSBuZXdlciBBU0NBVCBwaXBlbGluZSAtLSByYW4gaW50byBhIGZldyBwcm9ibGVtcyB3aXRoIHRpbWUgZWFybGllciB0aGF0IEknbGwgcHJvYmFibHkgaGF2ZSB0byByZXNvbHZlIGJ5IG1ha2luZyB0aGUgQVNDQVQgcGFja2FnZSBtb3JlIGVmZmljaWVudC4gR290IGhhbGZ3YXkgdGhyb3VnaCB0aGlzIHRoZW4gZ290IHNpZGV0cmFja2VkIGJ5IG90aGVyIGFuYWx5c2lzIC4uLgoKU28gdGhlc2UgcmVzdWx0cyBhcmUgcmVhbGx5IG9uIGFib3V0IDIvMyB0byAzLzQgb2YgdGhlIFRDR0EtT1YgY29ob3J0LiAKCmBgYHtyfQp0Y2dhX2hsYWxvc3NfdGFibGUgPC0gZXh0cmFjdF9sb2hobGFfdGFibGUobG9oaGxhX3RjZ2Ffb3V0ZGlyKQp0Y2dhX2hsYWxvc3NfdGFibGUkdGNnYV9zYW1wbGVfaWQgPC0gc3RyaW5ncjo6c3RyX2V4dHJhY3QodGNnYV9obGFsb3NzX3RhYmxlJHJlZ2lvbiwgIlRDR0FcXC1bMC05QS1aXXsyfVxcLVswLTlBLVpdezR9IikKdGNnYV9obGFsb3NzX3RhYmxlJGFuYWx5dGVfdHlwZSA8LSBzdHJpbmdyOjpzdHJfZXh0cmFjdCh0Y2dhX2hsYWxvc3NfdGFibGUkcmVnaW9uLCAiKD88PVRDR0FcXC1bMC05QS1aXXsyfVxcLVswLTlBLVpdezR9XFwtWzAtOUEtWl17M31cXC1bMC05QS1aXXsyfSlbQS1aXSIpCiN0Y2dhX2hsYWxvc3NfdGFibGUgPC0gc3Vic2V0KHRjZ2FfaGxhbG9zc190YWJsZSwgYW5hbHl0ZV90eXBlID09ICJEIikKYGBgCgpgYGB7cn0KaGlzdCh0Y2dhX2hsYWxvc3NfdGFibGUkSExBX3R5cGUxY29weU51bV93aXRoQkFGLCBicmVha3MgPSAzMCkKaGlzdCh0Y2dhX2hsYWxvc3NfdGFibGUkSExBX3R5cGUyY29weU51bV93aXRoQkFGLCBicmVha3MgPSAzMCkKYGBgCgojIyMgUHJldmFsZW5jZSBvZiBITEEgbG9zcwoKIyMjIyBCeSBzYW1wbGUga2V5CgpgYGB7cn0KdGNnYV9sb3NzX3RhYmxlIDwtIGNvbnN0cnVjdF9sb3NzX3RhYmxlKHRjZ2FfaGxhbG9zc190YWJsZSwgdHlwZSA9ICJUQ0dBIiwgc3VwcG9ydGl2ZV9zaXRlX3RocmVzaG9sZCA9IHN1cHBvcnRpdmVfc2l0ZV90aHJlc2hvbGQsIG1pc21hdGNoX3NpdGVfdGhyZXNob2xkID0gbWlzbWF0Y2hfc2l0ZV90aHJlc2hvbGQpCm1heF9wbGF0ZSA8LSB0Y2dhX2xvc3NfdGFibGUgJT4lIGdyb3VwX2J5KHRjZ2Ffc2FtcGxlX2lkKSAlPiUgc3VtbWFyaXNlKG1heF9wbGF0ZT1tYXgoYXMubnVtZXJpYyhwbGF0ZSkpKQp0Y2dhX2xvc3NfdGFibGUgPC0gdGNnYV9sb3NzX3RhYmxlICU+JSBwbHlyOjpqb2luKG1heF9wbGF0ZSkKdGNnYV9sb3NzX3RhYmxlIDwtIHN1YnNldCh0Y2dhX2xvc3NfdGFibGUsIGFzLm51bWVyaWMocGxhdGUpID09IG1heF9wbGF0ZSkKCnRjZ2FfbG9zc19zdW1tYXJpemVkIDwtIHN1bW1hcml6ZV9sb3NzX3RhYmxlKHRjZ2FfbG9zc190YWJsZSwgdHlwZSA9ICJUQ0dBIikKYGBgCgojIyMgQ29tcGFyaXNvbiB3aXRoIG1vbGVjdWxhciBzdWJ0eXBlcwoKYGBge3J9CnRjZ2FfbWFuaWZlc3RfZGF0YSA8LSB0Y2dhX2JhbV9tYW5pZmVzdCAlPiUgc3Vic2V0KHNwZWNpbWVuX3R5cGUgPT0gImRpc2Vhc2VkIiwgc2VsZWN0PWMoY2VudGVyLCBwYXRpZW50LCBiYXJjb2RlLCBzYW1wbGVfa2V5LCBzaG9ydF9iYXJjb2RlKSkKCm5tZl9zdWJ0eXBlc19tZXJnZWQgPC0gUmVkdWNlKGZ1bmN0aW9uKHgseSkgcGx5cjo6am9pbih4LHksdHlwZT0nZnVsbCcpLCBsaXN0KAogIG5tZl9zdWJ0eXBlcywKICB0Y2dhX21hbmlmZXN0X2RhdGEsCiAgdGNnYV9wYXBlcl9zdWJ0eXBlcwopKSAlPiUgcGx5cjo6cmVuYW1lKGMoJ3N1YnR5cGUnPSdubWZfc3VidHlwZScsICdzZWNvbmRhcnknPSdubWZfc2Vjb25kYXJ5X3N1YnR5cGUnKSkgJT4lIHN1YnNldChzZWxlY3Q9LWModGNnYV9zYW1wbGVfaWQpKQojbm1mX3N1YnR5cGVzX21lcmdlZF9ub2R1cGxpY2F0ZXMgPC0gbm1mX3N1YnR5cGVzX21lcmdlZFshZHVwbGljYXRlZChubWZfc3VidHlwZXNfbWVyZ2VkJHNob3J0X2JhcmNvZGUpLF0Kbm1mX3N1YnR5cGVzX21lcmdlZCR0Y2dhX3NhbXBsZV9pZCA8LSBubWZfc3VidHlwZXNfbWVyZ2VkJHBhdGllbnQKbm1mX3N1YnR5cGVzX21lcmdlZF9ub2R1cGxpY2F0ZXMgPC0gbm1mX3N1YnR5cGVzX21lcmdlZApubWZfc3VidHlwZXNfbWVyZ2VkX25vZHVwbGljYXRlcyA8LSBzdWJzZXQobm1mX3N1YnR5cGVzX21lcmdlZF9ub2R1cGxpY2F0ZXMsICFpcy5uYShzYW1wbGVfa2V5KSkgJT4lIHN1YnNldChzZWxlY3Q9LWMoYmFyY29kZSwgc2FtcGxlX2tleSwgY2VudGVyKSkgJT4lIHVuaXF1ZQpubWZfc3VidHlwZXNfbWVyZ2VkX25vZHVwbGljYXRlcyA8LSBubWZfc3VidHlwZXNfbWVyZ2VkX25vZHVwbGljYXRlc1shZHVwbGljYXRlZChubWZfc3VidHlwZXNfbWVyZ2VkX25vZHVwbGljYXRlcyRwYXRpZW50KSxdCmBgYAoKYGBge3J9CnRjZ2FfbG9zc19zdW1tYXJpemVkJGFuYWx5c2lzX2NlbnRlciA8LSBzdHJfZXh0cmFjdCh0Y2dhX2xvc3Nfc3VtbWFyaXplZCRzYW1wbGVfa2V5LCAiKE5vblxcLSk/QnJvYWQiKQoKdGNnYV9sb3NzX2Fubm90YXRlZCA8LSBSZWR1Y2UoZnVuY3Rpb24oeCx5KSBwbHlyOjpqb2luKHgsIHksIHR5cGUgPSAnZnVsbCcpLCBsaXN0KHRjZ2FfbG9zc19zdW1tYXJpemVkICU+JSBhcy5kYXRhLmZyYW1lLCB0Y2dhX292X2Fubm90YXRpb25zLCBubWZfc3VidHlwZXNfbWVyZ2VkX25vZHVwbGljYXRlcykpCmBgYAoKIyMjIyBTdWJ0eXBlcyBmcm9tIFlpa2FuJ3MgdGFibGUKCmBgYHtyfQp3aXRoKHRjZ2FfbG9zc19hbm5vdGF0ZWQsIHRhYmxlKE1vbGVjdWxhclN1YnR5cGUsIGxvc3MpKQoKd2l0aCh0Y2dhX2xvc3NfYW5ub3RhdGVkLCB0YWJsZShNb2xlY3VsYXJTdWJ0eXBlLCBsb3NzKSkvcm93U3Vtcyh3aXRoKHRjZ2FfbG9zc19hbm5vdGF0ZWQsIHRhYmxlKE1vbGVjdWxhclN1YnR5cGUsIGxvc3MpKSkKCmZpc2hlci50ZXN0KHdpdGgodGNnYV9sb3NzX2Fubm90YXRlZCwgdGFibGUoTW9sZWN1bGFyU3VidHlwZSAlaW4lIGMoIkltbXVub3JlYWN0aXZlIiwgIk1lc2VuY2h5bWFsIiksIGxvc3MpKSkKYGBgCgpgYGB7cn0Kd2l0aCh0Y2dhX2xvc3NfYW5ub3RhdGVkLCB0YWJsZShNb2xlY3VsYXJTdWJ0eXBlLCBsb2gpKQoKd2l0aCh0Y2dhX2xvc3NfYW5ub3RhdGVkLCB0YWJsZShNb2xlY3VsYXJTdWJ0eXBlLCBsb2gpKS9yb3dTdW1zKHdpdGgodGNnYV9sb3NzX2Fubm90YXRlZCwgdGFibGUoTW9sZWN1bGFyU3VidHlwZSwgbG9oKSkpCmBgYAoKCiMjIyMgTk1GLWluZmVycmVkIHN1YnR5cGVzCgpgYGB7cn0KIyMgTm90IHRlY2huaWNhbGx5IGEgcHJpbWFyeSBzaXRlIGZpbHRlciBoZXJlIC0tIHRoaXMgaXMganVzdCBhIHNpbXBsZSBXYW5nIGV0IGFsLiBmaWx0ZXIKZmlsdGVyX3ByaW1hcnkgPC0gRkFMU0UKCmRhdCA8LSB0Y2dhX2xvc3NfYW5ub3RhdGVkCgppZiAoZmlsdGVyX3ByaW1hcnkpIHsKICBkYXQgPC0gZGF0ICU+JSBzdWJzZXQoIWlzLm5hKE1vbGVjdWxhclN1YnR5cGUpKQp9CmBgYAoKYGBge3J9CndpdGgoZGF0LCB0YWJsZShubWZfc3VidHlwZSwgbG9zcykpCgp3aXRoKGRhdCwgdGFibGUobm1mX3N1YnR5cGUsIGxvc3MpKS9yb3dTdW1zKHdpdGgoZGF0LCB0YWJsZShubWZfc3VidHlwZSwgbG9zcykpKQpgYGAKCmBgYHtyfQp3aXRoKGRhdCwgdGFibGUobm1mX3N1YnR5cGUsIGxvaCkpCgp3aXRoKGRhdCwgdGFibGUobm1mX3N1YnR5cGUsIGxvaCkpL3Jvd1N1bXMod2l0aChkYXQsIHRhYmxlKG5tZl9zdWJ0eXBlLCBsb2gpKSkKYGBgCgpgYGB7cn0Kd2l0aChkYXQgJT4lIHN1YnNldChzaWxfd2lkdGggPiAwKSwgdGFibGUobm1mX3N1YnR5cGUsIGxvc3MpKQoKd2l0aChkYXQgJT4lIHN1YnNldChzaWxfd2lkdGggPiAwKSwgdGFibGUobm1mX3N1YnR5cGUsIGxvc3MpKS9yb3dTdW1zKHdpdGgoZGF0ICU+JSBzdWJzZXQoc2lsX3dpZHRoID4gMCksIHRhYmxlKG5tZl9zdWJ0eXBlLCBsb3NzKSkpCmBgYAoKYGBge3J9CndpdGgoZGF0ICU+JSBzdWJzZXQoc2lsX3dpZHRoID4gMCksIHRhYmxlKG5tZl9zdWJ0eXBlLCBsb2gpKQoKd2l0aChkYXQgJT4lIHN1YnNldChzaWxfd2lkdGggPiAwKSwgdGFibGUobm1mX3N1YnR5cGUsIGxvaCkpL3Jvd1N1bXMod2l0aChkYXQgJT4lIHN1YnNldChzaWxfd2lkdGggPiAwKSwgdGFibGUobm1mX3N1YnR5cGUsIGxvaCkpKQpgYGAKCiMjIyBFeHByZXNzaW9uIGRpZmZlcmVuY2VzIGJldHdlZW4gTk1GLWFubm90YXRlZCBzdWJ0eXBlcwoKYGBge3J9CnRjZ2Ffbm9uc3RkX2V4cHJfZGYgPC0gdGNnYV9ub25zdGRfZXhwcl9tYXQgJT4lIGFzLmRhdGEuZnJhbWUgJT4lIHRpYmJsZTo6Y29sdW1uX3RvX3Jvd25hbWVzKCJ0Y2dhX3NhbXBsZV9pZCIpICU+JSB0ICU+JSBhcy5kYXRhLmZyYW1lICU+JSB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigiTmFtZSIpCnRjZ2FfcGF0aHdheV9tYXRyaXhfYW1lYW4gPC0gaXRoaS5leHByOjpjcmVhdGVfcGF0aHdheV9tYXRyaXgodGNnYV9ub25zdGRfZXhwcl9kZiwgbmFub3N0cmluZ19sYWJlbHNfbW9kaWZpZWQsIGRiX3BhdGgsIGNvbnZlcnRfaWRzID0gRkFMU0UsIHN1bW1hcnlfbWV0aG9kID0gImFyaXRobWV0aWNfbWVhbiIpCnRjZ2FfcGF0aHdheV9tYXRyaXhfZ21lYW4gPC0gaXRoaS5leHByOjpjcmVhdGVfcGF0aHdheV9tYXRyaXgodGNnYV9ub25zdGRfZXhwcl9kZiwgbmFub3N0cmluZ19sYWJlbHNfbW9kaWZpZWQsIGRiX3BhdGgsIGNvbnZlcnRfaWRzID0gRkFMU0UsIHN1bW1hcnlfbWV0aG9kID0gImdlb21ldHJpY19tZWFuIikKCnRjZ2FfcGF0aHdheV9tYXRyaXhfbmFubyA8LSB0Y2dhX3BhdGh3YXlfbWF0cml4X2FtZWFuW3NldGRpZmYocm93bmFtZXModGNnYV9wYXRod2F5X21hdHJpeF9hbWVhbiksICJSb29uZXlfQ3l0b3RveGljaXR5IiksXQp0Y2dhX3BhdGh3YXlfbWF0cml4X3Jvb25leSA8LSB0Y2dhX3BhdGh3YXlfbWF0cml4X2dtZWFuWyJSb29uZXlfQ3l0b3RveGljaXR5IiwsZHJvcD1GQUxTRV0KCnRjZ2FfcGF0aHdheV9tYXRyaXggPC0gcmJpbmQodGNnYV9wYXRod2F5X21hdHJpeF9uYW5vLCB0Y2dhX3BhdGh3YXlfbWF0cml4X3Jvb25leSkKCnRjZ2FfcGF0aHdheV9kZiA8LSB0Y2dhX3BhdGh3YXlfbWF0cml4ICU+JSBhcy5tYXRyaXggJT4lIG1lbHQgJT4lIHBseXI6OnJlbmFtZShjKCdWYXIyJz0nc2hvcnRfYmFyY29kZScsICdWYXIxJz0ncGF0aHdheScsICd2YWx1ZSc9J2V4cHInKSkKYGBgCgoKYGBge3J9CnRjZ2FfcGF0aHdheV9kZl9hbm5vdGF0ZWQgPC0gcGx5cjo6am9pbih0Y2dhX3BhdGh3YXlfZGYsIG5tZl9zdWJ0eXBlc19tZXJnZWRfbm9kdXBsaWNhdGVzKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTIsIGZpZy53aWR0aCA9IDV9CnAgPC0gZ2dwbG90KHRjZ2FfcGF0aHdheV9kZl9hbm5vdGF0ZWQsIGFlcyh4PW5tZl9zdWJ0eXBlLCB5ID0gZXhwcikpICsgZ2VvbV9ib3hwbG90KCkgKyB0aGVtZV9idygpICsgdGhlbWVfUHVibGljYXRpb24oKSArIHRoZW1lX25hdHVyZSgpICsgZmFjZXRfd3JhcCh+IHBhdGh3YXksIHNjYWxlcyA9ICJmcmVlIiwgbmNvbCA9IDIpCgpwCmBgYAoKQzUgaXMgY2xlYXJseSB0aGUgbG93ZXN0LCBiZWxvdyBDNC4gCgojIyMgRXhwcmVzc2lvbiBkaWZmZXJlbmNlIGJldHdlZW4gTE9IIGFuZCBub24tTE9IIHNhbXBsZXMKCmBgYHtyfQp0Y2dhX3BhdGh3YXlfbG9zcyA8LSB0Y2dhX3BhdGh3YXlfZGZfYW5ub3RhdGVkICU+JSBhcy5kYXRhLmZyYW1lICU+JSBwbHlyOjpqb2luKHRjZ2FfbG9zc19hbm5vdGF0ZWQpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQgPSAxOCwgZmlnLndpZHRoID0gNX0KZGYgPC0gdGNnYV9wYXRod2F5X2xvc3MgJT4lIHN1YnNldCghaXMubmEobG9oKSkKZGYkY2VudGVyIDwtIHN0cl9leHRyYWN0KGRmJHRjZ2Ffc2FtcGxlX2lkLCAiKD88PVxcLSlbMC05QS1aXXsyfSg/PVxcLSkiKQoKcHZhbHMgPC0gaXRoaS51dGlsczo6Y29tcHV0ZV9wdmFsc19zdWJzZXRzKGRmLCBmYWNldF92YXJzID0gYygicGF0aHdheSIpLCBmb3JtdWxhID0gZXhwciB+IGxvaCwgY29yZnVuID0gd2lsY294LnRlc3QpCgpwIDwtIGdncGxvdChkZiwgYWVzKHg9bG9oLCB5ID0gZXhwcikpICsgZ2VvbV9ib3hwbG90KCkgKyB0aGVtZV9idygpICsgdGhlbWVfUHVibGljYXRpb24oKSArIHRoZW1lX25hdHVyZSgpICsgZmFjZXRfd3JhcCh+IHBhdGh3YXksIHNjYWxlcyA9ICJmcmVlIiwgbmNvbCA9IDIpICsgZ2VvbV90ZXh0KGRhdGE9cHZhbHMsIGFlcyh4PUluZiwgeT1JbmYsIGxhYmVsPXAudmFsdWUudGV4dCksIGhqdXN0PTEuMSwgdmp1c3Q9MS41LHNpemU9Mi41LHBhcnNlPVRSVUUpIAoKcApgYGAKCkkgYWxzbyBkaWQgdGhpcyB3aXRoIFRDR0EncyBSTkEtc2VxIGRhdGEgaW4gYW5vdGhlciBmaWxlIGFuZCBmb3VuZCBub3RoaW5nLiAKCiMjIyMgQnkgY2VudGVyCgpgYGB7ciwgZmlnLmhlaWdodCA9IDE4LCBmaWcud2lkdGggPSA1fQpkZl9zdWJzZXQgPC0gc3Vic2V0KGRmLCBwYXRod2F5ID09ICJSb29uZXlfQ3l0b3RveGljaXR5IiAmICFpcy5uYShsb2gpICYgIWlzLm5hKGNlbnRlcikpCgpwdmFscyA8LSBpdGhpLnV0aWxzOjpjb21wdXRlX3B2YWxzX3N1YnNldHMoZGZfc3Vic2V0LCBmYWNldF92YXJzID0gYygiY2VudGVyIiksIGZvcm11bGEgPSBleHByIH4gbG9oLCBjb3JmdW4gPSB3aWxjb3gudGVzdCkKCnAgPC0gZ2dwbG90KGRmX3N1YnNldCwgYWVzKHg9bG9oLCB5ID0gZXhwcikpICsgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2l6ZSA9IC0xKSArIGdlb21faml0dGVyKHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyKHdpZHRoID0gMC4yLCBoZWlnaHQgPSAwKSwgYWxwaGEgPSAwLjUpICsgdGhlbWVfYncoKSArIHRoZW1lX1B1YmxpY2F0aW9uKCkgKyB0aGVtZV9uYXR1cmUoKSArIGZhY2V0X3dyYXAofiBjZW50ZXIsIHNjYWxlcyA9ICJmcmVlIiwgbmNvbCA9IDIpICsgZ2VvbV90ZXh0KGRhdGE9cHZhbHMsIGFlcyh4PUluZiwgeT1JbmYsIGxhYmVsPXAudmFsdWUudGV4dCksIGhqdXN0PTEuMSwgdmp1c3Q9MS41LHNpemU9Mi41LHBhcnNlPVRSVUUpCgp0YWJsZShkZl9zdWJzZXQkY2VudGVyKQoKcApgYGAKClRoZSBVUGVubiBjZW50ZXIgc2hvd3Mgc29tZXRoaW5nLCBidXQgdGhlIG90aGVyIDIgYmlnIG9uZXMgLS0gQnJvYWQgYW5kIE1TS0NDIC0tIGRvIG5vdC4gCgojIyMjIFRDR0EtYW5ub3RhdGVkIHN1YnR5cGVzCgpgYGB7cn0Kd2l0aChkYXQgJT4lIHN1YnNldChwYXBlcl9wb3Nfc2lsaG91ZXR0ZSksIHRhYmxlKHRjZ2FfcGFwZXJfc3VidHlwZSwgbG9zcykpCgp3aXRoKGRhdCAlPiUgc3Vic2V0KHBhcGVyX3Bvc19zaWxob3VldHRlKSwgdGFibGUodGNnYV9wYXBlcl9zdWJ0eXBlLCBsb3NzKSkvcm93U3Vtcyh3aXRoKGRhdCAlPiUgc3Vic2V0KHBhcGVyX3Bvc19zaWxob3VldHRlKSwgdGFibGUodGNnYV9wYXBlcl9zdWJ0eXBlLCBsb3NzKSkpCmBgYAoKYGBge3J9CndpdGgoZGF0ICU+JSBzdWJzZXQocGFwZXJfcG9zX3NpbGhvdWV0dGUpLCB0YWJsZSh0Y2dhX3BhcGVyX3N1YnR5cGUsIGxvaCkpCgp3aXRoKGRhdCAlPiUgc3Vic2V0KHBhcGVyX3Bvc19zaWxob3VldHRlKSwgdGFibGUodGNnYV9wYXBlcl9zdWJ0eXBlLCBsb2gpKS9yb3dTdW1zKHdpdGgoZGF0ICU+JSBzdWJzZXQocGFwZXJfcG9zX3NpbGhvdWV0dGUpLCB0YWJsZSh0Y2dhX3BhcGVyX3N1YnR5cGUsIGxvaCkpKQpgYGAKCgojIyMgQ29tcGFyaXNvbiB3aXRoIGZvbGRiYWNrIGludmVyc2lvbi9IUkQgc3VidHlwZXMKCmBgYHtyfQp3aXRoKGRhdCwgdGFibGUoU3ViZ3JvdXAsIGxvc3MpKQpgYGAKCmBgYHtyfQp3aXRoKGRhdCwgdGFibGUoU3ViZ3JvdXAsIGxvaCkpCmBgYAoKTm90IHJlYWxseSBhbnkgZGlmZmVyZW5jZSBiZXR3ZW4gZm9sZGJhY2sgc3Vic2V0cyBpbiB0ZXJtcyBvZiB0aGlzLiAKCgoK