1 Parameters

2 Functions


library(stringi)
library(reticulate)
source_from_github(repositoy = "DEG_functions",version = "0.2.24")
source_from_github(repositoy = "cNMF_functions",version = "0.3.85",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
}

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

4 Models 2K vargenes

suffix = r.suffix
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()
# gep_scores = readRDS("/sci/labs/yotamd/lab_share/avishai.wizel/R_projects/EGFR/Data/cnmf/harmony_models_gep_scores.rds")
selected_k = 3
density_threshold = 0.1
# cnmf_obj.consensus(k=selected_k, density_threshold=density_threshold)
usage_norm, gep_scores, gep_tpm, topgenes = cnmf_obj.load_results(K=selected_k, density_threshold=density_threshold)

5 programs enrichment

gep_scores = py$gep_scores
gep_tpm = py$gep_tpm
usage_norm= py$usage_norm
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)

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)

xeno = FindVariableFeatures(object = xeno,nfeatures = 2000)
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|

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

7 Check if original cNMF score is like the calculated score

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

8 calculate score for Xeno

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.
all_metagenes = py$usage_by_calc

9 programs expression


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

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

umap expression

NA

10 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

hallmark_name = "GO_MITOTIC_CELL_CYCLE"
genesets  =getGmt("./Data/h.all.v7.0.symbols.pluscc.gmt")
var_features=xeno@assays$RNA@var.features
geneIds= genesets[[hallmark_name]]@geneIds
score <- apply(xeno@assays$RNA@data[intersect(geneIds,var_features),],2,mean)
xeno=AddMetaData(xeno,score,"GO_MITOTIC_CC")
metagenes_mean_compare(dataset = xeno,time.point_var = "treatment",prefix = "model",patient.ident_var = "orig.ident",pre_on = c("NT","OSI","res"),programs = c("GO_MITOTIC_CC"))

GO_MITOTIC_CC per patient

GO_MITOTIC_CC

NA

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

cc_scores = FetchData(object = xeno,vars = "GO_MITOTIC_CC")
 ggplot(cc_scores, aes(x=GO_MITOTIC_CC)) +
  geom_density()+
   geom_vline(
    aes(xintercept=mean(cc_scores$GO_MITOTIC_CC) + sd(cc_scores$GO_MITOTIC_CC) ,color="1 SD"),
          linetype="dashed", size=1)+
    geom_vline(
    aes(xintercept=mean(cc_scores$GO_MITOTIC_CC) + 2*sd(cc_scores$GO_MITOTIC_CC) ,color="2 SD"),
          linetype="dashed", size=1)
Warning: Use of `cc_scores$GO_MITOTIC_CC` is discouraged. Use `GO_MITOTIC_CC` instead.
Warning: Use of `cc_scores$GO_MITOTIC_CC` is discouraged. Use `GO_MITOTIC_CC` instead.
Warning: Use of `cc_scores$GO_MITOTIC_CC` is discouraged. Use `GO_MITOTIC_CC` instead.
Warning: Use of `cc_scores$GO_MITOTIC_CC` is discouraged. Use `GO_MITOTIC_CC` instead.

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

 df  = FetchData(object = xeno,vars = c("is_cycling","treatment")) %>% 
    filter (treatment %in% c("NT","OSI")) %>% 
    droplevels() 
  test = fisher.test(table(df))
    
  library(ggstatsplot)
print(
    ggbarstats(
    df, is_cycling, treatment,
    results.subtitle = FALSE,
    subtitle = paste0(
      "Fisher's exact test", ", p-value = ",
       round(test$p.value,10))
    )
  )

11 program assignment

larger_by = 1.5
xeno = program_assignment(dataset = xeno,larger_by = larger_by,program_names = colnames(all_metagenes))
print_tab(plt = 
            DimPlot(xeno,group.by = "program.assignment",cols = c(Hypoxia = "red",TNFa = "green",Cell_cycle = "blue","NA" = "grey"))
          ,title = "program.assignment",subtitle_num = 2)
print_tab(plt = 
              DimPlot(xeno,group.by = "orig.ident")
          ,title = "orig.ident",subtitle_num = 2)
print_tab(plt = 
            DimPlot(xeno,group.by = "treatment")
          ,title = "treatment",subtitle_num = 2)

p = cell_percentage(dataset = xeno,time.point_var = "treatment",by_program = T,x_order = c("NT","OSI","res"))
print_tab(plt = p,title = "by program",subtitle_num = 2)

p = cell_percentage(dataset = xeno,time.point_var = "treatment",by_tp  = T,x_order =c("Hypoxia","TNFa","Cell_cycle","NA"))
print_tab(plt = p,title = "by time point",subtitle_num = 2)
top_genes = gep_scores  %>%  arrange(desc(gep_scores["Hypoxia"])) #sort by score a
hypoxia_genes = head(rownames(top_genes),20) #take top top_genes_num
intersect(cluster_3_genes,hypoxia_genes)
library(ggvenn)
all = list(hypoxia_genes = hypoxia_genes, hif_targets = cluster_3_genes)
ggvenn(
  all
)

12 CC signature

# get genes and plot cor heatmap
hallmark_name = "HALLMARK_G2M_CHECKPOINT"
genesets  =getGmt("./Data/h.all.v7.0.symbols.pluscc.gmt")
geneIds= genesets[[hallmark_name]]@geneIds
hallmars_exp = FetchData(object = xeno,vars = c(geneIds))

Warning in FetchData.Seurat(object = xeno, vars = c(geneIds)) : The following requested variables were not found: AC027237.1, AC091021.1, PTTG3P

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

genes expression heatmap

NA

#choose clusters
chosen_clusters = c(1)
print ("chosen_clusters= ", chosen_clusters)

[1] “chosen_clusters=”

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

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

Expression

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

dist

Warning: Use of cc_scores$HALLMARK_G2M_CHECKPOINT is discouraged. Use HALLMARK_G2M_CHECKPOINT instead. Warning: Use of cc_scores$HALLMARK_G2M_CHECKPOINT is discouraged. Use HALLMARK_G2M_CHECKPOINT instead. Warning: Use of cc_scores$HALLMARK_G2M_CHECKPOINT is discouraged. Use HALLMARK_G2M_CHECKPOINT instead. Warning: Use of cc_scores$HALLMARK_G2M_CHECKPOINT is discouraged. Use HALLMARK_G2M_CHECKPOINT instead.

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

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

assignment 2 sd

NA

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

fisher

NA

12.1 correlation to nmf program

cor_res = cor(xeno$Cell_cycle,xeno$HALLMARK_G2M_CHECKPOINT)
print(paste("correlation of cc prgoram to HALLMARK_G2M_CHECKPOINT:", cor_res))
[1] "correlation of cc prgoram to HALLMARK_G2M_CHECKPOINT: 0.877586094823362"

13 TNFa signature

hallmark_name = "HALLMARK_TNFA_SIGNALING_VIA_NFKB"
genesets  =getGmt("./Data/h.all.v7.0.symbols.pluscc.gmt")
geneIds= genesets[[hallmark_name]]@geneIds
hallmars_exp = FetchData(object = xeno,vars = c(geneIds))

Warning in FetchData.Seurat(object = xeno, vars = c(geneIds)) : The following requested variables were not found: CCN1

hallmars_exp = hallmars_exp[,colSums(hallmars_exp[])>0] #remove no expression genes
hallmark_cor = cor(hallmars_exp)
pht1 = pheatmap(mat = hallmark_cor,silent = T)
num_of_clusters = 6
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)
  
  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")

genes expression heatmap

NA

chosen_genes = annotation[["myannotation"]] %>% dplyr::filter(cluster == 3 | cluster == 1 | cluster == 5) %>% rownames() #take relevant genes
score <- apply(xeno@assays$RNA@data[chosen_genes,],2,mean)
xeno=AddMetaData(xeno,score,hallmark_name)

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

Expression

NA

13.1 correlation to nmf program

cor_res = cor(xeno$HALLMARK_TNFA_SIGNALING_VIA_NFKB,xeno$TNFa)
print(paste("correlation of TNFa program to HALLMARK_TNFA_SIGNALING_VIA_NFKB:", cor_res))
[1] "correlation of TNFa program to HALLMARK_TNFA_SIGNALING_VIA_NFKB: 0.191011763193488"
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")

dist

NA

14 Signature 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("HALLMARK_G2M_CHECKPOINT","HALLMARK_TNFA_SIGNALING_VIA_NFKB"))

HALLMARK_G2M_CHECKPOINT per patient

HALLMARK_G2M_CHECKPOINT

HALLMARK_TNFA_SIGNALING_VIA_NFKB per patient

HALLMARK_TNFA_SIGNALING_VIA_NFKB

NA

15 HIF_targets- Hypoxia correlation


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_hypoxia2[,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")
}

Warning in FetchData.Seurat(object = xeno, vars = c(genes)) : The following requested variables were not found: AK4P1, BNIP3P1, LDHAP5, AL158201.1, MIR210, NLRP3P1, AL109946.1 geom_smooth() using formula ‘y ~ x’ geom_smooth() using formula ‘y ~ x’ ## geom_bin2d {.unnumbered }

geom_smooth() using formula ‘y ~ x’ geom_smooth() using formula ‘y ~ x’ ## geom_bin2d {.unnumbered }

geom_smooth() using formula ‘y ~ x’ geom_smooth() using formula ‘y ~ x’ ## geom_bin2d {.unnumbered }

NA

16 UMAPS

hif_targets_by_tp = FetchData(object = xeno,vars = c(hif_targets)) %>% rowSums() %>% as.data.frame() #mean expression
Warning in FetchData.Seurat(object = xeno, vars = c(hif_targets)) :
  The following requested variables were not found: AK4P1, BNIP3P1, LDHAP5, AL158201.1, MIR210, NLRP3P1, AL109946.1
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
Warning in FetchData.Seurat(object = xeno, vars = c(hif_targets)) :
  The following requested variables were not found: AK4P1, BNIP3P1, LDHAP5, AL158201.1, MIR210, NLRP3P1, AL109946.1
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

Warning in FetchData.Seurat(object = xeno, vars = c(new_hif_targets)) : The following requested variables were not found: AK4P1, BNIP3P1, LDHAP5, AL158201.1, MIR210, NLRP3P1, AL109946.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)  

geom_smooth() using formula ‘y ~ x’ geom_smooth() using formula ‘y ~ x’

  
  print_tab(plt = p,title = "geom_bin2d")

geom_bin2d

NA

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

17 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)
/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.
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")
}

Warning in FetchData.Seurat(object = xeno, vars = c(genes)) : The following requested variables were not found: AK4P1, BNIP3P1, LDHAP5, AL158201.1, MIR210, NLRP3P1, AL109946.1 geom_smooth() using formula ‘y ~ x’ geom_smooth() using formula ‘y ~ x’ ## geom_bin2d {.unnumbered }

geom_smooth() using formula ‘y ~ x’ geom_smooth() using formula ‘y ~ x’ ## geom_bin2d {.unnumbered }

geom_smooth() using formula ‘y ~ x’ geom_smooth() using formula ‘y ~ x’ ## geom_bin2d {.unnumbered }

NA

18 UMAPS

hif_targets_by_tp = FetchData(object = xeno,vars = c(hif_targets)) %>% rowSums() %>% as.data.frame() #mean expression
Warning in FetchData.Seurat(object = xeno, vars = c(hif_targets)) :
  The following requested variables were not found: AK4P1, BNIP3P1, LDHAP5, AL158201.1, MIR210, NLRP3P1, AL109946.1
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
Warning in FetchData.Seurat(object = xeno, vars = c(hif_targets)) :
  The following requested variables were not found: AK4P1, BNIP3P1, LDHAP5, AL158201.1, MIR210, NLRP3P1, AL109946.1
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")

19 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))
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.

