1. load libraries

#Differential Expression Analysis

2. load seurat object

#Differential Expression Analysis # 3. Pairwise Comparisons

library(Seurat)
library(dplyr)
library(tibble)
library(EnhancedVolcano)

# Extract normalized expression values for RNA assay
expression_data_RNA <- GetAssayData(All_samples_Merged, assay = "RNA", slot = "data")  # RNA-normalized counts

# Function to calculate mean expression for the specific comparison groups
calculate_mean_expression <- function(markers, ident1_cells, ident2_cells, expression_data) {
  group1_mean <- rowMeans(expression_data[, ident1_cells, drop = FALSE], na.rm = TRUE)
  group2_mean <- rowMeans(expression_data[, ident2_cells, drop = FALSE], na.rm = TRUE)
  
  markers <- markers %>%
    rownames_to_column("gene") %>%
    mutate(mean_expr_ident1 = group1_mean[gene],
           mean_expr_ident2 = group2_mean[gene])
  
  return(markers)
}

# Function to perform DE analysis, compute mean expression, generate volcano plot, and save results
perform_comparison_and_volcano <- function(All_samples_Merged, ident1, ident2, expression_data) {
  Idents(All_samples_Merged) <- "cell_line"
  
  # Get cells belonging to each identity
  ident1_cells <- WhichCells(All_samples_Merged, idents = ident1)
  ident2_cells <- WhichCells(All_samples_Merged, idents = ident2)
  
  # Perform differential expression analysis using RNA assay
  markers <- FindMarkers(All_samples_Merged, ident.1 = ident1, ident.2 = ident2, assay = "RNA")
  
  # Compute mean expression for the two compared groups using RNA-normalized counts
  markers_with_mean <- calculate_mean_expression(markers, ident1_cells, ident2_cells, expression_data)
  
  # Save results to CSV
  output_filename <- paste0("comparison_", ident1, "_vs_", ident2, "_with_mean_expression.csv")
  write.csv(markers_with_mean, file = output_filename, row.names = FALSE)
  
  # Create volcano plot
  volcano_plot <- EnhancedVolcano(markers_with_mean,
                                  lab = markers_with_mean$gene,
                                  x = 'avg_log2FC',
                                  y = 'p_val_adj',
                                  title = paste(ident1, 'vs', ident2),
                                  pCutoff = 0.05,
                                  FCcutoff = 1)
  
  print(volcano_plot)
  png(paste0("volcano_", ident1, "_vs_", ident2, ".png"), width = 12, height = 10, units = "in", res = 300)
  print(volcano_plot)
  dev.off()
  
  return(markers_with_mean)
}

# Perform comparisons dynamically for each cell line pair
p1_comparison <- perform_comparison_and_volcano(All_samples_Merged, "L1", "L2", expression_data_RNA)
Warning: One or more p-values is 0. Converting to 10^-1 * current lowest non-zero p-value...

p2_comparison <- perform_comparison_and_volcano(All_samples_Merged, "L3", "L4", expression_data_RNA)
Warning: One or more p-values is 0. Converting to 10^-1 * current lowest non-zero p-value...

p3_comparison_L5L6 <- perform_comparison_and_volcano(All_samples_Merged, "L5", "L6", expression_data_RNA)
Warning: One or more p-values is 0. Converting to 10^-1 * current lowest non-zero p-value...

p3_comparison_L5L7 <- perform_comparison_and_volcano(All_samples_Merged, "L5", "L7", expression_data_RNA)
Warning: One or more p-values is 0. Converting to 10^-1 * current lowest non-zero p-value...

p3_comparison_L6L7 <- perform_comparison_and_volcano(All_samples_Merged, "L6", "L7", expression_data_RNA)
Warning: One or more p-values is 0. Converting to 10^-1 * current lowest non-zero p-value...

# Print the first few rows of each result
head(p1_comparison)
head(p2_comparison)
head(p3_comparison_L5L6)
head(p3_comparison_L5L7)
head(p3_comparison_L6L7)

4. Pairwise Comparisons Filtering

library(dplyr)

