1 Functions

2 Data

genesets <- msigdb_download("Homo sapiens",category="H") %>% append( msigdb_download("Homo sapiens",category="C2",subcategory = "CP:KEGG"))
xeno_bulk = read.table(
  file = "./Data/osiRoxa_bulk/Oct23/gene_fpkm.xls",
  sep = "\t",
  header = TRUE
)
rownames(xeno_bulk) = make.unique(xeno_bulk[,"gene_name",drop=T])
xeno_bulk = xeno_bulk[,26:37]
cell.labels = names(xeno_bulk)
condition = str_extract(cell.labels, "osi|combo|ctrl|roxa")
metadata = data.frame(condition = condition, row.names = colnames(xeno_bulk))
library(DESeq2)
dds <- DESeqDataSetFromMatrix(countData = round(xeno_bulk),
                              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] 32780
dds1 <- dds[ rowSums(counts(dds)) >= 3, ]
nrow(dds1)
[1] 9259
vst = vst(dds, blind=FALSE)
library("ggfortify")
PCAdata <- prcomp(t(assay(vst)))
autoplot(PCAdata, data = metadata,colour = "condition",label = FALSE, main="PCA") # Show dots

4 DESeq

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

5 Top variable genes heatmap

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

mat <- xeno_bulk[ 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)) 

6 DEG

cpVSop <- results(dds,contrast = c("condition","combo","osi"))  %>% 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)
library(DT)
combo_vs_ctrl = results(dds,contrast = c("condition","combo","ctrl"))  %>% as.data.frame()
roxa_vs_ctrl = results(dds,contrast = c("condition","roxa","ctrl"))  %>% as.data.frame()
osi_vs_ctrl = results(dds,contrast = c("condition","osi","ctrl"))  %>% as.data.frame()

combo_vs_roxa = results(dds,contrast = c("condition","combo","roxa"))  %>% as.data.frame()
osi_vs_roxa = results(dds,contrast = c("condition","osi","roxa"))  %>% as.data.frame()
combo_vs_osi <- results(dds,contrast = c("condition","combo","osi"))  %>% as.data.frame()

dt1 = datatable(roxa_vs_ctrl %>% filter(padj <0.05) ,caption = "significant roxa VS ctrl")
dt2= datatable(combo_vs_ctrl %>% filter(padj <0.05),caption = "significant combo vs ctrl")
dt3 = datatable(osi_vs_ctrl %>% filter(padj <0.05),caption = "significant osi_vs_ctrl")
dt4 =datatable(combo_vs_roxa %>% filter(padj <0.05),caption = "significant combo_vs_roxa")
dt5 =datatable(osi_vs_roxa %>% filter(padj <0.05),caption = "significant osi_vs_roxa")
dt6 =datatable(combo_vs_osi %>% filter(padj <0.05),caption = "significant combo VS osi")
print_tab(plt = dt1,title = "significant roxa VS ctrl")

significant roxa VS ctrl

print_tab(plt = dt2,title = "significant combo vs ctrl")

significant combo vs ctrl

print_tab(plt = dt3,title = "significant osi VS ctrl")

significant osi VS ctrl

print_tab(plt = dt4,title = "significant combo VS roxa")

significant combo VS roxa

print_tab(plt = dt5,title = "significant osi VS roxa")

significant osi VS roxa

print_tab(plt = dt6,title = "significant combo VS osi")

significant combo VS osi

roxa_vs_ctrl["C4orf3",]

7 GSEA

plot_hyper <- function(genes_df,ident.1,ident.2) {
  genes_df = cpVSop[order(genes_df$log2FoldChange, genes_df$padj, decreasing = T), ] #order by FC, ties bt padj
  ranked_vec = genes_df[, "log2FoldChange"] %>% setNames(rownames(genes_df)) %>% na.omit() # make named vector
  
  hyp_obj <- hypeR_fgsea(ranked_vec, genesets, up_only = F)
  plt = hyp_dots(hyp_obj, merge = F)
  plt1 = plt$up + aes(size = nes) + ggtitle(paste("up in" ,ident.1))
  plt2 = plt$dn + aes(size = abs(nes)) + ggtitle(paste("up in" ,ident.2))
 return(plt1+plt2)
}

