1. load libraries

2. Load QC seurat Object


ss_Harro <- readRDS("ss_Harro_SS_4_MF_3_QC_object.rds")

3. Log-normalization (scale factor = 10,000) and Integration



# 1. Split Seurat object by sample
ss_list <- SplitObject(ss_Harro, split.by = "orig.ident")

# 2. Log-normalization + variable feature selection + cell cycle scoring
ss_list <- lapply(ss_list, function(x) {
  x <- NormalizeData(x, normalization.method = "LogNormalize", scale.factor = 10000)
  x <- FindVariableFeatures(x, selection.method = "vst", nfeatures = 5000)
  x <- CellCycleScoring(x, s.features = cc.genes$s.genes, g2m.features = cc.genes$g2m.genes)
  return(x)
})
Normalizing layer: counts.SS_P1.SeuratProject.SeuratProject.SeuratProject.SeuratProject.SeuratProject
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Finding variable features for layer counts.SS_P1.SeuratProject.SeuratProject.SeuratProject.SeuratProject.SeuratProject
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%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Avis : The `slot` argument of `GetAssayData()` is deprecated as of SeuratObject 5.0.0.
Please use the `layer` argument instead.Avis : The following features are not present in the object: MLF1IP, E2F8, not searching for symbol synonymsAvis : The following features are not present in the object: FAM64A, HN1, CDC25C, GAS2L3, not searching for symbol synonymsNormalizing layer: counts.SS_P2.SeuratProject.SeuratProject.SeuratProject.SeuratProject.SeuratProject
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Finding variable features for layer counts.SS_P2.SeuratProject.SeuratProject.SeuratProject.SeuratProject.SeuratProject
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%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Avis : The following features are not present in the object: MLF1IP, not searching for symbol synonymsAvis : The following features are not present in the object: FAM64A, HN1, GAS2L3, not searching for symbol synonymsNormalizing layer: counts.SS_P3.SeuratProject.SeuratProject.SeuratProject.SeuratProject
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Finding variable features for layer counts.SS_P3.SeuratProject.SeuratProject.SeuratProject.SeuratProject
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%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Avis : The following features are not present in the object: MLF1IP, not searching for symbol synonymsAvis : The following features are not present in the object: FAM64A, HN1, not searching for symbol synonymsNormalizing layer: counts.SS_P4.SeuratProject.SeuratProject.SeuratProject
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Finding variable features for layer counts.SS_P4.SeuratProject.SeuratProject.SeuratProject
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%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Avis : The following features are not present in the object: MLF1IP, not searching for symbol synonymsAvis : The following features are not present in the object: FAM64A, HN1, CDC25C, NEK2, GAS2L3, not searching for symbol synonymsNormalizing layer: counts.MF_P1.SeuratProject.SeuratProject
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Finding variable features for layer counts.MF_P1.SeuratProject.SeuratProject
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%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Avis : The following features are not present in the object: MLF1IP, not searching for symbol synonymsAvis : The following features are not present in the object: FAM64A, HN1, not searching for symbol synonymsNormalizing layer: counts.MF_P2.SeuratProject
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Finding variable features for layer counts.MF_P2.SeuratProject
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%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Avis : The following features are not present in the object: MLF1IP, not searching for symbol synonymsAvis : The following features are not present in the object: FAM64A, HN1, GAS2L3, not searching for symbol synonymsNormalizing layer: counts.MF_P3
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Finding variable features for layer counts.MF_P3
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%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Avis : The following features are not present in the object: MLF1IP, not searching for symbol synonymsAvis : The following features are not present in the object: FAM64A, HN1, not searching for symbol synonyms
# 3. Intersect genes across all objects to ensure consistency
common_genes <- Reduce(intersect, lapply(ss_list, rownames))
ss_list <- lapply(ss_list, function(x) {
  x <- subset(x, features = common_genes)
  return(x)
})

# 4. Remove TCR/Ig genes from variable features
tcr_genes <- grep("^TR[ABGD]|^IG[HKL]", common_genes, value = TRUE)
ss_list <- lapply(ss_list, function(x) {
  vgs <- VariableFeatures(x)
  vgs <- setdiff(vgs, tcr_genes)
  VariableFeatures(x) <- vgs
  return(x)
})

# 5. Run PCA on each object (required for RPCA)
ss_list <- lapply(ss_list, function(x) {
  x <- ScaleData(x, features = VariableFeatures(x), verbose = FALSE)
  x <- RunPCA(x, features = VariableFeatures(x), verbose = FALSE)
  return(x)
})

# 6. Select integration features
features <- SelectIntegrationFeatures(object.list = ss_list, nfeatures = 8000)

# 7. Find integration anchors using RPCA
anchors <- FindIntegrationAnchors(
  object.list = ss_list,
  anchor.features = features,
  reduction = "rpca",
  dims = 1:40
)
Scaling features for provided objects

  |                                                  | 0 % ~calculating  
Avis : Different features in new layer data than already exists for scale.data

  |++++++++                                          | 14% ~32s          
Avis : Different features in new layer data than already exists for scale.data

  |+++++++++++++++                                   | 29% ~21s          
Avis : Different features in new layer data than already exists for scale.data

  |++++++++++++++++++++++                            | 43% ~22s          
Avis : Different features in new layer data than already exists for scale.data

  |+++++++++++++++++++++++++++++                     | 57% ~14s          
Avis : Different features in new layer data than already exists for scale.data

  |++++++++++++++++++++++++++++++++++++              | 71% ~14s          
Avis : Different features in new layer data than already exists for scale.data

  |+++++++++++++++++++++++++++++++++++++++++++       | 86% ~07s          
Avis : Different features in new layer data than already exists for scale.data

  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=47s  
Computing within dataset neighborhoods

  |                                                  | 0 % ~calculating  
  |++++++++                                          | 14% ~43s          
  |+++++++++++++++                                   | 29% ~26s          
  |++++++++++++++++++++++                            | 43% ~28s          
  |+++++++++++++++++++++++++++++                     | 57% ~19s          
  |++++++++++++++++++++++++++++++++++++              | 71% ~19s          
  |+++++++++++++++++++++++++++++++++++++++++++       | 86% ~09s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=01m 02s
Finding all pairwise anchors

  |                                                  | 0 % ~calculating  
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 884 anchors

  |+++                                               | 5 % ~13m 19s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 1521 anchors

  |+++++                                             | 10% ~15m 36s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 944 anchors

  |++++++++                                          | 14% ~14m 48s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 1093 anchors

  |++++++++++                                        | 19% ~13m 09s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 743 anchors

  |++++++++++++                                      | 24% ~11m 20s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 1118 anchors

  |+++++++++++++++                                   | 29% ~10m 43s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 984 anchors

  |+++++++++++++++++                                 | 33% ~11m 53s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 735 anchors

  |++++++++++++++++++++                              | 38% ~12m 01s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 1102 anchors

  |++++++++++++++++++++++                            | 43% ~12m 24s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 898 anchors

  |++++++++++++++++++++++++                          | 48% ~11m 50s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 907 anchors

  |+++++++++++++++++++++++++++                       | 52% ~10m 44s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 707 anchors

  |+++++++++++++++++++++++++++++                     | 57% ~09m 28s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 906 anchors

  |+++++++++++++++++++++++++++++++                   | 62% ~08m 27s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 828 anchors

  |++++++++++++++++++++++++++++++++++                | 67% ~07m 16s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 4606 anchors

  |++++++++++++++++++++++++++++++++++++              | 71% ~06m 32s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 891 anchors

  |+++++++++++++++++++++++++++++++++++++++           | 76% ~05m 22s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 566 anchors

  |+++++++++++++++++++++++++++++++++++++++++         | 81% ~04m 11s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 773 anchors

  |+++++++++++++++++++++++++++++++++++++++++++       | 86% ~03m 07s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 720 anchors

  |++++++++++++++++++++++++++++++++++++++++++++++    | 90% ~02m 01s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 1315 anchors

  |++++++++++++++++++++++++++++++++++++++++++++++++  | 95% ~01m 03s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 1375 anchors

  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=21m 48s
# 8. Integrate data
ss_integrated <- IntegrateData(anchorset = anchors, dims = 1:40)
Merging dataset 6 into 5
Extracting anchors for merged samples
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
Avis : Layer counts isn't present in the assay object; returning NULLMerging dataset 4 into 3
Extracting anchors for merged samples
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
Avis : Layer counts isn't present in the assay object; returning NULLMerging dataset 2 into 1
Extracting anchors for merged samples
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
Avis : Layer counts isn't present in the assay object; returning NULLMerging dataset 7 into 5 6
Extracting anchors for merged samples
Finding integration vectors
Avis : Different cells in new layer data than already exists for scale.dataFinding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
Avis : Layer counts isn't present in the assay object; returning NULLMerging dataset 1 2 into 3 4
Extracting anchors for merged samples
Finding integration vectors
Avis : The `slot` argument of `SetAssayData()` is deprecated as of SeuratObject 5.0.0.
Please use the `layer` argument instead.Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
Avis : Layer counts isn't present in the assay object; returning NULLMerging dataset 3 4 1 2 into 5 6 7
Extracting anchors for merged samples
Finding integration vectors

4. PCA + UMAP


ss_Harro <- ss_integrated

# PCA
ss_Harro <- RunPCA(ss_Harro, npcs = 50)

# Optional: Visualize elbow plot
ElbowPlot(ss_Harro, ndims = 50)

5. PCA Visualization




# TEST-1
# given that the output of RunPCA is "pca"
# replace "so" by the name of your seurat object

pct <- ss_Harro[["pca"]]@stdev / sum(ss_Harro[["pca"]]@stdev) * 100
cumu <- cumsum(pct) # Calculate cumulative percents for each PC
# Determine the difference between variation of PC and subsequent PC
co2 <- sort(which((pct[-length(pct)] - pct[-1]) > 0.1), decreasing = T)[1] + 1
# last point where change of % of variation is more than 0.1%. -> co2
co2

# TEST-2
# get significant PCs
stdv <- ss_Harro[["pca"]]@stdev
sum.stdv <- sum(ss_Harro[["pca"]]@stdev)
percent.stdv <- (stdv / sum.stdv) * 100
cumulative <- cumsum(percent.stdv)
co1 <- which(cumulative > 90 & percent.stdv < 5)[1]
co2 <- sort(which((percent.stdv[1:length(percent.stdv) - 1] - 
                       percent.stdv[2:length(percent.stdv)]) > 0.1), 
              decreasing = T)[1] + 1
min.pc <- min(co1, co2)
min.pc

# Create a dataframe with values
plot_df <- data.frame(pct = percent.stdv, 
           cumu = cumulative, 
           rank = 1:length(percent.stdv))

# Elbow plot to visualize 
  ggplot(plot_df, aes(cumulative, percent.stdv, label = rank, color = rank > min.pc)) + 
  geom_text() + 
  geom_vline(xintercept = 90, color = "grey") + 
  geom_hline(yintercept = min(percent.stdv[percent.stdv > 5]), color = "grey") +
  theme_bw()

  

6. Clustering (resolution = 1.0)

# Then find neighbors & clusters
ss_Harro <- FindNeighbors(ss_Harro, dims = 1:40)
ss_Harro <- FindClusters(ss_Harro, resolution = 1.0)

# run UMAP
ss_Harro <- RunUMAP(ss_Harro, dims = 1:40)

ss_Harro <-RunTSNE(ss_Harro, dims.use = 1:40)

7. Visualize UMAP with Clusters


DimPlot(ss_Harro, reduction = "umap",group.by = "orig.ident", label = TRUE,repel = T, pt.size = 0.6) +
  ggtitle("UMAP of Sézary Syndrome CD4+ T Cells")


DimPlot(ss_Harro, reduction = "umap", label = TRUE,repel = T, pt.size = 0.6) +
  ggtitle("UMAP of Sézary Syndrome CD4+ T Cells")


DimPlot(ss_Harro, reduction = "tsne", label = TRUE, pt.size = 0.6) +
  ggtitle("TSNE of Sézary Syndrome CD4+ T Cells")

Save the Seurat object as an RDS



saveRDS(ss_Harro, file = "ss_Harro_SS_4_MF_3_Integrated_object_before_featureplot.rds")

8. 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")



Idents(ss_Harro) <- "seurat_clusters"


FeaturePlot(ss_Harro, 
             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_Harro, 
             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_Harro, 
             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_Harro, 
             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_Harro, 
             features = top_50_up$gene[41:50], 
             reduction = "umap", 
             cols = c("lightblue", "red"),  # Custom color gradient from light blue to red
             label = TRUE)

9. FeaturePlots for Top50 DOWN


FeaturePlot(ss_Harro, 
             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_Harro, 
             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_Harro, 
             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_Harro, 
             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_Harro, 
             features = top_50_down$gene[41:50], 
             reduction = "umap", 
             cols = c("lightblue", "red"),  # Custom color gradient from light blue to red
             label = TRUE)

Visualization



DimPlot(ss_Harro, group.by = "seurat_clusters", label = T, label.box = T, repel = T, reduction = "umap")

Visualization of Potential biomarkers-Upregulated


DefaultAssay(ss_Harro) <- "RNA"
Idents(ss_Harro) <- "Disease_state"

# 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_Harro, features = up_genes) +
  RotatedAxis() +
  scale_color_gradient2(low = "lightyellow", 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)
  )

Idents(ss_Harro) <- "orig.ident"

# 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_Harro, features = up_genes) +
  RotatedAxis() +
  scale_color_gradient2(low = "lightyellow", 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)
  )

Idents(ss_Harro) <- "seurat_clusters"

# 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_Harro, features = up_genes) +
  RotatedAxis() +
  scale_color_gradient2(low = "lightyellow", 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


Idents(ss_Harro) <- "Disease_state"
# 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_Harro, features = down_genes) +
  RotatedAxis() +
  scale_color_gradient2(low = "lightyellow", 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)
  )


Idents(ss_Harro) <- "orig.ident"
# 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_Harro, features = down_genes) +
  RotatedAxis() +
  scale_color_gradient2(low = "lightyellow", 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)
  )
Idents(ss_Harro) <- "seurat_clusters"

