Prerequisites: The analysis assumes a Seurat object named All_samples_Merged is loaded, containing both RNA (SCT assay) and ADT (ADT assay) data.

# Replace with the actual path to your Seurat object
All_samples_Merged <- readRDS("../../../PHD_3rd_YEAR_Analysis/0-Seurat_RDS_OBJECT_FINAL/All_samples_Merged_with_Renamed_Clusters_final-26-10-2025.rds") 

# Verify the object structure
print(All_samples_Merged)
# Set default assay to SCT for initial RNA-based context
DefaultAssay(All_samples_Merged) <- "SCT"

DimPlot(All_samples_Merged, group.by = "orig.ident", label = T)

1 Featureplots

DefaultAssay(All_samples_Merged) <- "SCT"

Idents(All_samples_Merged) <- "seurat_clusters"

all_markers_SS <- c(

  #–––––––––––––––––––––––––––––––––––––––––––––
  # 1. CD4 T-CELL LINEAGE / MEMORY / ACTIVATION
  #–––––––––––––––––––––––––––––––––––––––––––––
  "CD4","CD3D","CD3E","CD3G","TRAC","TRBC1","TRBC2",
  "IL7R","CCR7","SELL","TCF7","LTB","CD28","CD40LG",
  "TNFRSF4","TNFRSF9","ICOS","TOX2",

  #–––––––––––––––––––––––––––––––––––––––––––––
  # 2. EXHAUSTION / CHRONIC ACTIVATION
  #–––––––––––––––––––––––––––––––––––––––––––––
  "PDCD1","CTLA4","LAG3","TIGIT","HAVCR2","ENTPD1",
  "CD244","CXCL13","TOX","BATF",

  #–––––––––––––––––––––––––––––––––––––––––––––
  # 3. SÉZARY-SPECIFIC MALIGNANT SIGNATURES
  #–––––––––––––––––––––––––––––––––––––––––––––
  "GATA3","IKZF2","TOX","TOX2","DUSP4","CCR4",
  "KIR3DL2","KLRB1","JUN","JUNB","FOS","FOSB","DUSP2",
  "CD7","DPP4","CD26","CD3D","CD3E","CD3G",
  "NAMPT","LAMP3","HSPA1A","HSPA1B","TNFRSF1B",
  "FCRL3","HLA-DRA","HLA-DRB1","B2M",

  #–––––––––––––––––––––––––––––––––––––––––––––
  # 4. MALIGNANT DOWNREGULATED / TUMOR SUPPRESSION LOSS
  #–––––––––––––––––––––––––––––––––––––––––––––
  "SELL","TCF7","CD7","DPP4","STAT4","BACH2","CD26",
  "CD45RA","IL7R","CCR7",

  #–––––––––––––––––––––––––––––––––––––––––––––
  # 5. Th1 / Th2 / Th17 / Tfh SUBSET MARKERS
  #–––––––––––––––––––––––––––––––––––––––––––––
  # Th1
  "TBX21","IFNG","CXCR3",
  # Th2
  "GATA3","IL4","IL5","IL13",
  # Th17
  "RORC","IL17A","IL17F","CCR6",
  # Tfh
  "BCL6","CXCL13","PDCD1","ICOS",

  #–––––––––––––––––––––––––––––––––––––––––––––
  # 6. TREG PANEL
  #–––––––––––––––––––––––––––––––––––––––––––––
  "FOXP3","IL2RA","CTLA4","TIGIT","IKZF2","CCR8","TNFRSF18",

  #–––––––––––––––––––––––––––––––––––––––––––––
  # 7. CELL CYCLE / PROLIFERATION
  #–––––––––––––––––––––––––––––––––––––––––––––
  "MKI67","TOP2A","CENPF","PCNA","MCM4","MCM6",
  "UBE2C","CDK1","AURKA","AURKB","CCNB1","CCNB2",

  #–––––––––––––––––––––––––––––––––––––––––––––
  # 8. METABOLIC / STRESS RESPONSE (RELEVANT IN SS)
  #–––––––––––––––––––––––––––––––––––––––––––––
  "NAMPT","LGALS3","HSP90AA1","HSPB1","SOD2","TXN",

  #–––––––––––––––––––––––––––––––––––––––––––––
  # 9. CYTOKINES / CHEMOKINES FREQUENTLY ACTIVE IN SS
  #–––––––––––––––––––––––––––––––––––––––––––––
  "CCL5","CCL4","CCL22","CCL17","IL32","IL2","IL7",

  #–––––––––––––––––––––––––––––––––––––––––––––
  # 10. CONTAMINATION CONTROL — MYELOID / NK / B
  #–––––––––––––––––––––––––––––––––––––––––––––
  # Myeloid
  "LYZ","S100A8","S100A9","CD14","FCGR3A","MS4A7","CD68","CD163","MRC1",
  # NK
  "NKG7","GNLY","KLRD1","PRF1","GZMB","TRDC","TRGC2","CD160",
  # B cells / plasma
  "MS4A1","CD79A","CD79B","MZB1","JCHAIN"
)

