1 1. Libraries & Global Settings

suppressPackageStartupMessages({
  library(Seurat)
  library(monocle3)
  library(SeuratWrappers)
  library(dplyr)
  library(tidyr)
  library(tibble)
  library(ggplot2)
  library(patchwork)
  library(RColorBrewer)
  library(viridis)
  library(ggridges)
  library(ggrepel)
  library(Matrix)
  library(scales)
  library(pheatmap)
  library(cowplot)
  library(igraph)
})

set.seed(1234)
options(future.globals.maxSize = 8e9)

# ── Consistent colour palettes used throughout ──────────────────────────────
azimuth_l2_colors <- c(
  "CD4 Naive"     = "#2166AC",
  "CD4 TCM"       = "#74ADD1",
  "CD4 TEM"       = "#FEE090",
  "CD4 Temra/CTL" = "#D73027",
  "Treg"          = "#762A83"
)

bin_colors <- c(
  "Naive-like"  = "#2166AC",
  "TCM-like"    = "#74ADD1",
  "Treg-like"   = "#762A83",
  "TEM-like"    = "#FEE090",
  "Temra-like"  = "#D73027"
)

line_colors <- setNames(
  colorRampPalette(brewer.pal(8, "Dark2"))(7),
  paste0("L", 1:7)
)

# ── Output directories ───────────────────────────────────────────────────────
out_dir     <- "results/Mapping_Pipeline_v3"
fig_dir_qc  <- file.path(out_dir, "QC_Figures")
fig_dir_ms  <- file.path(out_dir, "Manuscript_Figures")
fig_dir_pdf <- file.path(out_dir, "Manuscript_Figures/PDF")

for (d in c(out_dir, fig_dir_qc, fig_dir_ms, fig_dir_pdf))
  dir.create(d, recursive = TRUE, showWarnings = FALSE)

# ── Save helper ──────────────────────────────────────────────────────────────
save_fig <- function(p, name, subdir = fig_dir_qc, w = 14, h = 9) {
  png_path <- file.path(subdir, paste0(name, ".png"))
  pdf_path <- file.path(fig_dir_pdf, paste0(name, ".pdf"))
  ggsave(png_path, plot = p, width = w, height = h, dpi = 300, bg = "white")
  if (subdir == fig_dir_ms)
    ggsave(pdf_path, plot = p, width = w, height = h, device = cairo_pdf)
  invisible(p)
}

cat("=== Environment ready ===\n")
=== Environment ready ===
cat("Seurat  :", as.character(packageVersion("Seurat")),  "\n")
Seurat  : 5.4.0 
cat("Monocle3:", as.character(packageVersion("monocle3")), "\n")
Monocle3: 1.4.26 
cat("Output  :", out_dir, "\n")
Output  : results/Mapping_Pipeline_v3 

2 2. Load & Validate Reference Object

# ════════════════════════════════════════════════════════════════════════════
# Load the Slingshot-ready healthy reference object.
# This object was confirmed to have:
#   ✅ UMAP model (intact — will NOT be replaced)
#   ✅ predicted.celltype.l2 (Azimuth l2)
#   ✅ cell_type, seurat_clusters, percent.mt, S.Score, G2M.Score
#   ✅ SCT assay (HVGs=2902, per-sample models)
#   ✅ integrated PCA 50 dims (intact — will NOT be replaced)
#   ✅ No proliferating cells
# ════════════════════════════════════════════════════════════════════════════

reference_integrated <- readRDS(
  "../../1-Final_Custom_MST_Monocle3_Trajectory_and_mapping/CD4_reference_clean_Azimuth_ready_for_Slingshot.rds"
)

cat("=== Reference object loaded ===\n")
=== Reference object loaded ===
cat("Cells     :", ncol(reference_integrated), "\n")
Cells     : 11466 
cat("Assays    :", paste(names(reference_integrated@assays), collapse = ", "), "\n")
Assays    : RNA, ADT, prediction.score.celltype.l1, prediction.score.celltype.l2, prediction.score.celltype.l3, SCT, integrated 
cat("Reductions:", paste(names(reference_integrated@reductions), collapse = ", "), "\n")
Reductions: pca, umap, integrated_dr, ref.umap 
# ── Hard stops: essential metadata must be present ───────────────────────────
stopifnot(
  "predicted.celltype.l2 missing" =
    "predicted.celltype.l2" %in% colnames(reference_integrated@meta.data),
  "cell_type missing" =
    "cell_type" %in% colnames(reference_integrated@meta.data),
  "umap reduction missing" =
    "umap" %in% names(reference_integrated@reductions),
  "pca reduction missing" =
    "pca" %in% names(reference_integrated@reductions)
)

# Proliferating cell check
prolif_check <- any(grepl("Prolif|prolif|cycling",
                            reference_integrated$predicted.celltype.l2,
                            ignore.case = TRUE))
if (prolif_check) stop("Proliferating cells detected — remove before proceeding.")
cat("\n✅ No proliferating cells\n")

✅ No proliferating cells
# ── Extend palette for any extra labels ─────────────────────────────────────
ref_l2_labels <- unique(as.character(reference_integrated$predicted.celltype.l2))
extra <- setdiff(ref_l2_labels, names(azimuth_l2_colors))
if (length(extra) > 0) {
  extra_colors <- setNames(
    colorRampPalette(brewer.pal(8, "Set2"))(length(extra)), extra)
  azimuth_l2_colors <- c(azimuth_l2_colors, extra_colors)
}

# ── QC Figure 1: Incoming reference UMAP (Azimuth l2 + cell_type) ───────────
p_in_l2 <- DimPlot(
  reference_integrated,
  group.by  = "predicted.celltype.l2",
  reduction = "umap",
  label     = TRUE, repel = TRUE, label.size = 3.5
) +
  scale_color_manual(values = azimuth_l2_colors, na.value = "grey70") +
  ggtitle("Incoming reference — Azimuth l2") +
  theme_classic() + NoLegend()

p_in_ct <- DimPlot(
  reference_integrated,
  group.by  = "cell_type",
  reduction = "umap",
  label     = TRUE, repel = TRUE, label.size = 3
) +
  ggtitle("Incoming reference — cell_type (original labels)") +
  theme_classic() + NoLegend()

qc1 <- p_in_l2 | p_in_ct
qc1

save_fig(qc1, "QC1_incoming_reference_UMAP", w = 18, h = 8)

cat("\nAzimuth l2 distribution:\n")

Azimuth l2 distribution:
print(table(reference_integrated$predicted.celltype.l2))

    CD4 Naive       CD4 TCM       CD4 TEM CD4 Temra/CTL          Treg 
         2037          9067           145            10           207 
cat("\ncell_type distribution:\n")

cell_type distribution:
print(table(reference_integrated$cell_type))

   CD4 Tnaive (CCR7+SELL+TCF7+)          CD4 TCM (CD161+/IL7R+)        CD4 TCM (CCR4+/Th2-like) CD4 CTL/Temra (GZMK+GZMA+CCL5+) 
                           5479                            3994                             522                             490 
      CD4 TEM (NF-kB activated)   CD4 Treg (FOXP3+Helios+CD25+)         CD4 Tnaive-RTE (IGF1R+) 
                            412                             336                             233 

3 3. Reference: Verify Existing Integration (No Rebuild)

Design decision: The reference object was already integrated across 3 donors using Seurat RPCA (integrated assay, 50-dim PCA, UMAP with frozen model). We do not re-run SCTransform or rebuild the UMAP. Doing so destroys the biology — cells scatter into 18+ clusters because SCT on a pre-integrated object re-introduces batch variation that CCA already removed.

What we use instead: - reference.reduction = "pca" — the existing integrated PCA (50 dims) - reduction.model = "umap" — the existing frozen UMAP model - Malignant cells are processed with npcs = 50 to match this dimensionality

The SCT assay on the reference (HVGs = 2902) is used only for feature intersection with the query — not for rebuilding the PCA.

# Keep integrated assay active (PCA was built on this)
DefaultAssay(reference_integrated) <- "integrated"

cat("=== Reference integration summary ===\n")
=== Reference integration summary ===
cat("Active assay   :", DefaultAssay(reference_integrated), "\n")
Active assay   : integrated 
cat("PCA assay used :", reference_integrated@reductions$pca@assay.used, "\n")
PCA assay used : integrated 
cat("PCA dims       :", ncol(Embeddings(reference_integrated, "pca")), "\n")
PCA dims       : 50 
cat("SCT HVGs       :", length(VariableFeatures(reference_integrated, assay = "SCT")), "\n")
SCT HVGs       : 0 
cat("SCT models     :", length(reference_integrated@assays$SCT@SCTModel.list),
    "(per-sample = correct)\n")
SCT models     : 3 (per-sample = correct)
# HARD STOP: UMAP model must be intact — never re-run RunUMAP
stopifnot(
  "UMAP model missing — MapQuery will fail" =
    !is.null(reference_integrated@reductions$umap@misc$model)
)
cat("UMAP model     : intact\n")
UMAP model     : intact
cat("Donors         :", nlevels(factor(reference_integrated$orig.ident)), "\n")
Donors         : 3 
print(table(reference_integrated$orig.ident))

CD4T_10x_S1 CD4T_10x_S2    CD4T_lab 
       3379        3221        4866 
# Define junk gene pattern (used later in §5 for query HVG filtering)
junk_pattern <- paste0(
  "^MT-|^RPL|^RPS|",
  "^HSP|^HSPA|^HSPB|^HSPD|^HSPE|^HSPH|",
  "^SNHG|MALAT1|NEAT1|XIST|^HIST"
)

# Recompute clusters on existing integrated PCA — for Monocle3 CDS slot ONLY
# Does NOT touch the UMAP or PCA
reference_integrated <- FindNeighbors(
  reference_integrated,
  reduction  = "pca",
  dims       = 1:50,
  graph.name = "integrated_snn",
  verbose    = FALSE
)
reference_integrated <- FindClusters(
  reference_integrated,
  resolution  = 0.3,
  graph.name  = "integrated_snn",
  verbose     = FALSE
)
cat("\nClusters (res=0.3):", nlevels(reference_integrated$seurat_clusters), "\n")

Clusters (res=0.3): 7 
# QC Figure 2: confirm biology is preserved on the intact UMAP
p_umap_l2 <- DimPlot(
  reference_integrated,
  group.by  = "predicted.celltype.l2",
  reduction = "umap",
  label     = TRUE, repel = TRUE, label.size = 4
) +
  scale_color_manual(values = azimuth_l2_colors, na.value = "grey70") +
  ggtitle("Reference UMAP (integrated) — Azimuth l2") +
  theme_classic() + NoLegend()

p_umap_cl <- DimPlot(
  reference_integrated,
  group.by  = "seurat_clusters",
  reduction = "umap",
  label     = TRUE, label.size = 4
) +
  ggtitle("Reference UMAP — Clusters (res=0.3) for Monocle3 CDS") +
  theme_classic() + NoLegend()

p_umap_ct <- DimPlot(
  reference_integrated,
  group.by  = "cell_type",
  reduction = "umap",
  label     = TRUE, repel = TRUE, label.size = 3
) +
  ggtitle("Reference UMAP — cell_type") +
  theme_classic() + NoLegend()

qc2 <- (p_umap_l2 | p_umap_cl) / p_umap_ct
qc2

save_fig(qc2, "QC2_reference_UMAP_verified", w = 18, h = 14)

# QC: Key marker feature plots on intact UMAP
DefaultAssay(reference_integrated) <- "SCT"
marker_genes <- c("CCR7", "SELL", "TCF7", "IL7R",
                  "GZMK", "GZMA", "GZMB", "PRF1",
                  "FOXP3", "IL2RA", "IKZF2",
                  "GNLY", "NKG7")
available_markers <- intersect(marker_genes, rownames(reference_integrated))
p_markers <- FeaturePlot(
  reference_integrated,
  features  = available_markers,
  reduction = "umap",
  ncol      = 5,
  cols      = c("lightgrey", "#D73027"),
  order     = TRUE
) &
  theme_classic() &
  theme(plot.title = element_text(size = 9, face = "bold"))
p_markers

save_fig(p_markers, "QC3_reference_marker_features", w = 20, h = 10)

DefaultAssay(reference_integrated) <- "integrated"
cat("\nReference verified — UMAP and PCA intact, biology preserved\n")

Reference verified — UMAP and PCA intact, biology preserved

3.1 Validate using known markers

DefaultAssay(reference_integrated) <- "RNA"

# Order matches trajectory: Naive → TCM → Treg branch / TEM → Temra
azimuth_l2_order <- c(
  "CD4 Naive",
  "CD4 TCM",
  "Treg",
  "CD4 TEM",
  "CD4 Temra/CTL"
)

# Only keep l2 labels present in the object
azimuth_l2_order <- intersect(
  azimuth_l2_order,
  unique(reference_integrated$predicted.celltype.l2)
)

reference_integrated@meta.data$l2_factor <- factor(
  reference_integrated$predicted.celltype.l2,
  levels = azimuth_l2_order
)
Idents(reference_integrated) <- "l2_factor"

panel_genes <- c(
  # Naive
  "CCR7","LEF1","TCF7","SELL","KLF2","SATB1","IL7R","CD27","MAL",
  # TCM
  "S100A4","AQP3","LTB","ITGB1","CD44","CCR4",
  # Shared activation
  "CD69","LMNA",
  # TEM
  "GZMK","CCL5","EOMES","CXCR3","HOPX","CXCR4","IFNG","TNF","CCR5",
  # Temra/CTL
  "GZMB","GZMA","PRF1","NKG7","CX3CR1","FGFBP2","GNLY","TBX21","ZEB2",
  "FCGR3A","KLRG1","NR4A2",
  # Treg
  "FOXP3","IL2RA","IKZF2","IKZF4","TIGIT","RTKN2","TNFRSF18","CTLA4",
  # Co-inhibitory — Treg suppressive machinery
  "PDCD1","HAVCR2","LAG3"
)

panel_genes <- unique(intersect(panel_genes, rownames(reference_integrated)))
cat("Genes found:", length(panel_genes), "/", length(unique(c(
  "CCR7","LEF1","TCF7","SELL","KLF2","SATB1","IL7R","CD27","MAL",
  "S100A4","AQP3","LTB","ITGB1","CD44","CCR4","CD69","LMNA",
  "GZMK","CCL5","EOMES","CXCR3","HOPX","CXCR4","IFNG","TNF","CCR5",
  "GZMB","GZMA","PRF1","NKG7","CX3CR1","FGFBP2","GNLY","TBX21","ZEB2",
  "FCGR3A","KLRG1","NR4A2",
  "FOXP3","IL2RA","IKZF2","IKZF4","TIGIT","RTKN2","TNFRSF18","CTLA4",
  "PDCD1","HAVCR2","LAG3"
))), "\n")
Genes found: 49 / 49 
p_dotplot_l2 <- DotPlot(
  reference_integrated,
  features  = panel_genes,
  group.by  = "l2_factor",
  cols      = c("lightgrey", "#d62728"),
  dot.scale = 5,
  scale     = TRUE,
  col.min   = -1.5,
  col.max   = 2.5
) +
  RotatedAxis() +
  coord_flip() +
  scale_color_gradient2(
    low      = "lightgrey",
    mid      = "#fee090",
    high     = "#d62728",
    midpoint = 0.5,
    name     = "Avg Expression"
  ) +
  theme(
    axis.text.x     = element_text(size = 9, face = "bold"),
    axis.text.y     = element_text(size = 7.5),
    plot.title      = element_text(size = 13, face = "bold"),
    plot.subtitle   = element_text(size = 9, colour = "grey40"),
    legend.position = "bottom"
  ) +
  labs(
    title    = "Marker gene expression — Azimuth l2 cell states",
    subtitle = ""
  )

print(p_dotplot_l2)

save_fig(p_dotplot_l2, "QC_DotPlot_AzimuthL2_markers", w = 10, h = 12)

# Restore assay and idents
DefaultAssay(reference_integrated) <- "integrated"
Idents(reference_integrated) <- "predicted.celltype.l2"

4 4. Monocle3 Trajectory — Single Run

Critical: learn_graph and order_cells run once. The resulting monocle3_pseudotime column is never overwritten. This is the exact value MapQuery transfers to Sézary cells.

# Metadata
colData(cds)$predicted.celltype.l2 <- reference_integrated$predicted.celltype.l2
if ("cell_type" %in% colnames(reference_integrated@meta.data))
  colData(cds)$cell_type <- reference_integrated$cell_type

cat("CDS built:", ncol(cds), "cells\n")
CDS built: 11466 cells
cat("Partitions:", nlevels(partitions(cds)), "(should be 1)\n")
Partitions: 1 (should be 1)
# ── Learn principal graph ────────────────────────────────────────────────────
set.seed(1234)

cds <- learn_graph(
  cds,
  use_partition       = FALSE,
  close_loop          = FALSE,
  learn_graph_control = list(
    minimal_branch_len  = 10,
    ncenter             = 900,
    orthogonal_proj_tip = FALSE
  ),
  verbose = FALSE
)



n_nodes  <- length(igraph::V(principal_graph(cds)$UMAP))
n_branch <- sum(igraph::degree(principal_graph(cds)$UMAP) > 2)

cat("\n✅ Principal graph learned\n")

✅ Principal graph learned
cat("Nodes       :", n_nodes, "\n")
Nodes       : 403 
cat("Branch points:", n_branch, "(expected 1-3 for effector axis + Treg branch)\n")
Branch points: 20 (expected 1-3 for effector axis + Treg branch)
if (n_branch == 0) {
  stop("No branch point found — Treg lineage not separated.\n",
       "Fix: re-run with minimal_branch_len = 5")
} else if (n_branch > 5) {
  warning(paste("Many branch points:", n_branch,
                "— consider minimal_branch_len = 15"))
}

# ── QC: Graph coloured by cell type ─────────────────────────────────────────
p_graph_l2 <- plot_cells(
  cds,
  color_cells_by        = "predicted.celltype.l2",
  label_cell_groups     = FALSE,
  show_trajectory_graph = TRUE,
  cell_size             = 0.7,
  trajectory_graph_color = "black",
  trajectory_graph_segment_size = 1.2
) +
  scale_color_manual(values = azimuth_l2_colors, na.value = "grey70") +
  ggtitle(sprintf("Principal graph — %d nodes, %d branch points", n_nodes, n_branch)) +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"))

p_graph_l2

save_fig(p_graph_l2, "QC4_principal_graph_cell_type", w = 10, h = 8)
# ── Root selection: centroid of CD4 Naive cells ──────────────────────────────
naive_cells <- colnames(cds)[
  grepl("naive|Naive|TN$", colData(cds)$predicted.celltype.l2, ignore.case = TRUE)]
cat("Naive cells for root centroid:", length(naive_cells), "\n")
Naive cells for root centroid: 2037 
stopifnot("No Naive cells found" = length(naive_cells) > 0)

naive_umap     <- Embeddings(reference_integrated, "umap")[naive_cells, ]
naive_centroid <- colMeans(naive_umap)
cat(sprintf("Naive centroid: UMAP1=%.3f, UMAP2=%.3f\n",
            naive_centroid[1], naive_centroid[2]))
Naive centroid: UMAP1=-3.437, UMAP2=-0.644
pr_nodes   <- t(cds@principal_graph_aux[["UMAP"]]$dp_mst)
node_dists <- rowSums(
  (pr_nodes - matrix(naive_centroid, nrow = nrow(pr_nodes), ncol = 2, byrow = TRUE))^2
)
root_node <- names(which.min(node_dists))
cat("Root node selected:", root_node, "\n")
Root node selected: Y_19 
# ════════════════════════════════════════════════════════════════════════════
# ORDER CELLS — monocle3_pseudotime computed here, NEVER overwritten
# ════════════════════════════════════════════════════════════════════════════
cds <- order_cells(cds, root_pr_nodes = root_node)

# Store in reference object
reference_integrated$monocle3_pseudotime <- pseudotime(cds)
reference_integrated$monocle3_pseudotime[
  !is.finite(reference_integrated$monocle3_pseudotime)] <- NA

cat("\n✅ monocle3_pseudotime stored in reference_integrated (FROZEN)\n")

✅ monocle3_pseudotime stored in reference_integrated (FROZEN)
print(summary(reference_integrated$monocle3_pseudotime[
  is.finite(reference_integrated$monocle3_pseudotime)]))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   4.545  11.180  12.310  18.214  29.034 
# ── Topology validation — HARD STOPS ────────────────────────────────────────
pt_order <- reference_integrated@meta.data %>%
  filter(is.finite(monocle3_pseudotime)) %>%
  group_by(predicted.celltype.l2) %>%
  summarise(
    n      = n(),
    med_pt = round(median(monocle3_pseudotime, na.rm = TRUE), 3),
    .groups = "drop"
  ) %>%
  arrange(med_pt)

cat("\n=== State median pseudotimes (topology check) ===\n")

=== State median pseudotimes (topology check) ===
print(pt_order)

get_med <- function(state) {
  v <- pt_order$med_pt[pt_order$predicted.celltype.l2 == state]
  if (length(v) == 0) stop(paste("State not found in topology:", state))
  v
}
naive_med <- get_med("CD4 Naive")
tcm_med   <- get_med("CD4 TCM")
treg_med  <- get_med("Treg")
tem_med   <- get_med("CD4 TEM")
temra_med <- get_med("CD4 Temra/CTL")

if (naive_med >= tcm_med)
  stop(sprintf("TOPOLOGY ERROR: Naive(%.2f) >= TCM(%.2f)", naive_med, tcm_med))
if (tcm_med >= tem_med)
  stop(sprintf("TOPOLOGY ERROR: TCM(%.2f) >= TEM(%.2f)", tcm_med, tem_med))
if (tem_med >= temra_med)
  stop(sprintf("TOPOLOGY ERROR: TEM(%.2f) >= Temra(%.2f)", tem_med, temra_med))
if (treg_med >= tem_med)
  stop(sprintf(
    "TOPOLOGY ERROR: Treg(%.2f) >= TEM(%.2f) — Treg must branch from TCM\n",
    treg_med, tem_med))

cat(sprintf(
  "\n✅ Topology confirmed: Naive(%.3f) < TCM(%.3f) < Treg(%.3f) < TEM(%.3f) < Temra(%.3f)\n",
  naive_med, tcm_med, treg_med, tem_med, temra_med
))

✅ Topology confirmed: Naive(3.389) < TCM(13.027) < Treg(18.114) < TEM(26.890) < Temra(27.350)
# ── QC Figure: Pseudotime on UMAP ────────────────────────────────────────────
p_pt_graph <- plot_cells(
  cds,
  color_cells_by        = "pseudotime",
  label_cell_groups     = FALSE,
  show_trajectory_graph = TRUE,
  cell_size             = 0.7,
  trajectory_graph_color = "black",
  trajectory_graph_segment_size = 1.2
) +
  scale_color_viridis_c(option = "plasma", name = "Pseudotime") +
  ggtitle("Monocle3 Pseudotime — Root = CD4 Naive") +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"))

p_pt_seurat <- FeaturePlot(
  reference_integrated,
  features  = "monocle3_pseudotime",
  reduction = "umap"
) +
  scale_color_viridis_c(option = "plasma", name = "Pseudotime") +
  ggtitle("Pseudotime on Reference UMAP (Seurat)") +
  theme_classic()

qc3 <- p_pt_graph | p_pt_seurat
qc3

save_fig(qc3, "QC5_monocle3_pseudotime_UMAP", w = 18, h = 8)

# ── QC: Pseudotime distribution by state ─────────────────────────────────────
pt_meta <- reference_integrated@meta.data %>%
  filter(is.finite(monocle3_pseudotime)) %>%
  mutate(predicted.celltype.l2 = factor(
    predicted.celltype.l2,
    levels = c("CD4 Naive","CD4 TCM","Treg","CD4 TEM","CD4 Temra/CTL")))

p_pt_violin <- ggplot(pt_meta,
                      aes(x = predicted.celltype.l2,
                          y = monocle3_pseudotime,
                          fill = predicted.celltype.l2)) +
  geom_violin(scale = "width", trim = TRUE, alpha = 0.85) +
  geom_boxplot(width = 0.12, fill = "white", outlier.size = 0.5) +
  scale_fill_manual(values = azimuth_l2_colors) +
  geom_hline(yintercept = c(naive_med, tcm_med, treg_med, tem_med, temra_med),
             linetype = "dashed", colour = "black", linewidth = 0.4, alpha = 0.5) +
  theme_classic() +
  theme(axis.text.x = element_text(angle = 30, hjust = 1),
        legend.position = "none") +
  labs(
    title = "Reference Pseudotime by State (Topology Confirmed)",
    subtitle = sprintf("Naive=%.3f | TCM=%.3f | Treg=%.3f | TEM=%.3f | Temra=%.3f",
                       naive_med, tcm_med, treg_med, tem_med, temra_med),
    x = NULL, y = "monocle3_pseudotime"
  )
p_pt_violin

save_fig(p_pt_violin, "QC6_pseudotime_by_state_violin", w = 10, h = 7)

5 5. Sézary Cells: Per-Line SCTransform

All_samples_Merged <- readRDS(
  "../../../../../1-Seurat_RDS_OBJECT_FINAL/All_samples_Merged_with_Renamed_Clusters_Cell_state-03-12-2025.rds.rds"
)

All_samples_Merged$Group <- ifelse(
  All_samples_Merged$cell_line %in% paste0("L", 1:7),
  "MalignantCD4T", "Other"
)

MalignantCD4T_raw <- subset(All_samples_Merged, subset = Group == "MalignantCD4T")
cat("Sézary cells loaded:", ncol(MalignantCD4T_raw), "\n")
Sézary cells loaded: 40695 
print(table(MalignantCD4T_raw$cell_line))

           L1            L2            L3            L4            L5            L6            L7 CD4Tcells_lab CD4Tcells_10x 
         5825          5935          6428          6006          6022          5148          5331             0             0 
rm(All_samples_Merged); gc()
             used    (Mb) gc trigger    (Mb)   max used    (Mb)
Ncells   10262648   548.1   15749107   841.1   15749107   841.1
Vcells 1465774711 11183.0 3187287748 24317.1 2707109753 20653.7
# ── QC Figure: Cell count per line ────────────────────────────────────────────
line_df <- as.data.frame(table(MalignantCD4T_raw$cell_line))
colnames(line_df) <- c("Line", "Cells")

p_cell_count <- ggplot(line_df, aes(x = Line, y = Cells, fill = Line)) +
  geom_bar(stat = "identity", width = 0.7) +
  geom_text(aes(label = comma(Cells)), vjust = -0.4, size = 3.5, fontface = "bold") +
  scale_fill_manual(values = line_colors) +
  scale_y_continuous(labels = comma, expand = expansion(mult = c(0, 0.15))) +
  theme_classic() +
  theme(legend.position = "none",
        axis.text = element_text(size = 11)) +
  labs(title = "Sézary Cell Lines — Cell Counts",
       x = "Cell Line", y = "Number of Cells")
p_cell_count

save_fig(p_cell_count, "QC8_sezary_cell_counts", w = 9, h = 6)
# Must specify assay="SCT" — DefaultAssay is "integrated" at this point
ref_hvgs       <- VariableFeatures(reference_integrated, assay = "integrated")
final_features <- intersect(ref_hvgs, shared_hvgs_clean)

cat(sprintf("\nShared HVGs  : %d\n", length(shared_hvgs)))

Shared HVGs  : 3000
cat(sprintf("After junk   : %d\n", length(shared_hvgs_clean)))
After junk   : 2866
cat(sprintf("Ref HVGs     : %d\n", length(ref_hvgs)))
Ref HVGs     : 2902
cat(sprintf("Final (ref ∩ query): %d genes\n", length(final_features)))
Final (ref ∩ query): 1356 genes
if (length(final_features) < 1500)
  warning("Fewer than 1500 shared features — consider nfeatures = 4000")

# ── Merge, scale, PCA ────────────────────────────────────────────────────────
MalignantCD4T <- merge(cell_line_list[[1]], y = cell_line_list[-1],
                       merge.data = TRUE)
VariableFeatures(MalignantCD4T) <- final_features

MalignantCD4T <- ScaleData(MalignantCD4T, features = final_features,
                            assay = "SCT", verbose = FALSE)
# npcs = 50 matches the reference integrated PCA (50 dims)
# FindTransferAnchors takes min(ref_dims, query_dims) automatically
MalignantCD4T <- RunPCA(MalignantCD4T, features = final_features,
                         assay = "SCT", npcs = 50, verbose = FALSE)

cat("\n✅ Query ready\n")

✅ Query ready
cat("Cells   :", ncol(MalignantCD4T), "\n")
Cells   : 40695 
cat("Features:", length(final_features), "\n")
Features: 1356 
cat("PCA dims:", ncol(Embeddings(MalignantCD4T, "pca")), "\n")
PCA dims: 50 
# ── QC Figure: HVG overlap ───────────────────────────────────────────────────
hvg_overlap_df <- data.frame(
  Set    = c("Reference HVGs", "Query shared HVGs (clean)", "Final intersection"),
  Genes  = c(length(ref_hvgs), length(shared_hvgs_clean), length(final_features))
)
p_hvg <- ggplot(hvg_overlap_df, aes(x = Set, y = Genes, fill = Set)) +
  geom_bar(stat = "identity", width = 0.6) +
  geom_text(aes(label = Genes), vjust = -0.4, size = 4, fontface = "bold") +
  scale_fill_manual(values = c("#2166AC","#74ADD1","#D73027")) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.15))) +
  theme_classic() +
  theme(legend.position = "none",
        axis.text.x = element_text(angle = 20, hjust = 1)) +
  labs(title = "HVG Overlap: Reference vs Query", x = NULL, y = "Gene Count")
p_hvg

save_fig(p_hvg, "QC9_HVG_overlap", w = 8, h = 6)

rm(MalignantCD4T_raw, cell_line_list); gc()
             used    (Mb) gc trigger    (Mb)   max used    (Mb)
Ncells   10612439   566.8   15749107   841.1   15749107   841.1
Vcells 1392620214 10624.9 4407706339 33628.2 5509632923 42035.2

5.1 variable genes all 7 cell line check

# Genes variable in ALL 7 lines
hvg_all7 <- names(hvg_freq[hvg_freq == 7])
cat("Genes variable in all 7 lines:", length(hvg_all7), "\n")
Genes variable in all 7 lines: 689 
print(hvg_all7)
  [1] "AARS"        "ABCC1"       "ABHD3"       "AC004687.1"  "AC006064.4"  "AC008105.3"  "AC011603.2"  "AC020916.1"  "ACAT2"       "ACLY"       
 [11] "ACTB"        "ACTG1"       "ACTN4"       "ADA"         "ADAM19"      "ADGRE5"      "AHNAK"       "AHR"         "AKAP13"      "AL133415.1" 
 [21] "AL138963.4"  "AL662797.1"  "ALOX5AP"     "ANKRD17"     "ANKRD44"     "ANLN"        "ANXA1"       "ANXA2"       "ANXA6"       "APP"        
 [31] "ARGLU1"      "ARHGAP11A"   "ARHGAP15"    "ARHGDIB"     "ARHGEF6"     "ARL4C"       "ARL6IP1"     "ASF1B"       "ASPM"        "ATAD2"      
 [41] "ATP1A1"      "ATP2A2"      "ATP2B1"      "ATP5MC1"     "ATXN1"       "AURKA"       "AURKB"       "B2M"         "BACH2"       "BCAT1"      
 [51] "BCL2"        "BHLHE40"     "BIRC3"       "BIRC5"       "BIRC6"       "BLVRA"       "BRCA1"       "BRIP1"       "BTG1"        "BTG2"       
 [61] "BUB1"        "BUB1B"       "C12orf75"    "C21orf58"    "CALM1"       "CALM2"       "CALR"        "CAMK4"       "CANX"        "CAPN2"      
 [71] "CARHSP1"     "CASK"        "CASP8"       "CAST"        "CBR3"        "CCDC28B"     "CCDC86"      "CCL5"        "CCNA2"       "CCNB1"      
 [81] "CCNB2"       "CCND2"       "CCND3"       "CCNE1"       "CCNE2"       "CCNF"        "CCR7"        "CCT5"        "CD151"       "CD3D"       
 [91] "CD48"        "CD52"        "CD55"        "CD59"        "CD69"        "CD70"        "CD74"        "CD96"        "CDC20"       "CDC6"       
[101] "CDCA2"       "CDCA3"       "CDCA5"       "CDCA7"       "CDCA8"       "CDK1"        "CDK2AP2"     "CDK6"        "CDKAL1"      "CDKN1A"     
[111] "CDKN2D"      "CDKN3"       "CDT1"        "CEBPB"       "CELF2"       "CENPA"       "CENPE"       "CENPF"       "CENPU"       "CEP128"     
[121] "CEP55"       "CHAC1"       "CHAF1A"      "CHCHD10"     "CHST11"      "CISH"        "CKAP2"       "CKAP2L"      "CKAP5"       "CKS1B"      
[131] "CKS2"        "CLDND1"      "CLSPN"       "CLTC"        "CNN2"        "CORO1A"      "CORO1B"      "COTL1"       "CRIP1"       "CTSC"       
[141] "CTSD"        "CXCR4"       "CYBA"        "CYLD"        "CYP51A1"     "CYTH1"       "CYTIP"       "CYTOR"       "DANCR"       "DCTN1"      
[151] "DDIT3"       "DDIT4"       "DDX21"       "DDX3X"       "DDX6"        "DENND1B"     "DENND4C"     "DEPDC1"      "DEPDC1B"     "DIAPH3"     
[161] "DLG1"        "DLGAP5"      "DNAJA1"      "DNAJB1"      "DOCK10"      "DOCK2"       "DOCK8"       "DSCC1"       "DTL"         "DUSP2"      
[171] "DYNLL1"      "E2F1"        "ECT2"        "EEF1A1"      "EEF2"        "EFHD2"       "EIF1"        "EIF4G1"      "ELMO1"       "EMP3"       
[181] "ENO1"        "ERC1"        "ERN1"        "ESCO2"       "ESYT1"       "ESYT2"       "ETS1"        "EVL"         "EXOC4"       "EZH2"       
[191] "FABP5"       "FAM107B"     "FAM111A"     "FAM111B"     "FAM83D"      "FASN"        "FBXL17"      "FBXL20"      "FBXO5"       "FDFT1"      
[201] "FEN1"        "FKBP11"      "FKBP4"       "FKBP5"       "FLI1"        "FLNA"        "FLOT1"       "FNDC3A"      "FOS"         "FOXN3"      
[211] "FOXP2"       "FTL"         "FTX"         "FUS"         "FXYD5"       "FYN"         "GABPB1-AS1"  "GAPDH"       "GARS"        "GAS5"       
[221] "GATA3"       "GINS2"       "GNG2"        "GOLGB1"      "GPHN"        "GPR15"       "GPR171"      "GPRIN3"      "GRN"         "GSTP1"      
[231] "GTSE1"       "H1FX"        "H2AFX"       "H2AFZ"       "H3F3B"       "HCST"        "HDAC9"       "HELLS"       "HERPUD1"     "HIPK2"      
[241] "HIST1H1A"    "HIST1H1B"    "HIST1H1C"    "HIST1H1D"    "HIST1H1E"    "HIST1H2AC"   "HIST1H2AE"   "HIST1H2AG"   "HIST1H2AL"   "HIST1H2BC"  
[251] "HIST1H2BJ"   "HIST1H3B"    "HIST1H3D"    "HIST1H3H"    "HIST1H3I"    "HIST1H4C"    "HIST2H2AB"   "HIST2H2AC"   "HIST2H2BF"   "HJURP"      
[261] "HLA-A"       "HLA-B"       "HLA-C"       "HLA-E"       "HMGB2"       "HMGCR"       "HMGCS1"      "HMGN2"       "HMMR"        "HNRNPA3"    
[271] "HNRNPAB"     "HNRNPH1"     "HNRNPU"      "HNRNPUL2"    "HP1BP3"      "HPGD"        "HSP90AA1"    "HSP90AB1"    "HSP90B1"     "HSPA1A"     
[281] "HSPA1B"      "HSPA5"       "HSPA8"       "HSPA9"       "HSPB1"       "HSPD1"       "HSPE1"       "HSPH1"       "HUWE1"       "IARS"       
[291] "ID2"         "IDH2"        "IDI1"        "IER2"        "IER3"        "IFITM1"      "IGF2R"       "IKZF1"       "IKZF2"       "IL10RA"     
[301] "IL2RB"       "IL32"        "IL4R"        "IL9R"        "ILF3-DT"     "IMMP2L"      "INCENP"      "INPP4B"      "INSIG1"      "IPO5"       
[311] "IQGAP1"      "IRF1"        "ISG20"       "ITGA4"       "ITGAL"       "ITGB2"       "ITGB7"       "ITK"         "ITM2B"       "ITM2C"      
[321] "JPT1"        "JUN"         "JUNB"        "JUND"        "KCNQ5"       "KIF11"       "KIF14"       "KIF15"       "KIF18B"      "KIF20A"     
[331] "KIF20B"      "KIF21B"      "KIF23"       "KIF2C"       "KIF4A"       "KIFC1"       "KLF6"        "KMT2C"       "KNL1"        "KNSTRN"     
[341] "KPNA2"       "LARP1"       "LASP1"       "LAT"         "LBR"         "LCP1"        "LCP2"        "LDHA"        "LDLR"        "LDLRAD4"    
[351] "LGALS1"      "LIME1"       "LINC00892"   "LINC01572"   "LMNA"        "LMNB1"       "LMO4"        "LRBA"        "LRPPRC"      "LSP1"       
[361] "LTA"         "LTB"         "LY6E"        "LYST"        "MACF1"       "MALAT1"      "MANF"        "MAP3K8"      "MARCKSL1"    "MAT2A"      
[371] "MBD5"        "MBNL1"       "MBP"         "MCL1"        "MCM10"       "MCM2"        "MCM3"        "MCM4"        "MCM5"        "MCM6"       
[381] "MCM7"        "MDFIC"       "MDN1"        "MGST3"       "MIB1"        "MIF"         "MIR4435-2HG" "MIS18BP1"    "MKI67"       "MKNK2"      
[391] "MMP25"       "MSH6"        "MSI2"        "MSMO1"       "MSN"         "MT-ATP6"     "MT-ATP8"     "MT-CO1"      "MT-CO2"      "MT-CO3"     
[401] "MT-CYB"      "MT-ND1"      "MT-ND2"      "MT-ND3"      "MT-ND4"      "MT-ND4L"     "MT-ND5"      "MT-ND6"      "MT1X"        "MT2A"       
[411] "MTHFD2"      "MTRNR2L12"   "MXD3"        "MYB"         "MYC"         "MYH9"        "MYL6"        "MYO1F"       "MYO1G"       "MZB1"       
[421] "NAMPT"       "NCAPD2"      "NCAPG"       "NCAPG2"      "NCL"         "NCOA3"       "NDC80"       "NEAT1"       "NEIL3"       "NEK2"       
[431] "NEK7"        "NFAT5"       "NFATC2"      "NFE2L3"      "NFKB1"       "NFKBIA"      "NIBAN1"      "NINJ1"       "NKTR"        "NME1"       
[441] "NOLC1"       "NOP16"       "NORAD"       "NPM1"        "NQO1"        "NR3C1"       "NSD2"        "NSMCE2"      "NUCB2"       "NUDT8"      
[451] "NUF2"        "NUFIP2"      "NUMA1"       "NUSAP1"      "ODC1"        "OPTN"        "OSBPL3"      "OSTF1"       "P2RY8"       "PALM2-AKAP2"
[461] "PARP14"      "PCLAF"       "PCNA"        "PDE3B"       "PDE4D"       "PDE7A"       "PGAM1"       "PGK1"        "PHACTR2"     "PHF19"      
[471] "PHLDA1"      "PIK3CD"      "PIK3R1"      "PIM1"        "PIM2"        "PIM3"        "PKM"         "PKMYT1"      "PLAAT4"      "PLEC"       
[481] "PLK1"        "PLP2"        "PLPP1"       "PMAIP1"      "PNN"         "PNRC1"       "POLR2A"      "PPDPF"       "PPP1R15A"    "PPP3CA"     
[491] "PRC1"        "PRDX1"       "PREX1"       "PRKCA"       "PRKDC"       "PRNP"        "PRR11"       "PSAT1"       "PTMA"        "PTMS"       
[501] "PTPN6"       "PTPN7"       "PTPRC"       "PTTG1"       "PUM3"        "PUS7"        "PVT1"        "PYCARD"      "RAB11FIP1"   "RAB37"      
[511] "RABGAP1L"    "RACGAP1"     "RAD21"       "RAD51B"      "RASGRP1"     "RBL1"        "RBM38"       "RBPJ"        "RCC2"        "RCSD1"      
[521] "REEP5"       "RELB"        "RERE"        "RHBDD2"      "RHOC"        "RNF213"      "RORA"        "RPL10"       "RPL11"       "RPL12"      
[531] "RPL13"       "RPL19"       "RPL22L1"     "RPL32"       "RPL41"       "RPLP0"       "RPLP1"       "RPS12"       "RPS14"       "RPS18"      
[541] "RPS2"        "RPS23"       "RPS3"        "RPS3A"       "RPS6KA5"     "RPS8"        "RRM2"        "RSRP1"       "RUNX3"       "S100A10"    
[551] "S100A11"     "S100A4"      "S100A6"      "S100P"       "SAC3D1"      "SAMD9"       "SASH3"       "SCLT1"       "SCPEP1"      "SDCBP"      
[561] "SEC14L1"     "SELENOW"     "SELPLG"      "SEMA4D"      "SEPTIN9"     "SERPINB1"    "SETX"        "SFPQ"        "SGO2"        "SH2D2A"     
[571] "SH3BGRL3"    "SH3BP1"      "SIK3"        "SIT1"        "SKAP1"       "SLBP"        "SLC16A1-AS1" "SLC1A5"      "SLC20A1"     "SLC25A32"   
[581] "SLC2A3"      "SLC38A2"     "SLC3A2"      "SLC43A3"     "SLC4A7"      "SLC7A5"      "SLC9A3R1"    "SLFN12L"     "SMARCA2"     "SMC1A"      
[591] "SMC4"        "SMG1"        "SMYD3"       "SNHG12"      "SNHG15"      "SNHG3"       "SNHG7"       "SNHG8"       "SNRNP200"    "SOCS1"      
[601] "SORL1"       "SOS1"        "SP140"       "SPAG5"       "SPIDR"       "SPOCK2"      "SPTAN1"      "SPTBN1"      "SQLE"        "SQSTM1"     
[611] "SREBF2"      "SRGN"        "SRM"         "SRRT"        "SRSF7"       "SSBP2"       "ST8SIA4"     "STAT1"       "STAT3"       "STAT4"      
[621] "STK10"       "STK17B"      "STMN1"       "SUN2"        "SYNE2"       "SYTL3"       "TACC3"       "TAF15"       "TAGLN2"      "TBC1D5"     
[631] "TBL1X"       "TCF12"       "TCP1"        "TFRC"        "TIMP1"       "TK1"         "TMBIM1"      "TMEM173"     "TMPO"        "TMSB10"     
[641] "TMSB4X"      "TMTC2"       "TMX4"        "TNFRSF1B"    "TNFSF10"     "TNIK"        "TOP2A"       "TPM4"        "TPX2"        "TRAF1"      
[651] "TRAF3IP3"    "TRBV20-1"    "TRG-AS1"     "TRIM44"      "TRIM56"      "TRIM59"      "TRIO"        "TROAP"       "TSC22D3"     "TTK"        
[661] "TUBA1A"      "TUBA1B"      "TUBA1C"      "TUBA4A"      "TUBB"        "TUBB4B"      "TYMS"        "UBALD2"      "UBC"         "UBE2C"      
[671] "UBE2S"       "UBR4"        "UCP2"        "UHRF1"       "UNG"         "VIM"         "WARS"        "WDR76"       "WWOX"        "XBP1"       
[681] "YWHAG"       "ZC3HAV1"     "ZEB1"        "ZFAND3"      "ZFAS1"       "ZFP36"       "ZFP36L1"     "ZFP36L2"     "ZYX"        
# Check which canonical T cell markers are in the all-7 set
t_cell_markers <- c(
  # Naive/memory
  "CCR7", "SELL", "TCF7", "IL7R", "LEF1", "KLF2",
  # Activation/exhaustion  
  "TOX", "PDCD1", "LAG3", "TIGIT", "CTLA4", "HAVCR2",
  # Effector
  "GZMB", "GZMK", "GZMA", "PRF1", "IFNG", "TNF",
  # Treg
  "FOXP3", "IL2RA", "IKZF2", "CTLA4",
  # Sézary specific
  "KIR3DL2", "PLS3", "TWIST1", "EPHA4", "CD164",
  # Proliferation
  "MKI67", "TOP2A", "CDK1"
)

found_in_all7 <- intersect(t_cell_markers, hvg_all7)
cat("\nCanonical markers in all-7 HVG set:\n")

Canonical markers in all-7 HVG set:
print(found_in_all7)
[1] "CCR7"  "IKZF2" "MKI67" "TOP2A" "CDK1" 
not_found <- setdiff(t_cell_markers, hvg_all7)
cat("\nMarkers NOT in all-7 set:\n")

Markers NOT in all-7 set:
print(not_found)
 [1] "SELL"    "TCF7"    "IL7R"    "LEF1"    "KLF2"    "TOX"     "PDCD1"   "LAG3"    "TIGIT"   "CTLA4"   "HAVCR2"  "GZMB"    "GZMK"    "GZMA"   
[15] "PRF1"    "IFNG"    "TNF"     "FOXP3"   "IL2RA"   "KIR3DL2" "PLS3"    "TWIST1"  "EPHA4"   "CD164"  

5.2 variable genes all 7 cell line check

# Check what junk genes are in your current HVG set
# before find-anchors runs

cat("=== Junk gene check on shared_hvgs ===\n")
=== Junk gene check on shared_hvgs ===
mt_in_hvgs <- shared_hvgs[grepl("^MT-", shared_hvgs)]
cat("MT genes in shared_hvgs:", length(mt_in_hvgs), "\n")
MT genes in shared_hvgs: 13 
print(mt_in_hvgs)
 [1] "MT-ATP6" "MT-ATP8" "MT-CO1"  "MT-CO2"  "MT-CO3"  "MT-CYB"  "MT-ND1"  "MT-ND2"  "MT-ND3"  "MT-ND4"  "MT-ND4L" "MT-ND5"  "MT-ND6" 
ribo_in_hvgs <- shared_hvgs[grepl("^RPL|^RPS", shared_hvgs)]
cat("\nRibosomal genes in shared_hvgs:", length(ribo_in_hvgs), "\n")

Ribosomal genes in shared_hvgs: 53 
print(ribo_in_hvgs)
 [1] "RPL10"   "RPL11"   "RPL12"   "RPL13"   "RPL19"   "RPL22L1" "RPL32"   "RPL41"   "RPLP0"   "RPLP1"   "RPS12"   "RPS14"   "RPS18"   "RPS2"   
[15] "RPS23"   "RPS3"    "RPS3A"   "RPS6KA5" "RPS8"    "RPL13A"  "RPL18A"  "RPL28"   "RPL29"   "RPL35A"  "RPL5"    "RPL7A"   "RPL8"    "RPS13"  
[29] "RPS6"    "RPS6KA3" "RPS7"    "RPL17"   "RPL23"   "RPL30"   "RPL35"   "RPL6"    "RPL7"    "RPS15A"  "RPS27L"  "RPS4X"   "RPL14"   "RPL23A" 
[43] "RPL26"   "RPL27A"  "RPL3"    "RPL37"   "RPL4"    "RPS17"   "RPS20"   "RPS24"   "RPS27A"  "RPS6KA1" "RPS6KC1"
hsp_in_hvgs <- shared_hvgs[grepl("^HSP|^HSPA|^HSPB", shared_hvgs)]
cat("\nHeat shock genes in shared_hvgs:", length(hsp_in_hvgs), "\n")

Heat shock genes in shared_hvgs: 13 
print(hsp_in_hvgs)
 [1] "HSP90AA1" "HSP90AB1" "HSP90B1"  "HSPA1A"   "HSPA1B"   "HSPA5"    "HSPA8"    "HSPA9"    "HSPB1"    "HSPD1"    "HSPE1"    "HSPH1"   
[13] "HSPA4"   
snhg_in_hvgs <- shared_hvgs[grepl("^SNHG|MALAT1|NEAT1", shared_hvgs)]
cat("\nlncRNA genes in shared_hvgs:", length(snhg_in_hvgs), "\n")

lncRNA genes in shared_hvgs: 15 
print(snhg_in_hvgs)
 [1] "MALAT1" "NEAT1"  "SNHG12" "SNHG15" "SNHG3"  "SNHG7"  "SNHG8"  "SNHG1"  "SNHG29" "SNHG16" "SNHG25" "SNHG17" "SNHG30" "SNHG32" "SNHG5" 
cat("\nTotal junk genes to be filtered:", 
    length(mt_in_hvgs) + length(ribo_in_hvgs) + 
    length(hsp_in_hvgs) + length(snhg_in_hvgs), "\n")

Total junk genes to be filtered: 94 

6 6. FindTransferAnchors

DefaultAssay(reference_integrated) <- "SCT"
DefaultAssay(MalignantCD4T)        <- "SCT"

dims_to_use <- min(50,
                   ncol(Embeddings(reference_integrated, "pca")),
                   ncol(Embeddings(MalignantCD4T, "pca")))
cat("Finding anchors: dims 1:", dims_to_use, "| features:", length(final_features), "\n\n")
Finding anchors: dims 1: 50 | features: 1356 
# ── HARD STOP: verify PCA rotation features overlap with final_features ──────
# reference.reduction="pca" projects the query into the reference PCA space.
# The PCA rotation matrix was built on "integrated" assay CCA features.
# final_features are SCT HVGs. Seurat uses only the intersection.
# If overlap is small, the projection is meaningless.
pca_features <- rownames(reference_integrated[["pca"]]@feature.loadings)
pca_overlap  <- intersect(pca_features, final_features)
cat(sprintf("Reference PCA rotation features : %d\n", length(pca_features)))
Reference PCA rotation features : 2902
cat(sprintf("final_features (SCT HVGs)        : %d\n", length(final_features)))
final_features (SCT HVGs)        : 1356
cat(sprintf("Overlap (used for projection)    : %d\n", length(pca_overlap)))
Overlap (used for projection)    : 1356
if (length(pca_overlap) < 200)
  stop(sprintf(
    "CRITICAL: PCA–SCT feature overlap is only %d genes.\n",
    length(pca_overlap),
    "Query projection onto reference PCA will be unreliable.\n",
    "Check that the reference object has SCT HVGs in its integrated PCA."
  ))
if (length(pca_overlap) < 500)
  warning(sprintf("Low PCA–SCT feature overlap: %d genes. Projection quality may be reduced.", length(pca_overlap)))

anchors <- FindTransferAnchors(
  reference            = reference_integrated,
  query                = MalignantCD4T,
  features             = final_features,
  normalization.method = "SCT",
  reference.assay      = "SCT",    # use SCT expression for feature matching
  query.assay          = "SCT",    # use SCT expression for feature matching
  reference.reduction  = "pca",    # integrated PCA (50 dims) — biology intact
  dims                 = 1:dims_to_use,
  k.anchor             = 10,
  k.filter             = 500,
  k.score              = 30,
  verbose              = TRUE
)
[1] "Given reference assay has multiple sct models, selecting model with most cells for finding transfer anchors"
# ── Anchor QC ────────────────────────────────────────────────────────────────
anchor_df    <- as.data.frame(slot(anchors, "anchors"))
n_anchors    <- nrow(anchor_df)
anchor_ratio <- ncol(MalignantCD4T) / n_anchors
mean_score   <- mean(anchor_df$score)
med_score    <- median(anchor_df$score)

cat(sprintf("\n=== Anchor summary ===\n"))

=== Anchor summary ===
cat(sprintf("Anchors           : %d\n", n_anchors))
Anchors           : 8022
cat(sprintf("Cells per anchor  : %.1f:1 (ideal ≤ 8:1)\n", anchor_ratio))
Cells per anchor  : 5.1:1 (ideal ≤ 8:1)
cat(sprintf("Score: mean=%.3f | median=%.3f\n", mean_score, med_score))
Score: mean=0.553 | median=0.538
if (anchor_ratio > 8)
  warning("Low anchor density — check junk gene removal and k.anchor = 10")

# QC figure: anchor score distribution
p_anchor <- ggplot(anchor_df, aes(x = score)) +
  geom_histogram(bins = 50, fill = "#2166AC", colour = "white", alpha = 0.85) +
  geom_vline(xintercept = mean_score,  linetype = "dashed", colour = "red",
             linewidth = 0.8) +
  geom_vline(xintercept = med_score, linetype = "dotted", colour = "darkgreen",
             linewidth = 0.8) +
  annotate("text", x = mean_score + 0.02, y = Inf, vjust = 1.5,
           label = sprintf("mean=%.3f", mean_score), colour = "red", size = 3.5) +
  annotate("text", x = med_score - 0.02, y = Inf, vjust = 3,
           label = sprintf("median=%.3f", med_score), colour = "darkgreen",
           size = 3.5, hjust = 1) +
  theme_classic() +
  labs(
    title = sprintf("Transfer Anchor Score Distribution (n=%d anchors)", n_anchors),
    subtitle = sprintf("Cells:anchors = %.1f:1", anchor_ratio),
    x = "Anchor Score", y = "Count"
  )
p_anchor

save_fig(p_anchor, "QC10_anchor_score_distribution", w = 10, h = 6)

6.1 Anchor breakdown by cell line

# anchor_df has columns: cell1 (reference index), cell2 (query index), score
# cell2 indexes into the QUERY object (MalignantCD4T) — map back to cell_line
query_cell_names <- colnames(MalignantCD4T)

anchor_lines <- anchor_df %>%
  mutate(
    query_cell = query_cell_names[cell2],
    cell_line  = MalignantCD4T@meta.data[query_cell, "cell_line"]
  ) %>%
  count(cell_line, name = "n_anchors") %>%
  arrange(cell_line) %>%
  mutate(
    n_cells         = as.integer(table(MalignantCD4T$cell_line)[cell_line]),
    cells_per_anchor = round(n_cells / n_anchors, 2),
    pct_anchors      = round(100 * n_anchors / sum(n_anchors), 1)
  )

cat("=== Anchors per cell line ===\n")
=== Anchors per cell line ===
print(anchor_lines)

cat(sprintf("\nTotal anchors : %d\n", sum(anchor_lines$n_anchors)))

Total anchors : 8022
cat(sprintf("Overall ratio : %.1f cells per anchor\n", 
            sum(anchor_lines$n_cells) / sum(anchor_lines$n_anchors)))
Overall ratio : 5.1 cells per anchor
# Flag any line with poor anchor density
poor_lines <- anchor_lines %>% filter(cells_per_anchor > 8)
if (nrow(poor_lines) > 0) {
  warning(sprintf("Poor anchor density (>8:1) in: %s",
                  paste(poor_lines$cell_line, collapse = ", ")))
}

# ── Plot: anchors and cells:anchor ratio per line ─────────────────────────────
p_anch_n <- ggplot(anchor_lines, aes(x = cell_line, y = n_anchors, fill = cell_line)) +
  geom_bar(stat = "identity", width = 0.7) +
  geom_text(aes(label = sprintf("%d\n(%.1f%%)", n_anchors, pct_anchors)),
            vjust = -0.3, size = 3.2, fontface = "bold") +
  scale_fill_manual(values = line_colors) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.18))) +
  theme_classic(base_size = 12) +
  theme(legend.position = "none",
        plot.title = element_text(face = "bold")) +
  labs(title = "A  Anchors per Cell Line",
       x = "Cell Line", y = "Number of Anchors")

p_anch_ratio <- ggplot(anchor_lines, aes(x = cell_line, y = cells_per_anchor,
                                          fill = cell_line)) +
  geom_bar(stat = "identity", width = 0.7) +
  geom_text(aes(label = sprintf("%.1f:1", cells_per_anchor)),
            vjust = -0.3, size = 3.2, fontface = "bold") +
  geom_hline(yintercept = 8, linetype = "dashed", colour = "red",
             linewidth = 0.7) +
  annotate("text", x = 0.6, y = 8.4, label = "8:1 threshold",
           colour = "red", size = 3, hjust = 0) +
  scale_fill_manual(values = line_colors) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.18))) +
  theme_classic(base_size = 12) +
  theme(legend.position = "none",
        plot.title = element_text(face = "bold")) +
  labs(title = "B  Cells per Anchor (lower = better coverage)",
       x = "Cell Line", y = "Cells : Anchor ratio")

p_anchor_lines <- p_anch_n | p_anch_ratio
p_anchor_lines

save_fig(p_anchor_lines, "QC10b_anchors_by_cell_line", w = 14, h = 6)

6.2 Anchor breakdown by Azimuth l2 cell type (reference side)

# anchor_df columns:
#   cell1 = index into REFERENCE (reference_integrated)
#   cell2 = index into QUERY (MalignantCD4T)
#   score = anchor score

ref_cell_names  <- colnames(reference_integrated)
query_cell_names <- colnames(MalignantCD4T)

anchor_full <- anchor_df %>%
  mutate(
    ref_cell      = ref_cell_names[cell1],
    query_cell    = query_cell_names[cell2],
    ref_celltype  = reference_integrated@meta.data[ref_cell,  "predicted.celltype.l2"],
    query_line    = MalignantCD4T@meta.data[query_cell, "cell_line"]
  )

# ── Table 1: anchors per reference cell type ─────────────────────────────────
by_reftype <- anchor_full %>%
  count(ref_celltype, name = "n_anchors") %>%
  arrange(desc(n_anchors)) %>%
  mutate(
    pct_anchors = round(100 * n_anchors / sum(n_anchors), 1),
    # how many reference cells of this type exist?
    n_ref_cells = as.integer(table(reference_integrated$predicted.celltype.l2)[ref_celltype]),
    anchors_per_ref_cell = round(n_anchors / n_ref_cells, 2)
  )

cat("=== Anchors by reference Azimuth l2 cell type ===\n")
=== Anchors by reference Azimuth l2 cell type ===
print(by_reftype)

# ── Table 2: cross-table — query line × reference cell type ──────────────────
cross_tab <- anchor_full %>%
  count(query_line, ref_celltype) %>%
  group_by(query_line) %>%
  mutate(pct = round(100 * n / sum(n), 1)) %>%
  ungroup()

cat("\n=== Anchor source (ref cell type) per query cell line ===\n")

=== Anchor source (ref cell type) per query cell line ===
cross_wide <- cross_tab %>%
  dplyr::select(query_line, ref_celltype, pct) %>%
  tidyr::pivot_wider(names_from = ref_celltype, values_from = pct,
                     values_fill = 0)
print(cross_wide)

# ── Plot A: bar chart — anchors per reference cell type ──────────────────────
p_by_type <- ggplot(by_reftype,
                    aes(x = reorder(ref_celltype, n_anchors),
                        y = n_anchors,
                        fill = ref_celltype)) +
  geom_bar(stat = "identity", width = 0.7) +
  geom_text(aes(label = sprintf("%d (%.1f%%)", n_anchors, pct_anchors)),
            hjust = -0.08, size = 3.5, fontface = "bold") +
  scale_fill_manual(values = azimuth_l2_colors, na.value = "grey70") +
  scale_y_continuous(expand = expansion(mult = c(0, 0.25))) +
  coord_flip() +
  theme_classic(base_size = 13) +
  theme(legend.position = "none",
        plot.title = element_text(face = "bold")) +
  labs(title = "A  Anchors per Reference Cell Type (Azimuth l2)",
       x = NULL, y = "Number of Anchors")

# ── Plot B: anchors per reference cell in that type (density of use) ─────────
p_density <- ggplot(by_reftype,
                    aes(x = reorder(ref_celltype, anchors_per_ref_cell),
                        y = anchors_per_ref_cell,
                        fill = ref_celltype)) +
  geom_bar(stat = "identity", width = 0.7) +
  geom_text(aes(label = sprintf("%.2f", anchors_per_ref_cell)),
            hjust = -0.1, size = 3.5, fontface = "bold") +
  scale_fill_manual(values = azimuth_l2_colors, na.value = "grey70") +
  scale_y_continuous(expand = expansion(mult = c(0, 0.25))) +
  coord_flip() +
  theme_classic(base_size = 13) +
  theme(legend.position = "none",
        plot.title = element_text(face = "bold")) +
  labs(title = "B  Anchors per Reference Cell\n(how heavily each state is used)",
       x = NULL, y = "Anchors / Reference Cell")

# ── Plot C: stacked bar — which ref cell type anchors each query line ─────────
cross_tab <- cross_tab %>%
  mutate(ref_celltype = factor(ref_celltype, levels = names(azimuth_l2_colors))) %>%
  arrange(query_line, ref_celltype) %>%
  group_by(query_line) %>%
  mutate(
    label_y = cumsum(pct) - 0.5 * pct,
    label   = ifelse(pct >= 3, sprintf("%.1f%%", pct), "")
  ) %>%
  ungroup()

p_cross <- ggplot(cross_tab,
                  aes(x = query_line, y = pct, fill = ref_celltype)) +
  geom_bar(stat = "identity", width = 0.78) +
  geom_text(aes(y = label_y, label = label),
            size = 3.0, fontface = "bold", colour = "white", vjust = 0.5) +
  scale_fill_manual(values = azimuth_l2_colors, na.value = "grey70",
                    name = "Reference\nCell Type") +
  scale_y_continuous(labels = function(x) paste0(x, "%"),
                     expand = expansion(mult = c(0, 0.02))) +
  theme_classic(base_size = 13) +
  theme(plot.title = element_text(face = "bold"),
        legend.position = "right") +
  labs(title = "C  Reference Cell Type Composition of Anchors per Query Line",
       x = "Query Cell Line", y = "% of Anchors")

# ── Assemble ──────────────────────────────────────────────────────────────────
p_anchor_reftype <- (p_by_type | p_density) / p_cross +
  plot_layout(heights = c(1, 1.2)) +
  plot_annotation(
    title    = "Anchor Quality — Reference Cell Type Breakdown",
    subtitle = sprintf("Total anchors: %d | Reference cells: %d | Query cells: %d",
                       nrow(anchor_df),
                       ncol(reference_integrated),
                       ncol(MalignantCD4T)),
    theme = theme(
      plot.title    = element_text(size = 15, face = "bold"),
      plot.subtitle = element_text(size = 10, colour = "grey40")
    )
  )

p_anchor_reftype

save_fig(p_anchor_reftype, "QC10c_anchors_by_ref_celltype",
         w = 16, h = 14)

7 7. MapQuery — Project Sézary Cells

cat("✅ MapQuery complete\n")
✅ MapQuery complete
cat("Mapped cells:", ncol(mapped_MalignantCD4T), "\n")
Mapped cells: 40695 
# Label transfer confidence
score_col <- "predicted.predicted.celltype.l2.score"
if (score_col %in% colnames(mapped_MalignantCD4T@meta.data)) {
  scores <- mapped_MalignantCD4T@meta.data[[score_col]]
  cat(sprintf("Label transfer confidence: mean=%.3f | median=%.3f\n",
              mean(scores, na.rm = TRUE), median(scores, na.rm = TRUE)))
}
Label transfer confidence: mean=0.958 | median=1.000
cat("\nTransferred label distribution:\n")

Transferred label distribution:
print(table(mapped_MalignantCD4T$predicted.predicted.celltype.l2))

CD4 Naive   CD4 TCM   CD4 TEM      Treg 
       37     40643        14         1 
cat("\nTransferred pseudotime summary:\n")

Transferred pseudotime summary:
print(summary(mapped_MalignantCD4T$predicted.pseudotime))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 0.2367 15.1562 19.5877 20.4392 25.7830 28.4802 
# ── QC Figure: Projection overview ───────────────────────────────────────────
ref_bg <- data.frame(
  Embeddings(reference_integrated, "umap"),
  stringsAsFactors = FALSE
)
colnames(ref_bg)[1:2] <- c("UMAP_1","UMAP_2")

query_coords <- data.frame(
  Embeddings(mapped_MalignantCD4T, "ref.umap"),
  pseudotime = mapped_MalignantCD4T$predicted.pseudotime,
  celltype   = mapped_MalignantCD4T$predicted.predicted.celltype.l2,
  stringsAsFactors = FALSE
)
colnames(query_coords)[1:2] <- c("UMAP_1","UMAP_2")

p_proj_pt <- ggplot() +
  geom_point(data = ref_bg, aes(UMAP_1, UMAP_2),
             colour = "grey87", size = 0.3, alpha = 0.6) +
  geom_point(data = query_coords %>% filter(is.finite(pseudotime)),
             aes(UMAP_1, UMAP_2, colour = pseudotime),
             size = 0.5, alpha = 0.8) +
  scale_colour_viridis_c(option = "plasma", name = "Pseudotime") +
  theme_classic() +
  ggtitle("Sézary cells — transferred pseudotime") +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"))

p_proj_ct <- ggplot() +
  geom_point(data = ref_bg, aes(UMAP_1, UMAP_2),
             colour = "grey87", size = 0.3, alpha = 0.6) +
  geom_point(data = query_coords,
             aes(UMAP_1, UMAP_2, colour = celltype),
             size = 0.5, alpha = 0.8) +
  scale_colour_manual(values = azimuth_l2_colors, na.value = "grey60",
                      name = "State") +
  guides(colour = guide_legend(override.aes = list(size = 3, alpha = 1))) +
  theme_classic() +
  ggtitle("Sézary cells — transferred cell state labels") +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"))

qc4 <- p_proj_pt | p_proj_ct
qc4

save_fig(qc4, "QC11_sezary_projection_overview", w = 18, h = 8)

# Score distribution
if (score_col %in% colnames(mapped_MalignantCD4T@meta.data)) {
  score_df <- data.frame(score = mapped_MalignantCD4T@meta.data[[score_col]])
  p_score <- ggplot(score_df, aes(x = score)) +
    geom_histogram(bins = 60, fill = "#2166AC", colour = "white", alpha = 0.85) +
    geom_vline(xintercept = median(score_df$score, na.rm = TRUE),
               linetype = "dashed", colour = "red", linewidth = 0.8) +
    annotate("text", x = median(score_df$score, na.rm = TRUE) + 0.01,
             y = Inf, vjust = 1.5, hjust = 0,
             label = sprintf("median=%.3f", median(score_df$score, na.rm = TRUE)),
             colour = "red", size = 3.5) +
    theme_classic() +
    labs(title = "Label Transfer Confidence Score — Sézary Cells",
         x = "Score", y = "Cell Count")
 
   p_score
  
  save_fig(p_score, "QC12_label_transfer_confidence", w = 10, h = 6)
}
  p_score

NA
NA

8 8. Bin Boundaries & State Assignment

# ════════════════════════════════════════════════════════════════════════════
# Bin boundaries are midpoints between adjacent reference state medians.
# Computed from reference_integrated$monocle3_pseudotime — the SAME column
# that was passed to MapQuery. The pseudotime scale of predicted.pseudotime
# in Sézary cells inherits this scale directly.
# ════════════════════════════════════════════════════════════════════════════

naive_tcm_cut <- round((naive_med + tcm_med)  / 2, 3)
tcm_tem_cut   <- round((tcm_med   + tem_med)  / 2, 3)
tem_temra_cut <- round((tem_med   + temra_med) / 2, 3)

cat("=== Bin boundaries ===\n")
=== Bin boundaries ===
cat(sprintf("Naive | TCM   = (%.3f + %.3f) / 2 = %.3f\n",
            naive_med, tcm_med, naive_tcm_cut))
Naive | TCM   = (3.389 + 13.027) / 2 = 8.208
cat(sprintf("TCM   | TEM   = (%.3f + %.3f) / 2 = %.3f\n",
            tcm_med, tem_med, tcm_tem_cut))
TCM   | TEM   = (13.027 + 26.890) / 2 = 19.959
cat(sprintf("TEM   | Temra = (%.3f + %.3f) / 2 = %.3f\n",
            tem_med, temra_med, tem_temra_cut))
TEM   | Temra = (26.890 + 27.350) / 2 = 27.120
cat("Treg  = label-based (branch — not linear axis)\n")
Treg  = label-based (branch — not linear axis)
# ── Assign bins ───────────────────────────────────────────────────────────────
mapped_MalignantCD4T$state_azimuth_l2 <-
  mapped_MalignantCD4T$predicted.predicted.celltype.l2

mapped_MalignantCD4T$pseudotime_value <-
  as.numeric(mapped_MalignantCD4T$predicted.pseudotime)

mapped_MalignantCD4T$pseudotime_bin <- factor(
  dplyr::case_when(
    mapped_MalignantCD4T$state_azimuth_l2 == "Treg"                        ~ "Treg-like",
    mapped_MalignantCD4T$pseudotime_value  < naive_tcm_cut                  ~ "Naive-like",
    mapped_MalignantCD4T$pseudotime_value >= naive_tcm_cut &
      mapped_MalignantCD4T$pseudotime_value < tcm_tem_cut                   ~ "TCM-like",
    mapped_MalignantCD4T$pseudotime_value >= tcm_tem_cut &
      mapped_MalignantCD4T$pseudotime_value < tem_temra_cut                 ~ "TEM-like",
    mapped_MalignantCD4T$pseudotime_value >= tem_temra_cut                  ~ "Temra-like",
    TRUE ~ NA_character_
  ),
  levels = c("Naive-like","TCM-like","Treg-like","TEM-like","Temra-like")
)

cat("\n=== Bin distribution ===\n")

=== Bin distribution ===
bin_tab <- table(mapped_MalignantCD4T$pseudotime_bin, useNA = "ifany")
bin_pct <- round(100 * prop.table(bin_tab), 2)
print(data.frame(n = as.integer(bin_tab), pct = as.numeric(bin_pct),
                 row.names = names(bin_tab)))

cat("\n=== Per cell line ===\n")

=== Per cell line ===
print(table(mapped_MalignantCD4T$cell_line,
            mapped_MalignantCD4T$pseudotime_bin, useNA = "ifany"))
    
     Naive-like TCM-like Treg-like TEM-like Temra-like
  L1        927     2099         1     2467        331
  L2         38     1842         0      645       3410
  L3          4     3881         0     1597        946
  L4         20     3308         0     2161        517
  L5          9     3867         0     1330        816
  L6          0     2196         0      891       2061
  L7          1     3005         0     1651        674
# ── QC Figure: Bin distribution ──────────────────────────────────────────────
bin_df <- mapped_MalignantCD4T@meta.data %>%
  filter(!is.na(pseudotime_bin)) %>%
  count(pseudotime_bin) %>%
  mutate(pct = round(100 * n / sum(n), 1))

p_bin_bar <- ggplot(bin_df, aes(x = pseudotime_bin, y = n, fill = pseudotime_bin)) +
  geom_bar(stat = "identity", width = 0.7) +
  geom_text(aes(label = sprintf("%s\n(%.1f%%)", comma(n), pct)),
            vjust = -0.3, size = 3.5, fontface = "bold") +
  scale_fill_manual(values = bin_colors) +
  scale_y_continuous(labels = comma, expand = expansion(mult = c(0, 0.18))) +
  theme_classic() +
  theme(legend.position = "none",
        axis.text = element_text(size = 11)) +
  labs(title = "Sézary Cells — Pseudotime Bin Distribution",
       x = NULL, y = "Cell Count")
p_bin_bar

save_fig(p_bin_bar, "QC13_pseudotime_bin_distribution", w = 9, h = 6)

# ── QC Figure: Bins on UMAP ───────────────────────────────────────────────────
query_bins <- data.frame(
  Embeddings(mapped_MalignantCD4T, "ref.umap"),
  pseudotime_bin = mapped_MalignantCD4T$pseudotime_bin,
  cell_line      = mapped_MalignantCD4T$cell_line
)
colnames(query_bins)[1:2] <- c("UMAP_1","UMAP_2")

p_bin_umap <- ggplot() +
  geom_point(data = ref_bg, aes(UMAP_1, UMAP_2),
             colour = "grey67", size = 0.3, alpha = 0.5) +
  geom_point(data = query_bins %>% filter(!is.na(pseudotime_bin)),
             aes(UMAP_1, UMAP_2, colour = pseudotime_bin),
             size = 0.5, alpha = 0.8) +
  scale_colour_manual(values = bin_colors, name = "Bin") +
  guides(colour = guide_legend(override.aes = list(size = 3, alpha = 1))) +
  theme_classic() +
  ggtitle("Sézary Cells — Pseudotime Bins on Reference UMAP") +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"))
p_bin_umap

save_fig(p_bin_umap, "QC14_bins_on_UMAP", w = 10, h = 8)

9 9. Save Objects

# Reference
saveRDS(reference_integrated,
        file.path(out_dir, "reference_integrated_RPCA_monocle3.Rds"))
cat("✅ reference_integrated saved (CCA integration intact, monocle3 pseudotime added)\n")
✅ reference_integrated saved (CCA integration intact, monocle3 pseudotime added)
# Mapped Sézary
saveRDS(mapped_MalignantCD4T,
        file.path(out_dir, "MalignantCD4T_mapped_pseudotime.Rds"))
Error: C stack usage  7971300 is too close to the limit
cat("✅ mapped_MalignantCD4T saved\n")
✅ mapped_MalignantCD4T saved
# Bin boundaries — single source of truth
bin_boundaries <- data.frame(
  boundary       = c("Naive_TCM", "TCM_TEM", "TEM_Temra"),
  pseudotime_cut = c(naive_tcm_cut, tcm_tem_cut, tem_temra_cut),
  naive_med      = naive_med,
  tcm_med        = tcm_med,
  treg_med       = treg_med,
  tem_med        = tem_med,
  temra_med      = temra_med
)
write.csv(bin_boundaries,
          file.path(out_dir, "bin_boundaries.csv"),
          row.names = FALSE)
cat("✅ bin_boundaries.csv saved\n")
✅ bin_boundaries.csv saved
# Full metadata
write.csv(mapped_MalignantCD4T@meta.data,
          file.path(out_dir, "metadata_full.csv"),
          row.names = TRUE)
cat("✅ metadata_full.csv saved\n")
✅ metadata_full.csv saved
cat("\nSaved files:\n")

Saved files:
print(list.files(out_dir))
[1] "bin_boundaries.csv"                     "Manuscript_Figures"                     "metadata_full.csv"                     
[4] "QC_Figures"                             "reference_integrated_RPCA_monocle3.Rds"

10 10. Manuscript Figures

All figures below are saved as high-resolution PNG (300 dpi) and PDF.

10.1 Figure 1 — Reference CD4+ T Cell Atlas

# Panel A: UMAP coloured by Azimuth l2
p_f1a <- DimPlot(
  reference_integrated,
  group.by  = "predicted.celltype.l2",
  reduction = "umap",
  label     = TRUE, repel = TRUE, label.size = 4.5, label.box = TRUE
) +
  scale_color_manual(values = azimuth_l2_colors, na.value = "grey70") +
  ggtitle("A  Healthy CD4\u207a T Cell Reference\n(Azimuth l2 States)") +
  theme_classic(base_size = 13) +
  theme(
    plot.title      = element_text(face = "bold", hjust = 0),
    legend.position = "bottom",
    legend.text     = element_text(size = 10)
  ) +
  guides(colour = guide_legend(nrow = 2, override.aes = list(size = 4)))

# Panel B: Pseudotime on reference UMAP
p_f1b <- FeaturePlot(
  reference_integrated,
  features  = "monocle3_pseudotime",
  reduction = "umap",
  order     = TRUE
) +
  scale_color_viridis_c(option = "plasma", name = "Pseudotime") +
  ggtitle("B  Monocle3 Pseudotime\n(Root = CD4 Naive)") +
  theme_classic(base_size = 13) +
  theme(plot.title = element_text(face = "bold", hjust = 0))

# Panel C: Pseudotime violin by state
state_order  <- c("CD4 Naive","CD4 TCM","Treg","CD4 TEM","CD4 Temra/CTL")
state_labels <- c("Naive","TCM","Treg","TEM","Temra/CTL")

pt_meta2 <- reference_integrated@meta.data %>%
  filter(is.finite(monocle3_pseudotime),
         predicted.celltype.l2 %in% state_order) %>%
  mutate(State = factor(predicted.celltype.l2,
                        levels = state_order,
                        labels = state_labels))

# ── Define colour vector BEFORE the ggplot call — never inside the + chain ───
azimuth_5 <- azimuth_l2_colors[state_order]
names(azimuth_5) <- state_labels

p_f1c <- ggplot(pt_meta2, aes(x = State, y = monocle3_pseudotime, fill = State)) +
  geom_violin(scale = "width", trim = TRUE, alpha = 0.85) +
  geom_boxplot(width = 0.12, fill = "white",
               outlier.size = 0.5, outlier.alpha = 0.3) +
  scale_fill_manual(values = azimuth_5) +
  geom_hline(
    yintercept = c(naive_med, tcm_med, treg_med, tem_med, temra_med),
    linetype = "dashed", colour = "black", linewidth = 0.4, alpha = 0.5
  ) +
  theme_classic(base_size = 13) +
  theme(
    legend.position = "none",
    axis.text.x     = element_text(angle = 30, hjust = 1),
    plot.title      = element_text(face = "bold", hjust = 0)
  ) +
  labs(
    title    = "C  Pseudotime by T Cell State",
    subtitle = sprintf("Naive=%.2f | TCM=%.2f | Treg=%.2f | TEM=%.2f | Temra=%.2f",
                       naive_med, tcm_med, treg_med, tem_med, temra_med),
    x = NULL, y = "Pseudotime"
  )

# ── Assemble figure ───────────────────────────────────────────────────────────
fig1 <- (p_f1a | p_f1b) / p_f1c +
  plot_layout(heights = c(1.2, 1)) +
  plot_annotation(
    title    = "Figure 1 — Healthy CD4\u207a T Cell Reference Atlas",
    subtitle = sprintf("n=%d cells | Monocle3 trajectory | Root: CD4 Naive",
                       ncol(reference_integrated)),
    theme    = theme(
      plot.title    = element_text(size = 16, face = "bold"),
      plot.subtitle = element_text(size = 11, colour = "grey40")
    )
  )

fig1

save_fig(fig1, "Figure1_Reference_Atlas", subdir = fig_dir_ms, w = 18, h = 14)

10.2 Figure 2 — Sézary Cell Projection onto Reference

# Panel A: All Sézary cells on reference UMAP coloured by pseudotime
p_f2a <- ggplot() +
  geom_point(data = ref_bg, aes(UMAP_1, UMAP_2),
             colour = "grey67", size = 0.3, alpha = 0.5) +
  geom_point(data = query_coords %>% filter(is.finite(pseudotime)),
             aes(UMAP_1, UMAP_2, colour = pseudotime),
             size = 0.4, alpha = 0.8) +
  scale_colour_viridis_c(option = "plasma", name = "Transferred\nPseudotime") +
  theme_classic(base_size = 13) +
  ggtitle("A  Sézary Cells Projected onto\nHealthy CD4⁺ T Cell Reference") +
  theme(plot.title = element_text(face = "bold", hjust = 0))

# Panel B: Bins on UMAP
p_f2b <- ggplot() +
  geom_point(data = ref_bg, aes(UMAP_1, UMAP_2),
             colour = "grey67", size = 0.3, alpha = 0.5) +
  geom_point(data = query_bins %>% filter(!is.na(pseudotime_bin)),
             aes(UMAP_1, UMAP_2, colour = pseudotime_bin),
             size = 0.4, alpha = 0.8) +
  scale_colour_manual(values = bin_colors, name = "State Bin") +
  guides(colour = guide_legend(override.aes = list(size = 3.5, alpha = 1))) +
  theme_classic(base_size = 13) +
  ggtitle("B  Differentiation State Bins\n(Pseudotime-anchored)") +
  theme(plot.title = element_text(face = "bold", hjust = 0))

# Panel C: Bin % stacked by line
line_bin_df <- mapped_MalignantCD4T@meta.data %>%
  filter(!is.na(pseudotime_bin)) %>%
  count(cell_line, pseudotime_bin) %>%
  group_by(cell_line) %>%
  mutate(pct = 100 * n / sum(n)) %>%
  ungroup()

p_f2c <- ggplot(line_bin_df,
                aes(x = cell_line, y = pct, fill = pseudotime_bin)) +
  geom_bar(stat = "identity", width = 0.78) +
  scale_fill_manual(values = bin_colors, name = "State Bin") +
  scale_y_continuous(labels = function(x) paste0(x, "%")) +
  theme_classic(base_size = 13) +
  theme(
    legend.position = "right",
    plot.title = element_text(face = "bold", hjust = 0)
  ) +
  labs(title = "C  State Bin Composition per Cell Line",
       x = "Cell Line", y = "% Cells")

fig2 <- (p_f2a | p_f2b) / p_f2c +
  plot_layout(heights = c(1.3, 1)) +
  plot_annotation(
    title    = "Figure 2 — Sézary CD4⁺ T Cell Projection and State Assignment",
    subtitle = sprintf("n=%d cells across %d cell lines",
                       ncol(mapped_MalignantCD4T),
                       length(unique(mapped_MalignantCD4T$cell_line))),
    theme    = theme(
      plot.title    = element_text(size = 16, face = "bold"),
      plot.subtitle = element_text(size = 11, colour = "grey40")
    )
  )
fig2

save_fig(fig2, "Figure2_Sezary_Projection", subdir = fig_dir_ms, w = 18, h = 14)

10.3 Figure 2_v2 — Sézary Cell Projection (with correctly placed % labels)


# Panel A
p_f2a <- ggplot() +
  geom_point(data = ref_bg, aes(UMAP_1, UMAP_2),
             colour = "grey67", size = 0.3, alpha = 0.5) +
  geom_point(data = query_coords %>% filter(is.finite(pseudotime)),
             aes(UMAP_1, UMAP_2, colour = pseudotime),
             size = 0.4, alpha = 0.8) +
  scale_colour_viridis_c(option = "plasma", name = "Transferred\nPseudotime") +
  theme_classic(base_size = 13) +
  ggtitle("A  Sézary Cells Projected onto\nHealthy CD4\u207a T Cell Reference") +
  theme(plot.title = element_text(face = "bold", hjust = 0))

# Panel B
p_f2b <- ggplot() +
  geom_point(data = ref_bg, aes(UMAP_1, UMAP_2),
             colour = "grey67", size = 0.3, alpha = 0.5) +
  geom_point(data = query_bins %>% filter(!is.na(pseudotime_bin)),
             aes(UMAP_1, UMAP_2, colour = pseudotime_bin),
             size = 0.4, alpha = 0.8) +
  scale_colour_manual(values = bin_colors, name = "State Bin") +
  guides(colour = guide_legend(override.aes = list(size = 3.5, alpha = 1))) +
  theme_classic(base_size = 13) +
  ggtitle("B  Differentiation State Bins\n(Pseudotime-anchored)") +
  theme(plot.title = element_text(face = "bold", hjust = 0))

# Panel C: stacked bar with correctly positioned % labels
# ── KEY FIX: sort within each line by the SAME factor order ggplot uses,
#    then cumsum so the midpoints match the actual rendered stack position ──
bin_level_order <- c("Naive-like","TCM-like","Treg-like","TEM-like","Temra-like")

line_bin_df <- mapped_MalignantCD4T@meta.data %>%
  filter(!is.na(pseudotime_bin)) %>%
  count(cell_line, pseudotime_bin) %>%
  group_by(cell_line) %>%
  mutate(pct = 100 * n / sum(n)) %>%
  ungroup() %>%
  mutate(pseudotime_bin = factor(pseudotime_bin, levels = bin_level_order)) %>%
  # sort within each cell_line in REVERSE factor order — ggplot stacks
  # bottom-to-top in factor order, so cumsum must go bottom-to-top too
  arrange(cell_line, pseudotime_bin) %>%
  group_by(cell_line) %>%
  mutate(
    # position = midpoint of this segment in the stacked bar
    label_y = cumsum(pct) - 0.5 * pct,
    label   = ifelse(pct >= 3, sprintf("%.1f%%", pct), "")
  ) %>%
  ungroup()

p_f2c <- ggplot(line_bin_df,
                aes(x = cell_line, y = pct, fill = pseudotime_bin)) +
  geom_bar(stat = "identity", width = 0.78) +
  geom_text(
    aes(y = label_y, label = label),
    size     = 3.2,
    fontface = "bold",
    colour   = "white",
    vjust    = 0.5
  ) +
  scale_fill_manual(values = bin_colors, name = "State Bin") +
  scale_y_continuous(labels = function(x) paste0(x, "%"),
                     expand = expansion(mult = c(0, 0.02))) +
  theme_classic(base_size = 13) +
  theme(
    legend.position = "right",
    plot.title      = element_text(face = "bold", hjust = 0)
  ) +
  labs(title = "C  State Bin Composition per Cell Line",
       x = "Cell Line", y = "% Cells")

fig2_v2 <- (p_f2a | p_f2b) / p_f2c +
  plot_layout(heights = c(1.3, 1)) +
  plot_annotation(
    title    = "Figure 2 — Sézary CD4\u207a T Cell Projection and State Assignment",
    subtitle = sprintf("n=%d cells across %d cell lines",
                       ncol(mapped_MalignantCD4T),
                       length(unique(mapped_MalignantCD4T$cell_line))),
    theme    = theme(
      plot.title    = element_text(size = 16, face = "bold"),
      plot.subtitle = element_text(size = 11, colour = "grey40")
    )
  )

fig2_v2

save_fig(fig2_v2, "Figure2_v2_Sezary_Projection_pct_labels",
         subdir = fig_dir_ms, w = 18, h = 14)

10.4 Figure 3 — Pseudotime Distribution & State Composition

pt_sezary <- mapped_MalignantCD4T@meta.data %>%
  filter(is.finite(pseudotime_value), !is.na(pseudotime_bin)) %>%
  mutate(
    cell_line = factor(cell_line, levels = paste0("L", 1:7)),
    pseudotime_bin = factor(pseudotime_bin,
                            levels = c("Naive-like","TCM-like","Treg-like",
                                       "TEM-like","Temra-like"))
  )

# Panel A: Ridge plot of pseudotime per line
p_f3a <- ggplot(pt_sezary,
                aes(x = pseudotime_value, y = cell_line, fill = cell_line)) +
  geom_density_ridges(scale = 1.2, alpha = 0.85, colour = "white",
                      quantile_lines = TRUE, quantiles = 2) +
  geom_vline(xintercept = c(naive_tcm_cut, tcm_tem_cut, tem_temra_cut),
             linetype = "dashed", colour = "black", linewidth = 0.6, alpha = 0.7) +
  annotate("text",
           x = c(naive_tcm_cut, tcm_tem_cut, tem_temra_cut),
           y = 1.2, vjust = -0.2, hjust = -0.05,
           label = c("Naive|TCM","TCM|TEM","TEM|Temra"),
           size = 3, colour = "black") +
  scale_fill_manual(values = line_colors) +
  theme_classic(base_size = 13) +
  theme(legend.position = "none",
        plot.title = element_text(face = "bold", hjust = 0)) +
  labs(title = "A  Pseudotime Distribution per Cell Line",
       x = "Transferred Pseudotime", y = "Cell Line")

# Panel B: Bin proportions — overall bubble/bar
bin_total_df <- mapped_MalignantCD4T@meta.data %>%
  filter(!is.na(pseudotime_bin)) %>%
  count(pseudotime_bin) %>%
  mutate(pct = round(100 * n / sum(n), 1),
         pseudotime_bin = factor(pseudotime_bin,
                                 levels = c("Naive-like","TCM-like","Treg-like",
                                            "TEM-like","Temra-like")))

p_f3b <- ggplot(bin_total_df, aes(x = pseudotime_bin, y = pct,
                                   fill = pseudotime_bin)) +
  geom_bar(stat = "identity", width = 0.7) +
  geom_text(aes(label = sprintf("%.1f%%\n(n=%s)", pct, comma(n))),
            vjust = -0.3, size = 3.5, fontface = "bold") +
  scale_fill_manual(values = bin_colors) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.2)),
                     labels = function(x) paste0(x, "%")) +
  theme_classic(base_size = 13) +
  theme(legend.position = "none",
        axis.text.x = element_text(angle = 25, hjust = 1),
        plot.title = element_text(face = "bold", hjust = 0)) +
  labs(title = "B  State Bin Composition — All Sézary Cells",
       x = NULL, y = "% Cells")

# Panel C: Heatmap of bin % by line
line_bin_wide <- line_bin_df %>%
  dplyr::select(cell_line, pseudotime_bin, pct) %>%
  tidyr::pivot_wider(names_from = pseudotime_bin, values_from = pct,
                     values_fill = 0) %>%
  tibble::column_to_rownames("cell_line")

annot_colors <- list(State = bin_colors)
p_f3c_grob <- pheatmap(
  as.matrix(line_bin_wide),
  color        = colorRampPalette(c("white","#FEE090","#D73027"))(100),
  display_numbers = TRUE,
  number_format   = "%.1f",
  number_color    = "black",
  fontsize_number = 9,
  cluster_rows    = FALSE,
  cluster_cols    = FALSE,
  border_color    = "white",
  main            = "C  State Bin % by Cell Line",
  angle_col       = 45,
  silent          = TRUE
)

fig3 <- (p_f3a | p_f3b) /
  wrap_elements(p_f3c_grob$gtable) +
  plot_layout(heights = c(1.2, 1)) +
  plot_annotation(
    title    = "Figure 3 — Pseudotime Distribution and State Composition",
    theme    = theme(plot.title = element_text(size = 16, face = "bold"))
  )
fig3

save_fig(fig3, "Figure3_Pseudotime_Distribution", subdir = fig_dir_ms, w = 18, h = 14)

10.5 Figure 4 — Key Marker Expression by State Bin

DefaultAssay(mapped_MalignantCD4T) <- "SCT"

# Panels A–D: violin/dot plots of key state markers
state_markers <- list(
  "Naive/TCM"  = c("CCR7","SELL","TCF7","IL7R","LEF1"),
  "Treg"       = c("FOXP3","IL2RA","IKZF2","CTLA4","TNFRSF4"),
  "TEM"        = c("GZMK","GZMA","CCL5","NKG7","CX3CR1"),
  "Temra/CTL"  = c("GZMB","PRF1","GNLY","FGFBP2","FCGR3A")
)

all_ms <- unique(unlist(state_markers))
avail_ms <- intersect(all_ms, rownames(mapped_MalignantCD4T))

dp <- DotPlot(
  mapped_MalignantCD4T,
  features    = avail_ms,
  group.by    = "pseudotime_bin",
  assay       = "SCT",
  dot.scale   = 7
) +
  scale_color_gradient2(low = "#2166AC", mid = "white", high = "#D73027",
                        midpoint = 0, name = "Avg Expr") +
  theme_classic(base_size = 12) +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, size = 9),
    plot.title  = element_text(face = "bold", hjust = 0)
  ) +
  labs(title = "Figure 4 — Key T Cell Marker Expression by Pseudotime Bin",
       x = NULL, y = "State Bin")
dp

save_fig(dp, "Figure4_Marker_DotPlot", subdir = fig_dir_ms, w = 18, h = 7)

10.6 Supplementary Figure S1 — Per-Cell-Line UMAP Projections

line_plot_list <- lapply(paste0("L", 1:7), function(ln) {
  df_ln <- query_bins %>% filter(cell_line == ln)

  ggplot() +
    geom_point(data = ref_bg, aes(UMAP_1, UMAP_2),
               colour = "grey90", size = 0.25, alpha = 0.4) +
    geom_point(data = df_ln %>% filter(!is.na(pseudotime_bin)),
               aes(UMAP_1, UMAP_2, colour = pseudotime_bin),
               size = 0.6, alpha = 0.9) +
    scale_colour_manual(values = bin_colors, name = "Bin") +
    theme_classic(base_size = 11) +
    theme(legend.position = "none",
          plot.title = element_text(face = "bold", hjust = 0.5, size = 10)) +
    ggtitle(sprintf("%s (n=%s)", ln, comma(nrow(df_ln))))
})

# Shared legend
legend_plot <- ggplot(
  data.frame(x=1:5, y=1, bin=names(bin_colors)),
  aes(x, y, colour = bin)
) +
  geom_point(size = 4) +
  scale_colour_manual(values = bin_colors, name = "State Bin") +
  guides(colour = guide_legend(override.aes = list(size = 5))) +
  theme_void() +
  theme(legend.position = "right")
shared_legend <- cowplot::get_legend(legend_plot)

s1_grid <- wrap_plots(line_plot_list, ncol = 4) +
  plot_annotation(
    title    = "Supplementary Figure S1 — Pseudotime Bin Distribution per Cell Line",
    subtitle = "Grey background = healthy reference cells",
    theme    = theme(
      plot.title    = element_text(size = 15, face = "bold"),
      plot.subtitle = element_text(size = 10, colour = "grey40")
    )
  )

# Attach shared legend to right side using cowplot
s1 <- cowplot::plot_grid(s1_grid, shared_legend,
                         ncol = 2, rel_widths = c(1, 0.08))
s1

# cowplot::plot_grid() returns a gtable, not a ggplot — use save_plot not ggsave
cowplot::save_plot(
  filename = file.path(fig_dir_ms, "SuppFig_S1_per_line_UMAP.png"),
  plot     = s1,
  base_width = 22, base_height = 14, dpi = 300, bg = "white"
)
cowplot::save_plot(
  filename = file.path(fig_dir_pdf, "SuppFig_S1_per_line_UMAP.pdf"),
  plot     = s1,
  base_width = 22, base_height = 14
)

10.7 Supplementary Figure S2 — Anchor & Transfer Quality

# Anchor scores
p_s2a <- ggplot(anchor_df, aes(x = score)) +
  geom_histogram(bins = 60, fill = "#2166AC", colour = "white", alpha = 0.85) +
  geom_vline(xintercept = median(anchor_df$score),
             linetype = "dashed", colour = "red", linewidth = 0.8) +
  annotate("text", x = median(anchor_df$score) + 0.02, y = Inf, vjust = 1.5, hjust = 0,
           label = sprintf("median=%.3f", median(anchor_df$score)),
           colour = "red", size = 3.5) +
  theme_classic(base_size = 12) +
  labs(title = "A  Transfer Anchor Score Distribution",
       subtitle = sprintf("n=%d anchors | cells:anchors = %.1f:1",
                          n_anchors, anchor_ratio),
       x = "Anchor Score", y = "Count")

# Label transfer confidence
if (score_col %in% colnames(mapped_MalignantCD4T@meta.data)) {
  sc_df <- data.frame(score = mapped_MalignantCD4T@meta.data[[score_col]])
  p_s2b <- ggplot(sc_df, aes(x = score)) +
    geom_histogram(bins = 60, fill = "#D73027", colour = "white", alpha = 0.85) +
    geom_vline(xintercept = median(sc_df$score, na.rm = TRUE),
               linetype = "dashed", colour = "black", linewidth = 0.8) +
    annotate("text", x = median(sc_df$score, na.rm = TRUE) - 0.02,
             y = Inf, vjust = 1.5, hjust = 1,
             label = sprintf("median=%.3f", median(sc_df$score, na.rm = TRUE)),
             colour = "black", size = 3.5) +
    theme_classic(base_size = 12) +
    labs(title = "B  Label Transfer Confidence Score — Sézary Cells",
         x = "Score", y = "Cell Count")
} else {
  p_s2b <- ggplot() + theme_void() + ggtitle("Score column not available")
}

s2 <- p_s2a | p_s2b
s2 <- s2 + plot_annotation(
  title = "Supplementary Figure S2 — Transfer Quality Metrics",
  theme = theme(plot.title = element_text(size = 15, face = "bold"))
)
s2

save_fig(s2, "SuppFig_S2_transfer_quality", subdir = fig_dir_ms, w = 16, h = 7)

11 11. Figure File Summary

cat("=== QC Figures saved ===\n")
=== QC Figures saved ===
qc_files <- list.files(fig_dir_qc, pattern = "\\.png$")
for (f in qc_files) cat(" ", f, "\n")
  QC_DotPlot_AzimuthL2_markers.png 
  QC1_incoming_reference_UMAP.png 
  QC10_anchor_score_distribution.png 
  QC11_sezary_projection_overview.png 
  QC12_label_transfer_confidence.png 
  QC13_pseudotime_bin_distribution.png 
  QC14_bins_on_UMAP.png 
  QC2_reference_UMAP_verified.png 
  QC3_reference_marker_features.png 
  QC4_principal_graph_cell_type.png 
  QC5_monocle3_pseudotime_UMAP.png 
  QC6_pseudotime_by_state_violin.png 
  QC8_sezary_cell_counts.png 
  QC9_HVG_overlap.png 
cat("\n=== Manuscript Figures saved ===\n")

=== Manuscript Figures saved ===
ms_files <- list.files(fig_dir_ms, pattern = "\\.png$")
for (f in ms_files) cat(" ", f, "\n")
  Figure1_Reference_Atlas.png 
  Figure2_Sezary_Projection.png 
  Figure3_Pseudotime_Distribution.png 
  Figure4_Marker_DotPlot.png 
  SuppFig_S1_per_line_UMAP.png 
  SuppFig_S2_transfer_quality.png 
cat("\n=== PDF Versions ===\n")

=== PDF Versions ===
pdf_files <- list.files(fig_dir_pdf, pattern = "\\.pdf$")
for (f in pdf_files) cat(" ", f, "\n")
  Figure1_Reference_Atlas.pdf 
  Figure2_Sezary_Projection.pdf 
  Figure3_Pseudotime_Distribution.pdf 
  Figure4_Marker_DotPlot.pdf 
  SuppFig_S1_per_line_UMAP.pdf 
  SuppFig_S2_transfer_quality.pdf 

12 12. Session Info

sessionInfo()
R version 4.5.2 (2025-10-31)
Platform: x86_64-redhat-linux-gnu
Running under: Rocky Linux 9.7 (Blue Onyx)

Matrix products: default
BLAS/LAPACK: FlexiBLAS OPENBLAS-OPENMP;  LAPACK version 3.9.0

locale:
 [1] LC_CTYPE=C.UTF-8       LC_NUMERIC=C           LC_TIME=C.UTF-8        LC_COLLATE=C.UTF-8     LC_MONETARY=C.UTF-8    LC_MESSAGES=C.UTF-8    LC_PAPER=C.UTF-8       LC_NAME=C              LC_ADDRESS=C          
[10] LC_TELEPHONE=C         LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C   

time zone: Europe/Paris
tzcode source: system (glibc)

attached base packages:
[1] stats4    stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] future_1.69.0               igraph_2.2.2                cowplot_1.2.0               pheatmap_1.0.13             scales_1.4.0                Matrix_1.7-4                ggrepel_0.9.6              
 [8] ggridges_0.5.7              viridis_0.6.5               viridisLite_0.4.3           RColorBrewer_1.1-3          patchwork_1.3.2             ggplot2_4.0.2               tibble_3.3.1               
[15] tidyr_1.3.2                 dplyr_1.2.0                 SeuratWrappers_0.4.0        monocle3_1.4.26             SingleCellExperiment_1.32.0 SummarizedExperiment_1.40.0 GenomicRanges_1.62.1       
[22] Seqinfo_1.0.0               IRanges_2.44.0              S4Vectors_0.48.0            MatrixGenerics_1.22.0       matrixStats_1.5.0           Biobase_2.70.0              BiocGenerics_0.56.0        
[29] generics_0.1.4              Seurat_5.4.0                SeuratObject_5.3.0          sp_2.2-1                   

loaded via a namespace (and not attached):
  [1] rstudioapi_0.18.0         jsonlite_2.0.0            magrittr_2.0.4            spatstat.utils_3.2-1      nloptr_2.2.1              farver_2.1.2              ragg_1.5.0               
  [8] vctrs_0.7.1               ROCR_1.0-12               DelayedMatrixStats_1.32.0 minqa_1.2.8               spatstat.explore_3.7-0    htmltools_0.5.9           S4Arrays_1.10.1          
 [15] SparseArray_1.10.8        sctransform_0.4.3         parallelly_1.46.1         KernSmooth_2.23-26        htmlwidgets_1.6.4         ica_1.0-3                 plyr_1.8.9               
 [22] plotly_4.12.0             zoo_1.8-15                mime_0.13                 lifecycle_1.0.5           pkgconfig_2.0.3           rsvd_1.0.5                R6_2.6.1                 
 [29] fastmap_1.2.0             rbibutils_2.4.1           fitdistrplus_1.2-6        shiny_1.12.1              digest_0.6.39             tensor_1.5.1              RSpectra_0.16-2          
 [36] irlba_2.3.7               textshaping_1.0.4         beachmat_2.26.0           labeling_0.4.3            progressr_0.18.0          spatstat.sparse_3.1-0     httr_1.4.8               
 [43] polyclip_1.10-7           abind_1.4-8               compiler_4.5.2            proxy_0.4-29              remotes_2.5.0             withr_3.0.2               S7_0.2.1                 
 [50] fastDummies_1.7.5         R.utils_2.13.0            MASS_7.3-65               DelayedArray_0.36.0       tools_4.5.2               lmtest_0.9-40             otel_0.2.0               
 [57] httpuv_1.6.16             future.apply_1.20.1       goftest_1.2-3             glmGamPoi_1.22.0          R.oo_1.27.1               glue_1.8.0                nlme_3.1-168             
 [64] promises_1.5.0            grid_4.5.2                Rtsne_0.17                cluster_2.1.8.2           reshape2_1.4.5            gtable_0.3.6              spatstat.data_3.1-9      
 [71] R.methodsS3_1.8.2         data.table_1.18.2.1       XVector_0.50.0            spatstat.geom_3.7-0       RcppAnnoy_0.0.23          RANN_2.6.2                pillar_1.11.1            
 [78] stringr_1.6.0             spam_2.11-3               RcppHNSW_0.6.0            later_1.4.6               splines_4.5.2             lattice_0.22-9            survival_3.8-6           
 [85] deldir_2.0-4              tidyselect_1.2.1          miniUI_0.1.2              pbapply_1.7-4             knitr_1.51                reformulas_0.4.4          gridExtra_2.3            
 [92] scattermore_1.2           xfun_0.56                 stringi_1.8.7             lazyeval_0.2.2            boot_1.3-32               evaluate_1.0.5            codetools_0.2-20         
 [99] BiocManager_1.30.27       cli_3.6.5                 uwot_0.2.4                systemfonts_1.3.1         Rdpack_2.6.6              xtable_1.8-4              reticulate_1.45.0        
