library(ithi.utils)
load_base_libs()

library(ithi.meta)
library(ithi.ihc)

Colour palettes

pal_patient <- select_palette("patient")

Parameters

db_path <- snakemake@params$db

ihc_table_path <- snakemake@input$ihc_table
tils_for_cluster <- unlist(snakemake@params$tils_for_cluster)
nclusts <- as.numeric(snakemake@params$nclusts)

neoediting_outdir <- snakemake@input$neoediting_outdir
epitope_dirs <- list.files(file.path(neoediting_outdir, "epitope_files"), full.names = TRUE)
spectrum_file <- file.path(neoediting_outdir, "background_spectrum", "signatures.txt")

Metadata

id_type <- "condensed_id"

db <- src_sqlite(db_path, create = FALSE)
duplicates <- collect(tbl(db, "duplicates"))

TIL clusters

ihc_table <- fread(ihc_table_path)
ihc_data <- subset(ihc_table, select = c(tils_for_cluster))
valid_rows <- apply(ihc_data, 1, function(x) all(!is.na(x)))

patient_ids <- as.data.frame(subset(ihc_table, select = c(patient_id)))
ihc_data <- as.data.frame(ihc_data[valid_rows, ])

patient_ids <- patient_ids[valid_rows, , drop = FALSE]
patient_ids$patient_id <- factor(patient_ids$patient_id)
colnames(patient_ids) <- "Patient"

rownames(ihc_data) <- rownames(patient_ids) <- as.data.frame(ihc_table)[, id_type][valid_rows]
dat_processed <- t(clip_values(scale(ihc_data)))
rownames(dat_processed) <- mapvalues(rownames(dat_processed), from = c("E_CD8_density", 
    "E_CD4_density", "E_CD20_density", "E_Plasma_density"), to = c("E CD8+", 
    "E CD4+", "E CD20+", "E Plasma"))

p <- pheatmap(dat_processed, clustering_method = "ward.D", annotation_col = patient_ids, 
    annotation_colors = list(Patient = pal_patient), cluster_rows = FALSE, show_colnames = FALSE, 
    legend = TRUE, cellwidth = 10, cellheight = 10, annotation_legend = FALSE)

clusts <- data.frame(cutree(p$tree_col, nclusts))
setDT(clusts, keep.rownames = TRUE)
clusts <- setNames(clusts, c(id_type, "cluster"))

clusts$cluster <- factor(clusts$cluster)
ihc_table_annotated <- merge(ihc_table, clusts, by = c(id_type))

Immunoediting

read_spectrum <- function(f) {
    dat <- fread(f)
    colnames(dat) <- mapvalues(colnames(dat), from = c("mutationseq_trinucleotide_ref", 
        "mutationseq_trinucleotide_alt"), to = c("triref", "trialt"))
    return(dat)
}

read_epitope_files <- function(epitope_files, spectrum) {
    epitopes <- rbind.fill(lapply(epitope_files, function(f) {
        sample_key <- basename(dirname(f))
        vars <- fread(f)
        cbind(sample_key = sample_key, vars)
    }))
    epitopes <- merge(epitopes, spectrum, by = c("trinuc_sig"))
    epitopes$patient_id <- map_id(epitopes$sample_key, from = "condensed_id", 
        to = "patient_id", db_path)
    return(epitopes)
}
spectrum <- read_spectrum(spectrum_file)

silent_epitope_files <- Sys.glob(file.path(epitope_dirs, "silent.tsv"))
nonsynonymous_epitope_files <- Sys.glob(file.path(epitope_dirs, "nonsynonymous.tsv"))
silent_epitopes <- read_epitope_files(silent_epitope_files, spectrum)
silent_dups <- duplicated(subset(silent_epitopes, select = c(sample_key, Chromosome, 
    Start, Reference, Variant)))
silent_epitopes <- silent_epitopes[!silent_dups, ]

nonsynonymous_epitopes <- read_epitope_files(nonsynonymous_epitope_files, spectrum)

Overall, there aren’t any major differences between the fraction of neoepitopes determined from nonsynonymous mutations vs. what would be expected from synonymous mutations. In other words, there is, on average, no immunoediting occurring on neoantigens in HGSC. Do keep in mind this is complicated by the lack of expression data, so we cannot truly confirm which are neoantigens.

sum(silent_epitopes$frac_binder)/nrow(silent_epitopes)
[1] 0.7216169
sum(silent_epitopes$frac_strong_binder)/nrow(silent_epitopes)
[1] 0.3326825
sum(nonsynonymous_epitopes$frac_binder)/nrow(nonsynonymous_epitopes)
[1] 0.71962
sum(nonsynonymous_epitopes$frac_strong_binder)/nrow(nonsynonymous_epitopes)
[1] 0.3303586

Allelic fractions

hist(with(subset(nonsynonymous_epitopes, `NetMHCpan MT Percentile` > 2), alt_counts/(ref_counts + 
    alt_counts)), breaks = 30)

hist(with(subset(nonsynonymous_epitopes, `NetMHCpan MT Percentile` <= 2), alt_counts/(ref_counts + 
    alt_counts)), breaks = 30)

tab1 <- table(subset(nonsynonymous_epitopes, `NetMHCpan MT Percentile` > 2)$is_ancestral)
tab2 <- table(subset(nonsynonymous_epitopes, `NetMHCpan MT Percentile` <= 2)$is_ancestral)
hist(with(silent_epitopes, alt_counts/(ref_counts + alt_counts)), breaks = 30)

fisher.test(rbind(tab1, tab2))

    Fisher's Exact Test for Count Data

data:  rbind(tab1, tab2)
p-value = 0.0101
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
 0.6776465 0.9518279
sample estimates:
odds ratio 
 0.8033361 

What does the peak near 0.5 mean? We might normally expect to see a peak at 0.5 as a result of heterozygosity, for tumours with high purity. Why does it only occur for the silent epitopes? Could it be a result of editing occuring for the nonsynonymous epitopes?

Nevermind, peak at 0.5 is gone. Was due to some really weird variant that had somehow passed my uniqueness filter.

Overall rates

silent_rates <- silent_epitopes %>% group_by(sample_key) %>% summarise(binders = sum(frac_binder), 
    strong_binder = sum(frac_strong_binder), total = n(), spbinder = binders/total, 
    spsbinder = strong_binder/total)
nonsynonymous_rates <- nonsynonymous_epitopes %>% group_by(sample_key) %>% summarise(ntotal = n(), 
    nepitopes = length(which(`NetMHCpan MT Percentile` <= 2)), nstrong = length(which(`NetMHCpan MT Percentile` <= 
        0.5)))


# nonsynonymous_rates <- nonsynonymous_epitopes %>% group_by(sample_key) %>%
# summarise(binders=sum(frac_binder), strong_binder=sum(frac_strong_binder),
# total=n(), npbinder=binders/total, npsbinder=strong_binder/total)

rates <- merge(silent_rates, nonsynonymous_rates, by = c("sample_key"))

rates$pred_epitopes <- with(rates, spbinder * ntotal)
rates$pred_strong <- with(rates, spsbinder * ntotal)

vs. TIL clusters

rates_clusts <- merge(rates, clusts, by.x = c("sample_key"), by.y = c("condensed_id"))

rates_clusts$patient_id <- map_id(rates_clusts$sample_key, from = "condensed_id", 
    to = "patient_id", db_path)
ggplot(rates_clusts, aes(x = cluster, y = nepitopes/pred_epitopes)) + geom_boxplot() + 
    theme_bw() + theme_Publication() + ylab("Observed/expected ratio") + geom_jitter(aes(colour = factor(patient_id)), 
    position = position_jitter(width = 0.2, height = 0)) + scale_color_manual(values = pal_patient)

ggplot(rates_clusts, aes(x = cluster, y = nstrong/pred_strong)) + geom_boxplot() + 
    theme_bw() + theme_Publication() + ylab("Observed/expected ratio")

This doesn’t show a significant correlation. There is a chance we’ll see better results by looking directly at TIL densities though.

vs. TIL densities

rates_ihc <- merge(rates, ihc_table, by.x = "sample_key", by.y = "condensed_id")

Binders

ggplot(rates_ihc, aes(x = E_CD8_density, y = nepitopes/pred_epitopes)) + theme_bw() + 
    theme_Publication() + ylab("Observed/expected ratio") + geom_point(aes(colour = factor(patient_id))) + 
    scale_color_manual(values = pal_patient) + facet_wrap(~patient_id, scales = "free")

