## Warning in scpcaTools::add_miQC(filtered_sce): prob_compromised was already
## calculated and will be replaced.
## Warning in miQC::mixtureModel(sce): Unable to identify two distributions. Use plotMetrics function
##                 to confirm assumptions of miQC are met.

## Warning in miQC::mixtureModel(sce): Unable to identify two distributions. Use plotMetrics function
##                 to confirm assumptions of miQC are met.

## Warning in miQC::mixtureModel(sce): Unable to identify two distributions. Use plotMetrics function
##                 to confirm assumptions of miQC are met.

Processing Information for SCPCL000706

Raw Sample Metrics

Library id SCPCL000706
Sample id SCPCS000099
Tech version 10Xv3
Data modalities RNA-seq, ADT
Cells reported by alevin-fry 1,311,042
Number of genes assayed 60,319
Number of RNA-seq reads sequenced 626,961,992
Percent of RNA-seq reads mapped to transcripts 82.92%
Number of antibodies assayed 22
Number of ADT reads sequenced 34,265,495
Percent of ADT reads mapped to ADTs 92.98%

Pre-Processing Information

Salmon version 1.8.0
Alevin-fry version 0.7.0
Transcriptome index Homo_sapiens.GRCh38.104.spliced_intron.txome
Alevin-fry droplet detection unfiltered
Resolution CellRangerLikeEm
Transcripts included Total and spliced only

RNA-seq Experiment Summary

Cell Statistics

Method used to filter empty droplets emptyDropsCellRanger
Number of cells post filtering empty droplets 2,308
Percent of reads in cells 51.29%
Median UMI count per cell 663
Median genes detected per cell 605
Median percent reads mitochondrial 3.03%
Method used to filter low quality cells Minimum_gene_cutoff
Cells after filtering low quality cells 2,306
Normalization method deconvolution
Minimum genes per cell cutoff 200

Knee Plot

Smoothed knee plot of filtered and unfiltered droplets

The total UMI count of each droplet (barcode) plotted against the rank of that droplet allows visualization of the distribution of sequencing depth across droplets. The droplets that are expected to contain cells were identified with DropletUtils::emptyDropsCellRanger(), unless otherwise specified in the Cell Statistics table, which uses both the total UMI counts and expressed gene content (adapted from Lun et al. 2019). As the boundary between droplets passing and failing this filter is not solely dependent on total UMI count, some regions contain droplets in both categories. The color in this plot indicates the percentage of droplets in a region passing the filter.

Cell Read Metrics

Total UMI x genes expressed

The above plot of cell metrics includes only droplets which have passed the emptyDropsCellRanger() filter. The plot will usually display a strong (but curved) relationship between the total UMI count and the number of genes detected. Cells with low UMI counts and high mitochondrial percentages may require further filtering.

miQC Model Diagnostics

miQC model diagnostics plot

We calculate the probability that a cell is compromised due to degradation or rupture using miQC (Hippen et al. 2021). This relies on fitting a mixture model using the number of genes expressed by a cell and the percentage of mitochondrial reads. The expected plot will show a characteristic triangular shape and two model fit lines. Cells with low numbers of genes expressed may have both low and high mitochondrial percentage, but cells with many genes tend to have a low mitochondrial percentage. Compromised cells are likely to have a fewer genes detected and higher percentage of mitochondrial reads.

If the model has failed to fit properly, the pattern of cells may differ, and there may not be model fit lines. This can be the result of a low-quality library or may occur if there is no mitochondrial content, as in the case of a high-quality single-nucleus sample. In such situations, the calculated probability of compromise may not be valid (see miQC vignette for more details).

Removing low quality cells

The below plot highlights cells that were removed prior to normalization and dimensionality reduction. Cells that should be removed based on RNA counts are those that are identified to be low quality cells, such as cells with high probability of being compromised. The method of filtering is indicated above the plot as either miQC or Minimum gene cutoff. If miQC, cells below the specified probability compromised cutoff and above the minimum number of unique genes identified are kept for downstream analyses. If only a Minimum gene cutoff is used, then miQC is not used and only those cells that pass the minimum number of unique genes identified threshold are retained. The dotted vertical line indicates the minimum gene cutoff used for filtering.

The raw counts from all cells that remain after filtering low quality cells (RNA only) are then normalized prior to selection of highly variable genes and dimensionality reduction.

Dimensionality Reduction

The below plot shows the UMAP (Uniform Manifold Approximation and Projection) embeddings for each cell, coloring each cell by the total number of genes detected per cell.

Expression of highly variable genes

The plots below show the same UMAP embeddings, coloring each cell by the expression level of the labeled gene. The genes chosen for plotting are the 12 most variable genes identified in the library. Gene symbols are used when available to label the UMAP plots. If gene symbols are not available, the Ensembl id will be shown.

CITE-seq Experiment Summary

This section details quality control statistics from the ADT (antibody-derived tag) component of CITE-seq experiments.

CITE-seq Experiment Statistics

Number of ADTs assayed 22
Number of reads sequenced 34,265,495
Percent reads mapped to ADTs 92.98%
Percent of ADTs in cells 6.07%
Percent of cells with ADTs 79.42%
Median ADT UMIs per cell 20

ADT Statistics

Antibody Mean UMI count per cell Percent of cells detected ADT target type
CD45 583.37 77.21 target
CD7 54.12 74.22 target
CD117 47.48 60.44 target
CD10 31.37 64.08 target
CD2 23.42 45.54 target
CD38 22.68 67.03 target
CD5 9.91 50.43 target
CD4 9.37 37.09 target
CD8A 8.86 42.16 target
CD3 8.01 46.36 target
CD22 6.43 43.72 target
CD15 5.94 47.36 target
CD1A 4.54 37.44 target
CD34 3.67 36.74 target
CD14 3.40 35.31 target
HLA-DR 3.25 31.98 target
CD66B 2.72 33.71 target
CD123 2.71 34.23 target
CD94 2.57 32.84 target
CD19 2.13 29.16 target
CD33 1.20 19.89 target
CD56 0.88 22.44 target

ADT Post-processing Statistics

Method used to identify cells to filter No filter
Normalization method log-normalization

Removing low quality cells based on ADT counts

No ADT filtering was performed on this library.

Expression of highly variable ADTs

The plots in this section visualize the top four most variable ADTS in the library.

The plot below displays normalized expression of these four ADTs, with one ADT shown per panel. Density plot showing normalized expression of highly variable ADTs

The plot below displays UMAP embeddings calculated from RNA expression, where each cell is colored by the expression level of the given ADT.

UMAP calculated from RNA expression but colored by normalized expression of highly variable ADTs

Session Info

