1 Load libraries

2 Load Annotated Healthy Integrated Object

reference_integrated<- readRDS("../CD4_reference_annotated_with_markers.rds")

DefaultAssay(reference_integrated) <- "RNA"

reference_integrated

2.1 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

3 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,
                         )

4 FeaturePlot to check TEMRA

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

5 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

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

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

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

9 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

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

11 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 

12 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 

13 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

14 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)

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

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