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
}
get_rpp = function(x, ver) {
filepath=paste0(data_dir,"/hpc_output/",ver,"/",x)
out = read_tsv(filepath, col_names = F, col_types = cols()) %>%
dplyr::rename(chromosome=X1, chr_pos=X2, reads=X3) %>%
mutate(sample = str_sub(x, 1, -16),
version = ver)
}
files = list.files(path = paste0(data_dir, '/hpc_output/combined/'),
pattern = '*readPerPos.txt')
read_per_pos = map(files, get_rpp, ver='combined')
rpp_df = do.call(rbind, read_per_pos)
summary_rpp = rpp_df %>%
left_join(strain_names, by = c("sample" = "strain")) %>%
group_by_at(vars(strain_names, sample)) %>%
rename(Gresham_ID = sample) %>%
summarize(total_sites = n(), min_rpp = min(reads), max_rpp = max(reads),
mean_rpp = mean(reads), median_rpp = median(reads))
summary_rpp %>%
knitr::kable() %>%
kableExtra::kable_styling()
write_csv(summary_rpp, paste0(fig_dir, "/SupplementaryTable1.csv"))
# 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")
#Supplemental_Fig_S9
# 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")
LS0tDQp0aXRsZTogIlRyYW5zcG9zb24gbXV0YWdlbmVzaXMgaW4gKkdBUDEqIENOViBzdHJhaW5zIg0KYXV0aG9yOiAiR3JhY2UgQXZlY2lsbGEiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQoNCmBgYHtyfQ0KbGlicmFyeShFbmhhbmNlZFZvbGNhbm8pDQpsaWJyYXJ5KERFU2VxMikNCmxpYnJhcnkob3JnLlNjLnNnZC5kYikNCmxpYnJhcnkoY2x1c3RlclByb2ZpbGVyKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHBhdGNod29yaykNCmxpYnJhcnkoZ2diZWVzd2FybSkNCmxpYnJhcnkoZ2dwdWJyKQ0KdGhlbWVfc2V0KHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDIwKSkNCg0KZGF0YV9kaXIgPSAiL1ZvbHVtZXMvR29vZ2xlRHJpdmUvTXkgRHJpdmUvR3Jlc2hhbSBMYWJfR3JhY2UvZnJhbmNlX3NhdGF5L0hlcm1lc19tdXRhZ2VuZXNpc19wYXBlci9kYXRhIg0KDQpmaWdfZGlyID0gIi9Wb2x1bWVzL0dvb2dsZURyaXZlL015IERyaXZlL0dyZXNoYW0gTGFiX0dyYWNlL2ZyYW5jZV9zYXRheS9IZXJtZXNfbXV0YWdlbmVzaXNfcGFwZXIvZmlndXJlcyINCg0Kc291cmNlKCIvVm9sdW1lcy9Hb29nbGVEcml2ZS9NeSBEcml2ZS9HcmVzaGFtIExhYl9HcmFjZS9mcmFuY2Vfc2F0YXkvSGVybWVzX211dGFnZW5lc2lzX3BhcGVyL2FuYWx5c2lzX3dfUFNfY29ycmVjdGlvbnMvZnVuY3Rpb25zLlIiKQ0KDQpzZXFfcnVucyA9IGMoImJnaTEiLCJiZ2kyIiwgIm55YzEiLCAibnljMiIpDQpgYGANCg0KYGBge3J9DQojIGdldCBhbGwgZ2VuZXMgZXhjbHVkaW5nIGR1YmlvdXMgb3JmcyBhbmQgdGhlaXIgY29weSBudW1iZXINCnN0cmFpbl9jbnMgPSByZWFkX2NzdihwYXN0ZTAoZGF0YV9kaXIsICIvZ2VuZV9tZWRpYW5fcmVsYXRpdmVfZGVwdGhfRE5BX2NvcnJlY3RlZF92My9nZW5lX21lZGlhbl9yZWxhdGl2ZV9kZXB0aF9ETkEtVGFibGUgMS5jc3YiKSkgJT4lIA0KICBzZWxlY3QoR2VuZSwgY29udGFpbnMoImNvciIpKSAlPiUNCiAgcGl2b3RfbG9uZ2VyKC1HZW5lLCBuYW1lc190byA9ICJzdHJhaW4iLCB2YWx1ZXNfdG8gPSAiY29weV9udW1iZXIiKSAlPiUNCiAgbXV0YXRlKHN0cmFpbiA9IHN0cl9leHRyYWN0KHN0cmFpbiwiWzAtOV17NH0iKSkgJT4lDQogIGxlZnRfam9pbihzdHJhaW5fbmFtZXMpDQoNCmFsbF9nZW5lcyA9IHN0cmFpbl9jbnMkR2VuZQ0KYGBgDQoNCiMgQ29ycmVsYXRpb24gYmV0d2VlbiBkaWZmZXJlbnQgc2VxdWVuY2luZyBtZXRob2RzDQpVc2luZyBpbnNlcnRpb25zIHBlciBnZW5lDQpgYGB7cn0NCmdldF9pcGcgPSBmdW5jdGlvbih4LCB2ZXIpew0KICBkYXRhID0gcmVhZF90c3YocGFzdGUwKGRhdGFfZGlyLCAiL2hwY19vdXRwdXQvIix2ZXIsICIvIiwgeCksIA0KICAgICAgICAgICAgICAgICAgY29sX3R5cGVzID0gY29scyhDRFM9Y29sX2NoYXJhY3RlcigpLGAjaW5zZXJ0aW9uYCA9IGNvbF9kb3VibGUoKSkpICU+JQ0KICAgIG11dGF0ZShzYW1wbGUgPSBzdHJfc3ViKHgsIDEsIC0yMiksIGdlbmU9TkEsDQogICAgICAgICAgIHJ1bj12ZXIpDQp9DQppcGdfZm9yY29yID0gTlVMTA0KZm9yKGkgaW4gc2VxX3J1bnMpIHsNCiAgaXBnX2ZpbGVzID0gbGlzdC5maWxlcyhwYXRoID0gcGFzdGUwKGRhdGFfZGlyLCAiL2hwY19vdXRwdXQvIiwgaSwgIi8iKSwgcGF0dGVybiA9ICcqaW5zZXJ0aW9uUGVyR2VuZS50eHQnKQ0KICBpcGdfdCA9IG1hcChpcGdfZmlsZXMsIGdldF9pcGcsIHZlcj1pKQ0KICBpcGdfZGZfdCA9IGRvLmNhbGwocmJpbmQsIGlwZ190KQ0KICBpcGdfZm9yY29yID0gaXBnX2ZvcmNvciAlPiUgDQogICAgYmluZF9yb3dzKGlwZ19kZl90ICU+JSB1bml0ZShzYW1wbGVfcmVwLCBzYW1wbGUsIHJ1bikpDQp9DQpgYGANCg0KYGBge3J9DQojIGdldCBjb3JyZWxhdGlvbnMNCmlwZ19mb3Jjb3IgPSBpcGdfZm9yY29yICU+JQ0KICBtdXRhdGUoc3RyYWluID0gc3RyX3N1YihzYW1wbGVfcmVwLCAxLCAtNiksDQogICAgICAgICByZXAgPSBzdHJfc3ViKHNhbXBsZV9yZXAsIC00LCAtMSkpICU+JQ0KICBsZWZ0X2pvaW4oc3RyYWluX25hbWVzKSAlPiUNCiAgdW5pdGUoc2FtcGxlX3JlcCwgc3RyYWluX25hbWVzLCByZXApICU+JQ0KICBkcGx5cjo6c2VsZWN0KENEUywgc2FtcGxlX3JlcCwgYCNpbnNlcnRpb25gKSAlPiUgDQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBzYW1wbGVfcmVwLCB2YWx1ZXNfZnJvbSA9IGAjaW5zZXJ0aW9uYCkgDQoNCg0KcmVwcyA9IGlwZ19mb3Jjb3IgJT4lDQogICAgZHBseXI6OnNlbGVjdChldV8xX255YzEsIGV1XzFfbnljMiwgZXVfMl9ueWMxLCBldV8yX255YzIpICANCmNvcl9wbG90cz1HR2FsbHk6OmdncGFpcnMocmVwcywgDQogICAgICAgICAgICAgICAgdXBwZXIgPSBsaXN0KGNvbnRpbnVvdXMgPSBHR2FsbHk6OndyYXAoImNvciIsIG1ldGhvZCA9ICJwZWFyc29uIikpKSArDQogICAgZ2d0aXRsZShMRVRURVJTWzFdKQ0KZ2dzYXZlKGNvcl9wbG90cywgZmlsZT1wYXN0ZTAoZmlnX2RpciwgIi9TRmlnWCIsIExFVFRFUlNbMV0sICIucGRmIiksIGhlaWdodCA9IDEwLCB3aWR0aCA9IDEwKQ0KDQppPTINCmZvcihzdHJhaW4gaW4gYygiYW5ldSIsICJ0cmlwMSIsICJ0cmlwMiIsICJ0cmlwMyIsICJ0cmlwNCIsICJpc28iLCAicXVhZCIpKSB7DQogIHJlcHMgPSBpcGdfZm9yY29yICU+JQ0KICAgIGRwbHlyOjpzZWxlY3QoY29sbmFtZXMoaXBnX2ZvcmNvcilbc3RyX2RldGVjdChjb2xuYW1lcyhpcGdfZm9yY29yKSwgc3RyYWluKV0pICANCiAgY29yX3Bsb3RzPUdHYWxseTo6Z2dwYWlycyhyZXBzLCANCiAgICAgICAgICAgICAgICB1cHBlciA9IGxpc3QoY29udGludW91cyA9IEdHYWxseTo6d3JhcCgiY29yIiwgbWV0aG9kID0gInBlYXJzb24iKSkpICsNCiAgICBnZ3RpdGxlKExFVFRFUlNbaV0pDQogIGdnc2F2ZShjb3JfcGxvdHMsIGZpbGU9cGFzdGUwKGZpZ19kaXIsICIvU0ZpZ1giLCBMRVRURVJTW2ldLCAiLnBkZiIpLCBoZWlnaHQgPSAxMCwgd2lkdGggPSAxMCkNCiAgaT1pKzENCn0NCg0KYGBgDQoNCmBgYHtyIGdldCByZWFkcyBwZXIgcG9zaXRpb259DQpnZXRfcnBwID0gZnVuY3Rpb24oeCwgdmVyKSB7DQogIGZpbGVwYXRoPXBhc3RlMChkYXRhX2RpciwiL2hwY19vdXRwdXQvIix2ZXIsIi8iLHgpDQogIG91dCA9IHJlYWRfdHN2KGZpbGVwYXRoLCBjb2xfbmFtZXMgPSBGLCBjb2xfdHlwZXMgPSBjb2xzKCkpICU+JQ0KICAgIGRwbHlyOjpyZW5hbWUoY2hyb21vc29tZT1YMSwgY2hyX3Bvcz1YMiwgcmVhZHM9WDMpICU+JQ0KICAgIG11dGF0ZShzYW1wbGUgPSBzdHJfc3ViKHgsIDEsIC0xNiksDQogICAgICAgICAgIHZlcnNpb24gPSB2ZXIpDQp9DQpmaWxlcyA9IGxpc3QuZmlsZXMocGF0aCA9IHBhc3RlMChkYXRhX2RpciwgJy9ocGNfb3V0cHV0L2NvbWJpbmVkLycpLA0KICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICcqcmVhZFBlclBvcy50eHQnKQ0KcmVhZF9wZXJfcG9zID0gbWFwKGZpbGVzLCBnZXRfcnBwLCB2ZXI9J2NvbWJpbmVkJykNCnJwcF9kZiA9IGRvLmNhbGwocmJpbmQsIHJlYWRfcGVyX3BvcykNCg0KYGBgDQoNCmBgYHtyIHN1cHBsZW1lbnRhcnkgdGFibGUgMSBsaWJyYXJ5IGNoYXJhY3RlcmlzdGljc30NCnN1bW1hcnlfcnBwID0gcnBwX2RmICU+JQ0KICBsZWZ0X2pvaW4oc3RyYWluX25hbWVzLCBieSA9IGMoInNhbXBsZSIgPSAic3RyYWluIikpICU+JQ0KICBncm91cF9ieV9hdCh2YXJzKHN0cmFpbl9uYW1lcywgc2FtcGxlKSkgJT4lIA0KICByZW5hbWUoR3Jlc2hhbV9JRCA9IHNhbXBsZSkgJT4lDQogIHN1bW1hcml6ZSh0b3RhbF9zaXRlcyA9IG4oKSwgbWluX3JwcCA9IG1pbihyZWFkcyksIG1heF9ycHAgPSBtYXgocmVhZHMpLA0KICAgICAgICAgICAgbWVhbl9ycHAgPSBtZWFuKHJlYWRzKSwgbWVkaWFuX3JwcCA9IG1lZGlhbihyZWFkcykpIA0Kc3VtbWFyeV9ycHAgJT4lDQogIGtuaXRyOjprYWJsZSgpICU+JQ0KICBrYWJsZUV4dHJhOjprYWJsZV9zdHlsaW5nKCkNCndyaXRlX2NzdihzdW1tYXJ5X3JwcCwgcGFzdGUwKGZpZ19kaXIsICIvU3VwcGxlbWVudGFyeVRhYmxlMS5jc3YiKSkNCmBgYA0KDQpgYGB7ciBzZmlnMn0NCiMgbnVtYmVyIG9mIGluc2VydGlvbiBzaXRlcyBzY2FsZXMgd2l0aCB0b3RhbCByZWFkcyBnZW5lcmF0ZWQNCnJlYWRzX3Blcl9saWIgPSByZWFkX2NzdihwYXN0ZTAoZGF0YV9kaXIsIi90b3RhbF9yZWFkc19wZXJfbGlicmFyeS5jc3YiKSkNCg0Kc2ZpZzIgPSByZWFkc19wZXJfbGliICU+JQ0KICBsZWZ0X2pvaW4oc3VtbWFyeV9ycHAsIGJ5ID0gYygiU2FtcGxlIj0iR3Jlc2hhbV9JRCIpKSAlPiUNCiAgZ2dwbG90KGFlcyh0b3RhbF9zaXRlcywgcmVhZHMsIGNvbG9yID0gc3RyYWluX25hbWVzKSkgKw0KICBnZW9tX3BvaW50KHNpemU9MikgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gc3RyYWluX2NvbHMpICsNCiAgeGxhYigiVW5pcXVlIGluc2VydGlvbiBzaXRlcyIpICsNCiAgeWxhYigiVG90YWwgcmVhZHMgIikgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpjb21tYSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpjb21tYSkgKw0KICB0aGVtZShsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpKQ0KDQpnZ3NhdmUocGFzdGUwKGZpZ19kaXIsIi9TRmlnMi5wZGYiKSwgcGxvdCA9IHNmaWcyLCB3aWR0aCA9IDguNSwgaGVpZ2h0ID0gNSwgdW5pdHMgPSAiaW4iKQ0KZ2dzYXZlKHBhc3RlMChmaWdfZGlyLCIvU0ZpZzIucG5nIiksIHBsb3QgPSBzZmlnMiwgd2lkdGggPSA4LjUsIGhlaWdodCA9IDUsIHVuaXRzID0gImluIikNCmBgYA0KDQoNCiNTdXBwbGVtZW50YWxfRmlnX1M5DQoNCmBgYHtyIFN1cHBsZW1lbnRhbF9GaWdfUzl9DQojIGVzc2VudGlhbCBnZW5lcyBoYXZlIGZld2VyIGluc2VydGlvbnMNCmdldF9jZHNfcHJvbW90ZXIgPSBmdW5jdGlvbih4LCB5KXsNCiAgeSA9IHkgJT4lIGRwbHlyOjpmaWx0ZXIoc3RyX3N0YXJ0cyhYOSwgcGFzdGUwKHgsICc7JykpKQ0KICBpZihucm93KHkpID4gMSkgew0KICAgIHkkWDQgPSBtaW4oeSRYNCkNCiAgICB5JFg1ID0gbWF4KHkkWDUpDQogIH0NCiAgY2hyb21vc29tZSA9IHkkWDENCiAgc3RyYW5kID0geSRYNw0KICBpZihzdHJhbmRbMV0gPT0gJysnKSB7DQogICAgc3RhcnQgPSB5JFg0DQogICAgc3RvcCA9IHkkWDUNCiAgICBwcm9tb3RlciA9IHkkWDQgLSAyMDANCiAgfSBlbHNlIHsNCiAgICBzdGFydCA9IHkkWDUNCiAgICBzdG9wID0geSRYNA0KICAgIHByb21vdGVyID0geSRYNSArIDIwMA0KICB9DQogIHJldHVybih0aWJibGUoY2hyb21vc29tZSwgc3RhcnQsIHN0b3AsIHByb21vdGVyLCBzdHJhbmQpWzEsXSkNCn0NCiMgeCBpcyBhIGdlbmUgdGhhdCBJIHdhbnQgdG8gZ2V0IGluZm8gZm9yIChpbiAiSUQ9Y2RzMCIgZm9ybSksIGluc2VydHMgaXMgdGhlIHJlYWRzIHBlciBwb3NpdGlvbiBmaWxlIA0KIyB3aWxsIHJldHVybiBmb3IgZWFjaCBzYW1wbGUgaW4gaW5zZXJ0cw0KZ2V0X2Jpbm5lZF91bmlxdWVfaW5zZXJ0aW9ucyA9IGZ1bmN0aW9uKHgsIGluc2VydHMpew0KICB5ID0gZ2V0X2Nkc19wcm9tb3Rlcih4LCB5ID0gZ2ZmX2NkcykNCiAgYmluX3NpemVfY2RzID0gKHkkc3RhcnQgLSB5JHN0b3ApLzEwMA0KICBjZHM9TlVMTA0KICBwcm9tbz1OVUxMDQogIGZvcihpIGluIHVuaXF1ZShpbnNlcnRzJHNhbXBsZSkpIHsNCiAgICBiaW5fZmlsbF9jZHMgPSBOVUxMDQogICAgYmluX2ZpbGxfcHJvbSA9IE5VTEwNCiAgICBpbmkgPSBpbnNlcnRzICU+JSBkcGx5cjo6ZmlsdGVyKHNhbXBsZSA9PSBpLCBjaHJvbW9zb21lID09IHkkY2hyb21vc29tZSkNCiAgICBpZih5JHN0cmFuZCA9PSAnKycpIHsNCiAgICAgIGZvcihqIGluIDE6MTAwKSB7DQogICAgICAgIGJpbl9maWxsX2Nkc1tqXSA9IG5yb3coaW5pICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgICBkcGx5cjo6ZmlsdGVyKGNocl9wb3MgPj0geSRzdGFydCtiaW5fc2l6ZV9jZHMqKGotMSkgJg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaHJfcG9zIDwgeSRzdGFydCtiaW5fc2l6ZV9jZHMqaiAmIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaHJfcG9zIDw9IHkkc3RvcCkpDQogICAgICAgIGJpbl9maWxsX3Byb21bal0gPSBucm93KGluaSAlPiUgZHBseXI6OmZpbHRlcihjaHJfcG9zID49IHkkcHJvbW90ZXIrMiooai0xKSAmDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNocl9wb3MgPD0geSRwcm9tb3RlcisyKmogJg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaHJfcG9zIDwgeSRzdGFydCkpDQogICAgICB9DQogICAgfSBlbHNlIHsNCiAgICAgIGZvcihqIGluIDE6MTAwKSB7DQogICAgICAgIGJpbl9maWxsX2Nkc1tqXSA9IG5yb3coaW5pICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgICBkcGx5cjo6ZmlsdGVyKGNocl9wb3MgPD0geSRzdGFydC1iaW5fc2l6ZV9jZHMqKGotMSkgJg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaHJfcG9zID4geSRzdGFydC1iaW5fc2l6ZV9jZHMqaiAmIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaHJfcG9zID49IHkkc3RvcCkpDQogICAgICAgIGJpbl9maWxsX3Byb21bal0gPSBucm93KGluaSAlPiUgZHBseXI6OmZpbHRlcihjaHJfcG9zIDw9IHkkcHJvbW90ZXItMiooai0xKSAmDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNocl9wb3MgPj0geSRwcm9tb3Rlci0yKmogJg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaHJfcG9zID4geSRzdGFydCkpDQogICAgICB9DQogICAgfQ0KICAgIG5hbWVzKGJpbl9maWxsX2NkcykgPSAxOjEwMA0KICAgIG5hbWVzKGJpbl9maWxsX3Byb20pID0gMToxMDANCiAgICBjZHMgPSBjZHMgJT4lIGJpbmRfcm93cyhjKHR5cGUgPSAiY2RzIiwgaWQ9eCwgc2FtcGxlPWksIGJpbl9maWxsX2NkcykpDQogICAgcHJvbW8gPSBwcm9tbyAlPiUgYmluZF9yb3dzKGModHlwZT0gInByb21vdGVyIixpZD14LCBzYW1wbGU9aSwgYmluX2ZpbGxfcHJvbSkpDQogIH0NCiAgYmluZF9yb3dzKGNkcywgcHJvbW8pDQp9DQoNCmJpbm5lZF9pbnNlcnRzID0gZG8uY2FsbChyYmluZCwgbWFwKGFsbF9nZW5lcyRYMSwgZ2V0X2Jpbm5lZF91bmlxdWVfaW5zZXJ0aW9ucywgaW5zZXJ0cyA9IHJwcF9kZikpDQoNCiN3cml0ZV9jc3YoYmlubmVkX2luc2VydHMsICIuL2Jpbm5lZF9pbnNlcnRzX3RlbXAuY3N2IikNCiNyZWFkX2NzdigiLi9iaW5uZWRfaW5zZXJ0c190ZW1wLmNzdiIpDQoNCnllYXN0X3I2NF90b19zeXN0ZW1hdGljIDwtIGZ1bmN0aW9uKG5hbWVfdmVjKSB7DQogIHRyYW5zbGF0ZWRfbmFtZXMgPC0gbWF0Y2gobmFtZV92ZWMsIGxhYnRvb2xzOjp5ZWFzdF9nZW5lX25hbWVzJEdDRl8wMDAxNDYwNDUuMl9SNjRfZ2Vub21pY19JRCwgbm9tYXRjaD1OQSkNCiAgdHJhbnNsYXRlZF9uYW1lcyA8LSBsYWJ0b29sczo6eWVhc3RfZ2VuZV9uYW1lc1t0cmFuc2xhdGVkX25hbWVzLCAiU3lzdGVtYXRpY19uYW1lIl0NCiAgbm9fdHJhbnNsYXRpb24gPC0gaXMubmEodHJhbnNsYXRlZF9uYW1lcykNCiAgdHJhbnNsYXRlZF9uYW1lc1tub190cmFuc2xhdGlvbl0gPC0gbmFtZV92ZWNbbm9fdHJhbnNsYXRpb25dDQogIHJldHVybih0cmFuc2xhdGVkX25hbWVzKQ0KfQ0KDQp0JGdlbmUgPSB5ZWFzdF9yNjRfdG9fc3lzdGVtYXRpYyh0JGlkKQ0KDQojIGdldCBsaXN0IG9mIGVzc2VudGlhbCBnZW5lcyBmcm9tIFdpbnplbGVyIDE5OTkNCmVzc19kZWwgPSByZWFkX3RzdihwYXN0ZTAoZGF0YV9kaXIsJy9Fc3NlbnRpYWxfT1JGcy50eHQnKSwgY29sX25hbWVzID0gVCwgY29tbWVudCA9ICc9JywgY29sX3R5cGVzID0gY29scygNCiAgcmVjX251bSA9IGNvbF9kb3VibGUoKSwNCiAgT1JGX25hbWUgPSBjb2xfY2hhcmFjdGVyKCksDQogIGRlbGV0aW9uX2FsaWFzID0gY29sX2NoYXJhY3RlcigpLA0KICBnZW5lX25hbWVzID0gY29sX2NoYXJhY3RlcigpLA0KICBVUFRBR19zZXF1ZW5jZV8yMG1lciA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgRE5UQUdfc2VxdWVuY2VfMjBtZXIgPSBjb2xfY2hhcmFjdGVyKCkNCikpICU+JQ0KICBkcGx5cjo6c2VsZWN0KE9SRl9uYW1lKSAlPiUgZHBseXI6OnJlbmFtZShnZW5lPU9SRl9uYW1lKSAlPiUNCiAgbXV0YXRlKGVzc19kZWwgPSAieWVzIikNCg0KIyBnZXQgZ2VuZSBmaXRuZXNzIGluIHlwZ2FsIGZyb20gY29zdGFuem8gZXQgYWwgMjAyMQ0KZml0X2dhbCA9IHJlYWRfY3N2KHBhc3RlMChkYXRhX2RpciwgIi9Db3N0YW56b19NdXRhbnQgRml0bmVzc19Db25kaXRpb25zLVRhYmxlIDEuY3N2IiksIGNvbF9uYW1lcyA9IFQpICU+JQ0KICBzZWxlY3QoYFN5c3RlbWF0aWMgTmFtZWAsIGBHZW5lIE5hbWVgLCBgQWxsZWxlIChFc3NlbnRpYWwgZ2VuZXMgb25seSlgLCBgR2FsYWN0b3NlYCkgJT4lDQogIG11dGF0ZShxdWFydGlsZSA9IGNhc2Vfd2hlbihHYWxhY3Rvc2UgPD0gcXVhbnRpbGUoR2FsYWN0b3NlLCBuYS5ybT1UKVsyXSB+ICJRMSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBHYWxhY3Rvc2UgPD0gcXVhbnRpbGUoR2FsYWN0b3NlLCBuYS5ybT1UKVszXSB+ICJRMiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBHYWxhY3Rvc2UgPD0gcXVhbnRpbGUoR2FsYWN0b3NlLCBuYS5ybT1UKVs0XSB+ICJRMyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBHYWxhY3Rvc2UgPD0gcXVhbnRpbGUoR2FsYWN0b3NlLCBuYS5ybT1UKVs1XSB+ICJRNCIsKSkNCg0KYmlubmVkX2luc2VydHMgPSBiaW5uZWRfaW5zZXJ0cyAlPiUgDQogIG11dGF0ZShlc3NlbnRpYWwgPSBkcGx5cjo6aWZfZWxzZShgZ2VuZWAgJWluJSBlc3NfZGVsJGdlbmUsICd5ZXMnLCAnbm8nKSkgJT4lIA0KICBsZWZ0X2pvaW4oZml0X2dhbCAlPiUgc2VsZWN0KGBTeXN0ZW1hdGljIE5hbWVgLCBxdWFydGlsZSksIGJ5PWMoImdlbmUiID0gIlN5c3RlbWF0aWMgTmFtZSIpKSAlPiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHM9YygtZ2VuZSwgLWVzc2VudGlhbCwgLXR5cGUsIC1pZCwgLXNhbXBsZSksIA0KICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiYmluIiwgdmFsdWVzX3RvID0gImluc2VydHNfcGVyX2JpbiIpICU+JQ0KICBtdXRhdGVfYXQoYygnYmluJywgJ2luc2VydHNfcGVyX2JpbicpLCBhcy5udW1lcmljKQ0KDQoNCm1ldGFfYmluX2luc2VydF9lc3NlbnRpYWwgPSBiaW5uZWRfaW5zZXJ0cyAlPiUgDQogIGdyb3VwX2J5X2F0KHZhcnMoc2FtcGxlLCB0eXBlLCBlc3NlbnRpYWwsIGJpbikpICU+JQ0KICBtdXRhdGUodG90YWxfaW5zZXJ0c19iaW4gPSBzdW0oaW5zZXJ0c19wZXJfYmluKSwgDQogICAgICAgICBtZWFuX2luc2VydHNfYmluID0gbWVhbihpbnNlcnRzX3Blcl9iaW4pLA0KICAgICAgICAgbWVkaWFuX2luc2VydHNfYmluID0gbWVkaWFuKGluc2VydHNfcGVyX2JpbiksDQogICAgICAgICBuZ2VuZV9ub3JtX3RvdGFsX2luc2VydHNfYmluID0gZHBseXI6OmlmX2Vsc2UoZXNzZW50aWFsID09ICd5ZXMnLCBzdW0oaW5zZXJ0c19wZXJfYmluKS9ucm93KGVzc19kZWwpLCBzdW0oaW5zZXJ0c19wZXJfYmluKS8obnJvdyhhbGxfZ2VuZXMpIC0gbnJvdyhlc3NfZGVsKSkpKSAlPiUNCiAgZHBseXI6OnNlbGVjdChzYW1wbGUsIHR5cGUsIGVzc2VudGlhbCwgYmluLCB0b3RhbF9pbnNlcnRzX2JpbiwgbWVhbl9pbnNlcnRzX2JpbiwgbWVkaWFuX2luc2VydHNfYmluLCBuZ2VuZV9ub3JtX3RvdGFsX2luc2VydHNfYmluKSAlPiUgZGlzdGluY3QoKQ0KDQptZXRhX2Jpbl9pbnNlcnRfZXNzZW50aWFsJHR5cGVfb3JkZXIgPSBmYWN0b3IobWV0YV9iaW5faW5zZXJ0X2Vzc2VudGlhbCR0eXBlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzPWMoJ3Byb21vdGVyJywgJ2NkcycpKQ0KDQpzZmlnM2EgPSBnZ3Bsb3QobWV0YV9iaW5faW5zZXJ0X2Vzc2VudGlhbCAlPiUgDQogICAgICAgICBmaWx0ZXIodHlwZSA9PSAnY2RzJykgJT4lDQogICAgICAgICAgIG11dGF0ZShzdHJhaW5fbmFtZXNfcmVwID0gY2FzZV93aGVuKHNhbXBsZSA9PSAiMTY1N18xIiB+ICJldV8xIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlID09ICIxNjU3XzIiIH4gImV1XzIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGUgPT0gIjE3MjgiIH4gImFuZXUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGUgPT0gIjE3MzQiIH4gInRyaXAxIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlID09ICIxNzQ3IiB+ICJ0cmlwMiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZSA9PSAiMTc1MSIgfiAidHJpcDMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGUgPT0gIjE3MzYiIH4gInRyaXA0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlID09ICIxNzQ0IiB+ICJpc28iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGUgPT0gIjE3NDAiIH4gInF1YWQiDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpICwgDQogICAgICAgYWVzKGJpbiwgbmdlbmVfbm9ybV90b3RhbF9pbnNlcnRzX2JpbiwgY29sb3IgPSBlc3NlbnRpYWwpKSArDQogIGdlb21fbGluZSgpICsNCiAgI3RoZW1lX21pbmltYWwoKSArDQogIGZhY2V0X3dyYXAofnN0cmFpbl9uYW1lc19yZXApICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCcjODBiMWQzJywgJyNmYjgwNzInKSwNCiAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiIiwgbGFiZWxzID0gYygiTm9uLWVzc2VudGlhbCIsICJFc3NlbnRpYWwiKSkgKw0KICB4bGFiKCclIG9mIENEUycpICsNCiAgeWxhYignTWVhbiB1bmlxdWUgaW5zZXJ0aW9uIHNpdGVzJykNCg0Kc2ZpZzNiPWJpbm5lZF9pbnNlcnRzICU+JSANCiAgdW5ncm91cCgpICU+JQ0KICBmaWx0ZXIodHlwZT09ImNkcyIpICU+JQ0KICBncm91cF9ieV9hdCh2YXJzKHNhbXBsZSwgdHlwZSwgcXVhcnRpbGUsIGJpbikpICU+JQ0KICBtdXRhdGUodG90YWxfaW5zZXJ0c19iaW4gPSBzdW0oaW5zZXJ0c19wZXJfYmluKSwgDQogICAgICAgICBtZWFuX2luc2VydHNfYmluID0gbWVhbihpbnNlcnRzX3Blcl9iaW4pLA0KICAgICAgICAgbWVkaWFuX2luc2VydHNfYmluID0gbWVkaWFuKGluc2VydHNfcGVyX2JpbikpICU+JQ0KICBkcGx5cjo6c2VsZWN0KHNhbXBsZSwgdHlwZSwgZXNzZW50aWFsLCBiaW4sIHRvdGFsX2luc2VydHNfYmluLCBtZWFuX2luc2VydHNfYmluLCBtZWRpYW5faW5zZXJ0c19iaW4sIHF1YXJ0aWxlKSAlPiUNCiAgZGlzdGluY3QoKSAlPiUNCiAgbXV0YXRlKHN0cmFpbl9uYW1lc19yZXAgPSBjYXNlX3doZW4oc2FtcGxlID09ICIxNjU3XzEiIH4gImV1XzEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGUgPT0gIjE2NTdfMiIgfiAiZXVfMiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZSA9PSAiMTcyOCIgfiAiYW5ldSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZSA9PSAiMTczNCIgfiAidHJpcDEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGUgPT0gIjE3NDciIH4gInRyaXAyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlID09ICIxNzUxIiB+ICJ0cmlwMyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZSA9PSAiMTczNiIgfiAidHJpcDQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGUgPT0gIjE3NDQiIH4gImlzbyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZSA9PSAiMTc0MCIgfiAicXVhZCINCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSkgJT4lDQogIGdncGxvdChhZXMoYmluLCBtZWFuX2luc2VydHNfYmluLCBjb2xvciA9IHF1YXJ0aWxlKSkgKw0KICBnZW9tX2xpbmUoKSArDQogICN0aGVtZV9taW5pbWFsKCkgKw0KICBmYWNldF93cmFwKH5zdHJhaW5fbmFtZXNfcmVwKSArDQogICNzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoJyM4MGIxZDMnLCAnI2ZiODA3MicpLA0KICAgIyAgICAgICAgICAgICAgICAgIG5hbWUgPSAiIiwgbGFiZWxzID0gYygiTm9uLWVzc2VudGlhbCIsICJFc3NlbnRpYWwiKSkgKw0KICB4bGFiKCclIG9mIENEUycpICsNCiAgeWxhYignTWVhbiB1bmlxdWUgaW5zZXJ0aW9uIHNpdGVzJykNCg0KcXVhbnRpbGUoZml0X2dhbCRHYWxhY3Rvc2UsIG5hLnJtPVQpDQoNCmxheW91dCA8LSAiDQpBDQpCDQoiDQoNCnNmaWczPXNmaWczYSArIHNmaWczYiArIHBsb3RfbGF5b3V0KGRlc2lnbiA9IGxheW91dCkgKyBwbG90X2Fubm90YXRpb24odGFnX2xldmVscyA9ICdBJykNCg0KZ2dzYXZlKHBhc3RlMChmaWdfZGlyLCIvU0ZpZzMucGRmIiksIHBsb3QgPSBzZmlnMywgd2lkdGggPSAxMiwgaGVpZ2h0ID0gMTYsIHVuaXRzID0gImluIikNCmdnc2F2ZShwYXN0ZTAoZmlnX2RpciwiL1NGaWczLnBuZyIpLCBwbG90ID0gc2ZpZzMsIHdpZHRoID0gMTIsIGhlaWdodCA9IDE2LCB1bml0cyA9ICJpbiIpDQpgYGANCg==