Introduction

This analysis validates CLIC1 as a biomarker in Sézary Syndrome using publicly available single-cell RNA-seq data from Herrera et al. (2021). The dataset includes:

  • Healthy Controls (HC): 1 donor, blood and skin
  • Sézary Syndrome (SS): 6 patients, blood ± skin samples
  • Mycosis Fungoides (MF): 1 patient, blood and skin

Reference: Herrera et al. (2021) - PMC8532199

load libraries

Define File Paths

# Base directory
base_dir <- "/home/bioinfo/1-Thesis_Final_Year_2025/2025-Final_Year_Results/2025-Year3_Analysis/Biomarkers_Validation_with_Public_Data/Herrera_Data/"

# Seurat object
seurat_file <- file.path(base_dir, "Herrara_All_samples.rds")

# TCR data directory
tcr_dir <- file.path(base_dir, "Herrara_TCR_AB")

# Output directory
output_dir <- "output"
dir.create(output_dir, showWarnings = FALSE)

Load Seurat Object

cat("Loading Seurat object...\n")
Loading Seurat object...
merged_seurat <- readRDS(seurat_file)

cat("Dataset dimensions:\n")
Dataset dimensions:
cat(sprintf("  - Cells: %d\n", ncol(merged_seurat)))
  - Cells: 30345
cat(sprintf("  - Genes: %d\n", nrow(merged_seurat)))
  - Genes: 33660
cat(sprintf("  - Samples: %s\n", paste(unique(merged_seurat$sample_id), collapse = ", ")))
  - Samples: SS1_Blood, SS2_Blood, SS3_Blood, SS4_Blood, SS5_Blood, SS6_Blood, MF1_Blood, SS1_Skin, SS2_Skin, SS3_Skin, SS4_Skin, MF1_Skin, Healthy_Skin, Healthy_Blood

Load TCR Data

tcr_list <- lapply(names(tcr_files), function(sample_name) {
cat("Reading:", sample_name, "\n")
df <- read.delim(gzfile(tcr_files[[sample_name]]), check.names = FALSE)
colnames(df)[1] <- "clonotype"

df_long <- df %>%
pivot_longer(
cols = -clonotype,
names_to = "cell_barcode",
values_to = "count"
) %>%
filter(count > 0) %>%
mutate(sample_id = sample_name)

return(df_long)
})
Reading: HC1_Blood 
Reading: HC1_Skin 
Reading: SS1_Blood 
Reading: SS1_Skin 
Reading: SS2_Blood 
Reading: SS2_Skin 
Reading: SS3_Blood 
Reading: SS3_Skin 
Reading: SS4_Blood 
Reading: SS4_Skin 
Reading: MFIV1_Blood 
Reading: MFIV1_Skin 
Reading: SS5_Blood 
Reading: SS6_Blood 
combined_tcr <- bind_rows(tcr_list)
cat("Total productive TCR assignments:", nrow(combined_tcr), "\n")
Total productive TCR assignments: 17899 

CLIC1 VALIDATION

Integrate TCR with Seurat

library(stringr)

# Extract alpha and beta chains from clonotype
combined_tcr <- combined_tcr %>%
  mutate(
    TCR_alpha = str_extract(clonotype, "(?<=TRA:)[^|]+"),
    TCR_beta  = str_extract(clonotype, "(?<=TRB:)[^|]+")
  )
# Make cell_barcode match Seurat object
combined_tcr <- combined_tcr %>%
  mutate(cell_barcode = paste0(sample_id, "_", cell_barcode))

# Keep only cells present in Seurat
tcr_in_seurat <- combined_tcr[combined_tcr$cell_barcode %in% colnames(merged_seurat), ]

# Create a metadata table for Seurat
tcr_meta <- tcr_in_seurat %>%
  select(cell_barcode, clonotype, TCR_alpha, TCR_beta) %>%
  column_to_rownames("cell_barcode")

merged_seurat <- AddMetaData(merged_seurat, metadata = tcr_meta)

Identify expanded malignant T cells

# =========================
# Identify expanded malignant T cells per SS sample using scRepertoire
# =========================

ss_samples <- c("SS1_Blood", "SS1_Skin", "SS2_Blood", "SS2_Skin",
                "SS3_Blood", "SS3_Skin", "SS4_Blood", "SS4_Skin",
                "SS5_Blood", "SS6_Blood")

malignant_cells_list <- list()

for (s in ss_samples) {
  sample_cells <- subset(merged_seurat, subset = sample_id == s)
  
  # Skip sample if no TCR_beta
  if (!"TCR_beta" %in% colnames(sample_cells@meta.data)) next
  
  clonotype_counts <- table(sample_cells$TCR_beta)
  expanded_clones <- names(clonotype_counts[clonotype_counts >= 5])
  
  # Skip if no expanded clones
  if (length(expanded_clones) == 0) next
  
  malignant <- subset(sample_cells, subset = TCR_beta %in% expanded_clones)
  
  # Only add if there are cells
  if (ncol(malignant) > 0) malignant_cells_list[[s]] <- malignant
}

# =========================
# Merge all malignant SS cells (robust)
# =========================
malignant_cells_list <- malignant_cells_list[!sapply(malignant_cells_list, is.null)] # remove NULLs
malignant_cells_list <- unname(malignant_cells_list)                                  # remove names
sezary_cells <- Reduce(function(x, y) merge(x, y), malignant_cells_list)             # merge all

highlight top clones


library(scRepertoire)
library(Seurat)

# ================================
# Clonal homeostasis (size distribution)
# ================================
clonalHomeostasis(sezary_cells, cloneCall = "clonotype")


# ================================
#  Clonal proportion / relative abundance
# ================================
clonalProportion(sezary_cells, cloneCall = "clonotype")

NA
NA

highlight top clones

library(scRepertoire)

clonalOverlap(sezary_cells, cloneCall = "clonotype", group.by = "sample_id", method = "morisita")

NA
NA

Merge all Sézary malignant cells with healthy controls

# ================================
# Merge all Sézary malignant cells with healthy controls
# ================================
# Ensure RNA assay
DefaultAssay(sezary_cells) <- "RNA"

# Normalize and identify variable features
sezary_cells <- NormalizeData(sezary_cells, normalization.method = "LogNormalize", scale.factor = 10000)
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
sezary_cells <- FindVariableFeatures(sezary_cells, selection.method = "vst", nfeatures = 2000)
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
sezary_cells <- ScaleData(sezary_cells)

  |                                                                                                       
  |                                                                                                 |   0%
  |                                                                                                       
  |================================================                                                 |  50%
  |                                                                                                       
  |=================================================================================================| 100%
sezary_cells <- RunPCA(sezary_cells, npcs = 20)

# Subset healthy control cells
hc_cells <- subset(merged_seurat, subset = sample_id %in% c("Healthy_Blood", "Healthy_Skin"))

# Merge all together
ss_vs_hc <- merge(
  x = sezary_cells,
  y = hc_cells,
  add.cell.ids = c("SS", "HC")
)

# ================================
# Normalize, find variable features, scale, and run PCA & UMAP on merged object
# ================================
DefaultAssay(ss_vs_hc) <- "RNA"
ss_vs_hc <- NormalizeData(ss_vs_hc, normalization.method = "LogNormalize", scale.factor = 10000)
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
ss_vs_hc <- FindVariableFeatures(ss_vs_hc, selection.method = "vst", nfeatures = 2000)
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
ss_vs_hc <- ScaleData(ss_vs_hc)

  |                                                                                                       
  |                                                                                                 |   0%
  |                                                                                                       
  |================================================                                                 |  50%
  |                                                                                                       
  |=================================================================================================| 100%
ss_vs_hc <- RunPCA(ss_vs_hc, npcs = 20)
ss_vs_hc <- RunUMAP(ss_vs_hc, dims = 1:20)
Using method 'umap'
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
# ================================
# Add tissue grouping column
# ================================
ss_vs_hc$tissue_group <- case_when(
  grepl("Blood", ss_vs_hc$sample_id, ignore.case = TRUE) ~ "Blood",
  grepl("Skin", ss_vs_hc$sample_id, ignore.case = TRUE) ~ "Skin",
  TRUE ~ "Other"
)

# ================================
# Visualize CLIC1 expression
# ================================

# FeaturePlot with red gradient
FeaturePlot(ss_vs_hc, features = "CLIC1", reduction = "umap",
            cols = c("grey90", "red"), label = TRUE)


# DotPlot by sample_id with red-grey gradient
DotPlot(ss_vs_hc, features = "CLIC1", group.by = "sample_id") +
  RotatedAxis() +
  scale_color_gradient(low = "grey90", high = "red") +
  ggtitle("CLIC1 Expression by Sample") +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, size = 12),
    axis.text.y = element_text(size = 12),
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14)
  )


# DotPlot by tissue_group with red-grey gradient
DotPlot(ss_vs_hc, features = "CLIC1", group.by = "tissue_group") +
  RotatedAxis() +
  scale_color_gradient(low = "grey90", high = "red") +
  ggtitle("CLIC1 Expression by Tissue") +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, size = 12),
    axis.text.y = element_text(size = 12),
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14)
  )


# ================================
# Visualize CLIC1
# ================================
# FeaturePlot
FeaturePlot(ss_vs_hc, features = "CLIC1", reduction = "umap")


# DotPlot grouped by sample
DotPlot(ss_vs_hc, features = "CLIC1", group.by = "sample_id") + RotatedAxis()


# DotPlot grouped by tissue
DotPlot(ss_vs_hc, features = "CLIC1", group.by = "tissue_group") + RotatedAxis()

Visualize CLIC1


# DimPlot by sample
DimPlot(ss_vs_hc, group.by = "sample_id", reduction = "umap")


