1. load libraries
library(dplyr)
library(ggplot2)
library(Seurat)
library(ComplexHeatmap)
library(presto)
library(tictoc)
library(SCpubr)
library(SeuratData)
library(Azimuth)
library(patchwork)
library(slingshot)
library(SingleCellExperiment)
options(timeout = 300)
set.seed(123)
# Colour palette used throughout — do not change
flow_colours <- c(
"Tnaive" = "#4472C4",
"Tcm" = "#ED7D31",
"Tem" = "#A9D18E",
"Temra" = "#C00000",
"Treg" = "#FFD700"
)
2. Load Seurat
Object
#Load Seurat Object merged from cell lines and a control(PBMC) after filtration
All_samples_Merged <- readRDS("../../CD4_reference_annotated_with_markers.rds")
Run Azmimuth and check
annotation again
library(SeuratData)
library(Azimuth)
options(timeout = 300) # Increase download timeout if needed [web:63]
sample <- All_samples_Merged
rm(All_samples_Merged)
gc()
used (Mb) gc trigger (Mb) max used (Mb)
Ncells 14034042 749.5 25295498 1351.0 21650150 1156.3
Vcells 313545618 2392.2 514272694 3923.6 334874035 2554.9
DefaultAssay(sample) <- "RNA"
sample <- RunAzimuth(sample, reference = "pbmcref")
0% 10 20 30 40 50 60 70 80 90 100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
| | 0 % ~calculating
|++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=05s
Using method 'umap'
0% 10 20 30 40 50 60 70 80 90 100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
0% 10 20 30 40 50 60 70 80 90 100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
0% 10 20 30 40 50 60 70 80 90 100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
0% 10 20 30 40 50 60 70 80 90 100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
DefaultAssay(sample) <- "SCT"
SCpubr::do_DimPlot(
sample = sample,
reduction = "umap",
group.by = "predicted.celltype.l2",
font.size = 18, legend.position = "right",
legend.title = "Cell type (Healthy CD4 T cells)"
)

NA
NA
Clean Object

Rename CD4 CTL → CD4
Temra/CTL
# Rename in metadata
clean_obj$predicted.celltype.l2[clean_obj$predicted.celltype.l2 == "CD4 CTL"] <- "CD4 Temra/CTL"
# Verify
table(clean_obj$predicted.celltype.l2)
CD4 Naive CD4 TCM CD4 TEM CD4 Temra/CTL Treg
2037 9067 145 10 207
Define Logical Order
for Legend
# Define desired order (Naive → TCM → TEM → Temra → Treg)
cell_order <- c("CD4 Naive", "CD4 TCM", "CD4 TEM", "CD4 Temra/CTL", "Treg")
# Set factor levels
clean_obj$predicted.celltype.l2 <- factor(clean_obj$predicted.celltype.l2,
levels = cell_order)
# Verify order
levels(clean_obj$predicted.celltype.l2)
[1] "CD4 Naive" "CD4 TCM" "CD4 TEM" "CD4 Temra/CTL" "Treg"
Publication-Quality
UMAP Plot
library(ggplot2)
p1 <- DimPlot(clean_obj,
group.by = "predicted.celltype.l2",
label = TRUE,
repel = TRUE,
cols = c("CD4 Naive" = "#1f77b4", # Blue
"CD4 TCM" = "#ff7f0e", # Orange
"CD4 TEM" = "#2ca02c", # Green
"CD4 Temra/CTL" = "#d62728", # Red
"Treg" = "#9467bd"), # Purple
pt.size = 0.5) +
guides(color = guide_legend(override.aes = list(size = 4))) +
labs(title = "Healthy CD4 T Cell Reference Atlas",
subtitle = "Quiescent states only | Azimuth L2 annotation") +
theme_void() +
theme(legend.position = "right",
plot.title = element_text(hjust = 0.5, face = "bold", size = 16),
plot.subtitle = element_text(hjust = 0.5, size = 12))
print(p1)

ggsave("healthy_cd4_reference_umap.pdf", p1, width = 10, height = 8, dpi = 300)
# PNG version (for presentations)
ggsave("healthy_cd4_reference_umap.png", p1,
width = 10, height = 8, dpi = 300, bg = "white")
library(ggplot2)
library(Azimuth)
# Run this diagnostic to understand what is happening
DefaultAssay(clean_obj) <- "RNA"
# Check S and G2M scores distribution
p1 <- ggplot(clean_obj@meta.data,
aes(x = S.Score, fill = dataset)) +
geom_histogram(bins = 50, alpha = 0.7, position = "identity") +
geom_vline(xintercept = 0, colour = "red", linetype = "dashed") +
facet_wrap(~dataset, ncol = 1) +
theme_bw() +
labs(title = "S score distribution per dataset",
subtitle = "Healthy resting T-cells should peak below 0")
p2 <- ggplot(clean_obj@meta.data,
aes(x = G2M.Score, fill = dataset)) +
geom_histogram(bins = 50, alpha = 0.7, position = "identity") +
geom_vline(xintercept = 0, colour = "red", linetype = "dashed") +
facet_wrap(~dataset, ncol = 1) +
theme_bw() +
labs(title = "G2M score distribution per dataset")
p1 | p2

# Check which cell types are driving S phase
cat("Phase per cell type:\n")
Phase per cell type:
print(table(clean_obj$Phase, clean_obj$predicted.celltype.l2))
CD4 Naive CD4 TCM CD4 TEM CD4 Temra/CTL Treg
G1 1151 4165 69 6 86
G2M 107 816 15 1 33
S 779 4086 61 3 88
# Check S phase scores per cell type
ggplot(clean_obj@meta.data,
aes(x = predicted.celltype.l2,
y = S.Score,
fill = predicted.celltype.l2)) +
geom_violin(scale = "width", trim = TRUE) +
geom_boxplot(width = 0.08, fill = "white", outlier.size = 0.2) +
geom_hline(yintercept = 0, colour = "red", linetype = "dashed") +
theme_bw() +
theme(axis.text.x = element_text(angle = 45, hjust = 1),
legend.position = "none") +
labs(title = "S.Score per cell type — values above 0 = cycling",
x = NULL, y = "S.Score")

