1 Functions

2 Data

HCC827Jun23 = read.table(
  file = "./Data/osiRoxa_bulk/Jun23/gene_fpkm.xls",
  sep = "\t",
  header = TRUE
)
rownames(HCC827Jun23) = make.unique(HCC827Jun23[,"gene_name",drop=T]) #set genes names
HCC827Jun23 = HCC827Jun23[,2:31]
names (HCC827Jun23) = gsub(x = names(HCC827Jun23),pattern = "op",replacement = "osiPersistors")%>% gsub(pattern = "cp",replacement = "comboPersistors") 
HCC827Jun23 = HCC827Jun23[,16:ncol(HCC827Jun23)] #take only HCC827
# create metadata
cell.labels = names(HCC827Jun23)
condition = str_extract(cell.labels, "osiPersistors|comboPersistors|osi|ctrl|roxa")
metadata = data.frame(condition = condition, row.names = colnames(HCC827Jun23))
library(DESeq2)
dds <- DESeqDataSetFromMatrix(countData = round(HCC827Jun23),
                              colData = metadata,
                              design = ~condition)
converting counts to integer mode
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  some variables in design formula are characters, converting to factors

3 PCA

nrow(dds)
[1] 27827
dds1 <- dds[ rowSums(counts(dds)) >= 3, ]
nrow(dds1)
[1] 8494
vst = vst(dds1, blind=FALSE)
-- note: fitType='parametric', but the dispersion trend was not well captured by the
   function: y = a/x + b, and a local regression fit was automatically substituted.
   specify fitType='local' or 'mean' to avoid this message next time.
library("ggfortify")
PCAdata <- prcomp(t(assay(vst)))
autoplot(PCAdata, data = metadata,colour = "condition",label = FALSE, main="PCA") # Show dots

#DESeq

dds <- DESeq(dds)
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
dds_HCC827_JUN23 = dds
dds = dds_HCC827_JUN23

4 Top variable genes heatmap

genes <- head(order(rowVars(assay(dds)), decreasing = TRUE), 1000)

mat <- HCC827Jun23[ genes, ]
mat <- t(scale(t(mat)))
anno <- as.data.frame(mat)

library(ComplexHeatmap) 
library(ggplot2) 
Heatmap(mat, cluster_rows = T, cluster_columns = F, column_labels = colnames(anno), name = "fpkm Z-score",row_names_gp = gpar(fontsize = 0)) 

5 DEG FC

cpVSop <- results(dds,contrast = c("condition","comboPersistors","osiPersistors"))  %>% as.data.frame()
roxaVSctrl <- results(dds,contrast = c("condition","roxa","ctrl"))  %>% as.data.frame()
diff_genes = data.frame(row.names = rownames(cpVSop), cpVSop_FC = cpVSop$log2FoldChange,roxaVSctrl_FC = roxaVSctrl$log2FoldChange,  cpVSop_padj = cpVSop$padj)
cpVSop = cpVSop[order(cpVSop$log2FoldChange, cpVSop$padj,decreasing = T),] #order by FC, ties bt padj
ranked_vec = cpVSop[,"log2FoldChange"]%>% setNames(rownames(cpVSop)) %>% na.omit() # make named vector

hyp_obj <- hypeR_fgsea(ranked_vec, genesets, up_only = F)

Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam, : There are ties in the preranked stats (11.24% of the list). The order of those tied genes will be arbitrary, which may produce unexpected results.

plt = hyp_dots(hyp_obj,merge = F)
plt1 = plt$up+ aes(size=nes)+ggtitle("up in comboPersistor")
plt2 = plt$dn+ aes(size=abs(nes))+ggtitle("up in osiPersistors")
print_tab(plt1+plt2,title = "cpVSop")

cpVSop

roxaVSctrl = roxaVSctrl[order(roxaVSctrl$log2FoldChange, roxaVSctrl$padj,decreasing = T),] #order by FC, ties bt padj
ranked_vec = roxaVSctrl[,"log2FoldChange"]%>% setNames(rownames(roxaVSctrl)) %>% na.omit()  # make named vector

hyp_obj <- hypeR_fgsea(ranked_vec, genesets, up_only = F)

Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam, : There are ties in the preranked stats (12.19% of the list). The order of those tied genes will be arbitrary, which may produce unexpected results.

plt = hyp_dots(hyp_obj,merge = F)
plt1 = plt$up+ aes(size=nes)+ggtitle("up in roxa")
plt2 = plt$dn+ aes(size=abs(nes))+ggtitle("up in ctrl")
print_tab(plt1+plt2,title = "cpVSop")

cpVSop

NA

6 DEG shrinked FC

dds$condition = relevel(dds$condition, ref = "osiPersistors")
dds <- nbinomWaldTest(dds)
cpVSop <- lfcShrink(dds,coef = "condition_comboPersistors_vs_osiPersistors")  %>% as.data.frame()

dds$condition = relevel(dds$condition, ref = "ctrl")
dds <- nbinomWaldTest(dds)
roxaVSctrl <- lfcShrink(dds,coef  = "condition_roxa_vs_ctrl")  %>% as.data.frame()


diff_genes = data.frame(row.names = rownames(cpVSop), cpVSop_FC = cpVSop$log2FoldChange,roxaVSctrl_FC = roxaVSctrl$log2FoldChange,  cpVSop_padj = cpVSop$padj)
ranked_vec = diff_genes[, 1] %>% setNames(rownames(diff_genes)) %>% sort(decreasing = TRUE)
hyp_obj <- hypeR_fgsea(ranked_vec, genesets, up_only = F)

Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam, : There are ties in the preranked stats (23.49% of the list). The order of those tied genes will be arbitrary, which may produce unexpected results.

plt = hyp_dots(hyp_obj,merge = F)
plt1 = plt$up+ aes(size=nes)+ggtitle("up in comboPersistor") + theme(  axis.text.y = element_text(size=10))
plt2 = plt$dn+ aes(size=abs(nes))+ggtitle("up in osiPersistors") + theme(axis.text.y = element_text(size=10))
print_tab(plt1+plt2,title = "cpVSop")

cpVSop

ranked_vec = diff_genes[, 2] %>% setNames(rownames(diff_genes)) %>% sort(decreasing = TRUE)
hyp_obj <- hypeR_fgsea(ranked_vec, genesets, up_only = F)

Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam, : There are ties in the preranked stats (23.49% of the list). The order of those tied genes will be arbitrary, which may produce unexpected results.

