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 S4A

# get variants distance to motifs (excluding peaks without motifs)
res_df = lapply(ab_tp_list, function(ab_tp) get_variant_distance2TFmotif(ab_tp, cht, fimo, same_peak = T) %>% 
                  mutate(condition = ab_tp)) %>% bind_rows()

dist_breaks = c(-1, 0, 20, 40, 60, 80, 100, 3000)
dist_labels = c("in motif", "1-20 bp", "21-40 bp", "41-60 bp", "61-80 bp", "81-100 bp", ">100 bp")

res_full = data.frame(matrix(ncol = 6, nrow = 0))
names(res_full) = c("dist_bin", "n", "share", "sd", "type", "condition")
background_sum_all_cond = data.frame(matrix(ncol = 7, nrow = 0))
names(background_sum_all_cond) = c("dist_bin", "n", "share", "share_full",  "type", "condition", "i")

for(ab_tp in ab_tp_list) {
  
  # all variants
  df_sel = res_df %>% dplyr::filter(condition == ab_tp)
  N_var = length(unique(df_sel$snp_id)) # number of variants in peaks with motifs
  N_peak = length(unique(df_sel$peak_id)) # number of peaks with motifs
  
  # significant variants
  df_sign = df_sel %>% filter(signif_strongAI)
  N_var_sign = length(unique(df_sign$snp_id)) # number of significant variants in peaks with motifs
  N_peak_sign = length(unique(df_sign$peak_id)) # number of AI peaks with motifs

  sign_sum = df_sign %>% 
    dplyr::group_by(peak_id) %>% 
    dplyr::mutate(min_dist = min(dist2motif)) %>%
    dplyr::filter(dist2motif == min_dist) %>%
    dplyr::select(peak_id, dist2motif) %>% unique() %>% ungroup() %>%
    dplyr::mutate(N_tot = n(), dist_bin = cut(dist2motif, breaks = dist_breaks, labels = dist_labels)) %>%
    dplyr::group_by(dist_bin) %>%
    dplyr::summarize(n = n(), share = n / mean(N_tot), sd = sd(n), type = "real", condition = ab_tp)
  
  
  df_non_sign = df_sel %>% dplyr::group_by(peak_id) %>% dplyr::mutate(AI_peak = any(signif_strongAI)) %>% dplyr::filter(!AI_peak) %>% ungroup()
  
  background_sum_all = lapply(1:10000, function(i) {
    
    #print(i)
    
    # 1. select same number of peaks as in AI peaks
    peak_ids = sample(unique(df_non_sign$peak_id), N_peak_sign)
    df_bg = df_non_sign %>% dplyr::filter(peak_id %in% peak_ids)
    
    # 2. select same number of variants as for AI peaks
    variant_ids = sample(unique(df_bg$snp_id), N_var_sign)
    df_bg %<>% filter(snp_id %in% variant_ids)
    
    N_peak_bg = length(unique(df_bg$peak_id)) 
    
    bg_sum = df_bg %>% 
      dplyr::group_by(peak_id) %>% 
      dplyr::mutate(min_dist = min(dist2motif)) %>%
      dplyr::filter(dist2motif == min_dist) %>%
      dplyr::select(peak_id, dist2motif) %>% unique() %>% ungroup() %>%
      dplyr::mutate(N_tot = n(), dist_bin = cut(dist2motif, breaks = dist_breaks, labels = dist_labels)) %>%
      dplyr::group_by(dist_bin) %>%
      dplyr::summarize(n = n(), share = n / mean(N_tot), share_full = n / N_peak_bg) %>%
      dplyr::mutate(condition = ab_tp, i = i)
    
    
    bg_sum$type = "background"
    bg_sum
    
  }) %>% bind_rows()
  
  background_sum_all_cond = rbind(background_sum_all_cond, background_sum_all)
  
  background_sum = background_sum_all %>% 
    dplyr::group_by(dist_bin) %>% 
    dplyr::summarize(n = mean(n), 
                     share = mean(share), 
                     sd = sd(share_full),
                     type = "background", 
                     condition = ab_tp)
  
  
  res = rbind.data.frame(sign_sum, background_sum)
  
  res_full = rbind.data.frame(res_full, res)

}


res_full$dist_bin = factor(res_full$dist_bin, levels = rev(dist_labels))
res_full$tf_labels = ab_tp_labels[res_full$condition]  
res_full$tf_labels = factor(res_full$tf_labels, levels = ab_tp_labels)

shares_in_motif = res_full %>% 
  arrange(tf_labels) %>% 
  filter(dist_bin == "in motif", type == "real") %>% 
  select(share) %>% unlist() %>% unique() %>% round(2)


res_full$dist_bin = factor(res_full$dist_bin, levels = dist_labels)
res_full$type = factor(res_full$type, levels = unique(res_full$type))

p = ggplot(res_full, aes(x = dist_bin, y = share, color = type, group = type)) +
  facet_wrap(~tf_labels, ncol = 3) +
  geom_ribbon(data=subset(res_full, type=="background"), aes(x=dist_bin, y = share, ymin = share - sd * 2, ymax = share + sd * 2, group = type), fill = "grey70", colour=NA, alpha = .4) +
  geom_point(size = 2) + 
  geom_line(linewidth = 1) +
  scale_color_manual(values = c("grey", "darkblue"), name = "", labels = c("AI peaks with motifs", "background")) +
  theme_bw() +
  ylab("Share of peaks") +
  xlab("Distance from TF motif") +
  theme(axis.text.y = element_text(size=14), axis.text.x = element_text(size=14, angle = 45, hjust = 1),
        axis.title.x = element_text(size=16), axis.title.y = element_text(size=16),
        legend.text=element_text(size=16), legend.title=element_text(size=16))


p

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

Empirical p-values for the test: real share is larger than background share


In motif

Condition p-value
Twi 2-4h 9.999^{-5}
CTCF 6-8h 9.999^{-5}
Mef2 6-8h 1.0001^{-4}
Mef2 10-12h 9.999^{-5}
Bin 6-8h 9.999^{-5}
Bin 10-12h 1.0001^{-4}


1-20 bp

Condition p-value
Twi 2-4h 0.0379
CTCF 6-8h 0.38196
Mef2 6-8h 0.39486
Mef2 10-12h 0.10009
Bin 6-8h 0.16348
Bin 10-12h 0.79562


21-40 bp

Condition p-value
Twi 2-4h 0.73813
CTCF 6-8h 0.9993
Mef2 6-8h 1
Mef2 10-12h 0.84762
Bin 6-8h 0.71863
Bin 10-12h 0.90831


41-60 bp

Condition p-value
Twi 2-4h 0.66383
CTCF 6-8h 0.996
Mef2 6-8h 0.73593
Mef2 10-12h 0.9998
Bin 6-8h 0.94411
Bin 10-12h 0.43036


61-80 bp

Condition p-value
Twi 2-4h 0.9999
CTCF 6-8h 1
Mef2 6-8h 0.92471
Mef2 10-12h 0.9726
Bin 6-8h 0.94691
Bin 10-12h 0.9971


81-100 bp

Condition p-value
Twi 2-4h 0.9994
CTCF 6-8h 0.9996
Mef2 6-8h 0.9989
Mef2 10-12h 0.9999
Bin 6-8h 0.9955
Bin 10-12h 0.72823


>100 bp

Condition p-value
Twi 2-4h 0.94161
CTCF 6-8h 0.97
Mef2 6-8h 0.76452
Mef2 10-12h 0.45485
Bin 6-8h 0.9952
Bin 10-12h 0.94581

3 Figure S4B - Fisher’s tests: enrichments of significant variants in motiifs in / outside peaks

out_df = data.frame(matrix(ncol = 10, nrow = 0))
names(out_df) = c("condition", "motif", "N_sign", "N_ns", "N_sign_motif", "N_ns_motif", "N_motif", "group", "odd_ratio", "pvalue")
i = 1

for(ab_tp in ab_tp_list) {
  
  tf = TFs[ab_tp]
  print(ab_tp)
  cht_sel = cht %>% filter(condition == ab_tp)
  
  # all signif variants - all, in and outside peaks
  N1 = cht_sel %>% filter(signif_strongAI) %>% select(snp_id) %>% unique() %>% tally() %>% unlist()
  N1_a = cht_sel %>% filter(signif_strongAI & dist2summit < 250) %>% select(snp_id) %>% unique() %>% tally() %>% unlist()
  N1_b = cht_sel %>% filter(signif_strongAI & dist2summit >= 250) %>% select(snp_id) %>% unique() %>% tally() %>% unlist()
  
  # all n.s. variants - in and outside peaks
  N2 = cht_sel %>% filter(!signif_strongAI) %>% select(snp_id) %>% unique() %>% tally() %>% unlist()
  N2_a = cht_sel %>% filter(!signif_strongAI & dist2summit < 250) %>% select(snp_id) %>% unique() %>% tally() %>% unlist()
  N2_b = cht_sel %>% filter(!signif_strongAI & dist2summit >= 250) %>% select(snp_id) %>% unique() %>% tally() %>% unlist()
  
  
  # variants in the motifs of selected TFs
  fimo_selected = parse_motifs_in_two_alleles(ab_tp, cht_sel, radius = 15, path2_base1 = "/all_variants_alleles/FIMO/",
                                              path2_base2 = "combined_motifs/fimo.tsv", 
                                              peak_radius = 250, subset_motif = F, subset_cht = T) 
  
  
  # 1. Enrichment in cognate motifs
  print("1. Enrichment in cognate motifs")
  #fimo_sel = fimo_selected %>% filter(motif_alt_id == tf & snp_id %in% cht_sel$snp_id)
  fimo_sel = fimo_selected %>% filter(motif_alt_id == tf)  # equivalent
  cognate_motif_ids = unique(fimo_sel$snp_id)
  
  # number of significant variants in motifs - all, in and outside peaks
  N3 = fimo_sel %>% filter(signif_strongAI) %>% select(snp_id) %>% unique() %>% tally() %>% unlist()
  N3_a = fimo_sel %>% filter(signif_strongAI & in_peak) %>% select(snp_id) %>% unique() %>% tally() %>% unlist()
  N3_b = fimo_sel %>% filter(signif_strongAI & !in_peak) %>% select(snp_id) %>% unique() %>% tally() %>% unlist()
  
  # number of n.s. variants in motifs - all, in and outside peaks
  N4 = fimo_sel %>% filter(!signif_strongAI) %>% select(snp_id) %>% unique() %>% tally() %>% unlist()
  N4_a = fimo_sel %>% filter(!signif_strongAI & in_peak) %>% select(snp_id) %>% unique() %>% tally() %>% unlist()
  N4_b = fimo_sel %>% filter(!signif_strongAI & !in_peak) %>% select(snp_id) %>% unique() %>% tally() %>% unlist()
  
  # mat = matrix(c(N3, N4, N1, N2), nrow = 2)
  # ft = fisher.test(mat)
  # out_df[i, ] = c(ab_tp, tf, N1, N2, N3, N4, N3 + N4, "all variants", ft$estimate, ft$p.value)
  # i = i + 1
  # print("1a. All variants")
  # print(ft)
  
  mat = matrix(c(N3_a, N4_a, N1_a, N2_a), nrow = 2)
  ft = fisher.test(mat)
  out_df[i, ] = c(ab_tp, tf, N1_a, N2_a, N3_a, N4_a, N3_a + N4_a, "in peaks", ft$estimate, ft$p.value)
  i = i + 1
  print("1b. Variants in peaks")
  print(ft)
  
  mat = matrix(c(N3_b, N4_b, N1_b, N2_b), nrow = 2)
  ft = fisher.test(mat)
  out_df[i, ] = c(ab_tp, tf, N1_b, N2_b, N3_b, N4_b, N3_b + N4_b, "outside peaks", ft$estimate, ft$p.value)
  i = i + 1
  print("1c. Variants outside peaks")
  print(ft)

}
   [1] "twi/24"
   [1] "1. Enrichment in cognate motifs"
   [1] "1b. Variants in peaks"
   
    Fisher's Exact Test for Count Data
   
   data:  mat
   p-value = 2.4e-11
   alternative hypothesis: true odds ratio is not equal to 1
   95 percent confidence interval:
    1.7026 2.5660
   sample estimates:
   odds ratio 
       2.0982 
   
   [1] "1c. Variants outside peaks"
   
    Fisher's Exact Test for Count Data
   
   data:  mat
   p-value = 0.0076
   alternative hypothesis: true odds ratio is not equal to 1
   95 percent confidence interval:
    1.0463 1.3476
   sample estimates:
   odds ratio 
       1.1895 
   
   [1] "ctcf/68"
   [1] "1. Enrichment in cognate motifs"
   [1] "1b. Variants in peaks"
   
    Fisher's Exact Test for Count Data
   
   data:  mat
   p-value <2e-16
   alternative hypothesis: true odds ratio is not equal to 1
   95 percent confidence interval:
    2.3256 3.3831
   sample estimates:
   odds ratio 
       2.8113 
   
   [1] "1c. Variants outside peaks"
   
    Fisher's Exact Test for Count Data
   
   data:  mat
   p-value = 0.92
   alternative hypothesis: true odds ratio is not equal to 1
   95 percent confidence interval:
    0.87304 1.12213
   sample estimates:
   odds ratio 
       0.9914 
   
   [1] "mef2/68"
   [1] "1. Enrichment in cognate motifs"
   [1] "1b. Variants in peaks"
   
    Fisher's Exact Test for Count Data
   
   data:  mat
   p-value <2e-16
   alternative hypothesis: true odds ratio is not equal to 1
   95 percent confidence interval:
    2.2275 3.3489
   sample estimates:
   odds ratio 
       2.7412 
   
   [1] "1c. Variants outside peaks"
   
    Fisher's Exact Test for Count Data
   
   data:  mat
   p-value = 0.78
   alternative hypothesis: true odds ratio is not equal to 1
   95 percent confidence interval:
    0.86807 1.19931
   sample estimates:
   odds ratio 
       1.0234 
   
   [1] "mef2/1012"
   [1] "1. Enrichment in cognate motifs"
   [1] "1b. Variants in peaks"
   
    Fisher's Exact Test for Count Data
   
   data:  mat
   p-value <2e-16
   alternative hypothesis: true odds ratio is not equal to 1
   95 percent confidence interval:
    2.2876 3.3341
   sample estimates:
   odds ratio 
       2.7702 
   
   [1] "1c. Variants outside peaks"
   
    Fisher's Exact Test for Count Data
   
   data:  mat
   p-value = 0.18
   alternative hypothesis: true odds ratio is not equal to 1
   95 percent confidence interval:
    0.95347 1.25785
   sample estimates:
   odds ratio 
       1.0975 
   
   [1] "bin/68"
   [1] "1. Enrichment in cognate motifs"
   [1] "1b. Variants in peaks"
   
    Fisher's Exact Test for Count Data
   
   data:  mat
   p-value = 4.7e-12
   alternative hypothesis: true odds ratio is not equal to 1
   95 percent confidence interval:
    2.1427 3.6830
   sample estimates:
   odds ratio 
       2.8278 
   
   [1] "1c. Variants outside peaks"
   
    Fisher's Exact Test for Count Data
   
   data:  mat
   p-value = 0.95
   alternative hypothesis: true odds ratio is not equal to 1
   95 percent confidence interval:
    0.75705 1.24591
   sample estimates:
   odds ratio 
      0.97841 
   
   [1] "bin/1012"
   [1] "1. Enrichment in cognate motifs"
   [1] "1b. Variants in peaks"
   
    Fisher's Exact Test for Count Data
   
   data:  mat
   p-value = 2.1e-13
   alternative hypothesis: true odds ratio is not equal to 1
   95 percent confidence interval:
    2.407 4.254
   sample estimates:
   odds ratio 
       3.2233 
   
   [1] "1c. Variants outside peaks"
   
    Fisher's Exact Test for Count Data
   
   data:  mat
   p-value = 0.044
   alternative hypothesis: true odds ratio is not equal to 1
   95 percent confidence interval:
    0.99598 1.66680
   sample estimates:
   odds ratio 
       1.2986