Re-embed — UMAP Only
(Preserve Existing RPCA Integration)
# CRITICAL:
# This object is already SCT normalised and RPCA integrated.
# The integrated assay PCA embedding IS the batch-corrected space.
#
# DO NOT run: ScaleData (would re-scale and destroy CC regression from SCT)
# DO NOT run: RunPCA (would recompute PCA, destroying RPCA integration
# and causing datasets to separate again)
# DO NOT run: SCTransform or IntegrateData
#
# ONLY run: FindNeighbors and RunUMAP on the EXISTING pca reduction
# This preserves the RPCA-corrected embedding and batch correction
cat("Available reductions:\n")
Available reductions:
print(names(clean_obj@reductions))
[1] "pca" "umap" "integrated_dr" "ref.umap"
DefaultAssay(clean_obj) <- "integrated"
# Use same dims as original integration
dims_use <- 1:20
# Rebuild neighbor graph on EXISTING pca embedding
clean_obj <- FindNeighbors(
clean_obj,
reduction = "pca",
dims = dims_use,
verbose = FALSE
)
# Rerun UMAP on EXISTING pca embedding
# return.model = TRUE is CRITICAL for MapQuery (malignant cell projection)
clean_obj <- RunUMAP(
clean_obj,
reduction = "pca",
dims = dims_use,
return.model = TRUE,
verbose = FALSE
)
# Recluster at multiple resolutions for flexibility
clean_obj <- FindClusters(
clean_obj,
resolution = c(0.1, 0.2, 0.3, 0.4, 0.5),
verbose = FALSE
)
cat("Clusters at resolution 0.3:",
length(unique(clean_obj$integrated_snn_res.0.3)), "\n")
Clusters at resolution 0.3: 10
Verify Integration
Preserved
# CRITICAL CHECK: datasets should be well mixed on UMAP
# If they are separated — integration was destroyed and needs to be re-done
p1 <- DimPlot(clean_obj,
group.by = "dataset",
shuffle = TRUE) +
ggtitle("Dataset mixing — should be well mixed\n(if separated: re-integration needed)")
p2 <- DimPlot(clean_obj,
group.by = "predicted.celltype.l2",
label = TRUE, repel = TRUE, label.box = TRUE) +
ggtitle("Azimuth l2 labels")
p3 <- DimPlot(clean_obj,
group.by = "Phase") +
ggtitle("Cell cycle phase (should be mixed, not separated)")
p1 | p2 | p3

Verify Integration
Preserved
p1

p2

# No CD8 cells remain
table(clean_obj$predicted.celltype.l2)
CD4 Naive CD4 TCM CD4 TEM CD4 Temra/CTL Treg
2037 9067 145 10 207
# High confidence scores
summary(clean_obj$mapping.score) # >0.65 ✓
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.1581 0.6618 0.7762 0.7455 0.8731 1.0000
summary(clean_obj$predicted.celltype.l2.score) # >0.75 ✓
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.2726 0.6740 0.8621 0.8126 0.9653 1.0000
Azimuth Score
Assessment
# Assess mapping and prediction scores to decide if l2 labels
# are reliable enough for trajectory analysis
p1 <- ggplot(clean_obj@meta.data,
aes(x = mapping.score)) +
geom_histogram(bins = 50, fill = "#4472C4", colour = "white") +
geom_vline(xintercept = 0.5, colour = "red",
linetype = "dashed", linewidth = 1) +
theme_bw() +
labs(title = "Mapping score distribution",
subtitle = "Cells below 0.5 are poorly mapped to PBMC reference",
x = "Mapping score", y = "Count")
p2 <- ggplot(clean_obj@meta.data,
aes(x = predicted.celltype.l2.score)) +
geom_histogram(bins = 50, fill = "#ED7D31", colour = "white") +
geom_vline(xintercept = 0.5, colour = "red",
linetype = "dashed", linewidth = 1) +
theme_bw() +
labs(title = "Prediction score l2",
x = "Prediction score", y = "Count")
p3 <- ggplot(clean_obj@meta.data,
aes(x = reorder(predicted.celltype.l2,
mapping.score, median),
y = mapping.score,
fill = predicted.celltype.l2)) +
geom_violin(scale = "width", trim = TRUE) +
geom_boxplot(width = 0.08, fill = "white", outlier.size = 0.2) +
geom_hline(yintercept = 0.5, colour = "red", linetype = "dashed") +
theme_bw() +
theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 9),
legend.position = "none") +
labs(title = "Mapping score per cell type", x = NULL, y = "Mapping score")
p4 <- ggplot(clean_obj@meta.data,
aes(x = reorder(predicted.celltype.l2,
predicted.celltype.l2.score, median),
y = predicted.celltype.l2.score,
fill = predicted.celltype.l2)) +
geom_violin(scale = "width", trim = TRUE) +
geom_boxplot(width = 0.08, fill = "white", outlier.size = 0.2) +
geom_hline(yintercept = 0.5, colour = "red", linetype = "dashed") +
theme_bw() +
theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 9),
legend.position = "none") +
labs(title = "Prediction score per cell type (l2)",
x = NULL, y = "Prediction score")
(p1 | p2) / p3 / p4

# Scores on UMAP
p5 <- FeaturePlot(clean_obj,
features = "mapping.score",
cols = c("grey90","#C00000"),
min.cutoff = 0, max.cutoff = 1) +
ggtitle("Mapping score on UMAP\n(red = high confidence)")
p6 <- FeaturePlot(clean_obj,
features = "predicted.celltype.l2.score",
cols = c("grey90","#4472C4"),
min.cutoff = 0, max.cutoff = 1) +
ggtitle("Prediction score l2 on UMAP\n(blue = high confidence)")
p5 | p6


library(patchwork)
# 4-panel report (exact SCpubr replica)
p1 <- FeaturePlot(clean_obj, features = "mapping.score") +
ggtitle("Azimuth Mapping Score")
p2 <- FeaturePlot(clean_obj, features = "predicted.celltype.l2.score") +
ggtitle("Azimuth L2 Score")
p3 <- DimPlot(clean_obj, group.by = "predicted.celltype.l2", label = TRUE) +
ggtitle("Local Clustering vs Azimuth")
p4 <- DimPlot(clean_obj, reduction = "ref.umap",
group.by = "predicted.celltype.l2", label = TRUE) +
ggtitle("PBMC Reference Projection")
# Final report
(p1 | p2) / (p3 | p4)

