Data
lung = readRDS("./Data/lung_cancercells_withTP_onlyPatients.rds")
lung_patients = lung$patient.ident %>% unique() %>% as.character()
lung_patients_filtered = lung_patients[!(lung_patients %in% c("X1055new","X1099"))] # remove patients with less than 100 malignant cells
lung = subset(x = lung,subset = patient.ident %in% lung_patients_filtered)
suffix ="xeno_genes_normalized_0-5sigma_2-7theta"
from cnmf import cNMF
suffix = r.suffix
import pickle
f = open('./Data/cnmf/cnmf_objects/patients_' + suffix + '_cnmf_obj.pckl', 'rb')
cnmf_obj = pickle.load(f)
f.close()
Functions
library(stringi)
library(reticulate)
source_from_github(repositoy = "DEG_functions",version = "0.2.24")
source_from_github(repositoy = "cNMF_functions",version = "0.3.9",script_name = "cnmf_function_Harmony.R")
K selection plot
plot_path = paste0("/sci/labs/yotamd/lab_share/avishai.wizel/R_projects/EGFR/Data/cnmf/cNMF_patients_Varnorm_Harmony_",suffix,"/cNMF_patients_Varnorm_Harmony_",suffix,".k_selection.png")
knitr::include_graphics(plot_path)

gep scores for all NMF
k’s
density_threshold = 0.1
usage_norm, gep_scores3, gep_tpm, topgenes = cnmf_obj.load_results(K=3, density_threshold=density_threshold)
usage_norm, gep_scores4, gep_tpm, topgenes = cnmf_obj.load_results(K=4, density_threshold=density_threshold)
usage_norm, gep_scores5, gep_tpm, topgenes = cnmf_obj.load_results(K=5, density_threshold=density_threshold)
usage_norm, gep_scores6, gep_tpm, topgenes = cnmf_obj.load_results(K=6, density_threshold=density_threshold)
usage_norm, gep_scores7, gep_tpm, topgenes = cnmf_obj.load_results(K=7, density_threshold=density_threshold)
usage_norm, gep_scores8, gep_tpm, topgenes = cnmf_obj.load_results(K=8, density_threshold=density_threshold)
usage_norm, gep_scores9, gep_tpm, topgenes = cnmf_obj.load_results(K=9, density_threshold=density_threshold)
Enrichment analysis by top 200 genes of each program
gep_scores3 = py$gep_scores3
gep_scores4 = py$gep_scores4
gep_scores5 = py$gep_scores5
gep_scores6 = py$gep_scores6
gep_scores7 = py$gep_scores7
gep_scores8 = py$gep_scores8
gep_scores9 = py$gep_scores9
all_gep_scores = list(gep_scores3 = gep_scores3, gep_scores4 = gep_scores4, gep_scores5 = gep_scores5, gep_scores6 = gep_scores6, gep_scores7= gep_scores7, gep_scores8 = gep_scores8, gep_scores9 = gep_scores9)
# canonical_pathways = msigdbr(species = "Homo sapiens", category = "C2") %>% dplyr::filter(gs_subcat != "CGP") %>% dplyr::distinct(gs_name, gene_symbol)
for (gep_name in names(all_gep_scores)) {
gep_scores = all_gep_scores[[gep_name]]
top_genes_num = 200
plt_list = list()
for (i in 1:ncol(gep_scores)) {
top_genes = gep_scores %>% arrange(desc(gep_scores[i])) #sort by score a
top = head(rownames(top_genes),top_genes_num) #take top top_genes_num
res = genes_vec_enrichment(genes = top,background = rownames(gep_scores),homer = T,title =
names(gep_scores)[i],silent = T,return_all = T,custom_pathways = NULL )
plt_list[[i]] = res$plt
}
print_tab(plt = ggarrange(plotlist = plt_list),
title = gep_name)
}
gep_scores3

gep_scores4

gep_scores5

gep_scores6

gep_scores7

gep_scores8

gep_scores9

NA
Chosen K
selected_k = 8
print("selected k = ",selected_k)
selected k = 8
density_threshold = 0.1
cnmf_obj.consensus(k=selected_k, density_threshold=density_threshold,show_clustering=True)
usage_norm, gep_scores, gep_tpm, topgenes = cnmf_obj.load_results(K=selected_k, density_threshold=density_threshold)
patients_geps = py$gep_scores
programs enrichment
with canonical
gep_scores = py$gep_scores
canonical_pathways = msigdbr(species = "Homo sapiens", category = "C2") %>% dplyr::filter(gs_subcat != "CGP") %>% dplyr::distinct(gs_name, gene_symbol)
top_genes_num = 200
plt_list = list()
for (i in 1:ncol(gep_scores)) {
top_genes = gep_scores %>% arrange(desc(gep_scores[i])) #sort by score a
top = head(rownames(top_genes),top_genes_num) #take top top_genes_num
res = genes_vec_enrichment(genes = top,background = rownames(gep_scores),homer = T,title =
names(gep_scores)[i],silent = T,return_all = T,custom_pathways = canonical_pathways )
plt_list[[i]] = res$plt
}
gridExtra::grid.arrange(grobs = plt_list)

Correlation of
programs
cor_res = cor(patients_geps)
breaks <- c(seq(-1,1,by=0.01))
colors_for_plot <- colorRampPalette(colors = c("blue", "white", "red"))(n = length(breaks))
pht = pheatmap(cor_res,color = colors_for_plot,breaks = breaks)

print_tab(pht,title = "correlation")
## correlation {.unnumbered }
#correlation based on top 200
all_top= c()
for (i in 1:ncol(patients_geps)) {
top_genes = patients_geps %>% arrange(desc(patients_geps[i])) #sort by score a
top = head(rownames(top_genes),200) #take top top_genes_num
all_top = c(all_top,top)
}
gep_scores_top = patients_geps[all_top,]
cor_res = cor(gep_scores_top)
breaks <- c(seq(-1,1,by=0.01))
colors_for_plot <- colorRampPalette(colors = c("blue", "white", "red"))(n = length(breaks))
# correlation by top 150 combined
pht = pheatmap(cor_res,color = colors_for_plot,breaks = breaks)