out_df$label = rep(ab_tp_labels, each = 2)
out_df$label = factor(out_df$label, levels = ab_tp_labels)
out_df$pvalue = as.numeric(out_df$pvalue)
out_df$odd_ratio = as.numeric(out_df$odd_ratio)



p = ggplot(out_df, aes(x = label, y = odd_ratio)) +
  facet_wrap(~group) +
  geom_hline(yintercept = 1, color = "darkred") +
  geom_bar(aes(fill = -log10(pvalue)), color = "darkblue", stat = "identity", position = "dodge", width = 0.5) +
  #scale_fill_manual(name = "", values = c("darkblue", "darkgrey"), labels = c("AI peaks", "non-AI peaks")) +
  #geom_text(aes(label = round(r1, 2), x = label, y = odds_ratio + 0.07), data = df, size = 6) +
  ylab("Enrichment in cognate TF motifs \nFisher's Test Odds Ratio") +
  theme_bw() +
  theme(axis.text.x = element_text(size = 14, angle = 45, hjust = 1, colour = TFcols),
        axis.text.y = element_text(size = 12), 
        axis.title.x = element_blank(),
        axis.title.y = element_text(size = 16),
        legend.text = element_text(size=14),
        legend.title = element_text(size=14))
   Warning: Vectorized input to `element_text()` is not officially supported.
   ℹ Results may be unexpected or may change in future versions of ggplot2.
p

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

4 Figure S4C - Motif prediction of AI

# Correlation between AI and delta_score

score_thres = 1
df_shared = fimo_alleles %>% filter(in_peak & !is.na(score.ref) & !is.na(score.alt)) %>%
  mutate(delta_score = as.numeric(score.ref) - as.numeric(score.alt),
         type = ifelse((AI > 0.5 & delta_score > 0) | (AI < 0.5 & delta_score < 0), "concordant", "discordant"))

df_shared %>% 
  group_by(condition, is_indel) %>% 
  summarize(min(abs(delta_score)), max(dist2summit), cor(delta_score, AI), share_concordant = sum(type == "concordant") / n(), n())
   `summarise()` has grouped output by 'condition'. You can override using the
   `.groups` argument.
df_sum = df_shared %>% filter(abs(delta_score) > score_thres  & dist2summit < 250) %>% 
  summarize(min(abs(delta_score)), max(dist2summit), cor = cor(delta_score, AI), share_concordant = sum(type == "concordant") / n(), n())

cor = round(df_sum$cor, 2)
n_conc = round(df_sum$share_concordant, 2) * 100
n_disc = (1 - round(df_sum$share_concordant, 2)) * 100


p = ggplot(df_shared %>% filter(abs(delta_score) > score_thres ), aes(x = delta_score, y = AI, color = type)) + 
  geom_point(size = 1, color = cbPalette[2]) + 
  geom_smooth(method = "lm", se = F, color = "darkblue", size = 0.5) +
  geom_vline(xintercept = -score_thres, color = "grey", size = 0.7) +
  geom_vline(xintercept = score_thres, color = "grey", size = 0.7) +
  geom_hline(yintercept = 0.5, color = "grey", size = 0.7) +
  #geom_hline(yintercept = 0.4, color = "grey", size = 0.7) +
  theme_bw() +
  annotate(geom = "text", x = -3.5, y = 0.95, label = paste("R=", cor)) +
  annotate(geom = "text", x = -3.5, y = 0.88, label = paste("% concordant: ", n_conc), size = 4) +
  xlab("Motif score change (REF-ALT)") +
  ylab("Allele Imbalamce") +
  #scale_color_manual(values = c(cbPalette[2], "darkgrey"), labels = c(paste0("concordant, ", n_conc, "%"), paste0("discordant, ", n_disc, "%")), name = "Variant type") +
  theme(axis.text=element_text(size=12),
        axis.title=element_text(size=14),
        legend.text = element_text(size=12),
        legend.title = element_text(size=12))
   Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
   ℹ Please use `linewidth` instead.
   This warning is displayed once every 8 hours.
   Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
   generated.
p
   `geom_smooth()` using formula = 'y ~ x'

outf = file.path(outdir_fig_suppl, paste0("FigS4C_motifs_AI_prediction.pdf"))
ggsave(outf, p, width = 4, height = 4)
   `geom_smooth()` using formula = 'y ~ x'

5 Figure S4D - ProBound scores on AI and non-AI variants

ProBound_CTCF = read.table("/g/furlong/project/68_F1_cisreg_ichip/analysis/ProBound/ProBound_CTCF_REF_sequence_15bp_around_variants.txt", header=TRUE)
ProBound_CTCF$TF = "CTCF"
ProBound_Bin = read.table("/g/furlong/project/68_F1_cisreg_ichip/analysis/ProBound/ProBound_Bin_REF_sequence_15bp_around_variants.txt", header=TRUE)
ProBound_Bin$TF = "Bin"
ProBound_Mef2 = read.table("/g/furlong/project/68_F1_cisreg_ichip/analysis/ProBound/ProBound_Mef2_REF_sequence_15bp_around_variants.txt", header=TRUE)
ProBound_Mef2$TF = "Mef2"
ProBound_Twi = read.table("/g/furlong/project/68_F1_cisreg_ichip/analysis/ProBound/ProBound_Twi_REF_sequence_15bp_around_variants.txt", header=TRUE)
ProBound_Twi$TF = "Twi"

ProBound_results_REF = rbind(ProBound_CTCF, ProBound_Bin, ProBound_Mef2, ProBound_Twi)
colnames(ProBound_results_REF) = c("variant_chr", "variant_pos", "REF", "ALT", "ProBound_bed_REF", "ProBound_seq_REF", "ProBound_score_REF", "TF")
ProBound_results_REF = ProBound_results_REF %>%
        group_by(TF) %>%
        mutate(ProBound_score_scaled_REF = ProBound_score_REF / max(ProBound_score_REF))


ProBound_ALT_CTCF = read.table("/g/furlong/project/68_F1_cisreg_ichip/analysis/ProBound/ProBound_CTCF_ALT_sequence_15bp_around_variants.txt", header=TRUE)
ProBound_ALT_CTCF$TF = "CTCF"
ProBound_ALT_Bin = read.table("/g/furlong/project/68_F1_cisreg_ichip/analysis/ProBound/ProBound_Bin_ALT_sequence_15bp_around_variants.txt", header=TRUE)
ProBound_ALT_Bin$TF = "Bin"
ProBound_ALT_Mef2 = read.table("/g/furlong/project/68_F1_cisreg_ichip/analysis/ProBound/ProBound_Mef2_ALT_sequence_15bp_around_variants.txt", header=TRUE)
ProBound_ALT_Mef2$TF = "Mef2"
ProBound_ALT_Twi = read.table("/g/furlong/project/68_F1_cisreg_ichip/analysis/ProBound/ProBound_Twi_ALT_sequence_15bp_around_variants.txt", header=TRUE)
ProBound_ALT_Twi$TF = "Twi"

ProBound_results_ALT = rbind(ProBound_ALT_CTCF, ProBound_ALT_Bin, ProBound_ALT_Mef2, ProBound_ALT_Twi)
colnames(ProBound_results_ALT) = c("variant_chr", "variant_pos", "REF", "ALT", "ProBound_bed_ALT", "ProBound_seq_ALT", "ProBound_score_ALT", "TF")
ProBound_results_ALT = ProBound_results_ALT %>%
        group_by(TF) %>%
        mutate(ProBound_score_scaled_ALT = ProBound_score_ALT / max(ProBound_score_ALT))


ProBound_results = merge(ProBound_results_REF, ProBound_results_ALT, by = c("variant_chr", "variant_pos", "REF", "ALT", "TF"), all.x=TRUE)
ProBound_results$variant_ID = paste(ProBound_results$variant_chr, ProBound_results$variant_pos, ProBound_results$TF, sep="_")
ProBound_results$ProBound_score_max = pmax(ProBound_results$ProBound_score_ALT, ProBound_results$ProBound_score_REF)


cht$variant_ID = paste(cht$snp_id, cht$ab, sep="_")
cht_ProBound = merge(cht, ProBound_results, by="variant_ID")
cht_ProBound$signif_strongAI = factor(cht_ProBound$signif_strongAI, levels=c(TRUE, FALSE))


p = ggplot(cht_ProBound, aes(x=signif_strongAI, y=ProBound_score_max, fill=signif_strongAI)) + 
      facet_wrap(~condition) +
      geom_violin(fill = "darkblue", alpha = 0.3) +
      geom_boxplot(width = 0.4, outlier.size = 0.1, fill = "darkblue", alpha = 0.5) +
      scale_y_log10() + 
      stat_compare_means(method = "wilcox") +
      xlab("Significant allelic imbalance") +
      ylab("-log(10) ProBound sscaled core") +
      theme_bw() +
      theme(axis.text.y = element_text(size=10), axis.text.x = element_text(size=10), 
        axis.title.x = element_text(size=10), axis.title.y = element_text(size=10),
        strip.text.x = element_text(size = 10), strip.text.y = element_text(size = 10),
        legend.position="none")
outf = file.path(outdir_fig_suppl, paste0("FigS4D_ProBound_max_scores_on_AI_variants.pdf"))
ggsave(outf, p, width = 6, height = 4)
   Warning: Removed 125432 rows containing non-finite values (`stat_ydensity()`).
   Warning: Removed 125432 rows containing non-finite values (`stat_boxplot()`).
   Warning: Removed 125432 rows containing non-finite values
   (`stat_compare_means()`).
