Setup and
Libraries
# Data Processing & Single-Cell Analysis
library(dplyr)
library(tibble)
library(tidyr)
library(Seurat)
library(Matrix)
# Visualization
library(ggplot2)
library(patchwork)
library(ComplexHeatmap)
library(circlize)
library(grid)
library(EnhancedVolcano)
# Create output directories if they do not exist
dir.create("Output_Figures", showWarnings = FALSE)
dir.create("Output_Tables", showWarnings = FALSE)
Load Seurat Object and
Define Conditions
# Load Seurat Object directly from cluster relative path
seurat_obj <- readRDS("../../0-Seurat_objects/Seurat_Object_With_TF_Activity.rds")
Idents(seurat_obj) <- "seurat_clusters"
# Define Malignant vs Non-Malignant (Clusters 3 & 10 = Normal CD4+ T reference)
non_malignant_clusters <- c(3, 10)
seurat_obj$Condition <- ifelse(seurat_obj$seurat_clusters %in% non_malignant_clusters,
"Non-Malignant",
"Malignant")
seurat_obj$Condition <- factor(seurat_obj$Condition, levels = c("Non-Malignant", "Malignant"))
print("Seurat Object Loaded successfully:")
[1] "Seurat Object Loaded successfully:"
table(seurat_obj$Condition)
Non-Malignant Malignant
7873 41432
Differential Statistics
for MAX & Network Partners
# --- 1. Gene Expression (SCT Assay) ---
DefaultAssay(seurat_obj) <- "SCT"
Idents(seurat_obj) <- "Condition"
candidate_genes <- intersect(
c("MAX", "MYC", "MLX", "MLXIP", "MLXIPL", "MNT", "MXD1", "MXI1", "E2F1", "CLIC1"),
rownames(seurat_obj[["SCT"]])
)
deg_sct <- FindMarkers(
seurat_obj,
features = candidate_genes,
ident.1 = "Malignant",
ident.2 = "Non-Malignant",
logfc.threshold = 0,
min.pct = 0
)
| | 0 % ~calculating
|+++++ | 10% ~00s
|++++++++++ | 20% ~00s
|+++++++++++++++ | 30% ~00s
|++++++++++++++++++++ | 40% ~00s
|+++++++++++++++++++++++++ | 50% ~00s
|++++++++++++++++++++++++++++++ | 60% ~00s
|+++++++++++++++++++++++++++++++++++ | 70% ~00s
|++++++++++++++++++++++++++++++++++++++++ | 80% ~00s
|+++++++++++++++++++++++++++++++++++++++++++++ | 90% ~00s
|++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=00s
deg_sct$Gene <- rownames(deg_sct)
deg_sct$Assay <- "SCT (mRNA Expression)"
# --- 2. TF Activity (dorothea Assay) ---
DefaultAssay(seurat_obj) <- "dorothea"
candidate_tfs <- intersect(
c("MAX", "MYC", "E2F1", "E2F4", "FOXM1", "FOXO1"),
rownames(seurat_obj[["dorothea"]])
)
deg_tf <- FindMarkers(
seurat_obj,
features = candidate_tfs,
ident.1 = "Malignant",
ident.2 = "Non-Malignant",
logfc.threshold = 0,
min.pct = 0
)
| | 0 % ~calculating
|+++++++++++++++++ | 33% ~01s
|++++++++++++++++++++++++++++++++++ | 67% ~00s
|++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=00s
deg_tf$Gene <- rownames(deg_tf)
deg_tf$Assay <- "dorothea (TF Activity)"
# Combine and save table for reviewer response
deg_summary <- bind_rows(deg_sct, deg_tf) %>%
select(Assay, Gene, avg_log2FC, pct.1, pct.2, p_val, p_val_adj)
write.csv(deg_summary, "Output_Tables/MAX_Network_Differential_Summary.csv", row.names = FALSE)
print("=== Differential Statistics for MAX & Key Network Members ===")
[1] "=== Differential Statistics for MAX & Key Network Members ==="
print(deg_summary)
UMAP Feature Plots: MAX
TF Activity vs. MAX Gene Expression
# --- Panel 1: MAX TF Activity (Red = dorothea Assay) ---
DefaultAssay(seurat_obj) <- "dorothea"
p_max_act <- FeaturePlot(seurat_obj, features = "MAX", order = TRUE, reduction = "umap") +
scale_color_gradientn(colors = c("grey90", "firebrick")) +
ggtitle("MAX Regulon Activity (dorothea)") +
theme(plot.title = element_text(face = "bold", size = 12))
# --- Panel 2: MAX Gene Expression (Blue = SCT Assay) ---
DefaultAssay(seurat_obj) <- "SCT"
p_max_exp <- FeaturePlot(seurat_obj, features = "MAX", order = TRUE, reduction = "umap") +
scale_color_gradientn(colors = c("grey90", "darkblue")) +
ggtitle("MAX Gene Expression (SCT)") +
theme(plot.title = element_text(face = "bold", size = 12))
# Combine side-by-side
fig_max_umap <- p_max_act | p_max_exp
fig_max_umap <- fig_max_umap + plot_annotation(
title = "MAX Network Decoupling in Sézary Syndrome (Activity vs. mRNA Expression)",
theme = theme(plot.title = element_text(face = "bold", size = 14))
)
# Display & Save
print(fig_max_umap)

