Contents

1 Setup and data

source("../utils/utils.R")
   ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
   ✔ dplyr     1.1.2     ✔ readr     2.1.4
   ✔ forcats   1.0.0     ✔ stringr   1.5.0
   ✔ ggplot2   3.4.4     ✔ tibble    3.2.1
   ✔ lubridate 1.9.2     ✔ tidyr     1.3.0
   ✔ purrr     1.0.1     
   ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
   ✖ dplyr::filter() masks stats::filter()
   ✖ dplyr::lag()    masks stats::lag()
   ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
   
   Attaching package: 'magrittr'
   
   
   The following object is masked from 'package:purrr':
   
       set_names
   
   
   The following object is masked from 'package:tidyr':
   
       extract
   
   
   Loading required package: GenomicRanges
   
   Loading required package: stats4
   
   Loading required package: BiocGenerics
   
   
   Attaching package: 'BiocGenerics'
   
   
   The following objects are masked from 'package:lubridate':
   
       intersect, setdiff, union
   
   
   The following objects are masked from 'package:dplyr':
   
       combine, intersect, setdiff, union
   
   
   The following objects are masked from 'package:stats':
   
       IQR, mad, sd, var, xtabs
   
   
   The following objects are masked from 'package:base':
   
       anyDuplicated, aperm, append, as.data.frame, basename, cbind,
       colnames, dirname, do.call, duplicated, eval, evalq, Filter, Find,
       get, grep, grepl, intersect, is.unsorted, lapply, Map, mapply,
       match, mget, order, paste, pmax, pmax.int, pmin, pmin.int,
       Position, rank, rbind, Reduce, rownames, sapply, setdiff, sort,
       table, tapply, union, unique, unsplit, which.max, which.min
   
   
   Loading required package: S4Vectors
   
   
   Attaching package: 'S4Vectors'
   
   
   The following objects are masked from 'package:lubridate':
   
       second, second<-
   
   
   The following objects are masked from 'package:dplyr':
   
       first, rename
   
   
   The following object is masked from 'package:tidyr':
   
       expand
   
   
   The following objects are masked from 'package:base':
   
       expand.grid, I, unname
   
   
   Loading required package: IRanges
   
   
   Attaching package: 'IRanges'
   
   
   The following object is masked from 'package:lubridate':
   
       %within%
   
   
   The following objects are masked from 'package:dplyr':
   
       collapse, desc, slice
   
   
   The following object is masked from 'package:purrr':
   
       reduce
   
   
   Loading required package: GenomeInfoDb
   
   
   Attaching package: 'GenomicRanges'
   
   
   The following object is masked from 'package:magrittr':
   
       subtract
   
   
   Loading required package: grid
   
   Loading required package: Biostrings
   
   Loading required package: XVector
   
   
   Attaching package: 'XVector'
   
   
   The following object is masked from 'package:purrr':
   
       compact
   
   
   
   Attaching package: 'Biostrings'
   
   
   The following object is masked from 'package:grid':
   
       pattern
   
   
   The following object is masked from 'package:base':
   
       strsplit
   
   
   
   Attaching package: 'gridExtra'
   
   
   The following object is masked from 'package:BiocGenerics':
   
       combine
   
   
   The following object is masked from 'package:dplyr':
   
       combine
   
   
   
   Attaching package: 'data.table'
   
   
   The following object is masked from 'package:GenomicRanges':
   
       shift
   
   
   The following object is masked from 'package:IRanges':
   
       shift
   
   
   The following objects are masked from 'package:S4Vectors':
   
       first, second
   
   
   The following objects are masked from 'package:lubridate':
   
       hour, isoweek, mday, minute, month, quarter, second, wday, week,
       yday, year
   
   
   The following objects are masked from 'package:dplyr':
   
       between, first, last
   
   
   The following object is masked from 'package:purrr':
   
       transpose
   
   
   
   
   Registered S3 method overwritten by 'gplots':
     method         from 
     reorder.factor gdata
   
   ChIPseeker v1.34.1  For help: https://guangchuangyu.github.io/software/ChIPseeker
   
   If you use ChIPseeker in published research, please cite:
   Qianwen Wang, Ming Li, Tianzhi Wu, Li Zhan, Lin Li, Meijun Chen, Wenqin Xie, Zijing Xie, Erqiang Hu, Shuangbin Xu, Guangchuang Yu. Exploring epigenomic datasets by ChIPseeker. Current Protocols 2022, 2(10): e585
   
   Loading required package: graph
   
   
   Attaching package: 'graph'
   
   
   The following object is masked from 'package:Biostrings':
   
       complement
   
   
   The following object is masked from 'package:stringr':
   
       boundary
   
   
   Loading required package: Biobase
   
   Welcome to Bioconductor
   
       Vignettes contain introductory material; view with
       'browseVignettes()'. To cite Bioconductor, see
       'citation("Biobase")', and for packages 'citation("pkgname")'.
   
   
   Loading required package: GO.db
   
   Loading required package: AnnotationDbi
   
   
   Attaching package: 'AnnotationDbi'
   
   
   The following object is masked from 'package:dplyr':
   
       select
   
   
   Loading required package: SparseM
   
   
   Attaching package: 'SparseM'
   
   
   The following object is masked from 'package:base':
   
       backsolve
   
   
   
   groupGOTerms:    GOBPTerm, GOMFTerm, GOCCTerm environments built.
   
   
   Attaching package: 'topGO'
   
   
   The following object is masked from 'package:grid':
   
       depth
   
   
   The following object is masked from 'package:IRanges':
   
       members
   
   
   Loading required package: GenomicFeatures
   
   
   Attaching package: 'GenomicFeatures'
   
   
   The following object is masked from 'package:topGO':
   
       genes
config = load_config()

# load CHT results
cht_full = lapply(ab_tp_list, function(ab_tp) load_cht_results(ab_tp, remove_chr = F)) %>% bind_rows()
cht = cht_full %>% filter(!TEST.SNP.CHROM %in% c("chrX", "chrY", "chrM"))
cht_sign = cht %>% filter(signif_strongAI) 

# genes and promoters
genes = load_genes()
promoters = resize(genes, width = 1000, fix = "start")

# combined motif set (all TFs, peaks + alleles)
fimo = get_full_motif_sets(cht, ab_tp_list)
# only alleles
fimo_alleles  = lapply(ab_tp_list, function(ab_tp) parse_motifs_in_two_alleles(ab_tp, cht)) %>% bind_rows() 

2 Figure S7A

variants_overlapping_motif = unique(gsub("_", ":", fimo_alleles$snp_id))

twi_24h = read_input("/g/furlong/project/103_Basenji/Mattia/analysis/correlations/Basenji_scores_and_allelic_imbalance_twi.24_annot.txt")
twi_24h_best_basenji_in_peak = take_best_Basenji_in_peak(twi_24h)

bin_68h = read_input("/g/furlong/project/103_Basenji/Mattia/analysis/correlations/Basenji_scores_and_allelic_imbalance_bin.68_annot.txt")
bin_68h_best_basenji_in_peak = take_best_Basenji_in_peak(bin_68h)

ctcf_68h = read_input("/g/furlong/project/103_Basenji/Mattia/analysis/correlations/Basenji_scores_and_allelic_imbalance_ctcf.68_annot.txt")
ctcf_68h_best_basenji_in_peak = take_best_Basenji_in_peak(ctcf_68h)

mef2_68h = read_input("/g/furlong/project/103_Basenji/Mattia/analysis/correlations/Basenji_scores_and_allelic_imbalance_mef2.68_annot.txt")
mef2_68h_best_basenji_in_peak = take_best_Basenji_in_peak(mef2_68h)

bin_1012h = read_input("/g/furlong/project/103_Basenji/Mattia/analysis/correlations/Basenji_scores_and_allelic_imbalance_bin.1012_annot.txt")
bin_1012h_best_basenji_in_peak = take_best_Basenji_in_peak(bin_1012h)

mef2_1012h = read_input("/g/furlong/project/103_Basenji/Mattia/analysis/correlations/Basenji_scores_and_allelic_imbalance_mef2.1012_annot.txt")
mef2_1012h_best_basenji_in_peak = take_best_Basenji_in_peak(mef2_1012h)

all_samples = rbind(twi_24h, bin_68h, ctcf_68h, mef2_68h, bin_1012h, mef2_1012h)
all_samples$correct_predict = factor(ifelse(all_samples$AI>0.5 & all_samples$Basenji_AI>0.5, "correct", ifelse(all_samples$AI<0.5 & all_samples$Basenji_AI<0.5, "correct", "incorrect")), levels=c("incorrect", "correct"))

all_samples_best_basenji_in_peak = rbind(twi_24h_best_basenji_in_peak, bin_68h_best_basenji_in_peak, ctcf_68h_best_basenji_in_peak, mef2_68h_best_basenji_in_peak, bin_1012h_best_basenji_in_peak, mef2_1012h_best_basenji_in_peak)
all_samples_best_basenji_in_peak$correct_predict = factor(ifelse(all_samples_best_basenji_in_peak$AI>0.5 & all_samples_best_basenji_in_peak$Basenji_AI>0.5, "correct", ifelse(all_samples_best_basenji_in_peak$AI<0.5 & all_samples_best_basenji_in_peak$Basenji_AI<0.5, "correct", "incorrect")), levels=c("incorrect", "correct"))

all_samples_best_basenji_in_peak_sub = subset(all_samples_best_basenji_in_peak, significant==TRUE)

all_samples_best_basenji_in_peak$best_variant = 1

all_samples_2nd_best_basenji_in_peak = take_next_best_Basenji_in_peak(all_samples, all_samples_best_basenji_in_peak)
all_samples_2nd_best_basenji_in_peak$best_variant = 2

all_samples_3nd_best_basenji_in_peak = take_next_best_Basenji_in_peak(all_samples, rbind(all_samples_best_basenji_in_peak, all_samples_2nd_best_basenji_in_peak))
all_samples_3nd_best_basenji_in_peak$best_variant = 3

all_samples_4nd_best_basenji_in_peak = take_next_best_Basenji_in_peak(all_samples, rbind(all_samples_best_basenji_in_peak, all_samples_2nd_best_basenji_in_peak, all_samples_3nd_best_basenji_in_peak))
all_samples_4nd_best_basenji_in_peak$best_variant = 4

all_samples_5nd_best_basenji_in_peak = take_next_best_Basenji_in_peak(all_samples, rbind(all_samples_best_basenji_in_peak, all_samples_2nd_best_basenji_in_peak, all_samples_3nd_best_basenji_in_peak, all_samples_4nd_best_basenji_in_peak))
all_samples_5nd_best_basenji_in_peak$best_variant = 5

all_samples$motif = ifelse((all_samples$variant_ID %in% variants_overlapping_motif), TRUE, FALSE)


all_samples_sub_on_motif = subset(all_samples, significant==TRUE & overlaps_motif=="overlaps_motif")
all_samples_best_basenji_in_peak_sub_on_motif = subset(all_samples_best_basenji_in_peak, significant==TRUE & overlaps_motif=="overlaps_motif")
all_samples_2nd_best_basenji_in_peak_sub_on_motif = subset(all_samples_2nd_best_basenji_in_peak, significant==TRUE & overlaps_motif=="overlaps_motif")
all_samples_3nd_best_basenji_in_peak_sub_on_motif = subset(all_samples_3nd_best_basenji_in_peak, significant==TRUE & overlaps_motif=="overlaps_motif")
all_samples_4nd_best_basenji_in_peak_sub_on_motif = subset(all_samples_4nd_best_basenji_in_peak, significant==TRUE & overlaps_motif=="overlaps_motif")
all_samples_5nd_best_basenji_in_peak_sub_on_motif = subset(all_samples_5nd_best_basenji_in_peak, significant==TRUE & overlaps_motif=="overlaps_motif")

all_samples_sub_outside_motif = subset(all_samples, significant==TRUE & overlaps_motif=="no_overlap")
all_samples_best_basenji_in_peak_sub_outside_motif = subset(all_samples_best_basenji_in_peak, significant==TRUE & overlaps_motif=="no_overlap")
all_samples_2nd_best_basenji_in_peak_sub_outside_motif = subset(all_samples_2nd_best_basenji_in_peak, significant==TRUE & overlaps_motif=="no_overlap")
all_samples_3nd_best_basenji_in_peak_sub_outside_motif = subset(all_samples_3nd_best_basenji_in_peak, significant==TRUE & overlaps_motif=="no_overlap")
all_samples_4nd_best_basenji_in_peak_sub_outside_motif = subset(all_samples_4nd_best_basenji_in_peak, significant==TRUE & overlaps_motif=="no_overlap")
all_samples_5nd_best_basenji_in_peak_sub_outside_motif = subset(all_samples_5nd_best_basenji_in_peak, significant==TRUE & overlaps_motif=="no_overlap")


success_proportion_on_motif = as.data.frame(t(matrix(c("1st", nrow(subset(all_samples_best_basenji_in_peak_sub_on_motif, (Basenji_AI > 0.5 & AI > 0.5) | (Basenji_AI < 0.5 & AI < 0.5))) / nrow(all_samples_best_basenji_in_peak_sub_on_motif), 
  "2nd", nrow(subset(all_samples_2nd_best_basenji_in_peak_sub_on_motif, (Basenji_AI > 0.5 & AI > 0.5) | (Basenji_AI < 0.5 & AI < 0.5))) / nrow(all_samples_2nd_best_basenji_in_peak_sub_on_motif), 
  "3rd", nrow(subset(all_samples_3nd_best_basenji_in_peak_sub_on_motif, (Basenji_AI > 0.5 & AI > 0.5) | (Basenji_AI < 0.5 & AI < 0.5))) / nrow(all_samples_3nd_best_basenji_in_peak_sub_on_motif), 
  "4th", nrow(subset(all_samples_4nd_best_basenji_in_peak_sub_on_motif, (Basenji_AI > 0.5 & AI > 0.5) | (Basenji_AI < 0.5 & AI < 0.5))) / nrow(all_samples_4nd_best_basenji_in_peak_sub_on_motif), 
  "5th", nrow(subset(all_samples_5nd_best_basenji_in_peak_sub_on_motif, (Basenji_AI > 0.5 & AI > 0.5) | (Basenji_AI < 0.5 & AI < 0.5))) / nrow(all_samples_5nd_best_basenji_in_peak_sub_on_motif), 
  "all", nrow(subset(all_samples_sub_on_motif, (Basenji_AI > 0.5 & AI > 0.5) | (Basenji_AI < 0.5 & AI < 0.5))) / nrow(all_samples_sub_on_motif)), nrow=2)))

