1. Load Libraries

2. load seurat object

#Load Seurat Object L7
load("../0-robj/5-Harmony_Integrated_All_samples_Merged_CD4Tcells_final_Resolution_Selected_0.8_ADT_Normalized_cleaned_mt.robj")


All_samples_Merged

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. Differential Expression Analysis

4.1 Using MAST with SCT and Latent Variables (Batch Correction)

markers_mast_SCT <- FindMarkers(
  All_samples_Merged,
  ident.1 = c("5", "9", "1", "2", "6", "8", "4", "0", "7", "11", "12", "13"), # Cell lines-Malignant
  ident.2 = c("3", "10"), # Normal CD4 T cells
  assay = "SCT",
  test.use = "MAST",
  latent.vars = c("cell_line", "Patient_origin"), # Adjust for batch effects
  min.pct = 0,
  logfc.threshold = 0
)
write.csv(markers_mast_SCT, file = "../0-robj/1-MAST_with_SCT_batch_patient_cellline_as_Covariate.csv", row.names = TRUE)

4.2 Using MAST with RNA and Latent Variables (Batch Correction)

markers_mast_RNA <- FindMarkers(
  All_samples_Merged,
 ident.1 = cc("5", "9", "1", "2", "6", "8", "4", "0", "7", "11", "12", "13"), # Cell lines-Malignant
  ident.2 = c("3", "10"), # Normal CD4 T cells
  assay = "RNA",
  test.use = "MAST",
  latent.vars = c("cell_line", "Patient_origin"), # Adjust for batch effects
  min.pct = 0,
  logfc.threshold = 0
)
Erreur dans cc("5", "9", "1", "2", "6", "8", "4", "0", "7", "11", "12", "13") : 
  impossible de trouver la fonction "cc"

5. Compute Mean Expression for Groups

library(Seurat)
library(dplyr)

# Define cell groups
group1_cells <- WhichCells(All_samples_Merged, idents = c("5", "9", "1", "2", "6", "8", "4", "0", "7", "11", "12", "13"))  # Malignant CD4+ T cells
group2_cells <- WhichCells(All_samples_Merged, idents = c("3", "10"))  # Normal CD4+ T cells

# Extract normalized expression values for both assays
expression_data_RNA <- GetAssayData(All_samples_Merged, assay = "RNA", layer = "data")  # Log-normalized counts
expression_data_SCT <- GetAssayData(All_samples_Merged, assay = "SCT", layer = "data")  # SCT-normalized counts (not Pearson residuals)

# Function to calculate mean expression for each group
calculate_mean_expression <- function(markers, group1_cells, group2_cells, expression_data) {
  group1_mean <- rowMeans(expression_data[, group1_cells, drop = FALSE], na.rm = TRUE)
  group2_mean <- rowMeans(expression_data[, group2_cells, drop = FALSE], na.rm = TRUE)
  
  markers <- markers %>%
    rownames_to_column("gene") %>%
    mutate(mean_expr_group1 = group1_mean[gene],
           mean_expr_group2 = group2_mean[gene])
  
  return(markers)
}

# Compute mean expression for RNA and SCT assays
markers_mast_RNA <- calculate_mean_expression(markers_mast_RNA, group1_cells, group2_cells, expression_data_RNA)
markers_mast_SCT <- calculate_mean_expression(markers_mast_SCT, group1_cells, group2_cells, expression_data_SCT)

# Save updated results with mean expression
write.csv(markers_mast_RNA, file = "../0-robj/2-MAST_with_RNA_batch_patient_cellline_as_Covariate_with_meanExpression.csv", row.names = TRUE)
write.csv(markers_mast_SCT, file = "../0-robj/1-MAST_with_SCT_batch_patient_cellline_as_Covariate_with_meanExpression.csv", row.names = TRUE)

6. Summarize Results

6.1 Summary Function

summarize_markers <- function(markers) {
  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("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")
}

6.2 Summarize Markers1 (MAST with SCT Assay)

cat("Markers1 Summary (MAST with SCT Assay):\n")
Markers1 Summary (MAST with SCT Assay):
summarize_markers(markers_mast_SCT)
Number of genes with p_val_adj = 0: 74 
Number of genes with p_val_adj = 1: 19337 
Number of significant genes (p_val_adj < 0.05): 5615 
Number of upregulated genes (avg_log2FC > 1): 15048 
Number of downregulated genes (avg_log2FC < -1): 2281 

6.3 Summary for Markers2 (MAST with RNA Assay)

cat("Markers2 Summary (MAST with RNA Assay):\n")
Markers2 Summary (MAST with RNA Assay):
summarize_markers(markers_mast_RNA)
Number of genes with p_val_adj = 0: 83 
Number of genes with p_val_adj = 1: 26400 
Number of significant genes (p_val_adj < 0.05): 9221 
Number of upregulated genes (avg_log2FC > 1): 7334 
Number of downregulated genes (avg_log2FC < -1): 15426 

