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()
Functions
library(stringi)
library(reticulate)
source_from_github(repositoy = "DEG_functions",version = "0.2.47")
source_from_github(repositoy = "cNMF_functions",version = "0.4.01",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:KEGG"))
genesets[["HIF_targets"]] = hif_targets
genesets_go <- msigdb_download("Homo sapiens",category="C5",subcategory = "GO:BP")
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)
gep scores for all NMF
k’s
density_threshold = 0.1
usage_norm3, gep_scores3, gep_tpm, topgenes = cnmf_obj.load_results(K=3, density_threshold=density_threshold)
usage_norm6, gep_scores6, gep_tpm, topgenes = cnmf_obj.load_results(K=6, density_threshold=density_threshold)
usage_norm7, gep_scores7, gep_tpm, topgenes = cnmf_obj.load_results(K=7, density_threshold=density_threshold)
usage_norm8, gep_scores8, gep_tpm, topgenes = cnmf_obj.load_results(K=8, density_threshold=density_threshold)
Enrichment analysis by top 200 genes of each program
gep_scores3 = py$gep_scores3
gep_scores6 = py$gep_scores6
gep_scores7 = py$gep_scores7
gep_scores8 = py$gep_scores8
GSEA for
every program
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)
print_tab(hyp_dots(hyp_obj,title = paste("program",col))+ aes(size=nes),title = paste0("gep",col))
}
gep1

gep2

gep3

gep4

gep5

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) ## gep6 {.unnumbered }

gep7

gep8

NA
gep_scores = py$gep_scores8
usage_norm = py$usage_norm8
progrmas from NMF
colnames(usage_norm) = paste0("gep",1:8)
#add each metagene to metadata
for (i in 1:ncol(usage_norm )) {
metagene_metadata = usage_norm [,i,drop=F]
lung = AddMetaData(object = lung,metadata = metagene_metadata,col.name = colnames(usage_norm)[i])
}
FeaturePlot(object = lung,features = colnames(usage_norm),ncol = 3)

progrmas
from NMF
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_norm)[1:5],without_split = F)
gep1 per patient

gep2 per patient

gep3 per patient

gep4 per patient

gep5 per patient

NA
Calculate usage by
counts before Harmony
# get expression with genes in cnmf input
genes = rownames(gep_scores)
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)
used (Mb) gc trigger (Mb) max used (Mb)
Ncells 13005635 694.6 21808952 1164.8 21808952 1164.8 Vcells
1505803258 11488.4 2197729618 16767.4 1767994410 13488.8
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)
/sci/labs/yotamd/lab_share/avishai.wizel/python_envs/miniconda/envs/cnmf_env_6/bin/python3.7:7: FutureWarning: X.dtype being converted to np.float32 from float64. In the next version of anndata (0.9) conversion will not be automatic. Pass dtype explicitly to avoid this warning. Pass `AnnData(X, dtype=X.dtype, ...)` to get the future behavour.
/sci/labs/yotamd/lab_share/avishai.wizel/python_envs/miniconda/envs/cnmf_env_6/bin/python3.7:8: FutureWarning: X.dtype being converted to np.float32 from float64. In the next version of anndata (0.9) conversion will not be automatic. Pass dtype explicitly to avoid this warning. Pass `AnnData(X, dtype=X.dtype, ...)` to get the future behavour.
usage_by_calc = py$usage_by_calc
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)

cor_res = cor(gep_scores)
breaks <- c(seq(-1,1,by=0.01))
colors_for_plot <- colorRampPalette(colors = c("blue", "white", "red"))(n = length(breaks))
pht = pheatmap(cor_res,color = colors_for_plot,breaks = breaks)
print_tab(pht,title = "correlation")
groups_list = c(5,6)
patients_geps = union_programs(groups_list = groups_list,all_metagenes = patients_geps)
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)
gep1 per patient

gep2 per patient

gep3 per patient

gep4 per patient

gep5 per patient

NA
programs_main_pathways = list(gep1 = 1:5, gep2 = 1:4,gep3 = 1:3)
programs LE genes
programs_main_pathways_names = list()
Warning message: In grSoftVersion() : unable to load shared object
‘/usr/local/lib/R/modules//R_X11.so’: libXt.so.6: cannot open shared
object file: No such file or directory
for (col in seq_along(gep_scores)) {
ranked_vec = gep_scores[,col] %>% setNames(rownames(gep_scores)) %>% 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()
scoresAndIndices = getPathwayScores(dataMatrix = lung@assays$RNA@data,pathwayGenes = le_genes)
pathway_name = paste0(hyp_obj$data[pathway_num,"label",drop=F],"_le")
lung=AddMetaData(lung,scoresAndIndices$pathwayScores,col.name = pathway_name)
print_tab(FeaturePlot(object = lung,features = pathway_name),title = pathway_name)
}
}
KEGG_AUTOIMMUNE_THYROID_DISEASE_le

KEGG_TYPE_I_DIABETES_MELLITUS_le

KEGG_INTESTINAL_IMMUNE_NETWORK_FOR_IGA_PRODUCTION_le

KEGG_SYSTEMIC_LUPUS_ERYTHEMATOSUS_le

KEGG_ALLOGRAFT_REJECTION_le

HALLMARK_TNFA_SIGNALING_VIA_NFKB_le

HALLMARK_P53_PATHWAY_le

HALLMARK_UV_RESPONSE_DN_le

KEGG_TGF_BETA_SIGNALING_PATHWAY_le

HALLMARK_HYPOXIA_le

HALLMARK_GLYCOLYSIS_le

HALLMARK_EPITHELIAL_MESENCHYMAL_TRANSITION_le

Error in programs_main_pathways[[col]] : subscript out of bounds
programs LE genes 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 = programs_main_pathways_names %>% unlist() %>% paste0("_le"),without_split = F)
KEGG_AUTOIMMUNE_THYROID_DISEASE_le per
patient

KEGG_TYPE_I_DIABETES_MELLITUS_le per patient

KEGG_INTESTINAL_IMMUNE_NETWORK_FOR_IGA_PRODUCTION_le
per patient

KEGG_SYSTEMIC_LUPUS_ERYTHEMATOSUS_le per
patient

