load libraries————————————
1. Read Seurat object (STCAT annotated and Cleaned)
All_samples_Merged <- readRDS("../All_samples_Merged_with_STCAT_and_cleaned.rds")
pbmc <- All_samples_Merged
rm(All_samples_Merged)
gc()
used (Mb) gc trigger (Mb) max used (Mb)
Ncells 8412352 449.3 15367708 820.8 11293490 603.2
Vcells 1227843168 9367.7 1529678067 11670.6 1244138755 9492.1
2. Visualizing Clusters
library(Seurat)
library(SeuratExtend)
Idents(pbmc) <- "Prediction"
# Visualizing cell clusters using DimPlot2
DimPlot2(pbmc, theme = theme_umap_arrows())

3. Visualizing Clusters
library(Seurat)
library(SeuratExtend)
Idents(pbmc) <- "Prediction"
# Visualizing cell Annotations using DimPlot2
DimPlot2(pbmc, theme = theme_umap_arrows())

Idents(pbmc) <- "orig.ident"
# Visualizing cell Annotations using DimPlot2
DimPlot2(pbmc, theme = theme_umap_arrows())

Idents(pbmc) <- "seurat_clusters"
# Visualizing cell Annotations using DimPlot2
DimPlot2(pbmc, theme = theme_umap_arrows())

4. Analyzing Cluster Distribution
# Cluster distribution bar plot
ClusterDistrBar(pbmc$orig.ident, pbmc$seurat_clusters)

# Annotations distribution bar plot
ClusterDistrBar(pbmc$orig.ident, pbmc$Prediction)

# Annotations distribution bar plot
ClusterDistrBar(pbmc$Patient_origin, pbmc$Prediction)

5. Marker Gene Analysis with Heatmap
# To examine the marker genes of each cluster and visualize them using a heatmap:
# Calculating z-scores for variable features
# genes.zscore1 <- CalcStats(
# pbmc,
# features = VariableFeatures(pbmc),
# group.by = "orig.ident",
# order = "p",
# n = 5)
# Displaying heatmap
Heatmap(genes.zscore1, lab_fill = "zscore")
Using id as id variables

# Calculating z-scores for variable features
# genes.zscore2 <- CalcStats(
# pbmc,
# features = VariableFeatures(pbmc),
# group.by = "seurat_clusters",
# order = "p",
# n = 5)
# Displaying heatmap
Heatmap(genes.zscore2, lab_fill = "zscore")
Using id as id variables

# Calculating z-scores for variable features
# genes.zscore3 <- CalcStats(
# pbmc,
# features = VariableFeatures(pbmc),
# group.by = "Prediction",
# order = "p",
# n = 5)
#
# Displaying heatmap
Heatmap(genes.zscore3, lab_fill = "zscore")
Using id as id variables

gc()
used (Mb) gc trigger (Mb) max used (Mb)
Ncells 11061468 590.8 19580058 1045.7 19580058 1045.7
Vcells 1243153300 9484.6 2386909928 18210.7 2386909513 18210.7
6. Enhanced Dot Plots (New in v1.1.0)
Idents(pbmc) <- "orig.ident"
# Create grouped features
grouped_features <- list(
"B_cell_markers" = c("MS4A1", "CD79A"),
"T_cell_markers" = c("CD3D", "CD8A", "IL7R"),
"Myeloid_markers" = c("CD14", "FCGR3A", "S100A8")
)
DotPlot2(pbmc, features = grouped_features)

Idents(pbmc) <- "seurat_clusters"
# Create grouped features
grouped_features <- list(
"B_cell_markers" = c("MS4A1", "CD79A"),
"T_cell_markers" = c("CD3D", "CD8A", "IL7R"),
"Myeloid_markers" = c("CD14", "FCGR3A", "S100A8")
)
DotPlot2(pbmc, features = grouped_features)

Idents(pbmc) <- "Prediction"
# Create grouped features
grouped_features <- list(
"B_cell_markers" = c("MS4A1", "CD79A"),
"T_cell_markers" = c("CD3D", "CD8A", "IL7R"),
"Myeloid_markers" = c("CD14", "FCGR3A", "S100A8")
)
DotPlot2(pbmc, features = grouped_features)

