1 Data

lung = readRDS("./Data/lung_cancercells_withTP_onlyPatients.rds")
lung_patients = lung$patient.ident %>% unique() %>% as.character()
lung_patients_filtered = lung_patients[!(lung_patients %in% c("X1055new","X1099"))] # remove patients with less than 100 malignant cells
lung = subset(x = lung,subset = patient.ident %in% lung_patients_filtered)
suffix ="xeno_genes_0-5sigma_2-7theta_100iter_26_9"
from cnmf import cNMF
suffix = r.suffix
import pickle
f = open('./Data/cnmf/cnmf_objects/patients_' + suffix + '_cnmf_obj.pckl', 'rb')
cnmf_obj = pickle.load(f)
f.close()

2 Functions

library(stringi)
library(reticulate)
source_from_github(repositoy = "DEG_functions",version = "0.2.47")
source_from_github(repositoy = "cNMF_functions",version = "0.4.02",script_name = "cnmf_functions_V3.R")
source_from_github(repositoy = "sc_general_functions",version = "0.1.28",script_name = "functions.R")
genesets <- msigdb_download("Homo sapiens",category="H") %>% append( msigdb_download("Homo sapiens",category="C2",subcategory = "CP"))
genesets[["HIF_targets"]] = hif_targets

genesets_go <- msigdb_gsets("Homo sapiens", "C5", "GO:BP", clean=TRUE)

3 K selection plot

plot_path = paste0("/sci/labs/yotamd/lab_share/avishai.wizel/R_projects/EGFR/Data/cnmf/cNMF_patients_Varnorm_Harmony_",suffix,"/cNMF_patients_Varnorm_Harmony_",suffix,".k_selection.png")
knitr::include_graphics(plot_path)
cnmf_obj.consensus(k=3, density_threshold=0.1,show_clustering=True)
cnmf_obj.consensus(k=6, density_threshold=0.1,show_clustering=True)
cnmf_obj.consensus(k=7, density_threshold=0.1,show_clustering=True)
cnmf_obj.consensus(k=8, density_threshold=0.1,show_clustering=True)

4 gep scores for all NMF k’s

density_threshold = 0.1
usage_norm3, gep_scores3, gep_tpm3, topgenes = cnmf_obj.load_results(K=3, density_threshold=density_threshold)
usage_norm6, gep_scores6, gep_tpm6, topgenes = cnmf_obj.load_results(K=6, density_threshold=density_threshold)
usage_norm7, gep_scores7, gep_tpm7, topgenes = cnmf_obj.load_results(K=7, density_threshold=density_threshold)
usage_norm8, gep_scores8, gep_tpm8, topgenes = cnmf_obj.load_results(K=8, density_threshold=density_threshold)

5 gsea of each program

gep_scores3 = py$gep_scores3
gep_scores6 = py$gep_scores6
gep_scores7 = py$gep_scores7
gep_scores8 = py$gep_scores8

gep_tpm8 = py$gep_tpm8
top_genes = py$topgenes
  for (col in seq_along(gep_scores8)) {
     ranked_vec = gep_scores8[,col] %>% setNames(rownames(gep_scores8)) %>% sort(decreasing = TRUE) 
     hyp_obj <- hypeR_fgsea(ranked_vec, genesets,up_only = T)
     print_tab(hyp_dots(hyp_obj,title = paste("program",col))+ aes(size=nes),title = paste0("gep",col))
  }

gep1

gep2

gep3

gep4

