1 Load Libraries

2 Load Objects

2.1 Load Reference (Healthy CD4+ T Cells with Trajectory)

# ── CRITICAL: use the ANNOTATED reference with saved UMAP model ────────────
# This is the cleaned reference object with:
#   - CD4 Proliferating cluster removed (MKI67+/TOP2A+/CDK1+ cells)
#   - Cluster 12 contamination removed
#   - UMAP reduction with return.model = TRUE
#   - monocle3_pseudotime column computed on the clean trajectory
#   - cell_type annotation (clusters 0-6, no proliferating)
#   - predicted.celltype.l2 (Azimuth l2)
# ──────────────────────────────────────────────────────────────────────────


reference_integrated <- readRDS("../Part3_Slingshot_Trajectory/part4_Slingshot+Projection/cd4_ref_dual_trajectory.rds")

cat("=== Reference object summary ===\n")
cat("Cells:", ncol(reference_integrated), "\n")
cat("Assays:", paste(names(reference_integrated@assays), collapse = ", "), "\n")
cat("Reductions:", paste(names(reference_integrated@reductions), collapse = ", "), "\n")
cat("UMAP model present:", !is.null(reference_integrated@reductions$umap@misc$model), "\n")

# ── Confirm clusters present ───────────────────────────────────────────────
cat("\nClusters present:", paste(sort(unique(reference_integrated$seurat_clusters)),
                                 collapse = ", "), "\n")

# ── Confirm CD4 Proliferating cells are ABSENT ────────────────────────────
# Check 1: cell_type label should not contain "Prolif"
if (any(grepl("Prolif|prolif|cycling|Cycling", reference_integrated$cell_type,
              ignore.case = TRUE))) {
  warning("⚠️  Proliferating cell_type labels still detected! Check removal step.")
} else {
  cat("✅ No proliferating cell_type labels found\n")
}

# Check 2: Molecular signature — MKI67/TOP2A expression should be near zero
prolif_markers <- c("MKI67", "TOP2A", "PCNA", "CDK1", "STMN1")
prolif_present <- intersect(prolif_markers, rownames(reference_integrated))

if (length(prolif_present) > 0) {
  DefaultAssay(reference_integrated) <- "SCT"
  prolif_expr <- Matrix::colMeans(
    GetAssayData(reference_integrated, layer = "data")[prolif_present, , drop = FALSE]
  )
  cat("Proliferation marker score — max:", round(max(prolif_expr), 3),
      " | mean:", round(mean(prolif_expr), 4), "\n")
  cat("Cells with any prolif marker > 0.5:", sum(prolif_expr > 0.5),
      "(expect near zero after removal)\n")
  if (sum(prolif_expr > 0.5) > 50) {
    warning("⚠️  Substantial proliferation signal remains — verify removal was complete.")
  } else {
    cat("✅ Proliferating cells confirmed removed\n")
  }
}

# ── Cell type distribution ─────────────────────────────────────────────────
cat("\nCell type distribution (should be 6 types, no Proliferating):\n")
print(table(reference_integrated$cell_type))

cat("\nAzimuth l2 distribution:\n")
print(table(reference_integrated$predicted.celltype.l2))

# ── Finalise Azimuth l2 colour palette from actual labels in data ──────────
ref_l2_labels <- unique(as.character(reference_integrated$predicted.celltype.l2))
ref_l2_labels <- ref_l2_labels[!is.na(ref_l2_labels)]
azimuth_l2_colors <- extend_palette(azimuth_l2_colors, ref_l2_labels)
cat("\nAzimuth l2 colour palette covers", length(ref_l2_labels), "reference labels ✅\n")

# NOTE: monocle3_pseudotime summary is printed AFTER trajectory is built
# (Section 2 below). If this is a freshly loaded reference that already
# has pseudotime stored, the validate-pseudotime chunk will summarise it.

# ── Validate: UMAP model MUST exist for MapQuery ──────────────────────────
if (is.null(reference_integrated@reductions$umap@misc$model)) {
  stop(
    "❌ UMAP model missing! Re-run on the cleaned (no-prolif) object:\n",
    "  reference_integrated <- RunUMAP(reference_integrated, dims = 1:20,\n",
    "                                   return.model = TRUE)\n",
    "Then re-save and reload."
  )
} else {
  cat("✅ UMAP model confirmed — ready for MapQuery projection\n")
}

2.2 Load & Prepare Malignant CD4+ T Cells — Per-Cell-Line SCTransform

# ── Load merged object ─────────────────────────────────────────────────────
All_samples_Merged <- readRDS(
  "/home/nabbasi/apollo_home/1-Seurat_RDS_OBJECT_FINAL/All_samples_Merged_with_Renamed_Clusters_Cell_state-03-12-2025.rds.rds"
)

cat("All samples:\n")
print(table(All_samples_Merged$cell_line))

# ── Define group labels ────────────────────────────────────────────────────
All_samples_Merged$Group <- ifelse(
  All_samples_Merged$cell_line %in% paste0("L", 1:7),
  "MalignantCD4T",
  ifelse(
    All_samples_Merged$cell_line %in% c("CD4Tcells_lab", "CD4Tcells_10x_S1", "CD4Tcells_10x_S2"),
    "NormalCD4T",
    "Other"
  )
)

cat("\nGroup distribution:\n")
print(table(All_samples_Merged$Group))

# ── Subset malignant cells ─────────────────────────────────────────────────
MalignantCD4T_raw <- subset(All_samples_Merged, subset = Group == "MalignantCD4T")
cat("\nMalignant CD4T cells:", ncol(MalignantCD4T_raw), "\n")
cat("Cell lines present:\n")
print(table(MalignantCD4T_raw$cell_line))

rm(All_samples_Merged)
gc()
# ══════════════════════════════════════════════════════════════════════════
# PER-CELL-LINE SCTransform
# ══════════════════════════════════════════════════════════════════════════
# WHY: Running SCTransform on the merged object creates a single shared
#      size-factor model that collapses batch variation with biology.
#      Each cell line is a separate library (different sequencing depth,
#      different ambient RNA profile). Per-line SCT corrects for this.
#
# APPROACH:
#   1. Split the malignant object by cell_line
#   2. Run SCTransform on each line independently
#   3. Merge back into one object (NOT integrate — integration is not
#      needed here because MapQuery uses reference anchors anyway)
#   4. Set VariableFeatures to the union of all per-line HVGs
#      (capped at 3000, ranked by cross-line frequency)
# ══════════════════════════════════════════════════════════════════════════

cat("=== Running per-cell-line SCTransform ===\n")
cat("This may take 5-15 minutes depending on cell count per line.\n\n")

# ── Step 1: Split by cell line ────────────────────────────────────────────
cell_line_list <- SplitObject(MalignantCD4T_raw, split.by = "cell_line")
cat("Cell lines to process:", paste(names(cell_line_list), collapse = ", "), "\n\n")

# ── Step 2: SCTransform each line independently ───────────────────────────
# vars.to.regress: remove cell-cycle and mitochondrial confounders
# These are biological covariates that would otherwise distort the
# differentiation signal in the trajectory projection.

cell_line_list <- lapply(names(cell_line_list), function(line_name) {
  obj <- cell_line_list[[line_name]]
  cat("Processing cell line:", line_name,
      "| Cells:", ncol(obj), "\n")

  # ── Compute % mitochondrial if not present ──────────────────────────────
  if (!"percent.mt" %in% colnames(obj@meta.data)) {
    obj[["percent.mt"]] <- PercentageFeatureSet(obj, pattern = "^MT-")
  }

  # ── Cell cycle scoring (for regression) ────────────────────────────────
  # Uses Seurat's built-in cc.genes (Tirosh et al.)
  # Regressing S.Score and G2M.Score removes cycling artefacts from the
  # SCT residuals without removing cycling cells from the object.
  tryCatch({
    obj <- CellCycleScoring(
      obj,
      s.features   = cc.genes$s.genes,
      g2m.features = cc.genes$g2m.genes,
      set.ident    = FALSE
    )
    vars_regress <- c("percent.mt", "S.Score", "G2M.Score")
    cat("  → Cell cycle scores computed for", line_name, "\n")
  }, error = function(e) {
    # If cell cycle genes not found (very small object), skip regression
    cat("  ⚠️  Cell cycle scoring failed for", line_name,
        "— regressing percent.mt only\n")
    vars_regress <<- "percent.mt"
  })

  # ── SCTransform ─────────────────────────────────────────────────────────
  obj <- SCTransform(
    obj,
    vars.to.regress  = vars_regress,
    variable.features.n = 3000,
    vst.flavor       = "v2",     # Pearson residuals v2 (faster, more stable)
    verbose          = FALSE
  )

  cat("  ✅", line_name, "SCT complete |",
      length(VariableFeatures(obj)), "HVGs\n")
  return(obj)
})
names(cell_line_list) <- names(SplitObject(MalignantCD4T_raw, split.by = "cell_line"))

# ── Step 3: Collect per-line HVGs ─────────────────────────────────────────
# Strategy: rank genes by how many cell lines they are variable in.
# Genes variable across multiple lines are robust HVGs not dominated
# by any single line's batch effect.

all_hvg_lists <- lapply(cell_line_list, VariableFeatures)
hvg_freq <- sort(table(unlist(all_hvg_lists)), decreasing = TRUE)

# Select top 3000 genes by cross-line frequency
n_hvgs      <- min(3000, length(hvg_freq))
shared_hvgs <- names(hvg_freq)[1:n_hvgs]

cat("\nTop 3000 HVGs selected by cross-line frequency\n")
cat("Genes variable in all", length(cell_line_list), "lines:",
    sum(hvg_freq == length(cell_line_list)), "\n")
cat("Genes variable in ≥3 lines:",
    sum(hvg_freq >= 3), "\n")

# ── Step 4: Merge SCT-normalised cell line objects ─────────────────────────
# merge() on SCT objects concatenates the corrected count matrices.
# We do NOT RunIntegration here — MapQuery will handle cross-dataset
# correction via anchor-based transfer.
cat("\nMerging per-line SCT objects...\n")

MalignantCD4T <- merge(
  x    = cell_line_list[[1]],
  y    = cell_line_list[-1],
  merge.data = TRUE    # concatenate SCT data layers
)

# ── Step 5: Set unified VariableFeatures on merged object ─────────────────
VariableFeatures(MalignantCD4T) <- shared_hvgs

# ── Step 6: Run PCA on merged SCT object ──────────────────────────────────
# PCA is needed for FindTransferAnchors (reference.reduction = "pca")
# We run it on the merged data so each cell has a PCA embedding consistent
# with the shared HVG space.
cat("Running PCA on merged malignant object...\n")

# Note: JoinLayers() is Seurat v5 only and not needed here.
# In Seurat v4, merge() with merge.data = TRUE already concatenates
# the SCT data slot directly — no layer joining required.

MalignantCD4T <- ScaleData(
  MalignantCD4T,
  features = shared_hvgs,
  assay    = "SCT",
  verbose  = FALSE
)
MalignantCD4T <- RunPCA(
  MalignantCD4T,
  features = shared_hvgs,
  assay    = "SCT",
  npcs     = 30,
  verbose  = FALSE
)

cat("✅ Per-cell-line SCT + merge complete\n")
cat("Final merged object:\n")
cat("  Cells:", ncol(MalignantCD4T), "\n")
cat("  VariableFeatures:", length(VariableFeatures(MalignantCD4T)), "\n")
cat("  PCA dims:", ncol(Embeddings(MalignantCD4T, "pca")), "\n")
cat("Cell line distribution:\n")
print(table(MalignantCD4T$cell_line))

# Clean up per-line list to free memory
rm(MalignantCD4T_raw, cell_line_list)
gc()

3 Reference Trajectory (Monocle3)

3.1 Build CDS from Reference

cat("CDS built:", ncol(cds), "cells\n")
CDS built: 11466 cells
cat("Clusters:", nlevels(factor(colData(cds)$seurat_clusters)), "\n")
Clusters: 8 
cat("Partitions:", nlevels(partitions(cds)), "\n")
Partitions: 0 
cat("\nCell type breakdown in CDS:\n")

Cell type breakdown in CDS:
print(table(colData(cds)$predicted.celltype.l2))

    CD4 Naive       CD4 TCM       CD4 TEM CD4 Temra/CTL          Treg 
         2037          9067           145            10           207 

3.2 Learn Trajectory Graph

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

✅ Principal graph learned!
cat("Nodes:", length(igraph::V(principal_graph(cds)$UMAP)), "\n")
Nodes: 349 
cat("Branch points:", sum(igraph::degree(principal_graph(cds)$UMAP) > 2), "\n")
Branch points: 18 
cat("Expect 1-2 branches (Treg divergence ± Tnaive-RTE)\n")
Expect 1-2 branches (Treg divergence ± Tnaive-RTE)
# ── VISUALIZE: Azimuth l2 (PRIMARY) + cell_type (SECONDARY) ───────────────
p1 <- plot_cells(cds,
                 color_cells_by = "predicted.celltype.l2",  # YOUR 5 labels
                 label_groups_by_cluster = FALSE,
                 label_leaves = TRUE,
                 label_branch_points = TRUE,
                 graph_label_size = 3.5,
                 cell_size = 0.8) +
  scale_color_manual(values = azimuth_l2_colors) +
  ggtitle("Monocle3 Graph: Azimuth l2 (CD4 Naive → Temra/CTL)") +
  theme(plot.title = element_text(hjust = 0.5, size = 14, face = "bold"))

p2 <- plot_cells(cds,
                 color_cells_by = "cell_type",
                 label_groups_by_cluster = FALSE,
                 label_leaves = TRUE,
                 label_branch_points = TRUE,
                 graph_label_size = 3.5,
                 cell_size = 0.8) +
  ggtitle("Monocle3 Graph: Cell Types") +
  theme(plot.title = element_text(hjust = 0.5, size = 14, face = "bold"))

p1 | p2

4 Fixed learn-graph Visualization

umap_coords <- as.data.frame(Embeddings(reference_integrated, "umap"))
colnames(umap_coords) <- c("UMAP1", "UMAP2")   # rename for clarity

umap_coords$l2        <- reference_integrated$predicted.celltype.l2
umap_coords$cell_type <- reference_integrated$cell_type

# Centroid per Azimuth l2 state
label_coords <- umap_coords %>%
  dplyr::group_by(l2) %>%
  dplyr::summarise(
    UMAP1 = median(UMAP1),
    UMAP2 = median(UMAP2),
    .groups = "drop"
  )

# Centroid per cell_type
label_coords2 <- umap_coords %>%
  dplyr::group_by(cell_type) %>%
  dplyr::summarise(
    UMAP1 = median(UMAP1),
    UMAP2 = median(UMAP2),
    .groups = "drop"
  )

library(ggrepel)

# Azimuth l2 plot
p1 <- plot_cells(
        cds,
        color_cells_by = "predicted.celltype.l2",
        label_groups_by_cluster = FALSE,
        label_leaves        = FALSE,
        label_branch_points = FALSE,
        cell_size           = 0.7,
        show_trajectory_graph = TRUE
      ) +
  scale_color_manual(values = azimuth_l2_colors, name = "State") +
  geom_label_repel(
    data = label_coords,
    aes(x = UMAP1, y = UMAP2, label = l2),
    size = 4, fontface = "bold",
    fill = "white", alpha = 0.85,
    box.padding = 0.5, label.padding = 0.3,
    segment.color = "grey40"
  ) +
  ggtitle("Monocle3 Graph: Azimuth l2 (CD4 Naive → Temra/CTL)") +
  theme(plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
        legend.position = "none")

# cell_type plot
p2 <- plot_cells(
        cds,
        color_cells_by = "cell_type",
        label_groups_by_cluster = FALSE,
        label_leaves        = FALSE,
        label_branch_points = FALSE,
        cell_size           = 0.7,
        show_trajectory_graph = TRUE
      ) +
  geom_label_repel(
    data = label_coords2,
    aes(x = UMAP1, y = UMAP2, label = cell_type),
    size = 3.5, fontface = "bold",
    fill = "white", alpha = 0.85,
    box.padding = 0.5,
    segment.color = "grey40"
  ) +
  ggtitle("Monocle3 Graph: Cell Types") +
  theme(plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
        legend.position = "none")

p1 | p2


p1 


p2

4.1 Set Root & Order Cells by Pseudotime

cat("\nPseudotime summary (finite values):\n")

Pseudotime summary (finite values):
print(summary(reference_integrated$monocle3_pseudotime[
  is.finite(reference_integrated$monocle3_pseudotime)
]))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   9.653  17.619  17.918  26.763  33.713 
# ── Plot pseudotime on trajectory ─────────────────────────────────────────
plot_cells(
  cds,
  color_cells_by    = "pseudotime",
  label_cell_groups = FALSE,
  cell_size         = 0.8,
  show_trajectory_graph = TRUE
) +
  scale_color_viridis_c(option = "plasma", name = "Pseudotime") +
  ggtitle("Reference CD4+ T Cell Pseudotime\n(Root = Tnaive, Terminal = Temra/CTL)") +
  theme(plot.title = element_text(hjust = 0.5, size = 14, face = "bold"))


# ── Pseudotime on Seurat UMAP ─────────────────────────────────────────────
FeaturePlot(
  reference_integrated,
  features  = "monocle3_pseudotime",
  reduction = "umap",
  cols      = c("lightblue", "darkblue", "red"),
  label     = TRUE,
  pt.size   = 0.5
) +
  ggtitle("Reference UMAP — Pseudotime") +
  theme(plot.title = element_text(hjust = 0.5))

5 Visualization

# ── Identify root node in the naive cluster ────────────────────────────────
# Root = cells in the Tnaive cluster (CCR7+SELL+TCF7+) = cluster 0
# Using the principal graph node closest to the Tnaive centroid ensures
# pseudotime=0 is biologically anchored to the most undifferentiated state.

cat("Available Azimuth l2 labels:\n")
Available Azimuth l2 labels:
print(sort(unique(colData(cds)$predicted.celltype.l2)))
[1] CD4 Naive     CD4 TCM       CD4 TEM       CD4 Temra/CTL Treg         
Levels: CD4 Naive CD4 TCM CD4 TEM CD4 Temra/CTL Treg
# Find naive cells — use both Azimuth label and our cell_type annotation
naive_ids <- rownames(colData(cds))[
  grepl("naive|Naive|TN$", colData(cds)$predicted.celltype.l2, ignore.case = TRUE) |
  grepl("Tnaive", as.character(colData(cds)$cell_type), ignore.case = FALSE)
]

cat("\nNaive root cells identified:", length(naive_ids), "\n")

Naive root cells identified: 5739 
if (length(naive_ids) == 0) {
  stop("❌ No naive root cells found. Check label strings above and adjust grep patterns.")
}

# ── Function to find the principal graph node closest to naive centroid ────
get_root_node <- function(cds, cell_ids) {
  closest <- cds@principal_graph_aux$UMAP$pr_graph_cell_proj_closest_vertex
  closest <- as.matrix(closest[colnames(cds), ])
  igraph::V(principal_graph(cds)$UMAP)$name[
    as.numeric(names(which.max(table(closest[cell_ids, ]))))
  ]
}

root_node <- get_root_node(cds, naive_ids)
cat("Root node:", root_node, "\n")
Root node: Y_338 
# ── Order cells ────────────────────────────────────────────────────────────
cds <- order_cells(cds, root_pr_nodes = root_node)

# Transfer pseudotime back to Seurat object
reference_integrated$monocle3_pseudotime <- pseudotime(cds)

# Replace Inf (unreachable cells) with NA for clean plotting
reference_integrated$monocle3_pseudotime[
  !is.finite(reference_integrated$monocle3_pseudotime)
] <- NA

cat("\nPseudotime summary (finite values):\n")

Pseudotime summary (finite values):
print(summary(reference_integrated$monocle3_pseudotime[
  is.finite(reference_integrated$monocle3_pseudotime)
]))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   9.653  17.619  17.918  26.763  33.713 
# ── Plot pseudotime on trajectory ─────────────────────────────────────────
plot_cells(
  cds,
  color_cells_by    = "pseudotime",
  label_cell_groups = FALSE,
  cell_size         = 0.8,
  show_trajectory_graph = TRUE
) +
  scale_color_viridis_c(option = "plasma", name = "Pseudotime") +
  ggtitle("Reference CD4+ T Cell Pseudotime\n(Root = Tnaive, Terminal = Temra/CTL)") +
  theme(plot.title = element_text(hjust = 0.5, size = 14, face = "bold"))


# ── Pseudotime on Seurat UMAP + state labels ─────────────────────────────
library(dplyr)
library(ggrepel)

umap_df <- as.data.frame(Embeddings(reference_integrated, "umap"))
colnames(umap_df) <- c("UMAP1", "UMAP2")
umap_df$pt <- reference_integrated$monocle3_pseudotime
umap_df$l2 <- reference_integrated$predicted.celltype.l2

umap_df <- umap_df[is.finite(umap_df$pt) & !is.na(umap_df$l2), ]

label_coords <- umap_df %>%
  group_by(l2) %>%
  summarise(
    UMAP1 = median(UMAP1),
    UMAP2 = median(UMAP2),
    .groups = "drop"
  )

p_umap <- FeaturePlot(
  reference_integrated,
  features  = "monocle3_pseudotime",
  reduction = "umap",
  cols      = c("lightblue", "green", "red"),
  label     = FALSE,
  pt.size   = 0.5
)

p_umap +
  geom_label_repel(
    data = label_coords,
    aes(x = UMAP1, y = UMAP2, label = l2),
    inherit.aes = FALSE,
    size = 4,
    fontface = "bold",
    fill = "white",
    alpha = 0.85,
    box.padding = 0.4,
    label.padding = 0.25,
    segment.color = "grey40"
  ) +
  ggtitle("Reference UMAP — Pseudotime with CD4 Naive / TCM / TEM / Temra/CTL / Treg labels") +
  theme(plot.title = element_text(hjust = 0.5))

# ── DEFINE MILESTONES: Key CD4 states along your trajectory ───────────────
# Based on your Azimuth l2 + pseudotime quantiles

library(dplyr)

# 1. Get state-specific pseudotime ranges
pt_ranges <- reference_integrated@meta.data %>%
  filter(is.finite(monocle3_pseudotime)) %>%
  group_by(predicted.celltype.l2) %>%
  summarise(
    n = n(),
    pt_min = round(min(monocle3_pseudotime), 2),
    pt_max = round(max(monocle3_pseudotime), 2),
    pt_median = round(median(monocle3_pseudotime), 2),
    .groups = "drop"
  ) %>%
  arrange(pt_median)

print("Pseudotime by state (milestone order):")
[1] "Pseudotime by state (milestone order):"
print(pt_ranges)

# 2. Define milestones (pseudotime quantiles + biology)
milestones <- data.frame(
  milestone = c("Naive", "Central_Memory", "Effector_Memory", "Terminal_Effector"),
  pseudotime = c(0.1, 0.8, 1.4, 2.0),  # Your trajectory quantiles
  state = c("CD4 Naive", "CD4 TCM", "CD4 TEM", "CD4 Temra/CTL")
)

print("Milestones defined:")
[1] "Milestones defined:"
print(milestones)

# 3. Assign cells to milestones — FIXED for YOUR 5 states
ref_milestones <- reference_integrated@meta.data %>%
  filter(is.finite(monocle3_pseudotime)) %>%
  mutate(
    milestone = case_when(
      # Naive: pt < 25th percentile
      monocle3_pseudotime <= quantile(monocle3_pseudotime, 0.25, na.rm = TRUE) ~ "Naive",
      
      # Central Memory (TCM): 25th-60th percentile  
      monocle3_pseudotime <= quantile(monocle3_pseudotime, 0.60, na.rm = TRUE) ~ "Central_Memory",
      
      # Treg + TEM: 60th-85th percentile (branch + effector memory)
      predicted.celltype.l2 == "Treg" | 
      (monocle3_pseudotime <= quantile(monocle3_pseudotime, 0.85, na.rm = TRUE)) ~ "Regulatory_Effector",
      
      # Terminal: TEMRA/CTL (top 15%)
      TRUE ~ "Terminal_Effector"
    ),
    
    # Simplified state mapping for coloring
    state_group = case_when(
      predicted.celltype.l2 == "CD4 Naive" ~ "Naive",
      predicted.celltype.l2 == "CD4 TCM" ~ "Central_Memory", 
      predicted.celltype.l2 == "Treg" ~ "Treg",
      predicted.celltype.l2 == "CD4 TEM" ~ "Effector_Memory",
      predicted.celltype.l2 == "CD4 Temra/CTL" ~ "Terminal_Effector"
    )
  )

cat("Milestone distribution:\n")
Milestone distribution:
print(table(ref_milestones$milestone))

     Central_Memory               Naive Regulatory_Effector   Terminal_Effector 
               4013                2867                2866                1720 
cat("\nState validation:\n") 

State validation:
print(table(ref_milestones$predicted.celltype.l2, ref_milestones$state_group))
               
                Central_Memory Effector_Memory Naive Terminal_Effector Treg
  CD4 Naive                  0               0  2037                 0    0
  CD4 TCM                 9067               0     0                 0    0
  CD4 TEM                    0             145     0                 0    0
  CD4 Temra/CTL              0               0     0                10    0
  Treg                       0               0     0                 0  207

5.1 Validate Pseudotime Against Cell Type

# ── Guard: only run if monocle3_pseudotime has already been computed ──────
# This column is created in the trajectory chunk (Section 2).
# If you are running this script for the first time on a freshly loaded
# reference (without pseudotime), this chunk will skip gracefully.
# Re-run after the trajectory section completes.

if (!"monocle3_pseudotime" %in% colnames(reference_integrated@meta.data)) {
  message(
    "⚠️  monocle3_pseudotime not yet computed — skipping validation plots.\n",
    "   Run Section 2 (Reference Trajectory) first, then re-run this chunk."
  )
} else {

# ── Violin: pseudotime distribution per Azimuth l2 label ─────────────────
# CONFIRMED label order in this dataset (low → high pseudotime):
#   CD4 Naive → CD4 TCM → CD4 TEM → CD4 Temra/CTL (highest)
#   Treg: separate branch, variable pseudotime
#
# We use predicted.celltype.l2 as PRIMARY label throughout — consistent
# with the rest of the analysis.

pt_data <- data.frame(
  pseudotime = reference_integrated$monocle3_pseudotime,
  l2         = reference_integrated$predicted.celltype.l2
) %>%
  filter(is.finite(pseudotime), !is.na(l2))

# Order l2 labels by median pseudotime
l2_order <- pt_data %>%
  group_by(l2) %>%
  summarise(med_pt = median(pseudotime, na.rm = TRUE)) %>%
  arrange(med_pt) %>%
  pull(l2)

pt_data$l2 <- factor(pt_data$l2, levels = l2_order)

# ── Violin plot coloured by Azimuth l2 ────────────────────────────────────
p_violin <- ggplot(pt_data, aes(x = l2, y = pseudotime, fill = l2)) +
  geom_violin(scale = "width", alpha = 0.85, trim = TRUE) +
  geom_boxplot(width = 0.12, fill = "white", outlier.size = 0.3) +
  scale_fill_manual(values = azimuth_l2_colors, na.value = "grey70") +
  theme_classic(base_size = 11) +
  theme(
    axis.text.x  = element_text(angle = 40, hjust = 1, size = 9),
    legend.position = "none",
    plot.title   = element_text(hjust = 0.5, face = "bold")
  ) +
  labs(
    title = "Pseudotime Distribution per Azimuth l2 Label (Reference)",
    x = "", y = "Monocle3 Pseudotime"
  )

# ── Ridge plot — same data, different view ────────────────────────────────
p_ridge <- ggplot(pt_data, aes(x = pseudotime, y = l2, fill = l2)) +
  geom_density_ridges(alpha = 0.75, scale = 1.2, rel_min_height = 0.01) +
  scale_fill_manual(values = azimuth_l2_colors, na.value = "grey70") +
  theme_classic(base_size = 10) +
  theme(legend.position = "none",
        plot.title = element_text(hjust = 0.5, face = "bold")) +
  labs(
    title = "Pseudotime Density by Azimuth l2 Label",
    x = "Pseudotime", y = ""
  )

p_violin | p_ridge

} # end else (monocle3_pseudotime exists)

6 Prepare Reference for MapQuery Projection

cat("Reference HVGs available:", length(ref_hvgs), "\n")
Reference HVGs available: 2902 
cat("PCA dims available:", ncol(Embeddings(reference_integrated, "pca")), "\n")
PCA dims available: 50 
cat("✅ Reference ready for MapQuery\n")
✅ Reference ready for MapQuery

7 Map Malignant CD4+ T Cells onto Reference

7.1 Find Transfer Anchors

# ══════════════════════════════════════════════════════════════════════════
# FindTransferAnchors
# ══════════════════════════════════════════════════════════════════════════
# normalization.method = "SCT": both objects are SCT-normalised
# reference.reduction  = "pca": anchors in the reference PCA space
# dims = 1:20: consistent with reference clustering
#
# KEY FIX: common_features now computed from per-line SCT HVGs (shared_hvgs)
# intersected with reference HVGs. This ensures anchors are found on genes
# that are variable in BOTH the reference biology AND each malignant line.
# Previously (merged SCT), common_features were dominated by batch-driven
# HVGs from one large SCT model → biased anchors → all cells → TCM.
# ══════════════════════════════════════════════════════════════════════════

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

ref_hvgs <- VariableFeatures(reference_integrated, assay = "SCT")
if (length(ref_hvgs) == 0) {
  ref_hvgs <- rownames(GetAssayData(reference_integrated, assay = "SCT",
                                     layer = "scale.data"))
}

# VariableFeatures on merged malignant = shared_hvgs set in per-line SCT block
query_hvgs <- VariableFeatures(MalignantCD4T)

common_features <- intersect(ref_hvgs, query_hvgs)
cat("Reference HVGs:", length(ref_hvgs), "\n")
cat("Query HVGs (per-line consensus):", length(query_hvgs), "\n")
cat("Common HVGs for anchor finding:", length(common_features), "\n")

if (length(common_features) < 1500) {
  warning(paste0(
    "⚠️  Only ", length(common_features), " common features found.\n",
    "   This is below the recommended minimum of 1500.\n",
    "   Check that both objects used SCTransform with similar gene sets.\n",
    "   Consider increasing nfeatures in SCTransform to 4000."
  ))
} else {
  cat("✅ Sufficient common features for robust anchor finding\n")
}


# ── Clean and rank common_features ──────────────────────────────────────────

# 1. Remove ribosomal, mitochondrial, heat shock, and other known batch genes
#    These are highly variable due to library quality, not biology.
junk_pattern <- "^RPL|^RPS|^MT-|^HSP|^HSPA|^HSPB|^HSPD|^HSPE|^HSPH|^SNHG|^MALAT1|^NEAT1|^XIST"
n_before <- length(common_features)
common_features_clean <- common_features[!grepl(junk_pattern, common_features)]
cat("Removed junk genes:", n_before - length(common_features_clean), "\n")
cat("Clean common features:", length(common_features_clean), "\n")

# 2. Rank by mean HVG rank across reference and query
#    SCTransform stores residual variance per gene — higher = more variable.
#    Genes ranked highly in BOTH objects are robustly variable (biology-driven).
ref_var_meta  <- reference_integrated[["SCT"]]@meta.features
query_var_meta <- MalignantCD4T[["SCT"]]@meta.features