plt = hyp_dots(hyp_obj,merge = F)
plt1 = plt$up+ aes(size=nes)+ggtitle("up in roxa")
plt2 = plt$dn+ aes(size=abs(nes))+ggtitle("up in ctrl")
print_tab(plt1+plt2,title = "cpVSop")

cpVSop

NA

7 DEG in comboVSosi but not in roxaVSctrl

cpVSop <- results(dds,contrast = c("condition","comboPersistors","osiPersistors"))  %>% as.data.frame()
roxaVSctrl <- results(dds,contrast = c("condition","roxa","ctrl"))  %>% as.data.frame()
diff_genes = data.frame(row.names = rownames(cpVSop), cpVSop_FC = 2**cpVSop$log2FoldChange,roxaVSctrl_FC = 2**roxaVSctrl$log2FoldChange,  cpVSop_padj = cpVSop$padj)
up_genes_df =  diff_genes %>% filter(cpVSop_FC > 2 & roxaVSctrl_FC<1.2 & cpVSop_padj<0.05) 
down_genes_df = diff_genes %>% filter(cpVSop_FC < 0.5 & roxaVSctrl_FC>0.8 & cpVSop_padj<0.05)
up_genes = diff_genes %>% filter(cpVSop_FC > 2 & roxaVSctrl_FC<1.2 & cpVSop_padj<0.05) %>% rownames()
down_genes = diff_genes %>% filter(cpVSop_FC < 0.5 & roxaVSctrl_FC>0.8 & cpVSop_padj<0.1)%>% rownames()

print_tab(up_genes_df,title = "up")

up

print_tab(down_genes_df,title = "down")

down

NA

hyp_obj <- hypeR(up_genes, genesets, test = "hypergeometric", fdr=1, plotting=F,background = rownames(H1975Oct23))
plt1 = hyp_dots(hyp_obj,title = "up in comboVSosi but not in roxaVSctrl")
 

hyp_obj <- hypeR(down_genes, genesets, test = "hypergeometric", fdr=1, plotting=F,background = rownames(H1975Oct23))
plt2 = hyp_dots(hyp_obj,title = "down in comboVSosi but not in roxaVSctrl")

plt1 + plt2

print_tab(data.frame(up_genes[up_genes %in% genesets$HALLMARK_GLYCOLYSIS]),title = "up genes in GLYCOLYSIS")

up genes in GLYCOLYSIS

NA

8 Intersection HCC827 and H1975 DEG

HCC827_down_genes
[1] "IFI6"      "CDKN2B"    "SELENBP1"  "RENBP"     "SLC6A9"    "LINC02582"
intersect(HCC827_up_genes,H1975_up_genes)
[1] "HMGB2"
intersect(HCC827_down_genes,H1975_down_genes)
character(0)

9 Expression heatmap

# select the 50 most differentially expressed genes 
# genes <- c("DUSP6")
# mat <- HCC827Jun23[ genes, ]
# mat <- t(scale(t(mat)))
# anno <- as.data.frame(mat)
# 
# library(ComplexHeatmap) 
# library(ggplot2) 
# p = Heatmap(mat, cluster_rows = F, cluster_columns = F, column_labels = colnames(anno), name = "fpkm Z-score") 
# print_tab(plt = p,title = "markers")

genes <- hif_targets
mat <- HCC827Jun23[genes, ] %>% filter(rowSums(across(where(is.numeric)))!=0)
mat <- t(scale(t(mat)))
anno <- as.data.frame(mat)

 
p = Heatmap(mat, cluster_rows = T, cluster_columns = F, column_labels = colnames(anno), name = "fpkm Z-score",column_title = "HIF targets",row_names_gp = gpar(fontsize = 8))

print_tab(plt = p,title = "HIF targets")

HIF targets

genes <- genesets$HALLMARK_G2M_CHECKPOINT
mat <- HCC827Jun23[genes, ] %>% filter(rowSums(across(where(is.numeric)))!=0)
mat <- t(scale(t(mat)))
anno <- as.data.frame(mat)

 
p = Heatmap(mat, cluster_rows = T, cluster_columns = F, column_labels = colnames(anno), name = "fpkm Z-score",column_title = "HALLMARK_G2M_CHECKPOINT",row_names_gp =gpar(fontsize = 0)) 

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

HALLMARK_G2M_CHECKPOINT

genes <- genesets$HALLMARK_HYPOXIA
mat <- HCC827Jun23[genes, ] %>% filter(rowSums(across(where(is.numeric)))!=0)
mat <- t(scale(t(mat)))
anno <- as.data.frame(mat)

 
p = Heatmap(mat, cluster_rows = T, cluster_columns = F, column_labels = colnames(anno), name = "fpkm Z-score",column_title = "HALLMARK_HYPOXIA",row_names_gp =gpar(fontsize = 0)) 

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

HALLMARK_HYPOXIA

NA

10 G2M heatmap

genes <- genesets$HALLMARK_G2M_CHECKPOINT
mat <- HCC827Jun23[genes, ] %>% filter(rowSums(across(where(is.numeric)))!=0)
mat <- t(scale(t(mat)))
anno <- as.data.frame(mat)

split = data.frame( cluster = cutree(hclust(dist(mat)), k = 3))
ha = rowAnnotation(cluster = as.character(split$cluster),col = list(cluster = structure(rainbow(n = 3), names=unique(split$cluster))))
p = Heatmap(mat, cluster_rows = T, cluster_columns = F, column_labels = colnames(anno), name = "fpkm Z-score",column_title = "HALLMARK_G2M_CHECKPOINT",row_names_gp =gpar(fontsize = 0),right_annotation = ha)

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

HALLMARK_G2M_CHECKPOINT

NA

11 Enrichment analysis

chosen_genes = split %>% dplyr::filter(cluster == 2) %>% rownames() #take relevant genes
hyp_obj <- hypeR(chosen_genes, genesets_wikipathways, test = "hypergeometric", fdr=1, plotting=F,background = rownames(H1975Oct23))
p1 = hyp_dots(hyp_obj,size_by = "none",title = "cluster 2")
chosen_genes = split %>% dplyr::filter(cluster == 3) %>% rownames() #take relevant genes
hyp_obj <- hypeR(chosen_genes, genesets_wikipathways, test = "hypergeometric", fdr=1, plotting=F,background = rownames(H1975Oct23))
p2 = hyp_dots(hyp_obj,size_by = "none",title = "cluster 3")

wiki_p = (p1/p2)
print_tab(plt = wiki_p,title = "wikipathways")

wikipathways