KEGG_ALLOGRAFT_REJECTION_le per patient

HALLMARK_TNFA_SIGNALING_VIA_NFKB_le per
patient

HALLMARK_P53_PATHWAY_le per patient

HALLMARK_UV_RESPONSE_DN_le per patient

KEGG_TGF_BETA_SIGNALING_PATHWAY_le per
patient

HALLMARK_HYPOXIA_le per patient

HALLMARK_GLYCOLYSIS_le per patient

HALLMARK_EPITHELIAL_MESENCHYMAL_TRANSITION_le per
patient

NA
Top program 2 genes
expression correlation
annotation = plot_genes_cor(dataset = xeno,geneIds = top_ot,height = 2.8)
## genes expression heatmap {.unnumbered }

NA
cluster
program expression
for (chosen_clusters in 1:length(unique(annotation$cluster))) {
chosen_genes = annotation %>% dplyr::filter(cluster == chosen_clusters) %>% rownames() #take relevant genes
# print(chosen_genes)
hyp_obj <- hypeR(chosen_genes, genesets, test = "hypergeometric", fdr=1, plotting=F,background = rownames(patients_geps))
scoresAndIndices <- getPathwayScores(lung@assays$RNA@data, chosen_genes)
lung=AddMetaData(lung,scoresAndIndices$pathwayScores,paste0("cluster",chosen_clusters))
print_tab(plt =
hyp_dots(hyp_obj,size_by = "none",title = paste0("cluster",chosen_clusters))+
FeaturePlot(object = lung,features = paste0("cluster",chosen_clusters)),
title = chosen_clusters)
cor_res = cor(lung$interferon_like,lung[[paste0("cluster",chosen_clusters)]])
# print(paste("correlation of TNFa program to", paste0("cluster",chosen_clusters),":", cor_res))
}
1

2

3

4

5

6

7

NA
cluster
program 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 = paste0("cluster",1:length(unique(annotation$cluster))),without_split = F)
cluster1 per patient

cluster2 per patient

cluster3 per patient

cluster4 per patient

cluster5 per patient

cluster6 per patient

cluster7 per patient

NA
cluster
program enrichment
top_ot = patients_geps[order(patients_geps[,1],decreasing = T),2,drop = F]%>% head(10) %>% rownames()
chosen_genes = top_ot
scoresAndIndices <- getPathwayScores(lung@assays$RNA@data, chosen_genes)
lung=AddMetaData(lung,scoresAndIndices$pathwayScores,"immune_gep")
cor_res = cor(lung$interferon_like,lung[["immune_gep"]])
print(paste("correlation of TNFa program to", "immune_gep",":", cor_res))
for (chosen_clusters in 1:length(unique(annotation$cluster))) {
chosen_genes = annotation %>% dplyr::filter(cluster == chosen_clusters) %>% rownames() #take relevant genes
# print(chosen_genes)
hyp_obj <- hypeR(chosen_genes, genesets, test = "hypergeometric", fdr=1, plotting=F,background = rownames(patients_geps))
scoresAndIndices <- getPathwayScores(lung@assays$RNA@data, chosen_genes)
lung=AddMetaData(lung,scoresAndIndices$pathwayScores,paste0("cluster",chosen_clusters))
print_tab(plt =
hyp_dots(hyp_obj,size_by = "none",title = paste0("cluster",chosen_clusters))+
FeaturePlot(object = lung,features = paste0("cluster",chosen_clusters)),
title = chosen_clusters)
cor_res = cor(lung$interferon_like,lung[[paste0("cluster",chosen_clusters)]])
print(paste("correlation of TNFa program to", paste0("cluster",chosen_clusters),":", cor_res))
}
## 1 {.unnumbered }

[1] "correlation of TNFa program to cluster1 : 0.155039646876199"
## 2 {.unnumbered }

[1] "correlation of TNFa program to cluster2 : 0.35203084026905"
## 3 {.unnumbered }

[1] "correlation of TNFa program to cluster3 : 0.163348283357048"
## 4 {.unnumbered }

[1] "correlation of TNFa program to cluster4 : -0.0422938672700064"
## 5 {.unnumbered }

[1] "correlation of TNFa program to cluster5 : 0.430856560234176"
## 6 {.unnumbered }

[1] "correlation of TNFa program to cluster6 : -0.107526561142319"
## 7 {.unnumbered }