plot_hyper(combo_vs_ctrl,ident.1 = "combo",ident.2 = "ctrl") %>%  print_tab(title = "combo VS ctrl")

combo VS ctrl

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

plot_hyper(osi_vs_ctrl,ident.1 = "osi",ident.2 = "ctrl")%>%  print_tab(title = "osi VS ctrl")

osi VS ctrl

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

plot_hyper(combo_vs_roxa,ident.1 = "combo",ident.2 = "roxa") %>%  print_tab(title = "combo VS roxa")

combo VS roxa

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

plot_hyper(osi_vs_roxa,ident.1 = "osi",ident.2 = "roxa") %>%  print_tab(title = "osi VS roxa")

osi VS roxa

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

NA

HALLMARK_HYPOXIA genes in combo_vs_ctrl_genes

genesets$HALLMARK_HYPOXIA[genesets$HALLMARK_HYPOXIA %in% combo_vs_ctrl_genes] 
[1] "BGN"    "FOSL2"  "GPC1"   "KLHL24" "NDST1"  "S100A4"

8 DEG shrinked FC

dds$condition = relevel(dds$condition, ref = "osi")
dds <- nbinomWaldTest(dds)
cpVSop <- lfcShrink(dds,coef = "condition_combo_vs_osi")  %>% 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)
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")

ranked_vec = diff_genes[, 2] %>% setNames(rownames(diff_genes)) %>% sort(decreasing = TRUE)
hyp_obj <- hypeR_fgsea(ranked_vec, genesets, up_only = F)
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")

9 DEG in comboVSosi but not in roxaVSctrl

cpVSop <- results(dds,contrast = c("condition","combo","osi"))  %>% 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")
print_tab(down_genes_df,title = "down")
cpVSop <- results(dds,contrast = c("condition","roxa","osi"))  %>% as.data.frame() %>% filter(padj<0.05)

10 Expression heatmap

# select the 50 most differentially expressed genes 
genes <- c("DUSP6")
mat <- xeno_bulk[ genes, ]
mat <- t(scale(t(mat)))
anno <- as.data.frame(mat)

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


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

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

vsd <- vst(dds, blind=FALSE)
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)