chosen_genes = split %>% dplyr::filter(cluster == 2) %>% rownames() #take relevant genes
hyp_obj <- hypeR(chosen_genes, genesets_biocarta, test = "hypergeometric", fdr=1, plotting=F,background = rownames(H1975Oct23))
p1 = hyp_dots(hyp_obj,size_by = "none",title = "cluster 2")
chosen_genes = split %>% dplyr::filter(cluster == 3) %>% rownames() #take relevant genes
hyp_obj <- hypeR(chosen_genes, genesets_biocarta, test = "hypergeometric", fdr=1, plotting=F,background = rownames(H1975Oct23))
p2 = hyp_dots(hyp_obj,size_by = "none",title = "cluster 3")

wiki_p = (p1/p2)
print_tab(plt = wiki_p,title = "biocarta")

biocarta

chosen_genes = split %>% dplyr::filter(cluster == 2) %>% rownames() #take relevant genes
hyp_obj <- hypeR(chosen_genes, genesets_pid, test = "hypergeometric", fdr=1, plotting=F,background = rownames(H1975Oct23))
p1 = hyp_dots(hyp_obj,size_by = "none",title = "cluster 2")
chosen_genes = split %>% dplyr::filter(cluster == 3) %>% rownames() #take relevant genes
hyp_obj <- hypeR(chosen_genes, genesets_pid, test = "hypergeometric", fdr=1, plotting=F,background = rownames(H1975Oct23))
p2 = hyp_dots(hyp_obj,size_by = "none",title = "cluster 3")

wiki_p = (p1/p2)
print_tab(plt = wiki_p,title = "pid")

pid

chosen_genes = split %>% dplyr::filter(cluster == 2) %>% rownames() #take relevant genes
hyp_obj <- hypeR(chosen_genes, genesets_REACTOME, test = "hypergeometric", fdr=1, plotting=F,background = rownames(H1975Oct23))
p1 = hyp_dots(hyp_obj,size_by = "none",title = "cluster 2")
chosen_genes = split %>% dplyr::filter(cluster == 3) %>% rownames() #take relevant genes
hyp_obj <- hypeR(chosen_genes, genesets_REACTOME, test = "hypergeometric", fdr=1, plotting=F,background = rownames(H1975Oct23))
p2 = hyp_dots(hyp_obj,size_by = "none",title = "cluster 3")

wiki_p = (p1/p2)
print_tab(plt = wiki_p,title = "REACTOME")

REACTOME

NA

12 Distance plot

vsd <- vst(dds, blind=FALSE)
-- note: fitType='parametric', but the dispersion trend was not well captured by the
   function: y = a/x + b, and a local regression fit was automatically substituted.
   specify fitType='local' or 'mean' to avoid this message next time.
sampleDists <- dist(t(assay(vsd)))
library("RColorBrewer")
sampleDistMatrix <- as.matrix(sampleDists)
colnames(sampleDistMatrix) <- NULL
colors <- colorRampPalette( rev(brewer.pal(9, "Blues")) )(255)
pheatmap(sampleDistMatrix,
         clustering_distance_rows=sampleDists,
         clustering_distance_cols=sampleDists,
         col=colors)