##. Enhanced Dot Plots (New in v1.1.0)
# Create grouped features
grouped_features_T <- list(
"Naive_T" = c("CCR7", "SELL", "LEF1", "TCF7"),
"Tcm" = c("CCR7", "IL7R", "CD62L"),
"Tem" = c("GZMK", "CXCR3", "KLRG1"),
"Temra" = c("GZMB", "PRF1", "KLRG1"),
"Treg" = c("FOXP3", "IL2RA", "IKZF2", "TIGIT"),
"Tfh" = c("CXCR5", "BCL6", "PDCD1", "ICOS"),
"Th17" = c("RORC", "IL17A", "IL23R"),
"Tex" = c("PDCD1", "TOX", "LAG3", "CTLA4"),
"Trm" = c("ITGAE", "CD69", "ZNF683"),
"Tisg" = c("ISG15", "IFI6", "MX1", "IFIT3"),
"Proliferation" = c("MKI67", "TOP2A", "STMN1"),
"Cell_Death" = c("BAX", "CASP3", "DFFA", "BCL2L11"),
"Adhesion" = c("ITGAL", "ICAM1", "CD44", "SELL"),
"Activated" = c("CD38", "HLA-DRA", "TNFRSF9", "IL2RA")
)
Idents(pbmc) <- "orig.ident"
DotPlot2(pbmc, features = grouped_features_T)
Warning: The following requested variables were not found: CD62LWarning: Removing duplicate features (keeping first occurrence): CCR7, KLRG1, PDCD1, SELL, IL2RA

Idents(pbmc) <- "seurat_clusters"
DotPlot2(pbmc, features = grouped_features_T)
Warning: The following requested variables were not found: CD62LWarning: Removing duplicate features (keeping first occurrence): CCR7, KLRG1, PDCD1, SELL, IL2RA

Idents(pbmc) <- "Prediction"
DotPlot2(pbmc, features = grouped_features_T)
Warning: The following requested variables were not found: CD62LWarning: Removing duplicate features (keeping first occurrence): CCR7, KLRG1, PDCD1, SELL, IL2RA

7. Analyzing Cluster Distribution
# Specifying genes and cells of interest
genes <- c("SELL", "IL2RA", "CD8A", "TOP2A")
cells <- WhichCells(pbmc, idents = c("CD4 Tn", "CD4 Treg", "CD4 Trm", "CD4 proliferation"))
# Violin plot with statistical analysis
VlnPlot2(
pbmc,
features = genes,
group.by = "Prediction",
cells = cells,
stat.method = "wilcox.test")

Displaying three markers on a single UMAP
FeaturePlot3(pbmc, feature.1 = "CD3D", feature.2 = "CD7", feature.3 = "CD8A", pt.size = 1)


FeaturePlot3(pbmc, feature.1 = "IL2RA", feature.2 = "CD69", feature.3 = "FOXP3", pt.size = 1)

FeaturePlot3(pbmc, feature.1 = "LAG3", feature.2 = "PDCD1", feature.3 = "CTLA4", pt.size = 1)

8. Create a basic volcano plot comparing two cell types:
Idents(pbmc) <- "Prediction"
VolcanoPlot(pbmc,
ident.1 = "CD4 Tn",
ident.2 = "CD4 Trm")
Warning: sparse->dense coercion: allocating vector of size 9.6 GiB
9. Conducting Geneset Enrichment Analysis (GSEA)
go_zscore <- CalcStats(
matr,
f = pbmc$orig.ident,
order = "p",
n = 3)
Heatmap(go_zscore, lab_fill = "zscore")
Using id as id variables

go_zscore <- CalcStats(
matr,
f = pbmc$seurat_clusters,
order = "p",
n = 3)
Heatmap(go_zscore, lab_fill = "zscore")
Using id as id variables

Conducting Geneset Enrichment Analysis (GSEA)
go_zscore <- CalcStats(
matr,
f = pbmc$Prediction,
order = "p",
n = 3)
Heatmap(go_zscore, lab_fill = "zscore")
Using id as id variables

9. Importing and Visualizing SCENIC Analysis
# Downloading a pre-computed SCENIC loom file
scenic_loom_path <- file.path(tempdir(), "pyscenic_integrated-output.loom")
download.file("https://zenodo.org/records/10944066/files/pbmc3k_small_pyscenic_integrated-output.loom", scenic_loom_path, mode = "wb")
trying URL 'https://zenodo.org/records/10944066/files/pbmc3k_small_pyscenic_integrated-output.loom'
Content type 'application/octet-stream' length 33355070 bytes (31.8 MB)
==================================================
downloaded 31.8 MB
# Importing SCENIC Loom Files into Seurat
pbmc <- ImportPyscenicLoom(scenic_loom_path, seu = pbmc)
Warning: Skipping validation step, some fields are not populatedError in ImportPyscenicLoom(scenic_loom_path, seu = pbmc) :
Loom file and Seurat object have different cell numbers
Displaying three markers on a single UMAP
library(Seurat)
library(SeuratExtend)
FeaturePlot3(pbmc, feature.1 = "CD3D", feature.2 = "CD7", feature.3 = "CD8A", pt.size = 1, dark.theme = TRUE)


FeaturePlot3(pbmc, feature.1 = "IL2RA", feature.2 = "CD69", feature.3 = "FOXP3", pt.size = 1, dark.theme = TRUE)

FeaturePlot3(pbmc, feature.1 = "LAG3", feature.2 = "PDCD1", feature.3 = "CTLA4", pt.size = 1, dark.theme = TRUE)

10. New ClusterDistrPlot Function
pbmc$condition <- ifelse(
pbmc$orig.ident %in% paste0("L", 1:7), # Malignant samples L1 to L7
"Malignant",
ifelse(
pbmc$orig.ident %in% c("CD4T_lab", "CD4T_10x"), # Healthy samples
"Healthy",
"Other" # for any other samples, if present
)
)
# Convert to factor with Malignant first, Healthy second
pbmc$condition <- factor(pbmc$condition, levels = c("Malignant", "Healthy"))
# Compare cluster distribution between conditions
ClusterDistrPlot(
origin = pbmc$orig.ident,
cluster = pbmc$Prediction,
condition = pbmc$condition
)
Attaching package: ‘rlist’
The following object is masked from ‘package:S4Vectors’:
List
The 'I want hue' color presets were generated from: https://medialab.github.io/iwanthue/
This message is shown once per session

11. Enhanced Log Fold Change Options in Differential Analysis
Plots
# Using log base 2 for fold change calculations in WaterfallPlot
WaterfallPlot(
pbmc,
group.by = "Prediction",
features = VariableFeatures(pbmc)[1:80],
ident.1 = "CD4 Tn",
ident.2 = "CD4 Trm",
length = "logFC",
log.base = "2", # Use log2 instead of natural log
top.n = 20)
Warning: no non-missing arguments to min; returning InfWarning: no non-missing arguments to max; returning -InfData range detected as 0-1. Using pseudocount = 0.01 for logFC calculation.
Warning: no non-missing arguments to max; returning -Inf
Error in `fortify()`:
! `data` must be a <data.frame>, or an object coercible by `fortify()`, or a valid
<data.frame>-like object coercible by `as.data.frame()`.
Caused by error in `.prevalidate_data_frame_like_object()`:
! `dim(data)` must return an <integer> of length 2.
Run `]8;;x-r-run:rlang::last_trace()rlang::last_trace()]8;;` to see where the error occurred.
Save the RDS after changes
saveRDS(All_samples_Merged, file = "STCAT_Annotation/All_samples_Merged_with_STCAT_and_cleaned.rds")
Ci0tLQp0aXRsZTogIlZpc3VhbGl6YXRpb24gYWZ0ZXIgU1RDQVQgYW5kIENsZWFuaW5nIHVzaW5nIFNldXJhdEV4dGVuZCIKYXV0aG9yOiBOYXNpciBNYWhtb29kIEFiYmFzaQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICAjcm1kZm9ybWF0czo6cmVhZHRoZWRvd24KICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRvY19jb2xsYXBzZWQ6IHRydWUKLS0tCgoKCiMjIGxvYWQgbGlicmFyaWVzLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQoKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoU2V1cmF0RXh0ZW5kKQpsaWJyYXJ5KFNldXJhdEV4dGVuZERhdGEpCmxpYnJhcnkobW9ub2NsZTMpCmxpYnJhcnkoU2V1cmF0V3JhcHBlcnMpCmxpYnJhcnkoaGFybW9ueSkKCgojIEV4dHJhIGxpYnJhcmllcwpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHBoZWF0bWFwKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoU0NwdWJyKQoKYGBgCgoKIyAxLiBSZWFkIFNldXJhdCBvYmplY3QgKFNUQ0FUIGFubm90YXRlZCBhbmQgQ2xlYW5lZCkKYGBge3IgbG9hZFNldXJhdH0KCkFsbF9zYW1wbGVzX01lcmdlZCA8LSByZWFkUkRTKCIuLi9BbGxfc2FtcGxlc19NZXJnZWRfd2l0aF9TVENBVF9hbmRfY2xlYW5lZC5yZHMiKQoKcGJtYyA8LSBBbGxfc2FtcGxlc19NZXJnZWQKCnJtKEFsbF9zYW1wbGVzX01lcmdlZCkKCmdjKCkKYGBgCgoKCiMgMi4gVmlzdWFsaXppbmcgQ2x1c3RlcnMKYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9CgpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShTZXVyYXRFeHRlbmQpCgpJZGVudHMocGJtYykgPC0gIlByZWRpY3Rpb24iCgojIFZpc3VhbGl6aW5nIGNlbGwgY2x1c3RlcnMgdXNpbmcgRGltUGxvdDIKRGltUGxvdDIocGJtYywgdGhlbWUgPSB0aGVtZV91bWFwX2Fycm93cygpKQpgYGAKCgojIDMuIFZpc3VhbGl6aW5nIENsdXN0ZXJzCmBgYHtyLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD04fQoKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoU2V1cmF0RXh0ZW5kKQoKSWRlbnRzKHBibWMpIDwtICJQcmVkaWN0aW9uIgoKIyBWaXN1YWxpemluZyBjZWxsIEFubm90YXRpb25zIHVzaW5nIERpbVBsb3QyCkRpbVBsb3QyKHBibWMsIHRoZW1lID0gdGhlbWVfdW1hcF9hcnJvd3MoKSkKCklkZW50cyhwYm1jKSA8LSAib3JpZy5pZGVudCIKCiMgVmlzdWFsaXppbmcgY2VsbCBBbm5vdGF0aW9ucyB1c2luZyBEaW1QbG90MgpEaW1QbG90MihwYm1jLCB0aGVtZSA9IHRoZW1lX3VtYXBfYXJyb3dzKCkpCgpJZGVudHMocGJtYykgPC0gInNldXJhdF9jbHVzdGVycyIKCiMgVmlzdWFsaXppbmcgY2VsbCBBbm5vdGF0aW9ucyB1c2luZyBEaW1QbG90MgpEaW1QbG90MihwYm1jLCB0aGVtZSA9IHRoZW1lX3VtYXBfYXJyb3dzKCkpCmBgYAoKCiMgNC4gQW5hbHl6aW5nIENsdXN0ZXIgRGlzdHJpYnV0aW9uCmBgYHtyLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD04fQoKIyBDbHVzdGVyIGRpc3RyaWJ1dGlvbiBiYXIgcGxvdApDbHVzdGVyRGlzdHJCYXIocGJtYyRvcmlnLmlkZW50LCBwYm1jJHNldXJhdF9jbHVzdGVycykKCiMgQW5ub3RhdGlvbnMgZGlzdHJpYnV0aW9uIGJhciBwbG90CkNsdXN0ZXJEaXN0ckJhcihwYm1jJG9yaWcuaWRlbnQsIHBibWMkUHJlZGljdGlvbikKCiMgQW5ub3RhdGlvbnMgZGlzdHJpYnV0aW9uIGJhciBwbG90CkNsdXN0ZXJEaXN0ckJhcihwYm1jJFBhdGllbnRfb3JpZ2luLCBwYm1jJFByZWRpY3Rpb24pCgpgYGAKCiMgNS4gTWFya2VyIEdlbmUgQW5hbHlzaXMgd2l0aCBIZWF0bWFwCmBgYHtyLCBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTJ9CgojIFRvIGV4YW1pbmUgdGhlIG1hcmtlciBnZW5lcyBvZiBlYWNoIGNsdXN0ZXIgYW5kIHZpc3VhbGl6ZSB0aGVtIHVzaW5nIGEgaGVhdG1hcDoKCiMgQ2FsY3VsYXRpbmcgei1zY29yZXMgZm9yIHZhcmlhYmxlIGZlYXR1cmVzCiMgZ2VuZXMuenNjb3JlMSA8LSBDYWxjU3RhdHMoCiMgICBwYm1jLAojICAgZmVhdHVyZXMgPSBWYXJpYWJsZUZlYXR1cmVzKHBibWMpLAojICAgZ3JvdXAuYnkgPSAib3JpZy5pZGVudCIsCiMgICBvcmRlciA9ICJwIiwKIyAgIG4gPSA1KQogIAojIERpc3BsYXlpbmcgaGVhdG1hcApIZWF0bWFwKGdlbmVzLnpzY29yZTEsIGxhYl9maWxsID0gInpzY29yZSIpCgoKIyBDYWxjdWxhdGluZyB6LXNjb3JlcyBmb3IgdmFyaWFibGUgZmVhdHVyZXMKIyBnZW5lcy56c2NvcmUyIDwtIENhbGNTdGF0cygKIyAgIHBibWMsCiMgICBmZWF0dXJlcyA9IFZhcmlhYmxlRmVhdHVyZXMocGJtYyksCiMgICBncm91cC5ieSA9ICJzZXVyYXRfY2x1c3RlcnMiLAojICAgb3JkZXIgPSAicCIsCiMgICBuID0gNSkKICAKIyBEaXNwbGF5aW5nIGhlYXRtYXAKSGVhdG1hcChnZW5lcy56c2NvcmUyLCBsYWJfZmlsbCA9ICJ6c2NvcmUiKQoKCiMgQ2FsY3VsYXRpbmcgei1zY29yZXMgZm9yIHZhcmlhYmxlIGZlYXR1cmVzCiMgZ2VuZXMuenNjb3JlMyA8LSBDYWxjU3RhdHMoCiMgICBwYm1jLAojICAgZmVhdHVyZXMgPSBWYXJpYWJsZUZlYXR1cmVzKHBibWMpLAojICAgZ3JvdXAuYnkgPSAiUHJlZGljdGlvbiIsCiMgICBvcmRlciA9ICJwIiwKIyAgIG4gPSA1KQojICAgCiMgRGlzcGxheWluZyBoZWF0bWFwCkhlYXRtYXAoZ2VuZXMuenNjb3JlMywgbGFiX2ZpbGwgPSAienNjb3JlIikKCmdjKCkKYGBgCgojIDYuIEVuaGFuY2VkIERvdCBQbG90cyAoTmV3IGluIHYxLjEuMCkKYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9CgpJZGVudHMocGJtYykgPC0gIm9yaWcuaWRlbnQiCgojIENyZWF0ZSBncm91cGVkIGZlYXR1cmVzCmdyb3VwZWRfZmVhdHVyZXMgPC0gbGlzdCgKICAiQl9jZWxsX21hcmtlcnMiID0gYygiTVM0QTEiLCAiQ0Q3OUEiKSwKICAiVF9jZWxsX21hcmtlcnMiID0gYygiQ0QzRCIsICJDRDhBIiwgIklMN1IiKSwKICAiTXllbG9pZF9tYXJrZXJzIiA9IGMoIkNEMTQiLCAiRkNHUjNBIiwgIlMxMDBBOCIpCikKCkRvdFBsb3QyKHBibWMsIGZlYXR1cmVzID0gZ3JvdXBlZF9mZWF0dXJlcykKCklkZW50cyhwYm1jKSA8LSAic2V1cmF0X2NsdXN0ZXJzIgoKIyBDcmVhdGUgZ3JvdXBlZCBmZWF0dXJlcwpncm91cGVkX2ZlYXR1cmVzIDwtIGxpc3QoCiAgIkJfY2VsbF9tYXJrZXJzIiA9IGMoIk1TNEExIiwgIkNENzlBIiksCiAgIlRfY2VsbF9tYXJrZXJzIiA9IGMoIkNEM0QiLCAiQ0Q4QSIsICJJTDdSIiksCiAgIk15ZWxvaWRfbWFya2VycyIgPSBjKCJDRDE0IiwgIkZDR1IzQSIsICJTMTAwQTgiKQopCgpEb3RQbG90MihwYm1jLCBmZWF0dXJlcyA9IGdyb3VwZWRfZmVhdHVyZXMpCgpJZGVudHMocGJtYykgPC0gIlByZWRpY3Rpb24iCgojIENyZWF0ZSBncm91cGVkIGZlYXR1cmVzCmdyb3VwZWRfZmVhdHVyZXMgPC0gbGlzdCgKICAiQl9jZWxsX21hcmtlcnMiID0gYygiTVM0QTEiLCAiQ0Q3OUEiKSwKICAiVF9jZWxsX21hcmtlcnMiID0gYygiQ0QzRCIsICJDRDhBIiwgIklMN1IiKSwKICAiTXllbG9pZF9tYXJrZXJzIiA9IGMoIkNEMTQiLCAiRkNHUjNBIiwgIlMxMDBBOCIpCikKCkRvdFBsb3QyKHBibWMsIGZlYXR1cmVzID0gZ3JvdXBlZF9mZWF0dXJlcykKCmBgYAoKIyMuIEVuaGFuY2VkIERvdCBQbG90cyAoTmV3IGluIHYxLjEuMCkKYGBge3IsIGZpZy5oZWlnaHQ9MTIsIGZpZy53aWR0aD0xMn0KCiMgQ3JlYXRlIGdyb3VwZWQgZmVhdHVyZXMKZ3JvdXBlZF9mZWF0dXJlc19UIDwtIGxpc3QoCiAgIk5haXZlX1QiICAgICAgID0gYygiQ0NSNyIsICJTRUxMIiwgIkxFRjEiLCAiVENGNyIpLAogICJUY20iICAgICAgICAgICA9IGMoIkNDUjciLCAiSUw3UiIsICJDRDYyTCIpLAogICJUZW0iICAgICAgICAgICA9IGMoIkdaTUsiLCAiQ1hDUjMiLCAiS0xSRzEiKSwKICAiVGVtcmEiICAgICAgICAgPSBjKCJHWk1CIiwgIlBSRjEiLCAiS0xSRzEiKSwKICAiVHJlZyIgICAgICAgICAgPSBjKCJGT1hQMyIsICJJTDJSQSIsICJJS1pGMiIsICJUSUdJVCIpLAogICJUZmgiICAgICAgICAgICA9IGMoIkNYQ1I1IiwgIkJDTDYiLCAiUERDRDEiLCAiSUNPUyIpLAogICJUaDE3IiAgICAgICAgICA9IGMoIlJPUkMiLCAiSUwxN0EiLCAiSUwyM1IiKSwKICAiVGV4IiAgICAgICAgICAgPSBjKCJQRENEMSIsICJUT1giLCAiTEFHMyIsICJDVExBNCIpLAogICJUcm0iICAgICAgICAgICA9IGMoIklUR0FFIiwgIkNENjkiLCAiWk5GNjgzIiksCiAgIlRpc2ciICAgICAgICAgID0gYygiSVNHMTUiLCAiSUZJNiIsICJNWDEiLCAiSUZJVDMiKSwKICAiUHJvbGlmZXJhdGlvbiIgPSBjKCJNS0k2NyIsICJUT1AyQSIsICJTVE1OMSIpLAogICJDZWxsX0RlYXRoIiAgICA9IGMoIkJBWCIsICJDQVNQMyIsICJERkZBIiwgIkJDTDJMMTEiKSwKICAiQWRoZXNpb24iICAgICAgPSBjKCJJVEdBTCIsICJJQ0FNMSIsICJDRDQ0IiwgIlNFTEwiKSwKICAiQWN0aXZhdGVkIiAgICAgPSBjKCJDRDM4IiwgIkhMQS1EUkEiLCAiVE5GUlNGOSIsICJJTDJSQSIpCikKCgpJZGVudHMocGJtYykgPC0gIm9yaWcuaWRlbnQiCkRvdFBsb3QyKHBibWMsIGZlYXR1cmVzID0gZ3JvdXBlZF9mZWF0dXJlc19UKQoKSWRlbnRzKHBibWMpIDwtICJzZXVyYXRfY2x1c3RlcnMiCgpEb3RQbG90MihwYm1jLCBmZWF0dXJlcyA9IGdyb3VwZWRfZmVhdHVyZXNfVCkKCklkZW50cyhwYm1jKSA8LSAiUHJlZGljdGlvbiIKCkRvdFBsb3QyKHBibWMsIGZlYXR1cmVzID0gZ3JvdXBlZF9mZWF0dXJlc19UKQoKYGBgCgojIDcuIEFuYWx5emluZyBDbHVzdGVyIERpc3RyaWJ1dGlvbgpgYGB7ciwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OH0KCiMgU3BlY2lmeWluZyBnZW5lcyBhbmQgY2VsbHMgb2YgaW50ZXJlc3QKZ2VuZXMgPC0gYygiU0VMTCIsICJJTDJSQSIsICJDRDhBIiwgIlRPUDJBIikKY2VsbHMgPC0gV2hpY2hDZWxscyhwYm1jLCBpZGVudHMgPSBjKCJDRDQgVG4iLCAiQ0Q0IFRyZWciLCAiQ0Q0IFRybSIsICJDRDQgcHJvbGlmZXJhdGlvbiIpKQoKIyBWaW9saW4gcGxvdCB3aXRoIHN0YXRpc3RpY2FsIGFuYWx5c2lzClZsblBsb3QyKAogIHBibWMsCiAgZmVhdHVyZXMgPSBnZW5lcywKICBncm91cC5ieSA9ICJQcmVkaWN0aW9uIiwKICBjZWxscyA9IGNlbGxzLAogIHN0YXQubWV0aG9kID0gIndpbGNveC50ZXN0IikKCmBgYAoKIyMgRGlzcGxheWluZyB0aHJlZSBtYXJrZXJzIG9uIGEgc2luZ2xlIFVNQVAKYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9CkZlYXR1cmVQbG90MyhwYm1jLCBmZWF0dXJlLjEgPSAiQ0QzRCIsIGZlYXR1cmUuMiA9ICJDRDciLCBmZWF0dXJlLjMgPSAiQ0Q4QSIsIHB0LnNpemUgPSAxKQoKRmVhdHVyZVBsb3QzKHBibWMsIGZlYXR1cmUuMSA9ICJJTDJSQSIsIGZlYXR1cmUuMiA9ICJDRDY5IiwgZmVhdHVyZS4zID0gIkZPWFAzIiwgcHQuc2l6ZSA9IDEpCgpGZWF0dXJlUGxvdDMocGJtYywgZmVhdHVyZS4xID0gIkxBRzMiLCBmZWF0dXJlLjIgPSAiUERDRDEiLCBmZWF0dXJlLjMgPSAiQ1RMQTQiLCBwdC5zaXplID0gMSkKCmBgYAoKCiMgOC4gQ3JlYXRlIGEgYmFzaWMgdm9sY2FubyBwbG90IGNvbXBhcmluZyB0d28gY2VsbCB0eXBlczoKYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9CklkZW50cyhwYm1jKSA8LSAiUHJlZGljdGlvbiIKClZvbGNhbm9QbG90KHBibWMsIAogICAgICAgICAgICBpZGVudC4xID0gIkNENCBUbiIsCiAgICAgICAgICAgIGlkZW50LjIgPSAiQ0Q0IFRybSIpICMgbm90IHBvc3NpYmxlIHRvIHJ1biBhcyBpdCByZXF1aXJlcyBhbG90IG9mIG1lbW9yeSwgVHJ5IGl0IG9uIFIgc2VydmVyCmBgYAoKCiMgOS4gQ29uZHVjdGluZyBHZW5lc2V0IEVucmljaG1lbnQgQW5hbHlzaXMgKEdTRUEpCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMH0KSWRlbnRzKHBibWMpIDwtICJvcmlnLmlkZW50IgoKb3B0aW9ucyhzcGUgPSAiaHVtYW4iKQpwYm1jIDwtIEdlbmVTZXRBbmFseXNpc0dPKHBibWMsIHBhcmVudCA9ICJpbW11bmVfc3lzdGVtX3Byb2Nlc3MiLCBuLm1pbiA9IDUpCm1hdHIgPC0gUmVuYW1lR08ocGJtY0BtaXNjJEFVQ2VsbCRHTyRpbW11bmVfc3lzdGVtX3Byb2Nlc3MpCmdvX3pzY29yZSA8LSBDYWxjU3RhdHMoCiAgbWF0ciwKICBmID0gcGJtYyRvcmlnLmlkZW50LAogIG9yZGVyID0gInAiLAogIG4gPSAzKQpIZWF0bWFwKGdvX3pzY29yZSwgbGFiX2ZpbGwgPSAienNjb3JlIikKCgpnb196c2NvcmUgPC0gQ2FsY1N0YXRzKAogIG1hdHIsCiAgZiA9IHBibWMkc2V1cmF0X2NsdXN0ZXJzLAogIG9yZGVyID0gInAiLAogIG4gPSAzKQpIZWF0bWFwKGdvX3pzY29yZSwgbGFiX2ZpbGwgPSAienNjb3JlIikKCgoKCmBgYAojIyBDb25kdWN0aW5nIEdlbmVzZXQgRW5yaWNobWVudCBBbmFseXNpcyAoR1NFQSkKYGBge3IsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMn0KZ29fenNjb3JlIDwtIENhbGNTdGF0cygKICBtYXRyLAogIGYgPSBwYm1jJFByZWRpY3Rpb24sCiAgb3JkZXIgPSAicCIsCiAgbiA9IDMpCkhlYXRtYXAoZ29fenNjb3JlLCBsYWJfZmlsbCA9ICJ6c2NvcmUiKQoKCmBgYAoKCiMgOS4gSW1wb3J0aW5nIGFuZCBWaXN1YWxpemluZyBTQ0VOSUMgQW5hbHlzaXMKYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9CiMgRG93bmxvYWRpbmcgYSBwcmUtY29tcHV0ZWQgU0NFTklDIGxvb20gZmlsZQpzY2VuaWNfbG9vbV9wYXRoIDwtIGZpbGUucGF0aCh0ZW1wZGlyKCksICJweXNjZW5pY19pbnRlZ3JhdGVkLW91dHB1dC5sb29tIikKZG93bmxvYWQuZmlsZSgiaHR0cHM6Ly96ZW5vZG8ub3JnL3JlY29yZHMvMTA5NDQwNjYvZmlsZXMvcGJtYzNrX3NtYWxsX3B5c2NlbmljX2ludGVncmF0ZWQtb3V0cHV0Lmxvb20iLCBzY2VuaWNfbG9vbV9wYXRoLCBtb2RlID0gIndiIikKCiMgSW1wb3J0aW5nIFNDRU5JQyBMb29tIEZpbGVzIGludG8gU2V1cmF0CnBibWMgPC0gSW1wb3J0UHlzY2VuaWNMb29tKHNjZW5pY19sb29tX3BhdGgsIHNldSA9IHBibWMpCgojIFZpc3VhbGl6aW5nIHZhcmlhYmxlcyBzdWNoIGFzIGNsdXN0ZXIsIGdlbmUgZXhwcmVzc2lvbiwgYW5kIFNDRU5JQyByZWd1bG9uIGFjdGl2aXR5IHdpdGggY3VzdG9taXplZCBjb2xvcnMKRGltUGxvdDIoCiAgcGJtYywKICBmZWF0dXJlcyA9IGMoInNldXJhdF9jbHVzdGVycyIsICJvcmlnLmlkZW50IiwgIkNFQlBBIiwgInRmX0NFQlBBIiksCiAgY29scyA9IGxpc3QoInRmX0NFQlBBIiA9ICJPclJkIiksCiAgdGhlbWUgPSBOb0F4ZXMoKQopICsgdGhlbWVfdW1hcF9hcnJvd3MoKQoKYGBgCiMjIERpc3BsYXlpbmcgdGhyZWUgbWFya2VycyBvbiBhIHNpbmdsZSBVTUFQCmBgYHtyLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD04fQpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShTZXVyYXRFeHRlbmQpCgpGZWF0dXJlUGxvdDMocGJtYywgZmVhdHVyZS4xID0gIkNEM0QiLCBmZWF0dXJlLjIgPSAiQ0Q3IiwgZmVhdHVyZS4zID0gIkNEOEEiLCBwdC5zaXplID0gMSwgZGFyay50aGVtZSA9IFRSVUUpCgpGZWF0dXJlUGxvdDMocGJtYywgZmVhdHVyZS4xID0gIklMMlJBIiwgZmVhdHVyZS4yID0gIkNENjkiLCBmZWF0dXJlLjMgPSAiRk9YUDMiLCBwdC5zaXplID0gMSwgZGFyay50aGVtZSA9IFRSVUUpCgpGZWF0dXJlUGxvdDMocGJtYywgZmVhdHVyZS4xID0gIkxBRzMiLCBmZWF0dXJlLjIgPSAiUERDRDEiLCBmZWF0dXJlLjMgPSAiQ1RMQTQiLCBwdC5zaXplID0gMSwgZGFyay50aGVtZSA9IFRSVUUpCgpgYGAKCgojIDEwLiBOZXcgQ2x1c3RlckRpc3RyUGxvdCBGdW5jdGlvbgpgYGB7ciwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OH0KCnBibWMkY29uZGl0aW9uIDwtIGlmZWxzZSgKICBwYm1jJG9yaWcuaWRlbnQgJWluJSBwYXN0ZTAoIkwiLCAxOjcpLCAgICAjIE1hbGlnbmFudCBzYW1wbGVzIEwxIHRvIEw3CiAgIk1hbGlnbmFudCIsCiAgaWZlbHNlKAogICAgcGJtYyRvcmlnLmlkZW50ICVpbiUgYygiQ0Q0VF9sYWIiLCAiQ0Q0VF8xMHgiKSwgICMgSGVhbHRoeSBzYW1wbGVzCiAgICAiSGVhbHRoeSIsCiAgICAiT3RoZXIiICAjIGZvciBhbnkgb3RoZXIgc2FtcGxlcywgaWYgcHJlc2VudAogICkKKQoKIyBDb252ZXJ0IHRvIGZhY3RvciB3aXRoIE1hbGlnbmFudCBmaXJzdCwgSGVhbHRoeSBzZWNvbmQKcGJtYyRjb25kaXRpb24gPC0gZmFjdG9yKHBibWMkY29uZGl0aW9uLCBsZXZlbHMgPSBjKCJNYWxpZ25hbnQiLCAiSGVhbHRoeSIpKQoKCgojIENvbXBhcmUgY2x1c3RlciBkaXN0cmlidXRpb24gYmV0d2VlbiBjb25kaXRpb25zCkNsdXN0ZXJEaXN0clBsb3QoCiAgb3JpZ2luID0gcGJtYyRvcmlnLmlkZW50LAogIGNsdXN0ZXIgPSBwYm1jJFByZWRpY3Rpb24sCiAgY29uZGl0aW9uID0gcGJtYyRjb25kaXRpb24KKQoKYGBgCgoKIyAxMS4gRW5oYW5jZWQgTG9nIEZvbGQgQ2hhbmdlIE9wdGlvbnMgaW4gRGlmZmVyZW50aWFsIEFuYWx5c2lzIFBsb3RzCmBgYHtyLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD04fQojIFVzaW5nIGxvZyBiYXNlIDIgZm9yIGZvbGQgY2hhbmdlIGNhbGN1bGF0aW9ucyBpbiBXYXRlcmZhbGxQbG90CldhdGVyZmFsbFBsb3QoCiAgcGJtYywgCiAgZ3JvdXAuYnkgPSAiUHJlZGljdGlvbiIsIAogIGZlYXR1cmVzID0gVmFyaWFibGVGZWF0dXJlcyhwYm1jKVsxOjgwXSwKICBpZGVudC4xID0gIkNENCBUbiIsIAogIGlkZW50LjIgPSAiQ0Q0IFRybSIsIAogIGxlbmd0aCA9ICJsb2dGQyIsCiAgbG9nLmJhc2UgPSAiMiIsICAgICMgVXNlIGxvZzIgaW5zdGVhZCBvZiBuYXR1cmFsIGxvZwogIHRvcC5uID0gMjApCgpgYGAKCiMjIFNhdmUgdGhlIFJEUyBhZnRlciBjaGFuZ2VzCmBgYHtyfQoKCnNhdmVSRFMoQWxsX3NhbXBsZXNfTWVyZ2VkLCBmaWxlID0gIlNUQ0FUX0Fubm90YXRpb24vQWxsX3NhbXBsZXNfTWVyZ2VkX3dpdGhfU1RDQVRfYW5kX2NsZWFuZWQucmRzIikKCgoKYGBgCg==