load libraries
LOAD DATA &
SETUP
# Make sure the file name matches exactly what you have
fg_all <- read.csv("../../../fgsea_all_results.csv", stringsAsFactors = FALSE)
cat("Loaded", nrow(fg_all), "pathways from fgsea_all_results.csv\n")
Loaded 9200 pathways from fgsea_all_results.csv
# STRICT EXCLUSION LIST (Updated)
prolif_terms <- c(
"CELL_CYCLE", "MITOTIC", "G2M", "E2F", "SPINDLE",
"CHROMOSOME", "DNA_REPLICATION", "NUCLEAR_DIVISION",
"ORGANELLE_FISSION", "KINETOCHORE", "CENTROSOME",
"REPLICATION", "SEGREGATION", "DIVISION", "M_PHASE",
"KINESINS", "MEIOSIS", "OOCYTE",
"MICROTUBULE", "CYTOSKELETON", "TRAFFIC", "GOLGI", "CYCLIN",
"RECOMBINATION", "REPAIR", "REPLICATIVE", "POLO_LIKE", "CHECKPOINTS",
"TRANSCRIPTION", "S_PHASE", "ANAPHASE", "TELOPHASE", "PROPHASE",
"CYTOKINESIS", "SPINDLE_ASSEMBLY", "SPINDLE_CHECKPOINT",
"MITOTIC_SPINDLE", "MITOTIC_CHECKPOINT", "MITOTIC_G1",
"MITOTIC_S_PHASE", "MITOTIC_G2M"
)
DATA PREPARATION
FUNCTION
prepare_data <- function(fg_tbl, topN = 10, exclude_prolif = FALSE,
sig_col = "padj", sig_cutoff = 0.05) {
# 1. Filter by Significance FIRST
# We select pathways where the chosen column (padj or pval) is less than the cutoff
fg_tbl <- fg_tbl %>% filter(!!sym(sig_col) < sig_cutoff)
# 2. Filter out proliferation (optional)
if (exclude_prolif) {
fg_tbl <- fg_tbl %>% filter(!grepl(paste(prolif_terms, collapse = "|"), pathway, ignore.case = TRUE))
}
# Check if empty after filtering
if(nrow(fg_tbl) == 0) {
warning("No pathways met the significance criteria!")
return(NULL)
}
# 3. Get Top N Up and Down per database
fg_plot <- bind_rows(
fg_tbl %>% filter(dataset == "hallmark") %>% { bind_rows(slice_max(., NES, n = topN), slice_min(., NES, n = topN)) },
fg_tbl %>% filter(dataset == "kegg") %>% { bind_rows(slice_max(., NES, n = topN), slice_min(., NES, n = topN)) },
fg_tbl %>% filter(dataset == "reactome") %>% { bind_rows(slice_max(., NES, n = topN), slice_min(., NES, n = topN)) },
fg_tbl %>% filter(dataset == "go_bp") %>% { bind_rows(slice_max(., NES, n = topN), slice_min(., NES, n = topN)) }
)
if(nrow(fg_plot) == 0) return(NULL)
# 4. Format Labels
fg_plot %>%
mutate(
db_prefix = case_when(
dataset == "hallmark" ~ "HALLMARK",
dataset == "kegg" ~ "KEGG",
dataset == "reactome" ~ "REACTOME",
dataset == "go_bp" ~ "GOBP"
),
clean_pathway = gsub("^HALLMARK_|^KEGG_|^REACTOME_|^GOBP_", "", pathway),
plot_label = paste0(db_prefix, "_", clean_pathway)
) %>%
arrange(NES) %>%
mutate(plot_label = factor(plot_label, levels = unique(plot_label)))
}
PLOTTING FUNCTION
create_plot <- function(data, color_var, color_label, title_text) {
if(is.null(data)) return(NULL)
ggplot(data, aes(x = NES, y = plot_label)) +
geom_point(aes(shape = dataset, size = leadingEdgeCount, color = !!sym(color_var)), alpha = 0.9) +
geom_vline(xintercept = 0, linetype = "solid", color = "gray80", linewidth = 0.5) +
scale_color_gradientn(
colors = c("red", "orange", "blue"),
trans = "log10",
name = color_label,
guide = guide_colorbar(reverse = TRUE)
) +
scale_shape_manual(
values = c("hallmark" = 17, "kegg" = 15, "reactome" = 3, "go_bp" = 16),
guide = "none"
) +
scale_size_continuous(range = c(3, 8), name = "Leading edge genes") +
theme_minimal() +
labs(x = "Normalized Enrichment Score (NES)", y = NULL, title = title_text) +
theme(
axis.text.y = element_text(size = 14, face = "bold", color = "black"),
axis.text.x = element_text(size = 10, face = "bold", color = "black"),
axis.title.x = element_text(size = 14, face = "bold", color = "black", margin = margin(t = 10)),
plot.title = element_text(face = "bold", size = 13, hjust = 0.5),
legend.position = "right",
legend.box = "vertical",
legend.title = element_text(face = "bold", size = 10),
panel.grid.major.y = element_line(color = "gray95")
)
}
Generate Plots
(Significance Filter Applied)
# A) All Pathways (ONLY significant by padj < 0.05)
df_all_padj <- prepare_data(fg_all, exclude_prolif = FALSE, sig_col = "padj", sig_cutoff = 0.05)
if(!is.null(df_all_padj)) {
p1 <- create_plot(df_all_padj, "padj", "FDR (padj)", "Significant Pathways (FDR < 0.05)")
print(p1)
ggsave("Fig1_Sig_All_padj.png", p1, width = 20, height = 18, dpi = 300)
}

