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==