Aishwarya Girish

Contents

Report

1. Introduction

Developmental bifurcations represent critical transitions in which cells or organisms diverge into distinct phenotypic fates. The freshwater planarian Phagocata morgani (P. morgani) undergoes such a bifurcation, developing into either an asexual or a sexual reproductive phenotype, each associated with a distinct growth trajectory. However, the mechanisms that govern these divergent outcomes, particularly the specific cell types that drive commitment toward either fate, remain poorly understood.

This notebook presents a quantitative framework for identifying cell-type-specific drivers of sexual and asexual growth trajectories in P. morgani. A particular focus is placed on identifying cell-type behaviour around the bifurcation points as they are regions in the developmental manifold where fate decisions are likely to occur. By statistically evaluating these transitions, candidate cellular populations that may act as intermediates or determinants of reproductive fate are identified.

The notebook is organized to guide the reader through each step of this analysis: from data preprocessing and pseudotime trajectory inference to cell-type abundance modeling and statistical enrichment testing. It serves as both a computational workflow and an interpretative tool for understanding the cellular dynamics in planaria.

1.1. Background

Development in P. morgani proceeds along distinct trajectories that give rise to sexual and asexual phenotypes. These trajectories are shaped by both environmental cues and intrinsic organismal properties, such as body size. To begin disentangling these factors, worms were maintained at a constant temperature of 17.5℃ — a condition known to sustain a mixed population of sexual and asexual individuals. This temperature was specifically chosen to allow for the separation of size-dependent effects from temperature-driven variation in cellular differentiation dynamics.

A single-cell atlas was constructed from this population by isolating nuclei from individual worms. Each worm was flash frozen and processed independently, with one worm per well in a 96-well plate. Prior to freezing, a video recording was captured for each worm, enabling quantification of morphological features such as body area and length using a standardized image analysis pipeline.

The resulting dataset was processed into a gene expression matrix and subsequently converted into a cell-type abundance matrix, where each row represents an individual worm and each column corresponds to a broad cell type. To ensure analytical robustness, cell types with extremely low abundance (<50 cells) across all samples were filtered out. Worm-level cell counts were then aggregated based on assigned cell-type annotations, yielding a worm-by-cell-type matrix reflecting absolute cell composition.

In parallel, morphological measurements (specifically worm length and area) were extracted for each sample to serve as covariates in downstream modeling. The raw count matrix was normalized using Monocle3’s size factor estimation framework to account for differences in total nuclei recovered per worm. This step corrected for variability in sequencing depth and overall cell recovery, enabling meaningful comparisons of cell-type proportions across worms.

The resulting size-normalized matrix forms the basis for all subsequent analyses.

1.2. Getting Started

To ensure reproducibility and transparency, all analyses were performed within an RNotebook framework using R (version 4.4.2). The Monocle3 package (Trapnell lab) was utilized for single-cell trajectory inference and normalization. Dependencies including Bioconductor packages and common data manipulation and visualization libraries were loaded as detailed below.

1.2.1. Installation and Setup
# Package Installation
required_packages <- c(
  # Core analysis
  "dplyr", "tidyr", "data.table", "ggplot2", "tibble",
  # Visualization
  "plotly", "pheatmap", "htmlwidgets", "gridExtra", "dendextend", "readr",
  # Data processing
  "VGAM", "zoo", "broom", "reshape2", "purrr", "splines"
)

# Install CRAN packages
new_packages <- required_packages[!(required_packages %in% installed.packages()[,"Package"])]
if(length(new_packages)) {
  install.packages(new_packages, dependencies = TRUE)
}

# Install Bioconductor packages
if (!requireNamespace("BiocManager", quietly = TRUE)) {
  install.packages("BiocManager")
}

bioc_packages <- c(
  'BiocGenerics', 'DelayedArray', 'DelayedMatrixStats',
  'limma', 'lme4', 'S4Vectors', 'SingleCellExperiment',
  'SummarizedExperiment', 'batchelor', 'HDF5Array',
  'terra', 'ggrastr'
)

new_bioc <- bioc_packages[!(bioc_packages %in% installed.packages()[,"Package"])]
if(length(new_bioc)) {
  BiocManager::install(new_bioc)
}

# Install GitHub packages
if (!requireNamespace("devtools", quietly = TRUE)) {
  install.packages("devtools")
}

if (!requireNamespace("remotes", quietly = TRUE)) {
  install.packages("remotes")
}

github_packages <- c(
  'cole-trapnell-lab/monocle3',
  'pln-team/PLNmodels',
  'cole-trapnell-lab/hooke'
)

# Check which GitHub packages need installation
if (!requireNamespace("monocle3", quietly = TRUE)) {
  devtools::install_github(github_packages[1])
}
if (!requireNamespace("PLNmodels", quietly = TRUE)) {
  remotes::install_github(github_packages[2])
}
if (!requireNamespace("hooke", quietly = TRUE)) {
  devtools::install_github(github_packages[3])
}

# Load all packages
all_packages <- c(required_packages, "monocle3", "PLNmodels", "hooke")

invisible(lapply(all_packages, function(pkg) {
  if (!require(pkg, character.only = TRUE)) {
    warning(paste("Package", pkg, "failed to load"))
  }
}))

# Verify loading
loaded <- sapply(all_packages, require, character.only = TRUE, quietly = TRUE)
if(all(loaded)) {
  message("All packages loaded successfully")
} else {
  warning("Failed to load: ", paste(names(loaded)[!loaded], collapse = ", "))
}

# # Print session info
# message("\nSession info:")
# sessionInfo()
1.2.2. Set Working Directory

The working directory was set to organize data and results appropriately.


setwd("/home/aishwarya/R/dorrity_lab_embl") #enter your working directory

2. Trajectory Inference Using Monocle3

To elucidate growth progression within the single-cell size atlas, trajectory inference was conducted using Monocle3. Principal component analysis (PCA) embeddings, specifically the first three principal components, were utilized in place of default UMAP embeddings to better represent the global structure of the data.

(Note: Principal Component Analysis (PCA) was selected over Uniform Manifold Approximation and Projection (UMAP) embeddings for trajectory inference due to PCA’s ability to preserve global data structure and variance. Unlike UMAP, which emphasizes local neighborhood relationships and nonlinear manifold learning primarily for visualization, PCA provides a linear projection that retains the largest sources of variation across the entire dataset. This characteristic is crucial when modeling developmental trajectories, as it ensures that the principal axes represent meaningful biological gradients—such as size and differentiation status—rather than focusing solely on local clustering. Using PCA embeddings thus enables more robust and interpretable inference of pseudotemporal progression in complex single-cell data.)

Given that morphological size in P. morgani correlates strongly with developmental stage, worm length (Lengthmm) was used as a biologically informed proxy for pseudotime, here referred to as pseudosize. Cells were clustered at high resolution to resolve fine-grained cell states, and a principal graph was constructed across the PCA spaceto model putative differentiation trajectories. Pseudotime values were then inferred along this graph, capturing size-associated developmental progression across individual worms. This approach facilitated the characterization and visualization of divergent cellular trajectories underlying sexual and asexual differentiation.


# Load preprocessed cell_data_set object
cds <- readRDS("size-cds-cellcounts_3e-5-highRes-cell-type.rds")
# Replace default UMAP embeddings with first three PCA components for dimensionality reduction
cds@int_colData@listData$reducedDims@listData$UMAP <- cds@int_colData@listData$reducedDims@listData$PCA[, 1:3]

# Cluster cells at a low resolution for fine granularity
cds <- cluster_cells(cds, resolution = 3e-5)
plot_cells_3d(cds, color_cells_by="Lengthmm")

# Learn principal graph to model developmental trajectories
cds <- learn_graph(cds, learn_graph_control=list(ncenter=7, prune_graph=FALSE, minimal_branch_len=1))
plot_cells_3d(cds, color_cells_by="Lengthmm", cell_size = 30)

# Order cells along the learned trajectory (interactive mode)
#cds <- order_cells(cds)

# Order Cells (NOTE: The root node was initially found in the interactive mode, but here the input is automated for a smooth knitting of the final HTML document.)

root_node <- "Y_6"  

cds <- order_cells(cds, root_pr_nodes = root_node)

# Assign pseudotime values reflecting developmental progression correlated with worm size
cds$pseudosize_pca <- pseudotime(cds)
monocle3_trajectory_plot <- plot_cells_3d(cds, color_cells_by="pseudosize_pca")
monocle3_trajectory_plot


# Extract and arrange metadata by pseudotime for downstream analysis
coldat <- as.data.frame(colData(cds))
coldat <- coldat %>% arrange(pseudosize_pca)

rowdat <- as.data.frame(rowData(cds))

# Extract and reorder counts matrix according to sample order in metadata
cell_counts <- as.matrix(counts(cds))[, coldat$sample]


# Calculate variance explained by PCA components to assess dimensionality reduction
var_explained <- cds@reduce_dim_aux$PCA@listData$model$prop_var_expl
var_explained                                # vector for every PC
 [1] 0.35782603 0.17105484 0.12641509 0.08478567 0.07126308 0.04854720 0.04694388 0.03448373 0.03137934 0.02730115
sum(var_explained[1:3])                      # cumulative for PC1–PC3
[1] 0.655296
sum(var_explained[1:7])                      # cumulative for PC1–PC7
[1] 0.9068358
if (!dir.exists("trajectory_output")) dir.create("trajectory_output")

# Save interactive 3D trajectory plot as an HTML widget
saveWidget(monocle3_trajectory_plot, "trajectory_output/monocle3_trajectory_plot.html", selfcontained = TRUE)

2.1. Dimensionality and Clustering

To determine the appropriate number of clusters in the PCA space, unsupervised k-means clustering was performed on the first three principal components of the cell type composition data. The working hypothesis was that incorporating more principal components (thereby capturing a greater proportion of variance) would yield finer-grained clusters and improve resolution. However, this hypothesis was not supported by the data.

Contrary to expectations, increasing the number of principal components (e.g., 7 PCs to capture ~80–90% of the variance) resulted in a decrease in the number of biologically meaningful clusters. This observation suggests that the additional components may predominantly capture technical noise or low-variance structure, thereby diluting the signal necessary for robust clustering. In contrast, the first three components, which collectively explain approximately 66% of the variance, retained the most relevant biological structure for delineating distinct cell states.

2.1.1. K-Means Elbow Plot

To assess cluster structure, a standard elbow plot was constructed by computing the total within-cluster sum of squares (WSS) for a range of k values. The maximum number of clusters evaluated was set to k = 15 to allow for detection of an inflection point in the within-cluster sum of squares (WSS) curve. This upper limit was chosen to exceed the anticipated number of biologically relevant clusters while avoiding excessive partitioning of the data. The WSS curve exhibited a distinct elbow, beyond which increases in k yielded minimal gains, indicating the optimal number of clusters. A distinct inflection point in the WSS curve indicated the optimal number of clusters (k=4), balancing model complexity and explanatory power.


# Needs ggplot2 and Monocle3 which were already loaded earlier
library(purrr)

# Extract PCA coordinates (first 3 PCs)
pca_coords <- reducedDims(cds)$PCA[, 1:3]  # Adjust to 1:3 if using 3D

# Calculate WSS for k=1 to k=15
set.seed(123)  # Reproducibility
max_k <- 15
wss <- map_dbl(1:max_k, ~{
  kmeans(pca_coords, centers = .x, nstart = 25, iter.max = 50)$tot.withinss
})

# Plot ELbow Curve

elbow_plot <- ggplot(data.frame(k = 1:max_k, WSS = wss), aes(x = k, y = WSS)) +
  geom_line(color = "#377EB8", linewidth = 1.2) +
  geom_point(color = "#E41A1C", size = 3) +
  labs(
    title = "K-means Elbow Plot (PCA Space)",
    x = "Number of clusters (k)",
    y = "Total Within-Cluster Sum of Squares (WSS)"
  ) +
  scale_x_continuous(breaks = 1:max_k) +
  theme_minimal() +
  theme(
    text = element_text(family = "Helvetica"),
    plot.title = element_text(face = "bold", hjust = 0.5),
    panel.grid.minor = element_blank(),
    
    # Solid white background for panel
    panel.background = element_rect(fill = "white", color = NA),
    # Add border around the plot panel
    panel.border = element_rect(color = "black", fill = NA, linewidth = 0.5),
    
    # Optional: add border around entire plot (including margin)
    plot.background = element_rect(color = "black", fill = "white", linewidth = 0.5)
  )

print(elbow_plot)

# Save plot
ggsave("trajectory_output/elbow_plot.png", plot = elbow_plot, width = 8, height = 6, dpi = 300)

NA
NA
2.1.2. K-Means Clustering

To identify discrete cellular states along the developmental trajectory, K-means clustering was performed on cells embedded in PCA space and ordered by pseudotime. All cells were initially assigned to a common early-state label (Prebranch_1). Cells exceeding a defined pseudotime threshold were considered post-branch and partitioned into two major clusters: Branch_1 and Branch_2.

An intermediate cluster, Prebranch_2, emerged within the transitional pseudotime window, representing a putative pre-commitment state preceding bifurcation.Importantly, clustering into three groups revealed a branch point along the growth trajectory that precedes the divergence into asexual and sexual pathways (Branch_1 and Branch_2 respectively). This early inflection is primarily represented by samples assigned to the Prebranch_2 cluster. The distinct positioning of this group suggests that a critical shift in cellular composition or developmental state may occur upstream of overt sexual differentiation. This observation raises the possibility that Prebranch_2 corresponds to a transitional phase characterized by an early commitment or upregulation of developmental programs.

These data-driven clusters delineate key stages of growth in P. morgani, with Branch_1 and Branch_2 corresponding to the committed asexual and sexual fates, respectively. Visualization in 3D PCA space confirmed that the inferred clusters recapitulate the underlying structure of developmental divergence.

Cluster Description Color
Prebranch_1 Early developmental state (common root) Gray
Prebranch_2 Transitional pre-commitment state Orange
Branch_1 Terminal state of the asexual trajectory Blue
Branch_2 Terminal state of the sexual trajectory Red

# Initialize all cells as prebranch_1
cds$branch <- "Prebranch_1"

#vIdentify post-branch cells using pseudotime threshold
pseudotime_threshold <- quantile(cds$pseudosize_pca, probs = 0.33)
post_branch_idx <- which(cds$pseudosize_pca > pseudotime_threshold)

# Branching logic (Main bifurcation: split post-branch cells into two clusters)
if(length(post_branch_idx) > 10) {
  post_coords <- reducedDims(cds)$PCA[post_branch_idx, 1:3]
  set.seed(123)
  km <- kmeans(post_coords, centers = 2)
  cds$branch[post_branch_idx] <- ifelse(km$cluster == 1, "Branch_1", "Branch_2")
  
  # Secondary clustering (Secondary bifurcation: split Branch_1 into Prebranch_2 and Branch_1)
  branch1_idx <- which(cds$branch == "Branch_1")
  if(length(branch1_idx) > 5) {
    branch1_coords <- reducedDims(cds)$PCA[branch1_idx, 1:3]
    set.seed(123)
    km2 <- kmeans(branch1_coords, centers = 2)
    cds$branch[branch1_idx] <- ifelse(km2$cluster == 1, "Branch_1", "Prebranch_2")
  }
}

# Define and order final cluster labels
cds$branch <- factor(cds$branch, 
                     levels = c("Prebranch_1", "Prebranch_2", "Branch_1", "Branch_2"))

names(cds$branch) <- colnames(cds)

# Color scheme
branch_colors <- c(
  "Prebranch_1" = "#999999",
  "Branch_1" = "#377EB8",
  "Prebranch_2" = "orange",
  "Branch_2" = "#E41A1C"
)


# 3D scatter plot of clusters 
clustering_plot_4 <- plot_ly()

for(branch in levels(cds$branch)) {
  if(any(cds$branch == branch)) {
    clustering_plot_4 <- clustering_plot_4 %>% add_trace(
      x = reducedDims(cds)$PCA[cds$branch == branch, 1],
      y = reducedDims(cds)$PCA[cds$branch == branch, 2],
      z = reducedDims(cds)$PCA[cds$branch == branch, 3],
      type = "scatter3d", mode = "markers",
      marker = list(
        size = ifelse(branch == "Prebranch_1", 4, 4),
        color = branch_colors[branch]
      ),
      name = branch
    )
  }
}

clustering_plot_4 <- clustering_plot_4 %>% 
  config(autosizable = TRUE) %>% 
  layout(
    scene = list(
      xaxis = list(title = "PC1"),
      yaxis = list(title = "PC2"),
      zaxis = list(title = "PC3")
    ),
    legend = list(
      orientation = "h", 
      x = 0.5, 
      xanchor = "center", 
      y = -0.15,  # Try more negative values if needed
      yanchor = "top"
    )
  )

clustering_plot_4

# Save plot
saveWidget(clustering_plot_4, "trajectory_output/clustering_plot_4.html", selfcontained = TRUE)

#NOTE: Another idea would be to try the Leiden clustering. Since Monocle3 already does that in the learn_graph() step, the k-means clustering (as illustrated above) should suffice.

2.2. Defining Trajectories

To enable focused downstream analyses, four biologically relevant trajectory subsets were delineated, each representing specific stages or fate decisions within P. morgani growth:

  • Early Development: comprising Prebranch_1 and Prebranch_2, representing initial stages prior to major fate commitment.

  • Asexual Trajectory: encompassing Prebranch_1, Prebranch_2, and Branch_1, corresponding to the developmental path leading to asexual worms.

  • Sexual Trajectory: including Prebranch_1, Prebranch_2, and Branch_2, representing the trajectory towards sexual differentiation.

  • Late Development: consisting of Branch_1 and Branch_2, capturing the terminal phases of both asexual and sexual lineages.

These trajectory definitions provide a structured framework for systematic comparison of cell type composition, dynamic variability, and pseudotemporal progression.


## Defining Clusters and Trajectories

# Set consistent cluster ordering and associated colors
branch_order <- c("Prebranch_1", "Prebranch_2", "Branch_1", "Branch_2")
branch_colors <- c(
  "Prebranch_1" = "#999999",  # grey
  "Prebranch_2" = "orange",   # orange
  "Branch_1"    = "#377EB8",  # blue
  "Branch_2"    = "#E41A1C"   # red
)

#coldat$cluster <- cds$branch[rownames(coldat)]  

# Assign cluster labels to cells
coldat$cluster <- as.character(cds$branch)[match(rownames(coldat), names(cds$branch))]
coldat$cluster <- factor(coldat$cluster, levels = c("Prebranch_1", "Prebranch_2", "Branch_1", "Branch_2"))

# Define trajectory groupings and their branch composition
trajectories <- list(
  early_dev = list(
    name = "Early Development",
    branches = c("Prebranch_1", "Prebranch_2"),
    color = c("#999999", "orange")
  ),
  asexual = list(
    name = "Asexual Trajectory",
    branches = c("Prebranch_1", "Prebranch_2", "Branch_1"),
    color = c("#999999", "orange", "#377EB8")
  ),
  sexual = list(
    name = "Sexual Trajectory",
    branches = c("Prebranch_1", "Prebranch_2", "Branch_2"),
    color = c("#999999", "orange", "#E41A1C")
  ),
  late_dev = list(
    name = "Late Development",
    branches = c("Branch_1", "Branch_2"),
    color = c("#377EB8", "#E41A1C")
  ),
  all_clusters = list(
    name = "All Clusters",
    branches = levels(cds$branch),
    color = unname(branch_colors[levels(cds$branch)])
  )
)


# Optional diagnostic: Check how many cells fall under each trajectory
for (traj_name in names(trajectories)) {
  clusters <- trajectories[[traj_name]]$branches
  cells <- rownames(coldat)[coldat$cluster %in% clusters]
  cat(sprintf("Trajectory '%s' contains %d cells across clusters: %s\n",
              traj_name, length(cells), paste(clusters, collapse = ", ")))
}
Trajectory 'early_dev' contains 54 cells across clusters: Prebranch_1, Prebranch_2
Trajectory 'asexual' contains 71 cells across clusters: Prebranch_1, Prebranch_2, Branch_1
Trajectory 'sexual' contains 77 cells across clusters: Prebranch_1, Prebranch_2, Branch_2
Trajectory 'late_dev' contains 40 cells across clusters: Branch_1, Branch_2
Trajectory 'all_clusters' contains 94 cells across clusters: Prebranch_1, Prebranch_2, Branch_1, Branch_2
2.2.1. Defining Branch Points and Visualizing Trajectories

Branch points within the developmental trajectory were identified as the minimum pseudotime values corresponding to transitions into distinct clusters (Prebranch_2, Branch_1, Branch_2). These branch points mark critical fate decisions along the pseudotemporal axis derived from the PCA embedding.

# Ensure pseudotime is available
if ("pseudosize_pca" %in% colnames(colData(cds))) {

  # Find branch transitions
  transitions <- list(
    Prebranch_2 = min(cds$pseudosize_pca[cds$branch == "Prebranch_2"], na.rm = TRUE),
    Branch_1 = min(cds$pseudosize_pca[cds$branch == "Branch_1"], na.rm = TRUE), 
    Branch_2 = min(cds$pseudosize_pca[cds$branch == "Branch_2"], na.rm = TRUE)
  )

  # Remove any invalid transitions (Inf, NA)
  transitions <- transitions[!is.infinite(unlist(transitions)) & !is.na(unlist(transitions))]

  # Create base 3D plot
  base_plot <- plot_cells_3d(
    cds,
    color_cells_by = "branch",
    cell_size = 30,
    trajectory_graph_color = "black",
    trajectory_graph_segment_size = 3
  )

  branch_points_plot <- base_plot

  # Helper: Get PCA coordinates near pseudotime ---
  get_coords_at_pseudotime <- function(cds, pseudotime_val) {
    idx <- which.min(abs(cds$pseudosize_pca - pseudotime_val))
    reducedDims(cds)$PCA[idx, 1:3]
  }

  # Add branch points with clean labels
  for (branch in names(transitions)) {
    coords <- get_coords_at_pseudotime(cds, transitions[[branch]])

    branch_points_plot <- branch_points_plot %>% add_trace(
      x = coords[1], y = coords[2], z = coords[3],
      type = "scatter3d",
      mode = "markers",
      marker = list(
        size = 12,
        color = branch_colors[branch],
        symbol = "diamond"
      ),
      name = sprintf("%s (t=%.2f)", branch, transitions[[branch]]),
      hoverinfo = "text",
      text = sprintf("%s start\nPseudotime: %.2f\nPC1: %.1f\nPC2: %.1f\nPC3: %.1f",
                     branch, transitions[[branch]], coords[1], coords[2], coords[3]),
      showlegend = TRUE
    )
  }

  # Create density plot with ordered legend
  branch_order <- c("Prebranch_1", "Prebranch_2", "Branch_1", "Branch_2")
  plot_data <- as.data.frame(colData(cds))
  plot_data$branch <- factor(plot_data$branch, levels = branch_order)

  density_plot <- ggplot(plot_data, 
                       aes(x = pseudosize_pca, fill = branch)) +
      geom_density(alpha = 0.5) +
      geom_vline(xintercept = unlist(transitions), 
                 linetype = "dashed",
                 color = branch_colors[names(transitions)]) +
      scale_fill_manual(values = branch_colors[branch_order],
                        breaks = branch_order) +
      labs(x = "Pseudotime", y = "Density", title = "Branch Transitions") +
      theme_minimal() +
      theme(
          text = element_text(family = "Helvetica"),
          legend.position = "bottom",
          legend.justification = "center",
          plot.title = element_text(hjust = 0.5, face = "bold"),  
          panel.border = element_rect(color = "black", fill = NA, size = 0.5),  
          plot.background = element_rect(color = "black", fill = NA, linewidth = 0.5)  
    )

  # Optional: Print transition info
  cat("=== Branch Transition Pseudotimes ===\n")
  print(data.frame(
    Branch = names(transitions),
    Pseudotime = round(unlist(transitions), 2),
    PC1 = sapply(names(transitions), function(x) round(reducedDims(cds)$PCA[which.min(abs(cds$pseudosize_pca - transitions[[x]])), 1], 2)),
    PC2 = sapply(names(transitions), function(x) round(reducedDims(cds)$PCA[which.min(abs(cds$pseudosize_pca - transitions[[x]])), 2], 2)),
    PC3 = sapply(names(transitions), function(x) round(reducedDims(cds)$PCA[which.min(abs(cds$pseudosize_pca - transitions[[x]])), 3], 2))
  ))

  # Return plots
  print(branch_points_plot)
  print(density_plot)

} else {
  warning("Pseudotime column 'pseudosize_pca' not found")
  NULL
}
=== Branch Transition Pseudotimes ===
#Save plots
ggsave("trajectory_output/density_plot.png", plot = density_plot, width = 8, height = 6, dpi = 300)


saveWidget(branch_points_plot, "trajectory_output/ branch_points_plot.html", selfcontained = TRUE)

# Minimum Spanning Tree coordinates (3 rows = PC1, PC2, PC3; 7 cols = nodes) manually retrieved from Monocle3 cds object: cds@principal_graph_aux@listData[["UMAP"]][["dp_mst"]]

mst_coords_raw <- matrix(
  c(-1.002902,  1.8693896,  1.892249,  3.2705521,  4.21178119, -5.3767044, -3.54361406,
    -1.385229, -1.9476252, -2.767477,  0.5152539,  3.19226895,  1.3584236,  0.07889964,
    -2.016103, -0.8172786,  2.155795, -0.4427244,  0.01372972,  0.9358482, -0.44058576),
  nrow = 3, byrow = TRUE,
  dimnames = list(c("PC1", "PC2", "PC3"), paste0("Y_", 1:7))
)

# Transpose so rows = nodes, cols = PCs
mst_coords <- t(mst_coords_raw)
colnames(mst_coords) <- c("PC1", "PC2", "PC3")

# MST edges manually retreived from cds object and defined (node indices, matching rownames in mst_coords)
mst_edges <- list(
  c(1,2),
  c(2,3),
  c(2,4),
  c(4,5),
  c(1,7),
  c(6,7)
)

# Optional: Define trajectories and their branches & colors (This is optional as it is already defined above)
trajectories <- list(
  early_dev = list(
    name = "Early Development",
    branches = c("Prebranch_1", "Prebranch_2"),
    color = c("#999999", "orange")
  ),
  asexual = list(
    name = "Asexual Trajectory",
    branches = c("Prebranch_1", "Prebranch_2", "Branch_1"),
    color = c("#999999", "orange", "#377EB8")
  ),
  sexual = list(
    name = "Sexual Trajectory",
    branches = c("Prebranch_1", "Prebranch_2", "Branch_2"),
    color = c("#999999", "orange", "#E41A1C")
  ),
  late_dev = list(
    name = "Late Development",
    branches = c("Branch_1", "Branch_2"),
    color = c("#377EB8", "#E41A1C")
  ),
  all_clusters = list(
    name = "All Clusters",
    branches = levels(cds$branch),
    color = unname(branch_colors[levels(cds$branch)])
  )
)

# Add sample IDs for each trajectory
for (traj_name in names(trajectories)) {
  trajectories[[traj_name]]$samples <- rownames(colData(cds))[cds$branch %in% trajectories[[traj_name]]$branches]
}

# Helper function to get coordinates at minimal pseudotime in a branch
get_coords_at_pseudotime <- function(cds, pseudotime_val) {
  idx <- which.min(abs(cds$pseudosize_pca - pseudotime_val))
  reducedDims(cds)$PCA[idx, 1:3]
}

# Branch transition pseudotime values
transitions <- list(
  Prebranch_2 = min(cds$pseudosize_pca[cds$branch == "Prebranch_2"], na.rm = TRUE),
  Branch_1 = min(cds$pseudosize_pca[cds$branch == "Branch_1"], na.rm = TRUE),
  Branch_2 = min(cds$pseudosize_pca[cds$branch == "Branch_2"], na.rm = TRUE)
)
transitions <- transitions[!is.infinite(unlist(transitions)) & !is.na(unlist(transitions))]

# Plotting loop
trajectory_plots <- lapply(trajectories, function(traj) {
  plot_colors <- branch_colors
  plot_colors[!names(plot_colors) %in% traj$branches] <- "#F0F0F0"
  
  trajectory_plot <- plot_ly() %>%
    layout(
      scene = list(
        xaxis = list(title = "PC1"),
        yaxis = list(title = "PC2"),
        zaxis = list(title = "PC3")
      ),
      title = list(text = traj$name, y = 0.95, x = 0.5, xanchor = "center"),
      legend = list(orientation = "h", x = 0.5, xanchor ="center", y = -0.1, yanchor = "top")
    )
  
  for(branch in levels(cds$branch)) {
    trajectory_plot <- trajectory_plot %>% add_trace(
      x = reducedDims(cds)$PCA[cds$branch == branch, 1],
      y = reducedDims(cds)$PCA[cds$branch == branch, 2],
      z = reducedDims(cds)$PCA[cds$branch == branch, 3],
      type = "scatter3d",
      mode = "markers",
      marker = list(
        size = ifelse(branch %in% traj$branches, 4, 3),
        color = plot_colors[branch],
        opacity = ifelse(branch %in% traj$branches, 1, 0.3)
      ),
      name = ifelse(branch %in% traj$branches, branch, paste0(branch, " (other)")),
      showlegend = branch %in% traj$branches
    )
  }
  
  for(edge in mst_edges) {
    trajectory_plot <- trajectory_plot %>% add_trace(
      x = mst_coords[edge, "PC1"],
      y = mst_coords[edge, "PC2"],
      z = mst_coords[edge, "PC3"],
      type = "scatter3d",
      mode = "lines",
      line = list(color = "black", width = 4),
      showlegend = FALSE
    )
  }
  
  for(branch in intersect(names(transitions), traj$branches)) {
    coords <- get_coords_at_pseudotime(cds, transitions[[branch]])
    trajectory_plot <- trajectory_plot %>% add_trace(
      x = coords[1], y = coords[2], z = coords[3],
      type = "scatter3d",
      mode = "markers",
      marker = list(
        size = 7,
        color = branch_colors[branch],
        symbol = "x"
      ),
      name = sprintf("%s (t=%.1f)", branch, transitions[[branch]]),
      hoverinfo = "text",
      text = sprintf("%s start\nPseudotime: %.2f", branch, transitions[[branch]]),
      showlegend = TRUE
    )
  }
  
  return(trajectory_plot)
})

# Display plots
trajectory_plots$early_dev
trajectory_plots$asexual
trajectory_plots$sexual
trajectory_plots$late_dev
trajectory_plots$all_clusters


saveWidget(trajectory_plots$early_dev, "trajectory_output/early_dev.html", selfcontained = TRUE)
saveWidget(trajectory_plots$asexual, "trajectory_output/asexual.html", selfcontained = TRUE)
saveWidget(trajectory_plots$sexual, "trajectory_output/sexual.html", selfcontained = TRUE)
saveWidget(trajectory_plots$late_dev, "trajectory_output/late_dev.html", selfcontained = TRUE)
saveWidget(trajectory_plots$all_clusters, "trajectory_output/all_clusters.html", selfcontained = TRUE)

3. Abundance Analysis

Cell type abundance patterns were analyzed along pseudotime trajectories to identify compositional changes associated with growth. The analysis focused on ±5% pseudotime windows around each branch point, comparing local cell type proportions to their global mean abundance across the corresponding trajectory. Wilcoxon rank-sum tests identified significantly enriched or depleted cell types during transitions, with three alternative hypotheses tested: enrichment, depletion, and non-directional changes (“two.sided”). Results were visualized using smoothed loess curves showing cell type proportions along pseudotime, with branch points marked by vertical lines.

Enriched cell types near branch points may represent transitional states or fate-committed progenitors. These populations often play critical roles in lineage bifurcation, either as bipotent intermediates or as sources of instructive signals. Conversely, depleted cell types suggest mutually exclusive fate choices or temporal separation of developmental programs. Cell types showing context-dependent abundance changes across different branches may indicate developmental plasticity, where populations retain the capacity for multiple fate decisions based on local conditions.

The timing of abundance peaks relative to branch points provides insights into the ordering of molecular events. Early-appearing cell types likely reflect initial fate priming, while late-appearing populations may represent terminal differentiation states. The pseudotemporal windowing approach captures these dynamics while accounting for variability in differentiation kinetics across cells. All findings were interpreted considering the compositional nature of the data, where changes in one cell type necessarily influence the interpretation of others in the ecosystem.

Technical validation confirmed the robustness of results to pseudotime reconstruction parameters and window size selection. While the analysis provides statistical identification of interesting cell populations, deeper biological interpretation requires integration with known lineage relationships and marker gene expression patterns from the broader dataset. The combined approach reveals how cellular heterogeneity is dynamically regulated during growth.

Trajectory Enriched Cell Types
Early Development
Prebranch_2 - Enrichment
Cathepsin 5, Intestine 1, Intestine 6, Cathepsin 2, Neural 5, Cathepsin 6, Parenchymal 3, Neural 8, Neural 1, Intestine 4
Asexual
Branch_1 - Enrichment
Cathepsin 1, Cathepsin 3, Neural 4, Intestine 5, Cathepsin 4, Parenchymal 6, Epidermal 5, Intestine 3, Cathepsin 8, Parenchymal 1
Sexual
Branch_2 - Enrichment
Parenchymal 5, Testes, Size specific 2, Epidermal 5, Neural 4, Size specific 1, Cathepsin 4, Cathepsin 3, Parenchymal 1, Epidermal 8
Trajectory Depleted Cell Types
Early Development
Prebranch_2 - Depletion
Size specific 1, Epidermal 4, Size specific 2, Parenchymal 5, Epidermal 3, Epidermal 8, Epidermal 2, Neural 10, Intestine 2, Testes
Asexual
Branch_1 - Depletion
Epidermal 8, Muscle 3, Muscle 2, Muscle 5, Neural 6, Parenchymal 2, Neoblast 2, Parenchymal 4, Neural 2, Parenchymal 5
Sexual
Branch_2 - Depletion
Muscle 2, Neural 1, Muscle 3, Epidermal 1, Parenchymal 3, Cathepsin 5, Neural 2, Neural 3, Intestine 2, Intestine 6


# Ensure sample names match between cell_counts and coldat
rownames(cell_counts) <- gsub("-", ".", rownames(cell_counts))  # Harmonize naming if needed
coldat <- coldat[colnames(cell_counts), ]  # Reorder coldat to match cell_counts columns

# Normalize counts to proportions (if not already normalized)
cell_props <- t(t(cell_counts) / colSums(cell_counts))  # Rows = cell types, columns = samples

#This was previously listed in another chunk, but I am running it again just for clarity
transitions <- list(
  Prebranch_2 = min(cds$pseudosize_pca[cds$branch == "Prebranch_2"], na.rm = TRUE),
  Branch_1 = min(cds$pseudosize_pca[cds$branch == "Branch_1"], na.rm = TRUE), 
  Branch_2 = min(cds$pseudosize_pca[cds$branch == "Branch_2"], na.rm = TRUE)
)


# min_prebranch2_time <- transitions$Prebranch_2
# min_branch1_time <- transitions$Branch_1
# min_branch2_time <- transitions$Branch_2

# --------------------------------------------------------------------------------------------------
# Function: analyze_abundance_for_branch
# Purpose: Identify cell types whose abundance significantly changes around a trajectory branch point.
# It computes fold-change, performs Wilcoxon tests, and visualizes smoothed abundance trends.
# --------------------------------------------------------------------------------------------------

analyze_abundance_for_branch <- function(
  cds, cell_props, coldat, trajectories, transitions,
  trajectory_key, branch_name,
  test_type = c("Enrichment", "Depletion", "Two Sided Test"),
  transition_color = "black",
  save_prefix = NULL
) {
  
    # Choose alternative hypothesis for Wilcoxon test based on user input
  wilcox_alternative <- switch(match.arg(test_type),
    "Enrichment" = "greater",
    "Depletion" = "less",
    "Two Sided Test" = "two.sided"
  )
  
  #Load necessary libraries
  library(dplyr)
  library(broom)
  library(ggplot2)
  library(reshape2)

  test_type <- match.arg(test_type)

  # Retrieve metadata for the trajectory of interest
  traj <- trajectories[[trajectory_key]]
  clusters <- traj$branches
  transition_time <- transitions[[branch_name]]
  
  # Define the pseudotime window (±5%) around the branch point
  transition_window <- 0.05 * max(coldat$pseudosize_pca, na.rm = TRUE)

  # Identify sample IDs in this trajectory
  traj_samples <- rownames(coldat)[coldat$cluster %in% clusters]

  # Compute fold-change in abundance (transition window vs global)
  compute_fc <- function(cell_type) {
    global_mean <- mean(cell_props[cell_type, traj_samples], na.rm = TRUE)
    window_samples <- rownames(coldat)[
      coldat$pseudosize_pca >= (transition_time - transition_window) &
      coldat$pseudosize_pca <= (transition_time + transition_window)
    ]
    window_mean <- mean(cell_props[cell_type, window_samples], na.rm = TRUE)
    data.frame(
      cell_type = cell_type,
      global_prop = global_mean,
      transition_prop = window_mean,
      fold_change = window_mean / global_mean
    )
  }

  # Perform Wilcoxon rank-sum test to assess enrichment/depletion
  test_enrichment <- function(cell_type) {
    in_window <- coldat$pseudosize_pca >= (transition_time - transition_window) &
                 coldat$pseudosize_pca <= (transition_time + transition_window)
    test <- wilcox.test(
      x = cell_props[cell_type, in_window],
      y = cell_props[cell_type, !in_window],
      alternative = wilcox_alternative
    )
  #   tidy(test) %>% mutate(cell_type = cell_type)
  # }
    # Create result data frame directly (no broom dependency)
    data.frame(
      cell_type = cell_type,
      p_value = test$p.value,
      statistic = test$statistic,
      method = test$method,
      stringsAsFactors = FALSE
    )
}

  # Run fold-change computation and statistical test for all cell types
  abundance_summary <- bind_rows(lapply(rownames(cell_props), compute_fc))
  enrichment_results <- bind_rows(lapply(rownames(cell_props), test_enrichment))
  
  # Merge fold-change and p-value results, adjust format
  abundance_summary <- abundance_summary %>%
    left_join(enrichment_results, by = "cell_type") %>%
    #rename(p_value = p.value) %>%
    arrange(p_value)

  # Visualize abundance trends for top 10 significant cell types
  top_celltypes <- head(abundance_summary$cell_type, 10)

  # Prepare data for plotting
  plot_data <- melt(
    data.frame(
      sample = rownames(coldat),
      pseudosize_pca = coldat$pseudosize_pca,
      t(cell_props[top_celltypes, ])
    ),
    id.vars = c("sample", "pseudosize_pca"),
    variable.name = "cell_type",
    value.name = "proportion"
  )
  
  # Generate LOESS-smoothed plot of abundance vs pseudotime
  abundance_plot <- ggplot(plot_data, aes(x = pseudosize_pca, y = proportion, color = cell_type)) +
    geom_smooth(method = "loess", se = FALSE) +
    geom_vline(xintercept = transition_time, linetype = "dashed", color = transition_color) +
    labs(
      title = paste(traj$name, ":", branch_name, "-", test_type),
      x = "Pseudotime",
      y = "Proportion",
      color = "Cell Type"
    ) +
    theme_minimal() +
  theme(
    text = element_text(family = "Helvetica"),
    plot.title = element_text(hjust = 0.5, face = "bold"),  
    panel.border = element_rect(color = "black", fill = NA, linewidth = 0.5),  
    plot.background = element_rect(color = "black", fill = NA, linewidth = 0.5)  
  )
  
  print(abundance_plot)

  # Save outputs if prefix given
  if (!is.null(save_prefix)) {
    ggsave(filename = paste0(save_prefix, "_", test_type, ".jpg"), plot = abundance_plot, width = 8, height = 5, dpi = 300)
    write.csv(abundance_summary, paste0(save_prefix, "_", test_type, "_summary.csv"), row.names = FALSE)
  }

  return(list(summary = abundance_summary, plot = abundance_plot))
}


# --------------------------------------------------------------------------------------------------
# Function: run_abundance_analysis_batch
# Purpose: Batch wrapper to apply abundance analysis across multiple branches and test types.
# --------------------------------------------------------------------------------------------------


run_abundance_analysis_batch <- function(
  cds, cell_props, coldat, trajectories, transitions,
  analysis_plan,
  test_types = c("Enrichment", "Depletion", "Two Sided Test"),
  save_dir = NULL
) {
  results <- list()
  
  # Loop over all entries in the analysis plan (each trajectory and branch)
  for (entry in analysis_plan) {
    for (test in test_types) {
      prefix <- if (!is.null(save_dir)) {
        file.path(save_dir, paste0(entry$trajectory_key, "_", entry$branch_name))
      } else {
        NULL
      }
      
      # Run Analysis
      res <- analyze_abundance_for_branch(
        cds = cds,
        cell_props = cell_props,
        coldat = coldat,
        trajectories = trajectories,
        transitions = transitions,
        trajectory_key = entry$trajectory_key,
        branch_name = entry$branch_name,
        test_type = test,
        save_prefix = prefix
      )

      results[[paste(entry$trajectory_key, entry$branch_name, test, sep = "_")]] <- res
    }
  }

  return(results)
}


# --------------------------------------------------------------------------------------------------
# Configuration: Analysis Plan
# Each list item defines a branch point and corresponding trajectory to analyze.
# --------------------------------------------------------------------------------------------------


analysis_plan <- list(
  list(trajectory_key = "sexual",  branch_name = "Branch_2"),
  list(trajectory_key = "asexual", branch_name = "Branch_1"),
  list(trajectory_key = "early_dev", branch_name = "Prebranch_2")
)

# --------------------------------------------------------------------------------------------------
# Run the Full Batch Analysis
# Results are stored in a named list indexed by trajectory/branch/test
# --------------------------------------------------------------------------------------------------

results <- run_abundance_analysis_batch(
  cds = cds,
  cell_props = cell_props,
  coldat = coldat,
  trajectories = trajectories,
  transitions = transitions,
  analysis_plan = analysis_plan,
  test_types = c("Enrichment", "Depletion", "Two Sided Test"),
  save_dir = "abundance_output"  # Set to NULL to disable saving
)

1: Yes
2: No
yes
Enter an item from the menu, or 0 to exit
Yes


# # Print all summaries
# for (name in names(results)) {
#   cat("\n==== Result for:", name, "====\n")
#   print(results[[name]]$summary)
# }

# Optionally, display all plots (in R console or notebook)
# for (name in names(results)) {
#   #cat("\n==== Plot for:", name, "====\n")
#   print(results[[name]]$abundance_plot)
# }

4. Variance Analysis

Dynamic changes in cellular variability often precede developmental bifurcations, reflecting critical slowing down—a hallmark of systems approaching a tipping point. Variance-based metrics thus provide a powerful lens to detect cell populations undergoing fate decisions or lineage priming.

4.1. Rolling Window Approach

To quantify dynamic variability in the cell types, we implemented a rolling window analysis of normalized variance (variance-to-mean ratio) centered around the inferred branch points of the asexual and sexual trajectories.

A symmetric transition window spanning ±10% of the maximum pseudotime was defined. This expanded window accounted for biological noise and temporal heterogeneity around bifurcation events, ensuring sufficient resolution to detect changes in variance. For each cell type, global normalized variance was calculated across all cells in a trajectory, alongside localized normalized variance within a defined transition window centered at each branch point. The fold change between local and global variance quantified the degree of variability enrichment. Cell types exhibiting high fold changes were identified as candidate contributors to fate bifurcation.

To assess the statistical significance of this enrichment, Levene’s test for equality of variances was performed, comparing abundance variance inside versus outside the transition window. Resulting p-values were adjusted for multiple testing using the Benjamini-Hochberg procedure, and cell types were ranked based on both fold-change magnitude and statistical significance.

Temporal trends in cell-type variability were visualized by computing rolling normalized variance curves across pseudotime, using a sliding window encompassing 20% of the ordered cell population. This smoothed measure was plotted for the top five variance-enriched cell types per trajectory, with dashed vertical lines indicating the corresponding branch points.

These curves highlight localized bursts in variability at bifurcation zones, indicating elevated heterogeneity in specific cell types, potentially reflective of lineage priming, fate conflict, or transitional plasticity. While these visualizations validated the localization of dynamic variability to branch points, the plots alone did not provide accurate insights and required complementary statistical analysis for interpretation.

# Use the correct branch transition times from the branch point identification step
branch1_time <- transitions$Branch_1
branch2_time <- transitions$Branch_2

# Define a larger transition window (e.g., ±10% of the pseudotime range)
transition_window <- 0.10 * max(coldat$pseudosize_pca)  # Increase window size to 10%

# --- Step 1: Compute Normalized Variance (Var/Mean) for Branch Points ---
compute_norm_variance <- function(cell_type, branch_time) {
  # Global stats
  global_var <- var(cell_props[cell_type, ])
  global_mean <- mean(cell_props[cell_type, ])
  global_norm_var <- global_var / global_mean
  
  # Branch time window stats
  branch_mask <- coldat$pseudosize_pca >= (branch_time - transition_window) & 
                 coldat$pseudosize_pca <= (branch_time + transition_window)
  branch_var <- var(cell_props[cell_type, branch_mask])
  branch_mean <- mean(cell_props[cell_type, branch_mask])
  branch_norm_var <- branch_var / branch_mean
  
  data.frame(
    cell_type = cell_type,
    global_norm_var = global_norm_var,
    branch_norm_var = branch_norm_var,
    fc_branch = branch_norm_var / global_norm_var  # Fold-change in normalized variance
  )
}

# Apply to both trajectories
variance_summary_trajectory1 <- bind_rows(lapply(rownames(cell_props), function(ct) {
  compute_norm_variance(ct, branch1_time)
})) %>%
  arrange(desc(fc_branch))

variance_summary_trajectory2 <- bind_rows(lapply(rownames(cell_props), function(ct) {
  compute_norm_variance(ct, branch2_time)
})) %>%
  arrange(desc(fc_branch))

# --- Step 2: Statistical Testing for Variance at Branch Points ---
# Testing variance changes at Branch 1
test_variance_enrichment_branch1 <- function(cell_type) {
  branch_mask <- coldat$pseudosize_pca >= (branch1_time - transition_window) & 
                 coldat$pseudosize_pca <= (branch1_time + transition_window)
  
  p_val <- car::leveneTest(
    y = cell_props[cell_type, ],
    group = factor(branch_mask, levels = c(FALSE, TRUE))
  )$`Pr(>F)`[1]
  
  data.frame(cell_type = cell_type, p_value = p_val)
}

# Testing variance changes at Branch 2
test_variance_enrichment_branch2 <- function(cell_type) {
  branch_mask <- coldat$pseudosize_pca >= (branch2_time - transition_window) & 
                 coldat$pseudosize_pca <= (branch2_time + transition_window)
  
  p_val <- car::leveneTest(
    y = cell_props[cell_type, ],
    group = factor(branch_mask, levels = c(FALSE, TRUE))
  )$`Pr(>F)`[1]
  
  data.frame(cell_type = cell_type, p_value = p_val)
}

# Apply tests for both branches
variance_enrichment_branch1 <- bind_rows(lapply(rownames(cell_props), test_variance_enrichment_branch1))
variance_enrichment_branch2 <- bind_rows(lapply(rownames(cell_props), test_variance_enrichment_branch2))

# Merge statistical results with variance summary
variance_summary_trajectory1 <- variance_summary_trajectory1 %>%
  left_join(variance_enrichment_branch1, by = "cell_type") %>%
  mutate(p_adj = p.adjust(p_value, method = "BH")) %>%
  arrange(p_value)

variance_summary_trajectory2 <- variance_summary_trajectory2 %>%
  left_join(variance_enrichment_branch2, by = "cell_type") %>%
  mutate(p_adj = p.adjust(p_value, method = "BH")) %>%
  arrange(p_value)

# Plot Normalized Variance Trends for Both Trajectories

# Top 5 cell types for both branches
top_celltypes_trajectory1 <- head(variance_summary_trajectory1$cell_type, 5)
top_celltypes_trajectory2 <- head(variance_summary_trajectory2$cell_type, 5)

# Compute rolling normalized variance for smooth trends
plot_data_trajectory1 <- lapply(top_celltypes_trajectory1, function(ct) {
  idx <- order(coldat$pseudosize_pca)
  props <- cell_props[ct, idx]
  pseudotime <- coldat$pseudosize_pca[idx]
  
  roll_window <- max(10, round(0.2 * length(props)))
  roll_var <- zoo::rollapply(props, width = roll_window, FUN = var, fill = NA, align = "center")
  roll_mean <- zoo::rollapply(props, width = roll_window, FUN = mean, fill = NA, align = "center")
  
  data.frame(
    cell_type = ct,
    pseudotime = pseudotime,
    norm_variance = roll_var / roll_mean
  )
}) %>% bind_rows()

plot_data_trajectory2 <- lapply(top_celltypes_trajectory2, function(ct) {
  idx <- order(coldat$pseudosize_pca)
  props <- cell_props[ct, idx]
  pseudotime <- coldat$pseudosize_pca[idx]
  
  roll_window <- max(10, round(0.2 * length(props)))
  roll_var <- zoo::rollapply(props, width = roll_window, FUN = var, fill = NA, align = "center")
  roll_mean <- zoo::rollapply(props, width = roll_window, FUN = mean, fill = NA, align = "center")
  
  data.frame(
    cell_type = ct,
    pseudotime = pseudotime,
    norm_variance = roll_var / roll_mean
  )
}) %>% bind_rows()

# Plot for trajectory 1 (Branch 1)
rolling_variance_branch1 <- 
  ggplot(plot_data_trajectory1, aes(x = pseudotime, y = norm_variance, color = cell_type)) +
  geom_line(linewidth = 1) +
  geom_vline(xintercept = branch1_time, linetype = "dashed", color = "blue") +
  labs(
    title = "Normalized Variance around Branch Point 1 in asexual trajectory",
    x = "Pseudotime",
    y = "Normalized Variance",
    color = "Cell Type"
  ) +
  theme_minimal() +
  theme(
    text = element_text(family = "Helvetica"),
    plot.title = element_text(hjust = 0.5, face = "bold"),  
    panel.border = element_rect(color = "black", fill = NA, linewidth = 0.5),  
    plot.background = element_rect(color = "black", fill = NA, linewidth = 0.5),
    legend.position = "bottom"
  )

# Plot for trajectory 2 (Branch 2)
rolling_variance_branch2 <-
  ggplot(plot_data_trajectory2, aes(x = pseudotime, y = norm_variance, color = cell_type)) +
  geom_line(linewidth = 1) +
  geom_vline(xintercept = branch2_time, linetype = "dashed", color = "red") +
  labs(
    title = "Normalized Variance around Branch Point 2 in sexual trajectory",
    x = "Pseudotime",
    y = "Normalized Variance",
    color = "Cell Type"
  ) +
  theme_minimal() +
  theme(
    text = element_text(family = "Helvetica"),
    plot.title = element_text(hjust = 0.5, face = "bold"),  
    panel.border = element_rect(color = "black", fill = NA, linewidth = 0.5),  
    plot.background = element_rect(color = "black", fill = NA, linewidth = 0.5),
    legend.position = "bottom"
  )

rolling_variance_branch1

rolling_variance_branch2

if (!dir.exists("variance_output")) dir.create("variance_output")

ggsave("variance_output/rolling_variance_branch1.png", plot = rolling_variance_branch1, width = 8, height = 6, dpi = 300)
ggsave("variance_output/rolling_variance_branch2.png", plot = rolling_variance_branch2, width = 8, height = 6, dpi = 300)

4.2. Negative Binomial Fit

To model the abundance a cell type over pseudotime within a trajectory, a negative binomial regression was applied. This approach is appropriate due to the overdispersion commonly observed in single-cell count data, where the variance exceeds the mean, violating the assumptions of a Poisson distribution.

The negative binomial model is defined as:

\[ Y_i \sim \text{NB}(\mu_i, \theta) \]

where:
- \(Y_i\) is the observed count for embryo \(i\),
- \(\mu_i\) is the expected value,
- \(\theta\) is the dispersion parameter (higher \(\theta\) implies lower overdispersion).

A spline-based model was fitted to capture nonlinear trends over pseudotime:

\[ \log(\mu_i) = \beta_0 + f(\text{pseudosize}_i) \]

where \(f(\cdot)\) is a natural spline basis function with 3 degrees of freedom. The model was compared to a null model with no pseudotime dependence using a likelihood ratio test, and a pseudo-\(R^2\) was computed to quantify model fit:

\[ \text{Pseudo-}R^2 = 1 - \frac{\log \mathcal{L}_{\text{model}}}{\log \mathcal{L}_{\text{null}}} \]

where \(\mathcal{L}\) denotes the likelihood of the respective models.

Model predictions were visualized over a dense grid of pseudotime values. Expected counts and variances were extracted using:

\[ \text{Var}(Y_i) = \mu_i \left(1 + \frac{\mu_i}{\theta} \right) \] Confidence intervals were simulated by drawing 100,000 samples from the fitted model to estimate the expected mean and 95% bounds per embryo. The final visualization shows the observed counts, predicted means, and simulated confidence bands, effectively capturing uncertainty and overdispersion in the model fit.

The model successfully captured the variance across pseudotime in the sexual trajectory, supporting its relevance for modeling cell type-specific dynamics.

Here, the cell type testes is shown as an illustrative example due to its clear pseudotime-dependent behavior and biological relevance to the sexual developmental fate. Its abundance profile provides a representative case of the model’s ability to detect structured variation. The full code and results for all cell types are included in the accompanying .Rmd file.

library(VGAM)
library(dplyr)
library(ggplot2)

# Set cell type and trajectory
current_cell_type <- "Testes"
trajectory_name <- "sexual"

# Get samples in the asexual trajectory
trajectory_samples <- trajectories[[trajectory_name]]$samples

# Filter colData for trajectory samples
cell_count_df <- colData(cds) %>%
  as.data.frame() %>%
  filter(rownames(.) %in% trajectory_samples) %>%
  mutate(
    cells = counts(cds)[current_cell_type, rownames(.)],
    cell_type = current_cell_type,
    total_cells = colSums(counts(cds))[rownames(.)],
    embryo = sample,
    pseudosize_pca = pseudosize_pca,
    genotype = 'pmor'
  )

# Fit negative binomial model
fit <- VGAM::vglm(cells ~ sm.ns(pseudosize_pca, df = 3),
                  data = cell_count_df,
                  family = negbinomial(zero = NULL),
                  trace = FALSE)

# Null model
fit.null <- VGAM::vglm(cells ~ 1,
                       data = cell_count_df,
                       family = negbinomial(zero = NULL),
                       trace = FALSE)

# Likelihood ratio test and pseudo R^2
lr.obj <- lrtest(fit, fit.null)
test.stat <- lr.obj@Body$Chisq[2]
p.value <- lr.obj@Body$`Pr(>Chisq)`[2]
pseudo_R2 <- 1 - (logLik(fit) / logLik(fit.null))

# Generate smooth prediction over pseudotime
fake_df <- data.frame(pseudosize_pca = seq(min(cell_count_df$pseudosize_pca, na.rm = TRUE),
                                           max(cell_count_df$pseudosize_pca, na.rm = TRUE),
                                           length.out = 94)) %>%
  mutate(embryo = paste('dummy', row_number(), sep = '-')) %>%
  column_to_rownames(var = "embryo")

# Predict from the model
pred_df <- as.data.frame(predict(fit, fake_df))
pred_df$pred_mu <- exp(pred_df[,1])
pred_df$pred_size <- exp(pred_df[,2])
pred_df$pred_cells <- pred_df$pred_mu
pred_df$pred_var <- pred_df$pred_mu * (1 + pred_df$pred_mu / pred_df$pred_size)

fake_df$cells <- pred_df$pred_cells
fake_df$pred_var <- pred_df$pred_var
fake_df$ci_upper <- pred_df$pred_cells + 2 * sqrt(fake_df$pred_var)
fake_df$ci_lower <- pred_df$pred_cells - 2 * sqrt(fake_df$pred_var)

# Simulation
sim_res <- as.matrix(simulate(fit, nsim = 100000))
cell_count_df$cells_per_embryo <- apply(sim_res, 1, mean)
cell_count_df$cells_per_embryo.stddev <- apply(sim_res, 1, sd)
cell_count_df$ci_lower_sim <- apply(sim_res, 1, quantile, probs = 0.025)
cell_count_df$ci_upper_sim <- apply(sim_res, 1, quantile, probs = 0.975)

# Plot
negative_binomial <- ggplot() +
  geom_ribbon(data = cell_count_df,
              aes(x = pseudosize_pca,
                  ymin = ci_lower_sim,
                  ymax = ci_upper_sim),
              alpha = 0.4, fill = '#207394') +
  geom_line(data = cell_count_df,
            aes(x = pseudosize_pca, y = cells_per_embryo),
            color = '#207394') +
  geom_point(data = cell_count_df,
             aes(x = pseudosize_pca, y = cells),
             col = 'black', pch = 21, fill = '#207394', size = 2.5, stroke = 1) +
  labs(title = paste0("Negative Binomial Fit for ", current_cell_type, " in ", trajectory_name, " trajectory"),
       y = "Cells per worm", x = "Pseudotime (pseudosize_pca)") +
  theme_minimal() +
  theme(
    text = element_text(family = "Helvetica"),
    plot.title = element_text(hjust = 0.5, face = "bold"),  
    panel.border = element_rect(color = "black", fill = NA, linewidth = 0.5),  
    plot.background = element_rect(color = "black", fill = NA, linewidth = 0.5)  
  )


ggsave("variance_output/negative_binomial.png", plot = negative_binomial, width = 8, height = 6, dpi = 300)

negative_binomial

NA
NA

4.3. Beta Binomial Fit

This modelling approach is particularly appropriate when modeling compositional data, where the number of observed cells of a given type is constrained by a total count per sample. The beta-binomial regression approach explicitly accounts for overdispersion and sampling competition among cell types, making it an appropriate tool for capturing the biological and technical variability in cell type proportions across pseudotime and fate trajectories.

Unlike the negative binomial model—which assumes that counts vary independently of total size—the beta-binomial explicitly accounts for the binomial nature of the data:

\[ Y_i \sim \text{BetaBinomial}(n_i, p_i, \rho_i) \]

where: - \(Y_i\) is the number of cells in embryo \(i\), - \(n_i\) is the total number of cells observed in that embryo, - \(p_i\) is the expected proportion of cells, - \(\rho_i\) represents overdispersion (i.e., correlation among trials).

This formulation captures both the mean proportion and extra-binomial variance due to biological or technical heterogeneity. The expected mean and variance are:

\[ \begin{aligned} \mathbb{E}[Y_i] &= n_i p_i \\ \text{Var}(Y_i) &= n_i p_i (1 - p_i)(1 + (n_i - 1)\rho_i) \end{aligned} \]

Smooth functions of pseudotime were used to model both \(p_i\) and \(\rho_i\), allowing non-linear trends in cell proportions to be captured along developmental time.

Biologically, this model is well-suited for capturing regulatory or developmental constraints on cell-type commitment, where an increase in one cell type necessitates a decrease in others. It is particularly useful for assessing relative changes in abundance rather than absolute cell numbers.

Model performance was evaluated using a likelihood ratio test against a null model and via a pseudo-\(R^2\) metric. Confidence intervals and variability bands were obtained through simulation from the fitted distribution.

This model effectively captured the shape and dispersion of cell proportion across pseudotime, offering more appropriate inference than count-based models like the negative binomial when compositional constraints are present.

library(VGAM)
library(dplyr)
library(ggplot2)
library(tibble)
library(tidyr)

# Set cell type and trajectory
current_cell_type <- "Testes"
trajectory_name <- "sexual"

# Get samples in the selected trajectory
trajectory_samples <- trajectories[[trajectory_name]]$samples

# Filter colData for selected trajectory samples
cell_count_df <- colData(cds) %>%
  as.data.frame() %>%
  filter(rownames(.) %in% trajectory_samples) %>%
  mutate(
    cells = counts(cds)[current_cell_type, rownames(.)],
    cell_type = current_cell_type,
    total_cells = colSums(counts(cds))[rownames(.)],
    embryo = sample,
    pseudosize_pca = pseudosize_pca,
    genotype = 'pmor'
  )

# Fit beta-binomial model
fit <- VGAM::vglm(cbind(cells, total_cells - cells) ~ sm.ns(pseudosize_pca, df = 3),
                  data = cell_count_df,
                  family = betabinomial(zero = NULL),
                  trace = FALSE)

# Null model
fit.null <- VGAM::vglm(cbind(cells, total_cells - cells) ~ 1,
                       data = cell_count_df,
                       family = betabinomial(zero = NULL),
                       trace = FALSE)

# Likelihood ratio test and pseudo R^2
lr.obj <- VGAM::lrtest(fit, fit.null)
test.stat <- lr.obj@Body$Chisq[2]
p.value <- lr.obj@Body$`Pr(>Chisq)`[2]
pseudo_R2 <- 1 - (logLik(fit) / logLik(fit.null))

# Evaluation results
mod_eval <- tibble(
  test.stat = test.stat,
  p.value = p.value,
  pseudo_R2 = pseudo_R2
)

print(mod_eval)

# Generate smooth prediction over pseudotime
fake_df <- data.frame(pseudosize_pca = seq(min(cell_count_df$pseudosize_pca, na.rm = TRUE),
                                           max(cell_count_df$pseudosize_pca, na.rm = TRUE),
                                           length.out = 94)) %>%
  mutate(embryo = paste('dummy', row_number(), sep = '-')) %>%
  column_to_rownames(var = "embryo")

# Predict from model
pred_df <- as.data.frame(predict(fit, fake_df))

# Recover natural-scale parameters
mean_cells <- mean(cell_count_df$total_cells, na.rm = TRUE)
pred_df$pred_mu <- plogis(pred_df[,1])
pred_df$pred_rho <- plogis(pred_df[,2])
pred_df$pred_cells <- pred_df$pred_mu * mean_cells
pred_df$pred_var <- mean_cells * pred_df$pred_mu * (1 - pred_df$pred_mu) *
                    (1 + (mean_cells - 1) * pred_df$pred_rho)

# Add to fake_df
fake_df$cells <- pred_df$pred_cells
fake_df$pred_var <- pred_df$pred_var
fake_df$ci_upper <- pred_df$pred_cells + 2 * sqrt(pred_df$pred_var)
fake_df$ci_lower <- pred_df$pred_cells - 2 * sqrt(pred_df$pred_var)
fake_df$n <- mean_cells

# Simulate from beta-binomial
nsim <- 10000
set.seed(123)
sim_res <- matrix(nrow = nrow(fake_df), ncol = nsim)

epsilon <- 1e-6

for (i in 1:nrow(fake_df)) {
  mu <- max(min(pred_df$pred_mu[i], 1 - epsilon), epsilon)
  rho <- max(min(pred_df$pred_rho[i], 1 - epsilon), epsilon)
  n <- as.integer(fake_df$n[i])
  
  shape_factor <- (1 - rho) / rho
  shape1 <- mu * shape_factor
  shape2 <- (1 - mu) * shape_factor

  sim_res[i, ] <- if (is.na(shape1) || is.na(shape2) || shape1 <= 0 || shape2 <= 0) {
    rbinom(nsim, size = n, prob = mu)
  } else {
    rbetabinom.ab(nsim, size = n, shape1 = shape1, shape2 = shape2)
  }
}

# Attach simulation results
fake_df$cells_per_embryo <- rowMeans(sim_res)
fake_df$cells_per_embryo.stddev <- apply(sim_res, 1, sd)
fake_df$ci_lower_sim <- apply(sim_res, 1, quantile, probs = 0.025)
fake_df$ci_upper_sim <- apply(sim_res, 1, quantile, probs = 0.975)

# Final plot
beta_binomial <- ggplot() +
  geom_ribbon(data = fake_df,
              aes(x = pseudosize_pca,
                  ymin = ci_lower_sim,
                  ymax = ci_upper_sim),
              alpha = 0.4, fill = '#207394') +
  geom_line(data = fake_df,
            aes(x = pseudosize_pca, y = cells_per_embryo),
            color = '#207394') +
  geom_point(data = cell_count_df,
             aes(x = pseudosize_pca, y = cells),
             col = 'black', pch = 21, fill = '#207394', size = 2.5, stroke = 1) +
  labs(title = paste0("Beta Binomial Fit for ", current_cell_type, " in ", trajectory_name, " trajectory"),
       y = "Cells per worm", x = "Pseudotime (pseudosize_pca)") +
  theme_minimal() +
  theme(
    text = element_text(family = "Helvetica"),
    plot.title = element_text(hjust = 0.5, face = "bold"),  
    panel.border = element_rect(color = "black", fill = NA, linewidth = 0.5),  
    plot.background = element_rect(color = "black", fill = NA, linewidth = 0.5)  
  )

beta_binomial


beta_binomial_extra <- ggplot(cell_count_df) + 
  # overly conservative CI ribbon (mean ± CI upper)
  geom_ribbon(data = fake_df,
              aes(x = pseudosize_pca,
                  ymin = cells - ci_upper,
                  ymax = cells + ci_upper),
              alpha = 0.25, fill = '#444444') +
  
  # plot ±1 SD from simulations
  geom_ribbon(data = fake_df,
              aes(x = pseudosize_pca,
                  ymin = cells_per_embryo - cells_per_embryo.stddev,
                  ymax = cells_per_embryo + cells_per_embryo.stddev),
              alpha = 0.5) +
  
  # 95% confidence interval from simulation
  geom_ribbon(data = fake_df,
              aes(x = pseudosize_pca,
                  ymin = ci_lower_sim,
                  ymax = ci_upper_sim),
              alpha = 0.5) +

  # mean fitted abundance over pseudotime
  geom_line(data = fake_df,
            aes(x = pseudosize_pca, y = cells)) +

  # observed data points
  geom_point(aes(x = pseudosize_pca, y = cells),
             col = 'black', pch = 21, fill = '#888888', size = 2.5, stroke = 1) +
  labs(title = paste0("Beta Binomial Fit for ", current_cell_type, " in ", trajectory_name, " trajectory"),       y = "Cells per worm", x = "Pseudotime (pseudosize_pca)") +
  theme_minimal() + # or theme_clean if defined 
  theme(
    text = element_text(family = "Helvetica"),
    plot.title = element_text(hjust = 0.5, face = "bold"),  
    panel.border = element_rect(color = "black", fill = NA, linewidth = 0.5),  
    plot.background = element_rect(color = "black", fill = NA, linewidth = 0.5)  
  )

beta_binomial_extra

ggsave("variance_output/beta_binomial.png", plot = beta_binomial, width = 8, height = 6, dpi = 300)
ggsave("variance_output/beta_binomial_extra.png", plot = beta_binomial_extra, width = 8, height = 6, dpi = 300)

5. A Combined Analysis for Abundance and Variance

To detect localized shifts in cell type abundance and variation bifurcations, a branch-centered differential analysis was applied across three major pseudotemporal trajectories: sexual, asexual, and early development. Branch points were defined from annotated pseudotime transitions, and a symmetric window was centered on the corresponding pseudotime coordinate. The window was iteratively expanded until it included at least five cells from the target trajectory, ensuring sufficient statistical power while preserving local resolution.

Cell type abundances within the window were compared to those outside the window (within the same trajectory) using non-parametric tests. The Wilcoxon rank-sum test assessed differences in central tendency, while Levene’s test evaluated differences in variance. These distribution-free methods are robust to sparsity, outliers, and heterogeneity common in single-cell data, but require a minimum sample size to yield stable p-values and avoid inflated false positives. A five-cell threshold was therefore imposed to satisfy these assumptions and maintain interpretability.

For each cell type, log\(_2\) fold changes in both mean and variance were calculated between in-window and out-of-window groups. P-values from both tests were integrated into a composite significance score:

\[ p_{\text{sum}} = -\log_{10}(p_{\text{mean}} + 10^{-10}) - \log_{10}(p_{\text{var}} + 10^{-10}) \]

Cell types were ranked by this combined score and stratified into empirical quantile tiers (e.g., top 10%, top 25%) to highlight the most significantly altered populations. These results were visualized as two-dimensional scatter plots with log\(_2\) fold change in mean and variance on the x- and y-axes, respectively, and point size encoding the \(p_{\text{sum}}\) score. Dashed lines at zero served as visual references for no change.

To assess window specificity, the overlap between window-included cells and trajectory membership was quantified. Cells within the pseudotime window but outside the target trajectory were examined by cluster identity to evaluate possible contamination from adjacent developmental programs.

This framework enables statistically robust identification of cell types that exhibit local shifts in abundance and variability at lineage bifurcations, providing insight into candidate regulators of developmental transitions.

Trajectory Cell Types
Early Development
Prebranch_2
Cathepsin+ 5, Parenchymal 2, Neural 1, Neural 2, Muscle 3, Intestine 1, Neural 6, Intestine 6, Epidermal 1, Epidermal 4, Muscle 2, Neoblast 3, Muscle 5
Asexual
Branch_1
Muscle 2, Neoblast 4, Muscle 3, Neural 1, Muscle 5, Neural 6, Neural 2, Intestine 7, Epidermal 8, Cathepsin+ 3, Neural 3, Cathepsin+ 4, Nueral 7
Sexual
Branch_2
Muscle 2, Epidermal 5, Neural 1, Muscle 3, Testes, Neural 2, Neoblast 2, Parenchymal 5, Neural 3, Size specific 2, Neural 9, Epidermal 1, Nueral 7, Cathepsin+ 2

# Combined plot
plot_branchpoint_in_trajectory <- function(trajectory_key, branch_name, min_samples = 5, label_top_n = "all", point_alpha = 0.8, base_size = 14) {
  branch_time <- transitions[[branch_name]]
  clusters_in_traj <- trajectories[[trajectory_key]]$branches
  traj_samples <- rownames(coldat)[coldat$cluster %in% clusters_in_traj]
  traj_coldat <- coldat[traj_samples, ]
  
  find_adequate_window <- function(branch_time, min_samples) {
    window_size <- 0.05 * max(coldat$pseudosize_pca)
    samples_in_window <- 0
    max_iterations <- 20
    iteration <- 0
    while (samples_in_window < min_samples && iteration < max_iterations) {
      in_window <- dplyr::between(traj_coldat$pseudosize_pca, 
                                  branch_time - window_size, 
                                  branch_time + window_size)
      samples_in_window <- sum(in_window)
      if (samples_in_window < min_samples) {
        window_size <- window_size * 1.5
      }
      iteration <- iteration + 1
    }
    return(window_size)
  }
  
  transition_window <- find_adequate_window(branch_time, min_samples)
  in_branch <- dplyr::between(traj_coldat$pseudosize_pca, 
                              branch_time - transition_window, 
                              branch_time + transition_window)

  results <- rownames(cell_props) %>%
    purrr::map_dfr(function(ct) {
      vals <- cell_props[ct, traj_samples]
      if (sum(in_branch) < 3 || sum(!in_branch) < 3) {
        return(data.frame(cell_type = ct, log2_mean_fc = NA_real_, log2_var_fc = NA_real_, p_sum = NA_real_))
      }
      mean_fc <- tryCatch((mean(vals[in_branch], na.rm = TRUE) + 1e-6) / (mean(vals[!in_branch], na.rm = TRUE) + 1e-6), error = function(e) NA_real_)
      mean_p <- tryCatch(wilcox.test(vals[in_branch], vals[!in_branch])$p.value, error = function(e) NA_real_)
      var_fc <- tryCatch((var(vals[in_branch], na.rm = TRUE) + 1e-6) / (var(vals[!in_branch], na.rm = TRUE) + 1e-6), error = function(e) NA_real_)
      var_p <- tryCatch(car::leveneTest(vals ~ factor(in_branch))$`Pr(>F)`[1], error = function(e) NA_real_)
      data.frame(cell_type = ct, log2_mean_fc = log2(mean_fc), log2_var_fc = log2(var_fc), p_sum = -log10(mean_p + 1e-10) + -log10(var_p + 1e-10))
    }) %>%
    dplyr::filter(!is.na(p_sum)) %>%
    dplyr::arrange(desc(p_sum))

  plot_data <- results %>%
    dplyr::mutate(
      significance = dplyr::case_when(
        p_sum > quantile(p_sum, 0.9, na.rm = TRUE) ~ "Top 10%",
        p_sum > quantile(p_sum, 0.75, na.rm = TRUE) ~ "Top 25%",
        TRUE ~ "Not significant"
      ),
      significance = factor(significance, levels = c("Not significant", "Top 25%", "Top 10%"))
    )

  y_range <- range(plot_data$log2_var_fc, na.rm = TRUE)
  x_range <- range(plot_data$log2_mean_fc, na.rm = TRUE)
  y_expansion <- diff(y_range) * 0.2
  x_expansion <- diff(x_range) * 0.2

  p <- ggplot2::ggplot(plot_data, aes(x = log2_mean_fc, y = log2_var_fc)) +
    ggplot2::geom_point(aes(size = p_sum, color = significance, fill = significance), alpha = point_alpha, shape = 21) +
    {
      if (label_top_n == "all") {
        ggrepel::geom_text_repel(
          aes(label = cell_type),
          size = 3.5,
          min.segment.length = 0.05,
          box.padding = 0.35,
          point.padding = 0.2,
          segment.size = 0.3,
          max.overlaps = Inf,
          segment.color = "grey50",
          segment.alpha = 0.4,
          force = 2,
          max.time = 10,
          max.iter = 100000
        )
      } else {
        ggrepel::geom_text_repel(
          data = head(plot_data, label_top_n),
          aes(label = cell_type),
          size = 3.8,
          box.padding = 0.4,
          point.padding = 0.3,
          force = 2
        )
      }
    } +
    ggplot2::geom_hline(yintercept = 0, linetype = "dashed", color = "grey40", linewidth = 0.3) +
    ggplot2::geom_vline(xintercept = 0, linetype = "dashed", color = "grey40", linewidth = 0.3) +
    ggplot2::scale_size_continuous(name = "-log10(p-value sum)", range = c(1.5, 6), breaks = scales::pretty_breaks(n = 4)) +
    ggplot2::scale_color_manual(name = "Significance", values = c("Not significant" = "grey70", "Top 25%" = "#F28E2B", "Top 10%" = "#E15759")) +
    ggplot2::scale_fill_manual(name = "Significance", values = c("Not significant" = "grey90", "Top 25%" = "#F28E2B", "Top 10%" = "#E15759")) +
    ggplot2::coord_cartesian(
      xlim = c(x_range[1] - x_expansion, x_range[2] + x_expansion),
      ylim = c(y_range[1] - y_expansion, y_range[2] + y_expansion),
      expand = FALSE
    ) +
    ggplot2::labs(
      title = paste("Branch Analysis in", trajectory_key),
      subtitle = sprintf("Focusing on: %s at pseudotime %.2f\nWindow: ±%.2f (%d trajectory samples)", branch_name, branch_time, transition_window, sum(in_branch)),
      x = expression(bold("Log"[2]*" Mean Fold Change")),
      y = expression(bold("Log"[2]*" Variance Fold Change")),
      caption = ifelse(label_top_n == "all", "All cell types labeled", paste("Top", label_top_n, "most significant cell types labeled"))
    ) +
    ggplot2::theme_minimal(base_size = base_size) +
    ggplot2::theme(
      legend.position = "right",
      legend.box = "vertical",
      panel.grid.minor = element_blank(),
      panel.grid.major = element_line(linewidth = 0.2),
      panel.border = element_rect(color = "black", fill = NA, linewidth = 0.5), 
      plot.title = element_text(face = "bold", size = 16),
      plot.subtitle = element_text(color = "grey40", size = 12),
      plot.caption = element_text(size = 10),
      aspect.ratio = 0.6
    )

  attr(p, "transition_window") <- transition_window
  attr(p, "branch_time") <- branch_time

  return(list(plot = p, data = plot_data))
}

analysis_plan <- list(
  list(trajectory_key = "sexual",  branch_name = "Branch_2"),
  list(trajectory_key = "asexual", branch_name = "Branch_1"),
  list(trajectory_key = "early_dev", branch_name = "Prebranch_2")
)

results_list <- purrr::map(analysis_plan, function(plan) {
  message("\nProcessing: ", plan$trajectory_key, " - ", plan$branch_name)
  plot_branchpoint_in_trajectory(
    trajectory_key = plan$trajectory_key,
    branch_name = plan$branch_name,
    label_top_n = "all"
  )
})

names(results_list) <- purrr::map_chr(analysis_plan, ~paste0(.x$trajectory_key, "_", .x$branch_name))
plots <- purrr::map(results_list, "plot")
plot_data_list <- purrr::map(results_list, "data")

if (!dir.exists("combined_analysis_output")) dir.create("combined_analysis_output")

# Save PNGs, JPGs, CSVs
purrr::walk2(names(plots), plots, function(name, plot) {
  ggsave(file.path("combined_analysis_output", paste0(name, "_branch_analysis.png")), plot, width = 18, height = 10, dpi = 300)
  ggsave(file.path("combined_analysis_output", paste0(name, "_branch_analysis.jpg")), plot, width = 18, height = 10, dpi = 300)
})

purrr::walk2(names(plot_data_list), plot_data_list, function(name, df) {
  write.csv(df, file = file.path("combined_analysis_output", paste0(name, "_plot_data.csv")), row.names = FALSE)
})



# Create and write diagnostic summary to a text file
diag_file <- file.path("combined_analysis_output", "branch_analysis_diagnostics.txt")
diag_con <- file(diag_file, open = "wt")

writeLines("=== Diagnostic Summary ===", diag_con)

for (i in seq_along(analysis_plan)) {
  plan <- analysis_plan[[i]]
  current_plot <- plots[[names(plots)[i]]]

  # Retrieve attributes from the plot object
  branch_time_val <- attr(current_plot, "branch_time")
  transition_window_val <- attr(current_plot, "transition_window")

  # Get trajectory clusters
  clusters_in_traj <- trajectories[[plan$trajectory_key]]$branches
  in_traj_logical_all_coldat <- coldat$cluster %in% clusters_in_traj

  # Global window around pseudotime
  in_pseudotime_window_all_coldat <- dplyr::between(
    coldat$pseudosize_pca,
    branch_time_val - transition_window_val,
    branch_time_val + transition_window_val
  )

  # Cells in both window and trajectory
  cells_in_window_and_trajectory <- sum(in_traj_logical_all_coldat & in_pseudotime_window_all_coldat)

  # Write diagnostics
  writeLines(sprintf("\nAnalysis: %s_%s", plan$trajectory_key, plan$branch_name), diag_con)
  writeLines(sprintf("  Branch time: %.3f", branch_time_val), diag_con)
  writeLines(sprintf("  Pseudotime window: ±%.3f", transition_window_val), diag_con)
  writeLines(sprintf("  Cells in trajectory: %d", sum(in_traj_logical_all_coldat)), diag_con)
  writeLines(sprintf("  Cells in pseudotime window (global): %d", sum(in_pseudotime_window_all_coldat)), diag_con)
  writeLines(sprintf("  Cells in both trajectory & window: %d", cells_in_window_and_trajectory), diag_con)

  # Special diagnostics for "sexual" only
  if (plan$trajectory_key == "sexual") {
    is_in_sexual_trajectory <- coldat$cluster %in% clusters_in_traj
    is_in_pseudotime_window <- in_pseudotime_window_all_coldat

    outside_cells_idx <- which(is_in_pseudotime_window & !is_in_sexual_trajectory)

    writeLines("  --- Cells in window but NOT in 'sexual' trajectory ---", diag_con)
    writeLines(sprintf("  Count: %d", length(outside_cells_idx)), diag_con)

    if (length(outside_cells_idx) > 0) {
      cluster_counts <- table(coldat$cluster[outside_cells_idx])
      cluster_lines <- capture.output(print(cluster_counts))
      writeLines(paste0("    ", cluster_lines), diag_con)
    } else {
      writeLines("    None", diag_con)
    }

    writeLines("  ------------------------------------------------------", diag_con)
  }
}

close(diag_con)
#message("Diagnostics saved to ", diag_file)



knitr::include_graphics("combined_analysis_output/sexual_Branch_2_branch_analysis.jpg")

knitr::include_graphics("combined_analysis_output/asexual_Branch_1_branch_analysis.jpg")

knitr::include_graphics("combined_analysis_output/early_dev_Prebranch_2_branch_analysis.jpg")

6. Covariation Decomposition using Poisson Lognormal Models

In this study, the pseudotime variable (pseudosize_pca),inferred from 3D PCA embeddings of single-cell profiles, serves as a proxy for worm length or developmental size. Since P. morgani exhibits indeterminate growth and continuous development, the position of a worm along the pseudotime axis roughly reflects its morphological and cellular complexity. Consequently, increases in pseudotime often correlate with larger worm size, higher total cell counts, and more differentiated tissue states.

This inherent coupling between pseudotime and organismal size presents a critical confound in covariance-based analyses of cell type abundance. Many cell populations increase in absolute number as a function of overall worm size, leading to spurious correlations that reflect shared scaling rather than functional coordination.

To disentangle sources of cell type covariation across developmental trajectories, a Poisson lognormal (PLN) modeling framework was applied to decompose total variability into size-dependent and size-independent components. Cell type count matrices were first transposed (samples × cell types) and normalized using log-transformed total cell counts per sample as offsets. A baseline PLN model was then fit to the data to estimate the total latent covariance structure across cell types. This model assumed that the observed counts \(\mathbf{Y}_i\) for sample \(i\) followed a Poisson distribution with log-mean given by:

\[ \log(\boldsymbol{\lambda}_i) = \boldsymbol{\mu} + \log(\mathbf{o}_i) + \mathbf{u}_i, \quad \mathbf{u}_i \sim \mathcal{N}(0, \Sigma_{\text{total}}) \]

where \(\boldsymbol{\mu}\) is the global mean abundance vector, \(\log(\mathbf{o}_i)\) denotes the log-offset for sample library size, and \(\Sigma_{\text{total}}\) captures structured covariation among cell types.

To isolate covariation specifically associated with developmental progression, a second PLN model incorporated the pseudotime coordinate (pseudosize_pca) as a smooth covariate using a natural spline basis with three degrees of freedom:

\[ \log(\boldsymbol{\lambda}_i) = \mathbf{B} \cdot \text{ns}(\text{pseudosize}_i, df=3) + \log(\mathbf{o}_i) + \mathbf{u}_i, \quad \mathbf{u}_i \sim \mathcal{N}(0, \Sigma_{\text{indep}}) \]

In this formulation, covariation driven by pseudotime was captured in the covariance of the model’s fitted values (size-dependent component), while the residual covariance \(\Sigma_{\text{indep}}\) represented size-independent structure. Correlation matrices corresponding to the total, size-dependent, and size-independent covariances were visualized as clustered heatmaps, revealing distinct modules of co-varying cell types.

Notably, the dendrogram derived from the size-independent correlation matrix identified clusters that corresponded precisely to cell types previously implicated as key drivers of the sexual and asexual trajectories in the abundance and combined analyses. This convergence across independent analytical frameworks supports the presence of biologically meaningful modules of co-regulated cell types that exhibit coordinated fluctuations beyond global developmental scaling effects. The PLN-based decomposition thus provided a principled means to separate global pseudotime effects from intrinsic regulatory associations among cell types, offering new insight into the organization of cell fate programs.


knitr::include_graphics("covariance_output/heatmap_total_cor.png")

knitr::include_graphics("covariance_output/heatmap_size_dep_cor.png")

knitr::include_graphics("covariance_output/heatmap_size_indep_cor.png")

knitr::include_graphics("covariance_output/dendrogram.png")

7. Conclusion

This study establishes a robust and generalizable analytical framework for investigating the cellular dynamics underlying developmental bifurcations in Phagocata morgani. By leveraging a meticulously generated, high-resolution single-cell size atlas and utilizing morphological size as a proxy for pseudotime, this framework provides a multidimensional perspective on reproductive fate commitment in an organism exhibiting indeterminate growth.

The approach integrates multiple complementary statistical strategies: negative and beta-binomial regression models effectively capture nonlinear abundance and compositional dynamics across pseudotime, while Poisson lognormal (PLN) models decompose cell type covariation into size-dependent and size-independent components. This modeling architecture enables a principled separation of global scaling effects from intrinsic regulatory associations, thereby enhancing the resolution of cellular programs involved in developmental decisions.

Several key insights emerge from this analysis:

  • The delineation of four distinct cellular states, including the identification of a transitional “pre-commitment” phase (Prebranch_2), redefines early developmental structure and highlights shifts in cellular composition that precede overt sexual differentiation.

  • Localized changes in both mean abundance and variability of specific cell type (particularly within the sexual trajectory) reveal transient enrichment and increased heterogeneity at lineage branch points. These patterns suggest critical roles for early progenitor states and reflect underlying fate plasticity and asynchronous cellular transitions.

  • A composite analysis of differential abundance and variance identified cell types such as Testes, Parenchymal 5, and Size-specific 1–3 as prominent regulators of the sexual trajectory, exhibiting coordinated changes in abundance, dispersion, and residual covariance.

  • A particularly novel contribution from the PLN-based decomposition further highlighted that these cell types cluster within size-independent modules of co-regulation, underscoring their likely functional interdependence and regulatory significance.

This work moves beyond traditional descriptive single-cell analysis by embedding statistical rigor into pseudotime-aware modeling. The combination of distributional modeling, local windowed comparisons, and covariance decomposition delivers a multifaceted understanding of cell state transitions. Collectively, the findings not only pinpoint candidate cellular drivers of bifurcation but also establish a versatile and extensible framework applicable to other systems characterized by continuous development or regenerative capacity.

This integrative approach lays a computational foundation for future studies seeking to mechanistically dissect fate commitment, cellular regulatory network functions, and the architecture of developmental plasticity in planaria.

8. Limitations of the Study

The present study is centered on establishing a computational and mathematical framework. Consequently, inherent limitations constrain the immediate biological interpretability of the results.

  • A few of the cell type annotations remain provisional, requiring further experimental validation to ensure accurate biological interpretation.

  • Pseudotime, while correlated with worm size and developmental progression, does not fully capture the complete biological heterogeneity or lineage-specific complexity inherent to the system.

  • Data sparsity and limited sample sizes, particularly for rare or transient populations, may reduce sensitivity to subtle but biologically relevant signals.

  • Modeling assumptions—including spline degrees of freedom, distributional choices, and window parameters—impact the robustness and sensitivity of findings and warrant further tuning and validation.

Future work should focus on integrating higher-resolution cell type annotations, incorporating multi-omics data, and expanding sample sizes to enhance statistical power. Additionally, experimental perturbations guided by the identified candidate cell types will be critical for validating mechanistic roles in fate bifurcations.

Data

The processed data and analysis scripts are available on GitHub.

Future Work

The size-independent covariance matrix derived from Poisson lognormal modeling of cell type abundance data serves as a critical tool to identify coordinated relationships among cell types. Building on this, a perturbation-driven in silico simulation framework can be developed where synthetic worms are generated by sampling from multivariate distributions parameterized by empirically observed means and covariances of cell type abundances.

This method preserves intrinsic cellular abundance correlations and enables systematic perturbations by modulating abundance vectors of cell types identified through the covariance matrix, either jointly or individually. Modulating these vectors within synthetic worms allows computational evaluation of how targeted perturbations influence pseudotemporal developmental trajectories and lineage bifurcation decisions between sexual and asexual fates.

Such simulations provide a hypothesis-driven platform to dissect the mechanistic contributions of specific cell populations, predict system-level responses to compositional changes, and guide focused experimental validations. This framework offers a robust means to explore compensatory networks and identify candidate driver populations that regulate reproductive fate outcomes in vivo.

Acknowledgements

This work was made possible through the support and wonderful lab environment provided by the Dorrity Group at EMBL. Special appreciation and gratitude goes to Mike and Gaurav for their timely mentorship, insightful discussions, and steady guidance throughout this work. Their support and encouragement played a key role in shaping both the scientific direction and execution of this study.

Author Details

LS0tCnRpdGxlOiAiQ2VsbHVsYXIgRHJpdmVycyBvZiBEaXZlcmdlbnQgUmVwcm9kdWN0aXZlIEZhdGVzIGluIF9QLiBtb3JnYW5pXyIKc3VidGl0bGU6ICJJbnRlcm5zaGlwIFJlcG9ydCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdG9jX2RlcHRoOiA2CiAgICB0aGVtZTogZmxhdGx5CiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKLS0tCgpgYGB7ciBjc3MsIHJlc3VsdHM9J2FzaXMnLCBlY2hvPUZBTFNFfQpjYXQoJwo8c3R5bGU+CgovKiBMaWdodCBiYWNrZ3JvdW5kICovCmJvZHkgewogIHRyYW5zaXRpb246IGJhY2tncm91bmQtY29sb3IgMC4zcywgY29sb3IgMC4zczsKfQoKLyogRGFyayBiYWNrZ3JvdW5kICovCmJvZHkuZGFyay1tb2RlIHsKICBjb2xvcjogI2ZmZmZmZjsKICBiYWNrZ3JvdW5kLWNvbG9yOiAjMjIyMjIyOwp9CgovKiBIaWRlIGZpcnN0IGhlYWRpbmcgKi8KI2NvbnRlbnRzIGgxIHsKICBkaXNwbGF5OiBub25lOwp9CgovKiBKdXN0aWZ5IHRleHQgKi8KcCwgYm9keSwgZGl2LCBzcGFuLCB0ZCwgdGggewogIHRleHQtYWxpZ246IGp1c3RpZnk7Cn0KLnRvY2lmeS1pdGVtIHsKICB0ZXh0LWFsaWduOiBsZWZ0Owp9Cgpib2R5LmRhcmstbW9kZSAubGlzdC1ncm91cC1pdGVtIHsKICBjb2xvcjogI2ZmZmZmZjsKICBiYWNrZ3JvdW5kLWNvbG9yOiAjMjIyMjIyOwp9CmJvZHkuZGFyay1tb2RlIC5saXN0LWdyb3VwLWl0ZW0uYWN0aXZlLApib2R5LmRhcmstbW9kZSAubGlzdC1ncm91cC1pdGVtLmFjdGl2ZTpob3ZlciB7CiAgYmFja2dyb3VuZDogIzJjM2U1MDsKfQoKLyogQ29tbW9uIFN0eWxlIGZvciBhbGwgaGVhZGluZ3MgKi8KaDEsIGgyLCBoMywgaDQsIGg1LCBoNiB7CnBhZGRpbmctYm90dG9tOiAxcmVtOwpib3JkZXItYm90dG9tOiAxcHggc29saWQgZ3JleTsKdGV4dC1hbGlnbjogbGVmdDsKfQoKaDMgewogIGZvbnQtc2l6ZTogMzZweDsKfQpoNCB7CiAgZm9udC1zaXplOiAzMHB4Owp9Cmg1IHsKICBmb250LXNpemU6IDI0cHg7Cn0KaDYgewogIGZvbnQtc2l6ZTogMThweDsKfQoKI2hlYWRlciBoMyB7CiAgZm9udC1zaXplOiAyNHB4Owp9CgojaGVhZGVyIGg0IHsKICBmb250LXNpemU6IDE4cHg7Cn0KCiNoZWFkZXIgaDEsCiNoZWFkZXIgaDMsCiNoZWFkZXIgaDQgewogIGJvcmRlcjogbm9uZTsKfQoKI2hlYWRlciBoMXsKdGV4dC1hbGlnbjogbGVmdDsKfQoKYm9keS5ib29rLXZpZXcgI2hlYWRlciBoMyB7CmNvbG9yOiB3aGl0ZTsKfQoKLyogVGFicyBkZXNpZ24gKi8KdWwubmF2LXBpbGxzIHsKICBtYXJnaW4tdG9wOiAycmVtOwogIGJvcmRlcjogMXB4IHNvbGlkIGdyZXk7CiAgYm9yZGVyLXJhZGl1czogNHB4OwogIHBhZGRpbmc6IDFyZW07Cn0KCi8qIFRhYmxlIHN0eWxpbmcgKi8KdGFibGUgewogIHdpZHRoOiAxMDAlOwp9CnRyOm50aC1jaGlsZChldmVuKSB7CiAgYmFja2dyb3VuZC1jb2xvcjogI2QzZDNkMzsKfQp0ci5oZWFkZXIgeyAKYmFja2dyb3VuZDogIzJjM2U1MDsKY29sb3I6IHdoaXRlOwp9CmJvZHkuZGFyay1tb2RlIHRhYmxlIHsKICBiYWNrZ3JvdW5kLWNvbG9yOiAjMzMzOwp9CmJvZHkuZGFyay1tb2RlIHRyOm50aC1jaGlsZChldmVuKSB7CiAgYmFja2dyb3VuZC1jb2xvcjogIzQ0NDsKfQoKLyogTWFpbiBTZWN0aW9uIFN0eWxlcyAgKi8KLnNlY3Rpb24ubGV2ZWwzIHsKICBwYWRkaW5nOiAxcmVtIDByZW07CiAgbWFyZ2luLWJvdHRvbTogMXJlbTsKfQouc2VjdGlvbi5sZXZlbDQsCi5zZWN0aW9uLmxldmVsNSwKLnNlY3Rpb24ubGV2ZWw2IHsKICBwYWRkaW5nOiAwLjVyZW0gMHJlbTsKfQoKLyogVG9nZ2xlIGJ1dHRvbiBzdHlsZSAqLwouZm9vdGVyLWJ0biB7CiAgICBjdXJzb3I6IHBvaW50ZXI7CiAgICBiYWNrZ3JvdW5kOiAjMmMzZTUwOwp9CgojdGhlbWUtc2VsZWN0IHsKIGNvbG9yOiB3aGl0ZTsKfQoKLnRoZW1lLXdyYXBwZXIgewogIGJhY2tncm91bmQgOiAjMmMzZTUwOwogIHBvc2l0aW9uOiBmaXhlZDsKICB6LWluZGV4OiAxMDAwOwogIGxlZnQ6IDBweDsKICBib3R0b206IDBweDsKICBwYWRkaW5nOiAxcmVtIDNyZW0gMXJlbSAycmVtOwogIGRpc3BsYXk6IGZsZXg7CiAganVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuOwogIHdpZHRoOjEwMHZ3Owp9CgoudGhlbWUtd3JhcHBlciBwLAoudGhlbWUtd3JhcHBlciBsYWJlbHsKICBtYXJnaW46IDA7CiAgY29sb3I6IHdoaXRlOwp9Cgpib2R5LmJvb2stdmlldyAuc2VjdGlvbi5sZXZlbDMgewogIGJvcmRlci1yYWRpdXM6IDEycHg7CiAgYm9yZGVyOiAxcHggc29saWQgI0QzRDNEMzsKICBwYWRkaW5nOiAxcmVtIDJyZW07CiAgbWFyZ2luOiAxLjI1cmVtIDByZW07Cn0KCmJvZHkuYm9vay12aWV3IC5zZWN0aW9uLmxldmVsNCwKYm9keS5ib29rLXZpZXcgLnNlY3Rpb24ubGV2ZWw1LApib2R5LmJvb2stdmlldyAuc2VjdGlvbi5sZXZlbDYgewogIHBhZGRpbmc6IDAuNXJlbSAwcmVtIDByZW0gMnJlbTsKfQoKLyogQmx1ZSBIZWFkZXIgU3R5bGVzICovCmJvZHkuYm9vay12aWV3ICNoZWFkZXIgewogICAgYm9yZGVyLXJhZGl1czogMTJweDsKICAgIGJvcmRlcjogMXB4IHNvbGlkIGdyZXk7CiAgICBwYWRkaW5nOiAwcmVtIDJyZW07CiAgICBtYXJnaW46IDI1cHggMCAxcmVtIDA7CiAgICBiYWNrZ3JvdW5kLWltYWdlOiByZXBlYXRpbmctbGluZWFyLWdyYWRpZW50KDkwZGVnLCByZ2JhKDE0MCwxNDAsMTQwLCAwLjEpIDBweCwgcmdiYSgxNDAsMTQwLDE0MCwgMC4xKSAxcHgsdHJhbnNwYXJlbnQgMXB4LCB0cmFuc3BhcmVudCA2MHB4KSxyZXBlYXRpbmctbGluZWFyLWdyYWRpZW50KDBkZWcsIHJnYmEoMTQwLDE0MCwxNDAsIDAuMSkgMHB4LCByZ2JhKDE0MCwxNDAsMTQwLCAwLjEpIDFweCx0cmFuc3BhcmVudCAxcHgsIHRyYW5zcGFyZW50IDYwcHgpLHJlcGVhdGluZy1saW5lYXItZ3JhZGllbnQoMGRlZywgcmdiYSgxNDAsMTQwLDE0MCwgMC4xKSAwcHgsIHJnYmEoMTQwLDE0MCwxNDAsIDAuMSkgMXB4LHRyYW5zcGFyZW50IDFweCwgdHJhbnNwYXJlbnQgMjBweCkscmVwZWF0aW5nLWxpbmVhci1ncmFkaWVudCg5MGRlZywgcmdiYSgxNDAsMTQwLDE0MCwgMC4xKSAwcHgsIHJnYmEoMTQwLDE0MCwxNDAsIDAuMSkgMXB4LHRyYW5zcGFyZW50IDFweCwgdHJhbnNwYXJlbnQgMjBweCksbGluZWFyLWdyYWRpZW50KDkwZGVnLCBoc2woMjEwLCAyOSUsIDI0JSksaHNsKDIxMCwgMjklLCAyNCUpKTsKfQoKYm9keS5ib29rLXZpZXcgI2hlYWRlciBoMSwKYm9keS5ib29rLXZpZXcgI2hlYWRlciBoNCB7CiAgY29sb3I6IHdoaXRlOwogIGJvcmRlcjogbm9uZTsKfQoKLnBsb3RseSB7CiAgd2lkdGg6IDEwMCUgIWltcG9ydGFudDsKICBkaXNwbGF5OiBmbGV4OwogIGp1c3RpZnktY29udGVudDogY2VudGVyOwp9CgpwID4gaW1nIHsKICBkaXNwbGF5OiBibG9jazsKICBtYXJnaW4tbGVmdDogYXV0bzsKICBtYXJnaW4tcmlnaHQ6IGF1dG87Cn0KCjwvc3R5bGU+CicpCmBgYAoKCgpgYGB7ciBqcywgcmVzdWx0cz0nYXNpcycsIGVjaG89RkFMU0V9CmNhdCgnCjxkaXYgY2xhc3M9InRoZW1lLXdyYXBwZXIiPgogIDxwPiBBaXNod2FyeWEgR2lyaXNoIDwvcD4KPGRpdj4KICA8bGFiZWw+U3dpdGNoIFRoZW1lIDogPC9sYWJlbD4KICA8c2VsZWN0IGlkPSJ0aGVtZS1zZWxlY3QiIGNsYXNzPSJmb290ZXItYnRuIj4KICAgIDxvcHRpb24gY2xhc3M9ImZvb3Rlci1idG4iIHZhbHVlPSJsaWdodCI+TGlnaHQ8L29wdGlvbj4KICAgIDxvcHRpb24gY2xhc3M9ImZvb3Rlci1idG4iIHZhbHVlPSJkYXJrIj5EYXJrPC9vcHRpb24+CiAgICA8b3B0aW9uIGNsYXNzPSJmb290ZXItYnRuIiB2YWx1ZT0iYm9vayI+Qm9vazwvb3B0aW9uPgogIDwvc2VsZWN0Pgo8L2Rpdj4KCjwvZGl2PgoKPHNjcmlwdD4KZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoInRoZW1lLXNlbGVjdCIpLmFkZEV2ZW50TGlzdGVuZXIoImNoYW5nZSIsIGZ1bmN0aW9uKCkgewogIGNvbnN0IGJvZHkgPSBkb2N1bWVudC5ib2R5OwogIGNvbnN0IHNlbGVjdGVkID0gdGhpcy52YWx1ZTsKCiAgLy8gUmVtb3ZlIGJvdGggY2xhc3NlcwogIGJvZHkuY2xhc3NMaXN0LnJlbW92ZSgiZGFyay1tb2RlIiwgImJvb2stdmlldyIpOwoKICAvLyBBZGQgY2xhc3MgYmFzZWQgb24gc2VsZWN0aW9uCiAgaWYgKHNlbGVjdGVkID09PSAiZGFyayIpIHsKICAgIGJvZHkuY2xhc3NMaXN0LmFkZCgiZGFyay1tb2RlIik7CiAgfSBlbHNlIGlmIChzZWxlY3RlZCA9PT0gImJvb2siKSB7CiAgICBib2R5LmNsYXNzTGlzdC5hZGQoImJvb2stdmlldyIpOwogIH0KfSk7Cjwvc2NyaXB0PgonKQpgYGAKCgoKCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQojIGtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UpCmBgYAoKCgojIENvbnRlbnRzIHsudGFic2V0IC50YWJzZXQtcGlsbHN9CgojIyBSZXBvcnQKCiMjIyAxLiBJbnRyb2R1Y3Rpb24KCkRldmVsb3BtZW50YWwgYmlmdXJjYXRpb25zIHJlcHJlc2VudCBjcml0aWNhbCB0cmFuc2l0aW9ucyBpbiB3aGljaCBjZWxscyBvciBvcmdhbmlzbXMgZGl2ZXJnZSBpbnRvIGRpc3RpbmN0IHBoZW5vdHlwaWMgZmF0ZXMuIFRoZSBmcmVzaHdhdGVyIHBsYW5hcmlhbiBfUGhhZ29jYXRhIG1vcmdhbmkgKFAuIG1vcmdhbmkpXyB1bmRlcmdvZXMgc3VjaCBhIGJpZnVyY2F0aW9uLCBkZXZlbG9waW5nIGludG8gZWl0aGVyIGFuIGFzZXh1YWwgb3IgYSBzZXh1YWwgcmVwcm9kdWN0aXZlIHBoZW5vdHlwZSwgZWFjaCBhc3NvY2lhdGVkIHdpdGggYSBkaXN0aW5jdCBncm93dGggdHJhamVjdG9yeS4gSG93ZXZlciwgdGhlIG1lY2hhbmlzbXMgdGhhdCBnb3Zlcm4gdGhlc2UgZGl2ZXJnZW50IG91dGNvbWVzLCBwYXJ0aWN1bGFybHkgdGhlIHNwZWNpZmljIGNlbGwgdHlwZXMgdGhhdCBkcml2ZSBjb21taXRtZW50IHRvd2FyZCBlaXRoZXIgZmF0ZSwgcmVtYWluIHBvb3JseSB1bmRlcnN0b29kLgoKKipUaGlzIG5vdGVib29rIHByZXNlbnRzIGEgcXVhbnRpdGF0aXZlIGZyYW1ld29yayBmb3IgaWRlbnRpZnlpbmcgY2VsbC10eXBlLXNwZWNpZmljIGRyaXZlcnMgb2Ygc2V4dWFsIGFuZCBhc2V4dWFsIGdyb3d0aCB0cmFqZWN0b3JpZXMgaW4gX1AuIG1vcmdhbmlfLioqIEEgcGFydGljdWxhciBmb2N1cyBpcyBwbGFjZWQgb24gaWRlbnRpZnlpbmcgY2VsbC10eXBlIGJlaGF2aW91ciBhcm91bmQgdGhlIGJpZnVyY2F0aW9uIHBvaW50cyBhcyB0aGV5IGFyZSByZWdpb25zIGluIHRoZSBkZXZlbG9wbWVudGFsIG1hbmlmb2xkIHdoZXJlIGZhdGUgZGVjaXNpb25zIGFyZSBsaWtlbHkgdG8gb2NjdXIuIEJ5IHN0YXRpc3RpY2FsbHkgZXZhbHVhdGluZyB0aGVzZSB0cmFuc2l0aW9ucywgY2FuZGlkYXRlIGNlbGx1bGFyIHBvcHVsYXRpb25zIHRoYXQgbWF5IGFjdCBhcyBpbnRlcm1lZGlhdGVzIG9yIGRldGVybWluYW50cyBvZiByZXByb2R1Y3RpdmUgZmF0ZSBhcmUgaWRlbnRpZmllZC4KClRoZSBub3RlYm9vayBpcyBvcmdhbml6ZWQgdG8gZ3VpZGUgdGhlIHJlYWRlciB0aHJvdWdoIGVhY2ggc3RlcCBvZiB0aGlzIGFuYWx5c2lzOiBmcm9tIGRhdGEgcHJlcHJvY2Vzc2luZyBhbmQgcHNldWRvdGltZSB0cmFqZWN0b3J5IGluZmVyZW5jZSB0byBjZWxsLXR5cGUgYWJ1bmRhbmNlIG1vZGVsaW5nIGFuZCBzdGF0aXN0aWNhbCBlbnJpY2htZW50IHRlc3RpbmcuIEl0IHNlcnZlcyBhcyBib3RoIGEgY29tcHV0YXRpb25hbCB3b3JrZmxvdyBhbmQgYW4gaW50ZXJwcmV0YXRpdmUgdG9vbCBmb3IgdW5kZXJzdGFuZGluZyB0aGUgY2VsbHVsYXIgZHluYW1pY3MgaW4gcGxhbmFyaWEuCgojIyMjIDEuMS4gQmFja2dyb3VuZAoKRGV2ZWxvcG1lbnQgaW4gX1AuIG1vcmdhbmlfIHByb2NlZWRzIGFsb25nIGRpc3RpbmN0IHRyYWplY3RvcmllcyB0aGF0IGdpdmUgcmlzZSB0byBzZXh1YWwgYW5kIGFzZXh1YWwgcGhlbm90eXBlcy4gVGhlc2UgdHJhamVjdG9yaWVzIGFyZSBzaGFwZWQgYnkgYm90aCBlbnZpcm9ubWVudGFsIGN1ZXMgYW5kIGludHJpbnNpYyBvcmdhbmlzbWFsIHByb3BlcnRpZXMsIHN1Y2ggYXMgYm9keSBzaXplLiBUbyBiZWdpbiBkaXNlbnRhbmdsaW5nIHRoZXNlIGZhY3RvcnMsIHdvcm1zIHdlcmUgbWFpbnRhaW5lZCBhdCBhIGNvbnN0YW50IHRlbXBlcmF0dXJlIG9mIDE3LjXihIMg4oCUIGEgY29uZGl0aW9uIGtub3duIHRvIHN1c3RhaW4gYSBtaXhlZCBwb3B1bGF0aW9uIG9mIHNleHVhbCBhbmQgYXNleHVhbCBpbmRpdmlkdWFscy4gVGhpcyB0ZW1wZXJhdHVyZSB3YXMgc3BlY2lmaWNhbGx5IGNob3NlbiB0byBhbGxvdyBmb3IgdGhlIHNlcGFyYXRpb24gb2Ygc2l6ZS1kZXBlbmRlbnQgZWZmZWN0cyBmcm9tIHRlbXBlcmF0dXJlLWRyaXZlbiB2YXJpYXRpb24gaW4gY2VsbHVsYXIgZGlmZmVyZW50aWF0aW9uIGR5bmFtaWNzLgoKQSBzaW5nbGUtY2VsbCBhdGxhcyB3YXMgY29uc3RydWN0ZWQgZnJvbSB0aGlzIHBvcHVsYXRpb24gYnkgaXNvbGF0aW5nIG51Y2xlaSBmcm9tIGluZGl2aWR1YWwgd29ybXMuIEVhY2ggd29ybSB3YXMgZmxhc2ggZnJvemVuIGFuZCBwcm9jZXNzZWQgaW5kZXBlbmRlbnRseSwgd2l0aCBvbmUgd29ybSBwZXIgd2VsbCBpbiBhIDk2LXdlbGwgcGxhdGUuIFByaW9yIHRvIGZyZWV6aW5nLCBhIHZpZGVvIHJlY29yZGluZyB3YXMgY2FwdHVyZWQgZm9yIGVhY2ggd29ybSwgZW5hYmxpbmcgcXVhbnRpZmljYXRpb24gb2YgbW9ycGhvbG9naWNhbCBmZWF0dXJlcyBzdWNoIGFzIGJvZHkgYXJlYSBhbmQgbGVuZ3RoIHVzaW5nIGEgc3RhbmRhcmRpemVkIGltYWdlIGFuYWx5c2lzIHBpcGVsaW5lLgoKVGhlIHJlc3VsdGluZyBkYXRhc2V0IHdhcyBwcm9jZXNzZWQgaW50byBhIGdlbmUgZXhwcmVzc2lvbiBtYXRyaXggYW5kIHN1YnNlcXVlbnRseSBjb252ZXJ0ZWQgaW50byBhIGNlbGwtdHlwZSBhYnVuZGFuY2UgbWF0cml4LCB3aGVyZSBlYWNoIHJvdyByZXByZXNlbnRzIGFuIGluZGl2aWR1YWwgd29ybSBhbmQgZWFjaCBjb2x1bW4gY29ycmVzcG9uZHMgdG8gYSBicm9hZCBjZWxsIHR5cGUuIFRvIGVuc3VyZSBhbmFseXRpY2FsIHJvYnVzdG5lc3MsIGNlbGwgdHlwZXMgd2l0aCBleHRyZW1lbHkgbG93IGFidW5kYW5jZSAoPDUwIGNlbGxzKSBhY3Jvc3MgYWxsIHNhbXBsZXMgd2VyZSBmaWx0ZXJlZCBvdXQuIFdvcm0tbGV2ZWwgY2VsbCBjb3VudHMgd2VyZSB0aGVuIGFnZ3JlZ2F0ZWQgYmFzZWQgb24gYXNzaWduZWQgY2VsbC10eXBlIGFubm90YXRpb25zLCB5aWVsZGluZyBhIHdvcm0tYnktY2VsbC10eXBlIG1hdHJpeCByZWZsZWN0aW5nIGFic29sdXRlIGNlbGwgY29tcG9zaXRpb24uCgpJbiBwYXJhbGxlbCwgbW9ycGhvbG9naWNhbCBtZWFzdXJlbWVudHMgKHNwZWNpZmljYWxseSB3b3JtIGxlbmd0aCBhbmQgYXJlYSkgd2VyZSBleHRyYWN0ZWQgZm9yIGVhY2ggc2FtcGxlIHRvIHNlcnZlIGFzIGNvdmFyaWF0ZXMgaW4gZG93bnN0cmVhbSBtb2RlbGluZy4gVGhlIHJhdyBjb3VudCBtYXRyaXggd2FzIG5vcm1hbGl6ZWQgdXNpbmcgTW9ub2NsZTMncyBzaXplIGZhY3RvciBlc3RpbWF0aW9uIGZyYW1ld29yayB0byBhY2NvdW50IGZvciBkaWZmZXJlbmNlcyBpbiB0b3RhbCBudWNsZWkgcmVjb3ZlcmVkIHBlciB3b3JtLiBUaGlzIHN0ZXAgY29ycmVjdGVkIGZvciB2YXJpYWJpbGl0eSBpbiBzZXF1ZW5jaW5nIGRlcHRoIGFuZCBvdmVyYWxsIGNlbGwgcmVjb3ZlcnksIGVuYWJsaW5nIG1lYW5pbmdmdWwgY29tcGFyaXNvbnMgb2YgY2VsbC10eXBlIHByb3BvcnRpb25zIGFjcm9zcyB3b3Jtcy4gCgpUaGUgcmVzdWx0aW5nIHNpemUtbm9ybWFsaXplZCBtYXRyaXggZm9ybXMgdGhlIGJhc2lzIGZvciBhbGwgc3Vic2VxdWVudCBhbmFseXNlcy4KCiMjIyMgMS4yLiBHZXR0aW5nIFN0YXJ0ZWQKClRvIGVuc3VyZSByZXByb2R1Y2liaWxpdHkgYW5kIHRyYW5zcGFyZW5jeSwgYWxsIGFuYWx5c2VzIHdlcmUgcGVyZm9ybWVkIHdpdGhpbiBhbiBSTm90ZWJvb2sgZnJhbWV3b3JrIHVzaW5nIFIgKHZlcnNpb24gNC40LjIpLiBUaGUgTW9ub2NsZTMgcGFja2FnZSAoVHJhcG5lbGwgbGFiKSB3YXMgdXRpbGl6ZWQgZm9yIHNpbmdsZS1jZWxsIHRyYWplY3RvcnkgaW5mZXJlbmNlIGFuZCBub3JtYWxpemF0aW9uLiBEZXBlbmRlbmNpZXMgaW5jbHVkaW5nIEJpb2NvbmR1Y3RvciBwYWNrYWdlcyBhbmQgY29tbW9uIGRhdGEgbWFuaXB1bGF0aW9uIGFuZCB2aXN1YWxpemF0aW9uIGxpYnJhcmllcyB3ZXJlIGxvYWRlZCBhcyBkZXRhaWxlZCBiZWxvdy4KCiMjIyMjIDEuMi4xLiBJbnN0YWxsYXRpb24gYW5kIFNldHVwCgpgYGB7ciBpbnN0YWxsYXRpb24gYW5kIHNldHVwfQojIFBhY2thZ2UgSW5zdGFsbGF0aW9uCnJlcXVpcmVkX3BhY2thZ2VzIDwtIGMoCiAgIyBDb3JlIGFuYWx5c2lzCiAgImRwbHlyIiwgInRpZHlyIiwgImRhdGEudGFibGUiLCAiZ2dwbG90MiIsICJ0aWJibGUiLAogICMgVmlzdWFsaXphdGlvbgogICJwbG90bHkiLCAicGhlYXRtYXAiLCAiaHRtbHdpZGdldHMiLCAiZ3JpZEV4dHJhIiwgImRlbmRleHRlbmQiLCAicmVhZHIiLAogICMgRGF0YSBwcm9jZXNzaW5nCiAgIlZHQU0iLCAiem9vIiwgImJyb29tIiwgInJlc2hhcGUyIiwgInB1cnJyIiwgInNwbGluZXMiCikKCiMgSW5zdGFsbCBDUkFOIHBhY2thZ2VzCm5ld19wYWNrYWdlcyA8LSByZXF1aXJlZF9wYWNrYWdlc1shKHJlcXVpcmVkX3BhY2thZ2VzICVpbiUgaW5zdGFsbGVkLnBhY2thZ2VzKClbLCJQYWNrYWdlIl0pXQppZihsZW5ndGgobmV3X3BhY2thZ2VzKSkgewogIGluc3RhbGwucGFja2FnZXMobmV3X3BhY2thZ2VzLCBkZXBlbmRlbmNpZXMgPSBUUlVFKQp9CgojIEluc3RhbGwgQmlvY29uZHVjdG9yIHBhY2thZ2VzCmlmICghcmVxdWlyZU5hbWVzcGFjZSgiQmlvY01hbmFnZXIiLCBxdWlldGx5ID0gVFJVRSkpIHsKICBpbnN0YWxsLnBhY2thZ2VzKCJCaW9jTWFuYWdlciIpCn0KCmJpb2NfcGFja2FnZXMgPC0gYygKICAnQmlvY0dlbmVyaWNzJywgJ0RlbGF5ZWRBcnJheScsICdEZWxheWVkTWF0cml4U3RhdHMnLAogICdsaW1tYScsICdsbWU0JywgJ1M0VmVjdG9ycycsICdTaW5nbGVDZWxsRXhwZXJpbWVudCcsCiAgJ1N1bW1hcml6ZWRFeHBlcmltZW50JywgJ2JhdGNoZWxvcicsICdIREY1QXJyYXknLAogICd0ZXJyYScsICdnZ3Jhc3RyJwopCgpuZXdfYmlvYyA8LSBiaW9jX3BhY2thZ2VzWyEoYmlvY19wYWNrYWdlcyAlaW4lIGluc3RhbGxlZC5wYWNrYWdlcygpWywiUGFja2FnZSJdKV0KaWYobGVuZ3RoKG5ld19iaW9jKSkgewogIEJpb2NNYW5hZ2VyOjppbnN0YWxsKG5ld19iaW9jKQp9CgojIEluc3RhbGwgR2l0SHViIHBhY2thZ2VzCmlmICghcmVxdWlyZU5hbWVzcGFjZSgiZGV2dG9vbHMiLCBxdWlldGx5ID0gVFJVRSkpIHsKICBpbnN0YWxsLnBhY2thZ2VzKCJkZXZ0b29scyIpCn0KCmlmICghcmVxdWlyZU5hbWVzcGFjZSgicmVtb3RlcyIsIHF1aWV0bHkgPSBUUlVFKSkgewogIGluc3RhbGwucGFja2FnZXMoInJlbW90ZXMiKQp9CgpnaXRodWJfcGFja2FnZXMgPC0gYygKICAnY29sZS10cmFwbmVsbC1sYWIvbW9ub2NsZTMnLAogICdwbG4tdGVhbS9QTE5tb2RlbHMnLAogICdjb2xlLXRyYXBuZWxsLWxhYi9ob29rZScKKQoKIyBDaGVjayB3aGljaCBHaXRIdWIgcGFja2FnZXMgbmVlZCBpbnN0YWxsYXRpb24KaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJtb25vY2xlMyIsIHF1aWV0bHkgPSBUUlVFKSkgewogIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YihnaXRodWJfcGFja2FnZXNbMV0pCn0KaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJQTE5tb2RlbHMiLCBxdWlldGx5ID0gVFJVRSkpIHsKICByZW1vdGVzOjppbnN0YWxsX2dpdGh1YihnaXRodWJfcGFja2FnZXNbMl0pCn0KaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJob29rZSIsIHF1aWV0bHkgPSBUUlVFKSkgewogIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YihnaXRodWJfcGFja2FnZXNbM10pCn0KCiMgTG9hZCBhbGwgcGFja2FnZXMKYWxsX3BhY2thZ2VzIDwtIGMocmVxdWlyZWRfcGFja2FnZXMsICJtb25vY2xlMyIsICJQTE5tb2RlbHMiLCAiaG9va2UiKQoKaW52aXNpYmxlKGxhcHBseShhbGxfcGFja2FnZXMsIGZ1bmN0aW9uKHBrZykgewogIGlmICghcmVxdWlyZShwa2csIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkpIHsKICAgIHdhcm5pbmcocGFzdGUoIlBhY2thZ2UiLCBwa2csICJmYWlsZWQgdG8gbG9hZCIpKQogIH0KfSkpCgojIFZlcmlmeSBsb2FkaW5nCmxvYWRlZCA8LSBzYXBwbHkoYWxsX3BhY2thZ2VzLCByZXF1aXJlLCBjaGFyYWN0ZXIub25seSA9IFRSVUUsIHF1aWV0bHkgPSBUUlVFKQppZihhbGwobG9hZGVkKSkgewogIG1lc3NhZ2UoIkFsbCBwYWNrYWdlcyBsb2FkZWQgc3VjY2Vzc2Z1bGx5IikKfSBlbHNlIHsKICB3YXJuaW5nKCJGYWlsZWQgdG8gbG9hZDogIiwgcGFzdGUobmFtZXMobG9hZGVkKVshbG9hZGVkXSwgY29sbGFwc2UgPSAiLCAiKSkKfQoKIyAjIFByaW50IHNlc3Npb24gaW5mbwojIG1lc3NhZ2UoIlxuU2Vzc2lvbiBpbmZvOiIpCiMgc2Vzc2lvbkluZm8oKQoKYGBgCgojIyMjIyAxLjIuMi4gU2V0IFdvcmtpbmcgRGlyZWN0b3J5CgpUaGUgd29ya2luZyBkaXJlY3Rvcnkgd2FzIHNldCB0byBvcmdhbml6ZSBkYXRhIGFuZCByZXN1bHRzIGFwcHJvcHJpYXRlbHkuCgpgYGB7ciB3b3JraW5nIGRpcmVjdG9yeX0KCnNldHdkKCIvVXNlcnMvZ2F1cmF2L0Rvd25sb2Fkcy9yZXBvcnQiKSAjZW50ZXIgeW91ciB3b3JraW5nIGRpcmVjdG9yeQoKYGBgCgojIyMgMi4gVHJhamVjdG9yeSBJbmZlcmVuY2UgVXNpbmcgTW9ub2NsZTMKClRvIGVsdWNpZGF0ZSBncm93dGggcHJvZ3Jlc3Npb24gd2l0aGluIHRoZSBzaW5nbGUtY2VsbCBzaXplIGF0bGFzLCB0cmFqZWN0b3J5IGluZmVyZW5jZSB3YXMgY29uZHVjdGVkIHVzaW5nIE1vbm9jbGUzLiAKKipQcmluY2lwYWwgY29tcG9uZW50IGFuYWx5c2lzIChQQ0EpIGVtYmVkZGluZ3MsIHNwZWNpZmljYWxseSB0aGUgZmlyc3QgdGhyZWUgcHJpbmNpcGFsIGNvbXBvbmVudHMsIHdlcmUgdXRpbGl6ZWQgaW4gcGxhY2Ugb2YgZGVmYXVsdCBVTUFQIGVtYmVkZGluZ3MgdG8gYmV0dGVyIHJlcHJlc2VudCB0aGUgZ2xvYmFsIHN0cnVjdHVyZSBvZiB0aGUgZGF0YS4qKgoKKE5vdGU6IFByaW5jaXBhbCBDb21wb25lbnQgQW5hbHlzaXMgKFBDQSkgd2FzIHNlbGVjdGVkIG92ZXIgVW5pZm9ybSBNYW5pZm9sZCBBcHByb3hpbWF0aW9uIGFuZCBQcm9qZWN0aW9uIChVTUFQKSBlbWJlZGRpbmdzIGZvciB0cmFqZWN0b3J5IGluZmVyZW5jZSBkdWUgdG8gUENB4oCZcyBhYmlsaXR5IHRvIHByZXNlcnZlIGdsb2JhbCBkYXRhIHN0cnVjdHVyZSBhbmQgdmFyaWFuY2UuIFVubGlrZSBVTUFQLCB3aGljaCBlbXBoYXNpemVzIGxvY2FsIG5laWdoYm9yaG9vZCByZWxhdGlvbnNoaXBzIGFuZCBub25saW5lYXIgbWFuaWZvbGQgbGVhcm5pbmcgcHJpbWFyaWx5IGZvciB2aXN1YWxpemF0aW9uLCBQQ0EgcHJvdmlkZXMgYSBsaW5lYXIgcHJvamVjdGlvbiB0aGF0IHJldGFpbnMgdGhlIGxhcmdlc3Qgc291cmNlcyBvZiB2YXJpYXRpb24gYWNyb3NzIHRoZSBlbnRpcmUgZGF0YXNldC4gVGhpcyBjaGFyYWN0ZXJpc3RpYyBpcyBjcnVjaWFsIHdoZW4gbW9kZWxpbmcgZGV2ZWxvcG1lbnRhbCB0cmFqZWN0b3JpZXMsIGFzIGl0IGVuc3VyZXMgdGhhdCB0aGUgcHJpbmNpcGFsIGF4ZXMgcmVwcmVzZW50IG1lYW5pbmdmdWwgYmlvbG9naWNhbCBncmFkaWVudHPigJRzdWNoIGFzIHNpemUgYW5kIGRpZmZlcmVudGlhdGlvbiBzdGF0dXPigJRyYXRoZXIgdGhhbiBmb2N1c2luZyBzb2xlbHkgb24gbG9jYWwgY2x1c3RlcmluZy4gVXNpbmcgUENBIGVtYmVkZGluZ3MgdGh1cyBlbmFibGVzIG1vcmUgcm9idXN0IGFuZCBpbnRlcnByZXRhYmxlIGluZmVyZW5jZSBvZiBwc2V1ZG90ZW1wb3JhbCBwcm9ncmVzc2lvbiBpbiBjb21wbGV4IHNpbmdsZS1jZWxsIGRhdGEuKQoKR2l2ZW4gdGhhdCBtb3JwaG9sb2dpY2FsIHNpemUgaW4gX1AuIG1vcmdhbmlfIGNvcnJlbGF0ZXMgc3Ryb25nbHkgd2l0aCBkZXZlbG9wbWVudGFsIHN0YWdlLCB3b3JtIGxlbmd0aCAoTGVuZ3RobW0pIHdhcyB1c2VkIGFzIGEgYmlvbG9naWNhbGx5IGluZm9ybWVkIHByb3h5IGZvciBwc2V1ZG90aW1lLCBoZXJlIHJlZmVycmVkIHRvIGFzIHBzZXVkb3NpemUuIENlbGxzIHdlcmUgY2x1c3RlcmVkIGF0IGhpZ2ggcmVzb2x1dGlvbiB0byByZXNvbHZlIGZpbmUtZ3JhaW5lZCBjZWxsIHN0YXRlcywgYW5kIGEgcHJpbmNpcGFsIGdyYXBoIHdhcyBjb25zdHJ1Y3RlZCBhY3Jvc3MgdGhlIFBDQSBzcGFjZXRvIG1vZGVsIHB1dGF0aXZlIGRpZmZlcmVudGlhdGlvbiB0cmFqZWN0b3JpZXMuIFBzZXVkb3RpbWUgdmFsdWVzIHdlcmUgdGhlbiBpbmZlcnJlZCBhbG9uZyB0aGlzIGdyYXBoLCBjYXB0dXJpbmcgc2l6ZS1hc3NvY2lhdGVkIGRldmVsb3BtZW50YWwgcHJvZ3Jlc3Npb24gYWNyb3NzIGluZGl2aWR1YWwgd29ybXMuIFRoaXMgYXBwcm9hY2ggZmFjaWxpdGF0ZWQgdGhlIGNoYXJhY3Rlcml6YXRpb24gYW5kIHZpc3VhbGl6YXRpb24gb2YgZGl2ZXJnZW50IGNlbGx1bGFyIHRyYWplY3RvcmllcyB1bmRlcmx5aW5nIHNleHVhbCBhbmQgYXNleHVhbCBkaWZmZXJlbnRpYXRpb24uCgoKYGBge3IgdHJhamVjdG9yeSBtb25vY2xlM30KCiMgTG9hZCBwcmVwcm9jZXNzZWQgY2VsbF9kYXRhX3NldCBvYmplY3QKY2RzIDwtIHJlYWRSRFMoInNpemUtY2RzLWNlbGxjb3VudHNfM2UtNS1oaWdoUmVzLWNlbGwtdHlwZS5yZHMiKQojIFJlcGxhY2UgZGVmYXVsdCBVTUFQIGVtYmVkZGluZ3Mgd2l0aCBmaXJzdCB0aHJlZSBQQ0EgY29tcG9uZW50cyBmb3IgZGltZW5zaW9uYWxpdHkgcmVkdWN0aW9uCmNkc0BpbnRfY29sRGF0YUBsaXN0RGF0YSRyZWR1Y2VkRGltc0BsaXN0RGF0YSRVTUFQIDwtIGNkc0BpbnRfY29sRGF0YUBsaXN0RGF0YSRyZWR1Y2VkRGltc0BsaXN0RGF0YSRQQ0FbLCAxOjNdCgojIENsdXN0ZXIgY2VsbHMgYXQgYSBsb3cgcmVzb2x1dGlvbiBmb3IgZmluZSBncmFudWxhcml0eQpjZHMgPC0gY2x1c3Rlcl9jZWxscyhjZHMsIHJlc29sdXRpb24gPSAzZS01KQpwbG90X2NlbGxzXzNkKGNkcywgY29sb3JfY2VsbHNfYnk9Ikxlbmd0aG1tIikKCiMgTGVhcm4gcHJpbmNpcGFsIGdyYXBoIHRvIG1vZGVsIGRldmVsb3BtZW50YWwgdHJhamVjdG9yaWVzCmNkcyA8LSBsZWFybl9ncmFwaChjZHMsIGxlYXJuX2dyYXBoX2NvbnRyb2w9bGlzdChuY2VudGVyPTcsIHBydW5lX2dyYXBoPUZBTFNFLCBtaW5pbWFsX2JyYW5jaF9sZW49MSkpCnBsb3RfY2VsbHNfM2QoY2RzLCBjb2xvcl9jZWxsc19ieT0iTGVuZ3RobW0iLCBjZWxsX3NpemUgPSAzMCkKCiMgT3JkZXIgY2VsbHMgYWxvbmcgdGhlIGxlYXJuZWQgdHJhamVjdG9yeSAoaW50ZXJhY3RpdmUgbW9kZSkKI2NkcyA8LSBvcmRlcl9jZWxscyhjZHMpCgojIE9yZGVyIENlbGxzIChOT1RFOiBUaGUgcm9vdCBub2RlIHdhcyBpbml0aWFsbHkgZm91bmQgaW4gdGhlIGludGVyYWN0aXZlIG1vZGUsIGJ1dCBoZXJlIHRoZSBpbnB1dCBpcyBhdXRvbWF0ZWQgZm9yIGEgc21vb3RoIGtuaXR0aW5nIG9mIHRoZSBmaW5hbCBIVE1MIGRvY3VtZW50LikKCnJvb3Rfbm9kZSA8LSAiWV82IiAgCgpjZHMgPC0gb3JkZXJfY2VsbHMoY2RzLCByb290X3ByX25vZGVzID0gcm9vdF9ub2RlKQoKIyBBc3NpZ24gcHNldWRvdGltZSB2YWx1ZXMgcmVmbGVjdGluZyBkZXZlbG9wbWVudGFsIHByb2dyZXNzaW9uIGNvcnJlbGF0ZWQgd2l0aCB3b3JtIHNpemUKY2RzJHBzZXVkb3NpemVfcGNhIDwtIHBzZXVkb3RpbWUoY2RzKQptb25vY2xlM190cmFqZWN0b3J5X3Bsb3QgPC0gcGxvdF9jZWxsc18zZChjZHMsIGNvbG9yX2NlbGxzX2J5PSJwc2V1ZG9zaXplX3BjYSIpCm1vbm9jbGUzX3RyYWplY3RvcnlfcGxvdAoKCiMgRXh0cmFjdCBhbmQgYXJyYW5nZSBtZXRhZGF0YSBieSBwc2V1ZG90aW1lIGZvciBkb3duc3RyZWFtIGFuYWx5c2lzCmNvbGRhdCA8LSBhcy5kYXRhLmZyYW1lKGNvbERhdGEoY2RzKSkKY29sZGF0IDwtIGNvbGRhdCAlPiUgYXJyYW5nZShwc2V1ZG9zaXplX3BjYSkKCnJvd2RhdCA8LSBhcy5kYXRhLmZyYW1lKHJvd0RhdGEoY2RzKSkKCiMgRXh0cmFjdCBhbmQgcmVvcmRlciBjb3VudHMgbWF0cml4IGFjY29yZGluZyB0byBzYW1wbGUgb3JkZXIgaW4gbWV0YWRhdGEKY2VsbF9jb3VudHMgPC0gYXMubWF0cml4KGNvdW50cyhjZHMpKVssIGNvbGRhdCRzYW1wbGVdCgoKIyBDYWxjdWxhdGUgdmFyaWFuY2UgZXhwbGFpbmVkIGJ5IFBDQSBjb21wb25lbnRzIHRvIGFzc2VzcyBkaW1lbnNpb25hbGl0eSByZWR1Y3Rpb24KdmFyX2V4cGxhaW5lZCA8LSBjZHNAcmVkdWNlX2RpbV9hdXgkUENBQGxpc3REYXRhJG1vZGVsJHByb3BfdmFyX2V4cGwKdmFyX2V4cGxhaW5lZCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB2ZWN0b3IgZm9yIGV2ZXJ5IFBDCnN1bSh2YXJfZXhwbGFpbmVkWzE6M10pICAgICAgICAgICAgICAgICAgICAgICMgY3VtdWxhdGl2ZSBmb3IgUEMx4oCTUEMzCnN1bSh2YXJfZXhwbGFpbmVkWzE6N10pICAgICAgICAgICAgICAgICAgICAgICMgY3VtdWxhdGl2ZSBmb3IgUEMx4oCTUEM3CgppZiAoIWRpci5leGlzdHMoInRyYWplY3Rvcnlfb3V0cHV0IikpIGRpci5jcmVhdGUoInRyYWplY3Rvcnlfb3V0cHV0IikKCiMgU2F2ZSBpbnRlcmFjdGl2ZSAzRCB0cmFqZWN0b3J5IHBsb3QgYXMgYW4gSFRNTCB3aWRnZXQKc2F2ZVdpZGdldChtb25vY2xlM190cmFqZWN0b3J5X3Bsb3QsICJ0cmFqZWN0b3J5X291dHB1dC9tb25vY2xlM190cmFqZWN0b3J5X3Bsb3QuaHRtbCIsIHNlbGZjb250YWluZWQgPSBUUlVFKQoKYGBgCgoKIyMjIyAyLjEuIERpbWVuc2lvbmFsaXR5IGFuZCBDbHVzdGVyaW5nCgpUbyBkZXRlcm1pbmUgdGhlIGFwcHJvcHJpYXRlIG51bWJlciBvZiBjbHVzdGVycyBpbiB0aGUgUENBIHNwYWNlLCB1bnN1cGVydmlzZWQgay1tZWFucyBjbHVzdGVyaW5nIHdhcyBwZXJmb3JtZWQgb24gdGhlIGZpcnN0IHRocmVlIHByaW5jaXBhbCBjb21wb25lbnRzIG9mIHRoZSBjZWxsIHR5cGUgY29tcG9zaXRpb24gZGF0YS4gVGhlIHdvcmtpbmcgaHlwb3RoZXNpcyB3YXMgdGhhdCBpbmNvcnBvcmF0aW5nIG1vcmUgcHJpbmNpcGFsIGNvbXBvbmVudHMgKHRoZXJlYnkgY2FwdHVyaW5nIGEgZ3JlYXRlciBwcm9wb3J0aW9uIG9mIHZhcmlhbmNlKSB3b3VsZCB5aWVsZCBmaW5lci1ncmFpbmVkIGNsdXN0ZXJzIGFuZCBpbXByb3ZlIHJlc29sdXRpb24uIEhvd2V2ZXIsIHRoaXMgaHlwb3RoZXNpcyB3YXMgbm90IHN1cHBvcnRlZCBieSB0aGUgZGF0YS4KCkNvbnRyYXJ5IHRvIGV4cGVjdGF0aW9ucywgaW5jcmVhc2luZyB0aGUgbnVtYmVyIG9mIHByaW5jaXBhbCBjb21wb25lbnRzIChlLmcuLCA3IFBDcyB0byBjYXB0dXJlIH44MOKAkzkwJSBvZiB0aGUgdmFyaWFuY2UpIHJlc3VsdGVkIGluIGEgZGVjcmVhc2UgaW4gdGhlIG51bWJlciBvZiBiaW9sb2dpY2FsbHkgbWVhbmluZ2Z1bCBjbHVzdGVycy4gVGhpcyBvYnNlcnZhdGlvbiBzdWdnZXN0cyB0aGF0IHRoZSBhZGRpdGlvbmFsIGNvbXBvbmVudHMgbWF5IHByZWRvbWluYW50bHkgY2FwdHVyZSB0ZWNobmljYWwgbm9pc2Ugb3IgbG93LXZhcmlhbmNlIHN0cnVjdHVyZSwgdGhlcmVieSBkaWx1dGluZyB0aGUgc2lnbmFsIG5lY2Vzc2FyeSBmb3Igcm9idXN0IGNsdXN0ZXJpbmcuIEluIGNvbnRyYXN0LCB0aGUgZmlyc3QgdGhyZWUgY29tcG9uZW50cywgd2hpY2ggY29sbGVjdGl2ZWx5IGV4cGxhaW4gYXBwcm94aW1hdGVseSA2NiUgb2YgdGhlIHZhcmlhbmNlLCByZXRhaW5lZCB0aGUgbW9zdCByZWxldmFudCBiaW9sb2dpY2FsIHN0cnVjdHVyZSBmb3IgZGVsaW5lYXRpbmcgZGlzdGluY3QgY2VsbCBzdGF0ZXMuCgojIyMjIyAyLjEuMS4gSy1NZWFucyBFbGJvdyBQbG90IAoKVG8gYXNzZXNzIGNsdXN0ZXIgc3RydWN0dXJlLCBhIHN0YW5kYXJkIGVsYm93IHBsb3Qgd2FzIGNvbnN0cnVjdGVkIGJ5IGNvbXB1dGluZyB0aGUgdG90YWwgd2l0aGluLWNsdXN0ZXIgc3VtIG9mIHNxdWFyZXMgKFdTUykgZm9yIGEgcmFuZ2Ugb2YgayB2YWx1ZXMuIFRoZSBtYXhpbXVtIG51bWJlciBvZiBjbHVzdGVycyBldmFsdWF0ZWQgd2FzIHNldCB0byBrID0gMTUgdG8gYWxsb3cgZm9yIGRldGVjdGlvbiBvZiBhbiBpbmZsZWN0aW9uIHBvaW50IGluIHRoZSB3aXRoaW4tY2x1c3RlciBzdW0gb2Ygc3F1YXJlcyAoV1NTKSBjdXJ2ZS4gVGhpcyB1cHBlciBsaW1pdCB3YXMgY2hvc2VuIHRvIGV4Y2VlZCB0aGUgYW50aWNpcGF0ZWQgbnVtYmVyIG9mIGJpb2xvZ2ljYWxseSByZWxldmFudCBjbHVzdGVycyB3aGlsZSBhdm9pZGluZyBleGNlc3NpdmUgcGFydGl0aW9uaW5nIG9mIHRoZSBkYXRhLiBUaGUgV1NTIGN1cnZlIGV4aGliaXRlZCBhIGRpc3RpbmN0IGVsYm93LCBiZXlvbmQgd2hpY2ggaW5jcmVhc2VzIGluIGsgeWllbGRlZCBtaW5pbWFsIGdhaW5zLCBpbmRpY2F0aW5nIHRoZSBvcHRpbWFsIG51bWJlciBvZiBjbHVzdGVycy4gQSBkaXN0aW5jdCBpbmZsZWN0aW9uIHBvaW50IGluIHRoZSBXU1MgY3VydmUgaW5kaWNhdGVkIHRoZSBvcHRpbWFsIG51bWJlciBvZiBjbHVzdGVycyAqKihrPTQpKiosIGJhbGFuY2luZyBtb2RlbCBjb21wbGV4aXR5IGFuZCBleHBsYW5hdG9yeSBwb3dlci4KCmBgYHtyIGstbWVhbnMgZWxib3cgcGxvdH0KCiMgTmVlZHMgZ2dwbG90MiBhbmQgTW9ub2NsZTMgd2hpY2ggd2VyZSBhbHJlYWR5IGxvYWRlZCBlYXJsaWVyCmxpYnJhcnkocHVycnIpCgojIEV4dHJhY3QgUENBIGNvb3JkaW5hdGVzIChmaXJzdCAzIFBDcykKcGNhX2Nvb3JkcyA8LSByZWR1Y2VkRGltcyhjZHMpJFBDQVssIDE6M10gICMgQWRqdXN0IHRvIDE6MyBpZiB1c2luZyAzRAoKIyBDYWxjdWxhdGUgV1NTIGZvciBrPTEgdG8gaz0xNQpzZXQuc2VlZCgxMjMpICAjIFJlcHJvZHVjaWJpbGl0eQptYXhfayA8LSAxNQp3c3MgPC0gbWFwX2RibCgxOm1heF9rLCB+ewogIGttZWFucyhwY2FfY29vcmRzLCBjZW50ZXJzID0gLngsIG5zdGFydCA9IDI1LCBpdGVyLm1heCA9IDUwKSR0b3Qud2l0aGluc3MKfSkKCiMgUGxvdCBFTGJvdyBDdXJ2ZQoKZWxib3dfcGxvdCA8LSBnZ3Bsb3QoZGF0YS5mcmFtZShrID0gMTptYXhfaywgV1NTID0gd3NzKSwgYWVzKHggPSBrLCB5ID0gV1NTKSkgKwogIGdlb21fbGluZShjb2xvciA9ICIjMzc3RUI4IiwgbGluZXdpZHRoID0gMS4yKSArCiAgZ2VvbV9wb2ludChjb2xvciA9ICIjRTQxQTFDIiwgc2l6ZSA9IDMpICsKICBsYWJzKAogICAgdGl0bGUgPSAiSy1tZWFucyBFbGJvdyBQbG90IChQQ0EgU3BhY2UpIiwKICAgIHggPSAiTnVtYmVyIG9mIGNsdXN0ZXJzIChrKSIsCiAgICB5ID0gIlRvdGFsIFdpdGhpbi1DbHVzdGVyIFN1bSBvZiBTcXVhcmVzIChXU1MpIgogICkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSAxOm1heF9rKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSgKICAgIHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIkhlbHZldGljYSIpLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBoanVzdCA9IDAuNSksCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgCiAgICAjIFNvbGlkIHdoaXRlIGJhY2tncm91bmQgZm9yIHBhbmVsCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiLCBjb2xvciA9IE5BKSwKICAgICMgQWRkIGJvcmRlciBhcm91bmQgdGhlIHBsb3QgcGFuZWwKICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvciA9ICJibGFjayIsIGZpbGwgPSBOQSwgbGluZXdpZHRoID0gMC41KSwKICAgIAogICAgIyBPcHRpb25hbDogYWRkIGJvcmRlciBhcm91bmQgZW50aXJlIHBsb3QgKGluY2x1ZGluZyBtYXJnaW4pCiAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3IgPSAiYmxhY2siLCBmaWxsID0gIndoaXRlIiwgbGluZXdpZHRoID0gMC41KQogICkKCnByaW50KGVsYm93X3Bsb3QpCgojIFNhdmUgcGxvdApnZ3NhdmUoInRyYWplY3Rvcnlfb3V0cHV0L2VsYm93X3Bsb3QucG5nIiwgcGxvdCA9IGVsYm93X3Bsb3QsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNiwgZHBpID0gMzAwKQoKCmBgYAoKYGBge3IgNCBjbHVzdGVycyBkaXJlY3QsIGVjaG8gPSBGQUxTRX0gCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyBUaGlzIGNodW5rIG9mIGNvZGUgaXMgdW5yZWZpbmVkIGZvciB0aGUgZm9sbG93aW5nIHJlYXNvbnM6CgojVGhlIGNsdXN0ZXIgYXNzaWdubWVudCBpcyBub3QgcHNldWRvdGltZSBvcmRlcmVkIGFuZCBpdCBpcyBhIGxpdHRsZSBjb21wbGljYXRlZC4gSSBoYXZlIGZpeGVkIGl0IGluIHRoZSBwb2ludCBudW1iZXIgMiBpbiB0aGlzIGNvZGUgYnV0LCBpdCBkb2Vzbid0IGZvbGxvdyB0aHJvdWdoIHdlbGwgd2l0aCB0aGUgcmVzdCBvZiB0aGUgY29kZS4gSXQgaXMgcGFydGljdWxhcmx5IGJhZCB3aXRoIGlkZW50aWZ5aW5nIHRoZSBicmFuY2ggcG9pbnRzIHdpdGggdGhlIGN1cnJlbnQgbG9naWMuIEkgYW0gc3VyZSB0aGF0IHdlIGNhbiB3cml0ZSBhIG1vcmUgY29tcGxpY2F0ZWQgbG9naWMgZm9yIGZpZ3VyaW5nIG91dCB0aGUgYnJhbmNoIHBvaW50cyBjb3JyZWN0bHkgd2l0aCB0aGlzIGNsdXN0ZXJpbmcsIGJ1dCBJIHRoaW5rIHRoZSBlbGVnYW5jZSBsaWVzIGluIHRoZSBzaW1wbGljaXR5IG9mIHRoZSBjb2RlIHVzZWQgaW4gdGhlIG5leHQgUiBjaHVuayBsYWJlbGxlZCAiNCBjbHVzdGVycyIuCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyAjIFJ1biBrLW1lYW5zIGNsdXN0ZXJpbmcgd2l0aCBrPTQKIyBjb29yZHMgPC0gcmVkdWNlZERpbXMoY2RzKSRQQ0FbLCAxOjNdCiMgc2V0LnNlZWQoMTIzKQojIGttNCA8LSBrbWVhbnMoY29vcmRzLCBjZW50ZXJzID0gNCkKIyAKIyAjIE1hcCBudW1lcmljIGNsdXN0ZXJzICgxOjQpIHRvIGNsdXN0ZXIgbmFtZXMgaW4gYSB2ZWN0b3IsIGUuZy46CiMgY2x1c3Rlcl9uYW1lcyA8LSBjKCJCcmFuY2hfMSIsICJQcmVicmFuY2hfMSIsICJCcmFuY2hfMiIsICJQcmVicmFuY2hfMiIpCiMgCiMgIyBNYXAgdGhlIG51bWVyaWMgY2x1c3RlciBhc3NpZ25tZW50cyB0byBjbHVzdGVyIG5hbWVzCiMgY2RzJGJyYW5jaCA8LSBmYWN0b3IoY2x1c3Rlcl9uYW1lc1trbTQkY2x1c3Rlcl0sIGxldmVscyA9IGNsdXN0ZXJfbmFtZXMpCiMgCiMgIyBEZWZpbmUgZml4ZWQgY29sb3JzIG1hdGNoaW5nIHRoZSBjbHVzdGVyIG5hbWVzOgojIGJyYW5jaF9jb2xvcnMgPC0gYygKIyAgICJQcmVicmFuY2hfMSIgPSAiIzk5OTk5OSIsICAjIGdyZXkKIyAgICJQcmVicmFuY2hfMiIgPSAib3JhbmdlIiwgICAjIG9yYW5nZQojICAgIkJyYW5jaF8xIiAgICA9ICIjMzc3RUI4IiwgICMgYmx1ZQojICAgIkJyYW5jaF8yIiAgICA9ICIjRTQxQTFDIiAgICMgcmVkCiMgKQojIAojIGxpYnJhcnkocGxvdGx5KQojIAojICMgRXh0cmFjdCBwc2V1ZG90aW1lIHZlY3RvciAob3B0aW9uYWwgb3JkZXJpbmcgd2l0aGluIGNsdXN0ZXJzKQojIHBzZXVkb3RpbWUgPC0gY2RzJHBzZXVkb3NpemVfcGNhCiMgbmFtZXMocHNldWRvdGltZSkgPC0gY29sbmFtZXMoY2RzKQojIAojICMgSW5pdGlhbGl6ZSAzRCBwbG90CiMgY2x1c3RlcmluZ19wbG90XzQgPC0gcGxvdF9seSgpCiMgCiMgIyBQbG90IGVhY2ggY2x1c3RlciBvcmRlcmVkIGJ5IHBzZXVkb3RpbWUKIyBmb3IoYnJhbmNoIGluIGxldmVscyhjZHMkYnJhbmNoKSkgewojICAgaWR4IDwtIHdoaWNoKGNkcyRicmFuY2ggPT0gYnJhbmNoKQojICAgaWYobGVuZ3RoKGlkeCkgPiAwKSB7CiMgICAgIG9yZGVyZWRfaWR4IDwtIGlkeFtvcmRlcihwc2V1ZG90aW1lW2lkeF0pXQojICAgICAKIyAgICAgY2x1c3RlcmluZ19wbG90XzQgPC0gY2x1c3RlcmluZ19wbG90XzQgJT4lIGFkZF90cmFjZSgKIyAgICAgICB4ID0gY29vcmRzW29yZGVyZWRfaWR4LCAxXSwKIyAgICAgICB5ID0gY29vcmRzW29yZGVyZWRfaWR4LCAyXSwKIyAgICAgICB6ID0gY29vcmRzW29yZGVyZWRfaWR4LCAzXSwKIyAgICAgICB0eXBlID0gInNjYXR0ZXIzZCIsCiMgICAgICAgbW9kZSA9ICJtYXJrZXJzIiwKIyAgICAgICBtYXJrZXIgPSBsaXN0KAojICAgICAgICAgc2l6ZSA9IDQsCiMgICAgICAgICBjb2xvciA9IGJyYW5jaF9jb2xvcnNbYnJhbmNoXQojICAgICAgICksCiMgICAgICAgbmFtZSA9IGJyYW5jaCwKIyAgICAgICBzaG93bGVnZW5kID0gVFJVRQojICAgICApCiMgICB9CiMgfQojIAojICMgTGF5b3V0CiMgY2x1c3RlcmluZ19wbG90XzQgPC0gY2x1c3RlcmluZ19wbG90XzQgJT4lIGxheW91dCgKIyAgIHNjZW5lID0gbGlzdCgKIyAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIlBDMSIpLAojICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiUEMyIiksCiMgICAgIHpheGlzID0gbGlzdCh0aXRsZSA9ICJQQzMiKQojICAgKSwKIyAgIGxlZ2VuZCA9IGxpc3Qob3JpZW50YXRpb24gPSAiaCIpCiMgKQojIAojIGNsdXN0ZXJpbmdfcGxvdF80CgoKYGBgCgojIyMjIyAyLjEuMi4gSy1NZWFucyBDbHVzdGVyaW5nCgpUbyBpZGVudGlmeSBkaXNjcmV0ZSBjZWxsdWxhciBzdGF0ZXMgYWxvbmcgdGhlIGRldmVsb3BtZW50YWwgdHJhamVjdG9yeSwgSy1tZWFucyBjbHVzdGVyaW5nIHdhcyBwZXJmb3JtZWQgb24gY2VsbHMgZW1iZWRkZWQgaW4gUENBIHNwYWNlIGFuZCBvcmRlcmVkIGJ5IHBzZXVkb3RpbWUuIEFsbCBjZWxscyB3ZXJlIGluaXRpYWxseSBhc3NpZ25lZCB0byBhIGNvbW1vbiBlYXJseS1zdGF0ZSBsYWJlbCAoUHJlYnJhbmNoXzEpLiBDZWxscyBleGNlZWRpbmcgYSBkZWZpbmVkIHBzZXVkb3RpbWUgdGhyZXNob2xkIHdlcmUgY29uc2lkZXJlZCBwb3N0LWJyYW5jaCBhbmQgcGFydGl0aW9uZWQgaW50byB0d28gbWFqb3IgY2x1c3RlcnM6IEJyYW5jaF8xIGFuZCBCcmFuY2hfMi4gCgoqKkFuIGludGVybWVkaWF0ZSBjbHVzdGVyLCBQcmVicmFuY2hfMiwgZW1lcmdlZCB3aXRoaW4gdGhlIHRyYW5zaXRpb25hbCBwc2V1ZG90aW1lIHdpbmRvdywgcmVwcmVzZW50aW5nIGEgcHV0YXRpdmUgcHJlLWNvbW1pdG1lbnQgc3RhdGUgcHJlY2VkaW5nIGJpZnVyY2F0aW9uLioqSW1wb3J0YW50bHksIGNsdXN0ZXJpbmcgaW50byB0aHJlZSBncm91cHMgcmV2ZWFsZWQgYSBicmFuY2ggcG9pbnQgYWxvbmcgdGhlIGdyb3d0aCB0cmFqZWN0b3J5IHRoYXQgcHJlY2VkZXMgdGhlIGRpdmVyZ2VuY2UgaW50byBhc2V4dWFsIGFuZCBzZXh1YWwgcGF0aHdheXMgKEJyYW5jaF8xIGFuZCBCcmFuY2hfMiByZXNwZWN0aXZlbHkpLiBUaGlzIGVhcmx5IGluZmxlY3Rpb24gaXMgcHJpbWFyaWx5IHJlcHJlc2VudGVkIGJ5IHNhbXBsZXMgYXNzaWduZWQgdG8gdGhlIFByZWJyYW5jaF8yIGNsdXN0ZXIuIFRoZSBkaXN0aW5jdCBwb3NpdGlvbmluZyBvZiB0aGlzIGdyb3VwIHN1Z2dlc3RzIHRoYXQgYSBjcml0aWNhbCBzaGlmdCBpbiBjZWxsdWxhciBjb21wb3NpdGlvbiBvciBkZXZlbG9wbWVudGFsIHN0YXRlIG1heSBvY2N1ciB1cHN0cmVhbSBvZiBvdmVydCBzZXh1YWwgZGlmZmVyZW50aWF0aW9uLiBUaGlzIG9ic2VydmF0aW9uIHJhaXNlcyB0aGUgcG9zc2liaWxpdHkgdGhhdCBQcmVicmFuY2hfMiBjb3JyZXNwb25kcyB0byBhIHRyYW5zaXRpb25hbCBwaGFzZSBjaGFyYWN0ZXJpemVkIGJ5IGFuIGVhcmx5IGNvbW1pdG1lbnQgb3IgdXByZWd1bGF0aW9uIG9mIGRldmVsb3BtZW50YWwgcHJvZ3JhbXMuCgpUaGVzZSBkYXRhLWRyaXZlbiBjbHVzdGVycyBkZWxpbmVhdGUga2V5IHN0YWdlcyBvZiBncm93dGggaW4gX1AuIG1vcmdhbmlfLCB3aXRoIEJyYW5jaF8xIGFuZCBCcmFuY2hfMiBjb3JyZXNwb25kaW5nIHRvIHRoZSBjb21taXR0ZWQgYXNleHVhbCBhbmQgc2V4dWFsIGZhdGVzLCByZXNwZWN0aXZlbHkuIFZpc3VhbGl6YXRpb24gaW4gM0QgUENBIHNwYWNlIGNvbmZpcm1lZCB0aGF0IHRoZSBpbmZlcnJlZCBjbHVzdGVycyByZWNhcGl0dWxhdGUgdGhlIHVuZGVybHlpbmcgc3RydWN0dXJlIG9mIGRldmVsb3BtZW50YWwgZGl2ZXJnZW5jZS4KCnwgQ2x1c3RlciAgICAgICB8IERlc2NyaXB0aW9uICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgQ29sb3IgICAgfAp8LS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLXwKfCBQcmVicmFuY2hfMSAgIHwgRWFybHkgZGV2ZWxvcG1lbnRhbCBzdGF0ZSAoY29tbW9uIHJvb3QpICAgICAgfCBHcmF5ICAgICB8CnwgUHJlYnJhbmNoXzIgICB8IFRyYW5zaXRpb25hbCBwcmUtY29tbWl0bWVudCBzdGF0ZSAgICAgICAgICAgIHwgT3JhbmdlICAgfAp8IEJyYW5jaF8xICAgICAgfCBUZXJtaW5hbCBzdGF0ZSBvZiB0aGUgYXNleHVhbCB0cmFqZWN0b3J5CSAgIHwgQmx1ZSAgICAgfAp8IEJyYW5jaF8yCSAgICB8IFRlcm1pbmFsIHN0YXRlIG9mIHRoZSBzZXh1YWwgdHJhamVjdG9yeSAgICAgIHwgUmVkICAgICAgfAoKYGBge3IgNCBjbHVzdGVyc30KCiMgSW5pdGlhbGl6ZSBhbGwgY2VsbHMgYXMgcHJlYnJhbmNoXzEKY2RzJGJyYW5jaCA8LSAiUHJlYnJhbmNoXzEiCgojdklkZW50aWZ5IHBvc3QtYnJhbmNoIGNlbGxzIHVzaW5nIHBzZXVkb3RpbWUgdGhyZXNob2xkCnBzZXVkb3RpbWVfdGhyZXNob2xkIDwtIHF1YW50aWxlKGNkcyRwc2V1ZG9zaXplX3BjYSwgcHJvYnMgPSAwLjMzKQpwb3N0X2JyYW5jaF9pZHggPC0gd2hpY2goY2RzJHBzZXVkb3NpemVfcGNhID4gcHNldWRvdGltZV90aHJlc2hvbGQpCgojIEJyYW5jaGluZyBsb2dpYyAoTWFpbiBiaWZ1cmNhdGlvbjogc3BsaXQgcG9zdC1icmFuY2ggY2VsbHMgaW50byB0d28gY2x1c3RlcnMpCmlmKGxlbmd0aChwb3N0X2JyYW5jaF9pZHgpID4gMTApIHsKICBwb3N0X2Nvb3JkcyA8LSByZWR1Y2VkRGltcyhjZHMpJFBDQVtwb3N0X2JyYW5jaF9pZHgsIDE6M10KICBzZXQuc2VlZCgxMjMpCiAga20gPC0ga21lYW5zKHBvc3RfY29vcmRzLCBjZW50ZXJzID0gMikKICBjZHMkYnJhbmNoW3Bvc3RfYnJhbmNoX2lkeF0gPC0gaWZlbHNlKGttJGNsdXN0ZXIgPT0gMSwgIkJyYW5jaF8xIiwgIkJyYW5jaF8yIikKICAKICAjIFNlY29uZGFyeSBjbHVzdGVyaW5nIChTZWNvbmRhcnkgYmlmdXJjYXRpb246IHNwbGl0IEJyYW5jaF8xIGludG8gUHJlYnJhbmNoXzIgYW5kIEJyYW5jaF8xKQogIGJyYW5jaDFfaWR4IDwtIHdoaWNoKGNkcyRicmFuY2ggPT0gIkJyYW5jaF8xIikKICBpZihsZW5ndGgoYnJhbmNoMV9pZHgpID4gNSkgewogICAgYnJhbmNoMV9jb29yZHMgPC0gcmVkdWNlZERpbXMoY2RzKSRQQ0FbYnJhbmNoMV9pZHgsIDE6M10KICAgIHNldC5zZWVkKDEyMykKICAgIGttMiA8LSBrbWVhbnMoYnJhbmNoMV9jb29yZHMsIGNlbnRlcnMgPSAyKQogICAgY2RzJGJyYW5jaFticmFuY2gxX2lkeF0gPC0gaWZlbHNlKGttMiRjbHVzdGVyID09IDEsICJCcmFuY2hfMSIsICJQcmVicmFuY2hfMiIpCiAgfQp9CgojIERlZmluZSBhbmQgb3JkZXIgZmluYWwgY2x1c3RlciBsYWJlbHMKY2RzJGJyYW5jaCA8LSBmYWN0b3IoY2RzJGJyYW5jaCwgCiAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIlByZWJyYW5jaF8xIiwgIlByZWJyYW5jaF8yIiwgIkJyYW5jaF8xIiwgIkJyYW5jaF8yIikpCgpuYW1lcyhjZHMkYnJhbmNoKSA8LSBjb2xuYW1lcyhjZHMpCgojIENvbG9yIHNjaGVtZQpicmFuY2hfY29sb3JzIDwtIGMoCiAgIlByZWJyYW5jaF8xIiA9ICIjOTk5OTk5IiwKICAiQnJhbmNoXzEiID0gIiMzNzdFQjgiLAogICJQcmVicmFuY2hfMiIgPSAib3JhbmdlIiwKICAiQnJhbmNoXzIiID0gIiNFNDFBMUMiCikKCgojIDNEIHNjYXR0ZXIgcGxvdCBvZiBjbHVzdGVycyAKY2x1c3RlcmluZ19wbG90XzQgPC0gcGxvdF9seSgpCgpmb3IoYnJhbmNoIGluIGxldmVscyhjZHMkYnJhbmNoKSkgewogIGlmKGFueShjZHMkYnJhbmNoID09IGJyYW5jaCkpIHsKICAgIGNsdXN0ZXJpbmdfcGxvdF80IDwtIGNsdXN0ZXJpbmdfcGxvdF80ICU+JSBhZGRfdHJhY2UoCiAgICAgIHggPSByZWR1Y2VkRGltcyhjZHMpJFBDQVtjZHMkYnJhbmNoID09IGJyYW5jaCwgMV0sCiAgICAgIHkgPSByZWR1Y2VkRGltcyhjZHMpJFBDQVtjZHMkYnJhbmNoID09IGJyYW5jaCwgMl0sCiAgICAgIHogPSByZWR1Y2VkRGltcyhjZHMpJFBDQVtjZHMkYnJhbmNoID09IGJyYW5jaCwgM10sCiAgICAgIHR5cGUgPSAic2NhdHRlcjNkIiwgbW9kZSA9ICJtYXJrZXJzIiwKICAgICAgbWFya2VyID0gbGlzdCgKICAgICAgICBzaXplID0gaWZlbHNlKGJyYW5jaCA9PSAiUHJlYnJhbmNoXzEiLCA0LCA0KSwKICAgICAgICBjb2xvciA9IGJyYW5jaF9jb2xvcnNbYnJhbmNoXQogICAgICApLAogICAgICBuYW1lID0gYnJhbmNoCiAgICApCiAgfQp9CgpjbHVzdGVyaW5nX3Bsb3RfNCA8LSBjbHVzdGVyaW5nX3Bsb3RfNCAlPiUgCiAgY29uZmlnKGF1dG9zaXphYmxlID0gVFJVRSkgJT4lIAogIGxheW91dCgKICAgIHNjZW5lID0gbGlzdCgKICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIlBDMSIpLAogICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiUEMyIiksCiAgICAgIHpheGlzID0gbGlzdCh0aXRsZSA9ICJQQzMiKQogICAgKSwKICAgIGxlZ2VuZCA9IGxpc3QoCiAgICAgIG9yaWVudGF0aW9uID0gImgiLCAKICAgICAgeCA9IDAuNSwgCiAgICAgIHhhbmNob3IgPSAiY2VudGVyIiwgCiAgICAgIHkgPSAtMC4xNSwgICMgVHJ5IG1vcmUgbmVnYXRpdmUgdmFsdWVzIGlmIG5lZWRlZAogICAgICB5YW5jaG9yID0gInRvcCIKICAgICkKICApCgpjbHVzdGVyaW5nX3Bsb3RfNAoKIyBTYXZlIHBsb3QKc2F2ZVdpZGdldChjbHVzdGVyaW5nX3Bsb3RfNCwgInRyYWplY3Rvcnlfb3V0cHV0L2NsdXN0ZXJpbmdfcGxvdF80Lmh0bWwiLCBzZWxmY29udGFpbmVkID0gVFJVRSkKCiNOT1RFOiBBbm90aGVyIGlkZWEgd291bGQgYmUgdG8gdHJ5IHRoZSBMZWlkZW4gY2x1c3RlcmluZy4gU2luY2UgTW9ub2NsZTMgYWxyZWFkeSBkb2VzIHRoYXQgaW4gdGhlIGxlYXJuX2dyYXBoKCkgc3RlcCwgdGhlIGstbWVhbnMgY2x1c3RlcmluZyAoYXMgaWxsdXN0cmF0ZWQgYWJvdmUpIHNob3VsZCBzdWZmaWNlLgpgYGAKCgojIyMjIDIuMi4gRGVmaW5pbmcgVHJhamVjdG9yaWVzCgpUbyBlbmFibGUgZm9jdXNlZCBkb3duc3RyZWFtIGFuYWx5c2VzLCBmb3VyIGJpb2xvZ2ljYWxseSByZWxldmFudCB0cmFqZWN0b3J5IHN1YnNldHMgd2VyZSBkZWxpbmVhdGVkLCBlYWNoIHJlcHJlc2VudGluZyBzcGVjaWZpYyBzdGFnZXMgb3IgZmF0ZSBkZWNpc2lvbnMgd2l0aGluIF9QLiBtb3JnYW5pXyBncm93dGg6CgogKyBFYXJseSBEZXZlbG9wbWVudDogY29tcHJpc2luZyBQcmVicmFuY2hfMSBhbmQgUHJlYnJhbmNoXzIsIHJlcHJlc2VudGluZyBpbml0aWFsIHN0YWdlcyBwcmlvciB0byBtYWpvciBmYXRlIGNvbW1pdG1lbnQuCgogKyBBc2V4dWFsIFRyYWplY3Rvcnk6IGVuY29tcGFzc2luZyBQcmVicmFuY2hfMSwgUHJlYnJhbmNoXzIsIGFuZCBCcmFuY2hfMSwgY29ycmVzcG9uZGluZyB0byB0aGUgZGV2ZWxvcG1lbnRhbCBwYXRoIGxlYWRpbmcgdG8gYXNleHVhbCB3b3Jtcy4KCiArIFNleHVhbCBUcmFqZWN0b3J5OiBpbmNsdWRpbmcgUHJlYnJhbmNoXzEsIFByZWJyYW5jaF8yLCBhbmQgQnJhbmNoXzIsIHJlcHJlc2VudGluZyB0aGUgdHJhamVjdG9yeSB0b3dhcmRzIHNleHVhbCBkaWZmZXJlbnRpYXRpb24uCgogKyBMYXRlIERldmVsb3BtZW50OiBjb25zaXN0aW5nIG9mIEJyYW5jaF8xIGFuZCBCcmFuY2hfMiwgY2FwdHVyaW5nIHRoZSB0ZXJtaW5hbCBwaGFzZXMgb2YgYm90aCBhc2V4dWFsIGFuZCBzZXh1YWwgbGluZWFnZXMuCiAKVGhlc2UgdHJhamVjdG9yeSBkZWZpbml0aW9ucyBwcm92aWRlIGEgc3RydWN0dXJlZCBmcmFtZXdvcmsgZm9yIHN5c3RlbWF0aWMgY29tcGFyaXNvbiBvZiBjZWxsIHR5cGUgY29tcG9zaXRpb24sIGR5bmFtaWMgdmFyaWFiaWxpdHksIGFuZCBwc2V1ZG90ZW1wb3JhbCBwcm9ncmVzc2lvbi4KCgpgYGB7ciB0cmFqZWN0b3J5IGRlZmluaXRpb25zfQoKIyMgRGVmaW5pbmcgQ2x1c3RlcnMgYW5kIFRyYWplY3RvcmllcwoKIyBTZXQgY29uc2lzdGVudCBjbHVzdGVyIG9yZGVyaW5nIGFuZCBhc3NvY2lhdGVkIGNvbG9ycwpicmFuY2hfb3JkZXIgPC0gYygiUHJlYnJhbmNoXzEiLCAiUHJlYnJhbmNoXzIiLCAiQnJhbmNoXzEiLCAiQnJhbmNoXzIiKQpicmFuY2hfY29sb3JzIDwtIGMoCiAgIlByZWJyYW5jaF8xIiA9ICIjOTk5OTk5IiwgICMgZ3JleQogICJQcmVicmFuY2hfMiIgPSAib3JhbmdlIiwgICAjIG9yYW5nZQogICJCcmFuY2hfMSIgICAgPSAiIzM3N0VCOCIsICAjIGJsdWUKICAiQnJhbmNoXzIiICAgID0gIiNFNDFBMUMiICAgIyByZWQKKQoKI2NvbGRhdCRjbHVzdGVyIDwtIGNkcyRicmFuY2hbcm93bmFtZXMoY29sZGF0KV0gIAoKIyBBc3NpZ24gY2x1c3RlciBsYWJlbHMgdG8gY2VsbHMKY29sZGF0JGNsdXN0ZXIgPC0gYXMuY2hhcmFjdGVyKGNkcyRicmFuY2gpW21hdGNoKHJvd25hbWVzKGNvbGRhdCksIG5hbWVzKGNkcyRicmFuY2gpKV0KY29sZGF0JGNsdXN0ZXIgPC0gZmFjdG9yKGNvbGRhdCRjbHVzdGVyLCBsZXZlbHMgPSBjKCJQcmVicmFuY2hfMSIsICJQcmVicmFuY2hfMiIsICJCcmFuY2hfMSIsICJCcmFuY2hfMiIpKQoKIyBEZWZpbmUgdHJhamVjdG9yeSBncm91cGluZ3MgYW5kIHRoZWlyIGJyYW5jaCBjb21wb3NpdGlvbgp0cmFqZWN0b3JpZXMgPC0gbGlzdCgKICBlYXJseV9kZXYgPSBsaXN0KAogICAgbmFtZSA9ICJFYXJseSBEZXZlbG9wbWVudCIsCiAgICBicmFuY2hlcyA9IGMoIlByZWJyYW5jaF8xIiwgIlByZWJyYW5jaF8yIiksCiAgICBjb2xvciA9IGMoIiM5OTk5OTkiLCAib3JhbmdlIikKICApLAogIGFzZXh1YWwgPSBsaXN0KAogICAgbmFtZSA9ICJBc2V4dWFsIFRyYWplY3RvcnkiLAogICAgYnJhbmNoZXMgPSBjKCJQcmVicmFuY2hfMSIsICJQcmVicmFuY2hfMiIsICJCcmFuY2hfMSIpLAogICAgY29sb3IgPSBjKCIjOTk5OTk5IiwgIm9yYW5nZSIsICIjMzc3RUI4IikKICApLAogIHNleHVhbCA9IGxpc3QoCiAgICBuYW1lID0gIlNleHVhbCBUcmFqZWN0b3J5IiwKICAgIGJyYW5jaGVzID0gYygiUHJlYnJhbmNoXzEiLCAiUHJlYnJhbmNoXzIiLCAiQnJhbmNoXzIiKSwKICAgIGNvbG9yID0gYygiIzk5OTk5OSIsICJvcmFuZ2UiLCAiI0U0MUExQyIpCiAgKSwKICBsYXRlX2RldiA9IGxpc3QoCiAgICBuYW1lID0gIkxhdGUgRGV2ZWxvcG1lbnQiLAogICAgYnJhbmNoZXMgPSBjKCJCcmFuY2hfMSIsICJCcmFuY2hfMiIpLAogICAgY29sb3IgPSBjKCIjMzc3RUI4IiwgIiNFNDFBMUMiKQogICksCiAgYWxsX2NsdXN0ZXJzID0gbGlzdCgKICAgIG5hbWUgPSAiQWxsIENsdXN0ZXJzIiwKICAgIGJyYW5jaGVzID0gbGV2ZWxzKGNkcyRicmFuY2gpLAogICAgY29sb3IgPSB1bm5hbWUoYnJhbmNoX2NvbG9yc1tsZXZlbHMoY2RzJGJyYW5jaCldKQogICkKKQoKCiMgT3B0aW9uYWwgZGlhZ25vc3RpYzogQ2hlY2sgaG93IG1hbnkgY2VsbHMgZmFsbCB1bmRlciBlYWNoIHRyYWplY3RvcnkKZm9yICh0cmFqX25hbWUgaW4gbmFtZXModHJhamVjdG9yaWVzKSkgewogIGNsdXN0ZXJzIDwtIHRyYWplY3Rvcmllc1tbdHJhal9uYW1lXV0kYnJhbmNoZXMKICBjZWxscyA8LSByb3duYW1lcyhjb2xkYXQpW2NvbGRhdCRjbHVzdGVyICVpbiUgY2x1c3RlcnNdCiAgY2F0KHNwcmludGYoIlRyYWplY3RvcnkgJyVzJyBjb250YWlucyAlZCBjZWxscyBhY3Jvc3MgY2x1c3RlcnM6ICVzXG4iLAogICAgICAgICAgICAgIHRyYWpfbmFtZSwgbGVuZ3RoKGNlbGxzKSwgcGFzdGUoY2x1c3RlcnMsIGNvbGxhcHNlID0gIiwgIikpKQp9CgoKYGBgCgoKIyMjIyMgMi4yLjEuIERlZmluaW5nIEJyYW5jaCBQb2ludHMgYW5kIFZpc3VhbGl6aW5nIFRyYWplY3RvcmllcwoKQnJhbmNoIHBvaW50cyB3aXRoaW4gdGhlIGRldmVsb3BtZW50YWwgdHJhamVjdG9yeSB3ZXJlIGlkZW50aWZpZWQgYXMgdGhlIG1pbmltdW0gcHNldWRvdGltZSB2YWx1ZXMgY29ycmVzcG9uZGluZyB0byB0cmFuc2l0aW9ucyBpbnRvIGRpc3RpbmN0IGNsdXN0ZXJzIChQcmVicmFuY2hfMiwgQnJhbmNoXzEsIEJyYW5jaF8yKS4gVGhlc2UgYnJhbmNoIHBvaW50cyBtYXJrIGNyaXRpY2FsIGZhdGUgZGVjaXNpb25zIGFsb25nIHRoZSBwc2V1ZG90ZW1wb3JhbCBheGlzIGRlcml2ZWQgZnJvbSB0aGUgUENBIGVtYmVkZGluZy4KCmBgYHtyIGJyYW5jaCBwb2ludCBpZGVudGlmaWNhdGlvbn0KIyBFbnN1cmUgcHNldWRvdGltZSBpcyBhdmFpbGFibGUKaWYgKCJwc2V1ZG9zaXplX3BjYSIgJWluJSBjb2xuYW1lcyhjb2xEYXRhKGNkcykpKSB7CgogICMgRmluZCBicmFuY2ggdHJhbnNpdGlvbnMKICB0cmFuc2l0aW9ucyA8LSBsaXN0KAogICAgUHJlYnJhbmNoXzIgPSBtaW4oY2RzJHBzZXVkb3NpemVfcGNhW2NkcyRicmFuY2ggPT0gIlByZWJyYW5jaF8yIl0sIG5hLnJtID0gVFJVRSksCiAgICBCcmFuY2hfMSA9IG1pbihjZHMkcHNldWRvc2l6ZV9wY2FbY2RzJGJyYW5jaCA9PSAiQnJhbmNoXzEiXSwgbmEucm0gPSBUUlVFKSwgCiAgICBCcmFuY2hfMiA9IG1pbihjZHMkcHNldWRvc2l6ZV9wY2FbY2RzJGJyYW5jaCA9PSAiQnJhbmNoXzIiXSwgbmEucm0gPSBUUlVFKQogICkKCiAgIyBSZW1vdmUgYW55IGludmFsaWQgdHJhbnNpdGlvbnMgKEluZiwgTkEpCiAgdHJhbnNpdGlvbnMgPC0gdHJhbnNpdGlvbnNbIWlzLmluZmluaXRlKHVubGlzdCh0cmFuc2l0aW9ucykpICYgIWlzLm5hKHVubGlzdCh0cmFuc2l0aW9ucykpXQoKICAjIENyZWF0ZSBiYXNlIDNEIHBsb3QKICBiYXNlX3Bsb3QgPC0gcGxvdF9jZWxsc18zZCgKICAgIGNkcywKICAgIGNvbG9yX2NlbGxzX2J5ID0gImJyYW5jaCIsCiAgICBjZWxsX3NpemUgPSAzMCwKICAgIHRyYWplY3RvcnlfZ3JhcGhfY29sb3IgPSAiYmxhY2siLAogICAgdHJhamVjdG9yeV9ncmFwaF9zZWdtZW50X3NpemUgPSAzCiAgKQoKICBicmFuY2hfcG9pbnRzX3Bsb3QgPC0gYmFzZV9wbG90CgogICMgSGVscGVyOiBHZXQgUENBIGNvb3JkaW5hdGVzIG5lYXIgcHNldWRvdGltZSAtLS0KICBnZXRfY29vcmRzX2F0X3BzZXVkb3RpbWUgPC0gZnVuY3Rpb24oY2RzLCBwc2V1ZG90aW1lX3ZhbCkgewogICAgaWR4IDwtIHdoaWNoLm1pbihhYnMoY2RzJHBzZXVkb3NpemVfcGNhIC0gcHNldWRvdGltZV92YWwpKQogICAgcmVkdWNlZERpbXMoY2RzKSRQQ0FbaWR4LCAxOjNdCiAgfQoKICAjIEFkZCBicmFuY2ggcG9pbnRzIHdpdGggY2xlYW4gbGFiZWxzCiAgZm9yIChicmFuY2ggaW4gbmFtZXModHJhbnNpdGlvbnMpKSB7CiAgICBjb29yZHMgPC0gZ2V0X2Nvb3Jkc19hdF9wc2V1ZG90aW1lKGNkcywgdHJhbnNpdGlvbnNbW2JyYW5jaF1dKQoKICAgIGJyYW5jaF9wb2ludHNfcGxvdCA8LSBicmFuY2hfcG9pbnRzX3Bsb3QgJT4lIGFkZF90cmFjZSgKICAgICAgeCA9IGNvb3Jkc1sxXSwgeSA9IGNvb3Jkc1syXSwgeiA9IGNvb3Jkc1szXSwKICAgICAgdHlwZSA9ICJzY2F0dGVyM2QiLAogICAgICBtb2RlID0gIm1hcmtlcnMiLAogICAgICBtYXJrZXIgPSBsaXN0KAogICAgICAgIHNpemUgPSAxMiwKICAgICAgICBjb2xvciA9IGJyYW5jaF9jb2xvcnNbYnJhbmNoXSwKICAgICAgICBzeW1ib2wgPSAiZGlhbW9uZCIKICAgICAgKSwKICAgICAgbmFtZSA9IHNwcmludGYoIiVzICh0PSUuMmYpIiwgYnJhbmNoLCB0cmFuc2l0aW9uc1tbYnJhbmNoXV0pLAogICAgICBob3ZlcmluZm8gPSAidGV4dCIsCiAgICAgIHRleHQgPSBzcHJpbnRmKCIlcyBzdGFydFxuUHNldWRvdGltZTogJS4yZlxuUEMxOiAlLjFmXG5QQzI6ICUuMWZcblBDMzogJS4xZiIsCiAgICAgICAgICAgICAgICAgICAgIGJyYW5jaCwgdHJhbnNpdGlvbnNbW2JyYW5jaF1dLCBjb29yZHNbMV0sIGNvb3Jkc1syXSwgY29vcmRzWzNdKSwKICAgICAgc2hvd2xlZ2VuZCA9IFRSVUUKICAgICkKICB9CgogICMgQ3JlYXRlIGRlbnNpdHkgcGxvdCB3aXRoIG9yZGVyZWQgbGVnZW5kCiAgYnJhbmNoX29yZGVyIDwtIGMoIlByZWJyYW5jaF8xIiwgIlByZWJyYW5jaF8yIiwgIkJyYW5jaF8xIiwgIkJyYW5jaF8yIikKICBwbG90X2RhdGEgPC0gYXMuZGF0YS5mcmFtZShjb2xEYXRhKGNkcykpCiAgcGxvdF9kYXRhJGJyYW5jaCA8LSBmYWN0b3IocGxvdF9kYXRhJGJyYW5jaCwgbGV2ZWxzID0gYnJhbmNoX29yZGVyKQoKICBkZW5zaXR5X3Bsb3QgPC0gZ2dwbG90KHBsb3RfZGF0YSwgCiAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBwc2V1ZG9zaXplX3BjYSwgZmlsbCA9IGJyYW5jaCkpICsKICAgICAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC41KSArCiAgICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IHVubGlzdCh0cmFuc2l0aW9ucyksIAogICAgICAgICAgICAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIsCiAgICAgICAgICAgICAgICAgY29sb3IgPSBicmFuY2hfY29sb3JzW25hbWVzKHRyYW5zaXRpb25zKV0pICsKICAgICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYnJhbmNoX2NvbG9yc1ticmFuY2hfb3JkZXJdLAogICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBicmFuY2hfb3JkZXIpICsKICAgICAgbGFicyh4ID0gIlBzZXVkb3RpbWUiLCB5ID0gIkRlbnNpdHkiLCB0aXRsZSA9ICJCcmFuY2ggVHJhbnNpdGlvbnMiKSArCiAgICAgIHRoZW1lX21pbmltYWwoKSArCiAgICAgIHRoZW1lKAogICAgICAgICAgdGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiSGVsdmV0aWNhIiksCiAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gImNlbnRlciIsCiAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKSwgIAogICAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG9yID0gImJsYWNrIiwgZmlsbCA9IE5BLCBzaXplID0gMC41KSwgIAogICAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG9yID0gImJsYWNrIiwgZmlsbCA9IE5BLCBsaW5ld2lkdGggPSAwLjUpICAKICAgICkKCiAgIyBPcHRpb25hbDogUHJpbnQgdHJhbnNpdGlvbiBpbmZvCiAgY2F0KCI9PT0gQnJhbmNoIFRyYW5zaXRpb24gUHNldWRvdGltZXMgPT09XG4iKQogIHByaW50KGRhdGEuZnJhbWUoCiAgICBCcmFuY2ggPSBuYW1lcyh0cmFuc2l0aW9ucyksCiAgICBQc2V1ZG90aW1lID0gcm91bmQodW5saXN0KHRyYW5zaXRpb25zKSwgMiksCiAgICBQQzEgPSBzYXBwbHkobmFtZXModHJhbnNpdGlvbnMpLCBmdW5jdGlvbih4KSByb3VuZChyZWR1Y2VkRGltcyhjZHMpJFBDQVt3aGljaC5taW4oYWJzKGNkcyRwc2V1ZG9zaXplX3BjYSAtIHRyYW5zaXRpb25zW1t4XV0pKSwgMV0sIDIpKSwKICAgIFBDMiA9IHNhcHBseShuYW1lcyh0cmFuc2l0aW9ucyksIGZ1bmN0aW9uKHgpIHJvdW5kKHJlZHVjZWREaW1zKGNkcykkUENBW3doaWNoLm1pbihhYnMoY2RzJHBzZXVkb3NpemVfcGNhIC0gdHJhbnNpdGlvbnNbW3hdXSkpLCAyXSwgMikpLAogICAgUEMzID0gc2FwcGx5KG5hbWVzKHRyYW5zaXRpb25zKSwgZnVuY3Rpb24oeCkgcm91bmQocmVkdWNlZERpbXMoY2RzKSRQQ0Fbd2hpY2gubWluKGFicyhjZHMkcHNldWRvc2l6ZV9wY2EgLSB0cmFuc2l0aW9uc1tbeF1dKSksIDNdLCAyKSkKICApKQoKICAjIFJldHVybiBwbG90cwogIHByaW50KGJyYW5jaF9wb2ludHNfcGxvdCkKICBwcmludChkZW5zaXR5X3Bsb3QpCgp9IGVsc2UgewogIHdhcm5pbmcoIlBzZXVkb3RpbWUgY29sdW1uICdwc2V1ZG9zaXplX3BjYScgbm90IGZvdW5kIikKICBOVUxMCn0KCiNTYXZlIHBsb3RzCmdnc2F2ZSgidHJhamVjdG9yeV9vdXRwdXQvZGVuc2l0eV9wbG90LnBuZyIsIHBsb3QgPSBkZW5zaXR5X3Bsb3QsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNiwgZHBpID0gMzAwKQoKc2F2ZVdpZGdldChicmFuY2hfcG9pbnRzX3Bsb3QsICJ0cmFqZWN0b3J5X291dHB1dC8gYnJhbmNoX3BvaW50c19wbG90Lmh0bWwiLCBzZWxmY29udGFpbmVkID0gVFJVRSkKCgpgYGAKCgpgYGB7ciB0cmFqZWN0b3JpZXMgdHJpYWwsIGVjaG8gPSBGQUxTRX0KCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKI1RISVMgSVMgQSBUUklBTCBDT0RFIEZPUiBUSEUgTkVYVCBQQVJULiBJVCBERUZJTkVTIFRIRSBJTkRJVklEVUFMIFRSQUpFQ1RPUklFUyBDT1JSRUNUTFkgQlVUIExBQ0tTIFRIRSBPVkVSTEFZIE9GIFRIRSBNT05PQ0xFMyBUUkFKRUNUT1JZIChJTiBCTEFDSyBDT0xPUikKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyAjIERlZmluZSB0cmFqZWN0b3JpZXMgd2l0aCBzYW1wbGUgaW5mb3JtYXRpb24KIyB0cmFqZWN0b3JpZXMgPC0gbGlzdCgKIyAgIGVhcmx5X2RldiA9IGxpc3QoCiMgICAgIG5hbWUgPSAiRWFybHkgRGV2ZWxvcG1lbnQiLAojICAgICBicmFuY2hlcyA9IGMoIlByZWJyYW5jaF8xIiwgIlByZWJyYW5jaF8yIiksCiMgICAgIGNvbG9yID0gYygiIzk5OTk5OSIsICJvcmFuZ2UiKSAgIyBHcmV5LCBPcmFuZ2UKIyAgICksCiMgICBhc2V4dWFsID0gbGlzdCgKIyAgICAgbmFtZSA9ICJBc2V4dWFsIFRyYWplY3RvcnkiLCAKIyAgICAgYnJhbmNoZXMgPSBjKCJQcmVicmFuY2hfMSIsICJQcmVicmFuY2hfMiIsICJCcmFuY2hfMSIpLAojICAgICBjb2xvciA9IGMoIiM5OTk5OTkiLCAib3JhbmdlIiwgIiMzNzdFQjgiKSAgIyBHcmV5LCBPcmFuZ2UsIEJsdWUKIyAgICksCiMgICBzZXh1YWwgPSBsaXN0KAojICAgICBuYW1lID0gIlNleHVhbCBUcmFqZWN0b3J5IiwKIyAgICAgYnJhbmNoZXMgPSBjKCJQcmVicmFuY2hfMSIsICJQcmVicmFuY2hfMiIsICJCcmFuY2hfMiIpLAojICAgICBjb2xvciA9IGMoIiM5OTk5OTkiLCAib3JhbmdlIiwgIiNFNDFBMUMiKSAgIyBHcmV5LCBPcmFuZ2UsIFJlZAojICAgKSwKIyAgIGxhdGVfZGV2ID0gbGlzdCgKIyAgICAgbmFtZSA9ICJMYXRlIERldmVsb3BtZW50IiwKIyAgICAgYnJhbmNoZXMgPSBjKCJCcmFuY2hfMSIsICJCcmFuY2hfMiIpLAojICAgICBjb2xvciA9IGMoIiMzNzdFQjgiLCAiI0U0MUExQyIpICAjIEJsdWUsIFJlZAojICAgKQojICkKIyAKIyAjIEFkZCBzYW1wbGUgSURzIHRvIGVhY2ggdHJhamVjdG9yeQojIGZvciAodHJhal9uYW1lIGluIG5hbWVzKHRyYWplY3RvcmllcykpIHsKIyAgIHRyYWplY3Rvcmllc1tbdHJhal9uYW1lXV0kc2FtcGxlcyA8LSByb3duYW1lcyhjb2xEYXRhKGNkcykpW2NkcyRicmFuY2ggJWluJSB0cmFqZWN0b3JpZXNbW3RyYWpfbmFtZV1dJGJyYW5jaGVzXQojIH0KIyAKIyAjIENyZWF0ZSBwbG90cyBmb3IgZWFjaCB0cmFqZWN0b3J5CiMgdHJhamVjdG9yeV9wbG90cyA8LSBsYXBwbHkodHJhamVjdG9yaWVzLCBmdW5jdGlvbih0cmFqKSB7CiMgICAjIENyZWF0ZSBhIGNvcHkgb2YgYnJhbmNoIGNvbG9ycyBmb3IgdGhpcyBwbG90CiMgICBwbG90X2NvbG9ycyA8LSBicmFuY2hfY29sb3JzCiMgICAjIEZhZGUgb3V0IG5vbi10cmFqZWN0b3J5IGJyYW5jaGVzICh2ZXJ5IGxpZ2h0IGdyZXkpCiMgICBwbG90X2NvbG9yc1shbmFtZXMocGxvdF9jb2xvcnMpICVpbiUgdHJhaiRicmFuY2hlc10gPC0gIiNGMEYwRjAiCiMgICAKIyAgICMgQmFzZSBwbG90CiMgICBwIDwtIHBsb3RfbHkoKSAlPiUKIyAgICAgbGF5b3V0KAojICAgICAgIHNjZW5lID0gbGlzdCgKIyAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJQQzEiKSwKIyAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJQQzIiKSwgCiMgICAgICAgICB6YXhpcyA9IGxpc3QodGl0bGUgPSAiUEMzIiksCiMgICAgICAgICBjYW1lcmEgPSBsaXN0KGV5ZSA9IGxpc3QoeCA9IC0xLjUsIHkgPSAtMS41LCB6ID0gMS41KSkKIyAgICAgICApLAojICAgICAgIHRpdGxlID0gbGlzdCh0ZXh0ID0gdHJhaiRuYW1lLCB5ID0gMC45NSwgeCA9IDAuNSwgeGFuY2hvciA9ICJjZW50ZXIiKSwKIyAgICAgICBsZWdlbmQgPSBsaXN0KG9yaWVudGF0aW9uID0gImgiKQojICAgICApCiMgICAKIyAgICMgQWRkIGFsbCBjZWxscyAobm9uLXRyYWplY3RvcnkgY2VsbHMgaW4gbGlnaHQgZ3JleSkKIyAgIGZvcihicmFuY2ggaW4gbGV2ZWxzKGNkcyRicmFuY2gpKSB7CiMgICAgIHAgPC0gcCAlPiUgYWRkX3RyYWNlKAojICAgICAgIHggPSByZWR1Y2VkRGltcyhjZHMpJFBDQVtjZHMkYnJhbmNoID09IGJyYW5jaCwgMV0sCiMgICAgICAgeSA9IHJlZHVjZWREaW1zKGNkcykkUENBW2NkcyRicmFuY2ggPT0gYnJhbmNoLCAyXSwKIyAgICAgICB6ID0gcmVkdWNlZERpbXMoY2RzKSRQQ0FbY2RzJGJyYW5jaCA9PSBicmFuY2gsIDNdLAojICAgICAgIHR5cGUgPSAic2NhdHRlcjNkIiwgCiMgICAgICAgbW9kZSA9ICJtYXJrZXJzIiwKIyAgICAgICBtYXJrZXIgPSBsaXN0KAojICAgICAgICAgc2l6ZSA9IGlmZWxzZShicmFuY2ggJWluJSB0cmFqJGJyYW5jaGVzLCA0LCAyKSwgICMgU21hbGxlciBmb3IgZmFkZWQgY2VsbHMKIyAgICAgICAgIGNvbG9yID0gcGxvdF9jb2xvcnNbYnJhbmNoXSwKIyAgICAgICAgIG9wYWNpdHkgPSBpZmVsc2UoYnJhbmNoICVpbiUgdHJhaiRicmFuY2hlcywgMSwgMC4zKSAgIyBNb3JlIHRyYW5zcGFyZW50IGZvciBmYWRlZAojICAgICAgICksCiMgICAgICAgbmFtZSA9IGlmZWxzZShicmFuY2ggJWluJSB0cmFqJGJyYW5jaGVzLCBicmFuY2gsIHBhc3RlMChicmFuY2gsICIgKG90aGVyKSIpKSwKIyAgICAgICBzaG93bGVnZW5kID0gYnJhbmNoICVpbiUgdHJhaiRicmFuY2hlcyAgIyBPbmx5IHNob3cgbGVnZW5kIGZvciB0cmFqZWN0b3J5IGJyYW5jaGVzCiMgICAgICkKIyAgIH0KIyAgIAojICAgIyBIaWdobGlnaHQgdHJhamVjdG9yeSBwYXRoICh0aGlja2VyIGJsYWNrIGxpbmUpCiMgICBwIDwtIHAgJT4lIGFkZF90cmFjZSgKIyAgICAgeCA9IGNkc0BwcmluY2lwYWxfZ3JhcGhfYXV4JFBDQSRkcF9tc3RbLDFdLAojICAgICB5ID0gY2RzQHByaW5jaXBhbF9ncmFwaF9hdXgkUENBJGRwX21zdFssMl0sIAojICAgICB6ID0gY2RzQHByaW5jaXBhbF9ncmFwaF9hdXgkUENBJGRwX21zdFssM10sCiMgICAgIHR5cGUgPSAic2NhdHRlcjNkIiwKIyAgICAgbW9kZSA9ICJsaW5lcyIsCiMgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gImJsYWNrIiwgd2lkdGggPSA4KSwKIyAgICAgbmFtZSA9ICJUcmFqZWN0b3J5IiwKIyAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFCiMgICApCiMgICAKIyAgICMgQWRkIHRyYW5zaXRpb24gcG9pbnRzIChvbmx5IGZvciBicmFuY2hlcyBpbiB0aGlzIHRyYWplY3RvcnkpCiMgICBmb3IgKGJyYW5jaCBpbiBpbnRlcnNlY3QobmFtZXModHJhbnNpdGlvbnMpLCB0cmFqJGJyYW5jaGVzKSkgewojICAgICBjb29yZHMgPC0gcmVkdWNlZERpbXMoY2RzKSRQQ0Fbd2hpY2gubWluKGFicyhjZHMkcHNldWRvc2l6ZV9wY2EgLSB0cmFuc2l0aW9uc1tbYnJhbmNoXV0pKSwgMTozXQojICAgICBwIDwtIHAgJT4lIGFkZF90cmFjZSgKIyAgICAgICB4ID0gY29vcmRzWzFdLCB5ID0gY29vcmRzWzJdLCB6ID0gY29vcmRzWzNdLAojICAgICAgIHR5cGUgPSAic2NhdHRlcjNkIiwKIyAgICAgICBtb2RlID0gIm1hcmtlcnMiLAojICAgICAgIG1hcmtlciA9IGxpc3QoCiMgICAgICAgICBzaXplID0gMTIsCiMgICAgICAgICBjb2xvciA9IGJyYW5jaF9jb2xvcnNbYnJhbmNoXSwKIyAgICAgICAgIHN5bWJvbCA9ICJkaWFtb25kIgojICAgICAgICksCiMgICAgICAgbmFtZSA9IHNwcmludGYoIiVzICh0PSUuMWYpIiwgYnJhbmNoLCB0cmFuc2l0aW9uc1tbYnJhbmNoXV0pLAojICAgICAgIGhvdmVyaW5mbyA9ICJ0ZXh0IiwKIyAgICAgICB0ZXh0ID0gc3ByaW50ZigiJXMgc3RhcnRcblBzZXVkb3RpbWU6ICUuMmYiLCBicmFuY2gsIHRyYW5zaXRpb25zW1ticmFuY2hdXSksCiMgICAgICAgc2hvd2xlZ2VuZCA9IFRSVUUKIyAgICAgKQojICAgfQojICAgCiMgICByZXR1cm4ocCkKIyB9KQojIAojICMgRGlzcGxheSBhbGwgcGxvdHMKIyB0cmFqZWN0b3J5X3Bsb3RzJGVhcmx5X2RldgojIHRyYWplY3RvcnlfcGxvdHMkYXNleHVhbAojIHRyYWplY3RvcnlfcGxvdHMkc2V4dWFsIAojIHRyYWplY3RvcnlfcGxvdHMkbGF0ZV9kZXYKIyAKIyAjIFlvdSBjYW4gYWxzbyBzYXZlIHRoZXNlIHBsb3RzCiMgIyBodG1sd2lkZ2V0czo6c2F2ZVdpZGdldChhc193aWRnZXQodHJhamVjdG9yeV9wbG90cyRlYXJseV9kZXYpLCAiZWFybHlfZGV2Lmh0bWwiKQpgYGAKCgoKYGBge3IgdHJhamVjdG9yaWVzfQoKIyBNaW5pbXVtIFNwYW5uaW5nIFRyZWUgY29vcmRpbmF0ZXMgKDMgcm93cyA9IFBDMSwgUEMyLCBQQzM7IDcgY29scyA9IG5vZGVzKSBtYW51YWxseSByZXRyaWV2ZWQgZnJvbSBNb25vY2xlMyBjZHMgb2JqZWN0OiBjZHNAcHJpbmNpcGFsX2dyYXBoX2F1eEBsaXN0RGF0YVtbIlVNQVAiXV1bWyJkcF9tc3QiXV0KCm1zdF9jb29yZHNfcmF3IDwtIG1hdHJpeCgKICBjKC0xLjAwMjkwMiwgIDEuODY5Mzg5NiwgIDEuODkyMjQ5LCAgMy4yNzA1NTIxLCAgNC4yMTE3ODExOSwgLTUuMzc2NzA0NCwgLTMuNTQzNjE0MDYsCiAgICAtMS4zODUyMjksIC0xLjk0NzYyNTIsIC0yLjc2NzQ3NywgIDAuNTE1MjUzOSwgIDMuMTkyMjY4OTUsICAxLjM1ODQyMzYsICAwLjA3ODg5OTY0LAogICAgLTIuMDE2MTAzLCAtMC44MTcyNzg2LCAgMi4xNTU3OTUsIC0wLjQ0MjcyNDQsICAwLjAxMzcyOTcyLCAgMC45MzU4NDgyLCAtMC40NDA1ODU3NiksCiAgbnJvdyA9IDMsIGJ5cm93ID0gVFJVRSwKICBkaW1uYW1lcyA9IGxpc3QoYygiUEMxIiwgIlBDMiIsICJQQzMiKSwgcGFzdGUwKCJZXyIsIDE6NykpCikKCiMgVHJhbnNwb3NlIHNvIHJvd3MgPSBub2RlcywgY29scyA9IFBDcwptc3RfY29vcmRzIDwtIHQobXN0X2Nvb3Jkc19yYXcpCmNvbG5hbWVzKG1zdF9jb29yZHMpIDwtIGMoIlBDMSIsICJQQzIiLCAiUEMzIikKCiMgTVNUIGVkZ2VzIG1hbnVhbGx5IHJldHJlaXZlZCBmcm9tIGNkcyBvYmplY3QgYW5kIGRlZmluZWQgKG5vZGUgaW5kaWNlcywgbWF0Y2hpbmcgcm93bmFtZXMgaW4gbXN0X2Nvb3JkcykKbXN0X2VkZ2VzIDwtIGxpc3QoCiAgYygxLDIpLAogIGMoMiwzKSwKICBjKDIsNCksCiAgYyg0LDUpLAogIGMoMSw3KSwKICBjKDYsNykKKQoKIyBPcHRpb25hbDogRGVmaW5lIHRyYWplY3RvcmllcyBhbmQgdGhlaXIgYnJhbmNoZXMgJiBjb2xvcnMgKFRoaXMgaXMgb3B0aW9uYWwgYXMgaXQgaXMgYWxyZWFkeSBkZWZpbmVkIGFib3ZlKQp0cmFqZWN0b3JpZXMgPC0gbGlzdCgKICBlYXJseV9kZXYgPSBsaXN0KAogICAgbmFtZSA9ICJFYXJseSBEZXZlbG9wbWVudCIsCiAgICBicmFuY2hlcyA9IGMoIlByZWJyYW5jaF8xIiwgIlByZWJyYW5jaF8yIiksCiAgICBjb2xvciA9IGMoIiM5OTk5OTkiLCAib3JhbmdlIikKICApLAogIGFzZXh1YWwgPSBsaXN0KAogICAgbmFtZSA9ICJBc2V4dWFsIFRyYWplY3RvcnkiLAogICAgYnJhbmNoZXMgPSBjKCJQcmVicmFuY2hfMSIsICJQcmVicmFuY2hfMiIsICJCcmFuY2hfMSIpLAogICAgY29sb3IgPSBjKCIjOTk5OTk5IiwgIm9yYW5nZSIsICIjMzc3RUI4IikKICApLAogIHNleHVhbCA9IGxpc3QoCiAgICBuYW1lID0gIlNleHVhbCBUcmFqZWN0b3J5IiwKICAgIGJyYW5jaGVzID0gYygiUHJlYnJhbmNoXzEiLCAiUHJlYnJhbmNoXzIiLCAiQnJhbmNoXzIiKSwKICAgIGNvbG9yID0gYygiIzk5OTk5OSIsICJvcmFuZ2UiLCAiI0U0MUExQyIpCiAgKSwKICBsYXRlX2RldiA9IGxpc3QoCiAgICBuYW1lID0gIkxhdGUgRGV2ZWxvcG1lbnQiLAogICAgYnJhbmNoZXMgPSBjKCJCcmFuY2hfMSIsICJCcmFuY2hfMiIpLAogICAgY29sb3IgPSBjKCIjMzc3RUI4IiwgIiNFNDFBMUMiKQogICksCiAgYWxsX2NsdXN0ZXJzID0gbGlzdCgKICAgIG5hbWUgPSAiQWxsIENsdXN0ZXJzIiwKICAgIGJyYW5jaGVzID0gbGV2ZWxzKGNkcyRicmFuY2gpLAogICAgY29sb3IgPSB1bm5hbWUoYnJhbmNoX2NvbG9yc1tsZXZlbHMoY2RzJGJyYW5jaCldKQogICkKKQoKIyBBZGQgc2FtcGxlIElEcyBmb3IgZWFjaCB0cmFqZWN0b3J5CmZvciAodHJhal9uYW1lIGluIG5hbWVzKHRyYWplY3RvcmllcykpIHsKICB0cmFqZWN0b3JpZXNbW3RyYWpfbmFtZV1dJHNhbXBsZXMgPC0gcm93bmFtZXMoY29sRGF0YShjZHMpKVtjZHMkYnJhbmNoICVpbiUgdHJhamVjdG9yaWVzW1t0cmFqX25hbWVdXSRicmFuY2hlc10KfQoKIyBIZWxwZXIgZnVuY3Rpb24gdG8gZ2V0IGNvb3JkaW5hdGVzIGF0IG1pbmltYWwgcHNldWRvdGltZSBpbiBhIGJyYW5jaApnZXRfY29vcmRzX2F0X3BzZXVkb3RpbWUgPC0gZnVuY3Rpb24oY2RzLCBwc2V1ZG90aW1lX3ZhbCkgewogIGlkeCA8LSB3aGljaC5taW4oYWJzKGNkcyRwc2V1ZG9zaXplX3BjYSAtIHBzZXVkb3RpbWVfdmFsKSkKICByZWR1Y2VkRGltcyhjZHMpJFBDQVtpZHgsIDE6M10KfQoKIyBCcmFuY2ggdHJhbnNpdGlvbiBwc2V1ZG90aW1lIHZhbHVlcwp0cmFuc2l0aW9ucyA8LSBsaXN0KAogIFByZWJyYW5jaF8yID0gbWluKGNkcyRwc2V1ZG9zaXplX3BjYVtjZHMkYnJhbmNoID09ICJQcmVicmFuY2hfMiJdLCBuYS5ybSA9IFRSVUUpLAogIEJyYW5jaF8xID0gbWluKGNkcyRwc2V1ZG9zaXplX3BjYVtjZHMkYnJhbmNoID09ICJCcmFuY2hfMSJdLCBuYS5ybSA9IFRSVUUpLAogIEJyYW5jaF8yID0gbWluKGNkcyRwc2V1ZG9zaXplX3BjYVtjZHMkYnJhbmNoID09ICJCcmFuY2hfMiJdLCBuYS5ybSA9IFRSVUUpCikKdHJhbnNpdGlvbnMgPC0gdHJhbnNpdGlvbnNbIWlzLmluZmluaXRlKHVubGlzdCh0cmFuc2l0aW9ucykpICYgIWlzLm5hKHVubGlzdCh0cmFuc2l0aW9ucykpXQoKIyBQbG90dGluZyBsb29wCnRyYWplY3RvcnlfcGxvdHMgPC0gbGFwcGx5KHRyYWplY3RvcmllcywgZnVuY3Rpb24odHJhaikgewogIHBsb3RfY29sb3JzIDwtIGJyYW5jaF9jb2xvcnMKICBwbG90X2NvbG9yc1shbmFtZXMocGxvdF9jb2xvcnMpICVpbiUgdHJhaiRicmFuY2hlc10gPC0gIiNGMEYwRjAiCiAgCiAgdHJhamVjdG9yeV9wbG90IDwtIHBsb3RfbHkoKSAlPiUKICAgIGxheW91dCgKICAgICAgc2NlbmUgPSBsaXN0KAogICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJQQzEiKSwKICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiUEMyIiksCiAgICAgICAgemF4aXMgPSBsaXN0KHRpdGxlID0gIlBDMyIpCiAgICAgICksCiAgICAgIHRpdGxlID0gbGlzdCh0ZXh0ID0gdHJhaiRuYW1lLCB5ID0gMC45NSwgeCA9IDAuNSwgeGFuY2hvciA9ICJjZW50ZXIiKSwKICAgICAgbGVnZW5kID0gbGlzdChvcmllbnRhdGlvbiA9ICJoIiwgeCA9IDAuNSwgeGFuY2hvciA9ImNlbnRlciIsIHkgPSAtMC4xLCB5YW5jaG9yID0gInRvcCIpCiAgICApCiAgCiAgZm9yKGJyYW5jaCBpbiBsZXZlbHMoY2RzJGJyYW5jaCkpIHsKICAgIHRyYWplY3RvcnlfcGxvdCA8LSB0cmFqZWN0b3J5X3Bsb3QgJT4lIGFkZF90cmFjZSgKICAgICAgeCA9IHJlZHVjZWREaW1zKGNkcykkUENBW2NkcyRicmFuY2ggPT0gYnJhbmNoLCAxXSwKICAgICAgeSA9IHJlZHVjZWREaW1zKGNkcykkUENBW2NkcyRicmFuY2ggPT0gYnJhbmNoLCAyXSwKICAgICAgeiA9IHJlZHVjZWREaW1zKGNkcykkUENBW2NkcyRicmFuY2ggPT0gYnJhbmNoLCAzXSwKICAgICAgdHlwZSA9ICJzY2F0dGVyM2QiLAogICAgICBtb2RlID0gIm1hcmtlcnMiLAogICAgICBtYXJrZXIgPSBsaXN0KAogICAgICAgIHNpemUgPSBpZmVsc2UoYnJhbmNoICVpbiUgdHJhaiRicmFuY2hlcywgNCwgMyksCiAgICAgICAgY29sb3IgPSBwbG90X2NvbG9yc1ticmFuY2hdLAogICAgICAgIG9wYWNpdHkgPSBpZmVsc2UoYnJhbmNoICVpbiUgdHJhaiRicmFuY2hlcywgMSwgMC4zKQogICAgICApLAogICAgICBuYW1lID0gaWZlbHNlKGJyYW5jaCAlaW4lIHRyYWokYnJhbmNoZXMsIGJyYW5jaCwgcGFzdGUwKGJyYW5jaCwgIiAob3RoZXIpIikpLAogICAgICBzaG93bGVnZW5kID0gYnJhbmNoICVpbiUgdHJhaiRicmFuY2hlcwogICAgKQogIH0KICAKICBmb3IoZWRnZSBpbiBtc3RfZWRnZXMpIHsKICAgIHRyYWplY3RvcnlfcGxvdCA8LSB0cmFqZWN0b3J5X3Bsb3QgJT4lIGFkZF90cmFjZSgKICAgICAgeCA9IG1zdF9jb29yZHNbZWRnZSwgIlBDMSJdLAogICAgICB5ID0gbXN0X2Nvb3Jkc1tlZGdlLCAiUEMyIl0sCiAgICAgIHogPSBtc3RfY29vcmRzW2VkZ2UsICJQQzMiXSwKICAgICAgdHlwZSA9ICJzY2F0dGVyM2QiLAogICAgICBtb2RlID0gImxpbmVzIiwKICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAiYmxhY2siLCB3aWR0aCA9IDQpLAogICAgICBzaG93bGVnZW5kID0gRkFMU0UKICAgICkKICB9CiAgCiAgZm9yKGJyYW5jaCBpbiBpbnRlcnNlY3QobmFtZXModHJhbnNpdGlvbnMpLCB0cmFqJGJyYW5jaGVzKSkgewogICAgY29vcmRzIDwtIGdldF9jb29yZHNfYXRfcHNldWRvdGltZShjZHMsIHRyYW5zaXRpb25zW1ticmFuY2hdXSkKICAgIHRyYWplY3RvcnlfcGxvdCA8LSB0cmFqZWN0b3J5X3Bsb3QgJT4lIGFkZF90cmFjZSgKICAgICAgeCA9IGNvb3Jkc1sxXSwgeSA9IGNvb3Jkc1syXSwgeiA9IGNvb3Jkc1szXSwKICAgICAgdHlwZSA9ICJzY2F0dGVyM2QiLAogICAgICBtb2RlID0gIm1hcmtlcnMiLAogICAgICBtYXJrZXIgPSBsaXN0KAogICAgICAgIHNpemUgPSA3LAogICAgICAgIGNvbG9yID0gYnJhbmNoX2NvbG9yc1ticmFuY2hdLAogICAgICAgIHN5bWJvbCA9ICJ4IgogICAgICApLAogICAgICBuYW1lID0gc3ByaW50ZigiJXMgKHQ9JS4xZikiLCBicmFuY2gsIHRyYW5zaXRpb25zW1ticmFuY2hdXSksCiAgICAgIGhvdmVyaW5mbyA9ICJ0ZXh0IiwKICAgICAgdGV4dCA9IHNwcmludGYoIiVzIHN0YXJ0XG5Qc2V1ZG90aW1lOiAlLjJmIiwgYnJhbmNoLCB0cmFuc2l0aW9uc1tbYnJhbmNoXV0pLAogICAgICBzaG93bGVnZW5kID0gVFJVRQogICAgKQogIH0KICAKICByZXR1cm4odHJhamVjdG9yeV9wbG90KQp9KQoKIyBEaXNwbGF5IHBsb3RzCnRyYWplY3RvcnlfcGxvdHMkZWFybHlfZGV2CnRyYWplY3RvcnlfcGxvdHMkYXNleHVhbAp0cmFqZWN0b3J5X3Bsb3RzJHNleHVhbAp0cmFqZWN0b3J5X3Bsb3RzJGxhdGVfZGV2CnRyYWplY3RvcnlfcGxvdHMkYWxsX2NsdXN0ZXJzCgoKc2F2ZVdpZGdldCh0cmFqZWN0b3J5X3Bsb3RzJGVhcmx5X2RldiwgInRyYWplY3Rvcnlfb3V0cHV0L2Vhcmx5X2Rldi5odG1sIiwgc2VsZmNvbnRhaW5lZCA9IFRSVUUpCnNhdmVXaWRnZXQodHJhamVjdG9yeV9wbG90cyRhc2V4dWFsLCAidHJhamVjdG9yeV9vdXRwdXQvYXNleHVhbC5odG1sIiwgc2VsZmNvbnRhaW5lZCA9IFRSVUUpCnNhdmVXaWRnZXQodHJhamVjdG9yeV9wbG90cyRzZXh1YWwsICJ0cmFqZWN0b3J5X291dHB1dC9zZXh1YWwuaHRtbCIsIHNlbGZjb250YWluZWQgPSBUUlVFKQpzYXZlV2lkZ2V0KHRyYWplY3RvcnlfcGxvdHMkbGF0ZV9kZXYsICJ0cmFqZWN0b3J5X291dHB1dC9sYXRlX2Rldi5odG1sIiwgc2VsZmNvbnRhaW5lZCA9IFRSVUUpCnNhdmVXaWRnZXQodHJhamVjdG9yeV9wbG90cyRhbGxfY2x1c3RlcnMsICJ0cmFqZWN0b3J5X291dHB1dC9hbGxfY2x1c3RlcnMuaHRtbCIsIHNlbGZjb250YWluZWQgPSBUUlVFKQpgYGAKIAoKIyMjIDMuIEFidW5kYW5jZSBBbmFseXNpcwoKQ2VsbCB0eXBlIGFidW5kYW5jZSBwYXR0ZXJucyB3ZXJlIGFuYWx5emVkIGFsb25nIHBzZXVkb3RpbWUgdHJhamVjdG9yaWVzIHRvIGlkZW50aWZ5IGNvbXBvc2l0aW9uYWwgY2hhbmdlcyBhc3NvY2lhdGVkIHdpdGggZ3Jvd3RoLiBUaGUgYW5hbHlzaXMgZm9jdXNlZCBvbiDCsTUlIHBzZXVkb3RpbWUgd2luZG93cyBhcm91bmQgZWFjaCBicmFuY2ggcG9pbnQsIGNvbXBhcmluZyBsb2NhbCBjZWxsIHR5cGUgcHJvcG9ydGlvbnMgdG8gdGhlaXIgZ2xvYmFsIG1lYW4gYWJ1bmRhbmNlIGFjcm9zcyB0aGUgY29ycmVzcG9uZGluZyB0cmFqZWN0b3J5LiBXaWxjb3hvbiByYW5rLXN1bSB0ZXN0cyBpZGVudGlmaWVkIHNpZ25pZmljYW50bHkgZW5yaWNoZWQgb3IgZGVwbGV0ZWQgY2VsbCB0eXBlcyBkdXJpbmcgdHJhbnNpdGlvbnMsIHdpdGggdGhyZWUgYWx0ZXJuYXRpdmUgaHlwb3RoZXNlcyB0ZXN0ZWQ6IGVucmljaG1lbnQsIGRlcGxldGlvbiwgYW5kIG5vbi1kaXJlY3Rpb25hbCBjaGFuZ2VzICgidHdvLnNpZGVkIikuIFJlc3VsdHMgd2VyZSB2aXN1YWxpemVkIHVzaW5nIHNtb290aGVkIGxvZXNzIGN1cnZlcyBzaG93aW5nIGNlbGwgdHlwZSBwcm9wb3J0aW9ucyBhbG9uZyBwc2V1ZG90aW1lLCB3aXRoIGJyYW5jaCBwb2ludHMgbWFya2VkIGJ5IHZlcnRpY2FsIGxpbmVzLgoKRW5yaWNoZWQgY2VsbCB0eXBlcyBuZWFyIGJyYW5jaCBwb2ludHMgbWF5IHJlcHJlc2VudCB0cmFuc2l0aW9uYWwgc3RhdGVzIG9yIGZhdGUtY29tbWl0dGVkIHByb2dlbml0b3JzLiBUaGVzZSBwb3B1bGF0aW9ucyBvZnRlbiBwbGF5IGNyaXRpY2FsIHJvbGVzIGluIGxpbmVhZ2UgYmlmdXJjYXRpb24sIGVpdGhlciBhcyBiaXBvdGVudCBpbnRlcm1lZGlhdGVzIG9yIGFzIHNvdXJjZXMgb2YgaW5zdHJ1Y3RpdmUgc2lnbmFscy4gQ29udmVyc2VseSwgZGVwbGV0ZWQgY2VsbCB0eXBlcyBzdWdnZXN0IG11dHVhbGx5IGV4Y2x1c2l2ZSBmYXRlIGNob2ljZXMgb3IgdGVtcG9yYWwgc2VwYXJhdGlvbiBvZiBkZXZlbG9wbWVudGFsIHByb2dyYW1zLiBDZWxsIHR5cGVzIHNob3dpbmcgY29udGV4dC1kZXBlbmRlbnQgYWJ1bmRhbmNlIGNoYW5nZXMgYWNyb3NzIGRpZmZlcmVudCBicmFuY2hlcyBtYXkgaW5kaWNhdGUgZGV2ZWxvcG1lbnRhbCBwbGFzdGljaXR5LCB3aGVyZSBwb3B1bGF0aW9ucyByZXRhaW4gdGhlIGNhcGFjaXR5IGZvciBtdWx0aXBsZSBmYXRlIGRlY2lzaW9ucyBiYXNlZCBvbiBsb2NhbCBjb25kaXRpb25zLgoKVGhlIHRpbWluZyBvZiBhYnVuZGFuY2UgcGVha3MgcmVsYXRpdmUgdG8gYnJhbmNoIHBvaW50cyBwcm92aWRlcyBpbnNpZ2h0cyBpbnRvIHRoZSBvcmRlcmluZyBvZiBtb2xlY3VsYXIgZXZlbnRzLiBFYXJseS1hcHBlYXJpbmcgY2VsbCB0eXBlcyBsaWtlbHkgcmVmbGVjdCBpbml0aWFsIGZhdGUgcHJpbWluZywgd2hpbGUgbGF0ZS1hcHBlYXJpbmcgcG9wdWxhdGlvbnMgbWF5IHJlcHJlc2VudCB0ZXJtaW5hbCBkaWZmZXJlbnRpYXRpb24gc3RhdGVzLiBUaGUgcHNldWRvdGVtcG9yYWwgd2luZG93aW5nIGFwcHJvYWNoIGNhcHR1cmVzIHRoZXNlIGR5bmFtaWNzIHdoaWxlIGFjY291bnRpbmcgZm9yIHZhcmlhYmlsaXR5IGluIGRpZmZlcmVudGlhdGlvbiBraW5ldGljcyBhY3Jvc3MgY2VsbHMuIEFsbCBmaW5kaW5ncyB3ZXJlIGludGVycHJldGVkIGNvbnNpZGVyaW5nIHRoZSBjb21wb3NpdGlvbmFsIG5hdHVyZSBvZiB0aGUgZGF0YSwgd2hlcmUgY2hhbmdlcyBpbiBvbmUgY2VsbCB0eXBlIG5lY2Vzc2FyaWx5IGluZmx1ZW5jZSB0aGUgaW50ZXJwcmV0YXRpb24gb2Ygb3RoZXJzIGluIHRoZSBlY29zeXN0ZW0uCgpUZWNobmljYWwgdmFsaWRhdGlvbiBjb25maXJtZWQgdGhlIHJvYnVzdG5lc3Mgb2YgcmVzdWx0cyB0byBwc2V1ZG90aW1lIHJlY29uc3RydWN0aW9uIHBhcmFtZXRlcnMgYW5kIHdpbmRvdyBzaXplIHNlbGVjdGlvbi4gV2hpbGUgdGhlIGFuYWx5c2lzIHByb3ZpZGVzIHN0YXRpc3RpY2FsIGlkZW50aWZpY2F0aW9uIG9mIGludGVyZXN0aW5nIGNlbGwgcG9wdWxhdGlvbnMsIGRlZXBlciBiaW9sb2dpY2FsIGludGVycHJldGF0aW9uIHJlcXVpcmVzIGludGVncmF0aW9uIHdpdGgga25vd24gbGluZWFnZSByZWxhdGlvbnNoaXBzIGFuZCBtYXJrZXIgZ2VuZSBleHByZXNzaW9uIHBhdHRlcm5zIGZyb20gdGhlIGJyb2FkZXIgZGF0YXNldC4gVGhlIGNvbWJpbmVkIGFwcHJvYWNoIHJldmVhbHMgaG93IGNlbGx1bGFyIGhldGVyb2dlbmVpdHkgaXMgZHluYW1pY2FsbHkgcmVndWxhdGVkIGR1cmluZyBncm93dGguCgp8ICoqVHJhamVjdG9yeSoqICAgICAgICAgICAgIHwgKipFbnJpY2hlZCBDZWxsIFR5cGVzKiogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18CnwgKipFYXJseSBEZXZlbG9wbWVudCoqPGJyPlByZWJyYW5jaF8yIC0gRW5yaWNobWVudCB8IENhdGhlcHNpbiA1LCBJbnRlc3RpbmUgMSwgSW50ZXN0aW5lIDYsIENhdGhlcHNpbiAyLCBOZXVyYWwgNSwgQ2F0aGVwc2luIDYsIFBhcmVuY2h5bWFsIDMsIE5ldXJhbCA4LCBOZXVyYWwgMSwgSW50ZXN0aW5lIDQgfAp8ICoqQXNleHVhbCoqPGJyPkJyYW5jaF8xIC0gRW5yaWNobWVudCAgICAgICAgICAgIHwgQ2F0aGVwc2luIDEsIENhdGhlcHNpbiAzLCBOZXVyYWwgNCwgSW50ZXN0aW5lIDUsIENhdGhlcHNpbiA0LCBQYXJlbmNoeW1hbCA2LCBFcGlkZXJtYWwgNSwgSW50ZXN0aW5lIDMsIENhdGhlcHNpbiA4LCBQYXJlbmNoeW1hbCAxIHwKfCAqKlNleHVhbCoqPGJyPkJyYW5jaF8yIC0gRW5yaWNobWVudCAgICAgICAgICAgICB8IFBhcmVuY2h5bWFsIDUsIFRlc3RlcywgU2l6ZSBzcGVjaWZpYyAyLCBFcGlkZXJtYWwgNSwgTmV1cmFsIDQsIFNpemUgc3BlY2lmaWMgMSwgQ2F0aGVwc2luIDQsIENhdGhlcHNpbiAzLCBQYXJlbmNoeW1hbCAxLCBFcGlkZXJtYWwgOCB8CgoKfCAqKlRyYWplY3RvcnkqKiAgICAgICAgICAgICB8ICoqRGVwbGV0ZWQgQ2VsbCBUeXBlcyoqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfAp8ICoqRWFybHkgRGV2ZWxvcG1lbnQqKjxicj5QcmVicmFuY2hfMiAtIERlcGxldGlvbiB8IFNpemUgc3BlY2lmaWMgMSwgRXBpZGVybWFsIDQsIFNpemUgc3BlY2lmaWMgMiwgUGFyZW5jaHltYWwgNSwgRXBpZGVybWFsIDMsIEVwaWRlcm1hbCA4LCBFcGlkZXJtYWwgMiwgTmV1cmFsIDEwLCBJbnRlc3RpbmUgMiwgVGVzdGVzIHwKfCAqKkFzZXh1YWwqKjxicj5CcmFuY2hfMSAtIERlcGxldGlvbiAgICAgICAgICAgIHwgRXBpZGVybWFsIDgsIE11c2NsZSAzLCBNdXNjbGUgMiwgTXVzY2xlIDUsIE5ldXJhbCA2LCBQYXJlbmNoeW1hbCAyLCBOZW9ibGFzdCAyLCBQYXJlbmNoeW1hbCA0LCBOZXVyYWwgMiwgUGFyZW5jaHltYWwgNSB8CnwgKipTZXh1YWwqKjxicj5CcmFuY2hfMiAtIERlcGxldGlvbiAgICAgICAgICAgICB8IE11c2NsZSAyLCBOZXVyYWwgMSwgTXVzY2xlIDMsIEVwaWRlcm1hbCAxLCBQYXJlbmNoeW1hbCAzLCBDYXRoZXBzaW4gNSwgTmV1cmFsIDIsIE5ldXJhbCAzLCBJbnRlc3RpbmUgMiwgSW50ZXN0aW5lIDYgfAoKYGBge3IgYWJ1bmRhbmNlIGFuYWx5c2lzIHByZXBhcmF0aW9ufQoKCiMgRW5zdXJlIHNhbXBsZSBuYW1lcyBtYXRjaCBiZXR3ZWVuIGNlbGxfY291bnRzIGFuZCBjb2xkYXQKcm93bmFtZXMoY2VsbF9jb3VudHMpIDwtIGdzdWIoIi0iLCAiLiIsIHJvd25hbWVzKGNlbGxfY291bnRzKSkgICMgSGFybW9uaXplIG5hbWluZyBpZiBuZWVkZWQKY29sZGF0IDwtIGNvbGRhdFtjb2xuYW1lcyhjZWxsX2NvdW50cyksIF0gICMgUmVvcmRlciBjb2xkYXQgdG8gbWF0Y2ggY2VsbF9jb3VudHMgY29sdW1ucwoKIyBOb3JtYWxpemUgY291bnRzIHRvIHByb3BvcnRpb25zIChpZiBub3QgYWxyZWFkeSBub3JtYWxpemVkKQpjZWxsX3Byb3BzIDwtIHQodChjZWxsX2NvdW50cykgLyBjb2xTdW1zKGNlbGxfY291bnRzKSkgICMgUm93cyA9IGNlbGwgdHlwZXMsIGNvbHVtbnMgPSBzYW1wbGVzCgojVGhpcyB3YXMgcHJldmlvdXNseSBsaXN0ZWQgaW4gYW5vdGhlciBjaHVuaywgYnV0IEkgYW0gcnVubmluZyBpdCBhZ2FpbiBqdXN0IGZvciBjbGFyaXR5CnRyYW5zaXRpb25zIDwtIGxpc3QoCiAgUHJlYnJhbmNoXzIgPSBtaW4oY2RzJHBzZXVkb3NpemVfcGNhW2NkcyRicmFuY2ggPT0gIlByZWJyYW5jaF8yIl0sIG5hLnJtID0gVFJVRSksCiAgQnJhbmNoXzEgPSBtaW4oY2RzJHBzZXVkb3NpemVfcGNhW2NkcyRicmFuY2ggPT0gIkJyYW5jaF8xIl0sIG5hLnJtID0gVFJVRSksIAogIEJyYW5jaF8yID0gbWluKGNkcyRwc2V1ZG9zaXplX3BjYVtjZHMkYnJhbmNoID09ICJCcmFuY2hfMiJdLCBuYS5ybSA9IFRSVUUpCikKCgojIG1pbl9wcmVicmFuY2gyX3RpbWUgPC0gdHJhbnNpdGlvbnMkUHJlYnJhbmNoXzIKIyBtaW5fYnJhbmNoMV90aW1lIDwtIHRyYW5zaXRpb25zJEJyYW5jaF8xCiMgbWluX2JyYW5jaDJfdGltZSA8LSB0cmFuc2l0aW9ucyRCcmFuY2hfMgoKCmBgYAoKCgoKYGBge3IgYWJ1bmFuY2UgYW5hbHlzaXN9CgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMgRnVuY3Rpb246IGFuYWx5emVfYWJ1bmRhbmNlX2Zvcl9icmFuY2gKIyBQdXJwb3NlOiBJZGVudGlmeSBjZWxsIHR5cGVzIHdob3NlIGFidW5kYW5jZSBzaWduaWZpY2FudGx5IGNoYW5nZXMgYXJvdW5kIGEgdHJhamVjdG9yeSBicmFuY2ggcG9pbnQuCiMgSXQgY29tcHV0ZXMgZm9sZC1jaGFuZ2UsIHBlcmZvcm1zIFdpbGNveG9uIHRlc3RzLCBhbmQgdmlzdWFsaXplcyBzbW9vdGhlZCBhYnVuZGFuY2UgdHJlbmRzLgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgphbmFseXplX2FidW5kYW5jZV9mb3JfYnJhbmNoIDwtIGZ1bmN0aW9uKAogIGNkcywgY2VsbF9wcm9wcywgY29sZGF0LCB0cmFqZWN0b3JpZXMsIHRyYW5zaXRpb25zLAogIHRyYWplY3Rvcnlfa2V5LCBicmFuY2hfbmFtZSwKICB0ZXN0X3R5cGUgPSBjKCJFbnJpY2htZW50IiwgIkRlcGxldGlvbiIsICJUd28gU2lkZWQgVGVzdCIpLAogIHRyYW5zaXRpb25fY29sb3IgPSAiYmxhY2siLAogIHNhdmVfcHJlZml4ID0gTlVMTAopIHsKICAKICAgICMgQ2hvb3NlIGFsdGVybmF0aXZlIGh5cG90aGVzaXMgZm9yIFdpbGNveG9uIHRlc3QgYmFzZWQgb24gdXNlciBpbnB1dAogIHdpbGNveF9hbHRlcm5hdGl2ZSA8LSBzd2l0Y2gobWF0Y2guYXJnKHRlc3RfdHlwZSksCiAgICAiRW5yaWNobWVudCIgPSAiZ3JlYXRlciIsCiAgICAiRGVwbGV0aW9uIiA9ICJsZXNzIiwKICAgICJUd28gU2lkZWQgVGVzdCIgPSAidHdvLnNpZGVkIgogICkKICAKICAjTG9hZCBuZWNlc3NhcnkgbGlicmFyaWVzCiAgbGlicmFyeShkcGx5cikKICBsaWJyYXJ5KGJyb29tKQogIGxpYnJhcnkoZ2dwbG90MikKICBsaWJyYXJ5KHJlc2hhcGUyKQoKICB0ZXN0X3R5cGUgPC0gbWF0Y2guYXJnKHRlc3RfdHlwZSkKCiAgIyBSZXRyaWV2ZSBtZXRhZGF0YSBmb3IgdGhlIHRyYWplY3Rvcnkgb2YgaW50ZXJlc3QKICB0cmFqIDwtIHRyYWplY3Rvcmllc1tbdHJhamVjdG9yeV9rZXldXQogIGNsdXN0ZXJzIDwtIHRyYWokYnJhbmNoZXMKICB0cmFuc2l0aW9uX3RpbWUgPC0gdHJhbnNpdGlvbnNbW2JyYW5jaF9uYW1lXV0KICAKICAjIERlZmluZSB0aGUgcHNldWRvdGltZSB3aW5kb3cgKMKxNSUpIGFyb3VuZCB0aGUgYnJhbmNoIHBvaW50CiAgdHJhbnNpdGlvbl93aW5kb3cgPC0gMC4wNSAqIG1heChjb2xkYXQkcHNldWRvc2l6ZV9wY2EsIG5hLnJtID0gVFJVRSkKCiAgIyBJZGVudGlmeSBzYW1wbGUgSURzIGluIHRoaXMgdHJhamVjdG9yeQogIHRyYWpfc2FtcGxlcyA8LSByb3duYW1lcyhjb2xkYXQpW2NvbGRhdCRjbHVzdGVyICVpbiUgY2x1c3RlcnNdCgogICMgQ29tcHV0ZSBmb2xkLWNoYW5nZSBpbiBhYnVuZGFuY2UgKHRyYW5zaXRpb24gd2luZG93IHZzIGdsb2JhbCkKICBjb21wdXRlX2ZjIDwtIGZ1bmN0aW9uKGNlbGxfdHlwZSkgewogICAgZ2xvYmFsX21lYW4gPC0gbWVhbihjZWxsX3Byb3BzW2NlbGxfdHlwZSwgdHJhal9zYW1wbGVzXSwgbmEucm0gPSBUUlVFKQogICAgd2luZG93X3NhbXBsZXMgPC0gcm93bmFtZXMoY29sZGF0KVsKICAgICAgY29sZGF0JHBzZXVkb3NpemVfcGNhID49ICh0cmFuc2l0aW9uX3RpbWUgLSB0cmFuc2l0aW9uX3dpbmRvdykgJgogICAgICBjb2xkYXQkcHNldWRvc2l6ZV9wY2EgPD0gKHRyYW5zaXRpb25fdGltZSArIHRyYW5zaXRpb25fd2luZG93KQogICAgXQogICAgd2luZG93X21lYW4gPC0gbWVhbihjZWxsX3Byb3BzW2NlbGxfdHlwZSwgd2luZG93X3NhbXBsZXNdLCBuYS5ybSA9IFRSVUUpCiAgICBkYXRhLmZyYW1lKAogICAgICBjZWxsX3R5cGUgPSBjZWxsX3R5cGUsCiAgICAgIGdsb2JhbF9wcm9wID0gZ2xvYmFsX21lYW4sCiAgICAgIHRyYW5zaXRpb25fcHJvcCA9IHdpbmRvd19tZWFuLAogICAgICBmb2xkX2NoYW5nZSA9IHdpbmRvd19tZWFuIC8gZ2xvYmFsX21lYW4KICAgICkKICB9CgogICMgUGVyZm9ybSBXaWxjb3hvbiByYW5rLXN1bSB0ZXN0IHRvIGFzc2VzcyBlbnJpY2htZW50L2RlcGxldGlvbgogIHRlc3RfZW5yaWNobWVudCA8LSBmdW5jdGlvbihjZWxsX3R5cGUpIHsKICAgIGluX3dpbmRvdyA8LSBjb2xkYXQkcHNldWRvc2l6ZV9wY2EgPj0gKHRyYW5zaXRpb25fdGltZSAtIHRyYW5zaXRpb25fd2luZG93KSAmCiAgICAgICAgICAgICAgICAgY29sZGF0JHBzZXVkb3NpemVfcGNhIDw9ICh0cmFuc2l0aW9uX3RpbWUgKyB0cmFuc2l0aW9uX3dpbmRvdykKICAgIHRlc3QgPC0gd2lsY294LnRlc3QoCiAgICAgIHggPSBjZWxsX3Byb3BzW2NlbGxfdHlwZSwgaW5fd2luZG93XSwKICAgICAgeSA9IGNlbGxfcHJvcHNbY2VsbF90eXBlLCAhaW5fd2luZG93XSwKICAgICAgYWx0ZXJuYXRpdmUgPSB3aWxjb3hfYWx0ZXJuYXRpdmUKICAgICkKICAjICAgdGlkeSh0ZXN0KSAlPiUgbXV0YXRlKGNlbGxfdHlwZSA9IGNlbGxfdHlwZSkKICAjIH0KICAgICMgQ3JlYXRlIHJlc3VsdCBkYXRhIGZyYW1lIGRpcmVjdGx5IChubyBicm9vbSBkZXBlbmRlbmN5KQogICAgZGF0YS5mcmFtZSgKICAgICAgY2VsbF90eXBlID0gY2VsbF90eXBlLAogICAgICBwX3ZhbHVlID0gdGVzdCRwLnZhbHVlLAogICAgICBzdGF0aXN0aWMgPSB0ZXN0JHN0YXRpc3RpYywKICAgICAgbWV0aG9kID0gdGVzdCRtZXRob2QsCiAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQogICAgKQp9CgogICMgUnVuIGZvbGQtY2hhbmdlIGNvbXB1dGF0aW9uIGFuZCBzdGF0aXN0aWNhbCB0ZXN0IGZvciBhbGwgY2VsbCB0eXBlcwogIGFidW5kYW5jZV9zdW1tYXJ5IDwtIGJpbmRfcm93cyhsYXBwbHkocm93bmFtZXMoY2VsbF9wcm9wcyksIGNvbXB1dGVfZmMpKQogIGVucmljaG1lbnRfcmVzdWx0cyA8LSBiaW5kX3Jvd3MobGFwcGx5KHJvd25hbWVzKGNlbGxfcHJvcHMpLCB0ZXN0X2VucmljaG1lbnQpKQogIAogICMgTWVyZ2UgZm9sZC1jaGFuZ2UgYW5kIHAtdmFsdWUgcmVzdWx0cywgYWRqdXN0IGZvcm1hdAogIGFidW5kYW5jZV9zdW1tYXJ5IDwtIGFidW5kYW5jZV9zdW1tYXJ5ICU+JQogICAgbGVmdF9qb2luKGVucmljaG1lbnRfcmVzdWx0cywgYnkgPSAiY2VsbF90eXBlIikgJT4lCiAgICAjcmVuYW1lKHBfdmFsdWUgPSBwLnZhbHVlKSAlPiUKICAgIGFycmFuZ2UocF92YWx1ZSkKCiAgIyBWaXN1YWxpemUgYWJ1bmRhbmNlIHRyZW5kcyBmb3IgdG9wIDEwIHNpZ25pZmljYW50IGNlbGwgdHlwZXMKICB0b3BfY2VsbHR5cGVzIDwtIGhlYWQoYWJ1bmRhbmNlX3N1bW1hcnkkY2VsbF90eXBlLCAxMCkKCiAgIyBQcmVwYXJlIGRhdGEgZm9yIHBsb3R0aW5nCiAgcGxvdF9kYXRhIDwtIG1lbHQoCiAgICBkYXRhLmZyYW1lKAogICAgICBzYW1wbGUgPSByb3duYW1lcyhjb2xkYXQpLAogICAgICBwc2V1ZG9zaXplX3BjYSA9IGNvbGRhdCRwc2V1ZG9zaXplX3BjYSwKICAgICAgdChjZWxsX3Byb3BzW3RvcF9jZWxsdHlwZXMsIF0pCiAgICApLAogICAgaWQudmFycyA9IGMoInNhbXBsZSIsICJwc2V1ZG9zaXplX3BjYSIpLAogICAgdmFyaWFibGUubmFtZSA9ICJjZWxsX3R5cGUiLAogICAgdmFsdWUubmFtZSA9ICJwcm9wb3J0aW9uIgogICkKICAKICAjIEdlbmVyYXRlIExPRVNTLXNtb290aGVkIHBsb3Qgb2YgYWJ1bmRhbmNlIHZzIHBzZXVkb3RpbWUKICBhYnVuZGFuY2VfcGxvdCA8LSBnZ3Bsb3QocGxvdF9kYXRhLCBhZXMoeCA9IHBzZXVkb3NpemVfcGNhLCB5ID0gcHJvcG9ydGlvbiwgY29sb3IgPSBjZWxsX3R5cGUpKSArCiAgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFKSArCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSB0cmFuc2l0aW9uX3RpbWUsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gdHJhbnNpdGlvbl9jb2xvcikgKwogICAgbGFicygKICAgICAgdGl0bGUgPSBwYXN0ZSh0cmFqJG5hbWUsICI6IiwgYnJhbmNoX25hbWUsICItIiwgdGVzdF90eXBlKSwKICAgICAgeCA9ICJQc2V1ZG90aW1lIiwKICAgICAgeSA9ICJQcm9wb3J0aW9uIiwKICAgICAgY29sb3IgPSAiQ2VsbCBUeXBlIgogICAgKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKAogICAgdGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiSGVsdmV0aWNhIiksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKSwgIAogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG9yID0gImJsYWNrIiwgZmlsbCA9IE5BLCBsaW5ld2lkdGggPSAwLjUpLCAgCiAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3IgPSAiYmxhY2siLCBmaWxsID0gTkEsIGxpbmV3aWR0aCA9IDAuNSkgIAogICkKICAKICBwcmludChhYnVuZGFuY2VfcGxvdCkKCiAgIyBTYXZlIG91dHB1dHMgaWYgcHJlZml4IGdpdmVuCiAgaWYgKCFpcy5udWxsKHNhdmVfcHJlZml4KSkgewogICAgZ2dzYXZlKGZpbGVuYW1lID0gcGFzdGUwKHNhdmVfcHJlZml4LCAiXyIsIHRlc3RfdHlwZSwgIi5qcGciKSwgcGxvdCA9IGFidW5kYW5jZV9wbG90LCB3aWR0aCA9IDgsIGhlaWdodCA9IDUsIGRwaSA9IDMwMCkKICAgIHdyaXRlLmNzdihhYnVuZGFuY2Vfc3VtbWFyeSwgcGFzdGUwKHNhdmVfcHJlZml4LCAiXyIsIHRlc3RfdHlwZSwgIl9zdW1tYXJ5LmNzdiIpLCByb3cubmFtZXMgPSBGQUxTRSkKICB9CgogIHJldHVybihsaXN0KHN1bW1hcnkgPSBhYnVuZGFuY2Vfc3VtbWFyeSwgcGxvdCA9IGFidW5kYW5jZV9wbG90KSkKfQoKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyBGdW5jdGlvbjogcnVuX2FidW5kYW5jZV9hbmFseXNpc19iYXRjaAojIFB1cnBvc2U6IEJhdGNoIHdyYXBwZXIgdG8gYXBwbHkgYWJ1bmRhbmNlIGFuYWx5c2lzIGFjcm9zcyBtdWx0aXBsZSBicmFuY2hlcyBhbmQgdGVzdCB0eXBlcy4KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKCnJ1bl9hYnVuZGFuY2VfYW5hbHlzaXNfYmF0Y2ggPC0gZnVuY3Rpb24oCiAgY2RzLCBjZWxsX3Byb3BzLCBjb2xkYXQsIHRyYWplY3RvcmllcywgdHJhbnNpdGlvbnMsCiAgYW5hbHlzaXNfcGxhbiwKICB0ZXN0X3R5cGVzID0gYygiRW5yaWNobWVudCIsICJEZXBsZXRpb24iLCAiVHdvIFNpZGVkIFRlc3QiKSwKICBzYXZlX2RpciA9IE5VTEwKKSB7CiAgcmVzdWx0cyA8LSBsaXN0KCkKICAKICAjIExvb3Agb3ZlciBhbGwgZW50cmllcyBpbiB0aGUgYW5hbHlzaXMgcGxhbiAoZWFjaCB0cmFqZWN0b3J5IGFuZCBicmFuY2gpCiAgZm9yIChlbnRyeSBpbiBhbmFseXNpc19wbGFuKSB7CiAgICBmb3IgKHRlc3QgaW4gdGVzdF90eXBlcykgewogICAgICBwcmVmaXggPC0gaWYgKCFpcy5udWxsKHNhdmVfZGlyKSkgewogICAgICAgIGZpbGUucGF0aChzYXZlX2RpciwgcGFzdGUwKGVudHJ5JHRyYWplY3Rvcnlfa2V5LCAiXyIsIGVudHJ5JGJyYW5jaF9uYW1lKSkKICAgICAgfSBlbHNlIHsKICAgICAgICBOVUxMCiAgICAgIH0KICAgICAgCiAgICAgICMgUnVuIEFuYWx5c2lzCiAgICAgIHJlcyA8LSBhbmFseXplX2FidW5kYW5jZV9mb3JfYnJhbmNoKAogICAgICAgIGNkcyA9IGNkcywKICAgICAgICBjZWxsX3Byb3BzID0gY2VsbF9wcm9wcywKICAgICAgICBjb2xkYXQgPSBjb2xkYXQsCiAgICAgICAgdHJhamVjdG9yaWVzID0gdHJhamVjdG9yaWVzLAogICAgICAgIHRyYW5zaXRpb25zID0gdHJhbnNpdGlvbnMsCiAgICAgICAgdHJhamVjdG9yeV9rZXkgPSBlbnRyeSR0cmFqZWN0b3J5X2tleSwKICAgICAgICBicmFuY2hfbmFtZSA9IGVudHJ5JGJyYW5jaF9uYW1lLAogICAgICAgIHRlc3RfdHlwZSA9IHRlc3QsCiAgICAgICAgc2F2ZV9wcmVmaXggPSBwcmVmaXgKICAgICAgKQoKICAgICAgcmVzdWx0c1tbcGFzdGUoZW50cnkkdHJhamVjdG9yeV9rZXksIGVudHJ5JGJyYW5jaF9uYW1lLCB0ZXN0LCBzZXAgPSAiXyIpXV0gPC0gcmVzCiAgICB9CiAgfQoKICByZXR1cm4ocmVzdWx0cykKfQoKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyBDb25maWd1cmF0aW9uOiBBbmFseXNpcyBQbGFuCiMgRWFjaCBsaXN0IGl0ZW0gZGVmaW5lcyBhIGJyYW5jaCBwb2ludCBhbmQgY29ycmVzcG9uZGluZyB0cmFqZWN0b3J5IHRvIGFuYWx5emUuCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCgphbmFseXNpc19wbGFuIDwtIGxpc3QoCiAgbGlzdCh0cmFqZWN0b3J5X2tleSA9ICJzZXh1YWwiLCAgYnJhbmNoX25hbWUgPSAiQnJhbmNoXzIiKSwKICBsaXN0KHRyYWplY3Rvcnlfa2V5ID0gImFzZXh1YWwiLCBicmFuY2hfbmFtZSA9ICJCcmFuY2hfMSIpLAogIGxpc3QodHJhamVjdG9yeV9rZXkgPSAiZWFybHlfZGV2IiwgYnJhbmNoX25hbWUgPSAiUHJlYnJhbmNoXzIiKQopCgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMgUnVuIHRoZSBGdWxsIEJhdGNoIEFuYWx5c2lzCiMgUmVzdWx0cyBhcmUgc3RvcmVkIGluIGEgbmFtZWQgbGlzdCBpbmRleGVkIGJ5IHRyYWplY3RvcnkvYnJhbmNoL3Rlc3QKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKcmVzdWx0cyA8LSBydW5fYWJ1bmRhbmNlX2FuYWx5c2lzX2JhdGNoKAogIGNkcyA9IGNkcywKICBjZWxsX3Byb3BzID0gY2VsbF9wcm9wcywKICBjb2xkYXQgPSBjb2xkYXQsCiAgdHJhamVjdG9yaWVzID0gdHJhamVjdG9yaWVzLAogIHRyYW5zaXRpb25zID0gdHJhbnNpdGlvbnMsCiAgYW5hbHlzaXNfcGxhbiA9IGFuYWx5c2lzX3BsYW4sCiAgdGVzdF90eXBlcyA9IGMoIkVucmljaG1lbnQiLCAiRGVwbGV0aW9uIiwgIlR3byBTaWRlZCBUZXN0IiksCiAgc2F2ZV9kaXIgPSAiYWJ1bmRhbmNlX291dHB1dCIgICMgU2V0IHRvIE5VTEwgdG8gZGlzYWJsZSBzYXZpbmcKKQoKIyAjIFByaW50IGFsbCBzdW1tYXJpZXMKIyBmb3IgKG5hbWUgaW4gbmFtZXMocmVzdWx0cykpIHsKIyAgIGNhdCgiXG49PT09IFJlc3VsdCBmb3I6IiwgbmFtZSwgIj09PT1cbiIpCiMgICBwcmludChyZXN1bHRzW1tuYW1lXV0kc3VtbWFyeSkKIyB9CgojIE9wdGlvbmFsbHksIGRpc3BsYXkgYWxsIHBsb3RzIChpbiBSIGNvbnNvbGUgb3Igbm90ZWJvb2spCiMgZm9yIChuYW1lIGluIG5hbWVzKHJlc3VsdHMpKSB7CiMgICAjY2F0KCJcbj09PT0gUGxvdCBmb3I6IiwgbmFtZSwgIj09PT1cbiIpCiMgICBwcmludChyZXN1bHRzW1tuYW1lXV0kYWJ1bmRhbmNlX3Bsb3QpCiMgfQoKCgpgYGAKCgojIyMgNC4gVmFyaWFuY2UgQW5hbHlzaXMKCkR5bmFtaWMgY2hhbmdlcyBpbiBjZWxsdWxhciB2YXJpYWJpbGl0eSBvZnRlbiBwcmVjZWRlIGRldmVsb3BtZW50YWwgYmlmdXJjYXRpb25zLCByZWZsZWN0aW5nIGNyaXRpY2FsIHNsb3dpbmcgZG93buKAlGEgaGFsbG1hcmsgb2Ygc3lzdGVtcyBhcHByb2FjaGluZyBhIHRpcHBpbmcgcG9pbnQuIFZhcmlhbmNlLWJhc2VkIG1ldHJpY3MgdGh1cyBwcm92aWRlIGEgcG93ZXJmdWwgbGVucyB0byBkZXRlY3QgY2VsbCBwb3B1bGF0aW9ucyB1bmRlcmdvaW5nIGZhdGUgZGVjaXNpb25zIG9yIGxpbmVhZ2UgcHJpbWluZy4KCiMjIyMgNC4xLiBSb2xsaW5nIFdpbmRvdyBBcHByb2FjaAoKVG8gcXVhbnRpZnkgZHluYW1pYyB2YXJpYWJpbGl0eSBpbiB0aGUgY2VsbCB0eXBlcywgd2UgaW1wbGVtZW50ZWQgYSByb2xsaW5nIHdpbmRvdyBhbmFseXNpcyBvZiBub3JtYWxpemVkIHZhcmlhbmNlICh2YXJpYW5jZS10by1tZWFuIHJhdGlvKSBjZW50ZXJlZCBhcm91bmQgdGhlIGluZmVycmVkIGJyYW5jaCBwb2ludHMgb2YgdGhlIGFzZXh1YWwgYW5kIHNleHVhbCB0cmFqZWN0b3JpZXMuCgpBIHN5bW1ldHJpYyB0cmFuc2l0aW9uIHdpbmRvdyBzcGFubmluZyDCsTEwJSBvZiB0aGUgbWF4aW11bSBwc2V1ZG90aW1lIHdhcyBkZWZpbmVkLiBUaGlzIGV4cGFuZGVkIHdpbmRvdyBhY2NvdW50ZWQgZm9yIGJpb2xvZ2ljYWwgbm9pc2UgYW5kIHRlbXBvcmFsIGhldGVyb2dlbmVpdHkgYXJvdW5kIGJpZnVyY2F0aW9uIGV2ZW50cywgZW5zdXJpbmcgc3VmZmljaWVudCByZXNvbHV0aW9uIHRvIGRldGVjdCBjaGFuZ2VzIGluIHZhcmlhbmNlLiBGb3IgZWFjaCBjZWxsIHR5cGUsIGdsb2JhbCBub3JtYWxpemVkIHZhcmlhbmNlIHdhcyBjYWxjdWxhdGVkIGFjcm9zcyBhbGwgY2VsbHMgaW4gYSB0cmFqZWN0b3J5LCBhbG9uZ3NpZGUgbG9jYWxpemVkIG5vcm1hbGl6ZWQgdmFyaWFuY2Ugd2l0aGluIGEgZGVmaW5lZCB0cmFuc2l0aW9uIHdpbmRvdyBjZW50ZXJlZCBhdCBlYWNoIGJyYW5jaCBwb2ludC4gVGhlIGZvbGQgY2hhbmdlIGJldHdlZW4gbG9jYWwgYW5kIGdsb2JhbCB2YXJpYW5jZSBxdWFudGlmaWVkIHRoZSBkZWdyZWUgb2YgdmFyaWFiaWxpdHkgZW5yaWNobWVudC4gQ2VsbCB0eXBlcyBleGhpYml0aW5nIGhpZ2ggZm9sZCBjaGFuZ2VzIHdlcmUgaWRlbnRpZmllZCBhcyBjYW5kaWRhdGUgY29udHJpYnV0b3JzIHRvIGZhdGUgYmlmdXJjYXRpb24uCgpUbyBhc3Nlc3MgdGhlIHN0YXRpc3RpY2FsIHNpZ25pZmljYW5jZSBvZiB0aGlzIGVucmljaG1lbnQsIExldmVuZeKAmXMgdGVzdCBmb3IgZXF1YWxpdHkgb2YgdmFyaWFuY2VzIHdhcyBwZXJmb3JtZWQsIGNvbXBhcmluZyBhYnVuZGFuY2UgdmFyaWFuY2UgaW5zaWRlIHZlcnN1cyBvdXRzaWRlIHRoZSB0cmFuc2l0aW9uIHdpbmRvdy4gUmVzdWx0aW5nIHAtdmFsdWVzIHdlcmUgYWRqdXN0ZWQgZm9yIG11bHRpcGxlIHRlc3RpbmcgdXNpbmcgdGhlIEJlbmphbWluaS1Ib2NoYmVyZyBwcm9jZWR1cmUsIGFuZCBjZWxsIHR5cGVzIHdlcmUgcmFua2VkIGJhc2VkIG9uIGJvdGggZm9sZC1jaGFuZ2UgbWFnbml0dWRlIGFuZCBzdGF0aXN0aWNhbCBzaWduaWZpY2FuY2UuCgpUZW1wb3JhbCB0cmVuZHMgaW4gY2VsbC10eXBlIHZhcmlhYmlsaXR5IHdlcmUgdmlzdWFsaXplZCBieSBjb21wdXRpbmcgcm9sbGluZyBub3JtYWxpemVkIHZhcmlhbmNlIGN1cnZlcyBhY3Jvc3MgcHNldWRvdGltZSwgdXNpbmcgYSBzbGlkaW5nIHdpbmRvdyBlbmNvbXBhc3NpbmcgMjAlIG9mIHRoZSBvcmRlcmVkIGNlbGwgcG9wdWxhdGlvbi4gVGhpcyBzbW9vdGhlZCBtZWFzdXJlIHdhcyBwbG90dGVkIGZvciB0aGUgdG9wIGZpdmUgdmFyaWFuY2UtZW5yaWNoZWQgY2VsbCB0eXBlcyBwZXIgdHJhamVjdG9yeSwgd2l0aCBkYXNoZWQgdmVydGljYWwgbGluZXMgaW5kaWNhdGluZyB0aGUgY29ycmVzcG9uZGluZyBicmFuY2ggcG9pbnRzLgoKVGhlc2UgY3VydmVzIGhpZ2hsaWdodCBsb2NhbGl6ZWQgYnVyc3RzIGluIHZhcmlhYmlsaXR5IGF0IGJpZnVyY2F0aW9uIHpvbmVzLCBpbmRpY2F0aW5nIGVsZXZhdGVkIGhldGVyb2dlbmVpdHkgaW4gc3BlY2lmaWMgY2VsbCB0eXBlcywgcG90ZW50aWFsbHkgcmVmbGVjdGl2ZSBvZiBsaW5lYWdlIHByaW1pbmcsIGZhdGUgY29uZmxpY3QsIG9yIHRyYW5zaXRpb25hbCBwbGFzdGljaXR5LiBXaGlsZSB0aGVzZSB2aXN1YWxpemF0aW9ucyB2YWxpZGF0ZWQgdGhlIGxvY2FsaXphdGlvbiBvZiBkeW5hbWljIHZhcmlhYmlsaXR5IHRvIGJyYW5jaCBwb2ludHMsIHRoZSBwbG90cyBhbG9uZSBkaWQgbm90IHByb3ZpZGUgYWNjdXJhdGUgaW5zaWdodHMgYW5kIHJlcXVpcmVkIGNvbXBsZW1lbnRhcnkgc3RhdGlzdGljYWwgYW5hbHlzaXMgZm9yIGludGVycHJldGF0aW9uLgoKCmBgYHtyIHJvbGxpbmcgd2luZG93IGFwcHJvYWNoIG9mIG5vcm1hbGl6ZWQgdmFyaWFuY2UgYW5hbHlzaXN9CiMgVXNlIHRoZSBjb3JyZWN0IGJyYW5jaCB0cmFuc2l0aW9uIHRpbWVzIGZyb20gdGhlIGJyYW5jaCBwb2ludCBpZGVudGlmaWNhdGlvbiBzdGVwCmJyYW5jaDFfdGltZSA8LSB0cmFuc2l0aW9ucyRCcmFuY2hfMQpicmFuY2gyX3RpbWUgPC0gdHJhbnNpdGlvbnMkQnJhbmNoXzIKCiMgRGVmaW5lIGEgbGFyZ2VyIHRyYW5zaXRpb24gd2luZG93IChlLmcuLCDCsTEwJSBvZiB0aGUgcHNldWRvdGltZSByYW5nZSkKdHJhbnNpdGlvbl93aW5kb3cgPC0gMC4xMCAqIG1heChjb2xkYXQkcHNldWRvc2l6ZV9wY2EpICAjIEluY3JlYXNlIHdpbmRvdyBzaXplIHRvIDEwJQoKIyAtLS0gU3RlcCAxOiBDb21wdXRlIE5vcm1hbGl6ZWQgVmFyaWFuY2UgKFZhci9NZWFuKSBmb3IgQnJhbmNoIFBvaW50cyAtLS0KY29tcHV0ZV9ub3JtX3ZhcmlhbmNlIDwtIGZ1bmN0aW9uKGNlbGxfdHlwZSwgYnJhbmNoX3RpbWUpIHsKICAjIEdsb2JhbCBzdGF0cwogIGdsb2JhbF92YXIgPC0gdmFyKGNlbGxfcHJvcHNbY2VsbF90eXBlLCBdKQogIGdsb2JhbF9tZWFuIDwtIG1lYW4oY2VsbF9wcm9wc1tjZWxsX3R5cGUsIF0pCiAgZ2xvYmFsX25vcm1fdmFyIDwtIGdsb2JhbF92YXIgLyBnbG9iYWxfbWVhbgogIAogICMgQnJhbmNoIHRpbWUgd2luZG93IHN0YXRzCiAgYnJhbmNoX21hc2sgPC0gY29sZGF0JHBzZXVkb3NpemVfcGNhID49IChicmFuY2hfdGltZSAtIHRyYW5zaXRpb25fd2luZG93KSAmIAogICAgICAgICAgICAgICAgIGNvbGRhdCRwc2V1ZG9zaXplX3BjYSA8PSAoYnJhbmNoX3RpbWUgKyB0cmFuc2l0aW9uX3dpbmRvdykKICBicmFuY2hfdmFyIDwtIHZhcihjZWxsX3Byb3BzW2NlbGxfdHlwZSwgYnJhbmNoX21hc2tdKQogIGJyYW5jaF9tZWFuIDwtIG1lYW4oY2VsbF9wcm9wc1tjZWxsX3R5cGUsIGJyYW5jaF9tYXNrXSkKICBicmFuY2hfbm9ybV92YXIgPC0gYnJhbmNoX3ZhciAvIGJyYW5jaF9tZWFuCiAgCiAgZGF0YS5mcmFtZSgKICAgIGNlbGxfdHlwZSA9IGNlbGxfdHlwZSwKICAgIGdsb2JhbF9ub3JtX3ZhciA9IGdsb2JhbF9ub3JtX3ZhciwKICAgIGJyYW5jaF9ub3JtX3ZhciA9IGJyYW5jaF9ub3JtX3ZhciwKICAgIGZjX2JyYW5jaCA9IGJyYW5jaF9ub3JtX3ZhciAvIGdsb2JhbF9ub3JtX3ZhciAgIyBGb2xkLWNoYW5nZSBpbiBub3JtYWxpemVkIHZhcmlhbmNlCiAgKQp9CgojIEFwcGx5IHRvIGJvdGggdHJhamVjdG9yaWVzCnZhcmlhbmNlX3N1bW1hcnlfdHJhamVjdG9yeTEgPC0gYmluZF9yb3dzKGxhcHBseShyb3duYW1lcyhjZWxsX3Byb3BzKSwgZnVuY3Rpb24oY3QpIHsKICBjb21wdXRlX25vcm1fdmFyaWFuY2UoY3QsIGJyYW5jaDFfdGltZSkKfSkpICU+JQogIGFycmFuZ2UoZGVzYyhmY19icmFuY2gpKQoKdmFyaWFuY2Vfc3VtbWFyeV90cmFqZWN0b3J5MiA8LSBiaW5kX3Jvd3MobGFwcGx5KHJvd25hbWVzKGNlbGxfcHJvcHMpLCBmdW5jdGlvbihjdCkgewogIGNvbXB1dGVfbm9ybV92YXJpYW5jZShjdCwgYnJhbmNoMl90aW1lKQp9KSkgJT4lCiAgYXJyYW5nZShkZXNjKGZjX2JyYW5jaCkpCgojIC0tLSBTdGVwIDI6IFN0YXRpc3RpY2FsIFRlc3RpbmcgZm9yIFZhcmlhbmNlIGF0IEJyYW5jaCBQb2ludHMgLS0tCiMgVGVzdGluZyB2YXJpYW5jZSBjaGFuZ2VzIGF0IEJyYW5jaCAxCnRlc3RfdmFyaWFuY2VfZW5yaWNobWVudF9icmFuY2gxIDwtIGZ1bmN0aW9uKGNlbGxfdHlwZSkgewogIGJyYW5jaF9tYXNrIDwtIGNvbGRhdCRwc2V1ZG9zaXplX3BjYSA+PSAoYnJhbmNoMV90aW1lIC0gdHJhbnNpdGlvbl93aW5kb3cpICYgCiAgICAgICAgICAgICAgICAgY29sZGF0JHBzZXVkb3NpemVfcGNhIDw9IChicmFuY2gxX3RpbWUgKyB0cmFuc2l0aW9uX3dpbmRvdykKICAKICBwX3ZhbCA8LSBjYXI6OmxldmVuZVRlc3QoCiAgICB5ID0gY2VsbF9wcm9wc1tjZWxsX3R5cGUsIF0sCiAgICBncm91cCA9IGZhY3RvcihicmFuY2hfbWFzaywgbGV2ZWxzID0gYyhGQUxTRSwgVFJVRSkpCiAgKSRgUHIoPkYpYFsxXQogIAogIGRhdGEuZnJhbWUoY2VsbF90eXBlID0gY2VsbF90eXBlLCBwX3ZhbHVlID0gcF92YWwpCn0KCiMgVGVzdGluZyB2YXJpYW5jZSBjaGFuZ2VzIGF0IEJyYW5jaCAyCnRlc3RfdmFyaWFuY2VfZW5yaWNobWVudF9icmFuY2gyIDwtIGZ1bmN0aW9uKGNlbGxfdHlwZSkgewogIGJyYW5jaF9tYXNrIDwtIGNvbGRhdCRwc2V1ZG9zaXplX3BjYSA+PSAoYnJhbmNoMl90aW1lIC0gdHJhbnNpdGlvbl93aW5kb3cpICYgCiAgICAgICAgICAgICAgICAgY29sZGF0JHBzZXVkb3NpemVfcGNhIDw9IChicmFuY2gyX3RpbWUgKyB0cmFuc2l0aW9uX3dpbmRvdykKICAKICBwX3ZhbCA8LSBjYXI6OmxldmVuZVRlc3QoCiAgICB5ID0gY2VsbF9wcm9wc1tjZWxsX3R5cGUsIF0sCiAgICBncm91cCA9IGZhY3RvcihicmFuY2hfbWFzaywgbGV2ZWxzID0gYyhGQUxTRSwgVFJVRSkpCiAgKSRgUHIoPkYpYFsxXQogIAogIGRhdGEuZnJhbWUoY2VsbF90eXBlID0gY2VsbF90eXBlLCBwX3ZhbHVlID0gcF92YWwpCn0KCiMgQXBwbHkgdGVzdHMgZm9yIGJvdGggYnJhbmNoZXMKdmFyaWFuY2VfZW5yaWNobWVudF9icmFuY2gxIDwtIGJpbmRfcm93cyhsYXBwbHkocm93bmFtZXMoY2VsbF9wcm9wcyksIHRlc3RfdmFyaWFuY2VfZW5yaWNobWVudF9icmFuY2gxKSkKdmFyaWFuY2VfZW5yaWNobWVudF9icmFuY2gyIDwtIGJpbmRfcm93cyhsYXBwbHkocm93bmFtZXMoY2VsbF9wcm9wcyksIHRlc3RfdmFyaWFuY2VfZW5yaWNobWVudF9icmFuY2gyKSkKCiMgTWVyZ2Ugc3RhdGlzdGljYWwgcmVzdWx0cyB3aXRoIHZhcmlhbmNlIHN1bW1hcnkKdmFyaWFuY2Vfc3VtbWFyeV90cmFqZWN0b3J5MSA8LSB2YXJpYW5jZV9zdW1tYXJ5X3RyYWplY3RvcnkxICU+JQogIGxlZnRfam9pbih2YXJpYW5jZV9lbnJpY2htZW50X2JyYW5jaDEsIGJ5ID0gImNlbGxfdHlwZSIpICU+JQogIG11dGF0ZShwX2FkaiA9IHAuYWRqdXN0KHBfdmFsdWUsIG1ldGhvZCA9ICJCSCIpKSAlPiUKICBhcnJhbmdlKHBfdmFsdWUpCgp2YXJpYW5jZV9zdW1tYXJ5X3RyYWplY3RvcnkyIDwtIHZhcmlhbmNlX3N1bW1hcnlfdHJhamVjdG9yeTIgJT4lCiAgbGVmdF9qb2luKHZhcmlhbmNlX2VucmljaG1lbnRfYnJhbmNoMiwgYnkgPSAiY2VsbF90eXBlIikgJT4lCiAgbXV0YXRlKHBfYWRqID0gcC5hZGp1c3QocF92YWx1ZSwgbWV0aG9kID0gIkJIIikpICU+JQogIGFycmFuZ2UocF92YWx1ZSkKCiMgUGxvdCBOb3JtYWxpemVkIFZhcmlhbmNlIFRyZW5kcyBmb3IgQm90aCBUcmFqZWN0b3JpZXMKCiMgVG9wIDUgY2VsbCB0eXBlcyBmb3IgYm90aCBicmFuY2hlcwp0b3BfY2VsbHR5cGVzX3RyYWplY3RvcnkxIDwtIGhlYWQodmFyaWFuY2Vfc3VtbWFyeV90cmFqZWN0b3J5MSRjZWxsX3R5cGUsIDUpCnRvcF9jZWxsdHlwZXNfdHJhamVjdG9yeTIgPC0gaGVhZCh2YXJpYW5jZV9zdW1tYXJ5X3RyYWplY3RvcnkyJGNlbGxfdHlwZSwgNSkKCiMgQ29tcHV0ZSByb2xsaW5nIG5vcm1hbGl6ZWQgdmFyaWFuY2UgZm9yIHNtb290aCB0cmVuZHMKcGxvdF9kYXRhX3RyYWplY3RvcnkxIDwtIGxhcHBseSh0b3BfY2VsbHR5cGVzX3RyYWplY3RvcnkxLCBmdW5jdGlvbihjdCkgewogIGlkeCA8LSBvcmRlcihjb2xkYXQkcHNldWRvc2l6ZV9wY2EpCiAgcHJvcHMgPC0gY2VsbF9wcm9wc1tjdCwgaWR4XQogIHBzZXVkb3RpbWUgPC0gY29sZGF0JHBzZXVkb3NpemVfcGNhW2lkeF0KICAKICByb2xsX3dpbmRvdyA8LSBtYXgoMTAsIHJvdW5kKDAuMiAqIGxlbmd0aChwcm9wcykpKQogIHJvbGxfdmFyIDwtIHpvbzo6cm9sbGFwcGx5KHByb3BzLCB3aWR0aCA9IHJvbGxfd2luZG93LCBGVU4gPSB2YXIsIGZpbGwgPSBOQSwgYWxpZ24gPSAiY2VudGVyIikKICByb2xsX21lYW4gPC0gem9vOjpyb2xsYXBwbHkocHJvcHMsIHdpZHRoID0gcm9sbF93aW5kb3csIEZVTiA9IG1lYW4sIGZpbGwgPSBOQSwgYWxpZ24gPSAiY2VudGVyIikKICAKICBkYXRhLmZyYW1lKAogICAgY2VsbF90eXBlID0gY3QsCiAgICBwc2V1ZG90aW1lID0gcHNldWRvdGltZSwKICAgIG5vcm1fdmFyaWFuY2UgPSByb2xsX3ZhciAvIHJvbGxfbWVhbgogICkKfSkgJT4lIGJpbmRfcm93cygpCgpwbG90X2RhdGFfdHJhamVjdG9yeTIgPC0gbGFwcGx5KHRvcF9jZWxsdHlwZXNfdHJhamVjdG9yeTIsIGZ1bmN0aW9uKGN0KSB7CiAgaWR4IDwtIG9yZGVyKGNvbGRhdCRwc2V1ZG9zaXplX3BjYSkKICBwcm9wcyA8LSBjZWxsX3Byb3BzW2N0LCBpZHhdCiAgcHNldWRvdGltZSA8LSBjb2xkYXQkcHNldWRvc2l6ZV9wY2FbaWR4XQogIAogIHJvbGxfd2luZG93IDwtIG1heCgxMCwgcm91bmQoMC4yICogbGVuZ3RoKHByb3BzKSkpCiAgcm9sbF92YXIgPC0gem9vOjpyb2xsYXBwbHkocHJvcHMsIHdpZHRoID0gcm9sbF93aW5kb3csIEZVTiA9IHZhciwgZmlsbCA9IE5BLCBhbGlnbiA9ICJjZW50ZXIiKQogIHJvbGxfbWVhbiA8LSB6b286OnJvbGxhcHBseShwcm9wcywgd2lkdGggPSByb2xsX3dpbmRvdywgRlVOID0gbWVhbiwgZmlsbCA9IE5BLCBhbGlnbiA9ICJjZW50ZXIiKQogIAogIGRhdGEuZnJhbWUoCiAgICBjZWxsX3R5cGUgPSBjdCwKICAgIHBzZXVkb3RpbWUgPSBwc2V1ZG90aW1lLAogICAgbm9ybV92YXJpYW5jZSA9IHJvbGxfdmFyIC8gcm9sbF9tZWFuCiAgKQp9KSAlPiUgYmluZF9yb3dzKCkKCiMgUGxvdCBmb3IgdHJhamVjdG9yeSAxIChCcmFuY2ggMSkKcm9sbGluZ192YXJpYW5jZV9icmFuY2gxIDwtIAogIGdncGxvdChwbG90X2RhdGFfdHJhamVjdG9yeTEsIGFlcyh4ID0gcHNldWRvdGltZSwgeSA9IG5vcm1fdmFyaWFuY2UsIGNvbG9yID0gY2VsbF90eXBlKSkgKwogIGdlb21fbGluZShsaW5ld2lkdGggPSAxKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYnJhbmNoMV90aW1lLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJibHVlIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJOb3JtYWxpemVkIFZhcmlhbmNlIGFyb3VuZCBCcmFuY2ggUG9pbnQgMSBpbiBhc2V4dWFsIHRyYWplY3RvcnkiLAogICAgeCA9ICJQc2V1ZG90aW1lIiwKICAgIHkgPSAiTm9ybWFsaXplZCBWYXJpYW5jZSIsCiAgICBjb2xvciA9ICJDZWxsIFR5cGUiCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSgKICAgIHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIkhlbHZldGljYSIpLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiksICAKICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvciA9ICJibGFjayIsIGZpbGwgPSBOQSwgbGluZXdpZHRoID0gMC41KSwgIAogICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG9yID0gImJsYWNrIiwgZmlsbCA9IE5BLCBsaW5ld2lkdGggPSAwLjUpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIKICApCgojIFBsb3QgZm9yIHRyYWplY3RvcnkgMiAoQnJhbmNoIDIpCnJvbGxpbmdfdmFyaWFuY2VfYnJhbmNoMiA8LQogIGdncGxvdChwbG90X2RhdGFfdHJhamVjdG9yeTIsIGFlcyh4ID0gcHNldWRvdGltZSwgeSA9IG5vcm1fdmFyaWFuY2UsIGNvbG9yID0gY2VsbF90eXBlKSkgKwogIGdlb21fbGluZShsaW5ld2lkdGggPSAxKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYnJhbmNoMl90aW1lLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJyZWQiKSArCiAgbGFicygKICAgIHRpdGxlID0gIk5vcm1hbGl6ZWQgVmFyaWFuY2UgYXJvdW5kIEJyYW5jaCBQb2ludCAyIGluIHNleHVhbCB0cmFqZWN0b3J5IiwKICAgIHggPSAiUHNldWRvdGltZSIsCiAgICB5ID0gIk5vcm1hbGl6ZWQgVmFyaWFuY2UiLAogICAgY29sb3IgPSAiQ2VsbCBUeXBlIgogICkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJIZWx2ZXRpY2EiKSwKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpLCAgCiAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3IgPSAiYmxhY2siLCBmaWxsID0gTkEsIGxpbmV3aWR0aCA9IDAuNSksICAKICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvciA9ICJibGFjayIsIGZpbGwgPSBOQSwgbGluZXdpZHRoID0gMC41KSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iCiAgKQoKcm9sbGluZ192YXJpYW5jZV9icmFuY2gxCnJvbGxpbmdfdmFyaWFuY2VfYnJhbmNoMgoKaWYgKCFkaXIuZXhpc3RzKCJ2YXJpYW5jZV9vdXRwdXQiKSkgZGlyLmNyZWF0ZSgidmFyaWFuY2Vfb3V0cHV0IikKCmdnc2F2ZSgidmFyaWFuY2Vfb3V0cHV0L3JvbGxpbmdfdmFyaWFuY2VfYnJhbmNoMS5wbmciLCBwbG90ID0gcm9sbGluZ192YXJpYW5jZV9icmFuY2gxLCB3aWR0aCA9IDgsIGhlaWdodCA9IDYsIGRwaSA9IDMwMCkKZ2dzYXZlKCJ2YXJpYW5jZV9vdXRwdXQvcm9sbGluZ192YXJpYW5jZV9icmFuY2gyLnBuZyIsIHBsb3QgPSByb2xsaW5nX3ZhcmlhbmNlX2JyYW5jaDIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNiwgZHBpID0gMzAwKQpgYGAKIyMjIyA0LjIuIE5lZ2F0aXZlIEJpbm9taWFsIEZpdAoKVG8gbW9kZWwgdGhlIGFidW5kYW5jZSBhIGNlbGwgdHlwZSBvdmVyIHBzZXVkb3RpbWUgd2l0aGluIGEgdHJhamVjdG9yeSwgYSAqKm5lZ2F0aXZlIGJpbm9taWFsIHJlZ3Jlc3Npb24qKiB3YXMgYXBwbGllZC4gVGhpcyBhcHByb2FjaCBpcyBhcHByb3ByaWF0ZSBkdWUgdG8gdGhlIG92ZXJkaXNwZXJzaW9uIGNvbW1vbmx5IG9ic2VydmVkIGluIHNpbmdsZS1jZWxsIGNvdW50IGRhdGEsIHdoZXJlIHRoZSB2YXJpYW5jZSBleGNlZWRzIHRoZSBtZWFuLCB2aW9sYXRpbmcgdGhlIGFzc3VtcHRpb25zIG9mIGEgUG9pc3NvbiBkaXN0cmlidXRpb24uCgpUaGUgbmVnYXRpdmUgYmlub21pYWwgbW9kZWwgaXMgZGVmaW5lZCBhczoKCiQkCllfaSBcc2ltIFx0ZXh0e05CfShcbXVfaSwgXHRoZXRhKQokJAoKd2hlcmU6ICAKLSBcKCBZX2kgXCkgaXMgdGhlIG9ic2VydmVkIGNvdW50IGZvciBlbWJyeW8gXCggaSBcKSwgIAotIFwoIFxtdV9pIFwpIGlzIHRoZSBleHBlY3RlZCB2YWx1ZSwgIAotIFwoIFx0aGV0YSBcKSBpcyB0aGUgZGlzcGVyc2lvbiBwYXJhbWV0ZXIgKGhpZ2hlciBcKCBcdGhldGEgXCkgaW1wbGllcyBsb3dlciBvdmVyZGlzcGVyc2lvbikuCgpBIHNwbGluZS1iYXNlZCBtb2RlbCB3YXMgZml0dGVkIHRvIGNhcHR1cmUgbm9ubGluZWFyIHRyZW5kcyBvdmVyIHBzZXVkb3RpbWU6CgokJApcbG9nKFxtdV9pKSA9IFxiZXRhXzAgKyBmKFx0ZXh0e3BzZXVkb3NpemV9X2kpCiQkCgp3aGVyZSBcKCBmKFxjZG90KSBcKSBpcyBhIG5hdHVyYWwgc3BsaW5lIGJhc2lzIGZ1bmN0aW9uIHdpdGggMyBkZWdyZWVzIG9mIGZyZWVkb20uIFRoZSBtb2RlbCB3YXMgY29tcGFyZWQgdG8gYSBudWxsIG1vZGVsIHdpdGggbm8gcHNldWRvdGltZSBkZXBlbmRlbmNlIHVzaW5nIGEgKipsaWtlbGlob29kIHJhdGlvIHRlc3QqKiwgYW5kIGEgcHNldWRvLVwoIFJeMiBcKSB3YXMgY29tcHV0ZWQgdG8gcXVhbnRpZnkgbW9kZWwgZml0OgoKJCQKXHRleHR7UHNldWRvLX1SXjIgPSAxIC0gXGZyYWN7XGxvZyBcbWF0aGNhbHtMfV97XHRleHR7bW9kZWx9fX17XGxvZyBcbWF0aGNhbHtMfV97XHRleHR7bnVsbH19fQokJAoKd2hlcmUgXCggXG1hdGhjYWx7TH0gXCkgZGVub3RlcyB0aGUgbGlrZWxpaG9vZCBvZiB0aGUgcmVzcGVjdGl2ZSBtb2RlbHMuCgpNb2RlbCBwcmVkaWN0aW9ucyB3ZXJlIHZpc3VhbGl6ZWQgb3ZlciBhIGRlbnNlIGdyaWQgb2YgcHNldWRvdGltZSB2YWx1ZXMuIEV4cGVjdGVkIGNvdW50cyBhbmQgdmFyaWFuY2VzIHdlcmUgZXh0cmFjdGVkIHVzaW5nOgoKJCQKXHRleHR7VmFyfShZX2kpID0gXG11X2kgXGxlZnQoMSArIFxmcmFje1xtdV9pfXtcdGhldGF9IFxyaWdodCkKJCQKQ29uZmlkZW5jZSBpbnRlcnZhbHMgd2VyZSBzaW11bGF0ZWQgYnkgZHJhd2luZyAxMDAsMDAwIHNhbXBsZXMgZnJvbSB0aGUgZml0dGVkIG1vZGVsIHRvIGVzdGltYXRlIHRoZSBleHBlY3RlZCBtZWFuIGFuZCA5NSUgYm91bmRzIHBlciBlbWJyeW8uIFRoZSBmaW5hbCB2aXN1YWxpemF0aW9uIHNob3dzIHRoZSBvYnNlcnZlZCBjb3VudHMsIHByZWRpY3RlZCBtZWFucywgYW5kIHNpbXVsYXRlZCBjb25maWRlbmNlIGJhbmRzLCBlZmZlY3RpdmVseSBjYXB0dXJpbmcgdW5jZXJ0YWludHkgYW5kIG92ZXJkaXNwZXJzaW9uIGluIHRoZSBtb2RlbCBmaXQuCgpUaGUgbW9kZWwgc3VjY2Vzc2Z1bGx5IGNhcHR1cmVkIHRoZSB2YXJpYW5jZSBhY3Jvc3MgcHNldWRvdGltZSBpbiB0aGUgKnNleHVhbCogdHJhamVjdG9yeSwgc3VwcG9ydGluZyBpdHMgcmVsZXZhbmNlIGZvciBtb2RlbGluZyBjZWxsIHR5cGUtc3BlY2lmaWMgZHluYW1pY3MuCgoqKkhlcmUsIHRoZSBjZWxsIHR5cGUgdGVzdGVzIGlzIHNob3duIGFzIGFuIGlsbHVzdHJhdGl2ZSBleGFtcGxlIGR1ZSB0byBpdHMgY2xlYXIgcHNldWRvdGltZS1kZXBlbmRlbnQgYmVoYXZpb3IgYW5kIGJpb2xvZ2ljYWwgcmVsZXZhbmNlIHRvIHRoZSBzZXh1YWwgZGV2ZWxvcG1lbnRhbCBmYXRlLiBJdHMgYWJ1bmRhbmNlIHByb2ZpbGUgcHJvdmlkZXMgYSByZXByZXNlbnRhdGl2ZSBjYXNlIG9mIHRoZSBtb2RlbCdzIGFiaWxpdHkgdG8gZGV0ZWN0IHN0cnVjdHVyZWQgdmFyaWF0aW9uLiBUaGUgZnVsbCBjb2RlIGFuZCByZXN1bHRzIGZvciBhbGwgY2VsbCB0eXBlcyBhcmUgaW5jbHVkZWQgaW4gdGhlIGFjY29tcGFueWluZyBgLlJtZGAgZmlsZS4qKgoKCmBgYHtyIG5lZ2F0aXZlIGJpbmltaWFsIHRyaWFsfQpsaWJyYXJ5KFZHQU0pCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKCiMgU2V0IGNlbGwgdHlwZSBhbmQgdHJhamVjdG9yeQpjdXJyZW50X2NlbGxfdHlwZSA8LSAiVGVzdGVzIgp0cmFqZWN0b3J5X25hbWUgPC0gInNleHVhbCIKCiMgR2V0IHNhbXBsZXMgaW4gdGhlIGFzZXh1YWwgdHJhamVjdG9yeQp0cmFqZWN0b3J5X3NhbXBsZXMgPC0gdHJhamVjdG9yaWVzW1t0cmFqZWN0b3J5X25hbWVdXSRzYW1wbGVzCgojIEZpbHRlciBjb2xEYXRhIGZvciB0cmFqZWN0b3J5IHNhbXBsZXMKY2VsbF9jb3VudF9kZiA8LSBjb2xEYXRhKGNkcykgJT4lCiAgYXMuZGF0YS5mcmFtZSgpICU+JQogIGZpbHRlcihyb3duYW1lcyguKSAlaW4lIHRyYWplY3Rvcnlfc2FtcGxlcykgJT4lCiAgbXV0YXRlKAogICAgY2VsbHMgPSBjb3VudHMoY2RzKVtjdXJyZW50X2NlbGxfdHlwZSwgcm93bmFtZXMoLildLAogICAgY2VsbF90eXBlID0gY3VycmVudF9jZWxsX3R5cGUsCiAgICB0b3RhbF9jZWxscyA9IGNvbFN1bXMoY291bnRzKGNkcykpW3Jvd25hbWVzKC4pXSwKICAgIGVtYnJ5byA9IHNhbXBsZSwKICAgIHBzZXVkb3NpemVfcGNhID0gcHNldWRvc2l6ZV9wY2EsCiAgICBnZW5vdHlwZSA9ICdwbW9yJwogICkKCiMgRml0IG5lZ2F0aXZlIGJpbm9taWFsIG1vZGVsCmZpdCA8LSBWR0FNOjp2Z2xtKGNlbGxzIH4gc20ubnMocHNldWRvc2l6ZV9wY2EsIGRmID0gMyksCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBjZWxsX2NvdW50X2RmLAogICAgICAgICAgICAgICAgICBmYW1pbHkgPSBuZWdiaW5vbWlhbCh6ZXJvID0gTlVMTCksCiAgICAgICAgICAgICAgICAgIHRyYWNlID0gRkFMU0UpCgojIE51bGwgbW9kZWwKZml0Lm51bGwgPC0gVkdBTTo6dmdsbShjZWxscyB+IDEsCiAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGNlbGxfY291bnRfZGYsCiAgICAgICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gbmVnYmlub21pYWwoemVybyA9IE5VTEwpLAogICAgICAgICAgICAgICAgICAgICAgIHRyYWNlID0gRkFMU0UpCgojIExpa2VsaWhvb2QgcmF0aW8gdGVzdCBhbmQgcHNldWRvIFJeMgpsci5vYmogPC0gbHJ0ZXN0KGZpdCwgZml0Lm51bGwpCnRlc3Quc3RhdCA8LSBsci5vYmpAQm9keSRDaGlzcVsyXQpwLnZhbHVlIDwtIGxyLm9iakBCb2R5JGBQcig+Q2hpc3EpYFsyXQpwc2V1ZG9fUjIgPC0gMSAtIChsb2dMaWsoZml0KSAvIGxvZ0xpayhmaXQubnVsbCkpCgojIEdlbmVyYXRlIHNtb290aCBwcmVkaWN0aW9uIG92ZXIgcHNldWRvdGltZQpmYWtlX2RmIDwtIGRhdGEuZnJhbWUocHNldWRvc2l6ZV9wY2EgPSBzZXEobWluKGNlbGxfY291bnRfZGYkcHNldWRvc2l6ZV9wY2EsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXgoY2VsbF9jb3VudF9kZiRwc2V1ZG9zaXplX3BjYSwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aC5vdXQgPSA5NCkpICU+JQogIG11dGF0ZShlbWJyeW8gPSBwYXN0ZSgnZHVtbXknLCByb3dfbnVtYmVyKCksIHNlcCA9ICctJykpICU+JQogIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAiZW1icnlvIikKCiMgUHJlZGljdCBmcm9tIHRoZSBtb2RlbApwcmVkX2RmIDwtIGFzLmRhdGEuZnJhbWUocHJlZGljdChmaXQsIGZha2VfZGYpKQpwcmVkX2RmJHByZWRfbXUgPC0gZXhwKHByZWRfZGZbLDFdKQpwcmVkX2RmJHByZWRfc2l6ZSA8LSBleHAocHJlZF9kZlssMl0pCnByZWRfZGYkcHJlZF9jZWxscyA8LSBwcmVkX2RmJHByZWRfbXUKcHJlZF9kZiRwcmVkX3ZhciA8LSBwcmVkX2RmJHByZWRfbXUgKiAoMSArIHByZWRfZGYkcHJlZF9tdSAvIHByZWRfZGYkcHJlZF9zaXplKQoKZmFrZV9kZiRjZWxscyA8LSBwcmVkX2RmJHByZWRfY2VsbHMKZmFrZV9kZiRwcmVkX3ZhciA8LSBwcmVkX2RmJHByZWRfdmFyCmZha2VfZGYkY2lfdXBwZXIgPC0gcHJlZF9kZiRwcmVkX2NlbGxzICsgMiAqIHNxcnQoZmFrZV9kZiRwcmVkX3ZhcikKZmFrZV9kZiRjaV9sb3dlciA8LSBwcmVkX2RmJHByZWRfY2VsbHMgLSAyICogc3FydChmYWtlX2RmJHByZWRfdmFyKQoKIyBTaW11bGF0aW9uCnNpbV9yZXMgPC0gYXMubWF0cml4KHNpbXVsYXRlKGZpdCwgbnNpbSA9IDEwMDAwMCkpCmNlbGxfY291bnRfZGYkY2VsbHNfcGVyX2VtYnJ5byA8LSBhcHBseShzaW1fcmVzLCAxLCBtZWFuKQpjZWxsX2NvdW50X2RmJGNlbGxzX3Blcl9lbWJyeW8uc3RkZGV2IDwtIGFwcGx5KHNpbV9yZXMsIDEsIHNkKQpjZWxsX2NvdW50X2RmJGNpX2xvd2VyX3NpbSA8LSBhcHBseShzaW1fcmVzLCAxLCBxdWFudGlsZSwgcHJvYnMgPSAwLjAyNSkKY2VsbF9jb3VudF9kZiRjaV91cHBlcl9zaW0gPC0gYXBwbHkoc2ltX3JlcywgMSwgcXVhbnRpbGUsIHByb2JzID0gMC45NzUpCgojIFBsb3QKbmVnYXRpdmVfYmlub21pYWwgPC0gZ2dwbG90KCkgKwogIGdlb21fcmliYm9uKGRhdGEgPSBjZWxsX2NvdW50X2RmLAogICAgICAgICAgICAgIGFlcyh4ID0gcHNldWRvc2l6ZV9wY2EsCiAgICAgICAgICAgICAgICAgIHltaW4gPSBjaV9sb3dlcl9zaW0sCiAgICAgICAgICAgICAgICAgIHltYXggPSBjaV91cHBlcl9zaW0pLAogICAgICAgICAgICAgIGFscGhhID0gMC40LCBmaWxsID0gJyMyMDczOTQnKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBjZWxsX2NvdW50X2RmLAogICAgICAgICAgICBhZXMoeCA9IHBzZXVkb3NpemVfcGNhLCB5ID0gY2VsbHNfcGVyX2VtYnJ5byksCiAgICAgICAgICAgIGNvbG9yID0gJyMyMDczOTQnKSArCiAgZ2VvbV9wb2ludChkYXRhID0gY2VsbF9jb3VudF9kZiwKICAgICAgICAgICAgIGFlcyh4ID0gcHNldWRvc2l6ZV9wY2EsIHkgPSBjZWxscyksCiAgICAgICAgICAgICBjb2wgPSAnYmxhY2snLCBwY2ggPSAyMSwgZmlsbCA9ICcjMjA3Mzk0Jywgc2l6ZSA9IDIuNSwgc3Ryb2tlID0gMSkgKwogIGxhYnModGl0bGUgPSBwYXN0ZTAoIk5lZ2F0aXZlIEJpbm9taWFsIEZpdCBmb3IgIiwgY3VycmVudF9jZWxsX3R5cGUsICIgaW4gIiwgdHJhamVjdG9yeV9uYW1lLCAiIHRyYWplY3RvcnkiKSwKICAgICAgIHkgPSAiQ2VsbHMgcGVyIHdvcm0iLCB4ID0gIlBzZXVkb3RpbWUgKHBzZXVkb3NpemVfcGNhKSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKAogICAgdGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiSGVsdmV0aWNhIiksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKSwgIAogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG9yID0gImJsYWNrIiwgZmlsbCA9IE5BLCBsaW5ld2lkdGggPSAwLjUpLCAgCiAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3IgPSAiYmxhY2siLCBmaWxsID0gTkEsIGxpbmV3aWR0aCA9IDAuNSkgIAogICkKCgpnZ3NhdmUoInZhcmlhbmNlX291dHB1dC9uZWdhdGl2ZV9iaW5vbWlhbC5wbmciLCBwbG90ID0gbmVnYXRpdmVfYmlub21pYWwsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNiwgZHBpID0gMzAwKQoKbmVnYXRpdmVfYmlub21pYWwKCgpgYGAKCgojIyMjIDQuMy4gQmV0YSBCaW5vbWlhbCBGaXQKClRoaXMgbW9kZWxsaW5nIGFwcHJvYWNoIGlzIHBhcnRpY3VsYXJseSBhcHByb3ByaWF0ZSB3aGVuIG1vZGVsaW5nICoqY29tcG9zaXRpb25hbCBkYXRhKiosIHdoZXJlIHRoZSBudW1iZXIgb2Ygb2JzZXJ2ZWQgY2VsbHMgb2YgYSBnaXZlbiB0eXBlIGlzIGNvbnN0cmFpbmVkIGJ5IGEgdG90YWwgY291bnQgcGVyIHNhbXBsZS4gVGhlIGJldGEtYmlub21pYWwgcmVncmVzc2lvbiBhcHByb2FjaCBleHBsaWNpdGx5IGFjY291bnRzIGZvciBvdmVyZGlzcGVyc2lvbiBhbmQgc2FtcGxpbmcgY29tcGV0aXRpb24gYW1vbmcgY2VsbCB0eXBlcywgbWFraW5nIGl0IGFuIGFwcHJvcHJpYXRlIHRvb2wgZm9yIGNhcHR1cmluZyB0aGUgYmlvbG9naWNhbCBhbmQgdGVjaG5pY2FsIHZhcmlhYmlsaXR5IGluIGNlbGwgdHlwZSBwcm9wb3J0aW9ucyBhY3Jvc3MgcHNldWRvdGltZSBhbmQgZmF0ZSB0cmFqZWN0b3JpZXMuCgpVbmxpa2UgdGhlIG5lZ2F0aXZlIGJpbm9taWFsIG1vZGVs4oCUd2hpY2ggYXNzdW1lcyB0aGF0IGNvdW50cyB2YXJ5IGluZGVwZW5kZW50bHkgb2YgdG90YWwgc2l6ZeKAlHRoZSBiZXRhLWJpbm9taWFsIGV4cGxpY2l0bHkgYWNjb3VudHMgZm9yIHRoZSAqKmJpbm9taWFsIG5hdHVyZSoqIG9mIHRoZSBkYXRhOgoKJCQKWV9pIFxzaW0gXHRleHR7QmV0YUJpbm9taWFsfShuX2ksIHBfaSwgXHJob19pKQokJAoKd2hlcmU6Ci0gXCggWV9pIFwpIGlzIHRoZSBudW1iZXIgb2YgY2VsbHMgaW4gZW1icnlvIFwoIGkgXCksCi0gXCggbl9pIFwpIGlzIHRoZSB0b3RhbCBudW1iZXIgb2YgY2VsbHMgb2JzZXJ2ZWQgaW4gdGhhdCBlbWJyeW8sCi0gXCggcF9pIFwpIGlzIHRoZSBleHBlY3RlZCBwcm9wb3J0aW9uIG9mIGNlbGxzLAotIFwoIFxyaG9faSBcKSByZXByZXNlbnRzIG92ZXJkaXNwZXJzaW9uIChpLmUuLCBjb3JyZWxhdGlvbiBhbW9uZyB0cmlhbHMpLgoKVGhpcyBmb3JtdWxhdGlvbiBjYXB0dXJlcyBib3RoIHRoZSAqKm1lYW4gcHJvcG9ydGlvbioqIGFuZCAqKmV4dHJhLWJpbm9taWFsIHZhcmlhbmNlKiogZHVlIHRvIGJpb2xvZ2ljYWwgb3IgdGVjaG5pY2FsIGhldGVyb2dlbmVpdHkuIFRoZSBleHBlY3RlZCBtZWFuIGFuZCB2YXJpYW5jZSBhcmU6CgokJApcYmVnaW57YWxpZ25lZH0KXG1hdGhiYntFfVtZX2ldICY9IG5faSBwX2kgXFwKXHRleHR7VmFyfShZX2kpICY9IG5faSBwX2kgKDEgLSBwX2kpKDEgKyAobl9pIC0gMSlccmhvX2kpClxlbmR7YWxpZ25lZH0KJCQKClNtb290aCBmdW5jdGlvbnMgb2YgcHNldWRvdGltZSB3ZXJlIHVzZWQgdG8gbW9kZWwgYm90aCBcKCBwX2kgXCkgYW5kIFwoIFxyaG9faSBcKSwgYWxsb3dpbmcgbm9uLWxpbmVhciB0cmVuZHMgaW4gY2VsbCBwcm9wb3J0aW9ucyB0byBiZSBjYXB0dXJlZCBhbG9uZyBkZXZlbG9wbWVudGFsIHRpbWUuCgpCaW9sb2dpY2FsbHksIHRoaXMgbW9kZWwgaXMgd2VsbC1zdWl0ZWQgZm9yIGNhcHR1cmluZyByZWd1bGF0b3J5IG9yIGRldmVsb3BtZW50YWwgY29uc3RyYWludHMgb24gY2VsbC10eXBlIGNvbW1pdG1lbnQsIHdoZXJlIGFuIGluY3JlYXNlIGluIG9uZSBjZWxsIHR5cGUgbmVjZXNzaXRhdGVzIGEgZGVjcmVhc2UgaW4gb3RoZXJzLiBJdCBpcyBwYXJ0aWN1bGFybHkgdXNlZnVsIGZvciBhc3Nlc3NpbmcgKipyZWxhdGl2ZSBjaGFuZ2VzIGluIGFidW5kYW5jZSoqIHJhdGhlciB0aGFuIGFic29sdXRlIGNlbGwgbnVtYmVycy4KCk1vZGVsIHBlcmZvcm1hbmNlIHdhcyBldmFsdWF0ZWQgdXNpbmcgYSBsaWtlbGlob29kIHJhdGlvIHRlc3QgYWdhaW5zdCBhIG51bGwgbW9kZWwgYW5kIHZpYSBhIHBzZXVkby1cKCBSXjIgXCkgbWV0cmljLiBDb25maWRlbmNlIGludGVydmFscyBhbmQgdmFyaWFiaWxpdHkgYmFuZHMgd2VyZSBvYnRhaW5lZCB0aHJvdWdoIHNpbXVsYXRpb24gZnJvbSB0aGUgZml0dGVkIGRpc3RyaWJ1dGlvbi4KClRoaXMgbW9kZWwgZWZmZWN0aXZlbHkgY2FwdHVyZWQgdGhlIHNoYXBlIGFuZCBkaXNwZXJzaW9uIG9mIGNlbGwgcHJvcG9ydGlvbiBhY3Jvc3MgcHNldWRvdGltZSwgb2ZmZXJpbmcgbW9yZSBhcHByb3ByaWF0ZSBpbmZlcmVuY2UgdGhhbiBjb3VudC1iYXNlZCBtb2RlbHMgbGlrZSB0aGUgbmVnYXRpdmUgYmlub21pYWwgd2hlbiBjb21wb3NpdGlvbmFsIGNvbnN0cmFpbnRzIGFyZSBwcmVzZW50LgoKYGBge3IgYmV0YS1iaW5vbWlhbH0KbGlicmFyeShWR0FNKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkodGliYmxlKQpsaWJyYXJ5KHRpZHlyKQoKIyBTZXQgY2VsbCB0eXBlIGFuZCB0cmFqZWN0b3J5CmN1cnJlbnRfY2VsbF90eXBlIDwtICJUZXN0ZXMiCnRyYWplY3RvcnlfbmFtZSA8LSAic2V4dWFsIgoKIyBHZXQgc2FtcGxlcyBpbiB0aGUgc2VsZWN0ZWQgdHJhamVjdG9yeQp0cmFqZWN0b3J5X3NhbXBsZXMgPC0gdHJhamVjdG9yaWVzW1t0cmFqZWN0b3J5X25hbWVdXSRzYW1wbGVzCgojIEZpbHRlciBjb2xEYXRhIGZvciBzZWxlY3RlZCB0cmFqZWN0b3J5IHNhbXBsZXMKY2VsbF9jb3VudF9kZiA8LSBjb2xEYXRhKGNkcykgJT4lCiAgYXMuZGF0YS5mcmFtZSgpICU+JQogIGZpbHRlcihyb3duYW1lcyguKSAlaW4lIHRyYWplY3Rvcnlfc2FtcGxlcykgJT4lCiAgbXV0YXRlKAogICAgY2VsbHMgPSBjb3VudHMoY2RzKVtjdXJyZW50X2NlbGxfdHlwZSwgcm93bmFtZXMoLildLAogICAgY2VsbF90eXBlID0gY3VycmVudF9jZWxsX3R5cGUsCiAgICB0b3RhbF9jZWxscyA9IGNvbFN1bXMoY291bnRzKGNkcykpW3Jvd25hbWVzKC4pXSwKICAgIGVtYnJ5byA9IHNhbXBsZSwKICAgIHBzZXVkb3NpemVfcGNhID0gcHNldWRvc2l6ZV9wY2EsCiAgICBnZW5vdHlwZSA9ICdwbW9yJwogICkKCiMgRml0IGJldGEtYmlub21pYWwgbW9kZWwKZml0IDwtIFZHQU06OnZnbG0oY2JpbmQoY2VsbHMsIHRvdGFsX2NlbGxzIC0gY2VsbHMpIH4gc20ubnMocHNldWRvc2l6ZV9wY2EsIGRmID0gMyksCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBjZWxsX2NvdW50X2RmLAogICAgICAgICAgICAgICAgICBmYW1pbHkgPSBiZXRhYmlub21pYWwoemVybyA9IE5VTEwpLAogICAgICAgICAgICAgICAgICB0cmFjZSA9IEZBTFNFKQoKIyBOdWxsIG1vZGVsCmZpdC5udWxsIDwtIFZHQU06OnZnbG0oY2JpbmQoY2VsbHMsIHRvdGFsX2NlbGxzIC0gY2VsbHMpIH4gMSwKICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gY2VsbF9jb3VudF9kZiwKICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSBiZXRhYmlub21pYWwoemVybyA9IE5VTEwpLAogICAgICAgICAgICAgICAgICAgICAgIHRyYWNlID0gRkFMU0UpCgojIExpa2VsaWhvb2QgcmF0aW8gdGVzdCBhbmQgcHNldWRvIFJeMgpsci5vYmogPC0gVkdBTTo6bHJ0ZXN0KGZpdCwgZml0Lm51bGwpCnRlc3Quc3RhdCA8LSBsci5vYmpAQm9keSRDaGlzcVsyXQpwLnZhbHVlIDwtIGxyLm9iakBCb2R5JGBQcig+Q2hpc3EpYFsyXQpwc2V1ZG9fUjIgPC0gMSAtIChsb2dMaWsoZml0KSAvIGxvZ0xpayhmaXQubnVsbCkpCgojIEV2YWx1YXRpb24gcmVzdWx0cwptb2RfZXZhbCA8LSB0aWJibGUoCiAgdGVzdC5zdGF0ID0gdGVzdC5zdGF0LAogIHAudmFsdWUgPSBwLnZhbHVlLAogIHBzZXVkb19SMiA9IHBzZXVkb19SMgopCgpwcmludChtb2RfZXZhbCkKCiMgR2VuZXJhdGUgc21vb3RoIHByZWRpY3Rpb24gb3ZlciBwc2V1ZG90aW1lCmZha2VfZGYgPC0gZGF0YS5mcmFtZShwc2V1ZG9zaXplX3BjYSA9IHNlcShtaW4oY2VsbF9jb3VudF9kZiRwc2V1ZG9zaXplX3BjYSwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heChjZWxsX2NvdW50X2RmJHBzZXVkb3NpemVfcGNhLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoLm91dCA9IDk0KSkgJT4lCiAgbXV0YXRlKGVtYnJ5byA9IHBhc3RlKCdkdW1teScsIHJvd19udW1iZXIoKSwgc2VwID0gJy0nKSkgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJlbWJyeW8iKQoKIyBQcmVkaWN0IGZyb20gbW9kZWwKcHJlZF9kZiA8LSBhcy5kYXRhLmZyYW1lKHByZWRpY3QoZml0LCBmYWtlX2RmKSkKCiMgUmVjb3ZlciBuYXR1cmFsLXNjYWxlIHBhcmFtZXRlcnMKbWVhbl9jZWxscyA8LSBtZWFuKGNlbGxfY291bnRfZGYkdG90YWxfY2VsbHMsIG5hLnJtID0gVFJVRSkKcHJlZF9kZiRwcmVkX211IDwtIHBsb2dpcyhwcmVkX2RmWywxXSkKcHJlZF9kZiRwcmVkX3JobyA8LSBwbG9naXMocHJlZF9kZlssMl0pCnByZWRfZGYkcHJlZF9jZWxscyA8LSBwcmVkX2RmJHByZWRfbXUgKiBtZWFuX2NlbGxzCnByZWRfZGYkcHJlZF92YXIgPC0gbWVhbl9jZWxscyAqIHByZWRfZGYkcHJlZF9tdSAqICgxIC0gcHJlZF9kZiRwcmVkX211KSAqCiAgICAgICAgICAgICAgICAgICAgKDEgKyAobWVhbl9jZWxscyAtIDEpICogcHJlZF9kZiRwcmVkX3JobykKCiMgQWRkIHRvIGZha2VfZGYKZmFrZV9kZiRjZWxscyA8LSBwcmVkX2RmJHByZWRfY2VsbHMKZmFrZV9kZiRwcmVkX3ZhciA8LSBwcmVkX2RmJHByZWRfdmFyCmZha2VfZGYkY2lfdXBwZXIgPC0gcHJlZF9kZiRwcmVkX2NlbGxzICsgMiAqIHNxcnQocHJlZF9kZiRwcmVkX3ZhcikKZmFrZV9kZiRjaV9sb3dlciA8LSBwcmVkX2RmJHByZWRfY2VsbHMgLSAyICogc3FydChwcmVkX2RmJHByZWRfdmFyKQpmYWtlX2RmJG4gPC0gbWVhbl9jZWxscwoKIyBTaW11bGF0ZSBmcm9tIGJldGEtYmlub21pYWwKbnNpbSA8LSAxMDAwMApzZXQuc2VlZCgxMjMpCnNpbV9yZXMgPC0gbWF0cml4KG5yb3cgPSBucm93KGZha2VfZGYpLCBuY29sID0gbnNpbSkKCmVwc2lsb24gPC0gMWUtNgoKZm9yIChpIGluIDE6bnJvdyhmYWtlX2RmKSkgewogIG11IDwtIG1heChtaW4ocHJlZF9kZiRwcmVkX211W2ldLCAxIC0gZXBzaWxvbiksIGVwc2lsb24pCiAgcmhvIDwtIG1heChtaW4ocHJlZF9kZiRwcmVkX3Job1tpXSwgMSAtIGVwc2lsb24pLCBlcHNpbG9uKQogIG4gPC0gYXMuaW50ZWdlcihmYWtlX2RmJG5baV0pCiAgCiAgc2hhcGVfZmFjdG9yIDwtICgxIC0gcmhvKSAvIHJobwogIHNoYXBlMSA8LSBtdSAqIHNoYXBlX2ZhY3RvcgogIHNoYXBlMiA8LSAoMSAtIG11KSAqIHNoYXBlX2ZhY3RvcgoKICBzaW1fcmVzW2ksIF0gPC0gaWYgKGlzLm5hKHNoYXBlMSkgfHwgaXMubmEoc2hhcGUyKSB8fCBzaGFwZTEgPD0gMCB8fCBzaGFwZTIgPD0gMCkgewogICAgcmJpbm9tKG5zaW0sIHNpemUgPSBuLCBwcm9iID0gbXUpCiAgfSBlbHNlIHsKICAgIHJiZXRhYmlub20uYWIobnNpbSwgc2l6ZSA9IG4sIHNoYXBlMSA9IHNoYXBlMSwgc2hhcGUyID0gc2hhcGUyKQogIH0KfQoKIyBBdHRhY2ggc2ltdWxhdGlvbiByZXN1bHRzCmZha2VfZGYkY2VsbHNfcGVyX2VtYnJ5byA8LSByb3dNZWFucyhzaW1fcmVzKQpmYWtlX2RmJGNlbGxzX3Blcl9lbWJyeW8uc3RkZGV2IDwtIGFwcGx5KHNpbV9yZXMsIDEsIHNkKQpmYWtlX2RmJGNpX2xvd2VyX3NpbSA8LSBhcHBseShzaW1fcmVzLCAxLCBxdWFudGlsZSwgcHJvYnMgPSAwLjAyNSkKZmFrZV9kZiRjaV91cHBlcl9zaW0gPC0gYXBwbHkoc2ltX3JlcywgMSwgcXVhbnRpbGUsIHByb2JzID0gMC45NzUpCgojIEZpbmFsIHBsb3QKYmV0YV9iaW5vbWlhbCA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9yaWJib24oZGF0YSA9IGZha2VfZGYsCiAgICAgICAgICAgICAgYWVzKHggPSBwc2V1ZG9zaXplX3BjYSwKICAgICAgICAgICAgICAgICAgeW1pbiA9IGNpX2xvd2VyX3NpbSwKICAgICAgICAgICAgICAgICAgeW1heCA9IGNpX3VwcGVyX3NpbSksCiAgICAgICAgICAgICAgYWxwaGEgPSAwLjQsIGZpbGwgPSAnIzIwNzM5NCcpICsKICBnZW9tX2xpbmUoZGF0YSA9IGZha2VfZGYsCiAgICAgICAgICAgIGFlcyh4ID0gcHNldWRvc2l6ZV9wY2EsIHkgPSBjZWxsc19wZXJfZW1icnlvKSwKICAgICAgICAgICAgY29sb3IgPSAnIzIwNzM5NCcpICsKICBnZW9tX3BvaW50KGRhdGEgPSBjZWxsX2NvdW50X2RmLAogICAgICAgICAgICAgYWVzKHggPSBwc2V1ZG9zaXplX3BjYSwgeSA9IGNlbGxzKSwKICAgICAgICAgICAgIGNvbCA9ICdibGFjaycsIHBjaCA9IDIxLCBmaWxsID0gJyMyMDczOTQnLCBzaXplID0gMi41LCBzdHJva2UgPSAxKSArCiAgbGFicyh0aXRsZSA9IHBhc3RlMCgiQmV0YSBCaW5vbWlhbCBGaXQgZm9yICIsIGN1cnJlbnRfY2VsbF90eXBlLCAiIGluICIsIHRyYWplY3RvcnlfbmFtZSwgIiB0cmFqZWN0b3J5IiksCiAgICAgICB5ID0gIkNlbGxzIHBlciB3b3JtIiwgeCA9ICJQc2V1ZG90aW1lIChwc2V1ZG9zaXplX3BjYSkiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSgKICAgIHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIkhlbHZldGljYSIpLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiksICAKICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvciA9ICJibGFjayIsIGZpbGwgPSBOQSwgbGluZXdpZHRoID0gMC41KSwgIAogICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG9yID0gImJsYWNrIiwgZmlsbCA9IE5BLCBsaW5ld2lkdGggPSAwLjUpICAKICApCgpiZXRhX2Jpbm9taWFsCgpiZXRhX2Jpbm9taWFsX2V4dHJhIDwtIGdncGxvdChjZWxsX2NvdW50X2RmKSArIAogICMgb3Zlcmx5IGNvbnNlcnZhdGl2ZSBDSSByaWJib24gKG1lYW4gwrEgQ0kgdXBwZXIpCiAgZ2VvbV9yaWJib24oZGF0YSA9IGZha2VfZGYsCiAgICAgICAgICAgICAgYWVzKHggPSBwc2V1ZG9zaXplX3BjYSwKICAgICAgICAgICAgICAgICAgeW1pbiA9IGNlbGxzIC0gY2lfdXBwZXIsCiAgICAgICAgICAgICAgICAgIHltYXggPSBjZWxscyArIGNpX3VwcGVyKSwKICAgICAgICAgICAgICBhbHBoYSA9IDAuMjUsIGZpbGwgPSAnIzQ0NDQ0NCcpICsKICAKICAjIHBsb3QgwrExIFNEIGZyb20gc2ltdWxhdGlvbnMKICBnZW9tX3JpYmJvbihkYXRhID0gZmFrZV9kZiwKICAgICAgICAgICAgICBhZXMoeCA9IHBzZXVkb3NpemVfcGNhLAogICAgICAgICAgICAgICAgICB5bWluID0gY2VsbHNfcGVyX2VtYnJ5byAtIGNlbGxzX3Blcl9lbWJyeW8uc3RkZGV2LAogICAgICAgICAgICAgICAgICB5bWF4ID0gY2VsbHNfcGVyX2VtYnJ5byArIGNlbGxzX3Blcl9lbWJyeW8uc3RkZGV2KSwKICAgICAgICAgICAgICBhbHBoYSA9IDAuNSkgKwogIAogICMgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgZnJvbSBzaW11bGF0aW9uCiAgZ2VvbV9yaWJib24oZGF0YSA9IGZha2VfZGYsCiAgICAgICAgICAgICAgYWVzKHggPSBwc2V1ZG9zaXplX3BjYSwKICAgICAgICAgICAgICAgICAgeW1pbiA9IGNpX2xvd2VyX3NpbSwKICAgICAgICAgICAgICAgICAgeW1heCA9IGNpX3VwcGVyX3NpbSksCiAgICAgICAgICAgICAgYWxwaGEgPSAwLjUpICsKCiAgIyBtZWFuIGZpdHRlZCBhYnVuZGFuY2Ugb3ZlciBwc2V1ZG90aW1lCiAgZ2VvbV9saW5lKGRhdGEgPSBmYWtlX2RmLAogICAgICAgICAgICBhZXMoeCA9IHBzZXVkb3NpemVfcGNhLCB5ID0gY2VsbHMpKSArCgogICMgb2JzZXJ2ZWQgZGF0YSBwb2ludHMKICBnZW9tX3BvaW50KGFlcyh4ID0gcHNldWRvc2l6ZV9wY2EsIHkgPSBjZWxscyksCiAgICAgICAgICAgICBjb2wgPSAnYmxhY2snLCBwY2ggPSAyMSwgZmlsbCA9ICcjODg4ODg4Jywgc2l6ZSA9IDIuNSwgc3Ryb2tlID0gMSkgKwogIGxhYnModGl0bGUgPSBwYXN0ZTAoIkJldGEgQmlub21pYWwgRml0IGZvciAiLCBjdXJyZW50X2NlbGxfdHlwZSwgIiBpbiAiLCB0cmFqZWN0b3J5X25hbWUsICIgdHJhamVjdG9yeSIpLCAgICAgICB5ID0gIkNlbGxzIHBlciB3b3JtIiwgeCA9ICJQc2V1ZG90aW1lIChwc2V1ZG9zaXplX3BjYSkiKSArCiAgdGhlbWVfbWluaW1hbCgpICsgIyBvciB0aGVtZV9jbGVhbiBpZiBkZWZpbmVkIAogIHRoZW1lKAogICAgdGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiSGVsdmV0aWNhIiksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKSwgIAogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG9yID0gImJsYWNrIiwgZmlsbCA9IE5BLCBsaW5ld2lkdGggPSAwLjUpLCAgCiAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3IgPSAiYmxhY2siLCBmaWxsID0gTkEsIGxpbmV3aWR0aCA9IDAuNSkgIAogICkKCmJldGFfYmlub21pYWxfZXh0cmEKCmdnc2F2ZSgidmFyaWFuY2Vfb3V0cHV0L2JldGFfYmlub21pYWwucG5nIiwgcGxvdCA9IGJldGFfYmlub21pYWwsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNiwgZHBpID0gMzAwKQpnZ3NhdmUoInZhcmlhbmNlX291dHB1dC9iZXRhX2Jpbm9taWFsX2V4dHJhLnBuZyIsIHBsb3QgPSBiZXRhX2Jpbm9taWFsX2V4dHJhLCB3aWR0aCA9IDgsIGhlaWdodCA9IDYsIGRwaSA9IDMwMCkKCmBgYAoKYGBge3IgYmV0YSBiaW5vbWlhbCBsb29wLCBlY2hvID0gRkFMU0V9CgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCiMgIyBUSElTIElTIEEgTE9PUCBUTyBSVU4gVEhFIEJFVEEgQklOT01JQUwgRklUUyBGT1IgQUxMIENFTEwgVFlQRVMgQUxPTkcgQUxMIFRSQUpFQ1RPUklFUwoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIGxpYnJhcnkocHVycnIpCiMgbGlicmFyeShmcykKIyAKIyAjIFNldCBvdXRwdXQgZGlyZWN0b3J5CiMgb3V0cHV0X2RpciA8LSAidmFyaWFuY2Vfb3V0cHV0L2JldGFfYmlub21pYWxfZml0cyIKIyBkaXJfY3JlYXRlKG91dHB1dF9kaXIpCiMgCiMgIyBEZWZpbmUgY2VsbCB0eXBlcyB0byBpbmNsdWRlCiMgY2VsbF90eXBlc190b190ZXN0IDwtIHJvd25hbWVzKGNvdW50cyhjZHMpKQojIAojICMgTG9vcGluZyBmdW5jdGlvbgojIGZpdF9iZXRhX2Jpbm9taWFsX21vZGVsIDwtIGZ1bmN0aW9uKGNlbGxfdHlwZSwgdHJhamVjdG9yeV9rZXkpIHsKIyAgIG1lc3NhZ2UoIlByb2Nlc3Npbmc6ICIsIGNlbGxfdHlwZSwgIiBpbiB0cmFqZWN0b3J5OiAiLCB0cmFqZWN0b3J5X2tleSkKIyAKIyAgICMgR2V0IHNhbXBsZXMgZm9yIGN1cnJlbnQgdHJhamVjdG9yeQojICAgdHJhamVjdG9yeV9zYW1wbGVzIDwtIHRyYWplY3Rvcmllc1tbdHJhamVjdG9yeV9rZXldXSRzYW1wbGVzCiMgICAKIyAgICMgU2tpcCBpZiBub3QgZW5vdWdoIHNhbXBsZXMKIyAgIGlmIChsZW5ndGgodHJhamVjdG9yeV9zYW1wbGVzKSA8IDEwKSByZXR1cm4oTlVMTCkKIyAKIyAgICMgQnVpbGQgZGF0YSBmcmFtZQojICAgY2VsbF9jb3VudF9kZiA8LSBjb2xEYXRhKGNkcykgJT4lCiMgICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUKIyAgICAgZmlsdGVyKHJvd25hbWVzKC4pICVpbiUgdHJhamVjdG9yeV9zYW1wbGVzKSAlPiUKIyAgICAgbXV0YXRlKAojICAgICAgIGNlbGxzID0gY291bnRzKGNkcylbY2VsbF90eXBlLCByb3duYW1lcyguKV0sCiMgICAgICAgY2VsbF90eXBlID0gY2VsbF90eXBlLAojICAgICAgIHRvdGFsX2NlbGxzID0gY29sU3Vtcyhjb3VudHMoY2RzKSlbcm93bmFtZXMoLildLAojICAgICAgIGVtYnJ5byA9IHNhbXBsZSwKIyAgICAgICBwc2V1ZG9zaXplX3BjYSA9IHBzZXVkb3NpemVfcGNhLAojICAgICAgIGdlbm90eXBlID0gJ3Btb3InCiMgICAgICkKIyAKIyAgIGlmIChzdW0oY2VsbF9jb3VudF9kZiRjZWxscykgPCA1KSByZXR1cm4oTlVMTCkgICMgU2tpcCB2ZXJ5IHNwYXJzZSBjZWxsIHR5cGVzCiMgCiMgICAjIEZpdCBtb2RlbHMKIyAgIGZpdCA8LSB0cnlDYXRjaCh7CiMgICAgIFZHQU06OnZnbG0oY2JpbmQoY2VsbHMsIHRvdGFsX2NlbGxzIC0gY2VsbHMpIH4gc20ubnMocHNldWRvc2l6ZV9wY2EsIGRmID0gMyksCiMgICAgICAgICAgICAgICAgZGF0YSA9IGNlbGxfY291bnRfZGYsCiMgICAgICAgICAgICAgICAgZmFtaWx5ID0gYmV0YWJpbm9taWFsKHplcm8gPSBOVUxMKSwKIyAgICAgICAgICAgICAgICB0cmFjZSA9IEZBTFNFKQojICAgfSwgZXJyb3IgPSBmdW5jdGlvbihlKSByZXR1cm4oTlVMTCkpCiMgCiMgICBmaXQubnVsbCA8LSB0cnlDYXRjaCh7CiMgICAgIFZHQU06OnZnbG0oY2JpbmQoY2VsbHMsIHRvdGFsX2NlbGxzIC0gY2VsbHMpIH4gMSwKIyAgICAgICAgICAgICAgICBkYXRhID0gY2VsbF9jb3VudF9kZiwKIyAgICAgICAgICAgICAgICBmYW1pbHkgPSBiZXRhYmlub21pYWwoemVybyA9IE5VTEwpLAojICAgICAgICAgICAgICAgIHRyYWNlID0gRkFMU0UpCiMgICB9LCBlcnJvciA9IGZ1bmN0aW9uKGUpIHJldHVybihOVUxMKSkKIyAKIyAgIGlmIChpcy5udWxsKGZpdCkgfHwgaXMubnVsbChmaXQubnVsbCkpIHJldHVybihOVUxMKQojIAojICAgIyBMaWtlbGlob29kIHRlc3QKIyAgIGxyLm9iaiA8LSBWR0FNOjpscnRlc3QoZml0LCBmaXQubnVsbCkKIyAgIHRlc3Quc3RhdCA8LSBsci5vYmpAQm9keSRDaGlzcVsyXQojICAgcC52YWx1ZSA8LSBsci5vYmpAQm9keSRgUHIoPkNoaXNxKWBbMl0KIyAgIHBzZXVkb19SMiA8LSAxIC0gKGxvZ0xpayhmaXQpIC8gbG9nTGlrKGZpdC5udWxsKSkKIyAKIyAgICMgUHJlZGljdGlvbiBncmlkCiMgICBmYWtlX2RmIDwtIGRhdGEuZnJhbWUocHNldWRvc2l6ZV9wY2EgPSBzZXEobWluKGNlbGxfY291bnRfZGYkcHNldWRvc2l6ZV9wY2EsIG5hLnJtID0gVFJVRSksCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4KGNlbGxfY291bnRfZGYkcHNldWRvc2l6ZV9wY2EsIG5hLnJtID0gVFJVRSksCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoLm91dCA9IDk0KSkgJT4lCiMgICAgIG11dGF0ZShlbWJyeW8gPSBwYXN0ZSgnZHVtbXknLCByb3dfbnVtYmVyKCksIHNlcCA9ICctJykpICU+JQojICAgICBjb2x1bW5fdG9fcm93bmFtZXModmFyID0gImVtYnJ5byIpCiMgICAKIyAgIHByZWRfZGYgPC0gYXMuZGF0YS5mcmFtZShwcmVkaWN0KGZpdCwgZmFrZV9kZikpCiMgICBtZWFuX2NlbGxzIDwtIG1lYW4oY2VsbF9jb3VudF9kZiR0b3RhbF9jZWxscywgbmEucm0gPSBUUlVFKQojICAgcHJlZF9kZiRwcmVkX211IDwtIHBsb2dpcyhwcmVkX2RmWywgMV0pCiMgICBwcmVkX2RmJHByZWRfcmhvIDwtIHBsb2dpcyhwcmVkX2RmWywgMl0pCiMgICBwcmVkX2RmJHByZWRfY2VsbHMgPC0gcHJlZF9kZiRwcmVkX211ICogbWVhbl9jZWxscwojICAgcHJlZF9kZiRwcmVkX3ZhciA8LSBtZWFuX2NlbGxzICogcHJlZF9kZiRwcmVkX211ICogKDEgLSBwcmVkX2RmJHByZWRfbXUpICoKIyAgICAgICAgICAgICAgICAgICAgICAgKDEgKyAobWVhbl9jZWxscyAtIDEpICogcHJlZF9kZiRwcmVkX3JobykKIyAKIyAgIGZha2VfZGYkY2VsbHMgPC0gcHJlZF9kZiRwcmVkX2NlbGxzCiMgICBmYWtlX2RmJHByZWRfdmFyIDwtIHByZWRfZGYkcHJlZF92YXIKIyAgIGZha2VfZGYkbiA8LSBtZWFuX2NlbGxzCiMgCiMgICAjIFNpbXVsYXRlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzCiMgICBuc2ltIDwtIDEwMDAwCiMgICBzZXQuc2VlZCgxMjMpCiMgICBzaW1fcmVzIDwtIG1hdHJpeChucm93ID0gbnJvdyhmYWtlX2RmKSwgbmNvbCA9IG5zaW0pCiMgICBlcHNpbG9uIDwtIDFlLTYKIyAKIyAgIGZvciAoaSBpbiAxOm5yb3coZmFrZV9kZikpIHsKIyAgICAgbXUgPC0gbWF4KG1pbihwcmVkX2RmJHByZWRfbXVbaV0sIDEgLSBlcHNpbG9uKSwgZXBzaWxvbikKIyAgICAgcmhvIDwtIG1heChtaW4ocHJlZF9kZiRwcmVkX3Job1tpXSwgMSAtIGVwc2lsb24pLCBlcHNpbG9uKQojICAgICBuIDwtIGFzLmludGVnZXIoZmFrZV9kZiRuW2ldKQojICAgICBzaGFwZV9mYWN0b3IgPC0gKDEgLSByaG8pIC8gcmhvCiMgICAgIHNoYXBlMSA8LSBtdSAqIHNoYXBlX2ZhY3RvcgojICAgICBzaGFwZTIgPC0gKDEgLSBtdSkgKiBzaGFwZV9mYWN0b3IKIyAgICAgc2ltX3Jlc1tpLCBdIDwtIGlmIChpcy5uYShzaGFwZTEpIHx8IGlzLm5hKHNoYXBlMikgfHwgc2hhcGUxIDw9IDAgfHwgc2hhcGUyIDw9IDApIHsKIyAgICAgICByYmlub20obnNpbSwgc2l6ZSA9IG4sIHByb2IgPSBtdSkKIyAgICAgfSBlbHNlIHsKIyAgICAgICByYmV0YWJpbm9tLmFiKG5zaW0sIHNpemUgPSBuLCBzaGFwZTEgPSBzaGFwZTEsIHNoYXBlMiA9IHNoYXBlMikKIyAgICAgfQojICAgfQojIAojICAgZmFrZV9kZiRjZWxsc19wZXJfZW1icnlvIDwtIHJvd01lYW5zKHNpbV9yZXMpCiMgICBmYWtlX2RmJGNlbGxzX3Blcl9lbWJyeW8uc3RkZGV2IDwtIGFwcGx5KHNpbV9yZXMsIDEsIHNkKQojICAgZmFrZV9kZiRjaV9sb3dlcl9zaW0gPC0gYXBwbHkoc2ltX3JlcywgMSwgcXVhbnRpbGUsIHByb2JzID0gMC4wMjUpCiMgICBmYWtlX2RmJGNpX3VwcGVyX3NpbSA8LSBhcHBseShzaW1fcmVzLCAxLCBxdWFudGlsZSwgcHJvYnMgPSAwLjk3NSkKIyAKIyAgICMgRmluYWwgcGxvdAojICAgcGxvdF9vdXQgPC0gZ2dwbG90KCkgKwojICAgICBnZW9tX3JpYmJvbihkYXRhID0gZmFrZV9kZiwKIyAgICAgICAgICAgICAgICAgYWVzKHggPSBwc2V1ZG9zaXplX3BjYSwKIyAgICAgICAgICAgICAgICAgICAgIHltaW4gPSBjaV9sb3dlcl9zaW0sCiMgICAgICAgICAgICAgICAgICAgICB5bWF4ID0gY2lfdXBwZXJfc2ltKSwKIyAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjQsIGZpbGwgPSAnIzIwNzM5NCcpICsKIyAgICAgZ2VvbV9saW5lKGRhdGEgPSBmYWtlX2RmLAojICAgICAgICAgICAgICAgYWVzKHggPSBwc2V1ZG9zaXplX3BjYSwgeSA9IGNlbGxzX3Blcl9lbWJyeW8pLAojICAgICAgICAgICAgICAgY29sb3IgPSAnIzIwNzM5NCcpICsKIyAgICAgZ2VvbV9wb2ludChkYXRhID0gY2VsbF9jb3VudF9kZiwKIyAgICAgICAgICAgICAgICBhZXMoeCA9IHBzZXVkb3NpemVfcGNhLCB5ID0gY2VsbHMpLAojICAgICAgICAgICAgICAgIGNvbCA9ICdibGFjaycsIHBjaCA9IDIxLCBmaWxsID0gJyMyMDczOTQnLCBzaXplID0gMi41LCBzdHJva2UgPSAxKSArCiMgICAgIGxhYnModGl0bGUgPSBwYXN0ZTAoY2VsbF90eXBlLCAiIGluICIsIHRyYWplY3Rvcnlfa2V5LCAiIHRyYWplY3RvcnkiKSwKIyAgICAgICAgICB5ID0gIkNlbGxzIHBlciB3b3JtIiwgeCA9ICJQc2V1ZG90aW1lIChwc2V1ZG9zaXplX3BjYSkiKSArCiMgICAgIHRoZW1lX21pbmltYWwoKQojIAojICAgIyBTYXZlCiMgICBmaWxlbmFtZSA8LSBwYXN0ZTAob3V0cHV0X2RpciwgIi8iLCB0cmFqZWN0b3J5X2tleSwgIl8iLCBnc3ViKCJbXmEtekEtWjAtOV0iLCAiXyIsIGNlbGxfdHlwZSksICIucG5nIikKIyAgIGdnc2F2ZShmaWxlbmFtZSwgcGxvdF9vdXQsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNCwgZHBpID0gMzAwKQojICAgCiMgICByZXR1cm4odGliYmxlKAojICAgICBjZWxsX3R5cGUgPSBjZWxsX3R5cGUsCiMgICAgIHRyYWplY3RvcnkgPSB0cmFqZWN0b3J5X2tleSwKIyAgICAgdGVzdC5zdGF0ID0gdGVzdC5zdGF0LAojICAgICBwLnZhbHVlID0gcC52YWx1ZSwKIyAgICAgcHNldWRvX1IyID0gcHNldWRvX1IyCiMgICApKQojIH0KIyAKIyAjIFJ1biBvdmVyIGFsbCBjb21iaW5hdGlvbnMKIyByZXN1bHRzIDwtIG1hcF9kZnIoY2VsbF90eXBlc190b190ZXN0LCBmdW5jdGlvbihjZWxsX3R5cGUpIHsKIyAgIG1hcF9kZnIobmFtZXModHJhamVjdG9yaWVzKSwgZnVuY3Rpb24odHJhaikgewojICAgICBmaXRfYmV0YV9iaW5vbWlhbF9tb2RlbChjZWxsX3R5cGUsIHRyYWopCiMgICB9KQojIH0pCiMgCiMgIyBTYXZlIHN1bW1hcnkKIyB3cml0ZS5jc3YocmVzdWx0cywgZmlsZSA9IGZpbGUucGF0aChvdXRwdXRfZGlyLCAiYmV0YV9iaW5vbWlhbF9zdW1tYXJ5LmNzdiIpLCByb3cubmFtZXMgPSBGQUxTRSkKCmBgYAoKCiMjIyA1LiBBIENvbWJpbmVkIEFuYWx5c2lzIGZvciBBYnVuZGFuY2UgYW5kIFZhcmlhbmNlCgpUbyBkZXRlY3QgbG9jYWxpemVkIHNoaWZ0cyBpbiBjZWxsIHR5cGUgYWJ1bmRhbmNlIGFuZCB2YXJpYXRpb24gYmlmdXJjYXRpb25zLCBhIGJyYW5jaC1jZW50ZXJlZCBkaWZmZXJlbnRpYWwgYW5hbHlzaXMgd2FzIGFwcGxpZWQgYWNyb3NzIHRocmVlIG1ham9yIHBzZXVkb3RlbXBvcmFsIHRyYWplY3RvcmllczogX3NleHVhbF8sIF9hc2V4dWFsXywgYW5kIF9lYXJseSBkZXZlbG9wbWVudF8uIEJyYW5jaCBwb2ludHMgd2VyZSBkZWZpbmVkIGZyb20gYW5ub3RhdGVkIHBzZXVkb3RpbWUgdHJhbnNpdGlvbnMsIGFuZCBhIHN5bW1ldHJpYyB3aW5kb3cgd2FzIGNlbnRlcmVkIG9uIHRoZSBjb3JyZXNwb25kaW5nIHBzZXVkb3RpbWUgY29vcmRpbmF0ZS4gVGhlIHdpbmRvdyB3YXMgaXRlcmF0aXZlbHkgZXhwYW5kZWQgdW50aWwgaXQgaW5jbHVkZWQgYXQgbGVhc3QgZml2ZSBjZWxscyBmcm9tIHRoZSB0YXJnZXQgdHJhamVjdG9yeSwgZW5zdXJpbmcgc3VmZmljaWVudCBzdGF0aXN0aWNhbCBwb3dlciB3aGlsZSBwcmVzZXJ2aW5nIGxvY2FsIHJlc29sdXRpb24uCgpDZWxsIHR5cGUgYWJ1bmRhbmNlcyB3aXRoaW4gdGhlIHdpbmRvdyB3ZXJlIGNvbXBhcmVkIHRvIHRob3NlIG91dHNpZGUgdGhlIHdpbmRvdyAod2l0aGluIHRoZSBzYW1lIHRyYWplY3RvcnkpIHVzaW5nIG5vbi1wYXJhbWV0cmljIHRlc3RzLiBUaGUgKipXaWxjb3hvbiByYW5rLXN1bSB0ZXN0KiogYXNzZXNzZWQgZGlmZmVyZW5jZXMgaW4gY2VudHJhbCB0ZW5kZW5jeSwgd2hpbGUgKipMZXZlbmXigJlzIHRlc3QqKiBldmFsdWF0ZWQgZGlmZmVyZW5jZXMgaW4gdmFyaWFuY2UuIFRoZXNlIGRpc3RyaWJ1dGlvbi1mcmVlIG1ldGhvZHMgYXJlIHJvYnVzdCB0byBzcGFyc2l0eSwgb3V0bGllcnMsIGFuZCBoZXRlcm9nZW5laXR5IGNvbW1vbiBpbiBzaW5nbGUtY2VsbCBkYXRhLCBidXQgcmVxdWlyZSBhIG1pbmltdW0gc2FtcGxlIHNpemUgdG8geWllbGQgc3RhYmxlIHAtdmFsdWVzIGFuZCBhdm9pZCBpbmZsYXRlZCBmYWxzZSBwb3NpdGl2ZXMuIEEgZml2ZS1jZWxsIHRocmVzaG9sZCB3YXMgdGhlcmVmb3JlIGltcG9zZWQgdG8gc2F0aXNmeSB0aGVzZSBhc3N1bXB0aW9ucyBhbmQgbWFpbnRhaW4gaW50ZXJwcmV0YWJpbGl0eS4KCkZvciBlYWNoIGNlbGwgdHlwZSwgbG9nXChfMlwpIGZvbGQgY2hhbmdlcyBpbiBib3RoIG1lYW4gYW5kIHZhcmlhbmNlIHdlcmUgY2FsY3VsYXRlZCBiZXR3ZWVuIGluLXdpbmRvdyBhbmQgb3V0LW9mLXdpbmRvdyBncm91cHMuIFAtdmFsdWVzIGZyb20gYm90aCB0ZXN0cyB3ZXJlIGludGVncmF0ZWQgaW50byBhIGNvbXBvc2l0ZSBzaWduaWZpY2FuY2Ugc2NvcmU6CgokJApwX3tcdGV4dHtzdW19fSA9IC1cbG9nX3sxMH0ocF97XHRleHR7bWVhbn19ICsgMTBeey0xMH0pIC0gXGxvZ197MTB9KHBfe1x0ZXh0e3Zhcn19ICsgMTBeey0xMH0pCiQkCgpDZWxsIHR5cGVzIHdlcmUgcmFua2VkIGJ5IHRoaXMgY29tYmluZWQgc2NvcmUgYW5kIHN0cmF0aWZpZWQgaW50byBlbXBpcmljYWwgcXVhbnRpbGUgdGllcnMgKGUuZy4sIHRvcCAxMCUsIHRvcCAyNSUpIHRvIGhpZ2hsaWdodCB0aGUgbW9zdCBzaWduaWZpY2FudGx5IGFsdGVyZWQgcG9wdWxhdGlvbnMuIFRoZXNlIHJlc3VsdHMgd2VyZSB2aXN1YWxpemVkIGFzIHR3by1kaW1lbnNpb25hbCBzY2F0dGVyIHBsb3RzIHdpdGggbG9nXChfMlwpIGZvbGQgY2hhbmdlIGluIG1lYW4gYW5kIHZhcmlhbmNlIG9uIHRoZSB4LSBhbmQgeS1heGVzLCByZXNwZWN0aXZlbHksIGFuZCBwb2ludCBzaXplIGVuY29kaW5nIHRoZSBcKCBwX3tcdGV4dHtzdW19fSBcKSBzY29yZS4gRGFzaGVkIGxpbmVzIGF0IHplcm8gc2VydmVkIGFzIHZpc3VhbCByZWZlcmVuY2VzIGZvciBubyBjaGFuZ2UuCgpUbyBhc3Nlc3Mgd2luZG93IHNwZWNpZmljaXR5LCB0aGUgb3ZlcmxhcCBiZXR3ZWVuIHdpbmRvdy1pbmNsdWRlZCBjZWxscyBhbmQgdHJhamVjdG9yeSBtZW1iZXJzaGlwIHdhcyBxdWFudGlmaWVkLiBDZWxscyB3aXRoaW4gdGhlIHBzZXVkb3RpbWUgd2luZG93IGJ1dCBvdXRzaWRlIHRoZSB0YXJnZXQgdHJhamVjdG9yeSB3ZXJlIGV4YW1pbmVkIGJ5IGNsdXN0ZXIgaWRlbnRpdHkgdG8gZXZhbHVhdGUgcG9zc2libGUgY29udGFtaW5hdGlvbiBmcm9tIGFkamFjZW50IGRldmVsb3BtZW50YWwgcHJvZ3JhbXMuCgpUaGlzIGZyYW1ld29yayBlbmFibGVzIHN0YXRpc3RpY2FsbHkgcm9idXN0IGlkZW50aWZpY2F0aW9uIG9mIGNlbGwgdHlwZXMgdGhhdCBleGhpYml0IGxvY2FsIHNoaWZ0cyBpbiBhYnVuZGFuY2UgYW5kIHZhcmlhYmlsaXR5IGF0IGxpbmVhZ2UgYmlmdXJjYXRpb25zLCBwcm92aWRpbmcgaW5zaWdodCBpbnRvIGNhbmRpZGF0ZSByZWd1bGF0b3JzIG9mIGRldmVsb3BtZW50YWwgdHJhbnNpdGlvbnMuCgp8ICoqVHJhamVjdG9yeSoqICAgICAgICAgICAgIHwgKipDZWxsIFR5cGVzKiogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfAp8ICoqRWFybHkgRGV2ZWxvcG1lbnQqKjxicj5QcmVicmFuY2hfMiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBDYXRoZXBzaW4rIDUsIFBhcmVuY2h5bWFsIDIsIE5ldXJhbCAxLCBOZXVyYWwgMiwgTXVzY2xlIDMsIEludGVzdGluZSAxLCBOZXVyYWwgNiwgSW50ZXN0aW5lIDYsIEVwaWRlcm1hbCAxLCBFcGlkZXJtYWwgNCwgTXVzY2xlIDIsIE5lb2JsYXN0IDMsIE11c2NsZSA1IHwKfCAqKkFzZXh1YWwqKjxicj5CcmFuY2hfMSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgTXVzY2xlIDIsIE5lb2JsYXN0IDQsIE11c2NsZSAzLCBOZXVyYWwgMSwgTXVzY2xlIDUsIE5ldXJhbCA2LCBOZXVyYWwgMiwgSW50ZXN0aW5lIDcsIEVwaWRlcm1hbCA4LCBDYXRoZXBzaW4rIDMsIE5ldXJhbCAzLCBDYXRoZXBzaW4rIDQsIE51ZXJhbCA3IHwKfCAqKlNleHVhbCoqPGJyPkJyYW5jaF8yICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgTXVzY2xlIDIsIEVwaWRlcm1hbCA1LCBOZXVyYWwgMSwgTXVzY2xlIDMsIFRlc3RlcywgTmV1cmFsIDIsIE5lb2JsYXN0IDIsIFBhcmVuY2h5bWFsIDUsIE5ldXJhbCAzLCBTaXplIHNwZWNpZmljIDIsIE5ldXJhbCA5LCBFcGlkZXJtYWwgMSwgTnVlcmFsIDcsIENhdGhlcHNpbisgMiB8CgoKCmBgYHtyIGNvbWJpbmVkIGFuYWx5c2lzfQoKIyBDb21iaW5lZCBwbG90CnBsb3RfYnJhbmNocG9pbnRfaW5fdHJhamVjdG9yeSA8LSBmdW5jdGlvbih0cmFqZWN0b3J5X2tleSwgYnJhbmNoX25hbWUsIG1pbl9zYW1wbGVzID0gNSwgbGFiZWxfdG9wX24gPSAiYWxsIiwgcG9pbnRfYWxwaGEgPSAwLjgsIGJhc2Vfc2l6ZSA9IDE0KSB7CiAgYnJhbmNoX3RpbWUgPC0gdHJhbnNpdGlvbnNbW2JyYW5jaF9uYW1lXV0KICBjbHVzdGVyc19pbl90cmFqIDwtIHRyYWplY3Rvcmllc1tbdHJhamVjdG9yeV9rZXldXSRicmFuY2hlcwogIHRyYWpfc2FtcGxlcyA8LSByb3duYW1lcyhjb2xkYXQpW2NvbGRhdCRjbHVzdGVyICVpbiUgY2x1c3RlcnNfaW5fdHJhal0KICB0cmFqX2NvbGRhdCA8LSBjb2xkYXRbdHJhal9zYW1wbGVzLCBdCiAgCiAgZmluZF9hZGVxdWF0ZV93aW5kb3cgPC0gZnVuY3Rpb24oYnJhbmNoX3RpbWUsIG1pbl9zYW1wbGVzKSB7CiAgICB3aW5kb3dfc2l6ZSA8LSAwLjA1ICogbWF4KGNvbGRhdCRwc2V1ZG9zaXplX3BjYSkKICAgIHNhbXBsZXNfaW5fd2luZG93IDwtIDAKICAgIG1heF9pdGVyYXRpb25zIDwtIDIwCiAgICBpdGVyYXRpb24gPC0gMAogICAgd2hpbGUgKHNhbXBsZXNfaW5fd2luZG93IDwgbWluX3NhbXBsZXMgJiYgaXRlcmF0aW9uIDwgbWF4X2l0ZXJhdGlvbnMpIHsKICAgICAgaW5fd2luZG93IDwtIGRwbHlyOjpiZXR3ZWVuKHRyYWpfY29sZGF0JHBzZXVkb3NpemVfcGNhLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyYW5jaF90aW1lIC0gd2luZG93X3NpemUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJhbmNoX3RpbWUgKyB3aW5kb3dfc2l6ZSkKICAgICAgc2FtcGxlc19pbl93aW5kb3cgPC0gc3VtKGluX3dpbmRvdykKICAgICAgaWYgKHNhbXBsZXNfaW5fd2luZG93IDwgbWluX3NhbXBsZXMpIHsKICAgICAgICB3aW5kb3dfc2l6ZSA8LSB3aW5kb3dfc2l6ZSAqIDEuNQogICAgICB9CiAgICAgIGl0ZXJhdGlvbiA8LSBpdGVyYXRpb24gKyAxCiAgICB9CiAgICByZXR1cm4od2luZG93X3NpemUpCiAgfQogIAogIHRyYW5zaXRpb25fd2luZG93IDwtIGZpbmRfYWRlcXVhdGVfd2luZG93KGJyYW5jaF90aW1lLCBtaW5fc2FtcGxlcykKICBpbl9icmFuY2ggPC0gZHBseXI6OmJldHdlZW4odHJhal9jb2xkYXQkcHNldWRvc2l6ZV9wY2EsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmFuY2hfdGltZSAtIHRyYW5zaXRpb25fd2luZG93LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJhbmNoX3RpbWUgKyB0cmFuc2l0aW9uX3dpbmRvdykKCiAgcmVzdWx0cyA8LSByb3duYW1lcyhjZWxsX3Byb3BzKSAlPiUKICAgIHB1cnJyOjptYXBfZGZyKGZ1bmN0aW9uKGN0KSB7CiAgICAgIHZhbHMgPC0gY2VsbF9wcm9wc1tjdCwgdHJhal9zYW1wbGVzXQogICAgICBpZiAoc3VtKGluX2JyYW5jaCkgPCAzIHx8IHN1bSghaW5fYnJhbmNoKSA8IDMpIHsKICAgICAgICByZXR1cm4oZGF0YS5mcmFtZShjZWxsX3R5cGUgPSBjdCwgbG9nMl9tZWFuX2ZjID0gTkFfcmVhbF8sIGxvZzJfdmFyX2ZjID0gTkFfcmVhbF8sIHBfc3VtID0gTkFfcmVhbF8pKQogICAgICB9CiAgICAgIG1lYW5fZmMgPC0gdHJ5Q2F0Y2goKG1lYW4odmFsc1tpbl9icmFuY2hdLCBuYS5ybSA9IFRSVUUpICsgMWUtNikgLyAobWVhbih2YWxzWyFpbl9icmFuY2hdLCBuYS5ybSA9IFRSVUUpICsgMWUtNiksIGVycm9yID0gZnVuY3Rpb24oZSkgTkFfcmVhbF8pCiAgICAgIG1lYW5fcCA8LSB0cnlDYXRjaCh3aWxjb3gudGVzdCh2YWxzW2luX2JyYW5jaF0sIHZhbHNbIWluX2JyYW5jaF0pJHAudmFsdWUsIGVycm9yID0gZnVuY3Rpb24oZSkgTkFfcmVhbF8pCiAgICAgIHZhcl9mYyA8LSB0cnlDYXRjaCgodmFyKHZhbHNbaW5fYnJhbmNoXSwgbmEucm0gPSBUUlVFKSArIDFlLTYpIC8gKHZhcih2YWxzWyFpbl9icmFuY2hdLCBuYS5ybSA9IFRSVUUpICsgMWUtNiksIGVycm9yID0gZnVuY3Rpb24oZSkgTkFfcmVhbF8pCiAgICAgIHZhcl9wIDwtIHRyeUNhdGNoKGNhcjo6bGV2ZW5lVGVzdCh2YWxzIH4gZmFjdG9yKGluX2JyYW5jaCkpJGBQcig+RilgWzFdLCBlcnJvciA9IGZ1bmN0aW9uKGUpIE5BX3JlYWxfKQogICAgICBkYXRhLmZyYW1lKGNlbGxfdHlwZSA9IGN0LCBsb2cyX21lYW5fZmMgPSBsb2cyKG1lYW5fZmMpLCBsb2cyX3Zhcl9mYyA9IGxvZzIodmFyX2ZjKSwgcF9zdW0gPSAtbG9nMTAobWVhbl9wICsgMWUtMTApICsgLWxvZzEwKHZhcl9wICsgMWUtMTApKQogICAgfSkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShwX3N1bSkpICU+JQogICAgZHBseXI6OmFycmFuZ2UoZGVzYyhwX3N1bSkpCgogIHBsb3RfZGF0YSA8LSByZXN1bHRzICU+JQogICAgZHBseXI6Om11dGF0ZSgKICAgICAgc2lnbmlmaWNhbmNlID0gZHBseXI6OmNhc2Vfd2hlbigKICAgICAgICBwX3N1bSA+IHF1YW50aWxlKHBfc3VtLCAwLjksIG5hLnJtID0gVFJVRSkgfiAiVG9wIDEwJSIsCiAgICAgICAgcF9zdW0gPiBxdWFudGlsZShwX3N1bSwgMC43NSwgbmEucm0gPSBUUlVFKSB+ICJUb3AgMjUlIiwKICAgICAgICBUUlVFIH4gIk5vdCBzaWduaWZpY2FudCIKICAgICAgKSwKICAgICAgc2lnbmlmaWNhbmNlID0gZmFjdG9yKHNpZ25pZmljYW5jZSwgbGV2ZWxzID0gYygiTm90IHNpZ25pZmljYW50IiwgIlRvcCAyNSUiLCAiVG9wIDEwJSIpKQogICAgKQoKICB5X3JhbmdlIDwtIHJhbmdlKHBsb3RfZGF0YSRsb2cyX3Zhcl9mYywgbmEucm0gPSBUUlVFKQogIHhfcmFuZ2UgPC0gcmFuZ2UocGxvdF9kYXRhJGxvZzJfbWVhbl9mYywgbmEucm0gPSBUUlVFKQogIHlfZXhwYW5zaW9uIDwtIGRpZmYoeV9yYW5nZSkgKiAwLjIKICB4X2V4cGFuc2lvbiA8LSBkaWZmKHhfcmFuZ2UpICogMC4yCgogIHAgPC0gZ2dwbG90Mjo6Z2dwbG90KHBsb3RfZGF0YSwgYWVzKHggPSBsb2cyX21lYW5fZmMsIHkgPSBsb2cyX3Zhcl9mYykpICsKICAgIGdncGxvdDI6Omdlb21fcG9pbnQoYWVzKHNpemUgPSBwX3N1bSwgY29sb3IgPSBzaWduaWZpY2FuY2UsIGZpbGwgPSBzaWduaWZpY2FuY2UpLCBhbHBoYSA9IHBvaW50X2FscGhhLCBzaGFwZSA9IDIxKSArCiAgICB7CiAgICAgIGlmIChsYWJlbF90b3BfbiA9PSAiYWxsIikgewogICAgICAgIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbCgKICAgICAgICAgIGFlcyhsYWJlbCA9IGNlbGxfdHlwZSksCiAgICAgICAgICBzaXplID0gMy41LAogICAgICAgICAgbWluLnNlZ21lbnQubGVuZ3RoID0gMC4wNSwKICAgICAgICAgIGJveC5wYWRkaW5nID0gMC4zNSwKICAgICAgICAgIHBvaW50LnBhZGRpbmcgPSAwLjIsCiAgICAgICAgICBzZWdtZW50LnNpemUgPSAwLjMsCiAgICAgICAgICBtYXgub3ZlcmxhcHMgPSBJbmYsCiAgICAgICAgICBzZWdtZW50LmNvbG9yID0gImdyZXk1MCIsCiAgICAgICAgICBzZWdtZW50LmFscGhhID0gMC40LAogICAgICAgICAgZm9yY2UgPSAyLAogICAgICAgICAgbWF4LnRpbWUgPSAxMCwKICAgICAgICAgIG1heC5pdGVyID0gMTAwMDAwCiAgICAgICAgKQogICAgICB9IGVsc2UgewogICAgICAgIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbCgKICAgICAgICAgIGRhdGEgPSBoZWFkKHBsb3RfZGF0YSwgbGFiZWxfdG9wX24pLAogICAgICAgICAgYWVzKGxhYmVsID0gY2VsbF90eXBlKSwKICAgICAgICAgIHNpemUgPSAzLjgsCiAgICAgICAgICBib3gucGFkZGluZyA9IDAuNCwKICAgICAgICAgIHBvaW50LnBhZGRpbmcgPSAwLjMsCiAgICAgICAgICBmb3JjZSA9IDIKICAgICAgICApCiAgICAgIH0KICAgIH0gKwogICAgZ2dwbG90Mjo6Z2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiZ3JleTQwIiwgbGluZXdpZHRoID0gMC4zKSArCiAgICBnZ3Bsb3QyOjpnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJncmV5NDAiLCBsaW5ld2lkdGggPSAwLjMpICsKICAgIGdncGxvdDI6OnNjYWxlX3NpemVfY29udGludW91cyhuYW1lID0gIi1sb2cxMChwLXZhbHVlIHN1bSkiLCByYW5nZSA9IGMoMS41LCA2KSwgYnJlYWtzID0gc2NhbGVzOjpwcmV0dHlfYnJlYWtzKG4gPSA0KSkgKwogICAgZ2dwbG90Mjo6c2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAiU2lnbmlmaWNhbmNlIiwgdmFsdWVzID0gYygiTm90IHNpZ25pZmljYW50IiA9ICJncmV5NzAiLCAiVG9wIDI1JSIgPSAiI0YyOEUyQiIsICJUb3AgMTAlIiA9ICIjRTE1NzU5IikpICsKICAgIGdncGxvdDI6OnNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiU2lnbmlmaWNhbmNlIiwgdmFsdWVzID0gYygiTm90IHNpZ25pZmljYW50IiA9ICJncmV5OTAiLCAiVG9wIDI1JSIgPSAiI0YyOEUyQiIsICJUb3AgMTAlIiA9ICIjRTE1NzU5IikpICsKICAgIGdncGxvdDI6OmNvb3JkX2NhcnRlc2lhbigKICAgICAgeGxpbSA9IGMoeF9yYW5nZVsxXSAtIHhfZXhwYW5zaW9uLCB4X3JhbmdlWzJdICsgeF9leHBhbnNpb24pLAogICAgICB5bGltID0gYyh5X3JhbmdlWzFdIC0geV9leHBhbnNpb24sIHlfcmFuZ2VbMl0gKyB5X2V4cGFuc2lvbiksCiAgICAgIGV4cGFuZCA9IEZBTFNFCiAgICApICsKICAgIGdncGxvdDI6OmxhYnMoCiAgICAgIHRpdGxlID0gcGFzdGUoIkJyYW5jaCBBbmFseXNpcyBpbiIsIHRyYWplY3Rvcnlfa2V5KSwKICAgICAgc3VidGl0bGUgPSBzcHJpbnRmKCJGb2N1c2luZyBvbjogJXMgYXQgcHNldWRvdGltZSAlLjJmXG5XaW5kb3c6IMKxJS4yZiAoJWQgdHJhamVjdG9yeSBzYW1wbGVzKSIsIGJyYW5jaF9uYW1lLCBicmFuY2hfdGltZSwgdHJhbnNpdGlvbl93aW5kb3csIHN1bShpbl9icmFuY2gpKSwKICAgICAgeCA9IGV4cHJlc3Npb24oYm9sZCgiTG9nIlsyXSoiIE1lYW4gRm9sZCBDaGFuZ2UiKSksCiAgICAgIHkgPSBleHByZXNzaW9uKGJvbGQoIkxvZyJbMl0qIiBWYXJpYW5jZSBGb2xkIENoYW5nZSIpKSwKICAgICAgY2FwdGlvbiA9IGlmZWxzZShsYWJlbF90b3BfbiA9PSAiYWxsIiwgIkFsbCBjZWxsIHR5cGVzIGxhYmVsZWQiLCBwYXN0ZSgiVG9wIiwgbGFiZWxfdG9wX24sICJtb3N0IHNpZ25pZmljYW50IGNlbGwgdHlwZXMgbGFiZWxlZCIpKQogICAgKSArCiAgICBnZ3Bsb3QyOjp0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IGJhc2Vfc2l6ZSkgKwogICAgZ2dwbG90Mjo6dGhlbWUoCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICAgIGxlZ2VuZC5ib3ggPSAidmVydGljYWwiLAogICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGxpbmV3aWR0aCA9IDAuMiksCiAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvciA9ICJibGFjayIsIGZpbGwgPSBOQSwgbGluZXdpZHRoID0gMC41KSwgCiAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE2KSwKICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJncmV5NDAiLCBzaXplID0gMTIpLAogICAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgYXNwZWN0LnJhdGlvID0gMC42CiAgICApCgogIGF0dHIocCwgInRyYW5zaXRpb25fd2luZG93IikgPC0gdHJhbnNpdGlvbl93aW5kb3cKICBhdHRyKHAsICJicmFuY2hfdGltZSIpIDwtIGJyYW5jaF90aW1lCgogIHJldHVybihsaXN0KHBsb3QgPSBwLCBkYXRhID0gcGxvdF9kYXRhKSkKfQoKYW5hbHlzaXNfcGxhbiA8LSBsaXN0KAogIGxpc3QodHJhamVjdG9yeV9rZXkgPSAic2V4dWFsIiwgIGJyYW5jaF9uYW1lID0gIkJyYW5jaF8yIiksCiAgbGlzdCh0cmFqZWN0b3J5X2tleSA9ICJhc2V4dWFsIiwgYnJhbmNoX25hbWUgPSAiQnJhbmNoXzEiKSwKICBsaXN0KHRyYWplY3Rvcnlfa2V5ID0gImVhcmx5X2RldiIsIGJyYW5jaF9uYW1lID0gIlByZWJyYW5jaF8yIikKKQoKcmVzdWx0c19saXN0IDwtIHB1cnJyOjptYXAoYW5hbHlzaXNfcGxhbiwgZnVuY3Rpb24ocGxhbikgewogIG1lc3NhZ2UoIlxuUHJvY2Vzc2luZzogIiwgcGxhbiR0cmFqZWN0b3J5X2tleSwgIiAtICIsIHBsYW4kYnJhbmNoX25hbWUpCiAgcGxvdF9icmFuY2hwb2ludF9pbl90cmFqZWN0b3J5KAogICAgdHJhamVjdG9yeV9rZXkgPSBwbGFuJHRyYWplY3Rvcnlfa2V5LAogICAgYnJhbmNoX25hbWUgPSBwbGFuJGJyYW5jaF9uYW1lLAogICAgbGFiZWxfdG9wX24gPSAiYWxsIgogICkKfSkKCm5hbWVzKHJlc3VsdHNfbGlzdCkgPC0gcHVycnI6Om1hcF9jaHIoYW5hbHlzaXNfcGxhbiwgfnBhc3RlMCgueCR0cmFqZWN0b3J5X2tleSwgIl8iLCAueCRicmFuY2hfbmFtZSkpCnBsb3RzIDwtIHB1cnJyOjptYXAocmVzdWx0c19saXN0LCAicGxvdCIpCnBsb3RfZGF0YV9saXN0IDwtIHB1cnJyOjptYXAocmVzdWx0c19saXN0LCAiZGF0YSIpCgppZiAoIWRpci5leGlzdHMoImNvbWJpbmVkX2FuYWx5c2lzX291dHB1dCIpKSBkaXIuY3JlYXRlKCJjb21iaW5lZF9hbmFseXNpc19vdXRwdXQiKQoKIyBTYXZlIFBOR3MsIEpQR3MsIENTVnMKcHVycnI6OndhbGsyKG5hbWVzKHBsb3RzKSwgcGxvdHMsIGZ1bmN0aW9uKG5hbWUsIHBsb3QpIHsKICBnZ3NhdmUoZmlsZS5wYXRoKCJjb21iaW5lZF9hbmFseXNpc19vdXRwdXQiLCBwYXN0ZTAobmFtZSwgIl9icmFuY2hfYW5hbHlzaXMucG5nIikpLCBwbG90LCB3aWR0aCA9IDE4LCBoZWlnaHQgPSAxMCwgZHBpID0gMzAwKQogIGdnc2F2ZShmaWxlLnBhdGgoImNvbWJpbmVkX2FuYWx5c2lzX291dHB1dCIsIHBhc3RlMChuYW1lLCAiX2JyYW5jaF9hbmFseXNpcy5qcGciKSksIHBsb3QsIHdpZHRoID0gMTgsIGhlaWdodCA9IDEwLCBkcGkgPSAzMDApCn0pCgpwdXJycjo6d2FsazIobmFtZXMocGxvdF9kYXRhX2xpc3QpLCBwbG90X2RhdGFfbGlzdCwgZnVuY3Rpb24obmFtZSwgZGYpIHsKICB3cml0ZS5jc3YoZGYsIGZpbGUgPSBmaWxlLnBhdGgoImNvbWJpbmVkX2FuYWx5c2lzX291dHB1dCIsIHBhc3RlMChuYW1lLCAiX3Bsb3RfZGF0YS5jc3YiKSksIHJvdy5uYW1lcyA9IEZBTFNFKQp9KQoKCgojIENyZWF0ZSBhbmQgd3JpdGUgZGlhZ25vc3RpYyBzdW1tYXJ5IHRvIGEgdGV4dCBmaWxlCmRpYWdfZmlsZSA8LSBmaWxlLnBhdGgoImNvbWJpbmVkX2FuYWx5c2lzX291dHB1dCIsICJicmFuY2hfYW5hbHlzaXNfZGlhZ25vc3RpY3MudHh0IikKZGlhZ19jb24gPC0gZmlsZShkaWFnX2ZpbGUsIG9wZW4gPSAid3QiKQoKd3JpdGVMaW5lcygiPT09IERpYWdub3N0aWMgU3VtbWFyeSA9PT0iLCBkaWFnX2NvbikKCmZvciAoaSBpbiBzZXFfYWxvbmcoYW5hbHlzaXNfcGxhbikpIHsKICBwbGFuIDwtIGFuYWx5c2lzX3BsYW5bW2ldXQogIGN1cnJlbnRfcGxvdCA8LSBwbG90c1tbbmFtZXMocGxvdHMpW2ldXV0KCiAgIyBSZXRyaWV2ZSBhdHRyaWJ1dGVzIGZyb20gdGhlIHBsb3Qgb2JqZWN0CiAgYnJhbmNoX3RpbWVfdmFsIDwtIGF0dHIoY3VycmVudF9wbG90LCAiYnJhbmNoX3RpbWUiKQogIHRyYW5zaXRpb25fd2luZG93X3ZhbCA8LSBhdHRyKGN1cnJlbnRfcGxvdCwgInRyYW5zaXRpb25fd2luZG93IikKCiAgIyBHZXQgdHJhamVjdG9yeSBjbHVzdGVycwogIGNsdXN0ZXJzX2luX3RyYWogPC0gdHJhamVjdG9yaWVzW1twbGFuJHRyYWplY3Rvcnlfa2V5XV0kYnJhbmNoZXMKICBpbl90cmFqX2xvZ2ljYWxfYWxsX2NvbGRhdCA8LSBjb2xkYXQkY2x1c3RlciAlaW4lIGNsdXN0ZXJzX2luX3RyYWoKCiAgIyBHbG9iYWwgd2luZG93IGFyb3VuZCBwc2V1ZG90aW1lCiAgaW5fcHNldWRvdGltZV93aW5kb3dfYWxsX2NvbGRhdCA8LSBkcGx5cjo6YmV0d2VlbigKICAgIGNvbGRhdCRwc2V1ZG9zaXplX3BjYSwKICAgIGJyYW5jaF90aW1lX3ZhbCAtIHRyYW5zaXRpb25fd2luZG93X3ZhbCwKICAgIGJyYW5jaF90aW1lX3ZhbCArIHRyYW5zaXRpb25fd2luZG93X3ZhbAogICkKCiAgIyBDZWxscyBpbiBib3RoIHdpbmRvdyBhbmQgdHJhamVjdG9yeQogIGNlbGxzX2luX3dpbmRvd19hbmRfdHJhamVjdG9yeSA8LSBzdW0oaW5fdHJhal9sb2dpY2FsX2FsbF9jb2xkYXQgJiBpbl9wc2V1ZG90aW1lX3dpbmRvd19hbGxfY29sZGF0KQoKICAjIFdyaXRlIGRpYWdub3N0aWNzCiAgd3JpdGVMaW5lcyhzcHJpbnRmKCJcbkFuYWx5c2lzOiAlc18lcyIsIHBsYW4kdHJhamVjdG9yeV9rZXksIHBsYW4kYnJhbmNoX25hbWUpLCBkaWFnX2NvbikKICB3cml0ZUxpbmVzKHNwcmludGYoIiAgQnJhbmNoIHRpbWU6ICUuM2YiLCBicmFuY2hfdGltZV92YWwpLCBkaWFnX2NvbikKICB3cml0ZUxpbmVzKHNwcmludGYoIiAgUHNldWRvdGltZSB3aW5kb3c6IMKxJS4zZiIsIHRyYW5zaXRpb25fd2luZG93X3ZhbCksIGRpYWdfY29uKQogIHdyaXRlTGluZXMoc3ByaW50ZigiICBDZWxscyBpbiB0cmFqZWN0b3J5OiAlZCIsIHN1bShpbl90cmFqX2xvZ2ljYWxfYWxsX2NvbGRhdCkpLCBkaWFnX2NvbikKICB3cml0ZUxpbmVzKHNwcmludGYoIiAgQ2VsbHMgaW4gcHNldWRvdGltZSB3aW5kb3cgKGdsb2JhbCk6ICVkIiwgc3VtKGluX3BzZXVkb3RpbWVfd2luZG93X2FsbF9jb2xkYXQpKSwgZGlhZ19jb24pCiAgd3JpdGVMaW5lcyhzcHJpbnRmKCIgIENlbGxzIGluIGJvdGggdHJhamVjdG9yeSAmIHdpbmRvdzogJWQiLCBjZWxsc19pbl93aW5kb3dfYW5kX3RyYWplY3RvcnkpLCBkaWFnX2NvbikKCiAgIyBTcGVjaWFsIGRpYWdub3N0aWNzIGZvciAic2V4dWFsIiBvbmx5CiAgaWYgKHBsYW4kdHJhamVjdG9yeV9rZXkgPT0gInNleHVhbCIpIHsKICAgIGlzX2luX3NleHVhbF90cmFqZWN0b3J5IDwtIGNvbGRhdCRjbHVzdGVyICVpbiUgY2x1c3RlcnNfaW5fdHJhagogICAgaXNfaW5fcHNldWRvdGltZV93aW5kb3cgPC0gaW5fcHNldWRvdGltZV93aW5kb3dfYWxsX2NvbGRhdAoKICAgIG91dHNpZGVfY2VsbHNfaWR4IDwtIHdoaWNoKGlzX2luX3BzZXVkb3RpbWVfd2luZG93ICYgIWlzX2luX3NleHVhbF90cmFqZWN0b3J5KQoKICAgIHdyaXRlTGluZXMoIiAgLS0tIENlbGxzIGluIHdpbmRvdyBidXQgTk9UIGluICdzZXh1YWwnIHRyYWplY3RvcnkgLS0tIiwgZGlhZ19jb24pCiAgICB3cml0ZUxpbmVzKHNwcmludGYoIiAgQ291bnQ6ICVkIiwgbGVuZ3RoKG91dHNpZGVfY2VsbHNfaWR4KSksIGRpYWdfY29uKQoKICAgIGlmIChsZW5ndGgob3V0c2lkZV9jZWxsc19pZHgpID4gMCkgewogICAgICBjbHVzdGVyX2NvdW50cyA8LSB0YWJsZShjb2xkYXQkY2x1c3RlcltvdXRzaWRlX2NlbGxzX2lkeF0pCiAgICAgIGNsdXN0ZXJfbGluZXMgPC0gY2FwdHVyZS5vdXRwdXQocHJpbnQoY2x1c3Rlcl9jb3VudHMpKQogICAgICB3cml0ZUxpbmVzKHBhc3RlMCgiICAgICIsIGNsdXN0ZXJfbGluZXMpLCBkaWFnX2NvbikKICAgIH0gZWxzZSB7CiAgICAgIHdyaXRlTGluZXMoIiAgICBOb25lIiwgZGlhZ19jb24pCiAgICB9CgogICAgd3JpdGVMaW5lcygiICAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0iLCBkaWFnX2NvbikKICB9Cn0KCmNsb3NlKGRpYWdfY29uKQojbWVzc2FnZSgiRGlhZ25vc3RpY3Mgc2F2ZWQgdG8gIiwgZGlhZ19maWxlKQoKCgprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiY29tYmluZWRfYW5hbHlzaXNfb3V0cHV0L3NleHVhbF9CcmFuY2hfMl9icmFuY2hfYW5hbHlzaXMuanBnIikKa25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImNvbWJpbmVkX2FuYWx5c2lzX291dHB1dC9hc2V4dWFsX0JyYW5jaF8xX2JyYW5jaF9hbmFseXNpcy5qcGciKQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiY29tYmluZWRfYW5hbHlzaXNfb3V0cHV0L2Vhcmx5X2Rldl9QcmVicmFuY2hfMl9icmFuY2hfYW5hbHlzaXMuanBnIikKYGBgCgojIyMgNi4gQ292YXJpYXRpb24gRGVjb21wb3NpdGlvbiB1c2luZyBQb2lzc29uIExvZ25vcm1hbCBNb2RlbHMKCkluIHRoaXMgc3R1ZHksIHRoZSBwc2V1ZG90aW1lIHZhcmlhYmxlIChwc2V1ZG9zaXplX3BjYSksaW5mZXJyZWQgZnJvbSAzRCBQQ0EgZW1iZWRkaW5ncyBvZiBzaW5nbGUtY2VsbCBwcm9maWxlcywgc2VydmVzIGFzIGEgcHJveHkgZm9yIHdvcm0gbGVuZ3RoIG9yIGRldmVsb3BtZW50YWwgc2l6ZS4gU2luY2UgX1AuIG1vcmdhbmlfIGV4aGliaXRzIGluZGV0ZXJtaW5hdGUgZ3Jvd3RoIGFuZCBjb250aW51b3VzIGRldmVsb3BtZW50LCB0aGUgcG9zaXRpb24gb2YgYSB3b3JtIGFsb25nIHRoZSBwc2V1ZG90aW1lIGF4aXMgcm91Z2hseSByZWZsZWN0cyBpdHMgbW9ycGhvbG9naWNhbCBhbmQgY2VsbHVsYXIgY29tcGxleGl0eS4gQ29uc2VxdWVudGx5LCBpbmNyZWFzZXMgaW4gcHNldWRvdGltZSBvZnRlbiBjb3JyZWxhdGUgd2l0aCBsYXJnZXIgd29ybSBzaXplLCBoaWdoZXIgdG90YWwgY2VsbCBjb3VudHMsIGFuZCBtb3JlIGRpZmZlcmVudGlhdGVkIHRpc3N1ZSBzdGF0ZXMuCgpUaGlzIGluaGVyZW50IGNvdXBsaW5nIGJldHdlZW4gcHNldWRvdGltZSBhbmQgb3JnYW5pc21hbCBzaXplIHByZXNlbnRzIGEgY3JpdGljYWwgY29uZm91bmQgaW4gY292YXJpYW5jZS1iYXNlZCBhbmFseXNlcyBvZiBjZWxsIHR5cGUgYWJ1bmRhbmNlLiBNYW55IGNlbGwgcG9wdWxhdGlvbnMgaW5jcmVhc2UgaW4gYWJzb2x1dGUgbnVtYmVyIGFzIGEgZnVuY3Rpb24gb2Ygb3ZlcmFsbCB3b3JtIHNpemUsIGxlYWRpbmcgdG8gc3B1cmlvdXMgY29ycmVsYXRpb25zIHRoYXQgcmVmbGVjdCBzaGFyZWQgc2NhbGluZyByYXRoZXIgdGhhbiBmdW5jdGlvbmFsIGNvb3JkaW5hdGlvbi4gCgpUbyBkaXNlbnRhbmdsZSBzb3VyY2VzIG9mIGNlbGwgdHlwZSBjb3ZhcmlhdGlvbiBhY3Jvc3MgZGV2ZWxvcG1lbnRhbCB0cmFqZWN0b3JpZXMsIGEgUG9pc3NvbiBsb2dub3JtYWwgKFBMTikgbW9kZWxpbmcgZnJhbWV3b3JrIHdhcyBhcHBsaWVkIHRvIGRlY29tcG9zZSB0b3RhbCB2YXJpYWJpbGl0eSBpbnRvIHNpemUtZGVwZW5kZW50IGFuZCBzaXplLWluZGVwZW5kZW50IGNvbXBvbmVudHMuIENlbGwgdHlwZSBjb3VudCBtYXRyaWNlcyB3ZXJlIGZpcnN0IHRyYW5zcG9zZWQgKHNhbXBsZXMgw5cgY2VsbCB0eXBlcykgYW5kIG5vcm1hbGl6ZWQgdXNpbmcgbG9nLXRyYW5zZm9ybWVkIHRvdGFsIGNlbGwgY291bnRzIHBlciBzYW1wbGUgYXMgb2Zmc2V0cy4gQSBiYXNlbGluZSBQTE4gbW9kZWwgd2FzIHRoZW4gZml0IHRvIHRoZSBkYXRhIHRvIGVzdGltYXRlIHRoZSB0b3RhbCBsYXRlbnQgY292YXJpYW5jZSBzdHJ1Y3R1cmUgYWNyb3NzIGNlbGwgdHlwZXMuIFRoaXMgbW9kZWwgYXNzdW1lZCB0aGF0IHRoZSBvYnNlcnZlZCBjb3VudHMgJFxtYXRoYmZ7WX1faSQgZm9yIHNhbXBsZSAkaSQgZm9sbG93ZWQgYSBQb2lzc29uIGRpc3RyaWJ1dGlvbiB3aXRoIGxvZy1tZWFuIGdpdmVuIGJ5OgoKJCQKXGxvZyhcYm9sZHN5bWJvbHtcbGFtYmRhfV9pKSA9IFxib2xkc3ltYm9se1xtdX0gKyBcbG9nKFxtYXRoYmZ7b31faSkgKyBcbWF0aGJme3V9X2ksIFxxdWFkIFxtYXRoYmZ7dX1faSBcc2ltIFxtYXRoY2Fse059KDAsIFxTaWdtYV97XHRleHR7dG90YWx9fSkKJCQKCndoZXJlICRcYm9sZHN5bWJvbHtcbXV9JCBpcyB0aGUgZ2xvYmFsIG1lYW4gYWJ1bmRhbmNlIHZlY3RvciwgJFxsb2coXG1hdGhiZntvfV9pKSQgZGVub3RlcyB0aGUgbG9nLW9mZnNldCBmb3Igc2FtcGxlIGxpYnJhcnkgc2l6ZSwgYW5kICRcU2lnbWFfe1x0ZXh0e3RvdGFsfX0kIGNhcHR1cmVzIHN0cnVjdHVyZWQgY292YXJpYXRpb24gYW1vbmcgY2VsbCB0eXBlcy4gCgpUbyBpc29sYXRlIGNvdmFyaWF0aW9uIHNwZWNpZmljYWxseSBhc3NvY2lhdGVkIHdpdGggZGV2ZWxvcG1lbnRhbCBwcm9ncmVzc2lvbiwgYSBzZWNvbmQgUExOIG1vZGVsIGluY29ycG9yYXRlZCB0aGUgcHNldWRvdGltZSBjb29yZGluYXRlIChgcHNldWRvc2l6ZV9wY2FgKSBhcyBhIHNtb290aCBjb3ZhcmlhdGUgdXNpbmcgYSBuYXR1cmFsIHNwbGluZSBiYXNpcyB3aXRoIHRocmVlIGRlZ3JlZXMgb2YgZnJlZWRvbToKCiQkClxsb2coXGJvbGRzeW1ib2x7XGxhbWJkYX1faSkgPSBcbWF0aGJme0J9IFxjZG90IFx0ZXh0e25zfShcdGV4dHtwc2V1ZG9zaXplfV9pLCBkZj0zKSArIFxsb2coXG1hdGhiZntvfV9pKSArIFxtYXRoYmZ7dX1faSwgXHF1YWQgXG1hdGhiZnt1fV9pIFxzaW0gXG1hdGhjYWx7Tn0oMCwgXFNpZ21hX3tcdGV4dHtpbmRlcH19KQokJAoKSW4gdGhpcyBmb3JtdWxhdGlvbiwgY292YXJpYXRpb24gZHJpdmVuIGJ5IHBzZXVkb3RpbWUgd2FzIGNhcHR1cmVkIGluIHRoZSBjb3ZhcmlhbmNlIG9mIHRoZSBtb2RlbOKAmXMgZml0dGVkIHZhbHVlcyAoc2l6ZS1kZXBlbmRlbnQgY29tcG9uZW50KSwgd2hpbGUgdGhlIHJlc2lkdWFsIGNvdmFyaWFuY2UgJFxTaWdtYV97XHRleHR7aW5kZXB9fSQgcmVwcmVzZW50ZWQgc2l6ZS1pbmRlcGVuZGVudCBzdHJ1Y3R1cmUuIENvcnJlbGF0aW9uIG1hdHJpY2VzIGNvcnJlc3BvbmRpbmcgdG8gdGhlIHRvdGFsLCBzaXplLWRlcGVuZGVudCwgYW5kIHNpemUtaW5kZXBlbmRlbnQgY292YXJpYW5jZXMgd2VyZSB2aXN1YWxpemVkIGFzIGNsdXN0ZXJlZCBoZWF0bWFwcywgcmV2ZWFsaW5nIGRpc3RpbmN0IG1vZHVsZXMgb2YgY28tdmFyeWluZyBjZWxsIHR5cGVzLgoKTm90YWJseSwgdGhlIGRlbmRyb2dyYW0gZGVyaXZlZCBmcm9tIHRoZSBzaXplLWluZGVwZW5kZW50IGNvcnJlbGF0aW9uIG1hdHJpeCBpZGVudGlmaWVkIGNsdXN0ZXJzIHRoYXQgY29ycmVzcG9uZGVkIHByZWNpc2VseSB0byBjZWxsIHR5cGVzIHByZXZpb3VzbHkgaW1wbGljYXRlZCBhcyBrZXkgZHJpdmVycyBvZiB0aGUgc2V4dWFsIGFuZCBhc2V4dWFsIHRyYWplY3RvcmllcyBpbiB0aGUgYWJ1bmRhbmNlIGFuZCBjb21iaW5lZCBhbmFseXNlcy4gVGhpcyBjb252ZXJnZW5jZSBhY3Jvc3MgaW5kZXBlbmRlbnQgYW5hbHl0aWNhbCBmcmFtZXdvcmtzIHN1cHBvcnRzIHRoZSBwcmVzZW5jZSBvZiBiaW9sb2dpY2FsbHkgbWVhbmluZ2Z1bCBtb2R1bGVzIG9mIGNvLXJlZ3VsYXRlZCBjZWxsIHR5cGVzIHRoYXQgZXhoaWJpdCBjb29yZGluYXRlZCBmbHVjdHVhdGlvbnMgYmV5b25kIGdsb2JhbCBkZXZlbG9wbWVudGFsIHNjYWxpbmcgZWZmZWN0cy4gVGhlIFBMTi1iYXNlZCBkZWNvbXBvc2l0aW9uIHRodXMgcHJvdmlkZWQgYSBwcmluY2lwbGVkIG1lYW5zIHRvIHNlcGFyYXRlIGdsb2JhbCBwc2V1ZG90aW1lIGVmZmVjdHMgZnJvbSBpbnRyaW5zaWMgcmVndWxhdG9yeSBhc3NvY2lhdGlvbnMgYW1vbmcgY2VsbCB0eXBlcywgb2ZmZXJpbmcgbmV3IGluc2lnaHQgaW50byB0aGUgb3JnYW5pemF0aW9uIG9mIGNlbGwgZmF0ZSBwcm9ncmFtcy4KCgpgYGB7ciBjb3ZhcmlhbmNlIG1hdHJpeCBmaW5hbCwgaW5jbHVkZT1GQUxTRX0KCmxpYnJhcnkoUExObW9kZWxzKQpsaWJyYXJ5KGhvb2tlKSAKbGlicmFyeShzcGxpbmVzKQpsaWJyYXJ5KHBoZWF0bWFwKQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShnZ3Bsb3QyKQoKIyBQcmVwYXJlIGRhdGEKZXhwX21hdHJpeCA8LSBhcy5tYXRyaXgoZXhwcnMoY2RzKSkKZXhwX21hdHJpeF90IDwtIHQoZXhwX21hdHJpeCkgICMgU2FtcGxlcyDDlyBDZWxsVHlwZXMKCiMgR2V0IHNpemUgdmFyaWFibGUgKHVzaW5nIHBzZXVkb3NpemVfcGNhIGFzIHNwZWNpZmllZCkKc2l6ZV92YXIgPC0gcERhdGEoY2RzKSRwc2V1ZG9zaXplX3BjYQpsb2dfb2Zmc2V0cyA8LSBsb2cocm93U3VtcyhleHBfbWF0cml4X3QpKSAgIyBMaWJyYXJ5IHNpemUgb2Zmc2V0cwoKIyBGaXQgYmFzaWMgUExOIG1vZGVsICh0b3RhbCBjb3ZhcmlhdGlvbikKcGxuX3RvdGFsIDwtIFBMTihleHBfbWF0cml4X3QgfiAxICsgb2Zmc2V0KGxvZ19vZmZzZXRzKSkKCiMgRml0IHNpemUtYWRqdXN0ZWQgbW9kZWwgdXNpbmcgaG9va2UncyBhcHByb2FjaAojIENyZWF0ZSBkZXNpZ24gbWF0cml4IGZvciBzaXplIGVmZmVjdHMKWF9zaXplIDwtIG1vZGVsLm1hdHJpeCh+IG5zKHNpemVfdmFyLCBkZiA9IDMpKSAKCiMgRml0IFBMTiB3aXRoIHNpemUgY292YXJpYXRlcwpwbG5fc2l6ZSA8LSBQTE4oZXhwX21hdHJpeF90IH4gWF9zaXplICsgb2Zmc2V0KGxvZ19vZmZzZXRzKSAtIDEpCgojIEV4dHJhY3QgY292YXJpYW5jZSBjb21wb25lbnRzCiMgVG90YWwgY292YXJpYW5jZQp0b3RhbF9jb3YgPC0gcGxuX3RvdGFsJG1vZGVsX3BhciRTaWdtYQoKIyBTaXplLWRlcGVuZGVudCBjb3ZhcmlhbmNlIChjb3ZhcmlhbmNlIG9mIGZpdHRlZCB2YWx1ZXMpCnNpemVfZGVwX2NvdiA8LSBjb3YoZml0dGVkKHBsbl9zaXplKSkKCiMgU2l6ZS1pbmRlcGVuZGVudCBjb3ZhcmlhbmNlIChyZXNpZHVhbCBjb3ZhcmlhbmNlKQpzaXplX2luZGVwX2NvdiA8LSBwbG5fc2l6ZSRtb2RlbF9wYXIkU2lnbWEKCiMgQ29udmVydCB0byBjb3JyZWxhdGlvbiBtYXRyaWNlcwp0b3RhbF9jb3IgPC0gY292MmNvcih0b3RhbF9jb3YpCnNpemVfZGVwX2NvciA8LSBjb3YyY29yKHNpemVfZGVwX2NvdikKc2l6ZV9pbmRlcF9jb3IgPC0gY292MmNvcihzaXplX2luZGVwX2NvdikKCgoKIyBWaXN1YWxpemF0aW9uCnBsb3RfaGVhdG1hcCA8LSBmdW5jdGlvbihjb3JfbWF0LCB0aXRsZSkgewogICMgU2V0IGxhcmdlciBvdmVyYWxsIGRpbWVuc2lvbnMKICBwaGVhdG1hcChjb3JfbWF0LAogICAgICAgICAgIGNvbG9yID0gY29sb3JSYW1wUGFsZXR0ZShjKCJibHVlIiwgIndoaXRlIiwgInJlZCIpKSgxMDApLAogICAgICAgICAgIGNsdXN0ZXJpbmdfbWV0aG9kID0gIndhcmQuRDIiLAogICAgICAgICAgIG1haW4gPSB0aXRsZSwKICAgICAgICAgICAKICAgICAgICAgICAjIENyaXRpY2FsIHNpemluZyBwYXJhbWV0ZXJzOgogICAgICAgICAgIGZvbnRzaXplID0gMTEsICAgICAgICAgICAgICAgICAgICMgQmFzZSBmb250IHNpemUKICAgICAgICAgICBmb250c2l6ZV9yb3cgPSA4LCAgICAgICAgICAgICAgICMgUm93IGxhYmVsIHNpemUKICAgICAgICAgICBmb250c2l6ZV9jb2wgPSA4LCAgICAgICAgICAgICAgICMgQ29sdW1uIGxhYmVsIHNpemUKICAgICAgICAgICBjZWxsd2lkdGggPSAxMiwgICAgICAgICAgICAgICAgICAjIENlbGwgd2lkdGggKHBpeGVscykKICAgICAgICAgICBjZWxsaGVpZ2h0ID0gMTIsICAgICAgICAgICAgICAgICAjIENlbGwgaGVpZ2h0IChwaXhlbHMpCiAgICAgICAgICAgdHJlZWhlaWdodF9yb3cgPSAxMDAsICAgICAgICAgICAgIyBEZW5kcm9ncmFtIGhlaWdodAogICAgICAgICAgIHRyZWVoZWlnaHRfY29sID0gMTAwLCAgICAgICAgICAgICMgRGVuZHJvZ3JhbSB3aWR0aAogICAgICAgICAgIG1hcmdpbnMgPSBjKDIwLCAyMCwgMjAsIDIwKSwgICAgICAgICAgICAgIyBCb3R0b20vcmlnaHQgbWFyZ2lucwogICAgICAgICAgIAogICAgICAgICAgICMgQW50aS1vdmVybGFwIG1lYXN1cmVzOgogICAgICAgICAgIHNob3dfcm93bmFtZXMgPSBUUlVFLCAgICAgICAgICAgICMgRm9yY2Ugcm93IGxhYmVscwogICAgICAgICAgIHNob3dfY29sbmFtZXMgPSBUUlVFLCAgICAgICAgICAgICMgRm9yY2UgY29sdW1uIGxhYmVscwogICAgICAgICAgIGFuZ2xlX2NvbCA9IDQ1LCAgICAgICAgICAgICAgICAgICMgQW5nbGVkIGNvbHVtbiBsYWJlbHMKICAgICAgICAgICBkaXNwbGF5X251bWJlcnMgPSBGQUxTRSwgICAgICAgICAjIFJlbW92ZSBudW1iZXJzIGlmIGNyb3dkZWQKICAgICAgICAgICBib3JkZXJfY29sb3IgPSBOQSAgICAgICAgICAgICAgICAjIE5vIGdyaWQgbGluZXMgYmV0d2VlbiBjZWxscwogICkKfQoKCiMgV3JhcHBlciBmdW5jdGlvbiB0byBzYXZlIFBORwpzYXZlX2hlYXRtYXAgPC0gZnVuY3Rpb24oY29yX21hdCwgdGl0bGUsIGZpbGVuYW1lLCBvdXRkaXIgPSAiY292YXJpYW5jZV9vdXRwdXQiLAogICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGggPSAzNjAwLCBoZWlnaHQgPSAzNjAwLCByZXMgPSAzMDApIHsKICBpZiAoIWRpci5leGlzdHMob3V0ZGlyKSkgZGlyLmNyZWF0ZShvdXRkaXIpCiAgZmlsZXBhdGggPC0gZmlsZS5wYXRoKG91dGRpciwgZmlsZW5hbWUpCiAgcG5nKGZpbGVwYXRoLCB3aWR0aCA9IHdpZHRoLCBoZWlnaHQgPSBoZWlnaHQsIHJlcyA9IHJlcykKICBwbG90X2hlYXRtYXAoY29yX21hdCwgdGl0bGUpCiAgZGV2Lm9mZigpCn0KCnNhdmVfaGVhdG1hcCh0b3RhbF9jb3IsICJUb3RhbCBDZWxsIFR5cGUgQ292YXJpYXRpb24iLCAiaGVhdG1hcF90b3RhbF9jb3IucG5nIikKc2F2ZV9oZWF0bWFwKHNpemVfZGVwX2NvciwgIlNpemUtRGVwZW5kZW50IENvdmFyaWF0aW9uIiwgImhlYXRtYXBfc2l6ZV9kZXBfY29yLnBuZyIpCnNhdmVfaGVhdG1hcChzaXplX2luZGVwX2NvciwgIlNpemUtSW5kZXBlbmRlbnQgQ292YXJpYXRpb24iLCAiaGVhdG1hcF9zaXplX2luZGVwX2Nvci5wbmciKQoKIyAjIEdlbmVyYXRlIHBsb3RzCnBfc2l6ZV9pbmRlcCA8LSBwbG90X2hlYXRtYXAoc2l6ZV9pbmRlcF9jb3IsICJTaXplLUluZGVwZW5kZW50IENvdmFyaWF0aW9uIikKCgojIEFycmFuZ2UgcGxvdHMKI2dyaWQuYXJyYW5nZShwX3RvdGFsJGd0YWJsZSwgcF9zaXplX2RlcCRndGFibGUsIHBfc2l6ZV9pbmRlcCRndGFibGUsIG5jb2wgPSAzKQoKCnJvd19kZW5kIDwtIGFzLmRlbmRyb2dyYW0ocF9zaXplX2luZGVwJHRyZWVfcm93KQoKIyBQbG90IGp1c3QgdGhlIHJvdyBkZW5kcm9ncmFtCnBsb3Qocm93X2RlbmQsCiAgICAgbWFpbiA9ICJSb3cgRGVuZHJvZ3JhbSAoU2l6ZS1JbmRlcGVuZGVudCBDb3ZhcmlhdGlvbikiLAogICAgIHhsYWIgPSAiU2FtcGxlcyIsCiAgICAgeWxhYiA9ICJIZWlnaHQiLAogICAgIGhvcml6ID0gRkFMU0UpCgpsaWJyYXJ5KGRlbmRleHRlbmQpICAjIEZvciBhZHZhbmNlZCBkZW5kcm9ncmFtIGN1c3RvbWl6YXRpb24KCiMgQ29udmVydCB0byBhIGVuaGFuY2VkIGRlbmRyb2dyYW0gb2JqZWN0CnJvd19kZW5kIDwtIHJvd19kZW5kICU+JQogIHNldCgiYnJhbmNoZXNfa19jb2xvciIsIGsgPSAzKSAlPiUgICMgQ29sb3IgYnJhbmNoZXMgYnkgMyBjbHVzdGVycwogIHNldCgiYnJhbmNoZXNfbHdkIiwgMS41KSAgICAgICAgICAgICMgVGhpY2tlciBicmFuY2hlcwoKaWYgKCFkaXIuZXhpc3RzKCJjb3ZhcmlhbmNlX291dHB1dCIpKSBkaXIuY3JlYXRlKCJjb3ZhcmlhbmNlX291dHB1dCIpCgpwbmcoImNvdmFyaWFuY2Vfb3V0cHV0L2RlbmRyb2dyYW0ucG5nIiwgd2lkdGggPSAzMDAwLCBoZWlnaHQgPSAxNTAwLCByZXMgPSAzMDApCiMgUGxvdCB3aXRoIGxhYmVscwpwbG90KHJvd19kZW5kLAogICAgIG5vZGVQYXIgPSBsaXN0KGxhYi5jZXggPSAwLjgsIHBjaCA9IE5BKSwgICMgQWRqdXN0IGxhYmVsIHNpemUKICAgICBsZWFmbGFiID0gInBlcnBlbmRpY3VsYXIiKSAgICAgICAgICAgICAgICAjIFZlcnRpY2FsIGxlYWYgbGFiZWxzCgpgYGAKCmBgYHtyIGNvdmFyaWFuY2UgcGxvdHN9Cgprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiY292YXJpYW5jZV9vdXRwdXQvaGVhdG1hcF90b3RhbF9jb3IucG5nIikKa25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImNvdmFyaWFuY2Vfb3V0cHV0L2hlYXRtYXBfc2l6ZV9kZXBfY29yLnBuZyIpCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJjb3ZhcmlhbmNlX291dHB1dC9oZWF0bWFwX3NpemVfaW5kZXBfY29yLnBuZyIpCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJjb3ZhcmlhbmNlX291dHB1dC9kZW5kcm9ncmFtLnBuZyIpCgpgYGAKCiMjIyA3LiBDb25jbHVzaW9uCgpUaGlzIHN0dWR5IGVzdGFibGlzaGVzIGEgcm9idXN0IGFuZCBnZW5lcmFsaXphYmxlIGFuYWx5dGljYWwgZnJhbWV3b3JrIGZvciBpbnZlc3RpZ2F0aW5nIHRoZSBjZWxsdWxhciBkeW5hbWljcyB1bmRlcmx5aW5nIGRldmVsb3BtZW50YWwgYmlmdXJjYXRpb25zIGluIF9QaGFnb2NhdGEgbW9yZ2FuaV8uIEJ5IGxldmVyYWdpbmcgYSBtZXRpY3Vsb3VzbHkgZ2VuZXJhdGVkLCBoaWdoLXJlc29sdXRpb24gc2luZ2xlLWNlbGwgc2l6ZSBhdGxhcyBhbmQgdXRpbGl6aW5nIG1vcnBob2xvZ2ljYWwgc2l6ZSBhcyBhIHByb3h5IGZvciBwc2V1ZG90aW1lLCB0aGlzIGZyYW1ld29yayBwcm92aWRlcyBhIG11bHRpZGltZW5zaW9uYWwgcGVyc3BlY3RpdmUgb24gcmVwcm9kdWN0aXZlIGZhdGUgY29tbWl0bWVudCBpbiBhbiBvcmdhbmlzbSBleGhpYml0aW5nIGluZGV0ZXJtaW5hdGUgZ3Jvd3RoLgoJClRoZSBhcHByb2FjaCBpbnRlZ3JhdGVzIG11bHRpcGxlIGNvbXBsZW1lbnRhcnkgc3RhdGlzdGljYWwgc3RyYXRlZ2llczogbmVnYXRpdmUgYW5kIGJldGEtYmlub21pYWwgcmVncmVzc2lvbiBtb2RlbHMgZWZmZWN0aXZlbHkgY2FwdHVyZSBub25saW5lYXIgYWJ1bmRhbmNlIGFuZCBjb21wb3NpdGlvbmFsIGR5bmFtaWNzIGFjcm9zcyBwc2V1ZG90aW1lLCB3aGlsZSBQb2lzc29uIGxvZ25vcm1hbCAoUExOKSBtb2RlbHMgZGVjb21wb3NlIGNlbGwgdHlwZSBjb3ZhcmlhdGlvbiBpbnRvIHNpemUtZGVwZW5kZW50IGFuZCBzaXplLWluZGVwZW5kZW50IGNvbXBvbmVudHMuIFRoaXMgbW9kZWxpbmcgYXJjaGl0ZWN0dXJlIGVuYWJsZXMgYSBwcmluY2lwbGVkIHNlcGFyYXRpb24gb2YgZ2xvYmFsIHNjYWxpbmcgZWZmZWN0cyBmcm9tIGludHJpbnNpYyByZWd1bGF0b3J5IGFzc29jaWF0aW9ucywgdGhlcmVieSBlbmhhbmNpbmcgdGhlIHJlc29sdXRpb24gb2YgY2VsbHVsYXIgcHJvZ3JhbXMgaW52b2x2ZWQgaW4gZGV2ZWxvcG1lbnRhbCBkZWNpc2lvbnMuCgkKU2V2ZXJhbCBrZXkgaW5zaWdodHMgZW1lcmdlIGZyb20gdGhpcyBhbmFseXNpczoKCisgVGhlIGRlbGluZWF0aW9uIG9mIGZvdXIgZGlzdGluY3QgY2VsbHVsYXIgc3RhdGVzLCBpbmNsdWRpbmcgdGhlIGlkZW50aWZpY2F0aW9uIG9mIGEgdHJhbnNpdGlvbmFsIOKAnHByZS1jb21taXRtZW504oCdIHBoYXNlIChQcmVicmFuY2hfMiksIHJlZGVmaW5lcyBlYXJseSBkZXZlbG9wbWVudGFsIHN0cnVjdHVyZSBhbmQgaGlnaGxpZ2h0cyBzaGlmdHMgaW4gY2VsbHVsYXIgY29tcG9zaXRpb24gdGhhdCBwcmVjZWRlIG92ZXJ0IHNleHVhbCBkaWZmZXJlbnRpYXRpb24uIAoJCisgTG9jYWxpemVkIGNoYW5nZXMgaW4gYm90aCBtZWFuIGFidW5kYW5jZSBhbmQgdmFyaWFiaWxpdHkgb2Ygc3BlY2lmaWMgY2VsbCB0eXBlIChwYXJ0aWN1bGFybHkgd2l0aGluIHRoZSBzZXh1YWwgdHJhamVjdG9yeSkgcmV2ZWFsIHRyYW5zaWVudCBlbnJpY2htZW50IGFuZCBpbmNyZWFzZWQgaGV0ZXJvZ2VuZWl0eSBhdCBsaW5lYWdlIGJyYW5jaCBwb2ludHMuIFRoZXNlIHBhdHRlcm5zIHN1Z2dlc3QgY3JpdGljYWwgcm9sZXMgZm9yIGVhcmx5IHByb2dlbml0b3Igc3RhdGVzIGFuZCByZWZsZWN0IHVuZGVybHlpbmcgZmF0ZSBwbGFzdGljaXR5IGFuZCBhc3luY2hyb25vdXMgY2VsbHVsYXIgdHJhbnNpdGlvbnMuCgkKKyBBIGNvbXBvc2l0ZSBhbmFseXNpcyBvZiBkaWZmZXJlbnRpYWwgYWJ1bmRhbmNlIGFuZCB2YXJpYW5jZSBpZGVudGlmaWVkIGNlbGwgdHlwZXMgc3VjaCBhcyBUZXN0ZXMsIFBhcmVuY2h5bWFsIDUsIGFuZCBTaXplLXNwZWNpZmljIDHigJMzIGFzIHByb21pbmVudCByZWd1bGF0b3JzIG9mIHRoZSBzZXh1YWwgdHJhamVjdG9yeSwgZXhoaWJpdGluZyBjb29yZGluYXRlZCBjaGFuZ2VzIGluIGFidW5kYW5jZSwgZGlzcGVyc2lvbiwgYW5kIHJlc2lkdWFsIGNvdmFyaWFuY2UuIAoJCisgQSBwYXJ0aWN1bGFybHkgbm92ZWwgY29udHJpYnV0aW9uIGZyb20gdGhlIFBMTi1iYXNlZCBkZWNvbXBvc2l0aW9uIGZ1cnRoZXIgaGlnaGxpZ2h0ZWQgdGhhdCB0aGVzZSBjZWxsIHR5cGVzIGNsdXN0ZXIgd2l0aGluIHNpemUtaW5kZXBlbmRlbnQgbW9kdWxlcyBvZiBjby1yZWd1bGF0aW9uLCB1bmRlcnNjb3JpbmcgdGhlaXIgbGlrZWx5IGZ1bmN0aW9uYWwgaW50ZXJkZXBlbmRlbmNlIGFuZCByZWd1bGF0b3J5IHNpZ25pZmljYW5jZS4KCQpUaGlzIHdvcmsgbW92ZXMgYmV5b25kIHRyYWRpdGlvbmFsIGRlc2NyaXB0aXZlIHNpbmdsZS1jZWxsIGFuYWx5c2lzIGJ5IGVtYmVkZGluZyBzdGF0aXN0aWNhbCByaWdvciBpbnRvIHBzZXVkb3RpbWUtYXdhcmUgbW9kZWxpbmcuIFRoZSBjb21iaW5hdGlvbiBvZiBkaXN0cmlidXRpb25hbCBtb2RlbGluZywgbG9jYWwgd2luZG93ZWQgY29tcGFyaXNvbnMsIGFuZCBjb3ZhcmlhbmNlIGRlY29tcG9zaXRpb24gZGVsaXZlcnMgYSBtdWx0aWZhY2V0ZWQgdW5kZXJzdGFuZGluZyBvZiBjZWxsIHN0YXRlIHRyYW5zaXRpb25zLiBDb2xsZWN0aXZlbHksIHRoZSBmaW5kaW5ncyBub3Qgb25seSBwaW5wb2ludCBjYW5kaWRhdGUgY2VsbHVsYXIgZHJpdmVycyBvZiBiaWZ1cmNhdGlvbiBidXQgYWxzbyBlc3RhYmxpc2ggYSB2ZXJzYXRpbGUgYW5kIGV4dGVuc2libGUgZnJhbWV3b3JrIGFwcGxpY2FibGUgdG8gb3RoZXIgc3lzdGVtcyBjaGFyYWN0ZXJpemVkIGJ5IGNvbnRpbnVvdXMgZGV2ZWxvcG1lbnQgb3IgcmVnZW5lcmF0aXZlIGNhcGFjaXR5LgoJClRoaXMgaW50ZWdyYXRpdmUgYXBwcm9hY2ggbGF5cyBhIGNvbXB1dGF0aW9uYWwgZm91bmRhdGlvbiBmb3IgZnV0dXJlIHN0dWRpZXMgc2Vla2luZyB0byBtZWNoYW5pc3RpY2FsbHkgZGlzc2VjdCBmYXRlIGNvbW1pdG1lbnQsIGNlbGx1bGFyIHJlZ3VsYXRvcnkgbmV0d29yayBmdW5jdGlvbnMsIGFuZCB0aGUgYXJjaGl0ZWN0dXJlIG9mIGRldmVsb3BtZW50YWwgcGxhc3RpY2l0eSBpbiBwbGFuYXJpYS4KCgojIyMgOC4gTGltaXRhdGlvbnMgb2YgdGhlIFN0dWR5CgpUaGUgcHJlc2VudCBzdHVkeSBpcyBjZW50ZXJlZCBvbiBlc3RhYmxpc2hpbmcgYSBjb21wdXRhdGlvbmFsIGFuZCBtYXRoZW1hdGljYWwgZnJhbWV3b3JrLiBDb25zZXF1ZW50bHksIGluaGVyZW50IGxpbWl0YXRpb25zIGNvbnN0cmFpbiB0aGUgaW1tZWRpYXRlIGJpb2xvZ2ljYWwgaW50ZXJwcmV0YWJpbGl0eSBvZiB0aGUgcmVzdWx0cy4KCisgQSBmZXcgb2YgdGhlIGNlbGwgdHlwZSBhbm5vdGF0aW9ucyByZW1haW4gcHJvdmlzaW9uYWwsIHJlcXVpcmluZyBmdXJ0aGVyIGV4cGVyaW1lbnRhbCB2YWxpZGF0aW9uIHRvIGVuc3VyZSBhY2N1cmF0ZSBiaW9sb2dpY2FsIGludGVycHJldGF0aW9uLgoKKyBQc2V1ZG90aW1lLCB3aGlsZSBjb3JyZWxhdGVkIHdpdGggd29ybSBzaXplIGFuZCBkZXZlbG9wbWVudGFsIHByb2dyZXNzaW9uLCBkb2VzIG5vdCBmdWxseSBjYXB0dXJlIHRoZSBjb21wbGV0ZSBiaW9sb2dpY2FsIGhldGVyb2dlbmVpdHkgb3IgbGluZWFnZS1zcGVjaWZpYyBjb21wbGV4aXR5IGluaGVyZW50IHRvIHRoZSBzeXN0ZW0uCgorIERhdGEgc3BhcnNpdHkgYW5kIGxpbWl0ZWQgc2FtcGxlIHNpemVzLCBwYXJ0aWN1bGFybHkgZm9yIHJhcmUgb3IgdHJhbnNpZW50IHBvcHVsYXRpb25zLCBtYXkgcmVkdWNlIHNlbnNpdGl2aXR5IHRvIHN1YnRsZSBidXQgYmlvbG9naWNhbGx5IHJlbGV2YW50IHNpZ25hbHMuCgorIE1vZGVsaW5nIGFzc3VtcHRpb25z4oCUaW5jbHVkaW5nIHNwbGluZSBkZWdyZWVzIG9mIGZyZWVkb20sIGRpc3RyaWJ1dGlvbmFsIGNob2ljZXMsIGFuZCB3aW5kb3cgcGFyYW1ldGVyc+KAlGltcGFjdCB0aGUgcm9idXN0bmVzcyBhbmQgc2Vuc2l0aXZpdHkgb2YgZmluZGluZ3MgYW5kIHdhcnJhbnQgZnVydGhlciB0dW5pbmcgYW5kIHZhbGlkYXRpb24uCgpGdXR1cmUgd29yayBzaG91bGQgZm9jdXMgb24gaW50ZWdyYXRpbmcgaGlnaGVyLXJlc29sdXRpb24gY2VsbCB0eXBlIGFubm90YXRpb25zLCBpbmNvcnBvcmF0aW5nIG11bHRpLW9taWNzIGRhdGEsIGFuZCBleHBhbmRpbmcgc2FtcGxlIHNpemVzIHRvIGVuaGFuY2Ugc3RhdGlzdGljYWwgcG93ZXIuIEFkZGl0aW9uYWxseSwgZXhwZXJpbWVudGFsIHBlcnR1cmJhdGlvbnMgZ3VpZGVkIGJ5IHRoZSBpZGVudGlmaWVkIGNhbmRpZGF0ZSBjZWxsIHR5cGVzIHdpbGwgYmUgY3JpdGljYWwgZm9yIHZhbGlkYXRpbmcgbWVjaGFuaXN0aWMgcm9sZXMgaW4gZmF0ZSBiaWZ1cmNhdGlvbnMuCgojIyBEYXRhCgpgYGB7ciwgcmVzdWx0cz0nYXNpcycsIGVjaG89RkFMU0V9CmNhdCgnCjxkaXYgc3R5bGU9InBvc2l0aW9uOiByZWxhdGl2ZTsgZGlzcGxheTogaW5saW5lLWJsb2NrOyB0ZXh0LWFsaWduOiBjZW50ZXI7Ij4KICA8aW1nIHNyYz0id29ybS5qcGVnIiBzdHlsZT0id2lkdGg6MTAwJTsgZGlzcGxheTogYmxvY2s7Ij4KICA8cCAgc3R5bGU9IgogICAgICAgcG9zaXRpb246IGFic29sdXRlOwogICAgICAgdG9wOiAzNyU7CiAgICAgICBsZWZ0OiAyNyU7CiAgICAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSgtNDAlLCAtMzAlKTsKICAgICAgIGNvbG9yOiBibGFjazsKICAgICAgIHBhZGRpbmc6IDEwcHggMjBweDsKICAgICAgIHRleHQtZGVjb3JhdGlvbjogbm9uZTsKICAgICAgIGJvcmRlci1yYWRpdXM6IDhweDsKICAgICAgIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgICAgZm9udC1zaXplOjMwcHg7CiAgICAgIj5UaGUgcHJvY2Vzc2VkIGRhdGEgYW5kIGFuYWx5c2lzIHNjcmlwdHMgXG4gYXJlIGF2YWlsYWJsZSBvbiAKICAgICAgICA8YSBocmVmPSJodHRwczovL2dpdGh1Yi5jb20vQWlzaHdhcnlhLUdpcmlzaC9Eb3JyaXR5LUxhYi1FTUJMIiB0YXJnZXQ9Il9ibGFuayI+R2l0SHViLjwvYT4KICA8L3A+CjwvZGl2PgonKQpgYGAKCiMjIEZ1dHVyZSBXb3JrCgpUaGUgc2l6ZS1pbmRlcGVuZGVudCBjb3ZhcmlhbmNlIG1hdHJpeCBkZXJpdmVkIGZyb20gUG9pc3NvbiBsb2dub3JtYWwgbW9kZWxpbmcgb2YgY2VsbCB0eXBlIGFidW5kYW5jZSBkYXRhIHNlcnZlcyBhcyBhIGNyaXRpY2FsIHRvb2wgdG8gaWRlbnRpZnkgY29vcmRpbmF0ZWQgcmVsYXRpb25zaGlwcyBhbW9uZyBjZWxsIHR5cGVzLiBCdWlsZGluZyBvbiB0aGlzLCBhIHBlcnR1cmJhdGlvbi1kcml2ZW4gaW4gc2lsaWNvIHNpbXVsYXRpb24gZnJhbWV3b3JrIGNhbiBiZSBkZXZlbG9wZWQgd2hlcmUgc3ludGhldGljIHdvcm1zIGFyZSBnZW5lcmF0ZWQgYnkgc2FtcGxpbmcgZnJvbSBtdWx0aXZhcmlhdGUgZGlzdHJpYnV0aW9ucyBwYXJhbWV0ZXJpemVkIGJ5IGVtcGlyaWNhbGx5IG9ic2VydmVkIG1lYW5zIGFuZCBjb3ZhcmlhbmNlcyBvZiBjZWxsIHR5cGUgYWJ1bmRhbmNlcy4KClRoaXMgbWV0aG9kIHByZXNlcnZlcyBpbnRyaW5zaWMgY2VsbHVsYXIgYWJ1bmRhbmNlIGNvcnJlbGF0aW9ucyBhbmQgZW5hYmxlcyBzeXN0ZW1hdGljIHBlcnR1cmJhdGlvbnMgYnkgbW9kdWxhdGluZyBhYnVuZGFuY2UgdmVjdG9ycyBvZiBjZWxsIHR5cGVzIGlkZW50aWZpZWQgdGhyb3VnaCB0aGUgY292YXJpYW5jZSBtYXRyaXgsIGVpdGhlciBqb2ludGx5IG9yIGluZGl2aWR1YWxseS4gTW9kdWxhdGluZyB0aGVzZSB2ZWN0b3JzIHdpdGhpbiBzeW50aGV0aWMgd29ybXMgYWxsb3dzIGNvbXB1dGF0aW9uYWwgZXZhbHVhdGlvbiBvZiBob3cgdGFyZ2V0ZWQgcGVydHVyYmF0aW9ucyBpbmZsdWVuY2UgcHNldWRvdGVtcG9yYWwgZGV2ZWxvcG1lbnRhbCB0cmFqZWN0b3JpZXMgYW5kIGxpbmVhZ2UgYmlmdXJjYXRpb24gZGVjaXNpb25zIGJldHdlZW4gc2V4dWFsIGFuZCBhc2V4dWFsIGZhdGVzLgoKU3VjaCBzaW11bGF0aW9ucyBwcm92aWRlIGEgaHlwb3RoZXNpcy1kcml2ZW4gcGxhdGZvcm0gdG8gZGlzc2VjdCB0aGUgbWVjaGFuaXN0aWMgY29udHJpYnV0aW9ucyBvZiBzcGVjaWZpYyBjZWxsIHBvcHVsYXRpb25zLCBwcmVkaWN0IHN5c3RlbS1sZXZlbCByZXNwb25zZXMgdG8gY29tcG9zaXRpb25hbCBjaGFuZ2VzLCBhbmQgZ3VpZGUgZm9jdXNlZCBleHBlcmltZW50YWwgdmFsaWRhdGlvbnMuIFRoaXMgZnJhbWV3b3JrIG9mZmVycyBhIHJvYnVzdCBtZWFucyB0byBleHBsb3JlIGNvbXBlbnNhdG9yeSBuZXR3b3JrcyBhbmQgaWRlbnRpZnkgY2FuZGlkYXRlIGRyaXZlciBwb3B1bGF0aW9ucyB0aGF0IHJlZ3VsYXRlIHJlcHJvZHVjdGl2ZSBmYXRlIG91dGNvbWVzIGluIHZpdm8uCgojIyBBY2tub3dsZWRnZW1lbnRzCgpUaGlzIHdvcmsgd2FzIG1hZGUgcG9zc2libGUgdGhyb3VnaCB0aGUgc3VwcG9ydCBhbmQgd29uZGVyZnVsIGxhYiBlbnZpcm9ubWVudCBwcm92aWRlZCBieSB0aGUgRG9ycml0eSBHcm91cCBhdCBFTUJMLiBTcGVjaWFsIGFwcHJlY2lhdGlvbiBhbmQgZ3JhdGl0dWRlIGdvZXMgdG8gTWlrZSBhbmQgR2F1cmF2IGZvciB0aGVpciB0aW1lbHkgbWVudG9yc2hpcCwgaW5zaWdodGZ1bCBkaXNjdXNzaW9ucywgYW5kIHN0ZWFkeSBndWlkYW5jZSB0aHJvdWdob3V0IHRoaXMgd29yay4gVGhlaXIgc3VwcG9ydCBhbmQgZW5jb3VyYWdlbWVudCBwbGF5ZWQgYSBrZXkgcm9sZSBpbiBzaGFwaW5nIGJvdGggdGhlIHNjaWVudGlmaWMgZGlyZWN0aW9uIGFuZCBleGVjdXRpb24gb2YgdGhpcyBzdHVkeS4KCkF1dGhvciBEZXRhaWxzCgotIE5hbWU6IEFpc2h3YXJ5YSBHaXJpc2gKLSBFbWFpbDogYWlzaHdhcnlhLmdpcmlzaEBzdHVkLnVuaS1oZWlkZWxiZXJnLmRlCi0gTGlua2VkSW46IFtodHRwczovL3d3dy5saW5rZWRpbi5jb20vaW4vYWlzaHdhcnlhZ2lyaXNoL10oaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2luL2Fpc2h3YXJ5YWdpcmlzaC8pCgo=