1 Functions


library(stringi)
library(reticulate)
source_from_github(repositoy = "DEG_functions",version = "0.2.24")
source_from_github(repositoy = "cNMF_functions",version = "0.3.91",script_name = "cnmf_function_Harmony.R")

no_neg <- function(x) {
  x = x + abs(min(x))
  x
}

sum_2_one <- function(x) {
  x =x/sum(x)
  x
}

2 Data

xeno = readRDS("./Data/10x_xeno_1000.Rds")
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)

3 Models 2K vargenes

import pickle
from cnmf import cNMF
f = open('./Data/cnmf/cnmf_objects/models_2Kvargenes_cnmf_obj.pckl', 'rb')
cnmf_obj = pickle.load(f)
f.close()

4 K selection plot

plot_path = paste0("/sci/labs/yotamd/lab_share/avishai.wizel/R_projects/EGFR/Data/cnmf/cNMF_models_Varnorm_Harmony_2Kvargenes/cNMF_models_Varnorm_Harmony_2Kvargenes.k_selection.png")
knitr::include_graphics(plot_path)

5 gep scores for all NMF k’s

density_threshold = 0.1
usage_norm3, gep_scores3, _, _ = cnmf_obj.load_results(K=3, density_threshold=density_threshold)
usage_norm4, gep_scores4, _, _ = cnmf_obj.load_results(K=4, density_threshold=density_threshold)
usage_norm5, gep_scores5, _, _ = cnmf_obj.load_results(K=5, density_threshold=density_threshold)
gep_scores3 = py$gep_scores3
gep_scores4 = py$gep_scores4
gep_scores5 = py$gep_scores5

usage_norm3 = py$usage_norm3
usage_norm4 = py$usage_norm4
usage_norm5 = py$usage_norm5
all_usage_norm = list(usage_norm3 = usage_norm3, usage_norm4 = usage_norm4, usage_norm5 = usage_norm5)
for (usage_num in seq_along(all_usage_norm)) {
  usage = all_usage_norm[[usage_num]]
  #add each metagene to metadata
  for (i in 1:ncol(usage)) {
    metage_metadata = usage %>% dplyr::select(i)
    xeno = AddMetaData(object = xeno,metadata = metage_metadata,col.name = paste0("gep",i))
  }
  if (usage_num==1) {
      print_tab(FeaturePlot(object = xeno,features = paste0("gep",1:ncol(usage)),ncol = 2),title = usage_num)

  }else{ print_tab(FeaturePlot(object = xeno,features = paste0("gep",1:ncol(usage)),ncol = 3),title = usage_num)}
}

1

2

3

NA

6 all NMF k’s enrichment


all_gep_scores =  list(gep_scores3 = gep_scores3, gep_scores4 = gep_scores4, gep_scores5 = gep_scores5)

genesets <- msigdb_download("Homo sapiens",category="H") %>% append( msigdb_download("Homo sapiens",category="C2",subcategory = "CP:KEGG"))
genesets[["HIF_targets"]] = hif_targets
genesets_env = gsets$new(genesets, name="my genesets", version="v1.0")

for (gep_num in seq_along(all_gep_scores)) {
  gep = all_gep_scores[[gep_num]]
  ranked_list = list()
  for (col in (gep)) {
   lst = col %>% setNames(rownames(gep)) %>% sort(decreasing = TRUE) 
   ranked_list  %<>% append(list(lst))
  }
  names(ranked_list) = paste0("gep",1:ncol(gep))
  
  
  
  hyp_obj <- hypeR(ranked_list, genesets_env, test="kstest", fdr=0.05, plotting=F,background = rownames(gep_scores3))
  print_tab(
    hyp_dots(hyp_obj,size_by = "significance",abrv = 100,merge = T)+
      scale_color_continuous(low = "red", high = "black", guide = guide_colorbar(reverse = TRUE))
    ,title = gep_num)
  
}

1

Scale for ‘colour’ is already present. Adding another scale for ‘colour’, which will replace the existing scale.

2

Scale for ‘colour’ is already present. Adding another scale for ‘colour’, which will replace the existing scale.

3

Scale for ‘colour’ is already present. Adding another scale for ‘colour’, which will replace the existing scale.

NA

7 programs enrichment

gep_scores = py$gep_scores3
usage_norm= py$usage_norm3
# or:
gep_scores = readRDS("/sci/labs/yotamd/lab_share/avishai.wizel/R_projects/EGFR/Data/cnmf/harmony_models_gep_scores.rds")
names (gep_scores) = c("Hypoxia","TNFa","Cell_cycle")
plt_list = list()

for (program  in names (gep_scores)) {
 p = ggplot(gep_scores, aes(x=!!ensym(program))) +
  geom_density()+xlab(program)+
   geom_vline(
    aes(xintercept=sort(gep_scores[,program],TRUE)[200]  ,color="top200"),
          linetype="dashed", size=1)+
   geom_vline(
    aes(xintercept=sort(gep_scores[,program],TRUE)[100]  ,color="top100"),
          linetype="dashed", size=1)+
      geom_vline(
    aes(xintercept=sort(gep_scores[,program],TRUE)[50]  ,color="top50"),
          linetype="dashed", size=1)+
         geom_vline(
    aes(xintercept=sort(gep_scores[,program],TRUE)[150]  ,color="top150"),
          linetype="dashed", size=1)+
   scale_color_manual(name = "top n genes", values = c(top200 = "blue",top100 = "red",top150 = "yellow",top50 = "green"))
   plt_list[[program]] <- p

}
 
ggarrange(plotlist = plt_list)

8 Programs hallmark enrichment

ntop = 150
plt_list = list()
hif_targets_set = data.frame(gs_name = "hif_targets",gene_symbol = hif_targets)

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),ntop) #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  = hif_targets_set)
   
  plt_list[[i]] = res$plt
}
gridExtra::grid.arrange(grobs = plt_list)

9 program 2 all cp

ntop = 150
i = 2 

  top_genes = gep_scores  %>%  arrange(desc(gep_scores[i])) #sort by score a
  top = head(rownames(top_genes),ntop) #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)
   
 print(res$plt) 

NA
NA

10 Program 2 all msigdb

ntop = 150
i = 2 

  top_genes = gep_scores  %>%  arrange(desc(gep_scores[i])) #sort by score a
  top = head(rownames(top_genes),ntop) #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  = all_pathways)
   
 print(res$plt) 
xeno = FindVariableFeatures(object = xeno,nfeatures = 2000)
xeno_vargenes = VariableFeatures(object = xeno)

xeno_expression = FetchData(object = xeno,vars = xeno_vargenes,slot='counts')
all_0_genes = colnames(xeno_expression)[colSums(xeno_expression==0, na.rm=TRUE)==nrow(xeno_expression)] #delete rows that have all 0
xeno_vargenes = xeno_vargenes[!xeno_vargenes %in% all_0_genes]

11 Test with expr after harmony

import numpy as np
import scanpy as sc

expr_after_harmony = sc.read_h5ad('./Data/cnmf/xeno_Harmony_NoNeg_2Kvargenes.h5ad').to_df()
tpm =  compute_tpm(expr_after_harmony)
cnmf_genes = expr_after_harmony.keys().to_list()
usage_by_calc = get_usage_from_score(counts=expr_after_harmony,tpm=tpm,genes=cnmf_genes,cnmf_obj=cnmf_obj,k=3)

12 Check if original cNMF score is like the calculated score

usage_by_calc = py$usage_by_calc
usage_norm = py$usage_norm3
cor(usage_by_calc,usage_norm)

13 calculate score for Xeno

import numpy as np
import scanpy as sc
xeno_expression = r.xeno_expression
xeno_vargenes = r.xeno_vargenes
tpm =  compute_tpm(xeno_expression)
usage_by_calc = get_usage_from_score(counts=xeno_expression,tpm=tpm,genes=xeno_vargenes, cnmf_obj=cnmf_obj,k=3)
/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.
xeno_usage = py$usage_by_calc

14 programs expression


names (xeno_usage) = c("Hypoxia","TNFa","Cell_cycle")
#add each metagene to metadata
for (i  in 1:ncol(xeno_usage)) {
  metage_metadata = xeno_usage %>% dplyr::select(i)
  xeno = AddMetaData(object = xeno,metadata = metage_metadata,col.name = names(xeno_usage)[i])
}

print_tab(plt = FeaturePlot(object = xeno,features = colnames(xeno_usage)),title = "umap expression")

umap expression

NA

15 programs regulation

metagenes_mean_compare(dataset = xeno,time.point_var = "treatment",prefix = "model",patient.ident_var = "orig.ident",pre_on = c("NT","OSI"),test = "wilcox.test",programs = c("Hypoxia","TNFa","Cell_cycle"))

Hypoxia per patient

Hypoxia

TNFa per patient

TNFa

Cell_cycle per patient

Cell_cycle

NA

DotPlot(object = xeno, features =  c("Hypoxia","TNFa","Cell_cycle"),group.by  = 'treatment')

16 CC signature

# get genes and plot cor heatmap

plot_genes_cor <- function(dataset,hallmark_name,num_of_clusters,geneIds = NULL) {
if(!is_null(geneIds)){
  geneIds = geneIds
}
else{
  geneIds= genesets[[hallmark_name]]@geneIds
}
hallmars_exp = FetchData(object = dataset,vars = c(geneIds))
hallmars_exp = hallmars_exp[,colSums(hallmars_exp[])>0] #remove no expression genes
hallmark_cor = cor(hallmars_exp)
pht1 = pheatmap(mat = hallmark_cor,silent = T)

# make annotations
num_of_clusters = num_of_clusters
clustering_distance = "euclidean"
myannotation = as.data.frame(cutree(pht1[["tree_row"]], k = num_of_clusters)) #split into k clusters
names(myannotation)[1] = "cluster"
myannotation$cluster = as.factor(myannotation$cluster)
palette1 <-brewer.pal(num_of_clusters, "Paired")
names(palette1) = unique(myannotation$cluster)
ann_colors = list (cluster = palette1)
annotation = list(ann_colors = ann_colors, myannotation = myannotation)

#choose colors
colors <- c(seq(-1,1,by=0.01))
my_palette <- c("blue",colorRampPalette(colors = c("blue", "white", "red"))
                                                 (n = length(colors)-3), "red")


print_tab(plt = 
              pheatmap(mat = hallmark_cor,annotation_col =  annotation[["myannotation"]], annotation_colors = annotation[["ann_colors"]], clustering_distance_rows = clustering_distance,clustering_distance_cols = clustering_distance,color = my_palette,breaks = colors,show_rownames = F,show_colnames = F)
            ,title = "genes expression heatmap")
return(annotation)

}
hallmark_name = "HALLMARK_G2M_CHECKPOINT"
annotation = plot_genes_cor(dataset = xeno,hallmark_name = hallmark_name,num_of_clusters = 4)

Warning in FetchData.Seurat(object = dataset, vars = c(geneIds)) : The following requested variables were not found: AC027237.1, AC091021.1, PTTG3P ## genes expression heatmap {.unnumbered }

NA

#choose clusters
chosen_clusters = c(1,2)
print (paste("chosen_clusters = ", chosen_clusters %>% toString()))

1 “chosen_clusters = 1, 2”

#UMAP expression of signature
chosen_genes = annotation[["myannotation"]] %>% dplyr::filter(cluster %in% chosen_clusters) %>% rownames() #take relevant genes
score <- apply(xeno@assays$RNA@data[chosen_genes,],2,mean)
xeno=AddMetaData(xeno,score,hallmark_name)
scoresAndIndices <- getPathwayScores(xeno@assays$RNA@data, chosen_genes)
xeno=AddMetaData(xeno,scoresAndIndices$pathwayScores,paste0(hallmark_name,"_sipsic"))
print_tab(FeaturePlot(object = xeno, features = paste0(hallmark_name,"_sipsic")),title = "Expression")

Expression

print_tab(FeaturePlot(object = xeno, features = hallmark_name),title = "Expression")

Expression

NA


#plot signature distribution
cc_scores = FetchData(object = xeno,vars = "HALLMARK_G2M_CHECKPOINT")
plt  =  ggplot(cc_scores, aes(x=HALLMARK_G2M_CHECKPOINT)) +
  geom_density()+
   geom_vline(
    aes(xintercept=mean(cc_scores$HALLMARK_G2M_CHECKPOINT) + sd(cc_scores$HALLMARK_G2M_CHECKPOINT) ,color="1 SD"),
          linetype="dashed", size=1)+
    geom_vline(
    aes(xintercept=mean(cc_scores$HALLMARK_G2M_CHECKPOINT) + 2*sd(cc_scores$HALLMARK_G2M_CHECKPOINT) ,color="2 SD"),
          linetype="dashed", size=1)

print_tab(plt = plt,title = "dist")

# Plot assignment 

cc_scores = cc_scores %>% mutate(is_cycling = if_else(condition = 
                                          HALLMARK_G2M_CHECKPOINT > mean(HALLMARK_G2M_CHECKPOINT) 
                                          +sd(HALLMARK_G2M_CHECKPOINT),
                                        true = "cycling",
                                        false = "non_cycling"))
xeno = AddMetaData(object = xeno,metadata = cc_scores$is_cycling,col.name = "is_cycling")
print_tab(plt = DimPlot(object = xeno,group.by = "is_cycling") , title = "assignment 1 sd")


# cc_scores = cc_scores %>% mutate(is_cycling = if_else(condition = 
#                                           HALLMARK_G2M_CHECKPOINT > mean(HALLMARK_G2M_CHECKPOINT) + 2*sd(cc_scores$HALLMARK_G2M_CHECKPOINT),
#                                         true = "cycling",
#                                         false = "non_cycling"))
# xeno = AddMetaData(object = xeno,metadata = cc_scores$is_cycling,col.name = "is_cycling")
# print_tab(plt = DimPlot(object = xeno,group.by = "is_cycling") , title = "assignment 2 sd")
 df  = FetchData(object = xeno,vars = c("is_cycling","treatment")) %>% 
    filter (treatment %in% c("NT","OSI")) %>% 
    droplevels() 
  test = fisher.test(table(df))
    
  library(ggstatsplot)

    plt = ggbarstats(
    df, is_cycling, treatment,
    results.subtitle = FALSE,
    subtitle = paste0(
      "Fisher's exact test", ", p-value = ",
       round(test$p.value,13))
    )
  
print_tab(plt = plt,title = "fisher")

16.1 correlation to nmf program

cor_res = cor(xeno$Cell_cycle,xeno[[hallmark_name]])
print(paste("correlation of TNFa program to", hallmark_name,":", cor_res))
[1] "correlation of TNFa program to HALLMARK_G2M_CHECKPOINT : 0.926264346933643"
cor_res = cor(xeno$Cell_cycle,xeno[[paste0(hallmark_name,"_sipsic")]])
print(paste("correlation of Cell_cycle program to", paste0(hallmark_name,"_sipsic"),":", cor_res))
[1] "correlation of Cell_cycle program to HALLMARK_G2M_CHECKPOINT_sipsic : 0.929443708586434"

17 TNFa signature

hallmark_name = "HALLMARK_TNFA_SIGNALING_VIA_NFKB"
annotation = plot_genes_cor(dataset = xeno,hallmark_name = hallmark_name,num_of_clusters = 6)

Warning in FetchData.Seurat(object = dataset, vars = c(geneIds)) : The following requested variables were not found: CCN1 ## genes expression heatmap {.unnumbered }

NA

chosen_clusters = c(1,5)
print (paste("chosen_clusters = ", chosen_clusters %>% toString()))

1 “chosen_clusters = 1, 5”

#UMAP expression of signature
chosen_genes = annotation[["myannotation"]] %>% dplyr::filter(cluster %in% chosen_clusters) %>% rownames() #take relevant genes
score <- apply(xeno@assays$RNA@data[chosen_genes,],2,mean)
xeno=AddMetaData(xeno,score,hallmark_name)
scoresAndIndices <- getPathwayScores(xeno@assays$RNA@data, chosen_genes)
xeno=AddMetaData(xeno,scoresAndIndices$pathwayScores,paste0(hallmark_name,"_sipsic"))
print_tab(FeaturePlot(object = xeno, features = paste0(hallmark_name,"_sipsic")),title = "Expression")

Expression

print_tab(FeaturePlot(object = xeno, features = hallmark_name),title = "Expression")

Expression

NA

17.1 correlation to nmf program

cor_res = cor(xeno$TNFa,xeno[[hallmark_name]])
print(paste("correlation of TNFa program to", hallmark_name,":", cor_res))
[1] "correlation of TNFa program to HALLMARK_TNFA_SIGNALING_VIA_NFKB : 0.471118461766633"
cor_res = cor(xeno$TNFa,xeno[[paste0(hallmark_name,"_sipsic")]])
print(paste("correlation of TNFa program to", paste0(hallmark_name,"_sipsic"),":", cor_res))
[1] "correlation of TNFa program to HALLMARK_TNFA_SIGNALING_VIA_NFKB_sipsic : 0.441336272152405"
cc_scores = FetchData(object = xeno,vars = hallmark_name)