R session information
## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.2.3 (2023-03-15)
##  os       Ubuntu 18.04.3 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  C.UTF-8
##  ctype    C.UTF-8
##  tz       Etc/UTC
##  date     2023-07-14
##  pandoc   2.17.1.1 @ /usr/lib/rstudio-server/bin/quarto/bin/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package              * version   date (UTC) lib source
##  beachmat               2.14.2    2023-04-07 [2] Bioconductor
##  beeswarm               0.4.0     2021-06-01 [2] CRAN (R 4.2.1)
##  Biobase              * 2.58.0    2022-11-01 [2] Bioconductor
##  BiocGenerics         * 0.44.0    2022-11-01 [2] Bioconductor
##  BiocNeighbors          1.16.0    2022-11-01 [2] Bioconductor
##  BiocParallel           1.32.6    2023-03-17 [2] Bioconductor
##  BiocSingular           1.14.0    2022-11-01 [2] Bioconductor
##  bitops                 1.0-7     2021-04-24 [2] CRAN (R 4.2.1)
##  bslib                  0.4.2     2022-12-16 [2] CRAN (R 4.2.1)
##  cachem                 1.0.7     2023-02-24 [2] CRAN (R 4.2.3)
##  cli                    3.6.1     2023-03-23 [2] CRAN (R 4.2.3)
##  codetools              0.2-19    2023-02-01 [2] CRAN (R 4.2.3)
##  colorspace             2.1-0     2023-01-23 [2] CRAN (R 4.2.3)
##  cowplot                1.1.1     2020-12-30 [2] CRAN (R 4.2.1)
##  crayon                 1.5.2     2022-09-29 [2] CRAN (R 4.2.1)
##  DelayedArray           0.24.0    2022-11-01 [2] Bioconductor
##  DelayedMatrixStats     1.20.0    2022-11-01 [2] Bioconductor
##  digest                 0.6.31    2022-12-11 [2] CRAN (R 4.2.1)
##  dplyr                * 1.1.2     2023-04-20 [2] RSPM (R 4.2.0)
##  evaluate               0.20      2023-01-17 [2] CRAN (R 4.2.3)
##  fansi                  1.0.4     2023-01-22 [2] CRAN (R 4.2.3)
##  farver                 2.1.1     2022-07-06 [2] CRAN (R 4.2.1)
##  fastmap                1.1.1     2023-02-24 [2] CRAN (R 4.2.3)
##  flexmix                2.3-19    2023-03-16 [2] CRAN (R 4.2.3)
##  forcats                1.0.0     2023-01-29 [2] CRAN (R 4.2.3)
##  generics               0.1.3     2022-07-05 [2] CRAN (R 4.2.1)
##  GenomeInfoDb         * 1.34.9    2023-02-02 [2] Bioconductor
##  GenomeInfoDbData       1.2.9     2023-01-06 [2] Bioconductor
##  GenomicRanges        * 1.50.2    2022-12-16 [2] Bioconductor
##  ggbeeswarm             0.7.1     2022-12-16 [2] CRAN (R 4.2.1)
##  ggplot2              * 3.4.2     2023-04-03 [2] RSPM (R 4.2.0)
##  ggrepel                0.9.3     2023-02-03 [2] CRAN (R 4.2.3)
##  glue                   1.6.2     2022-02-24 [2] CRAN (R 4.2.1)
##  gridExtra              2.3       2017-09-09 [2] CRAN (R 4.2.1)
##  gtable                 0.3.3     2023-03-21 [2] CRAN (R 4.2.3)
##  highr                  0.10      2022-12-22 [2] CRAN (R 4.2.1)
##  htmltools              0.5.5     2023-03-23 [2] CRAN (R 4.2.3)
##  httr                   1.4.5     2023-02-24 [2] CRAN (R 4.2.3)
##  IRanges              * 2.32.0    2022-11-01 [2] Bioconductor
##  irlba                  2.3.5.1   2022-10-03 [2] CRAN (R 4.2.1)
##  jquerylib              0.1.4     2021-04-26 [2] CRAN (R 4.2.1)
##  jsonlite               1.8.4     2022-12-06 [2] CRAN (R 4.2.1)
##  kableExtra             1.3.4     2021-02-20 [1] RSPM (R 4.2.0)
##  knitr                  1.42      2023-01-25 [2] CRAN (R 4.2.3)
##  labeling               0.4.2     2020-10-20 [2] CRAN (R 4.2.1)
##  lattice                0.21-8    2023-04-05 [2] RSPM (R 4.2.0)
##  lifecycle              1.0.3     2022-10-07 [2] CRAN (R 4.2.1)
##  magrittr               2.0.3     2022-03-30 [2] CRAN (R 4.2.1)
##  Matrix                 1.5-4     2023-04-04 [2] RSPM (R 4.2.0)
##  MatrixGenerics       * 1.10.0    2022-11-01 [2] Bioconductor
##  matrixStats          * 0.63.0    2022-11-18 [2] CRAN (R 4.2.1)
##  miQC                   1.6.0     2022-11-01 [2] Bioconductor
##  modeltools             0.2-23    2020-03-05 [2] RSPM (R 4.1.0)
##  munsell                0.5.0     2018-06-12 [2] CRAN (R 4.2.1)
##  nnet                   7.3-18    2022-09-28 [2] CRAN (R 4.2.3)
##  pillar                 1.9.0     2023-03-22 [2] CRAN (R 4.2.3)
##  pkgconfig              2.0.3     2019-09-22 [2] CRAN (R 4.2.1)
##  purrr                  1.0.1     2023-01-10 [2] CRAN (R 4.2.3)
##  R6                     2.5.1     2021-08-19 [2] CRAN (R 4.2.1)
##  Rcpp                   1.0.10    2023-01-22 [2] CRAN (R 4.2.3)
##  RCurl                  1.98-1.12 2023-03-27 [2] RSPM (R 4.2.0)
##  rlang                  1.1.0     2023-03-14 [2] CRAN (R 4.2.3)
##  rmarkdown              2.21      2023-03-26 [2] RSPM (R 4.2.0)
##  rstudioapi             0.14      2022-08-22 [2] CRAN (R 4.2.1)
##  rsvd                   1.0.5     2021-04-16 [2] CRAN (R 4.2.1)
##  rvest                  1.0.3     2022-08-19 [2] CRAN (R 4.2.1)
##  S4Vectors            * 0.36.2    2023-02-26 [2] Bioconductor
##  sass                   0.4.5     2023-01-24 [2] CRAN (R 4.2.3)
##  ScaledMatrix           1.6.0     2022-11-01 [2] Bioconductor
##  scales                 1.2.1     2022-08-20 [2] CRAN (R 4.2.1)
##  scater                 1.26.1    2022-11-13 [2] Bioconductor
##  scpcaTools             0.2.1     2023-05-10 [1] Github (AlexsLemonade/scpcaTools@d2ad3cd)
##  scuttle                1.8.4     2023-01-19 [2] Bioconductor
##  sessioninfo            1.2.2     2021-12-06 [1] RSPM (R 4.2.0)
##  SingleCellExperiment * 1.20.1    2023-03-17 [2] Bioconductor
##  sparseMatrixStats      1.10.0    2022-11-01 [2] Bioconductor
##  stringi                1.7.12    2023-01-11 [2] CRAN (R 4.2.3)
##  stringr                1.5.0     2022-12-02 [2] CRAN (R 4.2.1)
##  SummarizedExperiment * 1.28.0    2022-11-01 [2] Bioconductor
##  svglite                2.1.1     2023-01-10 [1] RSPM (R 4.2.0)
##  systemfonts            1.0.4     2022-02-11 [2] CRAN (R 4.2.1)
##  tibble                 3.2.1     2023-03-20 [2] CRAN (R 4.2.3)
##  tidyr                  1.3.0     2023-01-24 [2] CRAN (R 4.2.3)
##  tidyselect             1.2.0     2022-10-10 [2] CRAN (R 4.2.1)
##  utf8                   1.2.3     2023-01-31 [2] CRAN (R 4.2.3)
##  vctrs                  0.6.2     2023-04-19 [2] RSPM (R 4.2.0)
##  vipor                  0.4.5     2017-03-22 [2] CRAN (R 4.2.1)
##  viridis                0.6.2     2021-10-13 [2] CRAN (R 4.2.1)
##  viridisLite            0.4.1     2022-08-22 [2] CRAN (R 4.2.1)
##  webshot                0.5.4     2022-09-26 [1] RSPM (R 4.2.0)
##  withr                  2.5.0     2022-03-03 [2] CRAN (R 4.2.1)
##  xfun                   0.39      2023-04-20 [2] RSPM (R 4.2.0)
##  xml2                   1.3.3     2021-11-30 [2] CRAN (R 4.2.1)
##  XVector                0.38.0    2022-11-01 [2] Bioconductor
##  yaml                   2.3.7     2023-01-23 [2] CRAN (R 4.2.3)
##  zlibbioc               1.44.0    2022-11-01 [2] Bioconductor
## 
##  [1] /home/ccdl/stephanie/R/x86_64-pc-linux-gnu-library/4.2
##  [2] /opt/R/4.2.3/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────
LS0tCnBhcmFtczoKICBsaWJyYXJ5OiBFeGFtcGxlCiAgdW5maWx0ZXJlZF9zY2U6ICFyIHNjcGNhVG9vbHM6OjpzaW1fc2NlKCkKICBmaWx0ZXJlZF9zY2U6IE5VTEwKICBwcm9jZXNzZWRfc2NlOiBOVUxMCiAgZGF0ZTogIXIgU3lzLkRhdGUoKQoKdGl0bGU6ICJgciBnbHVlOjpnbHVlKCdTY1BDQSBRQyByZXBvcnQgZm9yIHtwYXJhbXMkbGlicmFyeX0nKWAiCmF1dGhvcjogIkNoaWxkaG9vZCBDYW5jZXIgRGF0YSBMYWIiCmRhdGU6ICJgciBwYXJhbXMkZGF0ZWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDIKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiBmYWxzZQogICAgbnVtYmVyX3NlY3Rpb25zOiBmYWxzZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQotLS0KCmBgYHtyIHNldHVwLCBtZXNzYWdlID0gRkFMU0UsIGVjaG8gPSBGQUxTRX0KIyBrbml0ciBvcHRpb25zCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBlY2hvID0gRkFMU0UKKQoKbGlicmFyeShTaW5nbGVDZWxsRXhwZXJpbWVudCkKbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQoKIyBTZXQgZGVmYXVsdCBnZ3Bsb3QgdGhlbWUKdGhlbWVfc2V0KAogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBsb3QubWFyZ2luID0gbWFyZ2luKHJlcCgyMCwgNCkpLCAKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAndHJhbnNwYXJlbnQnKSkKKQoKIyBIZWxwZXIgZnVuY3Rpb24gdG8gY2hhbmdlIE5VTEwgLT4gIk4vQSIgaW4gYSBkYXRhIGZyYW1lCnJlZm9ybWF0X251bGxzIDwtIGZ1bmN0aW9uKGRmKSB7CiAgZGYgfD4gbXV0YXRlKAogICAgYWNyb3NzKGV2ZXJ5dGhpbmcoKSwKICAgICAgLmZucyA9IFwoeCkgaWZlbHNlKHggPT0gIk5VTEwiLCAiTi9BIiwgeCkKICAgICkKICApCn0KYGBgCgpgYGB7ciBzY2Vfc2V0dXB9CiMgc2F2ZSBzb21lIHR5cGluZyBsYXRlcgpsaWJyYXJ5X2lkIDwtIHBhcmFtcyRsaWJyYXJ5CnVuZmlsdGVyZWRfc2NlIDwtIHBhcmFtcyR1bmZpbHRlcmVkX3NjZQpmaWx0ZXJlZF9zY2UgPC0gcGFyYW1zJGZpbHRlcmVkX3NjZQpwcm9jZXNzZWRfc2NlIDwtIHBhcmFtcyRwcm9jZXNzZWRfc2NlCgpsaWJyYXJ5X2lkIDwtICJTQ1BDTDAwMDcwNiIgCnVuZmlsdGVyZWRfc2NlIDwtIHJlYWRSRFMoZ2x1ZTo6Z2x1ZSgie2xpYnJhcnlfaWR9X3VuZmlsdGVyZWQucmRzIikpCmZpbHRlcmVkX3NjZSA8LSByZWFkUkRTKGdsdWU6OmdsdWUoIntsaWJyYXJ5X2lkfV9maWx0ZXJlZC5yZHMiKSkKcHJvY2Vzc2VkX3NjZSA8LSByZWFkUkRTKGdsdWU6OmdsdWUoIntsaWJyYXJ5X2lkfV9wcm9jZXNzZWQucmRzIikpCgpoYXNfZmlsdGVyZWQgPC0gIWlzLm51bGwoZmlsdGVyZWRfc2NlKQpoYXNfcHJvY2Vzc2VkIDwtICFpcy5udWxsKHByb2Nlc3NlZF9zY2UpCgojIGlmIHRoZXJlIGlzIG5vIGZpbHRlcmVkIHNjZSwgdXNlIHRoZSB1bmZpbHRlcmVkIGZvciBib3RoCmlmICghaGFzX2ZpbHRlcmVkKXsKICBmaWx0ZXJlZF9zY2UgPC0gdW5maWx0ZXJlZF9zY2UKfQoKIyBncmFiIHNhbXBsZSBpZCBmcm9tIGZpbHRlcmVkIHNjZSwgaWYgbWlzc2luZyBzZXQgc2FtcGxlIGlkIHRvIE5BCmlmKGlzLm51bGwobWV0YWRhdGEoZmlsdGVyZWRfc2NlKSRzYW1wbGVfaWQpKXsKICBzYW1wbGVfaWQgPC0gTkEKfSBlbHNlIHsKICBzYW1wbGVfaWQgPC0gbWV0YWRhdGEoZmlsdGVyZWRfc2NlKSRzYW1wbGVfaWQKfQoKIyBhZGQgY2VsbCBzdGF0cyBpZiBtaXNzaW5nCmlmIChpcy5udWxsKHVuZmlsdGVyZWRfc2NlJHN1bSkpewogIHVuZmlsdGVyZWRfc2NlIDwtIHNjdXR0bGU6OmFkZFBlckNlbGxRQ01ldHJpY3ModW5maWx0ZXJlZF9zY2UpCn0KaWYgKGlzLm51bGwoZmlsdGVyZWRfc2NlJHN1bSkpewogIGZpbHRlcmVkX3NjZSA8LSBzY3V0dGxlOjphZGRQZXJDZWxsUUNNZXRyaWNzKGZpbHRlcmVkX3NjZSkKfQppZiAoaXMubnVsbChmaWx0ZXJlZF9zY2Ukc3Vic2V0c19taXRvX3BlcmNlbnQpKXsKICBmaWx0ZXJlZF9zY2Ukc3Vic2V0c19taXRvX3BlcmNlbnQgPC0gTkFfcmVhbF8KICBza2lwX21pUUMgPC0gVFJVRQp9ZWxzZXsKICBza2lwX21pUUMgPC0gRkFMU0UKfQoKIyB0cnkgdG8gYWRkIG1pUUMgaWYgaXQgaXMgbWlzc2luZwppZiAoaXMubnVsbChtZXRhZGF0YShmaWx0ZXJlZF9zY2UpJG1pUUNfbW9kZWwpICYgIXNraXBfbWlRQyl7CiAgZmlsdGVyZWRfc2NlIDwtIHNjcGNhVG9vbHM6OmFkZF9taVFDKGZpbHRlcmVkX3NjZSkKfQoKIyMgQ2hlY2sgZm9yIGFkZGl0aW9uYWwgbW9kYWxpdGllcwptb2RhbGl0aWVzIDwtIGMoIlJOQS1zZXEiKQoKaGFzX2FkdCA8LSAiYWR0IiAlaW4lIGFsdEV4cE5hbWVzKGZpbHRlcmVkX3NjZSkKaWYgKGhhc19hZHQpIHsKICBtb2RhbGl0aWVzIDwtIGMobW9kYWxpdGllcywgIkFEVCIpCn0KCiMgY2hlY2sgZm9yIGNlbGxoYXNoIHRvIGFkZCB0byBsaXN0IG9mIG1vZGFsaXRpZXMKaGFzX2NlbGxoYXNoIDwtICJjZWxsaGFzaCIgJWluJSBhbHRFeHBOYW1lcyhmaWx0ZXJlZF9zY2UpCmlmIChoYXNfY2VsbGhhc2gpIHsKICBtb2RhbGl0aWVzIDwtIGMobW9kYWxpdGllcywgIk11bHRpcGxleCIpCn0KCiMgY2hlY2sgZm9yIHVtYXAsIG5lZWQgdG8gYmUgc3VyZSB0aGF0IHByb2Nlc3NlZF9zY2UgZXhpc3RzIGZpcnN0CmlmIChoYXNfcHJvY2Vzc2VkKSB7CiAgaGFzX3VtYXAgPC0gIlVNQVAiICVpbiUgcmVkdWNlZERpbU5hbWVzKHByb2Nlc3NlZF9zY2UpCn0gZWxzZSB7CiAgaGFzX3VtYXAgPC0gRkFMU0UKfQpgYGAKCgojIFByb2Nlc3NpbmcgSW5mb3JtYXRpb24gZm9yIGByIGxpYnJhcnlfaWRgCgpgYGB7ciwgcmVzdWx0cz0nYXNpcyd9CiMgb25seSBwcmludCBvdXQgbXVsdGlwbGV4ZWQgd2FybmluZyBpZiBtb3JlIHRoYW4gb25lIHNhbXBsZSBpcyBwcmVzZW50Cmhhc19tdWx0aXBsZXggPC0gbGVuZ3RoKHNhbXBsZV9pZCkgPiAxCgppZiAoaGFzX211bHRpcGxleCkgewogICMgY29udmVydCBzYW1wbGUgaWQgdG8gYnVsbGV0IHNlcGFyYXRlZCBsaXN0CiAgbXVsdGlwbGV4X3NhbXBsZXMgPC0gcGFzdGUwKCI8bGk+IiwgcGFzdGUoc2FtcGxlX2lkLCBjb2xsYXBzZSA9ICc8L2xpPjxsaT4nLCAiPC9saT4iKSkKICBnbHVlOjpnbHVlKCIKICAgIDxkaXYgY2xhc3M9XCJhbGVydCBhbGVydC13YXJuaW5nXCI+CgogICAgVGhpcyBsaWJyYXJ5IGlzIG11bHRpcGxleGVkIGFuZCBjb250YWlucyBkYXRhIGZyb20gbW9yZSB0aGFuIG9uZSBzYW1wbGUuCiAgICBEYXRhIGZyb20gdGhlIGZvbGxvd2luZyBzYW1wbGVzIGFyZSBpbmNsdWRlZCBpbiB0aGlzIGxpYnJhcnk6CgogICAge211bHRpcGxleF9zYW1wbGVzfQoKICAgIDwvZGl2PgogICIpCn0KCmBgYAoKIyMgUmF3IFNhbXBsZSBNZXRyaWNzCgpgYGB7ciB9CiMgZXh0cmFjdCBzY2UgbWV0YWRhdGEgY29udGFpbmluZyBwcm9jZXNzaW5nIGluZm9ybWF0aW9uIGFzIHRhYmxlCnVuZmlsdGVyZWRfbWV0YSA8LSBtZXRhZGF0YSh1bmZpbHRlcmVkX3NjZSkKCnNhbXBsZV9pbmZvcm1hdGlvbiA8LSB0aWJibGU6OnRpYmJsZSgKICAiTGlicmFyeSBpZCIgPSBsaWJyYXJ5X2lkLAogICJTYW1wbGUgaWQiID0gcGFzdGUoc2FtcGxlX2lkLCBjb2xsYXBzZSA9ICIsICIpLAogICJUZWNoIHZlcnNpb24iID0gZm9ybWF0KHVuZmlsdGVyZWRfbWV0YSR0ZWNoX3ZlcnNpb24pLCAjIGZvcm1hdCB0byBrZWVwIG51bGxzCiAgIkRhdGEgbW9kYWxpdGllcyIgPSBwYXN0ZShtb2RhbGl0aWVzLCBjb2xsYXBzZSA9ICIsICIpLAogICJDZWxscyByZXBvcnRlZCBieSBhbGV2aW4tZnJ5IiA9CiAgICBmb3JtYXQodW5maWx0ZXJlZF9tZXRhJGFmX251bV9jZWxscywgYmlnLm1hcmsgPSAnLCcsIHNjaWVudGlmaWMgPSBGQUxTRSksCiAgIk51bWJlciBvZiBnZW5lcyBhc3NheWVkIiA9CiAgICBmb3JtYXQobnJvdyh1bmZpbHRlcmVkX3NjZSksIGJpZy5tYXJrID0gJywnLCBzY2llbnRpZmljID0gRkFMU0UpLAogICJOdW1iZXIgb2YgUk5BLXNlcSByZWFkcyBzZXF1ZW5jZWQiID0KICAgIGZvcm1hdCh1bmZpbHRlcmVkX21ldGEkdG90YWxfcmVhZHMsIGJpZy5tYXJrID0gJywnLCBzY2llbnRpZmljID0gRkFMU0UpLAogICJQZXJjZW50IG9mIFJOQS1zZXEgcmVhZHMgbWFwcGVkIHRvIHRyYW5zY3JpcHRzIiA9CiAgICBwYXN0ZTAocm91bmQoKHVuZmlsdGVyZWRfbWV0YSRtYXBwZWRfcmVhZHMvdW5maWx0ZXJlZF9tZXRhJHRvdGFsX3JlYWRzKSAqMTAwLCAyKSwgIiUiKQopCgppZiAoaGFzX2FkdCkgewogIGFkdF9leHAgPC0gYWx0RXhwKGZpbHRlcmVkX3NjZSwgImFkdCIpICMgbXVzdCBiZSBmaWx0ZXJlZF9zY2UgaW4gY2FzZSBoYXNfcHJvY2Vzc2VkIGlzIEZBTFNFCiAgYWR0X21ldGEgPC0gbWV0YWRhdGEoYWR0X2V4cCkKCiAgc2FtcGxlX2luZm9ybWF0aW9uIDwtIHNhbXBsZV9pbmZvcm1hdGlvbiB8PgogICAgbXV0YXRlKAogICAgICAiTnVtYmVyIG9mIGFudGlib2RpZXMgYXNzYXllZCIgPQogICAgICAgIGZvcm1hdChucm93KGFkdF9leHApLCBiaWcubWFyayA9ICcsJywgc2NpZW50aWZpYyA9IEZBTFNFKSwKICAgICAgIk51bWJlciBvZiBBRFQgcmVhZHMgc2VxdWVuY2VkIiA9CiAgICAgICAgZm9ybWF0KGFkdF9tZXRhJHRvdGFsX3JlYWRzLCBiaWcubWFyayA9ICcsJywgc2NpZW50aWZpYyA9IEZBTFNFKSwKICAgICAgIlBlcmNlbnQgb2YgQURUIHJlYWRzIG1hcHBlZCB0byBBRFRzIiA9CiAgICAgICAgcGFzdGUwKHJvdW5kKGFkdF9tZXRhJG1hcHBlZF9yZWFkcy9hZHRfbWV0YSR0b3RhbF9yZWFkcyAqIDEwMCwgZGlnaXRzID0gMiksICIlIikKICAgICkKfQoKaWYgKGhhc19jZWxsaGFzaCkgewogIG11bHRpcGxleF9leHAgPC0gYWx0RXhwKGZpbHRlcmVkX3NjZSwgImNlbGxoYXNoIikKICBtdWx0aXBsZXhfbWV0YSA8LSBtZXRhZGF0YShtdWx0aXBsZXhfZXhwKQoKICBzYW1wbGVfaW5mb3JtYXRpb24gPC0gc2FtcGxlX2luZm9ybWF0aW9uIHw+CiAgICBtdXRhdGUoCiAgICAgICJOdW1iZXIgb2YgSFRPcyBhc3NheWVkIiA9CiAgICAgICAgZm9ybWF0KG5yb3cobXVsdGlwbGV4X2V4cCksIGJpZy5tYXJrID0gJywnLCBzY2llbnRpZmljID0gRkFMU0UpLAogICAgICAiTnVtYmVyIG9mIGNlbGxoYXNoIHJlYWRzIHNlcXVlbmNlZCIgPQogICAgICAgIGZvcm1hdChtdWx0aXBsZXhfbWV0YSR0b3RhbF9yZWFkcywgYmlnLm1hcmsgPSAnLCcsIHNjaWVudGlmaWMgPSBGQUxTRSksCiAgICAgICJQZXJjZW50IG9mIGNlbGxoYXNoIHJlYWRzIG1hcHBlZCB0byBIVE9zIiA9CiAgICAgICAgcGFzdGUwKHJvdW5kKG11bHRpcGxleF9tZXRhJG1hcHBlZF9yZWFkcy9tdWx0aXBsZXhfbWV0YSR0b3RhbF9yZWFkcyAqIDEwMCwgZGlnaXRzID0gMiksICIlIikKICAgICkKfQoKc2FtcGxlX2luZm9ybWF0aW9uIDwtIHNhbXBsZV9pbmZvcm1hdGlvbiB8PgogIHJlZm9ybWF0X251bGxzKCkgfD4KICB0KCkKCiMgbWFrZSB0YWJsZSB3aXRoIHNhbXBsZSBpbmZvcm1hdGlvbgprbml0cjo6a2FibGUoc2FtcGxlX2luZm9ybWF0aW9uLCBhbGlnbiA9ICdyJykgfD4KICBrYWJsZUV4dHJhOjprYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gInN0cmlwZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVsbF93aWR0aCA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSAibGVmdCIpIHw+CiAga2FibGVFeHRyYTo6Y29sdW1uX3NwZWMoMiwgbW9ub3NwYWNlID0gVFJVRSkKYGBgCgojIyBQcmUtUHJvY2Vzc2luZyBJbmZvcm1hdGlvbgoKYGBge3IgfQojIGRlZmluZSB0cmFuc2NyaXB0IHR5cGUKdHJhbnNjcmlwdF90eXBlIDwtIHBhc3RlKHVuZmlsdGVyZWRfbWV0YSR0cmFuc2NyaXB0X3R5cGUsIGNvbGxhcHNlID0gIiAiKQoKcHJvY2Vzc2luZ19pbmZvIDwtIHRpYmJsZTo6dGliYmxlKAogICJTYWxtb24gdmVyc2lvbiIgICAgICAgPSBmb3JtYXQodW5maWx0ZXJlZF9tZXRhJHNhbG1vbl92ZXJzaW9uKSwKICAiQWxldmluLWZyeSB2ZXJzaW9uIiAgID0gZm9ybWF0KHVuZmlsdGVyZWRfbWV0YSRhbGV2aW5mcnlfdmVyc2lvbiksCiAgIlRyYW5zY3JpcHRvbWUgaW5kZXgiICA9IGZvcm1hdCh1bmZpbHRlcmVkX21ldGEkcmVmZXJlbmNlX2luZGV4KSwKICAiQWxldmluLWZyeSBkcm9wbGV0IGRldGVjdGlvbiIgID0gZm9ybWF0KHVuZmlsdGVyZWRfbWV0YSRhZl9wZXJtaXRfdHlwZSksCiAgIlJlc29sdXRpb24iICAgICAgICAgICA9IGZvcm1hdCh1bmZpbHRlcmVkX21ldGEkYWZfcmVzb2x1dGlvbiksCiAgIlRyYW5zY3JpcHRzIGluY2x1ZGVkIiA9IGRwbHlyOjpjYXNlX3doZW4oCiAgICAgIHRyYW5zY3JpcHRfdHlwZSA9PSAidG90YWwgc3BsaWNlZCIgfiAiVG90YWwgYW5kIHNwbGljZWQgb25seSIsCiAgICAgIHRyYW5zY3JpcHRfdHlwZSA9PSAic3BsaWNlZCIgfiAiU3BsaWNlZCBvbmx5IiwKICAgICAgVFJVRSB+IHRyYW5zY3JpcHRfdHlwZSkKICApIHw+CiAgcmVmb3JtYXRfbnVsbHMoKSB8PgogIHQoKQoKCiMgbWFrZSB0YWJsZSB3aXRoIHByb2Nlc3NpbmcgaW5mb3JtYXRpb24Ka25pdHI6OmthYmxlKHByb2Nlc3NpbmdfaW5mbywgYWxpZ24gPSAncicpIHw+CiAga2FibGVFeHRyYTo6a2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9ICJzdHJpcGVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bGxfd2lkdGggPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gImxlZnQiKSB8PgogIGthYmxlRXh0cmE6OmNvbHVtbl9zcGVjKDIsIG1vbm9zcGFjZSA9IFRSVUUpCmBgYAoKIyBSTkEtc2VxIEV4cGVyaW1lbnQgU3VtbWFyeQoKIyMgQ2VsbCBTdGF0aXN0aWNzCgpgYGB7cn0KYmFzaWNfc3RhdGlzdGljcyA8LSB0aWJibGU6OnRpYmJsZSgKICAiTWV0aG9kIHVzZWQgdG8gZmlsdGVyIGVtcHR5IGRyb3BsZXRzIiAgICAgICAgICA9IG1ldGFkYXRhKGZpbHRlcmVkX3NjZSkkZmlsdGVyaW5nX21ldGhvZCwKICAiTnVtYmVyIG9mIGNlbGxzIHBvc3QgZmlsdGVyaW5nIGVtcHR5IGRyb3BsZXRzIiA9IGZvcm1hdChuY29sKGZpbHRlcmVkX3NjZSksIGJpZy5tYXJrID0gIiwiKSwKICAiUGVyY2VudCBvZiByZWFkcyBpbiBjZWxscyIgICAgICAgICAgICAgICAgICAgICA9IHBhc3RlMChyb3VuZCgoc3VtKGZpbHRlcmVkX3NjZSRzdW0pL3N1bSh1bmZpbHRlcmVkX3NjZSRzdW0pKSoxMDAsMiksIiUiKSwKICAiTWVkaWFuIFVNSSBjb3VudCBwZXIgY2VsbCIgICAgICAgICAgICAgICAgICAgICA9IGZvcm1hdChtZWRpYW4oZmlsdGVyZWRfc2NlJHN1bSksIGJpZy5tYXJrID0gIiwiKSwKICAiTWVkaWFuIGdlbmVzIGRldGVjdGVkIHBlciBjZWxsIiAgICAgICAgICAgICAgICA9IGZvcm1hdChtZWRpYW4oZmlsdGVyZWRfc2NlJGRldGVjdGVkKSwgYmlnLm1hcmsgPSAiLCIpLAogICJNZWRpYW4gcGVyY2VudCByZWFkcyBtaXRvY2hvbmRyaWFsIiAgICAgICAgICAgID0gcGFzdGUwKHJvdW5kKG1lZGlhbihmaWx0ZXJlZF9zY2Ukc3Vic2V0c19taXRvX3BlcmNlbnQpLCAyKSwgIiUiKQogICkKCiMgaWYgcHJvY2Vzc2VkIHNjZSBleGlzdHMgYWRkIGZpbHRlcmluZyBhbmQgbm9ybWFsaXphdGlvbiB0YWJsZQppZiAoaGFzX3Byb2Nlc3NlZCkgewogIHByb2Nlc3NlZF9tZXRhIDwtIG1ldGFkYXRhKHByb2Nlc3NlZF9zY2UpCgogIGJhc2ljX3N0YXRpc3RpY3MgPC0gYmFzaWNfc3RhdGlzdGljcyB8PgogICAgbXV0YXRlKAogICAgICAiTWV0aG9kIHVzZWQgdG8gZmlsdGVyIGxvdyBxdWFsaXR5IGNlbGxzIiA9IGZvcm1hdChwcm9jZXNzZWRfbWV0YSRzY3BjYV9maWx0ZXJfbWV0aG9kKSwKICAgICAgIkNlbGxzIGFmdGVyIGZpbHRlcmluZyBsb3cgcXVhbGl0eSBjZWxscyIgPSBmb3JtYXQoZGltKHByb2Nlc3NlZF9zY2UpWzJdLCBiaWcubWFyayA9ICcsJywgc2NpZW50aWZpYyA9IEZBTFNFKSwKICAgICAgIk5vcm1hbGl6YXRpb24gbWV0aG9kIiAgICAgICAgICAgICAgICAgICAgPSBmb3JtYXQocHJvY2Vzc2VkX21ldGEkbm9ybWFsaXphdGlvbiksCiAgICAgICJNaW5pbXVtIGdlbmVzIHBlciBjZWxsIGN1dG9mZiIgICAgICAgICAgID0gZm9ybWF0KHByb2Nlc3NlZF9tZXRhJG1pbl9nZW5lX2N1dG9mZikKICAgICkKICBpZiAocHJvY2Vzc2VkX21ldGEkc2NwY2FfZmlsdGVyX21ldGhvZCA9PSAibWlRQyIpIHsKICAgIGJhc2ljX3N0YXRpc3RpY3MgPC0gYmFzaWNfc3RhdGlzdGljcyB8PgogICAgICBtdXRhdGUoCiAgICAgICAgIlByb2JhYmlsaXR5IG9mIGNvbXByb21pc2VkIGNlbGwgY3V0b2ZmIiA9IGZvcm1hdChwcm9jZXNzZWRfbWV0YSRwcm9iX2NvbXByb21pc2VkX2N1dG9mZiwgYmlnLm1hcmsgPSAiLCIsIHNjaWVudGlmaWMgPSBGQUxTRSkKICAgICAgKQogIH0KfQoKYmFzaWNfc3RhdGlzdGljcyA8LSBiYXNpY19zdGF0aXN0aWNzIHw+CiAgcmVmb3JtYXRfbnVsbHMoKSB8PiAjIHJlZm9ybWF0IG51bGxzCiAgdCgpCgojIG1ha2UgdGFibGUgd2l0aCBiYXNpYyBzdGF0aXN0aWNzCmtuaXRyOjprYWJsZShiYXNpY19zdGF0aXN0aWNzLCBhbGlnbiA9ICdyJykgfD4KICBrYWJsZUV4dHJhOjprYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gInN0cmlwZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVsbF93aWR0aCA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSAibGVmdCIpIHw+CiAga2FibGVFeHRyYTo6Y29sdW1uX3NwZWMoMiwgbW9ub3NwYWNlID0gVFJVRSkKCmBgYAoKYGBge3IsIHJlc3VsdHM9J2FzaXMnfQppZiAoaGFzX2ZpbHRlcmVkICYmCiAgIChtZXRhZGF0YShmaWx0ZXJlZF9zY2UpJGZpbHRlcmluZ19tZXRob2QgPT0gIlVNSSBjdXRvZmYiKSkgewogIGdsdWU6OmdsdWUoIgogICAgPGRpdiBjbGFzcz1cImFsZXJ0IGFsZXJ0LXdhcm5pbmdcIj4KCiAgICBUaGlzIGxpYnJhcnkgbWF5IGNvbnRhaW4gYSBsb3cgbnVtYmVyIG9mIGNlbGxzIGFuZCB3YXMgdW5hYmxlIHRvIGJlIGZpbHRlcmVkIHVzaW5nIGBEcm9wbGV0VXRpbHNgLgogICAgRHJvcGxldHMgd2l0aCBhIHRvdGFsIFVNSSBjb3VudCDiiaUge21ldGFkYXRhKGZpbHRlcmVkX3NjZSkkdW1pX2N1dG9mZn0gYXJlIGluY2x1ZGVkIGluIHRoZSBmaWx0ZXJlZCBgU2luZ2xlQ2VsbEV4cGVyaW1lbnRgIG9iamVjdC4KCiAgICA8L2Rpdj4KICAiKQp9CmBgYAoKYGBge3IsIHJlc3VsdHM9J2FzaXMnfQojIGNoZWNrIGZvciBudW1iZXIgb2YgZmlsdGVyZWQgY2VsbHMKbWluX2ZpbHRlcmVkIDwtIDEwMAppZihoYXNfZmlsdGVyZWQpewogIGlmKG5jb2woZmlsdGVyZWRfc2NlKSA8IG1pbl9maWx0ZXJlZCl7CiAgICBnbHVlOjpnbHVlKCIKICAgICAgPGRpdiBjbGFzcz1cImFsZXJ0IGFsZXJ0LXdhcm5pbmdcIj4KCiAgICAgIFRoaXMgbGlicmFyeSBjb250YWlucyBmZXdlciB0aGFuIHttaW5fZmlsdGVyZWR9IGNlbGxzIGluIHRoZSBmaWx0ZXJlZCBgU2luZ2xlQ2VsbEV4cGVyaW1lbnRgIG9iamVjdC4KICAgICAgVGhpcyBtYXkgYWZmZWN0IHRoZSBpbnRlcnByZXRhdGlvbiBvZiByZXN1bHRzLgoKICAgICAgPC9kaXY+CiAgICAiKQogIH0KfQoKIyBjaGVjayBmb3IgbnVtYmVyIG9mIGNlbGxzIHBvc3QgcHJvY2Vzc2luZwptaW5fcHJvY2Vzc2VkIDwtIDUwCmlmKGhhc19wcm9jZXNzZWQpewogIGlmKG5jb2wocHJvY2Vzc2VkX3NjZSkgPCBtaW5fcHJvY2Vzc2VkKXsKICAgIGdsdWU6OmdsdWUoIgogICAgICA8ZGl2IGNsYXNzPVwiYWxlcnQgYWxlcnQtd2FybmluZ1wiPgoKICAgICAgVGhpcyBsaWJyYXJ5IGNvbnRhaW5zIGZld2VyIHRoYW4ge21pbl9wcm9jZXNzZWR9IGNlbGxzIGluIHRoZSBwcm9jZXNzZWQgYFNpbmdsZUNlbGxFeHBlcmltZW50YCBvYmplY3QgYWZ0ZXIgcmVtb3ZhbCBvZiBsb3cgcXVhbGl0eSBjZWxscy4KICAgICAgVU1BUCBpcyB1bmFibGUgdG8gYmUgY2FsY3VsYXRlZCBhbmQgcGxvdHMgd2lsbCBub3QgYmUgc2hvd24uCgogICAgICA8L2Rpdj4KICAgICIpCiAgfQp9CmBgYAoKIyMgS25lZSBQbG90CgpgYGB7ciwgZmlnLmFsdD0iU21vb3RoZWQga25lZSBwbG90IG9mIGZpbHRlcmVkIGFuZCB1bmZpbHRlcmVkIGRyb3BsZXRzIn0KdW5maWx0ZXJlZF9jZWxsZGF0YSA8LSBkYXRhLmZyYW1lKGNvbERhdGEodW5maWx0ZXJlZF9zY2UpKSB8PgogIG11dGF0ZSgKICAgIHJhbmsgPSByYW5rKC0gdW5maWx0ZXJlZF9zY2Ukc3VtLCB0aWVzLm1ldGhvZCA9ICJmaXJzdCIpLCAjIHVzaW5nIGZ1bGwgc3BlYyBmb3IgY2xhcml0eQogICAgZmlsdGVyX3Bhc3MgPSBjb2xuYW1lcyh1bmZpbHRlcmVkX3NjZSkgJWluJSBjb2xuYW1lcyhmaWx0ZXJlZF9zY2UpCiAgKSB8PgogIHNlbGVjdChzdW0sIHJhbmssIGZpbHRlcl9wYXNzKSB8PgogIGZpbHRlcihzdW0gPiAwKSAjIHJlbW92ZSB6ZXJvcyBmb3IgcGxvdHRpbmcKCgpncm91cGVkX2NlbGxkYXRhIDwtIHVuZmlsdGVyZWRfY2VsbGRhdGEgfD4KICBtdXRhdGUocmFua19ncm91cCA9IGZsb29yKHJhbmsgLyAxMDApICl8PgogIGdyb3VwX2J5KHJhbmtfZ3JvdXApIHw+CiAgc3VtbWFyaXplKAogICAgbWVkX3N1bSA9IG1lZGlhbihzdW0pLAogICAgbWVkX3JhbmsgPSBtZWRpYW4ocmFuayksCiAgICBwY3RfcGFzc2VkID0gc3VtKGZpbHRlcl9wYXNzKSAvIG4oKSAqIDEwMAogICkKCnRvcF9jZWxsZGF0YSA8LSB1bmZpbHRlcmVkX2NlbGxkYXRhIHw+CiAgZmlsdGVyKHJhbmsgPD0gNTApIHw+CiAgbXV0YXRlKGZpbHRlcl9wY3QgPSBpZmVsc2UoZmlsdGVyX3Bhc3MsIDEwMCwgMCkpCgpnZ3Bsb3QoZ3JvdXBlZF9jZWxsZGF0YSwgYWVzKHggPSBtZWRfcmFuaywgeSA9IG1lZF9zdW0sIGNvbG9yID0gcGN0X3Bhc3NlZCkpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IHJhbmssIHkgPSBzdW0sIGNvbG9yID0gZmlsdGVyX3BjdCksCiAgICAgICAgICAgICBkYXRhID0gdG9wX2NlbGxkYXRhLAogICAgICAgICAgICAgYWxwaGEgPSAwLjUpICsKICBnZW9tX2xpbmUobGluZXdpZHRoID0gMiwgbGluZWVuZCA9ICJyb3VuZCIsIGxpbmVqb2luPSAicm91bmQiKSArCiAgc2NhbGVfeF9sb2cxMChsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX251bWJlcihhY2N1cmFjeSA9IDEpKSArCiAgc2NhbGVfeV9sb2cxMChsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX251bWJlcihhY2N1cmFjeSA9IDEpKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQyKGxvdyA9ICJncmV5NzAiLAogICAgICAgICAgICAgICAgICAgICAgICBtaWQgPSAiZm9yZXN0Z3JlZW4iLAogICAgICAgICAgICAgICAgICAgICAgICBoaWdoID0gImRhcmtncmVlbiIsCiAgICAgICAgICAgICAgICAgICAgICAgIG1pZHBvaW50ID0gNTApICsKICBsYWJzKAogICAgeCA9ICJSYW5rIiwKICAgIHkgPSAiVG90YWwgVU1JIGNvdW50IiwKICAgIGNvbG9yID0gIiUgcGFzc2luZ1xuY2VsbCBmaWx0ZXIiCiAgKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gYygwLCAwKSwKICAgICAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoMCwwKSwKICAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvciA9ICJncmV5MjAiLCBsaW5ld2lkdGggPSAwLjI1KSwKICAgICAgICBsZWdlbmQuYm94Lm1hcmdpbiA9IG1hcmdpbihyZXAoNSwgNCkpKQpgYGAKClRoZSB0b3RhbCBVTUkgY291bnQgb2YgZWFjaCBkcm9wbGV0IChiYXJjb2RlKSBwbG90dGVkIGFnYWluc3QgdGhlIHJhbmsgb2YgdGhhdCBkcm9wbGV0IGFsbG93cyB2aXN1YWxpemF0aW9uIG9mIHRoZSBkaXN0cmlidXRpb24gb2Ygc2VxdWVuY2luZyBkZXB0aCBhY3Jvc3MgZHJvcGxldHMuClRoZSBkcm9wbGV0cyB0aGF0IGFyZSBleHBlY3RlZCB0byBjb250YWluIGNlbGxzIHdlcmUgaWRlbnRpZmllZCB3aXRoIFtgRHJvcGxldFV0aWxzOjplbXB0eURyb3BzQ2VsbFJhbmdlcigpYF0oaHR0cHM6Ly9iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL3JlbGVhc2UvYmlvYy9odG1sL0Ryb3BsZXRVdGlscy5odG1sKSwgdW5sZXNzIG90aGVyd2lzZSBzcGVjaWZpZWQgaW4gdGhlIGBDZWxsIFN0YXRpc3RpY3NgIHRhYmxlLCB3aGljaCB1c2VzIGJvdGggdGhlIHRvdGFsIFVNSSBjb3VudHMgYW5kIGV4cHJlc3NlZCBnZW5lIGNvbnRlbnQgKGFkYXB0ZWQgZnJvbSBbTHVuICBfZXQgYWwuXyAyMDE5XShodHRwczovL2RvaS5vcmcvMTAuMTE4Ni9zMTMwNTktMDE5LTE2NjIteSkpLgpBcyB0aGUgYm91bmRhcnkgYmV0d2VlbiBkcm9wbGV0cyBwYXNzaW5nIGFuZCBmYWlsaW5nIHRoaXMgZmlsdGVyIGlzIG5vdCBzb2xlbHkgZGVwZW5kZW50IG9uIHRvdGFsIFVNSSBjb3VudCwgc29tZSByZWdpb25zIGNvbnRhaW4gZHJvcGxldHMgaW4gYm90aCBjYXRlZ29yaWVzLgpUaGUgY29sb3IgaW4gdGhpcyBwbG90IGluZGljYXRlcyB0aGUgcGVyY2VudGFnZSBvZiBkcm9wbGV0cyBpbiBhIHJlZ2lvbiBwYXNzaW5nIHRoZSBmaWx0ZXIuCgojIyBDZWxsIFJlYWQgTWV0cmljcwoKYGBge3IsIGZpZy5hbHQ9IlRvdGFsIFVNSSB4IGdlbmVzIGV4cHJlc3NlZCJ9CmZpbHRlcmVkX2NlbGxkYXRhIDwtIGRhdGEuZnJhbWUoY29sRGF0YShmaWx0ZXJlZF9zY2UpKQoKZ2dwbG90KGZpbHRlcmVkX2NlbGxkYXRhLAogICAgICAgYWVzICh4ID0gc3VtLAogICAgICAgICAgICB5ID0gZGV0ZWN0ZWQsCiAgICAgICAgICAgIGNvbG9yID0gc3Vic2V0c19taXRvX3BlcmNlbnQpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMykgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYyhsaW1pdHMgPSBjKDAsIDEwMCkpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpsYWJlbF9udW1iZXIoYWNjdXJhY3kgPSAxKSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX251bWJlcihhY2N1cmFjeSA9IDEpKSArCiAgbGFicyh4ID0gIlRvdGFsIFVNSSBjb3VudCIsCiAgICAgICB5ID0gIk51bWJlciBvZiBnZW5lcyBkZXRlY3RlZCIsCiAgICAgICBjb2xvciA9ICJQZXJjZW50IHJlYWRzXG5taXRvY2hvbmRyaWFsIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMCwgMSksCiAgICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSBjKDAsMSksCiAgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3IgPSAiZ3JleTIwIiwgbGluZXdpZHRoID0gMC4yNSksCiAgICAgICAgbGVnZW5kLmJveC5tYXJnaW4gPSBtYXJnaW4ocmVwKDUsIDQpKSkKYGBgCgpUaGUgYWJvdmUgcGxvdCBvZiBjZWxsIG1ldHJpY3MgaW5jbHVkZXMgb25seSBkcm9wbGV0cyB3aGljaCBoYXZlIHBhc3NlZCB0aGUgYGVtcHR5RHJvcHNDZWxsUmFuZ2VyKClgIGZpbHRlci4KVGhlIHBsb3Qgd2lsbCB1c3VhbGx5IGRpc3BsYXkgYSBzdHJvbmcgKGJ1dCBjdXJ2ZWQpIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSB0b3RhbCBVTUkgY291bnQgYW5kIHRoZSBudW1iZXIgb2YgZ2VuZXMgZGV0ZWN0ZWQuCkNlbGxzIHdpdGggbG93IFVNSSBjb3VudHMgYW5kIGhpZ2ggbWl0b2Nob25kcmlhbCBwZXJjZW50YWdlcyBtYXkgcmVxdWlyZSBmdXJ0aGVyIGZpbHRlcmluZy4KCiMjIG1pUUMgTW9kZWwgRGlhZ25vc3RpY3MKCmBgYHtyLCBmaWcuYWx0PSJtaVFDIG1vZGVsIGRpYWdub3N0aWNzIHBsb3QiLCByZXN1bHRzPSdhc2lzJywgd2FybmluZz1GQUxTRX0KaWYgKHNraXBfbWlRQykgewogIGNhdCgibWlRQyBtb2RlbCBub3QgY3JlYXRlZCwgc2tpcHBpbmcgbWlRQyBwbG90LiBVc3VhbGx5IHRoaXMgaXMgYmVjYXVzZSBtaXRvY2hvbmRyaWFsIGdlbmUgZGF0YSB3YXMgbm90IGF2YWlsYWJsZS4iKQp9IGVsc2UgewogICMgcmVtb3ZlIHByb2JfY29tcHJvbWlzZWQgaWYgaXQgZXhpc3RzLCBhcyB0aGlzIHdpbGwgY2F1c2UgZXJyb3JzIHdpdGggcGxvdE1vZGVsCiAgZmlsdGVyZWRfc2NlJHByb2JfY29tcHJvbWlzZWQgPC0gTlVMTAogIG1pUUNfbW9kZWwgPC0gbWV0YWRhdGEoZmlsdGVyZWRfc2NlKSRtaVFDX21vZGVsCgogIGlmIChpcy5udWxsKG1pUUNfbW9kZWwpIHx8IGxlbmd0aChtaVFDX21vZGVsQGNvbXBvbmVudHMpIDwgMikgewogICAgIyBtb2RlbCBkaWRuJ3QgZml0LCBqdXN0IHBsb3QgbWV0cmljcwogICAgbWlRQ19wbG90IDwtIG1pUUM6OnBsb3RNZXRyaWNzKGZpbHRlcmVkX3NjZSkKICB9IGVsc2UgewogICAgbWlRQ19wbG90IDwtIG1pUUM6OnBsb3RNb2RlbChmaWx0ZXJlZF9zY2UsIG1vZGVsID0gbWlRQ19tb2RlbCkKICB9CgogIG1pUUNfcGxvdCArCiAgICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwxMDApKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpsYWJlbF9udW1iZXIoYWNjdXJhY3kgPSAxKSkgKwogICAgbGFicyh4ID0gIk51bWJlciBvZiBnZW5lcyBkZXRlY3RlZCIsCiAgICAgICAgIHkgPSAiUGVyY2VudCByZWFkcyBtaXRvY2hvbmRyaWFsIikgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gYygxLCAxKSwKICAgICAgICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygxLDEpLAogICAgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3IgPSAiZ3JleTIwIiwgbGluZXdpZHRoID0gMC4yNSksCiAgICAgICAgICBsZWdlbmQuYm94Lm1hcmdpbiA9IG1hcmdpbihyZXAoNSwgNCkpKQp9CmBgYAoKV2UgY2FsY3VsYXRlIHRoZSBwcm9iYWJpbGl0eSB0aGF0IGEgY2VsbCBpcyBjb21wcm9taXNlZCBkdWUgdG8gZGVncmFkYXRpb24gb3IgcnVwdHVyZSB1c2luZyBbYG1pUUNgXShodHRwczovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvcmVsZWFzZS9iaW9jL2h0bWwvbWlRQy5odG1sKSAoW0hpcHBlbiBfZXQgYWwuXyAyMDIxXShodHRwczovL2RvaS5vcmcvMTAuMTM3MS9qb3VybmFsLnBjYmkuMTAwOTI5MCkpLgpUaGlzIHJlbGllcyBvbiBmaXR0aW5nIGEgbWl4dHVyZSBtb2RlbCB1c2luZyB0aGUgbnVtYmVyIG9mIGdlbmVzIGV4cHJlc3NlZCBieSBhIGNlbGwgYW5kIHRoZSBwZXJjZW50YWdlIG9mIG1pdG9jaG9uZHJpYWwgcmVhZHMuClRoZSBleHBlY3RlZCBwbG90IHdpbGwgc2hvdyBhIGNoYXJhY3RlcmlzdGljIHRyaWFuZ3VsYXIgc2hhcGUgYW5kIHR3byBtb2RlbCBmaXQgbGluZXMuCkNlbGxzIHdpdGggbG93IG51bWJlcnMgb2YgZ2VuZXMgZXhwcmVzc2VkIG1heSBoYXZlIGJvdGggbG93IGFuZCBoaWdoIG1pdG9jaG9uZHJpYWwgcGVyY2VudGFnZSwgYnV0IGNlbGxzIHdpdGggbWFueSBnZW5lcyB0ZW5kIHRvIGhhdmUgYSBsb3cgbWl0b2Nob25kcmlhbCBwZXJjZW50YWdlLgpDb21wcm9taXNlZCBjZWxscyBhcmUgbGlrZWx5IHRvIGhhdmUgYSBmZXdlciBnZW5lcyBkZXRlY3RlZCBhbmQgaGlnaGVyIHBlcmNlbnRhZ2Ugb2YgbWl0b2Nob25kcmlhbCByZWFkcy4KCklmIHRoZSBtb2RlbCBoYXMgZmFpbGVkIHRvIGZpdCBwcm9wZXJseSwgdGhlIHBhdHRlcm4gb2YgY2VsbHMgbWF5IGRpZmZlciwgYW5kIHRoZXJlIG1heSBub3QgYmUgbW9kZWwgZml0IGxpbmVzLgpUaGlzIGNhbiBiZSB0aGUgcmVzdWx0IG9mIGEgbG93LXF1YWxpdHkgbGlicmFyeSBvciBtYXkgb2NjdXIgaWYgdGhlcmUgaXMgbm8gbWl0b2Nob25kcmlhbCBjb250ZW50LCBhcyBpbiB0aGUgY2FzZSBvZiBhIGhpZ2gtcXVhbGl0eSBzaW5nbGUtbnVjbGV1cyBzYW1wbGUuCkluIHN1Y2ggc2l0dWF0aW9ucywgdGhlIGNhbGN1bGF0ZWQgcHJvYmFiaWxpdHkgb2YgY29tcHJvbWlzZSBtYXkgbm90IGJlIHZhbGlkIChzZWUgW21pUUMgdmlnbmV0dGVdKGh0dHBzOi8vYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy8zLjEzL2Jpb2MvdmlnbmV0dGVzL21pUUMvaW5zdC9kb2MvbWlRQy5odG1sI3doZW4tbm90LXRvLXVzZS1taXFjKSBmb3IgbW9yZSBkZXRhaWxzKS4KCiMjIFJlbW92aW5nIGxvdyBxdWFsaXR5IGNlbGxzCgpUaGUgYmVsb3cgcGxvdCBoaWdobGlnaHRzIGNlbGxzIHRoYXQgd2VyZSByZW1vdmVkIHByaW9yIHRvIG5vcm1hbGl6YXRpb24gYW5kIGRpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbi4KQ2VsbHMgdGhhdCBzaG91bGQgYmUgcmVtb3ZlZCBiYXNlZCBvbiBSTkEgY291bnRzIGFyZSB0aG9zZSB0aGF0IGFyZSBpZGVudGlmaWVkIHRvIGJlIGxvdyBxdWFsaXR5IGNlbGxzLCBzdWNoIGFzIGNlbGxzIHdpdGggaGlnaCBwcm9iYWJpbGl0eSBvZiBiZWluZyBjb21wcm9taXNlZC4KVGhlIG1ldGhvZCBvZiBmaWx0ZXJpbmcgaXMgaW5kaWNhdGVkIGFib3ZlIHRoZSBwbG90IGFzIGVpdGhlciBgbWlRQ2Agb3IgYE1pbmltdW0gZ2VuZSBjdXRvZmZgLgpJZiBgbWlRQ2AsIGNlbGxzIGJlbG93IHRoZSBzcGVjaWZpZWQgcHJvYmFiaWxpdHkgY29tcHJvbWlzZWQgY3V0b2ZmIGFuZCBhYm92ZSB0aGUgbWluaW11bSBudW1iZXIgb2YgdW5pcXVlIGdlbmVzIGlkZW50aWZpZWQgYXJlIGtlcHQgZm9yIGRvd25zdHJlYW0gYW5hbHlzZXMuCklmIG9ubHkgYSBgTWluaW11bSBnZW5lIGN1dG9mZmAgaXMgdXNlZCwgdGhlbiBgbWlRQ2AgaXMgbm90IHVzZWQgYW5kIG9ubHkgdGhvc2UgY2VsbHMgdGhhdCBwYXNzIHRoZSBtaW5pbXVtIG51bWJlciBvZiB1bmlxdWUgZ2VuZXMgaWRlbnRpZmllZCB0aHJlc2hvbGQgYXJlIHJldGFpbmVkLgpUaGUgZG90dGVkIHZlcnRpY2FsIGxpbmUgaW5kaWNhdGVzIHRoZSBtaW5pbXVtIGdlbmUgY3V0b2ZmIHVzZWQgZm9yIGZpbHRlcmluZy4KCgpgYGB7ciByZXN1bHRzPSdhc2lzJ30KaWYgKGhhc19maWx0ZXJlZCAmIGhhc19wcm9jZXNzZWQpIHsKCiAgIyBncmFiIGN1dG9mZnMgYW5kIGZpbHRlcmluZyBtZXRob2QgZnJvbSBwcm9jZXNzZWQgc2NlCiAgbWluX2dlbmVfY3V0b2ZmIDwtIHByb2Nlc3NlZF9tZXRhJG1pbl9nZW5lX2N1dG9mZgoKICBmaWx0ZXJfbWV0aG9kIDwtIHByb2Nlc3NlZF9tZXRhJHNjcGNhX2ZpbHRlcl9tZXRob2QKCiAgIyBhZGQgY29sdW1uIHRvIGNvbGRhdGEgbGFiZWxpbmcgY2VsbHMgdG8ga2VlcC9yZW1vdmUgYmFzZWQgb24gZmlsdGVyaW5nIG1ldGhvZAogIGZpbHRlcmVkX2NvbGRhdGFfZGYgPC0gY29sRGF0YShmaWx0ZXJlZF9zY2UpIHw+CiAgICBhcy5kYXRhLmZyYW1lKCkgfD4KICAgIHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKCJiYXJjb2RlIikKCiAgZ2dwbG90KGZpbHRlcmVkX2NvbGRhdGFfZGYsIGFlcyh4ID0gZGV0ZWN0ZWQsIHkgPSBzdWJzZXRzX21pdG9fcGVyY2VudCwgY29sb3IgPSBzY3BjYV9maWx0ZXIpKSArCiAgICBnZW9tX3BvaW50KGFscGhhID0gMC41LCBzaXplID0gMSkgKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbWluX2dlbmVfY3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICBsYWJzKHggPSAiTnVtYmVyIG9mIGdlbmVzIGRldGVjdGVkIiwKICAgICAgICAgeSA9ICJNaXRvY2hvbmRyaWFsIHBlcmNlbnRhZ2UiLAogICAgICAgICBjb2xvciA9ICJGaWx0ZXIiLAogICAgICAgICB0aXRsZSA9IHN0cmluZ3I6OnN0cl9yZXBsYWNlKGZpbHRlcl9tZXRob2QsICJfIiwgIiAiKSkgKwogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBjKDEsIDEpLAogICAgICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSBjKDEsMSksCiAgICAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvciA9ICJncmV5MjAiLCBsaW5ld2lkdGggPSAwLjI1KSwKICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCn0gZWxzZSB7CiAgZ2x1ZTo6Z2x1ZSgiCiAgICA8ZGl2IGNsYXNzPVwiYWxlcnQgYWxlcnQtd2FybmluZ1wiPgoKICAgIE5vIGZpbHRlcmluZyBvZiBsb3cgcXVhbGl0eSBjZWxscyB3YXMgcGVyZm9ybWVkIG9uIHRoaXMgbGlicmFyeS4KCiAgICA8L2Rpdj4KICAiKQp9CmBgYAoKVGhlIHJhdyBjb3VudHMgZnJvbSBhbGwgY2VsbHMgdGhhdCByZW1haW4gYWZ0ZXIgZmlsdGVyaW5nIGxvdyBxdWFsaXR5IGNlbGxzIChSTkEgb25seSkgYXJlIHRoZW4gbm9ybWFsaXplZCBwcmlvciB0byBzZWxlY3Rpb24gb2YgaGlnaGx5IHZhcmlhYmxlIGdlbmVzIGFuZCBkaW1lbnNpb25hbGl0eSByZWR1Y3Rpb24uCgoKCjwhLS0gTmV4dCBzZWN0aW9uIGluY2x1ZGUgb25seSBpZiBVTUFQIGlzIHByZXNlbnQgLS0+CmBgYHtyLCBjaGlsZD0ndW1hcF9xYy5ybWQnLCBldmFsID0gaGFzX3VtYXB9CgpgYGAKCjwhLS0gTmV4dCBzZWN0aW9uIGluY2x1ZGVkIG9ubHkgaWYgQ0lURS1zZXEgZGF0YSBpcyBwcmVzZW50IC0tPgpgYGB7ciwgY2hpbGQ9J2NpdGVfcWMucm1kJywgZXZhbCA9IGhhc19hZHR9CmBgYAoKPCEtLSBOZXh0IHNlY3Rpb24gb25seSBpbmNsdWRlZCBpZiBtdWx0aXBsZXggZGF0YSBpcyBwcmVzZW50IC0tPgpgYGB7ciwgY2hpbGQ9J211bHRpcGxleF9xYy5ybWQnLCBldmFsID0gaGFzX2NlbGxoYXNofQoKYGBgCgoKIyBTZXNzaW9uIEluZm8KPGRldGFpbHM+CjxzdW1tYXJ5PlIgc2Vzc2lvbiBpbmZvcm1hdGlvbjwvc3VtbWFyeT4KYGBge3Igc2Vzc2lvbl9pbmZvfQppZiAocmVxdWlyZU5hbWVzcGFjZSgic2Vzc2lvbmluZm8iLCBxdWlldGx5ID0gVFJVRSkpIHsKICBzZXNzaW9uaW5mbzo6c2Vzc2lvbl9pbmZvKCkKfSBlbHNlIHsKICBzZXNzaW9uSW5mbygpCn0KCmBgYAo8L2RldGFpbHM+Cgo=