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")

Metagenes on ACC

# 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)
  acc_cancerCells_noACC1 = AddMetaData(object = acc_cancerCells_noACC1,metadata = metage_metadata)
}

print_tab(plt = 
            FeaturePlot(object = acc_cancerCells_noACC1,features = colnames(all_metagenes),max.cutoff = 100)
          ,title = "metagenes expression")

metagenes expression

all_metagenes= scale(all_metagenes) %>% as.data.frame()
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)
  acc_cancerCells_noACC1 = AddMetaData(object = acc_cancerCells_noACC1,metadata = metage_metadata)
}

print_tab(plt = 
            FeaturePlot(object = acc_cancerCells_noACC1,features = colnames(all_metagenes),max.cutoff = 100)
          ,title = "metagenes z-score expression")

metagenes z-score expression

NA

Assign to programs by z-scored metagenes

acc_cancerCells_noACC1 = program_assignment(dataset = acc_cancerCells_noACC1,larger_by = 2,program_names = colnames(all_metagenes))

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

metagenes by lum_over_myo

acc_cancerCells_noACC1 = subset(acc_cancerCells_noACC1,subset = patient.ident!= "ACC1")

lumScore_vs_program = FetchData(object = acc_cancerCells_noACC1,vars = c("lum_over_myo","program.assignment"))
lumScore_vs_program$program.assignment <- factor(lumScore_vs_program$program.assignment, levels = c("metagene.1","metagene.2","metagene.4"))

lumScore_vs_program = lumScore_vs_program %>% dplyr::filter(program.assignment %in% c("metagene.1","metagene.2","metagene.4"))
ggboxplot(lumScore_vs_program, x = "program.assignment", y = "lum_over_myo",
          palette = "jco",
          add = "jitter")+ stat_compare_means(method = "wilcox.test",comparisons = list(c("metagene.1","metagene.2"),c("metagene.2","metagene.4")))

Metagenes correlation with myo score

for (metagene in c("metagene.1","metagene.2","metagene.4")) {
   lum_score_vs_programScore = FetchData(object = acc_cancerCells_noACC1,vars = c(metagene,"myo_score"))
  print_tab(plt = 
    ggscatter(lum_score_vs_programScore, x = metagene, y = "myo_score", 
            add = "reg.line", conf.int = TRUE, 
            cor.coef = TRUE, cor.method = "pearson")
  ,title = metagene)
}

metagene.1

geom_smooth() using formula ‘y ~ x’

metagene.2

geom_smooth() using formula ‘y ~ x’

metagene.4

geom_smooth() using formula ‘y ~ x’

NA

NA

Metagenes correlation with lum score

for (metagene in c("metagene.1","metagene.2","metagene.4")) {
   lum_score_vs_programScore = FetchData(object = acc_cancerCells_noACC1,vars = c(metagene,"lum_score"))
  print_tab(plt = 
    ggscatter(lum_score_vs_programScore, x = metagene, y = "lum_score", 
            add = "reg.line", conf.int = TRUE, 
            cor.coef = TRUE, cor.method = "pearson")
  ,title = metagene)
}

metagene.1

geom_smooth() using formula ‘y ~ x’

metagene.2

geom_smooth() using formula ‘y ~ x’

metagene.4

geom_smooth() using formula ‘y ~ x’

NA

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)
}

metagene.1

geom_smooth() using formula ‘y ~ x’

metagene.2

geom_smooth() using formula ‘y ~ x’

metagene.4

geom_smooth() using formula ‘y ~ x’

NA

NA

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)
}

metagene.1

geom_smooth() using formula ‘y ~ x’

metagene.2

geom_smooth() using formula ‘y ~ x’

metagene.4

geom_smooth() using formula ‘y ~ x’

NA