# Function to summarize DE markers
summarize_markers <- function(markers, comparison_name) {
  num_pval0 <- sum(markers$p_val_adj == 0)
  num_pval1 <- sum(markers$p_val_adj == 1)
  num_significant <- sum(markers$p_val_adj < 0.05)
  num_upregulated <- sum(markers$avg_log2FC > 1)
  num_downregulated <- sum(markers$avg_log2FC < -1)
  
  cat("\nSummary for", comparison_name, ":\n")
  cat("Number of genes with p_val_adj = 0:", num_pval0, "\n")
  cat("Number of genes with p_val_adj = 1:", num_pval1, "\n")
  cat("Number of significant genes (p_val_adj < 0.05):", num_significant, "\n")
  cat("Number of upregulated genes (avg_log2FC > 1):", num_upregulated, "\n")
  cat("Number of downregulated genes (avg_log2FC < -1):", num_downregulated, "\n")
}

# Function to filter DE markers and save results
filter_and_save <- function(markers, ident1, ident2) {
  comparison_name <- paste(ident1, "vs", ident2)
  
  # Summary before filtering
  summarize_markers(markers, comparison_name)
  
  # Apply the expression filter
  markers_filtered <- markers %>%
    filter(!(mean_expr_ident1 < 0.2 & mean_expr_ident2 < 0.2))

  # Save filtered results
  output_filename <- paste0("comparison_", ident1, "_vs_", ident2, "_with_mean_expression_filtered.csv")
  write.csv(markers_filtered, file = output_filename, row.names = FALSE)
  
  cat("Filtered results saved to:", output_filename, "\n")
  
  return(markers_filtered)
}

# Apply the function to all comparisons
p1_filtered <- filter_and_save(p1_comparison, "L1", "L2")

Summary for L1 vs L2 :
Number of genes with p_val_adj = 0: 1301 
Number of genes with p_val_adj = 1: 2209 
Number of significant genes (p_val_adj < 0.05): 10169 
Number of upregulated genes (avg_log2FC > 1): 1297 
Number of downregulated genes (avg_log2FC < -1): 3216 
Filtered results saved to: comparison_L1_vs_L2_with_mean_expression_filtered.csv 
p2_filtered <- filter_and_save(p2_comparison, "L3", "L4")

Summary for L3 vs L4 :
Number of genes with p_val_adj = 0: 389 
Number of genes with p_val_adj = 1: 2998 
Number of significant genes (p_val_adj < 0.05): 8391 
Number of upregulated genes (avg_log2FC > 1): 943 
Number of downregulated genes (avg_log2FC < -1): 1537 
Filtered results saved to: comparison_L3_vs_L4_with_mean_expression_filtered.csv 
p3_filtered_L5L6 <- filter_and_save(p3_comparison_L5L6, "L5", "L6")

Summary for L5 vs L6 :
Number of genes with p_val_adj = 0: 375 
Number of genes with p_val_adj = 1: 3837 
Number of significant genes (p_val_adj < 0.05): 7656 
Number of upregulated genes (avg_log2FC > 1): 1350 
Number of downregulated genes (avg_log2FC < -1): 1700 
Filtered results saved to: comparison_L5_vs_L6_with_mean_expression_filtered.csv 
p3_filtered_L5L7 <- filter_and_save(p3_comparison_L5L7, "L5", "L7")

Summary for L5 vs L7 :
Number of genes with p_val_adj = 0: 189 
Number of genes with p_val_adj = 1: 4450 
Number of significant genes (p_val_adj < 0.05): 5982 
Number of upregulated genes (avg_log2FC > 1): 1063 
Number of downregulated genes (avg_log2FC < -1): 1129 
Filtered results saved to: comparison_L5_vs_L7_with_mean_expression_filtered.csv 
p3_filtered_L6L7 <- filter_and_save(p3_comparison_L6L7, "L6", "L7")

