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()
})
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)
})
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=