Correlation between different sequencing methods

Using insertions per gene

get_ipg = function(x, ver){
  data = read_tsv(paste0(data_dir, "/hpc_output/",ver, "/", x), 
                  col_types = cols(CDS=col_character(),`#insertion` = col_double())) %>%
    mutate(sample = str_sub(x, 1, -22), gene=NA,
           run=ver)
}
ipg_forcor = NULL
for(i in seq_runs) {
  ipg_files = list.files(path = paste0(data_dir, "/hpc_output/", i, "/"), pattern = '*insertionPerGene.txt')
  ipg_t = map(ipg_files, get_ipg, ver=i)
  ipg_df_t = do.call(rbind, ipg_t)
  ipg_forcor = ipg_forcor %>% 
    bind_rows(ipg_df_t %>% unite(sample_rep, sample, run))
}
# get correlations
ipg_forcor = ipg_forcor %>%
  mutate(strain = str_sub(sample_rep, 1, -6),
         rep = str_sub(sample_rep, -4, -1)) %>%
  left_join(strain_names) %>%
  unite(sample_rep, strain_names, rep) %>%
  dplyr::select(CDS, sample_rep, `#insertion`) %>% 
  pivot_wider(names_from = sample_rep, values_from = `#insertion`) 


reps = ipg_forcor %>%
    dplyr::select(eu_1_nyc1, eu_1_nyc2, eu_2_nyc1, eu_2_nyc2)  
cor_plots=GGally::ggpairs(reps, 
                upper = list(continuous = GGally::wrap("cor", method = "pearson"))) +
    ggtitle(LETTERS[1])
ggsave(cor_plots, file=paste0(fig_dir, "/SFigX", LETTERS[1], ".pdf"), height = 10, width = 10)

i=2
for(strain in c("aneu", "trip1", "trip2", "trip3", "trip4", "iso", "quad")) {
  reps = ipg_forcor %>%
    dplyr::select(colnames(ipg_forcor)[str_detect(colnames(ipg_forcor), strain)])  
  cor_plots=GGally::ggpairs(reps, 
                upper = list(continuous = GGally::wrap("cor", method = "pearson"))) +
    ggtitle(LETTERS[i])
  ggsave(cor_plots, file=paste0(fig_dir, "/SFigX", LETTERS[i], ".pdf"), height = 10, width = 10)
  i=i+1
}
# number of insertion sites scales with total reads generated
reads_per_lib = read_csv(paste0(data_dir,"/total_reads_per_library.csv"))

sfig2 = reads_per_lib %>%
  left_join(summary_rpp, by = c("Sample"="Gresham_ID")) %>%
  ggplot(aes(total_sites, reads, color = strain_names)) +
  geom_point(size=2) +
  scale_color_manual(values = strain_cols) +
  xlab("Unique insertion sites") +
  ylab("Total reads ") +
  scale_y_continuous(labels = scales::comma) +
  scale_x_continuous(labels = scales::comma) +
  theme(legend.title=element_blank())

ggsave(paste0(fig_dir,"/SFig2.pdf"), plot = sfig2, width = 8.5, height = 5, units = "in")
ggsave(paste0(fig_dir,"/SFig2.png"), plot = sfig2, width = 8.5, height = 5, units = "in")

Patterns of transposon insertion density remain a reliable predictor of sequence tolerance to disruptive mutation in CNV strains

# essential genes have fewer insertions
get_cds_promoter = function(x, y){
  y = y %>% dplyr::filter(str_starts(X9, paste0(x, ';')))
  if(nrow(y) > 1) {
    y$X4 = min(y$X4)
    y$X5 = max(y$X5)
  }
  chromosome = y$X1
  strand = y$X7
  if(strand[1] == '+') {
    start = y$X4
    stop = y$X5
    promoter = y$X4 - 200
  } else {
    start = y$X5
    stop = y$X4
    promoter = y$X5 + 200
  }
  return(tibble(chromosome, start, stop, promoter, strand)[1,])
}
# x is a gene that I want to get info for (in "ID=cds0" form), inserts is the reads per position file 
# will return for each sample in inserts
get_binned_unique_insertions = function(x, inserts){
  y = get_cds_promoter(x, y = gff_cds)
  bin_size_cds = (y$start - y$stop)/100
  cds=NULL
  promo=NULL
  for(i in unique(inserts$sample)) {
    bin_fill_cds = NULL
    bin_fill_prom = NULL
    ini = inserts %>% dplyr::filter(sample == i, chromosome == y$chromosome)
    if(y$strand == '+') {
      for(j in 1:100) {
        bin_fill_cds[j] = nrow(ini %>% 
                         dplyr::filter(chr_pos >= y$start+bin_size_cds*(j-1) &
                                         chr_pos < y$start+bin_size_cds*j & 
                                         chr_pos <= y$stop))
        bin_fill_prom[j] = nrow(ini %>% dplyr::filter(chr_pos >= y$promoter+2*(j-1) &
                                                        chr_pos <= y$promoter+2*j &
                                                        chr_pos < y$start))
      }
    } else {
      for(j in 1:100) {
        bin_fill_cds[j] = nrow(ini %>% 
                         dplyr::filter(chr_pos <= y$start-bin_size_cds*(j-1) &
                                         chr_pos > y$start-bin_size_cds*j & 
                                         chr_pos >= y$stop))
        bin_fill_prom[j] = nrow(ini %>% dplyr::filter(chr_pos <= y$promoter-2*(j-1) &
                                                        chr_pos >= y$promoter-2*j &
                                                        chr_pos > y$start))
      }
    }
    names(bin_fill_cds) = 1:100
    names(bin_fill_prom) = 1:100
    cds = cds %>% bind_rows(c(type = "cds", id=x, sample=i, bin_fill_cds))
    promo = promo %>% bind_rows(c(type= "promoter",id=x, sample=i, bin_fill_prom))
  }
  bind_rows(cds, promo)
}

binned_inserts = do.call(rbind, map(all_genes$X1, get_binned_unique_insertions, inserts = rpp_df))

#write_csv(binned_inserts, "./binned_inserts_temp.csv")
#read_csv("./binned_inserts_temp.csv")

yeast_r64_to_systematic <- function(name_vec) {
  translated_names <- match(name_vec, labtools::yeast_gene_names$GCF_000146045.2_R64_genomic_ID, nomatch=NA)
  translated_names <- labtools::yeast_gene_names[translated_names, "Systematic_name"]
  no_translation <- is.na(translated_names)
  translated_names[no_translation] <- name_vec[no_translation]
  return(translated_names)
}

t$gene = yeast_r64_to_systematic(t$id)

# get list of essential genes from Winzeler 1999
ess_del = read_tsv(paste0(data_dir,'/Essential_ORFs.txt'), col_names = T, comment = '=', col_types = cols(
  rec_num = col_double(),
  ORF_name = col_character(),
  deletion_alias = col_character(),
  gene_names = col_character(),
  UPTAG_sequence_20mer = col_character(),
  DNTAG_sequence_20mer = col_character()
)) %>%
  dplyr::select(ORF_name) %>% dplyr::rename(gene=ORF_name) %>%
  mutate(ess_del = "yes")

# get gene fitness in ypgal from costanzo et al 2021
fit_gal = read_csv(paste0(data_dir, "/Costanzo_Mutant Fitness_Conditions-Table 1.csv"), col_names = T) %>%
  select(`Systematic Name`, `Gene Name`, `Allele (Essential genes only)`, `Galactose`) %>%
  mutate(quartile = case_when(Galactose <= quantile(Galactose, na.rm=T)[2] ~ "Q1",
                              Galactose <= quantile(Galactose, na.rm=T)[3] ~ "Q2",
                              Galactose <= quantile(Galactose, na.rm=T)[4] ~ "Q3",
                              Galactose <= quantile(Galactose, na.rm=T)[5] ~ "Q4",))

binned_inserts = binned_inserts %>% 
  mutate(essential = dplyr::if_else(`gene` %in% ess_del$gene, 'yes', 'no')) %>% 
  left_join(fit_gal %>% select(`Systematic Name`, quartile), by=c("gene" = "Systematic Name")) %>%
  pivot_longer(cols=c(-gene, -essential, -type, -id, -sample), 
               names_to = "bin", values_to = "inserts_per_bin") %>%
  mutate_at(c('bin', 'inserts_per_bin'), as.numeric)


meta_bin_insert_essential = binned_inserts %>% 
  group_by_at(vars(sample, type, essential, bin)) %>%
  mutate(total_inserts_bin = sum(inserts_per_bin), 
         mean_inserts_bin = mean(inserts_per_bin),
         median_inserts_bin = median(inserts_per_bin),
         ngene_norm_total_inserts_bin = dplyr::if_else(essential == 'yes', sum(inserts_per_bin)/nrow(ess_del), sum(inserts_per_bin)/(nrow(all_genes) - nrow(ess_del)))) %>%
  dplyr::select(sample, type, essential, bin, total_inserts_bin, mean_inserts_bin, median_inserts_bin, ngene_norm_total_inserts_bin) %>% distinct()

meta_bin_insert_essential$type_order = factor(meta_bin_insert_essential$type,
                                    levels=c('promoter', 'cds'))

sfig3a = ggplot(meta_bin_insert_essential %>% 
         filter(type == 'cds') %>%
           mutate(strain_names_rep = case_when(sample == "1657_1" ~ "eu_1",
                                      sample == "1657_2" ~ "eu_2",
                                      sample == "1728" ~ "aneu",
                                      sample == "1734" ~ "trip1",
                                      sample == "1747" ~ "trip2",
                                      sample == "1751" ~ "trip3",
                                      sample == "1736" ~ "trip4",
                                      sample == "1744" ~ "iso",
                                      sample == "1740" ~ "quad"
                                      )) , 
       aes(bin, ngene_norm_total_inserts_bin, color = essential)) +
  geom_line() +
  #theme_minimal() +
  facet_wrap(~strain_names_rep) +
  scale_color_manual(values=c('#80b1d3', '#fb8072'),
                     name = "", labels = c("Non-essential", "Essential")) +
  xlab('% of CDS') +
  ylab('Mean unique insertion sites')

sfig3b=binned_inserts %>% 
  ungroup() %>%
  filter(type=="cds") %>%
  group_by_at(vars(sample, type, quartile, bin)) %>%
  mutate(total_inserts_bin = sum(inserts_per_bin), 
         mean_inserts_bin = mean(inserts_per_bin),
         median_inserts_bin = median(inserts_per_bin)) %>%
  dplyr::select(sample, type, essential, bin, total_inserts_bin, mean_inserts_bin, median_inserts_bin, quartile) %>%
  distinct() %>%
  mutate(strain_names_rep = case_when(sample == "1657_1" ~ "eu_1",
                                      sample == "1657_2" ~ "eu_2",
                                      sample == "1728" ~ "aneu",
                                      sample == "1734" ~ "trip1",
                                      sample == "1747" ~ "trip2",
                                      sample == "1751" ~ "trip3",
                                      sample == "1736" ~ "trip4",
                                      sample == "1744" ~ "iso",
                                      sample == "1740" ~ "quad"
                                      )) %>%
  ggplot(aes(bin, mean_inserts_bin, color = quartile)) +
  geom_line() +
  #theme_minimal() +
  facet_wrap(~strain_names_rep) +
  #scale_color_manual(values=c('#80b1d3', '#fb8072'),
   #                  name = "", labels = c("Non-essential", "Essential")) +
  xlab('% of CDS') +
  ylab('Mean unique insertion sites')

quantile(fit_gal$Galactose, na.rm=T)

layout <- "
A
B
"

sfig3=sfig3a + sfig3b + plot_layout(design = layout) + plot_annotation(tag_levels = 'A')

ggsave(paste0(fig_dir,"/SFig3.pdf"), plot = sfig3, width = 12, height = 16, units = "in")
ggsave(paste0(fig_dir,"/SFig3.png"), plot = sfig3, width = 12, height = 16, units = "in")

Get insertion profiles

#get insertion profiles for all genes
insert_profiles = map(all_genes_systematic, get_insert_profile, data = rpp_df)
insert_profiles = do.call(rbind, insert_profiles)

# add in zero categories
t=insert_profiles %>% right_join(tibble(all_genes_systematic), by= c("gene"="all_genes_systematic")) %>%
  mutate_at(vars(sample, gene, type), factor) 
t=t %>% 
  tidyr::expand(sample, gene, type)
insert_profiles = insert_profiles %>% #filter(!is.na(sample)) %>% 
  right_join(t) %>%
  mutate(n_insertions = replace_na(n_insertions, 0), normalized_insertions = replace_na(normalized_insertions, 0)) %>%
  distinct()

# write out so this doesn't need to be done again
write_csv(insert_profiles, paste0(data_dir,"/insertion_profiles.csv"))

Look at genes in CNV region

cnv_genes = strain_cns %>% filter(copy_number >= 2) %>% rename(sample = strain)
sfigq_sig = inserts_per_mill_cds %>% 
  left_join(ess_del) %>%
  filter(str_starts(gene, "YK")) %>%
  anti_join(cnv_genes) %>%
  left_join(strain_names) %>%
  group_by(sample) %>% 
  mutate(ess_del = if_else(is.na(ess_del), "not essential", ess_del)) %>% 
  rstatix::t_test(inserts_per_mill ~ ess_del) %>%
  ungroup() %>%
  mutate(significance = case_when(p <= 0.0001 ~ "****",
                                  p > 0.01 ~ "ns"))

sfig4a = inserts_per_mill_cds %>% 
  left_join(ess_del) %>%
  filter(str_starts(gene, "YK")) %>%
  anti_join(cnv_genes) %>%
  group_by(sample) %>% 
  mutate(ess_del = if_else(is.na(ess_del), "not essential", ess_del)) %>%
  ggplot(aes(strain_names, inserts_per_mill, color = ess_del)) +
  ylab("Normalized insertions") +
  xlab("") +
  geom_point(alpha=0.7, size=1, cex = 0.7, position=position_jitterdodge()) +
  geom_boxplot(outlier.shape = NA, alpha=0, lwd=1) +
  scale_color_manual(values=c('#80b1d3', '#fb8072'),
                     name = "", labels = c("Non-essential", "Essential")) +
  stat_pvalue_manual(
    sfigq_sig %>% rstatix::add_xy_position(x = "sample"), 
    y.position = 1500,
    label = "significance"
    ) +
  theme(legend.background = element_rect(fill="transparent"),
        legend.position=c(.85,.73)) 

sfig4a
# euploid insertion number predicts cnv insertion number
tt = t %>% mutate(common_name = labtools::yeast_systematic_to_common(gene), mean1657 = (`1657_1`+`1657_2`)/2) %>%
  pivot_longer(cols = starts_with("1"), names_to = "strain", values_to = "inserts_per_mill")

amp_regress = NULL
high_resids = NULL
for(samp in unique(tt$strain)) {
  tx = tt %>% filter(strain == samp) %>%
    filter(!is.na(inserts_per_mill))
  fit=lm(tx$inserts_per_mill~tx$mean1657)
  intercept = fit$coefficients[1]
  intercept_pval = summary(fit)$coefficients[,4][1]
  slope = fit$coefficients[2]
  slope_ci2.5 = confint(fit, 2, level=0.95)[1]
  slope_ci97.5 = confint(fit, 2, level=0.95)[2]
  slope_pval = summary(fit)$coefficients[,4][2]
  adjr2 = summary(fit)$adj.r.squared
  resid_sd = sigma(fit)
  n_greater2sigma = sum(abs(fit$residuals) > mean(fit$residuals) + resid_sd*2)
  n_amp_genes = tx$common_name[abs(fit$residuals) > mean(fit$residuals) + resid_sd*2]
  high_resids = high_resids %>% bind_rows(tibble(strain = samp, common_name = n_amp_genes, high_resid = "yes"))
  amp_regress = amp_regress %>% bind_rows(tibble(samp, intercept, intercept_pval, slope, slope_pval, slope_ci2.5, slope_ci97.5, adjr2, resid_sd, n_greater2sigma))
}