# DotPlot with firebrick color for high expression
DotPlot(ss_Harro, features = down_genes) +
  RotatedAxis() +
  scale_color_gradient2(low = "lightyellow", 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 the Seurat object as an RDS



saveRDS(ss_Harro, file = "ss_Harro_SS_4_MF_3_Integrated_object_after_featureplot_final.rds")
LS0tCnRpdGxlOiAiUG90ZW50aWFsIGJpb21hcmtlcnMgVmFsaWRhdGlvbiAoSGFycm9fNF9TU19hbmRfM19NRl9QYXRpZW50X1NhbXBsZXMpLUludGVncmF0aW9uIgphdXRob3I6IE5hc2lyIE1haG1vb2QgQWJiYXNpCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogICNybWRmb3JtYXRzOjpyZWFkdGhlZG93bgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdG9jX2NvbGxhcHNlZDogdHJ1ZQotLS0KCiMgMS4gbG9hZCBsaWJyYXJpZXMKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CgpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShTZXVyYXRPYmplY3QpCmxpYnJhcnkoU2V1cmF0RGF0YSkKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkoQXppbXV0aCkKbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShybWFya2Rvd24pCmxpYnJhcnkodGlueXRleCkKCgpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGRpdHRvU2VxKQpsaWJyYXJ5KGdncmVwZWwpCiNsaWJyYXJ5KGdndHJlZSkKbGlicmFyeShwYXJhbGxlbCkKbGlicmFyeShwbG90bHkpICAjIDNEIHBsb3QKbGlicmFyeShTZXVyYXQpICAjIElkZW50cygpCmxpYnJhcnkoU2V1cmF0RGlzaykgICMgU2F2ZUg1U2V1cmF0KCkKbGlicmFyeSh0aWJibGUpICAjIHJvd25uYW1lc190b19jb2x1bW4KbGlicmFyeShoYXJtb255KSAjIFJ1bkhhcm1vbnkoKQojb3B0aW9ucyhtYy5jb3JlcyA9IGRldGVjdENvcmVzKCkgLSAxKQoKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkobWFncml0dHIpCmxpYnJhcnkoZGJwbHlyKQpsaWJyYXJ5KHJtYXJrZG93bikKbGlicmFyeShrbml0cikKbGlicmFyeSh0aW55dGV4KQojQXppbXV0aCBBbm5vdGF0aW9uIGxpYnJhcmllcwpsaWJyYXJ5KEF6aW11dGgpCiNQcm9qZWNUaWxzIEFubm90YXRpb24gbGlicmFyaWVzCmxpYnJhcnkoU1RBQ0FTKQpsaWJyYXJ5KFByb2plY1RJTHMpCiNzaW5nbGVSIEFubm90YXRpb24gbGlicmFyaWVzCgpsaWJyYXJ5KFNpbmdsZUNlbGxFeHBlcmltZW50KQoKYGBgCgoKIyAyLiBMb2FkIFFDIHNldXJhdCBPYmplY3QKYGBge3IgbG9hZFNldXJhdH0KCnNzX0hhcnJvIDwtIHJlYWRSRFMoInNzX0hhcnJvX1NTXzRfTUZfM19RQ19vYmplY3QucmRzIikKCmBgYAoKCiMgMy4gTG9nLW5vcm1hbGl6YXRpb24gKHNjYWxlIGZhY3RvciA9IDEwLDAwMCkgYW5kIEludGVncmF0aW9uCmBgYHtyIFBDQSwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CgoKIyAxLiBTcGxpdCBTZXVyYXQgb2JqZWN0IGJ5IHNhbXBsZQpzc19saXN0IDwtIFNwbGl0T2JqZWN0KHNzX0hhcnJvLCBzcGxpdC5ieSA9ICJvcmlnLmlkZW50IikKCiMgMi4gSW50ZXJzZWN0IGdlbmVzIGFjcm9zcyBhbGwgb2JqZWN0cyB0byBlbnN1cmUgY29uc2lzdGVuY3kKY29tbW9uX2dlbmVzIDwtIFJlZHVjZShpbnRlcnNlY3QsIGxhcHBseShzc19saXN0LCByb3duYW1lcykpCnNzX2xpc3QgPC0gbGFwcGx5KHNzX2xpc3QsIGZ1bmN0aW9uKHgpIHsKICB4IDwtIHN1YnNldCh4LCBmZWF0dXJlcyA9IGNvbW1vbl9nZW5lcykKICByZXR1cm4oeCkKfSkKCiMgMy4gTG9nLW5vcm1hbGl6YXRpb24gKyB2YXJpYWJsZSBmZWF0dXJlIHNlbGVjdGlvbiArIGNlbGwgY3ljbGUgc2NvcmluZwpzc19saXN0IDwtIGxhcHBseShzc19saXN0LCBmdW5jdGlvbih4KSB7CiAgeCA8LSBOb3JtYWxpemVEYXRhKHgsIG5vcm1hbGl6YXRpb24ubWV0aG9kID0gIkxvZ05vcm1hbGl6ZSIsIHNjYWxlLmZhY3RvciA9IDEwMDAwKQogIHggPC0gRmluZFZhcmlhYmxlRmVhdHVyZXMoeCwgc2VsZWN0aW9uLm1ldGhvZCA9ICJ2c3QiLCBuZmVhdHVyZXMgPSA1MDAwKQogIHggPC0gQ2VsbEN5Y2xlU2NvcmluZyh4LCBzLmZlYXR1cmVzID0gY2MuZ2VuZXMkcy5nZW5lcywgZzJtLmZlYXR1cmVzID0gY2MuZ2VuZXMkZzJtLmdlbmVzKQogIHJldHVybih4KQp9KQoKIyA0LiBSZW1vdmUgY2Fub25pY2FsIFRDUi9JZyBnZW5lcyBmcm9tIHZhcmlhYmxlIGZlYXR1cmVzIChzYWZlIGFuZCBzcGVjaWZpYyByZWdleCkKdGNyX2lnX2dlbmVzIDwtIGdyZXAoCiAgIl5UUkFbVkpEXXxeVFJCW1ZKRF18XlRSRFtWSkRdfF5UUkdbVkpEXXxeSUdIW1ZESl18XklHS1tWREpdfF5JR0xbVkRKXSIsCiAgY29tbW9uX2dlbmVzLAogIHZhbHVlID0gVFJVRQopCnNzX2xpc3QgPC0gbGFwcGx5KHNzX2xpc3QsIGZ1bmN0aW9uKHgpIHsKICB2Z3MgPC0gVmFyaWFibGVGZWF0dXJlcyh4KQogIHZncyA8LSBzZXRkaWZmKHZncywgdGNyX2lnX2dlbmVzKQogIFZhcmlhYmxlRmVhdHVyZXMoeCkgPC0gdmdzCiAgcmV0dXJuKHgpCn0pCgojIDUuIFJ1biBQQ0Egb24gZWFjaCBvYmplY3QgKHJlcXVpcmVkIGZvciBSUENBKQpzc19saXN0IDwtIGxhcHBseShzc19saXN0LCBmdW5jdGlvbih4KSB7CiAgeCA8LSBTY2FsZURhdGEoeCwgZmVhdHVyZXMgPSBWYXJpYWJsZUZlYXR1cmVzKHgpLCB2ZXJib3NlID0gRkFMU0UpCiAgeCA8LSBSdW5QQ0EoeCwgZmVhdHVyZXMgPSBWYXJpYWJsZUZlYXR1cmVzKHgpLCB2ZXJib3NlID0gRkFMU0UpCiAgcmV0dXJuKHgpCn0pCgojIDYuIFNlbGVjdCBpbnRlZ3JhdGlvbiBmZWF0dXJlcwpmZWF0dXJlcyA8LSBTZWxlY3RJbnRlZ3JhdGlvbkZlYXR1cmVzKG9iamVjdC5saXN0ID0gc3NfbGlzdCwgbmZlYXR1cmVzID0gODAwMCkKCiMgNy4gRmluZCBpbnRlZ3JhdGlvbiBhbmNob3JzIHVzaW5nIFJQQ0EKYW5jaG9ycyA8LSBGaW5kSW50ZWdyYXRpb25BbmNob3JzKAogIG9iamVjdC5saXN0ID0gc3NfbGlzdCwKICBhbmNob3IuZmVhdHVyZXMgPSBmZWF0dXJlcywKICByZWR1Y3Rpb24gPSAicnBjYSIsCiAgZGltcyA9IDE6NDAKKQoKIyA4LiBJbnRlZ3JhdGUgZGF0YQpzc19pbnRlZ3JhdGVkIDwtIEludGVncmF0ZURhdGEoYW5jaG9yc2V0ID0gYW5jaG9ycywgZGltcyA9IDE6NDApCgojIDkuIFNldCB0aGUgZGVmYXVsdCBhc3NheSB0byAiaW50ZWdyYXRlZCIKRGVmYXVsdEFzc2F5KHNzX2ludGVncmF0ZWQpIDwtICJpbnRlZ3JhdGVkIgoKIyAxMC4gU2NhbGUgaW50ZWdyYXRlZCBkYXRhIGFuZCByZWdyZXNzIG91dCB1bndhbnRlZCB2YXJpYXRpb24Kc3NfaW50ZWdyYXRlZCA8LSBTY2FsZURhdGEoCiAgc3NfaW50ZWdyYXRlZCwKICB2YXJzLnRvLnJlZ3Jlc3MgPSBjKCJuQ291bnRfUk5BIiwgInBlcmNlbnQubXQiLCAiUy5TY29yZSIsICJHMk0uU2NvcmUiKQopCgpgYGAKCgojIDQuIFBDQSArIFVNQVAKYGBge3IgRWxib3csIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKc3NfSGFycm8gPC0gc3NfaW50ZWdyYXRlZAoKIyBQQ0EKc3NfSGFycm8gPC0gUnVuUENBKHNzX0hhcnJvLCBucGNzID0gNTApCgojIE9wdGlvbmFsOiBWaXN1YWxpemUgZWxib3cgcGxvdApFbGJvd1Bsb3Qoc3NfSGFycm8sIG5kaW1zID0gNTApCgpgYGAKCiMgNS4gUENBIFZpc3VhbGl6YXRpb24KYGBge3IgUENBLVRFU1QsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKCgojIFRFU1QtMQojIGdpdmVuIHRoYXQgdGhlIG91dHB1dCBvZiBSdW5QQ0EgaXMgInBjYSIKIyByZXBsYWNlICJzbyIgYnkgdGhlIG5hbWUgb2YgeW91ciBzZXVyYXQgb2JqZWN0CgpwY3QgPC0gc3NfSGFycm9bWyJwY2EiXV1Ac3RkZXYgLyBzdW0oc3NfSGFycm9bWyJwY2EiXV1Ac3RkZXYpICogMTAwCmN1bXUgPC0gY3Vtc3VtKHBjdCkgIyBDYWxjdWxhdGUgY3VtdWxhdGl2ZSBwZXJjZW50cyBmb3IgZWFjaCBQQwojIERldGVybWluZSB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHZhcmlhdGlvbiBvZiBQQyBhbmQgc3Vic2VxdWVudCBQQwpjbzIgPC0gc29ydCh3aGljaCgocGN0Wy1sZW5ndGgocGN0KV0gLSBwY3RbLTFdKSA+IDAuMSksIGRlY3JlYXNpbmcgPSBUKVsxXSArIDEKIyBsYXN0IHBvaW50IHdoZXJlIGNoYW5nZSBvZiAlIG9mIHZhcmlhdGlvbiBpcyBtb3JlIHRoYW4gMC4xJS4gLT4gY28yCmNvMgoKIyBURVNULTIKIyBnZXQgc2lnbmlmaWNhbnQgUENzCnN0ZHYgPC0gc3NfSGFycm9bWyJwY2EiXV1Ac3RkZXYKc3VtLnN0ZHYgPC0gc3VtKHNzX0hhcnJvW1sicGNhIl1dQHN0ZGV2KQpwZXJjZW50LnN0ZHYgPC0gKHN0ZHYgLyBzdW0uc3RkdikgKiAxMDAKY3VtdWxhdGl2ZSA8LSBjdW1zdW0ocGVyY2VudC5zdGR2KQpjbzEgPC0gd2hpY2goY3VtdWxhdGl2ZSA+IDkwICYgcGVyY2VudC5zdGR2IDwgNSlbMV0KY28yIDwtIHNvcnQod2hpY2goKHBlcmNlbnQuc3RkdlsxOmxlbmd0aChwZXJjZW50LnN0ZHYpIC0gMV0gLSAKICAgICAgICAgICAgICAgICAgICAgICBwZXJjZW50LnN0ZHZbMjpsZW5ndGgocGVyY2VudC5zdGR2KV0pID4gMC4xKSwgCiAgICAgICAgICAgICAgZGVjcmVhc2luZyA9IFQpWzFdICsgMQptaW4ucGMgPC0gbWluKGNvMSwgY28yKQptaW4ucGMKCiMgQ3JlYXRlIGEgZGF0YWZyYW1lIHdpdGggdmFsdWVzCnBsb3RfZGYgPC0gZGF0YS5mcmFtZShwY3QgPSBwZXJjZW50LnN0ZHYsIAogICAgICAgICAgIGN1bXUgPSBjdW11bGF0aXZlLCAKICAgICAgICAgICByYW5rID0gMTpsZW5ndGgocGVyY2VudC5zdGR2KSkKCiMgRWxib3cgcGxvdCB0byB2aXN1YWxpemUgCiAgZ2dwbG90KHBsb3RfZGYsIGFlcyhjdW11bGF0aXZlLCBwZXJjZW50LnN0ZHYsIGxhYmVsID0gcmFuaywgY29sb3IgPSByYW5rID4gbWluLnBjKSkgKyAKICBnZW9tX3RleHQoKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDkwLCBjb2xvciA9ICJncmV5IikgKyAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBtaW4ocGVyY2VudC5zdGR2W3BlcmNlbnQuc3RkdiA+IDVdKSwgY29sb3IgPSAiZ3JleSIpICsKICB0aGVtZV9idygpCgogIAoKYGBgCgojIDYuIENsdXN0ZXJpbmcgKHJlc29sdXRpb24gPSAxLjApCmBgYHtyIENsdXN0ZXJpbmcsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQojIFRoZW4gZmluZCBuZWlnaGJvcnMgJiBjbHVzdGVycwpzc19IYXJybyA8LSBGaW5kTmVpZ2hib3JzKHNzX0hhcnJvLCBkaW1zID0gMTo0MCkKc3NfSGFycm8gPC0gRmluZENsdXN0ZXJzKHNzX0hhcnJvLCByZXNvbHV0aW9uID0gMS4wKQoKIyBydW4gVU1BUApzc19IYXJybyA8LSBSdW5VTUFQKHNzX0hhcnJvLCBkaW1zID0gMTo0MCkKCnNzX0hhcnJvIDwtUnVuVFNORShzc19IYXJybywgZGltcy51c2UgPSAxOjQwKQoKYGBgCgoKIyA3LiBWaXN1YWxpemUgVU1BUCB3aXRoIENsdXN0ZXJzCmBgYHtyIFVNQVAsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKRGltUGxvdChzc19IYXJybywgcmVkdWN0aW9uID0gInVtYXAiLGdyb3VwLmJ5ID0gIm9yaWcuaWRlbnQiLCBsYWJlbCA9IFRSVUUscmVwZWwgPSBULCBwdC5zaXplID0gMC42KSArCiAgZ2d0aXRsZSgiVU1BUCBvZiBTw6l6YXJ5IFN5bmRyb21lIENENCsgVCBDZWxscyIpCgoKRGltUGxvdChzc19IYXJybywgcmVkdWN0aW9uID0gInVtYXAiLCBsYWJlbCA9IFRSVUUscmVwZWwgPSBULCBwdC5zaXplID0gMC42KSArCiAgZ2d0aXRsZSgiVU1BUCBvZiBTw6l6YXJ5IFN5bmRyb21lIENENCsgVCBDZWxscyIpCgoKRGltUGxvdChzc19IYXJybywgcmVkdWN0aW9uID0gInRzbmUiLCBsYWJlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjYpICsKICBnZ3RpdGxlKCJUU05FIG9mIFPDqXphcnkgU3luZHJvbWUgQ0Q0KyBUIENlbGxzIikKCmBgYAoKIyMgU2F2ZSB0aGUgU2V1cmF0IG9iamVjdCBhcyBhbiBSRFMKYGBge3Igc2F2ZTF9CgoKc2F2ZVJEUyhzc19IYXJybywgZmlsZSA9ICJzc19IYXJyb19TU180X01GXzNfSW50ZWdyYXRlZF9vYmplY3RfYmVmb3JlX2ZlYXR1cmVwbG90LnJkcyIpCgoKYGBgCgoKCiMgOC4gIEZlYXR1cmVQbG90cyBmb3IgVG9wNTAgVVAKYGBge3IgRmVhdHVyZVBsb3QxLCBmaWcuaGVpZ2h0PTE2LCBmaWcud2lkdGg9MjB9CnRvcF81MF91cCA8LSByZWFkLmNzdigidG9wXzUwX3VwcmVndWxhdGVkLmNzdiIpICAgICAgICAjIG9yIHJlYWQuZGVsaW0oInRvcF81MF91cC50c3YiKQp0b3BfNTBfZG93biA8LSByZWFkLmNzdigidG9wXzUwX2Rvd25yZWd1bGF0ZWQuY3N2IikKCgoKSWRlbnRzKHNzX0hhcnJvKSA8LSAic2V1cmF0X2NsdXN0ZXJzIgoKCkZlYXR1cmVQbG90KHNzX0hhcnJvLCAKICAgICAgICAgICAgIGZlYXR1cmVzID0gdG9wXzUwX3VwJGdlbmVbMToxMF0sIAogICAgICAgICAgICAgcmVkdWN0aW9uID0gInVtYXAiLCAKICAgICAgICAgICAgIGNvbHMgPSBjKCJsaWdodGJsdWUiLCAicmVkIiksICAjIEN1c3RvbSBjb2xvciBncmFkaWVudCBmcm9tIGxpZ2h0IGJsdWUgdG8gcmVkCiAgICAgICAgICAgICBsYWJlbCA9IFRSVUUpCgoKRmVhdHVyZVBsb3Qoc3NfSGFycm8sIAogICAgICAgICAgICAgZmVhdHVyZXMgPSB0b3BfNTBfdXAkZ2VuZVsxMToyMF0sIAogICAgICAgICAgICAgcmVkdWN0aW9uID0gInVtYXAiLCAKICAgICAgICAgICAgIGNvbHMgPSBjKCJsaWdodGJsdWUiLCAicmVkIiksICAjIEN1c3RvbSBjb2xvciBncmFkaWVudCBmcm9tIGxpZ2h0IGJsdWUgdG8gcmVkCiAgICAgICAgICAgICBsYWJlbCA9IFRSVUUpCgpGZWF0dXJlUGxvdChzc19IYXJybywgCiAgICAgICAgICAgICBmZWF0dXJlcyA9IHRvcF81MF91cCRnZW5lWzIxOjMwXSwgCiAgICAgICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsIAogICAgICAgICAgICAgY29scyA9IGMoImxpZ2h0Ymx1ZSIsICJyZWQiKSwgICMgQ3VzdG9tIGNvbG9yIGdyYWRpZW50IGZyb20gbGlnaHQgYmx1ZSB0byByZWQKICAgICAgICAgICAgIGxhYmVsID0gVFJVRSkKRmVhdHVyZVBsb3Qoc3NfSGFycm8sIAogICAgICAgICAgICAgZmVhdHVyZXMgPSB0b3BfNTBfdXAkZ2VuZVszMTo0MF0sIAogICAgICAgICAgICAgcmVkdWN0aW9uID0gInVtYXAiLCAKICAgICAgICAgICAgIGNvbHMgPSBjKCJsaWdodGJsdWUiLCAicmVkIiksICAjIEN1c3RvbSBjb2xvciBncmFkaWVudCBmcm9tIGxpZ2h0IGJsdWUgdG8gcmVkCiAgICAgICAgICAgICBsYWJlbCA9IFRSVUUpCkZlYXR1cmVQbG90KHNzX0hhcnJvLCAKICAgICAgICAgICAgIGZlYXR1cmVzID0gdG9wXzUwX3VwJGdlbmVbNDE6NTBdLCAKICAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwgCiAgICAgICAgICAgICBjb2xzID0gYygibGlnaHRibHVlIiwgInJlZCIpLCAgIyBDdXN0b20gY29sb3IgZ3JhZGllbnQgZnJvbSBsaWdodCBibHVlIHRvIHJlZAogICAgICAgICAgICAgbGFiZWwgPSBUUlVFKQoKYGBgCgoKCiMgOS4gIEZlYXR1cmVQbG90cyBmb3IgVG9wNTAgRE9XTgpgYGB7ciBGZWF0dXJlUGxvdDIsIGZpZy5oZWlnaHQ9MTYsIGZpZy53aWR0aD0yMH0KCkZlYXR1cmVQbG90KHNzX0hhcnJvLCAKICAgICAgICAgICAgIGZlYXR1cmVzID0gdG9wXzUwX2Rvd24kZ2VuZVsxOjEwXSwgCiAgICAgICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsIAogICAgICAgICAgICAgY29scyA9IGMoImxpZ2h0Ymx1ZSIsICJyZWQiKSwgICMgQ3VzdG9tIGNvbG9yIGdyYWRpZW50IGZyb20gbGlnaHQgYmx1ZSB0byByZWQKICAgICAgICAgICAgIGxhYmVsID0gVFJVRSkKCgpGZWF0dXJlUGxvdChzc19IYXJybywgCiAgICAgICAgICAgICBmZWF0dXJlcyA9IHRvcF81MF9kb3duJGdlbmVbMTE6MjBdLCAKICAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwgCiAgICAgICAgICAgICBjb2xzID0gYygibGlnaHRibHVlIiwgInJlZCIpLCAgIyBDdXN0b20gY29sb3IgZ3JhZGllbnQgZnJvbSBsaWdodCBibHVlIHRvIHJlZAogICAgICAgICAgICAgbGFiZWwgPSBUUlVFKQoKRmVhdHVyZVBsb3Qoc3NfSGFycm8sIAogICAgICAgICAgICAgZmVhdHVyZXMgPSB0b3BfNTBfZG93biRnZW5lWzIxOjMwXSwgCiAgICAgICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsIAogICAgICAgICAgICAgY29scyA9IGMoImxpZ2h0Ymx1ZSIsICJyZWQiKSwgICMgQ3VzdG9tIGNvbG9yIGdyYWRpZW50IGZyb20gbGlnaHQgYmx1ZSB0byByZWQKICAgICAgICAgICAgIGxhYmVsID0gVFJVRSkKRmVhdHVyZVBsb3Qoc3NfSGFycm8sIAogICAgICAgICAgICAgZmVhdHVyZXMgPSB0b3BfNTBfZG93biRnZW5lWzMxOjQwXSwgCiAgICAgICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsIAogICAgICAgICAgICAgY29scyA9IGMoImxpZ2h0Ymx1ZSIsICJyZWQiKSwgICMgQ3VzdG9tIGNvbG9yIGdyYWRpZW50IGZyb20gbGlnaHQgYmx1ZSB0byByZWQKICAgICAgICAgICAgIGxhYmVsID0gVFJVRSkKRmVhdHVyZVBsb3Qoc3NfSGFycm8sIAogICAgICAgICAgICAgZmVhdHVyZXMgPSB0b3BfNTBfZG93biRnZW5lWzQxOjUwXSwgCiAgICAgICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsIAogICAgICAgICAgICAgY29scyA9IGMoImxpZ2h0Ymx1ZSIsICJyZWQiKSwgICMgQ3VzdG9tIGNvbG9yIGdyYWRpZW50IGZyb20gbGlnaHQgYmx1ZSB0byByZWQKICAgICAgICAgICAgIGxhYmVsID0gVFJVRSkKYGBgCgojIyBWaXN1YWxpemF0aW9uCmBgYHtyIHVtYXB2aXMsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKCkRpbVBsb3Qoc3NfSGFycm8sIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVycyIsIGxhYmVsID0gVCwgbGFiZWwuYm94ID0gVCwgcmVwZWwgPSBULCByZWR1Y3Rpb24gPSAidW1hcCIpCgoKYGBgCgojIyBWaXN1YWxpemF0aW9uIG9mIFBvdGVudGlhbCBiaW9tYXJrZXJzLVVwcmVndWxhdGVkCmBgYHtyIGJpb21hcmtlcnN2aXMsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKRGVmYXVsdEFzc2F5KHNzX0hhcnJvKSA8LSAiUk5BIgpJZGVudHMoc3NfSGFycm8pIDwtICJEaXNlYXNlX3N0YXRlIgoKIyBWZWN0b3Igb2YgZ2VuZXMgdG8gcGxvdAp1cF9nZW5lcyA8LSBjKCJDTElDMSIsICJDT1g1QSIsIkdUU0YxIiwgIk1BRDJMMSIsIk1ZQkwyIiwiTVlMNkIiLCJOTUUxIiwiUExLMSIsICJQWUNSMSIsICJTTEMyNUE1IiwgIlNSSSIsICJUVUJBMUMiLCAiVUJFMlQiLCAiWVdIQUgiKQoKIyBEb3RQbG90IHdpdGggY3VzdG9tIGZpcmVicmljay1yZWQgZ3JhZGllbnQKRG90UGxvdChzc19IYXJybywgZmVhdHVyZXMgPSB1cF9nZW5lcykgKwogIFJvdGF0ZWRBeGlzKCkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50Mihsb3cgPSAibGlnaHR5ZWxsb3ciLCBtaWQgPSAicmVkIiwgaGlnaCA9ICJmaXJlYnJpY2siLCBtaWRwb2ludCA9IDEpICsKICBnZ3RpdGxlKCJFeHByZXNzaW9uIG9mIFVwcmVndWxhdGVkIEdlbmVzIGluIFPDqXphcnkgU3luZHJvbWUiKSArCiAgdGhlbWUoCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHNpemUgPSAxMiksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE0KQogICkKCklkZW50cyhzc19IYXJybykgPC0gIm9yaWcuaWRlbnQiCgojIFZlY3RvciBvZiBnZW5lcyB0byBwbG90CnVwX2dlbmVzIDwtIGMoIkNMSUMxIiwgIkNPWDVBIiwiR1RTRjEiLCAiTUFEMkwxIiwiTVlCTDIiLCJNWUw2QiIsIk5NRTEiLCJQTEsxIiwgIlBZQ1IxIiwgIlNMQzI1QTUiLCAiU1JJIiwgIlRVQkExQyIsICJVQkUyVCIsICJZV0hBSCIpCgojIERvdFBsb3Qgd2l0aCBjdXN0b20gZmlyZWJyaWNrLXJlZCBncmFkaWVudApEb3RQbG90KHNzX0hhcnJvLCBmZWF0dXJlcyA9IHVwX2dlbmVzKSArCiAgUm90YXRlZEF4aXMoKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQyKGxvdyA9ICJsaWdodHllbGxvdyIsIG1pZCA9ICJyZWQiLCBoaWdoID0gImZpcmVicmljayIsIG1pZHBvaW50ID0gMSkgKwogIGdndGl0bGUoIkV4cHJlc3Npb24gb2YgVXByZWd1bGF0ZWQgR2VuZXMgaW4gU8OpemFyeSBTeW5kcm9tZSIpICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgc2l6ZSA9IDEyKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLCBzaXplID0gMTQpCiAgKQoKSWRlbnRzKHNzX0hhcnJvKSA8LSAic2V1cmF0X2NsdXN0ZXJzIgoKIyBWZWN0b3Igb2YgZ2VuZXMgdG8gcGxvdAp1cF9nZW5lcyA8LSBjKCJDTElDMSIsICJDT1g1QSIsIkdUU0YxIiwgIk1BRDJMMSIsIk1ZQkwyIiwiTVlMNkIiLCJOTUUxIiwiUExLMSIsICJQWUNSMSIsICJTTEMyNUE1IiwgIlNSSSIsICJUVUJBMUMiLCAiVUJFMlQiLCAiWVdIQUgiKQoKIyBEb3RQbG90IHdpdGggY3VzdG9tIGZpcmVicmljay1yZWQgZ3JhZGllbnQKRG90UGxvdChzc19IYXJybywgZmVhdHVyZXMgPSB1cF9nZW5lcykgKwogIFJvdGF0ZWRBeGlzKCkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50Mihsb3cgPSAibGlnaHR5ZWxsb3ciLCBtaWQgPSAicmVkIiwgaGlnaCA9ICJmaXJlYnJpY2siLCBtaWRwb2ludCA9IDEpICsKICBnZ3RpdGxlKCJFeHByZXNzaW9uIG9mIFVwcmVndWxhdGVkIEdlbmVzIGluIFPDqXphcnkgU3luZHJvbWUiKSArCiAgdGhlbWUoCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHNpemUgPSAxMiksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE0KQogICkKCgpgYGAKCgoKIyMgVmlzdWFsaXphdGlvbiBvZiBQb3RlbnRpYWwgYmlvbWFya2Vycy1Eb3ducmVndWxhdGVkCmBgYHtyIHZpczIsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKSWRlbnRzKHNzX0hhcnJvKSA8LSAiRGlzZWFzZV9zdGF0ZSIKIyBEb3ducmVndWxhdGVkIGdlbmVzCmRvd25fZ2VuZXMgPC0gYygiVFhOSVAiLCAiUkFTQTMiLCAiUklQT1IyIiwgCiAgICAgICAgICAgICAgICAiWkZQMzYiLCAiWkZQMzZMMSIsICJaRlAzNkwyIiwKICAgICAgICAgICAgICAgICJQUk1UMiIsICJNQVgiLCAiUElLM0lQMSIsIAogICAgICAgICAgICAgICAgIkJURzEiLCAiQ0RLTjFCIikKCiMgRG90UGxvdCB3aXRoIGZpcmVicmljayBjb2xvciBmb3IgaGlnaCBleHByZXNzaW9uCkRvdFBsb3Qoc3NfSGFycm8sIGZlYXR1cmVzID0gZG93bl9nZW5lcykgKwogIFJvdGF0ZWRBeGlzKCkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50Mihsb3cgPSAibGlnaHR5ZWxsb3ciLCBtaWQgPSAicmVkIiwgaGlnaCA9ICJmaXJlYnJpY2siLCBtaWRwb2ludCA9IDEpICsKICBnZ3RpdGxlKCJFeHByZXNzaW9uIG9mIERvd25yZWd1bGF0ZWQgR2VuZXMgaW4gU8OpemFyeSBTeW5kcm9tZSIpICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgc2l6ZSA9IDEyKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLCBzaXplID0gMTQpCiAgKQoKCklkZW50cyhzc19IYXJybykgPC0gIm9yaWcuaWRlbnQiCiMgRG93bnJlZ3VsYXRlZCBnZW5lcwpkb3duX2dlbmVzIDwtIGMoIlRYTklQIiwgIlJBU0EzIiwgIlJJUE9SMiIsIAogICAgICAgICAgICAgICAgIlpGUDM2IiwgIlpGUDM2TDEiLCAiWkZQMzZMMiIsCiAgICAgICAgICAgICAgICAiUFJNVDIiLCAiTUFYIiwgIlBJSzNJUDEiLCAKICAgICAgICAgICAgICAgICJCVEcxIiwgIkNES04xQiIpCgojIERvdFBsb3Qgd2l0aCBmaXJlYnJpY2sgY29sb3IgZm9yIGhpZ2ggZXhwcmVzc2lvbgpEb3RQbG90KHNzX0hhcnJvLCBmZWF0dXJlcyA9IGRvd25fZ2VuZXMpICsKICBSb3RhdGVkQXhpcygpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudDIobG93ID0gImxpZ2h0eWVsbG93IiwgbWlkID0gInJlZCIsIGhpZ2ggPSAiZmlyZWJyaWNrIiwgbWlkcG9pbnQgPSAxKSArCiAgZ2d0aXRsZSgiRXhwcmVzc2lvbiBvZiBEb3ducmVndWxhdGVkIEdlbmVzIGluIFPDqXphcnkgU3luZHJvbWUiKSArCiAgdGhlbWUoCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHNpemUgPSAxMiksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE0KQogICkKSWRlbnRzKHNzX0hhcnJvKSA8LSAic2V1cmF0X2NsdXN0ZXJzIgoKIyBEb3RQbG90IHdpdGggZmlyZWJyaWNrIGNvbG9yIGZvciBoaWdoIGV4cHJlc3Npb24KRG90UGxvdChzc19IYXJybywgZmVhdHVyZXMgPSBkb3duX2dlbmVzKSArCiAgUm90YXRlZEF4aXMoKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQyKGxvdyA9ICJsaWdodHllbGxvdyIsIG1pZCA9ICJyZWQiLCBoaWdoID0gImZpcmVicmljayIsIG1pZHBvaW50ID0gMSkgKwogIGdndGl0bGUoIkV4cHJlc3Npb24gb2YgRG93bnJlZ3VsYXRlZCBHZW5lcyBpbiBTw6l6YXJ5IFN5bmRyb21lIikgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCBzaXplID0gMTIpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNCkKICApCmBgYAoKIyMgU2F2ZSB0aGUgU2V1cmF0IG9iamVjdCBhcyBhbiBSRFMKYGBge3Igc2F2ZVJEU0ZpbmFsfQoKCnNhdmVSRFMoc3NfSGFycm8sIGZpbGUgPSAic3NfSGFycm9fU1NfNF9NRl8zX0ludGVncmF0ZWRfb2JqZWN0X2FmdGVyX2ZlYXR1cmVwbG90X2ZpbmFsLnJkcyIpCgoKYGBgCgo=