Functions
Data
genesets <- msigdb_download("Homo sapiens",category="H") %>% append( msigdb_download("Homo sapiens",category="C2",subcategory = "CP:KEGG"))
xeno_bulk = read.table(
file = "/sci/labs/yotamd/lab_share/lung_sc/bulk/RoxaOsi/Oct23/star/mm39unmapped_noMTGLKI_tpm.txt",
sep = "\t",
header = TRUE
)
rownames(xeno_bulk) = make.unique(xeno_bulk[,"gene_name",drop=T])
xeno_bulk = xeno_bulk[,8:19]
names (xeno_bulk) = gsub(pattern = "_mm.*$",replacement = "",x = names (xeno_bulk))
xeno_bulk = xeno_bulk[,c("M2_ctrl", "M21_ctrl", "M36_ctrl", "M14_osi", "M33_osi", "M14_2_osi",
"M20_roxa", "M30_roxa", "M31_roxa", "M3_combo", "M26_combo",
"M32_combo")]
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
PCA
nrow(dds)
[1] 60580
dds1 <- dds[ rowSums(counts(dds)) >= 3, ]
nrow(dds1)
[1] 21163
vst = vst(dds, blind=FALSE)
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_xeno = dds
dds = dds_xeno
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 = "TPM Z-score",row_names_gp = gpar(fontsize = 0))

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 = "TPM 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 = "TPM Z-score",column_title = "HIF targets",row_names_gp = gpar(fontsize = 8))

genes <- genesets$HALLMARK_G2M_CHECKPOINT
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 = "TPM Z-score",column_title = "G2M targets",row_names_gp = gpar(fontsize = 0))

genes <- genesets$HALLMARK_HYPOXIA
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 = "TPM Z-score",column_title = "Hallmark Hypoxia",row_names_gp = gpar(fontsize = 0))

