Load libraries
Load Annotated Healthy
Integrated Object
reference_integrated<- readRDS("../CD4_reference_annotated_with_markers.rds")
DefaultAssay(reference_integrated) <- "RNA"
reference_integrated
Azimuth Label
Validation
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()

DimPlot(reference_integrated, group.by = "singler.hpca",
label = TRUE, repel = TRUE, label.size = 3) + NoLegend()

DimPlot(reference_integrated, group.by = "singler.immune",
label = TRUE, repel = TRUE, label.size = 3) + NoLegend()

print(table(reference_integrated$predicted.celltype.l1, reference_integrated$seurat_clusters))
0 1 2 3 4 5 6
CD4 T 5485 3998 522 487 412 340 232
CD8 T 0 0 0 4 0 1 1
print(table(reference_integrated$predicted.celltype.l2, reference_integrated$seurat_clusters))
0 1 2 3 4 5 6
CD4 CTL 0 0 0 11 0 0 0
CD4 Naive 2030 7 1 0 20 1 5
CD4 Proliferating 5 0 0 0 0 7 0
CD4 TCM 3421 3972 519 346 391 154 222
CD4 TEM 0 8 1 134 0 1 0
Treg 29 11 1 0 1 178 6
print(table(reference_integrated$predicted.celltype.l3, reference_integrated$seurat_clusters))
0 1 2 3 4 5 6
CD4 CTL 0 0 0 11 0 0 0
CD4 Naive 2036 9 1 0 20 1 5
CD4 Proliferating 5 0 0 0 0 7 0
CD4 TCM_1 3408 2545 506 74 371 48 201
CD4 TCM_2 1 314 3 26 17 102 13
CD4 TCM_3 8 1104 10 256 3 2 5
CD4 TEM_1 0 1 0 41 0 0 0
CD4 TEM_2 0 9 0 30 0 1 0
CD4 TEM_3 0 2 1 53 0 0 0
Treg Memory 9 14 1 0 1 158 9
Treg Naive 18 0 0 0 0 22 0
print(table(reference_integrated$singler.hpca, reference_integrated$seurat_clusters))
0 1 2 3 4 5 6
B_cell:Memory 1 0 0 0 0 0 0
Neutrophil:uropathogenic_E._coli_UTI89 0 0 0 0 1 0 0
NK_cell:CD56hiCD62L+ 0 0 0 1 0 0 0
T_cell:CD4+ 0 0 1 1 0 0 0
T_cell:CD4+_central_memory 460 2911 316 175 58 238 79
T_cell:CD4+_effector_memory 5 478 11 278 2 23 5
T_cell:CD4+_Naive 4996 578 186 5 315 75 134
T_cell:CD8+ 0 2 0 12 0 1 0
T_cell:CD8+_Central_memory 0 0 0 2 0 0 0
T_cell:CD8+_effector_memory 3 12 7 4 22 0 12
T_cell:CD8+_effector_memory_RA 0 0 0 1 0 0 1
T_cell:CD8+_naive 0 1 0 5 7 0 0
T_cell:gamma-delta 2 0 0 0 0 1 0
T_cell:Treg:Naive 2 1 0 0 0 2 1
print(table(reference_integrated$singler.immune, reference_integrated$seurat_clusters))
0 1 2 3 4 5 6
NK cells 0 1 0 10 1 0 1
T cells, CD4+, memory TREG 6 152 18 3 3 186 5
T cells, CD4+, naive 3827 66 48 0 121 2 100
T cells, CD4+, naive TREG 247 29 1 0 3 108 6
T cells, CD4+, naive, stimulated 22 16 5 0 85 0 7
T cells, CD4+, TFH 1181 1642 165 46 113 23 47
T cells, CD4+, Th1 18 174 18 284 5 11 5
T cells, CD4+, Th1_17 3 240 2 141 0 0 8
T cells, CD4+, Th17 11 992 82 3 10 7 16
T cells, CD4+, Th2 51 675 173 1 23 3 34
T cells, CD8+, naive 107 5 5 2 7 1 4
T cells, CD8+, naive, stimulated 5 3 5 1 39 0 0
Quick Visual Summary of
Top Markers(Dotplot)
library(dplyr)
# ── SCpubr DotPlot for top 5 markers ───────────────────────────────────
DefaultAssay(reference_integrated) <- "RNA"
# Get top 5 genes per cluster (already computed)
top5_genes <- reference_integrated@misc$markers_top5 %>%
dplyr::group_by(cluster) %>%
dplyr::slice_head(n = 5) %>%
dplyr::pull(gene) %>%
unique()
# ── SCpubr v1.x — minimal working syntax ───────────────────────────────
SCpubr::do_DotPlot(sample = reference_integrated,
features = top5_genes,
flip = TRUE,
)

FeaturePlot to check
TEMRA
FeaturePlot(
object = reference_integrated,
features = c("PRF1", "NKG7", "FGFBP2", "GNLY"),
cols = c("lightgrey", "red"),label = T,
ncol = 2
)

TABLE
Post-Annotation
table(reference_integrated$predicted.celltype.l2, reference_integrated@meta.data$cell_type)
CD4 Tnaive (CCR7+SELL+TCF7+) CD4 TCM (CD161+/IL7R+) CD4 TCM (CCR4+/Th2-like) CD4 CTL/Temra (GZMK+GZMA+CCL5+)
CD4 CTL 0 0 0 11
CD4 Naive 2030 7 1 0
CD4 Proliferating 5 0 0 0
CD4 TCM 3421 3972 519 346
CD4 TEM 0 8 1 134
Treg 29 11 1 0
CD4 TEM (NF-kB activated) CD4 Treg (FOXP3+Helios+CD25+) CD4 Tnaive-RTE (IGF1R+)
CD4 CTL 0 0 0
CD4 Naive 20 1 5
CD4 Proliferating 0 7 0
CD4 TCM 391 154 222
CD4 TEM 0 1 0
Treg 1 178 6
DimPlots
Post-Annotation
# FIX 1: chunk label renamed from 'markersscore' — was duplicate
DimPlot(reference_integrated, group.by = "seurat_clusters", label = TRUE, label.box = TRUE,
repel = TRUE) + ggtitle("Clusters 0-6")

DimPlot(reference_integrated, group.by = "cell_type", label = TRUE, repel = TRUE, label.box =
TRUE) + ggtitle("Cell Types")

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")
)
marker_list <- lapply(marker_list, function(x) intersect(x, rownames(reference_integrated)))
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"), label = TRUE, max.cutoff = "q95") +
plot_annotation(title = "Differentiation State Module Scores")

Treg Subset Validation
(CTLA4/TIGIT)
# Set assay and extract expression
DefaultAssay(reference_integrated) <- "RNA"
# Extract CTLA4 and TIGIT expression (log-normalized data)
ctla4_expr <- GetAssayData(reference_integrated, assay = "RNA", layer = "data")["CTLA4", ]
tigit_expr <- GetAssayData(reference_integrated, assay = "RNA", layer = "data")["TIGIT", ]
reference_integrated$treg_subset <- ifelse(
reference_integrated$seurat_clusters == "5",
ifelse(ctla4_expr > 0 & tigit_expr > 0, "Treg effector", "Treg resting"),
"non-Treg"
)
DimPlot(reference_integrated, group.by = "treg_subset", label = TRUE) +
ggtitle("Cluster 5 Treg heterogeneity by CTLA4/TIGIT")

FeaturePlots per
Differentiation State
DefaultAssay(reference_integrated) <- "RNA"
plot_markers_grid <- function(marker_vector, state_name) {
markers_present <- intersect(marker_vector, rownames(reference_integrated))
plots <- lapply(markers_present, function(gene) {
FeaturePlot(reference_integrated, features = gene, reduction = "umap",
cols = c("lightblue", "red"), label = TRUE)
})
wrap_plots(plots) + plot_annotation(title = paste(state_name, "Marker Expression"))
}
tnaive_plot <- plot_markers_grid(c("CCR7","SELL","LEF1","TCF7","IL7R","CD27", "NOSIP", "FOXO1", "KLF2", "LDHB"), "Tnaive")
tcm_plot <- plot_markers_grid(c("CCR7","SELL","IL7R","CD27", "ANXA1", "S100A4", "ITGB1", "AIM2"), "Tcm")
tem_plot <- plot_markers_grid(c("CXCR3","GZMK","PRF1", "CCL5", "CCR5"), "Tem")
temra_plot <- plot_markers_grid(c("GZMB","GZMH","PRF1","KLRG1","CX3CR1", "GNLY", "FGFBP2"), "Temra")
tex_plot <- plot_markers_grid(c("PDCD1","CTLA4","LAG3","TIGIT","TOX"), "Tex")
cd4ctl_plot <- plot_markers_grid(c("GZMB","PRF1","NKG7","KLRG1", "CRTAM"), "CD4 CTL")
cd4Treg_plot <- plot_markers_grid(c("FOXP3","IKZF2","CTLA4","TIGIT", "IL2RA"), "CD4 TREG")
tnaive_plot; tcm_plot; tem_plot; temra_plot;cd4Treg_plot; tex_plot; cd4ctl_plot







ADT Feature
Overview
DefaultAssay(reference_integrated) <- "ADT"
tnaive_adt <- c("CD45RA-TotalC","CD197-TotalC","CD127-TotalC")
tcm_adt <- c("CD45RO-TotalC","CD197-TotalC","CD127-TotalC")
tem_adt <- c("CD45RO-TotalC")
temra_adt <- c("CD45RA-TotalC","PD-1-TotalC","TIGIT-TotalC","HLA-DR-TotalC")
treg_adt <- c("CD25-TotalC","CD127-TotalC","CD45RA-TotalC")
plot_markers_grid_ADT <- function(marker_vector, state_name) {
avail <- intersect(marker_vector, rownames(reference_integrated[["ADT"]]))
if (length(avail) == 0) { cat("No ADT markers found for", state_name, "\n"); return(NULL) }
plots <- lapply(avail, function(prot) {
FeaturePlot(reference_integrated, features = prot, reduction = "umap",label = T,
cols = c("lightblue","red")) + ggtitle(prot)
})
wrap_plots(plots) + plot_annotation(title = paste(state_name, "ADT"))
}
plot_markers_grid_ADT(tnaive_adt, "Tnaive")