LS0tCnRpdGxlOiAnYHIgcnN0dWRpb2FwaTo6Z2V0U291cmNlRWRpdG9yQ29udGV4dCgpJHBhdGggJT4lIGJhc2VuYW1lKCkgJT4lIGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLHJlcGxhY2VtZW50ID0gIiIpYCcgCmF1dGhvcjogIkF2aXNoYWkgV2l6ZWwiCmRhdGU6ICdgciBTeXMudGltZSgpYCcKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdG9jOiB5ZXMKICAgIHRvY19jb2xsYXBzZTogeWVzCiAgICB0b2NfZmxvYXQ6IAogICAgICBjb2xsYXBzZWQ6IEZBTFNFCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvY19kZXB0aDogMQotLS0KCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+Ci5tYWluLWNvbnRhaW5lciB7CiAgbWF4LXdpZHRoOiA4NSUgIWltcG9ydGFudDsKICBtYXJnaW46IGF1dG87Cn0KPC9zdHlsZT4KCiMgRnVuY3Rpb25zCgpgYGB7ciB3YXJuaW5nPUZBTFNFfQpgYGAKCiMgRGF0YQoKYGBge3J9CkhDQzgyN0p1bjIzID0gcmVhZC50YWJsZSgKICBmaWxlID0gIi4vRGF0YS9vc2lSb3hhX2J1bGsvSnVuMjMvZ2VuZV9mcGttLnhscyIsCiAgc2VwID0gIlx0IiwKICBoZWFkZXIgPSBUUlVFCikKcm93bmFtZXMoSENDODI3SnVuMjMpID0gbWFrZS51bmlxdWUoSENDODI3SnVuMjNbLCJnZW5lX25hbWUiLGRyb3A9VF0pICNzZXQgZ2VuZXMgbmFtZXMKSENDODI3SnVuMjMgPSBIQ0M4MjdKdW4yM1ssMjozMV0KbmFtZXMgKEhDQzgyN0p1bjIzKSA9IGdzdWIoeCA9IG5hbWVzKEhDQzgyN0p1bjIzKSxwYXR0ZXJuID0gIm9wIixyZXBsYWNlbWVudCA9ICJvc2lQZXJzaXN0b3JzIiklPiUgZ3N1YihwYXR0ZXJuID0gImNwIixyZXBsYWNlbWVudCA9ICJjb21ib1BlcnNpc3RvcnMiKSAKSENDODI3SnVuMjMgPSBIQ0M4MjdKdW4yM1ssMTY6bmNvbChIQ0M4MjdKdW4yMyldICN0YWtlIG9ubHkgSENDODI3CmBgYAoKCmBgYHtyfQojIGNyZWF0ZSBtZXRhZGF0YQpjZWxsLmxhYmVscyA9IG5hbWVzKEhDQzgyN0p1bjIzKQpjb25kaXRpb24gPSBzdHJfZXh0cmFjdChjZWxsLmxhYmVscywgIm9zaVBlcnNpc3RvcnN8Y29tYm9QZXJzaXN0b3JzfG9zaXxjdHJsfHJveGEiKQptZXRhZGF0YSA9IGRhdGEuZnJhbWUoY29uZGl0aW9uID0gY29uZGl0aW9uLCByb3cubmFtZXMgPSBjb2xuYW1lcyhIQ0M4MjdKdW4yMykpCmBgYAoKYGBge3J9CmxpYnJhcnkoREVTZXEyKQpkZHMgPC0gREVTZXFEYXRhU2V0RnJvbU1hdHJpeChjb3VudERhdGEgPSByb3VuZChIQ0M4MjdKdW4yMyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGEgPSBtZXRhZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVzaWduID0gfmNvbmRpdGlvbikKYGBgCiMgUENBCmBgYHtyfQpucm93KGRkcykKZGRzMSA8LSBkZHNbIHJvd1N1bXMoY291bnRzKGRkcykpID49IDMsIF0KbnJvdyhkZHMxKQpgYGAKCmBgYHtyfQp2c3QgPSB2c3QoZGRzMSwgYmxpbmQ9RkFMU0UpCmBgYAoKYGBge3J9CmxpYnJhcnkoImdnZm9ydGlmeSIpClBDQWRhdGEgPC0gcHJjb21wKHQoYXNzYXkodnN0KSkpCmF1dG9wbG90KFBDQWRhdGEsIGRhdGEgPSBtZXRhZGF0YSxjb2xvdXIgPSAiY29uZGl0aW9uIixsYWJlbCA9IEZBTFNFLCBtYWluPSJQQ0EiKSAjIFNob3cgZG90cwoKYGBgCiNERVNlcQpgYGB7cn0KZGRzIDwtIERFU2VxKGRkcykKZGRzX0hDQzgyN19KVU4yMyA9IGRkcwpgYGAKCmBgYHtyfQpkZHMgPSBkZHNfSENDODI3X0pVTjIzCmBgYAoKIyBUb3AgdmFyaWFibGUgZ2VuZXMgaGVhdG1hcApgYGB7ciBmaWcuaGVpZ2h0PTd9CmdlbmVzIDwtIGhlYWQob3JkZXIocm93VmFycyhhc3NheShkZHMpKSwgZGVjcmVhc2luZyA9IFRSVUUpLCAxMDAwKQoKbWF0IDwtIEhDQzgyN0p1bjIzWyBnZW5lcywgXQptYXQgPC0gdChzY2FsZSh0KG1hdCkpKQphbm5vIDwtIGFzLmRhdGEuZnJhbWUobWF0KQoKbGlicmFyeShDb21wbGV4SGVhdG1hcCkgCmxpYnJhcnkoZ2dwbG90MikgCkhlYXRtYXAobWF0LCBjbHVzdGVyX3Jvd3MgPSBULCBjbHVzdGVyX2NvbHVtbnMgPSBGLCBjb2x1bW5fbGFiZWxzID0gY29sbmFtZXMoYW5ubyksIG5hbWUgPSAiZnBrbSBaLXNjb3JlIixyb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gMCkpIApgYGAKCiMgREVHIEZDIHsudGFic2V0fQpgYGB7cn0KY3BWU29wIDwtIHJlc3VsdHMoZGRzLGNvbnRyYXN0ID0gYygiY29uZGl0aW9uIiwiY29tYm9QZXJzaXN0b3JzIiwib3NpUGVyc2lzdG9ycyIpKSAgJT4lIGFzLmRhdGEuZnJhbWUoKQpyb3hhVlNjdHJsIDwtIHJlc3VsdHMoZGRzLGNvbnRyYXN0ID0gYygiY29uZGl0aW9uIiwicm94YSIsImN0cmwiKSkgICU+JSBhcy5kYXRhLmZyYW1lKCkKZGlmZl9nZW5lcyA9IGRhdGEuZnJhbWUocm93Lm5hbWVzID0gcm93bmFtZXMoY3BWU29wKSwgY3BWU29wX0ZDID0gY3BWU29wJGxvZzJGb2xkQ2hhbmdlLHJveGFWU2N0cmxfRkMgPSByb3hhVlNjdHJsJGxvZzJGb2xkQ2hhbmdlLCAgY3BWU29wX3BhZGogPSBjcFZTb3AkcGFkaikKYGBgCgoKYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTMsIHJlc3VsdHM9J2FzaXMnfQpjcFZTb3AgPSBjcFZTb3Bbb3JkZXIoY3BWU29wJGxvZzJGb2xkQ2hhbmdlLCBjcFZTb3AkcGFkaixkZWNyZWFzaW5nID0gVCksXSAjb3JkZXIgYnkgRkMsIHRpZXMgYnQgcGFkagpyYW5rZWRfdmVjID0gY3BWU29wWywibG9nMkZvbGRDaGFuZ2UiXSU+JSBzZXROYW1lcyhyb3duYW1lcyhjcFZTb3ApKSAlPiUgbmEub21pdCgpICMgbWFrZSBuYW1lZCB2ZWN0b3IKCmh5cF9vYmogPC0gaHlwZVJfZmdzZWEocmFua2VkX3ZlYywgZ2VuZXNldHMsIHVwX29ubHkgPSBGKQpwbHQgPSBoeXBfZG90cyhoeXBfb2JqLG1lcmdlID0gRikKcGx0MSA9IHBsdCR1cCsgYWVzKHNpemU9bmVzKStnZ3RpdGxlKCJ1cCBpbiBjb21ib1BlcnNpc3RvciIpCnBsdDIgPSBwbHQkZG4rIGFlcyhzaXplPWFicyhuZXMpKStnZ3RpdGxlKCJ1cCBpbiBvc2lQZXJzaXN0b3JzIikKcHJpbnRfdGFiKHBsdDErcGx0Mix0aXRsZSA9ICJjcFZTb3AiKQoKCnJveGFWU2N0cmwgPSByb3hhVlNjdHJsW29yZGVyKHJveGFWU2N0cmwkbG9nMkZvbGRDaGFuZ2UsIHJveGFWU2N0cmwkcGFkaixkZWNyZWFzaW5nID0gVCksXSAjb3JkZXIgYnkgRkMsIHRpZXMgYnQgcGFkagpyYW5rZWRfdmVjID0gcm94YVZTY3RybFssImxvZzJGb2xkQ2hhbmdlIl0lPiUgc2V0TmFtZXMocm93bmFtZXMocm94YVZTY3RybCkpICU+JSBuYS5vbWl0KCkgICMgbWFrZSBuYW1lZCB2ZWN0b3IKCmh5cF9vYmogPC0gaHlwZVJfZmdzZWEocmFua2VkX3ZlYywgZ2VuZXNldHMsIHVwX29ubHkgPSBGKQpwbHQgPSBoeXBfZG90cyhoeXBfb2JqLG1lcmdlID0gRikKcGx0MSA9IHBsdCR1cCsgYWVzKHNpemU9bmVzKStnZ3RpdGxlKCJ1cCBpbiByb3hhIikKcGx0MiA9IHBsdCRkbisgYWVzKHNpemU9YWJzKG5lcykpK2dndGl0bGUoInVwIGluIGN0cmwiKQpwcmludF90YWIocGx0MStwbHQyLHRpdGxlID0gInJveGFWU2N0cmwiKQpgYGAKCgojIERFRyBzaHJpbmtlZCBGQyB7LnRhYnNldH0KYGBge3J9CmRkcyRjb25kaXRpb24gPSByZWxldmVsKGRkcyRjb25kaXRpb24sIHJlZiA9ICJvc2lQZXJzaXN0b3JzIikKZGRzIDwtIG5iaW5vbVdhbGRUZXN0KGRkcykKY3BWU29wIDwtIGxmY1NocmluayhkZHMsY29lZiA9ICJjb25kaXRpb25fY29tYm9QZXJzaXN0b3JzX3ZzX29zaVBlcnNpc3RvcnMiKSAgJT4lIGFzLmRhdGEuZnJhbWUoKQoKZGRzJGNvbmRpdGlvbiA9IHJlbGV2ZWwoZGRzJGNvbmRpdGlvbiwgcmVmID0gImN0cmwiKQpkZHMgPC0gbmJpbm9tV2FsZFRlc3QoZGRzKQpyb3hhVlNjdHJsIDwtIGxmY1NocmluayhkZHMsY29lZiAgPSAiY29uZGl0aW9uX3JveGFfdnNfY3RybCIpICAlPiUgYXMuZGF0YS5mcmFtZSgpCgoKZGlmZl9nZW5lcyA9IGRhdGEuZnJhbWUocm93Lm5hbWVzID0gcm93bmFtZXMoY3BWU29wKSwgY3BWU29wX0ZDID0gY3BWU29wJGxvZzJGb2xkQ2hhbmdlLHJveGFWU2N0cmxfRkMgPSByb3hhVlNjdHJsJGxvZzJGb2xkQ2hhbmdlLCAgY3BWU29wX3BhZGogPSBjcFZTb3AkcGFkaikKCmBgYAoKCmBgYHtyIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEzLHJlc3VsdHM9J2FzaXMnfQpyYW5rZWRfdmVjID0gZGlmZl9nZW5lc1ssIDFdICU+JSBzZXROYW1lcyhyb3duYW1lcyhkaWZmX2dlbmVzKSkgJT4lIHNvcnQoZGVjcmVhc2luZyA9IFRSVUUpCmh5cF9vYmogPC0gaHlwZVJfZmdzZWEocmFua2VkX3ZlYywgZ2VuZXNldHMsIHVwX29ubHkgPSBGKQpwbHQgPSBoeXBfZG90cyhoeXBfb2JqLG1lcmdlID0gRikKcGx0MSA9IHBsdCR1cCsgYWVzKHNpemU9bmVzKStnZ3RpdGxlKCJ1cCBpbiBjb21ib1BlcnNpc3RvciIpICsgdGhlbWUoICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSkKcGx0MiA9IHBsdCRkbisgYWVzKHNpemU9YWJzKG5lcykpK2dndGl0bGUoInVwIGluIG9zaVBlcnNpc3RvcnMiKSArIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemU9MTApKQpwcmludF90YWIocGx0MStwbHQyLHRpdGxlID0gImNwVlNvcCIpCgpyYW5rZWRfdmVjID0gZGlmZl9nZW5lc1ssIDJdICU+JSBzZXROYW1lcyhyb3duYW1lcyhkaWZmX2dlbmVzKSkgJT4lIHNvcnQoZGVjcmVhc2luZyA9IFRSVUUpCmh5cF9vYmogPC0gaHlwZVJfZmdzZWEocmFua2VkX3ZlYywgZ2VuZXNldHMsIHVwX29ubHkgPSBGKQpwbHQgPSBoeXBfZG90cyhoeXBfb2JqLG1lcmdlID0gRikKcGx0MSA9IHBsdCR1cCsgYWVzKHNpemU9bmVzKStnZ3RpdGxlKCJ1cCBpbiByb3hhIikKcGx0MiA9IHBsdCRkbisgYWVzKHNpemU9YWJzKG5lcykpK2dndGl0bGUoInVwIGluIGN0cmwiKQpwcmludF90YWIocGx0MStwbHQyLHRpdGxlID0gImNwVlNvcCIpCgpgYGAKCiMgREVHIGluIGNvbWJvVlNvc2kgYnV0IG5vdCBpbiByb3hhVlNjdHJsIHsudGFic2V0fQoKYGBge3J9CmNwVlNvcCA8LSByZXN1bHRzKGRkcyxjb250cmFzdCA9IGMoImNvbmRpdGlvbiIsImNvbWJvUGVyc2lzdG9ycyIsIm9zaVBlcnNpc3RvcnMiKSkgICU+JSBhcy5kYXRhLmZyYW1lKCkKcm94YVZTY3RybCA8LSByZXN1bHRzKGRkcyxjb250cmFzdCA9IGMoImNvbmRpdGlvbiIsInJveGEiLCJjdHJsIikpICAlPiUgYXMuZGF0YS5mcmFtZSgpCmRpZmZfZ2VuZXMgPSBkYXRhLmZyYW1lKHJvdy5uYW1lcyA9IHJvd25hbWVzKGNwVlNvcCksIGNwVlNvcF9GQyA9IDIqKmNwVlNvcCRsb2cyRm9sZENoYW5nZSxyb3hhVlNjdHJsX0ZDID0gMioqcm94YVZTY3RybCRsb2cyRm9sZENoYW5nZSwgIGNwVlNvcF9wYWRqID0gY3BWU29wJHBhZGopCmBgYAoKYGBge3IgcmVzdWx0cz0nYXNpcyd9CnVwX2dlbmVzX2RmID0gIGRpZmZfZ2VuZXMgJT4lIGZpbHRlcihjcFZTb3BfRkMgPiAyICYgcm94YVZTY3RybF9GQzwxLjIgJiBjcFZTb3BfcGFkajwwLjA1KSAKZG93bl9nZW5lc19kZiA9IGRpZmZfZ2VuZXMgJT4lIGZpbHRlcihjcFZTb3BfRkMgPCAwLjUgJiByb3hhVlNjdHJsX0ZDPjAuOCAmIGNwVlNvcF9wYWRqPDAuMDUpCnVwX2dlbmVzID0gZGlmZl9nZW5lcyAlPiUgZmlsdGVyKGNwVlNvcF9GQyA+IDIgJiByb3hhVlNjdHJsX0ZDPDEuMiAmIGNwVlNvcF9wYWRqPDAuMDUpICU+JSByb3duYW1lcygpCmRvd25fZ2VuZXMgPSBkaWZmX2dlbmVzICU+JSBmaWx0ZXIoY3BWU29wX0ZDIDwgMC41ICYgcm94YVZTY3RybF9GQz4wLjggJiBjcFZTb3BfcGFkajwwLjEpJT4lIHJvd25hbWVzKCkKCnByaW50X3RhYih1cF9nZW5lc19kZix0aXRsZSA9ICJ1cCIpCnByaW50X3RhYihkb3duX2dlbmVzX2RmLHRpdGxlID0gImRvd24iKQoKCmBgYAojIHstfQoKYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTMscmVzdWx0cz0nYXNpcyd9Cmh5cF9vYmogPC0gaHlwZVIodXBfZ2VuZXMsIGdlbmVzZXRzLCB0ZXN0ID0gImh5cGVyZ2VvbWV0cmljIiwgZmRyPTEsIHBsb3R0aW5nPUYsYmFja2dyb3VuZCA9IHJvd25hbWVzKEgxOTc1T2N0MjMpKQpwbHQxID0gaHlwX2RvdHMoaHlwX29iaix0aXRsZSA9ICJ1cCBpbiBjb21ib1ZTb3NpIGJ1dCBub3QgaW4gcm94YVZTY3RybCIpCiAKCmh5cF9vYmogPC0gaHlwZVIoZG93bl9nZW5lcywgZ2VuZXNldHMsIHRlc3QgPSAiaHlwZXJnZW9tZXRyaWMiLCBmZHI9MSwgcGxvdHRpbmc9RixiYWNrZ3JvdW5kID0gcm93bmFtZXMoSDE5NzVPY3QyMykpCnBsdDIgPSBoeXBfZG90cyhoeXBfb2JqLHRpdGxlID0gImRvd24gaW4gY29tYm9WU29zaSBidXQgbm90IGluIHJveGFWU2N0cmwiKQoKcGx0MSArIHBsdDIKYGBgCmBgYHtyIHJlc3VsdHM9J2FzaXMnfQpwcmludF90YWIoZGF0YS5mcmFtZSh1cF9nZW5lc1t1cF9nZW5lcyAlaW4lIGdlbmVzZXRzJEhBTExNQVJLX0dMWUNPTFlTSVNdKSx0aXRsZSA9ICJ1cCBnZW5lcyBpbiBHTFlDT0xZU0lTIikKYGBgCiMgSW50ZXJzZWN0aW9uIEhDQzgyNyBhbmQgSDE5NzUgREVHCmBgYHtyfQpIQ0M4MjdfdXBfZ2VuZXMgPSB1cF9nZW5lcwpIQ0M4MjdfZG93bl9nZW5lcyA9IGRvd25fZ2VuZXMKCmBgYApgYGB7cn0KaW50ZXJzZWN0KEhDQzgyN191cF9nZW5lcyxIMTk3NV91cF9nZW5lcykKaW50ZXJzZWN0KEhDQzgyN19kb3duX2dlbmVzLEgxOTc1X2Rvd25fZ2VuZXMpCgpgYGAKCgojIEV4cHJlc3Npb24gaGVhdG1hcCB7LnRhYnNldH0KCmBgYHtyIGZpZy5oZWlnaHQ9NiwgcmVzdWx0cz0nYXNpcyd9CiMgc2VsZWN0IHRoZSA1MCBtb3N0IGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyAKIyBnZW5lcyA8LSBjKCJEVVNQNiIpCiMgbWF0IDwtIEhDQzgyN0p1bjIzWyBnZW5lcywgXQojIG1hdCA8LSB0KHNjYWxlKHQobWF0KSkpCiMgYW5ubyA8LSBhcy5kYXRhLmZyYW1lKG1hdCkKIyAKIyBsaWJyYXJ5KENvbXBsZXhIZWF0bWFwKSAKIyBsaWJyYXJ5KGdncGxvdDIpIAojIHAgPSBIZWF0bWFwKG1hdCwgY2x1c3Rlcl9yb3dzID0gRiwgY2x1c3Rlcl9jb2x1bW5zID0gRiwgY29sdW1uX2xhYmVscyA9IGNvbG5hbWVzKGFubm8pLCBuYW1lID0gImZwa20gWi1zY29yZSIpIAojIHByaW50X3RhYihwbHQgPSBwLHRpdGxlID0gIm1hcmtlcnMiKQoKZ2VuZXMgPC0gaGlmX3RhcmdldHMKbWF0IDwtIEhDQzgyN0p1bjIzW2dlbmVzLCBdICU+JSBmaWx0ZXIocm93U3VtcyhhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykpKSE9MCkKbWF0IDwtIHQoc2NhbGUodChtYXQpKSkKYW5ubyA8LSBhcy5kYXRhLmZyYW1lKG1hdCkKCiAKcCA9IEhlYXRtYXAobWF0LCBjbHVzdGVyX3Jvd3MgPSBULCBjbHVzdGVyX2NvbHVtbnMgPSBGLCBjb2x1bW5fbGFiZWxzID0gY29sbmFtZXMoYW5ubyksIG5hbWUgPSAiZnBrbSBaLXNjb3JlIixjb2x1bW5fdGl0bGUgPSAiSElGIHRhcmdldHMiLHJvd19uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSA4KSkKCnByaW50X3RhYihwbHQgPSBwLHRpdGxlID0gIkhJRiB0YXJnZXRzIikKCmdlbmVzIDwtIGdlbmVzZXRzJEhBTExNQVJLX0cyTV9DSEVDS1BPSU5UCm1hdCA8LSBIQ0M4MjdKdW4yM1tnZW5lcywgXSAlPiUgZmlsdGVyKHJvd1N1bXMoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpKSkhPTApCm1hdCA8LSB0KHNjYWxlKHQobWF0KSkpCmFubm8gPC0gYXMuZGF0YS5mcmFtZShtYXQpCgogCnAgPSBIZWF0bWFwKG1hdCwgY2x1c3Rlcl9yb3dzID0gVCwgY2x1c3Rlcl9jb2x1bW5zID0gRiwgY29sdW1uX2xhYmVscyA9IGNvbG5hbWVzKGFubm8pLCBuYW1lID0gImZwa20gWi1zY29yZSIsY29sdW1uX3RpdGxlID0gIkhBTExNQVJLX0cyTV9DSEVDS1BPSU5UIixyb3dfbmFtZXNfZ3AgPWdwYXIoZm9udHNpemUgPSAwKSkgCgpwcmludF90YWIocGx0ID0gcCx0aXRsZSA9ICJIQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVCIpCgpnZW5lcyA8LSBnZW5lc2V0cyRIQUxMTUFSS19IWVBPWElBCm1hdCA8LSBIQ0M4MjdKdW4yM1tnZW5lcywgXSAlPiUgZmlsdGVyKHJvd1N1bXMoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpKSkhPTApCm1hdCA8LSB0KHNjYWxlKHQobWF0KSkpCmFubm8gPC0gYXMuZGF0YS5mcmFtZShtYXQpCgogCnAgPSBIZWF0bWFwKG1hdCwgY2x1c3Rlcl9yb3dzID0gVCwgY2x1c3Rlcl9jb2x1bW5zID0gRiwgY29sdW1uX2xhYmVscyA9IGNvbG5hbWVzKGFubm8pLCBuYW1lID0gImZwa20gWi1zY29yZSIsY29sdW1uX3RpdGxlID0gIkhBTExNQVJLX0hZUE9YSUEiLHJvd19uYW1lc19ncCA9Z3Bhcihmb250c2l6ZSA9IDApKSAKCnByaW50X3RhYihwbHQgPSBwLHRpdGxlID0gIkhBTExNQVJLX0hZUE9YSUEiKQoKYGBgCgojIEcyTSBoZWF0bWFwCmBgYHtyIGZpZy5oZWlnaHQ9NiwgcmVzdWx0cz0nYXNpcyd9CmdlbmVzIDwtIGdlbmVzZXRzJEhBTExNQVJLX0cyTV9DSEVDS1BPSU5UCm1hdCA8LSBIQ0M4MjdKdW4yM1tnZW5lcywgXSAlPiUgZmlsdGVyKHJvd1N1bXMoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpKSkhPTApCm1hdCA8LSB0KHNjYWxlKHQobWF0KSkpCmFubm8gPC0gYXMuZGF0YS5mcmFtZShtYXQpCgpzcGxpdCA9IGRhdGEuZnJhbWUoIGNsdXN0ZXIgPSBjdXRyZWUoaGNsdXN0KGRpc3QobWF0KSksIGsgPSAzKSkKaGEgPSByb3dBbm5vdGF0aW9uKGNsdXN0ZXIgPSBhcy5jaGFyYWN0ZXIoc3BsaXQkY2x1c3RlciksY29sID0gbGlzdChjbHVzdGVyID0gc3RydWN0dXJlKHJhaW5ib3cobiA9IDMpLCBuYW1lcz11bmlxdWUoc3BsaXQkY2x1c3RlcikpKSkKcCA9IEhlYXRtYXAobWF0LCBjbHVzdGVyX3Jvd3MgPSBULCBjbHVzdGVyX2NvbHVtbnMgPSBGLCBjb2x1bW5fbGFiZWxzID0gY29sbmFtZXMoYW5ubyksIG5hbWUgPSAiZnBrbSBaLXNjb3JlIixjb2x1bW5fdGl0bGUgPSAiSEFMTE1BUktfRzJNX0NIRUNLUE9JTlQiLHJvd19uYW1lc19ncCA9Z3Bhcihmb250c2l6ZSA9IDApLHJpZ2h0X2Fubm90YXRpb24gPSBoYSkKCnByaW50X3RhYihwbHQgPSBwLHRpdGxlID0gIkhBTExNQVJLX0cyTV9DSEVDS1BPSU5UIikKCmBgYAojIEVucmljaG1lbnQgYW5hbHlzaXMgey50YWJzZXR9CmBgYHtyIGZpZy5oZWlnaHQ9NyxyZXN1bHRzPSdhc2lzJ30KY2hvc2VuX2dlbmVzID0gc3BsaXQgJT4lIGRwbHlyOjpmaWx0ZXIoY2x1c3RlciA9PSAyKSAlPiUgcm93bmFtZXMoKSAjdGFrZSByZWxldmFudCBnZW5lcwpoeXBfb2JqIDwtIGh5cGVSKGNob3Nlbl9nZW5lcywgZ2VuZXNldHNfd2lraXBhdGh3YXlzLCB0ZXN0ID0gImh5cGVyZ2VvbWV0cmljIiwgZmRyPTEsIHBsb3R0aW5nPUYsYmFja2dyb3VuZCA9IHJvd25hbWVzKEgxOTc1T2N0MjMpKQpwMSA9IGh5cF9kb3RzKGh5cF9vYmosc2l6ZV9ieSA9ICJub25lIix0aXRsZSA9ICJjbHVzdGVyIDIiKQpjaG9zZW5fZ2VuZXMgPSBzcGxpdCAlPiUgZHBseXI6OmZpbHRlcihjbHVzdGVyID09IDMpICU+JSByb3duYW1lcygpICN0YWtlIHJlbGV2YW50IGdlbmVzCmh5cF9vYmogPC0gaHlwZVIoY2hvc2VuX2dlbmVzLCBnZW5lc2V0c193aWtpcGF0aHdheXMsIHRlc3QgPSAiaHlwZXJnZW9tZXRyaWMiLCBmZHI9MSwgcGxvdHRpbmc9RixiYWNrZ3JvdW5kID0gcm93bmFtZXMoSDE5NzVPY3QyMykpCnAyID0gaHlwX2RvdHMoaHlwX29iaixzaXplX2J5ID0gIm5vbmUiLHRpdGxlID0gImNsdXN0ZXIgMyIpCgp3aWtpX3AgPSAocDEvcDIpCnByaW50X3RhYihwbHQgPSB3aWtpX3AsdGl0bGUgPSAid2lraXBhdGh3YXlzIikKCgpjaG9zZW5fZ2VuZXMgPSBzcGxpdCAlPiUgZHBseXI6OmZpbHRlcihjbHVzdGVyID09IDIpICU+JSByb3duYW1lcygpICN0YWtlIHJlbGV2YW50IGdlbmVzCmh5cF9vYmogPC0gaHlwZVIoY2hvc2VuX2dlbmVzLCBnZW5lc2V0c19iaW9jYXJ0YSwgdGVzdCA9ICJoeXBlcmdlb21ldHJpYyIsIGZkcj0xLCBwbG90dGluZz1GLGJhY2tncm91bmQgPSByb3duYW1lcyhIMTk3NU9jdDIzKSkKcDEgPSBoeXBfZG90cyhoeXBfb2JqLHNpemVfYnkgPSAibm9uZSIsdGl0bGUgPSAiY2x1c3RlciAyIikKY2hvc2VuX2dlbmVzID0gc3BsaXQgJT4lIGRwbHlyOjpmaWx0ZXIoY2x1c3RlciA9PSAzKSAlPiUgcm93bmFtZXMoKSAjdGFrZSByZWxldmFudCBnZW5lcwpoeXBfb2JqIDwtIGh5cGVSKGNob3Nlbl9nZW5lcywgZ2VuZXNldHNfYmlvY2FydGEsIHRlc3QgPSAiaHlwZXJnZW9tZXRyaWMiLCBmZHI9MSwgcGxvdHRpbmc9RixiYWNrZ3JvdW5kID0gcm93bmFtZXMoSDE5NzVPY3QyMykpCnAyID0gaHlwX2RvdHMoaHlwX29iaixzaXplX2J5ID0gIm5vbmUiLHRpdGxlID0gImNsdXN0ZXIgMyIpCgp3aWtpX3AgPSAocDEvcDIpCnByaW50X3RhYihwbHQgPSB3aWtpX3AsdGl0bGUgPSAiYmlvY2FydGEiKQoKY2hvc2VuX2dlbmVzID0gc3BsaXQgJT4lIGRwbHlyOjpmaWx0ZXIoY2x1c3RlciA9PSAyKSAlPiUgcm93bmFtZXMoKSAjdGFrZSByZWxldmFudCBnZW5lcwpoeXBfb2JqIDwtIGh5cGVSKGNob3Nlbl9nZW5lcywgZ2VuZXNldHNfcGlkLCB0ZXN0ID0gImh5cGVyZ2VvbWV0cmljIiwgZmRyPTEsIHBsb3R0aW5nPUYsYmFja2dyb3VuZCA9IHJvd25hbWVzKEgxOTc1T2N0MjMpKQpwMSA9IGh5cF9kb3RzKGh5cF9vYmosc2l6ZV9ieSA9ICJub25lIix0aXRsZSA9ICJjbHVzdGVyIDIiKQpjaG9zZW5fZ2VuZXMgPSBzcGxpdCAlPiUgZHBseXI6OmZpbHRlcihjbHVzdGVyID09IDMpICU+JSByb3duYW1lcygpICN0YWtlIHJlbGV2YW50IGdlbmVzCmh5cF9vYmogPC0gaHlwZVIoY2hvc2VuX2dlbmVzLCBnZW5lc2V0c19waWQsIHRlc3QgPSAiaHlwZXJnZW9tZXRyaWMiLCBmZHI9MSwgcGxvdHRpbmc9RixiYWNrZ3JvdW5kID0gcm93bmFtZXMoSDE5NzVPY3QyMykpCnAyID0gaHlwX2RvdHMoaHlwX29iaixzaXplX2J5ID0gIm5vbmUiLHRpdGxlID0gImNsdXN0ZXIgMyIpCgp3aWtpX3AgPSAocDEvcDIpCnByaW50X3RhYihwbHQgPSB3aWtpX3AsdGl0bGUgPSAicGlkIikKCmNob3Nlbl9nZW5lcyA9IHNwbGl0ICU+JSBkcGx5cjo6ZmlsdGVyKGNsdXN0ZXIgPT0gMikgJT4lIHJvd25hbWVzKCkgI3Rha2UgcmVsZXZhbnQgZ2VuZXMKaHlwX29iaiA8LSBoeXBlUihjaG9zZW5fZ2VuZXMsIGdlbmVzZXRzX1JFQUNUT01FLCB0ZXN0ID0gImh5cGVyZ2VvbWV0cmljIiwgZmRyPTEsIHBsb3R0aW5nPUYsYmFja2dyb3VuZCA9IHJvd25hbWVzKEgxOTc1T2N0MjMpKQpwMSA9IGh5cF9kb3RzKGh5cF9vYmosc2l6ZV9ieSA9ICJub25lIix0aXRsZSA9ICJjbHVzdGVyIDIiKQpjaG9zZW5fZ2VuZXMgPSBzcGxpdCAlPiUgZHBseXI6OmZpbHRlcihjbHVzdGVyID09IDMpICU+JSByb3duYW1lcygpICN0YWtlIHJlbGV2YW50IGdlbmVzCmh5cF9vYmogPC0gaHlwZVIoY2hvc2VuX2dlbmVzLCBnZW5lc2V0c19SRUFDVE9NRSwgdGVzdCA9ICJoeXBlcmdlb21ldHJpYyIsIGZkcj0xLCBwbG90dGluZz1GLGJhY2tncm91bmQgPSByb3duYW1lcyhIMTk3NU9jdDIzKSkKcDIgPSBoeXBfZG90cyhoeXBfb2JqLHNpemVfYnkgPSAibm9uZSIsdGl0bGUgPSAiY2x1c3RlciAzIikKCndpa2lfcCA9IChwMS9wMikKcHJpbnRfdGFiKHBsdCA9IHdpa2lfcCx0aXRsZSA9ICJSRUFDVE9NRSIpCgpgYGAKIyBEaXN0YW5jZSBwbG90CgpgYGB7cn0KdnNkIDwtIHZzdChkZHMsIGJsaW5kPUZBTFNFKQpzYW1wbGVEaXN0cyA8LSBkaXN0KHQoYXNzYXkodnNkKSkpCmxpYnJhcnkoIlJDb2xvckJyZXdlciIpCnNhbXBsZURpc3RNYXRyaXggPC0gYXMubWF0cml4KHNhbXBsZURpc3RzKQpjb2xuYW1lcyhzYW1wbGVEaXN0TWF0cml4KSA8LSBOVUxMCmNvbG9ycyA8LSBjb2xvclJhbXBQYWxldHRlKCByZXYoYnJld2VyLnBhbCg5LCAiQmx1ZXMiKSkgKSgyNTUpCnBoZWF0bWFwKHNhbXBsZURpc3RNYXRyaXgsCiAgICAgICAgIGNsdXN0ZXJpbmdfZGlzdGFuY2Vfcm93cz1zYW1wbGVEaXN0cywKICAgICAgICAgY2x1c3RlcmluZ19kaXN0YW5jZV9jb2xzPXNhbXBsZURpc3RzLAogICAgICAgICBjb2w9Y29sb3JzKQpgYGAKPHNjcmlwdCBzcmM9Imh0dHBzOi8vaHlwb3RoZXMuaXMvZW1iZWQuanMiIGFzeW5jPjwvc2NyaXB0PgoK