Compare Results Between SCT and RNA Assays

### Compare Results Between RNA and SCT Assays

# Load gene sets
genes_mast_sct <- markers_mast_SCT$gene
genes_mast_rna <- markers_mast_RNA$gene
common_genes_mast <- intersect(genes_mast_sct, genes_mast_rna)

cat("MAST: Common Genes Between SCT and RNA:", length(common_genes_mast), "\n")
MAST: Common Genes Between SCT and RNA: 26176 

7. Visualization

7.1 Volcano Plot for MAST-SCT with Batch Correction


EnhancedVolcano(markers_mast_SCT,
                lab = markers_mast_SCT$gene,
                x = "avg_log2FC",
                y = "p_val_adj",
                title = "Malignant_vs_Normal_MAST_SCT",
                pCutoff = 0.05,
                FCcutoff = 1.0)
Avis : One or more p-values is 0. Converting to 10^-1 * current lowest non-zero p-value...

7.2 Volcano Plot MAST-RNA with Batch Correction


EnhancedVolcano(markers_mast_RNA,
                lab = markers_mast_RNA$gene,
                x = "avg_log2FC",
                y = "p_val_adj",
                title = "Malignant_vs_Normal_MAST_RNA",
                pCutoff = 0.05,
                FCcutoff = 1.0)
Avis : One or more p-values is 0. Converting to 10^-1 * current lowest non-zero p-value...

7.3 Volcano Plot MAST-RNA with Batch Correction


### 1. Load Data and Prepare for Comparison

library(ggplot2)

df_sct <- read.csv("../0-robj/1-MAST_with_SCT_batch_patient_cellline_as_Covariate.csv", row.names = 1)
df_rna <- read.csv("../0-robj/2-MAST_with_RNA_batch_patient_cellline_as_Covariate.csv", row.names = 1)

df_sct$assay <- "SCT"
df_rna$assay <- "RNA"

df_combined <- rbind(df_sct, df_rna)

### 2. Volcano Plot for SCT vs RNA Comparison

ggplot(df_combined, aes(x = avg_log2FC, y = -log10(p_val_adj), color = assay)) +
  geom_point(alpha = 0.7) +
  theme_minimal() +
  labs(title = "Volcano Plot: RNA vs SCT", x = "Log2 Fold Change", y = "-Log10 Adjusted P-value") +
  scale_color_manual(values = c("SCT" = "blue", "RNA" = "red"))

7.4 Correlation of Log2 Fold Change Between RNA and SCT


# Correlation of Log2 Fold Change Between RNA and SCT
# Goal: See if genes have consistent fold changes between RNA and SCT normalization.


library(dplyr)  # Load dplyr to use rownames_to_column

# Convert row names to a "gene" column
df_sct <- df_sct %>% rownames_to_column(var = "gene")
df_rna <- df_rna %>% rownames_to_column(var = "gene")

# Merge datasets by gene
df_merged <- merge(df_sct, df_rna, by = "gene", suffixes = c("_SCT", "_RNA"))

# Scatter plot of log2FC values
ggplot(df_merged, aes(x = avg_log2FC_SCT, y = avg_log2FC_RNA)) +
  geom_point(alpha = 0.7, color = "blue") +
  geom_smooth(method = "lm", color = "red", linetype = "dashed") +
  theme_minimal() +
  labs(title = "Log2 Fold Change Comparison: SCT vs RNA",
       x = "SCT Log2 Fold Change",
       y = "RNA Log2 Fold Change") +
  geom_abline(slope = 1, intercept = 0, linetype = "dotted", color = "black")

7.5 Find overlap between the top 100 most significant genes:


cor(df_merged$avg_log2FC_SCT, df_merged$avg_log2FC_RNA, use = "complete.obs")
[1] 0.9815925
# Higher correlation (~0.8-1.0) suggests consistency between methods.
# Lower correlation (<0.6) may indicate different normalization effects.


library(ggplot2)
library(dplyr)

# Define a broader list of known Sezary genes
sezary_genes <- c("KIR3DL2", "TOX", "TWIST1", "CD52", "CCR4", "IL2RA", "CD7", "DPP4", "CCR7", "GATA3", "FOXP3", "CD8A", "CD4", "CYP27B1", "TET2")

# Filter the merged data to include only the known Sezary genes
df_filtered <- df_merged %>%
  filter(gene %in% sezary_genes)

