Load Reference Objects
(Step 1 outputs — not re-run)
# ── Load the reference Seurat object with frozen UMAP model ───────────────
cd4_ref <- readRDS("../../1-Custom_MST/Objects/cd4_ref_dual_trajectory.rds")
# ── Load MST graph and centroids ──────────────────────────────────────────
mst_graph <- readRDS("../../1-Custom_MST/Objects/mst_graph.rds")
milestone_centroids <- readRDS("../../1-Custom_MST/Objects/milestone_centroids.rds")
# ── Validate milestone structure ──────────────────────────────────────────
expected_ms <- sprintf("M%02d", 0:6)
actual_ms <- sort(unique(na.omit(cd4_ref@meta.data$milestone)))
stopifnot(
"Milestone mismatch — re-run Step 1 first" = identical(actual_ms, expected_ms),
"mst_pseudotime_norm missing" = "mst_pseudotime_norm" %in% colnames(cd4_ref@meta.data),
"monocle3_pseudotime_norm missing" = "monocle3_pseudotime_norm" %in% colnames(cd4_ref@meta.data),
"UMAP model missing from cd4_ref" = !is.null(cd4_ref@reductions[[UMAP_NAME]]@misc$model)
)
cat("✅ Reference objects loaded and validated\n")
✅ Reference objects loaded and validated
cat(sprintf(" %d reference cells | %d milestones\n", ncol(cd4_ref), length(actual_ms)))
11466 reference cells | 7 milestones
cat(sprintf(" MST: %d nodes, %d edges\n", vcount(mst_graph), ecount(mst_graph)))
MST: 7 nodes, 6 edges
cat("\nMilestone structure from Step 1:\n")
Milestone structure from Step 1:
print(milestone_centroids[, c("milestone","state","n_cells")])
# ── Build reference UMAP data frame for background plotting ───────────────
ref_umap_df <- as.data.frame(Embeddings(cd4_ref, UMAP_NAME))
colnames(ref_umap_df) <- c("UMAP_1","UMAP_2")
ref_umap_df$state <- cd4_ref@meta.data[[STATE_COL]]
ref_umap_df$milestone <- cd4_ref@meta.data$milestone
ref_umap_df$mst_pt <- cd4_ref@meta.data$mst_pseudotime_norm
ref_umap_df$m3_pt <- cd4_ref@meta.data$monocle3_pseudotime_norm
# ── MST edge data frame for overlay ───────────────────────────────────────
mst_edges <- as_edgelist(mst_graph)
mst_edge_df <- do.call(rbind, lapply(seq_len(nrow(mst_edges)), function(i) {
m1 <- mst_edges[i,1]; m2 <- mst_edges[i,2]
r1 <- milestone_centroids[milestone_centroids$milestone == m1, ]
r2 <- milestone_centroids[milestone_centroids$milestone == m2, ]
data.frame(x1=r1$UMAP_1, y1=r1$UMAP_2, x2=r2$UMAP_1, y2=r2$UMAP_2)
}))
Load Sézary Cell
Lines
all_obj <- readRDS("/home/nabbasi/apollo_home/1-Seurat_RDS_OBJECT_FINAL/All_samples_Merged_with_Renamed_Clusters_Cell_state-03-12-2025.rds.rds")
# ── cell_line column confirmed present (40,695 cells, L1–L7) ─────────────
all_obj$cell_line <- as.character(all_obj$cell_line)
sezary_obj <- subset(all_obj, subset = cell_line %in% CELL_LINES)
rm(all_obj); gc()
used (Mb) gc trigger (Mb) max used (Mb)
Ncells 9046606 483.2 16164308 863.3 16164308 863.3
Vcells 1394581656 10639.9 3064212682 23378.1 2635168938 20104.8
cat(sprintf("Sézary cells loaded: %d total\n", ncol(sezary_obj)))
Sézary cells loaded: 40695 total
Per cell line:
print(table(sezary_obj$cell_line))
L1 L2 L3 L4 L5 L6 L7
5825 5935 6428 6006 6022 5148 5331
DefaultAssay(sezary_obj) <- "RNA"
# Shared genes with reference (confirmed ~36,601)
shared_genes <- intersect(rownames(sezary_obj), rownames(cd4_ref))
cat(sprintf("\nShared genes (query ∩ reference): %d\n", length(shared_genes)))
Shared genes (query ∩ reference): 36601
stopifnot("Fewer than 2000 shared genes — check objects" = length(shared_genes) >= 2000)
# ── Check percent.mt exists — needed for SCTransform vars.to.regress ──────
# If percent.mt is absent, SCT will run without regressing it (see per-line chunk)
HAS_PCT_MT <- "percent.mt" %in% colnames(sezary_obj@meta.data)
cat(sprintf("\npercent.mt in metadata: %s\n", HAS_PCT_MT))
percent.mt in metadata: TRUE
Per-Cell-Line SCT +
Projection
Rationale for per-cell-line SCT:
Each Sézary cell line has its own library size distribution and
technical variation. Running SCTransform on each line independently fits
a line-specific regression model, which produces better-calibrated
residuals for anchor finding. This gives
FindTransferAnchors more reliable anchors compared to
normalising all lines together, at the cost of one SCT run per line
(~30–60 s each).
# ── Step 7: Summary ───────────────────────────────────────────────────────
cat("\nPredicted state distribution:\n")
Predicted state distribution:
print(table(sezary_obj$predicted.state))
CD4 TCM CD4 TEM Treg
40628 66 1
cat("\nPredicted milestone distribution:\n")
Predicted milestone distribution:
print(table(sezary_obj$predicted.milestone))
M01 M02 M03 M05
1713 38893 86 3
cat("\nMST pseudotime range:", round(range(sezary_obj$mst_pseudotime_norm, na.rm=TRUE), 1), "\n")
MST pseudotime range: 8.3 99.6
cat("\n✅ Projection complete\n")
✅ Projection complete
cat(sprintf("✅ Anchors found: %d anchor pairs\n", nrow(anchors@anchors)))
✅ Anchors found: 8661 anchor pairs
cat(sprintf("Cells projected: %d\n", ncol(sezary_obj)))
Cells projected: 40695
cat(sprintf("Mean prediction score: %.3f (>0.5 = reliable, >0.7 = confident)\n",
mean(sezary_obj$predicted.state.score, na.rm=TRUE)))
Mean prediction score: 0.984 (>0.5 = reliable, >0.7 = confident)
cat(sprintf("Cells with score >0.5: %d (%.1f%%)\n",
sum(sezary_obj$predicted.state.score > 0.5, na.rm=TRUE),
100*mean(sezary_obj$predicted.state.score > 0.5, na.rm=TRUE)))
Cells with score >0.5: 40643 (99.9%)
cat(sprintf("Cells with score >0.7: %d (%.1f%%)\n",
sum(sezary_obj$predicted.state.score > 0.7, na.rm=TRUE),
100*mean(sezary_obj$predicted.state.score > 0.7, na.rm=TRUE)))
Cells with score >0.7: 40207 (98.8%)
cat(sprintf("Cells with score >0.5: %d (%.1f%%)\n",
sum(sezary_obj$predicted.milestone.score > 0.5, na.rm=TRUE),
100*mean(sezary_obj$predicted.milestone.score > 0.5, na.rm=TRUE)))
Cells with score >0.5: 40388 (99.2%)
cat(sprintf("Cells with score >0.7: %d (%.1f%%)\n",
sum(sezary_obj$predicted.milestone.score > 0.7, na.rm=TRUE),
100*mean(sezary_obj$predicted.milestone.score > 0.7, na.rm=TRUE)))
Cells with score >0.7: 34183 (84.0%)
cat(sprintf("Total cells: %d\n", nrow(query_umap_df)))
Total cells: 40695
Per cell line:
print(table(query_umap_df$cell_line))
L1 L2 L3 L4 L5 L6 L7
5825 5935 6428 6006 6022 5148 5331
cat("\nMilestone distribution:\n")
Milestone distribution:
print(table(query_umap_df$predicted_milestone, useNA="ifany"))
M01 M02 M03 M05
1713 38893 86 3
transfer_summary <- query_umap_df %>%
group_by(cell_line) %>%
summarise(
n_cells = n(),
mst_pt_mean = round(mean(mst_pt, na.rm=TRUE), 1),
mst_pt_med = round(median(mst_pt, na.rm=TRUE), 1),
m3_pt_mean = round(mean(m3_pt, na.rm=TRUE), 1),
m3_pt_med = round(median(m3_pt, na.rm=TRUE), 1),
top_milestone = names(sort(table(predicted_milestone), decreasing=TRUE))[1],
.groups = "drop"
)
ms_wide <- query_umap_df %>%
filter(!is.na(predicted_milestone)) %>%
count(cell_line, predicted_milestone) %>%
group_by(cell_line) %>%
mutate(pct = round(100 * n / sum(n), 1)) %>%
select(cell_line, predicted_milestone, pct) %>%
pivot_wider(names_from=predicted_milestone, values_from=pct, values_fill=0)
for (m in MILESTONE_ORDER) {
if (!m %in% colnames(ms_wide)) ms_wide[[m]] <- 0
}
ms_wide <- ms_wide[, c("cell_line", MILESTONE_ORDER)]
full_summary <- left_join(transfer_summary, ms_wide, by="cell_line")
kable(full_summary,
caption = "Sézary projection summary — pseudotime and milestone composition",
digits = 1) %>%
kable_styling(bootstrap_options=c("striped","hover","condensed"),
full_width=FALSE) %>%
add_header_above(c(" "=ncol(transfer_summary),
"% cells per milestone"=length(MILESTONE_ORDER)))
Sézary projection summary — pseudotime and milestone composition
|
% cells per milestone |
| cell_line |
n_cells |
mst_pt_mean |
mst_pt_med |
m3_pt_mean |
m3_pt_med |
top_milestone |
M00 |
M01 |
M02 |
M03 |
M04 |
M05 |
M06 |
| L1 |
5825 |
57.5 |
55.7 |
68.6 |
66.1 |
M02 |
0 |
6.4 |
92.1 |
1.5 |
0 |
0.1 |
0 |
| L2 |
5935 |
52.7 |
54.5 |
57.2 |
58.9 |
M02 |
0 |
4.7 |
95.3 |
0.0 |
0 |
0.0 |
0 |
| L3 |
6428 |
52.1 |
53.5 |
61.0 |
60.7 |
M02 |
0 |
6.9 |
93.1 |
0.0 |
0 |
0.0 |
0 |
| L4 |
6006 |
56.7 |
56.7 |
63.7 |
60.6 |
M02 |
0 |
1.9 |
98.1 |
0.0 |
0 |
0.0 |
0 |
| L5 |
6022 |
51.8 |
52.8 |
57.4 |
58.4 |
M02 |
0 |
5.5 |
94.5 |
0.0 |
0 |
0.0 |
0 |
| L6 |
5148 |
58.3 |
57.1 |
62.8 |
60.7 |
M02 |
0 |
2.1 |
97.9 |
0.0 |
0 |
0.0 |
0 |
| L7 |
5331 |
55.5 |
55.8 |
62.8 |
60.0 |
M02 |
0 |
1.3 |
98.7 |
0.0 |
0 |
0.0 |
0 |
Save Outputs
dir.create("Objects", showWarnings=FALSE)
dir.create("Figures", showWarnings=FALSE)
dir.create("Tables", showWarnings=FALSE)
SaveSeuratRds(sezary_obj, "Objects/sezary_projected.rds")
write.csv(full_summary, "Tables/projection_summary_per_line.csv", row.names=FALSE)
write.csv(ms_comp, "Tables/milestone_composition_per_line.csv", row.names=FALSE)
ggsave("Figures/fig_all_lines_umap.pdf", p_all_lines, width=14, height=10)
ggsave("Figures/fig_violin_mst.pdf", p_violin_mst, width=10, height=5)
ggsave("Figures/fig_violin_m3.pdf", p_violin_m3, width=10, height=5)
ggsave("Figures/fig_milestone_composition.pdf", p_ms_bar, width=11, height=5)
ggsave("Figures/fig_pt_correlation.pdf", p_pt_cor, width=12, height=8)
cat("✅ All outputs saved\n")
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] stats4 stats graphics grDevices utils datasets methods base
other attached packages:
[1] future_1.69.0 kableExtra_1.4.0 knitr_1.51 RColorBrewer_1.1-3 scales_1.4.0
[6] viridis_0.6.5 viridisLite_0.4.3 patchwork_1.3.2 tidyr_1.3.2 dplyr_1.2.0
[11] ggrepel_0.9.6 ggplot2_4.0.2 igraph_2.2.2 monocle3_1.4.26 SingleCellExperiment_1.32.0
[16] SummarizedExperiment_1.40.0 GenomicRanges_1.62.1 Seqinfo_1.0.0 IRanges_2.44.0 S4Vectors_0.48.0
[21] MatrixGenerics_1.22.0 matrixStats_1.5.0 Biobase_2.70.0 BiocGenerics_0.56.0 generics_0.1.4
[26] SeuratWrappers_0.4.0 Seurat_5.4.0 SeuratObject_5.3.0 sp_2.2-1
loaded via a namespace (and not attached):
[1] RcppAnnoy_0.0.23 splines_4.5.2 later_1.4.6 tibble_3.3.1 R.oo_1.27.1 polyclip_1.10-7
[7] fastDummies_1.7.5 lifecycle_1.0.5 Rdpack_2.6.6 globals_0.19.0 lattice_0.22-9 MASS_7.3-65
[13] magrittr_2.0.4 plotly_4.12.0 sass_0.4.10 rmarkdown_2.30 jquerylib_0.1.4 yaml_2.3.12
[19] remotes_2.5.0 httpuv_1.6.16 otel_0.2.0 glmGamPoi_1.22.0 sctransform_0.4.3 spam_2.11-3
[25] spatstat.sparse_3.1-0 reticulate_1.45.0 cowplot_1.2.0 pbapply_1.7-4 minqa_1.2.8 abind_1.4-8
[31] Rtsne_0.17 purrr_1.2.1 R.utils_2.13.0 irlba_2.3.7 listenv_0.10.0 spatstat.utils_3.2-1
[37] goftest_1.2-3 RSpectra_0.16-2 spatstat.random_3.4-4 fitdistrplus_1.2-6 parallelly_1.46.1 DelayedMatrixStats_1.32.0
[43] svglite_2.2.2 codetools_0.2-20 DelayedArray_0.36.0 xml2_1.5.2 tidyselect_1.2.1 farver_2.1.2
[49] lme4_1.1-38 spatstat.explore_3.7-0 jsonlite_2.0.0 progressr_0.18.0 ggridges_0.5.7 survival_3.8-6
[55] systemfonts_1.3.1 tools_4.5.2 ragg_1.5.0 ica_1.0-3 Rcpp_1.1.1 glue_1.8.0
[61] gridExtra_2.3 SparseArray_1.10.8 xfun_0.56 withr_3.0.2 BiocManager_1.30.27 fastmap_1.2.0
[67] boot_1.3-32 digest_0.6.39 rsvd_1.0.5 R6_2.6.1 mime_0.13 textshaping_1.0.4
[73] scattermore_1.2 tensor_1.5.1 dichromat_2.0-0.1 spatstat.data_3.1-9 R.methodsS3_1.8.2 utf8_1.2.6
[79] data.table_1.18.2.1 httr_1.4.8 htmlwidgets_1.6.4 S4Arrays_1.10.1 uwot_0.2.4 pkgconfig_2.0.3
[85] gtable_0.3.6 rsconnect_1.7.0 lmtest_0.9-40 S7_0.2.1 XVector_0.50.0 htmltools_0.5.9
[91] dotCall64_1.2 png_0.1-8 spatstat.univar_3.1-6 reformulas_0.4.4 rstudioapi_0.18.0 tzdb_0.5.0
[97] reshape2_1.4.5 nlme_3.1-168 nloptr_2.2.1 zoo_1.8-15 cachem_1.1.0 stringr_1.6.0
[103] KernSmooth_2.23-26 parallel_4.5.2 miniUI_0.1.2 pillar_1.11.1 grid_4.5.2 vctrs_0.7.1
[109] RANN_2.6.2 promises_1.5.0 beachmat_2.26.0 xtable_1.8-4 cluster_2.1.8.2 evaluate_1.0.5
[115] readr_2.1.6 cli_3.6.5 compiler_4.5.2 rlang_1.1.7 future.apply_1.20.1 labeling_0.4.3
[121] fs_1.6.6 plyr_1.8.9 stringi_1.8.7 deldir_2.0-4 lazyeval_0.2.2 spatstat.geom_3.7-0
[127] Matrix_1.7-4 RcppHNSW_0.6.0 hms_1.1.4 sparseMatrixStats_1.22.0 shiny_1.12.1 rbibutils_2.4.1
[133] ROCR_1.0-12 bslib_0.10.0
LS0tCnRpdGxlOiAiU3RlcCAyOiBTw6l6YXJ5IENlbGwgTGluZSBQcm9qZWN0aW9uIG9udG8gQ0Q0IFJlZmVyZW5jZSBUcmFqZWN0b3J5IgpzdWJ0aXRsZTogIlBlci1jZWxsLWxpbmUgU0NUIHwgTVNUICsgTW9ub2NsZTMgcHNldWRvdGltZSB0cmFuc2ZlciB8IDctbWlsZXN0b25lIGFsaWdubWVudCIKYXV0aG9yOiAiTkFTSVIgTUFITU9PRCBBQkJBU0kiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICB0aGVtZTogam91cm5hbAogICAgaGlnaGxpZ2h0OiB0YW5nbwogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIGRmX3ByaW50OiBwYWdlZAogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICBmaWcuYWxpZ249ImNlbnRlciIsIGRwaT0xNTApCmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIE92ZXJ2aWV3CgoqKldoYXQgdGhpcyBzY3JpcHQgZG9lcyDigJQgbm90aGluZyBpcyByZS1jb21wdXRlZCBmcm9tIHNjcmF0Y2guKioKCi0gTG9hZHMgdGhlIGFscmVhZHktc2F2ZWQgcmVmZXJlbmNlIHRyYWplY3Rvcnkgb2JqZWN0cyBmcm9tIFN0ZXAgMQotIExvYWRzIFPDqXphcnkgY2VsbCBsaW5lcyBMMeKAk0w3Ci0gUnVucyAqKnBlci1jZWxsLWxpbmUgU0NUIG5vcm1hbGlzYXRpb24qKiBiZWZvcmUgYEZpbmRUcmFuc2ZlckFuY2hvcnNgCiAg4oaSIGVhY2ggbGluZSBnZXRzIGl0cyBvd24gU0NUIG1vZGVsIOKGkiBtb3JlIGJpb2xvZ2ljYWxseSBtZWFuaW5nZnVsIGFuY2hvcnMKLSBQcm9qZWN0cyBlYWNoIGxpbmUgaW5kaXZpZHVhbGx5IG9udG8gdGhlIGZyb3plbiByZWZlcmVuY2UgVU1BUAotIFRyYW5zZmVycyBib3RoICoqTVNUIHBzZXVkb3RpbWUqKiBhbmQgKipNb25vY2xlMyBwc2V1ZG90aW1lKiogZnJvbSByZWZlcmVuY2UKLSBUcmFuc2ZlcnMgKiptaWxlc3RvbmUgbGFiZWxzKiogKE0wMOKAk00wNikgc28gcG9zaXRpb25zIGNhbiBiZSBjb21wYXJlZCB3aXRoCiAgdGhlIDctbWlsZXN0b25lIHN0cnVjdHVyZSBjb25maXJtZWQgaW4gU3RlcCAxCi0gUHJvZHVjZXMgdmlzdWFsaXNhdGlvbnMgaWRlbnRpY2FsIGluIHN0eWxlIHRvIHByZXZpb3VzIHJlc3VsdHMgc28geW91IGNhbgogIGRpcmVjdGx5IGNvbXBhcmUgdGhpcyBydW4gKDcgbWlsZXN0b25lcykgd2l0aCB0aGUgcHJldmlvdXMgcnVuCgoqKlJlZmVyZW5jZSBtaWxlc3RvbmUgc3RydWN0dXJlIChhbHJlYWR5IGNvbmZpcm1lZCBpbiBTdGVwIDEpOioqCmBgYApNMDAgPSBDRDQgTmFpdmUgICAgICAoMjAzNykKTTAxID0gQ0Q0IFRDTSBlYXJseSAgKDQ3MTcpCk0wMiA9IENENCBUQ00gbGF0ZSAgICg0MzUwKQpNMDMgPSBDRDQgVEVNICAgICAgICAoMTQ1KQpNMDQgPSBDRDQgVGVtcmEvQ1RMICAoMTApCk0wNSA9IFRyZWcgcmVzdGluZyAgICgxNDYpCk0wNiA9IFRyZWcgZWZmZWN0b3IgICg2MSkKYGBgCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMgU2V0dXAKCmBgYHtyIGxpYnJhcmllc30Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKICBsaWJyYXJ5KFNldXJhdCkKICBsaWJyYXJ5KFNldXJhdFdyYXBwZXJzKQogIGxpYnJhcnkobW9ub2NsZTMpCiAgbGlicmFyeShpZ3JhcGgpCiAgbGlicmFyeShnZ3Bsb3QyKQogIGxpYnJhcnkoZ2dyZXBlbCkKICBsaWJyYXJ5KGRwbHlyKQogIGxpYnJhcnkodGlkeXIpCiAgbGlicmFyeShwYXRjaHdvcmspCiAgbGlicmFyeSh2aXJpZGlzKQogIGxpYnJhcnkoc2NhbGVzKQogIGxpYnJhcnkoUkNvbG9yQnJld2VyKQogIGxpYnJhcnkoa25pdHIpCiAgbGlicmFyeShrYWJsZUV4dHJhKQp9KQoKIyDilIDilIAgTXVzdCBtYXRjaCBTdGVwIDEgZXhhY3RseSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKU1RBVEVfQ09MT1JTIDwtIGMoCiAgIkNENCBOYWl2ZSIgICAgID0gIiM0NDcyQzQiLAogICJDRDQgVENNIiAgICAgICA9ICIjNzBBRDQ3IiwKICAiQ0Q0IFRFTSIgICAgICAgPSAiI0VEN0QzMSIsCiAgIkNENCBUZW1yYS9DVEwiID0gIiNDMDAwMDAiLAogICJUcmVnIiAgICAgICAgICA9ICIjNzAzMEEwIgopCgpDRUxMX0xJTkVfQ09MT1JTIDwtIHNldE5hbWVzKAogIGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCg4LCJEYXJrMiIpKSg3KSwKICBwYXN0ZTAoIkwiLCAxOjcpCikKCk1JTEVTVE9ORV9DT0xPUlMgPC0gc2V0TmFtZXMoCiAgYygiIzQ0NzJDNCIsICAgICAgICAgICAgIyBNMDAgTmFpdmUKICAgICIjNzBBRDQ3IiwiI0E5RDE4RSIsICAjIE0wMS9NMDIgVENNIGVhcmx5L2xhdGUKICAgICIjRUQ3RDMxIiwgICAgICAgICAgICAjIE0wMyBURU0KICAgICIjQzAwMDAwIiwgICAgICAgICAgICAjIE0wNCBUZW1yYQogICAgIiM3MDMwQTAiLCIjQjRBMEQ0IiksICMgTTA1L00wNiBUcmVnCiAgc3ByaW50ZigiTSUwMmQiLCAwOjYpCikKCk1JTEVTVE9ORV9MQUJFTFMgPC0gYygKICBNMDAgPSAiTTAwIE5haXZlIiwKICBNMDEgPSAiTTAxIFRDTShlYXJseSkiLAogIE0wMiA9ICJNMDIgVENNKGxhdGUpIiwKICBNMDMgPSAiTTAzIFRFTSIsCiAgTTA0ID0gIk0wNCBUZW1yYSIsCiAgTTA1ID0gIk0wNSBUcmVnKHJlc3QpIiwKICBNMDYgPSAiTTA2IFRyZWcoZWZmKSIKKQoKU1RBVEVfQ09MICA8LSAicHJlZGljdGVkLmNlbGx0eXBlLmwyIgpVTUFQX05BTUUgIDwtICJ1bWFwIgpDRUxMX0xJTkVTIDwtIHBhc3RlMCgiTCIsIDE6NykKCk1JTEVTVE9ORV9PUkRFUiA8LSBzcHJpbnRmKCJNJTAyZCIsIDA6NikKCmNhdCgi4pyTIFNldHVwIGNvbXBsZXRlXG4iKQpgYGAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBMb2FkIFJlZmVyZW5jZSBPYmplY3RzIChTdGVwIDEgb3V0cHV0cyDigJQgbm90IHJlLXJ1bikKCmBgYHtyIGxvYWQtcmVmZXJlbmNlfQojIOKUgOKUgCBMb2FkIHRoZSByZWZlcmVuY2UgU2V1cmF0IG9iamVjdCB3aXRoIGZyb3plbiBVTUFQIG1vZGVsIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApjZDRfcmVmIDwtIHJlYWRSRFMoIi4uLy4uLzEtQ3VzdG9tX01TVC9PYmplY3RzL2NkNF9yZWZfZHVhbF90cmFqZWN0b3J5LnJkcyIpCgojIOKUgOKUgCBMb2FkIE1TVCBncmFwaCBhbmQgY2VudHJvaWRzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAptc3RfZ3JhcGggICAgICAgICAgIDwtIHJlYWRSRFMoIi4uLy4uLzEtQ3VzdG9tX01TVC9PYmplY3RzL21zdF9ncmFwaC5yZHMiKQptaWxlc3RvbmVfY2VudHJvaWRzIDwtIHJlYWRSRFMoIi4uLy4uLzEtQ3VzdG9tX01TVC9PYmplY3RzL21pbGVzdG9uZV9jZW50cm9pZHMucmRzIikKCiMg4pSA4pSAIFZhbGlkYXRlIG1pbGVzdG9uZSBzdHJ1Y3R1cmUg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACmV4cGVjdGVkX21zIDwtIHNwcmludGYoIk0lMDJkIiwgMDo2KQphY3R1YWxfbXMgICA8LSBzb3J0KHVuaXF1ZShuYS5vbWl0KGNkNF9yZWZAbWV0YS5kYXRhJG1pbGVzdG9uZSkpKQpzdG9waWZub3QoCiAgIk1pbGVzdG9uZSBtaXNtYXRjaCDigJQgcmUtcnVuIFN0ZXAgMSBmaXJzdCIgPSBpZGVudGljYWwoYWN0dWFsX21zLCBleHBlY3RlZF9tcyksCiAgIm1zdF9wc2V1ZG90aW1lX25vcm0gbWlzc2luZyIgICAgICAgICAgICAgID0gIm1zdF9wc2V1ZG90aW1lX25vcm0iICVpbiUgY29sbmFtZXMoY2Q0X3JlZkBtZXRhLmRhdGEpLAogICJtb25vY2xlM19wc2V1ZG90aW1lX25vcm0gbWlzc2luZyIgICAgICAgICA9ICJtb25vY2xlM19wc2V1ZG90aW1lX25vcm0iICVpbiUgY29sbmFtZXMoY2Q0X3JlZkBtZXRhLmRhdGEpLAogICJVTUFQIG1vZGVsIG1pc3NpbmcgZnJvbSBjZDRfcmVmIiAgICAgICAgICA9ICFpcy5udWxsKGNkNF9yZWZAcmVkdWN0aW9uc1tbVU1BUF9OQU1FXV1AbWlzYyRtb2RlbCkKKQoKY2F0KCLinIUgUmVmZXJlbmNlIG9iamVjdHMgbG9hZGVkIGFuZCB2YWxpZGF0ZWRcbiIpCmNhdChzcHJpbnRmKCIgICAlZCByZWZlcmVuY2UgY2VsbHMgfCAlZCBtaWxlc3RvbmVzXG4iLCBuY29sKGNkNF9yZWYpLCBsZW5ndGgoYWN0dWFsX21zKSkpCmNhdChzcHJpbnRmKCIgICBNU1Q6ICVkIG5vZGVzLCAlZCBlZGdlc1xuIiwgdmNvdW50KG1zdF9ncmFwaCksIGVjb3VudChtc3RfZ3JhcGgpKSkKY2F0KCJcbk1pbGVzdG9uZSBzdHJ1Y3R1cmUgZnJvbSBTdGVwIDE6XG4iKQpwcmludChtaWxlc3RvbmVfY2VudHJvaWRzWywgYygibWlsZXN0b25lIiwic3RhdGUiLCJuX2NlbGxzIildKQoKIyDilIDilIAgQnVpbGQgcmVmZXJlbmNlIFVNQVAgZGF0YSBmcmFtZSBmb3IgYmFja2dyb3VuZCBwbG90dGluZyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKcmVmX3VtYXBfZGYgICAgICAgICAgIDwtIGFzLmRhdGEuZnJhbWUoRW1iZWRkaW5ncyhjZDRfcmVmLCBVTUFQX05BTUUpKQpjb2xuYW1lcyhyZWZfdW1hcF9kZikgPC0gYygiVU1BUF8xIiwiVU1BUF8yIikKcmVmX3VtYXBfZGYkc3RhdGUgICAgIDwtIGNkNF9yZWZAbWV0YS5kYXRhW1tTVEFURV9DT0xdXQpyZWZfdW1hcF9kZiRtaWxlc3RvbmUgPC0gY2Q0X3JlZkBtZXRhLmRhdGEkbWlsZXN0b25lCnJlZl91bWFwX2RmJG1zdF9wdCAgICA8LSBjZDRfcmVmQG1ldGEuZGF0YSRtc3RfcHNldWRvdGltZV9ub3JtCnJlZl91bWFwX2RmJG0zX3B0ICAgICA8LSBjZDRfcmVmQG1ldGEuZGF0YSRtb25vY2xlM19wc2V1ZG90aW1lX25vcm0KCiMg4pSA4pSAIE1TVCBlZGdlIGRhdGEgZnJhbWUgZm9yIG92ZXJsYXkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACm1zdF9lZGdlcyAgIDwtIGFzX2VkZ2VsaXN0KG1zdF9ncmFwaCkKbXN0X2VkZ2VfZGYgPC0gZG8uY2FsbChyYmluZCwgbGFwcGx5KHNlcV9sZW4obnJvdyhtc3RfZWRnZXMpKSwgZnVuY3Rpb24oaSkgewogIG0xIDwtIG1zdF9lZGdlc1tpLDFdOyBtMiA8LSBtc3RfZWRnZXNbaSwyXQogIHIxIDwtIG1pbGVzdG9uZV9jZW50cm9pZHNbbWlsZXN0b25lX2NlbnRyb2lkcyRtaWxlc3RvbmUgPT0gbTEsIF0KICByMiA8LSBtaWxlc3RvbmVfY2VudHJvaWRzW21pbGVzdG9uZV9jZW50cm9pZHMkbWlsZXN0b25lID09IG0yLCBdCiAgZGF0YS5mcmFtZSh4MT1yMSRVTUFQXzEsIHkxPXIxJFVNQVBfMiwgeDI9cjIkVU1BUF8xLCB5Mj1yMiRVTUFQXzIpCn0pKQpgYGAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBMb2FkIFPDqXphcnkgQ2VsbCBMaW5lcwoKYGBge3IgbG9hZC1zZXphcnl9CmFsbF9vYmogPC0gcmVhZFJEUygiL2hvbWUvbmFiYmFzaS9hcG9sbG9faG9tZS8xLVNldXJhdF9SRFNfT0JKRUNUX0ZJTkFML0FsbF9zYW1wbGVzX01lcmdlZF93aXRoX1JlbmFtZWRfQ2x1c3RlcnNfQ2VsbF9zdGF0ZS0wMy0xMi0yMDI1LnJkcy5yZHMiKQoKIyDilIDilIAgY2VsbF9saW5lIGNvbHVtbiBjb25maXJtZWQgcHJlc2VudCAoNDAsNjk1IGNlbGxzLCBMMeKAk0w3KSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKYWxsX29iaiRjZWxsX2xpbmUgPC0gYXMuY2hhcmFjdGVyKGFsbF9vYmokY2VsbF9saW5lKQpzZXphcnlfb2JqIDwtIHN1YnNldChhbGxfb2JqLCBzdWJzZXQgPSBjZWxsX2xpbmUgJWluJSBDRUxMX0xJTkVTKQpybShhbGxfb2JqKTsgZ2MoKQoKY2F0KHNwcmludGYoIlPDqXphcnkgY2VsbHMgbG9hZGVkOiAlZCB0b3RhbFxuIiwgbmNvbChzZXphcnlfb2JqKSkpCmNhdCgiUGVyIGNlbGwgbGluZTpcbiIpCnByaW50KHRhYmxlKHNlemFyeV9vYmokY2VsbF9saW5lKSkKCkRlZmF1bHRBc3NheShzZXphcnlfb2JqKSA8LSAiUk5BIgoKIyBTaGFyZWQgZ2VuZXMgd2l0aCByZWZlcmVuY2UgKGNvbmZpcm1lZCB+MzYsNjAxKQpzaGFyZWRfZ2VuZXMgPC0gaW50ZXJzZWN0KHJvd25hbWVzKHNlemFyeV9vYmopLCByb3duYW1lcyhjZDRfcmVmKSkKY2F0KHNwcmludGYoIlxuU2hhcmVkIGdlbmVzIChxdWVyeSDiiKkgcmVmZXJlbmNlKTogJWRcbiIsIGxlbmd0aChzaGFyZWRfZ2VuZXMpKSkKc3RvcGlmbm90KCJGZXdlciB0aGFuIDIwMDAgc2hhcmVkIGdlbmVzIOKAlCBjaGVjayBvYmplY3RzIiA9IGxlbmd0aChzaGFyZWRfZ2VuZXMpID49IDIwMDApCgojIOKUgOKUgCBDaGVjayBwZXJjZW50Lm10IGV4aXN0cyDigJQgbmVlZGVkIGZvciBTQ1RyYW5zZm9ybSB2YXJzLnRvLnJlZ3Jlc3Mg4pSA4pSA4pSA4pSA4pSA4pSACiMgSWYgcGVyY2VudC5tdCBpcyBhYnNlbnQsIFNDVCB3aWxsIHJ1biB3aXRob3V0IHJlZ3Jlc3NpbmcgaXQgKHNlZSBwZXItbGluZSBjaHVuaykKSEFTX1BDVF9NVCA8LSAicGVyY2VudC5tdCIgJWluJSBjb2xuYW1lcyhzZXphcnlfb2JqQG1ldGEuZGF0YSkKY2F0KHNwcmludGYoIlxucGVyY2VudC5tdCBpbiBtZXRhZGF0YTogJXNcbiIsIEhBU19QQ1RfTVQpKQpgYGAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBQZXItQ2VsbC1MaW5lIFNDVCArIFByb2plY3Rpb24KCioqUmF0aW9uYWxlIGZvciBwZXItY2VsbC1saW5lIFNDVDoqKiAgCkVhY2ggU8OpemFyeSBjZWxsIGxpbmUgaGFzIGl0cyBvd24gbGlicmFyeSBzaXplIGRpc3RyaWJ1dGlvbiBhbmQgdGVjaG5pY2FsCnZhcmlhdGlvbi4gUnVubmluZyBTQ1RyYW5zZm9ybSBvbiBlYWNoIGxpbmUgaW5kZXBlbmRlbnRseSBmaXRzIGEgbGluZS1zcGVjaWZpYwpyZWdyZXNzaW9uIG1vZGVsLCB3aGljaCBwcm9kdWNlcyBiZXR0ZXItY2FsaWJyYXRlZCByZXNpZHVhbHMgZm9yIGFuY2hvciBmaW5kaW5nLgpUaGlzIGdpdmVzIGBGaW5kVHJhbnNmZXJBbmNob3JzYCBtb3JlIHJlbGlhYmxlIGFuY2hvcnMgY29tcGFyZWQgdG8gbm9ybWFsaXNpbmcKYWxsIGxpbmVzIHRvZ2V0aGVyLCBhdCB0aGUgY29zdCBvZiBvbmUgU0NUIHJ1biBwZXIgbGluZSAofjMw4oCTNjAgcyBlYWNoKS4KCmBgYHtyIHBlci1saW5lLXByb2plY3Rpb24sIHJlc3VsdHM9J2hvbGQnfQoKcGxhbigic2VxdWVudGlhbCIpCm9wdGlvbnMoZnV0dXJlLmdsb2JhbHMubWF4U2l6ZSA9IDIwMDAwMCAqIDEwMjReMikgICMgMjAwIEdCIOKAlCBlZmZlY3RpdmVseSB1bmxpbWl0ZWQKCiMg4pSA4pSAIFN0ZXAgMTogQ2VsbCBjeWNsZSBzY29yaW5nIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApEZWZhdWx0QXNzYXkoc2V6YXJ5X29iaikgPC0gIlJOQSIKc2V6YXJ5X29iaiA8LSBOb3JtYWxpemVEYXRhKHNlemFyeV9vYmosIHZlcmJvc2U9RkFMU0UpCnNlemFyeV9vYmogPC0gQ2VsbEN5Y2xlU2NvcmluZygKICBzZXphcnlfb2JqLAogIHMuZmVhdHVyZXMgICA9IGNjLmdlbmVzLnVwZGF0ZWQuMjAxOSRzLmdlbmVzLAogIGcybS5mZWF0dXJlcyA9IGNjLmdlbmVzLnVwZGF0ZWQuMjAxOSRnMm0uZ2VuZXMsCiAgc2V0LmlkZW50ICAgID0gRkFMU0UKKQpjYXQoIkNlbGwgY3ljbGUgcGhhc2VzOlxuIik7IHByaW50KHRhYmxlKHNlemFyeV9vYmokUGhhc2UpKQoKIyDilIDilIAgU3RlcCAyOiBQZXItbGluZSBTQ1Qg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACkhBU19QQ1RfTVQgIDwtICJwZXJjZW50Lm10IiAlaW4lIGNvbG5hbWVzKHNlemFyeV9vYmpAbWV0YS5kYXRhKQpzZXphcnlfbGlzdCA8LSBTcGxpdE9iamVjdChzZXphcnlfb2JqLCBzcGxpdC5ieSA9ICJjZWxsX2xpbmUiKQoKc2V6YXJ5X2xpc3QgPC0gbGFwcGx5KHNlcV9hbG9uZyhzZXphcnlfbGlzdCksIGZ1bmN0aW9uKGkpIHsKICBjYXQoc3ByaW50ZigiICBTQ1Q6ICVzICglZCBjZWxscylcbiIsCiAgICAgICAgICAgICAgbmFtZXMoc2V6YXJ5X2xpc3QpW2ldLCBuY29sKHNlemFyeV9saXN0W1tpXV0pKSkKICBTQ1RyYW5zZm9ybSgKICAgIHNlemFyeV9saXN0W1tpXV0sCiAgICB2c3QuZmxhdm9yICAgICAgPSAidjIiLAogICAgdmFycy50by5yZWdyZXNzID0gYygiUy5TY29yZSIsICJHMk0uU2NvcmUiLAogICAgICAgICAgICAgICAgICAgICAgICBpZiAoSEFTX1BDVF9NVCkgInBlcmNlbnQubXQiIGVsc2UgTlVMTCksCiAgICB2ZXJib3NlICAgICAgICAgPSBGQUxTRQogICkKfSkKCnNlemFyeV9vYmogPC0gbWVyZ2Uoc2V6YXJ5X2xpc3RbWzFdXSwgc2V6YXJ5X2xpc3RbLTFdLCBtZXJnZS5kYXRhPVRSVUUpCmNhdChzcHJpbnRmKCJNZXJnZWQgcXVlcnk6ICVkIGNlbGxzXG4iLCBuY29sKHNlemFyeV9vYmopKSkKCiMg4pSA4pSAIFN0ZXAgMzogU2hhcmVkIGZlYXR1cmVzIGZyb20gcmVmZXJlbmNlIGludGVncmF0ZWQgYXNzYXkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACkRlZmF1bHRBc3NheShjZDRfcmVmKSA8LSAiaW50ZWdyYXRlZCIKcmVmX2ZlYXR1cmVzICAgICAgICAgIDwtIHJvd25hbWVzKGNkNF9yZWZbWyJpbnRlZ3JhdGVkIl1dQHNjYWxlLmRhdGEpCnF1ZXJ5X2dlbmVzICAgICAgICAgICA8LSByb3duYW1lcyhzZXphcnlfb2JqW1siU0NUIl1dKQpzaGFyZWRfZmVhdHVyZXMgICAgICAgPC0gaW50ZXJzZWN0KHJlZl9mZWF0dXJlcywgcXVlcnlfZ2VuZXMpCgpqdW5rX3BhdHRlcm4gICAgICAgICAgPC0gIl5SUEx8XlJQU3xeTVQtfF5IU1B8XlNOSEd8Xk1BTEFUMXxeTkVBVDF8XlhJU1R8XlRSQlZ8XlRSQVZ8XlRSR1Z8XlRSRFZ8XkhMQS0iCnNoYXJlZF9mZWF0dXJlc19jbGVhbiA8LSBzaGFyZWRfZmVhdHVyZXNbIWdyZXBsKGp1bmtfcGF0dGVybiwgc2hhcmVkX2ZlYXR1cmVzKV0KY2F0KHNwcmludGYoIlNoYXJlZCBmZWF0dXJlcyBhZnRlciBjbGVhbmluZzogJWRcbiIsIGxlbmd0aChzaGFyZWRfZmVhdHVyZXNfY2xlYW4pKSkKClZhcmlhYmxlRmVhdHVyZXMoc2V6YXJ5X29iaikgPC0gc2hhcmVkX2ZlYXR1cmVzX2NsZWFuCkRlZmF1bHRBc3NheShzZXphcnlfb2JqKSAgICAgPC0gIlNDVCIKCiMg4pSA4pSAIFN0ZXAgNDogRmluZFRyYW5zZmVyQW5jaG9ycyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKYW5jaG9ycyA8LSBGaW5kVHJhbnNmZXJBbmNob3JzKAogIHJlZmVyZW5jZSAgICAgICAgICAgID0gY2Q0X3JlZiwKICBxdWVyeSAgICAgICAgICAgICAgICA9IHNlemFyeV9vYmosCiAgZmVhdHVyZXMgICAgICAgICAgICAgPSBzaGFyZWRfZmVhdHVyZXNfY2xlYW4sCiAgbm9ybWFsaXphdGlvbi5tZXRob2QgPSAiU0NUIiwKICByZWZlcmVuY2UucmVkdWN0aW9uICA9ICJwY2EiLAogIHJlZHVjdGlvbiAgICAgICAgICAgID0gInBjYXByb2plY3QiLAogIGRpbXMgICAgICAgICAgICAgICAgID0gMTozMCwKICBrLmFuY2hvciAgICAgICAgICAgICA9IDEwLAogIGsuZmlsdGVyICAgICAgICAgICAgID0gNTAwLAogIGsuc2NvcmUgICAgICAgICAgICAgID0gMzAsCiAgdmVyYm9zZSAgICAgICAgICAgICAgPSBUUlVFCikKY2F0KHNwcmludGYoIkFuY2hvcnMgZm91bmQ6ICVkXG4iLCBucm93KGFuY2hvcnNAYW5jaG9ycykpKQoKIyDilIDilIAgU3RlcCA1OiBNYXBRdWVyeSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKc2V6YXJ5X29iaiA8LSBNYXBRdWVyeSgKICBhbmNob3JzZXQgICAgICAgICAgID0gYW5jaG9ycywKICBxdWVyeSAgICAgICAgICAgICAgID0gc2V6YXJ5X29iaiwKICByZWZlcmVuY2UgICAgICAgICAgID0gY2Q0X3JlZiwKICByZWZkYXRhICAgICAgICAgICAgID0gbGlzdCgKICAgIG1pbGVzdG9uZSA9IGNkNF9yZWZAbWV0YS5kYXRhJG1pbGVzdG9uZSwKICAgIHN0YXRlICAgICA9IGNkNF9yZWZAbWV0YS5kYXRhW1tTVEFURV9DT0xdXQogICksCiAgcmVmZXJlbmNlLnJlZHVjdGlvbiA9ICJwY2EiLAogIHJlZHVjdGlvbi5tb2RlbCAgICAgPSBVTUFQX05BTUUsCiAgdmVyYm9zZSAgICAgICAgICAgICA9IEZBTFNFCikKY2F0KHNwcmludGYoIk1hcFF1ZXJ5IGNvbXBsZXRlOiAlZCBjZWxsc1xuIiwgbmNvbChzZXphcnlfb2JqKSkpCgojIOKUgOKUgCBTdGVwIDY6IFRyYW5zZmVyIHBzZXVkb3RpbWUg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACnB0X21hdCAgICAgICAgICAgPC0gcmJpbmQoCiAgbXN0X3B0ID0gY2Q0X3JlZkBtZXRhLmRhdGEkbXN0X3BzZXVkb3RpbWVfbm9ybSwKICBtM19wdCAgPSBjZDRfcmVmQG1ldGEuZGF0YSRtb25vY2xlM19wc2V1ZG90aW1lX25vcm0KKQpjb2xuYW1lcyhwdF9tYXQpIDwtIGNvbG5hbWVzKGNkNF9yZWYpCgp3dF9yZWQgPC0gaWYgKCJyZWYucGNhIiAlaW4lIG5hbWVzKHNlemFyeV9vYmpAcmVkdWN0aW9ucykpICJyZWYucGNhIiBlbHNlICJwY2Fwcm9qZWN0IgpwdF90cmFuc2ZlciA8LSBUcmFuc2ZlckRhdGEoCiAgYW5jaG9yc2V0ICAgICAgICA9IGFuY2hvcnMsCiAgcmVmZGF0YSAgICAgICAgICA9IHB0X21hdCwKICB3ZWlnaHQucmVkdWN0aW9uID0gc2V6YXJ5X29ialtbd3RfcmVkXV0sCiAgZGltcyAgICAgICAgICAgICA9IDE6MzAKKQpwdF9kYXRhIDwtIEdldEFzc2F5RGF0YShwdF90cmFuc2ZlciwgbGF5ZXI9ImRhdGEiKQpjYXQoInB0IHJvd25hbWVzOiIsIHJvd25hbWVzKHB0X2RhdGEpLCAiXG4iKQpzZXphcnlfb2JqJG1zdF9wc2V1ZG90aW1lX25vcm0gICAgICA8LSBhcy5udW1lcmljKHB0X2RhdGFbIm1zdC1wdCIsIF0pCnNlemFyeV9vYmokbW9ub2NsZTNfcHNldWRvdGltZV9ub3JtIDwtIGFzLm51bWVyaWMocHRfZGF0YVsibTMtcHQiLCAgXSkKCiMg4pSA4pSAIFN0ZXAgNzogU3VtbWFyeSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKY2F0KCJcblByZWRpY3RlZCBzdGF0ZSBkaXN0cmlidXRpb246XG4iKQpwcmludCh0YWJsZShzZXphcnlfb2JqJHByZWRpY3RlZC5zdGF0ZSkpCmNhdCgiXG5QcmVkaWN0ZWQgbWlsZXN0b25lIGRpc3RyaWJ1dGlvbjpcbiIpCnByaW50KHRhYmxlKHNlemFyeV9vYmokcHJlZGljdGVkLm1pbGVzdG9uZSkpCmNhdCgiXG5NU1QgcHNldWRvdGltZSByYW5nZToiLCByb3VuZChyYW5nZShzZXphcnlfb2JqJG1zdF9wc2V1ZG90aW1lX25vcm0sIG5hLnJtPVRSVUUpLCAxKSwgIlxuIikKY2F0KCJcbuKchSBQcm9qZWN0aW9uIGNvbXBsZXRlXG4iKQoKCmNhdChzcHJpbnRmKCLinIUgQW5jaG9ycyBmb3VuZDogJWQgYW5jaG9yIHBhaXJzXG4iLCBucm93KGFuY2hvcnNAYW5jaG9ycykpKQpjYXQoc3ByaW50ZigiQ2VsbHMgcHJvamVjdGVkOiAlZFxuIiwgbmNvbChzZXphcnlfb2JqKSkpCmNhdChzcHJpbnRmKCJNZWFuIHByZWRpY3Rpb24gc2NvcmU6ICUuM2YgKD4wLjUgPSByZWxpYWJsZSwgPjAuNyA9IGNvbmZpZGVudClcbiIsCiAgICAgICAgICAgIG1lYW4oc2V6YXJ5X29iaiRwcmVkaWN0ZWQuc3RhdGUuc2NvcmUsIG5hLnJtPVRSVUUpKSkKY2F0KHNwcmludGYoIkNlbGxzIHdpdGggc2NvcmUgPjAuNTogJWQgKCUuMWYlJSlcbiIsCiAgICAgICAgICAgIHN1bShzZXphcnlfb2JqJHByZWRpY3RlZC5zdGF0ZS5zY29yZSA+IDAuNSwgbmEucm09VFJVRSksCiAgICAgICAgICAgIDEwMCptZWFuKHNlemFyeV9vYmokcHJlZGljdGVkLnN0YXRlLnNjb3JlID4gMC41LCBuYS5ybT1UUlVFKSkpCgpjYXQoc3ByaW50ZigiQ2VsbHMgd2l0aCBzY29yZSA+MC43OiAlZCAoJS4xZiUlKVxuIiwKICAgICAgICAgICAgc3VtKHNlemFyeV9vYmokcHJlZGljdGVkLnN0YXRlLnNjb3JlID4gMC43LCBuYS5ybT1UUlVFKSwKICAgICAgICAgICAgMTAwKm1lYW4oc2V6YXJ5X29iaiRwcmVkaWN0ZWQuc3RhdGUuc2NvcmUgPiAwLjcsIG5hLnJtPVRSVUUpKSkKCgpjYXQoc3ByaW50ZigiQ2VsbHMgd2l0aCBzY29yZSA+MC41OiAlZCAoJS4xZiUlKVxuIiwKICAgICAgICAgICAgc3VtKHNlemFyeV9vYmokcHJlZGljdGVkLm1pbGVzdG9uZS5zY29yZSA+IDAuNSwgbmEucm09VFJVRSksCiAgICAgICAgICAgIDEwMCptZWFuKHNlemFyeV9vYmokcHJlZGljdGVkLm1pbGVzdG9uZS5zY29yZSA+IDAuNSwgbmEucm09VFJVRSkpKQoKY2F0KHNwcmludGYoIkNlbGxzIHdpdGggc2NvcmUgPjAuNzogJWQgKCUuMWYlJSlcbiIsCiAgICAgICAgICAgIHN1bShzZXphcnlfb2JqJHByZWRpY3RlZC5taWxlc3RvbmUuc2NvcmUgPiAwLjcsIG5hLnJtPVRSVUUpLAogICAgICAgICAgICAxMDAqbWVhbihzZXphcnlfb2JqJHByZWRpY3RlZC5taWxlc3RvbmUuc2NvcmUgPiAwLjcsIG5hLnJtPVRSVUUpKSkKCmBgYAoKCgpgYGB7ciBtZXJnZS1wcm9qZWN0ZWR9CnF1ZXJ5X3VtYXBfZGYgPC0gYXMuZGF0YS5mcmFtZShFbWJlZGRpbmdzKHNlemFyeV9vYmosICJyZWYudW1hcCIpKQpjb2xuYW1lcyhxdWVyeV91bWFwX2RmKSA8LSBjKCJVTUFQXzEiLCJVTUFQXzIiKQpxdWVyeV91bWFwX2RmJGNlbGxfbGluZSAgICAgICAgICAgPC0gc2V6YXJ5X29iaiRjZWxsX2xpbmUKcXVlcnlfdW1hcF9kZiRwcmVkaWN0ZWRfc3RhdGUgICAgIDwtIHNlemFyeV9vYmokcHJlZGljdGVkLnN0YXRlCnF1ZXJ5X3VtYXBfZGYkcHJlZGljdGVkX21pbGVzdG9uZSA8LSBzZXphcnlfb2JqJHByZWRpY3RlZC5taWxlc3RvbmUKcXVlcnlfdW1hcF9kZiRtc3RfcHQgICAgICAgICAgICAgIDwtIHNlemFyeV9vYmokbXN0X3BzZXVkb3RpbWVfbm9ybQpxdWVyeV91bWFwX2RmJG0zX3B0ICAgICAgICAgICAgICAgPC0gc2V6YXJ5X29iaiRtb25vY2xlM19wc2V1ZG90aW1lX25vcm0KCmNhdChzcHJpbnRmKCJUb3RhbCBjZWxsczogJWRcbiIsIG5yb3cocXVlcnlfdW1hcF9kZikpKQpjYXQoIlBlciBjZWxsIGxpbmU6XG4iKQpwcmludCh0YWJsZShxdWVyeV91bWFwX2RmJGNlbGxfbGluZSkpCmNhdCgiXG5NaWxlc3RvbmUgZGlzdHJpYnV0aW9uOlxuIikKcHJpbnQodGFibGUocXVlcnlfdW1hcF9kZiRwcmVkaWN0ZWRfbWlsZXN0b25lLCB1c2VOQT0iaWZhbnkiKSkKCmBgYAoKLS0tCgpgYGB7ciBzdW1tYXJ5LXRhYmxlLCBmaWcud2lkdGg9MjAsIGZpZy5oZWlnaHQ9OH0KdHJhbnNmZXJfc3VtbWFyeSA8LSBxdWVyeV91bWFwX2RmICU+JQogIGdyb3VwX2J5KGNlbGxfbGluZSkgJT4lCiAgc3VtbWFyaXNlKAogICAgbl9jZWxscyAgICAgICA9IG4oKSwKICAgIG1zdF9wdF9tZWFuICAgPSByb3VuZChtZWFuKG1zdF9wdCwgbmEucm09VFJVRSksIDEpLAogICAgbXN0X3B0X21lZCAgICA9IHJvdW5kKG1lZGlhbihtc3RfcHQsIG5hLnJtPVRSVUUpLCAxKSwKICAgIG0zX3B0X21lYW4gICAgPSByb3VuZChtZWFuKG0zX3B0LCBuYS5ybT1UUlVFKSwgMSksCiAgICBtM19wdF9tZWQgICAgID0gcm91bmQobWVkaWFuKG0zX3B0LCBuYS5ybT1UUlVFKSwgMSksCiAgICB0b3BfbWlsZXN0b25lID0gbmFtZXMoc29ydCh0YWJsZShwcmVkaWN0ZWRfbWlsZXN0b25lKSwgZGVjcmVhc2luZz1UUlVFKSlbMV0sCiAgICAuZ3JvdXBzICAgICAgID0gImRyb3AiCiAgKQoKbXNfd2lkZSA8LSBxdWVyeV91bWFwX2RmICU+JQogIGZpbHRlcighaXMubmEocHJlZGljdGVkX21pbGVzdG9uZSkpICU+JQogIGNvdW50KGNlbGxfbGluZSwgcHJlZGljdGVkX21pbGVzdG9uZSkgJT4lCiAgZ3JvdXBfYnkoY2VsbF9saW5lKSAlPiUKICBtdXRhdGUocGN0ID0gcm91bmQoMTAwICogbiAvIHN1bShuKSwgMSkpICU+JQogIHNlbGVjdChjZWxsX2xpbmUsIHByZWRpY3RlZF9taWxlc3RvbmUsIHBjdCkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbT1wcmVkaWN0ZWRfbWlsZXN0b25lLCB2YWx1ZXNfZnJvbT1wY3QsIHZhbHVlc19maWxsPTApCgpmb3IgKG0gaW4gTUlMRVNUT05FX09SREVSKSB7CiAgaWYgKCFtICVpbiUgY29sbmFtZXMobXNfd2lkZSkpIG1zX3dpZGVbW21dXSA8LSAwCn0KbXNfd2lkZSAgICAgIDwtIG1zX3dpZGVbLCBjKCJjZWxsX2xpbmUiLCBNSUxFU1RPTkVfT1JERVIpXQpmdWxsX3N1bW1hcnkgPC0gbGVmdF9qb2luKHRyYW5zZmVyX3N1bW1hcnksIG1zX3dpZGUsIGJ5PSJjZWxsX2xpbmUiKQoKa2FibGUoZnVsbF9zdW1tYXJ5LAogICAgICBjYXB0aW9uID0gIlPDqXphcnkgcHJvamVjdGlvbiBzdW1tYXJ5IOKAlCBwc2V1ZG90aW1lIGFuZCBtaWxlc3RvbmUgY29tcG9zaXRpb24iLAogICAgICBkaWdpdHMgID0gMSkgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucz1jKCJzdHJpcGVkIiwiaG92ZXIiLCJjb25kZW5zZWQiKSwKICAgICAgICAgICAgICAgIGZ1bGxfd2lkdGg9RkFMU0UpICU+JQogIGFkZF9oZWFkZXJfYWJvdmUoYygiICI9bmNvbCh0cmFuc2Zlcl9zdW1tYXJ5KSwKICAgICAgICAgICAgICAgICAgICAgIiUgY2VsbHMgcGVyIG1pbGVzdG9uZSI9bGVuZ3RoKE1JTEVTVE9ORV9PUkRFUikpKQpgYGAKCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMgVmlzdWFsaXNhdGlvbnMgey50YWJzZXR9CgojIyBSZWZlcmVuY2UgVU1BUCDigJQgbWlsZXN0b25lcwoKYGBge3IgdmlzLXJlZi1taWxlc3RvbmVzLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9OH0KcF9yZWZfbXMgPC0gZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHJlZl91bWFwX2RmW3NhbXBsZShucm93KHJlZl91bWFwX2RmKSksXSwKICAgICAgICAgICAgIGFlcyh4PVVNQVBfMSwgeT1VTUFQXzIsIGNvbG91cj1zdGF0ZSksIHNpemU9LjQsIGFscGhhPS41KSArCiAgZ2VvbV9zZWdtZW50KGRhdGE9bXN0X2VkZ2VfZGYsCiAgICAgICAgICAgICAgIGFlcyh4PXgxLHk9eTEseGVuZD14Mix5ZW5kPXkyKSwKICAgICAgICAgICAgICAgY29sb3VyPSJibGFjayIsIGxpbmV3aWR0aD0xLCBhbHBoYT0uODUsIGxpbmVlbmQ9InJvdW5kIikgKwogIGdlb21fcG9pbnQoZGF0YT1taWxlc3RvbmVfY2VudHJvaWRzLAogICAgICAgICAgICAgYWVzKHg9VU1BUF8xLHk9VU1BUF8yLGZpbGw9c3RhdGUpLAogICAgICAgICAgICAgc2hhcGU9MjEsIHNpemU9OCwgY29sb3VyPSJ3aGl0ZSIsIHN0cm9rZT0yKSArCiAgZ2VvbV90ZXh0X3JlcGVsKGRhdGE9bWlsZXN0b25lX2NlbnRyb2lkcywKICAgICAgICAgICAgICAgICAgYWVzKHg9VU1BUF8xLHk9VU1BUF8yLAogICAgICAgICAgICAgICAgICAgICAgbGFiZWw9cGFzdGUwKG1pbGVzdG9uZSwiXG4oIixNSUxFU1RPTkVfTEFCRUxTW21pbGVzdG9uZV0sIikiKSksCiAgICAgICAgICAgICAgICAgIHNpemU9Mi44LCBmb250ZmFjZT0iYm9sZCIsCiAgICAgICAgICAgICAgICAgIGJnLmNvbG9yPSJncmV5ODAiLCBiZy5yPS4xNSwgbWF4Lm92ZXJsYXBzPTIwKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXM9U1RBVEVfQ09MT1JTLCBuYW1lPSJTdGF0ZSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9U1RBVEVfQ09MT1JTLCBndWlkZT0ibm9uZSIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGxhYnMoeD0iVU1BUC0xIiwgeT0iVU1BUC0yIiwKICAgICAgIHRpdGxlPSJSZWZlcmVuY2UgQ0Q0IFQgY2VsbHMg4oCUIDctbWlsZXN0b25lIHN0cnVjdHVyZSIsCiAgICAgICBzdWJ0aXRsZT0iTTAwPU5haXZlIHwgTTAxL00wMj1UQ00gfCBNMDM9VEVNIHwgTTA0PVRlbXJhIHwgTTA1L00wNj1UcmVnIikgKwogIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTMsZmFjZT0iYm9sZCIpKQoKcHJpbnQocF9yZWZfbXMpCgpgYGAKCmBgYHtyICwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Nn0KcF9yZWZfbXMgPC0gZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHJlZl91bWFwX2RmW3NhbXBsZShucm93KHJlZl91bWFwX2RmKSksXSwKICAgICAgICAgICAgIGFlcyh4PVVNQVBfMSwgeT1VTUFQXzIsIGNvbG91cj1zdGF0ZSksIHNpemU9LjQsIGFscGhhPS41KSArCiAgZ2VvbV9zZWdtZW50KGRhdGE9bXN0X2VkZ2VfZGYsCiAgICAgICAgICAgICAgIGFlcyh4PXgxLHk9eTEseGVuZD14Mix5ZW5kPXkyKSwKICAgICAgICAgICAgICAgY29sb3VyPSJibGFjayIsIGxpbmV3aWR0aD0xLCBhbHBoYT0uODUsIGxpbmVlbmQ9InJvdW5kIikgKwogIGdlb21fcG9pbnQoZGF0YT1taWxlc3RvbmVfY2VudHJvaWRzLAogICAgICAgICAgICAgYWVzKHg9VU1BUF8xLHk9VU1BUF8yLGZpbGw9c3RhdGUpLAogICAgICAgICAgICAgc2hhcGU9MjEsIHNpemU9OCwgY29sb3VyPSJ3aGl0ZSIsIHN0cm9rZT0yKSArCiAgZ2VvbV90ZXh0X3JlcGVsKGRhdGE9bWlsZXN0b25lX2NlbnRyb2lkcywKICAgICAgICAgICAgICAgICAgYWVzKHg9VU1BUF8xLHk9VU1BUF8yLAogICAgICAgICAgICAgICAgICAgICAgbGFiZWw9cGFzdGUwKG1pbGVzdG9uZSwiXG4oIixNSUxFU1RPTkVfTEFCRUxTW21pbGVzdG9uZV0sIikiKSksCiAgICAgICAgICAgICAgICAgIHNpemU9Mi44LCBmb250ZmFjZT0iYm9sZCIsCiAgICAgICAgICAgICAgICAgIGJnLmNvbG9yPSJncmV5ODAiLCBiZy5yPS4xNSwgbWF4Lm92ZXJsYXBzPTIwKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXM9U1RBVEVfQ09MT1JTLCBuYW1lPSJTdGF0ZSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9U1RBVEVfQ09MT1JTLCBndWlkZT0ibm9uZSIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGxhYnMoeD0iVU1BUC0xIiwgeT0iVU1BUC0yIiwKICAgICAgIHRpdGxlPSJSZWZlcmVuY2UgQ0Q0IFQgY2VsbHMg4oCUIDctbWlsZXN0b25lIHN0cnVjdHVyZSIsCiAgICAgICBzdWJ0aXRsZT0iTTAwPU5haXZlIHwgTTAxL00wMj1UQ00gfCBNMDM9VEVNIHwgTTA0PVRlbXJhIHwgTTA1L00wNj1UcmVnIikgKwogIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTMsZmFjZT0iYm9sZCIpKQoKcHJpbnQocF9yZWZfbXMpCgpgYGAKCgoKCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02fQpwX2FsbF9saW5lcyA8LSBnZ3Bsb3QoKSArCiAgIyBSZWZlcmVuY2UgYmFja2dyb3VuZAogIGdlb21fcG9pbnQoZGF0YSA9IHJlZl91bWFwX2RmW3NhbXBsZShucm93KHJlZl91bWFwX2RmKSksXSwKICAgICAgICAgICAgIGFlcyh4PVVNQVBfMSwgeT1VTUFQXzIpLAogICAgICAgICAgICAgY29sb3VyPSJncmV5NjgiLCBzaXplPS4yNSwgYWxwaGE9LjQpICsKICAjIE1TVCB0cmFqZWN0b3J5IGxpbmVzCiAgZ2VvbV9zZWdtZW50KGRhdGEgPSBtc3RfZWRnZV9kZiwKICAgICAgICAgICAgICAgYWVzKHg9eDEsIHk9eTEsIHhlbmQ9eDIsIHllbmQ9eTIpLAogICAgICAgICAgICAgICBjb2xvdXI9ImdyZXkzMCIsIGxpbmV3aWR0aD0xLCBhbHBoYT0uOCwgbGluZWVuZD0icm91bmQiKSArCiAgIyBTw6l6YXJ5IGNlbGxzIGNvbG91cmVkIGJ5IGNlbGwgbGluZQogIGdlb21fcG9pbnQoZGF0YSA9IHF1ZXJ5X3VtYXBfZGZbc2FtcGxlKG5yb3cocXVlcnlfdW1hcF9kZikpLF0sCiAgICAgICAgICAgICBhZXMoeD1VTUFQXzEsIHk9VU1BUF8yLCBjb2xvdXI9Y2VsbF9saW5lKSwKICAgICAgICAgICAgIHNpemU9MS41LCBhbHBoYT0uNzUpICsKICAjIE1pbGVzdG9uZSBsYWJlbHMgdXNpbmcgY29uZmlybWVkIDctbWlsZXN0b25lIG5hbWVzCiAgZ2VvbV9sYWJlbF9yZXBlbChkYXRhID0gbWlsZXN0b25lX2NlbnRyb2lkcywKICAgICAgICAgICAgICAgICAgIGFlcyh4PVVNQVBfMSwgeT1VTUFQXzIsCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWw9cGFzdGUwKG1pbGVzdG9uZSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTUlMRVNUT05FX0xBQkVMU1ttaWxlc3RvbmVdKSksCiAgICAgICAgICAgICAgICAgICBzaXplPTIuNSwgZm9udGZhY2U9ImJvbGQiLAogICAgICAgICAgICAgICAgICAgZmlsbD0id2hpdGUiLCBjb2xvdXI9ImdyZXkxNSIsCiAgICAgICAgICAgICAgICAgICBsYWJlbC5zaXplPTAuMiwgbWF4Lm92ZXJsYXBzPTIwLAogICAgICAgICAgICAgICAgICAgYm94LnBhZGRpbmc9MC41KSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXM9Q0VMTF9MSU5FX0NPTE9SUywgbmFtZT0iQ2VsbCBsaW5lIikgKwogIGd1aWRlcyhjb2xvdXI9Z3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcz1saXN0KHNpemU9NCwgYWxwaGE9MSkpKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBsYWJzKHg9IlVNQVAtMSIsIHk9IlVNQVAtMiIsCiAgICAgICB0aXRsZT0iU8OpemFyeSBjZWxsIGxpbmVzIOKAlCBwcm9qZWN0aW9uIG9udG8gaGVhbHRoeSBDRDQgVCBjZWxsIHJlZmVyZW5jZSIsCiAgICAgICBzdWJ0aXRsZT1zcHJpbnRmKCJHcmV5ID0gaGVhbHRoeSByZWZlcmVuY2UgKCVkIGNlbGxzKSB8IENvbG91cmVkID0gU8OpemFyeSBMMeKAk0w3ICglZCBjZWxscykgfCBMaW5lcyA9IE1TVCB0cmFqZWN0b3J5IiwKICAgICAgICAgICAgICAgICAgICAgICAgbnJvdyhyZWZfdW1hcF9kZiksIG5yb3cocXVlcnlfdW1hcF9kZikpKSArCiAgdGhlbWUocGxvdC50aXRsZSAgICA9IGVsZW1lbnRfdGV4dChzaXplPTEzLCBmYWNlPSJib2xkIiksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTksICBjb2xvdXI9ImdyZXk0MCIpLAogICAgICAgIGxlZ2VuZC50aXRsZSAgPSBlbGVtZW50X3RleHQoc2l6ZT0xMSwgZmFjZT0iYm9sZCIpLAogICAgICAgIGxlZ2VuZC50ZXh0ICAgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCkpCgpwcmludChwX2FsbF9saW5lcykKCmBgYAoKIyMgQWxsIExpbmVzIOKAlCBQb3NpdGlvbiBvbiBSZWZlcmVuY2UgVU1BUAoKYGBge3IgdmlzLWFsbC1saW5lcy11bWFwLCBmaWcud2lkdGg9MTQsIGZpZy5oZWlnaHQ9OX0KcF9hbGxfbGluZXMgPC0gZ2dwbG90KCkgKwogICMgUmVmZXJlbmNlIGJhY2tncm91bmQgKGdyZXkpCiAgZ2VvbV9wb2ludChkYXRhPXJlZl91bWFwX2RmLAogICAgICAgICAgICAgYWVzKHg9VU1BUF8xLHk9VU1BUF8yKSwgY29sb3VyPSJncmV5NjgiLCBzaXplPS4yNSwgYWxwaGE9LjYpICsKICAjIE1TVCBvdmVybGF5CiAgZ2VvbV9zZWdtZW50KGRhdGE9bXN0X2VkZ2VfZGYsCiAgICAgICAgICAgICAgIGFlcyh4PXgxLHk9eTEseGVuZD14Mix5ZW5kPXkyKSwKICAgICAgICAgICAgICAgY29sb3VyPSJncmV5MzAiLCBsaW5ld2lkdGg9LjcsIGFscGhhPS43LCBsaW5lZW5kPSJyb3VuZCIpICsKICAjIFF1ZXJ5IGNlbGxzIGNvbG91cmVkIGJ5IGNlbGwgbGluZQogIGdlb21fcG9pbnQoZGF0YT1xdWVyeV91bWFwX2RmW3NhbXBsZShucm93KHF1ZXJ5X3VtYXBfZGYpKSxdLAogICAgICAgICAgICAgYWVzKHg9VU1BUF8xLHk9VU1BUF8yLGNvbG91cj1jZWxsX2xpbmUpLCBzaXplPTEuMiwgYWxwaGE9Ljc1KSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXM9Q0VMTF9MSU5FX0NPTE9SUywgbmFtZT0iQ2VsbCBsaW5lIikgKwogICMgTWlsZXN0b25lIGxhYmVscwogIGdlb21fdGV4dF9yZXBlbChkYXRhPW1pbGVzdG9uZV9jZW50cm9pZHMsCiAgICAgICAgICAgICAgICAgIGFlcyh4PVVNQVBfMSx5PVVNQVBfMixsYWJlbD1taWxlc3RvbmUpLAogICAgICAgICAgICAgICAgICBzaXplPTMsIGZvbnRmYWNlPSJib2xkIiwgY29sb3VyPSJncmV5MjAiLAogICAgICAgICAgICAgICAgICBiZy5jb2xvcj0id2hpdGUiLCBiZy5yPS4xMiwgbWF4Lm92ZXJsYXBzPTE1KSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBsYWJzKHg9IlVNQVAtMSIseT0iVU1BUC0yIiwKICAgICAgIHRpdGxlPSJTw6l6YXJ5IEwx4oCTTDcgcHJvamVjdGVkIG9udG8gcmVmZXJlbmNlIFVNQVAiLAogICAgICAgc3VidGl0bGU9IkdyZXkgPSByZWZlcmVuY2UgfCBDb2xvdXJlZCA9IHF1ZXJ5IGNlbGwgbGluZXMiKSArCiAgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMyxmYWNlPSJib2xkIikpICsKICBmYWNldF93cmFwKH5jZWxsX2xpbmUsIG5jb2w9NCkKCnByaW50KHBfYWxsX2xpbmVzKQoKYGBgCgojIyBBbGwgTGluZXMg4oCUIE1TVCBQc2V1ZG90aW1lIG9uIFJlZmVyZW5jZSBVTUFQCgpgYGB7ciB2aXMtcHNldWRvdGltZS1tc3QsIGZpZy53aWR0aD0xNCwgZmlnLmhlaWdodD02fQojIFBhbmVsIDE6IHJlZmVyZW5jZSBwc2V1ZG90aW1lCnBfcmVmX3B0IDwtIGdncGxvdChyZWZfdW1hcF9kZltzYW1wbGUobnJvdyhyZWZfdW1hcF9kZikpLF0sCiAgICAgICAgICAgICAgICAgICAgYWVzKHg9VU1BUF8xLHk9VU1BUF8yLGNvbG91cj1tc3RfcHQpKSArCiAgZ2VvbV9wb2ludChzaXplPS4zLCBhbHBoYT0uNykgKwogIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oCiAgICBjb2xvdXJzPWMoIiMwRDA4ODciLCIjNkEwMEE4IiwiI0IxMkE5MCIsIiNFMTY0NjIiLCIjRkNBNjM2IiwiI0YwRjkyMSIpLAogICAgbmFtZT0iTVNUIHBzZXVkb3RpbWVcbigw4oCTMTAwKSIsIGxpbWl0cz1jKDAsMTAwKSwgbmEudmFsdWU9ImdyZXk4MCIpICsKICBnZW9tX3NlZ21lbnQoZGF0YT1tc3RfZWRnZV9kZixhZXMoeD14MSx5PXkxLHhlbmQ9eDIseWVuZD15MiksCiAgICAgICAgICAgICAgIGNvbG91cj0iYmxhY2siLGxpbmV3aWR0aD0uNixhbHBoYT0uNixpbmhlcml0LmFlcz1GQUxTRSkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgbGFicyh4PSJVTUFQLTEiLHk9IlVNQVAtMiIsdGl0bGU9IlJlZmVyZW5jZSDigJQgTVNUIHBzZXVkb3RpbWUiKSArCiAgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMixmYWNlPSJib2xkIikpCgojIFBhbmVsIDI6IHF1ZXJ5IHBzZXVkb3RpbWUgKGFsbCBsaW5lcyBjb21iaW5lZCkKcF9xdWVyeV9wdCA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChkYXRhPXJlZl91bWFwX2RmLCBhZXMoeD1VTUFQXzEseT1VTUFQXzIpLAogICAgICAgICAgICAgY29sb3VyPSJncmV5NzgiLCBzaXplPS4yLCBhbHBoYT0uNSkgKwogIGdlb21fcG9pbnQoZGF0YT1xdWVyeV91bWFwX2RmW3NhbXBsZShucm93KHF1ZXJ5X3VtYXBfZGYpKSxdLAogICAgICAgICAgICAgYWVzKHg9VU1BUF8xLHk9VU1BUF8yLGNvbG91cj1tc3RfcHQpLCBzaXplPTEsIGFscGhhPS44KSArCiAgc2NhbGVfY29sb3VyX2dyYWRpZW50bigKICAgIGNvbG91cnM9YygiIzBEMDg4NyIsIiM2QTAwQTgiLCIjQjEyQTkwIiwiI0UxNjQ2MiIsIiNGQ0E2MzYiLCIjRjBGOTIxIiksCiAgICBuYW1lPSJNU1QgcHNldWRvdGltZVxuKDDigJMxMDApIiwgbGltaXRzPWMoMCwxMDApLCBuYS52YWx1ZT0iZ3JleTgwIikgKwogIGdlb21fc2VnbWVudChkYXRhPW1zdF9lZGdlX2RmLGFlcyh4PXgxLHk9eTEseGVuZD14Mix5ZW5kPXkyKSwKICAgICAgICAgICAgICAgY29sb3VyPSJncmV5MzAiLGxpbmV3aWR0aD0uNixhbHBoYT0uNixpbmhlcml0LmFlcz1GQUxTRSkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgbGFicyh4PSJVTUFQLTEiLHk9IlVNQVAtMiIsdGl0bGU9IlPDqXphcnkgTDHigJNMNyDigJQgdHJhbnNmZXJyZWQgTVNUIHBzZXVkb3RpbWUiKSArCiAgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMixmYWNlPSJib2xkIikpCgpwcmludChwX3JlZl9wdCB8IHBfcXVlcnlfcHQpCgpgYGAKCiMjIFBlci1MaW5lIE1TVCBQc2V1ZG90aW1lIFZpb2xpbgoKYGBge3IgdmlzLXZpb2xpbi1tc3QsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTZ9CiMgTWlsZXN0b25lIG1lZGlhbiBsaW5lcyBmb3IgcmVmZXJlbmNlCm1zX21lZGlhbnMgPC0gY2Q0X3JlZkBtZXRhLmRhdGEgJT4lCiAgZ3JvdXBfYnkobWlsZXN0b25lKSAlPiUKICBzdW1tYXJpc2UobWVkID0gbWVkaWFuKG1zdF9wc2V1ZG90aW1lX25vcm0sIG5hLnJtPVRSVUUpLCAuZ3JvdXBzPSJkcm9wIikgJT4lCiAgZmlsdGVyKG1pbGVzdG9uZSAlaW4lIGMoIk0wMCIsIk0wMSIsIk0wMiIsIk0wMyIsIk0wNCIsIk0wNSIsIk0wNiIpKQoKdmlvbGluX2RmIDwtIGRhdGEuZnJhbWUoCiAgY2VsbF9saW5lID0gc2V6YXJ5X29iaiRjZWxsX2xpbmUsCiAgbXN0X3B0ICAgID0gc2V6YXJ5X29iaiRtc3RfcHNldWRvdGltZV9ub3JtLAogIG0zX3B0ICAgICA9IHNlemFyeV9vYmokbW9ub2NsZTNfcHNldWRvdGltZV9ub3JtLAogIG1pbGVzdG9uZSA9IHNlemFyeV9vYmokcHJlZGljdGVkLm1pbGVzdG9uZQopICU+JSBmaWx0ZXIoIWlzLm5hKG1zdF9wdCkpCgpwX3Zpb2xpbl9tc3QgPC0gZ2dwbG90KHZpb2xpbl9kZiwgYWVzKHg9Y2VsbF9saW5lLCB5PW1zdF9wdCwgZmlsbD1jZWxsX2xpbmUpKSArCiAgZ2VvbV92aW9saW4oc2NhbGU9IndpZHRoIiwgdHJpbT1GQUxTRSwgYWxwaGE9Ljg1KSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoPS4wOCwgZmlsbD0id2hpdGUiLCBvdXRsaWVyLnNpemU9LjMsIG91dGxpZXIuYWxwaGE9LjQpICsKICAjIFJlZmVyZW5jZSBtaWxlc3RvbmUgbWVkaWFuIGxpbmVzCiAgZ2VvbV9obGluZShkYXRhPW1zX21lZGlhbnMsCiAgICAgICAgICAgICBhZXMoeWludGVyY2VwdD1tZWQsIGxpbmV0eXBlPW1pbGVzdG9uZSksIGNvbG91cj0iZ3JleTQwIiwgbGluZXdpZHRoPS41KSArCiAgZ2VvbV90ZXh0KGRhdGE9bXNfbWVkaWFucywKICAgICAgICAgIGFlcyh4PTcuNiwgeT1tZWQsIGxhYmVsPW1pbGVzdG9uZSksCiAgICAgICAgICBzaXplPTIuOCwgaGp1c3Q9MCwgY29sb3VyPSJncmV5MjUiLAogICAgICAgICAgaW5oZXJpdC5hZXM9RkFMU0UpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9Q0VMTF9MSU5FX0NPTE9SUywgZ3VpZGU9Im5vbmUiKSArCiAgc2NhbGVfbGluZXR5cGVfbWFudWFsKHZhbHVlcz1yZXAoImRhc2hlZCIsNyksIGd1aWRlPSJub25lIikgKwogIGNvb3JkX2NhcnRlc2lhbih4bGltPWMoMC41LDguNSkpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGxhYnMoeD0iQ2VsbCBsaW5lIiwgeT0iTVNUIHBzZXVkb3RpbWUgKDDigJMxMDApIiwKICAgICAgIHRpdGxlPSJNU1QgcHNldWRvdGltZSBwZXIgU8OpemFyeSBjZWxsIGxpbmUiLAogICAgICAgc3VidGl0bGU9IkRhc2hlZCBsaW5lcyA9IHJlZmVyZW5jZSBtaWxlc3RvbmUgbWVkaWFucyAoTTAw4oCTTTA2KSIpICsKICB0aGVtZShwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTEzLGZhY2U9ImJvbGQiKSkKCnByaW50KHBfdmlvbGluX21zdCkKYGBgCgojIyBQZXItTGluZSBNb25vY2xlMyBQc2V1ZG90aW1lIFZpb2xpbgoKYGBge3IgdmlzLXZpb2xpbi1tMywgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9Nn0KIyBSZWZlcmVuY2UgbWlsZXN0b25lIG1lZGlhbnMg4oCUIE1vbm9jbGUzCm1zX21lZGlhbnNfbTMgPC0gY2Q0X3JlZkBtZXRhLmRhdGEgJT4lCiAgZ3JvdXBfYnkobWlsZXN0b25lKSAlPiUKICBzdW1tYXJpc2UobWVkID0gbWVkaWFuKG1vbm9jbGUzX3BzZXVkb3RpbWVfbm9ybSwgbmEucm09VFJVRSksIC5ncm91cHM9ImRyb3AiKQoKcF92aW9saW5fbTMgPC0gZ2dwbG90KHZpb2xpbl9kZiwgYWVzKHg9Y2VsbF9saW5lLCB5PW0zX3B0LCBmaWxsPWNlbGxfbGluZSkpICsKICBnZW9tX3Zpb2xpbihzY2FsZT0id2lkdGgiLCB0cmltPUZBTFNFLCBhbHBoYT0uODUpICsKICBnZW9tX2JveHBsb3Qod2lkdGg9LjA4LCBmaWxsPSJ3aGl0ZSIsIG91dGxpZXIuc2l6ZT0uMywgb3V0bGllci5hbHBoYT0uNCkgKwogIGdlb21faGxpbmUoZGF0YT1tc19tZWRpYW5zX20zLAogICAgICAgICAgICAgYWVzKHlpbnRlcmNlcHQ9bWVkLCBsaW5ldHlwZT1taWxlc3RvbmUpLCBjb2xvdXI9ImdyZXk0MCIsIGxpbmV3aWR0aD0uNSkgKwogIGdlb21fdGV4dChkYXRhPW1zX21lZGlhbnMsCiAgICAgICAgICBhZXMoeD03LjYsIHk9bWVkLCBsYWJlbD1taWxlc3RvbmUpLAogICAgICAgICAgc2l6ZT0yLjgsIGhqdXN0PTAsIGNvbG91cj0iZ3JleTI1IiwKICAgICAgICAgIGluaGVyaXQuYWVzPUZBTFNFKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPUNFTExfTElORV9DT0xPUlMsIGd1aWRlPSJub25lIikgKwogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXM9cmVwKCJkYXNoZWQiLDcpLCBndWlkZT0ibm9uZSIpICsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbT1jKDAuNSw4LjUpKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBsYWJzKHg9IkNlbGwgbGluZSIsIHk9Ik1vbm9jbGUzIHBzZXVkb3RpbWUgKDDigJMxMDApIiwKICAgICAgIHRpdGxlPSJNb25vY2xlMyBwc2V1ZG90aW1lIHBlciBTw6l6YXJ5IGNlbGwgbGluZSIsCiAgICAgICBzdWJ0aXRsZT0iRGFzaGVkIGxpbmVzID0gcmVmZXJlbmNlIG1pbGVzdG9uZSBtZWRpYW5zIChNMDDigJNNMDYpIikgKwogIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTMsZmFjZT0iYm9sZCIpKQoKcHJpbnQocF92aW9saW5fbTMpCmBgYAoKIyMgTWlsZXN0b25lIENvbXBvc2l0aW9uIHBlciBDZWxsIExpbmUKCmBgYHtyIHZpcy1taWxlc3RvbmUtYmFyLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD00fQptc19jb21wIDwtIHZpb2xpbl9kZiAlPiUKICBjb3VudChjZWxsX2xpbmUsIG1pbGVzdG9uZSkgJT4lCiAgZ3JvdXBfYnkoY2VsbF9saW5lKSAlPiUKICBtdXRhdGUocGN0ID0gMTAwICogbiAvIHN1bShuKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIGZpbHRlcighaXMubmEobWlsZXN0b25lKSkgJT4lCiAgbXV0YXRlKG1pbGVzdG9uZSA9IGZhY3RvcihtaWxlc3RvbmUsIGxldmVscz1zcHJpbnRmKCJNJTAyZCIsMDo2KSkpCgpwX21zX2JhciA8LSBnZ3Bsb3QobXNfY29tcCwgYWVzKHg9Y2VsbF9saW5lLCB5PXBjdCwgZmlsbD1taWxlc3RvbmUpKSArCiAgZ2VvbV9jb2wod2lkdGg9Ljc1KSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPU1JTEVTVE9ORV9DT0xPUlMsCiAgICAgICAgICAgICAgICAgICAgbGFiZWxzPU1JTEVTVE9ORV9MQUJFTFMsIG5hbWU9Ik1pbGVzdG9uZSIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGxhYnMoeD0iQ2VsbCBsaW5lIiwgeT0iJSBjZWxscyIsCiAgICAgICB0aXRsZT0iTWlsZXN0b25lIGNvbXBvc2l0aW9uIHBlciBTw6l6YXJ5IGNlbGwgbGluZSIsCiAgICAgICBzdWJ0aXRsZT0iQmFzZWQgb24gdHJhbnNmZXJyZWQgbWlsZXN0b25lIGxhYmVscyBmcm9tIHJlZmVyZW5jZSIpICsKICB0aGVtZShwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTEzLGZhY2U9ImJvbGQiKSwKICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT05KSkKCnByaW50KHBfbXNfYmFyKQpgYGAKCmBgYHtyIG1pbGVzdG9uZS1oZWF0bWFwLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NX0KCiMgTWlsZXN0b25lIGxhYmVscyB3aXRoIGJpb2xvZ2ljYWwgYW5ub3RhdGlvbgpNSUxFU1RPTkVfTEFCRUxTX0ZVTEwgPC0gYygKICAiTTAwIiA9ICJNMDBcbk5haXZlIiwKICAiTTAxIiA9ICJNMDFcblRDTSBlYXJseSIsCiAgIk0wMiIgPSAiTTAyXG5UQ00gbGF0ZVxuKGJyYW5jaCkiLAogICJNMDMiID0gIk0wM1xuVEVNIiwKICAiTTA0IiA9ICJNMDRcblRlbXJhIiwKICAiTTA1IiA9ICJNMDVcblRyZWcocmVzdCkiLAogICJNMDYiID0gIk0wNlxuVHJlZyhlZmYpIgopCgojIENvbXB1dGUgbWlsZXN0b25lIGRpc3RyaWJ1dGlvbiBwZXIgY2VsbCBsaW5lCm1zX3Blcl9saW5lIDwtIHF1ZXJ5X3VtYXBfZGYgJT4lCiAgZmlsdGVyKCFpcy5uYShwcmVkaWN0ZWRfbWlsZXN0b25lKSkgJT4lCiAgY291bnQoY2VsbF9saW5lLCBwcmVkaWN0ZWRfbWlsZXN0b25lKSAlPiUKICBncm91cF9ieShjZWxsX2xpbmUpICU+JQogIG11dGF0ZShwY3QgPSByb3VuZCgxMDAgKiBuIC8gc3VtKG4pLCAxKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZShwcmVkaWN0ZWRfbWlsZXN0b25lID0gZmFjdG9yKHByZWRpY3RlZF9taWxlc3RvbmUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gTUlMRVNUT05FX09SREVSKSkKCiMg4pSA4pSAIEhlYXRtYXAgdGlsZSBwbG90OiBjZWxsIGxpbmUgw5cgbWlsZXN0b25lIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApwX21zX2hlYXRtYXAgPC0gZ2dwbG90KG1zX3Blcl9saW5lLAogICAgICAgICAgICAgICAgICAgICAgICBhZXMoeD1wcmVkaWN0ZWRfbWlsZXN0b25lLCB5PWNlbGxfbGluZSwgZmlsbD1wY3QpKSArCiAgZ2VvbV90aWxlKGNvbG91cj0id2hpdGUiLCBsaW5ld2lkdGg9LjUpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsPWlmZWxzZShwY3QgPj0gMiwgcGFzdGUwKHBjdCwgIiUiKSwgIiIpKSwKICAgICAgICAgICAgc2l6ZT0zLjIsIGZvbnRmYWNlPSJib2xkIiwKICAgICAgICAgICAgY29sb3VyPWlmZWxzZShtc19wZXJfbGluZSRwY3QgPiA0MCwgIndoaXRlIiwgImdyZXkyMCIpKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudG4oCiAgICBjb2xvdXJzID0gYygiI0Y3RkJGRiIsIiNERUVCRjciLCIjOUVDQUUxIiwiIzQyOTJDNiIsIiMwODUxOUMiLCIjMDgzMDZCIiksCiAgICBuYW1lICAgID0gIiUgb2YgY2VsbFxubGluZSBjZWxscyIsCiAgICBsaW1pdHMgID0gYygwLCAxMDApCiAgKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHM9TUlMRVNUT05FX0xBQkVMU19GVUxMKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBsYWJzKHg9IlJlZmVyZW5jZSBtaWxlc3RvbmUiLCB5PSJTw6l6YXJ5IGNlbGwgbGluZSIsCiAgICAgICB0aXRsZT0iTWlsZXN0b25lIGRpc3RyaWJ1dGlvbiBwZXIgU8OpemFyeSBjZWxsIGxpbmUiLAogICAgICAgc3VidGl0bGU9IkRhcmtlciA9IG1vcmUgY2VsbHMgfCBNMDIgPSBicmFuY2ggcG9pbnQgYmV0d2VlbiBlZmZlY3RvciBhbmQgcmVndWxhdG9yeSBhcm1zIikgKwogIHRoZW1lKHBsb3QudGl0bGUgICA9IGVsZW1lbnRfdGV4dChzaXplPTEzLCBmYWNlPSJib2xkIiksCiAgICAgICAgcGxvdC5zdWJ0aXRsZT0gZWxlbWVudF90ZXh0KHNpemU9OSwgIGNvbG91cj0iZ3JleTQwIiksCiAgICAgICAgYXhpcy50ZXh0LnggID0gZWxlbWVudF90ZXh0KHNpemU9OSksCiAgICAgICAgYXhpcy50ZXh0LnkgID0gZWxlbWVudF90ZXh0KHNpemU9MTEsIGZhY2U9ImJvbGQiKSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT05KSkKCnByaW50KHBfbXNfaGVhdG1hcCkKCmdnc2F2ZSgiRmlndXJlcy9maWdfbWlsZXN0b25lX2hlYXRtYXAucGRmIiwgcF9tc19oZWF0bWFwLCB3aWR0aD0xMCwgaGVpZ2h0PTUpCmBgYAoKCgoKYGBge3IgbWlsZXN0b25lLXN0YWNrLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD01fQoKIyBDb2xvdXJzIHBlciBtaWxlc3RvbmUg4oCUIGRlcml2ZWQgZnJvbSBzdGF0ZSBjb2xvdXJzCm1zX3N0YXRlX2NvbG9ycyA8LSBzZXROYW1lcygKICBTVEFURV9DT0xPUlNbbWlsZXN0b25lX2NlbnRyb2lkcyRzdGF0ZVsKICAgIG1hdGNoKE1JTEVTVE9ORV9PUkRFUiwgbWlsZXN0b25lX2NlbnRyb2lkcyRtaWxlc3RvbmUpXV0sCiAgTUlMRVNUT05FX09SREVSCikKCnBfbXNfc3RhY2sgPC0gZ2dwbG90KG1zX3Blcl9saW5lLAogICAgICAgICAgICAgICAgICAgICAgYWVzKHg9Y2VsbF9saW5lLCB5PXBjdCwgZmlsbD1wcmVkaWN0ZWRfbWlsZXN0b25lKSkgKwogIGdlb21fY29sKHdpZHRoPS43NSwgY29sb3VyPSJ3aGl0ZSIsIGxpbmV3aWR0aD0uMykgKwogIGdlb21fdGV4dChhZXMobGFiZWw9aWZlbHNlKHBjdCA+PSA1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlMChwcmVkaWN0ZWRfbWlsZXN0b25lLCAiXG4iLCBwY3QsICIlIiksICIiKSksCiAgICAgICAgICAgIHBvc2l0aW9uPXBvc2l0aW9uX3N0YWNrKHZqdXN0PTAuNSksCiAgICAgICAgICAgIHNpemU9Mi44LCBjb2xvdXI9IndoaXRlIiwgZm9udGZhY2U9ImJvbGQiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPW1zX3N0YXRlX2NvbG9ycywKICAgICAgICAgICAgICAgICAgICBsYWJlbHM9TUlMRVNUT05FX0xBQkVMU19GVUxMLAogICAgICAgICAgICAgICAgICAgIG5hbWU9Ik1pbGVzdG9uZSIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kPWMoMCwwKSwgbGltaXRzPWMoMCwxMDUpKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBsYWJzKHg9IkNlbGwgbGluZSIsIHk9IiUgb2YgY2VsbHMiLAogICAgICAgdGl0bGU9Ik1pbGVzdG9uZSBjb21wb3NpdGlvbiBwZXIgU8OpemFyeSBjZWxsIGxpbmUiLAogICAgICAgc3VidGl0bGU9IkNvbG91ciA9IENENCBzdGF0ZSB8IExhYmVsIHNob3duIGlmIOKJpSA1JSIpICsKICB0aGVtZShwbG90LnRpdGxlICA9IGVsZW1lbnRfdGV4dChzaXplPTEzLCBmYWNlPSJib2xkIiksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTksIGNvbG91cj0iZ3JleTQwIiksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xMiwgZmFjZT0iYm9sZCIpKQoKcHJpbnQocF9tc19zdGFjaykKCmdnc2F2ZSgiRmlndXJlcy9maWdfbWlsZXN0b25lX3N0YWNrLnBkZiIsIHBfbXNfc3RhY2ssIHdpZHRoPTgsIGhlaWdodD01KQoKYGBgCgoKCk5vdGU6IHRoaXMgY2h1bmsgbXVzdCBjb21lICoqYWZ0ZXIqKiB0aGUgYG1pbGVzdG9uZS1oZWF0bWFwYCBjaHVuayBzaW5jZSBpdCB1c2VzIGBtc19wZXJfbGluZWAgYW5kIGBNSUxFU1RPTkVfTEFCRUxTX0ZVTExgIGRlZmluZWQgdGhlcmUuCgoKCiMjIE1TVCB2cyBNb25vY2xlMyBQc2V1ZG90aW1lIHBlciBMaW5lCgpgYGB7ciB2aXMtcHQtY29ycmVsYXRpb24sIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD04fQojIFNjYXR0ZXI6IE1TVCB2cyBNb25vY2xlMyBwZXIgY2VsbCBsaW5lIOKAlCBtZXRob2QgYWdyZWVtZW50IGNoZWNrCnBfcHRfY29yIDwtIGdncGxvdCh2aW9saW5fZGZbc2FtcGxlKG5yb3codmlvbGluX2RmKSksXSwKICAgICAgICAgICAgICAgICAgICBhZXMoeD1tc3RfcHQsIHk9bTNfcHQsIGNvbG91cj1taWxlc3RvbmUpKSArCiAgZ2VvbV9wb2ludChzaXplPS44LCBhbHBoYT0uNikgKwogIGdlb21fYWJsaW5lKHNsb3BlPTEsIGludGVyY2VwdD0wLCBsaW5ldHlwZT0iZGFzaGVkIiwgY29sb3VyPSJncmV5NDAiKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXM9TUlMRVNUT05FX0NPTE9SUywKICAgICAgICAgICAgICAgICAgICAgIGxhYmVscz1NSUxFU1RPTkVfTEFCRUxTLCBuYW1lPSJNaWxlc3RvbmUiKSArCiAgZmFjZXRfd3JhcCh+Y2VsbF9saW5lLCBuY29sPTQpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGxhYnMoeD0iTVNUIHBzZXVkb3RpbWUgKDDigJMxMDApIiwgeT0iTW9ub2NsZTMgcHNldWRvdGltZSAoMOKAkzEwMCkiLAogICAgICAgdGl0bGU9Ik1TVCB2cyBNb25vY2xlMyBwc2V1ZG90aW1lIHBlciBTw6l6YXJ5IGNlbGwgbGluZSIsCiAgICAgICBzdWJ0aXRsZT0iRGFzaGVkID0gcGVyZmVjdCBhZ3JlZW1lbnQiKSArCiAgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMyxmYWNlPSJib2xkIiksCiAgICAgICAgc3RyaXAudGV4dD1lbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpKQoKIyBDb21wdXRlIHBlci1saW5lIFNwZWFybWFuIHJobwpwdF9jb3JzIDwtIHZpb2xpbl9kZiAlPiUKICBncm91cF9ieShjZWxsX2xpbmUpICU+JQogIHN1bW1hcmlzZSgKICAgIHNwZWFybWFuID0gcm91bmQoY29yKG1zdF9wdCwgbTNfcHQsIG1ldGhvZD0ic3BlYXJtYW4iLCB1c2U9ImNvbXBsZXRlLm9icyIpLCAzKSwKICAgIG4gICAgICAgID0gbigpLAogICAgLmdyb3VwcyAgPSAiZHJvcCIKICApCgpwcmludChwX3B0X2NvcikKY2F0KCJcblBlci1saW5lIE1TVCB2cyBNb25vY2xlMyBTcGVhcm1hbiDPgTpcbiIpCnByaW50KHB0X2NvcnMpCgpgYGAKCiMjIFBlci1DZWxsLUxpbmUgSW5kaXZpZHVhbCBVTUFQcwoKYGBge3IgdmlzLXBlci1saW5lLWluZGl2aWR1YWwsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTR9CiMgSW5kaXZpZHVhbCBVTUFQICsgcHNldWRvdGltZSBmb3IgZWFjaCBsaW5lIOKAlCBzYW1lIHN0eWxlIGFzIHByZXZpb3VzIHJlc3VsdHMKcHRfZ3JhZGllbnQgPC0gc2NhbGVfY29sb3VyX2dyYWRpZW50bigKICBjb2xvdXJzID0gYygiIzBEMDg4NyIsIiM2QTAwQTgiLCIjQjEyQTkwIiwiI0UxNjQ2MiIsIiNGQ0E2MzYiLCIjRjBGOTIxIiksCiAgbmFtZSAgICA9ICJNU1QgcHNldWRvdGltZVxuKDDigJMxMDApIiwgbGltaXRzID0gYygwLDEwMCksIG5hLnZhbHVlID0gImdyZXk4MCIKKQoKZm9yIChsbiBpbiBDRUxMX0xJTkVTKSB7CiAgcV9kZiA8LSBxdWVyeV91bWFwX2RmICU+JSBmaWx0ZXIoY2VsbF9saW5lID09IGxuKQoKICBwIDwtIGdncGxvdCgpICsKICAgIGdlb21fcG9pbnQoZGF0YT1yZWZfdW1hcF9kZiwgYWVzKHg9VU1BUF8xLHk9VU1BUF8yKSwKICAgICAgICAgICAgICAgY29sb3VyPSJncmV5NzgiLCBzaXplPS4yNSwgYWxwaGE9LjUpICsKICAgIGdlb21fc2VnbWVudChkYXRhPW1zdF9lZGdlX2RmLAogICAgICAgICAgICAgICAgIGFlcyh4PXgxLHk9eTEseGVuZD14Mix5ZW5kPXkyKSwKICAgICAgICAgICAgICAgICBjb2xvdXI9ImdyZXkzMCIsIGxpbmV3aWR0aD0uNywgYWxwaGE9LjcsIGxpbmVlbmQ9InJvdW5kIikgKwogICAgZ2VvbV9wb2ludChkYXRhPXFfZGZbc2FtcGxlKG5yb3cocV9kZikpLF0sCiAgICAgICAgICAgICAgIGFlcyh4PVVNQVBfMSx5PVVNQVBfMixjb2xvdXI9bXN0X3B0KSwgc2l6ZT0xLjUsIGFscGhhPS44NSkgKwogICAgcHRfZ3JhZGllbnQgKwogICAgIyBNaWxlc3RvbmUgbGFiZWxzCiAgICBnZW9tX3RleHRfcmVwZWwoZGF0YT1taWxlc3RvbmVfY2VudHJvaWRzLAogICAgICAgICAgICAgICAgICAgIGFlcyh4PVVNQVBfMSx5PVVNQVBfMixsYWJlbD1taWxlc3RvbmUpLAogICAgICAgICAgICAgICAgICAgIHNpemU9Mi44LCBmb250ZmFjZT0iYm9sZCIsIGNvbG91cj0iZ3JleTIwIiwKICAgICAgICAgICAgICAgICAgICBiZy5jb2xvcj0id2hpdGUiLCBiZy5yPS4xLCBtYXgub3ZlcmxhcHM9MTUpICsKICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICBsYWJzKHg9IlVNQVAtMSIseT0iVU1BUC0yIiwKICAgICAgICAgdGl0bGU9c3ByaW50ZigiJXMg4oCUIE1TVCBwc2V1ZG90aW1lIG9uIHJlZmVyZW5jZSBVTUFQIiwgbG4pLAogICAgICAgICBzdWJ0aXRsZT1zcHJpbnRmKCJuPSVkIGNlbGxzIHwgTVNUIG1lZGlhbj0lLjFmIiwKICAgICAgICAgICAgICAgICBucm93KHFfZGYpLAogICAgICAgICAgICAgICAgIG1lZGlhbihxX2RmJG1zdF9wdCwgbmEucm09VFJVRSkpKSAgKwogICAgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMixmYWNlPSJib2xkIikpCgogIHByaW50KHApCn0KCmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIFBzZXVkb3RpbWUgU3VtbWFyeSBUYWJsZQoKYGBge3J9CiMgRnVsbCBwZXItbGluZSBzdW1tYXJ5IGluY2x1ZGluZyBtaWxlc3RvbmUgYnJlYWtkb3duCm1zX3dpZGUgPC0gbXNfY29tcCAlPiUKICBzZWxlY3QoY2VsbF9saW5lLCBtaWxlc3RvbmUsIHBjdCkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbT1taWxlc3RvbmUsIHZhbHVlc19mcm9tPXBjdCwgdmFsdWVzX2ZpbGw9MCkgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgfnJvdW5kKC4sIDEpKSkKCmZ1bGxfc3VtbWFyeSA8LSB0cmFuc2Zlcl9zdW1tYXJ5ICU+JQogIGxlZnRfam9pbihtc193aWRlLCBieT0iY2VsbF9saW5lIikKCmthYmxlKGZ1bGxfc3VtbWFyeSwKICAgICAgY2FwdGlvbiA9ICJTw6l6YXJ5IGNlbGwgbGluZSBwcm9qZWN0aW9uIHN1bW1hcnkg4oCUIHBzZXVkb3RpbWUgYW5kIG1pbGVzdG9uZSBjb21wb3NpdGlvbiAoJSkiLAogICAgICBkaWdpdHMgID0gMSkgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucz1jKCJzdHJpcGVkIiwiaG92ZXIiLCJjb25kZW5zZWQiKSwgZnVsbF93aWR0aD1GQUxTRSkgJT4lCiAgYWRkX2hlYWRlcl9hYm92ZShjKCIgIj1uY29sKHRyYW5zZmVyX3N1bW1hcnkpLAogICAgICAgICAgICAgICAgICAgICAiJSBjZWxscyBwZXIgbWlsZXN0b25lIj1uY29sKG1zX3dpZGUpLTEpKQpgYGAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBTYXZlIE91dHB1dHMKCmBgYHtyIHNhdmUtb3V0cHV0c30KZGlyLmNyZWF0ZSgiT2JqZWN0cyIsIHNob3dXYXJuaW5ncz1GQUxTRSkKZGlyLmNyZWF0ZSgiRmlndXJlcyIsIHNob3dXYXJuaW5ncz1GQUxTRSkKZGlyLmNyZWF0ZSgiVGFibGVzIiwgIHNob3dXYXJuaW5ncz1GQUxTRSkKClNhdmVTZXVyYXRSZHMoc2V6YXJ5X29iaiwgIk9iamVjdHMvc2V6YXJ5X3Byb2plY3RlZC5yZHMiKQoKd3JpdGUuY3N2KGZ1bGxfc3VtbWFyeSwgIlRhYmxlcy9wcm9qZWN0aW9uX3N1bW1hcnlfcGVyX2xpbmUuY3N2IiwgICByb3cubmFtZXM9RkFMU0UpCndyaXRlLmNzdihtc19jb21wLCAgICAgICJUYWJsZXMvbWlsZXN0b25lX2NvbXBvc2l0aW9uX3Blcl9saW5lLmNzdiIsIHJvdy5uYW1lcz1GQUxTRSkKCmdnc2F2ZSgiRmlndXJlcy9maWdfYWxsX2xpbmVzX3VtYXAucGRmIiwgICAgICAgIHBfYWxsX2xpbmVzLCAgd2lkdGg9MTQsIGhlaWdodD0xMCkKZ2dzYXZlKCJGaWd1cmVzL2ZpZ192aW9saW5fbXN0LnBkZiIsICAgICAgICAgICAgcF92aW9saW5fbXN0LCB3aWR0aD0xMCwgaGVpZ2h0PTUpCmdnc2F2ZSgiRmlndXJlcy9maWdfdmlvbGluX20zLnBkZiIsICAgICAgICAgICAgIHBfdmlvbGluX20zLCAgd2lkdGg9MTAsIGhlaWdodD01KQpnZ3NhdmUoIkZpZ3VyZXMvZmlnX21pbGVzdG9uZV9jb21wb3NpdGlvbi5wZGYiLCBwX21zX2JhciwgICAgIHdpZHRoPTExLCBoZWlnaHQ9NSkKZ2dzYXZlKCJGaWd1cmVzL2ZpZ19wdF9jb3JyZWxhdGlvbi5wZGYiLCAgICAgICAgcF9wdF9jb3IsICAgICB3aWR0aD0xMiwgaGVpZ2h0PTgpCgpjYXQoIuKchSBBbGwgb3V0cHV0cyBzYXZlZFxuIikKYGBgCgpgYGB7ciBzZXNzaW9ufQoKc2Vzc2lvbkluZm8oKQoKYGBgCg==