NA
LS0tCnRpdGxlOiAnYHIgcnN0dWRpb2FwaTo6Z2V0U291cmNlRWRpdG9yQ29udGV4dCgpJHBhdGggJT4lIGJhc2VuYW1lKCkgJT4lIGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLHJlcGxhY2VtZW50ID0gIiIpYCcgCmF1dGhvcjogIkF2aXNoYWkgV2l6ZWwiCmRhdGU6ICdgciBTeXMuRGF0ZSgpYCcKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdG9jOiB5ZXMKICAgIHRvY19jb2xsYXBzZTogeWVzCiAgICB0b2NfZmxvYXQ6IAogICAgICBjb2xsYXBzZWQ6IEZBTFNFCi0tLQoKCmBgYHtyfQphbGxfYWNjX2NhbmNlcl9jZWxscyA9IHJlYWRSRFMoIi4vRGF0YS9hY2NfY2FuY2VyX2NlbGxzX1YzLlJEUyIpCmFjY19jYW5jZXJDZWxsc19ub0FDQzEgPSBzdWJzZXQoYWxsX2FjY19jYW5jZXJfY2VsbHMsc3Vic2V0ID0gcGF0aWVudC5pZGVudCE9ICJBQ0MxIikKCmBgYAoKYGBge3J9CiAgb3JpZ2luYWxfbXlvX2dlbmVzID0gYygiVFA2MyIsICJUUDczIiwgIkNBVjEiLCAiQ0RIMyIsICJLUlQ1IiwgIktSVDE0IiwgIkFDVEEyIiwgIlRBR0xOIiwgIk1ZTEsiLCAiREtLMyIpCiAgb3JpZ2luYWxfbHVtX2dlbmVzID0gYygiS0lUIiwgIkVIRiIsICJFTEY1IiwgIktSVDciLCAiQ0xETjMiLCAiQ0xETjQiLCAiQ0QyNCIsICJMR0FMUzMiLCAiTENOMiIsICJTTFBJIikKICBub3RjaF90YXJnZXRzX2dlbmVzID0gYygiTlJBUlAiLCAiTk9UQ0gzIiwgIkhFUzQiLCAiSEVZMSIsICJIRVkyIikKICBub3RjaF9saWdhbmRzID0gYygiRExMMSIsICJKQUcxIiwgIkpBRzIiLCAiSEVZMSIpCgogIG9yaWdfbXlvc2NvcmU9YXBwbHkoYWNjX2NhbmNlckNlbGxzX25vQUNDMUBhc3NheXNbWyJSTkEiXV1bb3JpZ2luYWxfbXlvX2dlbmVzLF0sMixtZWFuKQogIG9yaWdfbGVzY29yZT1hcHBseShhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxQGFzc2F5c1tbIlJOQSJdXVtvcmlnaW5hbF9sdW1fZ2VuZXMsXSwyLG1lYW4pCiAgbm90Y2hfc2NvcmU9YXBwbHkoYWNjX2NhbmNlckNlbGxzX25vQUNDMUBhc3NheXNbWyJSTkEiXV1bbm90Y2hfdGFyZ2V0c19nZW5lcyxdLDIsbWVhbikKICBub3RjaF9saWdhbmRzX3Njb3JlPWFwcGx5KGFjY19jYW5jZXJDZWxsc19ub0FDQzFAYXNzYXlzW1siUk5BIl1dW25vdGNoX2xpZ2FuZHMsXSwyLG1lYW4pCgogIGFjY19jYW5jZXJDZWxsc19ub0FDQzEgPSBBZGRNZXRhRGF0YShvYmplY3QgPSBhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxLG1ldGFkYXRhID0gb3JpZ19sZXNjb3JlLW9yaWdfbXlvc2NvcmUsY29sLm5hbWUgPSAibHVtX292ZXJfbXlvIikKICAgIGFjY19jYW5jZXJDZWxsc19ub0FDQzEgPSBBZGRNZXRhRGF0YShvYmplY3QgPSBhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxLG1ldGFkYXRhID0gb3JpZ19teW9zY29yZSxjb2wubmFtZSA9ICJteW9fc2NvcmUiKQogICAgYWNjX2NhbmNlckNlbGxzX25vQUNDMSA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IGFjY19jYW5jZXJDZWxsc19ub0FDQzEsbWV0YWRhdGEgPSBvcmlnX2xlc2NvcmUsY29sLm5hbWUgPSAibHVtX3Njb3JlIikKICAgIGFjY19jYW5jZXJDZWxsc19ub0FDQzEgPSBBZGRNZXRhRGF0YShvYmplY3QgPSBhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxLG1ldGFkYXRhID0gbm90Y2hfc2NvcmUsY29sLm5hbWUgPSAibm90Y2hfc2NvcmUiKQogICAgCiAgYWNjX2NhbmNlckNlbGxzX25vQUNDMSA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IGFjY19jYW5jZXJDZWxsc19ub0FDQzEsbWV0YWRhdGEgPSBub3RjaF9saWdhbmRzX3Njb3JlLGNvbC5uYW1lID0gIm5vdGNoX2xpZ2FuZHNfc2NvcmVfc2NvcmUiKQoKCmBgYAojIyBMb2FkIG9iamVjdApgYGB7cHl0aG9ufQpmcm9tIGNubWYgaW1wb3J0IGNOTUYKaW1wb3J0IHBpY2tsZQpuZmVhdHVyZXMgPSAiMksiCmYgPSBvcGVuKCcuL0RhdGEvY05NRi9ITVNDX2NOTUZfJyArIG5mZWF0dXJlcysgJ3ZhcmdlbmVzL2NubWZfb2JqLnBja2wnLCAncmInKQpjbm1mX29iaiA9IHBpY2tsZS5sb2FkKGYpCmYuY2xvc2UoKQpgYGAKCmBgYHtweXRob259CnNlbGVjdGVkX2sgPSA0CmRlbnNpdHlfdGhyZXNob2xkID0gMC4xCmNubWZfb2JqLmNvbnNlbnN1cyhrPXNlbGVjdGVkX2ssIGRlbnNpdHlfdGhyZXNob2xkPWRlbnNpdHlfdGhyZXNob2xkLHNob3dfY2x1c3RlcmluZz1UcnVlKQp1c2FnZV9ub3JtLCBnZXBfc2NvcmVzLCBnZXBfdHBtLCB0b3BnZW5lcyA9IGNubWZfb2JqLmxvYWRfcmVzdWx0cyhLPXNlbGVjdGVkX2ssIGRlbnNpdHlfdGhyZXNob2xkPWRlbnNpdHlfdGhyZXNob2xkKQpgYGAKCmBgYHtyfQpnZXBfc2NvcmVzID0gcHkkZ2VwX3Njb3JlcwpnZXBfdHBtID0gcHkkZ2VwX3RwbQphbGxfbWV0YWdlbmVzPSBweSR1c2FnZV9ub3JtCmBgYAoKCgpgYGB7cHl0aG9ufQpkZWYgZ2V0X25vcm1fY291bnRzKGNvdW50cywgdHBtLGhpZ2hfdmFyaWFuY2VfZ2VuZXNfZmlsdGVyKTogI2Zyb20gY25tZi5weQogICAgaW1wb3J0IG51bXB5IGFzIG5wCiAgICBpbXBvcnQgc2NpcHkuc3BhcnNlIGFzIHNwCiAgICAjIyBTdWJzZXQgb3V0IGhpZ2gtdmFyaWFuY2UgZ2VuZXMKICAgIG5vcm1fY291bnRzID0gY291bnRzWzosIGhpZ2hfdmFyaWFuY2VfZ2VuZXNfZmlsdGVyXS5jb3B5KCkKICAKICAgICMjIFNjYWxlIGdlbmVzIHRvIHVuaXQgdmFyaWFuY2UKICAgIGlmIHNwLmlzc3BhcnNlKHRwbS5YKToKICAgICAgICBzYy5wcC5zY2FsZShub3JtX2NvdW50cywgemVyb19jZW50ZXI9RmFsc2UpCiAgICAgICAgaWYgbnAuaXNuYW4obm9ybV9jb3VudHMuWC5kYXRhKS5zdW0oKSA+IDA6CiAgICAgICAgICAgIHByaW50KCdXYXJuaW5nIE5hTnMgaW4gbm9ybWFsaXplZCBjb3VudHMgbWF0cml4JykgICAgICAgICAgICAgICAgICAgICAgIAogICAgZWxzZToKICAgICAgICBub3JtX2NvdW50cy5YIC89IG5vcm1fY291bnRzLlguc3RkKGF4aXM9MCwgZGRvZj0xKQogICAgICAgIGlmIG5wLmlzbmFuKG5vcm1fY291bnRzLlgpLnN1bSgpLnN1bSgpID4gMDoKICAgICAgICAgICAgcHJpbnQoJ1dhcm5pbmcgTmFOcyBpbiBub3JtYWxpemVkIGNvdW50cyBtYXRyaXgnKSAgICAgICAgICAgICAgICAgICAgCiAgICAKICAKICAgICMjIENoZWNrIGZvciBhbnkgY2VsbHMgdGhhdCBoYXZlIDAgY291bnRzIG9mIHRoZSBvdmVyZGlzcGVyc2VkIGdlbmVzCiAgICB6ZXJvY2VsbHMgPSBub3JtX2NvdW50cy5YLnN1bShheGlzPTEpPT0wCiAgICBpZiB6ZXJvY2VsbHMuc3VtKCk+MDoKICAgICAgICBleGFtcGxlcyA9IG5vcm1fY291bnRzLm9icy5pbmRleFt6ZXJvY2VsbHNdCiAgICAgICAgcHJpbnQoJ1dhcm5pbmc6ICVkIGNlbGxzIGhhdmUgemVybyBjb3VudHMgb2Ygb3ZlcmRpc3BlcnNlZCBnZW5lcy4gRS5nLiAlcycgJSAoemVyb2NlbGxzLnN1bSgpLCBleGFtcGxlc1swXSkpCiAgICAgICAgcHJpbnQoJ0NvbnNlbnN1cyBzdGVwIG1heSBub3QgcnVuIHdoZW4gdGhpcyBpcyB0aGUgY2FzZScpCiAgICAKICAgIHJldHVybihub3JtX2NvdW50cykKICAKZGVmIGdldF91c2FnZV9mcm9tX3Njb3JlKGNvdW50cyx0cG0sIGdlbmVzLGNubWZfb2JqKToKICAgICAgaW1wb3J0IGFubmRhdGEgYXMgYWQKICAgICAgaW1wb3J0IHNjYW5weSBhcyBzYwogICAgICBpbXBvcnQgbnVtcHkgYXMgbnAKICAgICAgZnJvbSBza2xlYXJuLmRlY29tcG9zaXRpb24gaW1wb3J0IG5vbl9uZWdhdGl2ZV9mYWN0b3JpemF0aW9uCiAgICAgIGltcG9ydCBwYW5kYXMgYXMgcGQKICAgICAgY291bnRzX2FkYXRhID0gYWQuQW5uRGF0YShjb3VudHMpCiAgICAgIHRwbV9hZGF0YSA9IGFkLkFubkRhdGEodHBtKQogICAgICBub3JtX2NvdW50cyA9IGdldF9ub3JtX2NvdW50cyhjb3VudHM9Y291bnRzX2FkYXRhLHRwbT10cG1fYWRhdGEsaGlnaF92YXJpYW5jZV9nZW5lc19maWx0ZXI9bnAuYXJyYXkoZ2VuZXMpKSAjbm9ybSBjb3VudHMgYXMgY25tZgogICAgICBzcGVjdHJhID0gY25tZl9vYmouZ2V0X21lZGlhbl9zcGVjdHJhKGs9NCkgI2dldCBzY29yZSAKICAgICAgc3BlY3RyYSA9IHNwZWN0cmFbc3BlY3RyYS5jb2x1bW5zLmludGVyc2VjdGlvbihnZW5lcyldICNyZW1vdmUgZ2VuZXMgbm90IGluIEBnZW5lcwogICAgICB1c2FnZV9ieV9jYWxjLF8sXyA9IG5vbl9uZWdhdGl2ZV9mYWN0b3JpemF0aW9uKFg9bm9ybV9jb3VudHMuWCwgSCA9IHNwZWN0cmEudmFsdWVzLCB1cGRhdGVfSD1GYWxzZSxuX2NvbXBvbmVudHMgPSA0LG1heF9pdGVyPTEwMDAsaW5pdCA9InJhbmRvbSIpCiAgICAgIHVzYWdlX2J5X2NhbGMgPSBwZC5EYXRhRnJhbWUodXNhZ2VfYnlfY2FsYywgaW5kZXg9Y291bnRzLmluZGV4LCBjb2x1bW5zPXNwZWN0cmEuaW5kZXgpICNpbnNlcnQgdG8gZGYrYWRkIG5hbWVzCiAgICAgIHVzYWdlX2J5X2NhbGMgPSB1c2FnZV9ieV9jYWxjLmRpdih1c2FnZV9ieV9jYWxjLnN1bShheGlzPTEpLCBheGlzPTApICMgc3VtIHJvd3MgdG8gMSAKICAgICAgcmV0dXJuKHVzYWdlX2J5X2NhbGMpCgpgYGAKIyBHZXQgZXhwcmVzc2lvbgpgYGB7cn0KbmZlYXR1cmVzID0gMjAwMAphY2MxX2NhbmNlcl9jZWxscyA9IEZpbmRWYXJpYWJsZUZlYXR1cmVzKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLG5mZWF0dXJlcyA9IG5mZWF0dXJlcykKdmFyZ2VuZXMgPSBWYXJpYWJsZUZlYXR1cmVzKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzKQpobXNjX2V4cHJlc3Npb24gPSB0KGFzLm1hdHJpeChHZXRBc3NheURhdGEoYWNjMV9jYW5jZXJfY2VsbHMsc2xvdD0nZGF0YScpKSkKaG1zY19leHByZXNzaW9uID0gMioqaG1zY19leHByZXNzaW9uICNjb252ZXJ0IGZyb20gbG9nMih0cG0rMSkgdG8gdHBtCmhtc2NfZXhwcmVzc2lvbiA9IGhtc2NfZXhwcmVzc2lvbi0xCmhtc2NfZXhwcmVzc2lvbiA9IGhtc2NfZXhwcmVzc2lvblssIWNvbFN1bXMoaG1zY19leHByZXNzaW9uPT0wLCBuYS5ybT1UUlVFKT09bnJvdyhobXNjX2V4cHJlc3Npb24pXSAjZGVsZXRlIHJvd3MgdGhhdCBoYXZlIGFsbCAwCmhtc2NfZXhwcmVzc2lvbiA9IGhtc2NfZXhwcmVzc2lvblssdmFyZ2VuZXNdCmhtc2NfZXhwcmVzc2lvbiA9IGhtc2NfZXhwcmVzc2lvbiAgJT4lIGFzLmRhdGEuZnJhbWUoKQoKCmBgYAoKIyBDYWxjdWxhdGUgdXNhZ2UKYGBge3B5dGhvbn0KaG1zY19leHByZXNzaW9uID0gci5obXNjX2V4cHJlc3Npb24KdmFyZ2VuZXMgPSByLnZhcmdlbmVzCnVzYWdlX2J5X2NhbGMgPSBnZXRfdXNhZ2VfZnJvbV9zY29yZShjb3VudHM9aG1zY19leHByZXNzaW9uLHRwbT1obXNjX2V4cHJlc3Npb24sZ2VuZXM9IHZhcmdlbmVzLGNubWZfb2JqPWNubWZfb2JqKQpgYGAKCmBgYHtyfQphbGxfbWV0YWdlbmVzPSBweSR1c2FnZV9ieV9jYWxjCmFsbF9tZXRhZ2VuZXMgPSBhbGxfbWV0YWdlbmVzWyxjKDEsNCwzLDIpXQoKYGBgCgoKIyBQcm9ncmFtcyBlbnJpY2htZW50cyB7LnRhYnNldH0KCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTgsIHJlc3VsdHM9J2FzaXMnfQojSGFsbG1hcmtzOgpwbHRfbGlzdCA9IGxpc3QoKQpmb3IgKGkgaW4gMTpuY29sKGdlcF9zY29yZXMpKSB7CiAgdG9wX2dlbmVzID0gZ2VwX3Njb3JlcyAgJT4lICBhcnJhbmdlKGRlc2MoZ2VwX3Njb3Jlc1tpXSkpICNzb3J0IGJ5IHNjb3JlIGEKICB0b3AgPSBoZWFkKHJvd25hbWVzKHRvcF9nZW5lcyksMjAwKSAjdGFrZSB0b3AgdG9wX2dlbmVzX251bQogIHJlcyA9IGdlbmVzX3ZlY19lbnJpY2htZW50KGdlbmVzID0gdG9wLGJhY2tncm91bmQgPSByb3duYW1lcyhnZXBfc2NvcmVzKSxob21lciA9IFQsdGl0bGUgPSAKICAgICAgICAgICAgICAgICAgICBpLHNpbGVudCA9IFQscmV0dXJuX2FsbCA9IFQpCiAgIAogIHBsdF9saXN0W1tpXV0gPSByZXMkcGx0Cn0KcCA9IGdnYXJyYW5nZShwbG90bGlzdCAgPSBwbHRfbGlzdCkKcHJpbnRfdGFiKHBsdCA9IHAsdGl0bGUgPSAiSEFMTE1BUksgZW5yaWNobWVudCIpCgojQ2Fub25pY2FsOgpjYW5vbmljYWxfcGF0aHdheXMgPSBtc2lnZGJyKHNwZWNpZXMgPSAiSG9tbyBzYXBpZW5zIiwgY2F0ZWdvcnkgPSAiQzIiKSAlPiUgZHBseXI6OmZpbHRlcihnc19zdWJjYXQgIT0gIkNHUCIpICU+JSAgZHBseXI6OmRpc3RpbmN0KGdzX25hbWUsIGdlbmVfc3ltYm9sKSAKCnBsdF9saXN0ID0gbGlzdCgpCmZvciAoaSBpbiAxOm5jb2woZ2VwX3Njb3JlcykpIHsKICB0b3BfZ2VuZXMgPSBnZXBfc2NvcmVzICAlPiUgIGFycmFuZ2UoZGVzYyhnZXBfc2NvcmVzW2ldKSkgI3NvcnQgYnkgc2NvcmUgYQogIHRvcCA9IGhlYWQocm93bmFtZXModG9wX2dlbmVzKSwyMDApICN0YWtlIHRvcCB0b3BfZ2VuZXNfbnVtCiAgcmVzID0gZ2VuZXNfdmVjX2VucmljaG1lbnQoZ2VuZXMgPSB0b3AsYmFja2dyb3VuZCA9IHJvd25hbWVzKGdlcF9zY29yZXMpLGhvbWVyID0gVCx0aXRsZSA9IAogICAgICAgICAgICAgICAgICAgIGksc2lsZW50ID0gVCxyZXR1cm5fYWxsID0gVCxjdXN0b21fcGF0aHdheXMgPSBjYW5vbmljYWxfcGF0aHdheXMpCiAgIAogIHBsdF9saXN0W1tpXV0gPSByZXMkcGx0Cn0KcCA9IGdnYXJyYW5nZShwbG90bGlzdCAgPSBwbHRfbGlzdCkKcHJpbnRfdGFiKHBsdCA9IHAsdGl0bGUgPSAiY2Fub25pY2FsIHBhdGh3YXkgZW5yaWNobWVudCIpCgoKCmBgYAojIyBsdW1pbmFsIGFuZCBteW8gZ2VuZXMgaW4gc2NvcmUKYGBge3IgcmVzdWx0cz0naG9sZCcsY29sbGFwc2U9VFJVRX0KIyBsdW0gZ2VuZXMgaW4gbWV0YWdlbmVzCm1lc3NhZ2UoImx1bSBnZW5lcyBpbiBtZXRhZ2VuZXM6IikKZm9yIChpIGluIDE6bmNvbChnZXBfc2NvcmVzKSkgewogIHRvcF9nZW5lcyA9IGdlcF9zY29yZXMgICU+JSAgYXJyYW5nZShkZXNjKGdlcF9zY29yZXNbaV0pKSAjc29ydCBieSBzY29yZSBhCiAgdG9wID0gaGVhZChyb3duYW1lcyh0b3BfZ2VuZXMpLDIwMCkgI3Rha2UgdG9wIHRvcF9nZW5lc19udW0KICBjYXQocGFzdGUwKCJtZXRhZ2VuZSAiLGksIjogIikpCiAgcHJpbnQob3JpZ2luYWxfbHVtX2dlbmVzW29yaWdpbmFsX2x1bV9nZW5lcyAlaW4lIHRvcF0pCgp9CmNhdCgiXG4iKQoKCiMgbXlvIGdlbmVzIGluIG1ldGFnZW5lcwptZXNzYWdlKCJteW8gZ2VuZXMgaW4gbWV0YWdlbmVzOiIpCmZvciAoaSBpbiAxOm5jb2woZ2VwX3Njb3JlcykpIHsKICB0b3BfZ2VuZXMgPSBnZXBfc2NvcmVzICAlPiUgIGFycmFuZ2UoZGVzYyhnZXBfc2NvcmVzW2ldKSkgI3NvcnQgYnkgc2NvcmUgYQogIHRvcCA9IGhlYWQocm93bmFtZXModG9wX2dlbmVzKSwyMDApICN0YWtlIHRvcCB0b3BfZ2VuZXNfbnVtCiAgY2F0KHBhc3RlMCgibWV0YWdlbmUgIixpLCI6ICIpKQogIHByaW50KG9yaWdpbmFsX215b19nZW5lc1tvcmlnaW5hbF9teW9fZ2VuZXMgJWluJSB0b3BdKQoKfQpjYXQoIlxuIikKCm5vdGNoX2dlbmVzID0gYygiSkFHMSIsIkpBRzIiLCJOT1RDSDMiLCJOT1RDSDIiLCJOT1RDSDEiLCJETEwxIiwiTVlCIiwiSEVTNCIsIkhFWTEiLCJIRVkyIiwiTlJBUlAiKQojIG5vdGNoIGdlbmVzIGluIG1ldGFnZW5lcwptZXNzYWdlKCJub3RjaCBnZW5lcyBpbiBtZXRhZ2VuZXM6IikKZm9yIChpIGluIDE6bmNvbChnZXBfc2NvcmVzKSkgewogIHRvcF9nZW5lcyA9IGdlcF9zY29yZXMgICU+JSAgYXJyYW5nZShkZXNjKGdlcF9zY29yZXNbaV0pKSAjc29ydCBieSBzY29yZSBhCiAgdG9wID0gaGVhZChyb3duYW1lcyh0b3BfZ2VuZXMpLDIwMCkgI3Rha2UgdG9wIHRvcF9nZW5lc19udW0KICBjYXQocGFzdGUwKCJtZXRhZ2VuZSAiLGksIjogIikpCiAgcHJpbnQobm90Y2hfZ2VuZXNbbm90Y2hfZ2VuZXMgJWluJSB0b3BdKQoKfQpjYXQoIlxuIikKYGBgCgoKCiMgTWV0YWdlbmVzIG9uIEFDQyAgey50YWJzZXR9CgpgYGB7ciBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTAsIHJlc3VsdHM9J2FzaXMnfQojIE1ha2UgbWV0YWdlbmUgbmFtZXMKZm9yIChpIGluIDE6bmNvbChhbGxfbWV0YWdlbmVzKSkgewogIGNvbG5hbWVzKGFsbF9tZXRhZ2VuZXMpW2ldID0gIm1ldGFnZW5lLiIgJT4lIHBhc3RlMChpKQp9CgoKI2FkZCBlYWNoIG1ldGFnZW5lIHRvIG1ldGFkYXRhCmZvciAoaSBpbiAxOm5jb2woYWxsX21ldGFnZW5lcykpIHsKICBtZXRhZ2VfbWV0YWRhdGEgPSBhbGxfbWV0YWdlbmVzICU+JSBzZWxlY3QoaSkKICBhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxID0gQWRkTWV0YURhdGEob2JqZWN0ID0gYWNjX2NhbmNlckNlbGxzX25vQUNDMSxtZXRhZGF0YSA9IG1ldGFnZV9tZXRhZGF0YSkKfQoKcHJpbnRfdGFiKHBsdCA9IAogICAgICAgICAgICBGZWF0dXJlUGxvdChvYmplY3QgPSBhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxLGZlYXR1cmVzID0gY29sbmFtZXMoYWxsX21ldGFnZW5lcyksbWF4LmN1dG9mZiA9IDEwMCkKICAgICAgICAgICx0aXRsZSA9ICJtZXRhZ2VuZXMgZXhwcmVzc2lvbiIpCgphbGxfbWV0YWdlbmVzPSBzY2FsZShhbGxfbWV0YWdlbmVzKSAlPiUgYXMuZGF0YS5mcmFtZSgpCmZvciAoaSBpbiAxOm5jb2woYWxsX21ldGFnZW5lcykpIHsKICBjb2xuYW1lcyhhbGxfbWV0YWdlbmVzKVtpXSA9ICJtZXRhZ2VuZS4iICU+JSBwYXN0ZTAoaSkKfQoKCiNhZGQgZWFjaCBtZXRhZ2VuZSB0byBtZXRhZGF0YQpmb3IgKGkgaW4gMTpuY29sKGFsbF9tZXRhZ2VuZXMpKSB7CiAgbWV0YWdlX21ldGFkYXRhID0gYWxsX21ldGFnZW5lcyAlPiUgc2VsZWN0KGkpCiAgYWNjX2NhbmNlckNlbGxzX25vQUNDMSA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IGFjY19jYW5jZXJDZWxsc19ub0FDQzEsbWV0YWRhdGEgPSBtZXRhZ2VfbWV0YWRhdGEpCn0KCnByaW50X3RhYihwbHQgPSAKICAgICAgICAgICAgRmVhdHVyZVBsb3Qob2JqZWN0ID0gYWNjX2NhbmNlckNlbGxzX25vQUNDMSxmZWF0dXJlcyA9IGNvbG5hbWVzKGFsbF9tZXRhZ2VuZXMpLG1heC5jdXRvZmYgPSAxMDApCiAgICAgICAgICAsdGl0bGUgPSAibWV0YWdlbmVzIHotc2NvcmUgZXhwcmVzc2lvbiIpCgpgYGAKCiMgQXNzaWduIHRvIHByb2dyYW1zIGJ5IHotc2NvcmVkIG1ldGFnZW5lcwpgYGB7cn0KYWNjX2NhbmNlckNlbGxzX25vQUNDMSA9IHByb2dyYW1fYXNzaWdubWVudChkYXRhc2V0ID0gYWNjX2NhbmNlckNlbGxzX25vQUNDMSxsYXJnZXJfYnkgPSAyLHByb2dyYW1fbmFtZXMgPSBjb2xuYW1lcyhhbGxfbWV0YWdlbmVzKSkKYGBgCgoKCiMgVU1BUFMgey50YWJzZXR9CgpgYGB7ciBlY2hvPVRSVUUsIHJlc3VsdHM9J2FzaXMnfQpjb2xvcnMgPSAgcmFpbmJvdyhhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxJHByb2dyYW0uYXNzaWdubWVudCAlPiUgdW5pcXVlKCkgJT4lIGxlbmd0aCgpLTEpCmNvbG9ycyA9IGMoY29sb3JzLCJncmV5IikKcHJpbnRfdGFiKHBsdCA9IERpbVBsb3Qob2JqZWN0ID0gYWNjX2NhbmNlckNlbGxzX25vQUNDMSxncm91cC5ieSA9ICJwcm9ncmFtLmFzc2lnbm1lbnQiLGNvbHMgPWNvbG9ycyksdGl0bGUgPSAicHJvZ3JhbS5hc3NpZ25tZW50IikKcHJpbnRfdGFiKHBsdCA9IERpbVBsb3Qob2JqZWN0ID0gYWNjX2NhbmNlckNlbGxzX25vQUNDMSxncm91cC5ieSA9ICJwYXRpZW50LmlkZW50IiksdGl0bGUgPSAicGF0aWVudC5pZGVudCIpCgpwcmludF90YWIocGx0ID0gRmVhdHVyZVBsb3Qob2JqZWN0ID0gYWNjX2NhbmNlckNlbGxzX25vQUNDMSxmZWF0dXJlcyA9ICJsdW1fc2NvcmUiKSx0aXRsZSA9ICJsdW1fc2NvcmUiKQoKcHJpbnRfdGFiKHBsdCA9IEZlYXR1cmVQbG90KG9iamVjdCA9IGFjY19jYW5jZXJDZWxsc19ub0FDQzEsZmVhdHVyZXMgPSAibXlvX3Njb3JlIiksdGl0bGUgPSAibXlvX3Njb3JlIikKCgoKYGBgCiMgbWV0YWdlbmVzIGJ5IGx1bV9vdmVyX215bwpgYGB7cn0KYWNjX2NhbmNlckNlbGxzX25vQUNDMSA9IHN1YnNldChhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxLHN1YnNldCA9IHBhdGllbnQuaWRlbnQhPSAiQUNDMSIpCgpsdW1TY29yZV92c19wcm9ncmFtID0gRmV0Y2hEYXRhKG9iamVjdCA9IGFjY19jYW5jZXJDZWxsc19ub0FDQzEsdmFycyA9IGMoImx1bV9vdmVyX215byIsInByb2dyYW0uYXNzaWdubWVudCIpKQpsdW1TY29yZV92c19wcm9ncmFtJHByb2dyYW0uYXNzaWdubWVudCA8LSBmYWN0b3IobHVtU2NvcmVfdnNfcHJvZ3JhbSRwcm9ncmFtLmFzc2lnbm1lbnQsIGxldmVscyA9IGMoIm1ldGFnZW5lLjEiLCJtZXRhZ2VuZS4yIiwibWV0YWdlbmUuNCIpKQoKbHVtU2NvcmVfdnNfcHJvZ3JhbSA9IGx1bVNjb3JlX3ZzX3Byb2dyYW0gJT4lIGRwbHlyOjpmaWx0ZXIocHJvZ3JhbS5hc3NpZ25tZW50ICVpbiUgYygibWV0YWdlbmUuMSIsIm1ldGFnZW5lLjIiLCJtZXRhZ2VuZS40IikpCmdnYm94cGxvdChsdW1TY29yZV92c19wcm9ncmFtLCB4ID0gInByb2dyYW0uYXNzaWdubWVudCIsIHkgPSAibHVtX292ZXJfbXlvIiwKICAgICAgICAgIHBhbGV0dGUgPSAiamNvIiwKICAgICAgICAgIGFkZCA9ICJqaXR0ZXIiKSsgc3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ3aWxjb3gudGVzdCIsY29tcGFyaXNvbnMgPSBsaXN0KGMoIm1ldGFnZW5lLjEiLCJtZXRhZ2VuZS4yIiksYygibWV0YWdlbmUuMiIsIm1ldGFnZW5lLjQiKSkpCmBgYAojIE1ldGFnZW5lcyBjb3JyZWxhdGlvbiB3aXRoIG15byBzY29yZSB7LnRhYnNldH0KCgoKYGBge3IgZWNobz1UUlVFLCByZXN1bHRzPSdhc2lzJ30KZm9yIChtZXRhZ2VuZSBpbiBjKCJtZXRhZ2VuZS4xIiwibWV0YWdlbmUuMiIsIm1ldGFnZW5lLjQiKSkgewogICBsdW1fc2NvcmVfdnNfcHJvZ3JhbVNjb3JlID0gRmV0Y2hEYXRhKG9iamVjdCA9IGFjY19jYW5jZXJDZWxsc19ub0FDQzEsdmFycyA9IGMobWV0YWdlbmUsIm15b19zY29yZSIpKQogIHByaW50X3RhYihwbHQgPSAKICAgIGdnc2NhdHRlcihsdW1fc2NvcmVfdnNfcHJvZ3JhbVNjb3JlLCB4ID0gbWV0YWdlbmUsIHkgPSAibXlvX3Njb3JlIiwgCiAgICAgICAgICAgIGFkZCA9ICJyZWcubGluZSIsIGNvbmYuaW50ID0gVFJVRSwgCiAgICAgICAgICAgIGNvci5jb2VmID0gVFJVRSwgY29yLm1ldGhvZCA9ICJwZWFyc29uIikKICAsdGl0bGUgPSBtZXRhZ2VuZSkKfQogCmBgYAoKCiMgTWV0YWdlbmVzIGNvcnJlbGF0aW9uIHdpdGggbHVtIHNjb3JlIHsudGFic2V0fQpgYGB7ciBlY2hvPVRSVUUsIHJlc3VsdHM9J2FzaXMnfQpmb3IgKG1ldGFnZW5lIGluIGMoIm1ldGFnZW5lLjEiLCJtZXRhZ2VuZS4yIiwibWV0YWdlbmUuNCIpKSB7CiAgIGx1bV9zY29yZV92c19wcm9ncmFtU2NvcmUgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjX2NhbmNlckNlbGxzX25vQUNDMSx2YXJzID0gYyhtZXRhZ2VuZSwibHVtX3Njb3JlIikpCiAgcHJpbnRfdGFiKHBsdCA9IAogICAgZ2dzY2F0dGVyKGx1bV9zY29yZV92c19wcm9ncmFtU2NvcmUsIHggPSBtZXRhZ2VuZSwgeSA9ICJsdW1fc2NvcmUiLCAKICAgICAgICAgICAgYWRkID0gInJlZy5saW5lIiwgY29uZi5pbnQgPSBUUlVFLCAKICAgICAgICAgICAgY29yLmNvZWYgPSBUUlVFLCBjb3IubWV0aG9kID0gInBlYXJzb24iKQogICx0aXRsZSA9IG1ldGFnZW5lKQp9CiAKYGBgCgoKCiMgTm90Y2ggc2NvcmUgey50YWJzZXR9CmBgYHtyIGVjaG89VFJVRSwgcmVzdWx0cz0nYXNpcyd9CmZvciAobWV0YWdlbmUgaW4gYygibWV0YWdlbmUuMSIsIm1ldGFnZW5lLjIiLCJtZXRhZ2VuZS40IikpIHsKICAgbHVtX3Njb3JlX3ZzX3Byb2dyYW1TY29yZSA9IEZldGNoRGF0YShvYmplY3QgPSBhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxLHZhcnMgPSBjKG1ldGFnZW5lLCJub3RjaF9zY29yZSIpKQogIHByaW50X3RhYihwbHQgPSAKICAgIGdnc2NhdHRlcihsdW1fc2NvcmVfdnNfcHJvZ3JhbVNjb3JlLCB4ID0gbWV0YWdlbmUsIHkgPSAibm90Y2hfc2NvcmUiLCAKICAgICAgICAgICAgYWRkID0gInJlZy5saW5lIiwgY29uZi5pbnQgPSBUUlVFLCAKICAgICAgICAgICAgY29yLmNvZWYgPSBUUlVFLCBjb3IubWV0aG9kID0gInBlYXJzb24iKQogICx0aXRsZSA9IG1ldGFnZW5lKQp9CiAKYGBgCgoKCiMgTm90Y2ggIGxpZ2FuZHMgc2NvcmUgey50YWJzZXR9CmBgYHtyIGVjaG89VFJVRSwgcmVzdWx0cz0nYXNpcyd9CmZvciAobWV0YWdlbmUgaW4gYygibWV0YWdlbmUuMSIsIm1ldGFnZW5lLjIiLCJtZXRhZ2VuZS40IikpIHsKICAgbHVtX3Njb3JlX3ZzX3Byb2dyYW1TY29yZSA9IEZldGNoRGF0YShvYmplY3QgPSBhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxLHZhcnMgPSBjKG1ldGFnZW5lLCJub3RjaF9saWdhbmRzX3Njb3JlX3Njb3JlIikpCiAgcHJpbnRfdGFiKHBsdCA9IAogICAgZ2dzY2F0dGVyKGx1bV9zY29yZV92c19wcm9ncmFtU2NvcmUsIHggPSBtZXRhZ2VuZSwgeSA9ICJub3RjaF9saWdhbmRzX3Njb3JlX3Njb3JlIiwgCiAgICAgICAgICAgIGFkZCA9ICJyZWcubGluZSIsIGNvbmYuaW50ID0gVFJVRSwgCiAgICAgICAgICAgIGNvci5jb2VmID0gVFJVRSwgY29yLm1ldGhvZCA9ICJwZWFyc29uIikKICAsdGl0bGUgPSBtZXRhZ2VuZSkKfQogCmBgYAoKCgoK