plt  =  ggplot(cc_scores, aes(x=HALLMARK_TNFA_SIGNALING_VIA_NFKB)) +
  geom_density()+
   geom_vline(
    aes(xintercept=mean(HALLMARK_TNFA_SIGNALING_VIA_NFKB) + sd(HALLMARK_TNFA_SIGNALING_VIA_NFKB) ,color="1 SD"),
          linetype="dashed", size=1)+
    geom_vline(
    aes(xintercept=mean(HALLMARK_TNFA_SIGNALING_VIA_NFKB) + 2*sd(HALLMARK_TNFA_SIGNALING_VIA_NFKB) ,color="2 SD"),
          linetype="dashed", size=1)+
    geom_vline(
    aes(xintercept=mean(HALLMARK_TNFA_SIGNALING_VIA_NFKB) ,color="mean"),
          linetype="dashed", size=1)

print_tab(plt = plt,title = "dist")

18 weighted ks test

genesets <- msigdb_download("Homo sapiens",category="H") %>% append( msigdb_download("Homo sapiens",category="C2",subcategory = "CP:KEGG")) 
genesets[["HIF_targets"]] = hif_targets

genesets = gsets$new(genesets, name="my geneset", version="v1.0")
  
ranked_list1 = gep_scores %>% select(1) %>% as_vector() %>% setNames(rownames(gep_scores)) %>% sort(decreasing = TRUE) 
ranked_list2 = gep_scores %>% select(2) %>% as_vector() %>% setNames(rownames(gep_scores)) %>% sort(decreasing = TRUE) 
ranked_list3 = gep_scores %>% select(3) %>% as_vector() %>% setNames(rownames(gep_scores)) %>% sort(decreasing = TRUE) 



ranked_list = list("gep1" = ranked_list1, "gep2" = ranked_list2,"gep3" = ranked_list3)
hyp_obj <- hypeR(ranked_list, genesets, test="kstest", fdr=0.05, plotting=F,background = rownames(gep_scores))
plots = hyp_dots(hyp_obj,size_by = "none")
print_tab(plt = plots[[1]],title = "GEP 1")

GEP 1

print_tab(plt = plots[[2]],title = "GEP 2")

GEP 2

print_tab(plt = plots[[3]],title = "GEP 3")

GEP 3

NA

19 APC signature

hallmark_name = "KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION"
annotation = plot_genes_cor(dataset = xeno,hallmark_name = hallmark_name,num_of_clusters = 4,canocical = T)

genes expression heatmap

NA

chosen_clusters = c(1,3)
print (paste("chosen_clusters = ", chosen_clusters %>% toString()))

1 “chosen_clusters = 1, 3”

#UMAP expression of signature
chosen_genes = annotation[["myannotation"]] %>% dplyr::filter(cluster %in% chosen_clusters) %>% rownames() #take relevant genes
score <- apply(xeno@assays$RNA@data[chosen_genes,],2,mean)
xeno=AddMetaData(xeno,score,hallmark_name)
scoresAndIndices <- getPathwayScores(xeno@assays$RNA@data, chosen_genes)
xeno=AddMetaData(xeno,scoresAndIndices$pathwayScores,paste0(hallmark_name,"_sipsic"))
print_tab(FeaturePlot(object = xeno, features = paste0(hallmark_name,"_sipsic")),title = "Expression")

Expression

print_tab(FeaturePlot(object = xeno, features = hallmark_name),title = "Expression")

Expression

NA

19.1 correlatino to nmf

cor_res = cor(xeno$TNFa,xeno[[hallmark_name]])
print(paste("correlation of TNFa program to", hallmark_name,":", cor_res))
[1] "correlation of TNFa program to KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION : 0.396759488432559"
cor_res = cor(xeno$TNFa,xeno[[paste0(hallmark_name,"_sipsic")]])
print(paste("correlation of TNFa program to", paste0(hallmark_name,"_sipsic"),":", cor_res))
[1] "correlation of TNFa program to KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION_sipsic : 0.333142851072643"

20 Signatures regulation

metagenes_mean_compare(dataset = xeno,time.point_var = "treatment",prefix = "model",patient.ident_var = "orig.ident",pre_on = c("NT","OSI","res"),programs = c("TNFa","HALLMARK_TNFA_SIGNALING_VIA_NFKB","KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION"))

TNFa per patient

TNFa

HALLMARK_TNFA_SIGNALING_VIA_NFKB per patient

HALLMARK_TNFA_SIGNALING_VIA_NFKB

KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION per patient

KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION

NA

21 intersection

top_ot = gep_scores3[order(gep_scores3[,2],decreasing = T),2,drop = F]%>% head(200) %>% rownames()
hallmark_name = "KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION"
geneIds= genesets[[hallmark_name]]
chosen_genes = intersect(geneIds,top_ot)
print(chosen_genes)

1 “CD74” “HLA-DMA” “HLA-DPA1” “HLA-DPB1” “HLA-DRA” “HLA-DRB1” “HLA-DRB5”

score <- apply(xeno@assays$RNA@data[chosen_genes,],2,mean)
xeno=AddMetaData(xeno,score,paste0(hallmark_name,"intersected"))
scoresAndIndices <- getPathwayScores(xeno@assays$RNA@data, chosen_genes)
xeno=AddMetaData(xeno,scoresAndIndices$pathwayScores,paste0(hallmark_name,"_intersected_sipsic"))
print_tab(FeaturePlot(object = xeno, features = paste0(hallmark_name,"_intersected_sipsic")),title = "Expression")

Expression

Warning 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

print_tab(FeaturePlot(object = xeno, features = paste0(hallmark_name,"intersected")),title = "Expression")

Expression

NA

cor_res = cor(xeno$TNFa,xeno[[paste0(hallmark_name,"intersected")]])
print(paste("correlation of TNFa program to", paste0(hallmark_name,"intersected"),":", cor_res))
[1] "correlation of TNFa program to KEGG_ANTIGEN_PROCESSING_AND_PRESENTATIONintersected : 0.536876281844422"
top_ot = gep_scores3[order(gep_scores3[,2],decreasing = T),2,drop = F]%>% head(200) %>% rownames()
hallmark_name = "HALLMARK_TNFA_SIGNALING_VIA_NFKB"
geneIds= genesets[[hallmark_name]]
chosen_genes = intersect(geneIds,top_ot)
print(chosen_genes)
 [1] "ATF3"    "BCL6"    "BTG2"    "CEBPD"   "CXCL2"   "EGR1"    "EGR2"    "FOS"     "FOSB"    "GADD45B" "IER2"    "JUN"    
[13] "JUNB"    "KLF2"    "NR4A1"   "NR4A2"   "NR4A3"   "REL"     "RHOB"    "SAT1"    "SOCS3"   "ZFP36"  
score <- apply(xeno@assays$RNA@data[chosen_genes,],2,mean)
xeno=AddMetaData(xeno,score,paste0(hallmark_name,"intersected"))
scoresAndIndices <- getPathwayScores(xeno@assays$RNA@data, chosen_genes)
xeno=AddMetaData(xeno,scoresAndIndices$pathwayScores,paste0(hallmark_name,"_intersected_sipsic"))
print_tab(FeaturePlot(object = xeno, features = paste0(hallmark_name,"_intersected_sipsic")),title = "Expression")
##   Expression {.unnumbered }  

print_tab(FeaturePlot(object = xeno, features = paste0(hallmark_name,"intersected")),title = "Expression")
##   Expression {.unnumbered }  

NA
cor_res = cor(xeno$TNFa,xeno[[paste0(hallmark_name,"intersected")]])
print(paste("correlation of TNFa program to", paste0(hallmark_name,"intersected"),":", cor_res))
[1] "correlation of TNFa program to HALLMARK_TNFA_SIGNALING_VIA_NFKBintersected : 0.488904752032433"

22 Norm pathways

sum_scores= xeno$HIF_targets+xeno$KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION+xeno$HALLMARK_G2M_CHECKPOINT

new_score = xeno$KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION/ sum_scores
xeno %<>% AddMetaData(metadata = new_score,col.name = "KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION_norm")

new_score = (xeno$HIF_targets/ sum_scores)%>% replace(is.na(.), 0)
xeno %<>% AddMetaData(metadata = new_score,col.name = "HIF_targets_norm")

new_score = xeno$HALLMARK_G2M_CHECKPOINT/ sum_scores
xeno %<>% AddMetaData(metadata = new_score,col.name = "HALLMARK_G2M_norm")
FeaturePlot(object = xeno,features = c("HALLMARK_G2M_norm", "KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION_norm","HIF_targets_norm"))

metagenes_mean_compare(dataset = xeno,time.point_var = "treatment",prefix = "model",patient.ident_var = "orig.ident",pre_on = c("NT","OSI","res"),programs = c("TNFa","HALLMARK_TNFA_SIGNALING_VIA_NFKB","KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION","KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION_norm"))

TNFa per patient

TNFa

HALLMARK_TNFA_SIGNALING_VIA_NFKB per patient

HALLMARK_TNFA_SIGNALING_VIA_NFKB

KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION per patient

KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION

KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION_norm per patient

KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION_norm

NA

23 program 2 clustering

num_of_clusters = 7
annotation = plot_genes_cor(dataset = xeno,hallmark_name = NULL,num_of_clusters = num_of_clusters,geneIds = top_ot)
##   genes expression heatmap {.unnumbered }  

NA

24 all clusters expression

