Installing airway
if (!requireNamespace("BiocManager", quietly = TRUE)) install.packages("BiocManager")
BiocManager::install("airway")
data(airway)
class(airway)
str(airway)
## Access metadata
meta <- airway %>%
colData() %>% ## To access metadata information
as.data.frame()
head(meta)
meta <- meta[,c(2,3)]
## Suggest a different approach
meta$dex <- gsub('trt', 'treated', meta$dex)
## Suggest a different approach
meta$dex <- gsub('untrt', 'untreated', meta$dex)
## Suggest a different approach
names(meta) <- c('cellLine', 'dexamethasone')
write.table(meta, file = "meta.csv", sep = ',',
col.names = T, row.names = T,
quote = F)
counts <- assay(airway)
write.table(counts, file = "counts_data.csv", sep = ',', col.names = T, row.names = T, quote = F)
counts <- read.csv("counts_data.csv")
counts[1:6, 1:6]
meta$dexamethasone <- relevel(factor(meta$dexamethasone), ref = "untreated")
x <- SummarizedExperiment(list(counts=as.matrix(counts)),
colData = meta)
x
symbols <- mapIds(
org.Hs.eg.db,
keys = rownames(x),
column = "SYMBOL",
keytype = "ENSEMBL",
multiVals = "first"
)
rowData(x)$symbol <- symbols
x
ens_ids <- rownames(x)
ens_ids_clean <- sub("\\..*$", "", ens_ids)
gene_symbols <- mapIds(
org.Hs.eg.db,
keys = ens_ids_clean,
keytype = "ENSEMBL",
column = "SYMBOL",
multiVals = "first"
)
gene_names <- mapIds(
org.Hs.eg.db,
keys = ens_ids_clean,
keytype = "ENSEMBL",
column = "GENENAME",
multiVals = "first"
)
rowData(x)$ensembl_id <- ens_ids_clean
rowData(x)$symbol <- gene_symbols
rowData(x)$gene_name <- gene_names
x
# making sure the row names in colData matches to column names in counts_data
all(colnames(counts) %in% rownames(meta))
# are they in the same order?
all(colnames(counts) == rownames(meta))
# Step 2: construct a DESeqDataSet object ----------
dds <- DESeqDataSetFromMatrix(countData = counts,
colData = meta,
design = ~ dexamethasone)
dds
# pre-filtering: removing rows with low gene counts, keeping rows that have at least 10 reads total
keep <- rowSums(counts(dds)) >= 10
dds <- dds[keep,]
dds
# set the factor level
dds$dexamethasone <- relevel(dds$dexamethasone, ref = "untreated")
# Step 3: Run DESeq ----------------------
dds <- DESeq(dds)
res <- results(dds)
str(res)
summary(res)
# contrasts
resultsNames(dds)
# e.g.: treated_4hrs, treated_8hrs, untreated
results(dds, contrast = c("dexamethasone", "treated", "untreated"))
# MA plot
plotMA(res)

vsd <- vst(dds, blind = FALSE)
mat <- assay(vsd)
plotPCA(vsd, intgroup = "dexamethasone")

pca_data <- plotPCA(vsd, intgroup = "dexamethasone", returnData = TRUE)
percent_var <- round(100 * attr(pca_data, "percentVar"))
ggplot(pca_data, aes(PC1, PC2, color = dexamethasone, label = name)) +
geom_point(size = 4) +
geom_text(vjust = -1) +
xlab(paste0("PC1: ", percent_var[1], "% variance")) +
ylab(paste0("PC2: ", percent_var[2], "% variance")) +
theme_minimal()

annot <- data.frame(ensembl_id = rowData(x)$ensembl_id,
symbol = rowData(x)$symbol,
gene_name = rowData(x)$gene_name)
head(annot)
head(res, 4)
res_df <- as.data.frame(res) %>%
rownames_to_column("ensembl_id") %>%
mutate(ensembl_id = sub("\\..*$", "", ensembl_id)) %>%
left_join(annot, by = "ensembl_id")
VOLCANO_Plot <- function(df, units = "in", height = 16, width = 16,
filename, dpi = 600,
cols = c("UP" = "firebrick3", "DOWN" = "steelblue", "ns" = "grey"),
ylim = c("",""),
xlim = c(-2.5,2.5)){
vp1 <- EnhancedVolcano(df,
lab = df$symbol,
x = 'log2FoldChange',
y = 'padj', pCutoff = 0.05, FCcutoff = 0.5)
print(vp1)
# ggsave(filename, units = units, height = height, width = width, dpi = dpi)
return(vp1)
}
VOLCANO_Plot(df = res_df)