ggsave("Output_Figures/Figure_MAX_UMAP_Activity_vs_Expression.pdf", plot = fig_max_umap, width = 11, height = 5)
ggsave("Output_Figures/Figure_MAX_UMAP_Activity_vs_Expression.png", plot = fig_max_umap, width = 11, height = 5, dpi = 300)
Violin Plots: Malignant
vs. Non-Malignant Quantification
# Panel A: MAX Expression (SCT)
vln_exp <- VlnPlot(seurat_obj, features = "MAX", assay = "SCT", group.by = "Condition", pt.size = 0.05) +
scale_fill_manual(values = c("Non-Malignant" = "#4DAF4A", "Malignant" = "#E41A1C")) +
ylab("Normalized Expression") +
ggtitle("MAX mRNA Expression (SCT)") +
theme(legend.position = "none", plot.title = element_text(face = "bold", size = 11))
# Panel B: MAX Activity (dorothea)
vln_act <- VlnPlot(seurat_obj, features = "MAX", assay = "dorothea", group.by = "Condition", pt.size = 0.05) +
scale_fill_manual(values = c("Non-Malignant" = "#4DAF4A", "Malignant" = "#E41A1C")) +
ylab("TF Activity Score") +
ggtitle("MAX TF Activity (dorothea)") +
theme(legend.position = "none", plot.title = element_text(face = "bold", size = 11))
# Panel C: MYC Activity (dorothea) for Direct Contrast
vln_myc <- VlnPlot(seurat_obj, features = "MYC", assay = "dorothea", group.by = "Condition", pt.size = 0.05) +
scale_fill_manual(values = c("Non-Malignant" = "#4DAF4A", "Malignant" = "#E41A1C")) +
ylab("TF Activity Score") +
ggtitle("MYC TF Activity (dorothea)") +
theme(legend.position = "none", plot.title = element_text(face = "bold", size = 11))
fig_vln_max <- vln_exp | vln_act | vln_myc
print(fig_vln_max)

ggsave("Output_Figures/Figure_MAX_MYC_Violin_Comparison.pdf", plot = fig_vln_max, width = 12, height = 4)
ggsave("Output_Figures/Figure_MAX_MYC_Violin_Comparison.png", plot = fig_vln_max, width = 12, height = 4, dpi = 300)
Cluster-Level
ComplexHeatmap (MAX vs. MYC and Core Regulators)
# Select targeted panel contrasting MYC/E2F oncogenic program with MAX and tumor suppressors
tf_panel <- c(
# Oncogenic / Proliferative
"MYC", "E2F1", "E2F4", "FOXM1", "SREBF1", "HIF1A",
# MAX
"MAX",
# Normal Homeostasis & Tumor Suppressors
"FOXO1", "FOXO4", "TCF7", "TBX21", "RUNX3"
)
# Extract TF Activity matrix (Seurat v4/v5 compatible)
mat_scaled <- tryCatch(
SeuratObject::GetAssayData(seurat_obj, assay = "dorothea", layer = "scale.data"),
error = function(e) NULL
)
mat_data <- SeuratObject::GetAssayData(seurat_obj, assay = "dorothea", layer = "data")
mat_use <- if (!is.null(mat_scaled) && nrow(mat_scaled) > 0) mat_scaled else mat_data
avail <- intersect(tf_panel, rownames(mat_use))
mat_use <- mat_use[avail, , drop = FALSE]
# Compute mean per cluster and calculate z-scores
clusters <- as.factor(seurat_obj$seurat_clusters)
avg_mat <- sapply(levels(clusters), function(cl) {
Matrix::rowMeans(mat_use[, clusters == cl, drop = FALSE])
})
colnames(avg_mat) <- levels(clusters)
avg_mat_z <- t(scale(t(avg_mat)))
avg_mat_z[is.na(avg_mat_z)] <- 0
# Set column annotations
cluster_status <- ifelse(colnames(avg_mat_z) %in% c("3", "10"),
"Normal CD4 T",
"Malignant CD4 T cells")
ha_col <- HeatmapAnnotation(
Cell_State = cluster_status,
col = list(Cell_State = c("Normal CD4 T" = "#4DAF4A", "Malignant CD4 T cells" = "#E41A1C")),
annotation_name_side = "left"
)
# Color scale: -3 to +3
col_fun <- circlize::colorRamp2(c(-3, 0, 3), c("#313695", "white", "#A50026"))
ht_max <- Heatmap(
avg_mat_z,
name = "TF activity (z)",
col = col_fun,
top_annotation = ha_col,
column_split = cluster_status,
cluster_rows = TRUE,
cluster_columns = TRUE,
show_row_dend = TRUE,
show_column_dend = TRUE,
row_names_gp = gpar(fontsize = 11, fontface = "bold"),
column_names_gp = gpar(fontsize = 10),
column_title = "Cluster-Level TF Activity: MYC/E2F Activation vs. MAX Repression",
heatmap_legend_param = list(direction = "vertical")
)
# Save and Draw
pdf("Output_Figures/Figure_MAX_MYC_Cluster_Heatmap.pdf", width = 10, height = 7)
draw(ht_max, merge_legend = TRUE)
dev.off()
null device
1
png("Output_Figures/Figure_MAX_MYC_Cluster_Heatmap.png", width = 10 * 300, height = 7 * 300, res = 300)
draw(ht_max, merge_legend = TRUE)
dev.off()
null device
1
draw(ht_max, merge_legend = TRUE)

Volcano Plot
Highlighting MAX & MYC Inferred Activity
# Differential TF Activity across all TFs
DefaultAssay(seurat_obj) <- "dorothea"
Idents(seurat_obj) <- "Condition"
all_tfs_diff <- FindMarkers(
seurat_obj,
ident.1 = "Malignant",
ident.2 = "Non-Malignant",
logfc.threshold = 0,
min.pct = 0
)
| | 0 % ~calculating
|+ | 2 % ~10s
|++ | 3 % ~09s
|+++ | 5 % ~09s
|++++ | 7 % ~09s
|+++++ | 8 % ~09s
|++++++ | 10% ~09s
|++++++ | 12% ~09s
|+++++++ | 14% ~08s
|++++++++ | 15% ~08s
|+++++++++ | 17% ~08s
|++++++++++ | 19% ~08s
|+++++++++++ | 20% ~08s
|++++++++++++ | 22% ~08s
|++++++++++++ | 24% ~08s
|+++++++++++++ | 25% ~07s
|++++++++++++++ | 27% ~07s
|+++++++++++++++ | 29% ~07s
|++++++++++++++++ | 31% ~07s
|+++++++++++++++++ | 32% ~07s
|+++++++++++++++++ | 34% ~07s
|++++++++++++++++++ | 36% ~07s
|+++++++++++++++++++ | 37% ~07s
|++++++++++++++++++++ | 39% ~07s
|+++++++++++++++++++++ | 41% ~06s
|++++++++++++++++++++++ | 42% ~06s
|+++++++++++++++++++++++ | 44% ~06s
|+++++++++++++++++++++++ | 46% ~06s
|++++++++++++++++++++++++ | 47% ~06s
|+++++++++++++++++++++++++ | 49% ~06s
|++++++++++++++++++++++++++ | 51% ~06s
|+++++++++++++++++++++++++++ | 53% ~06s
|++++++++++++++++++++++++++++ | 54% ~05s
|++++++++++++++++++++++++++++ | 56% ~05s
|+++++++++++++++++++++++++++++ | 58% ~05s
|++++++++++++++++++++++++++++++ | 59% ~05s
|+++++++++++++++++++++++++++++++ | 61% ~05s
|++++++++++++++++++++++++++++++++ | 63% ~04s
|+++++++++++++++++++++++++++++++++ | 64% ~04s
|++++++++++++++++++++++++++++++++++ | 66% ~04s
|++++++++++++++++++++++++++++++++++ | 68% ~04s
|+++++++++++++++++++++++++++++++++++ | 69% ~04s
|++++++++++++++++++++++++++++++++++++ | 71% ~03s
|+++++++++++++++++++++++++++++++++++++ | 73% ~03s
|++++++++++++++++++++++++++++++++++++++ | 75% ~03s
|+++++++++++++++++++++++++++++++++++++++ | 76% ~03s
|+++++++++++++++++++++++++++++++++++++++ | 78% ~03s
|++++++++++++++++++++++++++++++++++++++++ | 80% ~02s
|+++++++++++++++++++++++++++++++++++++++++ | 81% ~02s
|++++++++++++++++++++++++++++++++++++++++++ | 83% ~02s
|+++++++++++++++++++++++++++++++++++++++++++ | 85% ~02s
|++++++++++++++++++++++++++++++++++++++++++++ | 86% ~02s
|+++++++++++++++++++++++++++++++++++++++++++++ | 88% ~01s
|+++++++++++++++++++++++++++++++++++++++++++++ | 90% ~01s
|++++++++++++++++++++++++++++++++++++++++++++++ | 92% ~01s
|+++++++++++++++++++++++++++++++++++++++++++++++ | 93% ~01s
|++++++++++++++++++++++++++++++++++++++++++++++++ | 95% ~01s
|+++++++++++++++++++++++++++++++++++++++++++++++++ | 97% ~00s
|++++++++++++++++++++++++++++++++++++++++++++++++++| 98% ~00s
|++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=12s
# Key factors to highlight
tfs_to_label <- c("MAX", "MYC", "E2F1", "E2F4", "FOXM1", "FOXO1", "RELA", "IRF1", "STAT3", "RUNX3")
p_volcano_max <- EnhancedVolcano(
all_tfs_diff,
lab = rownames(all_tfs_diff),
selectLab = tfs_to_label,
x = 'avg_log2FC',
y = 'p_val_adj',
title = 'Differential TF Activity: Malignant vs. Non-Malignant CD4+ T Cells',
subtitle = 'DecoupleR Inferred Activity Highlighting the MAX/MYC Axis',
pCutoff = 1e-5,
FCcutoff = 0.5,
pointSize = 3.0,
labSize = 4.5,
drawConnectors = TRUE,
col = c("grey60", "forestgreen", "royalblue", "firebrick2")
)
print(p_volcano_max)

ggsave("Output_Figures/Figure_MAX_Volcano_TF_Activity.pdf", plot = p_volcano_max, width = 10, height = 8)
ggsave("Output_Figures/Figure_MAX_Volcano_TF_Activity.png", plot = p_volcano_max, width = 10, height = 8, dpi = 300)
Completion Summary
print("MAX network analysis complete. All tables exported to Output_Tables/ and figures to Output_Figures/.")
[1] "MAX network analysis complete. All tables exported to Output_Tables/ and figures to Output_Figures/."
LS0tCnRpdGxlOiAiTUFYIE5ldHdvcmsgRGVyZWd1bGF0aW9uIEFuYWx5c2lzIGluIFPDqXphcnkgU3luZHJvbWUiCmF1dGhvcjogIk5hc2lyIE1haG1vb2QgQWJiYXNpIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiB0cnVlCiAgICB0aGVtZTogam91cm5hbAotLS0KCiMgU2V0dXAgYW5kIExpYnJhcmllcwpgYGB7ciBzZXR1cCwgaW5jbHVkZT1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIERhdGEgUHJvY2Vzc2luZyAmIFNpbmdsZS1DZWxsIEFuYWx5c2lzCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGliYmxlKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShNYXRyaXgpCgojIFZpc3VhbGl6YXRpb24KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShDb21wbGV4SGVhdG1hcCkKbGlicmFyeShjaXJjbGl6ZSkKbGlicmFyeShncmlkKQpsaWJyYXJ5KEVuaGFuY2VkVm9sY2FubykKCiMgQ3JlYXRlIG91dHB1dCBkaXJlY3RvcmllcyBpZiB0aGV5IGRvIG5vdCBleGlzdApkaXIuY3JlYXRlKCJPdXRwdXRfRmlndXJlcyIsIHNob3dXYXJuaW5ncyA9IEZBTFNFKQpkaXIuY3JlYXRlKCJPdXRwdXRfVGFibGVzIiwgc2hvd1dhcm5pbmdzID0gRkFMU0UpCmBgYAoKIyBMb2FkIFNldXJhdCBPYmplY3QgYW5kIERlZmluZSBDb25kaXRpb25zCmBgYHtyIGxvYWQtZGF0YSwgbWVzc2FnZT1GQUxTRX0KIyBMb2FkIFNldXJhdCBPYmplY3QgZGlyZWN0bHkgZnJvbSBjbHVzdGVyIHJlbGF0aXZlIHBhdGgKc2V1cmF0X29iaiA8LSByZWFkUkRTKCIuLi8uLi8wLVNldXJhdF9vYmplY3RzL1NldXJhdF9PYmplY3RfV2l0aF9URl9BY3Rpdml0eS5yZHMiKQpJZGVudHMoc2V1cmF0X29iaikgPC0gInNldXJhdF9jbHVzdGVycyIKCiMgRGVmaW5lIE1hbGlnbmFudCB2cyBOb24tTWFsaWduYW50IChDbHVzdGVycyAzICYgMTAgPSBOb3JtYWwgQ0Q0KyBUIHJlZmVyZW5jZSkKbm9uX21hbGlnbmFudF9jbHVzdGVycyA8LSBjKDMsIDEwKQpzZXVyYXRfb2JqJENvbmRpdGlvbiA8LSBpZmVsc2Uoc2V1cmF0X29iaiRzZXVyYXRfY2x1c3RlcnMgJWluJSBub25fbWFsaWduYW50X2NsdXN0ZXJzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb24tTWFsaWduYW50IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWFsaWduYW50IikKc2V1cmF0X29iaiRDb25kaXRpb24gPC0gZmFjdG9yKHNldXJhdF9vYmokQ29uZGl0aW9uLCBsZXZlbHMgPSBjKCJOb24tTWFsaWduYW50IiwgIk1hbGlnbmFudCIpKQoKcHJpbnQoIlNldXJhdCBPYmplY3QgTG9hZGVkIHN1Y2Nlc3NmdWxseToiKQp0YWJsZShzZXVyYXRfb2JqJENvbmRpdGlvbikKYGBgCgojIERpZmZlcmVudGlhbCBTdGF0aXN0aWNzIGZvciBNQVggJiBOZXR3b3JrIFBhcnRuZXJzCmBgYHtyIG1heC1kaWZmZXJlbnRpYWwtc3RhdHMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgLS0tIDEuIEdlbmUgRXhwcmVzc2lvbiAoU0NUIEFzc2F5KSAtLS0KRGVmYXVsdEFzc2F5KHNldXJhdF9vYmopIDwtICJTQ1QiCklkZW50cyhzZXVyYXRfb2JqKSA8LSAiQ29uZGl0aW9uIgoKY2FuZGlkYXRlX2dlbmVzIDwtIGludGVyc2VjdCgKICBjKCJNQVgiLCAiTVlDIiwgIk1MWCIsICJNTFhJUCIsICJNTFhJUEwiLCAiTU5UIiwgIk1YRDEiLCAiTVhJMSIsICJFMkYxIiwgIkNMSUMxIiksCiAgcm93bmFtZXMoc2V1cmF0X29ialtbIlNDVCJdXSkKKQoKZGVnX3NjdCA8LSBGaW5kTWFya2VycygKICBzZXVyYXRfb2JqLAogIGZlYXR1cmVzID0gY2FuZGlkYXRlX2dlbmVzLAogIGlkZW50LjEgPSAiTWFsaWduYW50IiwKICBpZGVudC4yID0gIk5vbi1NYWxpZ25hbnQiLAogIGxvZ2ZjLnRocmVzaG9sZCA9IDAsCiAgbWluLnBjdCA9IDAKKQpkZWdfc2N0JEdlbmUgPC0gcm93bmFtZXMoZGVnX3NjdCkKZGVnX3NjdCRBc3NheSA8LSAiU0NUIChtUk5BIEV4cHJlc3Npb24pIgoKIyAtLS0gMi4gVEYgQWN0aXZpdHkgKGRvcm90aGVhIEFzc2F5KSAtLS0KRGVmYXVsdEFzc2F5KHNldXJhdF9vYmopIDwtICJkb3JvdGhlYSIKCmNhbmRpZGF0ZV90ZnMgPC0gaW50ZXJzZWN0KAogIGMoIk1BWCIsICJNWUMiLCAiRTJGMSIsICJFMkY0IiwgIkZPWE0xIiwgIkZPWE8xIiksCiAgcm93bmFtZXMoc2V1cmF0X29ialtbImRvcm90aGVhIl1dKQopCgpkZWdfdGYgPC0gRmluZE1hcmtlcnMoCiAgc2V1cmF0X29iaiwKICBmZWF0dXJlcyA9IGNhbmRpZGF0ZV90ZnMsCiAgaWRlbnQuMSA9ICJNYWxpZ25hbnQiLAogIGlkZW50LjIgPSAiTm9uLU1hbGlnbmFudCIsCiAgbG9nZmMudGhyZXNob2xkID0gMCwKICBtaW4ucGN0ID0gMAopCmRlZ190ZiRHZW5lIDwtIHJvd25hbWVzKGRlZ190ZikKZGVnX3RmJEFzc2F5IDwtICJkb3JvdGhlYSAoVEYgQWN0aXZpdHkpIgoKIyBDb21iaW5lIGFuZCBzYXZlIHRhYmxlIGZvciByZXZpZXdlciByZXNwb25zZQpkZWdfc3VtbWFyeSA8LSBiaW5kX3Jvd3MoZGVnX3NjdCwgZGVnX3RmKSAlPiUKICBzZWxlY3QoQXNzYXksIEdlbmUsIGF2Z19sb2cyRkMsIHBjdC4xLCBwY3QuMiwgcF92YWwsIHBfdmFsX2FkaikKCndyaXRlLmNzdihkZWdfc3VtbWFyeSwgIk91dHB1dF9UYWJsZXMvTUFYX05ldHdvcmtfRGlmZmVyZW50aWFsX1N1bW1hcnkuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCnByaW50KCI9PT0gRGlmZmVyZW50aWFsIFN0YXRpc3RpY3MgZm9yIE1BWCAmIEtleSBOZXR3b3JrIE1lbWJlcnMgPT09IikKcHJpbnQoZGVnX3N1bW1hcnkpCmBgYAoKIyBVTUFQIEZlYXR1cmUgUGxvdHM6IE1BWCBURiBBY3Rpdml0eSB2cy4gTUFYIEdlbmUgRXhwcmVzc2lvbgpgYGB7ciBtYXgtdW1hcC1mZWF0dXJlLXBsb3RzLCBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD0xMX0KIyAtLS0gUGFuZWwgMTogTUFYIFRGIEFjdGl2aXR5IChSZWQgPSBkb3JvdGhlYSBBc3NheSkgLS0tCkRlZmF1bHRBc3NheShzZXVyYXRfb2JqKSA8LSAiZG9yb3RoZWEiCnBfbWF4X2FjdCA8LSBGZWF0dXJlUGxvdChzZXVyYXRfb2JqLCBmZWF0dXJlcyA9ICJNQVgiLCBvcmRlciA9IFRSVUUsIHJlZHVjdGlvbiA9ICJ1bWFwIikgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSBjKCJncmV5OTAiLCAiZmlyZWJyaWNrIikpICsKICBnZ3RpdGxlKCJNQVggUmVndWxvbiBBY3Rpdml0eSAoZG9yb3RoZWEpIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDEyKSkKCiMgLS0tIFBhbmVsIDI6IE1BWCBHZW5lIEV4cHJlc3Npb24gKEJsdWUgPSBTQ1QgQXNzYXkpIC0tLQpEZWZhdWx0QXNzYXkoc2V1cmF0X29iaikgPC0gIlNDVCIKcF9tYXhfZXhwIDwtIEZlYXR1cmVQbG90KHNldXJhdF9vYmosIGZlYXR1cmVzID0gIk1BWCIsIG9yZGVyID0gVFJVRSwgcmVkdWN0aW9uID0gInVtYXAiKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IGMoImdyZXk5MCIsICJkYXJrYmx1ZSIpKSArCiAgZ2d0aXRsZSgiTUFYIEdlbmUgRXhwcmVzc2lvbiAoU0NUKSIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxMikpCgojIENvbWJpbmUgc2lkZS1ieS1zaWRlCmZpZ19tYXhfdW1hcCA8LSBwX21heF9hY3QgfCBwX21heF9leHAKZmlnX21heF91bWFwIDwtIGZpZ19tYXhfdW1hcCArIHBsb3RfYW5ub3RhdGlvbigKICB0aXRsZSA9ICJNQVggTmV0d29yayBEZWNvdXBsaW5nIGluIFPDqXphcnkgU3luZHJvbWUgKEFjdGl2aXR5IHZzLiBtUk5BIEV4cHJlc3Npb24pIiwKICB0aGVtZSA9IHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE0KSkKKQoKIyBEaXNwbGF5ICYgU2F2ZQpwcmludChmaWdfbWF4X3VtYXApCmdnc2F2ZSgiT3V0cHV0X0ZpZ3VyZXMvRmlndXJlX01BWF9VTUFQX0FjdGl2aXR5X3ZzX0V4cHJlc3Npb24ucGRmIiwgcGxvdCA9IGZpZ19tYXhfdW1hcCwgd2lkdGggPSAxMSwgaGVpZ2h0ID0gNSkKZ2dzYXZlKCJPdXRwdXRfRmlndXJlcy9GaWd1cmVfTUFYX1VNQVBfQWN0aXZpdHlfdnNfRXhwcmVzc2lvbi5wbmciLCBwbG90ID0gZmlnX21heF91bWFwLCB3aWR0aCA9IDExLCBoZWlnaHQgPSA1LCBkcGkgPSAzMDApCmBgYAoKIyBWaW9saW4gUGxvdHM6IE1hbGlnbmFudCB2cy4gTm9uLU1hbGlnbmFudCBRdWFudGlmaWNhdGlvbgpgYGB7ciBtYXgtdmlvbGluLXBsb3RzLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD0xMn0KIyBQYW5lbCBBOiBNQVggRXhwcmVzc2lvbiAoU0NUKQp2bG5fZXhwIDwtIFZsblBsb3Qoc2V1cmF0X29iaiwgZmVhdHVyZXMgPSAiTUFYIiwgYXNzYXkgPSAiU0NUIiwgZ3JvdXAuYnkgPSAiQ29uZGl0aW9uIiwgcHQuc2l6ZSA9IDAuMDUpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJOb24tTWFsaWduYW50IiA9ICIjNERBRjRBIiwgIk1hbGlnbmFudCIgPSAiI0U0MUExQyIpKSArCiAgeWxhYigiTm9ybWFsaXplZCBFeHByZXNzaW9uIikgKwogIGdndGl0bGUoIk1BWCBtUk5BIEV4cHJlc3Npb24gKFNDVCkiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxMSkpCgojIFBhbmVsIEI6IE1BWCBBY3Rpdml0eSAoZG9yb3RoZWEpCnZsbl9hY3QgPC0gVmxuUGxvdChzZXVyYXRfb2JqLCBmZWF0dXJlcyA9ICJNQVgiLCBhc3NheSA9ICJkb3JvdGhlYSIsIGdyb3VwLmJ5ID0gIkNvbmRpdGlvbiIsIHB0LnNpemUgPSAwLjA1KSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiTm9uLU1hbGlnbmFudCIgPSAiIzREQUY0QSIsICJNYWxpZ25hbnQiID0gIiNFNDFBMUMiKSkgKwogIHlsYWIoIlRGIEFjdGl2aXR5IFNjb3JlIikgKwogIGdndGl0bGUoIk1BWCBURiBBY3Rpdml0eSAoZG9yb3RoZWEpIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTEpKQoKIyBQYW5lbCBDOiBNWUMgQWN0aXZpdHkgKGRvcm90aGVhKSBmb3IgRGlyZWN0IENvbnRyYXN0CnZsbl9teWMgPC0gVmxuUGxvdChzZXVyYXRfb2JqLCBmZWF0dXJlcyA9ICJNWUMiLCBhc3NheSA9ICJkb3JvdGhlYSIsIGdyb3VwLmJ5ID0gIkNvbmRpdGlvbiIsIHB0LnNpemUgPSAwLjA1KSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiTm9uLU1hbGlnbmFudCIgPSAiIzREQUY0QSIsICJNYWxpZ25hbnQiID0gIiNFNDFBMUMiKSkgKwogIHlsYWIoIlRGIEFjdGl2aXR5IFNjb3JlIikgKwogIGdndGl0bGUoIk1ZQyBURiBBY3Rpdml0eSAoZG9yb3RoZWEpIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTEpKQoKZmlnX3Zsbl9tYXggPC0gdmxuX2V4cCB8IHZsbl9hY3QgfCB2bG5fbXljCnByaW50KGZpZ192bG5fbWF4KQoKZ2dzYXZlKCJPdXRwdXRfRmlndXJlcy9GaWd1cmVfTUFYX01ZQ19WaW9saW5fQ29tcGFyaXNvbi5wZGYiLCBwbG90ID0gZmlnX3Zsbl9tYXgsIHdpZHRoID0gMTIsIGhlaWdodCA9IDQpCmdnc2F2ZSgiT3V0cHV0X0ZpZ3VyZXMvRmlndXJlX01BWF9NWUNfVmlvbGluX0NvbXBhcmlzb24ucG5nIiwgcGxvdCA9IGZpZ192bG5fbWF4LCB3aWR0aCA9IDEyLCBoZWlnaHQgPSA0LCBkcGkgPSAzMDApCmBgYAoKIyBDbHVzdGVyLUxldmVsIENvbXBsZXhIZWF0bWFwIChNQVggdnMuIE1ZQyBhbmQgQ29yZSBSZWd1bGF0b3JzKQpgYGB7ciBtYXgtY29tcGxleC1oZWF0bWFwLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD0xMH0KIyBTZWxlY3QgdGFyZ2V0ZWQgcGFuZWwgY29udHJhc3RpbmcgTVlDL0UyRiBvbmNvZ2VuaWMgcHJvZ3JhbSB3aXRoIE1BWCBhbmQgdHVtb3Igc3VwcHJlc3NvcnMKdGZfcGFuZWwgPC0gYygKICAjIE9uY29nZW5pYyAvIFByb2xpZmVyYXRpdmUKICAiTVlDIiwgIkUyRjEiLCAiRTJGNCIsICJGT1hNMSIsICJTUkVCRjEiLCAiSElGMUEiLAogICMgTUFYCiAgIk1BWCIsCiAgIyBOb3JtYWwgSG9tZW9zdGFzaXMgJiBUdW1vciBTdXBwcmVzc29ycwogICJGT1hPMSIsICJGT1hPNCIsICJUQ0Y3IiwgIlRCWDIxIiwgIlJVTlgzIgopCgojIEV4dHJhY3QgVEYgQWN0aXZpdHkgbWF0cml4IChTZXVyYXQgdjQvdjUgY29tcGF0aWJsZSkKbWF0X3NjYWxlZCA8LSB0cnlDYXRjaCgKICBTZXVyYXRPYmplY3Q6OkdldEFzc2F5RGF0YShzZXVyYXRfb2JqLCBhc3NheSA9ICJkb3JvdGhlYSIsIGxheWVyID0gInNjYWxlLmRhdGEiKSwKICBlcnJvciA9IGZ1bmN0aW9uKGUpIE5VTEwKKQptYXRfZGF0YSA8LSBTZXVyYXRPYmplY3Q6OkdldEFzc2F5RGF0YShzZXVyYXRfb2JqLCBhc3NheSA9ICJkb3JvdGhlYSIsIGxheWVyID0gImRhdGEiKQptYXRfdXNlIDwtIGlmICghaXMubnVsbChtYXRfc2NhbGVkKSAmJiBucm93KG1hdF9zY2FsZWQpID4gMCkgbWF0X3NjYWxlZCBlbHNlIG1hdF9kYXRhCgphdmFpbCA8LSBpbnRlcnNlY3QodGZfcGFuZWwsIHJvd25hbWVzKG1hdF91c2UpKQptYXRfdXNlIDwtIG1hdF91c2VbYXZhaWwsICwgZHJvcCA9IEZBTFNFXQoKIyBDb21wdXRlIG1lYW4gcGVyIGNsdXN0ZXIgYW5kIGNhbGN1bGF0ZSB6LXNjb3JlcwpjbHVzdGVycyA8LSBhcy5mYWN0b3Ioc2V1cmF0X29iaiRzZXVyYXRfY2x1c3RlcnMpCmF2Z19tYXQgPC0gc2FwcGx5KGxldmVscyhjbHVzdGVycyksIGZ1bmN0aW9uKGNsKSB7CiAgTWF0cml4Ojpyb3dNZWFucyhtYXRfdXNlWywgY2x1c3RlcnMgPT0gY2wsIGRyb3AgPSBGQUxTRV0pCn0pCmNvbG5hbWVzKGF2Z19tYXQpIDwtIGxldmVscyhjbHVzdGVycykKCmF2Z19tYXRfeiA8LSB0KHNjYWxlKHQoYXZnX21hdCkpKQphdmdfbWF0X3pbaXMubmEoYXZnX21hdF96KV0gPC0gMAoKIyBTZXQgY29sdW1uIGFubm90YXRpb25zCmNsdXN0ZXJfc3RhdHVzIDwtIGlmZWxzZShjb2xuYW1lcyhhdmdfbWF0X3opICVpbiUgYygiMyIsICIxMCIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICJOb3JtYWwgQ0Q0IFQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICJNYWxpZ25hbnQgQ0Q0IFQgY2VsbHMiKQoKaGFfY29sIDwtIEhlYXRtYXBBbm5vdGF0aW9uKAogIENlbGxfU3RhdGUgPSBjbHVzdGVyX3N0YXR1cywKICBjb2wgPSBsaXN0KENlbGxfU3RhdGUgPSBjKCJOb3JtYWwgQ0Q0IFQiID0gIiM0REFGNEEiLCAiTWFsaWduYW50IENENCBUIGNlbGxzIiA9ICIjRTQxQTFDIikpLAogIGFubm90YXRpb25fbmFtZV9zaWRlID0gImxlZnQiCikKCiMgQ29sb3Igc2NhbGU6IC0zIHRvICszCmNvbF9mdW4gPC0gY2lyY2xpemU6OmNvbG9yUmFtcDIoYygtMywgMCwgMyksIGMoIiMzMTM2OTUiLCAid2hpdGUiLCAiI0E1MDAyNiIpKQoKaHRfbWF4IDwtIEhlYXRtYXAoCiAgYXZnX21hdF96LAogIG5hbWUgPSAiVEYgYWN0aXZpdHkgKHopIiwKICBjb2wgPSBjb2xfZnVuLAogIHRvcF9hbm5vdGF0aW9uID0gaGFfY29sLAogIGNvbHVtbl9zcGxpdCA9IGNsdXN0ZXJfc3RhdHVzLAogIGNsdXN0ZXJfcm93cyA9IFRSVUUsCiAgY2x1c3Rlcl9jb2x1bW5zID0gVFJVRSwKICBzaG93X3Jvd19kZW5kID0gVFJVRSwKICBzaG93X2NvbHVtbl9kZW5kID0gVFJVRSwKICByb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gMTEsIGZvbnRmYWNlID0gImJvbGQiKSwKICBjb2x1bW5fbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gMTApLAogIGNvbHVtbl90aXRsZSA9ICJDbHVzdGVyLUxldmVsIFRGIEFjdGl2aXR5OiBNWUMvRTJGIEFjdGl2YXRpb24gdnMuIE1BWCBSZXByZXNzaW9uIiwKICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QoZGlyZWN0aW9uID0gInZlcnRpY2FsIikKKQoKIyBTYXZlIGFuZCBEcmF3CnBkZigiT3V0cHV0X0ZpZ3VyZXMvRmlndXJlX01BWF9NWUNfQ2x1c3Rlcl9IZWF0bWFwLnBkZiIsIHdpZHRoID0gMTAsIGhlaWdodCA9IDcpCmRyYXcoaHRfbWF4LCBtZXJnZV9sZWdlbmQgPSBUUlVFKQpkZXYub2ZmKCkKCnBuZygiT3V0cHV0X0ZpZ3VyZXMvRmlndXJlX01BWF9NWUNfQ2x1c3Rlcl9IZWF0bWFwLnBuZyIsIHdpZHRoID0gMTAgKiAzMDAsIGhlaWdodCA9IDcgKiAzMDAsIHJlcyA9IDMwMCkKZHJhdyhodF9tYXgsIG1lcmdlX2xlZ2VuZCA9IFRSVUUpCmRldi5vZmYoKQoKZHJhdyhodF9tYXgsIG1lcmdlX2xlZ2VuZCA9IFRSVUUpCmBgYAoKIyBWb2xjYW5vIFBsb3QgSGlnaGxpZ2h0aW5nIE1BWCAmIE1ZQyBJbmZlcnJlZCBBY3Rpdml0eQpgYGB7ciBtYXgtdm9sY2Fuby1wbG90LCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMCwgd2FybmluZz1GQUxTRX0KIyBEaWZmZXJlbnRpYWwgVEYgQWN0aXZpdHkgYWNyb3NzIGFsbCBURnMKRGVmYXVsdEFzc2F5KHNldXJhdF9vYmopIDwtICJkb3JvdGhlYSIKSWRlbnRzKHNldXJhdF9vYmopIDwtICJDb25kaXRpb24iCgphbGxfdGZzX2RpZmYgPC0gRmluZE1hcmtlcnMoCiAgc2V1cmF0X29iaiwgCiAgaWRlbnQuMSA9ICJNYWxpZ25hbnQiLCAKICBpZGVudC4yID0gIk5vbi1NYWxpZ25hbnQiLCAKICBsb2dmYy50aHJlc2hvbGQgPSAwLCAKICBtaW4ucGN0ID0gMAopCgojIEtleSBmYWN0b3JzIHRvIGhpZ2hsaWdodAp0ZnNfdG9fbGFiZWwgPC0gYygiTUFYIiwgIk1ZQyIsICJFMkYxIiwgIkUyRjQiLCAiRk9YTTEiLCAiRk9YTzEiLCAiUkVMQSIsICJJUkYxIiwgIlNUQVQzIiwgIlJVTlgzIikKCnBfdm9sY2Fub19tYXggPC0gRW5oYW5jZWRWb2xjYW5vKAogIGFsbF90ZnNfZGlmZiwKICBsYWIgPSByb3duYW1lcyhhbGxfdGZzX2RpZmYpLAogIHNlbGVjdExhYiA9IHRmc190b19sYWJlbCwKICB4ID0gJ2F2Z19sb2cyRkMnLAogIHkgPSAncF92YWxfYWRqJywKICB0aXRsZSA9ICdEaWZmZXJlbnRpYWwgVEYgQWN0aXZpdHk6IE1hbGlnbmFudCB2cy4gTm9uLU1hbGlnbmFudCBDRDQrIFQgQ2VsbHMnLAogIHN1YnRpdGxlID0gJ0RlY291cGxlUiBJbmZlcnJlZCBBY3Rpdml0eSBIaWdobGlnaHRpbmcgdGhlIE1BWC9NWUMgQXhpcycsCiAgcEN1dG9mZiA9IDFlLTUsCiAgRkNjdXRvZmYgPSAwLjUsCiAgcG9pbnRTaXplID0gMy4wLAogIGxhYlNpemUgPSA0LjUsCiAgZHJhd0Nvbm5lY3RvcnMgPSBUUlVFLAogIGNvbCA9IGMoImdyZXk2MCIsICJmb3Jlc3RncmVlbiIsICJyb3lhbGJsdWUiLCAiZmlyZWJyaWNrMiIpCikKCnByaW50KHBfdm9sY2Fub19tYXgpCmdnc2F2ZSgiT3V0cHV0X0ZpZ3VyZXMvRmlndXJlX01BWF9Wb2xjYW5vX1RGX0FjdGl2aXR5LnBkZiIsIHBsb3QgPSBwX3ZvbGNhbm9fbWF4LCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA4KQpnZ3NhdmUoIk91dHB1dF9GaWd1cmVzL0ZpZ3VyZV9NQVhfVm9sY2Fub19URl9BY3Rpdml0eS5wbmciLCBwbG90ID0gcF92b2xjYW5vX21heCwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gOCwgZHBpID0gMzAwKQpgYGAKCiMgQ29tcGxldGlvbiBTdW1tYXJ5CmBgYHtyIGNvbXBsZXRpb259CnByaW50KCJNQVggbmV0d29yayBhbmFseXNpcyBjb21wbGV0ZS4gQWxsIHRhYmxlcyBleHBvcnRlZCB0byBPdXRwdXRfVGFibGVzLyBhbmQgZmlndXJlcyB0byBPdXRwdXRfRmlndXJlcy8uIikKYGBg