Warning in fgsea::fgseaMultilevel(stats = signature, pathways = gsets.obj$genesets, : There were 2 pathways for which P-values were not calculated properly due to unbalanced (positive and negative) gene-level statistic values. For such pathways pval, padj, NES, log2err are set to NA. You can try to increase the value of the argument nPermSimple (for example set it nPermSimple = 10000) ## gep5 {.unnumbered }

Warning in fgsea::fgseaMultilevel(stats = signature, pathways = gsets.obj$genesets, : There were 1 pathways for which P-values were not calculated properly due to unbalanced (positive and negative) gene-level statistic values. For such pathways pval, padj, NES, log2err are set to NA. You can try to increase the value of the argument nPermSimple (for example set it nPermSimple = 10000) ## gep6 {.unnumbered }

gep7

gep8

NA

programs_main_pathways = list(gep1 = 1:2, gep2 = 1:3,gep3 = 1:4)

6 Calculate usage by counts before Harmony

# get expression with genes in cnmf input
genes = rownames(gep_scores8)
lung_expression = t(as.matrix(GetAssayData(lung,slot='data'))) 
lung_expression = 2**lung_expression #convert from log2(tpm+1) to tpm
lung_expression = lung_expression-1
lung_expression = lung_expression[,genes] %>% as.data.frame()

all_0_genes = colnames(lung_expression)[colSums(lung_expression==0, na.rm=TRUE)==nrow(lung_expression)] #delete rows that have all 0
genes = genes[!genes %in% all_0_genes]
lung_expression = lung_expression[,!colnames(lung_expression) %in% all_0_genes]
gc(verbose = F)

lung_expression = r.lung_expression
genes = r.genes
usage_by_calc = get_usage_from_score(counts=lung_expression,tpm=lung_expression,genes=genes,cnmf_obj=cnmf_obj,k=8,sumTo1=True)
usage_by_calc = py$usage_by_calc
colnames(usage_by_calc) = c("autoimmune","TNFa.NFkB", "hypoxia","unknown2", "cell_cycle1", "cell_cycle2","INFg","unknown")
# colnames(usage_by_calc) = paste0("gep",1:8)
#add each metagene to metadata
for (i  in 1:ncol(usage_by_calc )) {
  metagene_metadata = usage_by_calc [,i,drop=F]
  lung = AddMetaData(object = lung,metadata = metagene_metadata,col.name = colnames(usage_by_calc)[i])
}

FeaturePlot(object = lung,features = colnames(usage_by_calc),ncol = 3)

7 Regulation

metagenes_mean_compare(dataset = lung,time.point_var = "time.point",prefix = "patient",patient.ident_var = "patient.ident",pre_on = c("pre-treatment","on-treatment"),test = "wilcox.test",programs = colnames(usage_by_calc)[1:5],without_split = F)

autoimmune per patient

TNFa.NFkB per patient

hypoxia per patient

hypoxia2 per patient

cell_cycle1 per patient

NA

8 Program 2

col=1
ranked_vec = gep_scores8[, col] %>% setNames(rownames(gep_scores8)) %>% sort(decreasing = TRUE)
print (paste("running gep",col))
hyp_obj <-hypeR_fgsea(ranked_vec, genesets_go, up_only = T)

print(hyp_dots(hyp_obj, title = paste("program", col), abrv = 70) + aes(size =nes))
  

pathway_num = 1
le_genes = hyp_obj$as.data.frame()[pathway_num,"le"] %>% strsplit(",") %>% unlist()
score = (lung_expression[, le_genes] %>% as.matrix())  %*% as.matrix(gep_scores8[le_genes, 2, drop =F])

# score = FetchData(object = lung,vars = le_genes) %>% rowMeans()
pathway_name = paste0(hyp_obj$data[pathway_num, "label", drop = F], "_le") %>% gsub(pattern = " ",replacement = "_")
lung = AddMetaData(lung, score, col.name = pathway_name)
print_tab(FeaturePlot(object = lung,features = pathway_name),title = pathway_name)
##   Positive_Regulation_Of_Transcription_By_Rna_Polymerase_Ii_le {.unnumbered }  

NA
cor(score,usage_by_calc[,2])
       [,1]
2 0.5433146
metagenes_mean_compare(dataset = lung,time.point_var = "time.point",prefix = "patient",patient.ident_var = "patient.ident",pre_on = c("pre-treatmen
                                                                                                                                      t","on-treatment"),test = "wilcox.test",programs = pathway_name,without_split = F)

Positive_Regulation_Of_Transcription_By_Rna_Polymerase_Ii_le per patient

NA

9 programs LE genes


programs_main_pathways_names = list()
  for (col in seq_along(gep_scores8)[1:3]) {
     ranked_vec = gep_scores8[,col] %>% setNames(rownames(gep_scores8)) %>% sort(decreasing = TRUE) 
     hyp_obj <- hypeR_fgsea(ranked_vec, genesets)
     programs_main_pathways_names[[col]] =  hyp_obj$data[programs_main_pathways[[col]],"label",drop=T]
     for (pathway_num in programs_main_pathways[[col]]) {
        le_genes =  hyp_obj$data[pathway_num,,drop=F] %>% pull("le") %>% strsplit(",") %>% unlist()
        # score = (lung_expression[,le_genes] %>% as.matrix())  %*% as.matrix(gep_scores8[le_genes,col,drop=F])
        # score = score %>% as.vector()
        score = FetchData(object = lung,vars = le_genes) %>% rowMeans()
        pathway_name = paste0(hyp_obj$data[pathway_num,"label",drop=F],"_le")
        lung=AddMetaData(lung,score,col.name = pathway_name)
        cor_res = cor(score,usage_by_calc[,col])
        print_tab(FeaturePlot(object = lung,features = pathway_name)+ggtitle(pathway_name, subtitle = paste("cor to usage:",cor_res)),title = pathway_name)
     }
  }

HALLMARK_INTERFERON_GAMMA_RESPONSE_le

HALLMARK_INTERFERON_ALPHA_RESPONSE_le

SA_FAS_SIGNALING_le

HALLMARK_TNFA_SIGNALING_VIA_NFKB_le

HALLMARK_P53_PATHWAY_le

HALLMARK_HYPOXIA_le

HALLMARK_GLYCOLYSIS_le

HALLMARK_EPITHELIAL_MESENCHYMAL_TRANSITION_le

HIF_targets_le

NA

10 programs LE genes

metagenes_mean_compare(dataset = lung,time.point_var = "time.point",prefix = "patient",patient.ident_var = "patient.ident",pre_on = c("pre-treatment","on-treatment"),test = "wilcox.test",programs = programs_main_pathways_names %>% unlist() %>% paste0("_le") ,without_split = F)

HALLMARK_INTERFERON_GAMMA_RESPONSE_le per patient

HALLMARK_INTERFERON_ALPHA_RESPONSE_le per patient

SA_FAS_SIGNALING_le per patient

HALLMARK_TNFA_SIGNALING_VIA_NFKB_le per patient

HALLMARK_P53_PATHWAY_le per patient

HALLMARK_HYPOXIA_le per patient

HALLMARK_GLYCOLYSIS_le per patient

HALLMARK_EPITHELIAL_MESENCHYMAL_TRANSITION_le per patient

HIF_targets_le per patient

NA

LS0tCnRpdGxlOiAnYHIgcnN0dWRpb2FwaTo6Z2V0U291cmNlRWRpdG9yQ29udGV4dCgpJHBhdGggJT4lIGJhc2VuYW1lKCkgJT4lIGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLHJlcGxhY2VtZW50ID0gIiIpYCcgCmF1dGhvcjogIkF2aXNoYWkgV2l6ZWwiCmRhdGU6ICdgciBTeXMudGltZSgpYCcKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdG9jOiB5ZXMKICAgIHRvY19jb2xsYXBzZTogeWVzCiAgICB0b2NfZmxvYXQ6IAogICAgICBjb2xsYXBzZWQ6IEZBTFNFCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvY19kZXB0aDogMQotLS0KCgojIERhdGEKCmBgYHtyfQpsdW5nID0gcmVhZFJEUygiLi9EYXRhL2x1bmdfY2FuY2VyY2VsbHNfd2l0aFRQX29ubHlQYXRpZW50cy5yZHMiKQpsdW5nX3BhdGllbnRzID0gbHVuZyRwYXRpZW50LmlkZW50ICU+JSB1bmlxdWUoKSAlPiUgYXMuY2hhcmFjdGVyKCkKbHVuZ19wYXRpZW50c19maWx0ZXJlZCA9IGx1bmdfcGF0aWVudHNbIShsdW5nX3BhdGllbnRzICVpbiUgYygiWDEwNTVuZXciLCJYMTA5OSIpKV0gIyByZW1vdmUgcGF0aWVudHMgd2l0aCBsZXNzIHRoYW4gMTAwIG1hbGlnbmFudCBjZWxscwpsdW5nID0gc3Vic2V0KHggPSBsdW5nLHN1YnNldCA9IHBhdGllbnQuaWRlbnQgJWluJSBsdW5nX3BhdGllbnRzX2ZpbHRlcmVkKQpgYGAKCgpgYGB7cn0Kc3VmZml4ID0ieGVub19nZW5lc18wLTVzaWdtYV8yLTd0aGV0YV8xMDBpdGVyXzI2XzkiCmBgYAoKCmBgYHtweXRob259CmZyb20gY25tZiBpbXBvcnQgY05NRgpzdWZmaXggPSByLnN1ZmZpeAppbXBvcnQgcGlja2xlCmYgPSBvcGVuKCcuL0RhdGEvY25tZi9jbm1mX29iamVjdHMvcGF0aWVudHNfJyArIHN1ZmZpeCArICdfY25tZl9vYmoucGNrbCcsICdyYicpCmNubWZfb2JqID0gcGlja2xlLmxvYWQoZikKZi5jbG9zZSgpCmBgYAoKCgojIEZ1bmN0aW9ucwoKYGBge3J9CmxpYnJhcnkoc3RyaW5naSkKbGlicmFyeShyZXRpY3VsYXRlKQpzb3VyY2VfZnJvbV9naXRodWIocmVwb3NpdG95ID0gIkRFR19mdW5jdGlvbnMiLHZlcnNpb24gPSAiMC4yLjQ3IikKc291cmNlX2Zyb21fZ2l0aHViKHJlcG9zaXRveSA9ICJjTk1GX2Z1bmN0aW9ucyIsdmVyc2lvbiA9ICIwLjQuMDIiLHNjcmlwdF9uYW1lID0gImNubWZfZnVuY3Rpb25zX1YzLlIiKQpzb3VyY2VfZnJvbV9naXRodWIocmVwb3NpdG95ID0gInNjX2dlbmVyYWxfZnVuY3Rpb25zIix2ZXJzaW9uID0gIjAuMS4yOCIsc2NyaXB0X25hbWUgPSAiZnVuY3Rpb25zLlIiKQpgYGAKCmBgYHtyfQpnZW5lc2V0cyA8LSBtc2lnZGJfZG93bmxvYWQoIkhvbW8gc2FwaWVucyIsY2F0ZWdvcnk9IkgiKSAlPiUgYXBwZW5kKCBtc2lnZGJfZG93bmxvYWQoIkhvbW8gc2FwaWVucyIsY2F0ZWdvcnk9IkMyIixzdWJjYXRlZ29yeSA9ICJDUCIpKQpnZW5lc2V0c1tbIkhJRl90YXJnZXRzIl1dID0gaGlmX3RhcmdldHMKCmdlbmVzZXRzX2dvIDwtIG1zaWdkYl9nc2V0cygiSG9tbyBzYXBpZW5zIiwgIkM1IiwgIkdPOkJQIiwgY2xlYW49VFJVRSkKCmBgYAoKIyBLIHNlbGVjdGlvbiBwbG90CmBgYHtyIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTR9CnBsb3RfcGF0aCA9IHBhc3RlMCgiL3NjaS9sYWJzL3lvdGFtZC9sYWJfc2hhcmUvYXZpc2hhaS53aXplbC9SX3Byb2plY3RzL0VHRlIvRGF0YS9jbm1mL2NOTUZfcGF0aWVudHNfVmFybm9ybV9IYXJtb255XyIsc3VmZml4LCIvY05NRl9wYXRpZW50c19WYXJub3JtX0hhcm1vbnlfIixzdWZmaXgsIi5rX3NlbGVjdGlvbi5wbmciKQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhwbG90X3BhdGgpCmBgYAoKCmBgYHtweXRob259CmNubWZfb2JqLmNvbnNlbnN1cyhrPTMsIGRlbnNpdHlfdGhyZXNob2xkPTAuMSxzaG93X2NsdXN0ZXJpbmc9VHJ1ZSkKY25tZl9vYmouY29uc2Vuc3VzKGs9NiwgZGVuc2l0eV90aHJlc2hvbGQ9MC4xLHNob3dfY2x1c3RlcmluZz1UcnVlKQpjbm1mX29iai5jb25zZW5zdXMoaz03LCBkZW5zaXR5X3RocmVzaG9sZD0wLjEsc2hvd19jbHVzdGVyaW5nPVRydWUpCmNubWZfb2JqLmNvbnNlbnN1cyhrPTgsIGRlbnNpdHlfdGhyZXNob2xkPTAuMSxzaG93X2NsdXN0ZXJpbmc9VHJ1ZSkKYGBgCgoKIyBnZXAgc2NvcmVzIGZvciBhbGwgTk1GIGsncwpgYGB7cHl0aG9ufQpkZW5zaXR5X3RocmVzaG9sZCA9IDAuMQp1c2FnZV9ub3JtMywgZ2VwX3Njb3JlczMsIGdlcF90cG0zLCB0b3BnZW5lcyA9IGNubWZfb2JqLmxvYWRfcmVzdWx0cyhLPTMsIGRlbnNpdHlfdGhyZXNob2xkPWRlbnNpdHlfdGhyZXNob2xkKQp1c2FnZV9ub3JtNiwgZ2VwX3Njb3JlczYsIGdlcF90cG02LCB0b3BnZW5lcyA9IGNubWZfb2JqLmxvYWRfcmVzdWx0cyhLPTYsIGRlbnNpdHlfdGhyZXNob2xkPWRlbnNpdHlfdGhyZXNob2xkKQp1c2FnZV9ub3JtNywgZ2VwX3Njb3JlczcsIGdlcF90cG03LCB0b3BnZW5lcyA9IGNubWZfb2JqLmxvYWRfcmVzdWx0cyhLPTcsIGRlbnNpdHlfdGhyZXNob2xkPWRlbnNpdHlfdGhyZXNob2xkKQp1c2FnZV9ub3JtOCwgZ2VwX3Njb3JlczgsIGdlcF90cG04LCB0b3BnZW5lcyA9IGNubWZfb2JqLmxvYWRfcmVzdWx0cyhLPTgsIGRlbnNpdHlfdGhyZXNob2xkPWRlbnNpdHlfdGhyZXNob2xkKQoKYGBgCgojIGdzZWEgb2YgZWFjaCBwcm9ncmFtIHsudGFic2V0fQpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04LCByZXN1bHRzPSdhc2lzJ30KZ2VwX3Njb3JlczMgPSBweSRnZXBfc2NvcmVzMwpnZXBfc2NvcmVzNiA9IHB5JGdlcF9zY29yZXM2CmdlcF9zY29yZXM3ID0gcHkkZ2VwX3Njb3JlczcKZ2VwX3Njb3JlczggPSBweSRnZXBfc2NvcmVzOAoKZ2VwX3RwbTggPSBweSRnZXBfdHBtOAp0b3BfZ2VuZXMgPSBweSR0b3BnZW5lcwpgYGAKCmBgYHtyIHJlc3VsdHM9J2FzaXMnfQogIGZvciAoY29sIGluIHNlcV9hbG9uZyhnZXBfc2NvcmVzOCkpIHsKICAgICByYW5rZWRfdmVjID0gZ2VwX3Njb3JlczhbLGNvbF0gJT4lIHNldE5hbWVzKHJvd25hbWVzKGdlcF9zY29yZXM4KSkgJT4lIHNvcnQoZGVjcmVhc2luZyA9IFRSVUUpIAogICAgIGh5cF9vYmogPC0gaHlwZVJfZmdzZWEocmFua2VkX3ZlYywgZ2VuZXNldHMsdXBfb25seSA9IFQpCiAgICAgcHJpbnRfdGFiKGh5cF9kb3RzKGh5cF9vYmosdGl0bGUgPSBwYXN0ZSgicHJvZ3JhbSIsY29sKSkrIGFlcyhzaXplPW5lcyksdGl0bGUgPSBwYXN0ZTAoImdlcCIsY29sKSkKICB9CmBgYAoKCgpgYGB7cn0KcHJvZ3JhbXNfbWFpbl9wYXRod2F5cyA9IGxpc3QoZ2VwMSA9IDE6MiwgZ2VwMiA9IDE6MyxnZXAzID0gMTo0KQpgYGAKCiMgQ2FsY3VsYXRlIHVzYWdlIGJ5IGNvdW50cyBiZWZvcmUgSGFybW9ueQpgYGB7ciBlY2hvPVRSVUUsIHJlc3VsdHM9J2FzaXMnfQojIGdldCBleHByZXNzaW9uIHdpdGggZ2VuZXMgaW4gY25tZiBpbnB1dApnZW5lcyA9IHJvd25hbWVzKGdlcF9zY29yZXM4KQpsdW5nX2V4cHJlc3Npb24gPSB0KGFzLm1hdHJpeChHZXRBc3NheURhdGEobHVuZyxzbG90PSdkYXRhJykpKSAKbHVuZ19leHByZXNzaW9uID0gMioqbHVuZ19leHByZXNzaW9uICNjb252ZXJ0IGZyb20gbG9nMih0cG0rMSkgdG8gdHBtCmx1bmdfZXhwcmVzc2lvbiA9IGx1bmdfZXhwcmVzc2lvbi0xCmx1bmdfZXhwcmVzc2lvbiA9IGx1bmdfZXhwcmVzc2lvblssZ2VuZXNdICU+JSBhcy5kYXRhLmZyYW1lKCkKCmFsbF8wX2dlbmVzID0gY29sbmFtZXMobHVuZ19leHByZXNzaW9uKVtjb2xTdW1zKGx1bmdfZXhwcmVzc2lvbj09MCwgbmEucm09VFJVRSk9PW5yb3cobHVuZ19leHByZXNzaW9uKV0gI2RlbGV0ZSByb3dzIHRoYXQgaGF2ZSBhbGwgMApnZW5lcyA9IGdlbmVzWyFnZW5lcyAlaW4lIGFsbF8wX2dlbmVzXQpsdW5nX2V4cHJlc3Npb24gPSBsdW5nX2V4cHJlc3Npb25bLCFjb2xuYW1lcyhsdW5nX2V4cHJlc3Npb24pICVpbiUgYWxsXzBfZ2VuZXNdCmdjKHZlcmJvc2UgPSBGKQpgYGAKCgpgYGB7cHl0aG9ufQoKbHVuZ19leHByZXNzaW9uID0gci5sdW5nX2V4cHJlc3Npb24KZ2VuZXMgPSByLmdlbmVzCnVzYWdlX2J5X2NhbGMgPSBnZXRfdXNhZ2VfZnJvbV9zY29yZShjb3VudHM9bHVuZ19leHByZXNzaW9uLHRwbT1sdW5nX2V4cHJlc3Npb24sZ2VuZXM9Z2VuZXMsY25tZl9vYmo9Y25tZl9vYmosaz04LHN1bVRvMT1UcnVlKQoKYGBgCgpgYGB7cn0KdXNhZ2VfYnlfY2FsYyA9IHB5JHVzYWdlX2J5X2NhbGMKYGBgCgpgYGB7cn0KY29sbmFtZXModXNhZ2VfYnlfY2FsYykgPSBjKCJhdXRvaW1tdW5lIiwiVE5GYS5ORmtCIiwgImh5cG94aWEiLCJ1bmtub3duMiIsICJjZWxsX2N5Y2xlMSIsICJjZWxsX2N5Y2xlMiIsIklORmciLCJ1bmtub3duIikKYGBgCgoKYGBge3IgZWNobz1UUlVFLCBmaWcuaGVpZ2h0PTksIGZpZy53aWR0aD0xMiwgcmVzdWx0cz0nYXNpcyd9CiMgY29sbmFtZXModXNhZ2VfYnlfY2FsYykgPSBwYXN0ZTAoImdlcCIsMTo4KQojYWRkIGVhY2ggbWV0YWdlbmUgdG8gbWV0YWRhdGEKZm9yIChpICBpbiAxOm5jb2wodXNhZ2VfYnlfY2FsYyApKSB7CiAgbWV0YWdlbmVfbWV0YWRhdGEgPSB1c2FnZV9ieV9jYWxjIFssaSxkcm9wPUZdCiAgbHVuZyA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IGx1bmcsbWV0YWRhdGEgPSBtZXRhZ2VuZV9tZXRhZGF0YSxjb2wubmFtZSA9IGNvbG5hbWVzKHVzYWdlX2J5X2NhbGMpW2ldKQp9CgpGZWF0dXJlUGxvdChvYmplY3QgPSBsdW5nLGZlYXR1cmVzID0gY29sbmFtZXModXNhZ2VfYnlfY2FsYyksbmNvbCA9IDMpCgpgYGAKIyBSZWd1bGF0aW9uIHsudGFic2V0fQoKYGBge3IgcmVzdWx0cz0nYXNpcyd9Cm1ldGFnZW5lc19tZWFuX2NvbXBhcmUoZGF0YXNldCA9IGx1bmcsdGltZS5wb2ludF92YXIgPSAidGltZS5wb2ludCIscHJlZml4ID0gInBhdGllbnQiLHBhdGllbnQuaWRlbnRfdmFyID0gInBhdGllbnQuaWRlbnQiLHByZV9vbiA9IGMoInByZS10cmVhdG1lbnQiLCJvbi10cmVhdG1lbnQiKSx0ZXN0ID0gIndpbGNveC50ZXN0Iixwcm9ncmFtcyA9IGNvbG5hbWVzKHVzYWdlX2J5X2NhbGMpWzE6NV0sd2l0aG91dF9zcGxpdCA9IEYpCmBgYAoKIyBQcm9ncmFtIDIKYGBge3J9CmNvbD0xCnJhbmtlZF92ZWMgPSBnZXBfc2NvcmVzOFssIGNvbF0gJT4lIHNldE5hbWVzKHJvd25hbWVzKGdlcF9zY29yZXM4KSkgJT4lIHNvcnQoZGVjcmVhc2luZyA9IFRSVUUpCnByaW50IChwYXN0ZSgicnVubmluZyBnZXAiLGNvbCkpCmh5cF9vYmogPC1oeXBlUl9mZ3NlYShyYW5rZWRfdmVjLCBnZW5lc2V0c19nbywgdXBfb25seSA9IFQpCgpwcmludChoeXBfZG90cyhoeXBfb2JqLCB0aXRsZSA9IHBhc3RlKCJwcm9ncmFtIiwgY29sKSwgYWJydiA9IDcwKSArIGFlcyhzaXplID1uZXMpKQogIApgYGAKCgpgYGB7cn0KY29sPTIKcmFua2VkX3ZlYyA9IGdlcF9zY29yZXM4WywgY29sXSAlPiUgc2V0TmFtZXMocm93bmFtZXMoZ2VwX3Njb3JlczgpKSAlPiUgc29ydChkZWNyZWFzaW5nID0gVFJVRSkKcHJpbnQgKHBhc3RlKCJydW5uaW5nIGdlcCIsY29sKSkKaHlwX29iaiA8LWh5cGVSX2Znc2VhKHJhbmtlZF92ZWMsIGdlbmVzZXRzX2dvLCB1cF9vbmx5ID0gVCkKCnByaW50KGh5cF9kb3RzKGh5cF9vYmosIHRpdGxlID0gcGFzdGUoInByb2dyYW0iLCBjb2wpLCBhYnJ2ID0gNzApICsgYWVzKHNpemUgPW5lcykpCiAgCmBgYApgYGB7cn0KcGF0aHdheV9udW0gPSAxCmxlX2dlbmVzID0gaHlwX29iaiRhcy5kYXRhLmZyYW1lKClbcGF0aHdheV9udW0sImxlIl0gJT4lIHN0cnNwbGl0KCIsIikgJT4lIHVubGlzdCgpCnNjb3JlID0gKGx1bmdfZXhwcmVzc2lvblssIGxlX2dlbmVzXSAlPiUgYXMubWF0cml4KCkpICAlKiUgYXMubWF0cml4KGdlcF9zY29yZXM4W2xlX2dlbmVzLCAyLCBkcm9wID1GXSkKCiMgc2NvcmUgPSBGZXRjaERhdGEob2JqZWN0ID0gbHVuZyx2YXJzID0gbGVfZ2VuZXMpICU+JSByb3dNZWFucygpCnBhdGh3YXlfbmFtZSA9IHBhc3RlMChoeXBfb2JqJGRhdGFbcGF0aHdheV9udW0sICJsYWJlbCIsIGRyb3AgPSBGXSwgIl9sZSIpICU+JSBnc3ViKHBhdHRlcm4gPSAiICIscmVwbGFjZW1lbnQgPSAiXyIpCmx1bmcgPSBBZGRNZXRhRGF0YShsdW5nLCBzY29yZSwgY29sLm5hbWUgPSBwYXRod2F5X25hbWUpCnByaW50X3RhYihGZWF0dXJlUGxvdChvYmplY3QgPSBsdW5nLGZlYXR1cmVzID0gcGF0aHdheV9uYW1lKSx0aXRsZSA9IHBhdGh3YXlfbmFtZSkKYGBgCmBgYHtyfQpwYXRod2F5X251bSA9IDEKbGVfZ2VuZXMgPSBoeXBfb2JqJGFzLmRhdGEuZnJhbWUoKVtwYXRod2F5X251bSwibGUiXSAlPiUgc3Ryc3BsaXQoIiwiKSAlPiUgdW5saXN0KCkKc2NvcmUgPSAobHVuZ19leHByZXNzaW9uWywgbGVfZ2VuZXNbIGxlX2dlbmVzICVpbiUgdG9wX2dlbmVzWzE6MjAwXV1dICU+JSBhcy5tYXRyaXgoKSkgICUqJSBhcy5tYXRyaXgoZ2VwX3Njb3JlczhbbGVfZ2VuZXNbIGxlX2dlbmVzICVpbiUgdG9wX2dlbmVzWzE6MjAwXV0sIDIsIGRyb3AgPUZdKQpjb3Ioc2NvcmUsdXNhZ2VfYnlfY2FsY1ssMl0pCnNjb3JlID0gRmV0Y2hEYXRhKG9iamVjdCA9IGx1bmcsdmFycyA9IGxlX2dlbmVzWyBsZV9nZW5lcyAlaW4lIHRvcF9nZW5lc1sxOjIwMF1dKSAlPiUgcm93TWVhbnMoKQpjb3Ioc2NvcmUsdXNhZ2VfYnlfY2FsY1ssMl0pCgogICAgICAgIAp0b3BfZ2VuZXMgPSBnZXBfc2NvcmVzOFssMl0gJT4lIHNldE5hbWVzKHJvd25hbWVzKGdlcF9zY29yZXM4KSkgJT4lIHNvcnQoZGVjcmVhc2luZyA9IFRSVUUpICU+JSBuYW1lcygpCnNjb3JlID0gKGx1bmdfZXhwcmVzc2lvblssIHRvcF9nZW5lc1sxOjIwMF1dICU+JSBhcy5tYXRyaXgoKSkgICUqJSBhcy5tYXRyaXgoZ2VwX3Njb3JlczhbdG9wX2dlbmVzWzE6MjAwXSwgMiwgZHJvcCA9Rl0pCiB0b3BfZ2VuZXMgJWluJSAgbGVfZ2VuZXMgJT4lIHdoaWNoKCkKY29yKHNjb3JlLHVzYWdlX2J5X2NhbGNbLDJdKQoKcGF0aHdheV9uYW1lID0gcGFzdGUwKGh5cF9vYmokZGF0YVtwYXRod2F5X251bSwgImxhYmVsIiwgZHJvcCA9IEZdLCAiX2xlIikgJT4lIGdzdWIocGF0dGVybiA9ICIgIixyZXBsYWNlbWVudCA9ICJfIikKbHVuZyA9IEFkZE1ldGFEYXRhKGx1bmcsIHNjb3JlLCBjb2wubmFtZSA9IHBhdGh3YXlfbmFtZSkKcHJpbnRfdGFiKEZlYXR1cmVQbG90KG9iamVjdCA9IGx1bmcsZmVhdHVyZXMgPSBwYXRod2F5X25hbWUpLHRpdGxlID0gcGF0aHdheV9uYW1lKQpgYGAKCmBgYHtyIHJlc3VsdHM9J2FzaXMnfQptZXRhZ2VuZXNfbWVhbl9jb21wYXJlKGRhdGFzZXQgPSBsdW5nLHRpbWUucG9pbnRfdmFyID0gInRpbWUucG9pbnQiLHByZWZpeCA9ICJwYXRpZW50IixwYXRpZW50LmlkZW50X3ZhciA9ICJwYXRpZW50LmlkZW50IixwcmVfb24gPSBjKCJwcmUtdHJlYXRtZW4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0Iiwib24tdHJlYXRtZW50IiksdGVzdCA9ICJ3aWxjb3gudGVzdCIscHJvZ3JhbXMgPSBwYXRod2F5X25hbWUsd2l0aG91dF9zcGxpdCA9IEYpCmBgYAoKCiMgcHJvZ3JhbXMgTEUgZ2VuZXMgey50YWJzZXR9CgoKCmBgYHtyIHJlc3VsdHM9J2FzaXMnfQoKcHJvZ3JhbXNfbWFpbl9wYXRod2F5c19uYW1lcyA9IGxpc3QoKQogIGZvciAoY29sIGluIHNlcV9hbG9uZyhnZXBfc2NvcmVzOClbMTozXSkgewogICAgIHJhbmtlZF92ZWMgPSBnZXBfc2NvcmVzOFssY29sXSAlPiUgc2V0TmFtZXMocm93bmFtZXMoZ2VwX3Njb3JlczgpKSAlPiUgc29ydChkZWNyZWFzaW5nID0gVFJVRSkgCiAgICAgaHlwX29iaiA8LSBoeXBlUl9mZ3NlYShyYW5rZWRfdmVjLCBnZW5lc2V0cykKICAgICBwcm9ncmFtc19tYWluX3BhdGh3YXlzX25hbWVzW1tjb2xdXSA9ICBoeXBfb2JqJGRhdGFbcHJvZ3JhbXNfbWFpbl9wYXRod2F5c1tbY29sXV0sImxhYmVsIixkcm9wPVRdCiAgICAgZm9yIChwYXRod2F5X251bSBpbiBwcm9ncmFtc19tYWluX3BhdGh3YXlzW1tjb2xdXSkgewogICAgICAgIGxlX2dlbmVzID0gIGh5cF9vYmokZGF0YVtwYXRod2F5X251bSwsZHJvcD1GXSAlPiUgcHVsbCgibGUiKSAlPiUgc3Ryc3BsaXQoIiwiKSAlPiUgdW5saXN0KCkKICAgICAgICAjIHNjb3JlID0gKGx1bmdfZXhwcmVzc2lvblssbGVfZ2VuZXNdICU+JSBhcy5tYXRyaXgoKSkgICUqJSBhcy5tYXRyaXgoZ2VwX3Njb3JlczhbbGVfZ2VuZXMsY29sLGRyb3A9Rl0pCiAgICAgICAgIyBzY29yZSA9IHNjb3JlICU+JSBhcy52ZWN0b3IoKQogICAgICAgIHNjb3JlID0gRmV0Y2hEYXRhKG9iamVjdCA9IGx1bmcsdmFycyA9IGxlX2dlbmVzKSAlPiUgcm93TWVhbnMoKQogICAgICAgIHBhdGh3YXlfbmFtZSA9IHBhc3RlMChoeXBfb2JqJGRhdGFbcGF0aHdheV9udW0sImxhYmVsIixkcm9wPUZdLCJfbGUiKQogICAgICAgIGx1bmc9QWRkTWV0YURhdGEobHVuZyxzY29yZSxjb2wubmFtZSA9IHBhdGh3YXlfbmFtZSkKICAgICAgICBjb3JfcmVzID0gY29yKHNjb3JlLHVzYWdlX2J5X2NhbGNbLGNvbF0pCiAgICAgICAgcHJpbnRfdGFiKEZlYXR1cmVQbG90KG9iamVjdCA9IGx1bmcsZmVhdHVyZXMgPSBwYXRod2F5X25hbWUpK2dndGl0bGUocGF0aHdheV9uYW1lLCBzdWJ0aXRsZSA9IHBhc3RlKCJjb3IgdG8gdXNhZ2U6Iixjb3JfcmVzKSksdGl0bGUgPSBwYXRod2F5X25hbWUpCiAgICAgfQogIH0KYGBgCiMgcHJvZ3JhbXMgTEUgZ2VuZXMgey50YWJzZXR9CgpgYGB7ciByZXN1bHRzPSdhc2lzJ30KbWV0YWdlbmVzX21lYW5fY29tcGFyZShkYXRhc2V0ID0gbHVuZyx0aW1lLnBvaW50X3ZhciA9ICJ0aW1lLnBvaW50IixwcmVmaXggPSAicGF0aWVudCIscGF0aWVudC5pZGVudF92YXIgPSAicGF0aWVudC5pZGVudCIscHJlX29uID0gYygicHJlLXRyZWF0bWVudCIsIm9uLXRyZWF0bWVudCIpLHRlc3QgPSAid2lsY294LnRlc3QiLHByb2dyYW1zID0gcHJvZ3JhbXNfbWFpbl9wYXRod2F5c19uYW1lcyAlPiUgdW5saXN0KCkgJT4lIHBhc3RlMCgiX2xlIikgLHdpdGhvdXRfc3BsaXQgPSBGKQpgYGAKPHNjcmlwdCBzcmM9Imh0dHBzOi8vaHlwb3RoZXMuaXMvZW1iZWQuanMiIGFzeW5jPjwvc2NyaXB0PgoKCg==