Overview
This script regenerates all manuscript figures from
the saved projection object. The reference object is loaded
solely to extract UMAP coordinates for the grey
background.
Objects required
reference_integrated |
../../1-Final_Custom_MST_Monocle3_Trajectory_and_mapping/1-Custom_MST/Objects/cd4_ref_dual_trajectory.rds |
UMAP background only — grey reference dots |
mapped_MalignantCD4T |
results/MalignantCD4T_Monocle3_projection/MalignantCD4T_mapped_monocle3_pseudotime_noProlif_ref.Rds |
All biology — pseudotime, labels, bins, colour
scales |
Key design
decisions
Pseudotime colour-scale limits (PT_LIMITS) |
mapped_MalignantCD4T$predicted.pseudotime |
| Bin boundaries |
Midpoints between actual reference state medians —
computed at runtime from ref_bg |
State medians (REF_MEDIANS) |
Computed at runtime from ref_bg — never
hard-coded |
| All bar charts, violins, density plots |
mapped_MalignantCD4T only |
Panel B fix
Previously called FeaturePlot(reference_integrated, ...)
without limits, producing a spurious 1.0–2.0 colour scale.
Fixed: Panel B plots Sézary cells coloured by
predicted.pseudotime with limits = PT_LIMITS
(correct 0–25 scale).
Bin design
Bins are anchored to actual reference state medians
computed from ref_bg. Boundaries = midpoint between
adjacent state medians (biology-principled, not arbitrary). Treg-like
bin is assigned by Azimuth label (Treg is a branch, not a linear
position).
1. Setup &
Libraries
suppressPackageStartupMessages({
library(Seurat)
library(ggplot2)
library(dplyr)
library(tidyr)
library(forcats)
library(patchwork)
library(scales)
library(RColorBrewer)
library(ggridges)
library(knitr)
library(kableExtra)
})
Registered S3 methods overwritten by 'htmltools':
method from
print.html tools:rstudio
print.shiny.tag tools:rstudio
print.shiny.tag.list tools:rstudio
Registered S3 method overwritten by 'rmarkdown':
method from
print.paged_df
dir.create("Figures/PNG", recursive = TRUE, showWarnings = FALSE)
dir.create("Figures/PDF", recursive = TRUE, showWarnings = FALSE)
save_fig <- function(p, name, w = 10, h = 8) {
ggsave(file.path("Figures/PNG", paste0(name, ".png")),
p, width = w, height = h, dpi = 300, bg = "white")
ggsave(file.path("Figures/PDF", paste0(name, ".pdf")),
p, width = w, height = h, useDingbats = FALSE)
invisible(cat(sprintf(" \u2713 %s [PNG + PDF]\n", name)))
}
STATE_COLORS <- c(
"CD4 Naive" = "#4472C4",
"CD4 TCM" = "#70AD47",
"CD4 TEM" = "#ED7D31",
"CD4 Temra/CTL" = "#C00000",
"Treg" = "#7030A0"
)
BIN_COLORS <- c(
"Naive-like" = "#4472C4",
"TCM-like" = "#70AD47",
"TEM-like" = "#ED7D31",
"Temra-like" = "#C00000",
"Treg-like" = "#7030A0"
)
STATE_ORDER <- c("CD4 Naive", "CD4 TCM", "CD4 TEM", "CD4 Temra/CTL", "Treg")
BIN_ORDER <- c("Naive-like", "TCM-like", "TEM-like", "Temra-like", "Treg-like")
LINE_ORDER <- paste0("L", 1:7)
cat("Setup complete.\n")
Setup complete.
2. Load & Validate
Objects
ref_path <- paste0(
"../../1-Final_Custom_MST_Monocle3_Trajectory_and_mapping/",
"1-Custom_MST/Objects/cd4_ref_dual_trajectory.rds"
)
reference_integrated <- readRDS(ref_path)
cat("Reference loaded:", ncol(reference_integrated), "cells\n")
Reference loaded: 11466 cells
stopifnot(
"umap reduction missing from reference" =
"umap" %in% names(reference_integrated@reductions)
)
obj_path <- paste0(
"../results/MalignantCD4T_Monocle3_projection/",
"MalignantCD4T_mapped_monocle3_pseudotime_noProlif_ref.Rds"
)
mapped_MalignantCD4T <- readRDS(obj_path)
cat("Query loaded: ", ncol(mapped_MalignantCD4T), "cells\n")
Query loaded: 40695 cells
stopifnot(
"ref.umap reduction missing — re-run MapQuery" =
"ref.umap" %in% names(mapped_MalignantCD4T@reductions),
"predicted.pseudotime column missing" =
"predicted.pseudotime" %in% colnames(mapped_MalignantCD4T@meta.data),
"predicted.predicted.celltype.l2 column missing" =
"predicted.predicted.celltype.l2" %in% colnames(mapped_MalignantCD4T@meta.data)
)
if (!"cell_line" %in% colnames(mapped_MalignantCD4T@meta.data)) {
if ("orig.ident" %in% colnames(mapped_MalignantCD4T@meta.data)) {
mapped_MalignantCD4T$cell_line <- mapped_MalignantCD4T$orig.ident
cat("NOTE: using orig.ident as cell_line\n")
} else {
stop("Cannot find cell_line or orig.ident in metadata")
}
}
cat("\npredicted.pseudotime summary (expect Min~0, Max~25):\n")
predicted.pseudotime summary (expect Min~0, Max~25):
print(summary(mapped_MalignantCD4T$predicted.pseudotime))
Min. 1st Qu. Median Mean 3rd Qu. Max.
1.156 16.431 17.703 17.655 19.487 25.553
cat("\nTransferred label distribution:\n")
Transferred label distribution:
print(sort(table(mapped_MalignantCD4T$predicted.predicted.celltype.l2,
useNA = "ifany"), decreasing = TRUE))
CD4 TCM CD4 TEM Treg CD4 Naive
40291 304 79 21
cat("\nCell line sizes:\n")
Cell line sizes:
print(sort(table(mapped_MalignantCD4T$cell_line, useNA = "ifany")))
L6 L7 L1 L2 L4 L5 L3
5148 5331 5825 5935 6006 6022 6428
3. Build Reference
Background (ref_bg)
# ref_bg serves two purposes:
# 1. Grey background dots in all projection UMAPs
# 2. Source for computing actual reference state medians (REF_MEDIANS)
ref_bg <- data.frame(
Embeddings(reference_integrated, "umap"),
state = reference_integrated$predicted.celltype.l2,
pseudotime = reference_integrated$monocle3_pseudotime,
stringsAsFactors = FALSE
)
colnames(ref_bg)[1:2] <- c("UMAP_1", "UMAP_2")
ref_bg$state <- factor(ref_bg$state, levels = STATE_ORDER)
cat("Reference monocle3_pseudotime (should be 0-25):\n")
Reference monocle3_pseudotime (should be 0-25):
print(summary(ref_bg$pseudotime))
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.000 3.855 7.404 9.926 15.525 25.356
ref_bg_plot <- ref_bg[sample(nrow(ref_bg)), ]
cat(sprintf("\nref_bg ready: %d reference cells\n", nrow(ref_bg)))
ref_bg ready: 11466 reference cells
4. Compute Reference
State Medians & Bin Boundaries
# ══════════════════════════════════════════════════════════════════════════
# REF_MEDIANS computed at runtime from actual ref_bg — NOT hard-coded.
#
# Diagnostic confirmed these actual values:
# CD4 Naive median = 3.293
# CD4 TCM median = 9.377 (was hard-coded as 13.36 — WRONG)
# CD4 TEM median = 24.840
# CD4 Temra/CTL median = 24.840 (only 10 cells)
# Treg median = 11.150 (was hard-coded as 18.75 — above Treg max of 17.40, WRONG)
#
# Bin boundaries derived as midpoints between adjacent state medians.
# ══════════════════════════════════════════════════════════════════════════
ref_state_medians <- ref_bg %>%
filter(!is.na(pseudotime), !is.na(state)) %>%
group_by(state) %>%
summarise(
n = n(),
med_pt = round(median(pseudotime, na.rm = TRUE), 3),
.groups = "drop"
) %>%
arrange(med_pt)
cat("=== Reference state medians (data-derived) ===\n")
=== Reference state medians (data-derived) ===
print(ref_state_medians)
get_med <- function(s) {
v <- ref_state_medians$med_pt[ref_state_medians$state == s]
if (length(v) == 0) stop(paste("State not found in ref_bg:", s))
v
}
naive_med <- get_med("CD4 Naive")
tcm_med <- get_med("CD4 TCM")
tem_med <- get_med("CD4 TEM")
temra_med <- get_med("CD4 Temra/CTL")
treg_med <- get_med("Treg")
BIN_NAIVE_TCM <- round((naive_med + tcm_med) / 2, 3)
BIN_TCM_TEM <- round((tcm_med + tem_med) / 2, 3)
BIN_TEM_TEMRA <- round((tem_med + temra_med) / 2, 3)
cat("\n=== Bin boundaries (midpoints between adjacent state medians) ===\n")
=== Bin boundaries (midpoints between adjacent state medians) ===
cat(sprintf(" Naive | TCM : %.3f\n", BIN_NAIVE_TCM))
Naive | TCM : 6.335
cat(sprintf(" TCM | TEM : %.3f\n", BIN_TCM_TEM))
TCM | TEM : 17.108
cat(sprintf(" TEM | Temra : %.3f\n", BIN_TEM_TEMRA))
TEM | Temra : 24.840
cat(sprintf(" Treg : label-based (branch logic)\n"))
Treg : label-based (branch logic)
if (abs(tem_med - temra_med) < 0.5) {
cat("\nNOTE: TEM and Temra medians are very close (n=10 Temra cells in reference).\n")
cat(" Temra-like bin will be negligible — biologically expected.\n")
}
NOTE: TEM and Temra medians are very close (n=10 Temra cells in reference).
Temra-like bin will be negligible — biologically expected.
REF_MEDIANS <- data.frame(
state = factor(STATE_ORDER, levels = STATE_ORDER),
med_pt = c(naive_med, tcm_med, tem_med, temra_med, treg_med)
)
cat("\n=== REF_MEDIANS (used for reference lines in all figures) ===\n")
=== REF_MEDIANS (used for reference lines in all figures) ===
print(REF_MEDIANS)
# ── REF_MEDIANS_EFFECTOR: Treg excluded ───────────────────────────────────
# Treg (median PT=11.15) and TCM (median PT=9.38) overlap entirely in
# pseudotime space — both states share the Naive→TCM graph segment.
# Showing a Treg line at PT=11.15 implies a pseudotime boundary that does
# not exist and misleads interpretation. Treg-like cells are assigned by
# transferred Azimuth label (KNN), not by pseudotime position.
REF_MEDIANS_EFFECTOR <- REF_MEDIANS %>%
filter(state != "Treg")
LINETYPE_EFFECTOR <- c(
"CD4 Naive" = "dotted",
"CD4 TCM" = "dashed",
"CD4 TEM" = "longdash",
"CD4 Temra/CTL" = "solid"
)
cat("=== REF_MEDIANS_EFFECTOR (Treg excluded) ===\n")
=== REF_MEDIANS_EFFECTOR (Treg excluded) ===
print(REF_MEDIANS_EFFECTOR)
5. Assign Pseudotime
Bins
assign_bin <- function(pt, lbl) {
if (isTRUE(grepl("Treg", lbl, ignore.case = TRUE))) return("Treg-like")
if (is.na(pt)) return(NA_character_)
if (pt <= BIN_NAIVE_TCM) return("Naive-like")
if (pt <= BIN_TCM_TEM) return("TCM-like")
if (pt <= BIN_TEM_TEMRA) return("TEM-like")
return("Temra-like")
}
mapped_MalignantCD4T$pseudotime_bin <- factor(
mapply(assign_bin,
pt = mapped_MalignantCD4T$predicted.pseudotime,
lbl = mapped_MalignantCD4T$predicted.predicted.celltype.l2),
levels = BIN_ORDER
)
cat("Pseudotime bin distribution (all cells):\n")
Pseudotime bin distribution (all cells):
print(table(mapped_MalignantCD4T$pseudotime_bin, useNA = "ifany"))
Naive-like TCM-like TEM-like Temra-like Treg-like
2287 13298 23485 1546 79
cat("\nPseudotime bin per cell line:\n")
Pseudotime bin per cell line:
print(table(mapped_MalignantCD4T$cell_line,
mapped_MalignantCD4T$pseudotime_bin, useNA = "ifany"))
Naive-like TCM-like TEM-like Temra-like Treg-like
L1 1407 1104 2630 682 2
L2 833 1593 3324 185 0
L3 4 2357 3613 447 7
L4 37 1384 4569 11 5
L5 3 3419 2414 178 8
L6 0 1815 3244 43 46
L7 3 1626 3691 0 11
6. Build Shared Data
Frames
query_df <- data.frame(
Embeddings(mapped_MalignantCD4T, "ref.umap"),
pseudotime = mapped_MalignantCD4T$predicted.pseudotime,
cell_line = factor(mapped_MalignantCD4T$cell_line, levels = LINE_ORDER),
label = mapped_MalignantCD4T$predicted.predicted.celltype.l2,
pseudotime_bin = mapped_MalignantCD4T$pseudotime_bin,
stringsAsFactors = FALSE
)
colnames(query_df)[1:2] <- c("UMAP_1", "UMAP_2")
PT_LIMITS <- range(query_df$pseudotime, na.rm = TRUE)
cat(sprintf("Pseudotime colour limits: %.3f to %.3f\n", PT_LIMITS[1], PT_LIMITS[2]))
Pseudotime colour limits: 1.156 to 25.553
label_df <- query_df %>%
filter(!is.na(label), !is.na(cell_line)) %>%
count(cell_line, label) %>%
group_by(cell_line) %>%
mutate(pct = 100 * n / sum(n)) %>%
ungroup() %>%
mutate(label = factor(label, levels = STATE_ORDER))
bin_df <- query_df %>%
filter(!is.na(pseudotime_bin), !is.na(cell_line)) %>%
count(cell_line, pseudotime_bin) %>%
group_by(cell_line) %>%
mutate(pct = 100 * n / sum(n)) %>%
ungroup()
cat("Data frames ready.\n")
Data frames ready.
7. Figure 7 —
Four-Panel Summary
bg_layer <- geom_point(
data = ref_bg_plot, aes(x = UMAP_1, y = UMAP_2),
colour = "grey68", size = 0.25, alpha = 0.45, inherit.aes = FALSE
)
p7a <- ggplot(query_df[sample(nrow(query_df)), ],
aes(UMAP_1, UMAP_2, colour = factor(label, levels = STATE_ORDER))) +
bg_layer +
geom_point(size = 0.35, alpha = 0.7) +
scale_colour_manual(values = STATE_COLORS, name = "Transferred\nLabel",
na.value = "grey80") +
guides(colour = guide_legend(override.aes = list(size = 3, alpha = 1))) +
theme_classic() +
labs(x = "UMAP-1", y = "UMAP-2",
title = "A. Sézary Cells — Transferred CD4 T Cell Labels") +
theme(plot.title = element_text(hjust = 0.5, size = 12, face = "bold"))
p7b <- ggplot(query_df[order(query_df$pseudotime, na.last = FALSE), ],
aes(UMAP_1, UMAP_2, colour = pseudotime)) +
bg_layer +
geom_point(size = 0.35, alpha = 0.8) +
scale_colour_gradientn(
colours = c("lightblue", "yellow", "red"),
name = "Pseudotime",
limits = PT_LIMITS,
na.value = "grey85"
) +
theme_classic() +
labs(x = "UMAP-1", y = "UMAP-2",
title = "B. Sézary Cells — Transferred Pseudotime [FIXED]") +
theme(plot.title = element_text(hjust = 0.5, size = 12, face = "bold"))
p7c <- ggplot(query_df[sample(nrow(query_df)), ],
aes(UMAP_1, UMAP_2, colour = pseudotime_bin)) +
bg_layer +
geom_point(size = 0.35, alpha = 0.7) +
scale_colour_manual(values = BIN_COLORS, name = "Pseudotime\nBin",
na.value = "grey80") +
guides(colour = guide_legend(override.aes = list(size = 3, alpha = 1))) +
theme_classic() +
labs(x = "UMAP-1", y = "UMAP-2",
title = "C. Sézary Cells — Pseudotime Bin") +
theme(plot.title = element_text(hjust = 0.5, size = 12, face = "bold"))
p7d <- ggplot(label_df, aes(cell_line, pct, fill = label)) +
geom_col(width = 0.75) +
geom_text(data = label_df %>% filter(pct > 3),
aes(label = sprintf("%.1f%%", pct)),
position = position_stack(vjust = 0.5),
size = 3, colour = "white", fontface = "bold") +
scale_fill_manual(values = STATE_COLORS, name = "Label") +
scale_y_continuous(expand = c(0, 0), limits = c(0, 101)) +
theme_classic() +
labs(x = "Cell Line", y = "% Cells",
title = "D. Transferred Label per Cell Line") +
theme(plot.title = element_text(hjust = 0.5, size = 12, face = "bold"),
axis.text.x = element_text(size = 10, face = "bold"))
fig7 <- (p7a | p7b) / (p7c | p7d)
print(fig7)

save_fig(fig7, "Fig7_FourPanel_Summary_FIXED", w = 18, h = 14)
✓ Fig7_FourPanel_Summary_FIXED [PNG + PDF]
save_fig(p7a, "Fig7A_Transferred_Labels", w = 9, h = 7)
✓ Fig7A_Transferred_Labels [PNG + PDF]
save_fig(p7b, "Fig7B_Transferred_Pseudotime_FIXED", w = 9, h = 7)
✓ Fig7B_Transferred_Pseudotime_FIXED [PNG + PDF]
save_fig(p7c, "Fig7C_Pseudotime_Bins_UMAP", w = 9, h = 7)
✓ Fig7C_Pseudotime_Bins_UMAP [PNG + PDF]
save_fig(p7d, "Fig7D_Label_BarChart_per_Line", w = 9, h = 7)
✓ Fig7D_Label_BarChart_per_Line [PNG + PDF]
8. Figure 1 —
Pseudotime Violin per Cell Line
fig1 <- ggplot(
query_df %>% filter(!is.na(pseudotime), !is.na(cell_line)),
aes(cell_line, pseudotime, fill = cell_line)
) +
geom_violin(scale = "width", trim = FALSE, alpha = 0.85, colour = "white") +
geom_boxplot(width = 0.06, fill = "white", colour = "grey40",
outlier.size = 0.3, outlier.alpha = 0.3) +
geom_hline(data = REF_MEDIANS,
aes(yintercept = med_pt, colour = state, linetype = state),
linewidth = 0.7, alpha = 0.9) +
scale_fill_brewer(palette = "Set2", guide = "none") +
scale_colour_manual(values = STATE_COLORS, name = "Reference\nmedian") +
scale_linetype_manual(
values = c("CD4 Naive" = "dotted", "CD4 TCM" = "dashed",
"CD4 TEM" = "longdash", "CD4 Temra/CTL" = "solid",
"Treg" = "twodash"),
name = "Reference\nmedian"
) +
scale_y_continuous(breaks = seq(0, 25, 5)) +
theme_classic() +
labs(
x = "Cell Line",
y = "Transferred Pseudotime",
title = "Figure 1 — Pseudotime Distribution per Sézary Cell Line",
subtitle = sprintf(
"Reference medians: Naive=%.2f | TCM=%.2f | Treg=%.2f | TEM=%.2f | Temra=%.2f",
naive_med, tcm_med, treg_med, tem_med, temra_med)
) +
theme(plot.title = element_text(size = 13, face = "bold"),
plot.subtitle = element_text(size = 9, colour = "grey40"),
axis.text.x = element_text(size = 11, face = "bold"))
print(fig1)

save_fig(fig1, "Fig1_Pseudotime_Violin_per_Line", w = 12, h = 6)
✓ Fig1_Pseudotime_Violin_per_Line [PNG + PDF]
fig1v2 <- ggplot(
query_df %>% filter(!is.na(pseudotime), !is.na(cell_line)),
aes(cell_line, pseudotime, fill = cell_line)
) +
geom_violin(scale = "width", trim = FALSE, alpha = 0.85, colour = "white") +
geom_boxplot(width = 0.06, fill = "white", colour = "grey40",
outlier.size = 0.3, outlier.alpha = 0.3) +
geom_hline(
data = REF_MEDIANS_EFFECTOR,
aes(yintercept = med_pt, colour = state, linetype = state),
linewidth = 0.7, alpha = 0.9
) +
scale_fill_brewer(palette = "Set2", guide = "none") +
scale_colour_manual(
values = STATE_COLORS[names(STATE_COLORS) != "Treg"],
name = "Reference\nmedian"
) +
scale_linetype_manual(
values = LINETYPE_EFFECTOR,
name = "Reference\nmedian"
) +
scale_y_continuous(breaks = seq(0, 25, 5)) +
theme_classic() +
labs(
x = "Cell Line",
y = "Transferred Pseudotime",
title = "Figure 1 — Pseudotime Distribution per Sézary Cell Line",
subtitle = sprintf(
"Effector axis medians: Naive=%.2f | TCM=%.2f | TEM=%.2f | Temra=%.2f\nTreg line omitted — Treg (PT=%.2f) overlaps TCM (PT=%.2f); Treg-like assigned by label",
naive_med, tcm_med, tem_med, temra_med, treg_med, tcm_med)
) +
theme(
plot.title = element_text(size = 13, face = "bold"),
plot.subtitle = element_text(size = 9, colour = "grey40"),
axis.text.x = element_text(size = 11, face = "bold")
)
print(fig1v2)

