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=