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

Separate blood and skin

# ================================
# 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)
  )

Save Seurat object


saveRDS(ss_vs_hc, file = "Sezary_Blood_Skin_vs_HC_TCR_filtered.rds")

saveRDS(ss_vs_hc_harmony, file = "Sezary_Blood_Skin_vs_HC_TCR_filtered.rds")
LS0tCnRpdGxlOiAiVENSICYgQ0xJQzEgQW5hbHlzaXMgaW4gU8OpemFyeSBTeW5kcm9tZShWYWxpZGF0aW9uIEhlcnJhcmEgZGF0YSIKYXV0aG9yOiBOYXNpciBNYWhtb29kIEFiYmFzaQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICAjcm1kZm9ybWF0czo6cmVhZHRoZWRvd24KICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRvY19jb2xsYXBzZWQ6IHRydWUKLS0tCiMgSW50cm9kdWN0aW9uCgpUaGlzIGFuYWx5c2lzIHZhbGlkYXRlcyBDTElDMSBhcyBhIGJpb21hcmtlciBpbiBTw6l6YXJ5IFN5bmRyb21lIHVzaW5nIHB1YmxpY2x5IGF2YWlsYWJsZSBzaW5nbGUtY2VsbCBSTkEtc2VxIGRhdGEgZnJvbSBIZXJyZXJhIGV0IGFsLiAoMjAyMSkuIFRoZSBkYXRhc2V0IGluY2x1ZGVzOgoKLSAqKkhlYWx0aHkgQ29udHJvbHMgKEhDKSoqOiAxIGRvbm9yLCBibG9vZCBhbmQgc2tpbgotICoqU8OpemFyeSBTeW5kcm9tZSAoU1MpKio6IDYgcGF0aWVudHMsIGJsb29kIMKxIHNraW4gc2FtcGxlcyAgCi0gKipNeWNvc2lzIEZ1bmdvaWRlcyAoTUYpKio6IDEgcGF0aWVudCwgYmxvb2QgYW5kIHNraW4KCioqUmVmZXJlbmNlKio6IEhlcnJlcmEgZXQgYWwuICgyMDIxKSAtIFBNQzg1MzIxOTkKCiBodHRwczovL3BtYy5uY2JpLm5sbS5uaWguZ292L2FydGljbGVzL1BNQzg1MzIxOTkvIAotLS0KCiMgbG9hZCBsaWJyYXJpZXMKYGBge3IgLCBpbmNsdWRlPUZBTFNFfQoKIyBDb3JlIHBhY2thZ2VzCmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpYmJsZSkKbGlicmFyeShnZ3Bsb3QyKQoKIyBTcGVjaWFsaXplZCBwYWNrYWdlcwpsaWJyYXJ5KHNjUmVwZXJ0b2lyZSkgICMgVENSIGFuYWx5c2lzCmxpYnJhcnkoZ2dwdWJyKSAgICAgICAgIyBTdGF0aXN0aWNhbCBwbG90dGluZwpsaWJyYXJ5KHJzdGF0aXgpICAgICAgICMgRWZmZWN0IHNpemVzCmxpYnJhcnkocGF0Y2h3b3JrKSAgICAgIyBDb21iaW5lIHBsb3RzCgojIFNldCB0aGVtZQp0aGVtZV9zZXQodGhlbWVfbWluaW1hbCgpKQoKIyBTdXBwcmVzcyB3YXJuaW5ncwpvcHRpb25zKHdhcm4gPSAtMSkKCmBgYAoKIyMgRGVmaW5lIEZpbGUgUGF0aHMKYGBge3IgcGF0aHN9CiMgQmFzZSBkaXJlY3RvcnkKYmFzZV9kaXIgPC0gIi9ob21lL2Jpb2luZm8vMS1UaGVzaXNfRmluYWxfWWVhcl8yMDI1LzIwMjUtRmluYWxfWWVhcl9SZXN1bHRzLzIwMjUtWWVhcjNfQW5hbHlzaXMvQmlvbWFya2Vyc19WYWxpZGF0aW9uX3dpdGhfUHVibGljX0RhdGEvSGVycmVyYV9EYXRhLyIKCiMgU2V1cmF0IG9iamVjdApzZXVyYXRfZmlsZSA8LSBmaWxlLnBhdGgoYmFzZV9kaXIsICJIZXJyYXJhX0FsbF9zYW1wbGVzLnJkcyIpCgojIFRDUiBkYXRhIGRpcmVjdG9yeQp0Y3JfZGlyIDwtIGZpbGUucGF0aChiYXNlX2RpciwgIkhlcnJhcmFfVENSX0FCIikKCiMgT3V0cHV0IGRpcmVjdG9yeQpvdXRwdXRfZGlyIDwtICJvdXRwdXQiCmRpci5jcmVhdGUob3V0cHV0X2Rpciwgc2hvd1dhcm5pbmdzID0gRkFMU0UpCmBgYAoKLS0tCgoKIyMgTG9hZCBTZXVyYXQgT2JqZWN0CmBgYHtyIGxvYWRfc2V1cmF0LCBtZXNzYWdlPUZBTFNFfQpjYXQoIkxvYWRpbmcgU2V1cmF0IG9iamVjdC4uLlxuIikKbWVyZ2VkX3NldXJhdCA8LSByZWFkUkRTKHNldXJhdF9maWxlKQoKY2F0KCJEYXRhc2V0IGRpbWVuc2lvbnM6XG4iKQpjYXQoc3ByaW50ZigiICAtIENlbGxzOiAlZFxuIiwgbmNvbChtZXJnZWRfc2V1cmF0KSkpCmNhdChzcHJpbnRmKCIgIC0gR2VuZXM6ICVkXG4iLCBucm93KG1lcmdlZF9zZXVyYXQpKSkKY2F0KHNwcmludGYoIiAgLSBTYW1wbGVzOiAlc1xuIiwgcGFzdGUodW5pcXVlKG1lcmdlZF9zZXVyYXQkc2FtcGxlX2lkKSwgY29sbGFwc2UgPSAiLCAiKSkpCmBgYAoKIyMgTG9hZCBUQ1IgRGF0YQpgYGB7ciBsb2FkX3RjciwgbWVzc2FnZT1GQUxTRX0KIyBMb2FkIGFsbCBmaWxlcywgcmVzaGFwZSBmcm9tIHdpZGUgdG8gbG9uZyBmb3JtYXQKbGlicmFyeSh0aWR5cikKbGlicmFyeShkcGx5cikKbGlicmFyeShyZWFkcikKCiMgRGVmaW5lIFRDUiBmaWxlIHBhdGhzIChnemlwcGVkKQojIERlZmluZSBUQ1IgZmlsZSBwYXRocyB3aXRoIGZ1bGwgcGF0aHMKCnRjcl9maWxlcyA8LSBsaXN0KApIQzFfQmxvb2QgPSBmaWxlLnBhdGgodGNyX2RpciwgIkdTTTUyMzQ1NzZfSEMxX0Jsb29kX2Nsb25vdHlwZUFCLnRzdi5neiIpLApIQzFfU2tpbiAgPSBmaWxlLnBhdGgodGNyX2RpciwgIkdTTTUyMzQ1NzdfSEMxX1NraW5fY2xvbm90eXBlQUIudHN2Lmd6IiksClNTMV9CbG9vZCA9IGZpbGUucGF0aCh0Y3JfZGlyLCAiR1NNNTIzNDU3OF9TUzFfQmxvb2RfY2xvbm90eXBlQUIudHN2Lmd6IiksClNTMV9Ta2luICA9IGZpbGUucGF0aCh0Y3JfZGlyLCAiR1NNNTIzNDU3OV9TUzFfU2tpbl9jbG9ub3R5cGVBQi50c3YuZ3oiKSwKU1MyX0Jsb29kID0gZmlsZS5wYXRoKHRjcl9kaXIsICJHU001MjM0NTgwX1NTMl9CbG9vZF9jbG9ub3R5cGVBQi50c3YuZ3oiKSwKU1MyX1NraW4gID0gZmlsZS5wYXRoKHRjcl9kaXIsICJHU001MjM0NTgxX1NTMl9Ta2luX2Nsb25vdHlwZUFCLnRzdi5neiIpLApTUzNfQmxvb2QgPSBmaWxlLnBhdGgodGNyX2RpciwgIkdTTTUyMzQ1ODJfU1MzX0Jsb29kX2Nsb25vdHlwZUFCLnRzdi5neiIpLApTUzNfU2tpbiAgPSBmaWxlLnBhdGgodGNyX2RpciwgIkdTTTUyMzQ1ODNfU1MzX1NraW5fY2xvbm90eXBlQUIudHN2Lmd6IiksClNTNF9CbG9vZCA9IGZpbGUucGF0aCh0Y3JfZGlyLCAiR1NNNTIzNDU4NF9TUzRfQmxvb2RfY2xvbm90eXBlQUIudHN2Lmd6IiksClNTNF9Ta2luICA9IGZpbGUucGF0aCh0Y3JfZGlyLCAiR1NNNTIzNDU4NV9TUzRfU2tpbl9jbG9ub3R5cGVBQi50c3YuZ3oiKSwKTUZJVjFfQmxvb2QgPSBmaWxlLnBhdGgodGNyX2RpciwgIkdTTTUyMzQ1ODZfTUZJVjFfQmxvb2RfY2xvbm90eXBlQUIudHN2Lmd6IiksCk1GSVYxX1NraW4gID0gZmlsZS5wYXRoKHRjcl9kaXIsICJHU001MjM0NTg3X01GSVYxX1NraW5fY2xvbm90eXBlQUIudHN2Lmd6IiksClNTNV9CbG9vZCAgID0gZmlsZS5wYXRoKHRjcl9kaXIsICJHU001MjM0NTg4X1NTNV9CbG9vZF9jbG9ub3R5cGVBQi50c3YuZ3oiKSwKU1M2X0Jsb29kICAgPSBmaWxlLnBhdGgodGNyX2RpciwgIkdTTTUyMzQ1ODlfU1M2X0Jsb29kX2Nsb25vdHlwZUFCLnRzdi5neiIpCikKCmNhdCgiTG9hZGluZyBnemlwcGVkIFRDUiBjbG9ub3R5cGUgZmlsZXMuLi5cbiIpCgojIFJlYWQgYW5kIGNvbnZlcnQgZWFjaCBmaWxlIGZyb20gd2lkZSB0byBsb25nIGZvcm1hdAoKdGNyX2xpc3QgPC0gbGFwcGx5KG5hbWVzKHRjcl9maWxlcyksIGZ1bmN0aW9uKHNhbXBsZV9uYW1lKSB7CmNhdCgiUmVhZGluZzoiLCBzYW1wbGVfbmFtZSwgIlxuIikKZGYgPC0gcmVhZC5kZWxpbShnemZpbGUodGNyX2ZpbGVzW1tzYW1wbGVfbmFtZV1dKSwgY2hlY2submFtZXMgPSBGQUxTRSkKY29sbmFtZXMoZGYpWzFdIDwtICJjbG9ub3R5cGUiCgpkZl9sb25nIDwtIGRmICU+JQpwaXZvdF9sb25nZXIoCmNvbHMgPSAtY2xvbm90eXBlLApuYW1lc190byA9ICJjZWxsX2JhcmNvZGUiLAp2YWx1ZXNfdG8gPSAiY291bnQiCikgJT4lCmZpbHRlcihjb3VudCA+IDApICU+JQptdXRhdGUoc2FtcGxlX2lkID0gc2FtcGxlX25hbWUpCgpyZXR1cm4oZGZfbG9uZykKfSkKCmNvbWJpbmVkX3RjciA8LSBiaW5kX3Jvd3ModGNyX2xpc3QpCmNhdCgiVG90YWwgcHJvZHVjdGl2ZSBUQ1IgYXNzaWdubWVudHM6IiwgbnJvdyhjb21iaW5lZF90Y3IpLCAiXG4iKQoKCmBgYAoKIyAqKkNMSUMxIFZBTElEQVRJT04qKgojIyAgSW50ZWdyYXRlIFRDUiB3aXRoIFNldXJhdApgYGB7ciAsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTZ9CmxpYnJhcnkoc3RyaW5ncikKCiMgRXh0cmFjdCBhbHBoYSBhbmQgYmV0YSBjaGFpbnMgZnJvbSBjbG9ub3R5cGUKY29tYmluZWRfdGNyIDwtIGNvbWJpbmVkX3RjciAlPiUKICBtdXRhdGUoCiAgICBUQ1JfYWxwaGEgPSBzdHJfZXh0cmFjdChjbG9ub3R5cGUsICIoPzw9VFJBOilbXnxdKyIpLAogICAgVENSX2JldGEgID0gc3RyX2V4dHJhY3QoY2xvbm90eXBlLCAiKD88PVRSQjopW158XSsiKQogICkKIyBNYWtlIGNlbGxfYmFyY29kZSBtYXRjaCBTZXVyYXQgb2JqZWN0CmNvbWJpbmVkX3RjciA8LSBjb21iaW5lZF90Y3IgJT4lCiAgbXV0YXRlKGNlbGxfYmFyY29kZSA9IHBhc3RlMChzYW1wbGVfaWQsICJfIiwgY2VsbF9iYXJjb2RlKSkKCiMgS2VlcCBvbmx5IGNlbGxzIHByZXNlbnQgaW4gU2V1cmF0CnRjcl9pbl9zZXVyYXQgPC0gY29tYmluZWRfdGNyW2NvbWJpbmVkX3RjciRjZWxsX2JhcmNvZGUgJWluJSBjb2xuYW1lcyhtZXJnZWRfc2V1cmF0KSwgXQoKIyBDcmVhdGUgYSBtZXRhZGF0YSB0YWJsZSBmb3IgU2V1cmF0CnRjcl9tZXRhIDwtIHRjcl9pbl9zZXVyYXQgJT4lCiAgc2VsZWN0KGNlbGxfYmFyY29kZSwgY2xvbm90eXBlLCBUQ1JfYWxwaGEsIFRDUl9iZXRhKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXMoImNlbGxfYmFyY29kZSIpCgptZXJnZWRfc2V1cmF0IDwtIEFkZE1ldGFEYXRhKG1lcmdlZF9zZXVyYXQsIG1ldGFkYXRhID0gdGNyX21ldGEpCgpgYGAKCgoKCiMjICBJZGVudGlmeSBleHBhbmRlZCBtYWxpZ25hbnQgVCBjZWxscyAKYGBge3IgLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD02fQojID09PT09PT09PT09PT09PT09PT09PT09PT0KIyBJZGVudGlmeSBleHBhbmRlZCBtYWxpZ25hbnQgVCBjZWxscyBwZXIgU1Mgc2FtcGxlIHVzaW5nIHNjUmVwZXJ0b2lyZQojID09PT09PT09PT09PT09PT09PT09PT09PT0KCnNzX3NhbXBsZXMgPC0gYygiU1MxX0Jsb29kIiwgIlNTMV9Ta2luIiwgIlNTMl9CbG9vZCIsICJTUzJfU2tpbiIsCiAgICAgICAgICAgICAgICAiU1MzX0Jsb29kIiwgIlNTM19Ta2luIiwgIlNTNF9CbG9vZCIsICJTUzRfU2tpbiIsCiAgICAgICAgICAgICAgICAiU1M1X0Jsb29kIiwgIlNTNl9CbG9vZCIpCgptYWxpZ25hbnRfY2VsbHNfbGlzdCA8LSBsaXN0KCkKCmZvciAocyBpbiBzc19zYW1wbGVzKSB7CiAgc2FtcGxlX2NlbGxzIDwtIHN1YnNldChtZXJnZWRfc2V1cmF0LCBzdWJzZXQgPSBzYW1wbGVfaWQgPT0gcykKICAKICAjIFNraXAgc2FtcGxlIGlmIG5vIFRDUl9iZXRhCiAgaWYgKCEiVENSX2JldGEiICVpbiUgY29sbmFtZXMoc2FtcGxlX2NlbGxzQG1ldGEuZGF0YSkpIG5leHQKICAKICBjbG9ub3R5cGVfY291bnRzIDwtIHRhYmxlKHNhbXBsZV9jZWxscyRUQ1JfYmV0YSkKICBleHBhbmRlZF9jbG9uZXMgPC0gbmFtZXMoY2xvbm90eXBlX2NvdW50c1tjbG9ub3R5cGVfY291bnRzID49IDVdKQogIAogICMgU2tpcCBpZiBubyBleHBhbmRlZCBjbG9uZXMKICBpZiAobGVuZ3RoKGV4cGFuZGVkX2Nsb25lcykgPT0gMCkgbmV4dAogIAogIG1hbGlnbmFudCA8LSBzdWJzZXQoc2FtcGxlX2NlbGxzLCBzdWJzZXQgPSBUQ1JfYmV0YSAlaW4lIGV4cGFuZGVkX2Nsb25lcykKICAKICAjIE9ubHkgYWRkIGlmIHRoZXJlIGFyZSBjZWxscwogIGlmIChuY29sKG1hbGlnbmFudCkgPiAwKSBtYWxpZ25hbnRfY2VsbHNfbGlzdFtbc11dIDwtIG1hbGlnbmFudAp9CgojID09PT09PT09PT09PT09PT09PT09PT09PT0KIyBNZXJnZSBhbGwgbWFsaWduYW50IFNTIGNlbGxzIChyb2J1c3QpCiMgPT09PT09PT09PT09PT09PT09PT09PT09PQptYWxpZ25hbnRfY2VsbHNfbGlzdCA8LSBtYWxpZ25hbnRfY2VsbHNfbGlzdFshc2FwcGx5KG1hbGlnbmFudF9jZWxsc19saXN0LCBpcy5udWxsKV0gIyByZW1vdmUgTlVMTHMKbWFsaWduYW50X2NlbGxzX2xpc3QgPC0gdW5uYW1lKG1hbGlnbmFudF9jZWxsc19saXN0KSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHJlbW92ZSBuYW1lcwpzZXphcnlfY2VsbHMgPC0gUmVkdWNlKGZ1bmN0aW9uKHgsIHkpIG1lcmdlKHgsIHkpLCBtYWxpZ25hbnRfY2VsbHNfbGlzdCkgICAgICAgICAgICAgIyBtZXJnZSBhbGwKCgpgYGAKCgojIyAgaGlnaGxpZ2h0IHRvcCBjbG9uZXMKYGBge3IgLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD02fQoKbGlicmFyeShzY1JlcGVydG9pcmUpCmxpYnJhcnkoU2V1cmF0KQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIENsb25hbCBob21lb3N0YXNpcyAoc2l6ZSBkaXN0cmlidXRpb24pCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KY2xvbmFsSG9tZW9zdGFzaXMoc2V6YXJ5X2NlbGxzLCBjbG9uZUNhbGwgPSAiY2xvbm90eXBlIikKCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyAgQ2xvbmFsIHByb3BvcnRpb24gLyByZWxhdGl2ZSBhYnVuZGFuY2UKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQpjbG9uYWxQcm9wb3J0aW9uKHNlemFyeV9jZWxscywgY2xvbmVDYWxsID0gImNsb25vdHlwZSIpCgoKYGBgCiMjICBoaWdobGlnaHQgdG9wIGNsb25lcwpgYGB7ciAsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTEyfQpsaWJyYXJ5KHNjUmVwZXJ0b2lyZSkKCmNsb25hbE92ZXJsYXAoc2V6YXJ5X2NlbGxzLCBjbG9uZUNhbGwgPSAiY2xvbm90eXBlIiwgZ3JvdXAuYnkgPSAic2FtcGxlX2lkIiwgbWV0aG9kID0gIm1vcmlzaXRhIikKCgpgYGAKCgoKCiMjICBTZXBhcmF0ZSBibG9vZCBhbmQgc2tpbgpgYGB7ciAsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTZ9CiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyBNZXJnZSBhbGwgU8OpemFyeSBtYWxpZ25hbnQgY2VsbHMgd2l0aCBoZWFsdGh5IGNvbnRyb2xzCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyBFbnN1cmUgUk5BIGFzc2F5CkRlZmF1bHRBc3NheShzZXphcnlfY2VsbHMpIDwtICJSTkEiCgojIE5vcm1hbGl6ZSBhbmQgaWRlbnRpZnkgdmFyaWFibGUgZmVhdHVyZXMKc2V6YXJ5X2NlbGxzIDwtIE5vcm1hbGl6ZURhdGEoc2V6YXJ5X2NlbGxzLCBub3JtYWxpemF0aW9uLm1ldGhvZCA9ICJMb2dOb3JtYWxpemUiLCBzY2FsZS5mYWN0b3IgPSAxMDAwMCkKc2V6YXJ5X2NlbGxzIDwtIEZpbmRWYXJpYWJsZUZlYXR1cmVzKHNlemFyeV9jZWxscywgc2VsZWN0aW9uLm1ldGhvZCA9ICJ2c3QiLCBuZmVhdHVyZXMgPSAyMDAwKQpzZXphcnlfY2VsbHMgPC0gU2NhbGVEYXRhKHNlemFyeV9jZWxscykKc2V6YXJ5X2NlbGxzIDwtIFJ1blBDQShzZXphcnlfY2VsbHMsIG5wY3MgPSAyMCkKCiMgU3Vic2V0IGhlYWx0aHkgY29udHJvbCBjZWxscwpoY19jZWxscyA8LSBzdWJzZXQobWVyZ2VkX3NldXJhdCwgc3Vic2V0ID0gc2FtcGxlX2lkICVpbiUgYygiSGVhbHRoeV9CbG9vZCIsICJIZWFsdGh5X1NraW4iKSkKCiMgTWVyZ2UgYWxsIHRvZ2V0aGVyCnNzX3ZzX2hjIDwtIG1lcmdlKAogIHggPSBzZXphcnlfY2VsbHMsCiAgeSA9IGhjX2NlbGxzLAogIGFkZC5jZWxsLmlkcyA9IGMoIlNTIiwgIkhDIikKKQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIE5vcm1hbGl6ZSwgZmluZCB2YXJpYWJsZSBmZWF0dXJlcywgc2NhbGUsIGFuZCBydW4gUENBICYgVU1BUCBvbiBtZXJnZWQgb2JqZWN0CiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KRGVmYXVsdEFzc2F5KHNzX3ZzX2hjKSA8LSAiUk5BIgpzc192c19oYyA8LSBOb3JtYWxpemVEYXRhKHNzX3ZzX2hjLCBub3JtYWxpemF0aW9uLm1ldGhvZCA9ICJMb2dOb3JtYWxpemUiLCBzY2FsZS5mYWN0b3IgPSAxMDAwMCkKc3NfdnNfaGMgPC0gRmluZFZhcmlhYmxlRmVhdHVyZXMoc3NfdnNfaGMsIHNlbGVjdGlvbi5tZXRob2QgPSAidnN0IiwgbmZlYXR1cmVzID0gMjAwMCkKc3NfdnNfaGMgPC0gU2NhbGVEYXRhKHNzX3ZzX2hjKQpzc192c19oYyA8LSBSdW5QQ0Eoc3NfdnNfaGMsIG5wY3MgPSAyMCkKc3NfdnNfaGMgPC0gUnVuVU1BUChzc192c19oYywgZGltcyA9IDE6MjApCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgQWRkIHRpc3N1ZSBncm91cGluZyBjb2x1bW4KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQpzc192c19oYyR0aXNzdWVfZ3JvdXAgPC0gY2FzZV93aGVuKAogIGdyZXBsKCJCbG9vZCIsIHNzX3ZzX2hjJHNhbXBsZV9pZCwgaWdub3JlLmNhc2UgPSBUUlVFKSB+ICJCbG9vZCIsCiAgZ3JlcGwoIlNraW4iLCBzc192c19oYyRzYW1wbGVfaWQsIGlnbm9yZS5jYXNlID0gVFJVRSkgfiAiU2tpbiIsCiAgVFJVRSB+ICJPdGhlciIKKQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIFZpc3VhbGl6ZSBDTElDMSBleHByZXNzaW9uCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCiMgRmVhdHVyZVBsb3Qgd2l0aCByZWQgZ3JhZGllbnQKRmVhdHVyZVBsb3Qoc3NfdnNfaGMsIGZlYXR1cmVzID0gIkNMSUMxIiwgcmVkdWN0aW9uID0gInVtYXAiLAogICAgICAgICAgICBjb2xzID0gYygiZ3JleTkwIiwgInJlZCIpLCBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVCkKCiMgRG90UGxvdCBieSBzYW1wbGVfaWQgd2l0aCByZWQtZ3JleSBncmFkaWVudApEb3RQbG90KHNzX3ZzX2hjLCBmZWF0dXJlcyA9ICJDTElDMSIsIGdyb3VwLmJ5ID0gInNhbXBsZV9pZCIpICsKICBSb3RhdGVkQXhpcygpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3cgPSAiZ3JleTkwIiwgaGlnaCA9ICJyZWQiKSArCiAgZ2d0aXRsZSgiQ0xJQzEgRXhwcmVzc2lvbiBieSBTYW1wbGUiKSArCiAgdGhlbWUoCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHNpemUgPSAxMiksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE0KQogICkKCiMgRG90UGxvdCBieSB0aXNzdWVfZ3JvdXAgd2l0aCByZWQtZ3JleSBncmFkaWVudApEb3RQbG90KHNzX3ZzX2hjLCBmZWF0dXJlcyA9ICJDTElDMSIsIGdyb3VwLmJ5ID0gInRpc3N1ZV9ncm91cCIpICsKICBSb3RhdGVkQXhpcygpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3cgPSAiZ3JleTkwIiwgaGlnaCA9ICJyZWQiKSArCiAgZ2d0aXRsZSgiQ0xJQzEgRXhwcmVzc2lvbiBieSBUaXNzdWUiKSArCiAgdGhlbWUoCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHNpemUgPSAxMiksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE0KQogICkKCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyBWaXN1YWxpemUgQ0xJQzEKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIEZlYXR1cmVQbG90CkZlYXR1cmVQbG90KHNzX3ZzX2hjLCBmZWF0dXJlcyA9ICJDTElDMSIsIHJlZHVjdGlvbiA9ICJ1bWFwIikKCiMgRG90UGxvdCBncm91cGVkIGJ5IHNhbXBsZQpEb3RQbG90KHNzX3ZzX2hjLCBmZWF0dXJlcyA9ICJDTElDMSIsIGdyb3VwLmJ5ID0gInNhbXBsZV9pZCIpICsgUm90YXRlZEF4aXMoKQoKIyBEb3RQbG90IGdyb3VwZWQgYnkgdGlzc3VlCkRvdFBsb3Qoc3NfdnNfaGMsIGZlYXR1cmVzID0gIkNMSUMxIiwgZ3JvdXAuYnkgPSAidGlzc3VlX2dyb3VwIikgKyBSb3RhdGVkQXhpcygpCgpgYGAKCgoKIyMgICAgVmlzdWFsaXplIENMSUMxCmBgYHtyICwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9Nn0KCiMgRGltUGxvdCBieSBzYW1wbGUKRGltUGxvdChzc192c19oYywgZ3JvdXAuYnkgPSAic2FtcGxlX2lkIiwgcmVkdWN0aW9uID0gInVtYXAiKQoKIyBGZWF0dXJlUGxvdCBmb3IgQ0xJQzEKRmVhdHVyZVBsb3Qoc3NfdnNfaGMsIGZlYXR1cmVzID0gIkNMSUMxIiwgcmVkdWN0aW9uID0gInVtYXAiKQoKIyBEb3RQbG90IGZvciBDTElDMSBhY3Jvc3MgZ3JvdXBzCkRvdFBsb3Qoc3NfdnNfaGMsIGZlYXR1cmVzID0gIkNMSUMxIiwgZ3JvdXAuYnkgPSAic2FtcGxlX2lkIikgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQoKIyBGZWF0dXJlUGxvdCB3aXRoIHJlZCBncmFkaWVudApGZWF0dXJlUGxvdChzc192c19oYywgZmVhdHVyZXMgPSAiQ0xJQzEiLCByZWR1Y3Rpb24gPSAidW1hcCIsCiAgICAgICAgICAgIGNvbHMgPSBjKCJncmV5OTAiLCAicmVkIiksIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUKQoKYGBgCiMjICAgRmVhdHVyZVBsb3RzIGZvciBUb3A1MCBVUApgYGB7ciAsIGZpZy5oZWlnaHQ9MTIsIGZpZy53aWR0aD0xNn0KdG9wXzUwX3VwIDwtIHJlYWQuY3N2KCJ0b3BfNTBfdXByZWd1bGF0ZWQuY3N2IikgICAgICAgICMgb3IgcmVhZC5kZWxpbSgidG9wXzUwX3VwLnRzdiIpCnRvcF81MF9kb3duIDwtIHJlYWQuY3N2KCJ0b3BfNTBfZG93bnJlZ3VsYXRlZC5jc3YiKQoKCgpGZWF0dXJlUGxvdChzc192c19oYywgCiAgICAgICAgICAgICBmZWF0dXJlcyA9IHRvcF81MF91cCRnZW5lWzE6MTBdLCAKICAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwgCiAgICAgICAgICAgICBjb2xzID0gYygibGlnaHRibHVlIiwgInJlZCIpLCAgIyBDdXN0b20gY29sb3IgZ3JhZGllbnQgZnJvbSBsaWdodCBibHVlIHRvIHJlZAogICAgICAgICAgICAgbGFiZWwgPSBUUlVFKQoKCkZlYXR1cmVQbG90KHNzX3ZzX2hjLCAKICAgICAgICAgICAgIGZlYXR1cmVzID0gdG9wXzUwX3VwJGdlbmVbMTE6MjBdLCAKICAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwgCiAgICAgICAgICAgICBjb2xzID0gYygibGlnaHRibHVlIiwgInJlZCIpLCAgIyBDdXN0b20gY29sb3IgZ3JhZGllbnQgZnJvbSBsaWdodCBibHVlIHRvIHJlZAogICAgICAgICAgICAgbGFiZWwgPSBUUlVFKQoKRmVhdHVyZVBsb3Qoc3NfdnNfaGMsIAogICAgICAgICAgICAgZmVhdHVyZXMgPSB0b3BfNTBfdXAkZ2VuZVsyMTozMF0sIAogICAgICAgICAgICAgcmVkdWN0aW9uID0gInVtYXAiLCAKICAgICAgICAgICAgIGNvbHMgPSBjKCJsaWdodGJsdWUiLCAicmVkIiksICAjIEN1c3RvbSBjb2xvciBncmFkaWVudCBmcm9tIGxpZ2h0IGJsdWUgdG8gcmVkCiAgICAgICAgICAgICBsYWJlbCA9IFRSVUUpCgpGZWF0dXJlUGxvdChzc192c19oYywgCiAgICAgICAgICAgICBmZWF0dXJlcyA9IHRvcF81MF91cCRnZW5lWzMxOjQwXSwgCiAgICAgICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsIAogICAgICAgICAgICAgY29scyA9IGMoImxpZ2h0Ymx1ZSIsICJyZWQiKSwgICMgQ3VzdG9tIGNvbG9yIGdyYWRpZW50IGZyb20gbGlnaHQgYmx1ZSB0byByZWQKICAgICAgICAgICAgIGxhYmVsID0gVFJVRSkKCkZlYXR1cmVQbG90KHNzX3ZzX2hjLCAKICAgICAgICAgICAgIGZlYXR1cmVzID0gdG9wXzUwX3VwJGdlbmVbNDE6NTBdLCAKICAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwgCiAgICAgICAgICAgICBjb2xzID0gYygibGlnaHRibHVlIiwgInJlZCIpLCAgIyBDdXN0b20gY29sb3IgZ3JhZGllbnQgZnJvbSBsaWdodCBibHVlIHRvIHJlZAogICAgICAgICAgICAgbGFiZWwgPSBUUlVFKQoKYGBgCgoKIyMgICBGZWF0dXJlUGxvdHMgZm9yIFRvcDUwIERPV04KYGBge3IgLCBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTZ9CgpGZWF0dXJlUGxvdChzc192c19oYywgCiAgICAgICAgICAgICBmZWF0dXJlcyA9IHRvcF81MF9kb3duJGdlbmVbMToxMF0sIAogICAgICAgICAgICAgcmVkdWN0aW9uID0gInVtYXAiLCAKICAgICAgICAgICAgIGNvbHMgPSBjKCJsaWdodGJsdWUiLCAicmVkIiksICAjIEN1c3RvbSBjb2xvciBncmFkaWVudCBmcm9tIGxpZ2h0IGJsdWUgdG8gcmVkCiAgICAgICAgICAgICBsYWJlbCA9IFRSVUUpCgpGZWF0dXJlUGxvdChzc192c19oYywgCiAgICAgICAgICAgICBmZWF0dXJlcyA9IHRvcF81MF9kb3duJGdlbmVbMTE6MjBdLCAKICAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwgCiAgICAgICAgICAgICBjb2xzID0gYygibGlnaHRibHVlIiwgInJlZCIpLCAgIyBDdXN0b20gY29sb3IgZ3JhZGllbnQgZnJvbSBsaWdodCBibHVlIHRvIHJlZAogICAgICAgICAgICAgbGFiZWwgPSBUUlVFKQoKRmVhdHVyZVBsb3Qoc3NfdnNfaGMsIAogICAgICAgICAgICAgZmVhdHVyZXMgPSB0b3BfNTBfZG93biRnZW5lWzIxOjMwXSwgCiAgICAgICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsIAogICAgICAgICAgICAgY29scyA9IGMoImxpZ2h0Ymx1ZSIsICJyZWQiKSwgICMgQ3VzdG9tIGNvbG9yIGdyYWRpZW50IGZyb20gbGlnaHQgYmx1ZSB0byByZWQKICAgICAgICAgICAgIGxhYmVsID0gVFJVRSkKCkZlYXR1cmVQbG90KHNzX3ZzX2hjLCAKICAgICAgICAgICAgIGZlYXR1cmVzID0gdG9wXzUwX2Rvd24kZ2VuZVszMTo0MF0sIAogICAgICAgICAgICAgcmVkdWN0aW9uID0gInVtYXAiLCAKICAgICAgICAgICAgIGNvbHMgPSBjKCJsaWdodGJsdWUiLCAicmVkIiksICAjIEN1c3RvbSBjb2xvciBncmFkaWVudCBmcm9tIGxpZ2h0IGJsdWUgdG8gcmVkCiAgICAgICAgICAgICBsYWJlbCA9IFRSVUUpCgpGZWF0dXJlUGxvdChzc192c19oYywgCiAgICAgICAgICAgICBmZWF0dXJlcyA9IHRvcF81MF9kb3duJGdlbmVbNDE6NTBdLCAKICAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwgCiAgICAgICAgICAgICBjb2xzID0gYygibGlnaHRibHVlIiwgInJlZCIpLCAgIyBDdXN0b20gY29sb3IgZ3JhZGllbnQgZnJvbSBsaWdodCBibHVlIHRvIHJlZAogICAgICAgICAgICAgbGFiZWwgPSBUUlVFKQoKCiAgCmBgYAoKIyMgICBWaXN1YWxpemF0aW9uIG9mIFBvdGVudGlhbCBiaW9tYXJrZXJzLVVwcmVndWxhdGVkCmBgYHtyICwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9MTB9CgojIFZlY3RvciBvZiBnZW5lcyB0byBwbG90CnVwX2dlbmVzIDwtIGMoIkNMSUMxIiwgIkNPWDVBIiwiR1RTRjEiLCAiTUFEMkwxIiwiTVlCTDIiLCJNWUw2QiIsIk5NRTEiLCJQTEsxIiwgIlBZQ1IxIiwgIlNMQzI1QTUiLCAiU1JJIiwgIlRVQkExQyIsICJVQkUyVCIsICJZV0hBSCIpCgojIERvdFBsb3Qgd2l0aCBjdXN0b20gZmlyZWJyaWNrLXJlZCBncmFkaWVudApEb3RQbG90KHNzX3ZzX2hjLCBmZWF0dXJlcyA9IHVwX2dlbmVzKSArCiAgUm90YXRlZEF4aXMoKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQyKGxvdyA9ICJsaWdodGJsdWUiLCBtaWQgPSAicmVkIiwgaGlnaCA9ICJmaXJlYnJpY2siLCBtaWRwb2ludCA9IDEpICsKICBnZ3RpdGxlKCJFeHByZXNzaW9uIG9mIFVwcmVndWxhdGVkIEdlbmVzIGluIFPDqXphcnkgU3luZHJvbWUiKSArCiAgdGhlbWUoCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHNpemUgPSAxMiksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE0KQogICkKCiMgRG90UGxvdCB3aXRoIGN1c3RvbSBmaXJlYnJpY2stcmVkIGdyYWRpZW50CkRvdFBsb3Qoc3NfdnNfaGMsIGZlYXR1cmVzID0gdXBfZ2VuZXMsIGdyb3VwLmJ5ID0gInNhbXBsZV9pZCIpICsKICBSb3RhdGVkQXhpcygpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudDIobG93ID0gImxpZ2h0Ymx1ZSIsIG1pZCA9ICJyZWQiLCBoaWdoID0gImZpcmVicmljayIsIG1pZHBvaW50ID0gMSkgKwogIGdndGl0bGUoIkV4cHJlc3Npb24gb2YgVXByZWd1bGF0ZWQgR2VuZXMgaW4gU8OpemFyeSBTeW5kcm9tZSIpICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgc2l6ZSA9IDEyKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLCBzaXplID0gMTQpCiAgKQoKIyBEb3RQbG90IHdpdGggY3VzdG9tIGZpcmVicmljay1yZWQgZ3JhZGllbnQKRG90UGxvdChzc192c19oYywgZmVhdHVyZXMgPSB1cF9nZW5lcywgZ3JvdXAuYnkgPSAidGlzc3VlIikgKwogIFJvdGF0ZWRBeGlzKCkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50Mihsb3cgPSAibGlnaHRibHVlIiwgbWlkID0gInJlZCIsIGhpZ2ggPSAiZmlyZWJyaWNrIiwgbWlkcG9pbnQgPSAxKSArCiAgZ2d0aXRsZSgiRXhwcmVzc2lvbiBvZiBVcHJlZ3VsYXRlZCBHZW5lcyBpbiBTw6l6YXJ5IFN5bmRyb21lIikgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCBzaXplID0gMTIpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNCkKICApCiMgRG90UGxvdCB3aXRoIGN1c3RvbSBmaXJlYnJpY2stcmVkIGdyYWRpZW50CkRvdFBsb3Qoc3NfdnNfaGMsIGZlYXR1cmVzID0gdXBfZ2VuZXMsIGdyb3VwLmJ5ID0gImNvbmRpdGlvbiIpICsKICBSb3RhdGVkQXhpcygpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudDIobG93ID0gImxpZ2h0Ymx1ZSIsIG1pZCA9ICJyZWQiLCBoaWdoID0gImZpcmVicmljayIsIG1pZHBvaW50ID0gMSkgKwogIGdndGl0bGUoIkV4cHJlc3Npb24gb2YgVXByZWd1bGF0ZWQgR2VuZXMgaW4gU8OpemFyeSBTeW5kcm9tZSIpICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgc2l6ZSA9IDEyKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLCBzaXplID0gMTQpCiAgKQoKCiMgRG90UGxvdCB3aXRoIGN1c3RvbSBmaXJlYnJpY2stcmVkIGdyYWRpZW50CkRvdFBsb3Qoc3NfdnNfaGMsIGZlYXR1cmVzID0gdXBfZ2VuZXMsIGdyb3VwLmJ5ID0gImNvbmRpdGlvbiIpICsKICBSb3RhdGVkQXhpcygpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudDIobG93ID0gImxpZ2h0Ymx1ZSIsIG1pZCA9ICJyZWQiLCBoaWdoID0gImZpcmVicmljayIsIG1pZHBvaW50ID0gMSkgKwogIGdndGl0bGUoIkV4cHJlc3Npb24gb2YgVXByZWd1bGF0ZWQgR2VuZXMgaW4gU8OpemFyeSBTeW5kcm9tZSIpICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgc2l6ZSA9IDEyKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLCBzaXplID0gMTQpKQoKYGBgCgojIyAgIFZpc3VhbGl6YXRpb24gb2YgUG90ZW50aWFsIGJpb21hcmtlcnMtRG93bnJlZ3VsYXRlZApgYGB7ciAsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTEwfQoKIyBEb3ducmVndWxhdGVkIGdlbmVzCmRvd25fZ2VuZXMgPC0gYygiVFhOSVAiLCAiUkFTQTMiLCAiUklQT1IyIiwgCiAgICAgICAgICAgICAgICAiWkZQMzYiLCAiWkZQMzZMMSIsICJaRlAzNkwyIiwKICAgICAgICAgICAgICAgICJQUk1UMiIsICJNQVgiLCAiUElLM0lQMSIsIAogICAgICAgICAgICAgICAgIkJURzEiLCAiQ0RLTjFCIikKCiMgRG90UGxvdCB3aXRoIGZpcmVicmljayBjb2xvciBmb3IgaGlnaCBleHByZXNzaW9uCkRvdFBsb3Qoc3NfdnNfaGMsIGZlYXR1cmVzID0gZG93bl9nZW5lcykgKwogIFJvdGF0ZWRBeGlzKCkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50Mihsb3cgPSAibGlnaHRibHVlIiwgbWlkID0gInJlZCIsIGhpZ2ggPSAiZmlyZWJyaWNrIiwgbWlkcG9pbnQgPSAxKSArCiAgZ2d0aXRsZSgiRXhwcmVzc2lvbiBvZiBEb3ducmVndWxhdGVkIEdlbmVzIGluIFPDqXphcnkgU3luZHJvbWUiKSArCiAgdGhlbWUoCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHNpemUgPSAxMiksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE0KQogICkKCiMgRG90UGxvdCB3aXRoIGZpcmVicmljayBjb2xvciBmb3IgaGlnaCBleHByZXNzaW9uCkRvdFBsb3Qoc3NfdnNfaGMsIGZlYXR1cmVzID0gZG93bl9nZW5lcywgZ3JvdXAuYnkgPSAic2FtcGxlX2lkIikgKwogIFJvdGF0ZWRBeGlzKCkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50Mihsb3cgPSAibGlnaHRibHVlIiwgbWlkID0gInJlZCIsIGhpZ2ggPSAiZmlyZWJyaWNrIiwgbWlkcG9pbnQgPSAxKSArCiAgZ2d0aXRsZSgiRXhwcmVzc2lvbiBvZiBEb3ducmVndWxhdGVkIEdlbmVzIGluIFPDqXphcnkgU3luZHJvbWUiKSArCiAgdGhlbWUoCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHNpemUgPSAxMiksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE0KQogICkKCiMgRG90UGxvdCB3aXRoIGZpcmVicmljayBjb2xvciBmb3IgaGlnaCBleHByZXNzaW9uCkRvdFBsb3Qoc3NfdnNfaGMsIGZlYXR1cmVzID0gZG93bl9nZW5lcywgZ3JvdXAuYnkgPSAidGlzc3VlIikgKwogIFJvdGF0ZWRBeGlzKCkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50Mihsb3cgPSAibGlnaHRibHVlIiwgbWlkID0gInJlZCIsIGhpZ2ggPSAiZmlyZWJyaWNrIiwgbWlkcG9pbnQgPSAxKSArCiAgZ2d0aXRsZSgiRXhwcmVzc2lvbiBvZiBEb3ducmVndWxhdGVkIEdlbmVzIGluIFPDqXphcnkgU3luZHJvbWUiKSArCiAgdGhlbWUoCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHNpemUgPSAxMiksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE0KQogICkKCiMgRG90UGxvdCB3aXRoIGZpcmVicmljayBjb2xvciBmb3IgaGlnaCBleHByZXNzaW9uCkRvdFBsb3Qoc3NfdnNfaGMsIGZlYXR1cmVzID0gZG93bl9nZW5lcywgZ3JvdXAuYnkgPSAiY29uZGl0aW9uIikgKwogIFJvdGF0ZWRBeGlzKCkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50Mihsb3cgPSAibGlnaHRibHVlIiwgbWlkID0gInJlZCIsIGhpZ2ggPSAiZmlyZWJyaWNrIiwgbWlkcG9pbnQgPSAxKSArCiAgZ2d0aXRsZSgiRXhwcmVzc2lvbiBvZiBEb3ducmVndWxhdGVkIEdlbmVzIGluIFPDqXphcnkgU3luZHJvbWUiKSArCiAgdGhlbWUoCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHNpemUgPSAxMiksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE0KQogICkKCmBgYAojIyAgIFNhdmUgU2V1cmF0IG9iamVjdApgYGB7ciAsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTZ9CgpzYXZlUkRTKHNzX3ZzX2hjLCBmaWxlID0gIlNlemFyeV9CbG9vZF9Ta2luX3ZzX0hDX1RDUl9maWx0ZXJlZC5yZHMiKQoKYGBgCgoKCgoKCgoK