1. Load Libraries

2. load seurat object

#Load Seurat Object
All_samples_Merged <- readRDS("/home/nabbasi/isilon/PHD_3rd_YEAR_Analysis/0-Seurat_RDS_OBJECT_FINAL/All_samples_Merged_Harmony_integrated_Cell_line_renamed_03-07-2025.rds")


All_samples_Merged
An object of class Seurat 
62900 features across 49305 samples within 6 assays 
Active assay: SCT (26176 features, 3000 variable features)
 3 layers present: counts, data, scale.data
 5 other assays present: RNA, ADT, prediction.score.celltype.l1, prediction.score.celltype.l2, prediction.score.celltype.l3
 5 dimensional reductions calculated: integrated_dr, ref.umap, pca, umap, harmony

3. Set Up Identifiers for Clustering

# Assign cluster identities to the Seurat object
Idents(All_samples_Merged) <- "seurat_clusters"

DimPlot(All_samples_Merged, reduction = "umap", group.by = "cell_line",label = T, label.box = T)

DimPlot(All_samples_Merged, reduction = "umap", group.by = "seurat_clusters",label = T, label.box = T)

4. Use FindAllMarkers() for DE on RNA assay

# Load necessary libraries
library(Seurat)

DefaultAssay(All_samples_Merged) <- "RNA"

All_samples_Merged <- NormalizeData(
  All_samples_Merged, 
  assay = "RNA", 
  normalization.method = "LogNormalize", 
  scale.factor = 10000
)

Idents(All_samples_Merged) <- "seurat_clusters"

all_markers <- FindAllMarkers(
  object = All_samples_Merged,
  assay = "RNA",
  logfc.threshold = 0,
  min.pct = 0,
  test.use = "wilcox",
  only.pos = FALSE,
  return.thresh = 1 # Keep all genes, don't filter by p-value
)

5. Load Gene Sets from MSigDB

library(Seurat)
library(dplyr)
library(purrr)
library(fgsea)
library(msigdbr)
library(ggplot2)
library(stringr)
library(forcats)

# 2. Load Gene Sets from MSigDB (your exact code)

# Hallmark (no subcollection needed)
hallmark_sets <- msigdbr(species = "Homo sapiens", category = "H") %>%
  split(x = .$gene_symbol, f = .$gs_name)
Avis : The `category` argument of `msigdbr()` is deprecated as of msigdbr 10.0.0.
Please use the `collection` argument instead.
# KEGG legacy pathways
kegg_sets <- msigdbr(
    species      = "Homo sapiens",
    category     = "C2",
    subcollection = "CP:KEGG_LEGACY"
  ) %>%
  split(x = .$gene_symbol, f = .$gs_name)

# Reactome pathways
reactome_sets <- msigdbr(
    species      = "Homo sapiens",
    category     = "C2",
    subcollection = "CP:REACTOME"
  ) %>%
  split(x = .$gene_symbol, f = .$gs_name)

# Immunologic signatures
c7_sets <- msigdbr(species = "Homo sapiens", category = "C7") %>%
  split(x = .$gene_symbol, f = .$gs_name)

# GO Biological Process, CC, MF
c5_bp <- msigdbr(species = "Homo sapiens", category = "C5", subcollection = "BP") %>%
  split(x = .$gene_symbol, f = .$gs_name)


# Combine all sets
msigdb_sets <- list(
  Hallmark = hallmark_sets,
  KEGG     = kegg_sets,
  Reactome = reactome_sets,
  C7       = c7_sets,
  GO_BP    = c5_bp
)

4. Run GSEA per Cluster using DE Files


# 3. Prepare output list for storing FGSEA results
gsea_all <- list()

# 4. Get unique clusters from all_markers
clusters <- unique(all_markers$cluster)

