1 Load libraries

2 Load Annotated Healthy Object

healthy_cd4 <- readRDS("../healthy_CD4_Subsetted_full_annotated_harmony.rds")

# Confirm cell counts and labels
cat("Healthy CD4 cells:", ncol(healthy_cd4), "\n")
Healthy CD4 cells: 12034 
print(table(healthy_cd4$predicted.celltype.l2, healthy_cd4$dataset))
                   
                    CD4T_10x_S1 CD4T_10x_S2 CD4T_lab
  CD4 CTL                     1           0       11
  CD4 Naive                1367         381      359
  CD4 Proliferating           9           4        0
  CD4 TCM                  2010        2856     4654
  CD4 TEM                    29          51       73
  Treg                       87         137        5
print(table(healthy_cd4$predicted.celltype.l3, healthy_cd4$dataset))
                   
                    CD4T_10x_S1 CD4T_10x_S2 CD4T_lab
  CD4 CTL                     1           0       11
  CD4 Naive                1370         382      363
  CD4 Proliferating           9           4        0
  CD4 TCM_1                1518        1859     4181
  CD4 TCM_2                 113         148      248
  CD4 TCM_3                 370         849      226
  CD4 TEM_1                  12          26        8
  CD4 TEM_2                  19          11       13
  CD4 TEM_3                   2           7       49
  Treg Memory                58         134        3
  Treg Naive                 31           9        0

3 Cell Cycle Scoring


DefaultAssay(healthy_cd4) <- "RNA"
healthy_cd4 <- NormalizeData(healthy_cd4, verbose = FALSE)

healthy_cd4 <- CellCycleScoring(
  healthy_cd4,
  s.features   = cc.genes.updated.2019$s.genes,
  g2m.features = cc.genes.updated.2019$g2m.genes,
  set.ident    = FALSE
)

print(table(healthy_cd4$Phase, healthy_cd4$dataset))
     
      CD4T_10x_S1 CD4T_10x_S2 CD4T_lab
  G1         1781        2021     1938
  G2M         242         263      491
  S          1480        1145     2673
DimPlot(healthy_cd4, group.by = "Phase") + ggtitle("Cell Cycle Phase")

4 SCTransform per Sample (with Cell Cycle + MT Regression)

5 Validation plots: dataset mixing and initial labels

# Validation plots
p1 <- DimPlot(reference_integrated, group.by = "predicted.celltype.l2",
              label = TRUE, repel = TRUE, label.size = 3) + NoLegend()
p2 <- DimPlot(reference_integrated, group.by = "dataset")
p3 <- DimPlot(reference_integrated, group.by = "seurat_clusters", label = TRUE)
(p1 | p2) / p3

5.1 Validation plots

# Validation plots
DimPlot(reference_integrated, group.by = "predicted.celltype.l1",
              label = TRUE, repel = TRUE, label.size = 3) + NoLegend()

DimPlot(reference_integrated, group.by = "predicted.celltype.l2",
              label = TRUE, repel = TRUE, label.size = 3) + NoLegend()

DimPlot(reference_integrated, group.by = "predicted.celltype.l3",
              label = TRUE, repel = TRUE, label.size = 3) + NoLegend()


print(table(healthy_cd4$predicted.celltype.l1, healthy_cd4$seurat_clusters))
       
           0    1    2    3    4    5    6    7    8    9   10   11   12   13   14   15   16   17   18   19   20
  CD4 T 5035 2758 2713    0   98   10  185  725   33    4   97  368    0    0    0    0    0    2    0    0    0
  CD8 T    1    0    0    0    0    0    3    1    0    0    0    1    0    0    0    0    0    0    0    0    0
print(table(healthy_cd4$predicted.celltype.l2, healthy_cd4$seurat_clusters))
                   
                       0    1    2    3    4    5    6    7    8    9   10   11   12   13   14   15   16   17   18   19   20
  CD4 CTL              0    0    0    0    0    0    5    0    1    3    3    0    0    0    0    0    0    0    0    0    0
  CD4 Naive            1 1116  911    0   15    0    0   51    0    0    0   13    0    0    0    0    0    0    0    0    0
  CD4 Proliferating   13    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0
  CD4 TCM           4836 1599 1762    0   83   10  130  666   29    1   61  341    0    0    0    0    0    2    0    0    0
  CD4 TEM             63    0    0    0    0    0   53    2    1    0   33    1    0    0    0    0    0    0    0    0    0
  Treg               123   43   40    0    0    0    0    7    2    0    0   14    0    0    0    0    0    0    0    0    0
print(table(healthy_cd4$predicted.celltype.l3, healthy_cd4$seurat_clusters))
                   
                       0    1    2    3    4    5    6    7    8    9   10   11   12   13   14   15   16   17   18   19   20
  CD4 CTL              0    0    0    0    0    0    5    0    1    3    3    0    0    0    0    0    0    0    0    0    0
  CD4 Naive            4 1116  916    0   15    0    0   51    0    0    0   13    0    0    0    0    0    0    0    0    0
  CD4 Proliferating   13    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0
  CD4 TCM_1         3076 1599 1758    0   83    9   80  627   24    1    9  292    0    0    0    0    0    0    0    0    0
  CD4 TCM_2          443    3    1    0    0    1   27   13    4    0    0   17    0    0    0    0    0    0    0    0    0
  CD4 TCM_3         1309    0    0    0    0    0   22   25    1    0   58   28    0    0    0    0    0    2    0    0    0
  CD4 TEM_1           18    0    0    0    0    0   11    0    1    0   16    0    0    0    0    0    0    0    0    0    0
  CD4 TEM_2           13    0    0    0    0    0   26    2    0    0    0    2    0    0    0    0    0    0    0    0    0
  CD4 TEM_3           30    0    0    0    0    0   17    0    0    0   11    0    0    0    0    0    0    0    0    0    0
  Treg Memory        128   20   21    0    0    0    0    7    2    0    0   17    0    0    0    0    0    0    0    0    0
  Treg Naive           2   20   17    0    0    0    0    1    0    0    0    0    0    0    0    0    0    0    0    0    0

6 Save Reference (before MapQuery)

# Save
saveRDS(reference_integrated, "CD4_reference_RPCA_SCT_integrated.rds")
cat("✅ COMPLETE:", ncol(reference_integrated), "cells integrated\n")
✅ COMPLETE: 12034 cells integrated

7 Marker Module Scores (Differentiation States)


DefaultAssay(reference_integrated) <- "RNA"


marker_list <- list(
  Tnaive = c("CCR7","SELL","LEF1","TCF7","IL7R","CD27","PTPRC"),
  Tcm    = c("CCR7","SELL","CD27","IL7R","BCL2","TCF7"),
  Tem    = c("CCR6","CXCR3","GZMK","PRF1","IFNG"),
  Temra  = c("GZMB","PRF1","KLRG1","CX3CR1"),
  Treg   = c("FOXP3","IL2RA","CTLA4","IKZF2"),
  Tex    = c("PDCD1","CTLA4","LAG3","TIGIT","TOX","ENTPD1"),
  CD4CTL = c("GZMB","PRF1","NKG7","KLRG1","CX3CR1")
)

# Keep only genes present
marker_list <- lapply(marker_list, function(x)
  intersect(x, rownames(reference_integrated))
)

# Drop any empty sets to avoid AddModuleScore warnings
marker_list <- marker_list[vapply(marker_list, length, 1L) > 0]

for (state in names(marker_list)) {
  reference_integrated <- AddModuleScore(
    reference_integrated,
    features = list(marker_list[[state]]),
    name     = state
  )
}

score_features <- paste0(names(marker_list), "1")

FeaturePlot(reference_integrated,
            features   = score_features,
            ncol       = 4,
            cols       = c("lightblue","red"),
            max.cutoff = "q95") +
  plot_annotation(title = "Differentiation State Module Scores")

7.1 FeaturePlots Markers based

# ---- Load libraries ----
library(Seurat)
library(ggplot2)
library(patchwork)

# ---- Define markers for differentiation states ----
tnaive_markers <- c("CCR7", "SELL", "LEF1", "TCF7", "IL7R", "CD27", "CD45RA")
tcm_markers    <- c("CCR7", "SELL", "CD45RO", "IL7R", "CD27")
tem_markers    <- c("CCR6", "CXCR3", "GZMK", "PRF1", "IFNG", "CD45RO")
temra_markers  <- c("GZMB", "PRF1", "KLRG1", "CX3CR1", "CD45RA")
tex_markers    <- c("PDCD1", "CTLA4", "LAG3", "TIGIT", "TOX", "ENTPD1")
cd4ctl_markers <- c("GZMB", "PRF1", "NKG7", "KLRG1", "CX3CR1")  # CD4 cytotoxic markers

# ---- Keep only markers present in the dataset ----
tnaive_markers <- tnaive_markers[tnaive_markers %in% rownames(reference_integrated)]
tcm_markers    <- tcm_markers[tcm_markers %in% rownames(reference_integrated)]
tem_markers    <- tem_markers[tem_markers %in% rownames(reference_integrated)]
temra_markers  <- temra_markers[temra_markers %in% rownames(reference_integrated)]
tex_markers    <- tex_markers[tex_markers %in% rownames(reference_integrated)]
cd4ctl_markers <- cd4ctl_markers[cd4ctl_markers %in% rownames(reference_integrated)]

# ---- Function to generate patchwork feature plots ----
plot_markers_grid <- function(marker_vector, state_name) {
  plots <- lapply(marker_vector, function(gene){
    FeaturePlot(reference_integrated, features = gene, reduction = "umap",
                cols = c("lightblue", "red"), label = TRUE) +
      theme(plot.title = element_text(hjust = 0.5))
  })
  wrap_plots(plots) + plot_annotation(title = paste(state_name, "Marker Expression"))
}

# ---- Generate grids for each state ----
tnaive_plot <- plot_markers_grid(tnaive_markers, "Tnaive")
tcm_plot    <- plot_markers_grid(tcm_markers, "Tcm")
tem_plot    <- plot_markers_grid(tem_markers, "Tem")
temra_plot  <- plot_markers_grid(temra_markers, "Temra")
tex_plot    <- plot_markers_grid(tex_markers, "Tex")
cd4ctl_plot <- plot_markers_grid(cd4ctl_markers, "CD4 CTL")

# ---- Display plots ----
tnaive_plot

tcm_plot

tem_plot

temra_plot

tex_plot

cd4ctl_plot

8 ADT FeaturePlots per differentiation state

# Tnaive: CD45RA+ CCR7+ CD127+ (naive/memory core)
tnaive_adt <- c("CD45RA-TotalC", "CD197-TotalC", "CD127-TotalC")

# Tcm: CD45RO+ CCR7+ CD127+ (central memory)
tcm_adt <- c("CD45RO-TotalC", "CD197-TotalC", "CD127-TotalC")

# Tem: CD45RO+ CCR7− (effector memory)
tem_adt <- c("CD45RO-TotalC")  # CCR7 low expected