plot_markers_grid_ADT(tcm_adt, "Tcm")

plot_markers_grid_ADT(temra_adt, "Temra/CD4CTL")

plot_markers_grid_ADT(treg_adt, "Treg")

ADT Gating —
CD4T_10x_S1
DefaultAssay(reference_integrated) <- "ADT"
s1 <- subset(reference_integrated, subset = dataset == "CD4T_10x_S1")
# FIX 8: auto-detect the data layer name rather than hardcoding
s1_data_layer <- grep("^data", names(Layers(s1[["ADT"]])), value = TRUE)[1]
cat("S1 ADT data layer:", s1_data_layer, "\n")
S1 ADT data layer: NA
adt_s1 <- as.matrix(LayerData(s1[["ADT"]], layer = s1_data_layer))
# FIX 4: Standardize protein names after stripping -TotalC
rownames(adt_s1) <- gsub("-TotalC", "", rownames(adt_s1))
rownames(adt_s1) <- gsub("^CD197$", "CCR7", rownames(adt_s1)) # CD197 → CCR7
rownames(adt_s1) <- gsub("^PD-1$", "PD1", rownames(adt_s1)) # PD-1 → PD1
rownames(adt_s1) <- gsub("^HLA-DR$","HLADR", rownames(adt_s1)) # HLA-DR→ HLADR
adt_z_s1 <- t(scale(t(adt_s1)))
adt_z_s1[is.nan(adt_z_s1)] <- 0
# FIX 4: Now use standardized names
CD45RA_hi <- is_hi("CD45RA", adt_z_s1)
CD45RO_hi <- is_hi("CD45RO", adt_z_s1)
CCR7_hi <- is_hi("CCR7", adt_z_s1) # was CD197 — now renamed above
CD127_hi <- is_hi("CD127", adt_z_s1)
CD25_hi <- is_hi("CD25", adt_z_s1)
PD1_hi <- is_hi("PD1", adt_z_s1) # was PD-1 — now renamed above
TIGIT_hi <- is_hi("TIGIT", adt_z_s1)
HLADR_hi <- is_hi("HLADR", adt_z_s1) # was HLA-DR — now renamed above
state_s1 <- rep("Other", ncol(adt_s1))
state_s1[CD25_hi & !CD127_hi] <- "Treg_ADT"
state_s1[CD45RA_hi & CCR7_hi & CD127_hi & !CD45RO_hi & !PD1_hi & !TIGIT_hi & state_s1=="Other"] <- "Tnaive_ADT"
state_s1[CD45RO_hi & CCR7_hi & !CD45RA_hi & state_s1=="Other"] <- "Tcm_ADT"
state_s1[CD45RO_hi & !CCR7_hi & !CD45RA_hi & state_s1=="Other"] <- "Tem_ADT"
state_s1[CD45RA_hi & !CCR7_hi & (PD1_hi | TIGIT_hi | HLADR_hi) & state_s1=="Other"] <- "Temra_CTL_ADT"
# FIX 6: Assign back to the full object using colnames(s1)
reference_integrated$ADT_state_s1 <- NA_character_
reference_integrated$ADT_state_s1[colnames(s1)] <- state_s1
cat("ADT gating - S1:\n"); print(table(state_s1))
ADT gating - S1:
state_s1
Other Tcm_ADT Tem_ADT Temra_CTL_ADT Tnaive_ADT Treg_ADT
2429 31 655 13 14 246
ADT Gating —
CD4T_lab
DefaultAssay(reference_integrated) <- "ADT"
lab <- subset(reference_integrated, subset = dataset == "CD4T_lab")
# FIX 10: Removed adt_lab_raw block — it was never defined
# FIX 8: Auto-detect lab ADT data layer
lab_data_layer <- grep("^data", names(Layers(lab[["ADT"]])), value = TRUE)[1]
cat("Lab ADT data layer:", lab_data_layer, "\n")
Lab ADT data layer: NA
if (is.na(lab_data_layer)) {
cat("⚠️ No data layer for lab ADT — run NormalizeData first\n")
DefaultAssay(reference_integrated) <- "ADT"
reference_integrated <- NormalizeData(reference_integrated, normalization.method = "CLR", margin = 2)
lab <- subset(reference_integrated, subset = dataset == "CD4T_lab")
lab_data_layer <- grep("^data", names(Layers(lab[["ADT"]])), value = TRUE)[1]
}
⚠️ No data layer for lab ADT — run NormalizeData first
| | 0 % ~calculating
|+ | 1 % ~00s
|+ | 2 % ~00s
|++ | 3 % ~00s
|++ | 4 % ~00s
|+++ | 5 % ~00s
|+++ | 6 % ~00s
|++++ | 7 % ~00s
|++++ | 8 % ~00s
|+++++ | 9 % ~00s
|+++++ | 10% ~00s
|++++++ | 11% ~00s
|++++++ | 12% ~00s
|+++++++ | 13% ~00s
|+++++++ | 14% ~00s
|++++++++ | 15% ~00s
|++++++++ | 16% ~00s
|+++++++++ | 17% ~00s
|+++++++++ | 18% ~00s
|++++++++++ | 19% ~00s
|++++++++++ | 20% ~00s
|+++++++++++ | 21% ~00s
|+++++++++++ | 22% ~00s
|++++++++++++ | 23% ~00s
|++++++++++++ | 24% ~00s
|+++++++++++++ | 25% ~00s
|+++++++++++++ | 26% ~00s
|++++++++++++++ | 27% ~00s
|++++++++++++++ | 28% ~00s
|+++++++++++++++ | 29% ~00s
|+++++++++++++++ | 30% ~00s
|++++++++++++++++ | 31% ~00s
|++++++++++++++++ | 32% ~00s
|+++++++++++++++++ | 33% ~00s
|+++++++++++++++++ | 34% ~00s
|++++++++++++++++++ | 35% ~00s
|++++++++++++++++++ | 36% ~00s
|+++++++++++++++++++ | 37% ~00s
|+++++++++++++++++++ | 38% ~00s
|++++++++++++++++++++ | 39% ~00s
|++++++++++++++++++++ | 40% ~00s
|+++++++++++++++++++++ | 41% ~00s
|+++++++++++++++++++++ | 42% ~00s
|++++++++++++++++++++++ | 43% ~00s
|++++++++++++++++++++++ | 44% ~00s
|+++++++++++++++++++++++ | 45% ~00s
|+++++++++++++++++++++++ | 46% ~00s
|++++++++++++++++++++++++ | 47% ~00s
|++++++++++++++++++++++++ | 48% ~00s
|+++++++++++++++++++++++++ | 49% ~00s
|+++++++++++++++++++++++++ | 50% ~00s
|++++++++++++++++++++++++++ | 51% ~00s
|++++++++++++++++++++++++++ | 52% ~00s
|+++++++++++++++++++++++++++ | 53% ~00s
|+++++++++++++++++++++++++++ | 54% ~00s
|++++++++++++++++++++++++++++ | 55% ~00s
|++++++++++++++++++++++++++++ | 56% ~00s
|+++++++++++++++++++++++++++++ | 57% ~00s
|+++++++++++++++++++++++++++++ | 58% ~00s
|++++++++++++++++++++++++++++++ | 59% ~00s
|++++++++++++++++++++++++++++++ | 60% ~00s
|+++++++++++++++++++++++++++++++ | 61% ~00s
|+++++++++++++++++++++++++++++++ | 62% ~00s
|++++++++++++++++++++++++++++++++ | 63% ~00s
|++++++++++++++++++++++++++++++++ | 64% ~00s
|+++++++++++++++++++++++++++++++++ | 65% ~00s
|+++++++++++++++++++++++++++++++++ | 66% ~00s
|++++++++++++++++++++++++++++++++++ | 67% ~00s
|++++++++++++++++++++++++++++++++++ | 68% ~00s
|+++++++++++++++++++++++++++++++++++ | 69% ~00s
|+++++++++++++++++++++++++++++++++++ | 70% ~00s
|++++++++++++++++++++++++++++++++++++ | 71% ~00s
|++++++++++++++++++++++++++++++++++++ | 72% ~00s
|+++++++++++++++++++++++++++++++++++++ | 73% ~00s
|+++++++++++++++++++++++++++++++++++++ | 74% ~00s
|++++++++++++++++++++++++++++++++++++++ | 75% ~00s
|++++++++++++++++++++++++++++++++++++++ | 76% ~00s
|+++++++++++++++++++++++++++++++++++++++ | 77% ~00s
|+++++++++++++++++++++++++++++++++++++++ | 78% ~00s
|++++++++++++++++++++++++++++++++++++++++ | 79% ~00s
|++++++++++++++++++++++++++++++++++++++++ | 80% ~00s
|+++++++++++++++++++++++++++++++++++++++++ | 81% ~00s
|+++++++++++++++++++++++++++++++++++++++++ | 82% ~00s
|++++++++++++++++++++++++++++++++++++++++++ | 83% ~00s
|++++++++++++++++++++++++++++++++++++++++++ | 84% ~00s
|+++++++++++++++++++++++++++++++++++++++++++ | 85% ~00s
|+++++++++++++++++++++++++++++++++++++++++++ | 86% ~00s
|++++++++++++++++++++++++++++++++++++++++++++ | 87% ~00s
|++++++++++++++++++++++++++++++++++++++++++++ | 88% ~00s
|+++++++++++++++++++++++++++++++++++++++++++++ | 89% ~00s
|+++++++++++++++++++++++++++++++++++++++++++++ | 90% ~00s
|++++++++++++++++++++++++++++++++++++++++++++++ | 91% ~00s
|++++++++++++++++++++++++++++++++++++++++++++++ | 92% ~00s
|+++++++++++++++++++++++++++++++++++++++++++++++ | 93% ~00s
|+++++++++++++++++++++++++++++++++++++++++++++++ | 94% ~00s
|++++++++++++++++++++++++++++++++++++++++++++++++ | 95% ~00s
|++++++++++++++++++++++++++++++++++++++++++++++++ | 96% ~00s
|+++++++++++++++++++++++++++++++++++++++++++++++++ | 97% ~00s
|+++++++++++++++++++++++++++++++++++++++++++++++++ | 98% ~00s
|++++++++++++++++++++++++++++++++++++++++++++++++++| 99% ~00s
|++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=00s
| | 0 % ~calculating
|+ | 1 % ~00s
|++ | 2 % ~00s
|++ | 3 % ~00s
|+++ | 4 % ~00s
|+++ | 5 % ~00s
|++++ | 6 % ~00s
|++++ | 7 % ~00s
|+++++ | 8 % ~00s
|+++++ | 9 % ~00s
|++++++ | 10% ~00s
|++++++ | 11% ~00s
|+++++++ | 12% ~00s
|+++++++ | 13% ~00s
|++++++++ | 14% ~00s
|++++++++ | 15% ~00s
|+++++++++ | 16% ~00s
|+++++++++ | 17% ~00s
|++++++++++ | 18% ~00s
|++++++++++ | 19% ~00s
|+++++++++++ | 20% ~00s
|+++++++++++ | 21% ~00s
|++++++++++++ | 22% ~00s
|++++++++++++ | 23% ~00s
|+++++++++++++ | 24% ~00s
|+++++++++++++ | 26% ~00s
|++++++++++++++ | 27% ~00s
|++++++++++++++ | 28% ~00s
|+++++++++++++++ | 29% ~00s
|+++++++++++++++ | 30% ~00s
|++++++++++++++++ | 31% ~00s
|++++++++++++++++ | 32% ~00s
|+++++++++++++++++ | 33% ~00s
|+++++++++++++++++ | 34% ~00s
|++++++++++++++++++ | 35% ~00s
|++++++++++++++++++ | 36% ~00s
|+++++++++++++++++++ | 37% ~00s
|+++++++++++++++++++ | 38% ~00s
|++++++++++++++++++++ | 39% ~00s
|++++++++++++++++++++ | 40% ~00s
|+++++++++++++++++++++ | 41% ~00s
|+++++++++++++++++++++ | 42% ~00s
|++++++++++++++++++++++ | 43% ~00s
|++++++++++++++++++++++ | 44% ~00s
|+++++++++++++++++++++++ | 45% ~00s
|+++++++++++++++++++++++ | 46% ~00s
|++++++++++++++++++++++++ | 47% ~00s
|++++++++++++++++++++++++ | 48% ~00s
|+++++++++++++++++++++++++ | 49% ~00s
|+++++++++++++++++++++++++ | 50% ~00s
|++++++++++++++++++++++++++ | 51% ~00s
|+++++++++++++++++++++++++++ | 52% ~00s
|+++++++++++++++++++++++++++ | 53% ~00s
|++++++++++++++++++++++++++++ | 54% ~00s
|++++++++++++++++++++++++++++ | 55% ~00s
|+++++++++++++++++++++++++++++ | 56% ~00s
|+++++++++++++++++++++++++++++ | 57% ~00s
|++++++++++++++++++++++++++++++ | 58% ~00s
|++++++++++++++++++++++++++++++ | 59% ~00s
|+++++++++++++++++++++++++++++++ | 60% ~00s
|+++++++++++++++++++++++++++++++ | 61% ~00s
|++++++++++++++++++++++++++++++++ | 62% ~00s
|++++++++++++++++++++++++++++++++ | 63% ~00s
|+++++++++++++++++++++++++++++++++ | 64% ~00s
|+++++++++++++++++++++++++++++++++ | 65% ~00s
|++++++++++++++++++++++++++++++++++ | 66% ~00s
|++++++++++++++++++++++++++++++++++ | 67% ~00s
|+++++++++++++++++++++++++++++++++++ | 68% ~00s
|+++++++++++++++++++++++++++++++++++ | 69% ~00s
|++++++++++++++++++++++++++++++++++++ | 70% ~00s
|++++++++++++++++++++++++++++++++++++ | 71% ~00s
|+++++++++++++++++++++++++++++++++++++ | 72% ~00s
|+++++++++++++++++++++++++++++++++++++ | 73% ~00s
|++++++++++++++++++++++++++++++++++++++ | 74% ~00s
|++++++++++++++++++++++++++++++++++++++ | 76% ~00s
|+++++++++++++++++++++++++++++++++++++++ | 77% ~00s
|+++++++++++++++++++++++++++++++++++++++ | 78% ~00s
|++++++++++++++++++++++++++++++++++++++++ | 79% ~00s
|++++++++++++++++++++++++++++++++++++++++ | 80% ~00s
|+++++++++++++++++++++++++++++++++++++++++ | 81% ~00s
|+++++++++++++++++++++++++++++++++++++++++ | 82% ~00s
|++++++++++++++++++++++++++++++++++++++++++ | 83% ~00s
|++++++++++++++++++++++++++++++++++++++++++ | 84% ~00s
|+++++++++++++++++++++++++++++++++++++++++++ | 85% ~00s
|+++++++++++++++++++++++++++++++++++++++++++ | 86% ~00s
|++++++++++++++++++++++++++++++++++++++++++++ | 87% ~00s
|++++++++++++++++++++++++++++++++++++++++++++ | 88% ~00s
|+++++++++++++++++++++++++++++++++++++++++++++ | 89% ~00s
|+++++++++++++++++++++++++++++++++++++++++++++ | 90% ~00s
|++++++++++++++++++++++++++++++++++++++++++++++ | 91% ~00s
|++++++++++++++++++++++++++++++++++++++++++++++ | 92% ~00s
|+++++++++++++++++++++++++++++++++++++++++++++++ | 93% ~00s
|+++++++++++++++++++++++++++++++++++++++++++++++ | 94% ~00s
|++++++++++++++++++++++++++++++++++++++++++++++++ | 95% ~00s
|++++++++++++++++++++++++++++++++++++++++++++++++ | 96% ~00s
|+++++++++++++++++++++++++++++++++++++++++++++++++ | 97% ~00s
|+++++++++++++++++++++++++++++++++++++++++++++++++ | 98% ~00s
|++++++++++++++++++++++++++++++++++++++++++++++++++| 99% ~00s
|++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=00s
| | 0 % ~calculating
|+ | 1 % ~00s
|+ | 2 % ~00s
|++ | 3 % ~00s
|++ | 4 % ~00s
|+++ | 5 % ~00s
|+++ | 6 % ~00s
|++++ | 7 % ~00s
|++++ | 8 % ~00s
|+++++ | 9 % ~00s
|+++++ | 10% ~00s
|++++++ | 11% ~00s
|++++++ | 12% ~00s
|+++++++ | 13% ~00s
|+++++++ | 14% ~00s
|++++++++ | 15% ~00s
|++++++++ | 16% ~00s
|+++++++++ | 17% ~00s
|+++++++++ | 18% ~00s
|++++++++++ | 19% ~00s
|++++++++++ | 20% ~00s
|+++++++++++ | 21% ~00s
|+++++++++++ | 22% ~00s
|++++++++++++ | 23% ~00s
|++++++++++++ | 24% ~00s
|+++++++++++++ | 25% ~00s
|+++++++++++++ | 26% ~00s
|++++++++++++++ | 27% ~00s
|++++++++++++++ | 28% ~00s
|+++++++++++++++ | 29% ~00s
|+++++++++++++++ | 30% ~00s
|++++++++++++++++ | 31% ~00s
|++++++++++++++++ | 32% ~00s
|+++++++++++++++++ | 33% ~00s
|+++++++++++++++++ | 34% ~00s
|++++++++++++++++++ | 35% ~00s
|++++++++++++++++++ | 36% ~00s
|+++++++++++++++++++ | 37% ~00s
|+++++++++++++++++++ | 38% ~00s
|++++++++++++++++++++ | 39% ~00s
|++++++++++++++++++++ | 40% ~00s
|+++++++++++++++++++++ | 41% ~00s
|+++++++++++++++++++++ | 42% ~00s
|++++++++++++++++++++++ | 43% ~00s
|++++++++++++++++++++++ | 44% ~00s
|+++++++++++++++++++++++ | 45% ~00s
|+++++++++++++++++++++++ | 46% ~00s
|++++++++++++++++++++++++ | 47% ~00s
|++++++++++++++++++++++++ | 48% ~00s
|+++++++++++++++++++++++++ | 49% ~00s
|+++++++++++++++++++++++++ | 50% ~00s
|++++++++++++++++++++++++++ | 51% ~00s
|++++++++++++++++++++++++++ | 52% ~00s
|+++++++++++++++++++++++++++ | 53% ~00s
|+++++++++++++++++++++++++++ | 54% ~00s
|++++++++++++++++++++++++++++ | 55% ~00s
|++++++++++++++++++++++++++++ | 56% ~00s
|+++++++++++++++++++++++++++++ | 57% ~00s
|+++++++++++++++++++++++++++++ | 58% ~00s
|++++++++++++++++++++++++++++++ | 59% ~00s
|++++++++++++++++++++++++++++++ | 60% ~00s
|+++++++++++++++++++++++++++++++ | 61% ~00s
|+++++++++++++++++++++++++++++++ | 62% ~00s
|++++++++++++++++++++++++++++++++ | 63% ~00s
|++++++++++++++++++++++++++++++++ | 64% ~00s
|+++++++++++++++++++++++++++++++++ | 65% ~00s
|+++++++++++++++++++++++++++++++++ | 66% ~00s
|++++++++++++++++++++++++++++++++++ | 67% ~00s
|++++++++++++++++++++++++++++++++++ | 68% ~00s
|+++++++++++++++++++++++++++++++++++ | 69% ~00s
|+++++++++++++++++++++++++++++++++++ | 70% ~00s
|++++++++++++++++++++++++++++++++++++ | 71% ~00s
|++++++++++++++++++++++++++++++++++++ | 72% ~00s
|+++++++++++++++++++++++++++++++++++++ | 73% ~00s
|+++++++++++++++++++++++++++++++++++++ | 74% ~00s
|++++++++++++++++++++++++++++++++++++++ | 75% ~00s
|++++++++++++++++++++++++++++++++++++++ | 76% ~00s
|+++++++++++++++++++++++++++++++++++++++ | 77% ~00s
|+++++++++++++++++++++++++++++++++++++++ | 78% ~00s
|++++++++++++++++++++++++++++++++++++++++ | 79% ~00s
|++++++++++++++++++++++++++++++++++++++++ | 80% ~00s
|+++++++++++++++++++++++++++++++++++++++++ | 81% ~00s
|+++++++++++++++++++++++++++++++++++++++++ | 82% ~00s
|++++++++++++++++++++++++++++++++++++++++++ | 83% ~00s
|++++++++++++++++++++++++++++++++++++++++++ | 84% ~00s
|+++++++++++++++++++++++++++++++++++++++++++ | 85% ~00s
|+++++++++++++++++++++++++++++++++++++++++++ | 86% ~00s
|++++++++++++++++++++++++++++++++++++++++++++ | 87% ~00s
|++++++++++++++++++++++++++++++++++++++++++++ | 88% ~00s
|+++++++++++++++++++++++++++++++++++++++++++++ | 89% ~00s
|+++++++++++++++++++++++++++++++++++++++++++++ | 90% ~00s
|++++++++++++++++++++++++++++++++++++++++++++++ | 91% ~00s
|++++++++++++++++++++++++++++++++++++++++++++++ | 92% ~00s
|+++++++++++++++++++++++++++++++++++++++++++++++ | 93% ~00s
|+++++++++++++++++++++++++++++++++++++++++++++++ | 94% ~00s
|++++++++++++++++++++++++++++++++++++++++++++++++ | 95% ~00s
|++++++++++++++++++++++++++++++++++++++++++++++++ | 96% ~00s
|+++++++++++++++++++++++++++++++++++++++++++++++++ | 97% ~00s
|+++++++++++++++++++++++++++++++++++++++++++++++++ | 98% ~00s
|++++++++++++++++++++++++++++++++++++++++++++++++++| 99% ~00s
|++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=00s
adt_lab <- as.matrix(LayerData(lab[["ADT"]], layer = lab_data_layer))
# Lab panel uses names WITHOUT -TotalC suffix, but standardize anyway
rownames(adt_lab) <- gsub("-TotalC", "", rownames(adt_lab))
rownames(adt_lab) <- gsub("^CD197$", "CCR7", rownames(adt_lab))
rownames(adt_lab) <- gsub("^PD-1$", "PD1", rownames(adt_lab))
rownames(adt_lab) <- gsub("^HLA-DR$","HLADR", rownames(adt_lab))
adt_z_lab <- t(scale(t(adt_lab)))
adt_z_lab[is.nan(adt_z_lab)] <- 0
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("HLADR", adt_z_lab)
state_lab <- rep("Other", ncol(adt_lab))
state_lab[CD25_hi_l & !CD127_hi_l] <- "Treg_ADT"
state_lab[CD45RA_hi_l & CCR7_hi_l & CD127_hi_l & !CD45RO_hi_l & !PD1_hi_l & !TIGIT_hi_l & state_lab=="Other"] <- "Tnaive_ADT"
state_lab[CD45RO_hi_l & CCR7_hi_l & !CD45RA_hi_l & state_lab=="Other"] <- "Tcm_ADT"
state_lab[CD45RO_hi_l & !CCR7_hi_l & !CD45RA_hi_l & state_lab=="Other"] <- "Tem_ADT"
state_lab[CD45RA_hi_l & !CCR7_hi_l & (PD1_hi_l|TIGIT_hi_l|HLADR_hi_l) & state_lab=="Other"] <- "Temra_CTL_ADT"
# FIX 7: Assign back to full object for lab cells
reference_integrated$ADT_state_lab <- NA_character_
reference_integrated$ADT_state_lab[colnames(lab)] <- state_lab
cat("ADT gating - Lab:\n"); print(table(state_lab))
ADT gating - Lab:
state_lab
Other Tcm_ADT Tem_ADT Temra_CTL_ADT Tnaive_ADT Treg_ADT
3504 29 1204 36 2 91
Combine S1 + Lab ADT
States (NEW)
# NEW CHUNK: Combine S1 and Lab ADT states into one column
reference_integrated$ADT_state <- coalesce(
reference_integrated$ADT_state_s1,
reference_integrated$ADT_state_lab
) # S2 cells will remain NA — correct
reference_integrated$ADT_state <- factor(reference_integrated$ADT_state,
levels = c("Tnaive_ADT","Tcm_ADT","Tem_ADT","Temra_CTL_ADT","Treg_ADT","Other"))
cat("ADT state coverage:\n")
ADT state coverage:
print(table(reference_integrated$ADT_state, reference_integrated$dataset, useNA = "ifany"))
CD4T_10x_S1 CD4T_10x_S2 CD4T_lab
Tnaive_ADT 14 0 2
Tcm_ADT 31 0 29
Tem_ADT 655 0 1204
Temra_CTL_ADT 13 0 36
Treg_ADT 246 0 91
Other 2429 0 3504
<NA> 0 3228 0
ADT Visualisation on
UMAP
adt_colors <- c("Tnaive_ADT"="#FF6B6B","Tcm_ADT"="#4ECDC4",
"Tem_ADT"="#45B7D1","Temra_CTL_ADT"="#96CEB4",
"Treg_ADT"="#FECA57","Other"="grey80")
p1 <- DimPlot(reference_integrated, group.by = "ADT_state",
cols = adt_colors, pt.size = 0.6, na.value = "grey90") +
ggtitle("ADT states (S1 + Lab) | S2 = grey")
# S1 only
p2 <- DimPlot(subset(reference_integrated, subset = dataset == "CD4T_10x_S1"),
group.by = "ADT_state", cols = adt_colors,
label = TRUE, label.box = TRUE, repel = TRUE) +
ggtitle("S1 ONLY — ADT gating") + NoLegend()
# Lab only
p3 <- DimPlot(subset(reference_integrated, subset = dataset == "CD4T_lab"),
group.by = "ADT_state", cols = adt_colors,
label = TRUE, label.box = TRUE, repel = TRUE) +
ggtitle("Lab ONLY — ADT gating") + NoLegend()
p1 / (p2 | p3)

