all_acc_cancer_cells = readRDS("./Data/acc_cancer_cells_V3.RDS")
original_myo_genes = c("TP63", "TP73", "CAV1", "CDH3", "KRT5", "KRT14", "ACTA2", "TAGLN", "MYLK", "DKK3")
original_lum_genes = c("KIT", "EHF", "ELF5", "KRT7", "CLDN3", "CLDN4", "CD24", "LGALS3", "LCN2", "SLPI")
notch_targets_genes = c("NRARP", "NOTCH3", "HES4", "HEY1", "HEY2")
notch_ligands = c("DLL1", "JAG1", "JAG2", "HEY1")
orig_myoscore=apply(acc_cancerCells_noACC1@assays[["RNA"]][original_myo_genes,],2,mean)
orig_lescore=apply(acc_cancerCells_noACC1@assays[["RNA"]][original_lum_genes,],2,mean)
notch_score=apply(acc_cancerCells_noACC1@assays[["RNA"]][notch_targets_genes,],2,mean)
notch_ligands_score=apply(acc_cancerCells_noACC1@assays[["RNA"]][notch_ligands,],2,mean)
acc_cancerCells_noACC1 = AddMetaData(object = acc_cancerCells_noACC1,metadata = orig_lescore-orig_myoscore,col.name = "lum_over_myo")
acc_cancerCells_noACC1 = AddMetaData(object = acc_cancerCells_noACC1,metadata = orig_myoscore,col.name = "myo_score")
acc_cancerCells_noACC1 = AddMetaData(object = acc_cancerCells_noACC1,metadata = orig_lescore,col.name = "lum_score")
acc_cancerCells_noACC1 = AddMetaData(object = acc_cancerCells_noACC1,metadata = notch_score,col.name = "notch_score")
acc_cancerCells_noACC1 = AddMetaData(object = acc_cancerCells_noACC1,metadata = notch_ligands_score,col.name = "notch_ligands_score_score")
Load object
reticulate::repl_python()
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)
/sci/labs/yotamd/lab_share/avishai.wizel/python_envs/miniconda/envs/cnmf_env_6/lib/python3.7/site-packages/scanpy/preprocessing/_simple.py:843: UserWarning: Received a view of an AnnData. Making a copy.
view_to_actual(adata)
usage_norm, gep_scores, gep_tpm, topgenes = cnmf_obj.load_results(K=selected_k, density_threshold=density_threshold)
quit
gep_scores = py$gep_scores
gep_tpm = py$gep_tpm
all_metagenes= py$usage_norm
def get_norm_counts(counts, tpm,high_variance_genes_filter): #from cnmf.py
import numpy as np
import scipy.sparse as sp
## Subset out high-variance genes
norm_counts = counts[:, high_variance_genes_filter].copy()
## Scale genes to unit variance
if sp.issparse(tpm.X):
sc.pp.scale(norm_counts, zero_center=False)
if np.isnan(norm_counts.X.data).sum() > 0:
print('Warning NaNs in normalized counts matrix')
else:
norm_counts.X /= norm_counts.X.std(axis=0, ddof=1)
if np.isnan(norm_counts.X).sum().sum() > 0:
print('Warning NaNs in normalized counts matrix')
## Check for any cells that have 0 counts of the overdispersed genes
zerocells = norm_counts.X.sum(axis=1)==0
if zerocells.sum()>0:
examples = norm_counts.obs.index[zerocells]
print('Warning: %d cells have zero counts of overdispersed genes. E.g. %s' % (zerocells.sum(), examples[0]))
print('Consensus step may not run when this is the case')
return(norm_counts)
def get_usage_from_score(counts,tpm, genes,cnmf_obj):
import anndata as ad
import scanpy as sc
import numpy as np
from sklearn.decomposition import non_negative_factorization
import pandas as pd
counts_adata = ad.AnnData(counts)
tpm_adata = ad.AnnData(tpm)
norm_counts = get_norm_counts(counts=counts_adata,tpm=tpm_adata,high_variance_genes_filter=np.array(genes)) #norm counts as cnmf
spectra = cnmf_obj.get_median_spectra(k=4) #get score
spectra = spectra[spectra.columns.intersection(genes)] #remove genes not in @genes
usage_by_calc,_,_ = non_negative_factorization(X=norm_counts.X, H = spectra.values, update_H=False,n_components = 4,max_iter=1000,init ="random")
usage_by_calc = pd.DataFrame(usage_by_calc, index=counts.index, columns=spectra.index) #insert to df+add names
usage_by_calc = usage_by_calc.div(usage_by_calc.sum(axis=1), axis=0) # sum rows to 1
return(usage_by_calc)
Get expression
nfeatures = 2000
acc1_cancer_cells = FindVariableFeatures(object = acc1_cancer_cells,nfeatures = nfeatures)
vargenes = VariableFeatures(object = acc1_cancer_cells)
hmsc_expression = t(as.matrix(GetAssayData(acc1_cancer_cells,slot='data')))
hmsc_expression = 2**hmsc_expression #convert from log2(tpm+1) to tpm
hmsc_expression = hmsc_expression-1
hmsc_expression = hmsc_expression[,!colSums(hmsc_expression==0, na.rm=TRUE)==nrow(hmsc_expression)] #delete rows that have all 0
hmsc_expression = hmsc_expression[,vargenes]
hmsc_expression = hmsc_expression %>% as.data.frame()
Calculate usage
hmsc_expression = r.hmsc_expression
vargenes = r.vargenes
usage_by_calc = get_usage_from_score(counts=hmsc_expression,tpm=hmsc_expression,genes= vargenes,cnmf_obj=cnmf_obj)
all_metagenes= py$usage_by_calc
all_metagenes = all_metagenes[,c(1,4,3,2)]
Programs enrichments
#Hallmarks:
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
}
p = ggarrange(plotlist = plt_list)
print_tab(plt = p,title = "HALLMARK enrichment")
HALLMARK enrichment

#Canonical:
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
}
p = ggarrange(plotlist = plt_list)
print_tab(plt = p,title = "canonical pathway enrichment")
canonical pathway enrichment

NA
luminal and myo genes in score
# lum genes in metagenes
message("lum genes in metagenes:")
lum genes in metagenes:
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
cat(paste0("metagene ",i,": "))
print(original_lum_genes[original_lum_genes %in% top])
}
metagene 1: [1] "KRT7" "SLPI"
metagene 2: [1] "CLDN4"
metagene 3: character(0)
metagene 4: [1] "KRT7" "LGALS3" "LCN2" "SLPI"
cat("\n")
# myo genes in metagenes
message("myo genes in metagenes:")
myo genes in metagenes:
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
cat(paste0("metagene ",i,": "))
print(original_myo_genes[original_myo_genes %in% top])
}
metagene 1: [1] "KRT14" "ACTA2" "DKK3"
metagene 2: character(0)
metagene 3: character(0)
metagene 4: character(0)
cat("\n")
notch_genes = c("JAG1","JAG2","NOTCH3","NOTCH2","NOTCH1","DLL1","MYB","HES4","HEY1","HEY2","NRARP")
# notch genes in metagenes
message("notch genes in metagenes:")
notch genes in metagenes:
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
cat(paste0("metagene ",i,": "))
print(notch_genes[notch_genes %in% top])
}
metagene 1: character(0)
metagene 2: character(0)
metagene 3: character(0)
metagene 4: character(0)
cat("\n")
UMAPS
colors = rainbow(acc_cancerCells_noACC1$program.assignment %>% unique() %>% length()-1)
colors = c(colors,"grey")
print_tab(plt = DimPlot(object = acc_cancerCells_noACC1,group.by = "program.assignment",cols =colors),title = "program.assignment")
program.assignment

print_tab(plt = DimPlot(object = acc_cancerCells_noACC1,group.by = "patient.ident"),title = "patient.ident")
patient.ident

print_tab(plt = FeaturePlot(object = acc_cancerCells_noACC1,features = "lum_score"),title = "lum_score")
lum_score

print_tab(plt = FeaturePlot(object = acc_cancerCells_noACC1,features = "myo_score"),title = "myo_score")
myo_score

