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

3 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

3.1 Clean Object

3.2 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 

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

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

4 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 

5 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

6 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 

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

8 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

9 Save Final Reference Object

cat("✅ Saved:", ncol(clean_obj), "cells\n")
✅ Saved: 11466 cells

```

LS0tCnRpdGxlOiAiQ0Q0IFQtY2VsbCBSZWZlcmVuY2UgKyBBemltdXRoIEFubm90YXRpb24gUmVwb3J0IgphdXRob3I6IE5hc2lyIE1haG1vb2QgQWJiYXNpCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHRydWUKICAgIHRoZW1lOiBqb3VybmFsCi0tLQoKCiMgMS4gbG9hZCBsaWJyYXJpZXMKYGBge3Igc2V0dXAsIGluY2x1ZGU9VFJVRX0KbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShDb21wbGV4SGVhdG1hcCkKbGlicmFyeShwcmVzdG8pCmxpYnJhcnkodGljdG9jKQpsaWJyYXJ5KFNDcHVicikKbGlicmFyeShTZXVyYXREYXRhKQpsaWJyYXJ5KEF6aW11dGgpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KHNsaW5nc2hvdCkKbGlicmFyeShTaW5nbGVDZWxsRXhwZXJpbWVudCkKCm9wdGlvbnModGltZW91dCA9IDMwMCkKc2V0LnNlZWQoMTIzKQoKIyBDb2xvdXIgcGFsZXR0ZSB1c2VkIHRocm91Z2hvdXQg4oCUIGRvIG5vdCBjaGFuZ2UKZmxvd19jb2xvdXJzIDwtIGMoCiAgIlRuYWl2ZSIgPSAiIzQ0NzJDNCIsCiAgIlRjbSIgICAgPSAiI0VEN0QzMSIsCiAgIlRlbSIgICAgPSAiI0E5RDE4RSIsCiAgIlRlbXJhIiAgPSAiI0MwMDAwMCIsCiAgIlRyZWciICAgPSAiI0ZGRDcwMCIKKQpgYGAKCgojIDIuIExvYWQgU2V1cmF0IE9iamVjdCAKYGBge3J9CgojTG9hZCBTZXVyYXQgT2JqZWN0IG1lcmdlZCBmcm9tIGNlbGwgbGluZXMgYW5kIGEgY29udHJvbChQQk1DKSBhZnRlciBmaWx0cmF0aW9uCkFsbF9zYW1wbGVzX01lcmdlZCA8LSByZWFkUkRTKCIuLi8uLi9DRDRfcmVmZXJlbmNlX2Fubm90YXRlZF93aXRoX21hcmtlcnMucmRzIikKCmBgYAoKCiMgUnVuIEF6bWltdXRoIGFuZCBjaGVjayBhbm5vdGF0aW9uIGFnYWluCmBgYHtyLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMn0KCmxpYnJhcnkoU2V1cmF0RGF0YSkKbGlicmFyeShBemltdXRoKQpvcHRpb25zKHRpbWVvdXQgPSAzMDApICAjIEluY3JlYXNlIGRvd25sb2FkIHRpbWVvdXQgaWYgbmVlZGVkIFt3ZWI6NjNdIAoKc2FtcGxlIDwtIEFsbF9zYW1wbGVzX01lcmdlZAoKcm0oQWxsX3NhbXBsZXNfTWVyZ2VkKQoKZ2MoKQoKRGVmYXVsdEFzc2F5KHNhbXBsZSkgPC0gIlJOQSIKCnNhbXBsZSA8LSBSdW5BemltdXRoKHNhbXBsZSwgcmVmZXJlbmNlID0gInBibWNyZWYiKQoKRGVmYXVsdEFzc2F5KHNhbXBsZSkgPC0gIlNDVCIKClNDcHVicjo6ZG9fRGltUGxvdCgKICBzYW1wbGUgPSBzYW1wbGUsCiAgcmVkdWN0aW9uID0gInVtYXAiLAogIGdyb3VwLmJ5ID0gInByZWRpY3RlZC5jZWxsdHlwZS5sMiIsCiAgZm9udC5zaXplID0gMTgsIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgbGVnZW5kLnRpdGxlID0gIkNlbGwgdHlwZSAoSGVhbHRoeSBDRDQgVCBjZWxscykiCikKCgpgYGAKCgojIyBDbGVhbiBPYmplY3QKYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKY2xlYW5fb2JqIDwtIHN1YnNldCgKICAgICBzYW1wbGUsCiAgICAgc3Vic2V0ID0gcHJlZGljdGVkLmNlbGx0eXBlLmwyICVpbiUgYygKICAgICAgICAgIkNEOCBOYWl2ZSIsICJDRDggVENNIiwgIkNEOCBURU0iLCAiUGxhdGVsZXQiLCAiQ0Q0IFByb2xpZmVyYXRpbmciCiAgICAgKSwKICAgICBpbnZlcnQgPSBUUlVFCiApCgpjYXQoIlxuQWZ0ZXIgY2xlYW5pbmc6IiwgbmNvbChjbGVhbl9vYmopLCAiY2VsbHNcbiIpCmNhdCgiXG5SZW1vdmVkIGNlbGwgdHlwZXM6XG4iKQoKY2F0KCJcblJlbWFpbmluZzpcbiIpCnByaW50KHRhYmxlKGNsZWFuX29iaiRwcmVkaWN0ZWQuY2VsbHR5cGUubDIpKQoKcm0oc2FtcGxlKTsgZ2MoKQoKU0NwdWJyOjpkb19EaW1QbG90KAogIHNhbXBsZSA9IGNsZWFuX29iaiwKICByZWR1Y3Rpb24gPSAidW1hcCIsCiAgZ3JvdXAuYnkgPSAicHJlZGljdGVkLmNlbGx0eXBlLmwyIiwKICBmb250LnNpemUgPSAxOCwgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwKICBsZWdlbmQudGl0bGUgPSAiQ2VsbCB0eXBlIChIZWFsdGh5IENENCBUIGNlbGxzKSIKKQoKYGBgCgojIyBSZW5hbWUgQ0Q0IENUTCDihpIgQ0Q0IFRlbXJhL0NUTApgYGB7ciwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CiMgUmVuYW1lIGluIG1ldGFkYXRhCmNsZWFuX29iaiRwcmVkaWN0ZWQuY2VsbHR5cGUubDJbY2xlYW5fb2JqJHByZWRpY3RlZC5jZWxsdHlwZS5sMiA9PSAiQ0Q0IENUTCJdIDwtICJDRDQgVGVtcmEvQ1RMIgoKIyBWZXJpZnkKdGFibGUoY2xlYW5fb2JqJHByZWRpY3RlZC5jZWxsdHlwZS5sMikKCmBgYAoKCiMjIERlZmluZSBMb2dpY2FsIE9yZGVyIGZvciBMZWdlbmQKYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQojIERlZmluZSBkZXNpcmVkIG9yZGVyIChOYWl2ZSDihpIgVENNIOKGkiBURU0g4oaSIFRlbXJhIOKGkiBUcmVnKQpjZWxsX29yZGVyIDwtIGMoIkNENCBOYWl2ZSIsICJDRDQgVENNIiwgIkNENCBURU0iLCAiQ0Q0IFRlbXJhL0NUTCIsICJUcmVnIikKCiMgU2V0IGZhY3RvciBsZXZlbHMKY2xlYW5fb2JqJHByZWRpY3RlZC5jZWxsdHlwZS5sMiA8LSBmYWN0b3IoY2xlYW5fb2JqJHByZWRpY3RlZC5jZWxsdHlwZS5sMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gY2VsbF9vcmRlcikKCiMgVmVyaWZ5IG9yZGVyCmxldmVscyhjbGVhbl9vYmokcHJlZGljdGVkLmNlbGx0eXBlLmwyKQoKYGBgCgoKCiMjIFB1YmxpY2F0aW9uLVF1YWxpdHkgVU1BUCBQbG90CmBgYHtyLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMH0KbGlicmFyeShnZ3Bsb3QyKQpwMSA8LSBEaW1QbG90KGNsZWFuX29iaiwKICAgICAgICAgICAgICBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiLAogICAgICAgICAgICAgIGxhYmVsID0gVFJVRSwKICAgICAgICAgICAgICByZXBlbCA9IFRSVUUsCiAgICAgICAgICAgICAgY29scyA9IGMoIkNENCBOYWl2ZSIgPSAiIzFmNzdiNCIsICAgICAgIyBCbHVlCiAgICAgICAgICAgICAgICAgICAgICAgIkNENCBUQ00iICAgPSAiI2ZmN2YwZSIsICAgICAgIyBPcmFuZ2UgIAogICAgICAgICAgICAgICAgICAgICAgICJDRDQgVEVNIiAgID0gIiMyY2EwMmMiLCAgICAgICMgR3JlZW4KICAgICAgICAgICAgICAgICAgICAgICAiQ0Q0IFRlbXJhL0NUTCIgPSAiI2Q2MjcyOCIsICAgICAgIyBSZWQKICAgICAgICAgICAgICAgICAgICAgICAiVHJlZyIgICAgICA9ICIjOTQ2N2JkIiksICAgICAjIFB1cnBsZQogICAgICAgICAgICAgIHB0LnNpemUgPSAwLjUpICsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNCkpKSArCiAgbGFicyh0aXRsZSA9ICJIZWFsdGh5IENENCBUIENlbGwgUmVmZXJlbmNlIEF0bGFzIiwKICAgICAgIHN1YnRpdGxlID0gIlF1aWVzY2VudCBzdGF0ZXMgb25seSB8IEF6aW11dGggTDIgYW5ub3RhdGlvbiIpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE2KSwKICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTIpKQoKcHJpbnQocDEpCmdnc2F2ZSgiaGVhbHRoeV9jZDRfcmVmZXJlbmNlX3VtYXAucGRmIiwgcDEsIHdpZHRoID0gMTAsIGhlaWdodCA9IDgsIGRwaSA9IDMwMCkKCiMgUE5HIHZlcnNpb24gKGZvciBwcmVzZW50YXRpb25zKQpnZ3NhdmUoImhlYWx0aHlfY2Q0X3JlZmVyZW5jZV91bWFwLnBuZyIsIHAxLCAKICAgICAgIHdpZHRoID0gMTAsIGhlaWdodCA9IDgsIGRwaSA9IDMwMCwgYmcgPSAid2hpdGUiKQoKYGBgCgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KEF6aW11dGgpCgojIFJ1biB0aGlzIGRpYWdub3N0aWMgdG8gdW5kZXJzdGFuZCB3aGF0IGlzIGhhcHBlbmluZwpEZWZhdWx0QXNzYXkoY2xlYW5fb2JqKSA8LSAiUk5BIgoKIyBDaGVjayBTIGFuZCBHMk0gc2NvcmVzIGRpc3RyaWJ1dGlvbgpwMSA8LSBnZ3Bsb3QoY2xlYW5fb2JqQG1ldGEuZGF0YSwKICAgICAgICAgICAgIGFlcyh4ID0gUy5TY29yZSwgZmlsbCA9IGRhdGFzZXQpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDUwLCBhbHBoYSA9IDAuNywgcG9zaXRpb24gPSAiaWRlbnRpdHkiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgY29sb3VyID0gInJlZCIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBmYWNldF93cmFwKH5kYXRhc2V0LCBuY29sID0gMSkgKwogIHRoZW1lX2J3KCkgKwogIGxhYnModGl0bGUgPSAiUyBzY29yZSBkaXN0cmlidXRpb24gcGVyIGRhdGFzZXQiLAogICAgICAgc3VidGl0bGUgPSAiSGVhbHRoeSByZXN0aW5nIFQtY2VsbHMgc2hvdWxkIHBlYWsgYmVsb3cgMCIpCgpwMiA8LSBnZ3Bsb3QoY2xlYW5fb2JqQG1ldGEuZGF0YSwKICAgICAgICAgICAgIGFlcyh4ID0gRzJNLlNjb3JlLCBmaWxsID0gZGF0YXNldCkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNTAsIGFscGhhID0gMC43LCBwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBjb2xvdXIgPSAicmVkIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGZhY2V0X3dyYXAofmRhdGFzZXQsIG5jb2wgPSAxKSArCiAgdGhlbWVfYncoKSArCiAgbGFicyh0aXRsZSA9ICJHMk0gc2NvcmUgZGlzdHJpYnV0aW9uIHBlciBkYXRhc2V0IikKCnAxIHwgcDIKCiMgQ2hlY2sgd2hpY2ggY2VsbCB0eXBlcyBhcmUgZHJpdmluZyBTIHBoYXNlCmNhdCgiUGhhc2UgcGVyIGNlbGwgdHlwZTpcbiIpCnByaW50KHRhYmxlKGNsZWFuX29iaiRQaGFzZSwgY2xlYW5fb2JqJHByZWRpY3RlZC5jZWxsdHlwZS5sMikpCgojIENoZWNrIFMgcGhhc2Ugc2NvcmVzIHBlciBjZWxsIHR5cGUKZ2dwbG90KGNsZWFuX29iakBtZXRhLmRhdGEsCiAgICAgICBhZXMoeCAgICA9IHByZWRpY3RlZC5jZWxsdHlwZS5sMiwKICAgICAgICAgICB5ICAgID0gUy5TY29yZSwKICAgICAgICAgICBmaWxsID0gcHJlZGljdGVkLmNlbGx0eXBlLmwyKSkgKwogIGdlb21fdmlvbGluKHNjYWxlID0gIndpZHRoIiwgdHJpbSA9IFRSVUUpICsKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjA4LCBmaWxsID0gIndoaXRlIiwgb3V0bGllci5zaXplID0gMC4yKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3VyID0gInJlZCIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCAgICA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIGxhYnModGl0bGUgPSAiUy5TY29yZSBwZXIgY2VsbCB0eXBlIOKAlCB2YWx1ZXMgYWJvdmUgMCA9IGN5Y2xpbmciLAogICAgICAgeCA9IE5VTEwsIHkgPSAiUy5TY29yZSIpCmBgYAojIFJlLWVtYmVkIOKAlCBVTUFQIE9ubHkgKFByZXNlcnZlIEV4aXN0aW5nIFJQQ0EgSW50ZWdyYXRpb24pCmBgYHtyIHJlZW1iZWR9CiMgQ1JJVElDQUw6CiMgVGhpcyBvYmplY3QgaXMgYWxyZWFkeSBTQ1Qgbm9ybWFsaXNlZCBhbmQgUlBDQSBpbnRlZ3JhdGVkLgojIFRoZSBpbnRlZ3JhdGVkIGFzc2F5IFBDQSBlbWJlZGRpbmcgSVMgdGhlIGJhdGNoLWNvcnJlY3RlZCBzcGFjZS4KIwojIERPIE5PVCBydW46ICBTY2FsZURhdGEgKHdvdWxkIHJlLXNjYWxlIGFuZCBkZXN0cm95IENDIHJlZ3Jlc3Npb24gZnJvbSBTQ1QpCiMgRE8gTk9UIHJ1bjogIFJ1blBDQSAgICAod291bGQgcmVjb21wdXRlIFBDQSwgZGVzdHJveWluZyBSUENBIGludGVncmF0aW9uCiMgICAgICAgICAgICAgICAgICAgICAgICAgYW5kIGNhdXNpbmcgZGF0YXNldHMgdG8gc2VwYXJhdGUgYWdhaW4pCiMgRE8gTk9UIHJ1bjogIFNDVHJhbnNmb3JtIG9yIEludGVncmF0ZURhdGEKIwojIE9OTFkgcnVuOiAgIEZpbmROZWlnaGJvcnMgYW5kIFJ1blVNQVAgb24gdGhlIEVYSVNUSU5HIHBjYSByZWR1Y3Rpb24KIyAgICAgICAgICAgICBUaGlzIHByZXNlcnZlcyB0aGUgUlBDQS1jb3JyZWN0ZWQgZW1iZWRkaW5nIGFuZCBiYXRjaCBjb3JyZWN0aW9uCgpjYXQoIkF2YWlsYWJsZSByZWR1Y3Rpb25zOlxuIikKcHJpbnQobmFtZXMoY2xlYW5fb2JqQHJlZHVjdGlvbnMpKQoKRGVmYXVsdEFzc2F5KGNsZWFuX29iaikgPC0gImludGVncmF0ZWQiCgojIFVzZSBzYW1lIGRpbXMgYXMgb3JpZ2luYWwgaW50ZWdyYXRpb24KZGltc191c2UgPC0gMToyMAoKIyBSZWJ1aWxkIG5laWdoYm9yIGdyYXBoIG9uIEVYSVNUSU5HIHBjYSBlbWJlZGRpbmcKY2xlYW5fb2JqIDwtIEZpbmROZWlnaGJvcnMoCiAgY2xlYW5fb2JqLAogIHJlZHVjdGlvbiA9ICJwY2EiLAogIGRpbXMgICAgICA9IGRpbXNfdXNlLAogIHZlcmJvc2UgICA9IEZBTFNFCikKCiMgUmVydW4gVU1BUCBvbiBFWElTVElORyBwY2EgZW1iZWRkaW5nCiMgcmV0dXJuLm1vZGVsID0gVFJVRSBpcyBDUklUSUNBTCBmb3IgTWFwUXVlcnkgKG1hbGlnbmFudCBjZWxsIHByb2plY3Rpb24pCmNsZWFuX29iaiA8LSBSdW5VTUFQKAogIGNsZWFuX29iaiwKICByZWR1Y3Rpb24gICAgPSAicGNhIiwKICBkaW1zICAgICAgICAgPSBkaW1zX3VzZSwKICByZXR1cm4ubW9kZWwgPSBUUlVFLAogIHZlcmJvc2UgICAgICA9IEZBTFNFCikKCiMgUmVjbHVzdGVyIGF0IG11bHRpcGxlIHJlc29sdXRpb25zIGZvciBmbGV4aWJpbGl0eQpjbGVhbl9vYmogPC0gRmluZENsdXN0ZXJzKAogIGNsZWFuX29iaiwKICByZXNvbHV0aW9uID0gYygwLjEsIDAuMiwgMC4zLCAwLjQsIDAuNSksCiAgdmVyYm9zZSAgICA9IEZBTFNFCikKCmNhdCgiQ2x1c3RlcnMgYXQgcmVzb2x1dGlvbiAwLjM6IiwKICAgIGxlbmd0aCh1bmlxdWUoY2xlYW5fb2JqJGludGVncmF0ZWRfc25uX3Jlcy4wLjMpKSwgIlxuIikKYGBgCgojIFZlcmlmeSBJbnRlZ3JhdGlvbiBQcmVzZXJ2ZWQKYGBge3IgdmVyaWZ5LWludGVncmF0aW9uLCBmaWcud2lkdGg9MjAsIGZpZy5oZWlnaHQ9N30KIyBDUklUSUNBTCBDSEVDSzogZGF0YXNldHMgc2hvdWxkIGJlIHdlbGwgbWl4ZWQgb24gVU1BUAojIElmIHRoZXkgYXJlIHNlcGFyYXRlZCDigJQgaW50ZWdyYXRpb24gd2FzIGRlc3Ryb3llZCBhbmQgbmVlZHMgdG8gYmUgcmUtZG9uZQoKcDEgPC0gRGltUGxvdChjbGVhbl9vYmosCiAgICAgICAgICAgICAgZ3JvdXAuYnkgPSAiZGF0YXNldCIsCiAgICAgICAgICAgICAgc2h1ZmZsZSAgPSBUUlVFKSArCiAgZ2d0aXRsZSgiRGF0YXNldCBtaXhpbmcg4oCUIHNob3VsZCBiZSB3ZWxsIG1peGVkXG4oaWYgc2VwYXJhdGVkOiByZS1pbnRlZ3JhdGlvbiBuZWVkZWQpIikKCnAyIDwtIERpbVBsb3QoY2xlYW5fb2JqLAogICAgICAgICAgICAgIGdyb3VwLmJ5ID0gInByZWRpY3RlZC5jZWxsdHlwZS5sMiIsCiAgICAgICAgICAgICAgbGFiZWwgICAgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGxhYmVsLmJveCA9IFRSVUUpICsKICBnZ3RpdGxlKCJBemltdXRoIGwyIGxhYmVscyIpCgpwMyA8LSBEaW1QbG90KGNsZWFuX29iaiwKICAgICAgICAgICAgICBncm91cC5ieSA9ICJQaGFzZSIpICsKICBnZ3RpdGxlKCJDZWxsIGN5Y2xlIHBoYXNlIChzaG91bGQgYmUgbWl4ZWQsIG5vdCBzZXBhcmF0ZWQpIikKCnAxIHwgcDIgfCBwMwoKYGBgCgojIFZlcmlmeSBJbnRlZ3JhdGlvbiBQcmVzZXJ2ZWQKYGBge3IgLCBmaWcud2lkdGg9OSwgZmlnLmhlaWdodD02fQoKcDEgCnAyIAoKIyBObyBDRDggY2VsbHMgcmVtYWluCnRhYmxlKGNsZWFuX29iaiRwcmVkaWN0ZWQuY2VsbHR5cGUubDIpCgojIEhpZ2ggY29uZmlkZW5jZSBzY29yZXMKc3VtbWFyeShjbGVhbl9vYmokbWFwcGluZy5zY29yZSkgICAgICAjID4wLjY1IOKckwpzdW1tYXJ5KGNsZWFuX29iaiRwcmVkaWN0ZWQuY2VsbHR5cGUubDIuc2NvcmUpICAjID4wLjc1IOKckwoKYGBgCgoKCgoKCiMgQXppbXV0aCBTY29yZSBBc3Nlc3NtZW50CmBgYHtyIGF6aW11dGgtc2NvcmVzLCBmaWcud2lkdGg9MTQsIGZpZy5oZWlnaHQ9MTZ9CiMgQXNzZXNzIG1hcHBpbmcgYW5kIHByZWRpY3Rpb24gc2NvcmVzIHRvIGRlY2lkZSBpZiBsMiBsYWJlbHMKIyBhcmUgcmVsaWFibGUgZW5vdWdoIGZvciB0cmFqZWN0b3J5IGFuYWx5c2lzCgpwMSA8LSBnZ3Bsb3QoY2xlYW5fb2JqQG1ldGEuZGF0YSwKICAgICAgICAgICAgIGFlcyh4ID0gbWFwcGluZy5zY29yZSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNTAsIGZpbGwgPSAiIzQ0NzJDNCIsIGNvbG91ciA9ICJ3aGl0ZSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLjUsIGNvbG91ciA9ICJyZWQiLAogICAgICAgICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIiwgbGluZXdpZHRoID0gMSkgKwogIHRoZW1lX2J3KCkgKwogIGxhYnModGl0bGUgICAgPSAiTWFwcGluZyBzY29yZSBkaXN0cmlidXRpb24iLAogICAgICAgc3VidGl0bGUgPSAiQ2VsbHMgYmVsb3cgMC41IGFyZSBwb29ybHkgbWFwcGVkIHRvIFBCTUMgcmVmZXJlbmNlIiwKICAgICAgIHggPSAiTWFwcGluZyBzY29yZSIsIHkgPSAiQ291bnQiKQoKcDIgPC0gZ2dwbG90KGNsZWFuX29iakBtZXRhLmRhdGEsCiAgICAgICAgICAgICBhZXMoeCA9IHByZWRpY3RlZC5jZWxsdHlwZS5sMi5zY29yZSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNTAsIGZpbGwgPSAiI0VEN0QzMSIsIGNvbG91ciA9ICJ3aGl0ZSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLjUsIGNvbG91ciA9ICJyZWQiLAogICAgICAgICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIiwgbGluZXdpZHRoID0gMSkgKwogIHRoZW1lX2J3KCkgKwogIGxhYnModGl0bGUgPSAiUHJlZGljdGlvbiBzY29yZSBsMiIsCiAgICAgICB4ID0gIlByZWRpY3Rpb24gc2NvcmUiLCB5ID0gIkNvdW50IikKCnAzIDwtIGdncGxvdChjbGVhbl9vYmpAbWV0YS5kYXRhLAogICAgICAgICAgICAgYWVzKHggICAgPSByZW9yZGVyKHByZWRpY3RlZC5jZWxsdHlwZS5sMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nLnNjb3JlLCBtZWRpYW4pLAogICAgICAgICAgICAgICAgIHkgICAgPSBtYXBwaW5nLnNjb3JlLAogICAgICAgICAgICAgICAgIGZpbGwgPSBwcmVkaWN0ZWQuY2VsbHR5cGUubDIpKSArCiAgZ2VvbV92aW9saW4oc2NhbGUgPSAid2lkdGgiLCB0cmltID0gVFJVRSkgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMDgsIGZpbGwgPSAid2hpdGUiLCBvdXRsaWVyLnNpemUgPSAwLjIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLjUsIGNvbG91ciA9ICJyZWQiLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggICAgID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgc2l6ZSA9IDkpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIGxhYnModGl0bGUgPSAiTWFwcGluZyBzY29yZSBwZXIgY2VsbCB0eXBlIiwgeCA9IE5VTEwsIHkgPSAiTWFwcGluZyBzY29yZSIpCgpwNCA8LSBnZ3Bsb3QoY2xlYW5fb2JqQG1ldGEuZGF0YSwKICAgICAgICAgICAgIGFlcyh4ICAgID0gcmVvcmRlcihwcmVkaWN0ZWQuY2VsbHR5cGUubDIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlZGljdGVkLmNlbGx0eXBlLmwyLnNjb3JlLCBtZWRpYW4pLAogICAgICAgICAgICAgICAgIHkgICAgPSBwcmVkaWN0ZWQuY2VsbHR5cGUubDIuc2NvcmUsCiAgICAgICAgICAgICAgICAgZmlsbCA9IHByZWRpY3RlZC5jZWxsdHlwZS5sMikpICsKICBnZW9tX3Zpb2xpbihzY2FsZSA9ICJ3aWR0aCIsIHRyaW0gPSBUUlVFKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4wOCwgZmlsbCA9ICJ3aGl0ZSIsIG91dGxpZXIuc2l6ZSA9IDAuMikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuNSwgY29sb3VyID0gInJlZCIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCAgICAgPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCBzaXplID0gOSksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgbGFicyh0aXRsZSA9ICJQcmVkaWN0aW9uIHNjb3JlIHBlciBjZWxsIHR5cGUgKGwyKSIsCiAgICAgICB4ID0gTlVMTCwgeSA9ICJQcmVkaWN0aW9uIHNjb3JlIikKCihwMSB8IHAyKSAvIHAzIC8gcDQKCiMgU2NvcmVzIG9uIFVNQVAKcDUgPC0gRmVhdHVyZVBsb3QoY2xlYW5fb2JqLAogICAgICAgICAgICAgICAgICBmZWF0dXJlcyAgID0gIm1hcHBpbmcuc2NvcmUiLAogICAgICAgICAgICAgICAgICBjb2xzICAgICAgID0gYygiZ3JleTkwIiwiI0MwMDAwMCIpLAogICAgICAgICAgICAgICAgICBtaW4uY3V0b2ZmID0gMCwgbWF4LmN1dG9mZiA9IDEpICsKICBnZ3RpdGxlKCJNYXBwaW5nIHNjb3JlIG9uIFVNQVBcbihyZWQgPSBoaWdoIGNvbmZpZGVuY2UpIikKCnA2IDwtIEZlYXR1cmVQbG90KGNsZWFuX29iaiwKICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgICA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIuc2NvcmUiLAogICAgICAgICAgICAgICAgICBjb2xzICAgICAgID0gYygiZ3JleTkwIiwiIzQ0NzJDNCIpLAogICAgICAgICAgICAgICAgICBtaW4uY3V0b2ZmID0gMCwgbWF4LmN1dG9mZiA9IDEpICsKICBnZ3RpdGxlKCJQcmVkaWN0aW9uIHNjb3JlIGwyIG9uIFVNQVBcbihibHVlID0gaGlnaCBjb25maWRlbmNlKSIpCgpwNSB8IHA2CmBgYApgYGB7cn0KCiMgV29ya3MgaW1tZWRpYXRlbHkKcF9hbm5vdCA8LSBkb19EaW1QbG90KAogIHNhbXBsZSA9IGNsZWFuX29iaiwKICBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiLAogIGxhYmVsID0gRkFMU0UsICAjIOKGkCBGaXg6IGRpc2FibGUgbGFiZWxzCiAgcGxvdC50aXRsZSA9ICJBemltdXRoIEwyIEFubm90YXRpb24iCikKcF9hbm5vdAoKYGBgCgoKCgpgYGB7ciwgZmlnLndpZHRoPTE0LCBmaWcuaGVpZ2h0PTE2fQpsaWJyYXJ5KHBhdGNod29yaykKCiMgNC1wYW5lbCByZXBvcnQgKGV4YWN0IFNDcHViciByZXBsaWNhKQpwMSA8LSBGZWF0dXJlUGxvdChjbGVhbl9vYmosIGZlYXR1cmVzID0gIm1hcHBpbmcuc2NvcmUiKSArIAogICAgICBnZ3RpdGxlKCJBemltdXRoIE1hcHBpbmcgU2NvcmUiKQoKcDIgPC0gRmVhdHVyZVBsb3QoY2xlYW5fb2JqLCBmZWF0dXJlcyA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIuc2NvcmUiKSArIAogICAgICBnZ3RpdGxlKCJBemltdXRoIEwyIFNjb3JlIikKCnAzIDwtIERpbVBsb3QoY2xlYW5fb2JqLCBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiLCBsYWJlbCA9IFRSVUUpICsKICAgICAgZ2d0aXRsZSgiTG9jYWwgQ2x1c3RlcmluZyB2cyBBemltdXRoIikKCnA0IDwtIERpbVBsb3QoY2xlYW5fb2JqLCByZWR1Y3Rpb24gPSAicmVmLnVtYXAiLCAKICAgICAgICAgICAgICBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiLCBsYWJlbCA9IFRSVUUpICsKICAgICAgZ2d0aXRsZSgiUEJNQyBSZWZlcmVuY2UgUHJvamVjdGlvbiIpCgojIEZpbmFsIHJlcG9ydAoocDEgfCBwMikgLyAocDMgfCBwNCkKZ2dzYXZlKCJhemltdXRoX21hbnVhbF9yZXBvcnQucG5nIiwgd2lkdGggPSAxNiwgaGVpZ2h0ID0gMTAsIGRwaSA9IDMwMCkKCgoKYGBgCgoKCgpgYGB7cn0KbGlicmFyeShkcGx5cikKCnByb3BfdGFibGUgPC0gY2xlYW5fb2JqQG1ldGEuZGF0YSAlPiUKICBkcGx5cjo6Y291bnQocHJlZGljdGVkLmNlbGx0eXBlLmwyKSAlPiUgICMg4oaQIEV4cGxpY2l0IGRwbHlyOjoKICBtdXRhdGUoUGVyY2VudCA9IHJvdW5kKG4gLyBzdW0obikgKiAxMDAsIDEpKSAlPiUKICBhcnJhbmdlKGRlc2MobikpCgpwcmludChwcm9wX3RhYmxlKQp3cml0ZS5jc3YocHJvcF90YWJsZSwgImNlbGx0eXBlX3Byb3BvcnRpb25zLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQoKYGBgCgoKCiMgRGVjaXNpb24gVGFibGUg4oCUIFNob3VsZCBXZSBVc2UgbDIgTGFiZWxzIGZvciBUcmFqZWN0b3J5PwpgYGB7ciBkZWNpc2lvbi10YWJsZX0KZGVjaXNpb25fZGYgPC0gY2xlYW5fb2JqQG1ldGEuZGF0YSAlPiUKICBncm91cF9ieShwcmVkaWN0ZWQuY2VsbHR5cGUubDIpICU+JQogIHN1bW1hcmlzZSgKICAgIG5fY2VsbHMgICAgICAgID0gbigpLAogICAgbWVkaWFuX21hcHBpbmcgPSByb3VuZChtZWRpYW4obWFwcGluZy5zY29yZSwgbmEucm0gPSBUUlVFKSwgMyksCiAgICBtZWRpYW5fcHJlZCAgICA9IHJvdW5kKG1lZGlhbihwcmVkaWN0ZWQuY2VsbHR5cGUubDIuc2NvcmUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpLCAzKSwKICAgIHBjdF9hYm92ZV8wLjUgID0gcm91bmQobWVhbihtYXBwaW5nLnNjb3JlID49IDAuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSAqIDEwMCwgMSksCiAgICAuZ3JvdXBzID0gImRyb3AiCiAgKSAlPiUKICBhcnJhbmdlKGRlc2Mobl9jZWxscykpCgpjYXQoIj09PSBGdWxsIGRlY2lzaW9uIHRhYmxlID09PVxuIikKcHJpbnQoZGVjaXNpb25fZGYpCgprZXlfc3RhdGVzIDwtIGMoIkNENCBOYWl2ZSIsIkNENCBUQ00iLCJDRDQgVEVNIiwiQ0Q0IFRFTVJBL0NUTCIsIlRyZWciKQpjYXQoIlxuPT09IEtleSB0cmFqZWN0b3J5IHN0YXRlcyA9PT1cbiIpCnByaW50KGRlY2lzaW9uX2RmICU+JSBmaWx0ZXIocHJlZGljdGVkLmNlbGx0eXBlLmwyICVpbiUga2V5X3N0YXRlcykpCgpjYXQoIlxuPT09IERlY2lzaW9uIHJ1bGUgPT09XG4iKQpjYXQoIklmIG1lZGlhbiBtYXBwaW5nIHNjb3JlID4gMC41IGZvciBDRDQgTmFpdmUgKyBDRDQgVENNICsgVHJlZzpcbiIpCmNhdCgi4oaSIFByb2NlZWQgd2l0aCBBemltdXRoIGwyIGxhYmVscyBmb3IgdHJhamVjdG9yeVxuIikKY2F0KCJJZiBtZWRpYW4gbWFwcGluZyBzY29yZSA8IDAuNSBmb3Iga2V5IHN0YXRlczpcbiIpCmNhdCgi4oaSIEZhbGwgYmFjayB0byBzZXVyYXRfY2x1c3RlcnMgd2l0aCBtYW51YWwgbWFya2VyIHZhbGlkYXRpb25cbiIpCmBgYAoKCgojIFNhdmUgRmluYWwgUmVmZXJlbmNlIE9iamVjdApgYGB7ciBzYXZlfQpEZWZhdWx0QXNzYXkoY2xlYW5fb2JqKSA8LSAiaW50ZWdyYXRlZCIKCnNhdmVSRFMoCiAgY2xlYW5fb2JqLAogICJDRDRfcmVmZXJlbmNlX2NsZWFuX0F6aW11dGhfcmVhZHlfZm9yX1NsaW5nc2hvdC5yZHMiLAogIGNvbXByZXNzID0gRkFMU0UgICAjIGZhc3RlciBmb3IgbGFyZ2Ugb2JqZWN0cwopCgpjYXQoIuKchSBTYXZlZDoiLCBuY29sKGNsZWFuX29iaiksICJjZWxsc1xuIikKCmBgYAoKCgoKYGBgCg==