for (chosen_clusters in 1:num_of_clusters) {
  chosen_genes = annotation[["myannotation"]] %>% dplyr::filter(cluster == chosen_clusters) %>% rownames() #take relevant genes
  # print(chosen_genes)
  hyp_obj <- hypeR(chosen_genes, genesets_env, test = "hypergeometric", fdr=1, plotting=F,background = rownames(gep_scores))

   scoresAndIndices <- getPathwayScores(xeno@assays$RNA@data, chosen_genes)
  xeno=AddMetaData(xeno,scoresAndIndices$pathwayScores,paste0("cluster",chosen_clusters))

  
  print_tab(plt = 
              hyp_dots(hyp_obj,size_by = "none",title = paste0("cluster",chosen_clusters))+
              FeaturePlot(object = xeno,features = paste0("cluster",chosen_clusters)),
            title = chosen_clusters)
  
  cor_res = cor(xeno$TNFa,xeno[[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

25 correlation of all clusters

for (chosen_clusters in 1:num_of_clusters) {
  chosen_genes = annotation[["myannotation"]] %>% dplyr::filter(cluster == chosen_clusters) %>% rownames() #take relevant genes
  cor_res = cor(xeno$TNFa,xeno[[paste0("cluster",chosen_clusters)]])
  print(paste("correlation of TNFa program to", paste0("cluster",chosen_clusters),":", cor_res))

}
[1] "correlation of TNFa program to cluster1 : 0.196505816390455"
[1] "correlation of TNFa program to cluster2 : 0.366147384813019"
[1] "correlation of TNFa program to cluster3 : 0.532136383102456"
[1] "correlation of TNFa program to cluster4 : 0.534315691094927"
[1] "correlation of TNFa program to cluster5 : 0.697969009217511"
[1] "correlation of TNFa program to cluster6 : 0.326695267801052"
[1] "correlation of TNFa program to cluster7 : 0.0360547219515362"

26 clusters 4 and 5

chosen_clusters = c(4,5)
  chosen_genes = annotation[["myannotation"]] %>% dplyr::filter(cluster %in% chosen_clusters) %>% rownames() #take relevant genes
  
  hyp_obj <- hypeR(chosen_genes, genesets_env, test = "hypergeometric", fdr=1, plotting=F,background = rownames(gep_scores))

   scoresAndIndices <- getPathwayScores(xeno@assays$RNA@data, chosen_genes)
   score_name = paste0("cluster_", paste0(chosen_clusters, collapse = "_"))
  xeno=AddMetaData(xeno,scoresAndIndices$pathwayScores,score_name)

  hyp_dots(hyp_obj,size_by = "none")+
    FeaturePlot(object = xeno,features = score_name)


  cor_res = cor(xeno$TNFa,xeno[[score_name]])
print(paste("correlation of TNFa program to", score_name,":", cor_res))
[1] "correlation of TNFa program to cluster_4_5 : 0.754961916533887"

27 Title

library(biomaRt)
ensembl = useEnsembl(biomart="ensembl", dataset="hsapiens_gene_ensembl")

for (chosen_clusters in 1:num_of_clusters) {
  chosen_genes = annotation[["myannotation"]] %>% dplyr::filter(cluster == chosen_clusters) %>% rownames() #take relevant genes
  genedesc <- getBM(attributes=c('external_gene_name','wikigene_description',"interpro_description"), filters = 'external_gene_name', values = chosen_genes, mart =ensembl)  
  print_tab(genedesc,title = chosen_clusters)
}

28 Programs regulation

metagenes_mean_compare(dataset = xeno,time.point_var = "treatment",prefix = "model",patient.ident_var = "orig.ident",pre_on = c("NT","OSI","res"),programs = c("TNFa","HALLMARK_TNFA_SIGNALING_VIA_NFKB","KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION","KEGG_ANTIGEN_PROCESSING_AND_PRESENTATIONintersected","cluster_4_5","cluster7"))

TNFa per patient

TNFa

HALLMARK_TNFA_SIGNALING_VIA_NFKB per patient

HALLMARK_TNFA_SIGNALING_VIA_NFKB

KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION per patient

KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION

KEGG_ANTIGEN_PROCESSING_AND_PRESENTATIONintersected per patient

KEGG_ANTIGEN_PROCESSING_AND_PRESENTATIONintersected

cluster_4_5 per patient

cluster_4_5

cluster7 per patient

cluster7

NA

29 HIF_targets- Hypoxia correlation

# plot correlation for every subset of hif targets
for (genes in list(hif_targets,xeno_cluster_3_genes,xeno_cluster_3_2_genes)) {
  hif_targets_by_tp = FetchData(object = xeno,vars = c(genes)) %>% rowSums() %>% as.data.frame() #mean expression
  hif_targets_by_tp[,2] = xeno$Hypoxia
  
  names(hif_targets_by_tp) = c("hif_targets","hypoxia_program")
  
  
  
  p1 = ggplot(hif_targets_by_tp, aes(x=hif_targets, y=hypoxia_program)) + 
      geom_point()+
    geom_density_2d(aes(color = ..level..)) +
    geom_smooth(method=lm) +
    stat_cor(method = "pearson", label.x = 20, label.y = 1.1)+
    scale_color_viridis_c()
  
  p2 = ggplot(hif_targets_by_tp, aes(x=hif_targets, y=hypoxia_program)) + 
    geom_bin2d() +
    theme_bw()+ scale_fill_gradientn(limits=c(0,1100), breaks=seq(0, 1100, by=200), colours=c("blue","yellow","red"))+ 
    stat_cor(method = "pearson", label.x = 20, label.y = 1.1)+
    geom_smooth(method=lm) 
  
  p = ggarrange(plotlist = list(p1,p2),nrow  = 2)  
  
  print_tab(plt = p,title = "geom_bin2d")
}

30 UMAPS

hif_targets_by_tp = FetchData(object = xeno,vars = c(hif_targets)) %>% rowSums() %>% as.data.frame() #mean expression
hif_targets_by_tp[,2] = xeno$Hypoxia
names(hif_targets_by_tp) = c("hif_targets","hypoxia_program")

high_hif_low_hypoxia_cells = hif_targets_by_tp %>% filter(hif_targets>25 & hypoxia_program < 0.2) %>% rownames()
low_hif_high_hypoxia_cells = hif_targets_by_tp %>% filter(hif_targets<15 & hypoxia_program > 0.6) %>% rownames()

hif_targets_by_tp = FetchData(object = xeno,vars = c(hif_targets)) %>% rowSums() %>% as.data.frame() #mean expression
xeno = AddMetaData(object = xeno, metadata = hif_targets_by_tp,col.name = "HIF_targets_score")
cells_to_highlight =  list(high_hif_low_hypoxia_cells = high_hif_low_hypoxia_cells, low_hif_high_hypoxia_cells = low_hif_high_hypoxia_cells)

DimPlot(object = xeno, cells.highlight = cells_to_highlight, cols.highlight = c("red","blue"), cols = "gray", order = TRUE)
FeaturePlot(object = xeno,features = c( "HIF_targets_score","Hypoxia","Cell_cycle" ))
hif_hypoxia_correlated_cells = colnames(xeno) [!colnames(xeno) %in% high_hif_low_hypoxia_cells & !colnames(xeno) %in% high_hif_low_hypoxia_cells]
hif_targets_score = FetchData(object = xeno,vars = c(hif_targets)) %>% rowSums() %>% as.data.frame() #mean expression
hif_targets_score[,2] = xeno$Hypoxia
names(hif_targets_score) = c("hif_targets","hypoxia_program")
hif_targets_score  = hif_targets_score %>% mutate(type = case_when(hif_targets>25 & hypoxia_program < 0.2 ~ "high_hif_low_hypoxia",
                                                                   hif_targets<15 & hypoxia_program > 0.6 ~ "low_hif_high_hypoxia",
                                                                   hif_targets>25 & hypoxia_program > 0.6 ~ "high_hif_high_hypoxia",
                                                                   hif_targets<15 & hypoxia_program <0.2 ~ "high_hif_high_hypoxia",
                                                                   TRUE ~ "other"))
xeno = AddMetaData(object = xeno,metadata = hif_targets_score[,"type", drop = F],col.name = "score_correlation")
xeno = SetIdent(object = xeno,value = "score_correlation")
DimPlot(object = xeno,group.by = "score_correlation")
markers = FindMarkers(object = xeno, ident.1 = "high_hif_low_hypoxia",ident.2 = "high_hif_high_hypoxia",densify = T)
updeg = markers %>% filter(p_val_adj<0.05 & avg_log2FC>0) %>% rownames()

new_hif_targets = hif_targets[!hif_targets %in% updeg]
hif_targets_by_tp = FetchData(object = xeno,vars = c(new_hif_targets)) %>% rowSums() %>% as.data.frame() #mean expression
  hif_targets_by_tp[,2] = xeno$Hypoxia
  
  names(hif_targets_by_tp) = c("hif_targets","hypoxia_program")
  
  
  
  p1 = ggplot(hif_targets_by_tp, aes(x=hif_targets, y=hypoxia_program)) + 
      geom_point()+
    geom_density_2d(aes(color = ..level..)) +
    geom_smooth(method=lm) +
    stat_cor(method = "pearson", label.x = 20, label.y = 1.1)+
    scale_color_viridis_c()
  
  p2 = ggplot(hif_targets_by_tp, aes(x=hif_targets, y=hypoxia_program)) + 
    geom_bin2d() +
    theme_bw()+ scale_fill_gradientn(limits=c(0,1100), breaks=seq(0, 1100, by=200), colours=c("blue","yellow","red"))+ 
    stat_cor(method = "pearson", label.x = 20, label.y = 1.1)+
    geom_smooth(method=lm) 
  
  p = ggarrange(plotlist = list(p1,p2),nrow  = 2)  
  
  print_tab(plt = p,title = "geom_bin2d")
upreg_hif_targets = hif_targets[hif_targets %in% updeg]
upreg_hif_targets_expr = FetchData(object = xeno,vars = c(upreg_hif_targets)) %>% rowSums() %>% as.data.frame() #mean expression
xeno = AddMetaData(object = xeno, metadata = upreg_hif_targets_expr,col.name = "upreg_hif_targets_score")
FeaturePlot(object = xeno,features = "upreg_hif_targets_score")

31 Calculate usage without cc in sum to 1

import numpy as np
import scanpy as sc
xeno_expression = r.xeno_expression
xeno_vargenes = r.xeno_vargenes
tpm =  compute_tpm(xeno_expression)
usage_by_calc = get_usage_from_score(counts=xeno_expression,tpm=tpm,genes=xeno_vargenes, cnmf_obj=cnmf_obj,k=3,sumTo1=False)
all_metagenes_noSumTo1 = py$usage_by_calc
tnf_and_hypoxia = all_metagenes_noSumTo1[,1:2]
tnf_and_hypoxia = apply(X = tnf_and_hypoxia, MARGIN = 1, sum_2_one) %>% t() %>%  as.data.frame()
tnf_and_hypoxia[is.na(tnf_and_hypoxia)] <- 0 #replace NAN's with 0.
# plot correlation for every subset of hif targets
for (genes in list(hif_targets,xeno_cluster_3_genes,xeno_cluster_3_2_genes)) {
  hif_targets_by_tp = FetchData(object = xeno,vars = c(genes)) %>% rowSums() %>% as.data.frame() #mean expression
  hif_targets_by_tp[,2] = tnf_and_hypoxia[,1]
  # hif_targets_by_tp[,2] = xeno$Hypoxia
  
  names(hif_targets_by_tp) = c("hif_targets","hypoxia_program")
  
  
  
  p1 = ggplot(hif_targets_by_tp, aes(x=hif_targets, y=hypoxia_program)) + 
      geom_point()+
    geom_density_2d(aes(color = ..level..)) +
    geom_smooth(method=lm) +
    stat_cor(method = "pearson", label.x = 20, label.y = 1.1)+
    scale_color_viridis_c()
  
  p2 = ggplot(hif_targets_by_tp, aes(x=hif_targets, y=hypoxia_program)) + 
    geom_bin2d() +
    theme_bw()+ scale_fill_gradientn(limits=c(0,1100), breaks=seq(0, 1100, by=200), colours=c("blue","yellow","red"))+ 
    stat_cor(method = "pearson", label.x = 20, label.y = 1.1)+
    geom_smooth(method=lm) 
  
  p = ggarrange(plotlist = list(p1,p2),nrow  = 2)  
  
  print_tab(plt = p,title = "geom_bin2d")
}

32 UMAPS

hif_targets_by_tp = FetchData(object = xeno,vars = c(hif_targets)) %>% rowSums() %>% as.data.frame() #mean expression
hif_targets_by_tp[,2] = tnf_and_hypoxia[,1]
names(hif_targets_by_tp) = c("hif_targets","hypoxia_program")

high_hif_low_hypoxia_cells = hif_targets_by_tp %>% filter(hif_targets>25 & hypoxia_program < 0.2) %>% rownames()

hif_targets_by_tp = FetchData(object = xeno,vars = c(hif_targets)) %>% rowSums() %>% as.data.frame() #mean expression
xeno = AddMetaData(object = xeno, metadata = hif_targets_by_tp,col.name = "HIF_targets_score")
xeno = AddMetaData(object = xeno, metadata = tnf_and_hypoxia[,1],col.name = "Hypoxia2")

DimPlot(object = xeno, cells.highlight = high_hif_low_hypoxia_cells, cols.highlight = "red", cols = "gray", order = TRUE)
FeaturePlot(object = xeno,features = c( "HIF_targets_score","Hypoxia2","Cell_cycle" ))
FeaturePlot(object = xeno,features = c("Hypoxia2"))
DimPlot(object = xeno,group.by = "orig.ident")

33 Hypoxia raw

xeno = AddMetaData(object = xeno,metadata = all_metagenes_noSumTo1[,1],col.name = "hypoxia_raw")
FeaturePlot(object = xeno,features = "hypoxia_raw") + scale_color_gradientn(colours = rainbow(5), limits = c(0, 3000))
LS0tCnRpdGxlOiAnYHIgcnN0dWRpb2FwaTo6Z2V0U291cmNlRWRpdG9yQ29udGV4dCgpJHBhdGggJT4lIGJhc2VuYW1lKCkgJT4lIGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLHJlcGxhY2VtZW50ID0gIiIpYCcgCmF1dGhvcjogIkF2aXNoYWkgV2l6ZWwiCmRhdGU6ICdgciBTeXMudGltZSgpYCcKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdG9jOiB5ZXMKICAgIHRvY19jb2xsYXBzZTogeWVzCiAgICB0b2NfZmxvYXQ6IAogICAgICBjb2xsYXBzZWQ6IEZBTFNFCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvY19kZXB0aDogMQotLS0KCgoKIyBGdW5jdGlvbnMKYGBge3Igd2FybmluZz1GQUxTRX0KCmxpYnJhcnkoc3RyaW5naSkKbGlicmFyeShyZXRpY3VsYXRlKQpzb3VyY2VfZnJvbV9naXRodWIocmVwb3NpdG95ID0gIkRFR19mdW5jdGlvbnMiLHZlcnNpb24gPSAiMC4yLjI0IikKc291cmNlX2Zyb21fZ2l0aHViKHJlcG9zaXRveSA9ICJjTk1GX2Z1bmN0aW9ucyIsdmVyc2lvbiA9ICIwLjMuOTEiLHNjcmlwdF9uYW1lID0gImNubWZfZnVuY3Rpb25fSGFybW9ueS5SIikKCm5vX25lZyA8LSBmdW5jdGlvbih4KSB7CiAgeCA9IHggKyBhYnMobWluKHgpKQogIHgKfQoKc3VtXzJfb25lIDwtIGZ1bmN0aW9uKHgpIHsKICB4ID14L3N1bSh4KQogIHgKfQoKYGBgCgoKCgojIERhdGEKYGBge3J9Cnhlbm8gPSByZWFkUkRTKCIuL0RhdGEvMTB4X3hlbm9fMTAwMC5SZHMiKQpsdW5nID0gcmVhZFJEUygiLi9EYXRhL2x1bmdfY2FuY2VyY2VsbHNfd2l0aFRQX29ubHlQYXRpZW50cy5yZHMiKQpsdW5nX3BhdGllbnRzID0gbHVuZyRwYXRpZW50LmlkZW50ICU+JSB1bmlxdWUoKSAlPiUgYXMuY2hhcmFjdGVyKCkKbHVuZ19wYXRpZW50c19maWx0ZXJlZCA9IGx1bmdfcGF0aWVudHNbIShsdW5nX3BhdGllbnRzICVpbiUgYygiWDEwNTVuZXciLCJYMTA5OSIpKV0gIyByZW1vdmUgcGF0aWVudHMgd2l0aCBsZXNzIHRoYW4gMTAwIG1hbGlnbmFudCBjZWxscwpsdW5nID0gc3Vic2V0KHggPSBsdW5nLHN1YnNldCA9IHBhdGllbnQuaWRlbnQgJWluJSBsdW5nX3BhdGllbnRzX2ZpbHRlcmVkKQpgYGAKCiMgTW9kZWxzIDJLIHZhcmdlbmVzIAoKYGBge3B5dGhvbn0KaW1wb3J0IHBpY2tsZQpmcm9tIGNubWYgaW1wb3J0IGNOTUYKZiA9IG9wZW4oJy4vRGF0YS9jbm1mL2NubWZfb2JqZWN0cy9tb2RlbHNfMkt2YXJnZW5lc19jbm1mX29iai5wY2tsJywgJ3JiJykKY25tZl9vYmogPSBwaWNrbGUubG9hZChmKQpmLmNsb3NlKCkKYGBgCgojIEsgc2VsZWN0aW9uIHBsb3QKYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9Mn0KcGxvdF9wYXRoID0gcGFzdGUwKCIvc2NpL2xhYnMveW90YW1kL2xhYl9zaGFyZS9hdmlzaGFpLndpemVsL1JfcHJvamVjdHMvRUdGUi9EYXRhL2NubWYvY05NRl9tb2RlbHNfVmFybm9ybV9IYXJtb255XzJLdmFyZ2VuZXMvY05NRl9tb2RlbHNfVmFybm9ybV9IYXJtb255XzJLdmFyZ2VuZXMua19zZWxlY3Rpb24ucG5nIikKa25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MocGxvdF9wYXRoKQpgYGAKCgoKIyBnZXAgc2NvcmVzIGZvciBhbGwgTk1GIGsncyB7LnRhYnNldH0KYGBge3B5dGhvbn0KZGVuc2l0eV90aHJlc2hvbGQgPSAwLjEKdXNhZ2Vfbm9ybTMsIGdlcF9zY29yZXMzLCBfLCBfID0gY25tZl9vYmoubG9hZF9yZXN1bHRzKEs9MywgZGVuc2l0eV90aHJlc2hvbGQ9ZGVuc2l0eV90aHJlc2hvbGQpCnVzYWdlX25vcm00LCBnZXBfc2NvcmVzNCwgXywgXyA9IGNubWZfb2JqLmxvYWRfcmVzdWx0cyhLPTQsIGRlbnNpdHlfdGhyZXNob2xkPWRlbnNpdHlfdGhyZXNob2xkKQp1c2FnZV9ub3JtNSwgZ2VwX3Njb3JlczUsIF8sIF8gPSBjbm1mX29iai5sb2FkX3Jlc3VsdHMoSz01LCBkZW5zaXR5X3RocmVzaG9sZD1kZW5zaXR5X3RocmVzaG9sZCkKYGBgCgpgYGB7cn0KZ2VwX3Njb3JlczMgPSBweSRnZXBfc2NvcmVzMwpnZXBfc2NvcmVzNCA9IHB5JGdlcF9zY29yZXM0CmdlcF9zY29yZXM1ID0gcHkkZ2VwX3Njb3JlczUKCnVzYWdlX25vcm0zID0gcHkkdXNhZ2Vfbm9ybTMKdXNhZ2Vfbm9ybTQgPSBweSR1c2FnZV9ub3JtNAp1c2FnZV9ub3JtNSA9IHB5JHVzYWdlX25vcm01CgpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTEwLCByZXN1bHRzPSdhc2lzJ30KYWxsX3VzYWdlX25vcm0gPSBsaXN0KHVzYWdlX25vcm0zID0gdXNhZ2Vfbm9ybTMsIHVzYWdlX25vcm00ID0gdXNhZ2Vfbm9ybTQsIHVzYWdlX25vcm01ID0gdXNhZ2Vfbm9ybTUpCmZvciAodXNhZ2VfbnVtIGluIHNlcV9hbG9uZyhhbGxfdXNhZ2Vfbm9ybSkpIHsKICB1c2FnZSA9IGFsbF91c2FnZV9ub3JtW1t1c2FnZV9udW1dXQogICNhZGQgZWFjaCBtZXRhZ2VuZSB0byBtZXRhZGF0YQogIGZvciAoaSBpbiAxOm5jb2wodXNhZ2UpKSB7CiAgICBtZXRhZ2VfbWV0YWRhdGEgPSB1c2FnZSAlPiUgZHBseXI6OnNlbGVjdChpKQogICAgeGVubyA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IHhlbm8sbWV0YWRhdGEgPSBtZXRhZ2VfbWV0YWRhdGEsY29sLm5hbWUgPSBwYXN0ZTAoImdlcCIsaSkpCiAgfQogIGlmICh1c2FnZV9udW09PTEpIHsKICAgICAgcHJpbnRfdGFiKEZlYXR1cmVQbG90KG9iamVjdCA9IHhlbm8sZmVhdHVyZXMgPSBwYXN0ZTAoImdlcCIsMTpuY29sKHVzYWdlKSksbmNvbCA9IDIpLHRpdGxlID0gdXNhZ2VfbnVtKQoKICB9ZWxzZXsgcHJpbnRfdGFiKEZlYXR1cmVQbG90KG9iamVjdCA9IHhlbm8sZmVhdHVyZXMgPSBwYXN0ZTAoImdlcCIsMTpuY29sKHVzYWdlKSksbmNvbCA9IDMpLHRpdGxlID0gdXNhZ2VfbnVtKX0KfQpgYGAKIyBhbGwgTk1GIGsncyAgZW5yaWNobWVudHsudGFic2V0fQoKCmBgYHtyIHJlc3VsdHM9J2FzaXMnfQoKYWxsX2dlcF9zY29yZXMgPSAgbGlzdChnZXBfc2NvcmVzMyA9IGdlcF9zY29yZXMzLCBnZXBfc2NvcmVzNCA9IGdlcF9zY29yZXM0LCBnZXBfc2NvcmVzNSA9IGdlcF9zY29yZXM1KQoKZ2VuZXNldHMgPC0gbXNpZ2RiX2Rvd25sb2FkKCJIb21vIHNhcGllbnMiLGNhdGVnb3J5PSJIIikgJT4lIGFwcGVuZCggbXNpZ2RiX2Rvd25sb2FkKCJIb21vIHNhcGllbnMiLGNhdGVnb3J5PSJDMiIsc3ViY2F0ZWdvcnkgPSAiQ1A6S0VHRyIpKQpnZW5lc2V0c1tbIkhJRl90YXJnZXRzIl1dID0gaGlmX3RhcmdldHMKZ2VuZXNldHNfZW52ID0gZ3NldHMkbmV3KGdlbmVzZXRzLCBuYW1lPSJteSBnZW5lc2V0cyIsIHZlcnNpb249InYxLjAiKQoKZm9yIChnZXBfbnVtIGluIHNlcV9hbG9uZyhhbGxfZ2VwX3Njb3JlcykpIHsKICBnZXAgPSBhbGxfZ2VwX3Njb3Jlc1tbZ2VwX251bV1dCiAgcmFua2VkX2xpc3QgPSBsaXN0KCkKICBmb3IgKGNvbCBpbiAoZ2VwKSkgewogICBsc3QgPSBjb2wgJT4lIHNldE5hbWVzKHJvd25hbWVzKGdlcCkpICU+JSBzb3J0KGRlY3JlYXNpbmcgPSBUUlVFKSAKICAgcmFua2VkX2xpc3QgICU8PiUgYXBwZW5kKGxpc3QobHN0KSkKICB9CiAgbmFtZXMocmFua2VkX2xpc3QpID0gcGFzdGUwKCJnZXAiLDE6bmNvbChnZXApKQogIAogIAogIAogIGh5cF9vYmogPC0gaHlwZVIocmFua2VkX2xpc3QsIGdlbmVzZXRzX2VudiwgdGVzdD0ia3N0ZXN0IiwgZmRyPTAuMDUsIHBsb3R0aW5nPUYsYmFja2dyb3VuZCA9IHJvd25hbWVzKGdlcF9zY29yZXMzKSkKICBwcmludF90YWIoCiAgICBoeXBfZG90cyhoeXBfb2JqLHNpemVfYnkgPSAic2lnbmlmaWNhbmNlIixhYnJ2ID0gMTAwLG1lcmdlID0gVCkrCiAgICAgIHNjYWxlX2NvbG9yX2NvbnRpbnVvdXMobG93ID0gInJlZCIsIGhpZ2ggPSAiYmxhY2siLCBndWlkZSA9IGd1aWRlX2NvbG9yYmFyKHJldmVyc2UgPSBUUlVFKSkKICAgICx0aXRsZSA9IGdlcF9udW0pCiAgCn0KCmBgYAoKIyBwcm9ncmFtcyBlbnJpY2htZW50CgoKYGBge3J9CmdlcF9zY29yZXMgPSBweSRnZXBfc2NvcmVzMwp1c2FnZV9ub3JtPSBweSR1c2FnZV9ub3JtMwpgYGAKCmBgYHtyfQojIG9yOgpnZXBfc2NvcmVzID0gcmVhZFJEUygiL3NjaS9sYWJzL3lvdGFtZC9sYWJfc2hhcmUvYXZpc2hhaS53aXplbC9SX3Byb2plY3RzL0VHRlIvRGF0YS9jbm1mL2hhcm1vbnlfbW9kZWxzX2dlcF9zY29yZXMucmRzIikKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD04fQpuYW1lcyAoZ2VwX3Njb3JlcykgPSBjKCJIeXBveGlhIiwiVE5GYSIsIkNlbGxfY3ljbGUiKQpwbHRfbGlzdCA9IGxpc3QoKQoKZm9yIChwcm9ncmFtICBpbiBuYW1lcyAoZ2VwX3Njb3JlcykpIHsKIHAgPSBnZ3Bsb3QoZ2VwX3Njb3JlcywgYWVzKHg9ISFlbnN5bShwcm9ncmFtKSkpICsKICBnZW9tX2RlbnNpdHkoKSt4bGFiKHByb2dyYW0pKwogICBnZW9tX3ZsaW5lKAogICAgYWVzKHhpbnRlcmNlcHQ9c29ydChnZXBfc2NvcmVzWyxwcm9ncmFtXSxUUlVFKVsyMDBdICAsY29sb3I9InRvcDIwMCIpLAogICAgICAgICAgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkrCiAgIGdlb21fdmxpbmUoCiAgICBhZXMoeGludGVyY2VwdD1zb3J0KGdlcF9zY29yZXNbLHByb2dyYW1dLFRSVUUpWzEwMF0gICxjb2xvcj0idG9wMTAwIiksCiAgICAgICAgICBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKSsKICAgICAgZ2VvbV92bGluZSgKICAgIGFlcyh4aW50ZXJjZXB0PXNvcnQoZ2VwX3Njb3Jlc1sscHJvZ3JhbV0sVFJVRSlbNTBdICAsY29sb3I9InRvcDUwIiksCiAgICAgICAgICBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKSsKICAgICAgICAgZ2VvbV92bGluZSgKICAgIGFlcyh4aW50ZXJjZXB0PXNvcnQoZ2VwX3Njb3Jlc1sscHJvZ3JhbV0sVFJVRSlbMTUwXSAgLGNvbG9yPSJ0b3AxNTAiKSwKICAgICAgICAgIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpKwogICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJ0b3AgbiBnZW5lcyIsIHZhbHVlcyA9IGModG9wMjAwID0gImJsdWUiLHRvcDEwMCA9ICJyZWQiLHRvcDE1MCA9ICJ5ZWxsb3ciLHRvcDUwID0gImdyZWVuIikpCiAgIHBsdF9saXN0W1twcm9ncmFtXV0gPC0gcAoKfQogCmdnYXJyYW5nZShwbG90bGlzdCA9IHBsdF9saXN0KQoKYGBgCgoKCgoKIyBQcm9ncmFtcyBoYWxsbWFyayBlbnJpY2htZW50CgpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fQpudG9wID0gMTUwCnBsdF9saXN0ID0gbGlzdCgpCmhpZl90YXJnZXRzX3NldCA9IGRhdGEuZnJhbWUoZ3NfbmFtZSA9ICJoaWZfdGFyZ2V0cyIsZ2VuZV9zeW1ib2wgPSBoaWZfdGFyZ2V0cykKCmZvciAoaSBpbiAxOm5jb2woZ2VwX3Njb3JlcykpIHsKICB0b3BfZ2VuZXMgPSBnZXBfc2NvcmVzICAlPiUgIGFycmFuZ2UoZGVzYyhnZXBfc2NvcmVzW2ldKSkgI3NvcnQgYnkgc2NvcmUgYQogIHRvcCA9IGhlYWQocm93bmFtZXModG9wX2dlbmVzKSxudG9wKSAjdGFrZSB0b3AgdG9wX2dlbmVzX251bQogIHJlcyA9IGdlbmVzX3ZlY19lbnJpY2htZW50KGdlbmVzID0gdG9wLGJhY2tncm91bmQgPSByb3duYW1lcyhnZXBfc2NvcmVzKSxob21lciA9IFQsdGl0bGUgPSAKICAgICAgICAgICAgICAgICAgICBpLHNpbGVudCA9IFQscmV0dXJuX2FsbCA9IFQsY3VzdG9tX3BhdGh3YXlzICA9IGhpZl90YXJnZXRzX3NldCkKICAgCiAgcGx0X2xpc3RbW2ldXSA9IHJlcyRwbHQKfQpncmlkRXh0cmE6OmdyaWQuYXJyYW5nZShncm9icyA9IHBsdF9saXN0KQpgYGAKCiMgcHJvZ3JhbSAyIGFsbCBjcApgYGB7cn0KbnRvcCA9IDE1MAppID0gMiAKCiAgdG9wX2dlbmVzID0gZ2VwX3Njb3JlcyAgJT4lICBhcnJhbmdlKGRlc2MoZ2VwX3Njb3Jlc1tpXSkpICNzb3J0IGJ5IHNjb3JlIGEKICB0b3AgPSBoZWFkKHJvd25hbWVzKHRvcF9nZW5lcyksbnRvcCkgI3Rha2UgdG9wIHRvcF9nZW5lc19udW0KICByZXMgPSBnZW5lc192ZWNfZW5yaWNobWVudChnZW5lcyA9IHRvcCxiYWNrZ3JvdW5kID0gcm93bmFtZXMoZ2VwX3Njb3JlcyksaG9tZXIgPSBULHRpdGxlID0gCiAgICAgICAgICAgICAgICAgICAgaSxzaWxlbnQgPSBULHJldHVybl9hbGwgPSBULGN1c3RvbV9wYXRod2F5cyAgPSBjYW5vbmljYWxfcGF0aHdheXMpCiAgIAogcHJpbnQocmVzJHBsdCkgCgoKYGBgCgojIFByb2dyYW0gMiBhbGwgbXNpZ2RiCmBgYHtyfQpudG9wID0gMTUwCmkgPSAyIAoKICB0b3BfZ2VuZXMgPSBnZXBfc2NvcmVzICAlPiUgIGFycmFuZ2UoZGVzYyhnZXBfc2NvcmVzW2ldKSkgI3NvcnQgYnkgc2NvcmUgYQogIHRvcCA9IGhlYWQocm93bmFtZXModG9wX2dlbmVzKSxudG9wKSAjdGFrZSB0b3AgdG9wX2dlbmVzX251bQogIHJlcyA9IGdlbmVzX3ZlY19lbnJpY2htZW50KGdlbmVzID0gdG9wLGJhY2tncm91bmQgPSByb3duYW1lcyhnZXBfc2NvcmVzKSxob21lciA9IFQsdGl0bGUgPSAKICAgICAgICAgICAgICAgICAgICBpLHNpbGVudCA9IFQscmV0dXJuX2FsbCA9IFQsY3VzdG9tX3BhdGh3YXlzICA9IGFsbF9wYXRod2F5cykKICAgCiBwcmludChyZXMkcGx0KSAKCgpgYGAKCgpgYGB7cn0KeGVubyA9IEZpbmRWYXJpYWJsZUZlYXR1cmVzKG9iamVjdCA9IHhlbm8sbmZlYXR1cmVzID0gMjAwMCkKeGVub192YXJnZW5lcyA9IFZhcmlhYmxlRmVhdHVyZXMob2JqZWN0ID0geGVubykKCnhlbm9fZXhwcmVzc2lvbiA9IEZldGNoRGF0YShvYmplY3QgPSB4ZW5vLHZhcnMgPSB4ZW5vX3ZhcmdlbmVzLHNsb3Q9J2NvdW50cycpCmFsbF8wX2dlbmVzID0gY29sbmFtZXMoeGVub19leHByZXNzaW9uKVtjb2xTdW1zKHhlbm9fZXhwcmVzc2lvbj09MCwgbmEucm09VFJVRSk9PW5yb3coeGVub19leHByZXNzaW9uKV0gI2RlbGV0ZSByb3dzIHRoYXQgaGF2ZSBhbGwgMAp4ZW5vX3ZhcmdlbmVzID0geGVub192YXJnZW5lc1sheGVub192YXJnZW5lcyAlaW4lIGFsbF8wX2dlbmVzXQoKYGBgCgoKCiMgVGVzdCB3aXRoIGV4cHIgYWZ0ZXIgaGFybW9ueQpgYGB7cHl0aG9ufQojIGltcG9ydCBudW1weSBhcyBucAojIGltcG9ydCBzY2FucHkgYXMgc2MKIyAKIyBleHByX2FmdGVyX2hhcm1vbnkgPSBzYy5yZWFkX2g1YWQoJy4vRGF0YS9jbm1mL3hlbm9fSGFybW9ueV9Ob05lZ18yS3ZhcmdlbmVzLmg1YWQnKS50b19kZigpCiMgdHBtID0gIGNvbXB1dGVfdHBtKGV4cHJfYWZ0ZXJfaGFybW9ueSkKIyBjbm1mX2dlbmVzID0gZXhwcl9hZnRlcl9oYXJtb255LmtleXMoKS50b19saXN0KCkKIyB1c2FnZV9ieV9jYWxjID0gZ2V0X3VzYWdlX2Zyb21fc2NvcmUoY291bnRzPWV4cHJfYWZ0ZXJfaGFybW9ueSx0cG09dHBtLGdlbmVzPWNubWZfZ2VuZXMsY25tZl9vYmo9Y25tZl9vYmosaz0zKQpgYGAKCiMgQ2hlY2sgaWYgb3JpZ2luYWwgY05NRiBzY29yZSBpcyBsaWtlIHRoZSBjYWxjdWxhdGVkIHNjb3JlCmBgYHtyfQp1c2FnZV9ieV9jYWxjID0gcHkkdXNhZ2VfYnlfY2FsYwp1c2FnZV9ub3JtID0gcHkkdXNhZ2Vfbm9ybTMKY29yKHVzYWdlX2J5X2NhbGMsdXNhZ2Vfbm9ybSkKYGBgCgojIGNhbGN1bGF0ZSBzY29yZSBmb3IgWGVubwpgYGB7cHl0aG9ufQppbXBvcnQgbnVtcHkgYXMgbnAKaW1wb3J0IHNjYW5weSBhcyBzYwp4ZW5vX2V4cHJlc3Npb24gPSByLnhlbm9fZXhwcmVzc2lvbgp4ZW5vX3ZhcmdlbmVzID0gci54ZW5vX3ZhcmdlbmVzCnRwbSA9ICBjb21wdXRlX3RwbSh4ZW5vX2V4cHJlc3Npb24pCnVzYWdlX2J5X2NhbGMgPSBnZXRfdXNhZ2VfZnJvbV9zY29yZShjb3VudHM9eGVub19leHByZXNzaW9uLHRwbT10cG0sZ2VuZXM9eGVub192YXJnZW5lcywgY25tZl9vYmo9Y25tZl9vYmosaz0zKQpgYGAKCmBgYHtyfQp4ZW5vX3VzYWdlID0gcHkkdXNhZ2VfYnlfY2FsYwpgYGAKCiMgcHJvZ3JhbXMgZXhwcmVzc2lvbiB7LnRhYnNldH0KYGBge3IgZWNobz1UUlVFLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD05LCByZXN1bHRzPSdhc2lzJ30KCm5hbWVzICh4ZW5vX3VzYWdlKSA9IGMoIkh5cG94aWEiLCJUTkZhIiwiQ2VsbF9jeWNsZSIpCiNhZGQgZWFjaCBtZXRhZ2VuZSB0byBtZXRhZGF0YQpmb3IgKGkgIGluIDE6bmNvbCh4ZW5vX3VzYWdlKSkgewogIG1ldGFnZV9tZXRhZGF0YSA9IHhlbm9fdXNhZ2UgJT4lIGRwbHlyOjpzZWxlY3QoaSkKICB4ZW5vID0gQWRkTWV0YURhdGEob2JqZWN0ID0geGVubyxtZXRhZGF0YSA9IG1ldGFnZV9tZXRhZGF0YSxjb2wubmFtZSA9IG5hbWVzKHhlbm9fdXNhZ2UpW2ldKQp9CgpwcmludF90YWIocGx0ID0gRmVhdHVyZVBsb3Qob2JqZWN0ID0geGVubyxmZWF0dXJlcyA9IGNvbG5hbWVzKHhlbm9fdXNhZ2UpKSx0aXRsZSA9ICJ1bWFwIGV4cHJlc3Npb24iKQoKCmBgYAoKCgojIHByb2dyYW1zIHJlZ3VsYXRpb24gey50YWJzZXR9CmBgYHtyIGVjaG89VFJVRSwgIHJlc3VsdHM9J2FzaXMnfQptZXRhZ2VuZXNfbWVhbl9jb21wYXJlKGRhdGFzZXQgPSB4ZW5vLHRpbWUucG9pbnRfdmFyID0gInRyZWF0bWVudCIscHJlZml4ID0gIm1vZGVsIixwYXRpZW50LmlkZW50X3ZhciA9ICJvcmlnLmlkZW50IixwcmVfb24gPSBjKCJOVCIsIk9TSSIpLHRlc3QgPSAid2lsY294LnRlc3QiLHByb2dyYW1zID0gYygiSHlwb3hpYSIsIlRORmEiLCJDZWxsX2N5Y2xlIikpCgpgYGAKCmBgYHtyfQpEb3RQbG90KG9iamVjdCA9IHhlbm8sIGZlYXR1cmVzID0gIGMoIkh5cG94aWEiLCJUTkZhIiwiQ2VsbF9jeWNsZSIpLGdyb3VwLmJ5ICA9ICd0cmVhdG1lbnQnKQpgYGAKCgoKIyBDQyBzaWduYXR1cmUgIHsudGFic2V0fQpgYGB7ciBlY2hvPVRSVUUsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTEwLCByZXN1bHRzPSdhc2lzJ30KIyBnZXQgZ2VuZXMgYW5kIHBsb3QgY29yIGhlYXRtYXAKCnBsb3RfZ2VuZXNfY29yIDwtIGZ1bmN0aW9uKGRhdGFzZXQsaGFsbG1hcmtfbmFtZSxudW1fb2ZfY2x1c3RlcnMsZ2VuZUlkcyA9IE5VTEwpIHsKaWYoIWlzX251bGwoZ2VuZUlkcykpewogIGdlbmVJZHMgPSBnZW5lSWRzCn0KZWxzZXsKICBnZW5lSWRzPSBnZW5lc2V0c1tbaGFsbG1hcmtfbmFtZV1dQGdlbmVJZHMKfQpoYWxsbWFyc19leHAgPSBGZXRjaERhdGEob2JqZWN0ID0gZGF0YXNldCx2YXJzID0gYyhnZW5lSWRzKSkKaGFsbG1hcnNfZXhwID0gaGFsbG1hcnNfZXhwWyxjb2xTdW1zKGhhbGxtYXJzX2V4cFtdKT4wXSAjcmVtb3ZlIG5vIGV4cHJlc3Npb24gZ2VuZXMKaGFsbG1hcmtfY29yID0gY29yKGhhbGxtYXJzX2V4cCkKcGh0MSA9IHBoZWF0bWFwKG1hdCA9IGhhbGxtYXJrX2NvcixzaWxlbnQgPSBUKQoKIyBtYWtlIGFubm90YXRpb25zCm51bV9vZl9jbHVzdGVycyA9IG51bV9vZl9jbHVzdGVycwpjbHVzdGVyaW5nX2Rpc3RhbmNlID0gImV1Y2xpZGVhbiIKbXlhbm5vdGF0aW9uID0gYXMuZGF0YS5mcmFtZShjdXRyZWUocGh0MVtbInRyZWVfcm93Il1dLCBrID0gbnVtX29mX2NsdXN0ZXJzKSkgI3NwbGl0IGludG8gayBjbHVzdGVycwpuYW1lcyhteWFubm90YXRpb24pWzFdID0gImNsdXN0ZXIiCm15YW5ub3RhdGlvbiRjbHVzdGVyID0gYXMuZmFjdG9yKG15YW5ub3RhdGlvbiRjbHVzdGVyKQpwYWxldHRlMSA8LWJyZXdlci5wYWwobnVtX29mX2NsdXN0ZXJzLCAiUGFpcmVkIikKbmFtZXMocGFsZXR0ZTEpID0gdW5pcXVlKG15YW5ub3RhdGlvbiRjbHVzdGVyKQphbm5fY29sb3JzID0gbGlzdCAoY2x1c3RlciA9IHBhbGV0dGUxKQphbm5vdGF0aW9uID0gbGlzdChhbm5fY29sb3JzID0gYW5uX2NvbG9ycywgbXlhbm5vdGF0aW9uID0gbXlhbm5vdGF0aW9uKQoKI2Nob29zZSBjb2xvcnMKY29sb3JzIDwtIGMoc2VxKC0xLDEsYnk9MC4wMSkpCm15X3BhbGV0dGUgPC0gYygiYmx1ZSIsY29sb3JSYW1wUGFsZXR0ZShjb2xvcnMgPSBjKCJibHVlIiwgIndoaXRlIiwgInJlZCIpKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKG4gPSBsZW5ndGgoY29sb3JzKS0zKSwgInJlZCIpCgoKcHJpbnRfdGFiKHBsdCA9IAogICAgICAgICAgICAgIHBoZWF0bWFwKG1hdCA9IGhhbGxtYXJrX2Nvcixhbm5vdGF0aW9uX2NvbCA9ICBhbm5vdGF0aW9uW1sibXlhbm5vdGF0aW9uIl1dLCBhbm5vdGF0aW9uX2NvbG9ycyA9IGFubm90YXRpb25bWyJhbm5fY29sb3JzIl1dLCBjbHVzdGVyaW5nX2Rpc3RhbmNlX3Jvd3MgPSBjbHVzdGVyaW5nX2Rpc3RhbmNlLGNsdXN0ZXJpbmdfZGlzdGFuY2VfY29scyA9IGNsdXN0ZXJpbmdfZGlzdGFuY2UsY29sb3IgPSBteV9wYWxldHRlLGJyZWFrcyA9IGNvbG9ycyxzaG93X3Jvd25hbWVzID0gRixzaG93X2NvbG5hbWVzID0gRikKICAgICAgICAgICAgLHRpdGxlID0gImdlbmVzIGV4cHJlc3Npb24gaGVhdG1hcCIpCnJldHVybihhbm5vdGF0aW9uKQoKfQpgYGAKCmBgYHtyIHJlc3VsdHM9J2FzaXMnfQpoYWxsbWFya19uYW1lID0gIkhBTExNQVJLX0cyTV9DSEVDS1BPSU5UIgphbm5vdGF0aW9uID0gcGxvdF9nZW5lc19jb3IoZGF0YXNldCA9IHhlbm8saGFsbG1hcmtfbmFtZSA9IGhhbGxtYXJrX25hbWUsbnVtX29mX2NsdXN0ZXJzID0gNCkKYGBgCgpgYGB7ciByZXN1bHRzPSdhc2lzJ30KI2Nob29zZSBjbHVzdGVycwpjaG9zZW5fY2x1c3RlcnMgPSBjKDEsMikKcHJpbnQgKHBhc3RlKCJjaG9zZW5fY2x1c3RlcnMgPSAiLCBjaG9zZW5fY2x1c3RlcnMgJT4lIHRvU3RyaW5nKCkpKQoKI1VNQVAgZXhwcmVzc2lvbiBvZiBzaWduYXR1cmUKY2hvc2VuX2dlbmVzID0gYW5ub3RhdGlvbltbIm15YW5ub3RhdGlvbiJdXSAlPiUgZHBseXI6OmZpbHRlcihjbHVzdGVyICVpbiUgY2hvc2VuX2NsdXN0ZXJzKSAlPiUgcm93bmFtZXMoKSAjdGFrZSByZWxldmFudCBnZW5lcwpzY29yZSA8LSBhcHBseSh4ZW5vQGFzc2F5cyRSTkFAZGF0YVtjaG9zZW5fZ2VuZXMsXSwyLG1lYW4pCnhlbm89QWRkTWV0YURhdGEoeGVubyxzY29yZSxoYWxsbWFya19uYW1lKQpzY29yZXNBbmRJbmRpY2VzIDwtIGdldFBhdGh3YXlTY29yZXMoeGVub0Bhc3NheXMkUk5BQGRhdGEsIGNob3Nlbl9nZW5lcykKeGVubz1BZGRNZXRhRGF0YSh4ZW5vLHNjb3Jlc0FuZEluZGljZXMkcGF0aHdheVNjb3JlcyxwYXN0ZTAoaGFsbG1hcmtfbmFtZSwiX3NpcHNpYyIpKQpwcmludF90YWIoRmVhdHVyZVBsb3Qob2JqZWN0ID0geGVubywgZmVhdHVyZXMgPSBwYXN0ZTAoaGFsbG1hcmtfbmFtZSwiX3NpcHNpYyIpKSx0aXRsZSA9ICJFeHByZXNzaW9uIikKcHJpbnRfdGFiKEZlYXR1cmVQbG90KG9iamVjdCA9IHhlbm8sIGZlYXR1cmVzID0gaGFsbG1hcmtfbmFtZSksdGl0bGUgPSAiRXhwcmVzc2lvbiIpCmBgYAoKYGBge3IgZWNobz1UUlVFLCByZXN1bHRzPSdhc2lzJ30KCiNwbG90IHNpZ25hdHVyZSBkaXN0cmlidXRpb24KY2Nfc2NvcmVzID0gRmV0Y2hEYXRhKG9iamVjdCA9IHhlbm8sdmFycyA9ICJIQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVCIpCnBsdCAgPSAgZ2dwbG90KGNjX3Njb3JlcywgYWVzKHg9SEFMTE1BUktfRzJNX0NIRUNLUE9JTlQpKSArCiAgZ2VvbV9kZW5zaXR5KCkrCiAgIGdlb21fdmxpbmUoCiAgICBhZXMoeGludGVyY2VwdD1tZWFuKGNjX3Njb3JlcyRIQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVCkgKyBzZChjY19zY29yZXMkSEFMTE1BUktfRzJNX0NIRUNLUE9JTlQpICxjb2xvcj0iMSBTRCIpLAogICAgICAgICAgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkrCiAgICBnZW9tX3ZsaW5lKAogICAgYWVzKHhpbnRlcmNlcHQ9bWVhbihjY19zY29yZXMkSEFMTE1BUktfRzJNX0NIRUNLUE9JTlQpICsgMipzZChjY19zY29yZXMkSEFMTE1BUktfRzJNX0NIRUNLUE9JTlQpICxjb2xvcj0iMiBTRCIpLAogICAgICAgICAgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkKCnByaW50X3RhYihwbHQgPSBwbHQsdGl0bGUgPSAiZGlzdCIpCgojIFBsb3QgYXNzaWdubWVudCAKCmNjX3Njb3JlcyA9IGNjX3Njb3JlcyAlPiUgbXV0YXRlKGlzX2N5Y2xpbmcgPSBpZl9lbHNlKGNvbmRpdGlvbiA9IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBIQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVCA+IG1lYW4oSEFMTE1BUktfRzJNX0NIRUNLUE9JTlQpIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICArc2QoSEFMTE1BUktfRzJNX0NIRUNLUE9JTlQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJ1ZSA9ICJjeWNsaW5nIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhbHNlID0gIm5vbl9jeWNsaW5nIikpCnhlbm8gPSBBZGRNZXRhRGF0YShvYmplY3QgPSB4ZW5vLG1ldGFkYXRhID0gY2Nfc2NvcmVzJGlzX2N5Y2xpbmcsY29sLm5hbWUgPSAiaXNfY3ljbGluZyIpCnByaW50X3RhYihwbHQgPSBEaW1QbG90KG9iamVjdCA9IHhlbm8sZ3JvdXAuYnkgPSAiaXNfY3ljbGluZyIpICwgdGl0bGUgPSAiYXNzaWdubWVudCAxIHNkIikKCgojIGNjX3Njb3JlcyA9IGNjX3Njb3JlcyAlPiUgbXV0YXRlKGlzX2N5Y2xpbmcgPSBpZl9lbHNlKGNvbmRpdGlvbiA9IAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEhBTExNQVJLX0cyTV9DSEVDS1BPSU5UID4gbWVhbihIQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVCkgKyAyKnNkKGNjX3Njb3JlcyRIQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVCksCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRydWUgPSAiY3ljbGluZyIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhbHNlID0gIm5vbl9jeWNsaW5nIikpCiMgeGVubyA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IHhlbm8sbWV0YWRhdGEgPSBjY19zY29yZXMkaXNfY3ljbGluZyxjb2wubmFtZSA9ICJpc19jeWNsaW5nIikKIyBwcmludF90YWIocGx0ID0gRGltUGxvdChvYmplY3QgPSB4ZW5vLGdyb3VwLmJ5ID0gImlzX2N5Y2xpbmciKSAsIHRpdGxlID0gImFzc2lnbm1lbnQgMiBzZCIpCgoKYGBgCgoKCgpgYGB7ciBlY2hvPVRSVUUsIHJlc3VsdHM9J2FzaXMnfQogZGYgID0gRmV0Y2hEYXRhKG9iamVjdCA9IHhlbm8sdmFycyA9IGMoImlzX2N5Y2xpbmciLCJ0cmVhdG1lbnQiKSkgJT4lIAogICAgZmlsdGVyICh0cmVhdG1lbnQgJWluJSBjKCJOVCIsIk9TSSIpKSAlPiUgCiAgICBkcm9wbGV2ZWxzKCkgCiAgdGVzdCA9IGZpc2hlci50ZXN0KHRhYmxlKGRmKSkKICAgIAogIGxpYnJhcnkoZ2dzdGF0c3Bsb3QpCgogICAgcGx0ID0gZ2diYXJzdGF0cygKICAgIGRmLCBpc19jeWNsaW5nLCB0cmVhdG1lbnQsCiAgICByZXN1bHRzLnN1YnRpdGxlID0gRkFMU0UsCiAgICBzdWJ0aXRsZSA9IHBhc3RlMCgKICAgICAgIkZpc2hlcidzIGV4YWN0IHRlc3QiLCAiLCBwLXZhbHVlID0gIiwKICAgICAgIHJvdW5kKHRlc3QkcC52YWx1ZSwxMykpCiAgICApCiAgCnByaW50X3RhYihwbHQgPSBwbHQsdGl0bGUgPSAiZmlzaGVyIikKYGBgCiMjIGNvcnJlbGF0aW9uIHRvIG5tZiBwcm9ncmFtCmBgYHtyfQpjb3JfcmVzID0gY29yKHhlbm8kQ2VsbF9jeWNsZSx4ZW5vW1toYWxsbWFya19uYW1lXV0pCnByaW50KHBhc3RlKCJjb3JyZWxhdGlvbiBvZiBUTkZhIHByb2dyYW0gdG8iLCBoYWxsbWFya19uYW1lLCI6IiwgY29yX3JlcykpCgpjb3JfcmVzID0gY29yKHhlbm8kQ2VsbF9jeWNsZSx4ZW5vW1twYXN0ZTAoaGFsbG1hcmtfbmFtZSwiX3NpcHNpYyIpXV0pCnByaW50KHBhc3RlKCJjb3JyZWxhdGlvbiBvZiBDZWxsX2N5Y2xlIHByb2dyYW0gdG8iLCBwYXN0ZTAoaGFsbG1hcmtfbmFtZSwiX3NpcHNpYyIpLCI6IiwgY29yX3JlcykpCmBgYAoKCiMgVE5GYSBzaWduYXR1cmUgIHsudGFic2V0fQoKYGBge3IgcmVzdWx0cz0nYXNpcyd9CmhhbGxtYXJrX25hbWUgPSAiSEFMTE1BUktfVE5GQV9TSUdOQUxJTkdfVklBX05GS0IiCmFubm90YXRpb24gPSBwbG90X2dlbmVzX2NvcihkYXRhc2V0ID0geGVubyxoYWxsbWFya19uYW1lID0gaGFsbG1hcmtfbmFtZSxudW1fb2ZfY2x1c3RlcnMgPSA2KQoKCmBgYAoKCmBgYHtyIGVjaG89VFJVRSwgcmVzdWx0cz0nYXNpcyd9CmNob3Nlbl9jbHVzdGVycyA9IGMoMSw1KQpwcmludCAocGFzdGUoImNob3Nlbl9jbHVzdGVycyA9ICIsIGNob3Nlbl9jbHVzdGVycyAlPiUgdG9TdHJpbmcoKSkpCgojVU1BUCBleHByZXNzaW9uIG9mIHNpZ25hdHVyZQpjaG9zZW5fZ2VuZXMgPSBhbm5vdGF0aW9uW1sibXlhbm5vdGF0aW9uIl1dICU+JSBkcGx5cjo6ZmlsdGVyKGNsdXN0ZXIgJWluJSBjaG9zZW5fY2x1c3RlcnMpICU+JSByb3duYW1lcygpICN0YWtlIHJlbGV2YW50IGdlbmVzCnNjb3JlIDwtIGFwcGx5KHhlbm9AYXNzYXlzJFJOQUBkYXRhW2Nob3Nlbl9nZW5lcyxdLDIsbWVhbikKeGVubz1BZGRNZXRhRGF0YSh4ZW5vLHNjb3JlLGhhbGxtYXJrX25hbWUpCnNjb3Jlc0FuZEluZGljZXMgPC0gZ2V0UGF0aHdheVNjb3Jlcyh4ZW5vQGFzc2F5cyRSTkFAZGF0YSwgY2hvc2VuX2dlbmVzKQp4ZW5vPUFkZE1ldGFEYXRhKHhlbm8sc2NvcmVzQW5kSW5kaWNlcyRwYXRod2F5U2NvcmVzLHBhc3RlMChoYWxsbWFya19uYW1lLCJfc2lwc2ljIikpCnByaW50X3RhYihGZWF0dXJlUGxvdChvYmplY3QgPSB4ZW5vLCBmZWF0dXJlcyA9IHBhc3RlMChoYWxsbWFya19uYW1lLCJfc2lwc2ljIikpLHRpdGxlID0gIkV4cHJlc3Npb24iKQpwcmludF90YWIoRmVhdHVyZVBsb3Qob2JqZWN0ID0geGVubywgZmVhdHVyZXMgPSBoYWxsbWFya19uYW1lKSx0aXRsZSA9ICJFeHByZXNzaW9uIikKYGBgCiMjIGNvcnJlbGF0aW9uIHRvIG5tZiBwcm9ncmFtCgpgYGB7cn0KY29yX3JlcyA9IGNvcih4ZW5vJFRORmEseGVub1tbaGFsbG1hcmtfbmFtZV1dKQpwcmludChwYXN0ZSgiY29ycmVsYXRpb24gb2YgVE5GYSBwcm9ncmFtIHRvIiwgaGFsbG1hcmtfbmFtZSwiOiIsIGNvcl9yZXMpKQoKY29yX3JlcyA9IGNvcih4ZW5vJFRORmEseGVub1tbcGFzdGUwKGhhbGxtYXJrX25hbWUsIl9zaXBzaWMiKV1dKQpwcmludChwYXN0ZSgiY29ycmVsYXRpb24gb2YgVE5GYSBwcm9ncmFtIHRvIiwgcGFzdGUwKGhhbGxtYXJrX25hbWUsIl9zaXBzaWMiKSwiOiIsIGNvcl9yZXMpKQpgYGAKCmBgYHtyIGVjaG89VFJVRSwgcmVzdWx0cz0nYXNpcyd9CmNjX3Njb3JlcyA9IEZldGNoRGF0YShvYmplY3QgPSB4ZW5vLHZhcnMgPSBoYWxsbWFya19uYW1lKQoKcGx0ICA9ICBnZ3Bsb3QoY2Nfc2NvcmVzLCBhZXMoeD1IQUxMTUFSS19UTkZBX1NJR05BTElOR19WSUFfTkZLQikpICsKICBnZW9tX2RlbnNpdHkoKSsKICAgZ2VvbV92bGluZSgKICAgIGFlcyh4aW50ZXJjZXB0PW1lYW4oSEFMTE1BUktfVE5GQV9TSUdOQUxJTkdfVklBX05GS0IpICsgc2QoSEFMTE1BUktfVE5GQV9TSUdOQUxJTkdfVklBX05GS0IpICxjb2xvcj0iMSBTRCIpLAogICAgICAgICAgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkrCiAgICBnZW9tX3ZsaW5lKAogICAgYWVzKHhpbnRlcmNlcHQ9bWVhbihIQUxMTUFSS19UTkZBX1NJR05BTElOR19WSUFfTkZLQikgKyAyKnNkKEhBTExNQVJLX1RORkFfU0lHTkFMSU5HX1ZJQV9ORktCKSAsY29sb3I9IjIgU0QiKSwKICAgICAgICAgIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpKwogICAgZ2VvbV92bGluZSgKICAgIGFlcyh4aW50ZXJjZXB0PW1lYW4oSEFMTE1BUktfVE5GQV9TSUdOQUxJTkdfVklBX05GS0IpICxjb2xvcj0ibWVhbiIpLAogICAgICAgICAgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkKCnByaW50X3RhYihwbHQgPSBwbHQsdGl0bGUgPSAiZGlzdCIpCmBgYAoKCgojIHdlaWdodGVkIGtzIHRlc3QgICB7LnRhYnNldH0KYGBge3IgLHJlc3VsdHM9J2FzaXMnfQoKICAKcmFua2VkX2xpc3QxID0gZ2VwX3Njb3JlcyAlPiUgc2VsZWN0KDEpICU+JSBhc192ZWN0b3IoKSAlPiUgc2V0TmFtZXMocm93bmFtZXMoZ2VwX3Njb3JlcykpICU+JSBzb3J0KGRlY3JlYXNpbmcgPSBUUlVFKSAKcmFua2VkX2xpc3QyID0gZ2VwX3Njb3JlcyAlPiUgc2VsZWN0KDIpICU+JSBhc192ZWN0b3IoKSAlPiUgc2V0TmFtZXMocm93bmFtZXMoZ2VwX3Njb3JlcykpICU+JSBzb3J0KGRlY3JlYXNpbmcgPSBUUlVFKSAKcmFua2VkX2xpc3QzID0gZ2VwX3Njb3JlcyAlPiUgc2VsZWN0KDMpICU+JSBhc192ZWN0b3IoKSAlPiUgc2V0TmFtZXMocm93bmFtZXMoZ2VwX3Njb3JlcykpICU+JSBzb3J0KGRlY3JlYXNpbmcgPSBUUlVFKSAKCgoKcmFua2VkX2xpc3QgPSBsaXN0KCJnZXAxIiA9IHJhbmtlZF9saXN0MSwgImdlcDIiID0gcmFua2VkX2xpc3QyLCJnZXAzIiA9IHJhbmtlZF9saXN0MykKaHlwX29iaiA8LSBoeXBlUihyYW5rZWRfbGlzdCwgZ2VuZXNldHNfZW52LCB0ZXN0PSJrc3Rlc3QiLCBmZHI9MC4wNSwgcGxvdHRpbmc9RixiYWNrZ3JvdW5kID0gcm93bmFtZXMoZ2VwX3Njb3JlcykpCnBsb3RzID0gaHlwX2RvdHMoaHlwX29iaixzaXplX2J5ID0gIm5vbmUiKQpwcmludF90YWIocGx0ID0gcGxvdHNbWzFdXSx0aXRsZSA9ICJHRVAgMSIpCnByaW50X3RhYihwbHQgPSBwbG90c1tbMl1dLHRpdGxlID0gIkdFUCAyIikKcHJpbnRfdGFiKHBsdCA9IHBsb3RzW1szXV0sdGl0bGUgPSAiR0VQIDMiKQoKYGBgCgoKIyBBUEMgc2lnbmF0dXJlICB7LnRhYnNldH0KCmBgYHtyIHJlc3VsdHM9J2FzaXMnfQpoYWxsbWFya19uYW1lID0gIktFR0dfQU5USUdFTl9QUk9DRVNTSU5HX0FORF9QUkVTRU5UQVRJT04iCmFubm90YXRpb24gPSBwbG90X2dlbmVzX2NvcihkYXRhc2V0ID0geGVubyxoYWxsbWFya19uYW1lID0gaGFsbG1hcmtfbmFtZSxudW1fb2ZfY2x1c3RlcnMgPSA0LGNhbm9jaWNhbCA9IFQpCmBgYAoKCmBgYHtyIGVjaG89VFJVRSwgcmVzdWx0cz0nYXNpcyd9CmNob3Nlbl9jbHVzdGVycyA9IGMoMSwzKQpwcmludCAocGFzdGUoImNob3Nlbl9jbHVzdGVycyA9ICIsIGNob3Nlbl9jbHVzdGVycyAlPiUgdG9TdHJpbmcoKSkpCgojVU1BUCBleHByZXNzaW9uIG9mIHNpZ25hdHVyZQpjaG9zZW5fZ2VuZXMgPSBhbm5vdGF0aW9uW1sibXlhbm5vdGF0aW9uIl1dICU+JSBkcGx5cjo6ZmlsdGVyKGNsdXN0ZXIgJWluJSBjaG9zZW5fY2x1c3RlcnMpICU+JSByb3duYW1lcygpICN0YWtlIHJlbGV2YW50IGdlbmVzCnNjb3JlIDwtIGFwcGx5KHhlbm9AYXNzYXlzJFJOQUBkYXRhW2Nob3Nlbl9nZW5lcyxdLDIsbWVhbikKeGVubz1BZGRNZXRhRGF0YSh4ZW5vLHNjb3JlLGhhbGxtYXJrX25hbWUpCnNjb3Jlc0FuZEluZGljZXMgPC0gZ2V0UGF0aHdheVNjb3Jlcyh4ZW5vQGFzc2F5cyRSTkFAZGF0YSwgY2hvc2VuX2dlbmVzKQp4ZW5vPUFkZE1ldGFEYXRhKHhlbm8sc2NvcmVzQW5kSW5kaWNlcyRwYXRod2F5U2NvcmVzLHBhc3RlMChoYWxsbWFya19uYW1lLCJfc2lwc2ljIikpCnByaW50X3RhYihGZWF0dXJlUGxvdChvYmplY3QgPSB4ZW5vLCBmZWF0dXJlcyA9IHBhc3RlMChoYWxsbWFya19uYW1lLCJfc2lwc2ljIikpLHRpdGxlID0gIkV4cHJlc3Npb24iKQpwcmludF90YWIoRmVhdHVyZVBsb3Qob2JqZWN0ID0geGVubywgZmVhdHVyZXMgPSBoYWxsbWFya19uYW1lKSx0aXRsZSA9ICJFeHByZXNzaW9uIikKYGBgCgojIyBjb3JyZWxhdGlubyB0byBubWYKYGBge3J9CmNvcl9yZXMgPSBjb3IoeGVubyRUTkZhLHhlbm9bW2hhbGxtYXJrX25hbWVdXSkKcHJpbnQocGFzdGUoImNvcnJlbGF0aW9uIG9mIFRORmEgcHJvZ3JhbSB0byIsIGhhbGxtYXJrX25hbWUsIjoiLCBjb3JfcmVzKSkKCmNvcl9yZXMgPSBjb3IoeGVubyRUTkZhLHhlbm9bW3Bhc3RlMChoYWxsbWFya19uYW1lLCJfc2lwc2ljIildXSkKcHJpbnQocGFzdGUoImNvcnJlbGF0aW9uIG9mIFRORmEgcHJvZ3JhbSB0byIsIHBhc3RlMChoYWxsbWFya19uYW1lLCJfc2lwc2ljIiksIjoiLCBjb3JfcmVzKSkKYGBgCgojIFNpZ25hdHVyZXMgcmVndWxhdGlvbiB7LnRhYnNldH0KYGBge3IgZWNobz1UUlVFLCByZXN1bHRzPSdhc2lzJ30KbWV0YWdlbmVzX21lYW5fY29tcGFyZShkYXRhc2V0ID0geGVubyx0aW1lLnBvaW50X3ZhciA9ICJ0cmVhdG1lbnQiLHByZWZpeCA9ICJtb2RlbCIscGF0aWVudC5pZGVudF92YXIgPSAib3JpZy5pZGVudCIscHJlX29uID0gYygiTlQiLCJPU0kiLCJyZXMiKSxwcm9ncmFtcyA9IGMoIlRORmEiLCJIQUxMTUFSS19UTkZBX1NJR05BTElOR19WSUFfTkZLQiIsIktFR0dfQU5USUdFTl9QUk9DRVNTSU5HX0FORF9QUkVTRU5UQVRJT04iKSkKCmBgYAogICAKIyBpbnRlcnNlY3Rpb24gey50YWJzZXR9CgpgYGB7ciByZXN1bHRzPSdhc2lzJ30KdG9wX290ID0gZ2VwX3Njb3JlczNbb3JkZXIoZ2VwX3Njb3JlczNbLDJdLGRlY3JlYXNpbmcgPSBUKSwyLGRyb3AgPSBGXSU+JSBoZWFkKDIwMCkgJT4lIHJvd25hbWVzKCkKaGFsbG1hcmtfbmFtZSA9ICJLRUdHX0FOVElHRU5fUFJPQ0VTU0lOR19BTkRfUFJFU0VOVEFUSU9OIgpnZW5lSWRzPSBnZW5lc2V0c1tbaGFsbG1hcmtfbmFtZV1dCmNob3Nlbl9nZW5lcyA9IGludGVyc2VjdChnZW5lSWRzLHRvcF9vdCkKcHJpbnQoY2hvc2VuX2dlbmVzKQpzY29yZSA8LSBhcHBseSh4ZW5vQGFzc2F5cyRSTkFAZGF0YVtjaG9zZW5fZ2VuZXMsXSwyLG1lYW4pCnhlbm89QWRkTWV0YURhdGEoeGVubyxzY29yZSxwYXN0ZTAoaGFsbG1hcmtfbmFtZSwiaW50ZXJzZWN0ZWQiKSkKc2NvcmVzQW5kSW5kaWNlcyA8LSBnZXRQYXRod2F5U2NvcmVzKHhlbm9AYXNzYXlzJFJOQUBkYXRhLCBjaG9zZW5fZ2VuZXMpCnhlbm89QWRkTWV0YURhdGEoeGVubyxzY29yZXNBbmRJbmRpY2VzJHBhdGh3YXlTY29yZXMscGFzdGUwKGhhbGxtYXJrX25hbWUsIl9pbnRlcnNlY3RlZF9zaXBzaWMiKSkKcHJpbnRfdGFiKEZlYXR1cmVQbG90KG9iamVjdCA9IHhlbm8sIGZlYXR1cmVzID0gcGFzdGUwKGhhbGxtYXJrX25hbWUsIl9pbnRlcnNlY3RlZF9zaXBzaWMiKSksdGl0bGUgPSAiRXhwcmVzc2lvbiIpCnByaW50X3RhYihGZWF0dXJlUGxvdChvYmplY3QgPSB4ZW5vLCBmZWF0dXJlcyA9IHBhc3RlMChoYWxsbWFya19uYW1lLCJpbnRlcnNlY3RlZCIpKSx0aXRsZSA9ICJFeHByZXNzaW9uIikKYGBgCgpgYGB7cn0KY29yX3JlcyA9IGNvcih4ZW5vJFRORmEseGVub1tbcGFzdGUwKGhhbGxtYXJrX25hbWUsImludGVyc2VjdGVkIildXSkKcHJpbnQocGFzdGUoImNvcnJlbGF0aW9uIG9mIFRORmEgcHJvZ3JhbSB0byIsIHBhc3RlMChoYWxsbWFya19uYW1lLCJpbnRlcnNlY3RlZCIpLCI6IiwgY29yX3JlcykpCgpgYGAKCmBgYHtyfQp0b3Bfb3QgPSBnZXBfc2NvcmVzM1tvcmRlcihnZXBfc2NvcmVzM1ssMl0sZGVjcmVhc2luZyA9IFQpLDIsZHJvcCA9IEZdJT4lIGhlYWQoMjAwKSAlPiUgcm93bmFtZXMoKQpoYWxsbWFya19uYW1lID0gIkhBTExNQVJLX1RORkFfU0lHTkFMSU5HX1ZJQV9ORktCIgpnZW5lSWRzPSBnZW5lc2V0c1tbaGFsbG1hcmtfbmFtZV1dCmNob3Nlbl9nZW5lcyA9IGludGVyc2VjdChnZW5lSWRzLHRvcF9vdCkKcHJpbnQoY2hvc2VuX2dlbmVzKQpzY29yZSA8LSBhcHBseSh4ZW5vQGFzc2F5cyRSTkFAZGF0YVtjaG9zZW5fZ2VuZXMsXSwyLG1lYW4pCnhlbm89QWRkTWV0YURhdGEoeGVubyxzY29yZSxwYXN0ZTAoaGFsbG1hcmtfbmFtZSwiaW50ZXJzZWN0ZWQiKSkKc2NvcmVzQW5kSW5kaWNlcyA8LSBnZXRQYXRod2F5U2NvcmVzKHhlbm9AYXNzYXlzJFJOQUBkYXRhLCBjaG9zZW5fZ2VuZXMpCnhlbm89QWRkTWV0YURhdGEoeGVubyxzY29yZXNBbmRJbmRpY2VzJHBhdGh3YXlTY29yZXMscGFzdGUwKGhhbGxtYXJrX25hbWUsIl9pbnRlcnNlY3RlZF9zaXBzaWMiKSkKcHJpbnRfdGFiKEZlYXR1cmVQbG90KG9iamVjdCA9IHhlbm8sIGZlYXR1cmVzID0gcGFzdGUwKGhhbGxtYXJrX25hbWUsIl9pbnRlcnNlY3RlZF9zaXBzaWMiKSksdGl0bGUgPSAiRXhwcmVzc2lvbiIpCnByaW50X3RhYihGZWF0dXJlUGxvdChvYmplY3QgPSB4ZW5vLCBmZWF0dXJlcyA9IHBhc3RlMChoYWxsbWFya19uYW1lLCJpbnRlcnNlY3RlZCIpKSx0aXRsZSA9ICJFeHByZXNzaW9uIikKYGBgCmBgYHtyfQpjb3JfcmVzID0gY29yKHhlbm8kVE5GYSx4ZW5vW1twYXN0ZTAoaGFsbG1hcmtfbmFtZSwiaW50ZXJzZWN0ZWQiKV1dKQpwcmludChwYXN0ZSgiY29ycmVsYXRpb24gb2YgVE5GYSBwcm9ncmFtIHRvIiwgcGFzdGUwKGhhbGxtYXJrX25hbWUsImludGVyc2VjdGVkIiksIjoiLCBjb3JfcmVzKSkKCmBgYAojICBOb3JtIHBhdGh3YXlzICB7LnRhYnNldH0KYGBge3IgZmlnLndpZHRoPTEwfQpzdW1fc2NvcmVzPSB4ZW5vJEhJRl90YXJnZXRzK3hlbm8kS0VHR19BTlRJR0VOX1BST0NFU1NJTkdfQU5EX1BSRVNFTlRBVElPTit4ZW5vJEhBTExNQVJLX0cyTV9DSEVDS1BPSU5UCgpuZXdfc2NvcmUgPSB4ZW5vJEtFR0dfQU5USUdFTl9QUk9DRVNTSU5HX0FORF9QUkVTRU5UQVRJT04vIHN1bV9zY29yZXMKeGVubyAlPD4lIEFkZE1ldGFEYXRhKG1ldGFkYXRhID0gbmV3X3Njb3JlLGNvbC5uYW1lID0gIktFR0dfQU5USUdFTl9QUk9DRVNTSU5HX0FORF9QUkVTRU5UQVRJT05fbm9ybSIpCgpuZXdfc2NvcmUgPSAoeGVubyRISUZfdGFyZ2V0cy8gc3VtX3Njb3JlcyklPiUgcmVwbGFjZShpcy5uYSguKSwgMCkKeGVubyAlPD4lIEFkZE1ldGFEYXRhKG1ldGFkYXRhID0gbmV3X3Njb3JlLGNvbC5uYW1lID0gIkhJRl90YXJnZXRzX25vcm0iKQoKbmV3X3Njb3JlID0geGVubyRIQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVC8gc3VtX3Njb3Jlcwp4ZW5vICU8PiUgQWRkTWV0YURhdGEobWV0YWRhdGEgPSBuZXdfc2NvcmUsY29sLm5hbWUgPSAiSEFMTE1BUktfRzJNX25vcm0iKQpGZWF0dXJlUGxvdChvYmplY3QgPSB4ZW5vLGZlYXR1cmVzID0gYygiSEFMTE1BUktfRzJNX25vcm0iLCAiS0VHR19BTlRJR0VOX1BST0NFU1NJTkdfQU5EX1BSRVNFTlRBVElPTl9ub3JtIiwiSElGX3RhcmdldHNfbm9ybSIpKQpgYGAKCmBgYHtyIGVjaG89VFJVRSwgcmVzdWx0cz0nYXNpcyd9Cm1ldGFnZW5lc19tZWFuX2NvbXBhcmUoZGF0YXNldCA9IHhlbm8sdGltZS5wb2ludF92YXIgPSAidHJlYXRtZW50IixwcmVmaXggPSAibW9kZWwiLHBhdGllbnQuaWRlbnRfdmFyID0gIm9yaWcuaWRlbnQiLHByZV9vbiA9IGMoIk5UIiwiT1NJIiwicmVzIikscHJvZ3JhbXMgPSBjKCJUTkZhIiwiSEFMTE1BUktfVE5GQV9TSUdOQUxJTkdfVklBX05GS0IiLCJLRUdHX0FOVElHRU5fUFJPQ0VTU0lOR19BTkRfUFJFU0VOVEFUSU9OIiwiS0VHR19BTlRJR0VOX1BST0NFU1NJTkdfQU5EX1BSRVNFTlRBVElPTl9ub3JtIikpCgpgYGAKCiMgcHJvZ3JhbSAyIGNsdXN0ZXJpbmcKYGBge3J9Cm51bV9vZl9jbHVzdGVycyA9IDcKYW5ub3RhdGlvbiA9IHBsb3RfZ2VuZXNfY29yKGRhdGFzZXQgPSB4ZW5vLGhhbGxtYXJrX25hbWUgPSBOVUxMLG51bV9vZl9jbHVzdGVycyA9IG51bV9vZl9jbHVzdGVycyxnZW5lSWRzID0gdG9wX290KQpgYGAKCiMgYWxsIGNsdXN0ZXJzIGV4cHJlc3Npb24gey50YWJzZXR9CmBgYHtyIHJlc3VsdHM9J2FzaXMnLGZpZy53aWR0aD0xNH0KZm9yIChjaG9zZW5fY2x1c3RlcnMgaW4gMTpudW1fb2ZfY2x1c3RlcnMpIHsKICBjaG9zZW5fZ2VuZXMgPSBhbm5vdGF0aW9uW1sibXlhbm5vdGF0aW9uIl1dICU+JSBkcGx5cjo6ZmlsdGVyKGNsdXN0ZXIgPT0gY2hvc2VuX2NsdXN0ZXJzKSAlPiUgcm93bmFtZXMoKSAjdGFrZSByZWxldmFudCBnZW5lcwogICMgcHJpbnQoY2hvc2VuX2dlbmVzKQogIGh5cF9vYmogPC0gaHlwZVIoY2hvc2VuX2dlbmVzLCBnZW5lc2V0c19lbnYsIHRlc3QgPSAiaHlwZXJnZW9tZXRyaWMiLCBmZHI9MSwgcGxvdHRpbmc9RixiYWNrZ3JvdW5kID0gcm93bmFtZXMoZ2VwX3Njb3JlcykpCgogICBzY29yZXNBbmRJbmRpY2VzIDwtIGdldFBhdGh3YXlTY29yZXMoeGVub0Bhc3NheXMkUk5BQGRhdGEsIGNob3Nlbl9nZW5lcykKICB4ZW5vPUFkZE1ldGFEYXRhKHhlbm8sc2NvcmVzQW5kSW5kaWNlcyRwYXRod2F5U2NvcmVzLHBhc3RlMCgiY2x1c3RlciIsY2hvc2VuX2NsdXN0ZXJzKSkKCiAgCiAgcHJpbnRfdGFiKHBsdCA9IAogICAgICAgICAgICAgIGh5cF9kb3RzKGh5cF9vYmosc2l6ZV9ieSA9ICJub25lIix0aXRsZSA9IHBhc3RlMCgiY2x1c3RlciIsY2hvc2VuX2NsdXN0ZXJzKSkrCiAgICAgICAgICAgICAgRmVhdHVyZVBsb3Qob2JqZWN0ID0geGVubyxmZWF0dXJlcyA9IHBhc3RlMCgiY2x1c3RlciIsY2hvc2VuX2NsdXN0ZXJzKSksCiAgICAgICAgICAgIHRpdGxlID0gY2hvc2VuX2NsdXN0ZXJzKQogIAogIGNvcl9yZXMgPSBjb3IoeGVubyRUTkZhLHhlbm9bW3Bhc3RlMCgiY2x1c3RlciIsY2hvc2VuX2NsdXN0ZXJzKV1dKQojIHByaW50KHBhc3RlKCJjb3JyZWxhdGlvbiBvZiBUTkZhIHByb2dyYW0gdG8iLCBwYXN0ZTAoImNsdXN0ZXIiLGNob3Nlbl9jbHVzdGVycyksIjoiLCBjb3JfcmVzKSkKCgp9CgoKYGBgCiMgY29ycmVsYXRpb24gb2YgYWxsIGNsdXN0ZXJzCmBgYHtyICxmaWcud2lkdGg9MTR9CmZvciAoY2hvc2VuX2NsdXN0ZXJzIGluIDE6bnVtX29mX2NsdXN0ZXJzKSB7CiAgY2hvc2VuX2dlbmVzID0gYW5ub3RhdGlvbltbIm15YW5ub3RhdGlvbiJdXSAlPiUgZHBseXI6OmZpbHRlcihjbHVzdGVyID09IGNob3Nlbl9jbHVzdGVycykgJT4lIHJvd25hbWVzKCkgI3Rha2UgcmVsZXZhbnQgZ2VuZXMKICBjb3JfcmVzID0gY29yKHhlbm8kVE5GYSx4ZW5vW1twYXN0ZTAoImNsdXN0ZXIiLGNob3Nlbl9jbHVzdGVycyldXSkKICBwcmludChwYXN0ZSgiY29ycmVsYXRpb24gb2YgVE5GYSBwcm9ncmFtIHRvIiwgcGFzdGUwKCJjbHVzdGVyIixjaG9zZW5fY2x1c3RlcnMpLCI6IiwgY29yX3JlcykpCgp9CgoKYGBgCiMgY2x1c3RlcnMgNCBhbmQgNSAKYGBge3IgZmlnLndpZHRoPTE0fQpjaG9zZW5fY2x1c3RlcnMgPSBjKDQsNSkKICBjaG9zZW5fZ2VuZXMgPSBhbm5vdGF0aW9uW1sibXlhbm5vdGF0aW9uIl1dICU+JSBkcGx5cjo6ZmlsdGVyKGNsdXN0ZXIgJWluJSBjaG9zZW5fY2x1c3RlcnMpICU+JSByb3duYW1lcygpICN0YWtlIHJlbGV2YW50IGdlbmVzCiAgCiAgaHlwX29iaiA8LSBoeXBlUihjaG9zZW5fZ2VuZXMsIGdlbmVzZXRzX2VudiwgdGVzdCA9ICJoeXBlcmdlb21ldHJpYyIsIGZkcj0xLCBwbG90dGluZz1GLGJhY2tncm91bmQgPSByb3duYW1lcyhnZXBfc2NvcmVzKSkKCiAgIHNjb3Jlc0FuZEluZGljZXMgPC0gZ2V0UGF0aHdheVNjb3Jlcyh4ZW5vQGFzc2F5cyRSTkFAZGF0YSwgY2hvc2VuX2dlbmVzKQogICBzY29yZV9uYW1lID0gcGFzdGUwKCJjbHVzdGVyXyIsIHBhc3RlMChjaG9zZW5fY2x1c3RlcnMsIGNvbGxhcHNlID0gIl8iKSkKICB4ZW5vPUFkZE1ldGFEYXRhKHhlbm8sc2NvcmVzQW5kSW5kaWNlcyRwYXRod2F5U2NvcmVzLHNjb3JlX25hbWUpCgogIGh5cF9kb3RzKGh5cF9vYmosc2l6ZV9ieSA9ICJub25lIikrCiAgICBGZWF0dXJlUGxvdChvYmplY3QgPSB4ZW5vLGZlYXR1cmVzID0gc2NvcmVfbmFtZSkKCiAgY29yX3JlcyA9IGNvcih4ZW5vJFRORmEseGVub1tbc2NvcmVfbmFtZV1dKQpwcmludChwYXN0ZSgiY29ycmVsYXRpb24gb2YgVE5GYSBwcm9ncmFtIHRvIiwgc2NvcmVfbmFtZSwiOiIsIGNvcl9yZXMpKQpgYGAKIyBUaXRsZSB7LnRhYnNldH0KCgpgYGB7ciByZXN1bHRzPSdhc2lzJ30KbGlicmFyeShiaW9tYVJ0KQplbnNlbWJsID0gdXNlRW5zZW1ibChiaW9tYXJ0PSJlbnNlbWJsIiwgZGF0YXNldD0iaHNhcGllbnNfZ2VuZV9lbnNlbWJsIikKCmZvciAoY2hvc2VuX2NsdXN0ZXJzIGluIDE6bnVtX29mX2NsdXN0ZXJzKSB7CiAgY2hvc2VuX2dlbmVzID0gYW5ub3RhdGlvbltbIm15YW5ub3RhdGlvbiJdXSAlPiUgZHBseXI6OmZpbHRlcihjbHVzdGVyID09IGNob3Nlbl9jbHVzdGVycykgJT4lIHJvd25hbWVzKCkgI3Rha2UgcmVsZXZhbnQgZ2VuZXMKICBnZW5lZGVzYyA8LSBnZXRCTShhdHRyaWJ1dGVzPWMoJ2V4dGVybmFsX2dlbmVfbmFtZScsJ3dpa2lnZW5lX2Rlc2NyaXB0aW9uJywiaW50ZXJwcm9fZGVzY3JpcHRpb24iKSwgZmlsdGVycyA9ICdleHRlcm5hbF9nZW5lX25hbWUnLCB2YWx1ZXMgPSBjaG9zZW5fZ2VuZXMsIG1hcnQgPWVuc2VtYmwpICAKICBwcmludF90YWIoZ2VuZWRlc2MsdGl0bGUgPSBjaG9zZW5fY2x1c3RlcnMpCn0KCgpgYGAKCiMgUHJvZ3JhbXMgcmVndWxhdGlvbiB7LnRhYnNldH0KYGBge3IgZWNobz1UUlVFLCByZXN1bHRzPSdhc2lzJ30KbWV0YWdlbmVzX21lYW5fY29tcGFyZShkYXRhc2V0ID0geGVubyx0aW1lLnBvaW50X3ZhciA9ICJ0cmVhdG1lbnQiLHByZWZpeCA9ICJtb2RlbCIscGF0aWVudC5pZGVudF92YXIgPSAib3JpZy5pZGVudCIscHJlX29uID0gYygiTlQiLCJPU0kiLCJyZXMiKSxwcm9ncmFtcyA9IGMoIlRORmEiLCJIQUxMTUFSS19UTkZBX1NJR05BTElOR19WSUFfTkZLQiIsIktFR0dfQU5USUdFTl9QUk9DRVNTSU5HX0FORF9QUkVTRU5UQVRJT04iLCJLRUdHX0FOVElHRU5fUFJPQ0VTU0lOR19BTkRfUFJFU0VOVEFUSU9OaW50ZXJzZWN0ZWQiLCJjbHVzdGVyXzRfNSIsImNsdXN0ZXI3IikpCgpgYGAKCiMgSElGX3RhcmdldHMtIEh5cG94aWEgY29ycmVsYXRpb24gIHsudGFic2V0fQpgYGB7ciBlY2hvPVRSVUUsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTYsIHJlc3VsdHM9J2FzaXMnfQojIHBsb3QgY29ycmVsYXRpb24gZm9yIGV2ZXJ5IHN1YnNldCBvZiBoaWYgdGFyZ2V0cwpmb3IgKGdlbmVzIGluIGxpc3QoaGlmX3RhcmdldHMseGVub19jbHVzdGVyXzNfZ2VuZXMseGVub19jbHVzdGVyXzNfMl9nZW5lcykpIHsKICBoaWZfdGFyZ2V0c19ieV90cCA9IEZldGNoRGF0YShvYmplY3QgPSB4ZW5vLHZhcnMgPSBjKGdlbmVzKSkgJT4lIHJvd1N1bXMoKSAlPiUgYXMuZGF0YS5mcmFtZSgpICNtZWFuIGV4cHJlc3Npb24KICBoaWZfdGFyZ2V0c19ieV90cFssMl0gPSB4ZW5vJEh5cG94aWEKICAKICBuYW1lcyhoaWZfdGFyZ2V0c19ieV90cCkgPSBjKCJoaWZfdGFyZ2V0cyIsImh5cG94aWFfcHJvZ3JhbSIpCiAgCiAgCiAgCiAgcDEgPSBnZ3Bsb3QoaGlmX3RhcmdldHNfYnlfdHAsIGFlcyh4PWhpZl90YXJnZXRzLCB5PWh5cG94aWFfcHJvZ3JhbSkpICsgCiAgICAgIGdlb21fcG9pbnQoKSsKICAgIGdlb21fZGVuc2l0eV8yZChhZXMoY29sb3IgPSAuLmxldmVsLi4pKSArCiAgICBnZW9tX3Ntb290aChtZXRob2Q9bG0pICsKICAgIHN0YXRfY29yKG1ldGhvZCA9ICJwZWFyc29uIiwgbGFiZWwueCA9IDIwLCBsYWJlbC55ID0gMS4xKSsKICAgIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYygpCiAgCiAgcDIgPSBnZ3Bsb3QoaGlmX3RhcmdldHNfYnlfdHAsIGFlcyh4PWhpZl90YXJnZXRzLCB5PWh5cG94aWFfcHJvZ3JhbSkpICsgCiAgICBnZW9tX2JpbjJkKCkgKwogICAgdGhlbWVfYncoKSsgc2NhbGVfZmlsbF9ncmFkaWVudG4obGltaXRzPWMoMCwxMTAwKSwgYnJlYWtzPXNlcSgwLCAxMTAwLCBieT0yMDApLCBjb2xvdXJzPWMoImJsdWUiLCJ5ZWxsb3ciLCJyZWQiKSkrIAogICAgc3RhdF9jb3IobWV0aG9kID0gInBlYXJzb24iLCBsYWJlbC54ID0gMjAsIGxhYmVsLnkgPSAxLjEpKwogICAgZ2VvbV9zbW9vdGgobWV0aG9kPWxtKSAKICAKICBwID0gZ2dhcnJhbmdlKHBsb3RsaXN0ID0gbGlzdChwMSxwMiksbnJvdyAgPSAyKSAgCiAgCiAgcHJpbnRfdGFiKHBsdCA9IHAsdGl0bGUgPSAiZ2VvbV9iaW4yZCIpCn0KCgpgYGAKCiMgVU1BUFMKYGBge3IgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9MTB9CmhpZl90YXJnZXRzX2J5X3RwID0gRmV0Y2hEYXRhKG9iamVjdCA9IHhlbm8sdmFycyA9IGMoaGlmX3RhcmdldHMpKSAlPiUgcm93U3VtcygpICU+JSBhcy5kYXRhLmZyYW1lKCkgI21lYW4gZXhwcmVzc2lvbgpoaWZfdGFyZ2V0c19ieV90cFssMl0gPSB4ZW5vJEh5cG94aWEKbmFtZXMoaGlmX3RhcmdldHNfYnlfdHApID0gYygiaGlmX3RhcmdldHMiLCJoeXBveGlhX3Byb2dyYW0iKQoKaGlnaF9oaWZfbG93X2h5cG94aWFfY2VsbHMgPSBoaWZfdGFyZ2V0c19ieV90cCAlPiUgZmlsdGVyKGhpZl90YXJnZXRzPjI1ICYgaHlwb3hpYV9wcm9ncmFtIDwgMC4yKSAlPiUgcm93bmFtZXMoKQpsb3dfaGlmX2hpZ2hfaHlwb3hpYV9jZWxscyA9IGhpZl90YXJnZXRzX2J5X3RwICU+JSBmaWx0ZXIoaGlmX3RhcmdldHM8MTUgJiBoeXBveGlhX3Byb2dyYW0gPiAwLjYpICU+JSByb3duYW1lcygpCgpoaWZfdGFyZ2V0c19ieV90cCA9IEZldGNoRGF0YShvYmplY3QgPSB4ZW5vLHZhcnMgPSBjKGhpZl90YXJnZXRzKSkgJT4lIHJvd1N1bXMoKSAlPiUgYXMuZGF0YS5mcmFtZSgpICNtZWFuIGV4cHJlc3Npb24KeGVubyA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IHhlbm8sIG1ldGFkYXRhID0gaGlmX3RhcmdldHNfYnlfdHAsY29sLm5hbWUgPSAiSElGX3RhcmdldHNfc2NvcmUiKQpjZWxsc190b19oaWdobGlnaHQgPSAgbGlzdChoaWdoX2hpZl9sb3dfaHlwb3hpYV9jZWxscyA9IGhpZ2hfaGlmX2xvd19oeXBveGlhX2NlbGxzLCBsb3dfaGlmX2hpZ2hfaHlwb3hpYV9jZWxscyA9IGxvd19oaWZfaGlnaF9oeXBveGlhX2NlbGxzKQoKRGltUGxvdChvYmplY3QgPSB4ZW5vLCBjZWxscy5oaWdobGlnaHQgPSBjZWxsc190b19oaWdobGlnaHQsIGNvbHMuaGlnaGxpZ2h0ID0gYygicmVkIiwiYmx1ZSIpLCBjb2xzID0gImdyYXkiLCBvcmRlciA9IFRSVUUpCkZlYXR1cmVQbG90KG9iamVjdCA9IHhlbm8sZmVhdHVyZXMgPSBjKCAiSElGX3RhcmdldHNfc2NvcmUiLCJIeXBveGlhIiwiQ2VsbF9jeWNsZSIgKSkKCmBgYApgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMH0KaGlmX2h5cG94aWFfY29ycmVsYXRlZF9jZWxscyA9IGNvbG5hbWVzKHhlbm8pIFshY29sbmFtZXMoeGVubykgJWluJSBoaWdoX2hpZl9sb3dfaHlwb3hpYV9jZWxscyAmICFjb2xuYW1lcyh4ZW5vKSAlaW4lIGhpZ2hfaGlmX2xvd19oeXBveGlhX2NlbGxzXQpoaWZfdGFyZ2V0c19zY29yZSA9IEZldGNoRGF0YShvYmplY3QgPSB4ZW5vLHZhcnMgPSBjKGhpZl90YXJnZXRzKSkgJT4lIHJvd1N1bXMoKSAlPiUgYXMuZGF0YS5mcmFtZSgpICNtZWFuIGV4cHJlc3Npb24KaGlmX3RhcmdldHNfc2NvcmVbLDJdID0geGVubyRIeXBveGlhCm5hbWVzKGhpZl90YXJnZXRzX3Njb3JlKSA9IGMoImhpZl90YXJnZXRzIiwiaHlwb3hpYV9wcm9ncmFtIikKaGlmX3RhcmdldHNfc2NvcmUgID0gaGlmX3RhcmdldHNfc2NvcmUgJT4lIG11dGF0ZSh0eXBlID0gY2FzZV93aGVuKGhpZl90YXJnZXRzPjI1ICYgaHlwb3hpYV9wcm9ncmFtIDwgMC4yIH4gImhpZ2hfaGlmX2xvd19oeXBveGlhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhpZl90YXJnZXRzPDE1ICYgaHlwb3hpYV9wcm9ncmFtID4gMC42IH4gImxvd19oaWZfaGlnaF9oeXBveGlhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhpZl90YXJnZXRzPjI1ICYgaHlwb3hpYV9wcm9ncmFtID4gMC42IH4gImhpZ2hfaGlmX2hpZ2hfaHlwb3hpYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoaWZfdGFyZ2V0czwxNSAmIGh5cG94aWFfcHJvZ3JhbSA8MC4yIH4gImhpZ2hfaGlmX2hpZ2hfaHlwb3hpYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIm90aGVyIikpCnhlbm8gPSBBZGRNZXRhRGF0YShvYmplY3QgPSB4ZW5vLG1ldGFkYXRhID0gaGlmX3RhcmdldHNfc2NvcmVbLCJ0eXBlIiwgZHJvcCA9IEZdLGNvbC5uYW1lID0gInNjb3JlX2NvcnJlbGF0aW9uIikKeGVubyA9IFNldElkZW50KG9iamVjdCA9IHhlbm8sdmFsdWUgPSAic2NvcmVfY29ycmVsYXRpb24iKQpEaW1QbG90KG9iamVjdCA9IHhlbm8sZ3JvdXAuYnkgPSAic2NvcmVfY29ycmVsYXRpb24iKQptYXJrZXJzID0gRmluZE1hcmtlcnMob2JqZWN0ID0geGVubywgaWRlbnQuMSA9ICJoaWdoX2hpZl9sb3dfaHlwb3hpYSIsaWRlbnQuMiA9ICJoaWdoX2hpZl9oaWdoX2h5cG94aWEiLGRlbnNpZnkgPSBUKQpgYGAKYGBge3IgZWNobz1UUlVFLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD02LCByZXN1bHRzPSdhc2lzJ30KdXBkZWcgPSBtYXJrZXJzICU+JSBmaWx0ZXIocF92YWxfYWRqPDAuMDUgJiBhdmdfbG9nMkZDPjApICU+JSByb3duYW1lcygpCgpuZXdfaGlmX3RhcmdldHMgPSBoaWZfdGFyZ2V0c1shaGlmX3RhcmdldHMgJWluJSB1cGRlZ10KaGlmX3RhcmdldHNfYnlfdHAgPSBGZXRjaERhdGEob2JqZWN0ID0geGVubyx2YXJzID0gYyhuZXdfaGlmX3RhcmdldHMpKSAlPiUgcm93U3VtcygpICU+JSBhcy5kYXRhLmZyYW1lKCkgI21lYW4gZXhwcmVzc2lvbgogIGhpZl90YXJnZXRzX2J5X3RwWywyXSA9IHhlbm8kSHlwb3hpYQogIAogIG5hbWVzKGhpZl90YXJnZXRzX2J5X3RwKSA9IGMoImhpZl90YXJnZXRzIiwiaHlwb3hpYV9wcm9ncmFtIikKICAKICAKICAKICBwMSA9IGdncGxvdChoaWZfdGFyZ2V0c19ieV90cCwgYWVzKHg9aGlmX3RhcmdldHMsIHk9aHlwb3hpYV9wcm9ncmFtKSkgKyAKICAgICAgZ2VvbV9wb2ludCgpKwogICAgZ2VvbV9kZW5zaXR5XzJkKGFlcyhjb2xvciA9IC4ubGV2ZWwuLikpICsKICAgIGdlb21fc21vb3RoKG1ldGhvZD1sbSkgKwogICAgc3RhdF9jb3IobWV0aG9kID0gInBlYXJzb24iLCBsYWJlbC54ID0gMjAsIGxhYmVsLnkgPSAxLjEpKwogICAgc2NhbGVfY29sb3JfdmlyaWRpc19jKCkKICAKICBwMiA9IGdncGxvdChoaWZfdGFyZ2V0c19ieV90cCwgYWVzKHg9aGlmX3RhcmdldHMsIHk9aHlwb3hpYV9wcm9ncmFtKSkgKyAKICAgIGdlb21fYmluMmQoKSArCiAgICB0aGVtZV9idygpKyBzY2FsZV9maWxsX2dyYWRpZW50bihsaW1pdHM9YygwLDExMDApLCBicmVha3M9c2VxKDAsIDExMDAsIGJ5PTIwMCksIGNvbG91cnM9YygiYmx1ZSIsInllbGxvdyIsInJlZCIpKSsgCiAgICBzdGF0X2NvcihtZXRob2QgPSAicGVhcnNvbiIsIGxhYmVsLnggPSAyMCwgbGFiZWwueSA9IDEuMSkrCiAgICBnZW9tX3Ntb290aChtZXRob2Q9bG0pIAogIAogIHAgPSBnZ2FycmFuZ2UocGxvdGxpc3QgPSBsaXN0KHAxLHAyKSxucm93ICA9IDIpICAKICAKICBwcmludF90YWIocGx0ID0gcCx0aXRsZSA9ICJnZW9tX2JpbjJkIikKCgpgYGAKCgpgYGB7cn0KdXByZWdfaGlmX3RhcmdldHMgPSBoaWZfdGFyZ2V0c1toaWZfdGFyZ2V0cyAlaW4lIHVwZGVnXQp1cHJlZ19oaWZfdGFyZ2V0c19leHByID0gRmV0Y2hEYXRhKG9iamVjdCA9IHhlbm8sdmFycyA9IGModXByZWdfaGlmX3RhcmdldHMpKSAlPiUgcm93U3VtcygpICU+JSBhcy5kYXRhLmZyYW1lKCkgI21lYW4gZXhwcmVzc2lvbgp4ZW5vID0gQWRkTWV0YURhdGEob2JqZWN0ID0geGVubywgbWV0YWRhdGEgPSB1cHJlZ19oaWZfdGFyZ2V0c19leHByLGNvbC5uYW1lID0gInVwcmVnX2hpZl90YXJnZXRzX3Njb3JlIikKRmVhdHVyZVBsb3Qob2JqZWN0ID0geGVubyxmZWF0dXJlcyA9ICJ1cHJlZ19oaWZfdGFyZ2V0c19zY29yZSIpCmBgYAoKCiMgQ2FsY3VsYXRlIHVzYWdlIHdpdGhvdXQgY2MgaW4gc3VtIHRvIDEKYGBge3B5dGhvbn0KaW1wb3J0IG51bXB5IGFzIG5wCmltcG9ydCBzY2FucHkgYXMgc2MKeGVub19leHByZXNzaW9uID0gci54ZW5vX2V4cHJlc3Npb24KeGVub192YXJnZW5lcyA9IHIueGVub192YXJnZW5lcwp0cG0gPSAgY29tcHV0ZV90cG0oeGVub19leHByZXNzaW9uKQp1c2FnZV9ieV9jYWxjID0gZ2V0X3VzYWdlX2Zyb21fc2NvcmUoY291bnRzPXhlbm9fZXhwcmVzc2lvbix0cG09dHBtLGdlbmVzPXhlbm9fdmFyZ2VuZXMsIGNubWZfb2JqPWNubWZfb2JqLGs9MyxzdW1UbzE9RmFsc2UpCmBgYAoKYGBge3J9CmFsbF9tZXRhZ2VuZXNfbm9TdW1UbzEgPSBweSR1c2FnZV9ieV9jYWxjCnRuZl9hbmRfaHlwb3hpYSA9IGFsbF9tZXRhZ2VuZXNfbm9TdW1UbzFbLDE6Ml0KdG5mX2FuZF9oeXBveGlhID0gYXBwbHkoWCA9IHRuZl9hbmRfaHlwb3hpYSwgTUFSR0lOID0gMSwgc3VtXzJfb25lKSAlPiUgdCgpICU+JSAgYXMuZGF0YS5mcmFtZSgpCnRuZl9hbmRfaHlwb3hpYVtpcy5uYSh0bmZfYW5kX2h5cG94aWEpXSA8LSAwICNyZXBsYWNlIE5BTidzIHdpdGggMC4KYGBgCgpgYGB7ciBlY2hvPVRSVUUsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTYsIHJlc3VsdHM9J2FzaXMnfQojIHBsb3QgY29ycmVsYXRpb24gZm9yIGV2ZXJ5IHN1YnNldCBvZiBoaWYgdGFyZ2V0cwpmb3IgKGdlbmVzIGluIGxpc3QoaGlmX3RhcmdldHMseGVub19jbHVzdGVyXzNfZ2VuZXMseGVub19jbHVzdGVyXzNfMl9nZW5lcykpIHsKICBoaWZfdGFyZ2V0c19ieV90cCA9IEZldGNoRGF0YShvYmplY3QgPSB4ZW5vLHZhcnMgPSBjKGdlbmVzKSkgJT4lIHJvd1N1bXMoKSAlPiUgYXMuZGF0YS5mcmFtZSgpICNtZWFuIGV4cHJlc3Npb24KICBoaWZfdGFyZ2V0c19ieV90cFssMl0gPSB0bmZfYW5kX2h5cG94aWFbLDFdCiAgIyBoaWZfdGFyZ2V0c19ieV90cFssMl0gPSB4ZW5vJEh5cG94aWEKICAKICBuYW1lcyhoaWZfdGFyZ2V0c19ieV90cCkgPSBjKCJoaWZfdGFyZ2V0cyIsImh5cG94aWFfcHJvZ3JhbSIpCiAgCiAgCiAgCiAgcDEgPSBnZ3Bsb3QoaGlmX3RhcmdldHNfYnlfdHAsIGFlcyh4PWhpZl90YXJnZXRzLCB5PWh5cG94aWFfcHJvZ3JhbSkpICsgCiAgICAgIGdlb21fcG9pbnQoKSsKICAgIGdlb21fZGVuc2l0eV8yZChhZXMoY29sb3IgPSAuLmxldmVsLi4pKSArCiAgICBnZW9tX3Ntb290aChtZXRob2Q9bG0pICsKICAgIHN0YXRfY29yKG1ldGhvZCA9ICJwZWFyc29uIiwgbGFiZWwueCA9IDIwLCBsYWJlbC55ID0gMS4xKSsKICAgIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYygpCiAgCiAgcDIgPSBnZ3Bsb3QoaGlmX3RhcmdldHNfYnlfdHAsIGFlcyh4PWhpZl90YXJnZXRzLCB5PWh5cG94aWFfcHJvZ3JhbSkpICsgCiAgICBnZW9tX2JpbjJkKCkgKwogICAgdGhlbWVfYncoKSsgc2NhbGVfZmlsbF9ncmFkaWVudG4obGltaXRzPWMoMCwxMTAwKSwgYnJlYWtzPXNlcSgwLCAxMTAwLCBieT0yMDApLCBjb2xvdXJzPWMoImJsdWUiLCJ5ZWxsb3ciLCJyZWQiKSkrIAogICAgc3RhdF9jb3IobWV0aG9kID0gInBlYXJzb24iLCBsYWJlbC54ID0gMjAsIGxhYmVsLnkgPSAxLjEpKwogICAgZ2VvbV9zbW9vdGgobWV0aG9kPWxtKSAKICAKICBwID0gZ2dhcnJhbmdlKHBsb3RsaXN0ID0gbGlzdChwMSxwMiksbnJvdyAgPSAyKSAgCiAgCiAgcHJpbnRfdGFiKHBsdCA9IHAsdGl0bGUgPSAiZ2VvbV9iaW4yZCIpCn0KCgpgYGAKCiMgVU1BUFMKYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OH0KaGlmX3RhcmdldHNfYnlfdHAgPSBGZXRjaERhdGEob2JqZWN0ID0geGVubyx2YXJzID0gYyhoaWZfdGFyZ2V0cykpICU+JSByb3dTdW1zKCkgJT4lIGFzLmRhdGEuZnJhbWUoKSAjbWVhbiBleHByZXNzaW9uCmhpZl90YXJnZXRzX2J5X3RwWywyXSA9IHRuZl9hbmRfaHlwb3hpYVssMV0KbmFtZXMoaGlmX3RhcmdldHNfYnlfdHApID0gYygiaGlmX3RhcmdldHMiLCJoeXBveGlhX3Byb2dyYW0iKQoKaGlnaF9oaWZfbG93X2h5cG94aWFfY2VsbHMgPSBoaWZfdGFyZ2V0c19ieV90cCAlPiUgZmlsdGVyKGhpZl90YXJnZXRzPjI1ICYgaHlwb3hpYV9wcm9ncmFtIDwgMC4yKSAlPiUgcm93bmFtZXMoKQoKaGlmX3RhcmdldHNfYnlfdHAgPSBGZXRjaERhdGEob2JqZWN0ID0geGVubyx2YXJzID0gYyhoaWZfdGFyZ2V0cykpICU+JSByb3dTdW1zKCkgJT4lIGFzLmRhdGEuZnJhbWUoKSAjbWVhbiBleHByZXNzaW9uCnhlbm8gPSBBZGRNZXRhRGF0YShvYmplY3QgPSB4ZW5vLCBtZXRhZGF0YSA9IGhpZl90YXJnZXRzX2J5X3RwLGNvbC5uYW1lID0gIkhJRl90YXJnZXRzX3Njb3JlIikKeGVubyA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IHhlbm8sIG1ldGFkYXRhID0gdG5mX2FuZF9oeXBveGlhWywxXSxjb2wubmFtZSA9ICJIeXBveGlhMiIpCgpEaW1QbG90KG9iamVjdCA9IHhlbm8sIGNlbGxzLmhpZ2hsaWdodCA9IGhpZ2hfaGlmX2xvd19oeXBveGlhX2NlbGxzLCBjb2xzLmhpZ2hsaWdodCA9ICJyZWQiLCBjb2xzID0gImdyYXkiLCBvcmRlciA9IFRSVUUpCkZlYXR1cmVQbG90KG9iamVjdCA9IHhlbm8sZmVhdHVyZXMgPSBjKCAiSElGX3RhcmdldHNfc2NvcmUiLCJIeXBveGlhMiIsIkNlbGxfY3ljbGUiICkpCkZlYXR1cmVQbG90KG9iamVjdCA9IHhlbm8sZmVhdHVyZXMgPSBjKCJIeXBveGlhMiIpKQpEaW1QbG90KG9iamVjdCA9IHhlbm8sZ3JvdXAuYnkgPSAib3JpZy5pZGVudCIpCgpgYGAKCiMgSHlwb3hpYSByYXcKYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTB9Cnhlbm8gPSBBZGRNZXRhRGF0YShvYmplY3QgPSB4ZW5vLG1ldGFkYXRhID0gYWxsX21ldGFnZW5lc19ub1N1bVRvMVssMV0sY29sLm5hbWUgPSAiaHlwb3hpYV9yYXciKQpGZWF0dXJlUGxvdChvYmplY3QgPSB4ZW5vLGZlYXR1cmVzID0gImh5cG94aWFfcmF3IikgKyBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3VycyA9IHJhaW5ib3coNSksIGxpbWl0cyA9IGMoMCwgMzAwMCkpCmBgYAoKCgo8c2NyaXB0IHNyYz0iaHR0cHM6Ly9oeXBvdGhlcy5pcy9lbWJlZC5qcyIgYXN5bmM+PC9zY3JpcHQ+Cg==