NA
Notch score
for (metagene in c("metagene.1","metagene.2","metagene.4")) {
lum_score_vs_programScore = FetchData(object = acc_cancerCells_noACC1,vars = c(metagene,"notch_score"))
print_tab(plt =
ggscatter(lum_score_vs_programScore, x = metagene, y = "notch_score",
add = "reg.line", conf.int = TRUE,
cor.coef = TRUE, cor.method = "pearson")
,title = metagene)
}
Notch ligands score
for (metagene in c("metagene.1","metagene.2","metagene.4")) {
lum_score_vs_programScore = FetchData(object = acc_cancerCells_noACC1,vars = c(metagene,"notch_ligands_score_score"))
print_tab(plt =
ggscatter(lum_score_vs_programScore, x = metagene, y = "notch_ligands_score_score",
add = "reg.line", conf.int = TRUE,
cor.coef = TRUE, cor.method = "pearson")
,title = metagene)
}
LS0tCnRpdGxlOiAnYHIgcnN0dWRpb2FwaTo6Z2V0U291cmNlRWRpdG9yQ29udGV4dCgpJHBhdGggJT4lIGJhc2VuYW1lKCkgJT4lIGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLHJlcGxhY2VtZW50ID0gIiIpYCcgCmF1dGhvcjogIkF2aXNoYWkgV2l6ZWwiCmRhdGU6ICdgciBTeXMuRGF0ZSgpYCcKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdG9jOiB5ZXMKICAgIHRvY19jb2xsYXBzZTogeWVzCiAgICB0b2NfZmxvYXQ6IAogICAgICBjb2xsYXBzZWQ6IEZBTFNFCi0tLQoKCmBgYHtyfQphbGxfYWNjX2NhbmNlcl9jZWxscyA9IHJlYWRSRFMoIi4vRGF0YS9hY2NfY2FuY2VyX2NlbGxzX1YzLlJEUyIpCmFjY19jYW5jZXJDZWxsc19ub0FDQzEgPSBzdWJzZXQoYWxsX2FjY19jYW5jZXJfY2VsbHMsc3Vic2V0ID0gcGF0aWVudC5pZGVudCE9ICJBQ0MxIikKCmBgYAoKYGBge3J9CiAgb3JpZ2luYWxfbXlvX2dlbmVzID0gYygiVFA2MyIsICJUUDczIiwgIkNBVjEiLCAiQ0RIMyIsICJLUlQ1IiwgIktSVDE0IiwgIkFDVEEyIiwgIlRBR0xOIiwgIk1ZTEsiLCAiREtLMyIpCiAgb3JpZ2luYWxfbHVtX2dlbmVzID0gYygiS0lUIiwgIkVIRiIsICJFTEY1IiwgIktSVDciLCAiQ0xETjMiLCAiQ0xETjQiLCAiQ0QyNCIsICJMR0FMUzMiLCAiTENOMiIsICJTTFBJIikKICBub3RjaF90YXJnZXRzX2dlbmVzID0gYygiTlJBUlAiLCAiTk9UQ0gzIiwgIkhFUzQiLCAiSEVZMSIsICJIRVkyIikKICBub3RjaF9saWdhbmRzID0gYygiRExMMSIsICJKQUcxIiwgIkpBRzIiLCAiSEVZMSIpCgogIG9yaWdfbXlvc2NvcmU9YXBwbHkoYWNjX2NhbmNlckNlbGxzX25vQUNDMUBhc3NheXNbWyJSTkEiXV1bb3JpZ2luYWxfbXlvX2dlbmVzLF0sMixtZWFuKQogIG9yaWdfbGVzY29yZT1hcHBseShhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxQGFzc2F5c1tbIlJOQSJdXVtvcmlnaW5hbF9sdW1fZ2VuZXMsXSwyLG1lYW4pCiAgbm90Y2hfc2NvcmU9YXBwbHkoYWNjX2NhbmNlckNlbGxzX25vQUNDMUBhc3NheXNbWyJSTkEiXV1bbm90Y2hfdGFyZ2V0c19nZW5lcyxdLDIsbWVhbikKICBub3RjaF9saWdhbmRzX3Njb3JlPWFwcGx5KGFjY19jYW5jZXJDZWxsc19ub0FDQzFAYXNzYXlzW1siUk5BIl1dW25vdGNoX2xpZ2FuZHMsXSwyLG1lYW4pCgogIGFjY19jYW5jZXJDZWxsc19ub0FDQzEgPSBBZGRNZXRhRGF0YShvYmplY3QgPSBhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxLG1ldGFkYXRhID0gb3JpZ19sZXNjb3JlLW9yaWdfbXlvc2NvcmUsY29sLm5hbWUgPSAibHVtX292ZXJfbXlvIikKICAgIGFjY19jYW5jZXJDZWxsc19ub0FDQzEgPSBBZGRNZXRhRGF0YShvYmplY3QgPSBhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxLG1ldGFkYXRhID0gb3JpZ19teW9zY29yZSxjb2wubmFtZSA9ICJteW9fc2NvcmUiKQogICAgYWNjX2NhbmNlckNlbGxzX25vQUNDMSA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IGFjY19jYW5jZXJDZWxsc19ub0FDQzEsbWV0YWRhdGEgPSBvcmlnX2xlc2NvcmUsY29sLm5hbWUgPSAibHVtX3Njb3JlIikKICAgIGFjY19jYW5jZXJDZWxsc19ub0FDQzEgPSBBZGRNZXRhRGF0YShvYmplY3QgPSBhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxLG1ldGFkYXRhID0gbm90Y2hfc2NvcmUsY29sLm5hbWUgPSAibm90Y2hfc2NvcmUiKQogICAgCiAgYWNjX2NhbmNlckNlbGxzX25vQUNDMSA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IGFjY19jYW5jZXJDZWxsc19ub0FDQzEsbWV0YWRhdGEgPSBub3RjaF9saWdhbmRzX3Njb3JlLGNvbC5uYW1lID0gIm5vdGNoX2xpZ2FuZHNfc2NvcmVfc2NvcmUiKQoKCmBgYAojIyBMb2FkIG9iamVjdApgYGB7cHl0aG9ufQpmcm9tIGNubWYgaW1wb3J0IGNOTUYKaW1wb3J0IHBpY2tsZQpuZmVhdHVyZXMgPSAiMksiCmYgPSBvcGVuKCcuL0RhdGEvY05NRi9ITVNDX2NOTUZfJyArIG5mZWF0dXJlcysgJ3ZhcmdlbmVzL2NubWZfb2JqLnBja2wnLCAncmInKQpjbm1mX29iaiA9IHBpY2tsZS5sb2FkKGYpCmYuY2xvc2UoKQpgYGAKCmBgYHtweXRob259CnNlbGVjdGVkX2sgPSA0CmRlbnNpdHlfdGhyZXNob2xkID0gMC4xCmNubWZfb2JqLmNvbnNlbnN1cyhrPXNlbGVjdGVkX2ssIGRlbnNpdHlfdGhyZXNob2xkPWRlbnNpdHlfdGhyZXNob2xkLHNob3dfY2x1c3RlcmluZz1UcnVlKQp1c2FnZV9ub3JtLCBnZXBfc2NvcmVzLCBnZXBfdHBtLCB0b3BnZW5lcyA9IGNubWZfb2JqLmxvYWRfcmVzdWx0cyhLPXNlbGVjdGVkX2ssIGRlbnNpdHlfdGhyZXNob2xkPWRlbnNpdHlfdGhyZXNob2xkKQpgYGAKCmBgYHtyfQpnZXBfc2NvcmVzID0gcHkkZ2VwX3Njb3JlcwpnZXBfdHBtID0gcHkkZ2VwX3RwbQphbGxfbWV0YWdlbmVzPSBweSR1c2FnZV9ub3JtCmBgYAoKCgpgYGB7cHl0aG9ufQpkZWYgZ2V0X25vcm1fY291bnRzKGNvdW50cywgdHBtLGhpZ2hfdmFyaWFuY2VfZ2VuZXNfZmlsdGVyKTogI2Zyb20gY25tZi5weQogICAgaW1wb3J0IG51bXB5IGFzIG5wCiAgICBpbXBvcnQgc2NpcHkuc3BhcnNlIGFzIHNwCiAgICAjIyBTdWJzZXQgb3V0IGhpZ2gtdmFyaWFuY2UgZ2VuZXMKICAgIG5vcm1fY291bnRzID0gY291bnRzWzosIGhpZ2hfdmFyaWFuY2VfZ2VuZXNfZmlsdGVyXS5jb3B5KCkKICAKICAgICMjIFNjYWxlIGdlbmVzIHRvIHVuaXQgdmFyaWFuY2UKICAgIGlmIHNwLmlzc3BhcnNlKHRwbS5YKToKICAgICAgICBzYy5wcC5zY2FsZShub3JtX2NvdW50cywgemVyb19jZW50ZXI9RmFsc2UpCiAgICAgICAgaWYgbnAuaXNuYW4obm9ybV9jb3VudHMuWC5kYXRhKS5zdW0oKSA+IDA6CiAgICAgICAgICAgIHByaW50KCdXYXJuaW5nIE5hTnMgaW4gbm9ybWFsaXplZCBjb3VudHMgbWF0cml4JykgICAgICAgICAgICAgICAgICAgICAgIAogICAgZWxzZToKICAgICAgICBub3JtX2NvdW50cy5YIC89IG5vcm1fY291bnRzLlguc3RkKGF4aXM9MCwgZGRvZj0xKQogICAgICAgIGlmIG5wLmlzbmFuKG5vcm1fY291bnRzLlgpLnN1bSgpLnN1bSgpID4gMDoKICAgICAgICAgICAgcHJpbnQoJ1dhcm5pbmcgTmFOcyBpbiBub3JtYWxpemVkIGNvdW50cyBtYXRyaXgnKSAgICAgICAgICAgICAgICAgICAgCiAgICAKICAKICAgICMjIENoZWNrIGZvciBhbnkgY2VsbHMgdGhhdCBoYXZlIDAgY291bnRzIG9mIHRoZSBvdmVyZGlzcGVyc2VkIGdlbmVzCiAgICB6ZXJvY2VsbHMgPSBub3JtX2NvdW50cy5YLnN1bShheGlzPTEpPT0wCiAgICBpZiB6ZXJvY2VsbHMuc3VtKCk+MDoKICAgICAgICBleGFtcGxlcyA9IG5vcm1fY291bnRzLm9icy5pbmRleFt6ZXJvY2VsbHNdCiAgICAgICAgcHJpbnQoJ1dhcm5pbmc6ICVkIGNlbGxzIGhhdmUgemVybyBjb3VudHMgb2Ygb3ZlcmRpc3BlcnNlZCBnZW5lcy4gRS5nLiAlcycgJSAoemVyb2NlbGxzLnN1bSgpLCBleGFtcGxlc1swXSkpCiAgICAgICAgcHJpbnQoJ0NvbnNlbnN1cyBzdGVwIG1heSBub3QgcnVuIHdoZW4gdGhpcyBpcyB0aGUgY2FzZScpCiAgICAKICAgIHJldHVybihub3JtX2NvdW50cykKICAKZGVmIGdldF91c2FnZV9mcm9tX3Njb3JlKGNvdW50cyx0cG0sIGdlbmVzLGNubWZfb2JqKToKICAgICAgaW1wb3J0IGFubmRhdGEgYXMgYWQKICAgICAgaW1wb3J0IHNjYW5weSBhcyBzYwogICAgICBpbXBvcnQgbnVtcHkgYXMgbnAKICAgICAgZnJvbSBza2xlYXJuLmRlY29tcG9zaXRpb24gaW1wb3J0IG5vbl9uZWdhdGl2ZV9mYWN0b3JpemF0aW9uCiAgICAgIGltcG9ydCBwYW5kYXMgYXMgcGQKICAgICAgY291bnRzX2FkYXRhID0gYWQuQW5uRGF0YShjb3VudHMpCiAgICAgIHRwbV9hZGF0YSA9IGFkLkFubkRhdGEodHBtKQogICAgICBub3JtX2NvdW50cyA9IGdldF9ub3JtX2NvdW50cyhjb3VudHM9Y291bnRzX2FkYXRhLHRwbT10cG1fYWRhdGEsaGlnaF92YXJpYW5jZV9nZW5lc19maWx0ZXI9bnAuYXJyYXkoZ2VuZXMpKSAjbm9ybSBjb3VudHMgYXMgY25tZgogICAgICBzcGVjdHJhID0gY25tZl9vYmouZ2V0X21lZGlhbl9zcGVjdHJhKGs9NCkgI2dldCBzY29yZSAKICAgICAgc3BlY3RyYSA9IHNwZWN0cmFbc3BlY3RyYS5jb2x1bW5zLmludGVyc2VjdGlvbihnZW5lcyldICNyZW1vdmUgZ2VuZXMgbm90IGluIEBnZW5lcwogICAgICB1c2FnZV9ieV9jYWxjLF8sXyA9IG5vbl9uZWdhdGl2ZV9mYWN0b3JpemF0aW9uKFg9bm9ybV9jb3VudHMuWCwgSCA9IHNwZWN0cmEudmFsdWVzLCB1cGRhdGVfSD1GYWxzZSxuX2NvbXBvbmVudHMgPSA0LG1heF9pdGVyPTEwMDAsaW5pdCA9InJhbmRvbSIpCiAgICAgIHVzYWdlX2J5X2NhbGMgPSBwZC5EYXRhRnJhbWUodXNhZ2VfYnlfY2FsYywgaW5kZXg9Y291bnRzLmluZGV4LCBjb2x1bW5zPXNwZWN0cmEuaW5kZXgpICNpbnNlcnQgdG8gZGYrYWRkIG5hbWVzCiAgICAgIHVzYWdlX2J5X2NhbGMgPSB1c2FnZV9ieV9jYWxjLmRpdih1c2FnZV9ieV9jYWxjLnN1bShheGlzPTEpLCBheGlzPTApICMgc3VtIHJvd3MgdG8gMSAKICAgICAgcmV0dXJuKHVzYWdlX2J5X2NhbGMpCgpgYGAKIyBHZXQgZXhwcmVzc2lvbgpgYGB7cn0KbmZlYXR1cmVzID0gMjAwMAphY2MxX2NhbmNlcl9jZWxscyA9IEZpbmRWYXJpYWJsZUZlYXR1cmVzKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLG5mZWF0dXJlcyA9IG5mZWF0dXJlcykKdmFyZ2VuZXMgPSBWYXJpYWJsZUZlYXR1cmVzKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzKQpobXNjX2V4cHJlc3Npb24gPSB0KGFzLm1hdHJpeChHZXRBc3NheURhdGEoYWNjMV9jYW5jZXJfY2VsbHMsc2xvdD0nZGF0YScpKSkKaG1zY19leHByZXNzaW9uID0gMioqaG1zY19leHByZXNzaW9uICNjb252ZXJ0IGZyb20gbG9nMih0cG0rMSkgdG8gdHBtCmhtc2NfZXhwcmVzc2lvbiA9IGhtc2NfZXhwcmVzc2lvbi0xCmhtc2NfZXhwcmVzc2lvbiA9IGhtc2NfZXhwcmVzc2lvblssIWNvbFN1bXMoaG1zY19leHByZXNzaW9uPT0wLCBuYS5ybT1UUlVFKT09bnJvdyhobXNjX2V4cHJlc3Npb24pXSAjZGVsZXRlIHJvd3MgdGhhdCBoYXZlIGFsbCAwCmhtc2NfZXhwcmVzc2lvbiA9IGhtc2NfZXhwcmVzc2lvblssdmFyZ2VuZXNdCmhtc2NfZXhwcmVzc2lvbiA9IGhtc2NfZXhwcmVzc2lvbiAgJT4lIGFzLmRhdGEuZnJhbWUoKQoKCmBgYAoKIyBDYWxjdWxhdGUgdXNhZ2UKYGBge3B5dGhvbn0KaG1zY19leHByZXNzaW9uID0gci5obXNjX2V4cHJlc3Npb24KdmFyZ2VuZXMgPSByLnZhcmdlbmVzCnVzYWdlX2J5X2NhbGMgPSBnZXRfdXNhZ2VfZnJvbV9zY29yZShjb3VudHM9aG1zY19leHByZXNzaW9uLHRwbT1obXNjX2V4cHJlc3Npb24sZ2VuZXM9IHZhcmdlbmVzLGNubWZfb2JqPWNubWZfb2JqKQpgYGAKCmBgYHtyfQphbGxfbWV0YWdlbmVzPSBweSR1c2FnZV9ieV9jYWxjCmFsbF9tZXRhZ2VuZXMgPSBhbGxfbWV0YWdlbmVzWyxjKDEsNCwzLDIpXQoKYGBgCgoKIyBQcm9ncmFtcyBlbnJpY2htZW50cyB7LnRhYnNldH0KCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTgsIHJlc3VsdHM9J2FzaXMnfQojSGFsbG1hcmtzOgpwbHRfbGlzdCA9IGxpc3QoKQpmb3IgKGkgaW4gMTpuY29sKGdlcF9zY29yZXMpKSB7CiAgdG9wX2dlbmVzID0gZ2VwX3Njb3JlcyAgJT4lICBhcnJhbmdlKGRlc2MoZ2VwX3Njb3Jlc1tpXSkpICNzb3J0IGJ5IHNjb3JlIGEKICB0b3AgPSBoZWFkKHJvd25hbWVzKHRvcF9nZW5lcyksMjAwKSAjdGFrZSB0b3AgdG9wX2dlbmVzX251bQogIHJlcyA9IGdlbmVzX3ZlY19lbnJpY2htZW50KGdlbmVzID0gdG9wLGJhY2tncm91bmQgPSByb3duYW1lcyhnZXBfc2NvcmVzKSxob21lciA9IFQsdGl0bGUgPSAKICAgICAgICAgICAgICAgICAgICBpLHNpbGVudCA9IFQscmV0dXJuX2FsbCA9IFQpCiAgIAogIHBsdF9saXN0W1tpXV0gPSByZXMkcGx0Cn0KcCA9IGdnYXJyYW5nZShwbG90bGlzdCAgPSBwbHRfbGlzdCkKcHJpbnRfdGFiKHBsdCA9IHAsdGl0bGUgPSAiSEFMTE1BUksgZW5yaWNobWVudCIpCgojQ2Fub25pY2FsOgpjYW5vbmljYWxfcGF0aHdheXMgPSBtc2lnZGJyKHNwZWNpZXMgPSAiSG9tbyBzYXBpZW5zIiwgY2F0ZWdvcnkgPSAiQzIiKSAlPiUgZHBseXI6OmZpbHRlcihnc19zdWJjYXQgIT0gIkNHUCIpICU+JSAgZHBseXI6OmRpc3RpbmN0KGdzX25hbWUsIGdlbmVfc3ltYm9sKSAKCnBsdF9saXN0ID0gbGlzdCgpCmZvciAoaSBpbiAxOm5jb2woZ2VwX3Njb3JlcykpIHsKICB0b3BfZ2VuZXMgPSBnZXBfc2NvcmVzICAlPiUgIGFycmFuZ2UoZGVzYyhnZXBfc2NvcmVzW2ldKSkgI3NvcnQgYnkgc2NvcmUgYQogIHRvcCA9IGhlYWQocm93bmFtZXModG9wX2dlbmVzKSwyMDApICN0YWtlIHRvcCB0b3BfZ2VuZXNfbnVtCiAgcmVzID0gZ2VuZXNfdmVjX2VucmljaG1lbnQoZ2VuZXMgPSB0b3AsYmFja2dyb3VuZCA9IHJvd25hbWVzKGdlcF9zY29yZXMpLGhvbWVyID0gVCx0aXRsZSA9IAogICAgICAgICAgICAgICAgICAgIGksc2lsZW50ID0gVCxyZXR1cm5fYWxsID0gVCxjdXN0b21fcGF0aHdheXMgPSBjYW5vbmljYWxfcGF0aHdheXMpCiAgIAogIHBsdF9saXN0W1tpXV0gPSByZXMkcGx0Cn0KcCA9IGdnYXJyYW5nZShwbG90bGlzdCAgPSBwbHRfbGlzdCkKcHJpbnRfdGFiKHBsdCA9IHAsdGl0bGUgPSAiY2Fub25pY2FsIHBhdGh3YXkgZW5yaWNobWVudCIpCgoKCmBgYAojIyBsdW1pbmFsIGFuZCBteW8gZ2VuZXMgaW4gc2NvcmUKYGBge3IgcmVzdWx0cz0naG9sZCcsY29sbGFwc2U9VFJVRX0KIyBsdW0gZ2VuZXMgaW4gbWV0YWdlbmVzCm1lc3NhZ2UoImx1bSBnZW5lcyBpbiBtZXRhZ2VuZXM6IikKZm9yIChpIGluIDE6bmNvbChnZXBfc2NvcmVzKSkgewogIHRvcF9nZW5lcyA9IGdlcF9zY29yZXMgICU+JSAgYXJyYW5nZShkZXNjKGdlcF9zY29yZXNbaV0pKSAjc29ydCBieSBzY29yZSBhCiAgdG9wID0gaGVhZChyb3duYW1lcyh0b3BfZ2VuZXMpLDIwMCkgI3Rha2UgdG9wIHRvcF9nZW5lc19udW0KICBjYXQocGFzdGUwKCJtZXRhZ2VuZSAiLGksIjogIikpCiAgcHJpbnQob3JpZ2luYWxfbHVtX2dlbmVzW29yaWdpbmFsX2x1bV9nZW5lcyAlaW4lIHRvcF0pCgp9CmNhdCgiXG4iKQoKCiMgbXlvIGdlbmVzIGluIG1ldGFnZW5lcwptZXNzYWdlKCJteW8gZ2VuZXMgaW4gbWV0YWdlbmVzOiIpCmZvciAoaSBpbiAxOm5jb2woZ2VwX3Njb3JlcykpIHsKICB0b3BfZ2VuZXMgPSBnZXBfc2NvcmVzICAlPiUgIGFycmFuZ2UoZGVzYyhnZXBfc2NvcmVzW2ldKSkgI3NvcnQgYnkgc2NvcmUgYQogIHRvcCA9IGhlYWQocm93bmFtZXModG9wX2dlbmVzKSwyMDApICN0YWtlIHRvcCB0b3BfZ2VuZXNfbnVtCiAgY2F0KHBhc3RlMCgibWV0YWdlbmUgIixpLCI6ICIpKQogIHByaW50KG9yaWdpbmFsX215b19nZW5lc1tvcmlnaW5hbF9teW9fZ2VuZXMgJWluJSB0b3BdKQoKfQpjYXQoIlxuIikKCm5vdGNoX2dlbmVzID0gYygiSkFHMSIsIkpBRzIiLCJOT1RDSDMiLCJOT1RDSDIiLCJOT1RDSDEiLCJETEwxIiwiTVlCIiwiSEVTNCIsIkhFWTEiLCJIRVkyIiwiTlJBUlAiKQojIG5vdGNoIGdlbmVzIGluIG1ldGFnZW5lcwptZXNzYWdlKCJub3RjaCBnZW5lcyBpbiBtZXRhZ2VuZXM6IikKZm9yIChpIGluIDE6bmNvbChnZXBfc2NvcmVzKSkgewogIHRvcF9nZW5lcyA9IGdlcF9zY29yZXMgICU+JSAgYXJyYW5nZShkZXNjKGdlcF9zY29yZXNbaV0pKSAjc29ydCBieSBzY29yZSBhCiAgdG9wID0gaGVhZChyb3duYW1lcyh0b3BfZ2VuZXMpLDIwMCkgI3Rha2UgdG9wIHRvcF9nZW5lc19udW0KICBjYXQocGFzdGUwKCJtZXRhZ2VuZSAiLGksIjogIikpCiAgcHJpbnQobm90Y2hfZ2VuZXNbbm90Y2hfZ2VuZXMgJWluJSB0b3BdKQoKfQpjYXQoIlxuIikKYGBgCgoKCiMgTWV0YWdlbmVzIG9uIEFDQyAgey50YWJzZXR9CgpgYGB7ciBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTAsIHJlc3VsdHM9J2FzaXMnfQojIE1ha2UgbWV0YWdlbmUgbmFtZXMKZm9yIChpIGluIDE6bmNvbChhbGxfbWV0YWdlbmVzKSkgewogIGNvbG5hbWVzKGFsbF9tZXRhZ2VuZXMpW2ldID0gIm1ldGFnZW5lLiIgJT4lIHBhc3RlMChpKQp9CgoKI2FkZCBlYWNoIG1ldGFnZW5lIHRvIG1ldGFkYXRhCmZvciAoaSBpbiAxOm5jb2woYWxsX21ldGFnZW5lcykpIHsKICBtZXRhZ2VfbWV0YWRhdGEgPSBhbGxfbWV0YWdlbmVzICU+JSBzZWxlY3QoaSkKICBhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxID0gQWRkTWV0YURhdGEob2JqZWN0ID0gYWNjX2NhbmNlckNlbGxzX25vQUNDMSxtZXRhZGF0YSA9IG1ldGFnZV9tZXRhZGF0YSkKfQoKcHJpbnRfdGFiKHBsdCA9IAogICAgICAgICAgICBGZWF0dXJlUGxvdChvYmplY3QgPSBhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxLGZlYXR1cmVzID0gY29sbmFtZXMoYWxsX21ldGFnZW5lcyksbWF4LmN1dG9mZiA9IDEwMCkKICAgICAgICAgICx0aXRsZSA9ICJtZXRhZ2VuZXMgZXhwcmVzc2lvbiIpCgphbGxfbWV0YWdlbmVzPSBzY2FsZShhbGxfbWV0YWdlbmVzKSAlPiUgYXMuZGF0YS5mcmFtZSgpCmZvciAoaSBpbiAxOm5jb2woYWxsX21ldGFnZW5lcykpIHsKICBjb2xuYW1lcyhhbGxfbWV0YWdlbmVzKVtpXSA9ICJtZXRhZ2VuZS4iICU+JSBwYXN0ZTAoaSkKfQoKCiNhZGQgZWFjaCBtZXRhZ2VuZSB0byBtZXRhZGF0YQpmb3IgKGkgaW4gMTpuY29sKGFsbF9tZXRhZ2VuZXMpKSB7CiAgbWV0YWdlX21ldGFkYXRhID0gYWxsX21ldGFnZW5lcyAlPiUgc2VsZWN0KGkpCiAgYWNjX2NhbmNlckNlbGxzX25vQUNDMSA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IGFjY19jYW5jZXJDZWxsc19ub0FDQzEsbWV0YWRhdGEgPSBtZXRhZ2VfbWV0YWRhdGEpCn0KCnByaW50X3RhYihwbHQgPSAKICAgICAgICAgICAgRmVhdHVyZVBsb3Qob2JqZWN0ID0gYWNjX2NhbmNlckNlbGxzX25vQUNDMSxmZWF0dXJlcyA9IGNvbG5hbWVzKGFsbF9tZXRhZ2VuZXMpLG1heC5jdXRvZmYgPSAxMDApCiAgICAgICAgICAsdGl0bGUgPSAibWV0YWdlbmVzIHotc2NvcmUgZXhwcmVzc2lvbiIpCgpgYGAKCiMgQXNzaWduIHRvIHByb2dyYW1zIGJ5IHotc2NvcmVkIG1ldGFnZW5lcwpgYGB7cn0KYWNjX2NhbmNlckNlbGxzX25vQUNDMSA9IHByb2dyYW1fYXNzaWdubWVudChkYXRhc2V0ID0gYWNjX2NhbmNlckNlbGxzX25vQUNDMSxsYXJnZXJfYnkgPSAyLHByb2dyYW1fbmFtZXMgPSBjb2xuYW1lcyhhbGxfbWV0YWdlbmVzKSkKYGBgCgoKCiMgVU1BUFMgey50YWJzZXR9CgpgYGB7ciBlY2hvPVRSVUUsIHJlc3VsdHM9J2FzaXMnfQpjb2xvcnMgPSAgcmFpbmJvdyhhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxJHByb2dyYW0uYXNzaWdubWVudCAlPiUgdW5pcXVlKCkgJT4lIGxlbmd0aCgpLTEpCmNvbG9ycyA9IGMoY29sb3JzLCJncmV5IikKcHJpbnRfdGFiKHBsdCA9IERpbVBsb3Qob2JqZWN0ID0gYWNjX2NhbmNlckNlbGxzX25vQUNDMSxncm91cC5ieSA9ICJwcm9ncmFtLmFzc2lnbm1lbnQiLGNvbHMgPWNvbG9ycyksdGl0bGUgPSAicHJvZ3JhbS5hc3NpZ25tZW50IikKcHJpbnRfdGFiKHBsdCA9IERpbVBsb3Qob2JqZWN0ID0gYWNjX2NhbmNlckNlbGxzX25vQUNDMSxncm91cC5ieSA9ICJwYXRpZW50LmlkZW50IiksdGl0bGUgPSAicGF0aWVudC5pZGVudCIpCgpwcmludF90YWIocGx0ID0gRmVhdHVyZVBsb3Qob2JqZWN0ID0gYWNjX2NhbmNlckNlbGxzX25vQUNDMSxmZWF0dXJlcyA9ICJsdW1fc2NvcmUiKSx0aXRsZSA9ICJsdW1fc2NvcmUiKQoKcHJpbnRfdGFiKHBsdCA9IEZlYXR1cmVQbG90KG9iamVjdCA9IGFjY19jYW5jZXJDZWxsc19ub0FDQzEsZmVhdHVyZXMgPSAibXlvX3Njb3JlIiksdGl0bGUgPSAibXlvX3Njb3JlIikKCgoKYGBgCiMgbWV0YWdlbmVzIGJ5IGx1bV9vdmVyX215bwpgYGB7cn0KYWNjX2NhbmNlckNlbGxzX25vQUNDMSA9IHN1YnNldChhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxLHN1YnNldCA9IHBhdGllbnQuaWRlbnQhPSAiQUNDMSIpCgpsdW1TY29yZV92c19wcm9ncmFtID0gRmV0Y2hEYXRhKG9iamVjdCA9IGFjY19jYW5jZXJDZWxsc19ub0FDQzEsdmFycyA9IGMoImx1bV9vdmVyX215byIsInByb2dyYW0uYXNzaWdubWVudCIpKQpsdW1TY29yZV92c19wcm9ncmFtJHByb2dyYW0uYXNzaWdubWVudCA8LSBmYWN0b3IobHVtU2NvcmVfdnNfcHJvZ3JhbSRwcm9ncmFtLmFzc2lnbm1lbnQsIGxldmVscyA9IGMoIm1ldGFnZW5lLjEiLCJtZXRhZ2VuZS4yIiwibWV0YWdlbmUuNCIpKQoKbHVtU2NvcmVfdnNfcHJvZ3JhbSA9IGx1bVNjb3JlX3ZzX3Byb2dyYW0gJT4lIGRwbHlyOjpmaWx0ZXIocHJvZ3JhbS5hc3NpZ25tZW50ICVpbiUgYygibWV0YWdlbmUuMSIsIm1ldGFnZW5lLjIiLCJtZXRhZ2VuZS40IikpCmdnYm94cGxvdChsdW1TY29yZV92c19wcm9ncmFtLCB4ID0gInByb2dyYW0uYXNzaWdubWVudCIsIHkgPSAibHVtX292ZXJfbXlvIiwKICAgICAgICAgIHBhbGV0dGUgPSAiamNvIiwKICAgICAgICAgIGFkZCA9ICJqaXR0ZXIiKSsgc3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ3aWxjb3gudGVzdCIsY29tcGFyaXNvbnMgPSBsaXN0KGMoIm1ldGFnZW5lLjEiLCJtZXRhZ2VuZS4yIiksYygibWV0YWdlbmUuMiIsIm1ldGFnZW5lLjQiKSkpCmBgYAojIE1ldGFnZW5lcyBjb3JyZWxhdGlvbiB3aXRoIG15byBzY29yZSB7LnRhYnNldH0KCgoKYGBge3IgZWNobz1UUlVFLCByZXN1bHRzPSdhc2lzJ30KZm9yIChtZXRhZ2VuZSBpbiBjKCJtZXRhZ2VuZS4xIiwibWV0YWdlbmUuMiIsIm1ldGFnZW5lLjQiKSkgewogICBsdW1fc2NvcmVfdnNfcHJvZ3JhbVNjb3JlID0gRmV0Y2hEYXRhKG9iamVjdCA9IGFjY19jYW5jZXJDZWxsc19ub0FDQzEsdmFycyA9IGMobWV0YWdlbmUsIm15b19zY29yZSIpKQogIHByaW50X3RhYihwbHQgPSAKICAgIGdnc2NhdHRlcihsdW1fc2NvcmVfdnNfcHJvZ3JhbVNjb3JlLCB4ID0gbWV0YWdlbmUsIHkgPSAibXlvX3Njb3JlIiwgCiAgICAgICAgICAgIGFkZCA9ICJyZWcubGluZSIsIGNvbmYuaW50ID0gVFJVRSwgCiAgICAgICAgICAgIGNvci5jb2VmID0gVFJVRSwgY29yLm1ldGhvZCA9ICJwZWFyc29uIikKICAsdGl0bGUgPSBtZXRhZ2VuZSkKfQogCmBgYAoKCiMgTWV0YWdlbmVzIGNvcnJlbGF0aW9uIHdpdGggbHVtIHNjb3JlIHsudGFic2V0fQpgYGB7ciBlY2hvPVRSVUUsIHJlc3VsdHM9J2FzaXMnfQpmb3IgKG1ldGFnZW5lIGluIGMoIm1ldGFnZW5lLjEiLCJtZXRhZ2VuZS4yIiwibWV0YWdlbmUuNCIpKSB7CiAgIGx1bV9zY29yZV92c19wcm9ncmFtU2NvcmUgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjX2NhbmNlckNlbGxzX25vQUNDMSx2YXJzID0gYyhtZXRhZ2VuZSwibHVtX3Njb3JlIikpCiAgcHJpbnRfdGFiKHBsdCA9IAogICAgZ2dzY2F0dGVyKGx1bV9zY29yZV92c19wcm9ncmFtU2NvcmUsIHggPSBtZXRhZ2VuZSwgeSA9ICJsdW1fc2NvcmUiLCAKICAgICAgICAgICAgYWRkID0gInJlZy5saW5lIiwgY29uZi5pbnQgPSBUUlVFLCAKICAgICAgICAgICAgY29yLmNvZWYgPSBUUlVFLCBjb3IubWV0aG9kID0gInBlYXJzb24iKQogICx0aXRsZSA9IG1ldGFnZW5lKQp9CiAKYGBgCgoKCiMgTm90Y2ggc2NvcmUgey50YWJzZXR9CmBgYHtyIGVjaG89VFJVRSwgcmVzdWx0cz0nYXNpcyd9CmZvciAobWV0YWdlbmUgaW4gYygibWV0YWdlbmUuMSIsIm1ldGFnZW5lLjIiLCJtZXRhZ2VuZS40IikpIHsKICAgbHVtX3Njb3JlX3ZzX3Byb2dyYW1TY29yZSA9IEZldGNoRGF0YShvYmplY3QgPSBhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxLHZhcnMgPSBjKG1ldGFnZW5lLCJub3RjaF9zY29yZSIpKQogIHByaW50X3RhYihwbHQgPSAKICAgIGdnc2NhdHRlcihsdW1fc2NvcmVfdnNfcHJvZ3JhbVNjb3JlLCB4ID0gbWV0YWdlbmUsIHkgPSAibm90Y2hfc2NvcmUiLCAKICAgICAgICAgICAgYWRkID0gInJlZy5saW5lIiwgY29uZi5pbnQgPSBUUlVFLCAKICAgICAgICAgICAgY29yLmNvZWYgPSBUUlVFLCBjb3IubWV0aG9kID0gInBlYXJzb24iKQogICx0aXRsZSA9IG1ldGFnZW5lKQp9CiAKYGBgCgoKCiMgTm90Y2ggIGxpZ2FuZHMgc2NvcmUgey50YWJzZXR9CmBgYHtyIGVjaG89VFJVRSwgcmVzdWx0cz0nYXNpcyd9CmZvciAobWV0YWdlbmUgaW4gYygibWV0YWdlbmUuMSIsIm1ldGFnZW5lLjIiLCJtZXRhZ2VuZS40IikpIHsKICAgbHVtX3Njb3JlX3ZzX3Byb2dyYW1TY29yZSA9IEZldGNoRGF0YShvYmplY3QgPSBhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxLHZhcnMgPSBjKG1ldGFnZW5lLCJub3RjaF9saWdhbmRzX3Njb3JlX3Njb3JlIikpCiAgcHJpbnRfdGFiKHBsdCA9IAogICAgZ2dzY2F0dGVyKGx1bV9zY29yZV92c19wcm9ncmFtU2NvcmUsIHggPSBtZXRhZ2VuZSwgeSA9ICJub3RjaF9saWdhbmRzX3Njb3JlX3Njb3JlIiwgCiAgICAgICAgICAgIGFkZCA9ICJyZWcubGluZSIsIGNvbmYuaW50ID0gVFJVRSwgCiAgICAgICAgICAgIGNvci5jb2VmID0gVFJVRSwgY29yLm1ldGhvZCA9ICJwZWFyc29uIikKICAsdGl0bGUgPSBtZXRhZ2VuZSkKfQogCmBgYAoKCgoK