# residual_variance column is set by SCTransform
if ("residual_variance" %in% colnames(ref_var_meta) &&
    "residual_variance" %in% colnames(query_var_meta)) {

  ref_ranks   <- ref_var_meta[common_features_clean, "residual_variance"]
  query_ranks <- query_var_meta[common_features_clean, "residual_variance"]

  # Replace NA with 0 (gene not in that object's variance table)
  ref_ranks[is.na(ref_ranks)]     <- 0
  query_ranks[is.na(query_ranks)] <- 0

  mean_var <- (ref_ranks + query_ranks) / 2
  common_features <- common_features_clean[order(mean_var, decreasing = TRUE)]

  cat("Top 20 ranked features (should be T cell biology):\n")
  print(head(common_features, 20))

} else {
  # Fallback: just use cleaned list without ranking
  cat("⚠️  residual_variance not found in SCT meta.features, using unranked clean list\n")
  common_features <- common_features_clean
}

# 3. Sanity check: key T cell marker genes present?
markers_to_check <- c("CCR7", "SELL", "TCF7", "IL7R", "GZMB", "PRF1",
                      "FOXP3", "CXCR5", "TOX", "PDCD1", "HAVCR2", "TIGIT",
                      "CD44", "CD69", "IFNG", "TNF", "EOMES", "TBX21")
found_markers <- markers_to_check[markers_to_check %in% common_features]
cat("\nKey T cell markers in feature set:", length(found_markers), "/", length(markers_to_check), "\n")
print(found_markers)

if (length(found_markers) < 5) {
  warning(paste0(
    "⚠️  Fewer than 5 canonical T cell markers in common_features.\n",
    "   The feature set may still be dominated by non-specific genes.\n",
    "   Consider: did SCTransform use sufficient nfeatures (3000-4000)?\n",
    "   Run: length(VariableFeatures(reference_integrated)) to check."
  ))
}


cat("\n=== Finding transfer anchors ===\n")

# Diagnostics
cat("Reference cells:", ncol(reference_integrated), "\n")
cat("Query cells:    ", ncol(MalignantCD4T), "\n")
cat("Common features:", length(common_features), "\n")

# Use as many dims as both objects support (up to 30)
dims_to_use <- min(30,
                   ncol(Embeddings(reference_integrated, "pca")),
                   ncol(Embeddings(MalignantCD4T, "pca")))
cat("Using dims 1:", dims_to_use, "\n")

# KEY CHANGES vs previous run:
#   k.anchor = 10   (was default 5)  → more initial anchor candidates
#   k.filter = 500  (was default 200) → less aggressive pruning on 40k query
#   dims = 1:30     (was 1:20)        → capture more variance in tumour cells
anchors <- FindTransferAnchors(
  reference            = reference_integrated,
  query                = MalignantCD4T,
  features             = common_features,
  normalization.method = "SCT",
  reference.reduction  = "pca",
  dims                 = 1:dims_to_use,
  k.anchor             = 10,
  k.filter             = 500,
  k.score              = 30,
  verbose              = TRUE
)

n_anchors    <- nrow(anchors@anchors)
anchor_ratio <- ncol(MalignantCD4T) / n_anchors
cat("Anchors found:", n_anchors, "\n")
cat("Cells per anchor:", round(anchor_ratio, 1), "\n")

if (anchor_ratio > 8) {
  warning(paste0(
    "⚠️  Low anchor density (1:", round(anchor_ratio, 1), ").\n",
    "   Ideal is 1:5 or better. Inspect head(common_features) for batch genes,\n",
    "   and check query UMAP projection before trusting pseudotime values."
  ))
} else {
  cat("✅ Anchor density acceptable\n")
}

7.2 MapQuery — Project onto Reference UMAP

cat("✅ MapQuery complete\n")
✅ MapQuery complete
cat("Mapped malignant cells:", ncol(mapped_MalignantCD4T), "\n")
Mapped malignant cells: 40695 
cat("\nTransferred metadata columns:\n")

Transferred metadata columns:
transferred_cols <- grep("^predicted\\.", colnames(mapped_MalignantCD4T@meta.data), value = TRUE)
print(transferred_cols)
 [1] "predicted.celltype.l1.score"           "predicted.celltype.l1"                 "predicted.celltype.l2.score"          
 [4] "predicted.celltype.l2"                 "predicted.celltype.l3.score"           "predicted.celltype.l3"                
 [7] "predicted.celltype.l1_backup"          "predicted.celltype.l2_backup"          "predicted.celltype.l3_backup"         
[10] "predicted.predicted.celltype.l2.score" "predicted.predicted.celltype.l2"       "predicted.pseudotime.score"           
[13] "predicted.pseudotime"                  "predicted.seurat_clusters.score"       "predicted.seurat_clusters"            
cat("\nTransferred pseudotime summary:\n")

Transferred pseudotime summary:
print(summary(mapped_MalignantCD4T$predicted.pseudotime))
    Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
 0.01186 24.06833 24.84493 23.88351 27.13900 33.71313 
cat("\nTransferred Azimuth l2 distribution (PRIMARY):\n")

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

CD4 Naive   CD4 TCM   CD4 TEM      Treg 
      108     40562        20         5 
cat("\nTransferred cluster distribution (secondary reference):\n")

Transferred cluster distribution (secondary reference):
print(table(mapped_MalignantCD4T$predicted.seurat_clusters))

    0     1    11     2     3     4     5     8     9 
 2188 27830    37  3779  1933  3107  1605    66   150 
# ── Sanity check: distribution should NOT be 99%+ in one state ────────────
l2_dist   <- prop.table(table(mapped_MalignantCD4T$predicted.predicted.celltype.l2))
max_state <- names(which.max(l2_dist))
max_pct   <- round(100 * max(l2_dist), 1)

if (max_pct > 90) {
  warning(paste0(
    "⚠️  ", max_pct, "% of cells mapped to '", max_state, "'.\n",
    "   This suggests a batch/SCT issue. Verify per-cell-line SCT ran correctly\n",
    "   and that common_features contain differentiation genes, not batch genes."
  ))
} else {
  cat("\n✅ State distribution looks diverse — projection appears unbiased\n")
  cat("   Most common state:", max_state, "(", max_pct, "% of cells)\n")
}

8 Visualise Projection on Reference UMAP

8.1 Reference + Malignant Overlay (Pseudotime)


# Coerce pseudotime from character to numeric (Seurat transfer quirk)
mapped_MalignantCD4T$predicted.pseudotime <- as.numeric(
  mapped_MalignantCD4T$predicted.pseudotime
)

# Verify
cat("Class:", class(mapped_MalignantCD4T$predicted.pseudotime), "\n")
Class: numeric 
cat("Range:", range(mapped_MalignantCD4T$predicted.pseudotime, na.rm = TRUE), "\n")
Range: 0.01186257 33.71313 
ref_umap <- data.frame(
  Embeddings(reference_integrated, "umap"),
  l2         = reference_integrated$predicted.celltype.l2,
  pseudotime = reference_integrated$monocle3_pseudotime,
  type       = "Reference"
)
colnames(ref_umap)[1:2] <- c("UMAP_1", "UMAP_2")

query_umap <- data.frame(
  Embeddings(mapped_MalignantCD4T, "ref.umap"),
  pseudotime = mapped_MalignantCD4T$predicted.pseudotime,   # numeric after fix
  cell_line  = mapped_MalignantCD4T$cell_line,
  l2_q       = mapped_MalignantCD4T$predicted.predicted.celltype.l2,
  type       = "Malignant"
)
colnames(query_umap)[1:2] <- c("UMAP_1", "UMAP_2")

# ── Cell line palette ─────────────────────────────────────────────────────
cell_line_palette <- colorRampPalette(brewer.pal(8, "Dark2"))(
  length(unique(query_umap$cell_line))
)
names(cell_line_palette) <- sort(unique(query_umap$cell_line))

all_l2_labels  <- unique(c(as.character(ref_umap$l2),
                             as.character(query_umap$l2_q)))
azimuth_l2_colors <- extend_palette(azimuth_l2_colors, all_l2_labels)

# ── Plot 1: Reference grey, malignant coloured by pseudotime ──────────────
p1 <- ggplot() +
  geom_point(data = ref_umap,
             aes(x = UMAP_1, y = UMAP_2),
             color = reference_color, size = 0.4, alpha = 0.6) +
  geom_point(data = query_umap %>% filter(is.finite(pseudotime)),
             aes(x = UMAP_1, y = UMAP_2, color = pseudotime),
             size = 1.2, alpha = 0.9) +
  scale_color_viridis_c(option = "plasma", name = "Pseudotime",
                        na.value = "grey40") +
  theme_classic(base_size = 11) +
  theme(plot.title = element_text(hjust = 0.5, face = "bold")) +
  ggtitle("Malignant CD4T Projected onto Reference\n(Coloured by transferred pseudotime)")

# ── Plot 2: Reference coloured by Azimuth l2, malignant cells in red ──────
p2 <- ggplot() +
  geom_point(data = ref_umap,
             aes(x = UMAP_1, y = UMAP_2, color = l2),
             size = 0.4, alpha = 0.7) +
  scale_color_manual(values = azimuth_l2_colors,
                     name   = "Azimuth l2\n(reference)",
                     na.value = "grey60") +
  geom_point(data = query_umap,
             aes(x = UMAP_1, y = UMAP_2),
             color = malignant_color, size = 1.0, alpha = 0.8, shape = 16) +
  theme_classic(base_size = 11) +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"),
        legend.key.size = unit(0.4, "cm"),
        legend.text = element_text(size = 8)) +
  ggtitle("Reference Azimuth l2 (colour)\n+ Malignant Cells (red overlay)")

p1 | p2

8.2 Azimuth l2 Annotation Overlay

p3 <- ggplot() +
  geom_point(data = ref_umap,
             aes(x = UMAP_1, y = UMAP_2),
             color = reference_color, size = 0.4, alpha = 0.6) +
  geom_point(data = query_umap,
             aes(x = UMAP_1, y = UMAP_2, color = l2_q),
             size = 1.2, alpha = 0.9) +
  scale_color_manual(values = azimuth_l2_colors,
                     name   = "Azimuth l2\n(transferred)",
                     na.value = "grey40") +
  theme_classic(base_size = 11) +
  theme(plot.title = element_text(hjust = 0.5, face = "bold")) +
  ggtitle("Malignant CD4T — Transferred Azimuth l2 Labels")

p4 <- ggplot() +
  geom_point(data = ref_umap,
             aes(x = UMAP_1, y = UMAP_2),
             color = reference_color, size = 0.4, alpha = 0.5) +
  geom_point(data = query_umap,
             aes(x = UMAP_1, y = UMAP_2, color = cell_line),
             size = 1.0, alpha = 0.9) +
  scale_color_manual(values = cell_line_palette, name = "Cell line") +
  theme_classic(base_size = 11) +
  theme(plot.title = element_text(hjust = 0.5, face = "bold")) +
  ggtitle("Malignant CD4T per Cell Line")

p3 | p4

8.3 Per Cell Line Facet — State Mapping

ggplot() +
  geom_point(data = ref_umap,
             aes(x = UMAP_1, y = UMAP_2),
             color = "grey60", size = 0.3, alpha = 0.5) +
  geom_point(data = query_umap %>% filter(is.finite(pseudotime)),
             aes(x = UMAP_1, y = UMAP_2, color = pseudotime),
             size = 0.9, alpha = 0.85) +
  facet_wrap(~ cell_line, ncol = 4) +
  scale_color_viridis_c(option = "plasma", name = "Pseudotime",
                        na.value = "grey60") +
  theme_classic(base_size = 10) +
  theme(strip.text = element_text(size = 9, face = "bold"),
        strip.background = element_rect(fill = "#E8F4FD"),
        plot.title = element_text(hjust = 0.5, face = "bold")) +
  ggtitle("Per Cell Line: Projection onto Reference UMAP (Pseudotime)")

9 Quantification — State Assignment

9.1 Assign Each Malignant Cell to a Reference State

# ── pseudotime bins based on reference quantiles ───────────────────────────
pt_vals   <- reference_integrated$monocle3_pseudotime
pt_vals   <- pt_vals[is.finite(pt_vals)]
pt_breaks <- quantile(pt_vals, probs = c(0, 1/3, 2/3, 1))

mapped_MalignantCD4T$state_azimuth_l2  <- mapped_MalignantCD4T$predicted.predicted.celltype.l2
mapped_MalignantCD4T$state_ref_cluster <- mapped_MalignantCD4T$predicted.seurat_clusters
mapped_MalignantCD4T$pseudotime_value  <- mapped_MalignantCD4T$predicted.pseudotime  # numeric

mapped_MalignantCD4T$pseudotime_bin <- cut(
  mapped_MalignantCD4T$pseudotime_value,
  breaks         = pt_breaks,
  labels         = c("Early (Tnaive-like)", "Mid (TCM/TEM-like)", "Late (Temra-like)"),
  include.lowest = TRUE
)

cat("=== State assignment complete ===\n")
=== State assignment complete ===
cat("\nAzimuth l2 state (PRIMARY):\n")

Azimuth l2 state (PRIMARY):
print(table(mapped_MalignantCD4T$state_azimuth_l2))

CD4 Naive   CD4 TCM   CD4 TEM      Treg 
      108     40562        20         5 
cat("\nReference cluster (cross-check):\n")

Reference cluster (cross-check):
print(table(mapped_MalignantCD4T$state_ref_cluster))

    0     1    11     2     3     4     5     8     9 
 2188 27830    37  3779  1933  3107  1605    66   150 
cat("\nPseudotime bin:\n")

Pseudotime bin:
print(table(mapped_MalignantCD4T$pseudotime_bin))

Early (Tnaive-like)  Mid (TCM/TEM-like)   Late (Temra-like) 
               3892               20081               16722 

9.2 Quantification Tables

state_summary <- mapped_MalignantCD4T@meta.data %>%
  count(state_azimuth_l2, name = "n_cells") %>%
  mutate(pct = round(100 * n_cells / sum(n_cells), 1)) %>%
  arrange(desc(n_cells))

cat("=== Overall Malignant CD4T State Distribution ===\n")
=== Overall Malignant CD4T State Distribution ===
print(state_summary)

state_per_line <- mapped_MalignantCD4T@meta.data %>%
  count(cell_line, state_azimuth_l2, name = "n_cells") %>%
  group_by(cell_line) %>%
  mutate(pct = round(100 * n_cells / sum(n_cells), 1)) %>%
  ungroup() %>%
  arrange(cell_line, desc(n_cells))

cat("\n=== State Distribution per Cell Line ===\n")

=== State Distribution per Cell Line ===
print(state_per_line, n = Inf)

cluster_summary <- mapped_MalignantCD4T@meta.data %>%
  count(state_ref_cluster, name = "n_cells") %>%
  mutate(pct = round(100 * n_cells / sum(n_cells), 1)) %>%
  arrange(as.numeric(as.character(state_ref_cluster)))

cat("\n=== Reference Cluster Distribution (cross-check) ===\n")

=== Reference Cluster Distribution (cross-check) ===
print(cluster_summary)

pt_bin_summary <- mapped_MalignantCD4T@meta.data %>%
  count(pseudotime_bin, name = "n_cells") %>%
  mutate(pct = round(100 * n_cells / sum(n_cells), 1))

cat("\n=== Pseudotime Bin Summary ===\n")

=== Pseudotime Bin Summary ===
print(pt_bin_summary)

9.3 Bar Chart — State Proportions

p_bar_overall <- ggplot(state_per_line,
                         aes(x = cell_line, y = pct, fill = state_azimuth_l2)) +
  geom_col(position = "stack", color = "white", linewidth = 0.3) +
  geom_text(aes(label = ifelse(pct >= 5, paste0(pct, "%"), "")),
            position = position_stack(vjust = 0.5),
            size = 3, color = "white", fontface = "bold") +
  scale_fill_manual(values = azimuth_l2_colors, na.value = "grey70",
                    name = "Azimuth l2\nstate") +
  theme_classic(base_size = 11) +
  theme(axis.text.x = element_text(angle = 40, hjust = 1),
        plot.title  = element_text(hjust = 0.5, face = "bold"),
        legend.key.size = unit(0.5, "cm")) +
  labs(title = "Malignant CD4T — State Composition per Cell Line\n(Azimuth l2 transferred labels)",
       x = "Cell Line", y = "% Cells")

pt_bin_line <- mapped_MalignantCD4T@meta.data %>%
  filter(!is.na(pseudotime_bin)) %>%
  count(cell_line, pseudotime_bin) %>%
  group_by(cell_line) %>%
  mutate(pct = round(100 * n / sum(n), 1)) %>%
  ungroup()

bin_colors <- c(
  "Early (Tnaive-like)" = "#4575B4",
  "Mid (TCM/TEM-like)"  = "#FEE090",
  "Late (Temra-like)"   = "#D73027"
)

p_bar_bins <- ggplot(pt_bin_line,
                      aes(x = cell_line, y = pct, fill = pseudotime_bin)) +
  geom_col(position = "stack", color = "white", linewidth = 0.3) +
  geom_text(aes(label = ifelse(pct >= 8, paste0(pct, "%"), "")),
            position = position_stack(vjust = 0.5),
            size = 3, color = "white", fontface = "bold") +
  scale_fill_manual(values = bin_colors, name = "Pseudotime\nBin") +
  theme_classic(base_size = 11) +
  theme(axis.text.x = element_text(angle = 40, hjust = 1),
        plot.title  = element_text(hjust = 0.5, face = "bold")) +
  labs(title = "Malignant CD4T — Pseudotime Bin Distribution per Cell Line",
       x = "Cell Line", y = "% Cells")

p_bar_overall / p_bar_bins

9.4 Heatmap — State Proportions Across Cell Lines

library(pheatmap)

heatmap_df <- state_per_line %>%
  select(cell_line, state_azimuth_l2, pct) %>%
  pivot_wider(names_from  = state_azimuth_l2,
              values_from = pct,
              values_fill = 0)

heatmap_mat             <- as.matrix(heatmap_df[, -1])
rownames(heatmap_mat)   <- heatmap_df$cell_line

pheatmap(
  heatmap_mat,
  color            = colorRampPalette(c("white", "#FEE090", "#D73027"))(50),
  display_numbers  = TRUE,
  number_format    = "%.1f%%",
  fontsize_number  = 8,
  fontsize_row     = 10,
  fontsize_col     = 9,
  angle_col        = 45,
  cluster_rows     = TRUE,
  cluster_cols     = TRUE,
  main             = "% Malignant Cells per State (Azimuth l2)\nClustered by cell line similarity",
  border_color     = "white"
)

10 Pseudotime Analysis of Malignant Cells

10.1 Pseudotime Distribution

ref_pt <- data.frame(
  pseudotime = reference_integrated$monocle3_pseudotime[
    is.finite(reference_integrated$monocle3_pseudotime)
  ],
  source = "Healthy reference"
)

mal_pt <- data.frame(
  pseudotime = mapped_MalignantCD4T$pseudotime_value[
    is.finite(mapped_MalignantCD4T$pseudotime_value)
  ],
  source = "Malignant CD4T"
)

pt_combined <- bind_rows(ref_pt, mal_pt)

p_density <- ggplot(pt_combined, aes(x = pseudotime, fill = source)) +
  geom_density(alpha = 0.65, adjust = 1.2) +
  scale_fill_manual(
    values = c("Healthy reference" = "#4575B4", "Malignant CD4T" = malignant_color),
    name = ""
  ) +
  theme_classic(base_size = 12) +
  theme(legend.position = "top",
        plot.title = element_text(hjust = 0.5, face = "bold")) +
  labs(title = "Pseudotime Distribution: Healthy Reference vs Malignant CD4T",
       subtitle = "Peak shift indicates differentiation arrest point",
       x = "Monocle3 Pseudotime", y = "Density")

mal_pt_line <- mapped_MalignantCD4T@meta.data %>%
  filter(is.finite(pseudotime_value)) %>%
  select(cell_line, pseudotime_value)

p_ridge_lines <- ggplot(mal_pt_line,
                         aes(x = pseudotime_value, y = cell_line, fill = cell_line)) +
  geom_density_ridges(alpha = 0.80, scale = 1.3, rel_min_height = 0.01,
                      quantile_lines = TRUE, quantiles = 2) +
  scale_fill_manual(values = cell_line_palette) +
  theme_classic(base_size = 11) +
  theme(legend.position = "none",
        plot.title = element_text(hjust = 0.5, face = "bold")) +
  labs(title = "Pseudotime Distribution per Cell Line",
       subtitle = "Vertical line = median",
       x = "Pseudotime", y = "")

p_density | p_ridge_lines

10.2 Pseudotime Summary Statistics Table

pt_stats <- mapped_MalignantCD4T@meta.data %>%
  filter(is.finite(pseudotime_value)) %>%
  group_by(cell_line) %>%
  summarise(
    n_cells   = n(),
    mean_pt   = round(mean(pseudotime_value), 3),
    median_pt = round(median(pseudotime_value), 3),
    sd_pt     = round(sd(pseudotime_value), 3),
    q25_pt    = round(quantile(pseudotime_value, 0.25), 3),
    q75_pt    = round(quantile(pseudotime_value, 0.75), 3),
    pct_early = round(100 * mean(pseudotime_value < pt_breaks[2], na.rm = TRUE), 1),
    pct_mid   = round(100 * mean(pseudotime_value >= pt_breaks[2] &
                                  pseudotime_value < pt_breaks[3], na.rm = TRUE), 1),
    pct_late  = round(100 * mean(pseudotime_value >= pt_breaks[3], na.rm = TRUE), 1)
  ) %>%
  arrange(median_pt)

cat("=== Pseudotime Statistics per Cell Line ===\n")
=== Pseudotime Statistics per Cell Line ===
print(pt_stats, n = Inf)

ref_stats <- reference_integrated@meta.data %>%
  filter(is.finite(monocle3_pseudotime), !is.na(predicted.celltype.l2)) %>%
  group_by(predicted.celltype.l2) %>%
  summarise(
    n_cells   = n(),
    mean_pt   = round(mean(monocle3_pseudotime), 3),
    median_pt = round(median(monocle3_pseudotime), 3)
  ) %>%
  arrange(median_pt)

cat("\n=== Reference Pseudotime per Azimuth l2 State (for comparison) ===\n")

=== Reference Pseudotime per Azimuth l2 State (for comparison) ===
print(ref_stats)

11 Integrated Summary Visualisation

11.1 Four-Panel Summary Figure

p_ref <- DimPlot(
  reference_integrated, group.by = "predicted.celltype.l2",
  reduction = "umap", label = TRUE, repel = TRUE,
  label.size = 3, pt.size = 0.4
) +
  scale_color_manual(values = azimuth_l2_colors, na.value = "grey40") +
  ggtitle("A. Reference CD4+ T Cells\n(Azimuth l2 — Proliferating removed)") +
  theme(plot.title = element_text(hjust = 0.5, size = 11, face = "bold")) +
  NoLegend()

p_pt_ref <- FeaturePlot(
  reference_integrated, features = "monocle3_pseudotime",
  reduction = "umap", cols = c("lightblue","yellow","red"), pt.size = 0.4
) +
  ggtitle("B. Reference Pseudotime\n(Naive → Temra axis)") +
  theme(plot.title = element_text(hjust = 0.5, size = 11, face = "bold"))

p_proj <- ggplot() +
  geom_point(data = ref_umap, aes(x = UMAP_1, y = UMAP_2),
             color = "grey88", size = 0.3, alpha = 0.6) +
  geom_point(data = query_umap %>% filter(is.finite(pseudotime)),
             aes(x = UMAP_1, y = UMAP_2, color = pseudotime),
             size = 1.0, alpha = 0.85) +
  scale_color_viridis_c(option = "plasma", name = "Pseudotime") +
  theme_classic(base_size = 10) +
  theme(plot.title = element_text(hjust = 0.5, size = 11, face = "bold")) +
  ggtitle("C. Malignant CD4T Projected\n(pseudotime transferred)")

top_states   <- state_summary %>% head(8) %>% pull(state_azimuth_l2)
state_plot_df <- state_per_line %>% filter(state_azimuth_l2 %in% top_states)

p_quant <- ggplot(state_plot_df,
                   aes(x = reorder(cell_line, -pct), y = pct,
                       fill = state_azimuth_l2)) +
  geom_col(position = "stack", color = "white", linewidth = 0.3) +
  scale_fill_manual(values = azimuth_l2_colors, na.value = "grey40",
                    name = "Azimuth l2") +
  theme_classic(base_size = 10) +
  theme(axis.text.x = element_text(angle = 40, hjust = 1, size = 9),
        plot.title  = element_text(hjust = 0.5, size = 11, face = "bold"),
        legend.key.size = unit(0.4, "cm"),
        legend.text = element_text(size = 8)) +
  labs(title = "D. State Proportions per Cell Line\n(Azimuth l2 transferred)",
       x = "", y = "% Cells")

(p_ref | p_pt_ref) / (p_proj | p_quant) +
  plot_annotation(
    title = "Malignant CD4+ T Cell Differentiation State Mapping\n(Sézary Syndrome — Monocle3 Reference Trajectory)",
    theme = theme(plot.title = element_text(hjust = 0.5, size = 14, face = "bold"))
  )

11.2 Pseudotime vs State Violin (publication-ready)

mal_state_pt <- mapped_MalignantCD4T@meta.data %>%
  filter(is.finite(pseudotime_value), !is.na(state_azimuth_l2)) %>%
  mutate(state = state_azimuth_l2)

state_order_mal <- mal_state_pt %>%
  group_by(state) %>%
  summarise(med = median(pseudotime_value)) %>%
  arrange(med) %>%
  pull(state)

mal_state_pt$state <- factor(mal_state_pt$state, levels = state_order_mal)

ggplot(mal_state_pt, aes(x = state, y = pseudotime_value, fill = state)) +
  geom_violin(scale = "width", alpha = 0.8, trim = TRUE) +
  geom_boxplot(width = 0.1, fill = "white", outlier.size = 0.3) +
  scale_fill_manual(values = azimuth_l2_colors, na.value = "grey70") +
  theme_classic(base_size = 11) +
  theme(axis.text.x = element_text(angle = 40, hjust = 1, size = 9),
        legend.position = "none",
        plot.title = element_text(hjust = 0.5, face = "bold")) +
  labs(title = "Pseudotime of Malignant CD4T per Transferred State\n(Azimuth l2 labels)",
       x = "Transferred Differentiation State",
       y = "Transferred Pseudotime")

12 Save Outputs

saveRDS(mapped_MalignantCD4T,file.path(out_dir, "MalignantCD4T_mapped_monocle3_pseudotime_noProlif_ref.rds"))
Error: C stack usage  7970484 is too close to the limit

13 Session Info


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

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

locale:
 [1] LC_CTYPE=C.UTF-8       LC_NUMERIC=C           LC_TIME=C.UTF-8        LC_COLLATE=C.UTF-8     LC_MONETARY=C.UTF-8    LC_MESSAGES=C.UTF-8    LC_PAPER=C.UTF-8      
 [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] pheatmap_1.0.13             future_1.69.0               scales_1.4.0                Matrix_1.7-4                ggrepel_0.9.6              
 [6] ggridges_0.5.7              viridis_0.6.5               viridisLite_0.4.3           RColorBrewer_1.1-3          patchwork_1.3.2            
[11] ggplot2_4.0.2               tibble_3.3.1                tidyr_1.3.2                 dplyr_1.2.0                 SeuratWrappers_0.4.0       
[16] monocle3_1.4.26             SingleCellExperiment_1.32.0 SummarizedExperiment_1.40.0 GenomicRanges_1.62.1        Seqinfo_1.0.0              
[21] IRanges_2.44.0              S4Vectors_0.48.0            MatrixGenerics_1.22.0       matrixStats_1.5.0           Biobase_2.70.0             
[26] BiocGenerics_0.56.0         generics_0.1.4              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               R.oo_1.27.1               polyclip_1.10-7           fastDummies_1.7.5        
  [7] lifecycle_1.0.5           Rdpack_2.6.6              globals_0.19.0            lattice_0.22-9            MASS_7.3-65               magrittr_2.0.4           
 [13] plotly_4.12.0             sass_0.4.10               rmarkdown_2.30            jquerylib_0.1.4           yaml_2.3.12               remotes_2.5.0            
 [19] httpuv_1.6.16             otel_0.2.0                glmGamPoi_1.22.0          sctransform_0.4.3         spam_2.11-3               spatstat.sparse_3.1-0    
 [25] reticulate_1.45.0         cowplot_1.2.0             pbapply_1.7-4             minqa_1.2.8               abind_1.4-8               Rtsne_0.17               
 [31] purrr_1.2.1               R.utils_2.13.0            irlba_2.3.7               listenv_0.10.0            spatstat.utils_3.2-1      goftest_1.2-3            
 [37] RSpectra_0.16-2           spatstat.random_3.4-4     fitdistrplus_1.2-6        parallelly_1.46.1         DelayedMatrixStats_1.32.0 codetools_0.2-20         
 [43] DelayedArray_0.36.0       tidyselect_1.2.1          farver_2.1.2              lme4_1.1-38               spatstat.explore_3.7-0    jsonlite_2.0.0           
 [49] progressr_0.18.0          survival_3.8-6            tools_4.5.2               ica_1.0-3                 Rcpp_1.1.1                glue_1.8.0               
 [55] gridExtra_2.3             SparseArray_1.10.8        xfun_0.56                 withr_3.0.2               BiocManager_1.30.27       fastmap_1.2.0            
 [61] boot_1.3-32               digest_0.6.39             rsvd_1.0.5                R6_2.6.1                  mime_0.13                 scattermore_1.2          
 [67] tensor_1.5.1              dichromat_2.0-0.1         spatstat.data_3.1-9       R.methodsS3_1.8.2         data.table_1.18.2.1       httr_1.4.8               
 [73] htmlwidgets_1.6.4         S4Arrays_1.10.1           uwot_0.2.4                pkgconfig_2.0.3           gtable_0.3.6              rsconnect_1.7.0          
 [79] lmtest_0.9-40             S7_0.2.1                  XVector_0.50.0            htmltools_0.5.9           dotCall64_1.2             png_0.1-8                
 [85] spatstat.univar_3.1-6     reformulas_0.4.4          knitr_1.51                rstudioapi_0.18.0         reshape2_1.4.5            nlme_3.1-168             
 [91] nloptr_2.2.1              proxy_0.4-29              zoo_1.8-15                cachem_1.1.0              stringr_1.6.0             KernSmooth_2.23-26       
 [97] parallel_4.5.2            miniUI_0.1.2              pillar_1.11.1             grid_4.5.2                vctrs_0.7.1               RANN_2.6.2               
