1. load libraries

2. Read object with all samples


All_samples_Merged <- readRDS("../../0-Seurat_RDS_OBJECT_FINAL/All_samples_Merged_with_STCAT_and_renamed_FINAL.rds")

# Add "group" column to metadata
All_samples_Merged$Group <- ifelse(All_samples_Merged$cell_line %in% paste0("L", 1:7),
                                   "MalignantCD4T",
                            ifelse(All_samples_Merged$cell_line %in% c("CD4Tcells_lab", "CD4Tcells_10x"),
                                   "NormalCD4T", "Other"))

table(All_samples_Merged$Group)

MalignantCD4T    NormalCD4T 
        40695          8610 

3. Read object with all Reference_CD4Tcells


 reference_integrated <- readRDS("Step1_sezary_cell_lines_mapped_to_cd4_reference_integrated_before_Query_Projection_03-09-2025.rds")

Trajectory and Pseudotime with Monocle3

reference_integrated$pseudotime[!is.finite(reference_integrated$pseudotime)] <- NA


max_finite <- max(reference_integrated$pseudotime, na.rm = TRUE)
reference_integrated$pseudotime[!is.finite(reference_integrated$pseudotime)] <- max_finite

summary(reference_integrated$pseudotime)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
0.00000 0.01969 0.19290 0.93865 0.90736 5.63665 
table(is.finite(reference_integrated$pseudotime))

TRUE 
8610 
FeaturePlot(
  reference_integrated,
  features = "pseudotime",
  reduction = "umap",
  cols = c("lightblue", "red"),
  label = TRUE
) + ggtitle("UMAP of Integrated CD4⁺ T Cells by Pseudotime") +
  theme(plot.title = element_text(hjust = 0.5))

NA
NA

Trajectory and Pseudotime with Monocle3



# 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")

4. Subset MalignantCD4T cells


# Subset MalignantCD4T cells
MalignantCD4T <- subset(All_samples_Merged, subset = Group == "MalignantCD4T")


# Use SCT assay for both
DefaultAssay(reference_integrated) <- "SCT"
DefaultAssay(MalignantCD4T) <- "SCT"


# Make sure both have variable features set
if (length(VariableFeatures(reference_integrated)) == 0) {
  reference_integrated <- FindVariableFeatures(reference_integrated, assay = "SCT", selection.method = "vst", nfeatures = 3000)
}
if (length(VariableFeatures(MalignantCD4T)) == 0) {
  MalignantCD4T <- FindVariableFeatures(MalignantCD4T, assay = "SCT", selection.method = "vst", nfeatures = 3000)
}

# Find anchors
anchors <- FindTransferAnchors(
  reference = reference_integrated,
  query = MalignantCD4T,
  normalization.method = "SCT",
  reference.reduction = "pca",
  dims = 1:18
)
[1] "Given reference assay has multiple sct models, selecting model with most cells for finding transfer anchors"
gc()
             used    (Mb) gc trigger    (Mb)   max used    (Mb)
Ncells    8828727   471.6   15971052   853.0   15971052   853.0
Vcells 2508768160 19140.4 4750680560 36244.9 3958833800 30203.6
reference_integrated <- RunUMAP(
  reference_integrated,
  reduction = "pca",
  dims = 1:18,
  assay = "SCT",
  return.model = TRUE,   # For Seurat v5, save.model = TRUE deprecated; use return.model
)
Using method 'umap'
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
# Map query onto reference and transfer pseudotime
mapped_MalignantCD4T <- MapQuery(
  anchorset = anchors,
  query = MalignantCD4T,
  reference = reference_integrated,
  refdata = list(
    pseudotime = reference_integrated$pseudotime,
    seurat_clusters = reference_integrated$seurat_clusters,
    Prediction = reference_integrated$Prediction,
    predicted.celltype.l2 = reference_integrated$predicted.celltype.l2
  ),
  reference.reduction = "pca",
  reduction.model = "umap"
)
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|

  |                                                  | 0 % ~calculating  
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=03s  
Using method 'umap'
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
# Convert numeric pseudotime vector into a 1-row matrix with rowname
pseudo_mat <- matrix(reference_integrated$pseudotime, nrow = 1)
colnames(pseudo_mat) <- colnames(reference_integrated)  # cells
rownames(pseudo_mat) <- "pseudotime"                     # feature name

