load libraries————————————
Read Seurat object with load as you save it with save()
function
All_samples_Merged <- readRDS("../STCAT_Annotation/All_samples_Merged_with_STCAT.rds")
1. Subset Normal CD4⁺ T Cells for Reference
# Load required library
library(Seurat)
# Subset normal CD4+ T cells from merged object
reference_cd4 <- subset(
All_samples_Merged,
subset = cell_line %in% c("CD4Tcells_lab", "CD4Tcells_10x")
)
# Ensure the SCT assay is available and set it as default
if ("SCT" %in% names(reference_cd4@assays)) {
DefaultAssay(reference_cd4) <- "SCT"
} else {
stop("SCT assay not found in the object. Please run SCTransform first.")
}
# Confirm object class and assays
print(class(reference_cd4)) # Should return "Seurat"
[1] "Seurat"
attr(,"package")
[1] "SeuratObject"
print(names(reference_cd4@assays)) # List available assays
[1] "RNA" "ADT" "prediction.score.celltype.l1"
[4] "prediction.score.celltype.l2" "prediction.score.celltype.l3" "SCT"
2. Normalize & Integrate Reference (Accommodate Multiple
Donors)
ref_list <- SplitObject(reference_cd4, split.by = "cell_line")
# Run SCTransform on each subset
ref_list <- lapply(ref_list, SCTransform, verbose = FALSE)
Warning: The `slot` argument of `SetAssayData()` is deprecated as of SeuratObject 5.0.0.
Please use the `layer` argument instead.Warning: The `slot` argument of `GetAssayData()` is deprecated as of SeuratObject 5.0.0.
Please use the `layer` argument instead.Warning: Different cells and/or features from existing assay SCTWarning: Different cells and/or features from existing assay SCT
# Run PCA on each SCT-normalized subset (required for RPCA)
ref_list <- lapply(ref_list, function(x) {
x <- RunPCA(x, assay = "SCT", verbose = FALSE)
return(x)
})
# Select integration features
ref_features <- SelectIntegrationFeatures(object.list = ref_list)
# Prepare SCT integration
ref_list <- PrepSCTIntegration(object.list = ref_list, anchor.features = ref_features)
| | 0 % ~calculating
|+++++++++++++++++++++++++ | 50% ~01s
|++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=01s
# Find integration anchors using RPCA reduction
ref_anchors <- FindIntegrationAnchors(
object.list = ref_list,
anchor.features = ref_features,
normalization.method = "SCT",
reduction = "rpca"
)
Computing within dataset neighborhoods
| | 0 % ~calculating
|+++++++++++++++++++++++++ | 50% ~01s
|++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=02s
Finding all pairwise anchors
| | 0 % ~calculating
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
Found 630 anchors
|++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=04s
# Integrate data
reference_integrated <- IntegrateData(anchorset = ref_anchors, normalization.method = "SCT")
[1] 1
Warning: Different cells and/or features from existing assay SCTWarning: Layer counts isn't present in the assay object; returning NULL
[1] 2
Warning: Different cells and/or features from existing assay SCTWarning: Layer counts isn't present in the assay object; returning NULLMerging dataset 2 into 1
Extracting anchors for merged samples
Finding integration vectors
Finding integration vector weights
0% 10 20 30 40 50 60 70 80 90 100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
Warning: Layer counts isn't present in the assay object; returning NULLWarning: Assay integrated changing from Assay to SCTAssayWarning: Layer counts isn't present in the assay object; returning NULLWarning: Different cells and/or features from existing assay SCT
# Set default assay to integrated
DefaultAssay(reference_integrated) <- "integrated"
3. Clustering & Dimensionality Reduction
reference_integrated <- RunPCA(reference_integrated, verbose = FALSE)
reference_integrated <- RunUMAP(reference_integrated, dims = 1:18)
Warning: The default method for RunUMAP has changed from calling Python UMAP via reticulate to the R-native UWOT using the cosine metric
To use Python UMAP via reticulate, set umap.method to 'umap-learn' and metric to 'correlation'
This message will be shown once per session12:29:11 UMAP embedding parameters a = 0.9922 b = 1.112
12:29:11 Read 8610 rows and found 18 numeric columns
12:29:11 Using Annoy for neighbor search, n_neighbors = 30
12:29:11 Building Annoy index with metric = cosine, n_trees = 50
0% 10 20 30 40 50 60 70 80 90 100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
12:29:12 Writing NN index file to temp file /tmp/RtmpgsQ1lC/file1a753457555a35
12:29:12 Searching Annoy index using 1 thread, search_k = 3000
12:29:14 Annoy recall = 100%
12:29:14 Commencing smooth kNN distance calibration using 1 thread with target n_neighbors = 30
12:29:15 Initializing from normalized Laplacian + noise (using RSpectra)
12:29:15 Commencing optimization for 500 epochs, with 361792 positive edges
12:29:15 Using rng type: pcg
Using method 'umap'
0% 10 20 30 40 50 60 70 80 90 100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
12:29:22 Optimization finished
reference_integrated <- FindNeighbors(reference_integrated, dims = 1:18)
Computing nearest neighbor graph
Computing SNN
reference_integrated <- FindClusters(reference_integrated, resolution = 0.3)
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck
Number of nodes: 8610
Number of edges: 308059
Running Louvain algorithm...
0% 10 20 30 40 50 60 70 80 90 100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.9201
Number of communities: 11
Elapsed time: 0 seconds
ElbowPlot(reference_integrated, ndims = 50)