# FeaturePlot for CLIC1
FeaturePlot(ss_vs_hc, features = "CLIC1", reduction = "umap")


# DotPlot for CLIC1 across groups
DotPlot(ss_vs_hc, features = "CLIC1", group.by = "sample_id") + 
  theme(axis.text.x = element_text(angle = 45, hjust = 1))


# FeaturePlot with red gradient
FeaturePlot(ss_vs_hc, features = "CLIC1", reduction = "umap",
            cols = c("grey90", "red"), label = TRUE, repel = T)

FeaturePlots for Top50 UP

top_50_up <- read.csv("top_50_upregulated.csv")        # or read.delim("top_50_up.tsv")
top_50_down <- read.csv("top_50_downregulated.csv")



FeaturePlot(ss_vs_hc, 
             features = top_50_up$gene[1:10], 
             reduction = "umap", 
             cols = c("lightblue", "red"),  # Custom color gradient from light blue to red
             label = TRUE)



FeaturePlot(ss_vs_hc, 
             features = top_50_up$gene[11:20], 
             reduction = "umap", 
             cols = c("lightblue", "red"),  # Custom color gradient from light blue to red
             label = TRUE)


FeaturePlot(ss_vs_hc, 
             features = top_50_up$gene[21:30], 
             reduction = "umap", 
             cols = c("lightblue", "red"),  # Custom color gradient from light blue to red
             label = TRUE)


FeaturePlot(ss_vs_hc, 
             features = top_50_up$gene[31:40], 
             reduction = "umap", 
             cols = c("lightblue", "red"),  # Custom color gradient from light blue to red
             label = TRUE)


FeaturePlot(ss_vs_hc, 
             features = top_50_up$gene[41:50], 
             reduction = "umap", 
             cols = c("lightblue", "red"),  # Custom color gradient from light blue to red
             label = TRUE)

FeaturePlots for Top50 DOWN


FeaturePlot(ss_vs_hc, 
             features = top_50_down$gene[1:10], 
             reduction = "umap", 
             cols = c("lightblue", "red"),  # Custom color gradient from light blue to red
             label = TRUE)


FeaturePlot(ss_vs_hc, 
             features = top_50_down$gene[11:20], 
             reduction = "umap", 
             cols = c("lightblue", "red"),  # Custom color gradient from light blue to red
             label = TRUE)


FeaturePlot(ss_vs_hc, 
             features = top_50_down$gene[21:30], 
             reduction = "umap", 
             cols = c("lightblue", "red"),  # Custom color gradient from light blue to red
             label = TRUE)


FeaturePlot(ss_vs_hc, 
             features = top_50_down$gene[31:40], 
             reduction = "umap", 
             cols = c("lightblue", "red"),  # Custom color gradient from light blue to red
             label = TRUE)


FeaturePlot(ss_vs_hc, 
             features = top_50_down$gene[41:50], 
             reduction = "umap", 
             cols = c("lightblue", "red"),  # Custom color gradient from light blue to red
             label = TRUE)



  )
Error: unexpected ')' in "  )"

Visualization of Potential biomarkers-Upregulated


# Vector of genes to plot
up_genes <- c("CLIC1", "COX5A","GTSF1", "MAD2L1","MYBL2","MYL6B","NME1","PLK1", "PYCR1", "SLC25A5", "SRI", "TUBA1C", "UBE2T", "YWHAH")

# DotPlot with custom firebrick-red gradient
DotPlot(ss_vs_hc, features = up_genes) +
  RotatedAxis() +
  scale_color_gradient2(low = "lightblue", mid = "red", high = "firebrick", midpoint = 1) +
  ggtitle("Expression of Upregulated Genes in Sézary Syndrome") +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, size = 12),
    axis.text.y = element_text(size = 12),
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14)
  )


# DotPlot with custom firebrick-red gradient
DotPlot(ss_vs_hc, features = up_genes, group.by = "sample_id") +
  RotatedAxis() +
  scale_color_gradient2(low = "lightblue", mid = "red", high = "firebrick", midpoint = 1) +
  ggtitle("Expression of Upregulated Genes in Sézary Syndrome") +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, size = 12),
    axis.text.y = element_text(size = 12),
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14)
  )


# DotPlot with custom firebrick-red gradient
DotPlot(ss_vs_hc, features = up_genes, group.by = "tissue") +
  RotatedAxis() +
  scale_color_gradient2(low = "lightblue", mid = "red", high = "firebrick", midpoint = 1) +
  ggtitle("Expression of Upregulated Genes in Sézary Syndrome") +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, size = 12),
    axis.text.y = element_text(size = 12),
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14)
  )

# DotPlot with custom firebrick-red gradient
DotPlot(ss_vs_hc, features = up_genes, group.by = "condition") +
  RotatedAxis() +
  scale_color_gradient2(low = "lightblue", mid = "red", high = "firebrick", midpoint = 1) +
  ggtitle("Expression of Upregulated Genes in Sézary Syndrome") +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, size = 12),
    axis.text.y = element_text(size = 12),
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14)
  )



# DotPlot with custom firebrick-red gradient
DotPlot(ss_vs_hc, features = up_genes, group.by = "condition") +
  RotatedAxis() +
  scale_color_gradient2(low = "lightblue", mid = "red", high = "firebrick", midpoint = 1) +
  ggtitle("Expression of Upregulated Genes in Sézary Syndrome") +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, size = 12),
    axis.text.y = element_text(size = 12),
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14))

Visualization of Potential biomarkers-Downregulated


# Downregulated genes
down_genes <- c("TXNIP", "RASA3", "RIPOR2", 
                "ZFP36", "ZFP36L1", "ZFP36L2",
                "PRMT2", "MAX", "PIK3IP1", 
                "BTG1", "CDKN1B")

# DotPlot with firebrick color for high expression
DotPlot(ss_vs_hc, features = down_genes) +
  RotatedAxis() +
  scale_color_gradient2(low = "lightblue", mid = "red", high = "firebrick", midpoint = 1) +
  ggtitle("Expression of Downregulated Genes in Sézary Syndrome") +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, size = 12),
    axis.text.y = element_text(size = 12),
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14)
  )


# DotPlot with firebrick color for high expression
DotPlot(ss_vs_hc, features = down_genes, group.by = "sample_id") +
  RotatedAxis() +
  scale_color_gradient2(low = "lightblue", mid = "red", high = "firebrick", midpoint = 1) +
  ggtitle("Expression of Downregulated Genes in Sézary Syndrome") +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, size = 12),
    axis.text.y = element_text(size = 12),
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14)
  )


# DotPlot with firebrick color for high expression
DotPlot(ss_vs_hc, features = down_genes, group.by = "tissue") +
  RotatedAxis() +
  scale_color_gradient2(low = "lightblue", mid = "red", high = "firebrick", midpoint = 1) +
  ggtitle("Expression of Downregulated Genes in Sézary Syndrome") +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, size = 12),
    axis.text.y = element_text(size = 12),
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14)
  )


# DotPlot with firebrick color for high expression
DotPlot(ss_vs_hc, features = down_genes, group.by = "condition") +
  RotatedAxis() +
  scale_color_gradient2(low = "lightblue", mid = "red", high = "firebrick", midpoint = 1) +
  ggtitle("Expression of Downregulated Genes in Sézary Syndrome") +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, size = 12),
    axis.text.y = element_text(size = 12),
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14)
  )

Compare condition using RNA assay-ss_vs_hc


# Load required libraries
library(Seurat)
library(dplyr)
library(tibble)

combined_seu <- ss_vs_hc

# Join the layers of the RNA assay
combined_seu <- JoinLayers(combined_seu, assay = "RNA")

# Ensure your identity class is set to disease status
Idents(combined_seu) <- "condition"  # e.g., levels: "SS", "Control"

# Run differential expression between SS vs Control
markers_disease <- FindMarkers(
  object = combined_seu,
  ident.1 = "SS",
  ident.2 = "Healthy",
  assay = "RNA",
  logfc.threshold = 0,
  min.pct = 0,
  test.use = "wilcox"  # or "MAST" if RNA assay supports it
)

# Save results to CSV
write.csv(markers_disease, file = "DE_SS_vs_Healthy_Herrara2021.csv", row.names = TRUE)

# Get log-normalized expression matrix (RNA assay)
expression_data_RNA <- GetAssayData(combined_seu, assay = "RNA", slot = "data")

# Get cell names for each group
ss_cells <- WhichCells(combined_seu, idents = "SS")
healthy_cells <- WhichCells(combined_seu, idents = "Healthy")

# Function to add mean expression per 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_SS = group1_mean[gene],
      mean_expr_Healthy = group2_mean[gene],
      log2FC_manual = log2(mean_expr_SS + 1) - log2(mean_expr_Healthy + 1)
    )
  return(markers)
}

# Apply the function and save final result
markers_disease_with_mean <- calculate_mean_expression(markers_disease, ss_cells, healthy_cells, expression_data_RNA)
write.csv(markers_disease_with_mean, "DE_SS_vs_Healthy_with_MeanExpr_Herrera2021.csv", row.names = FALSE)

Compare condition using RNA assay-Merged seurat


# Load required libraries
library(Seurat)
library(dplyr)
library(tibble)

combined_seu <- merged_seurat

# Join the layers of the RNA assay
combined_seu <- JoinLayers(combined_seu, assay = "RNA")

# Ensure your identity class is set to disease status
Idents(combined_seu) <- "condition"  # e.g., levels: "SS", "Control"

# Run differential expression between SS vs Control
markers_disease <- FindMarkers(
  object = combined_seu,
  ident.1 = "SS",
  ident.2 = "Healthy",
  assay = "RNA",
  logfc.threshold = 0,
  min.pct = 0,
  test.use = "wilcox"  
)

# Save results to CSV
write.csv(markers_disease, file = "MergedSeurat_DE_SS_vs_Healthy_Herrara2021.csv", row.names = TRUE)

# Get log-normalized expression matrix (RNA assay)
expression_data_RNA <- GetAssayData(combined_seu, assay = "RNA", slot = "data")

# Get cell names for each group
ss_cells <- WhichCells(combined_seu, idents = "SS")
healthy_cells <- WhichCells(combined_seu, idents = "Healthy")

# Function to add mean expression per 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_SS = group1_mean[gene],
      mean_expr_Healthy = group2_mean[gene],
      log2FC_manual = log2(mean_expr_SS + 1) - log2(mean_expr_Healthy + 1)
    )
  return(markers)
}

# Apply the function and save final result
markers_disease_with_mean <- calculate_mean_expression(markers_disease, ss_cells, healthy_cells, expression_data_RNA)
write.csv(markers_disease_with_mean, "MergedSeurat_DE_SS_vs_Healthy_with_MeanExpr_Herrera2021.csv", row.names = FALSE)

Save Seurat object


#saveRDS(ss_vs_hc, file = "Sezary_Blood_Skin_vs_HC_TCR_filtered.rds")
LS0tCnRpdGxlOiAiVENSICYgQ0xJQzEgQW5hbHlzaXMgaW4gU8OpemFyeSBTeW5kcm9tZShWYWxpZGF0aW9uIEhlcnJhcmEgZGF0YSIKYXV0aG9yOiBOYXNpciBNYWhtb29kIEFiYmFzaQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICAjcm1kZm9ybWF0czo6cmVhZHRoZWRvd24KICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRvY19jb2xsYXBzZWQ6IHRydWUKLS0tCiMgSW50cm9kdWN0aW9uCgpUaGlzIGFuYWx5c2lzIHZhbGlkYXRlcyBDTElDMSBhcyBhIGJpb21hcmtlciBpbiBTw6l6YXJ5IFN5bmRyb21lIHVzaW5nIHB1YmxpY2x5IGF2YWlsYWJsZSBzaW5nbGUtY2VsbCBSTkEtc2VxIGRhdGEgZnJvbSBIZXJyZXJhIGV0IGFsLiAoMjAyMSkuIFRoZSBkYXRhc2V0IGluY2x1ZGVzOgoKLSAqKkhlYWx0aHkgQ29udHJvbHMgKEhDKSoqOiAxIGRvbm9yLCBibG9vZCBhbmQgc2tpbgotICoqU8OpemFyeSBTeW5kcm9tZSAoU1MpKio6IDYgcGF0aWVudHMsIGJsb29kIMKxIHNraW4gc2FtcGxlcyAgCi0gKipNeWNvc2lzIEZ1bmdvaWRlcyAoTUYpKio6IDEgcGF0aWVudCwgYmxvb2QgYW5kIHNraW4KCioqUmVmZXJlbmNlKio6IEhlcnJlcmEgZXQgYWwuICgyMDIxKSAtIFBNQzg1MzIxOTkKCiBodHRwczovL3BtYy5uY2JpLm5sbS5uaWguZ292L2FydGljbGVzL1BNQzg1MzIxOTkvIAotLS0KCiMgbG9hZCBsaWJyYXJpZXMKYGBge3IgLCBpbmNsdWRlPUZBTFNFfQoKIyBDb3JlIHBhY2thZ2VzCmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpYmJsZSkKbGlicmFyeShnZ3Bsb3QyKQoKIyBTcGVjaWFsaXplZCBwYWNrYWdlcwpsaWJyYXJ5KHNjUmVwZXJ0b2lyZSkgICMgVENSIGFuYWx5c2lzCmxpYnJhcnkoZ2dwdWJyKSAgICAgICAgIyBTdGF0aXN0aWNhbCBwbG90dGluZwpsaWJyYXJ5KHJzdGF0aXgpICAgICAgICMgRWZmZWN0IHNpemVzCmxpYnJhcnkocGF0Y2h3b3JrKSAgICAgIyBDb21iaW5lIHBsb3RzCgojIFNldCB0aGVtZQp0aGVtZV9zZXQodGhlbWVfbWluaW1hbCgpKQoKIyBTdXBwcmVzcyB3YXJuaW5ncwpvcHRpb25zKHdhcm4gPSAtMSkKCmBgYAoKIyMgRGVmaW5lIEZpbGUgUGF0aHMKYGBge3IgcGF0aHN9CiMgQmFzZSBkaXJlY3RvcnkKYmFzZV9kaXIgPC0gIi9ob21lL2Jpb2luZm8vMS1UaGVzaXNfRmluYWxfWWVhcl8yMDI1LzIwMjUtRmluYWxfWWVhcl9SZXN1bHRzLzIwMjUtWWVhcjNfQW5hbHlzaXMvQmlvbWFya2Vyc19WYWxpZGF0aW9uX3dpdGhfUHVibGljX0RhdGEvSGVycmVyYV9EYXRhLyIKCiMgU2V1cmF0IG9iamVjdApzZXVyYXRfZmlsZSA8LSBmaWxlLnBhdGgoYmFzZV9kaXIsICJIZXJyYXJhX0FsbF9zYW1wbGVzLnJkcyIpCgojIFRDUiBkYXRhIGRpcmVjdG9yeQp0Y3JfZGlyIDwtIGZpbGUucGF0aChiYXNlX2RpciwgIkhlcnJhcmFfVENSX0FCIikKCiMgT3V0cHV0IGRpcmVjdG9yeQpvdXRwdXRfZGlyIDwtICJvdXRwdXQiCmRpci5jcmVhdGUob3V0cHV0X2Rpciwgc2hvd1dhcm5pbmdzID0gRkFMU0UpCmBgYAoKLS0tCgoKIyMgTG9hZCBTZXVyYXQgT2JqZWN0CmBgYHtyIGxvYWRfc2V1cmF0LCBtZXNzYWdlPUZBTFNFfQpjYXQoIkxvYWRpbmcgU2V1cmF0IG9iamVjdC4uLlxuIikKbWVyZ2VkX3NldXJhdCA8LSByZWFkUkRTKHNldXJhdF9maWxlKQoKY2F0KCJEYXRhc2V0IGRpbWVuc2lvbnM6XG4iKQpjYXQoc3ByaW50ZigiICAtIENlbGxzOiAlZFxuIiwgbmNvbChtZXJnZWRfc2V1cmF0KSkpCmNhdChzcHJpbnRmKCIgIC0gR2VuZXM6ICVkXG4iLCBucm93KG1lcmdlZF9zZXVyYXQpKSkKY2F0KHNwcmludGYoIiAgLSBTYW1wbGVzOiAlc1xuIiwgcGFzdGUodW5pcXVlKG1lcmdlZF9zZXVyYXQkc2FtcGxlX2lkKSwgY29sbGFwc2UgPSAiLCAiKSkpCmBgYAoKIyMgTG9hZCBUQ1IgRGF0YQpgYGB7ciBsb2FkX3RjciwgbWVzc2FnZT1GQUxTRX0KIyBMb2FkIGFsbCBmaWxlcywgcmVzaGFwZSBmcm9tIHdpZGUgdG8gbG9uZyBmb3JtYXQKbGlicmFyeSh0aWR5cikKbGlicmFyeShkcGx5cikKbGlicmFyeShyZWFkcikKCiMgRGVmaW5lIFRDUiBmaWxlIHBhdGhzIChnemlwcGVkKQojIERlZmluZSBUQ1IgZmlsZSBwYXRocyB3aXRoIGZ1bGwgcGF0aHMKCnRjcl9maWxlcyA8LSBsaXN0KApIQzFfQmxvb2QgPSBmaWxlLnBhdGgodGNyX2RpciwgIkdTTTUyMzQ1NzZfSEMxX0Jsb29kX2Nsb25vdHlwZUFCLnRzdi5neiIpLApIQzFfU2tpbiAgPSBmaWxlLnBhdGgodGNyX2RpciwgIkdTTTUyMzQ1NzdfSEMxX1NraW5fY2xvbm90eXBlQUIudHN2Lmd6IiksClNTMV9CbG9vZCA9IGZpbGUucGF0aCh0Y3JfZGlyLCAiR1NNNTIzNDU3OF9TUzFfQmxvb2RfY2xvbm90eXBlQUIudHN2Lmd6IiksClNTMV9Ta2luICA9IGZpbGUucGF0aCh0Y3JfZGlyLCAiR1NNNTIzNDU3OV9TUzFfU2tpbl9jbG9ub3R5cGVBQi50c3YuZ3oiKSwKU1MyX0Jsb29kID0gZmlsZS5wYXRoKHRjcl9kaXIsICJHU001MjM0NTgwX1NTMl9CbG9vZF9jbG9ub3R5cGVBQi50c3YuZ3oiKSwKU1MyX1NraW4gID0gZmlsZS5wYXRoKHRjcl9kaXIsICJHU001MjM0NTgxX1NTMl9Ta2luX2Nsb25vdHlwZUFCLnRzdi5neiIpLApTUzNfQmxvb2QgPSBmaWxlLnBhdGgodGNyX2RpciwgIkdTTTUyMzQ1ODJfU1MzX0Jsb29kX2Nsb25vdHlwZUFCLnRzdi5neiIpLApTUzNfU2tpbiAgPSBmaWxlLnBhdGgodGNyX2RpciwgIkdTTTUyMzQ1ODNfU1MzX1NraW5fY2xvbm90eXBlQUIudHN2Lmd6IiksClNTNF9CbG9vZCA9IGZpbGUucGF0aCh0Y3JfZGlyLCAiR1NNNTIzNDU4NF9TUzRfQmxvb2RfY2xvbm90eXBlQUIudHN2Lmd6IiksClNTNF9Ta2luICA9IGZpbGUucGF0aCh0Y3JfZGlyLCAiR1NNNTIzNDU4NV9TUzRfU2tpbl9jbG9ub3R5cGVBQi50c3YuZ3oiKSwKTUZJVjFfQmxvb2QgPSBmaWxlLnBhdGgodGNyX2RpciwgIkdTTTUyMzQ1ODZfTUZJVjFfQmxvb2RfY2xvbm90eXBlQUIudHN2Lmd6IiksCk1GSVYxX1NraW4gID0gZmlsZS5wYXRoKHRjcl9kaXIsICJHU001MjM0NTg3X01GSVYxX1NraW5fY2xvbm90eXBlQUIudHN2Lmd6IiksClNTNV9CbG9vZCAgID0gZmlsZS5wYXRoKHRjcl9kaXIsICJHU001MjM0NTg4X1NTNV9CbG9vZF9jbG9ub3R5cGVBQi50c3YuZ3oiKSwKU1M2X0Jsb29kICAgPSBmaWxlLnBhdGgodGNyX2RpciwgIkdTTTUyMzQ1ODlfU1M2X0Jsb29kX2Nsb25vdHlwZUFCLnRzdi5neiIpCikKCmNhdCgiTG9hZGluZyBnemlwcGVkIFRDUiBjbG9ub3R5cGUgZmlsZXMuLi5cbiIpCgojIFJlYWQgYW5kIGNvbnZlcnQgZWFjaCBmaWxlIGZyb20gd2lkZSB0byBsb25nIGZvcm1hdAoKdGNyX2xpc3QgPC0gbGFwcGx5KG5hbWVzKHRjcl9maWxlcyksIGZ1bmN0aW9uKHNhbXBsZV9uYW1lKSB7CmNhdCgiUmVhZGluZzoiLCBzYW1wbGVfbmFtZSwgIlxuIikKZGYgPC0gcmVhZC5kZWxpbShnemZpbGUodGNyX2ZpbGVzW1tzYW1wbGVfbmFtZV1dKSwgY2hlY2submFtZXMgPSBGQUxTRSkKY29sbmFtZXMoZGYpWzFdIDwtICJjbG9ub3R5cGUiCgpkZl9sb25nIDwtIGRmICU+JQpwaXZvdF9sb25nZXIoCmNvbHMgPSAtY2xvbm90eXBlLApuYW1lc190byA9ICJjZWxsX2JhcmNvZGUiLAp2YWx1ZXNfdG8gPSAiY291bnQiCikgJT4lCmZpbHRlcihjb3VudCA+IDApICU+JQptdXRhdGUoc2FtcGxlX2lkID0gc2FtcGxlX25hbWUpCgpyZXR1cm4oZGZfbG9uZykKfSkKCmNvbWJpbmVkX3RjciA8LSBiaW5kX3Jvd3ModGNyX2xpc3QpCmNhdCgiVG90YWwgcHJvZHVjdGl2ZSBUQ1IgYXNzaWdubWVudHM6IiwgbnJvdyhjb21iaW5lZF90Y3IpLCAiXG4iKQoKCmBgYAoKIyAqKkNMSUMxIFZBTElEQVRJT04qKgojIyAgSW50ZWdyYXRlIFRDUiB3aXRoIFNldXJhdApgYGB7ciAsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTZ9CmxpYnJhcnkoc3RyaW5ncikKCiMgRXh0cmFjdCBhbHBoYSBhbmQgYmV0YSBjaGFpbnMgZnJvbSBjbG9ub3R5cGUKY29tYmluZWRfdGNyIDwtIGNvbWJpbmVkX3RjciAlPiUKICBtdXRhdGUoCiAgICBUQ1JfYWxwaGEgPSBzdHJfZXh0cmFjdChjbG9ub3R5cGUsICIoPzw9VFJBOilbXnxdKyIpLAogICAgVENSX2JldGEgID0gc3RyX2V4dHJhY3QoY2xvbm90eXBlLCAiKD88PVRSQjopW158XSsiKQogICkKIyBNYWtlIGNlbGxfYmFyY29kZSBtYXRjaCBTZXVyYXQgb2JqZWN0CmNvbWJpbmVkX3RjciA8LSBjb21iaW5lZF90Y3IgJT4lCiAgbXV0YXRlKGNlbGxfYmFyY29kZSA9IHBhc3RlMChzYW1wbGVfaWQsICJfIiwgY2VsbF9iYXJjb2RlKSkKCiMgS2VlcCBvbmx5IGNlbGxzIHByZXNlbnQgaW4gU2V1cmF0CnRjcl9pbl9zZXVyYXQgPC0gY29tYmluZWRfdGNyW2NvbWJpbmVkX3RjciRjZWxsX2JhcmNvZGUgJWluJSBjb2xuYW1lcyhtZXJnZWRfc2V1cmF0KSwgXQoKIyBDcmVhdGUgYSBtZXRhZGF0YSB0YWJsZSBmb3IgU2V1cmF0CnRjcl9tZXRhIDwtIHRjcl9pbl9zZXVyYXQgJT4lCiAgc2VsZWN0KGNlbGxfYmFyY29kZSwgY2xvbm90eXBlLCBUQ1JfYWxwaGEsIFRDUl9iZXRhKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXMoImNlbGxfYmFyY29kZSIpCgptZXJnZWRfc2V1cmF0IDwtIEFkZE1ldGFEYXRhKG1lcmdlZF9zZXVyYXQsIG1ldGFkYXRhID0gdGNyX21ldGEpCgpgYGAKCgoKCiMjICBJZGVudGlmeSBleHBhbmRlZCBtYWxpZ25hbnQgVCBjZWxscyAKYGBge3IgLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD02fQojID09PT09PT09PT09PT09PT09PT09PT09PT0KIyBJZGVudGlmeSBleHBhbmRlZCBtYWxpZ25hbnQgVCBjZWxscyBwZXIgU1Mgc2FtcGxlIHVzaW5nIHNjUmVwZXJ0b2lyZQojID09PT09PT09PT09PT09PT09PT09PT09PT0KCnNzX3NhbXBsZXMgPC0gYygiU1MxX0Jsb29kIiwgIlNTMV9Ta2luIiwgIlNTMl9CbG9vZCIsICJTUzJfU2tpbiIsCiAgICAgICAgICAgICAgICAiU1MzX0Jsb29kIiwgIlNTM19Ta2luIiwgIlNTNF9CbG9vZCIsICJTUzRfU2tpbiIsCiAgICAgICAgICAgICAgICAiU1M1X0Jsb29kIiwgIlNTNl9CbG9vZCIpCgptYWxpZ25hbnRfY2VsbHNfbGlzdCA8LSBsaXN0KCkKCmZvciAocyBpbiBzc19zYW1wbGVzKSB7CiAgc2FtcGxlX2NlbGxzIDwtIHN1YnNldChtZXJnZWRfc2V1cmF0LCBzdWJzZXQgPSBzYW1wbGVfaWQgPT0gcykKICAKICAjIFNraXAgc2FtcGxlIGlmIG5vIFRDUl9iZXRhCiAgaWYgKCEiVENSX2JldGEiICVpbiUgY29sbmFtZXMoc2FtcGxlX2NlbGxzQG1ldGEuZGF0YSkpIG5leHQKICAKICBjbG9ub3R5cGVfY291bnRzIDwtIHRhYmxlKHNhbXBsZV9jZWxscyRUQ1JfYmV0YSkKICBleHBhbmRlZF9jbG9uZXMgPC0gbmFtZXMoY2xvbm90eXBlX2NvdW50c1tjbG9ub3R5cGVfY291bnRzID49IDVdKQogIAogICMgU2tpcCBpZiBubyBleHBhbmRlZCBjbG9uZXMKICBpZiAobGVuZ3RoKGV4cGFuZGVkX2Nsb25lcykgPT0gMCkgbmV4dAogIAogIG1hbGlnbmFudCA8LSBzdWJzZXQoc2FtcGxlX2NlbGxzLCBzdWJzZXQgPSBUQ1JfYmV0YSAlaW4lIGV4cGFuZGVkX2Nsb25lcykKICAKICAjIE9ubHkgYWRkIGlmIHRoZXJlIGFyZSBjZWxscwogIGlmIChuY29sKG1hbGlnbmFudCkgPiAwKSBtYWxpZ25hbnRfY2VsbHNfbGlzdFtbc11dIDwtIG1hbGlnbmFudAp9CgojID09PT09PT09PT09PT09PT09PT09PT09PT0KIyBNZXJnZSBhbGwgbWFsaWduYW50IFNTIGNlbGxzIChyb2J1c3QpCiMgPT09PT09PT09PT09PT09PT09PT09PT09PQptYWxpZ25hbnRfY2VsbHNfbGlzdCA8LSBtYWxpZ25hbnRfY2VsbHNfbGlzdFshc2FwcGx5KG1hbGlnbmFudF9jZWxsc19saXN0LCBpcy5udWxsKV0gIyByZW1vdmUgTlVMTHMKbWFsaWduYW50X2NlbGxzX2xpc3QgPC0gdW5uYW1lKG1hbGlnbmFudF9jZWxsc19saXN0KSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHJlbW92ZSBuYW1lcwpzZXphcnlfY2VsbHMgPC0gUmVkdWNlKGZ1bmN0aW9uKHgsIHkpIG1lcmdlKHgsIHkpLCBtYWxpZ25hbnRfY2VsbHNfbGlzdCkgICAgICAgICAgICAgIyBtZXJnZSBhbGwKCgpgYGAKCgojIyAgaGlnaGxpZ2h0IHRvcCBjbG9uZXMKYGBge3IgLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD02fQoKbGlicmFyeShzY1JlcGVydG9pcmUpCmxpYnJhcnkoU2V1cmF0KQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIENsb25hbCBob21lb3N0YXNpcyAoc2l6ZSBkaXN0cmlidXRpb24pCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KY2xvbmFsSG9tZW9zdGFzaXMoc2V6YXJ5X2NlbGxzLCBjbG9uZUNhbGwgPSAiY2xvbm90eXBlIikKCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyAgQ2xvbmFsIHByb3BvcnRpb24gLyByZWxhdGl2ZSBhYnVuZGFuY2UKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQpjbG9uYWxQcm9wb3J0aW9uKHNlemFyeV9jZWxscywgY2xvbmVDYWxsID0gImNsb25vdHlwZSIpCgoKYGBgCiMjICBoaWdobGlnaHQgdG9wIGNsb25lcwpgYGB7ciAsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTEyfQpsaWJyYXJ5KHNjUmVwZXJ0b2lyZSkKCmNsb25hbE92ZXJsYXAoc2V6YXJ5X2NlbGxzLCBjbG9uZUNhbGwgPSAiY2xvbm90eXBlIiwgZ3JvdXAuYnkgPSAic2FtcGxlX2lkIiwgbWV0aG9kID0gIm1vcmlzaXRhIikKCgpgYGAKCgoKCiMjICBNZXJnZSBhbGwgU8OpemFyeSBtYWxpZ25hbnQgY2VsbHMgd2l0aCBoZWFsdGh5IGNvbnRyb2xzCmBgYHtyICwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9Nn0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIE1lcmdlIGFsbCBTw6l6YXJ5IG1hbGlnbmFudCBjZWxscyB3aXRoIGhlYWx0aHkgY29udHJvbHMKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIEVuc3VyZSBSTkEgYXNzYXkKRGVmYXVsdEFzc2F5KHNlemFyeV9jZWxscykgPC0gIlJOQSIKCiMgTm9ybWFsaXplIGFuZCBpZGVudGlmeSB2YXJpYWJsZSBmZWF0dXJlcwpzZXphcnlfY2VsbHMgPC0gTm9ybWFsaXplRGF0YShzZXphcnlfY2VsbHMsIG5vcm1hbGl6YXRpb24ubWV0aG9kID0gIkxvZ05vcm1hbGl6ZSIsIHNjYWxlLmZhY3RvciA9IDEwMDAwKQpzZXphcnlfY2VsbHMgPC0gRmluZFZhcmlhYmxlRmVhdHVyZXMoc2V6YXJ5X2NlbGxzLCBzZWxlY3Rpb24ubWV0aG9kID0gInZzdCIsIG5mZWF0dXJlcyA9IDIwMDApCnNlemFyeV9jZWxscyA8LSBTY2FsZURhdGEoc2V6YXJ5X2NlbGxzKQpzZXphcnlfY2VsbHMgPC0gUnVuUENBKHNlemFyeV9jZWxscywgbnBjcyA9IDIwKQoKIyBTdWJzZXQgaGVhbHRoeSBjb250cm9sIGNlbGxzCmhjX2NlbGxzIDwtIHN1YnNldChtZXJnZWRfc2V1cmF0LCBzdWJzZXQgPSBzYW1wbGVfaWQgJWluJSBjKCJIZWFsdGh5X0Jsb29kIiwgIkhlYWx0aHlfU2tpbiIpKQoKIyBNZXJnZSBhbGwgdG9nZXRoZXIKc3NfdnNfaGMgPC0gbWVyZ2UoCiAgeCA9IHNlemFyeV9jZWxscywKICB5ID0gaGNfY2VsbHMsCiAgYWRkLmNlbGwuaWRzID0gYygiU1MiLCAiSEMiKQopCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgTm9ybWFsaXplLCBmaW5kIHZhcmlhYmxlIGZlYXR1cmVzLCBzY2FsZSwgYW5kIHJ1biBQQ0EgJiBVTUFQIG9uIG1lcmdlZCBvYmplY3QKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQpEZWZhdWx0QXNzYXkoc3NfdnNfaGMpIDwtICJSTkEiCnNzX3ZzX2hjIDwtIE5vcm1hbGl6ZURhdGEoc3NfdnNfaGMsIG5vcm1hbGl6YXRpb24ubWV0aG9kID0gIkxvZ05vcm1hbGl6ZSIsIHNjYWxlLmZhY3RvciA9IDEwMDAwKQpzc192c19oYyA8LSBGaW5kVmFyaWFibGVGZWF0dXJlcyhzc192c19oYywgc2VsZWN0aW9uLm1ldGhvZCA9ICJ2c3QiLCBuZmVhdHVyZXMgPSAyMDAwKQpzc192c19oYyA8LSBTY2FsZURhdGEoc3NfdnNfaGMpCnNzX3ZzX2hjIDwtIFJ1blBDQShzc192c19oYywgbnBjcyA9IDIwKQpzc192c19oYyA8LSBSdW5VTUFQKHNzX3ZzX2hjLCBkaW1zID0gMToyMCkKCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyBBZGQgdGlzc3VlIGdyb3VwaW5nIGNvbHVtbgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CnNzX3ZzX2hjJHRpc3N1ZV9ncm91cCA8LSBjYXNlX3doZW4oCiAgZ3JlcGwoIkJsb29kIiwgc3NfdnNfaGMkc2FtcGxlX2lkLCBpZ25vcmUuY2FzZSA9IFRSVUUpIH4gIkJsb29kIiwKICBncmVwbCgiU2tpbiIsIHNzX3ZzX2hjJHNhbXBsZV9pZCwgaWdub3JlLmNhc2UgPSBUUlVFKSB+ICJTa2luIiwKICBUUlVFIH4gIk90aGVyIgopCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgVmlzdWFsaXplIENMSUMxIGV4cHJlc3Npb24KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQoKIyBGZWF0dXJlUGxvdCB3aXRoIHJlZCBncmFkaWVudApGZWF0dXJlUGxvdChzc192c19oYywgZmVhdHVyZXMgPSAiQ0xJQzEiLCByZWR1Y3Rpb24gPSAidW1hcCIsCiAgICAgICAgICAgIGNvbHMgPSBjKCJncmV5OTAiLCAicmVkIiksIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUKQoKIyBEb3RQbG90IGJ5IHNhbXBsZV9pZCB3aXRoIHJlZC1ncmV5IGdyYWRpZW50CkRvdFBsb3Qoc3NfdnNfaGMsIGZlYXR1cmVzID0gIkNMSUMxIiwgZ3JvdXAuYnkgPSAic2FtcGxlX2lkIikgKwogIFJvdGF0ZWRBeGlzKCkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdyA9ICJncmV5OTAiLCBoaWdoID0gInJlZCIpICsKICBnZ3RpdGxlKCJDTElDMSBFeHByZXNzaW9uIGJ5IFNhbXBsZSIpICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgc2l6ZSA9IDEyKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLCBzaXplID0gMTQpCiAgKQoKIyBEb3RQbG90IGJ5IHRpc3N1ZV9ncm91cCB3aXRoIHJlZC1ncmV5IGdyYWRpZW50CkRvdFBsb3Qoc3NfdnNfaGMsIGZlYXR1cmVzID0gIkNMSUMxIiwgZ3JvdXAuYnkgPSAidGlzc3VlX2dyb3VwIikgKwogIFJvdGF0ZWRBeGlzKCkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdyA9ICJncmV5OTAiLCBoaWdoID0gInJlZCIpICsKICBnZ3RpdGxlKCJDTElDMSBFeHByZXNzaW9uIGJ5IFRpc3N1ZSIpICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgc2l6ZSA9IDEyKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLCBzaXplID0gMTQpCiAgKQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIFZpc3VhbGl6ZSBDTElDMQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgRmVhdHVyZVBsb3QKRmVhdHVyZVBsb3Qoc3NfdnNfaGMsIGZlYXR1cmVzID0gIkNMSUMxIiwgcmVkdWN0aW9uID0gInVtYXAiKQoKIyBEb3RQbG90IGdyb3VwZWQgYnkgc2FtcGxlCkRvdFBsb3Qoc3NfdnNfaGMsIGZlYXR1cmVzID0gIkNMSUMxIiwgZ3JvdXAuYnkgPSAic2FtcGxlX2lkIikgKyBSb3RhdGVkQXhpcygpCgojIERvdFBsb3QgZ3JvdXBlZCBieSB0aXNzdWUKRG90UGxvdChzc192c19oYywgZmVhdHVyZXMgPSAiQ0xJQzEiLCBncm91cC5ieSA9ICJ0aXNzdWVfZ3JvdXAiKSArIFJvdGF0ZWRBeGlzKCkKCmBgYAojIyAgICBWaXN1YWxpemUgQ0xJQzEKYGBge3IgLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD02fQoKIyBEaW1QbG90IGJ5IHNhbXBsZQpEaW1QbG90KHNzX3ZzX2hjLCBncm91cC5ieSA9ICJzYW1wbGVfaWQiLCByZWR1Y3Rpb24gPSAidW1hcCIpCgojIEZlYXR1cmVQbG90IGZvciBDTElDMQpGZWF0dXJlUGxvdChzc192c19oYywgZmVhdHVyZXMgPSAiQ0xJQzEiLCByZWR1Y3Rpb24gPSAidW1hcCIpCgojIERvdFBsb3QgZm9yIENMSUMxIGFjcm9zcyBncm91cHMKRG90UGxvdChzc192c19oYywgZmVhdHVyZXMgPSAiQ0xJQzEiLCBncm91cC5ieSA9ICJzYW1wbGVfaWQiKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCgojIEZlYXR1cmVQbG90IHdpdGggcmVkIGdyYWRpZW50CkZlYXR1cmVQbG90KHNzX3ZzX2hjLCBmZWF0dXJlcyA9ICJDTElDMSIsIHJlZHVjdGlvbiA9ICJ1bWFwIiwKICAgICAgICAgICAgY29scyA9IGMoImdyZXk5MCIsICJyZWQiKSwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFQpCgpgYGAKIyMgICBGZWF0dXJlUGxvdHMgZm9yIFRvcDUwIFVQCmBgYHtyICwgZmlnLmhlaWdodD0xMiwgZmlnLndpZHRoPTE2fQp0b3BfNTBfdXAgPC0gcmVhZC5jc3YoInRvcF81MF91cHJlZ3VsYXRlZC5jc3YiKSAgICAgICAgIyBvciByZWFkLmRlbGltKCJ0b3BfNTBfdXAudHN2IikKdG9wXzUwX2Rvd24gPC0gcmVhZC5jc3YoInRvcF81MF9kb3ducmVndWxhdGVkLmNzdiIpCgoKCkZlYXR1cmVQbG90KHNzX3ZzX2hjLCAKICAgICAgICAgICAgIGZlYXR1cmVzID0gdG9wXzUwX3VwJGdlbmVbMToxMF0sIAogICAgICAgICAgICAgcmVkdWN0aW9uID0gInVtYXAiLCAKICAgICAgICAgICAgIGNvbHMgPSBjKCJsaWdodGJsdWUiLCAicmVkIiksICAjIEN1c3RvbSBjb2xvciBncmFkaWVudCBmcm9tIGxpZ2h0IGJsdWUgdG8gcmVkCiAgICAgICAgICAgICBsYWJlbCA9IFRSVUUpCgoKRmVhdHVyZVBsb3Qoc3NfdnNfaGMsIAogICAgICAgICAgICAgZmVhdHVyZXMgPSB0b3BfNTBfdXAkZ2VuZVsxMToyMF0sIAogICAgICAgICAgICAgcmVkdWN0aW9uID0gInVtYXAiLCAKICAgICAgICAgICAgIGNvbHMgPSBjKCJsaWdodGJsdWUiLCAicmVkIiksICAjIEN1c3RvbSBjb2xvciBncmFkaWVudCBmcm9tIGxpZ2h0IGJsdWUgdG8gcmVkCiAgICAgICAgICAgICBsYWJlbCA9IFRSVUUpCgpGZWF0dXJlUGxvdChzc192c19oYywgCiAgICAgICAgICAgICBmZWF0dXJlcyA9IHRvcF81MF91cCRnZW5lWzIxOjMwXSwgCiAgICAgICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsIAogICAgICAgICAgICAgY29scyA9IGMoImxpZ2h0Ymx1ZSIsICJyZWQiKSwgICMgQ3VzdG9tIGNvbG9yIGdyYWRpZW50IGZyb20gbGlnaHQgYmx1ZSB0byByZWQKICAgICAgICAgICAgIGxhYmVsID0gVFJVRSkKCkZlYXR1cmVQbG90KHNzX3ZzX2hjLCAKICAgICAgICAgICAgIGZlYXR1cmVzID0gdG9wXzUwX3VwJGdlbmVbMzE6NDBdLCAKICAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwgCiAgICAgICAgICAgICBjb2xzID0gYygibGlnaHRibHVlIiwgInJlZCIpLCAgIyBDdXN0b20gY29sb3IgZ3JhZGllbnQgZnJvbSBsaWdodCBibHVlIHRvIHJlZAogICAgICAgICAgICAgbGFiZWwgPSBUUlVFKQoKRmVhdHVyZVBsb3Qoc3NfdnNfaGMsIAogICAgICAgICAgICAgZmVhdHVyZXMgPSB0b3BfNTBfdXAkZ2VuZVs0MTo1MF0sIAogICAgICAgICAgICAgcmVkdWN0aW9uID0gInVtYXAiLCAKICAgICAgICAgICAgIGNvbHMgPSBjKCJsaWdodGJsdWUiLCAicmVkIiksICAjIEN1c3RvbSBjb2xvciBncmFkaWVudCBmcm9tIGxpZ2h0IGJsdWUgdG8gcmVkCiAgICAgICAgICAgICBsYWJlbCA9IFRSVUUpCgpgYGAKCgojIyAgIEZlYXR1cmVQbG90cyBmb3IgVG9wNTAgRE9XTgpgYGB7ciAsIGZpZy5oZWlnaHQ9MTIsIGZpZy53aWR0aD0xNn0KCkZlYXR1cmVQbG90KHNzX3ZzX2hjLCAKICAgICAgICAgICAgIGZlYXR1cmVzID0gdG9wXzUwX2Rvd24kZ2VuZVsxOjEwXSwgCiAgICAgICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsIAogICAgICAgICAgICAgY29scyA9IGMoImxpZ2h0Ymx1ZSIsICJyZWQiKSwgICMgQ3VzdG9tIGNvbG9yIGdyYWRpZW50IGZyb20gbGlnaHQgYmx1ZSB0byByZWQKICAgICAgICAgICAgIGxhYmVsID0gVFJVRSkKCkZlYXR1cmVQbG90KHNzX3ZzX2hjLCAKICAgICAgICAgICAgIGZlYXR1cmVzID0gdG9wXzUwX2Rvd24kZ2VuZVsxMToyMF0sIAogICAgICAgICAgICAgcmVkdWN0aW9uID0gInVtYXAiLCAKICAgICAgICAgICAgIGNvbHMgPSBjKCJsaWdodGJsdWUiLCAicmVkIiksICAjIEN1c3RvbSBjb2xvciBncmFkaWVudCBmcm9tIGxpZ2h0IGJsdWUgdG8gcmVkCiAgICAgICAgICAgICBsYWJlbCA9IFRSVUUpCgpGZWF0dXJlUGxvdChzc192c19oYywgCiAgICAgICAgICAgICBmZWF0dXJlcyA9IHRvcF81MF9kb3duJGdlbmVbMjE6MzBdLCAKICAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwgCiAgICAgICAgICAgICBjb2xzID0gYygibGlnaHRibHVlIiwgInJlZCIpLCAgIyBDdXN0b20gY29sb3IgZ3JhZGllbnQgZnJvbSBsaWdodCBibHVlIHRvIHJlZAogICAgICAgICAgICAgbGFiZWwgPSBUUlVFKQoKRmVhdHVyZVBsb3Qoc3NfdnNfaGMsIAogICAgICAgICAgICAgZmVhdHVyZXMgPSB0b3BfNTBfZG93biRnZW5lWzMxOjQwXSwgCiAgICAgICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsIAogICAgICAgICAgICAgY29scyA9IGMoImxpZ2h0Ymx1ZSIsICJyZWQiKSwgICMgQ3VzdG9tIGNvbG9yIGdyYWRpZW50IGZyb20gbGlnaHQgYmx1ZSB0byByZWQKICAgICAgICAgICAgIGxhYmVsID0gVFJVRSkKCkZlYXR1cmVQbG90KHNzX3ZzX2hjLCAKICAgICAgICAgICAgIGZlYXR1cmVzID0gdG9wXzUwX2Rvd24kZ2VuZVs0MTo1MF0sIAogICAgICAgICAgICAgcmVkdWN0aW9uID0gInVtYXAiLCAKICAgICAgICAgICAgIGNvbHMgPSBjKCJsaWdodGJsdWUiLCAicmVkIiksICAjIEN1c3RvbSBjb2xvciBncmFkaWVudCBmcm9tIGxpZ2h0IGJsdWUgdG8gcmVkCiAgICAgICAgICAgICBsYWJlbCA9IFRSVUUpCgoKICAKYGBgCgojIyAgIFZpc3VhbGl6YXRpb24gb2YgUG90ZW50aWFsIGJpb21hcmtlcnMtVXByZWd1bGF0ZWQKYGBge3IgLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD0xMH0KCiMgVmVjdG9yIG9mIGdlbmVzIHRvIHBsb3QKdXBfZ2VuZXMgPC0gYygiQ0xJQzEiLCAiQ09YNUEiLCJHVFNGMSIsICJNQUQyTDEiLCJNWUJMMiIsIk1ZTDZCIiwiTk1FMSIsIlBMSzEiLCAiUFlDUjEiLCAiU0xDMjVBNSIsICJTUkkiLCAiVFVCQTFDIiwgIlVCRTJUIiwgIllXSEFIIikKCiMgRG90UGxvdCB3aXRoIGN1c3RvbSBmaXJlYnJpY2stcmVkIGdyYWRpZW50CkRvdFBsb3Qoc3NfdnNfaGMsIGZlYXR1cmVzID0gdXBfZ2VuZXMpICsKICBSb3RhdGVkQXhpcygpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudDIobG93ID0gImxpZ2h0Ymx1ZSIsIG1pZCA9ICJyZWQiLCBoaWdoID0gImZpcmVicmljayIsIG1pZHBvaW50ID0gMSkgKwogIGdndGl0bGUoIkV4cHJlc3Npb24gb2YgVXByZWd1bGF0ZWQgR2VuZXMgaW4gU8OpemFyeSBTeW5kcm9tZSIpICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgc2l6ZSA9IDEyKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLCBzaXplID0gMTQpCiAgKQoKIyBEb3RQbG90IHdpdGggY3VzdG9tIGZpcmVicmljay1yZWQgZ3JhZGllbnQKRG90UGxvdChzc192c19oYywgZmVhdHVyZXMgPSB1cF9nZW5lcywgZ3JvdXAuYnkgPSAic2FtcGxlX2lkIikgKwogIFJvdGF0ZWRBeGlzKCkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50Mihsb3cgPSAibGlnaHRibHVlIiwgbWlkID0gInJlZCIsIGhpZ2ggPSAiZmlyZWJyaWNrIiwgbWlkcG9pbnQgPSAxKSArCiAgZ2d0aXRsZSgiRXhwcmVzc2lvbiBvZiBVcHJlZ3VsYXRlZCBHZW5lcyBpbiBTw6l6YXJ5IFN5bmRyb21lIikgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCBzaXplID0gMTIpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNCkKICApCgojIERvdFBsb3Qgd2l0aCBjdXN0b20gZmlyZWJyaWNrLXJlZCBncmFkaWVudApEb3RQbG90KHNzX3ZzX2hjLCBmZWF0dXJlcyA9IHVwX2dlbmVzLCBncm91cC5ieSA9ICJ0aXNzdWUiKSArCiAgUm90YXRlZEF4aXMoKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQyKGxvdyA9ICJsaWdodGJsdWUiLCBtaWQgPSAicmVkIiwgaGlnaCA9ICJmaXJlYnJpY2siLCBtaWRwb2ludCA9IDEpICsKICBnZ3RpdGxlKCJFeHByZXNzaW9uIG9mIFVwcmVndWxhdGVkIEdlbmVzIGluIFPDqXphcnkgU3luZHJvbWUiKSArCiAgdGhlbWUoCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHNpemUgPSAxMiksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE0KQogICkKIyBEb3RQbG90IHdpdGggY3VzdG9tIGZpcmVicmljay1yZWQgZ3JhZGllbnQKRG90UGxvdChzc192c19oYywgZmVhdHVyZXMgPSB1cF9nZW5lcywgZ3JvdXAuYnkgPSAiY29uZGl0aW9uIikgKwogIFJvdGF0ZWRBeGlzKCkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50Mihsb3cgPSAibGlnaHRibHVlIiwgbWlkID0gInJlZCIsIGhpZ2ggPSAiZmlyZWJyaWNrIiwgbWlkcG9pbnQgPSAxKSArCiAgZ2d0aXRsZSgiRXhwcmVzc2lvbiBvZiBVcHJlZ3VsYXRlZCBHZW5lcyBpbiBTw6l6YXJ5IFN5bmRyb21lIikgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCBzaXplID0gMTIpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNCkKICApCgoKIyBEb3RQbG90IHdpdGggY3VzdG9tIGZpcmVicmljay1yZWQgZ3JhZGllbnQKRG90UGxvdChzc192c19oYywgZmVhdHVyZXMgPSB1cF9nZW5lcywgZ3JvdXAuYnkgPSAiY29uZGl0aW9uIikgKwogIFJvdGF0ZWRBeGlzKCkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50Mihsb3cgPSAibGlnaHRibHVlIiwgbWlkID0gInJlZCIsIGhpZ2ggPSAiZmlyZWJyaWNrIiwgbWlkcG9pbnQgPSAxKSArCiAgZ2d0aXRsZSgiRXhwcmVzc2lvbiBvZiBVcHJlZ3VsYXRlZCBHZW5lcyBpbiBTw6l6YXJ5IFN5bmRyb21lIikgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCBzaXplID0gMTIpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNCkpCgpgYGAKCiMjICAgVmlzdWFsaXphdGlvbiBvZiBQb3RlbnRpYWwgYmlvbWFya2Vycy1Eb3ducmVndWxhdGVkCmBgYHtyICwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9MTB9CgojIERvd25yZWd1bGF0ZWQgZ2VuZXMKZG93bl9nZW5lcyA8LSBjKCJUWE5JUCIsICJSQVNBMyIsICJSSVBPUjIiLCAKICAgICAgICAgICAgICAgICJaRlAzNiIsICJaRlAzNkwxIiwgIlpGUDM2TDIiLAogICAgICAgICAgICAgICAgIlBSTVQyIiwgIk1BWCIsICJQSUszSVAxIiwgCiAgICAgICAgICAgICAgICAiQlRHMSIsICJDREtOMUIiKQoKIyBEb3RQbG90IHdpdGggZmlyZWJyaWNrIGNvbG9yIGZvciBoaWdoIGV4cHJlc3Npb24KRG90UGxvdChzc192c19oYywgZmVhdHVyZXMgPSBkb3duX2dlbmVzKSArCiAgUm90YXRlZEF4aXMoKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQyKGxvdyA9ICJsaWdodGJsdWUiLCBtaWQgPSAicmVkIiwgaGlnaCA9ICJmaXJlYnJpY2siLCBtaWRwb2ludCA9IDEpICsKICBnZ3RpdGxlKCJFeHByZXNzaW9uIG9mIERvd25yZWd1bGF0ZWQgR2VuZXMgaW4gU8OpemFyeSBTeW5kcm9tZSIpICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgc2l6ZSA9IDEyKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLCBzaXplID0gMTQpCiAgKQoKIyBEb3RQbG90IHdpdGggZmlyZWJyaWNrIGNvbG9yIGZvciBoaWdoIGV4cHJlc3Npb24KRG90UGxvdChzc192c19oYywgZmVhdHVyZXMgPSBkb3duX2dlbmVzLCBncm91cC5ieSA9ICJzYW1wbGVfaWQiKSArCiAgUm90YXRlZEF4aXMoKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQyKGxvdyA9ICJsaWdodGJsdWUiLCBtaWQgPSAicmVkIiwgaGlnaCA9ICJmaXJlYnJpY2siLCBtaWRwb2ludCA9IDEpICsKICBnZ3RpdGxlKCJFeHByZXNzaW9uIG9mIERvd25yZWd1bGF0ZWQgR2VuZXMgaW4gU8OpemFyeSBTeW5kcm9tZSIpICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgc2l6ZSA9IDEyKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLCBzaXplID0gMTQpCiAgKQoKIyBEb3RQbG90IHdpdGggZmlyZWJyaWNrIGNvbG9yIGZvciBoaWdoIGV4cHJlc3Npb24KRG90UGxvdChzc192c19oYywgZmVhdHVyZXMgPSBkb3duX2dlbmVzLCBncm91cC5ieSA9ICJ0aXNzdWUiKSArCiAgUm90YXRlZEF4aXMoKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQyKGxvdyA9ICJsaWdodGJsdWUiLCBtaWQgPSAicmVkIiwgaGlnaCA9ICJmaXJlYnJpY2siLCBtaWRwb2ludCA9IDEpICsKICBnZ3RpdGxlKCJFeHByZXNzaW9uIG9mIERvd25yZWd1bGF0ZWQgR2VuZXMgaW4gU8OpemFyeSBTeW5kcm9tZSIpICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgc2l6ZSA9IDEyKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLCBzaXplID0gMTQpCiAgKQoKIyBEb3RQbG90IHdpdGggZmlyZWJyaWNrIGNvbG9yIGZvciBoaWdoIGV4cHJlc3Npb24KRG90UGxvdChzc192c19oYywgZmVhdHVyZXMgPSBkb3duX2dlbmVzLCBncm91cC5ieSA9ICJjb25kaXRpb24iKSArCiAgUm90YXRlZEF4aXMoKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQyKGxvdyA9ICJsaWdodGJsdWUiLCBtaWQgPSAicmVkIiwgaGlnaCA9ICJmaXJlYnJpY2siLCBtaWRwb2ludCA9IDEpICsKICBnZ3RpdGxlKCJFeHByZXNzaW9uIG9mIERvd25yZWd1bGF0ZWQgR2VuZXMgaW4gU8OpemFyeSBTeW5kcm9tZSIpICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgc2l6ZSA9IDEyKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLCBzaXplID0gMTQpCiAgKQoKYGBgCiMjICAgQ29tcGFyZSBjb25kaXRpb24gdXNpbmcgUk5BIGFzc2F5LXNzX3ZzX2hjCmBgYHtyICwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9Nn0KCiMgTG9hZCByZXF1aXJlZCBsaWJyYXJpZXMKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGliYmxlKQoKY29tYmluZWRfc2V1IDwtIHNzX3ZzX2hjCgojIEpvaW4gdGhlIGxheWVycyBvZiB0aGUgUk5BIGFzc2F5CmNvbWJpbmVkX3NldSA8LSBKb2luTGF5ZXJzKGNvbWJpbmVkX3NldSwgYXNzYXkgPSAiUk5BIikKCiMgRW5zdXJlIHlvdXIgaWRlbnRpdHkgY2xhc3MgaXMgc2V0IHRvIGRpc2Vhc2Ugc3RhdHVzCklkZW50cyhjb21iaW5lZF9zZXUpIDwtICJjb25kaXRpb24iICAjIGUuZy4sIGxldmVsczogIlNTIiwgIkNvbnRyb2wiCgojIFJ1biBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBiZXR3ZWVuIFNTIHZzIENvbnRyb2wKbWFya2Vyc19kaXNlYXNlIDwtIEZpbmRNYXJrZXJzKAogIG9iamVjdCA9IGNvbWJpbmVkX3NldSwKICBpZGVudC4xID0gIlNTIiwKICBpZGVudC4yID0gIkhlYWx0aHkiLAogIGFzc2F5ID0gIlJOQSIsCiAgbG9nZmMudGhyZXNob2xkID0gMCwKICBtaW4ucGN0ID0gMCwKICB0ZXN0LnVzZSA9ICJ3aWxjb3giICAKKQoKIyBTYXZlIHJlc3VsdHMgdG8gQ1NWCndyaXRlLmNzdihtYXJrZXJzX2Rpc2Vhc2UsIGZpbGUgPSAiREVfU1NfdnNfSGVhbHRoeV9IZXJyYXJhMjAyMS5jc3YiLCByb3cubmFtZXMgPSBUUlVFKQoKIyBHZXQgbG9nLW5vcm1hbGl6ZWQgZXhwcmVzc2lvbiBtYXRyaXggKFJOQSBhc3NheSkKZXhwcmVzc2lvbl9kYXRhX1JOQSA8LSBHZXRBc3NheURhdGEoY29tYmluZWRfc2V1LCBhc3NheSA9ICJSTkEiLCBzbG90ID0gImRhdGEiKQoKIyBHZXQgY2VsbCBuYW1lcyBmb3IgZWFjaCBncm91cApzc19jZWxscyA8LSBXaGljaENlbGxzKGNvbWJpbmVkX3NldSwgaWRlbnRzID0gIlNTIikKaGVhbHRoeV9jZWxscyA8LSBXaGljaENlbGxzKGNvbWJpbmVkX3NldSwgaWRlbnRzID0gIkhlYWx0aHkiKQoKIyBGdW5jdGlvbiB0byBhZGQgbWVhbiBleHByZXNzaW9uIHBlciBncm91cApjYWxjdWxhdGVfbWVhbl9leHByZXNzaW9uIDwtIGZ1bmN0aW9uKG1hcmtlcnMsIGdyb3VwMV9jZWxscywgZ3JvdXAyX2NlbGxzLCBleHByZXNzaW9uX2RhdGEpIHsKICBncm91cDFfbWVhbiA8LSByb3dNZWFucyhleHByZXNzaW9uX2RhdGFbLCBncm91cDFfY2VsbHMsIGRyb3AgPSBGQUxTRV0sIG5hLnJtID0gVFJVRSkKICBncm91cDJfbWVhbiA8LSByb3dNZWFucyhleHByZXNzaW9uX2RhdGFbLCBncm91cDJfY2VsbHMsIGRyb3AgPSBGQUxTRV0sIG5hLnJtID0gVFJVRSkKICBtYXJrZXJzIDwtIG1hcmtlcnMgJT4lCiAgICByb3duYW1lc190b19jb2x1bW4oImdlbmUiKSAlPiUKICAgIG11dGF0ZSgKICAgICAgbWVhbl9leHByX1NTID0gZ3JvdXAxX21lYW5bZ2VuZV0sCiAgICAgIG1lYW5fZXhwcl9IZWFsdGh5ID0gZ3JvdXAyX21lYW5bZ2VuZV0sCiAgICAgIGxvZzJGQ19tYW51YWwgPSBsb2cyKG1lYW5fZXhwcl9TUyArIDEpIC0gbG9nMihtZWFuX2V4cHJfSGVhbHRoeSArIDEpCiAgICApCiAgcmV0dXJuKG1hcmtlcnMpCn0KCiMgQXBwbHkgdGhlIGZ1bmN0aW9uIGFuZCBzYXZlIGZpbmFsIHJlc3VsdAptYXJrZXJzX2Rpc2Vhc2Vfd2l0aF9tZWFuIDwtIGNhbGN1bGF0ZV9tZWFuX2V4cHJlc3Npb24obWFya2Vyc19kaXNlYXNlLCBzc19jZWxscywgaGVhbHRoeV9jZWxscywgZXhwcmVzc2lvbl9kYXRhX1JOQSkKd3JpdGUuY3N2KG1hcmtlcnNfZGlzZWFzZV93aXRoX21lYW4sICJERV9TU192c19IZWFsdGh5X3dpdGhfTWVhbkV4cHJfSGVycmVyYTIwMjEuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCgpgYGAKCiMjICAgQ29tcGFyZSBjb25kaXRpb24gdXNpbmcgUk5BIGFzc2F5LU1lcmdlZCBzZXVyYXQKYGBge3IgLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD02fQoKIyBMb2FkIHJlcXVpcmVkIGxpYnJhcmllcwpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWJibGUpCgpjb21iaW5lZF9zZXUgPC0gbWVyZ2VkX3NldXJhdAoKIyBKb2luIHRoZSBsYXllcnMgb2YgdGhlIFJOQSBhc3NheQpjb21iaW5lZF9zZXUgPC0gSm9pbkxheWVycyhjb21iaW5lZF9zZXUsIGFzc2F5ID0gIlJOQSIpCgojIEVuc3VyZSB5b3VyIGlkZW50aXR5IGNsYXNzIGlzIHNldCB0byBkaXNlYXNlIHN0YXR1cwpJZGVudHMoY29tYmluZWRfc2V1KSA8LSAiY29uZGl0aW9uIiAgIyBlLmcuLCBsZXZlbHM6ICJTUyIsICJDb250cm9sIgoKIyBSdW4gZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYmV0d2VlbiBTUyB2cyBDb250cm9sCm1hcmtlcnNfZGlzZWFzZSA8LSBGaW5kTWFya2VycygKICBvYmplY3QgPSBjb21iaW5lZF9zZXUsCiAgaWRlbnQuMSA9ICJTUyIsCiAgaWRlbnQuMiA9ICJIZWFsdGh5IiwKICBhc3NheSA9ICJSTkEiLAogIGxvZ2ZjLnRocmVzaG9sZCA9IDAsCiAgbWluLnBjdCA9IDAsCiAgdGVzdC51c2UgPSAid2lsY294IiAgCikKCiMgU2F2ZSByZXN1bHRzIHRvIENTVgp3cml0ZS5jc3YobWFya2Vyc19kaXNlYXNlLCBmaWxlID0gIk1lcmdlZFNldXJhdF9ERV9TU192c19IZWFsdGh5X0hlcnJhcmEyMDIxLmNzdiIsIHJvdy5uYW1lcyA9IFRSVUUpCgojIEdldCBsb2ctbm9ybWFsaXplZCBleHByZXNzaW9uIG1hdHJpeCAoUk5BIGFzc2F5KQpleHByZXNzaW9uX2RhdGFfUk5BIDwtIEdldEFzc2F5RGF0YShjb21iaW5lZF9zZXUsIGFzc2F5ID0gIlJOQSIsIHNsb3QgPSAiZGF0YSIpCgojIEdldCBjZWxsIG5hbWVzIGZvciBlYWNoIGdyb3VwCnNzX2NlbGxzIDwtIFdoaWNoQ2VsbHMoY29tYmluZWRfc2V1LCBpZGVudHMgPSAiU1MiKQpoZWFsdGh5X2NlbGxzIDwtIFdoaWNoQ2VsbHMoY29tYmluZWRfc2V1LCBpZGVudHMgPSAiSGVhbHRoeSIpCgojIEZ1bmN0aW9uIHRvIGFkZCBtZWFuIGV4cHJlc3Npb24gcGVyIGdyb3VwCmNhbGN1bGF0ZV9tZWFuX2V4cHJlc3Npb24gPC0gZnVuY3Rpb24obWFya2VycywgZ3JvdXAxX2NlbGxzLCBncm91cDJfY2VsbHMsIGV4cHJlc3Npb25fZGF0YSkgewogIGdyb3VwMV9tZWFuIDwtIHJvd01lYW5zKGV4cHJlc3Npb25fZGF0YVssIGdyb3VwMV9jZWxscywgZHJvcCA9IEZBTFNFXSwgbmEucm0gPSBUUlVFKQogIGdyb3VwMl9tZWFuIDwtIHJvd01lYW5zKGV4cHJlc3Npb25fZGF0YVssIGdyb3VwMl9jZWxscywgZHJvcCA9IEZBTFNFXSwgbmEucm0gPSBUUlVFKQogIG1hcmtlcnMgPC0gbWFya2VycyAlPiUKICAgIHJvd25hbWVzX3RvX2NvbHVtbigiZ2VuZSIpICU+JQogICAgbXV0YXRlKAogICAgICBtZWFuX2V4cHJfU1MgPSBncm91cDFfbWVhbltnZW5lXSwKICAgICAgbWVhbl9leHByX0hlYWx0aHkgPSBncm91cDJfbWVhbltnZW5lXSwKICAgICAgbG9nMkZDX21hbnVhbCA9IGxvZzIobWVhbl9leHByX1NTICsgMSkgLSBsb2cyKG1lYW5fZXhwcl9IZWFsdGh5ICsgMSkKICAgICkKICByZXR1cm4obWFya2VycykKfQoKIyBBcHBseSB0aGUgZnVuY3Rpb24gYW5kIHNhdmUgZmluYWwgcmVzdWx0Cm1hcmtlcnNfZGlzZWFzZV93aXRoX21lYW4gPC0gY2FsY3VsYXRlX21lYW5fZXhwcmVzc2lvbihtYXJrZXJzX2Rpc2Vhc2UsIHNzX2NlbGxzLCBoZWFsdGh5X2NlbGxzLCBleHByZXNzaW9uX2RhdGFfUk5BKQp3cml0ZS5jc3YobWFya2Vyc19kaXNlYXNlX3dpdGhfbWVhbiwgIk1lcmdlZFNldXJhdF9ERV9TU192c19IZWFsdGh5X3dpdGhfTWVhbkV4cHJfSGVycmVyYTIwMjEuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCgpgYGAKCgojIyAgIFNhdmUgU2V1cmF0IG9iamVjdApgYGB7ciAsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTZ9Cgojc2F2ZVJEUyhzc192c19oYywgZmlsZSA9ICJTZXphcnlfQmxvb2RfU2tpbl92c19IQ19UQ1JfZmlsdGVyZWQucmRzIikKCmBgYAoKCgoKCgoKCg==