Summary for L6 vs L7 :
Number of genes with p_val_adj = 0: 172 
Number of genes with p_val_adj = 1: 4312 
Number of significant genes (p_val_adj < 0.05): 6485 
Number of upregulated genes (avg_log2FC > 1): 1113 
Number of downregulated genes (avg_log2FC < -1): 929 
Filtered results saved to: comparison_L6_vs_L7_with_mean_expression_filtered.csv 
LS0tCnRpdGxlOiAiU8OpemFyeSBTeW5kcm9tZSBDZWxsIExpbmUgQW5hbHlzaXNfTmV3VU1BUF9XaWxjb3hfUk5BX0Fzc2F5IgphdXRob3I6IE5hc2lyIE1haG1vb2QgQWJiYXNpCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogICMgcGRmX2RvY3VtZW50OiBkZWZhdWx0CiAgIyB3b3JkX2RvY3VtZW50OiBkZWZhdWx0CiAgIyBodG1sX2RvY3VtZW50OiBkZWZhdWx0CiAgI3JtZGZvcm1hdHM6OnJlYWR0aGVkb3duCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfY29sbGFwc2VkOiB0cnVlCi0tLQoKIyAxLiBsb2FkIGxpYnJhcmllcwpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KCgpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBoZWF0bWFwKQpsaWJyYXJ5KGNsdXN0ZXJQcm9maWxlcikKbGlicmFyeShvcmcuSHMuZWcuZGIpCmxpYnJhcnkoZW5yaWNocGxvdCkKbGlicmFyeShlbnJpY2hwbG90KQoKCgpgYGAKI0RpZmZlcmVudGlhbCBFeHByZXNzaW9uIEFuYWx5c2lzCgojIDIuIGxvYWQgc2V1cmF0IG9iamVjdApgYGB7ciBsb2FkX3NldXJhdH0KI0xvYWQgU2V1cmF0IE9iamVjdCBMNwpsb2FkKCI1LUhhcm1vbnlfSW50ZWdyYXRlZF9BbGxfc2FtcGxlc19NZXJnZWRfQ0Q0VGNlbGxzX2ZpbmFsX1Jlc29sdXRpb25fU2VsZWN0ZWRfMC44X0FEVF9Ob3JtYWxpemVkX2NsZWFuZWRfbXRfUk5BX2Fzc2F5X25vcm1hbGl6ZWQucm9iaiIpCgoKCmBgYAoKCiNEaWZmZXJlbnRpYWwgRXhwcmVzc2lvbiBBbmFseXNpcwojIDMuIFBhaXJ3aXNlIENvbXBhcmlzb25zCmBgYHtyICwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpYmJsZSkKbGlicmFyeShFbmhhbmNlZFZvbGNhbm8pCgojIEV4dHJhY3Qgbm9ybWFsaXplZCBleHByZXNzaW9uIHZhbHVlcyBmb3IgUk5BIGFzc2F5CmV4cHJlc3Npb25fZGF0YV9STkEgPC0gR2V0QXNzYXlEYXRhKEFsbF9zYW1wbGVzX01lcmdlZCwgYXNzYXkgPSAiUk5BIiwgc2xvdCA9ICJkYXRhIikgICMgUk5BLW5vcm1hbGl6ZWQgY291bnRzCgojIEZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSBtZWFuIGV4cHJlc3Npb24gZm9yIHRoZSBzcGVjaWZpYyBjb21wYXJpc29uIGdyb3VwcwpjYWxjdWxhdGVfbWVhbl9leHByZXNzaW9uIDwtIGZ1bmN0aW9uKG1hcmtlcnMsIGlkZW50MV9jZWxscywgaWRlbnQyX2NlbGxzLCBleHByZXNzaW9uX2RhdGEpIHsKICBncm91cDFfbWVhbiA8LSByb3dNZWFucyhleHByZXNzaW9uX2RhdGFbLCBpZGVudDFfY2VsbHMsIGRyb3AgPSBGQUxTRV0sIG5hLnJtID0gVFJVRSkKICBncm91cDJfbWVhbiA8LSByb3dNZWFucyhleHByZXNzaW9uX2RhdGFbLCBpZGVudDJfY2VsbHMsIGRyb3AgPSBGQUxTRV0sIG5hLnJtID0gVFJVRSkKICAKICBtYXJrZXJzIDwtIG1hcmtlcnMgJT4lCiAgICByb3duYW1lc190b19jb2x1bW4oImdlbmUiKSAlPiUKICAgIG11dGF0ZShtZWFuX2V4cHJfaWRlbnQxID0gZ3JvdXAxX21lYW5bZ2VuZV0sCiAgICAgICAgICAgbWVhbl9leHByX2lkZW50MiA9IGdyb3VwMl9tZWFuW2dlbmVdKQogIAogIHJldHVybihtYXJrZXJzKQp9CgojIEZ1bmN0aW9uIHRvIHBlcmZvcm0gREUgYW5hbHlzaXMsIGNvbXB1dGUgbWVhbiBleHByZXNzaW9uLCBnZW5lcmF0ZSB2b2xjYW5vIHBsb3QsIGFuZCBzYXZlIHJlc3VsdHMKcGVyZm9ybV9jb21wYXJpc29uX2FuZF92b2xjYW5vIDwtIGZ1bmN0aW9uKEFsbF9zYW1wbGVzX01lcmdlZCwgaWRlbnQxLCBpZGVudDIsIGV4cHJlc3Npb25fZGF0YSkgewogIElkZW50cyhBbGxfc2FtcGxlc19NZXJnZWQpIDwtICJjZWxsX2xpbmUiCiAgCiAgIyBHZXQgY2VsbHMgYmVsb25naW5nIHRvIGVhY2ggaWRlbnRpdHkKICBpZGVudDFfY2VsbHMgPC0gV2hpY2hDZWxscyhBbGxfc2FtcGxlc19NZXJnZWQsIGlkZW50cyA9IGlkZW50MSkKICBpZGVudDJfY2VsbHMgPC0gV2hpY2hDZWxscyhBbGxfc2FtcGxlc19NZXJnZWQsIGlkZW50cyA9IGlkZW50MikKICAKICAjIFBlcmZvcm0gZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMgdXNpbmcgUk5BIGFzc2F5CiAgbWFya2VycyA8LSBGaW5kTWFya2VycyhBbGxfc2FtcGxlc19NZXJnZWQsIGlkZW50LjEgPSBpZGVudDEsIGlkZW50LjIgPSBpZGVudDIsIGFzc2F5ID0gIlJOQSIpCiAgCiAgIyBDb21wdXRlIG1lYW4gZXhwcmVzc2lvbiBmb3IgdGhlIHR3byBjb21wYXJlZCBncm91cHMgdXNpbmcgUk5BLW5vcm1hbGl6ZWQgY291bnRzCiAgbWFya2Vyc193aXRoX21lYW4gPC0gY2FsY3VsYXRlX21lYW5fZXhwcmVzc2lvbihtYXJrZXJzLCBpZGVudDFfY2VsbHMsIGlkZW50Ml9jZWxscywgZXhwcmVzc2lvbl9kYXRhKQogIAogICMgU2F2ZSByZXN1bHRzIHRvIENTVgogIG91dHB1dF9maWxlbmFtZSA8LSBwYXN0ZTAoImNvbXBhcmlzb25fIiwgaWRlbnQxLCAiX3ZzXyIsIGlkZW50MiwgIl93aXRoX21lYW5fZXhwcmVzc2lvbi5jc3YiKQogIHdyaXRlLmNzdihtYXJrZXJzX3dpdGhfbWVhbiwgZmlsZSA9IG91dHB1dF9maWxlbmFtZSwgcm93Lm5hbWVzID0gRkFMU0UpCiAgCiAgIyBDcmVhdGUgdm9sY2FubyBwbG90CiAgdm9sY2Fub19wbG90IDwtIEVuaGFuY2VkVm9sY2FubyhtYXJrZXJzX3dpdGhfbWVhbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYiA9IG1hcmtlcnNfd2l0aF9tZWFuJGdlbmUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gJ2F2Z19sb2cyRkMnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9ICdwX3ZhbF9hZGonLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSBwYXN0ZShpZGVudDEsICd2cycsIGlkZW50MiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwQ3V0b2ZmID0gMC4wNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZDY3V0b2ZmID0gMSkKICAKICBwcmludCh2b2xjYW5vX3Bsb3QpCiAgcG5nKHBhc3RlMCgidm9sY2Fub18iLCBpZGVudDEsICJfdnNfIiwgaWRlbnQyLCAiLnBuZyIpLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiaW4iLCByZXMgPSAzMDApCiAgcHJpbnQodm9sY2Fub19wbG90KQogIGRldi5vZmYoKQogIAogIHJldHVybihtYXJrZXJzX3dpdGhfbWVhbikKfQoKIyBQZXJmb3JtIGNvbXBhcmlzb25zIGR5bmFtaWNhbGx5IGZvciBlYWNoIGNlbGwgbGluZSBwYWlyCnAxX2NvbXBhcmlzb24gPC0gcGVyZm9ybV9jb21wYXJpc29uX2FuZF92b2xjYW5vKEFsbF9zYW1wbGVzX01lcmdlZCwgIkwxIiwgIkwyIiwgZXhwcmVzc2lvbl9kYXRhX1JOQSkKcDJfY29tcGFyaXNvbiA8LSBwZXJmb3JtX2NvbXBhcmlzb25fYW5kX3ZvbGNhbm8oQWxsX3NhbXBsZXNfTWVyZ2VkLCAiTDMiLCAiTDQiLCBleHByZXNzaW9uX2RhdGFfUk5BKQpwM19jb21wYXJpc29uX0w1TDYgPC0gcGVyZm9ybV9jb21wYXJpc29uX2FuZF92b2xjYW5vKEFsbF9zYW1wbGVzX01lcmdlZCwgIkw1IiwgIkw2IiwgZXhwcmVzc2lvbl9kYXRhX1JOQSkKcDNfY29tcGFyaXNvbl9MNUw3IDwtIHBlcmZvcm1fY29tcGFyaXNvbl9hbmRfdm9sY2FubyhBbGxfc2FtcGxlc19NZXJnZWQsICJMNSIsICJMNyIsIGV4cHJlc3Npb25fZGF0YV9STkEpCnAzX2NvbXBhcmlzb25fTDZMNyA8LSBwZXJmb3JtX2NvbXBhcmlzb25fYW5kX3ZvbGNhbm8oQWxsX3NhbXBsZXNfTWVyZ2VkLCAiTDYiLCAiTDciLCBleHByZXNzaW9uX2RhdGFfUk5BKQoKIyBQcmludCB0aGUgZmlyc3QgZmV3IHJvd3Mgb2YgZWFjaCByZXN1bHQKaGVhZChwMV9jb21wYXJpc29uKQpoZWFkKHAyX2NvbXBhcmlzb24pCmhlYWQocDNfY29tcGFyaXNvbl9MNUw2KQpoZWFkKHAzX2NvbXBhcmlzb25fTDVMNykKaGVhZChwM19jb21wYXJpc29uX0w2TDcpCmBgYAojIDQuIFBhaXJ3aXNlIENvbXBhcmlzb25zIEZpbHRlcmluZyAKYGBge3IgLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMn0KbGlicmFyeShkcGx5cikKCiMgRnVuY3Rpb24gdG8gc3VtbWFyaXplIERFIG1hcmtlcnMKc3VtbWFyaXplX21hcmtlcnMgPC0gZnVuY3Rpb24obWFya2VycywgY29tcGFyaXNvbl9uYW1lKSB7CiAgbnVtX3B2YWwwIDwtIHN1bShtYXJrZXJzJHBfdmFsX2FkaiA9PSAwKQogIG51bV9wdmFsMSA8LSBzdW0obWFya2VycyRwX3ZhbF9hZGogPT0gMSkKICBudW1fc2lnbmlmaWNhbnQgPC0gc3VtKG1hcmtlcnMkcF92YWxfYWRqIDwgMC4wNSkKICBudW1fdXByZWd1bGF0ZWQgPC0gc3VtKG1hcmtlcnMkYXZnX2xvZzJGQyA+IDEpCiAgbnVtX2Rvd25yZWd1bGF0ZWQgPC0gc3VtKG1hcmtlcnMkYXZnX2xvZzJGQyA8IC0xKQogIAogIGNhdCgiXG5TdW1tYXJ5IGZvciIsIGNvbXBhcmlzb25fbmFtZSwgIjpcbiIpCiAgY2F0KCJOdW1iZXIgb2YgZ2VuZXMgd2l0aCBwX3ZhbF9hZGogPSAwOiIsIG51bV9wdmFsMCwgIlxuIikKICBjYXQoIk51bWJlciBvZiBnZW5lcyB3aXRoIHBfdmFsX2FkaiA9IDE6IiwgbnVtX3B2YWwxLCAiXG4iKQogIGNhdCgiTnVtYmVyIG9mIHNpZ25pZmljYW50IGdlbmVzIChwX3ZhbF9hZGogPCAwLjA1KToiLCBudW1fc2lnbmlmaWNhbnQsICJcbiIpCiAgY2F0KCJOdW1iZXIgb2YgdXByZWd1bGF0ZWQgZ2VuZXMgKGF2Z19sb2cyRkMgPiAxKToiLCBudW1fdXByZWd1bGF0ZWQsICJcbiIpCiAgY2F0KCJOdW1iZXIgb2YgZG93bnJlZ3VsYXRlZCBnZW5lcyAoYXZnX2xvZzJGQyA8IC0xKToiLCBudW1fZG93bnJlZ3VsYXRlZCwgIlxuIikKfQoKIyBGdW5jdGlvbiB0byBmaWx0ZXIgREUgbWFya2VycyBhbmQgc2F2ZSByZXN1bHRzCmZpbHRlcl9hbmRfc2F2ZSA8LSBmdW5jdGlvbihtYXJrZXJzLCBpZGVudDEsIGlkZW50MikgewogIGNvbXBhcmlzb25fbmFtZSA8LSBwYXN0ZShpZGVudDEsICJ2cyIsIGlkZW50MikKICAKICAjIFN1bW1hcnkgYmVmb3JlIGZpbHRlcmluZwogIHN1bW1hcml6ZV9tYXJrZXJzKG1hcmtlcnMsIGNvbXBhcmlzb25fbmFtZSkKICAKICAjIEFwcGx5IHRoZSBleHByZXNzaW9uIGZpbHRlcgogIG1hcmtlcnNfZmlsdGVyZWQgPC0gbWFya2VycyAlPiUKICAgIGZpbHRlcighKG1lYW5fZXhwcl9pZGVudDEgPCAwLjIgJiBtZWFuX2V4cHJfaWRlbnQyIDwgMC4yKSkKCiAgIyBTYXZlIGZpbHRlcmVkIHJlc3VsdHMKICBvdXRwdXRfZmlsZW5hbWUgPC0gcGFzdGUwKCJjb21wYXJpc29uXyIsIGlkZW50MSwgIl92c18iLCBpZGVudDIsICJfd2l0aF9tZWFuX2V4cHJlc3Npb25fZmlsdGVyZWQuY3N2IikKICB3cml0ZS5jc3YobWFya2Vyc19maWx0ZXJlZCwgZmlsZSA9IG91dHB1dF9maWxlbmFtZSwgcm93Lm5hbWVzID0gRkFMU0UpCiAgCiAgY2F0KCJGaWx0ZXJlZCByZXN1bHRzIHNhdmVkIHRvOiIsIG91dHB1dF9maWxlbmFtZSwgIlxuIikKICAKICByZXR1cm4obWFya2Vyc19maWx0ZXJlZCkKfQoKIyBBcHBseSB0aGUgZnVuY3Rpb24gdG8gYWxsIGNvbXBhcmlzb25zCnAxX2ZpbHRlcmVkIDwtIGZpbHRlcl9hbmRfc2F2ZShwMV9jb21wYXJpc29uLCAiTDEiLCAiTDIiKQpwMl9maWx0ZXJlZCA8LSBmaWx0ZXJfYW5kX3NhdmUocDJfY29tcGFyaXNvbiwgIkwzIiwgIkw0IikKcDNfZmlsdGVyZWRfTDVMNiA8LSBmaWx0ZXJfYW5kX3NhdmUocDNfY29tcGFyaXNvbl9MNUw2LCAiTDUiLCAiTDYiKQpwM19maWx0ZXJlZF9MNUw3IDwtIGZpbHRlcl9hbmRfc2F2ZShwM19jb21wYXJpc29uX0w1TDcsICJMNSIsICJMNyIpCnAzX2ZpbHRlcmVkX0w2TDcgPC0gZmlsdGVyX2FuZF9zYXZlKHAzX2NvbXBhcmlzb25fTDZMNywgIkw2IiwgIkw3IikKCgoKYGBgCgo=