# Volcano plot showing only the known Sezary genes with gene names
ggplot(df_filtered, aes(x = avg_log2FC_SCT, y = -log10(p_val_adj_SCT), color = gene)) +
  geom_point(alpha = 0.7) +
  geom_text(aes(label = gene), vjust = 1.5, hjust = 0.5, size = 3, color = "black") +  # Adding gene names
  theme_minimal() +
  labs(title = "Volcano Plot: Known Sezary Genes (SCT Assay)", 
       x = "Log2 Fold Change (SCT)", 
       y = "-Log10 Adjusted P-value") +
  scale_color_manual(values = c("KIR3DL2" = "#1f77b4",  # blue
                                "TOX" = "#ff7f0e",  # orange
                                "TWIST1" = "#2ca02c",  # green
                                "CD52" = "#9467bd",  # purple
                                "CCR4" = "#8c564b",  # brown
                                "IL2RA" = "#e377c2",  # pink
                                "CD7" = "#7f7f7f",  # gray
                                "DPP4" = "#bcbd22",  # yellow-green
                                "CCR7" = "#17becf",  # cyan
                                "GATA3" = "#d62728",  # red
                                "FOXP3" = "#8a2be2",  # blue-violet
                                "CD8A" = "#ff6347",  # tomato
                                "CD4" = "#3cb371",  # medium sea green
                                "CYP27B1" = "#ff1493",  # deep pink
                                "TET2" = "#00bfff")) +  # deep sky blue
  theme(legend.position = "top")