# Visualize UMAP colored by original donor (cell_line)
DimPlot(reference_integrated, group.by = "cell_line", reduction = "umap") +
ggtitle("UMAP of Integrated CD4⁺ T Cells")

# Visualize UMAP colored by original donor (cell_line)
DimPlot(reference_integrated, group.by = "integrated_snn_res.0.3", reduction = "umap") +
ggtitle("UMAP of Integrated CD4⁺ T Cells")

# Visualize UMAP colored by original donor (cell_line)
DimPlot(reference_integrated, group.by = "Prediction", reduction = "umap") +
ggtitle("UMAP of Integrated CD4⁺ T Cells")

# Visualize UMAP colored by original donor (cell_line)
DimPlot(reference_integrated, group.by = "predicted.celltype.l2", reduction = "umap") +
ggtitle("UMAP of Integrated CD4⁺ T Cells")

Save the mapped query object (Sézary cell lines projected onto
reference trajectory):
saveRDS(reference_integrated, file = "sezary_cell_lines_mapped_to_cd4_reference_integrated_before_Monocle3.rds")
4. Trajectory and Pseudotime with Monocle3
library(monocle3)
library(SeuratWrappers)
library(Matrix)
Attaching package: ‘Matrix’
The following object is masked from ‘package:S4Vectors’:
expand
cds <- as.cell_data_set(reference_integrated)
Warning: `PackageCheck()` was deprecated in SeuratObject 5.0.0.
Please use `rlang::check_installed()` instead.Warning: Monocle 3 trajectories require cluster partitions, which Seurat does not calculate. Please run 'cluster_cells' on your cell_data_set object
cds <- cluster_cells(cds, reduction_method = "UMAP")
cds <- learn_graph(cds, use_partition = TRUE)
|
| | 0%
|
|===============================================================================================================| 100%
|
| | 0%
|
|===============================================================================================================| 100%
|
| | 0%
|
|===============================================================================================================| 100%
naive_markers <- c("CCR7", "SELL", "LEF1")
naive_markers <- naive_markers[naive_markers %in% rownames(cds)]
# Extract log-normalized expression or fallback to counts log-transformed
if("logcounts" %in% assayNames(cds)) {
expr_mat <- assay(cds, "logcounts")
} else {
expr_mat <- log1p(assay(cds, "counts"))
}
naive_score <- Matrix::colMeans(expr_mat[naive_markers, , drop = FALSE])
threshold <- quantile(naive_score, 0.95)
root_cells <- names(naive_score[naive_score > threshold])
cds <- order_cells(cds, root_cells = root_cells)
reference_integrated$pseudotime <- pseudotime(cds)
plot_cells(cds, color_cells_by = "pseudotime", show_trajectory_graph = TRUE)
Cells aren't colored in a way that allows them to be grouped.

# Visualize UMAP colored by original donor (cell_line)
DimPlot(reference_integrated, group.by = "Prediction", reduction = "umap") +
ggtitle("UMAP of Integrated CD4⁺ T Cells")

# Visualize UMAP colored by original donor (cell_line)
DimPlot(reference_integrated, group.by = "predicted.celltype.l2", reduction = "umap") +
ggtitle("UMAP of Integrated CD4⁺ T Cells")

Save the mapped query object (Sézary cell lines projected onto
reference trajectory):
saveRDS(reference_integrated, file = "sezary_cell_lines_mapped_to_cd4_reference_integrated_before_Query_Projection.rds")
5. Prepare Sézary Syndrome Cell Lines as Query
# Load required packages
library(Seurat)
library(glmGamPoi) # Recommended for memory-efficient SCTransform
Attaching package: ‘glmGamPoi’
The following object is masked from ‘package:ggplot2’:
vars
The following object is masked from ‘package:dplyr’:
vars
library(future)
# Optional: Parallel setup to handle memory better
plan("multisession", workers = 4)
options(future.globals.maxSize = 50 * 1024^3) # 50 GB memory ceiling
# Step 1: Subset Sézary syndrome cell lines
query_subset <- subset(All_samples_Merged, subset = cell_line %in% paste0("L", 1:7))
gc()
used (Mb) gc trigger (Mb) max used (Mb)
Ncells 9283855 495.9 14812904 791.1 14812904 791.1
Vcells 2971711686 22672.4 4735597000 36129.8 4085964052 31173.5
# Step 2: Get raw counts matrix from RNA assay
query_raw <- GetAssayData(query_subset, assay = "RNA", slot = "counts")
# Step 3: Filter out genes expressed in <3 cells (saves memory)
keep_genes <- rowSums(query_raw > 0) >= 3
query_raw_filtered <- query_raw[keep_genes, ]
# Step 4: Create a new Seurat object with metadata preserved
query_cells <- CreateSeuratObject(counts = query_raw_filtered, meta.data = query_subset@meta.data)
# Step 5: Run SCTransform with glmGamPoi backend for better performance
query_cells <- SCTransform(
query_cells,
method = "glmGamPoi", # Faster and uses less RAM
variable.features.n = 3000, # Optional: focus on top 3000 variable genes
verbose = FALSE
)
6. Inject Cell Lines into Reference with MapQuery
# Find anchors between reference and query
anchors_query <- FindTransferAnchors(
reference = reference_integrated,
query = query_cells,
reference.reduction = "pca",
normalization.method = "SCT",
dims = 1:18
)
# Map query cells to reference
query_mapped <- MapQuery(
anchorset = anchors_query,
query = query_cells,
reference = reference_integrated,
refdata = list(
pseudotime = "pseudotime", # Transfer pseudotime
seurat_clusters = "seurat_clusters", # Transfer clusters
trajectory_position = "monocle3_embedding" # If storing MST coords
),
reference.reduction = "pca",
reduction.model = "umap"
)
7. Visualization (Plot Reference and Injected Cells by Pseudotime
and Cell Line)
# Plot the reference trajectory UMAP, colored by pseudotime
DimPlot(reference_integrated, group.by = "pseudotime", reduction = "umap") +
ggtitle("Reference CD4⁺ T Cell Trajectory (Pseudotime)")
# Overlay injected cell lines
DimPlot(query_mapped, reduction = "ref.umap", group.by = "cell_line", label = TRUE) +
ggtitle("Injected Sézary Cell Lines on Reference Trajectory")
Visualization & Analysis
# Combined UMAP with pseudotime
p1 <- DimPlot(reference_integrated,
group.by = "pseudotime",
reduction = "umap") +
scale_color_viridis_c(option = "magma")
p2 <- DimPlot(query_mapped,
reduction = "ref.umap",
group.by = "cell_line",
cols = "darkred") +
ggtitle("Sézary Cell Lines")
p1 + p2
# Pseudotime distribution in cell lines
VlnPlot(query_mapped,
features = "pseudotime",
group.by = "cell_line",
pt.size = 0.1) +
geom_boxplot(width = 0.2)
# Project cell lines on reference trajectory
FeaturePlot(query_mapped,
features = "pseudotime",
reduction = "ref.umap") +
geom_point(data = query_mapped[[]],
aes(x = refUMAP_1, y = refUMAP_2, color = pseudotime),
size = 1.5)
Analyze Pseudotime Distributions Across Cell Lines
FeaturePlot(query_mapped, features = "pseudotime", reduction = "ref.umap") +
ggtitle("Pseudotime Values of Injected Cell Lines")
VlnPlot(query_mapped, features = "pseudotime", group.by = "cell_line") +
ggtitle("Pseudotime Distribution by Cell Line")
Save the mapped query object (Sézary cell lines projected onto
reference trajectory):
saveRDS(query_mapped, file = "sezary_cell_lines_mapped_to_cd4_reference.rds")
Ci0tLQp0aXRsZTogIlRyYWplY3RvcnkgQW5hbHlzaXMgdXB0byBJbnRlZ3JhdGlvbiBvZiBDb250cm9sIgphdXRob3I6IE5hc2lyIE1haG1vb2QgQWJiYXNpCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogICNybWRmb3JtYXRzOjpyZWFkdGhlZG93bgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdG9jX2NvbGxhcHNlZDogdHJ1ZQotLS0KCgoKIyMgbG9hZCBsaWJyYXJpZXMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CgpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShtb25vY2xlMykKbGlicmFyeShTZXVyYXRXcmFwcGVycykKbGlicmFyeShoYXJtb255KQoKCiMgRXh0cmEgbGlicmFyaWVzCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkocGhlYXRtYXApCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShTQ3B1YnIpCgpgYGAKCgojIyBSZWFkIFNldXJhdCBvYmplY3Qgd2l0aCBsb2FkIGFzIHlvdSBzYXZlIGl0IHdpdGggc2F2ZSgpIGZ1bmN0aW9uCmBgYHtyIGxvYWRTZXVyYXR9CgpBbGxfc2FtcGxlc19NZXJnZWQgPC0gcmVhZFJEUygiLi4vU1RDQVRfQW5ub3RhdGlvbi9BbGxfc2FtcGxlc19NZXJnZWRfd2l0aF9TVENBVC5yZHMiKQoKCgoKYGBgCgojIDEuIFN1YnNldCBOb3JtYWwgQ0Q04oG6IFQgQ2VsbHMgZm9yIFJlZmVyZW5jZQpgYGB7cn0KIyBMb2FkIHJlcXVpcmVkIGxpYnJhcnkKbGlicmFyeShTZXVyYXQpCgojIFN1YnNldCBub3JtYWwgQ0Q0KyBUIGNlbGxzIGZyb20gbWVyZ2VkIG9iamVjdApyZWZlcmVuY2VfY2Q0IDwtIHN1YnNldCgKICBBbGxfc2FtcGxlc19NZXJnZWQsCiAgc3Vic2V0ID0gY2VsbF9saW5lICVpbiUgYygiQ0Q0VGNlbGxzX2xhYiIsICJDRDRUY2VsbHNfMTB4IikKKQoKIyBFbnN1cmUgdGhlIFNDVCBhc3NheSBpcyBhdmFpbGFibGUgYW5kIHNldCBpdCBhcyBkZWZhdWx0CmlmICgiU0NUIiAlaW4lIG5hbWVzKHJlZmVyZW5jZV9jZDRAYXNzYXlzKSkgewogIERlZmF1bHRBc3NheShyZWZlcmVuY2VfY2Q0KSA8LSAiU0NUIgp9IGVsc2UgewogIHN0b3AoIlNDVCBhc3NheSBub3QgZm91bmQgaW4gdGhlIG9iamVjdC4gUGxlYXNlIHJ1biBTQ1RyYW5zZm9ybSBmaXJzdC4iKQp9CgojIENvbmZpcm0gb2JqZWN0IGNsYXNzIGFuZCBhc3NheXMKcHJpbnQoY2xhc3MocmVmZXJlbmNlX2NkNCkpICAgICAgICAgICAgIyBTaG91bGQgcmV0dXJuICJTZXVyYXQiCnByaW50KG5hbWVzKHJlZmVyZW5jZV9jZDRAYXNzYXlzKSkgICAgICMgTGlzdCBhdmFpbGFibGUgYXNzYXlzCgoKYGBgCgojIDIuIE5vcm1hbGl6ZSAmIEludGVncmF0ZSBSZWZlcmVuY2UgKEFjY29tbW9kYXRlIE11bHRpcGxlIERvbm9ycykKYGBge3J9CgpyZWZfbGlzdCA8LSBTcGxpdE9iamVjdChyZWZlcmVuY2VfY2Q0LCBzcGxpdC5ieSA9ICJjZWxsX2xpbmUiKQoKIyBSdW4gU0NUcmFuc2Zvcm0gb24gZWFjaCBzdWJzZXQKcmVmX2xpc3QgPC0gbGFwcGx5KHJlZl9saXN0LCBTQ1RyYW5zZm9ybSwgdmVyYm9zZSA9IEZBTFNFKQoKIyBSdW4gUENBIG9uIGVhY2ggU0NULW5vcm1hbGl6ZWQgc3Vic2V0IChyZXF1aXJlZCBmb3IgUlBDQSkKcmVmX2xpc3QgPC0gbGFwcGx5KHJlZl9saXN0LCBmdW5jdGlvbih4KSB7CiAgeCA8LSBSdW5QQ0EoeCwgYXNzYXkgPSAiU0NUIiwgdmVyYm9zZSA9IEZBTFNFKQogIHJldHVybih4KQp9KQoKIyBTZWxlY3QgaW50ZWdyYXRpb24gZmVhdHVyZXMKcmVmX2ZlYXR1cmVzIDwtIFNlbGVjdEludGVncmF0aW9uRmVhdHVyZXMob2JqZWN0Lmxpc3QgPSByZWZfbGlzdCkKCiMgUHJlcGFyZSBTQ1QgaW50ZWdyYXRpb24KcmVmX2xpc3QgPC0gUHJlcFNDVEludGVncmF0aW9uKG9iamVjdC5saXN0ID0gcmVmX2xpc3QsIGFuY2hvci5mZWF0dXJlcyA9IHJlZl9mZWF0dXJlcykKCiMgRmluZCBpbnRlZ3JhdGlvbiBhbmNob3JzIHVzaW5nIFJQQ0EgcmVkdWN0aW9uCnJlZl9hbmNob3JzIDwtIEZpbmRJbnRlZ3JhdGlvbkFuY2hvcnMoCiAgb2JqZWN0Lmxpc3QgPSByZWZfbGlzdCwKICBhbmNob3IuZmVhdHVyZXMgPSByZWZfZmVhdHVyZXMsCiAgbm9ybWFsaXphdGlvbi5tZXRob2QgPSAiU0NUIiwKICByZWR1Y3Rpb24gPSAicnBjYSIKKQoKIyBJbnRlZ3JhdGUgZGF0YQpyZWZlcmVuY2VfaW50ZWdyYXRlZCA8LSBJbnRlZ3JhdGVEYXRhKGFuY2hvcnNldCA9IHJlZl9hbmNob3JzLCBub3JtYWxpemF0aW9uLm1ldGhvZCA9ICJTQ1QiKQoKIyBTZXQgZGVmYXVsdCBhc3NheSB0byBpbnRlZ3JhdGVkCkRlZmF1bHRBc3NheShyZWZlcmVuY2VfaW50ZWdyYXRlZCkgPC0gImludGVncmF0ZWQiCgpgYGAKCgojIDMuIENsdXN0ZXJpbmcgJiBEaW1lbnNpb25hbGl0eSBSZWR1Y3Rpb24KYGBge3J9CgpyZWZlcmVuY2VfaW50ZWdyYXRlZCA8LSBSdW5QQ0EocmVmZXJlbmNlX2ludGVncmF0ZWQsIHZlcmJvc2UgPSBGQUxTRSkKcmVmZXJlbmNlX2ludGVncmF0ZWQgPC0gUnVuVU1BUChyZWZlcmVuY2VfaW50ZWdyYXRlZCwgZGltcyA9IDE6MTgpCnJlZmVyZW5jZV9pbnRlZ3JhdGVkIDwtIEZpbmROZWlnaGJvcnMocmVmZXJlbmNlX2ludGVncmF0ZWQsIGRpbXMgPSAxOjE4KQpyZWZlcmVuY2VfaW50ZWdyYXRlZCA8LSBGaW5kQ2x1c3RlcnMocmVmZXJlbmNlX2ludGVncmF0ZWQsIHJlc29sdXRpb24gPSAwLjMpCgpFbGJvd1Bsb3QocmVmZXJlbmNlX2ludGVncmF0ZWQsIG5kaW1zID0gNTApCgojIFZpc3VhbGl6ZSBVTUFQIGNvbG9yZWQgYnkgb3JpZ2luYWwgZG9ub3IgKGNlbGxfbGluZSkKRGltUGxvdChyZWZlcmVuY2VfaW50ZWdyYXRlZCwgZ3JvdXAuYnkgPSAiY2VsbF9saW5lIiwgcmVkdWN0aW9uID0gInVtYXAiKSArCiAgZ2d0aXRsZSgiVU1BUCBvZiBJbnRlZ3JhdGVkIENENOKBuiBUIENlbGxzIikKCiMgVmlzdWFsaXplIFVNQVAgY29sb3JlZCBieSBvcmlnaW5hbCBkb25vciAoY2VsbF9saW5lKQpEaW1QbG90KHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCBncm91cC5ieSA9ICJpbnRlZ3JhdGVkX3Nubl9yZXMuMC4zIiwgcmVkdWN0aW9uID0gInVtYXAiKSArCiAgZ2d0aXRsZSgiVU1BUCBvZiBJbnRlZ3JhdGVkIENENOKBuiBUIENlbGxzIikKCiMgVmlzdWFsaXplIFVNQVAgY29sb3JlZCBieSBvcmlnaW5hbCBkb25vciAoY2VsbF9saW5lKQpEaW1QbG90KHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCBncm91cC5ieSA9ICJQcmVkaWN0aW9uIiwgcmVkdWN0aW9uID0gInVtYXAiKSArCiAgZ2d0aXRsZSgiVU1BUCBvZiBJbnRlZ3JhdGVkIENENOKBuiBUIENlbGxzIikKCiMgVmlzdWFsaXplIFVNQVAgY29sb3JlZCBieSBvcmlnaW5hbCBkb25vciAoY2VsbF9saW5lKQpEaW1QbG90KHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiLCByZWR1Y3Rpb24gPSAidW1hcCIpICsKICBnZ3RpdGxlKCJVTUFQIG9mIEludGVncmF0ZWQgQ0Q04oG6IFQgQ2VsbHMiKQoKYGBgCgojIyBTYXZlIHRoZSBtYXBwZWQgcXVlcnkgb2JqZWN0IChTw6l6YXJ5IGNlbGwgbGluZXMgcHJvamVjdGVkIG9udG8gcmVmZXJlbmNlIHRyYWplY3RvcnkpOgpgYGB7cn0KCgpzYXZlUkRTKHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCBmaWxlID0gInNlemFyeV9jZWxsX2xpbmVzX21hcHBlZF90b19jZDRfcmVmZXJlbmNlX2ludGVncmF0ZWRfYmVmb3JlX01vbm9jbGUzLnJkcyIpCgoKYGBgCgojIDQuIFRyYWplY3RvcnkgYW5kIFBzZXVkb3RpbWUgd2l0aCBNb25vY2xlMwpgYGB7cn0KbGlicmFyeShtb25vY2xlMykKbGlicmFyeShTZXVyYXRXcmFwcGVycykKbGlicmFyeShNYXRyaXgpCgpjZHMgPC0gYXMuY2VsbF9kYXRhX3NldChyZWZlcmVuY2VfaW50ZWdyYXRlZCkKY2RzIDwtIGNsdXN0ZXJfY2VsbHMoY2RzLCByZWR1Y3Rpb25fbWV0aG9kID0gIlVNQVAiKQpjZHMgPC0gbGVhcm5fZ3JhcGgoY2RzLCB1c2VfcGFydGl0aW9uID0gVFJVRSkKCm5haXZlX21hcmtlcnMgPC0gYygiQ0NSNyIsICJTRUxMIiwgIkxFRjEiKQpuYWl2ZV9tYXJrZXJzIDwtIG5haXZlX21hcmtlcnNbbmFpdmVfbWFya2VycyAlaW4lIHJvd25hbWVzKGNkcyldCgojIEV4dHJhY3QgbG9nLW5vcm1hbGl6ZWQgZXhwcmVzc2lvbiBvciBmYWxsYmFjayB0byBjb3VudHMgbG9nLXRyYW5zZm9ybWVkCmlmKCJsb2djb3VudHMiICVpbiUgYXNzYXlOYW1lcyhjZHMpKSB7CiAgZXhwcl9tYXQgPC0gYXNzYXkoY2RzLCAibG9nY291bnRzIikKfSBlbHNlIHsKICBleHByX21hdCA8LSBsb2cxcChhc3NheShjZHMsICJjb3VudHMiKSkKfQoKbmFpdmVfc2NvcmUgPC0gTWF0cml4Ojpjb2xNZWFucyhleHByX21hdFtuYWl2ZV9tYXJrZXJzLCAsIGRyb3AgPSBGQUxTRV0pCnRocmVzaG9sZCA8LSBxdWFudGlsZShuYWl2ZV9zY29yZSwgMC45NSkKcm9vdF9jZWxscyA8LSBuYW1lcyhuYWl2ZV9zY29yZVtuYWl2ZV9zY29yZSA+IHRocmVzaG9sZF0pCgpjZHMgPC0gb3JkZXJfY2VsbHMoY2RzLCByb290X2NlbGxzID0gcm9vdF9jZWxscykKcmVmZXJlbmNlX2ludGVncmF0ZWQkcHNldWRvdGltZSA8LSBwc2V1ZG90aW1lKGNkcykKCnBsb3RfY2VsbHMoY2RzLCBjb2xvcl9jZWxsc19ieSA9ICJwc2V1ZG90aW1lIiwgc2hvd190cmFqZWN0b3J5X2dyYXBoID0gVFJVRSkKCiMgVmlzdWFsaXplIFVNQVAgY29sb3JlZCBieSBvcmlnaW5hbCBkb25vciAoY2VsbF9saW5lKQpEaW1QbG90KHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCBncm91cC5ieSA9ICJQcmVkaWN0aW9uIiwgcmVkdWN0aW9uID0gInVtYXAiKSArCiAgZ2d0aXRsZSgiVU1BUCBvZiBJbnRlZ3JhdGVkIENENOKBuiBUIENlbGxzIikKCiMgVmlzdWFsaXplIFVNQVAgY29sb3JlZCBieSBvcmlnaW5hbCBkb25vciAoY2VsbF9saW5lKQpEaW1QbG90KHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiLCByZWR1Y3Rpb24gPSAidW1hcCIpICsKICBnZ3RpdGxlKCJVTUFQIG9mIEludGVncmF0ZWQgQ0Q04oG6IFQgQ2VsbHMiKQoKYGBgCgojIyBTYXZlIHRoZSBtYXBwZWQgcXVlcnkgb2JqZWN0IChTw6l6YXJ5IGNlbGwgbGluZXMgcHJvamVjdGVkIG9udG8gcmVmZXJlbmNlIHRyYWplY3RvcnkpOgpgYGB7cn0KCgpzYXZlUkRTKHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCBmaWxlID0gInNlemFyeV9jZWxsX2xpbmVzX21hcHBlZF90b19jZDRfcmVmZXJlbmNlX2ludGVncmF0ZWRfYmVmb3JlX1F1ZXJ5X1Byb2plY3Rpb24ucmRzIikKCgpgYGAKCgoKIyA1LiBQcmVwYXJlIFPDqXphcnkgU3luZHJvbWUgQ2VsbCBMaW5lcyBhcyBRdWVyeQpgYGB7cn0KIyBMb2FkIHJlcXVpcmVkIHBhY2thZ2VzCmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KGdsbUdhbVBvaSkgICAjIFJlY29tbWVuZGVkIGZvciBtZW1vcnktZWZmaWNpZW50IFNDVHJhbnNmb3JtCmxpYnJhcnkoZnV0dXJlKQoKIyBPcHRpb25hbDogUGFyYWxsZWwgc2V0dXAgdG8gaGFuZGxlIG1lbW9yeSBiZXR0ZXIKcGxhbigibXVsdGlzZXNzaW9uIiwgd29ya2VycyA9IDQpCm9wdGlvbnMoZnV0dXJlLmdsb2JhbHMubWF4U2l6ZSA9IDUwICogMTAyNF4zKSAgIyA1MCBHQiBtZW1vcnkgY2VpbGluZwoKIyBTdGVwIDE6IFN1YnNldCBTw6l6YXJ5IHN5bmRyb21lIGNlbGwgbGluZXMKcXVlcnlfc3Vic2V0IDwtIHN1YnNldChBbGxfc2FtcGxlc19NZXJnZWQsIHN1YnNldCA9IGNlbGxfbGluZSAlaW4lIHBhc3RlMCgiTCIsIDE6NykpCgojIFN0ZXAgMjogR2V0IHJhdyBjb3VudHMgbWF0cml4IGZyb20gUk5BIGFzc2F5CnF1ZXJ5X3JhdyA8LSBHZXRBc3NheURhdGEocXVlcnlfc3Vic2V0LCBhc3NheSA9ICJSTkEiLCBzbG90ID0gImNvdW50cyIpCgojIFN0ZXAgMzogRmlsdGVyIG91dCBnZW5lcyBleHByZXNzZWQgaW4gPDMgY2VsbHMgKHNhdmVzIG1lbW9yeSkKa2VlcF9nZW5lcyA8LSByb3dTdW1zKHF1ZXJ5X3JhdyA+IDApID49IDMKcXVlcnlfcmF3X2ZpbHRlcmVkIDwtIHF1ZXJ5X3Jhd1trZWVwX2dlbmVzLCBdCgojIFN0ZXAgNDogQ3JlYXRlIGEgbmV3IFNldXJhdCBvYmplY3Qgd2l0aCBtZXRhZGF0YSBwcmVzZXJ2ZWQKcXVlcnlfY2VsbHMgPC0gQ3JlYXRlU2V1cmF0T2JqZWN0KGNvdW50cyA9IHF1ZXJ5X3Jhd19maWx0ZXJlZCwgbWV0YS5kYXRhID0gcXVlcnlfc3Vic2V0QG1ldGEuZGF0YSkKCiMgU3RlcCA1OiBSdW4gU0NUcmFuc2Zvcm0gd2l0aCBnbG1HYW1Qb2kgYmFja2VuZCBmb3IgYmV0dGVyIHBlcmZvcm1hbmNlCnF1ZXJ5X3NldXJhdCA8LSBTQ1RyYW5zZm9ybSgKICBxdWVyeV9zZXVyYXQsCiAgbWV0aG9kID0gImdsbUdhbVBvaSIsCiAgY29uc2VydmUubWVtb3J5ID0gVFJVRSwgICAjIENyaXRpY2FsIGZvciBsYXJnZSBkYXRhc2V0cwogIHZhcmlhYmxlLmZlYXR1cmVzLm4gPSAwLCAgIyBEb24ndCByZXNlbGVjdCBmZWF0dXJlcyAodXNlIHJlZl9mZWF0dXJlcykKICB2ZXJib3NlID0gRkFMU0UKKQoKCmBgYAoKIyA2LiBJbmplY3QgQ2VsbCBMaW5lcyBpbnRvIFJlZmVyZW5jZSB3aXRoIE1hcFF1ZXJ5CmBgYHtyfQoKIyBGaW5kIGFuY2hvcnMgYmV0d2VlbiByZWZlcmVuY2UgYW5kIHF1ZXJ5CmFuY2hvcnNfcXVlcnkgPC0gRmluZFRyYW5zZmVyQW5jaG9ycygKICByZWZlcmVuY2UgPSByZWZlcmVuY2VfaW50ZWdyYXRlZCwKICBxdWVyeSA9IHF1ZXJ5X2NlbGxzLAogIHJlZmVyZW5jZS5yZWR1Y3Rpb24gPSAicGNhIiwKICBub3JtYWxpemF0aW9uLm1ldGhvZCA9ICJTQ1QiLAogIGRpbXMgPSAxOjE4CikKCiMgTWFwIHF1ZXJ5IGNlbGxzIHRvIHJlZmVyZW5jZQpxdWVyeV9tYXBwZWQgPC0gTWFwUXVlcnkoCiAgYW5jaG9yc2V0ID0gYW5jaG9yc19xdWVyeSwKICBxdWVyeSA9IHF1ZXJ5X2NlbGxzLAogIHJlZmVyZW5jZSA9IHJlZmVyZW5jZV9pbnRlZ3JhdGVkLAogIHJlZmRhdGEgPSBsaXN0KAogICAgcHNldWRvdGltZSA9ICJwc2V1ZG90aW1lIiwgICAgICAgICMgVHJhbnNmZXIgcHNldWRvdGltZQogICAgc2V1cmF0X2NsdXN0ZXJzID0gInNldXJhdF9jbHVzdGVycyIsICMgVHJhbnNmZXIgY2x1c3RlcnMKICAgIHRyYWplY3RvcnlfcG9zaXRpb24gPSAibW9ub2NsZTNfZW1iZWRkaW5nIiAjIElmIHN0b3JpbmcgTVNUIGNvb3JkcwogICksCiAgcmVmZXJlbmNlLnJlZHVjdGlvbiA9ICJwY2EiLCAKICByZWR1Y3Rpb24ubW9kZWwgPSAidW1hcCIKKQoKCmBgYAoKIyA3LiBWaXN1YWxpemF0aW9uIChQbG90IFJlZmVyZW5jZSBhbmQgSW5qZWN0ZWQgQ2VsbHMgYnkgUHNldWRvdGltZSBhbmQgQ2VsbCBMaW5lKQpgYGB7cn0KCiMgUGxvdCB0aGUgcmVmZXJlbmNlIHRyYWplY3RvcnkgVU1BUCwgY29sb3JlZCBieSBwc2V1ZG90aW1lCkRpbVBsb3QocmVmZXJlbmNlX2ludGVncmF0ZWQsIGdyb3VwLmJ5ID0gInBzZXVkb3RpbWUiLCByZWR1Y3Rpb24gPSAidW1hcCIpICsKICBnZ3RpdGxlKCJSZWZlcmVuY2UgQ0Q04oG6IFQgQ2VsbCBUcmFqZWN0b3J5IChQc2V1ZG90aW1lKSIpCgojIE92ZXJsYXkgaW5qZWN0ZWQgY2VsbCBsaW5lcwpEaW1QbG90KHF1ZXJ5X21hcHBlZCwgcmVkdWN0aW9uID0gInJlZi51bWFwIiwgZ3JvdXAuYnkgPSAiY2VsbF9saW5lIiwgbGFiZWwgPSBUUlVFKSArCiAgZ2d0aXRsZSgiSW5qZWN0ZWQgU8OpemFyeSBDZWxsIExpbmVzIG9uIFJlZmVyZW5jZSBUcmFqZWN0b3J5IikKCgpgYGAKCgojIyBWaXN1YWxpemF0aW9uICYgQW5hbHlzaXMKYGBge3J9CgojIENvbWJpbmVkIFVNQVAgd2l0aCBwc2V1ZG90aW1lCnAxIDwtIERpbVBsb3QocmVmZXJlbmNlX2ludGVncmF0ZWQsIAogICAgICAgICAgICAgIGdyb3VwLmJ5ID0gInBzZXVkb3RpbWUiLCAKICAgICAgICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKG9wdGlvbiA9ICJtYWdtYSIpCgpwMiA8LSBEaW1QbG90KHF1ZXJ5X21hcHBlZCwgCiAgICAgICAgICAgICAgcmVkdWN0aW9uID0gInJlZi51bWFwIiwgCiAgICAgICAgICAgICAgZ3JvdXAuYnkgPSAiY2VsbF9saW5lIiwgCiAgICAgICAgICAgICAgY29scyA9ICJkYXJrcmVkIikgKyAKICBnZ3RpdGxlKCJTw6l6YXJ5IENlbGwgTGluZXMiKQoKcDEgKyBwMgoKIyBQc2V1ZG90aW1lIGRpc3RyaWJ1dGlvbiBpbiBjZWxsIGxpbmVzClZsblBsb3QocXVlcnlfbWFwcGVkLCAKICAgICAgICBmZWF0dXJlcyA9ICJwc2V1ZG90aW1lIiwgCiAgICAgICAgZ3JvdXAuYnkgPSAiY2VsbF9saW5lIiwgCiAgICAgICAgcHQuc2l6ZSA9IDAuMSkgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMikKCiMgUHJvamVjdCBjZWxsIGxpbmVzIG9uIHJlZmVyZW5jZSB0cmFqZWN0b3J5CkZlYXR1cmVQbG90KHF1ZXJ5X21hcHBlZCwgCiAgICAgICAgICAgZmVhdHVyZXMgPSAicHNldWRvdGltZSIsIAogICAgICAgICAgIHJlZHVjdGlvbiA9ICJyZWYudW1hcCIpICsKICBnZW9tX3BvaW50KGRhdGEgPSBxdWVyeV9tYXBwZWRbW11dLCAKICAgICAgICAgICAgIGFlcyh4ID0gcmVmVU1BUF8xLCB5ID0gcmVmVU1BUF8yLCBjb2xvciA9IHBzZXVkb3RpbWUpLAogICAgICAgICAgICAgc2l6ZSA9IDEuNSkKCmBgYAojIyBBbmFseXplIFBzZXVkb3RpbWUgRGlzdHJpYnV0aW9ucyBBY3Jvc3MgQ2VsbCBMaW5lcwpgYGB7cn0KCgpGZWF0dXJlUGxvdChxdWVyeV9tYXBwZWQsIGZlYXR1cmVzID0gInBzZXVkb3RpbWUiLCByZWR1Y3Rpb24gPSAicmVmLnVtYXAiKSArCiAgZ2d0aXRsZSgiUHNldWRvdGltZSBWYWx1ZXMgb2YgSW5qZWN0ZWQgQ2VsbCBMaW5lcyIpCgpWbG5QbG90KHF1ZXJ5X21hcHBlZCwgZmVhdHVyZXMgPSAicHNldWRvdGltZSIsIGdyb3VwLmJ5ID0gImNlbGxfbGluZSIpICsKICBnZ3RpdGxlKCJQc2V1ZG90aW1lIERpc3RyaWJ1dGlvbiBieSBDZWxsIExpbmUiKQpgYGAKCiMjIFNhdmUgdGhlIG1hcHBlZCBxdWVyeSBvYmplY3QgKFPDqXphcnkgY2VsbCBsaW5lcyBwcm9qZWN0ZWQgb250byByZWZlcmVuY2UgdHJhamVjdG9yeSk6CmBgYHtyfQoKCnNhdmVSRFMocXVlcnlfbWFwcGVkLCBmaWxlID0gInNlemFyeV9jZWxsX2xpbmVzX21hcHBlZF90b19jZDRfcmVmZXJlbmNlLnJkcyIpCgpgYGAK