# B) All Pathways (ONLY significant by pval < 0.05)
df_all_pval <- prepare_data(fg_all, exclude_prolif = FALSE, sig_col = "pval", sig_cutoff = 0.05)
if(!is.null(df_all_pval)) {
p2 <- create_plot(df_all_pval, "pval", "P-value", "Significant Pathways (Nominal P < 0.05)")
print(p2)
ggsave("Fig2_Sig_All_pval.png", p2, width = 20, height = 18, dpi = 300)
}

# C) Non-Proliferation (ONLY significant by padj < 0.05)
df_no_prolif_padj <- prepare_data(fg_all, exclude_prolif = TRUE, sig_col = "padj", sig_cutoff = 0.05)
if(!is.null(df_no_prolif_padj)) {
p3 <- create_plot(df_no_prolif_padj, "padj", "FDR (padj)", "Significant Non-Prolif Pathways (FDR < 0.05)")
print(p3)
ggsave("Fig3_Sig_NonProlif_padj.png", p3, width = 20, height = 18, dpi = 300)
} else {
message("No Non-Proliferation pathways met FDR < 0.05 criteria.")
}

# D) Non-Proliferation (ONLY significant by pval < 0.05)
df_no_prolif_pval <- prepare_data(fg_all, exclude_prolif = TRUE, sig_col = "pval", sig_cutoff = 0.05)
if(!is.null(df_no_prolif_pval)) {
p4 <- create_plot(df_no_prolif_pval, "pval", "P-value", "Significant Non-Prolif Pathways (Nominal P < 0.05)")
print(p4)
ggsave("Fig4_Sig_NonProlif_pval.png", p4, width = 20, height = 18, dpi = 300)
}

LS0tCnRpdGxlOiAiZmdzZWEgQW5hbHlzaXMgZm9yIE1hbnVTY3JpcHRfRmViMjAyNi10b3AxMCBzaWduaWZpY2FudCBwYXRod2F5cyBvbmx5IgphdXRob3I6IE5hc2lyIE1haG1vb2QgQWJiYXNpCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHRydWUKICAgIHRoZW1lOiBqb3VybmFsCi0tLQoKCiMgbG9hZCBsaWJyYXJpZXMKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgQ3VzdG9tIEdTRUEgUGxvdHRpbmcgU2NyaXB0IC0gRk9VUiBWRVJTSU9OUwojIDEuIEFsbCBQYXRod2F5cyAocGFkaikKIyAyLiBBbGwgUGF0aHdheXMgKHAtdmFsdWUpCiMgMy4gTm9uLVByb2xpZmVyYXRpb24gKHBhZGopCiMgNC4gTm9uLVByb2xpZmVyYXRpb24gKHAtdmFsdWUpCiMKIyBTdHlsZTogQm9sZCBMYWJlbHMgKERCX1BBVEhXQVkpLCBObyBEYXRhc2V0IExlZ2VuZCwgVG9wIDMgVXAvRG93bgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZmdzZWEpCmxpYnJhcnkobXNpZ2RicikKbGlicmFyeShlbnJpY2hwbG90KQpsaWJyYXJ5KGNsdXN0ZXJQcm9maWxlcikKbGlicmFyeShnZ3JlcGVsKQoKYGBgCgoKIyBMT0FEIERBVEEgJiBTRVRVUCAKYGBge3IgbG9hZFNldXJhdH0KIyBNYWtlIHN1cmUgdGhlIGZpbGUgbmFtZSBtYXRjaGVzIGV4YWN0bHkgd2hhdCB5b3UgaGF2ZQpmZ19hbGwgPC0gcmVhZC5jc3YoIi4uLy4uLy4uL2Znc2VhX2FsbF9yZXN1bHRzLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKCmNhdCgiTG9hZGVkIiwgbnJvdyhmZ19hbGwpLCAicGF0aHdheXMgZnJvbSBmZ3NlYV9hbGxfcmVzdWx0cy5jc3ZcbiIpCgojIFNUUklDVCBFWENMVVNJT04gTElTVCAoVXBkYXRlZCkKcHJvbGlmX3Rlcm1zIDwtIGMoCiAgIkNFTExfQ1lDTEUiLCAiTUlUT1RJQyIsICJHMk0iLCAiRTJGIiwgIlNQSU5ETEUiLCAKICAiQ0hST01PU09NRSIsICJETkFfUkVQTElDQVRJT04iLCAiTlVDTEVBUl9ESVZJU0lPTiIsCiAgIk9SR0FORUxMRV9GSVNTSU9OIiwgIktJTkVUT0NIT1JFIiwgIkNFTlRST1NPTUUiLAogICJSRVBMSUNBVElPTiIsICJTRUdSRUdBVElPTiIsICJESVZJU0lPTiIsICJNX1BIQVNFIiwgCiAgIktJTkVTSU5TIiwgIk1FSU9TSVMiLCAiT09DWVRFIiwgCiAgIk1JQ1JPVFVCVUxFIiwgIkNZVE9TS0VMRVRPTiIsICJUUkFGRklDIiwgIkdPTEdJIiwgIkNZQ0xJTiIsCiAgIlJFQ09NQklOQVRJT04iLCAiUkVQQUlSIiwgIlJFUExJQ0FUSVZFIiwgIlBPTE9fTElLRSIsICJDSEVDS1BPSU5UUyIsCiAgIlRSQU5TQ1JJUFRJT04iLCAiU19QSEFTRSIsICJBTkFQSEFTRSIsICJURUxPUEhBU0UiLCAiUFJPUEhBU0UiLCAKICAiQ1lUT0tJTkVTSVMiLCAiU1BJTkRMRV9BU1NFTUJMWSIsICJTUElORExFX0NIRUNLUE9JTlQiLCAKICAiTUlUT1RJQ19TUElORExFIiwgIk1JVE9USUNfQ0hFQ0tQT0lOVCIsICJNSVRPVElDX0cxIiwgCiAgIk1JVE9USUNfU19QSEFTRSIsICJNSVRPVElDX0cyTSIKKQpgYGAKCgojIERBVEEgUFJFUEFSQVRJT04gRlVOQ1RJT04KYGBge3IsIGZpZy5oZWlnaHQ9IDYsIGZpZy53aWR0aD0gMTB9CnByZXBhcmVfZGF0YSA8LSBmdW5jdGlvbihmZ190YmwsIHRvcE4gPSAxMCwgZXhjbHVkZV9wcm9saWYgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBzaWdfY29sID0gInBhZGoiLCBzaWdfY3V0b2ZmID0gMC4wNSkgewogIAogICMgMS4gRmlsdGVyIGJ5IFNpZ25pZmljYW5jZSBGSVJTVAogICMgV2Ugc2VsZWN0IHBhdGh3YXlzIHdoZXJlIHRoZSBjaG9zZW4gY29sdW1uIChwYWRqIG9yIHB2YWwpIGlzIGxlc3MgdGhhbiB0aGUgY3V0b2ZmCiAgZmdfdGJsIDwtIGZnX3RibCAlPiUgZmlsdGVyKCEhc3ltKHNpZ19jb2wpIDwgc2lnX2N1dG9mZikKICAKICAjIDIuIEZpbHRlciBvdXQgcHJvbGlmZXJhdGlvbiAob3B0aW9uYWwpCiAgaWYgKGV4Y2x1ZGVfcHJvbGlmKSB7CiAgICBmZ190YmwgPC0gZmdfdGJsICU+JSBmaWx0ZXIoIWdyZXBsKHBhc3RlKHByb2xpZl90ZXJtcywgY29sbGFwc2UgPSAifCIpLCBwYXRod2F5LCBpZ25vcmUuY2FzZSA9IFRSVUUpKQogIH0KICAKICAjIENoZWNrIGlmIGVtcHR5IGFmdGVyIGZpbHRlcmluZwogIGlmKG5yb3coZmdfdGJsKSA9PSAwKSB7CiAgICB3YXJuaW5nKCJObyBwYXRod2F5cyBtZXQgdGhlIHNpZ25pZmljYW5jZSBjcml0ZXJpYSEiKQogICAgcmV0dXJuKE5VTEwpCiAgfQoKICAjIDMuIEdldCBUb3AgTiBVcCBhbmQgRG93biBwZXIgZGF0YWJhc2UKICBmZ19wbG90IDwtIGJpbmRfcm93cygKICAgIGZnX3RibCAlPiUgZmlsdGVyKGRhdGFzZXQgPT0gImhhbGxtYXJrIikgJT4lIHsgYmluZF9yb3dzKHNsaWNlX21heCguLCBORVMsIG4gPSB0b3BOKSwgc2xpY2VfbWluKC4sIE5FUywgbiA9IHRvcE4pKSB9LAogICAgZmdfdGJsICU+JSBmaWx0ZXIoZGF0YXNldCA9PSAia2VnZyIpICU+JSB7IGJpbmRfcm93cyhzbGljZV9tYXgoLiwgTkVTLCBuID0gdG9wTiksIHNsaWNlX21pbiguLCBORVMsIG4gPSB0b3BOKSkgfSwKICAgIGZnX3RibCAlPiUgZmlsdGVyKGRhdGFzZXQgPT0gInJlYWN0b21lIikgJT4lIHsgYmluZF9yb3dzKHNsaWNlX21heCguLCBORVMsIG4gPSB0b3BOKSwgc2xpY2VfbWluKC4sIE5FUywgbiA9IHRvcE4pKSB9LAogICAgZmdfdGJsICU+JSBmaWx0ZXIoZGF0YXNldCA9PSAiZ29fYnAiKSAlPiUgeyBiaW5kX3Jvd3Moc2xpY2VfbWF4KC4sIE5FUywgbiA9IHRvcE4pLCBzbGljZV9taW4oLiwgTkVTLCBuID0gdG9wTikpIH0KICApCiAgCiAgaWYobnJvdyhmZ19wbG90KSA9PSAwKSByZXR1cm4oTlVMTCkKCiAgIyA0LiBGb3JtYXQgTGFiZWxzCiAgZmdfcGxvdCAlPiUKICAgIG11dGF0ZSgKICAgICAgZGJfcHJlZml4ID0gY2FzZV93aGVuKAogICAgICAgIGRhdGFzZXQgPT0gImhhbGxtYXJrIiB+ICJIQUxMTUFSSyIsCiAgICAgICAgZGF0YXNldCA9PSAia2VnZyIgfiAiS0VHRyIsCiAgICAgICAgZGF0YXNldCA9PSAicmVhY3RvbWUiIH4gIlJFQUNUT01FIiwKICAgICAgICBkYXRhc2V0ID09ICJnb19icCIgfiAiR09CUCIKICAgICAgKSwKICAgICAgY2xlYW5fcGF0aHdheSA9IGdzdWIoIl5IQUxMTUFSS198XktFR0dffF5SRUFDVE9NRV98XkdPQlBfIiwgIiIsIHBhdGh3YXkpLAogICAgICBwbG90X2xhYmVsID0gcGFzdGUwKGRiX3ByZWZpeCwgIl8iLCBjbGVhbl9wYXRod2F5KQogICAgKSAlPiUKICAgIGFycmFuZ2UoTkVTKSAlPiUKICAgIG11dGF0ZShwbG90X2xhYmVsID0gZmFjdG9yKHBsb3RfbGFiZWwsIGxldmVscyA9IHVuaXF1ZShwbG90X2xhYmVsKSkpCn0KCmBgYAoKIyBQTE9UVElORyBGVU5DVElPTiAKYGBge3IsIGZpZy5oZWlnaHQ9IDYsIGZpZy53aWR0aD0gMTB9CmNyZWF0ZV9wbG90IDwtIGZ1bmN0aW9uKGRhdGEsIGNvbG9yX3ZhciwgY29sb3JfbGFiZWwsIHRpdGxlX3RleHQpIHsKICBpZihpcy5udWxsKGRhdGEpKSByZXR1cm4oTlVMTCkKICAKICBnZ3Bsb3QoZGF0YSwgYWVzKHggPSBORVMsIHkgPSBwbG90X2xhYmVsKSkgKwogICAgZ2VvbV9wb2ludChhZXMoc2hhcGUgPSBkYXRhc2V0LCBzaXplID0gbGVhZGluZ0VkZ2VDb3VudCwgY29sb3IgPSAhIXN5bShjb2xvcl92YXIpKSwgYWxwaGEgPSAwLjkpICsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gInNvbGlkIiwgY29sb3IgPSAiZ3JheTgwIiwgbGluZXdpZHRoID0gMC41KSArCgogICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKAogICAgICBjb2xvcnMgPSBjKCJyZWQiLCAib3JhbmdlIiwgImJsdWUiKSwKICAgICAgdHJhbnMgPSAibG9nMTAiLAogICAgICBuYW1lID0gY29sb3JfbGFiZWwsCiAgICAgIGd1aWRlID0gZ3VpZGVfY29sb3JiYXIocmV2ZXJzZSA9IFRSVUUpCiAgICApICsKCiAgICBzY2FsZV9zaGFwZV9tYW51YWwoCiAgICAgIHZhbHVlcyA9IGMoImhhbGxtYXJrIiA9IDE3LCAia2VnZyIgPSAxNSwgInJlYWN0b21lIiA9IDMsICJnb19icCIgPSAxNiksCiAgICAgIGd1aWRlID0gIm5vbmUiCiAgICApICsKCiAgICBzY2FsZV9zaXplX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDMsIDgpLCBuYW1lID0gIkxlYWRpbmcgZWRnZSBnZW5lcyIpICsKCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgbGFicyh4ID0gIk5vcm1hbGl6ZWQgRW5yaWNobWVudCBTY29yZSAoTkVTKSIsIHkgPSBOVUxMLCB0aXRsZSA9IHRpdGxlX3RleHQpICsKICAgIHRoZW1lKAogICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGZhY2UgPSAiYm9sZCIsIGNvbG9yID0gImJsYWNrIiksCiAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgZmFjZSA9ICJib2xkIiwgY29sb3IgPSAiYmxhY2siKSwKICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgZmFjZSA9ICJib2xkIiwgY29sb3IgPSAiYmxhY2siLCBtYXJnaW4gPSBtYXJnaW4odCA9IDEwKSksCiAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDEzLCBoanVzdCA9IDAuNSksCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICAgIGxlZ2VuZC5ib3ggPSAidmVydGljYWwiLAogICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDEwKSwKICAgICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9saW5lKGNvbG9yID0gImdyYXk5NSIpCiAgICApCn0KCmBgYAoKCiMgR2VuZXJhdGUgUGxvdHMgKFNpZ25pZmljYW5jZSBGaWx0ZXIgQXBwbGllZCkKYGBge3IsIGZpZy5oZWlnaHQ9IDE4LCBmaWcud2lkdGg9IDIwfQojIEEpIEFsbCBQYXRod2F5cyAoT05MWSBzaWduaWZpY2FudCBieSBwYWRqIDwgMC4wNSkKZGZfYWxsX3BhZGogPC0gcHJlcGFyZV9kYXRhKGZnX2FsbCwgZXhjbHVkZV9wcm9saWYgPSBGQUxTRSwgc2lnX2NvbCA9ICJwYWRqIiwgc2lnX2N1dG9mZiA9IDAuMDUpCmlmKCFpcy5udWxsKGRmX2FsbF9wYWRqKSkgewogIHAxIDwtIGNyZWF0ZV9wbG90KGRmX2FsbF9wYWRqLCAicGFkaiIsICJGRFIgKHBhZGopIiwgIlNpZ25pZmljYW50IFBhdGh3YXlzIChGRFIgPCAwLjA1KSIpCiAgcHJpbnQocDEpCiAgZ2dzYXZlKCJGaWcxX1NpZ19BbGxfcGFkai5wbmciLCBwMSwgd2lkdGggPSAyMCwgaGVpZ2h0ID0gMTgsIGRwaSA9IDMwMCkKfQoKIyBCKSBBbGwgUGF0aHdheXMgKE9OTFkgc2lnbmlmaWNhbnQgYnkgcHZhbCA8IDAuMDUpCmRmX2FsbF9wdmFsIDwtIHByZXBhcmVfZGF0YShmZ19hbGwsIGV4Y2x1ZGVfcHJvbGlmID0gRkFMU0UsIHNpZ19jb2wgPSAicHZhbCIsIHNpZ19jdXRvZmYgPSAwLjA1KQppZighaXMubnVsbChkZl9hbGxfcHZhbCkpIHsKICBwMiA8LSBjcmVhdGVfcGxvdChkZl9hbGxfcHZhbCwgInB2YWwiLCAiUC12YWx1ZSIsICJTaWduaWZpY2FudCBQYXRod2F5cyAoTm9taW5hbCBQIDwgMC4wNSkiKQogIHByaW50KHAyKQogIGdnc2F2ZSgiRmlnMl9TaWdfQWxsX3B2YWwucG5nIiwgcDIsIHdpZHRoID0gMjAsIGhlaWdodCA9IDE4LCBkcGkgPSAzMDApCn0KCiMgQykgTm9uLVByb2xpZmVyYXRpb24gKE9OTFkgc2lnbmlmaWNhbnQgYnkgcGFkaiA8IDAuMDUpCmRmX25vX3Byb2xpZl9wYWRqIDwtIHByZXBhcmVfZGF0YShmZ19hbGwsIGV4Y2x1ZGVfcHJvbGlmID0gVFJVRSwgc2lnX2NvbCA9ICJwYWRqIiwgc2lnX2N1dG9mZiA9IDAuMDUpCmlmKCFpcy5udWxsKGRmX25vX3Byb2xpZl9wYWRqKSkgewogIHAzIDwtIGNyZWF0ZV9wbG90KGRmX25vX3Byb2xpZl9wYWRqLCAicGFkaiIsICJGRFIgKHBhZGopIiwgIlNpZ25pZmljYW50IE5vbi1Qcm9saWYgUGF0aHdheXMgKEZEUiA8IDAuMDUpIikKICBwcmludChwMykKICBnZ3NhdmUoIkZpZzNfU2lnX05vblByb2xpZl9wYWRqLnBuZyIsIHAzLCB3aWR0aCA9IDIwLCBoZWlnaHQgPSAxOCwgZHBpID0gMzAwKQp9IGVsc2UgewogIG1lc3NhZ2UoIk5vIE5vbi1Qcm9saWZlcmF0aW9uIHBhdGh3YXlzIG1ldCBGRFIgPCAwLjA1IGNyaXRlcmlhLiIpCn0KCiMgRCkgTm9uLVByb2xpZmVyYXRpb24gKE9OTFkgc2lnbmlmaWNhbnQgYnkgcHZhbCA8IDAuMDUpCmRmX25vX3Byb2xpZl9wdmFsIDwtIHByZXBhcmVfZGF0YShmZ19hbGwsIGV4Y2x1ZGVfcHJvbGlmID0gVFJVRSwgc2lnX2NvbCA9ICJwdmFsIiwgc2lnX2N1dG9mZiA9IDAuMDUpCmlmKCFpcy5udWxsKGRmX25vX3Byb2xpZl9wdmFsKSkgewogIHA0IDwtIGNyZWF0ZV9wbG90KGRmX25vX3Byb2xpZl9wdmFsLCAicHZhbCIsICJQLXZhbHVlIiwgIlNpZ25pZmljYW50IE5vbi1Qcm9saWYgUGF0aHdheXMgKE5vbWluYWwgUCA8IDAuMDUpIikKICBwcmludChwNCkKICBnZ3NhdmUoIkZpZzRfU2lnX05vblByb2xpZl9wdmFsLnBuZyIsIHA0LCB3aWR0aCA9IDIwLCBoZWlnaHQgPSAxOCwgZHBpID0gMzAwKQp9CgpgYGAK