LS0tCnRpdGxlOiAiTUFTVCBvbiBTQ1QgYW5kIFJOQSBhc3NheSBhbmQgaXRzIGNvbXBhcmlzb24gdG8gc2VlIHdoaWNoIGlzIGJldHRlciIKYXV0aG9yOiAiTmFzaXIgTWFobW9vZCBBYmJhc2kiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIHRvY19jb2xsYXBzZWQ6IHllcwogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogeWVzCi0tLQoKIyAxLiBMb2FkIExpYnJhcmllcwpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoaGFybW9ueSkKbGlicmFyeShkcGx5cikKbGlicmFyeShFbmhhbmNlZFZvbGNhbm8pCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwaGVhdG1hcCkKbGlicmFyeSh0aWJibGUpCmBgYAoKCiMgMi4gbG9hZCBzZXVyYXQgb2JqZWN0CmBgYHtyIGxvYWRfc2V1cmF0fQojTG9hZCBTZXVyYXQgT2JqZWN0IEw3CmxvYWQoIi4uLzAtcm9iai81LUhhcm1vbnlfSW50ZWdyYXRlZF9BbGxfc2FtcGxlc19NZXJnZWRfQ0Q0VGNlbGxzX2ZpbmFsX1Jlc29sdXRpb25fU2VsZWN0ZWRfMC44X0FEVF9Ob3JtYWxpemVkX2NsZWFuZWRfbXQucm9iaiIpCgoKQWxsX3NhbXBsZXNfTWVyZ2VkCgoKCmBgYAoKIyAzLiBTZXQgVXAgSWRlbnRpZmllcnMgZm9yIENsdXN0ZXJpbmcKYGBge3J9CiMgQXNzaWduIGNsdXN0ZXIgaWRlbnRpdGllcyB0byB0aGUgU2V1cmF0IG9iamVjdApJZGVudHMoQWxsX3NhbXBsZXNfTWVyZ2VkKSA8LSAic2V1cmF0X2NsdXN0ZXJzIgoKRGltUGxvdChBbGxfc2FtcGxlc19NZXJnZWQsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAiY2VsbF9saW5lIixsYWJlbCA9IFQsIGxhYmVsLmJveCA9IFQpCkRpbVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVycyIsbGFiZWwgPSBULCBsYWJlbC5ib3ggPSBUKQoKYGBgCgojIDQuICBEaWZmZXJlbnRpYWwgRXhwcmVzc2lvbiBBbmFseXNpcwoKIyMgNC4xIFVzaW5nIE1BU1Qgd2l0aCBTQ1QgYW5kIExhdGVudCBWYXJpYWJsZXMgKEJhdGNoIENvcnJlY3Rpb24pCmBgYHtyfQptYXJrZXJzX21hc3RfU0NUIDwtIEZpbmRNYXJrZXJzKAogIEFsbF9zYW1wbGVzX01lcmdlZCwKICBpZGVudC4xID0gYygiNSIsICI5IiwgIjEiLCAiMiIsICI2IiwgIjgiLCAiNCIsICIwIiwgIjciLCAiMTEiLCAiMTIiLCAiMTMiKSwgIyBDZWxsIGxpbmVzLU1hbGlnbmFudAogIGlkZW50LjIgPSBjKCIzIiwgIjEwIiksICMgTm9ybWFsIENENCBUIGNlbGxzCiAgYXNzYXkgPSAiU0NUIiwKICB0ZXN0LnVzZSA9ICJNQVNUIiwKICBsYXRlbnQudmFycyA9IGMoImNlbGxfbGluZSIsICJQYXRpZW50X29yaWdpbiIpLCAjIEFkanVzdCBmb3IgYmF0Y2ggZWZmZWN0cwogIG1pbi5wY3QgPSAwLAogIGxvZ2ZjLnRocmVzaG9sZCA9IDAKKQp3cml0ZS5jc3YobWFya2Vyc19tYXN0X1NDVCwgZmlsZSA9ICIuLi8wLXJvYmovMS1NQVNUX3dpdGhfU0NUX2JhdGNoX3BhdGllbnRfY2VsbGxpbmVfYXNfQ292YXJpYXRlLmNzdiIsIHJvdy5uYW1lcyA9IFRSVUUpCmBgYAoKIyMgNC4yIFVzaW5nIE1BU1Qgd2l0aCBSTkEgYW5kIExhdGVudCBWYXJpYWJsZXMgKEJhdGNoIENvcnJlY3Rpb24pCmBgYHtyfQoKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkobWFncml0dHIpCgojIFNldCB0aGUgZGVmYXVsdCBhc3NheSB0byBSTkEKRGVmYXVsdEFzc2F5KEFsbF9zYW1wbGVzX01lcmdlZCkgPC0gIlJOQSIKCiMgTm9ybWFsaXplIHRoZSBSTkEgYXNzYXkgYnV0IERPIE5PVCBzY2FsZSB0aGUgZGF0YQpBbGxfc2FtcGxlc19NZXJnZWQgPC0gQWxsX3NhbXBsZXNfTWVyZ2VkICU+JQogIE5vcm1hbGl6ZURhdGEobm9ybWFsaXphdGlvbi5tZXRob2QgPSAiTG9nTm9ybWFsaXplIiwgc2NhbGUuZmFjdG9yID0gMTAwMDApCgoKbWFya2Vyc19tYXN0X1JOQSA8LSBGaW5kTWFya2VycygKICBBbGxfc2FtcGxlc19NZXJnZWQsCiBpZGVudC4xID0gYygiNSIsICI5IiwgIjEiLCAiMiIsICI2IiwgIjgiLCAiNCIsICIwIiwgIjciLCAiMTEiLCAiMTIiLCAiMTMiKSwgIyBDZWxsIGxpbmVzLU1hbGlnbmFudAogIGlkZW50LjIgPSBjKCIzIiwgIjEwIiksICMgTm9ybWFsIENENCBUIGNlbGxzCiAgYXNzYXkgPSAiUk5BIiwKICB0ZXN0LnVzZSA9ICJNQVNUIiwKICBsYXRlbnQudmFycyA9IGMoImNlbGxfbGluZSIsICJQYXRpZW50X29yaWdpbiIpLCAjIEFkanVzdCBmb3IgYmF0Y2ggZWZmZWN0cwogIG1pbi5wY3QgPSAwLAogIGxvZ2ZjLnRocmVzaG9sZCA9IDAKKQp3cml0ZS5jc3YobWFya2Vyc19tYXN0X1JOQSwgZmlsZSA9ICIuLi8wLXJvYmovMi1NQVNUX3dpdGhfUk5BX2JhdGNoX3BhdGllbnRfY2VsbGxpbmVfYXNfQ292YXJpYXRlLmNzdiIsIHJvdy5uYW1lcyA9IFRSVUUpCmBgYAoKCgojIDUuIENvbXB1dGUgTWVhbiBFeHByZXNzaW9uIGZvciBHcm91cHMKYGBge3J9CmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KGRwbHlyKQoKIyBEZWZpbmUgY2VsbCBncm91cHMKZ3JvdXAxX2NlbGxzIDwtIFdoaWNoQ2VsbHMoQWxsX3NhbXBsZXNfTWVyZ2VkLCBpZGVudHMgPSBjKCI1IiwgIjkiLCAiMSIsICIyIiwgIjYiLCAiOCIsICI0IiwgIjAiLCAiNyIsICIxMSIsICIxMiIsICIxMyIpKSAgIyBNYWxpZ25hbnQgQ0Q0KyBUIGNlbGxzCmdyb3VwMl9jZWxscyA8LSBXaGljaENlbGxzKEFsbF9zYW1wbGVzX01lcmdlZCwgaWRlbnRzID0gYygiMyIsICIxMCIpKSAgIyBOb3JtYWwgQ0Q0KyBUIGNlbGxzCgojIEV4dHJhY3Qgbm9ybWFsaXplZCBleHByZXNzaW9uIHZhbHVlcyBmb3IgYm90aCBhc3NheXMKZXhwcmVzc2lvbl9kYXRhX1JOQSA8LSBHZXRBc3NheURhdGEoQWxsX3NhbXBsZXNfTWVyZ2VkLCBhc3NheSA9ICJSTkEiLCBsYXllciA9ICJkYXRhIikgICMgTG9nLW5vcm1hbGl6ZWQgY291bnRzCmV4cHJlc3Npb25fZGF0YV9TQ1QgPC0gR2V0QXNzYXlEYXRhKEFsbF9zYW1wbGVzX01lcmdlZCwgYXNzYXkgPSAiU0NUIiwgbGF5ZXIgPSAiZGF0YSIpICAjIFNDVC1ub3JtYWxpemVkIGNvdW50cyAobm90IFBlYXJzb24gcmVzaWR1YWxzKQoKIyBGdW5jdGlvbiB0byBjYWxjdWxhdGUgbWVhbiBleHByZXNzaW9uIGZvciBlYWNoIGdyb3VwCmNhbGN1bGF0ZV9tZWFuX2V4cHJlc3Npb24gPC0gZnVuY3Rpb24obWFya2VycywgZ3JvdXAxX2NlbGxzLCBncm91cDJfY2VsbHMsIGV4cHJlc3Npb25fZGF0YSkgewogIGdyb3VwMV9tZWFuIDwtIHJvd01lYW5zKGV4cHJlc3Npb25fZGF0YVssIGdyb3VwMV9jZWxscywgZHJvcCA9IEZBTFNFXSwgbmEucm0gPSBUUlVFKQogIGdyb3VwMl9tZWFuIDwtIHJvd01lYW5zKGV4cHJlc3Npb25fZGF0YVssIGdyb3VwMl9jZWxscywgZHJvcCA9IEZBTFNFXSwgbmEucm0gPSBUUlVFKQogIAogIG1hcmtlcnMgPC0gbWFya2VycyAlPiUKICAgIHJvd25hbWVzX3RvX2NvbHVtbigiZ2VuZSIpICU+JQogICAgbXV0YXRlKG1lYW5fZXhwcl9ncm91cDEgPSBncm91cDFfbWVhbltnZW5lXSwKICAgICAgICAgICBtZWFuX2V4cHJfZ3JvdXAyID0gZ3JvdXAyX21lYW5bZ2VuZV0pCiAgCiAgcmV0dXJuKG1hcmtlcnMpCn0KCiMgQ29tcHV0ZSBtZWFuIGV4cHJlc3Npb24gZm9yIFJOQSBhbmQgU0NUIGFzc2F5cwptYXJrZXJzX21hc3RfUk5BIDwtIGNhbGN1bGF0ZV9tZWFuX2V4cHJlc3Npb24obWFya2Vyc19tYXN0X1JOQSwgZ3JvdXAxX2NlbGxzLCBncm91cDJfY2VsbHMsIGV4cHJlc3Npb25fZGF0YV9STkEpCm1hcmtlcnNfbWFzdF9TQ1QgPC0gY2FsY3VsYXRlX21lYW5fZXhwcmVzc2lvbihtYXJrZXJzX21hc3RfU0NULCBncm91cDFfY2VsbHMsIGdyb3VwMl9jZWxscywgZXhwcmVzc2lvbl9kYXRhX1NDVCkKCiMgU2F2ZSB1cGRhdGVkIHJlc3VsdHMgd2l0aCBtZWFuIGV4cHJlc3Npb24Kd3JpdGUuY3N2KG1hcmtlcnNfbWFzdF9STkEsIGZpbGUgPSAiLi4vMC1yb2JqLzItTUFTVF93aXRoX1JOQV9iYXRjaF9wYXRpZW50X2NlbGxsaW5lX2FzX0NvdmFyaWF0ZV93aXRoX21lYW5FeHByZXNzaW9uLmNzdiIsIHJvdy5uYW1lcyA9IFRSVUUpCndyaXRlLmNzdihtYXJrZXJzX21hc3RfU0NULCBmaWxlID0gIi4uLzAtcm9iai8xLU1BU1Rfd2l0aF9TQ1RfYmF0Y2hfcGF0aWVudF9jZWxsbGluZV9hc19Db3ZhcmlhdGVfd2l0aF9tZWFuRXhwcmVzc2lvbi5jc3YiLCByb3cubmFtZXMgPSBUUlVFKQoKYGBgCgojIDYuIFN1bW1hcml6ZSBSZXN1bHRzCgojIyA2LjEgU3VtbWFyeSBGdW5jdGlvbgpgYGB7cn0Kc3VtbWFyaXplX21hcmtlcnMgPC0gZnVuY3Rpb24obWFya2VycykgewogIG51bV9wdmFsMCA8LSBzdW0obWFya2VycyRwX3ZhbF9hZGogPT0gMCkKICBudW1fcHZhbDEgPC0gc3VtKG1hcmtlcnMkcF92YWxfYWRqID09IDEpCiAgbnVtX3NpZ25pZmljYW50IDwtIHN1bShtYXJrZXJzJHBfdmFsX2FkaiA8IDAuMDUpCiAgbnVtX3VwcmVndWxhdGVkIDwtIHN1bShtYXJrZXJzJGF2Z19sb2cyRkMgPiAxKQogIG51bV9kb3ducmVndWxhdGVkIDwtIHN1bShtYXJrZXJzJGF2Z19sb2cyRkMgPCAtMSkKICAKICBjYXQoIk51bWJlciBvZiBnZW5lcyB3aXRoIHBfdmFsX2FkaiA9IDA6IiwgbnVtX3B2YWwwLCAiXG4iKQogIGNhdCgiTnVtYmVyIG9mIGdlbmVzIHdpdGggcF92YWxfYWRqID0gMToiLCBudW1fcHZhbDEsICJcbiIpCiAgY2F0KCJOdW1iZXIgb2Ygc2lnbmlmaWNhbnQgZ2VuZXMgKHBfdmFsX2FkaiA8IDAuMDUpOiIsIG51bV9zaWduaWZpY2FudCwgIlxuIikKICBjYXQoIk51bWJlciBvZiB1cHJlZ3VsYXRlZCBnZW5lcyAoYXZnX2xvZzJGQyA+IDEpOiIsIG51bV91cHJlZ3VsYXRlZCwgIlxuIikKICBjYXQoIk51bWJlciBvZiBkb3ducmVndWxhdGVkIGdlbmVzIChhdmdfbG9nMkZDIDwgLTEpOiIsIG51bV9kb3ducmVndWxhdGVkLCAiXG4iKQp9CgpgYGAKCiMjIDYuMiBTdW1tYXJpemUgTWFya2VyczEgKE1BU1Qgd2l0aCBTQ1QgQXNzYXkpCmBgYHtyfQpjYXQoIk1hcmtlcnMxIFN1bW1hcnkgKE1BU1Qgd2l0aCBTQ1QgQXNzYXkpOlxuIikKc3VtbWFyaXplX21hcmtlcnMobWFya2Vyc19tYXN0X1NDVCkKCmBgYAoKIyMgNi4zIFN1bW1hcnkgZm9yIE1hcmtlcnMyIChNQVNUIHdpdGggUk5BIEFzc2F5KQpgYGB7cn0KY2F0KCJNYXJrZXJzMiBTdW1tYXJ5IChNQVNUIHdpdGggUk5BIEFzc2F5KTpcbiIpCnN1bW1hcml6ZV9tYXJrZXJzKG1hcmtlcnNfbWFzdF9STkEpCmBgYAoKIyMgQ29tcGFyZSBSZXN1bHRzIEJldHdlZW4gU0NUIGFuZCBSTkEgQXNzYXlzCmBgYHtyfQojIyMgQ29tcGFyZSBSZXN1bHRzIEJldHdlZW4gUk5BIGFuZCBTQ1QgQXNzYXlzCgojIExvYWQgZ2VuZSBzZXRzCmdlbmVzX21hc3Rfc2N0IDwtIG1hcmtlcnNfbWFzdF9TQ1QkZ2VuZQpnZW5lc19tYXN0X3JuYSA8LSBtYXJrZXJzX21hc3RfUk5BJGdlbmUKY29tbW9uX2dlbmVzX21hc3QgPC0gaW50ZXJzZWN0KGdlbmVzX21hc3Rfc2N0LCBnZW5lc19tYXN0X3JuYSkKCmNhdCgiTUFTVDogQ29tbW9uIEdlbmVzIEJldHdlZW4gU0NUIGFuZCBSTkE6IiwgbGVuZ3RoKGNvbW1vbl9nZW5lc19tYXN0KSwgIlxuIikKCmBgYAoKCiMgNy4gVmlzdWFsaXphdGlvbgoKIyMgNy4xIFZvbGNhbm8gUGxvdCBmb3IgTUFTVC1TQ1Qgd2l0aCBCYXRjaCBDb3JyZWN0aW9uCmBgYHtyLCBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTJ9CgpFbmhhbmNlZFZvbGNhbm8obWFya2Vyc19tYXN0X1NDVCwKICAgICAgICAgICAgICAgIGxhYiA9IG1hcmtlcnNfbWFzdF9TQ1QkZ2VuZSwKICAgICAgICAgICAgICAgIHggPSAiYXZnX2xvZzJGQyIsCiAgICAgICAgICAgICAgICB5ID0gInBfdmFsX2FkaiIsCiAgICAgICAgICAgICAgICB0aXRsZSA9ICJNYWxpZ25hbnRfdnNfTm9ybWFsX01BU1RfU0NUIiwKICAgICAgICAgICAgICAgIHBDdXRvZmYgPSAwLjA1LAogICAgICAgICAgICAgICAgRkNjdXRvZmYgPSAxLjApCgpgYGAKCiMjIDcuMiBWb2xjYW5vIFBsb3QgTUFTVC1STkEgd2l0aCBCYXRjaCBDb3JyZWN0aW9uCmBgYHtyLCBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTJ9CgpFbmhhbmNlZFZvbGNhbm8obWFya2Vyc19tYXN0X1JOQSwKICAgICAgICAgICAgICAgIGxhYiA9IG1hcmtlcnNfbWFzdF9STkEkZ2VuZSwKICAgICAgICAgICAgICAgIHggPSAiYXZnX2xvZzJGQyIsCiAgICAgICAgICAgICAgICB5ID0gInBfdmFsX2FkaiIsCiAgICAgICAgICAgICAgICB0aXRsZSA9ICJNYWxpZ25hbnRfdnNfTm9ybWFsX01BU1RfUk5BIiwKICAgICAgICAgICAgICAgIHBDdXRvZmYgPSAwLjA1LAogICAgICAgICAgICAgICAgRkNjdXRvZmYgPSAxLjApCgpgYGAKCiMjIDcuMyBWb2xjYW5vIFBsb3QgTUFTVC1STkEgd2l0aCBCYXRjaCBDb3JyZWN0aW9uCmBgYHtyLCBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTJ9CgojIyMgMS4gTG9hZCBEYXRhIGFuZCBQcmVwYXJlIGZvciBDb21wYXJpc29uCgpsaWJyYXJ5KGdncGxvdDIpCgpkZl9zY3QgPC0gcmVhZC5jc3YoIi4uLzAtcm9iai8xLU1BU1Rfd2l0aF9TQ1RfYmF0Y2hfcGF0aWVudF9jZWxsbGluZV9hc19Db3ZhcmlhdGUuY3N2Iiwgcm93Lm5hbWVzID0gMSkKZGZfcm5hIDwtIHJlYWQuY3N2KCIuLi8wLXJvYmovMi1NQVNUX3dpdGhfUk5BX2JhdGNoX3BhdGllbnRfY2VsbGxpbmVfYXNfQ292YXJpYXRlLmNzdiIsIHJvdy5uYW1lcyA9IDEpCgpkZl9zY3QkYXNzYXkgPC0gIlNDVCIKZGZfcm5hJGFzc2F5IDwtICJSTkEiCgpkZl9jb21iaW5lZCA8LSByYmluZChkZl9zY3QsIGRmX3JuYSkKCiMjIyAyLiBWb2xjYW5vIFBsb3QgZm9yIFNDVCB2cyBSTkEgQ29tcGFyaXNvbgoKZ2dwbG90KGRmX2NvbWJpbmVkLCBhZXMoeCA9IGF2Z19sb2cyRkMsIHkgPSAtbG9nMTAocF92YWxfYWRqKSwgY29sb3IgPSBhc3NheSkpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC43KSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIlZvbGNhbm8gUGxvdDogUk5BIHZzIFNDVCIsIHggPSAiTG9nMiBGb2xkIENoYW5nZSIsIHkgPSAiLUxvZzEwIEFkanVzdGVkIFAtdmFsdWUiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIlNDVCIgPSAiYmx1ZSIsICJSTkEiID0gInJlZCIpKQoKYGBgCgoKIyMgNy40IENvcnJlbGF0aW9uIG9mIExvZzIgRm9sZCBDaGFuZ2UgQmV0d2VlbiBSTkEgYW5kIFNDVApgYGB7ciwgZmlnLmhlaWdodD0xMiwgZmlnLndpZHRoPTEyfQoKIyBDb3JyZWxhdGlvbiBvZiBMb2cyIEZvbGQgQ2hhbmdlIEJldHdlZW4gUk5BIGFuZCBTQ1QKIyBHb2FsOiBTZWUgaWYgZ2VuZXMgaGF2ZSBjb25zaXN0ZW50IGZvbGQgY2hhbmdlcyBiZXR3ZWVuIFJOQSBhbmQgU0NUIG5vcm1hbGl6YXRpb24uCgoKbGlicmFyeShkcGx5cikgICMgTG9hZCBkcGx5ciB0byB1c2Ugcm93bmFtZXNfdG9fY29sdW1uCgoKIyBDb252ZXJ0IHJvdyBuYW1lcyB0byBhICJnZW5lIiBjb2x1bW4KZGZfc2N0IDwtIGRmX3NjdCAlPiUgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJnZW5lIikKZGZfcm5hIDwtIGRmX3JuYSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJnZW5lIikKCiMgTWVyZ2UgZGF0YXNldHMgYnkgZ2VuZQpkZl9tZXJnZWQgPC0gbWVyZ2UoZGZfc2N0LCBkZl9ybmEsIGJ5ID0gImdlbmUiLCBzdWZmaXhlcyA9IGMoIl9TQ1QiLCAiX1JOQSIpKQoKIyBTY2F0dGVyIHBsb3Qgb2YgbG9nMkZDIHZhbHVlcwpnZ3Bsb3QoZGZfbWVyZ2VkLCBhZXMoeCA9IGF2Z19sb2cyRkNfU0NULCB5ID0gYXZnX2xvZzJGQ19STkEpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNywgY29sb3IgPSAiYmx1ZSIpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBjb2xvciA9ICJyZWQiLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIkxvZzIgRm9sZCBDaGFuZ2UgQ29tcGFyaXNvbjogU0NUIHZzIFJOQSIsCiAgICAgICB4ID0gIlNDVCBMb2cyIEZvbGQgQ2hhbmdlIiwKICAgICAgIHkgPSAiUk5BIExvZzIgRm9sZCBDaGFuZ2UiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkb3R0ZWQiLCBjb2xvciA9ICJibGFjayIpCmBgYAoKCiMjIDcuNSBGaW5kIG92ZXJsYXAgYmV0d2VlbiB0aGUgdG9wIDEwMCBtb3N0IHNpZ25pZmljYW50IGdlbmVzOgpgYGB7ciwgZmlnLmhlaWdodD0xMiwgZmlnLndpZHRoPTEyfQoKY29yKGRmX21lcmdlZCRhdmdfbG9nMkZDX1NDVCwgZGZfbWVyZ2VkJGF2Z19sb2cyRkNfUk5BLCB1c2UgPSAiY29tcGxldGUub2JzIikKCiMgSGlnaGVyIGNvcnJlbGF0aW9uICh+MC44LTEuMCkgc3VnZ2VzdHMgY29uc2lzdGVuY3kgYmV0d2VlbiBtZXRob2RzLgojIExvd2VyIGNvcnJlbGF0aW9uICg8MC42KSBtYXkgaW5kaWNhdGUgZGlmZmVyZW50IG5vcm1hbGl6YXRpb24gZWZmZWN0cy4KCgpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZHBseXIpCgojIERlZmluZSBhIGJyb2FkZXIgbGlzdCBvZiBrbm93biBTZXphcnkgZ2VuZXMKc2V6YXJ5X2dlbmVzIDwtIGMoIktJUjNETDIiLCAiVE9YIiwgIlRXSVNUMSIsICJDRDUyIiwgIkNDUjQiLCAiSUwyUkEiLCAiQ0Q3IiwgIkRQUDQiLCAiQ0NSNyIsICJHQVRBMyIsICJGT1hQMyIsICJDRDhBIiwgIkNENCIsICJDWVAyN0IxIiwgIlRFVDIiKQoKIyBGaWx0ZXIgdGhlIG1lcmdlZCBkYXRhIHRvIGluY2x1ZGUgb25seSB0aGUga25vd24gU2V6YXJ5IGdlbmVzCmRmX2ZpbHRlcmVkIDwtIGRmX21lcmdlZCAlPiUKICBmaWx0ZXIoZ2VuZSAlaW4lIHNlemFyeV9nZW5lcykKCiMgVm9sY2FubyBwbG90IHNob3dpbmcgb25seSB0aGUga25vd24gU2V6YXJ5IGdlbmVzIHdpdGggZ2VuZSBuYW1lcwpnZ3Bsb3QoZGZfZmlsdGVyZWQsIGFlcyh4ID0gYXZnX2xvZzJGQ19TQ1QsIHkgPSAtbG9nMTAocF92YWxfYWRqX1NDVCksIGNvbG9yID0gZ2VuZSkpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC43KSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGdlbmUpLCB2anVzdCA9IDEuNSwgaGp1c3QgPSAwLjUsIHNpemUgPSAzLCBjb2xvciA9ICJibGFjayIpICsgICMgQWRkaW5nIGdlbmUgbmFtZXMKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiVm9sY2FubyBQbG90OiBLbm93biBTZXphcnkgR2VuZXMgKFNDVCBBc3NheSkiLCAKICAgICAgIHggPSAiTG9nMiBGb2xkIENoYW5nZSAoU0NUKSIsIAogICAgICAgeSA9ICItTG9nMTAgQWRqdXN0ZWQgUC12YWx1ZSIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiS0lSM0RMMiIgPSAiIzFmNzdiNCIsICAjIGJsdWUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVE9YIiA9ICIjZmY3ZjBlIiwgICMgb3JhbmdlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRXSVNUMSIgPSAiIzJjYTAyYyIsICAjIGdyZWVuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNENTIiID0gIiM5NDY3YmQiLCAgIyBwdXJwbGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ0NSNCIgPSAiIzhjNTY0YiIsICAjIGJyb3duCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIklMMlJBIiA9ICIjZTM3N2MyIiwgICMgcGluawogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDRDciID0gIiM3ZjdmN2YiLCAgIyBncmF5CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkRQUDQiID0gIiNiY2JkMjIiLCAgIyB5ZWxsb3ctZ3JlZW4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ0NSNyIgPSAiIzE3YmVjZiIsICAjIGN5YW4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR0FUQTMiID0gIiNkNjI3MjgiLCAgIyByZWQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRk9YUDMiID0gIiM4YTJiZTIiLCAgIyBibHVlLXZpb2xldAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDRDhBIiA9ICIjZmY2MzQ3IiwgICMgdG9tYXRvCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNENCIgPSAiIzNjYjM3MSIsICAjIG1lZGl1bSBzZWEgZ3JlZW4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ1lQMjdCMSIgPSAiI2ZmMTQ5MyIsICAjIGRlZXAgcGluawogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJURVQyIiA9ICIjMDBiZmZmIikpICsgICMgZGVlcCBza3kgYmx1ZQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQoKYGBg