library(EnhancedVolcano)
library(DESeq2)
library(org.Sc.sgd.db)
library(clusterProfiler)
library(tidyverse)
library(patchwork)
library(ggbeeswarm)
library(ggpubr)
theme_set(theme_bw(base_size = 20))
data_dir = "/Volumes/GoogleDrive/My Drive/Gresham Lab_Grace/france_satay/Hermes_mutagenesis_paper/data"
fig_dir = "/Volumes/GoogleDrive/My Drive/Gresham Lab_Grace/france_satay/Hermes_mutagenesis_paper/figures"
source("/Volumes/GoogleDrive/My Drive/Gresham Lab_Grace/france_satay/Hermes_mutagenesis_paper/analysis_w_PS_corrections/functions.R")
seq_runs = c("bgi1","bgi2", "nyc1", "nyc2")
# get all genes excluding dubious orfs and their copy number
strain_cns = read_csv(paste0(data_dir, "/gene_median_relative_depth_DNA_corrected_v3/gene_median_relative_depth_DNA-Table 1.csv")) %>%
select(Gene, contains("cor")) %>%
pivot_longer(-Gene, names_to = "strain", values_to = "copy_number") %>%
mutate(strain = str_extract(strain,"[0-9]{4}")) %>%
left_join(strain_names)
all_genes = strain_cns$Gene
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)
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"))
insert_profiles = read_csv(paste0(data_dir,"/insertion_profiles.csv"))
inserts_per_mill_cds = insert_profiles %>%
left_join(strain_names, c("sample" = "strain")) %>%
left_join(summary_rpp) %>%
filter(type %in% c("cds")) %>%
group_by(sample, gene) %>%
mutate(inserts = sum(n_insertions)) %>% ungroup() %>%
select(sample, strain_names, gene, inserts, total_sites) %>%
distinct() %>%
mutate(inserts_per_mill = inserts/(total_sites/1e6))
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
# 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")
LS0tDQp0aXRsZTogIlRyYW5zcG9zb24gbXV0YWdlbmVzaXMgaW4gKkdBUDEqIENOViBzdHJhaW5zIg0KYXV0aG9yOiAiR3JhY2UgQXZlY2lsbGEiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQoNCmBgYHtyfQ0KbGlicmFyeShFbmhhbmNlZFZvbGNhbm8pDQpsaWJyYXJ5KERFU2VxMikNCmxpYnJhcnkob3JnLlNjLnNnZC5kYikNCmxpYnJhcnkoY2x1c3RlclByb2ZpbGVyKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHBhdGNod29yaykNCmxpYnJhcnkoZ2diZWVzd2FybSkNCmxpYnJhcnkoZ2dwdWJyKQ0KdGhlbWVfc2V0KHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDIwKSkNCg0KZGF0YV9kaXIgPSAiL1ZvbHVtZXMvR29vZ2xlRHJpdmUvTXkgRHJpdmUvR3Jlc2hhbSBMYWJfR3JhY2UvZnJhbmNlX3NhdGF5L0hlcm1lc19tdXRhZ2VuZXNpc19wYXBlci9kYXRhIg0KDQpmaWdfZGlyID0gIi9Wb2x1bWVzL0dvb2dsZURyaXZlL015IERyaXZlL0dyZXNoYW0gTGFiX0dyYWNlL2ZyYW5jZV9zYXRheS9IZXJtZXNfbXV0YWdlbmVzaXNfcGFwZXIvZmlndXJlcyINCg0Kc291cmNlKCIvVm9sdW1lcy9Hb29nbGVEcml2ZS9NeSBEcml2ZS9HcmVzaGFtIExhYl9HcmFjZS9mcmFuY2Vfc2F0YXkvSGVybWVzX211dGFnZW5lc2lzX3BhcGVyL2FuYWx5c2lzX3dfUFNfY29ycmVjdGlvbnMvZnVuY3Rpb25zLlIiKQ0KDQpzZXFfcnVucyA9IGMoImJnaTEiLCJiZ2kyIiwgIm55YzEiLCAibnljMiIpDQpgYGANCg0KYGBge3J9DQojIGdldCBhbGwgZ2VuZXMgZXhjbHVkaW5nIGR1YmlvdXMgb3JmcyBhbmQgdGhlaXIgY29weSBudW1iZXINCnN0cmFpbl9jbnMgPSByZWFkX2NzdihwYXN0ZTAoZGF0YV9kaXIsICIvZ2VuZV9tZWRpYW5fcmVsYXRpdmVfZGVwdGhfRE5BX2NvcnJlY3RlZF92My9nZW5lX21lZGlhbl9yZWxhdGl2ZV9kZXB0aF9ETkEtVGFibGUgMS5jc3YiKSkgJT4lIA0KICBzZWxlY3QoR2VuZSwgY29udGFpbnMoImNvciIpKSAlPiUNCiAgcGl2b3RfbG9uZ2VyKC1HZW5lLCBuYW1lc190byA9ICJzdHJhaW4iLCB2YWx1ZXNfdG8gPSAiY29weV9udW1iZXIiKSAlPiUNCiAgbXV0YXRlKHN0cmFpbiA9IHN0cl9leHRyYWN0KHN0cmFpbiwiWzAtOV17NH0iKSkgJT4lDQogIGxlZnRfam9pbihzdHJhaW5fbmFtZXMpDQoNCmFsbF9nZW5lcyA9IHN0cmFpbl9jbnMkR2VuZQ0KYGBgDQoNCiMgQ29ycmVsYXRpb24gYmV0d2VlbiBkaWZmZXJlbnQgc2VxdWVuY2luZyBtZXRob2RzDQpVc2luZyBpbnNlcnRpb25zIHBlciBnZW5lDQpgYGB7cn0NCmdldF9pcGcgPSBmdW5jdGlvbih4LCB2ZXIpew0KICBkYXRhID0gcmVhZF90c3YocGFzdGUwKGRhdGFfZGlyLCAiL2hwY19vdXRwdXQvIix2ZXIsICIvIiwgeCksIA0KICAgICAgICAgICAgICAgICAgY29sX3R5cGVzID0gY29scyhDRFM9Y29sX2NoYXJhY3RlcigpLGAjaW5zZXJ0aW9uYCA9IGNvbF9kb3VibGUoKSkpICU+JQ0KICAgIG11dGF0ZShzYW1wbGUgPSBzdHJfc3ViKHgsIDEsIC0yMiksIGdlbmU9TkEsDQogICAgICAgICAgIHJ1bj12ZXIpDQp9DQppcGdfZm9yY29yID0gTlVMTA0KZm9yKGkgaW4gc2VxX3J1bnMpIHsNCiAgaXBnX2ZpbGVzID0gbGlzdC5maWxlcyhwYXRoID0gcGFzdGUwKGRhdGFfZGlyLCAiL2hwY19vdXRwdXQvIiwgaSwgIi8iKSwgcGF0dGVybiA9ICcqaW5zZXJ0aW9uUGVyR2VuZS50eHQnKQ0KICBpcGdfdCA9IG1hcChpcGdfZmlsZXMsIGdldF9pcGcsIHZlcj1pKQ0KICBpcGdfZGZfdCA9IGRvLmNhbGwocmJpbmQsIGlwZ190KQ0KICBpcGdfZm9yY29yID0gaXBnX2ZvcmNvciAlPiUgDQogICAgYmluZF9yb3dzKGlwZ19kZl90ICU+JSB1bml0ZShzYW1wbGVfcmVwLCBzYW1wbGUsIHJ1bikpDQp9DQpgYGANCg0KYGBge3J9DQojIGdldCBjb3JyZWxhdGlvbnMNCmlwZ19mb3Jjb3IgPSBpcGdfZm9yY29yICU+JQ0KICBtdXRhdGUoc3RyYWluID0gc3RyX3N1YihzYW1wbGVfcmVwLCAxLCAtNiksDQogICAgICAgICByZXAgPSBzdHJfc3ViKHNhbXBsZV9yZXAsIC00LCAtMSkpICU+JQ0KICBsZWZ0X2pvaW4oc3RyYWluX25hbWVzKSAlPiUNCiAgdW5pdGUoc2FtcGxlX3JlcCwgc3RyYWluX25hbWVzLCByZXApICU+JQ0KICBkcGx5cjo6c2VsZWN0KENEUywgc2FtcGxlX3JlcCwgYCNpbnNlcnRpb25gKSAlPiUgDQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBzYW1wbGVfcmVwLCB2YWx1ZXNfZnJvbSA9IGAjaW5zZXJ0aW9uYCkgDQoNCg0KcmVwcyA9IGlwZ19mb3Jjb3IgJT4lDQogICAgZHBseXI6OnNlbGVjdChldV8xX255YzEsIGV1XzFfbnljMiwgZXVfMl9ueWMxLCBldV8yX255YzIpICANCmNvcl9wbG90cz1HR2FsbHk6OmdncGFpcnMocmVwcywgDQogICAgICAgICAgICAgICAgdXBwZXIgPSBsaXN0KGNvbnRpbnVvdXMgPSBHR2FsbHk6OndyYXAoImNvciIsIG1ldGhvZCA9ICJwZWFyc29uIikpKSArDQogICAgZ2d0aXRsZShMRVRURVJTWzFdKQ0KZ2dzYXZlKGNvcl9wbG90cywgZmlsZT1wYXN0ZTAoZmlnX2RpciwgIi9TRmlnWCIsIExFVFRFUlNbMV0sICIucGRmIiksIGhlaWdodCA9IDEwLCB3aWR0aCA9IDEwKQ0KDQppPTINCmZvcihzdHJhaW4gaW4gYygiYW5ldSIsICJ0cmlwMSIsICJ0cmlwMiIsICJ0cmlwMyIsICJ0cmlwNCIsICJpc28iLCAicXVhZCIpKSB7DQogIHJlcHMgPSBpcGdfZm9yY29yICU+JQ0KICAgIGRwbHlyOjpzZWxlY3QoY29sbmFtZXMoaXBnX2ZvcmNvcilbc3RyX2RldGVjdChjb2xuYW1lcyhpcGdfZm9yY29yKSwgc3RyYWluKV0pICANCiAgY29yX3Bsb3RzPUdHYWxseTo6Z2dwYWlycyhyZXBzLCANCiAgICAgICAgICAgICAgICB1cHBlciA9IGxpc3QoY29udGludW91cyA9IEdHYWxseTo6d3JhcCgiY29yIiwgbWV0aG9kID0gInBlYXJzb24iKSkpICsNCiAgICBnZ3RpdGxlKExFVFRFUlNbaV0pDQogIGdnc2F2ZShjb3JfcGxvdHMsIGZpbGU9cGFzdGUwKGZpZ19kaXIsICIvU0ZpZ1giLCBMRVRURVJTW2ldLCAiLnBkZiIpLCBoZWlnaHQgPSAxMCwgd2lkdGggPSAxMCkNCiAgaT1pKzENCn0NCg0KYGBgDQoNCmBgYHtyIGdldCByZWFkcyBwZXIgcG9zaXRpb259DQpnZXRfcnBwID0gZnVuY3Rpb24oeCwgdmVyKSB7DQogIGZpbGVwYXRoPXBhc3RlMChkYXRhX2RpciwiL2hwY19vdXRwdXQvIix2ZXIsIi8iLHgpDQogIG91dCA9IHJlYWRfdHN2KGZpbGVwYXRoLCBjb2xfbmFtZXMgPSBGLCBjb2xfdHlwZXMgPSBjb2xzKCkpICU+JQ0KICAgIGRwbHlyOjpyZW5hbWUoY2hyb21vc29tZT1YMSwgY2hyX3Bvcz1YMiwgcmVhZHM9WDMpICU+JQ0KICAgIG11dGF0ZShzYW1wbGUgPSBzdHJfc3ViKHgsIDEsIC0xNiksDQogICAgICAgICAgIHZlcnNpb24gPSB2ZXIpDQp9DQpmaWxlcyA9IGxpc3QuZmlsZXMocGF0aCA9IHBhc3RlMChkYXRhX2RpciwgJy9ocGNfb3V0cHV0L2NvbWJpbmVkLycpLA0KICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICcqcmVhZFBlclBvcy50eHQnKQ0KcmVhZF9wZXJfcG9zID0gbWFwKGZpbGVzLCBnZXRfcnBwLCB2ZXI9J2NvbWJpbmVkJykNCnJwcF9kZiA9IGRvLmNhbGwocmJpbmQsIHJlYWRfcGVyX3BvcykNCg0KYGBgDQoNCg0KIyBHZXQgaW5zZXJ0aW9uIHByb2ZpbGVzDQpgYGB7ciBnZXQgaW5zZXJ0aW9uIHByb2ZpbGVzLCBtZXNzYWdlPUZBTFNFfQ0KI2dldCBpbnNlcnRpb24gcHJvZmlsZXMgZm9yIGFsbCBnZW5lcw0KaW5zZXJ0X3Byb2ZpbGVzID0gbWFwKGFsbF9nZW5lc19zeXN0ZW1hdGljLCBnZXRfaW5zZXJ0X3Byb2ZpbGUsIGRhdGEgPSBycHBfZGYpDQppbnNlcnRfcHJvZmlsZXMgPSBkby5jYWxsKHJiaW5kLCBpbnNlcnRfcHJvZmlsZXMpDQoNCiMgYWRkIGluIHplcm8gY2F0ZWdvcmllcw0KdD1pbnNlcnRfcHJvZmlsZXMgJT4lIHJpZ2h0X2pvaW4odGliYmxlKGFsbF9nZW5lc19zeXN0ZW1hdGljKSwgYnk9IGMoImdlbmUiPSJhbGxfZ2VuZXNfc3lzdGVtYXRpYyIpKSAlPiUNCiAgbXV0YXRlX2F0KHZhcnMoc2FtcGxlLCBnZW5lLCB0eXBlKSwgZmFjdG9yKSANCnQ9dCAlPiUgDQogIHRpZHlyOjpleHBhbmQoc2FtcGxlLCBnZW5lLCB0eXBlKQ0KaW5zZXJ0X3Byb2ZpbGVzID0gaW5zZXJ0X3Byb2ZpbGVzICU+JSAjZmlsdGVyKCFpcy5uYShzYW1wbGUpKSAlPiUgDQogIHJpZ2h0X2pvaW4odCkgJT4lDQogIG11dGF0ZShuX2luc2VydGlvbnMgPSByZXBsYWNlX25hKG5faW5zZXJ0aW9ucywgMCksIG5vcm1hbGl6ZWRfaW5zZXJ0aW9ucyA9IHJlcGxhY2VfbmEobm9ybWFsaXplZF9pbnNlcnRpb25zLCAwKSkgJT4lDQogIGRpc3RpbmN0KCkNCg0KIyB3cml0ZSBvdXQgc28gdGhpcyBkb2Vzbid0IG5lZWQgdG8gYmUgZG9uZSBhZ2Fpbg0Kd3JpdGVfY3N2KGluc2VydF9wcm9maWxlcywgcGFzdGUwKGRhdGFfZGlyLCIvaW5zZXJ0aW9uX3Byb2ZpbGVzLmNzdiIpKQ0KYGBgDQoNCmBgYHtyIGdldCBpbnNlcnRpb24gcHJvZmlsZSBjc3Z9DQppbnNlcnRfcHJvZmlsZXMgPSByZWFkX2NzdihwYXN0ZTAoZGF0YV9kaXIsIi9pbnNlcnRpb25fcHJvZmlsZXMuY3N2IikpDQpgYGANCg0KYGBge3J9DQppbnNlcnRzX3Blcl9taWxsX2NkcyA9IGluc2VydF9wcm9maWxlcyAlPiUgDQogIGxlZnRfam9pbihzdHJhaW5fbmFtZXMsIGMoInNhbXBsZSIgPSAic3RyYWluIikpICU+JQ0KICBsZWZ0X2pvaW4oc3VtbWFyeV9ycHApICU+JQ0KICBmaWx0ZXIodHlwZSAlaW4lIGMoImNkcyIpKSAlPiUNCiAgZ3JvdXBfYnkoc2FtcGxlLCBnZW5lKSAlPiUNCiAgbXV0YXRlKGluc2VydHMgPSBzdW0obl9pbnNlcnRpb25zKSkgJT4lIHVuZ3JvdXAoKSAlPiUNCiAgc2VsZWN0KHNhbXBsZSwgc3RyYWluX25hbWVzLCBnZW5lLCBpbnNlcnRzLCB0b3RhbF9zaXRlcykgJT4lDQogICAgZGlzdGluY3QoKSAlPiUNCiAgbXV0YXRlKGluc2VydHNfcGVyX21pbGwgPSBpbnNlcnRzLyh0b3RhbF9zaXRlcy8xZTYpKQ0KYGBgDQoNCg0KIyBMb29rIGF0IGdlbmVzIGluIENOViByZWdpb24NCg0KYGBge3J9DQpjbnZfZ2VuZXMgPSBzdHJhaW5fY25zICU+JSBmaWx0ZXIoY29weV9udW1iZXIgPj0gMikgJT4lIHJlbmFtZShzYW1wbGUgPSBzdHJhaW4pDQpgYGANCg0KDQpgYGB7ciBTdXBwbGVtZW50YWxfRmlnX1MxMEF9DQpzZmlncV9zaWcgPSBpbnNlcnRzX3Blcl9taWxsX2NkcyAlPiUgDQogIGxlZnRfam9pbihlc3NfZGVsKSAlPiUNCiAgZmlsdGVyKHN0cl9zdGFydHMoZ2VuZSwgIllLIikpICU+JQ0KICBhbnRpX2pvaW4oY252X2dlbmVzKSAlPiUNCiAgbGVmdF9qb2luKHN0cmFpbl9uYW1lcykgJT4lDQogIGdyb3VwX2J5KHNhbXBsZSkgJT4lIA0KICBtdXRhdGUoZXNzX2RlbCA9IGlmX2Vsc2UoaXMubmEoZXNzX2RlbCksICJub3QgZXNzZW50aWFsIiwgZXNzX2RlbCkpICU+JSANCiAgcnN0YXRpeDo6dF90ZXN0KGluc2VydHNfcGVyX21pbGwgfiBlc3NfZGVsKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBtdXRhdGUoc2lnbmlmaWNhbmNlID0gY2FzZV93aGVuKHAgPD0gMC4wMDAxIH4gIioqKioiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHAgPiAwLjAxIH4gIm5zIikpDQoNCnNmaWc0YSA9IGluc2VydHNfcGVyX21pbGxfY2RzICU+JSANCiAgbGVmdF9qb2luKGVzc19kZWwpICU+JQ0KICBmaWx0ZXIoc3RyX3N0YXJ0cyhnZW5lLCAiWUsiKSkgJT4lDQogIGFudGlfam9pbihjbnZfZ2VuZXMpICU+JQ0KICBncm91cF9ieShzYW1wbGUpICU+JSANCiAgbXV0YXRlKGVzc19kZWwgPSBpZl9lbHNlKGlzLm5hKGVzc19kZWwpLCAibm90IGVzc2VudGlhbCIsIGVzc19kZWwpKSAlPiUNCiAgZ2dwbG90KGFlcyhzdHJhaW5fbmFtZXMsIGluc2VydHNfcGVyX21pbGwsIGNvbG9yID0gZXNzX2RlbCkpICsNCiAgeWxhYigiTm9ybWFsaXplZCBpbnNlcnRpb25zIikgKw0KICB4bGFiKCIiKSArDQogIGdlb21fcG9pbnQoYWxwaGE9MC43LCBzaXplPTEsIGNleCA9IDAuNywgcG9zaXRpb249cG9zaXRpb25faml0dGVyZG9kZ2UoKSkgKw0KICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BLCBhbHBoYT0wLCBsd2Q9MSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoJyM4MGIxZDMnLCAnI2ZiODA3MicpLA0KICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICIiLCBsYWJlbHMgPSBjKCJOb24tZXNzZW50aWFsIiwgIkVzc2VudGlhbCIpKSArDQogIHN0YXRfcHZhbHVlX21hbnVhbCgNCiAgICBzZmlncV9zaWcgJT4lIHJzdGF0aXg6OmFkZF94eV9wb3NpdGlvbih4ID0gInNhbXBsZSIpLCANCiAgICB5LnBvc2l0aW9uID0gMTUwMCwNCiAgICBsYWJlbCA9ICJzaWduaWZpY2FuY2UiDQogICAgKSArDQogIHRoZW1lKGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9InRyYW5zcGFyZW50IiksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbj1jKC44NSwuNzMpKSANCg0Kc2ZpZzRhDQpgYGANCg0KYGBge3IgU3VwcGxlbWVudGFsX0ZpZ19TMTBCfQ0KIyBub24tYW1wbGlmaWVkIGdlbmVzDQp0ZW1wbyA9IGluc2VydHNfcGVyX21pbGxfY2RzICU+JSANCiAgc2VsZWN0KHN0cmFpbl9uYW1lcywgaW5zZXJ0c19wZXJfbWlsbCwgZ2VuZSkgJT4lDQogIGFudGlfam9pbihjbnZfZ2VuZXMgJT4lIHNlbGVjdChnZW5lLCBzdHJhaW5fbmFtZXMpKSAlPiUNCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9ICJzdHJhaW5fbmFtZXMiLCB2YWx1ZXNfZnJvbSA9ICJpbnNlcnRzX3Blcl9taWxsIikgJT4lDQogIG11dGF0ZShtZWFuMTY1NyA9IChldV8xICsgZXVfMikvMikgJT4lDQogIHBpdm90X2xvbmdlcihjb2xzPWMoYW5ldSwgdHJpcDEsIHRyaXAyLCB0cmlwMywgdHJpcDQsIGlzbywgcXVhZCksIG5hbWVzX3RvPSJzdHJhaW4iLCB2YWx1ZXNfdG8gPSAiaW5zZXJ0c19wZXJfbWlsbCIpDQoNCmFtcF9yZWdyZXNzID0gTlVMTA0KZm9yKHNhbXAgaW4gdW5pcXVlKHRlbXBvJHN0cmFpbikpIHsNCiAgdHggPSB0ZW1wbyAlPiUgZmlsdGVyKHN0cmFpbiA9PSBzYW1wKSAlPiUNCiAgICBmaWx0ZXIoIWlzLm5hKGluc2VydHNfcGVyX21pbGwpKQ0KICBmaXQ9bG0odHgkaW5zZXJ0c19wZXJfbWlsbH50eCRtZWFuMTY1NykNCiAgaW50ZXJjZXB0ID0gZml0JGNvZWZmaWNpZW50c1sxXQ0KICBpbnRlcmNlcHRfcHZhbCA9IHN1bW1hcnkoZml0KSRjb2VmZmljaWVudHNbLDRdWzFdDQogIHNsb3BlID0gZml0JGNvZWZmaWNpZW50c1syXQ0KICBzbG9wZV9jaTIuNSA9IGNvbmZpbnQoZml0LCAyLCBsZXZlbD0wLjk1KVsxXQ0KICBzbG9wZV9jaTk3LjUgPSBjb25maW50KGZpdCwgMiwgbGV2ZWw9MC45NSlbMl0NCiAgc2xvcGVfcHZhbCA9IHN1bW1hcnkoZml0KSRjb2VmZmljaWVudHNbLDRdWzJdDQogIGFkanIyID0gc3VtbWFyeShmaXQpJGFkai5yLnNxdWFyZWQNCiAgcmVzaWRfc2QgPSBzaWdtYShmaXQpDQogIG5fZ3JlYXRlcjJzaWdtYSA9IHN1bShhYnMoZml0JHJlc2lkdWFscykgPiBtZWFuKGZpdCRyZXNpZHVhbHMpICsgcmVzaWRfc2QqMikNCiAgbl9hbXBfZ2VuZXMgPSB0eCRjb21tb25fbmFtZVthYnMoZml0JHJlc2lkdWFscykgPiBtZWFuKGZpdCRyZXNpZHVhbHMpICsgcmVzaWRfc2QqMl0NCiAgYW1wX3JlZ3Jlc3MgPSBhbXBfcmVncmVzcyAlPiUgYmluZF9yb3dzKHRpYmJsZShzYW1wLCBpbnRlcmNlcHQsIGludGVyY2VwdF9wdmFsLCBzbG9wZSwgc2xvcGVfcHZhbCwgc2xvcGVfY2kyLjUsIHNsb3BlX2NpOTcuNSwgYWRqcjIsIHJlc2lkX3NkLCBuX2dyZWF0ZXIyc2lnbWEpKQ0KfQ0KDQpzZmlnNGIgPSB0ZW1wbyAlPiUgDQogICNsZWZ0X2pvaW4oc3RyYWluX25hbWVzKSAlPiUNCiAgI2ZpbHRlcihzdHJhaW4gIT0gIjE2NTdfMSIsIHN0cmFpbiAhPSAiMTY1N18yIikgJT4lDQogICNmaWx0ZXIoIWlzLm5hKGluc2VydHNfcGVyX21pbGwpLCBtZWFuMTY1NyA8IDc1MCkgJT4lDQogIGdncGxvdChhZXMobWVhbjE2NTcsIGluc2VydHNfcGVyX21pbGwpKSArDQogICNnZ2lyYXBoOjpnZW9tX3BvaW50X2ludGVyYWN0aXZlKGFlcyhkYXRhX2lkID0gY29tbW9uX25hbWUsIHRvb2x0aXAgPSBjb21tb25fbmFtZSksIGFscGhhID0gMC41KSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICdsbScsIHNlPUZBTFNFLCBjb2xvcj0iYmxhY2siKSArDQogIGdlb21fcG9pbnQoYWxwaGE9MC41KSArDQogICAgIGZhY2V0X3dyYXAofnN0cmFpbikgKw0KICAgICB0aGVtZV9idyhiYXNlX3NpemU9MTYpICsNCiAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArDQogIHlsYWIoIkNOViBzdHJhaW4gbm9ybWFsaXplZCBpbnNlcnRpb25zIikgKw0KICB4bGFiKCJFdXBsb2lkIG5vcm1hbGl6ZWQgaW5zZXJ0aW9ucyIpICsNCiAgZ2VvbV90ZXh0KGRhdGEgPSBhbXBfcmVncmVzcyAlPiUgcmVuYW1lKHN0cmFpbiA9IHNhbXApLCANCiAgICAgICAgICAgICBhZXMoMTUwLCAxNTAwLCBsYWJlbCA9IHBhc3RlKCJBZGogUjIgPSAiLCByb3VuZChhZGpyMiwyKSwgIlxuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTbG9wZSA9Iiwgcm91bmQoc2xvcGUsMiksICJcbiIpKSwNCiAgICAgICAgICAgICBzaXplPTQpICsNCiAgZ2d0aXRsZSgiQiIpDQpgYGANCg0K