NA
NA
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)
roxa_vs_ctrl = results(dds,contrast = c("condition","roxa","ctrl")) %>% as.data.frame()
combo_vs_ctrl = results(dds,contrast = c("condition","combo","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
NA
library(ggvenn)
deg = list(combo_vs_ctrl = combo_vs_ctrl%>% filter(padj <0.05) %>% rownames(),osi_vs_ctrl = osi_vs_ctrl%>% filter(padj <0.05) %>% rownames())
ggvenn(deg, c("combo_vs_ctrl", "osi_vs_ctrl")) # draw two-set venn

deg = list(combo_vs_roxa = combo_vs_roxa%>% filter(padj <0.05) %>% rownames(),osi_vs_roxa = osi_vs_roxa%>% filter(padj <0.05) %>% rownames())
ggvenn(deg, c("combo_vs_roxa", "osi_vs_roxa")) # draw two-set venn

deg = list(osi_vs_ctrl = osi_vs_ctrl%>% filter(padj <0.05) %>% rownames(),osi_vs_roxa = osi_vs_roxa%>% filter(padj <0.05) %>% rownames())
ggvenn(deg, c("osi_vs_ctrl", "osi_vs_roxa")) # draw two-set venn

LS0tCnRpdGxlOiAnYHIgcnN0dWRpb2FwaTo6Z2V0U291cmNlRWRpdG9yQ29udGV4dCgpJHBhdGggJT4lIGJhc2VuYW1lKCkgJT4lIGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLHJlcGxhY2VtZW50ID0gIiIpYCcgCmF1dGhvcjogIkF2aXNoYWkgV2l6ZWwiCmRhdGU6ICdgciBTeXMudGltZSgpYCcKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdG9jOiB5ZXMKICAgIHRvY19jb2xsYXBzZTogeWVzCiAgICB0b2NfZmxvYXQ6IAogICAgICBjb2xsYXBzZWQ6IEZBTFNFCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvY19kZXB0aDogMQotLS0KCgoKIyBGdW5jdGlvbnMKCmBgYHtyIHdhcm5pbmc9RkFMU0V9CmBgYAoKIyBEYXRhCgpgYGB7cn0KZ2VuZXNldHMgPC0gbXNpZ2RiX2Rvd25sb2FkKCJIb21vIHNhcGllbnMiLGNhdGVnb3J5PSJIIikgJT4lIGFwcGVuZCggbXNpZ2RiX2Rvd25sb2FkKCJIb21vIHNhcGllbnMiLGNhdGVnb3J5PSJDMiIsc3ViY2F0ZWdvcnkgPSAiQ1A6S0VHRyIpKQp4ZW5vX2J1bGsgPSByZWFkLnRhYmxlKAogIGZpbGUgPSAiL3NjaS9sYWJzL3lvdGFtZC9sYWJfc2hhcmUvbHVuZ19zYy9idWxrL1JveGFPc2kvT2N0MjMvc3Rhci9tbTM5dW5tYXBwZWRfbm9NVEdMS0lfdHBtLnR4dCIsCiAgc2VwID0gIlx0IiwKICBoZWFkZXIgPSBUUlVFCikKcm93bmFtZXMoeGVub19idWxrKSA9IG1ha2UudW5pcXVlKHhlbm9fYnVsa1ssImdlbmVfbmFtZSIsZHJvcD1UXSkKeGVub19idWxrID0geGVub19idWxrWyw4OjE5XQpuYW1lcyAoeGVub19idWxrKSA9IGdzdWIocGF0dGVybiA9ICJfbW0uKiQiLHJlcGxhY2VtZW50ID0gIiIseCA9IG5hbWVzICh4ZW5vX2J1bGspKQp4ZW5vX2J1bGsgPSB4ZW5vX2J1bGtbLGMoIk0yX2N0cmwiLCAiTTIxX2N0cmwiLCAiTTM2X2N0cmwiLCAiTTE0X29zaSIsICJNMzNfb3NpIiwgIk0xNF8yX29zaSIsIAoiTTIwX3JveGEiLCAiTTMwX3JveGEiLCAiTTMxX3JveGEiLCAiTTNfY29tYm8iLCAiTTI2X2NvbWJvIiwgCiJNMzJfY29tYm8iKV0KYGBgCgpgYGB7cn0KY2VsbC5sYWJlbHMgPSBuYW1lcyh4ZW5vX2J1bGspCmNvbmRpdGlvbiA9IHN0cl9leHRyYWN0KGNlbGwubGFiZWxzLCAib3NpfGNvbWJvfGN0cmx8cm94YSIpCm1ldGFkYXRhID0gZGF0YS5mcmFtZShjb25kaXRpb24gPSBjb25kaXRpb24sIHJvdy5uYW1lcyA9IGNvbG5hbWVzKHhlbm9fYnVsaykpCmBgYAoKYGBge3J9CmxpYnJhcnkoREVTZXEyKQpkZHMgPC0gREVTZXFEYXRhU2V0RnJvbU1hdHJpeChjb3VudERhdGEgPSByb3VuZCh4ZW5vX2J1bGspLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xEYXRhID0gbWV0YWRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbiA9IH5jb25kaXRpb24pCmBgYAoKCiMgUENBCmBgYHtyfQpucm93KGRkcykKZGRzMSA8LSBkZHNbIHJvd1N1bXMoY291bnRzKGRkcykpID49IDMsIF0KbnJvdyhkZHMxKQpgYGAKCmBgYHtyfQp2c3QgPSB2c3QoZGRzLCBibGluZD1GQUxTRSkKYGBgCgpgYGB7cn0KbGlicmFyeSgiZ2dmb3J0aWZ5IikKUENBZGF0YSA8LSBwcmNvbXAodChhc3NheSh2c3QpKSkKYXV0b3Bsb3QoUENBZGF0YSwgZGF0YSA9IG1ldGFkYXRhLGNvbG91ciA9ICJjb25kaXRpb24iLGxhYmVsID0gRkFMU0UsIG1haW49IlBDQSIpICMgU2hvdyBkb3RzCgpgYGAKIyBERVNlcQpgYGB7cn0KZGRzIDwtIERFU2VxKGRkcykKZGRzX3hlbm8gPSBkZHMKCmBgYAoKYGBge3J9CmRkcyA9IGRkc194ZW5vCmBgYAoKCgojIFRvcCB2YXJpYWJsZSBnZW5lcyBoZWF0bWFwCmBgYHtyfQpnZW5lcyA8LSBoZWFkKG9yZGVyKHJvd1ZhcnMoYXNzYXkoZGRzKSksIGRlY3JlYXNpbmcgPSBUUlVFKSwgMTAwMCkKCm1hdCA8LSB4ZW5vX2J1bGtbIGdlbmVzLCBdCm1hdCA8LSB0KHNjYWxlKHQobWF0KSkpCmFubm8gPC0gYXMuZGF0YS5mcmFtZShtYXQpCgpsaWJyYXJ5KENvbXBsZXhIZWF0bWFwKSAKbGlicmFyeShnZ3Bsb3QyKSAKSGVhdG1hcChtYXQsIGNsdXN0ZXJfcm93cyA9IFQsIGNsdXN0ZXJfY29sdW1ucyA9IEYsIGNvbHVtbl9sYWJlbHMgPSBjb2xuYW1lcyhhbm5vKSwgbmFtZSA9ICJUUE0gWi1zY29yZSIscm93X25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDApKSAKYGBgCgojIEV4cHJlc3Npb24gaGVhdG1hcCB7LnRhYnNldH0KCmBgYHtyIGZpZy5oZWlnaHQ9Nn0KIyBzZWxlY3QgdGhlIDUwIG1vc3QgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIApnZW5lcyA8LSBjKCJEVVNQNiIpCm1hdCA8LSB4ZW5vX2J1bGtbIGdlbmVzLCBdCm1hdCA8LSB0KHNjYWxlKHQobWF0KSkpCmFubm8gPC0gYXMuZGF0YS5mcmFtZShtYXQpCgpsaWJyYXJ5KENvbXBsZXhIZWF0bWFwKSAKbGlicmFyeShnZ3Bsb3QyKSAKSGVhdG1hcChtYXQsIGNsdXN0ZXJfcm93cyA9IEYsIGNsdXN0ZXJfY29sdW1ucyA9IEYsIGNvbHVtbl9sYWJlbHMgPSBjb2xuYW1lcyhhbm5vKSwgbmFtZSA9ICJUUE0gWi1zY29yZSIpIAoKZ2VuZXMgPC0gaGlmX3RhcmdldHMKbWF0IDwtIHhlbm9fYnVsa1tnZW5lcywgXSAlPiUgZmlsdGVyKHJvd1N1bXMoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpKSkhPTApCm1hdCA8LSB0KHNjYWxlKHQobWF0KSkpCmFubm8gPC0gYXMuZGF0YS5mcmFtZShtYXQpCgogCkhlYXRtYXAobWF0LCBjbHVzdGVyX3Jvd3MgPSBULCBjbHVzdGVyX2NvbHVtbnMgPSBGLCBjb2x1bW5fbGFiZWxzID0gY29sbmFtZXMoYW5ubyksIG5hbWUgPSAiVFBNIFotc2NvcmUiLGNvbHVtbl90aXRsZSA9ICJISUYgdGFyZ2V0cyIscm93X25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDgpKSAKCgpnZW5lcyA8LSBnZW5lc2V0cyRIQUxMTUFSS19HMk1fQ0hFQ0tQT0lOVAptYXQgPC0geGVub19idWxrW2dlbmVzLCBdICU+JSBmaWx0ZXIocm93U3VtcyhhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykpKSE9MCkKbWF0IDwtIHQoc2NhbGUodChtYXQpKSkKYW5ubyA8LSBhcy5kYXRhLmZyYW1lKG1hdCkKCiAKSGVhdG1hcChtYXQsIGNsdXN0ZXJfcm93cyA9IFQsIGNsdXN0ZXJfY29sdW1ucyA9IEYsIGNvbHVtbl9sYWJlbHMgPSBjb2xuYW1lcyhhbm5vKSwgbmFtZSA9ICJUUE0gWi1zY29yZSIsY29sdW1uX3RpdGxlID0gIkcyTSB0YXJnZXRzIixyb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gMCkpIAoKZ2VuZXMgPC0gZ2VuZXNldHMkSEFMTE1BUktfSFlQT1hJQQptYXQgPC0geGVub19idWxrW2dlbmVzLCBdICU+JSBmaWx0ZXIocm93U3VtcyhhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykpKSE9MCkKbWF0IDwtIHQoc2NhbGUodChtYXQpKSkKYW5ubyA8LSBhcy5kYXRhLmZyYW1lKG1hdCkKCiAKSGVhdG1hcChtYXQsIGNsdXN0ZXJfcm93cyA9IFQsIGNsdXN0ZXJfY29sdW1ucyA9IEYsIGNvbHVtbl9sYWJlbHMgPSBjb2xuYW1lcyhhbm5vKSwgbmFtZSA9ICJUUE0gWi1zY29yZSIsY29sdW1uX3RpdGxlID0gIkhhbGxtYXJrIEh5cG94aWEiLHJvd19uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSAwKSkgCgoKYGBgCgojIERFRyB7LnRhYnNldH0KYGBge3J9CmNwVlNvcCA8LSByZXN1bHRzKGRkcyxjb250cmFzdCA9IGMoImNvbmRpdGlvbiIsImNvbWJvIiwib3NpIikpICAlPiUgYXMuZGF0YS5mcmFtZSgpCnJveGFWU2N0cmwgPC0gcmVzdWx0cyhkZHMsY29udHJhc3QgPSBjKCJjb25kaXRpb24iLCJyb3hhIiwiY3RybCIpKSAgJT4lIGFzLmRhdGEuZnJhbWUoKQpkaWZmX2dlbmVzID0gZGF0YS5mcmFtZShyb3cubmFtZXMgPSByb3duYW1lcyhjcFZTb3ApLCBjcFZTb3BfRkMgPSBjcFZTb3AkbG9nMkZvbGRDaGFuZ2Uscm94YVZTY3RybF9GQyA9IHJveGFWU2N0cmwkbG9nMkZvbGRDaGFuZ2UsICBjcFZTb3BfcGFkaiA9IGNwVlNvcCRwYWRqKQpgYGAKCmBgYHtyIHJlc3VsdHM9J2FzaXMnfQpsaWJyYXJ5KERUKQpyb3hhX3ZzX2N0cmwgPSByZXN1bHRzKGRkcyxjb250cmFzdCA9IGMoImNvbmRpdGlvbiIsInJveGEiLCJjdHJsIikpICAlPiUgYXMuZGF0YS5mcmFtZSgpCmNvbWJvX3ZzX2N0cmwgPSByZXN1bHRzKGRkcyxjb250cmFzdCA9IGMoImNvbmRpdGlvbiIsImNvbWJvIiwiY3RybCIpKSAgJT4lIGFzLmRhdGEuZnJhbWUoKQpvc2lfdnNfY3RybCA9IHJlc3VsdHMoZGRzLGNvbnRyYXN0ID0gYygiY29uZGl0aW9uIiwib3NpIiwiY3RybCIpKSAgJT4lIGFzLmRhdGEuZnJhbWUoKQoKY29tYm9fdnNfcm94YSA9IHJlc3VsdHMoZGRzLGNvbnRyYXN0ID0gYygiY29uZGl0aW9uIiwiY29tYm8iLCJyb3hhIikpICAlPiUgYXMuZGF0YS5mcmFtZSgpCm9zaV92c19yb3hhID0gcmVzdWx0cyhkZHMsY29udHJhc3QgPSBjKCJjb25kaXRpb24iLCJvc2kiLCJyb3hhIikpICAlPiUgYXMuZGF0YS5mcmFtZSgpCmNvbWJvX3ZzX29zaSA8LSByZXN1bHRzKGRkcyxjb250cmFzdCA9IGMoImNvbmRpdGlvbiIsImNvbWJvIiwib3NpIikpICAlPiUgYXMuZGF0YS5mcmFtZSgpCgpkdDEgPSBkYXRhdGFibGUocm94YV92c19jdHJsJT4lIGZpbHRlcihwYWRqIDwwLjA1KSAgLGNhcHRpb24gPSAic2lnbmlmaWNhbnQgcm94YSBWUyBjdHJsIikKZHQyPSBkYXRhdGFibGUoY29tYm9fdnNfY3RybCAlPiUgZmlsdGVyKHBhZGogPDAuMDUpLGNhcHRpb24gPSAic2lnbmlmaWNhbnQgY29tYm8gdnMgY3RybCIpCmR0MyA9IGRhdGF0YWJsZShvc2lfdnNfY3RybCAlPiUgZmlsdGVyKHBhZGogPDAuMDUpLGNhcHRpb24gPSAic2lnbmlmaWNhbnQgb3NpX3ZzX2N0cmwiKQpkdDQgPWRhdGF0YWJsZShjb21ib192c19yb3hhICU+JSBmaWx0ZXIocGFkaiA8MC4wNSksY2FwdGlvbiA9ICJzaWduaWZpY2FudCBjb21ib192c19yb3hhIikKZHQ1ID1kYXRhdGFibGUob3NpX3ZzX3JveGEgJT4lIGZpbHRlcihwYWRqIDwwLjA1KSxjYXB0aW9uID0gInNpZ25pZmljYW50IG9zaV92c19yb3hhIikKZHQ2ID1kYXRhdGFibGUoY29tYm9fdnNfb3NpICU+JSBmaWx0ZXIocGFkaiA8MC4wNSksY2FwdGlvbiA9ICJzaWduaWZpY2FudCBjb21ibyBWUyBvc2kiKQpwcmludF90YWIocGx0ID0gZHQxLHRpdGxlID0gInNpZ25pZmljYW50IHJveGEgVlMgY3RybCIpCnByaW50X3RhYihwbHQgPSBkdDIsdGl0bGUgPSAic2lnbmlmaWNhbnQgY29tYm8gdnMgY3RybCIpCnByaW50X3RhYihwbHQgPSBkdDMsdGl0bGUgPSAic2lnbmlmaWNhbnQgb3NpIFZTIGN0cmwiKQpwcmludF90YWIocGx0ID0gZHQ0LHRpdGxlID0gInNpZ25pZmljYW50IGNvbWJvIFZTIHJveGEiKQpwcmludF90YWIocGx0ID0gZHQ1LHRpdGxlID0gInNpZ25pZmljYW50IG9zaSBWUyByb3hhIikKcHJpbnRfdGFiKHBsdCA9IGR0Nix0aXRsZSA9ICJzaWduaWZpY2FudCBjb21ibyBWUyBvc2kiKQpgYGAKYGBge3J9CmxpYnJhcnkoZ2d2ZW5uKQpkZWcgPSBsaXN0KGNvbWJvX3ZzX2N0cmwgPSBjb21ib192c19jdHJsJT4lIGZpbHRlcihwYWRqIDwwLjA1KSAlPiUgcm93bmFtZXMoKSxvc2lfdnNfY3RybCA9IG9zaV92c19jdHJsJT4lIGZpbHRlcihwYWRqIDwwLjA1KSAlPiUgcm93bmFtZXMoKSkKZ2d2ZW5uKGRlZywgYygiY29tYm9fdnNfY3RybCIsICJvc2lfdnNfY3RybCIpKSAgICAgICAgICAgICMgZHJhdyB0d28tc2V0IHZlbm4KCmRlZyA9IGxpc3QoY29tYm9fdnNfcm94YSA9IGNvbWJvX3ZzX3JveGElPiUgZmlsdGVyKHBhZGogPDAuMDUpICU+JSByb3duYW1lcygpLG9zaV92c19yb3hhID0gb3NpX3ZzX3JveGElPiUgZmlsdGVyKHBhZGogPDAuMDUpICU+JSByb3duYW1lcygpKQpnZ3Zlbm4oZGVnLCBjKCJjb21ib192c19yb3hhIiwgIm9zaV92c19yb3hhIikpICAgICAgICAgICAgIyBkcmF3IHR3by1zZXQgdmVubgpgYGAKCmBgYHtyfQpkZWcgPSBsaXN0KG9zaV92c19jdHJsID0gb3NpX3ZzX2N0cmwlPiUgZmlsdGVyKHBhZGogPDAuMDUpICU+JSByb3duYW1lcygpLG9zaV92c19yb3hhID0gb3NpX3ZzX3JveGElPiUgZmlsdGVyKHBhZGogPDAuMDUpICU+JSByb3duYW1lcygpKQpnZ3Zlbm4oZGVnLCBjKCJvc2lfdnNfY3RybCIsICJvc2lfdnNfcm94YSIpKSAgICAgICAgICAgICMgZHJhdyB0d28tc2V0IHZlbm4KYGBgCgoKCgo8c2NyaXB0IHNyYz0iaHR0cHM6Ly9oeXBvdGhlcy5pcy9lbWJlZC5qcyIgYXN5bmM+PC9zY3JpcHQ+Cgo=