# Temra/CD4CTL: CD45RA+ + exhaustion/effector (PD-1, TIGIT, HLA-DR)
temra_adt <- c("CD45RA-TotalC", "PD-1-TotalC", "TIGIT-TotalC", "HLA-DR-TotalC")

# Treg: CD25hi CD127low ±CD45RA (naive Treg vs activated)
treg_adt <- c("CD25-TotalC", "CD127-TotalC", "CD45RA-TotalC")

# Tex: exhaustion signature
tex_adt <- c("PD-1-TotalC", "TIGIT-TotalC", "HLA-DR-TotalC")


DefaultAssay(reference_integrated) <- "ADT"

plot_markers_grid_ADT <- function(marker_vector, state_name) {
  plots <- lapply(marker_vector, function(prot){
    FeaturePlot(reference_integrated, features = prot, reduction = "umap",
                cols = c("lightblue","red")) +
      ggtitle(prot)
  })
  wrap_plots(plots) + plot_annotation(title = paste(state_name, "ADT expression"))
}

plot_markers_grid_ADT(tnaive_adt, "Tnaive")

plot_markers_grid_ADT(tcm_adt,    "Tcm")

plot_markers_grid_ADT(tem_adt,    "Tem")

plot_markers_grid_ADT(temra_adt,  "Temra/CD4CTL")

plot_markers_grid_ADT(treg_adt,   "Treg")

plot_markers_grid_ADT(tex_adt,    "Tex")

NA
NA

8.1 Gating in 10x_S1 (uses *-TotalC)

## 10x_S1 ADT gating  (CITE-seq)
DefaultAssay(reference_integrated) <- "ADT"

s1 <- subset(reference_integrated, subset = dataset == "CD4T_10x_S1")
adt_s1 <- LayerData(s1[["ADT"]], layer = "data.CD4T_10x_S1.1")
rownames(adt_s1) <- gsub("-TotalC", "", rownames(adt_s1))  # CD45RA, CD197, ...

adt_z_s1 <- t(scale(t(adt_s1)))

is_hi <- function(g, zmat, z = 0.5) if (g %in% rownames(zmat)) zmat[g, ] > z else rep(FALSE, ncol(zmat))

CD45RA_hi <- is_hi("CD45RA", adt_z_s1)
CD45RO_hi <- is_hi("CD45RO", adt_z_s1)
CCR7_hi   <- is_hi("CD197",  adt_z_s1)
CD127_hi  <- is_hi("CD127",  adt_z_s1)
CD25_hi   <- is_hi("CD25",   adt_z_s1)
PD1_hi    <- is_hi("PD-1",   adt_z_s1)
TIGIT_hi  <- is_hi("TIGIT",  adt_z_s1)
HLADR_hi  <- is_hi("HLA-DR", adt_z_s1)

CCR7_lo  <- !CCR7_hi
CD127_lo <- !CD127_hi

state_s1 <- rep("Other", ncol(adt_s1))

# Treg
treg_idx <- CD25_hi & CD127_lo
state_s1[treg_idx] <- "Treg_ADT"

# Tnaive
tnaive_idx <- CD45RA_hi & CCR7_hi & CD127_hi & !CD45RO_hi & !PD1_hi & !TIGIT_hi
state_s1[tnaive_idx & state_s1 == "Other"] <- "Tnaive_ADT"

# Tcm
tcm_idx <- CD45RO_hi & CCR7_hi & !CD45RA_hi
state_s1[tcm_idx & state_s1 == "Other"] <- "Tcm_ADT"

# Tem
tem_idx <- CD45RO_hi & CCR7_lo & !CD45RA_hi
state_s1[tem_idx & state_s1 == "Other"] <- "Tem_ADT"

# Temra / CD4CTL
temra_idx <- CD45RA_hi & CCR7_lo & (PD1_hi | TIGIT_hi | HLADR_hi)
state_s1[temra_idx & state_s1 == "Other"] <- "Temra_CTL_ADT"

table(state_s1)
state_s1
        Other       Tcm_ADT       Tem_ADT Temra_CTL_ADT    Tnaive_ADT      Treg_ADT 
         1763            99           694           243           100           604 

8.2 Recover ADT for CD4T_lab from original object and align cells


# Match cells
lab_cells <- colnames(subset(reference_integrated, dataset == "CD4T_lab"))
lab_raw   <- sub("^PBMC_", "", lab_cells)

adt_lab_raw <- adt_lab_raw[, lab_raw, drop = FALSE]
Error in adt_lab_raw[, lab_raw, drop = FALSE] : subscript out of bounds

8.3 Extract ONLY overlapping cells


# Create new assay for CD4T_lab ADT data
reference_integrated[["ADT_lab"]] <- CreateAssay5Object(counts = adt_lab_raw)

# Verify it was added
lab <- subset(reference_integrated, subset = dataset == "CD4T_lab")
dim(LayerData(lab[["ADT_lab"]], layer = "counts"))
head(rownames(LayerData(lab[["ADT_lab"]], layer = "counts")))

8.4 Create and add ADT_lab assay


