Parameters
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
}
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)
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)
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 = 200
plt_list = list()
hif_targets_set = data.frame(gs_name = "hif_targets",gene_symbol = hif_targets)
i = 1
top_genes = gep_scores %>% arrange(desc(gep_scores[i])) #sort by score a
top = head(rownames(top_genes),ntop) #take top top_genes_num
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%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
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)
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)
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
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
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))
)
)

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

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

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.

LS0tCnRpdGxlOiAnYHIgcnN0dWRpb2FwaTo6Z2V0U291cmNlRWRpdG9yQ29udGV4dCgpJHBhdGggJT4lIGJhc2VuYW1lKCkgJT4lIGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLHJlcGxhY2VtZW50ID0gIiIpYCcgCmF1dGhvcjogIkF2aXNoYWkgV2l6ZWwiCmRhdGU6ICdgciBTeXMudGltZSgpYCcKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdG9jOiB5ZXMKICAgIHRvY19jb2xsYXBzZTogeWVzCiAgICB0b2NfZmxvYXQ6IAogICAgICBjb2xsYXBzZWQ6IEZBTFNFCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvY19kZXB0aDogMQotLS0KCiMgUGFyYW1ldGVycwoKYGBge3Igd2FybmluZz1GQUxTRX0KCmBgYAoKCiMgRnVuY3Rpb25zCgpgYGB7ciB3YXJuaW5nPUZBTFNFfQoKbGlicmFyeShzdHJpbmdpKQpsaWJyYXJ5KHJldGljdWxhdGUpCnNvdXJjZV9mcm9tX2dpdGh1YihyZXBvc2l0b3kgPSAiREVHX2Z1bmN0aW9ucyIsdmVyc2lvbiA9ICIwLjIuMjQiKQpzb3VyY2VfZnJvbV9naXRodWIocmVwb3NpdG95ID0gImNOTUZfZnVuY3Rpb25zIix2ZXJzaW9uID0gIjAuMy44NSIsc2NyaXB0X25hbWUgPSAiY25tZl9mdW5jdGlvbl9IYXJtb255LlIiKQoKbm9fbmVnIDwtIGZ1bmN0aW9uKHgpIHsKICB4ID0geCArIGFicyhtaW4oeCkpCiAgeAp9CgpzdW1fMl9vbmUgPC0gZnVuY3Rpb24oeCkgewogIHggPXgvc3VtKHgpCiAgeAp9CmBgYAoKCiMgRGF0YQoKYGBge3IgcmVhZF9kYXRhfQp4ZW5vID0gcmVhZFJEUygiLi9EYXRhLzEweF94ZW5vXzEwMDAuUmRzIikKbHVuZyA9IHJlYWRSRFMoIi4vRGF0YS9sdW5nX2NhbmNlcmNlbGxzX3dpdGhUUF9vbmx5UGF0aWVudHMucmRzIikKbHVuZ19wYXRpZW50cyA9IGx1bmckcGF0aWVudC5pZGVudCAlPiUgdW5pcXVlKCkgJT4lIGFzLmNoYXJhY3RlcigpCmx1bmdfcGF0aWVudHNfZmlsdGVyZWQgPSBsdW5nX3BhdGllbnRzWyEobHVuZ19wYXRpZW50cyAlaW4lIGMoIlgxMDU1bmV3IiwiWDEwOTkiKSldICMgcmVtb3ZlIHBhdGllbnRzIHdpdGggbGVzcyB0aGFuIDEwMCBtYWxpZ25hbnQgY2VsbHMKbHVuZyA9IHN1YnNldCh4ID0gbHVuZyxzdWJzZXQgPSBwYXRpZW50LmlkZW50ICVpbiUgbHVuZ19wYXRpZW50c19maWx0ZXJlZCkKYGBgCgojIE1vZGVscyAySyB2YXJnZW5lcyAKCmBgYHtweXRob259CnN1ZmZpeCA9IHIuc3VmZml4CmltcG9ydCBwaWNrbGUKZnJvbSBjbm1mIGltcG9ydCBjTk1GCmYgPSBvcGVuKCcuL0RhdGEvY25tZi9jbm1mX29iamVjdHMvbW9kZWxzXzJLdmFyZ2VuZXNfY25tZl9vYmoucGNrbCcsICdyYicpCmNubWZfb2JqID0gcGlja2xlLmxvYWQoZikKZi5jbG9zZSgpCmBgYAoKYGBge3J9CiMgZ2VwX3Njb3JlcyA9IHJlYWRSRFMoIi9zY2kvbGFicy95b3RhbWQvbGFiX3NoYXJlL2F2aXNoYWkud2l6ZWwvUl9wcm9qZWN0cy9FR0ZSL0RhdGEvY25tZi9oYXJtb255X21vZGVsc19nZXBfc2NvcmVzLnJkcyIpCmBgYAoKCmBgYHtweXRob259CnNlbGVjdGVkX2sgPSAzCmRlbnNpdHlfdGhyZXNob2xkID0gMC4xCiMgY25tZl9vYmouY29uc2Vuc3VzKGs9c2VsZWN0ZWRfaywgZGVuc2l0eV90aHJlc2hvbGQ9ZGVuc2l0eV90aHJlc2hvbGQpCnVzYWdlX25vcm0sIGdlcF9zY29yZXMsIGdlcF90cG0sIHRvcGdlbmVzID0gY25tZl9vYmoubG9hZF9yZXN1bHRzKEs9c2VsZWN0ZWRfaywgZGVuc2l0eV90aHJlc2hvbGQ9ZGVuc2l0eV90aHJlc2hvbGQpCmBgYAoKIyBwcm9ncmFtcyBlbnJpY2htZW50CgoKCmBgYHtyfQpnZXBfc2NvcmVzID0gcHkkZ2VwX3Njb3JlcwpnZXBfdHBtID0gcHkkZ2VwX3RwbQp1c2FnZV9ub3JtPSBweSR1c2FnZV9ub3JtCmBgYAoKCmBgYHtyIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9Cm5hbWVzIChnZXBfc2NvcmVzKSA9IGMoIkh5cG94aWEiLCJUTkZhIiwiQ2VsbF9jeWNsZSIpCnBsdF9saXN0ID0gbGlzdCgpCgpmb3IgKHByb2dyYW0gIGluIG5hbWVzIChnZXBfc2NvcmVzKSkgewogcCA9IGdncGxvdChnZXBfc2NvcmVzLCBhZXMoeD0hIWVuc3ltKHByb2dyYW0pKSkgKwogIGdlb21fZGVuc2l0eSgpK3hsYWIocHJvZ3JhbSkrCiAgIGdlb21fdmxpbmUoCiAgICBhZXMoeGludGVyY2VwdD1zb3J0KGdlcF9zY29yZXNbLHByb2dyYW1dLFRSVUUpWzIwMF0gICxjb2xvcj0idG9wMjAwIiksCiAgICAgICAgICBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKSsKICAgZ2VvbV92bGluZSgKICAgIGFlcyh4aW50ZXJjZXB0PXNvcnQoZ2VwX3Njb3Jlc1sscHJvZ3JhbV0sVFJVRSlbMTAwXSAgLGNvbG9yPSJ0b3AxMDAiKSwKICAgICAgICAgIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpKwogICAgICBnZW9tX3ZsaW5lKAogICAgYWVzKHhpbnRlcmNlcHQ9c29ydChnZXBfc2NvcmVzWyxwcm9ncmFtXSxUUlVFKVs1MF0gICxjb2xvcj0idG9wNTAiKSwKICAgICAgICAgIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpKwogICAgICAgICBnZW9tX3ZsaW5lKAogICAgYWVzKHhpbnRlcmNlcHQ9c29ydChnZXBfc2NvcmVzWyxwcm9ncmFtXSxUUlVFKVsxNTBdICAsY29sb3I9InRvcDE1MCIpLAogICAgICAgICAgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkrCiAgIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gInRvcCBuIGdlbmVzIiwgdmFsdWVzID0gYyh0b3AyMDAgPSAiYmx1ZSIsdG9wMTAwID0gInJlZCIsdG9wMTUwID0gInllbGxvdyIsdG9wNTAgPSAiZ3JlZW4iKSkKICAgcGx0X2xpc3RbW3Byb2dyYW1dXSA8LSBwCgp9CiAKZ2dhcnJhbmdlKHBsb3RsaXN0ID0gcGx0X2xpc3QpCgpgYGAKCgoKCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTgsIHJlc3VsdHM9J2hpZGUnfQpudG9wID0gMjAwCnBsdF9saXN0ID0gbGlzdCgpCmhpZl90YXJnZXRzX3NldCA9IGRhdGEuZnJhbWUoZ3NfbmFtZSA9ICJoaWZfdGFyZ2V0cyIsZ2VuZV9zeW1ib2wgPSBoaWZfdGFyZ2V0cykKaSA9IDEKCiAgdG9wX2dlbmVzID0gZ2VwX3Njb3JlcyAgJT4lICBhcnJhbmdlKGRlc2MoZ2VwX3Njb3Jlc1tpXSkpICNzb3J0IGJ5IHNjb3JlIGEKICB0b3AgPSBoZWFkKHJvd25hbWVzKHRvcF9nZW5lcyksbnRvcCkgI3Rha2UgdG9wIHRvcF9nZW5lc19udW0KICByZXMgPSBnZW5lc192ZWNfZW5yaWNobWVudChnZW5lcyA9IHRvcCxiYWNrZ3JvdW5kID0gcm93bmFtZXMoZ2VwX3Njb3JlcyksaG9tZXIgPSBULHRpdGxlID0gCiAgICAgICAgICAgICAgICAgICAgaSxzaWxlbnQgPSBULHJldHVybl9hbGwgPSBULGN1c3RvbV9wYXRod2F5cyAgPSBoaWZfdGFyZ2V0c19zZXQpCiAgIAogIHBsdF9saXN0W1tpXV0gPSByZXMkcGx0CgpncmlkRXh0cmE6OmdyaWQuYXJyYW5nZShncm9icyA9IHBsdF9saXN0KQpgYGAKCgpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04LCByZXN1bHRzPSdoaWRlJ30KbnRvcCA9IDE1MApwbHRfbGlzdCA9IGxpc3QoKQpoaWZfdGFyZ2V0c19zZXQgPSBkYXRhLmZyYW1lKGdzX25hbWUgPSAiaGlmX3RhcmdldHMiLGdlbmVfc3ltYm9sID0gaGlmX3RhcmdldHMpCgpmb3IgKGkgaW4gMTpuY29sKGdlcF9zY29yZXMpKSB7CiAgdG9wX2dlbmVzID0gZ2VwX3Njb3JlcyAgJT4lICBhcnJhbmdlKGRlc2MoZ2VwX3Njb3Jlc1tpXSkpICNzb3J0IGJ5IHNjb3JlIGEKICB0b3AgPSBoZWFkKHJvd25hbWVzKHRvcF9nZW5lcyksbnRvcCkgI3Rha2UgdG9wIHRvcF9nZW5lc19udW0KICByZXMgPSBnZW5lc192ZWNfZW5yaWNobWVudChnZW5lcyA9IHRvcCxiYWNrZ3JvdW5kID0gcm93bmFtZXMoZ2VwX3Njb3JlcyksaG9tZXIgPSBULHRpdGxlID0gCiAgICAgICAgICAgICAgICAgICAgaSxzaWxlbnQgPSBULHJldHVybl9hbGwgPSBULGN1c3RvbV9wYXRod2F5cyAgPSBoaWZfdGFyZ2V0c19zZXQpCiAgIAogIHBsdF9saXN0W1tpXV0gPSByZXMkcGx0Cn0KZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UoZ3JvYnMgPSBwbHRfbGlzdCkKYGBgCgoKCmBgYHtyfQp4ZW5vID0gRmluZFZhcmlhYmxlRmVhdHVyZXMob2JqZWN0ID0geGVubyxuZmVhdHVyZXMgPSAyMDAwKQp4ZW5vX3ZhcmdlbmVzID0gVmFyaWFibGVGZWF0dXJlcyhvYmplY3QgPSB4ZW5vKQoKeGVub19leHByZXNzaW9uID0gRmV0Y2hEYXRhKG9iamVjdCA9IHhlbm8sdmFycyA9IHhlbm9fdmFyZ2VuZXMsc2xvdD0nY291bnRzJykKYWxsXzBfZ2VuZXMgPSBjb2xuYW1lcyh4ZW5vX2V4cHJlc3Npb24pW2NvbFN1bXMoeGVub19leHByZXNzaW9uPT0wLCBuYS5ybT1UUlVFKT09bnJvdyh4ZW5vX2V4cHJlc3Npb24pXSAjZGVsZXRlIHJvd3MgdGhhdCBoYXZlIGFsbCAwCnhlbm9fdmFyZ2VuZXMgPSB4ZW5vX3ZhcmdlbmVzWyF4ZW5vX3ZhcmdlbmVzICVpbiUgYWxsXzBfZ2VuZXNdCgpgYGAKCgoKCiMgVGVzdCB3aXRoIGV4cHIgYWZ0ZXIgaGFybW9ueQpgYGB7cHl0aG9ufQppbXBvcnQgbnVtcHkgYXMgbnAKaW1wb3J0IHNjYW5weSBhcyBzYwoKZXhwcl9hZnRlcl9oYXJtb255ID0gc2MucmVhZF9oNWFkKCcuL0RhdGEvY25tZi94ZW5vX0hhcm1vbnlfTm9OZWdfMkt2YXJnZW5lcy5oNWFkJykudG9fZGYoKQp0cG0gPSAgY29tcHV0ZV90cG0oZXhwcl9hZnRlcl9oYXJtb255KQpjbm1mX2dlbmVzID0gZXhwcl9hZnRlcl9oYXJtb255LmtleXMoKS50b19saXN0KCkKdXNhZ2VfYnlfY2FsYyA9IGdldF91c2FnZV9mcm9tX3Njb3JlKGNvdW50cz1leHByX2FmdGVyX2hhcm1vbnksdHBtPXRwbSxnZW5lcz1jbm1mX2dlbmVzLGNubWZfb2JqPWNubWZfb2JqLGs9MykKYGBgCgojIENoZWNrIGlmIG9yaWdpbmFsIGNOTUYgc2NvcmUgaXMgbGlrZSB0aGUgY2FsY3VsYXRlZCBzY29yZQpgYGB7cn0KdXNhZ2VfYnlfY2FsYyA9IHB5JHVzYWdlX2J5X2NhbGMKdXNhZ2Vfbm9ybSA9IHB5JHVzYWdlX25vcm0KY29yKHVzYWdlX2J5X2NhbGMsdXNhZ2Vfbm9ybSkKYGBgCgojIGNhbGN1bGF0ZSBzY29yZSBmb3IgWGVubwpgYGB7cHl0aG9ufQppbXBvcnQgbnVtcHkgYXMgbnAKaW1wb3J0IHNjYW5weSBhcyBzYwp4ZW5vX2V4cHJlc3Npb24gPSByLnhlbm9fZXhwcmVzc2lvbgp4ZW5vX3ZhcmdlbmVzID0gci54ZW5vX3ZhcmdlbmVzCnRwbSA9ICBjb21wdXRlX3RwbSh4ZW5vX2V4cHJlc3Npb24pCnVzYWdlX2J5X2NhbGMgPSBnZXRfdXNhZ2VfZnJvbV9zY29yZShjb3VudHM9eGVub19leHByZXNzaW9uLHRwbT10cG0sZ2VuZXM9eGVub192YXJnZW5lcywgY25tZl9vYmo9Y25tZl9vYmosaz0zKQpgYGAKCmBgYHtyfQphbGxfbWV0YWdlbmVzID0gcHkkdXNhZ2VfYnlfY2FsYwpgYGAKCiMgcHJvZ3JhbXMgZXhwcmVzc2lvbiB7LnRhYnNldH0KYGBge3IgZWNobz1UUlVFLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD05LCByZXN1bHRzPSdhc2lzJ30KCm5hbWVzIChhbGxfbWV0YWdlbmVzKSA9IGMoIkh5cG94aWEiLCJUTkZhIiwiQ2VsbF9jeWNsZSIpCiNhZGQgZWFjaCBtZXRhZ2VuZSB0byBtZXRhZGF0YQpmb3IgKGkgIGluIDE6bmNvbChhbGxfbWV0YWdlbmVzKSkgewogIG1ldGFnZV9tZXRhZGF0YSA9IGFsbF9tZXRhZ2VuZXMgJT4lIGRwbHlyOjpzZWxlY3QoaSkKICAjIG1ldGFnZV9tZXRhZGF0YSA9IHNjYWxlKG1ldGFnZV9tZXRhZGF0YSkKICB4ZW5vID0gQWRkTWV0YURhdGEob2JqZWN0ID0geGVubyxtZXRhZGF0YSA9IG1ldGFnZV9tZXRhZGF0YSxjb2wubmFtZSA9IG5hbWVzKGFsbF9tZXRhZ2VuZXMpW2ldKQp9CgpwcmludF90YWIocGx0ID0gRmVhdHVyZVBsb3Qob2JqZWN0ID0geGVubyxmZWF0dXJlcyA9IGNvbG5hbWVzKGFsbF9tZXRhZ2VuZXMpKSx0aXRsZSA9ICJ1bWFwIGV4cHJlc3Npb24iKQoKCmBgYAoKCgojIHByb2dyYW1zIHJlZ3VsYXRpb24gey50YWJzZXR9CmBgYHtyIGVjaG89VFJVRSwgIHJlc3VsdHM9J2FzaXMnfQptZXRhZ2VuZXNfbWVhbl9jb21wYXJlKGRhdGFzZXQgPSB4ZW5vLHRpbWUucG9pbnRfdmFyID0gInRyZWF0bWVudCIscHJlZml4ID0gIm1vZGVsIixwYXRpZW50LmlkZW50X3ZhciA9ICJvcmlnLmlkZW50IixwcmVfb24gPSBjKCJOVCIsIk9TSSIpLHRlc3QgPSAid2lsY294LnRlc3QiLHByb2dyYW1zID0gYygiSHlwb3hpYSIsIlRORmEiLCJDZWxsX2N5Y2xlIikpCgpgYGAKCgoKYGBge3J9CmhhbGxtYXJrX25hbWUgPSAiR09fTUlUT1RJQ19DRUxMX0NZQ0xFIgpnZW5lc2V0cyAgPWdldEdtdCgiLi9EYXRhL2guYWxsLnY3LjAuc3ltYm9scy5wbHVzY2MuZ210IikKdmFyX2ZlYXR1cmVzPXhlbm9AYXNzYXlzJFJOQUB2YXIuZmVhdHVyZXMKZ2VuZUlkcz0gZ2VuZXNldHNbW2hhbGxtYXJrX25hbWVdXUBnZW5lSWRzCnNjb3JlIDwtIGFwcGx5KHhlbm9AYXNzYXlzJFJOQUBkYXRhW2ludGVyc2VjdChnZW5lSWRzLHZhcl9mZWF0dXJlcyksXSwyLG1lYW4pCnhlbm89QWRkTWV0YURhdGEoeGVubyxzY29yZSwiR09fTUlUT1RJQ19DQyIpCmBgYAoKYGBge3IgZWNobz1UUlVFLCByZXN1bHRzPSdhc2lzJ30KbWV0YWdlbmVzX21lYW5fY29tcGFyZShkYXRhc2V0ID0geGVubyx0aW1lLnBvaW50X3ZhciA9ICJ0cmVhdG1lbnQiLHByZWZpeCA9ICJtb2RlbCIscGF0aWVudC5pZGVudF92YXIgPSAib3JpZy5pZGVudCIscHJlX29uID0gYygiTlQiLCJPU0kiLCJyZXMiKSxwcm9ncmFtcyA9IGMoIkdPX01JVE9USUNfQ0MiKSkKCmBgYApgYGB7cn0KRG90UGxvdChvYmplY3QgPSB4ZW5vLCBmZWF0dXJlcyA9ICBjKCJIeXBveGlhIiwiVE5GYSIsIkNlbGxfY3ljbGUiLCJHT19NSVRPVElDX0NDIiksc2NhbGUgPSBGLGdyb3VwLmJ5ICA9ICd0cmVhdG1lbnQnKQpgYGAKCgpgYGB7cn0KY2Nfc2NvcmVzID0gRmV0Y2hEYXRhKG9iamVjdCA9IHhlbm8sdmFycyA9ICJHT19NSVRPVElDX0NDIikKIGdncGxvdChjY19zY29yZXMsIGFlcyh4PUdPX01JVE9USUNfQ0MpKSArCiAgZ2VvbV9kZW5zaXR5KCkrCiAgIGdlb21fdmxpbmUoCiAgICBhZXMoeGludGVyY2VwdD1tZWFuKGNjX3Njb3JlcyRHT19NSVRPVElDX0NDKSArIHNkKGNjX3Njb3JlcyRHT19NSVRPVElDX0NDKSAsY29sb3I9IjEgU0QiKSwKICAgICAgICAgIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpKwogICAgZ2VvbV92bGluZSgKICAgIGFlcyh4aW50ZXJjZXB0PW1lYW4oY2Nfc2NvcmVzJEdPX01JVE9USUNfQ0MpICsgMipzZChjY19zY29yZXMkR09fTUlUT1RJQ19DQykgLGNvbG9yPSIyIFNEIiksCiAgICAgICAgICBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKQogCmNjX3Njb3JlcyA9IGNjX3Njb3JlcyAlPiUgbXV0YXRlKGlzX2N5Y2xpbmcgPSBpZl9lbHNlKGNvbmRpdGlvbiA9IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBHT19NSVRPVElDX0NDID4gbWVhbihjY19zY29yZXMkR09fTUlUT1RJQ19DQykgKyBzZChjY19zY29yZXMkR09fTUlUT1RJQ19DQyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cnVlID0gImN5Y2xpbmciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFsc2UgPSAibm9uX2N5Y2xpbmciKSkKeGVubyA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IHhlbm8sbWV0YWRhdGEgPSBjY19zY29yZXMkaXNfY3ljbGluZyxjb2wubmFtZSA9ICJpc19jeWNsaW5nIikKRGltUGxvdChvYmplY3QgPSB4ZW5vLGdyb3VwLmJ5ID0gImlzX2N5Y2xpbmciKQoKYGBgCgoKYGBge3J9CiBkZiAgPSBGZXRjaERhdGEob2JqZWN0ID0geGVubyx2YXJzID0gYygiaXNfY3ljbGluZyIsInRyZWF0bWVudCIpKSAlPiUgCiAgICBmaWx0ZXIgKHRyZWF0bWVudCAlaW4lIGMoIk5UIiwiT1NJIikpICU+JSAKICAgIGRyb3BsZXZlbHMoKSAKICB0ZXN0ID0gZmlzaGVyLnRlc3QodGFibGUoZGYpKQogICAgCiAgbGlicmFyeShnZ3N0YXRzcGxvdCkKcHJpbnQoCiAgICBnZ2JhcnN0YXRzKAogICAgZGYsIGlzX2N5Y2xpbmcsIHRyZWF0bWVudCwKICAgIHJlc3VsdHMuc3VidGl0bGUgPSBGQUxTRSwKICAgIHN1YnRpdGxlID0gcGFzdGUwKAogICAgICAiRmlzaGVyJ3MgZXhhY3QgdGVzdCIsICIsIHAtdmFsdWUgPSAiLAogICAgICAgcm91bmQodGVzdCRwLnZhbHVlLDEwKSkKICAgICkKICApCgpgYGAKCgojIHByb2dyYW0gYXNzaWdubWVudCB7LnRhYnNldH0KYGBge3J9Cmxhcmdlcl9ieSA9IDEuNQp4ZW5vID0gcHJvZ3JhbV9hc3NpZ25tZW50KGRhdGFzZXQgPSB4ZW5vLGxhcmdlcl9ieSA9IGxhcmdlcl9ieSxwcm9ncmFtX25hbWVzID0gY29sbmFtZXMoYWxsX21ldGFnZW5lcykpCmBgYCAKCmBgYHtyIGVjaG89VFJVRSwgcmVzdWx0cz0nYXNpcyd9CnByaW50X3RhYihwbHQgPSAKICAgICAgICAgICAgRGltUGxvdCh4ZW5vLGdyb3VwLmJ5ID0gInByb2dyYW0uYXNzaWdubWVudCIsY29scyA9IGMoSHlwb3hpYSA9ICJyZWQiLFRORmEgPSAiZ3JlZW4iLENlbGxfY3ljbGUgPSAiYmx1ZSIsIk5BIiA9ICJncmV5IikpCiAgICAgICAgICAsdGl0bGUgPSAicHJvZ3JhbS5hc3NpZ25tZW50IixzdWJ0aXRsZV9udW0gPSAyKQpwcmludF90YWIocGx0ID0gCiAgICAgICAgICAgICAgRGltUGxvdCh4ZW5vLGdyb3VwLmJ5ID0gIm9yaWcuaWRlbnQiKQogICAgICAgICAgLHRpdGxlID0gIm9yaWcuaWRlbnQiLHN1YnRpdGxlX251bSA9IDIpCnByaW50X3RhYihwbHQgPSAKICAgICAgICAgICAgRGltUGxvdCh4ZW5vLGdyb3VwLmJ5ID0gInRyZWF0bWVudCIpCiAgICAgICAgICAsdGl0bGUgPSAidHJlYXRtZW50IixzdWJ0aXRsZV9udW0gPSAyKQoKcCA9IGNlbGxfcGVyY2VudGFnZShkYXRhc2V0ID0geGVubyx0aW1lLnBvaW50X3ZhciA9ICJ0cmVhdG1lbnQiLGJ5X3Byb2dyYW0gPSBULHhfb3JkZXIgPSBjKCJOVCIsIk9TSSIsInJlcyIpKQpwcmludF90YWIocGx0ID0gcCx0aXRsZSA9ICJieSBwcm9ncmFtIixzdWJ0aXRsZV9udW0gPSAyKQoKcCA9IGNlbGxfcGVyY2VudGFnZShkYXRhc2V0ID0geGVubyx0aW1lLnBvaW50X3ZhciA9ICJ0cmVhdG1lbnQiLGJ5X3RwICA9IFQseF9vcmRlciA9YygiSHlwb3hpYSIsIlRORmEiLCJDZWxsX2N5Y2xlIiwiTkEiKSkKcHJpbnRfdGFiKHBsdCA9IHAsdGl0bGUgPSAiYnkgdGltZSBwb2ludCIsc3VidGl0bGVfbnVtID0gMikKCgpgYGAKCgpgYGB7cn0KdG9wX2dlbmVzID0gZ2VwX3Njb3JlcyAgJT4lICBhcnJhbmdlKGRlc2MoZ2VwX3Njb3Jlc1siSHlwb3hpYSJdKSkgI3NvcnQgYnkgc2NvcmUgYQpoeXBveGlhX2dlbmVzID0gaGVhZChyb3duYW1lcyh0b3BfZ2VuZXMpLDIwKSAjdGFrZSB0b3AgdG9wX2dlbmVzX251bQppbnRlcnNlY3QoY2x1c3Rlcl8zX2dlbmVzLGh5cG94aWFfZ2VuZXMpCmBgYAoKYGBge3J9CmxpYnJhcnkoZ2d2ZW5uKQphbGwgPSBsaXN0KGh5cG94aWFfZ2VuZXMgPSBoeXBveGlhX2dlbmVzLCBoaWZfdGFyZ2V0cyA9IGNsdXN0ZXJfM19nZW5lcykKZ2d2ZW5uKAogIGFsbAopCmBgYAoKCgoKIyBDQyBzaWduYXR1cmUgIHsudGFic2V0fQoKCgoKYGBge3IgZWNobz1UUlVFLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD0xMCwgcmVzdWx0cz0nYXNpcyd9CiMgZ2V0IGdlbmVzIGFuZCBwbG90IGNvciBoZWF0bWFwCmhhbGxtYXJrX25hbWUgPSAiSEFMTE1BUktfRzJNX0NIRUNLUE9JTlQiCmdlbmVzZXRzICA9Z2V0R210KCIuL0RhdGEvaC5hbGwudjcuMC5zeW1ib2xzLnBsdXNjYy5nbXQiKQpnZW5lSWRzPSBnZW5lc2V0c1tbaGFsbG1hcmtfbmFtZV1dQGdlbmVJZHMKaGFsbG1hcnNfZXhwID0gRmV0Y2hEYXRhKG9iamVjdCA9IHhlbm8sdmFycyA9IGMoZ2VuZUlkcykpCmhhbGxtYXJzX2V4cCA9IGhhbGxtYXJzX2V4cFssY29sU3VtcyhoYWxsbWFyc19leHBbXSk+MF0gI3JlbW92ZSBubyBleHByZXNzaW9uIGdlbmVzCmhhbGxtYXJrX2NvciA9IGNvcihoYWxsbWFyc19leHApCnBodDEgPSBwaGVhdG1hcChtYXQgPSBoYWxsbWFya19jb3Isc2lsZW50ID0gVCkKCiMgbWFrZSBhbm5vdGF0aW9ucwpudW1fb2ZfY2x1c3RlcnMgPSA0CmNsdXN0ZXJpbmdfZGlzdGFuY2UgPSAiZXVjbGlkZWFuIgpteWFubm90YXRpb24gPSBhcy5kYXRhLmZyYW1lKGN1dHJlZShwaHQxW1sidHJlZV9yb3ciXV0sIGsgPSBudW1fb2ZfY2x1c3RlcnMpKSAjc3BsaXQgaW50byBrIGNsdXN0ZXJzCm5hbWVzKG15YW5ub3RhdGlvbilbMV0gPSAiY2x1c3RlciIKbXlhbm5vdGF0aW9uJGNsdXN0ZXIgPSBhcy5mYWN0b3IobXlhbm5vdGF0aW9uJGNsdXN0ZXIpCnBhbGV0dGUxIDwtYnJld2VyLnBhbChudW1fb2ZfY2x1c3RlcnMsICJQYWlyZWQiKQpuYW1lcyhwYWxldHRlMSkgPSB1bmlxdWUobXlhbm5vdGF0aW9uJGNsdXN0ZXIpCmFubl9jb2xvcnMgPSBsaXN0IChjbHVzdGVyID0gcGFsZXR0ZTEpCmFubm90YXRpb24gPSBsaXN0KGFubl9jb2xvcnMgPSBhbm5fY29sb3JzLCBteWFubm90YXRpb24gPSBteWFubm90YXRpb24pCgojY2hvb3NlIGNvbG9ycwpjb2xvcnMgPC0gYyhzZXEoLTEsMSxieT0wLjAxKSkKbXlfcGFsZXR0ZSA8LSBjKCJibHVlIixjb2xvclJhbXBQYWxldHRlKGNvbG9ycyA9IGMoImJsdWUiLCAid2hpdGUiLCAicmVkIikpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAobiA9IGxlbmd0aChjb2xvcnMpLTMpLCAicmVkIikKCgpwcmludF90YWIocGx0ID0gCiAgICAgICAgICAgICAgcGhlYXRtYXAobWF0ID0gaGFsbG1hcmtfY29yLGFubm90YXRpb25fY29sID0gIGFubm90YXRpb25bWyJteWFubm90YXRpb24iXV0sIGFubm90YXRpb25fY29sb3JzID0gYW5ub3RhdGlvbltbImFubl9jb2xvcnMiXV0sIGNsdXN0ZXJpbmdfZGlzdGFuY2Vfcm93cyA9IGNsdXN0ZXJpbmdfZGlzdGFuY2UsY2x1c3RlcmluZ19kaXN0YW5jZV9jb2xzID0gY2x1c3RlcmluZ19kaXN0YW5jZSxjb2xvciA9IG15X3BhbGV0dGUsYnJlYWtzID0gY29sb3JzLHNob3dfcm93bmFtZXMgPSBGLHNob3dfY29sbmFtZXMgPSBGKQogICAgICAgICAgICAsdGl0bGUgPSAiZ2VuZXMgZXhwcmVzc2lvbiBoZWF0bWFwIikKYGBgCgpgYGB7ciBlY2hvPVRSVUUsIHJlc3VsdHM9J2FzaXMnfQojY2hvb3NlIGNsdXN0ZXJzCmNob3Nlbl9jbHVzdGVycyA9IGMoMSwyLDMsNCkKcHJpbnQgKCJjaG9zZW5fY2x1c3RlcnM9ICIsIGNob3Nlbl9jbHVzdGVycykKCiNVTUFQIGV4cHJlc3Npb24gb2Ygc2lnbmF0dXJlCmNob3Nlbl9nZW5lcyA9IGFubm90YXRpb25bWyJteWFubm90YXRpb24iXV0gJT4lIGRwbHlyOjpmaWx0ZXIoY2x1c3RlciAlaW4lIGNob3Nlbl9jbHVzdGVycykgJT4lIHJvd25hbWVzKCkgI3Rha2UgcmVsZXZhbnQgZ2VuZXMKc2NvcmUgPC0gYXBwbHkoeGVub0Bhc3NheXMkUk5BQGRhdGFbY2hvc2VuX2dlbmVzLF0sMixtZWFuKQp4ZW5vPUFkZE1ldGFEYXRhKHhlbm8sc2NvcmUsaGFsbG1hcmtfbmFtZSkKCnByaW50X3RhYihGZWF0dXJlUGxvdChvYmplY3QgPSB4ZW5vLCBmZWF0dXJlcyA9IGhhbGxtYXJrX25hbWUpLHRpdGxlID0gIkV4cHJlc3Npb24iKQoKI3Bsb3Qgc2lnbmF0dXJlIGRpc3RyaWJ1dGlvbgpjY19zY29yZXMgPSBGZXRjaERhdGEob2JqZWN0ID0geGVubyx2YXJzID0gIkhBTExNQVJLX0cyTV9DSEVDS1BPSU5UIikKcGx0ICA9ICBnZ3Bsb3QoY2Nfc2NvcmVzLCBhZXMoeD1IQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVCkpICsKICBnZW9tX2RlbnNpdHkoKSsKICAgZ2VvbV92bGluZSgKICAgIGFlcyh4aW50ZXJjZXB0PW1lYW4oY2Nfc2NvcmVzJEhBTExNQVJLX0cyTV9DSEVDS1BPSU5UKSArIHNkKGNjX3Njb3JlcyRIQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVCkgLGNvbG9yPSIxIFNEIiksCiAgICAgICAgICBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKSsKICAgIGdlb21fdmxpbmUoCiAgICBhZXMoeGludGVyY2VwdD1tZWFuKGNjX3Njb3JlcyRIQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVCkgKyAyKnNkKGNjX3Njb3JlcyRIQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVCkgLGNvbG9yPSIyIFNEIiksCiAgICAgICAgICBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKQoKcHJpbnRfdGFiKHBsdCA9IHBsdCx0aXRsZSA9ICJkaXN0IikKCiMgUGxvdCBhc3NpZ25tZW50IAoKY2Nfc2NvcmVzID0gY2Nfc2NvcmVzICU+JSBtdXRhdGUoaXNfY3ljbGluZyA9IGlmX2Vsc2UoY29uZGl0aW9uID0gCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEhBTExNQVJLX0cyTV9DSEVDS1BPSU5UID4gbWVhbihIQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVCkgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICtzZChIQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cnVlID0gImN5Y2xpbmciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFsc2UgPSAibm9uX2N5Y2xpbmciKSkKeGVubyA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IHhlbm8sbWV0YWRhdGEgPSBjY19zY29yZXMkaXNfY3ljbGluZyxjb2wubmFtZSA9ICJpc19jeWNsaW5nIikKcHJpbnRfdGFiKHBsdCA9IERpbVBsb3Qob2JqZWN0ID0geGVubyxncm91cC5ieSA9ICJpc19jeWNsaW5nIikgLCB0aXRsZSA9ICJhc3NpZ25tZW50IDEgc2QiKQoKCiMgY2Nfc2NvcmVzID0gY2Nfc2NvcmVzICU+JSBtdXRhdGUoaXNfY3ljbGluZyA9IGlmX2Vsc2UoY29uZGl0aW9uID0gCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSEFMTE1BUktfRzJNX0NIRUNLUE9JTlQgPiBtZWFuKEhBTExNQVJLX0cyTV9DSEVDS1BPSU5UKSArIDIqc2QoY2Nfc2NvcmVzJEhBTExNQVJLX0cyTV9DSEVDS1BPSU5UKSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJ1ZSA9ICJjeWNsaW5nIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFsc2UgPSAibm9uX2N5Y2xpbmciKSkKIyB4ZW5vID0gQWRkTWV0YURhdGEob2JqZWN0ID0geGVubyxtZXRhZGF0YSA9IGNjX3Njb3JlcyRpc19jeWNsaW5nLGNvbC5uYW1lID0gImlzX2N5Y2xpbmciKQojIHByaW50X3RhYihwbHQgPSBEaW1QbG90KG9iamVjdCA9IHhlbm8sZ3JvdXAuYnkgPSAiaXNfY3ljbGluZyIpICwgdGl0bGUgPSAiYXNzaWdubWVudCAyIHNkIikKCgpgYGAKCgoKCmBgYHtyIGVjaG89VFJVRSwgcmVzdWx0cz0nYXNpcyd9CiBkZiAgPSBGZXRjaERhdGEob2JqZWN0ID0geGVubyx2YXJzID0gYygiaXNfY3ljbGluZyIsInRyZWF0bWVudCIpKSAlPiUgCiAgICBmaWx0ZXIgKHRyZWF0bWVudCAlaW4lIGMoIk5UIiwiT1NJIikpICU+JSAKICAgIGRyb3BsZXZlbHMoKSAKICB0ZXN0ID0gZmlzaGVyLnRlc3QodGFibGUoZGYpKQogICAgCiAgbGlicmFyeShnZ3N0YXRzcGxvdCkKCiAgICBwbHQgPSBnZ2JhcnN0YXRzKAogICAgZGYsIGlzX2N5Y2xpbmcsIHRyZWF0bWVudCwKICAgIHJlc3VsdHMuc3VidGl0bGUgPSBGQUxTRSwKICAgIHN1YnRpdGxlID0gcGFzdGUwKAogICAgICAiRmlzaGVyJ3MgZXhhY3QgdGVzdCIsICIsIHAtdmFsdWUgPSAiLAogICAgICAgcm91bmQodGVzdCRwLnZhbHVlLDEzKSkKICAgICkKICAKcHJpbnRfdGFiKHBsdCA9IHBsdCx0aXRsZSA9ICJmaXNoZXIiKQpgYGAKIyMgY29ycmVsYXRpb24gdG8gbm1mIHByb2dyYW0KYGBge3J9CmNvcl9yZXMgPSBjb3IoeGVubyRDZWxsX2N5Y2xlLHhlbm8kSEFMTE1BUktfRzJNX0NIRUNLUE9JTlQpCnByaW50KHBhc3RlKCJjb3JyZWxhdGlvbiBvZiBjYyBwcmdvcmFtIHRvIEhBTExNQVJLX0cyTV9DSEVDS1BPSU5UOiIsIGNvcl9yZXMpKQpgYGAKCgojIFRORmEgc2lnbmF0dXJlICB7LnRhYnNldH0KCmBgYHtyIHJlc3VsdHM9J2FzaXMnfQpoYWxsbWFya19uYW1lID0gIkhBTExNQVJLX1RORkFfU0lHTkFMSU5HX1ZJQV9ORktCIgpnZW5lc2V0cyAgPWdldEdtdCgiLi9EYXRhL2guYWxsLnY3LjAuc3ltYm9scy5wbHVzY2MuZ210IikKZ2VuZUlkcz0gZ2VuZXNldHNbW2hhbGxtYXJrX25hbWVdXUBnZW5lSWRzCmhhbGxtYXJzX2V4cCA9IEZldGNoRGF0YShvYmplY3QgPSB4ZW5vLHZhcnMgPSBjKGdlbmVJZHMpKQpoYWxsbWFyc19leHAgPSBoYWxsbWFyc19leHBbLGNvbFN1bXMoaGFsbG1hcnNfZXhwW10pPjBdICNyZW1vdmUgbm8gZXhwcmVzc2lvbiBnZW5lcwpoYWxsbWFya19jb3IgPSBjb3IoaGFsbG1hcnNfZXhwKQpwaHQxID0gcGhlYXRtYXAobWF0ID0gaGFsbG1hcmtfY29yLHNpbGVudCA9IFQpCmBgYAoKYGBge3IgZWNobz1UUlVFLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD0xMCwgcmVzdWx0cz0nYXNpcyd9Cm51bV9vZl9jbHVzdGVycyA9IDYKY2x1c3RlcmluZ19kaXN0YW5jZSA9ICJldWNsaWRlYW4iCm15YW5ub3RhdGlvbiA9IGFzLmRhdGEuZnJhbWUoY3V0cmVlKHBodDFbWyJ0cmVlX3JvdyJdXSwgayA9IG51bV9vZl9jbHVzdGVycykpICNzcGxpdCBpbnRvIGsgY2x1c3RlcnMKIApuYW1lcyhteWFubm90YXRpb24pWzFdID0gImNsdXN0ZXIiCiAgbXlhbm5vdGF0aW9uJGNsdXN0ZXIgPSBhcy5mYWN0b3IobXlhbm5vdGF0aW9uJGNsdXN0ZXIpCiAgCiAgcGFsZXR0ZTEgPC1icmV3ZXIucGFsKG51bV9vZl9jbHVzdGVycywgIlBhaXJlZCIpCgogIG5hbWVzKHBhbGV0dGUxKSA9IHVuaXF1ZShteWFubm90YXRpb24kY2x1c3RlcikKICBhbm5fY29sb3JzID0gbGlzdCAoY2x1c3RlciA9IHBhbGV0dGUxKQogIGFubm90YXRpb24gPSBsaXN0KGFubl9jb2xvcnMgPSBhbm5fY29sb3JzLCBteWFubm90YXRpb24gPSBteWFubm90YXRpb24pCiAgCiAgY29sb3JzIDwtIGMoc2VxKC0xLDEsYnk9MC4wMSkpCiAgbXlfcGFsZXR0ZSA8LSBjKCJibHVlIixjb2xvclJhbXBQYWxldHRlKGNvbG9ycyA9IGMoImJsdWUiLCAid2hpdGUiLCAicmVkIikpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChuID0gbGVuZ3RoKGNvbG9ycyktMyksICJyZWQiKQoKCiAgcHJpbnRfdGFiKHBsdCA9IAogICAgICAgICAgICAgICAgcGhlYXRtYXAobWF0ID0gaGFsbG1hcmtfY29yLGFubm90YXRpb25fY29sID0gIGFubm90YXRpb25bWyJteWFubm90YXRpb24iXV0sIGFubm90YXRpb25fY29sb3JzID0gYW5ub3RhdGlvbltbImFubl9jb2xvcnMiXV0sIGNsdXN0ZXJpbmdfZGlzdGFuY2Vfcm93cyA9IGNsdXN0ZXJpbmdfZGlzdGFuY2UsY2x1c3RlcmluZ19kaXN0YW5jZV9jb2xzID0gY2x1c3RlcmluZ19kaXN0YW5jZSxjb2xvciA9IG15X3BhbGV0dGUsYnJlYWtzID0gY29sb3JzLHNob3dfcm93bmFtZXMgPSBGLHNob3dfY29sbmFtZXMgPSBGKQogICAgICAgICAgICAsdGl0bGUgPSAiZ2VuZXMgZXhwcmVzc2lvbiBoZWF0bWFwIikKYGBgCmBgYHtyIGVjaG89VFJVRSwgcmVzdWx0cz0nYXNpcyd9CmNob3Nlbl9nZW5lcyA9IGFubm90YXRpb25bWyJteWFubm90YXRpb24iXV0gJT4lIGRwbHlyOjpmaWx0ZXIoY2x1c3RlciA9PSAzIHwgY2x1c3RlciA9PSAxIHwgY2x1c3RlciA9PSA1KSAlPiUgcm93bmFtZXMoKSAjdGFrZSByZWxldmFudCBnZW5lcwpzY29yZSA8LSBhcHBseSh4ZW5vQGFzc2F5cyRSTkFAZGF0YVtjaG9zZW5fZ2VuZXMsXSwyLG1lYW4pCnhlbm89QWRkTWV0YURhdGEoeGVubyxzY29yZSxoYWxsbWFya19uYW1lKQoKcHJpbnRfdGFiKEZlYXR1cmVQbG90KG9iamVjdCA9IHhlbm8sIGZlYXR1cmVzID0gaGFsbG1hcmtfbmFtZSksdGl0bGUgPSAiRXhwcmVzc2lvbiIpCmBgYAojIyBjb3JyZWxhdGlvbiB0byBubWYgcHJvZ3JhbQoKYGBge3J9CmNvcl9yZXMgPSBjb3IoeGVubyRIQUxMTUFSS19UTkZBX1NJR05BTElOR19WSUFfTkZLQix4ZW5vJFRORmEpCnByaW50KHBhc3RlKCJjb3JyZWxhdGlvbiBvZiBUTkZhIHByb2dyYW0gdG8gSEFMTE1BUktfVE5GQV9TSUdOQUxJTkdfVklBX05GS0I6IiwgY29yX3JlcykpCmBgYAoKYGBge3IgZWNobz1UUlVFLCByZXN1bHRzPSdhc2lzJ30KY2Nfc2NvcmVzID0gRmV0Y2hEYXRhKG9iamVjdCA9IHhlbm8sdmFycyA9IGhhbGxtYXJrX25hbWUpCgpwbHQgID0gIGdncGxvdChjY19zY29yZXMsIGFlcyh4PUhBTExNQVJLX1RORkFfU0lHTkFMSU5HX1ZJQV9ORktCKSkgKwogIGdlb21fZGVuc2l0eSgpKwogICBnZW9tX3ZsaW5lKAogICAgYWVzKHhpbnRlcmNlcHQ9bWVhbihIQUxMTUFSS19UTkZBX1NJR05BTElOR19WSUFfTkZLQikgKyBzZChIQUxMTUFSS19UTkZBX1NJR05BTElOR19WSUFfTkZLQikgLGNvbG9yPSIxIFNEIiksCiAgICAgICAgICBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKSsKICAgIGdlb21fdmxpbmUoCiAgICBhZXMoeGludGVyY2VwdD1tZWFuKEhBTExNQVJLX1RORkFfU0lHTkFMSU5HX1ZJQV9ORktCKSArIDIqc2QoSEFMTE1BUktfVE5GQV9TSUdOQUxJTkdfVklBX05GS0IpICxjb2xvcj0iMiBTRCIpLAogICAgICAgICAgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkrCiAgICBnZW9tX3ZsaW5lKAogICAgYWVzKHhpbnRlcmNlcHQ9bWVhbihIQUxMTUFSS19UTkZBX1NJR05BTElOR19WSUFfTkZLQikgLGNvbG9yPSJtZWFuIiksCiAgICAgICAgICBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKQoKcHJpbnRfdGFiKHBsdCA9IHBsdCx0aXRsZSA9ICJkaXN0IikKYGBgCiMgIFNpZ25hdHVyZSByZWd1bGF0aW9uICB7LnRhYnNldH0KCmBgYHtyIGVjaG89VFJVRSwgcmVzdWx0cz0nYXNpcyd9Cm1ldGFnZW5lc19tZWFuX2NvbXBhcmUoZGF0YXNldCA9IHhlbm8sdGltZS5wb2ludF92YXIgPSAidHJlYXRtZW50IixwcmVmaXggPSAibW9kZWwiLHBhdGllbnQuaWRlbnRfdmFyID0gIm9yaWcuaWRlbnQiLHByZV9vbiA9IGMoIk5UIiwiT1NJIiwicmVzIikscHJvZ3JhbXMgPSBjKCJIQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVCIsIkhBTExNQVJLX1RORkFfU0lHTkFMSU5HX1ZJQV9ORktCIikpCgpgYGAKCiMgSElGX3RhcmdldHMtIEh5cG94aWEgY29ycmVsYXRpb24gIHsudGFic2V0fQpgYGB7ciBlY2hvPVRSVUUsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTYsIHJlc3VsdHM9J2FzaXMnfQojIHBsb3QgY29ycmVsYXRpb24gZm9yIGV2ZXJ5IHN1YnNldCBvZiBoaWYgdGFyZ2V0cwpmb3IgKGdlbmVzIGluIGxpc3QoaGlmX3RhcmdldHMseGVub19jbHVzdGVyXzNfZ2VuZXMseGVub19jbHVzdGVyXzNfMl9nZW5lcykpIHsKICBoaWZfdGFyZ2V0c19ieV90cCA9IEZldGNoRGF0YShvYmplY3QgPSB4ZW5vLHZhcnMgPSBjKGdlbmVzKSkgJT4lIHJvd1N1bXMoKSAlPiUgYXMuZGF0YS5mcmFtZSgpICNtZWFuIGV4cHJlc3Npb24KICBoaWZfdGFyZ2V0c19ieV90cFssMl0gPSB4ZW5vJEh5cG94aWEKICAKICBuYW1lcyhoaWZfdGFyZ2V0c19ieV90cCkgPSBjKCJoaWZfdGFyZ2V0cyIsImh5cG94aWFfcHJvZ3JhbSIpCiAgCiAgCiAgCiAgcDEgPSBnZ3Bsb3QoaGlmX3RhcmdldHNfYnlfdHAsIGFlcyh4PWhpZl90YXJnZXRzLCB5PWh5cG94aWFfcHJvZ3JhbSkpICsgCiAgICAgIGdlb21fcG9pbnQoKSsKICAgIGdlb21fZGVuc2l0eV8yZChhZXMoY29sb3IgPSAuLmxldmVsLi4pKSArCiAgICBnZW9tX3Ntb290aChtZXRob2Q9bG0pICsKICAgIHN0YXRfY29yKG1ldGhvZCA9ICJwZWFyc29uIiwgbGFiZWwueCA9IDIwLCBsYWJlbC55ID0gMS4xKSsKICAgIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYygpCiAgCiAgcDIgPSBnZ3Bsb3QoaGlmX3RhcmdldHNfYnlfdHAsIGFlcyh4PWhpZl90YXJnZXRzLCB5PWh5cG94aWFfcHJvZ3JhbSkpICsgCiAgICBnZW9tX2JpbjJkKCkgKwogICAgdGhlbWVfYncoKSsgc2NhbGVfZmlsbF9ncmFkaWVudG4obGltaXRzPWMoMCwxMTAwKSwgYnJlYWtzPXNlcSgwLCAxMTAwLCBieT0yMDApLCBjb2xvdXJzPWMoImJsdWUiLCJ5ZWxsb3ciLCJyZWQiKSkrIAogICAgc3RhdF9jb3IobWV0aG9kID0gInBlYXJzb24iLCBsYWJlbC54ID0gMjAsIGxhYmVsLnkgPSAxLjEpKwogICAgZ2VvbV9zbW9vdGgobWV0aG9kPWxtKSAKICAKICBwID0gZ2dhcnJhbmdlKHBsb3RsaXN0ID0gbGlzdChwMSxwMiksbnJvdyAgPSAyKSAgCiAgCiAgcHJpbnRfdGFiKHBsdCA9IHAsdGl0bGUgPSAiZ2VvbV9iaW4yZCIpCn0KCgpgYGAKCgojIFVNQVBTCmBgYHtyIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTEwfQpoaWZfdGFyZ2V0c19ieV90cCA9IEZldGNoRGF0YShvYmplY3QgPSB4ZW5vLHZhcnMgPSBjKGhpZl90YXJnZXRzKSkgJT4lIHJvd1N1bXMoKSAlPiUgYXMuZGF0YS5mcmFtZSgpICNtZWFuIGV4cHJlc3Npb24KaGlmX3RhcmdldHNfYnlfdHBbLDJdID0geGVubyRIeXBveGlhCm5hbWVzKGhpZl90YXJnZXRzX2J5X3RwKSA9IGMoImhpZl90YXJnZXRzIiwiaHlwb3hpYV9wcm9ncmFtIikKCmhpZ2hfaGlmX2xvd19oeXBveGlhX2NlbGxzID0gaGlmX3RhcmdldHNfYnlfdHAgJT4lIGZpbHRlcihoaWZfdGFyZ2V0cz4yNSAmIGh5cG94aWFfcHJvZ3JhbSA8IDAuMikgJT4lIHJvd25hbWVzKCkKbG93X2hpZl9oaWdoX2h5cG94aWFfY2VsbHMgPSBoaWZfdGFyZ2V0c19ieV90cCAlPiUgZmlsdGVyKGhpZl90YXJnZXRzPDE1ICYgaHlwb3hpYV9wcm9ncmFtID4gMC42KSAlPiUgcm93bmFtZXMoKQoKaGlmX3RhcmdldHNfYnlfdHAgPSBGZXRjaERhdGEob2JqZWN0ID0geGVubyx2YXJzID0gYyhoaWZfdGFyZ2V0cykpICU+JSByb3dTdW1zKCkgJT4lIGFzLmRhdGEuZnJhbWUoKSAjbWVhbiBleHByZXNzaW9uCnhlbm8gPSBBZGRNZXRhRGF0YShvYmplY3QgPSB4ZW5vLCBtZXRhZGF0YSA9IGhpZl90YXJnZXRzX2J5X3RwLGNvbC5uYW1lID0gIkhJRl90YXJnZXRzX3Njb3JlIikKY2VsbHNfdG9faGlnaGxpZ2h0ID0gIGxpc3QoaGlnaF9oaWZfbG93X2h5cG94aWFfY2VsbHMgPSBoaWdoX2hpZl9sb3dfaHlwb3hpYV9jZWxscywgbG93X2hpZl9oaWdoX2h5cG94aWFfY2VsbHMgPSBsb3dfaGlmX2hpZ2hfaHlwb3hpYV9jZWxscykKCkRpbVBsb3Qob2JqZWN0ID0geGVubywgY2VsbHMuaGlnaGxpZ2h0ID0gY2VsbHNfdG9faGlnaGxpZ2h0LCBjb2xzLmhpZ2hsaWdodCA9IGMoInJlZCIsImJsdWUiKSwgY29scyA9ICJncmF5Iiwgb3JkZXIgPSBUUlVFKQpGZWF0dXJlUGxvdChvYmplY3QgPSB4ZW5vLGZlYXR1cmVzID0gYyggIkhJRl90YXJnZXRzX3Njb3JlIiwiSHlwb3hpYSIsIkNlbGxfY3ljbGUiICkpCgpgYGAKYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTB9CmhpZl9oeXBveGlhX2NvcnJlbGF0ZWRfY2VsbHMgPSBjb2xuYW1lcyh4ZW5vKSBbIWNvbG5hbWVzKHhlbm8pICVpbiUgaGlnaF9oaWZfbG93X2h5cG94aWFfY2VsbHMgJiAhY29sbmFtZXMoeGVubykgJWluJSBoaWdoX2hpZl9sb3dfaHlwb3hpYV9jZWxsc10KaGlmX3RhcmdldHNfc2NvcmUgPSBGZXRjaERhdGEob2JqZWN0ID0geGVubyx2YXJzID0gYyhoaWZfdGFyZ2V0cykpICU+JSByb3dTdW1zKCkgJT4lIGFzLmRhdGEuZnJhbWUoKSAjbWVhbiBleHByZXNzaW9uCmhpZl90YXJnZXRzX3Njb3JlWywyXSA9IHhlbm8kSHlwb3hpYQpuYW1lcyhoaWZfdGFyZ2V0c19zY29yZSkgPSBjKCJoaWZfdGFyZ2V0cyIsImh5cG94aWFfcHJvZ3JhbSIpCmhpZl90YXJnZXRzX3Njb3JlICA9IGhpZl90YXJnZXRzX3Njb3JlICU+JSBtdXRhdGUodHlwZSA9IGNhc2Vfd2hlbihoaWZfdGFyZ2V0cz4yNSAmIGh5cG94aWFfcHJvZ3JhbSA8IDAuMiB+ICJoaWdoX2hpZl9sb3dfaHlwb3hpYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoaWZfdGFyZ2V0czwxNSAmIGh5cG94aWFfcHJvZ3JhbSA+IDAuNiB+ICJsb3dfaGlmX2hpZ2hfaHlwb3hpYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoaWZfdGFyZ2V0cz4yNSAmIGh5cG94aWFfcHJvZ3JhbSA+IDAuNiB+ICJoaWdoX2hpZl9oaWdoX2h5cG94aWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGlmX3RhcmdldHM8MTUgJiBoeXBveGlhX3Byb2dyYW0gPDAuMiB+ICJoaWdoX2hpZl9oaWdoX2h5cG94aWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJvdGhlciIpKQp4ZW5vID0gQWRkTWV0YURhdGEob2JqZWN0ID0geGVubyxtZXRhZGF0YSA9IGhpZl90YXJnZXRzX3Njb3JlWywidHlwZSIsIGRyb3AgPSBGXSxjb2wubmFtZSA9ICJzY29yZV9jb3JyZWxhdGlvbiIpCnhlbm8gPSBTZXRJZGVudChvYmplY3QgPSB4ZW5vLHZhbHVlID0gInNjb3JlX2NvcnJlbGF0aW9uIikKRGltUGxvdChvYmplY3QgPSB4ZW5vLGdyb3VwLmJ5ID0gInNjb3JlX2NvcnJlbGF0aW9uIikKbWFya2VycyA9IEZpbmRNYXJrZXJzKG9iamVjdCA9IHhlbm8sIGlkZW50LjEgPSAiaGlnaF9oaWZfbG93X2h5cG94aWEiLGlkZW50LjIgPSAiaGlnaF9oaWZfaGlnaF9oeXBveGlhIixkZW5zaWZ5ID0gVCkKYGBgCmBgYHtyIGVjaG89VFJVRSwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9NiwgcmVzdWx0cz0nYXNpcyd9CnVwZGVnID0gbWFya2VycyAlPiUgZmlsdGVyKHBfdmFsX2FkajwwLjA1ICYgYXZnX2xvZzJGQz4wKSAlPiUgcm93bmFtZXMoKQoKbmV3X2hpZl90YXJnZXRzID0gaGlmX3RhcmdldHNbIWhpZl90YXJnZXRzICVpbiUgdXBkZWddCmhpZl90YXJnZXRzX2J5X3RwID0gRmV0Y2hEYXRhKG9iamVjdCA9IHhlbm8sdmFycyA9IGMobmV3X2hpZl90YXJnZXRzKSkgJT4lIHJvd1N1bXMoKSAlPiUgYXMuZGF0YS5mcmFtZSgpICNtZWFuIGV4cHJlc3Npb24KICBoaWZfdGFyZ2V0c19ieV90cFssMl0gPSB4ZW5vJEh5cG94aWEKICAKICBuYW1lcyhoaWZfdGFyZ2V0c19ieV90cCkgPSBjKCJoaWZfdGFyZ2V0cyIsImh5cG94aWFfcHJvZ3JhbSIpCiAgCiAgCiAgCiAgcDEgPSBnZ3Bsb3QoaGlmX3RhcmdldHNfYnlfdHAsIGFlcyh4PWhpZl90YXJnZXRzLCB5PWh5cG94aWFfcHJvZ3JhbSkpICsgCiAgICAgIGdlb21fcG9pbnQoKSsKICAgIGdlb21fZGVuc2l0eV8yZChhZXMoY29sb3IgPSAuLmxldmVsLi4pKSArCiAgICBnZW9tX3Ntb290aChtZXRob2Q9bG0pICsKICAgIHN0YXRfY29yKG1ldGhvZCA9ICJwZWFyc29uIiwgbGFiZWwueCA9IDIwLCBsYWJlbC55ID0gMS4xKSsKICAgIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYygpCiAgCiAgcDIgPSBnZ3Bsb3QoaGlmX3RhcmdldHNfYnlfdHAsIGFlcyh4PWhpZl90YXJnZXRzLCB5PWh5cG94aWFfcHJvZ3JhbSkpICsgCiAgICBnZW9tX2JpbjJkKCkgKwogICAgdGhlbWVfYncoKSsgc2NhbGVfZmlsbF9ncmFkaWVudG4obGltaXRzPWMoMCwxMTAwKSwgYnJlYWtzPXNlcSgwLCAxMTAwLCBieT0yMDApLCBjb2xvdXJzPWMoImJsdWUiLCJ5ZWxsb3ciLCJyZWQiKSkrIAogICAgc3RhdF9jb3IobWV0aG9kID0gInBlYXJzb24iLCBsYWJlbC54ID0gMjAsIGxhYmVsLnkgPSAxLjEpKwogICAgZ2VvbV9zbW9vdGgobWV0aG9kPWxtKSAKICAKICBwID0gZ2dhcnJhbmdlKHBsb3RsaXN0ID0gbGlzdChwMSxwMiksbnJvdyAgPSAyKSAgCiAgCiAgcHJpbnRfdGFiKHBsdCA9IHAsdGl0bGUgPSAiZ2VvbV9iaW4yZCIpCgoKYGBgCgoKYGBge3J9CnVwcmVnX2hpZl90YXJnZXRzID0gaGlmX3RhcmdldHNbaGlmX3RhcmdldHMgJWluJSB1cGRlZ10KdXByZWdfaGlmX3RhcmdldHNfZXhwciA9IEZldGNoRGF0YShvYmplY3QgPSB4ZW5vLHZhcnMgPSBjKHVwcmVnX2hpZl90YXJnZXRzKSkgJT4lIHJvd1N1bXMoKSAlPiUgYXMuZGF0YS5mcmFtZSgpICNtZWFuIGV4cHJlc3Npb24KeGVubyA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IHhlbm8sIG1ldGFkYXRhID0gdXByZWdfaGlmX3RhcmdldHNfZXhwcixjb2wubmFtZSA9ICJ1cHJlZ19oaWZfdGFyZ2V0c19zY29yZSIpCkZlYXR1cmVQbG90KG9iamVjdCA9IHhlbm8sZmVhdHVyZXMgPSAidXByZWdfaGlmX3RhcmdldHNfc2NvcmUiKQpgYGAKCgojIENhbGN1bGF0ZSB1c2FnZSB3aXRob3V0IGNjIGluIHN1bSB0byAxCmBgYHtweXRob259CmltcG9ydCBudW1weSBhcyBucAppbXBvcnQgc2NhbnB5IGFzIHNjCnhlbm9fZXhwcmVzc2lvbiA9IHIueGVub19leHByZXNzaW9uCnhlbm9fdmFyZ2VuZXMgPSByLnhlbm9fdmFyZ2VuZXMKdHBtID0gIGNvbXB1dGVfdHBtKHhlbm9fZXhwcmVzc2lvbikKdXNhZ2VfYnlfY2FsYyA9IGdldF91c2FnZV9mcm9tX3Njb3JlKGNvdW50cz14ZW5vX2V4cHJlc3Npb24sdHBtPXRwbSxnZW5lcz14ZW5vX3ZhcmdlbmVzLCBjbm1mX29iaj1jbm1mX29iaixrPTMsc3VtVG8xPUZhbHNlKQpgYGAKYGBge3J9CmFsbF9tZXRhZ2VuZXNfbm9TdW1UbzEgPSBweSR1c2FnZV9ieV9jYWxjCnRuZl9hbmRfaHlwb3hpYSA9IGFsbF9tZXRhZ2VuZXNfbm9TdW1UbzFbLDE6Ml0KdG5mX2FuZF9oeXBveGlhID0gYXBwbHkoWCA9IHRuZl9hbmRfaHlwb3hpYSwgTUFSR0lOID0gMSwgc3VtXzJfb25lKSAlPiUgdCgpICU+JSAgYXMuZGF0YS5mcmFtZSgpCnRuZl9hbmRfaHlwb3hpYVtpcy5uYSh0bmZfYW5kX2h5cG94aWEpXSA8LSAwICNyZXBsYWNlIE5BTidzIHdpdGggMC4KYGBgCgpgYGB7ciBlY2hvPVRSVUUsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTYsIHJlc3VsdHM9J2FzaXMnfQojIHBsb3QgY29ycmVsYXRpb24gZm9yIGV2ZXJ5IHN1YnNldCBvZiBoaWYgdGFyZ2V0cwpmb3IgKGdlbmVzIGluIGxpc3QoaGlmX3RhcmdldHMseGVub19jbHVzdGVyXzNfZ2VuZXMseGVub19jbHVzdGVyXzNfMl9nZW5lcykpIHsKICBoaWZfdGFyZ2V0c19ieV90cCA9IEZldGNoRGF0YShvYmplY3QgPSB4ZW5vLHZhcnMgPSBjKGdlbmVzKSkgJT4lIHJvd1N1bXMoKSAlPiUgYXMuZGF0YS5mcmFtZSgpICNtZWFuIGV4cHJlc3Npb24KICBoaWZfdGFyZ2V0c19ieV90cFssMl0gPSB0bmZfYW5kX2h5cG94aWFbLDFdCiAgIyBoaWZfdGFyZ2V0c19ieV90cFssMl0gPSB4ZW5vJEh5cG94aWEKICAKICBuYW1lcyhoaWZfdGFyZ2V0c19ieV90cCkgPSBjKCJoaWZfdGFyZ2V0cyIsImh5cG94aWFfcHJvZ3JhbSIpCiAgCiAgCiAgCiAgcDEgPSBnZ3Bsb3QoaGlmX3RhcmdldHNfYnlfdHAsIGFlcyh4PWhpZl90YXJnZXRzLCB5PWh5cG94aWFfcHJvZ3JhbSkpICsgCiAgICAgIGdlb21fcG9pbnQoKSsKICAgIGdlb21fZGVuc2l0eV8yZChhZXMoY29sb3IgPSAuLmxldmVsLi4pKSArCiAgICBnZW9tX3Ntb290aChtZXRob2Q9bG0pICsKICAgIHN0YXRfY29yKG1ldGhvZCA9ICJwZWFyc29uIiwgbGFiZWwueCA9IDIwLCBsYWJlbC55ID0gMS4xKSsKICAgIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYygpCiAgCiAgcDIgPSBnZ3Bsb3QoaGlmX3RhcmdldHNfYnlfdHAsIGFlcyh4PWhpZl90YXJnZXRzLCB5PWh5cG94aWFfcHJvZ3JhbSkpICsgCiAgICBnZW9tX2JpbjJkKCkgKwogICAgdGhlbWVfYncoKSsgc2NhbGVfZmlsbF9ncmFkaWVudG4obGltaXRzPWMoMCwxMTAwKSwgYnJlYWtzPXNlcSgwLCAxMTAwLCBieT0yMDApLCBjb2xvdXJzPWMoImJsdWUiLCJ5ZWxsb3ciLCJyZWQiKSkrIAogICAgc3RhdF9jb3IobWV0aG9kID0gInBlYXJzb24iLCBsYWJlbC54ID0gMjAsIGxhYmVsLnkgPSAxLjEpKwogICAgZ2VvbV9zbW9vdGgobWV0aG9kPWxtKSAKICAKICBwID0gZ2dhcnJhbmdlKHBsb3RsaXN0ID0gbGlzdChwMSxwMiksbnJvdyAgPSAyKSAgCiAgCiAgcHJpbnRfdGFiKHBsdCA9IHAsdGl0bGUgPSAiZ2VvbV9iaW4yZCIpCn0KCgpgYGAKCiMgVU1BUFMKYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OH0KaGlmX3RhcmdldHNfYnlfdHAgPSBGZXRjaERhdGEob2JqZWN0ID0geGVubyx2YXJzID0gYyhoaWZfdGFyZ2V0cykpICU+JSByb3dTdW1zKCkgJT4lIGFzLmRhdGEuZnJhbWUoKSAjbWVhbiBleHByZXNzaW9uCmhpZl90YXJnZXRzX2J5X3RwWywyXSA9IHRuZl9hbmRfaHlwb3hpYVssMV0KbmFtZXMoaGlmX3RhcmdldHNfYnlfdHApID0gYygiaGlmX3RhcmdldHMiLCJoeXBveGlhX3Byb2dyYW0iKQoKaGlnaF9oaWZfbG93X2h5cG94aWFfY2VsbHMgPSBoaWZfdGFyZ2V0c19ieV90cCAlPiUgZmlsdGVyKGhpZl90YXJnZXRzPjI1ICYgaHlwb3hpYV9wcm9ncmFtIDwgMC4yKSAlPiUgcm93bmFtZXMoKQoKaGlmX3RhcmdldHNfYnlfdHAgPSBGZXRjaERhdGEob2JqZWN0ID0geGVubyx2YXJzID0gYyhoaWZfdGFyZ2V0cykpICU+JSByb3dTdW1zKCkgJT4lIGFzLmRhdGEuZnJhbWUoKSAjbWVhbiBleHByZXNzaW9uCnhlbm8gPSBBZGRNZXRhRGF0YShvYmplY3QgPSB4ZW5vLCBtZXRhZGF0YSA9IGhpZl90YXJnZXRzX2J5X3RwLGNvbC5uYW1lID0gIkhJRl90YXJnZXRzX3Njb3JlIikKeGVubyA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IHhlbm8sIG1ldGFkYXRhID0gdG5mX2FuZF9oeXBveGlhWywxXSxjb2wubmFtZSA9ICJIeXBveGlhMiIpCgpEaW1QbG90KG9iamVjdCA9IHhlbm8sIGNlbGxzLmhpZ2hsaWdodCA9IGhpZ2hfaGlmX2xvd19oeXBveGlhX2NlbGxzLCBjb2xzLmhpZ2hsaWdodCA9ICJyZWQiLCBjb2xzID0gImdyYXkiLCBvcmRlciA9IFRSVUUpCkZlYXR1cmVQbG90KG9iamVjdCA9IHhlbm8sZmVhdHVyZXMgPSBjKCAiSElGX3RhcmdldHNfc2NvcmUiLCJIeXBveGlhMiIsIkNlbGxfY3ljbGUiICkpCkZlYXR1cmVQbG90KG9iamVjdCA9IHhlbm8sZmVhdHVyZXMgPSBjKCJIeXBveGlhMiIpKQpEaW1QbG90KG9iamVjdCA9IHhlbm8sZ3JvdXAuYnkgPSAib3JpZy5pZGVudCIpCgpgYGAKCiMgSHlwb3hpYSByYXcKYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTB9Cnhlbm8gPSBBZGRNZXRhRGF0YShvYmplY3QgPSB4ZW5vLG1ldGFkYXRhID0gYWxsX21ldGFnZW5lc19ub1N1bVRvMVssMV0sY29sLm5hbWUgPSAiaHlwb3hpYV9yYXciKQpGZWF0dXJlUGxvdChvYmplY3QgPSB4ZW5vLGZlYXR1cmVzID0gImh5cG94aWFfcmF3IikgKyBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3VycyA9IHJhaW5ib3coNSksIGxpbWl0cyA9IGMoMCwgMzAwMCkpCmBgYAoKCgo8c2NyaXB0IHNyYz0iaHR0cHM6Ly9oeXBvdGhlcy5pcy9lbWJlZC5qcyIgYXN5bmM+PC9zY3JpcHQ+Cg==