colnames(success_proportion_on_motif) = c("best_Basenji_AI", "proportion_correct")
success_proportion_on_motif$proportion_correct = as.numeric(success_proportion_on_motif$proportion_correct)





success_proportion_outside_motif = as.data.frame(t(matrix(c("1st", nrow(subset(all_samples_best_basenji_in_peak_sub_outside_motif, (Basenji_AI > 0.5 & AI > 0.5) | (Basenji_AI < 0.5 & AI < 0.5))) / nrow(all_samples_best_basenji_in_peak_sub_outside_motif), 
  "2nd", nrow(subset(all_samples_2nd_best_basenji_in_peak_sub_outside_motif, (Basenji_AI > 0.5 & AI > 0.5) | (Basenji_AI < 0.5 & AI < 0.5))) / nrow(all_samples_2nd_best_basenji_in_peak_sub_outside_motif), 
  "3rd", nrow(subset(all_samples_3nd_best_basenji_in_peak_sub_outside_motif, (Basenji_AI > 0.5 & AI > 0.5) | (Basenji_AI < 0.5 & AI < 0.5))) / nrow(all_samples_3nd_best_basenji_in_peak_sub_outside_motif), 
  "4th", nrow(subset(all_samples_4nd_best_basenji_in_peak_sub_outside_motif, (Basenji_AI > 0.5 & AI > 0.5) | (Basenji_AI < 0.5 & AI < 0.5))) / nrow(all_samples_4nd_best_basenji_in_peak_sub_outside_motif), 
  "5th", nrow(subset(all_samples_5nd_best_basenji_in_peak_sub_outside_motif, (Basenji_AI > 0.5 & AI > 0.5) | (Basenji_AI < 0.5 & AI < 0.5))) / nrow(all_samples_5nd_best_basenji_in_peak_sub_outside_motif), 
  "all", nrow(subset(all_samples_sub_outside_motif, (Basenji_AI > 0.5 & AI > 0.5) | (Basenji_AI < 0.5 & AI < 0.5))) / nrow(all_samples_sub_outside_motif)), nrow=2)))

colnames(success_proportion_outside_motif) = c("best_Basenji_AI", "proportion_correct")
success_proportion_outside_motif$proportion_correct = as.numeric(success_proportion_outside_motif$proportion_correct)




background_success_proportion_df = data.frame(row.names = c("1st", "2nd", "3rd", "4th", "5th", "all"))

for (i in seq(1, 1000)) {
  
  all_samples_variant = subset(all_samples)
  background_variant_shuff = all_samples_variant %>% 
    select(variant_ID, peak_ID, significant, correct_predict) %>%
    group_by(peak_ID) %>%
    mutate(rank=sample(row_number())) %>%
    ungroup()
  background_best_variant_shuff = subset(background_variant_shuff, rank==1 & significant==TRUE)
  background_2nd_best_variant_shuff = subset(background_variant_shuff, rank==2 & significant==TRUE)
  background_3nd_best_variant_shuff = subset(background_variant_shuff, rank==3 & significant==TRUE)
  background_4nd_best_variant_shuff = subset(background_variant_shuff, rank==4 & significant==TRUE)
  background_5nd_best_variant_shuff = subset(background_variant_shuff, rank==5 & significant==TRUE)

  background_success_proportion = as.data.frame(t(matrix(c("1st", nrow(subset(background_best_variant_shuff, (correct_predict=="correct"))) / nrow(background_best_variant_shuff), 
  "2nd", nrow(subset(background_2nd_best_variant_shuff, (correct_predict=="correct"))) / nrow(background_2nd_best_variant_shuff), 
  "3rd", nrow(subset(background_3nd_best_variant_shuff, (correct_predict=="correct"))) / nrow(background_3nd_best_variant_shuff), 
  "4th", nrow(subset(background_4nd_best_variant_shuff, (correct_predict=="correct"))) / nrow(background_4nd_best_variant_shuff), 
  "5th", nrow(subset(background_5nd_best_variant_shuff, (correct_predict=="correct"))) / nrow(background_5nd_best_variant_shuff), 
  "all", nrow(subset(background_variant_shuff, (correct_predict=="correct"))) / nrow(background_variant_shuff)), nrow=2)))

  colnames(background_success_proportion) = c("best_Basenji_AI", "proportion_correct")
  background_success_proportion$proportion_correct = as.numeric(background_success_proportion$proportion_correct)

  background_success_proportion_df = cbind(background_success_proportion_df, background_success_proportion$proportion_correct)
}


background_success_proportion_summary = data.frame(background_mean = rowMeans(background_success_proportion_df),
                                                   background_std = apply(background_success_proportion_df, 1, sd, na.rm = TRUE))
background_success_proportion_summary$best_Basenji_AI = rownames(background_success_proportion_summary)




success_proportion_on_motif = success_proportion_on_motif[c(1,2,3,4,5), ]
success_proportion_outside_motif = success_proportion_outside_motif[c(1,2,3,4,5), ]
background_success_proportion_summary = background_success_proportion_summary[c(1,2,3,4,5), ]



p = ggplot() +
    geom_point(data = success_proportion_on_motif, aes(x=best_Basenji_AI, y=proportion_correct, group=1), size=3, colour="#FFA736") +
    geom_line(data = success_proportion_on_motif, aes(x=best_Basenji_AI, y=proportion_correct, group=1), colour="#FFA736") +
    geom_point(data = success_proportion_outside_motif, aes(x=best_Basenji_AI, y=proportion_correct, group=1), size=3, colour="grey15") +
    geom_line(data = success_proportion_outside_motif, aes(x=best_Basenji_AI, y=proportion_correct, group=1), colour="grey15") +
   geom_line(data=background_success_proportion_summary, aes(x=best_Basenji_AI, y = background_mean, group=1), color = "grey60", linewidth = 1) + 
  geom_ribbon(data=background_success_proportion_summary, aes(x=best_Basenji_AI, y = background_mean, ymin = background_mean - background_std * 2, ymax = background_mean + background_std * 2, group=1), fill = "grey70", alpha = .2) +
    ylim(0.47, 1) +
    geom_hline(yintercept = 0.5, colour = "#C92B27", linetype="dashed") +
    geom_text(data = success_proportion_on_motif, aes(x = best_Basenji_AI, y = proportion_correct, label=round(proportion_correct, 3)), colour="grey15", fontface = 2, size = 4, vjust=-2) +
    geom_text(data = success_proportion_outside_motif, aes(x = best_Basenji_AI, y = proportion_correct, label=round(proportion_correct, 3)), colour="grey15", fontface = 2, size = 4, vjust=-2) +
    xlab("Best variant order (Basenji AI)") +
    ylab("Proportion of correct predictions (AI direction)") +
    theme_bw() + 
    theme(panel.grid = element_line(colour = "grey80", linewidth = 1), axis.text = element_text(size = 12)) +
    theme(axis.title = element_text(size = 12), plot.title = element_text(size=12)) +
    theme(panel.grid.minor = element_line(linewidth = 0.25), panel.grid.major = element_line(linewidth = 0.5)) +
    theme(legend.position = "none")

p

outf = file.path(outdir_fig_suppl, paste0("FigS7A_Variants_priority_motifs_overlap.pdf"))
ggsave(outf, p, width = 6, height = 4)

3 Figure S7B

give.n <- function(x){
  return(c(y = 0.025, label = length(x))) 
  # experiment with the multiplier to find the perfect position
}


all_samples$overlaps_motif = factor(all_samples$overlaps_motif, levels=c("overlaps_motif", "no_overlap"))
all_samples_sign_peak = subset(all_samples, peak_ID %in% unique(subset(all_samples, significant==TRUE)$peak_ID) )

p = ggplot(all_samples_sign_peak, aes(x=overlaps_motif, y=Basenji_abs_AI, fill=overlaps_motif)) + 
    geom_violin(width=1.15) + 
    geom_boxplot(width=0.02, outlier.shape = NA, fill="white", alpha=0.75) +
    ylim(0,0.010) +
    xlab("Variant overlaps cognate motif") +
    ylab("Basenji absolute pAI") +
    stat_summary(fun.data = give.n, geom = "text", fun.y = 0.25) +
    scale_fill_manual(values = c("#FFA736", "grey70")) +
    theme_bw() + 
    theme(panel.grid = element_line(colour = "grey80", linewidth = 1), axis.text = element_text(size = 12)) +
    theme(axis.title = element_text(size = 12), plot.title = element_text(size=12)) +
    theme(panel.grid.minor = element_line(linewidth = 0.25), panel.grid.major = element_line(linewidth = 0.5)) +
    theme(legend.position = "none")
   Warning: The `fun.y` argument of `stat_summary()` is deprecated as of ggplot2 3.3.0.
   ℹ Please use the `fun` argument instead.
   This warning is displayed once every 8 hours.
   Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
   generated.
p
   Warning: Removed 7496 rows containing non-finite values (`stat_ydensity()`).
   Warning: Removed 7496 rows containing non-finite values (`stat_boxplot()`).
   Warning: Removed 7496 rows containing non-finite values (`stat_summary()`).
   Warning: `position_dodge()` requires non-overlapping x intervals
   Warning: Removed 2 rows containing missing values (`geom_text()`).

outf = file.path(outdir_fig_suppl, paste0("FigS7B_Distribution_of_abs_AI_motif_overlap.pdf"))
ggsave(outf, p, width = 6, height = 4)
   Warning: Removed 7496 rows containing non-finite values (`stat_ydensity()`).
   Warning: Removed 7496 rows containing non-finite values (`stat_boxplot()`).
   Warning: Removed 7496 rows containing non-finite values (`stat_summary()`).
   Warning: `position_dodge()` requires non-overlapping x intervals
   Warning: Removed 2 rows containing missing values (`geom_text()`).

Wilcoxon pvalue: 0

4 Figure S7C

all_samples_best_basenji_sub = subset(all_samples_best_basenji_in_peak, significant==TRUE)
all_samples_2nd_best_basenji_sub = subset(all_samples_2nd_best_basenji_in_peak, significant==TRUE)
all_samples_3nd_best_basenji_sub = subset(all_samples_3nd_best_basenji_in_peak, significant==TRUE)
all_samples_4nd_best_basenji_sub = subset(all_samples_4nd_best_basenji_in_peak, significant==TRUE)
all_samples_5nd_best_basenji_sub = subset(all_samples_5nd_best_basenji_in_peak, significant==TRUE)

all_samples_rank_variants = rbind(all_samples_best_basenji_sub, all_samples_2nd_best_basenji_sub, all_samples_3nd_best_basenji_sub, all_samples_4nd_best_basenji_sub, all_samples_5nd_best_basenji_sub)

percentages = data.frame(table(all_samples_rank_variants[, c("best_variant", "overlaps_motif")])) %>% 
        pivot_wider(names_from =overlaps_motif, values_from = Freq)
percentages$tot = percentages$no_overlap + percentages$overlaps_motif
percentages$no_overlap = percentages$no_overlap / percentages$tot
percentages$overlaps_motif = percentages$overlaps_motif / percentages$tot
percentages = percentages %>%
    select(best_variant, no_overlap, overlaps_motif) %>%
    pivot_longer(cols = c(no_overlap, overlaps_motif))
colnames(percentages) = c("best_variant", "overlaps_motif", "ratio")

p = ggplot(percentages, aes(x=best_variant, y=ratio, fill=overlaps_motif)) + 
    geom_col(position="fill") +
    xlab("Best variant order (Basenji AI)") +
    ylab("Proportion of variants overlapping cognate motif") +
    scale_y_continuous(labels = scales::percent) +
    scale_fill_manual(values = c("grey70", "#FFA736")) +
    theme_bw() + 
    geom_text(aes(label = paste0(round(ratio*100, 1), "%")), position = position_fill(vjust = 0.5), size=5) +
    theme(panel.grid = element_line(colour = "grey80", linewidth = 1), axis.text = element_text(size = 12)) +
    theme(axis.title = element_text(size = 12), plot.title = element_text(size=12)) +
    theme(panel.grid.minor = element_line(linewidth = 0.25), panel.grid.major = element_line(linewidth = 0.5)) +
    theme(legend.position = "none")

p

outf = file.path(outdir_fig_suppl, paste0("FigS7C_Proportion_of_ranks_motifs_overlap.pdf"))
ggsave(outf, p, width = 6, height = 6)

5 Figure S7D

saturation_scores_predictions = read.table("/g/furlong/project/103_Basenji/Mattia/analysis/saturation_scores/Basenji_DataTable_predictions.txt", header=TRUE)
saturation_scores_predictions$Basenji_predict = gsub("0", "no_prediction", gsub("1", "full_prediction", gsub("partially", "partial_prediction", saturation_scores_predictions$Basenji_predict)))
saturation_scores_predictions$Basenji_predict = factor(saturation_scores_predictions$Basenji_predict, levels=c("full_prediction", "partial_prediction", "no_prediction"))

saturation_scores_predictions$motif_on_variant = ifelse(saturation_scores_predictions$variant_in_self_motif == 1, "self_motif", ifelse(saturation_scores_predictions$variant_in_other_motif == 1, "cofactor_motif", ifelse(saturation_scores_predictions$Basenji_predict == "no_prediction", "no_prediction", "no_motif")))
saturation_scores_predictions$motif_on_variant = factor(saturation_scores_predictions$motif_on_variant, levels=c("self_motif", "cofactor_motif","no_motif", "no_prediction"))
saturation_scores_predictions$condition = factor(saturation_scores_predictions$condition, levels=c("twi.24", "ctcf.68", "mef2.68", "mef2.1012", "bin.68", "bin.1012"))
saturation_scores_predictions$motifs_predictions = ifelse(saturation_scores_predictions$self_motif == 1 & saturation_scores_predictions$cofactor_motif == 1, "self_and_cofactor", ifelse(saturation_scores_predictions$self_motif == 1, "self_motif",  ifelse(saturation_scores_predictions$cofactor_motif == 1, "cofactor_motif", ifelse(saturation_scores_predictions$Basenji_predict == "no_prediction", "no_prediction" ,"no_motif"))))
saturation_scores_predictions$motifs_predictions = factor(saturation_scores_predictions$motifs_predictions, levels=c("self_and_cofactor", "self_motif", "cofactor_motif", "no_motif", "no_prediction"))

p = plot_counts_barplot(saturation_scores_predictions, "condition", "motifs_predictions") +
  scale_fill_manual(values = c("#339024", "#FF2341", "#FFA736", "grey70", "grey15")) +
  geom_text(aes(label=counts),  position = position_stack(vjust = 0.5), colour="white") +
  labs(fill="predicted_motifs")
   Scale for fill is already present.
   Adding another scale for fill, which will replace the existing scale.
p

outf = file.path(outdir_fig_suppl, paste0("FigS7D_basenji_predictions_by_predicted_motif.pdf"))
ggsave(outf, p, width = 3, height = 3)

6 Figure S7E

7 Figure S7F

twi_24h = read_input("/g/furlong/project/103_Basenji/Mattia/analysis/correlations/Basenji_scores_and_allelic_imbalance_twi.24_annot.txt")
twi_24h_best_basenji_in_peak = take_best_Basenji_in_peak(twi_24h)

bin_68h = read_input("/g/furlong/project/103_Basenji/Mattia/analysis/correlations/Basenji_scores_and_allelic_imbalance_bin.68_annot.txt")
bin_68h_best_basenji_in_peak = take_best_Basenji_in_peak(bin_68h)

ctcf_68h = read_input("/g/furlong/project/103_Basenji/Mattia/analysis/correlations/Basenji_scores_and_allelic_imbalance_ctcf.68_annot.txt")
ctcf_68h_best_basenji_in_peak = take_best_Basenji_in_peak(ctcf_68h)

mef2_68h = read_input("/g/furlong/project/103_Basenji/Mattia/analysis/correlations/Basenji_scores_and_allelic_imbalance_mef2.68_annot.txt")
mef2_68h_best_basenji_in_peak = take_best_Basenji_in_peak(mef2_68h)

bin_1012h = read_input("/g/furlong/project/103_Basenji/Mattia/analysis/correlations/Basenji_scores_and_allelic_imbalance_bin.1012_annot.txt")
bin_1012h_best_basenji_in_peak = take_best_Basenji_in_peak(bin_1012h)

mef2_1012h = read_input("/g/furlong/project/103_Basenji/Mattia/analysis/correlations/Basenji_scores_and_allelic_imbalance_mef2.1012_annot.txt")
mef2_1012h_best_basenji_in_peak = take_best_Basenji_in_peak(mef2_1012h)

all_samples = rbind(twi_24h, bin_68h, ctcf_68h, mef2_68h, bin_1012h, mef2_1012h)
all_samples$correct_predict = factor(ifelse(all_samples$AI>0.5 & all_samples$Basenji_AI>0.5, "correct", ifelse(all_samples$AI<0.5 & all_samples$Basenji_AI<0.5, "correct", "incorrect")), levels=c("incorrect", "correct"))

all_samples_best_basenji_in_peak = rbind(twi_24h_best_basenji_in_peak, bin_68h_best_basenji_in_peak, ctcf_68h_best_basenji_in_peak, mef2_68h_best_basenji_in_peak, bin_1012h_best_basenji_in_peak, mef2_1012h_best_basenji_in_peak)
all_samples_best_basenji_in_peak$correct_predict = factor(ifelse(all_samples_best_basenji_in_peak$AI>0.5 & all_samples_best_basenji_in_peak$Basenji_AI>0.5, "correct", ifelse(all_samples_best_basenji_in_peak$AI<0.5 & all_samples_best_basenji_in_peak$Basenji_AI<0.5, "correct", "incorrect")), levels=c("incorrect", "correct"))

all_samples_best_basenji_in_peak_sub = subset(all_samples_best_basenji_in_peak, significant==TRUE)


all_samples_best_basenji_in_peak$best_variant = 1
all_samples_2nd_best_basenji_in_peak = take_next_best_Basenji_in_peak(all_samples, all_samples_best_basenji_in_peak)
all_samples_2nd_best_basenji_in_peak$best_variant = 2
all_samples_3nd_best_basenji_in_peak = take_next_best_Basenji_in_peak(all_samples, rbind(all_samples_best_basenji_in_peak, all_samples_2nd_best_basenji_in_peak))
all_samples_3nd_best_basenji_in_peak$best_variant = 3
all_samples_4nd_best_basenji_in_peak = take_next_best_Basenji_in_peak(all_samples, rbind(all_samples_best_basenji_in_peak, all_samples_2nd_best_basenji_in_peak, all_samples_3nd_best_basenji_in_peak))
all_samples_4nd_best_basenji_in_peak$best_variant = 4
all_samples_5nd_best_basenji_in_peak = take_next_best_Basenji_in_peak(all_samples, rbind(all_samples_best_basenji_in_peak, all_samples_2nd_best_basenji_in_peak, all_samples_3nd_best_basenji_in_peak, all_samples_4nd_best_basenji_in_peak))
all_samples_5nd_best_basenji_in_peak$best_variant = 5

all_samples_sub = subset(all_samples, significant==TRUE)
all_samples_best_basenji_in_peak_sub = subset(all_samples_best_basenji_in_peak, significant==TRUE)
all_samples_2nd_best_basenji_in_peak_sub = subset(all_samples_2nd_best_basenji_in_peak, significant==TRUE)
all_samples_3nd_best_basenji_in_peak_sub = subset(all_samples_3nd_best_basenji_in_peak, significant==TRUE)
all_samples_4nd_best_basenji_in_peak_sub = subset(all_samples_4nd_best_basenji_in_peak, significant==TRUE)
all_samples_5nd_best_basenji_in_peak_sub = subset(all_samples_5nd_best_basenji_in_peak, significant==TRUE)


success_proportion = as.data.frame(t(matrix(c("1st", nrow(subset(all_samples_best_basenji_in_peak_sub, (Basenji_AI > 0.5 & AI > 0.5) | (Basenji_AI < 0.5 & AI < 0.5))) / nrow(all_samples_best_basenji_in_peak_sub), 
  "2nd", nrow(subset(all_samples_2nd_best_basenji_in_peak_sub, (Basenji_AI > 0.5 & AI > 0.5) | (Basenji_AI < 0.5 & AI < 0.5))) / nrow(all_samples_2nd_best_basenji_in_peak_sub), 
  "3rd", nrow(subset(all_samples_3nd_best_basenji_in_peak_sub, (Basenji_AI > 0.5 & AI > 0.5) | (Basenji_AI < 0.5 & AI < 0.5))) / nrow(all_samples_3nd_best_basenji_in_peak_sub), 
  "4th", nrow(subset(all_samples_4nd_best_basenji_in_peak_sub, (Basenji_AI > 0.5 & AI > 0.5) | (Basenji_AI < 0.5 & AI < 0.5))) / nrow(all_samples_4nd_best_basenji_in_peak_sub), 
  "5th", nrow(subset(all_samples_5nd_best_basenji_in_peak_sub, (Basenji_AI > 0.5 & AI > 0.5) | (Basenji_AI < 0.5 & AI < 0.5))) / nrow(all_samples_5nd_best_basenji_in_peak_sub), 
  "all", nrow(subset(all_samples_sub, (Basenji_AI > 0.5 & AI > 0.5) | (Basenji_AI < 0.5 & AI < 0.5))) / nrow(all_samples_sub)), nrow=2)))

colnames(success_proportion) = c("best_Basenji_AI", "proportion_correct")
success_proportion$proportion_correct = as.numeric(success_proportion$proportion_correct)

all_samples_best_basenji_in_peak_sub = subset(all_samples_best_basenji_in_peak, significant==TRUE & (Basenji_abs_AI > 0.1))

p = plot_counts_barplot(all_samples_best_basenji_in_peak_sub, "TSS", "correct_predict")
p

outf = file.path(outdir_fig_suppl, paste0("FigS7F_basenji_predictions_by_TSS.pdf"))
ggsave(outf, p, width = 3, height = 3)
p = plot_counts_barplot(all_samples_best_basenji_in_peak_sub, "overlaps_peak", "correct_predict")
p

outf = file.path(outdir_fig_suppl, paste0("FigS7F_basenji_predictions_by_peak_overlap.pdf"))
ggsave(outf, p, width = 3, height = 3)
p = plot_counts_barplot(all_samples_best_basenji_in_peak_sub, "overlaps_motif", "correct_predict")
p