f2c = tt %>% left_join(high_resids) %>% 
  mutate(label = if_else(is.na(high_resid), "",common_name)) %>%
  left_join(strain_names) %>%
  filter(strain != "1657_1", strain != "1657_2") %>%
  filter(!is.na(inserts_per_mill), mean1657 < 750) %>%
  ggplot(aes(mean1657, inserts_per_mill, label=label)) +
  #ggiraph::geom_point_interactive(aes(data_id = common_name, tooltip = common_name), alpha = 0.5) +
     geom_smooth(method = 'lm', se=FALSE, color="black") +
  geom_point(aes(color = high_resid),alpha=0.5) +
     ggrepel::geom_text_repel(box.padding = 0.5, size = 3.5, segment.size = 0.2, color = "black",max.overlaps=100) +
     facet_wrap(~strain_names, ncol = 1) +
     theme_bw(base_size=16) +
     theme(legend.position = "none") +
  ylab("CNV strain normalized insertions") +
  xlab("Euploid normalized insertions") +
  geom_text(data = amp_regress %>%
               left_join(strain_names, by=c("samp" = "strain")) %>%
               filter(samp != "1657_1", samp != "1657_2"), 
             aes(335, 1000, label = paste("Adj R2 = ", round(adjr2,2), "\n",
                                    "Slope =", round(slope,2), "\n")),
             size=4) +
  ggtitle("C")
  
ggsave(paste0(fig_dir,"/Fig2B.pdf"), plot = f2b, width = 12, height = 8, units = "in")
ggsave(paste0(fig_dir,"/Fig2C.pdf"), plot = f2c, width = 6, height = 14, units = "in")
ggsave(paste0(fig_dir,"/Fig2B.png"), plot = f2b, width = 12, height = 8, units = "in")
ggsave(paste0(fig_dir,"/Fig2C.png"), plot = f2c, width = 6, height = 14, units = "in")
# non-amplified genes
tempo = inserts_per_mill_cds %>% 
  select(strain_names, inserts_per_mill, gene) %>%
  anti_join(cnv_genes %>% select(gene, strain_names)) %>%
  pivot_wider(names_from = "strain_names", values_from = "inserts_per_mill") %>%
  mutate(mean1657 = (eu_1 + eu_2)/2) %>%
  pivot_longer(cols=c(aneu, trip1, trip2, trip3, trip4, iso, quad), names_to="strain", values_to = "inserts_per_mill")

amp_regress = NULL
for(samp in unique(tempo$strain)) {
  tx = tempo %>% filter(strain == samp) %>%
    filter(!is.na(inserts_per_mill))
  fit=lm(tx$inserts_per_mill~tx$mean1657)
  intercept = fit$coefficients[1]
  intercept_pval = summary(fit)$coefficients[,4][1]
  slope = fit$coefficients[2]
  slope_ci2.5 = confint(fit, 2, level=0.95)[1]
  slope_ci97.5 = confint(fit, 2, level=0.95)[2]
  slope_pval = summary(fit)$coefficients[,4][2]
  adjr2 = summary(fit)$adj.r.squared
  resid_sd = sigma(fit)
  n_greater2sigma = sum(abs(fit$residuals) > mean(fit$residuals) + resid_sd*2)
  n_amp_genes = tx$common_name[abs(fit$residuals) > mean(fit$residuals) + resid_sd*2]
  amp_regress = amp_regress %>% bind_rows(tibble(samp, intercept, intercept_pval, slope, slope_pval, slope_ci2.5, slope_ci97.5, adjr2, resid_sd, n_greater2sigma))
}

sfig4b = tempo %>% 
  #left_join(strain_names) %>%
  #filter(strain != "1657_1", strain != "1657_2") %>%
  #filter(!is.na(inserts_per_mill), mean1657 < 750) %>%
  ggplot(aes(mean1657, inserts_per_mill)) +
  #ggiraph::geom_point_interactive(aes(data_id = common_name, tooltip = common_name), alpha = 0.5) +
  geom_smooth(method = 'lm', se=FALSE, color="black") +
  geom_point(alpha=0.5) +
     facet_wrap(~strain) +
     theme_bw(base_size=16) +
     theme(legend.position = "none") +
  ylab("CNV strain normalized insertions") +
  xlab("Euploid normalized insertions") +
  geom_text(data = amp_regress %>% rename(strain = samp), 
             aes(150, 1500, label = paste("Adj R2 = ", round(adjr2,2), "\n",
                                    "Slope =", round(slope,2), "\n")),
             size=4) +
  ggtitle("B")
layout <- "
ABB
"
sfig4=sfig4a + sfig4b + plot_layout(design = layout)

ggsave(paste0(fig_dir,"/SFig4.png"), plot = sfig4, width = 20, height = 10, units = "in")
ggsave(paste0(fig_dir,"/SFig4.pdf"), plot = sfig4, width = 20, height = 10, units = "in")

Genes with no insertions in euploid, insertions in all CNV (and vice versa)

x = inserts_per_mill_cds %>% filter(sample %in% c("1657_1", "1657_2")) %>%
  group_by(gene) %>%
  summarise(n_ins = sum(inserts)) %>% filter(n_ins == 0)
stab2 = x %>% left_join(ess_del) %>%
  left_join(fit_gal, by = c("gene" = "Systematic Name")) %>%
  mutate(low_fitness_gal = if_else(Galactose < 1, "low fitness galactose", ""))

stab2 %>% 
  summarise(n = n(),
            n_ess = sum(!is.na(ess_del)),
            n_lowfit_gal = sum(Galactose < 1 & !is.na(Galactose)),
            n_notess = sum(is.na(ess_del)),
            n_not_gal = n()-sum(Galactose < 1 & !is.na(Galactose)),
            n_ess_or_lowfitgal = sum(!is.na(ess_del) | (Galactose < 1 & !is.na(Galactose))))

write_csv(stab2 %>% 
            select(gene, `Gene Name`, ess_del, Galactose, low_fitness_gal), paste0(fig_dir, "/SupplementaryTable2.csv"))
# check all that have inserts
f3a=inserts_per_mill_cds %>% 
  mutate(median_inserts_per_mill = median(inserts_per_mill)) %>%
  filter(gene %in% pull(x,gene)) %>%
  group_by(gene) %>%
  filter(!(sample %in% c("1657_1", "1657_2"))) %>%
  mutate(all_strains = sum(inserts)) %>%
  filter(all_strains > 0) %>%
  mutate(all_g0 = all(inserts > 0)) %>%
  filter(all_g0 == T) %>%
  ungroup() %>%
  left_join(cnv_genes) %>%
  mutate(common_name = labtools::yeast_systematic_to_common(gene)) %>%
  filter(!is.na(common_name)) %>%
  ggplot(aes(common_name, inserts_per_mill, fill = strain_names)) +
  geom_bar(stat = "identity", position = "dodge", width = 0.8) +
  scale_fill_manual(values = strain_cols[4:10]) +
  geom_abline(aes(intercept = median_inserts_per_mill, slope=0),
                color="azure4", size=0.75) +
  geom_text(aes(label = copy_number, x = common_name, y = inserts_per_mill), 
            position = position_dodge(width = 0.8), vjust = -0.6, size=5.5) +
  ylab("Insertions per million") +
  theme(legend.title=element_blank()) +
  xlab("")
  

ggsave(paste0(fig_dir,"/Fig3a.pdf"), plot = f3a, width = 12, height = 6.5, units = "in")
### Find genes that have insertions in both replicates of 1657
x = pull(inserts_per_mill_cds %>% filter(sample %in% c("1657_1", "1657_2")) %>%
  group_by(gene) %>%
    mutate(one = case_when(sample == "1657_1" & inserts > 0 ~ "yes",
                           sample == "1657_2" & inserts > 0 ~ "yes")) %>%
  summarise(n_ins = sum(one == "yes")) %>% filter(n_ins == 2), gene)

# check all that have inserts
inserts_per_mill_cds %>% 
  filter(gene %in% x) %>%
  group_by(gene) %>%
  filter(!(sample %in% c("1657_1", "1657_2"))) %>%
  mutate(all_strains = sum(inserts)) %>%
  filter(all_strains == 0) %>%
  ungroup() #%>%

Differential analysis with DESeq

count_df_cds = insert_profiles %>%
  filter(type == "cds") %>%
  select(gene, n_insertions, sample) %>%
  pivot_wider(names_from = "sample", values_from = "n_insertions")
# first all cds
diff_analysis_cds = NULL
gsea_cds=NULL

for(strain in c("1728", "1734", "1736", "1740", "1744", "1747", "1751")) {
  counts = as.data.frame(count_df_cds) %>% dplyr::select(`1657_1`, `1657_2`, strain)
  rownames(counts) = count_df_cds$gene
  coldata = data.frame(type = c("wt", "wt", "cnv"), sample = c('1657_1','1657_2',strain), row.names = colnames(counts))
  coldata$type = factor(coldata$type, levels = c('wt', 'cnv'))
  dds <- DESeqDataSetFromMatrix(countData = counts,
                              colData = coldata,
                              design = ~ type)
  dds <- DESeq(dds)
  res <- results(dds, alpha=0.05)
  diff_analysis_cds = bind_rows(diff_analysis_cds, 
                                    as_tibble(res) %>% 
                                      mutate(gene = rownames(res), strain = strain))
  geneList = res$log2FoldChange#[-1] #remove GRESHAMGFP
  gene.df <- bitr(rownames(res), fromType = "ORF", #[-1]
        toType = "ENTREZID",
        OrgDb = org.Sc.sgd.db::org.Sc.sgd.db)
  names(geneList) = gene.df$ENTREZID
  geneList = sort(geneList, decreasing = TRUE)
  ego <- gseGO(geneList     = geneList,
             OrgDb        = org.Sc.sgd.db::org.Sc.sgd.db,
             keyType = "ENTREZID",
              ont          = "BP",
              minGSSize    = 10,
              maxGSSize    = 500,
              pvalueCutoff = 0.05,
              pAdjustMethod="fdr",
              verbose      = FALSE,
              by="fgsea",
             seed = 1)
  ego = clusterProfiler::simplify(ego)
  gsea_cds = bind_rows(gsea_cds, as_tibble(ego@result) %>% mutate(sample = strain))
}
#write out so this doesn't have to run again
# these will probably also be supplementary files
write_csv(gsea_cds, paste0(data_dir,"/gsea_cds.csv"))
write_csv(diff_analysis_cds, paste0(data_dir,"/diff_analysis_cds.csv"))

gsea_cds_annotated.csv is also STable 3

# I am doing some manual consolidation of terms based on the overlap of the core enrichment between terms
#translation, peptide metabolic process, and peptide biosynthetic process have highly overlapping core enrichment, keeping metabolic process
# ribosomal large subunit biogenesis and maturation of LSU-rRNA have large overlap, keeping ribosomal large subunit biogenesis
# cellular monovalent inorganic cation homeostasis and monovalent inorganic cation homeostasis identical, keeping monovalent inorganic cation homeostasis
# mitochondrial respiratory chain complex assembly and cytochrome complex assembly very similar, keeping mitochondrial respiratory chain complex assembly
# electron transport chain and aerobic electron transport chain very similar, keeping aerobic electron transport chain
# ATP biosynthetic process, energy coupled proton transport down electrochemical gradient and ATP synthesis coupled proton transport identical, keeping ATP synthesis coupled proton transport

f3b= read_csv(paste0(data_dir,"/gsea_cds_annotated.csv")) %>% 
  filter(Keep == "Yes") %>%
  mutate(strain = as.character(sample)) %>%
  full_join(strain_names) %>%
  filter(!is.na(Description)) %>%
  add_row(strain_names = c("trip3", "trip4"), 
          Description = c("ribonucleoprotein complex biogenesis","ribonucleoprotein complex biogenesis")) %>%
  ggplot(aes(x = strain_names, y = reorder(Description, Order*-1), 
           color = enrichmentScore)) +
  geom_point(aes(size = p.adjust)) +
  scale_size("p adjust", trans="log10", range=c(15, 5), breaks=c(1e-10, 1e-8, 1e-6, 1e-4, 1e-2), limits = c(1e-10, .05)) +
  ggtitle("Biological Pathway")+
  xlab("")+
  ylab("")+
  scale_colour_gradient2(low = "blue", mid = "white", high = "red", breaks = c(-0.8, 0, 0.8)) 

ggsave(paste0(fig_dir,"/Fig3b.pdf"), plot = f3b, width = 13, height = 9, units = "in")
diff_analysis_cds = read_csv(paste0(data_dir,"/diff_analysis_cds.csv"))

f3c = diff_analysis_cds %>%
  filter(padj < 0.05) %>%
  mutate(strain = as.character(strain)) %>%
  left_join(strain_names) %>%
  mutate(common_name = labtools::yeast_systematic_to_common(gene)) %>%
  filter(common_name != "GRESHAMGFP") %>%
  left_join(cnv_genes, by = c("strain" = "sample", "gene" = "gene", "strain_names" = "strain_names")) %>%
  mutate(copy_number = if_else(is.na(copy_number),"",as.character(copy_number))) %>%
  ggplot(aes(strain_names, common_name, fill = log2FoldChange)) +
  geom_tile() +
  scale_fill_gradient2(low = "blue", mid = "white", high = "red") +
  theme_grey() +
  theme(panel.border = element_blank(),
          panel.grid.major = element_blank(),
          panel.grid.minor = element_blank(),
          axis.line = element_line(size = 0.5, linetype = "solid",
                                   colour = "black")) + 
  xlab("") +
  ylab("") + 
  geom_text(aes(strain_names, common_name, label=copy_number)) +
  labs(fill = "log2FoldChange\nfor p.adj < 0.05") 

# check size ####
ggsave(paste0(fig_dir,"/Fig3C.pdf"), plot = f3c, width = 9, height = 5, units = "in")
 sfig5a = diff_analysis_cds %>%
  #filter(padj < 0.05) %>%
  filter(gene %in% pull(diff_analysis_cds %>% filter(padj < 0.05), gene)) %>%
  mutate(sig = case_when(padj < 0.0001 ~ "****",
                         padj < 0.001 ~ "***",
                         padj < 0.01 ~ "**",
                         padj < 0.05 ~ "*",
                         is.na(padj) ~ "",
                         padj >= 0.05 ~ "")) %>%
  mutate(strain = as.character(strain)) %>%
  left_join(strain_names) %>%
  mutate(common_name = labtools::yeast_systematic_to_common(gene)) %>%
  filter(common_name != "GRESHAMGFP") %>%
  left_join(cnv_genes %>% mutate(strain = str_remove(strain, "DGY"))) %>%
  mutate(copy_number = if_else(is.na(copy_number),"",as.character(copy_number))) %>%
  ggplot(aes(strain_names, common_name, fill = log2FoldChange)) +
  geom_tile() +
  scale_fill_gradient2(low = "blue", mid = "white", high = "red") +
  theme_classic() + 
  xlab("") +
  ylab("") + 
  geom_text(aes(label=paste(copy_number, sig))) +
  labs(fill = "log2FoldChange")

ggsave(paste0(fig_dir,"/SFig5A.png"), plot = sfig5a, width = 9, height = 5, units = "in")
LS0tCnRpdGxlOiAiVHJhbnNwb3NvbiBtdXRhZ2VuZXNpcyBpbiAqR0FQMSogQ05WIHN0cmFpbnMiCmF1dGhvcjogIkdyYWNlIEF2ZWNpbGxhIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgoKYGBge3J9CmxpYnJhcnkoRW5oYW5jZWRWb2xjYW5vKQpsaWJyYXJ5KERFU2VxMikKbGlicmFyeShvcmcuU2Muc2dkLmRiKQpsaWJyYXJ5KGNsdXN0ZXJQcm9maWxlcikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KGdnYmVlc3dhcm0pCmxpYnJhcnkoZ2dwdWJyKQp0aGVtZV9zZXQodGhlbWVfYncoYmFzZV9zaXplID0gMjApKQoKZGF0YV9kaXIgPSAiL1ZvbHVtZXMvR29vZ2xlRHJpdmUvTXkgRHJpdmUvR3Jlc2hhbSBMYWJfR3JhY2UvZnJhbmNlX3NhdGF5L0hlcm1lc19tdXRhZ2VuZXNpc19wYXBlci9kYXRhIgoKZmlnX2RpciA9ICIvVm9sdW1lcy9Hb29nbGVEcml2ZS9NeSBEcml2ZS9HcmVzaGFtIExhYl9HcmFjZS9mcmFuY2Vfc2F0YXkvSGVybWVzX211dGFnZW5lc2lzX3BhcGVyL2ZpZ3VyZXMiCgpzb3VyY2UoIi9Wb2x1bWVzL0dvb2dsZURyaXZlL015IERyaXZlL0dyZXNoYW0gTGFiX0dyYWNlL2ZyYW5jZV9zYXRheS9IZXJtZXNfbXV0YWdlbmVzaXNfcGFwZXIvYW5hbHlzaXNfd19QU19jb3JyZWN0aW9ucy9mdW5jdGlvbnMuUiIpCgpzZXFfcnVucyA9IGMoImJnaTEiLCJiZ2kyIiwgIm55YzEiLCAibnljMiIpCmBgYAoKYGBge3J9CiMgZ2V0IGFsbCBnZW5lcyBleGNsdWRpbmcgZHViaW91cyBvcmZzIGFuZCB0aGVpciBjb3B5IG51bWJlcgpzdHJhaW5fY25zID0gcmVhZF9jc3YocGFzdGUwKGRhdGFfZGlyLCAiL2dlbmVfbWVkaWFuX3JlbGF0aXZlX2RlcHRoX0ROQV9jb3JyZWN0ZWRfdjMvZ2VuZV9tZWRpYW5fcmVsYXRpdmVfZGVwdGhfRE5BLVRhYmxlIDEuY3N2IikpICU+JSAKICBzZWxlY3QoR2VuZSwgY29udGFpbnMoImNvciIpKSAlPiUKICBwaXZvdF9sb25nZXIoLUdlbmUsIG5hbWVzX3RvID0gInN0cmFpbiIsIHZhbHVlc190byA9ICJjb3B5X251bWJlciIpICU+JQogIG11dGF0ZShzdHJhaW4gPSBzdHJfZXh0cmFjdChzdHJhaW4sIlswLTldezR9IikpICU+JQogIGxlZnRfam9pbihzdHJhaW5fbmFtZXMpCgphbGxfZ2VuZXMgPSBzdHJhaW5fY25zJEdlbmUKYGBgCgojIENvcnJlbGF0aW9uIGJldHdlZW4gZGlmZmVyZW50IHNlcXVlbmNpbmcgbWV0aG9kcwpVc2luZyBpbnNlcnRpb25zIHBlciBnZW5lCmBgYHtyfQpnZXRfaXBnID0gZnVuY3Rpb24oeCwgdmVyKXsKICBkYXRhID0gcmVhZF90c3YocGFzdGUwKGRhdGFfZGlyLCAiL2hwY19vdXRwdXQvIix2ZXIsICIvIiwgeCksIAogICAgICAgICAgICAgICAgICBjb2xfdHlwZXMgPSBjb2xzKENEUz1jb2xfY2hhcmFjdGVyKCksYCNpbnNlcnRpb25gID0gY29sX2RvdWJsZSgpKSkgJT4lCiAgICBtdXRhdGUoc2FtcGxlID0gc3RyX3N1Yih4LCAxLCAtMjIpLCBnZW5lPU5BLAogICAgICAgICAgIHJ1bj12ZXIpCn0KaXBnX2ZvcmNvciA9IE5VTEwKZm9yKGkgaW4gc2VxX3J1bnMpIHsKICBpcGdfZmlsZXMgPSBsaXN0LmZpbGVzKHBhdGggPSBwYXN0ZTAoZGF0YV9kaXIsICIvaHBjX291dHB1dC8iLCBpLCAiLyIpLCBwYXR0ZXJuID0gJyppbnNlcnRpb25QZXJHZW5lLnR4dCcpCiAgaXBnX3QgPSBtYXAoaXBnX2ZpbGVzLCBnZXRfaXBnLCB2ZXI9aSkKICBpcGdfZGZfdCA9IGRvLmNhbGwocmJpbmQsIGlwZ190KQogIGlwZ19mb3Jjb3IgPSBpcGdfZm9yY29yICU+JSAKICAgIGJpbmRfcm93cyhpcGdfZGZfdCAlPiUgdW5pdGUoc2FtcGxlX3JlcCwgc2FtcGxlLCBydW4pKQp9CmBgYAoKYGBge3J9CiMgZ2V0IGNvcnJlbGF0aW9ucwppcGdfZm9yY29yID0gaXBnX2ZvcmNvciAlPiUKICBtdXRhdGUoc3RyYWluID0gc3RyX3N1YihzYW1wbGVfcmVwLCAxLCAtNiksCiAgICAgICAgIHJlcCA9IHN0cl9zdWIoc2FtcGxlX3JlcCwgLTQsIC0xKSkgJT4lCiAgbGVmdF9qb2luKHN0cmFpbl9uYW1lcykgJT4lCiAgdW5pdGUoc2FtcGxlX3JlcCwgc3RyYWluX25hbWVzLCByZXApICU+JQogIGRwbHlyOjpzZWxlY3QoQ0RTLCBzYW1wbGVfcmVwLCBgI2luc2VydGlvbmApICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gc2FtcGxlX3JlcCwgdmFsdWVzX2Zyb20gPSBgI2luc2VydGlvbmApIAoKCnJlcHMgPSBpcGdfZm9yY29yICU+JQogICAgZHBseXI6OnNlbGVjdChldV8xX255YzEsIGV1XzFfbnljMiwgZXVfMl9ueWMxLCBldV8yX255YzIpICAKY29yX3Bsb3RzPUdHYWxseTo6Z2dwYWlycyhyZXBzLCAKICAgICAgICAgICAgICAgIHVwcGVyID0gbGlzdChjb250aW51b3VzID0gR0dhbGx5Ojp3cmFwKCJjb3IiLCBtZXRob2QgPSAicGVhcnNvbiIpKSkgKwogICAgZ2d0aXRsZShMRVRURVJTWzFdKQpnZ3NhdmUoY29yX3Bsb3RzLCBmaWxlPXBhc3RlMChmaWdfZGlyLCAiL1NGaWdYIiwgTEVUVEVSU1sxXSwgIi5wZGYiKSwgaGVpZ2h0ID0gMTAsIHdpZHRoID0gMTApCgppPTIKZm9yKHN0cmFpbiBpbiBjKCJhbmV1IiwgInRyaXAxIiwgInRyaXAyIiwgInRyaXAzIiwgInRyaXA0IiwgImlzbyIsICJxdWFkIikpIHsKICByZXBzID0gaXBnX2ZvcmNvciAlPiUKICAgIGRwbHlyOjpzZWxlY3QoY29sbmFtZXMoaXBnX2ZvcmNvcilbc3RyX2RldGVjdChjb2xuYW1lcyhpcGdfZm9yY29yKSwgc3RyYWluKV0pICAKICBjb3JfcGxvdHM9R0dhbGx5OjpnZ3BhaXJzKHJlcHMsIAogICAgICAgICAgICAgICAgdXBwZXIgPSBsaXN0KGNvbnRpbnVvdXMgPSBHR2FsbHk6OndyYXAoImNvciIsIG1ldGhvZCA9ICJwZWFyc29uIikpKSArCiAgICBnZ3RpdGxlKExFVFRFUlNbaV0pCiAgZ2dzYXZlKGNvcl9wbG90cywgZmlsZT1wYXN0ZTAoZmlnX2RpciwgIi9TRmlnWCIsIExFVFRFUlNbaV0sICIucGRmIiksIGhlaWdodCA9IDEwLCB3aWR0aCA9IDEwKQogIGk9aSsxCn0KCmBgYAoKYGBge3IgZ2V0IHJlYWRzIHBlciBwb3NpdGlvbn0KZ2V0X3JwcCA9IGZ1bmN0aW9uKHgsIHZlcikgewogIGZpbGVwYXRoPXBhc3RlMChkYXRhX2RpciwiL2hwY19vdXRwdXQvIix2ZXIsIi8iLHgpCiAgb3V0ID0gcmVhZF90c3YoZmlsZXBhdGgsIGNvbF9uYW1lcyA9IEYsIGNvbF90eXBlcyA9IGNvbHMoKSkgJT4lCiAgICBkcGx5cjo6cmVuYW1lKGNocm9tb3NvbWU9WDEsIGNocl9wb3M9WDIsIHJlYWRzPVgzKSAlPiUKICAgIG11dGF0ZShzYW1wbGUgPSBzdHJfc3ViKHgsIDEsIC0xNiksCiAgICAgICAgICAgdmVyc2lvbiA9IHZlcikKfQpmaWxlcyA9IGxpc3QuZmlsZXMocGF0aCA9IHBhc3RlMChkYXRhX2RpciwgJy9ocGNfb3V0cHV0L2NvbWJpbmVkLycpLAogICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gJypyZWFkUGVyUG9zLnR4dCcpCnJlYWRfcGVyX3BvcyA9IG1hcChmaWxlcywgZ2V0X3JwcCwgdmVyPSdjb21iaW5lZCcpCnJwcF9kZiA9IGRvLmNhbGwocmJpbmQsIHJlYWRfcGVyX3BvcykKCmBgYAoKYGBge3Igc3VwcGxlbWVudGFyeSB0YWJsZSAxIGxpYnJhcnkgY2hhcmFjdGVyaXN0aWNzfQpzdW1tYXJ5X3JwcCA9IHJwcF9kZiAlPiUKICBsZWZ0X2pvaW4oc3RyYWluX25hbWVzLCBieSA9IGMoInNhbXBsZSIgPSAic3RyYWluIikpICU+JQogIGdyb3VwX2J5X2F0KHZhcnMoc3RyYWluX25hbWVzLCBzYW1wbGUpKSAlPiUgCiAgcmVuYW1lKEdyZXNoYW1fSUQgPSBzYW1wbGUpICU+JQogIHN1bW1hcml6ZSh0b3RhbF9zaXRlcyA9IG4oKSwgbWluX3JwcCA9IG1pbihyZWFkcyksIG1heF9ycHAgPSBtYXgocmVhZHMpLAogICAgICAgICAgICBtZWFuX3JwcCA9IG1lYW4ocmVhZHMpLCBtZWRpYW5fcnBwID0gbWVkaWFuKHJlYWRzKSkgCnN1bW1hcnlfcnBwICU+JQogIGtuaXRyOjprYWJsZSgpICU+JQogIGthYmxlRXh0cmE6OmthYmxlX3N0eWxpbmcoKQp3cml0ZV9jc3Yoc3VtbWFyeV9ycHAsIHBhc3RlMChmaWdfZGlyLCAiL1N1cHBsZW1lbnRhcnlUYWJsZTEuY3N2IikpCmBgYAoKCmBgYHtyIHNmaWcyfQojIG51bWJlciBvZiBpbnNlcnRpb24gc2l0ZXMgc2NhbGVzIHdpdGggdG90YWwgcmVhZHMgZ2VuZXJhdGVkCnJlYWRzX3Blcl9saWIgPSByZWFkX2NzdihwYXN0ZTAoZGF0YV9kaXIsIi90b3RhbF9yZWFkc19wZXJfbGlicmFyeS5jc3YiKSkKCnNmaWcyID0gcmVhZHNfcGVyX2xpYiAlPiUKICBsZWZ0X2pvaW4oc3VtbWFyeV9ycHAsIGJ5ID0gYygiU2FtcGxlIj0iR3Jlc2hhbV9JRCIpKSAlPiUKICBnZ3Bsb3QoYWVzKHRvdGFsX3NpdGVzLCByZWFkcywgY29sb3IgPSBzdHJhaW5fbmFtZXMpKSArCiAgZ2VvbV9wb2ludChzaXplPTIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gc3RyYWluX2NvbHMpICsKICB4bGFiKCJVbmlxdWUgaW5zZXJ0aW9uIHNpdGVzIikgKwogIHlsYWIoIlRvdGFsIHJlYWRzICIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpjb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmNvbW1hKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSkKCmdnc2F2ZShwYXN0ZTAoZmlnX2RpciwiL1NGaWcyLnBkZiIpLCBwbG90ID0gc2ZpZzIsIHdpZHRoID0gOC41LCBoZWlnaHQgPSA1LCB1bml0cyA9ICJpbiIpCmdnc2F2ZShwYXN0ZTAoZmlnX2RpciwiL1NGaWcyLnBuZyIpLCBwbG90ID0gc2ZpZzIsIHdpZHRoID0gOC41LCBoZWlnaHQgPSA1LCB1bml0cyA9ICJpbiIpCmBgYAoKCiMgUGF0dGVybnMgb2YgdHJhbnNwb3NvbiBpbnNlcnRpb24gZGVuc2l0eSByZW1haW4gYSByZWxpYWJsZSBwcmVkaWN0b3Igb2Ygc2VxdWVuY2UgdG9sZXJhbmNlIHRvIGRpc3J1cHRpdmUgbXV0YXRpb24gaW4gQ05WIHN0cmFpbnMKCmBgYHtyIHNmaWczfQojIGVzc2VudGlhbCBnZW5lcyBoYXZlIGZld2VyIGluc2VydGlvbnMKZ2V0X2Nkc19wcm9tb3RlciA9IGZ1bmN0aW9uKHgsIHkpewogIHkgPSB5ICU+JSBkcGx5cjo6ZmlsdGVyKHN0cl9zdGFydHMoWDksIHBhc3RlMCh4LCAnOycpKSkKICBpZihucm93KHkpID4gMSkgewogICAgeSRYNCA9IG1pbih5JFg0KQogICAgeSRYNSA9IG1heCh5JFg1KQogIH0KICBjaHJvbW9zb21lID0geSRYMQogIHN0cmFuZCA9IHkkWDcKICBpZihzdHJhbmRbMV0gPT0gJysnKSB7CiAgICBzdGFydCA9IHkkWDQKICAgIHN0b3AgPSB5JFg1CiAgICBwcm9tb3RlciA9IHkkWDQgLSAyMDAKICB9IGVsc2UgewogICAgc3RhcnQgPSB5JFg1CiAgICBzdG9wID0geSRYNAogICAgcHJvbW90ZXIgPSB5JFg1ICsgMjAwCiAgfQogIHJldHVybih0aWJibGUoY2hyb21vc29tZSwgc3RhcnQsIHN0b3AsIHByb21vdGVyLCBzdHJhbmQpWzEsXSkKfQojIHggaXMgYSBnZW5lIHRoYXQgSSB3YW50IHRvIGdldCBpbmZvIGZvciAoaW4gIklEPWNkczAiIGZvcm0pLCBpbnNlcnRzIGlzIHRoZSByZWFkcyBwZXIgcG9zaXRpb24gZmlsZSAKIyB3aWxsIHJldHVybiBmb3IgZWFjaCBzYW1wbGUgaW4gaW5zZXJ0cwpnZXRfYmlubmVkX3VuaXF1ZV9pbnNlcnRpb25zID0gZnVuY3Rpb24oeCwgaW5zZXJ0cyl7CiAgeSA9IGdldF9jZHNfcHJvbW90ZXIoeCwgeSA9IGdmZl9jZHMpCiAgYmluX3NpemVfY2RzID0gKHkkc3RhcnQgLSB5JHN0b3ApLzEwMAogIGNkcz1OVUxMCiAgcHJvbW89TlVMTAogIGZvcihpIGluIHVuaXF1ZShpbnNlcnRzJHNhbXBsZSkpIHsKICAgIGJpbl9maWxsX2NkcyA9IE5VTEwKICAgIGJpbl9maWxsX3Byb20gPSBOVUxMCiAgICBpbmkgPSBpbnNlcnRzICU+JSBkcGx5cjo6ZmlsdGVyKHNhbXBsZSA9PSBpLCBjaHJvbW9zb21lID09IHkkY2hyb21vc29tZSkKICAgIGlmKHkkc3RyYW5kID09ICcrJykgewogICAgICBmb3IoaiBpbiAxOjEwMCkgewogICAgICAgIGJpbl9maWxsX2Nkc1tqXSA9IG5yb3coaW5pICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgIGRwbHlyOjpmaWx0ZXIoY2hyX3BvcyA+PSB5JHN0YXJ0K2Jpbl9zaXplX2Nkcyooai0xKSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2hyX3BvcyA8IHkkc3RhcnQrYmluX3NpemVfY2RzKmogJiAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaHJfcG9zIDw9IHkkc3RvcCkpCiAgICAgICAgYmluX2ZpbGxfcHJvbVtqXSA9IG5yb3coaW5pICU+JSBkcGx5cjo6ZmlsdGVyKGNocl9wb3MgPj0geSRwcm9tb3RlcisyKihqLTEpICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaHJfcG9zIDw9IHkkcHJvbW90ZXIrMipqICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaHJfcG9zIDwgeSRzdGFydCkpCiAgICAgIH0KICAgIH0gZWxzZSB7CiAgICAgIGZvcihqIGluIDE6MTAwKSB7CiAgICAgICAgYmluX2ZpbGxfY2RzW2pdID0gbnJvdyhpbmkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgZHBseXI6OmZpbHRlcihjaHJfcG9zIDw9IHkkc3RhcnQtYmluX3NpemVfY2RzKihqLTEpICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaHJfcG9zID4geSRzdGFydC1iaW5fc2l6ZV9jZHMqaiAmIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNocl9wb3MgPj0geSRzdG9wKSkKICAgICAgICBiaW5fZmlsbF9wcm9tW2pdID0gbnJvdyhpbmkgJT4lIGRwbHlyOjpmaWx0ZXIoY2hyX3BvcyA8PSB5JHByb21vdGVyLTIqKGotMSkgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNocl9wb3MgPj0geSRwcm9tb3Rlci0yKmogJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNocl9wb3MgPiB5JHN0YXJ0KSkKICAgICAgfQogICAgfQogICAgbmFtZXMoYmluX2ZpbGxfY2RzKSA9IDE6MTAwCiAgICBuYW1lcyhiaW5fZmlsbF9wcm9tKSA9IDE6MTAwCiAgICBjZHMgPSBjZHMgJT4lIGJpbmRfcm93cyhjKHR5cGUgPSAiY2RzIiwgaWQ9eCwgc2FtcGxlPWksIGJpbl9maWxsX2NkcykpCiAgICBwcm9tbyA9IHByb21vICU+JSBiaW5kX3Jvd3MoYyh0eXBlPSAicHJvbW90ZXIiLGlkPXgsIHNhbXBsZT1pLCBiaW5fZmlsbF9wcm9tKSkKICB9CiAgYmluZF9yb3dzKGNkcywgcHJvbW8pCn0KCmJpbm5lZF9pbnNlcnRzID0gZG8uY2FsbChyYmluZCwgbWFwKGFsbF9nZW5lcyRYMSwgZ2V0X2Jpbm5lZF91bmlxdWVfaW5zZXJ0aW9ucywgaW5zZXJ0cyA9IHJwcF9kZikpCgojd3JpdGVfY3N2KGJpbm5lZF9pbnNlcnRzLCAiLi9iaW5uZWRfaW5zZXJ0c190ZW1wLmNzdiIpCiNyZWFkX2NzdigiLi9iaW5uZWRfaW5zZXJ0c190ZW1wLmNzdiIpCgp5ZWFzdF9yNjRfdG9fc3lzdGVtYXRpYyA8LSBmdW5jdGlvbihuYW1lX3ZlYykgewogIHRyYW5zbGF0ZWRfbmFtZXMgPC0gbWF0Y2gobmFtZV92ZWMsIGxhYnRvb2xzOjp5ZWFzdF9nZW5lX25hbWVzJEdDRl8wMDAxNDYwNDUuMl9SNjRfZ2Vub21pY19JRCwgbm9tYXRjaD1OQSkKICB0cmFuc2xhdGVkX25hbWVzIDwtIGxhYnRvb2xzOjp5ZWFzdF9nZW5lX25hbWVzW3RyYW5zbGF0ZWRfbmFtZXMsICJTeXN0ZW1hdGljX25hbWUiXQogIG5vX3RyYW5zbGF0aW9uIDwtIGlzLm5hKHRyYW5zbGF0ZWRfbmFtZXMpCiAgdHJhbnNsYXRlZF9uYW1lc1tub190cmFuc2xhdGlvbl0gPC0gbmFtZV92ZWNbbm9fdHJhbnNsYXRpb25dCiAgcmV0dXJuKHRyYW5zbGF0ZWRfbmFtZXMpCn0KCnQkZ2VuZSA9IHllYXN0X3I2NF90b19zeXN0ZW1hdGljKHQkaWQpCgojIGdldCBsaXN0IG9mIGVzc2VudGlhbCBnZW5lcyBmcm9tIFdpbnplbGVyIDE5OTkKZXNzX2RlbCA9IHJlYWRfdHN2KHBhc3RlMChkYXRhX2RpciwnL0Vzc2VudGlhbF9PUkZzLnR4dCcpLCBjb2xfbmFtZXMgPSBULCBjb21tZW50ID0gJz0nLCBjb2xfdHlwZXMgPSBjb2xzKAogIHJlY19udW0gPSBjb2xfZG91YmxlKCksCiAgT1JGX25hbWUgPSBjb2xfY2hhcmFjdGVyKCksCiAgZGVsZXRpb25fYWxpYXMgPSBjb2xfY2hhcmFjdGVyKCksCiAgZ2VuZV9uYW1lcyA9IGNvbF9jaGFyYWN0ZXIoKSwKICBVUFRBR19zZXF1ZW5jZV8yMG1lciA9IGNvbF9jaGFyYWN0ZXIoKSwKICBETlRBR19zZXF1ZW5jZV8yMG1lciA9IGNvbF9jaGFyYWN0ZXIoKQopKSAlPiUKICBkcGx5cjo6c2VsZWN0KE9SRl9uYW1lKSAlPiUgZHBseXI6OnJlbmFtZShnZW5lPU9SRl9uYW1lKSAlPiUKICBtdXRhdGUoZXNzX2RlbCA9ICJ5ZXMiKQoKIyBnZXQgZ2VuZSBmaXRuZXNzIGluIHlwZ2FsIGZyb20gY29zdGFuem8gZXQgYWwgMjAyMQpmaXRfZ2FsID0gcmVhZF9jc3YocGFzdGUwKGRhdGFfZGlyLCAiL0Nvc3RhbnpvX011dGFudCBGaXRuZXNzX0NvbmRpdGlvbnMtVGFibGUgMS5jc3YiKSwgY29sX25hbWVzID0gVCkgJT4lCiAgc2VsZWN0KGBTeXN0ZW1hdGljIE5hbWVgLCBgR2VuZSBOYW1lYCwgYEFsbGVsZSAoRXNzZW50aWFsIGdlbmVzIG9ubHkpYCwgYEdhbGFjdG9zZWApICU+JQogIG11dGF0ZShxdWFydGlsZSA9IGNhc2Vfd2hlbihHYWxhY3Rvc2UgPD0gcXVhbnRpbGUoR2FsYWN0b3NlLCBuYS5ybT1UKVsyXSB+ICJRMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEdhbGFjdG9zZSA8PSBxdWFudGlsZShHYWxhY3Rvc2UsIG5hLnJtPVQpWzNdIH4gIlEyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgR2FsYWN0b3NlIDw9IHF1YW50aWxlKEdhbGFjdG9zZSwgbmEucm09VClbNF0gfiAiUTMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBHYWxhY3Rvc2UgPD0gcXVhbnRpbGUoR2FsYWN0b3NlLCBuYS5ybT1UKVs1XSB+ICJRNCIsKSkKCmJpbm5lZF9pbnNlcnRzID0gYmlubmVkX2luc2VydHMgJT4lIAogIG11dGF0ZShlc3NlbnRpYWwgPSBkcGx5cjo6aWZfZWxzZShgZ2VuZWAgJWluJSBlc3NfZGVsJGdlbmUsICd5ZXMnLCAnbm8nKSkgJT4lIAogIGxlZnRfam9pbihmaXRfZ2FsICU+JSBzZWxlY3QoYFN5c3RlbWF0aWMgTmFtZWAsIHF1YXJ0aWxlKSwgYnk9YygiZ2VuZSIgPSAiU3lzdGVtYXRpYyBOYW1lIikpICU+JQogIHBpdm90X2xvbmdlcihjb2xzPWMoLWdlbmUsIC1lc3NlbnRpYWwsIC10eXBlLCAtaWQsIC1zYW1wbGUpLCAKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiYmluIiwgdmFsdWVzX3RvID0gImluc2VydHNfcGVyX2JpbiIpICU+JQogIG11dGF0ZV9hdChjKCdiaW4nLCAnaW5zZXJ0c19wZXJfYmluJyksIGFzLm51bWVyaWMpCgoKbWV0YV9iaW5faW5zZXJ0X2Vzc2VudGlhbCA9IGJpbm5lZF9pbnNlcnRzICU+JSAKICBncm91cF9ieV9hdCh2YXJzKHNhbXBsZSwgdHlwZSwgZXNzZW50aWFsLCBiaW4pKSAlPiUKICBtdXRhdGUodG90YWxfaW5zZXJ0c19iaW4gPSBzdW0oaW5zZXJ0c19wZXJfYmluKSwgCiAgICAgICAgIG1lYW5faW5zZXJ0c19iaW4gPSBtZWFuKGluc2VydHNfcGVyX2JpbiksCiAgICAgICAgIG1lZGlhbl9pbnNlcnRzX2JpbiA9IG1lZGlhbihpbnNlcnRzX3Blcl9iaW4pLAogICAgICAgICBuZ2VuZV9ub3JtX3RvdGFsX2luc2VydHNfYmluID0gZHBseXI6OmlmX2Vsc2UoZXNzZW50aWFsID09ICd5ZXMnLCBzdW0oaW5zZXJ0c19wZXJfYmluKS9ucm93KGVzc19kZWwpLCBzdW0oaW5zZXJ0c19wZXJfYmluKS8obnJvdyhhbGxfZ2VuZXMpIC0gbnJvdyhlc3NfZGVsKSkpKSAlPiUKICBkcGx5cjo6c2VsZWN0KHNhbXBsZSwgdHlwZSwgZXNzZW50aWFsLCBiaW4sIHRvdGFsX2luc2VydHNfYmluLCBtZWFuX2luc2VydHNfYmluLCBtZWRpYW5faW5zZXJ0c19iaW4sIG5nZW5lX25vcm1fdG90YWxfaW5zZXJ0c19iaW4pICU+JSBkaXN0aW5jdCgpCgptZXRhX2Jpbl9pbnNlcnRfZXNzZW50aWFsJHR5cGVfb3JkZXIgPSBmYWN0b3IobWV0YV9iaW5faW5zZXJ0X2Vzc2VudGlhbCR0eXBlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHM9YygncHJvbW90ZXInLCAnY2RzJykpCgpzZmlnM2EgPSBnZ3Bsb3QobWV0YV9iaW5faW5zZXJ0X2Vzc2VudGlhbCAlPiUgCiAgICAgICAgIGZpbHRlcih0eXBlID09ICdjZHMnKSAlPiUKICAgICAgICAgICBtdXRhdGUoc3RyYWluX25hbWVzX3JlcCA9IGNhc2Vfd2hlbihzYW1wbGUgPT0gIjE2NTdfMSIgfiAiZXVfMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlID09ICIxNjU3XzIiIH4gImV1XzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZSA9PSAiMTcyOCIgfiAiYW5ldSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlID09ICIxNzM0IiB+ICJ0cmlwMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlID09ICIxNzQ3IiB+ICJ0cmlwMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlID09ICIxNzUxIiB+ICJ0cmlwMyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlID09ICIxNzM2IiB+ICJ0cmlwNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlID09ICIxNzQ0IiB+ICJpc28iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZSA9PSAiMTc0MCIgfiAicXVhZCIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApKSAsIAogICAgICAgYWVzKGJpbiwgbmdlbmVfbm9ybV90b3RhbF9pbnNlcnRzX2JpbiwgY29sb3IgPSBlc3NlbnRpYWwpKSArCiAgZ2VvbV9saW5lKCkgKwogICN0aGVtZV9taW5pbWFsKCkgKwogIGZhY2V0X3dyYXAofnN0cmFpbl9uYW1lc19yZXApICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoJyM4MGIxZDMnLCAnI2ZiODA3MicpLAogICAgICAgICAgICAgICAgICAgICBuYW1lID0gIiIsIGxhYmVscyA9IGMoIk5vbi1lc3NlbnRpYWwiLCAiRXNzZW50aWFsIikpICsKICB4bGFiKCclIG9mIENEUycpICsKICB5bGFiKCdNZWFuIHVuaXF1ZSBpbnNlcnRpb24gc2l0ZXMnKQoKc2ZpZzNiPWJpbm5lZF9pbnNlcnRzICU+JSAKICB1bmdyb3VwKCkgJT4lCiAgZmlsdGVyKHR5cGU9PSJjZHMiKSAlPiUKICBncm91cF9ieV9hdCh2YXJzKHNhbXBsZSwgdHlwZSwgcXVhcnRpbGUsIGJpbikpICU+JQogIG11dGF0ZSh0b3RhbF9pbnNlcnRzX2JpbiA9IHN1bShpbnNlcnRzX3Blcl9iaW4pLCAKICAgICAgICAgbWVhbl9pbnNlcnRzX2JpbiA9IG1lYW4oaW5zZXJ0c19wZXJfYmluKSwKICAgICAgICAgbWVkaWFuX2luc2VydHNfYmluID0gbWVkaWFuKGluc2VydHNfcGVyX2JpbikpICU+JQogIGRwbHlyOjpzZWxlY3Qoc2FtcGxlLCB0eXBlLCBlc3NlbnRpYWwsIGJpbiwgdG90YWxfaW5zZXJ0c19iaW4sIG1lYW5faW5zZXJ0c19iaW4sIG1lZGlhbl9pbnNlcnRzX2JpbiwgcXVhcnRpbGUpICU+JQogIGRpc3RpbmN0KCkgJT4lCiAgbXV0YXRlKHN0cmFpbl9uYW1lc19yZXAgPSBjYXNlX3doZW4oc2FtcGxlID09ICIxNjU3XzEiIH4gImV1XzEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZSA9PSAiMTY1N18yIiB+ICJldV8yIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGUgPT0gIjE3MjgiIH4gImFuZXUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZSA9PSAiMTczNCIgfiAidHJpcDEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZSA9PSAiMTc0NyIgfiAidHJpcDIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZSA9PSAiMTc1MSIgfiAidHJpcDMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZSA9PSAiMTczNiIgfiAidHJpcDQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZSA9PSAiMTc0NCIgfiAiaXNvIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGUgPT0gIjE3NDAiIH4gInF1YWQiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSkgJT4lCiAgZ2dwbG90KGFlcyhiaW4sIG1lYW5faW5zZXJ0c19iaW4sIGNvbG9yID0gcXVhcnRpbGUpKSArCiAgZ2VvbV9saW5lKCkgKwogICN0aGVtZV9taW5pbWFsKCkgKwogIGZhY2V0X3dyYXAofnN0cmFpbl9uYW1lc19yZXApICsKICAjc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCcjODBiMWQzJywgJyNmYjgwNzInKSwKICAgIyAgICAgICAgICAgICAgICAgIG5hbWUgPSAiIiwgbGFiZWxzID0gYygiTm9uLWVzc2VudGlhbCIsICJFc3NlbnRpYWwiKSkgKwogIHhsYWIoJyUgb2YgQ0RTJykgKwogIHlsYWIoJ01lYW4gdW5pcXVlIGluc2VydGlvbiBzaXRlcycpCgpxdWFudGlsZShmaXRfZ2FsJEdhbGFjdG9zZSwgbmEucm09VCkKCmxheW91dCA8LSAiCkEKQgoiCgpzZmlnMz1zZmlnM2EgKyBzZmlnM2IgKyBwbG90X2xheW91dChkZXNpZ24gPSBsYXlvdXQpICsgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSAnQScpCgpnZ3NhdmUocGFzdGUwKGZpZ19kaXIsIi9TRmlnMy5wZGYiKSwgcGxvdCA9IHNmaWczLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSAxNiwgdW5pdHMgPSAiaW4iKQpnZ3NhdmUocGFzdGUwKGZpZ19kaXIsIi9TRmlnMy5wbmciKSwgcGxvdCA9IHNmaWczLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSAxNiwgdW5pdHMgPSAiaW4iKQpgYGAKIAojIEdldCBpbnNlcnRpb24gcHJvZmlsZXMKYGBge3IgZ2V0IGluc2VydGlvbiBwcm9maWxlcywgbWVzc2FnZT1GQUxTRX0KI2dldCBpbnNlcnRpb24gcHJvZmlsZXMgZm9yIGFsbCBnZW5lcwppbnNlcnRfcHJvZmlsZXMgPSBtYXAoYWxsX2dlbmVzX3N5c3RlbWF0aWMsIGdldF9pbnNlcnRfcHJvZmlsZSwgZGF0YSA9IHJwcF9kZikKaW5zZXJ0X3Byb2ZpbGVzID0gZG8uY2FsbChyYmluZCwgaW5zZXJ0X3Byb2ZpbGVzKQoKIyBhZGQgaW4gemVybyBjYXRlZ29yaWVzCnQ9aW5zZXJ0X3Byb2ZpbGVzICU+JSByaWdodF9qb2luKHRpYmJsZShhbGxfZ2VuZXNfc3lzdGVtYXRpYyksIGJ5PSBjKCJnZW5lIj0iYWxsX2dlbmVzX3N5c3RlbWF0aWMiKSkgJT4lCiAgbXV0YXRlX2F0KHZhcnMoc2FtcGxlLCBnZW5lLCB0eXBlKSwgZmFjdG9yKSAKdD10ICU+JSAKICB0aWR5cjo6ZXhwYW5kKHNhbXBsZSwgZ2VuZSwgdHlwZSkKaW5zZXJ0X3Byb2ZpbGVzID0gaW5zZXJ0X3Byb2ZpbGVzICU+JSAjZmlsdGVyKCFpcy5uYShzYW1wbGUpKSAlPiUgCiAgcmlnaHRfam9pbih0KSAlPiUKICBtdXRhdGUobl9pbnNlcnRpb25zID0gcmVwbGFjZV9uYShuX2luc2VydGlvbnMsIDApLCBub3JtYWxpemVkX2luc2VydGlvbnMgPSByZXBsYWNlX25hKG5vcm1hbGl6ZWRfaW5zZXJ0aW9ucywgMCkpICU+JQogIGRpc3RpbmN0KCkKCiMgd3JpdGUgb3V0IHNvIHRoaXMgZG9lc24ndCBuZWVkIHRvIGJlIGRvbmUgYWdhaW4Kd3JpdGVfY3N2KGluc2VydF9wcm9maWxlcywgcGFzdGUwKGRhdGFfZGlyLCIvaW5zZXJ0aW9uX3Byb2ZpbGVzLmNzdiIpKQpgYGAKCmBgYHtyIGdldCBpbnNlcnRpb24gcHJvZmlsZSBjc3Z9Cmluc2VydF9wcm9maWxlcyA9IHJlYWRfY3N2KHBhc3RlMChkYXRhX2RpciwiL2luc2VydGlvbl9wcm9maWxlcy5jc3YiKSkKYGBgCgpgYGB7cn0KaW5zZXJ0c19wZXJfbWlsbF9jZHMgPSBpbnNlcnRfcHJvZmlsZXMgJT4lIAogIGxlZnRfam9pbihzdHJhaW5fbmFtZXMsIGMoInNhbXBsZSIgPSAic3RyYWluIikpICU+JQogIGxlZnRfam9pbihzdW1tYXJ5X3JwcCkgJT4lCiAgZmlsdGVyKHR5cGUgJWluJSBjKCJjZHMiKSkgJT4lCiAgZ3JvdXBfYnkoc2FtcGxlLCBnZW5lKSAlPiUKICBtdXRhdGUoaW5zZXJ0cyA9IHN1bShuX2luc2VydGlvbnMpKSAlPiUgdW5ncm91cCgpICU+JQogIHNlbGVjdChzYW1wbGUsIHN0cmFpbl9uYW1lcywgZ2VuZSwgaW5zZXJ0cywgdG90YWxfc2l0ZXMpICU+JQogICAgZGlzdGluY3QoKSAlPiUKICBtdXRhdGUoaW5zZXJ0c19wZXJfbWlsbCA9IGluc2VydHMvKHRvdGFsX3NpdGVzLzFlNikpCmBgYAoKCiMgTG9vayBhdCBnZW5lcyBpbiBDTlYgcmVnaW9uCgpgYGB7cn0KY252X2dlbmVzID0gc3RyYWluX2NucyAlPiUgZmlsdGVyKGNvcHlfbnVtYmVyID49IDIpICU+JSByZW5hbWUoc2FtcGxlID0gc3RyYWluKQpgYGAKCmBgYHtyIGZpZ3VyZSAyYn0KdD1jbnZfZ2VuZXMgJT4lCiAgc2VsZWN0KEdlbmUpICU+JQogIGRpc3RpbmN0KCkgJT4lCiAgbXV0YXRlKHNhbXBsZSA9ICIxNjU3XzEiLCBjb3B5X251bWJlciA9IDEpCgpjbnZfZ2VuZXMgPSBjbnZfZ2VuZXMgJT4lCiAgYmluZF9yb3dzKHQgJT4lIGJpbmRfcm93cyh0ICU+JSBtdXRhdGUoc2FtcGxlID0gIjE2NTdfMiIpKSkgJT4lCiAgZmlsdGVyKEdlbmUgIT0gIkthbk1YIikgJT4lCiAgbXV0YXRlKEdlbmUgPSBpZl9lbHNlKEdlbmUgPT0gIm1DaXRyaW5lIiwgIkdSRVNIQU1HRlAiLCBHZW5lKSkgJT4lCiAgc2VsZWN0KC1zdHJhaW5fbmFtZXMpICU+JQogIGxlZnRfam9pbihpbnNlcnRzX3Blcl9taWxsX2NkcywgYnk9YygiR2VuZSIgPSAiZ2VuZSIsICJzYW1wbGUiKSkgJT4lCiAgbGVmdF9qb2luKGVzc19kZWwsIGJ5PWMoIkdlbmUiID0gImdlbmUiKSkgJT4lCiAgcmVuYW1lKGdlbmUgPSBHZW5lKSAlPiUKICBkaXN0aW5jdCgpICU+JQogIGxlZnRfam9pbihzdHJhaW5fbmFtZXMpICU+JSAKICBtdXRhdGUoZXNzX2RlbCA9IGlmX2Vsc2UoaXMubmEoZXNzX2RlbCksICJub3QgZXNzZW50aWFsIiwgZXNzX2RlbCkpCgp0PWNudl9nZW5lcyAlPiUgZGlzdGluY3QoKSAlPiUKICBmaWx0ZXIoIWlzLm5hKGluc2VydHNfcGVyX21pbGwpKSAlPiUKICBzZWxlY3QoZ2VuZSwgc3RyYWluLCBpbnNlcnRzX3Blcl9taWxsKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gc3RyYWluLCB2YWx1ZXNfZnJvbSA9IGluc2VydHNfcGVyX21pbGwpCgpwYWlyZWRfdCA9IE5VTEwKZm9yKHNhbXAgaW4gdW5pcXVlKGNudl9nZW5lcyRzdHJhaW4pKSB7CiAgYSA9IHQgJT4lCiAgICBzZWxlY3Qoc2FtcCwgIjE2NTdfMSIpICU+JQogICAgbmEuZXhjbHVkZSgpCiAgcGFpcmVkX3QgPSBwYWlyZWRfdCAlPiUKICAgIGJpbmRfcm93cyh0aWJibGUoc2FtcGxlID0gc2FtcCwgCiAgICAgICAgICAgICAgICAgICAgIHBfdmFsID0gdC50ZXN0KHB1bGwoYSxzYW1wKSwgcHVsbChhLCIxNjU3XzEiKSwgcGFpcmVkID0gVCkkcC52YWx1ZSwgCiAgICAgICAgICAgICAgICAgICAgIGRmID0gdC50ZXN0KHB1bGwoYSxzYW1wKSwgcHVsbChhLCIxNjU3XzEiKSwgcGFpcmVkID0gVCkkcGFyYW1ldGVyKSkKfQpwYWlyZWRfdAoKZXNzX3QgPSBjbnZfZ2VuZXMgJT4lIAogIGZpbHRlcihnZW5lICE9ICJHUkVTSEFNR0ZQIikgJT4lCiAgZ3JvdXBfYnkoc2FtcGxlKSAlPiUgCiAgcnN0YXRpeDo6dF90ZXN0KGluc2VydHNfcGVyX21pbGwgfiBlc3NfZGVsLCBkZXRhaWxlZD1UKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKHNpZ25pZiA9IGNhc2Vfd2hlbihwIDwgMC4wMDAxIH4gICIqKioqIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHAgPiAwLjAxIH4gIm5zIikpICU+JQogIGxlZnRfam9pbihzdHJhaW5fbmFtZXMsIGJ5ID0gYygic2FtcGxlIiA9ICJzdHJhaW4iKSkgJT4lCiAgYXJyYW5nZShzdHJhaW5fbmFtZXMpICU+JQogIG11dGF0ZShmb2xkX21lYW5zID0gZXN0aW1hdGUxL2VzdGltYXRlMiwgZGlmZl9tZWFucyA9IGVzdGltYXRlMSAtIGVzdGltYXRlMikKCgojIHBlcm11dGF0aW9uIHRlc3QKCnBlcm11dGVfbWVhbnMgPSBmdW5jdGlvbihzdHJhaW4sIGxhYmVscywgZGF0YSwgbikgewogIHBlcm1NZWFucyA9IGxpc3QoKQogIGZvcihpIGluIDE6bil7CiAgICBwZXJtU2FtcGxlID0gc2FtcGxlKGRhdGEsIHJlcGxhY2U9RikKICAgIHBlcm1NZWFuc1tbaV1dID0gdGFwcGx5KHBlcm1TYW1wbGUsIGxhYmVscywgbWVhbikKICB9CiAgcmV0dXJuKGRvLmNhbGwocmJpbmQsIHBlcm1NZWFucykgJT4lIGFzX3RpYmJsZSgpICU+JSAKICAgIG11dGF0ZShzYW1wbGUgPSBzdHJhaW4pICU+JSByZW5hbWUobWVhbl9lc3MgPSB5ZXMsIG1lYW5fbm9uZXNzID0gYG5vdCBlc3NlbnRpYWxgKSkKfQoKcGVybVJlc3VsdCA9IE5VTEwKZm9yKHNhbXAgaW4gdW5pcXVlKGNudl9nZW5lcyRzdHJhaW4pKXsKICAgIGEgPSBjbnZfZ2VuZXMgJT4lCiAgICAgIGZpbHRlcihzdHJhaW4gPT0gc2FtcCkKICAgIHBlcm1SZXN1bHQgPSBwZXJtUmVzdWx0ICU+JQogICAgICBiaW5kX3Jvd3MocGVybXV0ZV9tZWFucyhzYW1wLCBhJGVzc19kZWwsIGEkaW5zZXJ0c19wZXJfbWlsbCwgbj0xZTYpKQp9CgoKdHJ1ZV9tZWFucyA9IGNudl9nZW5lcyAlPiUKICBncm91cF9ieShzdHJhaW4sIGVzc19kZWwpICU+JQogIHN1bW1hcmlzZShtZWFuX2lucyA9IG1lYW4oaW5zZXJ0c19wZXJfbWlsbCkpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBlc3NfZGVsLCB2YWx1ZXNfZnJvbSA9IG1lYW5faW5zKSAlPiUKICByZW5hbWUobWVhbl9lc3MgPSB5ZXMsIG1lYW5fbm9uZXNzID0gYG5vdCBlc3NlbnRpYWxgKQoKcGVybVJlc3VsdCAlPiUgCiAgcmVuYW1lKHN0cmFpbiA9IHNhbXBsZSkgJT4lCiAgZ2dwbG90KGFlcyhtZWFuX25vbmVzcy9tZWFuX2VzcykpICsKICBnZW9tX2hpc3RvZ3JhbSgpICsKICBnZW9tX3ZsaW5lKGRhdGEgPSB0cnVlX21lYW5zLCBhZXMoeGludGVyY2VwdCA9IG1lYW5fbm9uZXNzL21lYW5fZXNzKSkgKwogIGZhY2V0X3dyYXAofnN0cmFpbikgCgpwZXJtUmVzdWx0ICU+JQogIHJlbmFtZShzdHJhaW4gPSBzYW1wbGUpICU+JQogIGdyb3VwX2J5KHN0cmFpbikgJT4lCiAgbXV0YXRlKG1lYW5fcmF0aW8gPSBtZWFuX25vbmVzcy9tZWFuX2VzcykgJT4lCiAgZnVsbF9qb2luKHRydWVfbWVhbnMgJT4lIG11dGF0ZShtZWFuX3JhdGlvX3RydWUgPSBtZWFuX25vbmVzcy9tZWFuX2VzcykgJT4lIHNlbGVjdChzdHJhaW4sIG1lYW5fcmF0aW9fdHJ1ZSkpICU+JQogIHN1bW1hcmlzZShwX3ZhbCA9IHN1bShtZWFuX3JhdGlvID49IG1lYW5fcmF0aW9fdHJ1ZSkvMWU2LCBjaV8yLjUgPSBxdWFudGlsZShtZWFuX3JhdGlvLCBwcm9icyA9IDAuMDI1KSxjaV85Ny41ID0gcXVhbnRpbGUobWVhbl9yYXRpbywgcHJvYnMgPSAwLjk3NSkpCgoKZjJiID0gY252X2dlbmVzICU+JQogICNmdWxsX2pvaW4oc3RyYWluX25hbWVzLCBieSA9Yygic2FtcGxlIiA9ICJzdHJhaW4iKSkgJT4lCiAgZmlsdGVyKGdlbmUgIT0gIkdSRVNIQU1HRlAiKSAlPiUKICBtdXRhdGUoZXNzID0gaWZfZWxzZShlc3NfZGVsID09ICJ5ZXMiLCAiRXNzZW50aWFsIiwgIk5vbi1lc3NlbnRpYWwiKSkgJT4lCiAgZmlsdGVyKCFpcy5uYShzdHJhaW5fbmFtZXMpKSAlPiUKICBnZ3Bsb3QoYWVzKHN0cmFpbl9uYW1lcywgaW5zZXJ0c19wZXJfbWlsbCwgY29sb3IgPSBlc3MpKSArCiAgeWxhYigiTm9ybWFsaXplZCBpbnNlcnRpb25zIikgKwogIHhsYWIoIiIpICsKICBnZW9tX3BvaW50KGFscGhhPTAuNywgc2l6ZT0xLCBjZXggPSAwLjcsIHBvc2l0aW9uPXBvc2l0aW9uX2ppdHRlcmRvZGdlKCkpICsKICB0aGVtZV9idyhiYXNlX3NpemUgPSAyMikgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEsIGFscGhhPTAsIGx3ZD0xKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCcjZmI4MDcyJywnIzgwYjFkMycpLAogICAgICAgICAgICAgICAgICAgICBuYW1lID0gIiIsIGxhYmVscyA9IGMoIkVzc2VudGlhbCIsICJOb24tZXNzZW50aWFsIikpICsKICBzdGF0X3B2YWx1ZV9tYW51YWwoCiAgICBlc3NfdCAlPiUgcnN0YXRpeDo6YWRkX3h5X3Bvc2l0aW9uKHggPSAic3RyYWluX25hbWVzIiksIAogICAgeS5wb3NpdGlvbiA9IDE1MDAsCiAgICBsYWJlbCA9ICJzaWduaWYiLAogICAgc2l6ZT01CiAgICApICsKICBnZ3RpdGxlKCJCIikgKwogIHRoZW1lKGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9InRyYW5zcGFyZW50IiksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uPWMoLjg1LC43MykpIApgYGAKCmBgYHtyIHNmaWc0YX0Kc2ZpZ3Ffc2lnID0gaW5zZXJ0c19wZXJfbWlsbF9jZHMgJT4lIAogIGxlZnRfam9pbihlc3NfZGVsKSAlPiUKICBmaWx0ZXIoc3RyX3N0YXJ0cyhnZW5lLCAiWUsiKSkgJT4lCiAgYW50aV9qb2luKGNudl9nZW5lcykgJT4lCiAgbGVmdF9qb2luKHN0cmFpbl9uYW1lcykgJT4lCiAgZ3JvdXBfYnkoc2FtcGxlKSAlPiUgCiAgbXV0YXRlKGVzc19kZWwgPSBpZl9lbHNlKGlzLm5hKGVzc19kZWwpLCAibm90IGVzc2VudGlhbCIsIGVzc19kZWwpKSAlPiUgCiAgcnN0YXRpeDo6dF90ZXN0KGluc2VydHNfcGVyX21pbGwgfiBlc3NfZGVsKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKHNpZ25pZmljYW5jZSA9IGNhc2Vfd2hlbihwIDw9IDAuMDAwMSB+ICIqKioqIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHAgPiAwLjAxIH4gIm5zIikpCgpzZmlnNGEgPSBpbnNlcnRzX3Blcl9taWxsX2NkcyAlPiUgCiAgbGVmdF9qb2luKGVzc19kZWwpICU+JQogIGZpbHRlcihzdHJfc3RhcnRzKGdlbmUsICJZSyIpKSAlPiUKICBhbnRpX2pvaW4oY252X2dlbmVzKSAlPiUKICBncm91cF9ieShzYW1wbGUpICU+JSAKICBtdXRhdGUoZXNzX2RlbCA9IGlmX2Vsc2UoaXMubmEoZXNzX2RlbCksICJub3QgZXNzZW50aWFsIiwgZXNzX2RlbCkpICU+JQogIGdncGxvdChhZXMoc3RyYWluX25hbWVzLCBpbnNlcnRzX3Blcl9taWxsLCBjb2xvciA9IGVzc19kZWwpKSArCiAgeWxhYigiTm9ybWFsaXplZCBpbnNlcnRpb25zIikgKwogIHhsYWIoIiIpICsKICBnZW9tX3BvaW50KGFscGhhPTAuNywgc2l6ZT0xLCBjZXggPSAwLjcsIHBvc2l0aW9uPXBvc2l0aW9uX2ppdHRlcmRvZGdlKCkpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BLCBhbHBoYT0wLCBsd2Q9MSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygnIzgwYjFkMycsICcjZmI4MDcyJyksCiAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiIiwgbGFiZWxzID0gYygiTm9uLWVzc2VudGlhbCIsICJFc3NlbnRpYWwiKSkgKwogIHN0YXRfcHZhbHVlX21hbnVhbCgKICAgIHNmaWdxX3NpZyAlPiUgcnN0YXRpeDo6YWRkX3h5X3Bvc2l0aW9uKHggPSAic2FtcGxlIiksIAogICAgeS5wb3NpdGlvbiA9IDE1MDAsCiAgICBsYWJlbCA9ICJzaWduaWZpY2FuY2UiCiAgICApICsKICB0aGVtZShsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSJ0cmFuc3BhcmVudCIpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbj1jKC44NSwuNzMpKSAKCnNmaWc0YQpgYGAKCgpgYGB7ciBmaWcyY30KIyBldXBsb2lkIGluc2VydGlvbiBudW1iZXIgcHJlZGljdHMgY252IGluc2VydGlvbiBudW1iZXIKdHQgPSB0ICU+JSBtdXRhdGUoY29tbW9uX25hbWUgPSBsYWJ0b29sczo6eWVhc3Rfc3lzdGVtYXRpY190b19jb21tb24oZ2VuZSksIG1lYW4xNjU3ID0gKGAxNjU3XzFgK2AxNjU3XzJgKS8yKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IHN0YXJ0c193aXRoKCIxIiksIG5hbWVzX3RvID0gInN0cmFpbiIsIHZhbHVlc190byA9ICJpbnNlcnRzX3Blcl9taWxsIikKCmFtcF9yZWdyZXNzID0gTlVMTApoaWdoX3Jlc2lkcyA9IE5VTEwKZm9yKHNhbXAgaW4gdW5pcXVlKHR0JHN0cmFpbikpIHsKICB0eCA9IHR0ICU+JSBmaWx0ZXIoc3RyYWluID09IHNhbXApICU+JQogICAgZmlsdGVyKCFpcy5uYShpbnNlcnRzX3Blcl9taWxsKSkKICBmaXQ9bG0odHgkaW5zZXJ0c19wZXJfbWlsbH50eCRtZWFuMTY1NykKICBpbnRlcmNlcHQgPSBmaXQkY29lZmZpY2llbnRzWzFdCiAgaW50ZXJjZXB0X3B2YWwgPSBzdW1tYXJ5KGZpdCkkY29lZmZpY2llbnRzWyw0XVsxXQogIHNsb3BlID0gZml0JGNvZWZmaWNpZW50c1syXQogIHNsb3BlX2NpMi41ID0gY29uZmludChmaXQsIDIsIGxldmVsPTAuOTUpWzFdCiAgc2xvcGVfY2k5Ny41ID0gY29uZmludChmaXQsIDIsIGxldmVsPTAuOTUpWzJdCiAgc2xvcGVfcHZhbCA9IHN1bW1hcnkoZml0KSRjb2VmZmljaWVudHNbLDRdWzJdCiAgYWRqcjIgPSBzdW1tYXJ5KGZpdCkkYWRqLnIuc3F1YXJlZAogIHJlc2lkX3NkID0gc2lnbWEoZml0KQogIG5fZ3JlYXRlcjJzaWdtYSA9IHN1bShhYnMoZml0JHJlc2lkdWFscykgPiBtZWFuKGZpdCRyZXNpZHVhbHMpICsgcmVzaWRfc2QqMikKICBuX2FtcF9nZW5lcyA9IHR4JGNvbW1vbl9uYW1lW2FicyhmaXQkcmVzaWR1YWxzKSA+IG1lYW4oZml0JHJlc2lkdWFscykgKyByZXNpZF9zZCoyXQogIGhpZ2hfcmVzaWRzID0gaGlnaF9yZXNpZHMgJT4lIGJpbmRfcm93cyh0aWJibGUoc3RyYWluID0gc2FtcCwgY29tbW9uX25hbWUgPSBuX2FtcF9nZW5lcywgaGlnaF9yZXNpZCA9ICJ5ZXMiKSkKICBhbXBfcmVncmVzcyA9IGFtcF9yZWdyZXNzICU+JSBiaW5kX3Jvd3ModGliYmxlKHNhbXAsIGludGVyY2VwdCwgaW50ZXJjZXB0X3B2YWwsIHNsb3BlLCBzbG9wZV9wdmFsLCBzbG9wZV9jaTIuNSwgc2xvcGVfY2k5Ny41LCBhZGpyMiwgcmVzaWRfc2QsIG5fZ3JlYXRlcjJzaWdtYSkpCn0KCmYyYyA9IHR0ICU+JSBsZWZ0X2pvaW4oaGlnaF9yZXNpZHMpICU+JSAKICBtdXRhdGUobGFiZWwgPSBpZl9lbHNlKGlzLm5hKGhpZ2hfcmVzaWQpLCAiIixjb21tb25fbmFtZSkpICU+JQogIGxlZnRfam9pbihzdHJhaW5fbmFtZXMpICU+JQogIGZpbHRlcihzdHJhaW4gIT0gIjE2NTdfMSIsIHN0cmFpbiAhPSAiMTY1N18yIikgJT4lCiAgZmlsdGVyKCFpcy5uYShpbnNlcnRzX3Blcl9taWxsKSwgbWVhbjE2NTcgPCA3NTApICU+JQogIGdncGxvdChhZXMobWVhbjE2NTcsIGluc2VydHNfcGVyX21pbGwsIGxhYmVsPWxhYmVsKSkgKwogICNnZ2lyYXBoOjpnZW9tX3BvaW50X2ludGVyYWN0aXZlKGFlcyhkYXRhX2lkID0gY29tbW9uX25hbWUsIHRvb2x0aXAgPSBjb21tb25fbmFtZSksIGFscGhhID0gMC41KSArCiAgICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gJ2xtJywgc2U9RkFMU0UsIGNvbG9yPSJibGFjayIpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGhpZ2hfcmVzaWQpLGFscGhhPTAuNSkgKwogICAgIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChib3gucGFkZGluZyA9IDAuNSwgc2l6ZSA9IDMuNSwgc2VnbWVudC5zaXplID0gMC4yLCBjb2xvciA9ICJibGFjayIsbWF4Lm92ZXJsYXBzPTEwMCkgKwogICAgIGZhY2V0X3dyYXAofnN0cmFpbl9uYW1lcywgbmNvbCA9IDEpICsKICAgICB0aGVtZV9idyhiYXNlX3NpemU9MTYpICsKICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICB5bGFiKCJDTlYgc3RyYWluIG5vcm1hbGl6ZWQgaW5zZXJ0aW9ucyIpICsKICB4bGFiKCJFdXBsb2lkIG5vcm1hbGl6ZWQgaW5zZXJ0aW9ucyIpICsKICBnZW9tX3RleHQoZGF0YSA9IGFtcF9yZWdyZXNzICU+JQogICAgICAgICAgICAgICBsZWZ0X2pvaW4oc3RyYWluX25hbWVzLCBieT1jKCJzYW1wIiA9ICJzdHJhaW4iKSkgJT4lCiAgICAgICAgICAgICAgIGZpbHRlcihzYW1wICE9ICIxNjU3XzEiLCBzYW1wICE9ICIxNjU3XzIiKSwgCiAgICAgICAgICAgICBhZXMoMzM1LCAxMDAwLCBsYWJlbCA9IHBhc3RlKCJBZGogUjIgPSAiLCByb3VuZChhZGpyMiwyKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNsb3BlID0iLCByb3VuZChzbG9wZSwyKSwgIlxuIikpLAogICAgICAgICAgICAgc2l6ZT00KSArCiAgZ2d0aXRsZSgiQyIpCiAgCmBgYAoKCmBgYHtyIGZpZzJ9Cmdnc2F2ZShwYXN0ZTAoZmlnX2RpciwiL0ZpZzJCLnBkZiIpLCBwbG90ID0gZjJiLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSA4LCB1bml0cyA9ICJpbiIpCmdnc2F2ZShwYXN0ZTAoZmlnX2RpciwiL0ZpZzJDLnBkZiIpLCBwbG90ID0gZjJjLCB3aWR0aCA9IDYsIGhlaWdodCA9IDE0LCB1bml0cyA9ICJpbiIpCmdnc2F2ZShwYXN0ZTAoZmlnX2RpciwiL0ZpZzJCLnBuZyIpLCBwbG90ID0gZjJiLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSA4LCB1bml0cyA9ICJpbiIpCmdnc2F2ZShwYXN0ZTAoZmlnX2RpciwiL0ZpZzJDLnBuZyIpLCBwbG90ID0gZjJjLCB3aWR0aCA9IDYsIGhlaWdodCA9IDE0LCB1bml0cyA9ICJpbiIpCmBgYAoKYGBge3IgU0ZpZyA0Qn0KIyBub24tYW1wbGlmaWVkIGdlbmVzCnRlbXBvID0gaW5zZXJ0c19wZXJfbWlsbF9jZHMgJT4lIAogIHNlbGVjdChzdHJhaW5fbmFtZXMsIGluc2VydHNfcGVyX21pbGwsIGdlbmUpICU+JQogIGFudGlfam9pbihjbnZfZ2VuZXMgJT4lIHNlbGVjdChnZW5lLCBzdHJhaW5fbmFtZXMpKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gInN0cmFpbl9uYW1lcyIsIHZhbHVlc19mcm9tID0gImluc2VydHNfcGVyX21pbGwiKSAlPiUKICBtdXRhdGUobWVhbjE2NTcgPSAoZXVfMSArIGV1XzIpLzIpICU+JQogIHBpdm90X2xvbmdlcihjb2xzPWMoYW5ldSwgdHJpcDEsIHRyaXAyLCB0cmlwMywgdHJpcDQsIGlzbywgcXVhZCksIG5hbWVzX3RvPSJzdHJhaW4iLCB2YWx1ZXNfdG8gPSAiaW5zZXJ0c19wZXJfbWlsbCIpCgphbXBfcmVncmVzcyA9IE5VTEwKZm9yKHNhbXAgaW4gdW5pcXVlKHRlbXBvJHN0cmFpbikpIHsKICB0eCA9IHRlbXBvICU+JSBmaWx0ZXIoc3RyYWluID09IHNhbXApICU+JQogICAgZmlsdGVyKCFpcy5uYShpbnNlcnRzX3Blcl9taWxsKSkKICBmaXQ9bG0odHgkaW5zZXJ0c19wZXJfbWlsbH50eCRtZWFuMTY1NykKICBpbnRlcmNlcHQgPSBmaXQkY29lZmZpY2llbnRzWzFdCiAgaW50ZXJjZXB0X3B2YWwgPSBzdW1tYXJ5KGZpdCkkY29lZmZpY2llbnRzWyw0XVsxXQogIHNsb3BlID0gZml0JGNvZWZmaWNpZW50c1syXQogIHNsb3BlX2NpMi41ID0gY29uZmludChmaXQsIDIsIGxldmVsPTAuOTUpWzFdCiAgc2xvcGVfY2k5Ny41ID0gY29uZmludChmaXQsIDIsIGxldmVsPTAuOTUpWzJdCiAgc2xvcGVfcHZhbCA9IHN1bW1hcnkoZml0KSRjb2VmZmljaWVudHNbLDRdWzJdCiAgYWRqcjIgPSBzdW1tYXJ5KGZpdCkkYWRqLnIuc3F1YXJlZAogIHJlc2lkX3NkID0gc2lnbWEoZml0KQogIG5fZ3JlYXRlcjJzaWdtYSA9IHN1bShhYnMoZml0JHJlc2lkdWFscykgPiBtZWFuKGZpdCRyZXNpZHVhbHMpICsgcmVzaWRfc2QqMikKICBuX2FtcF9nZW5lcyA9IHR4JGNvbW1vbl9uYW1lW2FicyhmaXQkcmVzaWR1YWxzKSA+IG1lYW4oZml0JHJlc2lkdWFscykgKyByZXNpZF9zZCoyXQogIGFtcF9yZWdyZXNzID0gYW1wX3JlZ3Jlc3MgJT4lIGJpbmRfcm93cyh0aWJibGUoc2FtcCwgaW50ZXJjZXB0LCBpbnRlcmNlcHRfcHZhbCwgc2xvcGUsIHNsb3BlX3B2YWwsIHNsb3BlX2NpMi41LCBzbG9wZV9jaTk3LjUsIGFkanIyLCByZXNpZF9zZCwgbl9ncmVhdGVyMnNpZ21hKSkKfQoKc2ZpZzRiID0gdGVtcG8gJT4lIAogICNsZWZ0X2pvaW4oc3RyYWluX25hbWVzKSAlPiUKICAjZmlsdGVyKHN0cmFpbiAhPSAiMTY1N18xIiwgc3RyYWluICE9ICIxNjU3XzIiKSAlPiUKICAjZmlsdGVyKCFpcy5uYShpbnNlcnRzX3Blcl9taWxsKSwgbWVhbjE2NTcgPCA3NTApICU+JQogIGdncGxvdChhZXMobWVhbjE2NTcsIGluc2VydHNfcGVyX21pbGwpKSArCiAgI2dnaXJhcGg6Omdlb21fcG9pbnRfaW50ZXJhY3RpdmUoYWVzKGRhdGFfaWQgPSBjb21tb25fbmFtZSwgdG9vbHRpcCA9IGNvbW1vbl9uYW1lKSwgYWxwaGEgPSAwLjUpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAnbG0nLCBzZT1GQUxTRSwgY29sb3I9ImJsYWNrIikgKwogIGdlb21fcG9pbnQoYWxwaGE9MC41KSArCiAgICAgZmFjZXRfd3JhcCh+c3RyYWluKSArCiAgICAgdGhlbWVfYncoYmFzZV9zaXplPTE2KSArCiAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgeWxhYigiQ05WIHN0cmFpbiBub3JtYWxpemVkIGluc2VydGlvbnMiKSArCiAgeGxhYigiRXVwbG9pZCBub3JtYWxpemVkIGluc2VydGlvbnMiKSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBhbXBfcmVncmVzcyAlPiUgcmVuYW1lKHN0cmFpbiA9IHNhbXApLCAKICAgICAgICAgICAgIGFlcygxNTAsIDE1MDAsIGxhYmVsID0gcGFzdGUoIkFkaiBSMiA9ICIsIHJvdW5kKGFkanIyLDIpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2xvcGUgPSIsIHJvdW5kKHNsb3BlLDIpLCAiXG4iKSksCiAgICAgICAgICAgICBzaXplPTQpICsKICBnZ3RpdGxlKCJCIikKYGBgCgpgYGB7ciBzZmlnNH0KbGF5b3V0IDwtICIKQUJCCiIKc2ZpZzQ9c2ZpZzRhICsgc2ZpZzRiICsgcGxvdF9sYXlvdXQoZGVzaWduID0gbGF5b3V0KQoKZ2dzYXZlKHBhc3RlMChmaWdfZGlyLCIvU0ZpZzQucG5nIiksIHBsb3QgPSBzZmlnNCwgd2lkdGggPSAyMCwgaGVpZ2h0ID0gMTAsIHVuaXRzID0gImluIikKZ2dzYXZlKHBhc3RlMChmaWdfZGlyLCIvU0ZpZzQucGRmIiksIHBsb3QgPSBzZmlnNCwgd2lkdGggPSAyMCwgaGVpZ2h0ID0gMTAsIHVuaXRzID0gImluIikKYGBgCgoKIyMgR2VuZXMgd2l0aCBubyBpbnNlcnRpb25zIGluIGV1cGxvaWQsIGluc2VydGlvbnMgaW4gYWxsIENOViAoYW5kIHZpY2UgdmVyc2EpCgpgYGB7ciBzdXAgdGFibGUgMn0KeCA9IGluc2VydHNfcGVyX21pbGxfY2RzICU+JSBmaWx0ZXIoc2FtcGxlICVpbiUgYygiMTY1N18xIiwgIjE2NTdfMiIpKSAlPiUKICBncm91cF9ieShnZW5lKSAlPiUKICBzdW1tYXJpc2Uobl9pbnMgPSBzdW0oaW5zZXJ0cykpICU+JSBmaWx0ZXIobl9pbnMgPT0gMCkKc3RhYjIgPSB4ICU+JSBsZWZ0X2pvaW4oZXNzX2RlbCkgJT4lCiAgbGVmdF9qb2luKGZpdF9nYWwsIGJ5ID0gYygiZ2VuZSIgPSAiU3lzdGVtYXRpYyBOYW1lIikpICU+JQogIG11dGF0ZShsb3dfZml0bmVzc19nYWwgPSBpZl9lbHNlKEdhbGFjdG9zZSA8IDEsICJsb3cgZml0bmVzcyBnYWxhY3Rvc2UiLCAiIikpCgpzdGFiMiAlPiUgCiAgc3VtbWFyaXNlKG4gPSBuKCksCiAgICAgICAgICAgIG5fZXNzID0gc3VtKCFpcy5uYShlc3NfZGVsKSksCiAgICAgICAgICAgIG5fbG93Zml0X2dhbCA9IHN1bShHYWxhY3Rvc2UgPCAxICYgIWlzLm5hKEdhbGFjdG9zZSkpLAogICAgICAgICAgICBuX25vdGVzcyA9IHN1bShpcy5uYShlc3NfZGVsKSksCiAgICAgICAgICAgIG5fbm90X2dhbCA9IG4oKS1zdW0oR2FsYWN0b3NlIDwgMSAmICFpcy5uYShHYWxhY3Rvc2UpKSwKICAgICAgICAgICAgbl9lc3Nfb3JfbG93Zml0Z2FsID0gc3VtKCFpcy5uYShlc3NfZGVsKSB8IChHYWxhY3Rvc2UgPCAxICYgIWlzLm5hKEdhbGFjdG9zZSkpKSkKCndyaXRlX2NzdihzdGFiMiAlPiUgCiAgICAgICAgICAgIHNlbGVjdChnZW5lLCBgR2VuZSBOYW1lYCwgZXNzX2RlbCwgR2FsYWN0b3NlLCBsb3dfZml0bmVzc19nYWwpLCBwYXN0ZTAoZmlnX2RpciwgIi9TdXBwbGVtZW50YXJ5VGFibGUyLmNzdiIpKQpgYGAKCgpgYGB7ciBmaWcgM2F9CiMgY2hlY2sgYWxsIHRoYXQgaGF2ZSBpbnNlcnRzCmYzYT1pbnNlcnRzX3Blcl9taWxsX2NkcyAlPiUgCiAgbXV0YXRlKG1lZGlhbl9pbnNlcnRzX3Blcl9taWxsID0gbWVkaWFuKGluc2VydHNfcGVyX21pbGwpKSAlPiUKICBmaWx0ZXIoZ2VuZSAlaW4lIHB1bGwoeCxnZW5lKSkgJT4lCiAgZ3JvdXBfYnkoZ2VuZSkgJT4lCiAgZmlsdGVyKCEoc2FtcGxlICVpbiUgYygiMTY1N18xIiwgIjE2NTdfMiIpKSkgJT4lCiAgbXV0YXRlKGFsbF9zdHJhaW5zID0gc3VtKGluc2VydHMpKSAlPiUKICBmaWx0ZXIoYWxsX3N0cmFpbnMgPiAwKSAlPiUKICBtdXRhdGUoYWxsX2cwID0gYWxsKGluc2VydHMgPiAwKSkgJT4lCiAgZmlsdGVyKGFsbF9nMCA9PSBUKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbGVmdF9qb2luKGNudl9nZW5lcykgJT4lCiAgbXV0YXRlKGNvbW1vbl9uYW1lID0gbGFidG9vbHM6OnllYXN0X3N5c3RlbWF0aWNfdG9fY29tbW9uKGdlbmUpKSAlPiUKICBmaWx0ZXIoIWlzLm5hKGNvbW1vbl9uYW1lKSkgJT4lCiAgZ2dwbG90KGFlcyhjb21tb25fbmFtZSwgaW5zZXJ0c19wZXJfbWlsbCwgZmlsbCA9IHN0cmFpbl9uYW1lcykpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiLCB3aWR0aCA9IDAuOCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHN0cmFpbl9jb2xzWzQ6MTBdKSArCiAgZ2VvbV9hYmxpbmUoYWVzKGludGVyY2VwdCA9IG1lZGlhbl9pbnNlcnRzX3Blcl9taWxsLCBzbG9wZT0wKSwKICAgICAgICAgICAgICAgIGNvbG9yPSJhenVyZTQiLCBzaXplPTAuNzUpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gY29weV9udW1iZXIsIHggPSBjb21tb25fbmFtZSwgeSA9IGluc2VydHNfcGVyX21pbGwpLCAKICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksIHZqdXN0ID0gLTAuNiwgc2l6ZT01LjUpICsKICB5bGFiKCJJbnNlcnRpb25zIHBlciBtaWxsaW9uIikgKwogIHRoZW1lKGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCkpICsKICB4bGFiKCIiKQogIAoKZ2dzYXZlKHBhc3RlMChmaWdfZGlyLCIvRmlnM2EucGRmIiksIHBsb3QgPSBmM2EsIHdpZHRoID0gMTIsIGhlaWdodCA9IDYuNSwgdW5pdHMgPSAiaW4iKQoKYGBgCgpgYGB7cn0KIyMjIEZpbmQgZ2VuZXMgdGhhdCBoYXZlIGluc2VydGlvbnMgaW4gYm90aCByZXBsaWNhdGVzIG9mIDE2NTcKeCA9IHB1bGwoaW5zZXJ0c19wZXJfbWlsbF9jZHMgJT4lIGZpbHRlcihzYW1wbGUgJWluJSBjKCIxNjU3XzEiLCAiMTY1N18yIikpICU+JQogIGdyb3VwX2J5KGdlbmUpICU+JQogICAgbXV0YXRlKG9uZSA9IGNhc2Vfd2hlbihzYW1wbGUgPT0gIjE2NTdfMSIgJiBpbnNlcnRzID4gMCB+ICJ5ZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGUgPT0gIjE2NTdfMiIgJiBpbnNlcnRzID4gMCB+ICJ5ZXMiKSkgJT4lCiAgc3VtbWFyaXNlKG5faW5zID0gc3VtKG9uZSA9PSAieWVzIikpICU+JSBmaWx0ZXIobl9pbnMgPT0gMiksIGdlbmUpCgojIGNoZWNrIGFsbCB0aGF0IGhhdmUgaW5zZXJ0cwppbnNlcnRzX3Blcl9taWxsX2NkcyAlPiUgCiAgZmlsdGVyKGdlbmUgJWluJSB4KSAlPiUKICBncm91cF9ieShnZW5lKSAlPiUKICBmaWx0ZXIoIShzYW1wbGUgJWluJSBjKCIxNjU3XzEiLCAiMTY1N18yIikpKSAlPiUKICBtdXRhdGUoYWxsX3N0cmFpbnMgPSBzdW0oaW5zZXJ0cykpICU+JQogIGZpbHRlcihhbGxfc3RyYWlucyA9PSAwKSAlPiUKICB1bmdyb3VwKCkgIyU+JQpgYGAKCiMjIERpZmZlcmVudGlhbCBhbmFseXNpcyB3aXRoIERFU2VxCgpgYGB7cn0KY291bnRfZGZfY2RzID0gaW5zZXJ0X3Byb2ZpbGVzICU+JQogIGZpbHRlcih0eXBlID09ICJjZHMiKSAlPiUKICBzZWxlY3QoZ2VuZSwgbl9pbnNlcnRpb25zLCBzYW1wbGUpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSAic2FtcGxlIiwgdmFsdWVzX2Zyb20gPSAibl9pbnNlcnRpb25zIikKYGBgCgpgYGB7cn0KIyBmaXJzdCBhbGwgY2RzCmRpZmZfYW5hbHlzaXNfY2RzID0gTlVMTApnc2VhX2Nkcz1OVUxMCgpmb3Ioc3RyYWluIGluIGMoIjE3MjgiLCAiMTczNCIsICIxNzM2IiwgIjE3NDAiLCAiMTc0NCIsICIxNzQ3IiwgIjE3NTEiKSkgewogIGNvdW50cyA9IGFzLmRhdGEuZnJhbWUoY291bnRfZGZfY2RzKSAlPiUgZHBseXI6OnNlbGVjdChgMTY1N18xYCwgYDE2NTdfMmAsIHN0cmFpbikKICByb3duYW1lcyhjb3VudHMpID0gY291bnRfZGZfY2RzJGdlbmUKICBjb2xkYXRhID0gZGF0YS5mcmFtZSh0eXBlID0gYygid3QiLCAid3QiLCAiY252IiksIHNhbXBsZSA9IGMoJzE2NTdfMScsJzE2NTdfMicsc3RyYWluKSwgcm93Lm5hbWVzID0gY29sbmFtZXMoY291bnRzKSkKICBjb2xkYXRhJHR5cGUgPSBmYWN0b3IoY29sZGF0YSR0eXBlLCBsZXZlbHMgPSBjKCd3dCcsICdjbnYnKSkKICBkZHMgPC0gREVTZXFEYXRhU2V0RnJvbU1hdHJpeChjb3VudERhdGEgPSBjb3VudHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGEgPSBjb2xkYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXNpZ24gPSB+IHR5cGUpCiAgZGRzIDwtIERFU2VxKGRkcykKICByZXMgPC0gcmVzdWx0cyhkZHMsIGFscGhhPTAuMDUpCiAgZGlmZl9hbmFseXNpc19jZHMgPSBiaW5kX3Jvd3MoZGlmZl9hbmFseXNpc19jZHMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc190aWJibGUocmVzKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGdlbmUgPSByb3duYW1lcyhyZXMpLCBzdHJhaW4gPSBzdHJhaW4pKQogIGdlbmVMaXN0ID0gcmVzJGxvZzJGb2xkQ2hhbmdlI1stMV0gI3JlbW92ZSBHUkVTSEFNR0ZQCiAgZ2VuZS5kZiA8LSBiaXRyKHJvd25hbWVzKHJlcyksIGZyb21UeXBlID0gIk9SRiIsICNbLTFdCiAgICAgICAgdG9UeXBlID0gIkVOVFJFWklEIiwKICAgICAgICBPcmdEYiA9IG9yZy5TYy5zZ2QuZGI6Om9yZy5TYy5zZ2QuZGIpCiAgbmFtZXMoZ2VuZUxpc3QpID0gZ2VuZS5kZiRFTlRSRVpJRAogIGdlbmVMaXN0ID0gc29ydChnZW5lTGlzdCwgZGVjcmVhc2luZyA9IFRSVUUpCiAgZWdvIDwtIGdzZUdPKGdlbmVMaXN0ICAgICA9IGdlbmVMaXN0LAogICAgICAgICAgICAgT3JnRGIgICAgICAgID0gb3JnLlNjLnNnZC5kYjo6b3JnLlNjLnNnZC5kYiwKICAgICAgICAgICAgIGtleVR5cGUgPSAiRU5UUkVaSUQiLAogICAgICAgICAgICAgIG9udCAgICAgICAgICA9ICJCUCIsCiAgICAgICAgICAgICAgbWluR1NTaXplICAgID0gMTAsCiAgICAgICAgICAgICAgbWF4R1NTaXplICAgID0gNTAwLAogICAgICAgICAgICAgIHB2YWx1ZUN1dG9mZiA9IDAuMDUsCiAgICAgICAgICAgICAgcEFkanVzdE1ldGhvZD0iZmRyIiwKICAgICAgICAgICAgICB2ZXJib3NlICAgICAgPSBGQUxTRSwKICAgICAgICAgICAgICBieT0iZmdzZWEiLAogICAgICAgICAgICAgc2VlZCA9IDEpCiAgZWdvID0gY2x1c3RlclByb2ZpbGVyOjpzaW1wbGlmeShlZ28pCiAgZ3NlYV9jZHMgPSBiaW5kX3Jvd3MoZ3NlYV9jZHMsIGFzX3RpYmJsZShlZ29AcmVzdWx0KSAlPiUgbXV0YXRlKHNhbXBsZSA9IHN0cmFpbikpCn0KI3dyaXRlIG91dCBzbyB0aGlzIGRvZXNuJ3QgaGF2ZSB0byBydW4gYWdhaW4KIyB0aGVzZSB3aWxsIHByb2JhYmx5IGFsc28gYmUgc3VwcGxlbWVudGFyeSBmaWxlcwp3cml0ZV9jc3YoZ3NlYV9jZHMsIHBhc3RlMChkYXRhX2RpciwiL2dzZWFfY2RzLmNzdiIpKQp3cml0ZV9jc3YoZGlmZl9hbmFseXNpc19jZHMsIHBhc3RlMChkYXRhX2RpciwiL2RpZmZfYW5hbHlzaXNfY2RzLmNzdiIpKQpgYGAKCmdzZWFfY2RzX2Fubm90YXRlZC5jc3YgaXMgYWxzbyBTVGFibGUgMwoKYGBge3IgZmlnIDNifQojIEkgYW0gZG9pbmcgc29tZSBtYW51YWwgY29uc29saWRhdGlvbiBvZiB0ZXJtcyBiYXNlZCBvbiB0aGUgb3ZlcmxhcCBvZiB0aGUgY29yZSBlbnJpY2htZW50IGJldHdlZW4gdGVybXMKI3RyYW5zbGF0aW9uLCBwZXB0aWRlIG1ldGFib2xpYyBwcm9jZXNzLCBhbmQgcGVwdGlkZSBiaW9zeW50aGV0aWMgcHJvY2VzcyBoYXZlIGhpZ2hseSBvdmVybGFwcGluZyBjb3JlIGVucmljaG1lbnQsIGtlZXBpbmcgbWV0YWJvbGljIHByb2Nlc3MKIyByaWJvc29tYWwgbGFyZ2Ugc3VidW5pdCBiaW9nZW5lc2lzIGFuZCBtYXR1cmF0aW9uIG9mIExTVS1yUk5BIGhhdmUgbGFyZ2Ugb3ZlcmxhcCwga2VlcGluZyByaWJvc29tYWwgbGFyZ2Ugc3VidW5pdCBiaW9nZW5lc2lzCiMgY2VsbHVsYXIgbW9ub3ZhbGVudCBpbm9yZ2FuaWMgY2F0aW9uIGhvbWVvc3Rhc2lzIGFuZCBtb25vdmFsZW50IGlub3JnYW5pYyBjYXRpb24gaG9tZW9zdGFzaXMgaWRlbnRpY2FsLCBrZWVwaW5nIG1vbm92YWxlbnQgaW5vcmdhbmljIGNhdGlvbiBob21lb3N0YXNpcwojIG1pdG9jaG9uZHJpYWwgcmVzcGlyYXRvcnkgY2hhaW4gY29tcGxleCBhc3NlbWJseSBhbmQgY3l0b2Nocm9tZSBjb21wbGV4IGFzc2VtYmx5IHZlcnkgc2ltaWxhciwga2VlcGluZyBtaXRvY2hvbmRyaWFsIHJlc3BpcmF0b3J5IGNoYWluIGNvbXBsZXggYXNzZW1ibHkKIyBlbGVjdHJvbiB0cmFuc3BvcnQgY2hhaW4gYW5kIGFlcm9iaWMgZWxlY3Ryb24gdHJhbnNwb3J0IGNoYWluIHZlcnkgc2ltaWxhciwga2VlcGluZyBhZXJvYmljIGVsZWN0cm9uIHRyYW5zcG9ydCBjaGFpbgojIEFUUCBiaW9zeW50aGV0aWMgcHJvY2VzcywgZW5lcmd5IGNvdXBsZWQgcHJvdG9uIHRyYW5zcG9ydCBkb3duIGVsZWN0cm9jaGVtaWNhbCBncmFkaWVudCBhbmQgQVRQIHN5bnRoZXNpcyBjb3VwbGVkIHByb3RvbiB0cmFuc3BvcnQgaWRlbnRpY2FsLCBrZWVwaW5nIEFUUCBzeW50aGVzaXMgY291cGxlZCBwcm90b24gdHJhbnNwb3J0CgpmM2I9IHJlYWRfY3N2KHBhc3RlMChkYXRhX2RpciwiL2dzZWFfY2RzX2Fubm90YXRlZC5jc3YiKSkgJT4lIAogIGZpbHRlcihLZWVwID09ICJZZXMiKSAlPiUKICBtdXRhdGUoc3RyYWluID0gYXMuY2hhcmFjdGVyKHNhbXBsZSkpICU+JQogIGZ1bGxfam9pbihzdHJhaW5fbmFtZXMpICU+JQogIGZpbHRlcighaXMubmEoRGVzY3JpcHRpb24pKSAlPiUKICBhZGRfcm93KHN0cmFpbl9uYW1lcyA9IGMoInRyaXAzIiwgInRyaXA0IiksIAogICAgICAgICAgRGVzY3JpcHRpb24gPSBjKCJyaWJvbnVjbGVvcHJvdGVpbiBjb21wbGV4IGJpb2dlbmVzaXMiLCJyaWJvbnVjbGVvcHJvdGVpbiBjb21wbGV4IGJpb2dlbmVzaXMiKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gc3RyYWluX25hbWVzLCB5ID0gcmVvcmRlcihEZXNjcmlwdGlvbiwgT3JkZXIqLTEpLCAKICAgICAgICAgICBjb2xvciA9IGVucmljaG1lbnRTY29yZSkpICsKICBnZW9tX3BvaW50KGFlcyhzaXplID0gcC5hZGp1c3QpKSArCiAgc2NhbGVfc2l6ZSgicCBhZGp1c3QiLCB0cmFucz0ibG9nMTAiLCByYW5nZT1jKDE1LCA1KSwgYnJlYWtzPWMoMWUtMTAsIDFlLTgsIDFlLTYsIDFlLTQsIDFlLTIpLCBsaW1pdHMgPSBjKDFlLTEwLCAuMDUpKSArCiAgZ2d0aXRsZSgiQmlvbG9naWNhbCBQYXRod2F5IikrCiAgeGxhYigiIikrCiAgeWxhYigiIikrCiAgc2NhbGVfY29sb3VyX2dyYWRpZW50Mihsb3cgPSAiYmx1ZSIsIG1pZCA9ICJ3aGl0ZSIsIGhpZ2ggPSAicmVkIiwgYnJlYWtzID0gYygtMC44LCAwLCAwLjgpKSAKCmdnc2F2ZShwYXN0ZTAoZmlnX2RpciwiL0ZpZzNiLnBkZiIpLCBwbG90ID0gZjNiLCB3aWR0aCA9IDEzLCBoZWlnaHQgPSA5LCB1bml0cyA9ICJpbiIpCmBgYAoKYGBge3IgZmlnIDNjfQpkaWZmX2FuYWx5c2lzX2NkcyA9IHJlYWRfY3N2KHBhc3RlMChkYXRhX2RpciwiL2RpZmZfYW5hbHlzaXNfY2RzLmNzdiIpKQoKZjNjID0gZGlmZl9hbmFseXNpc19jZHMgJT4lCiAgZmlsdGVyKHBhZGogPCAwLjA1KSAlPiUKICBtdXRhdGUoc3RyYWluID0gYXMuY2hhcmFjdGVyKHN0cmFpbikpICU+JQogIGxlZnRfam9pbihzdHJhaW5fbmFtZXMpICU+JQogIG11dGF0ZShjb21tb25fbmFtZSA9IGxhYnRvb2xzOjp5ZWFzdF9zeXN0ZW1hdGljX3RvX2NvbW1vbihnZW5lKSkgJT4lCiAgZmlsdGVyKGNvbW1vbl9uYW1lICE9ICJHUkVTSEFNR0ZQIikgJT4lCiAgbGVmdF9qb2luKGNudl9nZW5lcywgYnkgPSBjKCJzdHJhaW4iID0gInNhbXBsZSIsICJnZW5lIiA9ICJnZW5lIiwgInN0cmFpbl9uYW1lcyIgPSAic3RyYWluX25hbWVzIikpICU+JQogIG11dGF0ZShjb3B5X251bWJlciA9IGlmX2Vsc2UoaXMubmEoY29weV9udW1iZXIpLCIiLGFzLmNoYXJhY3Rlcihjb3B5X251bWJlcikpKSAlPiUKICBnZ3Bsb3QoYWVzKHN0cmFpbl9uYW1lcywgY29tbW9uX25hbWUsIGZpbGwgPSBsb2cyRm9sZENoYW5nZSkpICsKICBnZW9tX3RpbGUoKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudDIobG93ID0gImJsdWUiLCBtaWQgPSAid2hpdGUiLCBoaWdoID0gInJlZCIpICsKICB0aGVtZV9ncmV5KCkgKwogIHRoZW1lKHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKHNpemUgPSAwLjUsIGxpbmV0eXBlID0gInNvbGlkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSAiYmxhY2siKSkgKyAKICB4bGFiKCIiKSArCiAgeWxhYigiIikgKyAKICBnZW9tX3RleHQoYWVzKHN0cmFpbl9uYW1lcywgY29tbW9uX25hbWUsIGxhYmVsPWNvcHlfbnVtYmVyKSkgKwogIGxhYnMoZmlsbCA9ICJsb2cyRm9sZENoYW5nZVxuZm9yIHAuYWRqIDwgMC4wNSIpIAoKIyBjaGVjayBzaXplICMjIyMKZ2dzYXZlKHBhc3RlMChmaWdfZGlyLCIvRmlnM0MucGRmIiksIHBsb3QgPSBmM2MsIHdpZHRoID0gOSwgaGVpZ2h0ID0gNSwgdW5pdHMgPSAiaW4iKQpgYGAKCmBgYHtyIHNmaWc1YX0KIHNmaWc1YSA9IGRpZmZfYW5hbHlzaXNfY2RzICU+JQogICNmaWx0ZXIocGFkaiA8IDAuMDUpICU+JQogIGZpbHRlcihnZW5lICVpbiUgcHVsbChkaWZmX2FuYWx5c2lzX2NkcyAlPiUgZmlsdGVyKHBhZGogPCAwLjA1KSwgZ2VuZSkpICU+JQogIG11dGF0ZShzaWcgPSBjYXNlX3doZW4ocGFkaiA8IDAuMDAwMSB+ICIqKioqIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHBhZGogPCAwLjAwMSB+ICIqKioiLAogICAgICAgICAgICAgICAgICAgICAgICAgcGFkaiA8IDAuMDEgfiAiKioiLAogICAgICAgICAgICAgICAgICAgICAgICAgcGFkaiA8IDAuMDUgfiAiKiIsCiAgICAgICAgICAgICAgICAgICAgICAgICBpcy5uYShwYWRqKSB+ICIiLAogICAgICAgICAgICAgICAgICAgICAgICAgcGFkaiA+PSAwLjA1IH4gIiIpKSAlPiUKICBtdXRhdGUoc3RyYWluID0gYXMuY2hhcmFjdGVyKHN0cmFpbikpICU+JQogIGxlZnRfam9pbihzdHJhaW5fbmFtZXMpICU+JQogIG11dGF0ZShjb21tb25fbmFtZSA9IGxhYnRvb2xzOjp5ZWFzdF9zeXN0ZW1hdGljX3RvX2NvbW1vbihnZW5lKSkgJT4lCiAgZmlsdGVyKGNvbW1vbl9uYW1lICE9ICJHUkVTSEFNR0ZQIikgJT4lCiAgbGVmdF9qb2luKGNudl9nZW5lcyAlPiUgbXV0YXRlKHN0cmFpbiA9IHN0cl9yZW1vdmUoc3RyYWluLCAiREdZIikpKSAlPiUKICBtdXRhdGUoY29weV9udW1iZXIgPSBpZl9lbHNlKGlzLm5hKGNvcHlfbnVtYmVyKSwiIixhcy5jaGFyYWN0ZXIoY29weV9udW1iZXIpKSkgJT4lCiAgZ2dwbG90KGFlcyhzdHJhaW5fbmFtZXMsIGNvbW1vbl9uYW1lLCBmaWxsID0gbG9nMkZvbGRDaGFuZ2UpKSArCiAgZ2VvbV90aWxlKCkgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGxvdyA9ICJibHVlIiwgbWlkID0gIndoaXRlIiwgaGlnaCA9ICJyZWQiKSArCiAgdGhlbWVfY2xhc3NpYygpICsgCiAgeGxhYigiIikgKwogIHlsYWIoIiIpICsgCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1wYXN0ZShjb3B5X251bWJlciwgc2lnKSkpICsKICBsYWJzKGZpbGwgPSAibG9nMkZvbGRDaGFuZ2UiKQoKZ2dzYXZlKHBhc3RlMChmaWdfZGlyLCIvU0ZpZzVBLnBuZyIpLCBwbG90ID0gc2ZpZzVhLCB3aWR0aCA9IDksIGhlaWdodCA9IDUsIHVuaXRzID0gImluIikKYGBgCgo=