save_fig(fig1v2, "Fig1v2_Pseudotime_Violin_NoTreg", w = 12, h = 6)
✓ Fig1v2_Pseudotime_Violin_NoTreg [PNG + PDF]
9. Figure 2 — UMAP:
Pseudotime + Label Side by Side
p2a <- ggplot(query_df[order(query_df$pseudotime, na.last = FALSE), ],
aes(UMAP_1, UMAP_2, colour = pseudotime)) +
geom_point(data = ref_bg_plot, aes(UMAP_1, UMAP_2),
colour = "grey68", size = 0.25, alpha = 0.45, inherit.aes = FALSE) +
geom_point(size = 0.25, alpha = 0.8) +
scale_colour_gradientn(
colours = c("#0D0887","#6A00A8","#B12A90","#E16462","#FCA636","#F0F921"),
name = "Pseudotime", limits = PT_LIMITS, na.value = "grey85"
) +
theme_classic() +
labs(x = "UMAP-1", y = "UMAP-2",
title = "A. Transferred pseudotime gradient",
subtitle = "Grey = healthy reference | Coloured = Sézary cells") +
theme(plot.title = element_text(size = 12, face = "bold"))
p2b <- ggplot(query_df[sample(nrow(query_df)), ],
aes(UMAP_1, UMAP_2, colour = factor(label, levels = STATE_ORDER))) +
geom_point(data = ref_bg_plot, aes(UMAP_1, UMAP_2),
colour = "grey88", size = 0.25, alpha = 0.45, inherit.aes = FALSE) +
geom_point(size = 0.25, alpha = 0.7) +
scale_colour_manual(values = STATE_COLORS, name = "Transferred\nlabel",
na.value = "grey80") +
guides(colour = guide_legend(override.aes = list(size = 3, alpha = 1))) +
theme_classic() +
labs(x = "UMAP-1", y = "UMAP-2",
title = "B. Transferred label identity",
subtitle = "96-99.9% CD4 TCM across all seven lines") +
theme(plot.title = element_text(size = 12, face = "bold"))
fig2 <- p2a | p2b
print(fig2)

save_fig(fig2, "Fig2_UMAP_Pseudotime_and_Label", w = 16, h = 7)
✓ Fig2_UMAP_Pseudotime_and_Label [PNG + PDF]
10. Figure 3 — Label
Bar Chart + Per Cell Line UMAP Facets
p3a <- ggplot(label_df, aes(cell_line, pct, fill = label)) +
geom_col(width = 0.75) +
geom_text(data = label_df %>% filter(pct > 5),
aes(label = sprintf("%.0f%%", pct)),
position = position_stack(vjust = 0.5),
size = 3, colour = "white", fontface = "bold") +
scale_fill_manual(values = STATE_COLORS, name = "Label") +
scale_y_continuous(expand = c(0, 0), limits = c(0, 101)) +
theme_classic() +
labs(x = "Cell Line", y = "% Cells", title = "A. Transferred Azimuth l2 Labels") +
theme(plot.title = element_text(size = 12, face = "bold"),
axis.text.x = element_text(size = 10, face = "bold"))
p3b <- ggplot(
query_df %>% filter(!is.na(cell_line)) %>% arrange(pseudotime),
aes(UMAP_1, UMAP_2, colour = pseudotime)
) +
geom_point(
data = ref_bg_plot %>%
slice(rep(1:n(), times = length(levels(query_df$cell_line)))),
aes(UMAP_1, UMAP_2), colour = "grey88", size = 0.2, alpha = 0.4,
inherit.aes = FALSE
) +
geom_point(size = 0.2, alpha = 0.8) +
scale_colour_gradientn(
colours = c("#0D0887","#6A00A8","#B12A90","#E16462","#FCA636","#F0F921"),
name = "Pseudotime", limits = PT_LIMITS, na.value = "grey85"
) +
facet_wrap(~ cell_line, nrow = 2) +
theme_classic() +
theme(strip.text = element_text(face = "bold", size = 10),
plot.title = element_text(size = 12, face = "bold"),
axis.text = element_blank(), axis.ticks = element_blank()) +
labs(x = NULL, y = NULL,
title = "B. Per Cell Line UMAP — Projected Pseudotime (Grey = healthy reference)")
fig3 <- p3a + p3b + plot_layout(widths = c(1, 2))
print(fig3)

save_fig(fig3, "Fig3_Labels_PerLine_UMAP", w = 18, h = 6)
✓ Fig3_Labels_PerLine_UMAP [PNG + PDF]
11. Figure 4 — Per
Cell Line Facet UMAP (Key Heterogeneity Figure)
fig4 <- ggplot(
query_df %>% filter(!is.na(cell_line)) %>% arrange(pseudotime),
aes(UMAP_1, UMAP_2, colour = pseudotime)
) +
geom_point(
data = ref_bg_plot %>%
slice(rep(1:n(), times = length(levels(query_df$cell_line)))),
aes(UMAP_1, UMAP_2), colour = "grey88", size = 0.2, alpha = 0.4,
inherit.aes = FALSE
) +
geom_point(size = 0.25, alpha = 0.8) +
scale_colour_gradientn(
colours = c("#0D0887","#6A00A8","#B12A90","#E16462","#FCA636","#F0F921"),
name = "Pseudotime\n(Naive->Temra)", limits = PT_LIMITS, na.value = "grey85"
) +
facet_wrap(~ cell_line, nrow = 2) +
theme_classic() +
theme(
strip.text = element_text(face = "bold", size = 12),
strip.background = element_rect(fill = "grey95", colour = "grey60"),
plot.title = element_text(size = 14, face = "bold"),
plot.subtitle = element_text(size = 10, colour = "grey40"),
axis.text = element_blank(), axis.ticks = element_blank(),
legend.position = "right"
) +
labs(x = NULL, y = NULL,
title = "Figure 4 — Per Cell Line Facet UMAP: Differentiation Position",
subtitle = "L1 most heterogeneous (spans full trajectory) | L6 most arrested (tight TCM cluster)")
print(fig4)

save_fig(fig4, "Fig4_PerLine_Facet_UMAP", w = 18, h = 10)
✓ Fig4_PerLine_Facet_UMAP [PNG + PDF]
12. Figure 5 — Label
vs Pseudotime Bins Bar Charts
p5a <- ggplot(label_df, aes(cell_line, pct, fill = label)) +
geom_col(width = 0.7) +
geom_text(data = label_df %>% filter(pct > 3),
aes(label = sprintf("%.1f%%", pct)),
position = position_stack(vjust = 0.5),
size = 3.2, colour = "white", fontface = "bold") +
scale_fill_manual(values = STATE_COLORS, name = "Label") +
scale_y_continuous(expand = c(0, 0), limits = c(0, 101)) +
theme_classic() +
labs(x = NULL, y = "% Cells",
title = "A. Transferred Azimuth l2 Label (Cell of Origin)",
subtitle = "96-99.9% CD4 TCM across all lines — TCM origin confirmed") +
theme(plot.title = element_text(size = 12, face = "bold"),
plot.subtitle = element_text(size = 10, colour = "grey40"),
axis.text.x = element_blank(), axis.ticks.x = element_blank())
p5b <- ggplot(bin_df, aes(cell_line, pct, fill = pseudotime_bin)) +
geom_col(width = 0.7) +
geom_text(data = bin_df %>% filter(pct > 3),
aes(label = sprintf("%.1f%%", pct)),
position = position_stack(vjust = 0.5),
size = 3.2, colour = "white", fontface = "bold") +
scale_fill_manual(values = BIN_COLORS, name = "Pseudotime bin") +
scale_y_continuous(expand = c(0, 0), limits = c(0, 101)) +
theme_classic() +
labs(x = "Cell Line", y = "% Cells",
title = "B. Pseudotime Bin Assignment (Differentiation Position)",
subtitle = sprintf(
"Bin boundaries — Naive|TCM: %.2f | TCM|TEM: %.2f | TEM|Temra: %.2f | Treg: label-based",
BIN_NAIVE_TCM, BIN_TCM_TEM, BIN_TEM_TEMRA)) +
theme(plot.title = element_text(size = 12, face = "bold"),
plot.subtitle = element_text(size = 9, colour = "grey40"),
axis.text.x = element_text(size = 11, face = "bold"))
fig5 <- p5a / p5b
print(fig5)

save_fig(fig5, "Fig5_Label_vs_Pseudotime_Bins", w = 16, h = 12)
✓ Fig5_Label_vs_Pseudotime_Bins [PNG + PDF]
save_fig(p5a, "Fig5A_Label_Transfer_BarChart", w = 10, h = 5)
✓ Fig5A_Label_Transfer_BarChart [PNG + PDF]
save_fig(p5b, "Fig5B_Pseudotime_Bins_BarChart", w = 10, h = 5)
✓ Fig5B_Pseudotime_Bins_BarChart [PNG + PDF]
13. Figure 6 —
Pseudotime Density + Ridgeplot
p6a <- ggplot(query_df %>% filter(!is.na(pseudotime)), aes(x = pseudotime)) +
geom_density(fill = "#c0392b", colour = "#c0392b", alpha = 0.4, linewidth = 0.9) +
geom_vline(data = REF_MEDIANS,
aes(xintercept = med_pt, colour = state),
linetype = "dashed", linewidth = 0.7) +
geom_text(data = REF_MEDIANS,
aes(x = med_pt, y = Inf,
label = gsub("CD4 ", "", as.character(state))),
inherit.aes = FALSE,
angle = 90, hjust = 1.1, vjust = -0.3, size = 2.8, colour = "grey30") +
scale_colour_manual(values = STATE_COLORS, name = "Reference\nstate median") +
scale_x_continuous(limits = c(0, 26), breaks = seq(0, 25, 5)) +
theme_classic() +
labs(
x = "Transferred Pseudotime",
y = "Density",
title = "A. Sézary Pseudotime Distribution — All Lines Combined",
subtitle = sprintf(
"Reference medians: Naive=%.2f | TCM=%.2f | Treg=%.2f | TEM=%.2f | Temra=%.2f",
naive_med, tcm_med, treg_med, tem_med, temra_med)
) +
theme(plot.title = element_text(size = 12, face = "bold"),
plot.subtitle = element_text(size = 9, colour = "grey40"),
legend.position = "right")
p6b <- ggplot(
query_df %>% filter(!is.na(pseudotime), !is.na(cell_line)),
aes(x = pseudotime, y = fct_rev(cell_line), fill = cell_line)
) +
geom_density_ridges(scale = 0.9, rel_min_height = 0.01,
alpha = 0.85, colour = "white") +
geom_vline(xintercept = c(BIN_NAIVE_TCM, BIN_TCM_TEM, BIN_TEM_TEMRA),
linetype = "dashed", colour = "grey50", linewidth = 0.5) +
annotate("text", x = BIN_NAIVE_TCM, y = 0.5, label = "Naive|TCM",
size = 2.5, hjust = 1.05, colour = "grey40", angle = 90) +
annotate("text", x = BIN_TCM_TEM, y = 0.5, label = "TCM|TEM",
size = 2.5, hjust = 1.05, colour = "grey40", angle = 90) +
annotate("text", x = BIN_TEM_TEMRA, y = 0.5, label = "TEM|Temra",
size = 2.5, hjust = 1.05, colour = "grey40", angle = 90) +
scale_fill_brewer(palette = "Set2", guide = "none") +
scale_x_continuous(limits = c(0, 26), breaks = seq(0, 25, 5)) +
theme_ridges(grid = FALSE) +
labs(x = "Transferred Pseudotime", y = "Cell Line",
title = "B. Per Cell Line Pseudotime Ridgeplot",
subtitle = "L1 multimodal | L3-L7 narrow peaks at TCM-TEM boundary") +
theme(plot.title = element_text(size = 12, face = "bold"),
plot.subtitle = element_text(size = 10, colour = "grey40"))
fig6 <- p6a | p6b
print(fig6)

save_fig(fig6, "Fig6_Density_and_Ridgeplot", w = 16, h = 7)
✓ Fig6_Density_and_Ridgeplot [PNG + PDF]
save_fig(p6a, "Fig6A_Density_Overall", w = 8, h = 6)
✓ Fig6A_Density_Overall [PNG + PDF]
save_fig(p6b, "Fig6B_Ridgeplot_PerLine", w = 8, h = 6)
✓ Fig6B_Ridgeplot_PerLine [PNG + PDF]
p6a_v2 <- ggplot(
query_df %>% filter(!is.na(pseudotime)),
aes(x = pseudotime)
) +
geom_density(fill = "#c0392b", colour = "#c0392b", alpha = 0.4, linewidth = 0.9) +
geom_vline(
data = REF_MEDIANS_EFFECTOR,
aes(xintercept = med_pt, colour = state),
linetype = "dashed", linewidth = 0.7
) +
geom_text(
data = REF_MEDIANS_EFFECTOR,
aes(x = med_pt, y = Inf,
label = gsub("CD4 ", "", as.character(state))),
inherit.aes = FALSE,
angle = 90, hjust = 1.1, vjust = -0.3, size = 2.8, colour = "grey30"
) +
scale_colour_manual(
values = STATE_COLORS[names(STATE_COLORS) != "Treg"],
name = "Reference\nstate median"
) +
scale_x_continuous(limits = c(0, 26), breaks = seq(0, 25, 5)) +
theme_classic() +
labs(
x = "Transferred Pseudotime",
y = "Density",
title = "A. Sézary Pseudotime Distribution — All Lines Combined",
subtitle = sprintf(
"Effector axis medians: Naive=%.2f | TCM=%.2f | TEM=%.2f | Temra=%.2f\nTreg line omitted — overlaps TCM; Treg-like assigned by label not pseudotime",
naive_med, tcm_med, tem_med, temra_med)
) +
theme(
plot.title = element_text(size = 12, face = "bold"),
plot.subtitle = element_text(size = 9, colour = "grey40"),
legend.position = "right"
)
print(p6a_v2)

save_fig(p6a_v2, "Fig6Av2_Density_NoTreg", w = 8, h = 6)
✓ Fig6Av2_Density_NoTreg [PNG + PDF]
14. Figure 8 — Violin:
Transferred Pseudotime per Label
fig8 <- ggplot(
query_df %>%
filter(!is.na(pseudotime), !is.na(label)) %>%
mutate(label = factor(label, levels = STATE_ORDER)),
aes(label, pseudotime, fill = label)
) +
geom_violin(scale = "width", trim = FALSE, alpha = 0.85, colour = "white") +
geom_boxplot(width = 0.07, fill = "white", colour = "grey40",
outlier.size = 0.4, outlier.alpha = 0.3) +
geom_hline(data = REF_MEDIANS, aes(yintercept = med_pt),
linetype = "dotted", colour = "grey55", linewidth = 0.6) +
# Annotations driven entirely from REF_MEDIANS — no hard-coded y values
geom_text(
data = REF_MEDIANS,
aes(x = 0.55,
y = med_pt,
label = sprintf("Ref: %s (%.2f)",
gsub("CD4 ", "", as.character(state)), med_pt)),
inherit.aes = FALSE,
hjust = 0, size = 2.8, colour = "grey40"
) +
scale_fill_manual(values = STATE_COLORS, guide = "none") +
scale_y_continuous(breaks = seq(0, 25, 5)) +
theme_classic() +
labs(
x = "Transferred Azimuth l2 Label",
y = "Transferred Pseudotime",
title = "Figure 8 — Transferred Pseudotime per Label (All Cell Lines)",
subtitle = "CD4 Naive internal control at PT~4 | TCM broad distribution | TEM at terminal PT~25"
) +
theme(plot.title = element_text(size = 13, face = "bold"),
plot.subtitle = element_text(size = 10, colour = "grey40"),
axis.text.x = element_text(size = 10, face = "bold"))
print(fig8)

save_fig(fig8, "Fig8_Violin_Pseudotime_per_Label", w = 12, h = 6)
✓ Fig8_Violin_Pseudotime_per_Label [PNG + PDF]
# For TEM and Temra: median=24.84 for both (Temra n=10, all at same PT).
# Use actual reference max values to separate the lines visually:
# TEM max = 25.00 (from diagnostic)
# Temra max = 24.84 (all 10 cells identical)
# Better approach: show TEM median and Temra median separately but
# acknowledge in subtitle they are nearly identical.
# Override: use mean instead of median for TEM/Temra to separate lines
REF_MEDIANS_EFFECTOR_PLOT <- REF_MEDIANS_EFFECTOR %>%
mutate(med_pt = case_when(
state == "CD4 TEM" ~ 23.962, # mean from diagnostic (median=24.84 same as Temra)
state == "CD4 Temra/CTL" ~ 24.840, # all 10 cells identical
TRUE ~ med_pt
),
label_text = case_when(
state == "CD4 TEM" ~ sprintf("Ref: TEM (mean=23.96)"),
state == "CD4 Temra/CTL" ~ sprintf("Ref: Temra (24.84, n=10)"),
state == "CD4 Naive" ~ sprintf("Ref: Naive (%.2f)", med_pt),
state == "CD4 TCM" ~ sprintf("Ref: TCM (%.2f)", med_pt),
TRUE ~ as.character(state)
))
fig8v2 <- ggplot(
query_df %>%
filter(!is.na(pseudotime), !is.na(label)) %>%
mutate(label = factor(label, levels = STATE_ORDER)), # drop=FALSE keeps Temra axis
aes(label, pseudotime, fill = label)
) +
geom_violin(scale = "width", trim = FALSE, alpha = 0.85, colour = "white") +
geom_boxplot(width = 0.07, fill = "white", colour = "grey40",
outlier.size = 0.4, outlier.alpha = 0.3) +
geom_hline(
data = REF_MEDIANS_EFFECTOR_PLOT,
aes(yintercept = med_pt),
linetype = "dotted", colour = "grey55", linewidth = 0.6
) +
geom_text(
data = REF_MEDIANS_EFFECTOR_PLOT,
aes(x = 0.55,
y = med_pt,
label = label_text),
inherit.aes = FALSE,
hjust = 0, size = 2.8, colour = "grey40"
) +
scale_fill_manual(values = STATE_COLORS, na.value = "grey80", guide = "none",
drop = FALSE) +
scale_x_discrete(drop = FALSE) + # ← forces CD4 Temra/CTL to appear
scale_y_continuous(breaks = seq(0, 25, 5)) +
theme_classic() +
labs(
x = "Transferred Azimuth l2 Label",
y = "Transferred Pseudotime",
title = "Figure 8 — Transferred Pseudotime per Label (All Cell Lines)",
subtitle = sprintf(
"Effector axis: Naive=%.2f | TCM=%.2f | TEM~24.84 | Temra~24.84 (n=10, identical)\nCD4 Temra/CTL: no Sézary cells received this label — consistent with TCM arrest phenotype\nTreg line omitted — overlaps TCM; Treg-like assigned by label",
naive_med, tcm_med)
) +
theme(
plot.title = element_text(size = 13, face = "bold"),
plot.subtitle = element_text(size = 9, colour = "grey40"),
axis.text.x = element_text(size = 10, face = "bold")
)
print(fig8v2)

save_fig(fig8v2, "Fig8v2_Violin_NoTreg", w = 12, h = 6)
✓ Fig8v2_Violin_NoTreg [PNG + PDF]
fig8v2 <- ggplot(
query_df %>%
filter(!is.na(pseudotime), !is.na(label)) %>%
mutate(label = factor(label, levels = STATE_ORDER)),
aes(label, pseudotime, fill = label)
) +
geom_violin(scale = "width", trim = FALSE, alpha = 0.85, colour = "white") +
geom_boxplot(width = 0.07, fill = "white", colour = "grey40",
outlier.size = 0.4, outlier.alpha = 0.3) +
geom_hline(
data = REF_MEDIANS_EFFECTOR,
aes(yintercept = med_pt),
linetype = "dotted", colour = "grey55", linewidth = 0.6
) +
geom_text(
data = REF_MEDIANS_EFFECTOR,
aes(x = 0.55,
y = med_pt,
label = sprintf("Ref: %s (%.2f)",
gsub("CD4 ", "", as.character(state)), med_pt)),
inherit.aes = FALSE,
hjust = 0, size = 2.8, colour = "grey40"
) +
scale_fill_manual(values = STATE_COLORS, guide = "none") +
scale_y_continuous(breaks = seq(0, 25, 5)) +
theme_classic() +
labs(
x = "Transferred Azimuth l2 Label",
y = "Transferred Pseudotime",
title = "Figure 8 — Transferred Pseudotime per Label (All Cell Lines)",
subtitle = sprintf(
"Effector axis reference lines: Naive=%.2f | TCM=%.2f | TEM=%.2f | Temra=%.2f\nTreg line omitted — Treg (PT=%.2f) overlaps TCM; Treg-like violin shown as biological confirmation",
naive_med, tcm_med, tem_med, temra_med, treg_med)
) +
theme(
plot.title = element_text(size = 13, face = "bold"),
plot.subtitle = element_text(size = 9, colour = "grey40"),
axis.text.x = element_text(size = 10, face = "bold")
)
print(fig8v2)

save_fig(fig8v2, "Fig8v2_Violin_NoTreg", w = 12, h = 6)
✓ Fig8v2_Violin_NoTreg [PNG + PDF]
15. Figure 9 —
Cross-Table: Label vs Pseudotime Bin (PRIMARY RESULT)
cross_df <- query_df %>%
filter(!is.na(label), !is.na(pseudotime_bin)) %>%
mutate(label = factor(label, levels = STATE_ORDER)) %>%
count(label, pseudotime_bin) %>%
group_by(label) %>%
mutate(pct = 100 * n / sum(n)) %>%
ungroup()
tcm_discordant <- cross_df %>%
filter(label == "CD4 TCM",
pseudotime_bin %in% c("TEM-like", "Temra-like")) %>%
summarise(pct = sum(pct)) %>%
pull(pct)
fig9 <- ggplot(cross_df, aes(pseudotime_bin, pct, fill = pseudotime_bin)) +
geom_col(width = 0.7) +
geom_text(aes(label = sprintf("%.1f%%", pct)),
vjust = -0.3, size = 3.5, fontface = "bold") +
scale_fill_manual(values = BIN_COLORS, guide = "none") +
scale_y_continuous(expand = c(0, 0), limits = c(0, 115)) +
facet_wrap(~ label, nrow = 1, scales = "free_x") +
theme_classic() +
theme(
strip.text = element_text(face = "bold", size = 11),
strip.background = element_rect(fill = "grey95", colour = "grey60"),
axis.text.x = element_text(size = 9, face = "bold", angle = 30, hjust = 1),
plot.title = element_text(size = 14, face = "bold"),
plot.subtitle = element_text(size = 10, colour = "grey40")
) +
labs(
x = "Pseudotime Bin",
y = "% of Cells with This Label",
title = "Figure 9 — Cross-Table: Transferred Label vs Pseudotime Bin [PRIMARY RESULT]",
subtitle = sprintf(
"TCM-labelled cells: %.1f%% discordant (TEM-like or Temra-like)\nTreg panel: 100%% Treg-like by design",
tcm_discordant)
)
print(fig9)

save_fig(fig9, "Fig9_CrossTable_Label_vs_Bin_PRIMARY", w = 18, h = 7)
✓ Fig9_CrossTable_Label_vs_Bin_PRIMARY [PNG + PDF]
16. Supplementary
Figures
Supp S1 — Per Cell
Line Pseudotime Density (Faceted)
suppS1 <- ggplot(
query_df %>% filter(!is.na(pseudotime), !is.na(cell_line)),
aes(x = pseudotime, fill = cell_line, colour = cell_line)
) +
geom_density(alpha = 0.35, linewidth = 0.8) +
geom_vline(data = REF_MEDIANS, aes(xintercept = med_pt),
colour = "grey45", linetype = "dashed", linewidth = 0.5) +
scale_fill_brewer(palette = "Set2", guide = "none") +
scale_colour_brewer(palette = "Set2", guide = "none") +
scale_x_continuous(limits = c(0, 26), breaks = seq(0, 25, 5)) +
facet_wrap(~ cell_line, nrow = 2) +
theme_classic() +
theme(strip.text = element_text(face = "bold"),
plot.title = element_text(size = 12, face = "bold"),
plot.subtitle = element_text(size = 9, colour = "grey40")) +
labs(x = "Transferred Pseudotime", y = "Density",
title = "Supp S1 — Per Cell Line Pseudotime Density",
subtitle = "Grey dashed lines = data-derived reference state medians")
print(suppS1)

save_fig(suppS1, "SuppS1_Density_PerLine_Facet", w = 12, h = 7)
✓ SuppS1_Density_PerLine_Facet [PNG + PDF]
Supp S2 — Ridgeplot
Standalone
suppS2 <- p6b +
ggtitle(
"Supp S2 — Per Cell Line Pseudotime Ridgeplot",
subtitle = sprintf(
"Bin boundaries: Naive|TCM=%.2f | TCM|TEM=%.2f | TEM|Temra=%.2f",
BIN_NAIVE_TCM, BIN_TCM_TEM, BIN_TEM_TEMRA)
)
print(suppS2)

save_fig(suppS2, "SuppS2_Ridgeplot_PerLine", w = 10, h = 7)
✓ SuppS2_Ridgeplot_PerLine [PNG + PDF]
Supp S3 — Violin per
Label x Cell Line (Faceted)
suppS3 <- ggplot(
query_df %>%
filter(!is.na(label), !is.na(cell_line), !is.na(pseudotime)) %>%
mutate(label = factor(label, levels = STATE_ORDER)),
aes(cell_line, pseudotime, fill = cell_line)
) +
geom_violin(scale = "width", trim = FALSE, alpha = 0.8, colour = "white") +
geom_boxplot(width = 0.07, fill = "white", colour = "grey40",
outlier.size = 0.2, outlier.alpha = 0.3) +
scale_fill_brewer(palette = "Set2", guide = "none") +
scale_y_continuous(breaks = seq(0, 25, 5)) +
facet_wrap(~ label, nrow = 1) +
theme_classic() +
theme(
strip.text = element_text(face = "bold", size = 10),
strip.background = element_rect(fill = "grey95", colour = "grey60"),
axis.text.x = element_text(size = 9, face = "bold", angle = 30, hjust = 1),
plot.title = element_text(size = 12, face = "bold"),
plot.subtitle = element_text(size = 9, colour = "grey40")
) +
labs(x = "Cell Line", y = "Transferred Pseudotime",
title = "Supp S3 — Violin: Pseudotime per Label x Cell Line",
subtitle = "Complements Fig 9 — shows within-state per-line heterogeneity")
print(suppS3)

save_fig(suppS3, "SuppS3_Violin_Label_x_Line", w = 16, h = 10)
✓ SuppS3_Violin_Label_x_Line [PNG + PDF]
Supp S4 — Pseudotime
Bin Bar Chart with Full Percentages
suppS4 <- ggplot(bin_df, aes(cell_line, pct, fill = pseudotime_bin)) +
geom_col(width = 0.7) +
geom_text(data = bin_df %>% filter(pct > 2),
aes(label = sprintf("%.1f%%", pct)),
position = position_stack(vjust = 0.5),
size = 3.5, colour = "white", fontface = "bold") +
scale_fill_manual(values = BIN_COLORS, name = "Pseudotime bin") +
scale_y_continuous(expand = c(0, 0), limits = c(0, 101)) +
theme_classic() +
labs(
x = "Cell Line",
y = "% Cells",
title = "Supp S4 — Pseudotime Bin Composition per Cell Line",
subtitle = sprintf(
"Bin boundaries: Naive|TCM=%.2f | TCM|TEM=%.2f | TEM|Temra=%.2f | Treg=label-based",
BIN_NAIVE_TCM, BIN_TCM_TEM, BIN_TEM_TEMRA)
) +
theme(plot.title = element_text(size = 12, face = "bold"),
plot.subtitle = element_text(size = 9, colour = "grey40"),
axis.text.x = element_text(size = 11, face = "bold"))
print(suppS4)

save_fig(suppS4, "SuppS4_Bins_BarChart_Detailed", w = 14, h = 6)
✓ SuppS4_Bins_BarChart_Detailed [PNG + PDF]
18. 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
[7] LC_PAPER=C.UTF-8 LC_NAME=C LC_ADDRESS=C LC_TELEPHONE=C LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C
time zone: Europe/Paris
tzcode source: system (glibc)
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] kableExtra_1.4.0 knitr_1.51 ggridges_0.5.7 RColorBrewer_1.1-3 scales_1.4.0 patchwork_1.3.2 forcats_1.0.1
[8] tidyr_1.3.2 dplyr_1.2.0 ggplot2_4.0.2 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 farver_2.1.2 rmarkdown_2.30
[7] ragg_1.5.0 vctrs_0.7.1 ROCR_1.0-12 spatstat.explore_3.7-0 htmltools_0.5.9 sass_0.4.10
[13] sctransform_0.4.3 parallelly_1.46.1 KernSmooth_2.23-26 bslib_0.10.0 htmlwidgets_1.6.4 ica_1.0-3
[19] plyr_1.8.9 plotly_4.12.0 zoo_1.8-15 cachem_1.1.0 igraph_2.2.2 mime_0.13
[25] lifecycle_1.0.5 pkgconfig_2.0.3 Matrix_1.7-4 R6_2.6.1 fastmap_1.2.0 fitdistrplus_1.2-6
[31] future_1.69.0 shiny_1.12.1 digest_0.6.39 S4Vectors_0.48.0 tensor_1.5.1 RSpectra_0.16-2
[37] irlba_2.3.7 textshaping_1.0.4 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 withr_3.0.2 S7_0.2.1 fastDummies_1.7.5
[49] MASS_7.3-65 tools_4.5.2 lmtest_0.9-40 otel_0.2.0 httpuv_1.6.16 future.apply_1.20.1
[55] goftest_1.2-3 glue_1.8.0 nlme_3.1-168 promises_1.5.0 grid_4.5.2 Rtsne_0.17
[61] cluster_2.1.8.2 reshape2_1.4.5 generics_0.1.4 gtable_0.3.6 spatstat.data_3.1-9 data.table_1.18.2.1
[67] xml2_1.5.2 XVector_0.50.0 BiocGenerics_0.56.0 spatstat.geom_3.7-0 RcppAnnoy_0.0.23 ggrepel_0.9.6
[73] RANN_2.6.2 pillar_1.11.1 stringr_1.6.0 spam_2.11-3 RcppHNSW_0.6.0 later_1.4.6
[79] splines_4.5.2 lattice_0.22-9 survival_3.8-6 deldir_2.0-4 tidyselect_1.2.1 miniUI_0.1.2
[85] pbapply_1.7-4 gridExtra_2.3 IRanges_2.44.0 svglite_2.2.2 scattermore_1.2 stats4_4.5.2
[91] xfun_0.56 Biobase_2.70.0 matrixStats_1.5.0 stringi_1.8.7 lazyeval_0.2.2 yaml_2.3.12
[97] evaluate_1.0.5 codetools_0.2-20 tibble_3.3.1 cli_3.6.5 uwot_0.2.4 xtable_1.8-4
[103] reticulate_1.45.0 systemfonts_1.3.1 jquerylib_0.1.4 dichromat_2.0-0.1 Rcpp_1.1.1 globals_0.19.0
[109] spatstat.random_3.4-4 png_0.1-8 spatstat.univar_3.1-6 parallel_4.5.2 dotCall64_1.2 listenv_0.10.0
[115] viridisLite_0.4.3 purrr_1.2.1 rlang_1.1.7 cowplot_1.2.0
LS0tCnRpdGxlOiAiU8OpemFyeSBTeW5kcm9tZSDigJQgUHNldWRvdGltZSBUcmFqZWN0b3J5IEZpZ3VyZXMiCnN1YnRpdGxlOiAiQ0Q0KyBUIENlbGwgUmVmZXJlbmNlIFByb2plY3Rpb24gfCBTdGF0ZS1BbmNob3JlZCBQc2V1ZG90aW1lIEJpbnMgfCBQTkcgKyBQREYgb3V0cHV0IgphdXRob3I6ICJOYXNpciBNYWhtb29kIEFiYmFzaSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogZmFsc2UKICAgIHRoZW1lOiBqb3VybmFsCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBlY2hvICAgICAgPSBUUlVFLAogIG1lc3NhZ2UgICA9IEZBTFNFLAogIHdhcm5pbmcgICA9IEZBTFNFLAogIGZpZy5hbGlnbiA9ICJjZW50ZXIiLAogIGRwaSAgICAgICA9IDE1MAopCmBgYAoKLS0tCgojIE92ZXJ2aWV3CgpUaGlzIHNjcmlwdCByZWdlbmVyYXRlcyAqKmFsbCBtYW51c2NyaXB0IGZpZ3VyZXMqKiBmcm9tIHRoZSBzYXZlZCBwcm9qZWN0aW9uIG9iamVjdC4KVGhlIHJlZmVyZW5jZSBvYmplY3QgaXMgbG9hZGVkICoqc29sZWx5KiogdG8gZXh0cmFjdCBVTUFQIGNvb3JkaW5hdGVzIGZvciB0aGUgZ3JleSBiYWNrZ3JvdW5kLgoKIyMgT2JqZWN0cyByZXF1aXJlZAoKfCBPYmplY3QgfCBQYXRoIHwgUm9sZSB8CnwtLS0tLS0tLXwtLS0tLS18LS0tLS0tfAp8IGByZWZlcmVuY2VfaW50ZWdyYXRlZGAgfCBgLi4vLi4vMS1GaW5hbF9DdXN0b21fTVNUX01vbm9jbGUzX1RyYWplY3RvcnlfYW5kX21hcHBpbmcvMS1DdXN0b21fTVNUL09iamVjdHMvY2Q0X3JlZl9kdWFsX3RyYWplY3RvcnkucmRzYCB8ICoqVU1BUCBiYWNrZ3JvdW5kIG9ubHkqKiDigJQgZ3JleSByZWZlcmVuY2UgZG90cyB8CnwgYG1hcHBlZF9NYWxpZ25hbnRDRDRUYCB8IGByZXN1bHRzL01hbGlnbmFudENENFRfTW9ub2NsZTNfcHJvamVjdGlvbi9NYWxpZ25hbnRDRDRUX21hcHBlZF9tb25vY2xlM19wc2V1ZG90aW1lX25vUHJvbGlmX3JlZi5SZHNgIHwgKipBbGwgYmlvbG9neSoqIOKAlCBwc2V1ZG90aW1lLCBsYWJlbHMsIGJpbnMsIGNvbG91ciBzY2FsZXMgfAoKIyMgS2V5IGRlc2lnbiBkZWNpc2lvbnMKCnwgSXRlbSB8IFNvdXJjZSB8CnwtLS0tLS18LS0tLS0tLS18CnwgUHNldWRvdGltZSBjb2xvdXItc2NhbGUgbGltaXRzIChgUFRfTElNSVRTYCkgfCBgbWFwcGVkX01hbGlnbmFudENENFQkcHJlZGljdGVkLnBzZXVkb3RpbWVgIHwKfCBCaW4gYm91bmRhcmllcyB8IE1pZHBvaW50cyBiZXR3ZWVuICoqYWN0dWFsKiogcmVmZXJlbmNlIHN0YXRlIG1lZGlhbnMg4oCUIGNvbXB1dGVkIGF0IHJ1bnRpbWUgZnJvbSBgcmVmX2JnYCB8CnwgU3RhdGUgbWVkaWFucyAoYFJFRl9NRURJQU5TYCkgfCBDb21wdXRlZCBhdCBydW50aW1lIGZyb20gYHJlZl9iZ2Ag4oCUICoqbmV2ZXIgaGFyZC1jb2RlZCoqIHwKfCBBbGwgYmFyIGNoYXJ0cywgdmlvbGlucywgZGVuc2l0eSBwbG90cyB8IGBtYXBwZWRfTWFsaWduYW50Q0Q0VGAgb25seSB8CgojIyBQYW5lbCBCIGZpeAoKUHJldmlvdXNseSBjYWxsZWQgYEZlYXR1cmVQbG90KHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCAuLi4pYCB3aXRob3V0IGBsaW1pdHNgLApwcm9kdWNpbmcgYSBzcHVyaW91cyAxLjDigJMyLjAgY29sb3VyIHNjYWxlLiBGaXhlZDogUGFuZWwgQiBwbG90cyBTw6l6YXJ5IGNlbGxzCmNvbG91cmVkIGJ5IGBwcmVkaWN0ZWQucHNldWRvdGltZWAgd2l0aCBgbGltaXRzID0gUFRfTElNSVRTYCAoY29ycmVjdCAw4oCTMjUgc2NhbGUpLgoKIyMgQmluIGRlc2lnbgoKQmlucyBhcmUgYW5jaG9yZWQgdG8gKiphY3R1YWwgcmVmZXJlbmNlIHN0YXRlIG1lZGlhbnMqKiBjb21wdXRlZCBmcm9tIGByZWZfYmdgLgpCb3VuZGFyaWVzID0gbWlkcG9pbnQgYmV0d2VlbiBhZGphY2VudCBzdGF0ZSBtZWRpYW5zIChiaW9sb2d5LXByaW5jaXBsZWQsIG5vdCBhcmJpdHJhcnkpLgpUcmVnLWxpa2UgYmluIGlzIGFzc2lnbmVkIGJ5IEF6aW11dGggbGFiZWwgKFRyZWcgaXMgYSBicmFuY2gsIG5vdCBhIGxpbmVhciBwb3NpdGlvbikuCgotLS0KCiMgMS4gU2V0dXAgJiBMaWJyYXJpZXMKCmBgYHtyIGxpYnJhcmllc30Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKICBsaWJyYXJ5KFNldXJhdCkKICBsaWJyYXJ5KGdncGxvdDIpCiAgbGlicmFyeShkcGx5cikKICBsaWJyYXJ5KHRpZHlyKQogIGxpYnJhcnkoZm9yY2F0cykKICBsaWJyYXJ5KHBhdGNod29yaykKICBsaWJyYXJ5KHNjYWxlcykKICBsaWJyYXJ5KFJDb2xvckJyZXdlcikKICBsaWJyYXJ5KGdncmlkZ2VzKQogIGxpYnJhcnkoa25pdHIpCiAgbGlicmFyeShrYWJsZUV4dHJhKQp9KQoKZGlyLmNyZWF0ZSgiRmlndXJlcy9QTkciLCByZWN1cnNpdmUgPSBUUlVFLCBzaG93V2FybmluZ3MgPSBGQUxTRSkKZGlyLmNyZWF0ZSgiRmlndXJlcy9QREYiLCByZWN1cnNpdmUgPSBUUlVFLCBzaG93V2FybmluZ3MgPSBGQUxTRSkKCnNhdmVfZmlnIDwtIGZ1bmN0aW9uKHAsIG5hbWUsIHcgPSAxMCwgaCA9IDgpIHsKICBnZ3NhdmUoZmlsZS5wYXRoKCJGaWd1cmVzL1BORyIsIHBhc3RlMChuYW1lLCAiLnBuZyIpKSwKICAgICAgICAgcCwgd2lkdGggPSB3LCBoZWlnaHQgPSBoLCBkcGkgPSAzMDAsIGJnID0gIndoaXRlIikKICBnZ3NhdmUoZmlsZS5wYXRoKCJGaWd1cmVzL1BERiIsIHBhc3RlMChuYW1lLCAiLnBkZiIpKSwKICAgICAgICAgcCwgd2lkdGggPSB3LCBoZWlnaHQgPSBoLCB1c2VEaW5nYmF0cyA9IEZBTFNFKQogIGludmlzaWJsZShjYXQoc3ByaW50ZigiICBcdTI3MTMgICVzICBbUE5HICsgUERGXVxuIiwgbmFtZSkpKQp9CgpTVEFURV9DT0xPUlMgPC0gYygKICAiQ0Q0IE5haXZlIiAgICAgPSAiIzQ0NzJDNCIsCiAgIkNENCBUQ00iICAgICAgID0gIiM3MEFENDciLAogICJDRDQgVEVNIiAgICAgICA9ICIjRUQ3RDMxIiwKICAiQ0Q0IFRlbXJhL0NUTCIgPSAiI0MwMDAwMCIsCiAgIlRyZWciICAgICAgICAgID0gIiM3MDMwQTAiCikKCkJJTl9DT0xPUlMgPC0gYygKICAiTmFpdmUtbGlrZSIgID0gIiM0NDcyQzQiLAogICJUQ00tbGlrZSIgICAgPSAiIzcwQUQ0NyIsCiAgIlRFTS1saWtlIiAgICA9ICIjRUQ3RDMxIiwKICAiVGVtcmEtbGlrZSIgID0gIiNDMDAwMDAiLAogICJUcmVnLWxpa2UiICAgPSAiIzcwMzBBMCIKKQoKU1RBVEVfT1JERVIgPC0gYygiQ0Q0IE5haXZlIiwgIkNENCBUQ00iLCAiQ0Q0IFRFTSIsICJDRDQgVGVtcmEvQ1RMIiwgIlRyZWciKQpCSU5fT1JERVIgICA8LSBjKCJOYWl2ZS1saWtlIiwgIlRDTS1saWtlIiwgIlRFTS1saWtlIiwgIlRlbXJhLWxpa2UiLCAiVHJlZy1saWtlIikKTElORV9PUkRFUiAgPC0gcGFzdGUwKCJMIiwgMTo3KQoKY2F0KCJTZXR1cCBjb21wbGV0ZS5cbiIpCmBgYAoKLS0tCgojIDIuIExvYWQgJiBWYWxpZGF0ZSBPYmplY3RzCgpgYGB7ciBsb2FkLW9iamVjdHN9CnJlZl9wYXRoIDwtIHBhc3RlMCgKICAiLi4vLi4vMS1GaW5hbF9DdXN0b21fTVNUX01vbm9jbGUzX1RyYWplY3RvcnlfYW5kX21hcHBpbmcvIiwKICAiMS1DdXN0b21fTVNUL09iamVjdHMvY2Q0X3JlZl9kdWFsX3RyYWplY3RvcnkucmRzIgopCnJlZmVyZW5jZV9pbnRlZ3JhdGVkIDwtIHJlYWRSRFMocmVmX3BhdGgpCmNhdCgiUmVmZXJlbmNlIGxvYWRlZDoiLCBuY29sKHJlZmVyZW5jZV9pbnRlZ3JhdGVkKSwgImNlbGxzXG4iKQoKc3RvcGlmbm90KAogICJ1bWFwIHJlZHVjdGlvbiBtaXNzaW5nIGZyb20gcmVmZXJlbmNlIiA9CiAgICAidW1hcCIgJWluJSBuYW1lcyhyZWZlcmVuY2VfaW50ZWdyYXRlZEByZWR1Y3Rpb25zKQopCgpvYmpfcGF0aCA8LSBwYXN0ZTAoCiAgIi4uL3Jlc3VsdHMvTWFsaWduYW50Q0Q0VF9Nb25vY2xlM19wcm9qZWN0aW9uLyIsCiAgIk1hbGlnbmFudENENFRfbWFwcGVkX21vbm9jbGUzX3BzZXVkb3RpbWVfbm9Qcm9saWZfcmVmLlJkcyIKKQptYXBwZWRfTWFsaWduYW50Q0Q0VCA8LSByZWFkUkRTKG9ial9wYXRoKQpjYXQoIlF1ZXJ5IGxvYWRlZDogICAgIiwgbmNvbChtYXBwZWRfTWFsaWduYW50Q0Q0VCksICJjZWxsc1xuIikKCnN0b3BpZm5vdCgKICAicmVmLnVtYXAgcmVkdWN0aW9uIG1pc3Npbmcg4oCUIHJlLXJ1biBNYXBRdWVyeSIgPQogICAgInJlZi51bWFwIiAlaW4lIG5hbWVzKG1hcHBlZF9NYWxpZ25hbnRDRDRUQHJlZHVjdGlvbnMpLAogICJwcmVkaWN0ZWQucHNldWRvdGltZSBjb2x1bW4gbWlzc2luZyIgPQogICAgInByZWRpY3RlZC5wc2V1ZG90aW1lIiAlaW4lIGNvbG5hbWVzKG1hcHBlZF9NYWxpZ25hbnRDRDRUQG1ldGEuZGF0YSksCiAgInByZWRpY3RlZC5wcmVkaWN0ZWQuY2VsbHR5cGUubDIgY29sdW1uIG1pc3NpbmciID0KICAgICJwcmVkaWN0ZWQucHJlZGljdGVkLmNlbGx0eXBlLmwyIiAlaW4lIGNvbG5hbWVzKG1hcHBlZF9NYWxpZ25hbnRDRDRUQG1ldGEuZGF0YSkKKQoKaWYgKCEiY2VsbF9saW5lIiAlaW4lIGNvbG5hbWVzKG1hcHBlZF9NYWxpZ25hbnRDRDRUQG1ldGEuZGF0YSkpIHsKICBpZiAoIm9yaWcuaWRlbnQiICVpbiUgY29sbmFtZXMobWFwcGVkX01hbGlnbmFudENENFRAbWV0YS5kYXRhKSkgewogICAgbWFwcGVkX01hbGlnbmFudENENFQkY2VsbF9saW5lIDwtIG1hcHBlZF9NYWxpZ25hbnRDRDRUJG9yaWcuaWRlbnQKICAgIGNhdCgiTk9URTogdXNpbmcgb3JpZy5pZGVudCBhcyBjZWxsX2xpbmVcbiIpCiAgfSBlbHNlIHsKICAgIHN0b3AoIkNhbm5vdCBmaW5kIGNlbGxfbGluZSBvciBvcmlnLmlkZW50IGluIG1ldGFkYXRhIikKICB9Cn0KCmNhdCgiXG5wcmVkaWN0ZWQucHNldWRvdGltZSBzdW1tYXJ5IChleHBlY3QgTWlufjAsIE1heH4yNSk6XG4iKQpwcmludChzdW1tYXJ5KG1hcHBlZF9NYWxpZ25hbnRDRDRUJHByZWRpY3RlZC5wc2V1ZG90aW1lKSkKY2F0KCJcblRyYW5zZmVycmVkIGxhYmVsIGRpc3RyaWJ1dGlvbjpcbiIpCnByaW50KHNvcnQodGFibGUobWFwcGVkX01hbGlnbmFudENENFQkcHJlZGljdGVkLnByZWRpY3RlZC5jZWxsdHlwZS5sMiwKICAgICAgICAgICAgICAgICB1c2VOQSA9ICJpZmFueSIpLCBkZWNyZWFzaW5nID0gVFJVRSkpCmNhdCgiXG5DZWxsIGxpbmUgc2l6ZXM6XG4iKQpwcmludChzb3J0KHRhYmxlKG1hcHBlZF9NYWxpZ25hbnRDRDRUJGNlbGxfbGluZSwgdXNlTkEgPSAiaWZhbnkiKSkpCmBgYAoKLS0tCgojIDMuIEJ1aWxkIFJlZmVyZW5jZSBCYWNrZ3JvdW5kIChgcmVmX2JnYCkKCmBgYHtyIGJ1aWxkLXJlZi1iZ30KIyByZWZfYmcgc2VydmVzIHR3byBwdXJwb3NlczoKIyAgIDEuIEdyZXkgYmFja2dyb3VuZCBkb3RzIGluIGFsbCBwcm9qZWN0aW9uIFVNQVBzCiMgICAyLiBTb3VyY2UgZm9yIGNvbXB1dGluZyBhY3R1YWwgcmVmZXJlbmNlIHN0YXRlIG1lZGlhbnMgKFJFRl9NRURJQU5TKQpyZWZfYmcgPC0gZGF0YS5mcmFtZSgKICBFbWJlZGRpbmdzKHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCAidW1hcCIpLAogIHN0YXRlICAgICAgPSByZWZlcmVuY2VfaW50ZWdyYXRlZCRwcmVkaWN0ZWQuY2VsbHR5cGUubDIsCiAgcHNldWRvdGltZSA9IHJlZmVyZW5jZV9pbnRlZ3JhdGVkJG1vbm9jbGUzX3BzZXVkb3RpbWUsCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFCikKY29sbmFtZXMocmVmX2JnKVsxOjJdIDwtIGMoIlVNQVBfMSIsICJVTUFQXzIiKQpyZWZfYmckc3RhdGUgPC0gZmFjdG9yKHJlZl9iZyRzdGF0ZSwgbGV2ZWxzID0gU1RBVEVfT1JERVIpCgpjYXQoIlJlZmVyZW5jZSBtb25vY2xlM19wc2V1ZG90aW1lIChzaG91bGQgYmUgMC0yNSk6XG4iKQpwcmludChzdW1tYXJ5KHJlZl9iZyRwc2V1ZG90aW1lKSkKCnJlZl9iZ19wbG90IDwtIHJlZl9iZ1tzYW1wbGUobnJvdyhyZWZfYmcpKSwgXQpjYXQoc3ByaW50ZigiXG5yZWZfYmcgcmVhZHk6ICVkIHJlZmVyZW5jZSBjZWxsc1xuIiwgbnJvdyhyZWZfYmcpKSkKYGBgCgotLS0KCiMgNC4gQ29tcHV0ZSBSZWZlcmVuY2UgU3RhdGUgTWVkaWFucyAmIEJpbiBCb3VuZGFyaWVzCgpgYGB7ciBjb21wdXRlLW1lZGlhbnMtYmluc30KIyDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZAKIyBSRUZfTUVESUFOUyBjb21wdXRlZCBhdCBydW50aW1lIGZyb20gYWN0dWFsIHJlZl9iZyDigJQgTk9UIGhhcmQtY29kZWQuCiMKIyBEaWFnbm9zdGljIGNvbmZpcm1lZCB0aGVzZSBhY3R1YWwgdmFsdWVzOgojICAgQ0Q0IE5haXZlICAgICBtZWRpYW4gPSAgMy4yOTMKIyAgIENENCBUQ00gICAgICAgbWVkaWFuID0gIDkuMzc3ICAod2FzIGhhcmQtY29kZWQgYXMgMTMuMzYg4oCUIFdST05HKQojICAgQ0Q0IFRFTSAgICAgICBtZWRpYW4gPSAyNC44NDAKIyAgIENENCBUZW1yYS9DVEwgbWVkaWFuID0gMjQuODQwICAob25seSAxMCBjZWxscykKIyAgIFRyZWcgICAgICAgICAgbWVkaWFuID0gMTEuMTUwICAod2FzIGhhcmQtY29kZWQgYXMgMTguNzUg4oCUIGFib3ZlIFRyZWcgbWF4IG9mIDE3LjQwLCBXUk9ORykKIwojIEJpbiBib3VuZGFyaWVzIGRlcml2ZWQgYXMgbWlkcG9pbnRzIGJldHdlZW4gYWRqYWNlbnQgc3RhdGUgbWVkaWFucy4KIyDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZAKCnJlZl9zdGF0ZV9tZWRpYW5zIDwtIHJlZl9iZyAlPiUKICBmaWx0ZXIoIWlzLm5hKHBzZXVkb3RpbWUpLCAhaXMubmEoc3RhdGUpKSAlPiUKICBncm91cF9ieShzdGF0ZSkgJT4lCiAgc3VtbWFyaXNlKAogICAgbiAgICAgID0gbigpLAogICAgbWVkX3B0ID0gcm91bmQobWVkaWFuKHBzZXVkb3RpbWUsIG5hLnJtID0gVFJVRSksIDMpLAogICAgLmdyb3VwcyA9ICJkcm9wIgogICkgJT4lCiAgYXJyYW5nZShtZWRfcHQpCgpjYXQoIj09PSBSZWZlcmVuY2Ugc3RhdGUgbWVkaWFucyAoZGF0YS1kZXJpdmVkKSA9PT1cbiIpCnByaW50KHJlZl9zdGF0ZV9tZWRpYW5zKQoKZ2V0X21lZCA8LSBmdW5jdGlvbihzKSB7CiAgdiA8LSByZWZfc3RhdGVfbWVkaWFucyRtZWRfcHRbcmVmX3N0YXRlX21lZGlhbnMkc3RhdGUgPT0gc10KICBpZiAobGVuZ3RoKHYpID09IDApIHN0b3AocGFzdGUoIlN0YXRlIG5vdCBmb3VuZCBpbiByZWZfYmc6IiwgcykpCiAgdgp9CgpuYWl2ZV9tZWQgIDwtIGdldF9tZWQoIkNENCBOYWl2ZSIpCnRjbV9tZWQgICAgPC0gZ2V0X21lZCgiQ0Q0IFRDTSIpCnRlbV9tZWQgICAgPC0gZ2V0X21lZCgiQ0Q0IFRFTSIpCnRlbXJhX21lZCAgPC0gZ2V0X21lZCgiQ0Q0IFRlbXJhL0NUTCIpCnRyZWdfbWVkICAgPC0gZ2V0X21lZCgiVHJlZyIpCgpCSU5fTkFJVkVfVENNICA8LSByb3VuZCgobmFpdmVfbWVkICsgdGNtX21lZCkgIC8gMiwgMykKQklOX1RDTV9URU0gICAgPC0gcm91bmQoKHRjbV9tZWQgICArIHRlbV9tZWQpICAgLyAyLCAzKQpCSU5fVEVNX1RFTVJBICA8LSByb3VuZCgodGVtX21lZCAgICsgdGVtcmFfbWVkKSAvIDIsIDMpCgpjYXQoIlxuPT09IEJpbiBib3VuZGFyaWVzIChtaWRwb2ludHMgYmV0d2VlbiBhZGphY2VudCBzdGF0ZSBtZWRpYW5zKSA9PT1cbiIpCmNhdChzcHJpbnRmKCIgIE5haXZlIHwgVENNICAgOiAlLjNmXG4iLCBCSU5fTkFJVkVfVENNKSkKY2F0KHNwcmludGYoIiAgVENNICAgfCBURU0gICA6ICUuM2ZcbiIsIEJJTl9UQ01fVEVNKSkKY2F0KHNwcmludGYoIiAgVEVNICAgfCBUZW1yYSA6ICUuM2ZcbiIsIEJJTl9URU1fVEVNUkEpKQpjYXQoc3ByaW50ZigiICBUcmVnICAgICAgICAgICA6IGxhYmVsLWJhc2VkIChicmFuY2ggbG9naWMpXG4iKSkKCmlmIChhYnModGVtX21lZCAtIHRlbXJhX21lZCkgPCAwLjUpIHsKICBjYXQoIlxuTk9URTogVEVNIGFuZCBUZW1yYSBtZWRpYW5zIGFyZSB2ZXJ5IGNsb3NlIChuPTEwIFRlbXJhIGNlbGxzIGluIHJlZmVyZW5jZSkuXG4iKQogIGNhdCgiICAgICAgVGVtcmEtbGlrZSBiaW4gd2lsbCBiZSBuZWdsaWdpYmxlIOKAlCBiaW9sb2dpY2FsbHkgZXhwZWN0ZWQuXG4iKQp9CgpSRUZfTUVESUFOUyA8LSBkYXRhLmZyYW1lKAogIHN0YXRlICA9IGZhY3RvcihTVEFURV9PUkRFUiwgbGV2ZWxzID0gU1RBVEVfT1JERVIpLAogIG1lZF9wdCA9IGMobmFpdmVfbWVkLCB0Y21fbWVkLCB0ZW1fbWVkLCB0ZW1yYV9tZWQsIHRyZWdfbWVkKQopCgpjYXQoIlxuPT09IFJFRl9NRURJQU5TICh1c2VkIGZvciByZWZlcmVuY2UgbGluZXMgaW4gYWxsIGZpZ3VyZXMpID09PVxuIikKcHJpbnQoUkVGX01FRElBTlMpCmBgYAoKYGBge3J9CiMg4pSA4pSAIFJFRl9NRURJQU5TX0VGRkVDVE9SOiBUcmVnIGV4Y2x1ZGVkIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAojIFRyZWcgKG1lZGlhbiBQVD0xMS4xNSkgYW5kIFRDTSAobWVkaWFuIFBUPTkuMzgpIG92ZXJsYXAgZW50aXJlbHkgaW4KIyBwc2V1ZG90aW1lIHNwYWNlIOKAlCBib3RoIHN0YXRlcyBzaGFyZSB0aGUgTmFpdmXihpJUQ00gZ3JhcGggc2VnbWVudC4KIyBTaG93aW5nIGEgVHJlZyBsaW5lIGF0IFBUPTExLjE1IGltcGxpZXMgYSBwc2V1ZG90aW1lIGJvdW5kYXJ5IHRoYXQgZG9lcwojIG5vdCBleGlzdCBhbmQgbWlzbGVhZHMgaW50ZXJwcmV0YXRpb24uIFRyZWctbGlrZSBjZWxscyBhcmUgYXNzaWduZWQgYnkKIyB0cmFuc2ZlcnJlZCBBemltdXRoIGxhYmVsIChLTk4pLCBub3QgYnkgcHNldWRvdGltZSBwb3NpdGlvbi4KUkVGX01FRElBTlNfRUZGRUNUT1IgPC0gUkVGX01FRElBTlMgJT4lCiAgZmlsdGVyKHN0YXRlICE9ICJUcmVnIikKCkxJTkVUWVBFX0VGRkVDVE9SIDwtIGMoCiAgIkNENCBOYWl2ZSIgICAgID0gImRvdHRlZCIsCiAgIkNENCBUQ00iICAgICAgID0gImRhc2hlZCIsCiAgIkNENCBURU0iICAgICAgID0gImxvbmdkYXNoIiwKICAiQ0Q0IFRlbXJhL0NUTCIgPSAic29saWQiCikKCmNhdCgiPT09IFJFRl9NRURJQU5TX0VGRkVDVE9SIChUcmVnIGV4Y2x1ZGVkKSA9PT1cbiIpCnByaW50KFJFRl9NRURJQU5TX0VGRkVDVE9SKQpgYGAKCgojIDUuIEFzc2lnbiBQc2V1ZG90aW1lIEJpbnMKCmBgYHtyIGFzc2lnbi1iaW5zfQphc3NpZ25fYmluIDwtIGZ1bmN0aW9uKHB0LCBsYmwpIHsKICBpZiAoaXNUUlVFKGdyZXBsKCJUcmVnIiwgbGJsLCBpZ25vcmUuY2FzZSA9IFRSVUUpKSkgcmV0dXJuKCJUcmVnLWxpa2UiKQogIGlmIChpcy5uYShwdCkpICAgICAgICAgICAgIHJldHVybihOQV9jaGFyYWN0ZXJfKQogIGlmIChwdCA8PSBCSU5fTkFJVkVfVENNKSAgIHJldHVybigiTmFpdmUtbGlrZSIpCiAgaWYgKHB0IDw9IEJJTl9UQ01fVEVNKSAgICAgcmV0dXJuKCJUQ00tbGlrZSIpCiAgaWYgKHB0IDw9IEJJTl9URU1fVEVNUkEpICAgcmV0dXJuKCJURU0tbGlrZSIpCiAgcmV0dXJuKCJUZW1yYS1saWtlIikKfQoKbWFwcGVkX01hbGlnbmFudENENFQkcHNldWRvdGltZV9iaW4gPC0gZmFjdG9yKAogIG1hcHBseShhc3NpZ25fYmluLAogICAgICAgICBwdCAgPSBtYXBwZWRfTWFsaWduYW50Q0Q0VCRwcmVkaWN0ZWQucHNldWRvdGltZSwKICAgICAgICAgbGJsID0gbWFwcGVkX01hbGlnbmFudENENFQkcHJlZGljdGVkLnByZWRpY3RlZC5jZWxsdHlwZS5sMiksCiAgbGV2ZWxzID0gQklOX09SREVSCikKCmNhdCgiUHNldWRvdGltZSBiaW4gZGlzdHJpYnV0aW9uIChhbGwgY2VsbHMpOlxuIikKcHJpbnQodGFibGUobWFwcGVkX01hbGlnbmFudENENFQkcHNldWRvdGltZV9iaW4sIHVzZU5BID0gImlmYW55IikpCmNhdCgiXG5Qc2V1ZG90aW1lIGJpbiBwZXIgY2VsbCBsaW5lOlxuIikKcHJpbnQodGFibGUobWFwcGVkX01hbGlnbmFudENENFQkY2VsbF9saW5lLAogICAgICAgICAgICBtYXBwZWRfTWFsaWduYW50Q0Q0VCRwc2V1ZG90aW1lX2JpbiwgdXNlTkEgPSAiaWZhbnkiKSkKYGBgCgotLS0KCiMgNi4gQnVpbGQgU2hhcmVkIERhdGEgRnJhbWVzCgpgYGB7ciBidWlsZC1kYXRhZnJhbWVzfQpxdWVyeV9kZiA8LSBkYXRhLmZyYW1lKAogIEVtYmVkZGluZ3MobWFwcGVkX01hbGlnbmFudENENFQsICJyZWYudW1hcCIpLAogIHBzZXVkb3RpbWUgICAgID0gbWFwcGVkX01hbGlnbmFudENENFQkcHJlZGljdGVkLnBzZXVkb3RpbWUsCiAgY2VsbF9saW5lICAgICAgPSBmYWN0b3IobWFwcGVkX01hbGlnbmFudENENFQkY2VsbF9saW5lLCBsZXZlbHMgPSBMSU5FX09SREVSKSwKICBsYWJlbCAgICAgICAgICA9IG1hcHBlZF9NYWxpZ25hbnRDRDRUJHByZWRpY3RlZC5wcmVkaWN0ZWQuY2VsbHR5cGUubDIsCiAgcHNldWRvdGltZV9iaW4gPSBtYXBwZWRfTWFsaWduYW50Q0Q0VCRwc2V1ZG90aW1lX2JpbiwKICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UKKQpjb2xuYW1lcyhxdWVyeV9kZilbMToyXSA8LSBjKCJVTUFQXzEiLCAiVU1BUF8yIikKClBUX0xJTUlUUyA8LSByYW5nZShxdWVyeV9kZiRwc2V1ZG90aW1lLCBuYS5ybSA9IFRSVUUpCmNhdChzcHJpbnRmKCJQc2V1ZG90aW1lIGNvbG91ciBsaW1pdHM6ICUuM2YgdG8gJS4zZlxuIiwgUFRfTElNSVRTWzFdLCBQVF9MSU1JVFNbMl0pKQoKbGFiZWxfZGYgPC0gcXVlcnlfZGYgJT4lCiAgZmlsdGVyKCFpcy5uYShsYWJlbCksICFpcy5uYShjZWxsX2xpbmUpKSAlPiUKICBjb3VudChjZWxsX2xpbmUsIGxhYmVsKSAlPiUKICBncm91cF9ieShjZWxsX2xpbmUpICU+JQogIG11dGF0ZShwY3QgPSAxMDAgKiBuIC8gc3VtKG4pKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKGxhYmVsID0gZmFjdG9yKGxhYmVsLCBsZXZlbHMgPSBTVEFURV9PUkRFUikpCgpiaW5fZGYgPC0gcXVlcnlfZGYgJT4lCiAgZmlsdGVyKCFpcy5uYShwc2V1ZG90aW1lX2JpbiksICFpcy5uYShjZWxsX2xpbmUpKSAlPiUKICBjb3VudChjZWxsX2xpbmUsIHBzZXVkb3RpbWVfYmluKSAlPiUKICBncm91cF9ieShjZWxsX2xpbmUpICU+JQogIG11dGF0ZShwY3QgPSAxMDAgKiBuIC8gc3VtKG4pKSAlPiUKICB1bmdyb3VwKCkKCmNhdCgiRGF0YSBmcmFtZXMgcmVhZHkuXG4iKQpgYGAKCi0tLQoKIyA3LiBGaWd1cmUgNyDigJQgRm91ci1QYW5lbCBTdW1tYXJ5CgpgYGB7ciBmaWc3LWZvdXItcGFuZWwsIGZpZy53aWR0aD0xOCwgZmlnLmhlaWdodD0xNH0KCmJnX2xheWVyIDwtIGdlb21fcG9pbnQoCiAgZGF0YSA9IHJlZl9iZ19wbG90LCBhZXMoeCA9IFVNQVBfMSwgeSA9IFVNQVBfMiksCiAgY29sb3VyID0gImdyZXk2OCIsIHNpemUgPSAwLjI1LCBhbHBoYSA9IDAuNDUsIGluaGVyaXQuYWVzID0gRkFMU0UKKQoKcDdhIDwtIGdncGxvdChxdWVyeV9kZltzYW1wbGUobnJvdyhxdWVyeV9kZikpLCBdLAogICAgICAgICAgICAgIGFlcyhVTUFQXzEsIFVNQVBfMiwgY29sb3VyID0gZmFjdG9yKGxhYmVsLCBsZXZlbHMgPSBTVEFURV9PUkRFUikpKSArCiAgYmdfbGF5ZXIgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDAuMzUsIGFscGhhID0gMC43KSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBTVEFURV9DT0xPUlMsIG5hbWUgPSAiVHJhbnNmZXJyZWRcbkxhYmVsIiwKICAgICAgICAgICAgICAgICAgICAgIG5hLnZhbHVlID0gImdyZXk4MCIpICsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDMsIGFscGhhID0gMSkpKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBsYWJzKHggPSAiVU1BUC0xIiwgeSA9ICJVTUFQLTIiLAogICAgICAgdGl0bGUgPSAiQS4gU8OpemFyeSBDZWxscyDigJQgVHJhbnNmZXJyZWQgQ0Q0IFQgQ2VsbCBMYWJlbHMiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSkKCnA3YiA8LSBnZ3Bsb3QocXVlcnlfZGZbb3JkZXIocXVlcnlfZGYkcHNldWRvdGltZSwgbmEubGFzdCA9IEZBTFNFKSwgXSwKICAgICAgICAgICAgICBhZXMoVU1BUF8xLCBVTUFQXzIsIGNvbG91ciA9IHBzZXVkb3RpbWUpKSArCiAgYmdfbGF5ZXIgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDAuMzUsIGFscGhhID0gMC44KSArCiAgc2NhbGVfY29sb3VyX2dyYWRpZW50bigKICAgIGNvbG91cnMgID0gYygibGlnaHRibHVlIiwgInllbGxvdyIsICJyZWQiKSwKICAgIG5hbWUgICAgID0gIlBzZXVkb3RpbWUiLAogICAgbGltaXRzICAgPSBQVF9MSU1JVFMsCiAgICBuYS52YWx1ZSA9ICJncmV5ODUiCiAgKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBsYWJzKHggPSAiVU1BUC0xIiwgeSA9ICJVTUFQLTIiLAogICAgICAgdGl0bGUgPSAiQi4gU8OpemFyeSBDZWxscyDigJQgVHJhbnNmZXJyZWQgUHNldWRvdGltZSAgW0ZJWEVEXSIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpKQoKcDdjIDwtIGdncGxvdChxdWVyeV9kZltzYW1wbGUobnJvdyhxdWVyeV9kZikpLCBdLAogICAgICAgICAgICAgIGFlcyhVTUFQXzEsIFVNQVBfMiwgY29sb3VyID0gcHNldWRvdGltZV9iaW4pKSArCiAgYmdfbGF5ZXIgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDAuMzUsIGFscGhhID0gMC43KSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBCSU5fQ09MT1JTLCBuYW1lID0gIlBzZXVkb3RpbWVcbkJpbiIsCiAgICAgICAgICAgICAgICAgICAgICBuYS52YWx1ZSA9ICJncmV5ODAiKSArCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzLCBhbHBoYSA9IDEpKSkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgbGFicyh4ID0gIlVNQVAtMSIsIHkgPSAiVU1BUC0yIiwKICAgICAgIHRpdGxlID0gIkMuIFPDqXphcnkgQ2VsbHMg4oCUIFBzZXVkb3RpbWUgQmluIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIikpCgpwN2QgPC0gZ2dwbG90KGxhYmVsX2RmLCBhZXMoY2VsbF9saW5lLCBwY3QsIGZpbGwgPSBsYWJlbCkpICsKICBnZW9tX2NvbCh3aWR0aCA9IDAuNzUpICsKICBnZW9tX3RleHQoZGF0YSA9IGxhYmVsX2RmICU+JSBmaWx0ZXIocGN0ID4gMyksCiAgICAgICAgICAgIGFlcyhsYWJlbCA9IHNwcmludGYoIiUuMWYlJSIsIHBjdCkpLAogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSwKICAgICAgICAgICAgc2l6ZSA9IDMsIGNvbG91ciA9ICJ3aGl0ZSIsIGZvbnRmYWNlID0gImJvbGQiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gU1RBVEVfQ09MT1JTLCBuYW1lID0gIkxhYmVsIikgKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsIDApLCBsaW1pdHMgPSBjKDAsIDEwMSkpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGxhYnMoeCA9ICJDZWxsIExpbmUiLCB5ID0gIiUgQ2VsbHMiLAogICAgICAgdGl0bGUgPSAiRC4gVHJhbnNmZXJyZWQgTGFiZWwgcGVyIENlbGwgTGluZSIpICsKICB0aGVtZShwbG90LnRpdGxlICA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsIGZhY2UgPSAiYm9sZCIpKQoKZmlnNyA8LSAocDdhIHwgcDdiKSAvIChwN2MgfCBwN2QpCnByaW50KGZpZzcpCnNhdmVfZmlnKGZpZzcsICJGaWc3X0ZvdXJQYW5lbF9TdW1tYXJ5X0ZJWEVEIiwgICAgICAgdyA9IDE4LCBoID0gMTQpCnNhdmVfZmlnKHA3YSwgICJGaWc3QV9UcmFuc2ZlcnJlZF9MYWJlbHMiLCAgICAgICAgICAgdyA9IDksICBoID0gNykKc2F2ZV9maWcocDdiLCAgIkZpZzdCX1RyYW5zZmVycmVkX1BzZXVkb3RpbWVfRklYRUQiLCB3ID0gOSwgIGggPSA3KQpzYXZlX2ZpZyhwN2MsICAiRmlnN0NfUHNldWRvdGltZV9CaW5zX1VNQVAiLCAgICAgICAgIHcgPSA5LCAgaCA9IDcpCnNhdmVfZmlnKHA3ZCwgICJGaWc3RF9MYWJlbF9CYXJDaGFydF9wZXJfTGluZSIsICAgICAgdyA9IDksICBoID0gNykKYGBgCgotLS0KCiMgOC4gRmlndXJlIDEg4oCUIFBzZXVkb3RpbWUgVmlvbGluIHBlciBDZWxsIExpbmUKCmBgYHtyIGZpZzEtdmlvbGluLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9Nn0KCmZpZzEgPC0gZ2dwbG90KAogICAgcXVlcnlfZGYgJT4lIGZpbHRlcighaXMubmEocHNldWRvdGltZSksICFpcy5uYShjZWxsX2xpbmUpKSwKICAgIGFlcyhjZWxsX2xpbmUsIHBzZXVkb3RpbWUsIGZpbGwgPSBjZWxsX2xpbmUpCiAgKSArCiAgZ2VvbV92aW9saW4oc2NhbGUgPSAid2lkdGgiLCB0cmltID0gRkFMU0UsIGFscGhhID0gMC44NSwgY29sb3VyID0gIndoaXRlIikgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMDYsIGZpbGwgPSAid2hpdGUiLCBjb2xvdXIgPSAiZ3JleTQwIiwKICAgICAgICAgICAgICAgb3V0bGllci5zaXplID0gMC4zLCBvdXRsaWVyLmFscGhhID0gMC4zKSArCiAgZ2VvbV9obGluZShkYXRhID0gUkVGX01FRElBTlMsCiAgICAgICAgICAgICBhZXMoeWludGVyY2VwdCA9IG1lZF9wdCwgY29sb3VyID0gc3RhdGUsIGxpbmV0eXBlID0gc3RhdGUpLAogICAgICAgICAgICAgbGluZXdpZHRoID0gMC43LCBhbHBoYSA9IDAuOSkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIsIGd1aWRlID0gIm5vbmUiKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBTVEFURV9DT0xPUlMsIG5hbWUgPSAiUmVmZXJlbmNlXG5tZWRpYW4iKSArCiAgc2NhbGVfbGluZXR5cGVfbWFudWFsKAogICAgdmFsdWVzID0gYygiQ0Q0IE5haXZlIiA9ICJkb3R0ZWQiLCAiQ0Q0IFRDTSIgPSAiZGFzaGVkIiwKICAgICAgICAgICAgICAgIkNENCBURU0iID0gImxvbmdkYXNoIiwgIkNENCBUZW1yYS9DVEwiID0gInNvbGlkIiwKICAgICAgICAgICAgICAgIlRyZWciID0gInR3b2Rhc2giKSwKICAgIG5hbWUgPSAiUmVmZXJlbmNlXG5tZWRpYW4iCiAgKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAyNSwgNSkpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGxhYnMoCiAgICB4ICAgICAgICA9ICJDZWxsIExpbmUiLAogICAgeSAgICAgICAgPSAiVHJhbnNmZXJyZWQgUHNldWRvdGltZSIsCiAgICB0aXRsZSAgICA9ICJGaWd1cmUgMSDigJQgUHNldWRvdGltZSBEaXN0cmlidXRpb24gcGVyIFPDqXphcnkgQ2VsbCBMaW5lIiwKICAgIHN1YnRpdGxlID0gc3ByaW50ZigKICAgICAgIlJlZmVyZW5jZSBtZWRpYW5zOiBOYWl2ZT0lLjJmIHwgVENNPSUuMmYgfCBUcmVnPSUuMmYgfCBURU09JS4yZiB8IFRlbXJhPSUuMmYiLAogICAgICBuYWl2ZV9tZWQsIHRjbV9tZWQsIHRyZWdfbWVkLCB0ZW1fbWVkLCB0ZW1yYV9tZWQpCiAgKSArCiAgdGhlbWUocGxvdC50aXRsZSAgICA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksICBjb2xvdXIgPSAiZ3JleTQwIiksCiAgICAgICAgYXhpcy50ZXh0LnggICA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEsIGZhY2UgPSAiYm9sZCIpKQoKcHJpbnQoZmlnMSkKc2F2ZV9maWcoZmlnMSwgIkZpZzFfUHNldWRvdGltZV9WaW9saW5fcGVyX0xpbmUiLCB3ID0gMTIsIGggPSA2KQpgYGAKCmBgYHtyICwgZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTd9CmZpZzF2MiA8LSBnZ3Bsb3QoCiAgICBxdWVyeV9kZiAlPiUgZmlsdGVyKCFpcy5uYShwc2V1ZG90aW1lKSwgIWlzLm5hKGNlbGxfbGluZSkpLAogICAgYWVzKGNlbGxfbGluZSwgcHNldWRvdGltZSwgZmlsbCA9IGNlbGxfbGluZSkKICApICsKICBnZW9tX3Zpb2xpbihzY2FsZSA9ICJ3aWR0aCIsIHRyaW0gPSBGQUxTRSwgYWxwaGEgPSAwLjg1LCBjb2xvdXIgPSAid2hpdGUiKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4wNiwgZmlsbCA9ICJ3aGl0ZSIsIGNvbG91ciA9ICJncmV5NDAiLAogICAgICAgICAgICAgICBvdXRsaWVyLnNpemUgPSAwLjMsIG91dGxpZXIuYWxwaGEgPSAwLjMpICsKICBnZW9tX2hsaW5lKAogICAgZGF0YSAgICAgID0gUkVGX01FRElBTlNfRUZGRUNUT1IsCiAgICBhZXMoeWludGVyY2VwdCA9IG1lZF9wdCwgY29sb3VyID0gc3RhdGUsIGxpbmV0eXBlID0gc3RhdGUpLAogICAgbGluZXdpZHRoID0gMC43LCBhbHBoYSA9IDAuOQogICkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIsIGd1aWRlID0gIm5vbmUiKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCgKICAgIHZhbHVlcyA9IFNUQVRFX0NPTE9SU1tuYW1lcyhTVEFURV9DT0xPUlMpICE9ICJUcmVnIl0sCiAgICBuYW1lICAgPSAiUmVmZXJlbmNlXG5tZWRpYW4iCiAgKSArCiAgc2NhbGVfbGluZXR5cGVfbWFudWFsKAogICAgdmFsdWVzID0gTElORVRZUEVfRUZGRUNUT1IsCiAgICBuYW1lICAgPSAiUmVmZXJlbmNlXG5tZWRpYW4iCiAgKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAyNSwgNSkpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGxhYnMoCiAgICB4ICAgICAgICA9ICJDZWxsIExpbmUiLAogICAgeSAgICAgICAgPSAiVHJhbnNmZXJyZWQgUHNldWRvdGltZSIsCiAgICB0aXRsZSAgICA9ICJGaWd1cmUgMSDigJQgUHNldWRvdGltZSBEaXN0cmlidXRpb24gcGVyIFPDqXphcnkgQ2VsbCBMaW5lIiwKICAgIHN1YnRpdGxlID0gc3ByaW50ZigKICAgICAgIkVmZmVjdG9yIGF4aXMgbWVkaWFuczogTmFpdmU9JS4yZiB8IFRDTT0lLjJmIHwgVEVNPSUuMmYgfCBUZW1yYT0lLjJmXG5UcmVnIGxpbmUgb21pdHRlZCDigJQgVHJlZyAoUFQ9JS4yZikgb3ZlcmxhcHMgVENNIChQVD0lLjJmKTsgVHJlZy1saWtlIGFzc2lnbmVkIGJ5IGxhYmVsIiwKICAgICAgbmFpdmVfbWVkLCB0Y21fbWVkLCB0ZW1fbWVkLCB0ZW1yYV9tZWQsIHRyZWdfbWVkLCB0Y21fbWVkKQogICkgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSAgICA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMsIGZhY2UgPSAiYm9sZCIpLAogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSwgIGNvbG91ciA9ICJncmV5NDAiKSwKICAgIGF4aXMudGV4dC54ICAgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExLCBmYWNlID0gImJvbGQiKQogICkKCnByaW50KGZpZzF2MikKc2F2ZV9maWcoZmlnMXYyLCAiRmlnMXYyX1BzZXVkb3RpbWVfVmlvbGluX05vVHJlZyIsIHcgPSAxMiwgaCA9IDYpCmBgYAoKCi0tLQoKIyA5LiBGaWd1cmUgMiDigJQgVU1BUDogUHNldWRvdGltZSArIExhYmVsIFNpZGUgYnkgU2lkZQoKYGBge3IgZmlnMi11bWFwLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9N30KCnAyYSA8LSBnZ3Bsb3QocXVlcnlfZGZbb3JkZXIocXVlcnlfZGYkcHNldWRvdGltZSwgbmEubGFzdCA9IEZBTFNFKSwgXSwKICAgICAgICAgICAgICBhZXMoVU1BUF8xLCBVTUFQXzIsIGNvbG91ciA9IHBzZXVkb3RpbWUpKSArCiAgZ2VvbV9wb2ludChkYXRhID0gcmVmX2JnX3Bsb3QsIGFlcyhVTUFQXzEsIFVNQVBfMiksCiAgICAgICAgICAgICBjb2xvdXIgPSAiZ3JleTY4Iiwgc2l6ZSA9IDAuMjUsIGFscGhhID0gMC40NSwgaW5oZXJpdC5hZXMgPSBGQUxTRSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDAuMjUsIGFscGhhID0gMC44KSArCiAgc2NhbGVfY29sb3VyX2dyYWRpZW50bigKICAgIGNvbG91cnMgPSBjKCIjMEQwODg3IiwiIzZBMDBBOCIsIiNCMTJBOTAiLCIjRTE2NDYyIiwiI0ZDQTYzNiIsIiNGMEY5MjEiKSwKICAgIG5hbWUgPSAiUHNldWRvdGltZSIsIGxpbWl0cyA9IFBUX0xJTUlUUywgbmEudmFsdWUgPSAiZ3JleTg1IgogICkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgbGFicyh4ID0gIlVNQVAtMSIsIHkgPSAiVU1BUC0yIiwKICAgICAgIHRpdGxlICAgID0gIkEuIFRyYW5zZmVycmVkIHBzZXVkb3RpbWUgZ3JhZGllbnQiLAogICAgICAgc3VidGl0bGUgPSAiR3JleSA9IGhlYWx0aHkgcmVmZXJlbmNlICB8ICBDb2xvdXJlZCA9IFPDqXphcnkgY2VsbHMiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpKQoKcDJiIDwtIGdncGxvdChxdWVyeV9kZltzYW1wbGUobnJvdyhxdWVyeV9kZikpLCBdLAogICAgICAgICAgICAgIGFlcyhVTUFQXzEsIFVNQVBfMiwgY29sb3VyID0gZmFjdG9yKGxhYmVsLCBsZXZlbHMgPSBTVEFURV9PUkRFUikpKSArCiAgZ2VvbV9wb2ludChkYXRhID0gcmVmX2JnX3Bsb3QsIGFlcyhVTUFQXzEsIFVNQVBfMiksCiAgICAgICAgICAgICBjb2xvdXIgPSAiZ3JleTg4Iiwgc2l6ZSA9IDAuMjUsIGFscGhhID0gMC40NSwgaW5oZXJpdC5hZXMgPSBGQUxTRSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDAuMjUsIGFscGhhID0gMC43KSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBTVEFURV9DT0xPUlMsIG5hbWUgPSAiVHJhbnNmZXJyZWRcbmxhYmVsIiwKICAgICAgICAgICAgICAgICAgICAgIG5hLnZhbHVlID0gImdyZXk4MCIpICsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDMsIGFscGhhID0gMSkpKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBsYWJzKHggPSAiVU1BUC0xIiwgeSA9ICJVTUFQLTIiLAogICAgICAgdGl0bGUgICAgPSAiQi4gVHJhbnNmZXJyZWQgbGFiZWwgaWRlbnRpdHkiLAogICAgICAgc3VidGl0bGUgPSAiOTYtOTkuOSUgQ0Q0IFRDTSBhY3Jvc3MgYWxsIHNldmVuIGxpbmVzIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSkKCmZpZzIgPC0gcDJhIHwgcDJiCnByaW50KGZpZzIpCnNhdmVfZmlnKGZpZzIsICJGaWcyX1VNQVBfUHNldWRvdGltZV9hbmRfTGFiZWwiLCB3ID0gMTYsIGggPSA3KQpgYGAKCi0tLQoKIyAxMC4gRmlndXJlIDMg4oCUIExhYmVsIEJhciBDaGFydCArIFBlciBDZWxsIExpbmUgVU1BUCBGYWNldHMKCmBgYHtyIGZpZzMtbGFiZWwtdW1hcCwgZmlnLndpZHRoPTE4LCBmaWcuaGVpZ2h0PTZ9CgpwM2EgPC0gZ2dwbG90KGxhYmVsX2RmLCBhZXMoY2VsbF9saW5lLCBwY3QsIGZpbGwgPSBsYWJlbCkpICsKICBnZW9tX2NvbCh3aWR0aCA9IDAuNzUpICsKICBnZW9tX3RleHQoZGF0YSA9IGxhYmVsX2RmICU+JSBmaWx0ZXIocGN0ID4gNSksCiAgICAgICAgICAgIGFlcyhsYWJlbCA9IHNwcmludGYoIiUuMGYlJSIsIHBjdCkpLAogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSwKICAgICAgICAgICAgc2l6ZSA9IDMsIGNvbG91ciA9ICJ3aGl0ZSIsIGZvbnRmYWNlID0gImJvbGQiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gU1RBVEVfQ09MT1JTLCBuYW1lID0gIkxhYmVsIikgKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsIDApLCBsaW1pdHMgPSBjKDAsIDEwMSkpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGxhYnMoeCA9ICJDZWxsIExpbmUiLCB5ID0gIiUgQ2VsbHMiLCB0aXRsZSA9ICJBLiBUcmFuc2ZlcnJlZCBBemltdXRoIGwyIExhYmVscyIpICsKICB0aGVtZShwbG90LnRpdGxlICA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgZmFjZSA9ICJib2xkIikpCgpwM2IgPC0gZ2dwbG90KAogICAgcXVlcnlfZGYgJT4lIGZpbHRlcighaXMubmEoY2VsbF9saW5lKSkgJT4lIGFycmFuZ2UocHNldWRvdGltZSksCiAgICBhZXMoVU1BUF8xLCBVTUFQXzIsIGNvbG91ciA9IHBzZXVkb3RpbWUpCiAgKSArCiAgZ2VvbV9wb2ludCgKICAgIGRhdGEgPSByZWZfYmdfcGxvdCAlPiUKICAgICAgc2xpY2UocmVwKDE6bigpLCB0aW1lcyA9IGxlbmd0aChsZXZlbHMocXVlcnlfZGYkY2VsbF9saW5lKSkpKSwKICAgIGFlcyhVTUFQXzEsIFVNQVBfMiksIGNvbG91ciA9ICJncmV5ODgiLCBzaXplID0gMC4yLCBhbHBoYSA9IDAuNCwKICAgIGluaGVyaXQuYWVzID0gRkFMU0UKICApICsKICBnZW9tX3BvaW50KHNpemUgPSAwLjIsIGFscGhhID0gMC44KSArCiAgc2NhbGVfY29sb3VyX2dyYWRpZW50bigKICAgIGNvbG91cnMgPSBjKCIjMEQwODg3IiwiIzZBMDBBOCIsIiNCMTJBOTAiLCIjRTE2NDYyIiwiI0ZDQTYzNiIsIiNGMEY5MjEiKSwKICAgIG5hbWUgPSAiUHNldWRvdGltZSIsIGxpbWl0cyA9IFBUX0xJTUlUUywgbmEudmFsdWUgPSAiZ3JleTg1IgogICkgKwogIGZhY2V0X3dyYXAofiBjZWxsX2xpbmUsIG5yb3cgPSAyKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZShzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxMCksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIGF4aXMudGV4dCAgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCkpICsKICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCwKICAgICAgIHRpdGxlID0gIkIuIFBlciBDZWxsIExpbmUgVU1BUCDigJQgUHJvamVjdGVkIFBzZXVkb3RpbWUgIChHcmV5ID0gaGVhbHRoeSByZWZlcmVuY2UpIikKCmZpZzMgPC0gcDNhICsgcDNiICsgcGxvdF9sYXlvdXQod2lkdGhzID0gYygxLCAyKSkKcHJpbnQoZmlnMykKc2F2ZV9maWcoZmlnMywgIkZpZzNfTGFiZWxzX1BlckxpbmVfVU1BUCIsIHcgPSAxOCwgaCA9IDYpCmBgYAoKLS0tCgojIDExLiBGaWd1cmUgNCDigJQgUGVyIENlbGwgTGluZSBGYWNldCBVTUFQIChLZXkgSGV0ZXJvZ2VuZWl0eSBGaWd1cmUpCgpgYGB7ciBmaWc0LWZhY2V0LXVtYXAsIGZpZy53aWR0aD0xOCwgZmlnLmhlaWdodD0xMH0KCmZpZzQgPC0gZ2dwbG90KAogICAgcXVlcnlfZGYgJT4lIGZpbHRlcighaXMubmEoY2VsbF9saW5lKSkgJT4lIGFycmFuZ2UocHNldWRvdGltZSksCiAgICBhZXMoVU1BUF8xLCBVTUFQXzIsIGNvbG91ciA9IHBzZXVkb3RpbWUpCiAgKSArCiAgZ2VvbV9wb2ludCgKICAgIGRhdGEgPSByZWZfYmdfcGxvdCAlPiUKICAgICAgc2xpY2UocmVwKDE6bigpLCB0aW1lcyA9IGxlbmd0aChsZXZlbHMocXVlcnlfZGYkY2VsbF9saW5lKSkpKSwKICAgIGFlcyhVTUFQXzEsIFVNQVBfMiksIGNvbG91ciA9ICJncmV5ODgiLCBzaXplID0gMC4yLCBhbHBoYSA9IDAuNCwKICAgIGluaGVyaXQuYWVzID0gRkFMU0UKICApICsKICBnZW9tX3BvaW50KHNpemUgPSAwLjI1LCBhbHBoYSA9IDAuOCkgKwogIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oCiAgICBjb2xvdXJzID0gYygiIzBEMDg4NyIsIiM2QTAwQTgiLCIjQjEyQTkwIiwiI0UxNjQ2MiIsIiNGQ0E2MzYiLCIjRjBGOTIxIiksCiAgICBuYW1lID0gIlBzZXVkb3RpbWVcbihOYWl2ZS0+VGVtcmEpIiwgbGltaXRzID0gUFRfTElNSVRTLCBuYS52YWx1ZSA9ICJncmV5ODUiCiAgKSArCiAgZmFjZXRfd3JhcCh+IGNlbGxfbGluZSwgbnJvdyA9IDIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKAogICAgc3RyaXAudGV4dCAgICAgICA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTIpLAogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImdyZXk5NSIsIGNvbG91ciA9ICJncmV5NjAiKSwKICAgIHBsb3QudGl0bGUgICAgICAgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBmYWNlID0gImJvbGQiKSwKICAgIHBsb3Quc3VidGl0bGUgICAgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBjb2xvdXIgPSAiZ3JleTQwIiksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksCiAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiCiAgKSArCiAgbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwsCiAgICAgICB0aXRsZSAgICA9ICJGaWd1cmUgNCDigJQgUGVyIENlbGwgTGluZSBGYWNldCBVTUFQOiBEaWZmZXJlbnRpYXRpb24gUG9zaXRpb24iLAogICAgICAgc3VidGl0bGUgPSAiTDEgbW9zdCBoZXRlcm9nZW5lb3VzIChzcGFucyBmdWxsIHRyYWplY3RvcnkpICB8ICBMNiBtb3N0IGFycmVzdGVkICh0aWdodCBUQ00gY2x1c3RlcikiKQoKcHJpbnQoZmlnNCkKc2F2ZV9maWcoZmlnNCwgIkZpZzRfUGVyTGluZV9GYWNldF9VTUFQIiwgdyA9IDE4LCBoID0gMTApCmBgYAoKLS0tCgojIDEyLiBGaWd1cmUgNSDigJQgTGFiZWwgdnMgUHNldWRvdGltZSBCaW5zIEJhciBDaGFydHMKCmBgYHtyIGZpZzUtYmFyY2hhcnRzLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTJ9CgpwNWEgPC0gZ2dwbG90KGxhYmVsX2RmLCBhZXMoY2VsbF9saW5lLCBwY3QsIGZpbGwgPSBsYWJlbCkpICsKICBnZW9tX2NvbCh3aWR0aCA9IDAuNykgKwogIGdlb21fdGV4dChkYXRhID0gbGFiZWxfZGYgJT4lIGZpbHRlcihwY3QgPiAzKSwKICAgICAgICAgICAgYWVzKGxhYmVsID0gc3ByaW50ZigiJS4xZiUlIiwgcGN0KSksCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpLAogICAgICAgICAgICBzaXplID0gMy4yLCBjb2xvdXIgPSAid2hpdGUiLCBmb250ZmFjZSA9ICJib2xkIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IFNUQVRFX0NPTE9SUywgbmFtZSA9ICJMYWJlbCIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLCAwKSwgbGltaXRzID0gYygwLCAxMDEpKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBsYWJzKHggPSBOVUxMLCB5ID0gIiUgQ2VsbHMiLAogICAgICAgdGl0bGUgICAgPSAiQS4gVHJhbnNmZXJyZWQgQXppbXV0aCBsMiBMYWJlbCAoQ2VsbCBvZiBPcmlnaW4pIiwKICAgICAgIHN1YnRpdGxlID0gIjk2LTk5LjklIENENCBUQ00gYWNyb3NzIGFsbCBsaW5lcyDigJQgVENNIG9yaWdpbiBjb25maXJtZWQiKSArCiAgdGhlbWUocGxvdC50aXRsZSAgICA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBjb2xvdXIgPSAiZ3JleTQwIiksCiAgICAgICAgYXhpcy50ZXh0LnggICA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpKQoKcDViIDwtIGdncGxvdChiaW5fZGYsIGFlcyhjZWxsX2xpbmUsIHBjdCwgZmlsbCA9IHBzZXVkb3RpbWVfYmluKSkgKwogIGdlb21fY29sKHdpZHRoID0gMC43KSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBiaW5fZGYgJT4lIGZpbHRlcihwY3QgPiAzKSwKICAgICAgICAgICAgYWVzKGxhYmVsID0gc3ByaW50ZigiJS4xZiUlIiwgcGN0KSksCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpLAogICAgICAgICAgICBzaXplID0gMy4yLCBjb2xvdXIgPSAid2hpdGUiLCBmb250ZmFjZSA9ICJib2xkIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IEJJTl9DT0xPUlMsIG5hbWUgPSAiUHNldWRvdGltZSBiaW4iKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgMCksIGxpbWl0cyA9IGMoMCwgMTAxKSkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgbGFicyh4ID0gIkNlbGwgTGluZSIsIHkgPSAiJSBDZWxscyIsCiAgICAgICB0aXRsZSAgICA9ICJCLiBQc2V1ZG90aW1lIEJpbiBBc3NpZ25tZW50IChEaWZmZXJlbnRpYXRpb24gUG9zaXRpb24pIiwKICAgICAgIHN1YnRpdGxlID0gc3ByaW50ZigKICAgICAgICAgIkJpbiBib3VuZGFyaWVzIOKAlCBOYWl2ZXxUQ006ICUuMmYgIHwgIFRDTXxURU06ICUuMmYgIHwgIFRFTXxUZW1yYTogJS4yZiAgfCAgVHJlZzogbGFiZWwtYmFzZWQiLAogICAgICAgICBCSU5fTkFJVkVfVENNLCBCSU5fVENNX1RFTSwgQklOX1RFTV9URU1SQSkpICsKICB0aGVtZShwbG90LnRpdGxlICAgID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSwgIGNvbG91ciA9ICJncmV5NDAiKSwKICAgICAgICBheGlzLnRleHQueCAgID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMSwgZmFjZSA9ICJib2xkIikpCgpmaWc1IDwtIHA1YSAvIHA1YgpwcmludChmaWc1KQpzYXZlX2ZpZyhmaWc1LCAiRmlnNV9MYWJlbF92c19Qc2V1ZG90aW1lX0JpbnMiLCAgdyA9IDE2LCBoID0gMTIpCnNhdmVfZmlnKHA1YSwgICJGaWc1QV9MYWJlbF9UcmFuc2Zlcl9CYXJDaGFydCIsICB3ID0gMTAsIGggPSA1KQpzYXZlX2ZpZyhwNWIsICAiRmlnNUJfUHNldWRvdGltZV9CaW5zX0JhckNoYXJ0IiwgdyA9IDEwLCBoID0gNSkKYGBgCgotLS0KCiMgMTMuIEZpZ3VyZSA2IOKAlCBQc2V1ZG90aW1lIERlbnNpdHkgKyBSaWRnZXBsb3QKCmBgYHtyIGZpZzYtZGVuc2l0eSwgZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTd9CgpwNmEgPC0gZ2dwbG90KHF1ZXJ5X2RmICU+JSBmaWx0ZXIoIWlzLm5hKHBzZXVkb3RpbWUpKSwgYWVzKHggPSBwc2V1ZG90aW1lKSkgKwogIGdlb21fZGVuc2l0eShmaWxsID0gIiNjMDM5MmIiLCBjb2xvdXIgPSAiI2MwMzkyYiIsIGFscGhhID0gMC40LCBsaW5ld2lkdGggPSAwLjkpICsKICBnZW9tX3ZsaW5lKGRhdGEgPSBSRUZfTUVESUFOUywKICAgICAgICAgICAgIGFlcyh4aW50ZXJjZXB0ID0gbWVkX3B0LCBjb2xvdXIgPSBzdGF0ZSksCiAgICAgICAgICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiLCBsaW5ld2lkdGggPSAwLjcpICsKICBnZW9tX3RleHQoZGF0YSA9IFJFRl9NRURJQU5TLAogICAgICAgICAgICBhZXMoeCA9IG1lZF9wdCwgeSA9IEluZiwKICAgICAgICAgICAgICAgIGxhYmVsID0gZ3N1YigiQ0Q0ICIsICIiLCBhcy5jaGFyYWN0ZXIoc3RhdGUpKSksCiAgICAgICAgICAgIGluaGVyaXQuYWVzID0gRkFMU0UsCiAgICAgICAgICAgIGFuZ2xlID0gOTAsIGhqdXN0ID0gMS4xLCB2anVzdCA9IC0wLjMsIHNpemUgPSAyLjgsIGNvbG91ciA9ICJncmV5MzAiKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBTVEFURV9DT0xPUlMsIG5hbWUgPSAiUmVmZXJlbmNlXG5zdGF0ZSBtZWRpYW4iKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgMjYpLCBicmVha3MgPSBzZXEoMCwgMjUsIDUpKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBsYWJzKAogICAgeCAgICAgICAgPSAiVHJhbnNmZXJyZWQgUHNldWRvdGltZSIsCiAgICB5ICAgICAgICA9ICJEZW5zaXR5IiwKICAgIHRpdGxlICAgID0gIkEuIFPDqXphcnkgUHNldWRvdGltZSBEaXN0cmlidXRpb24g4oCUIEFsbCBMaW5lcyBDb21iaW5lZCIsCiAgICBzdWJ0aXRsZSA9IHNwcmludGYoCiAgICAgICJSZWZlcmVuY2UgbWVkaWFuczogTmFpdmU9JS4yZiB8IFRDTT0lLjJmIHwgVHJlZz0lLjJmIHwgVEVNPSUuMmYgfCBUZW1yYT0lLjJmIiwKICAgICAgbmFpdmVfbWVkLCB0Y21fbWVkLCB0cmVnX21lZCwgdGVtX21lZCwgdGVtcmFfbWVkKQogICkgKwogIHRoZW1lKHBsb3QudGl0bGUgICAgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwKICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LCAgY29sb3VyID0gImdyZXk0MCIpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpCgpwNmIgPC0gZ2dwbG90KAogICAgcXVlcnlfZGYgJT4lIGZpbHRlcighaXMubmEocHNldWRvdGltZSksICFpcy5uYShjZWxsX2xpbmUpKSwKICAgIGFlcyh4ID0gcHNldWRvdGltZSwgeSA9IGZjdF9yZXYoY2VsbF9saW5lKSwgZmlsbCA9IGNlbGxfbGluZSkKICApICsKICBnZW9tX2RlbnNpdHlfcmlkZ2VzKHNjYWxlID0gMC45LCByZWxfbWluX2hlaWdodCA9IDAuMDEsCiAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuODUsIGNvbG91ciA9ICJ3aGl0ZSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKEJJTl9OQUlWRV9UQ00sIEJJTl9UQ01fVEVNLCBCSU5fVEVNX1RFTVJBKSwKICAgICAgICAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG91ciA9ICJncmV5NTAiLCBsaW5ld2lkdGggPSAwLjUpICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSBCSU5fTkFJVkVfVENNLCB5ID0gMC41LCBsYWJlbCA9ICJOYWl2ZXxUQ00iLAogICAgICAgICAgIHNpemUgPSAyLjUsIGhqdXN0ID0gMS4wNSwgY29sb3VyID0gImdyZXk0MCIsIGFuZ2xlID0gOTApICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSBCSU5fVENNX1RFTSwgICB5ID0gMC41LCBsYWJlbCA9ICJUQ018VEVNIiwKICAgICAgICAgICBzaXplID0gMi41LCBoanVzdCA9IDEuMDUsIGNvbG91ciA9ICJncmV5NDAiLCBhbmdsZSA9IDkwKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gQklOX1RFTV9URU1SQSwgeSA9IDAuNSwgbGFiZWwgPSAiVEVNfFRlbXJhIiwKICAgICAgICAgICBzaXplID0gMi41LCBoanVzdCA9IDEuMDUsIGNvbG91ciA9ICJncmV5NDAiLCBhbmdsZSA9IDkwKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIiwgZ3VpZGUgPSAibm9uZSIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAyNiksIGJyZWFrcyA9IHNlcSgwLCAyNSwgNSkpICsKICB0aGVtZV9yaWRnZXMoZ3JpZCA9IEZBTFNFKSArCiAgbGFicyh4ID0gIlRyYW5zZmVycmVkIFBzZXVkb3RpbWUiLCB5ID0gIkNlbGwgTGluZSIsCiAgICAgICB0aXRsZSAgICA9ICJCLiBQZXIgQ2VsbCBMaW5lIFBzZXVkb3RpbWUgUmlkZ2VwbG90IiwKICAgICAgIHN1YnRpdGxlID0gIkwxIG11bHRpbW9kYWwgIHwgIEwzLUw3IG5hcnJvdyBwZWFrcyBhdCBUQ00tVEVNIGJvdW5kYXJ5IikgKwogIHRoZW1lKHBsb3QudGl0bGUgICAgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwKICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgY29sb3VyID0gImdyZXk0MCIpKQoKZmlnNiA8LSBwNmEgfCBwNmIKcHJpbnQoZmlnNikKc2F2ZV9maWcoZmlnNiwgIkZpZzZfRGVuc2l0eV9hbmRfUmlkZ2VwbG90IiwgdyA9IDE2LCBoID0gNykKc2F2ZV9maWcocDZhLCAgIkZpZzZBX0RlbnNpdHlfT3ZlcmFsbCIsICAgICB3ID0gOCwgIGggPSA2KQpzYXZlX2ZpZyhwNmIsICAiRmlnNkJfUmlkZ2VwbG90X1BlckxpbmUiLCAgIHcgPSA4LCAgaCA9IDYpCmBgYAoKCgpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTZ9CnA2YV92MiA8LSBnZ3Bsb3QoCiAgICBxdWVyeV9kZiAlPiUgZmlsdGVyKCFpcy5uYShwc2V1ZG90aW1lKSksCiAgICBhZXMoeCA9IHBzZXVkb3RpbWUpCiAgKSArCiAgZ2VvbV9kZW5zaXR5KGZpbGwgPSAiI2MwMzkyYiIsIGNvbG91ciA9ICIjYzAzOTJiIiwgYWxwaGEgPSAwLjQsIGxpbmV3aWR0aCA9IDAuOSkgKwogIGdlb21fdmxpbmUoCiAgICBkYXRhICAgICA9IFJFRl9NRURJQU5TX0VGRkVDVE9SLAogICAgYWVzKHhpbnRlcmNlcHQgPSBtZWRfcHQsIGNvbG91ciA9IHN0YXRlKSwKICAgIGxpbmV0eXBlID0gImRhc2hlZCIsIGxpbmV3aWR0aCA9IDAuNwogICkgKwogIGdlb21fdGV4dCgKICAgIGRhdGEgICAgICAgID0gUkVGX01FRElBTlNfRUZGRUNUT1IsCiAgICBhZXMoeCA9IG1lZF9wdCwgeSA9IEluZiwKICAgICAgICBsYWJlbCA9IGdzdWIoIkNENCAiLCAiIiwgYXMuY2hhcmFjdGVyKHN0YXRlKSkpLAogICAgaW5oZXJpdC5hZXMgPSBGQUxTRSwKICAgIGFuZ2xlID0gOTAsIGhqdXN0ID0gMS4xLCB2anVzdCA9IC0wLjMsIHNpemUgPSAyLjgsIGNvbG91ciA9ICJncmV5MzAiCiAgKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCgKICAgIHZhbHVlcyA9IFNUQVRFX0NPTE9SU1tuYW1lcyhTVEFURV9DT0xPUlMpICE9ICJUcmVnIl0sCiAgICBuYW1lICAgPSAiUmVmZXJlbmNlXG5zdGF0ZSBtZWRpYW4iCiAgKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgMjYpLCBicmVha3MgPSBzZXEoMCwgMjUsIDUpKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBsYWJzKAogICAgeCAgICAgICAgPSAiVHJhbnNmZXJyZWQgUHNldWRvdGltZSIsCiAgICB5ICAgICAgICA9ICJEZW5zaXR5IiwKICAgIHRpdGxlICAgID0gIkEuIFPDqXphcnkgUHNldWRvdGltZSBEaXN0cmlidXRpb24g4oCUIEFsbCBMaW5lcyBDb21iaW5lZCIsCiAgICBzdWJ0aXRsZSA9IHNwcmludGYoCiAgICAgICJFZmZlY3RvciBheGlzIG1lZGlhbnM6IE5haXZlPSUuMmYgfCBUQ009JS4yZiB8IFRFTT0lLjJmIHwgVGVtcmE9JS4yZlxuVHJlZyBsaW5lIG9taXR0ZWQg4oCUIG92ZXJsYXBzIFRDTTsgVHJlZy1saWtlIGFzc2lnbmVkIGJ5IGxhYmVsIG5vdCBwc2V1ZG90aW1lIiwKICAgICAgbmFpdmVfbWVkLCB0Y21fbWVkLCB0ZW1fbWVkLCB0ZW1yYV9tZWQpCiAgKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlICAgICAgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwKICAgIHBsb3Quc3VidGl0bGUgICA9IGVsZW1lbnRfdGV4dChzaXplID0gOSwgIGNvbG91ciA9ICJncmV5NDAiKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIKICApCgpwcmludChwNmFfdjIpCnNhdmVfZmlnKHA2YV92MiwgIkZpZzZBdjJfRGVuc2l0eV9Ob1RyZWciLCB3ID0gOCwgaCA9IDYpCgpgYGAKCi0tLQoKIyAxNC4gRmlndXJlIDgg4oCUIFZpb2xpbjogVHJhbnNmZXJyZWQgUHNldWRvdGltZSBwZXIgTGFiZWwKCmBgYHtyIGZpZzgtdmlvbGluLXBlci1sYWJlbCwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTZ9CgpmaWc4IDwtIGdncGxvdCgKICAgIHF1ZXJ5X2RmICU+JQogICAgICBmaWx0ZXIoIWlzLm5hKHBzZXVkb3RpbWUpLCAhaXMubmEobGFiZWwpKSAlPiUKICAgICAgbXV0YXRlKGxhYmVsID0gZmFjdG9yKGxhYmVsLCBsZXZlbHMgPSBTVEFURV9PUkRFUikpLAogICAgYWVzKGxhYmVsLCBwc2V1ZG90aW1lLCBmaWxsID0gbGFiZWwpCiAgKSArCiAgZ2VvbV92aW9saW4oc2NhbGUgPSAid2lkdGgiLCB0cmltID0gRkFMU0UsIGFscGhhID0gMC44NSwgY29sb3VyID0gIndoaXRlIikgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMDcsIGZpbGwgPSAid2hpdGUiLCBjb2xvdXIgPSAiZ3JleTQwIiwKICAgICAgICAgICAgICAgb3V0bGllci5zaXplID0gMC40LCBvdXRsaWVyLmFscGhhID0gMC4zKSArCiAgZ2VvbV9obGluZShkYXRhID0gUkVGX01FRElBTlMsIGFlcyh5aW50ZXJjZXB0ID0gbWVkX3B0KSwKICAgICAgICAgICAgIGxpbmV0eXBlID0gImRvdHRlZCIsIGNvbG91ciA9ICJncmV5NTUiLCBsaW5ld2lkdGggPSAwLjYpICsKICAjIEFubm90YXRpb25zIGRyaXZlbiBlbnRpcmVseSBmcm9tIFJFRl9NRURJQU5TIOKAlCBubyBoYXJkLWNvZGVkIHkgdmFsdWVzCiAgZ2VvbV90ZXh0KAogICAgZGF0YSAgICAgICAgPSBSRUZfTUVESUFOUywKICAgIGFlcyh4ICAgICAgID0gMC41NSwKICAgICAgICB5ICAgICAgID0gbWVkX3B0LAogICAgICAgIGxhYmVsICAgPSBzcHJpbnRmKCJSZWY6ICVzICglLjJmKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ3N1YigiQ0Q0ICIsICIiLCBhcy5jaGFyYWN0ZXIoc3RhdGUpKSwgbWVkX3B0KSksCiAgICBpbmhlcml0LmFlcyA9IEZBTFNFLAogICAgaGp1c3QgPSAwLCBzaXplID0gMi44LCBjb2xvdXIgPSAiZ3JleTQwIgogICkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IFNUQVRFX0NPTE9SUywgZ3VpZGUgPSAibm9uZSIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDI1LCA1KSkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgbGFicygKICAgIHggICAgICAgID0gIlRyYW5zZmVycmVkIEF6aW11dGggbDIgTGFiZWwiLAogICAgeSAgICAgICAgPSAiVHJhbnNmZXJyZWQgUHNldWRvdGltZSIsCiAgICB0aXRsZSAgICA9ICJGaWd1cmUgOCDigJQgVHJhbnNmZXJyZWQgUHNldWRvdGltZSBwZXIgTGFiZWwgKEFsbCBDZWxsIExpbmVzKSIsCiAgICBzdWJ0aXRsZSA9ICJDRDQgTmFpdmUgaW50ZXJuYWwgY29udHJvbCBhdCBQVH40ICB8ICBUQ00gYnJvYWQgZGlzdHJpYnV0aW9uICB8ICBURU0gYXQgdGVybWluYWwgUFR+MjUiCiAgKSArCiAgdGhlbWUocGxvdC50aXRsZSAgICA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBjb2xvdXIgPSAiZ3JleTQwIiksCiAgICAgICAgYXhpcy50ZXh0LnggICA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsIGZhY2UgPSAiYm9sZCIpKQoKcHJpbnQoZmlnOCkKc2F2ZV9maWcoZmlnOCwgIkZpZzhfVmlvbGluX1BzZXVkb3RpbWVfcGVyX0xhYmVsIiwgdyA9IDEyLCBoID0gNikKYGBgCgoKCgpgYGB7ciAsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD02fQoKIyBGb3IgVEVNIGFuZCBUZW1yYTogbWVkaWFuPTI0Ljg0IGZvciBib3RoIChUZW1yYSBuPTEwLCBhbGwgYXQgc2FtZSBQVCkuCiMgVXNlIGFjdHVhbCByZWZlcmVuY2UgbWF4IHZhbHVlcyB0byBzZXBhcmF0ZSB0aGUgbGluZXMgdmlzdWFsbHk6CiMgICBURU0gICBtYXggPSAyNS4wMCAgKGZyb20gZGlhZ25vc3RpYykKIyAgIFRlbXJhIG1heCA9IDI0Ljg0ICAoYWxsIDEwIGNlbGxzIGlkZW50aWNhbCkKIyBCZXR0ZXIgYXBwcm9hY2g6IHNob3cgVEVNIG1lZGlhbiBhbmQgVGVtcmEgbWVkaWFuIHNlcGFyYXRlbHkgYnV0CiMgYWNrbm93bGVkZ2UgaW4gc3VidGl0bGUgdGhleSBhcmUgbmVhcmx5IGlkZW50aWNhbC4KCiMgT3ZlcnJpZGU6IHVzZSBtZWFuIGluc3RlYWQgb2YgbWVkaWFuIGZvciBURU0vVGVtcmEgdG8gc2VwYXJhdGUgbGluZXMKUkVGX01FRElBTlNfRUZGRUNUT1JfUExPVCA8LSBSRUZfTUVESUFOU19FRkZFQ1RPUiAlPiUKICBtdXRhdGUobWVkX3B0ID0gY2FzZV93aGVuKAogICAgc3RhdGUgPT0gIkNENCBURU0iICAgICAgIH4gMjMuOTYyLCAgIyBtZWFuIGZyb20gZGlhZ25vc3RpYyAobWVkaWFuPTI0Ljg0IHNhbWUgYXMgVGVtcmEpCiAgICBzdGF0ZSA9PSAiQ0Q0IFRlbXJhL0NUTCIgfiAyNC44NDAsICAjIGFsbCAxMCBjZWxscyBpZGVudGljYWwKICAgIFRSVUUgfiBtZWRfcHQKICApLAogIGxhYmVsX3RleHQgPSBjYXNlX3doZW4oCiAgICBzdGF0ZSA9PSAiQ0Q0IFRFTSIgICAgICAgfiBzcHJpbnRmKCJSZWY6IFRFTSAobWVhbj0yMy45NikiKSwKICAgIHN0YXRlID09ICJDRDQgVGVtcmEvQ1RMIiB+IHNwcmludGYoIlJlZjogVGVtcmEgKDI0Ljg0LCBuPTEwKSIpLAogICAgc3RhdGUgPT0gIkNENCBOYWl2ZSIgICAgIH4gc3ByaW50ZigiUmVmOiBOYWl2ZSAoJS4yZikiLCBtZWRfcHQpLAogICAgc3RhdGUgPT0gIkNENCBUQ00iICAgICAgIH4gc3ByaW50ZigiUmVmOiBUQ00gKCUuMmYpIiwgbWVkX3B0KSwKICAgIFRSVUUgfiBhcy5jaGFyYWN0ZXIoc3RhdGUpCiAgKSkKCmZpZzh2MiA8LSBnZ3Bsb3QoCiAgICBxdWVyeV9kZiAlPiUKICAgICAgZmlsdGVyKCFpcy5uYShwc2V1ZG90aW1lKSwgIWlzLm5hKGxhYmVsKSkgJT4lCiAgICAgIG11dGF0ZShsYWJlbCA9IGZhY3RvcihsYWJlbCwgbGV2ZWxzID0gU1RBVEVfT1JERVIpKSwgICMgZHJvcD1GQUxTRSBrZWVwcyBUZW1yYSBheGlzCiAgICBhZXMobGFiZWwsIHBzZXVkb3RpbWUsIGZpbGwgPSBsYWJlbCkKICApICsKICBnZW9tX3Zpb2xpbihzY2FsZSA9ICJ3aWR0aCIsIHRyaW0gPSBGQUxTRSwgYWxwaGEgPSAwLjg1LCBjb2xvdXIgPSAid2hpdGUiKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4wNywgZmlsbCA9ICJ3aGl0ZSIsIGNvbG91ciA9ICJncmV5NDAiLAogICAgICAgICAgICAgICBvdXRsaWVyLnNpemUgPSAwLjQsIG91dGxpZXIuYWxwaGEgPSAwLjMpICsKICBnZW9tX2hsaW5lKAogICAgZGF0YSAgICAgID0gUkVGX01FRElBTlNfRUZGRUNUT1JfUExPVCwKICAgIGFlcyh5aW50ZXJjZXB0ID0gbWVkX3B0KSwKICAgIGxpbmV0eXBlICA9ICJkb3R0ZWQiLCBjb2xvdXIgPSAiZ3JleTU1IiwgbGluZXdpZHRoID0gMC42CiAgKSArCiAgZ2VvbV90ZXh0KAogICAgZGF0YSAgICAgICAgPSBSRUZfTUVESUFOU19FRkZFQ1RPUl9QTE9ULAogICAgYWVzKHggICAgICAgPSAwLjU1LAogICAgICAgIHkgICAgICAgPSBtZWRfcHQsCiAgICAgICAgbGFiZWwgICA9IGxhYmVsX3RleHQpLAogICAgaW5oZXJpdC5hZXMgPSBGQUxTRSwKICAgIGhqdXN0ID0gMCwgc2l6ZSA9IDIuOCwgY29sb3VyID0gImdyZXk0MCIKICApICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBTVEFURV9DT0xPUlMsIG5hLnZhbHVlID0gImdyZXk4MCIsIGd1aWRlID0gIm5vbmUiLAogICAgICAgICAgICAgICAgICAgIGRyb3AgPSBGQUxTRSkgKwogIHNjYWxlX3hfZGlzY3JldGUoZHJvcCA9IEZBTFNFKSArICAgIyDihpAgZm9yY2VzIENENCBUZW1yYS9DVEwgdG8gYXBwZWFyCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAyNSwgNSkpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGxhYnMoCiAgICB4ICAgICAgICA9ICJUcmFuc2ZlcnJlZCBBemltdXRoIGwyIExhYmVsIiwKICAgIHkgICAgICAgID0gIlRyYW5zZmVycmVkIFBzZXVkb3RpbWUiLAogICAgdGl0bGUgICAgPSAiRmlndXJlIDgg4oCUIFRyYW5zZmVycmVkIFBzZXVkb3RpbWUgcGVyIExhYmVsIChBbGwgQ2VsbCBMaW5lcykiLAogICAgc3VidGl0bGUgPSBzcHJpbnRmKAogICAgICAiRWZmZWN0b3IgYXhpczogTmFpdmU9JS4yZiB8IFRDTT0lLjJmIHwgVEVNfjI0Ljg0IHwgVGVtcmF+MjQuODQgKG49MTAsIGlkZW50aWNhbClcbkNENCBUZW1yYS9DVEw6IG5vIFPDqXphcnkgY2VsbHMgcmVjZWl2ZWQgdGhpcyBsYWJlbCDigJQgY29uc2lzdGVudCB3aXRoIFRDTSBhcnJlc3QgcGhlbm90eXBlXG5UcmVnIGxpbmUgb21pdHRlZCDigJQgb3ZlcmxhcHMgVENNOyBUcmVnLWxpa2UgYXNzaWduZWQgYnkgbGFiZWwiLAogICAgICBuYWl2ZV9tZWQsIHRjbV9tZWQpCiAgKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlICAgID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMywgZmFjZSA9ICJib2xkIiksCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LCAgY29sb3VyID0gImdyZXk0MCIpLAogICAgYXhpcy50ZXh0LnggICA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsIGZhY2UgPSAiYm9sZCIpCiAgKQoKcHJpbnQoZmlnOHYyKQpzYXZlX2ZpZyhmaWc4djIsICJGaWc4djJfVmlvbGluX05vVHJlZyIsIHcgPSAxMiwgaCA9IDYpCgpgYGAKCmBgYHtyICwgZmlnLndpZHRoPTE4LCBmaWcuaGVpZ2h0PTd9CmZpZzh2MiA8LSBnZ3Bsb3QoCiAgICBxdWVyeV9kZiAlPiUKICAgICAgZmlsdGVyKCFpcy5uYShwc2V1ZG90aW1lKSwgIWlzLm5hKGxhYmVsKSkgJT4lCiAgICAgIG11dGF0ZShsYWJlbCA9IGZhY3RvcihsYWJlbCwgbGV2ZWxzID0gU1RBVEVfT1JERVIpKSwKICAgIGFlcyhsYWJlbCwgcHNldWRvdGltZSwgZmlsbCA9IGxhYmVsKQogICkgKwogIGdlb21fdmlvbGluKHNjYWxlID0gIndpZHRoIiwgdHJpbSA9IEZBTFNFLCBhbHBoYSA9IDAuODUsIGNvbG91ciA9ICJ3aGl0ZSIpICsKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjA3LCBmaWxsID0gIndoaXRlIiwgY29sb3VyID0gImdyZXk0MCIsCiAgICAgICAgICAgICAgIG91dGxpZXIuc2l6ZSA9IDAuNCwgb3V0bGllci5hbHBoYSA9IDAuMykgKwogIGdlb21faGxpbmUoCiAgICBkYXRhICAgICAgPSBSRUZfTUVESUFOU19FRkZFQ1RPUiwKICAgIGFlcyh5aW50ZXJjZXB0ID0gbWVkX3B0KSwKICAgIGxpbmV0eXBlICA9ICJkb3R0ZWQiLCBjb2xvdXIgPSAiZ3JleTU1IiwgbGluZXdpZHRoID0gMC42CiAgKSArCiAgZ2VvbV90ZXh0KAogICAgZGF0YSAgICAgICAgPSBSRUZfTUVESUFOU19FRkZFQ1RPUiwKICAgIGFlcyh4ICAgICAgID0gMC41NSwKICAgICAgICB5ICAgICAgID0gbWVkX3B0LAogICAgICAgIGxhYmVsICAgPSBzcHJpbnRmKCJSZWY6ICVzICglLjJmKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ3N1YigiQ0Q0ICIsICIiLCBhcy5jaGFyYWN0ZXIoc3RhdGUpKSwgbWVkX3B0KSksCiAgICBpbmhlcml0LmFlcyA9IEZBTFNFLAogICAgaGp1c3QgPSAwLCBzaXplID0gMi44LCBjb2xvdXIgPSAiZ3JleTQwIgogICkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IFNUQVRFX0NPTE9SUywgZ3VpZGUgPSAibm9uZSIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDI1LCA1KSkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgbGFicygKICAgIHggICAgICAgID0gIlRyYW5zZmVycmVkIEF6aW11dGggbDIgTGFiZWwiLAogICAgeSAgICAgICAgPSAiVHJhbnNmZXJyZWQgUHNldWRvdGltZSIsCiAgICB0aXRsZSAgICA9ICJGaWd1cmUgOCDigJQgVHJhbnNmZXJyZWQgUHNldWRvdGltZSBwZXIgTGFiZWwgKEFsbCBDZWxsIExpbmVzKSIsCiAgICBzdWJ0aXRsZSA9IHNwcmludGYoCiAgICAgICJFZmZlY3RvciBheGlzIHJlZmVyZW5jZSBsaW5lczogTmFpdmU9JS4yZiB8IFRDTT0lLjJmIHwgVEVNPSUuMmYgfCBUZW1yYT0lLjJmXG5UcmVnIGxpbmUgb21pdHRlZCDigJQgVHJlZyAoUFQ9JS4yZikgb3ZlcmxhcHMgVENNOyBUcmVnLWxpa2UgdmlvbGluIHNob3duIGFzIGJpb2xvZ2ljYWwgY29uZmlybWF0aW9uIiwKICAgICAgbmFpdmVfbWVkLCB0Y21fbWVkLCB0ZW1fbWVkLCB0ZW1yYV9tZWQsIHRyZWdfbWVkKQogICkgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSAgICA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMsIGZhY2UgPSAiYm9sZCIpLAogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSwgIGNvbG91ciA9ICJncmV5NDAiKSwKICAgIGF4aXMudGV4dC54ICAgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBmYWNlID0gImJvbGQiKQogICkKCnByaW50KGZpZzh2MikKc2F2ZV9maWcoZmlnOHYyLCAiRmlnOHYyX1Zpb2xpbl9Ob1RyZWciLCB3ID0gMTIsIGggPSA2KQoKYGBgCgoKLS0tCgojIDE1LiBGaWd1cmUgOSDigJQgQ3Jvc3MtVGFibGU6IExhYmVsIHZzIFBzZXVkb3RpbWUgQmluIChQUklNQVJZIFJFU1VMVCkKCmBgYHtyICwgZmlnLndpZHRoPTE4LCBmaWcuaGVpZ2h0PTd9Cgpjcm9zc19kZiA8LSBxdWVyeV9kZiAlPiUKICBmaWx0ZXIoIWlzLm5hKGxhYmVsKSwgIWlzLm5hKHBzZXVkb3RpbWVfYmluKSkgJT4lCiAgbXV0YXRlKGxhYmVsID0gZmFjdG9yKGxhYmVsLCBsZXZlbHMgPSBTVEFURV9PUkRFUikpICU+JQogIGNvdW50KGxhYmVsLCBwc2V1ZG90aW1lX2JpbikgJT4lCiAgZ3JvdXBfYnkobGFiZWwpICU+JQogIG11dGF0ZShwY3QgPSAxMDAgKiBuIC8gc3VtKG4pKSAlPiUKICB1bmdyb3VwKCkKCnRjbV9kaXNjb3JkYW50IDwtIGNyb3NzX2RmICU+JQogIGZpbHRlcihsYWJlbCA9PSAiQ0Q0IFRDTSIsCiAgICAgICAgIHBzZXVkb3RpbWVfYmluICVpbiUgYygiVEVNLWxpa2UiLCAiVGVtcmEtbGlrZSIpKSAlPiUKICBzdW1tYXJpc2UocGN0ID0gc3VtKHBjdCkpICU+JQogIHB1bGwocGN0KQoKZmlnOSA8LSBnZ3Bsb3QoY3Jvc3NfZGYsIGFlcyhwc2V1ZG90aW1lX2JpbiwgcGN0LCBmaWxsID0gcHNldWRvdGltZV9iaW4pKSArCiAgZ2VvbV9jb2wod2lkdGggPSAwLjcpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gc3ByaW50ZigiJS4xZiUlIiwgcGN0KSksCiAgICAgICAgICAgIHZqdXN0ID0gLTAuMywgc2l6ZSA9IDMuNSwgZm9udGZhY2UgPSAiYm9sZCIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBCSU5fQ09MT1JTLCBndWlkZSA9ICJub25lIikgKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsIDApLCBsaW1pdHMgPSBjKDAsIDExNSkpICsKICBmYWNldF93cmFwKH4gbGFiZWwsIG5yb3cgPSAxLCBzY2FsZXMgPSAiZnJlZV94IikgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUoCiAgICBzdHJpcC50ZXh0ICAgICAgID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxMSksCiAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiZ3JleTk1IiwgY29sb3VyID0gImdyZXk2MCIpLAogICAgYXhpcy50ZXh0LnggICAgICA9IGVsZW1lbnRfdGV4dChzaXplID0gOSwgZmFjZSA9ICJib2xkIiwgYW5nbGUgPSAzMCwgaGp1c3QgPSAxKSwKICAgIHBsb3QudGl0bGUgICAgICAgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBmYWNlID0gImJvbGQiKSwKICAgIHBsb3Quc3VidGl0bGUgICAgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBjb2xvdXIgPSAiZ3JleTQwIikKICApICsKICBsYWJzKAogICAgeCAgICAgICAgPSAiUHNldWRvdGltZSBCaW4iLAogICAgeSAgICAgICAgPSAiJSBvZiBDZWxscyB3aXRoIFRoaXMgTGFiZWwiLAogICAgdGl0bGUgICAgPSAiRmlndXJlIDkg4oCUIENyb3NzLVRhYmxlOiBUcmFuc2ZlcnJlZCBMYWJlbCB2cyBQc2V1ZG90aW1lIEJpbiAgW1BSSU1BUlkgUkVTVUxUXSIsCiAgICBzdWJ0aXRsZSA9IHNwcmludGYoCiAgICAgICJUQ00tbGFiZWxsZWQgY2VsbHM6ICUuMWYlJSBkaXNjb3JkYW50IChURU0tbGlrZSBvciBUZW1yYS1saWtlKVxuVHJlZyBwYW5lbDogMTAwJSUgVHJlZy1saWtlIGJ5IGRlc2lnbiIsCiAgICAgIHRjbV9kaXNjb3JkYW50KQogICkKCnByaW50KGZpZzkpCnNhdmVfZmlnKGZpZzksICJGaWc5X0Nyb3NzVGFibGVfTGFiZWxfdnNfQmluX1BSSU1BUlkiLCB3ID0gMTgsIGggPSA3KQpgYGAKCi0tLQoKIyAxNi4gU3VwcGxlbWVudGFyeSBGaWd1cmVzCgojIyBTdXBwIFMxIOKAlCBQZXIgQ2VsbCBMaW5lIFBzZXVkb3RpbWUgRGVuc2l0eSAoRmFjZXRlZCkKCmBgYHtyIHN1cHBTMS1kZW5zaXR5LWZhY2V0LCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9N30KCnN1cHBTMSA8LSBnZ3Bsb3QoCiAgICBxdWVyeV9kZiAlPiUgZmlsdGVyKCFpcy5uYShwc2V1ZG90aW1lKSwgIWlzLm5hKGNlbGxfbGluZSkpLAogICAgYWVzKHggPSBwc2V1ZG90aW1lLCBmaWxsID0gY2VsbF9saW5lLCBjb2xvdXIgPSBjZWxsX2xpbmUpCiAgKSArCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC4zNSwgbGluZXdpZHRoID0gMC44KSArCiAgZ2VvbV92bGluZShkYXRhID0gUkVGX01FRElBTlMsIGFlcyh4aW50ZXJjZXB0ID0gbWVkX3B0KSwKICAgICAgICAgICAgIGNvbG91ciA9ICJncmV5NDUiLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBsaW5ld2lkdGggPSAwLjUpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDIiLCBndWlkZSA9ICJub25lIikgKwogIHNjYWxlX2NvbG91cl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIiwgZ3VpZGUgPSAibm9uZSIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAyNiksIGJyZWFrcyA9IHNlcSgwLCAyNSwgNSkpICsKICBmYWNldF93cmFwKH4gY2VsbF9saW5lLCBucm93ID0gMikgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUoc3RyaXAudGV4dCAgICA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKSwKICAgICAgICBwbG90LnRpdGxlICAgID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSwgIGNvbG91ciA9ICJncmV5NDAiKSkgKwogIGxhYnMoeCA9ICJUcmFuc2ZlcnJlZCBQc2V1ZG90aW1lIiwgeSA9ICJEZW5zaXR5IiwKICAgICAgIHRpdGxlICAgID0gIlN1cHAgUzEg4oCUIFBlciBDZWxsIExpbmUgUHNldWRvdGltZSBEZW5zaXR5IiwKICAgICAgIHN1YnRpdGxlID0gIkdyZXkgZGFzaGVkIGxpbmVzID0gZGF0YS1kZXJpdmVkIHJlZmVyZW5jZSBzdGF0ZSBtZWRpYW5zIikKCnByaW50KHN1cHBTMSkKc2F2ZV9maWcoc3VwcFMxLCAiU3VwcFMxX0RlbnNpdHlfUGVyTGluZV9GYWNldCIsIHcgPSAxMiwgaCA9IDcpCmBgYAoKIyMgU3VwcCBTMiDigJQgUmlkZ2VwbG90IFN0YW5kYWxvbmUKCmBgYHtyIHN1cHBTMi1yaWRnZXBsb3QsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD03fQoKc3VwcFMyIDwtIHA2YiArCiAgZ2d0aXRsZSgKICAgICJTdXBwIFMyIOKAlCBQZXIgQ2VsbCBMaW5lIFBzZXVkb3RpbWUgUmlkZ2VwbG90IiwKICAgIHN1YnRpdGxlID0gc3ByaW50ZigKICAgICAgIkJpbiBib3VuZGFyaWVzOiBOYWl2ZXxUQ009JS4yZiB8IFRDTXxURU09JS4yZiB8IFRFTXxUZW1yYT0lLjJmIiwKICAgICAgQklOX05BSVZFX1RDTSwgQklOX1RDTV9URU0sIEJJTl9URU1fVEVNUkEpCiAgKQoKcHJpbnQoc3VwcFMyKQpzYXZlX2ZpZyhzdXBwUzIsICJTdXBwUzJfUmlkZ2VwbG90X1BlckxpbmUiLCB3ID0gMTAsIGggPSA3KQpgYGAKCiMjIFN1cHAgUzMg4oCUIFZpb2xpbiBwZXIgTGFiZWwgeCBDZWxsIExpbmUgKEZhY2V0ZWQpCgpgYGB7ciBzdXBwUzMtdmlvbGluLWxhYmVsLWxpbmUsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD0xMH0KCnN1cHBTMyA8LSBnZ3Bsb3QoCiAgICBxdWVyeV9kZiAlPiUKICAgICAgZmlsdGVyKCFpcy5uYShsYWJlbCksICFpcy5uYShjZWxsX2xpbmUpLCAhaXMubmEocHNldWRvdGltZSkpICU+JQogICAgICBtdXRhdGUobGFiZWwgPSBmYWN0b3IobGFiZWwsIGxldmVscyA9IFNUQVRFX09SREVSKSksCiAgICBhZXMoY2VsbF9saW5lLCBwc2V1ZG90aW1lLCBmaWxsID0gY2VsbF9saW5lKQogICkgKwogIGdlb21fdmlvbGluKHNjYWxlID0gIndpZHRoIiwgdHJpbSA9IEZBTFNFLCBhbHBoYSA9IDAuOCwgY29sb3VyID0gIndoaXRlIikgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMDcsIGZpbGwgPSAid2hpdGUiLCBjb2xvdXIgPSAiZ3JleTQwIiwKICAgICAgICAgICAgICAgb3V0bGllci5zaXplID0gMC4yLCBvdXRsaWVyLmFscGhhID0gMC4zKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIiwgZ3VpZGUgPSAibm9uZSIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDI1LCA1KSkgKwogIGZhY2V0X3dyYXAofiBsYWJlbCwgbnJvdyA9IDEpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKAogICAgc3RyaXAudGV4dCAgICAgICA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTApLAogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImdyZXk5NSIsIGNvbG91ciA9ICJncmV5NjAiKSwKICAgIGF4aXMudGV4dC54ICAgICAgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksIGZhY2UgPSAiYm9sZCIsIGFuZ2xlID0gMzAsIGhqdXN0ID0gMSksCiAgICBwbG90LnRpdGxlICAgICAgID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICBwbG90LnN1YnRpdGxlICAgID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LCAgY29sb3VyID0gImdyZXk0MCIpCiAgKSArCiAgbGFicyh4ID0gIkNlbGwgTGluZSIsIHkgPSAiVHJhbnNmZXJyZWQgUHNldWRvdGltZSIsCiAgICAgICB0aXRsZSAgICA9ICJTdXBwIFMzIOKAlCBWaW9saW46IFBzZXVkb3RpbWUgcGVyIExhYmVsIHggQ2VsbCBMaW5lIiwKICAgICAgIHN1YnRpdGxlID0gIkNvbXBsZW1lbnRzIEZpZyA5IOKAlCBzaG93cyB3aXRoaW4tc3RhdGUgcGVyLWxpbmUgaGV0ZXJvZ2VuZWl0eSIpCgpwcmludChzdXBwUzMpCnNhdmVfZmlnKHN1cHBTMywgIlN1cHBTM19WaW9saW5fTGFiZWxfeF9MaW5lIiwgdyA9IDE2LCBoID0gMTApCmBgYAoKIyMgU3VwcCBTNCDigJQgUHNldWRvdGltZSBCaW4gQmFyIENoYXJ0IHdpdGggRnVsbCBQZXJjZW50YWdlcwoKYGBge3Igc3VwcFM0LWJpbnMtZGV0YWlsZWQsIGZpZy53aWR0aD0xNCwgZmlnLmhlaWdodD02fQoKc3VwcFM0IDwtIGdncGxvdChiaW5fZGYsIGFlcyhjZWxsX2xpbmUsIHBjdCwgZmlsbCA9IHBzZXVkb3RpbWVfYmluKSkgKwogIGdlb21fY29sKHdpZHRoID0gMC43KSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBiaW5fZGYgJT4lIGZpbHRlcihwY3QgPiAyKSwKICAgICAgICAgICAgYWVzKGxhYmVsID0gc3ByaW50ZigiJS4xZiUlIiwgcGN0KSksCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpLAogICAgICAgICAgICBzaXplID0gMy41LCBjb2xvdXIgPSAid2hpdGUiLCBmb250ZmFjZSA9ICJib2xkIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IEJJTl9DT0xPUlMsIG5hbWUgPSAiUHNldWRvdGltZSBiaW4iKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgMCksIGxpbWl0cyA9IGMoMCwgMTAxKSkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgbGFicygKICAgIHggICAgICAgID0gIkNlbGwgTGluZSIsCiAgICB5ICAgICAgICA9ICIlIENlbGxzIiwKICAgIHRpdGxlICAgID0gIlN1cHAgUzQg4oCUIFBzZXVkb3RpbWUgQmluIENvbXBvc2l0aW9uIHBlciBDZWxsIExpbmUiLAogICAgc3VidGl0bGUgPSBzcHJpbnRmKAogICAgICAiQmluIGJvdW5kYXJpZXM6IE5haXZlfFRDTT0lLjJmICB8ICBUQ018VEVNPSUuMmYgIHwgIFRFTXxUZW1yYT0lLjJmICB8ICBUcmVnPWxhYmVsLWJhc2VkIiwKICAgICAgQklOX05BSVZFX1RDTSwgQklOX1RDTV9URU0sIEJJTl9URU1fVEVNUkEpCiAgKSArCiAgdGhlbWUocGxvdC50aXRsZSAgICA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksICBjb2xvdXIgPSAiZ3JleTQwIiksCiAgICAgICAgYXhpcy50ZXh0LnggICA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEsIGZhY2UgPSAiYm9sZCIpKQoKcHJpbnQoc3VwcFM0KQpzYXZlX2ZpZyhzdXBwUzQsICJTdXBwUzRfQmluc19CYXJDaGFydF9EZXRhaWxlZCIsIHcgPSAxNCwgaCA9IDYpCmBgYAoKLS0tCgojIDE3LiBGaWd1cmUgTWFuaWZlc3QKCmBgYHtyIG1hbmlmZXN0LCBlY2hvPUZBTFNFfQptYW5pZmVzdCA8LSBkYXRhLmZyYW1lKAogIEZpbGUgPSBjKAogICAgIkZpZzdfRm91clBhbmVsX1N1bW1hcnlfRklYRUQiLAogICAgIkZpZzdBX1RyYW5zZmVycmVkX0xhYmVscyIsCiAgICAiRmlnN0JfVHJhbnNmZXJyZWRfUHNldWRvdGltZV9GSVhFRCIsCiAgICAiRmlnN0NfUHNldWRvdGltZV9CaW5zX1VNQVAiLAogICAgIkZpZzdEX0xhYmVsX0JhckNoYXJ0X3Blcl9MaW5lIiwKICAgICJGaWcxX1BzZXVkb3RpbWVfVmlvbGluX3Blcl9MaW5lIiwKICAgICJGaWcyX1VNQVBfUHNldWRvdGltZV9hbmRfTGFiZWwiLAogICAgIkZpZzNfTGFiZWxzX1BlckxpbmVfVU1BUCIsCiAgICAiRmlnNF9QZXJMaW5lX0ZhY2V0X1VNQVAiLAogICAgIkZpZzVfTGFiZWxfdnNfUHNldWRvdGltZV9CaW5zIiwKICAgICJGaWc1QV9MYWJlbF9UcmFuc2Zlcl9CYXJDaGFydCIsCiAgICAiRmlnNUJfUHNldWRvdGltZV9CaW5zX0JhckNoYXJ0IiwKICAgICJGaWc2X0RlbnNpdHlfYW5kX1JpZGdlcGxvdCIsCiAgICAiRmlnNkFfRGVuc2l0eV9PdmVyYWxsIiwKICAgICJGaWc2Ql9SaWRnZXBsb3RfUGVyTGluZSIsCiAgICAiRmlnOF9WaW9saW5fUHNldWRvdGltZV9wZXJfTGFiZWwiLAogICAgIkZpZzlfQ3Jvc3NUYWJsZV9MYWJlbF92c19CaW5fUFJJTUFSWSIsCiAgICAiU3VwcFMxX0RlbnNpdHlfUGVyTGluZV9GYWNldCIsCiAgICAiU3VwcFMyX1JpZGdlcGxvdF9QZXJMaW5lIiwKICAgICJTdXBwUzNfVmlvbGluX0xhYmVsX3hfTGluZSIsCiAgICAiU3VwcFM0X0JpbnNfQmFyQ2hhcnRfRGV0YWlsZWQiCiAgKSwKICBEZXNjcmlwdGlvbiA9IGMoCiAgICAiRm91ci1wYW5lbDogbGFiZWxzIHwgcHNldWRvdGltZSAoRklYRUQpIHwgYmlucyB8IGxhYmVsIGJhciIsCiAgICAiU2V6YXJ5IFVNQVAg4oCUIHRyYW5zZmVycmVkIEF6aW11dGggbDIgbGFiZWwiLAogICAgIlNlemFyeSBVTUFQIOKAlCB0cmFuc2ZlcnJlZCBwc2V1ZG90aW1lLCBGSVhFRCAwLTI1IGNvbG91ciBzY2FsZSIsCiAgICAiU2V6YXJ5IFVNQVAg4oCUIHBzZXVkb3RpbWUgYmluIGNvbG91ciIsCiAgICAiVHJhbnNmZXJyZWQgbGFiZWwgcHJvcG9ydGlvbnMgcGVyIGNlbGwgbGluZSBiYXIgY2hhcnQiLAogICAgIlBzZXVkb3RpbWUgdmlvbGluIHBlciBjZWxsIGxpbmUgd2l0aCBkYXRhLWRlcml2ZWQgcmVmZXJlbmNlIG1lZGlhbnMiLAogICAgIlVNQVAgcHNldWRvdGltZSBncmFkaWVudCArIGxhYmVsIGlkZW50aXR5IHNpZGUgYnkgc2lkZSIsCiAgICAiTGFiZWwgYmFyIGNoYXJ0ICsgcGVyIGNlbGwgbGluZSBVTUFQIGZhY2V0cyIsCiAgICAiUGVyIGNlbGwgbGluZSBmYWNldCBVTUFQIOKAlCBrZXkgaW50ZXItbGluZSBoZXRlcm9nZW5laXR5IGZpZ3VyZSIsCiAgICAiRHVhbCBiYXIgY2hhcnQ6IGxhYmVscyAodG9wKSBhbmQgcHNldWRvdGltZSBiaW5zIChib3R0b20pIiwKICAgICJMYWJlbCB0cmFuc2ZlciBwcm9wb3J0aW9ucyBiYXIgY2hhcnQgb25seSIsCiAgICAiUHNldWRvdGltZSBiaW4gcHJvcG9ydGlvbnMgYmFyIGNoYXJ0IG9ubHkiLAogICAgIk92ZXJhbGwgcHNldWRvdGltZSBkZW5zaXR5ICsgcGVyLWxpbmUgcmlkZ2VwbG90IiwKICAgICJPdmVyYWxsIHBzZXVkb3RpbWUgZGVuc2l0eSB3aXRoIGRhdGEtZGVyaXZlZCByZWZlcmVuY2UgbWVkaWFuIGxpbmVzIiwKICAgICJQZXIgY2VsbCBsaW5lIHBzZXVkb3RpbWUgcmlkZ2VwbG90IHdpdGggYmluIGJvdW5kYXJpZXMiLAogICAgIlZpb2xpbjogdHJhbnNmZXJyZWQgcHNldWRvdGltZSBwZXIgbGFiZWwg4oCUIGRhdGEtZGVyaXZlZCBhbm5vdGF0aW9ucyIsCiAgICAiQ3Jvc3MtdGFibGU6IGxhYmVsIHZzIHBzZXVkb3RpbWUgYmluIOKAlCBQUklNQVJZIFJFU1VMVCIsCiAgICAiUGVyIGNlbGwgbGluZSBwc2V1ZG90aW1lIGRlbnNpdHkgZmFjZXRlZCIsCiAgICAiUGVyIGNlbGwgbGluZSByaWRnZXBsb3Qgc3RhbmRhbG9uZSIsCiAgICAiVmlvbGluOiBwc2V1ZG90aW1lIHBlciBsYWJlbCB4IGNlbGwgbGluZSBmYWNldGVkIiwKICAgICJQc2V1ZG90aW1lIGJpbiBiYXIgY2hhcnQgd2l0aCBmdWxsIHBlcmNlbnRhZ2VzIGxhYmVsbGVkIgogICksCiAgTWFudXNjcmlwdCA9IGMoCiAgICAiRmlnIDEgY29tYmluZWQiLCAiRmlnIDFBIiwgIkZpZyAxQiAoRklYRUQpIiwgIkZpZyAxQyIsICJGaWcgMUQiLAogICAgIlN1cHAiLCAiRmlnIDIiLCAiRmlnIDMiLCAiRmlnIDQgKEtFWSkiLAogICAgIkZpZyA1IiwgIuKAlCIsICJGaWcgNUIiLAogICAgIlN1cHAiLCAiU3VwcCBTMyIsICJTdXBwIFM0IiwKICAgICJTdXBwIFM1IiwgIkZpZyAyIChQUklNQVJZKSIsCiAgICAiU3VwcCBTMSIsICJTdXBwIFMyIiwgIlN1cHAgUzYiLCAiU3VwcCIKICApLAogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQopCgprYWJsZShtYW5pZmVzdCwKICAgICAgY2FwdGlvbiA9ICJBbGwgMjEgZmlndXJlcyDigJQgRmlndXJlcy9QTkcvKi5wbmcgKDMwMCBkcGkpIGFuZCBGaWd1cmVzL1BERi8qLnBkZiIpICU+JQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwiY29uZGVuc2VkIiwiaG92ZXIiKSwKICAgICAgICAgICAgICAgIGZ1bGxfd2lkdGggPSBUUlVFKSAlPiUKICByb3dfc3BlYyh3aGljaChncmVwbCgiRklYRUR8UFJJTUFSWSIsIG1hbmlmZXN0JEZpbGUpKSwKICAgICAgICAgICBib2xkID0gVFJVRSwgYmFja2dyb3VuZCA9ICIjZmZmM2NkIikKYGBgCgotLS0KCiMgMTguIFNlc3Npb24gSW5mbwoKYGBge3Igc2Vzc2lvbi1pbmZvfQpzZXNzaW9uSW5mbygpCmBgYAo=