From this plot we can see a negative correlation between obs/expected ratio and epithelial CD8+ density for some patients. It’s also apparent that the patients for which we don’t see this correlation are patients with low levels of TILs (so that the values on the x-axis are very tightly spaced). We formulate the following linear mixed model:

mod <- lmer(nepitopes/pred_epitopes ~ E_CD8_density + (1 | patient_id), subset(rates_ihc, 
    !is.na(E_CD8_density)))
summary(mod)
Linear mixed model fit by REML t-tests use Satterthwaite approximations
  to degrees of freedom [lmerMod]
Formula: nepitopes/pred_epitopes ~ E_CD8_density + (1 | patient_id)
   Data: subset(rates_ihc, !is.na(E_CD8_density))

REML criterion at convergence: -63.4

Scaled residuals: 
     Min       1Q   Median       3Q      Max 
-2.08176 -0.40628  0.04027  0.56379  1.79161 

Random effects:
 Groups     Name        Variance Std.Dev.
 patient_id (Intercept) 0.043792 0.20926 
 Residual               0.006302 0.07939 
Number of obs: 55, groups:  patient_id, 13

Fixed effects:
                Estimate Std. Error         df t value Pr(>|t|)    
(Intercept)    1.0059464  0.0608862 12.7700000  16.522 5.39e-10 ***
E_CD8_density -0.0012898  0.0004055 47.5800000  -3.181  0.00258 ** 
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
            (Intr)
E_CD8_dnsty -0.233
anova(mod)

So we’ve demonstrated that observed/expected neoepitopes is negatively correlated with epithelial CD8+ density – consistent with the theory that immunoediting of neoepitopes occurs in samples with higher epithelial CD8+ TIL.

Strong binders

ggplot(rates_ihc, aes(x = E_CD8_density, y = nstrong/pred_strong)) + theme_bw() + 
    theme_Publication() + ylab("Observed/expected ratio") + geom_point(aes(colour = factor(patient_id))) + 
    scale_color_manual(values = pal_patient) + facet_wrap(~patient_id, scales = "free")

mod <- lmer(nstrong/pred_strong ~ E_CD8_density + (1 | patient_id), rates_ihc)
summary(mod)
Linear mixed model fit by REML t-tests use Satterthwaite approximations
  to degrees of freedom [lmerMod]
Formula: nstrong/pred_strong ~ E_CD8_density + (1 | patient_id)
   Data: rates_ihc

REML criterion at convergence: 23.8

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-2.1649 -0.6097 -0.1265  0.5142  2.4078 

Random effects:
 Groups     Name        Variance Std.Dev.
 patient_id (Intercept) 0.10230  0.3198  
 Residual               0.04031  0.2008  
Number of obs: 55, groups:  patient_id, 13

Fixed effects:
                Estimate Std. Error         df t value Pr(>|t|)    
(Intercept)    1.0460945  0.0993728 12.5900000  10.527 1.33e-07 ***
E_CD8_density -0.0017944  0.0009616 52.8100000  -1.866   0.0676 .  
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
            (Intr)
E_CD8_dnsty -0.342
anova(mod)

This isn’t significant. One could attribute this to the lower numbers of strong epitopes used for computing the background spectrum – leading to larger uncertainty. To offset this we could get more samples to use for the background. It would be worth asking Rooney et al. to provide their spectrum which is presumably computed on a much larger set of samples.

Also it’s worth noting that we can do this analysis on TCGA too, since we don’t need noncoding mutations. So I should probably download the TCGA bams too and process them.

LS0tCnRpdGxlOiAiSW1tdW5vZWRpdGluZyIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDUKICAgIHRvY19mbG9hdDogdHJ1ZQpwYXJhbXM6CiAgcm1kOiAiaW1tdW5vZWRpdGluZy5SbWQiCi0tLQogICAgICAgICAgICAgICAgICAgICAgICBgYGB7ciwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCiMjIyMjIyMjIFNuYWtlbWFrZSBoZWFkZXIgIyMjIyMjIyMKbGlicmFyeShtZXRob2RzKQpTbmFrZW1ha2UgPC0gc2V0Q2xhc3MoCiAgICAiU25ha2VtYWtlIiwKICAgIHNsb3RzID0gYygKICAgICAgICBpbnB1dCA9ICJsaXN0IiwKICAgICAgICBvdXRwdXQgPSAibGlzdCIsCiAgICAgICAgcGFyYW1zID0gImxpc3QiLAogICAgICAgIHdpbGRjYXJkcyA9ICJsaXN0IiwKICAgICAgICB0aHJlYWRzID0gIm51bWVyaWMiLAogICAgICAgIGxvZyA9ICJsaXN0IiwKICAgICAgICByZXNvdXJjZXMgPSAibGlzdCIsCiAgICAgICAgY29uZmlnID0gImxpc3QiLAogICAgICAgIHJ1bGUgPSAiY2hhcmFjdGVyIgogICAgKQopCnNuYWtlbWFrZSA8LSBTbmFrZW1ha2UoCiAgICBpbnB1dCA9IGxpc3QoJy9zaGFobGFiL2FsemhhbmcvcGlwZWxpbmVfb3V0cHV0cy9pdGhfaW1tdW5lL25lb2VkaXRpbmcvcnVuNCcsICdSbWQvaW1tdW5vZWRpdGluZy5SbWQnLCAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL2FuYWx5c2lzL1JtZC9fc2l0ZS55bWwnLCAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvaWhjX3RhYmxlLnRzdicsICJuZW9lZGl0aW5nX291dGRpciIgPSAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvbmVvZWRpdGluZy9ydW40JywgIm5vdGVib29rIiA9ICdSbWQvaW1tdW5vZWRpdGluZy5SbWQnLCAic2l0ZV9maWxlIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvYW5hbHlzaXMvUm1kL19zaXRlLnltbCcsICJpaGNfdGFibGUiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3RhYmxlcy9ydW4yL2loY190YWJsZS50c3YnKSwKICAgIG91dHB1dCA9IGxpc3QoJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3dlYi9pbW11bm9lZGl0aW5nLm5iLmh0bWwnKSwKICAgIHBhcmFtcyA9IGxpc3QoMywgJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9tZXRhZGF0YS9kYi9pbW11bmVfcHJvamVjdC5zcWxpdGUzJywgJ2l0aGktYW5hbHlzaXMtaXRoLXRpbC1hbmFseXNpcycsIGMoJ0VfQ0Q4X2RlbnNpdHknLCAnRV9DRDRfZGVuc2l0eScsICdFX0NEMjBfZGVuc2l0eScsICdFX1BsYXNtYV9kZW5zaXR5JywgJ1NfQ0Q4X2RlbnNpdHknLCAnU19DRDRfZGVuc2l0eScsICdTX0NEMjBfZGVuc2l0eScsICdTX1BsYXNtYV9kZW5zaXR5JyksICJuY2x1c3RzIiA9IDMsICJkYiIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL21ldGFkYXRhL2RiL2ltbXVuZV9wcm9qZWN0LnNxbGl0ZTMnLCAibmFtZSIgPSAnaXRoaS1hbmFseXNpcy1pdGgtdGlsLWFuYWx5c2lzJywgInRpbHNfZm9yX2NsdXN0ZXIiID0gYygnRV9DRDhfZGVuc2l0eScsICdFX0NENF9kZW5zaXR5JywgJ0VfQ0QyMF9kZW5zaXR5JywgJ0VfUGxhc21hX2RlbnNpdHknLCAnU19DRDhfZGVuc2l0eScsICdTX0NENF9kZW5zaXR5JywgJ1NfQ0QyMF9kZW5zaXR5JywgJ1NfUGxhc21hX2RlbnNpdHknKSksCiAgICB3aWxkY2FyZHMgPSBsaXN0KCksCiAgICB0aHJlYWRzID0gMSwKICAgIGxvZyA9IGxpc3QoJy9zaGFobGFiL2FsemhhbmcvY2x1c3R0bXAvcGFwZXJhbmFseXNpczIvbmVvYW50aWdlbl9lZGl0aW5nLmxvZycpLAogICAgcmVzb3VyY2VzID0gbGlzdCgpLAogICAgY29uZmlnID0gbGlzdCgibW1jdG1fc2FtcGxlX3Jlc3VsdF9kaXIiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9yZXN1bHRzL21tY3RtX3Jlc3VsdHMvaXRoX2J5LXNhbXBsZS9vdXRwdXQnLCAiaXRoX3N0YXRfdHlwZXMiID0gYygnZW50cm9weScsICdwb3N0cHJvY2Vzc2VkX2RpdmVyZ2VuY2UnLCAnY29tYmluZWRfaXRoX25vcm1hbGl6ZWQnLCAncHJvcG9ydGlvbl9zdWJjbG9uYWwnKSwgImlncGFydGl0aW9uX291dGRpciIgPSAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvaWdwYXJ0aXRpb24vcnVuMjInLCAidGNyX2RpdmVyc2l0eSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvbWl4Y3IvbWl4Y3JfcnVucy9pdGhfMV8yXzMvbWl4Y3I1L3Bvc3Rwcm9jZXNzL1RSQi9wb3N0ZmlsdGVyX2RpdmVyc2l0eV9zdGF0cy9kaXZlcnNpdHkuc3RyaWN0LnJlc2FtcGxlZC50eHQnLCAibWFwc2NhcGVfbm90ZWJvb2siID0gJ1JtZC9tYXBzY2FwZS5SbWQnLCAiaXRoX3N0YXRpc3RpY3Nfbm90ZWJvb2siID0gJ1JtZC9pdGhfc3RhdGlzdGljcy5SbWQnLCAicHJldmFsZW5jZV90aHJlc2hvbGQiID0gMC4wMSwgInBhdGllbnRzX2Zvcl9jbG9uYWwiID0gYygxLCAyLCAzLCA0LCA3LCA5LCAxMCwgMTEsIDEyLCAxMywgMTQsIDE1LCAxNiwgMTcpLCAidGFibGVfZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMicsICJtbWN0bV9zYW1wbGVfYWRfc2lncGxvdCIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3Jlc3VsdHMvbW1jdG1fcmVzdWx0cy9pdGhfYnktYW5jZXN0cnktc2FtcGxlL3Bsb3RzL2l0aC1ieS1hbmNlc3RyYWwtc2FtcGxlX3Nudi1zdl9zaWdzX211bHRpcGFuZWwucGRmJywgImljZ2NfY2xpbmljYWwiID0gJy9zaGFobGFiL2FsemhhbmcvZGF0YS9JQ0dDL2Rvbm9yLk9WLUFVLnRzdicsICJub3RlYm9va19kaXIiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3dlYicsICJjbGFzc2lmaWVyX3R5cGUiID0gJ2tubicsICJpdGhfcHJvamVjdF9yZXN1bHRzIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL2l0aDMvZGF0YS9yZXN1bHRzJywgIm1tY3RtX292X2NvbWJpbmVkX3NpZ3Bsb3QiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9yZXN1bHRzL21tY3RtX3Jlc3VsdHMvY29tYmluZWRfb3ZfbW1jdG0vcGxvdHMvb3Zfc252LXN2X3NpZ3NfbXVsdGlwYW5lbC5wZGYnLCAibW1jdG1fcGF0aWVudF9hZF9zaWdwbG90IiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcmVzdWx0cy9tbWN0bV9yZXN1bHRzL2l0aF9ieS1wYXRpZW50LWFuY2VzdHJ5L3Bsb3RzL2l0aC1ieS1wYXRpZW50LWFuY2VzdHJ5X3Nudi1zdl9zaWdzX211bHRpcGFuZWwucGRmJywgInRpbHNfZm9yX2NsdXN0ZXIiID0gYygnRV9DRDhfZGVuc2l0eScsICdFX0NENF9kZW5zaXR5JywgJ0VfQ0QyMF9kZW5zaXR5JywgJ0VfUGxhc21hX2RlbnNpdHknLCAnU19DRDhfZGVuc2l0eScsICdTX0NENF9kZW5zaXR5JywgJ1NfQ0QyMF9kZW5zaXR5JywgJ1NfUGxhc21hX2RlbnNpdHknKSwgInZhcmlhYmlsaXR5X3R5cGUiID0gJ3N0YWJpbGl6ZScsICJtdmNsdXN0X25jbHVzdCIgPSAzLCAiUE5HX0RFTlNJVFkiID0gMzAwLCAibGlicmFyeV9zaXplcyIgPSAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvbWl4Y3IvbWl4Y3JfcnVucy9pdGhfMV8yXzMvbWl4Y3I1L2xpYnJhcnlfc2l6ZXMudHN2JywgInNhZF9ub3RlYm9vayIgPSAnUm1kL3NwZWNpZXNfYWJ1bmRhbmNlX2Rpc3RyaWJ1dGlvbnMuUm1kJywgInByb3BvcnRpb25fc3ViY2xvbmFsX2ZpbGUiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9kYXRhL2l0aC9jb21wbGV0ZS9vbGRfcHJvcG9ydGlvbl9zdWJjbG9uYWwudHN2JywgImRlZmF1bHRfc2FtcGxlciIgPSAnSE1DJywgImloY194Y3JfdGlsdHlwZXMiID0gYygnRV9DRDhfZGVuc2l0eScsICdFX0NENF9kZW5zaXR5JywgJ0VfQ0QyMF9kZW5zaXR5JywgJ0VfUGxhc21hX2RlbnNpdHknLCAnU19DRDhfZGVuc2l0eScsICdTX0NENF9kZW5zaXR5JywgJ1NfQ0QyMF9kZW5zaXR5JywgJ1NfUGxhc21hX2RlbnNpdHknLCAnVF9DRDhfZGVuc2l0eScsICdUX0NENF9kZW5zaXR5JywgJ1RfQ0QyMF9kZW5zaXR5JywgJ1RfUGxhc21hX2RlbnNpdHknKSwgIm1tY3RtX2FuY2VzdHJhbF9kZXNjZW5kYW50X3Jlc3VsdF9kaXIiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9yZXN1bHRzL21tY3RtX3Jlc3VsdHMvaXRoX2J5LWFuY2VzdHJ5LXNhbXBsZS9vdXRwdXQnLCAibXV0YXRpb25fc2lnbmF0dXJlX25vdGVib29rIiA9ICdSbWQvbXV0YXRpb25fc2lnbmF0dXJlcy5SbWQnLCAiZHJpdmVyX2FuYWx5c2lzX25vdGVib29rIiA9ICdSbWQvZHJpdmVyX2FuYWx5c2lzLlJtZCcsICJzaXRlX2ZpbGUiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9hbmFseXNpcy9SbWQvX3NpdGUueW1sJywgInhjcl9tYXBwaW5nX25vdGVib29rIiA9ICdSbWQveGNyX21hcHBpbmcuUm1kJywgInNwYXRpYWxfcmVzdWx0X2RpcnMiID0gbGlzdCgic3Ryb21hbCIgPSAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvc3BhdHNpbS9pdGg1L2FiYycsICJlcGl0aGVsaWFsIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9zcGF0c2ltL2l0aDMvYWJjJyksICJ0Y2dhX2V4cHJfbWF0cml4IiA9ICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvVENHQS9leHByX21hdHJpeF9ub3JtYWxpemVfc3RhbmRhcmRpemVfbm9kdXBsaWNhdGVzLnRzdicsICJleGFtcGxlX21zYV9wbG90IiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9pZ3BhcnRpdGlvbi9ydW4xMy9vbGQvYWxpZ25tZW50X3Bsb3RzL21zYS9pdGgyXzIvY2x1c3Q5L2luZGVsX3JldmVyc2VkLmh0bWwnLCAidGNnYV9jbGluaWNhbCIgPSAnL3NoYWhsYWIvYWx6aGFuZy9kYXRhL1RDR0Evc3luYXBzZV9jbGluQWxsX2RhdGEudHN2JywgIm5hbm9zdHJpbmdfZGF0YSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3Jlc3VsdHMvbmFub3N0cmluZ19yZXN1bHRzL2l0aF9mdWxsL3FjL2xpbW1hX3F1YW50aWxlL25vcm1hbGl6ZWRfZXhwcmVzc2lvbl92b2FfbGFiZWxzX2ZpbHRlcmVkLnRzdicsICJpY2djX21vbGVjdWxhcl9zdWJ0eXBlcyIgPSAnL3NoYWhsYWIvYWx6aGFuZy9kYXRhL0lDR0MvaWNnY19wcmltYXJ5X3R1bW91cl9zdWJ0eXBlcy50c3YnLCAiaWhjX3J1bjEiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9kYXRhL2loYy9jZDhjZDNjZDIwL3ZhbGlkYXRlZF9zdGF0c193ZWlnaHRlZF9uZXcucmRhdGEnLCAibW1jdG1fZmluYWxfcGF0aWVudF9kaXIiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9yZXN1bHRzL21tY3RtX3Jlc3VsdHMvaXRoX2J5LXBhdGllbnRfd2l0aC1vdicsICJpaGNfcnVuMiIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2RhdGEvaWhjL2NkNzljZDEzOGNkNjgvdmFsaWRhdGVkX3N0YXRzX3dlaWdodGVkLnJkYXRhJywgImltbXR5cGVyX21vZGVscyIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3Jlc3VsdHMvaW1tdHlwZXJfcmVzdWx0cy9rbGFyZW5iZWVrL2FhX3ZqL2dyYWRib29zdCcsICJpY2djX2V4cHJfbWVsdGVkIiA9ICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvSUNHQy9PVkFVX2V4cHJfbWVsdGVkLnRzdicsICJpbW11bmVfdmFyaWFiaWxpdHlfbm90ZWJvb2siID0gJ1JtZC9pbW11bmVfdmFyaWFiaWxpdHkuUm1kJywgIm5lb2VkaXRpbmdfb3V0ZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9uZW9lZGl0aW5nL3J1bjQnLCAiaWNnY19zcGVjaW1lbl9maWxlIiA9ICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvSUNHQy9zcGVjaW1lbi50c3YnLCAiY2xvbmVfYnJhbmNoX2xlbmd0aF9maWxlIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvZGF0YS9pdGgvY29tcGxldGUvYnJhbmNoX2RhdGEudHN2JywgImV4YW1wbGVfYW5ub3RhdGlvbnMiID0gJy9zaGFobGFiL2FsemhhbmcvcGlwZWxpbmVfb3V0cHV0cy9pdGhfaW1tdW5lL2lncGFydGl0aW9uL3J1bjEzL2ZpbmFsX3BhcnRpdGlvbnMvaXRoMl8yL2NsdXN0OS9hbm5vdGF0aW9uc19mbGFnZ2VkLnRzdicsICJ3YW5nX2ZiaV9zdGF0dXMiID0gJy9zaGFobGFiL2FsemhhbmcvZGF0YS9JQ0dDL25nLjM4NDktUzEyLnR4dCcsICJzcGF0aWFsX25vdGVib29rIiA9ICdSbWQvc3BhdGlhbF9hbmFseXNpcy5SbWQnLCAiaWNnY19ub3JtYWxpemVkX3JlYWRzX21hdHJpeCIgPSAnL3NoYWhsYWIvYWx6aGFuZy9kYXRhL0lDR0MvT1ZBVV9leHByX21hdHJpeC50c3YnLCAibmVvYW50aWdlbl9lZGl0aW5nX25vdGVib29rIiA9ICdSbWQvaW1tdW5vZWRpdGluZy5SbWQnLCAiYmNycGh5bG9fZXhhbXBsZXNfbm90ZWJvb2siID0gJ1JtZC9iY3JfcGh5bG9fZXhhbXBsZXMuUm1kJywgIm1tY3RtX2ZpbmFsX3BhdGllbnRfc2lncGxvdCIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3Jlc3VsdHMvbW1jdG1fcmVzdWx0cy9pdGhfYnktcGF0aWVudF93aXRoLW92L3Bsb3RzL2l0aC1ieS1wYXRpZW50X3Nudi1zdl9zaWdzX211bHRpcGFuZWwucGRmJywgInhjcl9jbG9uZXNfbm90ZWJvb2siID0gJ1JtZC94Y3JfY2xvbmVzX2FuYWx5c2lzLlJtZCcsICJpbmRleF9ub3RlYm9vayIgPSAnUm1kL2luZGV4LlJtZCcsICJwaGVub3R5cGVfdGhyZXNob2xkIiA9IDAuODUsICJpbW10eXBlcl9sZW5ndGhzIiA9ICcxMSAxMiAxMyAxNCAxNSAxNiAxNyAxOCcsICJqX2RpY3Rpb25hcnkiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9zdWJwcm9qZWN0cy9pbW10eXBlci9tZXRhZGF0YS9pbWd0L0hvbW9fc2FwaWVuc19UUkJKLmZhc3RhJywgInRpbF9jbGFzc2lmaWVyX25vdGVib29rIiA9ICdSbWQvdGlsX2NsYXNzaWZpZXIuUm1kJywgImtub3duX3N1YnR5cGVzX21lcmdlZCIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2RhdGEvZXhwcmVzc2lvbi9rbm93bl9zdWJ0eXBlc19tZXJnZWQudHN2JywgImxvZ2RpciIgPSAnL3NoYWhsYWIvYWx6aGFuZy9jbHVzdHRtcC9wYXBlcmFuYWx5c2lzMicsICJpbnRlcm1lZGlhdGVfZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy9pbnRlcm1lZGlhdGVzL3J1bjInLCAiYmNycGh5bG9fY29ycmVsYXRpb25zX25vdGVib29rIiA9ICdSbWQvYmNyX3BoeWxvX2NvcnJlbGF0aW9ucy5SbWQnLCAibmFub3N0cmluZ19hbm5vdGF0aW9ucyIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2RhdGEvZXhwcmVzc2lvbi9uYW5vc3RyaW5nL3BhbmNhbmNlcl9hbm5vdGF0aW9ucy50c3YnLCAiUE5HX1FVQUxJVFkiID0gMzAwLCAia25vd25fc3VidHlwZV9maWxlIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvZGF0YS9leHByZXNzaW9uL2FycmF5L3N1YnR5cGVzL2tub3duX3N1YnR5cGVzLnRzdicsICJ0aWxzX2Zvcl92YXJpYWJpbGl0eSIgPSBjKCdFX0NEOF9kZW5zaXR5JywgJ0VfQ0Q0X2RlbnNpdHknLCAnRV9DRDIwX2RlbnNpdHknLCAnRV9QbGFzbWFfZGVuc2l0eScsICdTX0NEOF9kZW5zaXR5JywgJ1NfQ0Q0X2RlbnNpdHknLCAnU19DRDIwX2RlbnNpdHknLCAnU19QbGFzbWFfZGVuc2l0eScpLCAiY2xvbmFsX3NhbXBsZXJzIiA9IGMoJ0hNQycsICdOVVRTJyksICJ4Y3JfcWNfbm90ZWJvb2siID0gJ1JtZC9yZXBsaWNhdGVzLlJtZCcsICJkcml2ZXJfbWFwIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvc3VicHJvamVjdHMvZHJpdmVycy9kYXRhL2dlbmVfbGlzdF9tYXBwZWQuYmVkJywgIm1tY3RtX3BhdGllbnRfYW5jZXN0cmFsX2Rlc2NlbmRhbnRfcmVzdWx0X2RpciIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3Jlc3VsdHMvbW1jdG1fcmVzdWx0cy9pdGhfYnktcGF0aWVudC1hbmNlc3RyeS9vdXRwdXQnLCAibW9sc3VidHlwZV9ub3RlYm9vayIgPSAnUm1kL21vbGVjdWxhcl9zdWJ0eXBlcy5SbWQnLCAibW9sc3VidHlwZV90aWx0eXBlcyIgPSBjKCdFX0NEOF9kZW5zaXR5JywgJ0VfQ0Q0X2RlbnNpdHknLCAnRV9DRDIwX2RlbnNpdHknLCAnRV9QbGFzbWFfZGVuc2l0eScsICdTX0NEOF9kZW5zaXR5JywgJ1NfQ0Q0X2RlbnNpdHknLCAnU19DRDIwX2RlbnNpdHknLCAnU19QbGFzbWFfZGVuc2l0eScpLCAibWFzdGVyX3ZhcmlhbnRfZmlsZSIgPSAnL3NoYWhsYWIvYW1jcGhlcnNvbi9wcm9qZWN0cy9pdGgzL2l0aDMvbm90ZWJvb2tzL2Jlc3Bva2UvaXRoX3NudnMudHN2JywgImJlbmNobWFya2RpciIgPSAnL3NoYWhsYWIvYWx6aGFuZy9iZW5jaG1hcmtzL3BhcGVyYW5hbHlzaXMyJywgInhjcm1hcHNjYXBlX25vdGVib29rIiA9ICdSbWQveGNybWFwc2NhcGUuUm1kJywgImJjcl9kaXZlcnNpdHkiID0gJy9zaGFobGFiL2FsemhhbmcvcGlwZWxpbmVfb3V0cHV0cy9pdGhfaW1tdW5lL21peGNyL21peGNyX3J1bnMvaXRoXzFfMl8zL21peGNyNS9wb3N0cHJvY2Vzcy9JR0gvcG9zdGZpbHRlcl9kaXZlcnNpdHlfc3RhdHMvZGl2ZXJzaXR5LnN0cmljdC5yZXNhbXBsZWQudHh0JywgImJjcnBoeWxvX3RpbHR5cGVzIiA9IGMoJ0VfQ0Q4X2RlbnNpdHknLCAnRV9DRDRfZGVuc2l0eScsICdFX0NEMjBfZGVuc2l0eScsICdFX1BsYXNtYV9kZW5zaXR5JywgJ1NfQ0Q4X2RlbnNpdHknLCAnU19DRDRfZGVuc2l0eScsICdTX0NEMjBfZGVuc2l0eScsICdTX1BsYXNtYV9kZW5zaXR5JywgJ1RfQ0Q4X2RlbnNpdHknLCAnVF9DRDRfZGVuc2l0eScsICdUX0NEMjBfZGVuc2l0eScsICdUX1BsYXNtYV9kZW5zaXR5JyksICJjbG9uZV90cmVlX2ZpbGUiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9kYXRhL2l0aC9jb21wbGV0ZS90cmVlX2RhdGEudHN2JywgImRiIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvbWV0YWRhdGEvZGIvaW1tdW5lX3Byb2plY3Quc3FsaXRlMycsICJjbG9uZV9wcmV2YWxlbmNlX2ZpbGUiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9kYXRhL2l0aC9jb21wbGV0ZS9jbG9uZV9kYXRhLnRzdicsICJmaWd1cmVfZ2FsbGVyeV9ub3RlYm9vayIgPSAnUm1kL2ZpZ3VyZXMuUm1kJywgIm1hc3Rlcl9icmVha3BvaW50X2ZpbGUiID0gJy9zaGFobGFiL2FtY3BoZXJzb24vcHJvamVjdHMvaXRoMy9pdGgzL25vdGVib29rcy9iZXNwb2tlL2l0aF9icmVha3BvaW50cy50c3YnLCAidGNnYV9vdl9hbm5vdGF0aW9ucyIgPSAnL3NoYWhsYWIvYWx6aGFuZy9kYXRhL1RDR0EvdGNnYV9vdl9hbm5vdGF0aW9uX3N1cDEzLnR4dCcsICJpaGNfeGNyX3N0YXRzX25vdGVib29rIiA9ICdSbWQvaWhjX3hjcl9zdGF0cy5SbWQnLCAieGNyX2Rpc3RhbmNlX21ldGhvZCIgPSAnaG9ybicsICJpdGhfc3RhdHNfZmlsZSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2RhdGEvaXRoL2NvbXBsZXRlL2Nsb25hbF9tZWFzdXJlcy50c3YnLCAibW1jdG1fb3ZfY29tYmluZWRfcmVzdWx0X2RpciIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3Jlc3VsdHMvbW1jdG1fcmVzdWx0cy9jb21iaW5lZF9vdl9tbWN0bS9vdXRwdXQnLCAibW1jdG1fc2FtcGxlX3NpZ3Bsb3QiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9yZXN1bHRzL21tY3RtX3Jlc3VsdHMvaXRoX2J5LXNhbXBsZS9wbG90cy9pdGgtYnktc2FtcGxlX3Nudi1zdl9zaWdzX211bHRpcGFuZWwucGRmJywgIm11bHRpdmlld2NsdXN0ZXJpbmdfbm90ZWJvb2siID0gJ1JtZC9tdWx0aXZpZXdjbHVzdGVyaW5nLlJtZCcsICJtdmNsdXN0X3RpbHR5cGVzIiA9IGMoJ0VfQ0Q4X2RlbnNpdHknLCAnRV9DRDRfZGVuc2l0eScsICdFX0NEMjBfZGVuc2l0eScsICdFX1BsYXNtYV9kZW5zaXR5JywgJ1NfQ0Q4X2RlbnNpdHknLCAnU19DRDRfZGVuc2l0eScsICdTX0NEMjBfZGVuc2l0eScsICdTX1BsYXNtYV9kZW5zaXR5JyksICJpdGhfdGlsX25vdGVib29rIiA9ICdSbWQvaXRoX3RpbF9kZW5zaXRpZXMuUm1kJywgInRjcl9jbG9ub3R5cGVzIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9taXhjci9taXhjcl9ydW5zL2l0aF8xXzJfMy9taXhjcjUvY2xvbm90eXBlcy9UUkJfY2xvbm90eXBlc19maWx0ZXJlZC50eHQnLCAibXV0c2lnX3RpbHR5cGVzIiA9IGMoJ0VfQ0Q4X2RlbnNpdHknLCAnRV9DRDRfZGVuc2l0eScsICdFX0NEMjBfZGVuc2l0eScsICdFX1BsYXNtYV9kZW5zaXR5JywgJ1NfQ0Q4X2RlbnNpdHknLCAnU19DRDRfZGVuc2l0eScsICdTX0NEMjBfZGVuc2l0eScsICdTX1BsYXNtYV9kZW5zaXR5JywgJ1RfQ0Q4X2RlbnNpdHknLCAnVF9DRDRfZGVuc2l0eScsICdUX0NEMjBfZGVuc2l0eScsICdUX1BsYXNtYV9kZW5zaXR5JyksICJzdWJ0eXBlX21hcmtlcl9maWxlIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvZGF0YS9leHByZXNzaW9uL25hbm9zdHJpbmcvc3VidHlwZV9tYXJrZXJzLnRzdicsICJiY3JfY2xvbm90eXBlcyIgPSAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvbWl4Y3IvbWl4Y3JfcnVucy9pdGhfMV8yXzMvbWl4Y3I1L2Nsb25vdHlwZXMvSUdIX2Nsb25vdHlwZXNfZmlsdGVyZWQudHh0JywgInZfZGljdGlvbmFyeSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3N1YnByb2plY3RzL2ltbXR5cGVyL21ldGFkYXRhL2ltZ3QvSG9tb19zYXBpZW5zX1RSQlYuZmFzdGEnLCAibmFub3N0cmluZ19zaWduYXR1cmVfbm90ZWJvb2siID0gJ1JtZC9uYW5vc3RyaW5nX3NpZ25hdHVyZXMuUm1kJywgIm5jbHVzdHMiID0gMyksCiAgICBydWxlID0gJ25lb2FudGlnZW5fZWRpdGluZycKKQojIyMjIyMjIyBPcmlnaW5hbCBzY3JpcHQgIyMjIyMjIyMjCgogICAgICAgICAgICAgICAgICAgICAgICBgYGAKCgpgYGB7ciBnbG9iYWxfY2h1bmtfb3B0aW9ucywgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCB0aWR5PVRSVUUsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UpCmBgYAoKCmBgYHtyfQpsaWJyYXJ5KGl0aGkudXRpbHMpCmxvYWRfYmFzZV9saWJzKCkKCmxpYnJhcnkoaXRoaS5tZXRhKQpsaWJyYXJ5KGl0aGkuaWhjKQpgYGAKCiMjIENvbG91ciBwYWxldHRlcwoKYGBge3J9CnBhbF9wYXRpZW50IDwtIHNlbGVjdF9wYWxldHRlKCJwYXRpZW50IikKYGBgCgojIyBQYXJhbWV0ZXJzCgpgYGB7cn0KZGJfcGF0aCA8LSBzbmFrZW1ha2VAcGFyYW1zJGRiCgppaGNfdGFibGVfcGF0aCA8LSBzbmFrZW1ha2VAaW5wdXQkaWhjX3RhYmxlCnRpbHNfZm9yX2NsdXN0ZXIgPC0gdW5saXN0KHNuYWtlbWFrZUBwYXJhbXMkdGlsc19mb3JfY2x1c3RlcikKbmNsdXN0cyA8LSBhcy5udW1lcmljKHNuYWtlbWFrZUBwYXJhbXMkbmNsdXN0cykKCm5lb2VkaXRpbmdfb3V0ZGlyIDwtIHNuYWtlbWFrZUBpbnB1dCRuZW9lZGl0aW5nX291dGRpcgplcGl0b3BlX2RpcnMgPC0gbGlzdC5maWxlcyhmaWxlLnBhdGgobmVvZWRpdGluZ19vdXRkaXIsICJlcGl0b3BlX2ZpbGVzIiksIGZ1bGwubmFtZXMgPSBUUlVFKQpzcGVjdHJ1bV9maWxlIDwtIGZpbGUucGF0aChuZW9lZGl0aW5nX291dGRpciwgImJhY2tncm91bmRfc3BlY3RydW0iLCAic2lnbmF0dXJlcy50eHQiKQpgYGAKCiMjIE1ldGFkYXRhCgpgYGB7cn0KaWRfdHlwZSA8LSAiY29uZGVuc2VkX2lkIgoKZGIgPC0gc3JjX3NxbGl0ZShkYl9wYXRoLCBjcmVhdGU9RkFMU0UpCmR1cGxpY2F0ZXMgPC0gY29sbGVjdCh0YmwoZGIsICJkdXBsaWNhdGVzIikpCmBgYAoKIyMgVElMIGNsdXN0ZXJzCgpgYGB7cn0KaWhjX3RhYmxlIDwtIGZyZWFkKGloY190YWJsZV9wYXRoKQpgYGAKCmBgYHtyfQppaGNfZGF0YSA8LSBzdWJzZXQoaWhjX3RhYmxlLCBzZWxlY3Q9Yyh0aWxzX2Zvcl9jbHVzdGVyKSkKdmFsaWRfcm93cyA8LSBhcHBseShpaGNfZGF0YSwgMSwgZnVuY3Rpb24oeCkgYWxsKCFpcy5uYSh4KSkpCgpwYXRpZW50X2lkcyA8LSBhcy5kYXRhLmZyYW1lKHN1YnNldChpaGNfdGFibGUsIHNlbGVjdD1jKHBhdGllbnRfaWQpKSkKaWhjX2RhdGEgPC0gYXMuZGF0YS5mcmFtZShpaGNfZGF0YVt2YWxpZF9yb3dzLF0pCgpwYXRpZW50X2lkcyA8LSBwYXRpZW50X2lkc1t2YWxpZF9yb3dzLCxkcm9wPUZBTFNFXQpwYXRpZW50X2lkcyRwYXRpZW50X2lkIDwtIGZhY3RvcihwYXRpZW50X2lkcyRwYXRpZW50X2lkKQpjb2xuYW1lcyhwYXRpZW50X2lkcykgPC0gIlBhdGllbnQiCgpyb3duYW1lcyhpaGNfZGF0YSkgPC0gcm93bmFtZXMocGF0aWVudF9pZHMpIDwtIGFzLmRhdGEuZnJhbWUoaWhjX3RhYmxlKVssaWRfdHlwZV1bdmFsaWRfcm93c10KYGBgCgpgYGB7ciwgZmlnLndpZHRoPTE4LCBmaWcuaGVpZ2h0PTR9CmRhdF9wcm9jZXNzZWQgPC0gdChjbGlwX3ZhbHVlcyhzY2FsZShpaGNfZGF0YSkpKQpyb3duYW1lcyhkYXRfcHJvY2Vzc2VkKSA8LSBtYXB2YWx1ZXMocm93bmFtZXMoZGF0X3Byb2Nlc3NlZCksIGZyb20gPSBjKCJFX0NEOF9kZW5zaXR5IiwgIkVfQ0Q0X2RlbnNpdHkiLCAiRV9DRDIwX2RlbnNpdHkiLCAiRV9QbGFzbWFfZGVuc2l0eSIpLAogICAgICAgICAgdG89YygiRSBDRDgrIiwgIkUgQ0Q0KyIsICJFIENEMjArIiwgIkUgUGxhc21hIikpCgpwIDwtIHBoZWF0bWFwKGRhdF9wcm9jZXNzZWQsIGNsdXN0ZXJpbmdfbWV0aG9kID0gIndhcmQuRCIsIGFubm90YXRpb25fY29sID0gcGF0aWVudF9pZHMsIAogICAgICAgICAgICAgIGFubm90YXRpb25fY29sb3JzID0gbGlzdChQYXRpZW50PXBhbF9wYXRpZW50KSwgY2x1c3Rlcl9yb3dzID0gRkFMU0UsCiAgICAgICAgICAgICAgc2hvd19jb2xuYW1lcyA9IEZBTFNFLCBsZWdlbmQgPSBUUlVFLCBjZWxsd2lkdGg9MTAsIGNlbGxoZWlnaHQ9MTAsCiAgICAgICAgICAgICAgYW5ub3RhdGlvbl9sZWdlbmQgPSBGQUxTRSkKYGBgCgpgYGB7cn0KY2x1c3RzIDwtIGRhdGEuZnJhbWUoY3V0cmVlKHAkdHJlZV9jb2wsIG5jbHVzdHMpKQpzZXREVChjbHVzdHMsIGtlZXAucm93bmFtZXMgPSBUUlVFKQpjbHVzdHMgPC0gc2V0TmFtZXMoY2x1c3RzLCBjKGlkX3R5cGUsICJjbHVzdGVyIikpCgpjbHVzdHMkY2x1c3RlciA8LSBmYWN0b3IoY2x1c3RzJGNsdXN0ZXIpCmloY190YWJsZV9hbm5vdGF0ZWQgPC0gbWVyZ2UoaWhjX3RhYmxlLCBjbHVzdHMsIGJ5PWMoaWRfdHlwZSkpCmBgYAoKIyMgSW1tdW5vZWRpdGluZwoKYGBge3J9CnJlYWRfc3BlY3RydW0gPC0gZnVuY3Rpb24oZikgewogIGRhdCA8LSBmcmVhZChmKQogIGNvbG5hbWVzKGRhdCkgPC0gbWFwdmFsdWVzKGNvbG5hbWVzKGRhdCksIGZyb209YygibXV0YXRpb25zZXFfdHJpbnVjbGVvdGlkZV9yZWYiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJtdXRhdGlvbnNlcV90cmludWNsZW90aWRlX2FsdCIpLAogICAgICAgICAgICB0bz1jKCJ0cmlyZWYiLCAidHJpYWx0IikpCiAgcmV0dXJuKGRhdCkKfQoKcmVhZF9lcGl0b3BlX2ZpbGVzIDwtIGZ1bmN0aW9uKGVwaXRvcGVfZmlsZXMsIHNwZWN0cnVtKSB7CiAgZXBpdG9wZXMgPC0gcmJpbmQuZmlsbChsYXBwbHkoZXBpdG9wZV9maWxlcywgZnVuY3Rpb24oZikgewogICAgc2FtcGxlX2tleSA8LSBiYXNlbmFtZShkaXJuYW1lKGYpKQogICAgdmFycyA8LSBmcmVhZChmKQogICAgY2JpbmQoc2FtcGxlX2tleT1zYW1wbGVfa2V5LCB2YXJzKQogIH0pKQogIGVwaXRvcGVzIDwtIG1lcmdlKGVwaXRvcGVzLCBzcGVjdHJ1bSwgYnk9YygidHJpbnVjX3NpZyIpKQogIGVwaXRvcGVzJHBhdGllbnRfaWQgPC0gbWFwX2lkKGVwaXRvcGVzJHNhbXBsZV9rZXksIGZyb20gPSAiY29uZGVuc2VkX2lkIiwgdG89InBhdGllbnRfaWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRiX3BhdGgpCiAgcmV0dXJuKGVwaXRvcGVzKQp9CmBgYAoKYGBge3J9CnNwZWN0cnVtIDwtIHJlYWRfc3BlY3RydW0oc3BlY3RydW1fZmlsZSkKCnNpbGVudF9lcGl0b3BlX2ZpbGVzIDwtIFN5cy5nbG9iKGZpbGUucGF0aChlcGl0b3BlX2RpcnMsICJzaWxlbnQudHN2IikpCm5vbnN5bm9ueW1vdXNfZXBpdG9wZV9maWxlcyA8LSBTeXMuZ2xvYihmaWxlLnBhdGgoZXBpdG9wZV9kaXJzLCAibm9uc3lub255bW91cy50c3YiKSkKYGBgCgpgYGB7cn0Kc2lsZW50X2VwaXRvcGVzIDwtIHJlYWRfZXBpdG9wZV9maWxlcyhzaWxlbnRfZXBpdG9wZV9maWxlcywgc3BlY3RydW0pCnNpbGVudF9kdXBzIDwtIGR1cGxpY2F0ZWQoc3Vic2V0KHNpbGVudF9lcGl0b3Blcywgc2VsZWN0PWMoc2FtcGxlX2tleSwgQ2hyb21vc29tZSwgU3RhcnQsIFJlZmVyZW5jZSwgVmFyaWFudCkpKQpzaWxlbnRfZXBpdG9wZXMgPC0gc2lsZW50X2VwaXRvcGVzWyFzaWxlbnRfZHVwcyxdCgpub25zeW5vbnltb3VzX2VwaXRvcGVzIDwtIHJlYWRfZXBpdG9wZV9maWxlcyhub25zeW5vbnltb3VzX2VwaXRvcGVfZmlsZXMsIHNwZWN0cnVtKQpgYGAKCk92ZXJhbGwsIHRoZXJlIGFyZW4ndCBhbnkgbWFqb3IgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgZnJhY3Rpb24gb2YgbmVvZXBpdG9wZXMgZGV0ZXJtaW5lZCBmcm9tIG5vbnN5bm9ueW1vdXMgbXV0YXRpb25zIHZzLiB3aGF0IHdvdWxkIGJlIGV4cGVjdGVkIGZyb20gc3lub255bW91cyBtdXRhdGlvbnMuIEluIG90aGVyIHdvcmRzLCB0aGVyZSBpcywgb24gYXZlcmFnZSwgbm8gaW1tdW5vZWRpdGluZyBvY2N1cnJpbmcgb24gbmVvYW50aWdlbnMgaW4gSEdTQy4gRG8ga2VlcCBpbiBtaW5kIHRoaXMgaXMgY29tcGxpY2F0ZWQgYnkgdGhlIGxhY2sgb2YgZXhwcmVzc2lvbiBkYXRhLCBzbyB3ZSBjYW5ub3QgdHJ1bHkgY29uZmlybSB3aGljaCBhcmUgbmVvYW50aWdlbnMuIAoKYGBge3J9CnN1bShzaWxlbnRfZXBpdG9wZXMkZnJhY19iaW5kZXIpL25yb3coc2lsZW50X2VwaXRvcGVzKQpzdW0oc2lsZW50X2VwaXRvcGVzJGZyYWNfc3Ryb25nX2JpbmRlcikvbnJvdyhzaWxlbnRfZXBpdG9wZXMpCnN1bShub25zeW5vbnltb3VzX2VwaXRvcGVzJGZyYWNfYmluZGVyKS9ucm93KG5vbnN5bm9ueW1vdXNfZXBpdG9wZXMpCnN1bShub25zeW5vbnltb3VzX2VwaXRvcGVzJGZyYWNfc3Ryb25nX2JpbmRlcikvbnJvdyhub25zeW5vbnltb3VzX2VwaXRvcGVzKQpgYGAKCiMjIyBBbGxlbGljIGZyYWN0aW9ucwoKYGBge3J9Cmhpc3Qod2l0aChzdWJzZXQobm9uc3lub255bW91c19lcGl0b3BlcywgYE5ldE1IQ3BhbiBNVCBQZXJjZW50aWxlYCA+IDIpLCBhbHRfY291bnRzLyhyZWZfY291bnRzK2FsdF9jb3VudHMpKSwgYnJlYWtzPTMwKQpoaXN0KHdpdGgoc3Vic2V0KG5vbnN5bm9ueW1vdXNfZXBpdG9wZXMsIGBOZXRNSENwYW4gTVQgUGVyY2VudGlsZWAgPD0gMiksIGFsdF9jb3VudHMvKHJlZl9jb3VudHMrYWx0X2NvdW50cykpLCBicmVha3M9MzApCgp0YWIxIDwtIHRhYmxlKHN1YnNldChub25zeW5vbnltb3VzX2VwaXRvcGVzLCBgTmV0TUhDcGFuIE1UIFBlcmNlbnRpbGVgID4gMikkaXNfYW5jZXN0cmFsKQp0YWIyIDwtIHRhYmxlKHN1YnNldChub25zeW5vbnltb3VzX2VwaXRvcGVzLCBgTmV0TUhDcGFuIE1UIFBlcmNlbnRpbGVgIDw9IDIpJGlzX2FuY2VzdHJhbCkKaGlzdCh3aXRoKHNpbGVudF9lcGl0b3BlcywgYWx0X2NvdW50cy8ocmVmX2NvdW50cythbHRfY291bnRzKSksIGJyZWFrcz0zMCkKCmZpc2hlci50ZXN0KHJiaW5kKHRhYjEsIHRhYjIpKQpgYGAKCldoYXQgZG9lcyB0aGUgcGVhayBuZWFyIDAuNSBtZWFuPyBXZSBtaWdodCBub3JtYWxseSBleHBlY3QgdG8gc2VlIGEgcGVhayBhdCAwLjUgYXMgYSByZXN1bHQgb2YgaGV0ZXJvenlnb3NpdHksIGZvciB0dW1vdXJzIHdpdGggaGlnaCBwdXJpdHkuIFdoeSBkb2VzIGl0IG9ubHkgb2NjdXIgZm9yIHRoZSBzaWxlbnQgZXBpdG9wZXM/IENvdWxkIGl0IGJlIGEgcmVzdWx0IG9mIGVkaXRpbmcgb2NjdXJpbmcgZm9yIHRoZSBub25zeW5vbnltb3VzIGVwaXRvcGVzPyAKCk5ldmVybWluZCwgcGVhayBhdCAwLjUgaXMgZ29uZS4gV2FzIGR1ZSB0byBzb21lIHJlYWxseSB3ZWlyZCB2YXJpYW50IHRoYXQgaGFkIHNvbWVob3cgcGFzc2VkIG15IHVuaXF1ZW5lc3MgZmlsdGVyLiAKCiMjIyBPdmVyYWxsIHJhdGVzCgpgYGB7cn0Kc2lsZW50X3JhdGVzIDwtIHNpbGVudF9lcGl0b3BlcyAlPiUgZ3JvdXBfYnkoc2FtcGxlX2tleSkgJT4lIHN1bW1hcmlzZShiaW5kZXJzPXN1bShmcmFjX2JpbmRlciksIHN0cm9uZ19iaW5kZXI9c3VtKGZyYWNfc3Ryb25nX2JpbmRlciksIHRvdGFsPW4oKSwgc3BiaW5kZXI9YmluZGVycy90b3RhbCwgc3BzYmluZGVyPXN0cm9uZ19iaW5kZXIvdG90YWwpCm5vbnN5bm9ueW1vdXNfcmF0ZXMgPC0gbm9uc3lub255bW91c19lcGl0b3BlcyAlPiUgZ3JvdXBfYnkoc2FtcGxlX2tleSkgJT4lCiAgc3VtbWFyaXNlKG50b3RhbD1uKCksIG5lcGl0b3Blcz1sZW5ndGgod2hpY2goYE5ldE1IQ3BhbiBNVCBQZXJjZW50aWxlYCA8PSAyKSksIAogICAgICAgICAgICBuc3Ryb25nPWxlbmd0aCh3aGljaChgTmV0TUhDcGFuIE1UIFBlcmNlbnRpbGVgIDw9IDAuNSkpKQoKCiNub25zeW5vbnltb3VzX3JhdGVzIDwtIG5vbnN5bm9ueW1vdXNfZXBpdG9wZXMgJT4lIGdyb3VwX2J5KHNhbXBsZV9rZXkpICU+JSBzdW1tYXJpc2UoYmluZGVycz1zdW0oZnJhY19iaW5kZXIpLCBzdHJvbmdfYmluZGVyPXN1bShmcmFjX3N0cm9uZ19iaW5kZXIpLCB0b3RhbD1uKCksIG5wYmluZGVyPWJpbmRlcnMvdG90YWwsIG5wc2JpbmRlcj1zdHJvbmdfYmluZGVyL3RvdGFsKSAKCnJhdGVzIDwtIG1lcmdlKHNpbGVudF9yYXRlcywgbm9uc3lub255bW91c19yYXRlcywgYnk9Yygic2FtcGxlX2tleSIpKQoKcmF0ZXMkcHJlZF9lcGl0b3BlcyA8LSB3aXRoKHJhdGVzLCBzcGJpbmRlciAqIG50b3RhbCkKcmF0ZXMkcHJlZF9zdHJvbmcgPC0gd2l0aChyYXRlcywgc3BzYmluZGVyICogbnRvdGFsKQpgYGAKCiMjIyB2cy4gVElMIGNsdXN0ZXJzCgpgYGB7cn0KcmF0ZXNfY2x1c3RzIDwtIG1lcmdlKHJhdGVzLCBjbHVzdHMsIGJ5Lng9Yygic2FtcGxlX2tleSIpLCBieS55PWMoImNvbmRlbnNlZF9pZCIpKQoKcmF0ZXNfY2x1c3RzJHBhdGllbnRfaWQgPC0gbWFwX2lkKHJhdGVzX2NsdXN0cyRzYW1wbGVfa2V5LCBmcm9tPSJjb25kZW5zZWRfaWQiLCB0bz0icGF0aWVudF9pZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYl9wYXRoKQpgYGAKCmBgYHtyfQpnZ3Bsb3QocmF0ZXNfY2x1c3RzLCBhZXMoeD1jbHVzdGVyLCB5PW5lcGl0b3Blcy9wcmVkX2VwaXRvcGVzKSkgKyBnZW9tX2JveHBsb3QoKSArIHRoZW1lX2J3KCkgKyB0aGVtZV9QdWJsaWNhdGlvbigpICsgeWxhYigiT2JzZXJ2ZWQvZXhwZWN0ZWQgcmF0aW8iKSArIGdlb21faml0dGVyKGFlcyhjb2xvdXI9ZmFjdG9yKHBhdGllbnRfaWQpKSwgcG9zaXRpb249cG9zaXRpb25faml0dGVyKHdpZHRoPTAuMiwgaGVpZ2h0PTApKSArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxfcGF0aWVudCkKYGBgCgpgYGB7cn0KZ2dwbG90KHJhdGVzX2NsdXN0cywgYWVzKHg9Y2x1c3RlciwgeT1uc3Ryb25nL3ByZWRfc3Ryb25nKSkgKyBnZW9tX2JveHBsb3QoKSArIHRoZW1lX2J3KCkgKyB0aGVtZV9QdWJsaWNhdGlvbigpICsgeWxhYigiT2JzZXJ2ZWQvZXhwZWN0ZWQgcmF0aW8iKQpgYGAKClRoaXMgZG9lc24ndCBzaG93IGEgc2lnbmlmaWNhbnQgY29ycmVsYXRpb24uIFRoZXJlIGlzIGEgY2hhbmNlIHdlJ2xsIHNlZSBiZXR0ZXIgcmVzdWx0cyBieSBsb29raW5nIGRpcmVjdGx5IGF0IFRJTCBkZW5zaXRpZXMgdGhvdWdoLiAKCiMjIyB2cy4gVElMIGRlbnNpdGllcwoKYGBge3J9CnJhdGVzX2loYyA8LSBtZXJnZShyYXRlcywgaWhjX3RhYmxlLCBieS54PSJzYW1wbGVfa2V5IiwgYnkueT0iY29uZGVuc2VkX2lkIikKYGBgCgojIyMjIEJpbmRlcnMKCmBgYHtyLCBmaWcud2lkdGg9OSwgZmlnLmhlaWdodD05fQpnZ3Bsb3QocmF0ZXNfaWhjLCBhZXMoeD1FX0NEOF9kZW5zaXR5LCB5PW5lcGl0b3Blcy9wcmVkX2VwaXRvcGVzKSkgKyB0aGVtZV9idygpICsgdGhlbWVfUHVibGljYXRpb24oKSArIHlsYWIoIk9ic2VydmVkL2V4cGVjdGVkIHJhdGlvIikgKyBnZW9tX3BvaW50KGFlcyhjb2xvdXI9ZmFjdG9yKHBhdGllbnRfaWQpKSkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsX3BhdGllbnQpICsgZmFjZXRfd3JhcCh+IHBhdGllbnRfaWQsIHNjYWxlcz0iZnJlZSIpCmBgYAoKRnJvbSB0aGlzIHBsb3Qgd2UgY2FuIHNlZSBhIG5lZ2F0aXZlIGNvcnJlbGF0aW9uIGJldHdlZW4gb2JzL2V4cGVjdGVkIHJhdGlvIGFuZCBlcGl0aGVsaWFsIENEOCsgZGVuc2l0eSBmb3Igc29tZSBwYXRpZW50cy4gSXQncyBhbHNvIGFwcGFyZW50IHRoYXQgdGhlIHBhdGllbnRzIGZvciB3aGljaCB3ZSBkb24ndCBzZWUgdGhpcyBjb3JyZWxhdGlvbiBhcmUgcGF0aWVudHMgd2l0aCBsb3cgbGV2ZWxzIG9mIFRJTHMgKHNvIHRoYXQgdGhlIHZhbHVlcyBvbiB0aGUgeC1heGlzIGFyZSB2ZXJ5IHRpZ2h0bHkgc3BhY2VkKS4gV2UgZm9ybXVsYXRlIHRoZSBmb2xsb3dpbmcgbGluZWFyIG1peGVkIG1vZGVsOgoKYGBge3J9Cm1vZCA8LSBsbWVyKG5lcGl0b3Blcy9wcmVkX2VwaXRvcGVzIH4gRV9DRDhfZGVuc2l0eSArICgxfHBhdGllbnRfaWQpLCBzdWJzZXQocmF0ZXNfaWhjLCAhaXMubmEoRV9DRDhfZGVuc2l0eSkpKQpzdW1tYXJ5KG1vZCkKYW5vdmEobW9kKQpgYGAKClNvIHdlJ3ZlIGRlbW9uc3RyYXRlZCB0aGF0IG9ic2VydmVkL2V4cGVjdGVkIG5lb2VwaXRvcGVzIGlzIG5lZ2F0aXZlbHkgY29ycmVsYXRlZCB3aXRoIGVwaXRoZWxpYWwgQ0Q4KyBkZW5zaXR5IC0tIGNvbnNpc3RlbnQgd2l0aCB0aGUgdGhlb3J5IHRoYXQgaW1tdW5vZWRpdGluZyBvZiBuZW9lcGl0b3BlcyBvY2N1cnMgaW4gc2FtcGxlcyB3aXRoIGhpZ2hlciBlcGl0aGVsaWFsIENEOCsgVElMLiAKCiMjIyMgU3Ryb25nIGJpbmRlcnMKCmBgYHtyLCBmaWcud2lkdGg9OSwgZmlnLmhlaWdodD05fQpnZ3Bsb3QocmF0ZXNfaWhjLCBhZXMoeD1FX0NEOF9kZW5zaXR5LCB5PW5zdHJvbmcvcHJlZF9zdHJvbmcpKSArIHRoZW1lX2J3KCkgKyB0aGVtZV9QdWJsaWNhdGlvbigpICsgeWxhYigiT2JzZXJ2ZWQvZXhwZWN0ZWQgcmF0aW8iKSArIGdlb21fcG9pbnQoYWVzKGNvbG91cj1mYWN0b3IocGF0aWVudF9pZCkpKSArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxfcGF0aWVudCkgKyBmYWNldF93cmFwKH4gcGF0aWVudF9pZCwgc2NhbGVzPSJmcmVlIikKYGBgCgoKYGBge3J9Cm1vZCA8LSBsbWVyKG5zdHJvbmcvcHJlZF9zdHJvbmcgfiBFX0NEOF9kZW5zaXR5ICsgKDF8cGF0aWVudF9pZCksIHJhdGVzX2loYykKc3VtbWFyeShtb2QpCmFub3ZhKG1vZCkKYGBgCgpUaGlzIGlzbid0IHNpZ25pZmljYW50LiBPbmUgY291bGQgYXR0cmlidXRlIHRoaXMgdG8gdGhlIGxvd2VyIG51bWJlcnMgb2Ygc3Ryb25nIGVwaXRvcGVzIHVzZWQgZm9yIGNvbXB1dGluZyB0aGUgYmFja2dyb3VuZCBzcGVjdHJ1bSAtLSBsZWFkaW5nIHRvIGxhcmdlciB1bmNlcnRhaW50eS4gVG8gb2Zmc2V0IHRoaXMgd2UgY291bGQgZ2V0IG1vcmUgc2FtcGxlcyB0byB1c2UgZm9yIHRoZSBiYWNrZ3JvdW5kLiBJdCB3b3VsZCBiZSB3b3J0aCBhc2tpbmcgUm9vbmV5IGV0IGFsLiB0byBwcm92aWRlIHRoZWlyIHNwZWN0cnVtIHdoaWNoIGlzIHByZXN1bWFibHkgY29tcHV0ZWQgb24gYSBtdWNoIGxhcmdlciBzZXQgb2Ygc2FtcGxlcy4gCgpBbHNvIGl0J3Mgd29ydGggbm90aW5nIHRoYXQgd2UgKipjYW4qKiBkbyB0aGlzIGFuYWx5c2lzIG9uIFRDR0EgdG9vLCBzaW5jZSB3ZSBkb24ndCBuZWVkIG5vbmNvZGluZyBtdXRhdGlvbnMuIFNvIEkgc2hvdWxkIHByb2JhYmx5IGRvd25sb2FkIHRoZSBUQ0dBIGJhbXMgdG9vIGFuZCBwcm9jZXNzIHRoZW0uIAo=