[106] dichromat_2.0-0.1         Rcpp_1.1.1                globals_0.19.0            spatstat.random_3.4-4     png_0.1-8                 spatstat.univar_3.1-6     parallel_4.5.2           
[113] assertthat_0.2.1          dotCall64_1.2             sparseMatrixStats_1.22.0  lme4_1.1-38               listenv_0.10.0            purrr_1.2.1               rlang_1.1.7              
LS0tCnRpdGxlOiAiU8OpemFyeSBDRDQrIFQgQ2VsbCBQc2V1ZG90aW1lIE1hcHBpbmcgUGlwZWxpbmUiCnN1YnRpdGxlOiAidjMg4oCUIEhlYWx0aHkgUmVmZXJlbmNlIChSUENBIGludGFjdCkg4oaSIE1vbm9jbGUzIFRyYWplY3Rvcnkg4oaSIFPDqXphcnkgUHJvamVjdGlvbiIKYXV0aG9yOiAiTmFzaXIgTWFobW9vZCBBYmJhc2kiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICB0aGVtZTogam91cm5hbAogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgZmlnX3dpZHRoOiAxNAogICAgZmlnX2hlaWdodDogOQotLS0KCjwhLS0K4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQClBJUEVMSU5FIERFU0lHTiDigJQgUkVBRCBCRUZPUkUgRURJVElORwrilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZAKCklOUFVUOiAgQ0Q0X3JlZmVyZW5jZV9jbGVhbl9BemltdXRoX3JlYWR5X2Zvcl9TbGluZ3Nob3QucmRzCiAgICAgICAg4oazIEhlYWx0aHkgQ0Q0KyBUIGNlbGxzLCBBemltdXRoIGwyIGxhYmVscywgVU1BUCBtb2RlbCBpbnRhY3QsCiAgICAgICAgICBIYXJtb255L2ludGVncmF0ZWQgUENBICg1MCBkaW1zKSwgUk5BICsgU0NUICsgaW50ZWdyYXRlZCBhc3NheXMKClNURVAgMTogUmVmZXJlbmNlIOKAlCBLRUVQIGV4aXN0aW5nIENDQSBpbnRlZ3JhdGlvbiBpbnRhY3QKICAgICAgICDihrMgaW50ZWdyYXRlZCBhc3NheSwgNTAtZGltIFBDQSwgVU1BUCBtb2RlbCBhbHJlYWR5IGZyb3plbgogICAgICAgIOKGsyBEbyBOT1QgcmUtcnVuIFNDVHJhbnNmb3JtIG9yIFJ1blVNQVAg4oCUIHRoaXMgZGVzdHJveXMgYmF0Y2ggY29ycmVjdGlvbgoKU1RFUCAyOiBNb25vY2xlMyB0cmFqZWN0b3J5IG9uIGZyb3plbiBVTUFQCiAgICAgICAg4oazIGxlYXJuX2dyYXBoIG9uY2Ug4oaSIG9yZGVyX2NlbGxzIG9uY2Ug4oaSIG1vbm9jbGUzX3BzZXVkb3RpbWUgRlJPWkVOCiAgICAgICAg4oazIFRoaXMgY29sdW1uIGlzIHRoZSBzaW5nbGUgcHNldWRvdGltZSB2YWx1ZSB0cmFuc2ZlcnJlZCBieSBNYXBRdWVyeQoKU1RFUCAzOiBTw6l6YXJ5IGNlbGxzIOKAlCBwZXItbGluZSBTQ1RyYW5zZm9ybSwgc2hhcmVkIEhWRyBpbnRlcnNlY3Rpb24sIFBDQQoKU1RFUCA0OiBGaW5kVHJhbnNmZXJBbmNob3JzICsgTWFwUXVlcnkgaW4gY29uc2lzdGVudCBTQ1QgUENBIHNwYWNlCgpTVEVQIDU6IEJpbiBib3VuZGFyaWVzIGZyb20gcmVmZXJlbmNlIHN0YXRlIG1lZGlhbnMKClNURVAgNjogUUMgZmlndXJlcyBmb3IgZXZlcnkgc3RlcAoKU1RFUCA3OiBNYW51c2NyaXB0IGZpZ3VyZXMKCktFWSBDT05TVFJBSU5UOiBtb25vY2xlM19wc2V1ZG90aW1lIGlzIE5FVkVSIG92ZXJ3cml0dGVuIGFmdGVyIG9yZGVyX2NlbGxzLgrilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZAKLS0+CgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVjaG8gICAgICA9IFRSVUUsCiAgd2FybmluZyAgID0gRkFMU0UsCiAgbWVzc2FnZSAgID0gRkFMU0UsCiAgZmlnLmFsaWduID0gImNlbnRlciIsCiAgZHBpICAgICAgID0gMTIwCikKYGBgCgotLS0KCiMgMS4gTGlicmFyaWVzICYgR2xvYmFsIFNldHRpbmdzIHsjbGlicmFyaWVzfQoKYGBge3IgbGlicmFyaWVzfQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMoewogIGxpYnJhcnkoU2V1cmF0KQogIGxpYnJhcnkobW9ub2NsZTMpCiAgbGlicmFyeShTZXVyYXRXcmFwcGVycykKICBsaWJyYXJ5KGRwbHlyKQogIGxpYnJhcnkodGlkeXIpCiAgbGlicmFyeSh0aWJibGUpCiAgbGlicmFyeShnZ3Bsb3QyKQogIGxpYnJhcnkocGF0Y2h3b3JrKQogIGxpYnJhcnkoUkNvbG9yQnJld2VyKQogIGxpYnJhcnkodmlyaWRpcykKICBsaWJyYXJ5KGdncmlkZ2VzKQogIGxpYnJhcnkoZ2dyZXBlbCkKICBsaWJyYXJ5KE1hdHJpeCkKICBsaWJyYXJ5KHNjYWxlcykKICBsaWJyYXJ5KHBoZWF0bWFwKQogIGxpYnJhcnkoY293cGxvdCkKICBsaWJyYXJ5KGlncmFwaCkKfSkKCnNldC5zZWVkKDEyMzQpCm9wdGlvbnMoZnV0dXJlLmdsb2JhbHMubWF4U2l6ZSA9IDhlOSkKCiMg4pSA4pSAIENvbnNpc3RlbnQgY29sb3VyIHBhbGV0dGVzIHVzZWQgdGhyb3VnaG91dCDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKYXppbXV0aF9sMl9jb2xvcnMgPC0gYygKICAiQ0Q0IE5haXZlIiAgICAgPSAiIzIxNjZBQyIsCiAgIkNENCBUQ00iICAgICAgID0gIiM3NEFERDEiLAogICJDRDQgVEVNIiAgICAgICA9ICIjRkVFMDkwIiwKICAiQ0Q0IFRlbXJhL0NUTCIgPSAiI0Q3MzAyNyIsCiAgIlRyZWciICAgICAgICAgID0gIiM3NjJBODMiCikKCmJpbl9jb2xvcnMgPC0gYygKICAiTmFpdmUtbGlrZSIgID0gIiMyMTY2QUMiLAogICJUQ00tbGlrZSIgICAgPSAiIzc0QUREMSIsCiAgIlRyZWctbGlrZSIgICA9ICIjNzYyQTgzIiwKICAiVEVNLWxpa2UiICAgID0gIiNGRUUwOTAiLAogICJUZW1yYS1saWtlIiAgPSAiI0Q3MzAyNyIKKQoKbGluZV9jb2xvcnMgPC0gc2V0TmFtZXMoCiAgY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDgsICJEYXJrMiIpKSg3KSwKICBwYXN0ZTAoIkwiLCAxOjcpCikKCiMg4pSA4pSAIE91dHB1dCBkaXJlY3RvcmllcyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKb3V0X2RpciAgICAgPC0gInJlc3VsdHMvTWFwcGluZ19QaXBlbGluZV92MyIKZmlnX2Rpcl9xYyAgPC0gZmlsZS5wYXRoKG91dF9kaXIsICJRQ19GaWd1cmVzIikKZmlnX2Rpcl9tcyAgPC0gZmlsZS5wYXRoKG91dF9kaXIsICJNYW51c2NyaXB0X0ZpZ3VyZXMiKQpmaWdfZGlyX3BkZiA8LSBmaWxlLnBhdGgob3V0X2RpciwgIk1hbnVzY3JpcHRfRmlndXJlcy9QREYiKQoKZm9yIChkIGluIGMob3V0X2RpciwgZmlnX2Rpcl9xYywgZmlnX2Rpcl9tcywgZmlnX2Rpcl9wZGYpKQogIGRpci5jcmVhdGUoZCwgcmVjdXJzaXZlID0gVFJVRSwgc2hvd1dhcm5pbmdzID0gRkFMU0UpCgojIOKUgOKUgCBTYXZlIGhlbHBlciDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKc2F2ZV9maWcgPC0gZnVuY3Rpb24ocCwgbmFtZSwgc3ViZGlyID0gZmlnX2Rpcl9xYywgdyA9IDE0LCBoID0gOSkgewogIHBuZ19wYXRoIDwtIGZpbGUucGF0aChzdWJkaXIsIHBhc3RlMChuYW1lLCAiLnBuZyIpKQogIHBkZl9wYXRoIDwtIGZpbGUucGF0aChmaWdfZGlyX3BkZiwgcGFzdGUwKG5hbWUsICIucGRmIikpCiAgZ2dzYXZlKHBuZ19wYXRoLCBwbG90ID0gcCwgd2lkdGggPSB3LCBoZWlnaHQgPSBoLCBkcGkgPSAzMDAsIGJnID0gIndoaXRlIikKICBpZiAoc3ViZGlyID09IGZpZ19kaXJfbXMpCiAgICBnZ3NhdmUocGRmX3BhdGgsIHBsb3QgPSBwLCB3aWR0aCA9IHcsIGhlaWdodCA9IGgsIGRldmljZSA9IGNhaXJvX3BkZikKICBpbnZpc2libGUocCkKfQoKY2F0KCI9PT0gRW52aXJvbm1lbnQgcmVhZHkgPT09XG4iKQpjYXQoIlNldXJhdCAgOiIsIGFzLmNoYXJhY3RlcihwYWNrYWdlVmVyc2lvbigiU2V1cmF0IikpLCAgIlxuIikKY2F0KCJNb25vY2xlMzoiLCBhcy5jaGFyYWN0ZXIocGFja2FnZVZlcnNpb24oIm1vbm9jbGUzIikpLCAiXG4iKQpjYXQoIk91dHB1dCAgOiIsIG91dF9kaXIsICJcbiIpCmBgYAoKLS0tCgojIDIuIExvYWQgJiBWYWxpZGF0ZSBSZWZlcmVuY2UgT2JqZWN0IHsjbG9hZC1yZWZlcmVuY2V9CgpgYGB7ciBsb2FkLXJlZmVyZW5jZSwgZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTd9CiMg4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQCiMgTG9hZCB0aGUgU2xpbmdzaG90LXJlYWR5IGhlYWx0aHkgcmVmZXJlbmNlIG9iamVjdC4KIyBUaGlzIG9iamVjdCB3YXMgY29uZmlybWVkIHRvIGhhdmU6CiMgICDinIUgVU1BUCBtb2RlbCAoaW50YWN0IOKAlCB3aWxsIE5PVCBiZSByZXBsYWNlZCkKIyAgIOKchSBwcmVkaWN0ZWQuY2VsbHR5cGUubDIgKEF6aW11dGggbDIpCiMgICDinIUgY2VsbF90eXBlLCBzZXVyYXRfY2x1c3RlcnMsIHBlcmNlbnQubXQsIFMuU2NvcmUsIEcyTS5TY29yZQojICAg4pyFIFNDVCBhc3NheSAoSFZHcz0yOTAyLCBwZXItc2FtcGxlIG1vZGVscykKIyAgIOKchSBpbnRlZ3JhdGVkIFBDQSA1MCBkaW1zIChpbnRhY3Qg4oCUIHdpbGwgTk9UIGJlIHJlcGxhY2VkKQojICAg4pyFIE5vIHByb2xpZmVyYXRpbmcgY2VsbHMKIyDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZAKCnJlZmVyZW5jZV9pbnRlZ3JhdGVkIDwtIHJlYWRSRFMoCiAgIi4uLy4uLzEtRmluYWxfQ3VzdG9tX01TVF9Nb25vY2xlM19UcmFqZWN0b3J5X2FuZF9tYXBwaW5nL0NENF9yZWZlcmVuY2VfY2xlYW5fQXppbXV0aF9yZWFkeV9mb3JfU2xpbmdzaG90LnJkcyIKKQoKY2F0KCI9PT0gUmVmZXJlbmNlIG9iamVjdCBsb2FkZWQgPT09XG4iKQpjYXQoIkNlbGxzICAgICA6IiwgbmNvbChyZWZlcmVuY2VfaW50ZWdyYXRlZCksICJcbiIpCmNhdCgiQXNzYXlzICAgIDoiLCBwYXN0ZShuYW1lcyhyZWZlcmVuY2VfaW50ZWdyYXRlZEBhc3NheXMpLCBjb2xsYXBzZSA9ICIsICIpLCAiXG4iKQpjYXQoIlJlZHVjdGlvbnM6IiwgcGFzdGUobmFtZXMocmVmZXJlbmNlX2ludGVncmF0ZWRAcmVkdWN0aW9ucyksIGNvbGxhcHNlID0gIiwgIiksICJcbiIpCgojIOKUgOKUgCBIYXJkIHN0b3BzOiBlc3NlbnRpYWwgbWV0YWRhdGEgbXVzdCBiZSBwcmVzZW50IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApzdG9waWZub3QoCiAgInByZWRpY3RlZC5jZWxsdHlwZS5sMiBtaXNzaW5nIiA9CiAgICAicHJlZGljdGVkLmNlbGx0eXBlLmwyIiAlaW4lIGNvbG5hbWVzKHJlZmVyZW5jZV9pbnRlZ3JhdGVkQG1ldGEuZGF0YSksCiAgImNlbGxfdHlwZSBtaXNzaW5nIiA9CiAgICAiY2VsbF90eXBlIiAlaW4lIGNvbG5hbWVzKHJlZmVyZW5jZV9pbnRlZ3JhdGVkQG1ldGEuZGF0YSksCiAgInVtYXAgcmVkdWN0aW9uIG1pc3NpbmciID0KICAgICJ1bWFwIiAlaW4lIG5hbWVzKHJlZmVyZW5jZV9pbnRlZ3JhdGVkQHJlZHVjdGlvbnMpLAogICJwY2EgcmVkdWN0aW9uIG1pc3NpbmciID0KICAgICJwY2EiICVpbiUgbmFtZXMocmVmZXJlbmNlX2ludGVncmF0ZWRAcmVkdWN0aW9ucykKKQoKIyBQcm9saWZlcmF0aW5nIGNlbGwgY2hlY2sKcHJvbGlmX2NoZWNrIDwtIGFueShncmVwbCgiUHJvbGlmfHByb2xpZnxjeWNsaW5nIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZmVyZW5jZV9pbnRlZ3JhdGVkJHByZWRpY3RlZC5jZWxsdHlwZS5sMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlnbm9yZS5jYXNlID0gVFJVRSkpCmlmIChwcm9saWZfY2hlY2spIHN0b3AoIlByb2xpZmVyYXRpbmcgY2VsbHMgZGV0ZWN0ZWQg4oCUIHJlbW92ZSBiZWZvcmUgcHJvY2VlZGluZy4iKQpjYXQoIlxu4pyFIE5vIHByb2xpZmVyYXRpbmcgY2VsbHNcbiIpCgojIOKUgOKUgCBFeHRlbmQgcGFsZXR0ZSBmb3IgYW55IGV4dHJhIGxhYmVscyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKcmVmX2wyX2xhYmVscyA8LSB1bmlxdWUoYXMuY2hhcmFjdGVyKHJlZmVyZW5jZV9pbnRlZ3JhdGVkJHByZWRpY3RlZC5jZWxsdHlwZS5sMikpCmV4dHJhIDwtIHNldGRpZmYocmVmX2wyX2xhYmVscywgbmFtZXMoYXppbXV0aF9sMl9jb2xvcnMpKQppZiAobGVuZ3RoKGV4dHJhKSA+IDApIHsKICBleHRyYV9jb2xvcnMgPC0gc2V0TmFtZXMoCiAgICBjb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwoOCwgIlNldDIiKSkobGVuZ3RoKGV4dHJhKSksIGV4dHJhKQogIGF6aW11dGhfbDJfY29sb3JzIDwtIGMoYXppbXV0aF9sMl9jb2xvcnMsIGV4dHJhX2NvbG9ycykKfQoKIyDilIDilIAgUUMgRmlndXJlIDE6IEluY29taW5nIHJlZmVyZW5jZSBVTUFQIChBemltdXRoIGwyICsgY2VsbF90eXBlKSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKcF9pbl9sMiA8LSBEaW1QbG90KAogIHJlZmVyZW5jZV9pbnRlZ3JhdGVkLAogIGdyb3VwLmJ5ICA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiLAogIHJlZHVjdGlvbiA9ICJ1bWFwIiwKICBsYWJlbCAgICAgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSAzLjUKKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGF6aW11dGhfbDJfY29sb3JzLCBuYS52YWx1ZSA9ICJncmV5NzAiKSArCiAgZ2d0aXRsZSgiSW5jb21pbmcgcmVmZXJlbmNlIOKAlCBBemltdXRoIGwyIikgKwogIHRoZW1lX2NsYXNzaWMoKSArIE5vTGVnZW5kKCkKCnBfaW5fY3QgPC0gRGltUGxvdCgKICByZWZlcmVuY2VfaW50ZWdyYXRlZCwKICBncm91cC5ieSAgPSAiY2VsbF90eXBlIiwKICByZWR1Y3Rpb24gPSAidW1hcCIsCiAgbGFiZWwgICAgID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBsYWJlbC5zaXplID0gMwopICsKICBnZ3RpdGxlKCJJbmNvbWluZyByZWZlcmVuY2Ug4oCUIGNlbGxfdHlwZSAob3JpZ2luYWwgbGFiZWxzKSIpICsKICB0aGVtZV9jbGFzc2ljKCkgKyBOb0xlZ2VuZCgpCgpxYzEgPC0gcF9pbl9sMiB8IHBfaW5fY3QKcWMxCnNhdmVfZmlnKHFjMSwgIlFDMV9pbmNvbWluZ19yZWZlcmVuY2VfVU1BUCIsIHcgPSAxOCwgaCA9IDgpCgpjYXQoIlxuQXppbXV0aCBsMiBkaXN0cmlidXRpb246XG4iKQpwcmludCh0YWJsZShyZWZlcmVuY2VfaW50ZWdyYXRlZCRwcmVkaWN0ZWQuY2VsbHR5cGUubDIpKQpjYXQoIlxuY2VsbF90eXBlIGRpc3RyaWJ1dGlvbjpcbiIpCnByaW50KHRhYmxlKHJlZmVyZW5jZV9pbnRlZ3JhdGVkJGNlbGxfdHlwZSkpCmBgYAoKCi0tLQoKIyAzLiBSZWZlcmVuY2U6IFZlcmlmeSBFeGlzdGluZyBJbnRlZ3JhdGlvbiAoTm8gUmVidWlsZCkgeyNyZWZlcmVuY2UtdmVyaWZ5fQoKPiAqKkRlc2lnbiBkZWNpc2lvbjoqKiBUaGUgcmVmZXJlbmNlIG9iamVjdCB3YXMgYWxyZWFkeSBpbnRlZ3JhdGVkIGFjcm9zcyAzIGRvbm9ycwo+IHVzaW5nIFNldXJhdCBSUENBIChgaW50ZWdyYXRlZGAgYXNzYXksIDUwLWRpbSBQQ0EsIFVNQVAgd2l0aCBmcm96ZW4gbW9kZWwpLgo+ICoqV2UgZG8gbm90IHJlLXJ1biBTQ1RyYW5zZm9ybSBvciByZWJ1aWxkIHRoZSBVTUFQLioqIERvaW5nIHNvIGRlc3Ryb3lzIHRoZQo+IGJpb2xvZ3kg4oCUIGNlbGxzIHNjYXR0ZXIgaW50byAxOCsgY2x1c3RlcnMgYmVjYXVzZSBTQ1Qgb24gYSBwcmUtaW50ZWdyYXRlZCBvYmplY3QKPiByZS1pbnRyb2R1Y2VzIGJhdGNoIHZhcmlhdGlvbiB0aGF0IENDQSBhbHJlYWR5IHJlbW92ZWQuCj4KPiAqKldoYXQgd2UgdXNlIGluc3RlYWQ6KioKPiAtIGByZWZlcmVuY2UucmVkdWN0aW9uID0gInBjYSJgIOKAlCB0aGUgZXhpc3RpbmcgaW50ZWdyYXRlZCBQQ0EgKDUwIGRpbXMpCj4gLSBgcmVkdWN0aW9uLm1vZGVsID0gInVtYXAiYCDigJQgdGhlIGV4aXN0aW5nIGZyb3plbiBVTUFQIG1vZGVsCj4gLSBNYWxpZ25hbnQgY2VsbHMgYXJlIHByb2Nlc3NlZCB3aXRoIGBucGNzID0gNTBgIHRvICoqbWF0Y2gqKiB0aGlzIGRpbWVuc2lvbmFsaXR5Cj4KPiBUaGUgU0NUIGFzc2F5IG9uIHRoZSByZWZlcmVuY2UgKEhWR3MgPSAyOTAyKSBpcyB1c2VkIG9ubHkgZm9yIGZlYXR1cmUKPiBpbnRlcnNlY3Rpb24gd2l0aCB0aGUgcXVlcnkg4oCUIG5vdCBmb3IgcmVidWlsZGluZyB0aGUgUENBLgoKYGBge3IgcmVmZXJlbmNlLXZlcmlmeSwgZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTd9CiMgS2VlcCBpbnRlZ3JhdGVkIGFzc2F5IGFjdGl2ZSAoUENBIHdhcyBidWlsdCBvbiB0aGlzKQpEZWZhdWx0QXNzYXkocmVmZXJlbmNlX2ludGVncmF0ZWQpIDwtICJpbnRlZ3JhdGVkIgoKY2F0KCI9PT0gUmVmZXJlbmNlIGludGVncmF0aW9uIHN1bW1hcnkgPT09XG4iKQpjYXQoIkFjdGl2ZSBhc3NheSAgIDoiLCBEZWZhdWx0QXNzYXkocmVmZXJlbmNlX2ludGVncmF0ZWQpLCAiXG4iKQpjYXQoIlBDQSBhc3NheSB1c2VkIDoiLCByZWZlcmVuY2VfaW50ZWdyYXRlZEByZWR1Y3Rpb25zJHBjYUBhc3NheS51c2VkLCAiXG4iKQpjYXQoIlBDQSBkaW1zICAgICAgIDoiLCBuY29sKEVtYmVkZGluZ3MocmVmZXJlbmNlX2ludGVncmF0ZWQsICJwY2EiKSksICJcbiIpCmNhdCgiU0NUIEhWR3MgICAgICAgOiIsIGxlbmd0aChWYXJpYWJsZUZlYXR1cmVzKHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCBhc3NheSA9ICJTQ1QiKSksICJcbiIpCmNhdCgiU0NUIG1vZGVscyAgICAgOiIsIGxlbmd0aChyZWZlcmVuY2VfaW50ZWdyYXRlZEBhc3NheXMkU0NUQFNDVE1vZGVsLmxpc3QpLAogICAgIihwZXItc2FtcGxlID0gY29ycmVjdClcbiIpCgojIEhBUkQgU1RPUDogVU1BUCBtb2RlbCBtdXN0IGJlIGludGFjdCDigJQgbmV2ZXIgcmUtcnVuIFJ1blVNQVAKc3RvcGlmbm90KAogICJVTUFQIG1vZGVsIG1pc3Npbmcg4oCUIE1hcFF1ZXJ5IHdpbGwgZmFpbCIgPQogICAgIWlzLm51bGwocmVmZXJlbmNlX2ludGVncmF0ZWRAcmVkdWN0aW9ucyR1bWFwQG1pc2MkbW9kZWwpCikKY2F0KCJVTUFQIG1vZGVsICAgICA6IGludGFjdFxuIikKY2F0KCJEb25vcnMgICAgICAgICA6IiwgbmxldmVscyhmYWN0b3IocmVmZXJlbmNlX2ludGVncmF0ZWQkb3JpZy5pZGVudCkpLCAiXG4iKQpwcmludCh0YWJsZShyZWZlcmVuY2VfaW50ZWdyYXRlZCRvcmlnLmlkZW50KSkKCiMgRGVmaW5lIGp1bmsgZ2VuZSBwYXR0ZXJuICh1c2VkIGxhdGVyIGluIMKnNSBmb3IgcXVlcnkgSFZHIGZpbHRlcmluZykKanVua19wYXR0ZXJuIDwtIHBhc3RlMCgKICAiXk1ULXxeUlBMfF5SUFN8IiwKICAiXkhTUHxeSFNQQXxeSFNQQnxeSFNQRHxeSFNQRXxeSFNQSHwiLAogICJeU05IR3xNQUxBVDF8TkVBVDF8WElTVHxeSElTVCIKKQoKIyBSZWNvbXB1dGUgY2x1c3RlcnMgb24gZXhpc3RpbmcgaW50ZWdyYXRlZCBQQ0Eg4oCUIGZvciBNb25vY2xlMyBDRFMgc2xvdCBPTkxZCiMgRG9lcyBOT1QgdG91Y2ggdGhlIFVNQVAgb3IgUENBCnJlZmVyZW5jZV9pbnRlZ3JhdGVkIDwtIEZpbmROZWlnaGJvcnMoCiAgcmVmZXJlbmNlX2ludGVncmF0ZWQsCiAgcmVkdWN0aW9uICA9ICJwY2EiLAogIGRpbXMgICAgICAgPSAxOjUwLAogIGdyYXBoLm5hbWUgPSAiaW50ZWdyYXRlZF9zbm4iLAogIHZlcmJvc2UgICAgPSBGQUxTRQopCnJlZmVyZW5jZV9pbnRlZ3JhdGVkIDwtIEZpbmRDbHVzdGVycygKICByZWZlcmVuY2VfaW50ZWdyYXRlZCwKICByZXNvbHV0aW9uICA9IDAuMywKICBncmFwaC5uYW1lICA9ICJpbnRlZ3JhdGVkX3NubiIsCiAgdmVyYm9zZSAgICAgPSBGQUxTRQopCmNhdCgiXG5DbHVzdGVycyAocmVzPTAuMyk6IiwgbmxldmVscyhyZWZlcmVuY2VfaW50ZWdyYXRlZCRzZXVyYXRfY2x1c3RlcnMpLCAiXG4iKQoKIyBRQyBGaWd1cmUgMjogY29uZmlybSBiaW9sb2d5IGlzIHByZXNlcnZlZCBvbiB0aGUgaW50YWN0IFVNQVAKcF91bWFwX2wyIDwtIERpbVBsb3QoCiAgcmVmZXJlbmNlX2ludGVncmF0ZWQsCiAgZ3JvdXAuYnkgID0gInByZWRpY3RlZC5jZWxsdHlwZS5sMiIsCiAgcmVkdWN0aW9uID0gInVtYXAiLAogIGxhYmVsICAgICA9IFRSVUUsIHJlcGVsID0gVFJVRSwgbGFiZWwuc2l6ZSA9IDQKKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGF6aW11dGhfbDJfY29sb3JzLCBuYS52YWx1ZSA9ICJncmV5NzAiKSArCiAgZ2d0aXRsZSgiUmVmZXJlbmNlIFVNQVAgKGludGVncmF0ZWQpIOKAlCBBemltdXRoIGwyIikgKwogIHRoZW1lX2NsYXNzaWMoKSArIE5vTGVnZW5kKCkKCnBfdW1hcF9jbCA8LSBEaW1QbG90KAogIHJlZmVyZW5jZV9pbnRlZ3JhdGVkLAogIGdyb3VwLmJ5ICA9ICJzZXVyYXRfY2x1c3RlcnMiLAogIHJlZHVjdGlvbiA9ICJ1bWFwIiwKICBsYWJlbCAgICAgPSBUUlVFLCBsYWJlbC5zaXplID0gNAopICsKICBnZ3RpdGxlKCJSZWZlcmVuY2UgVU1BUCDigJQgQ2x1c3RlcnMgKHJlcz0wLjMpIGZvciBNb25vY2xlMyBDRFMiKSArCiAgdGhlbWVfY2xhc3NpYygpICsgTm9MZWdlbmQoKQoKcF91bWFwX2N0IDwtIERpbVBsb3QoCiAgcmVmZXJlbmNlX2ludGVncmF0ZWQsCiAgZ3JvdXAuYnkgID0gImNlbGxfdHlwZSIsCiAgcmVkdWN0aW9uID0gInVtYXAiLAogIGxhYmVsICAgICA9IFRSVUUsIHJlcGVsID0gVFJVRSwgbGFiZWwuc2l6ZSA9IDMKKSArCiAgZ2d0aXRsZSgiUmVmZXJlbmNlIFVNQVAg4oCUIGNlbGxfdHlwZSIpICsKICB0aGVtZV9jbGFzc2ljKCkgKyBOb0xlZ2VuZCgpCgpxYzIgPC0gKHBfdW1hcF9sMiB8IHBfdW1hcF9jbCkgLyBwX3VtYXBfY3QKcWMyCnNhdmVfZmlnKHFjMiwgIlFDMl9yZWZlcmVuY2VfVU1BUF92ZXJpZmllZCIsIHcgPSAxOCwgaCA9IDE0KQoKIyBRQzogS2V5IG1hcmtlciBmZWF0dXJlIHBsb3RzIG9uIGludGFjdCBVTUFQCkRlZmF1bHRBc3NheShyZWZlcmVuY2VfaW50ZWdyYXRlZCkgPC0gIlNDVCIKbWFya2VyX2dlbmVzIDwtIGMoIkNDUjciLCAiU0VMTCIsICJUQ0Y3IiwgIklMN1IiLAogICAgICAgICAgICAgICAgICAiR1pNSyIsICJHWk1BIiwgIkdaTUIiLCAiUFJGMSIsCiAgICAgICAgICAgICAgICAgICJGT1hQMyIsICJJTDJSQSIsICJJS1pGMiIsCiAgICAgICAgICAgICAgICAgICJHTkxZIiwgIk5LRzciKQphdmFpbGFibGVfbWFya2VycyA8LSBpbnRlcnNlY3QobWFya2VyX2dlbmVzLCByb3duYW1lcyhyZWZlcmVuY2VfaW50ZWdyYXRlZCkpCnBfbWFya2VycyA8LSBGZWF0dXJlUGxvdCgKICByZWZlcmVuY2VfaW50ZWdyYXRlZCwKICBmZWF0dXJlcyAgPSBhdmFpbGFibGVfbWFya2VycywKICByZWR1Y3Rpb24gPSAidW1hcCIsCiAgbmNvbCAgICAgID0gNSwKICBjb2xzICAgICAgPSBjKCJsaWdodGdyZXkiLCAiI0Q3MzAyNyIpLAogIG9yZGVyICAgICA9IFRSVUUKKSAmCiAgdGhlbWVfY2xhc3NpYygpICYKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LCBmYWNlID0gImJvbGQiKSkKcF9tYXJrZXJzCnNhdmVfZmlnKHBfbWFya2VycywgIlFDM19yZWZlcmVuY2VfbWFya2VyX2ZlYXR1cmVzIiwgdyA9IDIwLCBoID0gMTApCgpEZWZhdWx0QXNzYXkocmVmZXJlbmNlX2ludGVncmF0ZWQpIDwtICJpbnRlZ3JhdGVkIgpjYXQoIlxuUmVmZXJlbmNlIHZlcmlmaWVkIOKAlCBVTUFQIGFuZCBQQ0EgaW50YWN0LCBiaW9sb2d5IHByZXNlcnZlZFxuIikKYGBgCgoKIyMgVmFsaWRhdGUgdXNpbmcga25vd24gbWFya2VycwoKYGBge3IgcGFuZWwtZG90cGxvdC1hemltdXRoLWwyLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD0xMH0KRGVmYXVsdEFzc2F5KHJlZmVyZW5jZV9pbnRlZ3JhdGVkKSA8LSAiUk5BIgoKIyBPcmRlciBtYXRjaGVzIHRyYWplY3Rvcnk6IE5haXZlIOKGkiBUQ00g4oaSIFRyZWcgYnJhbmNoIC8gVEVNIOKGkiBUZW1yYQphemltdXRoX2wyX29yZGVyIDwtIGMoCiAgIkNENCBOYWl2ZSIsCiAgIkNENCBUQ00iLAogICJUcmVnIiwKICAiQ0Q0IFRFTSIsCiAgIkNENCBUZW1yYS9DVEwiCikKCiMgT25seSBrZWVwIGwyIGxhYmVscyBwcmVzZW50IGluIHRoZSBvYmplY3QKYXppbXV0aF9sMl9vcmRlciA8LSBpbnRlcnNlY3QoCiAgYXppbXV0aF9sMl9vcmRlciwKICB1bmlxdWUocmVmZXJlbmNlX2ludGVncmF0ZWQkcHJlZGljdGVkLmNlbGx0eXBlLmwyKQopCgpyZWZlcmVuY2VfaW50ZWdyYXRlZEBtZXRhLmRhdGEkbDJfZmFjdG9yIDwtIGZhY3RvcigKICByZWZlcmVuY2VfaW50ZWdyYXRlZCRwcmVkaWN0ZWQuY2VsbHR5cGUubDIsCiAgbGV2ZWxzID0gYXppbXV0aF9sMl9vcmRlcgopCklkZW50cyhyZWZlcmVuY2VfaW50ZWdyYXRlZCkgPC0gImwyX2ZhY3RvciIKCnBhbmVsX2dlbmVzIDwtIGMoCiAgIyBOYWl2ZQogICJDQ1I3IiwiTEVGMSIsIlRDRjciLCJTRUxMIiwiS0xGMiIsIlNBVEIxIiwiSUw3UiIsIkNEMjciLCJNQUwiLAogICMgVENNCiAgIlMxMDBBNCIsIkFRUDMiLCJMVEIiLCJJVEdCMSIsIkNENDQiLCJDQ1I0IiwKICAjIFNoYXJlZCBhY3RpdmF0aW9uCiAgIkNENjkiLCJMTU5BIiwKICAjIFRFTQogICJHWk1LIiwiQ0NMNSIsIkVPTUVTIiwiQ1hDUjMiLCJIT1BYIiwiQ1hDUjQiLCJJRk5HIiwiVE5GIiwiQ0NSNSIsCiAgIyBUZW1yYS9DVEwKICAiR1pNQiIsIkdaTUEiLCJQUkYxIiwiTktHNyIsIkNYM0NSMSIsIkZHRkJQMiIsIkdOTFkiLCJUQlgyMSIsIlpFQjIiLAogICJGQ0dSM0EiLCJLTFJHMSIsIk5SNEEyIiwKICAjIFRyZWcKICAiRk9YUDMiLCJJTDJSQSIsIklLWkYyIiwiSUtaRjQiLCJUSUdJVCIsIlJUS04yIiwiVE5GUlNGMTgiLCJDVExBNCIsCiAgIyBDby1pbmhpYml0b3J5IOKAlCBUcmVnIHN1cHByZXNzaXZlIG1hY2hpbmVyeQogICJQRENEMSIsIkhBVkNSMiIsIkxBRzMiCikKCnBhbmVsX2dlbmVzIDwtIHVuaXF1ZShpbnRlcnNlY3QocGFuZWxfZ2VuZXMsIHJvd25hbWVzKHJlZmVyZW5jZV9pbnRlZ3JhdGVkKSkpCmNhdCgiR2VuZXMgZm91bmQ6IiwgbGVuZ3RoKHBhbmVsX2dlbmVzKSwgIi8iLCBsZW5ndGgodW5pcXVlKGMoCiAgIkNDUjciLCJMRUYxIiwiVENGNyIsIlNFTEwiLCJLTEYyIiwiU0FUQjEiLCJJTDdSIiwiQ0QyNyIsIk1BTCIsCiAgIlMxMDBBNCIsIkFRUDMiLCJMVEIiLCJJVEdCMSIsIkNENDQiLCJDQ1I0IiwiQ0Q2OSIsIkxNTkEiLAogICJHWk1LIiwiQ0NMNSIsIkVPTUVTIiwiQ1hDUjMiLCJIT1BYIiwiQ1hDUjQiLCJJRk5HIiwiVE5GIiwiQ0NSNSIsCiAgIkdaTUIiLCJHWk1BIiwiUFJGMSIsIk5LRzciLCJDWDNDUjEiLCJGR0ZCUDIiLCJHTkxZIiwiVEJYMjEiLCJaRUIyIiwKICAiRkNHUjNBIiwiS0xSRzEiLCJOUjRBMiIsCiAgIkZPWFAzIiwiSUwyUkEiLCJJS1pGMiIsIklLWkY0IiwiVElHSVQiLCJSVEtOMiIsIlRORlJTRjE4IiwiQ1RMQTQiLAogICJQRENEMSIsIkhBVkNSMiIsIkxBRzMiCikpKSwgIlxuIikKCnBfZG90cGxvdF9sMiA8LSBEb3RQbG90KAogIHJlZmVyZW5jZV9pbnRlZ3JhdGVkLAogIGZlYXR1cmVzICA9IHBhbmVsX2dlbmVzLAogIGdyb3VwLmJ5ICA9ICJsMl9mYWN0b3IiLAogIGNvbHMgICAgICA9IGMoImxpZ2h0Z3JleSIsICIjZDYyNzI4IiksCiAgZG90LnNjYWxlID0gNSwKICBzY2FsZSAgICAgPSBUUlVFLAogIGNvbC5taW4gICA9IC0xLjUsCiAgY29sLm1heCAgID0gMi41CikgKwogIFJvdGF0ZWRBeGlzKCkgKwogIGNvb3JkX2ZsaXAoKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQyKAogICAgbG93ICAgICAgPSAibGlnaHRncmV5IiwKICAgIG1pZCAgICAgID0gIiNmZWUwOTAiLAogICAgaGlnaCAgICAgPSAiI2Q2MjcyOCIsCiAgICBtaWRwb2ludCA9IDAuNSwKICAgIG5hbWUgICAgID0gIkF2ZyBFeHByZXNzaW9uIgogICkgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggICAgID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LCBmYWNlID0gImJvbGQiKSwKICAgIGF4aXMudGV4dC55ICAgICA9IGVsZW1lbnRfdGV4dChzaXplID0gNy41KSwKICAgIHBsb3QudGl0bGUgICAgICA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMsIGZhY2UgPSAiYm9sZCIpLAogICAgcGxvdC5zdWJ0aXRsZSAgID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LCBjb2xvdXIgPSAiZ3JleTQwIiksCiAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIgogICkgKwogIGxhYnMoCiAgICB0aXRsZSAgICA9ICJNYXJrZXIgZ2VuZSBleHByZXNzaW9uIOKAlCBBemltdXRoIGwyIGNlbGwgc3RhdGVzIiwKICAgIHN1YnRpdGxlID0gIiIKICApCgpwcmludChwX2RvdHBsb3RfbDIpCnNhdmVfZmlnKHBfZG90cGxvdF9sMiwgIlFDX0RvdFBsb3RfQXppbXV0aEwyX21hcmtlcnMiLCB3ID0gMTAsIGggPSAxMikKCiMgUmVzdG9yZSBhc3NheSBhbmQgaWRlbnRzCkRlZmF1bHRBc3NheShyZWZlcmVuY2VfaW50ZWdyYXRlZCkgPC0gImludGVncmF0ZWQiCklkZW50cyhyZWZlcmVuY2VfaW50ZWdyYXRlZCkgPC0gInByZWRpY3RlZC5jZWxsdHlwZS5sMiIKYGBgCgoKLS0tCgojIDQuIE1vbm9jbGUzIFRyYWplY3Rvcnkg4oCUIFNpbmdsZSBSdW4geyNtb25vY2xlM30KCj4gKipDcml0aWNhbDoqKiBgbGVhcm5fZ3JhcGhgIGFuZCBgb3JkZXJfY2VsbHNgIHJ1biAqKm9uY2UqKi4KPiBUaGUgcmVzdWx0aW5nIGBtb25vY2xlM19wc2V1ZG90aW1lYCBjb2x1bW4gaXMgKipuZXZlciBvdmVyd3JpdHRlbioqLgo+IFRoaXMgaXMgdGhlIGV4YWN0IHZhbHVlIE1hcFF1ZXJ5IHRyYW5zZmVycyB0byBTw6l6YXJ5IGNlbGxzLgoKYGBge3IgYnVpbGQtY2RzLCBmaWcud2lkdGg9MTQsIGZpZy5oZWlnaHQ9N30KY2F0KCI9PT0gQnVpbGRpbmcgTW9ub2NsZTMgQ0RTID09PVxuIikKCiMgQ1JJVElDQUw6IHNldCBEZWZhdWx0QXNzYXk9IlJOQSIgYmVmb3JlIGFzLmNlbGxfZGF0YV9zZXQoKQojICJpbnRlZ3JhdGVkIiBhc3NheSBjb250YWlucyBjZW50ZXJlZC9zY2FsZWQgdmFsdWVzIChjYW4gYmUgbmVnYXRpdmUpIOKAlAojIG1vbm9jbGUzIHNpemUgZmFjdG9yIGVzdGltYXRpb24gcmVxdWlyZXMgcmF3IGNvdW50cyBmcm9tIFJOQSBhc3NheS4KIyBsZWFybl9ncmFwaCBhbmQgb3JkZXJfY2VsbHMgdXNlIFVNQVAgY29vcmRzIG9ubHkgKHdoaWNoIHdlIG92ZXJ3cml0ZSksCiMgYnV0IHRoZSBDRFMgZXhwcmVzc2lvbiBtYXRyaXggbXVzdCBiZSBub24tbmVnYXRpdmUgZm9yIG1vbm9jbGUzIGludGVybmFscy4KRGVmYXVsdEFzc2F5KHJlZmVyZW5jZV9pbnRlZ3JhdGVkKSA8LSAiUk5BIgpjZHMgPC0gYXMuY2VsbF9kYXRhX3NldChyZWZlcmVuY2VfaW50ZWdyYXRlZCkKRGVmYXVsdEFzc2F5KHJlZmVyZW5jZV9pbnRlZ3JhdGVkKSA8LSAiaW50ZWdyYXRlZCIgICAjIHJlc3RvcmUgaW1tZWRpYXRlbHkKCiMgVHJhbnNmZXIgdGhlIGZyb3plbiBVTUFQIGNvb3JkaW5hdGVzIGludG8gQ0RTCiMgbGVhcm5fZ3JhcGggb3BlcmF0ZXMgaW4gdGhpcyAyRCBzcGFjZSBvbmx5IOKAlCBQQ0Egbm90IHVzZWQKcmVkdWNlZERpbShjZHMsICJVTUFQIikgPC0gRW1iZWRkaW5ncyhyZWZlcmVuY2VfaW50ZWdyYXRlZCwgInVtYXAiKQoKIyBTaW5nbGUgcGFydGl0aW9uOiBmb3JjZXMgb25lIGNvbm5lY3RlZCBncmFwaCBjYXB0dXJpbmcgZWZmZWN0b3IgKyBUcmVnIGxpbmVhZ2VzCnBhcnRpdGlvbl92ZWMgPC0gc2V0TmFtZXMoZmFjdG9yKHJlcCgxTCwgbmNvbChjZHMpKSksIGNvbG5hbWVzKGNkcykpCmNkc0BjbHVzdGVycyRVTUFQJHBhcnRpdGlvbnMgPC0gcGFydGl0aW9uX3ZlYwoKIyBUcmFuc2ZlciBTZXVyYXQgY2x1c3RlcnMKY2x1c3Rlcl92ZWMgPC0gc2V0TmFtZXMoCiAgZmFjdG9yKHJlZmVyZW5jZV9pbnRlZ3JhdGVkJHNldXJhdF9jbHVzdGVyc1tjb2xuYW1lcyhjZHMpXSksCiAgY29sbmFtZXMoY2RzKQopCmNkc0BjbHVzdGVycyRVTUFQJGNsdXN0ZXJzIDwtIGNsdXN0ZXJfdmVjCgojIE1ldGFkYXRhCmNvbERhdGEoY2RzKSRwcmVkaWN0ZWQuY2VsbHR5cGUubDIgPC0gcmVmZXJlbmNlX2ludGVncmF0ZWQkcHJlZGljdGVkLmNlbGx0eXBlLmwyCmlmICgiY2VsbF90eXBlIiAlaW4lIGNvbG5hbWVzKHJlZmVyZW5jZV9pbnRlZ3JhdGVkQG1ldGEuZGF0YSkpCiAgY29sRGF0YShjZHMpJGNlbGxfdHlwZSA8LSByZWZlcmVuY2VfaW50ZWdyYXRlZCRjZWxsX3R5cGUKCmNhdCgiQ0RTIGJ1aWx0OiIsIG5jb2woY2RzKSwgImNlbGxzXG4iKQpjYXQoIlBhcnRpdGlvbnM6IiwgbmxldmVscyhwYXJ0aXRpb25zKGNkcykpLCAiKHNob3VsZCBiZSAxKVxuIikKYGBgCgpgYGB7ciBsZWFybi1ncmFwaCwgZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTd9CiMg4pSA4pSAIExlYXJuIHByaW5jaXBhbCBncmFwaCDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKc2V0LnNlZWQoMTIzNCkKCmNkcyA8LSBsZWFybl9ncmFwaCgKICBjZHMsCiAgdXNlX3BhcnRpdGlvbiAgICAgICA9IEZBTFNFLAogIGNsb3NlX2xvb3AgICAgICAgICAgPSBGQUxTRSwKICBsZWFybl9ncmFwaF9jb250cm9sID0gbGlzdCgKICAgIG1pbmltYWxfYnJhbmNoX2xlbiAgPSAxMCwKICAgIG5jZW50ZXIgICAgICAgICAgICAgPSA5MDAsCiAgICBvcnRob2dvbmFsX3Byb2pfdGlwID0gRkFMU0UKICApLAogIHZlcmJvc2UgPSBGQUxTRQopCgoKCm5fbm9kZXMgIDwtIGxlbmd0aChpZ3JhcGg6OlYocHJpbmNpcGFsX2dyYXBoKGNkcykkVU1BUCkpCm5fYnJhbmNoIDwtIHN1bShpZ3JhcGg6OmRlZ3JlZShwcmluY2lwYWxfZ3JhcGgoY2RzKSRVTUFQKSA+IDIpCgpjYXQoIlxu4pyFIFByaW5jaXBhbCBncmFwaCBsZWFybmVkXG4iKQpjYXQoIk5vZGVzICAgICAgIDoiLCBuX25vZGVzLCAiXG4iKQpjYXQoIkJyYW5jaCBwb2ludHM6Iiwgbl9icmFuY2gsICIoZXhwZWN0ZWQgMS0zIGZvciBlZmZlY3RvciBheGlzICsgVHJlZyBicmFuY2gpXG4iKQoKaWYgKG5fYnJhbmNoID09IDApIHsKICBzdG9wKCJObyBicmFuY2ggcG9pbnQgZm91bmQg4oCUIFRyZWcgbGluZWFnZSBub3Qgc2VwYXJhdGVkLlxuIiwKICAgICAgICJGaXg6IHJlLXJ1biB3aXRoIG1pbmltYWxfYnJhbmNoX2xlbiA9IDUiKQp9IGVsc2UgaWYgKG5fYnJhbmNoID4gNSkgewogIHdhcm5pbmcocGFzdGUoIk1hbnkgYnJhbmNoIHBvaW50czoiLCBuX2JyYW5jaCwKICAgICAgICAgICAgICAgICLigJQgY29uc2lkZXIgbWluaW1hbF9icmFuY2hfbGVuID0gMTUiKSkKfQoKIyDilIDilIAgUUM6IEdyYXBoIGNvbG91cmVkIGJ5IGNlbGwgdHlwZSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKcF9ncmFwaF9sMiA8LSBwbG90X2NlbGxzKAogIGNkcywKICBjb2xvcl9jZWxsc19ieSAgICAgICAgPSAicHJlZGljdGVkLmNlbGx0eXBlLmwyIiwKICBsYWJlbF9jZWxsX2dyb3VwcyAgICAgPSBGQUxTRSwKICBzaG93X3RyYWplY3RvcnlfZ3JhcGggPSBUUlVFLAogIGNlbGxfc2l6ZSAgICAgICAgICAgICA9IDAuNywKICB0cmFqZWN0b3J5X2dyYXBoX2NvbG9yID0gImJsYWNrIiwKICB0cmFqZWN0b3J5X2dyYXBoX3NlZ21lbnRfc2l6ZSA9IDEuMgopICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYXppbXV0aF9sMl9jb2xvcnMsIG5hLnZhbHVlID0gImdyZXk3MCIpICsKICBnZ3RpdGxlKHNwcmludGYoIlByaW5jaXBhbCBncmFwaCDigJQgJWQgbm9kZXMsICVkIGJyYW5jaCBwb2ludHMiLCBuX25vZGVzLCBuX2JyYW5jaCkpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKSkKCnBfZ3JhcGhfbDIKc2F2ZV9maWcocF9ncmFwaF9sMiwgIlFDNF9wcmluY2lwYWxfZ3JhcGhfY2VsbF90eXBlIiwgdyA9IDEwLCBoID0gOCkKYGBgCgpgYGB7ciBwc2V1ZG90aW1lLXJvb3QsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD03fQojIOKUgOKUgCBSb290IHNlbGVjdGlvbjogY2VudHJvaWQgb2YgQ0Q0IE5haXZlIGNlbGxzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApuYWl2ZV9jZWxscyA8LSBjb2xuYW1lcyhjZHMpWwogIGdyZXBsKCJuYWl2ZXxOYWl2ZXxUTiQiLCBjb2xEYXRhKGNkcykkcHJlZGljdGVkLmNlbGx0eXBlLmwyLCBpZ25vcmUuY2FzZSA9IFRSVUUpXQpjYXQoIk5haXZlIGNlbGxzIGZvciByb290IGNlbnRyb2lkOiIsIGxlbmd0aChuYWl2ZV9jZWxscyksICJcbiIpCnN0b3BpZm5vdCgiTm8gTmFpdmUgY2VsbHMgZm91bmQiID0gbGVuZ3RoKG5haXZlX2NlbGxzKSA+IDApCgpuYWl2ZV91bWFwICAgICA8LSBFbWJlZGRpbmdzKHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCAidW1hcCIpW25haXZlX2NlbGxzLCBdCm5haXZlX2NlbnRyb2lkIDwtIGNvbE1lYW5zKG5haXZlX3VtYXApCmNhdChzcHJpbnRmKCJOYWl2ZSBjZW50cm9pZDogVU1BUDE9JS4zZiwgVU1BUDI9JS4zZlxuIiwKICAgICAgICAgICAgbmFpdmVfY2VudHJvaWRbMV0sIG5haXZlX2NlbnRyb2lkWzJdKSkKCnByX25vZGVzICAgPC0gdChjZHNAcHJpbmNpcGFsX2dyYXBoX2F1eFtbIlVNQVAiXV0kZHBfbXN0KQpub2RlX2Rpc3RzIDwtIHJvd1N1bXMoCiAgKHByX25vZGVzIC0gbWF0cml4KG5haXZlX2NlbnRyb2lkLCBucm93ID0gbnJvdyhwcl9ub2RlcyksIG5jb2wgPSAyLCBieXJvdyA9IFRSVUUpKV4yCikKcm9vdF9ub2RlIDwtIG5hbWVzKHdoaWNoLm1pbihub2RlX2Rpc3RzKSkKY2F0KCJSb290IG5vZGUgc2VsZWN0ZWQ6Iiwgcm9vdF9ub2RlLCAiXG4iKQoKIyDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZAKIyBPUkRFUiBDRUxMUyDigJQgbW9ub2NsZTNfcHNldWRvdGltZSBjb21wdXRlZCBoZXJlLCBORVZFUiBvdmVyd3JpdHRlbgojIOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkApjZHMgPC0gb3JkZXJfY2VsbHMoY2RzLCByb290X3ByX25vZGVzID0gcm9vdF9ub2RlKQoKIyBTdG9yZSBpbiByZWZlcmVuY2Ugb2JqZWN0CnJlZmVyZW5jZV9pbnRlZ3JhdGVkJG1vbm9jbGUzX3BzZXVkb3RpbWUgPC0gcHNldWRvdGltZShjZHMpCnJlZmVyZW5jZV9pbnRlZ3JhdGVkJG1vbm9jbGUzX3BzZXVkb3RpbWVbCiAgIWlzLmZpbml0ZShyZWZlcmVuY2VfaW50ZWdyYXRlZCRtb25vY2xlM19wc2V1ZG90aW1lKV0gPC0gTkEKCmNhdCgiXG7inIUgbW9ub2NsZTNfcHNldWRvdGltZSBzdG9yZWQgaW4gcmVmZXJlbmNlX2ludGVncmF0ZWQgKEZST1pFTilcbiIpCnByaW50KHN1bW1hcnkocmVmZXJlbmNlX2ludGVncmF0ZWQkbW9ub2NsZTNfcHNldWRvdGltZVsKICBpcy5maW5pdGUocmVmZXJlbmNlX2ludGVncmF0ZWQkbW9ub2NsZTNfcHNldWRvdGltZSldKSkKCiMg4pSA4pSAIFRvcG9sb2d5IHZhbGlkYXRpb24g4oCUIEhBUkQgU1RPUFMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACnB0X29yZGVyIDwtIHJlZmVyZW5jZV9pbnRlZ3JhdGVkQG1ldGEuZGF0YSAlPiUKICBmaWx0ZXIoaXMuZmluaXRlKG1vbm9jbGUzX3BzZXVkb3RpbWUpKSAlPiUKICBncm91cF9ieShwcmVkaWN0ZWQuY2VsbHR5cGUubDIpICU+JQogIHN1bW1hcmlzZSgKICAgIG4gICAgICA9IG4oKSwKICAgIG1lZF9wdCA9IHJvdW5kKG1lZGlhbihtb25vY2xlM19wc2V1ZG90aW1lLCBuYS5ybSA9IFRSVUUpLCAzKSwKICAgIC5ncm91cHMgPSAiZHJvcCIKICApICU+JQogIGFycmFuZ2UobWVkX3B0KQoKY2F0KCJcbj09PSBTdGF0ZSBtZWRpYW4gcHNldWRvdGltZXMgKHRvcG9sb2d5IGNoZWNrKSA9PT1cbiIpCnByaW50KHB0X29yZGVyKQoKZ2V0X21lZCA8LSBmdW5jdGlvbihzdGF0ZSkgewogIHYgPC0gcHRfb3JkZXIkbWVkX3B0W3B0X29yZGVyJHByZWRpY3RlZC5jZWxsdHlwZS5sMiA9PSBzdGF0ZV0KICBpZiAobGVuZ3RoKHYpID09IDApIHN0b3AocGFzdGUoIlN0YXRlIG5vdCBmb3VuZCBpbiB0b3BvbG9neToiLCBzdGF0ZSkpCiAgdgp9Cm5haXZlX21lZCA8LSBnZXRfbWVkKCJDRDQgTmFpdmUiKQp0Y21fbWVkICAgPC0gZ2V0X21lZCgiQ0Q0IFRDTSIpCnRyZWdfbWVkICA8LSBnZXRfbWVkKCJUcmVnIikKdGVtX21lZCAgIDwtIGdldF9tZWQoIkNENCBURU0iKQp0ZW1yYV9tZWQgPC0gZ2V0X21lZCgiQ0Q0IFRlbXJhL0NUTCIpCgppZiAobmFpdmVfbWVkID49IHRjbV9tZWQpCiAgc3RvcChzcHJpbnRmKCJUT1BPTE9HWSBFUlJPUjogTmFpdmUoJS4yZikgPj0gVENNKCUuMmYpIiwgbmFpdmVfbWVkLCB0Y21fbWVkKSkKaWYgKHRjbV9tZWQgPj0gdGVtX21lZCkKICBzdG9wKHNwcmludGYoIlRPUE9MT0dZIEVSUk9SOiBUQ00oJS4yZikgPj0gVEVNKCUuMmYpIiwgdGNtX21lZCwgdGVtX21lZCkpCmlmICh0ZW1fbWVkID49IHRlbXJhX21lZCkKICBzdG9wKHNwcmludGYoIlRPUE9MT0dZIEVSUk9SOiBURU0oJS4yZikgPj0gVGVtcmEoJS4yZikiLCB0ZW1fbWVkLCB0ZW1yYV9tZWQpKQppZiAodHJlZ19tZWQgPj0gdGVtX21lZCkKICBzdG9wKHNwcmludGYoCiAgICAiVE9QT0xPR1kgRVJST1I6IFRyZWcoJS4yZikgPj0gVEVNKCUuMmYpIOKAlCBUcmVnIG11c3QgYnJhbmNoIGZyb20gVENNXG4iLAogICAgdHJlZ19tZWQsIHRlbV9tZWQpKQoKY2F0KHNwcmludGYoCiAgIlxu4pyFIFRvcG9sb2d5IGNvbmZpcm1lZDogTmFpdmUoJS4zZikgPCBUQ00oJS4zZikgPCBUcmVnKCUuM2YpIDwgVEVNKCUuM2YpIDwgVGVtcmEoJS4zZilcbiIsCiAgbmFpdmVfbWVkLCB0Y21fbWVkLCB0cmVnX21lZCwgdGVtX21lZCwgdGVtcmFfbWVkCikpCgojIOKUgOKUgCBRQyBGaWd1cmU6IFBzZXVkb3RpbWUgb24gVU1BUCDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKcF9wdF9ncmFwaCA8LSBwbG90X2NlbGxzKAogIGNkcywKICBjb2xvcl9jZWxsc19ieSAgICAgICAgPSAicHNldWRvdGltZSIsCiAgbGFiZWxfY2VsbF9ncm91cHMgICAgID0gRkFMU0UsCiAgc2hvd190cmFqZWN0b3J5X2dyYXBoID0gVFJVRSwKICBjZWxsX3NpemUgICAgICAgICAgICAgPSAwLjcsCiAgdHJhamVjdG9yeV9ncmFwaF9jb2xvciA9ICJibGFjayIsCiAgdHJhamVjdG9yeV9ncmFwaF9zZWdtZW50X3NpemUgPSAxLjIKKSArCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKG9wdGlvbiA9ICJwbGFzbWEiLCBuYW1lID0gIlBzZXVkb3RpbWUiKSArCiAgZ2d0aXRsZSgiTW9ub2NsZTMgUHNldWRvdGltZSDigJQgUm9vdCA9IENENCBOYWl2ZSIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKSkKCnBfcHRfc2V1cmF0IDwtIEZlYXR1cmVQbG90KAogIHJlZmVyZW5jZV9pbnRlZ3JhdGVkLAogIGZlYXR1cmVzICA9ICJtb25vY2xlM19wc2V1ZG90aW1lIiwKICByZWR1Y3Rpb24gPSAidW1hcCIKKSArCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKG9wdGlvbiA9ICJwbGFzbWEiLCBuYW1lID0gIlBzZXVkb3RpbWUiKSArCiAgZ2d0aXRsZSgiUHNldWRvdGltZSBvbiBSZWZlcmVuY2UgVU1BUCAoU2V1cmF0KSIpICsKICB0aGVtZV9jbGFzc2ljKCkKCnFjMyA8LSBwX3B0X2dyYXBoIHwgcF9wdF9zZXVyYXQKcWMzCnNhdmVfZmlnKHFjMywgIlFDNV9tb25vY2xlM19wc2V1ZG90aW1lX1VNQVAiLCB3ID0gMTgsIGggPSA4KQoKIyDilIDilIAgUUM6IFBzZXVkb3RpbWUgZGlzdHJpYnV0aW9uIGJ5IHN0YXRlIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApwdF9tZXRhIDwtIHJlZmVyZW5jZV9pbnRlZ3JhdGVkQG1ldGEuZGF0YSAlPiUKICBmaWx0ZXIoaXMuZmluaXRlKG1vbm9jbGUzX3BzZXVkb3RpbWUpKSAlPiUKICBtdXRhdGUocHJlZGljdGVkLmNlbGx0eXBlLmwyID0gZmFjdG9yKAogICAgcHJlZGljdGVkLmNlbGx0eXBlLmwyLAogICAgbGV2ZWxzID0gYygiQ0Q0IE5haXZlIiwiQ0Q0IFRDTSIsIlRyZWciLCJDRDQgVEVNIiwiQ0Q0IFRlbXJhL0NUTCIpKSkKCnBfcHRfdmlvbGluIDwtIGdncGxvdChwdF9tZXRhLAogICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBwcmVkaWN0ZWQuY2VsbHR5cGUubDIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IG1vbm9jbGUzX3BzZXVkb3RpbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IHByZWRpY3RlZC5jZWxsdHlwZS5sMikpICsKICBnZW9tX3Zpb2xpbihzY2FsZSA9ICJ3aWR0aCIsIHRyaW0gPSBUUlVFLCBhbHBoYSA9IDAuODUpICsKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjEyLCBmaWxsID0gIndoaXRlIiwgb3V0bGllci5zaXplID0gMC41KSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYXppbXV0aF9sMl9jb2xvcnMpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBjKG5haXZlX21lZCwgdGNtX21lZCwgdHJlZ19tZWQsIHRlbV9tZWQsIHRlbXJhX21lZCksCiAgICAgICAgICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvdXIgPSAiYmxhY2siLCBsaW5ld2lkdGggPSAwLjQsIGFscGhhID0gMC41KSArCiAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMwLCBoanVzdCA9IDEpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJSZWZlcmVuY2UgUHNldWRvdGltZSBieSBTdGF0ZSAoVG9wb2xvZ3kgQ29uZmlybWVkKSIsCiAgICBzdWJ0aXRsZSA9IHNwcmludGYoIk5haXZlPSUuM2YgfCBUQ009JS4zZiB8IFRyZWc9JS4zZiB8IFRFTT0lLjNmIHwgVGVtcmE9JS4zZiIsCiAgICAgICAgICAgICAgICAgICAgICAgbmFpdmVfbWVkLCB0Y21fbWVkLCB0cmVnX21lZCwgdGVtX21lZCwgdGVtcmFfbWVkKSwKICAgIHggPSBOVUxMLCB5ID0gIm1vbm9jbGUzX3BzZXVkb3RpbWUiCiAgKQpwX3B0X3Zpb2xpbgpzYXZlX2ZpZyhwX3B0X3Zpb2xpbiwgIlFDNl9wc2V1ZG90aW1lX2J5X3N0YXRlX3Zpb2xpbiIsIHcgPSAxMCwgaCA9IDcpCmBgYAoKLS0tCgojIDUuIFPDqXphcnkgQ2VsbHM6IFBlci1MaW5lIFNDVHJhbnNmb3JtIHsjc2V6YXJ5LXNjdH0KCmBgYHtyIGxvYWQtbWFsaWduYW50LCBmaWcud2lkdGg9MTQsIGZpZy5oZWlnaHQ9Nn0KQWxsX3NhbXBsZXNfTWVyZ2VkIDwtIHJlYWRSRFMoCiAgIi4uLy4uLy4uLy4uLy4uLzEtU2V1cmF0X1JEU19PQkpFQ1RfRklOQUwvQWxsX3NhbXBsZXNfTWVyZ2VkX3dpdGhfUmVuYW1lZF9DbHVzdGVyc19DZWxsX3N0YXRlLTAzLTEyLTIwMjUucmRzLnJkcyIKKQoKQWxsX3NhbXBsZXNfTWVyZ2VkJEdyb3VwIDwtIGlmZWxzZSgKICBBbGxfc2FtcGxlc19NZXJnZWQkY2VsbF9saW5lICVpbiUgcGFzdGUwKCJMIiwgMTo3KSwKICAiTWFsaWduYW50Q0Q0VCIsICJPdGhlciIKKQoKTWFsaWduYW50Q0Q0VF9yYXcgPC0gc3Vic2V0KEFsbF9zYW1wbGVzX01lcmdlZCwgc3Vic2V0ID0gR3JvdXAgPT0gIk1hbGlnbmFudENENFQiKQpjYXQoIlPDqXphcnkgY2VsbHMgbG9hZGVkOiIsIG5jb2woTWFsaWduYW50Q0Q0VF9yYXcpLCAiXG4iKQpwcmludCh0YWJsZShNYWxpZ25hbnRDRDRUX3JhdyRjZWxsX2xpbmUpKQpybShBbGxfc2FtcGxlc19NZXJnZWQpOyBnYygpCgojIOKUgOKUgCBRQyBGaWd1cmU6IENlbGwgY291bnQgcGVyIGxpbmUg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACmxpbmVfZGYgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShNYWxpZ25hbnRDRDRUX3JhdyRjZWxsX2xpbmUpKQpjb2xuYW1lcyhsaW5lX2RmKSA8LSBjKCJMaW5lIiwgIkNlbGxzIikKCnBfY2VsbF9jb3VudCA8LSBnZ3Bsb3QobGluZV9kZiwgYWVzKHggPSBMaW5lLCB5ID0gQ2VsbHMsIGZpbGwgPSBMaW5lKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDAuNykgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBjb21tYShDZWxscykpLCB2anVzdCA9IC0wLjQsIHNpemUgPSAzLjUsIGZvbnRmYWNlID0gImJvbGQiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gbGluZV9jb2xvcnMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEsIGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLCAwLjE1KSkpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExKSkgKwogIGxhYnModGl0bGUgPSAiU8OpemFyeSBDZWxsIExpbmVzIOKAlCBDZWxsIENvdW50cyIsCiAgICAgICB4ID0gIkNlbGwgTGluZSIsIHkgPSAiTnVtYmVyIG9mIENlbGxzIikKCnBfY2VsbF9jb3VudAoKc2F2ZV9maWcocF9jZWxsX2NvdW50LCAiUUM4X3NlemFyeV9jZWxsX2NvdW50cyIsIHcgPSA5LCBoID0gNikKYGBgCgpgYGB7ciBwZXItbGluZS1zY3QsIGZpZy53aWR0aD0xNCwgZmlnLmhlaWdodD02fQpjZWxsX2xpbmVfbGlzdCAgPC0gU3BsaXRPYmplY3QoTWFsaWduYW50Q0Q0VF9yYXcsIHNwbGl0LmJ5ID0gImNlbGxfbGluZSIpCmNlbGxfbGluZV9uYW1lcyA8LSBuYW1lcyhjZWxsX2xpbmVfbGlzdCkKY2F0KCJQcm9jZXNzaW5nIiwgbGVuZ3RoKGNlbGxfbGluZV9uYW1lcyksICJjZWxsIGxpbmVzIHdpdGggU0NUcmFuc2Zvcm0uLi5cbiIpCgpjZWxsX2xpbmVfbGlzdCA8LSBsYXBwbHkoY2VsbF9saW5lX25hbWVzLCBmdW5jdGlvbihsbikgewogIG9iaiA8LSBjZWxsX2xpbmVfbGlzdFtbbG5dXQogIGNhdChsbiwgInwgY2VsbHM6IiwgbmNvbChvYmopKQoKICBpZiAoISJwZXJjZW50Lm10IiAlaW4lIGNvbG5hbWVzKG9iakBtZXRhLmRhdGEpKQogICAgb2JqW1sicGVyY2VudC5tdCJdXSA8LSBQZXJjZW50YWdlRmVhdHVyZVNldChvYmosIHBhdHRlcm4gPSAiXk1ULSIpCgogIG9iaiA8LSB0cnlDYXRjaCh7CiAgICBvYmogPC0gQ2VsbEN5Y2xlU2NvcmluZyhvYmosIHMuZmVhdHVyZXMgPSBjYy5nZW5lcyRzLmdlbmVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZzJtLmZlYXR1cmVzID0gY2MuZ2VuZXMkZzJtLmdlbmVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2V0LmlkZW50ID0gRkFMU0UpCiAgICBTQ1RyYW5zZm9ybShvYmosIHZhcnMudG8ucmVncmVzcyA9IGMoInBlcmNlbnQubXQiLCJTLlNjb3JlIiwiRzJNLlNjb3JlIiksCiAgICAgICAgICAgICAgICB2YXJpYWJsZS5mZWF0dXJlcy5uID0gMzAwMCwgdnN0LmZsYXZvciA9ICJ2MiIsIHZlcmJvc2UgPSBGQUxTRSkKICB9LCBlcnJvciA9IGZ1bmN0aW9uKGUpIHsKICAgIGNhdCgiIFtjZWxsIGN5Y2xlIGZhaWxlZCDigJQgcGVyY2VudC5tdCBvbmx5XSIpCiAgICBTQ1RyYW5zZm9ybShvYmosIHZhcnMudG8ucmVncmVzcyA9ICJwZXJjZW50Lm10IiwKICAgICAgICAgICAgICAgIHZhcmlhYmxlLmZlYXR1cmVzLm4gPSAzMDAwLCB2c3QuZmxhdm9yID0gInYyIiwgdmVyYm9zZSA9IEZBTFNFKQogIH0pCiAgY2F0KCIg4pyFXG4iKQogIG9iagp9KQpuYW1lcyhjZWxsX2xpbmVfbGlzdCkgPC0gY2VsbF9saW5lX25hbWVzCgojIOKUgOKUgCBTaGFyZWQgSFZHcyBieSBjcm9zcy1saW5lIGZyZXF1ZW5jeSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKYWxsX2h2Z19saXN0cyA8LSBsYXBwbHkoY2VsbF9saW5lX2xpc3QsIFZhcmlhYmxlRmVhdHVyZXMpCmh2Z19mcmVxICAgICAgPC0gc29ydCh0YWJsZSh1bmxpc3QoYWxsX2h2Z19saXN0cykpLCBkZWNyZWFzaW5nID0gVFJVRSkKc2hhcmVkX2h2Z3MgICA8LSBuYW1lcyhodmdfZnJlcSlbc2VxX2xlbihtaW4oMzAwMCwgbGVuZ3RoKGh2Z19mcmVxKSkpXQpzaGFyZWRfaHZnc19jbGVhbiA8LSBzaGFyZWRfaHZnc1shZ3JlcGwoanVua19wYXR0ZXJuLCBzaGFyZWRfaHZncyldCgojIE11c3Qgc3BlY2lmeSBhc3NheT0iU0NUIiDigJQgRGVmYXVsdEFzc2F5IGlzICJpbnRlZ3JhdGVkIiBhdCB0aGlzIHBvaW50CnJlZl9odmdzICAgICAgIDwtIFZhcmlhYmxlRmVhdHVyZXMocmVmZXJlbmNlX2ludGVncmF0ZWQsIGFzc2F5ID0gImludGVncmF0ZWQiKQpmaW5hbF9mZWF0dXJlcyA8LSBpbnRlcnNlY3QocmVmX2h2Z3MsIHNoYXJlZF9odmdzX2NsZWFuKQoKY2F0KHNwcmludGYoIlxuU2hhcmVkIEhWR3MgIDogJWRcbiIsIGxlbmd0aChzaGFyZWRfaHZncykpKQpjYXQoc3ByaW50ZigiQWZ0ZXIganVuayAgIDogJWRcbiIsIGxlbmd0aChzaGFyZWRfaHZnc19jbGVhbikpKQpjYXQoc3ByaW50ZigiUmVmIEhWR3MgICAgIDogJWRcbiIsIGxlbmd0aChyZWZfaHZncykpKQpjYXQoc3ByaW50ZigiRmluYWwgKHJlZiDiiKkgcXVlcnkpOiAlZCBnZW5lc1xuIiwgbGVuZ3RoKGZpbmFsX2ZlYXR1cmVzKSkpCgppZiAobGVuZ3RoKGZpbmFsX2ZlYXR1cmVzKSA8IDE1MDApCiAgd2FybmluZygiRmV3ZXIgdGhhbiAxNTAwIHNoYXJlZCBmZWF0dXJlcyDigJQgY29uc2lkZXIgbmZlYXR1cmVzID0gNDAwMCIpCgojIOKUgOKUgCBNZXJnZSwgc2NhbGUsIFBDQSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKTWFsaWduYW50Q0Q0VCA8LSBtZXJnZShjZWxsX2xpbmVfbGlzdFtbMV1dLCB5ID0gY2VsbF9saW5lX2xpc3RbLTFdLAogICAgICAgICAgICAgICAgICAgICAgIG1lcmdlLmRhdGEgPSBUUlVFKQpWYXJpYWJsZUZlYXR1cmVzKE1hbGlnbmFudENENFQpIDwtIGZpbmFsX2ZlYXR1cmVzCgpNYWxpZ25hbnRDRDRUIDwtIFNjYWxlRGF0YShNYWxpZ25hbnRDRDRULCBmZWF0dXJlcyA9IGZpbmFsX2ZlYXR1cmVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzYXkgPSAiU0NUIiwgdmVyYm9zZSA9IEZBTFNFKQojIG5wY3MgPSA1MCBtYXRjaGVzIHRoZSByZWZlcmVuY2UgaW50ZWdyYXRlZCBQQ0EgKDUwIGRpbXMpCiMgRmluZFRyYW5zZmVyQW5jaG9ycyB0YWtlcyBtaW4ocmVmX2RpbXMsIHF1ZXJ5X2RpbXMpIGF1dG9tYXRpY2FsbHkKTWFsaWduYW50Q0Q0VCA8LSBSdW5QQ0EoTWFsaWduYW50Q0Q0VCwgZmVhdHVyZXMgPSBmaW5hbF9mZWF0dXJlcywKICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2F5ID0gIlNDVCIsIG5wY3MgPSA1MCwgdmVyYm9zZSA9IEZBTFNFKQoKY2F0KCJcbuKchSBRdWVyeSByZWFkeVxuIikKY2F0KCJDZWxscyAgIDoiLCBuY29sKE1hbGlnbmFudENENFQpLCAiXG4iKQpjYXQoIkZlYXR1cmVzOiIsIGxlbmd0aChmaW5hbF9mZWF0dXJlcyksICJcbiIpCmNhdCgiUENBIGRpbXM6IiwgbmNvbChFbWJlZGRpbmdzKE1hbGlnbmFudENENFQsICJwY2EiKSksICJcbiIpCgojIOKUgOKUgCBRQyBGaWd1cmU6IEhWRyBvdmVybGFwIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApodmdfb3ZlcmxhcF9kZiA8LSBkYXRhLmZyYW1lKAogIFNldCAgICA9IGMoIlJlZmVyZW5jZSBIVkdzIiwgIlF1ZXJ5IHNoYXJlZCBIVkdzIChjbGVhbikiLCAiRmluYWwgaW50ZXJzZWN0aW9uIiksCiAgR2VuZXMgID0gYyhsZW5ndGgocmVmX2h2Z3MpLCBsZW5ndGgoc2hhcmVkX2h2Z3NfY2xlYW4pLCBsZW5ndGgoZmluYWxfZmVhdHVyZXMpKQopCnBfaHZnIDwtIGdncGxvdChodmdfb3ZlcmxhcF9kZiwgYWVzKHggPSBTZXQsIHkgPSBHZW5lcywgZmlsbCA9IFNldCkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAwLjYpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gR2VuZXMpLCB2anVzdCA9IC0wLjQsIHNpemUgPSA0LCBmb250ZmFjZSA9ICJib2xkIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiMyMTY2QUMiLCIjNzRBREQxIiwiI0Q3MzAyNyIpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLCAwLjE1KSkpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDIwLCBoanVzdCA9IDEpKSArCiAgbGFicyh0aXRsZSA9ICJIVkcgT3ZlcmxhcDogUmVmZXJlbmNlIHZzIFF1ZXJ5IiwgeCA9IE5VTEwsIHkgPSAiR2VuZSBDb3VudCIpCnBfaHZnCnNhdmVfZmlnKHBfaHZnLCAiUUM5X0hWR19vdmVybGFwIiwgdyA9IDgsIGggPSA2KQoKcm0oTWFsaWduYW50Q0Q0VF9yYXcsIGNlbGxfbGluZV9saXN0KTsgZ2MoKQpgYGAKCgoKCiMjIHZhcmlhYmxlIGdlbmVzIGFsbCA3IGNlbGwgbGluZSBjaGVjawoKYGBge3J9CiMgR2VuZXMgdmFyaWFibGUgaW4gQUxMIDcgbGluZXMKaHZnX2FsbDcgPC0gbmFtZXMoaHZnX2ZyZXFbaHZnX2ZyZXEgPT0gN10pCmNhdCgiR2VuZXMgdmFyaWFibGUgaW4gYWxsIDcgbGluZXM6IiwgbGVuZ3RoKGh2Z19hbGw3KSwgIlxuIikKcHJpbnQoaHZnX2FsbDcpCgoKCiMgQ2hlY2sgd2hpY2ggY2Fub25pY2FsIFQgY2VsbCBtYXJrZXJzIGFyZSBpbiB0aGUgYWxsLTcgc2V0CnRfY2VsbF9tYXJrZXJzIDwtIGMoCiAgIyBOYWl2ZS9tZW1vcnkKICAiQ0NSNyIsICJTRUxMIiwgIlRDRjciLCAiSUw3UiIsICJMRUYxIiwgIktMRjIiLAogICMgQWN0aXZhdGlvbi9leGhhdXN0aW9uICAKICAiVE9YIiwgIlBEQ0QxIiwgIkxBRzMiLCAiVElHSVQiLCAiQ1RMQTQiLCAiSEFWQ1IyIiwKICAjIEVmZmVjdG9yCiAgIkdaTUIiLCAiR1pNSyIsICJHWk1BIiwgIlBSRjEiLCAiSUZORyIsICJUTkYiLAogICMgVHJlZwogICJGT1hQMyIsICJJTDJSQSIsICJJS1pGMiIsICJDVExBNCIsCiAgIyBTw6l6YXJ5IHNwZWNpZmljCiAgIktJUjNETDIiLCAiUExTMyIsICJUV0lTVDEiLCAiRVBIQTQiLCAiQ0QxNjQiLAogICMgUHJvbGlmZXJhdGlvbgogICJNS0k2NyIsICJUT1AyQSIsICJDREsxIgopCgpmb3VuZF9pbl9hbGw3IDwtIGludGVyc2VjdCh0X2NlbGxfbWFya2VycywgaHZnX2FsbDcpCmNhdCgiXG5DYW5vbmljYWwgbWFya2VycyBpbiBhbGwtNyBIVkcgc2V0OlxuIikKcHJpbnQoZm91bmRfaW5fYWxsNykKCm5vdF9mb3VuZCA8LSBzZXRkaWZmKHRfY2VsbF9tYXJrZXJzLCBodmdfYWxsNykKY2F0KCJcbk1hcmtlcnMgTk9UIGluIGFsbC03IHNldDpcbiIpCnByaW50KG5vdF9mb3VuZCkKCgoKYGBgCgojIyB2YXJpYWJsZSBnZW5lcyBhbGwgNyBjZWxsIGxpbmUgY2hlY2sKYGBge3J9CiMgQ2hlY2sgd2hhdCBqdW5rIGdlbmVzIGFyZSBpbiB5b3VyIGN1cnJlbnQgSFZHIHNldAojIGJlZm9yZSBmaW5kLWFuY2hvcnMgcnVucwoKY2F0KCI9PT0gSnVuayBnZW5lIGNoZWNrIG9uIHNoYXJlZF9odmdzID09PVxuIikKCm10X2luX2h2Z3MgPC0gc2hhcmVkX2h2Z3NbZ3JlcGwoIl5NVC0iLCBzaGFyZWRfaHZncyldCmNhdCgiTVQgZ2VuZXMgaW4gc2hhcmVkX2h2Z3M6IiwgbGVuZ3RoKG10X2luX2h2Z3MpLCAiXG4iKQpwcmludChtdF9pbl9odmdzKQoKcmlib19pbl9odmdzIDwtIHNoYXJlZF9odmdzW2dyZXBsKCJeUlBMfF5SUFMiLCBzaGFyZWRfaHZncyldCmNhdCgiXG5SaWJvc29tYWwgZ2VuZXMgaW4gc2hhcmVkX2h2Z3M6IiwgbGVuZ3RoKHJpYm9faW5faHZncyksICJcbiIpCnByaW50KHJpYm9faW5faHZncykKCmhzcF9pbl9odmdzIDwtIHNoYXJlZF9odmdzW2dyZXBsKCJeSFNQfF5IU1BBfF5IU1BCIiwgc2hhcmVkX2h2Z3MpXQpjYXQoIlxuSGVhdCBzaG9jayBnZW5lcyBpbiBzaGFyZWRfaHZnczoiLCBsZW5ndGgoaHNwX2luX2h2Z3MpLCAiXG4iKQpwcmludChoc3BfaW5faHZncykKCnNuaGdfaW5faHZncyA8LSBzaGFyZWRfaHZnc1tncmVwbCgiXlNOSEd8TUFMQVQxfE5FQVQxIiwgc2hhcmVkX2h2Z3MpXQpjYXQoIlxubG5jUk5BIGdlbmVzIGluIHNoYXJlZF9odmdzOiIsIGxlbmd0aChzbmhnX2luX2h2Z3MpLCAiXG4iKQpwcmludChzbmhnX2luX2h2Z3MpCgpjYXQoIlxuVG90YWwganVuayBnZW5lcyB0byBiZSBmaWx0ZXJlZDoiLCAKICAgIGxlbmd0aChtdF9pbl9odmdzKSArIGxlbmd0aChyaWJvX2luX2h2Z3MpICsgCiAgICBsZW5ndGgoaHNwX2luX2h2Z3MpICsgbGVuZ3RoKHNuaGdfaW5faHZncyksICJcbiIpCmBgYAoKLS0tCgojIDYuIEZpbmRUcmFuc2ZlckFuY2hvcnMgeyNmaW5kLWFuY2hvcnN9CgpgYGB7ciBmaW5kLWFuY2hvcnMsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD01fQpEZWZhdWx0QXNzYXkocmVmZXJlbmNlX2ludGVncmF0ZWQpIDwtICJTQ1QiCkRlZmF1bHRBc3NheShNYWxpZ25hbnRDRDRUKSAgICAgICAgPC0gIlNDVCIKCmRpbXNfdG9fdXNlIDwtIG1pbig1MCwKICAgICAgICAgICAgICAgICAgIG5jb2woRW1iZWRkaW5ncyhyZWZlcmVuY2VfaW50ZWdyYXRlZCwgInBjYSIpKSwKICAgICAgICAgICAgICAgICAgIG5jb2woRW1iZWRkaW5ncyhNYWxpZ25hbnRDRDRULCAicGNhIikpKQpjYXQoIkZpbmRpbmcgYW5jaG9yczogZGltcyAxOiIsIGRpbXNfdG9fdXNlLCAifCBmZWF0dXJlczoiLCBsZW5ndGgoZmluYWxfZmVhdHVyZXMpLCAiXG5cbiIpCgojIOKUgOKUgCBIQVJEIFNUT1A6IHZlcmlmeSBQQ0Egcm90YXRpb24gZmVhdHVyZXMgb3ZlcmxhcCB3aXRoIGZpbmFsX2ZlYXR1cmVzIOKUgOKUgOKUgOKUgOKUgOKUgAojIHJlZmVyZW5jZS5yZWR1Y3Rpb249InBjYSIgcHJvamVjdHMgdGhlIHF1ZXJ5IGludG8gdGhlIHJlZmVyZW5jZSBQQ0Egc3BhY2UuCiMgVGhlIFBDQSByb3RhdGlvbiBtYXRyaXggd2FzIGJ1aWx0IG9uICJpbnRlZ3JhdGVkIiBhc3NheSBDQ0EgZmVhdHVyZXMuCiMgZmluYWxfZmVhdHVyZXMgYXJlIFNDVCBIVkdzLiBTZXVyYXQgdXNlcyBvbmx5IHRoZSBpbnRlcnNlY3Rpb24uCiMgSWYgb3ZlcmxhcCBpcyBzbWFsbCwgdGhlIHByb2plY3Rpb24gaXMgbWVhbmluZ2xlc3MuCnBjYV9mZWF0dXJlcyA8LSByb3duYW1lcyhyZWZlcmVuY2VfaW50ZWdyYXRlZFtbInBjYSJdXUBmZWF0dXJlLmxvYWRpbmdzKQpwY2Ffb3ZlcmxhcCAgPC0gaW50ZXJzZWN0KHBjYV9mZWF0dXJlcywgZmluYWxfZmVhdHVyZXMpCmNhdChzcHJpbnRmKCJSZWZlcmVuY2UgUENBIHJvdGF0aW9uIGZlYXR1cmVzIDogJWRcbiIsIGxlbmd0aChwY2FfZmVhdHVyZXMpKSkKY2F0KHNwcmludGYoImZpbmFsX2ZlYXR1cmVzIChTQ1QgSFZHcykgICAgICAgIDogJWRcbiIsIGxlbmd0aChmaW5hbF9mZWF0dXJlcykpKQpjYXQoc3ByaW50ZigiT3ZlcmxhcCAodXNlZCBmb3IgcHJvamVjdGlvbikgICAgOiAlZFxuIiwgbGVuZ3RoKHBjYV9vdmVybGFwKSkpCmlmIChsZW5ndGgocGNhX292ZXJsYXApIDwgMjAwKQogIHN0b3Aoc3ByaW50ZigKICAgICJDUklUSUNBTDogUENB4oCTU0NUIGZlYXR1cmUgb3ZlcmxhcCBpcyBvbmx5ICVkIGdlbmVzLlxuIiwKICAgIGxlbmd0aChwY2Ffb3ZlcmxhcCksCiAgICAiUXVlcnkgcHJvamVjdGlvbiBvbnRvIHJlZmVyZW5jZSBQQ0Egd2lsbCBiZSB1bnJlbGlhYmxlLlxuIiwKICAgICJDaGVjayB0aGF0IHRoZSByZWZlcmVuY2Ugb2JqZWN0IGhhcyBTQ1QgSFZHcyBpbiBpdHMgaW50ZWdyYXRlZCBQQ0EuIgogICkpCmlmIChsZW5ndGgocGNhX292ZXJsYXApIDwgNTAwKQogIHdhcm5pbmcoc3ByaW50ZigiTG93IFBDQeKAk1NDVCBmZWF0dXJlIG92ZXJsYXA6ICVkIGdlbmVzLiBQcm9qZWN0aW9uIHF1YWxpdHkgbWF5IGJlIHJlZHVjZWQuIiwgbGVuZ3RoKHBjYV9vdmVybGFwKSkpCgphbmNob3JzIDwtIEZpbmRUcmFuc2ZlckFuY2hvcnMoCiAgcmVmZXJlbmNlICAgICAgICAgICAgPSByZWZlcmVuY2VfaW50ZWdyYXRlZCwKICBxdWVyeSAgICAgICAgICAgICAgICA9IE1hbGlnbmFudENENFQsCiAgZmVhdHVyZXMgICAgICAgICAgICAgPSBmaW5hbF9mZWF0dXJlcywKICBub3JtYWxpemF0aW9uLm1ldGhvZCA9ICJTQ1QiLAogIHJlZmVyZW5jZS5hc3NheSAgICAgID0gIlNDVCIsICAgICMgdXNlIFNDVCBleHByZXNzaW9uIGZvciBmZWF0dXJlIG1hdGNoaW5nCiAgcXVlcnkuYXNzYXkgICAgICAgICAgPSAiU0NUIiwgICAgIyB1c2UgU0NUIGV4cHJlc3Npb24gZm9yIGZlYXR1cmUgbWF0Y2hpbmcKICByZWZlcmVuY2UucmVkdWN0aW9uICA9ICJwY2EiLCAgICAjIGludGVncmF0ZWQgUENBICg1MCBkaW1zKSDigJQgYmlvbG9neSBpbnRhY3QKICBkaW1zICAgICAgICAgICAgICAgICA9IDE6ZGltc190b191c2UsCiAgay5hbmNob3IgICAgICAgICAgICAgPSAxMCwKICBrLmZpbHRlciAgICAgICAgICAgICA9IDUwMCwKICBrLnNjb3JlICAgICAgICAgICAgICA9IDMwLAogIHZlcmJvc2UgICAgICAgICAgICAgID0gVFJVRQopCgojIOKUgOKUgCBBbmNob3IgUUMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACmFuY2hvcl9kZiAgICA8LSBhcy5kYXRhLmZyYW1lKHNsb3QoYW5jaG9ycywgImFuY2hvcnMiKSkKbl9hbmNob3JzICAgIDwtIG5yb3coYW5jaG9yX2RmKQphbmNob3JfcmF0aW8gPC0gbmNvbChNYWxpZ25hbnRDRDRUKSAvIG5fYW5jaG9ycwptZWFuX3Njb3JlICAgPC0gbWVhbihhbmNob3JfZGYkc2NvcmUpCm1lZF9zY29yZSAgICA8LSBtZWRpYW4oYW5jaG9yX2RmJHNjb3JlKQoKY2F0KHNwcmludGYoIlxuPT09IEFuY2hvciBzdW1tYXJ5ID09PVxuIikpCmNhdChzcHJpbnRmKCJBbmNob3JzICAgICAgICAgICA6ICVkXG4iLCBuX2FuY2hvcnMpKQpjYXQoc3ByaW50ZigiQ2VsbHMgcGVyIGFuY2hvciAgOiAlLjFmOjEgKGlkZWFsIOKJpCA4OjEpXG4iLCBhbmNob3JfcmF0aW8pKQpjYXQoc3ByaW50ZigiU2NvcmU6IG1lYW49JS4zZiB8IG1lZGlhbj0lLjNmXG4iLCBtZWFuX3Njb3JlLCBtZWRfc2NvcmUpKQoKaWYgKGFuY2hvcl9yYXRpbyA+IDgpCiAgd2FybmluZygiTG93IGFuY2hvciBkZW5zaXR5IOKAlCBjaGVjayBqdW5rIGdlbmUgcmVtb3ZhbCBhbmQgay5hbmNob3IgPSAxMCIpCgojIFFDIGZpZ3VyZTogYW5jaG9yIHNjb3JlIGRpc3RyaWJ1dGlvbgpwX2FuY2hvciA8LSBnZ3Bsb3QoYW5jaG9yX2RmLCBhZXMoeCA9IHNjb3JlKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSA1MCwgZmlsbCA9ICIjMjE2NkFDIiwgY29sb3VyID0gIndoaXRlIiwgYWxwaGEgPSAwLjg1KSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbWVhbl9zY29yZSwgIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG91ciA9ICJyZWQiLAogICAgICAgICAgICAgbGluZXdpZHRoID0gMC44KSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbWVkX3Njb3JlLCBsaW5ldHlwZSA9ICJkb3R0ZWQiLCBjb2xvdXIgPSAiZGFya2dyZWVuIiwKICAgICAgICAgICAgIGxpbmV3aWR0aCA9IDAuOCkgKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IG1lYW5fc2NvcmUgKyAwLjAyLCB5ID0gSW5mLCB2anVzdCA9IDEuNSwKICAgICAgICAgICBsYWJlbCA9IHNwcmludGYoIm1lYW49JS4zZiIsIG1lYW5fc2NvcmUpLCBjb2xvdXIgPSAicmVkIiwgc2l6ZSA9IDMuNSkgKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IG1lZF9zY29yZSAtIDAuMDIsIHkgPSBJbmYsIHZqdXN0ID0gMywKICAgICAgICAgICBsYWJlbCA9IHNwcmludGYoIm1lZGlhbj0lLjNmIiwgbWVkX3Njb3JlKSwgY29sb3VyID0gImRhcmtncmVlbiIsCiAgICAgICAgICAgc2l6ZSA9IDMuNSwgaGp1c3QgPSAxKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBsYWJzKAogICAgdGl0bGUgPSBzcHJpbnRmKCJUcmFuc2ZlciBBbmNob3IgU2NvcmUgRGlzdHJpYnV0aW9uIChuPSVkIGFuY2hvcnMpIiwgbl9hbmNob3JzKSwKICAgIHN1YnRpdGxlID0gc3ByaW50ZigiQ2VsbHM6YW5jaG9ycyA9ICUuMWY6MSIsIGFuY2hvcl9yYXRpbyksCiAgICB4ID0gIkFuY2hvciBTY29yZSIsIHkgPSAiQ291bnQiCiAgKQpwX2FuY2hvcgpzYXZlX2ZpZyhwX2FuY2hvciwgIlFDMTBfYW5jaG9yX3Njb3JlX2Rpc3RyaWJ1dGlvbiIsIHcgPSAxMCwgaCA9IDYpCmBgYAoKCiMjIEFuY2hvciBicmVha2Rvd24gYnkgY2VsbCBsaW5lCmBgYHtyIGFuY2hvci1ieS1saW5lLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NX0KIyBhbmNob3JfZGYgaGFzIGNvbHVtbnM6IGNlbGwxIChyZWZlcmVuY2UgaW5kZXgpLCBjZWxsMiAocXVlcnkgaW5kZXgpLCBzY29yZQojIGNlbGwyIGluZGV4ZXMgaW50byB0aGUgUVVFUlkgb2JqZWN0IChNYWxpZ25hbnRDRDRUKSDigJQgbWFwIGJhY2sgdG8gY2VsbF9saW5lCnF1ZXJ5X2NlbGxfbmFtZXMgPC0gY29sbmFtZXMoTWFsaWduYW50Q0Q0VCkKCmFuY2hvcl9saW5lcyA8LSBhbmNob3JfZGYgJT4lCiAgbXV0YXRlKAogICAgcXVlcnlfY2VsbCA9IHF1ZXJ5X2NlbGxfbmFtZXNbY2VsbDJdLAogICAgY2VsbF9saW5lICA9IE1hbGlnbmFudENENFRAbWV0YS5kYXRhW3F1ZXJ5X2NlbGwsICJjZWxsX2xpbmUiXQogICkgJT4lCiAgY291bnQoY2VsbF9saW5lLCBuYW1lID0gIm5fYW5jaG9ycyIpICU+JQogIGFycmFuZ2UoY2VsbF9saW5lKSAlPiUKICBtdXRhdGUoCiAgICBuX2NlbGxzICAgICAgICAgPSBhcy5pbnRlZ2VyKHRhYmxlKE1hbGlnbmFudENENFQkY2VsbF9saW5lKVtjZWxsX2xpbmVdKSwKICAgIGNlbGxzX3Blcl9hbmNob3IgPSByb3VuZChuX2NlbGxzIC8gbl9hbmNob3JzLCAyKSwKICAgIHBjdF9hbmNob3JzICAgICAgPSByb3VuZCgxMDAgKiBuX2FuY2hvcnMgLyBzdW0obl9hbmNob3JzKSwgMSkKICApCgpjYXQoIj09PSBBbmNob3JzIHBlciBjZWxsIGxpbmUgPT09XG4iKQpwcmludChhbmNob3JfbGluZXMpCgpjYXQoc3ByaW50ZigiXG5Ub3RhbCBhbmNob3JzIDogJWRcbiIsIHN1bShhbmNob3JfbGluZXMkbl9hbmNob3JzKSkpCmNhdChzcHJpbnRmKCJPdmVyYWxsIHJhdGlvIDogJS4xZiBjZWxscyBwZXIgYW5jaG9yXG4iLCAKICAgICAgICAgICAgc3VtKGFuY2hvcl9saW5lcyRuX2NlbGxzKSAvIHN1bShhbmNob3JfbGluZXMkbl9hbmNob3JzKSkpCgojIEZsYWcgYW55IGxpbmUgd2l0aCBwb29yIGFuY2hvciBkZW5zaXR5CnBvb3JfbGluZXMgPC0gYW5jaG9yX2xpbmVzICU+JSBmaWx0ZXIoY2VsbHNfcGVyX2FuY2hvciA+IDgpCmlmIChucm93KHBvb3JfbGluZXMpID4gMCkgewogIHdhcm5pbmcoc3ByaW50ZigiUG9vciBhbmNob3IgZGVuc2l0eSAoPjg6MSkgaW46ICVzIiwKICAgICAgICAgICAgICAgICAgcGFzdGUocG9vcl9saW5lcyRjZWxsX2xpbmUsIGNvbGxhcHNlID0gIiwgIikpKQp9CgojIOKUgOKUgCBQbG90OiBhbmNob3JzIGFuZCBjZWxsczphbmNob3IgcmF0aW8gcGVyIGxpbmUg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACnBfYW5jaF9uIDwtIGdncGxvdChhbmNob3JfbGluZXMsIGFlcyh4ID0gY2VsbF9saW5lLCB5ID0gbl9hbmNob3JzLCBmaWxsID0gY2VsbF9saW5lKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDAuNykgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBzcHJpbnRmKCIlZFxuKCUuMWYlJSkiLCBuX2FuY2hvcnMsIHBjdF9hbmNob3JzKSksCiAgICAgICAgICAgIHZqdXN0ID0gLTAuMywgc2l6ZSA9IDMuMiwgZm9udGZhY2UgPSAiYm9sZCIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBsaW5lX2NvbG9ycykgKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwgMC4xOCkpKSArCiAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAxMikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpKSArCiAgbGFicyh0aXRsZSA9ICJBICBBbmNob3JzIHBlciBDZWxsIExpbmUiLAogICAgICAgeCA9ICJDZWxsIExpbmUiLCB5ID0gIk51bWJlciBvZiBBbmNob3JzIikKCnBfYW5jaF9yYXRpbyA8LSBnZ3Bsb3QoYW5jaG9yX2xpbmVzLCBhZXMoeCA9IGNlbGxfbGluZSwgeSA9IGNlbGxzX3Blcl9hbmNob3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBjZWxsX2xpbmUpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMC43KSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHNwcmludGYoIiUuMWY6MSIsIGNlbGxzX3Blcl9hbmNob3IpKSwKICAgICAgICAgICAgdmp1c3QgPSAtMC4zLCBzaXplID0gMy4yLCBmb250ZmFjZSA9ICJib2xkIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDgsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG91ciA9ICJyZWQiLAogICAgICAgICAgICAgbGluZXdpZHRoID0gMC43KSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMC42LCB5ID0gOC40LCBsYWJlbCA9ICI4OjEgdGhyZXNob2xkIiwKICAgICAgICAgICBjb2xvdXIgPSAicmVkIiwgc2l6ZSA9IDMsIGhqdXN0ID0gMCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGxpbmVfY29sb3JzKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLCAwLjE4KSkpICsKICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDEyKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIikpICsKICBsYWJzKHRpdGxlID0gIkIgIENlbGxzIHBlciBBbmNob3IgKGxvd2VyID0gYmV0dGVyIGNvdmVyYWdlKSIsCiAgICAgICB4ID0gIkNlbGwgTGluZSIsIHkgPSAiQ2VsbHMgOiBBbmNob3IgcmF0aW8iKQoKcF9hbmNob3JfbGluZXMgPC0gcF9hbmNoX24gfCBwX2FuY2hfcmF0aW8KcF9hbmNob3JfbGluZXMKc2F2ZV9maWcocF9hbmNob3JfbGluZXMsICJRQzEwYl9hbmNob3JzX2J5X2NlbGxfbGluZSIsIHcgPSAxNCwgaCA9IDYpCmBgYAoKCiMjIEFuY2hvciBicmVha2Rvd24gYnkgQXppbXV0aCBsMiBjZWxsIHR5cGUgKHJlZmVyZW5jZSBzaWRlKQpgYGB7ciBhbmNob3ItYnktcmVmLWNlbGx0eXBlLCBmaWcud2lkdGg9MTQsIGZpZy5oZWlnaHQ9MTB9CiMgYW5jaG9yX2RmIGNvbHVtbnM6CiMgICBjZWxsMSA9IGluZGV4IGludG8gUkVGRVJFTkNFIChyZWZlcmVuY2VfaW50ZWdyYXRlZCkKIyAgIGNlbGwyID0gaW5kZXggaW50byBRVUVSWSAoTWFsaWduYW50Q0Q0VCkKIyAgIHNjb3JlID0gYW5jaG9yIHNjb3JlCgpyZWZfY2VsbF9uYW1lcyAgPC0gY29sbmFtZXMocmVmZXJlbmNlX2ludGVncmF0ZWQpCnF1ZXJ5X2NlbGxfbmFtZXMgPC0gY29sbmFtZXMoTWFsaWduYW50Q0Q0VCkKCmFuY2hvcl9mdWxsIDwtIGFuY2hvcl9kZiAlPiUKICBtdXRhdGUoCiAgICByZWZfY2VsbCAgICAgID0gcmVmX2NlbGxfbmFtZXNbY2VsbDFdLAogICAgcXVlcnlfY2VsbCAgICA9IHF1ZXJ5X2NlbGxfbmFtZXNbY2VsbDJdLAogICAgcmVmX2NlbGx0eXBlICA9IHJlZmVyZW5jZV9pbnRlZ3JhdGVkQG1ldGEuZGF0YVtyZWZfY2VsbCwgICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiXSwKICAgIHF1ZXJ5X2xpbmUgICAgPSBNYWxpZ25hbnRDRDRUQG1ldGEuZGF0YVtxdWVyeV9jZWxsLCAiY2VsbF9saW5lIl0KICApCgojIOKUgOKUgCBUYWJsZSAxOiBhbmNob3JzIHBlciByZWZlcmVuY2UgY2VsbCB0eXBlIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApieV9yZWZ0eXBlIDwtIGFuY2hvcl9mdWxsICU+JQogIGNvdW50KHJlZl9jZWxsdHlwZSwgbmFtZSA9ICJuX2FuY2hvcnMiKSAlPiUKICBhcnJhbmdlKGRlc2Mobl9hbmNob3JzKSkgJT4lCiAgbXV0YXRlKAogICAgcGN0X2FuY2hvcnMgPSByb3VuZCgxMDAgKiBuX2FuY2hvcnMgLyBzdW0obl9hbmNob3JzKSwgMSksCiAgICAjIGhvdyBtYW55IHJlZmVyZW5jZSBjZWxscyBvZiB0aGlzIHR5cGUgZXhpc3Q/CiAgICBuX3JlZl9jZWxscyA9IGFzLmludGVnZXIodGFibGUocmVmZXJlbmNlX2ludGVncmF0ZWQkcHJlZGljdGVkLmNlbGx0eXBlLmwyKVtyZWZfY2VsbHR5cGVdKSwKICAgIGFuY2hvcnNfcGVyX3JlZl9jZWxsID0gcm91bmQobl9hbmNob3JzIC8gbl9yZWZfY2VsbHMsIDIpCiAgKQoKY2F0KCI9PT0gQW5jaG9ycyBieSByZWZlcmVuY2UgQXppbXV0aCBsMiBjZWxsIHR5cGUgPT09XG4iKQpwcmludChieV9yZWZ0eXBlKQoKIyDilIDilIAgVGFibGUgMjogY3Jvc3MtdGFibGUg4oCUIHF1ZXJ5IGxpbmUgw5cgcmVmZXJlbmNlIGNlbGwgdHlwZSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKY3Jvc3NfdGFiIDwtIGFuY2hvcl9mdWxsICU+JQogIGNvdW50KHF1ZXJ5X2xpbmUsIHJlZl9jZWxsdHlwZSkgJT4lCiAgZ3JvdXBfYnkocXVlcnlfbGluZSkgJT4lCiAgbXV0YXRlKHBjdCA9IHJvdW5kKDEwMCAqIG4gLyBzdW0obiksIDEpKSAlPiUKICB1bmdyb3VwKCkKCmNhdCgiXG49PT0gQW5jaG9yIHNvdXJjZSAocmVmIGNlbGwgdHlwZSkgcGVyIHF1ZXJ5IGNlbGwgbGluZSA9PT1cbiIpCmNyb3NzX3dpZGUgPC0gY3Jvc3NfdGFiICU+JQogIGRwbHlyOjpzZWxlY3QocXVlcnlfbGluZSwgcmVmX2NlbGx0eXBlLCBwY3QpICU+JQogIHRpZHlyOjpwaXZvdF93aWRlcihuYW1lc19mcm9tID0gcmVmX2NlbGx0eXBlLCB2YWx1ZXNfZnJvbSA9IHBjdCwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzX2ZpbGwgPSAwKQpwcmludChjcm9zc193aWRlKQoKIyDilIDilIAgUGxvdCBBOiBiYXIgY2hhcnQg4oCUIGFuY2hvcnMgcGVyIHJlZmVyZW5jZSBjZWxsIHR5cGUg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACnBfYnlfdHlwZSA8LSBnZ3Bsb3QoYnlfcmVmdHlwZSwKICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IHJlb3JkZXIocmVmX2NlbGx0eXBlLCBuX2FuY2hvcnMpLAogICAgICAgICAgICAgICAgICAgICAgICB5ID0gbl9hbmNob3JzLAogICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gcmVmX2NlbGx0eXBlKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDAuNykgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBzcHJpbnRmKCIlZCAoJS4xZiUlKSIsIG5fYW5jaG9ycywgcGN0X2FuY2hvcnMpKSwKICAgICAgICAgICAgaGp1c3QgPSAtMC4wOCwgc2l6ZSA9IDMuNSwgZm9udGZhY2UgPSAiYm9sZCIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBhemltdXRoX2wyX2NvbG9ycywgbmEudmFsdWUgPSAiZ3JleTcwIikgKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwgMC4yNSkpKSArCiAgY29vcmRfZmxpcCgpICsKICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDEzKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIikpICsKICBsYWJzKHRpdGxlID0gIkEgIEFuY2hvcnMgcGVyIFJlZmVyZW5jZSBDZWxsIFR5cGUgKEF6aW11dGggbDIpIiwKICAgICAgIHggPSBOVUxMLCB5ID0gIk51bWJlciBvZiBBbmNob3JzIikKCiMg4pSA4pSAIFBsb3QgQjogYW5jaG9ycyBwZXIgcmVmZXJlbmNlIGNlbGwgaW4gdGhhdCB0eXBlIChkZW5zaXR5IG9mIHVzZSkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACnBfZGVuc2l0eSA8LSBnZ3Bsb3QoYnlfcmVmdHlwZSwKICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IHJlb3JkZXIocmVmX2NlbGx0eXBlLCBhbmNob3JzX3Blcl9yZWZfY2VsbCksCiAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBhbmNob3JzX3Blcl9yZWZfY2VsbCwKICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IHJlZl9jZWxsdHlwZSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAwLjcpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gc3ByaW50ZigiJS4yZiIsIGFuY2hvcnNfcGVyX3JlZl9jZWxsKSksCiAgICAgICAgICAgIGhqdXN0ID0gLTAuMSwgc2l6ZSA9IDMuNSwgZm9udGZhY2UgPSAiYm9sZCIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBhemltdXRoX2wyX2NvbG9ycywgbmEudmFsdWUgPSAiZ3JleTcwIikgKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwgMC4yNSkpKSArCiAgY29vcmRfZmxpcCgpICsKICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDEzKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIikpICsKICBsYWJzKHRpdGxlID0gIkIgIEFuY2hvcnMgcGVyIFJlZmVyZW5jZSBDZWxsXG4oaG93IGhlYXZpbHkgZWFjaCBzdGF0ZSBpcyB1c2VkKSIsCiAgICAgICB4ID0gTlVMTCwgeSA9ICJBbmNob3JzIC8gUmVmZXJlbmNlIENlbGwiKQoKIyDilIDilIAgUGxvdCBDOiBzdGFja2VkIGJhciDigJQgd2hpY2ggcmVmIGNlbGwgdHlwZSBhbmNob3JzIGVhY2ggcXVlcnkgbGluZSDilIDilIDilIDilIDilIDilIDilIDilIDilIAKY3Jvc3NfdGFiIDwtIGNyb3NzX3RhYiAlPiUKICBtdXRhdGUocmVmX2NlbGx0eXBlID0gZmFjdG9yKHJlZl9jZWxsdHlwZSwgbGV2ZWxzID0gbmFtZXMoYXppbXV0aF9sMl9jb2xvcnMpKSkgJT4lCiAgYXJyYW5nZShxdWVyeV9saW5lLCByZWZfY2VsbHR5cGUpICU+JQogIGdyb3VwX2J5KHF1ZXJ5X2xpbmUpICU+JQogIG11dGF0ZSgKICAgIGxhYmVsX3kgPSBjdW1zdW0ocGN0KSAtIDAuNSAqIHBjdCwKICAgIGxhYmVsICAgPSBpZmVsc2UocGN0ID49IDMsIHNwcmludGYoIiUuMWYlJSIsIHBjdCksICIiKQogICkgJT4lCiAgdW5ncm91cCgpCgpwX2Nyb3NzIDwtIGdncGxvdChjcm9zc190YWIsCiAgICAgICAgICAgICAgICAgIGFlcyh4ID0gcXVlcnlfbGluZSwgeSA9IHBjdCwgZmlsbCA9IHJlZl9jZWxsdHlwZSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAwLjc4KSArCiAgZ2VvbV90ZXh0KGFlcyh5ID0gbGFiZWxfeSwgbGFiZWwgPSBsYWJlbCksCiAgICAgICAgICAgIHNpemUgPSAzLjAsIGZvbnRmYWNlID0gImJvbGQiLCBjb2xvdXIgPSAid2hpdGUiLCB2anVzdCA9IDAuNSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGF6aW11dGhfbDJfY29sb3JzLCBuYS52YWx1ZSA9ICJncmV5NzAiLAogICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiUmVmZXJlbmNlXG5DZWxsIFR5cGUiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIHBhc3RlMCh4LCAiJSIpLAogICAgICAgICAgICAgICAgICAgICBleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwgMC4wMikpKSArCiAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAxMykgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikgKwogIGxhYnModGl0bGUgPSAiQyAgUmVmZXJlbmNlIENlbGwgVHlwZSBDb21wb3NpdGlvbiBvZiBBbmNob3JzIHBlciBRdWVyeSBMaW5lIiwKICAgICAgIHggPSAiUXVlcnkgQ2VsbCBMaW5lIiwgeSA9ICIlIG9mIEFuY2hvcnMiKQoKIyDilIDilIAgQXNzZW1ibGUg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACnBfYW5jaG9yX3JlZnR5cGUgPC0gKHBfYnlfdHlwZSB8IHBfZGVuc2l0eSkgLyBwX2Nyb3NzICsKICBwbG90X2xheW91dChoZWlnaHRzID0gYygxLCAxLjIpKSArCiAgcGxvdF9hbm5vdGF0aW9uKAogICAgdGl0bGUgICAgPSAiQW5jaG9yIFF1YWxpdHkg4oCUIFJlZmVyZW5jZSBDZWxsIFR5cGUgQnJlYWtkb3duIiwKICAgIHN1YnRpdGxlID0gc3ByaW50ZigiVG90YWwgYW5jaG9yczogJWQgfCBSZWZlcmVuY2UgY2VsbHM6ICVkIHwgUXVlcnkgY2VsbHM6ICVkIiwKICAgICAgICAgICAgICAgICAgICAgICBucm93KGFuY2hvcl9kZiksCiAgICAgICAgICAgICAgICAgICAgICAgbmNvbChyZWZlcmVuY2VfaW50ZWdyYXRlZCksCiAgICAgICAgICAgICAgICAgICAgICAgbmNvbChNYWxpZ25hbnRDRDRUKSksCiAgICB0aGVtZSA9IHRoZW1lKAogICAgICBwbG90LnRpdGxlICAgID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIiksCiAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBjb2xvdXIgPSAiZ3JleTQwIikKICAgICkKICApCgpwX2FuY2hvcl9yZWZ0eXBlCnNhdmVfZmlnKHBfYW5jaG9yX3JlZnR5cGUsICJRQzEwY19hbmNob3JzX2J5X3JlZl9jZWxsdHlwZSIsCiAgICAgICAgIHcgPSAxNiwgaCA9IDE0KQpgYGAKCgoKLS0tCgojIDcuIE1hcFF1ZXJ5IOKAlCBQcm9qZWN0IFPDqXphcnkgQ2VsbHMgeyNtYXAtcXVlcnl9CgpgYGB7ciBtYXAtcXVlcnksIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD01fQptYXBwZWRfTWFsaWduYW50Q0Q0VCA8LSBNYXBRdWVyeSgKICBhbmNob3JzZXQgICAgICAgICAgID0gYW5jaG9ycywKICBxdWVyeSAgICAgICAgICAgICAgID0gTWFsaWduYW50Q0Q0VCwKICByZWZlcmVuY2UgICAgICAgICAgID0gcmVmZXJlbmNlX2ludGVncmF0ZWQsCiAgcmVmZGF0YSAgICAgICAgICAgICA9IGxpc3QoCiAgICBwc2V1ZG90aW1lICAgICAgICAgICAgPSAibW9ub2NsZTNfcHNldWRvdGltZSIsICAgICAgICMgZnJvemVuIHBzZXVkb3RpbWUKICAgIHByZWRpY3RlZC5jZWxsdHlwZS5sMiA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiICAgICAgIyBBemltdXRoIGwyIGxhYmVscwogICksCiAgcmVmZXJlbmNlLnJlZHVjdGlvbiA9ICJwY2EiLCAgICAjIGludGVncmF0ZWQgUENBICg1MCBkaW1zKSDigJQgc2FtZSBhcyBGaW5kVHJhbnNmZXJBbmNob3JzCiAgcmVkdWN0aW9uLm1vZGVsICAgICA9ICJ1bWFwIiAgICAjIGZyb3plbiBVTUFQIG1vZGVsIGZyb20gU2VjdGlvbiAzCikKCiMgQ29lcmNlIHBzZXVkb3RpbWUgdG8gbnVtZXJpYwptYXBwZWRfTWFsaWduYW50Q0Q0VCRwcmVkaWN0ZWQucHNldWRvdGltZSA8LSBhcy5udW1lcmljKAogIG1hcHBlZF9NYWxpZ25hbnRDRDRUJHByZWRpY3RlZC5wc2V1ZG90aW1lCikKCmNhdCgi4pyFIE1hcFF1ZXJ5IGNvbXBsZXRlXG4iKQpjYXQoIk1hcHBlZCBjZWxsczoiLCBuY29sKG1hcHBlZF9NYWxpZ25hbnRDRDRUKSwgIlxuIikKCiMgTGFiZWwgdHJhbnNmZXIgY29uZmlkZW5jZQpzY29yZV9jb2wgPC0gInByZWRpY3RlZC5wcmVkaWN0ZWQuY2VsbHR5cGUubDIuc2NvcmUiCmlmIChzY29yZV9jb2wgJWluJSBjb2xuYW1lcyhtYXBwZWRfTWFsaWduYW50Q0Q0VEBtZXRhLmRhdGEpKSB7CiAgc2NvcmVzIDwtIG1hcHBlZF9NYWxpZ25hbnRDRDRUQG1ldGEuZGF0YVtbc2NvcmVfY29sXV0KICBjYXQoc3ByaW50ZigiTGFiZWwgdHJhbnNmZXIgY29uZmlkZW5jZTogbWVhbj0lLjNmIHwgbWVkaWFuPSUuM2ZcbiIsCiAgICAgICAgICAgICAgbWVhbihzY29yZXMsIG5hLnJtID0gVFJVRSksIG1lZGlhbihzY29yZXMsIG5hLnJtID0gVFJVRSkpKQp9CgpjYXQoIlxuVHJhbnNmZXJyZWQgbGFiZWwgZGlzdHJpYnV0aW9uOlxuIikKcHJpbnQodGFibGUobWFwcGVkX01hbGlnbmFudENENFQkcHJlZGljdGVkLnByZWRpY3RlZC5jZWxsdHlwZS5sMikpCgpjYXQoIlxuVHJhbnNmZXJyZWQgcHNldWRvdGltZSBzdW1tYXJ5OlxuIikKcHJpbnQoc3VtbWFyeShtYXBwZWRfTWFsaWduYW50Q0Q0VCRwcmVkaWN0ZWQucHNldWRvdGltZSkpCgojIOKUgOKUgCBRQyBGaWd1cmU6IFByb2plY3Rpb24gb3ZlcnZpZXcg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACnJlZl9iZyA8LSBkYXRhLmZyYW1lKAogIEVtYmVkZGluZ3MocmVmZXJlbmNlX2ludGVncmF0ZWQsICJ1bWFwIiksCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFCikKY29sbmFtZXMocmVmX2JnKVsxOjJdIDwtIGMoIlVNQVBfMSIsIlVNQVBfMiIpCgpxdWVyeV9jb29yZHMgPC0gZGF0YS5mcmFtZSgKICBFbWJlZGRpbmdzKG1hcHBlZF9NYWxpZ25hbnRDRDRULCAicmVmLnVtYXAiKSwKICBwc2V1ZG90aW1lID0gbWFwcGVkX01hbGlnbmFudENENFQkcHJlZGljdGVkLnBzZXVkb3RpbWUsCiAgY2VsbHR5cGUgICA9IG1hcHBlZF9NYWxpZ25hbnRDRDRUJHByZWRpY3RlZC5wcmVkaWN0ZWQuY2VsbHR5cGUubDIsCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFCikKY29sbmFtZXMocXVlcnlfY29vcmRzKVsxOjJdIDwtIGMoIlVNQVBfMSIsIlVNQVBfMiIpCgpwX3Byb2pfcHQgPC0gZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHJlZl9iZywgYWVzKFVNQVBfMSwgVU1BUF8yKSwKICAgICAgICAgICAgIGNvbG91ciA9ICJncmV5ODciLCBzaXplID0gMC4zLCBhbHBoYSA9IDAuNikgKwogIGdlb21fcG9pbnQoZGF0YSA9IHF1ZXJ5X2Nvb3JkcyAlPiUgZmlsdGVyKGlzLmZpbml0ZShwc2V1ZG90aW1lKSksCiAgICAgICAgICAgICBhZXMoVU1BUF8xLCBVTUFQXzIsIGNvbG91ciA9IHBzZXVkb3RpbWUpLAogICAgICAgICAgICAgc2l6ZSA9IDAuNSwgYWxwaGEgPSAwLjgpICsKICBzY2FsZV9jb2xvdXJfdmlyaWRpc19jKG9wdGlvbiA9ICJwbGFzbWEiLCBuYW1lID0gIlBzZXVkb3RpbWUiKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBnZ3RpdGxlKCJTw6l6YXJ5IGNlbGxzIOKAlCB0cmFuc2ZlcnJlZCBwc2V1ZG90aW1lIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpKQoKcF9wcm9qX2N0IDwtIGdncGxvdCgpICsKICBnZW9tX3BvaW50KGRhdGEgPSByZWZfYmcsIGFlcyhVTUFQXzEsIFVNQVBfMiksCiAgICAgICAgICAgICBjb2xvdXIgPSAiZ3JleTg3Iiwgc2l6ZSA9IDAuMywgYWxwaGEgPSAwLjYpICsKICBnZW9tX3BvaW50KGRhdGEgPSBxdWVyeV9jb29yZHMsCiAgICAgICAgICAgICBhZXMoVU1BUF8xLCBVTUFQXzIsIGNvbG91ciA9IGNlbGx0eXBlKSwKICAgICAgICAgICAgIHNpemUgPSAwLjUsIGFscGhhID0gMC44KSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBhemltdXRoX2wyX2NvbG9ycywgbmEudmFsdWUgPSAiZ3JleTYwIiwKICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiU3RhdGUiKSArCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzLCBhbHBoYSA9IDEpKSkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgZ2d0aXRsZSgiU8OpemFyeSBjZWxscyDigJQgdHJhbnNmZXJyZWQgY2VsbCBzdGF0ZSBsYWJlbHMiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIikpCgpxYzQgPC0gcF9wcm9qX3B0IHwgcF9wcm9qX2N0CnFjNApzYXZlX2ZpZyhxYzQsICJRQzExX3NlemFyeV9wcm9qZWN0aW9uX292ZXJ2aWV3IiwgdyA9IDE4LCBoID0gOCkKCiMgU2NvcmUgZGlzdHJpYnV0aW9uCmlmIChzY29yZV9jb2wgJWluJSBjb2xuYW1lcyhtYXBwZWRfTWFsaWduYW50Q0Q0VEBtZXRhLmRhdGEpKSB7CiAgc2NvcmVfZGYgPC0gZGF0YS5mcmFtZShzY29yZSA9IG1hcHBlZF9NYWxpZ25hbnRDRDRUQG1ldGEuZGF0YVtbc2NvcmVfY29sXV0pCiAgcF9zY29yZSA8LSBnZ3Bsb3Qoc2NvcmVfZGYsIGFlcyh4ID0gc2NvcmUpKSArCiAgICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNjAsIGZpbGwgPSAiIzIxNjZBQyIsIGNvbG91ciA9ICJ3aGl0ZSIsIGFscGhhID0gMC44NSkgKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbWVkaWFuKHNjb3JlX2RmJHNjb3JlLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvdXIgPSAicmVkIiwgbGluZXdpZHRoID0gMC44KSArCiAgICBhbm5vdGF0ZSgidGV4dCIsIHggPSBtZWRpYW4oc2NvcmVfZGYkc2NvcmUsIG5hLnJtID0gVFJVRSkgKyAwLjAxLAogICAgICAgICAgICAgeSA9IEluZiwgdmp1c3QgPSAxLjUsIGhqdXN0ID0gMCwKICAgICAgICAgICAgIGxhYmVsID0gc3ByaW50ZigibWVkaWFuPSUuM2YiLCBtZWRpYW4oc2NvcmVfZGYkc2NvcmUsIG5hLnJtID0gVFJVRSkpLAogICAgICAgICAgICAgY29sb3VyID0gInJlZCIsIHNpemUgPSAzLjUpICsKICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICBsYWJzKHRpdGxlID0gIkxhYmVsIFRyYW5zZmVyIENvbmZpZGVuY2UgU2NvcmUg4oCUIFPDqXphcnkgQ2VsbHMiLAogICAgICAgICB4ID0gIlNjb3JlIiwgeSA9ICJDZWxsIENvdW50IikKIAogICBwX3Njb3JlCiAgCiAgc2F2ZV9maWcocF9zY29yZSwgIlFDMTJfbGFiZWxfdHJhbnNmZXJfY29uZmlkZW5jZSIsIHcgPSAxMCwgaCA9IDYpCn0KCmBgYAoKCmBgYHtyICwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9NH0KICBwX3Njb3JlCiAgCgpgYGAKLS0tCgojIDguIEJpbiBCb3VuZGFyaWVzICYgU3RhdGUgQXNzaWdubWVudCB7I2Jpbi1ib3VuZGFyaWVzfQoKYGBge3IgYmluLWJvdW5kYXJpZXMsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD03fQojIOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkAojIEJpbiBib3VuZGFyaWVzIGFyZSBtaWRwb2ludHMgYmV0d2VlbiBhZGphY2VudCByZWZlcmVuY2Ugc3RhdGUgbWVkaWFucy4KIyBDb21wdXRlZCBmcm9tIHJlZmVyZW5jZV9pbnRlZ3JhdGVkJG1vbm9jbGUzX3BzZXVkb3RpbWUg4oCUIHRoZSBTQU1FIGNvbHVtbgojIHRoYXQgd2FzIHBhc3NlZCB0byBNYXBRdWVyeS4gVGhlIHBzZXVkb3RpbWUgc2NhbGUgb2YgcHJlZGljdGVkLnBzZXVkb3RpbWUKIyBpbiBTw6l6YXJ5IGNlbGxzIGluaGVyaXRzIHRoaXMgc2NhbGUgZGlyZWN0bHkuCiMg4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQCgpuYWl2ZV90Y21fY3V0IDwtIHJvdW5kKChuYWl2ZV9tZWQgKyB0Y21fbWVkKSAgLyAyLCAzKQp0Y21fdGVtX2N1dCAgIDwtIHJvdW5kKCh0Y21fbWVkICAgKyB0ZW1fbWVkKSAgLyAyLCAzKQp0ZW1fdGVtcmFfY3V0IDwtIHJvdW5kKCh0ZW1fbWVkICAgKyB0ZW1yYV9tZWQpIC8gMiwgMykKCmNhdCgiPT09IEJpbiBib3VuZGFyaWVzID09PVxuIikKY2F0KHNwcmludGYoIk5haXZlIHwgVENNICAgPSAoJS4zZiArICUuM2YpIC8gMiA9ICUuM2ZcbiIsCiAgICAgICAgICAgIG5haXZlX21lZCwgdGNtX21lZCwgbmFpdmVfdGNtX2N1dCkpCmNhdChzcHJpbnRmKCJUQ00gICB8IFRFTSAgID0gKCUuM2YgKyAlLjNmKSAvIDIgPSAlLjNmXG4iLAogICAgICAgICAgICB0Y21fbWVkLCB0ZW1fbWVkLCB0Y21fdGVtX2N1dCkpCmNhdChzcHJpbnRmKCJURU0gICB8IFRlbXJhID0gKCUuM2YgKyAlLjNmKSAvIDIgPSAlLjNmXG4iLAogICAgICAgICAgICB0ZW1fbWVkLCB0ZW1yYV9tZWQsIHRlbV90ZW1yYV9jdXQpKQpjYXQoIlRyZWcgID0gbGFiZWwtYmFzZWQgKGJyYW5jaCDigJQgbm90IGxpbmVhciBheGlzKVxuIikKCiMg4pSA4pSAIEFzc2lnbiBiaW5zIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAptYXBwZWRfTWFsaWduYW50Q0Q0VCRzdGF0ZV9hemltdXRoX2wyIDwtCiAgbWFwcGVkX01hbGlnbmFudENENFQkcHJlZGljdGVkLnByZWRpY3RlZC5jZWxsdHlwZS5sMgoKbWFwcGVkX01hbGlnbmFudENENFQkcHNldWRvdGltZV92YWx1ZSA8LQogIGFzLm51bWVyaWMobWFwcGVkX01hbGlnbmFudENENFQkcHJlZGljdGVkLnBzZXVkb3RpbWUpCgptYXBwZWRfTWFsaWduYW50Q0Q0VCRwc2V1ZG90aW1lX2JpbiA8LSBmYWN0b3IoCiAgZHBseXI6OmNhc2Vfd2hlbigKICAgIG1hcHBlZF9NYWxpZ25hbnRDRDRUJHN0YXRlX2F6aW11dGhfbDIgPT0gIlRyZWciICAgICAgICAgICAgICAgICAgICAgICAgfiAiVHJlZy1saWtlIiwKICAgIG1hcHBlZF9NYWxpZ25hbnRDRDRUJHBzZXVkb3RpbWVfdmFsdWUgIDwgbmFpdmVfdGNtX2N1dCAgICAgICAgICAgICAgICAgIH4gIk5haXZlLWxpa2UiLAogICAgbWFwcGVkX01hbGlnbmFudENENFQkcHNldWRvdGltZV92YWx1ZSA+PSBuYWl2ZV90Y21fY3V0ICYKICAgICAgbWFwcGVkX01hbGlnbmFudENENFQkcHNldWRvdGltZV92YWx1ZSA8IHRjbV90ZW1fY3V0ICAgICAgICAgICAgICAgICAgIH4gIlRDTS1saWtlIiwKICAgIG1hcHBlZF9NYWxpZ25hbnRDRDRUJHBzZXVkb3RpbWVfdmFsdWUgPj0gdGNtX3RlbV9jdXQgJgogICAgICBtYXBwZWRfTWFsaWduYW50Q0Q0VCRwc2V1ZG90aW1lX3ZhbHVlIDwgdGVtX3RlbXJhX2N1dCAgICAgICAgICAgICAgICAgfiAiVEVNLWxpa2UiLAogICAgbWFwcGVkX01hbGlnbmFudENENFQkcHNldWRvdGltZV92YWx1ZSA+PSB0ZW1fdGVtcmFfY3V0ICAgICAgICAgICAgICAgICAgfiAiVGVtcmEtbGlrZSIsCiAgICBUUlVFIH4gTkFfY2hhcmFjdGVyXwogICksCiAgbGV2ZWxzID0gYygiTmFpdmUtbGlrZSIsIlRDTS1saWtlIiwiVHJlZy1saWtlIiwiVEVNLWxpa2UiLCJUZW1yYS1saWtlIikKKQoKY2F0KCJcbj09PSBCaW4gZGlzdHJpYnV0aW9uID09PVxuIikKYmluX3RhYiA8LSB0YWJsZShtYXBwZWRfTWFsaWduYW50Q0Q0VCRwc2V1ZG90aW1lX2JpbiwgdXNlTkEgPSAiaWZhbnkiKQpiaW5fcGN0IDwtIHJvdW5kKDEwMCAqIHByb3AudGFibGUoYmluX3RhYiksIDIpCnByaW50KGRhdGEuZnJhbWUobiA9IGFzLmludGVnZXIoYmluX3RhYiksIHBjdCA9IGFzLm51bWVyaWMoYmluX3BjdCksCiAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID0gbmFtZXMoYmluX3RhYikpKQoKY2F0KCJcbj09PSBQZXIgY2VsbCBsaW5lID09PVxuIikKcHJpbnQodGFibGUobWFwcGVkX01hbGlnbmFudENENFQkY2VsbF9saW5lLAogICAgICAgICAgICBtYXBwZWRfTWFsaWduYW50Q0Q0VCRwc2V1ZG90aW1lX2JpbiwgdXNlTkEgPSAiaWZhbnkiKSkKCiMg4pSA4pSAIFFDIEZpZ3VyZTogQmluIGRpc3RyaWJ1dGlvbiDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKYmluX2RmIDwtIG1hcHBlZF9NYWxpZ25hbnRDRDRUQG1ldGEuZGF0YSAlPiUKICBmaWx0ZXIoIWlzLm5hKHBzZXVkb3RpbWVfYmluKSkgJT4lCiAgY291bnQocHNldWRvdGltZV9iaW4pICU+JQogIG11dGF0ZShwY3QgPSByb3VuZCgxMDAgKiBuIC8gc3VtKG4pLCAxKSkKCnBfYmluX2JhciA8LSBnZ3Bsb3QoYmluX2RmLCBhZXMoeCA9IHBzZXVkb3RpbWVfYmluLCB5ID0gbiwgZmlsbCA9IHBzZXVkb3RpbWVfYmluKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDAuNykgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBzcHJpbnRmKCIlc1xuKCUuMWYlJSkiLCBjb21tYShuKSwgcGN0KSksCiAgICAgICAgICAgIHZqdXN0ID0gLTAuMywgc2l6ZSA9IDMuNSwgZm9udGZhY2UgPSAiYm9sZCIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBiaW5fY29sb3JzKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hLCBleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwgMC4xOCkpKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMSkpICsKICBsYWJzKHRpdGxlID0gIlPDqXphcnkgQ2VsbHMg4oCUIFBzZXVkb3RpbWUgQmluIERpc3RyaWJ1dGlvbiIsCiAgICAgICB4ID0gTlVMTCwgeSA9ICJDZWxsIENvdW50IikKcF9iaW5fYmFyCnNhdmVfZmlnKHBfYmluX2JhciwgIlFDMTNfcHNldWRvdGltZV9iaW5fZGlzdHJpYnV0aW9uIiwgdyA9IDksIGggPSA2KQoKIyDilIDilIAgUUMgRmlndXJlOiBCaW5zIG9uIFVNQVAg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACnF1ZXJ5X2JpbnMgPC0gZGF0YS5mcmFtZSgKICBFbWJlZGRpbmdzKG1hcHBlZF9NYWxpZ25hbnRDRDRULCAicmVmLnVtYXAiKSwKICBwc2V1ZG90aW1lX2JpbiA9IG1hcHBlZF9NYWxpZ25hbnRDRDRUJHBzZXVkb3RpbWVfYmluLAogIGNlbGxfbGluZSAgICAgID0gbWFwcGVkX01hbGlnbmFudENENFQkY2VsbF9saW5lCikKY29sbmFtZXMocXVlcnlfYmlucylbMToyXSA8LSBjKCJVTUFQXzEiLCJVTUFQXzIiKQoKcF9iaW5fdW1hcCA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gcmVmX2JnLCBhZXMoVU1BUF8xLCBVTUFQXzIpLAogICAgICAgICAgICAgY29sb3VyID0gImdyZXk2NyIsIHNpemUgPSAwLjMsIGFscGhhID0gMC41KSArCiAgZ2VvbV9wb2ludChkYXRhID0gcXVlcnlfYmlucyAlPiUgZmlsdGVyKCFpcy5uYShwc2V1ZG90aW1lX2JpbikpLAogICAgICAgICAgICAgYWVzKFVNQVBfMSwgVU1BUF8yLCBjb2xvdXIgPSBwc2V1ZG90aW1lX2JpbiksCiAgICAgICAgICAgICBzaXplID0gMC41LCBhbHBoYSA9IDAuOCkgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYmluX2NvbG9ycywgbmFtZSA9ICJCaW4iKSArCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzLCBhbHBoYSA9IDEpKSkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgZ2d0aXRsZSgiU8OpemFyeSBDZWxscyDigJQgUHNldWRvdGltZSBCaW5zIG9uIFJlZmVyZW5jZSBVTUFQIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpKQpwX2Jpbl91bWFwCnNhdmVfZmlnKHBfYmluX3VtYXAsICJRQzE0X2JpbnNfb25fVU1BUCIsIHcgPSAxMCwgaCA9IDgpCmBgYAoKLS0tCgojIDkuIFNhdmUgT2JqZWN0cyB7I3NhdmV9CgpgYGB7ciBzYXZlLW9iamVjdHN9CiMgUmVmZXJlbmNlCnNhdmVSRFMocmVmZXJlbmNlX2ludGVncmF0ZWQsCiAgICAgICAgZmlsZS5wYXRoKG91dF9kaXIsICJyZWZlcmVuY2VfaW50ZWdyYXRlZF9SUENBX21vbm9jbGUzLlJkcyIpKQpjYXQoIuKchSByZWZlcmVuY2VfaW50ZWdyYXRlZCBzYXZlZCAoQ0NSQSBpbnRlZ3JhdGlvbiBpbnRhY3QsIG1vbm9jbGUzIHBzZXVkb3RpbWUgYWRkZWQpXG4iKQoKIyBNYXBwZWQgU8OpemFyeQpzYXZlUkRTKG1hcHBlZF9NYWxpZ25hbnRDRDRULAogICAgICAgIGZpbGUucGF0aChvdXRfZGlyLCAiTWFsaWduYW50Q0Q0VF9tYXBwZWRfcHNldWRvdGltZS5SZHMiKSkKY2F0KCLinIUgbWFwcGVkX01hbGlnbmFudENENFQgc2F2ZWRcbiIpCgojIEJpbiBib3VuZGFyaWVzIOKAlCBzaW5nbGUgc291cmNlIG9mIHRydXRoCmJpbl9ib3VuZGFyaWVzIDwtIGRhdGEuZnJhbWUoCiAgYm91bmRhcnkgICAgICAgPSBjKCJOYWl2ZV9UQ00iLCAiVENNX1RFTSIsICJURU1fVGVtcmEiKSwKICBwc2V1ZG90aW1lX2N1dCA9IGMobmFpdmVfdGNtX2N1dCwgdGNtX3RlbV9jdXQsIHRlbV90ZW1yYV9jdXQpLAogIG5haXZlX21lZCAgICAgID0gbmFpdmVfbWVkLAogIHRjbV9tZWQgICAgICAgID0gdGNtX21lZCwKICB0cmVnX21lZCAgICAgICA9IHRyZWdfbWVkLAogIHRlbV9tZWQgICAgICAgID0gdGVtX21lZCwKICB0ZW1yYV9tZWQgICAgICA9IHRlbXJhX21lZAopCndyaXRlLmNzdihiaW5fYm91bmRhcmllcywKICAgICAgICAgIGZpbGUucGF0aChvdXRfZGlyLCAiYmluX2JvdW5kYXJpZXMuY3N2IiksCiAgICAgICAgICByb3cubmFtZXMgPSBGQUxTRSkKY2F0KCLinIUgYmluX2JvdW5kYXJpZXMuY3N2IHNhdmVkXG4iKQoKIyBGdWxsIG1ldGFkYXRhCndyaXRlLmNzdihtYXBwZWRfTWFsaWduYW50Q0Q0VEBtZXRhLmRhdGEsCiAgICAgICAgICBmaWxlLnBhdGgob3V0X2RpciwgIm1ldGFkYXRhX2Z1bGwuY3N2IiksCiAgICAgICAgICByb3cubmFtZXMgPSBUUlVFKQpjYXQoIuKchSBtZXRhZGF0YV9mdWxsLmNzdiBzYXZlZFxuIikKCmNhdCgiXG5TYXZlZCBmaWxlczpcbiIpCnByaW50KGxpc3QuZmlsZXMob3V0X2RpcikpCmBgYAoKLS0tCgojIDEwLiBNYW51c2NyaXB0IEZpZ3VyZXMgeyNtYW51c2NyaXB0fQoKPiBBbGwgZmlndXJlcyBiZWxvdyBhcmUgc2F2ZWQgYXMgaGlnaC1yZXNvbHV0aW9uIFBORyAoMzAwIGRwaSkgYW5kIFBERi4KCiMjIEZpZ3VyZSAxIOKAlCBSZWZlcmVuY2UgQ0Q0KyBUIENlbGwgQXRsYXMKCmBgYHtyIGZpZzEtcmVmZXJlbmNlLWF0bGFzLCBmaWcud2lkdGg9MTgsIGZpZy5oZWlnaHQ9MTR9CiMgUGFuZWwgQTogVU1BUCBjb2xvdXJlZCBieSBBemltdXRoIGwyCnBfZjFhIDwtIERpbVBsb3QoCiAgcmVmZXJlbmNlX2ludGVncmF0ZWQsCiAgZ3JvdXAuYnkgID0gInByZWRpY3RlZC5jZWxsdHlwZS5sMiIsCiAgcmVkdWN0aW9uID0gInVtYXAiLAogIGxhYmVsICAgICA9IFRSVUUsIHJlcGVsID0gVFJVRSwgbGFiZWwuc2l6ZSA9IDQuNSwgbGFiZWwuYm94ID0gVFJVRQopICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYXppbXV0aF9sMl9jb2xvcnMsIG5hLnZhbHVlID0gImdyZXk3MCIpICsKICBnZ3RpdGxlKCJBICBIZWFsdGh5IENENFx1MjA3YSBUIENlbGwgUmVmZXJlbmNlXG4oQXppbXV0aCBsMiBTdGF0ZXMpIikgKwogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMTMpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgICAgICA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBoanVzdCA9IDApLAogICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICBsZWdlbmQudGV4dCAgICAgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKQogICkgKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQobnJvdyA9IDIsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDQpKSkKCiMgUGFuZWwgQjogUHNldWRvdGltZSBvbiByZWZlcmVuY2UgVU1BUApwX2YxYiA8LSBGZWF0dXJlUGxvdCgKICByZWZlcmVuY2VfaW50ZWdyYXRlZCwKICBmZWF0dXJlcyAgPSAibW9ub2NsZTNfcHNldWRvdGltZSIsCiAgcmVkdWN0aW9uID0gInVtYXAiLAogIG9yZGVyICAgICA9IFRSVUUKKSArCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKG9wdGlvbiA9ICJwbGFzbWEiLCBuYW1lID0gIlBzZXVkb3RpbWUiKSArCiAgZ2d0aXRsZSgiQiAgTW9ub2NsZTMgUHNldWRvdGltZVxuKFJvb3QgPSBDRDQgTmFpdmUpIikgKwogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMTMpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIGhqdXN0ID0gMCkpCgojIFBhbmVsIEM6IFBzZXVkb3RpbWUgdmlvbGluIGJ5IHN0YXRlCnN0YXRlX29yZGVyICA8LSBjKCJDRDQgTmFpdmUiLCJDRDQgVENNIiwiVHJlZyIsIkNENCBURU0iLCJDRDQgVGVtcmEvQ1RMIikKc3RhdGVfbGFiZWxzIDwtIGMoIk5haXZlIiwiVENNIiwiVHJlZyIsIlRFTSIsIlRlbXJhL0NUTCIpCgpwdF9tZXRhMiA8LSByZWZlcmVuY2VfaW50ZWdyYXRlZEBtZXRhLmRhdGEgJT4lCiAgZmlsdGVyKGlzLmZpbml0ZShtb25vY2xlM19wc2V1ZG90aW1lKSwKICAgICAgICAgcHJlZGljdGVkLmNlbGx0eXBlLmwyICVpbiUgc3RhdGVfb3JkZXIpICU+JQogIG11dGF0ZShTdGF0ZSA9IGZhY3RvcihwcmVkaWN0ZWQuY2VsbHR5cGUubDIsCiAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IHN0YXRlX29yZGVyLAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzdGF0ZV9sYWJlbHMpKQoKIyDilIDilIAgRGVmaW5lIGNvbG91ciB2ZWN0b3IgQkVGT1JFIHRoZSBnZ3Bsb3QgY2FsbCDigJQgbmV2ZXIgaW5zaWRlIHRoZSArIGNoYWluIOKUgOKUgOKUgAphemltdXRoXzUgPC0gYXppbXV0aF9sMl9jb2xvcnNbc3RhdGVfb3JkZXJdCm5hbWVzKGF6aW11dGhfNSkgPC0gc3RhdGVfbGFiZWxzCgpwX2YxYyA8LSBnZ3Bsb3QocHRfbWV0YTIsIGFlcyh4ID0gU3RhdGUsIHkgPSBtb25vY2xlM19wc2V1ZG90aW1lLCBmaWxsID0gU3RhdGUpKSArCiAgZ2VvbV92aW9saW4oc2NhbGUgPSAid2lkdGgiLCB0cmltID0gVFJVRSwgYWxwaGEgPSAwLjg1KSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4xMiwgZmlsbCA9ICJ3aGl0ZSIsCiAgICAgICAgICAgICAgIG91dGxpZXIuc2l6ZSA9IDAuNSwgb3V0bGllci5hbHBoYSA9IDAuMykgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGF6aW11dGhfNSkgKwogIGdlb21faGxpbmUoCiAgICB5aW50ZXJjZXB0ID0gYyhuYWl2ZV9tZWQsIHRjbV9tZWQsIHRyZWdfbWVkLCB0ZW1fbWVkLCB0ZW1yYV9tZWQpLAogICAgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3VyID0gImJsYWNrIiwgbGluZXdpZHRoID0gMC40LCBhbHBoYSA9IDAuNQogICkgKwogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMTMpICsKICB0aGVtZSgKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgIGF4aXMudGV4dC54ICAgICA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMwLCBoanVzdCA9IDEpLAogICAgcGxvdC50aXRsZSAgICAgID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIGhqdXN0ID0gMCkKICApICsKICBsYWJzKAogICAgdGl0bGUgICAgPSAiQyAgUHNldWRvdGltZSBieSBUIENlbGwgU3RhdGUiLAogICAgc3VidGl0bGUgPSBzcHJpbnRmKCJOYWl2ZT0lLjJmIHwgVENNPSUuMmYgfCBUcmVnPSUuMmYgfCBURU09JS4yZiB8IFRlbXJhPSUuMmYiLAogICAgICAgICAgICAgICAgICAgICAgIG5haXZlX21lZCwgdGNtX21lZCwgdHJlZ19tZWQsIHRlbV9tZWQsIHRlbXJhX21lZCksCiAgICB4ID0gTlVMTCwgeSA9ICJQc2V1ZG90aW1lIgogICkKCiMg4pSA4pSAIEFzc2VtYmxlIGZpZ3VyZSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKZmlnMSA8LSAocF9mMWEgfCBwX2YxYikgLyBwX2YxYyArCiAgcGxvdF9sYXlvdXQoaGVpZ2h0cyA9IGMoMS4yLCAxKSkgKwogIHBsb3RfYW5ub3RhdGlvbigKICAgIHRpdGxlICAgID0gIkZpZ3VyZSAxIOKAlCBIZWFsdGh5IENENFx1MjA3YSBUIENlbGwgUmVmZXJlbmNlIEF0bGFzIiwKICAgIHN1YnRpdGxlID0gc3ByaW50Zigibj0lZCBjZWxscyB8IE1vbm9jbGUzIHRyYWplY3RvcnkgfCBSb290OiBDRDQgTmFpdmUiLAogICAgICAgICAgICAgICAgICAgICAgIG5jb2wocmVmZXJlbmNlX2ludGVncmF0ZWQpKSwKICAgIHRoZW1lICAgID0gdGhlbWUoCiAgICAgIHBsb3QudGl0bGUgICAgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBmYWNlID0gImJvbGQiKSwKICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEsIGNvbG91ciA9ICJncmV5NDAiKQogICAgKQogICkKCmZpZzEKc2F2ZV9maWcoZmlnMSwgIkZpZ3VyZTFfUmVmZXJlbmNlX0F0bGFzIiwgc3ViZGlyID0gZmlnX2Rpcl9tcywgdyA9IDE4LCBoID0gMTQpCmBgYAoKIyMgRmlndXJlIDIg4oCUIFPDqXphcnkgQ2VsbCBQcm9qZWN0aW9uIG9udG8gUmVmZXJlbmNlCgpgYGB7ciBmaWcyLXByb2plY3Rpb24sIGZpZy53aWR0aD0xOCwgZmlnLmhlaWdodD0xMn0KIyBQYW5lbCBBOiBBbGwgU8OpemFyeSBjZWxscyBvbiByZWZlcmVuY2UgVU1BUCBjb2xvdXJlZCBieSBwc2V1ZG90aW1lCnBfZjJhIDwtIGdncGxvdCgpICsKICBnZW9tX3BvaW50KGRhdGEgPSByZWZfYmcsIGFlcyhVTUFQXzEsIFVNQVBfMiksCiAgICAgICAgICAgICBjb2xvdXIgPSAiZ3JleTY3Iiwgc2l6ZSA9IDAuMywgYWxwaGEgPSAwLjUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBxdWVyeV9jb29yZHMgJT4lIGZpbHRlcihpcy5maW5pdGUocHNldWRvdGltZSkpLAogICAgICAgICAgICAgYWVzKFVNQVBfMSwgVU1BUF8yLCBjb2xvdXIgPSBwc2V1ZG90aW1lKSwKICAgICAgICAgICAgIHNpemUgPSAwLjQsIGFscGhhID0gMC44KSArCiAgc2NhbGVfY29sb3VyX3ZpcmlkaXNfYyhvcHRpb24gPSAicGxhc21hIiwgbmFtZSA9ICJUcmFuc2ZlcnJlZFxuUHNldWRvdGltZSIpICsKICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDEzKSArCiAgZ2d0aXRsZSgiQSAgU8OpemFyeSBDZWxscyBQcm9qZWN0ZWQgb250b1xuSGVhbHRoeSBDRDTigbogVCBDZWxsIFJlZmVyZW5jZSIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIGhqdXN0ID0gMCkpCgojIFBhbmVsIEI6IEJpbnMgb24gVU1BUApwX2YyYiA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gcmVmX2JnLCBhZXMoVU1BUF8xLCBVTUFQXzIpLAogICAgICAgICAgICAgY29sb3VyID0gImdyZXk2NyIsIHNpemUgPSAwLjMsIGFscGhhID0gMC41KSArCiAgZ2VvbV9wb2ludChkYXRhID0gcXVlcnlfYmlucyAlPiUgZmlsdGVyKCFpcy5uYShwc2V1ZG90aW1lX2JpbikpLAogICAgICAgICAgICAgYWVzKFVNQVBfMSwgVU1BUF8yLCBjb2xvdXIgPSBwc2V1ZG90aW1lX2JpbiksCiAgICAgICAgICAgICBzaXplID0gMC40LCBhbHBoYSA9IDAuOCkgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYmluX2NvbG9ycywgbmFtZSA9ICJTdGF0ZSBCaW4iKSArCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzLjUsIGFscGhhID0gMSkpKSArCiAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAxMykgKwogIGdndGl0bGUoIkIgIERpZmZlcmVudGlhdGlvbiBTdGF0ZSBCaW5zXG4oUHNldWRvdGltZS1hbmNob3JlZCkiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBoanVzdCA9IDApKQoKIyBQYW5lbCBDOiBCaW4gJSBzdGFja2VkIGJ5IGxpbmUKbGluZV9iaW5fZGYgPC0gbWFwcGVkX01hbGlnbmFudENENFRAbWV0YS5kYXRhICU+JQogIGZpbHRlcighaXMubmEocHNldWRvdGltZV9iaW4pKSAlPiUKICBjb3VudChjZWxsX2xpbmUsIHBzZXVkb3RpbWVfYmluKSAlPiUKICBncm91cF9ieShjZWxsX2xpbmUpICU+JQogIG11dGF0ZShwY3QgPSAxMDAgKiBuIC8gc3VtKG4pKSAlPiUKICB1bmdyb3VwKCkKCnBfZjJjIDwtIGdncGxvdChsaW5lX2Jpbl9kZiwKICAgICAgICAgICAgICAgIGFlcyh4ID0gY2VsbF9saW5lLCB5ID0gcGN0LCBmaWxsID0gcHNldWRvdGltZV9iaW4pKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMC43OCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGJpbl9jb2xvcnMsIG5hbWUgPSAiU3RhdGUgQmluIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBwYXN0ZTAoeCwgIiUiKSkgKwogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMTMpICsKICB0aGVtZSgKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIGhqdXN0ID0gMCkKICApICsKICBsYWJzKHRpdGxlID0gIkMgIFN0YXRlIEJpbiBDb21wb3NpdGlvbiBwZXIgQ2VsbCBMaW5lIiwKICAgICAgIHggPSAiQ2VsbCBMaW5lIiwgeSA9ICIlIENlbGxzIikKCmZpZzIgPC0gKHBfZjJhIHwgcF9mMmIpIC8gcF9mMmMgKwogIHBsb3RfbGF5b3V0KGhlaWdodHMgPSBjKDEuMywgMSkpICsKICBwbG90X2Fubm90YXRpb24oCiAgICB0aXRsZSAgICA9ICJGaWd1cmUgMiDigJQgU8OpemFyeSBDRDTigbogVCBDZWxsIFByb2plY3Rpb24gYW5kIFN0YXRlIEFzc2lnbm1lbnQiLAogICAgc3VidGl0bGUgPSBzcHJpbnRmKCJuPSVkIGNlbGxzIGFjcm9zcyAlZCBjZWxsIGxpbmVzIiwKICAgICAgICAgICAgICAgICAgICAgICBuY29sKG1hcHBlZF9NYWxpZ25hbnRDRDRUKSwKICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGgodW5pcXVlKG1hcHBlZF9NYWxpZ25hbnRDRDRUJGNlbGxfbGluZSkpKSwKICAgIHRoZW1lICAgID0gdGhlbWUoCiAgICAgIHBsb3QudGl0bGUgICAgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBmYWNlID0gImJvbGQiKSwKICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEsIGNvbG91ciA9ICJncmV5NDAiKQogICAgKQogICkKZmlnMgpzYXZlX2ZpZyhmaWcyLCAiRmlndXJlMl9TZXphcnlfUHJvamVjdGlvbiIsIHN1YmRpciA9IGZpZ19kaXJfbXMsIHcgPSAxOCwgaCA9IDE0KQpgYGAKCgojIyBGaWd1cmUgMl92MiDigJQgU8OpemFyeSBDZWxsIFByb2plY3Rpb24gKHdpdGggY29ycmVjdGx5IHBsYWNlZCAlIGxhYmVscykKYGBge3IgZmlnMi12Mi1wcm9qZWN0aW9uLCBmaWcud2lkdGg9MTgsIGZpZy5oZWlnaHQ9MTJ9CgojIFBhbmVsIEEKcF9mMmEgPC0gZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHJlZl9iZywgYWVzKFVNQVBfMSwgVU1BUF8yKSwKICAgICAgICAgICAgIGNvbG91ciA9ICJncmV5NjciLCBzaXplID0gMC4zLCBhbHBoYSA9IDAuNSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHF1ZXJ5X2Nvb3JkcyAlPiUgZmlsdGVyKGlzLmZpbml0ZShwc2V1ZG90aW1lKSksCiAgICAgICAgICAgICBhZXMoVU1BUF8xLCBVTUFQXzIsIGNvbG91ciA9IHBzZXVkb3RpbWUpLAogICAgICAgICAgICAgc2l6ZSA9IDAuNCwgYWxwaGEgPSAwLjgpICsKICBzY2FsZV9jb2xvdXJfdmlyaWRpc19jKG9wdGlvbiA9ICJwbGFzbWEiLCBuYW1lID0gIlRyYW5zZmVycmVkXG5Qc2V1ZG90aW1lIikgKwogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMTMpICsKICBnZ3RpdGxlKCJBICBTw6l6YXJ5IENlbGxzIFByb2plY3RlZCBvbnRvXG5IZWFsdGh5IENENFx1MjA3YSBUIENlbGwgUmVmZXJlbmNlIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgaGp1c3QgPSAwKSkKCiMgUGFuZWwgQgpwX2YyYiA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gcmVmX2JnLCBhZXMoVU1BUF8xLCBVTUFQXzIpLAogICAgICAgICAgICAgY29sb3VyID0gImdyZXk2NyIsIHNpemUgPSAwLjMsIGFscGhhID0gMC41KSArCiAgZ2VvbV9wb2ludChkYXRhID0gcXVlcnlfYmlucyAlPiUgZmlsdGVyKCFpcy5uYShwc2V1ZG90aW1lX2JpbikpLAogICAgICAgICAgICAgYWVzKFVNQVBfMSwgVU1BUF8yLCBjb2xvdXIgPSBwc2V1ZG90aW1lX2JpbiksCiAgICAgICAgICAgICBzaXplID0gMC40LCBhbHBoYSA9IDAuOCkgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYmluX2NvbG9ycywgbmFtZSA9ICJTdGF0ZSBCaW4iKSArCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzLjUsIGFscGhhID0gMSkpKSArCiAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAxMykgKwogIGdndGl0bGUoIkIgIERpZmZlcmVudGlhdGlvbiBTdGF0ZSBCaW5zXG4oUHNldWRvdGltZS1hbmNob3JlZCkiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBoanVzdCA9IDApKQoKIyBQYW5lbCBDOiBzdGFja2VkIGJhciB3aXRoIGNvcnJlY3RseSBwb3NpdGlvbmVkICUgbGFiZWxzCiMg4pSA4pSAIEtFWSBGSVg6IHNvcnQgd2l0aGluIGVhY2ggbGluZSBieSB0aGUgU0FNRSBmYWN0b3Igb3JkZXIgZ2dwbG90IHVzZXMsCiMgICAgdGhlbiBjdW1zdW0gc28gdGhlIG1pZHBvaW50cyBtYXRjaCB0aGUgYWN0dWFsIHJlbmRlcmVkIHN0YWNrIHBvc2l0aW9uIOKUgOKUgApiaW5fbGV2ZWxfb3JkZXIgPC0gYygiTmFpdmUtbGlrZSIsIlRDTS1saWtlIiwiVHJlZy1saWtlIiwiVEVNLWxpa2UiLCJUZW1yYS1saWtlIikKCmxpbmVfYmluX2RmIDwtIG1hcHBlZF9NYWxpZ25hbnRDRDRUQG1ldGEuZGF0YSAlPiUKICBmaWx0ZXIoIWlzLm5hKHBzZXVkb3RpbWVfYmluKSkgJT4lCiAgY291bnQoY2VsbF9saW5lLCBwc2V1ZG90aW1lX2JpbikgJT4lCiAgZ3JvdXBfYnkoY2VsbF9saW5lKSAlPiUKICBtdXRhdGUocGN0ID0gMTAwICogbiAvIHN1bShuKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZShwc2V1ZG90aW1lX2JpbiA9IGZhY3Rvcihwc2V1ZG90aW1lX2JpbiwgbGV2ZWxzID0gYmluX2xldmVsX29yZGVyKSkgJT4lCiAgIyBzb3J0IHdpdGhpbiBlYWNoIGNlbGxfbGluZSBpbiBSRVZFUlNFIGZhY3RvciBvcmRlciDigJQgZ2dwbG90IHN0YWNrcwogICMgYm90dG9tLXRvLXRvcCBpbiBmYWN0b3Igb3JkZXIsIHNvIGN1bXN1bSBtdXN0IGdvIGJvdHRvbS10by10b3AgdG9vCiAgYXJyYW5nZShjZWxsX2xpbmUsIHBzZXVkb3RpbWVfYmluKSAlPiUKICBncm91cF9ieShjZWxsX2xpbmUpICU+JQogIG11dGF0ZSgKICAgICMgcG9zaXRpb24gPSBtaWRwb2ludCBvZiB0aGlzIHNlZ21lbnQgaW4gdGhlIHN0YWNrZWQgYmFyCiAgICBsYWJlbF95ID0gY3Vtc3VtKHBjdCkgLSAwLjUgKiBwY3QsCiAgICBsYWJlbCAgID0gaWZlbHNlKHBjdCA+PSAzLCBzcHJpbnRmKCIlLjFmJSUiLCBwY3QpLCAiIikKICApICU+JQogIHVuZ3JvdXAoKQoKcF9mMmMgPC0gZ2dwbG90KGxpbmVfYmluX2RmLAogICAgICAgICAgICAgICAgYWVzKHggPSBjZWxsX2xpbmUsIHkgPSBwY3QsIGZpbGwgPSBwc2V1ZG90aW1lX2JpbikpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAwLjc4KSArCiAgZ2VvbV90ZXh0KAogICAgYWVzKHkgPSBsYWJlbF95LCBsYWJlbCA9IGxhYmVsKSwKICAgIHNpemUgICAgID0gMy4yLAogICAgZm9udGZhY2UgPSAiYm9sZCIsCiAgICBjb2xvdXIgICA9ICJ3aGl0ZSIsCiAgICB2anVzdCAgICA9IDAuNQogICkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGJpbl9jb2xvcnMsIG5hbWUgPSAiU3RhdGUgQmluIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBwYXN0ZTAoeCwgIiUiKSwKICAgICAgICAgICAgICAgICAgICAgZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAsIDAuMDIpKSkgKwogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMTMpICsKICB0aGVtZSgKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICBwbG90LnRpdGxlICAgICAgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgaGp1c3QgPSAwKQogICkgKwogIGxhYnModGl0bGUgPSAiQyAgU3RhdGUgQmluIENvbXBvc2l0aW9uIHBlciBDZWxsIExpbmUiLAogICAgICAgeCA9ICJDZWxsIExpbmUiLCB5ID0gIiUgQ2VsbHMiKQoKZmlnMl92MiA8LSAocF9mMmEgfCBwX2YyYikgLyBwX2YyYyArCiAgcGxvdF9sYXlvdXQoaGVpZ2h0cyA9IGMoMS4zLCAxKSkgKwogIHBsb3RfYW5ub3RhdGlvbigKICAgIHRpdGxlICAgID0gIkZpZ3VyZSAyIOKAlCBTw6l6YXJ5IENENFx1MjA3YSBUIENlbGwgUHJvamVjdGlvbiBhbmQgU3RhdGUgQXNzaWdubWVudCIsCiAgICBzdWJ0aXRsZSA9IHNwcmludGYoIm49JWQgY2VsbHMgYWNyb3NzICVkIGNlbGwgbGluZXMiLAogICAgICAgICAgICAgICAgICAgICAgIG5jb2wobWFwcGVkX01hbGlnbmFudENENFQpLAogICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aCh1bmlxdWUobWFwcGVkX01hbGlnbmFudENENFQkY2VsbF9saW5lKSkpLAogICAgdGhlbWUgICAgPSB0aGVtZSgKICAgICAgcGxvdC50aXRsZSAgICA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGZhY2UgPSAiYm9sZCIpLAogICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMSwgY29sb3VyID0gImdyZXk0MCIpCiAgICApCiAgKQoKZmlnMl92MgpzYXZlX2ZpZyhmaWcyX3YyLCAiRmlndXJlMl92Ml9TZXphcnlfUHJvamVjdGlvbl9wY3RfbGFiZWxzIiwKICAgICAgICAgc3ViZGlyID0gZmlnX2Rpcl9tcywgdyA9IDE4LCBoID0gMTQpCmBgYAoKCgojIyBGaWd1cmUgMyDigJQgUHNldWRvdGltZSBEaXN0cmlidXRpb24gJiBTdGF0ZSBDb21wb3NpdGlvbgoKYGBge3IgZmlnMy1wc2V1ZG90aW1lLWRpc3RyaWJ1dGlvbiwgZmlnLndpZHRoPTE4LCBmaWcuaGVpZ2h0PTh9CnB0X3NlemFyeSA8LSBtYXBwZWRfTWFsaWduYW50Q0Q0VEBtZXRhLmRhdGEgJT4lCiAgZmlsdGVyKGlzLmZpbml0ZShwc2V1ZG90aW1lX3ZhbHVlKSwgIWlzLm5hKHBzZXVkb3RpbWVfYmluKSkgJT4lCiAgbXV0YXRlKAogICAgY2VsbF9saW5lID0gZmFjdG9yKGNlbGxfbGluZSwgbGV2ZWxzID0gcGFzdGUwKCJMIiwgMTo3KSksCiAgICBwc2V1ZG90aW1lX2JpbiA9IGZhY3Rvcihwc2V1ZG90aW1lX2JpbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIk5haXZlLWxpa2UiLCJUQ00tbGlrZSIsIlRyZWctbGlrZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJURU0tbGlrZSIsIlRlbXJhLWxpa2UiKSkKICApCgojIFBhbmVsIEE6IFJpZGdlIHBsb3Qgb2YgcHNldWRvdGltZSBwZXIgbGluZQpwX2YzYSA8LSBnZ3Bsb3QocHRfc2V6YXJ5LAogICAgICAgICAgICAgICAgYWVzKHggPSBwc2V1ZG90aW1lX3ZhbHVlLCB5ID0gY2VsbF9saW5lLCBmaWxsID0gY2VsbF9saW5lKSkgKwogIGdlb21fZGVuc2l0eV9yaWRnZXMoc2NhbGUgPSAxLjIsIGFscGhhID0gMC44NSwgY29sb3VyID0gIndoaXRlIiwKICAgICAgICAgICAgICAgICAgICAgIHF1YW50aWxlX2xpbmVzID0gVFJVRSwgcXVhbnRpbGVzID0gMikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMobmFpdmVfdGNtX2N1dCwgdGNtX3RlbV9jdXQsIHRlbV90ZW1yYV9jdXQpLAogICAgICAgICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3VyID0gImJsYWNrIiwgbGluZXdpZHRoID0gMC42LCBhbHBoYSA9IDAuNykgKwogIGFubm90YXRlKCJ0ZXh0IiwKICAgICAgICAgICB4ID0gYyhuYWl2ZV90Y21fY3V0LCB0Y21fdGVtX2N1dCwgdGVtX3RlbXJhX2N1dCksCiAgICAgICAgICAgeSA9IDEuMiwgdmp1c3QgPSAtMC4yLCBoanVzdCA9IC0wLjA1LAogICAgICAgICAgIGxhYmVsID0gYygiTmFpdmV8VENNIiwiVENNfFRFTSIsIlRFTXxUZW1yYSIpLAogICAgICAgICAgIHNpemUgPSAzLCBjb2xvdXIgPSAiYmxhY2siKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gbGluZV9jb2xvcnMpICsKICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDEzKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgaGp1c3QgPSAwKSkgKwogIGxhYnModGl0bGUgPSAiQSAgUHNldWRvdGltZSBEaXN0cmlidXRpb24gcGVyIENlbGwgTGluZSIsCiAgICAgICB4ID0gIlRyYW5zZmVycmVkIFBzZXVkb3RpbWUiLCB5ID0gIkNlbGwgTGluZSIpCgojIFBhbmVsIEI6IEJpbiBwcm9wb3J0aW9ucyDigJQgb3ZlcmFsbCBidWJibGUvYmFyCmJpbl90b3RhbF9kZiA8LSBtYXBwZWRfTWFsaWduYW50Q0Q0VEBtZXRhLmRhdGEgJT4lCiAgZmlsdGVyKCFpcy5uYShwc2V1ZG90aW1lX2JpbikpICU+JQogIGNvdW50KHBzZXVkb3RpbWVfYmluKSAlPiUKICBtdXRhdGUocGN0ID0gcm91bmQoMTAwICogbiAvIHN1bShuKSwgMSksCiAgICAgICAgIHBzZXVkb3RpbWVfYmluID0gZmFjdG9yKHBzZXVkb3RpbWVfYmluLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJOYWl2ZS1saWtlIiwiVENNLWxpa2UiLCJUcmVnLWxpa2UiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJURU0tbGlrZSIsIlRlbXJhLWxpa2UiKSkpCgpwX2YzYiA8LSBnZ3Bsb3QoYmluX3RvdGFsX2RmLCBhZXMoeCA9IHBzZXVkb3RpbWVfYmluLCB5ID0gcGN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBwc2V1ZG90aW1lX2JpbikpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAwLjcpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gc3ByaW50ZigiJS4xZiUlXG4obj0lcykiLCBwY3QsIGNvbW1hKG4pKSksCiAgICAgICAgICAgIHZqdXN0ID0gLTAuMywgc2l6ZSA9IDMuNSwgZm9udGZhY2UgPSAiYm9sZCIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBiaW5fY29sb3JzKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLCAwLjIpKSwKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gZnVuY3Rpb24oeCkgcGFzdGUwKHgsICIlIikpICsKICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDEzKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMjUsIGhqdXN0ID0gMSksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBoanVzdCA9IDApKSArCiAgbGFicyh0aXRsZSA9ICJCICBTdGF0ZSBCaW4gQ29tcG9zaXRpb24g4oCUIEFsbCBTw6l6YXJ5IENlbGxzIiwKICAgICAgIHggPSBOVUxMLCB5ID0gIiUgQ2VsbHMiKQoKIyBQYW5lbCBDOiBIZWF0bWFwIG9mIGJpbiAlIGJ5IGxpbmUKbGluZV9iaW5fd2lkZSA8LSBsaW5lX2Jpbl9kZiAlPiUKICBkcGx5cjo6c2VsZWN0KGNlbGxfbGluZSwgcHNldWRvdGltZV9iaW4sIHBjdCkgJT4lCiAgdGlkeXI6OnBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBwc2V1ZG90aW1lX2JpbiwgdmFsdWVzX2Zyb20gPSBwY3QsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlc19maWxsID0gMCkgJT4lCiAgdGliYmxlOjpjb2x1bW5fdG9fcm93bmFtZXMoImNlbGxfbGluZSIpCgphbm5vdF9jb2xvcnMgPC0gbGlzdChTdGF0ZSA9IGJpbl9jb2xvcnMpCnBfZjNjX2dyb2IgPC0gcGhlYXRtYXAoCiAgYXMubWF0cml4KGxpbmVfYmluX3dpZGUpLAogIGNvbG9yICAgICAgICA9IGNvbG9yUmFtcFBhbGV0dGUoYygid2hpdGUiLCIjRkVFMDkwIiwiI0Q3MzAyNyIpKSgxMDApLAogIGRpc3BsYXlfbnVtYmVycyA9IFRSVUUsCiAgbnVtYmVyX2Zvcm1hdCAgID0gIiUuMWYiLAogIG51bWJlcl9jb2xvciAgICA9ICJibGFjayIsCiAgZm9udHNpemVfbnVtYmVyID0gOSwKICBjbHVzdGVyX3Jvd3MgICAgPSBGQUxTRSwKICBjbHVzdGVyX2NvbHMgICAgPSBGQUxTRSwKICBib3JkZXJfY29sb3IgICAgPSAid2hpdGUiLAogIG1haW4gICAgICAgICAgICA9ICJDICBTdGF0ZSBCaW4gJSBieSBDZWxsIExpbmUiLAogIGFuZ2xlX2NvbCAgICAgICA9IDQ1LAogIHNpbGVudCAgICAgICAgICA9IFRSVUUKKQoKZmlnMyA8LSAocF9mM2EgfCBwX2YzYikgLwogIHdyYXBfZWxlbWVudHMocF9mM2NfZ3JvYiRndGFibGUpICsKICBwbG90X2xheW91dChoZWlnaHRzID0gYygxLjIsIDEpKSArCiAgcGxvdF9hbm5vdGF0aW9uKAogICAgdGl0bGUgICAgPSAiRmlndXJlIDMg4oCUIFBzZXVkb3RpbWUgRGlzdHJpYnV0aW9uIGFuZCBTdGF0ZSBDb21wb3NpdGlvbiIsCiAgICB0aGVtZSAgICA9IHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBmYWNlID0gImJvbGQiKSkKICApCmZpZzMKc2F2ZV9maWcoZmlnMywgIkZpZ3VyZTNfUHNldWRvdGltZV9EaXN0cmlidXRpb24iLCBzdWJkaXIgPSBmaWdfZGlyX21zLCB3ID0gMTgsIGggPSAxNCkKYGBgCgojIyBGaWd1cmUgNCDigJQgS2V5IE1hcmtlciBFeHByZXNzaW9uIGJ5IFN0YXRlIEJpbgoKYGBge3IgZmlnNC1tYXJrZXJzLCBmaWcud2lkdGg9MTgsIGZpZy5oZWlnaHQ9MTB9CkRlZmF1bHRBc3NheShtYXBwZWRfTWFsaWduYW50Q0Q0VCkgPC0gIlNDVCIKCiMgUGFuZWxzIEHigJNEOiB2aW9saW4vZG90IHBsb3RzIG9mIGtleSBzdGF0ZSBtYXJrZXJzCnN0YXRlX21hcmtlcnMgPC0gbGlzdCgKICAiTmFpdmUvVENNIiAgPSBjKCJDQ1I3IiwiU0VMTCIsIlRDRjciLCJJTDdSIiwiTEVGMSIpLAogICJUcmVnIiAgICAgICA9IGMoIkZPWFAzIiwiSUwyUkEiLCJJS1pGMiIsIkNUTEE0IiwiVE5GUlNGNCIpLAogICJURU0iICAgICAgICA9IGMoIkdaTUsiLCJHWk1BIiwiQ0NMNSIsIk5LRzciLCJDWDNDUjEiKSwKICAiVGVtcmEvQ1RMIiAgPSBjKCJHWk1CIiwiUFJGMSIsIkdOTFkiLCJGR0ZCUDIiLCJGQ0dSM0EiKQopCgphbGxfbXMgPC0gdW5pcXVlKHVubGlzdChzdGF0ZV9tYXJrZXJzKSkKYXZhaWxfbXMgPC0gaW50ZXJzZWN0KGFsbF9tcywgcm93bmFtZXMobWFwcGVkX01hbGlnbmFudENENFQpKQoKZHAgPC0gRG90UGxvdCgKICBtYXBwZWRfTWFsaWduYW50Q0Q0VCwKICBmZWF0dXJlcyAgICA9IGF2YWlsX21zLAogIGdyb3VwLmJ5ICAgID0gInBzZXVkb3RpbWVfYmluIiwKICBhc3NheSAgICAgICA9ICJTQ1QiLAogIGRvdC5zY2FsZSAgID0gNwopICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudDIobG93ID0gIiMyMTY2QUMiLCBtaWQgPSAid2hpdGUiLCBoaWdoID0gIiNENzMwMjciLAogICAgICAgICAgICAgICAgICAgICAgICBtaWRwb2ludCA9IDAsIG5hbWUgPSAiQXZnIEV4cHIiKSArCiAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAxMikgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCBzaXplID0gOSksCiAgICBwbG90LnRpdGxlICA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBoanVzdCA9IDApCiAgKSArCiAgbGFicyh0aXRsZSA9ICJGaWd1cmUgNCDigJQgS2V5IFQgQ2VsbCBNYXJrZXIgRXhwcmVzc2lvbiBieSBQc2V1ZG90aW1lIEJpbiIsCiAgICAgICB4ID0gTlVMTCwgeSA9ICJTdGF0ZSBCaW4iKQpkcApzYXZlX2ZpZyhkcCwgIkZpZ3VyZTRfTWFya2VyX0RvdFBsb3QiLCBzdWJkaXIgPSBmaWdfZGlyX21zLCB3ID0gMTgsIGggPSA3KQpgYGAKCiMjIFN1cHBsZW1lbnRhcnkgRmlndXJlIFMxIOKAlCBQZXItQ2VsbC1MaW5lIFVNQVAgUHJvamVjdGlvbnMKCmBgYHtyIHN1cHBmaWctczEtcGVyLWxpbmUsIGZpZy53aWR0aD0xNCwgZmlnLmhlaWdodD03fQpsaW5lX3Bsb3RfbGlzdCA8LSBsYXBwbHkocGFzdGUwKCJMIiwgMTo3KSwgZnVuY3Rpb24obG4pIHsKICBkZl9sbiA8LSBxdWVyeV9iaW5zICU+JSBmaWx0ZXIoY2VsbF9saW5lID09IGxuKQoKICBnZ3Bsb3QoKSArCiAgICBnZW9tX3BvaW50KGRhdGEgPSByZWZfYmcsIGFlcyhVTUFQXzEsIFVNQVBfMiksCiAgICAgICAgICAgICAgIGNvbG91ciA9ICJncmV5OTAiLCBzaXplID0gMC4yNSwgYWxwaGEgPSAwLjQpICsKICAgIGdlb21fcG9pbnQoZGF0YSA9IGRmX2xuICU+JSBmaWx0ZXIoIWlzLm5hKHBzZXVkb3RpbWVfYmluKSksCiAgICAgICAgICAgICAgIGFlcyhVTUFQXzEsIFVNQVBfMiwgY29sb3VyID0gcHNldWRvdGltZV9iaW4pLAogICAgICAgICAgICAgICBzaXplID0gMC42LCBhbHBoYSA9IDAuOSkgKwogICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBiaW5fY29sb3JzLCBuYW1lID0gIkJpbiIpICsKICAgIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMTEpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgaGp1c3QgPSAwLjUsIHNpemUgPSAxMCkpICsKICAgIGdndGl0bGUoc3ByaW50ZigiJXMgKG49JXMpIiwgbG4sIGNvbW1hKG5yb3coZGZfbG4pKSkpCn0pCgojIFNoYXJlZCBsZWdlbmQKbGVnZW5kX3Bsb3QgPC0gZ2dwbG90KAogIGRhdGEuZnJhbWUoeD0xOjUsIHk9MSwgYmluPW5hbWVzKGJpbl9jb2xvcnMpKSwKICBhZXMoeCwgeSwgY29sb3VyID0gYmluKQopICsKICBnZW9tX3BvaW50KHNpemUgPSA0KSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBiaW5fY29sb3JzLCBuYW1lID0gIlN0YXRlIEJpbiIpICsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDUpKSkgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikKc2hhcmVkX2xlZ2VuZCA8LSBjb3dwbG90OjpnZXRfbGVnZW5kKGxlZ2VuZF9wbG90KQoKczFfZ3JpZCA8LSB3cmFwX3Bsb3RzKGxpbmVfcGxvdF9saXN0LCBuY29sID0gNCkgKwogIHBsb3RfYW5ub3RhdGlvbigKICAgIHRpdGxlICAgID0gIlN1cHBsZW1lbnRhcnkgRmlndXJlIFMxIOKAlCBQc2V1ZG90aW1lIEJpbiBEaXN0cmlidXRpb24gcGVyIENlbGwgTGluZSIsCiAgICBzdWJ0aXRsZSA9ICJHcmV5IGJhY2tncm91bmQgPSBoZWFsdGh5IHJlZmVyZW5jZSBjZWxscyIsCiAgICB0aGVtZSAgICA9IHRoZW1lKAogICAgICBwbG90LnRpdGxlICAgID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIiksCiAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBjb2xvdXIgPSAiZ3JleTQwIikKICAgICkKICApCgojIEF0dGFjaCBzaGFyZWQgbGVnZW5kIHRvIHJpZ2h0IHNpZGUgdXNpbmcgY293cGxvdApzMSA8LSBjb3dwbG90OjpwbG90X2dyaWQoczFfZ3JpZCwgc2hhcmVkX2xlZ2VuZCwKICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAyLCByZWxfd2lkdGhzID0gYygxLCAwLjA4KSkKczEKIyBjb3dwbG90OjpwbG90X2dyaWQoKSByZXR1cm5zIGEgZ3RhYmxlLCBub3QgYSBnZ3Bsb3Qg4oCUIHVzZSBzYXZlX3Bsb3Qgbm90IGdnc2F2ZQpjb3dwbG90OjpzYXZlX3Bsb3QoCiAgZmlsZW5hbWUgPSBmaWxlLnBhdGgoZmlnX2Rpcl9tcywgIlN1cHBGaWdfUzFfcGVyX2xpbmVfVU1BUC5wbmciKSwKICBwbG90ICAgICA9IHMxLAogIGJhc2Vfd2lkdGggPSAyMiwgYmFzZV9oZWlnaHQgPSAxNCwgZHBpID0gMzAwLCBiZyA9ICJ3aGl0ZSIKKQpjb3dwbG90OjpzYXZlX3Bsb3QoCiAgZmlsZW5hbWUgPSBmaWxlLnBhdGgoZmlnX2Rpcl9wZGYsICJTdXBwRmlnX1MxX3Blcl9saW5lX1VNQVAucGRmIiksCiAgcGxvdCAgICAgPSBzMSwKICBiYXNlX3dpZHRoID0gMjIsIGJhc2VfaGVpZ2h0ID0gMTQKKQpgYGAKCiMjIFN1cHBsZW1lbnRhcnkgRmlndXJlIFMyIOKAlCBBbmNob3IgJiBUcmFuc2ZlciBRdWFsaXR5CgpgYGB7ciBzdXBwZmlnLXMyLXF1YWxpdHksIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD02fQojIEFuY2hvciBzY29yZXMKcF9zMmEgPC0gZ2dwbG90KGFuY2hvcl9kZiwgYWVzKHggPSBzY29yZSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNjAsIGZpbGwgPSAiIzIxNjZBQyIsIGNvbG91ciA9ICJ3aGl0ZSIsIGFscGhhID0gMC44NSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IG1lZGlhbihhbmNob3JfZGYkc2NvcmUpLAogICAgICAgICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3VyID0gInJlZCIsIGxpbmV3aWR0aCA9IDAuOCkgKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IG1lZGlhbihhbmNob3JfZGYkc2NvcmUpICsgMC4wMiwgeSA9IEluZiwgdmp1c3QgPSAxLjUsIGhqdXN0ID0gMCwKICAgICAgICAgICBsYWJlbCA9IHNwcmludGYoIm1lZGlhbj0lLjNmIiwgbWVkaWFuKGFuY2hvcl9kZiRzY29yZSkpLAogICAgICAgICAgIGNvbG91ciA9ICJyZWQiLCBzaXplID0gMy41KSArCiAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAxMikgKwogIGxhYnModGl0bGUgPSAiQSAgVHJhbnNmZXIgQW5jaG9yIFNjb3JlIERpc3RyaWJ1dGlvbiIsCiAgICAgICBzdWJ0aXRsZSA9IHNwcmludGYoIm49JWQgYW5jaG9ycyB8IGNlbGxzOmFuY2hvcnMgPSAlLjFmOjEiLAogICAgICAgICAgICAgICAgICAgICAgICAgIG5fYW5jaG9ycywgYW5jaG9yX3JhdGlvKSwKICAgICAgIHggPSAiQW5jaG9yIFNjb3JlIiwgeSA9ICJDb3VudCIpCgojIExhYmVsIHRyYW5zZmVyIGNvbmZpZGVuY2UKaWYgKHNjb3JlX2NvbCAlaW4lIGNvbG5hbWVzKG1hcHBlZF9NYWxpZ25hbnRDRDRUQG1ldGEuZGF0YSkpIHsKICBzY19kZiA8LSBkYXRhLmZyYW1lKHNjb3JlID0gbWFwcGVkX01hbGlnbmFudENENFRAbWV0YS5kYXRhW1tzY29yZV9jb2xdXSkKICBwX3MyYiA8LSBnZ3Bsb3Qoc2NfZGYsIGFlcyh4ID0gc2NvcmUpKSArCiAgICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNjAsIGZpbGwgPSAiI0Q3MzAyNyIsIGNvbG91ciA9ICJ3aGl0ZSIsIGFscGhhID0gMC44NSkgKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbWVkaWFuKHNjX2RmJHNjb3JlLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvdXIgPSAiYmxhY2siLCBsaW5ld2lkdGggPSAwLjgpICsKICAgIGFubm90YXRlKCJ0ZXh0IiwgeCA9IG1lZGlhbihzY19kZiRzY29yZSwgbmEucm0gPSBUUlVFKSAtIDAuMDIsCiAgICAgICAgICAgICB5ID0gSW5mLCB2anVzdCA9IDEuNSwgaGp1c3QgPSAxLAogICAgICAgICAgICAgbGFiZWwgPSBzcHJpbnRmKCJtZWRpYW49JS4zZiIsIG1lZGlhbihzY19kZiRzY29yZSwgbmEucm0gPSBUUlVFKSksCiAgICAgICAgICAgICBjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gMy41KSArCiAgICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDEyKSArCiAgICBsYWJzKHRpdGxlID0gIkIgIExhYmVsIFRyYW5zZmVyIENvbmZpZGVuY2UgU2NvcmUg4oCUIFPDqXphcnkgQ2VsbHMiLAogICAgICAgICB4ID0gIlNjb3JlIiwgeSA9ICJDZWxsIENvdW50IikKfSBlbHNlIHsKICBwX3MyYiA8LSBnZ3Bsb3QoKSArIHRoZW1lX3ZvaWQoKSArIGdndGl0bGUoIlNjb3JlIGNvbHVtbiBub3QgYXZhaWxhYmxlIikKfQoKczIgPC0gcF9zMmEgfCBwX3MyYgpzMiA8LSBzMiArIHBsb3RfYW5ub3RhdGlvbigKICB0aXRsZSA9ICJTdXBwbGVtZW50YXJ5IEZpZ3VyZSBTMiDigJQgVHJhbnNmZXIgUXVhbGl0eSBNZXRyaWNzIiwKICB0aGVtZSA9IHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1LCBmYWNlID0gImJvbGQiKSkKKQpzMgpzYXZlX2ZpZyhzMiwgIlN1cHBGaWdfUzJfdHJhbnNmZXJfcXVhbGl0eSIsIHN1YmRpciA9IGZpZ19kaXJfbXMsIHcgPSAxNiwgaCA9IDcpCmBgYAoKLS0tCgojIDExLiBGaWd1cmUgRmlsZSBTdW1tYXJ5IHsjZmlndXJlLXN1bW1hcnl9CgpgYGB7ciBmaWd1cmUtc3VtbWFyeX0KY2F0KCI9PT0gUUMgRmlndXJlcyBzYXZlZCA9PT1cbiIpCnFjX2ZpbGVzIDwtIGxpc3QuZmlsZXMoZmlnX2Rpcl9xYywgcGF0dGVybiA9ICJcXC5wbmckIikKZm9yIChmIGluIHFjX2ZpbGVzKSBjYXQoIiAiLCBmLCAiXG4iKQoKY2F0KCJcbj09PSBNYW51c2NyaXB0IEZpZ3VyZXMgc2F2ZWQgPT09XG4iKQptc19maWxlcyA8LSBsaXN0LmZpbGVzKGZpZ19kaXJfbXMsIHBhdHRlcm4gPSAiXFwucG5nJCIpCmZvciAoZiBpbiBtc19maWxlcykgY2F0KCIgIiwgZiwgIlxuIikKCmNhdCgiXG49PT0gUERGIFZlcnNpb25zID09PVxuIikKcGRmX2ZpbGVzIDwtIGxpc3QuZmlsZXMoZmlnX2Rpcl9wZGYsIHBhdHRlcm4gPSAiXFwucGRmJCIpCmZvciAoZiBpbiBwZGZfZmlsZXMpIGNhdCgiICIsIGYsICJcbiIpCmBgYAoKLS0tCgojIDEyLiBTZXNzaW9uIEluZm8geyNzZXNzaW9uLWluZm99CgpgYGB7ciBzZXNzaW9uLWluZm99CnNlc3Npb25JbmZvKCkKYGBgCg==