LS0tCnRpdGxlOiAnYHIgcnN0dWRpb2FwaTo6Z2V0U291cmNlRWRpdG9yQ29udGV4dCgpJHBhdGggJT4lIGJhc2VuYW1lKCkgJT4lIGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLHJlcGxhY2VtZW50ID0gIiIpYCcgCmF1dGhvcjogIkF2aXNoYWkgV2l6ZWwiCmRhdGU6ICdgciBTeXMudGltZSgpYCcKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdG9jOiB5ZXMKICAgIHRvY19jb2xsYXBzZTogeWVzCiAgICB0b2NfZmxvYXQ6IAogICAgICBjb2xsYXBzZWQ6IEZBTFNFCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvY19kZXB0aDogMQotLS0KCgoKIyBGdW5jdGlvbnMKCmBgYHtyIHdhcm5pbmc9RkFMU0V9CmBgYAoKIyBEYXRhCgpgYGB7cn0KZ2VuZXNldHMgPC0gbXNpZ2RiX2Rvd25sb2FkKCJIb21vIHNhcGllbnMiLGNhdGVnb3J5PSJIIikgJT4lIGFwcGVuZCggbXNpZ2RiX2Rvd25sb2FkKCJIb21vIHNhcGllbnMiLGNhdGVnb3J5PSJDMiIsc3ViY2F0ZWdvcnkgPSAiQ1A6S0VHRyIpKQp4ZW5vX2J1bGsgPSByZWFkLnRhYmxlKAogIGZpbGUgPSAiLi9EYXRhL29zaVJveGFfYnVsay9PY3QyMy9nZW5lX2Zwa20ueGxzIiwKICBzZXAgPSAiXHQiLAogIGhlYWRlciA9IFRSVUUKKQpyb3duYW1lcyh4ZW5vX2J1bGspID0gbWFrZS51bmlxdWUoeGVub19idWxrWywiZ2VuZV9uYW1lIixkcm9wPVRdKQp4ZW5vX2J1bGsgPSB4ZW5vX2J1bGtbLDI2OjM3XQoKYGBgCgpgYGB7cn0KY2VsbC5sYWJlbHMgPSBuYW1lcyh4ZW5vX2J1bGspCmNvbmRpdGlvbiA9IHN0cl9leHRyYWN0KGNlbGwubGFiZWxzLCAib3NpfGNvbWJvfGN0cmx8cm94YSIpCm1ldGFkYXRhID0gZGF0YS5mcmFtZShjb25kaXRpb24gPSBjb25kaXRpb24sIHJvdy5uYW1lcyA9IGNvbG5hbWVzKHhlbm9fYnVsaykpCmBgYAoKYGBge3J9CmxpYnJhcnkoREVTZXEyKQpkZHMgPC0gREVTZXFEYXRhU2V0RnJvbU1hdHJpeChjb3VudERhdGEgPSByb3VuZCh4ZW5vX2J1bGspLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xEYXRhID0gbWV0YWRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbiA9IH5jb25kaXRpb24pCmBgYAoKCiMgUENBCmBgYHtyfQpucm93KGRkcykKZGRzMSA8LSBkZHNbIHJvd1N1bXMoY291bnRzKGRkcykpID49IDMsIF0KbnJvdyhkZHMxKQpgYGAKCmBgYHtyfQp2c3QgPSB2c3QoZGRzLCBibGluZD1GQUxTRSkKYGBgCgpgYGB7cn0KbGlicmFyeSgiZ2dmb3J0aWZ5IikKUENBZGF0YSA8LSBwcmNvbXAodChhc3NheSh2c3QpKSkKYXV0b3Bsb3QoUENBZGF0YSwgZGF0YSA9IG1ldGFkYXRhLGNvbG91ciA9ICJjb25kaXRpb24iLGxhYmVsID0gRkFMU0UsIG1haW49IlBDQSIpICMgU2hvdyBkb3RzCgpgYGAKIyBERVNlcQpgYGB7cn0KZGRzIDwtIERFU2VxKGRkcykKZGRzX3hlbm8gPSBkZHMKCmBgYApgYGB7cn0KZGRzID0gZGRzX3hlbm8KYGBgCiMgVG9wIHZhcmlhYmxlIGdlbmVzIGhlYXRtYXAKYGBge3J9CmdlbmVzIDwtIGhlYWQob3JkZXIocm93VmFycyhhc3NheShkZHMpKSwgZGVjcmVhc2luZyA9IFRSVUUpLCAxMDAwKQoKbWF0IDwtIHhlbm9fYnVsa1sgZ2VuZXMsIF0KbWF0IDwtIHQoc2NhbGUodChtYXQpKSkKYW5ubyA8LSBhcy5kYXRhLmZyYW1lKG1hdCkKCmxpYnJhcnkoQ29tcGxleEhlYXRtYXApIApsaWJyYXJ5KGdncGxvdDIpIApIZWF0bWFwKG1hdCwgY2x1c3Rlcl9yb3dzID0gVCwgY2x1c3Rlcl9jb2x1bW5zID0gRiwgY29sdW1uX2xhYmVscyA9IGNvbG5hbWVzKGFubm8pLCBuYW1lID0gImZwa20gWi1zY29yZSIscm93X25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDApKSAKYGBgCgojIERFRyB7LnRhYnNldH0KYGBge3J9CmNwVlNvcCA8LSByZXN1bHRzKGRkcyxjb250cmFzdCA9IGMoImNvbmRpdGlvbiIsImNvbWJvIiwib3NpIikpICAlPiUgYXMuZGF0YS5mcmFtZSgpCnJveGFWU2N0cmwgPC0gcmVzdWx0cyhkZHMsY29udHJhc3QgPSBjKCJjb25kaXRpb24iLCJyb3hhIiwiY3RybCIpKSAgJT4lIGFzLmRhdGEuZnJhbWUoKQpkaWZmX2dlbmVzID0gZGF0YS5mcmFtZShyb3cubmFtZXMgPSByb3duYW1lcyhjcFZTb3ApLCBjcFZTb3BfRkMgPSBjcFZTb3AkbG9nMkZvbGRDaGFuZ2Uscm94YVZTY3RybF9GQyA9IHJveGFWU2N0cmwkbG9nMkZvbGRDaGFuZ2UsICBjcFZTb3BfcGFkaiA9IGNwVlNvcCRwYWRqKQpgYGAKCmBgYHtyIHJlc3VsdHM9J2FzaXMnfQpsaWJyYXJ5KERUKQpjb21ib192c19jdHJsID0gcmVzdWx0cyhkZHMsY29udHJhc3QgPSBjKCJjb25kaXRpb24iLCJjb21ibyIsImN0cmwiKSkgICU+JSBhcy5kYXRhLmZyYW1lKCkKcm94YV92c19jdHJsID0gcmVzdWx0cyhkZHMsY29udHJhc3QgPSBjKCJjb25kaXRpb24iLCJyb3hhIiwiY3RybCIpKSAgJT4lIGFzLmRhdGEuZnJhbWUoKQpvc2lfdnNfY3RybCA9IHJlc3VsdHMoZGRzLGNvbnRyYXN0ID0gYygiY29uZGl0aW9uIiwib3NpIiwiY3RybCIpKSAgJT4lIGFzLmRhdGEuZnJhbWUoKQoKY29tYm9fdnNfcm94YSA9IHJlc3VsdHMoZGRzLGNvbnRyYXN0ID0gYygiY29uZGl0aW9uIiwiY29tYm8iLCJyb3hhIikpICAlPiUgYXMuZGF0YS5mcmFtZSgpCm9zaV92c19yb3hhID0gcmVzdWx0cyhkZHMsY29udHJhc3QgPSBjKCJjb25kaXRpb24iLCJvc2kiLCJyb3hhIikpICAlPiUgYXMuZGF0YS5mcmFtZSgpCmNvbWJvX3ZzX29zaSA8LSByZXN1bHRzKGRkcyxjb250cmFzdCA9IGMoImNvbmRpdGlvbiIsImNvbWJvIiwib3NpIikpICAlPiUgYXMuZGF0YS5mcmFtZSgpCgpkdDEgPSBkYXRhdGFibGUocm94YV92c19jdHJsICU+JSBmaWx0ZXIocGFkaiA8MC4wNSkgLGNhcHRpb24gPSAic2lnbmlmaWNhbnQgcm94YSBWUyBjdHJsIikKZHQyPSBkYXRhdGFibGUoY29tYm9fdnNfY3RybCAlPiUgZmlsdGVyKHBhZGogPDAuMDUpLGNhcHRpb24gPSAic2lnbmlmaWNhbnQgY29tYm8gdnMgY3RybCIpCmR0MyA9IGRhdGF0YWJsZShvc2lfdnNfY3RybCAlPiUgZmlsdGVyKHBhZGogPDAuMDUpLGNhcHRpb24gPSAic2lnbmlmaWNhbnQgb3NpX3ZzX2N0cmwiKQpkdDQgPWRhdGF0YWJsZShjb21ib192c19yb3hhICU+JSBmaWx0ZXIocGFkaiA8MC4wNSksY2FwdGlvbiA9ICJzaWduaWZpY2FudCBjb21ib192c19yb3hhIikKZHQ1ID1kYXRhdGFibGUob3NpX3ZzX3JveGEgJT4lIGZpbHRlcihwYWRqIDwwLjA1KSxjYXB0aW9uID0gInNpZ25pZmljYW50IG9zaV92c19yb3hhIikKZHQ2ID1kYXRhdGFibGUoY29tYm9fdnNfb3NpICU+JSBmaWx0ZXIocGFkaiA8MC4wNSksY2FwdGlvbiA9ICJzaWduaWZpY2FudCBjb21ibyBWUyBvc2kiKQpwcmludF90YWIocGx0ID0gZHQxLHRpdGxlID0gInNpZ25pZmljYW50IHJveGEgVlMgY3RybCIpCnByaW50X3RhYihwbHQgPSBkdDIsdGl0bGUgPSAic2lnbmlmaWNhbnQgY29tYm8gdnMgY3RybCIpCnByaW50X3RhYihwbHQgPSBkdDMsdGl0bGUgPSAic2lnbmlmaWNhbnQgb3NpIFZTIGN0cmwiKQpwcmludF90YWIocGx0ID0gZHQ0LHRpdGxlID0gInNpZ25pZmljYW50IGNvbWJvIFZTIHJveGEiKQpwcmludF90YWIocGx0ID0gZHQ1LHRpdGxlID0gInNpZ25pZmljYW50IG9zaSBWUyByb3hhIikKcHJpbnRfdGFiKHBsdCA9IGR0Nix0aXRsZSA9ICJzaWduaWZpY2FudCBjb21ibyBWUyBvc2kiKQpyb3hhX3ZzX2N0cmxbIkM0b3JmMyIsXQpgYGAKCgojIEdTRUEgey50YWJzZXR9CmBgYHtyIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEzLCByZXN1bHRzPSdhc2lzJ30KcGxvdF9oeXBlciA8LSBmdW5jdGlvbihnZW5lc19kZixpZGVudC4xLGlkZW50LjIpIHsKICBnZW5lc19kZiA9IGNwVlNvcFtvcmRlcihnZW5lc19kZiRsb2cyRm9sZENoYW5nZSwgZ2VuZXNfZGYkcGFkaiwgZGVjcmVhc2luZyA9IFQpLCBdICNvcmRlciBieSBGQywgdGllcyBidCBwYWRqCiAgcmFua2VkX3ZlYyA9IGdlbmVzX2RmWywgImxvZzJGb2xkQ2hhbmdlIl0gJT4lIHNldE5hbWVzKHJvd25hbWVzKGdlbmVzX2RmKSkgJT4lIG5hLm9taXQoKSAjIG1ha2UgbmFtZWQgdmVjdG9yCiAgCiAgaHlwX29iaiA8LSBoeXBlUl9mZ3NlYShyYW5rZWRfdmVjLCBnZW5lc2V0cywgdXBfb25seSA9IEYpCiAgcGx0ID0gaHlwX2RvdHMoaHlwX29iaiwgbWVyZ2UgPSBGKQogIHBsdDEgPSBwbHQkdXAgKyBhZXMoc2l6ZSA9IG5lcykgKyBnZ3RpdGxlKHBhc3RlKCJ1cCBpbiIgLGlkZW50LjEpKQogIHBsdDIgPSBwbHQkZG4gKyBhZXMoc2l6ZSA9IGFicyhuZXMpKSArIGdndGl0bGUocGFzdGUoInVwIGluIiAsaWRlbnQuMikpCiByZXR1cm4ocGx0MStwbHQyKQp9CgpwbG90X2h5cGVyKGNvbWJvX3ZzX2N0cmwsaWRlbnQuMSA9ICJjb21ibyIsaWRlbnQuMiA9ICJjdHJsIikgJT4lICBwcmludF90YWIodGl0bGUgPSAiY29tYm8gVlMgY3RybCIpCnBsb3RfaHlwZXIob3NpX3ZzX2N0cmwsaWRlbnQuMSA9ICJvc2kiLGlkZW50LjIgPSAiY3RybCIpJT4lICBwcmludF90YWIodGl0bGUgPSAib3NpIFZTIGN0cmwiKQpwbG90X2h5cGVyKGNvbWJvX3ZzX3JveGEsaWRlbnQuMSA9ICJjb21ibyIsaWRlbnQuMiA9ICJyb3hhIikgJT4lICBwcmludF90YWIodGl0bGUgPSAiY29tYm8gVlMgcm94YSIpCnBsb3RfaHlwZXIob3NpX3ZzX3JveGEsaWRlbnQuMSA9ICJvc2kiLGlkZW50LjIgPSAicm94YSIpICU+JSAgcHJpbnRfdGFiKHRpdGxlID0gIm9zaSBWUyByb3hhIikKCmBgYApIQUxMTUFSS19IWVBPWElBIGdlbmVzIGluIGNvbWJvX3ZzX2N0cmxfZ2VuZXMKYGBge3J9CmdlbmVzZXRzJEhBTExNQVJLX0hZUE9YSUFbZ2VuZXNldHMkSEFMTE1BUktfSFlQT1hJQSAlaW4lIGNvbWJvX3ZzX2N0cmxfZ2VuZXNdIApgYGAKCiMgREVHIHNocmlua2VkIEZDIHsudGFic2V0fQpgYGB7cn0KZGRzJGNvbmRpdGlvbiA9IHJlbGV2ZWwoZGRzJGNvbmRpdGlvbiwgcmVmID0gIm9zaSIpCmRkcyA8LSBuYmlub21XYWxkVGVzdChkZHMpCmNwVlNvcCA8LSBsZmNTaHJpbmsoZGRzLGNvZWYgPSAiY29uZGl0aW9uX2NvbWJvX3ZzX29zaSIpICAlPiUgYXMuZGF0YS5mcmFtZSgpCgpkZHMkY29uZGl0aW9uID0gcmVsZXZlbChkZHMkY29uZGl0aW9uLCByZWYgPSAiY3RybCIpCmRkcyA8LSBuYmlub21XYWxkVGVzdChkZHMpCnJveGFWU2N0cmwgPC0gbGZjU2hyaW5rKGRkcyxjb2VmICA9ICJjb25kaXRpb25fcm94YV92c19jdHJsIikgICU+JSBhcy5kYXRhLmZyYW1lKCkKCgpkaWZmX2dlbmVzID0gZGF0YS5mcmFtZShyb3cubmFtZXMgPSByb3duYW1lcyhjcFZTb3ApLCBjcFZTb3BfRkMgPSBjcFZTb3AkbG9nMkZvbGRDaGFuZ2Uscm94YVZTY3RybF9GQyA9IHJveGFWU2N0cmwkbG9nMkZvbGRDaGFuZ2UsICBjcFZTb3BfcGFkaiA9IGNwVlNvcCRwYWRqKQoKYGBgCgoKYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTMscmVzdWx0cz0nYXNpcyd9CnJhbmtlZF92ZWMgPSBkaWZmX2dlbmVzWywgMV0gJT4lIHNldE5hbWVzKHJvd25hbWVzKGRpZmZfZ2VuZXMpKSAlPiUgc29ydChkZWNyZWFzaW5nID0gVFJVRSkKaHlwX29iaiA8LSBoeXBlUl9mZ3NlYShyYW5rZWRfdmVjLCBnZW5lc2V0cywgdXBfb25seSA9IEYpCnBsdCA9IGh5cF9kb3RzKGh5cF9vYmosbWVyZ2UgPSBGKQpwbHQxID0gcGx0JHVwKyBhZXMoc2l6ZT1uZXMpK2dndGl0bGUoInVwIGluIGNvbWJvUGVyc2lzdG9yIikgKyB0aGVtZSggIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemU9MTApKQpwbHQyID0gcGx0JGRuKyBhZXMoc2l6ZT1hYnMobmVzKSkrZ2d0aXRsZSgidXAgaW4gb3NpUGVyc2lzdG9ycyIpICsgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCkpCnByaW50X3RhYihwbHQxK3BsdDIsdGl0bGUgPSAiY3BWU29wIikKCnJhbmtlZF92ZWMgPSBkaWZmX2dlbmVzWywgMl0gJT4lIHNldE5hbWVzKHJvd25hbWVzKGRpZmZfZ2VuZXMpKSAlPiUgc29ydChkZWNyZWFzaW5nID0gVFJVRSkKaHlwX29iaiA8LSBoeXBlUl9mZ3NlYShyYW5rZWRfdmVjLCBnZW5lc2V0cywgdXBfb25seSA9IEYpCnBsdCA9IGh5cF9kb3RzKGh5cF9vYmosbWVyZ2UgPSBGKQpwbHQxID0gcGx0JHVwKyBhZXMoc2l6ZT1uZXMpK2dndGl0bGUoInVwIGluIHJveGEiKQpwbHQyID0gcGx0JGRuKyBhZXMoc2l6ZT1hYnMobmVzKSkrZ2d0aXRsZSgidXAgaW4gY3RybCIpCnByaW50X3RhYihwbHQxK3BsdDIsdGl0bGUgPSAiY3BWU29wIikKCmBgYAoKIyBERUcgaW4gY29tYm9WU29zaSBidXQgbm90IGluIHJveGFWU2N0cmwgey50YWJzZXR9CgpgYGB7ciByZXN1bHRzPSdhc2lzJ30KY3BWU29wIDwtIHJlc3VsdHMoZGRzLGNvbnRyYXN0ID0gYygiY29uZGl0aW9uIiwiY29tYm8iLCJvc2kiKSkgICU+JSBhcy5kYXRhLmZyYW1lKCkKcm94YVZTY3RybCA8LSByZXN1bHRzKGRkcyxjb250cmFzdCA9IGMoImNvbmRpdGlvbiIsInJveGEiLCJjdHJsIikpICAlPiUgYXMuZGF0YS5mcmFtZSgpCmRpZmZfZ2VuZXMgPSBkYXRhLmZyYW1lKHJvdy5uYW1lcyA9IHJvd25hbWVzKGNwVlNvcCksIGNwVlNvcF9GQyA9IDIqKmNwVlNvcCRsb2cyRm9sZENoYW5nZSxyb3hhVlNjdHJsX0ZDID0gMioqcm94YVZTY3RybCRsb2cyRm9sZENoYW5nZSwgIGNwVlNvcF9wYWRqID0gY3BWU29wJHBhZGopCnVwX2dlbmVzX2RmID0gIGRpZmZfZ2VuZXMgJT4lIGZpbHRlcihjcFZTb3BfRkMgPiAyICYgcm94YVZTY3RybF9GQzwxLjIgJiBjcFZTb3BfcGFkajwwLjA1KSAKZG93bl9nZW5lc19kZiA9IGRpZmZfZ2VuZXMgJT4lIGZpbHRlcihjcFZTb3BfRkMgPCAwLjUgJiByb3hhVlNjdHJsX0ZDPjAuOCAmIGNwVlNvcF9wYWRqPDAuMDUpCnVwX2dlbmVzID0gZGlmZl9nZW5lcyAlPiUgZmlsdGVyKGNwVlNvcF9GQyA+IDIgJiByb3hhVlNjdHJsX0ZDPDEuMiAmIGNwVlNvcF9wYWRqPDAuMDUpICU+JSByb3duYW1lcygpCmRvd25fZ2VuZXMgPSBkaWZmX2dlbmVzICU+JSBmaWx0ZXIoY3BWU29wX0ZDIDwgMC41ICYgcm94YVZTY3RybF9GQz4wLjggJiBjcFZTb3BfcGFkajwwLjEpJT4lIHJvd25hbWVzKCkKCnByaW50X3RhYih1cF9nZW5lc19kZix0aXRsZSA9ICJ1cCIpCnByaW50X3RhYihkb3duX2dlbmVzX2RmLHRpdGxlID0gImRvd24iKQpgYGAKYGBge3J9CmNwVlNvcCA8LSByZXN1bHRzKGRkcyxjb250cmFzdCA9IGMoImNvbmRpdGlvbiIsInJveGEiLCJvc2kiKSkgICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIGZpbHRlcihwYWRqPDAuMDUpCmBgYAoKIyBFeHByZXNzaW9uIGhlYXRtYXAgey50YWJzZXR9CgpgYGB7cn0KIyBzZWxlY3QgdGhlIDUwIG1vc3QgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIApnZW5lcyA8LSBjKCJEVVNQNiIpCm1hdCA8LSB4ZW5vX2J1bGtbIGdlbmVzLCBdCm1hdCA8LSB0KHNjYWxlKHQobWF0KSkpCmFubm8gPC0gYXMuZGF0YS5mcmFtZShtYXQpCgpsaWJyYXJ5KENvbXBsZXhIZWF0bWFwKSAKbGlicmFyeShnZ3Bsb3QyKSAKSGVhdG1hcChtYXQsIGNsdXN0ZXJfcm93cyA9IEYsIGNsdXN0ZXJfY29sdW1ucyA9IEYsIGNvbHVtbl9sYWJlbHMgPSBjb2xuYW1lcyhhbm5vKSwgbmFtZSA9ICJmcGttIFotc2NvcmUiKSAKCmdlbmVzIDwtIGhpZl90YXJnZXRzCm1hdCA8LSB4ZW5vX2J1bGtbZ2VuZXMsIF0gJT4lIGZpbHRlcihyb3dTdW1zKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSkpIT0wKQptYXQgPC0gdChzY2FsZSh0KG1hdCkpKQphbm5vIDwtIGFzLmRhdGEuZnJhbWUobWF0KQoKIApIZWF0bWFwKG1hdCwgY2x1c3Rlcl9yb3dzID0gVCwgY2x1c3Rlcl9jb2x1bW5zID0gRiwgY29sdW1uX2xhYmVscyA9IGNvbG5hbWVzKGFubm8pLCBuYW1lID0gImZwa20gWi1zY29yZSIsY29sdW1uX3RpdGxlID0gIkhJRiB0YXJnZXRzIixyb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gOCkpIAoKYGBgCgoKYGBge3J9CnZzZCA8LSB2c3QoZGRzLCBibGluZD1GQUxTRSkKc2FtcGxlRGlzdHMgPC0gZGlzdCh0KGFzc2F5KHZzZCkpKQpsaWJyYXJ5KCJSQ29sb3JCcmV3ZXIiKQpzYW1wbGVEaXN0TWF0cml4IDwtIGFzLm1hdHJpeChzYW1wbGVEaXN0cykKY29sbmFtZXMoc2FtcGxlRGlzdE1hdHJpeCkgPC0gTlVMTApjb2xvcnMgPC0gY29sb3JSYW1wUGFsZXR0ZSggcmV2KGJyZXdlci5wYWwoOSwgIkJsdWVzIikpICkoMjU1KQpwaGVhdG1hcChzYW1wbGVEaXN0TWF0cml4LAogICAgICAgICBjbHVzdGVyaW5nX2Rpc3RhbmNlX3Jvd3M9c2FtcGxlRGlzdHMsCiAgICAgICAgIGNsdXN0ZXJpbmdfZGlzdGFuY2VfY29scz1zYW1wbGVEaXN0cywKICAgICAgICAgY29sPWNvbG9ycykKYGBgCgo8c2NyaXB0IHNyYz0iaHR0cHM6Ly9oeXBvdGhlcy5pcy9lbWJlZC5qcyIgYXN5bmM+PC9zY3JpcHQ+Cgo=