# Create new assay for CD4T_lab ADT data
reference_integrated[["ADT_lab"]] <- CreateAssay5Object(counts = adt_lab_raw)
Error in `fn()`:
! Cannot add new cells with [[<-
Run `]8;;x-r-run:rlang::last_trace()rlang::last_trace()]8;;` to see where the error occurred.

8.5 Now gate on CD4T_lab cells (works!)


# Create new assay for CD4T_lab ADT data
reference_integrated[["ADT_lab"]] <- CreateAssay5Object(counts = adt_lab_raw)

# Verify it was added
lab <- subset(reference_integrated, subset = dataset == "CD4T_lab")
dim(LayerData(lab[["ADT_lab"]], layer = "counts"))
head(rownames(LayerData(lab[["ADT_lab"]], layer = "counts")))

8.6 Gating in CD4T_lab (uses markers without -TotalC)


DefaultAssay(reference_integrated) <- "ADT"

## CD4T_lab ADT gating  (lab panel)

# Subset lab dataset
lab <- subset(reference_integrated, subset = dataset == "CD4T_lab")

# Get ADT expression (RNA-like markers without -TotalC)
adt_lab <- LayerData(lab[["ADT"]], layer = "data")   # not slot=
# Check rownames:
head(rownames(adt_lab))
NULL
# Z-score
adt_z_lab <- t(scale(t(adt_lab)))

is_hi <- function(g, zmat, z = 0.5) {
  if (!g %in% rownames(zmat)) return(rep(FALSE, ncol(zmat)))
  zmat[g, ] > z
}

CD45RA_hi_l <- is_hi("CD45RA", adt_z_lab)
CD45RO_hi_l <- is_hi("CD45RO", adt_z_lab)
CCR7_hi_l   <- is_hi("CCR7",   adt_z_lab)
CD127_hi_l  <- is_hi("CD127",  adt_z_lab)
CD25_hi_l   <- is_hi("CD25",   adt_z_lab)
PD1_hi_l    <- is_hi("PD1",    adt_z_lab)
TIGIT_hi_l  <- is_hi("TIGIT",  adt_z_lab)
HLADR_hi_l  <- is_hi("HLA-DR", adt_z_lab)  # if present

CCR7_lo_l  <- !CCR7_hi_l
CD127_lo_l <- !CD127_hi_l

state_lab <- rep("Other", ncol(adt_lab))

# Treg
treg_idx_l <- CD25_hi_l & CD127_lo_l
state_lab[treg_idx_l] <- "Treg_ADT"

# Tnaive
tnaive_idx_l <- CD45RA_hi_l & CCR7_hi_l & CD127_hi_l & !CD45RO_hi_l & !PD1_hi_l & !TIGIT_hi_l
state_lab[tnaive_idx_l & state_lab == "Other"] <- "Tnaive_ADT"

# Tcm
tcm_idx_l <- CD45RO_hi_l & CCR7_hi_l & !CD45RA_hi_l
state_lab[tcm_idx_l & state_lab == "Other"] <- "Tcm_ADT"

# Tem
tem_idx_l <- CD45RO_hi_l & CCR7_lo_l & !CD45RA_hi_l
state_lab[tem_idx_l & state_lab == "Other"] <- "Tem_ADT"

# Temra/CD4CTL
temra_idx_l <- CD45RA_hi_l & CCR7_lo_l & (PD1_hi_l | TIGIT_hi_l | HLADR_hi_l)
state_lab[temra_idx_l & state_lab == "Other"] <- "Temra_CTL_ADT"

table(state_lab)
< table of extent 0 >

8.7 Assign per‑cell differentiation state

# Collect module score column names (they end with "1")
state_names <- names(marker_list)              # e.g. "Tnaive","Tcm",...
score_cols  <- paste0(state_names, "1")        # "Tnaive1","Tcm1",...

# Build matrix of scores
score_mat <- as.data.frame(reference_integrated@meta.data[, score_cols])

# For each cell, find which state has the highest score
state_max_idx   <- apply(score_mat, 1, which.max)
state_max_label <- state_names[state_max_idx]

# Optionally impose a minimum separation: if top score is not sufficiently
# higher than the second, call the cell "Mixed"
top_vals  <- apply(score_mat, 1, max)
second_vals <- apply(score_mat, 1, function(x) sort(x, decreasing = TRUE)[2])
delta <- top_vals - second_vals
state_max_label[delta < 0.05] <- "Mixed"   # 0.05 is an example threshold

# Store in metadata
reference_integrated$diff_state <- factor(state_max_label,
                                          levels = c("Tnaive","Tcm","Tem","Temra",
                                                     "Treg","Tex","CD4CTL","Mixed"))

# UMAP colored by inferred differentiation state
DimPlot(reference_integrated, group.by = "diff_state", label = TRUE, label.box = T, repel = T) +
  ggtitle("Inferred CD4 T-cell differentiation states")

9 ADT markers and extraction (10x_S1 already run)


# o you can do:
# 
# Tnaive: CD3+ CD4+ CD45RA+ CD45RO− CCR7+ CD127+
# 
# Tcm: CD3+ CD4+ CD45RO+ CCR7+ CD45RA−
# 
# Tem: CD3+ CD4+ CD45RO+ CCR7− (or low) CD45RA−
# 
# Temra: CD3+ CD4+ CD45RA+ CD45RO+/− CCR7−



DefaultAssay(reference_integrated) <- "ADT"

adt_markers_raw <- c("CD3-TotalC","CD4-TotalC","CD45RA-TotalC",
                     "CD45RO-TotalC","CD197-TotalC","CD127-TotalC",
                     "CD25-TotalC","HLA-DR-TotalC","PD1-TotalC","TIGIT-TotalC")

FeaturePlot(reference_integrated,
            features = adt_markers_raw,
            reduction = "umap",
            cols = c("lightblue","red"),
            ncol = 3) +
  plot_annotation(title = "Key ADT markers (10x_S1 cells)")

10 Derive ADT‑based “high/low” categories

# Full UMAP, 10x_S1 colored, others grey
p1 <- DimPlot(reference_integrated,
              group.by = "ADT_state2",
              reduction = "umap",
              pt.size   = 0.5) +
  scale_color_manual(values = c("Tnaive_ADT" = "#FF6B6B", "Tcm_ADT" = "#4ECDC4",
                                "Tem_ADT" = "#45B7D1", "Temra_CTL_ADT" = "#96CEB4",
                                "Treg_ADT" = "#FECA57", "Other" = "grey80")) +
  ggtitle("Full UMAP: 10x_S1 colored by ADT, others grey")

p2 <- DimPlot(subset(reference_integrated, dataset == "CD4T_10x_S1"),
              group.by = "ADT_state2",
              reduction = "umap",
              label = TRUE, label.box = TRUE, repel = TRUE) +
  ggtitle("10x_S1 ONLY") +
  NoLegend()

p1 | p2

10.1 Logical gating for Tnaive/Tcm/Tem/Temra

# Boolean vectors per marker
CD45RA_hi <- is_high("CD45RA", adt_z)
CD45RO_hi <- is_high("CD45RO", adt_z)
CCR7_hi   <- is_high("CD197",  adt_z)   # CCR7
CD127_hi  <- is_high("CD127",  adt_z)

# Gating rules
Tnaive_idx <-  CD45RA_hi &  CCR7_hi & CD127_hi & !CD45RO_hi
Tcm_idx    <- !CD45RA_hi &  CCR7_hi &  CD45RO_hi
Tem_idx    <- !CD45RA_hi & !CCR7_hi &  CD45RO_hi
Temra_idx  <-  CD45RA_hi & !CCR7_hi & (CD45RO_hi | !CD45RO_hi)  # RA+ CCR7−

# Assign state; resolve conflicts by priority
state <- rep("Other", ncol(adt))
state[Tnaive_idx] <- "Tnaive"
state[Tcm_idx]    <- "Tcm"
state[Tem_idx]    <- "Tem"
state[Temra_idx]  <- "Temra"

# Store in metadata (10x_S1 subset)
s1_subset$ADT_state <- state

# Put back into full object
reference_integrated$ADT_state <- NA
reference_integrated$ADT_state[colnames(s1_subset)] <- s1_subset$ADT_state
reference_integrated$ADT_state <- factor(reference_integrated$ADT_state,
                                         levels = c("Tnaive","Tcm","Tem","Temra","Other"))

11 Visualize ADT‑defined states on your integrated UMAP

DefaultAssay(reference_integrated) <- "integrated"

DimPlot(reference_integrated,
        group.by = "ADT_state",
        reduction = "umap",
        label = TRUE, label.box = T, repel = T) +
  ggtitle("CD4T_10x_S1 cells annotated by ADT gating")

12 Monocle3 Trajectory

cds <- as.cell_data_set(reference_integrated)

# Transfer UMAP + partitions from Seurat
reducedDim(cds, "UMAP") <- Embeddings(reference_integrated, "umap")
cds@clusters$UMAP$partitions <- factor(rep(1, ncol(cds)))
cds@clusters$UMAP$clusters   <- reference_integrated$seurat_clusters
colData(cds)$celltype         <- reference_integrated$predicted.celltype.l2
colData(cds)$dataset          <- reference_integrated$dataset
cds <- learn_graph(cds,
                   use_partition = FALSE,
                   close_loop    = FALSE,
                   verbose       = FALSE)

plot_cells(cds,
           color_cells_by          = "celltype",
           label_groups_by_cluster = FALSE,
           label_leaves            = TRUE,
           label_branch_points     = TRUE,
           graph_label_size        = 4) +
  ggtitle("Monocle3 — CD4 T-cell Trajectory Milestones")
# Root = CD4 Naive centroid
naive_ids <- rownames(colData(cds))[
  colData(cds)$celltype %in% c("CD4 Naive")
]

get_root_node <- function(cds, cell_ids) {
  closest <- cds@principal_graph_aux$UMAP$pr_graph_cell_proj_closest_vertex
  closest <- as.matrix(closest[colnames(cds), ])
  igraph::V(principal_graph(cds)$UMAP)$name[
    as.numeric(names(which.max(table(closest[cell_ids, ]))))]
}

cds <- order_cells(cds, root_pr_nodes = get_root_node(cds, naive_ids))
reference_integrated$monocle3_pseudotime <- pseudotime(cds)

plot_cells(cds,
           color_cells_by    = "pseudotime",
           label_cell_groups = FALSE) +
  scale_color_viridis_c(option = "plasma") +
  ggtitle("Pseudotime: Naive → Memory → Effector → Treg")

13 Save Reference (before MapQuery)

saveRDS(reference_integrated,
        "CD4_reference_RPCA_SCT_Trajectory_annotated.rds")

cat("Reference saved:", ncol(reference_integrated), "cells\n")

```

LS0tCnRpdGxlOiAiQ0Q0IFQtY2VsbCBSZWZlcmVuY2UgKyBTZXphcnkgUHJvamVjdGlvbiIKc3VidGl0bGU6ICJSUENBLVNDVCBJbnRlZ3JhdGlvbiB8IE1vbm9jbGUzIHwgTWFwUXVlcnkiCmF1dGhvcjogTmFzaXIgTWFobW9vZCBBYmJhc2kKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogdHJ1ZQogICAgdGhlbWU6IGpvdXJuYWwKLS0tCgoKIyBMb2FkIGxpYnJhcmllcwpgYGB7ciwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gOCkKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkobW9ub2NsZTMpCmxpYnJhcnkoU2V1cmF0V3JhcHBlcnMpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpvcHRpb25zKGZ1dHVyZS5nbG9iYWxzLm1heFNpemUgPSA4ZTkpCnNldC5zZWVkKDEyMykKYGBgCgoKCgojIExvYWQgQW5ub3RhdGVkIEhlYWx0aHkgT2JqZWN0CmBgYHtyIGxvYWQgb2JqZWN0fQpoZWFsdGh5X2NkNCA8LSByZWFkUkRTKCIuLi9oZWFsdGh5X0NENF9TdWJzZXR0ZWRfZnVsbF9hbm5vdGF0ZWRfaGFybW9ueS5yZHMiKQoKIyBDb25maXJtIGNlbGwgY291bnRzIGFuZCBsYWJlbHMKY2F0KCJIZWFsdGh5IENENCBjZWxsczoiLCBuY29sKGhlYWx0aHlfY2Q0KSwgIlxuIikKcHJpbnQodGFibGUoaGVhbHRoeV9jZDQkcHJlZGljdGVkLmNlbGx0eXBlLmwyLCBoZWFsdGh5X2NkNCRkYXRhc2V0KSkKcHJpbnQodGFibGUoaGVhbHRoeV9jZDQkcHJlZGljdGVkLmNlbGx0eXBlLmwzLCBoZWFsdGh5X2NkNCRkYXRhc2V0KSkKCmBgYAoKCgoKIyBDZWxsIEN5Y2xlIFNjb3JpbmcKYGBge3IgY2VsbGN5Y2xlfQoKRGVmYXVsdEFzc2F5KGhlYWx0aHlfY2Q0KSA8LSAiUk5BIgpoZWFsdGh5X2NkNCA8LSBOb3JtYWxpemVEYXRhKGhlYWx0aHlfY2Q0LCB2ZXJib3NlID0gRkFMU0UpCgpoZWFsdGh5X2NkNCA8LSBDZWxsQ3ljbGVTY29yaW5nKAogIGhlYWx0aHlfY2Q0LAogIHMuZmVhdHVyZXMgICA9IGNjLmdlbmVzLnVwZGF0ZWQuMjAxOSRzLmdlbmVzLAogIGcybS5mZWF0dXJlcyA9IGNjLmdlbmVzLnVwZGF0ZWQuMjAxOSRnMm0uZ2VuZXMsCiAgc2V0LmlkZW50ICAgID0gRkFMU0UKKQoKcHJpbnQodGFibGUoaGVhbHRoeV9jZDQkUGhhc2UsIGhlYWx0aHlfY2Q0JGRhdGFzZXQpKQpEaW1QbG90KGhlYWx0aHlfY2Q0LCBncm91cC5ieSA9ICJQaGFzZSIpICsgZ2d0aXRsZSgiQ2VsbCBDeWNsZSBQaGFzZSIpCmBgYAoKIyBTQ1RyYW5zZm9ybSBwZXIgU2FtcGxlICh3aXRoIENlbGwgQ3ljbGUgKyBNVCBSZWdyZXNzaW9uKQpgYGB7ciBTQ1QrUlBDQX0KIyDilIDilIAgMC4gU3BsaXQgKyBTQ1Qg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACnJlZl9saXN0IDwtIFNwbGl0T2JqZWN0KGhlYWx0aHlfY2Q0LCBzcGxpdC5ieSA9ICJkYXRhc2V0IikKCnJlZl9saXN0IDwtIGxhcHBseShyZWZfbGlzdCwgZnVuY3Rpb24oeCkgewogIFNDVHJhbnNmb3JtKAogICAgeCwKICAgIHZhcnMudG8ucmVncmVzcyA9IGMoIlMuU2NvcmUiLCAiRzJNLlNjb3JlIiwgInBlcmNlbnQubXQiKSwKICAgIHZzdC5mbGF2b3IgPSAidjIiLAogICAgdmVyYm9zZSA9IEZBTFNFCiAgKQp9KQpjYXQoIlNDVCBjb21wbGV0ZSBwZXIgc2FtcGxlXG4iKQpwcmludChzYXBwbHkocmVmX2xpc3QsIG5jb2wpKQoKIyDilIDilIAgU2VsZWN0IGludGVncmF0aW9uIGZlYXR1cmVzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApyZWZfZmVhdHVyZXMgPC0gU2VsZWN0SW50ZWdyYXRpb25GZWF0dXJlcyhvYmplY3QubGlzdCA9IHJlZl9saXN0LCBuZmVhdHVyZXMgPSAzMDAwKQpyZWZfZmVhdHVyZXMgPC0gcmVmX2ZlYXR1cmVzWyFncmVwbCgiXlRSQlZ8XlRSQVZ8XlRSR1Z8XlRSRFZ8XkhMQS18XlhJU1QiLCByZWZfZmVhdHVyZXMpXQpjYXQoIkZlYXR1cmVzIGFmdGVyIFRDUi9ITEEgZmlsdGVyOiIsIGxlbmd0aChyZWZfZmVhdHVyZXMpLCAiXG4iKQoKIyDilIDilIAgUHJlcFNDVEludGVncmF0aW9uIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApyZWZfbGlzdCA8LSBQcmVwU0NUSW50ZWdyYXRpb24oCiAgb2JqZWN0Lmxpc3QgICAgID0gcmVmX2xpc3QsCiAgYW5jaG9yLmZlYXR1cmVzID0gcmVmX2ZlYXR1cmVzLAogIHZlcmJvc2UgICAgICAgICA9IEZBTFNFCikKY2F0KCJQcmVwU0NUSW50ZWdyYXRpb24gZG9uZVxuIikKCiMg4pSA4pSAIFNLSVAgU1lOQ0hST05JWkFUSU9OIC0gRElSRUNUIFRPIFBDQSAmIFJQQ0Eg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACmNhdCgiUnVubmluZyBQQ0Eg4oaSIFJQQ0EgaW50ZWdyYXRpb24gKG5vIG1hbnVhbCBzeW5jIG5lZWRlZCkuLi5cbiIpCgojIFBDQSBwZXIgc2FtcGxlIChSUENBIHVzZXMgdGhlc2UgUENzKQpyZWZfbGlzdCA8LSBsYXBwbHkocmVmX2xpc3QsIGZ1bmN0aW9uKHgpIHsKICBSdW5QQ0EoeCwgYXNzYXkgPSAiU0NUIiwgZmVhdHVyZXMgPSByZWZfZmVhdHVyZXMsIHZlcmJvc2UgPSBGQUxTRSkKfSkKY2F0KCLinIUgUENBIGNvbXBsZXRlXG4iKQoKIyBGaW5kIGFuY2hvcnMgKFJQQ0EgaGFuZGxlcyBsYXllciBtaXNtYXRjaGVzIGF1dG9tYXRpY2FsbHkpCnJlZl9hbmNob3JzIDwtIEZpbmRJbnRlZ3JhdGlvbkFuY2hvcnMoCiAgb2JqZWN0Lmxpc3QgICAgICAgICAgPSByZWZfbGlzdCwKICBub3JtYWxpemF0aW9uLm1ldGhvZCA9ICJTQ1QiLAogIGFuY2hvci5mZWF0dXJlcyAgICAgID0gcmVmX2ZlYXR1cmVzLAogIHJlZHVjdGlvbiAgICAgICAgICAgID0gInJwY2EiLAogIGRpbXMgICAgICAgICAgICAgICAgID0gMTozMCwKICBrLmFuY2hvciAgICAgICAgICAgICA9IDE1LAogIHZlcmJvc2UgICAgICAgICAgICAgID0gVFJVRQopCmNhdCgi4pyFIEFuY2hvcnMgZm91bmRcbiIpCgoKIyDilIDilIAgSW50ZWdyYXRlIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApyZWZlcmVuY2VfaW50ZWdyYXRlZCA8LSBJbnRlZ3JhdGVEYXRhKAogIGFuY2hvcnNldCAgICAgICAgICAgID0gcmVmX2FuY2hvcnMsCiAgbm9ybWFsaXphdGlvbi5tZXRob2QgPSAiU0NUIiwKICB2ZXJib3NlICAgICAgICAgICAgICA9IFRSVUUKKQpjYXQoIuKchSBJbnRlZ3JhdGVEYXRhIGNvbXBsZXRlOiIsIG5jb2wocmVmZXJlbmNlX2ludGVncmF0ZWQpLCAiY2VsbHNcbiIpCgojIOKUgOKUgCBTdGFuZGFyZGl6ZSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKVmFyaWFibGVGZWF0dXJlcyhyZWZlcmVuY2VfaW50ZWdyYXRlZCkgPC0gcmVmX2ZlYXR1cmVzCkRlZmF1bHRBc3NheShyZWZlcmVuY2VfaW50ZWdyYXRlZCkgPC0gImludGVncmF0ZWQiCgojIOKUgOKUgCBTY2FsZSArIFBDQSArIFVNQVAg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACnJlZmVyZW5jZV9pbnRlZ3JhdGVkIDwtIFNjYWxlRGF0YShyZWZlcmVuY2VfaW50ZWdyYXRlZCwgdmVyYm9zZSA9IEZBTFNFKQpyZWZlcmVuY2VfaW50ZWdyYXRlZCA8LSBSdW5QQ0EocmVmZXJlbmNlX2ludGVncmF0ZWQsIG5wY3MgPSA1MCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybi5tb2RlbCA9IFRSVUUsIHZlcmJvc2UgPSBGQUxTRSkKRWxib3dQbG90KHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCBuZGltcyA9IDUwKQoKZGltc191c2UgPC0gMToyMAoKcmVmZXJlbmNlX2ludGVncmF0ZWQgPC0gUnVuVU1BUChyZWZlcmVuY2VfaW50ZWdyYXRlZCwgZGltcyA9IGRpbXNfdXNlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybi5tb2RlbCA9IFRSVUUsIHZlcmJvc2UgPSBGQUxTRSkKcmVmZXJlbmNlX2ludGVncmF0ZWQgPC0gRmluZE5laWdoYm9ycyhyZWZlcmVuY2VfaW50ZWdyYXRlZCwgZGltcyA9IGRpbXNfdXNlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2UgPSBGQUxTRSkKcmVmZXJlbmNlX2ludGVncmF0ZWQgPC0gRmluZENsdXN0ZXJzKHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCByZXNvbHV0aW9uID0gMC4zLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IEZBTFNFKQoKCmBgYAoKCiMgVmFsaWRhdGlvbiBwbG90czogZGF0YXNldCBtaXhpbmcgYW5kIGluaXRpYWwgbGFiZWxzCmBgYHtyIHZhbGlkYXRlLCBmaWcud2lkdGg9MTQsIGZpZy5oZWlnaHQ9MTB9CiMgVmFsaWRhdGlvbiBwbG90cwpwMSA8LSBEaW1QbG90KHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiLAogICAgICAgICAgICAgIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBsYWJlbC5zaXplID0gMykgKyBOb0xlZ2VuZCgpCnAyIDwtIERpbVBsb3QocmVmZXJlbmNlX2ludGVncmF0ZWQsIGdyb3VwLmJ5ID0gImRhdGFzZXQiKQpwMyA8LSBEaW1QbG90KHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCBncm91cC5ieSA9ICJzZXVyYXRfY2x1c3RlcnMiLCBsYWJlbCA9IFRSVUUpCihwMSB8IHAyKSAvIHAzCmBgYAoKIyMgVmFsaWRhdGlvbiBwbG90cwpgYGB7ciAsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD04fQojIFZhbGlkYXRpb24gcGxvdHMKRGltUGxvdChyZWZlcmVuY2VfaW50ZWdyYXRlZCwgZ3JvdXAuYnkgPSAicHJlZGljdGVkLmNlbGx0eXBlLmwxIiwKICAgICAgICAgICAgICBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgbGFiZWwuc2l6ZSA9IDMpICsgTm9MZWdlbmQoKQpEaW1QbG90KHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiLAogICAgICAgICAgICAgIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBsYWJlbC5zaXplID0gMykgKyBOb0xlZ2VuZCgpCkRpbVBsb3QocmVmZXJlbmNlX2ludGVncmF0ZWQsIGdyb3VwLmJ5ID0gInByZWRpY3RlZC5jZWxsdHlwZS5sMyIsCiAgICAgICAgICAgICAgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSAzKSArIE5vTGVnZW5kKCkKCnByaW50KHRhYmxlKGhlYWx0aHlfY2Q0JHByZWRpY3RlZC5jZWxsdHlwZS5sMSwgaGVhbHRoeV9jZDQkc2V1cmF0X2NsdXN0ZXJzKSkKcHJpbnQodGFibGUoaGVhbHRoeV9jZDQkcHJlZGljdGVkLmNlbGx0eXBlLmwyLCBoZWFsdGh5X2NkNCRzZXVyYXRfY2x1c3RlcnMpKQpwcmludCh0YWJsZShoZWFsdGh5X2NkNCRwcmVkaWN0ZWQuY2VsbHR5cGUubDMsIGhlYWx0aHlfY2Q0JHNldXJhdF9jbHVzdGVycykpCgpgYGAKCiMgU2F2ZSBSZWZlcmVuY2UgKGJlZm9yZSBNYXBRdWVyeSkKYGBge3Igc2F2ZS1yZWZ9CiMgU2F2ZQpzYXZlUkRTKHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCAiQ0Q0X3JlZmVyZW5jZV9SUENBX1NDVF9pbnRlZ3JhdGVkLnJkcyIpCmNhdCgi4pyFIENPTVBMRVRFOiIsIG5jb2wocmVmZXJlbmNlX2ludGVncmF0ZWQpLCAiY2VsbHMgaW50ZWdyYXRlZFxuIikKCgpgYGAKCgoKIyBNYXJrZXIgTW9kdWxlIFNjb3JlcyAoRGlmZmVyZW50aWF0aW9uIFN0YXRlcykKYGBge3IgbWFya2Vyc3Njb3JlLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9OH0KCkRlZmF1bHRBc3NheShyZWZlcmVuY2VfaW50ZWdyYXRlZCkgPC0gIlJOQSIKCgptYXJrZXJfbGlzdCA8LSBsaXN0KAogIFRuYWl2ZSA9IGMoIkNDUjciLCJTRUxMIiwiTEVGMSIsIlRDRjciLCJJTDdSIiwiQ0QyNyIsIlBUUFJDIiksCiAgVGNtICAgID0gYygiQ0NSNyIsIlNFTEwiLCJDRDI3IiwiSUw3UiIsIkJDTDIiLCJUQ0Y3IiksCiAgVGVtICAgID0gYygiQ0NSNiIsIkNYQ1IzIiwiR1pNSyIsIlBSRjEiLCJJRk5HIiksCiAgVGVtcmEgID0gYygiR1pNQiIsIlBSRjEiLCJLTFJHMSIsIkNYM0NSMSIpLAogIFRyZWcgICA9IGMoIkZPWFAzIiwiSUwyUkEiLCJDVExBNCIsIklLWkYyIiksCiAgVGV4ICAgID0gYygiUERDRDEiLCJDVExBNCIsIkxBRzMiLCJUSUdJVCIsIlRPWCIsIkVOVFBEMSIpLAogIENENENUTCA9IGMoIkdaTUIiLCJQUkYxIiwiTktHNyIsIktMUkcxIiwiQ1gzQ1IxIikKKQoKIyBLZWVwIG9ubHkgZ2VuZXMgcHJlc2VudAptYXJrZXJfbGlzdCA8LSBsYXBwbHkobWFya2VyX2xpc3QsIGZ1bmN0aW9uKHgpCiAgaW50ZXJzZWN0KHgsIHJvd25hbWVzKHJlZmVyZW5jZV9pbnRlZ3JhdGVkKSkKKQoKIyBEcm9wIGFueSBlbXB0eSBzZXRzIHRvIGF2b2lkIEFkZE1vZHVsZVNjb3JlIHdhcm5pbmdzCm1hcmtlcl9saXN0IDwtIG1hcmtlcl9saXN0W3ZhcHBseShtYXJrZXJfbGlzdCwgbGVuZ3RoLCAxTCkgPiAwXQoKZm9yIChzdGF0ZSBpbiBuYW1lcyhtYXJrZXJfbGlzdCkpIHsKICByZWZlcmVuY2VfaW50ZWdyYXRlZCA8LSBBZGRNb2R1bGVTY29yZSgKICAgIHJlZmVyZW5jZV9pbnRlZ3JhdGVkLAogICAgZmVhdHVyZXMgPSBsaXN0KG1hcmtlcl9saXN0W1tzdGF0ZV1dKSwKICAgIG5hbWUgICAgID0gc3RhdGUKICApCn0KCnNjb3JlX2ZlYXR1cmVzIDwtIHBhc3RlMChuYW1lcyhtYXJrZXJfbGlzdCksICIxIikKCkZlYXR1cmVQbG90KHJlZmVyZW5jZV9pbnRlZ3JhdGVkLAogICAgICAgICAgICBmZWF0dXJlcyAgID0gc2NvcmVfZmVhdHVyZXMsCiAgICAgICAgICAgIG5jb2wgICAgICAgPSA0LAogICAgICAgICAgICBjb2xzICAgICAgID0gYygibGlnaHRibHVlIiwicmVkIiksCiAgICAgICAgICAgIG1heC5jdXRvZmYgPSAicTk1IikgKwogIHBsb3RfYW5ub3RhdGlvbih0aXRsZSA9ICJEaWZmZXJlbnRpYXRpb24gU3RhdGUgTW9kdWxlIFNjb3JlcyIpCgpgYGAKIyMgRmVhdHVyZVBsb3RzIE1hcmtlcnMgYmFzZWQKYGBge3IsZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CiMgLS0tLSBMb2FkIGxpYnJhcmllcyAtLS0tCmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocGF0Y2h3b3JrKQoKIyAtLS0tIERlZmluZSBtYXJrZXJzIGZvciBkaWZmZXJlbnRpYXRpb24gc3RhdGVzIC0tLS0KdG5haXZlX21hcmtlcnMgPC0gYygiQ0NSNyIsICJTRUxMIiwgIkxFRjEiLCAiVENGNyIsICJJTDdSIiwgIkNEMjciLCAiQ0Q0NVJBIikKdGNtX21hcmtlcnMgICAgPC0gYygiQ0NSNyIsICJTRUxMIiwgIkNENDVSTyIsICJJTDdSIiwgIkNEMjciKQp0ZW1fbWFya2VycyAgICA8LSBjKCJDQ1I2IiwgIkNYQ1IzIiwgIkdaTUsiLCAiUFJGMSIsICJJRk5HIiwgIkNENDVSTyIpCnRlbXJhX21hcmtlcnMgIDwtIGMoIkdaTUIiLCAiUFJGMSIsICJLTFJHMSIsICJDWDNDUjEiLCAiQ0Q0NVJBIikKdGV4X21hcmtlcnMgICAgPC0gYygiUERDRDEiLCAiQ1RMQTQiLCAiTEFHMyIsICJUSUdJVCIsICJUT1giLCAiRU5UUEQxIikKY2Q0Y3RsX21hcmtlcnMgPC0gYygiR1pNQiIsICJQUkYxIiwgIk5LRzciLCAiS0xSRzEiLCAiQ1gzQ1IxIikgICMgQ0Q0IGN5dG90b3hpYyBtYXJrZXJzCgojIC0tLS0gS2VlcCBvbmx5IG1hcmtlcnMgcHJlc2VudCBpbiB0aGUgZGF0YXNldCAtLS0tCnRuYWl2ZV9tYXJrZXJzIDwtIHRuYWl2ZV9tYXJrZXJzW3RuYWl2ZV9tYXJrZXJzICVpbiUgcm93bmFtZXMocmVmZXJlbmNlX2ludGVncmF0ZWQpXQp0Y21fbWFya2VycyAgICA8LSB0Y21fbWFya2Vyc1t0Y21fbWFya2VycyAlaW4lIHJvd25hbWVzKHJlZmVyZW5jZV9pbnRlZ3JhdGVkKV0KdGVtX21hcmtlcnMgICAgPC0gdGVtX21hcmtlcnNbdGVtX21hcmtlcnMgJWluJSByb3duYW1lcyhyZWZlcmVuY2VfaW50ZWdyYXRlZCldCnRlbXJhX21hcmtlcnMgIDwtIHRlbXJhX21hcmtlcnNbdGVtcmFfbWFya2VycyAlaW4lIHJvd25hbWVzKHJlZmVyZW5jZV9pbnRlZ3JhdGVkKV0KdGV4X21hcmtlcnMgICAgPC0gdGV4X21hcmtlcnNbdGV4X21hcmtlcnMgJWluJSByb3duYW1lcyhyZWZlcmVuY2VfaW50ZWdyYXRlZCldCmNkNGN0bF9tYXJrZXJzIDwtIGNkNGN0bF9tYXJrZXJzW2NkNGN0bF9tYXJrZXJzICVpbiUgcm93bmFtZXMocmVmZXJlbmNlX2ludGVncmF0ZWQpXQoKIyAtLS0tIEZ1bmN0aW9uIHRvIGdlbmVyYXRlIHBhdGNod29yayBmZWF0dXJlIHBsb3RzIC0tLS0KcGxvdF9tYXJrZXJzX2dyaWQgPC0gZnVuY3Rpb24obWFya2VyX3ZlY3Rvciwgc3RhdGVfbmFtZSkgewogIHBsb3RzIDwtIGxhcHBseShtYXJrZXJfdmVjdG9yLCBmdW5jdGlvbihnZW5lKXsKICAgIEZlYXR1cmVQbG90KHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCBmZWF0dXJlcyA9IGdlbmUsIHJlZHVjdGlvbiA9ICJ1bWFwIiwKICAgICAgICAgICAgICAgIGNvbHMgPSBjKCJsaWdodGJsdWUiLCAicmVkIiksIGxhYmVsID0gVFJVRSkgKwogICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKICB9KQogIHdyYXBfcGxvdHMocGxvdHMpICsgcGxvdF9hbm5vdGF0aW9uKHRpdGxlID0gcGFzdGUoc3RhdGVfbmFtZSwgIk1hcmtlciBFeHByZXNzaW9uIikpCn0KCiMgLS0tLSBHZW5lcmF0ZSBncmlkcyBmb3IgZWFjaCBzdGF0ZSAtLS0tCnRuYWl2ZV9wbG90IDwtIHBsb3RfbWFya2Vyc19ncmlkKHRuYWl2ZV9tYXJrZXJzLCAiVG5haXZlIikKdGNtX3Bsb3QgICAgPC0gcGxvdF9tYXJrZXJzX2dyaWQodGNtX21hcmtlcnMsICJUY20iKQp0ZW1fcGxvdCAgICA8LSBwbG90X21hcmtlcnNfZ3JpZCh0ZW1fbWFya2VycywgIlRlbSIpCnRlbXJhX3Bsb3QgIDwtIHBsb3RfbWFya2Vyc19ncmlkKHRlbXJhX21hcmtlcnMsICJUZW1yYSIpCnRleF9wbG90ICAgIDwtIHBsb3RfbWFya2Vyc19ncmlkKHRleF9tYXJrZXJzLCAiVGV4IikKY2Q0Y3RsX3Bsb3QgPC0gcGxvdF9tYXJrZXJzX2dyaWQoY2Q0Y3RsX21hcmtlcnMsICJDRDQgQ1RMIikKCiMgLS0tLSBEaXNwbGF5IHBsb3RzIC0tLS0KdG5haXZlX3Bsb3QKdGNtX3Bsb3QKdGVtX3Bsb3QKdGVtcmFfcGxvdAp0ZXhfcGxvdApjZDRjdGxfcGxvdAoKYGBgCgoKCgojIEFEVCBGZWF0dXJlUGxvdHMgcGVyIGRpZmZlcmVudGlhdGlvbiBzdGF0ZQpgYGB7cixmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xNH0KIyBUbmFpdmU6IENENDVSQSsgQ0NSNysgQ0QxMjcrIChuYWl2ZS9tZW1vcnkgY29yZSkKdG5haXZlX2FkdCA8LSBjKCJDRDQ1UkEtVG90YWxDIiwgIkNEMTk3LVRvdGFsQyIsICJDRDEyNy1Ub3RhbEMiKQoKIyBUY206IENENDVSTysgQ0NSNysgQ0QxMjcrIChjZW50cmFsIG1lbW9yeSkKdGNtX2FkdCA8LSBjKCJDRDQ1Uk8tVG90YWxDIiwgIkNEMTk3LVRvdGFsQyIsICJDRDEyNy1Ub3RhbEMiKQoKIyBUZW06IENENDVSTysgQ0NSN+KIkiAoZWZmZWN0b3IgbWVtb3J5KQp0ZW1fYWR0IDwtIGMoIkNENDVSTy1Ub3RhbEMiKSAgIyBDQ1I3IGxvdyBleHBlY3RlZAoKIyBUZW1yYS9DRDRDVEw6IENENDVSQSsgKyBleGhhdXN0aW9uL2VmZmVjdG9yIChQRC0xLCBUSUdJVCwgSExBLURSKQp0ZW1yYV9hZHQgPC0gYygiQ0Q0NVJBLVRvdGFsQyIsICJQRC0xLVRvdGFsQyIsICJUSUdJVC1Ub3RhbEMiLCAiSExBLURSLVRvdGFsQyIpCgojIFRyZWc6IENEMjVoaSBDRDEyN2xvdyDCsUNENDVSQSAobmFpdmUgVHJlZyB2cyBhY3RpdmF0ZWQpCnRyZWdfYWR0IDwtIGMoIkNEMjUtVG90YWxDIiwgIkNEMTI3LVRvdGFsQyIsICJDRDQ1UkEtVG90YWxDIikKCiMgVGV4OiBleGhhdXN0aW9uIHNpZ25hdHVyZQp0ZXhfYWR0IDwtIGMoIlBELTEtVG90YWxDIiwgIlRJR0lULVRvdGFsQyIsICJITEEtRFItVG90YWxDIikKCgpEZWZhdWx0QXNzYXkocmVmZXJlbmNlX2ludGVncmF0ZWQpIDwtICJBRFQiCgpwbG90X21hcmtlcnNfZ3JpZF9BRFQgPC0gZnVuY3Rpb24obWFya2VyX3ZlY3Rvciwgc3RhdGVfbmFtZSkgewogIHBsb3RzIDwtIGxhcHBseShtYXJrZXJfdmVjdG9yLCBmdW5jdGlvbihwcm90KXsKICAgIEZlYXR1cmVQbG90KHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCBmZWF0dXJlcyA9IHByb3QsIHJlZHVjdGlvbiA9ICJ1bWFwIiwKICAgICAgICAgICAgICAgIGNvbHMgPSBjKCJsaWdodGJsdWUiLCJyZWQiKSkgKwogICAgICBnZ3RpdGxlKHByb3QpCiAgfSkKICB3cmFwX3Bsb3RzKHBsb3RzKSArIHBsb3RfYW5ub3RhdGlvbih0aXRsZSA9IHBhc3RlKHN0YXRlX25hbWUsICJBRFQgZXhwcmVzc2lvbiIpKQp9CgpwbG90X21hcmtlcnNfZ3JpZF9BRFQodG5haXZlX2FkdCwgIlRuYWl2ZSIpCnBsb3RfbWFya2Vyc19ncmlkX0FEVCh0Y21fYWR0LCAgICAiVGNtIikKcGxvdF9tYXJrZXJzX2dyaWRfQURUKHRlbV9hZHQsICAgICJUZW0iKQpwbG90X21hcmtlcnNfZ3JpZF9BRFQodGVtcmFfYWR0LCAgIlRlbXJhL0NENENUTCIpCnBsb3RfbWFya2Vyc19ncmlkX0FEVCh0cmVnX2FkdCwgICAiVHJlZyIpCnBsb3RfbWFya2Vyc19ncmlkX0FEVCh0ZXhfYWR0LCAgICAiVGV4IikKCgpgYGAKCiMjIEdhdGluZyBpbiAxMHhfUzEgKHVzZXMgKi1Ub3RhbEMpCmBgYHtyfQojIyAxMHhfUzEgQURUIGdhdGluZyAgKENJVEUtc2VxKQpEZWZhdWx0QXNzYXkocmVmZXJlbmNlX2ludGVncmF0ZWQpIDwtICJBRFQiCgpzMSA8LSBzdWJzZXQocmVmZXJlbmNlX2ludGVncmF0ZWQsIHN1YnNldCA9IGRhdGFzZXQgPT0gIkNENFRfMTB4X1MxIikKYWR0X3MxIDwtIExheWVyRGF0YShzMVtbIkFEVCJdXSwgbGF5ZXIgPSAiZGF0YS5DRDRUXzEweF9TMS4xIikKcm93bmFtZXMoYWR0X3MxKSA8LSBnc3ViKCItVG90YWxDIiwgIiIsIHJvd25hbWVzKGFkdF9zMSkpICAjIENENDVSQSwgQ0QxOTcsIC4uLgoKYWR0X3pfczEgPC0gdChzY2FsZSh0KGFkdF9zMSkpKQoKaXNfaGkgPC0gZnVuY3Rpb24oZywgem1hdCwgeiA9IDAuNSkgaWYgKGcgJWluJSByb3duYW1lcyh6bWF0KSkgem1hdFtnLCBdID4geiBlbHNlIHJlcChGQUxTRSwgbmNvbCh6bWF0KSkKCkNENDVSQV9oaSA8LSBpc19oaSgiQ0Q0NVJBIiwgYWR0X3pfczEpCkNENDVST19oaSA8LSBpc19oaSgiQ0Q0NVJPIiwgYWR0X3pfczEpCkNDUjdfaGkgICA8LSBpc19oaSgiQ0QxOTciLCAgYWR0X3pfczEpCkNEMTI3X2hpICA8LSBpc19oaSgiQ0QxMjciLCAgYWR0X3pfczEpCkNEMjVfaGkgICA8LSBpc19oaSgiQ0QyNSIsICAgYWR0X3pfczEpClBEMV9oaSAgICA8LSBpc19oaSgiUEQtMSIsICAgYWR0X3pfczEpClRJR0lUX2hpICA8LSBpc19oaSgiVElHSVQiLCAgYWR0X3pfczEpCkhMQURSX2hpICA8LSBpc19oaSgiSExBLURSIiwgYWR0X3pfczEpCgpDQ1I3X2xvICA8LSAhQ0NSN19oaQpDRDEyN19sbyA8LSAhQ0QxMjdfaGkKCnN0YXRlX3MxIDwtIHJlcCgiT3RoZXIiLCBuY29sKGFkdF9zMSkpCgojIFRyZWcKdHJlZ19pZHggPC0gQ0QyNV9oaSAmIENEMTI3X2xvCnN0YXRlX3MxW3RyZWdfaWR4XSA8LSAiVHJlZ19BRFQiCgojIFRuYWl2ZQp0bmFpdmVfaWR4IDwtIENENDVSQV9oaSAmIENDUjdfaGkgJiBDRDEyN19oaSAmICFDRDQ1Uk9faGkgJiAhUEQxX2hpICYgIVRJR0lUX2hpCnN0YXRlX3MxW3RuYWl2ZV9pZHggJiBzdGF0ZV9zMSA9PSAiT3RoZXIiXSA8LSAiVG5haXZlX0FEVCIKCiMgVGNtCnRjbV9pZHggPC0gQ0Q0NVJPX2hpICYgQ0NSN19oaSAmICFDRDQ1UkFfaGkKc3RhdGVfczFbdGNtX2lkeCAmIHN0YXRlX3MxID09ICJPdGhlciJdIDwtICJUY21fQURUIgoKIyBUZW0KdGVtX2lkeCA8LSBDRDQ1Uk9faGkgJiBDQ1I3X2xvICYgIUNENDVSQV9oaQpzdGF0ZV9zMVt0ZW1faWR4ICYgc3RhdGVfczEgPT0gIk90aGVyIl0gPC0gIlRlbV9BRFQiCgojIFRlbXJhIC8gQ0Q0Q1RMCnRlbXJhX2lkeCA8LSBDRDQ1UkFfaGkgJiBDQ1I3X2xvICYgKFBEMV9oaSB8IFRJR0lUX2hpIHwgSExBRFJfaGkpCnN0YXRlX3MxW3RlbXJhX2lkeCAmIHN0YXRlX3MxID09ICJPdGhlciJdIDwtICJUZW1yYV9DVExfQURUIgoKdGFibGUoc3RhdGVfczEpCmBgYAoKIyMgUmVjb3ZlciBBRFQgZm9yIENENFRfbGFiIGZyb20gb3JpZ2luYWwgb2JqZWN0IGFuZCBhbGlnbiBjZWxscwpgYGB7cn0KCiMgTWF0Y2ggY2VsbHMKbGFiX2NlbGxzIDwtIGNvbG5hbWVzKHN1YnNldChyZWZlcmVuY2VfaW50ZWdyYXRlZCwgZGF0YXNldCA9PSAiQ0Q0VF9sYWIiKSkKbGFiX3JhdyAgIDwtIHN1YigiXlBCTUNfIiwgIiIsIGxhYl9jZWxscykKCmFkdF9sYWJfcmF3IDwtIGFkdF9sYWJfcmF3WywgbGFiX3JhdywgZHJvcCA9IEZBTFNFXQpjb2xuYW1lcyhhZHRfbGFiX3JhdykgPC0gbGFiX2NlbGxzCgojIEFkZCBhc3NheSBPTkNFCnJlZmVyZW5jZV9pbnRlZ3JhdGVkW1siQURUX2xhYiJdXSA8LSBDcmVhdGVBc3NheTVPYmplY3QoY291bnRzID0gYWR0X2xhYl9yYXcpCgpgYGAKCiMjIEV4dHJhY3QgT05MWSBvdmVybGFwcGluZyBjZWxscwpgYGB7cn0KCiMgQ3JlYXRlIG5ldyBhc3NheSBmb3IgQ0Q0VF9sYWIgQURUIGRhdGEKcmVmZXJlbmNlX2ludGVncmF0ZWRbWyJBRFRfbGFiIl1dIDwtIENyZWF0ZUFzc2F5NU9iamVjdChjb3VudHMgPSBhZHRfbGFiX3JhdykKCiMgVmVyaWZ5IGl0IHdhcyBhZGRlZApsYWIgPC0gc3Vic2V0KHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCBzdWJzZXQgPSBkYXRhc2V0ID09ICJDRDRUX2xhYiIpCmRpbShMYXllckRhdGEobGFiW1siQURUX2xhYiJdXSwgbGF5ZXIgPSAiY291bnRzIikpCmhlYWQocm93bmFtZXMoTGF5ZXJEYXRhKGxhYltbIkFEVF9sYWIiXV0sIGxheWVyID0gImNvdW50cyIpKSkKCmBgYAoKIyMgQ3JlYXRlIGFuZCBhZGQgQURUX2xhYiBhc3NheQpgYGB7cn0KCiMgQ3JlYXRlIG5ldyBhc3NheSBmb3IgQ0Q0VF9sYWIgQURUIGRhdGEKcmVmZXJlbmNlX2ludGVncmF0ZWRbWyJBRFRfbGFiIl1dIDwtIENyZWF0ZUFzc2F5NU9iamVjdChjb3VudHMgPSBhZHRfbGFiX3JhdykKCiMgVmVyaWZ5IGl0IHdhcyBhZGRlZApsYWIgPC0gc3Vic2V0KHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCBzdWJzZXQgPSBkYXRhc2V0ID09ICJDRDRUX2xhYiIpCmRpbShMYXllckRhdGEobGFiW1siQURUX2xhYiJdXSwgbGF5ZXIgPSAiY291bnRzIikpCmhlYWQocm93bmFtZXMoTGF5ZXJEYXRhKGxhYltbIkFEVF9sYWIiXV0sIGxheWVyID0gImNvdW50cyIpKSkKCmBgYAoKCiMjIE5vdyBnYXRlIG9uIENENFRfbGFiIGNlbGxzICh3b3JrcyEpCmBgYHtyfQoKIyBDcmVhdGUgbmV3IGFzc2F5IGZvciBDRDRUX2xhYiBBRFQgZGF0YQpyZWZlcmVuY2VfaW50ZWdyYXRlZFtbIkFEVF9sYWIiXV0gPC0gQ3JlYXRlQXNzYXk1T2JqZWN0KGNvdW50cyA9IGFkdF9sYWJfcmF3KQoKIyBWZXJpZnkgaXQgd2FzIGFkZGVkCmxhYiA8LSBzdWJzZXQocmVmZXJlbmNlX2ludGVncmF0ZWQsIHN1YnNldCA9IGRhdGFzZXQgPT0gIkNENFRfbGFiIikKZGltKExheWVyRGF0YShsYWJbWyJBRFRfbGFiIl1dLCBsYXllciA9ICJjb3VudHMiKSkKaGVhZChyb3duYW1lcyhMYXllckRhdGEobGFiW1siQURUX2xhYiJdXSwgbGF5ZXIgPSAiY291bnRzIikpKQoKYGBgCgoKCgoKCgoKCiMjIEdhdGluZyBpbiBDRDRUX2xhYiAodXNlcyBtYXJrZXJzIHdpdGhvdXQgLVRvdGFsQykKYGBge3J9CgpEZWZhdWx0QXNzYXkocmVmZXJlbmNlX2ludGVncmF0ZWQpIDwtICJBRFQiCgojIyBDRDRUX2xhYiBBRFQgZ2F0aW5nICAobGFiIHBhbmVsKQoKIyBTdWJzZXQgbGFiIGRhdGFzZXQKbGFiIDwtIHN1YnNldChyZWZlcmVuY2VfaW50ZWdyYXRlZCwgc3Vic2V0ID0gZGF0YXNldCA9PSAiQ0Q0VF9sYWIiKQoKIyBHZXQgQURUIGV4cHJlc3Npb24gKFJOQS1saWtlIG1hcmtlcnMgd2l0aG91dCAtVG90YWxDKQphZHRfbGFiIDwtIExheWVyRGF0YShsYWJbWyJBRFQiXV0sIGxheWVyID0gImRhdGEiKSAgICMgbm90IHNsb3Q9CiMgQ2hlY2sgcm93bmFtZXM6CmhlYWQocm93bmFtZXMoYWR0X2xhYikpCgojIFotc2NvcmUKYWR0X3pfbGFiIDwtIHQoc2NhbGUodChhZHRfbGFiKSkpCgppc19oaSA8LSBmdW5jdGlvbihnLCB6bWF0LCB6ID0gMC41KSB7CiAgaWYgKCFnICVpbiUgcm93bmFtZXMoem1hdCkpIHJldHVybihyZXAoRkFMU0UsIG5jb2woem1hdCkpKQogIHptYXRbZywgXSA+IHoKfQoKQ0Q0NVJBX2hpX2wgPC0gaXNfaGkoIkNENDVSQSIsIGFkdF96X2xhYikKQ0Q0NVJPX2hpX2wgPC0gaXNfaGkoIkNENDVSTyIsIGFkdF96X2xhYikKQ0NSN19oaV9sICAgPC0gaXNfaGkoIkNDUjciLCAgIGFkdF96X2xhYikKQ0QxMjdfaGlfbCAgPC0gaXNfaGkoIkNEMTI3IiwgIGFkdF96X2xhYikKQ0QyNV9oaV9sICAgPC0gaXNfaGkoIkNEMjUiLCAgIGFkdF96X2xhYikKUEQxX2hpX2wgICAgPC0gaXNfaGkoIlBEMSIsICAgIGFkdF96X2xhYikKVElHSVRfaGlfbCAgPC0gaXNfaGkoIlRJR0lUIiwgIGFkdF96X2xhYikKSExBRFJfaGlfbCAgPC0gaXNfaGkoIkhMQS1EUiIsIGFkdF96X2xhYikgICMgaWYgcHJlc2VudAoKQ0NSN19sb19sICA8LSAhQ0NSN19oaV9sCkNEMTI3X2xvX2wgPC0gIUNEMTI3X2hpX2wKCnN0YXRlX2xhYiA8LSByZXAoIk90aGVyIiwgbmNvbChhZHRfbGFiKSkKCiMgVHJlZwp0cmVnX2lkeF9sIDwtIENEMjVfaGlfbCAmIENEMTI3X2xvX2wKc3RhdGVfbGFiW3RyZWdfaWR4X2xdIDwtICJUcmVnX0FEVCIKCiMgVG5haXZlCnRuYWl2ZV9pZHhfbCA8LSBDRDQ1UkFfaGlfbCAmIENDUjdfaGlfbCAmIENEMTI3X2hpX2wgJiAhQ0Q0NVJPX2hpX2wgJiAhUEQxX2hpX2wgJiAhVElHSVRfaGlfbApzdGF0ZV9sYWJbdG5haXZlX2lkeF9sICYgc3RhdGVfbGFiID09ICJPdGhlciJdIDwtICJUbmFpdmVfQURUIgoKIyBUY20KdGNtX2lkeF9sIDwtIENENDVST19oaV9sICYgQ0NSN19oaV9sICYgIUNENDVSQV9oaV9sCnN0YXRlX2xhYlt0Y21faWR4X2wgJiBzdGF0ZV9sYWIgPT0gIk90aGVyIl0gPC0gIlRjbV9BRFQiCgojIFRlbQp0ZW1faWR4X2wgPC0gQ0Q0NVJPX2hpX2wgJiBDQ1I3X2xvX2wgJiAhQ0Q0NVJBX2hpX2wKc3RhdGVfbGFiW3RlbV9pZHhfbCAmIHN0YXRlX2xhYiA9PSAiT3RoZXIiXSA8LSAiVGVtX0FEVCIKCiMgVGVtcmEvQ0Q0Q1RMCnRlbXJhX2lkeF9sIDwtIENENDVSQV9oaV9sICYgQ0NSN19sb19sICYgKFBEMV9oaV9sIHwgVElHSVRfaGlfbCB8IEhMQURSX2hpX2wpCnN0YXRlX2xhYlt0ZW1yYV9pZHhfbCAmIHN0YXRlX2xhYiA9PSAiT3RoZXIiXSA8LSAiVGVtcmFfQ1RMX0FEVCIKCnRhYmxlKHN0YXRlX2xhYikKYGBgCiMjIEFzc2lnbiBwZXLigJFjZWxsIGRpZmZlcmVudGlhdGlvbiBzdGF0ZQpgYGB7cn0KIyBDb2xsZWN0IG1vZHVsZSBzY29yZSBjb2x1bW4gbmFtZXMgKHRoZXkgZW5kIHdpdGggIjEiKQpzdGF0ZV9uYW1lcyA8LSBuYW1lcyhtYXJrZXJfbGlzdCkgICAgICAgICAgICAgICMgZS5nLiAiVG5haXZlIiwiVGNtIiwuLi4Kc2NvcmVfY29scyAgPC0gcGFzdGUwKHN0YXRlX25hbWVzLCAiMSIpICAgICAgICAjICJUbmFpdmUxIiwiVGNtMSIsLi4uCgojIEJ1aWxkIG1hdHJpeCBvZiBzY29yZXMKc2NvcmVfbWF0IDwtIGFzLmRhdGEuZnJhbWUocmVmZXJlbmNlX2ludGVncmF0ZWRAbWV0YS5kYXRhWywgc2NvcmVfY29sc10pCgojIEZvciBlYWNoIGNlbGwsIGZpbmQgd2hpY2ggc3RhdGUgaGFzIHRoZSBoaWdoZXN0IHNjb3JlCnN0YXRlX21heF9pZHggICA8LSBhcHBseShzY29yZV9tYXQsIDEsIHdoaWNoLm1heCkKc3RhdGVfbWF4X2xhYmVsIDwtIHN0YXRlX25hbWVzW3N0YXRlX21heF9pZHhdCgojIE9wdGlvbmFsbHkgaW1wb3NlIGEgbWluaW11bSBzZXBhcmF0aW9uOiBpZiB0b3Agc2NvcmUgaXMgbm90IHN1ZmZpY2llbnRseQojIGhpZ2hlciB0aGFuIHRoZSBzZWNvbmQsIGNhbGwgdGhlIGNlbGwgIk1peGVkIgp0b3BfdmFscyAgPC0gYXBwbHkoc2NvcmVfbWF0LCAxLCBtYXgpCnNlY29uZF92YWxzIDwtIGFwcGx5KHNjb3JlX21hdCwgMSwgZnVuY3Rpb24oeCkgc29ydCh4LCBkZWNyZWFzaW5nID0gVFJVRSlbMl0pCmRlbHRhIDwtIHRvcF92YWxzIC0gc2Vjb25kX3ZhbHMKc3RhdGVfbWF4X2xhYmVsW2RlbHRhIDwgMC4wNV0gPC0gIk1peGVkIiAgICMgMC4wNSBpcyBhbiBleGFtcGxlIHRocmVzaG9sZAoKIyBTdG9yZSBpbiBtZXRhZGF0YQpyZWZlcmVuY2VfaW50ZWdyYXRlZCRkaWZmX3N0YXRlIDwtIGZhY3RvcihzdGF0ZV9tYXhfbGFiZWwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIlRuYWl2ZSIsIlRjbSIsIlRlbSIsIlRlbXJhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVHJlZyIsIlRleCIsIkNENENUTCIsIk1peGVkIikpCgojIFVNQVAgY29sb3JlZCBieSBpbmZlcnJlZCBkaWZmZXJlbnRpYXRpb24gc3RhdGUKRGltUGxvdChyZWZlcmVuY2VfaW50ZWdyYXRlZCwgZ3JvdXAuYnkgPSAiZGlmZl9zdGF0ZSIsIGxhYmVsID0gVFJVRSwgbGFiZWwuYm94ID0gVCwgcmVwZWwgPSBUKSArCiAgZ2d0aXRsZSgiSW5mZXJyZWQgQ0Q0IFQtY2VsbCBkaWZmZXJlbnRpYXRpb24gc3RhdGVzIikKYGBgCgoKCiMgQURUIG1hcmtlcnMgYW5kIGV4dHJhY3Rpb24gKDEweF9TMSBhbHJlYWR5IHJ1bikKYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKIyBvIHlvdSBjYW4gZG86CiMgCiMgVG5haXZlOiBDRDMrIENENCsgQ0Q0NVJBKyBDRDQ1Uk/iiJIgQ0NSNysgQ0QxMjcrCiMgCiMgVGNtOiBDRDMrIENENCsgQ0Q0NVJPKyBDQ1I3KyBDRDQ1UkHiiJIKIyAKIyBUZW06IENEMysgQ0Q0KyBDRDQ1Uk8rIENDUjfiiJIgKG9yIGxvdykgQ0Q0NVJB4oiSCiMgCiMgVGVtcmE6IENEMysgQ0Q0KyBDRDQ1UkErIENENDVSTysv4oiSIENDUjfiiJIKCgoKRGVmYXVsdEFzc2F5KHJlZmVyZW5jZV9pbnRlZ3JhdGVkKSA8LSAiQURUIgoKYWR0X21hcmtlcnNfcmF3IDwtIGMoIkNEMy1Ub3RhbEMiLCJDRDQtVG90YWxDIiwiQ0Q0NVJBLVRvdGFsQyIsCiAgICAgICAgICAgICAgICAgICAgICJDRDQ1Uk8tVG90YWxDIiwiQ0QxOTctVG90YWxDIiwiQ0QxMjctVG90YWxDIiwKICAgICAgICAgICAgICAgICAgICAgIkNEMjUtVG90YWxDIiwiSExBLURSLVRvdGFsQyIsIlBEMS1Ub3RhbEMiLCJUSUdJVC1Ub3RhbEMiKQoKRmVhdHVyZVBsb3QocmVmZXJlbmNlX2ludGVncmF0ZWQsCiAgICAgICAgICAgIGZlYXR1cmVzID0gYWR0X21hcmtlcnNfcmF3LAogICAgICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsCiAgICAgICAgICAgIGNvbHMgPSBjKCJsaWdodGJsdWUiLCJyZWQiKSwKICAgICAgICAgICAgbmNvbCA9IDMpICsKICBwbG90X2Fubm90YXRpb24odGl0bGUgPSAiS2V5IEFEVCBtYXJrZXJzICgxMHhfUzEgY2VsbHMpIikKYGBgCiMgRGVyaXZlIEFEVOKAkWJhc2VkIOKAnGhpZ2gvbG934oCdIGNhdGVnb3JpZXMKYGBge3J9CiMgRnVsbCBVTUFQLCAxMHhfUzEgY29sb3JlZCwgb3RoZXJzIGdyZXkKcDEgPC0gRGltUGxvdChyZWZlcmVuY2VfaW50ZWdyYXRlZCwKICAgICAgICAgICAgICBncm91cC5ieSA9ICJBRFRfc3RhdGUyIiwKICAgICAgICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsCiAgICAgICAgICAgICAgcHQuc2l6ZSAgID0gMC41KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIlRuYWl2ZV9BRFQiID0gIiNGRjZCNkIiLCAiVGNtX0FEVCIgPSAiIzRFQ0RDNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRlbV9BRFQiID0gIiM0NUI3RDEiLCAiVGVtcmFfQ1RMX0FEVCIgPSAiIzk2Q0VCNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRyZWdfQURUIiA9ICIjRkVDQTU3IiwgIk90aGVyIiA9ICJncmV5ODAiKSkgKwogIGdndGl0bGUoIkZ1bGwgVU1BUDogMTB4X1MxIGNvbG9yZWQgYnkgQURULCBvdGhlcnMgZ3JleSIpCgpwMiA8LSBEaW1QbG90KHN1YnNldChyZWZlcmVuY2VfaW50ZWdyYXRlZCwgZGF0YXNldCA9PSAiQ0Q0VF8xMHhfUzEiKSwKICAgICAgICAgICAgICBncm91cC5ieSA9ICJBRFRfc3RhdGUyIiwKICAgICAgICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsCiAgICAgICAgICAgICAgbGFiZWwgPSBUUlVFLCBsYWJlbC5ib3ggPSBUUlVFLCByZXBlbCA9IFRSVUUpICsKICBnZ3RpdGxlKCIxMHhfUzEgT05MWSIpICsKICBOb0xlZ2VuZCgpCgpwMSB8IHAyCmBgYAoKIyMgTG9naWNhbCBnYXRpbmcgZm9yIFRuYWl2ZS9UY20vVGVtL1RlbXJhCmBgYHtyfQojIEJvb2xlYW4gdmVjdG9ycyBwZXIgbWFya2VyCkNENDVSQV9oaSA8LSBpc19oaWdoKCJDRDQ1UkEiLCBhZHRfeikKQ0Q0NVJPX2hpIDwtIGlzX2hpZ2goIkNENDVSTyIsIGFkdF96KQpDQ1I3X2hpICAgPC0gaXNfaGlnaCgiQ0QxOTciLCAgYWR0X3opICAgIyBDQ1I3CkNEMTI3X2hpICA8LSBpc19oaWdoKCJDRDEyNyIsICBhZHRfeikKCiMgR2F0aW5nIHJ1bGVzClRuYWl2ZV9pZHggPC0gIENENDVSQV9oaSAmICBDQ1I3X2hpICYgQ0QxMjdfaGkgJiAhQ0Q0NVJPX2hpClRjbV9pZHggICAgPC0gIUNENDVSQV9oaSAmICBDQ1I3X2hpICYgIENENDVST19oaQpUZW1faWR4ICAgIDwtICFDRDQ1UkFfaGkgJiAhQ0NSN19oaSAmICBDRDQ1Uk9faGkKVGVtcmFfaWR4ICA8LSAgQ0Q0NVJBX2hpICYgIUNDUjdfaGkgJiAoQ0Q0NVJPX2hpIHwgIUNENDVST19oaSkgICMgUkErIENDUjfiiJIKCiMgQXNzaWduIHN0YXRlOyByZXNvbHZlIGNvbmZsaWN0cyBieSBwcmlvcml0eQpzdGF0ZSA8LSByZXAoIk90aGVyIiwgbmNvbChhZHQpKQpzdGF0ZVtUbmFpdmVfaWR4XSA8LSAiVG5haXZlIgpzdGF0ZVtUY21faWR4XSAgICA8LSAiVGNtIgpzdGF0ZVtUZW1faWR4XSAgICA8LSAiVGVtIgpzdGF0ZVtUZW1yYV9pZHhdICA8LSAiVGVtcmEiCgojIFN0b3JlIGluIG1ldGFkYXRhICgxMHhfUzEgc3Vic2V0KQpzMV9zdWJzZXQkQURUX3N0YXRlIDwtIHN0YXRlCgojIFB1dCBiYWNrIGludG8gZnVsbCBvYmplY3QKcmVmZXJlbmNlX2ludGVncmF0ZWQkQURUX3N0YXRlIDwtIE5BCnJlZmVyZW5jZV9pbnRlZ3JhdGVkJEFEVF9zdGF0ZVtjb2xuYW1lcyhzMV9zdWJzZXQpXSA8LSBzMV9zdWJzZXQkQURUX3N0YXRlCnJlZmVyZW5jZV9pbnRlZ3JhdGVkJEFEVF9zdGF0ZSA8LSBmYWN0b3IocmVmZXJlbmNlX2ludGVncmF0ZWQkQURUX3N0YXRlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIlRuYWl2ZSIsIlRjbSIsIlRlbSIsIlRlbXJhIiwiT3RoZXIiKSkKYGBgCgojIFZpc3VhbGl6ZSBBRFTigJFkZWZpbmVkIHN0YXRlcyBvbiB5b3VyIGludGVncmF0ZWQgVU1BUApgYGB7ciBNb25vY2xlM30KRGVmYXVsdEFzc2F5KHJlZmVyZW5jZV9pbnRlZ3JhdGVkKSA8LSAiaW50ZWdyYXRlZCIKCkRpbVBsb3QocmVmZXJlbmNlX2ludGVncmF0ZWQsCiAgICAgICAgZ3JvdXAuYnkgPSAiQURUX3N0YXRlIiwKICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsCiAgICAgICAgbGFiZWwgPSBUUlVFLCBsYWJlbC5ib3ggPSBULCByZXBlbCA9IFQpICsKICBnZ3RpdGxlKCJDRDRUXzEweF9TMSBjZWxscyBhbm5vdGF0ZWQgYnkgQURUIGdhdGluZyIpCmBgYAoKCgojIE1vbm9jbGUzIFRyYWplY3RvcnkKYGBge3IgfQpjZHMgPC0gYXMuY2VsbF9kYXRhX3NldChyZWZlcmVuY2VfaW50ZWdyYXRlZCkKCiMgVHJhbnNmZXIgVU1BUCArIHBhcnRpdGlvbnMgZnJvbSBTZXVyYXQKcmVkdWNlZERpbShjZHMsICJVTUFQIikgPC0gRW1iZWRkaW5ncyhyZWZlcmVuY2VfaW50ZWdyYXRlZCwgInVtYXAiKQpjZHNAY2x1c3RlcnMkVU1BUCRwYXJ0aXRpb25zIDwtIGZhY3RvcihyZXAoMSwgbmNvbChjZHMpKSkKY2RzQGNsdXN0ZXJzJFVNQVAkY2x1c3RlcnMgICA8LSByZWZlcmVuY2VfaW50ZWdyYXRlZCRzZXVyYXRfY2x1c3RlcnMKY29sRGF0YShjZHMpJGNlbGx0eXBlICAgICAgICAgPC0gcmVmZXJlbmNlX2ludGVncmF0ZWQkcHJlZGljdGVkLmNlbGx0eXBlLmwyCmNvbERhdGEoY2RzKSRkYXRhc2V0ICAgICAgICAgIDwtIHJlZmVyZW5jZV9pbnRlZ3JhdGVkJGRhdGFzZXQKYGBgCgpgYGB7ciBsZWFybi1ncmFwaH0KY2RzIDwtIGxlYXJuX2dyYXBoKGNkcywKICAgICAgICAgICAgICAgICAgIHVzZV9wYXJ0aXRpb24gPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGNsb3NlX2xvb3AgICAgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIHZlcmJvc2UgICAgICAgPSBGQUxTRSkKCnBsb3RfY2VsbHMoY2RzLAogICAgICAgICAgIGNvbG9yX2NlbGxzX2J5ICAgICAgICAgID0gImNlbGx0eXBlIiwKICAgICAgICAgICBsYWJlbF9ncm91cHNfYnlfY2x1c3RlciA9IEZBTFNFLAogICAgICAgICAgIGxhYmVsX2xlYXZlcyAgICAgICAgICAgID0gVFJVRSwKICAgICAgICAgICBsYWJlbF9icmFuY2hfcG9pbnRzICAgICA9IFRSVUUsCiAgICAgICAgICAgZ3JhcGhfbGFiZWxfc2l6ZSAgICAgICAgPSA0KSArCiAgZ2d0aXRsZSgiTW9ub2NsZTMg4oCUIENENCBULWNlbGwgVHJhamVjdG9yeSBNaWxlc3RvbmVzIikKCgpgYGAKCmBgYHtyIHBzZXVkb3RpbWV9CiMgUm9vdCA9IENENCBOYWl2ZSBjZW50cm9pZApuYWl2ZV9pZHMgPC0gcm93bmFtZXMoY29sRGF0YShjZHMpKVsKICBjb2xEYXRhKGNkcykkY2VsbHR5cGUgJWluJSBjKCJDRDQgTmFpdmUiKQpdCgpnZXRfcm9vdF9ub2RlIDwtIGZ1bmN0aW9uKGNkcywgY2VsbF9pZHMpIHsKICBjbG9zZXN0IDwtIGNkc0BwcmluY2lwYWxfZ3JhcGhfYXV4JFVNQVAkcHJfZ3JhcGhfY2VsbF9wcm9qX2Nsb3Nlc3RfdmVydGV4CiAgY2xvc2VzdCA8LSBhcy5tYXRyaXgoY2xvc2VzdFtjb2xuYW1lcyhjZHMpLCBdKQogIGlncmFwaDo6VihwcmluY2lwYWxfZ3JhcGgoY2RzKSRVTUFQKSRuYW1lWwogICAgYXMubnVtZXJpYyhuYW1lcyh3aGljaC5tYXgodGFibGUoY2xvc2VzdFtjZWxsX2lkcywgXSkpKSldCn0KCmNkcyA8LSBvcmRlcl9jZWxscyhjZHMsIHJvb3RfcHJfbm9kZXMgPSBnZXRfcm9vdF9ub2RlKGNkcywgbmFpdmVfaWRzKSkKcmVmZXJlbmNlX2ludGVncmF0ZWQkbW9ub2NsZTNfcHNldWRvdGltZSA8LSBwc2V1ZG90aW1lKGNkcykKCnBsb3RfY2VsbHMoY2RzLAogICAgICAgICAgIGNvbG9yX2NlbGxzX2J5ICAgID0gInBzZXVkb3RpbWUiLAogICAgICAgICAgIGxhYmVsX2NlbGxfZ3JvdXBzID0gRkFMU0UpICsKICBzY2FsZV9jb2xvcl92aXJpZGlzX2Mob3B0aW9uID0gInBsYXNtYSIpICsKICBnZ3RpdGxlKCJQc2V1ZG90aW1lOiBOYWl2ZSDihpIgTWVtb3J5IOKGkiBFZmZlY3RvciDihpIgVHJlZyIpCmBgYAoKLS0tCgojIFNhdmUgUmVmZXJlbmNlIChiZWZvcmUgTWFwUXVlcnkpCgpgYGB7ciBzYXZlcmVmLWZpbmFsfQpzYXZlUkRTKHJlZmVyZW5jZV9pbnRlZ3JhdGVkLAogICAgICAgICJDRDRfcmVmZXJlbmNlX1JQQ0FfU0NUX1RyYWplY3RvcnlfYW5ub3RhdGVkLnJkcyIpCgpjYXQoIlJlZmVyZW5jZSBzYXZlZDoiLCBuY29sKHJlZmVyZW5jZV9pbnRlZ3JhdGVkKSwgImNlbGxzXG4iKQoKYGBgCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgpgYGAKCgoKCg==