load libraries————————————

1. Load and Subset Normal CD4 T Cells


ctrl <- readRDS("../0-Seurat_RDS_OBJECT_FINAL/Seurat_object_Final_changes/All_samples_Merged_with_STCAT_Annotation_final-5-09-2025.rds")

Idents(ctrl) <- "seurat_clusters"
table(ctrl@active.ident)

   0    1    2    3    4    5    6    7    8    9   10   11   12   13 
6789 5275 4663 4661 4086 3634 3536 3409 3338 3273 3212 1675 1063  691 

2. Reference data


reference <- scPred::pbmc_1
reference
An object of class Seurat 
32838 features across 3500 samples within 1 assay 
Active assay: RNA (32838 features, 0 variable features)
 2 layers present: counts, data

Reference data




# Run SCTransform (normalization + variance stabilization)
reference <- SCTransform(reference, verbose = FALSE)

# Find variable features is done inside SCTransform, no need to run separately

# Run PCA on SCT assay
reference <- RunPCA(reference, assay = "SCT", verbose = FALSE, reduction.name = "pca")


# Run UMAP on PCA
reference <- RunUMAP(reference, dims = 1:30)
Using method 'umap'
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
DimPlot(reference, group.by = "cell_type", label = TRUE, repel = TRUE) + NoAxes()

Run all steps of the analysis for the ctrl sample as well


DimPlot(ctrl, group.by = "seurat_clusters", label = TRUE, repel = TRUE) + NoAxes()

3. Label transfer

# Set default assay to SCT
DefaultAssay(reference) <- "SCT"

# 1. Make sure SCT is the default assay in your query (ctrl)
DefaultAssay(ctrl) <- "SCT"

# 2. (Optional but recommended) Run SCTransform if not already done
# If you already normalized with SCTransform, you can skip this.
# ctrl <- SCTransform(ctrl, verbose = FALSE)

# 3. Find anchors between reference and query
transfer.anchors <- FindTransferAnchors(
    reference = reference,
    query = ctrl,
    normalization.method = "SCT",   # MUST be SCT
    reference.reduction = "pca",   # Azimuth references use spca
    dims = 1:30
)

# 4. Transfer annotations (cell types, etc.)
predictions <- TransferData(
    anchorset = transfer.anchors,
    refdata = reference$cell_type,  # column from reference metadata
    dims = 1:30
)
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
# 5. Add predictions back into your query object
ctrl <- AddMetaData(ctrl, metadata = predictions)

Dimplot-myumap


DimPlot(ctrl, group.by = "predicted.id", label = T, repel = T) + NoAxes()

barplot Distributions


ggplot(ctrl@meta.data, aes(x = seurat_clusters, fill = predicted.id)) +
    geom_bar() +
    theme_classic()

4. SinlgeR


  # Set default assay to SCT
  DefaultAssay(ctrl) <- "SCT"
  
  # Convert to SingleCellExperiment quietly
  sce <- as.SingleCellExperiment(ctrl)

Immune cell reference


 immune = celldex::DatabaseImmuneCellExpressionData()
singler.immune <- SingleR(test = sce, ref = immune, assay.type.test=1,
    labels = immune$label.fine)

head(singler.immune)

HPCA reference


hpca <- celldex::HumanPrimaryCellAtlasData()
singler.hpca <- SingleR(test = sce, ref = hpca, assay.type.test=1,
    labels = hpca$label.fine)

head(singler.hpca)

Compare results:


ctrl$singler.immune = singler.immune$pruned.labels
ctrl$singler.hpca = singler.hpca$pruned.labels


DimPlot(ctrl, group.by = c("singler.hpca", "singler.immune"), ncol = 2, label = T, label.box = T, repel = T)

Compare results:


ctrl$singler.immune = singler.immune$pruned.labels
ctrl$singler.hpca = singler.hpca$pruned.labels


DimPlot(ctrl, group.by = c("singler.hpca", "singler.immune"), ncol = 2, label = F, label.box = F, repel = T)

5. Azimuth