sig_res <- subset(res_df,
padj < 0.05 &
abs(log2FoldChange) > 1)
head(sig_res)
nrow(sig_res)
head(sig_res[order(-sig_res$log2FoldChange), ])
head(sig_res[order(sig_res$log2FoldChange), ])
res_df$significant <- ifelse(res_df$padj < 0.05 &
abs(res_df$log2FoldChange) > 1, "yes", "no")
ggplot(res_df, aes(x = log2FoldChange, y = -log10(padj), color = significant)) +
geom_point(alpha = 0.7) +
theme_minimal() +
xlab("log2 fold change") +
ylab("-log10 adjusted p-value")

res_df <- res %>%
as.data.frame() %>%
tibble::rownames_to_column("ensembl_id") %>%
mutate(ensembl_id = sub("\\..*$", "", ensembl_id)) %>%
left_join(annot, by = "ensembl_id") %>%
filter(padj < 0.05,
abs(log2FoldChange) > 1) %>%
mutate(
DE = case_when(
log2FoldChange > 1 ~ "UP",
log2FoldChange < -1 ~ "DOWN"
)
)
head(res_df)
symbol_to_ens <- setNames(
rowData(x)$ensembl_id,
rowData(x)$symbol
)
plotCounts(dds, gene = "PDK4", intgroup = "dexamethasone", main = "PDK4")
plotCounts(dds, gene = symbol_to_ens["PDK4"], intgroup = "dexamethasone", main = "PDK4")

plotCounts(dds, gene = symbol_to_ens["TP53"], intgroup = "dexamethasone", main = "TP53")

GO terms
GO_res <- enrichGO(
gene = res_df$symbol,
OrgDb = "org.Hs.eg.db",
keyType = "SYMBOL",
ont = "ALL",
pAdjustMethod = "BH",
qvalueCutoff = 0.05,
pvalueCutoff = 0.05,
readable = TRUE
)
str(GO_res)
dotplot(GO_res)

Up_reg <- res_df %>% filter(DE == "UP")
Down_reg <- res_df %>% filter(DE == "DOWN")
GO_res_up <- enrichGO(
gene = Up_reg$symbol,
OrgDb = "org.Hs.eg.db",
keyType = "SYMBOL",
ont = "ALL",
pAdjustMethod = "BH",
qvalueCutoff = 0.05,
pvalueCutoff = 0.05,
readable = TRUE
)
dotplot(GO_res_up)

GO_res_down <- enrichGO(
gene = Down_reg$symbol,
OrgDb = "org.Hs.eg.db",
keyType = "SYMBOL",
ont = "ALL",
pAdjustMethod = "BH",
qvalueCutoff = 0.05,
pvalueCutoff = 0.05,
readable = TRUE
)
dotplot(GO_res_down)

LS0tCnRpdGxlOiAiQnVsayBSTkFzZXEgYW5hbHlzaXMiCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgICclZCAlQiAlWScpYCIKYXV0aG9yOiAiTW9oYW1lZCBIYXNzYW4iCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdGhlbWU6IGNlcnVsZWFuCiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMwplZGl0b3Jfb3B0aW9uczoKICBtYXJrZG93bjoKICAgIHdyYXA6IDcyCi0tLQpgYGB7ciBzZXR1cCwgaW5jbHVkZSA9IEZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFQsIHJlc3VsdHMgPSAiaGlkZSIpCnJlcXVpcmUoImtuaXRyIikKIyBvcHRzX2tuaXQkc2V0KHJvb3QuZGlyID0gIi8iKQpgYGAKCmBgYHtyfQojIENSQU4gZmlyc3QKcGNrcyA8LSBsaXN0KGMoInBhY21hbiIsCiAgInRpZHl2ZXJzZSIsCiAgInBoZWF0bWFwIiwKICAiUkNvbG9yQnJld2VyIiwKICAic3R5bGVyIiwKICAicmVtb3RlcyIKKQopCmxhcHBseShwY2tzLCBpbnN0YWxsLnBhY2thZ2VzKQoKIyBCaW9jb25kdWN0b3IgaW5zdGFsbGVyCmlmICghcmVxdWlyZU5hbWVzcGFjZSgiQmlvY01hbmFnZXIiLCBxdWlldGx5ID0gVFJVRSkpIHsKICBpbnN0YWxsLnBhY2thZ2VzKCJCaW9jTWFuYWdlciIpCn0KCiMgQmlvY29uZHVjdG9yIHBhY2thZ2VzCkJpb2NNYW5hZ2VyOjppbnN0YWxsKGMoCiAgImFpcndheSIsCiAgIlN1bW1hcml6ZWRFeHBlcmltZW50IiwKICAiREVTZXEyIiwKICAib3JnLkhzLmVnLmRiIiwKICAiQW5ub3RhdGlvbkRiaSIsCiAgIkVuaGFuY2VkVm9sY2FubyIsCiAgImNsdXN0ZXJQcm9maWxlciIsCiAgImVucmljaHBsb3QiCikpCmBgYAoKCgpgYGB7ciByYW5kb20tc2VlZC1zZXR0aW5nfQpzZXQuc2VlZCgxMjM0NSkKYGBgCgpgYGB7ciBsb2FkaW5nLWxpYnJhcmllcywgcmVzdWx0cz0naGlkZSd9CnBhY21hbjo6cF9sb2FkKHRpZHl2ZXJzZSwgU3VtbWFyaXplZEV4cGVyaW1lbnQsIGFpcndheSwgb3JnLkhzLmVnLmRiLAogICAgICAgICAgICAgICBSQ29sb3JCcmV3ZXIsRW5oYW5jZWRWb2xjYW5vLCBwaGVhdG1hcCwgQW5ub3RhdGlvbkRiaSwgREVTZXEyLCBzdHlsZXIsIGNsdXN0ZXJQcm9maWxlciwgcmVtb3RlcykKYGBgCgojIyBJbnN0YWxsaW5nIGFpcndheQoKYGBge3IsIGV2YWw9RkFMU0V9CmlmICghcmVxdWlyZU5hbWVzcGFjZSgiQmlvY01hbmFnZXIiLCBxdWlldGx5ID0gVFJVRSkpIGluc3RhbGwucGFja2FnZXMoIkJpb2NNYW5hZ2VyIikKQmlvY01hbmFnZXI6Omluc3RhbGwoImFpcndheSIpCmBgYAoKYGBge3J9CmRhdGEoYWlyd2F5KQpgYGAKCgpgYGB7cn0KY2xhc3MoYWlyd2F5KQpgYGAKCmBgYHtyfQpzdHIoYWlyd2F5KQpgYGAKCgpgYGB7cn0KIyMgQWNjZXNzIG1ldGFkYXRhCm1ldGEgPC0gYWlyd2F5ICU+JSAKICBjb2xEYXRhKCkgJT4lICMjIFRvIGFjY2VzcyBtZXRhZGF0YSBpbmZvcm1hdGlvbgogIGFzLmRhdGEuZnJhbWUoKQpoZWFkKG1ldGEpCmBgYAoKYGBge3J9Cm1ldGEgPC0gbWV0YVssYygyLDMpXQojIyBTdWdnZXN0IGEgZGlmZmVyZW50IGFwcHJvYWNoCgptZXRhJGRleCA8LSBnc3ViKCd0cnQnLCAndHJlYXRlZCcsIG1ldGEkZGV4KQojIyBTdWdnZXN0IGEgZGlmZmVyZW50IGFwcHJvYWNoCgptZXRhJGRleCA8LSBnc3ViKCd1bnRydCcsICd1bnRyZWF0ZWQnLCBtZXRhJGRleCkKCiMjIFN1Z2dlc3QgYSBkaWZmZXJlbnQgYXBwcm9hY2gKbmFtZXMobWV0YSkgPC0gYygnY2VsbExpbmUnLCAnZGV4YW1ldGhhc29uZScpCgp3cml0ZS50YWJsZShtZXRhLCBmaWxlID0gIm1ldGEuY3N2Iiwgc2VwID0gJywnLCAKICAgICAgICAgICAgY29sLm5hbWVzID0gVCwgcm93Lm5hbWVzID0gVCwgCiAgICAgICAgICAgIHF1b3RlID0gRikKCmNvdW50cyA8LSBhc3NheShhaXJ3YXkpCndyaXRlLnRhYmxlKGNvdW50cywgZmlsZSA9ICJjb3VudHNfZGF0YS5jc3YiLCBzZXAgPSAnLCcsIGNvbC5uYW1lcyA9IFQsIHJvdy5uYW1lcyA9IFQsIHF1b3RlID0gRikKYGBgCgoKYGBge3J9CmNvdW50cyA8LSByZWFkLmNzdigiY291bnRzX2RhdGEuY3N2IikKYGBgCgoKYGBge3J9CmNvdW50c1sxOjYsIDE6Nl0KYGBgCgoKYGBge3J9Cm1ldGEkZGV4YW1ldGhhc29uZSA8LSByZWxldmVsKGZhY3RvcihtZXRhJGRleGFtZXRoYXNvbmUpLCByZWYgPSAidW50cmVhdGVkIikKYGBgCgpgYGB7cn0KeCA8LSBTdW1tYXJpemVkRXhwZXJpbWVudChsaXN0KGNvdW50cz1hcy5tYXRyaXgoY291bnRzKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGEgPSBtZXRhKQp4CmBgYAoKCmBgYHtyfQpzeW1ib2xzIDwtIG1hcElkcygKICAgIG9yZy5Icy5lZy5kYiwKICAgIGtleXMgPSByb3duYW1lcyh4KSwKICAgIGNvbHVtbiA9ICJTWU1CT0wiLAogICAga2V5dHlwZSA9ICJFTlNFTUJMIiwKICAgIG11bHRpVmFscyA9ICJmaXJzdCIKKQpyb3dEYXRhKHgpJHN5bWJvbCA8LSBzeW1ib2xzCmBgYAoKCmBgYHtyfQp4CmBgYAoKCmBgYHtyfQplbnNfaWRzIDwtIHJvd25hbWVzKHgpCmVuc19pZHNfY2xlYW4gPC0gc3ViKCJcXC4uKiQiLCAiIiwgZW5zX2lkcykKCmdlbmVfc3ltYm9scyA8LSBtYXBJZHMoCiAgb3JnLkhzLmVnLmRiLAogIGtleXMgPSBlbnNfaWRzX2NsZWFuLAogIGtleXR5cGUgPSAiRU5TRU1CTCIsCiAgY29sdW1uID0gIlNZTUJPTCIsCiAgbXVsdGlWYWxzID0gImZpcnN0IgopCgpnZW5lX25hbWVzIDwtIG1hcElkcygKICBvcmcuSHMuZWcuZGIsCiAga2V5cyA9IGVuc19pZHNfY2xlYW4sCiAga2V5dHlwZSA9ICJFTlNFTUJMIiwKICBjb2x1bW4gPSAiR0VORU5BTUUiLAogIG11bHRpVmFscyA9ICJmaXJzdCIKKQoKcm93RGF0YSh4KSRlbnNlbWJsX2lkIDwtIGVuc19pZHNfY2xlYW4Kcm93RGF0YSh4KSRzeW1ib2wgPC0gZ2VuZV9zeW1ib2xzCnJvd0RhdGEoeCkkZ2VuZV9uYW1lIDwtIGdlbmVfbmFtZXMKYGBgCgpgYGB7cn0KeApgYGAKCgpgYGB7cn0KIyBtYWtpbmcgc3VyZSB0aGUgcm93IG5hbWVzIGluIGNvbERhdGEgbWF0Y2hlcyB0byBjb2x1bW4gbmFtZXMgaW4gY291bnRzX2RhdGEKYWxsKGNvbG5hbWVzKGNvdW50cykgJWluJSByb3duYW1lcyhtZXRhKSkKCiMgYXJlIHRoZXkgaW4gdGhlIHNhbWUgb3JkZXI/CmFsbChjb2xuYW1lcyhjb3VudHMpID09IHJvd25hbWVzKG1ldGEpKQoKYGBgCgoKCmBgYHtyfQojIFN0ZXAgMjogY29uc3RydWN0IGEgREVTZXFEYXRhU2V0IG9iamVjdCAtLS0tLS0tLS0tCmRkcyA8LSBERVNlcURhdGFTZXRGcm9tTWF0cml4KGNvdW50RGF0YSA9IGNvdW50cywKICAgICAgICAgICAgICAgICAgICAgICBjb2xEYXRhID0gbWV0YSwKICAgICAgICAgICAgICAgICAgICAgICBkZXNpZ24gPSB+IGRleGFtZXRoYXNvbmUpCmRkcwojIHByZS1maWx0ZXJpbmc6IHJlbW92aW5nIHJvd3Mgd2l0aCBsb3cgZ2VuZSBjb3VudHMsIGtlZXBpbmcgcm93cyB0aGF0IGhhdmUgYXQgbGVhc3QgMTAgcmVhZHMgdG90YWwKa2VlcCA8LSByb3dTdW1zKGNvdW50cyhkZHMpKSA+PSAxMApkZHMgPC0gZGRzW2tlZXAsXQoKZGRzCgojIHNldCB0aGUgZmFjdG9yIGxldmVsCmRkcyRkZXhhbWV0aGFzb25lIDwtIHJlbGV2ZWwoZGRzJGRleGFtZXRoYXNvbmUsIHJlZiA9ICJ1bnRyZWF0ZWQiKQpgYGAKCgpgYGB7cn0KIyBTdGVwIDM6IFJ1biBERVNlcSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tCmRkcyA8LSBERVNlcShkZHMpCnJlcyA8LSByZXN1bHRzKGRkcykKYGBgCgpgYGB7cn0Kc3RyKHJlcykKYGBgCgpgYGB7cn0Kc3VtbWFyeShyZXMpCmBgYAoKCgoKCmBgYHtyfQojIGNvbnRyYXN0cwpyZXN1bHRzTmFtZXMoZGRzKQoKIyBlLmcuOiB0cmVhdGVkXzRocnMsIHRyZWF0ZWRfOGhycywgdW50cmVhdGVkCgpyZXN1bHRzKGRkcywgY29udHJhc3QgPSBjKCJkZXhhbWV0aGFzb25lIiwgInRyZWF0ZWQiLCAidW50cmVhdGVkIikpCgojIE1BIHBsb3QKcGxvdE1BKHJlcykKCmBgYAoKCmBgYHtyfQp2c2QgPC0gdnN0KGRkcywgYmxpbmQgPSBGQUxTRSkKbWF0IDwtIGFzc2F5KHZzZCkKYGBgCgpgYGB7cn0KcGxvdFBDQSh2c2QsIGludGdyb3VwID0gImRleGFtZXRoYXNvbmUiKQpgYGAKCgpgYGB7cn0KcGNhX2RhdGEgPC0gcGxvdFBDQSh2c2QsIGludGdyb3VwID0gImRleGFtZXRoYXNvbmUiLCByZXR1cm5EYXRhID0gVFJVRSkKcGVyY2VudF92YXIgPC0gcm91bmQoMTAwICogYXR0cihwY2FfZGF0YSwgInBlcmNlbnRWYXIiKSkKZ2dwbG90KHBjYV9kYXRhLCBhZXMoUEMxLCBQQzIsIGNvbG9yID0gZGV4YW1ldGhhc29uZSwgbGFiZWwgPSBuYW1lKSkgKwpnZW9tX3BvaW50KHNpemUgPSA0KSArCmdlb21fdGV4dCh2anVzdCA9IC0xKSArCnhsYWIocGFzdGUwKCJQQzE6ICIsIHBlcmNlbnRfdmFyWzFdLCAiJSB2YXJpYW5jZSIpKSArCnlsYWIocGFzdGUwKCJQQzI6ICIsIHBlcmNlbnRfdmFyWzJdLCAiJSB2YXJpYW5jZSIpKSArCnRoZW1lX21pbmltYWwoKQpgYGAKCgoKYGBge3J9CmFubm90IDwtIGRhdGEuZnJhbWUoZW5zZW1ibF9pZCA9IHJvd0RhdGEoeCkkZW5zZW1ibF9pZCwKICAgICAgICAgICAgICAgICAgICBzeW1ib2wgPSByb3dEYXRhKHgpJHN5bWJvbCwKICAgICAgICAgICAgICAgICAgICBnZW5lX25hbWUgPSByb3dEYXRhKHgpJGdlbmVfbmFtZSkKCmhlYWQoYW5ub3QpCmBgYAoKYGBge3J9CmhlYWQocmVzLCA0KQpgYGAKCgpgYGB7cn0KcmVzX2RmIDwtIHJlcyAlPiUgCiAgYXMuZGF0YS5mcmFtZSgpICU+JQogIHJvd25hbWVzX3RvX2NvbHVtbigiZW5zZW1ibF9pZCIpICU+JQogIG11dGF0ZShlbnNlbWJsX2lkID0gc3ViKCJcXC4uKiQiLCAiIiwgZW5zZW1ibF9pZCkpICU+JQogIGxlZnRfam9pbihhbm5vdCwgYnkgPSAiZW5zZW1ibF9pZCIpCmBgYAoKCgoKYGBge3J9ClZPTENBTk9fUGxvdCA8LSBmdW5jdGlvbihkZiwgdW5pdHMgPSAiaW4iLCBoZWlnaHQgPSAxNiwgd2lkdGggPSAxNiwKZmlsZW5hbWUsIGRwaSA9IDYwMCwKY29scyA9IGMoIlVQIiA9ICJmaXJlYnJpY2szIiwgIkRPV04iID0gInN0ZWVsYmx1ZSIsICJucyIgPSAiZ3JleSIpLAp5bGltID0gYygiIiwiIiksCnhsaW0gPSBjKC0yLjUsMi41KSl7CnZwMSA8LSBFbmhhbmNlZFZvbGNhbm8oZGYsCmxhYiA9IGRmJHN5bWJvbCwKeCA9ICdsb2cyRm9sZENoYW5nZScsCnkgPSAncGFkaicsIHBDdXRvZmYgPSAwLjA1LCBGQ2N1dG9mZiA9IDAuNSkKcHJpbnQodnAxKQojIGdnc2F2ZShmaWxlbmFtZSwgdW5pdHMgPSB1bml0cywgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoLCBkcGkgPSBkcGkpCnJldHVybih2cDEpCn0KYGBgCgoKYGBge3IsIGZpZy5oZWlnaHQ9OSwgZmlnLndpZHRoPTEwfQpWT0xDQU5PX1Bsb3QoZGYgPSByZXNfZGYpCmBgYAoKCgpgYGB7cn0Kc2lnX3JlcyA8LSBzdWJzZXQocmVzX2RmLCAKICAgICAgICAgICAgICAgICAgcGFkaiA8IDAuMDUgJiAKICAgICAgICAgICAgICAgICAgICBhYnMobG9nMkZvbGRDaGFuZ2UpID4gMSkKaGVhZChzaWdfcmVzKQpgYGAKCgoKYGBge3J9Cm5yb3coc2lnX3JlcykKYGBgCgoKCmBgYHtyfQpoZWFkKHNpZ19yZXNbb3JkZXIoLXNpZ19yZXMkbG9nMkZvbGRDaGFuZ2UpLCBdKQpgYGAKCgpgYGB7cn0KaGVhZChzaWdfcmVzW29yZGVyKHNpZ19yZXMkbG9nMkZvbGRDaGFuZ2UpLCBdKQpgYGAKCgoKYGBge3J9CnJlc19kZiRzaWduaWZpY2FudCA8LSBpZmVsc2UocmVzX2RmJHBhZGogPCAwLjA1ICYgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhYnMocmVzX2RmJGxvZzJGb2xkQ2hhbmdlKSA+IDEsICJ5ZXMiLCAibm8iKQoKZ2dwbG90KHJlc19kZiwgYWVzKHggPSBsb2cyRm9sZENoYW5nZSwgeSA9IC1sb2cxMChwYWRqKSwgY29sb3IgPSBzaWduaWZpY2FudCkpICsKZ2VvbV9wb2ludChhbHBoYSA9IDAuNykgKwp0aGVtZV9taW5pbWFsKCkgKwp4bGFiKCJsb2cyIGZvbGQgY2hhbmdlIikgKwp5bGFiKCItbG9nMTAgYWRqdXN0ZWQgcC12YWx1ZSIpCmBgYAoKYGBge3J9CnJlc19kZiA8LSByZXMgJT4lIAogIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4oImVuc2VtYmxfaWQiKSAlPiUgCiAgbXV0YXRlKGVuc2VtYmxfaWQgPSBzdWIoIlxcLi4qJCIsICIiLCBlbnNlbWJsX2lkKSkgJT4lIAogIGxlZnRfam9pbihhbm5vdCwgYnkgPSAiZW5zZW1ibF9pZCIpICU+JSAKICBmaWx0ZXIocGFkaiA8IDAuMDUsIAogICAgICAgICBhYnMobG9nMkZvbGRDaGFuZ2UpID4gMSkgJT4lIAogIG11dGF0ZSgKICAgIERFID0gY2FzZV93aGVuKAogICAgICBsb2cyRm9sZENoYW5nZSA+IDEgfiAiVVAiLAogICAgICBsb2cyRm9sZENoYW5nZSA8IC0xIH4gIkRPV04iCiAgICApCiAgKQoKaGVhZChyZXNfZGYpCmBgYAoKYGBge3J9CnN5bWJvbF90b19lbnMgPC0gc2V0TmFtZXMoCiAgcm93RGF0YSh4KSRlbnNlbWJsX2lkLAogIHJvd0RhdGEoeCkkc3ltYm9sCikKYGBgCgoKYGBge3IsIGV2YWw9RkFMU0V9CnBsb3RDb3VudHMoZGRzLCBnZW5lID0gIlBESzQiLCBpbnRncm91cCA9ICJkZXhhbWV0aGFzb25lIiwgbWFpbiA9ICJQREs0IikKYGBgCgoKYGBge3J9CnBsb3RDb3VudHMoZGRzLCBnZW5lID0gc3ltYm9sX3RvX2Vuc1siUERLNCJdLCBpbnRncm91cCA9ICJkZXhhbWV0aGFzb25lIiwgbWFpbiA9ICJQREs0IikKYGBgCgoKYGBge3J9CnBsb3RDb3VudHMoZGRzLCBnZW5lID0gc3ltYm9sX3RvX2Vuc1siVFA1MyJdLCBpbnRncm91cCA9ICJkZXhhbWV0aGFzb25lIiwgbWFpbiA9ICJUUDUzIikKYGBgCgojIyBDb25zdHJ1Y3QgYSBsb29wIHRvIHBsb3QgMTAgZ2VuZXMKYGBge3J9CgpgYGAKCgoKYGBge3J9CmxpYnJhcnkoZHBseXIpCgp0b3BfdXAgPC0gcmVzX2RmICU+JQogIGZpbHRlcihERSA9PSAiVVAiKSAlPiUKICBhcnJhbmdlKHBhZGopICU+JQogIHNsaWNlX2hlYWQobiA9IDIwKQoKdG9wX2Rvd24gPC0gcmVzX2RmICU+JQogIGZpbHRlcihERSA9PSAiRE9XTiIpICU+JQogIGFycmFuZ2UocGFkaikgJT4lCiAgc2xpY2VfaGVhZChuID0gMjApCgpoZWF0bWFwX2RmIDwtIGJpbmRfcm93cyh0b3BfdXAsIHRvcF9kb3duKQpgYGAKCmBgYHtyfQptYXRfc3ViIDwtIG1hdFtoZWF0bWFwX2RmJGVuc2VtYmxfaWQsICwgZHJvcCA9IEZBTFNFXQpgYGAKCmBgYHtyfQpnZW5lX2xhYmVscyA8LSBoZWF0bWFwX2RmJHN5bWJvbApnZW5lX2xhYmVsc1tpcy5uYShnZW5lX2xhYmVscykgfCBnZW5lX2xhYmVscyA9PSAiIl0gPC0gaGVhdG1hcF9kZiRlbnNlbWJsX2lkW2lzLm5hKGdlbmVfbGFiZWxzKSB8IGdlbmVfbGFiZWxzID09ICIiXQpnZW5lX2xhYmVscyA8LSBtYWtlLnVuaXF1ZShnZW5lX2xhYmVscykKCnJvd25hbWVzKG1hdF9zdWIpIDwtIGdlbmVfbGFiZWxzCmBgYAoKYGBge3J9Cm1hdF9zY2FsZWQgPC0gdChzY2FsZSh0KG1hdF9zdWIpKSkKbWF0X3NjYWxlZFtpcy5uYShtYXRfc2NhbGVkKV0gPC0gMApgYGAKCgpgYGB7cn0KYW5ub3RhdGlvbl9jb2wgPC0gZGF0YS5mcmFtZSgKICBkZXhhbWV0aGFzb25lID0gY29sRGF0YShkZHMpJGRleGFtZXRoYXNvbmUKKQoKcm93bmFtZXMoYW5ub3RhdGlvbl9jb2wpIDwtIGNvbG5hbWVzKG1hdF9zY2FsZWQpCmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD03fQpwaGVhdG1hcCgKICBtYXRfc2NhbGVkLAogIGFubm90YXRpb25fY29sID0gYW5ub3RhdGlvbl9jb2wsCiAgY2x1c3Rlcl9yb3dzID0gVFJVRSwKICBjbHVzdGVyX2NvbHMgPSBUUlVFLAogIHNob3dfcm93bmFtZXMgPSBUUlVFLAogIHNob3dfY29sbmFtZXMgPSBUUlVFLAogIGZvbnRzaXplX3JvdyA9IDgsCiAgZm9udHNpemVfY29sID0gMTAsCiAgYm9yZGVyX2NvbG9yID0gTkEsCiAgY29sb3IgPSBjb2xvclJhbXBQYWxldHRlKHJldihicmV3ZXIucGFsKG4gPSAxMSwgbmFtZSA9ICJSZEJ1IikpKSgxMDApLAogIG1haW4gPSAiVG9wIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyIKKQpgYGAKCiMgR08gdGVybXMKCmBgYHtyfQpHT19yZXMgPC0gZW5yaWNoR08oCiAgZ2VuZSA9IHJlc19kZiRzeW1ib2wsCiAgT3JnRGIgPSAib3JnLkhzLmVnLmRiIiwKICBrZXlUeXBlID0gIlNZTUJPTCIsCiAgb250ID0gIkFMTCIsCiAgcEFkanVzdE1ldGhvZCA9ICJCSCIsCiAgcXZhbHVlQ3V0b2ZmID0gMC4wNSwKICBwdmFsdWVDdXRvZmYgPSAwLjA1LAogIHJlYWRhYmxlID0gVFJVRQopCgpgYGAKCgpgYGB7cn0Kc3RyKEdPX3JlcykKYGBgCgoKYGBge3J9CmRvdHBsb3QoR09fcmVzKQpgYGAKCgpgYGB7cn0KVXBfcmVnIDwtIHJlc19kZiAlPiUgZmlsdGVyKERFID09ICJVUCIpCkRvd25fcmVnIDwtIHJlc19kZiAlPiUgZmlsdGVyKERFID09ICJET1dOIikKYGBgCgoKYGBge3J9CkdPX3Jlc191cCA8LSBlbnJpY2hHTygKICBnZW5lID0gVXBfcmVnJHN5bWJvbCwKICBPcmdEYiA9ICJvcmcuSHMuZWcuZGIiLAogIGtleVR5cGUgPSAiU1lNQk9MIiwKICBvbnQgPSAiQUxMIiwKICBwQWRqdXN0TWV0aG9kID0gIkJIIiwKICBxdmFsdWVDdXRvZmYgPSAwLjA1LAogIHB2YWx1ZUN1dG9mZiA9IDAuMDUsCiAgcmVhZGFibGUgPSBUUlVFCikKCmRvdHBsb3QoR09fcmVzX3VwKQoKYGBgCgoKCmBgYHtyfQpHT19yZXNfZG93biA8LSBlbnJpY2hHTygKICBnZW5lID0gRG93bl9yZWckc3ltYm9sLAogIE9yZ0RiID0gIm9yZy5Icy5lZy5kYiIsCiAga2V5VHlwZSA9ICJTWU1CT0wiLAogIG9udCA9ICJBTEwiLAogIHBBZGp1c3RNZXRob2QgPSAiQkgiLAogIHF2YWx1ZUN1dG9mZiA9IDAuMDUsCiAgcHZhbHVlQ3V0b2ZmID0gMC4wNSwKICByZWFkYWJsZSA9IFRSVUUKKQoKZG90cGxvdChHT19yZXNfZG93bikKYGBgCgoKCgoKIyMgTW9yZSB2aXN1YWxpemF0aW9uIHRvb2xzCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9CmVucmljaHBsb3Q6OmNuZXRwbG90KEdPX3Jlc191cCkKYGBgCgoKYGBge3IsIGZpZy5oZWlnaHQ9MjAsIGZpZy53aWR0aD0yMH0KR09fcmVzX3VwIDwtIGVucmljaHBsb3Q6OnBhaXJ3aXNlX3Rlcm1zaW0oR09fcmVzX3VwKQplbnJpY2hwbG90OjplbWFwcGxvdChHT19yZXNfdXApCmBgYAoKCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9CmVucmljaHBsb3Q6OmVtYXBwbG90X2NsdXN0ZXIoR09fcmVzX3VwKQpgYGAKCmBgYHtyfQplbnJpY2hwbG90Ojp1cHNldHBsb3QoR09fcmVzX3VwKQpgYGAKCgpgYGB7ciwgZmlnLndpZHRoPTIwLCBmaWcuaGVpZ2h0PTIwfQplbnJpY2hwbG90Ojpzc3Bsb3QoR09fcmVzX3VwKQpgYGAKCgpgYGB7ciwgZmlnLmhlaWdodD0yMCwgZmlnLndpZHRoPTd9CmVucmljaHBsb3Q6OnRyZWVwbG90KEdPX3Jlc191cCwgc2hvd0NhdGVnb3J5ID0gMTApCmBgYAoKCgoKYGBge3J9CiMjIFRvIGV4cGxvcmUKP2VucmljaEtFR0coKQpgYGAKCmBgYHtyfQo/ZW5yaWNoREFWSUQKYGBgCgoKCg==