outf = file.path(outdir_fig_suppl, paste0("FigS7F_basenji_predictions_by_motif_overlap.pdf"))
ggsave(outf, p, width = 3, height = 3)
LS0tCnRpdGxlOiAiRmlndXJlIFM3IgpvdXRwdXQ6CiAgIEJpb2NTdHlsZTo6aHRtbF9kb2N1bWVudDoKICAgICAgdG9jOiB0cnVlCiAgICAgIGRmX3ByaW50OiBwYWdlZAogICAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZQogICAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICAgIGhpZ2hsaWdodDogdGFuZ28KI2JpYmxpb2dyYXBoeToga25uX21sX2ludHJvLmJpYgplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCmBgYHtyIHN0eWxlLCBlY2hvPUZBTFNFLCByZXN1bHRzPSJhc2lzIn0KbGlicmFyeSgia25pdHIiKQpvcHRpb25zKGRpZ2l0cyA9IDIsIHdpZHRoID0gODApCm9wdGlvbnMoYml0bWFwVHlwZSA9ICdjYWlybycpCmdvbGRlbl9yYXRpbyA8LSAoMSArIHNxcnQoNSkpIC8gMgpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgdGlkeSA9IEZBTFNFLCBpbmNsdWRlID0gVFJVRSwgY2FjaGUgPSBGQUxTRSwKICAgICAgICAgICAgICAgZGV2PWMoJ3BuZycsICdwZGYnKSwgY29tbWVudCA9ICcgICcsIGRwaSA9IDMwMCkKCm9wdGlvbnMoc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQprbml0cjo6b3B0c19jaHVuayRzZXQoY2FjaGU9RkFMU0UpCm9wdGlvbnMoZGlnaXRzID0gNSkgICAgICAgICAKYGBgCgoKIyBTZXR1cCBhbmQgZGF0YQoKYGBge3J9CnNvdXJjZSgiLi4vdXRpbHMvdXRpbHMuUiIpCmNvbmZpZyA9IGxvYWRfY29uZmlnKCkKCiMgbG9hZCBDSFQgcmVzdWx0cwpjaHRfZnVsbCA9IGxhcHBseShhYl90cF9saXN0LCBmdW5jdGlvbihhYl90cCkgbG9hZF9jaHRfcmVzdWx0cyhhYl90cCwgcmVtb3ZlX2NociA9IEYpKSAlPiUgYmluZF9yb3dzKCkKY2h0ID0gY2h0X2Z1bGwgJT4lIGZpbHRlcighVEVTVC5TTlAuQ0hST00gJWluJSBjKCJjaHJYIiwgImNoclkiLCAiY2hyTSIpKQpjaHRfc2lnbiA9IGNodCAlPiUgZmlsdGVyKHNpZ25pZl9zdHJvbmdBSSkgCgojIGdlbmVzIGFuZCBwcm9tb3RlcnMKZ2VuZXMgPSBsb2FkX2dlbmVzKCkKcHJvbW90ZXJzID0gcmVzaXplKGdlbmVzLCB3aWR0aCA9IDEwMDAsIGZpeCA9ICJzdGFydCIpCgojIGNvbWJpbmVkIG1vdGlmIHNldCAoYWxsIFRGcywgcGVha3MgKyBhbGxlbGVzKQpmaW1vID0gZ2V0X2Z1bGxfbW90aWZfc2V0cyhjaHQsIGFiX3RwX2xpc3QpCiMgb25seSBhbGxlbGVzCmZpbW9fYWxsZWxlcyAgPSBsYXBwbHkoYWJfdHBfbGlzdCwgZnVuY3Rpb24oYWJfdHApIHBhcnNlX21vdGlmc19pbl90d29fYWxsZWxlcyhhYl90cCwgY2h0KSkgJT4lIGJpbmRfcm93cygpIApgYGAKCgoKCgoKCgoKCiMgRmlndXJlIFM3QQoKYGBge3IgfQp2YXJpYW50c19vdmVybGFwcGluZ19tb3RpZiA9IHVuaXF1ZShnc3ViKCJfIiwgIjoiLCBmaW1vX2FsbGVsZXMkc25wX2lkKSkKCnR3aV8yNGggPSByZWFkX2lucHV0KCIvZy9mdXJsb25nL3Byb2plY3QvMTAzX0Jhc2VuamkvTWF0dGlhL2FuYWx5c2lzL2NvcnJlbGF0aW9ucy9CYXNlbmppX3Njb3Jlc19hbmRfYWxsZWxpY19pbWJhbGFuY2VfdHdpLjI0X2Fubm90LnR4dCIpCnR3aV8yNGhfYmVzdF9iYXNlbmppX2luX3BlYWsgPSB0YWtlX2Jlc3RfQmFzZW5qaV9pbl9wZWFrKHR3aV8yNGgpCgpiaW5fNjhoID0gcmVhZF9pbnB1dCgiL2cvZnVybG9uZy9wcm9qZWN0LzEwM19CYXNlbmppL01hdHRpYS9hbmFseXNpcy9jb3JyZWxhdGlvbnMvQmFzZW5qaV9zY29yZXNfYW5kX2FsbGVsaWNfaW1iYWxhbmNlX2Jpbi42OF9hbm5vdC50eHQiKQpiaW5fNjhoX2Jlc3RfYmFzZW5qaV9pbl9wZWFrID0gdGFrZV9iZXN0X0Jhc2VuamlfaW5fcGVhayhiaW5fNjhoKQoKY3RjZl82OGggPSByZWFkX2lucHV0KCIvZy9mdXJsb25nL3Byb2plY3QvMTAzX0Jhc2VuamkvTWF0dGlhL2FuYWx5c2lzL2NvcnJlbGF0aW9ucy9CYXNlbmppX3Njb3Jlc19hbmRfYWxsZWxpY19pbWJhbGFuY2VfY3RjZi42OF9hbm5vdC50eHQiKQpjdGNmXzY4aF9iZXN0X2Jhc2VuamlfaW5fcGVhayA9IHRha2VfYmVzdF9CYXNlbmppX2luX3BlYWsoY3RjZl82OGgpCgptZWYyXzY4aCA9IHJlYWRfaW5wdXQoIi9nL2Z1cmxvbmcvcHJvamVjdC8xMDNfQmFzZW5qaS9NYXR0aWEvYW5hbHlzaXMvY29ycmVsYXRpb25zL0Jhc2Vuamlfc2NvcmVzX2FuZF9hbGxlbGljX2ltYmFsYW5jZV9tZWYyLjY4X2Fubm90LnR4dCIpCm1lZjJfNjhoX2Jlc3RfYmFzZW5qaV9pbl9wZWFrID0gdGFrZV9iZXN0X0Jhc2VuamlfaW5fcGVhayhtZWYyXzY4aCkKCmJpbl8xMDEyaCA9IHJlYWRfaW5wdXQoIi9nL2Z1cmxvbmcvcHJvamVjdC8xMDNfQmFzZW5qaS9NYXR0aWEvYW5hbHlzaXMvY29ycmVsYXRpb25zL0Jhc2Vuamlfc2NvcmVzX2FuZF9hbGxlbGljX2ltYmFsYW5jZV9iaW4uMTAxMl9hbm5vdC50eHQiKQpiaW5fMTAxMmhfYmVzdF9iYXNlbmppX2luX3BlYWsgPSB0YWtlX2Jlc3RfQmFzZW5qaV9pbl9wZWFrKGJpbl8xMDEyaCkKCm1lZjJfMTAxMmggPSByZWFkX2lucHV0KCIvZy9mdXJsb25nL3Byb2plY3QvMTAzX0Jhc2VuamkvTWF0dGlhL2FuYWx5c2lzL2NvcnJlbGF0aW9ucy9CYXNlbmppX3Njb3Jlc19hbmRfYWxsZWxpY19pbWJhbGFuY2VfbWVmMi4xMDEyX2Fubm90LnR4dCIpCm1lZjJfMTAxMmhfYmVzdF9iYXNlbmppX2luX3BlYWsgPSB0YWtlX2Jlc3RfQmFzZW5qaV9pbl9wZWFrKG1lZjJfMTAxMmgpCgphbGxfc2FtcGxlcyA9IHJiaW5kKHR3aV8yNGgsIGJpbl82OGgsIGN0Y2ZfNjhoLCBtZWYyXzY4aCwgYmluXzEwMTJoLCBtZWYyXzEwMTJoKQphbGxfc2FtcGxlcyRjb3JyZWN0X3ByZWRpY3QgPSBmYWN0b3IoaWZlbHNlKGFsbF9zYW1wbGVzJEFJPjAuNSAmIGFsbF9zYW1wbGVzJEJhc2VuamlfQUk+MC41LCAiY29ycmVjdCIsIGlmZWxzZShhbGxfc2FtcGxlcyRBSTwwLjUgJiBhbGxfc2FtcGxlcyRCYXNlbmppX0FJPDAuNSwgImNvcnJlY3QiLCAiaW5jb3JyZWN0IikpLCBsZXZlbHM9YygiaW5jb3JyZWN0IiwgImNvcnJlY3QiKSkKCmFsbF9zYW1wbGVzX2Jlc3RfYmFzZW5qaV9pbl9wZWFrID0gcmJpbmQodHdpXzI0aF9iZXN0X2Jhc2VuamlfaW5fcGVhaywgYmluXzY4aF9iZXN0X2Jhc2VuamlfaW5fcGVhaywgY3RjZl82OGhfYmVzdF9iYXNlbmppX2luX3BlYWssIG1lZjJfNjhoX2Jlc3RfYmFzZW5qaV9pbl9wZWFrLCBiaW5fMTAxMmhfYmVzdF9iYXNlbmppX2luX3BlYWssIG1lZjJfMTAxMmhfYmVzdF9iYXNlbmppX2luX3BlYWspCmFsbF9zYW1wbGVzX2Jlc3RfYmFzZW5qaV9pbl9wZWFrJGNvcnJlY3RfcHJlZGljdCA9IGZhY3RvcihpZmVsc2UoYWxsX3NhbXBsZXNfYmVzdF9iYXNlbmppX2luX3BlYWskQUk+MC41ICYgYWxsX3NhbXBsZXNfYmVzdF9iYXNlbmppX2luX3BlYWskQmFzZW5qaV9BST4wLjUsICJjb3JyZWN0IiwgaWZlbHNlKGFsbF9zYW1wbGVzX2Jlc3RfYmFzZW5qaV9pbl9wZWFrJEFJPDAuNSAmIGFsbF9zYW1wbGVzX2Jlc3RfYmFzZW5qaV9pbl9wZWFrJEJhc2VuamlfQUk8MC41LCAiY29ycmVjdCIsICJpbmNvcnJlY3QiKSksIGxldmVscz1jKCJpbmNvcnJlY3QiLCAiY29ycmVjdCIpKQoKYWxsX3NhbXBsZXNfYmVzdF9iYXNlbmppX2luX3BlYWtfc3ViID0gc3Vic2V0KGFsbF9zYW1wbGVzX2Jlc3RfYmFzZW5qaV9pbl9wZWFrLCBzaWduaWZpY2FudD09VFJVRSkKCmFsbF9zYW1wbGVzX2Jlc3RfYmFzZW5qaV9pbl9wZWFrJGJlc3RfdmFyaWFudCA9IDEKCmFsbF9zYW1wbGVzXzJuZF9iZXN0X2Jhc2VuamlfaW5fcGVhayA9IHRha2VfbmV4dF9iZXN0X0Jhc2VuamlfaW5fcGVhayhhbGxfc2FtcGxlcywgYWxsX3NhbXBsZXNfYmVzdF9iYXNlbmppX2luX3BlYWspCmFsbF9zYW1wbGVzXzJuZF9iZXN0X2Jhc2VuamlfaW5fcGVhayRiZXN0X3ZhcmlhbnQgPSAyCgphbGxfc2FtcGxlc18zbmRfYmVzdF9iYXNlbmppX2luX3BlYWsgPSB0YWtlX25leHRfYmVzdF9CYXNlbmppX2luX3BlYWsoYWxsX3NhbXBsZXMsIHJiaW5kKGFsbF9zYW1wbGVzX2Jlc3RfYmFzZW5qaV9pbl9wZWFrLCBhbGxfc2FtcGxlc18ybmRfYmVzdF9iYXNlbmppX2luX3BlYWspKQphbGxfc2FtcGxlc18zbmRfYmVzdF9iYXNlbmppX2luX3BlYWskYmVzdF92YXJpYW50ID0gMwoKYWxsX3NhbXBsZXNfNG5kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrID0gdGFrZV9uZXh0X2Jlc3RfQmFzZW5qaV9pbl9wZWFrKGFsbF9zYW1wbGVzLCByYmluZChhbGxfc2FtcGxlc19iZXN0X2Jhc2VuamlfaW5fcGVhaywgYWxsX3NhbXBsZXNfMm5kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrLCBhbGxfc2FtcGxlc18zbmRfYmVzdF9iYXNlbmppX2luX3BlYWspKQphbGxfc2FtcGxlc180bmRfYmVzdF9iYXNlbmppX2luX3BlYWskYmVzdF92YXJpYW50ID0gNAoKYWxsX3NhbXBsZXNfNW5kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrID0gdGFrZV9uZXh0X2Jlc3RfQmFzZW5qaV9pbl9wZWFrKGFsbF9zYW1wbGVzLCByYmluZChhbGxfc2FtcGxlc19iZXN0X2Jhc2VuamlfaW5fcGVhaywgYWxsX3NhbXBsZXNfMm5kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrLCBhbGxfc2FtcGxlc18zbmRfYmVzdF9iYXNlbmppX2luX3BlYWssIGFsbF9zYW1wbGVzXzRuZF9iZXN0X2Jhc2VuamlfaW5fcGVhaykpCmFsbF9zYW1wbGVzXzVuZF9iZXN0X2Jhc2VuamlfaW5fcGVhayRiZXN0X3ZhcmlhbnQgPSA1CgphbGxfc2FtcGxlcyRtb3RpZiA9IGlmZWxzZSgoYWxsX3NhbXBsZXMkdmFyaWFudF9JRCAlaW4lIHZhcmlhbnRzX292ZXJsYXBwaW5nX21vdGlmKSwgVFJVRSwgRkFMU0UpCgoKYWxsX3NhbXBsZXNfc3ViX29uX21vdGlmID0gc3Vic2V0KGFsbF9zYW1wbGVzLCBzaWduaWZpY2FudD09VFJVRSAmIG92ZXJsYXBzX21vdGlmPT0ib3ZlcmxhcHNfbW90aWYiKQphbGxfc2FtcGxlc19iZXN0X2Jhc2VuamlfaW5fcGVha19zdWJfb25fbW90aWYgPSBzdWJzZXQoYWxsX3NhbXBsZXNfYmVzdF9iYXNlbmppX2luX3BlYWssIHNpZ25pZmljYW50PT1UUlVFICYgb3ZlcmxhcHNfbW90aWY9PSJvdmVybGFwc19tb3RpZiIpCmFsbF9zYW1wbGVzXzJuZF9iZXN0X2Jhc2VuamlfaW5fcGVha19zdWJfb25fbW90aWYgPSBzdWJzZXQoYWxsX3NhbXBsZXNfMm5kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrLCBzaWduaWZpY2FudD09VFJVRSAmIG92ZXJsYXBzX21vdGlmPT0ib3ZlcmxhcHNfbW90aWYiKQphbGxfc2FtcGxlc18zbmRfYmVzdF9iYXNlbmppX2luX3BlYWtfc3ViX29uX21vdGlmID0gc3Vic2V0KGFsbF9zYW1wbGVzXzNuZF9iZXN0X2Jhc2VuamlfaW5fcGVhaywgc2lnbmlmaWNhbnQ9PVRSVUUgJiBvdmVybGFwc19tb3RpZj09Im92ZXJsYXBzX21vdGlmIikKYWxsX3NhbXBsZXNfNG5kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrX3N1Yl9vbl9tb3RpZiA9IHN1YnNldChhbGxfc2FtcGxlc180bmRfYmVzdF9iYXNlbmppX2luX3BlYWssIHNpZ25pZmljYW50PT1UUlVFICYgb3ZlcmxhcHNfbW90aWY9PSJvdmVybGFwc19tb3RpZiIpCmFsbF9zYW1wbGVzXzVuZF9iZXN0X2Jhc2VuamlfaW5fcGVha19zdWJfb25fbW90aWYgPSBzdWJzZXQoYWxsX3NhbXBsZXNfNW5kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrLCBzaWduaWZpY2FudD09VFJVRSAmIG92ZXJsYXBzX21vdGlmPT0ib3ZlcmxhcHNfbW90aWYiKQoKYWxsX3NhbXBsZXNfc3ViX291dHNpZGVfbW90aWYgPSBzdWJzZXQoYWxsX3NhbXBsZXMsIHNpZ25pZmljYW50PT1UUlVFICYgb3ZlcmxhcHNfbW90aWY9PSJub19vdmVybGFwIikKYWxsX3NhbXBsZXNfYmVzdF9iYXNlbmppX2luX3BlYWtfc3ViX291dHNpZGVfbW90aWYgPSBzdWJzZXQoYWxsX3NhbXBsZXNfYmVzdF9iYXNlbmppX2luX3BlYWssIHNpZ25pZmljYW50PT1UUlVFICYgb3ZlcmxhcHNfbW90aWY9PSJub19vdmVybGFwIikKYWxsX3NhbXBsZXNfMm5kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrX3N1Yl9vdXRzaWRlX21vdGlmID0gc3Vic2V0KGFsbF9zYW1wbGVzXzJuZF9iZXN0X2Jhc2VuamlfaW5fcGVhaywgc2lnbmlmaWNhbnQ9PVRSVUUgJiBvdmVybGFwc19tb3RpZj09Im5vX292ZXJsYXAiKQphbGxfc2FtcGxlc18zbmRfYmVzdF9iYXNlbmppX2luX3BlYWtfc3ViX291dHNpZGVfbW90aWYgPSBzdWJzZXQoYWxsX3NhbXBsZXNfM25kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrLCBzaWduaWZpY2FudD09VFJVRSAmIG92ZXJsYXBzX21vdGlmPT0ibm9fb3ZlcmxhcCIpCmFsbF9zYW1wbGVzXzRuZF9iZXN0X2Jhc2VuamlfaW5fcGVha19zdWJfb3V0c2lkZV9tb3RpZiA9IHN1YnNldChhbGxfc2FtcGxlc180bmRfYmVzdF9iYXNlbmppX2luX3BlYWssIHNpZ25pZmljYW50PT1UUlVFICYgb3ZlcmxhcHNfbW90aWY9PSJub19vdmVybGFwIikKYWxsX3NhbXBsZXNfNW5kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrX3N1Yl9vdXRzaWRlX21vdGlmID0gc3Vic2V0KGFsbF9zYW1wbGVzXzVuZF9iZXN0X2Jhc2VuamlfaW5fcGVhaywgc2lnbmlmaWNhbnQ9PVRSVUUgJiBvdmVybGFwc19tb3RpZj09Im5vX292ZXJsYXAiKQoKCnN1Y2Nlc3NfcHJvcG9ydGlvbl9vbl9tb3RpZiA9IGFzLmRhdGEuZnJhbWUodChtYXRyaXgoYygiMXN0IiwgbnJvdyhzdWJzZXQoYWxsX3NhbXBsZXNfYmVzdF9iYXNlbmppX2luX3BlYWtfc3ViX29uX21vdGlmLCAoQmFzZW5qaV9BSSA+IDAuNSAmIEFJID4gMC41KSB8IChCYXNlbmppX0FJIDwgMC41ICYgQUkgPCAwLjUpKSkgLyBucm93KGFsbF9zYW1wbGVzX2Jlc3RfYmFzZW5qaV9pbl9wZWFrX3N1Yl9vbl9tb3RpZiksIAogICIybmQiLCBucm93KHN1YnNldChhbGxfc2FtcGxlc18ybmRfYmVzdF9iYXNlbmppX2luX3BlYWtfc3ViX29uX21vdGlmLCAoQmFzZW5qaV9BSSA+IDAuNSAmIEFJID4gMC41KSB8IChCYXNlbmppX0FJIDwgMC41ICYgQUkgPCAwLjUpKSkgLyBucm93KGFsbF9zYW1wbGVzXzJuZF9iZXN0X2Jhc2VuamlfaW5fcGVha19zdWJfb25fbW90aWYpLCAKICAiM3JkIiwgbnJvdyhzdWJzZXQoYWxsX3NhbXBsZXNfM25kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrX3N1Yl9vbl9tb3RpZiwgKEJhc2VuamlfQUkgPiAwLjUgJiBBSSA+IDAuNSkgfCAoQmFzZW5qaV9BSSA8IDAuNSAmIEFJIDwgMC41KSkpIC8gbnJvdyhhbGxfc2FtcGxlc18zbmRfYmVzdF9iYXNlbmppX2luX3BlYWtfc3ViX29uX21vdGlmKSwgCiAgIjR0aCIsIG5yb3coc3Vic2V0KGFsbF9zYW1wbGVzXzRuZF9iZXN0X2Jhc2VuamlfaW5fcGVha19zdWJfb25fbW90aWYsIChCYXNlbmppX0FJID4gMC41ICYgQUkgPiAwLjUpIHwgKEJhc2VuamlfQUkgPCAwLjUgJiBBSSA8IDAuNSkpKSAvIG5yb3coYWxsX3NhbXBsZXNfNG5kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrX3N1Yl9vbl9tb3RpZiksIAogICI1dGgiLCBucm93KHN1YnNldChhbGxfc2FtcGxlc181bmRfYmVzdF9iYXNlbmppX2luX3BlYWtfc3ViX29uX21vdGlmLCAoQmFzZW5qaV9BSSA+IDAuNSAmIEFJID4gMC41KSB8IChCYXNlbmppX0FJIDwgMC41ICYgQUkgPCAwLjUpKSkgLyBucm93KGFsbF9zYW1wbGVzXzVuZF9iZXN0X2Jhc2VuamlfaW5fcGVha19zdWJfb25fbW90aWYpLCAKICAiYWxsIiwgbnJvdyhzdWJzZXQoYWxsX3NhbXBsZXNfc3ViX29uX21vdGlmLCAoQmFzZW5qaV9BSSA+IDAuNSAmIEFJID4gMC41KSB8IChCYXNlbmppX0FJIDwgMC41ICYgQUkgPCAwLjUpKSkgLyBucm93KGFsbF9zYW1wbGVzX3N1Yl9vbl9tb3RpZikpLCBucm93PTIpKSkKCmNvbG5hbWVzKHN1Y2Nlc3NfcHJvcG9ydGlvbl9vbl9tb3RpZikgPSBjKCJiZXN0X0Jhc2VuamlfQUkiLCAicHJvcG9ydGlvbl9jb3JyZWN0IikKc3VjY2Vzc19wcm9wb3J0aW9uX29uX21vdGlmJHByb3BvcnRpb25fY29ycmVjdCA9IGFzLm51bWVyaWMoc3VjY2Vzc19wcm9wb3J0aW9uX29uX21vdGlmJHByb3BvcnRpb25fY29ycmVjdCkKCgoKCgpzdWNjZXNzX3Byb3BvcnRpb25fb3V0c2lkZV9tb3RpZiA9IGFzLmRhdGEuZnJhbWUodChtYXRyaXgoYygiMXN0IiwgbnJvdyhzdWJzZXQoYWxsX3NhbXBsZXNfYmVzdF9iYXNlbmppX2luX3BlYWtfc3ViX291dHNpZGVfbW90aWYsIChCYXNlbmppX0FJID4gMC41ICYgQUkgPiAwLjUpIHwgKEJhc2VuamlfQUkgPCAwLjUgJiBBSSA8IDAuNSkpKSAvIG5yb3coYWxsX3NhbXBsZXNfYmVzdF9iYXNlbmppX2luX3BlYWtfc3ViX291dHNpZGVfbW90aWYpLCAKICAiMm5kIiwgbnJvdyhzdWJzZXQoYWxsX3NhbXBsZXNfMm5kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrX3N1Yl9vdXRzaWRlX21vdGlmLCAoQmFzZW5qaV9BSSA+IDAuNSAmIEFJID4gMC41KSB8IChCYXNlbmppX0FJIDwgMC41ICYgQUkgPCAwLjUpKSkgLyBucm93KGFsbF9zYW1wbGVzXzJuZF9iZXN0X2Jhc2VuamlfaW5fcGVha19zdWJfb3V0c2lkZV9tb3RpZiksIAogICIzcmQiLCBucm93KHN1YnNldChhbGxfc2FtcGxlc18zbmRfYmVzdF9iYXNlbmppX2luX3BlYWtfc3ViX291dHNpZGVfbW90aWYsIChCYXNlbmppX0FJID4gMC41ICYgQUkgPiAwLjUpIHwgKEJhc2VuamlfQUkgPCAwLjUgJiBBSSA8IDAuNSkpKSAvIG5yb3coYWxsX3NhbXBsZXNfM25kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrX3N1Yl9vdXRzaWRlX21vdGlmKSwgCiAgIjR0aCIsIG5yb3coc3Vic2V0KGFsbF9zYW1wbGVzXzRuZF9iZXN0X2Jhc2VuamlfaW5fcGVha19zdWJfb3V0c2lkZV9tb3RpZiwgKEJhc2VuamlfQUkgPiAwLjUgJiBBSSA+IDAuNSkgfCAoQmFzZW5qaV9BSSA8IDAuNSAmIEFJIDwgMC41KSkpIC8gbnJvdyhhbGxfc2FtcGxlc180bmRfYmVzdF9iYXNlbmppX2luX3BlYWtfc3ViX291dHNpZGVfbW90aWYpLCAKICAiNXRoIiwgbnJvdyhzdWJzZXQoYWxsX3NhbXBsZXNfNW5kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrX3N1Yl9vdXRzaWRlX21vdGlmLCAoQmFzZW5qaV9BSSA+IDAuNSAmIEFJID4gMC41KSB8IChCYXNlbmppX0FJIDwgMC41ICYgQUkgPCAwLjUpKSkgLyBucm93KGFsbF9zYW1wbGVzXzVuZF9iZXN0X2Jhc2VuamlfaW5fcGVha19zdWJfb3V0c2lkZV9tb3RpZiksIAogICJhbGwiLCBucm93KHN1YnNldChhbGxfc2FtcGxlc19zdWJfb3V0c2lkZV9tb3RpZiwgKEJhc2VuamlfQUkgPiAwLjUgJiBBSSA+IDAuNSkgfCAoQmFzZW5qaV9BSSA8IDAuNSAmIEFJIDwgMC41KSkpIC8gbnJvdyhhbGxfc2FtcGxlc19zdWJfb3V0c2lkZV9tb3RpZikpLCBucm93PTIpKSkKCmNvbG5hbWVzKHN1Y2Nlc3NfcHJvcG9ydGlvbl9vdXRzaWRlX21vdGlmKSA9IGMoImJlc3RfQmFzZW5qaV9BSSIsICJwcm9wb3J0aW9uX2NvcnJlY3QiKQpzdWNjZXNzX3Byb3BvcnRpb25fb3V0c2lkZV9tb3RpZiRwcm9wb3J0aW9uX2NvcnJlY3QgPSBhcy5udW1lcmljKHN1Y2Nlc3NfcHJvcG9ydGlvbl9vdXRzaWRlX21vdGlmJHByb3BvcnRpb25fY29ycmVjdCkKCgoKCmJhY2tncm91bmRfc3VjY2Vzc19wcm9wb3J0aW9uX2RmID0gZGF0YS5mcmFtZShyb3cubmFtZXMgPSBjKCIxc3QiLCAiMm5kIiwgIjNyZCIsICI0dGgiLCAiNXRoIiwgImFsbCIpKQoKZm9yIChpIGluIHNlcSgxLCAxMDAwKSkgewogIAogIGFsbF9zYW1wbGVzX3ZhcmlhbnQgPSBzdWJzZXQoYWxsX3NhbXBsZXMpCiAgYmFja2dyb3VuZF92YXJpYW50X3NodWZmID0gYWxsX3NhbXBsZXNfdmFyaWFudCAlPiUgCiAgICBzZWxlY3QodmFyaWFudF9JRCwgcGVha19JRCwgc2lnbmlmaWNhbnQsIGNvcnJlY3RfcHJlZGljdCkgJT4lCiAgICBncm91cF9ieShwZWFrX0lEKSAlPiUKICAgIG11dGF0ZShyYW5rPXNhbXBsZShyb3dfbnVtYmVyKCkpKSAlPiUKICAgIHVuZ3JvdXAoKQogIGJhY2tncm91bmRfYmVzdF92YXJpYW50X3NodWZmID0gc3Vic2V0KGJhY2tncm91bmRfdmFyaWFudF9zaHVmZiwgcmFuaz09MSAmIHNpZ25pZmljYW50PT1UUlVFKQogIGJhY2tncm91bmRfMm5kX2Jlc3RfdmFyaWFudF9zaHVmZiA9IHN1YnNldChiYWNrZ3JvdW5kX3ZhcmlhbnRfc2h1ZmYsIHJhbms9PTIgJiBzaWduaWZpY2FudD09VFJVRSkKICBiYWNrZ3JvdW5kXzNuZF9iZXN0X3ZhcmlhbnRfc2h1ZmYgPSBzdWJzZXQoYmFja2dyb3VuZF92YXJpYW50X3NodWZmLCByYW5rPT0zICYgc2lnbmlmaWNhbnQ9PVRSVUUpCiAgYmFja2dyb3VuZF80bmRfYmVzdF92YXJpYW50X3NodWZmID0gc3Vic2V0KGJhY2tncm91bmRfdmFyaWFudF9zaHVmZiwgcmFuaz09NCAmIHNpZ25pZmljYW50PT1UUlVFKQogIGJhY2tncm91bmRfNW5kX2Jlc3RfdmFyaWFudF9zaHVmZiA9IHN1YnNldChiYWNrZ3JvdW5kX3ZhcmlhbnRfc2h1ZmYsIHJhbms9PTUgJiBzaWduaWZpY2FudD09VFJVRSkKCiAgYmFja2dyb3VuZF9zdWNjZXNzX3Byb3BvcnRpb24gPSBhcy5kYXRhLmZyYW1lKHQobWF0cml4KGMoIjFzdCIsIG5yb3coc3Vic2V0KGJhY2tncm91bmRfYmVzdF92YXJpYW50X3NodWZmLCAoY29ycmVjdF9wcmVkaWN0PT0iY29ycmVjdCIpKSkgLyBucm93KGJhY2tncm91bmRfYmVzdF92YXJpYW50X3NodWZmKSwgCiAgIjJuZCIsIG5yb3coc3Vic2V0KGJhY2tncm91bmRfMm5kX2Jlc3RfdmFyaWFudF9zaHVmZiwgKGNvcnJlY3RfcHJlZGljdD09ImNvcnJlY3QiKSkpIC8gbnJvdyhiYWNrZ3JvdW5kXzJuZF9iZXN0X3ZhcmlhbnRfc2h1ZmYpLCAKICAiM3JkIiwgbnJvdyhzdWJzZXQoYmFja2dyb3VuZF8zbmRfYmVzdF92YXJpYW50X3NodWZmLCAoY29ycmVjdF9wcmVkaWN0PT0iY29ycmVjdCIpKSkgLyBucm93KGJhY2tncm91bmRfM25kX2Jlc3RfdmFyaWFudF9zaHVmZiksIAogICI0dGgiLCBucm93KHN1YnNldChiYWNrZ3JvdW5kXzRuZF9iZXN0X3ZhcmlhbnRfc2h1ZmYsIChjb3JyZWN0X3ByZWRpY3Q9PSJjb3JyZWN0IikpKSAvIG5yb3coYmFja2dyb3VuZF80bmRfYmVzdF92YXJpYW50X3NodWZmKSwgCiAgIjV0aCIsIG5yb3coc3Vic2V0KGJhY2tncm91bmRfNW5kX2Jlc3RfdmFyaWFudF9zaHVmZiwgKGNvcnJlY3RfcHJlZGljdD09ImNvcnJlY3QiKSkpIC8gbnJvdyhiYWNrZ3JvdW5kXzVuZF9iZXN0X3ZhcmlhbnRfc2h1ZmYpLCAKICAiYWxsIiwgbnJvdyhzdWJzZXQoYmFja2dyb3VuZF92YXJpYW50X3NodWZmLCAoY29ycmVjdF9wcmVkaWN0PT0iY29ycmVjdCIpKSkgLyBucm93KGJhY2tncm91bmRfdmFyaWFudF9zaHVmZikpLCBucm93PTIpKSkKCiAgY29sbmFtZXMoYmFja2dyb3VuZF9zdWNjZXNzX3Byb3BvcnRpb24pID0gYygiYmVzdF9CYXNlbmppX0FJIiwgInByb3BvcnRpb25fY29ycmVjdCIpCiAgYmFja2dyb3VuZF9zdWNjZXNzX3Byb3BvcnRpb24kcHJvcG9ydGlvbl9jb3JyZWN0ID0gYXMubnVtZXJpYyhiYWNrZ3JvdW5kX3N1Y2Nlc3NfcHJvcG9ydGlvbiRwcm9wb3J0aW9uX2NvcnJlY3QpCgogIGJhY2tncm91bmRfc3VjY2Vzc19wcm9wb3J0aW9uX2RmID0gY2JpbmQoYmFja2dyb3VuZF9zdWNjZXNzX3Byb3BvcnRpb25fZGYsIGJhY2tncm91bmRfc3VjY2Vzc19wcm9wb3J0aW9uJHByb3BvcnRpb25fY29ycmVjdCkKfQoKCmJhY2tncm91bmRfc3VjY2Vzc19wcm9wb3J0aW9uX3N1bW1hcnkgPSBkYXRhLmZyYW1lKGJhY2tncm91bmRfbWVhbiA9IHJvd01lYW5zKGJhY2tncm91bmRfc3VjY2Vzc19wcm9wb3J0aW9uX2RmKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZF9zdGQgPSBhcHBseShiYWNrZ3JvdW5kX3N1Y2Nlc3NfcHJvcG9ydGlvbl9kZiwgMSwgc2QsIG5hLnJtID0gVFJVRSkpCmJhY2tncm91bmRfc3VjY2Vzc19wcm9wb3J0aW9uX3N1bW1hcnkkYmVzdF9CYXNlbmppX0FJID0gcm93bmFtZXMoYmFja2dyb3VuZF9zdWNjZXNzX3Byb3BvcnRpb25fc3VtbWFyeSkKCgoKCnN1Y2Nlc3NfcHJvcG9ydGlvbl9vbl9tb3RpZiA9IHN1Y2Nlc3NfcHJvcG9ydGlvbl9vbl9tb3RpZltjKDEsMiwzLDQsNSksIF0Kc3VjY2Vzc19wcm9wb3J0aW9uX291dHNpZGVfbW90aWYgPSBzdWNjZXNzX3Byb3BvcnRpb25fb3V0c2lkZV9tb3RpZltjKDEsMiwzLDQsNSksIF0KYmFja2dyb3VuZF9zdWNjZXNzX3Byb3BvcnRpb25fc3VtbWFyeSA9IGJhY2tncm91bmRfc3VjY2Vzc19wcm9wb3J0aW9uX3N1bW1hcnlbYygxLDIsMyw0LDUpLCBdCgoKCnAgPSBnZ3Bsb3QoKSArCiAgICBnZW9tX3BvaW50KGRhdGEgPSBzdWNjZXNzX3Byb3BvcnRpb25fb25fbW90aWYsIGFlcyh4PWJlc3RfQmFzZW5qaV9BSSwgeT1wcm9wb3J0aW9uX2NvcnJlY3QsIGdyb3VwPTEpLCBzaXplPTMsIGNvbG91cj0iI0ZGQTczNiIpICsKICAgIGdlb21fbGluZShkYXRhID0gc3VjY2Vzc19wcm9wb3J0aW9uX29uX21vdGlmLCBhZXMoeD1iZXN0X0Jhc2VuamlfQUksIHk9cHJvcG9ydGlvbl9jb3JyZWN0LCBncm91cD0xKSwgY29sb3VyPSIjRkZBNzM2IikgKwogICAgZ2VvbV9wb2ludChkYXRhID0gc3VjY2Vzc19wcm9wb3J0aW9uX291dHNpZGVfbW90aWYsIGFlcyh4PWJlc3RfQmFzZW5qaV9BSSwgeT1wcm9wb3J0aW9uX2NvcnJlY3QsIGdyb3VwPTEpLCBzaXplPTMsIGNvbG91cj0iZ3JleTE1IikgKwogICAgZ2VvbV9saW5lKGRhdGEgPSBzdWNjZXNzX3Byb3BvcnRpb25fb3V0c2lkZV9tb3RpZiwgYWVzKHg9YmVzdF9CYXNlbmppX0FJLCB5PXByb3BvcnRpb25fY29ycmVjdCwgZ3JvdXA9MSksIGNvbG91cj0iZ3JleTE1IikgKwogICBnZW9tX2xpbmUoZGF0YT1iYWNrZ3JvdW5kX3N1Y2Nlc3NfcHJvcG9ydGlvbl9zdW1tYXJ5LCBhZXMoeD1iZXN0X0Jhc2VuamlfQUksIHkgPSBiYWNrZ3JvdW5kX21lYW4sIGdyb3VwPTEpLCBjb2xvciA9ICJncmV5NjAiLCBsaW5ld2lkdGggPSAxKSArIAogIGdlb21fcmliYm9uKGRhdGE9YmFja2dyb3VuZF9zdWNjZXNzX3Byb3BvcnRpb25fc3VtbWFyeSwgYWVzKHg9YmVzdF9CYXNlbmppX0FJLCB5ID0gYmFja2dyb3VuZF9tZWFuLCB5bWluID0gYmFja2dyb3VuZF9tZWFuIC0gYmFja2dyb3VuZF9zdGQgKiAyLCB5bWF4ID0gYmFja2dyb3VuZF9tZWFuICsgYmFja2dyb3VuZF9zdGQgKiAyLCBncm91cD0xKSwgZmlsbCA9ICJncmV5NzAiLCBhbHBoYSA9IC4yKSArCiAgICB5bGltKDAuNDcsIDEpICsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuNSwgY29sb3VyID0gIiNDOTJCMjciLCBsaW5ldHlwZT0iZGFzaGVkIikgKwogICAgZ2VvbV90ZXh0KGRhdGEgPSBzdWNjZXNzX3Byb3BvcnRpb25fb25fbW90aWYsIGFlcyh4ID0gYmVzdF9CYXNlbmppX0FJLCB5ID0gcHJvcG9ydGlvbl9jb3JyZWN0LCBsYWJlbD1yb3VuZChwcm9wb3J0aW9uX2NvcnJlY3QsIDMpKSwgY29sb3VyPSJncmV5MTUiLCBmb250ZmFjZSA9IDIsIHNpemUgPSA0LCB2anVzdD0tMikgKwogICAgZ2VvbV90ZXh0KGRhdGEgPSBzdWNjZXNzX3Byb3BvcnRpb25fb3V0c2lkZV9tb3RpZiwgYWVzKHggPSBiZXN0X0Jhc2VuamlfQUksIHkgPSBwcm9wb3J0aW9uX2NvcnJlY3QsIGxhYmVsPXJvdW5kKHByb3BvcnRpb25fY29ycmVjdCwgMykpLCBjb2xvdXI9ImdyZXkxNSIsIGZvbnRmYWNlID0gMiwgc2l6ZSA9IDQsIHZqdXN0PS0yKSArCiAgICB4bGFiKCJCZXN0IHZhcmlhbnQgb3JkZXIgKEJhc2VuamkgQUkpIikgKwogICAgeWxhYigiUHJvcG9ydGlvbiBvZiBjb3JyZWN0IHByZWRpY3Rpb25zIChBSSBkaXJlY3Rpb24pIikgKwogICAgdGhlbWVfYncoKSArIAogICAgdGhlbWUocGFuZWwuZ3JpZCA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JleTgwIiwgbGluZXdpZHRoID0gMSksIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpKSArCiAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xMikpICsKICAgIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2xpbmUobGluZXdpZHRoID0gMC4yNSksIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUobGluZXdpZHRoID0gMC41KSkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKcApvdXRmID0gZmlsZS5wYXRoKG91dGRpcl9maWdfc3VwcGwsIHBhc3RlMCgiRmlnUzdBX1ZhcmlhbnRzX3ByaW9yaXR5X21vdGlmc19vdmVybGFwLnBkZiIpKQpnZ3NhdmUob3V0ZiwgcCwgd2lkdGggPSA2LCBoZWlnaHQgPSA0KQpgYGAKCgojIEZpZ3VyZSBTN0IKCgpgYGB7ciB9CmdpdmUubiA8LSBmdW5jdGlvbih4KXsKICByZXR1cm4oYyh5ID0gMC4wMjUsIGxhYmVsID0gbGVuZ3RoKHgpKSkgCiAgIyBleHBlcmltZW50IHdpdGggdGhlIG11bHRpcGxpZXIgdG8gZmluZCB0aGUgcGVyZmVjdCBwb3NpdGlvbgp9CgoKYWxsX3NhbXBsZXMkb3ZlcmxhcHNfbW90aWYgPSBmYWN0b3IoYWxsX3NhbXBsZXMkb3ZlcmxhcHNfbW90aWYsIGxldmVscz1jKCJvdmVybGFwc19tb3RpZiIsICJub19vdmVybGFwIikpCmFsbF9zYW1wbGVzX3NpZ25fcGVhayA9IHN1YnNldChhbGxfc2FtcGxlcywgcGVha19JRCAlaW4lIHVuaXF1ZShzdWJzZXQoYWxsX3NhbXBsZXMsIHNpZ25pZmljYW50PT1UUlVFKSRwZWFrX0lEKSApCgpwID0gZ2dwbG90KGFsbF9zYW1wbGVzX3NpZ25fcGVhaywgYWVzKHg9b3ZlcmxhcHNfbW90aWYsIHk9QmFzZW5qaV9hYnNfQUksIGZpbGw9b3ZlcmxhcHNfbW90aWYpKSArIAogICAgZ2VvbV92aW9saW4od2lkdGg9MS4xNSkgKyAKICAgIGdlb21fYm94cGxvdCh3aWR0aD0wLjAyLCBvdXRsaWVyLnNoYXBlID0gTkEsIGZpbGw9IndoaXRlIiwgYWxwaGE9MC43NSkgKwogICAgeWxpbSgwLDAuMDEwKSArCiAgICB4bGFiKCJWYXJpYW50IG92ZXJsYXBzIGNvZ25hdGUgbW90aWYiKSArCiAgICB5bGFiKCJCYXNlbmppIGFic29sdXRlIHBBSSIpICsKICAgIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IGdpdmUubiwgZ2VvbSA9ICJ0ZXh0IiwgZnVuLnkgPSAwLjI1KSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjRkZBNzM2IiwgImdyZXk3MCIpKSArCiAgICB0aGVtZV9idygpICsgCiAgICB0aGVtZShwYW5lbC5ncmlkID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmV5ODAiLCBsaW5ld2lkdGggPSAxKSwgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpICsKICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSkgKwogICAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfbGluZShsaW5ld2lkdGggPSAwLjI1KSwgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShsaW5ld2lkdGggPSAwLjUpKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgoKcApvdXRmID0gZmlsZS5wYXRoKG91dGRpcl9maWdfc3VwcGwsIHBhc3RlMCgiRmlnUzdCX0Rpc3RyaWJ1dGlvbl9vZl9hYnNfQUlfbW90aWZfb3ZlcmxhcC5wZGYiKSkKZ2dzYXZlKG91dGYsIHAsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNCkKYGBgCgpXaWxjb3hvbiBwdmFsdWU6IGByIHdpbGNveC50ZXN0KHN1YnNldChhbGxfc2FtcGxlcywgb3ZlcmxhcHNfbW90aWY9PSJvdmVybGFwc19tb3RpZiIpJEJhc2VuamlfYWJzX0FJLCBzdWJzZXQoYWxsX3NhbXBsZXMsIG92ZXJsYXBzX21vdGlmPT0ibm9fb3ZlcmxhcCIpJEJhc2VuamlfYWJzX0FJKSRwLnZhbHVlYCAgIAoKCiMgRmlndXJlIFM3QwoKYGBge3IgfQphbGxfc2FtcGxlc19iZXN0X2Jhc2Vuamlfc3ViID0gc3Vic2V0KGFsbF9zYW1wbGVzX2Jlc3RfYmFzZW5qaV9pbl9wZWFrLCBzaWduaWZpY2FudD09VFJVRSkKYWxsX3NhbXBsZXNfMm5kX2Jlc3RfYmFzZW5qaV9zdWIgPSBzdWJzZXQoYWxsX3NhbXBsZXNfMm5kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrLCBzaWduaWZpY2FudD09VFJVRSkKYWxsX3NhbXBsZXNfM25kX2Jlc3RfYmFzZW5qaV9zdWIgPSBzdWJzZXQoYWxsX3NhbXBsZXNfM25kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrLCBzaWduaWZpY2FudD09VFJVRSkKYWxsX3NhbXBsZXNfNG5kX2Jlc3RfYmFzZW5qaV9zdWIgPSBzdWJzZXQoYWxsX3NhbXBsZXNfNG5kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrLCBzaWduaWZpY2FudD09VFJVRSkKYWxsX3NhbXBsZXNfNW5kX2Jlc3RfYmFzZW5qaV9zdWIgPSBzdWJzZXQoYWxsX3NhbXBsZXNfNW5kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrLCBzaWduaWZpY2FudD09VFJVRSkKCmFsbF9zYW1wbGVzX3JhbmtfdmFyaWFudHMgPSByYmluZChhbGxfc2FtcGxlc19iZXN0X2Jhc2Vuamlfc3ViLCBhbGxfc2FtcGxlc18ybmRfYmVzdF9iYXNlbmppX3N1YiwgYWxsX3NhbXBsZXNfM25kX2Jlc3RfYmFzZW5qaV9zdWIsIGFsbF9zYW1wbGVzXzRuZF9iZXN0X2Jhc2Vuamlfc3ViLCBhbGxfc2FtcGxlc181bmRfYmVzdF9iYXNlbmppX3N1YikKCnBlcmNlbnRhZ2VzID0gZGF0YS5mcmFtZSh0YWJsZShhbGxfc2FtcGxlc19yYW5rX3ZhcmlhbnRzWywgYygiYmVzdF92YXJpYW50IiwgIm92ZXJsYXBzX21vdGlmIildKSkgJT4lIAogICAgICAgIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPW92ZXJsYXBzX21vdGlmLCB2YWx1ZXNfZnJvbSA9IEZyZXEpCnBlcmNlbnRhZ2VzJHRvdCA9IHBlcmNlbnRhZ2VzJG5vX292ZXJsYXAgKyBwZXJjZW50YWdlcyRvdmVybGFwc19tb3RpZgpwZXJjZW50YWdlcyRub19vdmVybGFwID0gcGVyY2VudGFnZXMkbm9fb3ZlcmxhcCAvIHBlcmNlbnRhZ2VzJHRvdApwZXJjZW50YWdlcyRvdmVybGFwc19tb3RpZiA9IHBlcmNlbnRhZ2VzJG92ZXJsYXBzX21vdGlmIC8gcGVyY2VudGFnZXMkdG90CnBlcmNlbnRhZ2VzID0gcGVyY2VudGFnZXMgJT4lCiAgICBzZWxlY3QoYmVzdF92YXJpYW50LCBub19vdmVybGFwLCBvdmVybGFwc19tb3RpZikgJT4lCiAgICBwaXZvdF9sb25nZXIoY29scyA9IGMobm9fb3ZlcmxhcCwgb3ZlcmxhcHNfbW90aWYpKQpjb2xuYW1lcyhwZXJjZW50YWdlcykgPSBjKCJiZXN0X3ZhcmlhbnQiLCAib3ZlcmxhcHNfbW90aWYiLCAicmF0aW8iKQoKcCA9IGdncGxvdChwZXJjZW50YWdlcywgYWVzKHg9YmVzdF92YXJpYW50LCB5PXJhdGlvLCBmaWxsPW92ZXJsYXBzX21vdGlmKSkgKyAKICAgIGdlb21fY29sKHBvc2l0aW9uPSJmaWxsIikgKwogICAgeGxhYigiQmVzdCB2YXJpYW50IG9yZGVyIChCYXNlbmppIEFJKSIpICsKICAgIHlsYWIoIlByb3BvcnRpb24gb2YgdmFyaWFudHMgb3ZlcmxhcHBpbmcgY29nbmF0ZSBtb3RpZiIpICsKICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImdyZXk3MCIsICIjRkZBNzM2IikpICsKICAgIHRoZW1lX2J3KCkgKyAKICAgIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZTAocm91bmQocmF0aW8qMTAwLCAxKSwgIiUiKSksIHBvc2l0aW9uID0gcG9zaXRpb25fZmlsbCh2anVzdCA9IDAuNSksIHNpemU9NSkgKwogICAgdGhlbWUocGFuZWwuZ3JpZCA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JleTgwIiwgbGluZXdpZHRoID0gMSksIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpKSArCiAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xMikpICsKICAgIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2xpbmUobGluZXdpZHRoID0gMC4yNSksIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUobGluZXdpZHRoID0gMC41KSkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKcAoKb3V0ZiA9IGZpbGUucGF0aChvdXRkaXJfZmlnX3N1cHBsLCBwYXN0ZTAoIkZpZ1M3Q19Qcm9wb3J0aW9uX29mX3JhbmtzX21vdGlmc19vdmVybGFwLnBkZiIpKQpnZ3NhdmUob3V0ZiwgcCwgd2lkdGggPSA2LCBoZWlnaHQgPSA2KQpgYGAKCgoKCiMgRmlndXJlIFM3RAoKYGBge3IgfQpzYXR1cmF0aW9uX3Njb3Jlc19wcmVkaWN0aW9ucyA9IHJlYWQudGFibGUoIi9nL2Z1cmxvbmcvcHJvamVjdC8xMDNfQmFzZW5qaS9NYXR0aWEvYW5hbHlzaXMvc2F0dXJhdGlvbl9zY29yZXMvQmFzZW5qaV9EYXRhVGFibGVfcHJlZGljdGlvbnMudHh0IiwgaGVhZGVyPVRSVUUpCnNhdHVyYXRpb25fc2NvcmVzX3ByZWRpY3Rpb25zJEJhc2VuamlfcHJlZGljdCA9IGdzdWIoIjAiLCAibm9fcHJlZGljdGlvbiIsIGdzdWIoIjEiLCAiZnVsbF9wcmVkaWN0aW9uIiwgZ3N1YigicGFydGlhbGx5IiwgInBhcnRpYWxfcHJlZGljdGlvbiIsIHNhdHVyYXRpb25fc2NvcmVzX3ByZWRpY3Rpb25zJEJhc2VuamlfcHJlZGljdCkpKQpzYXR1cmF0aW9uX3Njb3Jlc19wcmVkaWN0aW9ucyRCYXNlbmppX3ByZWRpY3QgPSBmYWN0b3Ioc2F0dXJhdGlvbl9zY29yZXNfcHJlZGljdGlvbnMkQmFzZW5qaV9wcmVkaWN0LCBsZXZlbHM9YygiZnVsbF9wcmVkaWN0aW9uIiwgInBhcnRpYWxfcHJlZGljdGlvbiIsICJub19wcmVkaWN0aW9uIikpCgpzYXR1cmF0aW9uX3Njb3Jlc19wcmVkaWN0aW9ucyRtb3RpZl9vbl92YXJpYW50ID0gaWZlbHNlKHNhdHVyYXRpb25fc2NvcmVzX3ByZWRpY3Rpb25zJHZhcmlhbnRfaW5fc2VsZl9tb3RpZiA9PSAxLCAic2VsZl9tb3RpZiIsIGlmZWxzZShzYXR1cmF0aW9uX3Njb3Jlc19wcmVkaWN0aW9ucyR2YXJpYW50X2luX290aGVyX21vdGlmID09IDEsICJjb2ZhY3Rvcl9tb3RpZiIsIGlmZWxzZShzYXR1cmF0aW9uX3Njb3Jlc19wcmVkaWN0aW9ucyRCYXNlbmppX3ByZWRpY3QgPT0gIm5vX3ByZWRpY3Rpb24iLCAibm9fcHJlZGljdGlvbiIsICJub19tb3RpZiIpKSkKc2F0dXJhdGlvbl9zY29yZXNfcHJlZGljdGlvbnMkbW90aWZfb25fdmFyaWFudCA9IGZhY3RvcihzYXR1cmF0aW9uX3Njb3Jlc19wcmVkaWN0aW9ucyRtb3RpZl9vbl92YXJpYW50LCBsZXZlbHM9Yygic2VsZl9tb3RpZiIsICJjb2ZhY3Rvcl9tb3RpZiIsIm5vX21vdGlmIiwgIm5vX3ByZWRpY3Rpb24iKSkKc2F0dXJhdGlvbl9zY29yZXNfcHJlZGljdGlvbnMkY29uZGl0aW9uID0gZmFjdG9yKHNhdHVyYXRpb25fc2NvcmVzX3ByZWRpY3Rpb25zJGNvbmRpdGlvbiwgbGV2ZWxzPWMoInR3aS4yNCIsICJjdGNmLjY4IiwgIm1lZjIuNjgiLCAibWVmMi4xMDEyIiwgImJpbi42OCIsICJiaW4uMTAxMiIpKQpzYXR1cmF0aW9uX3Njb3Jlc19wcmVkaWN0aW9ucyRtb3RpZnNfcHJlZGljdGlvbnMgPSBpZmVsc2Uoc2F0dXJhdGlvbl9zY29yZXNfcHJlZGljdGlvbnMkc2VsZl9tb3RpZiA9PSAxICYgc2F0dXJhdGlvbl9zY29yZXNfcHJlZGljdGlvbnMkY29mYWN0b3JfbW90aWYgPT0gMSwgInNlbGZfYW5kX2NvZmFjdG9yIiwgaWZlbHNlKHNhdHVyYXRpb25fc2NvcmVzX3ByZWRpY3Rpb25zJHNlbGZfbW90aWYgPT0gMSwgInNlbGZfbW90aWYiLCAgaWZlbHNlKHNhdHVyYXRpb25fc2NvcmVzX3ByZWRpY3Rpb25zJGNvZmFjdG9yX21vdGlmID09IDEsICJjb2ZhY3Rvcl9tb3RpZiIsIGlmZWxzZShzYXR1cmF0aW9uX3Njb3Jlc19wcmVkaWN0aW9ucyRCYXNlbmppX3ByZWRpY3QgPT0gIm5vX3ByZWRpY3Rpb24iLCAibm9fcHJlZGljdGlvbiIgLCJub19tb3RpZiIpKSkpCnNhdHVyYXRpb25fc2NvcmVzX3ByZWRpY3Rpb25zJG1vdGlmc19wcmVkaWN0aW9ucyA9IGZhY3RvcihzYXR1cmF0aW9uX3Njb3Jlc19wcmVkaWN0aW9ucyRtb3RpZnNfcHJlZGljdGlvbnMsIGxldmVscz1jKCJzZWxmX2FuZF9jb2ZhY3RvciIsICJzZWxmX21vdGlmIiwgImNvZmFjdG9yX21vdGlmIiwgIm5vX21vdGlmIiwgIm5vX3ByZWRpY3Rpb24iKSkKCnAgPSBwbG90X2NvdW50c19iYXJwbG90KHNhdHVyYXRpb25fc2NvcmVzX3ByZWRpY3Rpb25zLCAiY29uZGl0aW9uIiwgIm1vdGlmc19wcmVkaWN0aW9ucyIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjMzM5MDI0IiwgIiNGRjIzNDEiLCAiI0ZGQTczNiIsICJncmV5NzAiLCAiZ3JleTE1IikpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsPWNvdW50cyksICBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSwgY29sb3VyPSJ3aGl0ZSIpICsKICBsYWJzKGZpbGw9InByZWRpY3RlZF9tb3RpZnMiKQpwCgpvdXRmID0gZmlsZS5wYXRoKG91dGRpcl9maWdfc3VwcGwsIHBhc3RlMCgiRmlnUzdEX2Jhc2VuamlfcHJlZGljdGlvbnNfYnlfcHJlZGljdGVkX21vdGlmLnBkZiIpKQpnZ3NhdmUob3V0ZiwgcCwgd2lkdGggPSAzLCBoZWlnaHQgPSAzKQpgYGAKCiMgRmlndXJlIFM3RQoKYGBge3IgcGxvdF9tb3RpZl9pbl92YXJpYW50LCBjb21tZW50PU5BLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gMTJ9CnAgPSBwbG90X2NvdW50c19iYXJwbG90KHNhdHVyYXRpb25fc2NvcmVzX3ByZWRpY3Rpb25zLCAiY29ycmVjdF9wcmVkaWN0IiwgIm1vdGlmX29uX3ZhcmlhbnQiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI0ZGMjM0MSIsICIjRkZBNzM2IiwgImdyZXk3MCIsICJncmV5MTUiKSkgKwogIGdlb21fdGV4dChhZXMobGFiZWw9Y291bnRzKSwgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpLCBjb2xvdXI9IndoaXRlIikgKwogIGxhYnMoZmlsbD0ibW90aWYgb24gdmFyaWFudCIpICsKICBnZ3RpdGxlKCJQcmVkaWN0aW9ucyBhbmQgbW90aWYgb24gdmFyaWFudCIpCgpwCgpvdXRmID0gZmlsZS5wYXRoKG91dGRpcl9maWdfc3VwcGwsIHBhc3RlMCgiRmlnUzdFX2Jhc2VuamlfcHJlZGljdGlvbnNfYnlfcHJlZGljdGVkX21vdGlmX2NvcnJlY3QucGRmIikpCmdnc2F2ZShvdXRmLCBwLCB3aWR0aCA9IDMsIGhlaWdodCA9IDMpCmBgYAoKCgoKCgoKIyBGaWd1cmUgUzdGCgpgYGB7ciB9CnR3aV8yNGggPSByZWFkX2lucHV0KCIvZy9mdXJsb25nL3Byb2plY3QvMTAzX0Jhc2VuamkvTWF0dGlhL2FuYWx5c2lzL2NvcnJlbGF0aW9ucy9CYXNlbmppX3Njb3Jlc19hbmRfYWxsZWxpY19pbWJhbGFuY2VfdHdpLjI0X2Fubm90LnR4dCIpCnR3aV8yNGhfYmVzdF9iYXNlbmppX2luX3BlYWsgPSB0YWtlX2Jlc3RfQmFzZW5qaV9pbl9wZWFrKHR3aV8yNGgpCgpiaW5fNjhoID0gcmVhZF9pbnB1dCgiL2cvZnVybG9uZy9wcm9qZWN0LzEwM19CYXNlbmppL01hdHRpYS9hbmFseXNpcy9jb3JyZWxhdGlvbnMvQmFzZW5qaV9zY29yZXNfYW5kX2FsbGVsaWNfaW1iYWxhbmNlX2Jpbi42OF9hbm5vdC50eHQiKQpiaW5fNjhoX2Jlc3RfYmFzZW5qaV9pbl9wZWFrID0gdGFrZV9iZXN0X0Jhc2VuamlfaW5fcGVhayhiaW5fNjhoKQoKY3RjZl82OGggPSByZWFkX2lucHV0KCIvZy9mdXJsb25nL3Byb2plY3QvMTAzX0Jhc2VuamkvTWF0dGlhL2FuYWx5c2lzL2NvcnJlbGF0aW9ucy9CYXNlbmppX3Njb3Jlc19hbmRfYWxsZWxpY19pbWJhbGFuY2VfY3RjZi42OF9hbm5vdC50eHQiKQpjdGNmXzY4aF9iZXN0X2Jhc2VuamlfaW5fcGVhayA9IHRha2VfYmVzdF9CYXNlbmppX2luX3BlYWsoY3RjZl82OGgpCgptZWYyXzY4aCA9IHJlYWRfaW5wdXQoIi9nL2Z1cmxvbmcvcHJvamVjdC8xMDNfQmFzZW5qaS9NYXR0aWEvYW5hbHlzaXMvY29ycmVsYXRpb25zL0Jhc2Vuamlfc2NvcmVzX2FuZF9hbGxlbGljX2ltYmFsYW5jZV9tZWYyLjY4X2Fubm90LnR4dCIpCm1lZjJfNjhoX2Jlc3RfYmFzZW5qaV9pbl9wZWFrID0gdGFrZV9iZXN0X0Jhc2VuamlfaW5fcGVhayhtZWYyXzY4aCkKCmJpbl8xMDEyaCA9IHJlYWRfaW5wdXQoIi9nL2Z1cmxvbmcvcHJvamVjdC8xMDNfQmFzZW5qaS9NYXR0aWEvYW5hbHlzaXMvY29ycmVsYXRpb25zL0Jhc2Vuamlfc2NvcmVzX2FuZF9hbGxlbGljX2ltYmFsYW5jZV9iaW4uMTAxMl9hbm5vdC50eHQiKQpiaW5fMTAxMmhfYmVzdF9iYXNlbmppX2luX3BlYWsgPSB0YWtlX2Jlc3RfQmFzZW5qaV9pbl9wZWFrKGJpbl8xMDEyaCkKCm1lZjJfMTAxMmggPSByZWFkX2lucHV0KCIvZy9mdXJsb25nL3Byb2plY3QvMTAzX0Jhc2VuamkvTWF0dGlhL2FuYWx5c2lzL2NvcnJlbGF0aW9ucy9CYXNlbmppX3Njb3Jlc19hbmRfYWxsZWxpY19pbWJhbGFuY2VfbWVmMi4xMDEyX2Fubm90LnR4dCIpCm1lZjJfMTAxMmhfYmVzdF9iYXNlbmppX2luX3BlYWsgPSB0YWtlX2Jlc3RfQmFzZW5qaV9pbl9wZWFrKG1lZjJfMTAxMmgpCgphbGxfc2FtcGxlcyA9IHJiaW5kKHR3aV8yNGgsIGJpbl82OGgsIGN0Y2ZfNjhoLCBtZWYyXzY4aCwgYmluXzEwMTJoLCBtZWYyXzEwMTJoKQphbGxfc2FtcGxlcyRjb3JyZWN0X3ByZWRpY3QgPSBmYWN0b3IoaWZlbHNlKGFsbF9zYW1wbGVzJEFJPjAuNSAmIGFsbF9zYW1wbGVzJEJhc2VuamlfQUk+MC41LCAiY29ycmVjdCIsIGlmZWxzZShhbGxfc2FtcGxlcyRBSTwwLjUgJiBhbGxfc2FtcGxlcyRCYXNlbmppX0FJPDAuNSwgImNvcnJlY3QiLCAiaW5jb3JyZWN0IikpLCBsZXZlbHM9YygiaW5jb3JyZWN0IiwgImNvcnJlY3QiKSkKCmFsbF9zYW1wbGVzX2Jlc3RfYmFzZW5qaV9pbl9wZWFrID0gcmJpbmQodHdpXzI0aF9iZXN0X2Jhc2VuamlfaW5fcGVhaywgYmluXzY4aF9iZXN0X2Jhc2VuamlfaW5fcGVhaywgY3RjZl82OGhfYmVzdF9iYXNlbmppX2luX3BlYWssIG1lZjJfNjhoX2Jlc3RfYmFzZW5qaV9pbl9wZWFrLCBiaW5fMTAxMmhfYmVzdF9iYXNlbmppX2luX3BlYWssIG1lZjJfMTAxMmhfYmVzdF9iYXNlbmppX2luX3BlYWspCmFsbF9zYW1wbGVzX2Jlc3RfYmFzZW5qaV9pbl9wZWFrJGNvcnJlY3RfcHJlZGljdCA9IGZhY3RvcihpZmVsc2UoYWxsX3NhbXBsZXNfYmVzdF9iYXNlbmppX2luX3BlYWskQUk+MC41ICYgYWxsX3NhbXBsZXNfYmVzdF9iYXNlbmppX2luX3BlYWskQmFzZW5qaV9BST4wLjUsICJjb3JyZWN0IiwgaWZlbHNlKGFsbF9zYW1wbGVzX2Jlc3RfYmFzZW5qaV9pbl9wZWFrJEFJPDAuNSAmIGFsbF9zYW1wbGVzX2Jlc3RfYmFzZW5qaV9pbl9wZWFrJEJhc2VuamlfQUk8MC41LCAiY29ycmVjdCIsICJpbmNvcnJlY3QiKSksIGxldmVscz1jKCJpbmNvcnJlY3QiLCAiY29ycmVjdCIpKQoKYWxsX3NhbXBsZXNfYmVzdF9iYXNlbmppX2luX3BlYWtfc3ViID0gc3Vic2V0KGFsbF9zYW1wbGVzX2Jlc3RfYmFzZW5qaV9pbl9wZWFrLCBzaWduaWZpY2FudD09VFJVRSkKCgphbGxfc2FtcGxlc19iZXN0X2Jhc2VuamlfaW5fcGVhayRiZXN0X3ZhcmlhbnQgPSAxCmFsbF9zYW1wbGVzXzJuZF9iZXN0X2Jhc2VuamlfaW5fcGVhayA9IHRha2VfbmV4dF9iZXN0X0Jhc2VuamlfaW5fcGVhayhhbGxfc2FtcGxlcywgYWxsX3NhbXBsZXNfYmVzdF9iYXNlbmppX2luX3BlYWspCmFsbF9zYW1wbGVzXzJuZF9iZXN0X2Jhc2VuamlfaW5fcGVhayRiZXN0X3ZhcmlhbnQgPSAyCmFsbF9zYW1wbGVzXzNuZF9iZXN0X2Jhc2VuamlfaW5fcGVhayA9IHRha2VfbmV4dF9iZXN0X0Jhc2VuamlfaW5fcGVhayhhbGxfc2FtcGxlcywgcmJpbmQoYWxsX3NhbXBsZXNfYmVzdF9iYXNlbmppX2luX3BlYWssIGFsbF9zYW1wbGVzXzJuZF9iZXN0X2Jhc2VuamlfaW5fcGVhaykpCmFsbF9zYW1wbGVzXzNuZF9iZXN0X2Jhc2VuamlfaW5fcGVhayRiZXN0X3ZhcmlhbnQgPSAzCmFsbF9zYW1wbGVzXzRuZF9iZXN0X2Jhc2VuamlfaW5fcGVhayA9IHRha2VfbmV4dF9iZXN0X0Jhc2VuamlfaW5fcGVhayhhbGxfc2FtcGxlcywgcmJpbmQoYWxsX3NhbXBsZXNfYmVzdF9iYXNlbmppX2luX3BlYWssIGFsbF9zYW1wbGVzXzJuZF9iZXN0X2Jhc2VuamlfaW5fcGVhaywgYWxsX3NhbXBsZXNfM25kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrKSkKYWxsX3NhbXBsZXNfNG5kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrJGJlc3RfdmFyaWFudCA9IDQKYWxsX3NhbXBsZXNfNW5kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrID0gdGFrZV9uZXh0X2Jlc3RfQmFzZW5qaV9pbl9wZWFrKGFsbF9zYW1wbGVzLCByYmluZChhbGxfc2FtcGxlc19iZXN0X2Jhc2VuamlfaW5fcGVhaywgYWxsX3NhbXBsZXNfMm5kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrLCBhbGxfc2FtcGxlc18zbmRfYmVzdF9iYXNlbmppX2luX3BlYWssIGFsbF9zYW1wbGVzXzRuZF9iZXN0X2Jhc2VuamlfaW5fcGVhaykpCmFsbF9zYW1wbGVzXzVuZF9iZXN0X2Jhc2VuamlfaW5fcGVhayRiZXN0X3ZhcmlhbnQgPSA1CgphbGxfc2FtcGxlc19zdWIgPSBzdWJzZXQoYWxsX3NhbXBsZXMsIHNpZ25pZmljYW50PT1UUlVFKQphbGxfc2FtcGxlc19iZXN0X2Jhc2VuamlfaW5fcGVha19zdWIgPSBzdWJzZXQoYWxsX3NhbXBsZXNfYmVzdF9iYXNlbmppX2luX3BlYWssIHNpZ25pZmljYW50PT1UUlVFKQphbGxfc2FtcGxlc18ybmRfYmVzdF9iYXNlbmppX2luX3BlYWtfc3ViID0gc3Vic2V0KGFsbF9zYW1wbGVzXzJuZF9iZXN0X2Jhc2VuamlfaW5fcGVhaywgc2lnbmlmaWNhbnQ9PVRSVUUpCmFsbF9zYW1wbGVzXzNuZF9iZXN0X2Jhc2VuamlfaW5fcGVha19zdWIgPSBzdWJzZXQoYWxsX3NhbXBsZXNfM25kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrLCBzaWduaWZpY2FudD09VFJVRSkKYWxsX3NhbXBsZXNfNG5kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrX3N1YiA9IHN1YnNldChhbGxfc2FtcGxlc180bmRfYmVzdF9iYXNlbmppX2luX3BlYWssIHNpZ25pZmljYW50PT1UUlVFKQphbGxfc2FtcGxlc181bmRfYmVzdF9iYXNlbmppX2luX3BlYWtfc3ViID0gc3Vic2V0KGFsbF9zYW1wbGVzXzVuZF9iZXN0X2Jhc2VuamlfaW5fcGVhaywgc2lnbmlmaWNhbnQ9PVRSVUUpCgoKc3VjY2Vzc19wcm9wb3J0aW9uID0gYXMuZGF0YS5mcmFtZSh0KG1hdHJpeChjKCIxc3QiLCBucm93KHN1YnNldChhbGxfc2FtcGxlc19iZXN0X2Jhc2VuamlfaW5fcGVha19zdWIsIChCYXNlbmppX0FJID4gMC41ICYgQUkgPiAwLjUpIHwgKEJhc2VuamlfQUkgPCAwLjUgJiBBSSA8IDAuNSkpKSAvIG5yb3coYWxsX3NhbXBsZXNfYmVzdF9iYXNlbmppX2luX3BlYWtfc3ViKSwgCiAgIjJuZCIsIG5yb3coc3Vic2V0KGFsbF9zYW1wbGVzXzJuZF9iZXN0X2Jhc2VuamlfaW5fcGVha19zdWIsIChCYXNlbmppX0FJID4gMC41ICYgQUkgPiAwLjUpIHwgKEJhc2VuamlfQUkgPCAwLjUgJiBBSSA8IDAuNSkpKSAvIG5yb3coYWxsX3NhbXBsZXNfMm5kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrX3N1YiksIAogICIzcmQiLCBucm93KHN1YnNldChhbGxfc2FtcGxlc18zbmRfYmVzdF9iYXNlbmppX2luX3BlYWtfc3ViLCAoQmFzZW5qaV9BSSA+IDAuNSAmIEFJID4gMC41KSB8IChCYXNlbmppX0FJIDwgMC41ICYgQUkgPCAwLjUpKSkgLyBucm93KGFsbF9zYW1wbGVzXzNuZF9iZXN0X2Jhc2VuamlfaW5fcGVha19zdWIpLCAKICAiNHRoIiwgbnJvdyhzdWJzZXQoYWxsX3NhbXBsZXNfNG5kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrX3N1YiwgKEJhc2VuamlfQUkgPiAwLjUgJiBBSSA+IDAuNSkgfCAoQmFzZW5qaV9BSSA8IDAuNSAmIEFJIDwgMC41KSkpIC8gbnJvdyhhbGxfc2FtcGxlc180bmRfYmVzdF9iYXNlbmppX2luX3BlYWtfc3ViKSwgCiAgIjV0aCIsIG5yb3coc3Vic2V0KGFsbF9zYW1wbGVzXzVuZF9iZXN0X2Jhc2VuamlfaW5fcGVha19zdWIsIChCYXNlbmppX0FJID4gMC41ICYgQUkgPiAwLjUpIHwgKEJhc2VuamlfQUkgPCAwLjUgJiBBSSA8IDAuNSkpKSAvIG5yb3coYWxsX3NhbXBsZXNfNW5kX2Jlc3RfYmFzZW5qaV9pbl9wZWFrX3N1YiksIAogICJhbGwiLCBucm93KHN1YnNldChhbGxfc2FtcGxlc19zdWIsIChCYXNlbmppX0FJID4gMC41ICYgQUkgPiAwLjUpIHwgKEJhc2VuamlfQUkgPCAwLjUgJiBBSSA8IDAuNSkpKSAvIG5yb3coYWxsX3NhbXBsZXNfc3ViKSksIG5yb3c9MikpKQoKY29sbmFtZXMoc3VjY2Vzc19wcm9wb3J0aW9uKSA9IGMoImJlc3RfQmFzZW5qaV9BSSIsICJwcm9wb3J0aW9uX2NvcnJlY3QiKQpzdWNjZXNzX3Byb3BvcnRpb24kcHJvcG9ydGlvbl9jb3JyZWN0ID0gYXMubnVtZXJpYyhzdWNjZXNzX3Byb3BvcnRpb24kcHJvcG9ydGlvbl9jb3JyZWN0KQoKYWxsX3NhbXBsZXNfYmVzdF9iYXNlbmppX2luX3BlYWtfc3ViID0gc3Vic2V0KGFsbF9zYW1wbGVzX2Jlc3RfYmFzZW5qaV9pbl9wZWFrLCBzaWduaWZpY2FudD09VFJVRSAmIChCYXNlbmppX2Fic19BSSA+IDAuMSkpCgpwID0gcGxvdF9jb3VudHNfYmFycGxvdChhbGxfc2FtcGxlc19iZXN0X2Jhc2VuamlfaW5fcGVha19zdWIsICJUU1MiLCAiY29ycmVjdF9wcmVkaWN0IikKcAoKb3V0ZiA9IGZpbGUucGF0aChvdXRkaXJfZmlnX3N1cHBsLCBwYXN0ZTAoIkZpZ1M3Rl9iYXNlbmppX3ByZWRpY3Rpb25zX2J5X1RTUy5wZGYiKSkKZ2dzYXZlKG91dGYsIHAsIHdpZHRoID0gMywgaGVpZ2h0ID0gMykKYGBgCgoKYGBge3IgfQpwID0gcGxvdF9jb3VudHNfYmFycGxvdChhbGxfc2FtcGxlc19iZXN0X2Jhc2VuamlfaW5fcGVha19zdWIsICJvdmVybGFwc19wZWFrIiwgImNvcnJlY3RfcHJlZGljdCIpCnAKCm91dGYgPSBmaWxlLnBhdGgob3V0ZGlyX2ZpZ19zdXBwbCwgcGFzdGUwKCJGaWdTN0ZfYmFzZW5qaV9wcmVkaWN0aW9uc19ieV9wZWFrX292ZXJsYXAucGRmIikpCmdnc2F2ZShvdXRmLCBwLCB3aWR0aCA9IDMsIGhlaWdodCA9IDMpCmBgYAoKCmBgYHtyIH0KcCA9IHBsb3RfY291bnRzX2JhcnBsb3QoYWxsX3NhbXBsZXNfYmVzdF9iYXNlbmppX2luX3BlYWtfc3ViLCAib3ZlcmxhcHNfbW90aWYiLCAiY29ycmVjdF9wcmVkaWN0IikKcAoKb3V0ZiA9IGZpbGUucGF0aChvdXRkaXJfZmlnX3N1cHBsLCBwYXN0ZTAoIkZpZ1M3Rl9iYXNlbmppX3ByZWRpY3Rpb25zX2J5X21vdGlmX292ZXJsYXAucGRmIikpCmdnc2F2ZShvdXRmLCBwLCB3aWR0aCA9IDMsIGhlaWdodCA9IDMpCmBgYAoKCgoKCgoKCgoKCg==