FeatPlot_canonical <- lapply(all_markers_SS, function(x){
    
    name = x
    print(name)
    jpeg(paste0("immune_featPlot_", name, ".jpeg"), width=10, height=10, units = 'in', res = 300)
    print(FeaturePlot(All_samples_Merged, features = x, reduction = "umap", label = TRUE, min.cutoff = 0, cols = c("navyblue", "darkseagreen","yellow","firebrick1")))
    dev.off()
    
}) 

2 Featureplots

DefaultAssay(All_samples_Merged) <- "SCT"
Idents(All_samples_Merged) <- "orig.ident"

library(viridis)

FeatPlot_canonical <- lapply(all_markers_SS, function(gene){

    message("Plotting: ", gene)

    # Extract gene expression
    expr <- FetchData(All_samples_Merged, vars = gene)[, 1]
    expr[!is.finite(expr)] <- NA   # remove Inf, NaN

    # Case 1: gene not expressed
    if (all(is.na(expr)) || all(expr == 0, na.rm = TRUE)) {

        warning(paste0("Gene ", gene, " has zero/NA expression. Plot will be blank."))

        p <- FeaturePlot(
            All_samples_Merged,
            features = gene,
            reduction = "umap",
            min.cutoff = NA,
            max.cutoff = NA,
            label = TRUE
        ) +
        scale_colour_viridis(option = "magma", na.value = "grey90") +
        ggtitle(paste0(gene, " (no expression)")) +
        theme_void()

        print(p)
        return(NULL)
    }

    # Case 2: normal gene → NO quantile cutoffs (avoids your error)
    p <- FeaturePlot(
        All_samples_Merged,
        features = gene,
        reduction = "umap",
        min.cutoff = NA,
        max.cutoff = NA,
        label = TRUE
    ) +
    scale_colour_viridis(option = "magma", na.value = "grey90") +
    ggtitle(gene) +
    theme_void() +
    theme(
        plot.title = element_text(size = 16, face = "bold"),
        legend.position = "right"
    )

    print(p)
})

3 Featureplots-Clusters

DefaultAssay(All_samples_Merged) <- "SCT"
Idents(All_samples_Merged) <- "seurat_clusters"

library(viridis)