LS0tCnRpdGxlOiAnYHIgcnN0dWRpb2FwaTo6Z2V0U291cmNlRWRpdG9yQ29udGV4dCgpJHBhdGggJT4lIGJhc2VuYW1lKCkgJT4lIGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLHJlcGxhY2VtZW50ID0gIiIpYCcgCmF1dGhvcjogIkF2aXNoYWkgV2l6ZWwiCmRhdGU6ICdgciBTeXMudGltZSgpYCcKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdG9jOiB5ZXMKICAgIHRvY19jb2xsYXBzZTogeWVzCiAgICB0b2NfZmxvYXQ6IAogICAgICBjb2xsYXBzZWQ6IEZBTFNFCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvY19kZXB0aDogMQotLS0KCiMgUGFyYW1ldGVycwoKYGBge3Igd2FybmluZz1GQUxTRX0KCmBgYAoKCiMgRnVuY3Rpb25zCgpgYGB7ciB3YXJuaW5nPUZBTFNFfQoKbGlicmFyeShzdHJpbmdpKQpsaWJyYXJ5KHJldGljdWxhdGUpCnNvdXJjZV9mcm9tX2dpdGh1YihyZXBvc2l0b3kgPSAiREVHX2Z1bmN0aW9ucyIsdmVyc2lvbiA9ICIwLjIuMjQiKQpzb3VyY2VfZnJvbV9naXRodWIocmVwb3NpdG95ID0gImNOTUZfZnVuY3Rpb25zIix2ZXJzaW9uID0gIjAuMy44NSIsc2NyaXB0X25hbWUgPSAiY25tZl9mdW5jdGlvbl9IYXJtb255LlIiKQoKbm9fbmVnIDwtIGZ1bmN0aW9uKHgpIHsKICB4ID0geCArIGFicyhtaW4oeCkpCiAgeAp9CgpzdW1fMl9vbmUgPC0gZnVuY3Rpb24oeCkgewogIHggPXgvc3VtKHgpCiAgeAp9CmBgYAoKCiMgRGF0YQoKYGBge3IgcmVhZF9kYXRhfQp4ZW5vID0gcmVhZFJEUygiLi9EYXRhLzEweF94ZW5vXzEwMDAuUmRzIikKbHVuZyA9IHJlYWRSRFMoIi4vRGF0YS9sdW5nX2NhbmNlcmNlbGxzX3dpdGhUUF9vbmx5UGF0aWVudHMucmRzIikKbHVuZ19wYXRpZW50cyA9IGx1bmckcGF0aWVudC5pZGVudCAlPiUgdW5pcXVlKCkgJT4lIGFzLmNoYXJhY3RlcigpCmx1bmdfcGF0aWVudHNfZmlsdGVyZWQgPSBsdW5nX3BhdGllbnRzWyEobHVuZ19wYXRpZW50cyAlaW4lIGMoIlgxMDU1bmV3IiwiWDEwOTkiKSldICMgcmVtb3ZlIHBhdGllbnRzIHdpdGggbGVzcyB0aGFuIDEwMCBtYWxpZ25hbnQgY2VsbHMKbHVuZyA9IHN1YnNldCh4ID0gbHVuZyxzdWJzZXQgPSBwYXRpZW50LmlkZW50ICVpbiUgbHVuZ19wYXRpZW50c19maWx0ZXJlZCkKYGBgCgojIE1vZGVscyAySyB2YXJnZW5lcyAKCmBgYHtweXRob259CnN1ZmZpeCA9IHIuc3VmZml4CmltcG9ydCBwaWNrbGUKZnJvbSBjbm1mIGltcG9ydCBjTk1GCmYgPSBvcGVuKCcuL0RhdGEvY25tZi9jbm1mX29iamVjdHMvbW9kZWxzXzJLdmFyZ2VuZXNfY25tZl9vYmoucGNrbCcsICdyYicpCmNubWZfb2JqID0gcGlja2xlLmxvYWQoZikKZi5jbG9zZSgpCmBgYAoKYGBge3J9CiMgZ2VwX3Njb3JlcyA9IHJlYWRSRFMoIi9zY2kvbGFicy95b3RhbWQvbGFiX3NoYXJlL2F2aXNoYWkud2l6ZWwvUl9wcm9qZWN0cy9FR0ZSL0RhdGEvY25tZi9oYXJtb255X21vZGVsc19nZXBfc2NvcmVzLnJkcyIpCmBgYAoKCmBgYHtweXRob259CnNlbGVjdGVkX2sgPSAzCmRlbnNpdHlfdGhyZXNob2xkID0gMC4xCiMgY25tZl9vYmouY29uc2Vuc3VzKGs9c2VsZWN0ZWRfaywgZGVuc2l0eV90aHJlc2hvbGQ9ZGVuc2l0eV90aHJlc2hvbGQpCnVzYWdlX25vcm0sIGdlcF9zY29yZXMsIGdlcF90cG0sIHRvcGdlbmVzID0gY25tZl9vYmoubG9hZF9yZXN1bHRzKEs9c2VsZWN0ZWRfaywgZGVuc2l0eV90aHJlc2hvbGQ9ZGVuc2l0eV90aHJlc2hvbGQpCmBgYAoKIyBwcm9ncmFtcyBlbnJpY2htZW50CgoKCmBgYHtyfQpnZXBfc2NvcmVzID0gcHkkZ2VwX3Njb3JlcwpnZXBfdHBtID0gcHkkZ2VwX3RwbQp1c2FnZV9ub3JtPSBweSR1c2FnZV9ub3JtCmBgYAoKCmBgYHtyIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9Cm5hbWVzIChnZXBfc2NvcmVzKSA9IGMoIkh5cG94aWEiLCJUTkZhIiwiQ2VsbF9jeWNsZSIpCnBsdF9saXN0ID0gbGlzdCgpCgpmb3IgKHByb2dyYW0gIGluIG5hbWVzIChnZXBfc2NvcmVzKSkgewogcCA9IGdncGxvdChnZXBfc2NvcmVzLCBhZXMoeD0hIWVuc3ltKHByb2dyYW0pKSkgKwogIGdlb21fZGVuc2l0eSgpK3hsYWIocHJvZ3JhbSkrCiAgIGdlb21fdmxpbmUoCiAgICBhZXMoeGludGVyY2VwdD1zb3J0KGdlcF9zY29yZXNbLHByb2dyYW1dLFRSVUUpWzIwMF0gICxjb2xvcj0idG9wMjAwIiksCiAgICAgICAgICBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKSsKICAgZ2VvbV92bGluZSgKICAgIGFlcyh4aW50ZXJjZXB0PXNvcnQoZ2VwX3Njb3Jlc1sscHJvZ3JhbV0sVFJVRSlbMTAwXSAgLGNvbG9yPSJ0b3AxMDAiKSwKICAgICAgICAgIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpKwogICAgICBnZW9tX3ZsaW5lKAogICAgYWVzKHhpbnRlcmNlcHQ9c29ydChnZXBfc2NvcmVzWyxwcm9ncmFtXSxUUlVFKVs1MF0gICxjb2xvcj0idG9wNTAiKSwKICAgICAgICAgIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpKwogICAgICAgICBnZW9tX3ZsaW5lKAogICAgYWVzKHhpbnRlcmNlcHQ9c29ydChnZXBfc2NvcmVzWyxwcm9ncmFtXSxUUlVFKVsxNTBdICAsY29sb3I9InRvcDE1MCIpLAogICAgICAgICAgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkrCiAgIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gInRvcCBuIGdlbmVzIiwgdmFsdWVzID0gYyh0b3AyMDAgPSAiYmx1ZSIsdG9wMTAwID0gInJlZCIsdG9wMTUwID0gInllbGxvdyIsdG9wNTAgPSAiZ3JlZW4iKSkKICAgcGx0X2xpc3RbW3Byb2dyYW1dXSA8LSBwCgp9CiAKZ2dhcnJhbmdlKHBsb3RsaXN0ID0gcGx0X2xpc3QpCgpgYGAKCgoKCgoKCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTgsIHJlc3VsdHM9J2hpZGUnfQpudG9wID0gMTUwCnBsdF9saXN0ID0gbGlzdCgpCmhpZl90YXJnZXRzX3NldCA9IGRhdGEuZnJhbWUoZ3NfbmFtZSA9ICJoaWZfdGFyZ2V0cyIsZ2VuZV9zeW1ib2wgPSBoaWZfdGFyZ2V0cykKCmZvciAoaSBpbiAxOm5jb2woZ2VwX3Njb3JlcykpIHsKICB0b3BfZ2VuZXMgPSBnZXBfc2NvcmVzICAlPiUgIGFycmFuZ2UoZGVzYyhnZXBfc2NvcmVzW2ldKSkgI3NvcnQgYnkgc2NvcmUgYQogIHRvcCA9IGhlYWQocm93bmFtZXModG9wX2dlbmVzKSxudG9wKSAjdGFrZSB0b3AgdG9wX2dlbmVzX251bQogIHJlcyA9IGdlbmVzX3ZlY19lbnJpY2htZW50KGdlbmVzID0gdG9wLGJhY2tncm91bmQgPSByb3duYW1lcyhnZXBfc2NvcmVzKSxob21lciA9IFQsdGl0bGUgPSAKICAgICAgICAgICAgICAgICAgICBpLHNpbGVudCA9IFQscmV0dXJuX2FsbCA9IFQsY3VzdG9tX3BhdGh3YXlzICA9IGhpZl90YXJnZXRzX3NldCkKICAgCiAgcGx0X2xpc3RbW2ldXSA9IHJlcyRwbHQKfQpncmlkRXh0cmE6OmdyaWQuYXJyYW5nZShncm9icyA9IHBsdF9saXN0KQpgYGAKCgoKYGBge3J9Cnhlbm8gPSBGaW5kVmFyaWFibGVGZWF0dXJlcyhvYmplY3QgPSB4ZW5vLG5mZWF0dXJlcyA9IDIwMDApCnhlbm9fdmFyZ2VuZXMgPSBWYXJpYWJsZUZlYXR1cmVzKG9iamVjdCA9IHhlbm8pCgp4ZW5vX2V4cHJlc3Npb24gPSBGZXRjaERhdGEob2JqZWN0ID0geGVubyx2YXJzID0geGVub192YXJnZW5lcyxzbG90PSdjb3VudHMnKQphbGxfMF9nZW5lcyA9IGNvbG5hbWVzKHhlbm9fZXhwcmVzc2lvbilbY29sU3Vtcyh4ZW5vX2V4cHJlc3Npb249PTAsIG5hLnJtPVRSVUUpPT1ucm93KHhlbm9fZXhwcmVzc2lvbildICNkZWxldGUgcm93cyB0aGF0IGhhdmUgYWxsIDAKeGVub192YXJnZW5lcyA9IHhlbm9fdmFyZ2VuZXNbIXhlbm9fdmFyZ2VuZXMgJWluJSBhbGxfMF9nZW5lc10KCmBgYAoKCgoKIyBUZXN0IHdpdGggZXhwciBhZnRlciBoYXJtb255CmBgYHtweXRob259CmltcG9ydCBudW1weSBhcyBucAppbXBvcnQgc2NhbnB5IGFzIHNjCgpleHByX2FmdGVyX2hhcm1vbnkgPSBzYy5yZWFkX2g1YWQoJy4vRGF0YS9jbm1mL3hlbm9fSGFybW9ueV9Ob05lZ18yS3ZhcmdlbmVzLmg1YWQnKS50b19kZigpCnRwbSA9ICBjb21wdXRlX3RwbShleHByX2FmdGVyX2hhcm1vbnkpCmNubWZfZ2VuZXMgPSBleHByX2FmdGVyX2hhcm1vbnkua2V5cygpLnRvX2xpc3QoKQp1c2FnZV9ieV9jYWxjID0gZ2V0X3VzYWdlX2Zyb21fc2NvcmUoY291bnRzPWV4cHJfYWZ0ZXJfaGFybW9ueSx0cG09dHBtLGdlbmVzPWNubWZfZ2VuZXMsY25tZl9vYmo9Y25tZl9vYmosaz0zKQpgYGAKCiMgQ2hlY2sgaWYgb3JpZ2luYWwgY05NRiBzY29yZSBpcyBsaWtlIHRoZSBjYWxjdWxhdGVkIHNjb3JlCmBgYHtyfQp1c2FnZV9ieV9jYWxjID0gcHkkdXNhZ2VfYnlfY2FsYwp1c2FnZV9ub3JtID0gcHkkdXNhZ2Vfbm9ybQpjb3IodXNhZ2VfYnlfY2FsYyx1c2FnZV9ub3JtKQpgYGAKCiMgY2FsY3VsYXRlIHNjb3JlIGZvciBYZW5vCmBgYHtweXRob259CmltcG9ydCBudW1weSBhcyBucAppbXBvcnQgc2NhbnB5IGFzIHNjCnhlbm9fZXhwcmVzc2lvbiA9IHIueGVub19leHByZXNzaW9uCnhlbm9fdmFyZ2VuZXMgPSByLnhlbm9fdmFyZ2VuZXMKdHBtID0gIGNvbXB1dGVfdHBtKHhlbm9fZXhwcmVzc2lvbikKdXNhZ2VfYnlfY2FsYyA9IGdldF91c2FnZV9mcm9tX3Njb3JlKGNvdW50cz14ZW5vX2V4cHJlc3Npb24sdHBtPXRwbSxnZW5lcz14ZW5vX3ZhcmdlbmVzLCBjbm1mX29iaj1jbm1mX29iaixrPTMpCmBgYAoKYGBge3J9CmFsbF9tZXRhZ2VuZXMgPSBweSR1c2FnZV9ieV9jYWxjCmBgYAoKIyBwcm9ncmFtcyBleHByZXNzaW9uIHsudGFic2V0fQpgYGB7ciBlY2hvPVRSVUUsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTksIHJlc3VsdHM9J2FzaXMnfQoKbmFtZXMgKGFsbF9tZXRhZ2VuZXMpID0gYygiSHlwb3hpYSIsIlRORmEiLCJDZWxsX2N5Y2xlIikKI2FkZCBlYWNoIG1ldGFnZW5lIHRvIG1ldGFkYXRhCmZvciAoaSAgaW4gMTpuY29sKGFsbF9tZXRhZ2VuZXMpKSB7CiAgbWV0YWdlX21ldGFkYXRhID0gYWxsX21ldGFnZW5lcyAlPiUgZHBseXI6OnNlbGVjdChpKQogICMgbWV0YWdlX21ldGFkYXRhID0gc2NhbGUobWV0YWdlX21ldGFkYXRhKQogIHhlbm8gPSBBZGRNZXRhRGF0YShvYmplY3QgPSB4ZW5vLG1ldGFkYXRhID0gbWV0YWdlX21ldGFkYXRhLGNvbC5uYW1lID0gbmFtZXMoYWxsX21ldGFnZW5lcylbaV0pCn0KCnByaW50X3RhYihwbHQgPSBGZWF0dXJlUGxvdChvYmplY3QgPSB4ZW5vLGZlYXR1cmVzID0gY29sbmFtZXMoYWxsX21ldGFnZW5lcykpLHRpdGxlID0gInVtYXAgZXhwcmVzc2lvbiIpCgoKYGBgCgoKCiMgcHJvZ3JhbXMgcmVndWxhdGlvbiB7LnRhYnNldH0KYGBge3IgZWNobz1UUlVFLCAgcmVzdWx0cz0nYXNpcyd9Cm1ldGFnZW5lc19tZWFuX2NvbXBhcmUoZGF0YXNldCA9IHhlbm8sdGltZS5wb2ludF92YXIgPSAidHJlYXRtZW50IixwcmVmaXggPSAibW9kZWwiLHBhdGllbnQuaWRlbnRfdmFyID0gIm9yaWcuaWRlbnQiLHByZV9vbiA9IGMoIk5UIiwiT1NJIiksdGVzdCA9ICJ3aWxjb3gudGVzdCIscHJvZ3JhbXMgPSBjKCJIeXBveGlhIiwiVE5GYSIsIkNlbGxfY3ljbGUiKSkKCmBgYAoKCgpgYGB7cn0KaGFsbG1hcmtfbmFtZSA9ICJHT19NSVRPVElDX0NFTExfQ1lDTEUiCmdlbmVzZXRzICA9Z2V0R210KCIuL0RhdGEvaC5hbGwudjcuMC5zeW1ib2xzLnBsdXNjYy5nbXQiKQp2YXJfZmVhdHVyZXM9eGVub0Bhc3NheXMkUk5BQHZhci5mZWF0dXJlcwpnZW5lSWRzPSBnZW5lc2V0c1tbaGFsbG1hcmtfbmFtZV1dQGdlbmVJZHMKc2NvcmUgPC0gYXBwbHkoeGVub0Bhc3NheXMkUk5BQGRhdGFbaW50ZXJzZWN0KGdlbmVJZHMsdmFyX2ZlYXR1cmVzKSxdLDIsbWVhbikKeGVubz1BZGRNZXRhRGF0YSh4ZW5vLHNjb3JlLCJHT19NSVRPVElDX0NDIikKYGBgCgpgYGB7ciBlY2hvPVRSVUUsIHJlc3VsdHM9J2FzaXMnfQptZXRhZ2VuZXNfbWVhbl9jb21wYXJlKGRhdGFzZXQgPSB4ZW5vLHRpbWUucG9pbnRfdmFyID0gInRyZWF0bWVudCIscHJlZml4ID0gIm1vZGVsIixwYXRpZW50LmlkZW50X3ZhciA9ICJvcmlnLmlkZW50IixwcmVfb24gPSBjKCJOVCIsIk9TSSIsInJlcyIpLHByb2dyYW1zID0gYygiR09fTUlUT1RJQ19DQyIpKQoKYGBgCmBgYHtyfQpEb3RQbG90KG9iamVjdCA9IHhlbm8sIGZlYXR1cmVzID0gIGMoIkh5cG94aWEiLCJUTkZhIiwiQ2VsbF9jeWNsZSIsIkdPX01JVE9USUNfQ0MiKSxzY2FsZSA9IEYsZ3JvdXAuYnkgID0gJ3RyZWF0bWVudCcpCmBgYAoKCmBgYHtyfQpjY19zY29yZXMgPSBGZXRjaERhdGEob2JqZWN0ID0geGVubyx2YXJzID0gIkdPX01JVE9USUNfQ0MiKQogZ2dwbG90KGNjX3Njb3JlcywgYWVzKHg9R09fTUlUT1RJQ19DQykpICsKICBnZW9tX2RlbnNpdHkoKSsKICAgZ2VvbV92bGluZSgKICAgIGFlcyh4aW50ZXJjZXB0PW1lYW4oY2Nfc2NvcmVzJEdPX01JVE9USUNfQ0MpICsgc2QoY2Nfc2NvcmVzJEdPX01JVE9USUNfQ0MpICxjb2xvcj0iMSBTRCIpLAogICAgICAgICAgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkrCiAgICBnZW9tX3ZsaW5lKAogICAgYWVzKHhpbnRlcmNlcHQ9bWVhbihjY19zY29yZXMkR09fTUlUT1RJQ19DQykgKyAyKnNkKGNjX3Njb3JlcyRHT19NSVRPVElDX0NDKSAsY29sb3I9IjIgU0QiKSwKICAgICAgICAgIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpCiAKY2Nfc2NvcmVzID0gY2Nfc2NvcmVzICU+JSBtdXRhdGUoaXNfY3ljbGluZyA9IGlmX2Vsc2UoY29uZGl0aW9uID0gCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEdPX01JVE9USUNfQ0MgPiBtZWFuKGNjX3Njb3JlcyRHT19NSVRPVElDX0NDKSArIHNkKGNjX3Njb3JlcyRHT19NSVRPVElDX0NDKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRydWUgPSAiY3ljbGluZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWxzZSA9ICJub25fY3ljbGluZyIpKQp4ZW5vID0gQWRkTWV0YURhdGEob2JqZWN0ID0geGVubyxtZXRhZGF0YSA9IGNjX3Njb3JlcyRpc19jeWNsaW5nLGNvbC5uYW1lID0gImlzX2N5Y2xpbmciKQpEaW1QbG90KG9iamVjdCA9IHhlbm8sZ3JvdXAuYnkgPSAiaXNfY3ljbGluZyIpCgpgYGAKCgpgYGB7cn0KIGRmICA9IEZldGNoRGF0YShvYmplY3QgPSB4ZW5vLHZhcnMgPSBjKCJpc19jeWNsaW5nIiwidHJlYXRtZW50IikpICU+JSAKICAgIGZpbHRlciAodHJlYXRtZW50ICVpbiUgYygiTlQiLCJPU0kiKSkgJT4lIAogICAgZHJvcGxldmVscygpIAogIHRlc3QgPSBmaXNoZXIudGVzdCh0YWJsZShkZikpCiAgICAKICBsaWJyYXJ5KGdnc3RhdHNwbG90KQpwcmludCgKICAgIGdnYmFyc3RhdHMoCiAgICBkZiwgaXNfY3ljbGluZywgdHJlYXRtZW50LAogICAgcmVzdWx0cy5zdWJ0aXRsZSA9IEZBTFNFLAogICAgc3VidGl0bGUgPSBwYXN0ZTAoCiAgICAgICJGaXNoZXIncyBleGFjdCB0ZXN0IiwgIiwgcC12YWx1ZSA9ICIsCiAgICAgICByb3VuZCh0ZXN0JHAudmFsdWUsMTApKQogICAgKQogICkKCmBgYAoKCiMgcHJvZ3JhbSBhc3NpZ25tZW50IHsudGFic2V0fQpgYGB7cn0KbGFyZ2VyX2J5ID0gMS41Cnhlbm8gPSBwcm9ncmFtX2Fzc2lnbm1lbnQoZGF0YXNldCA9IHhlbm8sbGFyZ2VyX2J5ID0gbGFyZ2VyX2J5LHByb2dyYW1fbmFtZXMgPSBjb2xuYW1lcyhhbGxfbWV0YWdlbmVzKSkKYGBgIAoKYGBge3IgZWNobz1UUlVFLCByZXN1bHRzPSdhc2lzJ30KcHJpbnRfdGFiKHBsdCA9IAogICAgICAgICAgICBEaW1QbG90KHhlbm8sZ3JvdXAuYnkgPSAicHJvZ3JhbS5hc3NpZ25tZW50Iixjb2xzID0gYyhIeXBveGlhID0gInJlZCIsVE5GYSA9ICJncmVlbiIsQ2VsbF9jeWNsZSA9ICJibHVlIiwiTkEiID0gImdyZXkiKSkKICAgICAgICAgICx0aXRsZSA9ICJwcm9ncmFtLmFzc2lnbm1lbnQiLHN1YnRpdGxlX251bSA9IDIpCnByaW50X3RhYihwbHQgPSAKICAgICAgICAgICAgICBEaW1QbG90KHhlbm8sZ3JvdXAuYnkgPSAib3JpZy5pZGVudCIpCiAgICAgICAgICAsdGl0bGUgPSAib3JpZy5pZGVudCIsc3VidGl0bGVfbnVtID0gMikKcHJpbnRfdGFiKHBsdCA9IAogICAgICAgICAgICBEaW1QbG90KHhlbm8sZ3JvdXAuYnkgPSAidHJlYXRtZW50IikKICAgICAgICAgICx0aXRsZSA9ICJ0cmVhdG1lbnQiLHN1YnRpdGxlX251bSA9IDIpCgpwID0gY2VsbF9wZXJjZW50YWdlKGRhdGFzZXQgPSB4ZW5vLHRpbWUucG9pbnRfdmFyID0gInRyZWF0bWVudCIsYnlfcHJvZ3JhbSA9IFQseF9vcmRlciA9IGMoIk5UIiwiT1NJIiwicmVzIikpCnByaW50X3RhYihwbHQgPSBwLHRpdGxlID0gImJ5IHByb2dyYW0iLHN1YnRpdGxlX251bSA9IDIpCgpwID0gY2VsbF9wZXJjZW50YWdlKGRhdGFzZXQgPSB4ZW5vLHRpbWUucG9pbnRfdmFyID0gInRyZWF0bWVudCIsYnlfdHAgID0gVCx4X29yZGVyID1jKCJIeXBveGlhIiwiVE5GYSIsIkNlbGxfY3ljbGUiLCJOQSIpKQpwcmludF90YWIocGx0ID0gcCx0aXRsZSA9ICJieSB0aW1lIHBvaW50IixzdWJ0aXRsZV9udW0gPSAyKQoKCmBgYAoKCmBgYHtyfQp0b3BfZ2VuZXMgPSBnZXBfc2NvcmVzICAlPiUgIGFycmFuZ2UoZGVzYyhnZXBfc2NvcmVzWyJIeXBveGlhIl0pKSAjc29ydCBieSBzY29yZSBhCmh5cG94aWFfZ2VuZXMgPSBoZWFkKHJvd25hbWVzKHRvcF9nZW5lcyksMjApICN0YWtlIHRvcCB0b3BfZ2VuZXNfbnVtCmludGVyc2VjdChjbHVzdGVyXzNfZ2VuZXMsaHlwb3hpYV9nZW5lcykKYGBgCgpgYGB7cn0KbGlicmFyeShnZ3Zlbm4pCmFsbCA9IGxpc3QoaHlwb3hpYV9nZW5lcyA9IGh5cG94aWFfZ2VuZXMsIGhpZl90YXJnZXRzID0gY2x1c3Rlcl8zX2dlbmVzKQpnZ3Zlbm4oCiAgYWxsCikKYGBgCgoKCgojIENDIHNpZ25hdHVyZSAgey50YWJzZXR9CgoKCgpgYGB7ciBlY2hvPVRSVUUsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTEwLCByZXN1bHRzPSdhc2lzJ30KIyBnZXQgZ2VuZXMgYW5kIHBsb3QgY29yIGhlYXRtYXAKaGFsbG1hcmtfbmFtZSA9ICJIQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVCIKZ2VuZXNldHMgID1nZXRHbXQoIi4vRGF0YS9oLmFsbC52Ny4wLnN5bWJvbHMucGx1c2NjLmdtdCIpCmdlbmVJZHM9IGdlbmVzZXRzW1toYWxsbWFya19uYW1lXV1AZ2VuZUlkcwpoYWxsbWFyc19leHAgPSBGZXRjaERhdGEob2JqZWN0ID0geGVubyx2YXJzID0gYyhnZW5lSWRzKSkKaGFsbG1hcnNfZXhwID0gaGFsbG1hcnNfZXhwWyxjb2xTdW1zKGhhbGxtYXJzX2V4cFtdKT4wXSAjcmVtb3ZlIG5vIGV4cHJlc3Npb24gZ2VuZXMKaGFsbG1hcmtfY29yID0gY29yKGhhbGxtYXJzX2V4cCkKcGh0MSA9IHBoZWF0bWFwKG1hdCA9IGhhbGxtYXJrX2NvcixzaWxlbnQgPSBUKQoKIyBtYWtlIGFubm90YXRpb25zCm51bV9vZl9jbHVzdGVycyA9IDQKY2x1c3RlcmluZ19kaXN0YW5jZSA9ICJldWNsaWRlYW4iCm15YW5ub3RhdGlvbiA9IGFzLmRhdGEuZnJhbWUoY3V0cmVlKHBodDFbWyJ0cmVlX3JvdyJdXSwgayA9IG51bV9vZl9jbHVzdGVycykpICNzcGxpdCBpbnRvIGsgY2x1c3RlcnMKbmFtZXMobXlhbm5vdGF0aW9uKVsxXSA9ICJjbHVzdGVyIgpteWFubm90YXRpb24kY2x1c3RlciA9IGFzLmZhY3RvcihteWFubm90YXRpb24kY2x1c3RlcikKcGFsZXR0ZTEgPC1icmV3ZXIucGFsKG51bV9vZl9jbHVzdGVycywgIlBhaXJlZCIpCm5hbWVzKHBhbGV0dGUxKSA9IHVuaXF1ZShteWFubm90YXRpb24kY2x1c3RlcikKYW5uX2NvbG9ycyA9IGxpc3QgKGNsdXN0ZXIgPSBwYWxldHRlMSkKYW5ub3RhdGlvbiA9IGxpc3QoYW5uX2NvbG9ycyA9IGFubl9jb2xvcnMsIG15YW5ub3RhdGlvbiA9IG15YW5ub3RhdGlvbikKCiNjaG9vc2UgY29sb3JzCmNvbG9ycyA8LSBjKHNlcSgtMSwxLGJ5PTAuMDEpKQpteV9wYWxldHRlIDwtIGMoImJsdWUiLGNvbG9yUmFtcFBhbGV0dGUoY29sb3JzID0gYygiYmx1ZSIsICJ3aGl0ZSIsICJyZWQiKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChuID0gbGVuZ3RoKGNvbG9ycyktMyksICJyZWQiKQoKCnByaW50X3RhYihwbHQgPSAKICAgICAgICAgICAgICBwaGVhdG1hcChtYXQgPSBoYWxsbWFya19jb3IsYW5ub3RhdGlvbl9jb2wgPSAgYW5ub3RhdGlvbltbIm15YW5ub3RhdGlvbiJdXSwgYW5ub3RhdGlvbl9jb2xvcnMgPSBhbm5vdGF0aW9uW1siYW5uX2NvbG9ycyJdXSwgY2x1c3RlcmluZ19kaXN0YW5jZV9yb3dzID0gY2x1c3RlcmluZ19kaXN0YW5jZSxjbHVzdGVyaW5nX2Rpc3RhbmNlX2NvbHMgPSBjbHVzdGVyaW5nX2Rpc3RhbmNlLGNvbG9yID0gbXlfcGFsZXR0ZSxicmVha3MgPSBjb2xvcnMsc2hvd19yb3duYW1lcyA9IEYsc2hvd19jb2xuYW1lcyA9IEYpCiAgICAgICAgICAgICx0aXRsZSA9ICJnZW5lcyBleHByZXNzaW9uIGhlYXRtYXAiKQpgYGAKCmBgYHtyIGVjaG89VFJVRSwgcmVzdWx0cz0nYXNpcyd9CiNjaG9vc2UgY2x1c3RlcnMKY2hvc2VuX2NsdXN0ZXJzID0gYygxKQpwcmludCAoImNob3Nlbl9jbHVzdGVycz0gIiwgY2hvc2VuX2NsdXN0ZXJzKQoKI1VNQVAgZXhwcmVzc2lvbiBvZiBzaWduYXR1cmUKY2hvc2VuX2dlbmVzID0gYW5ub3RhdGlvbltbIm15YW5ub3RhdGlvbiJdXSAlPiUgZHBseXI6OmZpbHRlcihjbHVzdGVyICVpbiUgY2hvc2VuX2NsdXN0ZXJzKSAlPiUgcm93bmFtZXMoKSAjdGFrZSByZWxldmFudCBnZW5lcwpzY29yZSA8LSBhcHBseSh4ZW5vQGFzc2F5cyRSTkFAZGF0YVtjaG9zZW5fZ2VuZXMsXSwyLG1lYW4pCnhlbm89QWRkTWV0YURhdGEoeGVubyxzY29yZSxoYWxsbWFya19uYW1lKQoKcHJpbnRfdGFiKEZlYXR1cmVQbG90KG9iamVjdCA9IHhlbm8sIGZlYXR1cmVzID0gaGFsbG1hcmtfbmFtZSksdGl0bGUgPSAiRXhwcmVzc2lvbiIpCgojcGxvdCBzaWduYXR1cmUgZGlzdHJpYnV0aW9uCmNjX3Njb3JlcyA9IEZldGNoRGF0YShvYmplY3QgPSB4ZW5vLHZhcnMgPSAiSEFMTE1BUktfRzJNX0NIRUNLUE9JTlQiKQpwbHQgID0gIGdncGxvdChjY19zY29yZXMsIGFlcyh4PUhBTExNQVJLX0cyTV9DSEVDS1BPSU5UKSkgKwogIGdlb21fZGVuc2l0eSgpKwogICBnZW9tX3ZsaW5lKAogICAgYWVzKHhpbnRlcmNlcHQ9bWVhbihjY19zY29yZXMkSEFMTE1BUktfRzJNX0NIRUNLUE9JTlQpICsgc2QoY2Nfc2NvcmVzJEhBTExNQVJLX0cyTV9DSEVDS1BPSU5UKSAsY29sb3I9IjEgU0QiKSwKICAgICAgICAgIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpKwogICAgZ2VvbV92bGluZSgKICAgIGFlcyh4aW50ZXJjZXB0PW1lYW4oY2Nfc2NvcmVzJEhBTExNQVJLX0cyTV9DSEVDS1BPSU5UKSArIDIqc2QoY2Nfc2NvcmVzJEhBTExNQVJLX0cyTV9DSEVDS1BPSU5UKSAsY29sb3I9IjIgU0QiKSwKICAgICAgICAgIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpCgpwcmludF90YWIocGx0ID0gcGx0LHRpdGxlID0gImRpc3QiKQoKIyBQbG90IGFzc2lnbm1lbnQgCgpjY19zY29yZXMgPSBjY19zY29yZXMgJT4lIG11dGF0ZShpc19jeWNsaW5nID0gaWZfZWxzZShjb25kaXRpb24gPSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSEFMTE1BUktfRzJNX0NIRUNLUE9JTlQgPiBtZWFuKEhBTExNQVJLX0cyTV9DSEVDS1BPSU5UKSArIHNkKEhBTExNQVJLX0cyTV9DSEVDS1BPSU5UKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRydWUgPSAiY3ljbGluZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWxzZSA9ICJub25fY3ljbGluZyIpKQp4ZW5vID0gQWRkTWV0YURhdGEob2JqZWN0ID0geGVubyxtZXRhZGF0YSA9IGNjX3Njb3JlcyRpc19jeWNsaW5nLGNvbC5uYW1lID0gImlzX2N5Y2xpbmciKQpwcmludF90YWIocGx0ID0gRGltUGxvdChvYmplY3QgPSB4ZW5vLGdyb3VwLmJ5ID0gImlzX2N5Y2xpbmciKSAsIHRpdGxlID0gImFzc2lnbm1lbnQgMSBzZCIpCgoKY2Nfc2NvcmVzID0gY2Nfc2NvcmVzICU+JSBtdXRhdGUoaXNfY3ljbGluZyA9IGlmX2Vsc2UoY29uZGl0aW9uID0gCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEhBTExNQVJLX0cyTV9DSEVDS1BPSU5UID4gbWVhbihIQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVCkgKyAyKnNkKGNjX3Njb3JlcyRIQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cnVlID0gImN5Y2xpbmciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFsc2UgPSAibm9uX2N5Y2xpbmciKSkKeGVubyA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IHhlbm8sbWV0YWRhdGEgPSBjY19zY29yZXMkaXNfY3ljbGluZyxjb2wubmFtZSA9ICJpc19jeWNsaW5nIikKcHJpbnRfdGFiKHBsdCA9IERpbVBsb3Qob2JqZWN0ID0geGVubyxncm91cC5ieSA9ICJpc19jeWNsaW5nIikgLCB0aXRsZSA9ICJhc3NpZ25tZW50IDIgc2QiKQoKCmBgYAoKCgoKYGBge3IgZWNobz1UUlVFLCByZXN1bHRzPSdhc2lzJ30KIGRmICA9IEZldGNoRGF0YShvYmplY3QgPSB4ZW5vLHZhcnMgPSBjKCJpc19jeWNsaW5nIiwidHJlYXRtZW50IikpICU+JSAKICAgIGZpbHRlciAodHJlYXRtZW50ICVpbiUgYygiTlQiLCJPU0kiKSkgJT4lIAogICAgZHJvcGxldmVscygpIAogIHRlc3QgPSBmaXNoZXIudGVzdCh0YWJsZShkZikpCiAgICAKICBsaWJyYXJ5KGdnc3RhdHNwbG90KQoKICAgIHBsdCA9IGdnYmFyc3RhdHMoCiAgICBkZiwgaXNfY3ljbGluZywgdHJlYXRtZW50LAogICAgcmVzdWx0cy5zdWJ0aXRsZSA9IEZBTFNFLAogICAgc3VidGl0bGUgPSBwYXN0ZTAoCiAgICAgICJGaXNoZXIncyBleGFjdCB0ZXN0IiwgIiwgcC12YWx1ZSA9ICIsCiAgICAgICByb3VuZCh0ZXN0JHAudmFsdWUsMTMpKQogICAgKQogIApwcmludF90YWIocGx0ID0gcGx0LHRpdGxlID0gImZpc2hlciIpCmBgYAojIyBjb3JyZWxhdGlvbiB0byBubWYgcHJvZ3JhbQpgYGB7cn0KY29yX3JlcyA9IGNvcih4ZW5vJENlbGxfY3ljbGUseGVubyRIQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVCkKcHJpbnQocGFzdGUoImNvcnJlbGF0aW9uIG9mIGNjIHByZ29yYW0gdG8gSEFMTE1BUktfRzJNX0NIRUNLUE9JTlQ6IiwgY29yX3JlcykpCmBgYAoKCiMgVE5GYSBzaWduYXR1cmUgIHsudGFic2V0fQoKYGBge3IgcmVzdWx0cz0nYXNpcyd9CmhhbGxtYXJrX25hbWUgPSAiSEFMTE1BUktfVE5GQV9TSUdOQUxJTkdfVklBX05GS0IiCmdlbmVzZXRzICA9Z2V0R210KCIuL0RhdGEvaC5hbGwudjcuMC5zeW1ib2xzLnBsdXNjYy5nbXQiKQpnZW5lSWRzPSBnZW5lc2V0c1tbaGFsbG1hcmtfbmFtZV1dQGdlbmVJZHMKaGFsbG1hcnNfZXhwID0gRmV0Y2hEYXRhKG9iamVjdCA9IHhlbm8sdmFycyA9IGMoZ2VuZUlkcykpCmhhbGxtYXJzX2V4cCA9IGhhbGxtYXJzX2V4cFssY29sU3VtcyhoYWxsbWFyc19leHBbXSk+MF0gI3JlbW92ZSBubyBleHByZXNzaW9uIGdlbmVzCmhhbGxtYXJrX2NvciA9IGNvcihoYWxsbWFyc19leHApCnBodDEgPSBwaGVhdG1hcChtYXQgPSBoYWxsbWFya19jb3Isc2lsZW50ID0gVCkKYGBgCgpgYGB7ciBlY2hvPVRSVUUsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTEwLCByZXN1bHRzPSdhc2lzJ30KbnVtX29mX2NsdXN0ZXJzID0gNgpjbHVzdGVyaW5nX2Rpc3RhbmNlID0gImV1Y2xpZGVhbiIKbXlhbm5vdGF0aW9uID0gYXMuZGF0YS5mcmFtZShjdXRyZWUocGh0MVtbInRyZWVfcm93Il1dLCBrID0gbnVtX29mX2NsdXN0ZXJzKSkgI3NwbGl0IGludG8gayBjbHVzdGVycwogCm5hbWVzKG15YW5ub3RhdGlvbilbMV0gPSAiY2x1c3RlciIKICBteWFubm90YXRpb24kY2x1c3RlciA9IGFzLmZhY3RvcihteWFubm90YXRpb24kY2x1c3RlcikKICAKICBwYWxldHRlMSA8LWJyZXdlci5wYWwobnVtX29mX2NsdXN0ZXJzLCAiUGFpcmVkIikKCiAgbmFtZXMocGFsZXR0ZTEpID0gdW5pcXVlKG15YW5ub3RhdGlvbiRjbHVzdGVyKQogIGFubl9jb2xvcnMgPSBsaXN0IChjbHVzdGVyID0gcGFsZXR0ZTEpCiAgYW5ub3RhdGlvbiA9IGxpc3QoYW5uX2NvbG9ycyA9IGFubl9jb2xvcnMsIG15YW5ub3RhdGlvbiA9IG15YW5ub3RhdGlvbikKICAKICBjb2xvcnMgPC0gYyhzZXEoLTEsMSxieT0wLjAxKSkKICBteV9wYWxldHRlIDwtIGMoImJsdWUiLGNvbG9yUmFtcFBhbGV0dGUoY29sb3JzID0gYygiYmx1ZSIsICJ3aGl0ZSIsICJyZWQiKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKG4gPSBsZW5ndGgoY29sb3JzKS0zKSwgInJlZCIpCgoKICBwcmludF90YWIocGx0ID0gCiAgICAgICAgICAgICAgICBwaGVhdG1hcChtYXQgPSBoYWxsbWFya19jb3IsYW5ub3RhdGlvbl9jb2wgPSAgYW5ub3RhdGlvbltbIm15YW5ub3RhdGlvbiJdXSwgYW5ub3RhdGlvbl9jb2xvcnMgPSBhbm5vdGF0aW9uW1siYW5uX2NvbG9ycyJdXSwgY2x1c3RlcmluZ19kaXN0YW5jZV9yb3dzID0gY2x1c3RlcmluZ19kaXN0YW5jZSxjbHVzdGVyaW5nX2Rpc3RhbmNlX2NvbHMgPSBjbHVzdGVyaW5nX2Rpc3RhbmNlLGNvbG9yID0gbXlfcGFsZXR0ZSxicmVha3MgPSBjb2xvcnMsc2hvd19yb3duYW1lcyA9IEYsc2hvd19jb2xuYW1lcyA9IEYpCiAgICAgICAgICAgICx0aXRsZSA9ICJnZW5lcyBleHByZXNzaW9uIGhlYXRtYXAiKQpgYGAKYGBge3IgZWNobz1UUlVFLCByZXN1bHRzPSdhc2lzJ30KY2hvc2VuX2dlbmVzID0gYW5ub3RhdGlvbltbIm15YW5ub3RhdGlvbiJdXSAlPiUgZHBseXI6OmZpbHRlcihjbHVzdGVyID09IDMgfCBjbHVzdGVyID09IDEgfCBjbHVzdGVyID09IDUpICU+JSByb3duYW1lcygpICN0YWtlIHJlbGV2YW50IGdlbmVzCnNjb3JlIDwtIGFwcGx5KHhlbm9AYXNzYXlzJFJOQUBkYXRhW2Nob3Nlbl9nZW5lcyxdLDIsbWVhbikKeGVubz1BZGRNZXRhRGF0YSh4ZW5vLHNjb3JlLGhhbGxtYXJrX25hbWUpCgpwcmludF90YWIoRmVhdHVyZVBsb3Qob2JqZWN0ID0geGVubywgZmVhdHVyZXMgPSBoYWxsbWFya19uYW1lKSx0aXRsZSA9ICJFeHByZXNzaW9uIikKYGBgCiMjIGNvcnJlbGF0aW9uIHRvIG5tZiBwcm9ncmFtCgpgYGB7cn0KY29yX3JlcyA9IGNvcih4ZW5vJEhBTExNQVJLX1RORkFfU0lHTkFMSU5HX1ZJQV9ORktCLHhlbm8kVE5GYSkKcHJpbnQocGFzdGUoImNvcnJlbGF0aW9uIG9mIFRORmEgcHJvZ3JhbSB0byBIQUxMTUFSS19UTkZBX1NJR05BTElOR19WSUFfTkZLQjoiLCBjb3JfcmVzKSkKYGBgCgpgYGB7ciBlY2hvPVRSVUUsIHJlc3VsdHM9J2FzaXMnfQpjY19zY29yZXMgPSBGZXRjaERhdGEob2JqZWN0ID0geGVubyx2YXJzID0gaGFsbG1hcmtfbmFtZSkKCnBsdCAgPSAgZ2dwbG90KGNjX3Njb3JlcywgYWVzKHg9SEFMTE1BUktfVE5GQV9TSUdOQUxJTkdfVklBX05GS0IpKSArCiAgZ2VvbV9kZW5zaXR5KCkrCiAgIGdlb21fdmxpbmUoCiAgICBhZXMoeGludGVyY2VwdD1tZWFuKEhBTExNQVJLX1RORkFfU0lHTkFMSU5HX1ZJQV9ORktCKSArIHNkKEhBTExNQVJLX1RORkFfU0lHTkFMSU5HX1ZJQV9ORktCKSAsY29sb3I9IjEgU0QiKSwKICAgICAgICAgIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpKwogICAgZ2VvbV92bGluZSgKICAgIGFlcyh4aW50ZXJjZXB0PW1lYW4oSEFMTE1BUktfVE5GQV9TSUdOQUxJTkdfVklBX05GS0IpICsgMipzZChIQUxMTUFSS19UTkZBX1NJR05BTElOR19WSUFfTkZLQikgLGNvbG9yPSIyIFNEIiksCiAgICAgICAgICBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKSsKICAgIGdlb21fdmxpbmUoCiAgICBhZXMoeGludGVyY2VwdD1tZWFuKEhBTExNQVJLX1RORkFfU0lHTkFMSU5HX1ZJQV9ORktCKSAsY29sb3I9Im1lYW4iKSwKICAgICAgICAgIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpCgpwcmludF90YWIocGx0ID0gcGx0LHRpdGxlID0gImRpc3QiKQpgYGAKIyAgU2lnbmF0dXJlIHJlZ3VsYXRpb24gIHsudGFic2V0fQoKYGBge3IgZWNobz1UUlVFLCByZXN1bHRzPSdhc2lzJ30KbWV0YWdlbmVzX21lYW5fY29tcGFyZShkYXRhc2V0ID0geGVubyx0aW1lLnBvaW50X3ZhciA9ICJ0cmVhdG1lbnQiLHByZWZpeCA9ICJtb2RlbCIscGF0aWVudC5pZGVudF92YXIgPSAib3JpZy5pZGVudCIscHJlX29uID0gYygiTlQiLCJPU0kiLCJyZXMiKSxwcm9ncmFtcyA9IGMoIkhBTExNQVJLX0cyTV9DSEVDS1BPSU5UIiwiSEFMTE1BUktfVE5GQV9TSUdOQUxJTkdfVklBX05GS0IiKSkKCmBgYAoKIyBISUZfdGFyZ2V0cy0gSHlwb3hpYSBjb3JyZWxhdGlvbiAgey50YWJzZXR9CmBgYHtyIGVjaG89VFJVRSwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9NiwgcmVzdWx0cz0nYXNpcyd9CiMgcGxvdCBjb3JyZWxhdGlvbiBmb3IgZXZlcnkgc3Vic2V0IG9mIGhpZiB0YXJnZXRzCmZvciAoZ2VuZXMgaW4gbGlzdChoaWZfdGFyZ2V0cyx4ZW5vX2NsdXN0ZXJfM19nZW5lcyx4ZW5vX2NsdXN0ZXJfM18yX2dlbmVzKSkgewogIGhpZl90YXJnZXRzX2J5X3RwID0gRmV0Y2hEYXRhKG9iamVjdCA9IHhlbm8sdmFycyA9IGMoZ2VuZXMpKSAlPiUgcm93U3VtcygpICU+JSBhcy5kYXRhLmZyYW1lKCkgI21lYW4gZXhwcmVzc2lvbgogIGhpZl90YXJnZXRzX2J5X3RwWywyXSA9IHhlbm8kSHlwb3hpYQogIAogIG5hbWVzKGhpZl90YXJnZXRzX2J5X3RwKSA9IGMoImhpZl90YXJnZXRzIiwiaHlwb3hpYV9wcm9ncmFtIikKICAKICAKICAKICBwMSA9IGdncGxvdChoaWZfdGFyZ2V0c19ieV90cCwgYWVzKHg9aGlmX3RhcmdldHMsIHk9aHlwb3hpYV9wcm9ncmFtKSkgKyAKICAgICAgZ2VvbV9wb2ludCgpKwogICAgZ2VvbV9kZW5zaXR5XzJkKGFlcyhjb2xvciA9IC4ubGV2ZWwuLikpICsKICAgIGdlb21fc21vb3RoKG1ldGhvZD1sbSkgKwogICAgc3RhdF9jb3IobWV0aG9kID0gInBlYXJzb24iLCBsYWJlbC54ID0gMjAsIGxhYmVsLnkgPSAxLjEpKwogICAgc2NhbGVfY29sb3JfdmlyaWRpc19jKCkKICAKICBwMiA9IGdncGxvdChoaWZfdGFyZ2V0c19ieV90cCwgYWVzKHg9aGlmX3RhcmdldHMsIHk9aHlwb3hpYV9wcm9ncmFtKSkgKyAKICAgIGdlb21fYmluMmQoKSArCiAgICB0aGVtZV9idygpKyBzY2FsZV9maWxsX2dyYWRpZW50bihsaW1pdHM9YygwLDExMDApLCBicmVha3M9c2VxKDAsIDExMDAsIGJ5PTIwMCksIGNvbG91cnM9YygiYmx1ZSIsInllbGxvdyIsInJlZCIpKSsgCiAgICBzdGF0X2NvcihtZXRob2QgPSAicGVhcnNvbiIsIGxhYmVsLnggPSAyMCwgbGFiZWwueSA9IDEuMSkrCiAgICBnZW9tX3Ntb290aChtZXRob2Q9bG0pIAogIAogIHAgPSBnZ2FycmFuZ2UocGxvdGxpc3QgPSBsaXN0KHAxLHAyKSxucm93ICA9IDIpICAKICAKICBwcmludF90YWIocGx0ID0gcCx0aXRsZSA9ICJnZW9tX2JpbjJkIikKfQoKCmBgYAoKCiMgVU1BUFMKYGBge3IgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9MTB9CmhpZl90YXJnZXRzX2J5X3RwID0gRmV0Y2hEYXRhKG9iamVjdCA9IHhlbm8sdmFycyA9IGMoaGlmX3RhcmdldHMpKSAlPiUgcm93U3VtcygpICU+JSBhcy5kYXRhLmZyYW1lKCkgI21lYW4gZXhwcmVzc2lvbgpoaWZfdGFyZ2V0c19ieV90cFssMl0gPSB4ZW5vJEh5cG94aWEKbmFtZXMoaGlmX3RhcmdldHNfYnlfdHApID0gYygiaGlmX3RhcmdldHMiLCJoeXBveGlhX3Byb2dyYW0iKQoKaGlnaF9oaWZfbG93X2h5cG94aWFfY2VsbHMgPSBoaWZfdGFyZ2V0c19ieV90cCAlPiUgZmlsdGVyKGhpZl90YXJnZXRzPjI1ICYgaHlwb3hpYV9wcm9ncmFtIDwgMC4yKSAlPiUgcm93bmFtZXMoKQpsb3dfaGlmX2hpZ2hfaHlwb3hpYV9jZWxscyA9IGhpZl90YXJnZXRzX2J5X3RwICU+JSBmaWx0ZXIoaGlmX3RhcmdldHM8MTUgJiBoeXBveGlhX3Byb2dyYW0gPiAwLjYpICU+JSByb3duYW1lcygpCgpoaWZfdGFyZ2V0c19ieV90cCA9IEZldGNoRGF0YShvYmplY3QgPSB4ZW5vLHZhcnMgPSBjKGhpZl90YXJnZXRzKSkgJT4lIHJvd1N1bXMoKSAlPiUgYXMuZGF0YS5mcmFtZSgpICNtZWFuIGV4cHJlc3Npb24KeGVubyA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IHhlbm8sIG1ldGFkYXRhID0gaGlmX3RhcmdldHNfYnlfdHAsY29sLm5hbWUgPSAiSElGX3RhcmdldHNfc2NvcmUiKQpjZWxsc190b19oaWdobGlnaHQgPSAgbGlzdChoaWdoX2hpZl9sb3dfaHlwb3hpYV9jZWxscyA9IGhpZ2hfaGlmX2xvd19oeXBveGlhX2NlbGxzLCBsb3dfaGlmX2hpZ2hfaHlwb3hpYV9jZWxscyA9IGxvd19oaWZfaGlnaF9oeXBveGlhX2NlbGxzKQoKRGltUGxvdChvYmplY3QgPSB4ZW5vLCBjZWxscy5oaWdobGlnaHQgPSBjZWxsc190b19oaWdobGlnaHQsIGNvbHMuaGlnaGxpZ2h0ID0gYygicmVkIiwiYmx1ZSIpLCBjb2xzID0gImdyYXkiLCBvcmRlciA9IFRSVUUpCkZlYXR1cmVQbG90KG9iamVjdCA9IHhlbm8sZmVhdHVyZXMgPSBjKCAiSElGX3RhcmdldHNfc2NvcmUiLCJIeXBveGlhIiwiQ2VsbF9jeWNsZSIgKSkKCmBgYApgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMH0KaGlmX2h5cG94aWFfY29ycmVsYXRlZF9jZWxscyA9IGNvbG5hbWVzKHhlbm8pIFshY29sbmFtZXMoeGVubykgJWluJSBoaWdoX2hpZl9sb3dfaHlwb3hpYV9jZWxscyAmICFjb2xuYW1lcyh4ZW5vKSAlaW4lIGhpZ2hfaGlmX2xvd19oeXBveGlhX2NlbGxzXQpoaWZfdGFyZ2V0c19zY29yZSA9IEZldGNoRGF0YShvYmplY3QgPSB4ZW5vLHZhcnMgPSBjKGhpZl90YXJnZXRzKSkgJT4lIHJvd1N1bXMoKSAlPiUgYXMuZGF0YS5mcmFtZSgpICNtZWFuIGV4cHJlc3Npb24KaGlmX3RhcmdldHNfc2NvcmVbLDJdID0geGVubyRIeXBveGlhCm5hbWVzKGhpZl90YXJnZXRzX3Njb3JlKSA9IGMoImhpZl90YXJnZXRzIiwiaHlwb3hpYV9wcm9ncmFtIikKaGlmX3RhcmdldHNfc2NvcmUgID0gaGlmX3RhcmdldHNfc2NvcmUgJT4lIG11dGF0ZSh0eXBlID0gY2FzZV93aGVuKGhpZl90YXJnZXRzPjI1ICYgaHlwb3hpYV9wcm9ncmFtIDwgMC4yIH4gImhpZ2hfaGlmX2xvd19oeXBveGlhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhpZl90YXJnZXRzPDE1ICYgaHlwb3hpYV9wcm9ncmFtID4gMC42IH4gImxvd19oaWZfaGlnaF9oeXBveGlhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhpZl90YXJnZXRzPjI1ICYgaHlwb3hpYV9wcm9ncmFtID4gMC42IH4gImhpZ2hfaGlmX2hpZ2hfaHlwb3hpYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoaWZfdGFyZ2V0czwxNSAmIGh5cG94aWFfcHJvZ3JhbSA8MC4yIH4gImhpZ2hfaGlmX2hpZ2hfaHlwb3hpYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIm90aGVyIikpCnhlbm8gPSBBZGRNZXRhRGF0YShvYmplY3QgPSB4ZW5vLG1ldGFkYXRhID0gaGlmX3RhcmdldHNfc2NvcmVbLCJ0eXBlIiwgZHJvcCA9IEZdLGNvbC5uYW1lID0gInNjb3JlX2NvcnJlbGF0aW9uIikKeGVubyA9IFNldElkZW50KG9iamVjdCA9IHhlbm8sdmFsdWUgPSAic2NvcmVfY29ycmVsYXRpb24iKQpEaW1QbG90KG9iamVjdCA9IHhlbm8sZ3JvdXAuYnkgPSAic2NvcmVfY29ycmVsYXRpb24iKQptYXJrZXJzID0gRmluZE1hcmtlcnMob2JqZWN0ID0geGVubywgaWRlbnQuMSA9ICJoaWdoX2hpZl9sb3dfaHlwb3hpYSIsaWRlbnQuMiA9ICJoaWdoX2hpZl9oaWdoX2h5cG94aWEiLGRlbnNpZnkgPSBUKQpgYGAKYGBge3IgZWNobz1UUlVFLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD02LCByZXN1bHRzPSdhc2lzJ30KdXBkZWcgPSBtYXJrZXJzICU+JSBmaWx0ZXIocF92YWxfYWRqPDAuMDUgJiBhdmdfbG9nMkZDPjApICU+JSByb3duYW1lcygpCgpuZXdfaGlmX3RhcmdldHMgPSBoaWZfdGFyZ2V0c1shaGlmX3RhcmdldHMgJWluJSB1cGRlZ10KaGlmX3RhcmdldHNfYnlfdHAgPSBGZXRjaERhdGEob2JqZWN0ID0geGVubyx2YXJzID0gYyhuZXdfaGlmX3RhcmdldHMpKSAlPiUgcm93U3VtcygpICU+JSBhcy5kYXRhLmZyYW1lKCkgI21lYW4gZXhwcmVzc2lvbgogIGhpZl90YXJnZXRzX2J5X3RwWywyXSA9IHhlbm8kSHlwb3hpYQogIAogIG5hbWVzKGhpZl90YXJnZXRzX2J5X3RwKSA9IGMoImhpZl90YXJnZXRzIiwiaHlwb3hpYV9wcm9ncmFtIikKICAKICAKICAKICBwMSA9IGdncGxvdChoaWZfdGFyZ2V0c19ieV90cCwgYWVzKHg9aGlmX3RhcmdldHMsIHk9aHlwb3hpYV9wcm9ncmFtKSkgKyAKICAgICAgZ2VvbV9wb2ludCgpKwogICAgZ2VvbV9kZW5zaXR5XzJkKGFlcyhjb2xvciA9IC4ubGV2ZWwuLikpICsKICAgIGdlb21fc21vb3RoKG1ldGhvZD1sbSkgKwogICAgc3RhdF9jb3IobWV0aG9kID0gInBlYXJzb24iLCBsYWJlbC54ID0gMjAsIGxhYmVsLnkgPSAxLjEpKwogICAgc2NhbGVfY29sb3JfdmlyaWRpc19jKCkKICAKICBwMiA9IGdncGxvdChoaWZfdGFyZ2V0c19ieV90cCwgYWVzKHg9aGlmX3RhcmdldHMsIHk9aHlwb3hpYV9wcm9ncmFtKSkgKyAKICAgIGdlb21fYmluMmQoKSArCiAgICB0aGVtZV9idygpKyBzY2FsZV9maWxsX2dyYWRpZW50bihsaW1pdHM9YygwLDExMDApLCBicmVha3M9c2VxKDAsIDExMDAsIGJ5PTIwMCksIGNvbG91cnM9YygiYmx1ZSIsInllbGxvdyIsInJlZCIpKSsgCiAgICBzdGF0X2NvcihtZXRob2QgPSAicGVhcnNvbiIsIGxhYmVsLnggPSAyMCwgbGFiZWwueSA9IDEuMSkrCiAgICBnZW9tX3Ntb290aChtZXRob2Q9bG0pIAogIAogIHAgPSBnZ2FycmFuZ2UocGxvdGxpc3QgPSBsaXN0KHAxLHAyKSxucm93ICA9IDIpICAKICAKICBwcmludF90YWIocGx0ID0gcCx0aXRsZSA9ICJnZW9tX2JpbjJkIikKCgpgYGAKCgpgYGB7cn0KdXByZWdfaGlmX3RhcmdldHMgPSBoaWZfdGFyZ2V0c1toaWZfdGFyZ2V0cyAlaW4lIHVwZGVnXQp1cHJlZ19oaWZfdGFyZ2V0c19leHByID0gRmV0Y2hEYXRhKG9iamVjdCA9IHhlbm8sdmFycyA9IGModXByZWdfaGlmX3RhcmdldHMpKSAlPiUgcm93U3VtcygpICU+JSBhcy5kYXRhLmZyYW1lKCkgI21lYW4gZXhwcmVzc2lvbgp4ZW5vID0gQWRkTWV0YURhdGEob2JqZWN0ID0geGVubywgbWV0YWRhdGEgPSB1cHJlZ19oaWZfdGFyZ2V0c19leHByLGNvbC5uYW1lID0gInVwcmVnX2hpZl90YXJnZXRzX3Njb3JlIikKRmVhdHVyZVBsb3Qob2JqZWN0ID0geGVubyxmZWF0dXJlcyA9ICJ1cHJlZ19oaWZfdGFyZ2V0c19zY29yZSIpCmBgYAoKCiMgQ2FsY3VsYXRlIHVzYWdlIHdpdGhvdXQgY2MgaW4gc3VtIHRvIDEKYGBge3B5dGhvbn0KaW1wb3J0IG51bXB5IGFzIG5wCmltcG9ydCBzY2FucHkgYXMgc2MKeGVub19leHByZXNzaW9uID0gci54ZW5vX2V4cHJlc3Npb24KeGVub192YXJnZW5lcyA9IHIueGVub192YXJnZW5lcwp0cG0gPSAgY29tcHV0ZV90cG0oeGVub19leHByZXNzaW9uKQp1c2FnZV9ieV9jYWxjID0gZ2V0X3VzYWdlX2Zyb21fc2NvcmUoY291bnRzPXhlbm9fZXhwcmVzc2lvbix0cG09dHBtLGdlbmVzPXhlbm9fdmFyZ2VuZXMsIGNubWZfb2JqPWNubWZfb2JqLGs9MyxzdW1UbzE9RmFsc2UpCmBgYApgYGB7cn0KYWxsX21ldGFnZW5lc19ub1N1bVRvMSA9IHB5JHVzYWdlX2J5X2NhbGMKdG5mX2FuZF9oeXBveGlhID0gYWxsX21ldGFnZW5lc19ub1N1bVRvMVssMToyXQp0bmZfYW5kX2h5cG94aWEgPSBhcHBseShYID0gdG5mX2FuZF9oeXBveGlhLCBNQVJHSU4gPSAxLCBzdW1fMl9vbmUpICU+JSB0KCkgJT4lICBhcy5kYXRhLmZyYW1lKCkKdG5mX2FuZF9oeXBveGlhW2lzLm5hKHRuZl9hbmRfaHlwb3hpYSldIDwtIDAgI3JlcGxhY2UgTkFOJ3Mgd2l0aCAwLgpgYGAKCmBgYHtyIGVjaG89VFJVRSwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9NiwgcmVzdWx0cz0nYXNpcyd9CiMgcGxvdCBjb3JyZWxhdGlvbiBmb3IgZXZlcnkgc3Vic2V0IG9mIGhpZiB0YXJnZXRzCmZvciAoZ2VuZXMgaW4gbGlzdChoaWZfdGFyZ2V0cyx4ZW5vX2NsdXN0ZXJfM19nZW5lcyx4ZW5vX2NsdXN0ZXJfM18yX2dlbmVzKSkgewogIGhpZl90YXJnZXRzX2J5X3RwID0gRmV0Y2hEYXRhKG9iamVjdCA9IHhlbm8sdmFycyA9IGMoZ2VuZXMpKSAlPiUgcm93U3VtcygpICU+JSBhcy5kYXRhLmZyYW1lKCkgI21lYW4gZXhwcmVzc2lvbgogIGhpZl90YXJnZXRzX2J5X3RwWywyXSA9IHRuZl9hbmRfaHlwb3hpYVssMV0KICAjIGhpZl90YXJnZXRzX2J5X3RwWywyXSA9IHhlbm8kSHlwb3hpYQogIAogIG5hbWVzKGhpZl90YXJnZXRzX2J5X3RwKSA9IGMoImhpZl90YXJnZXRzIiwiaHlwb3hpYV9wcm9ncmFtIikKICAKICAKICAKICBwMSA9IGdncGxvdChoaWZfdGFyZ2V0c19ieV90cCwgYWVzKHg9aGlmX3RhcmdldHMsIHk9aHlwb3hpYV9wcm9ncmFtKSkgKyAKICAgICAgZ2VvbV9wb2ludCgpKwogICAgZ2VvbV9kZW5zaXR5XzJkKGFlcyhjb2xvciA9IC4ubGV2ZWwuLikpICsKICAgIGdlb21fc21vb3RoKG1ldGhvZD1sbSkgKwogICAgc3RhdF9jb3IobWV0aG9kID0gInBlYXJzb24iLCBsYWJlbC54ID0gMjAsIGxhYmVsLnkgPSAxLjEpKwogICAgc2NhbGVfY29sb3JfdmlyaWRpc19jKCkKICAKICBwMiA9IGdncGxvdChoaWZfdGFyZ2V0c19ieV90cCwgYWVzKHg9aGlmX3RhcmdldHMsIHk9aHlwb3hpYV9wcm9ncmFtKSkgKyAKICAgIGdlb21fYmluMmQoKSArCiAgICB0aGVtZV9idygpKyBzY2FsZV9maWxsX2dyYWRpZW50bihsaW1pdHM9YygwLDExMDApLCBicmVha3M9c2VxKDAsIDExMDAsIGJ5PTIwMCksIGNvbG91cnM9YygiYmx1ZSIsInllbGxvdyIsInJlZCIpKSsgCiAgICBzdGF0X2NvcihtZXRob2QgPSAicGVhcnNvbiIsIGxhYmVsLnggPSAyMCwgbGFiZWwueSA9IDEuMSkrCiAgICBnZW9tX3Ntb290aChtZXRob2Q9bG0pIAogIAogIHAgPSBnZ2FycmFuZ2UocGxvdGxpc3QgPSBsaXN0KHAxLHAyKSxucm93ICA9IDIpICAKICAKICBwcmludF90YWIocGx0ID0gcCx0aXRsZSA9ICJnZW9tX2JpbjJkIikKfQoKCmBgYAoKIyBVTUFQUwpgYGB7ciBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD04fQpoaWZfdGFyZ2V0c19ieV90cCA9IEZldGNoRGF0YShvYmplY3QgPSB4ZW5vLHZhcnMgPSBjKGhpZl90YXJnZXRzKSkgJT4lIHJvd1N1bXMoKSAlPiUgYXMuZGF0YS5mcmFtZSgpICNtZWFuIGV4cHJlc3Npb24KaGlmX3RhcmdldHNfYnlfdHBbLDJdID0gdG5mX2FuZF9oeXBveGlhWywxXQpuYW1lcyhoaWZfdGFyZ2V0c19ieV90cCkgPSBjKCJoaWZfdGFyZ2V0cyIsImh5cG94aWFfcHJvZ3JhbSIpCgpoaWdoX2hpZl9sb3dfaHlwb3hpYV9jZWxscyA9IGhpZl90YXJnZXRzX2J5X3RwICU+JSBmaWx0ZXIoaGlmX3RhcmdldHM+MjUgJiBoeXBveGlhX3Byb2dyYW0gPCAwLjIpICU+JSByb3duYW1lcygpCgpoaWZfdGFyZ2V0c19ieV90cCA9IEZldGNoRGF0YShvYmplY3QgPSB4ZW5vLHZhcnMgPSBjKGhpZl90YXJnZXRzKSkgJT4lIHJvd1N1bXMoKSAlPiUgYXMuZGF0YS5mcmFtZSgpICNtZWFuIGV4cHJlc3Npb24KeGVubyA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IHhlbm8sIG1ldGFkYXRhID0gaGlmX3RhcmdldHNfYnlfdHAsY29sLm5hbWUgPSAiSElGX3RhcmdldHNfc2NvcmUiKQp4ZW5vID0gQWRkTWV0YURhdGEob2JqZWN0ID0geGVubywgbWV0YWRhdGEgPSB0bmZfYW5kX2h5cG94aWFbLDFdLGNvbC5uYW1lID0gIkh5cG94aWEyIikKCkRpbVBsb3Qob2JqZWN0ID0geGVubywgY2VsbHMuaGlnaGxpZ2h0ID0gaGlnaF9oaWZfbG93X2h5cG94aWFfY2VsbHMsIGNvbHMuaGlnaGxpZ2h0ID0gInJlZCIsIGNvbHMgPSAiZ3JheSIsIG9yZGVyID0gVFJVRSkKRmVhdHVyZVBsb3Qob2JqZWN0ID0geGVubyxmZWF0dXJlcyA9IGMoICJISUZfdGFyZ2V0c19zY29yZSIsIkh5cG94aWEyIiwiQ2VsbF9jeWNsZSIgKSkKRmVhdHVyZVBsb3Qob2JqZWN0ID0geGVubyxmZWF0dXJlcyA9IGMoIkh5cG94aWEyIikpCkRpbVBsb3Qob2JqZWN0ID0geGVubyxncm91cC5ieSA9ICJvcmlnLmlkZW50IikKCmBgYAoKIyBIeXBveGlhIHJhdwpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMH0KeGVubyA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IHhlbm8sbWV0YWRhdGEgPSBhbGxfbWV0YWdlbmVzX25vU3VtVG8xWywxXSxjb2wubmFtZSA9ICJoeXBveGlhX3JhdyIpCkZlYXR1cmVQbG90KG9iamVjdCA9IHhlbm8sZmVhdHVyZXMgPSAiaHlwb3hpYV9yYXciKSArIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvdXJzID0gcmFpbmJvdyg1KSwgbGltaXRzID0gYygwLCAzMDAwKSkKYGBgCgoKCjxzY3JpcHQgc3JjPSJodHRwczovL2h5cG90aGVzLmlzL2VtYmVkLmpzIiBhc3luYz48L3NjcmlwdD4K