ggsave("azimuth_manual_report.png", width = 16, height = 10, dpi = 300)
library(dplyr)
prop_table <- clean_obj@meta.data %>%
dplyr::count(predicted.celltype.l2) %>% # ← Explicit dplyr::
mutate(Percent = round(n / sum(n) * 100, 1)) %>%
arrange(desc(n))
print(prop_table)
write.csv(prop_table, "celltype_proportions.csv", row.names = FALSE)
Decision Table — Should
We Use l2 Labels for Trajectory?
decision_df <- clean_obj@meta.data %>%
group_by(predicted.celltype.l2) %>%
summarise(
n_cells = n(),
median_mapping = round(median(mapping.score, na.rm = TRUE), 3),
median_pred = round(median(predicted.celltype.l2.score,
na.rm = TRUE), 3),
pct_above_0.5 = round(mean(mapping.score >= 0.5,
na.rm = TRUE) * 100, 1),
.groups = "drop"
) %>%
arrange(desc(n_cells))
cat("=== Full decision table ===\n")
=== Full decision table ===
print(decision_df)
key_states <- c("CD4 Naive","CD4 TCM","CD4 TEM","CD4 TEMRA/CTL","Treg")
cat("\n=== Key trajectory states ===\n")
=== Key trajectory states ===
print(decision_df %>% filter(predicted.celltype.l2 %in% key_states))
cat("\n=== Decision rule ===\n")
=== Decision rule ===
cat("If median mapping score > 0.5 for CD4 Naive + CD4 TCM + Treg:\n")
If median mapping score > 0.5 for CD4 Naive + CD4 TCM + Treg:
cat("→ Proceed with Azimuth l2 labels for trajectory\n")
→ Proceed with Azimuth l2 labels for trajectory
cat("If median mapping score < 0.5 for key states:\n")
If median mapping score < 0.5 for key states:
cat("→ Fall back to seurat_clusters with manual marker validation\n")
→ Fall back to seurat_clusters with manual marker validation
Save Final Reference
Object
cat("✅ Saved:", ncol(clean_obj), "cells\n")
✅ Saved: 11466 cells
```
LS0tCnRpdGxlOiAiQ0Q0IFQtY2VsbCBSZWZlcmVuY2UgKyBBemltdXRoIEFubm90YXRpb24gUmVwb3J0IgphdXRob3I6IE5hc2lyIE1haG1vb2QgQWJiYXNpCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHRydWUKICAgIHRoZW1lOiBqb3VybmFsCi0tLQoKCiMgMS4gbG9hZCBsaWJyYXJpZXMKYGBge3Igc2V0dXAsIGluY2x1ZGU9VFJVRX0KbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShDb21wbGV4SGVhdG1hcCkKbGlicmFyeShwcmVzdG8pCmxpYnJhcnkodGljdG9jKQpsaWJyYXJ5KFNDcHVicikKbGlicmFyeShTZXVyYXREYXRhKQpsaWJyYXJ5KEF6aW11dGgpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KHNsaW5nc2hvdCkKbGlicmFyeShTaW5nbGVDZWxsRXhwZXJpbWVudCkKCm9wdGlvbnModGltZW91dCA9IDMwMCkKc2V0LnNlZWQoMTIzKQoKIyBDb2xvdXIgcGFsZXR0ZSB1c2VkIHRocm91Z2hvdXQg4oCUIGRvIG5vdCBjaGFuZ2UKZmxvd19jb2xvdXJzIDwtIGMoCiAgIlRuYWl2ZSIgPSAiIzQ0NzJDNCIsCiAgIlRjbSIgICAgPSAiI0VEN0QzMSIsCiAgIlRlbSIgICAgPSAiI0E5RDE4RSIsCiAgIlRlbXJhIiAgPSAiI0MwMDAwMCIsCiAgIlRyZWciICAgPSAiI0ZGRDcwMCIKKQpgYGAKCgojIDIuIExvYWQgU2V1cmF0IE9iamVjdCAKYGBge3J9CgojTG9hZCBTZXVyYXQgT2JqZWN0IG1lcmdlZCBmcm9tIGNlbGwgbGluZXMgYW5kIGEgY29udHJvbChQQk1DKSBhZnRlciBmaWx0cmF0aW9uCkFsbF9zYW1wbGVzX01lcmdlZCA8LSByZWFkUkRTKCIuLi8uLi9DRDRfcmVmZXJlbmNlX2Fubm90YXRlZF93aXRoX21hcmtlcnMucmRzIikKCmBgYAoKCiMgUnVuIEF6bWltdXRoIGFuZCBjaGVjayBhbm5vdGF0aW9uIGFnYWluCmBgYHtyLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMn0KCmxpYnJhcnkoU2V1cmF0RGF0YSkKbGlicmFyeShBemltdXRoKQpvcHRpb25zKHRpbWVvdXQgPSAzMDApICAjIEluY3JlYXNlIGRvd25sb2FkIHRpbWVvdXQgaWYgbmVlZGVkIFt3ZWI6NjNdIAoKc2FtcGxlIDwtIEFsbF9zYW1wbGVzX01lcmdlZAoKcm0oQWxsX3NhbXBsZXNfTWVyZ2VkKQoKZ2MoKQoKRGVmYXVsdEFzc2F5KHNhbXBsZSkgPC0gIlJOQSIKCnNhbXBsZSA8LSBSdW5BemltdXRoKHNhbXBsZSwgcmVmZXJlbmNlID0gInBibWNyZWYiKQoKRGVmYXVsdEFzc2F5KHNhbXBsZSkgPC0gIlNDVCIKClNDcHVicjo6ZG9fRGltUGxvdCgKICBzYW1wbGUgPSBzYW1wbGUsCiAgcmVkdWN0aW9uID0gInVtYXAiLAogIGdyb3VwLmJ5ID0gInByZWRpY3RlZC5jZWxsdHlwZS5sMiIsCiAgZm9udC5zaXplID0gMTgsIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgbGVnZW5kLnRpdGxlID0gIkNlbGwgdHlwZSAoSGVhbHRoeSBDRDQgVCBjZWxscykiCikKCgpgYGAKCgojIyBDbGVhbiBPYmplY3QKYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKY2xlYW5fb2JqIDwtIHN1YnNldCgKICAgICBzYW1wbGUsCiAgICAgc3Vic2V0ID0gcHJlZGljdGVkLmNlbGx0eXBlLmwyICVpbiUgYygKICAgICAgICAgIkNEOCBOYWl2ZSIsICJDRDggVENNIiwgIkNEOCBURU0iLCAiUGxhdGVsZXQiLCAiQ0Q0IFByb2xpZmVyYXRpbmciCiAgICAgKSwKICAgICBpbnZlcnQgPSBUUlVFCiApCgpjYXQoIlxuQWZ0ZXIgY2xlYW5pbmc6IiwgbmNvbChjbGVhbl9vYmopLCAiY2VsbHNcbiIpCmNhdCgiXG5SZW1vdmVkIGNlbGwgdHlwZXM6XG4iKQoKY2F0KCJcblJlbWFpbmluZzpcbiIpCnByaW50KHRhYmxlKGNsZWFuX29iaiRwcmVkaWN0ZWQuY2VsbHR5cGUubDIpKQoKcm0oc2FtcGxlKTsgZ2MoKQoKU0NwdWJyOjpkb19EaW1QbG90KAogIHNhbXBsZSA9IGNsZWFuX29iaiwKICByZWR1Y3Rpb24gPSAidW1hcCIsCiAgZ3JvdXAuYnkgPSAicHJlZGljdGVkLmNlbGx0eXBlLmwyIiwKICBmb250LnNpemUgPSAxOCwgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwKICBsZWdlbmQudGl0bGUgPSAiQ2VsbCB0eXBlIChIZWFsdGh5IENENCBUIGNlbGxzKSIKKQoKYGBgCgojIyBSZW5hbWUgQ0Q0IENUTCDihpIgQ0Q0IFRlbXJhL0NUTApgYGB7ciwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CiMgUmVuYW1lIGluIG1ldGFkYXRhCmNsZWFuX29iaiRwcmVkaWN0ZWQuY2VsbHR5cGUubDJbY2xlYW5fb2JqJHByZWRpY3RlZC5jZWxsdHlwZS5sMiA9PSAiQ0Q0IENUTCJdIDwtICJDRDQgVGVtcmEvQ1RMIgoKIyBWZXJpZnkKdGFibGUoY2xlYW5fb2JqJHByZWRpY3RlZC5jZWxsdHlwZS5sMikKCmBgYAoKCiMjIERlZmluZSBMb2dpY2FsIE9yZGVyIGZvciBMZWdlbmQKYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQojIERlZmluZSBkZXNpcmVkIG9yZGVyIChOYWl2ZSDihpIgVENNIOKGkiBURU0g4oaSIFRlbXJhIOKGkiBUcmVnKQpjZWxsX29yZGVyIDwtIGMoIkNENCBOYWl2ZSIsICJDRDQgVENNIiwgIkNENCBURU0iLCAiQ0Q0IFRlbXJhL0NUTCIsICJUcmVnIikKCiMgU2V0IGZhY3RvciBsZXZlbHMKY2xlYW5fb2JqJHByZWRpY3RlZC5jZWxsdHlwZS5sMiA8LSBmYWN0b3IoY2xlYW5fb2JqJHByZWRpY3RlZC5jZWxsdHlwZS5sMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gY2VsbF9vcmRlcikKCiMgVmVyaWZ5IG9yZGVyCmxldmVscyhjbGVhbl9vYmokcHJlZGljdGVkLmNlbGx0eXBlLmwyKQoKYGBgCgoKCiMjIFB1YmxpY2F0aW9uLVF1YWxpdHkgVU1BUCBQbG90CmBgYHtyLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMH0KbGlicmFyeShnZ3Bsb3QyKQpwMSA8LSBEaW1QbG90KGNsZWFuX29iaiwKICAgICAgICAgICAgICBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiLAogICAgICAgICAgICAgIGxhYmVsID0gVFJVRSwKICAgICAgICAgICAgICByZXBlbCA9IFRSVUUsCiAgICAgICAgICAgICAgY29scyA9IGMoIkNENCBOYWl2ZSIgPSAiIzFmNzdiNCIsICAgICAgIyBCbHVlCiAgICAgICAgICAgICAgICAgICAgICAgIkNENCBUQ00iICAgPSAiI2ZmN2YwZSIsICAgICAgIyBPcmFuZ2UgIAogICAgICAgICAgICAgICAgICAgICAgICJDRDQgVEVNIiAgID0gIiMyY2EwMmMiLCAgICAgICMgR3JlZW4KICAgICAgICAgICAgICAgICAgICAgICAiQ0Q0IFRlbXJhL0NUTCIgPSAiI2Q2MjcyOCIsICAgICAgIyBSZWQKICAgICAgICAgICAgICAgICAgICAgICAiVHJlZyIgICAgICA9ICIjOTQ2N2JkIiksICAgICAjIFB1cnBsZQogICAgICAgICAgICAgIHB0LnNpemUgPSAwLjUpICsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNCkpKSArCiAgbGFicyh0aXRsZSA9ICJIZWFsdGh5IENENCBUIENlbGwgUmVmZXJlbmNlIEF0bGFzIiwKICAgICAgIHN1YnRpdGxlID0gIlF1aWVzY2VudCBzdGF0ZXMgb25seSB8IEF6aW11dGggTDIgYW5ub3RhdGlvbiIpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE2KSwKICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTIpKQoKcHJpbnQocDEpCmdnc2F2ZSgiaGVhbHRoeV9jZDRfcmVmZXJlbmNlX3VtYXAucGRmIiwgcDEsIHdpZHRoID0gMTAsIGhlaWdodCA9IDgsIGRwaSA9IDMwMCkKCiMgUE5HIHZlcnNpb24gKGZvciBwcmVzZW50YXRpb25zKQpnZ3NhdmUoImhlYWx0aHlfY2Q0X3JlZmVyZW5jZV91bWFwLnBuZyIsIHAxLCAKICAgICAgIHdpZHRoID0gMTAsIGhlaWdodCA9IDgsIGRwaSA9IDMwMCwgYmcgPSAid2hpdGUiKQoKYGBgCgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KEF6aW11dGgpCgojIFJ1biB0aGlzIGRpYWdub3N0aWMgdG8gdW5kZXJzdGFuZCB3aGF0IGlzIGhhcHBlbmluZwpEZWZhdWx0QXNzYXkoY2xlYW5fb2JqKSA8LSAiUk5BIgoKIyBDaGVjayBTIGFuZCBHMk0gc2NvcmVzIGRpc3RyaWJ1dGlvbgpwMSA8LSBnZ3Bsb3QoY2xlYW5fb2JqQG1ldGEuZGF0YSwKICAgICAgICAgICAgIGFlcyh4ID0gUy5TY29yZSwgZmlsbCA9IGRhdGFzZXQpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDUwLCBhbHBoYSA9IDAuNywgcG9zaXRpb24gPSAiaWRlbnRpdHkiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgY29sb3VyID0gInJlZCIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBmYWNldF93cmFwKH5kYXRhc2V0LCBuY29sID0gMSkgKwogIHRoZW1lX2J3KCkgKwogIGxhYnModGl0bGUgPSAiUyBzY29yZSBkaXN0cmlidXRpb24gcGVyIGRhdGFzZXQiLAogICAgICAgc3VidGl0bGUgPSAiSGVhbHRoeSByZXN0aW5nIFQtY2VsbHMgc2hvdWxkIHBlYWsgYmVsb3cgMCIpCgpwMiA8LSBnZ3Bsb3QoY2xlYW5fb2JqQG1ldGEuZGF0YSwKICAgICAgICAgICAgIGFlcyh4ID0gRzJNLlNjb3JlLCBmaWxsID0gZGF0YXNldCkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNTAsIGFscGhhID0gMC43LCBwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBjb2xvdXIgPSAicmVkIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGZhY2V0X3dyYXAofmRhdGFzZXQsIG5jb2wgPSAxKSArCiAgdGhlbWVfYncoKSArCiAgbGFicyh0aXRsZSA9ICJHMk0gc2NvcmUgZGlzdHJpYnV0aW9uIHBlciBkYXRhc2V0IikKCnAxIHwgcDIKCiMgQ2hlY2sgd2hpY2ggY2VsbCB0eXBlcyBhcmUgZHJpdmluZyBTIHBoYXNlCmNhdCgiUGhhc2UgcGVyIGNlbGwgdHlwZTpcbiIpCnByaW50KHRhYmxlKGNsZWFuX29iaiRQaGFzZSwgY2xlYW5fb2JqJHByZWRpY3RlZC5jZWxsdHlwZS5sMikpCgojIENoZWNrIFMgcGhhc2Ugc2NvcmVzIHBlciBjZWxsIHR5cGUKZ2dwbG90KGNsZWFuX29iakBtZXRhLmRhdGEsCiAgICAgICBhZXMoeCAgICA9IHByZWRpY3RlZC5jZWxsdHlwZS5sMiwKICAgICAgICAgICB5ICAgID0gUy5TY29yZSwKICAgICAgICAgICBmaWxsID0gcHJlZGljdGVkLmNlbGx0eXBlLmwyKSkgKwogIGdlb21fdmlvbGluKHNjYWxlID0gIndpZHRoIiwgdHJpbSA9IFRSVUUpICsKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjA4LCBmaWxsID0gIndoaXRlIiwgb3V0bGllci5zaXplID0gMC4yKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3VyID0gInJlZCIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCAgICA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIGxhYnModGl0bGUgPSAiUy5TY29yZSBwZXIgY2VsbCB0eXBlIOKAlCB2YWx1ZXMgYWJvdmUgMCA9IGN5Y2xpbmciLAogICAgICAgeCA9IE5VTEwsIHkgPSAiUy5TY29yZSIpCmBgYAojIFJlLWVtYmVkIOKAlCBVTUFQIE9ubHkgKFByZXNlcnZlIEV4aXN0aW5nIFJQQ0EgSW50ZWdyYXRpb24pCmBgYHtyIHJlZW1iZWR9CiMgQ1JJVElDQUw6CiMgVGhpcyBvYmplY3QgaXMgYWxyZWFkeSBTQ1Qgbm9ybWFsaXNlZCBhbmQgUlBDQSBpbnRlZ3JhdGVkLgojIFRoZSBpbnRlZ3JhdGVkIGFzc2F5IFBDQSBlbWJlZGRpbmcgSVMgdGhlIGJhdGNoLWNvcnJlY3RlZCBzcGFjZS4KIwojIERPIE5PVCBydW46ICBTY2FsZURhdGEgKHdvdWxkIHJlLXNjYWxlIGFuZCBkZXN0cm95IENDIHJlZ3Jlc3Npb24gZnJvbSBTQ1QpCiMgRE8gTk9UIHJ1bjogIFJ1blBDQSAgICAod291bGQgcmVjb21wdXRlIFBDQSwgZGVzdHJveWluZyBSUENBIGludGVncmF0aW9uCiMgICAgICAgICAgICAgICAgICAgICAgICAgYW5kIGNhdXNpbmcgZGF0YXNldHMgdG8gc2VwYXJhdGUgYWdhaW4pCiMgRE8gTk9UIHJ1bjogIFNDVHJhbnNmb3JtIG9yIEludGVncmF0ZURhdGEKIwojIE9OTFkgcnVuOiAgIEZpbmROZWlnaGJvcnMgYW5kIFJ1blVNQVAgb24gdGhlIEVYSVNUSU5HIHBjYSByZWR1Y3Rpb24KIyAgICAgICAgICAgICBUaGlzIHByZXNlcnZlcyB0aGUgUlBDQS1jb3JyZWN0ZWQgZW1iZWRkaW5nIGFuZCBiYXRjaCBjb3JyZWN0aW9uCgpjYXQoIkF2YWlsYWJsZSByZWR1Y3Rpb25zOlxuIikKcHJpbnQobmFtZXMoY2xlYW5fb2JqQHJlZHVjdGlvbnMpKQoKRGVmYXVsdEFzc2F5KGNsZWFuX29iaikgPC0gImludGVncmF0ZWQiCgojIFVzZSBzYW1lIGRpbXMgYXMgb3JpZ2luYWwgaW50ZWdyYXRpb24KZGltc191c2UgPC0gMToyMAoKIyBSZWJ1aWxkIG5laWdoYm9yIGdyYXBoIG9uIEVYSVNUSU5HIHBjYSBlbWJlZGRpbmcKY2xlYW5fb2JqIDwtIEZpbmROZWlnaGJvcnMoCiAgY2xlYW5fb2JqLAogIHJlZHVjdGlvbiA9ICJwY2EiLAogIGRpbXMgICAgICA9IGRpbXNfdXNlLAogIHZlcmJvc2UgICA9IEZBTFNFCikKCiMgUmVydW4gVU1BUCBvbiBFWElTVElORyBwY2EgZW1iZWRkaW5nCiMgcmV0dXJuLm1vZGVsID0gVFJVRSBpcyBDUklUSUNBTCBmb3IgTWFwUXVlcnkgKG1hbGlnbmFudCBjZWxsIHByb2plY3Rpb24pCmNsZWFuX29iaiA8LSBSdW5VTUFQKAogIGNsZWFuX29iaiwKICByZWR1Y3Rpb24gICAgPSAicGNhIiwKICBkaW1zICAgICAgICAgPSBkaW1zX3VzZSwKICByZXR1cm4ubW9kZWwgPSBUUlVFLAogIHZlcmJvc2UgICAgICA9IEZBTFNFCikKCiMgUmVjbHVzdGVyIGF0IG11bHRpcGxlIHJlc29sdXRpb25zIGZvciBmbGV4aWJpbGl0eQpjbGVhbl9vYmogPC0gRmluZENsdXN0ZXJzKAogIGNsZWFuX29iaiwKICByZXNvbHV0aW9uID0gYygwLjEsIDAuMiwgMC4zLCAwLjQsIDAuNSksCiAgdmVyYm9zZSAgICA9IEZBTFNFCikKCmNhdCgiQ2x1c3RlcnMgYXQgcmVzb2x1dGlvbiAwLjM6IiwKICAgIGxlbmd0aCh1bmlxdWUoY2xlYW5fb2JqJGludGVncmF0ZWRfc25uX3Jlcy4wLjMpKSwgIlxuIikKYGBgCgojIFZlcmlmeSBJbnRlZ3JhdGlvbiBQcmVzZXJ2ZWQKYGBge3IgdmVyaWZ5LWludGVncmF0aW9uLCBmaWcud2lkdGg9MjAsIGZpZy5oZWlnaHQ9N30KIyBDUklUSUNBTCBDSEVDSzogZGF0YXNldHMgc2hvdWxkIGJlIHdlbGwgbWl4ZWQgb24gVU1BUAojIElmIHRoZXkgYXJlIHNlcGFyYXRlZCDigJQgaW50ZWdyYXRpb24gd2FzIGRlc3Ryb3llZCBhbmQgbmVlZHMgdG8gYmUgcmUtZG9uZQoKcDEgPC0gRGltUGxvdChjbGVhbl9vYmosCiAgICAgICAgICAgICAgZ3JvdXAuYnkgPSAiZGF0YXNldCIsCiAgICAgICAgICAgICAgc2h1ZmZsZSAgPSBUUlVFKSArCiAgZ2d0aXRsZSgiRGF0YXNldCBtaXhpbmcg4oCUIHNob3VsZCBiZSB3ZWxsIG1peGVkXG4oaWYgc2VwYXJhdGVkOiByZS1pbnRlZ3JhdGlvbiBuZWVkZWQpIikKCnAyIDwtIERpbVBsb3QoY2xlYW5fb2JqLAogICAgICAgICAgICAgIGdyb3VwLmJ5ID0gInByZWRpY3RlZC5jZWxsdHlwZS5sMiIsCiAgICAgICAgICAgICAgbGFiZWwgICAgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGxhYmVsLmJveCA9IFRSVUUpICsKICBnZ3RpdGxlKCJBemltdXRoIGwyIGxhYmVscyIpCgpwMyA8LSBEaW1QbG90KGNsZWFuX29iaiwKICAgICAgICAgICAgICBncm91cC5ieSA9ICJQaGFzZSIpICsKICBnZ3RpdGxlKCJDZWxsIGN5Y2xlIHBoYXNlIChzaG91bGQgYmUgbWl4ZWQsIG5vdCBzZXBhcmF0ZWQpIikKCnAxIHwgcDIgfCBwMwoKYGBgCgojIFZlcmlmeSBJbnRlZ3JhdGlvbiBQcmVzZXJ2ZWQKYGBge3IgLCBmaWcud2lkdGg9OSwgZmlnLmhlaWdodD02fQoKcDEgCnAyIAoKIyBObyBDRDggY2VsbHMgcmVtYWluCnRhYmxlKGNsZWFuX29iaiRwcmVkaWN0ZWQuY2VsbHR5cGUubDIpCgojIEhpZ2ggY29uZmlkZW5jZSBzY29yZXMKc3VtbWFyeShjbGVhbl9vYmokbWFwcGluZy5zY29yZSkgICAgICAjID4wLjY1IOKckwpzdW1tYXJ5KGNsZWFuX29iaiRwcmVkaWN0ZWQuY2VsbHR5cGUubDIuc2NvcmUpICAjID4wLjc1IOKckwoKYGBgCgoKCgoKCiMgQXppbXV0aCBTY29yZSBBc3Nlc3NtZW50CmBgYHtyIGF6aW11dGgtc2NvcmVzLCBmaWcud2lkdGg9MTQsIGZpZy5oZWlnaHQ9MTZ9CiMgQXNzZXNzIG1hcHBpbmcgYW5kIHByZWRpY3Rpb24gc2NvcmVzIHRvIGRlY2lkZSBpZiBsMiBsYWJlbHMKIyBhcmUgcmVsaWFibGUgZW5vdWdoIGZvciB0cmFqZWN0b3J5IGFuYWx5c2lzCgpwMSA8LSBnZ3Bsb3QoY2xlYW5fb2JqQG1ldGEuZGF0YSwKICAgICAgICAgICAgIGFlcyh4ID0gbWFwcGluZy5zY29yZSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNTAsIGZpbGwgPSAiIzQ0NzJDNCIsIGNvbG91ciA9ICJ3aGl0ZSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLjUsIGNvbG91ciA9ICJyZWQiLAogICAgICAgICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIiwgbGluZXdpZHRoID0gMSkgKwogIHRoZW1lX2J3KCkgKwogIGxhYnModGl0bGUgICAgPSAiTWFwcGluZyBzY29yZSBkaXN0cmlidXRpb24iLAogICAgICAgc3VidGl0bGUgPSAiQ2VsbHMgYmVsb3cgMC41IGFyZSBwb29ybHkgbWFwcGVkIHRvIFBCTUMgcmVmZXJlbmNlIiwKICAgICAgIHggPSAiTWFwcGluZyBzY29yZSIsIHkgPSAiQ291bnQiKQoKcDIgPC0gZ2dwbG90KGNsZWFuX29iakBtZXRhLmRhdGEsCiAgICAgICAgICAgICBhZXMoeCA9IHByZWRpY3RlZC5jZWxsdHlwZS5sMi5zY29yZSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNTAsIGZpbGwgPSAiI0VEN0QzMSIsIGNvbG91ciA9ICJ3aGl0ZSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLjUsIGNvbG91ciA9ICJyZWQiLAogICAgICAgICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIiwgbGluZXdpZHRoID0gMSkgKwogIHRoZW1lX2J3KCkgKwogIGxhYnModGl0bGUgPSAiUHJlZGljdGlvbiBzY29yZSBsMiIsCiAgICAgICB4ID0gIlByZWRpY3Rpb24gc2NvcmUiLCB5ID0gIkNvdW50IikKCnAzIDwtIGdncGxvdChjbGVhbl9vYmpAbWV0YS5kYXRhLAogICAgICAgICAgICAgYWVzKHggICAgPSByZW9yZGVyKHByZWRpY3RlZC5jZWxsdHlwZS5sMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nLnNjb3JlLCBtZWRpYW4pLAogICAgICAgICAgICAgICAgIHkgICAgPSBtYXBwaW5nLnNjb3JlLAogICAgICAgICAgICAgICAgIGZpbGwgPSBwcmVkaWN0ZWQuY2VsbHR5cGUubDIpKSArCiAgZ2VvbV92aW9saW4oc2NhbGUgPSAid2lkdGgiLCB0cmltID0gVFJVRSkgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMDgsIGZpbGwgPSAid2hpdGUiLCBvdXRsaWVyLnNpemUgPSAwLjIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLjUsIGNvbG91ciA9ICJyZWQiLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggICAgID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgc2l6ZSA9IDkpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIGxhYnModGl0bGUgPSAiTWFwcGluZyBzY29yZSBwZXIgY2VsbCB0eXBlIiwgeCA9IE5VTEwsIHkgPSAiTWFwcGluZyBzY29yZSIpCgpwNCA8LSBnZ3Bsb3QoY2xlYW5fb2JqQG1ldGEuZGF0YSwKICAgICAgICAgICAgIGFlcyh4ICAgID0gcmVvcmRlcihwcmVkaWN0ZWQuY2VsbHR5cGUubDIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlZGljdGVkLmNlbGx0eXBlLmwyLnNjb3JlLCBtZWRpYW4pLAogICAgICAgICAgICAgICAgIHkgICAgPSBwcmVkaWN0ZWQuY2VsbHR5cGUubDIuc2NvcmUsCiAgICAgICAgICAgICAgICAgZmlsbCA9IHByZWRpY3RlZC5jZWxsdHlwZS5sMikpICsKICBnZW9tX3Zpb2xpbihzY2FsZSA9ICJ3aWR0aCIsIHRyaW0gPSBUUlVFKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4wOCwgZmlsbCA9ICJ3aGl0ZSIsIG91dGxpZXIuc2l6ZSA9IDAuMikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuNSwgY29sb3VyID0gInJlZCIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCAgICAgPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCBzaXplID0gOSksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgbGFicyh0aXRsZSA9ICJQcmVkaWN0aW9uIHNjb3JlIHBlciBjZWxsIHR5cGUgKGwyKSIsCiAgICAgICB4ID0gTlVMTCwgeSA9ICJQcmVkaWN0aW9uIHNjb3JlIikKCihwMSB8IHAyKSAvIHAzIC8gcDQKCiMgU2NvcmVzIG9uIFVNQVAKcDUgPC0gRmVhdHVyZVBsb3QoY2xlYW5fb2JqLAogICAgICAgICAgICAgICAgICBmZWF0dXJlcyAgID0gIm1hcHBpbmcuc2NvcmUiLAogICAgICAgICAgICAgICAgICBjb2xzICAgICAgID0gYygiZ3JleTkwIiwiI0MwMDAwMCIpLAogICAgICAgICAgICAgICAgICBtaW4uY3V0b2ZmID0gMCwgbWF4LmN1dG9mZiA9IDEpICsKICBnZ3RpdGxlKCJNYXBwaW5nIHNjb3JlIG9uIFVNQVBcbihyZWQgPSBoaWdoIGNvbmZpZGVuY2UpIikKCnA2IDwtIEZlYXR1cmVQbG90KGNsZWFuX29iaiwKICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgICA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIuc2NvcmUiLAogICAgICAgICAgICAgICAgICBjb2xzICAgICAgID0gYygiZ3JleTkwIiwiIzQ0NzJDNCIpLAogICAgICAgICAgICAgICAgICBtaW4uY3V0b2ZmID0gMCwgbWF4LmN1dG9mZiA9IDEpICsKICBnZ3RpdGxlKCJQcmVkaWN0aW9uIHNjb3JlIGwyIG9uIFVNQVBcbihibHVlID0gaGlnaCBjb25maWRlbmNlKSIpCgpwNSB8IHA2CmBgYApgYGB7cn0KCiMgV29ya3MgaW1tZWRpYXRlbHkKcF9hbm5vdCA8LSBkb19EaW1QbG90KAogIHNhbXBsZSA9IGNsZWFuX29iaiwKICBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiLAogIGxhYmVsID0gRkFMU0UsICAjIOKGkCBGaXg6IGRpc2FibGUgbGFiZWxzCiAgcGxvdC50aXRsZSA9ICJBemltdXRoIEwyIEFubm90YXRpb24iCikKcF9hbm5vdAoKYGBgCgoKCgpgYGB7ciwgZmlnLndpZHRoPTE0LCBmaWcuaGVpZ2h0PTE2fQpsaWJyYXJ5KHBhdGNod29yaykKCiMgNC1wYW5lbCByZXBvcnQgKGV4YWN0IFNDcHViciByZXBsaWNhKQpwMSA8LSBGZWF0dXJlUGxvdChjbGVhbl9vYmosIGZlYXR1cmVzID0gIm1hcHBpbmcuc2NvcmUiKSArIAogICAgICBnZ3RpdGxlKCJBemltdXRoIE1hcHBpbmcgU2NvcmUiKQoKcDIgPC0gRmVhdHVyZVBsb3QoY2xlYW5fb2JqLCBmZWF0dXJlcyA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIuc2NvcmUiKSArIAogICAgICBnZ3RpdGxlKCJBemltdXRoIEwyIFNjb3JlIikKCnAzIDwtIERpbVBsb3QoY2xlYW5fb2JqLCBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiLCBsYWJlbCA9IFRSVUUpICsKICAgICAgZ2d0aXRsZSgiTG9jYWwgQ2x1c3RlcmluZyB2cyBBemltdXRoIikKCnA0IDwtIERpbVBsb3QoY2xlYW5fb2JqLCByZWR1Y3Rpb24gPSAicmVmLnVtYXAiLCAKICAgICAgICAgICAgICBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiLCBsYWJlbCA9IFRSVUUpICsKICAgICAgZ2d0aXRsZSgiUEJNQyBSZWZlcmVuY2UgUHJvamVjdGlvbiIpCgojIEZpbmFsIHJlcG9ydAoocDEgfCBwMikgLyAocDMgfCBwNCkKZ2dzYXZlKCJhemltdXRoX21hbnVhbF9yZXBvcnQucG5nIiwgd2lkdGggPSAxNiwgaGVpZ2h0ID0gMTAsIGRwaSA9IDMwMCkKCgoKYGBgCgoKCgpgYGB7cn0KbGlicmFyeShkcGx5cikKCnByb3BfdGFibGUgPC0gY2xlYW5fb2JqQG1ldGEuZGF0YSAlPiUKICBkcGx5cjo6Y291bnQocHJlZGljdGVkLmNlbGx0eXBlLmwyKSAlPiUgICMg4oaQIEV4cGxpY2l0IGRwbHlyOjoKICBtdXRhdGUoUGVyY2VudCA9IHJvdW5kKG4gLyBzdW0obikgKiAxMDAsIDEpKSAlPiUKICBhcnJhbmdlKGRlc2MobikpCgpwcmludChwcm9wX3RhYmxlKQp3cml0ZS5jc3YocHJvcF90YWJsZSwgImNlbGx0eXBlX3Byb3BvcnRpb25zLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQoKYGBgCgoKCiMgRGVjaXNpb24gVGFibGUg4oCUIFNob3VsZCBXZSBVc2UgbDIgTGFiZWxzIGZvciBUcmFqZWN0b3J5PwpgYGB7ciBkZWNpc2lvbi10YWJsZX0KZGVjaXNpb25fZGYgPC0gY2xlYW5fb2JqQG1ldGEuZGF0YSAlPiUKICBncm91cF9ieShwcmVkaWN0ZWQuY2VsbHR5cGUubDIpICU+JQogIHN1bW1hcmlzZSgKICAgIG5fY2VsbHMgICAgICAgID0gbigpLAogICAgbWVkaWFuX21hcHBpbmcgPSByb3VuZChtZWRpYW4obWFwcGluZy5zY29yZSwgbmEucm0gPSBUUlVFKSwgMyksCiAgICBtZWRpYW5fcHJlZCAgICA9IHJvdW5kKG1lZGlhbihwcmVkaWN0ZWQuY2VsbHR5cGUubDIuc2NvcmUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpLCAzKSwKICAgIHBjdF9hYm92ZV8wLjUgID0gcm91bmQobWVhbihtYXBwaW5nLnNjb3JlID49IDAuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSAqIDEwMCwgMSksCiAgICAuZ3JvdXBzID0gImRyb3AiCiAgKSAlPiUKICBhcnJhbmdlKGRlc2Mobl9jZWxscykpCgpjYXQoIj09PSBGdWxsIGRlY2lzaW9uIHRhYmxlID09PVxuIikKcHJpbnQoZGVjaXNpb25fZGYpCgprZXlfc3RhdGVzIDwtIGMoIkNENCBOYWl2ZSIsIkNENCBUQ00iLCJDRDQgVEVNIiwiQ0Q0IFRFTVJBL0NUTCIsIlRyZWciKQpjYXQoIlxuPT09IEtleSB0cmFqZWN0b3J5IHN0YXRlcyA9PT1cbiIpCnByaW50KGRlY2lzaW9uX2RmICU+JSBmaWx0ZXIocHJlZGljdGVkLmNlbGx0eXBlLmwyICVpbiUga2V5X3N0YXRlcykpCgpjYXQoIlxuPT09IERlY2lzaW9uIHJ1bGUgPT09XG4iKQpjYXQoIklmIG1lZGlhbiBtYXBwaW5nIHNjb3JlID4gMC41IGZvciBDRDQgTmFpdmUgKyBDRDQgVENNICsgVHJlZzpcbiIpCmNhdCgi4oaSIFByb2NlZWQgd2l0aCBBemltdXRoIGwyIGxhYmVscyBmb3IgdHJhamVjdG9yeVxuIikKY2F0KCJJZiBtZWRpYW4gbWFwcGluZyBzY29yZSA8IDAuNSBmb3Iga2V5IHN0YXRlczpcbiIpCmNhdCgi4oaSIEZhbGwgYmFjayB0byBzZXVyYXRfY2x1c3RlcnMgd2l0aCBtYW51YWwgbWFya2VyIHZhbGlkYXRpb25cbiIpCmBgYAoKCgojIFNhdmUgRmluYWwgUmVmZXJlbmNlIE9iamVjdApgYGB7ciBzYXZlfQpEZWZhdWx0QXNzYXkoY2xlYW5fb2JqKSA8LSAiaW50ZWdyYXRlZCIKCnNhdmVSRFMoCiAgY2xlYW5fb2JqLAogICJDRDRfcmVmZXJlbmNlX2NsZWFuX0F6aW11dGhfcmVhZHlfZm9yX1NsaW5nc2hvdC5yZHMiLAogIGNvbXByZXNzID0gRkFMU0UgICAjIGZhc3RlciBmb3IgbGFyZ2Ugb2JqZWN0cwopCgpjYXQoIuKchSBTYXZlZDoiLCBuY29sKGNsZWFuX29iaiksICJjZWxsc1xuIikKCmBgYAoKCgoKYGBgCg==