print_tab(pht,title = "top 200 genes correlation")
## top 200 genes correlation {.unnumbered }
Combine similar
programs
groups_list = c(4,3,6)
patients_geps = union_programs(groups_list = groups_list,all_metagenes = patients_geps)
plt_list = list()
for (program in names (patients_geps)) {
p = ggplot(patients_geps, aes(x=!!ensym(program))) +
geom_density()+xlab(program)+
geom_vline(
aes(xintercept=sort(patients_geps[,program],TRUE)[200] ,color="top200"),
linetype="dashed", size=1)+
geom_vline(
aes(xintercept=sort(patients_geps[,program],TRUE)[100] ,color="top100"),
linetype="dashed", size=1)+
geom_vline(
aes(xintercept=sort(patients_geps[,program],TRUE)[50] ,color="top50"),
linetype="dashed", size=1)+
geom_vline(
aes(xintercept=sort(patients_geps[,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)

top_genes_num = 200
plt_list = list()
for (i in 1:ncol(patients_geps)) {
top_genes = patients_geps %>% arrange(desc(patients_geps[i])) #sort by score a
top = head(rownames(top_genes),top_genes_num) #take top top_genes_num
res = genes_vec_enrichment(genes = top,background = rownames(patients_geps),homer = T,title =
names(patients_geps)[i],silent = T,return_all = T,custom_pathways = canonical_pathways)
plt_list[[i]] = res$plt
}
gridExtra::grid.arrange(grobs = plt_list)

Calculate usage
# get expression with genes in cnmf input
lung = FindVariableFeatures(object = lung,nfeatures = 2000)
genes = rownames(lung)[rownames(lung) %in% VariableFeatures(object = xeno)[1:2000]]
lung_expression = t(as.matrix(GetAssayData(lung,slot='data')))
lung_expression = 2**lung_expression #convert from log2(tpm+1) to tpm
lung_expression = lung_expression-1
lung_expression = lung_expression[,genes] %>% as.data.frame()
all_0_genes = colnames(lung_expression)[colSums(lung_expression==0, na.rm=TRUE)==nrow(lung_expression)] #delete rows that have all 0
genes = genes[!genes %in% all_0_genes]
lung_expression = lung_expression[,!colnames(lung_expression) %in% all_0_genes]
gc(verbose = F)
lung_expression = r.lung_expression
genes = r.genes
gep_scores = r.patients_geps
usage_by_calc = get_usage_from_score(counts=lung_expression,tpm=lung_expression,genes=genes,cnmf_obj=cnmf_obj,k=selected_k,sumTo1=False)
usage_by_calc = py$usage_by_calc
groups_list = c(4,3,6)
usage_by_calc = union_programs(groups_list = groups_list,all_metagenes = usage_by_calc)
usage_by_calc = apply(usage_by_calc, MARGIN = 1, sum_2_one) %>% t() %>% as.data.frame()
usage_by_calc =usage_by_calc %>% rename(cell_cycle = gep4.3.6, hypoxia_like = gep2, interferon_like = gep1, TNFa = gep5, INF2 = gep7)
Usgage UMAP
all_metagenes= usage_by_calc
#add each metagene to metadata
for (i in 1:ncol(all_metagenes)) {
metage_metadata = all_metagenes %>% dplyr::select(i)
lung = AddMetaData(object = lung,metadata = metage_metadata)
}
Note: Using an external vector in selections is ambiguous.
ℹ Use `all_of(i)` instead of `i` to silence this message.
ℹ See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
This message is displayed once per session.
FeaturePlot(object = lung,features = colnames(all_metagenes),ncol = 3)
Warning: The following variables were found in both object metadata and the default assay: INF2
Returning metadata; if you want the feature, please use the assay's key (eg. rna_INF2)

DimPlot(object = lung,group.by = "time.point",pt.size = 0.5)
pre_treatment_cells = FetchData(object = lung,vars = "time.point") %>% filter(time.point == "pre-treatment") %>% rownames()
on_treatment_cells = FetchData(object = lung,vars = "time.point") %>% filter(time.point == "on-treatment") %>% rownames()
cells_to_highlight = list(pre_treatment_cells = pre_treatment_cells)
DimPlot(object = lung, cells.highlight = cells_to_highlight, cols.highlight = c("red"), cols = "gray", order = TRUE, label = T, repel = T)
cells_to_highlight = list(on_treatment_cells = on_treatment_cells)
DimPlot(object = lung, cells.highlight = cells_to_highlight, cols.highlight = c("cyan3"), cols = "gray", order = TRUE, label = T, repel = T)
DotPlot(object = lung, features = c("hypoxia_like","interferon_like","cell_cycle","TNFa", "INF2"),scale = T,group.by = 'time.point')
Warning: The following variables were found in both object metadata and the default assay: INF2
Returning metadata; if you want the feature, please use the assay's key (eg. rna_INF2)

Assignment
larger_by = 1.25
lung = program_assignment(dataset = lung,larger_by = larger_by,program_names = colnames(all_metagenes))
p = cell_percentage(dataset = lung,time.point_var = "time.point",by_program = T)
print_tab(plt = p,title = "by program")
p = cell_percentage(dataset = lung,time.point_var = "time.point",by_tp = T,x_order = NULL)
print_tab(plt = p,title = "by timepoint")
# colors = rainbow(ncol(all_metagenes))
# fc <- colorRampPalette(c("lightgreen", "darkgreen"))
# greens = fc(4)
# colors[1] = "blue"
# colors[2:3] = greens[1:2]
# colors[4] = "red"
# colors[5:6] = greens[3:4]
# colors = c(colors,"grey")
# DimPlot(lung,group.by = "program.assignment",pt.size = 0.5,cols =colors)
# colors = rainbow(ncol(all_metagenes))
# colors = c(colors,"grey")
# DimPlot(lung,group.by = "program.assignment",pt.size = 0.5,cols =colors)
DimPlot(lung,group.by = "program.assignment",pt.size = 0.5)
DimPlot(lung,group.by = "patient.ident",pt.size = 0.5)
DimPlot(lung,group.by = "time.point",pt.size = 0.5)
Score
regulation
metagenes_mean_compare(dataset = lung, time.point_var = "time.point",prefix = "patient",patient.ident_var = "patient.ident",pre_on = c("pre-treatment","on-treatment"),axis.text.x = 8,programs = c("hypoxia_like","interferon_like","cell_cycle"))
hypoxia_like per patient

hypoxia_like

interferon_like per patient

interferon_like

cell_cycle per patient

cell_cycle

NA
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 = lung,vars = c(geneIds))
Warning in FetchData.Seurat(object = lung, vars = c(geneIds)) : The
following requested variables were not found: AC027237.1, JPT1, KNL1,
TENT4A, 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,2,3,4)
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(lung@assays$RNA@data[chosen_genes,],2,mean)
lung=AddMetaData(lung,score,hallmark_name)
print_tab(FeaturePlot(object = lung, features = hallmark_name),title = "Expression")
Expression

#plot signature distribution
cc_scores = FetchData(object = lung,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"))
lung = AddMetaData(object = lung,metadata = cc_scores$is_cycling,col.name = "is_cycling")
print_tab(plt = DimPlot(object = lung,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"))
# lung = AddMetaData(object = lung,metadata = cc_scores$is_cycling,col.name = "is_cycling")
# print_tab(plt = DimPlot(object = lung,group.by = "is_cycling") , title = "assignment 2 sd")
#
df = FetchData(object = lung,vars = c("is_cycling","time.point")) %>%
filter (time.point %in% c("pre-treatment","on-treatment")) %>%
droplevels()
test = fisher.test(table(df))
library(ggstatsplot)
plt = ggbarstats(
df, is_cycling, time.point,
results.subtitle = FALSE,
subtitle = paste0(
"Fisher's exact test", ", p-value = ",
round(test$p.value,13))
)
print_tab(plt = plt,title = "fisher")
fisher

NA
#correlation to NMF
cor_res = cor(lung$cell_cycle,lung$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.77656941037506"
Hypoxia
signature
# get genes and create heatmap
hallmark_name = "HALLMARK_HYPOXIA"
genesets =getGmt("./Data/h.all.v7.0.symbols.pluscc.gmt")
geneIds= genesets[[hallmark_name]]@geneIds
hallmars_exp = FetchData(object = lung,vars = c(geneIds))
Warning in FetchData.Seurat(object = lung, vars = c(geneIds)) : The
following requested variables were not found: CAVIN3, CCN5, LARGE1,
CAVIN1, CCN1, CCN2
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 = 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)
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 == 1 | cluster == 2) %>% rownames() #take relevant genes
score <- apply(lung@assays$RNA@data[chosen_genes,],2,mean)
lung=AddMetaData(lung,score,hallmark_name)
print_tab(FeaturePlot(object = lung, features = hallmark_name),title = "Expression")
Expression

NA
cc_scores = FetchData(object = lung,vars = hallmark_name)
plt = ggplot(cc_scores, aes(x=HALLMARK_HYPOXIA)) +
geom_density()+
geom_vline(
aes(xintercept=mean(cc_scores$HALLMARK_HYPOXIA) + sd(cc_scores$HALLMARK_HYPOXIA) ,color="1 SD"),
linetype="dashed", size=1)+
geom_vline(
aes(xintercept=mean(cc_scores$HALLMARK_HYPOXIA) + 2*sd(cc_scores$HALLMARK_HYPOXIA) ,color="2 SD"),
linetype="dashed", size=1)
print_tab(plt = plt,title = "dist")
dist
Warning: Use of cc_scores$HALLMARK_HYPOXIA is
discouraged. Use HALLMARK_HYPOXIA instead. Warning: Use of
cc_scores$HALLMARK_HYPOXIA is discouraged. Use
HALLMARK_HYPOXIA instead. Warning: Use of
cc_scores$HALLMARK_HYPOXIA is discouraged. Use
HALLMARK_HYPOXIA instead. Warning: Use of
cc_scores$HALLMARK_HYPOXIA is discouraged. Use
HALLMARK_HYPOXIA instead.

NA
correlation to
nmf
cor_res = cor(lung$hypoxia_like,lung$HALLMARK_HYPOXIA)
print(paste("correlation of hypoxia program to HALLMARK_HYPOXIA:", cor_res))
[1] "correlation of hypoxia program to HALLMARK_HYPOXIA: 0.487874254360783"
glycolysis signature
hallmark_name = "HALLMARK_GLYCOLYSIS"
genesets =getGmt("./Data/h.all.v7.0.symbols.pluscc.gmt")
geneIds= genesets[[hallmark_name]]@geneIds
hallmars_exp = FetchData(object = lung,vars = c(geneIds))
Warning in FetchData.Seurat(object = lung, vars = c(geneIds)) : The
following requested variables were not found: AC010618.1, AC074143.1
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 = 5
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 == 1 | cluster == 2 | cluster == 5) %>% rownames() #take relevant genes
score <- apply(lung@assays$RNA@data[chosen_genes,],2,mean)
lung=AddMetaData(lung,score,hallmark_name)
print_tab(FeaturePlot(object = lung, features = hallmark_name),title = "Expression")
Expression

NA
cc_scores = FetchData(object = lung,vars = hallmark_name)
plt = ggplot(cc_scores, aes(x=HALLMARK_GLYCOLYSIS)) +
geom_density()+
geom_vline(
aes(xintercept=mean(HALLMARK_GLYCOLYSIS) + sd(HALLMARK_GLYCOLYSIS) ,color="1 SD"),
linetype="dashed", size=1)+
geom_vline(
aes(xintercept=mean(HALLMARK_GLYCOLYSIS) + 2*sd(HALLMARK_GLYCOLYSIS) ,color="2 SD"),
linetype="dashed", size=1)+
geom_vline(
aes(xintercept=mean(HALLMARK_GLYCOLYSIS) ,color="mean"),
linetype="dashed", size=1)
print_tab(plt = plt,title = "dist")
dist

NA
INF
signature
hallmark_name = "HALLMARK_INTERFERON_GAMMA_RESPONSE"
genesets =getGmt("./Data/h.all.v7.0.symbols.pluscc.gmt")
geneIds= genesets[[hallmark_name]]@geneIds
hallmars_exp = FetchData(object = lung,vars = c(geneIds))
Warning in FetchData.Seurat(object = lung, vars = c(geneIds)) : The
following requested variables were not found: AC124319.1
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 = 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)
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_clusters = c(2,3)
chosen_genes = annotation[["myannotation"]] %>% dplyr::filter(cluster %in% chosen_clusters ) %>% rownames() #take relevant genes
score <- apply(lung@assays$RNA@data[chosen_genes,],2,mean)
lung=AddMetaData(lung,score,hallmark_name)
print_tab(FeaturePlot(object = lung, features = hallmark_name),title = "Expression")
Expression

NA
cc_scores = FetchData(object = lung,vars = hallmark_name)
plt = ggplot(cc_scores, aes(x=HALLMARK_INTERFERON_GAMMA_RESPONSE)) +
geom_density()+
geom_vline(
aes(xintercept=mean(HALLMARK_INTERFERON_GAMMA_RESPONSE) + sd(HALLMARK_INTERFERON_GAMMA_RESPONSE) ,color="1 SD"),
linetype="dashed", size=1)+
geom_vline(
aes(xintercept=mean(HALLMARK_INTERFERON_GAMMA_RESPONSE) + 2*sd(HALLMARK_INTERFERON_GAMMA_RESPONSE) ,color="2 SD"),
linetype="dashed", size=1)+
geom_vline(
aes(xintercept=mean(HALLMARK_INTERFERON_GAMMA_RESPONSE) ,color="mean"),
linetype="dashed", size=1)
print_tab(plt = plt,title = "dist")
dist

NA
correlatino to
nmf
cor_res = cor(lung$interferon_like,lung$HALLMARK_INTERFERON_GAMMA_RESPONSE)
print(paste("correlation of ifn program to HALLMARK_INTERFERON_GAMMA_RESPONSE:", cor_res))
[1] "correlation of ifn program to HALLMARK_INTERFERON_GAMMA_RESPONSE: 0.056908124816368"
APC
signature
hallmark_name = "KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION"
# genesets =getGmt("./Data/h.all.v7.0.symbols.pluscc.gmt")
# geneIds= genesets[[hallmark_name]]@geneIds
geneIds = canonical_pathways %>% filter(gs_name == hallmark_name) %>% pull(gene_symbol) %>% intersect(rownames(lung))
hallmars_exp = FetchData(object = lung,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)
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)
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
NA
chosen_clusters = c(4)
chosen_genes = annotation[["myannotation"]] %>% dplyr::filter(cluster %in% chosen_clusters ) %>% rownames() #take relevant genes
score <- apply(lung@assays$RNA@data[chosen_genes,],2,mean)
lung=AddMetaData(lung,score,hallmark_name)
print_tab(FeaturePlot(object = lung, features = hallmark_name),title = "Expression")
Expression

NA
correlatino to
nmf
cor_res = cor(lung$interferon_like,lung$KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION)
print(paste("correlation of ifn program to KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION:", cor_res))
[1] "correlation of ifn program to KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION: 0.421455421412037"
INF
like signature
hallmark_name = "IFN_like_genes"
i = 1
top_genes = patients_geps %>% arrange(desc(patients_geps[i])) #sort by score a
top = head(rownames(top_genes),100) #take top top_genes_num
chosen_genes = top %>% intersect(rownames(lung))
score <- apply(lung@assays$RNA@data[chosen_genes,],2,mean)
lung=AddMetaData(lung,score,hallmark_name)
print_tab(FeaturePlot(object = lung, features = hallmark_name),title = "Expression")
Expression

NA
correlatino to
nmf
cor_res = cor(lung$interferon_like,lung$IFN_like_genes)
print(paste("correlation of ifn program to KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION:", cor_res))
[1] "correlation of ifn program to KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION: 0.417529710113569"
Signature regulation
metagenes_mean_compare(dataset = lung, time.point_var = "time.point",prefix = "patient",patient.ident_var = "patient.ident",pre_on = c("pre-treatment","on-treatment"),axis.text.x = 8,programs = c("HALLMARK_HYPOXIA","HALLMARK_INTERFERON_GAMMA_RESPONSE","KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION","IFN_like_genes","HALLMARK_G2M_CHECKPOINT"))
HALLMARK_HYPOXIA per patient

HALLMARK_HYPOXIA

HALLMARK_INTERFERON_GAMMA_RESPONSE per
patient

HALLMARK_INTERFERON_GAMMA_RESPONSE

KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION per
patient

KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION

IFN_like_genes per patient

IFN_like_genes

HALLMARK_G2M_CHECKPOINT per patient

HALLMARK_G2M_CHECKPOINT

NA
LS0tCnRpdGxlOiAnYHIgcnN0dWRpb2FwaTo6Z2V0U291cmNlRWRpdG9yQ29udGV4dCgpJHBhdGggJT4lIGJhc2VuYW1lKCkgJT4lIGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLHJlcGxhY2VtZW50ID0gIiIpYCcgCmF1dGhvcjogIkF2aXNoYWkgV2l6ZWwiCmRhdGU6ICdgciBTeXMudGltZSgpYCcKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdG9jOiB5ZXMKICAgIHRvY19jb2xsYXBzZTogeWVzCiAgICB0b2NfZmxvYXQ6IAogICAgICBjb2xsYXBzZWQ6IEZBTFNFCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvY19kZXB0aDogMQotLS0KCgojIERhdGEKCmBgYHtyfQpsdW5nID0gcmVhZFJEUygiLi9EYXRhL2x1bmdfY2FuY2VyY2VsbHNfd2l0aFRQX29ubHlQYXRpZW50cy5yZHMiKQpsdW5nX3BhdGllbnRzID0gbHVuZyRwYXRpZW50LmlkZW50ICU+JSB1bmlxdWUoKSAlPiUgYXMuY2hhcmFjdGVyKCkKbHVuZ19wYXRpZW50c19maWx0ZXJlZCA9IGx1bmdfcGF0aWVudHNbIShsdW5nX3BhdGllbnRzICVpbiUgYygiWDEwNTVuZXciLCJYMTA5OSIpKV0gIyByZW1vdmUgcGF0aWVudHMgd2l0aCBsZXNzIHRoYW4gMTAwIG1hbGlnbmFudCBjZWxscwpsdW5nID0gc3Vic2V0KHggPSBsdW5nLHN1YnNldCA9IHBhdGllbnQuaWRlbnQgJWluJSBsdW5nX3BhdGllbnRzX2ZpbHRlcmVkKQpgYGAKCgpgYGB7cn0Kc3VmZml4ID0ieGVub19nZW5lc19ub3JtYWxpemVkXzAtNXNpZ21hXzItN3RoZXRhIgpgYGAKCgpgYGB7cHl0aG9ufQpmcm9tIGNubWYgaW1wb3J0IGNOTUYKc3VmZml4ID0gci5zdWZmaXgKaW1wb3J0IHBpY2tsZQpmID0gb3BlbignLi9EYXRhL2NubWYvY25tZl9vYmplY3RzL3BhdGllbnRzXycgKyBzdWZmaXggKyAnX2NubWZfb2JqLnBja2wnLCAncmInKQpjbm1mX29iaiA9IHBpY2tsZS5sb2FkKGYpCmYuY2xvc2UoKQpgYGAKCgojIEZ1bmN0aW9ucwoKYGBge3J9CmxpYnJhcnkoc3RyaW5naSkKbGlicmFyeShyZXRpY3VsYXRlKQpzb3VyY2VfZnJvbV9naXRodWIocmVwb3NpdG95ID0gIkRFR19mdW5jdGlvbnMiLHZlcnNpb24gPSAiMC4yLjI0IikKc291cmNlX2Zyb21fZ2l0aHViKHJlcG9zaXRveSA9ICJjTk1GX2Z1bmN0aW9ucyIsdmVyc2lvbiA9ICIwLjMuOSIsc2NyaXB0X25hbWUgPSAiY25tZl9mdW5jdGlvbl9IYXJtb255LlIiKSAKYGBgCgojIEsgc2VsZWN0aW9uIHBsb3QKYGBge3IgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9NH0KcGxvdF9wYXRoID0gcGFzdGUwKCIvc2NpL2xhYnMveW90YW1kL2xhYl9zaGFyZS9hdmlzaGFpLndpemVsL1JfcHJvamVjdHMvRUdGUi9EYXRhL2NubWYvY05NRl9wYXRpZW50c19WYXJub3JtX0hhcm1vbnlfIixzdWZmaXgsIi9jTk1GX3BhdGllbnRzX1Zhcm5vcm1fSGFybW9ueV8iLHN1ZmZpeCwiLmtfc2VsZWN0aW9uLnBuZyIpCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKHBsb3RfcGF0aCkKYGBgCgoKCgoKCiMgZ2VwIHNjb3JlcyBmb3IgYWxsIE5NRiBrJ3MKYGBge3B5dGhvbn0KZGVuc2l0eV90aHJlc2hvbGQgPSAwLjEKdXNhZ2Vfbm9ybSwgZ2VwX3Njb3JlczMsIGdlcF90cG0sIHRvcGdlbmVzID0gY25tZl9vYmoubG9hZF9yZXN1bHRzKEs9MywgZGVuc2l0eV90aHJlc2hvbGQ9ZGVuc2l0eV90aHJlc2hvbGQpCnVzYWdlX25vcm0sIGdlcF9zY29yZXM0LCBnZXBfdHBtLCB0b3BnZW5lcyA9IGNubWZfb2JqLmxvYWRfcmVzdWx0cyhLPTQsIGRlbnNpdHlfdGhyZXNob2xkPWRlbnNpdHlfdGhyZXNob2xkKQp1c2FnZV9ub3JtLCBnZXBfc2NvcmVzNSwgZ2VwX3RwbSwgdG9wZ2VuZXMgPSBjbm1mX29iai5sb2FkX3Jlc3VsdHMoSz01LCBkZW5zaXR5X3RocmVzaG9sZD1kZW5zaXR5X3RocmVzaG9sZCkKdXNhZ2Vfbm9ybSwgZ2VwX3Njb3JlczYsIGdlcF90cG0sIHRvcGdlbmVzID0gY25tZl9vYmoubG9hZF9yZXN1bHRzKEs9NiwgZGVuc2l0eV90aHJlc2hvbGQ9ZGVuc2l0eV90aHJlc2hvbGQpCnVzYWdlX25vcm0sIGdlcF9zY29yZXM3LCBnZXBfdHBtLCB0b3BnZW5lcyA9IGNubWZfb2JqLmxvYWRfcmVzdWx0cyhLPTcsIGRlbnNpdHlfdGhyZXNob2xkPWRlbnNpdHlfdGhyZXNob2xkKQp1c2FnZV9ub3JtLCBnZXBfc2NvcmVzOCwgZ2VwX3RwbSwgdG9wZ2VuZXMgPSBjbm1mX29iai5sb2FkX3Jlc3VsdHMoSz04LCBkZW5zaXR5X3RocmVzaG9sZD1kZW5zaXR5X3RocmVzaG9sZCkKdXNhZ2Vfbm9ybSwgZ2VwX3Njb3JlczksIGdlcF90cG0sIHRvcGdlbmVzID0gY25tZl9vYmoubG9hZF9yZXN1bHRzKEs9OSwgZGVuc2l0eV90aHJlc2hvbGQ9ZGVuc2l0eV90aHJlc2hvbGQpCgpgYGAKCgojIEVucmljaG1lbnQgYW5hbHlzaXMgYnkgdG9wIDIwMCBnZW5lcyBvZiBlYWNoIHByb2dyYW0gey50YWJzZXR9CmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTgsIHJlc3VsdHM9J2FzaXMnfQpnZXBfc2NvcmVzMyA9IHB5JGdlcF9zY29yZXMzCmdlcF9zY29yZXM0ID0gcHkkZ2VwX3Njb3JlczQKZ2VwX3Njb3JlczUgPSBweSRnZXBfc2NvcmVzNQpnZXBfc2NvcmVzNiA9IHB5JGdlcF9zY29yZXM2CmdlcF9zY29yZXM3ID0gcHkkZ2VwX3Njb3JlczcKZ2VwX3Njb3JlczggPSBweSRnZXBfc2NvcmVzOApnZXBfc2NvcmVzOSA9IHB5JGdlcF9zY29yZXM5CgphbGxfZ2VwX3Njb3JlcyA9ICBsaXN0KGdlcF9zY29yZXMzID0gZ2VwX3Njb3JlczMsIGdlcF9zY29yZXM0ID0gZ2VwX3Njb3JlczQsIGdlcF9zY29yZXM1ID0gZ2VwX3Njb3JlczUsIGdlcF9zY29yZXM2ID0gZ2VwX3Njb3JlczYsIGdlcF9zY29yZXM3PSBnZXBfc2NvcmVzNywgZ2VwX3Njb3JlczggPSBnZXBfc2NvcmVzOCwgZ2VwX3Njb3JlczkgPSBnZXBfc2NvcmVzOSkKIyBjYW5vbmljYWxfcGF0aHdheXMgPSBtc2lnZGJyKHNwZWNpZXMgPSAiSG9tbyBzYXBpZW5zIiwgY2F0ZWdvcnkgPSAiQzIiKSAlPiUgZHBseXI6OmZpbHRlcihnc19zdWJjYXQgIT0gIkNHUCIpICU+JSAgZHBseXI6OmRpc3RpbmN0KGdzX25hbWUsIGdlbmVfc3ltYm9sKSAKZm9yIChnZXBfbmFtZSBpbiBuYW1lcyhhbGxfZ2VwX3Njb3JlcykpIHsKICBnZXBfc2NvcmVzID0gYWxsX2dlcF9zY29yZXNbW2dlcF9uYW1lXV0KICB0b3BfZ2VuZXNfbnVtID0gMjAwCiAgcGx0X2xpc3QgPSBsaXN0KCkKICBmb3IgKGkgaW4gMTpuY29sKGdlcF9zY29yZXMpKSB7CiAgICB0b3BfZ2VuZXMgPSBnZXBfc2NvcmVzICAlPiUgIGFycmFuZ2UoZGVzYyhnZXBfc2NvcmVzW2ldKSkgI3NvcnQgYnkgc2NvcmUgYQogICAgdG9wID0gaGVhZChyb3duYW1lcyh0b3BfZ2VuZXMpLHRvcF9nZW5lc19udW0pICN0YWtlIHRvcCB0b3BfZ2VuZXNfbnVtCiAgICByZXMgPSBnZW5lc192ZWNfZW5yaWNobWVudChnZW5lcyA9IHRvcCxiYWNrZ3JvdW5kID0gcm93bmFtZXMoZ2VwX3Njb3JlcyksaG9tZXIgPSBULHRpdGxlID0gCiAgICAgICAgICAgICAgICAgICAgICBuYW1lcyhnZXBfc2NvcmVzKVtpXSxzaWxlbnQgPSBULHJldHVybl9hbGwgPSBULGN1c3RvbV9wYXRod2F5cyA9IE5VTEwgKQogICAgIAogICAgcGx0X2xpc3RbW2ldXSA9IHJlcyRwbHQKICB9CiAgcHJpbnRfdGFiKHBsdCA9ICAgZ2dhcnJhbmdlKHBsb3RsaXN0ID0gcGx0X2xpc3QpLAogICAgICAgICAgICB0aXRsZSA9IGdlcF9uYW1lKQp9CmBgYAoKIyBDaG9zZW4gSwpgYGB7cHl0aG9ufQpzZWxlY3RlZF9rID0gOApwcmludCgic2VsZWN0ZWQgayA9ICIsc2VsZWN0ZWRfaykKZGVuc2l0eV90aHJlc2hvbGQgPSAwLjEKY25tZl9vYmouY29uc2Vuc3VzKGs9c2VsZWN0ZWRfaywgZGVuc2l0eV90aHJlc2hvbGQ9ZGVuc2l0eV90aHJlc2hvbGQsc2hvd19jbHVzdGVyaW5nPVRydWUpCnVzYWdlX25vcm0sIGdlcF9zY29yZXMsIGdlcF90cG0sIHRvcGdlbmVzID0gY25tZl9vYmoubG9hZF9yZXN1bHRzKEs9c2VsZWN0ZWRfaywgZGVuc2l0eV90aHJlc2hvbGQ9ZGVuc2l0eV90aHJlc2hvbGQpCmBgYApgYGB7cn0KcGF0aWVudHNfZ2VwcyA9IHB5JGdlcF9zY29yZXMKYGBgCgojIyBwcm9ncmFtcyBlbnJpY2htZW50IHdpdGggY2Fub25pY2FsCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTgsIHJlc3VsdHM9J2hpZGUnfQoKY2Fub25pY2FsX3BhdGh3YXlzID0gbXNpZ2RicihzcGVjaWVzID0gIkhvbW8gc2FwaWVucyIsIGNhdGVnb3J5ID0gIkMyIikgJT4lIGRwbHlyOjpmaWx0ZXIoZ3Nfc3ViY2F0ICE9ICJDR1AiKSAlPiUgIGRwbHlyOjpkaXN0aW5jdChnc19uYW1lLCBnZW5lX3N5bWJvbCkKCnRvcF9nZW5lc19udW0gPSAyMDAKcGx0X2xpc3QgPSBsaXN0KCkKZm9yIChpIGluIDE6bmNvbChwYXRpZW50c19nZXBzKSkgewogIHRvcF9nZW5lcyA9IHBhdGllbnRzX2dlcHMgICU+JSAgYXJyYW5nZShkZXNjKHBhdGllbnRzX2dlcHNbaV0pKSAjc29ydCBieSBzY29yZSBhCiAgdG9wID0gaGVhZChyb3duYW1lcyh0b3BfZ2VuZXMpLHRvcF9nZW5lc19udW0pICN0YWtlIHRvcCB0b3BfZ2VuZXNfbnVtCiAgcmVzID0gZ2VuZXNfdmVjX2VucmljaG1lbnQoZ2VuZXMgPSB0b3AsYmFja2dyb3VuZCA9IHJvd25hbWVzKHBhdGllbnRzX2dlcHMpLGhvbWVyID0gVCx0aXRsZSA9IAogICAgICAgICAgICAgICAgICAgIG5hbWVzKHBhdGllbnRzX2dlcHMpW2ldLHNpbGVudCA9IFQscmV0dXJuX2FsbCA9IFQsY3VzdG9tX3BhdGh3YXlzID0gY2Fub25pY2FsX3BhdGh3YXlzICkKICAgCiAgcGx0X2xpc3RbW2ldXSA9IHJlcyRwbHQKfQpncmlkRXh0cmE6OmdyaWQuYXJyYW5nZShncm9icyA9IHBsdF9saXN0KQpgYGAKCiMgQ29ycmVsYXRpb24gb2YgcHJvZ3JhbXMKCmBgYHtyfQpjb3JfcmVzID0gY29yKHBhdGllbnRzX2dlcHMpCmJyZWFrcyA8LSBjKHNlcSgtMSwxLGJ5PTAuMDEpKQpjb2xvcnNfZm9yX3Bsb3QgPC0gY29sb3JSYW1wUGFsZXR0ZShjb2xvcnMgPSBjKCJibHVlIiwgIndoaXRlIiwgInJlZCIpKShuID0gbGVuZ3RoKGJyZWFrcykpCgpwaHQgPSBwaGVhdG1hcChjb3JfcmVzLGNvbG9yID0gY29sb3JzX2Zvcl9wbG90LGJyZWFrcyA9IGJyZWFrcykKcHJpbnRfdGFiKHBodCx0aXRsZSA9ICJjb3JyZWxhdGlvbiIpCgojY29ycmVsYXRpb24gYmFzZWQgb24gdG9wIDIwMAphbGxfdG9wPSBjKCkKZm9yIChpIGluIDE6bmNvbChwYXRpZW50c19nZXBzKSkgewogIHRvcF9nZW5lcyA9IHBhdGllbnRzX2dlcHMgICU+JSAgYXJyYW5nZShkZXNjKHBhdGllbnRzX2dlcHNbaV0pKSAjc29ydCBieSBzY29yZSBhCiAgdG9wID0gaGVhZChyb3duYW1lcyh0b3BfZ2VuZXMpLDIwMCkgI3Rha2UgdG9wIHRvcF9nZW5lc19udW0KYWxsX3RvcCA9IGMoYWxsX3RvcCx0b3ApCn0KZ2VwX3Njb3Jlc190b3AgPSBwYXRpZW50c19nZXBzW2FsbF90b3AsXQpjb3JfcmVzID0gY29yKGdlcF9zY29yZXNfdG9wKQoKYnJlYWtzIDwtIGMoc2VxKC0xLDEsYnk9MC4wMSkpCmNvbG9yc19mb3JfcGxvdCA8LSBjb2xvclJhbXBQYWxldHRlKGNvbG9ycyA9IGMoImJsdWUiLCAid2hpdGUiLCAicmVkIikpKG4gPSBsZW5ndGgoYnJlYWtzKSkKCiMgY29ycmVsYXRpb24gYnkgdG9wIDE1MCBjb21iaW5lZApwaHQgPSBwaGVhdG1hcChjb3JfcmVzLGNvbG9yID0gY29sb3JzX2Zvcl9wbG90LGJyZWFrcyA9IGJyZWFrcykKcHJpbnRfdGFiKHBodCx0aXRsZSA9ICJ0b3AgMjAwIGdlbmVzIGNvcnJlbGF0aW9uIikKCmBgYAoKIyBDb21iaW5lIHNpbWlsYXIgcHJvZ3JhbXMKYGBge3J9Cmdyb3Vwc19saXN0ID0gYyg0LDMsNikKcGF0aWVudHNfZ2VwcyA9IHVuaW9uX3Byb2dyYW1zKGdyb3Vwc19saXN0ID0gZ3JvdXBzX2xpc3QsYWxsX21ldGFnZW5lcyA9IHBhdGllbnRzX2dlcHMpCmBgYAoKCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTE0fQpwbHRfbGlzdCA9IGxpc3QoKQoKZm9yIChwcm9ncmFtICBpbiBuYW1lcyAocGF0aWVudHNfZ2VwcykpIHsKIHAgPSBnZ3Bsb3QocGF0aWVudHNfZ2VwcywgYWVzKHg9ISFlbnN5bShwcm9ncmFtKSkpICsKICBnZW9tX2RlbnNpdHkoKSt4bGFiKHByb2dyYW0pKwogICBnZW9tX3ZsaW5lKAogICAgYWVzKHhpbnRlcmNlcHQ9c29ydChwYXRpZW50c19nZXBzWyxwcm9ncmFtXSxUUlVFKVsyMDBdICAsY29sb3I9InRvcDIwMCIpLAogICAgICAgICAgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkrCiAgIGdlb21fdmxpbmUoCiAgICBhZXMoeGludGVyY2VwdD1zb3J0KHBhdGllbnRzX2dlcHNbLHByb2dyYW1dLFRSVUUpWzEwMF0gICxjb2xvcj0idG9wMTAwIiksCiAgICAgICAgICBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKSsKICAgICAgZ2VvbV92bGluZSgKICAgIGFlcyh4aW50ZXJjZXB0PXNvcnQocGF0aWVudHNfZ2Vwc1sscHJvZ3JhbV0sVFJVRSlbNTBdICAsY29sb3I9InRvcDUwIiksCiAgICAgICAgICBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKSsKICAgICAgICAgZ2VvbV92bGluZSgKICAgIGFlcyh4aW50ZXJjZXB0PXNvcnQocGF0aWVudHNfZ2Vwc1sscHJvZ3JhbV0sVFJVRSlbMTUwXSAgLGNvbG9yPSJ0b3AxNTAiKSwKICAgICAgICAgIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpKwogICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJ0b3AgbiBnZW5lcyIsIHZhbHVlcyA9IGModG9wMjAwID0gImJsdWUiLHRvcDEwMCA9ICJyZWQiLHRvcDE1MCA9ICJ5ZWxsb3ciLHRvcDUwID0gImdyZWVuIikpCiAgIHBsdF9saXN0W1twcm9ncmFtXV0gPC0gcAoKfQogCmdnYXJyYW5nZShwbG90bGlzdCA9IHBsdF9saXN0KQoKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04LCByZXN1bHRzPSdoaWRlJ30KdG9wX2dlbmVzX251bSA9IDIwMApwbHRfbGlzdCA9IGxpc3QoKQpmb3IgKGkgaW4gMTpuY29sKHBhdGllbnRzX2dlcHMpKSB7CiAgdG9wX2dlbmVzID0gcGF0aWVudHNfZ2VwcyAgJT4lICBhcnJhbmdlKGRlc2MocGF0aWVudHNfZ2Vwc1tpXSkpICNzb3J0IGJ5IHNjb3JlIGEKICB0b3AgPSBoZWFkKHJvd25hbWVzKHRvcF9nZW5lcyksdG9wX2dlbmVzX251bSkgI3Rha2UgdG9wIHRvcF9nZW5lc19udW0KICByZXMgPSBnZW5lc192ZWNfZW5yaWNobWVudChnZW5lcyA9IHRvcCxiYWNrZ3JvdW5kID0gcm93bmFtZXMocGF0aWVudHNfZ2VwcyksaG9tZXIgPSBULHRpdGxlID0gCiAgICAgICAgICAgICAgICAgICAgIG5hbWVzKHBhdGllbnRzX2dlcHMpW2ldLHNpbGVudCA9IFQscmV0dXJuX2FsbCA9IFQsY3VzdG9tX3BhdGh3YXlzID0gY2Fub25pY2FsX3BhdGh3YXlzKQogICAKICBwbHRfbGlzdFtbaV1dID0gcmVzJHBsdAp9CmdyaWRFeHRyYTo6Z3JpZC5hcnJhbmdlKGdyb2JzID0gcGx0X2xpc3QpCmBgYAoKIyBDYWxjdWxhdGUgdXNhZ2UKYGBge3IgZWNobz1UUlVFLCByZXN1bHRzPSdhc2lzJ30KIyBnZXQgZXhwcmVzc2lvbiB3aXRoIGdlbmVzIGluIGNubWYgaW5wdXQKbHVuZyA9IEZpbmRWYXJpYWJsZUZlYXR1cmVzKG9iamVjdCA9IGx1bmcsbmZlYXR1cmVzID0gMjAwMCkKZ2VuZXMgPSByb3duYW1lcyhsdW5nKVtyb3duYW1lcyhsdW5nKSAlaW4lIFZhcmlhYmxlRmVhdHVyZXMob2JqZWN0ID0geGVubylbMToyMDAwXV0KCmx1bmdfZXhwcmVzc2lvbiA9IHQoYXMubWF0cml4KEdldEFzc2F5RGF0YShsdW5nLHNsb3Q9J2RhdGEnKSkpIApsdW5nX2V4cHJlc3Npb24gPSAyKipsdW5nX2V4cHJlc3Npb24gI2NvbnZlcnQgZnJvbSBsb2cyKHRwbSsxKSB0byB0cG0KbHVuZ19leHByZXNzaW9uID0gbHVuZ19leHByZXNzaW9uLTEKbHVuZ19leHByZXNzaW9uID0gbHVuZ19leHByZXNzaW9uWyxnZW5lc10gJT4lIGFzLmRhdGEuZnJhbWUoKQoKYWxsXzBfZ2VuZXMgPSBjb2xuYW1lcyhsdW5nX2V4cHJlc3Npb24pW2NvbFN1bXMobHVuZ19leHByZXNzaW9uPT0wLCBuYS5ybT1UUlVFKT09bnJvdyhsdW5nX2V4cHJlc3Npb24pXSAjZGVsZXRlIHJvd3MgdGhhdCBoYXZlIGFsbCAwCmdlbmVzID0gZ2VuZXNbIWdlbmVzICVpbiUgYWxsXzBfZ2VuZXNdCmx1bmdfZXhwcmVzc2lvbiA9IGx1bmdfZXhwcmVzc2lvblssIWNvbG5hbWVzKGx1bmdfZXhwcmVzc2lvbikgJWluJSBhbGxfMF9nZW5lc10KZ2ModmVyYm9zZSA9IEYpCmBgYAoKCgoKYGBge3B5dGhvbn0KCmx1bmdfZXhwcmVzc2lvbiA9IHIubHVuZ19leHByZXNzaW9uCmdlbmVzID0gci5nZW5lcwpnZXBfc2NvcmVzID0gci5wYXRpZW50c19nZXBzCnVzYWdlX2J5X2NhbGMgPSBnZXRfdXNhZ2VfZnJvbV9zY29yZShjb3VudHM9bHVuZ19leHByZXNzaW9uLHRwbT1sdW5nX2V4cHJlc3Npb24sZ2VuZXM9Z2VuZXMsY25tZl9vYmo9Y25tZl9vYmosaz1zZWxlY3RlZF9rLHN1bVRvMT1GYWxzZSkKYGBgCgoKYGBge3J9CnVzYWdlX2J5X2NhbGMgPSBweSR1c2FnZV9ieV9jYWxjCmdyb3Vwc19saXN0ID0gYyg0LDMsNikKdXNhZ2VfYnlfY2FsYyA9IHVuaW9uX3Byb2dyYW1zKGdyb3Vwc19saXN0ID0gZ3JvdXBzX2xpc3QsYWxsX21ldGFnZW5lcyA9IHVzYWdlX2J5X2NhbGMpCnVzYWdlX2J5X2NhbGMgPSBhcHBseSh1c2FnZV9ieV9jYWxjLCBNQVJHSU4gPSAxLCBzdW1fMl9vbmUpICU+JSB0KCkgJT4lIGFzLmRhdGEuZnJhbWUoKQp1c2FnZV9ieV9jYWxjID11c2FnZV9ieV9jYWxjICU+JSByZW5hbWUoY2VsbF9jeWNsZSA9IGdlcDQuMy42LCBoeXBveGlhX2xpa2UgPSBnZXAyLCBpbnRlcmZlcm9uX2xpa2UgPSBnZXAxLCBUTkZhID0gIGdlcDUsIElORjIgPSBnZXA3KQpgYGAKCgoKIyBVc2dhZ2UgVU1BUApgYGB7ciBmaWcuaGVpZ2h0PTksIGZpZy53aWR0aD0xM30KYWxsX21ldGFnZW5lcz0gdXNhZ2VfYnlfY2FsYwoKI2FkZCBlYWNoIG1ldGFnZW5lIHRvIG1ldGFkYXRhCmZvciAoaSBpbiAxOm5jb2woYWxsX21ldGFnZW5lcykpIHsKICBtZXRhZ2VfbWV0YWRhdGEgPSBhbGxfbWV0YWdlbmVzICU+JSBkcGx5cjo6c2VsZWN0KGkpCiAgbHVuZyA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IGx1bmcsbWV0YWRhdGEgPSBtZXRhZ2VfbWV0YWRhdGEpCn0KRmVhdHVyZVBsb3Qob2JqZWN0ID0gbHVuZyxmZWF0dXJlcyA9IGNvbG5hbWVzKGFsbF9tZXRhZ2VuZXMpLG5jb2wgPSAzKQpgYGAKCgpgYGB7ciBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD0xMH0KRGltUGxvdChvYmplY3QgPSBsdW5nLGdyb3VwLmJ5ID0gInRpbWUucG9pbnQiLHB0LnNpemUgPSAwLjUpCnByZV90cmVhdG1lbnRfY2VsbHMgPSBGZXRjaERhdGEob2JqZWN0ID0gbHVuZyx2YXJzID0gInRpbWUucG9pbnQiKSAlPiUgZmlsdGVyKHRpbWUucG9pbnQgPT0gInByZS10cmVhdG1lbnQiKSAlPiUgcm93bmFtZXMoKQpvbl90cmVhdG1lbnRfY2VsbHMgPSBGZXRjaERhdGEob2JqZWN0ID0gbHVuZyx2YXJzID0gInRpbWUucG9pbnQiKSAlPiUgZmlsdGVyKHRpbWUucG9pbnQgPT0gIm9uLXRyZWF0bWVudCIpICU+JSByb3duYW1lcygpCgpjZWxsc190b19oaWdobGlnaHQgPSAgbGlzdChwcmVfdHJlYXRtZW50X2NlbGxzID0gcHJlX3RyZWF0bWVudF9jZWxscykKRGltUGxvdChvYmplY3QgPSBsdW5nLCBjZWxscy5oaWdobGlnaHQgPSBjZWxsc190b19oaWdobGlnaHQsIGNvbHMuaGlnaGxpZ2h0ID0gYygicmVkIiksIGNvbHMgPSAiZ3JheSIsIG9yZGVyID0gVFJVRSwgbGFiZWwgPSBULCByZXBlbCA9IFQpCgpjZWxsc190b19oaWdobGlnaHQgPSAgbGlzdChvbl90cmVhdG1lbnRfY2VsbHMgPSBvbl90cmVhdG1lbnRfY2VsbHMpCkRpbVBsb3Qob2JqZWN0ID0gbHVuZywgY2VsbHMuaGlnaGxpZ2h0ID0gY2VsbHNfdG9faGlnaGxpZ2h0LCBjb2xzLmhpZ2hsaWdodCA9IGMoImN5YW4zIiksIGNvbHMgPSAiZ3JheSIsIG9yZGVyID0gVFJVRSwgIGxhYmVsID0gVCwgcmVwZWwgPSBUKQoKYGBgCgoKCmBgYHtyIGZpZy53aWR0aD05fQpEb3RQbG90KG9iamVjdCA9IGx1bmcsIGZlYXR1cmVzID0gYygiaHlwb3hpYV9saWtlIiwiaW50ZXJmZXJvbl9saWtlIiwiY2VsbF9jeWNsZSIsIlRORmEiLCAiSU5GMiIpLHNjYWxlID0gVCxncm91cC5ieSAgPSAndGltZS5wb2ludCcpCmBgYAoKIyBBc3NpZ25tZW50IApgYGB7cn0KbGFyZ2VyX2J5ID0gMS4yNQpsdW5nID0gcHJvZ3JhbV9hc3NpZ25tZW50KGRhdGFzZXQgPSBsdW5nLGxhcmdlcl9ieSA9IGxhcmdlcl9ieSxwcm9ncmFtX25hbWVzID0gY29sbmFtZXMoYWxsX21ldGFnZW5lcykpCmBgYAoKCgpgYGB7ciBlY2hvPVRSVUUsIGZpZy53aWR0aD0xMCwgcmVzdWx0cz0nYXNpcyd9CnAgPSBjZWxsX3BlcmNlbnRhZ2UoZGF0YXNldCA9IGx1bmcsdGltZS5wb2ludF92YXIgPSAidGltZS5wb2ludCIsYnlfcHJvZ3JhbSA9IFQpCnByaW50X3RhYihwbHQgPSBwLHRpdGxlID0gImJ5IHByb2dyYW0iKQpwID0gY2VsbF9wZXJjZW50YWdlKGRhdGFzZXQgPSBsdW5nLHRpbWUucG9pbnRfdmFyID0gInRpbWUucG9pbnQiLGJ5X3RwID0gVCx4X29yZGVyID0gTlVMTCkKcHJpbnRfdGFiKHBsdCA9IHAsdGl0bGUgPSAiYnkgdGltZXBvaW50IikKCmBgYAoKYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTB9CiMgY29sb3JzID0gIHJhaW5ib3cobmNvbChhbGxfbWV0YWdlbmVzKSkKIyBmYyA8LSBjb2xvclJhbXBQYWxldHRlKGMoImxpZ2h0Z3JlZW4iLCAiZGFya2dyZWVuIikpCiMgZ3JlZW5zID0gZmMoNCkKIyBjb2xvcnNbMV0gPSAiYmx1ZSIKIyBjb2xvcnNbMjozXSA9IGdyZWVuc1sxOjJdCiMgY29sb3JzWzRdID0gInJlZCIKIyBjb2xvcnNbNTo2XSA9IGdyZWVuc1szOjRdCiMgY29sb3JzID0gYyhjb2xvcnMsImdyZXkiKQojIERpbVBsb3QobHVuZyxncm91cC5ieSA9ICJwcm9ncmFtLmFzc2lnbm1lbnQiLHB0LnNpemUgPSAwLjUsY29scyA9Y29sb3JzKQoKCiMgY29sb3JzID0gIHJhaW5ib3cobmNvbChhbGxfbWV0YWdlbmVzKSkKIyBjb2xvcnMgPSBjKGNvbG9ycywiZ3JleSIpCiMgRGltUGxvdChsdW5nLGdyb3VwLmJ5ID0gInByb2dyYW0uYXNzaWdubWVudCIscHQuc2l6ZSA9IDAuNSxjb2xzID1jb2xvcnMpCgpEaW1QbG90KGx1bmcsZ3JvdXAuYnkgPSAicHJvZ3JhbS5hc3NpZ25tZW50IixwdC5zaXplID0gMC41KQpEaW1QbG90KGx1bmcsZ3JvdXAuYnkgPSAicGF0aWVudC5pZGVudCIscHQuc2l6ZSA9IDAuNSkKRGltUGxvdChsdW5nLGdyb3VwLmJ5ID0gInRpbWUucG9pbnQiLHB0LnNpemUgPSAwLjUpCmBgYAoKCiMgU2NvcmUgcmVndWxhdGlvbiB7LnRhYnNldH0KCmBgYHtyIGVjaG89VFJVRSwgcmVzdWx0cz0nYXNpcyd9Cm1ldGFnZW5lc19tZWFuX2NvbXBhcmUoZGF0YXNldCA9IGx1bmcsIHRpbWUucG9pbnRfdmFyID0gInRpbWUucG9pbnQiLHByZWZpeCA9ICJwYXRpZW50IixwYXRpZW50LmlkZW50X3ZhciA9ICJwYXRpZW50LmlkZW50IixwcmVfb24gPSBjKCJwcmUtdHJlYXRtZW50Iiwib24tdHJlYXRtZW50IiksYXhpcy50ZXh0LnggPSA4LHByb2dyYW1zID0gYygiaHlwb3hpYV9saWtlIiwiaW50ZXJmZXJvbl9saWtlIiwiY2VsbF9jeWNsZSIpKQpgYGAKCgoKIyBDQyBzaWduYXR1cmUgIHsudGFic2V0fQoKCgpgYGB7ciByZXN1bHRzPSdhc2lzJ30KCmBgYAoKYGBge3IgZWNobz1UUlVFLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD0xMCwgcmVzdWx0cz0nYXNpcyd9CiMgZ2V0IGdlbmVzIGFuZCBwbG90IGNvciBoZWF0bWFwCmhhbGxtYXJrX25hbWUgPSAiSEFMTE1BUktfRzJNX0NIRUNLUE9JTlQiCmdlbmVzZXRzICA9Z2V0R210KCIuL0RhdGEvaC5hbGwudjcuMC5zeW1ib2xzLnBsdXNjYy5nbXQiKQpnZW5lSWRzPSBnZW5lc2V0c1tbaGFsbG1hcmtfbmFtZV1dQGdlbmVJZHMKaGFsbG1hcnNfZXhwID0gRmV0Y2hEYXRhKG9iamVjdCA9IGx1bmcsdmFycyA9IGMoZ2VuZUlkcykpCmhhbGxtYXJzX2V4cCA9IGhhbGxtYXJzX2V4cFssY29sU3VtcyhoYWxsbWFyc19leHBbXSk+MF0gI3JlbW92ZSBubyBleHByZXNzaW9uIGdlbmVzCmhhbGxtYXJrX2NvciA9IGNvcihoYWxsbWFyc19leHApCnBodDEgPSBwaGVhdG1hcChtYXQgPSBoYWxsbWFya19jb3Isc2lsZW50ID0gVCkKCiMgbWFrZSBhbm5vdGF0aW9ucwpudW1fb2ZfY2x1c3RlcnMgPSA0CmNsdXN0ZXJpbmdfZGlzdGFuY2UgPSAiZXVjbGlkZWFuIgpteWFubm90YXRpb24gPSBhcy5kYXRhLmZyYW1lKGN1dHJlZShwaHQxW1sidHJlZV9yb3ciXV0sIGsgPSBudW1fb2ZfY2x1c3RlcnMpKSAjc3BsaXQgaW50byBrIGNsdXN0ZXJzCm5hbWVzKG15YW5ub3RhdGlvbilbMV0gPSAiY2x1c3RlciIKbXlhbm5vdGF0aW9uJGNsdXN0ZXIgPSBhcy5mYWN0b3IobXlhbm5vdGF0aW9uJGNsdXN0ZXIpCnBhbGV0dGUxIDwtYnJld2VyLnBhbChudW1fb2ZfY2x1c3RlcnMsICJQYWlyZWQiKQpuYW1lcyhwYWxldHRlMSkgPSB1bmlxdWUobXlhbm5vdGF0aW9uJGNsdXN0ZXIpCmFubl9jb2xvcnMgPSBsaXN0IChjbHVzdGVyID0gcGFsZXR0ZTEpCmFubm90YXRpb24gPSBsaXN0KGFubl9jb2xvcnMgPSBhbm5fY29sb3JzLCBteWFubm90YXRpb24gPSBteWFubm90YXRpb24pCgojY2hvb3NlIGNvbG9ycwpjb2xvcnMgPC0gYyhzZXEoLTEsMSxieT0wLjAxKSkKbXlfcGFsZXR0ZSA8LSBjKCJibHVlIixjb2xvclJhbXBQYWxldHRlKGNvbG9ycyA9IGMoImJsdWUiLCAid2hpdGUiLCAicmVkIikpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAobiA9IGxlbmd0aChjb2xvcnMpLTMpLCAicmVkIikKCgpwcmludF90YWIocGx0ID0gCiAgICAgICAgICAgICAgcGhlYXRtYXAobWF0ID0gaGFsbG1hcmtfY29yLGFubm90YXRpb25fY29sID0gIGFubm90YXRpb25bWyJteWFubm90YXRpb24iXV0sIGFubm90YXRpb25fY29sb3JzID0gYW5ub3RhdGlvbltbImFubl9jb2xvcnMiXV0sIGNsdXN0ZXJpbmdfZGlzdGFuY2Vfcm93cyA9IGNsdXN0ZXJpbmdfZGlzdGFuY2UsY2x1c3RlcmluZ19kaXN0YW5jZV9jb2xzID0gY2x1c3RlcmluZ19kaXN0YW5jZSxjb2xvciA9IG15X3BhbGV0dGUsYnJlYWtzID0gY29sb3JzLHNob3dfcm93bmFtZXMgPSBGLHNob3dfY29sbmFtZXMgPSBGKQogICAgICAgICAgICAsdGl0bGUgPSAiZ2VuZXMgZXhwcmVzc2lvbiBoZWF0bWFwIikKYGBgCgpgYGB7ciBlY2hvPVRSVUUsIHJlc3VsdHM9J2FzaXMnfQojY2hvb3NlIGNsdXN0ZXJzCmNob3Nlbl9jbHVzdGVycyA9IGMoMSwyLDMsNCkKcHJpbnQgKCJjaG9zZW5fY2x1c3RlcnM9ICIsIGNob3Nlbl9jbHVzdGVycykKCiNVTUFQIGV4cHJlc3Npb24gb2Ygc2lnbmF0dXJlCmNob3Nlbl9nZW5lcyA9IGFubm90YXRpb25bWyJteWFubm90YXRpb24iXV0gJT4lIGRwbHlyOjpmaWx0ZXIoY2x1c3RlciAlaW4lIGNob3Nlbl9jbHVzdGVycykgJT4lIHJvd25hbWVzKCkgI3Rha2UgcmVsZXZhbnQgZ2VuZXMKc2NvcmUgPC0gYXBwbHkobHVuZ0Bhc3NheXMkUk5BQGRhdGFbY2hvc2VuX2dlbmVzLF0sMixtZWFuKQpsdW5nPUFkZE1ldGFEYXRhKGx1bmcsc2NvcmUsaGFsbG1hcmtfbmFtZSkKCnByaW50X3RhYihGZWF0dXJlUGxvdChvYmplY3QgPSBsdW5nLCBmZWF0dXJlcyA9IGhhbGxtYXJrX25hbWUpLHRpdGxlID0gIkV4cHJlc3Npb24iKQoKI3Bsb3Qgc2lnbmF0dXJlIGRpc3RyaWJ1dGlvbgpjY19zY29yZXMgPSBGZXRjaERhdGEob2JqZWN0ID0gbHVuZyx2YXJzID0gIkhBTExNQVJLX0cyTV9DSEVDS1BPSU5UIikKcGx0ICA9ICBnZ3Bsb3QoY2Nfc2NvcmVzLCBhZXMoeD1IQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVCkpICsKICBnZW9tX2RlbnNpdHkoKSsKICAgZ2VvbV92bGluZSgKICAgIGFlcyh4aW50ZXJjZXB0PW1lYW4oY2Nfc2NvcmVzJEhBTExNQVJLX0cyTV9DSEVDS1BPSU5UKSArIHNkKGNjX3Njb3JlcyRIQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVCkgLGNvbG9yPSIxIFNEIiksCiAgICAgICAgICBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKSsKICAgIGdlb21fdmxpbmUoCiAgICBhZXMoeGludGVyY2VwdD1tZWFuKGNjX3Njb3JlcyRIQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVCkgKyAyKnNkKGNjX3Njb3JlcyRIQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVCkgLGNvbG9yPSIyIFNEIiksCiAgICAgICAgICBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKQoKcHJpbnRfdGFiKHBsdCA9IHBsdCx0aXRsZSA9ICJkaXN0IikKCiMgUGxvdCBhc3NpZ25tZW50IAoKY2Nfc2NvcmVzID0gY2Nfc2NvcmVzICU+JSBtdXRhdGUoaXNfY3ljbGluZyA9IGlmX2Vsc2UoY29uZGl0aW9uID0gCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEhBTExNQVJLX0cyTV9DSEVDS1BPSU5UID4gbWVhbihIQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVCkgKyBzZChIQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cnVlID0gImN5Y2xpbmciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFsc2UgPSAibm9uX2N5Y2xpbmciKSkKbHVuZyA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IGx1bmcsbWV0YWRhdGEgPSBjY19zY29yZXMkaXNfY3ljbGluZyxjb2wubmFtZSA9ICJpc19jeWNsaW5nIikKcHJpbnRfdGFiKHBsdCA9IERpbVBsb3Qob2JqZWN0ID0gbHVuZyxncm91cC5ieSA9ICJpc19jeWNsaW5nIikgLCB0aXRsZSA9ICJhc3NpZ25tZW50IDEgc2QiKQoKIyAKIyBjY19zY29yZXMgPSBjY19zY29yZXMgJT4lIG11dGF0ZShpc19jeWNsaW5nID0gaWZfZWxzZShjb25kaXRpb24gPSAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBIQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVCA+IG1lYW4oSEFMTE1BUktfRzJNX0NIRUNLUE9JTlQpICsgMipzZChjY19zY29yZXMkSEFMTE1BUktfRzJNX0NIRUNLUE9JTlQpLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cnVlID0gImN5Y2xpbmciLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWxzZSA9ICJub25fY3ljbGluZyIpKQojIGx1bmcgPSBBZGRNZXRhRGF0YShvYmplY3QgPSBsdW5nLG1ldGFkYXRhID0gY2Nfc2NvcmVzJGlzX2N5Y2xpbmcsY29sLm5hbWUgPSAiaXNfY3ljbGluZyIpCiMgcHJpbnRfdGFiKHBsdCA9IERpbVBsb3Qob2JqZWN0ID0gbHVuZyxncm91cC5ieSA9ICJpc19jeWNsaW5nIikgLCB0aXRsZSA9ICJhc3NpZ25tZW50IDIgc2QiKQojIAoKYGBgCgoKCgpgYGB7ciBlY2hvPVRSVUUsIHJlc3VsdHM9J2FzaXMnfQogZGYgID0gRmV0Y2hEYXRhKG9iamVjdCA9IGx1bmcsdmFycyA9IGMoImlzX2N5Y2xpbmciLCJ0aW1lLnBvaW50IikpICU+JSAKICAgIGZpbHRlciAodGltZS5wb2ludCAlaW4lIGMoInByZS10cmVhdG1lbnQiLCJvbi10cmVhdG1lbnQiKSkgJT4lIAogICAgZHJvcGxldmVscygpIAogIHRlc3QgPSBmaXNoZXIudGVzdCh0YWJsZShkZikpCiAgICAKICBsaWJyYXJ5KGdnc3RhdHNwbG90KQoKICAgIHBsdCA9IGdnYmFyc3RhdHMoCiAgICBkZiwgaXNfY3ljbGluZywgdGltZS5wb2ludCwKICAgIHJlc3VsdHMuc3VidGl0bGUgPSBGQUxTRSwKICAgIHN1YnRpdGxlID0gcGFzdGUwKAogICAgICAiRmlzaGVyJ3MgZXhhY3QgdGVzdCIsICIsIHAtdmFsdWUgPSAiLAogICAgICAgcm91bmQodGVzdCRwLnZhbHVlLDEzKSkKICAgICkKICAKcHJpbnRfdGFiKHBsdCA9IHBsdCx0aXRsZSA9ICJmaXNoZXIiKQpgYGAKI2NvcnJlbGF0aW9uIHRvIE5NRgpgYGB7cn0KY29yX3JlcyA9IGNvcihsdW5nJGNlbGxfY3ljbGUsbHVuZyRIQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVCkKcHJpbnQocGFzdGUoImNvcnJlbGF0aW9uIG9mIGNjIHByZ29yYW0gdG8gSEFMTE1BUktfRzJNX0NIRUNLUE9JTlQ6IiwgY29yX3JlcykpCmBgYAoKIyBIeXBveGlhIHNpZ25hdHVyZSAgey50YWJzZXR9CgoKYGBge3IgZWNobz1UUlVFLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD0xMCwgcmVzdWx0cz0nYXNpcyd9CiMgZ2V0IGdlbmVzIGFuZCBjcmVhdGUgaGVhdG1hcApoYWxsbWFya19uYW1lID0gIkhBTExNQVJLX0hZUE9YSUEiCmdlbmVzZXRzICA9Z2V0R210KCIuL0RhdGEvaC5hbGwudjcuMC5zeW1ib2xzLnBsdXNjYy5nbXQiKQpnZW5lSWRzPSBnZW5lc2V0c1tbaGFsbG1hcmtfbmFtZV1dQGdlbmVJZHMKaGFsbG1hcnNfZXhwID0gRmV0Y2hEYXRhKG9iamVjdCA9IGx1bmcsdmFycyA9IGMoZ2VuZUlkcykpCmhhbGxtYXJzX2V4cCA9IGhhbGxtYXJzX2V4cFssY29sU3VtcyhoYWxsbWFyc19leHBbXSk+MF0gI3JlbW92ZSBubyBleHByZXNzaW9uIGdlbmVzCmhhbGxtYXJrX2NvciA9IGNvcihoYWxsbWFyc19leHApCnBodDEgPSBwaGVhdG1hcChtYXQgPSBoYWxsbWFya19jb3Isc2lsZW50ID0gVCkKCm51bV9vZl9jbHVzdGVycyA9IDQKY2x1c3RlcmluZ19kaXN0YW5jZSA9ICJldWNsaWRlYW4iCm15YW5ub3RhdGlvbiA9IGFzLmRhdGEuZnJhbWUoY3V0cmVlKHBodDFbWyJ0cmVlX3JvdyJdXSwgayA9IG51bV9vZl9jbHVzdGVycykpICNzcGxpdCBpbnRvIGsgY2x1c3RlcnMKIApuYW1lcyhteWFubm90YXRpb24pWzFdID0gImNsdXN0ZXIiCiAgbXlhbm5vdGF0aW9uJGNsdXN0ZXIgPSBhcy5mYWN0b3IobXlhbm5vdGF0aW9uJGNsdXN0ZXIpCiAgCiAgcGFsZXR0ZTEgPC1icmV3ZXIucGFsKG51bV9vZl9jbHVzdGVycywgIlBhaXJlZCIpCgogIG5hbWVzKHBhbGV0dGUxKSA9IHVuaXF1ZShteWFubm90YXRpb24kY2x1c3RlcikKICBhbm5fY29sb3JzID0gbGlzdCAoY2x1c3RlciA9IHBhbGV0dGUxKQogIGFubm90YXRpb24gPSBsaXN0KGFubl9jb2xvcnMgPSBhbm5fY29sb3JzLCBteWFubm90YXRpb24gPSBteWFubm90YXRpb24pCiAgCiAgY29sb3JzIDwtIGMoc2VxKC0xLDEsYnk9MC4wMSkpCiAgbXlfcGFsZXR0ZSA8LSBjKCJibHVlIixjb2xvclJhbXBQYWxldHRlKGNvbG9ycyA9IGMoImJsdWUiLCAid2hpdGUiLCAicmVkIikpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChuID0gbGVuZ3RoKGNvbG9ycyktMyksICJyZWQiKQoKCiAgcHJpbnRfdGFiKHBsdCA9IAogICAgICAgICAgICAgICAgcGhlYXRtYXAobWF0ID0gaGFsbG1hcmtfY29yLGFubm90YXRpb25fY29sID0gIGFubm90YXRpb25bWyJteWFubm90YXRpb24iXV0sIGFubm90YXRpb25fY29sb3JzID0gYW5ub3RhdGlvbltbImFubl9jb2xvcnMiXV0sIGNsdXN0ZXJpbmdfZGlzdGFuY2Vfcm93cyA9IGNsdXN0ZXJpbmdfZGlzdGFuY2UsY2x1c3RlcmluZ19kaXN0YW5jZV9jb2xzID0gY2x1c3RlcmluZ19kaXN0YW5jZSxjb2xvciA9IG15X3BhbGV0dGUsYnJlYWtzID0gY29sb3JzLHNob3dfcm93bmFtZXMgPSBGLHNob3dfY29sbmFtZXMgPSBGKQogICAgICAgICAgICAsdGl0bGUgPSAiZ2VuZXMgZXhwcmVzc2lvbiBoZWF0bWFwIikKYGBgCgpgYGB7ciBlY2hvPVRSVUUsIHJlc3VsdHM9J2FzaXMnfQpjaG9zZW5fZ2VuZXMgPSBhbm5vdGF0aW9uW1sibXlhbm5vdGF0aW9uIl1dICU+JSBkcGx5cjo6ZmlsdGVyKGNsdXN0ZXIgPT0gMSB8IGNsdXN0ZXIgPT0gMikgJT4lIHJvd25hbWVzKCkgI3Rha2UgcmVsZXZhbnQgZ2VuZXMKc2NvcmUgPC0gYXBwbHkobHVuZ0Bhc3NheXMkUk5BQGRhdGFbY2hvc2VuX2dlbmVzLF0sMixtZWFuKQpsdW5nPUFkZE1ldGFEYXRhKGx1bmcsc2NvcmUsaGFsbG1hcmtfbmFtZSkKCnByaW50X3RhYihGZWF0dXJlUGxvdChvYmplY3QgPSBsdW5nLCBmZWF0dXJlcyA9IGhhbGxtYXJrX25hbWUpLHRpdGxlID0gIkV4cHJlc3Npb24iKQpgYGAKCgpgYGB7ciBlY2hvPVRSVUUsIHJlc3VsdHM9J2FzaXMnfQpjY19zY29yZXMgPSBGZXRjaERhdGEob2JqZWN0ID0gbHVuZyx2YXJzID0gaGFsbG1hcmtfbmFtZSkKCnBsdCAgPSAgZ2dwbG90KGNjX3Njb3JlcywgYWVzKHg9SEFMTE1BUktfSFlQT1hJQSkpICsKICBnZW9tX2RlbnNpdHkoKSsKICAgZ2VvbV92bGluZSgKICAgIGFlcyh4aW50ZXJjZXB0PW1lYW4oY2Nfc2NvcmVzJEhBTExNQVJLX0hZUE9YSUEpICsgc2QoY2Nfc2NvcmVzJEhBTExNQVJLX0hZUE9YSUEpICxjb2xvcj0iMSBTRCIpLAogICAgICAgICAgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkrCiAgICBnZW9tX3ZsaW5lKAogICAgYWVzKHhpbnRlcmNlcHQ9bWVhbihjY19zY29yZXMkSEFMTE1BUktfSFlQT1hJQSkgKyAyKnNkKGNjX3Njb3JlcyRIQUxMTUFSS19IWVBPWElBKSAsY29sb3I9IjIgU0QiKSwKICAgICAgICAgIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpCgpwcmludF90YWIocGx0ID0gcGx0LHRpdGxlID0gImRpc3QiKQpgYGAKIyMgY29ycmVsYXRpb24gdG8gbm1mCmBgYHtyfQpjb3JfcmVzID0gY29yKGx1bmckaHlwb3hpYV9saWtlLGx1bmckSEFMTE1BUktfSFlQT1hJQSkKcHJpbnQocGFzdGUoImNvcnJlbGF0aW9uIG9mIGh5cG94aWEgcHJvZ3JhbSB0byBIQUxMTUFSS19IWVBPWElBOiIsIGNvcl9yZXMpKQpgYGAKCgojIGdseWNvbHlzaXMgc2lnbmF0dXJlICB7LnRhYnNldH0KCmBgYHtyIHJlc3VsdHM9J2FzaXMnfQpoYWxsbWFya19uYW1lID0gIkhBTExNQVJLX0dMWUNPTFlTSVMiCmdlbmVzZXRzICA9Z2V0R210KCIuL0RhdGEvaC5hbGwudjcuMC5zeW1ib2xzLnBsdXNjYy5nbXQiKQpnZW5lSWRzPSBnZW5lc2V0c1tbaGFsbG1hcmtfbmFtZV1dQGdlbmVJZHMKaGFsbG1hcnNfZXhwID0gRmV0Y2hEYXRhKG9iamVjdCA9IGx1bmcsdmFycyA9IGMoZ2VuZUlkcykpCmhhbGxtYXJzX2V4cCA9IGhhbGxtYXJzX2V4cFssY29sU3VtcyhoYWxsbWFyc19leHBbXSk+MF0gI3JlbW92ZSBubyBleHByZXNzaW9uIGdlbmVzCmhhbGxtYXJrX2NvciA9IGNvcihoYWxsbWFyc19leHApCnBodDEgPSBwaGVhdG1hcChtYXQgPSBoYWxsbWFya19jb3Isc2lsZW50ID0gVCkKYGBgCgpgYGB7ciBlY2hvPVRSVUUsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTEwLCByZXN1bHRzPSdhc2lzJ30KbnVtX29mX2NsdXN0ZXJzID0gNQpjbHVzdGVyaW5nX2Rpc3RhbmNlID0gImV1Y2xpZGVhbiIKbXlhbm5vdGF0aW9uID0gYXMuZGF0YS5mcmFtZShjdXRyZWUocGh0MVtbInRyZWVfcm93Il1dLCBrID0gbnVtX29mX2NsdXN0ZXJzKSkgI3NwbGl0IGludG8gayBjbHVzdGVycwogCm5hbWVzKG15YW5ub3RhdGlvbilbMV0gPSAiY2x1c3RlciIKICBteWFubm90YXRpb24kY2x1c3RlciA9IGFzLmZhY3RvcihteWFubm90YXRpb24kY2x1c3RlcikKICAKICBwYWxldHRlMSA8LWJyZXdlci5wYWwobnVtX29mX2NsdXN0ZXJzLCAiUGFpcmVkIikKCiAgbmFtZXMocGFsZXR0ZTEpID0gdW5pcXVlKG15YW5ub3RhdGlvbiRjbHVzdGVyKQogIGFubl9jb2xvcnMgPSBsaXN0IChjbHVzdGVyID0gcGFsZXR0ZTEpCiAgYW5ub3RhdGlvbiA9IGxpc3QoYW5uX2NvbG9ycyA9IGFubl9jb2xvcnMsIG15YW5ub3RhdGlvbiA9IG15YW5ub3RhdGlvbikKICAKICBjb2xvcnMgPC0gYyhzZXEoLTEsMSxieT0wLjAxKSkKICBteV9wYWxldHRlIDwtIGMoImJsdWUiLGNvbG9yUmFtcFBhbGV0dGUoY29sb3JzID0gYygiYmx1ZSIsICJ3aGl0ZSIsICJyZWQiKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKG4gPSBsZW5ndGgoY29sb3JzKS0zKSwgInJlZCIpCgoKICBwcmludF90YWIocGx0ID0gCiAgICAgICAgICAgICAgICBwaGVhdG1hcChtYXQgPSBoYWxsbWFya19jb3IsYW5ub3RhdGlvbl9jb2wgPSAgYW5ub3RhdGlvbltbIm15YW5ub3RhdGlvbiJdXSwgYW5ub3RhdGlvbl9jb2xvcnMgPSBhbm5vdGF0aW9uW1siYW5uX2NvbG9ycyJdXSwgY2x1c3RlcmluZ19kaXN0YW5jZV9yb3dzID0gY2x1c3RlcmluZ19kaXN0YW5jZSxjbHVzdGVyaW5nX2Rpc3RhbmNlX2NvbHMgPSBjbHVzdGVyaW5nX2Rpc3RhbmNlLGNvbG9yID0gbXlfcGFsZXR0ZSxicmVha3MgPSBjb2xvcnMsc2hvd19yb3duYW1lcyA9IEYsc2hvd19jb2xuYW1lcyA9IEYpCiAgICAgICAgICAgICx0aXRsZSA9ICJnZW5lcyBleHByZXNzaW9uIGhlYXRtYXAiKQpgYGAKCmBgYHtyIGVjaG89VFJVRSwgcmVzdWx0cz0nYXNpcyd9CmNob3Nlbl9nZW5lcyA9IGFubm90YXRpb25bWyJteWFubm90YXRpb24iXV0gJT4lIGRwbHlyOjpmaWx0ZXIoY2x1c3RlciA9PSAxIHwgY2x1c3RlciA9PSAyIHwgY2x1c3RlciA9PSA1KSAlPiUgcm93bmFtZXMoKSAjdGFrZSByZWxldmFudCBnZW5lcwpzY29yZSA8LSBhcHBseShsdW5nQGFzc2F5cyRSTkFAZGF0YVtjaG9zZW5fZ2VuZXMsXSwyLG1lYW4pCmx1bmc9QWRkTWV0YURhdGEobHVuZyxzY29yZSxoYWxsbWFya19uYW1lKQoKcHJpbnRfdGFiKEZlYXR1cmVQbG90KG9iamVjdCA9IGx1bmcsIGZlYXR1cmVzID0gaGFsbG1hcmtfbmFtZSksdGl0bGUgPSAiRXhwcmVzc2lvbiIpCmBgYAoKYGBge3IgZWNobz1UUlVFLCByZXN1bHRzPSdhc2lzJ30KY2Nfc2NvcmVzID0gRmV0Y2hEYXRhKG9iamVjdCA9IGx1bmcsdmFycyA9IGhhbGxtYXJrX25hbWUpCgpwbHQgID0gIGdncGxvdChjY19zY29yZXMsIGFlcyh4PUhBTExNQVJLX0dMWUNPTFlTSVMpKSArCiAgZ2VvbV9kZW5zaXR5KCkrCiAgIGdlb21fdmxpbmUoCiAgICBhZXMoeGludGVyY2VwdD1tZWFuKEhBTExNQVJLX0dMWUNPTFlTSVMpICsgc2QoSEFMTE1BUktfR0xZQ09MWVNJUykgLGNvbG9yPSIxIFNEIiksCiAgICAgICAgICBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKSsKICAgIGdlb21fdmxpbmUoCiAgICBhZXMoeGludGVyY2VwdD1tZWFuKEhBTExNQVJLX0dMWUNPTFlTSVMpICsgMipzZChIQUxMTUFSS19HTFlDT0xZU0lTKSAsY29sb3I9IjIgU0QiKSwKICAgICAgICAgIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpKwogICAgZ2VvbV92bGluZSgKICAgIGFlcyh4aW50ZXJjZXB0PW1lYW4oSEFMTE1BUktfR0xZQ09MWVNJUykgLGNvbG9yPSJtZWFuIiksCiAgICAgICAgICBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKQoKcHJpbnRfdGFiKHBsdCA9IHBsdCx0aXRsZSA9ICJkaXN0IikKYGBgCgoKIyBJTkYgc2lnbmF0dXJlICB7LnRhYnNldH0KCmBgYHtyIHJlc3VsdHM9J2FzaXMnfQpoYWxsbWFya19uYW1lID0gIkhBTExNQVJLX0lOVEVSRkVST05fR0FNTUFfUkVTUE9OU0UiCmdlbmVzZXRzICA9Z2V0R210KCIuL0RhdGEvaC5hbGwudjcuMC5zeW1ib2xzLnBsdXNjYy5nbXQiKQpnZW5lSWRzPSBnZW5lc2V0c1tbaGFsbG1hcmtfbmFtZV1dQGdlbmVJZHMKaGFsbG1hcnNfZXhwID0gRmV0Y2hEYXRhKG9iamVjdCA9IGx1bmcsdmFycyA9IGMoZ2VuZUlkcykpCmhhbGxtYXJzX2V4cCA9IGhhbGxtYXJzX2V4cFssY29sU3VtcyhoYWxsbWFyc19leHBbXSk+MF0gI3JlbW92ZSBubyBleHByZXNzaW9uIGdlbmVzCmhhbGxtYXJrX2NvciA9IGNvcihoYWxsbWFyc19leHApCnBodDEgPSBwaGVhdG1hcChtYXQgPSBoYWxsbWFya19jb3Isc2lsZW50ID0gVCkKYGBgCgpgYGB7ciBlY2hvPVRSVUUsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTEwLCByZXN1bHRzPSdhc2lzJ30KbnVtX29mX2NsdXN0ZXJzID0gNApjbHVzdGVyaW5nX2Rpc3RhbmNlID0gImV1Y2xpZGVhbiIKbXlhbm5vdGF0aW9uID0gYXMuZGF0YS5mcmFtZShjdXRyZWUocGh0MVtbInRyZWVfcm93Il1dLCBrID0gbnVtX29mX2NsdXN0ZXJzKSkgI3NwbGl0IGludG8gayBjbHVzdGVycwogCm5hbWVzKG15YW5ub3RhdGlvbilbMV0gPSAiY2x1c3RlciIKICBteWFubm90YXRpb24kY2x1c3RlciA9IGFzLmZhY3RvcihteWFubm90YXRpb24kY2x1c3RlcikKICAKICBwYWxldHRlMSA8LWJyZXdlci5wYWwobnVtX29mX2NsdXN0ZXJzLCAiUGFpcmVkIikKCiAgbmFtZXMocGFsZXR0ZTEpID0gdW5pcXVlKG15YW5ub3RhdGlvbiRjbHVzdGVyKQogIGFubl9jb2xvcnMgPSBsaXN0IChjbHVzdGVyID0gcGFsZXR0ZTEpCiAgYW5ub3RhdGlvbiA9IGxpc3QoYW5uX2NvbG9ycyA9IGFubl9jb2xvcnMsIG15YW5ub3RhdGlvbiA9IG15YW5ub3RhdGlvbikKICAKICBjb2xvcnMgPC0gYyhzZXEoLTEsMSxieT0wLjAxKSkKICBteV9wYWxldHRlIDwtIGMoImJsdWUiLGNvbG9yUmFtcFBhbGV0dGUoY29sb3JzID0gYygiYmx1ZSIsICJ3aGl0ZSIsICJyZWQiKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKG4gPSBsZW5ndGgoY29sb3JzKS0zKSwgInJlZCIpCgoKICBwcmludF90YWIocGx0ID0gCiAgICAgICAgICAgICAgICBwaGVhdG1hcChtYXQgPSBoYWxsbWFya19jb3IsYW5ub3RhdGlvbl9jb2wgPSAgYW5ub3RhdGlvbltbIm15YW5ub3RhdGlvbiJdXSwgYW5ub3RhdGlvbl9jb2xvcnMgPSBhbm5vdGF0aW9uW1siYW5uX2NvbG9ycyJdXSwgY2x1c3RlcmluZ19kaXN0YW5jZV9yb3dzID0gY2x1c3RlcmluZ19kaXN0YW5jZSxjbHVzdGVyaW5nX2Rpc3RhbmNlX2NvbHMgPSBjbHVzdGVyaW5nX2Rpc3RhbmNlLGNvbG9yID0gbXlfcGFsZXR0ZSxicmVha3MgPSBjb2xvcnMsc2hvd19yb3duYW1lcyA9IEYsc2hvd19jb2xuYW1lcyA9IEYpCiAgICAgICAgICAgICx0aXRsZSA9ICJnZW5lcyBleHByZXNzaW9uIGhlYXRtYXAiKQpgYGAKYGBge3IgZWNobz1UUlVFLCByZXN1bHRzPSdhc2lzJ30KY2hvc2VuX2NsdXN0ZXJzID0gYygyLDMpCmNob3Nlbl9nZW5lcyA9IGFubm90YXRpb25bWyJteWFubm90YXRpb24iXV0gJT4lIGRwbHlyOjpmaWx0ZXIoY2x1c3RlciAlaW4lIGNob3Nlbl9jbHVzdGVycyApICU+JSByb3duYW1lcygpICN0YWtlIHJlbGV2YW50IGdlbmVzCnNjb3JlIDwtIGFwcGx5KGx1bmdAYXNzYXlzJFJOQUBkYXRhW2Nob3Nlbl9nZW5lcyxdLDIsbWVhbikKbHVuZz1BZGRNZXRhRGF0YShsdW5nLHNjb3JlLGhhbGxtYXJrX25hbWUpCgpwcmludF90YWIoRmVhdHVyZVBsb3Qob2JqZWN0ID0gbHVuZywgZmVhdHVyZXMgPSBoYWxsbWFya19uYW1lKSx0aXRsZSA9ICJFeHByZXNzaW9uIikKYGBgCgpgYGB7ciBlY2hvPVRSVUUsIHJlc3VsdHM9J2FzaXMnfQpjY19zY29yZXMgPSBGZXRjaERhdGEob2JqZWN0ID0gbHVuZyx2YXJzID0gaGFsbG1hcmtfbmFtZSkKCnBsdCAgPSAgZ2dwbG90KGNjX3Njb3JlcywgYWVzKHg9SEFMTE1BUktfSU5URVJGRVJPTl9HQU1NQV9SRVNQT05TRSkpICsKICBnZW9tX2RlbnNpdHkoKSsKICAgZ2VvbV92bGluZSgKICAgIGFlcyh4aW50ZXJjZXB0PW1lYW4oSEFMTE1BUktfSU5URVJGRVJPTl9HQU1NQV9SRVNQT05TRSkgKyBzZChIQUxMTUFSS19JTlRFUkZFUk9OX0dBTU1BX1JFU1BPTlNFKSAsY29sb3I9IjEgU0QiKSwKICAgICAgICAgIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpKwogICAgZ2VvbV92bGluZSgKICAgIGFlcyh4aW50ZXJjZXB0PW1lYW4oSEFMTE1BUktfSU5URVJGRVJPTl9HQU1NQV9SRVNQT05TRSkgKyAyKnNkKEhBTExNQVJLX0lOVEVSRkVST05fR0FNTUFfUkVTUE9OU0UpICxjb2xvcj0iMiBTRCIpLAogICAgICAgICAgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkrCiAgICBnZW9tX3ZsaW5lKAogICAgYWVzKHhpbnRlcmNlcHQ9bWVhbihIQUxMTUFSS19JTlRFUkZFUk9OX0dBTU1BX1JFU1BPTlNFKSAsY29sb3I9Im1lYW4iKSwKICAgICAgICAgIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpCgpwcmludF90YWIocGx0ID0gcGx0LHRpdGxlID0gImRpc3QiKQpgYGAKCiMjIGNvcnJlbGF0aW5vIHRvIG5tZgpgYGB7cn0KY29yX3JlcyA9IGNvcihsdW5nJGludGVyZmVyb25fbGlrZSxsdW5nJEhBTExNQVJLX0lOVEVSRkVST05fR0FNTUFfUkVTUE9OU0UpCnByaW50KHBhc3RlKCJjb3JyZWxhdGlvbiBvZiBpZm4gcHJvZ3JhbSB0byBIQUxMTUFSS19JTlRFUkZFUk9OX0dBTU1BX1JFU1BPTlNFOiIsIGNvcl9yZXMpKQpgYGAKCiMgQVBDIHNpZ25hdHVyZSAgey50YWJzZXR9CgpgYGB7ciByZXN1bHRzPSdhc2lzJ30KaGFsbG1hcmtfbmFtZSA9ICJLRUdHX0FOVElHRU5fUFJPQ0VTU0lOR19BTkRfUFJFU0VOVEFUSU9OIgojIGdlbmVzZXRzICA9Z2V0R210KCIuL0RhdGEvaC5hbGwudjcuMC5zeW1ib2xzLnBsdXNjYy5nbXQiKQojIGdlbmVJZHM9IGdlbmVzZXRzW1toYWxsbWFya19uYW1lXV1AZ2VuZUlkcwpnZW5lSWRzID0gY2Fub25pY2FsX3BhdGh3YXlzICU+JSBmaWx0ZXIoZ3NfbmFtZSA9PSBoYWxsbWFya19uYW1lKSAlPiUgcHVsbChnZW5lX3N5bWJvbCkgJT4lIGludGVyc2VjdChyb3duYW1lcyhsdW5nKSkKCmhhbGxtYXJzX2V4cCA9IEZldGNoRGF0YShvYmplY3QgPSBsdW5nLHZhcnMgPSBjKGdlbmVJZHMpKQpoYWxsbWFyc19leHAgPSBoYWxsbWFyc19leHBbLGNvbFN1bXMoaGFsbG1hcnNfZXhwW10pPjBdICNyZW1vdmUgbm8gZXhwcmVzc2lvbiBnZW5lcwpoYWxsbWFya19jb3IgPSBjb3IoaGFsbG1hcnNfZXhwKQpwaHQxID0gcGhlYXRtYXAobWF0ID0gaGFsbG1hcmtfY29yLHNpbGVudCA9IFQpCmBgYAoKYGBge3IgZWNobz1UUlVFLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD0xMCwgcmVzdWx0cz0nYXNpcyd9Cm51bV9vZl9jbHVzdGVycyA9IDQKY2x1c3RlcmluZ19kaXN0YW5jZSA9ICJldWNsaWRlYW4iCm15YW5ub3RhdGlvbiA9IGFzLmRhdGEuZnJhbWUoY3V0cmVlKHBodDFbWyJ0cmVlX3JvdyJdXSwgayA9IG51bV9vZl9jbHVzdGVycykpICNzcGxpdCBpbnRvIGsgY2x1c3RlcnMKIApuYW1lcyhteWFubm90YXRpb24pWzFdID0gImNsdXN0ZXIiCiAgbXlhbm5vdGF0aW9uJGNsdXN0ZXIgPSBhcy5mYWN0b3IobXlhbm5vdGF0aW9uJGNsdXN0ZXIpCiAgCiAgcGFsZXR0ZTEgPC1icmV3ZXIucGFsKG51bV9vZl9jbHVzdGVycywgIlBhaXJlZCIpCgogIG5hbWVzKHBhbGV0dGUxKSA9IHVuaXF1ZShteWFubm90YXRpb24kY2x1c3RlcikKICBhbm5fY29sb3JzID0gbGlzdCAoY2x1c3RlciA9IHBhbGV0dGUxKQogIGFubm90YXRpb24gPSBsaXN0KGFubl9jb2xvcnMgPSBhbm5fY29sb3JzLCBteWFubm90YXRpb24gPSBteWFubm90YXRpb24pCiAgCiAgY29sb3JzIDwtIGMoc2VxKC0xLDEsYnk9MC4wMSkpCiAgbXlfcGFsZXR0ZSA8LSBjKCJibHVlIixjb2xvclJhbXBQYWxldHRlKGNvbG9ycyA9IGMoImJsdWUiLCAid2hpdGUiLCAicmVkIikpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChuID0gbGVuZ3RoKGNvbG9ycyktMyksICJyZWQiKQoKCiAgcHJpbnRfdGFiKHBsdCA9IAogICAgICAgICAgICAgICAgcGhlYXRtYXAobWF0ID0gaGFsbG1hcmtfY29yLGFubm90YXRpb25fY29sID0gIGFubm90YXRpb25bWyJteWFubm90YXRpb24iXV0sIGFubm90YXRpb25fY29sb3JzID0gYW5ub3RhdGlvbltbImFubl9jb2xvcnMiXV0sIGNsdXN0ZXJpbmdfZGlzdGFuY2Vfcm93cyA9IGNsdXN0ZXJpbmdfZGlzdGFuY2UsY2x1c3RlcmluZ19kaXN0YW5jZV9jb2xzID0gY2x1c3RlcmluZ19kaXN0YW5jZSxjb2xvciA9IG15X3BhbGV0dGUsYnJlYWtzID0gY29sb3JzLHNob3dfcm93bmFtZXMgPSBGLHNob3dfY29sbmFtZXMgPSBGKQogICAgICAgICAgICAsdGl0bGUgPSAiZ2VuZXMgZXhwcmVzc2lvbiBoZWF0bWFwIikKICAKYGBgCgpgYGB7ciBlY2hvPVRSVUUsIHJlc3VsdHM9J2FzaXMnfQpjaG9zZW5fY2x1c3RlcnMgPSBjKDQpCmNob3Nlbl9nZW5lcyA9IGFubm90YXRpb25bWyJteWFubm90YXRpb24iXV0gJT4lIGRwbHlyOjpmaWx0ZXIoY2x1c3RlciAlaW4lIGNob3Nlbl9jbHVzdGVycyApICU+JSByb3duYW1lcygpICN0YWtlIHJlbGV2YW50IGdlbmVzCnNjb3JlIDwtIGFwcGx5KGx1bmdAYXNzYXlzJFJOQUBkYXRhW2Nob3Nlbl9nZW5lcyxdLDIsbWVhbikKbHVuZz1BZGRNZXRhRGF0YShsdW5nLHNjb3JlLGhhbGxtYXJrX25hbWUpCgpwcmludF90YWIoRmVhdHVyZVBsb3Qob2JqZWN0ID0gbHVuZywgZmVhdHVyZXMgPSBoYWxsbWFya19uYW1lKSx0aXRsZSA9ICJFeHByZXNzaW9uIikKYGBgCgojIyBjb3JyZWxhdGlubyB0byBubWYKYGBge3J9CmNvcl9yZXMgPSBjb3IobHVuZyRpbnRlcmZlcm9uX2xpa2UsbHVuZyRLRUdHX0FOVElHRU5fUFJPQ0VTU0lOR19BTkRfUFJFU0VOVEFUSU9OKQpwcmludChwYXN0ZSgiY29ycmVsYXRpb24gb2YgaWZuIHByb2dyYW0gdG8gS0VHR19BTlRJR0VOX1BST0NFU1NJTkdfQU5EX1BSRVNFTlRBVElPTjoiLCBjb3JfcmVzKSkKYGBgCgoKIyBJTkYgbGlrZSBzaWduYXR1cmUgIHsudGFic2V0fQoKCmBgYHtyIGVjaG89VFJVRSwgcmVzdWx0cz0nYXNpcyd9CmhhbGxtYXJrX25hbWUgPSAiSUZOX2xpa2VfZ2VuZXMiCmkgPSAxCnRvcF9nZW5lcyA9IHBhdGllbnRzX2dlcHMgICU+JSAgYXJyYW5nZShkZXNjKHBhdGllbnRzX2dlcHNbaV0pKSAjc29ydCBieSBzY29yZSBhCnRvcCA9IGhlYWQocm93bmFtZXModG9wX2dlbmVzKSwxMDApICN0YWtlIHRvcCB0b3BfZ2VuZXNfbnVtCmNob3Nlbl9nZW5lcyA9IHRvcCAlPiUgaW50ZXJzZWN0KHJvd25hbWVzKGx1bmcpKQpzY29yZSA8LSBhcHBseShsdW5nQGFzc2F5cyRSTkFAZGF0YVtjaG9zZW5fZ2VuZXMsXSwyLG1lYW4pCmx1bmc9QWRkTWV0YURhdGEobHVuZyxzY29yZSxoYWxsbWFya19uYW1lKQoKcHJpbnRfdGFiKEZlYXR1cmVQbG90KG9iamVjdCA9IGx1bmcsIGZlYXR1cmVzID0gaGFsbG1hcmtfbmFtZSksdGl0bGUgPSAiRXhwcmVzc2lvbiIpCmBgYAoKIyMgY29ycmVsYXRpbm8gdG8gbm1mCmBgYHtyfQpjb3JfcmVzID0gY29yKGx1bmckaW50ZXJmZXJvbl9saWtlLGx1bmckSUZOX2xpa2VfZ2VuZXMpCnByaW50KHBhc3RlKCJjb3JyZWxhdGlvbiBvZiBpZm4gcHJvZ3JhbSB0byBJRk5fbGlrZV9nZW5lczoiLCBjb3JfcmVzKSkKYGBgCgojICBTaWduYXR1cmUgcmVndWxhdGlvbiAgey50YWJzZXR9CmBgYHtyIGVjaG89VFJVRSwgcmVzdWx0cz0nYXNpcyd9Cm1ldGFnZW5lc19tZWFuX2NvbXBhcmUoZGF0YXNldCA9IGx1bmcsIHRpbWUucG9pbnRfdmFyID0gInRpbWUucG9pbnQiLHByZWZpeCA9ICJwYXRpZW50IixwYXRpZW50LmlkZW50X3ZhciA9ICJwYXRpZW50LmlkZW50IixwcmVfb24gPSBjKCJwcmUtdHJlYXRtZW50Iiwib24tdHJlYXRtZW50IiksYXhpcy50ZXh0LnggPSA4LHByb2dyYW1zID0gYygiSEFMTE1BUktfSFlQT1hJQSIsIkhBTExNQVJLX0lOVEVSRkVST05fR0FNTUFfUkVTUE9OU0UiLCJLRUdHX0FOVElHRU5fUFJPQ0VTU0lOR19BTkRfUFJFU0VOVEFUSU9OIiwiSUZOX2xpa2VfZ2VuZXMiLCJIQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVCIpKQpgYGAKCgoKCg==