1 load libraries

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

3 PREPARE DATA FOR RADAR PLOT (WITH DATABASE PREFIX)–V1

prepare_radar_data_v1 <- function(fg_tbl, topN_per_db = 3, exclude_prolif = TRUE) {

  # A. Filter Proliferation (if requested)
  if (exclude_prolif) {
    fg_tbl <- fg_tbl %>% filter(!grepl(paste(prolif_terms, collapse = "|"), pathway, ignore.case = TRUE))
  }

  # B. Filter for significant pathways only
  fg_tbl <- fg_tbl %>% filter(pval < 0.05)

  # C. Select Top N pathways PER DATABASE (balanced)
  top_paths <- bind_rows(
    fg_tbl %>% filter(dataset == "hallmark") %>% arrange(pval) %>% slice_head(n = topN_per_db),
    fg_tbl %>% filter(dataset == "kegg") %>% arrange(pval) %>% slice_head(n = topN_per_db),
    fg_tbl %>% filter(dataset == "reactome") %>% arrange(pval) %>% slice_head(n = topN_per_db),
    fg_tbl %>% filter(dataset == "go_bp") %>% arrange(pval) %>% slice_head(n = topN_per_db)
  ) %>%
    mutate(
      log_pval = -log10(pval + 1e-15), # Transform P-value
      # Add Database Prefix
      db_prefix = case_when(
        dataset == "hallmark" ~ "HALLMARK",
        dataset == "kegg" ~ "KEGG",
        dataset == "reactome" ~ "REACTOME",
        dataset == "go_bp" ~ "GOBP"
      ),
      # Clean pathway name
      clean_pathway = gsub("^HALLMARK_|^KEGG_|^REACTOME_|^GOBP_", "", pathway),
      clean_pathway = str_trunc(clean_pathway, 25),
      # Combine: DB_PATHWAY format
      plot_label = paste0(db_prefix, "_", clean_pathway),
      direction = ifelse(NES > 0, "Up", "Down")
    ) %>%
    # D. Make unique to avoid duplicates
    mutate(plot_label = make.unique(as.character(plot_label), sep = " ")) %>%
    # E. Sort by log_pval for smooth spiral
    arrange(log_pval) %>%
    mutate(plot_label = factor(plot_label, levels = plot_label))

  return(top_paths)
}

4 PREPARE DATA FOR RADAR PLOT (BALANCED UP/DOWN FROM EACH DATABASE)-V2

prepare_radar_data_v2 <- function(fg_tbl, topN_per_db = 3, exclude_prolif = TRUE) {

  # A. Filter Proliferation (if requested)
  if (exclude_prolif) {
    fg_tbl <- fg_tbl %>% filter(!grepl(paste(prolif_terms, collapse = "|"), pathway, ignore.case = TRUE))
  }

  # B. Filter for significant pathways only
  fg_tbl <- fg_tbl %>% filter(pval < 0.05)

  # C. Select Top N UPREGULATED and DOWNREGULATED pathways PER DATABASE
  top_paths <- bind_rows(
    # Hallmark
    fg_tbl %>% filter(dataset == "hallmark", NES > 0) %>% arrange(pval) %>% slice_head(n = ceiling(topN_per_db/2)),
    fg_tbl %>% filter(dataset == "hallmark", NES < 0) %>% arrange(pval) %>% slice_head(n = floor(topN_per_db/2)),
    
    # KEGG
    fg_tbl %>% filter(dataset == "kegg", NES > 0) %>% arrange(pval) %>% slice_head(n = ceiling(topN_per_db/2)),
    fg_tbl %>% filter(dataset == "kegg", NES < 0) %>% arrange(pval) %>% slice_head(n = floor(topN_per_db/2)),
    
    # Reactome
    fg_tbl %>% filter(dataset == "reactome", NES > 0) %>% arrange(pval) %>% slice_head(n = ceiling(topN_per_db/2)),
    fg_tbl %>% filter(dataset == "reactome", NES < 0) %>% arrange(pval) %>% slice_head(n = floor(topN_per_db/2)),
    
    # GO:BP
    fg_tbl %>% filter(dataset == "go_bp", NES > 0) %>% arrange(pval) %>% slice_head(n = ceiling(topN_per_db/2)),
    fg_tbl %>% filter(dataset == "go_bp", NES < 0) %>% arrange(pval) %>% slice_head(n = floor(topN_per_db/2))
  ) %>%
    mutate(
      log_pval = -log10(pval + 1e-15),
      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),
      clean_pathway = str_trunc(clean_pathway, 25),
      plot_label = paste0(db_prefix, "_", clean_pathway),
      direction = ifelse(NES > 0, "Up", "Down")
    ) %>%
    mutate(plot_label = make.unique(as.character(plot_label), sep = " ")) %>%
    arrange(log_pval) %>%
    mutate(plot_label = factor(plot_label, levels = plot_label))

  return(top_paths)
}

4.1 GGPLOT RADAR FUNCTION (SPIRAL STYLE)

create_ggplot_radar <- function(data, title_text) {

  # Threshold line for p < 0.05 (-log10(0.05) ~= 1.3)
  threshold_val <- -log10(0.05)

  # Max limit for the plot
  max_val <- max(data$log_pval) * 1.2

  ggplot(data, aes(x = plot_label, y = log_pval)) +

    # A) The Shaded Area (Spiral Effect)
    geom_area(aes(group = 1), fill = "#DDA0DD", alpha = 0.4) +
    
    # B) The Line Border
    geom_line(aes(group = 1), color = "#800080", linewidth = 1) +

    # C) The Points (Colored by Up/Down)
    geom_point(aes(color = direction), size = 3) +
    scale_color_manual(values = c("Up" = "purple", "Down" = "blue")) +

    # D) The "P < 0.05" Central Threshold Circle
    geom_hline(yintercept = threshold_val, linetype = "dashed", color = "black", linewidth = 0.8) +
    annotate("text", x = 1, y = threshold_val, label = "p < 0.05", 
             color = "black", fontface = "bold", size = 3, vjust = -1) +

    # E) Radial Transformation
    coord_polar(start = 0, clip = "off") +

    # F) Theme Adjustments
    theme_minimal() +
    labs(
      title = title_text,
      x = NULL,
      y = "-log10(p-value)",
      color = "Regulation"
    ) +
    scale_y_continuous(limits = c(0, max_val)) +
    theme(
      axis.text.x = element_text(size = 9, face = "bold", color = "black"),
      axis.text.y = element_text(size = 8, color = "gray50"),
      panel.grid.major = element_line(color = "gray85", linetype = "dotted"),
      plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
      legend.position = "bottom",
      plot.margin = margin(t = 20, r = 20, b = 20, l = 20)
    )
}

4.2 GENERATE FIGURE 1 (Version 1 - No Proliferation)

radar_df_fig1 <- prepare_radar_data_v1(fg_all, topN_per_db = 5, exclude_prolif = TRUE)
p1 <- create_ggplot_radar(radar_df_fig1, "Top Enriched Pathways (Non-Proliferative)")

ggsave("Fig1_Radar_NoProlif_AllSig.png", p1, width = 18, height = 18, dpi = 300)
ggsave("Fig1_Radar_NoProlif_AllSig.pdf", p1, width = 18, height = 18)

print("✅ Created Figure 1: Fig1_Radar_NoProlif_AllSig.png")
[1] "✅ Created Figure 1: Fig1_Radar_NoProlif_AllSig.png"
print(p1)


radar_df_fig2 <- prepare_radar_data_v1(fg_all, topN_per_db = 5, exclude_prolif = FALSE)
p2 <- create_ggplot_radar(radar_df_fig2, "Top Enriched Pathways (Including Proliferation)")

ggsave("Fig2_Radar_WithProlif_AllSig.png", p2, width = 18, height = 18, dpi = 300)
ggsave("Fig2_Radar_WithProlif_AllSig.pdf", p2, width = 18, height = 18)

print("✅ Created Figure 2: Fig2_Radar_WithProlif_AllSig.png")
[1] "✅ Created Figure 2: Fig2_Radar_WithProlif_AllSig.png"
print(p2)

4.3 GENERATE FIGURE 3 (Version 2 - No Proliferation, Balanced Up/Down)

radar_df_fig3 <- prepare_radar_data_v2(fg_all, topN_per_db = 5, exclude_prolif = TRUE)
p3 <- create_ggplot_radar(radar_df_fig3, "Top Enriched Pathways (Non-Proliferative, Balanced)")

ggsave("Fig3_Radar_NoProlif_Balanced.png", p3, width = 18, height = 18, dpi = 300)
ggsave("Fig3_Radar_NoProlif_Balanced.pdf", p3, width = 18, height = 18)

print("✅ Created Figure 3: Fig3_Radar_NoProlif_Balanced.png")
[1] "✅ Created Figure 3: Fig3_Radar_NoProlif_Balanced.png"
print(p3)


radar_df_fig4 <- prepare_radar_data_v2(fg_all, topN_per_db = 5, exclude_prolif = FALSE)
p4 <- create_ggplot_radar(radar_df_fig4, "Top Enriched Pathways (Including Proliferation, Balanced)")

ggsave("Fig4_Radar_WithProlif_Balanced.png", p4, width = 18, height = 18, dpi = 300)
ggsave("Fig4_Radar_WithProlif_Balanced.pdf", p4, width = 18, height = 18)

print("✅ Created Figure 4: Fig4_Radar_WithProlif_Balanced.png")
[1] "✅ Created Figure 4: Fig4_Radar_WithProlif_Balanced.png"
print(p4)

LS0tCnRpdGxlOiAiR0dQTE9UMiBSQURBUiBQTE9UUyAtIEFMTCBQQVRIV0FZUyAoU2lnbmlmaWNhbnQgT25seSkiCmF1dGhvcjogTmFzaXIgTWFobW9vZCBBYmJhc2kKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogdHJ1ZQogICAgdGhlbWU6IGpvdXJuYWwKLS0tCgoKIyBsb2FkIGxpYnJhcmllcwpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBDdXN0b20gR1NFQSBQbG90dGluZyBTY3JpcHQgLSBTUElSQUwgUkFEQVIgQ0hBUlQKIyBGZWF0dXJlczoKIyAtIFJlcGxpY2F0ZXMgdGhlICJTcGlyYWwiIGxvb2sgZnJvbSByZWZlcmVuY2UKIyAtIFNvcnRzIHBhdGh3YXlzIGJ5IHNpZ25pZmljYW5jZSBmb3Igc21vb3RoIHJpc2UKIyAtIFBsb3RzIC1sb2cxMChwLXZhbHVlKSBvbiByYWRpYWwgYXhpcwojIC0gR2VuZXJhdGVzIDQgcGxvdHM6IFdpdGggYW5kIFdpdGhvdXQgUHJvbGlmZXJhdGlvbiAoMiB2ZXJzaW9ucyBlYWNoKQojIC0gSW5jbHVkZXMgRGF0YWJhc2UgUHJlZml4IChIQUxMTUFSS18sIEtFR0dfLCBldGMuKQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZmdzZWEpCmxpYnJhcnkobXNpZ2RicikKbGlicmFyeShlbnJpY2hwbG90KQpsaWJyYXJ5KGNsdXN0ZXJQcm9maWxlcikKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KHNjYWxlcykKCmBgYAoKCiMgTE9BRCBEQVRBICYgU0VUVVAgCmBgYHtyIGxvYWRTZXVyYXR9CiMgTWFrZSBzdXJlIHRoZSBmaWxlIG5hbWUgbWF0Y2hlcyBleGFjdGx5IHdoYXQgeW91IGhhdmUKZmdfYWxsIDwtIHJlYWQuY3N2KCIuLi8uLi8uLi8uLi9mZ3NlYV9hbGxfcmVzdWx0cy5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCgpjYXQoIkxvYWRlZCIsIG5yb3coZmdfYWxsKSwgInBhdGh3YXlzIGZyb20gZmdzZWFfYWxsX3Jlc3VsdHMuY3N2XG4iKQoKIyBTVFJJQ1QgRVhDTFVTSU9OIExJU1QgKFVwZGF0ZWQpCnByb2xpZl90ZXJtcyA8LSBjKAogICJDRUxMX0NZQ0xFIiwgIk1JVE9USUMiLCAiRzJNIiwgIkUyRiIsICJTUElORExFIiwgCiAgIkNIUk9NT1NPTUUiLCAiRE5BX1JFUExJQ0FUSU9OIiwgIk5VQ0xFQVJfRElWSVNJT04iLAogICJPUkdBTkVMTEVfRklTU0lPTiIsICJLSU5FVE9DSE9SRSIsICJDRU5UUk9TT01FIiwKICAiUkVQTElDQVRJT04iLCAiU0VHUkVHQVRJT04iLCAiRElWSVNJT04iLCAiTV9QSEFTRSIsIAogICJLSU5FU0lOUyIsICJNRUlPU0lTIiwgIk9PQ1lURSIsIAogICJNSUNST1RVQlVMRSIsICJDWVRPU0tFTEVUT04iLCAiVFJBRkZJQyIsICJHT0xHSSIsICJDWUNMSU4iLAogICJSRUNPTUJJTkFUSU9OIiwgIlJFUEFJUiIsICJSRVBMSUNBVElWRSIsICJQT0xPX0xJS0UiLCAiQ0hFQ0tQT0lOVFMiLAogICJUUkFOU0NSSVBUSU9OIiwgIlNfUEhBU0UiLCAiQU5BUEhBU0UiLCAiVEVMT1BIQVNFIiwgIlBST1BIQVNFIiwgCiAgIkNZVE9LSU5FU0lTIiwgIlNQSU5ETEVfQVNTRU1CTFkiLCAiU1BJTkRMRV9DSEVDS1BPSU5UIiwgCiAgIk1JVE9USUNfU1BJTkRMRSIsICJNSVRPVElDX0NIRUNLUE9JTlQiLCAiTUlUT1RJQ19HMSIsIAogICJNSVRPVElDX1NfUEhBU0UiLCAiTUlUT1RJQ19HMk0iCikKYGBgCgoKIyBQUkVQQVJFIERBVEEgRk9SIFJBREFSIFBMT1QgKFdJVEggREFUQUJBU0UgUFJFRklYKS0tVjEKYGBge3IsIGZpZy5oZWlnaHQ9IDYsIGZpZy53aWR0aD0gMTB9CnByZXBhcmVfcmFkYXJfZGF0YV92MSA8LSBmdW5jdGlvbihmZ190YmwsIHRvcE5fcGVyX2RiID0gMywgZXhjbHVkZV9wcm9saWYgPSBUUlVFKSB7CgogICMgQS4gRmlsdGVyIFByb2xpZmVyYXRpb24gKGlmIHJlcXVlc3RlZCkKICBpZiAoZXhjbHVkZV9wcm9saWYpIHsKICAgIGZnX3RibCA8LSBmZ190YmwgJT4lIGZpbHRlcighZ3JlcGwocGFzdGUocHJvbGlmX3Rlcm1zLCBjb2xsYXBzZSA9ICJ8IiksIHBhdGh3YXksIGlnbm9yZS5jYXNlID0gVFJVRSkpCiAgfQoKICAjIEIuIEZpbHRlciBmb3Igc2lnbmlmaWNhbnQgcGF0aHdheXMgb25seQogIGZnX3RibCA8LSBmZ190YmwgJT4lIGZpbHRlcihwdmFsIDwgMC4wNSkKCiAgIyBDLiBTZWxlY3QgVG9wIE4gcGF0aHdheXMgUEVSIERBVEFCQVNFIChiYWxhbmNlZCkKICB0b3BfcGF0aHMgPC0gYmluZF9yb3dzKAogICAgZmdfdGJsICU+JSBmaWx0ZXIoZGF0YXNldCA9PSAiaGFsbG1hcmsiKSAlPiUgYXJyYW5nZShwdmFsKSAlPiUgc2xpY2VfaGVhZChuID0gdG9wTl9wZXJfZGIpLAogICAgZmdfdGJsICU+JSBmaWx0ZXIoZGF0YXNldCA9PSAia2VnZyIpICU+JSBhcnJhbmdlKHB2YWwpICU+JSBzbGljZV9oZWFkKG4gPSB0b3BOX3Blcl9kYiksCiAgICBmZ190YmwgJT4lIGZpbHRlcihkYXRhc2V0ID09ICJyZWFjdG9tZSIpICU+JSBhcnJhbmdlKHB2YWwpICU+JSBzbGljZV9oZWFkKG4gPSB0b3BOX3Blcl9kYiksCiAgICBmZ190YmwgJT4lIGZpbHRlcihkYXRhc2V0ID09ICJnb19icCIpICU+JSBhcnJhbmdlKHB2YWwpICU+JSBzbGljZV9oZWFkKG4gPSB0b3BOX3Blcl9kYikKICApICU+JQogICAgbXV0YXRlKAogICAgICBsb2dfcHZhbCA9IC1sb2cxMChwdmFsICsgMWUtMTUpLCAjIFRyYW5zZm9ybSBQLXZhbHVlCiAgICAgICMgQWRkIERhdGFiYXNlIFByZWZpeAogICAgICBkYl9wcmVmaXggPSBjYXNlX3doZW4oCiAgICAgICAgZGF0YXNldCA9PSAiaGFsbG1hcmsiIH4gIkhBTExNQVJLIiwKICAgICAgICBkYXRhc2V0ID09ICJrZWdnIiB+ICJLRUdHIiwKICAgICAgICBkYXRhc2V0ID09ICJyZWFjdG9tZSIgfiAiUkVBQ1RPTUUiLAogICAgICAgIGRhdGFzZXQgPT0gImdvX2JwIiB+ICJHT0JQIgogICAgICApLAogICAgICAjIENsZWFuIHBhdGh3YXkgbmFtZQogICAgICBjbGVhbl9wYXRod2F5ID0gZ3N1YigiXkhBTExNQVJLX3xeS0VHR198XlJFQUNUT01FX3xeR09CUF8iLCAiIiwgcGF0aHdheSksCiAgICAgIGNsZWFuX3BhdGh3YXkgPSBzdHJfdHJ1bmMoY2xlYW5fcGF0aHdheSwgMjUpLAogICAgICAjIENvbWJpbmU6IERCX1BBVEhXQVkgZm9ybWF0CiAgICAgIHBsb3RfbGFiZWwgPSBwYXN0ZTAoZGJfcHJlZml4LCAiXyIsIGNsZWFuX3BhdGh3YXkpLAogICAgICBkaXJlY3Rpb24gPSBpZmVsc2UoTkVTID4gMCwgIlVwIiwgIkRvd24iKQogICAgKSAlPiUKICAgICMgRC4gTWFrZSB1bmlxdWUgdG8gYXZvaWQgZHVwbGljYXRlcwogICAgbXV0YXRlKHBsb3RfbGFiZWwgPSBtYWtlLnVuaXF1ZShhcy5jaGFyYWN0ZXIocGxvdF9sYWJlbCksIHNlcCA9ICIgIikpICU+JQogICAgIyBFLiBTb3J0IGJ5IGxvZ19wdmFsIGZvciBzbW9vdGggc3BpcmFsCiAgICBhcnJhbmdlKGxvZ19wdmFsKSAlPiUKICAgIG11dGF0ZShwbG90X2xhYmVsID0gZmFjdG9yKHBsb3RfbGFiZWwsIGxldmVscyA9IHBsb3RfbGFiZWwpKQoKICByZXR1cm4odG9wX3BhdGhzKQp9CmBgYAoKCiMgUFJFUEFSRSBEQVRBIEZPUiBSQURBUiBQTE9UIChCQUxBTkNFRCBVUC9ET1dOIEZST00gRUFDSCBEQVRBQkFTRSktVjIKYGBge3IsIGZpZy5oZWlnaHQ9IDYsIGZpZy53aWR0aD0gOH0KcHJlcGFyZV9yYWRhcl9kYXRhX3YyIDwtIGZ1bmN0aW9uKGZnX3RibCwgdG9wTl9wZXJfZGIgPSAzLCBleGNsdWRlX3Byb2xpZiA9IFRSVUUpIHsKCiAgIyBBLiBGaWx0ZXIgUHJvbGlmZXJhdGlvbiAoaWYgcmVxdWVzdGVkKQogIGlmIChleGNsdWRlX3Byb2xpZikgewogICAgZmdfdGJsIDwtIGZnX3RibCAlPiUgZmlsdGVyKCFncmVwbChwYXN0ZShwcm9saWZfdGVybXMsIGNvbGxhcHNlID0gInwiKSwgcGF0aHdheSwgaWdub3JlLmNhc2UgPSBUUlVFKSkKICB9CgogICMgQi4gRmlsdGVyIGZvciBzaWduaWZpY2FudCBwYXRod2F5cyBvbmx5CiAgZmdfdGJsIDwtIGZnX3RibCAlPiUgZmlsdGVyKHB2YWwgPCAwLjA1KQoKICAjIEMuIFNlbGVjdCBUb3AgTiBVUFJFR1VMQVRFRCBhbmQgRE9XTlJFR1VMQVRFRCBwYXRod2F5cyBQRVIgREFUQUJBU0UKICB0b3BfcGF0aHMgPC0gYmluZF9yb3dzKAogICAgIyBIYWxsbWFyawogICAgZmdfdGJsICU+JSBmaWx0ZXIoZGF0YXNldCA9PSAiaGFsbG1hcmsiLCBORVMgPiAwKSAlPiUgYXJyYW5nZShwdmFsKSAlPiUgc2xpY2VfaGVhZChuID0gY2VpbGluZyh0b3BOX3Blcl9kYi8yKSksCiAgICBmZ190YmwgJT4lIGZpbHRlcihkYXRhc2V0ID09ICJoYWxsbWFyayIsIE5FUyA8IDApICU+JSBhcnJhbmdlKHB2YWwpICU+JSBzbGljZV9oZWFkKG4gPSBmbG9vcih0b3BOX3Blcl9kYi8yKSksCiAgICAKICAgICMgS0VHRwogICAgZmdfdGJsICU+JSBmaWx0ZXIoZGF0YXNldCA9PSAia2VnZyIsIE5FUyA+IDApICU+JSBhcnJhbmdlKHB2YWwpICU+JSBzbGljZV9oZWFkKG4gPSBjZWlsaW5nKHRvcE5fcGVyX2RiLzIpKSwKICAgIGZnX3RibCAlPiUgZmlsdGVyKGRhdGFzZXQgPT0gImtlZ2ciLCBORVMgPCAwKSAlPiUgYXJyYW5nZShwdmFsKSAlPiUgc2xpY2VfaGVhZChuID0gZmxvb3IodG9wTl9wZXJfZGIvMikpLAogICAgCiAgICAjIFJlYWN0b21lCiAgICBmZ190YmwgJT4lIGZpbHRlcihkYXRhc2V0ID09ICJyZWFjdG9tZSIsIE5FUyA+IDApICU+JSBhcnJhbmdlKHB2YWwpICU+JSBzbGljZV9oZWFkKG4gPSBjZWlsaW5nKHRvcE5fcGVyX2RiLzIpKSwKICAgIGZnX3RibCAlPiUgZmlsdGVyKGRhdGFzZXQgPT0gInJlYWN0b21lIiwgTkVTIDwgMCkgJT4lIGFycmFuZ2UocHZhbCkgJT4lIHNsaWNlX2hlYWQobiA9IGZsb29yKHRvcE5fcGVyX2RiLzIpKSwKICAgIAogICAgIyBHTzpCUAogICAgZmdfdGJsICU+JSBmaWx0ZXIoZGF0YXNldCA9PSAiZ29fYnAiLCBORVMgPiAwKSAlPiUgYXJyYW5nZShwdmFsKSAlPiUgc2xpY2VfaGVhZChuID0gY2VpbGluZyh0b3BOX3Blcl9kYi8yKSksCiAgICBmZ190YmwgJT4lIGZpbHRlcihkYXRhc2V0ID09ICJnb19icCIsIE5FUyA8IDApICU+JSBhcnJhbmdlKHB2YWwpICU+JSBzbGljZV9oZWFkKG4gPSBmbG9vcih0b3BOX3Blcl9kYi8yKSkKICApICU+JQogICAgbXV0YXRlKAogICAgICBsb2dfcHZhbCA9IC1sb2cxMChwdmFsICsgMWUtMTUpLAogICAgICBkYl9wcmVmaXggPSBjYXNlX3doZW4oCiAgICAgICAgZGF0YXNldCA9PSAiaGFsbG1hcmsiIH4gIkhBTExNQVJLIiwKICAgICAgICBkYXRhc2V0ID09ICJrZWdnIiB+ICJLRUdHIiwKICAgICAgICBkYXRhc2V0ID09ICJyZWFjdG9tZSIgfiAiUkVBQ1RPTUUiLAogICAgICAgIGRhdGFzZXQgPT0gImdvX2JwIiB+ICJHT0JQIgogICAgICApLAogICAgICBjbGVhbl9wYXRod2F5ID0gZ3N1YigiXkhBTExNQVJLX3xeS0VHR198XlJFQUNUT01FX3xeR09CUF8iLCAiIiwgcGF0aHdheSksCiAgICAgIGNsZWFuX3BhdGh3YXkgPSBzdHJfdHJ1bmMoY2xlYW5fcGF0aHdheSwgMjUpLAogICAgICBwbG90X2xhYmVsID0gcGFzdGUwKGRiX3ByZWZpeCwgIl8iLCBjbGVhbl9wYXRod2F5KSwKICAgICAgZGlyZWN0aW9uID0gaWZlbHNlKE5FUyA+IDAsICJVcCIsICJEb3duIikKICAgICkgJT4lCiAgICBtdXRhdGUocGxvdF9sYWJlbCA9IG1ha2UudW5pcXVlKGFzLmNoYXJhY3RlcihwbG90X2xhYmVsKSwgc2VwID0gIiAiKSkgJT4lCiAgICBhcnJhbmdlKGxvZ19wdmFsKSAlPiUKICAgIG11dGF0ZShwbG90X2xhYmVsID0gZmFjdG9yKHBsb3RfbGFiZWwsIGxldmVscyA9IHBsb3RfbGFiZWwpKQoKICByZXR1cm4odG9wX3BhdGhzKQp9CmBgYAoKCgojIyBHR1BMT1QgUkFEQVIgRlVOQ1RJT04gKFNQSVJBTCBTVFlMRSkKYGBge3IsIGZpZy5oZWlnaHQ9IDYsIGZpZy53aWR0aD0gMTB9CmNyZWF0ZV9nZ3Bsb3RfcmFkYXIgPC0gZnVuY3Rpb24oZGF0YSwgdGl0bGVfdGV4dCkgewoKICAjIFRocmVzaG9sZCBsaW5lIGZvciBwIDwgMC4wNSAoLWxvZzEwKDAuMDUpIH49IDEuMykKICB0aHJlc2hvbGRfdmFsIDwtIC1sb2cxMCgwLjA1KQoKICAjIE1heCBsaW1pdCBmb3IgdGhlIHBsb3QKICBtYXhfdmFsIDwtIG1heChkYXRhJGxvZ19wdmFsKSAqIDEuMgoKICBnZ3Bsb3QoZGF0YSwgYWVzKHggPSBwbG90X2xhYmVsLCB5ID0gbG9nX3B2YWwpKSArCgogICAgIyBBKSBUaGUgU2hhZGVkIEFyZWEgKFNwaXJhbCBFZmZlY3QpCiAgICBnZW9tX2FyZWEoYWVzKGdyb3VwID0gMSksIGZpbGwgPSAiI0REQTBERCIsIGFscGhhID0gMC40KSArCiAgICAKICAgICMgQikgVGhlIExpbmUgQm9yZGVyCiAgICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gMSksIGNvbG9yID0gIiM4MDAwODAiLCBsaW5ld2lkdGggPSAxKSArCgogICAgIyBDKSBUaGUgUG9pbnRzIChDb2xvcmVkIGJ5IFVwL0Rvd24pCiAgICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGRpcmVjdGlvbiksIHNpemUgPSAzKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiVXAiID0gInB1cnBsZSIsICJEb3duIiA9ICJibHVlIikpICsKCiAgICAjIEQpIFRoZSAiUCA8IDAuMDUiIENlbnRyYWwgVGhyZXNob2xkIENpcmNsZQogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gdGhyZXNob2xkX3ZhbCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiYmxhY2siLCBsaW5ld2lkdGggPSAwLjgpICsKICAgIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSB0aHJlc2hvbGRfdmFsLCBsYWJlbCA9ICJwIDwgMC4wNSIsIAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBmb250ZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDMsIHZqdXN0ID0gLTEpICsKCiAgICAjIEUpIFJhZGlhbCBUcmFuc2Zvcm1hdGlvbgogICAgY29vcmRfcG9sYXIoc3RhcnQgPSAwLCBjbGlwID0gIm9mZiIpICsKCiAgICAjIEYpIFRoZW1lIEFkanVzdG1lbnRzCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgbGFicygKICAgICAgdGl0bGUgPSB0aXRsZV90ZXh0LAogICAgICB4ID0gTlVMTCwKICAgICAgeSA9ICItbG9nMTAocC12YWx1ZSkiLAogICAgICBjb2xvciA9ICJSZWd1bGF0aW9uIgogICAgKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCBtYXhfdmFsKSkgKwogICAgdGhlbWUoCiAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LCBmYWNlID0gImJvbGQiLCBjb2xvciA9ICJibGFjayIpLAogICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCwgY29sb3IgPSAiZ3JheTUwIiksCiAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiZ3JheTg1IiwgbGluZXR5cGUgPSAiZG90dGVkIiksCiAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNCksCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbih0ID0gMjAsIHIgPSAyMCwgYiA9IDIwLCBsID0gMjApCiAgICApCn0KCmBgYAoKCiMjIEdFTkVSQVRFIEZJR1VSRSAxIChWZXJzaW9uIDEgLSBObyBQcm9saWZlcmF0aW9uKQpgYGB7ciwgZmlnLmhlaWdodD0gMTgsIGZpZy53aWR0aD0gMTh9CnJhZGFyX2RmX2ZpZzEgPC0gcHJlcGFyZV9yYWRhcl9kYXRhX3YxKGZnX2FsbCwgdG9wTl9wZXJfZGIgPSA1LCBleGNsdWRlX3Byb2xpZiA9IFRSVUUpCnAxIDwtIGNyZWF0ZV9nZ3Bsb3RfcmFkYXIocmFkYXJfZGZfZmlnMSwgIlRvcCBFbnJpY2hlZCBQYXRod2F5cyAoTm9uLVByb2xpZmVyYXRpdmUpIikKCmdnc2F2ZSgiRmlnMV9SYWRhcl9Ob1Byb2xpZl9BbGxTaWcucG5nIiwgcDEsIHdpZHRoID0gMTgsIGhlaWdodCA9IDE4LCBkcGkgPSAzMDApCmdnc2F2ZSgiRmlnMV9SYWRhcl9Ob1Byb2xpZl9BbGxTaWcucGRmIiwgcDEsIHdpZHRoID0gMTgsIGhlaWdodCA9IDE4KQoKcHJpbnQoIuKchSBDcmVhdGVkIEZpZ3VyZSAxOiBGaWcxX1JhZGFyX05vUHJvbGlmX0FsbFNpZy5wbmciKQpwcmludChwMSkKCnJhZGFyX2RmX2ZpZzIgPC0gcHJlcGFyZV9yYWRhcl9kYXRhX3YxKGZnX2FsbCwgdG9wTl9wZXJfZGIgPSA1LCBleGNsdWRlX3Byb2xpZiA9IEZBTFNFKQpwMiA8LSBjcmVhdGVfZ2dwbG90X3JhZGFyKHJhZGFyX2RmX2ZpZzIsICJUb3AgRW5yaWNoZWQgUGF0aHdheXMgKEluY2x1ZGluZyBQcm9saWZlcmF0aW9uKSIpCgpnZ3NhdmUoIkZpZzJfUmFkYXJfV2l0aFByb2xpZl9BbGxTaWcucG5nIiwgcDIsIHdpZHRoID0gMTgsIGhlaWdodCA9IDE4LCBkcGkgPSAzMDApCmdnc2F2ZSgiRmlnMl9SYWRhcl9XaXRoUHJvbGlmX0FsbFNpZy5wZGYiLCBwMiwgd2lkdGggPSAxOCwgaGVpZ2h0ID0gMTgpCgpwcmludCgi4pyFIENyZWF0ZWQgRmlndXJlIDI6IEZpZzJfUmFkYXJfV2l0aFByb2xpZl9BbGxTaWcucG5nIikKcHJpbnQocDIpCgpgYGAKCiMjIEdFTkVSQVRFIEZJR1VSRSAzIChWZXJzaW9uIDIgLSBObyBQcm9saWZlcmF0aW9uLCBCYWxhbmNlZCBVcC9Eb3duKQpgYGB7ciwgZmlnLmhlaWdodD0gMTgsIGZpZy53aWR0aD0gMTh9CnJhZGFyX2RmX2ZpZzMgPC0gcHJlcGFyZV9yYWRhcl9kYXRhX3YyKGZnX2FsbCwgdG9wTl9wZXJfZGIgPSA1LCBleGNsdWRlX3Byb2xpZiA9IFRSVUUpCnAzIDwtIGNyZWF0ZV9nZ3Bsb3RfcmFkYXIocmFkYXJfZGZfZmlnMywgIlRvcCBFbnJpY2hlZCBQYXRod2F5cyAoTm9uLVByb2xpZmVyYXRpdmUsIEJhbGFuY2VkKSIpCgpnZ3NhdmUoIkZpZzNfUmFkYXJfTm9Qcm9saWZfQmFsYW5jZWQucG5nIiwgcDMsIHdpZHRoID0gMTgsIGhlaWdodCA9IDE4LCBkcGkgPSAzMDApCmdnc2F2ZSgiRmlnM19SYWRhcl9Ob1Byb2xpZl9CYWxhbmNlZC5wZGYiLCBwMywgd2lkdGggPSAxOCwgaGVpZ2h0ID0gMTgpCgpwcmludCgi4pyFIENyZWF0ZWQgRmlndXJlIDM6IEZpZzNfUmFkYXJfTm9Qcm9saWZfQmFsYW5jZWQucG5nIikKcHJpbnQocDMpCgpyYWRhcl9kZl9maWc0IDwtIHByZXBhcmVfcmFkYXJfZGF0YV92MihmZ19hbGwsIHRvcE5fcGVyX2RiID0gNSwgZXhjbHVkZV9wcm9saWYgPSBGQUxTRSkKcDQgPC0gY3JlYXRlX2dncGxvdF9yYWRhcihyYWRhcl9kZl9maWc0LCAiVG9wIEVucmljaGVkIFBhdGh3YXlzIChJbmNsdWRpbmcgUHJvbGlmZXJhdGlvbiwgQmFsYW5jZWQpIikKCmdnc2F2ZSgiRmlnNF9SYWRhcl9XaXRoUHJvbGlmX0JhbGFuY2VkLnBuZyIsIHA0LCB3aWR0aCA9IDE4LCBoZWlnaHQgPSAxOCwgZHBpID0gMzAwKQpnZ3NhdmUoIkZpZzRfUmFkYXJfV2l0aFByb2xpZl9CYWxhbmNlZC5wZGYiLCBwNCwgd2lkdGggPSAxOCwgaGVpZ2h0ID0gMTgpCgpwcmludCgi4pyFIENyZWF0ZWQgRmlndXJlIDQ6IEZpZzRfUmFkYXJfV2l0aFByb2xpZl9CYWxhbmNlZC5wbmciKQpwcmludChwNCkKCmBgYAoKCgoK