LS0tCnRpdGxlOiAiRmlndXJlX1M0IgpvdXRwdXQ6CiAgIEJpb2NTdHlsZTo6aHRtbF9kb2N1bWVudDoKICAgICAgdG9jOiB0cnVlCiAgICAgIGRmX3ByaW50OiBwYWdlZAogICAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZQogICAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICAgIGhpZ2hsaWdodDogdGFuZ28KI2JpYmxpb2dyYXBoeToga25uX21sX2ludHJvLmJpYgplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCmBgYHtyIHN0eWxlLCBlY2hvPUZBTFNFLCByZXN1bHRzPSJhc2lzIn0KbGlicmFyeSgia25pdHIiKQpvcHRpb25zKGRpZ2l0cyA9IDIsIHdpZHRoID0gODApCm9wdGlvbnMoYml0bWFwVHlwZSA9ICdjYWlybycpCmdvbGRlbl9yYXRpbyA8LSAoMSArIHNxcnQoNSkpIC8gMgpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgdGlkeSA9IEZBTFNFLCBpbmNsdWRlID0gVFJVRSwgY2FjaGUgPSBGQUxTRSwKICAgICAgICAgICAgICAgZGV2PWMoJ3BuZycsICdwZGYnKSwgY29tbWVudCA9ICcgICcsIGRwaSA9IDMwMCkKCm9wdGlvbnMoc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQprbml0cjo6b3B0c19jaHVuayRzZXQoY2FjaGU9RkFMU0UpCm9wdGlvbnMoZGlnaXRzID0gNSkgICAgICAgICAKYGBgCgojIFNldHVwIGFuZCBkYXRhCgpgYGB7cn0Kc291cmNlKCIuLi91dGlscy91dGlscy5SIikKY29uZmlnID0gbG9hZF9jb25maWcoKQoKIyBsb2FkIENIVCByZXN1bHRzCmNodF9mdWxsID0gbGFwcGx5KGFiX3RwX2xpc3QsIGZ1bmN0aW9uKGFiX3RwKSBsb2FkX2NodF9yZXN1bHRzKGFiX3RwLCByZW1vdmVfY2hyID0gRikpICU+JSBiaW5kX3Jvd3MoKQpjaHQgPSBjaHRfZnVsbCAlPiUgZmlsdGVyKCFURVNULlNOUC5DSFJPTSAlaW4lIGMoImNoclgiLCAiY2hyWSIsICJjaHJNIikpCmNodF9zaWduID0gY2h0ICU+JSBmaWx0ZXIoc2lnbmlmX3N0cm9uZ0FJKSAKCiMgZ2VuZXMgYW5kIHByb21vdGVycwpnZW5lcyA9IGxvYWRfZ2VuZXMoKQpwcm9tb3RlcnMgPSByZXNpemUoZ2VuZXMsIHdpZHRoID0gMTAwMCwgZml4ID0gInN0YXJ0IikKCiMgY29tYmluZWQgbW90aWYgc2V0IChhbGwgVEZzLCBwZWFrcyArIGFsbGVsZXMpCmZpbW8gPSBnZXRfZnVsbF9tb3RpZl9zZXRzKGNodCwgYWJfdHBfbGlzdCkKIyBvbmx5IGFsbGVsZXMKZmltb19hbGxlbGVzICA9IGxhcHBseShhYl90cF9saXN0LCBmdW5jdGlvbihhYl90cCkgcGFyc2VfbW90aWZzX2luX3R3b19hbGxlbGVzKGFiX3RwLCBjaHQpKSAlPiUgYmluZF9yb3dzKCkgCgpgYGAKCgoKIyBGaWd1cmUgUzRBCgpgYGB7ciwgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9M30KCiMgZ2V0IHZhcmlhbnRzIGRpc3RhbmNlIHRvIG1vdGlmcyAoZXhjbHVkaW5nIHBlYWtzIHdpdGhvdXQgbW90aWZzKQpyZXNfZGYgPSBsYXBwbHkoYWJfdHBfbGlzdCwgZnVuY3Rpb24oYWJfdHApIGdldF92YXJpYW50X2Rpc3RhbmNlMlRGbW90aWYoYWJfdHAsIGNodCwgZmltbywgc2FtZV9wZWFrID0gVCkgJT4lIAogICAgICAgICAgICAgICAgICBtdXRhdGUoY29uZGl0aW9uID0gYWJfdHApKSAlPiUgYmluZF9yb3dzKCkKCmRpc3RfYnJlYWtzID0gYygtMSwgMCwgMjAsIDQwLCA2MCwgODAsIDEwMCwgMzAwMCkKZGlzdF9sYWJlbHMgPSBjKCJpbiBtb3RpZiIsICIxLTIwIGJwIiwgIjIxLTQwIGJwIiwgIjQxLTYwIGJwIiwgIjYxLTgwIGJwIiwgIjgxLTEwMCBicCIsICI+MTAwIGJwIikKCnJlc19mdWxsID0gZGF0YS5mcmFtZShtYXRyaXgobmNvbCA9IDYsIG5yb3cgPSAwKSkKbmFtZXMocmVzX2Z1bGwpID0gYygiZGlzdF9iaW4iLCAibiIsICJzaGFyZSIsICJzZCIsICJ0eXBlIiwgImNvbmRpdGlvbiIpCmJhY2tncm91bmRfc3VtX2FsbF9jb25kID0gZGF0YS5mcmFtZShtYXRyaXgobmNvbCA9IDcsIG5yb3cgPSAwKSkKbmFtZXMoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQpID0gYygiZGlzdF9iaW4iLCAibiIsICJzaGFyZSIsICJzaGFyZV9mdWxsIiwgICJ0eXBlIiwgImNvbmRpdGlvbiIsICJpIikKCmZvcihhYl90cCBpbiBhYl90cF9saXN0KSB7CiAgCiAgIyBhbGwgdmFyaWFudHMKICBkZl9zZWwgPSByZXNfZGYgJT4lIGRwbHlyOjpmaWx0ZXIoY29uZGl0aW9uID09IGFiX3RwKQogIE5fdmFyID0gbGVuZ3RoKHVuaXF1ZShkZl9zZWwkc25wX2lkKSkgIyBudW1iZXIgb2YgdmFyaWFudHMgaW4gcGVha3Mgd2l0aCBtb3RpZnMKICBOX3BlYWsgPSBsZW5ndGgodW5pcXVlKGRmX3NlbCRwZWFrX2lkKSkgIyBudW1iZXIgb2YgcGVha3Mgd2l0aCBtb3RpZnMKICAKICAjIHNpZ25pZmljYW50IHZhcmlhbnRzCiAgZGZfc2lnbiA9IGRmX3NlbCAlPiUgZmlsdGVyKHNpZ25pZl9zdHJvbmdBSSkKICBOX3Zhcl9zaWduID0gbGVuZ3RoKHVuaXF1ZShkZl9zaWduJHNucF9pZCkpICMgbnVtYmVyIG9mIHNpZ25pZmljYW50IHZhcmlhbnRzIGluIHBlYWtzIHdpdGggbW90aWZzCiAgTl9wZWFrX3NpZ24gPSBsZW5ndGgodW5pcXVlKGRmX3NpZ24kcGVha19pZCkpICMgbnVtYmVyIG9mIEFJIHBlYWtzIHdpdGggbW90aWZzCgogIHNpZ25fc3VtID0gZGZfc2lnbiAlPiUgCiAgICBkcGx5cjo6Z3JvdXBfYnkocGVha19pZCkgJT4lIAogICAgZHBseXI6Om11dGF0ZShtaW5fZGlzdCA9IG1pbihkaXN0Mm1vdGlmKSkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKGRpc3QybW90aWYgPT0gbWluX2Rpc3QpICU+JQogICAgZHBseXI6OnNlbGVjdChwZWFrX2lkLCBkaXN0Mm1vdGlmKSAlPiUgdW5pcXVlKCkgJT4lIHVuZ3JvdXAoKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoTl90b3QgPSBuKCksIGRpc3RfYmluID0gY3V0KGRpc3QybW90aWYsIGJyZWFrcyA9IGRpc3RfYnJlYWtzLCBsYWJlbHMgPSBkaXN0X2xhYmVscykpICU+JQogICAgZHBseXI6Omdyb3VwX2J5KGRpc3RfYmluKSAlPiUKICAgIGRwbHlyOjpzdW1tYXJpemUobiA9IG4oKSwgc2hhcmUgPSBuIC8gbWVhbihOX3RvdCksIHNkID0gc2QobiksIHR5cGUgPSAicmVhbCIsIGNvbmRpdGlvbiA9IGFiX3RwKQogIAogIAogIGRmX25vbl9zaWduID0gZGZfc2VsICU+JSBkcGx5cjo6Z3JvdXBfYnkocGVha19pZCkgJT4lIGRwbHlyOjptdXRhdGUoQUlfcGVhayA9IGFueShzaWduaWZfc3Ryb25nQUkpKSAlPiUgZHBseXI6OmZpbHRlcighQUlfcGVhaykgJT4lIHVuZ3JvdXAoKQogIAogIGJhY2tncm91bmRfc3VtX2FsbCA9IGxhcHBseSgxOjEwMDAwLCBmdW5jdGlvbihpKSB7CiAgICAKICAgICNwcmludChpKQogICAgCiAgICAjIDEuIHNlbGVjdCBzYW1lIG51bWJlciBvZiBwZWFrcyBhcyBpbiBBSSBwZWFrcwogICAgcGVha19pZHMgPSBzYW1wbGUodW5pcXVlKGRmX25vbl9zaWduJHBlYWtfaWQpLCBOX3BlYWtfc2lnbikKICAgIGRmX2JnID0gZGZfbm9uX3NpZ24gJT4lIGRwbHlyOjpmaWx0ZXIocGVha19pZCAlaW4lIHBlYWtfaWRzKQogICAgCiAgICAjIDIuIHNlbGVjdCBzYW1lIG51bWJlciBvZiB2YXJpYW50cyBhcyBmb3IgQUkgcGVha3MKICAgIHZhcmlhbnRfaWRzID0gc2FtcGxlKHVuaXF1ZShkZl9iZyRzbnBfaWQpLCBOX3Zhcl9zaWduKQogICAgZGZfYmcgJTw+JSBmaWx0ZXIoc25wX2lkICVpbiUgdmFyaWFudF9pZHMpCiAgICAKICAgIE5fcGVha19iZyA9IGxlbmd0aCh1bmlxdWUoZGZfYmckcGVha19pZCkpIAogICAgCiAgICBiZ19zdW0gPSBkZl9iZyAlPiUgCiAgICAgIGRwbHlyOjpncm91cF9ieShwZWFrX2lkKSAlPiUgCiAgICAgIGRwbHlyOjptdXRhdGUobWluX2Rpc3QgPSBtaW4oZGlzdDJtb3RpZikpICU+JQogICAgICBkcGx5cjo6ZmlsdGVyKGRpc3QybW90aWYgPT0gbWluX2Rpc3QpICU+JQogICAgICBkcGx5cjo6c2VsZWN0KHBlYWtfaWQsIGRpc3QybW90aWYpICU+JSB1bmlxdWUoKSAlPiUgdW5ncm91cCgpICU+JQogICAgICBkcGx5cjo6bXV0YXRlKE5fdG90ID0gbigpLCBkaXN0X2JpbiA9IGN1dChkaXN0Mm1vdGlmLCBicmVha3MgPSBkaXN0X2JyZWFrcywgbGFiZWxzID0gZGlzdF9sYWJlbHMpKSAlPiUKICAgICAgZHBseXI6Omdyb3VwX2J5KGRpc3RfYmluKSAlPiUKICAgICAgZHBseXI6OnN1bW1hcml6ZShuID0gbigpLCBzaGFyZSA9IG4gLyBtZWFuKE5fdG90KSwgc2hhcmVfZnVsbCA9IG4gLyBOX3BlYWtfYmcpICU+JQogICAgICBkcGx5cjo6bXV0YXRlKGNvbmRpdGlvbiA9IGFiX3RwLCBpID0gaSkKICAgIAogICAgCiAgICBiZ19zdW0kdHlwZSA9ICJiYWNrZ3JvdW5kIgogICAgYmdfc3VtCiAgICAKICB9KSAlPiUgYmluZF9yb3dzKCkKICAKICBiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCA9IHJiaW5kKGJhY2tncm91bmRfc3VtX2FsbF9jb25kLCBiYWNrZ3JvdW5kX3N1bV9hbGwpCiAgCiAgYmFja2dyb3VuZF9zdW0gPSBiYWNrZ3JvdW5kX3N1bV9hbGwgJT4lIAogICAgZHBseXI6Omdyb3VwX2J5KGRpc3RfYmluKSAlPiUgCiAgICBkcGx5cjo6c3VtbWFyaXplKG4gPSBtZWFuKG4pLCAKICAgICAgICAgICAgICAgICAgICAgc2hhcmUgPSBtZWFuKHNoYXJlKSwgCiAgICAgICAgICAgICAgICAgICAgIHNkID0gc2Qoc2hhcmVfZnVsbCksCiAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAiYmFja2dyb3VuZCIsIAogICAgICAgICAgICAgICAgICAgICBjb25kaXRpb24gPSBhYl90cCkKICAKICAKICByZXMgPSByYmluZC5kYXRhLmZyYW1lKHNpZ25fc3VtLCBiYWNrZ3JvdW5kX3N1bSkKICAKICByZXNfZnVsbCA9IHJiaW5kLmRhdGEuZnJhbWUocmVzX2Z1bGwsIHJlcykKCn0KCgpyZXNfZnVsbCRkaXN0X2JpbiA9IGZhY3RvcihyZXNfZnVsbCRkaXN0X2JpbiwgbGV2ZWxzID0gcmV2KGRpc3RfbGFiZWxzKSkKcmVzX2Z1bGwkdGZfbGFiZWxzID0gYWJfdHBfbGFiZWxzW3Jlc19mdWxsJGNvbmRpdGlvbl0gIApyZXNfZnVsbCR0Zl9sYWJlbHMgPSBmYWN0b3IocmVzX2Z1bGwkdGZfbGFiZWxzLCBsZXZlbHMgPSBhYl90cF9sYWJlbHMpCgpzaGFyZXNfaW5fbW90aWYgPSByZXNfZnVsbCAlPiUgCiAgYXJyYW5nZSh0Zl9sYWJlbHMpICU+JSAKICBmaWx0ZXIoZGlzdF9iaW4gPT0gImluIG1vdGlmIiwgdHlwZSA9PSAicmVhbCIpICU+JSAKICBzZWxlY3Qoc2hhcmUpICU+JSB1bmxpc3QoKSAlPiUgdW5pcXVlKCkgJT4lIHJvdW5kKDIpCgoKcmVzX2Z1bGwkZGlzdF9iaW4gPSBmYWN0b3IocmVzX2Z1bGwkZGlzdF9iaW4sIGxldmVscyA9IGRpc3RfbGFiZWxzKQpyZXNfZnVsbCR0eXBlID0gZmFjdG9yKHJlc19mdWxsJHR5cGUsIGxldmVscyA9IHVuaXF1ZShyZXNfZnVsbCR0eXBlKSkKCnAgPSBnZ3Bsb3QocmVzX2Z1bGwsIGFlcyh4ID0gZGlzdF9iaW4sIHkgPSBzaGFyZSwgY29sb3IgPSB0eXBlLCBncm91cCA9IHR5cGUpKSArCiAgZmFjZXRfd3JhcCh+dGZfbGFiZWxzLCBuY29sID0gMykgKwogIGdlb21fcmliYm9uKGRhdGE9c3Vic2V0KHJlc19mdWxsLCB0eXBlPT0iYmFja2dyb3VuZCIpLCBhZXMoeD1kaXN0X2JpbiwgeSA9IHNoYXJlLCB5bWluID0gc2hhcmUgLSBzZCAqIDIsIHltYXggPSBzaGFyZSArIHNkICogMiwgZ3JvdXAgPSB0eXBlKSwgZmlsbCA9ICJncmV5NzAiLCBjb2xvdXI9TkEsIGFscGhhID0gLjQpICsKICBnZW9tX3BvaW50KHNpemUgPSAyKSArIAogIGdlb21fbGluZShsaW5ld2lkdGggPSAxKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImdyZXkiLCAiZGFya2JsdWUiKSwgbmFtZSA9ICIiLCBsYWJlbHMgPSBjKCJBSSBwZWFrcyB3aXRoIG1vdGlmcyIsICJiYWNrZ3JvdW5kIikpICsKICB0aGVtZV9idygpICsKICB5bGFiKCJTaGFyZSBvZiBwZWFrcyIpICsKICB4bGFiKCJEaXN0YW5jZSBmcm9tIFRGIG1vdGlmIikgKwogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemU9MTQpLCBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTE0LCBhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplPTE2KSwgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemU9MTYpLAogICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTE2KSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE2KSkKCgpwCm91dGYgPSBmaWxlLnBhdGgob3V0ZGlyX2ZpZ19zdXBwbCwgcGFzdGUwKCJGaWdTNEFfZGlzdDJtb3RpZl92c19iYWNrZ3JvdW5kLnBkZiIpKQpnZ3NhdmUob3V0ZiwgcCwgd2lkdGggPSAxMiwgaGVpZ2h0ID0gNikKCmBgYAoKKipFbXBpcmljYWwgcC12YWx1ZXMgZm9yIHRoZSB0ZXN0OiByZWFsIHNoYXJlIGlzIGxhcmdlciB0aGFuIGJhY2tncm91bmQgc2hhcmUqKgoKPGJyPgoKKipJbiBtb3RpZioqCgp8IENvbmRpdGlvbiB8IHAtdmFsdWUgfAp8IDotLS0tLS0tLS0tLSB8IDotLS0tLS0tLS0tLTogfAp8IFR3aSAyLTRoIHwgYHIgKHN1bShzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iaW4gbW90aWYiICYgY29uZGl0aW9uPT0idHdpLzI0Iikkc2hhcmUgPj0gc3Vic2V0KHJlc19mdWxsLCB0eXBlPT0icmVhbCIgJiBjb25kaXRpb249PSJ0d2kvMjQiICYgZGlzdF9iaW49PSJpbiBtb3RpZiIpJHNoYXJlKSArIDEpIC8gKGxlbmd0aChzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iaW4gbW90aWYiICYgY29uZGl0aW9uPT0idHdpLzI0Iikkc2hhcmUpICsgMSlgIHwKfCBDVENGIDYtOGggfCBgciAoc3VtKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSJpbiBtb3RpZiIgJiBjb25kaXRpb249PSJjdGNmLzY4Iikkc2hhcmUgPj0gc3Vic2V0KHJlc19mdWxsLCB0eXBlPT0icmVhbCIgJiBjb25kaXRpb249PSJjdGNmLzY4IiAmIGRpc3RfYmluPT0iaW4gbW90aWYiKSRzaGFyZSkgKyAxKSAvIChsZW5ndGgoc3Vic2V0KGJhY2tncm91bmRfc3VtX2FsbF9jb25kLCBkaXN0X2Jpbj09ImluIG1vdGlmIiAmIGNvbmRpdGlvbj09ImN0Y2YvNjgiKSRzaGFyZSkgKyAxKWAgfAp8IE1lZjIgNi04aCB8IGByIChzdW0oc3Vic2V0KGJhY2tncm91bmRfc3VtX2FsbF9jb25kLCBkaXN0X2Jpbj09ImluIG1vdGlmIiAmIGNvbmRpdGlvbj09Im1lZjIvNjgiKSRzaGFyZSA+PSBzdWJzZXQocmVzX2Z1bGwsIHR5cGU9PSJyZWFsIiAmIGNvbmRpdGlvbj09Im1lZjIvNjgiICYgZGlzdF9iaW49PSJpbiBtb3RpZiIpJHNoYXJlKSArIDEpIC8gKGxlbmd0aChzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iaW4gbW90aWYiICYgY29uZGl0aW9uPT0ibWVmMi82OCIpJHNoYXJlKSArIDEpYCB8CnwgTWVmMiAxMC0xMmggfCBgciAoc3VtKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSJpbiBtb3RpZiIgJiBjb25kaXRpb249PSJtZWYyLzEwMTIiKSRzaGFyZSA+PSBzdWJzZXQocmVzX2Z1bGwsIHR5cGU9PSJyZWFsIiAmIGNvbmRpdGlvbj09Im1lZjIvMTAxMiIgJiBkaXN0X2Jpbj09ImluIG1vdGlmIikkc2hhcmUpICsgMSkgLyAobGVuZ3RoKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSJpbiBtb3RpZiIgJiBjb25kaXRpb249PSJtZWYyLzEwMTIiKSRzaGFyZSkgKyAxKWAgfAp8IEJpbiA2LThoIHwgYHIgKHN1bShzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iaW4gbW90aWYiICYgY29uZGl0aW9uPT0iYmluLzY4Iikkc2hhcmUgPj0gc3Vic2V0KHJlc19mdWxsLCB0eXBlPT0icmVhbCIgJiBjb25kaXRpb249PSJiaW4vNjgiICYgZGlzdF9iaW49PSJpbiBtb3RpZiIpJHNoYXJlKSArIDEpIC8gKGxlbmd0aChzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iaW4gbW90aWYiICYgY29uZGl0aW9uPT0iYmluLzY4Iikkc2hhcmUpICsgMSlgIHwKfCBCaW4gMTAtMTJoIHwgYHIgKHN1bShzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iaW4gbW90aWYiICYgY29uZGl0aW9uPT0iYmluLzEwMTIiKSRzaGFyZSA+PSBzdWJzZXQocmVzX2Z1bGwsIHR5cGU9PSJyZWFsIiAmIGNvbmRpdGlvbj09ImJpbi8xMDEyIiAmIGRpc3RfYmluPT0iaW4gbW90aWYiKSRzaGFyZSkgKyAxKSAvIChsZW5ndGgoc3Vic2V0KGJhY2tncm91bmRfc3VtX2FsbF9jb25kLCBkaXN0X2Jpbj09ImluIG1vdGlmIiAmIGNvbmRpdGlvbj09ImJpbi8xMDEyIikkc2hhcmUpICsgMSlgIHwKCgo8YnI+CgoqKjEtMjAgYnAqKgoKfCBDb25kaXRpb24gfCBwLXZhbHVlIHwKfCA6LS0tLS0tLS0tLS0gfCA6LS0tLS0tLS0tLS06IHwKfCBUd2kgMi00aCB8IGByIChzdW0oc3Vic2V0KGJhY2tncm91bmRfc3VtX2FsbF9jb25kLCBkaXN0X2Jpbj09IjEtMjAgYnAiICYgY29uZGl0aW9uPT0idHdpLzI0Iikkc2hhcmUgPj0gc3Vic2V0KHJlc19mdWxsLCB0eXBlPT0icmVhbCIgJiBjb25kaXRpb249PSJ0d2kvMjQiICYgZGlzdF9iaW49PSIxLTIwIGJwIikkc2hhcmUpICsgMSkgLyAobGVuZ3RoKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSIxLTIwIGJwIiAmIGNvbmRpdGlvbj09InR3aS8yNCIpJHNoYXJlKSArIDEpYCB8CnwgQ1RDRiA2LThoIHwgYHIgKHN1bShzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iMS0yMCBicCIgJiBjb25kaXRpb249PSJjdGNmLzY4Iikkc2hhcmUgPj0gc3Vic2V0KHJlc19mdWxsLCB0eXBlPT0icmVhbCIgJiBjb25kaXRpb249PSJjdGNmLzY4IiAmIGRpc3RfYmluPT0iMS0yMCBicCIpJHNoYXJlKSArIDEpIC8gKGxlbmd0aChzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iMS0yMCBicCIgJiBjb25kaXRpb249PSJjdGNmLzY4Iikkc2hhcmUpICsgMSlgIHwKfCBNZWYyIDYtOGggfCBgciAoc3VtKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSIxLTIwIGJwIiAmIGNvbmRpdGlvbj09Im1lZjIvNjgiKSRzaGFyZSA+PSBzdWJzZXQocmVzX2Z1bGwsIHR5cGU9PSJyZWFsIiAmIGNvbmRpdGlvbj09Im1lZjIvNjgiICYgZGlzdF9iaW49PSIxLTIwIGJwIikkc2hhcmUpICsgMSkgLyAobGVuZ3RoKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSIxLTIwIGJwIiAmIGNvbmRpdGlvbj09Im1lZjIvNjgiKSRzaGFyZSkgKyAxKWAgfAp8IE1lZjIgMTAtMTJoIHwgYHIgKHN1bShzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iMS0yMCBicCIgJiBjb25kaXRpb249PSJtZWYyLzEwMTIiKSRzaGFyZSA+PSBzdWJzZXQocmVzX2Z1bGwsIHR5cGU9PSJyZWFsIiAmIGNvbmRpdGlvbj09Im1lZjIvMTAxMiIgJiBkaXN0X2Jpbj09IjEtMjAgYnAiKSRzaGFyZSkgKyAxKSAvIChsZW5ndGgoc3Vic2V0KGJhY2tncm91bmRfc3VtX2FsbF9jb25kLCBkaXN0X2Jpbj09IjEtMjAgYnAiICYgY29uZGl0aW9uPT0ibWVmMi8xMDEyIikkc2hhcmUpICsgMSlgIHwKfCBCaW4gNi04aCB8IGByIChzdW0oc3Vic2V0KGJhY2tncm91bmRfc3VtX2FsbF9jb25kLCBkaXN0X2Jpbj09IjEtMjAgYnAiICYgY29uZGl0aW9uPT0iYmluLzY4Iikkc2hhcmUgPj0gc3Vic2V0KHJlc19mdWxsLCB0eXBlPT0icmVhbCIgJiBjb25kaXRpb249PSJiaW4vNjgiICYgZGlzdF9iaW49PSIxLTIwIGJwIikkc2hhcmUpICsgMSkgLyAobGVuZ3RoKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSIxLTIwIGJwIiAmIGNvbmRpdGlvbj09ImJpbi82OCIpJHNoYXJlKSArIDEpYCB8CnwgQmluIDEwLTEyaCB8IGByIChzdW0oc3Vic2V0KGJhY2tncm91bmRfc3VtX2FsbF9jb25kLCBkaXN0X2Jpbj09IjEtMjAgYnAiICYgY29uZGl0aW9uPT0iYmluLzEwMTIiKSRzaGFyZSA+PSBzdWJzZXQocmVzX2Z1bGwsIHR5cGU9PSJyZWFsIiAmIGNvbmRpdGlvbj09ImJpbi8xMDEyIiAmIGRpc3RfYmluPT0iMS0yMCBicCIpJHNoYXJlKSArIDEpIC8gKGxlbmd0aChzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iMS0yMCBicCIgJiBjb25kaXRpb249PSJiaW4vMTAxMiIpJHNoYXJlKSArIDEpYCB8Cgo8YnI+CgoqKjIxLTQwIGJwKioKCnwgQ29uZGl0aW9uIHwgcC12YWx1ZSB8CnwgOi0tLS0tLS0tLS0tIHwgOi0tLS0tLS0tLS0tOiB8CnwgVHdpIDItNGggfCBgciAoc3VtKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSIyMS00MCBicCIgJiBjb25kaXRpb249PSJ0d2kvMjQiKSRzaGFyZSA+PSBzdWJzZXQocmVzX2Z1bGwsIHR5cGU9PSJyZWFsIiAmIGNvbmRpdGlvbj09InR3aS8yNCIgJiBkaXN0X2Jpbj09IjIxLTQwIGJwIikkc2hhcmUpICsgMSkgLyAobGVuZ3RoKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSIyMS00MCBicCIgJiBjb25kaXRpb249PSJ0d2kvMjQiKSRzaGFyZSkgKyAxKWAgfAp8IENUQ0YgNi04aCB8IGByIChzdW0oc3Vic2V0KGJhY2tncm91bmRfc3VtX2FsbF9jb25kLCBkaXN0X2Jpbj09IjIxLTQwIGJwIiAmIGNvbmRpdGlvbj09ImN0Y2YvNjgiKSRzaGFyZSA+PSBzdWJzZXQocmVzX2Z1bGwsIHR5cGU9PSJyZWFsIiAmIGNvbmRpdGlvbj09ImN0Y2YvNjgiICYgZGlzdF9iaW49PSIyMS00MCBicCIpJHNoYXJlKSArIDEpIC8gKGxlbmd0aChzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iMjEtNDAgYnAiICYgY29uZGl0aW9uPT0iY3RjZi82OCIpJHNoYXJlKSArIDEpYCB8CnwgTWVmMiA2LThoIHwgYHIgKHN1bShzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iMjEtNDAgYnAiICYgY29uZGl0aW9uPT0ibWVmMi82OCIpJHNoYXJlID49IHN1YnNldChyZXNfZnVsbCwgdHlwZT09InJlYWwiICYgY29uZGl0aW9uPT0ibWVmMi82OCIgJiBkaXN0X2Jpbj09IjIxLTQwIGJwIikkc2hhcmUpICsgMSkgLyAobGVuZ3RoKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSIyMS00MCBicCIgJiBjb25kaXRpb249PSJtZWYyLzY4Iikkc2hhcmUpICsgMSlgIHwKfCBNZWYyIDEwLTEyaCB8IGByIChzdW0oc3Vic2V0KGJhY2tncm91bmRfc3VtX2FsbF9jb25kLCBkaXN0X2Jpbj09IjIxLTQwIGJwIiAmIGNvbmRpdGlvbj09Im1lZjIvMTAxMiIpJHNoYXJlID49IHN1YnNldChyZXNfZnVsbCwgdHlwZT09InJlYWwiICYgY29uZGl0aW9uPT0ibWVmMi8xMDEyIiAmIGRpc3RfYmluPT0iMjEtNDAgYnAiKSRzaGFyZSkgKyAxKSAvIChsZW5ndGgoc3Vic2V0KGJhY2tncm91bmRfc3VtX2FsbF9jb25kLCBkaXN0X2Jpbj09IjIxLTQwIGJwIiAmIGNvbmRpdGlvbj09Im1lZjIvMTAxMiIpJHNoYXJlKSArIDEpYCB8CnwgQmluIDYtOGggfCBgciAoc3VtKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSIyMS00MCBicCIgJiBjb25kaXRpb249PSJiaW4vNjgiKSRzaGFyZSA+PSBzdWJzZXQocmVzX2Z1bGwsIHR5cGU9PSJyZWFsIiAmIGNvbmRpdGlvbj09ImJpbi82OCIgJiBkaXN0X2Jpbj09IjIxLTQwIGJwIikkc2hhcmUpICsgMSkgLyAobGVuZ3RoKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSIyMS00MCBicCIgJiBjb25kaXRpb249PSJiaW4vNjgiKSRzaGFyZSkgKyAxKWAgfAp8IEJpbiAxMC0xMmggfCBgciAoc3VtKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSIyMS00MCBicCIgJiBjb25kaXRpb249PSJiaW4vMTAxMiIpJHNoYXJlID49IHN1YnNldChyZXNfZnVsbCwgdHlwZT09InJlYWwiICYgY29uZGl0aW9uPT0iYmluLzEwMTIiICYgZGlzdF9iaW49PSIyMS00MCBicCIpJHNoYXJlKSArIDEpIC8gKGxlbmd0aChzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iMjEtNDAgYnAiICYgY29uZGl0aW9uPT0iYmluLzEwMTIiKSRzaGFyZSkgKyAxKWAgfAoKCjxicj4KCioqNDEtNjAgYnAqKgoKfCBDb25kaXRpb24gfCBwLXZhbHVlIHwKfCA6LS0tLS0tLS0tLS0gfCA6LS0tLS0tLS0tLS06IHwKfCBUd2kgMi00aCB8IGByIChzdW0oc3Vic2V0KGJhY2tncm91bmRfc3VtX2FsbF9jb25kLCBkaXN0X2Jpbj09IjQxLTYwIGJwIiAmIGNvbmRpdGlvbj09InR3aS8yNCIpJHNoYXJlID49IHN1YnNldChyZXNfZnVsbCwgdHlwZT09InJlYWwiICYgY29uZGl0aW9uPT0idHdpLzI0IiAmIGRpc3RfYmluPT0iNDEtNjAgYnAiKSRzaGFyZSkgKyAxKSAvIChsZW5ndGgoc3Vic2V0KGJhY2tncm91bmRfc3VtX2FsbF9jb25kLCBkaXN0X2Jpbj09IjQxLTYwIGJwIiAmIGNvbmRpdGlvbj09InR3aS8yNCIpJHNoYXJlKSArIDEpYCB8CnwgQ1RDRiA2LThoIHwgYHIgKHN1bShzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iNDEtNjAgYnAiICYgY29uZGl0aW9uPT0iY3RjZi82OCIpJHNoYXJlID49IHN1YnNldChyZXNfZnVsbCwgdHlwZT09InJlYWwiICYgY29uZGl0aW9uPT0iY3RjZi82OCIgJiBkaXN0X2Jpbj09IjQxLTYwIGJwIikkc2hhcmUpICsgMSkgLyAobGVuZ3RoKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSI0MS02MCBicCIgJiBjb25kaXRpb249PSJjdGNmLzY4Iikkc2hhcmUpICsgMSlgIHwKfCBNZWYyIDYtOGggfCBgciAoc3VtKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSI0MS02MCBicCIgJiBjb25kaXRpb249PSJtZWYyLzY4Iikkc2hhcmUgPj0gc3Vic2V0KHJlc19mdWxsLCB0eXBlPT0icmVhbCIgJiBjb25kaXRpb249PSJtZWYyLzY4IiAmIGRpc3RfYmluPT0iNDEtNjAgYnAiKSRzaGFyZSkgKyAxKSAvIChsZW5ndGgoc3Vic2V0KGJhY2tncm91bmRfc3VtX2FsbF9jb25kLCBkaXN0X2Jpbj09IjQxLTYwIGJwIiAmIGNvbmRpdGlvbj09Im1lZjIvNjgiKSRzaGFyZSkgKyAxKWAgfAp8IE1lZjIgMTAtMTJoIHwgYHIgKHN1bShzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iNDEtNjAgYnAiICYgY29uZGl0aW9uPT0ibWVmMi8xMDEyIikkc2hhcmUgPj0gc3Vic2V0KHJlc19mdWxsLCB0eXBlPT0icmVhbCIgJiBjb25kaXRpb249PSJtZWYyLzEwMTIiICYgZGlzdF9iaW49PSI0MS02MCBicCIpJHNoYXJlKSArIDEpIC8gKGxlbmd0aChzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iNDEtNjAgYnAiICYgY29uZGl0aW9uPT0ibWVmMi8xMDEyIikkc2hhcmUpICsgMSlgIHwKfCBCaW4gNi04aCB8IGByIChzdW0oc3Vic2V0KGJhY2tncm91bmRfc3VtX2FsbF9jb25kLCBkaXN0X2Jpbj09IjQxLTYwIGJwIiAmIGNvbmRpdGlvbj09ImJpbi82OCIpJHNoYXJlID49IHN1YnNldChyZXNfZnVsbCwgdHlwZT09InJlYWwiICYgY29uZGl0aW9uPT0iYmluLzY4IiAmIGRpc3RfYmluPT0iNDEtNjAgYnAiKSRzaGFyZSkgKyAxKSAvIChsZW5ndGgoc3Vic2V0KGJhY2tncm91bmRfc3VtX2FsbF9jb25kLCBkaXN0X2Jpbj09IjQxLTYwIGJwIiAmIGNvbmRpdGlvbj09ImJpbi82OCIpJHNoYXJlKSArIDEpYCB8CnwgQmluIDEwLTEyaCB8IGByIChzdW0oc3Vic2V0KGJhY2tncm91bmRfc3VtX2FsbF9jb25kLCBkaXN0X2Jpbj09IjQxLTYwIGJwIiAmIGNvbmRpdGlvbj09ImJpbi8xMDEyIikkc2hhcmUgPj0gc3Vic2V0KHJlc19mdWxsLCB0eXBlPT0icmVhbCIgJiBjb25kaXRpb249PSJiaW4vMTAxMiIgJiBkaXN0X2Jpbj09IjQxLTYwIGJwIikkc2hhcmUpICsgMSkgLyAobGVuZ3RoKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSI0MS02MCBicCIgJiBjb25kaXRpb249PSJiaW4vMTAxMiIpJHNoYXJlKSArIDEpYCB8CgoKPGJyPgoKKio2MS04MCBicCoqCgp8IENvbmRpdGlvbiB8IHAtdmFsdWUgfAp8IDotLS0tLS0tLS0tLSB8IDotLS0tLS0tLS0tLTogfAp8IFR3aSAyLTRoIHwgYHIgKHN1bShzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iNjEtODAgYnAiICYgY29uZGl0aW9uPT0idHdpLzI0Iikkc2hhcmUgPj0gc3Vic2V0KHJlc19mdWxsLCB0eXBlPT0icmVhbCIgJiBjb25kaXRpb249PSJ0d2kvMjQiICYgZGlzdF9iaW49PSI2MS04MCBicCIpJHNoYXJlKSArIDEpIC8gKGxlbmd0aChzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iNjEtODAgYnAiICYgY29uZGl0aW9uPT0idHdpLzI0Iikkc2hhcmUpICsgMSlgIHwKfCBDVENGIDYtOGggfCBgciAoc3VtKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSI2MS04MCBicCIgJiBjb25kaXRpb249PSJjdGNmLzY4Iikkc2hhcmUgPj0gc3Vic2V0KHJlc19mdWxsLCB0eXBlPT0icmVhbCIgJiBjb25kaXRpb249PSJjdGNmLzY4IiAmIGRpc3RfYmluPT0iNjEtODAgYnAiKSRzaGFyZSkgKyAxKSAvIChsZW5ndGgoc3Vic2V0KGJhY2tncm91bmRfc3VtX2FsbF9jb25kLCBkaXN0X2Jpbj09IjYxLTgwIGJwIiAmIGNvbmRpdGlvbj09ImN0Y2YvNjgiKSRzaGFyZSkgKyAxKWAgfAp8IE1lZjIgNi04aCB8IGByIChzdW0oc3Vic2V0KGJhY2tncm91bmRfc3VtX2FsbF9jb25kLCBkaXN0X2Jpbj09IjYxLTgwIGJwIiAmIGNvbmRpdGlvbj09Im1lZjIvNjgiKSRzaGFyZSA+PSBzdWJzZXQocmVzX2Z1bGwsIHR5cGU9PSJyZWFsIiAmIGNvbmRpdGlvbj09Im1lZjIvNjgiICYgZGlzdF9iaW49PSI2MS04MCBicCIpJHNoYXJlKSArIDEpIC8gKGxlbmd0aChzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iNjEtODAgYnAiICYgY29uZGl0aW9uPT0ibWVmMi82OCIpJHNoYXJlKSArIDEpYCB8CnwgTWVmMiAxMC0xMmggfCBgciAoc3VtKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSI2MS04MCBicCIgJiBjb25kaXRpb249PSJtZWYyLzEwMTIiKSRzaGFyZSA+PSBzdWJzZXQocmVzX2Z1bGwsIHR5cGU9PSJyZWFsIiAmIGNvbmRpdGlvbj09Im1lZjIvMTAxMiIgJiBkaXN0X2Jpbj09IjYxLTgwIGJwIikkc2hhcmUpICsgMSkgLyAobGVuZ3RoKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSI2MS04MCBicCIgJiBjb25kaXRpb249PSJtZWYyLzEwMTIiKSRzaGFyZSkgKyAxKWAgfAp8IEJpbiA2LThoIHwgYHIgKHN1bShzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iNjEtODAgYnAiICYgY29uZGl0aW9uPT0iYmluLzY4Iikkc2hhcmUgPj0gc3Vic2V0KHJlc19mdWxsLCB0eXBlPT0icmVhbCIgJiBjb25kaXRpb249PSJiaW4vNjgiICYgZGlzdF9iaW49PSI2MS04MCBicCIpJHNoYXJlKSArIDEpIC8gKGxlbmd0aChzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iNjEtODAgYnAiICYgY29uZGl0aW9uPT0iYmluLzY4Iikkc2hhcmUpICsgMSlgIHwKfCBCaW4gMTAtMTJoIHwgYHIgKHN1bShzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iNjEtODAgYnAiICYgY29uZGl0aW9uPT0iYmluLzEwMTIiKSRzaGFyZSA+PSBzdWJzZXQocmVzX2Z1bGwsIHR5cGU9PSJyZWFsIiAmIGNvbmRpdGlvbj09ImJpbi8xMDEyIiAmIGRpc3RfYmluPT0iNjEtODAgYnAiKSRzaGFyZSkgKyAxKSAvIChsZW5ndGgoc3Vic2V0KGJhY2tncm91bmRfc3VtX2FsbF9jb25kLCBkaXN0X2Jpbj09IjYxLTgwIGJwIiAmIGNvbmRpdGlvbj09ImJpbi8xMDEyIikkc2hhcmUpICsgMSlgIHwKCgo8YnI+CgoqKjgxLTEwMCBicCoqCgp8IENvbmRpdGlvbiB8IHAtdmFsdWUgfAp8IDotLS0tLS0tLS0tLSB8IDotLS0tLS0tLS0tLTogfAp8IFR3aSAyLTRoIHwgYHIgKHN1bShzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iODEtMTAwIGJwIiAmIGNvbmRpdGlvbj09InR3aS8yNCIpJHNoYXJlID49IHN1YnNldChyZXNfZnVsbCwgdHlwZT09InJlYWwiICYgY29uZGl0aW9uPT0idHdpLzI0IiAmIGRpc3RfYmluPT0iODEtMTAwIGJwIikkc2hhcmUpICsgMSkgLyAobGVuZ3RoKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSI4MS0xMDAgYnAiICYgY29uZGl0aW9uPT0idHdpLzI0Iikkc2hhcmUpICsgMSlgIHwKfCBDVENGIDYtOGggfCBgciAoc3VtKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSI4MS0xMDAgYnAiICYgY29uZGl0aW9uPT0iY3RjZi82OCIpJHNoYXJlID49IHN1YnNldChyZXNfZnVsbCwgdHlwZT09InJlYWwiICYgY29uZGl0aW9uPT0iY3RjZi82OCIgJiBkaXN0X2Jpbj09IjgxLTEwMCBicCIpJHNoYXJlKSArIDEpIC8gKGxlbmd0aChzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iODEtMTAwIGJwIiAmIGNvbmRpdGlvbj09ImN0Y2YvNjgiKSRzaGFyZSkgKyAxKWAgfAp8IE1lZjIgNi04aCB8IGByIChzdW0oc3Vic2V0KGJhY2tncm91bmRfc3VtX2FsbF9jb25kLCBkaXN0X2Jpbj09IjgxLTEwMCBicCIgJiBjb25kaXRpb249PSJtZWYyLzY4Iikkc2hhcmUgPj0gc3Vic2V0KHJlc19mdWxsLCB0eXBlPT0icmVhbCIgJiBjb25kaXRpb249PSJtZWYyLzY4IiAmIGRpc3RfYmluPT0iODEtMTAwIGJwIikkc2hhcmUpICsgMSkgLyAobGVuZ3RoKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSI4MS0xMDAgYnAiICYgY29uZGl0aW9uPT0ibWVmMi82OCIpJHNoYXJlKSArIDEpYCB8CnwgTWVmMiAxMC0xMmggfCBgciAoc3VtKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSI4MS0xMDAgYnAiICYgY29uZGl0aW9uPT0ibWVmMi8xMDEyIikkc2hhcmUgPj0gc3Vic2V0KHJlc19mdWxsLCB0eXBlPT0icmVhbCIgJiBjb25kaXRpb249PSJtZWYyLzEwMTIiICYgZGlzdF9iaW49PSI4MS0xMDAgYnAiKSRzaGFyZSkgKyAxKSAvIChsZW5ndGgoc3Vic2V0KGJhY2tncm91bmRfc3VtX2FsbF9jb25kLCBkaXN0X2Jpbj09IjgxLTEwMCBicCIgJiBjb25kaXRpb249PSJtZWYyLzEwMTIiKSRzaGFyZSkgKyAxKWAgfAp8IEJpbiA2LThoIHwgYHIgKHN1bShzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iODEtMTAwIGJwIiAmIGNvbmRpdGlvbj09ImJpbi82OCIpJHNoYXJlID49IHN1YnNldChyZXNfZnVsbCwgdHlwZT09InJlYWwiICYgY29uZGl0aW9uPT0iYmluLzY4IiAmIGRpc3RfYmluPT0iODEtMTAwIGJwIikkc2hhcmUpICsgMSkgLyAobGVuZ3RoKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSI4MS0xMDAgYnAiICYgY29uZGl0aW9uPT0iYmluLzY4Iikkc2hhcmUpICsgMSlgIHwKfCBCaW4gMTAtMTJoIHwgYHIgKHN1bShzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iODEtMTAwIGJwIiAmIGNvbmRpdGlvbj09ImJpbi8xMDEyIikkc2hhcmUgPj0gc3Vic2V0KHJlc19mdWxsLCB0eXBlPT0icmVhbCIgJiBjb25kaXRpb249PSJiaW4vMTAxMiIgJiBkaXN0X2Jpbj09IjgxLTEwMCBicCIpJHNoYXJlKSArIDEpIC8gKGxlbmd0aChzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iODEtMTAwIGJwIiAmIGNvbmRpdGlvbj09ImJpbi8xMDEyIikkc2hhcmUpICsgMSlgIHwKCgo8YnI+CgoqKj4xMDAgYnAqKgoKfCBDb25kaXRpb24gfCBwLXZhbHVlIHwKfCA6LS0tLS0tLS0tLS0gfCA6LS0tLS0tLS0tLS06IHwKfCBUd2kgMi00aCB8IGByIChzdW0oc3Vic2V0KGJhY2tncm91bmRfc3VtX2FsbF9jb25kLCBkaXN0X2Jpbj09Ij4xMDAgYnAiICYgY29uZGl0aW9uPT0idHdpLzI0Iikkc2hhcmUgPj0gc3Vic2V0KHJlc19mdWxsLCB0eXBlPT0icmVhbCIgJiBjb25kaXRpb249PSJ0d2kvMjQiICYgZGlzdF9iaW49PSI+MTAwIGJwIikkc2hhcmUpICsgMSkgLyAobGVuZ3RoKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSI+MTAwIGJwIiAmIGNvbmRpdGlvbj09InR3aS8yNCIpJHNoYXJlKSArIDEpYCB8CnwgQ1RDRiA2LThoIHwgYHIgKHN1bShzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iPjEwMCBicCIgJiBjb25kaXRpb249PSJjdGNmLzY4Iikkc2hhcmUgPj0gc3Vic2V0KHJlc19mdWxsLCB0eXBlPT0icmVhbCIgJiBjb25kaXRpb249PSJjdGNmLzY4IiAmIGRpc3RfYmluPT0iPjEwMCBicCIpJHNoYXJlKSArIDEpIC8gKGxlbmd0aChzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iPjEwMCBicCIgJiBjb25kaXRpb249PSJjdGNmLzY4Iikkc2hhcmUpICsgMSlgIHwKfCBNZWYyIDYtOGggfCBgciAoc3VtKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSI+MTAwIGJwIiAmIGNvbmRpdGlvbj09Im1lZjIvNjgiKSRzaGFyZSA+PSBzdWJzZXQocmVzX2Z1bGwsIHR5cGU9PSJyZWFsIiAmIGNvbmRpdGlvbj09Im1lZjIvNjgiICYgZGlzdF9iaW49PSI+MTAwIGJwIikkc2hhcmUpICsgMSkgLyAobGVuZ3RoKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSI+MTAwIGJwIiAmIGNvbmRpdGlvbj09Im1lZjIvNjgiKSRzaGFyZSkgKyAxKWAgfAp8IE1lZjIgMTAtMTJoIHwgYHIgKHN1bShzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iPjEwMCBicCIgJiBjb25kaXRpb249PSJtZWYyLzEwMTIiKSRzaGFyZSA+PSBzdWJzZXQocmVzX2Z1bGwsIHR5cGU9PSJyZWFsIiAmIGNvbmRpdGlvbj09Im1lZjIvMTAxMiIgJiBkaXN0X2Jpbj09Ij4xMDAgYnAiKSRzaGFyZSkgKyAxKSAvIChsZW5ndGgoc3Vic2V0KGJhY2tncm91bmRfc3VtX2FsbF9jb25kLCBkaXN0X2Jpbj09Ij4xMDAgYnAiICYgY29uZGl0aW9uPT0ibWVmMi8xMDEyIikkc2hhcmUpICsgMSlgIHwKfCBCaW4gNi04aCB8IGByIChzdW0oc3Vic2V0KGJhY2tncm91bmRfc3VtX2FsbF9jb25kLCBkaXN0X2Jpbj09Ij4xMDAgYnAiICYgY29uZGl0aW9uPT0iYmluLzY4Iikkc2hhcmUgPj0gc3Vic2V0KHJlc19mdWxsLCB0eXBlPT0icmVhbCIgJiBjb25kaXRpb249PSJiaW4vNjgiICYgZGlzdF9iaW49PSI+MTAwIGJwIikkc2hhcmUpICsgMSkgLyAobGVuZ3RoKHN1YnNldChiYWNrZ3JvdW5kX3N1bV9hbGxfY29uZCwgZGlzdF9iaW49PSI+MTAwIGJwIiAmIGNvbmRpdGlvbj09ImJpbi82OCIpJHNoYXJlKSArIDEpYCB8CnwgQmluIDEwLTEyaCB8IGByIChzdW0oc3Vic2V0KGJhY2tncm91bmRfc3VtX2FsbF9jb25kLCBkaXN0X2Jpbj09Ij4xMDAgYnAiICYgY29uZGl0aW9uPT0iYmluLzEwMTIiKSRzaGFyZSA+PSBzdWJzZXQocmVzX2Z1bGwsIHR5cGU9PSJyZWFsIiAmIGNvbmRpdGlvbj09ImJpbi8xMDEyIiAmIGRpc3RfYmluPT0iPjEwMCBicCIpJHNoYXJlKSArIDEpIC8gKGxlbmd0aChzdWJzZXQoYmFja2dyb3VuZF9zdW1fYWxsX2NvbmQsIGRpc3RfYmluPT0iPjEwMCBicCIgJiBjb25kaXRpb249PSJiaW4vMTAxMiIpJHNoYXJlKSArIDEpYCB8CgoKCgojIEZpZ3VyZSBTNEIgLSBGaXNoZXIncyB0ZXN0czogZW5yaWNobWVudHMgb2Ygc2lnbmlmaWNhbnQgdmFyaWFudHMgaW4gbW90aWlmcyBpbiAvIG91dHNpZGUgcGVha3MKCmBgYHtyfQpvdXRfZGYgPSBkYXRhLmZyYW1lKG1hdHJpeChuY29sID0gMTAsIG5yb3cgPSAwKSkKbmFtZXMob3V0X2RmKSA9IGMoImNvbmRpdGlvbiIsICJtb3RpZiIsICJOX3NpZ24iLCAiTl9ucyIsICJOX3NpZ25fbW90aWYiLCAiTl9uc19tb3RpZiIsICJOX21vdGlmIiwgImdyb3VwIiwgIm9kZF9yYXRpbyIsICJwdmFsdWUiKQppID0gMQoKZm9yKGFiX3RwIGluIGFiX3RwX2xpc3QpIHsKICAKICB0ZiA9IFRGc1thYl90cF0KICBwcmludChhYl90cCkKICBjaHRfc2VsID0gY2h0ICU+JSBmaWx0ZXIoY29uZGl0aW9uID09IGFiX3RwKQogIAogICMgYWxsIHNpZ25pZiB2YXJpYW50cyAtIGFsbCwgaW4gYW5kIG91dHNpZGUgcGVha3MKICBOMSA9IGNodF9zZWwgJT4lIGZpbHRlcihzaWduaWZfc3Ryb25nQUkpICU+JSBzZWxlY3Qoc25wX2lkKSAlPiUgdW5pcXVlKCkgJT4lIHRhbGx5KCkgJT4lIHVubGlzdCgpCiAgTjFfYSA9IGNodF9zZWwgJT4lIGZpbHRlcihzaWduaWZfc3Ryb25nQUkgJiBkaXN0MnN1bW1pdCA8IDI1MCkgJT4lIHNlbGVjdChzbnBfaWQpICU+JSB1bmlxdWUoKSAlPiUgdGFsbHkoKSAlPiUgdW5saXN0KCkKICBOMV9iID0gY2h0X3NlbCAlPiUgZmlsdGVyKHNpZ25pZl9zdHJvbmdBSSAmIGRpc3Qyc3VtbWl0ID49IDI1MCkgJT4lIHNlbGVjdChzbnBfaWQpICU+JSB1bmlxdWUoKSAlPiUgdGFsbHkoKSAlPiUgdW5saXN0KCkKICAKICAjIGFsbCBuLnMuIHZhcmlhbnRzIC0gaW4gYW5kIG91dHNpZGUgcGVha3MKICBOMiA9IGNodF9zZWwgJT4lIGZpbHRlcighc2lnbmlmX3N0cm9uZ0FJKSAlPiUgc2VsZWN0KHNucF9pZCkgJT4lIHVuaXF1ZSgpICU+JSB0YWxseSgpICU+JSB1bmxpc3QoKQogIE4yX2EgPSBjaHRfc2VsICU+JSBmaWx0ZXIoIXNpZ25pZl9zdHJvbmdBSSAmIGRpc3Qyc3VtbWl0IDwgMjUwKSAlPiUgc2VsZWN0KHNucF9pZCkgJT4lIHVuaXF1ZSgpICU+JSB0YWxseSgpICU+JSB1bmxpc3QoKQogIE4yX2IgPSBjaHRfc2VsICU+JSBmaWx0ZXIoIXNpZ25pZl9zdHJvbmdBSSAmIGRpc3Qyc3VtbWl0ID49IDI1MCkgJT4lIHNlbGVjdChzbnBfaWQpICU+JSB1bmlxdWUoKSAlPiUgdGFsbHkoKSAlPiUgdW5saXN0KCkKICAKICAKICAjIHZhcmlhbnRzIGluIHRoZSBtb3RpZnMgb2Ygc2VsZWN0ZWQgVEZzCiAgZmltb19zZWxlY3RlZCA9IHBhcnNlX21vdGlmc19pbl90d29fYWxsZWxlcyhhYl90cCwgY2h0X3NlbCwgcmFkaXVzID0gMTUsIHBhdGgyX2Jhc2UxID0gIi9hbGxfdmFyaWFudHNfYWxsZWxlcy9GSU1PLyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXRoMl9iYXNlMiA9ICJjb21iaW5lZF9tb3RpZnMvZmltby50c3YiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBlYWtfcmFkaXVzID0gMjUwLCBzdWJzZXRfbW90aWYgPSBGLCBzdWJzZXRfY2h0ID0gVCkgCiAgCiAgCiAgIyAxLiBFbnJpY2htZW50IGluIGNvZ25hdGUgbW90aWZzCiAgcHJpbnQoIjEuIEVucmljaG1lbnQgaW4gY29nbmF0ZSBtb3RpZnMiKQogICNmaW1vX3NlbCA9IGZpbW9fc2VsZWN0ZWQgJT4lIGZpbHRlcihtb3RpZl9hbHRfaWQgPT0gdGYgJiBzbnBfaWQgJWluJSBjaHRfc2VsJHNucF9pZCkKICBmaW1vX3NlbCA9IGZpbW9fc2VsZWN0ZWQgJT4lIGZpbHRlcihtb3RpZl9hbHRfaWQgPT0gdGYpICAjIGVxdWl2YWxlbnQKICBjb2duYXRlX21vdGlmX2lkcyA9IHVuaXF1ZShmaW1vX3NlbCRzbnBfaWQpCiAgCiAgIyBudW1iZXIgb2Ygc2lnbmlmaWNhbnQgdmFyaWFudHMgaW4gbW90aWZzIC0gYWxsLCBpbiBhbmQgb3V0c2lkZSBwZWFrcwogIE4zID0gZmltb19zZWwgJT4lIGZpbHRlcihzaWduaWZfc3Ryb25nQUkpICU+JSBzZWxlY3Qoc25wX2lkKSAlPiUgdW5pcXVlKCkgJT4lIHRhbGx5KCkgJT4lIHVubGlzdCgpCiAgTjNfYSA9IGZpbW9fc2VsICU+JSBmaWx0ZXIoc2lnbmlmX3N0cm9uZ0FJICYgaW5fcGVhaykgJT4lIHNlbGVjdChzbnBfaWQpICU+JSB1bmlxdWUoKSAlPiUgdGFsbHkoKSAlPiUgdW5saXN0KCkKICBOM19iID0gZmltb19zZWwgJT4lIGZpbHRlcihzaWduaWZfc3Ryb25nQUkgJiAhaW5fcGVhaykgJT4lIHNlbGVjdChzbnBfaWQpICU+JSB1bmlxdWUoKSAlPiUgdGFsbHkoKSAlPiUgdW5saXN0KCkKICAKICAjIG51bWJlciBvZiBuLnMuIHZhcmlhbnRzIGluIG1vdGlmcyAtIGFsbCwgaW4gYW5kIG91dHNpZGUgcGVha3MKICBONCA9IGZpbW9fc2VsICU+JSBmaWx0ZXIoIXNpZ25pZl9zdHJvbmdBSSkgJT4lIHNlbGVjdChzbnBfaWQpICU+JSB1bmlxdWUoKSAlPiUgdGFsbHkoKSAlPiUgdW5saXN0KCkKICBONF9hID0gZmltb19zZWwgJT4lIGZpbHRlcighc2lnbmlmX3N0cm9uZ0FJICYgaW5fcGVhaykgJT4lIHNlbGVjdChzbnBfaWQpICU+JSB1bmlxdWUoKSAlPiUgdGFsbHkoKSAlPiUgdW5saXN0KCkKICBONF9iID0gZmltb19zZWwgJT4lIGZpbHRlcighc2lnbmlmX3N0cm9uZ0FJICYgIWluX3BlYWspICU+JSBzZWxlY3Qoc25wX2lkKSAlPiUgdW5pcXVlKCkgJT4lIHRhbGx5KCkgJT4lIHVubGlzdCgpCiAgCiAgIyBtYXQgPSBtYXRyaXgoYyhOMywgTjQsIE4xLCBOMiksIG5yb3cgPSAyKQogICMgZnQgPSBmaXNoZXIudGVzdChtYXQpCiAgIyBvdXRfZGZbaSwgXSA9IGMoYWJfdHAsIHRmLCBOMSwgTjIsIE4zLCBONCwgTjMgKyBONCwgImFsbCB2YXJpYW50cyIsIGZ0JGVzdGltYXRlLCBmdCRwLnZhbHVlKQogICMgaSA9IGkgKyAxCiAgIyBwcmludCgiMWEuIEFsbCB2YXJpYW50cyIpCiAgIyBwcmludChmdCkKICAKICBtYXQgPSBtYXRyaXgoYyhOM19hLCBONF9hLCBOMV9hLCBOMl9hKSwgbnJvdyA9IDIpCiAgZnQgPSBmaXNoZXIudGVzdChtYXQpCiAgb3V0X2RmW2ksIF0gPSBjKGFiX3RwLCB0ZiwgTjFfYSwgTjJfYSwgTjNfYSwgTjRfYSwgTjNfYSArIE40X2EsICJpbiBwZWFrcyIsIGZ0JGVzdGltYXRlLCBmdCRwLnZhbHVlKQogIGkgPSBpICsgMQogIHByaW50KCIxYi4gVmFyaWFudHMgaW4gcGVha3MiKQogIHByaW50KGZ0KQogIAogIG1hdCA9IG1hdHJpeChjKE4zX2IsIE40X2IsIE4xX2IsIE4yX2IpLCBucm93ID0gMikKICBmdCA9IGZpc2hlci50ZXN0KG1hdCkKICBvdXRfZGZbaSwgXSA9IGMoYWJfdHAsIHRmLCBOMV9iLCBOMl9iLCBOM19iLCBONF9iLCBOM19iICsgTjRfYiwgIm91dHNpZGUgcGVha3MiLCBmdCRlc3RpbWF0ZSwgZnQkcC52YWx1ZSkKICBpID0gaSArIDEKICBwcmludCgiMWMuIFZhcmlhbnRzIG91dHNpZGUgcGVha3MiKQogIHByaW50KGZ0KQoKfQoKCm91dF9kZiRsYWJlbCA9IHJlcChhYl90cF9sYWJlbHMsIGVhY2ggPSAyKQpvdXRfZGYkbGFiZWwgPSBmYWN0b3Iob3V0X2RmJGxhYmVsLCBsZXZlbHMgPSBhYl90cF9sYWJlbHMpCm91dF9kZiRwdmFsdWUgPSBhcy5udW1lcmljKG91dF9kZiRwdmFsdWUpCm91dF9kZiRvZGRfcmF0aW8gPSBhcy5udW1lcmljKG91dF9kZiRvZGRfcmF0aW8pCgoKCnAgPSBnZ3Bsb3Qob3V0X2RmLCBhZXMoeCA9IGxhYmVsLCB5ID0gb2RkX3JhdGlvKSkgKwogIGZhY2V0X3dyYXAofmdyb3VwKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMSwgY29sb3IgPSAiZGFya3JlZCIpICsKICBnZW9tX2JhcihhZXMoZmlsbCA9IC1sb2cxMChwdmFsdWUpKSwgY29sb3IgPSAiZGFya2JsdWUiLCBzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiLCB3aWR0aCA9IDAuNSkgKwogICNzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIiIsIHZhbHVlcyA9IGMoImRhcmtibHVlIiwgImRhcmtncmV5IiksIGxhYmVscyA9IGMoIkFJIHBlYWtzIiwgIm5vbi1BSSBwZWFrcyIpKSArCiAgI2dlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChyMSwgMiksIHggPSBsYWJlbCwgeSA9IG9kZHNfcmF0aW8gKyAwLjA3KSwgZGF0YSA9IGRmLCBzaXplID0gNikgKwogIHlsYWIoIkVucmljaG1lbnQgaW4gY29nbmF0ZSBURiBtb3RpZnMgXG5GaXNoZXIncyBUZXN0IE9kZHMgUmF0aW8iKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIGNvbG91ciA9IFRGY29scyksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwgCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTQpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE0KSkKCgpwCgpvdXRmID0gZmlsZS5wYXRoKG91dGRpcl9maWdfc3VwcGwsIHBhc3RlMCgiRmlnUzRCX21vdGlmc19pbl9wZWFrc19maXNoZXIucGRmIikpCmdnc2F2ZShvdXRmLCBwLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA2KQpgYGAKCgojIEZpZ3VyZSBTNEMgLSBNb3RpZiBwcmVkaWN0aW9uIG9mIEFJCgpgYGB7cn0KCiMgQ29ycmVsYXRpb24gYmV0d2VlbiBBSSBhbmQgZGVsdGFfc2NvcmUKCnNjb3JlX3RocmVzID0gMQpkZl9zaGFyZWQgPSBmaW1vX2FsbGVsZXMgJT4lIGZpbHRlcihpbl9wZWFrICYgIWlzLm5hKHNjb3JlLnJlZikgJiAhaXMubmEoc2NvcmUuYWx0KSkgJT4lCiAgbXV0YXRlKGRlbHRhX3Njb3JlID0gYXMubnVtZXJpYyhzY29yZS5yZWYpIC0gYXMubnVtZXJpYyhzY29yZS5hbHQpLAogICAgICAgICB0eXBlID0gaWZlbHNlKChBSSA+IDAuNSAmIGRlbHRhX3Njb3JlID4gMCkgfCAoQUkgPCAwLjUgJiBkZWx0YV9zY29yZSA8IDApLCAiY29uY29yZGFudCIsICJkaXNjb3JkYW50IikpCgpkZl9zaGFyZWQgJT4lIAogIGdyb3VwX2J5KGNvbmRpdGlvbiwgaXNfaW5kZWwpICU+JSAKICBzdW1tYXJpemUobWluKGFicyhkZWx0YV9zY29yZSkpLCBtYXgoZGlzdDJzdW1taXQpLCBjb3IoZGVsdGFfc2NvcmUsIEFJKSwgc2hhcmVfY29uY29yZGFudCA9IHN1bSh0eXBlID09ICJjb25jb3JkYW50IikgLyBuKCksIG4oKSkKCmRmX3N1bSA9IGRmX3NoYXJlZCAlPiUgZmlsdGVyKGFicyhkZWx0YV9zY29yZSkgPiBzY29yZV90aHJlcyAgJiBkaXN0MnN1bW1pdCA8IDI1MCkgJT4lIAogIHN1bW1hcml6ZShtaW4oYWJzKGRlbHRhX3Njb3JlKSksIG1heChkaXN0MnN1bW1pdCksIGNvciA9IGNvcihkZWx0YV9zY29yZSwgQUkpLCBzaGFyZV9jb25jb3JkYW50ID0gc3VtKHR5cGUgPT0gImNvbmNvcmRhbnQiKSAvIG4oKSwgbigpKQoKY29yID0gcm91bmQoZGZfc3VtJGNvciwgMikKbl9jb25jID0gcm91bmQoZGZfc3VtJHNoYXJlX2NvbmNvcmRhbnQsIDIpICogMTAwCm5fZGlzYyA9ICgxIC0gcm91bmQoZGZfc3VtJHNoYXJlX2NvbmNvcmRhbnQsIDIpKSAqIDEwMAoKCnAgPSBnZ3Bsb3QoZGZfc2hhcmVkICU+JSBmaWx0ZXIoYWJzKGRlbHRhX3Njb3JlKSA+IHNjb3JlX3RocmVzICksIGFlcyh4ID0gZGVsdGFfc2NvcmUsIHkgPSBBSSwgY29sb3IgPSB0eXBlKSkgKyAKICBnZW9tX3BvaW50KHNpemUgPSAxLCBjb2xvciA9IGNiUGFsZXR0ZVsyXSkgKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEYsIGNvbG9yID0gImRhcmtibHVlIiwgc2l6ZSA9IDAuNSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IC1zY29yZV90aHJlcywgY29sb3IgPSAiZ3JleSIsIHNpemUgPSAwLjcpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBzY29yZV90aHJlcywgY29sb3IgPSAiZ3JleSIsIHNpemUgPSAwLjcpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLjUsIGNvbG9yID0gImdyZXkiLCBzaXplID0gMC43KSArCiAgI2dlb21faGxpbmUoeWludGVyY2VwdCA9IDAuNCwgY29sb3IgPSAiZ3JleSIsIHNpemUgPSAwLjcpICsKICB0aGVtZV9idygpICsKICBhbm5vdGF0ZShnZW9tID0gInRleHQiLCB4ID0gLTMuNSwgeSA9IDAuOTUsIGxhYmVsID0gcGFzdGUoIlI9IiwgY29yKSkgKwogIGFubm90YXRlKGdlb20gPSAidGV4dCIsIHggPSAtMy41LCB5ID0gMC44OCwgbGFiZWwgPSBwYXN0ZSgiJSBjb25jb3JkYW50OiAiLCBuX2NvbmMpLCBzaXplID0gNCkgKwogIHhsYWIoIk1vdGlmIHNjb3JlIGNoYW5nZSAoUkVGLUFMVCkiKSArCiAgeWxhYigiQWxsZWxlIEltYmFsYW1jZSIpICsKICAjc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoY2JQYWxldHRlWzJdLCAiZGFya2dyZXkiKSwgbGFiZWxzID0gYyhwYXN0ZTAoImNvbmNvcmRhbnQsICIsIG5fY29uYywgIiUiKSwgcGFzdGUwKCJkaXNjb3JkYW50LCAiLCBuX2Rpc2MsICIlIikpLCBuYW1lID0gIlZhcmlhbnQgdHlwZSIpICsKICB0aGVtZShheGlzLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTIpLAogICAgICAgIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTQpLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTIpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSkKCgpwCm91dGYgPSBmaWxlLnBhdGgob3V0ZGlyX2ZpZ19zdXBwbCwgcGFzdGUwKCJGaWdTNENfbW90aWZzX0FJX3ByZWRpY3Rpb24ucGRmIikpCmdnc2F2ZShvdXRmLCBwLCB3aWR0aCA9IDQsIGhlaWdodCA9IDQpCgpgYGAKCgoKIyBGaWd1cmUgUzREIC0gUHJvQm91bmQgc2NvcmVzIG9uIEFJIGFuZCBub24tQUkgdmFyaWFudHMKCmBgYHtyfQpQcm9Cb3VuZF9DVENGID0gcmVhZC50YWJsZSgiL2cvZnVybG9uZy9wcm9qZWN0LzY4X0YxX2Npc3JlZ19pY2hpcC9hbmFseXNpcy9Qcm9Cb3VuZC9Qcm9Cb3VuZF9DVENGX1JFRl9zZXF1ZW5jZV8xNWJwX2Fyb3VuZF92YXJpYW50cy50eHQiLCBoZWFkZXI9VFJVRSkKUHJvQm91bmRfQ1RDRiRURiA9ICJDVENGIgpQcm9Cb3VuZF9CaW4gPSByZWFkLnRhYmxlKCIvZy9mdXJsb25nL3Byb2plY3QvNjhfRjFfY2lzcmVnX2ljaGlwL2FuYWx5c2lzL1Byb0JvdW5kL1Byb0JvdW5kX0Jpbl9SRUZfc2VxdWVuY2VfMTVicF9hcm91bmRfdmFyaWFudHMudHh0IiwgaGVhZGVyPVRSVUUpClByb0JvdW5kX0JpbiRURiA9ICJCaW4iClByb0JvdW5kX01lZjIgPSByZWFkLnRhYmxlKCIvZy9mdXJsb25nL3Byb2plY3QvNjhfRjFfY2lzcmVnX2ljaGlwL2FuYWx5c2lzL1Byb0JvdW5kL1Byb0JvdW5kX01lZjJfUkVGX3NlcXVlbmNlXzE1YnBfYXJvdW5kX3ZhcmlhbnRzLnR4dCIsIGhlYWRlcj1UUlVFKQpQcm9Cb3VuZF9NZWYyJFRGID0gIk1lZjIiClByb0JvdW5kX1R3aSA9IHJlYWQudGFibGUoIi9nL2Z1cmxvbmcvcHJvamVjdC82OF9GMV9jaXNyZWdfaWNoaXAvYW5hbHlzaXMvUHJvQm91bmQvUHJvQm91bmRfVHdpX1JFRl9zZXF1ZW5jZV8xNWJwX2Fyb3VuZF92YXJpYW50cy50eHQiLCBoZWFkZXI9VFJVRSkKUHJvQm91bmRfVHdpJFRGID0gIlR3aSIKClByb0JvdW5kX3Jlc3VsdHNfUkVGID0gcmJpbmQoUHJvQm91bmRfQ1RDRiwgUHJvQm91bmRfQmluLCBQcm9Cb3VuZF9NZWYyLCBQcm9Cb3VuZF9Ud2kpCmNvbG5hbWVzKFByb0JvdW5kX3Jlc3VsdHNfUkVGKSA9IGMoInZhcmlhbnRfY2hyIiwgInZhcmlhbnRfcG9zIiwgIlJFRiIsICJBTFQiLCAiUHJvQm91bmRfYmVkX1JFRiIsICJQcm9Cb3VuZF9zZXFfUkVGIiwgIlByb0JvdW5kX3Njb3JlX1JFRiIsICJURiIpClByb0JvdW5kX3Jlc3VsdHNfUkVGID0gUHJvQm91bmRfcmVzdWx0c19SRUYgJT4lCiAgICAgICAgZ3JvdXBfYnkoVEYpICU+JQogICAgICAgIG11dGF0ZShQcm9Cb3VuZF9zY29yZV9zY2FsZWRfUkVGID0gUHJvQm91bmRfc2NvcmVfUkVGIC8gbWF4KFByb0JvdW5kX3Njb3JlX1JFRikpCgoKUHJvQm91bmRfQUxUX0NUQ0YgPSByZWFkLnRhYmxlKCIvZy9mdXJsb25nL3Byb2plY3QvNjhfRjFfY2lzcmVnX2ljaGlwL2FuYWx5c2lzL1Byb0JvdW5kL1Byb0JvdW5kX0NUQ0ZfQUxUX3NlcXVlbmNlXzE1YnBfYXJvdW5kX3ZhcmlhbnRzLnR4dCIsIGhlYWRlcj1UUlVFKQpQcm9Cb3VuZF9BTFRfQ1RDRiRURiA9ICJDVENGIgpQcm9Cb3VuZF9BTFRfQmluID0gcmVhZC50YWJsZSgiL2cvZnVybG9uZy9wcm9qZWN0LzY4X0YxX2Npc3JlZ19pY2hpcC9hbmFseXNpcy9Qcm9Cb3VuZC9Qcm9Cb3VuZF9CaW5fQUxUX3NlcXVlbmNlXzE1YnBfYXJvdW5kX3ZhcmlhbnRzLnR4dCIsIGhlYWRlcj1UUlVFKQpQcm9Cb3VuZF9BTFRfQmluJFRGID0gIkJpbiIKUHJvQm91bmRfQUxUX01lZjIgPSByZWFkLnRhYmxlKCIvZy9mdXJsb25nL3Byb2plY3QvNjhfRjFfY2lzcmVnX2ljaGlwL2FuYWx5c2lzL1Byb0JvdW5kL1Byb0JvdW5kX01lZjJfQUxUX3NlcXVlbmNlXzE1YnBfYXJvdW5kX3ZhcmlhbnRzLnR4dCIsIGhlYWRlcj1UUlVFKQpQcm9Cb3VuZF9BTFRfTWVmMiRURiA9ICJNZWYyIgpQcm9Cb3VuZF9BTFRfVHdpID0gcmVhZC50YWJsZSgiL2cvZnVybG9uZy9wcm9qZWN0LzY4X0YxX2Npc3JlZ19pY2hpcC9hbmFseXNpcy9Qcm9Cb3VuZC9Qcm9Cb3VuZF9Ud2lfQUxUX3NlcXVlbmNlXzE1YnBfYXJvdW5kX3ZhcmlhbnRzLnR4dCIsIGhlYWRlcj1UUlVFKQpQcm9Cb3VuZF9BTFRfVHdpJFRGID0gIlR3aSIKClByb0JvdW5kX3Jlc3VsdHNfQUxUID0gcmJpbmQoUHJvQm91bmRfQUxUX0NUQ0YsIFByb0JvdW5kX0FMVF9CaW4sIFByb0JvdW5kX0FMVF9NZWYyLCBQcm9Cb3VuZF9BTFRfVHdpKQpjb2xuYW1lcyhQcm9Cb3VuZF9yZXN1bHRzX0FMVCkgPSBjKCJ2YXJpYW50X2NociIsICJ2YXJpYW50X3BvcyIsICJSRUYiLCAiQUxUIiwgIlByb0JvdW5kX2JlZF9BTFQiLCAiUHJvQm91bmRfc2VxX0FMVCIsICJQcm9Cb3VuZF9zY29yZV9BTFQiLCAiVEYiKQpQcm9Cb3VuZF9yZXN1bHRzX0FMVCA9IFByb0JvdW5kX3Jlc3VsdHNfQUxUICU+JQogICAgICAgIGdyb3VwX2J5KFRGKSAlPiUKICAgICAgICBtdXRhdGUoUHJvQm91bmRfc2NvcmVfc2NhbGVkX0FMVCA9IFByb0JvdW5kX3Njb3JlX0FMVCAvIG1heChQcm9Cb3VuZF9zY29yZV9BTFQpKQoKClByb0JvdW5kX3Jlc3VsdHMgPSBtZXJnZShQcm9Cb3VuZF9yZXN1bHRzX1JFRiwgUHJvQm91bmRfcmVzdWx0c19BTFQsIGJ5ID0gYygidmFyaWFudF9jaHIiLCAidmFyaWFudF9wb3MiLCAiUkVGIiwgIkFMVCIsICJURiIpLCBhbGwueD1UUlVFKQpQcm9Cb3VuZF9yZXN1bHRzJHZhcmlhbnRfSUQgPSBwYXN0ZShQcm9Cb3VuZF9yZXN1bHRzJHZhcmlhbnRfY2hyLCBQcm9Cb3VuZF9yZXN1bHRzJHZhcmlhbnRfcG9zLCBQcm9Cb3VuZF9yZXN1bHRzJFRGLCBzZXA9Il8iKQpQcm9Cb3VuZF9yZXN1bHRzJFByb0JvdW5kX3Njb3JlX21heCA9IHBtYXgoUHJvQm91bmRfcmVzdWx0cyRQcm9Cb3VuZF9zY29yZV9BTFQsIFByb0JvdW5kX3Jlc3VsdHMkUHJvQm91bmRfc2NvcmVfUkVGKQoKCmNodCR2YXJpYW50X0lEID0gcGFzdGUoY2h0JHNucF9pZCwgY2h0JGFiLCBzZXA9Il8iKQpjaHRfUHJvQm91bmQgPSBtZXJnZShjaHQsIFByb0JvdW5kX3Jlc3VsdHMsIGJ5PSJ2YXJpYW50X0lEIikKY2h0X1Byb0JvdW5kJHNpZ25pZl9zdHJvbmdBSSA9IGZhY3RvcihjaHRfUHJvQm91bmQkc2lnbmlmX3N0cm9uZ0FJLCBsZXZlbHM9YyhUUlVFLCBGQUxTRSkpCgoKcCA9IGdncGxvdChjaHRfUHJvQm91bmQsIGFlcyh4PXNpZ25pZl9zdHJvbmdBSSwgeT1Qcm9Cb3VuZF9zY29yZV9tYXgsIGZpbGw9c2lnbmlmX3N0cm9uZ0FJKSkgKyAKICAgICAgZmFjZXRfd3JhcCh+Y29uZGl0aW9uKSArCiAgICAgIGdlb21fdmlvbGluKGZpbGwgPSAiZGFya2JsdWUiLCBhbHBoYSA9IDAuMykgKwogICAgICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjQsIG91dGxpZXIuc2l6ZSA9IDAuMSwgZmlsbCA9ICJkYXJrYmx1ZSIsIGFscGhhID0gMC41KSArCiAgICAgIHNjYWxlX3lfbG9nMTAoKSArIAogICAgICBzdGF0X2NvbXBhcmVfbWVhbnMobWV0aG9kID0gIndpbGNveCIpICsKICAgICAgeGxhYigiU2lnbmlmaWNhbnQgYWxsZWxpYyBpbWJhbGFuY2UiKSArCiAgICAgIHlsYWIoIi1sb2coMTApIFByb0JvdW5kIHNzY2FsZWQgY29yZSIpICsKICAgICAgdGhlbWVfYncoKSArCiAgICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemU9MTApLCBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSwgCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemU9MTApLCBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCksCiAgICAgICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksIHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpCm91dGYgPSBmaWxlLnBhdGgob3V0ZGlyX2ZpZ19zdXBwbCwgcGFzdGUwKCJGaWdTNERfUHJvQm91bmRfbWF4X3Njb3Jlc19vbl9BSV92YXJpYW50cy5wZGYiKSkKZ2dzYXZlKG91dGYsIHAsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNCkKYGBgCg==