Parameters
suffix = ""
data_to_read = ""
functions
source_from_github(repositoy = "DEG_functions",version = "0.2.24")
source_from_github(repositoy = "HMSC_functions",version = "0.1.12",script_name = "functions.R")
source_from_github(repositoy = "cNMF_functions",version = "0.3.72",script_name = "cnmf_function_Harmony.R")
no_neg <- function(x) {
x = x + abs(min(x))
x
}
sum_2_one <- function(x) {
x =x/sum(x)
x
}
Data
Load object
from cnmf import cNMF
import pickle
nfeatures = "2K"
f = open('./Data/cNMF/HMSC_cNMF_' + nfeatures+ 'vargenes/cnmf_obj.pckl', 'rb')
cnmf_obj = pickle.load(f)
f.close()
selected_k = 4
density_threshold = 0.1
cnmf_obj.consensus(k=selected_k, density_threshold=density_threshold,show_clustering=True)
usage_norm, gep_scores, gep_tpm, topgenes = cnmf_obj.load_results(K=selected_k, density_threshold=density_threshold)
gep_scores = py$gep_scores
gep_tpm = py$gep_tpm
all_metagenes= py$usage_norm
Hallmark Enrichment
analysis by top 200 genes of each program
plt_list = list()
for (i in 1:ncol(gep_scores)) {
top_genes = gep_scores %>% arrange(desc(gep_scores[i])) #sort by score a
top = head(rownames(top_genes),200) #take top top_genes_num
res = genes_vec_enrichment(genes = top,background = rownames(gep_scores),homer = T,title =
i,silent = T,return_all = T)
plt_list[[i]] = res$plt
}
gridExtra::grid.arrange(grobs = plt_list)

Hallmark + canonical
Enrichment analysis by top 200 genes of each program
canonical_pathways = msigdbr(species = "Homo sapiens", category = "C2") %>% dplyr::filter(gs_subcat != "CGP") %>% dplyr::distinct(gs_name, gene_symbol)
plt_list = list()
for (i in 1:ncol(gep_scores)) {
top_genes = gep_scores %>% arrange(desc(gep_scores[i])) #sort by score a
top = head(rownames(top_genes),200) #take top top_genes_num
res = genes_vec_enrichment(genes = top,background = rownames(gep_scores),homer = T,title =
i,silent = T,return_all = T,custom_pathways = canonical_pathways)
plt_list[[i]] = res$plt
}
gridExtra::grid.arrange(grobs = plt_list)

Expression by scores from cnmf
# Make metagene names
for (i in 1:ncol(all_metagenes)) {
colnames(all_metagenes)[i] = "metagene." %>% paste0(i)
}
#add each metagene to metadata
for (i in 1:ncol(all_metagenes)) {
metage_metadata = all_metagenes %>% select(i)
acc1_cancer_cells = AddMetaData(object = acc1_cancer_cells,metadata = metage_metadata)
}
print_tab(plt =
FeaturePlot(object = acc1_cancer_cells,features = colnames(all_metagenes))
,title = "expression",subtitle_num = 2)
expression

print_tab(
plt = FeaturePlot(object = acc1_cancer_cells,features = colnames(all_metagenes),max.cutoff = 0.05)
,title = "max.cutoff = 0.05",subtitle_num = 2)
max.cutoff = 0.05

NA
Expression by scores from cnmf + Z score
all_metagenes_norm= scale(all_metagenes) %>% as.data.frame()
# Make metagene names
for (i in 1:ncol(all_metagenes_norm)) {
colnames(all_metagenes_norm)[i] = "metagene." %>% paste0(i)
}
#add each metagene to metadata
for (i in 1:ncol(all_metagenes_norm)) {
metage_metadata = all_metagenes_norm %>% select(i)
acc1_cancer_cells = AddMetaData(object = acc1_cancer_cells,metadata = metage_metadata)
}
print_tab(plt =
FeaturePlot(object = acc1_cancer_cells,features = colnames(all_metagenes))
,title = "expression",subtitle_num = 2)
expression

print_tab(
plt = FeaturePlot(object = acc1_cancer_cells,features = colnames(all_metagenes),max.cutoff = 0.5)
,title = "max.cutoff = 0.5",subtitle_num = 2)
max.cutoff = 0.5

NA
Expression by coefficients inversion * expression
all_metagenes_inversed = expression_inversion(gep_scores = gep_scores %>% as.matrix() ,dataset = acc1_cancer_cells) %>% t() %>% as.data.frame()
# Make metagene names
for (i in 1:ncol(all_metagenes_inversed)) {
colnames(all_metagenes_inversed)[i] = "metagene." %>% paste0(i)
}
#add each metagene to metadata
for (i in 1:ncol(all_metagenes_inversed)) {
metage_metadata = all_metagenes_inversed %>% select(i)
acc1_cancer_cells = AddMetaData(object = acc1_cancer_cells,metadata = metage_metadata)
}
FeaturePlot(object = acc1_cancer_cells,features = colnames(all_metagenes_inversed))

Expression by (coefficients inversion sum to 1) * expression
gep_scores_norm = apply(gep_scores, 2, no_neg)
gep_scores_norm = apply(gep_scores_norm, 2, sum_2_one)
all_metagenes_inversed = expression_inversion(gep_scores = gep_scores_norm ,dataset = acc1_cancer_cells) %>% t() %>% as.data.frame()
# Make metagene names
for (i in 1:ncol(all_metagenes_inversed)) {
colnames(all_metagenes_inversed)[i] = "metagene." %>% paste0(i)
}
#add each metagene to metadata
for (i in 1:ncol(all_metagenes_inversed)) {
metage_metadata = all_metagenes_inversed %>% select(i)
acc1_cancer_cells = AddMetaData(object = acc1_cancer_cells,metadata = metage_metadata)
}
print_tab(plt =
FeaturePlot(object = acc1_cancer_cells,features = colnames(all_metagenes))
,title = "expression",subtitle_num = 2)
expression

print_tab(
plt = FeaturePlot(object = acc1_cancer_cells,features = colnames(all_metagenes),max.cutoff = 750)
,title = "max.cutoff = 750",subtitle_num = 2)
max.cutoff = 750

NA
Expression by coefficients sum to 1 * expression
gep_scores_norm = apply(gep_scores, 2, no_neg)
gep_scores_norm = apply(gep_scores_norm, 2, sum_2_one) %>% as.data.frame()
all_metagenes_mult = expression_mult(gep_scores = gep_scores_norm ,dataset = acc1_cancer_cells,top_genes = T)
# Make metagene names
for (i in 1:ncol(all_metagenes_mult)) {
colnames(all_metagenes_mult)[i] = "metagene." %>% paste0(i)
}
#add each metagene to metadata
for (i in 1:ncol(all_metagenes_mult)) {
metage_metadata = all_metagenes_mult %>% select(i)
acc1_cancer_cells = AddMetaData(object = acc1_cancer_cells,metadata = metage_metadata)
}
print_tab(plt =
FeaturePlot(object = acc1_cancer_cells,features = colnames(all_metagenes))
,title = "expression",subtitle_num = 2)
expression

print_tab(
plt = FeaturePlot(object = acc1_cancer_cells,features = colnames(all_metagenes),max.cutoff = 50)
,title = "max.cutoff = 50",subtitle_num = 2)
max.cutoff = 50

NA
LS0tCnRpdGxlOiAnYHIgcnN0dWRpb2FwaTo6Z2V0U291cmNlRWRpdG9yQ29udGV4dCgpJHBhdGggJT4lIGJhc2VuYW1lKCkgJT4lIGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLHJlcGxhY2VtZW50ID0gIiIpYCcgCmF1dGhvcjogIkF2aXNoYWkgV2l6ZWwiCmRhdGU6ICdgciBTeXMudGltZSgpYCcKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdG9jOiB5ZXMKICAgIHRvY19jb2xsYXBzZTogeWVzCiAgICB0b2NfZmxvYXQ6IAogICAgICBjb2xsYXBzZWQ6IEZBTFNFCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvY19kZXB0aDogMQotLS0KCiMjIFBhcmFtZXRlcnMKCmBgYHtyIHdhcm5pbmc9RkFMU0V9CnN1ZmZpeCA9ICIiCmRhdGFfdG9fcmVhZCA9ICIiCmBgYAoKCiMjIGZ1bmN0aW9ucwoKYGBge3Igd2FybmluZz1GQUxTRX0Kc291cmNlX2Zyb21fZ2l0aHViKHJlcG9zaXRveSA9ICJERUdfZnVuY3Rpb25zIix2ZXJzaW9uID0gIjAuMi4yNCIpCnNvdXJjZV9mcm9tX2dpdGh1YihyZXBvc2l0b3kgPSAiSE1TQ19mdW5jdGlvbnMiLHZlcnNpb24gPSAiMC4xLjEyIixzY3JpcHRfbmFtZSA9ICJmdW5jdGlvbnMuUiIpCnNvdXJjZV9mcm9tX2dpdGh1YihyZXBvc2l0b3kgPSAiY05NRl9mdW5jdGlvbnMiLHZlcnNpb24gPSAiMC4zLjcyIixzY3JpcHRfbmFtZSA9ICJjbm1mX2Z1bmN0aW9uX0hhcm1vbnkuUiIpCgpub19uZWcgPC0gZnVuY3Rpb24oeCkgewogIHggPSB4ICsgYWJzKG1pbih4KSkKICB4Cn0KCnN1bV8yX29uZSA8LSBmdW5jdGlvbih4KSB7CiAgeCA9eC9zdW0oeCkKICB4Cn0KCmBgYAoKIyMgRGF0YQoKYGBge3J9CgpgYGAKCgoKIyMgTG9hZCBvYmplY3QKYGBge3B5dGhvbn0KZnJvbSBjbm1mIGltcG9ydCBjTk1GCmltcG9ydCBwaWNrbGUKbmZlYXR1cmVzID0gIjJLIgpmID0gb3BlbignLi9EYXRhL2NOTUYvSE1TQ19jTk1GXycgKyBuZmVhdHVyZXMrICd2YXJnZW5lcy9jbm1mX29iai5wY2tsJywgJ3JiJykKY25tZl9vYmogPSBwaWNrbGUubG9hZChmKQpmLmNsb3NlKCkKYGBgCgoKYGBge3B5dGhvbn0Kc2VsZWN0ZWRfayA9IDQKZGVuc2l0eV90aHJlc2hvbGQgPSAwLjEKY25tZl9vYmouY29uc2Vuc3VzKGs9c2VsZWN0ZWRfaywgZGVuc2l0eV90aHJlc2hvbGQ9ZGVuc2l0eV90aHJlc2hvbGQsc2hvd19jbHVzdGVyaW5nPVRydWUpCnVzYWdlX25vcm0sIGdlcF9zY29yZXMsIGdlcF90cG0sIHRvcGdlbmVzID0gY25tZl9vYmoubG9hZF9yZXN1bHRzKEs9c2VsZWN0ZWRfaywgZGVuc2l0eV90aHJlc2hvbGQ9ZGVuc2l0eV90aHJlc2hvbGQpCmBgYAoKYGBge3J9CmdlcF9zY29yZXMgPSBweSRnZXBfc2NvcmVzCmdlcF90cG0gPSBweSRnZXBfdHBtCmFsbF9tZXRhZ2VuZXM9IHB5JHVzYWdlX25vcm0KYGBgCgojIEhhbGxtYXJrIEVucmljaG1lbnQgYW5hbHlzaXMgYnkgdG9wIDIwMCBnZW5lcyBvZiBlYWNoIHByb2dyYW0KYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OCwgcmVzdWx0cz0naGlkZSd9CnBsdF9saXN0ID0gbGlzdCgpCmZvciAoaSBpbiAxOm5jb2woZ2VwX3Njb3JlcykpIHsKICB0b3BfZ2VuZXMgPSBnZXBfc2NvcmVzICAlPiUgIGFycmFuZ2UoZGVzYyhnZXBfc2NvcmVzW2ldKSkgI3NvcnQgYnkgc2NvcmUgYQogIHRvcCA9IGhlYWQocm93bmFtZXModG9wX2dlbmVzKSwyMDApICN0YWtlIHRvcCB0b3BfZ2VuZXNfbnVtCiAgcmVzID0gZ2VuZXNfdmVjX2VucmljaG1lbnQoZ2VuZXMgPSB0b3AsYmFja2dyb3VuZCA9IHJvd25hbWVzKGdlcF9zY29yZXMpLGhvbWVyID0gVCx0aXRsZSA9IAogICAgICAgICAgICAgICAgICAgIGksc2lsZW50ID0gVCxyZXR1cm5fYWxsID0gVCkKICAgCiAgcGx0X2xpc3RbW2ldXSA9IHJlcyRwbHQKfQpncmlkRXh0cmE6OmdyaWQuYXJyYW5nZShncm9icyA9IHBsdF9saXN0KQpgYGAKCiMgSGFsbG1hcmsgKyBjYW5vbmljYWwgRW5yaWNobWVudCBhbmFseXNpcyBieSB0b3AgMjAwIGdlbmVzIG9mIGVhY2ggcHJvZ3JhbQoKYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OCwgcmVzdWx0cz0naGlkZSd9CgpjYW5vbmljYWxfcGF0aHdheXMgPSBtc2lnZGJyKHNwZWNpZXMgPSAiSG9tbyBzYXBpZW5zIiwgY2F0ZWdvcnkgPSAiQzIiKSAlPiUgZHBseXI6OmZpbHRlcihnc19zdWJjYXQgIT0gIkNHUCIpICU+JSAgZHBseXI6OmRpc3RpbmN0KGdzX25hbWUsIGdlbmVfc3ltYm9sKSAKCnBsdF9saXN0ID0gbGlzdCgpCmZvciAoaSBpbiAxOm5jb2woZ2VwX3Njb3JlcykpIHsKICB0b3BfZ2VuZXMgPSBnZXBfc2NvcmVzICAlPiUgIGFycmFuZ2UoZGVzYyhnZXBfc2NvcmVzW2ldKSkgI3NvcnQgYnkgc2NvcmUgYQogIHRvcCA9IGhlYWQocm93bmFtZXModG9wX2dlbmVzKSwyMDApICN0YWtlIHRvcCB0b3BfZ2VuZXNfbnVtCiAgcmVzID0gZ2VuZXNfdmVjX2VucmljaG1lbnQoZ2VuZXMgPSB0b3AsYmFja2dyb3VuZCA9IHJvd25hbWVzKGdlcF9zY29yZXMpLGhvbWVyID0gVCx0aXRsZSA9IAogICAgICAgICAgICAgICAgICAgIGksc2lsZW50ID0gVCxyZXR1cm5fYWxsID0gVCxjdXN0b21fcGF0aHdheXMgPSBjYW5vbmljYWxfcGF0aHdheXMpCiAgIAogIHBsdF9saXN0W1tpXV0gPSByZXMkcGx0Cn0KZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UoZ3JvYnMgPSBwbHRfbGlzdCkKYGBgCgojIEV4cHJlc3Npb24gYnkgc2NvcmVzIGZyb20gY25tZiB7LnRhYnNldH0KYGBge3IgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwLCByZXN1bHRzPSdhc2lzJ30gCiMgTWFrZSBtZXRhZ2VuZSBuYW1lcwpmb3IgKGkgaW4gMTpuY29sKGFsbF9tZXRhZ2VuZXMpKSB7CiAgY29sbmFtZXMoYWxsX21ldGFnZW5lcylbaV0gPSAibWV0YWdlbmUuIiAlPiUgcGFzdGUwKGkpCn0KCiNhZGQgZWFjaCBtZXRhZ2VuZSB0byBtZXRhZGF0YQpmb3IgKGkgaW4gMTpuY29sKGFsbF9tZXRhZ2VuZXMpKSB7CiAgbWV0YWdlX21ldGFkYXRhID0gYWxsX21ldGFnZW5lcyAlPiUgc2VsZWN0KGkpCiAgYWNjMV9jYW5jZXJfY2VsbHMgPSBBZGRNZXRhRGF0YShvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyxtZXRhZGF0YSA9IG1ldGFnZV9tZXRhZGF0YSkKfQoKcHJpbnRfdGFiKHBsdCA9IAogICAgICAgICAgICBGZWF0dXJlUGxvdChvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyxmZWF0dXJlcyA9IGNvbG5hbWVzKGFsbF9tZXRhZ2VuZXMpKQosdGl0bGUgPSAiZXhwcmVzc2lvbiIsc3VidGl0bGVfbnVtID0gMikKCgpwcmludF90YWIoCiAgcGx0ID0gRmVhdHVyZVBsb3Qob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsZmVhdHVyZXMgPSBjb2xuYW1lcyhhbGxfbWV0YWdlbmVzKSxtYXguY3V0b2ZmID0gMC4wNSkKICAgICAgICAgICx0aXRsZSA9ICJtYXguY3V0b2ZmID0gMC4wNSIsc3VidGl0bGVfbnVtID0gMikKCmBgYAojIEV4cHJlc3Npb24gYnkgc2NvcmVzIGZyb20gY25tZiArIFogc2NvcmUgey50YWJzZXR9CmBgYHtyIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMCwgcmVzdWx0cz0nYXNpcyd9IAoKCmFsbF9tZXRhZ2VuZXNfbm9ybT0gc2NhbGUoYWxsX21ldGFnZW5lcykgJT4lIGFzLmRhdGEuZnJhbWUoKQojIE1ha2UgbWV0YWdlbmUgbmFtZXMKZm9yIChpIGluIDE6bmNvbChhbGxfbWV0YWdlbmVzX25vcm0pKSB7CiAgY29sbmFtZXMoYWxsX21ldGFnZW5lc19ub3JtKVtpXSA9ICJtZXRhZ2VuZS4iICU+JSBwYXN0ZTAoaSkKfQoKI2FkZCBlYWNoIG1ldGFnZW5lIHRvIG1ldGFkYXRhCmZvciAoaSBpbiAxOm5jb2woYWxsX21ldGFnZW5lc19ub3JtKSkgewogIG1ldGFnZV9tZXRhZGF0YSA9IGFsbF9tZXRhZ2VuZXNfbm9ybSAlPiUgc2VsZWN0KGkpCiAgYWNjMV9jYW5jZXJfY2VsbHMgPSBBZGRNZXRhRGF0YShvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyxtZXRhZGF0YSA9IG1ldGFnZV9tZXRhZGF0YSkKfQoKcHJpbnRfdGFiKHBsdCA9IAogICAgICAgICAgICBGZWF0dXJlUGxvdChvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyxmZWF0dXJlcyA9IGNvbG5hbWVzKGFsbF9tZXRhZ2VuZXMpKQosdGl0bGUgPSAiZXhwcmVzc2lvbiIsc3VidGl0bGVfbnVtID0gMikKCgpwcmludF90YWIoCiAgcGx0ID0gRmVhdHVyZVBsb3Qob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsZmVhdHVyZXMgPSBjb2xuYW1lcyhhbGxfbWV0YWdlbmVzKSxtYXguY3V0b2ZmID0gMC41KQogICAgICAgICAgLHRpdGxlID0gIm1heC5jdXRvZmYgPSAwLjUiLHN1YnRpdGxlX251bSA9IDIpCgpgYGAKIyBFeHByZXNzaW9uIGJ5IGNvZWZmaWNpZW50cyBpbnZlcnNpb24gKiBleHByZXNzaW9uICB7LnRhYnNldH0KYGBge3J9CgphbGxfbWV0YWdlbmVzX2ludmVyc2VkICA9IGV4cHJlc3Npb25faW52ZXJzaW9uKGdlcF9zY29yZXMgPSBnZXBfc2NvcmVzICU+JSBhcy5tYXRyaXgoKSAsZGF0YXNldCA9IGFjYzFfY2FuY2VyX2NlbGxzKSAlPiUgdCgpICU+JSBhcy5kYXRhLmZyYW1lKCkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTAsIHJlc3VsdHM9J2FzaXMnfSAKCiMgTWFrZSBtZXRhZ2VuZSBuYW1lcwpmb3IgKGkgaW4gMTpuY29sKGFsbF9tZXRhZ2VuZXNfaW52ZXJzZWQpKSB7CiAgY29sbmFtZXMoYWxsX21ldGFnZW5lc19pbnZlcnNlZClbaV0gPSAibWV0YWdlbmUuIiAlPiUgcGFzdGUwKGkpCn0KCiNhZGQgZWFjaCBtZXRhZ2VuZSB0byBtZXRhZGF0YQpmb3IgKGkgaW4gMTpuY29sKGFsbF9tZXRhZ2VuZXNfaW52ZXJzZWQpKSB7CiAgbWV0YWdlX21ldGFkYXRhID0gYWxsX21ldGFnZW5lc19pbnZlcnNlZCAlPiUgc2VsZWN0KGkpCiAgYWNjMV9jYW5jZXJfY2VsbHMgPSBBZGRNZXRhRGF0YShvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyxtZXRhZGF0YSA9IG1ldGFnZV9tZXRhZGF0YSkKfQoKRmVhdHVyZVBsb3Qob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsZmVhdHVyZXMgPSBjb2xuYW1lcyhhbGxfbWV0YWdlbmVzX2ludmVyc2VkKSkKCmBgYAoKIyBFeHByZXNzaW9uIGJ5IChjb2VmZmljaWVudHMgaW52ZXJzaW9uIHN1bSB0byAxKSAqIGV4cHJlc3Npb24gey50YWJzZXR9CmBgYHtyfQpnZXBfc2NvcmVzX25vcm0gPSBhcHBseShnZXBfc2NvcmVzLCAyLCBub19uZWcpCmdlcF9zY29yZXNfbm9ybSA9IGFwcGx5KGdlcF9zY29yZXNfbm9ybSwgMiwgc3VtXzJfb25lKQoKCmFsbF9tZXRhZ2VuZXNfaW52ZXJzZWQgID0gZXhwcmVzc2lvbl9pbnZlcnNpb24oZ2VwX3Njb3JlcyA9IGdlcF9zY29yZXNfbm9ybSAsZGF0YXNldCA9IGFjYzFfY2FuY2VyX2NlbGxzKSAlPiUgdCgpICU+JSBhcy5kYXRhLmZyYW1lKCkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTAsIHJlc3VsdHM9J2FzaXMnfSAKCiMgTWFrZSBtZXRhZ2VuZSBuYW1lcwpmb3IgKGkgaW4gMTpuY29sKGFsbF9tZXRhZ2VuZXNfaW52ZXJzZWQpKSB7CiAgY29sbmFtZXMoYWxsX21ldGFnZW5lc19pbnZlcnNlZClbaV0gPSAibWV0YWdlbmUuIiAlPiUgcGFzdGUwKGkpCn0KCiNhZGQgZWFjaCBtZXRhZ2VuZSB0byBtZXRhZGF0YQpmb3IgKGkgaW4gMTpuY29sKGFsbF9tZXRhZ2VuZXNfaW52ZXJzZWQpKSB7CiAgbWV0YWdlX21ldGFkYXRhID0gYWxsX21ldGFnZW5lc19pbnZlcnNlZCAlPiUgc2VsZWN0KGkpCiAgYWNjMV9jYW5jZXJfY2VsbHMgPSBBZGRNZXRhRGF0YShvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyxtZXRhZGF0YSA9IG1ldGFnZV9tZXRhZGF0YSkKfQoKcHJpbnRfdGFiKHBsdCA9IAogICAgICAgICAgICBGZWF0dXJlUGxvdChvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyxmZWF0dXJlcyA9IGNvbG5hbWVzKGFsbF9tZXRhZ2VuZXMpKQosdGl0bGUgPSAiZXhwcmVzc2lvbiIsc3VidGl0bGVfbnVtID0gMikKCgpwcmludF90YWIoCiAgcGx0ID0gRmVhdHVyZVBsb3Qob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsZmVhdHVyZXMgPSBjb2xuYW1lcyhhbGxfbWV0YWdlbmVzKSxtYXguY3V0b2ZmID0gNzUwKQogICAgICAgICAgLHRpdGxlID0gIm1heC5jdXRvZmYgPSA3NTAiLHN1YnRpdGxlX251bSA9IDIpCmBgYAoKIyBFeHByZXNzaW9uIGJ5IGNvZWZmaWNpZW50cyBzdW0gdG8gMSAqIGV4cHJlc3Npb24gey50YWJzZXR9CmBgYHtyfQpnZXBfc2NvcmVzX25vcm0gPSBhcHBseShnZXBfc2NvcmVzLCAyLCBub19uZWcpCmdlcF9zY29yZXNfbm9ybSA9IGFwcGx5KGdlcF9zY29yZXNfbm9ybSwgMiwgc3VtXzJfb25lKSAlPiUgYXMuZGF0YS5mcmFtZSgpCgoKYWxsX21ldGFnZW5lc19tdWx0ICA9IGV4cHJlc3Npb25fbXVsdChnZXBfc2NvcmVzID0gZ2VwX3Njb3Jlc19ub3JtICxkYXRhc2V0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdG9wX2dlbmVzID0gVCkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTAsIHJlc3VsdHM9J2FzaXMnfSAKCiMgTWFrZSBtZXRhZ2VuZSBuYW1lcwpmb3IgKGkgaW4gMTpuY29sKGFsbF9tZXRhZ2VuZXNfbXVsdCkpIHsKICBjb2xuYW1lcyhhbGxfbWV0YWdlbmVzX211bHQpW2ldID0gIm1ldGFnZW5lLiIgJT4lIHBhc3RlMChpKQp9CgojYWRkIGVhY2ggbWV0YWdlbmUgdG8gbWV0YWRhdGEKZm9yIChpIGluIDE6bmNvbChhbGxfbWV0YWdlbmVzX211bHQpKSB7CiAgbWV0YWdlX21ldGFkYXRhID0gYWxsX21ldGFnZW5lc19tdWx0ICU+JSBzZWxlY3QoaSkKICBhY2MxX2NhbmNlcl9jZWxscyA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLG1ldGFkYXRhID0gbWV0YWdlX21ldGFkYXRhKQp9CgpwcmludF90YWIocGx0ID0gCiAgICAgICAgICAgIEZlYXR1cmVQbG90KG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLGZlYXR1cmVzID0gY29sbmFtZXMoYWxsX21ldGFnZW5lcykpCix0aXRsZSA9ICJleHByZXNzaW9uIixzdWJ0aXRsZV9udW0gPSAyKQoKCnByaW50X3RhYigKICBwbHQgPSBGZWF0dXJlUGxvdChvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyxmZWF0dXJlcyA9IGNvbG5hbWVzKGFsbF9tZXRhZ2VuZXMpLG1heC5jdXRvZmYgPSA1MCkKICAgICAgICAgICx0aXRsZSA9ICJtYXguY3V0b2ZmID0gNTAiLHN1YnRpdGxlX251bSA9IDIpCmBgYAo=