[1] "correlation of TNFa program to cluster7 : -0.0617622603084714"
mult = as.matrix(t(gep_scores[,1,drop=F])) %*% (lung@assays$RNA@data[rownames(gep_scores),] %>% as.matrix())
names(mult) = colnames(lung)
mult = as.data.frame(t(mult))
lung=AddMetaData(lung,mult,"immune_gep_mult")
cor_res = cor(lung$interferon_like,lung[["immune_gep_mult"]])
print(paste("correlation of TNFa program to", "immune_gep_mult",":", cor_res))
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 = "immune_gep_mult",without_split = F)
# get expression with genes in cnmf input
lung = FindVariableFeatures(object = lung,nfeatures = 2000)
genes = rownames(lung)[rownames(lung) %in% VariableFeatures(object = xeno)[1:2000]]
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
# gep_scores = r.patients_geps
usage_by_calc = get_usage_from_score(counts=lung_expression,tpm=lung_expression,genes=genes,cnmf_obj=cnmf_obj,k=8,sumTo1=False)
usage_by_calc = py$usage_by_calc
groups_list = c(4,3,6)
usage_by_calc = union_programs(groups_list = groups_list,all_metagenes = usage_by_calc)
# usage_by_calc = apply(usage_by_calc, MARGIN = 1, sum_2_one) %>% t() %>% as.data.frame()
usage_by_calc =usage_by_calc %>% rename(cell_cycle = gep4.3.6, hypoxia_like = gep2, interferon_like = gep1, TNFa = gep5, INF2 = gep7)
lung=AddMetaData(lung,usage_by_calc[,1,drop=F],"immune_gep_no_sum2one")
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 = "immune_gep_no_sum2one",without_split = F)
LS0tCnRpdGxlOiAnYHIgcnN0dWRpb2FwaTo6Z2V0U291cmNlRWRpdG9yQ29udGV4dCgpJHBhdGggJT4lIGJhc2VuYW1lKCkgJT4lIGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLHJlcGxhY2VtZW50ID0gIiIpYCcgCmF1dGhvcjogIkF2aXNoYWkgV2l6ZWwiCmRhdGU6ICdgciBTeXMudGltZSgpYCcKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdG9jOiB5ZXMKICAgIHRvY19jb2xsYXBzZTogeWVzCiAgICB0b2NfZmxvYXQ6IAogICAgICBjb2xsYXBzZWQ6IEZBTFNFCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvY19kZXB0aDogMQplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCgojIERhdGEKCmBgYHtyfQpsdW5nID0gcmVhZFJEUygiLi9EYXRhL2x1bmdfY2FuY2VyY2VsbHNfd2l0aFRQX29ubHlQYXRpZW50cy5yZHMiKQpsdW5nX3BhdGllbnRzID0gbHVuZyRwYXRpZW50LmlkZW50ICU+JSB1bmlxdWUoKSAlPiUgYXMuY2hhcmFjdGVyKCkKbHVuZ19wYXRpZW50c19maWx0ZXJlZCA9IGx1bmdfcGF0aWVudHNbIShsdW5nX3BhdGllbnRzICVpbiUgYygiWDEwNTVuZXciLCJYMTA5OSIpKV0gIyByZW1vdmUgcGF0aWVudHMgd2l0aCBsZXNzIHRoYW4gMTAwIG1hbGlnbmFudCBjZWxscwpsdW5nID0gc3Vic2V0KHggPSBsdW5nLHN1YnNldCA9IHBhdGllbnQuaWRlbnQgJWluJSBsdW5nX3BhdGllbnRzX2ZpbHRlcmVkKQpgYGAKCgpgYGB7cn0Kc3VmZml4ID0ieGVub19nZW5lc18wLTVzaWdtYV8yLTd0aGV0YV8xMDBpdGVyXzI2XzkiCmBgYAoKCmBgYHtweXRob259CmZyb20gY25tZiBpbXBvcnQgY05NRgpzdWZmaXggPSByLnN1ZmZpeAppbXBvcnQgcGlja2xlCmYgPSBvcGVuKCcuL0RhdGEvY25tZi9jbm1mX29iamVjdHMvcGF0aWVudHNfJyArIHN1ZmZpeCArICdfY25tZl9vYmoucGNrbCcsICdyYicpCmNubWZfb2JqID0gcGlja2xlLmxvYWQoZikKZi5jbG9zZSgpCmBgYAoKCgojIEZ1bmN0aW9ucwoKYGBge3J9CmxpYnJhcnkoc3RyaW5naSkKbGlicmFyeShyZXRpY3VsYXRlKQpzb3VyY2VfZnJvbV9naXRodWIocmVwb3NpdG95ID0gIkRFR19mdW5jdGlvbnMiLHZlcnNpb24gPSAiMC4yLjQ3IikKc291cmNlX2Zyb21fZ2l0aHViKHJlcG9zaXRveSA9ICJjTk1GX2Z1bmN0aW9ucyIsdmVyc2lvbiA9ICIwLjQuMDEiLHNjcmlwdF9uYW1lID0gImNubWZfZnVuY3Rpb25zX1YzLlIiKQpzb3VyY2VfZnJvbV9naXRodWIocmVwb3NpdG95ID0gInNjX2dlbmVyYWxfZnVuY3Rpb25zIix2ZXJzaW9uID0gIjAuMS4yOCIsc2NyaXB0X25hbWUgPSAiZnVuY3Rpb25zLlIiKQpgYGAKCmBgYHtyfQpnZW5lc2V0cyA8LSBtc2lnZGJfZG93bmxvYWQoIkhvbW8gc2FwaWVucyIsY2F0ZWdvcnk9IkgiKSAlPiUgYXBwZW5kKCBtc2lnZGJfZG93bmxvYWQoIkhvbW8gc2FwaWVucyIsY2F0ZWdvcnk9IkMyIixzdWJjYXRlZ29yeSA9ICJDUDpLRUdHIikpCmdlbmVzZXRzW1siSElGX3RhcmdldHMiXV0gPSBoaWZfdGFyZ2V0cwoKZ2VuZXNldHNfZ28gPC0gbXNpZ2RiX2Rvd25sb2FkKCJIb21vIHNhcGllbnMiLGNhdGVnb3J5PSJDNSIsc3ViY2F0ZWdvcnkgPSAiR086QlAiKQpgYGAKCiMgSyBzZWxlY3Rpb24gcGxvdApgYGB7ciBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD00fQpwbG90X3BhdGggPSBwYXN0ZTAoIi9zY2kvbGFicy95b3RhbWQvbGFiX3NoYXJlL2F2aXNoYWkud2l6ZWwvUl9wcm9qZWN0cy9FR0ZSL0RhdGEvY25tZi9jTk1GX3BhdGllbnRzX1Zhcm5vcm1fSGFybW9ueV8iLHN1ZmZpeCwiL2NOTUZfcGF0aWVudHNfVmFybm9ybV9IYXJtb255XyIsc3VmZml4LCIua19zZWxlY3Rpb24ucG5nIikKa25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MocGxvdF9wYXRoKQpgYGAKCgpgYGB7cHl0aG9ufQpjbm1mX29iai5jb25zZW5zdXMoaz0zLCBkZW5zaXR5X3RocmVzaG9sZD0wLjEsc2hvd19jbHVzdGVyaW5nPVRydWUpCmNubWZfb2JqLmNvbnNlbnN1cyhrPTYsIGRlbnNpdHlfdGhyZXNob2xkPTAuMSxzaG93X2NsdXN0ZXJpbmc9VHJ1ZSkKY25tZl9vYmouY29uc2Vuc3VzKGs9NywgZGVuc2l0eV90aHJlc2hvbGQ9MC4xLHNob3dfY2x1c3RlcmluZz1UcnVlKQpjbm1mX29iai5jb25zZW5zdXMoaz04LCBkZW5zaXR5X3RocmVzaG9sZD0wLjEsc2hvd19jbHVzdGVyaW5nPVRydWUpCmBgYAoKCiMgZ2VwIHNjb3JlcyBmb3IgYWxsIE5NRiBrJ3MKYGBge3B5dGhvbn0KZGVuc2l0eV90aHJlc2hvbGQgPSAwLjEKdXNhZ2Vfbm9ybTMsIGdlcF9zY29yZXMzLCBnZXBfdHBtLCB0b3BnZW5lcyA9IGNubWZfb2JqLmxvYWRfcmVzdWx0cyhLPTMsIGRlbnNpdHlfdGhyZXNob2xkPWRlbnNpdHlfdGhyZXNob2xkKQp1c2FnZV9ub3JtNiwgZ2VwX3Njb3JlczYsIGdlcF90cG0sIHRvcGdlbmVzID0gY25tZl9vYmoubG9hZF9yZXN1bHRzKEs9NiwgZGVuc2l0eV90aHJlc2hvbGQ9ZGVuc2l0eV90aHJlc2hvbGQpCnVzYWdlX25vcm03LCBnZXBfc2NvcmVzNywgZ2VwX3RwbSwgdG9wZ2VuZXMgPSBjbm1mX29iai5sb2FkX3Jlc3VsdHMoSz03LCBkZW5zaXR5X3RocmVzaG9sZD1kZW5zaXR5X3RocmVzaG9sZCkKdXNhZ2Vfbm9ybTgsIGdlcF9zY29yZXM4LCBnZXBfdHBtLCB0b3BnZW5lcyA9IGNubWZfb2JqLmxvYWRfcmVzdWx0cyhLPTgsIGRlbnNpdHlfdGhyZXNob2xkPWRlbnNpdHlfdGhyZXNob2xkKQoKYGBgCgojIEVucmljaG1lbnQgYW5hbHlzaXMgYnkgdG9wIDIwMCBnZW5lcyBvZiBlYWNoIHByb2dyYW0gey50YWJzZXR9CmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTgsIHJlc3VsdHM9J2FzaXMnfQpnZXBfc2NvcmVzMyA9IHB5JGdlcF9zY29yZXMzCmdlcF9zY29yZXM2ID0gcHkkZ2VwX3Njb3JlczYKZ2VwX3Njb3JlczcgPSBweSRnZXBfc2NvcmVzNwpnZXBfc2NvcmVzOCA9IHB5JGdlcF9zY29yZXM4CgoKYGBgCgojIEdTRUEgZm9yIGV2ZXJ5IHByb2dyYW0gey50YWJzZXR9CgpgYGB7ciByZXN1bHRzPSdhc2lzJ30KICBmb3IgKGNvbCBpbiBzZXFfYWxvbmcoZ2VwX3Njb3JlczgpKSB7CiAgICAgcmFua2VkX3ZlYyA9IGdlcF9zY29yZXM4Wyxjb2xdICU+JSBzZXROYW1lcyhyb3duYW1lcyhnZXBfc2NvcmVzOCkpICU+JSBzb3J0KGRlY3JlYXNpbmcgPSBUUlVFKSAKICAgICBoeXBfb2JqIDwtIGh5cGVSX2Znc2VhKHJhbmtlZF92ZWMsIGdlbmVzZXRzKQogICAgICAgcHJpbnRfdGFiKGh5cF9kb3RzKGh5cF9vYmosdGl0bGUgPSBwYXN0ZSgicHJvZ3JhbSIsY29sKSkrIGFlcyhzaXplPW5lcyksdGl0bGUgPSBwYXN0ZTAoImdlcCIsY29sKSkKICB9CmBgYAoKCgoKYGBge3J9CmdlcF9zY29yZXMgPSBweSRnZXBfc2NvcmVzOAp1c2FnZV9ub3JtID0gcHkkdXNhZ2Vfbm9ybTgKYGBgCgojIHByb2dybWFzIGZyb20gTk1GCmBgYHtyIGVjaG89VFJVRSwgZmlnLmhlaWdodD05LCBmaWcud2lkdGg9MTIsIHJlc3VsdHM9J2FzaXMnfQpjb2xuYW1lcyh1c2FnZV9ub3JtKSA9IHBhc3RlMCgiZ2VwIiwxOjgpCiNhZGQgZWFjaCBtZXRhZ2VuZSB0byBtZXRhZGF0YQpmb3IgKGkgIGluIDE6bmNvbCh1c2FnZV9ub3JtICkpIHsKICBtZXRhZ2VuZV9tZXRhZGF0YSA9IHVzYWdlX25vcm0gWyxpLGRyb3A9Rl0KICBsdW5nID0gQWRkTWV0YURhdGEob2JqZWN0ID0gbHVuZyxtZXRhZGF0YSA9IG1ldGFnZW5lX21ldGFkYXRhLGNvbC5uYW1lID0gY29sbmFtZXModXNhZ2Vfbm9ybSlbaV0pCn0KCkZlYXR1cmVQbG90KG9iamVjdCA9IGx1bmcsZmVhdHVyZXMgPSBjb2xuYW1lcyh1c2FnZV9ub3JtKSxuY29sID0gMykKCmBgYAojIHByb2dybWFzIGZyb20gTk1GIHsudGFic2V0fQoKYGBge3IgcmVzdWx0cz0nYXNpcyd9Cm1ldGFnZW5lc19tZWFuX2NvbXBhcmUoZGF0YXNldCA9IGx1bmcsdGltZS5wb2ludF92YXIgPSAidGltZS5wb2ludCIscHJlZml4ID0gInBhdGllbnQiLHBhdGllbnQuaWRlbnRfdmFyID0gInBhdGllbnQuaWRlbnQiLHByZV9vbiA9IGMoInByZS10cmVhdG1lbnQiLCJvbi10cmVhdG1lbnQiKSx0ZXN0ID0gIndpbGNveC50ZXN0Iixwcm9ncmFtcyA9IGNvbG5hbWVzKHVzYWdlX25vcm0pWzE6NV0sd2l0aG91dF9zcGxpdCA9IEYpCmBgYAoKIyBDYWxjdWxhdGUgdXNhZ2UgYnkgY291bnRzIGJlZm9yZSBIYXJtb255CmBgYHtyIGVjaG89VFJVRSwgcmVzdWx0cz0nYXNpcyd9CiMgZ2V0IGV4cHJlc3Npb24gd2l0aCBnZW5lcyBpbiBjbm1mIGlucHV0CmdlbmVzID0gcm93bmFtZXMoZ2VwX3Njb3JlcykKbHVuZ19leHByZXNzaW9uID0gdChhcy5tYXRyaXgoR2V0QXNzYXlEYXRhKGx1bmcsc2xvdD0nZGF0YScpKSkgCmx1bmdfZXhwcmVzc2lvbiA9IDIqKmx1bmdfZXhwcmVzc2lvbiAjY29udmVydCBmcm9tIGxvZzIodHBtKzEpIHRvIHRwbQpsdW5nX2V4cHJlc3Npb24gPSBsdW5nX2V4cHJlc3Npb24tMQpsdW5nX2V4cHJlc3Npb24gPSBsdW5nX2V4cHJlc3Npb25bLGdlbmVzXSAlPiUgYXMuZGF0YS5mcmFtZSgpCgphbGxfMF9nZW5lcyA9IGNvbG5hbWVzKGx1bmdfZXhwcmVzc2lvbilbY29sU3VtcyhsdW5nX2V4cHJlc3Npb249PTAsIG5hLnJtPVRSVUUpPT1ucm93KGx1bmdfZXhwcmVzc2lvbildICNkZWxldGUgcm93cyB0aGF0IGhhdmUgYWxsIDAKZ2VuZXMgPSBnZW5lc1shZ2VuZXMgJWluJSBhbGxfMF9nZW5lc10KbHVuZ19leHByZXNzaW9uID0gbHVuZ19leHByZXNzaW9uWywhY29sbmFtZXMobHVuZ19leHByZXNzaW9uKSAlaW4lIGFsbF8wX2dlbmVzXQpnYyh2ZXJib3NlID0gRikKYGBgCgoKYGBge3B5dGhvbn0KbHVuZ19leHByZXNzaW9uID0gci5sdW5nX2V4cHJlc3Npb24KZ2VuZXMgPSByLmdlbmVzCnVzYWdlX2J5X2NhbGMgPSBnZXRfdXNhZ2VfZnJvbV9zY29yZShjb3VudHM9bHVuZ19leHByZXNzaW9uLHRwbT1sdW5nX2V4cHJlc3Npb24sZ2VuZXM9Z2VuZXMsY25tZl9vYmo9Y25tZl9vYmosaz04LHN1bVRvMT1UcnVlKQpgYGAKYGBge3J9CnVzYWdlX2J5X2NhbGMgPSBweSR1c2FnZV9ieV9jYWxjCmBgYAoKYGBge3IgZWNobz1UUlVFLCBmaWcuaGVpZ2h0PTksIGZpZy53aWR0aD0xMiwgcmVzdWx0cz0nYXNpcyd9CmNvbG5hbWVzKHVzYWdlX2J5X2NhbGMpID0gcGFzdGUwKCJnZXAiLDE6OCkKI2FkZCBlYWNoIG1ldGFnZW5lIHRvIG1ldGFkYXRhCmZvciAoaSAgaW4gMTpuY29sKHVzYWdlX2J5X2NhbGMgKSkgewogIG1ldGFnZW5lX21ldGFkYXRhID0gdXNhZ2VfYnlfY2FsYyBbLGksZHJvcD1GXQogIGx1bmcgPSBBZGRNZXRhRGF0YShvYmplY3QgPSBsdW5nLG1ldGFkYXRhID0gbWV0YWdlbmVfbWV0YWRhdGEsY29sLm5hbWUgPSBjb2xuYW1lcyh1c2FnZV9ieV9jYWxjKVtpXSkKfQoKRmVhdHVyZVBsb3Qob2JqZWN0ID0gbHVuZyxmZWF0dXJlcyA9IGNvbG5hbWVzKHVzYWdlX2J5X2NhbGMpLG5jb2wgPSAzKQoKYGBgCgpgYGB7cn0KY29yX3JlcyA9IGNvcihnZXBfc2NvcmVzKQpicmVha3MgPC0gYyhzZXEoLTEsMSxieT0wLjAxKSkKY29sb3JzX2Zvcl9wbG90IDwtIGNvbG9yUmFtcFBhbGV0dGUoY29sb3JzID0gYygiYmx1ZSIsICJ3aGl0ZSIsICJyZWQiKSkobiA9IGxlbmd0aChicmVha3MpKQoKcGh0ID0gcGhlYXRtYXAoY29yX3Jlcyxjb2xvciA9IGNvbG9yc19mb3JfcGxvdCxicmVha3MgPSBicmVha3MpCnByaW50X3RhYihwaHQsdGl0bGUgPSAiY29ycmVsYXRpb24iKQpgYGAKCmBgYHtyfQpncm91cHNfbGlzdCA9IGMoNSw2KQpwYXRpZW50c19nZXBzID0gdW5pb25fcHJvZ3JhbXMoZ3JvdXBzX2xpc3QgPSBncm91cHNfbGlzdCxhbGxfbWV0YWdlbmVzID0gcGF0aWVudHNfZ2VwcykKYGBgCgojIFJlZ3VsYXRpb24gey50YWJzZXR9CgpgYGB7ciByZXN1bHRzPSdhc2lzJ30KbWV0YWdlbmVzX21lYW5fY29tcGFyZShkYXRhc2V0ID0gbHVuZyx0aW1lLnBvaW50X3ZhciA9ICJ0aW1lLnBvaW50IixwcmVmaXggPSAicGF0aWVudCIscGF0aWVudC5pZGVudF92YXIgPSAicGF0aWVudC5pZGVudCIscHJlX29uID0gYygicHJlLXRyZWF0bWVudCIsIm9uLXRyZWF0bWVudCIpLHRlc3QgPSAid2lsY294LnRlc3QiLHByb2dyYW1zID0gY29sbmFtZXModXNhZ2VfYnlfY2FsYylbMTo1XSx3aXRob3V0X3NwbGl0ID0gRikKYGBgCmBgYHtyfQpwcm9ncmFtc19tYWluX3BhdGh3YXlzID0gbGlzdChnZXAxID0gMTo1LCBnZXAyID0gMTo0LGdlcDMgPSAxOjMpCmBgYAoKIyBwcm9ncmFtcyBMRSBnZW5lcyB7LnRhYnNldH0KCmBgYHtyIHJlc3VsdHM9J2FzaXMnfQpwcm9ncmFtc19tYWluX3BhdGh3YXlzX25hbWVzID0gbGlzdCgpCiAgZm9yIChjb2wgaW4gc2VxX2Fsb25nKGdlcF9zY29yZXMpKSB7CiAgICAgcmFua2VkX3ZlYyA9IGdlcF9zY29yZXNbLGNvbF0gJT4lIHNldE5hbWVzKHJvd25hbWVzKGdlcF9zY29yZXMpKSAlPiUgc29ydChkZWNyZWFzaW5nID0gVFJVRSkgCiAgICAgaHlwX29iaiA8LSBoeXBlUl9mZ3NlYShyYW5rZWRfdmVjLCBnZW5lc2V0cykKICAgICBwcm9ncmFtc19tYWluX3BhdGh3YXlzX25hbWVzW1tjb2xdXSA9ICBoeXBfb2JqJGRhdGFbcHJvZ3JhbXNfbWFpbl9wYXRod2F5c1tbY29sXV0sImxhYmVsIixkcm9wPVRdCiAgICAgZm9yIChwYXRod2F5X251bSBpbiBwcm9ncmFtc19tYWluX3BhdGh3YXlzW1tjb2xdXSkgewogICAgICAgIGxlX2dlbmVzID0gIGh5cF9vYmokZGF0YVtwYXRod2F5X251bSwsZHJvcD1GXSAlPiUgcHVsbCgibGUiKSAlPiUgc3Ryc3BsaXQoIiwiKSAlPiUgdW5saXN0KCkKICAgICAgICBzY29yZXNBbmRJbmRpY2VzID0gZ2V0UGF0aHdheVNjb3JlcyhkYXRhTWF0cml4ID0gbHVuZ0Bhc3NheXMkUk5BQGRhdGEscGF0aHdheUdlbmVzID0gbGVfZ2VuZXMpCiAgICAgICAgcGF0aHdheV9uYW1lID0gcGFzdGUwKGh5cF9vYmokZGF0YVtwYXRod2F5X251bSwibGFiZWwiLGRyb3A9Rl0sIl9sZSIpCiAgICAgICAgbHVuZz1BZGRNZXRhRGF0YShsdW5nLHNjb3Jlc0FuZEluZGljZXMkcGF0aHdheVNjb3Jlcyxjb2wubmFtZSA9IHBhdGh3YXlfbmFtZSkKICAgICAgICBwcmludF90YWIoRmVhdHVyZVBsb3Qob2JqZWN0ID0gbHVuZyxmZWF0dXJlcyA9IHBhdGh3YXlfbmFtZSksdGl0bGUgPSBwYXRod2F5X25hbWUpCiAgICAgfQogIH0KYGBgCgoKIyBwcm9ncmFtcyBMRSBnZW5lcyByZWd1bGF0aW9uIHsudGFic2V0fQoKYGBge3IgcmVzdWx0cz0nYXNpcyd9Cm1ldGFnZW5lc19tZWFuX2NvbXBhcmUoZGF0YXNldCA9IGx1bmcsdGltZS5wb2ludF92YXIgPSAidGltZS5wb2ludCIscHJlZml4ID0gInBhdGllbnQiLHBhdGllbnQuaWRlbnRfdmFyID0gInBhdGllbnQuaWRlbnQiLHByZV9vbiA9IGMoInByZS10cmVhdG1lbnQiLCJvbi10cmVhdG1lbnQiKSx0ZXN0ID0gIndpbGNveC50ZXN0Iixwcm9ncmFtcyA9IHByb2dyYW1zX21haW5fcGF0aHdheXNfbmFtZXMgJT4lIHVubGlzdCgpICU+JSBwYXN0ZTAoIl9sZSIpLHdpdGhvdXRfc3BsaXQgPSBGKQpgYGAKCgojIFRvcCBwcm9ncmFtIDIgZ2VuZXMgZXhwcmVzc2lvbiBjb3JyZWxhdGlvbgpgYGB7cn0KdG9wX290ID0gZ2VwX3Njb3JlcyBbb3JkZXIoZ2VwX3Njb3JlcyBbLDJdLGRlY3JlYXNpbmcgPSBUKSwyLGRyb3AgPSBGXSU+JSBoZWFkKDIwMCkgJT4lIHJvd25hbWVzKCkKCmFubm90YXRpb24gPSBwbG90X2dlbmVzX2NvcihkYXRhc2V0ID0geGVubyxnZW5lSWRzID0gdG9wX290LGhlaWdodCA9IDIuOCkKCmBgYAojIGNsdXN0ZXIgcHJvZ3JhbSBleHByZXNzaW9uIHsudGFic2V0fQoKYGBge3IgcmVzdWx0cz0nYXNpcycsZmlnLndpZHRoPTE0fQpmb3IgKGNob3Nlbl9jbHVzdGVycyBpbiAxOmxlbmd0aCh1bmlxdWUoYW5ub3RhdGlvbiRjbHVzdGVyKSkpIHsKICBjaG9zZW5fZ2VuZXMgPSBhbm5vdGF0aW9uICU+JSBkcGx5cjo6ZmlsdGVyKGNsdXN0ZXIgPT0gY2hvc2VuX2NsdXN0ZXJzKSAlPiUgcm93bmFtZXMoKSAjdGFrZSByZWxldmFudCBnZW5lcwogICMgcHJpbnQoY2hvc2VuX2dlbmVzKQogIGh5cF9vYmogPC0gaHlwZVIoY2hvc2VuX2dlbmVzLCBnZW5lc2V0cywgdGVzdCA9ICJoeXBlcmdlb21ldHJpYyIsIGZkcj0xLCBwbG90dGluZz1GLGJhY2tncm91bmQgPSByb3duYW1lcyhwYXRpZW50c19nZXBzKSkKCiAgIHNjb3Jlc0FuZEluZGljZXMgPC0gZ2V0UGF0aHdheVNjb3JlcyhsdW5nQGFzc2F5cyRSTkFAZGF0YSwgY2hvc2VuX2dlbmVzKQogIGx1bmc9QWRkTWV0YURhdGEobHVuZyxzY29yZXNBbmRJbmRpY2VzJHBhdGh3YXlTY29yZXMscGFzdGUwKCJjbHVzdGVyIixjaG9zZW5fY2x1c3RlcnMpKQoKICAKICBwcmludF90YWIocGx0ID0gCiAgICAgICAgICAgICAgaHlwX2RvdHMoaHlwX29iaixzaXplX2J5ID0gIm5vbmUiLHRpdGxlID0gcGFzdGUwKCJjbHVzdGVyIixjaG9zZW5fY2x1c3RlcnMpKSsKICAgICAgICAgICAgICBGZWF0dXJlUGxvdChvYmplY3QgPSBsdW5nLGZlYXR1cmVzID0gcGFzdGUwKCJjbHVzdGVyIixjaG9zZW5fY2x1c3RlcnMpKSwKICAgICAgICAgICAgdGl0bGUgPSBjaG9zZW5fY2x1c3RlcnMpCiAgCiAgY29yX3JlcyA9IGNvcihsdW5nJGludGVyZmVyb25fbGlrZSxsdW5nW1twYXN0ZTAoImNsdXN0ZXIiLGNob3Nlbl9jbHVzdGVycyldXSkKIyBwcmludChwYXN0ZSgiY29ycmVsYXRpb24gb2YgVE5GYSBwcm9ncmFtIHRvIiwgcGFzdGUwKCJjbHVzdGVyIixjaG9zZW5fY2x1c3RlcnMpLCI6IiwgY29yX3JlcykpCgp9CgpgYGAKCgojIGNsdXN0ZXIgcHJvZ3JhbSByZWd1bGF0aW9uIHsudGFic2V0fQpgYGB7ciByZXN1bHRzPSdhc2lzJ30KbWV0YWdlbmVzX21lYW5fY29tcGFyZShkYXRhc2V0ID0gbHVuZyx0aW1lLnBvaW50X3ZhciA9ICJ0aW1lLnBvaW50IixwcmVmaXggPSAicGF0aWVudCIscGF0aWVudC5pZGVudF92YXIgPSAicGF0aWVudC5pZGVudCIscHJlX29uID0gYygicHJlLXRyZWF0bWVudCIsIm9uLXRyZWF0bWVudCIpLHRlc3QgPSAid2lsY294LnRlc3QiLHByb2dyYW1zID0gcGFzdGUwKCJjbHVzdGVyIiwxOmxlbmd0aCh1bmlxdWUoYW5ub3RhdGlvbiRjbHVzdGVyKSkpLHdpdGhvdXRfc3BsaXQgPSBGKQpgYGAKCiMgY2x1c3RlciBwcm9ncmFtIGVucmljaG1lbnQgey50YWJzZXR9CmBgYHtyfQp0b3Bfb3QgPSBwYXRpZW50c19nZXBzW29yZGVyKHBhdGllbnRzX2dlcHNbLDFdLGRlY3JlYXNpbmcgPSBUKSwyLGRyb3AgPSBGXSU+JSBoZWFkKDEwKSAlPiUgcm93bmFtZXMoKQoKY2hvc2VuX2dlbmVzID0gdG9wX290CiBzY29yZXNBbmRJbmRpY2VzIDwtIGdldFBhdGh3YXlTY29yZXMobHVuZ0Bhc3NheXMkUk5BQGRhdGEsIGNob3Nlbl9nZW5lcykKICBsdW5nPUFkZE1ldGFEYXRhKGx1bmcsc2NvcmVzQW5kSW5kaWNlcyRwYXRod2F5U2NvcmVzLCJpbW11bmVfZ2VwIikKCiAgCiAgCiAgY29yX3JlcyA9IGNvcihsdW5nJGludGVyZmVyb25fbGlrZSxsdW5nW1siaW1tdW5lX2dlcCJdXSkKcHJpbnQocGFzdGUoImNvcnJlbGF0aW9uIG9mIFRORmEgcHJvZ3JhbSB0byIsICJpbW11bmVfZ2VwIiwiOiIsIGNvcl9yZXMpKQpgYGAKYGBge3J9Cm1ldGFnZW5lc19tZWFuX2NvbXBhcmUoZGF0YXNldCA9IGx1bmcsdGltZS5wb2ludF92YXIgPSAidGltZS5wb2ludCIscHJlZml4ID0gInBhdGllbnQiLHBhdGllbnQuaWRlbnRfdmFyID0gInBhdGllbnQuaWRlbnQiLHByZV9vbiA9IGMoInByZS10cmVhdG1lbnQiLCJvbi10cmVhdG1lbnQiKSx0ZXN0ID0gIndpbGNveC50ZXN0Iixwcm9ncmFtcyA9ICJpbW11bmVfZ2VwIix3aXRob3V0X3NwbGl0ID0gRikKYGBgCgpgYGB7cn0KbXVsdCA9IGFzLm1hdHJpeCh0KGdlcF9zY29yZXNbLDEsZHJvcD1GXSkpICUqJSAobHVuZ0Bhc3NheXMkUk5BQGRhdGFbcm93bmFtZXMoZ2VwX3Njb3JlcyksXSAlPiUgYXMubWF0cml4KCkpCm5hbWVzKG11bHQpID0gY29sbmFtZXMobHVuZykKbXVsdCA9IGFzLmRhdGEuZnJhbWUodChtdWx0KSkKIGx1bmc9QWRkTWV0YURhdGEobHVuZyxtdWx0LCJpbW11bmVfZ2VwX211bHQiKQogIGNvcl9yZXMgPSBjb3IobHVuZyRpbnRlcmZlcm9uX2xpa2UsbHVuZ1tbImltbXVuZV9nZXBfbXVsdCJdXSkKcHJpbnQocGFzdGUoImNvcnJlbGF0aW9uIG9mIFRORmEgcHJvZ3JhbSB0byIsICJpbW11bmVfZ2VwX211bHQiLCI6IiwgY29yX3JlcykpCmBgYApgYGB7cn0KbWV0YWdlbmVzX21lYW5fY29tcGFyZShkYXRhc2V0ID0gbHVuZyx0aW1lLnBvaW50X3ZhciA9ICJ0aW1lLnBvaW50IixwcmVmaXggPSAicGF0aWVudCIscGF0aWVudC5pZGVudF92YXIgPSAicGF0aWVudC5pZGVudCIscHJlX29uID0gYygicHJlLXRyZWF0bWVudCIsIm9uLXRyZWF0bWVudCIpLHRlc3QgPSAid2lsY294LnRlc3QiLHByb2dyYW1zID0gImltbXVuZV9nZXBfbXVsdCIsd2l0aG91dF9zcGxpdCA9IEYpCmBgYApgYGB7ciBlY2hvPVRSVUUsIHJlc3VsdHM9J2FzaXMnfQojIGdldCBleHByZXNzaW9uIHdpdGggZ2VuZXMgaW4gY25tZiBpbnB1dApsdW5nID0gRmluZFZhcmlhYmxlRmVhdHVyZXMob2JqZWN0ID0gbHVuZyxuZmVhdHVyZXMgPSAyMDAwKQpnZW5lcyA9IHJvd25hbWVzKGx1bmcpW3Jvd25hbWVzKGx1bmcpICVpbiUgVmFyaWFibGVGZWF0dXJlcyhvYmplY3QgPSB4ZW5vKVsxOjIwMDBdXQoKbHVuZ19leHByZXNzaW9uID0gdChhcy5tYXRyaXgoR2V0QXNzYXlEYXRhKGx1bmcsc2xvdD0nZGF0YScpKSkgCmx1bmdfZXhwcmVzc2lvbiA9IDIqKmx1bmdfZXhwcmVzc2lvbiAjY29udmVydCBmcm9tIGxvZzIodHBtKzEpIHRvIHRwbQpsdW5nX2V4cHJlc3Npb24gPSBsdW5nX2V4cHJlc3Npb24tMQpsdW5nX2V4cHJlc3Npb24gPSBsdW5nX2V4cHJlc3Npb25bLGdlbmVzXSAlPiUgYXMuZGF0YS5mcmFtZSgpCgphbGxfMF9nZW5lcyA9IGNvbG5hbWVzKGx1bmdfZXhwcmVzc2lvbilbY29sU3VtcyhsdW5nX2V4cHJlc3Npb249PTAsIG5hLnJtPVRSVUUpPT1ucm93KGx1bmdfZXhwcmVzc2lvbildICNkZWxldGUgcm93cyB0aGF0IGhhdmUgYWxsIDAKZ2VuZXMgPSBnZW5lc1shZ2VuZXMgJWluJSBhbGxfMF9nZW5lc10KbHVuZ19leHByZXNzaW9uID0gbHVuZ19leHByZXNzaW9uWywhY29sbmFtZXMobHVuZ19leHByZXNzaW9uKSAlaW4lIGFsbF8wX2dlbmVzXQpnYyh2ZXJib3NlID0gRikKYGBgCgpgYGB7cHl0aG9ufQoKbHVuZ19leHByZXNzaW9uID0gci5sdW5nX2V4cHJlc3Npb24KZ2VuZXMgPSByLmdlbmVzCiMgZ2VwX3Njb3JlcyA9IHIucGF0aWVudHNfZ2Vwcwp1c2FnZV9ieV9jYWxjID0gZ2V0X3VzYWdlX2Zyb21fc2NvcmUoY291bnRzPWx1bmdfZXhwcmVzc2lvbix0cG09bHVuZ19leHByZXNzaW9uLGdlbmVzPWdlbmVzLGNubWZfb2JqPWNubWZfb2JqLGs9OCxzdW1UbzE9RmFsc2UpCmBgYAoKCmBgYHtyfQp1c2FnZV9ieV9jYWxjID0gcHkkdXNhZ2VfYnlfY2FsYwpncm91cHNfbGlzdCA9IGMoNCwzLDYpCnVzYWdlX2J5X2NhbGMgPSB1bmlvbl9wcm9ncmFtcyhncm91cHNfbGlzdCA9IGdyb3Vwc19saXN0LGFsbF9tZXRhZ2VuZXMgPSB1c2FnZV9ieV9jYWxjKQojIHVzYWdlX2J5X2NhbGMgPSBhcHBseSh1c2FnZV9ieV9jYWxjLCBNQVJHSU4gPSAxLCBzdW1fMl9vbmUpICU+JSB0KCkgJT4lIGFzLmRhdGEuZnJhbWUoKQp1c2FnZV9ieV9jYWxjID11c2FnZV9ieV9jYWxjICU+JSByZW5hbWUoY2VsbF9jeWNsZSA9IGdlcDQuMy42LCBoeXBveGlhX2xpa2UgPSBnZXAyLCBpbnRlcmZlcm9uX2xpa2UgPSBnZXAxLCBUTkZhID0gIGdlcDUsIElORjIgPSBnZXA3KQpgYGAKCmBgYHtyfQpsdW5nPUFkZE1ldGFEYXRhKGx1bmcsdXNhZ2VfYnlfY2FsY1ssMSxkcm9wPUZdLCJpbW11bmVfZ2VwX25vX3N1bTJvbmUiKQptZXRhZ2VuZXNfbWVhbl9jb21wYXJlKGRhdGFzZXQgPSBsdW5nLHRpbWUucG9pbnRfdmFyID0gInRpbWUucG9pbnQiLHByZWZpeCA9ICJwYXRpZW50IixwYXRpZW50LmlkZW50X3ZhciA9ICJwYXRpZW50LmlkZW50IixwcmVfb24gPSBjKCJwcmUtdHJlYXRtZW50Iiwib24tdHJlYXRtZW50IiksdGVzdCA9ICJ3aWxjb3gudGVzdCIscHJvZ3JhbXMgPSAiaW1tdW5lX2dlcF9ub19zdW0yb25lIix3aXRob3V0X3NwbGl0ID0gRikKYGBgCgo=