# options(future.globals.maxSize = 1e9)
# 
# library(SeuratData)
# 
# DefaultAssay(ctrl) <- "SCT"
# 
# ctrl <- RunAzimuth(ctrl, reference = "pbmcref")

Azimuth Dimplot

DimPlot(ctrl, group.by = "predicted.celltype.l1", label = T, repel = T) + NoAxes()


DimPlot(ctrl, group.by = "predicted.celltype.l2", label = T, repel = T) + NoAxes()


DimPlot(ctrl, group.by = "predicted.celltype.l3", label = T, repel = T) + NoAxes()

6. ProjectTils Annotation_CD4T_human_ref_v1

#reference atlas
 DimPlot(ref, label = T)

#Visualize projection
 plot.projection(ref, query.projected, linesize = 0.5, pointsize = 0.5)


 #Plot the predicted composition of the query in terms of reference T cell subtypes
 plot.statepred.composition(ref, query.projected, metric = "Percent")




# Now you can plot
DimPlot(ctrl, group.by = "functional.cluster", 
        reduction = "umap",
        label.size = 3,
        repel = TRUE,
        label = FALSE)

NA
NA

7. Compare results


crossTab(ctrl, "predicted.id", "singler.hpca")

crossTab(ctrl, "predicted.id", "singler.immune")

crossTab(ctrl, "singler.hpca", "singler.immune")

crossTab(ctrl, "predicted.id", "predicted.celltype.l1")

crossTab(ctrl, "predicted.celltype.l2", "functional.cluster")

crossTab(ctrl, "Prediction", "functional.cluster")
NA

Compare results


wrap_plots(
    DimPlot(ctrl, label = T, group.by = "predicted.id") + NoAxes() + ggtitle("LabelTransfer"),
    DimPlot(ctrl, label = F, group.by = "singler.hpca" ) + NoAxes() + ggtitle("SingleR HPCA"),
    DimPlot(ctrl, label = F, group.by = "singler.immune") + NoAxes() + ggtitle("SingleR Ref"),
    DimPlot(ctrl, label = T, group.by = "predicted.celltype.l1") + NoAxes() + ggtitle("Azimuth l1"),
    ncol = 2
)

Compare results


wrap_plots(
    DimPlot(ctrl, label = T, group.by = "predicted.id") + NoAxes() + ggtitle("LabelTransfer"),
    DimPlot(ctrl, label = F, group.by = "singler.hpca") + NoAxes() + ggtitle("SingleR HPCA"),
    DimPlot(ctrl, label = F, group.by = "singler.immune") + NoAxes() + ggtitle("SingleR Ref"),
    DimPlot(ctrl, label = F, group.by = "predicted.celltype.l2") + NoAxes() + ggtitle("LabelTransfer"),
    DimPlot(ctrl, label = T, group.by = "functional.cluster") + NoAxes() + ggtitle("ProjecTils CD4"),
    DimPlot(ctrl, label = F, group.by = "Prediction") + NoAxes() + ggtitle("STCAT"),
    ncol = 2
)

8. save all the annotation in object into RDS