[103] promises_1.5.0            beachmat_2.26.0           xtable_1.8-4              cluster_2.1.8.2           evaluate_1.0.5            cli_3.6.5                
[109] query_ranks rlang_1.1.7               future.apply_1.20.1       labeling_0.4.3            plyr_1.8.9                stringi_1.8.7            
[115] deldir_2.0-4              assertthat_0.2.1          lazyeval_0.2.2            spatstat.geom_3.7-0       RcppHNSW_0.6.0            sparseMatrixStats_1.22.0 
[121] shiny_1.12.1              rbibutils_2.4.1           ROCR_1.0-12               igraph_2.2.2              bslib_0.10.0             
LS0tCnRpdGxlOiAiTWFsaWduYW50IENENCBUIENlbGwgVHJhamVjdG9yeSBBbmFseXNpcyIKc3VidGl0bGU6ICJNb25vY2xlMyBwc2V1ZG90aW1lIG1hcHBpbmciCmF1dGhvcjogIk5hc2lyIE1haG1vb2QgQWJiYXNpIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiB0cnVlCiAgICB0aGVtZTogam91cm5hbAogICAgaGlnaGxpZ2h0OiB0YW5nbwogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIGRmX3ByaW50OiBwYWdlZAogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCi0tLQoKCiAgICAKCjwhLS0gICAg4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQIC0tPgo8IS0tICAgICAgU0NJRU5USUZJQyBSQVRJT05BTEUgJiBBUFBST0FDSCBDT01NRU5UQVJZIC0tPgo8IS0tICAg4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQIC0tPgoKPCEtLSAgIFdIWSBUSElTIEFQUFJPQUNIPyAtLT4KPCEtLSAgIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgCAtLT4KPCEtLSAgIFPDqXphcnkgU3luZHJvbWUgKFNTKSBpcyBhIGxldWtlbWljIGZvcm0gb2YgY3V0YW5lb3VzIFQtY2VsbCBseW1waG9tYSBpbiB3aGljaCAtLT4KPCEtLSAgIG1hbGlnbmFudCBDRDQrIFQgY2VsbHMgKFPDqXphcnkgY2VsbHMpIGFjY3VtdWxhdGUgaW4gYmxvb2QsIHNraW4sIGFuZCBseW1waCBub2Rlcy4gLS0+CjwhLS0gICBBIGNlbnRyYWwgdW5yZXNvbHZlZCBxdWVzdGlvbiBpczogV0hFUkUgYWxvbmcgdGhlIG5vcm1hbCBDRDQrIFQgY2VsbCBkaWZmZXJlbnRpYXRpb24gLS0+CjwhLS0gICBjb250aW51dW0gZG8gdGhlc2UgbWFsaWduYW50IGNlbGxzIGFycmVzdCBvciBvcmlnaW5hdGU/IC0tPgoKPCEtLSAgIENsYXNzaWNhbCBidWxrIGFwcHJvYWNoZXMgKG1pY3JvYXJyYXksIGJ1bGsgUk5BLXNlcSkgY2Fubm90IHJlc29sdmUgdGhpcyBiZWNhdXNlIHRoZXkgLS0+CjwhLS0gICBhdmVyYWdlIGFjcm9zcyBtaWxsaW9ucyBvZiBjZWxscy4gU2luZ2xlLWNlbGwgUk5BLXNlcSArIHBzZXVkb3RpbWUgdHJhamVjdG9yeSBhbmFseXNpcyAtLT4KPCEtLSAgIGFsbG93cyB1cyB0bzogLS0+Cgo8IS0tICAgMS4gQlVJTEQgYSByZWZlcmVuY2UgZGlmZmVyZW50aWF0aW9uIG1hcCBmcm9tIEhFQUxUSFkgQ0Q0KyBUIGNlbGxzIHNwYW5uaW5nIGFsbCAtLT4KPCEtLSAgICAgIGtub3duIHN0YXRlczogVG5haXZlIOKGkiBUQ00g4oaSIFRFTSDihpIgVGVtcmEsIHdpdGggVHJlZyBhcyBhIHNpZGUgYnJhbmNoLiAtLT4KPCEtLSAgICAgIFRoaXMgcmVmZXJlbmNlIGlzIHRoZSAibm9ybWFsIGF0bGFzIiBvZiBDRDQrIFQgY2VsbCBiaW9sb2d5LiAtLT4KCjwhLS0gICAyLiBQUk9KRUNUIG1hbGlnbmFudCBTw6l6YXJ5IGNlbGxzIG9udG8gdGhpcyBoZWFsdGh5IGF0bGFzIHVzaW5nIFNldXJhdCBNYXBRdWVyeSAtLT4KPCEtLSAgICAgIChhbmNob3JlZCBSUENBLWJhc2VkIHRyYW5zZmVyKS4gRWFjaCBtYWxpZ25hbnQgY2VsbCBnZXRzIGNvb3JkaW5hdGVzIGluIHRoZSAtLT4KPCEtLSAgICAgIHJlZmVyZW5jZSBVTUFQIHNwYWNlIOKAlCBtZWFuaW5nIHdlIGNhbiBzZWUgZXhhY3RseSBXSEVSRSBpdCBmYWxscyByZWxhdGl2ZSAtLT4KPCEtLSAgICAgIHRvIGhlYWx0aHkgZGlmZmVyZW50aWF0aW9uIHN0YXRlcy4gLS0+Cgo8IS0tICAgMy4gVFJBTlNGRVIgcHNldWRvdGltZSBmcm9tIHJlZmVyZW5jZSB0byBxdWVyeS4gQmVjYXVzZSB0aGUgaGVhbHRoeSB0cmFqZWN0b3J5IC0tPgo8IS0tICAgICAgaGFzIGEgY29udGludW91cyBwc2V1ZG90aW1lIGF4aXMgKE5haXZlPTAg4oaSIFRlbXJhPW1heCksIGVhY2ggcHJvamVjdGVkIC0tPgo8IS0tICAgICAgbWFsaWduYW50IGNlbGwgaW5oZXJpdHMgYSBwc2V1ZG90aW1lIHZhbHVlLiBUaGlzIHRlbGxzIHVzOiAtLT4KPCEtLSAgICAgICAgLSBMb3cgcHNldWRvdGltZSDihpIgbWFsaWduYW50IGNlbGwgcmVzZW1ibGVzIG5hw692ZS9lYXJseSBtZW1vcnkgc3RhdGUgLS0+CjwhLS0gICAgICAgIC0gSGlnaCBwc2V1ZG90aW1lIOKGkiBtYWxpZ25hbnQgY2VsbCByZXNlbWJsZXMgbGF0ZSBlZmZlY3Rvci9UZW1yYSBzdGF0ZSAtLT4KPCEtLSAgICAgICAgLSBJbnRlcm1lZGlhdGUg4oaSIG1hbGlnbmFudCBjZWxsIGlzIGFycmVzdGVkIGF0IGEgc3BlY2lmaWMgbWVtb3J5IGNoZWNrcG9pbnQgLS0+Cgo8IS0tICAgNC4gUVVBTlRJRlkgc3RhdGUgZGlzdHJpYnV0aW9uOiBCeSBjb21iaW5pbmcgcHJvamVjdGVkIGNvb3JkaW5hdGVzIHdpdGggQXppbXV0aCAtLT4KPCEtLSAgICAgIHByZWRpY3RlZC5jZWxsdHlwZS5sMiBsYWJlbHMgKHRyYW5zZmVycmVkIGZyb20gcmVmZXJlbmNlKSwgd2UgY2FuIGNvdW50IHdoYXQgLS0+CjwhLS0gICAgICBmcmFjdGlvbiBvZiBtYWxpZ25hbnQgY2VsbHMgbWFwIHRvIGVhY2ggaGVhbHRoeSBzdGF0ZSAoVG5haXZlLCBUQ00sIFRFTSwgVGVtcmEsIC0tPgo8IS0tICAgICAgVHJlZykuIFRoaXMgcHJvdmlkZXMgYSBtb2xlY3VsYXIgImZpbmdlcnByaW50IiBvZiB0aGUgbWFsaWduYW50IHBvcHVsYXRpb24uIC0tPgoKPCEtLSAgIFdIWSBNT05PQ0xFMyBPTiBUSEUgUkVGRVJFTkNFIChOT1QgT04gTUFMSUdOQU5UIENFTExTKT8gLS0+CjwhLS0gICDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAgLS0+CjwhLS0gICBSdW5uaW5nIE1vbm9jbGUzIG9uIG1hbGlnbmFudCBjZWxscyBhbG9uZSB3b3VsZCBwcm9kdWNlIGEgdHJhamVjdG9yeSByZWZsZWN0aW5nIC0tPgo8IS0tICAgdHVtb3VyIGhldGVyb2dlbmVpdHkg4oCUIG5vdCB0aGUgYmlvbG9naWNhbCBkaWZmZXJlbnRpYXRpb24gYXhpcyB3ZSB3YW50IHRvIG1lYXN1cmUgLS0+CjwhLS0gICBhZ2FpbnN0LiBJbnN0ZWFkOiAtLT4KCjwhLS0gICAgIFN0ZXAgMTogTGVhcm4gdGhlIHRyYWplY3Rvcnkgb24gSEVBTFRIWSByZWZlcmVuY2UgY2VsbHMgb25seS4gLS0+CjwhLS0gICAgICAgICAgICAgTW9ub2NsZTMgYnVpbGRzIGEgcHJpbmNpcGFsIGdyYXBoIHRocm91Z2ggdGhlIGhlYWx0aHkgbWFuaWZvbGQuIC0tPgo8IS0tICAgICAgICAgICAgIFJvb3QgPSBDRDQgVG5haXZlIGNsdXN0ZXIgKENDUjcrU0VMTCtUQ0Y3KykuIC0tPgoKPCEtLSAgICAgU3RlcCAyOiBGcmVlemUgdGhlIHJlZmVyZW5jZSBVTUFQIG1vZGVsIChyZXR1cm4ubW9kZWwgPSBUUlVFIGluIFJ1blVNQVApLiAtLT4KCjwhLS0gICAgIFN0ZXAgMzogUHJvamVjdCBtYWxpZ25hbnQgY2VsbHMgaW50byB0aGlzIGZyb3plbiBzcGFjZSB2aWEgTWFwUXVlcnkuIC0tPgo8IS0tICAgICAgICAgICAgIE1hbGlnbmFudCBjZWxscyBETyBOT1QgYWx0ZXIgdGhlIHJlZmVyZW5jZSB0cmFqZWN0b3J5IOKAlCAtLT4KPCEtLSAgICAgICAgICAgICB0aGV5IGFyZSBvdmVybGFpZCBhcyAicGFzc2VuZ2VycyIgb24gdGhlIGhlYWx0aHkgdG9wb2xvZ3kuIC0tPgoKPCEtLSAgICAgU3RlcCA0OiBUcmFuc2ZlciBwc2V1ZG90aW1lIGFuZCBBemltdXRoIGwyIGxhYmVscyB0byBwcm9qZWN0ZWQgY2VsbHMuIC0tPgoKPCEtLSAgIFRoaXMgaXMgbWV0aG9kb2xvZ2ljYWxseSBlcXVpdmFsZW50IHRvIHdoYXQgQ2VyYXBpbyBldCBhbC4gZGlkOiAtLT4KPCEtLSAgIGJ1aWxkaW5nIGEgcmVmZXJlbmNlIENENCsgdHJhamVjdG9yeSBhbmQgcHJvamVjdGluZyB0dW1vdXIgY2VsbHMgdG8gaWRlbnRpZnkgLS0+CjwhLS0gICB0aGUgZGlmZmVyZW50aWF0aW9uIHN0YXRlIG9mIGFycmVzdCBpbiBTw6l6YXJ5IGNlbGxzLiAtLT4KCjwhLS0gICBXSElDSCBPQkpFQ1QgVE8gVVNFPyAtLT4KPCEtLSAgIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgCAtLT4KPCEtLSAgIFVzZSB0aGUgQU5OT1RBVEVEIHJlZmVyZW5jZSB3aXRoIE1vbm9jbGUzIHRyYWplY3RvcnkgYWxyZWFkeSBjb21wdXRlZCAtLT4KPCEtLSAgIEFORCB3aXRoIENENCBQcm9saWZlcmF0aW5nIGNlbGxzIHJlbW92ZWQuIFRoaXMgb2JqZWN0IGhhczogLS0+CjwhLS0gICAgIC0gSW50ZWdyYXRlZCBVTUFQIHdpdGggcmV0dXJuLm1vZGVsID0gVFJVRSAgICAgICAgICDinIUgLS0+CjwhLS0gICAgIC0gU2V1cmF0IGNsdXN0ZXJzIDAtNiB3aXRoIGNlbGxfdHlwZSBhbm5vdGF0aW9uICAgICDinIUgLS0+CjwhLS0gICAgIC0gbW9ub2NsZTNfcHNldWRvdGltZSBjb2x1bW4gYWxyZWFkeSBjb21wdXRlZCAgICAgICDinIUgLS0+CjwhLS0gICAgIC0gcHJlZGljdGVkLmNlbGx0eXBlLmwyIChBemltdXRoKSBsYWJlbHMgICAgICAgICAgICDinIUgLS0+CjwhLS0gICAgIC0gQ0Q0IFByb2xpZmVyYXRpbmcgY2x1c3RlciByZW1vdmVkICAgICAgICAgICAgICAgICDinIUgLS0+CjwhLS0gICAgIC0gQ2x1c3RlciAxMiBjb250YW1pbmF0aW9uIHJlbW92ZWQgICAgICAgICAgICAgICAgICDinIUgLS0+Cgo8IS0tICAgV0hZIFJFTU9WRSBDRDQgUFJPTElGRVJBVElORyBDRUxMUyBGUk9NIFRIRSBSRUZFUkVOQ0U/IC0tPgo8IS0tICAg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAIC0tPgo8IS0tICAgUHJvbGlmZXJhdGluZyBDRDQrIFQgY2VsbHMgKE1LSTY3KywgVE9QMkErLCBDREsxKykgcmVwcmVzZW50IGNlbGxzIC0tPgo8IS0tICAgYWN0aXZlbHkgY3ljbGluZyB0aHJvdWdoIHRoZSBjZWxsIGN5Y2xlIOKAlCBub3QgYSBzdGFibGUgZGlmZmVyZW50aWF0aW9uIC0tPgo8IS0tICAgc3RhdGUuIEluY2x1ZGluZyB0aGVtIGluIHRoZSB0cmFqZWN0b3J5IHdvdWxkOiAtLT4KPCEtLSAgICAgMS4gQ3JlYXRlIGEgc3B1cmlvdXMgYnJhbmNoIHB1bGxlZCBieSBjZWxsIGN5Y2xlIHNpZ25hdHVyZSAoUy9HMk0gZ2VuZXMpIC0tPgo8IS0tICAgICAgICByYXRoZXIgdGhhbiBkaWZmZXJlbnRpYXRpb24gZ2VuZXMgKENDUjcsIEdaTUssIEZPWFAzIGV0Yy4pIC0tPgo8IS0tICAgICAyLiBEaXN0b3J0IHRoZSBwc2V1ZG90aW1lIGF4aXMg4oCUIHByb2xpZmVyYXRpbmcgY2VsbHMgZ2V0IGludGVybWVkaWF0ZSAtLT4KPCEtLSAgICAgICAgcHNldWRvdGltZSB2YWx1ZXMgdGhhdCBkb24ndCByZWZsZWN0IHRoZWlyIHRydWUgZGlmZmVyZW50aWF0aW9uIHN0YXRlIC0tPgo8IS0tICAgICAzLiBDb25mb3VuZCB0aGUgbWFsaWduYW50IGNlbGwgcHJvamVjdGlvbiDigJQgU8OpemFyeSBjZWxscyB0aGF0IGhhcHBlbiAtLT4KPCEtLSAgICAgICAgdG8gYmUgcHJvbGlmZXJhdGluZyB3b3VsZCBtYXAgdG8gdGhlIHdyb25nIHJlZmVyZW5jZSBzdGF0ZSAtLT4KPCEtLSAgIFJlbW92aW5nIHRoZW0gcHJvZHVjZXMgYSBjbGVhbiBUbmFpdmUg4oaSIFRDTSDihpIgVEVNIOKGkiBUZW1yYSBheGlzLiAtLT4KCjwhLS0gICBETyBOT1QgcmUtcnVuIFNDVHJhbnNmb3JtL2ludGVncmF0aW9uIG9uIHRoZSByZWZlcmVuY2UgYXQgdGhpcyBzdGVwLiAtLT4KPCEtLSAgIERPIE5PVCB1c2UgdGhlIHJhdyBwcmUtdHJhamVjdG9yeSBvYmplY3Qg4oCUIGl0IGxhY2tzIHRoZSBVTUFQIG1vZGVsIG5lZWRlZCAtLT4KPCEtLSAgIGZvciBNYXBRdWVyeSBwcm9qZWN0aW9uLiAtLT4KPCEtLSAgIERPIE5PVCB1c2UgdGhlIHNsaW5nc2hvdC1yZWFkeSBvYmplY3Qg4oCUIHNhbWUgaXNzdWUsIG5vIGZyb3plbiBVTUFQIG1vZGVsLiAtLT4KCjwhLS0g4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQICAtLT4KCgojIExvYWQgTGlicmFyaWVzCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgZWNobyAgICA9IFRSVUUsCiAgd2FybmluZyA9IEZBTFNFLAogIG1lc3NhZ2UgPSBGQUxTRSwKICBmaWcud2lkdGggID0gMTIsCiAgZmlnLmhlaWdodCA9IDgKKQoKIyBDb3JlIHNpbmdsZS1jZWxsCmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KG1vbm9jbGUzKQpsaWJyYXJ5KFNldXJhdFdyYXBwZXJzKQoKIyBEYXRhIHdyYW5nbGluZwpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHRpYmJsZSkKCiMgVmlzdWFsaXNhdGlvbgpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeSh2aXJpZGlzKQpsaWJyYXJ5KGdncmlkZ2VzKSAgICAjIGZvciBwc2V1ZG90aW1lIGRlbnNpdHkgcmlkZ2UgcGxvdHMKbGlicmFyeShnZ3JlcGVsKSAgICAgIyBmb3IgbGFiZWwgcmVwdWxzaW9uCgojIFN0YXRpc3RpY3MgJiB0YWJsZXMKbGlicmFyeShNYXRyaXgpCmxpYnJhcnkoc2NhbGVzKSAgICAgICMgZm9yIHBlcmNlbnQgZm9ybWF0dGluZwoKb3B0aW9ucyhmdXR1cmUuZ2xvYmFscy5tYXhTaXplID0gOGU5KQpzZXQuc2VlZCgxMjM0KQoKIyDilIDilIAgQ29sb3VyIHBhbGV0dGVzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAojIFBSSU1BUlk6IEF6aW11dGggcHJlZGljdGVkLmNlbGx0eXBlLmwyIGNvbG91cnMg4oCUIGJ1aWx0IERZTkFNSUNBTExZIGZyb20KIyBhY3R1YWwgbGFiZWxzIGluIHRoZSBkYXRhIChhZnRlciBsb2FkaW5nIHRoZSByZWZlcmVuY2Ugb2JqZWN0KS4KIyBUaGVzZSBrbm93biBBemltdXRoIGwyIENENCBUIGNlbGwgbGFiZWxzIGFyZSBwcmUtc2VlZGVkIGhlcmUgc28gY29sb3VycwojIGFyZSBjb25zaXN0ZW50IGFuZCBiaW9sb2dpY2FsbHkgb3JkZXJlZCAoYmx1ZT1uYWl2ZSDihpIgcmVkPWVmZmVjdG9yKS4KIyBBbnkgZXh0cmEgbGFiZWxzIG5vdCBsaXN0ZWQgaGVyZSB3aWxsIGJlIGFzc2lnbmVkIGNvbG91cnMgYXV0b21hdGljYWxseS4KCmF6aW11dGhfbDJfY29sb3JzIDwtIGMoCiAgIyDilIDilIAgTmFpdmUg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACiAgIkNENCBOYWl2ZSIgICAgICAgICAgPSAiIzIxNjZBQyIsICAgIyBkYXJrIGJsdWUKICAiQ0Q0IFROIiAgICAgICAgICAgICA9ICIjMjE2NkFDIiwgICAjIGFsaWFzCiAgIyDilIDilIAgQ2VudHJhbCBNZW1vcnkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACiAgIkNENCBUQ00iICAgICAgICAgICAgPSAiIzc0QUREMSIsICAgIyBza3kgYmx1ZQogICMg4pSA4pSAIEVmZmVjdG9yIE1lbW9yeSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKICAiQ0Q0IFRFTSIgICAgICAgICAgICA9ICIjRkVFMDkwIiwgICAjIHBhbGUgeWVsbG93CiAgIyDimqDvuI8gIENPTkZJUk1FRCBsYWJlbCBpbiB0aGlzIGRhdGFzZXQ6ICJDRDQgVGVtcmEvQ1RMIiAoQXppbXV0aCB2MS4xKykKICAiQ0Q0IFRlbXJhL0NUTCIgICAgICA9ICIjRDczMDI3IiwgICAjIHJlZCAg4oaQIGV4YWN0IG1hdGNoIHRvIGRhdGEKICAiQ0Q0IFRFTVJBIiAgICAgICAgICA9ICIjRDczMDI3IiwgICAjIGFsaWFzIOKAlCBvbGRlciBBemltdXRoIChhbGwgY2FwcykKICAiQ0Q0IFRFTVJBL0NUTCIgICAgICA9ICIjRDczMDI3IiwgICAjIGFsaWFzIOKAlCB1cHBlcmNhc2UgdmFyaWFudAogICJDRDQgQ1RMIiAgICAgICAgICAgID0gIiNENzMwMjciLCAgICMgYWxpYXMg4oCUIHNvbWUgcmVmZXJlbmNlIGJ1aWxkcwogICMg4pSA4pSAIFJlZ3VsYXRvcnkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACiAgIlRyZWciICAgICAgICAgICAgICAgPSAiIzc2MkE4MyIsICAgIyBkYXJrIHB1cnBsZSAg4oaQIGNvbmZpcm1lZCBsYWJlbCBpbiB0aGlzIGRhdGEKICAiVHJlZyBOYWl2ZSIgICAgICAgICA9ICIjOTk3MEFCIiwgICAjIG1lZGl1bSBwdXJwbGUg4oCUIGFsaWFzCiAgIlRyZWcgTWVtb3J5IiAgICAgICAgPSAiIzc2MkE4MyIsICAgIyBhbGlhcwogICMg4pSA4pSAIE90aGVyIENENCBzdWJzZXRzIHRoYXQgQXppbXV0aCBsMiBtYXkgcmV0dXJuIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAogICJDRDQgUHJvbGlmZXJhdGluZyIgID0gIiNBNkE2QTYiLCAgICMgZ3JleSAg4oCUIE5PVEU6IHByZXNlbnQgaW4gcXVlcnkgY2VsbHMgb25seQogICJUaDEiICAgICAgICAgICAgICAgID0gIiNGNDZENDMiLAogICJUaDE3IiAgICAgICAgICAgICAgID0gIiNGREFFNjEiLAogICJUaDEvVGgxNyIgICAgICAgICAgID0gIiNGRUUwOEIiLAogICJUZmgiICAgICAgICAgICAgICAgID0gIiM2NkMyQTUiLAogICJDRDQgVENNXzEiICAgICAgICAgID0gIiM5RUNBRTEiLAogICJDRDQgVENNXzIiICAgICAgICAgID0gIiM2QkFFRDYiLAogICJDRDQgVENNXzMiICAgICAgICAgID0gIiM0MjkyQzYiLAogICJDRDQgVEVNXzEiICAgICAgICAgID0gIiNGREQwQTIiLAogICJDRDQgVEVNXzIiICAgICAgICAgID0gIiNGREFFNkIiLAogICJDRDQgVEVNXzMiICAgICAgICAgID0gIiNGRDhEM0MiLAogICJDRDQgVEVNXzQiICAgICAgICAgID0gIiNEOTQ4MDEiCikKIyBOT1RFOiBDRDQgUHJvbGlmZXJhdGluZyBpcyBrZXB0IGluIHRoaXMgcGFsZXR0ZSAoZ3JleSkgYmVjYXVzZSBpdCBtYXkKIyBhcHBlYXIgaW4gdGhlIE1BTElHTkFOVCBjZWxscyBhZnRlciBwcm9qZWN0aW9uIOKAlCBtYWxpZ25hbnQgU8OpemFyeSBjZWxscwojIGNhbiBiZSBjeWNsaW5nLiBJdCBpcyBhYnNlbnQgZnJvbSB0aGUgUkVGRVJFTkNFIG9ubHkuCgptYWxpZ25hbnRfY29sb3IgPC0gIiNFMzFBMUMiICAgIyB2aXZpZCByZWQgZm9yIG1hbGlnbmFudCBjZWxsIG92ZXJsYXkKcmVmZXJlbmNlX2NvbG9yIDwtICJncmV5ODUiICAgICMgcmVmZXJlbmNlIGJhY2tncm91bmQgaW4gb3ZlcmxheSBwbG90cwoKIyDilIDilIAgSGVscGVyOiBleHRlbmQgcGFsZXR0ZSBmb3IgYW55IHVuZXhwZWN0ZWQgbDIgbGFiZWxzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAojIENhbGxlZCBhZnRlciBsb2FkaW5nIGRhdGEgdG8gZmlsbCBpbiBhbnkgbGFiZWxzIG5vdCBpbiBhemltdXRoX2wyX2NvbG9ycwpleHRlbmRfcGFsZXR0ZSA8LSBmdW5jdGlvbihwYWxldHRlLCBsYWJlbHMpIHsKICBtaXNzaW5nX2xhYmVscyA8LSBzZXRkaWZmKGxhYmVscywgbmFtZXMocGFsZXR0ZSkpCiAgaWYgKGxlbmd0aChtaXNzaW5nX2xhYmVscykgPiAwKSB7CiAgICBleHRyYV9jb2xzIDwtIGNvbG9yUmFtcFBhbGV0dGUoUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKDgsICJEYXJrMiIpKShsZW5ndGgobWlzc2luZ19sYWJlbHMpKQogICAgbmFtZXMoZXh0cmFfY29scykgPC0gbWlzc2luZ19sYWJlbHMKICAgIHBhbGV0dGUgPC0gYyhwYWxldHRlLCBleHRyYV9jb2xzKQogIH0KICBwYWxldHRlCn0KYGBgCgoKIyBMb2FkIE9iamVjdHMKCiMjIExvYWQgUmVmZXJlbmNlIChIZWFsdGh5IENENCsgVCBDZWxscyB3aXRoIFRyYWplY3RvcnkpCgpgYGB7ciBsb2FkLXJlZmVyZW5jZX0KIyDilIDilIAgQ1JJVElDQUw6IHVzZSB0aGUgQU5OT1RBVEVEIHJlZmVyZW5jZSB3aXRoIHNhdmVkIFVNQVAgbW9kZWwg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACiMgVGhpcyBpcyB0aGUgY2xlYW5lZCByZWZlcmVuY2Ugb2JqZWN0IHdpdGg6CiMgICAtIENENCBQcm9saWZlcmF0aW5nIGNsdXN0ZXIgcmVtb3ZlZCAoTUtJNjcrL1RPUDJBKy9DREsxKyBjZWxscykKIyAgIC0gQ2x1c3RlciAxMiBjb250YW1pbmF0aW9uIHJlbW92ZWQKIyAgIC0gVU1BUCByZWR1Y3Rpb24gd2l0aCByZXR1cm4ubW9kZWwgPSBUUlVFCiMgICAtIG1vbm9jbGUzX3BzZXVkb3RpbWUgY29sdW1uIGNvbXB1dGVkIG9uIHRoZSBjbGVhbiB0cmFqZWN0b3J5CiMgICAtIGNlbGxfdHlwZSBhbm5vdGF0aW9uIChjbHVzdGVycyAwLTYsIG5vIHByb2xpZmVyYXRpbmcpCiMgICAtIHByZWRpY3RlZC5jZWxsdHlwZS5sMiAoQXppbXV0aCBsMikKIyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKCgpyZWZlcmVuY2VfaW50ZWdyYXRlZCA8LSByZWFkUkRTKCIuLi9QYXJ0M19TbGluZ3Nob3RfVHJhamVjdG9yeS9wYXJ0NF9TbGluZ3Nob3QrUHJvamVjdGlvbi9jZDRfcmVmX2R1YWxfdHJhamVjdG9yeS5yZHMiKQoKY2F0KCI9PT0gUmVmZXJlbmNlIG9iamVjdCBzdW1tYXJ5ID09PVxuIikKY2F0KCJDZWxsczoiLCBuY29sKHJlZmVyZW5jZV9pbnRlZ3JhdGVkKSwgIlxuIikKY2F0KCJBc3NheXM6IiwgcGFzdGUobmFtZXMocmVmZXJlbmNlX2ludGVncmF0ZWRAYXNzYXlzKSwgY29sbGFwc2UgPSAiLCAiKSwgIlxuIikKY2F0KCJSZWR1Y3Rpb25zOiIsIHBhc3RlKG5hbWVzKHJlZmVyZW5jZV9pbnRlZ3JhdGVkQHJlZHVjdGlvbnMpLCBjb2xsYXBzZSA9ICIsICIpLCAiXG4iKQpjYXQoIlVNQVAgbW9kZWwgcHJlc2VudDoiLCAhaXMubnVsbChyZWZlcmVuY2VfaW50ZWdyYXRlZEByZWR1Y3Rpb25zJHVtYXBAbWlzYyRtb2RlbCksICJcbiIpCgojIOKUgOKUgCBDb25maXJtIGNsdXN0ZXJzIHByZXNlbnQg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACmNhdCgiXG5DbHVzdGVycyBwcmVzZW50OiIsIHBhc3RlKHNvcnQodW5pcXVlKHJlZmVyZW5jZV9pbnRlZ3JhdGVkJHNldXJhdF9jbHVzdGVycykpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xsYXBzZSA9ICIsICIpLCAiXG4iKQoKIyDilIDilIAgQ29uZmlybSBDRDQgUHJvbGlmZXJhdGluZyBjZWxscyBhcmUgQUJTRU5UIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAojIENoZWNrIDE6IGNlbGxfdHlwZSBsYWJlbCBzaG91bGQgbm90IGNvbnRhaW4gIlByb2xpZiIKaWYgKGFueShncmVwbCgiUHJvbGlmfHByb2xpZnxjeWNsaW5nfEN5Y2xpbmciLCByZWZlcmVuY2VfaW50ZWdyYXRlZCRjZWxsX3R5cGUsCiAgICAgICAgICAgICAgaWdub3JlLmNhc2UgPSBUUlVFKSkpIHsKICB3YXJuaW5nKCLimqDvuI8gIFByb2xpZmVyYXRpbmcgY2VsbF90eXBlIGxhYmVscyBzdGlsbCBkZXRlY3RlZCEgQ2hlY2sgcmVtb3ZhbCBzdGVwLiIpCn0gZWxzZSB7CiAgY2F0KCLinIUgTm8gcHJvbGlmZXJhdGluZyBjZWxsX3R5cGUgbGFiZWxzIGZvdW5kXG4iKQp9CgojIENoZWNrIDI6IE1vbGVjdWxhciBzaWduYXR1cmUg4oCUIE1LSTY3L1RPUDJBIGV4cHJlc3Npb24gc2hvdWxkIGJlIG5lYXIgemVybwpwcm9saWZfbWFya2VycyA8LSBjKCJNS0k2NyIsICJUT1AyQSIsICJQQ05BIiwgIkNESzEiLCAiU1RNTjEiKQpwcm9saWZfcHJlc2VudCA8LSBpbnRlcnNlY3QocHJvbGlmX21hcmtlcnMsIHJvd25hbWVzKHJlZmVyZW5jZV9pbnRlZ3JhdGVkKSkKCmlmIChsZW5ndGgocHJvbGlmX3ByZXNlbnQpID4gMCkgewogIERlZmF1bHRBc3NheShyZWZlcmVuY2VfaW50ZWdyYXRlZCkgPC0gIlNDVCIKICBwcm9saWZfZXhwciA8LSBNYXRyaXg6OmNvbE1lYW5zKAogICAgR2V0QXNzYXlEYXRhKHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCBsYXllciA9ICJkYXRhIilbcHJvbGlmX3ByZXNlbnQsICwgZHJvcCA9IEZBTFNFXQogICkKICBjYXQoIlByb2xpZmVyYXRpb24gbWFya2VyIHNjb3JlIOKAlCBtYXg6Iiwgcm91bmQobWF4KHByb2xpZl9leHByKSwgMyksCiAgICAgICIgfCBtZWFuOiIsIHJvdW5kKG1lYW4ocHJvbGlmX2V4cHIpLCA0KSwgIlxuIikKICBjYXQoIkNlbGxzIHdpdGggYW55IHByb2xpZiBtYXJrZXIgPiAwLjU6Iiwgc3VtKHByb2xpZl9leHByID4gMC41KSwKICAgICAgIihleHBlY3QgbmVhciB6ZXJvIGFmdGVyIHJlbW92YWwpXG4iKQogIGlmIChzdW0ocHJvbGlmX2V4cHIgPiAwLjUpID4gNTApIHsKICAgIHdhcm5pbmcoIuKaoO+4jyAgU3Vic3RhbnRpYWwgcHJvbGlmZXJhdGlvbiBzaWduYWwgcmVtYWlucyDigJQgdmVyaWZ5IHJlbW92YWwgd2FzIGNvbXBsZXRlLiIpCiAgfSBlbHNlIHsKICAgIGNhdCgi4pyFIFByb2xpZmVyYXRpbmcgY2VsbHMgY29uZmlybWVkIHJlbW92ZWRcbiIpCiAgfQp9CgojIOKUgOKUgCBDZWxsIHR5cGUgZGlzdHJpYnV0aW9uIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApjYXQoIlxuQ2VsbCB0eXBlIGRpc3RyaWJ1dGlvbiAoc2hvdWxkIGJlIDYgdHlwZXMsIG5vIFByb2xpZmVyYXRpbmcpOlxuIikKcHJpbnQodGFibGUocmVmZXJlbmNlX2ludGVncmF0ZWQkY2VsbF90eXBlKSkKCmNhdCgiXG5BemltdXRoIGwyIGRpc3RyaWJ1dGlvbjpcbiIpCnByaW50KHRhYmxlKHJlZmVyZW5jZV9pbnRlZ3JhdGVkJHByZWRpY3RlZC5jZWxsdHlwZS5sMikpCgojIOKUgOKUgCBGaW5hbGlzZSBBemltdXRoIGwyIGNvbG91ciBwYWxldHRlIGZyb20gYWN0dWFsIGxhYmVscyBpbiBkYXRhIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApyZWZfbDJfbGFiZWxzIDwtIHVuaXF1ZShhcy5jaGFyYWN0ZXIocmVmZXJlbmNlX2ludGVncmF0ZWQkcHJlZGljdGVkLmNlbGx0eXBlLmwyKSkKcmVmX2wyX2xhYmVscyA8LSByZWZfbDJfbGFiZWxzWyFpcy5uYShyZWZfbDJfbGFiZWxzKV0KYXppbXV0aF9sMl9jb2xvcnMgPC0gZXh0ZW5kX3BhbGV0dGUoYXppbXV0aF9sMl9jb2xvcnMsIHJlZl9sMl9sYWJlbHMpCmNhdCgiXG5BemltdXRoIGwyIGNvbG91ciBwYWxldHRlIGNvdmVycyIsIGxlbmd0aChyZWZfbDJfbGFiZWxzKSwgInJlZmVyZW5jZSBsYWJlbHMg4pyFXG4iKQoKIyBOT1RFOiBtb25vY2xlM19wc2V1ZG90aW1lIHN1bW1hcnkgaXMgcHJpbnRlZCBBRlRFUiB0cmFqZWN0b3J5IGlzIGJ1aWx0CiMgKFNlY3Rpb24gMiBiZWxvdykuIElmIHRoaXMgaXMgYSBmcmVzaGx5IGxvYWRlZCByZWZlcmVuY2UgdGhhdCBhbHJlYWR5CiMgaGFzIHBzZXVkb3RpbWUgc3RvcmVkLCB0aGUgdmFsaWRhdGUtcHNldWRvdGltZSBjaHVuayB3aWxsIHN1bW1hcmlzZSBpdC4KCiMg4pSA4pSAIFZhbGlkYXRlOiBVTUFQIG1vZGVsIE1VU1QgZXhpc3QgZm9yIE1hcFF1ZXJ5IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAppZiAoaXMubnVsbChyZWZlcmVuY2VfaW50ZWdyYXRlZEByZWR1Y3Rpb25zJHVtYXBAbWlzYyRtb2RlbCkpIHsKICBzdG9wKAogICAgIuKdjCBVTUFQIG1vZGVsIG1pc3NpbmchIFJlLXJ1biBvbiB0aGUgY2xlYW5lZCAobm8tcHJvbGlmKSBvYmplY3Q6XG4iLAogICAgIiAgcmVmZXJlbmNlX2ludGVncmF0ZWQgPC0gUnVuVU1BUChyZWZlcmVuY2VfaW50ZWdyYXRlZCwgZGltcyA9IDE6MjAsXG4iLAogICAgIiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuLm1vZGVsID0gVFJVRSlcbiIsCiAgICAiVGhlbiByZS1zYXZlIGFuZCByZWxvYWQuIgogICkKfSBlbHNlIHsKICBjYXQoIuKchSBVTUFQIG1vZGVsIGNvbmZpcm1lZCDigJQgcmVhZHkgZm9yIE1hcFF1ZXJ5IHByb2plY3Rpb25cbiIpCn0KYGBgCgojIyBMb2FkICYgUHJlcGFyZSBNYWxpZ25hbnQgQ0Q0KyBUIENlbGxzIOKAlCBQZXItQ2VsbC1MaW5lIFNDVHJhbnNmb3JtCgpgYGB7ciBsb2FkLW1hbGlnbmFudH0KIyDilIDilIAgTG9hZCBtZXJnZWQgb2JqZWN0IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApBbGxfc2FtcGxlc19NZXJnZWQgPC0gcmVhZFJEUygKICAiL2hvbWUvbmFiYmFzaS9hcG9sbG9faG9tZS8xLVNldXJhdF9SRFNfT0JKRUNUX0ZJTkFML0FsbF9zYW1wbGVzX01lcmdlZF93aXRoX1JlbmFtZWRfQ2x1c3RlcnNfQ2VsbF9zdGF0ZS0wMy0xMi0yMDI1LnJkcy5yZHMiCikKCmNhdCgiQWxsIHNhbXBsZXM6XG4iKQpwcmludCh0YWJsZShBbGxfc2FtcGxlc19NZXJnZWQkY2VsbF9saW5lKSkKCiMg4pSA4pSAIERlZmluZSBncm91cCBsYWJlbHMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACkFsbF9zYW1wbGVzX01lcmdlZCRHcm91cCA8LSBpZmVsc2UoCiAgQWxsX3NhbXBsZXNfTWVyZ2VkJGNlbGxfbGluZSAlaW4lIHBhc3RlMCgiTCIsIDE6NyksCiAgIk1hbGlnbmFudENENFQiLAogIGlmZWxzZSgKICAgIEFsbF9zYW1wbGVzX01lcmdlZCRjZWxsX2xpbmUgJWluJSBjKCJDRDRUY2VsbHNfbGFiIiwgIkNENFRjZWxsc18xMHhfUzEiLCAiQ0Q0VGNlbGxzXzEweF9TMiIpLAogICAgIk5vcm1hbENENFQiLAogICAgIk90aGVyIgogICkKKQoKY2F0KCJcbkdyb3VwIGRpc3RyaWJ1dGlvbjpcbiIpCnByaW50KHRhYmxlKEFsbF9zYW1wbGVzX01lcmdlZCRHcm91cCkpCgojIOKUgOKUgCBTdWJzZXQgbWFsaWduYW50IGNlbGxzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApNYWxpZ25hbnRDRDRUX3JhdyA8LSBzdWJzZXQoQWxsX3NhbXBsZXNfTWVyZ2VkLCBzdWJzZXQgPSBHcm91cCA9PSAiTWFsaWduYW50Q0Q0VCIpCmNhdCgiXG5NYWxpZ25hbnQgQ0Q0VCBjZWxsczoiLCBuY29sKE1hbGlnbmFudENENFRfcmF3KSwgIlxuIikKY2F0KCJDZWxsIGxpbmVzIHByZXNlbnQ6XG4iKQpwcmludCh0YWJsZShNYWxpZ25hbnRDRDRUX3JhdyRjZWxsX2xpbmUpKQoKcm0oQWxsX3NhbXBsZXNfTWVyZ2VkKQpnYygpCmBgYAoKYGBge3IgcGVyLWxpbmUtc2N0fQojIOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkAojIFBFUi1DRUxMLUxJTkUgU0NUcmFuc2Zvcm0KIyDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZAKIyBXSFk6IFJ1bm5pbmcgU0NUcmFuc2Zvcm0gb24gdGhlIG1lcmdlZCBvYmplY3QgY3JlYXRlcyBhIHNpbmdsZSBzaGFyZWQKIyAgICAgIHNpemUtZmFjdG9yIG1vZGVsIHRoYXQgY29sbGFwc2VzIGJhdGNoIHZhcmlhdGlvbiB3aXRoIGJpb2xvZ3kuCiMgICAgICBFYWNoIGNlbGwgbGluZSBpcyBhIHNlcGFyYXRlIGxpYnJhcnkgKGRpZmZlcmVudCBzZXF1ZW5jaW5nIGRlcHRoLAojICAgICAgZGlmZmVyZW50IGFtYmllbnQgUk5BIHByb2ZpbGUpLiBQZXItbGluZSBTQ1QgY29ycmVjdHMgZm9yIHRoaXMuCiMKIyBBUFBST0FDSDoKIyAgIDEuIFNwbGl0IHRoZSBtYWxpZ25hbnQgb2JqZWN0IGJ5IGNlbGxfbGluZQojICAgMi4gUnVuIFNDVHJhbnNmb3JtIG9uIGVhY2ggbGluZSBpbmRlcGVuZGVudGx5CiMgICAzLiBNZXJnZSBiYWNrIGludG8gb25lIG9iamVjdCAoTk9UIGludGVncmF0ZSDigJQgaW50ZWdyYXRpb24gaXMgbm90CiMgICAgICBuZWVkZWQgaGVyZSBiZWNhdXNlIE1hcFF1ZXJ5IHVzZXMgcmVmZXJlbmNlIGFuY2hvcnMgYW55d2F5KQojICAgNC4gU2V0IFZhcmlhYmxlRmVhdHVyZXMgdG8gdGhlIHVuaW9uIG9mIGFsbCBwZXItbGluZSBIVkdzCiMgICAgICAoY2FwcGVkIGF0IDMwMDAsIHJhbmtlZCBieSBjcm9zcy1saW5lIGZyZXF1ZW5jeSkKIyDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZAKCmNhdCgiPT09IFJ1bm5pbmcgcGVyLWNlbGwtbGluZSBTQ1RyYW5zZm9ybSA9PT1cbiIpCmNhdCgiVGhpcyBtYXkgdGFrZSA1LTE1IG1pbnV0ZXMgZGVwZW5kaW5nIG9uIGNlbGwgY291bnQgcGVyIGxpbmUuXG5cbiIpCgojIOKUgOKUgCBTdGVwIDE6IFNwbGl0IGJ5IGNlbGwgbGluZSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKY2VsbF9saW5lX2xpc3QgPC0gU3BsaXRPYmplY3QoTWFsaWduYW50Q0Q0VF9yYXcsIHNwbGl0LmJ5ID0gImNlbGxfbGluZSIpCmNhdCgiQ2VsbCBsaW5lcyB0byBwcm9jZXNzOiIsIHBhc3RlKG5hbWVzKGNlbGxfbGluZV9saXN0KSwgY29sbGFwc2UgPSAiLCAiKSwgIlxuXG4iKQoKIyDilIDilIAgU3RlcCAyOiBTQ1RyYW5zZm9ybSBlYWNoIGxpbmUgaW5kZXBlbmRlbnRseSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKIyB2YXJzLnRvLnJlZ3Jlc3M6IHJlbW92ZSBjZWxsLWN5Y2xlIGFuZCBtaXRvY2hvbmRyaWFsIGNvbmZvdW5kZXJzCiMgVGhlc2UgYXJlIGJpb2xvZ2ljYWwgY292YXJpYXRlcyB0aGF0IHdvdWxkIG90aGVyd2lzZSBkaXN0b3J0IHRoZQojIGRpZmZlcmVudGlhdGlvbiBzaWduYWwgaW4gdGhlIHRyYWplY3RvcnkgcHJvamVjdGlvbi4KCmNlbGxfbGluZV9saXN0IDwtIGxhcHBseShuYW1lcyhjZWxsX2xpbmVfbGlzdCksIGZ1bmN0aW9uKGxpbmVfbmFtZSkgewogIG9iaiA8LSBjZWxsX2xpbmVfbGlzdFtbbGluZV9uYW1lXV0KICBjYXQoIlByb2Nlc3NpbmcgY2VsbCBsaW5lOiIsIGxpbmVfbmFtZSwKICAgICAgInwgQ2VsbHM6IiwgbmNvbChvYmopLCAiXG4iKQoKICAjIOKUgOKUgCBDb21wdXRlICUgbWl0b2Nob25kcmlhbCBpZiBub3QgcHJlc2VudCDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKICBpZiAoISJwZXJjZW50Lm10IiAlaW4lIGNvbG5hbWVzKG9iakBtZXRhLmRhdGEpKSB7CiAgICBvYmpbWyJwZXJjZW50Lm10Il1dIDwtIFBlcmNlbnRhZ2VGZWF0dXJlU2V0KG9iaiwgcGF0dGVybiA9ICJeTVQtIikKICB9CgogICMg4pSA4pSAIENlbGwgY3ljbGUgc2NvcmluZyAoZm9yIHJlZ3Jlc3Npb24pIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAogICMgVXNlcyBTZXVyYXQncyBidWlsdC1pbiBjYy5nZW5lcyAoVGlyb3NoIGV0IGFsLikKICAjIFJlZ3Jlc3NpbmcgUy5TY29yZSBhbmQgRzJNLlNjb3JlIHJlbW92ZXMgY3ljbGluZyBhcnRlZmFjdHMgZnJvbSB0aGUKICAjIFNDVCByZXNpZHVhbHMgd2l0aG91dCByZW1vdmluZyBjeWNsaW5nIGNlbGxzIGZyb20gdGhlIG9iamVjdC4KICB0cnlDYXRjaCh7CiAgICBvYmogPC0gQ2VsbEN5Y2xlU2NvcmluZygKICAgICAgb2JqLAogICAgICBzLmZlYXR1cmVzICAgPSBjYy5nZW5lcyRzLmdlbmVzLAogICAgICBnMm0uZmVhdHVyZXMgPSBjYy5nZW5lcyRnMm0uZ2VuZXMsCiAgICAgIHNldC5pZGVudCAgICA9IEZBTFNFCiAgICApCiAgICB2YXJzX3JlZ3Jlc3MgPC0gYygicGVyY2VudC5tdCIsICJTLlNjb3JlIiwgIkcyTS5TY29yZSIpCiAgICBjYXQoIiAg4oaSIENlbGwgY3ljbGUgc2NvcmVzIGNvbXB1dGVkIGZvciIsIGxpbmVfbmFtZSwgIlxuIikKICB9LCBlcnJvciA9IGZ1bmN0aW9uKGUpIHsKICAgICMgSWYgY2VsbCBjeWNsZSBnZW5lcyBub3QgZm91bmQgKHZlcnkgc21hbGwgb2JqZWN0KSwgc2tpcCByZWdyZXNzaW9uCiAgICBjYXQoIiAg4pqg77iPICBDZWxsIGN5Y2xlIHNjb3JpbmcgZmFpbGVkIGZvciIsIGxpbmVfbmFtZSwKICAgICAgICAi4oCUIHJlZ3Jlc3NpbmcgcGVyY2VudC5tdCBvbmx5XG4iKQogICAgdmFyc19yZWdyZXNzIDw8LSAicGVyY2VudC5tdCIKICB9KQoKICAjIOKUgOKUgCBTQ1RyYW5zZm9ybSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKICBvYmogPC0gU0NUcmFuc2Zvcm0oCiAgICBvYmosCiAgICB2YXJzLnRvLnJlZ3Jlc3MgID0gdmFyc19yZWdyZXNzLAogICAgdmFyaWFibGUuZmVhdHVyZXMubiA9IDMwMDAsCiAgICB2c3QuZmxhdm9yICAgICAgID0gInYyIiwgICAgICMgUGVhcnNvbiByZXNpZHVhbHMgdjIgKGZhc3RlciwgbW9yZSBzdGFibGUpCiAgICB2ZXJib3NlICAgICAgICAgID0gRkFMU0UKICApCgogIGNhdCgiICDinIUiLCBsaW5lX25hbWUsICJTQ1QgY29tcGxldGUgfCIsCiAgICAgIGxlbmd0aChWYXJpYWJsZUZlYXR1cmVzKG9iaikpLCAiSFZHc1xuIikKICByZXR1cm4ob2JqKQp9KQpuYW1lcyhjZWxsX2xpbmVfbGlzdCkgPC0gbmFtZXMoU3BsaXRPYmplY3QoTWFsaWduYW50Q0Q0VF9yYXcsIHNwbGl0LmJ5ID0gImNlbGxfbGluZSIpKQoKIyDilIDilIAgU3RlcCAzOiBDb2xsZWN0IHBlci1saW5lIEhWR3Mg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACiMgU3RyYXRlZ3k6IHJhbmsgZ2VuZXMgYnkgaG93IG1hbnkgY2VsbCBsaW5lcyB0aGV5IGFyZSB2YXJpYWJsZSBpbi4KIyBHZW5lcyB2YXJpYWJsZSBhY3Jvc3MgbXVsdGlwbGUgbGluZXMgYXJlIHJvYnVzdCBIVkdzIG5vdCBkb21pbmF0ZWQKIyBieSBhbnkgc2luZ2xlIGxpbmUncyBiYXRjaCBlZmZlY3QuCgphbGxfaHZnX2xpc3RzIDwtIGxhcHBseShjZWxsX2xpbmVfbGlzdCwgVmFyaWFibGVGZWF0dXJlcykKaHZnX2ZyZXEgPC0gc29ydCh0YWJsZSh1bmxpc3QoYWxsX2h2Z19saXN0cykpLCBkZWNyZWFzaW5nID0gVFJVRSkKCiMgU2VsZWN0IHRvcCAzMDAwIGdlbmVzIGJ5IGNyb3NzLWxpbmUgZnJlcXVlbmN5Cm5faHZncyAgICAgIDwtIG1pbigzMDAwLCBsZW5ndGgoaHZnX2ZyZXEpKQpzaGFyZWRfaHZncyA8LSBuYW1lcyhodmdfZnJlcSlbMTpuX2h2Z3NdCgpjYXQoIlxuVG9wIDMwMDAgSFZHcyBzZWxlY3RlZCBieSBjcm9zcy1saW5lIGZyZXF1ZW5jeVxuIikKY2F0KCJHZW5lcyB2YXJpYWJsZSBpbiBhbGwiLCBsZW5ndGgoY2VsbF9saW5lX2xpc3QpLCAibGluZXM6IiwKICAgIHN1bShodmdfZnJlcSA9PSBsZW5ndGgoY2VsbF9saW5lX2xpc3QpKSwgIlxuIikKY2F0KCJHZW5lcyB2YXJpYWJsZSBpbiDiiaUzIGxpbmVzOiIsCiAgICBzdW0oaHZnX2ZyZXEgPj0gMyksICJcbiIpCgojIOKUgOKUgCBTdGVwIDQ6IE1lcmdlIFNDVC1ub3JtYWxpc2VkIGNlbGwgbGluZSBvYmplY3RzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAojIG1lcmdlKCkgb24gU0NUIG9iamVjdHMgY29uY2F0ZW5hdGVzIHRoZSBjb3JyZWN0ZWQgY291bnQgbWF0cmljZXMuCiMgV2UgZG8gTk9UIFJ1bkludGVncmF0aW9uIGhlcmUg4oCUIE1hcFF1ZXJ5IHdpbGwgaGFuZGxlIGNyb3NzLWRhdGFzZXQKIyBjb3JyZWN0aW9uIHZpYSBhbmNob3ItYmFzZWQgdHJhbnNmZXIuCmNhdCgiXG5NZXJnaW5nIHBlci1saW5lIFNDVCBvYmplY3RzLi4uXG4iKQoKTWFsaWduYW50Q0Q0VCA8LSBtZXJnZSgKICB4ICAgID0gY2VsbF9saW5lX2xpc3RbWzFdXSwKICB5ICAgID0gY2VsbF9saW5lX2xpc3RbLTFdLAogIG1lcmdlLmRhdGEgPSBUUlVFICAgICMgY29uY2F0ZW5hdGUgU0NUIGRhdGEgbGF5ZXJzCikKCiMg4pSA4pSAIFN0ZXAgNTogU2V0IHVuaWZpZWQgVmFyaWFibGVGZWF0dXJlcyBvbiBtZXJnZWQgb2JqZWN0IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApWYXJpYWJsZUZlYXR1cmVzKE1hbGlnbmFudENENFQpIDwtIHNoYXJlZF9odmdzCgojIOKUgOKUgCBTdGVwIDY6IFJ1biBQQ0Egb24gbWVyZ2VkIFNDVCBvYmplY3Qg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACiMgUENBIGlzIG5lZWRlZCBmb3IgRmluZFRyYW5zZmVyQW5jaG9ycyAocmVmZXJlbmNlLnJlZHVjdGlvbiA9ICJwY2EiKQojIFdlIHJ1biBpdCBvbiB0aGUgbWVyZ2VkIGRhdGEgc28gZWFjaCBjZWxsIGhhcyBhIFBDQSBlbWJlZGRpbmcgY29uc2lzdGVudAojIHdpdGggdGhlIHNoYXJlZCBIVkcgc3BhY2UuCmNhdCgiUnVubmluZyBQQ0Egb24gbWVyZ2VkIG1hbGlnbmFudCBvYmplY3QuLi5cbiIpCgojIE5vdGU6IEpvaW5MYXllcnMoKSBpcyBTZXVyYXQgdjUgb25seSBhbmQgbm90IG5lZWRlZCBoZXJlLgojIEluIFNldXJhdCB2NCwgbWVyZ2UoKSB3aXRoIG1lcmdlLmRhdGEgPSBUUlVFIGFscmVhZHkgY29uY2F0ZW5hdGVzCiMgdGhlIFNDVCBkYXRhIHNsb3QgZGlyZWN0bHkg4oCUIG5vIGxheWVyIGpvaW5pbmcgcmVxdWlyZWQuCgpNYWxpZ25hbnRDRDRUIDwtIFNjYWxlRGF0YSgKICBNYWxpZ25hbnRDRDRULAogIGZlYXR1cmVzID0gc2hhcmVkX2h2Z3MsCiAgYXNzYXkgICAgPSAiU0NUIiwKICB2ZXJib3NlICA9IEZBTFNFCikKTWFsaWduYW50Q0Q0VCA8LSBSdW5QQ0EoCiAgTWFsaWduYW50Q0Q0VCwKICBmZWF0dXJlcyA9IHNoYXJlZF9odmdzLAogIGFzc2F5ICAgID0gIlNDVCIsCiAgbnBjcyAgICAgPSAzMCwKICB2ZXJib3NlICA9IEZBTFNFCikKCmNhdCgi4pyFIFBlci1jZWxsLWxpbmUgU0NUICsgbWVyZ2UgY29tcGxldGVcbiIpCmNhdCgiRmluYWwgbWVyZ2VkIG9iamVjdDpcbiIpCmNhdCgiICBDZWxsczoiLCBuY29sKE1hbGlnbmFudENENFQpLCAiXG4iKQpjYXQoIiAgVmFyaWFibGVGZWF0dXJlczoiLCBsZW5ndGgoVmFyaWFibGVGZWF0dXJlcyhNYWxpZ25hbnRDRDRUKSksICJcbiIpCmNhdCgiICBQQ0EgZGltczoiLCBuY29sKEVtYmVkZGluZ3MoTWFsaWduYW50Q0Q0VCwgInBjYSIpKSwgIlxuIikKY2F0KCJDZWxsIGxpbmUgZGlzdHJpYnV0aW9uOlxuIikKcHJpbnQodGFibGUoTWFsaWduYW50Q0Q0VCRjZWxsX2xpbmUpKQoKIyBDbGVhbiB1cCBwZXItbGluZSBsaXN0IHRvIGZyZWUgbWVtb3J5CnJtKE1hbGlnbmFudENENFRfcmF3LCBjZWxsX2xpbmVfbGlzdCkKZ2MoKQpgYGAKCgoKIyBSZWZlcmVuY2UgVHJhamVjdG9yeSAoTW9ub2NsZTMpCgojIyBCdWlsZCBDRFMgZnJvbSBSZWZlcmVuY2UKCmBgYHtyIGJ1aWxkLWNkc30KIyDilIDilIAgQ29udmVydCBTZXVyYXQgcmVmZXJlbmNlIHRvIENlbGxEYXRhU2V0IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAojIFdlIHVzZSB0aGUgcmVmZXJlbmNlIHRvIGJ1aWxkL2NvbmZpcm0gdGhlIHRyYWplY3RvcnkuCiMgSWYgbW9ub2NsZTNfcHNldWRvdGltZSBhbHJlYWR5IGV4aXN0cyBpbiB0aGUgb2JqZWN0IChmcm9tIHByZXZpb3VzIHJ1biksCiMgd2UgY2FuIHNraXAgbGVhcm5fZ3JhcGggYW5kIGdvIHN0cmFpZ2h0IHRvIHByb2plY3Rpb24uCiMgSGVyZSB3ZSByZS1idWlsZCBmb3IgY29tcGxldGVuZXNzIGFuZCByZXByb2R1Y2liaWxpdHkuCgpjYXQoIj09PSBCdWlsZGluZyBNb25vY2xlMyBDRFMgZnJvbSByZWZlcmVuY2UgPT09XG4iKQoKY2RzIDwtIGFzLmNlbGxfZGF0YV9zZXQocmVmZXJlbmNlX2ludGVncmF0ZWQpCgojIOKUgOKUgCBUcmFuc2ZlciBVTUFQIGNvb3JkaW5hdGVzIGZyb20gU2V1cmF0ICh1c2UgdGhlIGZyb3plbiByZWZlcmVuY2UgVU1BUCkg4pSACnJlZHVjZWREaW0oY2RzLCAiVU1BUCIpIDwtIEVtYmVkZGluZ3MocmVmZXJlbmNlX2ludGVncmF0ZWQsICJ1bWFwIikKCiMg4pSA4pSAIFNldCBwYXJ0aXRpb25zOiBzaW5nbGUgcGFydGl0aW9uID0gb25lIGNvbm5lY3RlZCB0cmFqZWN0b3J5IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAojIEZvciBDRDQgVCBjZWxsIGRpZmZlcmVudGlhdGlvbiB3ZSBleHBlY3QgYSBsaW5lYXIvYnJhbmNoZWQgYnV0IGNvbm5lY3RlZAojIGdyYXBoIOKAlCB1c2VfcGFydGl0aW9uPUZBTFNFIGdpdmVzIGNsZWFuZXIgcmVzdWx0cyBmb3IgYSBzaW5nbGUgbGluZWFnZS4KY2RzQGNsdXN0ZXJzJFVNQVAkcGFydGl0aW9ucyA8LSBmYWN0b3IocmVwKDEsIG5jb2woY2RzKSkpCgojIOKUgOKUgCBTZXQgY2x1c3RlciBhc3NpZ25tZW50cyBhbGlnbmVkIHRvIFNldXJhdCBjbHVzdGVycyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKY2x1c3Rlcl92ZWMgPC0gcmVmZXJlbmNlX2ludGVncmF0ZWQkc2V1cmF0X2NsdXN0ZXJzW2NvbG5hbWVzKGNkcyldCmNkc0BjbHVzdGVycyRVTUFQJGNsdXN0ZXJzIDwtIGZhY3RvcihjbHVzdGVyX3ZlYykKCiMg4pSA4pSAIFRyYW5zZmVyIGNlbGwgbWV0YWRhdGEg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACmNvbERhdGEoY2RzKSRjZWxsX2xpbmUgICAgICAgICAgICAgPC0gcmVmZXJlbmNlX2ludGVncmF0ZWQkb3JpZy5pZGVudApjb2xEYXRhKGNkcykkY2VsbF90eXBlICAgICAgICAgICAgIDwtIHJlZmVyZW5jZV9pbnRlZ3JhdGVkJGNlbGxfdHlwZQpjb2xEYXRhKGNkcykkcHJlZGljdGVkLmNlbGx0eXBlLmwyIDwtIHJlZmVyZW5jZV9pbnRlZ3JhdGVkJHByZWRpY3RlZC5jZWxsdHlwZS5sMgpjb2xEYXRhKGNkcykkc2V1cmF0X2NsdXN0ZXJzICAgICAgIDwtIHJlZmVyZW5jZV9pbnRlZ3JhdGVkJGludGVncmF0ZWRfc25uX3Jlcy4wLjIKCiMgVHJhbnNmZXIgc2FtcGxlL29yaWdpbiBjb2x1bW4gaWYgaXQgZXhpc3RzIChuYW1lIG1heSB2YXJ5KQppZiAoIm9yaWcuaWRlbnQiICVpbiUgY29sbmFtZXMocmVmZXJlbmNlX2ludGVncmF0ZWRAbWV0YS5kYXRhKSkgewogIGNvbERhdGEoY2RzKSRzYW1wbGUgPC0gcmVmZXJlbmNlX2ludGVncmF0ZWQkb3JpZy5pZGVudAp9IGVsc2UgaWYgKCJzYW1wbGUiICVpbiUgY29sbmFtZXMocmVmZXJlbmNlX2ludGVncmF0ZWRAbWV0YS5kYXRhKSkgewogIGNvbERhdGEoY2RzKSRzYW1wbGUgPC0gcmVmZXJlbmNlX2ludGVncmF0ZWQkc2FtcGxlCn0KCmNhdCgiQ0RTIGJ1aWx0OiIsIG5jb2woY2RzKSwgImNlbGxzXG4iKQpjYXQoIkNsdXN0ZXJzOiIsIG5sZXZlbHMoZmFjdG9yKGNvbERhdGEoY2RzKSRzZXVyYXRfY2x1c3RlcnMpKSwgIlxuIikKY2F0KCJQYXJ0aXRpb25zOiIsIG5sZXZlbHMocGFydGl0aW9ucyhjZHMpKSwgIlxuIikKY2F0KCJcbkNlbGwgdHlwZSBicmVha2Rvd24gaW4gQ0RTOlxuIikKcHJpbnQodGFibGUoY29sRGF0YShjZHMpJHByZWRpY3RlZC5jZWxsdHlwZS5sMikpCgpgYGAKCiMjIExlYXJuIFRyYWplY3RvcnkgR3JhcGgKCmBgYHtyIGxlYXJuLWdyYXBoLCBmaWcud2lkdGg9MTQsIGZpZy5oZWlnaHQ9OH0KIyDilIDilIAgTGVhcm4gcHJpbmNpcGFsIGdyYXBoIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAojIHVzZV9wYXJ0aXRpb24gPSBGQUxTRTogc2luZ2xlIGNvbm5lY3RlZCBncmFwaCBhY3Jvc3MgYWxsIGhlYWx0aHkgY2VsbHMuCiMgICAgICAgICAgICAgICAgICAgICAgICBUaGlzIHdvcmtzIHdlbGwgaGVyZSBiZWNhdXNlIENENCBQcm9saWZlcmF0aW5nIGNlbGxzCiMgICAgICAgICAgICAgICAgICAgICAgICBoYXZlIGJlZW4gcmVtb3ZlZCDigJQgd2l0aG91dCB0aGVtLCB0aGUgbWFuaWZvbGQgaXMgYQojICAgICAgICAgICAgICAgICAgICAgICAgY2xlYW4gY29udGludW91cyBkaWZmZXJlbnRpYXRpb24gc3BhY2Ugd2l0aCBubwojICAgICAgICAgICAgICAgICAgICAgICAgc3B1cmlvdXMgY2VsbC1jeWNsZSBicmFuY2ggcHVsbGluZyBjZWxscyBhd2F5LgojIGNsb3NlX2xvb3AgICAgPSBGQUxTRTogb3BlbiB0cmFqZWN0b3J5IChUbmFpdmUg4oaSIFRlbXJhIGxpbmVhciBheGlzKS4KIyAgICAgICAgICAgICAgICAgICAgICAgIFRoZSB0cmFqZWN0b3J5IHNob3VsZCBub3QgbG9vcCBiYWNrIG9uIGl0c2VsZi4KIwojIFJBVElPTkFMRTogUmVtb3ZpbmcgcHJvbGlmZXJhdGluZyBjZWxscyBpcyBrZXkgdG8gdGhpcyBzdGVwIHdvcmtpbmcgd2VsbC4KIyBQcmV2aW91c2x5ICh3aXRoIHByb2xpZmVyYXRpbmcgY2VsbHMpLCBNb25vY2xlMyB3b3VsZCBjcmVhdGUgYW4gYXJ0aWZhY3R1YWwKIyBicmFuY2ggZHJpdmVuIGJ5IE1LSTY3L1RPUDJBL0NESzEgcmF0aGVyIHRoYW4gZGlmZmVyZW50aWF0aW9uIGdlbmVzLgojIE5vdyB0aGUgZ3JhcGggY2xlYW5seSBmb2xsb3dzOiBUbmFpdmUg4oaSIFRDTSDihpIgVEVNIOKGkiBUZW1yYSAoKyBUcmVnIGJyYW5jaCkuCgojIOKUgOKUgCBGSVggUEFSVElUSU9OUyBOQU1FUyAoQ1JJVElDQUwpIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAppZiAoaXMubnVsbChuYW1lcyhjZHNAY2x1c3RlcnMkVU1BUCRwYXJ0aXRpb25zKSkpIHsKICBjZHNAY2x1c3RlcnMkVU1BUCRwYXJ0aXRpb25zIDwtIHJlcCgxLCBuY29sKGNkcykpCiAgbmFtZXMoY2RzQGNsdXN0ZXJzJFVNQVAkcGFydGl0aW9ucykgPC0gY29sbmFtZXMoY2RzKQp9CmNhdCgi4pyFIFBhcnRpdGlvbnMgZml4ZWQ6IiwgdGFibGUoY2RzQGNsdXN0ZXJzJFVNQVAkcGFydGl0aW9ucyksICJcbiIpCgojIOKUgOKUgCBGSVggQ0xVU1RFUlMgKGlmIG5lZWRlZCkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACmlmIChpcy5udWxsKGNkc0BjbHVzdGVycyRVTUFQJGNsdXN0ZXJzKSkgewogIGNsdXN0ZXJ2ZWMgPC0gcmVmZXJlbmNlX2ludGVncmF0ZWQkc2V1cmF0X2NsdXN0ZXJzW2NvbG5hbWVzKGNkcyldCiAgY2RzQGNsdXN0ZXJzJFVNQVAkY2x1c3RlcnMgPC0gZmFjdG9yKGNsdXN0ZXJ2ZWMpCn0KY2F0KCLinIUgQ2x1c3RlcnM6IiwgbGVuZ3RoKHVuaXF1ZShjZHNAY2x1c3RlcnMkVU1BUCRjbHVzdGVycykpLCAiXG4iKQoKIyDilIDilIAgTEVBUk4gR1JBUEgg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACmNkcyA8LSBsZWFybl9ncmFwaChjZHMsIHVzZV9wYXJ0aXRpb24gPSBGQUxTRSwgY2xvc2VfbG9vcCA9IEZBTFNFLCB2ZXJib3NlID0gVFJVRSkKCmNhdCgiXG7inIUgUHJpbmNpcGFsIGdyYXBoIGxlYXJuZWQhXG4iKQpjYXQoIk5vZGVzOiIsIGxlbmd0aChpZ3JhcGg6OlYocHJpbmNpcGFsX2dyYXBoKGNkcykkVU1BUCkpLCAiXG4iKQpjYXQoIkJyYW5jaCBwb2ludHM6Iiwgc3VtKGlncmFwaDo6ZGVncmVlKHByaW5jaXBhbF9ncmFwaChjZHMpJFVNQVApID4gMiksICJcbiIpCmNhdCgiRXhwZWN0IDEtMiBicmFuY2hlcyAoVHJlZyBkaXZlcmdlbmNlIMKxIFRuYWl2ZS1SVEUpXG4iKQoKIyDilIDilIAgVklTVUFMSVpFOiBBemltdXRoIGwyIChQUklNQVJZKSArIGNlbGxfdHlwZSAoU0VDT05EQVJZKSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKcDEgPC0gcGxvdF9jZWxscyhjZHMsCiAgICAgICAgICAgICAgICAgY29sb3JfY2VsbHNfYnkgPSAicHJlZGljdGVkLmNlbGx0eXBlLmwyIiwgICMgWU9VUiA1IGxhYmVscwogICAgICAgICAgICAgICAgIGxhYmVsX2dyb3Vwc19ieV9jbHVzdGVyID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgbGFiZWxfbGVhdmVzID0gVFJVRSwKICAgICAgICAgICAgICAgICBsYWJlbF9icmFuY2hfcG9pbnRzID0gVFJVRSwKICAgICAgICAgICAgICAgICBncmFwaF9sYWJlbF9zaXplID0gMy41LAogICAgICAgICAgICAgICAgIGNlbGxfc2l6ZSA9IDAuOCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBhemltdXRoX2wyX2NvbG9ycykgKwogIGdndGl0bGUoIk1vbm9jbGUzIEdyYXBoOiBBemltdXRoIGwyIChDRDQgTmFpdmUg4oaSIFRlbXJhL0NUTCkiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE0LCBmYWNlID0gImJvbGQiKSkKCnAyIDwtIHBsb3RfY2VsbHMoY2RzLAogICAgICAgICAgICAgICAgIGNvbG9yX2NlbGxzX2J5ID0gImNlbGxfdHlwZSIsCiAgICAgICAgICAgICAgICAgbGFiZWxfZ3JvdXBzX2J5X2NsdXN0ZXIgPSBGQUxTRSwKICAgICAgICAgICAgICAgICBsYWJlbF9sZWF2ZXMgPSBUUlVFLAogICAgICAgICAgICAgICAgIGxhYmVsX2JyYW5jaF9wb2ludHMgPSBUUlVFLAogICAgICAgICAgICAgICAgIGdyYXBoX2xhYmVsX3NpemUgPSAzLjUsCiAgICAgICAgICAgICAgICAgY2VsbF9zaXplID0gMC44KSArCiAgZ2d0aXRsZSgiTW9ub2NsZTMgR3JhcGg6IENlbGwgVHlwZXMiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE0LCBmYWNlID0gImJvbGQiKSkKCnAxIHwgcDIKCmBgYAoKIyBGaXhlZCBsZWFybi1ncmFwaCBWaXN1YWxpemF0aW9uCmBgYHtyIFZpc3VhbGl6YXRpb25zLCBmaWcud2lkdGg9MTQsIGZpZy5oZWlnaHQ9OH0KdW1hcF9jb29yZHMgPC0gYXMuZGF0YS5mcmFtZShFbWJlZGRpbmdzKHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCAidW1hcCIpKQpjb2xuYW1lcyh1bWFwX2Nvb3JkcykgPC0gYygiVU1BUDEiLCAiVU1BUDIiKSAgICMgcmVuYW1lIGZvciBjbGFyaXR5Cgp1bWFwX2Nvb3JkcyRsMiAgICAgICAgPC0gcmVmZXJlbmNlX2ludGVncmF0ZWQkcHJlZGljdGVkLmNlbGx0eXBlLmwyCnVtYXBfY29vcmRzJGNlbGxfdHlwZSA8LSByZWZlcmVuY2VfaW50ZWdyYXRlZCRjZWxsX3R5cGUKCiMgQ2VudHJvaWQgcGVyIEF6aW11dGggbDIgc3RhdGUKbGFiZWxfY29vcmRzIDwtIHVtYXBfY29vcmRzICU+JQogIGRwbHlyOjpncm91cF9ieShsMikgJT4lCiAgZHBseXI6OnN1bW1hcmlzZSgKICAgIFVNQVAxID0gbWVkaWFuKFVNQVAxKSwKICAgIFVNQVAyID0gbWVkaWFuKFVNQVAyKSwKICAgIC5ncm91cHMgPSAiZHJvcCIKICApCgojIENlbnRyb2lkIHBlciBjZWxsX3R5cGUKbGFiZWxfY29vcmRzMiA8LSB1bWFwX2Nvb3JkcyAlPiUKICBkcGx5cjo6Z3JvdXBfYnkoY2VsbF90eXBlKSAlPiUKICBkcGx5cjo6c3VtbWFyaXNlKAogICAgVU1BUDEgPSBtZWRpYW4oVU1BUDEpLAogICAgVU1BUDIgPSBtZWRpYW4oVU1BUDIpLAogICAgLmdyb3VwcyA9ICJkcm9wIgogICkKCmxpYnJhcnkoZ2dyZXBlbCkKCiMgQXppbXV0aCBsMiBwbG90CnAxIDwtIHBsb3RfY2VsbHMoCiAgICAgICAgY2RzLAogICAgICAgIGNvbG9yX2NlbGxzX2J5ID0gInByZWRpY3RlZC5jZWxsdHlwZS5sMiIsCiAgICAgICAgbGFiZWxfZ3JvdXBzX2J5X2NsdXN0ZXIgPSBGQUxTRSwKICAgICAgICBsYWJlbF9sZWF2ZXMgICAgICAgID0gRkFMU0UsCiAgICAgICAgbGFiZWxfYnJhbmNoX3BvaW50cyA9IEZBTFNFLAogICAgICAgIGNlbGxfc2l6ZSAgICAgICAgICAgPSAwLjcsCiAgICAgICAgc2hvd190cmFqZWN0b3J5X2dyYXBoID0gVFJVRQogICAgICApICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYXppbXV0aF9sMl9jb2xvcnMsIG5hbWUgPSAiU3RhdGUiKSArCiAgZ2VvbV9sYWJlbF9yZXBlbCgKICAgIGRhdGEgPSBsYWJlbF9jb29yZHMsCiAgICBhZXMoeCA9IFVNQVAxLCB5ID0gVU1BUDIsIGxhYmVsID0gbDIpLAogICAgc2l6ZSA9IDQsIGZvbnRmYWNlID0gImJvbGQiLAogICAgZmlsbCA9ICJ3aGl0ZSIsIGFscGhhID0gMC44NSwKICAgIGJveC5wYWRkaW5nID0gMC41LCBsYWJlbC5wYWRkaW5nID0gMC4zLAogICAgc2VnbWVudC5jb2xvciA9ICJncmV5NDAiCiAgKSArCiAgZ2d0aXRsZSgiTW9ub2NsZTMgR3JhcGg6IEF6aW11dGggbDIgKENENCBOYWl2ZSDihpIgVGVtcmEvQ1RMKSIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTQsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCiMgY2VsbF90eXBlIHBsb3QKcDIgPC0gcGxvdF9jZWxscygKICAgICAgICBjZHMsCiAgICAgICAgY29sb3JfY2VsbHNfYnkgPSAiY2VsbF90eXBlIiwKICAgICAgICBsYWJlbF9ncm91cHNfYnlfY2x1c3RlciA9IEZBTFNFLAogICAgICAgIGxhYmVsX2xlYXZlcyAgICAgICAgPSBGQUxTRSwKICAgICAgICBsYWJlbF9icmFuY2hfcG9pbnRzID0gRkFMU0UsCiAgICAgICAgY2VsbF9zaXplICAgICAgICAgICA9IDAuNywKICAgICAgICBzaG93X3RyYWplY3RvcnlfZ3JhcGggPSBUUlVFCiAgICAgICkgKwogIGdlb21fbGFiZWxfcmVwZWwoCiAgICBkYXRhID0gbGFiZWxfY29vcmRzMiwKICAgIGFlcyh4ID0gVU1BUDEsIHkgPSBVTUFQMiwgbGFiZWwgPSBjZWxsX3R5cGUpLAogICAgc2l6ZSA9IDMuNSwgZm9udGZhY2UgPSAiYm9sZCIsCiAgICBmaWxsID0gIndoaXRlIiwgYWxwaGEgPSAwLjg1LAogICAgYm94LnBhZGRpbmcgPSAwLjUsCiAgICBzZWdtZW50LmNvbG9yID0gImdyZXk0MCIKICApICsKICBnZ3RpdGxlKCJNb25vY2xlMyBHcmFwaDogQ2VsbCBUeXBlcyIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTQsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCnAxIHwgcDIKCnAxIAoKcDIKYGBgCgoKIyMgU2V0IFJvb3QgJiBPcmRlciBDZWxscyBieSBQc2V1ZG90aW1lCgpgYGB7ciBwc2V1ZG90aW1lLXJvb3QsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD04fQojIOKUgOKUgCBJZGVudGlmeSByb290IG5vZGUgaW4gdGhlIG5haXZlIGNsdXN0ZXIg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACiMgUm9vdCA9IGNlbGxzIGluIHRoZSBUbmFpdmUgY2x1c3RlciAoQ0NSNytTRUxMK1RDRjcrKSA9IGNsdXN0ZXIgMAojIFVzaW5nIHRoZSBwcmluY2lwYWwgZ3JhcGggbm9kZSBjbG9zZXN0IHRvIHRoZSBUbmFpdmUgY2VudHJvaWQgZW5zdXJlcwojIHBzZXVkb3RpbWU9MCBpcyBiaW9sb2dpY2FsbHkgYW5jaG9yZWQgdG8gdGhlIG1vc3QgdW5kaWZmZXJlbnRpYXRlZCBzdGF0ZS4KCmNhdCgiQXZhaWxhYmxlIEF6aW11dGggbDIgbGFiZWxzOlxuIikKcHJpbnQoc29ydCh1bmlxdWUoY29sRGF0YShjZHMpJHByZWRpY3RlZC5jZWxsdHlwZS5sMikpKQoKIyBGaW5kIG5haXZlIGNlbGxzIOKAlCB1c2UgYm90aCBBemltdXRoIGxhYmVsIGFuZCBvdXIgY2VsbF90eXBlIGFubm90YXRpb24KbmFpdmVfaWRzIDwtIHJvd25hbWVzKGNvbERhdGEoY2RzKSlbCiAgZ3JlcGwoIm5haXZlfE5haXZlfFROJCIsIGNvbERhdGEoY2RzKSRwcmVkaWN0ZWQuY2VsbHR5cGUubDIsIGlnbm9yZS5jYXNlID0gVFJVRSkgfAogIGdyZXBsKCJUbmFpdmUiLCBhcy5jaGFyYWN0ZXIoY29sRGF0YShjZHMpJGNlbGxfdHlwZSksIGlnbm9yZS5jYXNlID0gRkFMU0UpCl0KCmNhdCgiXG5OYWl2ZSByb290IGNlbGxzIGlkZW50aWZpZWQ6IiwgbGVuZ3RoKG5haXZlX2lkcyksICJcbiIpCmlmIChsZW5ndGgobmFpdmVfaWRzKSA9PSAwKSB7CiAgc3RvcCgi4p2MIE5vIG5haXZlIHJvb3QgY2VsbHMgZm91bmQuIENoZWNrIGxhYmVsIHN0cmluZ3MgYWJvdmUgYW5kIGFkanVzdCBncmVwIHBhdHRlcm5zLiIpCn0KCiMg4pSA4pSAIEZ1bmN0aW9uIHRvIGZpbmQgdGhlIHByaW5jaXBhbCBncmFwaCBub2RlIGNsb3Nlc3QgdG8gbmFpdmUgY2VudHJvaWQg4pSA4pSA4pSA4pSACmdldF9yb290X25vZGUgPC0gZnVuY3Rpb24oY2RzLCBjZWxsX2lkcykgewogIGNsb3Nlc3QgPC0gY2RzQHByaW5jaXBhbF9ncmFwaF9hdXgkVU1BUCRwcl9ncmFwaF9jZWxsX3Byb2pfY2xvc2VzdF92ZXJ0ZXgKICBjbG9zZXN0IDwtIGFzLm1hdHJpeChjbG9zZXN0W2NvbG5hbWVzKGNkcyksIF0pCiAgaWdyYXBoOjpWKHByaW5jaXBhbF9ncmFwaChjZHMpJFVNQVApJG5hbWVbCiAgICBhcy5udW1lcmljKG5hbWVzKHdoaWNoLm1heCh0YWJsZShjbG9zZXN0W2NlbGxfaWRzLCBdKSkpKQogIF0KfQoKcm9vdF9ub2RlIDwtIGdldF9yb290X25vZGUoY2RzLCBuYWl2ZV9pZHMpCmNhdCgiUm9vdCBub2RlOiIsIHJvb3Rfbm9kZSwgIlxuIikKCiMg4pSA4pSAIE9yZGVyIGNlbGxzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApjZHMgPC0gb3JkZXJfY2VsbHMoY2RzLCByb290X3ByX25vZGVzID0gcm9vdF9ub2RlKQoKIyBUcmFuc2ZlciBwc2V1ZG90aW1lIGJhY2sgdG8gU2V1cmF0IG9iamVjdApyZWZlcmVuY2VfaW50ZWdyYXRlZCRtb25vY2xlM19wc2V1ZG90aW1lIDwtIHBzZXVkb3RpbWUoY2RzKQoKIyBSZXBsYWNlIEluZiAodW5yZWFjaGFibGUgY2VsbHMpIHdpdGggTkEgZm9yIGNsZWFuIHBsb3R0aW5nCnJlZmVyZW5jZV9pbnRlZ3JhdGVkJG1vbm9jbGUzX3BzZXVkb3RpbWVbCiAgIWlzLmZpbml0ZShyZWZlcmVuY2VfaW50ZWdyYXRlZCRtb25vY2xlM19wc2V1ZG90aW1lKQpdIDwtIE5BCgpjYXQoIlxuUHNldWRvdGltZSBzdW1tYXJ5IChmaW5pdGUgdmFsdWVzKTpcbiIpCnByaW50KHN1bW1hcnkocmVmZXJlbmNlX2ludGVncmF0ZWQkbW9ub2NsZTNfcHNldWRvdGltZVsKICBpcy5maW5pdGUocmVmZXJlbmNlX2ludGVncmF0ZWQkbW9ub2NsZTNfcHNldWRvdGltZSkKXSkpCgojIOKUgOKUgCBQbG90IHBzZXVkb3RpbWUgb24gdHJhamVjdG9yeSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKcGxvdF9jZWxscygKICBjZHMsCiAgY29sb3JfY2VsbHNfYnkgICAgPSAicHNldWRvdGltZSIsCiAgbGFiZWxfY2VsbF9ncm91cHMgPSBGQUxTRSwKICBjZWxsX3NpemUgICAgICAgICA9IDAuOCwKICBzaG93X3RyYWplY3RvcnlfZ3JhcGggPSBUUlVFCikgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYyhvcHRpb24gPSAicGxhc21hIiwgbmFtZSA9ICJQc2V1ZG90aW1lIikgKwogIGdndGl0bGUoIlJlZmVyZW5jZSBDRDQrIFQgQ2VsbCBQc2V1ZG90aW1lXG4oUm9vdCA9IFRuYWl2ZSwgVGVybWluYWwgPSBUZW1yYS9DVEwpIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxNCwgZmFjZSA9ICJib2xkIikpCgojIOKUgOKUgCBQc2V1ZG90aW1lIG9uIFNldXJhdCBVTUFQIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApGZWF0dXJlUGxvdCgKICByZWZlcmVuY2VfaW50ZWdyYXRlZCwKICBmZWF0dXJlcyAgPSAibW9ub2NsZTNfcHNldWRvdGltZSIsCiAgcmVkdWN0aW9uID0gInVtYXAiLAogIGNvbHMgICAgICA9IGMoImxpZ2h0Ymx1ZSIsICJkYXJrYmx1ZSIsICJyZWQiKSwKICBsYWJlbCAgICAgPSBUUlVFLAogIHB0LnNpemUgICA9IDAuNQopICsKICBnZ3RpdGxlKCJSZWZlcmVuY2UgVU1BUCDigJQgUHNldWRvdGltZSIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKCmBgYAoKIyBWaXN1YWxpemF0aW9uCmBgYHtyICwgZmlnLndpZHRoPTE0LCBmaWcuaGVpZ2h0PTh9CiMg4pSA4pSAIElkZW50aWZ5IHJvb3Qgbm9kZSBpbiB0aGUgbmFpdmUgY2x1c3RlciDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKIyBSb290ID0gY2VsbHMgaW4gdGhlIFRuYWl2ZSBjbHVzdGVyIChDQ1I3K1NFTEwrVENGNyspID0gY2x1c3RlciAwCiMgVXNpbmcgdGhlIHByaW5jaXBhbCBncmFwaCBub2RlIGNsb3Nlc3QgdG8gdGhlIFRuYWl2ZSBjZW50cm9pZCBlbnN1cmVzCiMgcHNldWRvdGltZT0wIGlzIGJpb2xvZ2ljYWxseSBhbmNob3JlZCB0byB0aGUgbW9zdCB1bmRpZmZlcmVudGlhdGVkIHN0YXRlLgoKY2F0KCJBdmFpbGFibGUgQXppbXV0aCBsMiBsYWJlbHM6XG4iKQpwcmludChzb3J0KHVuaXF1ZShjb2xEYXRhKGNkcykkcHJlZGljdGVkLmNlbGx0eXBlLmwyKSkpCgojIEZpbmQgbmFpdmUgY2VsbHMg4oCUIHVzZSBib3RoIEF6aW11dGggbGFiZWwgYW5kIG91ciBjZWxsX3R5cGUgYW5ub3RhdGlvbgpuYWl2ZV9pZHMgPC0gcm93bmFtZXMoY29sRGF0YShjZHMpKVsKICBncmVwbCgibmFpdmV8TmFpdmV8VE4kIiwgY29sRGF0YShjZHMpJHByZWRpY3RlZC5jZWxsdHlwZS5sMiwgaWdub3JlLmNhc2UgPSBUUlVFKSB8CiAgZ3JlcGwoIlRuYWl2ZSIsIGFzLmNoYXJhY3Rlcihjb2xEYXRhKGNkcykkY2VsbF90eXBlKSwgaWdub3JlLmNhc2UgPSBGQUxTRSkKXQoKY2F0KCJcbk5haXZlIHJvb3QgY2VsbHMgaWRlbnRpZmllZDoiLCBsZW5ndGgobmFpdmVfaWRzKSwgIlxuIikKaWYgKGxlbmd0aChuYWl2ZV9pZHMpID09IDApIHsKICBzdG9wKCLinYwgTm8gbmFpdmUgcm9vdCBjZWxscyBmb3VuZC4gQ2hlY2sgbGFiZWwgc3RyaW5ncyBhYm92ZSBhbmQgYWRqdXN0IGdyZXAgcGF0dGVybnMuIikKfQoKIyDilIDilIAgRnVuY3Rpb24gdG8gZmluZCB0aGUgcHJpbmNpcGFsIGdyYXBoIG5vZGUgY2xvc2VzdCB0byBuYWl2ZSBjZW50cm9pZCDilIDilIDilIDilIAKZ2V0X3Jvb3Rfbm9kZSA8LSBmdW5jdGlvbihjZHMsIGNlbGxfaWRzKSB7CiAgY2xvc2VzdCA8LSBjZHNAcHJpbmNpcGFsX2dyYXBoX2F1eCRVTUFQJHByX2dyYXBoX2NlbGxfcHJval9jbG9zZXN0X3ZlcnRleAogIGNsb3Nlc3QgPC0gYXMubWF0cml4KGNsb3Nlc3RbY29sbmFtZXMoY2RzKSwgXSkKICBpZ3JhcGg6OlYocHJpbmNpcGFsX2dyYXBoKGNkcykkVU1BUCkkbmFtZVsKICAgIGFzLm51bWVyaWMobmFtZXMod2hpY2gubWF4KHRhYmxlKGNsb3Nlc3RbY2VsbF9pZHMsIF0pKSkpCiAgXQp9Cgpyb290X25vZGUgPC0gZ2V0X3Jvb3Rfbm9kZShjZHMsIG5haXZlX2lkcykKY2F0KCJSb290IG5vZGU6Iiwgcm9vdF9ub2RlLCAiXG4iKQoKIyDilIDilIAgT3JkZXIgY2VsbHMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACmNkcyA8LSBvcmRlcl9jZWxscyhjZHMsIHJvb3RfcHJfbm9kZXMgPSByb290X25vZGUpCgojIFRyYW5zZmVyIHBzZXVkb3RpbWUgYmFjayB0byBTZXVyYXQgb2JqZWN0CnJlZmVyZW5jZV9pbnRlZ3JhdGVkJG1vbm9jbGUzX3BzZXVkb3RpbWUgPC0gcHNldWRvdGltZShjZHMpCgojIFJlcGxhY2UgSW5mICh1bnJlYWNoYWJsZSBjZWxscykgd2l0aCBOQSBmb3IgY2xlYW4gcGxvdHRpbmcKcmVmZXJlbmNlX2ludGVncmF0ZWQkbW9ub2NsZTNfcHNldWRvdGltZVsKICAhaXMuZmluaXRlKHJlZmVyZW5jZV9pbnRlZ3JhdGVkJG1vbm9jbGUzX3BzZXVkb3RpbWUpCl0gPC0gTkEKCmNhdCgiXG5Qc2V1ZG90aW1lIHN1bW1hcnkgKGZpbml0ZSB2YWx1ZXMpOlxuIikKcHJpbnQoc3VtbWFyeShyZWZlcmVuY2VfaW50ZWdyYXRlZCRtb25vY2xlM19wc2V1ZG90aW1lWwogIGlzLmZpbml0ZShyZWZlcmVuY2VfaW50ZWdyYXRlZCRtb25vY2xlM19wc2V1ZG90aW1lKQpdKSkKCiMg4pSA4pSAIFBsb3QgcHNldWRvdGltZSBvbiB0cmFqZWN0b3J5IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApwbG90X2NlbGxzKAogIGNkcywKICBjb2xvcl9jZWxsc19ieSAgICA9ICJwc2V1ZG90aW1lIiwKICBsYWJlbF9jZWxsX2dyb3VwcyA9IEZBTFNFLAogIGNlbGxfc2l6ZSAgICAgICAgID0gMC44LAogIHNob3dfdHJhamVjdG9yeV9ncmFwaCA9IFRSVUUKKSArCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKG9wdGlvbiA9ICJwbGFzbWEiLCBuYW1lID0gIlBzZXVkb3RpbWUiKSArCiAgZ2d0aXRsZSgiUmVmZXJlbmNlIENENCsgVCBDZWxsIFBzZXVkb3RpbWVcbihSb290ID0gVG5haXZlLCBUZXJtaW5hbCA9IFRlbXJhL0NUTCkiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE0LCBmYWNlID0gImJvbGQiKSkKCiMg4pSA4pSAIFBzZXVkb3RpbWUgb24gU2V1cmF0IFVNQVAgKyBzdGF0ZSBsYWJlbHMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dyZXBlbCkKCnVtYXBfZGYgPC0gYXMuZGF0YS5mcmFtZShFbWJlZGRpbmdzKHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCAidW1hcCIpKQpjb2xuYW1lcyh1bWFwX2RmKSA8LSBjKCJVTUFQMSIsICJVTUFQMiIpCnVtYXBfZGYkcHQgPC0gcmVmZXJlbmNlX2ludGVncmF0ZWQkbW9ub2NsZTNfcHNldWRvdGltZQp1bWFwX2RmJGwyIDwtIHJlZmVyZW5jZV9pbnRlZ3JhdGVkJHByZWRpY3RlZC5jZWxsdHlwZS5sMgoKdW1hcF9kZiA8LSB1bWFwX2RmW2lzLmZpbml0ZSh1bWFwX2RmJHB0KSAmICFpcy5uYSh1bWFwX2RmJGwyKSwgXQoKbGFiZWxfY29vcmRzIDwtIHVtYXBfZGYgJT4lCiAgZ3JvdXBfYnkobDIpICU+JQogIHN1bW1hcmlzZSgKICAgIFVNQVAxID0gbWVkaWFuKFVNQVAxKSwKICAgIFVNQVAyID0gbWVkaWFuKFVNQVAyKSwKICAgIC5ncm91cHMgPSAiZHJvcCIKICApCgpwX3VtYXAgPC0gRmVhdHVyZVBsb3QoCiAgcmVmZXJlbmNlX2ludGVncmF0ZWQsCiAgZmVhdHVyZXMgID0gIm1vbm9jbGUzX3BzZXVkb3RpbWUiLAogIHJlZHVjdGlvbiA9ICJ1bWFwIiwKICBjb2xzICAgICAgPSBjKCJsaWdodGJsdWUiLCAiZ3JlZW4iLCAicmVkIiksCiAgbGFiZWwgICAgID0gRkFMU0UsCiAgcHQuc2l6ZSAgID0gMC41CikKCnBfdW1hcCArCiAgZ2VvbV9sYWJlbF9yZXBlbCgKICAgIGRhdGEgPSBsYWJlbF9jb29yZHMsCiAgICBhZXMoeCA9IFVNQVAxLCB5ID0gVU1BUDIsIGxhYmVsID0gbDIpLAogICAgaW5oZXJpdC5hZXMgPSBGQUxTRSwKICAgIHNpemUgPSA0LAogICAgZm9udGZhY2UgPSAiYm9sZCIsCiAgICBmaWxsID0gIndoaXRlIiwKICAgIGFscGhhID0gMC44NSwKICAgIGJveC5wYWRkaW5nID0gMC40LAogICAgbGFiZWwucGFkZGluZyA9IDAuMjUsCiAgICBzZWdtZW50LmNvbG9yID0gImdyZXk0MCIKICApICsKICBnZ3RpdGxlKCJSZWZlcmVuY2UgVU1BUCDigJQgUHNldWRvdGltZSB3aXRoIENENCBOYWl2ZSAvIFRDTSAvIFRFTSAvIFRlbXJhL0NUTCAvIFRyZWcgbGFiZWxzIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQoKYGBgCgpgYGB7ciBtaWxlc3RvbmVzLCBmaWcud2lkdGg9MTQsIGZpZy5oZWlnaHQ9Nn0KIyDilIDilIAgREVGSU5FIE1JTEVTVE9ORVM6IEtleSBDRDQgc3RhdGVzIGFsb25nIHlvdXIgdHJhamVjdG9yeSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKIyBCYXNlZCBvbiB5b3VyIEF6aW11dGggbDIgKyBwc2V1ZG90aW1lIHF1YW50aWxlcwoKbGlicmFyeShkcGx5cikKCiMgMS4gR2V0IHN0YXRlLXNwZWNpZmljIHBzZXVkb3RpbWUgcmFuZ2VzCnB0X3JhbmdlcyA8LSByZWZlcmVuY2VfaW50ZWdyYXRlZEBtZXRhLmRhdGEgJT4lCiAgZmlsdGVyKGlzLmZpbml0ZShtb25vY2xlM19wc2V1ZG90aW1lKSkgJT4lCiAgZ3JvdXBfYnkocHJlZGljdGVkLmNlbGx0eXBlLmwyKSAlPiUKICBzdW1tYXJpc2UoCiAgICBuID0gbigpLAogICAgcHRfbWluID0gcm91bmQobWluKG1vbm9jbGUzX3BzZXVkb3RpbWUpLCAyKSwKICAgIHB0X21heCA9IHJvdW5kKG1heChtb25vY2xlM19wc2V1ZG90aW1lKSwgMiksCiAgICBwdF9tZWRpYW4gPSByb3VuZChtZWRpYW4obW9ub2NsZTNfcHNldWRvdGltZSksIDIpLAogICAgLmdyb3VwcyA9ICJkcm9wIgogICkgJT4lCiAgYXJyYW5nZShwdF9tZWRpYW4pCgpwcmludCgiUHNldWRvdGltZSBieSBzdGF0ZSAobWlsZXN0b25lIG9yZGVyKToiKQpwcmludChwdF9yYW5nZXMpCgojIDIuIERlZmluZSBtaWxlc3RvbmVzIChwc2V1ZG90aW1lIHF1YW50aWxlcyArIGJpb2xvZ3kpCm1pbGVzdG9uZXMgPC0gZGF0YS5mcmFtZSgKICBtaWxlc3RvbmUgPSBjKCJOYWl2ZSIsICJDZW50cmFsX01lbW9yeSIsICJFZmZlY3Rvcl9NZW1vcnkiLCAiVGVybWluYWxfRWZmZWN0b3IiKSwKICBwc2V1ZG90aW1lID0gYygwLjEsIDAuOCwgMS40LCAyLjApLCAgIyBZb3VyIHRyYWplY3RvcnkgcXVhbnRpbGVzCiAgc3RhdGUgPSBjKCJDRDQgTmFpdmUiLCAiQ0Q0IFRDTSIsICJDRDQgVEVNIiwgIkNENCBUZW1yYS9DVEwiKQopCgpwcmludCgiTWlsZXN0b25lcyBkZWZpbmVkOiIpCnByaW50KG1pbGVzdG9uZXMpCgojIDMuIEFzc2lnbiBjZWxscyB0byBtaWxlc3RvbmVzIOKAlCBGSVhFRCBmb3IgWU9VUiA1IHN0YXRlcwpyZWZfbWlsZXN0b25lcyA8LSByZWZlcmVuY2VfaW50ZWdyYXRlZEBtZXRhLmRhdGEgJT4lCiAgZmlsdGVyKGlzLmZpbml0ZShtb25vY2xlM19wc2V1ZG90aW1lKSkgJT4lCiAgbXV0YXRlKAogICAgbWlsZXN0b25lID0gY2FzZV93aGVuKAogICAgICAjIE5haXZlOiBwdCA8IDI1dGggcGVyY2VudGlsZQogICAgICBtb25vY2xlM19wc2V1ZG90aW1lIDw9IHF1YW50aWxlKG1vbm9jbGUzX3BzZXVkb3RpbWUsIDAuMjUsIG5hLnJtID0gVFJVRSkgfiAiTmFpdmUiLAogICAgICAKICAgICAgIyBDZW50cmFsIE1lbW9yeSAoVENNKTogMjV0aC02MHRoIHBlcmNlbnRpbGUgIAogICAgICBtb25vY2xlM19wc2V1ZG90aW1lIDw9IHF1YW50aWxlKG1vbm9jbGUzX3BzZXVkb3RpbWUsIDAuNjAsIG5hLnJtID0gVFJVRSkgfiAiQ2VudHJhbF9NZW1vcnkiLAogICAgICAKICAgICAgIyBUcmVnICsgVEVNOiA2MHRoLTg1dGggcGVyY2VudGlsZSAoYnJhbmNoICsgZWZmZWN0b3IgbWVtb3J5KQogICAgICBwcmVkaWN0ZWQuY2VsbHR5cGUubDIgPT0gIlRyZWciIHwgCiAgICAgIChtb25vY2xlM19wc2V1ZG90aW1lIDw9IHF1YW50aWxlKG1vbm9jbGUzX3BzZXVkb3RpbWUsIDAuODUsIG5hLnJtID0gVFJVRSkpIH4gIlJlZ3VsYXRvcnlfRWZmZWN0b3IiLAogICAgICAKICAgICAgIyBUZXJtaW5hbDogVEVNUkEvQ1RMICh0b3AgMTUlKQogICAgICBUUlVFIH4gIlRlcm1pbmFsX0VmZmVjdG9yIgogICAgKSwKICAgIAogICAgIyBTaW1wbGlmaWVkIHN0YXRlIG1hcHBpbmcgZm9yIGNvbG9yaW5nCiAgICBzdGF0ZV9ncm91cCA9IGNhc2Vfd2hlbigKICAgICAgcHJlZGljdGVkLmNlbGx0eXBlLmwyID09ICJDRDQgTmFpdmUiIH4gIk5haXZlIiwKICAgICAgcHJlZGljdGVkLmNlbGx0eXBlLmwyID09ICJDRDQgVENNIiB+ICJDZW50cmFsX01lbW9yeSIsIAogICAgICBwcmVkaWN0ZWQuY2VsbHR5cGUubDIgPT0gIlRyZWciIH4gIlRyZWciLAogICAgICBwcmVkaWN0ZWQuY2VsbHR5cGUubDIgPT0gIkNENCBURU0iIH4gIkVmZmVjdG9yX01lbW9yeSIsCiAgICAgIHByZWRpY3RlZC5jZWxsdHlwZS5sMiA9PSAiQ0Q0IFRlbXJhL0NUTCIgfiAiVGVybWluYWxfRWZmZWN0b3IiCiAgICApCiAgKQoKY2F0KCJNaWxlc3RvbmUgZGlzdHJpYnV0aW9uOlxuIikKcHJpbnQodGFibGUocmVmX21pbGVzdG9uZXMkbWlsZXN0b25lKSkKY2F0KCJcblN0YXRlIHZhbGlkYXRpb246XG4iKSAKcHJpbnQodGFibGUocmVmX21pbGVzdG9uZXMkcHJlZGljdGVkLmNlbGx0eXBlLmwyLCByZWZfbWlsZXN0b25lcyRzdGF0ZV9ncm91cCkpCgpgYGAKCgojIyBWYWxpZGF0ZSBQc2V1ZG90aW1lIEFnYWluc3QgQ2VsbCBUeXBlCgpgYGB7ciB2YWxpZGF0ZS1wc2V1ZG90aW1lLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NX0KIyDilIDilIAgR3VhcmQ6IG9ubHkgcnVuIGlmIG1vbm9jbGUzX3BzZXVkb3RpbWUgaGFzIGFscmVhZHkgYmVlbiBjb21wdXRlZCDilIDilIDilIDilIDilIDilIAKIyBUaGlzIGNvbHVtbiBpcyBjcmVhdGVkIGluIHRoZSB0cmFqZWN0b3J5IGNodW5rIChTZWN0aW9uIDIpLgojIElmIHlvdSBhcmUgcnVubmluZyB0aGlzIHNjcmlwdCBmb3IgdGhlIGZpcnN0IHRpbWUgb24gYSBmcmVzaGx5IGxvYWRlZAojIHJlZmVyZW5jZSAod2l0aG91dCBwc2V1ZG90aW1lKSwgdGhpcyBjaHVuayB3aWxsIHNraXAgZ3JhY2VmdWxseS4KIyBSZS1ydW4gYWZ0ZXIgdGhlIHRyYWplY3Rvcnkgc2VjdGlvbiBjb21wbGV0ZXMuCgppZiAoISJtb25vY2xlM19wc2V1ZG90aW1lIiAlaW4lIGNvbG5hbWVzKHJlZmVyZW5jZV9pbnRlZ3JhdGVkQG1ldGEuZGF0YSkpIHsKICBtZXNzYWdlKAogICAgIuKaoO+4jyAgbW9ub2NsZTNfcHNldWRvdGltZSBub3QgeWV0IGNvbXB1dGVkIOKAlCBza2lwcGluZyB2YWxpZGF0aW9uIHBsb3RzLlxuIiwKICAgICIgICBSdW4gU2VjdGlvbiAyIChSZWZlcmVuY2UgVHJhamVjdG9yeSkgZmlyc3QsIHRoZW4gcmUtcnVuIHRoaXMgY2h1bmsuIgogICkKfSBlbHNlIHsKCiMg4pSA4pSAIFZpb2xpbjogcHNldWRvdGltZSBkaXN0cmlidXRpb24gcGVyIEF6aW11dGggbDIgbGFiZWwg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACiMgQ09ORklSTUVEIGxhYmVsIG9yZGVyIGluIHRoaXMgZGF0YXNldCAobG93IOKGkiBoaWdoIHBzZXVkb3RpbWUpOgojICAgQ0Q0IE5haXZlIOKGkiBDRDQgVENNIOKGkiBDRDQgVEVNIOKGkiBDRDQgVGVtcmEvQ1RMIChoaWdoZXN0KQojICAgVHJlZzogc2VwYXJhdGUgYnJhbmNoLCB2YXJpYWJsZSBwc2V1ZG90aW1lCiMKIyBXZSB1c2UgcHJlZGljdGVkLmNlbGx0eXBlLmwyIGFzIFBSSU1BUlkgbGFiZWwgdGhyb3VnaG91dCDigJQgY29uc2lzdGVudAojIHdpdGggdGhlIHJlc3Qgb2YgdGhlIGFuYWx5c2lzLgoKcHRfZGF0YSA8LSBkYXRhLmZyYW1lKAogIHBzZXVkb3RpbWUgPSByZWZlcmVuY2VfaW50ZWdyYXRlZCRtb25vY2xlM19wc2V1ZG90aW1lLAogIGwyICAgICAgICAgPSByZWZlcmVuY2VfaW50ZWdyYXRlZCRwcmVkaWN0ZWQuY2VsbHR5cGUubDIKKSAlPiUKICBmaWx0ZXIoaXMuZmluaXRlKHBzZXVkb3RpbWUpLCAhaXMubmEobDIpKQoKIyBPcmRlciBsMiBsYWJlbHMgYnkgbWVkaWFuIHBzZXVkb3RpbWUKbDJfb3JkZXIgPC0gcHRfZGF0YSAlPiUKICBncm91cF9ieShsMikgJT4lCiAgc3VtbWFyaXNlKG1lZF9wdCA9IG1lZGlhbihwc2V1ZG90aW1lLCBuYS5ybSA9IFRSVUUpKSAlPiUKICBhcnJhbmdlKG1lZF9wdCkgJT4lCiAgcHVsbChsMikKCnB0X2RhdGEkbDIgPC0gZmFjdG9yKHB0X2RhdGEkbDIsIGxldmVscyA9IGwyX29yZGVyKQoKIyDilIDilIAgVmlvbGluIHBsb3QgY29sb3VyZWQgYnkgQXppbXV0aCBsMiDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKcF92aW9saW4gPC0gZ2dwbG90KHB0X2RhdGEsIGFlcyh4ID0gbDIsIHkgPSBwc2V1ZG90aW1lLCBmaWxsID0gbDIpKSArCiAgZ2VvbV92aW9saW4oc2NhbGUgPSAid2lkdGgiLCBhbHBoYSA9IDAuODUsIHRyaW0gPSBUUlVFKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4xMiwgZmlsbCA9ICJ3aGl0ZSIsIG91dGxpZXIuc2l6ZSA9IDAuMykgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGF6aW11dGhfbDJfY29sb3JzLCBuYS52YWx1ZSA9ICJncmV5NzAiKSArCiAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAxMSkgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDAsIGhqdXN0ID0gMSwgc2l6ZSA9IDkpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgcGxvdC50aXRsZSAgID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKQogICkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJQc2V1ZG90aW1lIERpc3RyaWJ1dGlvbiBwZXIgQXppbXV0aCBsMiBMYWJlbCAoUmVmZXJlbmNlKSIsCiAgICB4ID0gIiIsIHkgPSAiTW9ub2NsZTMgUHNldWRvdGltZSIKICApCgojIOKUgOKUgCBSaWRnZSBwbG90IOKAlCBzYW1lIGRhdGEsIGRpZmZlcmVudCB2aWV3IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApwX3JpZGdlIDwtIGdncGxvdChwdF9kYXRhLCBhZXMoeCA9IHBzZXVkb3RpbWUsIHkgPSBsMiwgZmlsbCA9IGwyKSkgKwogIGdlb21fZGVuc2l0eV9yaWRnZXMoYWxwaGEgPSAwLjc1LCBzY2FsZSA9IDEuMiwgcmVsX21pbl9oZWlnaHQgPSAwLjAxKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYXppbXV0aF9sMl9jb2xvcnMsIG5hLnZhbHVlID0gImdyZXk3MCIpICsKICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDEwKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpKSArCiAgbGFicygKICAgIHRpdGxlID0gIlBzZXVkb3RpbWUgRGVuc2l0eSBieSBBemltdXRoIGwyIExhYmVsIiwKICAgIHggPSAiUHNldWRvdGltZSIsIHkgPSAiIgogICkKCnBfdmlvbGluIHwgcF9yaWRnZQoKfSAjIGVuZCBlbHNlIChtb25vY2xlM19wc2V1ZG90aW1lIGV4aXN0cykKYGBgCgoKIyBQcmVwYXJlIFJlZmVyZW5jZSBmb3IgTWFwUXVlcnkgUHJvamVjdGlvbgoKYGBge3IgcHJlcGFyZS1yZWZlcmVuY2V9CiMg4pSA4pSAIEVuc3VyZSBTQ1QgYXNzYXkgYW5kIHZhcmlhYmxlIGZlYXR1cmVzIGFyZSBzZXQg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACiMgTWFwUXVlcnkgcmVxdWlyZXM6CiMgICAxLiBEZWZhdWx0QXNzYXkgPSAiU0NUIiBvbiByZWZlcmVuY2UKIyAgIDIuIFZhcmlhYmxlRmVhdHVyZXMgc2V0IG9uIHJlZmVyZW5jZSBTQ1QKIyAgIDMuIFBDQSByZWR1Y3Rpb24gYXZhaWxhYmxlCiMgICA0LiBVTUFQIHdpdGggcmV0dXJuLm1vZGVsID0gVFJVRSAodmFsaWRhdGVkIGFib3ZlKQoKRGVmYXVsdEFzc2F5KHJlZmVyZW5jZV9pbnRlZ3JhdGVkKSA8LSAiU0NUIgoKcmVmX2h2Z3MgPC0gVmFyaWFibGVGZWF0dXJlcyhyZWZlcmVuY2VfaW50ZWdyYXRlZCwgYXNzYXkgPSAiU0NUIikKCmlmIChsZW5ndGgocmVmX2h2Z3MpID09IDApIHsKICBjYXQoIuKaoO+4jyAgTm8gSFZHcyBzdG9yZWQg4oCUIGV4dHJhY3RpbmcgZnJvbSBzY2FsZS5kYXRhIHJvd25hbWVzXG4iKQogIHJlZl9odmdzIDwtIHJvd25hbWVzKEdldEFzc2F5RGF0YShyZWZlcmVuY2VfaW50ZWdyYXRlZCwgYXNzYXkgPSAiU0NUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxheWVyID0gInNjYWxlLmRhdGEiKSkKfQoKY2F0KCJSZWZlcmVuY2UgSFZHcyBhdmFpbGFibGU6IiwgbGVuZ3RoKHJlZl9odmdzKSwgIlxuIikKY2F0KCJQQ0EgZGltcyBhdmFpbGFibGU6IiwgbmNvbChFbWJlZGRpbmdzKHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCAicGNhIikpLCAiXG4iKQpjYXQoIuKchSBSZWZlcmVuY2UgcmVhZHkgZm9yIE1hcFF1ZXJ5XG4iKQoKCmBgYAoKCiMgTWFwIE1hbGlnbmFudCBDRDQrIFQgQ2VsbHMgb250byBSZWZlcmVuY2UKCiMjIEZpbmQgVHJhbnNmZXIgQW5jaG9ycwoKYGBge3IgZmluZC1hbmNob3JzfQojIOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkAojIEZpbmRUcmFuc2ZlckFuY2hvcnMKIyDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZAKIyBub3JtYWxpemF0aW9uLm1ldGhvZCA9ICJTQ1QiOiBib3RoIG9iamVjdHMgYXJlIFNDVC1ub3JtYWxpc2VkCiMgcmVmZXJlbmNlLnJlZHVjdGlvbiAgPSAicGNhIjogYW5jaG9ycyBpbiB0aGUgcmVmZXJlbmNlIFBDQSBzcGFjZQojIGRpbXMgPSAxOjIwOiBjb25zaXN0ZW50IHdpdGggcmVmZXJlbmNlIGNsdXN0ZXJpbmcKIwojIEtFWSBGSVg6IGNvbW1vbl9mZWF0dXJlcyBub3cgY29tcHV0ZWQgZnJvbSBwZXItbGluZSBTQ1QgSFZHcyAoc2hhcmVkX2h2Z3MpCiMgaW50ZXJzZWN0ZWQgd2l0aCByZWZlcmVuY2UgSFZHcy4gVGhpcyBlbnN1cmVzIGFuY2hvcnMgYXJlIGZvdW5kIG9uIGdlbmVzCiMgdGhhdCBhcmUgdmFyaWFibGUgaW4gQk9USCB0aGUgcmVmZXJlbmNlIGJpb2xvZ3kgQU5EIGVhY2ggbWFsaWduYW50IGxpbmUuCiMgUHJldmlvdXNseSAobWVyZ2VkIFNDVCksIGNvbW1vbl9mZWF0dXJlcyB3ZXJlIGRvbWluYXRlZCBieSBiYXRjaC1kcml2ZW4KIyBIVkdzIGZyb20gb25lIGxhcmdlIFNDVCBtb2RlbCDihpIgYmlhc2VkIGFuY2hvcnMg4oaSIGFsbCBjZWxscyDihpIgVENNLgojIOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkAoKRGVmYXVsdEFzc2F5KHJlZmVyZW5jZV9pbnRlZ3JhdGVkKSA8LSAiU0NUIgpEZWZhdWx0QXNzYXkoTWFsaWduYW50Q0Q0VCkgICAgICAgIDwtICJTQ1QiCgpyZWZfaHZncyA8LSBWYXJpYWJsZUZlYXR1cmVzKHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCBhc3NheSA9ICJTQ1QiKQppZiAobGVuZ3RoKHJlZl9odmdzKSA9PSAwKSB7CiAgcmVmX2h2Z3MgPC0gcm93bmFtZXMoR2V0QXNzYXlEYXRhKHJlZmVyZW5jZV9pbnRlZ3JhdGVkLCBhc3NheSA9ICJTQ1QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGF5ZXIgPSAic2NhbGUuZGF0YSIpKQp9CgojIFZhcmlhYmxlRmVhdHVyZXMgb24gbWVyZ2VkIG1hbGlnbmFudCA9IHNoYXJlZF9odmdzIHNldCBpbiBwZXItbGluZSBTQ1QgYmxvY2sKcXVlcnlfaHZncyA8LSBWYXJpYWJsZUZlYXR1cmVzKE1hbGlnbmFudENENFQpCgpjb21tb25fZmVhdHVyZXMgPC0gaW50ZXJzZWN0KHJlZl9odmdzLCBxdWVyeV9odmdzKQpjYXQoIlJlZmVyZW5jZSBIVkdzOiIsIGxlbmd0aChyZWZfaHZncyksICJcbiIpCmNhdCgiUXVlcnkgSFZHcyAocGVyLWxpbmUgY29uc2Vuc3VzKToiLCBsZW5ndGgocXVlcnlfaHZncyksICJcbiIpCmNhdCgiQ29tbW9uIEhWR3MgZm9yIGFuY2hvciBmaW5kaW5nOiIsIGxlbmd0aChjb21tb25fZmVhdHVyZXMpLCAiXG4iKQoKaWYgKGxlbmd0aChjb21tb25fZmVhdHVyZXMpIDwgMTUwMCkgewogIHdhcm5pbmcocGFzdGUwKAogICAgIuKaoO+4jyAgT25seSAiLCBsZW5ndGgoY29tbW9uX2ZlYXR1cmVzKSwgIiBjb21tb24gZmVhdHVyZXMgZm91bmQuXG4iLAogICAgIiAgIFRoaXMgaXMgYmVsb3cgdGhlIHJlY29tbWVuZGVkIG1pbmltdW0gb2YgMTUwMC5cbiIsCiAgICAiICAgQ2hlY2sgdGhhdCBib3RoIG9iamVjdHMgdXNlZCBTQ1RyYW5zZm9ybSB3aXRoIHNpbWlsYXIgZ2VuZSBzZXRzLlxuIiwKICAgICIgICBDb25zaWRlciBpbmNyZWFzaW5nIG5mZWF0dXJlcyBpbiBTQ1RyYW5zZm9ybSB0byA0MDAwLiIKICApKQp9IGVsc2UgewogIGNhdCgi4pyFIFN1ZmZpY2llbnQgY29tbW9uIGZlYXR1cmVzIGZvciByb2J1c3QgYW5jaG9yIGZpbmRpbmdcbiIpCn0KCgojIOKUgOKUgCBDbGVhbiBhbmQgcmFuayBjb21tb25fZmVhdHVyZXMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACgojIDEuIFJlbW92ZSByaWJvc29tYWwsIG1pdG9jaG9uZHJpYWwsIGhlYXQgc2hvY2ssIGFuZCBvdGhlciBrbm93biBiYXRjaCBnZW5lcwojICAgIFRoZXNlIGFyZSBoaWdobHkgdmFyaWFibGUgZHVlIHRvIGxpYnJhcnkgcXVhbGl0eSwgbm90IGJpb2xvZ3kuCmp1bmtfcGF0dGVybiA8LSAiXlJQTHxeUlBTfF5NVC18XkhTUHxeSFNQQXxeSFNQQnxeSFNQRHxeSFNQRXxeSFNQSHxeU05IR3xeTUFMQVQxfF5ORUFUMXxeWElTVCIKbl9iZWZvcmUgPC0gbGVuZ3RoKGNvbW1vbl9mZWF0dXJlcykKY29tbW9uX2ZlYXR1cmVzX2NsZWFuIDwtIGNvbW1vbl9mZWF0dXJlc1shZ3JlcGwoanVua19wYXR0ZXJuLCBjb21tb25fZmVhdHVyZXMpXQpjYXQoIlJlbW92ZWQganVuayBnZW5lczoiLCBuX2JlZm9yZSAtIGxlbmd0aChjb21tb25fZmVhdHVyZXNfY2xlYW4pLCAiXG4iKQpjYXQoIkNsZWFuIGNvbW1vbiBmZWF0dXJlczoiLCBsZW5ndGgoY29tbW9uX2ZlYXR1cmVzX2NsZWFuKSwgIlxuIikKCiMgMi4gUmFuayBieSBtZWFuIEhWRyByYW5rIGFjcm9zcyByZWZlcmVuY2UgYW5kIHF1ZXJ5CiMgICAgU0NUcmFuc2Zvcm0gc3RvcmVzIHJlc2lkdWFsIHZhcmlhbmNlIHBlciBnZW5lIOKAlCBoaWdoZXIgPSBtb3JlIHZhcmlhYmxlLgojICAgIEdlbmVzIHJhbmtlZCBoaWdobHkgaW4gQk9USCBvYmplY3RzIGFyZSByb2J1c3RseSB2YXJpYWJsZSAoYmlvbG9neS1kcml2ZW4pLgpyZWZfdmFyX21ldGEgIDwtIHJlZmVyZW5jZV9pbnRlZ3JhdGVkW1siU0NUIl1dQG1ldGEuZmVhdHVyZXMKcXVlcnlfdmFyX21ldGEgPC0gTWFsaWduYW50Q0Q0VFtbIlNDVCJdXUBtZXRhLmZlYXR1cmVzCgojIHJlc2lkdWFsX3ZhcmlhbmNlIGNvbHVtbiBpcyBzZXQgYnkgU0NUcmFuc2Zvcm0KaWYgKCJyZXNpZHVhbF92YXJpYW5jZSIgJWluJSBjb2xuYW1lcyhyZWZfdmFyX21ldGEpICYmCiAgICAicmVzaWR1YWxfdmFyaWFuY2UiICVpbiUgY29sbmFtZXMocXVlcnlfdmFyX21ldGEpKSB7CgogIHJlZl9yYW5rcyAgIDwtIHJlZl92YXJfbWV0YVtjb21tb25fZmVhdHVyZXNfY2xlYW4sICJyZXNpZHVhbF92YXJpYW5jZSJdCiAgcXVlcnlfcmFua3MgPC0gcXVlcnlfdmFyX21ldGFbY29tbW9uX2ZlYXR1cmVzX2NsZWFuLCAicmVzaWR1YWxfdmFyaWFuY2UiXQoKICAjIFJlcGxhY2UgTkEgd2l0aCAwIChnZW5lIG5vdCBpbiB0aGF0IG9iamVjdCdzIHZhcmlhbmNlIHRhYmxlKQogIHJlZl9yYW5rc1tpcy5uYShyZWZfcmFua3MpXSAgICAgPC0gMAogIHF1ZXJ5X3JhbmtzW2lzLm5hKHF1ZXJ5X3JhbmtzKV0gPC0gMAoKICBtZWFuX3ZhciA8LSAocmVmX3JhbmtzICsgcXVlcnlfcmFua3MpIC8gMgogIGNvbW1vbl9mZWF0dXJlcyA8LSBjb21tb25fZmVhdHVyZXNfY2xlYW5bb3JkZXIobWVhbl92YXIsIGRlY3JlYXNpbmcgPSBUUlVFKV0KCiAgY2F0KCJUb3AgMjAgcmFua2VkIGZlYXR1cmVzIChzaG91bGQgYmUgVCBjZWxsIGJpb2xvZ3kpOlxuIikKICBwcmludChoZWFkKGNvbW1vbl9mZWF0dXJlcywgMjApKQoKfSBlbHNlIHsKICAjIEZhbGxiYWNrOiBqdXN0IHVzZSBjbGVhbmVkIGxpc3Qgd2l0aG91dCByYW5raW5nCiAgY2F0KCLimqDvuI8gIHJlc2lkdWFsX3ZhcmlhbmNlIG5vdCBmb3VuZCBpbiBTQ1QgbWV0YS5mZWF0dXJlcywgdXNpbmcgdW5yYW5rZWQgY2xlYW4gbGlzdFxuIikKICBjb21tb25fZmVhdHVyZXMgPC0gY29tbW9uX2ZlYXR1cmVzX2NsZWFuCn0KCiMgMy4gU2FuaXR5IGNoZWNrOiBrZXkgVCBjZWxsIG1hcmtlciBnZW5lcyBwcmVzZW50PwptYXJrZXJzX3RvX2NoZWNrIDwtIGMoIkNDUjciLCAiU0VMTCIsICJUQ0Y3IiwgIklMN1IiLCAiR1pNQiIsICJQUkYxIiwKICAgICAgICAgICAgICAgICAgICAgICJGT1hQMyIsICJDWENSNSIsICJUT1giLCAiUERDRDEiLCAiSEFWQ1IyIiwgIlRJR0lUIiwKICAgICAgICAgICAgICAgICAgICAgICJDRDQ0IiwgIkNENjkiLCAiSUZORyIsICJUTkYiLCAiRU9NRVMiLCAiVEJYMjEiKQpmb3VuZF9tYXJrZXJzIDwtIG1hcmtlcnNfdG9fY2hlY2tbbWFya2Vyc190b19jaGVjayAlaW4lIGNvbW1vbl9mZWF0dXJlc10KY2F0KCJcbktleSBUIGNlbGwgbWFya2VycyBpbiBmZWF0dXJlIHNldDoiLCBsZW5ndGgoZm91bmRfbWFya2VycyksICIvIiwgbGVuZ3RoKG1hcmtlcnNfdG9fY2hlY2spLCAiXG4iKQpwcmludChmb3VuZF9tYXJrZXJzKQoKaWYgKGxlbmd0aChmb3VuZF9tYXJrZXJzKSA8IDUpIHsKICB3YXJuaW5nKHBhc3RlMCgKICAgICLimqDvuI8gIEZld2VyIHRoYW4gNSBjYW5vbmljYWwgVCBjZWxsIG1hcmtlcnMgaW4gY29tbW9uX2ZlYXR1cmVzLlxuIiwKICAgICIgICBUaGUgZmVhdHVyZSBzZXQgbWF5IHN0aWxsIGJlIGRvbWluYXRlZCBieSBub24tc3BlY2lmaWMgZ2VuZXMuXG4iLAogICAgIiAgIENvbnNpZGVyOiBkaWQgU0NUcmFuc2Zvcm0gdXNlIHN1ZmZpY2llbnQgbmZlYXR1cmVzICgzMDAwLTQwMDApP1xuIiwKICAgICIgICBSdW46IGxlbmd0aChWYXJpYWJsZUZlYXR1cmVzKHJlZmVyZW5jZV9pbnRlZ3JhdGVkKSkgdG8gY2hlY2suIgogICkpCn0KCgpjYXQoIlxuPT09IEZpbmRpbmcgdHJhbnNmZXIgYW5jaG9ycyA9PT1cbiIpCgojIERpYWdub3N0aWNzCmNhdCgiUmVmZXJlbmNlIGNlbGxzOiIsIG5jb2wocmVmZXJlbmNlX2ludGVncmF0ZWQpLCAiXG4iKQpjYXQoIlF1ZXJ5IGNlbGxzOiAgICAiLCBuY29sKE1hbGlnbmFudENENFQpLCAiXG4iKQpjYXQoIkNvbW1vbiBmZWF0dXJlczoiLCBsZW5ndGgoY29tbW9uX2ZlYXR1cmVzKSwgIlxuIikKCiMgVXNlIGFzIG1hbnkgZGltcyBhcyBib3RoIG9iamVjdHMgc3VwcG9ydCAodXAgdG8gMzApCmRpbXNfdG9fdXNlIDwtIG1pbigzMCwKICAgICAgICAgICAgICAgICAgIG5jb2woRW1iZWRkaW5ncyhyZWZlcmVuY2VfaW50ZWdyYXRlZCwgInBjYSIpKSwKICAgICAgICAgICAgICAgICAgIG5jb2woRW1iZWRkaW5ncyhNYWxpZ25hbnRDRDRULCAicGNhIikpKQpjYXQoIlVzaW5nIGRpbXMgMToiLCBkaW1zX3RvX3VzZSwgIlxuIikKCiMgS0VZIENIQU5HRVMgdnMgcHJldmlvdXMgcnVuOgojICAgay5hbmNob3IgPSAxMCAgICh3YXMgZGVmYXVsdCA1KSAg4oaSIG1vcmUgaW5pdGlhbCBhbmNob3IgY2FuZGlkYXRlcwojICAgay5maWx0ZXIgPSA1MDAgICh3YXMgZGVmYXVsdCAyMDApIOKGkiBsZXNzIGFnZ3Jlc3NpdmUgcHJ1bmluZyBvbiA0MGsgcXVlcnkKIyAgIGRpbXMgPSAxOjMwICAgICAod2FzIDE6MjApICAgICAgICDihpIgY2FwdHVyZSBtb3JlIHZhcmlhbmNlIGluIHR1bW91ciBjZWxscwphbmNob3JzIDwtIEZpbmRUcmFuc2ZlckFuY2hvcnMoCiAgcmVmZXJlbmNlICAgICAgICAgICAgPSByZWZlcmVuY2VfaW50ZWdyYXRlZCwKICBxdWVyeSAgICAgICAgICAgICAgICA9IE1hbGlnbmFudENENFQsCiAgZmVhdHVyZXMgICAgICAgICAgICAgPSBjb21tb25fZmVhdHVyZXMsCiAgbm9ybWFsaXphdGlvbi5tZXRob2QgPSAiU0NUIiwKICByZWZlcmVuY2UucmVkdWN0aW9uICA9ICJwY2EiLAogIGRpbXMgICAgICAgICAgICAgICAgID0gMTpkaW1zX3RvX3VzZSwKICBrLmFuY2hvciAgICAgICAgICAgICA9IDEwLAogIGsuZmlsdGVyICAgICAgICAgICAgID0gNTAwLAogIGsuc2NvcmUgICAgICAgICAgICAgID0gMzAsCiAgdmVyYm9zZSAgICAgICAgICAgICAgPSBUUlVFCikKCm5fYW5jaG9ycyAgICA8LSBucm93KGFuY2hvcnNAYW5jaG9ycykKYW5jaG9yX3JhdGlvIDwtIG5jb2woTWFsaWduYW50Q0Q0VCkgLyBuX2FuY2hvcnMKY2F0KCJBbmNob3JzIGZvdW5kOiIsIG5fYW5jaG9ycywgIlxuIikKY2F0KCJDZWxscyBwZXIgYW5jaG9yOiIsIHJvdW5kKGFuY2hvcl9yYXRpbywgMSksICJcbiIpCgppZiAoYW5jaG9yX3JhdGlvID4gOCkgewogIHdhcm5pbmcocGFzdGUwKAogICAgIuKaoO+4jyAgTG93IGFuY2hvciBkZW5zaXR5ICgxOiIsIHJvdW5kKGFuY2hvcl9yYXRpbywgMSksICIpLlxuIiwKICAgICIgICBJZGVhbCBpcyAxOjUgb3IgYmV0dGVyLiBJbnNwZWN0IGhlYWQoY29tbW9uX2ZlYXR1cmVzKSBmb3IgYmF0Y2ggZ2VuZXMsXG4iLAogICAgIiAgIGFuZCBjaGVjayBxdWVyeSBVTUFQIHByb2plY3Rpb24gYmVmb3JlIHRydXN0aW5nIHBzZXVkb3RpbWUgdmFsdWVzLiIKICApKQp9IGVsc2UgewogIGNhdCgi4pyFIEFuY2hvciBkZW5zaXR5IGFjY2VwdGFibGVcbiIpCn0KYGBgCgojIyBNYXBRdWVyeSDigJQgUHJvamVjdCBvbnRvIFJlZmVyZW5jZSBVTUFQCgpgYGB7ciBtYXAtcXVlcnl9CiMg4pSA4pSAIE1hcFF1ZXJ5IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAojIFRoaXMgZG9lcyB0aHJlZSB0aGluZ3Mgc2ltdWx0YW5lb3VzbHk6CiMgICAxLiBUcmFuc2ZlckRhdGE6IHRyYW5zZmVycyBsYWJlbHMgKyBwc2V1ZG90aW1lIGZyb20gcmVmZXJlbmNlIHRvIHF1ZXJ5CiMgICAyLiBJbnRlZ3JhdGVFbWJlZGRpbmdzOiBwcm9qZWN0cyBxdWVyeSBQQ0EgaW50byByZWZlcmVuY2UgUENBIHNwYWNlCiMgICAzLiBQcm9qZWN0VU1BUDogcHJvamVjdHMgcXVlcnkgY2VsbHMgb250byB0aGUgRlJPWkVOIHJlZmVyZW5jZSBVTUFQCiMKIyByZWZkYXRhIHRyYW5zZmVyczoKIyAgIC0gbW9ub2NsZTNfcHNldWRvdGltZTogY29udGludW91cyBwc2V1ZG90aW1lIHZhbHVlICh2aWEgd2VpZ2h0ZWQgYW5jaG9ycykKIyAgIC0gc2V1cmF0X2NsdXN0ZXJzOiAgICAgcmVmZXJlbmNlIGNsdXN0ZXIgSUQgKDAtNikKIyAgIC0gY2VsbF90eXBlOiAgICAgICAgICAgb3VyIGFubm90YXRlZCBjZWxsIHR5cGUgbGFiZWwKIyAgIC0gcHJlZGljdGVkLmNlbGx0eXBlLmwyOiBBemltdXRoIGwyIGxhYmVsIChLRVkgZm9yIHN0YXRlIGludGVycHJldGF0aW9uKQoKY2F0KCI9PT0gUHJvamVjdGluZyBtYWxpZ25hbnQgY2VsbHMgb250byByZWZlcmVuY2UgKE1hcFF1ZXJ5KSA9PT1cbiIpCgptYXBwZWRfTWFsaWduYW50Q0Q0VCA8LSBNYXBRdWVyeSgKICBhbmNob3JzZXQgICAgICAgICA9IGFuY2hvcnMsCiAgcXVlcnkgICAgICAgICAgICAgPSBNYWxpZ25hbnRDRDRULAogIHJlZmVyZW5jZSAgICAgICAgID0gcmVmZXJlbmNlX2ludGVncmF0ZWQsCiAgcmVmZGF0YSAgICAgICAgICAgPSBsaXN0KAogICAgIyBQUklNQVJZIOKAlCBBemltdXRoIGwyIGxhYmVsOiB0aGUgbWFpbiBzdGF0ZSBhbm5vdGF0aW9uIHVzZWQgdGhyb3VnaG91dAogICAgcHJlZGljdGVkLmNlbGx0eXBlLmwyID0gInByZWRpY3RlZC5jZWxsdHlwZS5sMiIsCiAgICAjIENPTlRJTlVPVVMg4oCUIHBzZXVkb3RpbWUgdmFsdWUgZnJvbSBNb25vY2xlMyB0cmFqZWN0b3J5CiAgICBwc2V1ZG90aW1lICAgICAgICAgICAgPSAibW9ub2NsZTNfcHNldWRvdGltZSIsCiAgICAjIFNFQ09OREFSWSDigJQgcmVmZXJlbmNlIGNsdXN0ZXIgSUQgKGludGVnZXIsIGZvciBjcm9zcy1jaGVjayBvbmx5KQogICAgc2V1cmF0X2NsdXN0ZXJzICAgICAgID0gInNldXJhdF9jbHVzdGVycyIKICApLAogIHJlZmVyZW5jZS5yZWR1Y3Rpb24gPSAicGNhIiwKICByZWR1Y3Rpb24ubW9kZWwgICAgID0gInVtYXAiCikKCmNhdCgi4pyFIE1hcFF1ZXJ5IGNvbXBsZXRlXG4iKQpjYXQoIk1hcHBlZCBtYWxpZ25hbnQgY2VsbHM6IiwgbmNvbChtYXBwZWRfTWFsaWduYW50Q0Q0VCksICJcbiIpCmNhdCgiXG5UcmFuc2ZlcnJlZCBtZXRhZGF0YSBjb2x1bW5zOlxuIikKdHJhbnNmZXJyZWRfY29scyA8LSBncmVwKCJecHJlZGljdGVkXFwuIiwgY29sbmFtZXMobWFwcGVkX01hbGlnbmFudENENFRAbWV0YS5kYXRhKSwgdmFsdWUgPSBUUlVFKQpwcmludCh0cmFuc2ZlcnJlZF9jb2xzKQoKY2F0KCJcblRyYW5zZmVycmVkIHBzZXVkb3RpbWUgc3VtbWFyeTpcbiIpCnByaW50KHN1bW1hcnkobWFwcGVkX01hbGlnbmFudENENFQkcHJlZGljdGVkLnBzZXVkb3RpbWUpKQoKY2F0KCJcblRyYW5zZmVycmVkIEF6aW11dGggbDIgZGlzdHJpYnV0aW9uIChQUklNQVJZKTpcbiIpCnByaW50KHRhYmxlKG1hcHBlZF9NYWxpZ25hbnRDRDRUJHByZWRpY3RlZC5wcmVkaWN0ZWQuY2VsbHR5cGUubDIpKQoKY2F0KCJcblRyYW5zZmVycmVkIGNsdXN0ZXIgZGlzdHJpYnV0aW9uIChzZWNvbmRhcnkgcmVmZXJlbmNlKTpcbiIpCnByaW50KHRhYmxlKG1hcHBlZF9NYWxpZ25hbnRDRDRUJHByZWRpY3RlZC5zZXVyYXRfY2x1c3RlcnMpKQoKIyDilIDilIAgU2FuaXR5IGNoZWNrOiBkaXN0cmlidXRpb24gc2hvdWxkIE5PVCBiZSA5OSUrIGluIG9uZSBzdGF0ZSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKbDJfZGlzdCAgIDwtIHByb3AudGFibGUodGFibGUobWFwcGVkX01hbGlnbmFudENENFQkcHJlZGljdGVkLnByZWRpY3RlZC5jZWxsdHlwZS5sMikpCm1heF9zdGF0ZSA8LSBuYW1lcyh3aGljaC5tYXgobDJfZGlzdCkpCm1heF9wY3QgICA8LSByb3VuZCgxMDAgKiBtYXgobDJfZGlzdCksIDEpCgppZiAobWF4X3BjdCA+IDkwKSB7CiAgd2FybmluZyhwYXN0ZTAoCiAgICAi4pqg77iPICAiLCBtYXhfcGN0LCAiJSBvZiBjZWxscyBtYXBwZWQgdG8gJyIsIG1heF9zdGF0ZSwgIicuXG4iLAogICAgIiAgIFRoaXMgc3VnZ2VzdHMgYSBiYXRjaC9TQ1QgaXNzdWUuIFZlcmlmeSBwZXItY2VsbC1saW5lIFNDVCByYW4gY29ycmVjdGx5XG4iLAogICAgIiAgIGFuZCB0aGF0IGNvbW1vbl9mZWF0dXJlcyBjb250YWluIGRpZmZlcmVudGlhdGlvbiBnZW5lcywgbm90IGJhdGNoIGdlbmVzLiIKICApKQp9IGVsc2UgewogIGNhdCgiXG7inIUgU3RhdGUgZGlzdHJpYnV0aW9uIGxvb2tzIGRpdmVyc2Ug4oCUIHByb2plY3Rpb24gYXBwZWFycyB1bmJpYXNlZFxuIikKICBjYXQoIiAgIE1vc3QgY29tbW9uIHN0YXRlOiIsIG1heF9zdGF0ZSwgIigiLCBtYXhfcGN0LCAiJSBvZiBjZWxscylcbiIpCn0KCmBgYAoKCiMgVmlzdWFsaXNlIFByb2plY3Rpb24gb24gUmVmZXJlbmNlIFVNQVAKCiMjIFJlZmVyZW5jZSArIE1hbGlnbmFudCBPdmVybGF5IChQc2V1ZG90aW1lKQoKYGBge3IgcGxvdC1wc2V1ZG90aW1lLW92ZXJsYXksIGZpZy53aWR0aD0xNCwgZmlnLmhlaWdodD02fQoKIyBDb2VyY2UgcHNldWRvdGltZSBmcm9tIGNoYXJhY3RlciB0byBudW1lcmljIChTZXVyYXQgdHJhbnNmZXIgcXVpcmspCm1hcHBlZF9NYWxpZ25hbnRDRDRUJHByZWRpY3RlZC5wc2V1ZG90aW1lIDwtIGFzLm51bWVyaWMoCiAgbWFwcGVkX01hbGlnbmFudENENFQkcHJlZGljdGVkLnBzZXVkb3RpbWUKKQoKIyBWZXJpZnkKY2F0KCJDbGFzczoiLCBjbGFzcyhtYXBwZWRfTWFsaWduYW50Q0Q0VCRwcmVkaWN0ZWQucHNldWRvdGltZSksICJcbiIpCmNhdCgiUmFuZ2U6IiwgcmFuZ2UobWFwcGVkX01hbGlnbmFudENENFQkcHJlZGljdGVkLnBzZXVkb3RpbWUsIG5hLnJtID0gVFJVRSksICJcbiIpCgoKCgpyZWZfdW1hcCA8LSBkYXRhLmZyYW1lKAogIEVtYmVkZGluZ3MocmVmZXJlbmNlX2ludGVncmF0ZWQsICJ1bWFwIiksCiAgbDIgICAgICAgICA9IHJlZmVyZW5jZV9pbnRlZ3JhdGVkJHByZWRpY3RlZC5jZWxsdHlwZS5sMiwKICBwc2V1ZG90aW1lID0gcmVmZXJlbmNlX2ludGVncmF0ZWQkbW9ub2NsZTNfcHNldWRvdGltZSwKICB0eXBlICAgICAgID0gIlJlZmVyZW5jZSIKKQpjb2xuYW1lcyhyZWZfdW1hcClbMToyXSA8LSBjKCJVTUFQXzEiLCAiVU1BUF8yIikKCnF1ZXJ5X3VtYXAgPC0gZGF0YS5mcmFtZSgKICBFbWJlZGRpbmdzKG1hcHBlZF9NYWxpZ25hbnRDRDRULCAicmVmLnVtYXAiKSwKICBwc2V1ZG90aW1lID0gbWFwcGVkX01hbGlnbmFudENENFQkcHJlZGljdGVkLnBzZXVkb3RpbWUsICAgIyBudW1lcmljIGFmdGVyIGZpeAogIGNlbGxfbGluZSAgPSBtYXBwZWRfTWFsaWduYW50Q0Q0VCRjZWxsX2xpbmUsCiAgbDJfcSAgICAgICA9IG1hcHBlZF9NYWxpZ25hbnRDRDRUJHByZWRpY3RlZC5wcmVkaWN0ZWQuY2VsbHR5cGUubDIsCiAgdHlwZSAgICAgICA9ICJNYWxpZ25hbnQiCikKY29sbmFtZXMocXVlcnlfdW1hcClbMToyXSA8LSBjKCJVTUFQXzEiLCAiVU1BUF8yIikKCiMg4pSA4pSAIENlbGwgbGluZSBwYWxldHRlIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApjZWxsX2xpbmVfcGFsZXR0ZSA8LSBjb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwoOCwgIkRhcmsyIikpKAogIGxlbmd0aCh1bmlxdWUocXVlcnlfdW1hcCRjZWxsX2xpbmUpKQopCm5hbWVzKGNlbGxfbGluZV9wYWxldHRlKSA8LSBzb3J0KHVuaXF1ZShxdWVyeV91bWFwJGNlbGxfbGluZSkpCgphbGxfbDJfbGFiZWxzICA8LSB1bmlxdWUoYyhhcy5jaGFyYWN0ZXIocmVmX3VtYXAkbDIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLmNoYXJhY3RlcihxdWVyeV91bWFwJGwyX3EpKSkKYXppbXV0aF9sMl9jb2xvcnMgPC0gZXh0ZW5kX3BhbGV0dGUoYXppbXV0aF9sMl9jb2xvcnMsIGFsbF9sMl9sYWJlbHMpCgojIOKUgOKUgCBQbG90IDE6IFJlZmVyZW5jZSBncmV5LCBtYWxpZ25hbnQgY29sb3VyZWQgYnkgcHNldWRvdGltZSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKcDEgPC0gZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHJlZl91bWFwLAogICAgICAgICAgICAgYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIpLAogICAgICAgICAgICAgY29sb3IgPSByZWZlcmVuY2VfY29sb3IsIHNpemUgPSAwLjQsIGFscGhhID0gMC42KSArCiAgZ2VvbV9wb2ludChkYXRhID0gcXVlcnlfdW1hcCAlPiUgZmlsdGVyKGlzLmZpbml0ZShwc2V1ZG90aW1lKSksCiAgICAgICAgICAgICBhZXMoeCA9IFVNQVBfMSwgeSA9IFVNQVBfMiwgY29sb3IgPSBwc2V1ZG90aW1lKSwKICAgICAgICAgICAgIHNpemUgPSAxLjIsIGFscGhhID0gMC45KSArCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKG9wdGlvbiA9ICJwbGFzbWEiLCBuYW1lID0gIlBzZXVkb3RpbWUiLAogICAgICAgICAgICAgICAgICAgICAgICBuYS52YWx1ZSA9ICJncmV5NDAiKSArCiAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAxMSkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpKSArCiAgZ2d0aXRsZSgiTWFsaWduYW50IENENFQgUHJvamVjdGVkIG9udG8gUmVmZXJlbmNlXG4oQ29sb3VyZWQgYnkgdHJhbnNmZXJyZWQgcHNldWRvdGltZSkiKQoKIyDilIDilIAgUGxvdCAyOiBSZWZlcmVuY2UgY29sb3VyZWQgYnkgQXppbXV0aCBsMiwgbWFsaWduYW50IGNlbGxzIGluIHJlZCDilIDilIDilIDilIDilIDilIAKcDIgPC0gZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHJlZl91bWFwLAogICAgICAgICAgICAgYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIsIGNvbG9yID0gbDIpLAogICAgICAgICAgICAgc2l6ZSA9IDAuNCwgYWxwaGEgPSAwLjcpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYXppbXV0aF9sMl9jb2xvcnMsCiAgICAgICAgICAgICAgICAgICAgIG5hbWUgICA9ICJBemltdXRoIGwyXG4ocmVmZXJlbmNlKSIsCiAgICAgICAgICAgICAgICAgICAgIG5hLnZhbHVlID0gImdyZXk2MCIpICsKICBnZW9tX3BvaW50KGRhdGEgPSBxdWVyeV91bWFwLAogICAgICAgICAgICAgYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIpLAogICAgICAgICAgICAgY29sb3IgPSBtYWxpZ25hbnRfY29sb3IsIHNpemUgPSAxLjAsIGFscGhhID0gMC44LCBzaGFwZSA9IDE2KSArCiAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAxMSkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC40LCAiY20iKSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpICsKICBnZ3RpdGxlKCJSZWZlcmVuY2UgQXppbXV0aCBsMiAoY29sb3VyKVxuKyBNYWxpZ25hbnQgQ2VsbHMgKHJlZCBvdmVybGF5KSIpCgpwMSB8IHAyCmBgYAoKIyMgQXppbXV0aCBsMiBBbm5vdGF0aW9uIE92ZXJsYXkKCmBgYHtyIHBsb3QtYXppbXV0aC1vdmVybGF5LCBmaWcud2lkdGg9MTQsIGZpZy5oZWlnaHQ9Nn0KcDMgPC0gZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHJlZl91bWFwLAogICAgICAgICAgICAgYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIpLAogICAgICAgICAgICAgY29sb3IgPSByZWZlcmVuY2VfY29sb3IsIHNpemUgPSAwLjQsIGFscGhhID0gMC42KSArCiAgZ2VvbV9wb2ludChkYXRhID0gcXVlcnlfdW1hcCwKICAgICAgICAgICAgIGFlcyh4ID0gVU1BUF8xLCB5ID0gVU1BUF8yLCBjb2xvciA9IGwyX3EpLAogICAgICAgICAgICAgc2l6ZSA9IDEuMiwgYWxwaGEgPSAwLjkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYXppbXV0aF9sMl9jb2xvcnMsCiAgICAgICAgICAgICAgICAgICAgIG5hbWUgICA9ICJBemltdXRoIGwyXG4odHJhbnNmZXJyZWQpIiwKICAgICAgICAgICAgICAgICAgICAgbmEudmFsdWUgPSAiZ3JleTQwIikgKwogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMTEpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKSkgKwogIGdndGl0bGUoIk1hbGlnbmFudCBDRDRUIOKAlCBUcmFuc2ZlcnJlZCBBemltdXRoIGwyIExhYmVscyIpCgpwNCA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gcmVmX3VtYXAsCiAgICAgICAgICAgICBhZXMoeCA9IFVNQVBfMSwgeSA9IFVNQVBfMiksCiAgICAgICAgICAgICBjb2xvciA9IHJlZmVyZW5jZV9jb2xvciwgc2l6ZSA9IDAuNCwgYWxwaGEgPSAwLjUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBxdWVyeV91bWFwLAogICAgICAgICAgICAgYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIsIGNvbG9yID0gY2VsbF9saW5lKSwKICAgICAgICAgICAgIHNpemUgPSAxLjAsIGFscGhhID0gMC45KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNlbGxfbGluZV9wYWxldHRlLCBuYW1lID0gIkNlbGwgbGluZSIpICsKICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDExKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIikpICsKICBnZ3RpdGxlKCJNYWxpZ25hbnQgQ0Q0VCBwZXIgQ2VsbCBMaW5lIikKCnAzIHwgcDQKYGBgCgojIyBQZXIgQ2VsbCBMaW5lIEZhY2V0IOKAlCBTdGF0ZSBNYXBwaW5nCgpgYGB7ciBwbG90LXBlci1jZWxsbGluZSwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTZ9CmdncGxvdCgpICsKICBnZW9tX3BvaW50KGRhdGEgPSByZWZfdW1hcCwKICAgICAgICAgICAgIGFlcyh4ID0gVU1BUF8xLCB5ID0gVU1BUF8yKSwKICAgICAgICAgICAgIGNvbG9yID0gImdyZXk2MCIsIHNpemUgPSAwLjMsIGFscGhhID0gMC41KSArCiAgZ2VvbV9wb2ludChkYXRhID0gcXVlcnlfdW1hcCAlPiUgZmlsdGVyKGlzLmZpbml0ZShwc2V1ZG90aW1lKSksCiAgICAgICAgICAgICBhZXMoeCA9IFVNQVBfMSwgeSA9IFVNQVBfMiwgY29sb3IgPSBwc2V1ZG90aW1lKSwKICAgICAgICAgICAgIHNpemUgPSAwLjksIGFscGhhID0gMC44NSkgKwogIGZhY2V0X3dyYXAofiBjZWxsX2xpbmUsIG5jb2wgPSA0KSArCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKG9wdGlvbiA9ICJwbGFzbWEiLCBuYW1lID0gIlBzZXVkb3RpbWUiLAogICAgICAgICAgICAgICAgICAgICAgICBuYS52YWx1ZSA9ICJncmV5NjAiKSArCiAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAxMCkgKwogIHRoZW1lKHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjRThGNEZEIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIikpICsKICBnZ3RpdGxlKCJQZXIgQ2VsbCBMaW5lOiBQcm9qZWN0aW9uIG9udG8gUmVmZXJlbmNlIFVNQVAgKFBzZXVkb3RpbWUpIikKYGBgCgoKIyBRdWFudGlmaWNhdGlvbiDigJQgU3RhdGUgQXNzaWdubWVudAoKIyMgQXNzaWduIEVhY2ggTWFsaWduYW50IENlbGwgdG8gYSBSZWZlcmVuY2UgU3RhdGUKCmBgYHtyIHN0YXRlLWFzc2lnbm1lbnR9CiMg4pSA4pSAIHBzZXVkb3RpbWUgYmlucyBiYXNlZCBvbiByZWZlcmVuY2UgcXVhbnRpbGVzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApwdF92YWxzICAgPC0gcmVmZXJlbmNlX2ludGVncmF0ZWQkbW9ub2NsZTNfcHNldWRvdGltZQpwdF92YWxzICAgPC0gcHRfdmFsc1tpcy5maW5pdGUocHRfdmFscyldCnB0X2JyZWFrcyA8LSBxdWFudGlsZShwdF92YWxzLCBwcm9icyA9IGMoMCwgMS8zLCAyLzMsIDEpKQoKbWFwcGVkX01hbGlnbmFudENENFQkc3RhdGVfYXppbXV0aF9sMiAgPC0gbWFwcGVkX01hbGlnbmFudENENFQkcHJlZGljdGVkLnByZWRpY3RlZC5jZWxsdHlwZS5sMgptYXBwZWRfTWFsaWduYW50Q0Q0VCRzdGF0ZV9yZWZfY2x1c3RlciA8LSBtYXBwZWRfTWFsaWduYW50Q0Q0VCRwcmVkaWN0ZWQuc2V1cmF0X2NsdXN0ZXJzCm1hcHBlZF9NYWxpZ25hbnRDRDRUJHBzZXVkb3RpbWVfdmFsdWUgIDwtIG1hcHBlZF9NYWxpZ25hbnRDRDRUJHByZWRpY3RlZC5wc2V1ZG90aW1lICAjIG51bWVyaWMKCm1hcHBlZF9NYWxpZ25hbnRDRDRUJHBzZXVkb3RpbWVfYmluIDwtIGN1dCgKICBtYXBwZWRfTWFsaWduYW50Q0Q0VCRwc2V1ZG90aW1lX3ZhbHVlLAogIGJyZWFrcyAgICAgICAgID0gcHRfYnJlYWtzLAogIGxhYmVscyAgICAgICAgID0gYygiRWFybHkgKFRuYWl2ZS1saWtlKSIsICJNaWQgKFRDTS9URU0tbGlrZSkiLCAiTGF0ZSAoVGVtcmEtbGlrZSkiKSwKICBpbmNsdWRlLmxvd2VzdCA9IFRSVUUKKQoKY2F0KCI9PT0gU3RhdGUgYXNzaWdubWVudCBjb21wbGV0ZSA9PT1cbiIpCmNhdCgiXG5BemltdXRoIGwyIHN0YXRlIChQUklNQVJZKTpcbiIpCnByaW50KHRhYmxlKG1hcHBlZF9NYWxpZ25hbnRDRDRUJHN0YXRlX2F6aW11dGhfbDIpKQpjYXQoIlxuUmVmZXJlbmNlIGNsdXN0ZXIgKGNyb3NzLWNoZWNrKTpcbiIpCnByaW50KHRhYmxlKG1hcHBlZF9NYWxpZ25hbnRDRDRUJHN0YXRlX3JlZl9jbHVzdGVyKSkKY2F0KCJcblBzZXVkb3RpbWUgYmluOlxuIikKcHJpbnQodGFibGUobWFwcGVkX01hbGlnbmFudENENFQkcHNldWRvdGltZV9iaW4pKQpgYGAKCiMjIFF1YW50aWZpY2F0aW9uIFRhYmxlcwoKYGBge3IgcXVhbnRpZnktc3RhdGVzLCBmaWcud2lkdGg9MTQsIGZpZy5oZWlnaHQ9Nn0Kc3RhdGVfc3VtbWFyeSA8LSBtYXBwZWRfTWFsaWduYW50Q0Q0VEBtZXRhLmRhdGEgJT4lCiAgY291bnQoc3RhdGVfYXppbXV0aF9sMiwgbmFtZSA9ICJuX2NlbGxzIikgJT4lCiAgbXV0YXRlKHBjdCA9IHJvdW5kKDEwMCAqIG5fY2VsbHMgLyBzdW0obl9jZWxscyksIDEpKSAlPiUKICBhcnJhbmdlKGRlc2Mobl9jZWxscykpCgpjYXQoIj09PSBPdmVyYWxsIE1hbGlnbmFudCBDRDRUIFN0YXRlIERpc3RyaWJ1dGlvbiA9PT1cbiIpCnByaW50KHN0YXRlX3N1bW1hcnkpCgpzdGF0ZV9wZXJfbGluZSA8LSBtYXBwZWRfTWFsaWduYW50Q0Q0VEBtZXRhLmRhdGEgJT4lCiAgY291bnQoY2VsbF9saW5lLCBzdGF0ZV9hemltdXRoX2wyLCBuYW1lID0gIm5fY2VsbHMiKSAlPiUKICBncm91cF9ieShjZWxsX2xpbmUpICU+JQogIG11dGF0ZShwY3QgPSByb3VuZCgxMDAgKiBuX2NlbGxzIC8gc3VtKG5fY2VsbHMpLCAxKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIGFycmFuZ2UoY2VsbF9saW5lLCBkZXNjKG5fY2VsbHMpKQoKY2F0KCJcbj09PSBTdGF0ZSBEaXN0cmlidXRpb24gcGVyIENlbGwgTGluZSA9PT1cbiIpCnByaW50KHN0YXRlX3Blcl9saW5lLCBuID0gSW5mKQoKY2x1c3Rlcl9zdW1tYXJ5IDwtIG1hcHBlZF9NYWxpZ25hbnRDRDRUQG1ldGEuZGF0YSAlPiUKICBjb3VudChzdGF0ZV9yZWZfY2x1c3RlciwgbmFtZSA9ICJuX2NlbGxzIikgJT4lCiAgbXV0YXRlKHBjdCA9IHJvdW5kKDEwMCAqIG5fY2VsbHMgLyBzdW0obl9jZWxscyksIDEpKSAlPiUKICBhcnJhbmdlKGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHN0YXRlX3JlZl9jbHVzdGVyKSkpCgpjYXQoIlxuPT09IFJlZmVyZW5jZSBDbHVzdGVyIERpc3RyaWJ1dGlvbiAoY3Jvc3MtY2hlY2spID09PVxuIikKcHJpbnQoY2x1c3Rlcl9zdW1tYXJ5KQoKcHRfYmluX3N1bW1hcnkgPC0gbWFwcGVkX01hbGlnbmFudENENFRAbWV0YS5kYXRhICU+JQogIGNvdW50KHBzZXVkb3RpbWVfYmluLCBuYW1lID0gIm5fY2VsbHMiKSAlPiUKICBtdXRhdGUocGN0ID0gcm91bmQoMTAwICogbl9jZWxscyAvIHN1bShuX2NlbGxzKSwgMSkpCgpjYXQoIlxuPT09IFBzZXVkb3RpbWUgQmluIFN1bW1hcnkgPT09XG4iKQpwcmludChwdF9iaW5fc3VtbWFyeSkKYGBgCgojIyBCYXIgQ2hhcnQg4oCUIFN0YXRlIFByb3BvcnRpb25zCgpgYGB7ciBiYXJwbG90LXN0YXRlcywgZmlnLndpZHRoPTE0LCBmaWcuaGVpZ2h0PTEwfQpwX2Jhcl9vdmVyYWxsIDwtIGdncGxvdChzdGF0ZV9wZXJfbGluZSwKICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gY2VsbF9saW5lLCB5ID0gcGN0LCBmaWxsID0gc3RhdGVfYXppbXV0aF9sMikpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJzdGFjayIsIGNvbG9yID0gIndoaXRlIiwgbGluZXdpZHRoID0gMC4zKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGlmZWxzZShwY3QgPj0gNSwgcGFzdGUwKHBjdCwgIiUiKSwgIiIpKSwKICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSksCiAgICAgICAgICAgIHNpemUgPSAzLCBjb2xvciA9ICJ3aGl0ZSIsIGZvbnRmYWNlID0gImJvbGQiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYXppbXV0aF9sMl9jb2xvcnMsIG5hLnZhbHVlID0gImdyZXk3MCIsCiAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJBemltdXRoIGwyXG5zdGF0ZSIpICsKICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDExKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0MCwgaGp1c3QgPSAxKSwKICAgICAgICBwbG90LnRpdGxlICA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjUsICJjbSIpKSArCiAgbGFicyh0aXRsZSA9ICJNYWxpZ25hbnQgQ0Q0VCDigJQgU3RhdGUgQ29tcG9zaXRpb24gcGVyIENlbGwgTGluZVxuKEF6aW11dGggbDIgdHJhbnNmZXJyZWQgbGFiZWxzKSIsCiAgICAgICB4ID0gIkNlbGwgTGluZSIsIHkgPSAiJSBDZWxscyIpCgpwdF9iaW5fbGluZSA8LSBtYXBwZWRfTWFsaWduYW50Q0Q0VEBtZXRhLmRhdGEgJT4lCiAgZmlsdGVyKCFpcy5uYShwc2V1ZG90aW1lX2JpbikpICU+JQogIGNvdW50KGNlbGxfbGluZSwgcHNldWRvdGltZV9iaW4pICU+JQogIGdyb3VwX2J5KGNlbGxfbGluZSkgJT4lCiAgbXV0YXRlKHBjdCA9IHJvdW5kKDEwMCAqIG4gLyBzdW0obiksIDEpKSAlPiUKICB1bmdyb3VwKCkKCmJpbl9jb2xvcnMgPC0gYygKICAiRWFybHkgKFRuYWl2ZS1saWtlKSIgPSAiIzQ1NzVCNCIsCiAgIk1pZCAoVENNL1RFTS1saWtlKSIgID0gIiNGRUUwOTAiLAogICJMYXRlIChUZW1yYS1saWtlKSIgICA9ICIjRDczMDI3IgopCgpwX2Jhcl9iaW5zIDwtIGdncGxvdChwdF9iaW5fbGluZSwKICAgICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gY2VsbF9saW5lLCB5ID0gcGN0LCBmaWxsID0gcHNldWRvdGltZV9iaW4pKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAic3RhY2siLCBjb2xvciA9ICJ3aGl0ZSIsIGxpbmV3aWR0aCA9IDAuMykgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBpZmVsc2UocGN0ID49IDgsIHBhc3RlMChwY3QsICIlIiksICIiKSksCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpLAogICAgICAgICAgICBzaXplID0gMywgY29sb3IgPSAid2hpdGUiLCBmb250ZmFjZSA9ICJib2xkIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGJpbl9jb2xvcnMsIG5hbWUgPSAiUHNldWRvdGltZVxuQmluIikgKwogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMTEpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQwLCBoanVzdCA9IDEpLAogICAgICAgIHBsb3QudGl0bGUgID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKSkgKwogIGxhYnModGl0bGUgPSAiTWFsaWduYW50IENENFQg4oCUIFBzZXVkb3RpbWUgQmluIERpc3RyaWJ1dGlvbiBwZXIgQ2VsbCBMaW5lIiwKICAgICAgIHggPSAiQ2VsbCBMaW5lIiwgeSA9ICIlIENlbGxzIikKCnBfYmFyX292ZXJhbGwgLyBwX2Jhcl9iaW5zCmBgYAoKIyMgSGVhdG1hcCDigJQgU3RhdGUgUHJvcG9ydGlvbnMgQWNyb3NzIENlbGwgTGluZXMKCmBgYHtyIGhlYXRtYXAtc3RhdGVzLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9Nn0KbGlicmFyeShwaGVhdG1hcCkKCmhlYXRtYXBfZGYgPC0gc3RhdGVfcGVyX2xpbmUgJT4lCiAgc2VsZWN0KGNlbGxfbGluZSwgc3RhdGVfYXppbXV0aF9sMiwgcGN0KSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tICA9IHN0YXRlX2F6aW11dGhfbDIsCiAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSBwY3QsCiAgICAgICAgICAgICAgdmFsdWVzX2ZpbGwgPSAwKQoKaGVhdG1hcF9tYXQgICAgICAgICAgICAgPC0gYXMubWF0cml4KGhlYXRtYXBfZGZbLCAtMV0pCnJvd25hbWVzKGhlYXRtYXBfbWF0KSAgIDwtIGhlYXRtYXBfZGYkY2VsbF9saW5lCgpwaGVhdG1hcCgKICBoZWF0bWFwX21hdCwKICBjb2xvciAgICAgICAgICAgID0gY29sb3JSYW1wUGFsZXR0ZShjKCJ3aGl0ZSIsICIjRkVFMDkwIiwgIiNENzMwMjciKSkoNTApLAogIGRpc3BsYXlfbnVtYmVycyAgPSBUUlVFLAogIG51bWJlcl9mb3JtYXQgICAgPSAiJS4xZiUlIiwKICBmb250c2l6ZV9udW1iZXIgID0gOCwKICBmb250c2l6ZV9yb3cgICAgID0gMTAsCiAgZm9udHNpemVfY29sICAgICA9IDksCiAgYW5nbGVfY29sICAgICAgICA9IDQ1LAogIGNsdXN0ZXJfcm93cyAgICAgPSBUUlVFLAogIGNsdXN0ZXJfY29scyAgICAgPSBUUlVFLAogIG1haW4gICAgICAgICAgICAgPSAiJSBNYWxpZ25hbnQgQ2VsbHMgcGVyIFN0YXRlIChBemltdXRoIGwyKVxuQ2x1c3RlcmVkIGJ5IGNlbGwgbGluZSBzaW1pbGFyaXR5IiwKICBib3JkZXJfY29sb3IgICAgID0gIndoaXRlIgopCmBgYAoKCiMgUHNldWRvdGltZSBBbmFseXNpcyBvZiBNYWxpZ25hbnQgQ2VsbHMKCiMjIFBzZXVkb3RpbWUgRGlzdHJpYnV0aW9uCgpgYGB7ciBwc2V1ZG90aW1lLWRpc3RyaWJ1dGlvbiwgZmlnLndpZHRoPTE0LCBmaWcuaGVpZ2h0PTZ9CnJlZl9wdCA8LSBkYXRhLmZyYW1lKAogIHBzZXVkb3RpbWUgPSByZWZlcmVuY2VfaW50ZWdyYXRlZCRtb25vY2xlM19wc2V1ZG90aW1lWwogICAgaXMuZmluaXRlKHJlZmVyZW5jZV9pbnRlZ3JhdGVkJG1vbm9jbGUzX3BzZXVkb3RpbWUpCiAgXSwKICBzb3VyY2UgPSAiSGVhbHRoeSByZWZlcmVuY2UiCikKCm1hbF9wdCA8LSBkYXRhLmZyYW1lKAogIHBzZXVkb3RpbWUgPSBtYXBwZWRfTWFsaWduYW50Q0Q0VCRwc2V1ZG90aW1lX3ZhbHVlWwogICAgaXMuZmluaXRlKG1hcHBlZF9NYWxpZ25hbnRDRDRUJHBzZXVkb3RpbWVfdmFsdWUpCiAgXSwKICBzb3VyY2UgPSAiTWFsaWduYW50IENENFQiCikKCnB0X2NvbWJpbmVkIDwtIGJpbmRfcm93cyhyZWZfcHQsIG1hbF9wdCkKCnBfZGVuc2l0eSA8LSBnZ3Bsb3QocHRfY29tYmluZWQsIGFlcyh4ID0gcHNldWRvdGltZSwgZmlsbCA9IHNvdXJjZSkpICsKICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjY1LCBhZGp1c3QgPSAxLjIpICsKICBzY2FsZV9maWxsX21hbnVhbCgKICAgIHZhbHVlcyA9IGMoIkhlYWx0aHkgcmVmZXJlbmNlIiA9ICIjNDU3NUI0IiwgIk1hbGlnbmFudCBDRDRUIiA9IG1hbGlnbmFudF9jb2xvciksCiAgICBuYW1lID0gIiIKICApICsKICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDEyKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIikpICsKICBsYWJzKHRpdGxlID0gIlBzZXVkb3RpbWUgRGlzdHJpYnV0aW9uOiBIZWFsdGh5IFJlZmVyZW5jZSB2cyBNYWxpZ25hbnQgQ0Q0VCIsCiAgICAgICBzdWJ0aXRsZSA9ICJQZWFrIHNoaWZ0IGluZGljYXRlcyBkaWZmZXJlbnRpYXRpb24gYXJyZXN0IHBvaW50IiwKICAgICAgIHggPSAiTW9ub2NsZTMgUHNldWRvdGltZSIsIHkgPSAiRGVuc2l0eSIpCgptYWxfcHRfbGluZSA8LSBtYXBwZWRfTWFsaWduYW50Q0Q0VEBtZXRhLmRhdGEgJT4lCiAgZmlsdGVyKGlzLmZpbml0ZShwc2V1ZG90aW1lX3ZhbHVlKSkgJT4lCiAgc2VsZWN0KGNlbGxfbGluZSwgcHNldWRvdGltZV92YWx1ZSkKCnBfcmlkZ2VfbGluZXMgPC0gZ2dwbG90KG1hbF9wdF9saW5lLAogICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBwc2V1ZG90aW1lX3ZhbHVlLCB5ID0gY2VsbF9saW5lLCBmaWxsID0gY2VsbF9saW5lKSkgKwogIGdlb21fZGVuc2l0eV9yaWRnZXMoYWxwaGEgPSAwLjgwLCBzY2FsZSA9IDEuMywgcmVsX21pbl9oZWlnaHQgPSAwLjAxLAogICAgICAgICAgICAgICAgICAgICAgcXVhbnRpbGVfbGluZXMgPSBUUlVFLCBxdWFudGlsZXMgPSAyKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY2VsbF9saW5lX3BhbGV0dGUpICsKICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDExKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpKSArCiAgbGFicyh0aXRsZSA9ICJQc2V1ZG90aW1lIERpc3RyaWJ1dGlvbiBwZXIgQ2VsbCBMaW5lIiwKICAgICAgIHN1YnRpdGxlID0gIlZlcnRpY2FsIGxpbmUgPSBtZWRpYW4iLAogICAgICAgeCA9ICJQc2V1ZG90aW1lIiwgeSA9ICIiKQoKcF9kZW5zaXR5IHwgcF9yaWRnZV9saW5lcwpgYGAKCiMjIFBzZXVkb3RpbWUgU3VtbWFyeSBTdGF0aXN0aWNzIFRhYmxlCgpgYGB7ciBwc2V1ZG90aW1lLXN0YXRzfQpwdF9zdGF0cyA8LSBtYXBwZWRfTWFsaWduYW50Q0Q0VEBtZXRhLmRhdGEgJT4lCiAgZmlsdGVyKGlzLmZpbml0ZShwc2V1ZG90aW1lX3ZhbHVlKSkgJT4lCiAgZ3JvdXBfYnkoY2VsbF9saW5lKSAlPiUKICBzdW1tYXJpc2UoCiAgICBuX2NlbGxzICAgPSBuKCksCiAgICBtZWFuX3B0ICAgPSByb3VuZChtZWFuKHBzZXVkb3RpbWVfdmFsdWUpLCAzKSwKICAgIG1lZGlhbl9wdCA9IHJvdW5kKG1lZGlhbihwc2V1ZG90aW1lX3ZhbHVlKSwgMyksCiAgICBzZF9wdCAgICAgPSByb3VuZChzZChwc2V1ZG90aW1lX3ZhbHVlKSwgMyksCiAgICBxMjVfcHQgICAgPSByb3VuZChxdWFudGlsZShwc2V1ZG90aW1lX3ZhbHVlLCAwLjI1KSwgMyksCiAgICBxNzVfcHQgICAgPSByb3VuZChxdWFudGlsZShwc2V1ZG90aW1lX3ZhbHVlLCAwLjc1KSwgMyksCiAgICBwY3RfZWFybHkgPSByb3VuZCgxMDAgKiBtZWFuKHBzZXVkb3RpbWVfdmFsdWUgPCBwdF9icmVha3NbMl0sIG5hLnJtID0gVFJVRSksIDEpLAogICAgcGN0X21pZCAgID0gcm91bmQoMTAwICogbWVhbihwc2V1ZG90aW1lX3ZhbHVlID49IHB0X2JyZWFrc1syXSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwc2V1ZG90aW1lX3ZhbHVlIDwgcHRfYnJlYWtzWzNdLCBuYS5ybSA9IFRSVUUpLCAxKSwKICAgIHBjdF9sYXRlICA9IHJvdW5kKDEwMCAqIG1lYW4ocHNldWRvdGltZV92YWx1ZSA+PSBwdF9icmVha3NbM10sIG5hLnJtID0gVFJVRSksIDEpCiAgKSAlPiUKICBhcnJhbmdlKG1lZGlhbl9wdCkKCmNhdCgiPT09IFBzZXVkb3RpbWUgU3RhdGlzdGljcyBwZXIgQ2VsbCBMaW5lID09PVxuIikKcHJpbnQocHRfc3RhdHMsIG4gPSBJbmYpCgpyZWZfc3RhdHMgPC0gcmVmZXJlbmNlX2ludGVncmF0ZWRAbWV0YS5kYXRhICU+JQogIGZpbHRlcihpcy5maW5pdGUobW9ub2NsZTNfcHNldWRvdGltZSksICFpcy5uYShwcmVkaWN0ZWQuY2VsbHR5cGUubDIpKSAlPiUKICBncm91cF9ieShwcmVkaWN0ZWQuY2VsbHR5cGUubDIpICU+JQogIHN1bW1hcmlzZSgKICAgIG5fY2VsbHMgICA9IG4oKSwKICAgIG1lYW5fcHQgICA9IHJvdW5kKG1lYW4obW9ub2NsZTNfcHNldWRvdGltZSksIDMpLAogICAgbWVkaWFuX3B0ID0gcm91bmQobWVkaWFuKG1vbm9jbGUzX3BzZXVkb3RpbWUpLCAzKQogICkgJT4lCiAgYXJyYW5nZShtZWRpYW5fcHQpCgpjYXQoIlxuPT09IFJlZmVyZW5jZSBQc2V1ZG90aW1lIHBlciBBemltdXRoIGwyIFN0YXRlIChmb3IgY29tcGFyaXNvbikgPT09XG4iKQpwcmludChyZWZfc3RhdHMpCmBgYAoKCiMgSW50ZWdyYXRlZCBTdW1tYXJ5IFZpc3VhbGlzYXRpb24KCiMjIEZvdXItUGFuZWwgU3VtbWFyeSBGaWd1cmUKCmBgYHtyIHN1bW1hcnktZmlndXJlLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9MTB9CnBfcmVmIDwtIERpbVBsb3QoCiAgcmVmZXJlbmNlX2ludGVncmF0ZWQsIGdyb3VwLmJ5ID0gInByZWRpY3RlZC5jZWxsdHlwZS5sMiIsCiAgcmVkdWN0aW9uID0gInVtYXAiLCBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwKICBsYWJlbC5zaXplID0gMywgcHQuc2l6ZSA9IDAuNAopICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYXppbXV0aF9sMl9jb2xvcnMsIG5hLnZhbHVlID0gImdyZXk0MCIpICsKICBnZ3RpdGxlKCJBLiBSZWZlcmVuY2UgQ0Q0KyBUIENlbGxzXG4oQXppbXV0aCBsMiDigJQgUHJvbGlmZXJhdGluZyByZW1vdmVkKSIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTEsIGZhY2UgPSAiYm9sZCIpKSArCiAgTm9MZWdlbmQoKQoKcF9wdF9yZWYgPC0gRmVhdHVyZVBsb3QoCiAgcmVmZXJlbmNlX2ludGVncmF0ZWQsIGZlYXR1cmVzID0gIm1vbm9jbGUzX3BzZXVkb3RpbWUiLAogIHJlZHVjdGlvbiA9ICJ1bWFwIiwgY29scyA9IGMoImxpZ2h0Ymx1ZSIsInllbGxvdyIsInJlZCIpLCBwdC5zaXplID0gMC40CikgKwogIGdndGl0bGUoIkIuIFJlZmVyZW5jZSBQc2V1ZG90aW1lXG4oTmFpdmUg4oaSIFRlbXJhIGF4aXMpIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxMSwgZmFjZSA9ICJib2xkIikpCgpwX3Byb2ogPC0gZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHJlZl91bWFwLCBhZXMoeCA9IFVNQVBfMSwgeSA9IFVNQVBfMiksCiAgICAgICAgICAgICBjb2xvciA9ICJncmV5ODgiLCBzaXplID0gMC4zLCBhbHBoYSA9IDAuNikgKwogIGdlb21fcG9pbnQoZGF0YSA9IHF1ZXJ5X3VtYXAgJT4lIGZpbHRlcihpcy5maW5pdGUocHNldWRvdGltZSkpLAogICAgICAgICAgICAgYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIsIGNvbG9yID0gcHNldWRvdGltZSksCiAgICAgICAgICAgICBzaXplID0gMS4wLCBhbHBoYSA9IDAuODUpICsKICBzY2FsZV9jb2xvcl92aXJpZGlzX2Mob3B0aW9uID0gInBsYXNtYSIsIG5hbWUgPSAiUHNldWRvdGltZSIpICsKICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDEwKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDExLCBmYWNlID0gImJvbGQiKSkgKwogIGdndGl0bGUoIkMuIE1hbGlnbmFudCBDRDRUIFByb2plY3RlZFxuKHBzZXVkb3RpbWUgdHJhbnNmZXJyZWQpIikKCnRvcF9zdGF0ZXMgICA8LSBzdGF0ZV9zdW1tYXJ5ICU+JSBoZWFkKDgpICU+JSBwdWxsKHN0YXRlX2F6aW11dGhfbDIpCnN0YXRlX3Bsb3RfZGYgPC0gc3RhdGVfcGVyX2xpbmUgJT4lIGZpbHRlcihzdGF0ZV9hemltdXRoX2wyICVpbiUgdG9wX3N0YXRlcykKCnBfcXVhbnQgPC0gZ2dwbG90KHN0YXRlX3Bsb3RfZGYsCiAgICAgICAgICAgICAgICAgICBhZXMoeCA9IHJlb3JkZXIoY2VsbF9saW5lLCAtcGN0KSwgeSA9IHBjdCwKICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gc3RhdGVfYXppbXV0aF9sMikpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJzdGFjayIsIGNvbG9yID0gIndoaXRlIiwgbGluZXdpZHRoID0gMC4zKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYXppbXV0aF9sMl9jb2xvcnMsIG5hLnZhbHVlID0gImdyZXk0MCIsCiAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJBemltdXRoIGwyIikgKwogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMTApICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQwLCBoanVzdCA9IDEsIHNpemUgPSA5KSwKICAgICAgICBwbG90LnRpdGxlICA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDExLCBmYWNlID0gImJvbGQiKSwKICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNCwgImNtIiksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpKSArCiAgbGFicyh0aXRsZSA9ICJELiBTdGF0ZSBQcm9wb3J0aW9ucyBwZXIgQ2VsbCBMaW5lXG4oQXppbXV0aCBsMiB0cmFuc2ZlcnJlZCkiLAogICAgICAgeCA9ICIiLCB5ID0gIiUgQ2VsbHMiKQoKKHBfcmVmIHwgcF9wdF9yZWYpIC8gKHBfcHJvaiB8IHBfcXVhbnQpICsKICBwbG90X2Fubm90YXRpb24oCiAgICB0aXRsZSA9ICJNYWxpZ25hbnQgQ0Q0KyBUIENlbGwgRGlmZmVyZW50aWF0aW9uIFN0YXRlIE1hcHBpbmdcbihTw6l6YXJ5IFN5bmRyb21lIOKAlCBNb25vY2xlMyBSZWZlcmVuY2UgVHJhamVjdG9yeSkiLAogICAgdGhlbWUgPSB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTQsIGZhY2UgPSAiYm9sZCIpKQogICkKYGBgCgojIyBQc2V1ZG90aW1lIHZzIFN0YXRlIFZpb2xpbiAocHVibGljYXRpb24tcmVhZHkpCgpgYGB7ciBwc2V1ZG90aW1lLXZzLXN0YXRlLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD01fQptYWxfc3RhdGVfcHQgPC0gbWFwcGVkX01hbGlnbmFudENENFRAbWV0YS5kYXRhICU+JQogIGZpbHRlcihpcy5maW5pdGUocHNldWRvdGltZV92YWx1ZSksICFpcy5uYShzdGF0ZV9hemltdXRoX2wyKSkgJT4lCiAgbXV0YXRlKHN0YXRlID0gc3RhdGVfYXppbXV0aF9sMikKCnN0YXRlX29yZGVyX21hbCA8LSBtYWxfc3RhdGVfcHQgJT4lCiAgZ3JvdXBfYnkoc3RhdGUpICU+JQogIHN1bW1hcmlzZShtZWQgPSBtZWRpYW4ocHNldWRvdGltZV92YWx1ZSkpICU+JQogIGFycmFuZ2UobWVkKSAlPiUKICBwdWxsKHN0YXRlKQoKbWFsX3N0YXRlX3B0JHN0YXRlIDwtIGZhY3RvcihtYWxfc3RhdGVfcHQkc3RhdGUsIGxldmVscyA9IHN0YXRlX29yZGVyX21hbCkKCmdncGxvdChtYWxfc3RhdGVfcHQsIGFlcyh4ID0gc3RhdGUsIHkgPSBwc2V1ZG90aW1lX3ZhbHVlLCBmaWxsID0gc3RhdGUpKSArCiAgZ2VvbV92aW9saW4oc2NhbGUgPSAid2lkdGgiLCBhbHBoYSA9IDAuOCwgdHJpbSA9IFRSVUUpICsKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjEsIGZpbGwgPSAid2hpdGUiLCBvdXRsaWVyLnNpemUgPSAwLjMpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBhemltdXRoX2wyX2NvbG9ycywgbmEudmFsdWUgPSAiZ3JleTcwIikgKwogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMTEpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQwLCBoanVzdCA9IDEsIHNpemUgPSA5KSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIikpICsKICBsYWJzKHRpdGxlID0gIlBzZXVkb3RpbWUgb2YgTWFsaWduYW50IENENFQgcGVyIFRyYW5zZmVycmVkIFN0YXRlXG4oQXppbXV0aCBsMiBsYWJlbHMpIiwKICAgICAgIHggPSAiVHJhbnNmZXJyZWQgRGlmZmVyZW50aWF0aW9uIFN0YXRlIiwKICAgICAgIHkgPSAiVHJhbnNmZXJyZWQgUHNldWRvdGltZSIpCmBgYAoKCiMgU2F2ZSBPdXRwdXRzCgpgYGB7ciBzYXZlLW91dHB1dHN9Cm91dF9kaXIgPC0gInJlc3VsdHMvTWFsaWduYW50Q0Q0VF9Nb25vY2xlM19wcm9qZWN0aW9uIgppZiAoIWRpci5leGlzdHMob3V0X2RpcikpIGRpci5jcmVhdGUob3V0X2RpciwgcmVjdXJzaXZlID0gVFJVRSkKCnNhdmVSRFMobWFwcGVkX01hbGlnbmFudENENFQsZmlsZS5wYXRoKG91dF9kaXIsICJNYWxpZ25hbnRDRDRUX21hcHBlZF9tb25vY2xlM19wc2V1ZG90aW1lX25vUHJvbGlmX3JlZi5yZHMiKSkKCndyaXRlLmNzdihzdGF0ZV9zdW1tYXJ5LAogICAgICAgICAgZmlsZS5wYXRoKG91dF9kaXIsICJzdGF0ZV9kaXN0cmlidXRpb25fb3ZlcmFsbC5jc3YiKSwKICAgICAgICAgIHJvdy5uYW1lcyA9IEZBTFNFKQp3cml0ZS5jc3Yoc3RhdGVfcGVyX2xpbmUsCiAgICAgICAgICBmaWxlLnBhdGgob3V0X2RpciwgInN0YXRlX2Rpc3RyaWJ1dGlvbl9wZXJfY2VsbGxpbmUuY3N2IiksCiAgICAgICAgICByb3cubmFtZXMgPSBGQUxTRSkKd3JpdGUuY3N2KHB0X3N0YXRzLAogICAgICAgICAgZmlsZS5wYXRoKG91dF9kaXIsICJwc2V1ZG90aW1lX3N0YXRzX3Blcl9jZWxsbGluZS5jc3YiKSwKICAgICAgICAgIHJvdy5uYW1lcyA9IEZBTFNFKQp3cml0ZS5jc3YobWFwcGVkX01hbGlnbmFudENENFRAbWV0YS5kYXRhLAogICAgICAgICAgZmlsZS5wYXRoKG91dF9kaXIsICJNYWxpZ25hbnRDRDRUX2Z1bGxfbWV0YWRhdGFfd2l0aF9wcm9qZWN0aW9uLmNzdiIpLAogICAgICAgICAgcm93Lm5hbWVzID0gVFJVRSkKCmNhdCgi4pyFIEFsbCBvdXRwdXRzIHNhdmVkIHRvOiIsIG91dF9kaXIsICJcbiIpCmNhdCgiXG5GaWxlcyBzYXZlZDpcbiIpCnByaW50KGxpc3QuZmlsZXMob3V0X2RpcikpCmBgYAoKCiMgU2Vzc2lvbiBJbmZvCgpgYGB7ciBzZXNzaW9uLWluZm99CgpzZXNzaW9uSW5mbygpCgpgYGAKCjwhLS0g4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQCiAgICAgSU5URVJQUkVUQVRJT04gR1VJREUKICAgICDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZAKCiAgSE9XIFRPIElOVEVSUFJFVCBZT1VSIFJFU1VMVFM6CiAg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACgogIDEuIFdIRVJFIERPIE1BTElHTkFOVCBDRUxMUyBQUk9KRUNUPwogICAgIExvb2sgYXQgUGFuZWwgQyBvZiB0aGUgc3VtbWFyeSBmaWd1cmUuIElmIG1hbGlnbmFudCBjZWxscyBjbHVzdGVyCiAgICAgcHJlZG9taW5hbnRseSBvdmVyOgogICAgICAgLSBUbmFpdmUvVENNIHRlcnJpdG9yeSDihpIgZWFybHkvY2VudHJhbCBtZW1vcnkgYXJyZXN0IChjb21tb24gaW4gU1MpCiAgICAgICAtIFRFTSB0ZXJyaXRvcnkgICAgICAgICDihpIgZWZmZWN0b3IgbWVtb3J5IHBoZW5vdHlwZQogICAgICAgLSBUZW1yYSB0ZXJyaXRvcnkgICAgICAg4oaSIGxhdGUgZWZmZWN0b3IvY3l0b3RveGljIHBoZW5vdHlwZQogICAgICAgLSBNaXhlZC9zcHJlYWQgICAgICAgICAg4oaSIGhldGVyb2dlbmVvdXMgcG9wdWxhdGlvbgoKICAyLiBQU0VVRE9USU1FIFZBTFVFUzoKICAgICBDb21wYXJlIG1hbGlnbmFudCBtZWRpYW4gcHNldWRvdGltZSB0byByZWZlcmVuY2UgdmFsdWVzIGZyb20gcmVmX3N0YXRzLgogICAgIElmIG1hbGlnbmFudCBtZWRpYW4g4omIIHJlZmVyZW5jZSBUQ00gbWVkaWFuIOKGkiBUQ00tbGlrZSBhcnJlc3QuCiAgICAgQSBsZWZ0LXNoaWZ0ZWQgZGlzdHJpYnV0aW9uIChsb3cgcHNldWRvdGltZSkgPSBtb3JlIG5haXZlLWxpa2UgY2VsbHMuCgogIDMuIENFTEwgTElORSBESUZGRVJFTkNFUzoKICAgICBUaGUgcGVyLWNlbGwtbGluZSBoZWF0bWFwIHJldmVhbHMgd2hldGhlciBkaWZmZXJlbnQgU8OpemFyeSBjZWxsIGxpbmVzCiAgICAgaGF2ZSBkaXN0aW5jdCBkaWZmZXJlbnRpYXRpb24gc3RhdGVzIOKAlCBiaW9sb2dpY2FsbHkgaW1wb3J0YW50IGFzCiAgICAgZGlmZmVyZW50IGxpbmVzIG1heSBtb2RlbCBkaWZmZXJlbnQgc3RhZ2VzIG9mIHRoZSBkaXNlYXNlLgoKICA0LiBTQU5JVFkgQ0hFQ0s6IElmID45MCUgb2YgY2VsbHMgc3RpbGwgbWFwIHRvIG9uZSBzdGF0ZSBhZnRlciBwZXItbGluZSBTQ1QsCiAgICAgaW52ZXN0aWdhdGU6CiAgICAgICBhLiBBcmUgdGhlIGNvbW1vbl9mZWF0dXJlcyAofjIwMDArIGdlbmVzKSBkaXZlcnNlIGFuZCBiaW9sb2dpY2FsbHkKICAgICAgICAgIG1lYW5pbmdmdWwgKENDUjcsIEdaTUssIEZPWFAzLCBUQ0Y3LCBTRUxMIOKAlCBub3QganVzdCByaWJvc29tYWwvTVQpPwogICAgICAgYi4gSXMgdGhlIHJlZmVyZW5jZSBVTUFQIG1vZGVsIGNvcnJlY3RseSBmcm96ZW4gKHJldHVybi5tb2RlbCA9IFRSVUUpPwogICAgICAgYy4gQXJlIHRoZXJlIDw1MDAgY2VsbHMgaW4gYW55IG9uZSBjZWxsIGxpbmU/IFNtYWxsIGxpbmVzIGNhbiBwcm9kdWNlCiAgICAgICAgICB1bnN0YWJsZSBTQ1QgbW9kZWxzLiBFeGNsdWRlIGxpbmVzIHdpdGggPDIwMCBjZWxscy4KCiAgS05PV04gQklPTE9HWSAoU8OpemFyeSBTeW5kcm9tZSk6CiAg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACiAgUHVibGlzaGVkIGxpdGVyYXR1cmUgKENlcmFwaW8gZXQgYWwuKSBzaG93cyBTw6l6YXJ5IGNlbGxzIHByZWRvbWluYW50bHkKICByZXNlbWJsZSBjZW50cmFsIG1lbW9yeSAoVENNKSBvciBza2luLWhvbWluZyBURU0gY2VsbHMuIEZPWFAzKyBUcmVnLWxpa2UKICBmZWF0dXJlcyBhcmUgYWxzbyByZXBvcnRlZCBpbiBzb21lIFNTIGNhc2VzLiBJZiB5b3VyIG1hbGlnbmFudCBjZWxscyBtYXAKICBwcmVkb21pbmFudGx5IHRvIFRDTS9URU0gdGVycml0b3J5IHdpdGggbG93LXRvLW1lZGl1bSBwc2V1ZG90aW1lLCB0aGlzCiAgaXMgY29uc2lzdGVudCB3aXRoIHB1Ymxpc2hlZCBmaW5kaW5ncy4KCuKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkCAtLT4K