# Transfer numeric pseudotime
pseudotime_transfer <- TransferData(
  anchorset = anchors,
  refdata = pseudo_mat,
  weight.reduction = MalignantCD4T[["pca"]],
  dims = 1:18
)
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
# Extract the data from the assay
pseudotime_vector <- GetAssayData(pseudotime_transfer, slot = "data")["pseudotime", ]

# Add to metadata
mapped_MalignantCD4T$pseudotime <- pseudotime_vector

#  Visualize pseudotime
FeaturePlot(mapped_MalignantCD4T,
            features = "pseudotime",
            reduction = "ref.umap",
            cols = c("lightblue","red"),
            label = TRUE) +
  ggtitle("Pseudotime Mapping of MalignantCD4T onto Reference") +
  theme(plot.title = element_text(hjust = 0.5))


#  Visualize transferred cell type annotations
DimPlot(mapped_MalignantCD4T, group.by = "Prediction", reduction = "ref.umap") +
  ggtitle("Mapped MalignantCD4T: Prediction Annotations") +
  theme(plot.title = element_text(hjust = 0.5))


DimPlot(mapped_MalignantCD4T, group.by = "predicted.celltype.l2", reduction = "ref.umap") +
  ggtitle("Mapped MalignantCD4T: predicted.celltype.l2 Annotations") +
  theme(plot.title = element_text(hjust = 0.5))

Mapping of MalignantCD4T on Reference



library(ggplot2)

# Prepare reference data
ref_df <- data.frame(Embeddings(reference_integrated, "umap"))
ref_df$dataset <- "Reference"

# Prepare MalignantCD4T query data
query_df <- data.frame(Embeddings(mapped_MalignantCD4T, "ref.umap"))
query_df$dataset <- "MalignantCD4T"
query_df$pseudotime <- mapped_MalignantCD4T$pseudotime  # if pseudotime exists

# Plot reference in grey, MalignantCD4T cells colored by pseudotime
ggplot() +
  geom_point(data = ref_df, aes(x = umap_1, y = umap_2),
             color = "grey80", size = 0.5) +
  geom_point(data = query_df, aes(x = refUMAP_1, y = refUMAP_2, color = pseudotime),
             size = 1) +
  scale_color_gradient(low = "lightblue", high = "red") +
  theme_classic() +
  ggtitle("MalignantCD4T cells projected onto reference UMAP") +
  theme(plot.title = element_text(hjust = 0.5))

NA
NA

Mapping of MalignantCD4T on Reference (Azimuth)


library(ggplot2)

# Reference coordinates (grey background)
ref_df <- data.frame(Embeddings(reference_integrated, "umap"))
ref_df$dataset <- "Reference"

# Query (MalignantCD4T) coordinates
query_df <- data.frame(Embeddings(mapped_MalignantCD4T, "ref.umap"))
query_df$dataset <- "MalignantCD4T"

# Make sure annotations exist in mapped_MalignantCD4T
query_df$celltype <- mapped_MalignantCD4T$predicted.celltype.l2  # or "Prediction"

library(RColorBrewer)

big_palette <- colorRampPalette(brewer.pal(12, "Paired"))(20)

ggplot() +
  geom_point(data = ref_df, aes(x = umap_1, y = umap_2),
             color = "grey80", size = 0.5) +
  geom_point(data = query_df, aes(x = refUMAP_1, y = refUMAP_2, color = celltype),
             size = 1) +
  scale_color_manual(values = big_palette) +
  theme_classic() +
  ggtitle("MalignantCD4T cells projected onto reference UMAP with annotations") +
  theme(plot.title = element_text(hjust = 0.5))

NA
NA

Mapping of MalignantCD4T on Reference (STCAT)


library(ggplot2)

# Reference coordinates (grey background)
ref_df <- data.frame(Embeddings(reference_integrated, "umap"))
ref_df$dataset <- "Reference"