# Save the Seurat object with all annotations
saveRDS(ctrl, file = "All_samples_Merged_with_all_annotations_ATLAS-18-09-2025.rds")
LS0tCnRpdGxlOiAiQ2VsbHR5cGUgUHJlZGljdGlvbiB1c2luZyBkaWZmZXJlbnQgUmVmZXJlbmNlcy0xOC0wOS0yMDI1IgphdXRob3I6IE5hc2lyIE1haG1vb2QgQWJiYXNpCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogICNybWRmb3JtYXRzOjpyZWFkdGhlZG93bgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdG9jX2NvbGxhcHNlZDogdHJ1ZQotLS0KCgojIyBsb2FkIGxpYnJhcmllcy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KCiAgICBsaWJyYXJ5KFNldXJhdCkKICAgIGxpYnJhcnkoZHBseXIpCiAgICBsaWJyYXJ5KHBhdGNod29yaykKICAgIGxpYnJhcnkoZ2dwbG90MikKICAgIGxpYnJhcnkocGhlYXRtYXApCiAgICBsaWJyYXJ5KHNjUHJlZCkKICAgIGxpYnJhcnkoY2VsbGRleCkKICAgIGxpYnJhcnkoU2luZ2xlUikKICAgIGxpYnJhcnkocmVtb3RlcykKICAgIGxpYnJhcnkocHJlc3RvKQogICAgbGlicmFyeShTZXVyYXREaXNrKQogICAgbGlicmFyeShTZXVyYXREYXRhKQogICAgbGlicmFyeShBemltdXRoKQoKYGBgCgoKIyAxLiBMb2FkIGFuZCBTdWJzZXQgTm9ybWFsIENENCBUIENlbGxzCmBgYHtyIGxvYWRTZXVyYXR9CgpjdHJsIDwtIHJlYWRSRFMoIi4uLzAtU2V1cmF0X1JEU19PQkpFQ1RfRklOQUwvU2V1cmF0X29iamVjdF9GaW5hbF9jaGFuZ2VzL0FsbF9zYW1wbGVzX01lcmdlZF93aXRoX1NUQ0FUX0Fubm90YXRpb25fZmluYWwtNS0wOS0yMDI1LnJkcyIpCgpJZGVudHMoY3RybCkgPC0gInNldXJhdF9jbHVzdGVycyIKdGFibGUoY3RybEBhY3RpdmUuaWRlbnQpCgoKYGBgCgoKIyAyLiBSZWZlcmVuY2UgZGF0YQpgYGB7cn0KCnJlZmVyZW5jZSA8LSBzY1ByZWQ6OnBibWNfMQpyZWZlcmVuY2UKCmBgYAoKCiMjIFJlZmVyZW5jZSBkYXRhCmBgYHtyfQoKCgojIFJ1biBTQ1RyYW5zZm9ybSAobm9ybWFsaXphdGlvbiArIHZhcmlhbmNlIHN0YWJpbGl6YXRpb24pCnJlZmVyZW5jZSA8LSBTQ1RyYW5zZm9ybShyZWZlcmVuY2UsIHZlcmJvc2UgPSBGQUxTRSkKCiMgRmluZCB2YXJpYWJsZSBmZWF0dXJlcyBpcyBkb25lIGluc2lkZSBTQ1RyYW5zZm9ybSwgbm8gbmVlZCB0byBydW4gc2VwYXJhdGVseQoKIyBSdW4gUENBIG9uIFNDVCBhc3NheQpyZWZlcmVuY2UgPC0gUnVuUENBKHJlZmVyZW5jZSwgYXNzYXkgPSAiU0NUIiwgdmVyYm9zZSA9IEZBTFNFLCByZWR1Y3Rpb24ubmFtZSA9ICJwY2EiKQoKCiMgUnVuIFVNQVAgb24gUENBCnJlZmVyZW5jZSA8LSBSdW5VTUFQKHJlZmVyZW5jZSwgZGltcyA9IDE6MzApCgoKRGltUGxvdChyZWZlcmVuY2UsIGdyb3VwLmJ5ID0gImNlbGxfdHlwZSIsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFKSArIE5vQXhlcygpCgpgYGAKCiMjIFJ1biBhbGwgc3RlcHMgb2YgdGhlIGFuYWx5c2lzIGZvciB0aGUgY3RybCBzYW1wbGUgYXMgd2VsbApgYGB7cn0KCkRpbVBsb3QoY3RybCwgZ3JvdXAuYnkgPSAic2V1cmF0X2NsdXN0ZXJzIiwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUpICsgTm9BeGVzKCkKCmBgYAoKIyAzLiBMYWJlbCB0cmFuc2ZlcgpgYGB7cn0KIyBTZXQgZGVmYXVsdCBhc3NheSB0byBTQ1QKRGVmYXVsdEFzc2F5KHJlZmVyZW5jZSkgPC0gIlNDVCIKCiMgMS4gTWFrZSBzdXJlIFNDVCBpcyB0aGUgZGVmYXVsdCBhc3NheSBpbiB5b3VyIHF1ZXJ5IChjdHJsKQpEZWZhdWx0QXNzYXkoY3RybCkgPC0gIlNDVCIKCiMgMi4gKE9wdGlvbmFsIGJ1dCByZWNvbW1lbmRlZCkgUnVuIFNDVHJhbnNmb3JtIGlmIG5vdCBhbHJlYWR5IGRvbmUKIyBJZiB5b3UgYWxyZWFkeSBub3JtYWxpemVkIHdpdGggU0NUcmFuc2Zvcm0sIHlvdSBjYW4gc2tpcCB0aGlzLgojIGN0cmwgPC0gU0NUcmFuc2Zvcm0oY3RybCwgdmVyYm9zZSA9IEZBTFNFKQoKIyAzLiBGaW5kIGFuY2hvcnMgYmV0d2VlbiByZWZlcmVuY2UgYW5kIHF1ZXJ5CnRyYW5zZmVyLmFuY2hvcnMgPC0gRmluZFRyYW5zZmVyQW5jaG9ycygKICAgIHJlZmVyZW5jZSA9IHJlZmVyZW5jZSwKICAgIHF1ZXJ5ID0gY3RybCwKICAgIG5vcm1hbGl6YXRpb24ubWV0aG9kID0gIlNDVCIsICAgIyBNVVNUIGJlIFNDVAogICAgcmVmZXJlbmNlLnJlZHVjdGlvbiA9ICJwY2EiLCAgICMgQXppbXV0aCByZWZlcmVuY2VzIHVzZSBzcGNhCiAgICBkaW1zID0gMTozMAopCgojIDQuIFRyYW5zZmVyIGFubm90YXRpb25zIChjZWxsIHR5cGVzLCBldGMuKQpwcmVkaWN0aW9ucyA8LSBUcmFuc2ZlckRhdGEoCiAgICBhbmNob3JzZXQgPSB0cmFuc2Zlci5hbmNob3JzLAogICAgcmVmZGF0YSA9IHJlZmVyZW5jZSRjZWxsX3R5cGUsICAjIGNvbHVtbiBmcm9tIHJlZmVyZW5jZSBtZXRhZGF0YQogICAgZGltcyA9IDE6MzAKKQoKIyA1LiBBZGQgcHJlZGljdGlvbnMgYmFjayBpbnRvIHlvdXIgcXVlcnkgb2JqZWN0CmN0cmwgPC0gQWRkTWV0YURhdGEoY3RybCwgbWV0YWRhdGEgPSBwcmVkaWN0aW9ucykKCgpgYGAKCgojIyBEaW1wbG90LW15dW1hcApgYGB7cn0KCkRpbVBsb3QoY3RybCwgZ3JvdXAuYnkgPSAicHJlZGljdGVkLmlkIiwgbGFiZWwgPSBULCByZXBlbCA9IFQpICsgTm9BeGVzKCkKCmBgYAojIyBiYXJwbG90IERpc3RyaWJ1dGlvbnMKYGBge3J9CgpnZ3Bsb3QoY3RybEBtZXRhLmRhdGEsIGFlcyh4ID0gc2V1cmF0X2NsdXN0ZXJzLCBmaWxsID0gcHJlZGljdGVkLmlkKSkgKwogICAgZ2VvbV9iYXIoKSArCiAgICB0aGVtZV9jbGFzc2ljKCkKCmBgYAoKCiMgNC4gU2lubGdlUgpgYGB7cn0KCiAgIyBTZXQgZGVmYXVsdCBhc3NheSB0byBTQ1QKICBEZWZhdWx0QXNzYXkoY3RybCkgPC0gIlNDVCIKICAKICAjIENvbnZlcnQgdG8gU2luZ2xlQ2VsbEV4cGVyaW1lbnQgcXVpZXRseQogIHNjZSA8LSBhcy5TaW5nbGVDZWxsRXhwZXJpbWVudChjdHJsKQoKYGBgCgoKCgoKIyMgSW1tdW5lIGNlbGwgcmVmZXJlbmNlCmBgYHtyfQoKIGltbXVuZSA9IGNlbGxkZXg6OkRhdGFiYXNlSW1tdW5lQ2VsbEV4cHJlc3Npb25EYXRhKCkKc2luZ2xlci5pbW11bmUgPC0gU2luZ2xlUih0ZXN0ID0gc2NlLCByZWYgPSBpbW11bmUsIGFzc2F5LnR5cGUudGVzdD0xLAogICAgbGFiZWxzID0gaW1tdW5lJGxhYmVsLmZpbmUpCgpoZWFkKHNpbmdsZXIuaW1tdW5lKQoKYGBgCgoKCgoKCiMjIEhQQ0EgcmVmZXJlbmNlCmBgYHtyfQoKaHBjYSA8LSBjZWxsZGV4OjpIdW1hblByaW1hcnlDZWxsQXRsYXNEYXRhKCkKc2luZ2xlci5ocGNhIDwtIFNpbmdsZVIodGVzdCA9IHNjZSwgcmVmID0gaHBjYSwgYXNzYXkudHlwZS50ZXN0PTEsCiAgICBsYWJlbHMgPSBocGNhJGxhYmVsLmZpbmUpCgpoZWFkKHNpbmdsZXIuaHBjYSkKCmBgYAoKCiMjIENvbXBhcmUgcmVzdWx0czoKYGBge3IsICBmaWcuaGVpZ2h0PSA2LCBmaWcud2lkdGg9IDIwfQoKY3RybCRzaW5nbGVyLmltbXVuZSA9IHNpbmdsZXIuaW1tdW5lJHBydW5lZC5sYWJlbHMKY3RybCRzaW5nbGVyLmhwY2EgPSBzaW5nbGVyLmhwY2EkcHJ1bmVkLmxhYmVscwoKCkRpbVBsb3QoY3RybCwgZ3JvdXAuYnkgPSBjKCJzaW5nbGVyLmhwY2EiLCAic2luZ2xlci5pbW11bmUiKSwgbmNvbCA9IDIsIGxhYmVsID0gVCwgbGFiZWwuYm94ID0gVCwgcmVwZWwgPSBUKQoKYGBgCgojIyBDb21wYXJlIHJlc3VsdHM6CmBgYHtyLCBmaWcuaGVpZ2h0PSA2LCBmaWcud2lkdGg9IDIwfQoKY3RybCRzaW5nbGVyLmltbXVuZSA9IHNpbmdsZXIuaW1tdW5lJHBydW5lZC5sYWJlbHMKY3RybCRzaW5nbGVyLmhwY2EgPSBzaW5nbGVyLmhwY2EkcHJ1bmVkLmxhYmVscwoKCkRpbVBsb3QoY3RybCwgZ3JvdXAuYnkgPSBjKCJzaW5nbGVyLmhwY2EiLCAic2luZ2xlci5pbW11bmUiKSwgbmNvbCA9IDIsIGxhYmVsID0gRiwgbGFiZWwuYm94ID0gRiwgcmVwZWwgPSBUKQoKYGBgCgoKIyA1LiBBemltdXRoCmBgYHtyfQojIG9wdGlvbnMoZnV0dXJlLmdsb2JhbHMubWF4U2l6ZSA9IDFlOSkKIyAKIyBsaWJyYXJ5KFNldXJhdERhdGEpCiMgCiMgRGVmYXVsdEFzc2F5KGN0cmwpIDwtICJTQ1QiCiMgCiMgY3RybCA8LSBSdW5BemltdXRoKGN0cmwsIHJlZmVyZW5jZSA9ICJwYm1jcmVmIikKCmBgYAoKIyMgQXppbXV0aCBEaW1wbG90CmBgYHtyLCBmaWcuaGVpZ2h0PSA2LCBmaWcud2lkdGg9IDEwfQpEaW1QbG90KGN0cmwsIGdyb3VwLmJ5ID0gInByZWRpY3RlZC5jZWxsdHlwZS5sMSIsIGxhYmVsID0gVCwgcmVwZWwgPSBUKSArIE5vQXhlcygpCgpEaW1QbG90KGN0cmwsIGdyb3VwLmJ5ID0gInByZWRpY3RlZC5jZWxsdHlwZS5sMiIsIGxhYmVsID0gVCwgcmVwZWwgPSBUKSArIE5vQXhlcygpCgpEaW1QbG90KGN0cmwsIGdyb3VwLmJ5ID0gInByZWRpY3RlZC5jZWxsdHlwZS5sMyIsIGxhYmVsID0gVCwgcmVwZWwgPSBUKSArIE5vQXhlcygpCgpgYGAKCgoKIyA2LiBQcm9qZWN0VGlscyBBbm5vdGF0aW9uX0NENFRfaHVtYW5fcmVmX3YxCmBgYHtyfQpsaWJyYXJ5KFNUQUNBUykKbGlicmFyeShQcm9qZWNUSUxzKQoKCiNMb2FkIHJlZmVyZW5jZSBhdGxhcyBhbmQgcXVlcnkgZGF0YQogcmVmIDwtIHJlYWRSRFMoZmlsZSA9ICJDRDRUX2h1bWFuX3JlZl92MS5yZHMiKQoKY3RybCA8LSBQcm9qZWNUSUxzLmNsYXNzaWZpZXIocXVlcnkgPSBjdHJsLCByZWYgPSByZWYpCgoKI3JlZmVyZW5jZSBhdGxhcwogRGltUGxvdChyZWYsIGxhYmVsID0gVCkKCiNWaXN1YWxpemUgcHJvamVjdGlvbgogcGxvdC5wcm9qZWN0aW9uKHJlZiwgcXVlcnkucHJvamVjdGVkLCBsaW5lc2l6ZSA9IDAuNSwgcG9pbnRzaXplID0gMC41KQoKICNQbG90IHRoZSBwcmVkaWN0ZWQgY29tcG9zaXRpb24gb2YgdGhlIHF1ZXJ5IGluIHRlcm1zIG9mIHJlZmVyZW5jZSBUIGNlbGwgc3VidHlwZXMKIHBsb3Quc3RhdGVwcmVkLmNvbXBvc2l0aW9uKHJlZiwgcXVlcnkucHJvamVjdGVkLCBtZXRyaWMgPSAiUGVyY2VudCIpCgoKCiMgTm93IHlvdSBjYW4gcGxvdApEaW1QbG90KGN0cmwsIGdyb3VwLmJ5ID0gImZ1bmN0aW9uYWwuY2x1c3RlciIsIAogICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwKICAgICAgICBsYWJlbC5zaXplID0gMywKICAgICAgICByZXBlbCA9IFRSVUUsCiAgICAgICAgbGFiZWwgPSBGQUxTRSkKIAogCgpgYGAKCgojIDcuIENvbXBhcmUgcmVzdWx0cwpgYGB7cn0KCmNyb3NzVGFiKGN0cmwsICJwcmVkaWN0ZWQuaWQiLCAic2luZ2xlci5ocGNhIikKCmNyb3NzVGFiKGN0cmwsICJwcmVkaWN0ZWQuaWQiLCAic2luZ2xlci5pbW11bmUiKQoKY3Jvc3NUYWIoY3RybCwgInNpbmdsZXIuaHBjYSIsICJzaW5nbGVyLmltbXVuZSIpCgpjcm9zc1RhYihjdHJsLCAicHJlZGljdGVkLmlkIiwgInByZWRpY3RlZC5jZWxsdHlwZS5sMSIpCgpjcm9zc1RhYihjdHJsLCAicHJlZGljdGVkLmNlbGx0eXBlLmwyIiwgImZ1bmN0aW9uYWwuY2x1c3RlciIpCgpjcm9zc1RhYihjdHJsLCAiUHJlZGljdGlvbiIsICJmdW5jdGlvbmFsLmNsdXN0ZXIiKQoKYGBgCgojIyAgQ29tcGFyZSByZXN1bHRzCmBgYHtyLCBmaWcuaGVpZ2h0PSA4LCBmaWcud2lkdGg9IDIwfQoKd3JhcF9wbG90cygKICAgIERpbVBsb3QoY3RybCwgbGFiZWwgPSBULCBncm91cC5ieSA9ICJwcmVkaWN0ZWQuaWQiKSArIE5vQXhlcygpICsgZ2d0aXRsZSgiTGFiZWxUcmFuc2ZlciIpLAogICAgRGltUGxvdChjdHJsLCBsYWJlbCA9IEYsIGdyb3VwLmJ5ID0gInNpbmdsZXIuaHBjYSIgKSArIE5vQXhlcygpICsgZ2d0aXRsZSgiU2luZ2xlUiBIUENBIiksCiAgICBEaW1QbG90KGN0cmwsIGxhYmVsID0gRiwgZ3JvdXAuYnkgPSAic2luZ2xlci5pbW11bmUiKSArIE5vQXhlcygpICsgZ2d0aXRsZSgiU2luZ2xlUiBSZWYiKSwKICAgIERpbVBsb3QoY3RybCwgbGFiZWwgPSBULCBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDEiKSArIE5vQXhlcygpICsgZ2d0aXRsZSgiQXppbXV0aCBsMSIpLAogICAgbmNvbCA9IDIKKQoKYGBgCgoKIyMgIENvbXBhcmUgcmVzdWx0cwpgYGB7ciwgZmlnLmhlaWdodD0gMTIsIGZpZy53aWR0aD0gMjB9Cgp3cmFwX3Bsb3RzKAogICAgRGltUGxvdChjdHJsLCBsYWJlbCA9IFQsIGdyb3VwLmJ5ID0gInByZWRpY3RlZC5pZCIpICsgTm9BeGVzKCkgKyBnZ3RpdGxlKCJMYWJlbFRyYW5zZmVyIiksCiAgICBEaW1QbG90KGN0cmwsIGxhYmVsID0gRiwgZ3JvdXAuYnkgPSAic2luZ2xlci5ocGNhIikgKyBOb0F4ZXMoKSArIGdndGl0bGUoIlNpbmdsZVIgSFBDQSIpLAogICAgRGltUGxvdChjdHJsLCBsYWJlbCA9IEYsIGdyb3VwLmJ5ID0gInNpbmdsZXIuaW1tdW5lIikgKyBOb0F4ZXMoKSArIGdndGl0bGUoIlNpbmdsZVIgUmVmIiksCiAgICBEaW1QbG90KGN0cmwsIGxhYmVsID0gRiwgZ3JvdXAuYnkgPSAicHJlZGljdGVkLmNlbGx0eXBlLmwyIikgKyBOb0F4ZXMoKSArIGdndGl0bGUoIkxhYmVsVHJhbnNmZXIiKSwKICAgIERpbVBsb3QoY3RybCwgbGFiZWwgPSBULCBncm91cC5ieSA9ICJmdW5jdGlvbmFsLmNsdXN0ZXIiKSArIE5vQXhlcygpICsgZ2d0aXRsZSgiUHJvamVjVGlscyBDRDQiKSwKICAgIERpbVBsb3QoY3RybCwgbGFiZWwgPSBGLCBncm91cC5ieSA9ICJQcmVkaWN0aW9uIikgKyBOb0F4ZXMoKSArIGdndGl0bGUoIlNUQ0FUIiksCiAgICBuY29sID0gMgopCgpgYGAKCiMgOC4gc2F2ZSBhbGwgdGhlIGFubm90YXRpb24gaW4gb2JqZWN0IGludG8gUkRTCmBgYHtyfQoKIyBTYXZlIHRoZSBTZXVyYXQgb2JqZWN0IHdpdGggYWxsIGFubm90YXRpb25zCnNhdmVSRFMoY3RybCwgZmlsZSA9ICJBbGxfc2FtcGxlc19NZXJnZWRfd2l0aF9hbGxfYW5ub3RhdGlvbnNfQVRMQVMtMTgtMDktMjAyNS5yZHMiKQoKYGBgCg==