library(ithi.utils)
load_base_libs()

library(ithi.meta)
library(ithi.clones)
library(ithi.seq)

Colour palettes

pal_patient <- select_palette("patient")

Parameters

db_path <- snakemake@params$db

ith_stats_file <- snakemake@input$ith_stats
# proportion_subclonality_file <- snakemake@input$subclonality
tumour_purity_file <- snakemake@input$tumour_purity

old_result_file <- "/shahlab/alzhang/projects/ITH_Immune/data/ith/old_ith_comparison.tsv"

Metadata

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

Description

New clonal predictions are still under a lot of work so we have to validate their quality.

Old clonal predictions

Here’s what things looked like under the old set of predictions:

old_comparison <- fread(old_result_file)
old_comparison$patient_id <- factor(old_comparison$patient_id)

ith_vars <- c("divergence", "entropy", "composite_ith")
other_vars <- colnames(old_comparison)[!colnames(old_comparison) %in% ith_vars]
old_comparison_melted <- melt(old_comparison, id.vars = other_vars, measure.vars = ith_vars, 
    variable.name = "ithtype", value.name = "ith")
pvals <- setNames(ddply(old_comparison_melted, .(ithtype), function(x) {
    df <- x
    corres <- with(df, cor.test(proportion_subclonal, ith, method = "spearman"))
    
    pval <- corres$p.value
    eq <- substitute(italic(P) == p, list(p = format(pval, digits = 3)))
    return(as.character(as.expression(eq)))
}), c("ithtype", "p.value"))

ggplot(old_comparison_melted, aes(x = proportion_subclonal, y = ith)) + geom_point(aes(colour = patient_id)) + 
    theme_bw() + theme_Publication() + facet_wrap(~ithtype, scales = "free") + 
    scale_color_manual(values = pal_patient) + geom_text(data = pvals, aes(x = Inf, 
    y = Inf, label = p.value), hjust = 1.1, vjust = 1.5, size = 3, parse = TRUE)

This is what we expect to see: a reasonably good correlation between naive measures of ITH and more “rigorous” measures.

New clonal predictions

ith_stats <- read_ith_stats(ith_stats_file, db_path, duplicates = FALSE)
# subclonality <- fread(proportion_subclonality_file)

# new_comparison <- merge(ith_stats, subclonality, by=c('condensed_id',
# 'patient_id'))
new_comparison <- ith_stats

ith_vars <- c("divergence", "entropy", "postprocessed_divergence", "combined_ith_raw", 
    "combined_ith_normalized")
other_vars <- colnames(new_comparison)[!colnames(new_comparison) %in% ith_vars]
new_comparison_melted <- melt(new_comparison, id.vars = other_vars, measure.vars = ith_vars, 
    variable.name = "ithtype", value.name = "ith")
pvals <- setNames(ddply(new_comparison_melted, .(ithtype), function(x) {
    df <- x
    corres <- with(df, cor.test(proportion_subclonal, ith, method = "spearman"))
    
    pval <- corres$p.value
    eq <- substitute(italic(P) == p, list(p = format(pval, digits = 3)))
    return(as.character(as.expression(eq)))
}), c("ithtype", "p.value"))

ggplot(new_comparison_melted, aes(x = proportion_subclonal, y = ith)) + geom_point(aes(colour = patient_id)) + 
    theme_bw() + theme_Publication() + facet_wrap(~ithtype, scales = "free") + 
    scale_color_manual(values = pal_patient) + geom_text(data = pvals, aes(x = Inf, 
    y = Inf, label = p.value), hjust = 1.1, vjust = 1.5, size = 3, parse = TRUE)

As of now, these are pretty terrible, suggesting that the clonal predictions probably need to be worked out. Or perhaps we can just modify our measures.

Tumour purity vs. ITH

A potential issue for inferring clonal diversity values is tumour purity. Low tumour purities reduce the effective read count contributed by non-malignant cells and hence may reduce the power of clonal inference.

tumour_purity <- read_tumour_purity(tumour_purity_file, db_path)

Old estimates

ith_vars <- c("divergence", "entropy", "composite_ith", "proportion_subclonal")
other_vars <- colnames(old_comparison)[!colnames(old_comparison) %in% ith_vars]
old_comparison_melted2 <- melt(old_comparison, id.vars = other_vars, measure.vars = ith_vars, 
    variable.name = "ithtype", value.name = "ith")

old_comparison_melted2 <- plyr::join(old_comparison_melted2, tumour_purity)
pvals <- setNames(ddply(old_comparison_melted2, .(ithtype), function(x) {
    df <- x
    corres <- with(df, cor.test(tumour_content, ith, method = "spearman"))
    
    pval <- corres$p.value
    eq <- substitute(italic(P) == p, list(p = format(pval, digits = 3)))
    return(as.character(as.expression(eq)))
}), c("ithtype", "p.value"))

ggplot(old_comparison_melted2, aes(x = tumour_content, y = ith)) + geom_point(aes(colour = patient_id)) + 
    theme_bw() + theme_Publication() + facet_wrap(~ithtype, scales = "free") + 
    scale_color_manual(values = pal_patient) + geom_text(data = pvals, aes(x = Inf, 
    y = Inf, label = p.value), hjust = 1.1, vjust = 1.5, size = 3, parse = TRUE)

Oddly enough, tumour purity has a slight negative correlation with ITH. So, more pure samples have less ITH. That’s the opposite of what we’d expect naively.

New estimates

ith_vars <- c("divergence", "entropy", "postprocessed_divergence", "proportion_subclonal", 
    "combined_ith_raw", "combined_ith_normalized")
other_vars <- colnames(new_comparison)[!colnames(new_comparison) %in% ith_vars]
new_comparison_melted2 <- melt(new_comparison, id.vars = other_vars, measure.vars = ith_vars, 
    variable.name = "ithtype", value.name = "ith")

new_comparison_melted2 <- plyr::join(new_comparison_melted2, tumour_purity)
pvals <- setNames(ddply(new_comparison_melted2, .(ithtype), function(x) {
    df <- x
    corres <- with(df, cor.test(tumour_content, ith, method = "spearman"))
    
    pval <- corres$p.value
    eq <- substitute(italic(P) == p, list(p = format(pval, digits = 3)))
    return(as.character(as.expression(eq)))
}), c("ithtype", "p.value"))

ggplot(new_comparison_melted2, aes(x = tumour_content, y = ith)) + geom_point(aes(colour = patient_id)) + 
    theme_bw() + theme_Publication() + facet_wrap(~ithtype, scales = "free") + 
    scale_color_manual(values = pal_patient) + geom_text(data = pvals, aes(x = Inf, 
    y = Inf, label = p.value), hjust = 1.1, vjust = 1.5, size = 3, parse = TRUE)

LS0tCnRpdGxlOiAiQ2xvbmFsIHN0YXRpc3RpY3MiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiA1CiAgICB0b2NfZmxvYXQ6IHRydWUKcGFyYW1zOgogIHJtZDogIml0aF9zdGF0aXN0aWNzLlJtZCIKLS0tCiAgICAgICAgICAgICAgICAgICAgICAgIGBgYHtyLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKIyMjIyMjIyMgU25ha2VtYWtlIGhlYWRlciAjIyMjIyMjIwpsaWJyYXJ5KG1ldGhvZHMpClNuYWtlbWFrZSA8LSBzZXRDbGFzcygKICAgICJTbmFrZW1ha2UiLAogICAgc2xvdHMgPSBjKAogICAgICAgIGlucHV0ID0gImxpc3QiLAogICAgICAgIG91dHB1dCA9ICJsaXN0IiwKICAgICAgICBwYXJhbXMgPSAibGlzdCIsCiAgICAgICAgd2lsZGNhcmRzID0gImxpc3QiLAogICAgICAgIHRocmVhZHMgPSAibnVtZXJpYyIsCiAgICAgICAgbG9nID0gImxpc3QiLAogICAgICAgIHJlc291cmNlcyA9ICJsaXN0IiwKICAgICAgICBjb25maWcgPSAibGlzdCIsCiAgICAgICAgcnVsZSA9ICJjaGFyYWN0ZXIiCiAgICApCikKc25ha2VtYWtlIDwtIFNuYWtlbWFrZSgKICAgIGlucHV0ID0gbGlzdCgnUm1kL2l0aF9zdGF0aXN0aWNzLlJtZCcsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMi9pdGhfc3RhdGlzdGljcy50c3YnLCAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL2FuYWx5c2lzL1JtZC9fc2l0ZS55bWwnLCAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvdGFibGVzL3J1bjIvdHVtb3VyX3B1cml0eS50c3YnLCAibm90ZWJvb2siID0gJ1JtZC9pdGhfc3RhdGlzdGljcy5SbWQnLCAiaXRoX3N0YXRzX2ZpbGUiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3RhYmxlcy9ydW4yL2l0aF9zdGF0aXN0aWNzLnRzdicsICJzaXRlX2ZpbGUiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9hbmFseXNpcy9SbWQvX3NpdGUueW1sJywgInR1bW91cl9wdXJpdHkiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3RhYmxlcy9ydW4yL3R1bW91cl9wdXJpdHkudHN2JyksCiAgICBvdXRwdXQgPSBsaXN0KCcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy93ZWIvaXRoX3N0YXRpc3RpY3MubmIuaHRtbCcpLAogICAgcGFyYW1zID0gbGlzdCgnaXRoaS1hbmFseXNpcy1pdGgtc3RhdGlzdGljcycsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvbWV0YWRhdGEvZGIvaW1tdW5lX3Byb2plY3Quc3FsaXRlMycsICJuYW1lIiA9ICdpdGhpLWFuYWx5c2lzLWl0aC1zdGF0aXN0aWNzJywgImRiIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvbWV0YWRhdGEvZGIvaW1tdW5lX3Byb2plY3Quc3FsaXRlMycpLAogICAgd2lsZGNhcmRzID0gbGlzdCgpLAogICAgdGhyZWFkcyA9IDEsCiAgICBsb2cgPSBsaXN0KCcvc2hhaGxhYi9hbHpoYW5nL2NsdXN0dG1wL3BhcGVyYW5hbHlzaXMyL2l0aF9zdGF0aXN0aWNzLmxvZycpLAogICAgcmVzb3VyY2VzID0gbGlzdCgpLAogICAgY29uZmlnID0gbGlzdCgidGNnYV9vdl9hbm5vdGF0aW9ucyIgPSAnL3NoYWhsYWIvYWx6aGFuZy9kYXRhL1RDR0EvdGNnYV9vdl9hbm5vdGF0aW9uX3N1cDEzLnR4dCcsICJwYXRpZW50c19mb3JfY2xvbmFsIiA9IGMoMSwgMiwgMywgNCwgNywgOSwgMTAsIDExLCAxMiwgMTMsIDE0LCAxNSwgMTYsIDE3KSwgIm1tY3RtX292X2NvbWJpbmVkX3Jlc3VsdF9kaXIiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9yZXN1bHRzL21tY3RtX3Jlc3VsdHMvY29tYmluZWRfb3ZfbW1jdG0vb3V0cHV0JywgIm5hbm9zdHJpbmdfZGF0YSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3Jlc3VsdHMvbmFub3N0cmluZ19yZXN1bHRzL2l0aF9mdWxsL3FjL2xpbW1hX3F1YW50aWxlL25vcm1hbGl6ZWRfZXhwcmVzc2lvbl92b2FfbGFiZWxzX2ZpbHRlcmVkLnRzdicsICJtbWN0bV9zYW1wbGVfYWRfc2lncGxvdCIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3Jlc3VsdHMvbW1jdG1fcmVzdWx0cy9pdGhfYnktYW5jZXN0cnktc2FtcGxlL3Bsb3RzL2l0aC1ieS1hbmNlc3RyYWwtc2FtcGxlX3Nudi1zdl9zaWdzX211bHRpcGFuZWwucGRmJywgImNsb25lX3RyZWVfZmlsZSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2RhdGEvaXRoL2NvbXBsZXRlL3RyZWVfZGF0YS50c3YnLCAibWFzdGVyX3ZhcmlhbnRfZmlsZSIgPSAnL3NoYWhsYWIvYW1jcGhlcnNvbi9wcm9qZWN0cy9pdGgzL2l0aDMvbm90ZWJvb2tzL2Jlc3Bva2UvaXRoX3NudnMudHN2JywgIm1tY3RtX3NhbXBsZV9zaWdwbG90IiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcmVzdWx0cy9tbWN0bV9yZXN1bHRzL2l0aF9ieS1zYW1wbGUvcGxvdHMvaXRoLWJ5LXNhbXBsZV9zbnYtc3Zfc2lnc19tdWx0aXBhbmVsLnBkZicsICJ4Y3JfcWNfbm90ZWJvb2siID0gJ1JtZC9yZXBsaWNhdGVzLlJtZCcsICJpdGhfc3RhdHNfZmlsZSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2RhdGEvaXRoL2NvbXBsZXRlL2Nsb25hbF9tZWFzdXJlcy50c3YnLCAibW9sc3VidHlwZV90aWx0eXBlcyIgPSBjKCdFX0NEOF9kZW5zaXR5JywgJ0VfQ0Q0X2RlbnNpdHknLCAnRV9DRDIwX2RlbnNpdHknLCAnRV9QbGFzbWFfZGVuc2l0eScsICdTX0NEOF9kZW5zaXR5JywgJ1NfQ0Q0X2RlbnNpdHknLCAnU19DRDIwX2RlbnNpdHknLCAnU19QbGFzbWFfZGVuc2l0eScpLCAial9kaWN0aW9uYXJ5IiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvc3VicHJvamVjdHMvaW1tdHlwZXIvbWV0YWRhdGEvaW1ndC9Ib21vX3NhcGllbnNfVFJCSi5mYXN0YScsICJ0Y2dhX2V4cHJfbWF0cml4IiA9ICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvVENHQS9leHByX21hdHJpeF9ub3JtYWxpemVfc3RhbmRhcmRpemVfbm9kdXBsaWNhdGVzLnRzdicsICJuZW9lZGl0aW5nX291dGRpciIgPSAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvbmVvZWRpdGluZy9ydW40JywgIlBOR19ERU5TSVRZIiA9IDMwMCwgIm12Y2x1c3RfdGlsdHlwZXMiID0gYygnRV9DRDhfZGVuc2l0eScsICdFX0NENF9kZW5zaXR5JywgJ0VfQ0QyMF9kZW5zaXR5JywgJ0VfUGxhc21hX2RlbnNpdHknLCAnU19DRDhfZGVuc2l0eScsICdTX0NENF9kZW5zaXR5JywgJ1NfQ0QyMF9kZW5zaXR5JywgJ1NfUGxhc21hX2RlbnNpdHknKSwgImZpZ3VyZV9nYWxsZXJ5X25vdGVib29rIiA9ICdSbWQvZmlndXJlcy5SbWQnLCAibWFzdGVyX2JyZWFrcG9pbnRfZmlsZSIgPSAnL3NoYWhsYWIvYW1jcGhlcnNvbi9wcm9qZWN0cy9pdGgzL2l0aDMvbm90ZWJvb2tzL2Jlc3Bva2UvaXRoX2JyZWFrcG9pbnRzLnRzdicsICJzaXRlX2ZpbGUiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9hbmFseXNpcy9SbWQvX3NpdGUueW1sJywgIm11bHRpdmlld2NsdXN0ZXJpbmdfbm90ZWJvb2siID0gJ1JtZC9tdWx0aXZpZXdjbHVzdGVyaW5nLlJtZCcsICJpdGhfc3RhdGlzdGljc19ub3RlYm9vayIgPSAnUm1kL2l0aF9zdGF0aXN0aWNzLlJtZCcsICJwcm9wb3J0aW9uX3N1YmNsb25hbF9maWxlIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvZGF0YS9pdGgvY29tcGxldGUvb2xkX3Byb3BvcnRpb25fc3ViY2xvbmFsLnRzdicsICJkYiIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL21ldGFkYXRhL2RiL2ltbXVuZV9wcm9qZWN0LnNxbGl0ZTMnLCAiaWdwYXJ0aXRpb25fb3V0ZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9pZ3BhcnRpdGlvbi9ydW4yMicsICJ2X2RpY3Rpb25hcnkiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9zdWJwcm9qZWN0cy9pbW10eXBlci9tZXRhZGF0YS9pbWd0L0hvbW9fc2FwaWVuc19UUkJWLmZhc3RhJywgIm5jbHVzdHMiID0gMywgImluZGV4X25vdGVib29rIiA9ICdSbWQvaW5kZXguUm1kJywgImljZ2NfZXhwcl9tZWx0ZWQiID0gJy9zaGFobGFiL2FsemhhbmcvZGF0YS9JQ0dDL09WQVVfZXhwcl9tZWx0ZWQudHN2JywgImloY19ydW4yIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvZGF0YS9paGMvY2Q3OWNkMTM4Y2Q2OC92YWxpZGF0ZWRfc3RhdHNfd2VpZ2h0ZWQucmRhdGEnLCAiZHJpdmVyX21hcCIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3N1YnByb2plY3RzL2RyaXZlcnMvZGF0YS9nZW5lX2xpc3RfbWFwcGVkLmJlZCcsICJpdGhfcHJvamVjdF9yZXN1bHRzIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL2l0aDMvZGF0YS9yZXN1bHRzJywgImJjcl9jbG9ub3R5cGVzIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9taXhjci9taXhjcl9ydW5zL2l0aF8xXzJfMy9taXhjcjUvY2xvbm90eXBlcy9JR0hfY2xvbm90eXBlc19maWx0ZXJlZC50eHQnLCAibGlicmFyeV9zaXplcyIgPSAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvbWl4Y3IvbWl4Y3JfcnVucy9pdGhfMV8yXzMvbWl4Y3I1L2xpYnJhcnlfc2l6ZXMudHN2JywgIm11dHNpZ190aWx0eXBlcyIgPSBjKCdFX0NEOF9kZW5zaXR5JywgJ0VfQ0Q0X2RlbnNpdHknLCAnRV9DRDIwX2RlbnNpdHknLCAnRV9QbGFzbWFfZGVuc2l0eScsICdTX0NEOF9kZW5zaXR5JywgJ1NfQ0Q0X2RlbnNpdHknLCAnU19DRDIwX2RlbnNpdHknLCAnU19QbGFzbWFfZGVuc2l0eScsICdUX0NEOF9kZW5zaXR5JywgJ1RfQ0Q0X2RlbnNpdHknLCAnVF9DRDIwX2RlbnNpdHknLCAnVF9QbGFzbWFfZGVuc2l0eScpLCAieGNyX2Rpc3RhbmNlX21ldGhvZCIgPSAnaG9ybicsICJpY2djX2NsaW5pY2FsIiA9ICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvSUNHQy9kb25vci5PVi1BVS50c3YnLCAiaWhjX3hjcl9zdGF0c19ub3RlYm9vayIgPSAnUm1kL2loY194Y3Jfc3RhdHMuUm1kJywgInRpbF9jbGFzc2lmaWVyX25vdGVib29rIiA9ICdSbWQvdGlsX2NsYXNzaWZpZXIuUm1kJywgInRjcl9jbG9ub3R5cGVzIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9taXhjci9taXhjcl9ydW5zL2l0aF8xXzJfMy9taXhjcjUvY2xvbm90eXBlcy9UUkJfY2xvbm90eXBlc19maWx0ZXJlZC50eHQnLCAiaW1tdHlwZXJfbW9kZWxzIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcmVzdWx0cy9pbW10eXBlcl9yZXN1bHRzL2tsYXJlbmJlZWsvYWFfdmovZ3JhZGJvb3N0JywgImloY19ydW4xIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvZGF0YS9paGMvY2Q4Y2QzY2QyMC92YWxpZGF0ZWRfc3RhdHNfd2VpZ2h0ZWRfbmV3LnJkYXRhJywgInBoZW5vdHlwZV90aHJlc2hvbGQiID0gMC44NSwgImRlZmF1bHRfc2FtcGxlciIgPSAnSE1DJywgIm1tY3RtX292X2NvbWJpbmVkX3NpZ3Bsb3QiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9yZXN1bHRzL21tY3RtX3Jlc3VsdHMvY29tYmluZWRfb3ZfbW1jdG0vcGxvdHMvb3Zfc252LXN2X3NpZ3NfbXVsdGlwYW5lbC5wZGYnLCAiaXRoX3N0YXRfdHlwZXMiID0gYygnZW50cm9weScsICdwb3N0cHJvY2Vzc2VkX2RpdmVyZ2VuY2UnLCAnY29tYmluZWRfaXRoX25vcm1hbGl6ZWQnLCAncHJvcG9ydGlvbl9zdWJjbG9uYWwnKSwgImJjcnBoeWxvX2NvcnJlbGF0aW9uc19ub3RlYm9vayIgPSAnUm1kL2Jjcl9waHlsb19jb3JyZWxhdGlvbnMuUm1kJywgImNsb25hbF9zYW1wbGVycyIgPSBjKCdITUMnLCAnTlVUUycpLCAid2FuZ19mYmlfc3RhdHVzIiA9ICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvSUNHQy9uZy4zODQ5LVMxMi50eHQnLCAibW1jdG1fcGF0aWVudF9hbmNlc3RyYWxfZGVzY2VuZGFudF9yZXN1bHRfZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcmVzdWx0cy9tbWN0bV9yZXN1bHRzL2l0aF9ieS1wYXRpZW50LWFuY2VzdHJ5L291dHB1dCcsICJjbG9uZV9wcmV2YWxlbmNlX2ZpbGUiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9kYXRhL2l0aC9jb21wbGV0ZS9jbG9uZV9kYXRhLnRzdicsICJ0Y3JfZGl2ZXJzaXR5IiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9taXhjci9taXhjcl9ydW5zL2l0aF8xXzJfMy9taXhjcjUvcG9zdHByb2Nlc3MvVFJCL3Bvc3RmaWx0ZXJfZGl2ZXJzaXR5X3N0YXRzL2RpdmVyc2l0eS5zdHJpY3QucmVzYW1wbGVkLnR4dCcsICJ4Y3JfY2xvbmVzX25vdGVib29rIiA9ICdSbWQveGNyX2Nsb25lc19hbmFseXNpcy5SbWQnLCAic3VidHlwZV9tYXJrZXJfZmlsZSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2RhdGEvZXhwcmVzc2lvbi9uYW5vc3RyaW5nL3N1YnR5cGVfbWFya2Vycy50c3YnLCAibm90ZWJvb2tfZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy93ZWInLCAibW1jdG1fZmluYWxfcGF0aWVudF9kaXIiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9yZXN1bHRzL21tY3RtX3Jlc3VsdHMvaXRoX2J5LXBhdGllbnRfd2l0aC1vdicsICJ0aWxzX2Zvcl92YXJpYWJpbGl0eSIgPSBjKCdFX0NEOF9kZW5zaXR5JywgJ0VfQ0Q0X2RlbnNpdHknLCAnRV9DRDIwX2RlbnNpdHknLCAnRV9QbGFzbWFfZGVuc2l0eScsICdTX0NEOF9kZW5zaXR5JywgJ1NfQ0Q0X2RlbnNpdHknLCAnU19DRDIwX2RlbnNpdHknLCAnU19QbGFzbWFfZGVuc2l0eScpLCAidGlsc19mb3JfY2x1c3RlciIgPSBjKCdFX0NEOF9kZW5zaXR5JywgJ0VfQ0Q0X2RlbnNpdHknLCAnRV9DRDIwX2RlbnNpdHknLCAnRV9QbGFzbWFfZGVuc2l0eScsICdTX0NEOF9kZW5zaXR5JywgJ1NfQ0Q0X2RlbnNpdHknLCAnU19DRDIwX2RlbnNpdHknLCAnU19QbGFzbWFfZGVuc2l0eScpLCAiaW1tdW5lX3ZhcmlhYmlsaXR5X25vdGVib29rIiA9ICdSbWQvaW1tdW5lX3ZhcmlhYmlsaXR5LlJtZCcsICJkcml2ZXJfYW5hbHlzaXNfbm90ZWJvb2siID0gJ1JtZC9kcml2ZXJfYW5hbHlzaXMuUm1kJywgIm5hbm9zdHJpbmdfYW5ub3RhdGlvbnMiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9kYXRhL2V4cHJlc3Npb24vbmFub3N0cmluZy9wYW5jYW5jZXJfYW5ub3RhdGlvbnMudHN2JywgImloY194Y3JfdGlsdHlwZXMiID0gYygnRV9DRDhfZGVuc2l0eScsICdFX0NENF9kZW5zaXR5JywgJ0VfQ0QyMF9kZW5zaXR5JywgJ0VfUGxhc21hX2RlbnNpdHknLCAnU19DRDhfZGVuc2l0eScsICdTX0NENF9kZW5zaXR5JywgJ1NfQ0QyMF9kZW5zaXR5JywgJ1NfUGxhc21hX2RlbnNpdHknLCAnVF9DRDhfZGVuc2l0eScsICdUX0NENF9kZW5zaXR5JywgJ1RfQ0QyMF9kZW5zaXR5JywgJ1RfUGxhc21hX2RlbnNpdHknKSwgImV4YW1wbGVfYW5ub3RhdGlvbnMiID0gJy9zaGFobGFiL2FsemhhbmcvcGlwZWxpbmVfb3V0cHV0cy9pdGhfaW1tdW5lL2lncGFydGl0aW9uL3J1bjEzL2ZpbmFsX3BhcnRpdGlvbnMvaXRoMl8yL2NsdXN0OS9hbm5vdGF0aW9uc19mbGFnZ2VkLnRzdicsICJrbm93bl9zdWJ0eXBlX2ZpbGUiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9kYXRhL2V4cHJlc3Npb24vYXJyYXkvc3VidHlwZXMva25vd25fc3VidHlwZXMudHN2JywgIm1hcHNjYXBlX25vdGVib29rIiA9ICdSbWQvbWFwc2NhcGUuUm1kJywgImljZ2NfbW9sZWN1bGFyX3N1YnR5cGVzIiA9ICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvSUNHQy9pY2djX3ByaW1hcnlfdHVtb3VyX3N1YnR5cGVzLnRzdicsICJleGFtcGxlX21zYV9wbG90IiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9pZ3BhcnRpdGlvbi9ydW4xMy9vbGQvYWxpZ25tZW50X3Bsb3RzL21zYS9pdGgyXzIvY2x1c3Q5L2luZGVsX3JldmVyc2VkLmh0bWwnLCAiYmNyX2RpdmVyc2l0eSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvbWl4Y3IvbWl4Y3JfcnVucy9pdGhfMV8yXzMvbWl4Y3I1L3Bvc3Rwcm9jZXNzL0lHSC9wb3N0ZmlsdGVyX2RpdmVyc2l0eV9zdGF0cy9kaXZlcnNpdHkuc3RyaWN0LnJlc2FtcGxlZC50eHQnLCAidmFyaWFiaWxpdHlfdHlwZSIgPSAnc3RhYmlsaXplJywgInhjcm1hcHNjYXBlX25vdGVib29rIiA9ICdSbWQveGNybWFwc2NhcGUuUm1kJywgIm12Y2x1c3RfbmNsdXN0IiA9IDMsICJjbG9uZV9icmFuY2hfbGVuZ3RoX2ZpbGUiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9kYXRhL2l0aC9jb21wbGV0ZS9icmFuY2hfZGF0YS50c3YnLCAic2FkX25vdGVib29rIiA9ICdSbWQvc3BlY2llc19hYnVuZGFuY2VfZGlzdHJpYnV0aW9ucy5SbWQnLCAieGNyX21hcHBpbmdfbm90ZWJvb2siID0gJ1JtZC94Y3JfbWFwcGluZy5SbWQnLCAibmVvYW50aWdlbl9lZGl0aW5nX25vdGVib29rIiA9ICdSbWQvaW1tdW5vZWRpdGluZy5SbWQnLCAidGFibGVfZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy90YWJsZXMvcnVuMicsICJpY2djX3NwZWNpbWVuX2ZpbGUiID0gJy9zaGFobGFiL2FsemhhbmcvZGF0YS9JQ0dDL3NwZWNpbWVuLnRzdicsICJtbWN0bV9maW5hbF9wYXRpZW50X3NpZ3Bsb3QiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9yZXN1bHRzL21tY3RtX3Jlc3VsdHMvaXRoX2J5LXBhdGllbnRfd2l0aC1vdi9wbG90cy9pdGgtYnktcGF0aWVudF9zbnYtc3Zfc2lnc19tdWx0aXBhbmVsLnBkZicsICJ0Y2dhX2NsaW5pY2FsIiA9ICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvVENHQS9zeW5hcHNlX2NsaW5BbGxfZGF0YS50c3YnLCAibW1jdG1fc2FtcGxlX3Jlc3VsdF9kaXIiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9yZXN1bHRzL21tY3RtX3Jlc3VsdHMvaXRoX2J5LXNhbXBsZS9vdXRwdXQnLCAiaW1tdHlwZXJfbGVuZ3RocyIgPSAnMTEgMTIgMTMgMTQgMTUgMTYgMTcgMTgnLCAiYmNycGh5bG9fZXhhbXBsZXNfbm90ZWJvb2siID0gJ1JtZC9iY3JfcGh5bG9fZXhhbXBsZXMuUm1kJywgIm1tY3RtX3BhdGllbnRfYWRfc2lncGxvdCIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3Jlc3VsdHMvbW1jdG1fcmVzdWx0cy9pdGhfYnktcGF0aWVudC1hbmNlc3RyeS9wbG90cy9pdGgtYnktcGF0aWVudC1hbmNlc3RyeV9zbnYtc3Zfc2lnc19tdWx0aXBhbmVsLnBkZicsICJiY3JwaHlsb190aWx0eXBlcyIgPSBjKCdFX0NEOF9kZW5zaXR5JywgJ0VfQ0Q0X2RlbnNpdHknLCAnRV9DRDIwX2RlbnNpdHknLCAnRV9QbGFzbWFfZGVuc2l0eScsICdTX0NEOF9kZW5zaXR5JywgJ1NfQ0Q0X2RlbnNpdHknLCAnU19DRDIwX2RlbnNpdHknLCAnU19QbGFzbWFfZGVuc2l0eScsICdUX0NEOF9kZW5zaXR5JywgJ1RfQ0Q0X2RlbnNpdHknLCAnVF9DRDIwX2RlbnNpdHknLCAnVF9QbGFzbWFfZGVuc2l0eScpLCAiY2xhc3NpZmllcl90eXBlIiA9ICdrbm4nLCAiaXRoX3RpbF9ub3RlYm9vayIgPSAnUm1kL2l0aF90aWxfZGVuc2l0aWVzLlJtZCcsICJQTkdfUVVBTElUWSIgPSAzMDAsICJrbm93bl9zdWJ0eXBlc19tZXJnZWQiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9kYXRhL2V4cHJlc3Npb24va25vd25fc3VidHlwZXNfbWVyZ2VkLnRzdicsICJpbnRlcm1lZGlhdGVfZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy9pbnRlcm1lZGlhdGVzL3J1bjInLCAibmFub3N0cmluZ19zaWduYXR1cmVfbm90ZWJvb2siID0gJ1JtZC9uYW5vc3RyaW5nX3NpZ25hdHVyZXMuUm1kJywgIm1tY3RtX2FuY2VzdHJhbF9kZXNjZW5kYW50X3Jlc3VsdF9kaXIiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9yZXN1bHRzL21tY3RtX3Jlc3VsdHMvaXRoX2J5LWFuY2VzdHJ5LXNhbXBsZS9vdXRwdXQnLCAiYmVuY2htYXJrZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL2JlbmNobWFya3MvcGFwZXJhbmFseXNpczInLCAibW9sc3VidHlwZV9ub3RlYm9vayIgPSAnUm1kL21vbGVjdWxhcl9zdWJ0eXBlcy5SbWQnLCAic3BhdGlhbF9yZXN1bHRfZGlycyIgPSBsaXN0KCJlcGl0aGVsaWFsIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9zcGF0c2ltL2l0aDMvYWJjJywgInN0cm9tYWwiID0gJy9zaGFobGFiL2FsemhhbmcvcGlwZWxpbmVfb3V0cHV0cy9pdGhfaW1tdW5lL3NwYXRzaW0vaXRoNS9hYmMnKSwgInNwYXRpYWxfbm90ZWJvb2siID0gJ1JtZC9zcGF0aWFsX2FuYWx5c2lzLlJtZCcsICJpY2djX25vcm1hbGl6ZWRfcmVhZHNfbWF0cml4IiA9ICcvc2hhaGxhYi9hbHpoYW5nL2RhdGEvSUNHQy9PVkFVX2V4cHJfbWF0cml4LnRzdicsICJtdXRhdGlvbl9zaWduYXR1cmVfbm90ZWJvb2siID0gJ1JtZC9tdXRhdGlvbl9zaWduYXR1cmVzLlJtZCcsICJwcmV2YWxlbmNlX3RocmVzaG9sZCIgPSAwLjAxLCAibG9nZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL2NsdXN0dG1wL3BhcGVyYW5hbHlzaXMyJyksCiAgICBydWxlID0gJ2l0aF9zdGF0aXN0aWNzJwopCiMjIyMjIyMjIE9yaWdpbmFsIHNjcmlwdCAjIyMjIyMjIyMKCiAgICAgICAgICAgICAgICAgICAgICAgIGBgYAoKCmBgYHtyIGdsb2JhbF9jaHVua19vcHRpb25zLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIHRpZHk9VFJVRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSkKYGBgCgoKYGBge3J9CmxpYnJhcnkoaXRoaS51dGlscykKbG9hZF9iYXNlX2xpYnMoKQoKbGlicmFyeShpdGhpLm1ldGEpCmxpYnJhcnkoaXRoaS5jbG9uZXMpCmxpYnJhcnkoaXRoaS5zZXEpCmBgYAoKIyMgQ29sb3VyIHBhbGV0dGVzCgpgYGB7cn0KcGFsX3BhdGllbnQgPC0gc2VsZWN0X3BhbGV0dGUoInBhdGllbnQiKQpgYGAKCiMjIFBhcmFtZXRlcnMKCmBgYHtyfQpkYl9wYXRoIDwtIHNuYWtlbWFrZUBwYXJhbXMkZGIKCml0aF9zdGF0c19maWxlIDwtIHNuYWtlbWFrZUBpbnB1dCRpdGhfc3RhdHMKI3Byb3BvcnRpb25fc3ViY2xvbmFsaXR5X2ZpbGUgPC0gc25ha2VtYWtlQGlucHV0JHN1YmNsb25hbGl0eQp0dW1vdXJfcHVyaXR5X2ZpbGUgPC0gc25ha2VtYWtlQGlucHV0JHR1bW91cl9wdXJpdHkKCm9sZF9yZXN1bHRfZmlsZSA8LSAiL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2RhdGEvaXRoL29sZF9pdGhfY29tcGFyaXNvbi50c3YiCmBgYAoKIyMgTWV0YWRhdGEKCmBgYHtyfQpkYiA8LSBzcmNfc3FsaXRlKGRiX3BhdGgsIGNyZWF0ZT1GQUxTRSkKc2FtcGxlcyA8LSBjb2xsZWN0KHRibChkYiwgInNhbXBsZXMiKSkKYGBgCgojIyBEZXNjcmlwdGlvbgoKTmV3IGNsb25hbCBwcmVkaWN0aW9ucyBhcmUgc3RpbGwgdW5kZXIgYSBsb3Qgb2Ygd29yayBzbyB3ZSBoYXZlIHRvIHZhbGlkYXRlIHRoZWlyIHF1YWxpdHkuIAoKIyMjIE9sZCBjbG9uYWwgcHJlZGljdGlvbnMKCkhlcmUncyB3aGF0IHRoaW5ncyBsb29rZWQgbGlrZSB1bmRlciB0aGUgb2xkIHNldCBvZiBwcmVkaWN0aW9uczoKCmBgYHtyfQpvbGRfY29tcGFyaXNvbiA8LSBmcmVhZChvbGRfcmVzdWx0X2ZpbGUpCm9sZF9jb21wYXJpc29uJHBhdGllbnRfaWQgPC0gZmFjdG9yKG9sZF9jb21wYXJpc29uJHBhdGllbnRfaWQpCgppdGhfdmFycyA8LSBjKCJkaXZlcmdlbmNlIiwgImVudHJvcHkiLCAiY29tcG9zaXRlX2l0aCIpCm90aGVyX3ZhcnMgPC0gY29sbmFtZXMob2xkX2NvbXBhcmlzb24pWyFjb2xuYW1lcyhvbGRfY29tcGFyaXNvbikgJWluJSBpdGhfdmFyc10Kb2xkX2NvbXBhcmlzb25fbWVsdGVkIDwtIG1lbHQob2xkX2NvbXBhcmlzb24sIGlkLnZhcnMgPSBvdGhlcl92YXJzLCBtZWFzdXJlLnZhcnMgPSBpdGhfdmFycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyaWFibGUubmFtZSA9ICJpdGh0eXBlIiwgdmFsdWUubmFtZSA9ICJpdGgiKQpgYGAKCmBgYHtyfQpwdmFscyA8LSBzZXROYW1lcyhkZHBseShvbGRfY29tcGFyaXNvbl9tZWx0ZWQsIC4oaXRodHlwZSksIGZ1bmN0aW9uKHgpIHsKICBkZiA8LSB4CiAgY29ycmVzIDwtIHdpdGgoZGYsIGNvci50ZXN0KHByb3BvcnRpb25fc3ViY2xvbmFsLCBpdGgsIG1ldGhvZD0ic3BlYXJtYW4iKSkKICAKICBwdmFsIDwtIGNvcnJlcyRwLnZhbHVlCiAgZXEgPC0gc3Vic3RpdHV0ZShpdGFsaWMoUCk9PXAsIGxpc3QocD1mb3JtYXQocHZhbCwgZGlnaXRzPTMpKSkKICByZXR1cm4oYXMuY2hhcmFjdGVyKGFzLmV4cHJlc3Npb24oZXEpKSkKfSksIGMoIml0aHR5cGUiLCAicC52YWx1ZSIpKQoKZ2dwbG90KG9sZF9jb21wYXJpc29uX21lbHRlZCwgYWVzKHg9cHJvcG9ydGlvbl9zdWJjbG9uYWwsIHk9aXRoKSkgKyBnZW9tX3BvaW50KGFlcyhjb2xvdXI9cGF0aWVudF9pZCkpICsgdGhlbWVfYncoKSArIHRoZW1lX1B1YmxpY2F0aW9uKCkgKyBmYWNldF93cmFwKH4gaXRodHlwZSwgc2NhbGVzID0gImZyZWUiKSArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxfcGF0aWVudCkgKyBnZW9tX3RleHQoZGF0YT1wdmFscywgYWVzKHg9SW5mLCB5PUluZiwgbGFiZWw9cC52YWx1ZSksIGhqdXN0PTEuMSwgdmp1c3Q9MS41LHNpemU9MyxwYXJzZT1UUlVFKSAKYGBgCgpUaGlzIGlzIHdoYXQgd2UgZXhwZWN0IHRvIHNlZTogYSByZWFzb25hYmx5IGdvb2QgY29ycmVsYXRpb24gYmV0d2VlbiBuYWl2ZSBtZWFzdXJlcyBvZiBJVEggYW5kIG1vcmUgInJpZ29yb3VzIiBtZWFzdXJlcy4gCgoKIyMjIE5ldyBjbG9uYWwgcHJlZGljdGlvbnMKCmBgYHtyfQppdGhfc3RhdHMgPC0gcmVhZF9pdGhfc3RhdHMoaXRoX3N0YXRzX2ZpbGUsIGRiX3BhdGgsIGR1cGxpY2F0ZXM9RkFMU0UpCiNzdWJjbG9uYWxpdHkgPC0gZnJlYWQocHJvcG9ydGlvbl9zdWJjbG9uYWxpdHlfZmlsZSkKCiNuZXdfY29tcGFyaXNvbiA8LSBtZXJnZShpdGhfc3RhdHMsIHN1YmNsb25hbGl0eSwgYnk9YygiY29uZGVuc2VkX2lkIiwgInBhdGllbnRfaWQiKSkKbmV3X2NvbXBhcmlzb24gPC0gaXRoX3N0YXRzCgppdGhfdmFycyA8LSBjKCJkaXZlcmdlbmNlIiwgImVudHJvcHkiLCAicG9zdHByb2Nlc3NlZF9kaXZlcmdlbmNlIiwgImNvbWJpbmVkX2l0aF9yYXciLCAiY29tYmluZWRfaXRoX25vcm1hbGl6ZWQiKQpvdGhlcl92YXJzIDwtIGNvbG5hbWVzKG5ld19jb21wYXJpc29uKVshY29sbmFtZXMobmV3X2NvbXBhcmlzb24pICVpbiUgaXRoX3ZhcnNdCm5ld19jb21wYXJpc29uX21lbHRlZCA8LSBtZWx0KG5ld19jb21wYXJpc29uLCBpZC52YXJzID0gb3RoZXJfdmFycywgbWVhc3VyZS52YXJzID0gaXRoX3ZhcnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlLm5hbWUgPSAiaXRodHlwZSIsIHZhbHVlLm5hbWUgPSAiaXRoIikKYGBgCgoKCmBgYHtyfQpwdmFscyA8LSBzZXROYW1lcyhkZHBseShuZXdfY29tcGFyaXNvbl9tZWx0ZWQsIC4oaXRodHlwZSksIGZ1bmN0aW9uKHgpIHsKICBkZiA8LSB4CiAgY29ycmVzIDwtIHdpdGgoZGYsIGNvci50ZXN0KHByb3BvcnRpb25fc3ViY2xvbmFsLCBpdGgsIG1ldGhvZD0ic3BlYXJtYW4iKSkKICAKICBwdmFsIDwtIGNvcnJlcyRwLnZhbHVlCiAgZXEgPC0gc3Vic3RpdHV0ZShpdGFsaWMoUCk9PXAsIGxpc3QocD1mb3JtYXQocHZhbCwgZGlnaXRzPTMpKSkKICByZXR1cm4oYXMuY2hhcmFjdGVyKGFzLmV4cHJlc3Npb24oZXEpKSkKfSksIGMoIml0aHR5cGUiLCAicC52YWx1ZSIpKQoKZ2dwbG90KG5ld19jb21wYXJpc29uX21lbHRlZCwgYWVzKHg9cHJvcG9ydGlvbl9zdWJjbG9uYWwsIHk9aXRoKSkgKyBnZW9tX3BvaW50KGFlcyhjb2xvdXI9cGF0aWVudF9pZCkpICsgdGhlbWVfYncoKSArIHRoZW1lX1B1YmxpY2F0aW9uKCkgKyBmYWNldF93cmFwKH4gaXRodHlwZSwgc2NhbGVzID0gImZyZWUiKSArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxfcGF0aWVudCkgKyBnZW9tX3RleHQoZGF0YT1wdmFscywgYWVzKHg9SW5mLCB5PUluZiwgbGFiZWw9cC52YWx1ZSksIGhqdXN0PTEuMSwgdmp1c3Q9MS41LHNpemU9MyxwYXJzZT1UUlVFKSAKYGBgCgpBcyBvZiBub3csIHRoZXNlIGFyZSBwcmV0dHkgdGVycmlibGUsIHN1Z2dlc3RpbmcgdGhhdCB0aGUgY2xvbmFsIHByZWRpY3Rpb25zIHByb2JhYmx5IG5lZWQgdG8gYmUgd29ya2VkIG91dC4gT3IgcGVyaGFwcyB3ZSBjYW4ganVzdCBtb2RpZnkgb3VyIG1lYXN1cmVzLiAKCiMjIFR1bW91ciBwdXJpdHkgdnMuIElUSAoKQSBwb3RlbnRpYWwgaXNzdWUgZm9yIGluZmVycmluZyBjbG9uYWwgZGl2ZXJzaXR5IHZhbHVlcyBpcyB0dW1vdXIgcHVyaXR5LiBMb3cgdHVtb3VyIHB1cml0aWVzIHJlZHVjZSB0aGUgZWZmZWN0aXZlIHJlYWQgY291bnQgY29udHJpYnV0ZWQgYnkgbm9uLW1hbGlnbmFudCBjZWxscyBhbmQgaGVuY2UgbWF5IHJlZHVjZSB0aGUgcG93ZXIgb2YgY2xvbmFsIGluZmVyZW5jZS4gCgpgYGB7cn0KdHVtb3VyX3B1cml0eSA8LSByZWFkX3R1bW91cl9wdXJpdHkodHVtb3VyX3B1cml0eV9maWxlLCBkYl9wYXRoKQpgYGAKCiMjIyBPbGQgZXN0aW1hdGVzCgpgYGB7cn0KaXRoX3ZhcnMgPC0gYygiZGl2ZXJnZW5jZSIsICJlbnRyb3B5IiwgImNvbXBvc2l0ZV9pdGgiLCAicHJvcG9ydGlvbl9zdWJjbG9uYWwiKQpvdGhlcl92YXJzIDwtIGNvbG5hbWVzKG9sZF9jb21wYXJpc29uKVshY29sbmFtZXMob2xkX2NvbXBhcmlzb24pICVpbiUgaXRoX3ZhcnNdCm9sZF9jb21wYXJpc29uX21lbHRlZDIgPC0gbWVsdChvbGRfY29tcGFyaXNvbiwgaWQudmFycyA9IG90aGVyX3ZhcnMsIG1lYXN1cmUudmFycyA9IGl0aF92YXJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZS5uYW1lID0gIml0aHR5cGUiLCB2YWx1ZS5uYW1lID0gIml0aCIpCgpvbGRfY29tcGFyaXNvbl9tZWx0ZWQyIDwtIHBseXI6OmpvaW4ob2xkX2NvbXBhcmlzb25fbWVsdGVkMiwgdHVtb3VyX3B1cml0eSkKYGBgCgpgYGB7cn0KcHZhbHMgPC0gc2V0TmFtZXMoZGRwbHkob2xkX2NvbXBhcmlzb25fbWVsdGVkMiwgLihpdGh0eXBlKSwgZnVuY3Rpb24oeCkgewogIGRmIDwtIHgKICBjb3JyZXMgPC0gd2l0aChkZiwgY29yLnRlc3QodHVtb3VyX2NvbnRlbnQsIGl0aCwgbWV0aG9kPSJzcGVhcm1hbiIpKQogIAogIHB2YWwgPC0gY29ycmVzJHAudmFsdWUKICBlcSA8LSBzdWJzdGl0dXRlKGl0YWxpYyhQKT09cCwgbGlzdChwPWZvcm1hdChwdmFsLCBkaWdpdHM9MykpKQogIHJldHVybihhcy5jaGFyYWN0ZXIoYXMuZXhwcmVzc2lvbihlcSkpKQp9KSwgYygiaXRodHlwZSIsICJwLnZhbHVlIikpCgpnZ3Bsb3Qob2xkX2NvbXBhcmlzb25fbWVsdGVkMiwgYWVzKHg9dHVtb3VyX2NvbnRlbnQsIHk9aXRoKSkgKyBnZW9tX3BvaW50KGFlcyhjb2xvdXI9cGF0aWVudF9pZCkpICsgdGhlbWVfYncoKSArIHRoZW1lX1B1YmxpY2F0aW9uKCkgKyBmYWNldF93cmFwKH4gaXRodHlwZSwgc2NhbGVzID0gImZyZWUiKSArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxfcGF0aWVudCkgKyBnZW9tX3RleHQoZGF0YT1wdmFscywgYWVzKHg9SW5mLCB5PUluZiwgbGFiZWw9cC52YWx1ZSksIGhqdXN0PTEuMSwgdmp1c3Q9MS41LHNpemU9MyxwYXJzZT1UUlVFKSAKYGBgCgoKT2RkbHkgZW5vdWdoLCB0dW1vdXIgcHVyaXR5IGhhcyBhIHNsaWdodCBuZWdhdGl2ZSBjb3JyZWxhdGlvbiB3aXRoIElUSC4gU28sIG1vcmUgcHVyZSBzYW1wbGVzIGhhdmUgbGVzcyBJVEguIFRoYXQncyB0aGUgb3Bwb3NpdGUgb2Ygd2hhdCB3ZSdkIGV4cGVjdCBuYWl2ZWx5LiAKCiMjIyBOZXcgZXN0aW1hdGVzCgpgYGB7cn0KaXRoX3ZhcnMgPC0gYygiZGl2ZXJnZW5jZSIsICJlbnRyb3B5IiwgInBvc3Rwcm9jZXNzZWRfZGl2ZXJnZW5jZSIsICJwcm9wb3J0aW9uX3N1YmNsb25hbCIsICJjb21iaW5lZF9pdGhfcmF3IiwgImNvbWJpbmVkX2l0aF9ub3JtYWxpemVkIikKb3RoZXJfdmFycyA8LSBjb2xuYW1lcyhuZXdfY29tcGFyaXNvbilbIWNvbG5hbWVzKG5ld19jb21wYXJpc29uKSAlaW4lIGl0aF92YXJzXQpuZXdfY29tcGFyaXNvbl9tZWx0ZWQyIDwtIG1lbHQobmV3X2NvbXBhcmlzb24sIGlkLnZhcnMgPSBvdGhlcl92YXJzLCBtZWFzdXJlLnZhcnMgPSBpdGhfdmFycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyaWFibGUubmFtZSA9ICJpdGh0eXBlIiwgdmFsdWUubmFtZSA9ICJpdGgiKQoKbmV3X2NvbXBhcmlzb25fbWVsdGVkMiA8LSBwbHlyOjpqb2luKG5ld19jb21wYXJpc29uX21lbHRlZDIsIHR1bW91cl9wdXJpdHkpCmBgYAoKYGBge3J9CnB2YWxzIDwtIHNldE5hbWVzKGRkcGx5KG5ld19jb21wYXJpc29uX21lbHRlZDIsIC4oaXRodHlwZSksIGZ1bmN0aW9uKHgpIHsKICBkZiA8LSB4CiAgY29ycmVzIDwtIHdpdGgoZGYsIGNvci50ZXN0KHR1bW91cl9jb250ZW50LCBpdGgsIG1ldGhvZD0ic3BlYXJtYW4iKSkKICAKICBwdmFsIDwtIGNvcnJlcyRwLnZhbHVlCiAgZXEgPC0gc3Vic3RpdHV0ZShpdGFsaWMoUCk9PXAsIGxpc3QocD1mb3JtYXQocHZhbCwgZGlnaXRzPTMpKSkKICByZXR1cm4oYXMuY2hhcmFjdGVyKGFzLmV4cHJlc3Npb24oZXEpKSkKfSksIGMoIml0aHR5cGUiLCAicC52YWx1ZSIpKQoKZ2dwbG90KG5ld19jb21wYXJpc29uX21lbHRlZDIsIGFlcyh4PXR1bW91cl9jb250ZW50LCB5PWl0aCkpICsgZ2VvbV9wb2ludChhZXMoY29sb3VyPXBhdGllbnRfaWQpKSArIHRoZW1lX2J3KCkgKyB0aGVtZV9QdWJsaWNhdGlvbigpICsgZmFjZXRfd3JhcCh+IGl0aHR5cGUsIHNjYWxlcyA9ICJmcmVlIikgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsX3BhdGllbnQpICsgZ2VvbV90ZXh0KGRhdGE9cHZhbHMsIGFlcyh4PUluZiwgeT1JbmYsIGxhYmVsPXAudmFsdWUpLCBoanVzdD0xLjEsIHZqdXN0PTEuNSxzaXplPTMscGFyc2U9VFJVRSkgCmBgYA==