# Query (MalignantCD4T) coordinates
query_df <- data.frame(Embeddings(mapped_MalignantCD4T, "ref.umap"))
query_df$dataset <- "MalignantCD4T"

# Make sure annotations exist in mapped_MalignantCD4T
query_df$celltype <- mapped_MalignantCD4T$Prediction  # or "Prediction"

library(RColorBrewer)

# Get a palette with up to 20 colors
big_palette <- colorRampPalette(brewer.pal(12, "Paired"))(20)

ggplot() +
  geom_point(data = ref_df, aes(x = umap_1, y = umap_2),
             color = "grey80", size = 0.5) +
  geom_point(data = query_df, aes(x = refUMAP_1, y = refUMAP_2, color = celltype),
             size = 1) +
  scale_color_manual(values = big_palette) +
  theme_classic() +
  ggtitle("MalignantCD4T cells projected onto reference UMAP with annotations") +
  theme(plot.title = element_text(hjust = 0.5))

NA
NA

5. Subset MalignantCD4T Projection


# 1. Define output directory
out_dir <- "results/MalignantCD4T_projection"
if(!dir.exists(out_dir)) dir.create(out_dir, recursive = TRUE)

save(mapped_MalignantCD4T, file = file.path(out_dir, "MalignantCD4T_mapped_on_reference_with_pseudotime-3-8-2025.Robj"))
LS0tCnRpdGxlOiAiU3RlcDI6TWFsaWduYW50Q0Q0VCBwcm9qZWN0aW9uIG9mIFJlZmVyZW5jZUNENFRjZWxscyIKYXV0aG9yOiAiTmFzaXIgTWFobW9vZCBBYmJhc2kiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIHRvY19jb2xsYXBzZWQ6IHllcwogIHdvcmRfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICBwZGZfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwotLS0KCiMgMS4gbG9hZCBsaWJyYXJpZXMKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CgpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShtb25vY2xlMykKbGlicmFyeShTZXVyYXRXcmFwcGVycykKbGlicmFyeShoYXJtb255KQoKCiMgRXh0cmEgbGlicmFyaWVzCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkocGhlYXRtYXApCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShNYXRyaXgpCmxpYnJhcnkocGF0Y2h3b3JrKQoKCnNldC5zZWVkKDEyMzQpCgpgYGAKCgojIDIuIFJlYWQgb2JqZWN0IHdpdGggYWxsIHNhbXBsZXMKYGBge3IgfQoKQWxsX3NhbXBsZXNfTWVyZ2VkIDwtIHJlYWRSRFMoIi4uLy4uLzAtU2V1cmF0X1JEU19PQkpFQ1RfRklOQUwvQWxsX3NhbXBsZXNfTWVyZ2VkX3dpdGhfU1RDQVRfYW5kX3JlbmFtZWRfRklOQUwucmRzIikKCiMgQWRkICJncm91cCIgY29sdW1uIHRvIG1ldGFkYXRhCkFsbF9zYW1wbGVzX01lcmdlZCRHcm91cCA8LSBpZmVsc2UoQWxsX3NhbXBsZXNfTWVyZ2VkJGNlbGxfbGluZSAlaW4lIHBhc3RlMCgiTCIsIDE6NyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1hbGlnbmFudENENFQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKEFsbF9zYW1wbGVzX01lcmdlZCRjZWxsX2xpbmUgJWluJSBjKCJDRDRUY2VsbHNfbGFiIiwgIkNENFRjZWxsc18xMHgiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm9ybWFsQ0Q0VCIsICJPdGhlciIpKQoKdGFibGUoQWxsX3NhbXBsZXNfTWVyZ2VkJEdyb3VwKQoKCgpgYGAKCiMgMy4gUmVhZCBvYmplY3Qgd2l0aCBhbGwgUmVmZXJlbmNlX0NENFRjZWxscwpgYGB7ciB9CgogcmVmZXJlbmNlX2ludGVncmF0ZWQgPC0gcmVhZFJEUygiU3RlcDFfc2V6YXJ5X2NlbGxfbGluZXNfbWFwcGVkX3RvX2NkNF9yZWZlcmVuY2VfaW50ZWdyYXRlZF9iZWZvcmVfUXVlcnlfUHJvamVjdGlvbl8wMy0wOS0yMDI1LnJkcyIpCgoKYGBgCgoKIyMgVHJhamVjdG9yeSBhbmQgUHNldWRvdGltZSB3aXRoIE1vbm9jbGUzCmBgYHtyfQpyZWZlcmVuY2VfaW50ZWdyYXRlZCRwc2V1ZG90aW1lWyFpcy5maW5pdGUocmVmZXJlbmNlX2ludGVncmF0ZWQkcHNldWRvdGltZSldIDwtIE5BCgoKbWF4X2Zpbml0ZSA8LSBtYXgocmVmZXJlbmNlX2ludGVncmF0ZWQkcHNldWRvdGltZSwgbmEucm0gPSBUUlVFKQpyZWZlcmVuY2VfaW50ZWdyYXRlZCRwc2V1ZG90aW1lWyFpcy5maW5pdGUocmVmZXJlbmNlX2ludGVncmF0ZWQkcHNldWRvdGltZSldIDwtIG1heF9maW5pdGUKCnN1bW1hcnkocmVmZXJlbmNlX2ludGVncmF0ZWQkcHNldWRvdGltZSkKdGFibGUoaXMuZmluaXRlKHJlZmVyZW5jZV9pbnRlZ3JhdGVkJHBzZXVkb3RpbWUpKQoKRmVhdHVyZVBsb3QoCiAgcmVmZXJlbmNlX2ludGVncmF0ZWQsCiAgZmVhdHVyZXMgPSAicHNldWRvdGltZSIsCiAgcmVkdWN0aW9uID0gInVtYXAiLAogIGNvbHMgPSBjKCJsaWdodGJsdWUiLCAicmVkIiksCiAgbGFiZWwgPSBUUlVFCikgKyBnZ3RpdGxlKCJVTUFQIG9mIEludGVncmF0ZWQgQ0Q04oG6IFQgQ2VsbHMgYnkgUHNldWRvdGltZSIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKCgpgYGAKIyMgVHJhamVjdG9yeSBhbmQgUHNldWRvdGltZSB3aXRoIE1vbm9jbGUzCmBgYHtyfQoKCiMgVmlzdWFsaXplIFVNQVAgY29sb3JlZCBieSBvcmlnaW5hbCBkb25vciAoY2VsbF9saW5lKQpEaW1QbG90KHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCBncm91cC5ieSA9ICJQcmVkaWN0aW9uIiwgcmVkdWN0aW9uID0gInVtYXAiKSArCiAgZ2d0aXRsZSgiVU1BUCBvZiBJbnRlZ3JhdGVkIENENOKBuiBUIENlbGxzIikKCiMgVmlzdWFsaXplIFVNQVAgY29sb3JlZCBieSBvcmlnaW5hbCBkb25vciAoY2VsbF9saW5lKQpEaW1QbG90KHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiLCByZWR1Y3Rpb24gPSAidW1hcCIpICsKICBnZ3RpdGxlKCJVTUFQIG9mIEludGVncmF0ZWQgQ0Q04oG6IFQgQ2VsbHMiKQoKYGBgCgojIDQuIFN1YnNldCBNYWxpZ25hbnRDRDRUIGNlbGxzCmBgYHtyIH0KCiMgU3Vic2V0IE1hbGlnbmFudENENFQgY2VsbHMKTWFsaWduYW50Q0Q0VCA8LSBzdWJzZXQoQWxsX3NhbXBsZXNfTWVyZ2VkLCBzdWJzZXQgPSBHcm91cCA9PSAiTWFsaWduYW50Q0Q0VCIpCgoKIyBVc2UgU0NUIGFzc2F5IGZvciBib3RoCkRlZmF1bHRBc3NheShyZWZlcmVuY2VfaW50ZWdyYXRlZCkgPC0gIlNDVCIKRGVmYXVsdEFzc2F5KE1hbGlnbmFudENENFQpIDwtICJTQ1QiCgoKIyBNYWtlIHN1cmUgYm90aCBoYXZlIHZhcmlhYmxlIGZlYXR1cmVzIHNldAppZiAobGVuZ3RoKFZhcmlhYmxlRmVhdHVyZXMocmVmZXJlbmNlX2ludGVncmF0ZWQpKSA9PSAwKSB7CiAgcmVmZXJlbmNlX2ludGVncmF0ZWQgPC0gRmluZFZhcmlhYmxlRmVhdHVyZXMocmVmZXJlbmNlX2ludGVncmF0ZWQsIGFzc2F5ID0gIlNDVCIsIHNlbGVjdGlvbi5tZXRob2QgPSAidnN0IiwgbmZlYXR1cmVzID0gMzAwMCkKfQppZiAobGVuZ3RoKFZhcmlhYmxlRmVhdHVyZXMoTWFsaWduYW50Q0Q0VCkpID09IDApIHsKICBNYWxpZ25hbnRDRDRUIDwtIEZpbmRWYXJpYWJsZUZlYXR1cmVzKE1hbGlnbmFudENENFQsIGFzc2F5ID0gIlNDVCIsIHNlbGVjdGlvbi5tZXRob2QgPSAidnN0IiwgbmZlYXR1cmVzID0gMzAwMCkKfQoKIyBGaW5kIGFuY2hvcnMKYW5jaG9ycyA8LSBGaW5kVHJhbnNmZXJBbmNob3JzKAogIHJlZmVyZW5jZSA9IHJlZmVyZW5jZV9pbnRlZ3JhdGVkLAogIHF1ZXJ5ID0gTWFsaWduYW50Q0Q0VCwKICBub3JtYWxpemF0aW9uLm1ldGhvZCA9ICJTQ1QiLAogIHJlZmVyZW5jZS5yZWR1Y3Rpb24gPSAicGNhIiwKICBkaW1zID0gMToxOAopCgpyZWZlcmVuY2VfaW50ZWdyYXRlZCA8LSBSdW5VTUFQKAogIHJlZmVyZW5jZV9pbnRlZ3JhdGVkLAogIHJlZHVjdGlvbiA9ICJwY2EiLAogIGRpbXMgPSAxOjE4LAogIGFzc2F5ID0gIlNDVCIsCiAgcmV0dXJuLm1vZGVsID0gVFJVRSwgICAjIEZvciBTZXVyYXQgdjUsIHNhdmUubW9kZWwgPSBUUlVFIGRlcHJlY2F0ZWQ7IHVzZSByZXR1cm4ubW9kZWwKKQoKCiMgTWFwIHF1ZXJ5IG9udG8gcmVmZXJlbmNlIGFuZCB0cmFuc2ZlciBwc2V1ZG90aW1lCm1hcHBlZF9NYWxpZ25hbnRDRDRUIDwtIE1hcFF1ZXJ5KAogIGFuY2hvcnNldCA9IGFuY2hvcnMsCiAgcXVlcnkgPSBNYWxpZ25hbnRDRDRULAogIHJlZmVyZW5jZSA9IHJlZmVyZW5jZV9pbnRlZ3JhdGVkLAogIHJlZmRhdGEgPSBsaXN0KAogICAgcHNldWRvdGltZSA9IHJlZmVyZW5jZV9pbnRlZ3JhdGVkJHBzZXVkb3RpbWUsCiAgICBzZXVyYXRfY2x1c3RlcnMgPSByZWZlcmVuY2VfaW50ZWdyYXRlZCRzZXVyYXRfY2x1c3RlcnMsCiAgICBQcmVkaWN0aW9uID0gcmVmZXJlbmNlX2ludGVncmF0ZWQkUHJlZGljdGlvbiwKICAgIHByZWRpY3RlZC5jZWxsdHlwZS5sMiA9IHJlZmVyZW5jZV9pbnRlZ3JhdGVkJHByZWRpY3RlZC5jZWxsdHlwZS5sMgogICksCiAgcmVmZXJlbmNlLnJlZHVjdGlvbiA9ICJwY2EiLAogIHJlZHVjdGlvbi5tb2RlbCA9ICJ1bWFwIgopCgojIENvbnZlcnQgbnVtZXJpYyBwc2V1ZG90aW1lIHZlY3RvciBpbnRvIGEgMS1yb3cgbWF0cml4IHdpdGggcm93bmFtZQpwc2V1ZG9fbWF0IDwtIG1hdHJpeChyZWZlcmVuY2VfaW50ZWdyYXRlZCRwc2V1ZG90aW1lLCBucm93ID0gMSkKY29sbmFtZXMocHNldWRvX21hdCkgPC0gY29sbmFtZXMocmVmZXJlbmNlX2ludGVncmF0ZWQpICAjIGNlbGxzCnJvd25hbWVzKHBzZXVkb19tYXQpIDwtICJwc2V1ZG90aW1lIiAgICAgICAgICAgICAgICAgICAgICMgZmVhdHVyZSBuYW1lCgojIFRyYW5zZmVyIG51bWVyaWMgcHNldWRvdGltZQpwc2V1ZG90aW1lX3RyYW5zZmVyIDwtIFRyYW5zZmVyRGF0YSgKICBhbmNob3JzZXQgPSBhbmNob3JzLAogIHJlZmRhdGEgPSBwc2V1ZG9fbWF0LAogIHdlaWdodC5yZWR1Y3Rpb24gPSBNYWxpZ25hbnRDRDRUW1sicGNhIl1dLAogIGRpbXMgPSAxOjE4CikKCiMgRXh0cmFjdCB0aGUgZGF0YSBmcm9tIHRoZSBhc3NheQpwc2V1ZG90aW1lX3ZlY3RvciA8LSBHZXRBc3NheURhdGEocHNldWRvdGltZV90cmFuc2Zlciwgc2xvdCA9ICJkYXRhIilbInBzZXVkb3RpbWUiLCBdCgojIEFkZCB0byBtZXRhZGF0YQptYXBwZWRfTWFsaWduYW50Q0Q0VCRwc2V1ZG90aW1lIDwtIHBzZXVkb3RpbWVfdmVjdG9yCgojICBWaXN1YWxpemUgcHNldWRvdGltZQpGZWF0dXJlUGxvdChtYXBwZWRfTWFsaWduYW50Q0Q0VCwKICAgICAgICAgICAgZmVhdHVyZXMgPSAicHNldWRvdGltZSIsCiAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJyZWYudW1hcCIsCiAgICAgICAgICAgIGNvbHMgPSBjKCJsaWdodGJsdWUiLCJyZWQiKSwKICAgICAgICAgICAgbGFiZWwgPSBUUlVFKSArCiAgZ2d0aXRsZSgiUHNldWRvdGltZSBNYXBwaW5nIG9mIE1hbGlnbmFudENENFQgb250byBSZWZlcmVuY2UiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCgojICBWaXN1YWxpemUgdHJhbnNmZXJyZWQgY2VsbCB0eXBlIGFubm90YXRpb25zCkRpbVBsb3QobWFwcGVkX01hbGlnbmFudENENFQsIGdyb3VwLmJ5ID0gIlByZWRpY3Rpb24iLCByZWR1Y3Rpb24gPSAicmVmLnVtYXAiKSArCiAgZ2d0aXRsZSgiTWFwcGVkIE1hbGlnbmFudENENFQ6IFByZWRpY3Rpb24gQW5ub3RhdGlvbnMiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCgpEaW1QbG90KG1hcHBlZF9NYWxpZ25hbnRDRDRULCBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiLCByZWR1Y3Rpb24gPSAicmVmLnVtYXAiKSArCiAgZ2d0aXRsZSgiTWFwcGVkIE1hbGlnbmFudENENFQ6IHByZWRpY3RlZC5jZWxsdHlwZS5sMiBBbm5vdGF0aW9ucyIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKCmBgYAojIyBNYXBwaW5nIG9mIE1hbGlnbmFudENENFQgb24gUmVmZXJlbmNlCmBgYHtyfQoKCmxpYnJhcnkoZ2dwbG90MikKCiMgUHJlcGFyZSByZWZlcmVuY2UgZGF0YQpyZWZfZGYgPC0gZGF0YS5mcmFtZShFbWJlZGRpbmdzKHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCAidW1hcCIpKQpyZWZfZGYkZGF0YXNldCA8LSAiUmVmZXJlbmNlIgoKIyBQcmVwYXJlIE1hbGlnbmFudENENFQgcXVlcnkgZGF0YQpxdWVyeV9kZiA8LSBkYXRhLmZyYW1lKEVtYmVkZGluZ3MobWFwcGVkX01hbGlnbmFudENENFQsICJyZWYudW1hcCIpKQpxdWVyeV9kZiRkYXRhc2V0IDwtICJNYWxpZ25hbnRDRDRUIgpxdWVyeV9kZiRwc2V1ZG90aW1lIDwtIG1hcHBlZF9NYWxpZ25hbnRDRDRUJHBzZXVkb3RpbWUgICMgaWYgcHNldWRvdGltZSBleGlzdHMKCiMgUGxvdCByZWZlcmVuY2UgaW4gZ3JleSwgTWFsaWduYW50Q0Q0VCBjZWxscyBjb2xvcmVkIGJ5IHBzZXVkb3RpbWUKZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHJlZl9kZiwgYWVzKHggPSB1bWFwXzEsIHkgPSB1bWFwXzIpLAogICAgICAgICAgICAgY29sb3IgPSAiZ3JleTgwIiwgc2l6ZSA9IDAuNSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHF1ZXJ5X2RmLCBhZXMoeCA9IHJlZlVNQVBfMSwgeSA9IHJlZlVNQVBfMiwgY29sb3IgPSBwc2V1ZG90aW1lKSwKICAgICAgICAgICAgIHNpemUgPSAxKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gImxpZ2h0Ymx1ZSIsIGhpZ2ggPSAicmVkIikgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgZ2d0aXRsZSgiTWFsaWduYW50Q0Q0VCBjZWxscyBwcm9qZWN0ZWQgb250byByZWZlcmVuY2UgVU1BUCIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKCgpgYGAKIyMgTWFwcGluZyBvZiBNYWxpZ25hbnRDRDRUIG9uIFJlZmVyZW5jZSAoQXppbXV0aCkKYGBge3J9CgpsaWJyYXJ5KGdncGxvdDIpCgojIFJlZmVyZW5jZSBjb29yZGluYXRlcyAoZ3JleSBiYWNrZ3JvdW5kKQpyZWZfZGYgPC0gZGF0YS5mcmFtZShFbWJlZGRpbmdzKHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCAidW1hcCIpKQpyZWZfZGYkZGF0YXNldCA8LSAiUmVmZXJlbmNlIgoKIyBRdWVyeSAoTWFsaWduYW50Q0Q0VCkgY29vcmRpbmF0ZXMKcXVlcnlfZGYgPC0gZGF0YS5mcmFtZShFbWJlZGRpbmdzKG1hcHBlZF9NYWxpZ25hbnRDRDRULCAicmVmLnVtYXAiKSkKcXVlcnlfZGYkZGF0YXNldCA8LSAiTWFsaWduYW50Q0Q0VCIKCiMgTWFrZSBzdXJlIGFubm90YXRpb25zIGV4aXN0IGluIG1hcHBlZF9NYWxpZ25hbnRDRDRUCnF1ZXJ5X2RmJGNlbGx0eXBlIDwtIG1hcHBlZF9NYWxpZ25hbnRDRDRUJHByZWRpY3RlZC5jZWxsdHlwZS5sMiAgIyBvciAiUHJlZGljdGlvbiIKCmxpYnJhcnkoUkNvbG9yQnJld2VyKQoKYmlnX3BhbGV0dGUgPC0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDEyLCAiUGFpcmVkIikpKDIwKQoKZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHJlZl9kZiwgYWVzKHggPSB1bWFwXzEsIHkgPSB1bWFwXzIpLAogICAgICAgICAgICAgY29sb3IgPSAiZ3JleTgwIiwgc2l6ZSA9IDAuNSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHF1ZXJ5X2RmLCBhZXMoeCA9IHJlZlVNQVBfMSwgeSA9IHJlZlVNQVBfMiwgY29sb3IgPSBjZWxsdHlwZSksCiAgICAgICAgICAgICBzaXplID0gMSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBiaWdfcGFsZXR0ZSkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgZ2d0aXRsZSgiTWFsaWduYW50Q0Q0VCBjZWxscyBwcm9qZWN0ZWQgb250byByZWZlcmVuY2UgVU1BUCB3aXRoIGFubm90YXRpb25zIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQoKCmBgYAoKIyMgTWFwcGluZyBvZiBNYWxpZ25hbnRDRDRUIG9uIFJlZmVyZW5jZSAoU1RDQVQpCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMH0KCmxpYnJhcnkoZ2dwbG90MikKCiMgUmVmZXJlbmNlIGNvb3JkaW5hdGVzIChncmV5IGJhY2tncm91bmQpCnJlZl9kZiA8LSBkYXRhLmZyYW1lKEVtYmVkZGluZ3MocmVmZXJlbmNlX2ludGVncmF0ZWQsICJ1bWFwIikpCnJlZl9kZiRkYXRhc2V0IDwtICJSZWZlcmVuY2UiCgojIFF1ZXJ5IChNYWxpZ25hbnRDRDRUKSBjb29yZGluYXRlcwpxdWVyeV9kZiA8LSBkYXRhLmZyYW1lKEVtYmVkZGluZ3MobWFwcGVkX01hbGlnbmFudENENFQsICJyZWYudW1hcCIpKQpxdWVyeV9kZiRkYXRhc2V0IDwtICJNYWxpZ25hbnRDRDRUIgoKIyBNYWtlIHN1cmUgYW5ub3RhdGlvbnMgZXhpc3QgaW4gbWFwcGVkX01hbGlnbmFudENENFQKcXVlcnlfZGYkY2VsbHR5cGUgPC0gbWFwcGVkX01hbGlnbmFudENENFQkUHJlZGljdGlvbiAgIyBvciAiUHJlZGljdGlvbiIKCmxpYnJhcnkoUkNvbG9yQnJld2VyKQoKIyBHZXQgYSBwYWxldHRlIHdpdGggdXAgdG8gMjAgY29sb3JzCmJpZ19wYWxldHRlIDwtIGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCgxMiwgIlBhaXJlZCIpKSgyMCkKCmdncGxvdCgpICsKICBnZW9tX3BvaW50KGRhdGEgPSByZWZfZGYsIGFlcyh4ID0gdW1hcF8xLCB5ID0gdW1hcF8yKSwKICAgICAgICAgICAgIGNvbG9yID0gImdyZXk4MCIsIHNpemUgPSAwLjUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBxdWVyeV9kZiwgYWVzKHggPSByZWZVTUFQXzEsIHkgPSByZWZVTUFQXzIsIGNvbG9yID0gY2VsbHR5cGUpLAogICAgICAgICAgICAgc2l6ZSA9IDEpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYmlnX3BhbGV0dGUpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGdndGl0bGUoIk1hbGlnbmFudENENFQgY2VsbHMgcHJvamVjdGVkIG9udG8gcmVmZXJlbmNlIFVNQVAgd2l0aCBhbm5vdGF0aW9ucyIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKCgpgYGAKCiMgNS4gU3Vic2V0IE1hbGlnbmFudENENFQgUHJvamVjdGlvbgpgYGB7ciBzYXZlZmluYWx9CgojIDEuIERlZmluZSBvdXRwdXQgZGlyZWN0b3J5Cm91dF9kaXIgPC0gInJlc3VsdHMvTWFsaWduYW50Q0Q0VF9wcm9qZWN0aW9uIgppZighZGlyLmV4aXN0cyhvdXRfZGlyKSkgZGlyLmNyZWF0ZShvdXRfZGlyLCByZWN1cnNpdmUgPSBUUlVFKQoKc2F2ZShtYXBwZWRfTWFsaWduYW50Q0Q0VCwgZmlsZSA9IGZpbGUucGF0aChvdXRfZGlyLCAiTWFsaWduYW50Q0Q0VF9tYXBwZWRfb25fcmVmZXJlbmNlX3dpdGhfcHNldWRvdGltZS0zLTgtMjAyNS5Sb2JqIikpCgoKYGBgCgoK