Assign Per-Cell
Differentiation State from Module Scores
score_cols <- paste0(names(marker_list), "1")
score_mat <- as.data.frame(reference_integrated@meta.data[, score_cols])
state_max_idx <- apply(score_mat, 1, which.max)
state_max_label <- names(marker_list)[state_max_idx]
top_vals <- apply(score_mat, 1, max)
second_vals <- apply(score_mat, 1, function(x) sort(x, decreasing=TRUE)[2])
state_max_label[top_vals - second_vals < 0.05] <- "Mixed"
reference_integrated$diff_state <- factor(state_max_label,
levels = c("Tnaive","Tcm","Tem","Temra","Treg","Tex","CD4CTL","Mixed"))
DimPlot(reference_integrated, group.by = "diff_state", label = TRUE, label.box = TRUE, repel = TRUE) +
ggtitle("Inferred CD4 T-cell differentiation states")

Save annotated
reference
# # Save annotated reference
# saveRDS(reference_integrated, "CD4_reference_annotated_with_ADTmarkers.rds")
# cat("✅ Annotated reference with markers saved!\n")
LS0tCnRpdGxlOiAiVHJhbnNjcmlwdG9taWNzIGFuZCBBRFQgYW5ub3RhdGlvbiIKYXV0aG9yOiBOYXNpciBNYWhtb29kIEFiYmFzaQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiB0cnVlCiAgICB0aGVtZTogam91cm5hbAotLS0KCgojIExvYWQgbGlicmFyaWVzCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQoKa25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gOCkKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkobW9ub2NsZTMpCmxpYnJhcnkoU2V1cmF0V3JhcHBlcnMpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpvcHRpb25zKGZ1dHVyZS5nbG9iYWxzLm1heFNpemUgPSA4ZTkpCnNldC5zZWVkKDEyMykKCiMg4pSA4pSAIERlZmluZSBpc19oaSgpIE9OQ0UgaGVyZSBzbyBpdCBpcyBhdmFpbGFibGUgaW4gQUxMIGRvd25zdHJlYW0gY2h1bmtzIOKUgOKUgAppc19oaSA8LSBmdW5jdGlvbihnLCB6bWF0LCB6ID0gMC41KSB7CiAgaWYgKCFnICVpbiUgcm93bmFtZXMoem1hdCkpIHJldHVybihyZXAoRkFMU0UsIG5jb2woem1hdCkpKQogIHptYXRbZywgXSA+IHoKfQoKaXNfaGlnaCA8LSBpc19oaSAgICMgRklYIDM6IGFsaWFzIHNvIGJvdGggbmFtZXMgd29yayBkb3duc3RyZWFtCmBgYAoKIyBMb2FkIEFubm90YXRlZCBIZWFsdGh5IEludGVncmF0ZWQgT2JqZWN0CmBgYHtyIGxvYWQgb2JqZWN0fQpyZWZlcmVuY2VfaW50ZWdyYXRlZDwtIHJlYWRSRFMoIi4uL0NENF9yZWZlcmVuY2VfYW5ub3RhdGVkX3dpdGhfbWFya2Vycy5yZHMiKQoKRGVmYXVsdEFzc2F5KHJlZmVyZW5jZV9pbnRlZ3JhdGVkKSA8LSAiUk5BIgoKcmVmZXJlbmNlX2ludGVncmF0ZWQKYGBgCgojIyBBemltdXRoIExhYmVsIFZhbGlkYXRpb24KYGBge3IgLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02fQpEaW1QbG90KHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDEiLAogICAgICAgIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBsYWJlbC5zaXplID0gMykgKyBOb0xlZ2VuZCgpCkRpbVBsb3QocmVmZXJlbmNlX2ludGVncmF0ZWQsIGdyb3VwLmJ5ID0gInByZWRpY3RlZC5jZWxsdHlwZS5sMiIsCiAgICAgICAgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSAzKSArIE5vTGVnZW5kKCkKRGltUGxvdChyZWZlcmVuY2VfaW50ZWdyYXRlZCwgZ3JvdXAuYnkgPSAicHJlZGljdGVkLmNlbGx0eXBlLmwzIiwKICAgICAgICBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgbGFiZWwuc2l6ZSA9IDMpICsgTm9MZWdlbmQoKQoKRGltUGxvdChyZWZlcmVuY2VfaW50ZWdyYXRlZCwgZ3JvdXAuYnkgPSAic2luZ2xlci5ocGNhIiwKICAgICAgICBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgbGFiZWwuc2l6ZSA9IDMpICsgTm9MZWdlbmQoKQoKRGltUGxvdChyZWZlcmVuY2VfaW50ZWdyYXRlZCwgZ3JvdXAuYnkgPSAic2luZ2xlci5pbW11bmUiLAogICAgICAgIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBsYWJlbC5zaXplID0gMykgKyBOb0xlZ2VuZCgpCgpwcmludCh0YWJsZShyZWZlcmVuY2VfaW50ZWdyYXRlZCRwcmVkaWN0ZWQuY2VsbHR5cGUubDEsIHJlZmVyZW5jZV9pbnRlZ3JhdGVkJHNldXJhdF9jbHVzdGVycykpCnByaW50KHRhYmxlKHJlZmVyZW5jZV9pbnRlZ3JhdGVkJHByZWRpY3RlZC5jZWxsdHlwZS5sMiwgcmVmZXJlbmNlX2ludGVncmF0ZWQkc2V1cmF0X2NsdXN0ZXJzKSkKcHJpbnQodGFibGUocmVmZXJlbmNlX2ludGVncmF0ZWQkcHJlZGljdGVkLmNlbGx0eXBlLmwzLCByZWZlcmVuY2VfaW50ZWdyYXRlZCRzZXVyYXRfY2x1c3RlcnMpKQpwcmludCh0YWJsZShyZWZlcmVuY2VfaW50ZWdyYXRlZCRzaW5nbGVyLmhwY2EsIHJlZmVyZW5jZV9pbnRlZ3JhdGVkJHNldXJhdF9jbHVzdGVycykpCnByaW50KHRhYmxlKHJlZmVyZW5jZV9pbnRlZ3JhdGVkJHNpbmdsZXIuaW1tdW5lLCByZWZlcmVuY2VfaW50ZWdyYXRlZCRzZXVyYXRfY2x1c3RlcnMpKQoKYGBgCgoKIyBRdWljayBWaXN1YWwgU3VtbWFyeSBvZiBUb3AgTWFya2VycyhEb3RwbG90KQpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTh9CmxpYnJhcnkoZHBseXIpCgojIOKUgOKUgCBTQ3B1YnIgRG90UGxvdCBmb3IgdG9wIDUgbWFya2VycyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKRGVmYXVsdEFzc2F5KHJlZmVyZW5jZV9pbnRlZ3JhdGVkKSA8LSAiUk5BIgoKIyBHZXQgdG9wIDUgZ2VuZXMgcGVyIGNsdXN0ZXIgKGFscmVhZHkgY29tcHV0ZWQpCnRvcDVfZ2VuZXMgPC0gcmVmZXJlbmNlX2ludGVncmF0ZWRAbWlzYyRtYXJrZXJzX3RvcDUgJT4lCiAgZHBseXI6Omdyb3VwX2J5KGNsdXN0ZXIpICU+JQogIGRwbHlyOjpzbGljZV9oZWFkKG4gPSA1KSAlPiUKICBkcGx5cjo6cHVsbChnZW5lKSAlPiUKICB1bmlxdWUoKQoKIyDilIDilIAgU0NwdWJyIHYxLngg4oCUIG1pbmltYWwgd29ya2luZyBzeW50YXgg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACgpTQ3B1YnI6OmRvX0RvdFBsb3Qoc2FtcGxlID0gcmVmZXJlbmNlX2ludGVncmF0ZWQsIAogICAgICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSB0b3A1X2dlbmVzLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGZsaXAgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgKQoKYGBgCgoKIyBGZWF0dXJlUGxvdCB0byBjaGVjayBURU1SQQpgYGB7ciwgZmlnLndpZHRoPTE0LCBmaWcuaGVpZ2h0PTEyfQpGZWF0dXJlUGxvdCgKICBvYmplY3QgPSByZWZlcmVuY2VfaW50ZWdyYXRlZCwKICBmZWF0dXJlcyA9IGMoIlBSRjEiLCAiTktHNyIsICJGR0ZCUDIiLCAiR05MWSIpLAogIGNvbHMgPSBjKCJsaWdodGdyZXkiLCAicmVkIiksbGFiZWwgPSBULAogIG5jb2wgPSAyCikKCmBgYCAKCiMgVEFCTEUgUG9zdC1Bbm5vdGF0aW9uCmBgYHtyLCBmaWcud2lkdGg9MTQsIGZpZy5oZWlnaHQ9NX0KdGFibGUocmVmZXJlbmNlX2ludGVncmF0ZWQkcHJlZGljdGVkLmNlbGx0eXBlLmwyLCByZWZlcmVuY2VfaW50ZWdyYXRlZEBtZXRhLmRhdGEkY2VsbF90eXBlKQoKYGBgCgojIERpbVBsb3RzIFBvc3QtQW5ub3RhdGlvbgpgYGB7ciBkaW1wbG90cy1hbm5vdGF0ZWQsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD02fQojIEZJWCAxOiBjaHVuayBsYWJlbCByZW5hbWVkIGZyb20gJ21hcmtlcnNzY29yZScg4oCUIHdhcyBkdXBsaWNhdGUKRGltUGxvdChyZWZlcmVuY2VfaW50ZWdyYXRlZCwgZ3JvdXAuYnkgPSAic2V1cmF0X2NsdXN0ZXJzIiwgbGFiZWwgPSBUUlVFLCBsYWJlbC5ib3ggPSBUUlVFLApyZXBlbCA9IFRSVUUpICsgZ2d0aXRsZSgiQ2x1c3RlcnMgMC02IikKRGltUGxvdChyZWZlcmVuY2VfaW50ZWdyYXRlZCwgZ3JvdXAuYnkgPSAiY2VsbF90eXBlIiwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGxhYmVsLmJveCA9ClRSVUUpICsgZ2d0aXRsZSgiQ2VsbCBUeXBlcyIpCmBgYAoKIyBNYXJrZXIgTW9kdWxlIFNjb3JlcyAoRGlmZmVyZW50aWF0aW9uIFN0YXRlcykKYGBge3IgbW9kdWxlLXNjb3JlcywgZmlnLndpZHRoPTE4LCBmaWcuaGVpZ2h0PTh9CkRlZmF1bHRBc3NheShyZWZlcmVuY2VfaW50ZWdyYXRlZCkgPC0gIlJOQSIKbWFya2VyX2xpc3QgPC0gbGlzdCgKVG5haXZlID0gYygiQ0NSNyIsIlNFTEwiLCJMRUYxIiwiVENGNyIsIklMN1IiLCJDRDI3IiwiUFRQUkMiKSwKVGNtCj0gYygiQ0NSNyIsIlNFTEwiLCJDRDI3IiwiSUw3UiIsIkJDTDIiLCJUQ0Y3IiksClRlbQo9IGMoIkNDUjYiLCJDWENSMyIsIkdaTUsiLCJQUkYxIiwiSUZORyIpLApUZW1yYSA9IGMoIkdaTUIiLCJQUkYxIiwiS0xSRzEiLCJDWDNDUjEiKSwKVHJlZwo9IGMoIkZPWFAzIiwiSUwyUkEiLCJDVExBNCIsIklLWkYyIiksClRleAo9IGMoIlBEQ0QxIiwiQ1RMQTQiLCJMQUczIiwiVElHSVQiLCJUT1giLCJFTlRQRDEiKSwKQ0Q0Q1RMID0gYygiR1pNQiIsIlBSRjEiLCJOS0c3IiwiS0xSRzEiLCJDWDNDUjEiKQopCm1hcmtlcl9saXN0IDwtIGxhcHBseShtYXJrZXJfbGlzdCwgZnVuY3Rpb24oeCkgaW50ZXJzZWN0KHgsIHJvd25hbWVzKHJlZmVyZW5jZV9pbnRlZ3JhdGVkKSkpCm1hcmtlcl9saXN0IDwtIG1hcmtlcl9saXN0W3ZhcHBseShtYXJrZXJfbGlzdCwgbGVuZ3RoLCAxTCkgPiAwXQpmb3IgKHN0YXRlIGluIG5hbWVzKG1hcmtlcl9saXN0KSkgewpyZWZlcmVuY2VfaW50ZWdyYXRlZCA8LSBBZGRNb2R1bGVTY29yZShyZWZlcmVuY2VfaW50ZWdyYXRlZCwgZmVhdHVyZXMgPQpsaXN0KG1hcmtlcl9saXN0W1tzdGF0ZV1dKSwgbmFtZSA9IHN0YXRlKQp9CnNjb3JlX2ZlYXR1cmVzIDwtIHBhc3RlMChuYW1lcyhtYXJrZXJfbGlzdCksICIxIikKRmVhdHVyZVBsb3QocmVmZXJlbmNlX2ludGVncmF0ZWQsIGZlYXR1cmVzID0gc2NvcmVfZmVhdHVyZXMsIG5jb2wgPSA0LApjb2xzID0gYygibGlnaHRibHVlIiwicmVkIiksIGxhYmVsID0gVFJVRSwgbWF4LmN1dG9mZiA9ICJxOTUiKSArCnBsb3RfYW5ub3RhdGlvbih0aXRsZSA9ICJEaWZmZXJlbnRpYXRpb24gU3RhdGUgTW9kdWxlIFNjb3JlcyIpCgpgYGAKCiMgVHJlZyBTdWJzZXQgVmFsaWRhdGlvbiAoQ1RMQTQvVElHSVQpCmBgYHtyIHRyZWctdmFsaWRhdGlvbiwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Nn0KCiMgU2V0IGFzc2F5IGFuZCBleHRyYWN0IGV4cHJlc3Npb24KRGVmYXVsdEFzc2F5KHJlZmVyZW5jZV9pbnRlZ3JhdGVkKSA8LSAiUk5BIgoKIyBFeHRyYWN0IENUTEE0IGFuZCBUSUdJVCBleHByZXNzaW9uIChsb2ctbm9ybWFsaXplZCBkYXRhKQpjdGxhNF9leHByIDwtIEdldEFzc2F5RGF0YShyZWZlcmVuY2VfaW50ZWdyYXRlZCwgYXNzYXkgPSAiUk5BIiwgbGF5ZXIgPSAiZGF0YSIpWyJDVExBNCIsIF0KdGlnaXRfZXhwciA8LSBHZXRBc3NheURhdGEocmVmZXJlbmNlX2ludGVncmF0ZWQsIGFzc2F5ID0gIlJOQSIsIGxheWVyID0gImRhdGEiKVsiVElHSVQiLCBdCgpyZWZlcmVuY2VfaW50ZWdyYXRlZCR0cmVnX3N1YnNldCA8LSBpZmVsc2UoCnJlZmVyZW5jZV9pbnRlZ3JhdGVkJHNldXJhdF9jbHVzdGVycyA9PSAiNSIsCmlmZWxzZShjdGxhNF9leHByID4gMCAmIHRpZ2l0X2V4cHIgPiAwLCAiVHJlZyBlZmZlY3RvciIsICJUcmVnIHJlc3RpbmciKSwKIm5vbi1UcmVnIgopCgpEaW1QbG90KHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCBncm91cC5ieSA9ICJ0cmVnX3N1YnNldCIsIGxhYmVsID0gVFJVRSkgKwpnZ3RpdGxlKCJDbHVzdGVyIDUgVHJlZyBoZXRlcm9nZW5laXR5IGJ5IENUTEE0L1RJR0lUIikKCmBgYAoKCiMgRmVhdHVyZVBsb3RzIHBlciBEaWZmZXJlbnRpYXRpb24gU3RhdGUKYGBge3IgLCBmaWcud2lkdGg9MTQsIGZpZy5oZWlnaHQ9OH0KCkRlZmF1bHRBc3NheShyZWZlcmVuY2VfaW50ZWdyYXRlZCkgPC0gIlJOQSIKcGxvdF9tYXJrZXJzX2dyaWQgPC0gZnVuY3Rpb24obWFya2VyX3ZlY3Rvciwgc3RhdGVfbmFtZSkgewptYXJrZXJzX3ByZXNlbnQgPC0gaW50ZXJzZWN0KG1hcmtlcl92ZWN0b3IsIHJvd25hbWVzKHJlZmVyZW5jZV9pbnRlZ3JhdGVkKSkKcGxvdHMgPC0gbGFwcGx5KG1hcmtlcnNfcHJlc2VudCwgZnVuY3Rpb24oZ2VuZSkgewpGZWF0dXJlUGxvdChyZWZlcmVuY2VfaW50ZWdyYXRlZCwgZmVhdHVyZXMgPSBnZW5lLCByZWR1Y3Rpb24gPSAidW1hcCIsCmNvbHMgPSBjKCJsaWdodGJsdWUiLCAicmVkIiksIGxhYmVsID0gVFJVRSkKfSkKCndyYXBfcGxvdHMocGxvdHMpICsgcGxvdF9hbm5vdGF0aW9uKHRpdGxlID0gcGFzdGUoc3RhdGVfbmFtZSwgIk1hcmtlciBFeHByZXNzaW9uIikpCn0KCnRuYWl2ZV9wbG90IDwtIHBsb3RfbWFya2Vyc19ncmlkKGMoIkNDUjciLCJTRUxMIiwiTEVGMSIsIlRDRjciLCJJTDdSIiwiQ0QyNyIsICJOT1NJUCIsICJGT1hPMSIsICJLTEYyIiwgIkxESEIiKSwgIlRuYWl2ZSIpCnRjbV9wbG90IDwtIHBsb3RfbWFya2Vyc19ncmlkKGMoIkNDUjciLCJTRUxMIiwiSUw3UiIsIkNEMjciLCAiQU5YQTEiLCAiUzEwMEE0IiwgIklUR0IxIiwgIkFJTTIiKSwgIlRjbSIpCnRlbV9wbG90IDwtIHBsb3RfbWFya2Vyc19ncmlkKGMoIkNYQ1IzIiwiR1pNSyIsIlBSRjEiLCAiQ0NMNSIsICAiQ0NSNSIpLCAiVGVtIikKdGVtcmFfcGxvdCA8LSBwbG90X21hcmtlcnNfZ3JpZChjKCJHWk1CIiwiR1pNSCIsIlBSRjEiLCJLTFJHMSIsIkNYM0NSMSIsICJHTkxZIiwgIkZHRkJQMiIpLCAiVGVtcmEiKQp0ZXhfcGxvdCA8LSBwbG90X21hcmtlcnNfZ3JpZChjKCJQRENEMSIsIkNUTEE0IiwiTEFHMyIsIlRJR0lUIiwiVE9YIiksICJUZXgiKQpjZDRjdGxfcGxvdCA8LSBwbG90X21hcmtlcnNfZ3JpZChjKCJHWk1CIiwiUFJGMSIsIk5LRzciLCJLTFJHMSIsICJDUlRBTSIpLCAiQ0Q0IENUTCIpCmNkNFRyZWdfcGxvdCA8LSBwbG90X21hcmtlcnNfZ3JpZChjKCJGT1hQMyIsIklLWkYyIiwiQ1RMQTQiLCJUSUdJVCIsICJJTDJSQSIpLCAiQ0Q0IFRSRUciKQoKdG5haXZlX3Bsb3Q7IHRjbV9wbG90OyB0ZW1fcGxvdDsgdGVtcmFfcGxvdDtjZDRUcmVnX3Bsb3Q7IHRleF9wbG90OyBjZDRjdGxfcGxvdAoKYGBgCgojIEFEVCBGZWF0dXJlIE92ZXJ2aWV3CmBgYHtyLCBmaWcud2lkdGg9MTgsIGZpZy5oZWlnaHQ9Nn0KCkRlZmF1bHRBc3NheShyZWZlcmVuY2VfaW50ZWdyYXRlZCkgPC0gIkFEVCIKCnRuYWl2ZV9hZHQgPC0gYygiQ0Q0NVJBLVRvdGFsQyIsIkNEMTk3LVRvdGFsQyIsIkNEMTI3LVRvdGFsQyIpCnRjbV9hZHQgICAgPC0gYygiQ0Q0NVJPLVRvdGFsQyIsIkNEMTk3LVRvdGFsQyIsIkNEMTI3LVRvdGFsQyIpCnRlbV9hZHQgICAgPC0gYygiQ0Q0NVJPLVRvdGFsQyIpCnRlbXJhX2FkdCAgPC0gYygiQ0Q0NVJBLVRvdGFsQyIsIlBELTEtVG90YWxDIiwiVElHSVQtVG90YWxDIiwiSExBLURSLVRvdGFsQyIpCnRyZWdfYWR0ICAgPC0gYygiQ0QyNS1Ub3RhbEMiLCJDRDEyNy1Ub3RhbEMiLCJDRDQ1UkEtVG90YWxDIikKCnBsb3RfbWFya2Vyc19ncmlkX0FEVCA8LSBmdW5jdGlvbihtYXJrZXJfdmVjdG9yLCBzdGF0ZV9uYW1lKSB7CiAgYXZhaWwgPC0gaW50ZXJzZWN0KG1hcmtlcl92ZWN0b3IsIHJvd25hbWVzKHJlZmVyZW5jZV9pbnRlZ3JhdGVkW1siQURUIl1dKSkKICBpZiAobGVuZ3RoKGF2YWlsKSA9PSAwKSB7IGNhdCgiTm8gQURUIG1hcmtlcnMgZm91bmQgZm9yIiwgc3RhdGVfbmFtZSwgIlxuIik7IHJldHVybihOVUxMKSB9CiAgcGxvdHMgPC0gbGFwcGx5KGF2YWlsLCBmdW5jdGlvbihwcm90KSB7CiAgICBGZWF0dXJlUGxvdChyZWZlcmVuY2VfaW50ZWdyYXRlZCwgZmVhdHVyZXMgPSBwcm90LCByZWR1Y3Rpb24gPSAidW1hcCIsbGFiZWwgPSBULAogICAgICAgICAgICAgICAgY29scyA9IGMoImxpZ2h0Ymx1ZSIsInJlZCIpKSArIGdndGl0bGUocHJvdCkKICB9KQogIHdyYXBfcGxvdHMocGxvdHMpICsgcGxvdF9hbm5vdGF0aW9uKHRpdGxlID0gcGFzdGUoc3RhdGVfbmFtZSwgIkFEVCIpKQp9CgpwbG90X21hcmtlcnNfZ3JpZF9BRFQodG5haXZlX2FkdCwgIlRuYWl2ZSIpCnBsb3RfbWFya2Vyc19ncmlkX0FEVCh0Y21fYWR0LCAgICAiVGNtIikKcGxvdF9tYXJrZXJzX2dyaWRfQURUKHRlbXJhX2FkdCwgICJUZW1yYS9DRDRDVEwiKQpwbG90X21hcmtlcnNfZ3JpZF9BRFQodHJlZ19hZHQsICAgIlRyZWciKQoKYGBgCgoKIyBBRFQgR2F0aW5nIOKAlCBDRDRUXzEweF9TMQpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Nn0KCkRlZmF1bHRBc3NheShyZWZlcmVuY2VfaW50ZWdyYXRlZCkgPC0gIkFEVCIKczEgICAgIDwtIHN1YnNldChyZWZlcmVuY2VfaW50ZWdyYXRlZCwgc3Vic2V0ID0gZGF0YXNldCA9PSAiQ0Q0VF8xMHhfUzEiKQoKIyBGSVggODogYXV0by1kZXRlY3QgdGhlIGRhdGEgbGF5ZXIgbmFtZSByYXRoZXIgdGhhbiBoYXJkY29kaW5nCnMxX2RhdGFfbGF5ZXIgPC0gZ3JlcCgiXmRhdGEiLCBuYW1lcyhMYXllcnMoczFbWyJBRFQiXV0pKSwgdmFsdWUgPSBUUlVFKVsxXQpjYXQoIlMxIEFEVCBkYXRhIGxheWVyOiIsIHMxX2RhdGFfbGF5ZXIsICJcbiIpCmFkdF9zMSA8LSBhcy5tYXRyaXgoTGF5ZXJEYXRhKHMxW1siQURUIl1dLCBsYXllciA9IHMxX2RhdGFfbGF5ZXIpKQoKIyBGSVggNDogU3RhbmRhcmRpemUgcHJvdGVpbiBuYW1lcyBhZnRlciBzdHJpcHBpbmcgLVRvdGFsQwpyb3duYW1lcyhhZHRfczEpIDwtIGdzdWIoIi1Ub3RhbEMiLCAiIiwgcm93bmFtZXMoYWR0X3MxKSkKcm93bmFtZXMoYWR0X3MxKSA8LSBnc3ViKCJeQ0QxOTckIiwgIkNDUjciLCAgcm93bmFtZXMoYWR0X3MxKSkgICAjIENEMTk3IOKGkiBDQ1I3CnJvd25hbWVzKGFkdF9zMSkgPC0gZ3N1YigiXlBELTEkIiwgICJQRDEiLCAgIHJvd25hbWVzKGFkdF9zMSkpICAgIyBQRC0xICDihpIgUEQxCnJvd25hbWVzKGFkdF9zMSkgPC0gZ3N1YigiXkhMQS1EUiQiLCJITEFEUiIsIHJvd25hbWVzKGFkdF9zMSkpICAgIyBITEEtRFLihpIgSExBRFIKCmFkdF96X3MxIDwtIHQoc2NhbGUodChhZHRfczEpKSkKYWR0X3pfczFbaXMubmFuKGFkdF96X3MxKV0gPC0gMAoKIyBGSVggNDogTm93IHVzZSBzdGFuZGFyZGl6ZWQgbmFtZXMKQ0Q0NVJBX2hpIDwtIGlzX2hpKCJDRDQ1UkEiLCBhZHRfel9zMSkKQ0Q0NVJPX2hpIDwtIGlzX2hpKCJDRDQ1Uk8iLCBhZHRfel9zMSkKQ0NSN19oaSAgIDwtIGlzX2hpKCJDQ1I3IiwgICBhZHRfel9zMSkgICAjIHdhcyBDRDE5NyDigJQgbm93IHJlbmFtZWQgYWJvdmUKQ0QxMjdfaGkgIDwtIGlzX2hpKCJDRDEyNyIsICBhZHRfel9zMSkKQ0QyNV9oaSAgIDwtIGlzX2hpKCJDRDI1IiwgICBhZHRfel9zMSkKUEQxX2hpICAgIDwtIGlzX2hpKCJQRDEiLCAgICBhZHRfel9zMSkgICAjIHdhcyBQRC0xIOKAlCBub3cgcmVuYW1lZCBhYm92ZQpUSUdJVF9oaSAgPC0gaXNfaGkoIlRJR0lUIiwgIGFkdF96X3MxKQpITEFEUl9oaSAgPC0gaXNfaGkoIkhMQURSIiwgIGFkdF96X3MxKSAgICMgd2FzIEhMQS1EUiDigJQgbm93IHJlbmFtZWQgYWJvdmUKCnN0YXRlX3MxIDwtIHJlcCgiT3RoZXIiLCBuY29sKGFkdF9zMSkpCnN0YXRlX3MxW0NEMjVfaGkgJiAhQ0QxMjdfaGldIDwtICJUcmVnX0FEVCIKc3RhdGVfczFbQ0Q0NVJBX2hpICYgQ0NSN19oaSAmIENEMTI3X2hpICYgIUNENDVST19oaSAmICFQRDFfaGkgJiAhVElHSVRfaGkgJiBzdGF0ZV9zMT09Ik90aGVyIl0gPC0gIlRuYWl2ZV9BRFQiCnN0YXRlX3MxW0NENDVST19oaSAmIENDUjdfaGkgICYgIUNENDVSQV9oaSAmIHN0YXRlX3MxPT0iT3RoZXIiXSA8LSAiVGNtX0FEVCIKc3RhdGVfczFbQ0Q0NVJPX2hpICYgIUNDUjdfaGkgJiAhQ0Q0NVJBX2hpICYgc3RhdGVfczE9PSJPdGhlciJdIDwtICJUZW1fQURUIgpzdGF0ZV9zMVtDRDQ1UkFfaGkgJiAhQ0NSN19oaSAmIChQRDFfaGkgfCBUSUdJVF9oaSB8IEhMQURSX2hpKSAmIHN0YXRlX3MxPT0iT3RoZXIiXSA8LSAiVGVtcmFfQ1RMX0FEVCIKCiMgRklYIDY6IEFzc2lnbiBiYWNrIHRvIHRoZSBmdWxsIG9iamVjdCB1c2luZyBjb2xuYW1lcyhzMSkKcmVmZXJlbmNlX2ludGVncmF0ZWQkQURUX3N0YXRlX3MxIDwtIE5BX2NoYXJhY3Rlcl8KcmVmZXJlbmNlX2ludGVncmF0ZWQkQURUX3N0YXRlX3MxW2NvbG5hbWVzKHMxKV0gPC0gc3RhdGVfczEKCmNhdCgiQURUIGdhdGluZyAtIFMxOlxuIik7IHByaW50KHRhYmxlKHN0YXRlX3MxKSkKCmBgYAoKCgoKIyBBRFQgR2F0aW5nIOKAlCBDRDRUX2xhYgpgYGB7ciAsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTZ9CkRlZmF1bHRBc3NheShyZWZlcmVuY2VfaW50ZWdyYXRlZCkgPC0gIkFEVCIKbGFiIDwtIHN1YnNldChyZWZlcmVuY2VfaW50ZWdyYXRlZCwgc3Vic2V0ID0gZGF0YXNldCA9PSAiQ0Q0VF9sYWIiKQoKIyBGSVggMTA6IFJlbW92ZWQgYWR0X2xhYl9yYXcgYmxvY2sg4oCUIGl0IHdhcyBuZXZlciBkZWZpbmVkCiMgRklYIDg6IEF1dG8tZGV0ZWN0IGxhYiBBRFQgZGF0YSBsYXllcgpsYWJfZGF0YV9sYXllciA8LSBncmVwKCJeZGF0YSIsIG5hbWVzKExheWVycyhsYWJbWyJBRFQiXV0pKSwgdmFsdWUgPSBUUlVFKVsxXQpjYXQoIkxhYiBBRFQgZGF0YSBsYXllcjoiLCBsYWJfZGF0YV9sYXllciwgIlxuIikKCmlmIChpcy5uYShsYWJfZGF0YV9sYXllcikpIHsKICBjYXQoIuKaoO+4jyAgTm8gZGF0YSBsYXllciBmb3IgbGFiIEFEVCDigJQgcnVuIE5vcm1hbGl6ZURhdGEgZmlyc3RcbiIpCiAgRGVmYXVsdEFzc2F5KHJlZmVyZW5jZV9pbnRlZ3JhdGVkKSA8LSAiQURUIgogIHJlZmVyZW5jZV9pbnRlZ3JhdGVkIDwtIE5vcm1hbGl6ZURhdGEocmVmZXJlbmNlX2ludGVncmF0ZWQsIG5vcm1hbGl6YXRpb24ubWV0aG9kID0gIkNMUiIsIG1hcmdpbiA9IDIpCiAgbGFiIDwtIHN1YnNldChyZWZlcmVuY2VfaW50ZWdyYXRlZCwgc3Vic2V0ID0gZGF0YXNldCA9PSAiQ0Q0VF9sYWIiKQogIGxhYl9kYXRhX2xheWVyIDwtIGdyZXAoIl5kYXRhIiwgbmFtZXMoTGF5ZXJzKGxhYltbIkFEVCJdXSkpLCB2YWx1ZSA9IFRSVUUpWzFdCn0KCmFkdF9sYWIgPC0gYXMubWF0cml4KExheWVyRGF0YShsYWJbWyJBRFQiXV0sIGxheWVyID0gbGFiX2RhdGFfbGF5ZXIpKQoKIyBMYWIgcGFuZWwgdXNlcyBuYW1lcyBXSVRIT1VUIC1Ub3RhbEMgc3VmZml4LCBidXQgc3RhbmRhcmRpemUgYW55d2F5CnJvd25hbWVzKGFkdF9sYWIpIDwtIGdzdWIoIi1Ub3RhbEMiLCAiIiwgcm93bmFtZXMoYWR0X2xhYikpCnJvd25hbWVzKGFkdF9sYWIpIDwtIGdzdWIoIl5DRDE5NyQiLCAiQ0NSNyIsICByb3duYW1lcyhhZHRfbGFiKSkKcm93bmFtZXMoYWR0X2xhYikgPC0gZ3N1YigiXlBELTEkIiwgICJQRDEiLCAgIHJvd25hbWVzKGFkdF9sYWIpKQpyb3duYW1lcyhhZHRfbGFiKSA8LSBnc3ViKCJeSExBLURSJCIsIkhMQURSIiwgcm93bmFtZXMoYWR0X2xhYikpCgphZHRfel9sYWIgPC0gdChzY2FsZSh0KGFkdF9sYWIpKSkKYWR0X3pfbGFiW2lzLm5hbihhZHRfel9sYWIpXSA8LSAwCgpDRDQ1UkFfaGlfbCA8LSBpc19oaSgiQ0Q0NVJBIiwgYWR0X3pfbGFiKQpDRDQ1Uk9faGlfbCA8LSBpc19oaSgiQ0Q0NVJPIiwgYWR0X3pfbGFiKQpDQ1I3X2hpX2wgICA8LSBpc19oaSgiQ0NSNyIsICAgYWR0X3pfbGFiKQpDRDEyN19oaV9sICA8LSBpc19oaSgiQ0QxMjciLCAgYWR0X3pfbGFiKQpDRDI1X2hpX2wgICA8LSBpc19oaSgiQ0QyNSIsICAgYWR0X3pfbGFiKQpQRDFfaGlfbCAgICA8LSBpc19oaSgiUEQxIiwgICAgYWR0X3pfbGFiKQpUSUdJVF9oaV9sICA8LSBpc19oaSgiVElHSVQiLCAgYWR0X3pfbGFiKQpITEFEUl9oaV9sICA8LSBpc19oaSgiSExBRFIiLCAgYWR0X3pfbGFiKQoKc3RhdGVfbGFiIDwtIHJlcCgiT3RoZXIiLCBuY29sKGFkdF9sYWIpKQpzdGF0ZV9sYWJbQ0QyNV9oaV9sICYgIUNEMTI3X2hpX2xdICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8LSAiVHJlZ19BRFQiCnN0YXRlX2xhYltDRDQ1UkFfaGlfbCAmIENDUjdfaGlfbCAmIENEMTI3X2hpX2wgJiAhQ0Q0NVJPX2hpX2wgJiAhUEQxX2hpX2wgJiAhVElHSVRfaGlfbCAmIHN0YXRlX2xhYj09Ik90aGVyIl0gPC0gIlRuYWl2ZV9BRFQiCnN0YXRlX2xhYltDRDQ1Uk9faGlfbCAmIENDUjdfaGlfbCAgJiAhQ0Q0NVJBX2hpX2wgJiBzdGF0ZV9sYWI9PSJPdGhlciJdICAgICAgICAgICAgICAgIDwtICJUY21fQURUIgpzdGF0ZV9sYWJbQ0Q0NVJPX2hpX2wgJiAhQ0NSN19oaV9sICYgIUNENDVSQV9oaV9sICYgc3RhdGVfbGFiPT0iT3RoZXIiXSAgICAgICAgICAgICAgIDwtICJUZW1fQURUIgpzdGF0ZV9sYWJbQ0Q0NVJBX2hpX2wgJiAhQ0NSN19oaV9sICYgKFBEMV9oaV9sfFRJR0lUX2hpX2x8SExBRFJfaGlfbCkgJiBzdGF0ZV9sYWI9PSJPdGhlciJdIDwtICJUZW1yYV9DVExfQURUIgoKIyBGSVggNzogQXNzaWduIGJhY2sgdG8gZnVsbCBvYmplY3QgZm9yIGxhYiBjZWxscwpyZWZlcmVuY2VfaW50ZWdyYXRlZCRBRFRfc3RhdGVfbGFiIDwtIE5BX2NoYXJhY3Rlcl8KcmVmZXJlbmNlX2ludGVncmF0ZWQkQURUX3N0YXRlX2xhYltjb2xuYW1lcyhsYWIpXSA8LSBzdGF0ZV9sYWIKCmNhdCgiQURUIGdhdGluZyAtIExhYjpcbiIpOyBwcmludCh0YWJsZShzdGF0ZV9sYWIpKQoKYGBgCgoKIyBDb21iaW5lIFMxICsgTGFiIEFEVCBTdGF0ZXMgKE5FVykKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTZ9CiMgTkVXIENIVU5LOiBDb21iaW5lIFMxIGFuZCBMYWIgQURUIHN0YXRlcyBpbnRvIG9uZSBjb2x1bW4KcmVmZXJlbmNlX2ludGVncmF0ZWQkQURUX3N0YXRlIDwtIGNvYWxlc2NlKAogIHJlZmVyZW5jZV9pbnRlZ3JhdGVkJEFEVF9zdGF0ZV9zMSwKICByZWZlcmVuY2VfaW50ZWdyYXRlZCRBRFRfc3RhdGVfbGFiCikgICAjIFMyIGNlbGxzIHdpbGwgcmVtYWluIE5BIOKAlCBjb3JyZWN0CgpyZWZlcmVuY2VfaW50ZWdyYXRlZCRBRFRfc3RhdGUgPC0gZmFjdG9yKHJlZmVyZW5jZV9pbnRlZ3JhdGVkJEFEVF9zdGF0ZSwKICBsZXZlbHMgPSBjKCJUbmFpdmVfQURUIiwiVGNtX0FEVCIsIlRlbV9BRFQiLCJUZW1yYV9DVExfQURUIiwiVHJlZ19BRFQiLCJPdGhlciIpKQoKY2F0KCJBRFQgc3RhdGUgY292ZXJhZ2U6XG4iKQpwcmludCh0YWJsZShyZWZlcmVuY2VfaW50ZWdyYXRlZCRBRFRfc3RhdGUsIHJlZmVyZW5jZV9pbnRlZ3JhdGVkJGRhdGFzZXQsIHVzZU5BID0gImlmYW55IikpCgoKYGBgCgojIEFEVCBWaXN1YWxpc2F0aW9uIG9uIFVNQVAKYGBge3IgLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTJ9CmFkdF9jb2xvcnMgPC0gYygiVG5haXZlX0FEVCI9IiNGRjZCNkIiLCJUY21fQURUIj0iIzRFQ0RDNCIsCiAgICAgICAgICAgICAgICJUZW1fQURUIj0iIzQ1QjdEMSIsIlRlbXJhX0NUTF9BRFQiPSIjOTZDRUI0IiwKICAgICAgICAgICAgICAgIlRyZWdfQURUIj0iI0ZFQ0E1NyIsIk90aGVyIj0iZ3JleTgwIikKCnAxIDwtIERpbVBsb3QocmVmZXJlbmNlX2ludGVncmF0ZWQsIGdyb3VwLmJ5ID0gIkFEVF9zdGF0ZSIsCiAgICAgICAgICAgICAgY29scyA9IGFkdF9jb2xvcnMsIHB0LnNpemUgPSAwLjYsIG5hLnZhbHVlID0gImdyZXk5MCIpICsKICBnZ3RpdGxlKCJBRFQgc3RhdGVzIChTMSArIExhYikgfCBTMiA9IGdyZXkiKQoKIyBTMSBvbmx5CnAyIDwtIERpbVBsb3Qoc3Vic2V0KHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCBzdWJzZXQgPSBkYXRhc2V0ID09ICJDRDRUXzEweF9TMSIpLAogICAgICAgICAgICAgZ3JvdXAuYnkgPSAiQURUX3N0YXRlIiwgY29scyA9IGFkdF9jb2xvcnMsCiAgICAgICAgICAgICBsYWJlbCA9IFRSVUUsIGxhYmVsLmJveCA9IFRSVUUsIHJlcGVsID0gVFJVRSkgKwogIGdndGl0bGUoIlMxIE9OTFkg4oCUIEFEVCBnYXRpbmciKSArIE5vTGVnZW5kKCkKCiMgTGFiIG9ubHkKcDMgPC0gRGltUGxvdChzdWJzZXQocmVmZXJlbmNlX2ludGVncmF0ZWQsIHN1YnNldCA9IGRhdGFzZXQgPT0gIkNENFRfbGFiIiksCiAgICAgICAgICAgICBncm91cC5ieSA9ICJBRFRfc3RhdGUiLCBjb2xzID0gYWR0X2NvbG9ycywKICAgICAgICAgICAgIGxhYmVsID0gVFJVRSwgbGFiZWwuYm94ID0gVFJVRSwgcmVwZWwgPSBUUlVFKSArCiAgZ2d0aXRsZSgiTGFiIE9OTFkg4oCUIEFEVCBnYXRpbmciKSArIE5vTGVnZW5kKCkKCnAxIC8gKHAyIHwgcDMpCgpgYGAKCgoKIyBBc3NpZ24gUGVyLUNlbGwgRGlmZmVyZW50aWF0aW9uIFN0YXRlIGZyb20gTW9kdWxlIFNjb3JlcwpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Nn0Kc2NvcmVfY29scyA8LSBwYXN0ZTAobmFtZXMobWFya2VyX2xpc3QpLCAiMSIpCnNjb3JlX21hdCAgPC0gYXMuZGF0YS5mcmFtZShyZWZlcmVuY2VfaW50ZWdyYXRlZEBtZXRhLmRhdGFbLCBzY29yZV9jb2xzXSkKCnN0YXRlX21heF9pZHggICA8LSBhcHBseShzY29yZV9tYXQsIDEsIHdoaWNoLm1heCkKc3RhdGVfbWF4X2xhYmVsIDwtIG5hbWVzKG1hcmtlcl9saXN0KVtzdGF0ZV9tYXhfaWR4XQoKdG9wX3ZhbHMgICAgPC0gYXBwbHkoc2NvcmVfbWF0LCAxLCBtYXgpCnNlY29uZF92YWxzIDwtIGFwcGx5KHNjb3JlX21hdCwgMSwgZnVuY3Rpb24oeCkgc29ydCh4LCBkZWNyZWFzaW5nPVRSVUUpWzJdKQpzdGF0ZV9tYXhfbGFiZWxbdG9wX3ZhbHMgLSBzZWNvbmRfdmFscyA8IDAuMDVdIDwtICJNaXhlZCIKCnJlZmVyZW5jZV9pbnRlZ3JhdGVkJGRpZmZfc3RhdGUgPC0gZmFjdG9yKHN0YXRlX21heF9sYWJlbCwKICBsZXZlbHMgPSBjKCJUbmFpdmUiLCJUY20iLCJUZW0iLCJUZW1yYSIsIlRyZWciLCJUZXgiLCJDRDRDVEwiLCJNaXhlZCIpKQoKRGltUGxvdChyZWZlcmVuY2VfaW50ZWdyYXRlZCwgZ3JvdXAuYnkgPSAiZGlmZl9zdGF0ZSIsIGxhYmVsID0gVFJVRSwgbGFiZWwuYm94ID0gVFJVRSwgcmVwZWwgPSBUUlVFKSArCiAgZ2d0aXRsZSgiSW5mZXJyZWQgQ0Q0IFQtY2VsbCBkaWZmZXJlbnRpYXRpb24gc3RhdGVzIikKCmBgYAoKCgojIFNhdmUgYW5ub3RhdGVkIHJlZmVyZW5jZQpgYGB7cn0KIyAjIFNhdmUgYW5ub3RhdGVkIHJlZmVyZW5jZQojIHNhdmVSRFMocmVmZXJlbmNlX2ludGVncmF0ZWQsICJDRDRfcmVmZXJlbmNlX2Fubm90YXRlZF93aXRoX0FEVG1hcmtlcnMucmRzIikKIyBjYXQoIuKchSBBbm5vdGF0ZWQgcmVmZXJlbmNlICB3aXRoIG1hcmtlcnMgc2F2ZWQhXG4iKQoKYGBgIAo=