FeatPlot_canonical <- lapply(all_markers_SS, function(gene){

    message("Plotting: ", gene)

    # Extract gene expression
    expr <- FetchData(All_samples_Merged, vars = gene)[, 1]
    expr[!is.finite(expr)] <- NA   # remove Inf, NaN

    # Case 1: gene not expressed
    if (all(is.na(expr)) || all(expr == 0, na.rm = TRUE)) {

        warning(paste0("Gene ", gene, " has zero/NA expression. Plot will be blank."))

        p2 <- FeaturePlot(
            All_samples_Merged,
            features = gene,
            reduction = "umap",
            min.cutoff = NA,
            max.cutoff = NA,
            label = TRUE
        ) +
        scale_colour_viridis(option = "magma", na.value = "grey90") +
        ggtitle(paste0(gene, " (no expression)")) +
        theme_void()

        print(p2)
        return(NULL)
    }

    # Case 2: normal gene → NO quantile cutoffs (avoids your error)
    p2 <- FeaturePlot(
        All_samples_Merged,
        features = gene,
        reduction = "umap",
        min.cutoff = NA,
        max.cutoff = NA,
        label = TRUE
    ) +
    scale_colour_viridis(option = "magma", na.value = "grey90") +
    ggtitle(gene) +
    theme_void() +
    theme(
        plot.title = element_text(size = 16, face = "bold"),
        legend.position = "right"
    )

    print(p2)
})
LS0tCnRpdGxlOiAiRmVhdHVyZVBsb3QgaW1wb3J0YW50IEdlbmVzIgphdXRob3I6ICJOQVNJUiBNQUhNT09EIEFCQkFTSSIKZGF0ZTogImByIGZvcm1hdChTeXMuRGF0ZSgpLCAnJUIgJWQsICVZJylgIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogdHJ1ZQogICAgdGhlbWU6IGpvdXJuYWwKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA4KQojIExvYWQgbmVjZXNzYXJ5IGxpYnJhcmllcwpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShkcGx5cikKbGlicmFyeShwaGVhdG1hcCkgIyBGb3IgaGVhdG1hcCB2aXN1YWxpemF0aW9uCmxpYnJhcnkoYXBlKSAjIEZvciB0cmVlIHZpc3VhbGl6YXRpb24KbGlicmFyeShkaXR0b1NlcSkgIyBGb3IgZGl0dG9IZWF0bWFwCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpgYGAKCgoqKlByZXJlcXVpc2l0ZXM6KiogVGhlIGFuYWx5c2lzIGFzc3VtZXMgYSBTZXVyYXQgb2JqZWN0IG5hbWVkIGBBbGxfc2FtcGxlc19NZXJnZWRgIGlzIGxvYWRlZCwgY29udGFpbmluZyBib3RoIFJOQSAoU0NUIGFzc2F5KSBhbmQgQURUIChBRFQgYXNzYXkpIGRhdGEuCgpgYGB7ciBsb2FkX2RhdGEsIGV2YWw9RkFMU0V9CiMgUmVwbGFjZSB3aXRoIHRoZSBhY3R1YWwgcGF0aCB0byB5b3VyIFNldXJhdCBvYmplY3QKQWxsX3NhbXBsZXNfTWVyZ2VkIDwtIHJlYWRSRFMoIi4uLy4uLy4uL1BIRF8zcmRfWUVBUl9BbmFseXNpcy8wLVNldXJhdF9SRFNfT0JKRUNUX0ZJTkFML0FsbF9zYW1wbGVzX01lcmdlZF93aXRoX1JlbmFtZWRfQ2x1c3RlcnNfZmluYWwtMjYtMTAtMjAyNS5yZHMiKSAKCiMgVmVyaWZ5IHRoZSBvYmplY3Qgc3RydWN0dXJlCnByaW50KEFsbF9zYW1wbGVzX01lcmdlZCkKIyBTZXQgZGVmYXVsdCBhc3NheSB0byBTQ1QgZm9yIGluaXRpYWwgUk5BLWJhc2VkIGNvbnRleHQKRGVmYXVsdEFzc2F5KEFsbF9zYW1wbGVzX01lcmdlZCkgPC0gIlNDVCIKCkRpbVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCBncm91cC5ieSA9ICJvcmlnLmlkZW50IiwgbGFiZWwgPSBUKQpgYGAKCgojIyBGZWF0dXJlcGxvdHMKYGBge3IgLCAgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OH0KRGVmYXVsdEFzc2F5KEFsbF9zYW1wbGVzX01lcmdlZCkgPC0gIlNDVCIKCklkZW50cyhBbGxfc2FtcGxlc19NZXJnZWQpIDwtICJzZXVyYXRfY2x1c3RlcnMiCgphbGxfbWFya2Vyc19TUyA8LSBjKAoKICAj4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCTCiAgIyAxLiBDRDQgVC1DRUxMIExJTkVBR0UgLyBNRU1PUlkgLyBBQ1RJVkFUSU9OCiAgI+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAkwogICJDRDQiLCJDRDNEIiwiQ0QzRSIsIkNEM0ciLCJUUkFDIiwiVFJCQzEiLCJUUkJDMiIsCiAgIklMN1IiLCJDQ1I3IiwiU0VMTCIsIlRDRjciLCJMVEIiLCJDRDI4IiwiQ0Q0MExHIiwKICAiVE5GUlNGNCIsIlRORlJTRjkiLCJJQ09TIiwiVE9YMiIsCgogICPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJMKICAjIDIuIEVYSEFVU1RJT04gLyBDSFJPTklDIEFDVElWQVRJT04KICAj4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCTCiAgIlBEQ0QxIiwiQ1RMQTQiLCJMQUczIiwiVElHSVQiLCJIQVZDUjIiLCJFTlRQRDEiLAogICJDRDI0NCIsIkNYQ0wxMyIsIlRPWCIsIkJBVEYiLAoKICAj4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCTCiAgIyAzLiBTw4laQVJZLVNQRUNJRklDIE1BTElHTkFOVCBTSUdOQVRVUkVTCiAgI+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAkwogICJHQVRBMyIsIklLWkYyIiwiVE9YIiwiVE9YMiIsIkRVU1A0IiwiQ0NSNCIsCiAgIktJUjNETDIiLCJLTFJCMSIsIkpVTiIsIkpVTkIiLCJGT1MiLCJGT1NCIiwiRFVTUDIiLAogICJDRDciLCJEUFA0IiwiQ0QyNiIsIkNEM0QiLCJDRDNFIiwiQ0QzRyIsCiAgIk5BTVBUIiwiTEFNUDMiLCJIU1BBMUEiLCJIU1BBMUIiLCJUTkZSU0YxQiIsCiAgIkZDUkwzIiwiSExBLURSQSIsIkhMQS1EUkIxIiwiQjJNIiwKCiAgI+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAkwogICMgNC4gTUFMSUdOQU5UIERPV05SRUdVTEFURUQgLyBUVU1PUiBTVVBQUkVTU0lPTiBMT1NTCiAgI+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAkwogICJTRUxMIiwiVENGNyIsIkNENyIsIkRQUDQiLCJTVEFUNCIsIkJBQ0gyIiwiQ0QyNiIsCiAgIkNENDVSQSIsIklMN1IiLCJDQ1I3IiwKCiAgI+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAkwogICMgNS4gVGgxIC8gVGgyIC8gVGgxNyAvIFRmaCBTVUJTRVQgTUFSS0VSUwogICPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJMKICAjIFRoMQogICJUQlgyMSIsIklGTkciLCJDWENSMyIsCiAgIyBUaDIKICAiR0FUQTMiLCJJTDQiLCJJTDUiLCJJTDEzIiwKICAjIFRoMTcKICAiUk9SQyIsIklMMTdBIiwiSUwxN0YiLCJDQ1I2IiwKICAjIFRmaAogICJCQ0w2IiwiQ1hDTDEzIiwiUERDRDEiLCJJQ09TIiwKCiAgI+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAkwogICMgNi4gVFJFRyBQQU5FTAogICPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJMKICAiRk9YUDMiLCJJTDJSQSIsIkNUTEE0IiwiVElHSVQiLCJJS1pGMiIsIkNDUjgiLCJUTkZSU0YxOCIsCgogICPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJMKICAjIDcuIENFTEwgQ1lDTEUgLyBQUk9MSUZFUkFUSU9OCiAgI+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAkwogICJNS0k2NyIsIlRPUDJBIiwiQ0VOUEYiLCJQQ05BIiwiTUNNNCIsIk1DTTYiLAogICJVQkUyQyIsIkNESzEiLCJBVVJLQSIsIkFVUktCIiwiQ0NOQjEiLCJDQ05CMiIsCgogICPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJMKICAjIDguIE1FVEFCT0xJQyAvIFNUUkVTUyBSRVNQT05TRSAoUkVMRVZBTlQgSU4gU1MpCiAgI+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAkwogICJOQU1QVCIsIkxHQUxTMyIsIkhTUDkwQUExIiwiSFNQQjEiLCJTT0QyIiwiVFhOIiwKCiAgI+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAk+KAkwogICMgOS4gQ1lUT0tJTkVTIC8gQ0hFTU9LSU5FUyBGUkVRVUVOVExZIEFDVElWRSBJTiBTUwogICPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJMKICAiQ0NMNSIsIkNDTDQiLCJDQ0wyMiIsIkNDTDE3IiwiSUwzMiIsIklMMiIsIklMNyIsCgogICPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJPigJMKICAjIDEwLiBDT05UQU1JTkFUSU9OIENPTlRST0wg4oCUIE1ZRUxPSUQgLyBOSyAvIEIKICAj4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCT4oCTCiAgIyBNeWVsb2lkCiAgIkxZWiIsIlMxMDBBOCIsIlMxMDBBOSIsIkNEMTQiLCJGQ0dSM0EiLCJNUzRBNyIsIkNENjgiLCJDRDE2MyIsIk1SQzEiLAogICMgTksKICAiTktHNyIsIkdOTFkiLCJLTFJEMSIsIlBSRjEiLCJHWk1CIiwiVFJEQyIsIlRSR0MyIiwiQ0QxNjAiLAogICMgQiBjZWxscyAvIHBsYXNtYQogICJNUzRBMSIsIkNENzlBIiwiQ0Q3OUIiLCJNWkIxIiwiSkNIQUlOIgopCgpGZWF0UGxvdF9jYW5vbmljYWwgPC0gbGFwcGx5KGFsbF9tYXJrZXJzX1NTLCBmdW5jdGlvbih4KXsKICAgIAogICAgbmFtZSA9IHgKICAgIHByaW50KG5hbWUpCiAgICBqcGVnKHBhc3RlMCgiaW1tdW5lX2ZlYXRQbG90XyIsIG5hbWUsICIuanBlZyIpLCB3aWR0aD0xMCwgaGVpZ2h0PTEwLCB1bml0cyA9ICdpbicsIHJlcyA9IDMwMCkKICAgIHByaW50KEZlYXR1cmVQbG90KEFsbF9zYW1wbGVzX01lcmdlZCwgZmVhdHVyZXMgPSB4LCByZWR1Y3Rpb24gPSAidW1hcCIsIGxhYmVsID0gVFJVRSwgbWluLmN1dG9mZiA9IDAsIGNvbHMgPSBjKCJuYXZ5Ymx1ZSIsICJkYXJrc2VhZ3JlZW4iLCJ5ZWxsb3ciLCJmaXJlYnJpY2sxIikpKQogICAgZGV2Lm9mZigpCiAgICAKfSkgCgpgYGAKCgojIyBGZWF0dXJlcGxvdHMKYGBge3IgLCAgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OH0KRGVmYXVsdEFzc2F5KEFsbF9zYW1wbGVzX01lcmdlZCkgPC0gIlNDVCIKSWRlbnRzKEFsbF9zYW1wbGVzX01lcmdlZCkgPC0gIm9yaWcuaWRlbnQiCgpsaWJyYXJ5KHZpcmlkaXMpCgpGZWF0UGxvdF9jYW5vbmljYWwgPC0gbGFwcGx5KGFsbF9tYXJrZXJzX1NTLCBmdW5jdGlvbihnZW5lKXsKCiAgICBtZXNzYWdlKCJQbG90dGluZzogIiwgZ2VuZSkKCiAgICAjIEV4dHJhY3QgZ2VuZSBleHByZXNzaW9uCiAgICBleHByIDwtIEZldGNoRGF0YShBbGxfc2FtcGxlc19NZXJnZWQsIHZhcnMgPSBnZW5lKVssIDFdCiAgICBleHByWyFpcy5maW5pdGUoZXhwcildIDwtIE5BICAgIyByZW1vdmUgSW5mLCBOYU4KCiAgICAjIENhc2UgMTogZ2VuZSBub3QgZXhwcmVzc2VkCiAgICBpZiAoYWxsKGlzLm5hKGV4cHIpKSB8fCBhbGwoZXhwciA9PSAwLCBuYS5ybSA9IFRSVUUpKSB7CgogICAgICAgIHdhcm5pbmcocGFzdGUwKCJHZW5lICIsIGdlbmUsICIgaGFzIHplcm8vTkEgZXhwcmVzc2lvbi4gUGxvdCB3aWxsIGJlIGJsYW5rLiIpKQoKICAgICAgICBwIDwtIEZlYXR1cmVQbG90KAogICAgICAgICAgICBBbGxfc2FtcGxlc19NZXJnZWQsCiAgICAgICAgICAgIGZlYXR1cmVzID0gZ2VuZSwKICAgICAgICAgICAgcmVkdWN0aW9uID0gInVtYXAiLAogICAgICAgICAgICBtaW4uY3V0b2ZmID0gTkEsCiAgICAgICAgICAgIG1heC5jdXRvZmYgPSBOQSwKICAgICAgICAgICAgbGFiZWwgPSBUUlVFCiAgICAgICAgKSArCiAgICAgICAgc2NhbGVfY29sb3VyX3ZpcmlkaXMob3B0aW9uID0gIm1hZ21hIiwgbmEudmFsdWUgPSAiZ3JleTkwIikgKwogICAgICAgIGdndGl0bGUocGFzdGUwKGdlbmUsICIgKG5vIGV4cHJlc3Npb24pIikpICsKICAgICAgICB0aGVtZV92b2lkKCkKCiAgICAgICAgcHJpbnQocCkKICAgICAgICByZXR1cm4oTlVMTCkKICAgIH0KCiAgICAjIENhc2UgMjogbm9ybWFsIGdlbmUg4oaSIE5PIHF1YW50aWxlIGN1dG9mZnMgKGF2b2lkcyB5b3VyIGVycm9yKQogICAgcCA8LSBGZWF0dXJlUGxvdCgKICAgICAgICBBbGxfc2FtcGxlc19NZXJnZWQsCiAgICAgICAgZmVhdHVyZXMgPSBnZW5lLAogICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwKICAgICAgICBtaW4uY3V0b2ZmID0gTkEsCiAgICAgICAgbWF4LmN1dG9mZiA9IE5BLAogICAgICAgIGxhYmVsID0gVFJVRQogICAgKSArCiAgICBzY2FsZV9jb2xvdXJfdmlyaWRpcyhvcHRpb24gPSAibWFnbWEiLCBuYS52YWx1ZSA9ICJncmV5OTAiKSArCiAgICBnZ3RpdGxlKGdlbmUpICsKICAgIHRoZW1lX3ZvaWQoKSArCiAgICB0aGVtZSgKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IgogICAgKQoKICAgIHByaW50KHApCn0pCgoKYGBgCgoKIyMgRmVhdHVyZXBsb3RzLUNsdXN0ZXJzCmBgYHtyICwgIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9CkRlZmF1bHRBc3NheShBbGxfc2FtcGxlc19NZXJnZWQpIDwtICJTQ1QiCklkZW50cyhBbGxfc2FtcGxlc19NZXJnZWQpIDwtICJzZXVyYXRfY2x1c3RlcnMiCgpsaWJyYXJ5KHZpcmlkaXMpCgpGZWF0UGxvdF9jYW5vbmljYWwgPC0gbGFwcGx5KGFsbF9tYXJrZXJzX1NTLCBmdW5jdGlvbihnZW5lKXsKCiAgICBtZXNzYWdlKCJQbG90dGluZzogIiwgZ2VuZSkKCiAgICAjIEV4dHJhY3QgZ2VuZSBleHByZXNzaW9uCiAgICBleHByIDwtIEZldGNoRGF0YShBbGxfc2FtcGxlc19NZXJnZWQsIHZhcnMgPSBnZW5lKVssIDFdCiAgICBleHByWyFpcy5maW5pdGUoZXhwcildIDwtIE5BICAgIyByZW1vdmUgSW5mLCBOYU4KCiAgICAjIENhc2UgMTogZ2VuZSBub3QgZXhwcmVzc2VkCiAgICBpZiAoYWxsKGlzLm5hKGV4cHIpKSB8fCBhbGwoZXhwciA9PSAwLCBuYS5ybSA9IFRSVUUpKSB7CgogICAgICAgIHdhcm5pbmcocGFzdGUwKCJHZW5lICIsIGdlbmUsICIgaGFzIHplcm8vTkEgZXhwcmVzc2lvbi4gUGxvdCB3aWxsIGJlIGJsYW5rLiIpKQoKICAgICAgICBwMiA8LSBGZWF0dXJlUGxvdCgKICAgICAgICAgICAgQWxsX3NhbXBsZXNfTWVyZ2VkLAogICAgICAgICAgICBmZWF0dXJlcyA9IGdlbmUsCiAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwKICAgICAgICAgICAgbWluLmN1dG9mZiA9IE5BLAogICAgICAgICAgICBtYXguY3V0b2ZmID0gTkEsCiAgICAgICAgICAgIGxhYmVsID0gVFJVRQogICAgICAgICkgKwogICAgICAgIHNjYWxlX2NvbG91cl92aXJpZGlzKG9wdGlvbiA9ICJtYWdtYSIsIG5hLnZhbHVlID0gImdyZXk5MCIpICsKICAgICAgICBnZ3RpdGxlKHBhc3RlMChnZW5lLCAiIChubyBleHByZXNzaW9uKSIpKSArCiAgICAgICAgdGhlbWVfdm9pZCgpCgogICAgICAgIHByaW50KHAyKQogICAgICAgIHJldHVybihOVUxMKQogICAgfQoKICAgICMgQ2FzZSAyOiBub3JtYWwgZ2VuZSDihpIgTk8gcXVhbnRpbGUgY3V0b2ZmcyAoYXZvaWRzIHlvdXIgZXJyb3IpCiAgICBwMiA8LSBGZWF0dXJlUGxvdCgKICAgICAgICBBbGxfc2FtcGxlc19NZXJnZWQsCiAgICAgICAgZmVhdHVyZXMgPSBnZW5lLAogICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwKICAgICAgICBtaW4uY3V0b2ZmID0gTkEsCiAgICAgICAgbWF4LmN1dG9mZiA9IE5BLAogICAgICAgIGxhYmVsID0gVFJVRQogICAgKSArCiAgICBzY2FsZV9jb2xvdXJfdmlyaWRpcyhvcHRpb24gPSAibWFnbWEiLCBuYS52YWx1ZSA9ICJncmV5OTAiKSArCiAgICBnZ3RpdGxlKGdlbmUpICsKICAgIHRoZW1lX3ZvaWQoKSArCiAgICB0aGVtZSgKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IgogICAgKQoKICAgIHByaW50KHAyKQp9KQoKCmBgYAo=