# 5. Loop over each cluster and run FGSEA
for (cluster_id in clusters) {
  
  cat("Processing cluster:", cluster_id, "\n")
  
  # Subset DE genes for cluster vs rest
  de_df <- all_markers %>%
    filter(cluster == cluster_id) %>%
    filter(!is.na(avg_log2FC))
  
  # Create named vector ranked by avg_log2FC (descending)
  ranked_genes <- deframe(de_df %>% select(gene, avg_log2FC))
  ranked_genes <- sort(ranked_genes, decreasing = TRUE)
  
  # Run FGSEA on each MSigDB collection
  for (db_name in names(msigdb_sets)) {
    fgsea_res <- fgsea(
      pathways = msigdb_sets[[db_name]],
      stats = ranked_genes,
      minSize = 10,
      maxSize = 300,
      nperm = 10000
    )
    
    if (nrow(fgsea_res) > 0) {
      fgsea_res$cluster <- cluster_id
      fgsea_res$database <- db_name
      
      # Save in list with unique name
      gsea_all[[paste0("Cluster_", cluster_id, "_", db_name)]] <- fgsea_res
    }
  }
}
Processing cluster: 0 
Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.37% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.37% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.37% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.37% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.37% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Processing cluster: 1 
Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.39% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.39% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.39% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.39% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.39% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Processing cluster: 2 
Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Processing cluster: 3 
Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.42% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.42% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.42% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.42% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.42% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Processing cluster: 4 
Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.4% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.4% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.4% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.4% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.4% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Processing cluster: 5 
Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : There were 3 pathways for which P-values were not calculated properly due to unbalanced gene-level statistic valuesAvis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Processing cluster: 6 
Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.4% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.4% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.4% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.4% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.4% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Processing cluster: 7 
Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Processing cluster: 8 
Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Processing cluster: 9 
Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Processing cluster: 10 
Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.42% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.42% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.42% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.42% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.42% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Processing cluster: 11 
Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.43% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : There were 15 pathways for which P-values were not calculated properly due to unbalanced gene-level statistic valuesAvis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.43% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.43% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : There were 18 pathways for which P-values were not calculated properly due to unbalanced gene-level statistic valuesAvis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.43% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : There were 15 pathways for which P-values were not calculated properly due to unbalanced gene-level statistic valuesAvis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.43% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : There were 98 pathways for which P-values were not calculated properly due to unbalanced gene-level statistic values
Processing cluster: 12 
Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : There were 14 pathways for which P-values were not calculated properly due to unbalanced gene-level statistic valuesAvis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : There were 6 pathways for which P-values were not calculated properly due to unbalanced gene-level statistic valuesAvis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : There were 129 pathways for which P-values were not calculated properly due to unbalanced gene-level statistic valuesAvis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : There were 2517 pathways for which P-values were not calculated properly due to unbalanced gene-level statistic valuesAvis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : There were 198 pathways for which P-values were not calculated properly due to unbalanced gene-level statistic values
Processing cluster: 13 
Avis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : There were 18 pathways for which P-values were not calculated properly due to unbalanced gene-level statistic valuesAvis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : There were 16 pathways for which P-values were not calculated properly due to unbalanced gene-level statistic valuesAvis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : There were 110 pathways for which P-values were not calculated properly due to unbalanced gene-level statistic valuesAvis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : There were 3342 pathways for which P-values were not calculated properly due to unbalanced gene-level statistic valuesAvis : You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.Avis : There are ties in the preranked stats (0.41% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.Avis : There were 368 pathways for which P-values were not calculated properly due to unbalanced gene-level statistic values
setwd("/isilon/homes/nabbasi/PHD_3rd_YEAR_Analysis/5-Clusters_vs_Control_fgsea/fgsea_on_findAllMarkers")

Combine and Save All GSEA Results

# 6. Combine all GSEA results into one dataframe
gsea_df <- bind_rows(gsea_all)

# 7. Flatten leadingEdge list column into a semicolon-separated string
gsea_df <- gsea_df %>%
  mutate(leadingEdge = map_chr(leadingEdge, ~ paste(.x, collapse = ";")))

# 8. Save combined results (optional)
write.csv(gsea_df, "GSEA_MSigDB_Results_Clusterwise_findAllMarkers_used.csv", row.names = FALSE)

# 9. Create folders and save cluster-wise results separately
gsea_by_cluster <- split(gsea_df, gsea_df$cluster)

for (cluster_id in names(gsea_by_cluster)) {
  folder_name <- paste0("Cluster_", cluster_id)
  
  if (!dir.exists(folder_name)) {
    dir.create(folder_name)
  }
  
  file_path <- file.path(folder_name, paste0("GSEA_Cluster_", cluster_id, ".csv"))
  write.csv(gsea_by_cluster[[cluster_id]], file = file_path, row.names = FALSE)
}

Combine and Save All GSEA Results

# 10. Plot top GSEA pathways per cluster & collection (top 3 per cluster/db, padj<0.05)
top_terms <- gsea_df %>%
  filter(padj < 0.05) %>%
  group_by(cluster, database) %>%
  slice_max(NES, n = 10, with_ties = FALSE) %>%
  ungroup()

# Clean pathway names
top_terms$pathway <- gsub("GO_|REACTOME_|KEGG_", "", top_terms$pathway)
top_terms$pathway <- gsub("_", " ", top_terms$pathway)
top_terms$pathway <- str_to_title(top_terms$pathway)
top_terms$pathway <- str_trunc(top_terms$pathway, width = 60)

# Plot using ggplot2
p1 <- ggplot(top_terms, aes(x = fct_reorder(pathway, NES), y = NES, fill = database)) +
  geom_col(width = 0.9) +
  coord_flip() +
  facet_grid(database ~ cluster, scales = "free_y", space = "free") +
  geom_hline(yintercept = 0, linetype = "dashed", color = "gray50") +
  labs(
    x = "Pathway",
    y = "Normalized Enrichment Score (NES)",
    title = "Top GSEA Pathways per Cluster",
    fill = "Database"
  ) +
  scale_fill_brewer(palette = "Set2") +
  theme_minimal(base_size = 16) +
  theme(
    strip.text = element_text(face = "bold", size = 16),
    strip.background = element_rect(fill = "gray90", color = "black"),
    strip.placement = "outside",
    legend.position = "bottom",
    axis.text.y = element_text(face = "bold", size = 13),
    axis.text.x = element_text(size = 14),
    panel.spacing = unit(1, "lines"),
    panel.border = element_rect(color = "black", fill = NA, size = 1.5)
  )

 ggsave("Top_GSEA_Pathways_Per_Cluster1.pdf", p, width = 30, height = 58, limitsize = FALSE)

p1

Combine and Save All GSEA Results

library(ggplot2)
library(ggforce)
library(forcats)
library(dplyr)
library(stringr)

# Force cluster order
top_terms$cluster <- factor(top_terms$cluster, levels = as.character(0:13))

# Clean and shorten pathway names
top_terms <- top_terms %>%
  mutate(
    pathway = gsub("GO_|REACTOME_|KEGG_", "", pathway),
    pathway = gsub("_", " ", pathway),
    pathway = str_to_title(pathway),
    pathway = str_trunc(pathway, width = 60)
  )

# Add direction column
top_terms <- top_terms %>%
  mutate(direction = ifelse(NES > 0, "Upregulated", "Downregulated"))

# Use direction and database together for color
top_terms$direction_db <- interaction(top_terms$direction, top_terms$database, sep = "_")

# Define custom colors for each direction+db combo (optional: customize as you like)
n_colors <- length(unique(top_terms$direction_db))
palette <- scales::hue_pal()(n_colors)
names(palette) <- unique(top_terms$direction_db)

# Plot
p2 <- ggplot(top_terms, aes(x = fct_reorder(pathway, NES), y = NES, fill = direction_db)) +
  geom_col(width = 0.9) +
  coord_flip() +
  facet_grid(database ~ cluster, scales = "free_y", space = "free") +
  geom_hline(yintercept = 0, linetype = "dashed", color = "gray50") +
  labs(
    x = "Pathway",
    y = "Normalized Enrichment Score (NES)",
    title = "Top GSEA Pathways per Cluster",
    fill = "Direction + DB"
  ) +
  scale_fill_manual(values = palette) +
  theme_minimal(base_size = 16) +
  theme(
    strip.text = element_text(face = "bold", size = 16),
    strip.background = element_rect(fill = "gray90", color = "black"),
    strip.placement = "outside",
    legend.position = "bottom",
    axis.text.y = element_text(face = "bold", size = 13),
    axis.text.x = element_text(size = 14),
    panel.spacing = unit(1, "lines"),
    panel.border = element_rect(color = "black", fill = NA, size = 1.5)
  )

# Save with correct size override
 ggsave("Top_GSEA_Pathways_Per_Cluster2.pdf", p, width = 30, height = 58, limitsize = FALSE)
p2

Combine and Save All GSEA Results

Combine and Save All GSEA Results

# Required packages
library(msigdbr)
library(fgsea)
library(dplyr)
library(tibble)
library(forcats)
library(ggplot2)
library(pheatmap)
library(stringr)

# 1. Curated Sézary syndrome–relevant MSigDB pathways
curated_pathways <- c(
  # Hallmark
  "HALLMARK_JAK_STAT3_SIGNALING", "HALLMARK_TNFA_SIGNALING_VIA_NFKB", "HALLMARK_APOPTOSIS",
  # KEGG
  "KEGG_T_CELL_RECEPTOR_SIGNALING_PATHWAY", "KEGG_JAK_STAT_SIGNALING_PATHWAY",
  "KEGG_PI3K_AKT_SIGNALING_PATHWAY", "KEGG_MAPK_SIGNALING_PATHWAY",
  "KEGG_TGF_BETA_SIGNALING_PATHWAY", "KEGG_CELL_CYCLE", "KEGG_APOPTOSIS",
  # Reactome
  "REACTOME_SIGNALING_BY_TCR", "REACTOME_SIGNALING_BY_JAK_STAT",
  "REACTOME_PI3K_AKT_ACTIVATION", "REACTOME_NFKB_ACTIVATION",
  # GO (Biological Process)
  "GOBP_CYTOKINE_MEDIATED_SIGNALING_PATHWAY", "GOBP_T_CELL_ACTIVATION",
  "GOBP_CELL_CYCLE_PROCESS", "GOBP_APOPTOTIC_PROCESS",
  "GOBP_MAPK_CASCADE", "GOBP_NF_KAPPA_B_TRANSCRIPTION_FACTOR_ACTIVITY",
  "GOBP_JAK_STAT_CASCADE", "GOBP_EPIGENETIC_REGULATION"
)

# 2. Load MSigDB genes
msig_df <- msigdbr(species = "Homo sapiens") %>%
  filter(gs_name %in% curated_pathways)

pathways_list <- split(msig_df$gene_symbol, msig_df$gs_name)

# 3. Split FindAllMarkers data frame by cluster
cluster_stats <- split(all_markers, all_markers$cluster)

# 4. Run fgsea using avg_log2FC as ranking metric
fgsea_results <- lapply(cluster_stats, function(stats_df) {
  # Ensure avg_log2FC exists and gene names are present
  stats_df <- stats_df %>%
    filter(!is.na(avg_log2FC)) %>%
    distinct(gene, .keep_all = TRUE)

  # Check if gene column exists
  if (!"gene" %in% colnames(stats_df)) {
    warning("No 'gene' column found in stats_df")
    return(NULL)
  }

  # Create rank vector
  ranks <- stats_df$avg_log2FC
  names(ranks) <- stats_df$gene
  ranks <- sort(ranks, decreasing = TRUE)

  # Optional: skip small rank vectors
  if (length(ranks) < 100) return(NULL)

   fgsea(
    pathways = pathways_list,
    stats = sort(ranks, decreasing = TRUE),
    minSize = 10,
    maxSize = 300,
    nperm = 10000
  )
})


# 5. Combine and annotate results
gsea_df <- bind_rows(lapply(names(fgsea_results), function(cluster) {
  res <- fgsea_results[[cluster]]
  res$cluster <- cluster
  res
}))

# 6. Ensure all pathways appear across clusters
all_combos <- expand.grid(
  cluster = names(cluster_stats),
  pathway = curated_pathways,
  stringsAsFactors = FALSE
)

gsea_complete <- all_combos %>%
  left_join(gsea_df, by = c("cluster", "pathway")) %>%
  mutate(
    NES = ifelse(is.na(NES), 0, NES),
    padj = ifelse(is.na(padj), 1, padj),
    database = case_when(
      str_detect(pathway, "^HALLMARK") ~ "Hallmark",
      str_detect(pathway, "^KEGG") ~ "KEGG",
      str_detect(pathway, "^REACTOME") ~ "Reactome",
      str_detect(pathway, "^GOBP") ~ "GO",
      TRUE ~ "Other"
    ),
    direction_db = ifelse(NES > 0, paste0("+ ", database), paste0("- ", database)),
    sig = ifelse(padj < 0.05, "*", "")
  )

# 7. Color palette
palette <- c(
  `+ Hallmark` = "#d62728", `- Hallmark` = "#fcbba1",
  `+ KEGG` = "#2ca02c", `- KEGG` = "#b9f6ca",
  `+ Reactome` = "#1f77b4", `- Reactome` = "#aec7e8",
  `+ GO` = "#9467bd", `- GO` = "#d5bde3"
)

# 8. Plot
p4 <- ggplot(gsea_complete, aes(x = fct_reorder(pathway, NES), y = NES, fill = direction_db)) +
  geom_col(width = 0.9) +
  geom_text(aes(label = sig), hjust = -0.3, size = 5, fontface = "bold", color = "black") +
  coord_flip() +
  facet_grid(database ~ cluster, scales = "free_y", space = "free") +
  geom_hline(yintercept = 0, linetype = "dashed", color = "gray50") +
  labs(
    x = "Pathway",
    y = "Normalized Enrichment Score (NES)",
    title = "GSEA (avg_log2FC only) — Curated Pathways per Cluster",
    fill = "Enrichment"
  ) +
  scale_fill_manual(values = palette, na.value = "gray80") +
  theme_minimal(base_size = 16) +
  theme(
    strip.text = element_text(face = "bold", size = 16),
    strip.background = element_rect(fill = "gray90", color = "black"),
    legend.position = "bottom",
    axis.text.y = element_text(face = "bold", size = 13),
    axis.text.x = element_text(size = 14),
    panel.spacing = unit(1, "lines"),
    panel.border = element_rect(color = "black", fill = NA, size = 1.5)
  )

# 9. Save to PDF
ggsave("Curated_GSEA_avgLogFC_Only.pdf", p4, width = 30, height = 58, limitsize = FALSE)

p4
LS0tCnRpdGxlOiAiZmluZEFsbE1hcmtlcnMtTmV3VU1BUCBmZ3NlYSBBbmFseXNpcyIKYXV0aG9yOiAiTmFzaXIgTWFobW9vZCBBYmJhc2kiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIHRvY19jb2xsYXBzZWQ6IHllcwogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogeWVzCi0tLQoKIyAxLiBMb2FkIExpYnJhcmllcwpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoaGFybW9ueSkKbGlicmFyeShkcGx5cikKbGlicmFyeShFbmhhbmNlZFZvbGNhbm8pCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwaGVhdG1hcCkKbGlicmFyeSh0aWJibGUpCmBgYAoKCiMgMi4gbG9hZCBzZXVyYXQgb2JqZWN0CmBgYHtyIGxvYWRfc2V1cmF0fQojTG9hZCBTZXVyYXQgT2JqZWN0CkFsbF9zYW1wbGVzX01lcmdlZCA8LSByZWFkUkRTKCIvaG9tZS9uYWJiYXNpL2lzaWxvbi9QSERfM3JkX1lFQVJfQW5hbHlzaXMvMC1TZXVyYXRfUkRTX09CSkVDVF9GSU5BTC9BbGxfc2FtcGxlc19NZXJnZWRfSGFybW9ueV9pbnRlZ3JhdGVkX0NlbGxfbGluZV9yZW5hbWVkXzAzLTA3LTIwMjUucmRzIikKCgpBbGxfc2FtcGxlc19NZXJnZWQKYGBgCgojIDMuIFNldCBVcCBJZGVudGlmaWVycyBmb3IgQ2x1c3RlcmluZwpgYGB7cn0KIyBBc3NpZ24gY2x1c3RlciBpZGVudGl0aWVzIHRvIHRoZSBTZXVyYXQgb2JqZWN0CklkZW50cyhBbGxfc2FtcGxlc19NZXJnZWQpIDwtICJzZXVyYXRfY2x1c3RlcnMiCgpEaW1QbG90KEFsbF9zYW1wbGVzX01lcmdlZCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJjZWxsX2xpbmUiLGxhYmVsID0gVCwgbGFiZWwuYm94ID0gVCkKRGltUGxvdChBbGxfc2FtcGxlc19NZXJnZWQsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAic2V1cmF0X2NsdXN0ZXJzIixsYWJlbCA9IFQsIGxhYmVsLmJveCA9IFQpCgpgYGAKCiMgNC4gVXNlIEZpbmRBbGxNYXJrZXJzKCkgZm9yIERFIG9uIFJOQSBhc3NheQpgYGB7cn0KIyBMb2FkIG5lY2Vzc2FyeSBsaWJyYXJpZXMKbGlicmFyeShTZXVyYXQpCgpEZWZhdWx0QXNzYXkoQWxsX3NhbXBsZXNfTWVyZ2VkKSA8LSAiUk5BIgoKQWxsX3NhbXBsZXNfTWVyZ2VkIDwtIE5vcm1hbGl6ZURhdGEoCiAgQWxsX3NhbXBsZXNfTWVyZ2VkLCAKICBhc3NheSA9ICJSTkEiLCAKICBub3JtYWxpemF0aW9uLm1ldGhvZCA9ICJMb2dOb3JtYWxpemUiLCAKICBzY2FsZS5mYWN0b3IgPSAxMDAwMAopCgpJZGVudHMoQWxsX3NhbXBsZXNfTWVyZ2VkKSA8LSAic2V1cmF0X2NsdXN0ZXJzIgoKYWxsX21hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnMoCiAgb2JqZWN0ID0gQWxsX3NhbXBsZXNfTWVyZ2VkLAogIGFzc2F5ID0gIlJOQSIsCiAgbG9nZmMudGhyZXNob2xkID0gMCwKICBtaW4ucGN0ID0gMCwKICB0ZXN0LnVzZSA9ICJ3aWxjb3giLAogIG9ubHkucG9zID0gRkFMU0UsCiAgcmV0dXJuLnRocmVzaCA9IDEgIyBLZWVwIGFsbCBnZW5lcywgZG9uJ3QgZmlsdGVyIGJ5IHAtdmFsdWUKKQoKYGBgCgojIDUuICAgTG9hZCBHZW5lIFNldHMgZnJvbSBNU2lnREIKYGBge3IgLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMn0KbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkocHVycnIpCmxpYnJhcnkoZmdzZWEpCmxpYnJhcnkobXNpZ2RicikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkoZm9yY2F0cykKCiMgMi4gTG9hZCBHZW5lIFNldHMgZnJvbSBNU2lnREIgKHlvdXIgZXhhY3QgY29kZSkKCiMgSGFsbG1hcmsgKG5vIHN1YmNvbGxlY3Rpb24gbmVlZGVkKQpoYWxsbWFya19zZXRzIDwtIG1zaWdkYnIoc3BlY2llcyA9ICJIb21vIHNhcGllbnMiLCBjYXRlZ29yeSA9ICJIIikgJT4lCiAgc3BsaXQoeCA9IC4kZ2VuZV9zeW1ib2wsIGYgPSAuJGdzX25hbWUpCgojIEtFR0cgbGVnYWN5IHBhdGh3YXlzCmtlZ2dfc2V0cyA8LSBtc2lnZGJyKAogICAgc3BlY2llcyAgICAgID0gIkhvbW8gc2FwaWVucyIsCiAgICBjYXRlZ29yeSAgICAgPSAiQzIiLAogICAgc3ViY29sbGVjdGlvbiA9ICJDUDpLRUdHX0xFR0FDWSIKICApICU+JQogIHNwbGl0KHggPSAuJGdlbmVfc3ltYm9sLCBmID0gLiRnc19uYW1lKQoKIyBSZWFjdG9tZSBwYXRod2F5cwpyZWFjdG9tZV9zZXRzIDwtIG1zaWdkYnIoCiAgICBzcGVjaWVzICAgICAgPSAiSG9tbyBzYXBpZW5zIiwKICAgIGNhdGVnb3J5ICAgICA9ICJDMiIsCiAgICBzdWJjb2xsZWN0aW9uID0gIkNQOlJFQUNUT01FIgogICkgJT4lCiAgc3BsaXQoeCA9IC4kZ2VuZV9zeW1ib2wsIGYgPSAuJGdzX25hbWUpCgojIEltbXVub2xvZ2ljIHNpZ25hdHVyZXMKYzdfc2V0cyA8LSBtc2lnZGJyKHNwZWNpZXMgPSAiSG9tbyBzYXBpZW5zIiwgY2F0ZWdvcnkgPSAiQzciKSAlPiUKICBzcGxpdCh4ID0gLiRnZW5lX3N5bWJvbCwgZiA9IC4kZ3NfbmFtZSkKCiMgR08gQmlvbG9naWNhbCBQcm9jZXNzLCBDQywgTUYKYzVfYnAgPC0gbXNpZ2RicihzcGVjaWVzID0gIkhvbW8gc2FwaWVucyIsIGNhdGVnb3J5ID0gIkM1Iiwgc3ViY29sbGVjdGlvbiA9ICJCUCIpICU+JQogIHNwbGl0KHggPSAuJGdlbmVfc3ltYm9sLCBmID0gLiRnc19uYW1lKQoKCiMgQ29tYmluZSBhbGwgc2V0cwptc2lnZGJfc2V0cyA8LSBsaXN0KAogIEhhbGxtYXJrID0gaGFsbG1hcmtfc2V0cywKICBLRUdHICAgICA9IGtlZ2dfc2V0cywKICBSZWFjdG9tZSA9IHJlYWN0b21lX3NldHMsCiAgQzcgICAgICAgPSBjN19zZXRzLAogIEdPX0JQICAgID0gYzVfYnAKKQoKYGBgCgoKCiMgNC4gIFJ1biBHU0VBIHBlciBDbHVzdGVyIHVzaW5nIERFIEZpbGVzCmBgYHtyICwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CgojIDMuIFByZXBhcmUgb3V0cHV0IGxpc3QgZm9yIHN0b3JpbmcgRkdTRUEgcmVzdWx0cwpnc2VhX2FsbCA8LSBsaXN0KCkKCiMgNC4gR2V0IHVuaXF1ZSBjbHVzdGVycyBmcm9tIGFsbF9tYXJrZXJzCmNsdXN0ZXJzIDwtIHVuaXF1ZShhbGxfbWFya2VycyRjbHVzdGVyKQoKIyA1LiBMb29wIG92ZXIgZWFjaCBjbHVzdGVyIGFuZCBydW4gRkdTRUEKZm9yIChjbHVzdGVyX2lkIGluIGNsdXN0ZXJzKSB7CiAgCiAgY2F0KCJQcm9jZXNzaW5nIGNsdXN0ZXI6IiwgY2x1c3Rlcl9pZCwgIlxuIikKICAKICAjIFN1YnNldCBERSBnZW5lcyBmb3IgY2x1c3RlciB2cyByZXN0CiAgZGVfZGYgPC0gYWxsX21hcmtlcnMgJT4lCiAgICBmaWx0ZXIoY2x1c3RlciA9PSBjbHVzdGVyX2lkKSAlPiUKICAgIGZpbHRlcighaXMubmEoYXZnX2xvZzJGQykpCiAgCiAgIyBDcmVhdGUgbmFtZWQgdmVjdG9yIHJhbmtlZCBieSBhdmdfbG9nMkZDIChkZXNjZW5kaW5nKQogIHJhbmtlZF9nZW5lcyA8LSBkZWZyYW1lKGRlX2RmICU+JSBzZWxlY3QoZ2VuZSwgYXZnX2xvZzJGQykpCiAgcmFua2VkX2dlbmVzIDwtIHNvcnQocmFua2VkX2dlbmVzLCBkZWNyZWFzaW5nID0gVFJVRSkKICAKICAjIFJ1biBGR1NFQSBvbiBlYWNoIE1TaWdEQiBjb2xsZWN0aW9uCiAgZm9yIChkYl9uYW1lIGluIG5hbWVzKG1zaWdkYl9zZXRzKSkgewogICAgZmdzZWFfcmVzIDwtIGZnc2VhKAogICAgICBwYXRod2F5cyA9IG1zaWdkYl9zZXRzW1tkYl9uYW1lXV0sCiAgICAgIHN0YXRzID0gcmFua2VkX2dlbmVzLAogICAgICBtaW5TaXplID0gMTAsCiAgICAgIG1heFNpemUgPSAzMDAsCiAgICAgIG5wZXJtID0gMTAwMDAKICAgICkKICAgIAogICAgaWYgKG5yb3coZmdzZWFfcmVzKSA+IDApIHsKICAgICAgZmdzZWFfcmVzJGNsdXN0ZXIgPC0gY2x1c3Rlcl9pZAogICAgICBmZ3NlYV9yZXMkZGF0YWJhc2UgPC0gZGJfbmFtZQogICAgICAKICAgICAgIyBTYXZlIGluIGxpc3Qgd2l0aCB1bmlxdWUgbmFtZQogICAgICBnc2VhX2FsbFtbcGFzdGUwKCJDbHVzdGVyXyIsIGNsdXN0ZXJfaWQsICJfIiwgZGJfbmFtZSldXSA8LSBmZ3NlYV9yZXMKICAgIH0KICB9Cn0KCgpgYGAKCiMjIENvbWJpbmUgYW5kIFNhdmUgQWxsIEdTRUEgUmVzdWx0cwpgYGB7ciAsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQojIDYuIENvbWJpbmUgYWxsIEdTRUEgcmVzdWx0cyBpbnRvIG9uZSBkYXRhZnJhbWUKZ3NlYV9kZiA8LSBiaW5kX3Jvd3MoZ3NlYV9hbGwpCgojIDcuIEZsYXR0ZW4gbGVhZGluZ0VkZ2UgbGlzdCBjb2x1bW4gaW50byBhIHNlbWljb2xvbi1zZXBhcmF0ZWQgc3RyaW5nCmdzZWFfZGYgPC0gZ3NlYV9kZiAlPiUKICBtdXRhdGUobGVhZGluZ0VkZ2UgPSBtYXBfY2hyKGxlYWRpbmdFZGdlLCB+IHBhc3RlKC54LCBjb2xsYXBzZSA9ICI7IikpKQoKIyA4LiBTYXZlIGNvbWJpbmVkIHJlc3VsdHMgKG9wdGlvbmFsKQp3cml0ZS5jc3YoZ3NlYV9kZiwgIkdTRUFfTVNpZ0RCX1Jlc3VsdHNfQ2x1c3Rlcndpc2VfZmluZEFsbE1hcmtlcnNfdXNlZC5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkKCiMgOS4gQ3JlYXRlIGZvbGRlcnMgYW5kIHNhdmUgY2x1c3Rlci13aXNlIHJlc3VsdHMgc2VwYXJhdGVseQpnc2VhX2J5X2NsdXN0ZXIgPC0gc3BsaXQoZ3NlYV9kZiwgZ3NlYV9kZiRjbHVzdGVyKQoKZm9yIChjbHVzdGVyX2lkIGluIG5hbWVzKGdzZWFfYnlfY2x1c3RlcikpIHsKICBmb2xkZXJfbmFtZSA8LSBwYXN0ZTAoIkNsdXN0ZXJfIiwgY2x1c3Rlcl9pZCkKICAKICBpZiAoIWRpci5leGlzdHMoZm9sZGVyX25hbWUpKSB7CiAgICBkaXIuY3JlYXRlKGZvbGRlcl9uYW1lKQogIH0KICAKICBmaWxlX3BhdGggPC0gZmlsZS5wYXRoKGZvbGRlcl9uYW1lLCBwYXN0ZTAoIkdTRUFfQ2x1c3Rlcl8iLCBjbHVzdGVyX2lkLCAiLmNzdiIpKQogIHdyaXRlLmNzdihnc2VhX2J5X2NsdXN0ZXJbW2NsdXN0ZXJfaWRdXSwgZmlsZSA9IGZpbGVfcGF0aCwgcm93Lm5hbWVzID0gRkFMU0UpCn0KCgoKCmBgYAoKCiMjIENvbWJpbmUgYW5kIFNhdmUgQWxsIEdTRUEgUmVzdWx0cwpgYGB7ciAsIGZpZy5oZWlnaHQ9MzAsIGZpZy53aWR0aD01OH0KIyAxMC4gUGxvdCB0b3AgR1NFQSBwYXRod2F5cyBwZXIgY2x1c3RlciAmIGNvbGxlY3Rpb24gKHRvcCAzIHBlciBjbHVzdGVyL2RiLCBwYWRqPDAuMDUpCnRvcF90ZXJtcyA8LSBnc2VhX2RmICU+JQogIGZpbHRlcihwYWRqIDwgMC4wNSkgJT4lCiAgZ3JvdXBfYnkoY2x1c3RlciwgZGF0YWJhc2UpICU+JQogIHNsaWNlX21heChORVMsIG4gPSAxMCwgd2l0aF90aWVzID0gRkFMU0UpICU+JQogIHVuZ3JvdXAoKQoKIyBDbGVhbiBwYXRod2F5IG5hbWVzCnRvcF90ZXJtcyRwYXRod2F5IDwtIGdzdWIoIkdPX3xSRUFDVE9NRV98S0VHR18iLCAiIiwgdG9wX3Rlcm1zJHBhdGh3YXkpCnRvcF90ZXJtcyRwYXRod2F5IDwtIGdzdWIoIl8iLCAiICIsIHRvcF90ZXJtcyRwYXRod2F5KQp0b3BfdGVybXMkcGF0aHdheSA8LSBzdHJfdG9fdGl0bGUodG9wX3Rlcm1zJHBhdGh3YXkpCnRvcF90ZXJtcyRwYXRod2F5IDwtIHN0cl90cnVuYyh0b3BfdGVybXMkcGF0aHdheSwgd2lkdGggPSA2MCkKCiMgUGxvdCB1c2luZyBnZ3Bsb3QyCnAxIDwtIGdncGxvdCh0b3BfdGVybXMsIGFlcyh4ID0gZmN0X3Jlb3JkZXIocGF0aHdheSwgTkVTKSwgeSA9IE5FUywgZmlsbCA9IGRhdGFiYXNlKSkgKwogIGdlb21fY29sKHdpZHRoID0gMC45KSArCiAgY29vcmRfZmxpcCgpICsKICBmYWNldF9ncmlkKGRhdGFiYXNlIH4gY2x1c3Rlciwgc2NhbGVzID0gImZyZWVfeSIsIHNwYWNlID0gImZyZWUiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiZ3JheTUwIikgKwogIGxhYnMoCiAgICB4ID0gIlBhdGh3YXkiLAogICAgeSA9ICJOb3JtYWxpemVkIEVucmljaG1lbnQgU2NvcmUgKE5FUykiLAogICAgdGl0bGUgPSAiVG9wIEdTRUEgUGF0aHdheXMgcGVyIENsdXN0ZXIiLAogICAgZmlsbCA9ICJEYXRhYmFzZSIKICApICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDIiKSArCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNikgKwogIHRoZW1lKAogICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTYpLAogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImdyYXk5MCIsIGNvbG9yID0gImJsYWNrIiksCiAgICBzdHJpcC5wbGFjZW1lbnQgPSAib3V0c2lkZSIsCiAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxMyksCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLAogICAgcGFuZWwuc3BhY2luZyA9IHVuaXQoMSwgImxpbmVzIiksCiAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3IgPSAiYmxhY2siLCBmaWxsID0gTkEsIHNpemUgPSAxLjUpCiAgKQoKIGdnc2F2ZSgiVG9wX0dTRUFfUGF0aHdheXNfUGVyX0NsdXN0ZXIxLnBkZiIsIHAsIHdpZHRoID0gMzAsIGhlaWdodCA9IDU4LCBsaW1pdHNpemUgPSBGQUxTRSkKCnAxCgpgYGAKCgojIyBDb21iaW5lIGFuZCBTYXZlIEFsbCBHU0VBIFJlc3VsdHMKYGBge3IgLCBmaWcuaGVpZ2h0PTMwLCBmaWcud2lkdGg9NTh9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ2ZvcmNlKQpsaWJyYXJ5KGZvcmNhdHMpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoc3RyaW5ncikKCiMgRm9yY2UgY2x1c3RlciBvcmRlcgp0b3BfdGVybXMkY2x1c3RlciA8LSBmYWN0b3IodG9wX3Rlcm1zJGNsdXN0ZXIsIGxldmVscyA9IGFzLmNoYXJhY3RlcigwOjEzKSkKCiMgQ2xlYW4gYW5kIHNob3J0ZW4gcGF0aHdheSBuYW1lcwp0b3BfdGVybXMgPC0gdG9wX3Rlcm1zICU+JQogIG11dGF0ZSgKICAgIHBhdGh3YXkgPSBnc3ViKCJHT198UkVBQ1RPTUVffEtFR0dfIiwgIiIsIHBhdGh3YXkpLAogICAgcGF0aHdheSA9IGdzdWIoIl8iLCAiICIsIHBhdGh3YXkpLAogICAgcGF0aHdheSA9IHN0cl90b190aXRsZShwYXRod2F5KSwKICAgIHBhdGh3YXkgPSBzdHJfdHJ1bmMocGF0aHdheSwgd2lkdGggPSA2MCkKICApCgojIEFkZCBkaXJlY3Rpb24gY29sdW1uCnRvcF90ZXJtcyA8LSB0b3BfdGVybXMgJT4lCiAgbXV0YXRlKGRpcmVjdGlvbiA9IGlmZWxzZShORVMgPiAwLCAiVXByZWd1bGF0ZWQiLCAiRG93bnJlZ3VsYXRlZCIpKQoKIyBVc2UgZGlyZWN0aW9uIGFuZCBkYXRhYmFzZSB0b2dldGhlciBmb3IgY29sb3IKdG9wX3Rlcm1zJGRpcmVjdGlvbl9kYiA8LSBpbnRlcmFjdGlvbih0b3BfdGVybXMkZGlyZWN0aW9uLCB0b3BfdGVybXMkZGF0YWJhc2UsIHNlcCA9ICJfIikKCiMgRGVmaW5lIGN1c3RvbSBjb2xvcnMgZm9yIGVhY2ggZGlyZWN0aW9uK2RiIGNvbWJvIChvcHRpb25hbDogY3VzdG9taXplIGFzIHlvdSBsaWtlKQpuX2NvbG9ycyA8LSBsZW5ndGgodW5pcXVlKHRvcF90ZXJtcyRkaXJlY3Rpb25fZGIpKQpwYWxldHRlIDwtIHNjYWxlczo6aHVlX3BhbCgpKG5fY29sb3JzKQpuYW1lcyhwYWxldHRlKSA8LSB1bmlxdWUodG9wX3Rlcm1zJGRpcmVjdGlvbl9kYikKCiMgUGxvdApwMiA8LSBnZ3Bsb3QodG9wX3Rlcm1zLCBhZXMoeCA9IGZjdF9yZW9yZGVyKHBhdGh3YXksIE5FUyksIHkgPSBORVMsIGZpbGwgPSBkaXJlY3Rpb25fZGIpKSArCiAgZ2VvbV9jb2wod2lkdGggPSAwLjkpICsKICBjb29yZF9mbGlwKCkgKwogIGZhY2V0X2dyaWQoZGF0YWJhc2UgfiBjbHVzdGVyLCBzY2FsZXMgPSAiZnJlZV95Iiwgc3BhY2UgPSAiZnJlZSIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJncmF5NTAiKSArCiAgbGFicygKICAgIHggPSAiUGF0aHdheSIsCiAgICB5ID0gIk5vcm1hbGl6ZWQgRW5yaWNobWVudCBTY29yZSAoTkVTKSIsCiAgICB0aXRsZSA9ICJUb3AgR1NFQSBQYXRod2F5cyBwZXIgQ2x1c3RlciIsCiAgICBmaWxsID0gIkRpcmVjdGlvbiArIERCIgogICkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGUpICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE2KSArCiAgdGhlbWUoCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNiksCiAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiZ3JheTkwIiwgY29sb3IgPSAiYmxhY2siKSwKICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIiwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDEzKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksCiAgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgxLCAibGluZXMiKSwKICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvciA9ICJibGFjayIsIGZpbGwgPSBOQSwgc2l6ZSA9IDEuNSkKICApCgojIFNhdmUgd2l0aCBjb3JyZWN0IHNpemUgb3ZlcnJpZGUKIGdnc2F2ZSgiVG9wX0dTRUFfUGF0aHdheXNfUGVyX0NsdXN0ZXIyLnBkZiIsIHAsIHdpZHRoID0gMzAsIGhlaWdodCA9IDU4LCBsaW1pdHNpemUgPSBGQUxTRSkKcDIKYGBgCgojIyBDb21iaW5lIGFuZCBTYXZlIEFsbCBHU0VBIFJlc3VsdHMKYGBge3IgLCBmaWcuaGVpZ2h0PTE4LCBmaWcud2lkdGg9MjB9CiMgUmVxdWlyZWQgcGFja2FnZXMKbGlicmFyeShtc2lnZGJyKQpsaWJyYXJ5KGZnc2VhKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpYmJsZSkKbGlicmFyeShmb3JjYXRzKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocGhlYXRtYXApCmxpYnJhcnkoc3RyaW5ncikKCiMgU3BsaXQgdGhlIGFsbG1hcmtlcnMgKGZyb20gRmluZEFsbE1hcmtlcnMpIGludG8gYSBuYW1lZCBsaXN0IHBlciBjbHVzdGVyCmNsdXN0ZXJfc3RhdHMgPC0gc3BsaXQoYWxsX21hcmtlcnMsIGFsbF9tYXJrZXJzJGNsdXN0ZXIpCgoKIyAxLiBDdXJhdGVkIFPDqXphcnkgc3luZHJvbWXigJNyZWxldmFudCBwYXRod2F5cyAodXNlIHRoZWlyIGV4YWN0IE1TaWdEQiBuYW1lcykKY3VyYXRlZF9wYXRod2F5cyA8LSBjKAogICMgSGFsbG1hcmsKICAiSEFMTE1BUktfSkFLX1NUQVQzX1NJR05BTElORyIsICJIQUxMTUFSS19UTkZBX1NJR05BTElOR19WSUFfTkZLQiIsICJIQUxMTUFSS19BUE9QVE9TSVMiLAogICMgS0VHRwogICJLRUdHX1RfQ0VMTF9SRUNFUFRPUl9TSUdOQUxJTkdfUEFUSFdBWSIsICJLRUdHX0pBS19TVEFUX1NJR05BTElOR19QQVRIV0FZIiwKICAiS0VHR19QSTNLX0FLVF9TSUdOQUxJTkdfUEFUSFdBWSIsICJLRUdHX01BUEtfU0lHTkFMSU5HX1BBVEhXQVkiLAogICJLRUdHX1RHRl9CRVRBX1NJR05BTElOR19QQVRIV0FZIiwgIktFR0dfQ0VMTF9DWUNMRSIsICJLRUdHX0FQT1BUT1NJUyIsCiAgIyBSZWFjdG9tZQogICJSRUFDVE9NRV9TSUdOQUxJTkdfQllfVENSIiwgIlJFQUNUT01FX1NJR05BTElOR19CWV9KQUtfU1RBVCIsCiAgIlJFQUNUT01FX1BJM0tfQUtUX0FDVElWQVRJT04iLCAiUkVBQ1RPTUVfTkZLQl9BQ1RJVkFUSU9OIiwKICAjIEdPIChCaW9sb2dpY2FsIFByb2Nlc3MpCiAgIkdPQlBfQ1lUT0tJTkVfTUVESUFURURfU0lHTkFMSU5HX1BBVEhXQVkiLCAiR09CUF9UX0NFTExfQUNUSVZBVElPTiIsCiAgIkdPQlBfQ0VMTF9DWUNMRV9QUk9DRVNTIiwgIkdPQlBfQVBPUFRPVElDX1BST0NFU1MiLAogICJHT0JQX01BUEtfQ0FTQ0FERSIsICJHT0JQX05GX0tBUFBBX0JfVFJBTlNDUklQVElPTl9GQUNUT1JfQUNUSVZJVFkiLAogICJHT0JQX0pBS19TVEFUX0NBU0NBREUiLCAiR09CUF9FUElHRU5FVElDX1JFR1VMQVRJT04iCikKCiMgMi4gTG9hZCBwYXRod2F5cyBmcm9tIG1zaWdkYnIKbXNpZ19kZiA8LSBtc2lnZGJyKHNwZWNpZXMgPSAiSG9tbyBzYXBpZW5zIikgJT4lCiAgZmlsdGVyKGdzX25hbWUgJWluJSBjdXJhdGVkX3BhdGh3YXlzKQoKcGF0aHdheXNfbGlzdCA8LSBzcGxpdChtc2lnX2RmJGdlbmVfc3ltYm9sLCBtc2lnX2RmJGdzX25hbWUpCgojIDMuIFlvdXIgaW5wdXQ6IGEgbGlzdCBvZiByYW5rZWQgZ2VuZSBzdGF0cyAoZS5nLiwgZnJvbSBTZXVyYXQ6OkZpbmRNYXJrZXJzKSBmb3IgZWFjaCBjbHVzdGVyCiMgRXhhbXBsZTogY2x1c3Rlcl9zdGF0cyBpcyBhIG5hbWVkIGxpc3Qgb2YgZGF0YS5mcmFtZXMsIGVhY2ggY29udGFpbmluZyBnZW5lLCBhdmdfbG9nMkZDLCBwX3ZhbF9hZGoKIyBFeGFtcGxlIG9mIG1ha2luZyByYW5rIHZlY3Rvcjogc3RhdHMkYXZnX2xvZzJGQyAqIC1sb2cxMChzdGF0cyRwX3ZhbF9hZGogKyAxZS0zMDApCgojIFJlcGxhY2Ugd2l0aCB5b3VyIHJlYWwgY2x1c3Rlci1sZXZlbCBzdGF0cyBsaXN0CiMgY2x1c3Rlcl9zdGF0cyA8LSBsaXN0KGNsdXN0ZXJBID0gZGZfQSwgY2x1c3RlckIgPSBkZl9CLCAuLi4pCgojIDQuIFJ1biBmZ3NlYSBmb3IgZWFjaCBjbHVzdGVyCmZnc2VhX3Jlc3VsdHMgPC0gbGFwcGx5KGNsdXN0ZXJfc3RhdHMsIGZ1bmN0aW9uKHN0YXRzX2RmKSB7CiAgc3RhdHNfZGYgPC0gc3RhdHNfZGYgJT4lIGZpbHRlcighaXMubmEocF92YWxfYWRqKSwgIWlzLm5hKGF2Z19sb2cyRkMpKQogIHJhbmtzIDwtIHN0YXRzX2RmJGF2Z19sb2cyRkMgKiAtbG9nMTAoc3RhdHNfZGYkcF92YWxfYWRqICsgMWUtMzAwKQogIG5hbWVzKHJhbmtzKSA8LSByb3duYW1lcyhzdGF0c19kZikKICBmZ3NlYShwYXRod2F5cyA9IHBhdGh3YXlzX2xpc3QsIHN0YXRzID0gc29ydChyYW5rcywgZGVjcmVhc2luZyA9IFRSVUUpLCBucGVybSA9IDUwMDApCn0pCgojIDUuIENvbWJpbmUgYW5kIGFubm90YXRlCmdzZWFfZGYgPC0gYmluZF9yb3dzKGxhcHBseShuYW1lcyhmZ3NlYV9yZXN1bHRzKSwgZnVuY3Rpb24oY2x1c3RlcikgewogIHJlcyA8LSBmZ3NlYV9yZXN1bHRzW1tjbHVzdGVyXV0KICByZXMkY2x1c3RlciA8LSBjbHVzdGVyCiAgcmVzCn0pKQoKIyBGaWx0ZXIgdG8gY3VyYXRlZCBwYXRod2F5cyAoYWxyZWFkeSBkb25lIGJ1dCBnb29kIHRvIGRvdWJsZSBjaGVjaykKZ3NlYV9kZiA8LSBnc2VhX2RmICU+JSBmaWx0ZXIocGF0aHdheSAlaW4lIGN1cmF0ZWRfcGF0aHdheXMpCgojIEFkZCBwYXRod2F5IHNvdXJjZSBsYWJlbApnc2VhX2RmIDwtIGdzZWFfZGYgJT4lCiAgbXV0YXRlKGRhdGFiYXNlID0gY2FzZV93aGVuKAogICAgc3RyX2RldGVjdChwYXRod2F5LCAiXkhBTExNQVJLIikgfiAiSGFsbG1hcmsiLAogICAgc3RyX2RldGVjdChwYXRod2F5LCAiXktFR0ciKSB+ICJLRUdHIiwKICAgIHN0cl9kZXRlY3QocGF0aHdheSwgIl5SRUFDVE9NRSIpIH4gIlJlYWN0b21lIiwKICAgIHN0cl9kZXRlY3QocGF0aHdheSwgIl5HT0JQIikgfiAiR08iLAogICAgVFJVRSB+ICJPdGhlciIKICApKSAlPiUKICBtdXRhdGUoZGlyZWN0aW9uX2RiID0gaWZlbHNlKE5FUyA+IDAsIHBhc3RlMCgiKyAiLCBkYXRhYmFzZSksIHBhc3RlMCgiLSAiLCBkYXRhYmFzZSkpKQoKIyA2LiBPcHRpb25hbGx5IGZpbHRlciB0byB0b3AgTiBwYXRod2F5cyBwZXIgY2x1c3Rlcgp0b3BfdGVybXMgPC0gZ3NlYV9kZiAlPiUKICBncm91cF9ieShjbHVzdGVyLCBkYXRhYmFzZSkgJT4lCiAgdG9wX24oNSwgd3QgPSBhYnMoTkVTKSkgJT4lCiAgdW5ncm91cCgpCgojIDcuIFNldCBmaWxsIHBhbGV0dGUgZm9yIHVwL2Rvd24tcmVndWxhdGlvbgpwYWxldHRlIDwtIGMoCiAgIkhhbGxtYXJrIiA9ICIjZDYyNzI4IiwgIktFR0ciID0gIiMyY2EwMmMiLAogICJSZWFjdG9tZSIgPSAiIzFmNzdiNCIsICJHTyIgPSAiIzk0NjdiZCIKKQpwYWxldHRlIDwtIGMoCiAgYCsgSGFsbG1hcmtgID0gIiNkNjI3MjgiLCBgLSBIYWxsbWFya2AgPSAiI2ZjYmJhMSIsCiAgYCsgS0VHR2AgPSAiIzJjYTAyYyIsIGAtIEtFR0dgID0gIiNiOWY2Y2EiLAogIGArIFJlYWN0b21lYCA9ICIjMWY3N2I0IiwgYC0gUmVhY3RvbWVgID0gIiNhZWM3ZTgiLAogIGArIEdPYCA9ICIjOTQ2N2JkIiwgYC0gR09gID0gIiNkNWJkZTMiCikKCiMgOC4gUGxvdApwMyA8LSBnZ3Bsb3QodG9wX3Rlcm1zLCBhZXMoeCA9IGZjdF9yZW9yZGVyKHBhdGh3YXksIE5FUyksIHkgPSBORVMsIGZpbGwgPSBkaXJlY3Rpb25fZGIpKSArCiAgZ2VvbV9jb2wod2lkdGggPSAwLjkpICsKICBjb29yZF9mbGlwKCkgKwogIGZhY2V0X2dyaWQoZGF0YWJhc2UgfiBjbHVzdGVyLCBzY2FsZXMgPSAiZnJlZV95Iiwgc3BhY2UgPSAiZnJlZSIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJncmF5NTAiKSArCiAgbGFicygKICAgIHggPSAiUGF0aHdheSIsCiAgICB5ID0gIk5vcm1hbGl6ZWQgRW5yaWNobWVudCBTY29yZSAoTkVTKSIsCiAgICB0aXRsZSA9ICJUb3AgR1NFQSBQYXRod2F5cyBwZXIgQ2x1c3RlciIsCiAgICBmaWxsID0gIkRpcmVjdGlvbiArIERCIgogICkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGUpICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE2KSArCiAgdGhlbWUoCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNiksCiAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiZ3JheTkwIiwgY29sb3IgPSAiYmxhY2siKSwKICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIiwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDEzKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksCiAgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgxLCAibGluZXMiKSwKICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvciA9ICJibGFjayIsIGZpbGwgPSBOQSwgc2l6ZSA9IDEuNSkKICApCgojIDkuIFNhdmUgdGhlIHBsb3QKZ2dzYXZlKCJUb3BfR1NFQV9QYXRod2F5c19QZXJfQ2x1c3RlcjMucGRmIiwgcDMsIHdpZHRoID0gMzAsIGhlaWdodCA9IDU4LCBsaW1pdHNpemUgPSBGQUxTRSkKCnAzCmBgYAoKCiMjIENvbWJpbmUgYW5kIFNhdmUgQWxsIEdTRUEgUmVzdWx0cwpgYGB7ciAsIGZpZy5oZWlnaHQ9MTgsIGZpZy53aWR0aD0yMH0KIyBSZXF1aXJlZCBwYWNrYWdlcwpsaWJyYXJ5KG1zaWdkYnIpCmxpYnJhcnkoZmdzZWEpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGliYmxlKQpsaWJyYXJ5KGZvcmNhdHMpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwaGVhdG1hcCkKbGlicmFyeShzdHJpbmdyKQoKIyAxLiBDdXJhdGVkIFPDqXphcnkgc3luZHJvbWXigJNyZWxldmFudCBNU2lnREIgcGF0aHdheXMKY3VyYXRlZF9wYXRod2F5cyA8LSBjKAogICMgSGFsbG1hcmsKICAiSEFMTE1BUktfSkFLX1NUQVQzX1NJR05BTElORyIsICJIQUxMTUFSS19UTkZBX1NJR05BTElOR19WSUFfTkZLQiIsICJIQUxMTUFSS19BUE9QVE9TSVMiLAogICMgS0VHRwogICJLRUdHX1RfQ0VMTF9SRUNFUFRPUl9TSUdOQUxJTkdfUEFUSFdBWSIsICJLRUdHX0pBS19TVEFUX1NJR05BTElOR19QQVRIV0FZIiwKICAiS0VHR19QSTNLX0FLVF9TSUdOQUxJTkdfUEFUSFdBWSIsICJLRUdHX01BUEtfU0lHTkFMSU5HX1BBVEhXQVkiLAogICJLRUdHX1RHRl9CRVRBX1NJR05BTElOR19QQVRIV0FZIiwgIktFR0dfQ0VMTF9DWUNMRSIsICJLRUdHX0FQT1BUT1NJUyIsCiAgIyBSZWFjdG9tZQogICJSRUFDVE9NRV9TSUdOQUxJTkdfQllfVENSIiwgIlJFQUNUT01FX1NJR05BTElOR19CWV9KQUtfU1RBVCIsCiAgIlJFQUNUT01FX1BJM0tfQUtUX0FDVElWQVRJT04iLCAiUkVBQ1RPTUVfTkZLQl9BQ1RJVkFUSU9OIiwKICAjIEdPIChCaW9sb2dpY2FsIFByb2Nlc3MpCiAgIkdPQlBfQ1lUT0tJTkVfTUVESUFURURfU0lHTkFMSU5HX1BBVEhXQVkiLCAiR09CUF9UX0NFTExfQUNUSVZBVElPTiIsCiAgIkdPQlBfQ0VMTF9DWUNMRV9QUk9DRVNTIiwgIkdPQlBfQVBPUFRPVElDX1BST0NFU1MiLAogICJHT0JQX01BUEtfQ0FTQ0FERSIsICJHT0JQX05GX0tBUFBBX0JfVFJBTlNDUklQVElPTl9GQUNUT1JfQUNUSVZJVFkiLAogICJHT0JQX0pBS19TVEFUX0NBU0NBREUiLCAiR09CUF9FUElHRU5FVElDX1JFR1VMQVRJT04iCikKCiMgMi4gTG9hZCBNU2lnREIgZ2VuZXMKbXNpZ19kZiA8LSBtc2lnZGJyKHNwZWNpZXMgPSAiSG9tbyBzYXBpZW5zIikgJT4lCiAgZmlsdGVyKGdzX25hbWUgJWluJSBjdXJhdGVkX3BhdGh3YXlzKQoKcGF0aHdheXNfbGlzdCA8LSBzcGxpdChtc2lnX2RmJGdlbmVfc3ltYm9sLCBtc2lnX2RmJGdzX25hbWUpCgojIDMuIFNwbGl0IEZpbmRBbGxNYXJrZXJzIGRhdGEgZnJhbWUgYnkgY2x1c3RlcgpjbHVzdGVyX3N0YXRzIDwtIHNwbGl0KGFsbF9tYXJrZXJzLCBhbGxfbWFya2VycyRjbHVzdGVyKQoKIyA0LiBSdW4gZmdzZWEgdXNpbmcgYXZnX2xvZzJGQyBhcyByYW5raW5nIG1ldHJpYwpmZ3NlYV9yZXN1bHRzIDwtIGxhcHBseShjbHVzdGVyX3N0YXRzLCBmdW5jdGlvbihzdGF0c19kZikgewogICMgRW5zdXJlIGF2Z19sb2cyRkMgZXhpc3RzIGFuZCBnZW5lIG5hbWVzIGFyZSBwcmVzZW50CiAgc3RhdHNfZGYgPC0gc3RhdHNfZGYgJT4lCiAgICBmaWx0ZXIoIWlzLm5hKGF2Z19sb2cyRkMpKSAlPiUKICAgIGRpc3RpbmN0KGdlbmUsIC5rZWVwX2FsbCA9IFRSVUUpCgogICMgQ2hlY2sgaWYgZ2VuZSBjb2x1bW4gZXhpc3RzCiAgaWYgKCEiZ2VuZSIgJWluJSBjb2xuYW1lcyhzdGF0c19kZikpIHsKICAgIHdhcm5pbmcoIk5vICdnZW5lJyBjb2x1bW4gZm91bmQgaW4gc3RhdHNfZGYiKQogICAgcmV0dXJuKE5VTEwpCiAgfQoKICAjIENyZWF0ZSByYW5rIHZlY3RvcgogIHJhbmtzIDwtIHN0YXRzX2RmJGF2Z19sb2cyRkMKICBuYW1lcyhyYW5rcykgPC0gc3RhdHNfZGYkZ2VuZQogIHJhbmtzIDwtIHNvcnQocmFua3MsIGRlY3JlYXNpbmcgPSBUUlVFKQoKICAjIE9wdGlvbmFsOiBza2lwIHNtYWxsIHJhbmsgdmVjdG9ycwogIGlmIChsZW5ndGgocmFua3MpIDwgMTAwKSByZXR1cm4oTlVMTCkKCiAgIGZnc2VhKAogICAgcGF0aHdheXMgPSBwYXRod2F5c19saXN0LAogICAgc3RhdHMgPSBzb3J0KHJhbmtzLCBkZWNyZWFzaW5nID0gVFJVRSksCiAgICBtaW5TaXplID0gMTAsCiAgICBtYXhTaXplID0gMzAwLAogICAgbnBlcm0gPSAxMDAwMAogICkKfSkKCgojIDUuIENvbWJpbmUgYW5kIGFubm90YXRlIHJlc3VsdHMKZ3NlYV9kZiA8LSBiaW5kX3Jvd3MobGFwcGx5KG5hbWVzKGZnc2VhX3Jlc3VsdHMpLCBmdW5jdGlvbihjbHVzdGVyKSB7CiAgcmVzIDwtIGZnc2VhX3Jlc3VsdHNbW2NsdXN0ZXJdXQogIHJlcyRjbHVzdGVyIDwtIGNsdXN0ZXIKICByZXMKfSkpCgojIDYuIEVuc3VyZSBhbGwgcGF0aHdheXMgYXBwZWFyIGFjcm9zcyBjbHVzdGVycwphbGxfY29tYm9zIDwtIGV4cGFuZC5ncmlkKAogIGNsdXN0ZXIgPSBuYW1lcyhjbHVzdGVyX3N0YXRzKSwKICBwYXRod2F5ID0gY3VyYXRlZF9wYXRod2F5cywKICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UKKQoKZ3NlYV9jb21wbGV0ZSA8LSBhbGxfY29tYm9zICU+JQogIGxlZnRfam9pbihnc2VhX2RmLCBieSA9IGMoImNsdXN0ZXIiLCAicGF0aHdheSIpKSAlPiUKICBtdXRhdGUoCiAgICBORVMgPSBpZmVsc2UoaXMubmEoTkVTKSwgMCwgTkVTKSwKICAgIHBhZGogPSBpZmVsc2UoaXMubmEocGFkaiksIDEsIHBhZGopLAogICAgZGF0YWJhc2UgPSBjYXNlX3doZW4oCiAgICAgIHN0cl9kZXRlY3QocGF0aHdheSwgIl5IQUxMTUFSSyIpIH4gIkhhbGxtYXJrIiwKICAgICAgc3RyX2RldGVjdChwYXRod2F5LCAiXktFR0ciKSB+ICJLRUdHIiwKICAgICAgc3RyX2RldGVjdChwYXRod2F5LCAiXlJFQUNUT01FIikgfiAiUmVhY3RvbWUiLAogICAgICBzdHJfZGV0ZWN0KHBhdGh3YXksICJeR09CUCIpIH4gIkdPIiwKICAgICAgVFJVRSB+ICJPdGhlciIKICAgICksCiAgICBkaXJlY3Rpb25fZGIgPSBpZmVsc2UoTkVTID4gMCwgcGFzdGUwKCIrICIsIGRhdGFiYXNlKSwgcGFzdGUwKCItICIsIGRhdGFiYXNlKSksCiAgICBzaWcgPSBpZmVsc2UocGFkaiA8IDAuMDUsICIqIiwgIiIpCiAgKQoKIyA3LiBDb2xvciBwYWxldHRlCnBhbGV0dGUgPC0gYygKICBgKyBIYWxsbWFya2AgPSAiI2Q2MjcyOCIsIGAtIEhhbGxtYXJrYCA9ICIjZmNiYmExIiwKICBgKyBLRUdHYCA9ICIjMmNhMDJjIiwgYC0gS0VHR2AgPSAiI2I5ZjZjYSIsCiAgYCsgUmVhY3RvbWVgID0gIiMxZjc3YjQiLCBgLSBSZWFjdG9tZWAgPSAiI2FlYzdlOCIsCiAgYCsgR09gID0gIiM5NDY3YmQiLCBgLSBHT2AgPSAiI2Q1YmRlMyIKKQoKIyA4LiBQbG90CnA0IDwtIGdncGxvdChnc2VhX2NvbXBsZXRlLCBhZXMoeCA9IGZjdF9yZW9yZGVyKHBhdGh3YXksIE5FUyksIHkgPSBORVMsIGZpbGwgPSBkaXJlY3Rpb25fZGIpKSArCiAgZ2VvbV9jb2wod2lkdGggPSAwLjkpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gc2lnKSwgaGp1c3QgPSAtMC4zLCBzaXplID0gNSwgZm9udGZhY2UgPSAiYm9sZCIsIGNvbG9yID0gImJsYWNrIikgKwogIGNvb3JkX2ZsaXAoKSArCiAgZmFjZXRfZ3JpZChkYXRhYmFzZSB+IGNsdXN0ZXIsIHNjYWxlcyA9ICJmcmVlX3kiLCBzcGFjZSA9ICJmcmVlIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gImdyYXk1MCIpICsKICBsYWJzKAogICAgeCA9ICJQYXRod2F5IiwKICAgIHkgPSAiTm9ybWFsaXplZCBFbnJpY2htZW50IFNjb3JlIChORVMpIiwKICAgIHRpdGxlID0gIkdTRUEgKGF2Z19sb2cyRkMgb25seSkg4oCUIEN1cmF0ZWQgUGF0aHdheXMgcGVyIENsdXN0ZXIiLAogICAgZmlsbCA9ICJFbnJpY2htZW50IgogICkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGUsIG5hLnZhbHVlID0gImdyYXk4MCIpICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE2KSArCiAgdGhlbWUoCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNiksCiAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiZ3JheTkwIiwgY29sb3IgPSAiYmxhY2siKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDEzKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksCiAgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgxLCAibGluZXMiKSwKICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvciA9ICJibGFjayIsIGZpbGwgPSBOQSwgc2l6ZSA9IDEuNSkKICApCgojIDkuIFNhdmUgdG8gUERGCmdnc2F2ZSgiQ3VyYXRlZF9HU0VBX2F2Z0xvZ0ZDX09ubHkucGRmIiwgcDQsIHdpZHRoID0gMzAsIGhlaWdodCA9IDU4LCBsaW1pdHNpemUgPSBGQUxTRSkKCnA0CmBgYAoKCg==