This report contains a summary of cell type annotation results for library SCPCL000001. The goal of this report is to provide more detailed information about cell type annotation results as an initial evaluation of their quality and reliability.

Performing cell type annotation is an inherently challenging task with high levels of uncertainty, especially when using automated annotation methods. One way to address this is to use multiple cell type annotation approaches and compare the results, as we have begun to do in this report.

When multiple methods annotate a given cell as the same or similar cell type, this may qualitatively indicate a more robust annotation.

Note that the contents of this report will vary based on which cell type annotations are present. Further, be aware that different cell type annotation methods may assign different labels to the same or similar cell type (e.g., the different string representations B cell naive and Naive B cell), due to use of different underlying reference datasets. Please note that all cell type annotation reference datasets are derived from normal (not tumor) tissue.

This library contains the following cell type annotations:

  • Annotations from SingleR, a reference-based approach (Looney et al. 2019). The BlueprintEncodeData dataset, obtained from the celldex package, was used for reference annotations.
  • Annotations from CellAssign, a marker-gene-based approach (Zhang et al. 2019). Marker genes for cell types were obtained from PanglaoDB and compiled into a reference named brain-compartment. This reference includes the following organs and tissue compartments: brain, embryo, immune system, and vasculature.

Cell type Annotation Summary

The plots and tables included here detail the results from performing cell type annotation.

Statistics

When reprocessing this library, old results from running SingleR and CellAssign were used. This means results were calculated with a slightly different set of cells. Any cells that are missing have been annotated as Unclassified cell in the object and will not be shown in any plots.

SingleR cell type annotations

In this table, cells labeled “Unknown cell type” are those which SingleR pruned due to low-quality assignments. In the processed result files, these cells are labeled NA.
Annotated cell type Number of cells Percent of cells
neuron 2315 88.19%
macrophage 196 7.47%
monocyte 12 0.46%
effector memory CD8-positive, alpha-beta T cell 11 0.42%
CD4-positive, alpha-beta T cell 10 0.38%
mesangial cell 8 0.3%
fat cell 6 0.23%
central memory CD8-positive, alpha-beta T cell 5 0.19%
naive B cell 5 0.19%
central memory CD4-positive, alpha-beta T cell 4 0.15%
chondrocyte 4 0.15%
melanocyte 4 0.15%
natural killer cell 4 0.15%
class switched memory B cell 3 0.11%
erythrocyte 3 0.11%
astrocyte 2 0.08%
CD8-positive, alpha-beta T cell 1 0.04%
common lymphoid progenitor 1 0.04%
granulocyte monocyte progenitor cell 1 0.04%
hematopoietic stem cell 1 0.04%
muscle cell 1 0.04%
plasma cell 1 0.04%
Unknown cell type 27 1.03%

CellAssign cell type annotations

In this table, cells labeled “Unknown cell type” are those which CellAssign could not confidently assign to a label in the reference list. In the processed result files, these cells are labeled "other".
Annotated cell type Number of cells Percent of cells
Purkinje neurons 1872 71.31%
Microglia 200 7.62%
Gamma delta T cells 111 4.23%
T memory cells 25 0.95%
Oligodendrocytes 15 0.57%
Dendritic cells 13 0.5%
B cells 12 0.46%
Satellite glial cells 11 0.42%
Schwann cells 8 0.3%
Meningeal cells 7 0.27%
T cells 7 0.27%
NK cells 6 0.23%
Astrocytes 4 0.15%
Macrophages 4 0.15%
Megakaryocytes 3 0.11%
Monocytes 3 0.11%
Neural stem/precursor cells 3 0.11%
Tanycytes 3 0.11%
Endothelial cells 2 0.08%
Natural killer T cells 2 0.08%
Neutrophils 2 0.08%
Nuocytes 2 0.08%
Choroid plexus cells 1 0.04%
Dopaminergic neurons 1 0.04%
Endothelial cells (blood brain barrier) 1 0.04%
Epiblast cells 1 0.04%
GABAergic neurons 1 0.04%
Oligodendrocyte progenitor cells 1 0.04%
Serotonergic neurons 1 0.04%
Trophoblast cells 1 0.04%
Unknown cell type 302 11.5%

UMAPs

In this section, we show UMAPs colored by clusters. Clusters were calculated using the graph-based Louvain algorithm with Jaccard weighting.

Next, we show UMAPs colored by cell types. For each cell typing method, we show a separate faceted UMAP. In each panel, cells that were assigned the given cell type label are colored, while all other cells are in grey.

For legibility, only the seven most common cell types are shown. All other cell types are grouped together and labeled “All remaining cell types” (not to be confused with “Unknown cell type” which represents cells that could not be classified).

Cell label comparison plots

This section displays heatmaps comparing cell labels from various methods.

We use the Jaccard similarity index to display the agreement between between pairs of labels assigned by different annotation methods.

The Jaccard index reflects the degree of overlap between the two labels and ranges from 0 to 1.

  • If the labels are assigned to identical sets of cells, the Jaccard index will be 1.
  • If the labels are assigned to completely non-overlapping sets of cells, the Jaccard index will be 0.

High agreement between methods qualitatively indicates higher confidence in the cell type annotation.

Unsupervised clustering

Here we show the labels from unsupervised clustering compared to cell type annotations. Cluster assignment was performed using the Louvain algorithm.

Automated annotations

This section displays a heatmap directly comparing SingleR and CellAssign cell type annotations. Note that due to different annotations references, these methods may use different names for similar cell types.

Quality assessments of automated annotations

SingleR annotations

To assess the quality of SingleR cell type annotations, we use the delta median statistic.

  • Delta median is calculated for each cell as the difference between the SingleR score of the annotated cell type label and the median score of the other cell type labels in the reference dataset.
  • Higher delta median values indicate higher quality cell type annotations.

You can interpret this plot as follows:

  • Each point represents the delta median statistic of a given cell whose SingleR annotation is shown on the y-axis.
  • The point style indicates SingleR’s quality assessment of the annotation:
    • High-quality cell annotations are shown as closed points.
    • Low-quality cell annotations are shown as open points. In other sections of this report, these cells are labeled as Unknown cell types.
    • For more information on how SingleR calculates annotation quality, please refer to this SingleR documentation.
  • Diamonds represent the median of the delta median statistic specifically among high-quality annotations for the given cell type annotation.

CellAssign annotations

To assess the quality of CellAssign cell type annotations, we consider the probability associated with the annotated cell type. These probabilities are provided directly by CellAssign:

  • CellAssign first calculates the probability of each cell being annotated as each cell type present in the reference.
  • CellAssign then annotates cells by selecting the cell type with the highest probability among all cell types considered.
  • These probabilities range from 0 to 1, with larger values indicating greater confidence in a given cell type label. We therefore expect reliable labels to have values close to 1.

The plot below shows the distribution of CellAssign-calculated probabilities for the final cell type labels. Line segments represent individual values that comprise each distribution.

For cell types with 2 or fewer labeled cells, only the individual value line segments are shown. Line segments are also taller for any cell type label with 5 or fewer cells.

Session Info

R session information

## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.3.2 (2023-10-31)
##  os       Ubuntu 22.04.3 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_US.UTF-8
##  ctype    en_US.UTF-8
##  tz       Etc/UTC
##  date     2024-03-18
##  pandoc   2.9.2.1 @ /usr/bin/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package              * version   date (UTC) lib source
##  abind                  1.4-5     2016-07-21 [1] RSPM (R 4.3.0)
##  beachmat               2.16.0    2023-04-25 [1] Bioconductor
##  beeswarm               0.4.0     2021-06-01 [1] RSPM (R 4.3.0)
##  Biobase              * 2.60.0    2023-04-25 [1] Bioconductor
##  BiocGenerics         * 0.46.0    2023-04-25 [1] Bioconductor
##  BiocNeighbors          1.18.0    2023-04-25 [1] Bioconductor
##  BiocParallel           1.34.2    2023-05-22 [1] Bioconductor
##  BiocSingular           1.16.0    2023-04-25 [1] Bioconductor
##  bitops                 1.0-7     2021-04-24 [1] RSPM (R 4.3.0)
##  bluster                1.10.0    2023-04-25 [1] Bioconductor
##  bslib                  0.5.1     2023-08-11 [1] RSPM (R 4.3.0)
##  cachem                 1.0.8     2023-05-01 [1] RSPM (R 4.3.0)
##  Cairo                  1.6-1     2023-08-18 [1] RSPM (R 4.3.0)
##  circlize               0.4.15    2022-05-10 [1] RSPM (R 4.3.0)
##  cli                    3.6.1     2023-03-23 [1] RSPM (R 4.3.0)
##  clue                   0.3-65    2023-09-23 [1] RSPM (R 4.3.0)
##  cluster                2.1.4     2022-08-22 [2] CRAN (R 4.3.2)
##  codetools              0.2-19    2023-02-01 [2] CRAN (R 4.3.2)
##  colorspace             2.1-0     2023-01-23 [1] RSPM (R 4.3.0)
##  ComplexHeatmap         2.16.0    2023-04-25 [1] Bioconductor
##  cowplot                1.1.1     2020-12-30 [1] RSPM (R 4.3.0)
##  crayon                 1.5.2     2022-09-29 [1] RSPM (R 4.3.0)
##  DelayedArray           0.26.7    2023-07-28 [1] Bioconductor
##  DelayedMatrixStats     1.22.6    2023-08-28 [1] Bioconductor
##  digest                 0.6.33    2023-07-07 [1] RSPM (R 4.3.0)
##  doParallel             1.0.17    2022-02-07 [1] RSPM (R 4.3.0)
##  dplyr                * 1.1.4     2023-11-17 [1] RSPM (R 4.3.0)
##  dqrng                  0.3.1     2023-08-30 [1] RSPM (R 4.3.0)
##  edgeR                  3.42.4    2023-05-31 [1] Bioconductor
##  evaluate               0.23      2023-11-01 [1] RSPM (R 4.3.0)
##  fansi                  1.0.5     2023-10-08 [1] RSPM (R 4.3.0)
##  farver                 2.1.1     2022-07-06 [1] RSPM (R 4.3.0)
##  fastmap                1.1.1     2023-02-24 [1] RSPM (R 4.3.0)
##  flexmix                2.3-19    2023-03-16 [1] RSPM (R 4.3.0)
##  forcats                1.0.0     2023-01-29 [1] RSPM (R 4.3.0)
##  foreach                1.5.2     2022-02-02 [1] RSPM (R 4.3.0)
##  generics               0.1.3     2022-07-05 [1] RSPM (R 4.3.0)
##  GenomeInfoDb         * 1.36.4    2023-10-02 [1] Bioconductor
##  GenomeInfoDbData       1.2.10    2024-03-08 [1] Bioconductor
##  GenomicRanges        * 1.52.1    2023-10-08 [1] Bioconductor
##  getopt                 1.20.4    2023-10-01 [1] RSPM (R 4.3.0)
##  GetoptLong             1.0.5     2020-12-15 [1] RSPM (R 4.3.0)
##  ggbeeswarm             0.7.2     2023-04-29 [1] RSPM (R 4.3.0)
##  ggforce                0.4.1     2022-10-04 [1] RSPM (R 4.3.0)
##  ggplot2              * 3.4.4     2023-10-12 [1] RSPM (R 4.3.0)
##  ggrepel                0.9.4     2023-10-13 [1] RSPM (R 4.3.0)
##  GlobalOptions          0.1.2     2020-06-10 [1] RSPM (R 4.3.0)
##  glue                   1.6.2     2022-02-24 [1] RSPM (R 4.3.0)
##  gridExtra              2.3       2017-09-09 [1] RSPM (R 4.3.0)
##  gtable                 0.3.4     2023-08-21 [1] RSPM (R 4.3.0)
##  highr                  0.10      2022-12-22 [1] RSPM (R 4.3.0)
##  hms                    1.1.3     2023-03-21 [1] RSPM (R 4.3.0)
##  htmltools              0.5.7     2023-11-03 [1] RSPM (R 4.3.0)
##  httr                   1.4.7     2023-08-15 [1] RSPM (R 4.3.0)
##  igraph                 1.5.1     2023-08-10 [1] RSPM (R 4.3.0)
##  IRanges              * 2.34.1    2023-06-22 [1] Bioconductor
##  irlba                  2.3.5.1   2022-10-03 [1] RSPM (R 4.3.0)
##  iterators              1.0.14    2022-02-05 [1] RSPM (R 4.3.0)
##  jquerylib              0.1.4     2021-04-26 [1] RSPM (R 4.3.0)
##  jsonlite               1.8.7     2023-06-29 [1] RSPM (R 4.3.0)
##  kableExtra             1.3.4     2021-02-20 [1] RSPM (R 4.3.0)
##  knitr                  1.45      2023-10-30 [1] RSPM (R 4.3.0)
##  labeling               0.4.3     2023-08-29 [1] RSPM (R 4.3.0)
##  lattice                0.22-5    2023-10-24 [1] RSPM (R 4.3.0)
##  lifecycle              1.0.4     2023-11-07 [1] RSPM (R 4.3.0)
##  limma                  3.56.2    2023-06-04 [1] Bioconductor
##  locfit                 1.5-9.8   2023-06-11 [1] RSPM (R 4.3.0)
##  lubridate              1.9.3     2023-09-27 [1] RSPM (R 4.3.0)
##  magrittr               2.0.3     2022-03-30 [1] RSPM (R 4.3.0)
##  MASS                   7.3-60    2023-05-04 [2] CRAN (R 4.3.2)
##  Matrix                 1.6-3     2023-11-14 [1] RSPM (R 4.3.0)
##  MatrixGenerics       * 1.12.3    2023-07-30 [1] Bioconductor
##  matrixStats          * 1.1.0     2023-11-07 [1] RSPM (R 4.3.0)
##  metapod                1.8.0     2023-04-25 [1] Bioconductor
##  miQC                   1.8.0     2023-04-27 [1] Bioconductor
##  modeltools             0.2-23    2020-03-05 [1] RSPM (R 4.3.0)
##  munsell                0.5.0     2018-06-12 [1] RSPM (R 4.3.0)
##  nnet                   7.3-19    2023-05-03 [2] CRAN (R 4.3.2)
##  optparse             * 1.7.3     2022-07-20 [1] RSPM (R 4.3.0)
##  pillar                 1.9.0     2023-03-22 [1] RSPM (R 4.3.0)
##  pkgconfig              2.0.3     2019-09-22 [1] RSPM (R 4.3.0)
##  png                    0.1-8     2022-11-29 [1] RSPM (R 4.3.0)
##  polyclip               1.10-6    2023-09-27 [1] RSPM (R 4.3.0)
##  purrr                  1.0.2     2023-08-10 [1] RSPM (R 4.3.0)
##  R6                     2.5.1     2021-08-19 [1] RSPM (R 4.3.0)
##  RColorBrewer           1.1-3     2022-04-03 [1] RSPM (R 4.3.0)
##  Rcpp                   1.0.11    2023-07-06 [1] RSPM (R 4.3.0)
##  RCurl                  1.98-1.13 2023-11-02 [1] RSPM (R 4.3.0)
##  readr                  2.1.4     2023-02-10 [1] RSPM (R 4.3.0)
##  rjson                  0.2.21    2022-01-09 [1] RSPM (R 4.3.0)
##  rlang                  1.1.2     2023-11-04 [1] RSPM (R 4.3.0)
##  rmarkdown              2.25      2023-09-18 [1] RSPM (R 4.3.0)
##  rstudioapi             0.15.0    2023-07-07 [1] RSPM (R 4.3.0)
##  rsvd                   1.0.5     2021-04-16 [1] RSPM (R 4.3.0)
##  rvest                  1.0.3     2022-08-19 [1] RSPM (R 4.3.0)
##  S4Arrays               1.0.6     2023-08-30 [1] Bioconductor
##  S4Vectors            * 0.38.2    2023-09-22 [1] Bioconductor
##  sass                   0.4.7     2023-07-15 [1] RSPM (R 4.3.0)
##  ScaledMatrix           1.8.1     2023-05-03 [1] Bioconductor
##  scales                 1.2.1     2022-08-20 [1] RSPM (R 4.3.0)
##  scater                 1.28.0    2023-04-25 [1] Bioconductor
##  scpcaTools             0.3.2     2024-03-12 [1] Github (AlexsLemonade/scpcaTools@20c9029)
##  scran                  1.28.2    2023-07-23 [1] Bioconductor
##  scuttle                1.10.3    2023-10-10 [1] Bioconductor
##  sessioninfo            1.2.2     2021-12-06 [1] RSPM (R 4.3.0)
##  shape                  1.4.6     2021-05-19 [1] RSPM (R 4.3.0)
##  SingleCellExperiment * 1.22.0    2023-04-25 [1] Bioconductor
##  sparseMatrixStats      1.12.2    2023-07-02 [1] Bioconductor
##  statmod                1.5.0     2023-01-06 [1] RSPM (R 4.3.0)
##  stringi                1.8.1     2023-11-13 [1] RSPM (R 4.3.0)
##  stringr                1.5.1     2023-11-14 [1] RSPM (R 4.3.0)
##  SummarizedExperiment * 1.30.2    2023-06-06 [1] Bioconductor
##  svglite                2.1.2     2023-10-11 [1] RSPM (R 4.3.0)
##  systemfonts            1.0.5     2023-10-09 [1] RSPM (R 4.3.0)
##  tibble                 3.2.1     2023-03-20 [1] RSPM (R 4.3.0)
##  tidyr                  1.3.0     2023-01-24 [1] RSPM (R 4.3.0)
##  tidyselect             1.2.0     2022-10-10 [1] RSPM (R 4.3.0)
##  timechange             0.2.0     2023-01-11 [1] RSPM (R 4.3.0)
##  tweenr                 2.0.2     2022-09-06 [1] RSPM (R 4.3.0)
##  tzdb                   0.4.0     2023-05-12 [1] RSPM (R 4.3.0)
##  utf8                   1.2.4     2023-10-22 [1] RSPM (R 4.3.0)
##  vctrs                  0.6.4     2023-10-12 [1] RSPM (R 4.3.0)
##  vipor                  0.4.5     2017-03-22 [1] RSPM (R 4.3.0)
##  viridis                0.6.4     2023-07-22 [1] RSPM (R 4.3.0)
##  viridisLite            0.4.2     2023-05-02 [1] RSPM (R 4.3.0)
##  webshot                0.5.5     2023-06-26 [1] RSPM (R 4.3.0)
##  withr                  2.5.2     2023-10-30 [1] RSPM (R 4.3.0)
##  xfun                   0.41      2023-11-01 [1] RSPM (R 4.3.0)
##  xml2                   1.3.5     2023-07-06 [1] RSPM (R 4.3.0)
##  XVector                0.40.0    2023-04-25 [1] Bioconductor
##  yaml                   2.3.7     2023-01-23 [1] RSPM (R 4.3.0)
##  zlibbioc               1.46.0    2023-04-25 [1] Bioconductor
## 
##  [1] /usr/local/lib/R/site-library
##  [2] /usr/local/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────
LS0tCnBhcmFtczoKICBsaWJyYXJ5OiBFeGFtcGxlCiAgcHJvY2Vzc2VkX3NjZTogTlVMTAogIGRhdGU6ICFyIFN5cy5EYXRlKCkKdGl0bGU6ICJgciBnbHVlOjpnbHVlKCdTY1BDQSBTdXBwbGVtZW50YWwgY2VsbCB0eXBlIHJlcG9ydCBmb3Ige3BhcmFtcyRsaWJyYXJ5fScpYCIKYXV0aG9yOiAiQ2hpbGRob29kIENhbmNlciBEYXRhIExhYiIKZGF0ZTogImByIHBhcmFtcyRkYXRlYCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMgogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCi0tLQoKYGBge3Igc2V0dXAsIG1lc3NhZ2UgPSBGQUxTRSwgZWNobyA9IEZBTFNFfQojIGtuaXRyIG9wdGlvbnMKa25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVjaG8gPSBGQUxTRQopCgpsaWJyYXJ5KFNpbmdsZUNlbGxFeHBlcmltZW50KQpsaWJyYXJ5KGdncGxvdDIpCgojIFNldCBkZWZhdWx0IGdncGxvdCB0aGVtZQp0aGVtZV9zZXQoCiAgdGhlbWVfYncoKSArCiAgICB0aGVtZSgKICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4ocmVwKDIwLCA0KSksCiAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpCiAgICApCikKCiMgVGhpcyBfaXNfIHRoZSBzdXBwbGVtZW50YWwgcmVwb3J0CiMgd2Ugc2hvdWxkIG5vdCBwcmludCB0aGUgY2h1bmsgZnJvbSBjZWxsdHlwZXNfcWMucm1kIHJlY2FwaXR1bGF0aW5nIGJ1bGxldHMKIyAgYW5kIHBvaW50aW5nIHVzZXJzIHRvIHRoaXMgc3VwcCByZXBvcnQKaXNfc3VwcGxlbWVudGFsIDwtIFRSVUUKYGBgCgo8IS0tIEltcG9ydCBzaGFyZWQgZnVuY3Rpb25zIGZvciBjZWxsIHR5cGUgd3JhbmdsaW5nIC0tPgpgYGB7ciwgY2hpbGQ9J3V0aWxzL2NlbGx0eXBlX2Z1bmN0aW9ucy5ybWQnfQpgYGAKYGBge3IsIGNoaWxkPSd1dGlscy9yZXBvcnRfZnVuY3Rpb25zLnJtZCd9CmBgYAoKCjwhLS0gRGVmaW5lIGhlbHBlciBmdW5jdGlvbnMgZm9yIGNhbGN1bGF0aW5nIEphY2NhcmQgbWF0cmljZXMgLS0+CmBgYHtyfQojJyBGdW5jdGlvbiB0byBjYWxjdWxhdGUgSmFjY2FyZCBzaW1pbGFyaXR5IG9uIHR3byB2ZWN0b3JzCiMnCiMnIEBwYXJhbSB2ZWMxIEZpcnN0IHZlY3RvcgojJyBAcGFyYW0gdmVjMiBTZWNvbmQgdmVjdG9yCiMnCiMnIEByZXR1cm4gSmFjY2FyZCBzaW1pbGFyaXR5IGJldHdlZW4gdGhlIHZlY3RvcnMKamFjY2FyZCA8LSBmdW5jdGlvbih2ZWMxLCB2ZWMyKSB7CiAgbGVuZ3RoKGludGVyc2VjdCh2ZWMxLCB2ZWMyKSkgLyBsZW5ndGgodW5pb24odmVjMSwgdmVjMikpCn0KCgojIFdyYXBwZXIgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIGphY2NhcmQgc2ltaWxhcml0eSBtYXRyaXggZm9yIHR3byBjYXRlZ29yaWNhbCB2YXJpYWJsZXMKIycKIycgQHBhcmFtIGNlbGx0eXBlX2RmIFRoZSBjZWxsdHlwZV9kZiBkYXRhIGZyYW1lIHdoaWNoIG11c3QgY29udGFpbiB0aGVzZSBjb2x1bW5zOgojJyAgIGBjb2xuYW1lMWAsIGBjb2xuYW1lMmAsIGFuZCBgYmFyY29kZXNgCiMnIEBwYXJhbSBjb2xuYW1lMSBDb2x1bW4gbmFtZSwgYXMgYSBzdHJpbmcsIG9mIGZpcnN0IGNhdGVnb3JpY2FsIHZhcmlhYmxlIG9mIGludGVyZXN0CiMnIEBwYXJhbSBjb2xuYW1lMiBDb2x1bW4gbmFtZSwgYXMgYSBzdHJpbmcsIG9mIHNlY29uZCBjYXRlZ29yaWNhbCB2YXJpYWJsZSBvZiBpbnRlcmVzdAojJwojJyBAcmV0dXJuIEphY2NhcmQgc2ltaWxhcml0eSBtYXRyaXggZm9yIHRoZSB0d28gY29sdW1ucy4gYGNvbG5hbWUxYCB2YWx1ZXMgd2lsbAojJyAgIGJlIHJvdyBuYW1lcyBhbmQgYGNvbG5hbWUyYCB2YWx1ZXMgd2lsbCBiZSBjb2x1bW4gbmFtZXMgaW4gdGhlIGZpbmFsIG1hdHJpeAptYWtlX2phY2NhcmRfbWF0cml4IDwtIGZ1bmN0aW9uKGNlbGx0eXBlX2RmLCBjb2xuYW1lMSwgY29sbmFtZTIpIHsKICAjIG1ha2UgbGlzdHMgb2YgYmFyY29kZXMgZm9yIGVhY2ggY2F0ZWdvcnksIG5hbWVkIGJ5IHRoZSBjYXRlZ29yeQogIGlkMV9saXN0IDwtIHNwbGl0KGNlbGx0eXBlX2RmJGJhcmNvZGVzLCBjZWxsdHlwZV9kZltbY29sbmFtZTFdXSkKICBpZDJfbGlzdCA8LSBzcGxpdChjZWxsdHlwZV9kZiRiYXJjb2RlcywgY2VsbHR5cGVfZGZbW2NvbG5hbWUyXV0pCgogICMgY3JlYXRlIHRoZSBncmlkIG9mIGNvbXBhcmlzb25zCiAgY3Jvc3NfZGYgPC0gdGlkeXI6OmV4cGFuZF9ncmlkKGlkMSA9IG5hbWVzKGlkMV9saXN0KSwgaWQyID0gbmFtZXMoaWQyX2xpc3QpKQoKICAjIGNhbGN1bGF0ZSBhIHNpbmdsZSBKYWNjYXJkIGluZGV4IGZvciBlYWNoIGNvbWJpbmF0aW9uIHVzaW5nIHNwbGl0IGxpc3RzICYgaWRzCiAgamFjY2FyZF9zY29yZXMgPC0gY3Jvc3NfZGYgfD4KICAgIHB1cnJyOjpwbWFwX2RibChcKGlkMSwgaWQyKXsKICAgICAgamFjY2FyZChpZDFfbGlzdFtbaWQxXV0sIGlkMl9saXN0W1tpZDJdXSkKICAgIH0pCgogICMgYWRkIHNjb3JlcyB0byB0aGUgY29tcGFyaXNvbiBncmlkIGFuZCBjb252ZXJ0IHRvIG1hdHJpeAogIGphY2NhcmRfbWF0cml4IDwtIGNyb3NzX2RmIHw+CiAgICBkcGx5cjo6bXV0YXRlKGphY2NhcmQgPSBqYWNjYXJkX3Njb3JlcykgfD4KICAgICMgY29udmVydCB0byBtYXRyaXgKICAgIHRpZHlyOjpwaXZvdF93aWRlcigKICAgICAgbmFtZXNfZnJvbSA9ICJpZDIiLAogICAgICB2YWx1ZXNfZnJvbSA9ICJqYWNjYXJkIgogICAgKSB8PgogICAgdGliYmxlOjpjb2x1bW5fdG9fcm93bmFtZXModmFyID0gImlkMSIpIHw+CiAgICBhcy5tYXRyaXgoKQoKICByZXR1cm4oamFjY2FyZF9tYXRyaXgpCn0KYGBgCgoKPCEtLSBEZWZpbmUgdmFyaWFibGVzLCBvcHRpb25zLCBhbmQgZnVuY3Rpb25zIGZvciBwbG90dGluZyBoZWF0bWFwcyAtLT4KYGBge3J9CiMgRGVmaW5lIGNvbG9yIHJhbXAgZm9yIHNoYXJlZCB1c2UgaW4gdGhlIGhlYXRtYXAKaGVhdG1hcF9jb2xfZnVuIDwtIGNpcmNsaXplOjpjb2xvclJhbXAyKGMoMCwgMSksIGNvbG9ycyA9IGMoIndoaXRlIiwgImRhcmtzbGF0ZWJsdWUiKSkKCiMgU2V0IGhlYXRtYXAgcGFkZGluZyBvcHRpb24KaGVhdG1hcF9wYWRkaW5nIDwtIDAuMgpDb21wbGV4SGVhdG1hcDo6aHRfb3B0KFRJVExFX1BBRERJTkcgPSBncmlkOjp1bml0KGhlYXRtYXBfcGFkZGluZywgImluIikpCgojJyBDcmVhdGUgYSBDb21wbGV4SGVhdG1hcCBmcm9tIGEgbWF0cml4CiMnCiMnIEBwYXJhbSBtYXQgTWF0cml4IHRvIGNyZWF0ZSBoZWF0bWFwIGZyb20uCiMnIEBwYXJhbSByb3dfdGl0bGUgTGFiZWwgZm9yIHJvdyB0aXRsZS4KIycgQHBhcmFtIGNvbHVtbl90aXRsZSBMYWJlbCBmb3IgY29sdW1uIHRpdGxlLgojJyBAcGFyYW0gbGFiZWxzX2ZvbnRfc2l6ZSBGb250IHNpemUgdG8gdXNlIGZvciByb3dzIGFuZCBjb2x1bW4gbGFiZWxzLgojJyBAcGFyYW0ga2VlcF9sZWdlbmRfbmFtZSBUaGUgbmFtZSB0byB1c2UgaW4gdGhlIGxlZ2VuZAojJyBAcGFyYW0gY29sX2Z1biBDb2xvciBmdW5jdGlvbiBmb3IgdGhlIGhlYXRtYXAgcGFsZXR0ZS4gRGVmYXVsdCBpcyBgaGVhdG1hcF9jb2xfZnVuYC4KIycgQHBhcmFtIC4uLiBBZGRpdGlvbmFsIGFyZ3VtZW50cyB0byBwYXNzIHRvIGBDb21wbGV4SGVhdG1hcDo6SGVhdG1hcCgpYAojJwojJyBAcmV0dXJuIEEgQ29tcGxleEhlYXRtYXAgb2JqZWN0CmNyZWF0ZV9zaW5nbGVfaGVhdG1hcCA8LSBmdW5jdGlvbigKICAgIG1hdCwKICAgIHJvd190aXRsZSwKICAgIGNvbHVtbl90aXRsZSwKICAgIGxhYmVsc19mb250X3NpemUsCiAgICBrZWVwX2xlZ2VuZF9uYW1lLAogICAgY29sX2Z1biA9IGhlYXRtYXBfY29sX2Z1biwKICAgIC4uLikgewogIGhlYXQgPC0gQ29tcGxleEhlYXRtYXA6OkhlYXRtYXAoCiAgICB0KG1hdCksICMgdHJhbnNwb3NlIGJlY2F1c2UgbWF0cml4IHJvd3MgYXJlIGluIGNvbW1vbiAmIHdlIHdhbnQgYSB2ZXJ0aWNhbCBhcnJhbmdlbWVudAogICAgY29sID0gY29sX2Z1biwKICAgIGJvcmRlciA9IFRSVUUsICMgZWFjaCBoZWF0bWFwIGdldHMgaXRzIG93biBvdXRsaW5lCiAgICAjIyBSb3cgcGFyYW1ldGVycwogICAgY2x1c3Rlcl9yb3dzID0gRkFMU0UsCiAgICByb3dfdGl0bGUgPSByb3dfdGl0bGUsICMgZWFjaCBoZWF0bWFwIGdldHMgaXRzIG93biB0aXRsZQogICAgcm93X3RpdGxlX2dwID0gZ3JpZDo6Z3Bhcihmb250c2l6ZSA9IDEwKSwKICAgIHJvd190aXRsZV9zaWRlID0gInJpZ2h0IiwKICAgIHJvd19uYW1lc19zaWRlID0gImxlZnQiLAogICAgcm93X25hbWVzX2dwID0gZ3JpZDo6Z3Bhcihmb250c2l6ZSA9IGxhYmVsc19mb250X3NpemUpLAogICAgIyMgQ29sdW1uIHBhcmFtZXRlcnMKICAgIGNsdXN0ZXJfY29sdW1ucyA9IEZBTFNFLAogICAgY29sdW1uX3RpdGxlID0gY29sdW1uX3RpdGxlLAogICAgY29sdW1uX3RpdGxlX2dwID0gZ3JpZDo6Z3Bhcihmb250c2l6ZSA9IDEwKSwKICAgIGNvbHVtbl9uYW1lc19zaWRlID0gImJvdHRvbSIsCiAgICBjb2x1bW5fbmFtZXNfZ3AgPSBncmlkOjpncGFyKGZvbnRzaXplID0gbGFiZWxzX2ZvbnRfc2l6ZSksCiAgICAjIyMgcGFzc2VkIGluIGFyZ3MKICAgIC4uLiwKICAgICMjIExlZ2VuZCBwYXJhbWV0ZXJzCiAgICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QoCiAgICAgIHRpdGxlID0gIkphY2NhcmQgaW5kZXgiLAogICAgICBkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsCiAgICAgIGxlZ2VuZF93aWR0aCA9IHVuaXQoMS41LCAiaW4iKQogICAgKSwKICAgICMgb25seSBrZWVwIGxlZ2VuZHMgdGhhdCBtYXRjaCBga2VlcF9sZWdlbmRfbmFtZWAKICAgIHNob3dfaGVhdG1hcF9sZWdlbmQgPSByb3dfdGl0bGUgPT0ga2VlcF9sZWdlbmRfbmFtZSwKICApCgogIHJldHVybihoZWF0KQp9CgojJyBGdW5jdGlvbiB0byBwbG90IGEgdmVydGljYWxseS1zdGFja2VkIENvbXBsZXhIZWF0bWFwIGZyb20gYSBsaXN0IG9mIG1hdHJpY2VzCiMnCiMnIEBwYXJhbSBtYXRyaXhfbGlzdCBMaXN0IG9mIG1hdHJpY2VzIHRvIHBsb3QgaW4gYSB2ZXJ0aWNhbCBsYXlvdXQKIycgQHBhcmFtIGNvbHVtbl90aXRsZSBUaXRsZSB0byB1c2UgZm9yIGNvbHVtbnMsIHNoYXJlZCBhbW9uZyBhbGwgaGVhdG1hcHMKIycgQHBhcmFtIGxhYmVsc19mb250X3NpemUgRm9udCBzaXplIHRvIHVzZSBmb3Igcm93cyBhbmQgY29sdW1uIGxhYmVscwojJyBAcGFyYW0gY29sX2Z1biBDb2xvciBmdW5jdGlvbiBmb3IgdGhlIGhlYXRtYXAgcGFsZXR0ZS4gRGVmYXVsdCBpcyBgaGVhdG1hdF9jb2xfZnVuYAojJyBAcGFyYW0gLi4uIEFkZGl0aW9uYWwgYXJndW1lbnRzIHRvIHBhc3MgdG8gYENvbXBsZXhIZWF0bWFwOjpIZWF0bWFwKClgCiMnCiMnIEByZXR1cm4gQSBsaXN0IG9mIENvbXBsZXhIZWF0bWFwIG9iamVjdHMKY3JlYXRlX2hlYXRtYXBfbGlzdCA8LSBmdW5jdGlvbigKICAgIG1hdHJpeF9saXN0LAogICAgY29sdW1uX3RpdGxlLAogICAgbGFiZWxzX2ZvbnRfc2l6ZSwKICAgIGNvbF9mdW4gPSBoZWF0bWFwX2NvbF9mdW4sCiAgICAuLi4pIHsKICAjIFdlIG9ubHkgd2FudCBvbmUgc2hhcmVkIGxlZ2VuZCBpbiB0aGUgZW5kLCBhcmJpdHJhcmlseSBncmFiIHRoZSBmaXJzdCBvbmUKICBrZWVwX2xlZ2VuZF9uYW1lIDwtIG5hbWVzKG1hdHJpeF9saXN0KVsxXQoKICBoZWF0bWFwX2xpc3QgPC0gbWF0cml4X2xpc3QgfD4KICAgIHB1cnJyOjppbWFwKAogICAgICBcKG1hdCwgbmFtZSkgY3JlYXRlX3NpbmdsZV9oZWF0bWFwKAogICAgICAgIG1hdCwKICAgICAgICBuYW1lLAogICAgICAgIGNvbHVtbl90aXRsZSwKICAgICAgICBsYWJlbHNfZm9udF9zaXplLAogICAgICAgIGtlZXBfbGVnZW5kX25hbWUsCiAgICAgICAgY29sX2Z1biwKICAgICAgICAuLi4KICAgICAgKQogICAgKSB8PgogICAgIyBjb25jYXRlbmF0ZSB2ZXJ0aWNhbGx5IGludG8gSGVhdG1hcExpc3Qgb2JqZWN0CiAgICBwdXJycjo6cmVkdWNlKENvbXBsZXhIZWF0bWFwOjpgJXYlYCkKCiAgcmV0dXJuKGhlYXRtYXBfbGlzdCkKfQoKCiMnIERldGVybWluZSB0aGUgbGFiZWwgZm9udCBzaXplIGJhc2VkIG9uICMgY2hhcmFjdGVycyBpbiBjZWxsIHR5cGUgbGFiZWxzCiMnCiMnIEBwYXJhbSBpbnB1dF9sYWJlbHMgVmVjdG9yIG9mIGNlbGwgdHlwZSBsYWJlbHMKIycKIycgQHJldHVybiBGb250IHNpemUgbnVtZXJpYyBhcyBkZXRlcm1pbmVkIGJ5IGxvbmdlc3QgY2VsbCB0eXBlIGxhYmVsCmZpbmRfbGFiZWxfc2l6ZSA8LSBmdW5jdGlvbihpbnB1dF9sYWJlbHMpIHsKICBsb25nZXN0X25hbWUgPC0gaW5wdXRfbGFiZWxzIHw+CiAgICBzdHJpbmdyOjpzdHJfbGVuZ3RoKCkgfD4KICAgIG1heCgpCgogIGxhYmVsc19mb250X3NpemUgPC0gZHBseXI6OmNhc2Vfd2hlbigKICAgIGxvbmdlc3RfbmFtZSA8IDM1IH4gOS41LAogICAgbG9uZ2VzdF9uYW1lIDwgNDUgfiA4LjUsCiAgICBsb25nZXN0X25hbWUgPCA2MCB+IDcuNSwKICAgIC5kZWZhdWx0ID0gNi41CiAgKQoKICByZXR1cm4obGFiZWxzX2ZvbnRfc2l6ZSkKfQpgYGAKCgpgYGB7cn0KIycgRnVuY3Rpb24gdG8gY2FsY3VsYXRlIG9wdGltYWwgaGVhdG1hcCBwbG90IHZpZXcgaGVpZ2h0CiMnCiMnIEBwYXJhbSByb3dfbmFtZXMgVmVjdG9yIG9mIHJvd25hbWVzCiMnIEBwYXJhbSBjb2xfbmFtZXMgVmVjdG9yIG9mIGNvbHVtbiBuYW1lcwojJyBAcGFyYW0gbl9zcGFjZXJzIE51bWJlciBvZiBzcGFjZXJzIGJldHdlZW4gc3RhY2tlZCBoZWF0bWFwcwojJyBAcGFyYW0gc3BhY2VyX3NpemUgU3BhY2VyIHNpemUgaW4gaW5jaGVzCiMnIEBwYXJhbSBtaW5faGVpZ2h0IE1pbmltaXplIGhlaWdodCByZXF1aXJlZC4gRGVmYXVsdCA0IgojJwojJyBAcmV0dXJuIEhlYXRtYXAgaGVpZ2h0IGluIGluY2hlcwpjYWxjdWxhdGVfcGxvdF9oZWlnaHQgPC0gZnVuY3Rpb24oCiAgICByb3dfbmFtZXMsCiAgICBjb2xfbmFtZXMsCiAgICBuX3NwYWNlcnMsCiAgICBzcGFjZXJfc2l6ZSA9IGhlYXRtYXBfcGFkZGluZywKICAgIG1pbl9oZWlnaHQgPSA0KSB7CiAgIyBmaXJzdCwgYmFzZWQgb24gbnVtYmVyIG9mIGNlbGxzIGluIHJvd19uYW1lczoKICAjICAgNiBjZWxsIHR5cGVzIHRvIGFuIGluY2gKICBoZWF0X2hlaWdodCA8LSBsZW5ndGgocm93X25hbWVzKSAvIDYKCiAgIyBuZXh0LCBiYXNlZCBvbiBuY2hhciBvZiBjb2xfbmFtZXM6CiAgIyAgIDEwIGNoYXJhY3RlcnMgdG8gYW4gaW5jaAogICMgdXNpbmcgc3RyaW5ncjo6c3RyX2xlbmd0aCgpIGluIGNhc2UgY29sX25hbWVzIGlzIGEgZmFjdG9yIHZlY3RvcgogIGhlYXRfaGVpZ2h0IDwtIGhlYXRfaGVpZ2h0ICsgbWF4KHN0cmluZ3I6OnN0cl9sZW5ndGgoY29sX25hbWVzKSkgLyAxMAoKICAjIGZpbmFsbHksIGFkZCBpbiBhbnkgcGFkZGluZwogIGhlYXRfaGVpZ2h0IDwtIGhlYXRfaGVpZ2h0ICsgbl9zcGFjZXJzICogc3BhY2VyX3NpemUKCiAgcmV0dXJuKAogICAgbWF4KGMobWluX2hlaWdodCwgaGVhdF9oZWlnaHQpKQogICkKfQpgYGAKCgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGVjaG8gPSBGQUxTRX0KIyBkZWZpbmUgbGlicmFyeSBhbmQgc2NlIG9iamVjdApsaWJyYXJ5X2lkIDwtIHBhcmFtcyRsaWJyYXJ5CnByb2Nlc3NlZF9zY2UgPC0gcGFyYW1zJHByb2Nlc3NlZF9zY2UKCiMgY2hlY2sgZm9yIGFubm90YXRpb24gbWV0aG9kcwpoYXNfc2luZ2xlciA8LSAic2luZ2xlciIgJWluJSBtZXRhZGF0YShwcm9jZXNzZWRfc2NlKSRjZWxsdHlwZV9tZXRob2RzCmhhc19jZWxsYXNzaWduIDwtICJjZWxsYXNzaWduIiAlaW4lIG1ldGFkYXRhKHByb2Nlc3NlZF9zY2UpJGNlbGx0eXBlX21ldGhvZHMKaGFzX3N1Ym1pdHRlciA8LSAic3VibWl0dGVyIiAlaW4lIG1ldGFkYXRhKHByb2Nlc3NlZF9zY2UpJGNlbGx0eXBlX21ldGhvZHMgJiYKICAhYWxsKGlzLm5hKHByb2Nlc3NlZF9zY2Ukc3VibWl0dGVyX2NlbGx0eXBlX2Fubm90YXRpb24pKSAjIG1ha2Ugc3VyZSB0aGV5IGFyZW4ndCBhbGwgTkEKCiMgY2hlY2sgZm9yIHVtYXAKaGFzX3VtYXAgPC0gIlVNQVAiICVpbiUgcmVkdWNlZERpbU5hbWVzKHByb2Nlc3NlZF9zY2UpCgojIHdoYXQgY2VsbHR5cGVzIGFyZSBhdmFpbGFibGU/CmF2YWlsYWJsZV9jZWxsdHlwZXMgPC0gYygKICBpZmVsc2UoaGFzX3N1Ym1pdHRlciwgIlN1Ym1pdHRlciIsIE5BKSwKICBpZmVsc2UoaGFzX3NpbmdsZXIsICJTaW5nbGVSIiwgTkEpLAogIGlmZWxzZShoYXNfY2VsbGFzc2lnbiwgIkNlbGxBc3NpZ24iLCBOQSkKKSB8PgogIG5hLm9taXQoKSB8PgogIGFzLmNoYXJhY3RlcigpCgojIHdhcyBjZWxsYXNzaWduIHJ1bj8KY2VsbGFzc2lnbl9ub3RfcnVuIDwtIGNoZWNrX2NlbGxhc3NpZ25fbm90X3J1bigKICBoYXNfY2VsbGFzc2lnbiwKICBjb2xEYXRhKHByb2Nlc3NlZF9zY2UpCikKCiMgVGhpcyB2YXJpYWJsZSBuZWVkIHRvIGJlIGRlZmluZWQgZm9yIGVkZ2UgY29uZGl0aW9ucyB3aGVuIGNlcnRhaW4gY2VsbCB0eXBlcwojICBhcmVuJ3QgYXZhaWxhYmxlOgojICBXaGVuIHdlIGhhdmUgY2h1bmtzIHdpdGggYGV2YWw9PGhhc19tZXRob2Q+YCwga25pdHIgc2VlbXMgdG8gbmVlZCBhbGwgb3RoZXIKIyAgdmFyaWFibGVzIHVzZWQgaW4gY2h1bmsgcGFyYW1zIGRlZmluZWQsIGluY2x1ZGluZyBwbG90IGRpbWVuc2lvbiB2YXJpYWJsZXMKIyAgd2hpY2ggd291bGQgaGF2ZSBvbmx5IGJlZW4gY3JlYXRlZCBpbiBjaHVua3Mgd2hpY2ggYWxzbyBoYWQgYW4gYXNzb2NpYXRlZAojICBldmFsPTxoYXNfbWV0aG9kPmAuIFNpbmNlIHRob3NlIGNodW5rcyB3b24ndCBoYXZlIGJlZW4gZXZhbCdkIGlmIEZBTFNFLCB3ZQojICBuZWVkIHRvIGRlZmluZSB0aGlzIHZhcmlhYmxlIHRvIHByZXZlbnQgZXJyb3JzLCBidXQgdGhpcyB2YWx1ZSB3aWxsIG5ldmVyCiMgIGFjdHVhbGx5IGJlIHVzZWQuCnBsb3RfaGVpZ2h0IDwtIDEKCiMgRGV0ZXJtaW5lIGlmIGxpYnJhcnkgaXMgbXVsdGlwbGV4ZWQ6CiMgIHNhbXBsZV9pZCBzaG91bGQgYmUgZGVmaW5lZCB3aXRoIGxlbmd0aCA+IDEKc2FtcGxlX2lkIDwtIG1ldGFkYXRhKHByb2Nlc3NlZF9zY2UpJHNhbXBsZV9pZApoYXNfbXVsdGlwbGV4IDwtIGxlbmd0aChzYW1wbGVfaWQpID4gMQoKIyBkZXRlcm1pbmUgVU1BUCBwb2ludCBzaXppbmcKdW1hcF9wb2ludHNfc2l6ZXMgPC0gZGV0ZXJtaW5lX3VtYXBfcG9pbnRfc2l6ZShuY29sKHByb2Nlc3NlZF9zY2UpKQp1bWFwX3BvaW50X3NpemUgPC0gdW1hcF9wb2ludHNfc2l6ZXNbMV0KdW1hcF9mYWNldF9wb2ludF9zaXplIDwtIHVtYXBfcG9pbnRzX3NpemVzWzJdCmBgYAoKPCEtLSBJZiBtdWx0aXBsZXhlZCwgb3BlbiB3aXRoIHdhcm5pbmcgIC0tPiAKYGBge3IsIGV2YWwgPSBoYXNfbXVsdGlwbGV4LCByZXN1bHRzPSdhc2lzJ30KIyBjb252ZXJ0IHNhbXBsZSBpZCB0byBidWxsZXQgc2VwYXJhdGVkIGxpc3QKbXVsdGlwbGV4X3NhbXBsZXMgPC0gcGFzdGUwKCI8bGk+IiwgcGFzdGUoc2FtcGxlX2lkLCBjb2xsYXBzZSA9ICI8L2xpPjxsaT4iLCAiPC9saT4iKSkKZ2x1ZTo6Z2x1ZSgiCiA8ZGl2IGNsYXNzPVwiYWxlcnQgYWxlcnQtd2FybmluZ1wiPgoKIFRoaXMgbGlicmFyeSBpcyBtdWx0aXBsZXhlZCBhbmQgY29udGFpbnMgZGF0YSBmcm9tIG1vcmUgdGhhbiBvbmUgc2FtcGxlLgogRGF0YSBmcm9tIHRoZSBmb2xsb3dpbmcgc2FtcGxlcyBhcmUgaW5jbHVkZWQgaW4gdGhpcyBsaWJyYXJ5OgoKICAgIHttdWx0aXBsZXhfc2FtcGxlc30KCiAgPC9kaXY+CiIpCmBgYAoKVGhpcyByZXBvcnQgY29udGFpbnMgYSBzdW1tYXJ5IG9mIGNlbGwgdHlwZSBhbm5vdGF0aW9uIHJlc3VsdHMgZm9yIGxpYnJhcnkgYHIgbGlicmFyeV9pZGAuClRoZSBnb2FsIG9mIHRoaXMgcmVwb3J0IGlzIHRvIHByb3ZpZGUgbW9yZSBkZXRhaWxlZCBpbmZvcm1hdGlvbiBhYm91dCBjZWxsIHR5cGUgYW5ub3RhdGlvbiByZXN1bHRzIGFzIGFuIGluaXRpYWwgZXZhbHVhdGlvbiBvZiB0aGVpciBxdWFsaXR5IGFuZCByZWxpYWJpbGl0eS4KClBlcmZvcm1pbmcgY2VsbCB0eXBlIGFubm90YXRpb24gaXMgYW4gaW5oZXJlbnRseSBjaGFsbGVuZ2luZyB0YXNrIHdpdGggaGlnaCBsZXZlbHMgb2YgdW5jZXJ0YWludHksIGVzcGVjaWFsbHkgd2hlbiB1c2luZyBhdXRvbWF0ZWQgYW5ub3RhdGlvbiBtZXRob2RzLgpPbmUgd2F5IHRvIGFkZHJlc3MgdGhpcyBpcyB0byB1c2UgbXVsdGlwbGUgY2VsbCB0eXBlIGFubm90YXRpb24gYXBwcm9hY2hlcyBhbmQgY29tcGFyZSB0aGUgcmVzdWx0cywgYXMgd2UgaGF2ZSBiZWd1biB0byBkbyBpbiB0aGlzIHJlcG9ydC4KCldoZW4gbXVsdGlwbGUgbWV0aG9kcyBhbm5vdGF0ZSBhIGdpdmVuIGNlbGwgYXMgdGhlIHNhbWUgb3Igc2ltaWxhciBjZWxsIHR5cGUsIHRoaXMgbWF5IHF1YWxpdGF0aXZlbHkgaW5kaWNhdGUgYSBtb3JlIHJvYnVzdCBhbm5vdGF0aW9uLgoKTm90ZSB0aGF0IHRoZSBjb250ZW50cyBvZiB0aGlzIHJlcG9ydCB3aWxsIHZhcnkgYmFzZWQgb24gd2hpY2ggY2VsbCB0eXBlIGFubm90YXRpb25zIGFyZSBwcmVzZW50LgpGdXJ0aGVyLCBiZSBhd2FyZSB0aGF0IGRpZmZlcmVudCBjZWxsIHR5cGUgYW5ub3RhdGlvbiBtZXRob2RzIG1heSBhc3NpZ24gZGlmZmVyZW50IGxhYmVscyB0byB0aGUgc2FtZSBvciBzaW1pbGFyIGNlbGwgdHlwZSAoZS5nLiwgdGhlIGRpZmZlcmVudCBzdHJpbmcgcmVwcmVzZW50YXRpb25zIGBCIGNlbGwgbmFpdmVgIGFuZCBgTmFpdmUgQiBjZWxsYCksIGR1ZSB0byB1c2Ugb2YgZGlmZmVyZW50IHVuZGVybHlpbmcgcmVmZXJlbmNlIGRhdGFzZXRzLgpQbGVhc2Ugbm90ZSB0aGF0IGFsbCBjZWxsIHR5cGUgYW5ub3RhdGlvbiByZWZlcmVuY2UgZGF0YXNldHMgYXJlIGRlcml2ZWQgZnJvbSBub3JtYWwgKG5vdCB0dW1vcikgdGlzc3VlLgoKPCEtLU5vdGUgdGhhdCB0aGUgc3BlY2lmaWMgY29udGVudHMgb2YgdGhpcyByZXBvcnQgd2lsbCBkZXBlbmQgb24gd2hpY2ggY2VsbCB0eXBlIGFubm90YXRpb25zIGFyZSBwcmVzZW50Li0tPgoqKlRoaXMgbGlicmFyeSBjb250YWlucyB0aGUgZm9sbG93aW5nIGNlbGwgdHlwZSBhbm5vdGF0aW9uczoqKgoKYGBge3IgcmVzdWx0cz0nYXNpcyd9CiMgYnVpbGQgdXAgdGhpcyBzdHJpbmcgYXMgd2UgZ286Cm1ldGhvZHNfdGV4dCA8LSAiIgoKaWYgKGhhc19zdWJtaXR0ZXIpIHsKICBtZXRob2RzX3RleHQgPC0gZ2x1ZTo6Z2x1ZSgKICAgICJ7bWV0aG9kc190ZXh0fQogICAgKiBTdWJtaXR0ZXItcHJvdmlkZWQgY2VsbCB0eXBlIGFubm90YXRpb24sIGdlbmVyYXRlZCBieSB0aGUgb3JpZ2luYWwgbGFiIHdoaWNoIHByb2R1Y2VkIHRoaXMgZGF0YS5cbiIKICApCn0KCmlmIChoYXNfc2luZ2xlcikgewogIG1ldGhvZHNfdGV4dCA8LSBnbHVlOjpnbHVlKAogICAgInttZXRob2RzX3RleHR9CiAgICAqIEFubm90YXRpb25zIGZyb20gW2BTaW5nbGVSYF0oaHR0cHM6Ly9iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL3JlbGVhc2UvYmlvYy9odG1sL1NpbmdsZVIuaHRtbCksIGEgcmVmZXJlbmNlLWJhc2VkIGFwcHJvYWNoIChbTG9vbmV5IF9ldCBhbC5fIDIwMTldKGh0dHBzOi8vZG9pLm9yZy8xMC4xMDM4L3M0MTU5MC0wMTgtMDI3Ni15KSkuCiAgICBUaGUgYHttZXRhZGF0YShwcm9jZXNzZWRfc2NlKSRzaW5nbGVyX3JlZmVyZW5jZX1gIGRhdGFzZXQsIG9idGFpbmVkIGZyb20gdGhlIFtgY2VsbGRleGAgcGFja2FnZV0oaHR0cDovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvcmVsZWFzZS9kYXRhL2V4cGVyaW1lbnQvaHRtbC9jZWxsZGV4Lmh0bWwpLCB3YXMgdXNlZCBmb3IgcmVmZXJlbmNlIGFubm90YXRpb25zLlxuIgogICkKfQoKaWYgKGhhc19jZWxsYXNzaWduKSB7CiAgb3JnYW5zIDwtIG1ldGFkYXRhKHByb2Nlc3NlZF9zY2UpJGNlbGxhc3NpZ25fcmVmZXJlbmNlX29yZ2FucyB8PgogICAgc3RyaW5ncjo6c3RyX3RvX2xvd2VyKCkKICAjIHNwbGl0IHVwIGFuZCBhZGQgYW4gYGFuZGAgYmVmb3JlIHRoZSBmaW5hbCBvcmdhbgogIG9yZ2Fuc19zdHJpbmcgPC0gc3RyaW5ncjo6c3RyX3NwbGl0XzEob3JnYW5zLCBwYXR0ZXJuID0gIiwgIikgfD4KICAgIHN0cmluZ3I6OnN0cl9mbGF0dGVuX2NvbW1hKGxhc3QgPSAiLCBhbmQgIikKCiAgcmVmX25hbWUgPC0gbWV0YWRhdGEocHJvY2Vzc2VkX3NjZSkkY2VsbGFzc2lnbl9yZWZlcmVuY2UKCiAgbWV0aG9kc190ZXh0IDwtIGdsdWU6OmdsdWUoCiAgICAie21ldGhvZHNfdGV4dH0KICAgICogQW5ub3RhdGlvbnMgZnJvbSBbYENlbGxBc3NpZ25gXShodHRwczovL2dpdGh1Yi5jb20vSXJyYXRpb25vbmUvY2VsbGFzc2lnbiksIGEgbWFya2VyLWdlbmUtYmFzZWQgYXBwcm9hY2ggKFtaaGFuZyBfZXQgYWwuXyAyMDE5XShodHRwczovL2RvaS5vcmcvMTAuMTAzOC9zNDE1OTItMDE5LTA1MjktMSkpLgogICAgTWFya2VyIGdlbmVzIGZvciBjZWxsIHR5cGVzIHdlcmUgb2J0YWluZWQgZnJvbSBbUGFuZ2xhb0RCXShodHRwczovL3BhbmdsYW9kYi5zZS8pIGFuZCBjb21waWxlZCBpbnRvIGEgcmVmZXJlbmNlIG5hbWVkIGB7cmVmX25hbWV9YC4KICAgIFRoaXMgcmVmZXJlbmNlIGluY2x1ZGVzIHRoZSBmb2xsb3dpbmcgb3JnYW5zIGFuZCB0aXNzdWUgY29tcGFydG1lbnRzOiB7b3JnYW5zX3N0cmluZ30uXG4iCiAgKQp9CgpnbHVlOjpnbHVlKCJ7bWV0aG9kc190ZXh0fSIpCmBgYAoKYGBge3IgZXZhbD1jZWxsYXNzaWduX25vdF9ydW4sIHJlc3VsdHM9J2FzaXMnfQpnbHVlOjpnbHVlKCIKICAgPGRpdiBjbGFzcz1cImFsZXJ0IGFsZXJ0LWluZm9cIj4KICAgQ2VsbCB0eXBlIGFubm90YXRpb24gd2l0aCBbYENlbGxBc3NpZ25gXShodHRwczovL2dpdGh1Yi5jb20vSXJyYXRpb25vbmUvY2VsbGFzc2lnbiksIGEgbWFya2VyLWdlbmUtYmFzZWQgYXBwcm9hY2ggKFtaaGFuZyBfZXQgYWwuXyAyMDE5XShodHRwczovL2RvaS5vcmcvMTAuMTAzOC9zNDE1OTItMDE5LTA1MjktMSkpLCB3YXMgYXR0ZW1wdGVkIGJ1dCBub3QgcnVuIGR1ZSB0byBhbiBpbnN1ZmZpY2llbnQgbnVtYmVyIG9mIGNlbGxzLgogIDwvZGl2PgoiKQpgYGAKCgo8IS0tLS0tLS0gQ2FsbCB0aGUgY2VsbHR5cGVzX3FjIHJlcG9ydCBzZWN0aW9uIGZyb20gdGhlIG1haW4gcmVwb3J0IC0tLS0tLS0tLS0tPgpgYGB7ciwgY2hpbGQ9J2NlbGx0eXBlc19xYy5ybWQnfQpgYGAKCgojIENlbGwgbGFiZWwgY29tcGFyaXNvbiBwbG90cwoKVGhpcyBzZWN0aW9uIGRpc3BsYXlzIGhlYXRtYXBzIGNvbXBhcmluZyBjZWxsIGxhYmVscyBmcm9tIHZhcmlvdXMgbWV0aG9kcy4KCldlIHVzZSB0aGUgW0phY2NhcmQgc2ltaWxhcml0eSBpbmRleF0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvSmFjY2FyZF9pbmRleCkgdG8gZGlzcGxheSB0aGUgYWdyZWVtZW50IGJldHdlZW4gYmV0d2VlbiBwYWlycyBvZiBsYWJlbHMgYXNzaWduZWQgYnkgZGlmZmVyZW50IGFubm90YXRpb24gbWV0aG9kcy4KClRoZSBKYWNjYXJkIGluZGV4IHJlZmxlY3RzIHRoZSBkZWdyZWUgb2Ygb3ZlcmxhcCBiZXR3ZWVuIHRoZSB0d28gbGFiZWxzIGFuZCByYW5nZXMgZnJvbSAwIHRvIDEuCgoqIElmIHRoZSBsYWJlbHMgYXJlIGFzc2lnbmVkIHRvIGlkZW50aWNhbCBzZXRzIG9mIGNlbGxzLCB0aGUgSmFjY2FyZCBpbmRleCB3aWxsIGJlIDEuCiogSWYgdGhlIGxhYmVscyBhcmUgYXNzaWduZWQgdG8gY29tcGxldGVseSBub24tb3ZlcmxhcHBpbmcgc2V0cyBvZiBjZWxscywgdGhlIEphY2NhcmQgaW5kZXggd2lsbCBiZSAwLgoKSGlnaCBhZ3JlZW1lbnQgYmV0d2VlbiBtZXRob2RzIHF1YWxpdGF0aXZlbHkgaW5kaWNhdGVzIGhpZ2hlciBjb25maWRlbmNlIGluIHRoZSBjZWxsIHR5cGUgYW5ub3RhdGlvbi4KCgoKCgo8IS0tIElmIG11bHRpcGxleGVkLCBzaG93IGluZm8gYWxlcnQgaW5zdGVhZCBvZiB0aGlzIGhlYXRtYXAgLS0+IApgYGB7ciwgZXZhbCA9IGhhc19tdWx0aXBsZXgsIHJlc3VsdHM9J2FzaXMnfQpnbHVlOjpnbHVlKCIKIDxkaXYgY2xhc3M9XCJhbGVydCBhbGVydC1pbmZvXCI+CgogIE5vIGhlYXRtYXAgY29tcGFyaW5nIGNsdXN0ZXIgYW5kIGNlbGwgdHlwZSBhbm5vdGF0aW9uIGxhYmVscyBpcyBzaG93biBiZWNhdXNlIHRoZSBwcmVzZW5jZSBvZiBtdWx0aXBsZSBzYW1wbGVzIG1heSBjb25mb3VuZCBjbHVzdGVyIGFzc2lnbm1lbnQuCgogIDwvZGl2PgoiKQpgYGAKCjwhLS0gSWYgbm90IG11bHRpcGxleGVkLCBzaG93IHRoZSBoZWFkZXIsIHRleHQsIGFuZCBoZWF0bWFwIC0tPiAKYGBge3IsIGV2YWwgPSAhaGFzX211bHRpcGxleCwgcmVzdWx0cz0nYXNpcyd9CmdsdWU6OmdsdWUoIgogICMjIFVuc3VwZXJ2aXNlZCBjbHVzdGVyaW5nCgogIEhlcmUgd2Ugc2hvdyB0aGUgbGFiZWxzIGZyb20gdW5zdXBlcnZpc2VkIGNsdXN0ZXJpbmcgY29tcGFyZWQgdG8gY2VsbCB0eXBlIGFubm90YXRpb25zLgogIENsdXN0ZXIgYXNzaWdubWVudCB3YXMgcGVyZm9ybWVkIHVzaW5nIHRoZSBge21ldGFkYXRhKHByb2Nlc3NlZF9zY2UpJGNsdXN0ZXJfYWxnb3JpdGhtfWAgYWxnb3JpdGhtLgoiKQoKIyBDYWxjdWxhdGUgYWxsIGphY2NhcmQgbWF0cmljZXMgb2YgaW50ZXJlc3QgZm9yIGlucHV0IHRvIGhlYXRtYXAKamFjY2FyZF9jbHVzdGVyX21hdHJpY2VzIDwtIGF2YWlsYWJsZV9jZWxsdHlwZXMgfD4KICBzdHJpbmdyOjpzdHJfdG9fbG93ZXIoKSB8PgogIHB1cnJyOjpzZXRfbmFtZXMoYXZhaWxhYmxlX2NlbGx0eXBlcykgfD4KICBwdXJycjo6bWFwKFwobmFtZSkgewogICAgbWFrZV9qYWNjYXJkX21hdHJpeCgKICAgICAgY2VsbHR5cGVfZGYsCiAgICAgICJjbHVzdGVyIiwKICAgICAgZ2x1ZTo6Z2x1ZSgie25hbWV9X2NlbGx0eXBlX2Fubm90YXRpb24iKQogICAgKQogIH0pCgphbGxfY2VsbHR5cGVzIDwtIGphY2NhcmRfY2x1c3Rlcl9tYXRyaWNlcyB8PgogIHB1cnJyOjptYXAoY29sbmFtZXMpIHw+CiAgdW5saXN0KCkKCnBsb3RfaGVpZ2h0IDwtIGNhbGN1bGF0ZV9wbG90X2hlaWdodCgKICBhbGxfY2VsbHR5cGVzLAogIHVuaXF1ZShjZWxsdHlwZV9kZiRjbHVzdGVyKSwKICBsZW5ndGgoamFjY2FyZF9jbHVzdGVyX21hdHJpY2VzKSAtIDEKKQpgYGAKCgpgYGB7ciwgZXZhbCA9ICFoYXNfbXVsdGlwbGV4LCBmaWcuaGVpZ2h0ID0gcGxvdF9oZWlnaHQsIGZpZy53aWR0aCA9IDguNSwgd2FybmluZyA9IEZBTFNFfQpqYWNjYXJkX2NsdXN0ZXJfbWF0cmljZXMgfD4KICBjcmVhdGVfaGVhdG1hcF9saXN0KAogICAgY29sdW1uX3RpdGxlID0gIkNsdXN0ZXJzIiwKICAgIGxhYmVsc19mb250X3NpemUgPSBmaW5kX2xhYmVsX3NpemUoYWxsX2NlbGx0eXBlcyksCiAgICAjIyBhZGRpdGlvbmFsIGFyZ3VtZW50cwogICAgY29sdW1uX25hbWVzX3JvdCA9IDAKICApIHw+CiAgQ29tcGxleEhlYXRtYXA6OmRyYXcoCiAgICBoZWF0bWFwX2xlZ2VuZF9zaWRlID0gImJvdHRvbSIKICApCmBgYAoKCgo8IS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIFN1Ym1pdHRlciBoZWF0bWFwcyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tPgpgYGB7ciwgZXZhbCA9IGhhc19zdWJtaXR0ZXIgJiAoaGFzX2NlbGxhc3NpZ24gfCBoYXNfc2luZ2xlcil9CiMgZG9uJ3QgY29tcGFyZSBzdWJtaXR0ZXIgdG8gc3VibWl0dGVyCmF2YWlsYWJsZV9jZWxsdHlwZXMgPC0gYXZhaWxhYmxlX2NlbGx0eXBlc1shKGF2YWlsYWJsZV9jZWxsdHlwZXMgPT0gIlN1Ym1pdHRlciIpXQoKbWV0aG9kc19zdHJpbmcgPC0gYXZhaWxhYmxlX2NlbGx0eXBlcyB8PgogIHN0cmluZ3I6OnN0cl9yZXBsYWNlX2FsbCgiXiIsICJgIikgfD4KICBzdHJpbmdyOjpzdHJfcmVwbGFjZV9hbGwoIiQiLCAiYCIpIHw+CiAgc3RyaW5ncjo6c3RyX2ZsYXR0ZW5fY29tbWEoIiwgYW5kICIpCgprbml0cjo6YXNpc19vdXRwdXQoCiAgZ2x1ZTo6Z2x1ZSgKICAgICIjIyBTdWJtaXR0ZXItcHJvdmlkZWQgYW5ub3RhdGlvbnMKCiAgVGhpcyBzZWN0aW9uIGRpc3BsYXlzIGhlYXRtYXBzIGNvbXBhcmluZyBzdWJtaXR0ZXItcHJvdmlkZWQgY2VsbCB0eXBlIGFubm90YXRpb25zIHRvIHRob3NlIG9idGFpbmVkIGZyb20ge21ldGhvZHNfc3RyaW5nfS4iCiAgKQopCmBgYAoKYGBge3IsIGV2YWwgPSBoYXNfc3VibWl0dGVyICYgKGhhc19jZWxsYXNzaWduIHwgaGFzX3NpbmdsZXIpfQojIGNhbGN1bGF0ZSBtYXRyaWNlcyBjb21wYXJpbmcgdG8gc3VibWl0dGVyCmphY2NhcmRfc3VibWl0dGVyX21hdHJpY2VzIDwtIGF2YWlsYWJsZV9jZWxsdHlwZXMgfD4KICBzdHJpbmdyOjpzdHJfdG9fbG93ZXIoKSB8PgogIHB1cnJyOjptYXAoXChuYW1lKSB7CiAgICBtYWtlX2phY2NhcmRfbWF0cml4KAogICAgICBjZWxsdHlwZV9kZiwKICAgICAgInN1Ym1pdHRlcl9jZWxsdHlwZV9hbm5vdGF0aW9uIiwKICAgICAgZ2x1ZTo6Z2x1ZSgie25hbWV9X2NlbGx0eXBlX2Fubm90YXRpb24iKQogICAgKQogIH0pIHw+CiAgcHVycnI6OnNldF9uYW1lcyhhdmFpbGFibGVfY2VsbHR5cGVzKQoKIyBob3cgbWFueSBjZWxsIHR5cGVzPwphbGxfY2VsbHR5cGVzIDwtIGphY2NhcmRfc3VibWl0dGVyX21hdHJpY2VzIHw+CiAgcHVycnI6Om1hcChjb2xuYW1lcykgfD4KICB1bmxpc3QoKQoKcGxvdF9oZWlnaHQgPC0gY2FsY3VsYXRlX3Bsb3RfaGVpZ2h0KAogIGFsbF9jZWxsdHlwZXMsCiAgdW5pcXVlKGNlbGx0eXBlX2RmJHN1Ym1pdHRlcl9jZWxsdHlwZV9hbm5vdGF0aW9uKSwKICBsZW5ndGgoamFjY2FyZF9zdWJtaXR0ZXJfbWF0cmljZXMpIC0gMQopCmBgYAoKYGBge3IsIGV2YWwgPSBoYXNfc3VibWl0dGVyICYgKGhhc19jZWxsYXNzaWduIHwgaGFzX3NpbmdsZXIpLCBmaWcuaGVpZ2h0ID0gcGxvdF9oZWlnaHQsIGZpZy53aWR0aCA9IDguNSwgd2FybmluZyA9IEZBTFNFfQpqYWNjYXJkX3N1Ym1pdHRlcl9tYXRyaWNlcyB8PgogIGNyZWF0ZV9oZWF0bWFwX2xpc3QoCiAgICBjb2x1bW5fdGl0bGUgPSAiU3VibWl0dGVyLXByb3ZpZGVkIGFubm90YXRpb25zIiwKICAgIGxhYmVsc19mb250X3NpemUgPSBmaW5kX2xhYmVsX3NpemUoYWxsX2NlbGx0eXBlcyksCiAgICAjIGFkZGl0aW9uYWwgYXJndW1lbnRzCiAgICBjb2x1bW5fbmFtZXNfcm90ID0gOTAKICApIHw+CiAgQ29tcGxleEhlYXRtYXA6OmRyYXcoCiAgICBoZWF0bWFwX2xlZ2VuZF9zaWRlID0gImJvdHRvbSIKICApCmBgYAoKCjwhLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBTaW5nbGVSL0NlbGxBc3NpZ24gaGVhdG1hcCAgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0+CmBgYHtyLCBldmFsID0gaGFzX2NlbGxhc3NpZ24gJiBoYXNfc2luZ2xlciwgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9OH0Ka25pdHI6OmFzaXNfb3V0cHV0KCIKIyMgQXV0b21hdGVkIGFubm90YXRpb25zCgpUaGlzIHNlY3Rpb24gZGlzcGxheXMgYSBoZWF0bWFwIGRpcmVjdGx5IGNvbXBhcmluZyBgU2luZ2xlUmAgYW5kIGBDZWxsQXNzaWduYCBjZWxsIHR5cGUgYW5ub3RhdGlvbnMuCk5vdGUgdGhhdCBkdWUgdG8gZGlmZmVyZW50IGFubm90YXRpb25zIHJlZmVyZW5jZXMsIHRoZXNlIG1ldGhvZHMgbWF5IHVzZSBkaWZmZXJlbnQgbmFtZXMgZm9yIHNpbWlsYXIgY2VsbCB0eXBlcy4KIikKCiMgU2V0IHBsb3QgZGltZW5zaW9ucyBiYXNlZCBvbiBudW1iZXIgb2YgU2luZ2xlUiBjZWxsIHR5cGVzCmFsbF9jZWxsdHlwZXMgPC0gbGV2ZWxzKGNlbGx0eXBlX2RmJHNpbmdsZXJfY2VsbHR5cGVfYW5ub3RhdGlvbikKcGxvdF9oZWlnaHQgPC0gY2FsY3VsYXRlX3Bsb3RfaGVpZ2h0KAogIHVuaXF1ZShjZWxsdHlwZV9kZiRzaW5nbGVyX2NlbGx0eXBlX2Fubm90YXRpb24pLAogIHVuaXF1ZShjZWxsdHlwZV9kZiRjZWxsYXNzaWduX2NlbGx0eXBlX2Fubm90YXRpb24pLAogIDAKKQpgYGAKCgpgYGB7ciwgZXZhbCA9IGhhc19jZWxsYXNzaWduICYgaGFzX3NpbmdsZXIsIGZpZy5oZWlnaHQgPSBwbG90X2hlaWdodCwgZmlnLndpZHRoID0gOC41fQojIENhbGN1bGF0ZSBqYWNjYXJkIG1hdHJpeApzaW5nbGVyX2NlbGxhc3NpZ25fbWF0cml4IDwtIG1ha2VfamFjY2FyZF9tYXRyaXgoCiAgY2VsbHR5cGVfZGYsCiAgInNpbmdsZXJfY2VsbHR5cGVfYW5ub3RhdGlvbiIsCiAgImNlbGxhc3NpZ25fY2VsbHR5cGVfYW5ub3RhdGlvbiIKKQoKY3JlYXRlX3NpbmdsZV9oZWF0bWFwKAogIHNpbmdsZXJfY2VsbGFzc2lnbl9tYXRyaXgsCiAgcm93X3RpdGxlID0gIkNlbGxBc3NpZ24gYW5ub3RhdGlvbnMiLAogIGNvbHVtbl90aXRsZSA9ICJTaW5nbGVSIGFubm90YXRpb25zIiwKICBsYWJlbHNfZm9udF9zaXplID0gZmluZF9sYWJlbF9zaXplKGFsbF9jZWxsdHlwZXMpLAogIGtlZXBfbGVnZW5kX25hbWUgPSAiQ2VsbEFzc2lnbiBhbm5vdGF0aW9ucyIsCiAgY29sX2Z1biA9IGhlYXRtYXBfY29sX2Z1biwKICAjIGFkZGl0aW9uYWwgYXJndW1lbnRzCiAgY29sdW1uX25hbWVzX3JvdCA9IDkwCikgfD4KICBDb21wbGV4SGVhdG1hcDo6ZHJhdygKICAgIGhlYXRtYXBfbGVnZW5kX3NpZGUgPSAiYm90dG9tIgogICkKYGBgCgo8IS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gRGlhZ25vc3RpYyBwbG90cyAgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tPgpgYGB7ciwgZXZhbCA9IGhhc19zaW5nbGVyIHwgaGFzX2NlbGxhc3NpZ24gfQprbml0cjo6YXNpc19vdXRwdXQoIgojIFF1YWxpdHkgYXNzZXNzbWVudHMgb2YgYXV0b21hdGVkIGFubm90YXRpb25zCiIpCmBgYAoKCjwhLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIFNpbmdsZVIgZGVsdGEgbWVkaWFuICAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0+CmBgYHtyLCBldmFsID0gaGFzX3NpbmdsZXJ9CmtuaXRyOjphc2lzX291dHB1dCgiCiMjIGBTaW5nbGVSYCBhbm5vdGF0aW9ucwoKVG8gYXNzZXNzIHRoZSBxdWFsaXR5IG9mIGBTaW5nbGVSYCBjZWxsIHR5cGUgYW5ub3RhdGlvbnMsIHdlIHVzZSB0aGUgZGVsdGEgbWVkaWFuIHN0YXRpc3RpYy4KCi0gRGVsdGEgbWVkaWFuIGlzIGNhbGN1bGF0ZWQgZm9yIGVhY2ggY2VsbCBhcyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBgU2luZ2xlUmAgc2NvcmUgb2YgdGhlIGFubm90YXRlZCBjZWxsIHR5cGUgbGFiZWwgYW5kIHRoZSBtZWRpYW4gc2NvcmUgb2YgdGhlIG90aGVyIGNlbGwgdHlwZSBsYWJlbHMgaW4gdGhlIHJlZmVyZW5jZSBkYXRhc2V0LgotIEhpZ2hlciBkZWx0YSBtZWRpYW4gdmFsdWVzIGluZGljYXRlIGhpZ2hlciBxdWFsaXR5IGNlbGwgdHlwZSBhbm5vdGF0aW9ucy4KICAtIFZhbHVlcyBjYW4gcmFuZ2UgZnJvbSAwLTEuCiAgLSBOb3RlIHRoYXQgdGhlcmUgaXMgbm8gdW5pdmVyc2FsIHRocmVzaG9sZCBmb3IgY2FsbGluZyBhYnNvbHV0ZSBoaWdoIHZzLiBsb3cgcXVhbGl0eSwgYXMgZGVzY3JpYmVkIGluIHRoZSBbYFNpbmdsZVJgIGJvb2sgc2VjdGlvbiBvbiAnQW5ub3RhdGlvbiBkaWFnbm9zdGljcyddKGh0dHBzOi8vYmlvY29uZHVjdG9yLm9yZy9ib29rcy9yZWxlYXNlL1NpbmdsZVJCb29rL2Fubm90YXRpb24tZGlhZ25vc3RpY3MuaHRtbCNhbm5vdGF0aW9uLWRpYWdub3N0aWNzKS4KCllvdSBjYW4gaW50ZXJwcmV0IHRoaXMgcGxvdCBhcyBmb2xsb3dzOgoKLSBFYWNoIHBvaW50IHJlcHJlc2VudHMgdGhlIGRlbHRhIG1lZGlhbiBzdGF0aXN0aWMgb2YgYSBnaXZlbiBjZWxsIHdob3NlIGBTaW5nbGVSYCBhbm5vdGF0aW9uIGlzIHNob3duIG9uIHRoZSB5LWF4aXMuCi0gVGhlIHBvaW50IHN0eWxlIGluZGljYXRlcyBgU2luZ2xlUmAncyBxdWFsaXR5IGFzc2Vzc21lbnQgb2YgdGhlIGFubm90YXRpb246CiAgLSBIaWdoLXF1YWxpdHkgY2VsbCBhbm5vdGF0aW9ucyBhcmUgc2hvd24gYXMgY2xvc2VkIHBvaW50cy4KICAtIExvdy1xdWFsaXR5IGNlbGwgYW5ub3RhdGlvbnMgYXJlIHNob3duIGFzIG9wZW4gcG9pbnRzLgogIEluIG90aGVyIHNlY3Rpb25zIG9mIHRoaXMgcmVwb3J0LCB0aGVzZSBjZWxscyBhcmUgbGFiZWxlZCBhcyBgVW5rbm93biBjZWxsIHR5cGVzYC4KICAtIEZvciBtb3JlIGluZm9ybWF0aW9uIG9uIGhvdyBgU2luZ2xlUmAgY2FsY3VsYXRlcyBhbm5vdGF0aW9uIHF1YWxpdHksIHBsZWFzZSByZWZlciB0byBbdGhpcyBgU2luZ2xlUmAgZG9jdW1lbnRhdGlvbl0oaHR0cHM6Ly9yZHJyLmlvL2Jpb2MvU2luZ2xlUi9tYW4vcHJ1bmVTY29yZXMuaHRtbCkuCi0gRGlhbW9uZHMgcmVwcmVzZW50IHRoZSBtZWRpYW4gb2YgdGhlIGRlbHRhIG1lZGlhbiBzdGF0aXN0aWMgc3BlY2lmaWNhbGx5IGFtb25nIGhpZ2gtcXVhbGl0eSBhbm5vdGF0aW9ucyBmb3IgdGhlIGdpdmVuIGNlbGwgdHlwZSBhbm5vdGF0aW9uLgoiKQpgYGAKCgpgYGB7ciwgZXZhbCA9IGhhc19zaW5nbGVyLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQojIFByZXBhcmUgU2luZ2xlUiBzY29yZXMgZm9yIHBsb3QKCiMgZXh0cmFjdCBzY29yZXMgaW50byBtYXRyaXgKc2luZ2xlcl9zY29yZXMgPC0gbWV0YWRhdGEocHJvY2Vzc2VkX3NjZSkkc2luZ2xlcl9yZXN1bHQkc2NvcmVzCgojIENyZWF0ZSBkYXRhIGZyYW1lIGZvciBwbG90dGluZyB3aXRoIGRlbHRhIG1lZGlhbiBhbmQgdGhlIGZ1bGwgKm5vbi1wcnVuZWQqIGNlbGwgbGFiZWxzCmRlbHRhX21lZGlhbl9kZiA8LSB0aWJibGU6OnRpYmJsZSgKICBkZWx0YV9tZWRpYW4gPSByb3dNYXhzKHNpbmdsZXJfc2NvcmVzKSAtIHJvd01lZGlhbnMoc2luZ2xlcl9zY29yZXMpLAogICMgTmVlZCB0byBncmFiIHRoZSBub24tcHJ1bmVkIGxhYmVsIGZvciB0aGlzIHBsb3QKICBmdWxsX2xhYmVscyA9IG1ldGFkYXRhKHByb2Nlc3NlZF9zY2UpJHNpbmdsZXJfcmVzdWx0JGxhYmVscywKICAjIGlmIHBydW5lZC5sYWJlbHMgYXJlIE5BID09PiBsb3cgY29uZmlkZW5jZQogICMgc28sIG5lZ2F0ZSBmb3IgdGhpcyB2YXJpYWJsZToKICBjb25maWRlbnQgPSAhaXMubmEobWV0YWRhdGEocHJvY2Vzc2VkX3NjZSkkc2luZ2xlcl9yZXN1bHQkcHJ1bmVkLmxhYmVscykKKSB8PgogIGRwbHlyOjptdXRhdGUoCiAgICBjb25maWRlbnQgPSBpZmVsc2UoY29uZmlkZW50LCAiSGlnaC1xdWFsaXR5IiwgIkxvdy1xdWFsaXR5IikKICApCgojIElmIG9udG9sb2dpZXMgd2VyZSB1c2VkIGZvciBgZnVsbF9sYWJlbHNgLCB3ZSdsbCBuZWVkIHRvIG1hcCBiYWNrIHRvIGNlbGwgdHlwZSBuYW1lcwojICBmb3IgdGhlIHBsb3QgaXRzZWxmLgppZiAoInNpbmdsZXJfY2VsbHR5cGVfb250b2xvZ3kiICVpbiUgbmFtZXMoY2VsbHR5cGVfZGYpKSB7CiAgIyB3ZSB1c2UgaW5uZXJfam9pbiBiL2MgdGhlIGFib3ZlIHRpYmJsZSBkb2VzIE5PVCBjb250YWluICJVbmtub3duIGNlbGwgdHlwZSIsIHdoaWNoCiAgIyAgd2UgZG8gbm90IHdhbnQgdG8gZGlzcGxheSBoZXJlCiAgZGVsdGFfbWVkaWFuX2RmIDwtIGRlbHRhX21lZGlhbl9kZiB8PgogICAgZHBseXI6OmlubmVyX2pvaW4oCiAgICAgIHRpYmJsZTo6dGliYmxlKAogICAgICAgIGZ1bGxfbGFiZWxzID0gY2VsbHR5cGVfZGYkc2luZ2xlcl9jZWxsdHlwZV9vbnRvbG9neSwKICAgICAgICBjZWxsdHlwZSA9IGNlbGx0eXBlX2RmJHNpbmdsZXJfY2VsbHR5cGVfYW5ub3RhdGlvbgogICAgICApIHw+IGRwbHlyOjpkaXN0aW5jdCgpCiAgICApIHw+CiAgICBkcGx5cjo6c2VsZWN0KC1mdWxsX2xhYmVscykKfSBlbHNlIHsKICAjIG90aGVyd2lzZSwgZnVsbF9sYWJlbHMgYWxyZWFkeSBjb250YWluIHdoYXQgd2Ugd2FudCB0byBwbG90LCBzbyBqdXN0IHJlbmFtZSBpdAogIGRlbHRhX21lZGlhbl9kZiA8LSBkZWx0YV9tZWRpYW5fZGYgfD4KICAgIGRwbHlyOjpyZW5hbWUoY2VsbHR5cGUgPSBmdWxsX2xhYmVscykKICAjIHN0aWxsIG5lZWQgdG8gYWRkIGxldmVsczoKICAjIE5vdGUgdGhhdCB0aGUgbGV2ZWwgIlVua25vd24gY2VsbCB0eXBlIiB3aWxsIHN0aWxsIGJlIHByZXNlbnQsIGJ1dCB0aGVyZSBpcyBubyBzdWNoIHZhbHVlIGluIHRoZSBkYXRhLCBzbyBpdCB3b24ndCBtYXR0ZXIKICBsZXZlbHMoZGVsdGFfbWVkaWFuX2RmJGNlbGx0eXBlKSA8LSBsZXZlbHMoY2VsbHR5cGVfZGYkc2luZ2xlcl9jZWxsdHlwZV9hbm5vdGF0aW9uKQp9CgojIEVuc3VyZSB3ZSBoYXZlIG5vICJVbmtub3duIGNlbGwgdHlwZSIgdmFsdWVzIGxlZnQ6CmlmIChhbnkoZGVsdGFfbWVkaWFuX2RmJGNlbGx0eXBlID09ICJVbmtub3duIGNlbGwgdHlwZSIpKSB7CiAgc3RvcCgiRmFpbGVkIHRvIHByb2Nlc3MgU2luZ2xlUiBkYXRhIGZvciBkaWFnbm9zdGljIHBsb3QuIikKfQoKIyBhZGQgY29sdW1uIHdpdGggb3JkZXJlZCBsZXZlbHMgd2l0aCB3cmFwcGVkIGxhYmVscyBmb3IgdmlzdWFsaXphdGlvbgpkZWx0YV9tZWRpYW5fZGYkYW5ub3RhdGlvbl93cmFwcGVkIDwtIGZhY3RvcigKICBkZWx0YV9tZWRpYW5fZGYkY2VsbHR5cGUsCiAgIyByZXYoKSBzbyBsYXJnZSBncm91cHMgYXJlIGF0IHRoZSBUT1Agb2YgdGhlIHBsb3QKICBsZXZlbHMgPSByZXYobGV2ZWxzKGRlbHRhX21lZGlhbl9kZiRjZWxsdHlwZSkpLAogIGxhYmVscyA9IHJldihzdHJpbmdyOjpzdHJfd3JhcChsZXZlbHMoZGVsdGFfbWVkaWFuX2RmJGNlbGx0eXBlKSwgMzApKQopCgojIFN1YnNldCB0aGUgZGF0YSB0byBqdXN0IGNvbmZpZGVudCBwb2ludHMgZm9yIG1lZGlhbisvLUlRUgpkZWx0YV9tZWRpYW5fY29uZmlkZW50X2RmIDwtIGRlbHRhX21lZGlhbl9kZiB8PgogIGRwbHlyOjpmaWx0ZXIoY29uZmlkZW50ID09ICJIaWdoLXF1YWxpdHkiKQoKIyBEZXRlcm1pbmUgaGVpZ2h0IGZvciBwbG90IGFyZWEgYmFzZWQgb24gbnVtYmVyIG9mIGNlbGxzCnBsb3RfaGVpZ2h0IDwtIGxlbmd0aCh1bmlxdWUoZGVsdGFfbWVkaWFuX2RmJGNlbGx0eXBlKSkgLyAyLjUKYGBgCgpgYGB7ciwgZXZhbCA9IGhhc19zaW5nbGVyLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuaGVpZ2h0ID0gcGxvdF9oZWlnaHQsIGZpZy53aWR0aCA9IDh9CiMgUGxvdCBkZWx0YV9tZWRpYW4gYWNyb3NzIGNlbGx0eXBlcyBjb2xvcmVkIGJ5IHBydW5pbmcKZ2dwbG90KGRlbHRhX21lZGlhbl9kZikgKwogIGFlcygKICAgIHggPSBkZWx0YV9tZWRpYW4sCiAgICB5ID0gYW5ub3RhdGlvbl93cmFwcGVkLAogICAgc2hhcGUgPSBjb25maWRlbnQsCiAgICBhbHBoYSA9IGNvbmZpZGVudAogICkgKwogIGdnZm9yY2U6Omdlb21fc2luYSgKICAgIHNpemUgPSAwLjgsCiAgICBjb2xvciA9ICJibGFjayIsICMgd2lsbCBnZXQgYXBwbGllZCB0byBhbGwgY29uZmlkZW50IHBvaW50cyBhbmQgbm9uLWNvbmZpZGVudCBvdXRsaW5lCiAgICBmaWxsID0gIndoaXRlIiwgIyB3aWxsIGFwcGx5IHRvIG5vbi1jb25maWRlbnQgZmlsbCBvbmx5CiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC4wNSkgIyBLZWVwIGJvdGggdHlwZXMgb2YgcG9pbnRzIG1vc3RseSBpbiBsaW5lCiAgKSArCiAgIyBIYW5kbGUgcG9pbnRzIGFlc3RoZXRpY3M6CiAgIyAgY29uZmlkZW50IGFyZSBjbG9zZWQgYmxhY2sgd2l0aCBhbHBoYSA9IDAuNQogICMgIG5vdCBjb25maWRlbnQgYXJlIG9wZW4gYmxhY2sgd2l0aCBhbHBoYSA9IDEKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygxOSwgMjEpKSArCiAgc2NhbGVfYWxwaGFfbWFudWFsKHZhbHVlcyA9IGMoMC41LCAxKSkgKwogIGxhYnMoCiAgICB4ID0gIkRlbHRhIG1lZGlhbiBzdGF0aXN0aWMiLAogICAgeSA9ICJDZWxsIHR5cGUgYW5ub3RhdGlvbiIsCiAgICBzaGFwZSA9ICJDZWxsIHR5cGUgYW5ub3RhdGlvbiBxdWFsaXR5IgogICkgKwogICMgYWRkIG1lZGlhbiBkaWFtb25kIGZvciBjb25maWRlbnQgcG9pbnRzIG9ubHkKICBzdGF0X3N1bW1hcnkoCiAgICBkYXRhID0gZGVsdGFfbWVkaWFuX2NvbmZpZGVudF9kZiwKICAgIGNvbG9yID0gInJlZCIsCiAgICBnZW9tID0gInBvaW50IiwKICAgIGZ1biA9ICJtZWRpYW4iLAogICAgc2hhcGUgPSAxOCwKICAgIHNpemUgPSAyLjI1LAogICAgYWxwaGEgPSAwLjkKICApICsKICBndWlkZXMoCiAgICBhbHBoYSA9IEZBTFNFLAogICAgc2hhcGUgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMS41LCBhbHBoYSA9IDAuNTUpKQogICkgKwogIHRoZW1lKAogICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIKICApCmBgYAoKCjwhLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBDZWxsQXNzaWduIHByb2JhYmlsaXR5IHBsb3QgIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0+CmBgYHtyLCBldmFsID0gaGFzX2NlbGxhc3NpZ259CmtuaXRyOjphc2lzX291dHB1dCgiCiMjIGBDZWxsQXNzaWduYCBhbm5vdGF0aW9ucwoKVG8gYXNzZXNzIHRoZSBxdWFsaXR5IG9mIGBDZWxsQXNzaWduYCBjZWxsIHR5cGUgYW5ub3RhdGlvbnMsIHdlIGNvbnNpZGVyIHRoZSBwcm9iYWJpbGl0eSBhc3NvY2lhdGVkIHdpdGggdGhlIGFubm90YXRlZCBjZWxsIHR5cGUuClRoZXNlIHByb2JhYmlsaXRpZXMgYXJlIHByb3ZpZGVkIGRpcmVjdGx5IGJ5IGBDZWxsQXNzaWduYDoKCi0gYENlbGxBc3NpZ25gIGZpcnN0IGNhbGN1bGF0ZXMgdGhlIHByb2JhYmlsaXR5IG9mIGVhY2ggY2VsbCBiZWluZyBhbm5vdGF0ZWQgYXMgZWFjaCBjZWxsIHR5cGUgcHJlc2VudCBpbiB0aGUgcmVmZXJlbmNlLgotIGBDZWxsQXNzaWduYCB0aGVuIGFubm90YXRlcyBjZWxscyBieSBzZWxlY3RpbmcgdGhlIGNlbGwgdHlwZSB3aXRoIHRoZSBoaWdoZXN0IHByb2JhYmlsaXR5IGFtb25nIGFsbCBjZWxsIHR5cGVzIGNvbnNpZGVyZWQuCi0gVGhlc2UgcHJvYmFiaWxpdGllcyByYW5nZSBmcm9tIDAgdG8gMSwgd2l0aCBsYXJnZXIgdmFsdWVzIGluZGljYXRpbmcgZ3JlYXRlciBjb25maWRlbmNlIGluIGEgZ2l2ZW4gY2VsbCB0eXBlIGxhYmVsLgpXZSB0aGVyZWZvcmUgZXhwZWN0IHJlbGlhYmxlIGxhYmVscyB0byBoYXZlIHZhbHVlcyBjbG9zZSB0byAxLgoKVGhlIHBsb3QgYmVsb3cgc2hvd3MgdGhlIGRpc3RyaWJ1dGlvbiBvZiBgQ2VsbEFzc2lnbmAtY2FsY3VsYXRlZCBwcm9iYWJpbGl0aWVzIGZvciB0aGUgZmluYWwgY2VsbCB0eXBlIGxhYmVscy4KTGluZSBzZWdtZW50cyByZXByZXNlbnQgaW5kaXZpZHVhbCB2YWx1ZXMgdGhhdCBjb21wcmlzZSBlYWNoIGRpc3RyaWJ1dGlvbi4KCkZvciBjZWxsIHR5cGVzIHdpdGggMiBvciBmZXdlciBsYWJlbGVkIGNlbGxzLCBvbmx5IHRoZSBpbmRpdmlkdWFsIHZhbHVlIGxpbmUgc2VnbWVudHMgYXJlIHNob3duLgpMaW5lIHNlZ21lbnRzIGFyZSBhbHNvIHRhbGxlciBmb3IgYW55IGNlbGwgdHlwZSBsYWJlbCB3aXRoIDUgb3IgZmV3ZXIgY2VsbHMuCiIpCgojIERldGVybWluZSBoZWlnaHQgaW4gaW5jaGVzIGZvciBwbG90IGFyZWEKcGxvdF9oZWlnaHQgPC0gY2VpbGluZyhsZW5ndGgodW5pcXVlKGNlbGx0eXBlX2RmJGNlbGxhc3NpZ25fY2VsbHR5cGVfYW5ub3RhdGlvbikpIC8gMi41KQpgYGAKCgpgYGB7ciwgZXZhbCA9IGhhc19jZWxsYXNzaWduLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuaGVpZ2h0ID0gcGxvdF9oZWlnaHQsIGZpZy53aWR0aCA9IDh9CiMgZGVmaW5lIGJhbmR3aWR0aCBmb3IgYWxsIGNhbGN1bGF0aW9ucwpkZW5zaXR5X2J3IDwtIDAuMDMKCiMgZmluZCB0aGUgbWF4aW11bSBkZW5zaXR5IGFjcm9zcyBhbGwgZGlzdHJpYnV0aW9ucywgYW5kCiMgIHNhdmUgdGhlIG1heGltdW0gZm9yIGRldGVybWluaW5nIGdlb21fc2VnbWVudCBoZWlnaHQKeV9tYXggPC0gY2VsbHR5cGVfZGYkY2VsbGFzc2lnbl9tYXhfcHJlZGljdGlvbiB8PgogIHNwbGl0KGNlbGx0eXBlX2RmJGNlbGxhc3NpZ25fY2VsbHR5cGVfYW5ub3RhdGlvbikgfD4KICAjIG1ha2Ugc3VyZSB3ZSBnZXQgcmlkIG9mIGFueSBzbWFsbCBncm91cHMKICBwdXJycjo6ZGlzY2FyZChcKHgpIHN1bShpcy5maW5pdGUoeCkpIDw9IDIpIHw+CiAgIyByZW1vdmUgYW55IE5BJ3MgdGhhdCBtYXkgaGF2ZSBzbGlwcGVkIGluCiAgcHVycnI6Om1hcF9kYmwoCiAgICBcKHgpIG1heChkZW5zaXR5KHgsIGJ3ID0gZGVuc2l0eV9idywgbmEucm0gPSBUUlVFKSR5KQogICkgfD4KICBtYXgobmEucm0gPSBUUlVFKQoKIyBhZGQgY291bnQgdG8gY2VsbHR5cGVfZGYgZm9yIHNldHRpbmcgYWxwaGEgYW5kIHllbmQgdmFsdWVzCmNlbGx0eXBlX2RmIDwtIGNlbGx0eXBlX2RmIHw+CiAgZHBseXI6OmFkZF9jb3VudChjZWxsYXNzaWduX2NlbGx0eXBlX2Fubm90YXRpb24pCgojIG1ha2UgdGhlIHBsb3QhCmdncGxvdChjZWxsdHlwZV9kZikgKwogIGFlcyh4ID0gY2VsbGFzc2lnbl9tYXhfcHJlZGljdGlvbikgKwogIGdlb21fZGVuc2l0eSgKICAgIGJ3ID0gZGVuc2l0eV9idywKICAgIGZpbGwgPSAiZ3JleTY1IiwKICAgIGxpbmV3aWR0aCA9IDAuMjUsCiAgICBib3VuZHMgPSBjKDAsIDEpCiAgKSArCiAgZ2VvbV9zZWdtZW50KAogICAgYWVzKAogICAgICAjIHNldCBhbHBoYSB0byB2YXJ5IGJhc2VkIG9uIHRoZSBudW1iZXIgb2YgcG9pbnRzIGluIHRoZSByb3cgc3VjaCB0aGF0CiAgICAgICMgIHJvd3Mgd2l0aCBtb3JlIHBvaW50cyBhcmUgbW9yZSB0cmFuc3BhcmVudAogICAgICBhbHBoYSA9IHBtYXgoMC4yLCAxIC0gMC4wMSAqIG4pLAogICAgICB4ZW5kID0gY2VsbGFzc2lnbl9tYXhfcHJlZGljdGlvbiwKICAgICAgIyBzZXQgeWVuZCBhcyBlaXRoZXIgMCBmb3Igcm93cyB3aXRoIG1hbnkgcG9pbnRzLCBvciB5X21heC8yLjUgZm9yCiAgICAgICMgIHJvd3Mgd2l0aCBmZXcgcG9pbnRzCiAgICAgIHllbmQgPSBpZmVsc2UobiA+IDUsIDAsIHlfbWF4IC8gMi41KSwKICAgICAgeSA9IC1JbmYKICAgICksCiAgICBjb2xvciA9ICJibHVlIgogICkgKwogIGxhYnMoCiAgICB4ID0gIlByb2JhYmlsaXR5IG9mIGFubm90YXRlZCBjZWxsIHR5cGUiLAogICAgeSA9ICJDZWxsIHR5cGUgYW5ub3RhdGlvbiIKICApICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAxKSkgKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAuMSwgMC4xKSkgKwogIHNjYWxlX2FscGhhX2lkZW50aXR5KCkgKwogIGZhY2V0X2dyaWQoCiAgICByb3dzID0gdmFycyhjZWxsYXNzaWduX2NlbGx0eXBlX2Fubm90YXRpb24pLAogICAgc3dpdGNoID0gInkiCiAgKSArCiAgdGhlbWUoCiAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgc3RyaXAudGV4dC55LmxlZnQgPSBlbGVtZW50X3RleHQoCiAgICAgIGFuZ2xlID0gMCwKICAgICAgaGp1c3QgPSAxCiAgICApLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuc3BhY2luZyA9IHVuaXQoMC4wMiwgImluIikKICApCmBgYAoKCiMgU2Vzc2lvbiBJbmZvCjxkZXRhaWxzPgo8c3VtbWFyeT5SIHNlc3Npb24gaW5mb3JtYXRpb248L3N1bW1hcnk+CmBgYHtyIHNlc3Npb25faW5mb30KaWYgKHJlcXVpcmVOYW1lc3BhY2UoInNlc3Npb25pbmZvIiwgcXVpZXRseSA9IFRSVUUpKSB7CiAgc2Vzc2lvbmluZm86OnNlc3Npb25faW5mbygpCn0gZWxzZSB7CiAgc2Vzc2lvbkluZm8oKQp9CmBgYAo8L2RldGFpbHM+Cg==