1 Overview

In Tang et al. (2024), we developed the simplified MyProstateScore2.0 (sMPS2), a 7-gene urine test which achieves similar state-of-the-art diagnostic accuracy for predicting high-grade prostate cancer as the original 18-gene MyProstateScore2.0 (MPS2) (Tosoian et al. 2024). This simplified biomarker test provides a more cost-effective alternative to the original MPS2 test and greatly increases its accessibility for routine clinical care.

In this PCS documentation (Yu and Kumbier 2020), we expand upon the sMPS2 model development pipeline, transparently documenting and justifying human judgment calls (including data preprocessing and modeling decisions) when possible. We also provide additional visualizations and stability analyses to further support the robustness and generalizability of the sMPS2 test.

2 Exploratory Data Analysis

In this section, we provide a brief exploration of the Development Cohort data, which was used to develop the simplified MyProstateScore2.0 (sMPS2) test. This Development Cohort consists of 761 samples and was used to build the original MPS2 models (Tosoian et al. 2024).

Below, we visualize the (marginal) distribution of each gene and clinical variable, grouped by prostate cancer (PCa) grade. Some interesting observations:

  • The expression of some genes, such as PCA3 and T2:ERG (used in the original MPS test (Tomlins et al. 2011)), show clear differences between low- and high-grade prostate cancers (Figure 2.2).
  • While PSA, by itself, appears to have limited diagnostic accuracy in this cohort, prostate volume shows greater potential for distinguishing between low- and high-grade PCa (Figure 2.4).
  • We emphasize that these are merely observations based on marginal analyses. More formal analyses will be conducted in subsequent sections.

We also plot a correlation heatmap (Figure 2.3), showing the pairwise relationships between two genes’ expressions (as measured via their Ct values). This correlation heatmap shows that there are indeed strong positive correlations between groups of genes, which can complicate the interpretation and affect the stability of feature importances.

Primary Outcome

Figure 2.1: Number of high-grade and low-grade prostate cancer (PCa) patients in Development Cohort.

Gene Expression Data

Distribution of Ct values in Development Cohort for each gene by prostate cancer (PCa) grade.

Figure 2.2: Distribution of Ct values in Development Cohort for each gene by prostate cancer (PCa) grade.

Figure 2.3: Correlation heatmap of gene expression (Ct values) in Development Cohort data. Genes have been clustered using hierarchical clustering.

Clinical Variables

Distribution of clinical features in Development Cohort by prostate cancer (PCa) grade.

Figure 2.4: Distribution of clinical features in Development Cohort by prostate cancer (PCa) grade.

3 Data Preprocessing Choices

As discussed in Tang et al. (2024), gene expression in each urine sample was measured via the cycle threshold (Ct) using qPCR profiling across 54 genes. These 54 genes were previously nominated as potential biomarkers for prostate cancer (PCa) detection in the MPS2 study (Tosoian et al. 2024) and are thus of interest here. In what follows, we recap the data preprocessing procedure used in this study (also described in Tang et al. (2024)) and provide additional justification for our judgment calls wherever possible.

As a starting point, we preprocessed the expression data as in the original MPS2 study (Tosoian et al. 2024):

  1. We set the upper Ct value limit to 35. Specifically, Ct values greater than this limit were considered undetected and set to 35. Ct values from OpenArray that were “Undetermined” or “Inconclusive/No Amp” were also considered to be undetected and set to the upper Ct value limit of 35.

    • While it is arguably common practice to set the upper Ct value limit to 40, previous work has shown that setting the Ct value limit to 40 can often introduce unwanted biases and that setting this limit to 35 can effectively reduce this bias (McCall et al. 2014).
  2. We computed the standard deviation (SD) across 3 technical replicates. If SD \(\geq\) 1, the replicate farthest from the mean was removed; otherwise, all 3 replicates were kept. This is to help filter out poor quality replicates.

  3. We computed the average Ct value across the remaining technical replicates.

  4. All samples with an average Ct value of the reference gene KLK3 above the 95th percentile were removed.

    • Note that KLK3 is a well-known prostate marker. Hence, if the urine sample does not contain detectable levels of KLK3 (i.e., the average Ct value for KLK3 is high), it is unlikely that the sample will contain detectable levels of other prostate cancer biomarkers. We thus performed this filtering step to remove poor quality samples.
  5. We normalized the average Ct values for each target gene by KLK3 using the formula -[ average Ct of gene X - average Ct of KLK3 ].

  6. Finally, z-score scaling was applied to the normalized average Ct before downstream model development and feature selection.

We refer to this data preprocessing pipeline as the base preprocessing pipeline. However, there are several alternative, but equally-reasonable ways to deal with undetectable Ct values and poor quality samples in the data preprocessing. While we cannot explore all possible preprocessing choices, we do explore a few alternatives in this work in order to improve the robustness of our model and conclusions. Namely, we considered the following alternative preprocessing pipelines:

  • Ct limit = 40 preprocessing pipeline: Rather than setting the upper Ct value limit to 35 for undetected replicates, we instead follow popular practice and set the upper Ct value limit to 40. All other preprocessing steps remain unchanged from the base preprocessing pipeline.
  • Normalized Ct limit = -21 preprocessing pipeline: In the aforementioned data preprocessing pipelines, the Ct values for undetected replicates were set prior to the normalization of the Ct values. Thus, the normalized Ct value for undetected replicates differs between genes. For comparison, in this preprocessing pipeline, we instead replace the Ct values for all undetected replicates after Ct normalization to have a constant value of -21 (which was the lowest Ct value post-normalization). All other preprocessing steps remain unchanged from the base preprocessing pipeline.
  • No sample exclusion preprocessing pipeline: Rather than excluding all samples with an average Ct value of the reference gene KLK3 above the 95th percentile, this preprocessing pipeline does not exclude any samples based upon their Ct value for the reference gene KLK3. This is to assess whether or not the exclusion of samples based upon their Ct value for the reference gene KLK3 impacts downstream conclusions. All other data preprocessing steps remain unchanged from the base preprocessing pipeline.

In addition to these preprocessed gene expression data, we also have access to various clinical data for each sample. We chose to focus on the following clinical variables for model development, as they are both known to be associated with high-grade prostate cancer and generally available in clinical practice: age, race, family history of prostate cancer, abnormal DRE, prior negative biopsy, and prostate specific antigen (PSA) (Thompson et al. 2006).

4 Modeling Choices

For each preprocessed dataset, we trained many different statistical/machine learning models to predict high-grade prostate cancer (PCa). Specifically, we considered the following models:

Logistic-based Models:

  • Logistic regression
  • Logistic regression with \(L_1\) (LASSO) regularization
  • Logistic regression with \(L_2\) (ridge) regularization
  • Logistic regression with combined \(L_1\) + \(L_2\) (elastic net) regularization

Tree-based Models:

  • Random forests (RF)
  • Gradient boosting decision trees (GBDT)
  • RuleFit
  • Random forests+ (RF+)
  • Fast interpretable greedy-tree sums (FIGS)

We focused on these logistic- and tree-based models given the importance of interpretability and our goal of identifying important genes for reliable biomarker development. While the logistic-based models are generally thought to serve as baseline models, the tree-based models can provide greater flexibility to capture more complex relationships between genes and the outcome of interest without sacrificing interpretability. We note that other flexible but interpretable machine learning models could also be considered and may be of interest in future work. However, in this current work, we chose to first focus on these logistic-based models and tree-based models – the latter of which is often uniquely suited for biological tasks such as this, in part due to the resemblance between the thresholding behavior of decision trees and the on-off switch-like behavior commonly thought to govern genetic processes (Nelson, Lehninger, and Cox 2008).

We detailed the hyperparameters and python implementation used for each model in Table 1 in Tang et al. (2024). Hyperparameters were tuned using 5-fold cross-validation.

5 Prediction Check

As the first step in the sMPS2 model development pipeline, we performed a prediction check to filter out models which have poor prediction performance and thus may not accurately reflect reality (Yu and Kumbier 2020). Here, guided by the PCS framework, we use prediction performance as a reality check and a minimum requirement for interpretability. Moreover, we assess the prediction performance, not only for different models but also for different data preprocessing pipelines. Examining multiple prediction metrics (i.e., area under the receiver operating characteristic (AUROC), area under the precision-recall curve (AUPRC), and classification accuracy), we found that:

  • The prediction performance was quite stable across different data preprocessing pipelines. Notably, the variation in prediction performance across data preprocessing pipelines (blue barplot) was substantially smaller than the variation in prediction performance across models (pink barplot). These observations suggest that downstream conclusions are robust to these data preprocessing choices.
  • Ordinary logistic regression appears to have reasonable prediction performance (only \(\sim 1\%\) lower than the best-performing model in terms of AUROC). Given its simplicity, we chose to use logistic regression as the baseline model to determine whether or not other models passed the prediction check.
  • RuleFit, GBDT, and FIGS, on average, performed worse than logistic regression across the different prediction performance metrics, suggesting that they may not be appropriate fits for this data. RF also performed slightly worse than logistic regression on average. However, unlike RuleFit, GBDT, and FIGS, RF yielded higher prediction performance (measured via AUROC, AUPRC, and classification accuracy) than logistic regression in at least one data preprocessing pipeline. We thus excluded RuleFit, GBDT, and FIGS (but not RF) from the remainder of the model development pipeline.

We defer additional methodological details on how this prediction check was conducted to Tang et al. (2024).

AUROC

(Left) For each choice of data preprocessing and prediction model, the validation AUROC, averaged across 4 CV folds and 10 repeated Development-Test splits, is shown. The error bars represent the inner 95% quantile range of the distribution of AUROCs. (Middle, Right) We compare the variation in AUROC across data preprocessing pipelines and methods. In the middle subplot, we show the range of mean AUROCs across the four data preprocessing pipelines for each method. In the right subplot, we show the difference between the mean AUROC from each method and the best performing method (i.e., logistic regression with the elastic net penalty) across all data preprocessing pipelines. The difference in AUROCs across data preprocessing pipelines is substantially smaller than that across prediction methods, suggesting that the development pipeline and downstream findings are robust to data preprocessing choices.

Figure 5.1: (Left) For each choice of data preprocessing and prediction model, the validation AUROC, averaged across 4 CV folds and 10 repeated Development-Test splits, is shown. The error bars represent the inner 95% quantile range of the distribution of AUROCs. (Middle, Right) We compare the variation in AUROC across data preprocessing pipelines and methods. In the middle subplot, we show the range of mean AUROCs across the four data preprocessing pipelines for each method. In the right subplot, we show the difference between the mean AUROC from each method and the best performing method (i.e., logistic regression with the elastic net penalty) across all data preprocessing pipelines. The difference in AUROCs across data preprocessing pipelines is substantially smaller than that across prediction methods, suggesting that the development pipeline and downstream findings are robust to data preprocessing choices.

AUPRC

(Left) For each choice of data preprocessing and prediction model, the validation AUPRC, averaged across 4 CV folds and 10 repeated Development-Test splits, is shown. The error bars represent the inner 95% quantile range of the distribution of AUPRCs. (Middle, Right) We compare the variation in AUPRC across data preprocessing pipelines and methods. In the middle subplot, we show the range of mean AUPRCs across the four data preprocessing pipelines for each method. In the right subplot, we show the difference between the mean AUPRC from each method and the best performing method (i.e., logistic regression with the elastic net penalty) across all data preprocessing pipelines. The difference in AUPRCs across data preprocessing pipelines is substantially smaller than that across prediction methods, suggesting that the development pipeline and downstream findings are robust to data preprocessing choices.

Figure 5.2: (Left) For each choice of data preprocessing and prediction model, the validation AUPRC, averaged across 4 CV folds and 10 repeated Development-Test splits, is shown. The error bars represent the inner 95% quantile range of the distribution of AUPRCs. (Middle, Right) We compare the variation in AUPRC across data preprocessing pipelines and methods. In the middle subplot, we show the range of mean AUPRCs across the four data preprocessing pipelines for each method. In the right subplot, we show the difference between the mean AUPRC from each method and the best performing method (i.e., logistic regression with the elastic net penalty) across all data preprocessing pipelines. The difference in AUPRCs across data preprocessing pipelines is substantially smaller than that across prediction methods, suggesting that the development pipeline and downstream findings are robust to data preprocessing choices.

Accuracy

(Left) For each choice of data preprocessing and prediction model, the validation Accuracy, averaged across 4 CV folds and 10 repeated Development-Test splits, is shown. The error bars represent the inner 95% quantile range of the distribution of Accuracys. (Middle, Right) We compare the variation in Accuracy across data preprocessing pipelines and methods. In the middle subplot, we show the range of mean Accuracys across the four data preprocessing pipelines for each method. In the right subplot, we show the difference between the mean Accuracy from each method and the best performing method (i.e., logistic regression with the elastic net penalty) across all data preprocessing pipelines. The difference in Accuracys across data preprocessing pipelines is substantially smaller than that across prediction methods, suggesting that the development pipeline and downstream findings are robust to data preprocessing choices.

Figure 5.3: (Left) For each choice of data preprocessing and prediction model, the validation Accuracy, averaged across 4 CV folds and 10 repeated Development-Test splits, is shown. The error bars represent the inner 95% quantile range of the distribution of Accuracys. (Middle, Right) We compare the variation in Accuracy across data preprocessing pipelines and methods. In the middle subplot, we show the range of mean Accuracys across the four data preprocessing pipelines for each method. In the right subplot, we show the difference between the mean Accuracy from each method and the best performing method (i.e., logistic regression with the elastic net penalty) across all data preprocessing pipelines. The difference in Accuracys across data preprocessing pipelines is substantially smaller than that across prediction methods, suggesting that the development pipeline and downstream findings are robust to data preprocessing choices.

6 Stability-driven Gene Ranking

After filtering out the poor-performing prediction models, we sought next to identify the topmost important genes, which were stably important across all four data preprocessing pipelines, six prediction-checked models, and ten Development-Test splits (i.e., \(4 \times 6 \times 10 = 240\) combinations). Details on how we computed the gene importances for each model are discussed in Tang et al. (2024).

We instead use this opportunity to conduct a stability analysis of the PCS-ensembled gene rankings. As discussed in Tang et al. (2024), the obtained PCS-ensembled gene rankings are an ensemble of gene rankings across four different data preprocessing pipelines and six prediction-checked models (RF, RF+, logistic elastic net, logistic LASSO, logistic ridge, and ordinary logistic regression). We chose to use these six prediction models since each passed the prediction check. However, it is natural to wonder whether the PCS-ensembled gene rankings would change if a different subset of the prediction-checked prediction models were used. In particular, since the original set of prediction models consisted of four logistic-based models and two tree-based models, we investigated how the PCS-ensembled gene rankings would change if we used a “balanced” set of prediction models, composed of two logistic-based models and two tree-based models.

Below in the Gene Ranking Summary tab, we examined the PCS-ensembled gene rankings, ensembled across all four data preprocessing pipelines and

  • all six prediction-checked models (RF, RF+, logistic elastic net, logistic LASSO, logistic ridge, and ordinary logistic regression)
  • two logistic-based models (logistic elastic net and logistic ridge) and the two tree-based models (RF and RF+)
  • two logistic-based models with (logistic elastic net and logistic LASSO) and the two tree-based models (RF and RF+)
  • two logistic-based models with (logistic elastic net and logistic) and the two tree-based models (RF and RF+)

Here, we chose to always include logistic elastic net in the PCS ensemble as it demonstrated the highest predictive power in the prediction check step.

Takeaways from this stability analysis of the PCS-ensembled gene rankings:

  • Besides the shuffled ranking of PCA3, the top gene rankings are the same across the different PCS ensembles:
    • Order of top-ranked genes when including all methods or the balanced ensemble with logistic elastic net, logistic, RF, and RF+: T2:ERG, SCHLAP1, OR51E2, PCAT14, TFF3, PCA3, APOC1
    • Order of top-ranked genes using the two balanced method ensembles, excluding logistic regression: T2:ERG, SCHLAP1, PCA3, OR51E2, PCAT14, TFF3, APOC1
  • When ensembling across all six prediction-checked models, PCA3 was the 5th ranked gene according to its mean rank, ranked in the top 5 in almost 50% of the fits, but appeared to have mild instability (seen by the moderate SD of its ranking distribution) (Figure 6.1). However, when excluding the ordinary logistic regression model (which performed worse than the regularized logistic regression models in the prediction check (Figure 5.1)) from the balanced PCS ensembles, PCA3 became the 3rd ranked gene according to its mean rank, ranked in the top 5 in over 60% of the fits, and exhibited far greater stability than before (Figures 6.2-6.3). This boost in ranking and stability supports the case for including PCA3 in the final sMPS2 model.
  • While APOC1 appears to be a stably ranked top 10 gene in the initial PCS ensemble using all six prediction-checked models, we found that APOC1 only appeared in the top 10 in approximately 50% of the fits when using the balanced PCS ensembles (Figures 6.2-6.4). The top 6 genes, in contrast, appeared in the top 10 in >70% (and often >85%) of the fits when using the balanced PCS ensembles. This contrast is further seen by the stark drop in the top 10 stability plot between TFF3 and APOC1, possibly suggesting that APOC1 is not as stably important as the other top genes and perhaps should be excluded from the final sMPS2 model.
  • Across the different PCS ensembles, the 7th-ranked gene (CAMKK2 in the original PCS ensemble and ERG in the balanced PCS ensembles) and onward appear to have substantially more unstable gene rankings compared to the top 6 genes (as made evident in the SD Rank subplots). For this reason, we chose not to include these genes in the final sMPS2 model.
  • Overall, this stability analysis provided crucial information to help us decide which genes to include in the final sMPS2 model. More specifically, using evidence provided by this stability analysis, we decided to include T2:ERG, SCHLAP1, OR51E2, PCAT14, TFF3, and PCA3 in the final s7MPS2 model. Given the borderline status of APOC1, we also developed the s8MPS2 model, which includes all of the genes from s7MPS2 and APOC1.

To supplement this stability analysis, we also provide a more granular view of the gene rankings per data preprocessing pipeline and model in the Gene Ranking Heatmap tab. These heatmaps showcase both genes that are stably important across all data preprocessing pipelines and methods as well as genes that are stably important across only a subset of data preprocessing pipelines and/or methods. In particular, these heatmaps confirm that the logistic regression model drives much of the instability that we observed previously in the PCA3 gene rankings.

Gene Ranking Summary

Aggregating All Methods

Figure 6.1: Summary of the gene importance rankings, as measuerd by their mean gene ranking across four data preprocessing pipelines and 6 prediction-checked models (Logistic, Logistic Elastic Net, Logistic Lasso, Logistic Ridge, RF, RF+), the variability of their gene rankings as measured by the standard deviation (SD) of this distribution, and the proportion of times that the gene appeared int he top 5, 10, and 17 genes. The six genes highlighted in dark teal were used in the s7MPS2 model. The APOC1 gene, highlighted in light teal, was used in the s8MPS2 model.

Aggregating RF, RF+, Elastic Net, Ridge

Figure 6.2: Summary of the gene importance rankings, as measuerd by their mean gene ranking across four data preprocessing pipelines and 4 prediction-checked models (Logistic Elastic Net, Logistic Ridge, RF, RF+), the variability of their gene rankings as measured by the standard deviation (SD) of this distribution, and the proportion of times that the gene appeared int he top 5, 10, and 17 genes. The six genes highlighted in dark teal were used in the s7MPS2 model. The APOC1 gene, highlighted in light teal, was used in the s8MPS2 model.

Aggregating RF, RF+, Elastic Net, Lasso

Figure 6.3: Summary of the gene importance rankings, as measuerd by their mean gene ranking across four data preprocessing pipelines and 4 prediction-checked models (Logistic Elastic Net, Logistic Lasso, RF, RF+), the variability of their gene rankings as measured by the standard deviation (SD) of this distribution, and the proportion of times that the gene appeared int he top 5, 10, and 17 genes. The six genes highlighted in dark teal were used in the s7MPS2 model. The APOC1 gene, highlighted in light teal, was used in the s8MPS2 model.

Aggregating RF, RF+, Elastic Net, Logistic

Figure 6.4: Summary of the gene importance rankings, as measuerd by their mean gene ranking across four data preprocessing pipelines and 4 prediction-checked models (Logistic, Logistic Elastic Net, RF, RF+), the variability of their gene rankings as measured by the standard deviation (SD) of this distribution, and the proportion of times that the gene appeared int he top 5, 10, and 17 genes. The six genes highlighted in dark teal were used in the s7MPS2 model. The APOC1 gene, highlighted in light teal, was used in the s8MPS2 model.

Gene Ranking Heatmap

Figure 6.5: Heatmap of the mean gene ranking (averaged across 10 Development-Test splits) per data preprocessing pipeline and model choice.

Heatmap of the gene ranking per data preprocessing pipeline, model, and Development-Test split. Each row corresponds to a different Development-Test split for the data preprocessing pipeline and model choice labeled on the right.

Figure 6.6: Heatmap of the gene ranking per data preprocessing pipeline, model, and Development-Test split. Each row corresponds to a different Development-Test split for the data preprocessing pipeline and model choice labeled on the right.

7 Validation

We next assessed the impact of the choice of gene panel size (i.e,. the number of top-ranked genes used in the sMPS2 model) and the gene ranking strategy (i.e., model-specific versus model-ensembled versus PCS-ensembled) on the prediction accuracy, evaluated on the test set (from the Development-Test split). Test prediction accuracies are averaged across 10 different Development-Test splits. In this section, we summarize these test prediction results (measured via AUROC, AUPRC, and classification accuracy) across the different gene panel sizes, gene ranking strategies, data preprocessing pipelines, and model choices. In general, the results suggest that 6 or 7 genes are sufficient to achieve competitive prediction performance, and that the PCS-ensembled gene ranking strategy is the most robust across different data preprocessing pipelines and model choices.

In Tang et al. (2024), we additionally conducted and detailed an external validation study, which confirmed the strong prediction accuracy of the sMPS2 models. However, given the blinded nature of the external validation study, the data is not accessible by the co-first authors for use in this PCS documentation. We refer the reader to the original publication for details.

AUROC

Mean AUROC, evaluated on test set, when training various models (rows) using various choices of gene panel sizes (x-axis), data preprocessing pipelines (columns), and gene rankings (color). The PCS-ensembled gene rankings (in black) generally yield the highest test AUROCs compared to other procedures for obtaining the gene rankings. Moreover, using 6 or 7 predictor genes (vertical dotted and dashed lines, respectively) yields very competitive test prediction performance and is often comparable to the high achieved AUROC.

Figure 7.1: Mean AUROC, evaluated on test set, when training various models (rows) using various choices of gene panel sizes (x-axis), data preprocessing pipelines (columns), and gene rankings (color). The PCS-ensembled gene rankings (in black) generally yield the highest test AUROCs compared to other procedures for obtaining the gene rankings. Moreover, using 6 or 7 predictor genes (vertical dotted and dashed lines, respectively) yields very competitive test prediction performance and is often comparable to the high achieved AUROC.

AUPRC

Mean AUPRC, evaluated on test set, when training various models (rows) using various choices of gene panel sizes (x-axis), data preprocessing pipelines (columns), and gene rankings (color). The PCS-ensembled gene rankings (in black) generally yield the highest test AUPRCs compared to other procedures for obtaining the gene rankings. Moreover, using 6 or 7 predictor genes (vertical dotted and dashed lines, respectively) yields very competitive test prediction performance and is often comparable to the high achieved AUPRC.

Figure 7.2: Mean AUPRC, evaluated on test set, when training various models (rows) using various choices of gene panel sizes (x-axis), data preprocessing pipelines (columns), and gene rankings (color). The PCS-ensembled gene rankings (in black) generally yield the highest test AUPRCs compared to other procedures for obtaining the gene rankings. Moreover, using 6 or 7 predictor genes (vertical dotted and dashed lines, respectively) yields very competitive test prediction performance and is often comparable to the high achieved AUPRC.

Accuracy

Mean Accuracy, evaluated on test set, when training various models (rows) using various choices of gene panel sizes (x-axis), data preprocessing pipelines (columns), and gene rankings (color). The PCS-ensembled gene rankings (in black) generally yield the highest test Accuracys compared to other procedures for obtaining the gene rankings. Moreover, using 6 or 7 predictor genes (vertical dotted and dashed lines, respectively) yields very competitive test prediction performance and is often comparable to the high achieved Accuracy.

Figure 7.3: Mean Accuracy, evaluated on test set, when training various models (rows) using various choices of gene panel sizes (x-axis), data preprocessing pipelines (columns), and gene rankings (color). The PCS-ensembled gene rankings (in black) generally yield the highest test Accuracys compared to other procedures for obtaining the gene rankings. Moreover, using 6 or 7 predictor genes (vertical dotted and dashed lines, respectively) yields very competitive test prediction performance and is often comparable to the high achieved Accuracy.

8 Final Remarks

In this PCS documentation (Yu and Kumbier 2020), we have shed additional light on the various decisions that were made throughout the development of the sMPS2 model and have justified many of these choices to the best of our ability. While we acknowledge that other equally-reasonable choices could have been made, we hope that this documentation will be a useful resource for researchers and clinicians who are interested in building upon this work.

Bibliography

McCall, Matthew N, Helene R McMurray, Hartmut Land, and Anthony Almudevar. 2014. “On Non-Detects in qPCR Data.” Bioinformatics 30 (16): 2310–16.
Nelson, David L, Albert L Lehninger, and Michael M Cox. 2008. Lehninger Principles of Biochemistry. Macmillan.
Tang, Tiffany M, Yuping Zhang, Ana M Kenney, Cassie Xie, Yingye Zheng, Jeffrey J Tosoian, Lanbo Xiao, et al. 2024. “A Simplified MyProstateScore2.0 for High-Grade Prostate Cancer.”
Thompson, Ian M, Donna Pauler Ankerst, Chen Chi, Phyllis J Goodman, Catherine M Tangen, M Scott Lucia, Ziding Feng, Howard L Parnes, and Charles A Coltman Jr. 2006. “Assessing Prostate Cancer Risk: Results from the Prostate Cancer Prevention Trial.” Journal of the National Cancer Institute 98 (8): 529–34.
Tomlins, Scott A, Sheila MJ Aubin, Javed Siddiqui, Robert J Lonigro, Laurie Sefton-Miller, Siobhan Miick, Sarah Williamsen, et al. 2011. “Urine TMPRSS2: ERG Fusion Transcript Stratifies Prostate Cancer Risk in Men with Elevated Serum PSA.” Science Translational Medicine 3 (94): 94ra72–72.
Tosoian, Jeffrey J, Yuping Zhang, Lanbo Xiao, Cassie Xie, Nathan L Samora, Yashar S Niknafs, Zoey Chopra, et al. 2024. “Development and Validation of an 18-Gene Urine Test for High-Grade Prostate Cancer.” JAMA Oncology.
Yu, Bin, and Karl Kumbier. 2020. “Veridical Data Science.” Proceedings of the National Academy of Sciences 117 (8): 3920–29. https://doi.org/10.1073/pnas.1901326117.
LS0tCnRpdGxlOiAiUENTIGRvY3VtZW50YXRpb24gZm9yIHRoZSBzaW1wbGlmaWVkIE15UHJvc3RhdGVTY29yZTIuMCAoc01QUzIpIgojIGF1dGhvcjogIlRpZmZhbnkgTS4gVGFuZyIKZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJUIgJWQsICVZJylgIgpiaWJsaW9ncmFwaHk6IGJpYmxpb2dyYXBoeS5iaWIKb3V0cHV0OiAKICB2dGhlbWVzOjp2bW9kZXJuOgogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9Cm9wdGlvbnMod2lkdGggPSAxMDAwMCkKa25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVjaG8gPSBGQUxTRSwgCiAgd2FybmluZyA9IEZBTFNFLCAKICBtZXNzYWdlID0gRkFMU0UsCiAgY2FjaGUgPSBGQUxTRSwKICBmaWcuYWxpZ24gPSAiY2VudGVyIiwKICBmaWcucG9zID0gIkgiLAogICMgZmlnLnNob3cgPSAiaG9sZCIsCiAgZmlnLmhlaWdodCA9IDEyLAogIGZpZy53aWR0aCA9IDEwCikKCmxpYnJhcnkocGF0Y2h3b3JrKQoKUkVTVUxUU19QQVRIIDwtICIuLi9yZXN1bHRzIgpEQVRBX1BBVEggPC0gIi4uL2RhdGEiCkZJR1VSRVNfUEFUSCA8LSAiLi4vcGFwZXJfZmlndXJlcyIKClBJUEVMSU5FUyA8LSBjKAogICJCYXNlIiA9ICJvcmlnaW5hbCIsCiAgIk5vIFNhbXBsZSBFeGNsdXNpb24iID0gIm5vX3NhbXBsZV9maWx0ZXJpbmciLCAKICAiQ3QgTGltaXQgPSA0MCIgPSAiY3Q0MCIsCiAgIk5vcm0uIEN0IExpbWl0ID0gLTIxIiA9ICJub3JtY3QyMSIKKQpSRVBTIDwtIDE6MTAKVE9QS19NT0RFUyA8LSBjKAogICJNb2RlbC1zcGVjaWZpYyIgPSAibmFpdmUiLAogICJNb2RlbC1lbnNlbWJsZWQiID0gImVuc2VtYmxlIiwKICAiUENTLWVuc2VtYmxlZCIgPSAicGNzIgopCgpzdWJjaHVua19pZHggPC0gMQpmaWdfaGVpZ2h0IDwtIDYKZmlnX3dpZHRoIDwtIDE0CgpyZW5hbWVfbWV0aG9kcyA8LSBmdW5jdGlvbihtZXRob2QpIHsKICBkcGx5cjo6Y2FzZV93aGVuKAogICAgbWV0aG9kID09ICJsb2dpc3RpYyIgfiAiTG9naXN0aWMiLAogICAgbWV0aG9kID09ICJlbG5ldCIgfiAiTG9naXN0aWNcbkVsYXN0aWMgTmV0IiwKICAgIG1ldGhvZCA9PSAicmlkZ2UiIH4gIkxvZ2lzdGljXG5SaWRnZSIsCiAgICBtZXRob2QgPT0gImxhc3NvIiB+ICJMb2dpc3RpY1xuTGFzc28iLAogICAgbWV0aG9kID09ICJyYW5kZiIgfiAiUkYiLAogICAgbWV0aG9kID09ICJyZnBsdXMiIH4gIlJGKyIsCiAgICBtZXRob2QgPT0gImZpZ3MiIH4gIkZJR1MiLAogICAgbWV0aG9kID09ICJnYiIgfiAiR0JEVCIsCiAgICBtZXRob2QgPT0gInJ1bGVmaXQiIH4gIlJ1bGVGaXQiLAogICAgVFJVRSB+IG1ldGhvZAogICkKfQoKcmVuYW1lX3BpcGVsaW5lcyA8LSBmdW5jdGlvbihwaXBlbGluZSkgewogIGRwbHlyOjpjYXNlX3doZW4oCiAgICBwaXBlbGluZSA9PSAib3JpZ2luYWwiIH4gIkJhc2UiLAogICAgcGlwZWxpbmUgPT0gIm5vX3NhbXBsZV9maWx0ZXJpbmciIH4gIk5vIFNhbXBsZSBFeGNsdXNpb24iLAogICAgcGlwZWxpbmUgPT0gImN0NDAiIH4gIkN0IExpbWl0ID0gNDAiLAogICAgcGlwZWxpbmUgPT0gIm5vcm1jdDIxIiB+ICJOb3JtLiBDdCBMaW1pdCA9IC0yMSIKICApCn0KCnJlbmFtZV9jb2xzIDwtIGZ1bmN0aW9uKGNvbCkgewogIG91dCA8LSByZW5hbWVfbWV0aG9kcyhjb2wpCiAgZHBseXI6OmNhc2Vfd2hlbigKICAgIG91dCA9PSAiZm9sZF9pZCIgfiAiRm9sZCBJRCIsCiAgICBvdXQgPT0gImF1cm9jIiB+ICJBVVJPQyIsCiAgICBvdXQgPT0gImF1cHJjIiB+ICJBVVBSQyIsCiAgICBvdXQgPT0gInZhciIgfiAiVmFyaWFibGUiLAogICAgb3V0ID09ICJ2YXJuYW1lIiB+ICJWYXJpYWJsZSBOYW1lIiwKICAgIG91dCA9PSAiZXZhbF90eXBlIiB+ICJFdmFsdWF0aW9uIFR5cGUiLAogICAgb3V0ID09ICJrIiB+ICIjIFRvcCBGZWF0dXJlcyIsCiAgICBvdXQgPT0gInNhbXBsZV9pZCIgfiAiU2FtcGxlIElEIiwKICAgIFRSVUUgfiBSLnV0aWxzOjpjYXBpdGFsaXplKG91dCkKICApCn0KCnBhbmVsX2NsYXNzIDwtICJwYW5lbCBwYW5lbC1kZWZhdWx0IHBhZGRlZC1wYW5lbCIKcGFkZGVkX3BhbmVsX2NsYXNzIDwtICJwYW5lbCBwYW5lbC1kZWZhdWx0IHBhZGRlZC1wYW5lbCIKCm1ldHJpY3MgPC0gYygiQVVST0MiLCAiQVVQUkMiLCAiQWNjdXJhY3kiKQppZF9jb2xzIDwtIGMoIlJlcCIsICJGb2xkIElEIiwgIk1ldHJpYyIpCmltZ190eXBlcyA8LSBjKCJwZGYiKQpgYGAKCmBgYHtjc3N9Ci5idG4tdG9vbGJhciB7CiAgZGlzcGxheTogbm9uZTsKfQoKLmZpZ3VyZSBwLmNhcHRpb24gewogIGZvbnQtc2l6ZTogOTAlOwogIHBhZGRpbmc6IDhweDsKfQoKLmZpZ3VyZSB7CiAgZGlzcGxheTogaW5oZXJpdDsKfQoKLmNpdGF0aW9uIHsKICBjb2xvcjogIzAwOTY4ODsKfQoKLmNzbC1lbnRyeSB7CiAgbWFyZ2luLWJvdHRvbTogMC41ZW07Cn0KYGBgCgojIE92ZXJ2aWV3Cgo8ZGl2IGNsYXNzPSJwYW5lbCBwYW5lbC1kZWZhdWx0IHBhZGRlZC1wYW5lbCI+CkluIFtAdGFuZzIwMjRzaW1wbGlmaWVkXShodHRwczovL2pvdXJuYWxzLnNhZ2VwdWIuY29tL2RvaS8xMC4xMTc3LzE4NzU4NTkyMjQxMzA4NzU1KSwgd2UgZGV2ZWxvcGVkIHRoZSBzaW1wbGlmaWVkIE15UHJvc3RhdGVTY29yZTIuMCAoc01QUzIpLCBhIDctZ2VuZSB1cmluZSB0ZXN0IHdoaWNoIGFjaGlldmVzIHNpbWlsYXIgc3RhdGUtb2YtdGhlLWFydCBkaWFnbm9zdGljIGFjY3VyYWN5IGZvciBwcmVkaWN0aW5nIGhpZ2gtZ3JhZGUgcHJvc3RhdGUgY2FuY2VyIGFzIHRoZSBvcmlnaW5hbCAxOC1nZW5lIE15UHJvc3RhdGVTY29yZTIuMCAoTVBTMikgW0B0b3NvaWFuMjAyNGRldmVsb3BtZW50XS4KVGhpcyBzaW1wbGlmaWVkIGJpb21hcmtlciB0ZXN0IHByb3ZpZGVzIGEgbW9yZSBjb3N0LWVmZmVjdGl2ZSBhbHRlcm5hdGl2ZSB0byB0aGUgb3JpZ2luYWwgTVBTMiB0ZXN0IGFuZCBncmVhdGx5IGluY3JlYXNlcyBpdHMgYWNjZXNzaWJpbGl0eSBmb3Igcm91dGluZSBjbGluaWNhbCBjYXJlLiAKCkluIHRoaXMgUENTIGRvY3VtZW50YXRpb24gW0B5dTIwMjB2ZXJpZGljYWxdLCB3ZSBleHBhbmQgdXBvbiB0aGUgc01QUzIgbW9kZWwgZGV2ZWxvcG1lbnQgcGlwZWxpbmUsIHRyYW5zcGFyZW50bHkgZG9jdW1lbnRpbmcgYW5kIGp1c3RpZnlpbmcgaHVtYW4ganVkZ21lbnQgY2FsbHMgKGluY2x1ZGluZyBkYXRhIHByZXByb2Nlc3NpbmcgYW5kIG1vZGVsaW5nIGRlY2lzaW9ucykgd2hlbiBwb3NzaWJsZS4gCldlIGFsc28gcHJvdmlkZSBhZGRpdGlvbmFsIHZpc3VhbGl6YXRpb25zIGFuZCBzdGFiaWxpdHkgYW5hbHlzZXMgdG8gZnVydGhlciBzdXBwb3J0IHRoZSByb2J1c3RuZXNzIGFuZCBnZW5lcmFsaXphYmlsaXR5IG9mIHRoZSBzTVBTMiB0ZXN0Lgo8L2Rpdj4KCiMgRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcyB7LnRhYnNldCAudGFic2V0LXZtb2Rlcm59Cgo8ZGl2IGNsYXNzPSJwYW5lbCBwYW5lbC1kZWZhdWx0IHBhZGRlZC1wYW5lbCI+CkluIHRoaXMgc2VjdGlvbiwgd2UgcHJvdmlkZSBhIGJyaWVmIGV4cGxvcmF0aW9uIG9mIHRoZSBEZXZlbG9wbWVudCBDb2hvcnQgZGF0YSwgd2hpY2ggd2FzIHVzZWQgdG8gZGV2ZWxvcCB0aGUgc2ltcGxpZmllZCBNeVByb3N0YXRlU2NvcmUyLjAgKHNNUFMyKSB0ZXN0LiBUaGlzIERldmVsb3BtZW50IENvaG9ydCBjb25zaXN0cyBvZiA3NjEgc2FtcGxlcyBhbmQgd2FzIHVzZWQgdG8gYnVpbGQgdGhlIG9yaWdpbmFsIE1QUzIgbW9kZWxzIFtAdG9zb2lhbjIwMjRkZXZlbG9wbWVudF0uCgpCZWxvdywgd2UgdmlzdWFsaXplIHRoZSAobWFyZ2luYWwpIGRpc3RyaWJ1dGlvbiBvZiBlYWNoIGdlbmUgYW5kIGNsaW5pY2FsIHZhcmlhYmxlLCBncm91cGVkIGJ5IHByb3N0YXRlIGNhbmNlciAoUENhKSBncmFkZS4gU29tZSBpbnRlcmVzdGluZyBvYnNlcnZhdGlvbnM6CgotIFRoZSBleHByZXNzaW9uIG9mIHNvbWUgZ2VuZXMsIHN1Y2ggYXMgKlBDQTMqIGFuZCAqVDI6RVJHKiAodXNlZCBpbiB0aGUgb3JpZ2luYWwgTVBTIHRlc3QgW0B0b21saW5zMjAxMXVyaW5lXSksIHNob3cgY2xlYXIgZGlmZmVyZW5jZXMgYmV0d2VlbiBsb3ctIGFuZCBoaWdoLWdyYWRlIHByb3N0YXRlIGNhbmNlcnMgKEZpZ3VyZSBcQHJlZihmaWc6c3ViY2h1bmstMikpLgotIFdoaWxlIFBTQSwgYnkgaXRzZWxmLCBhcHBlYXJzIHRvIGhhdmUgbGltaXRlZCBkaWFnbm9zdGljIGFjY3VyYWN5IGluIHRoaXMgY29ob3J0LCBwcm9zdGF0ZSB2b2x1bWUgc2hvd3MgZ3JlYXRlciBwb3RlbnRpYWwgZm9yIGRpc3Rpbmd1aXNoaW5nIGJldHdlZW4gbG93LSBhbmQgaGlnaC1ncmFkZSBQQ2EgKEZpZ3VyZSBcQHJlZihmaWc6c3ViY2h1bmstNCkpLgotIFdlIGVtcGhhc2l6ZSB0aGF0IHRoZXNlIGFyZSBtZXJlbHkgb2JzZXJ2YXRpb25zIGJhc2VkIG9uIG1hcmdpbmFsIGFuYWx5c2VzLiBNb3JlIGZvcm1hbCBhbmFseXNlcyB3aWxsIGJlIGNvbmR1Y3RlZCBpbiBzdWJzZXF1ZW50IHNlY3Rpb25zLgoKV2UgYWxzbyBwbG90IGEgY29ycmVsYXRpb24gaGVhdG1hcCAoRmlndXJlIFxAcmVmKGZpZzpzdWJjaHVuay0zKSksIHNob3dpbmcgdGhlIHBhaXJ3aXNlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB0d28gZ2VuZXMnIGV4cHJlc3Npb25zIChhcyBtZWFzdXJlZCB2aWEgdGhlaXIgQ3QgdmFsdWVzKS4gVGhpcyBjb3JyZWxhdGlvbiBoZWF0bWFwIHNob3dzIHRoYXQgdGhlcmUgYXJlIGluZGVlZCBzdHJvbmcgcG9zaXRpdmUgY29ycmVsYXRpb25zIGJldHdlZW4gZ3JvdXBzIG9mIGdlbmVzLCB3aGljaCBjYW4gY29tcGxpY2F0ZSB0aGUgaW50ZXJwcmV0YXRpb24gYW5kIGFmZmVjdCB0aGUgc3RhYmlsaXR5IG9mIGZlYXR1cmUgaW1wb3J0YW5jZXMuCjwvZGl2PgoKYGBge3IgcmVzdWx0cyA9ICJhc2lzIn0KZGF0YSA8LSBkYXRhLnRhYmxlOjpmcmVhZCgKICBmaWxlLnBhdGgoREFUQV9QQVRILCAiZGF0YV9vcmlnaW5hbC5jc3YiKQopIHw+IAogIHRpYmJsZTo6YXNfdGliYmxlKCkgfD4gCiAgdGliYmxlOjpjb2x1bW5fdG9fcm93bmFtZXMoIlYxIikgfD4gCiAgZHBseXI6Om11dGF0ZSgKICAgIGdyb3VwaW5nID0gc3RyaW5ncjo6c3RyX3RvX3RpdGxlKGdyb3VwaW5nKQogICkKY2xpbl92YXJzIDwtIGMoCiAgIkFnZSIgPSAiYWdlIiwKICAiQWZyaWNhbi1BbWVyaWNhbiIgPSAiYWEiLAogICJGYW1pbHkgSGlzdG9yeSBvZiBQQ2EiID0gImZoeCIsCiAgIkFibm9ybWFsIERSRSIgPSAiZHJlX2FibmwiLAogICJQcmlvciBOZWdhdGl2ZSBCaW9wc3kiID0gImJ4X3ByaW9yX25lZyIsCiAgIlBTQSIgPSAicHNhIiwKICAiUHJvc3RhdGUgVm9sdW1lIiA9ICJwcm9zdGF0ZV92b2x1bWUiCikKeSA8LSBkYXRhJGdyb3VwaW5nCgpjYXQoIlxuXG4jIyBQcmltYXJ5IE91dGNvbWUgey51bm51bWJlcmVkfVxuXG4iKQp0YWIgPC0gZGF0YSB8PiAKICBkcGx5cjo6Z3JvdXBfYnkoZ3JvdXBpbmcpIHw+CiAgZHBseXI6OnN1bW1hcmlzZSgKICAgIEZyZXF1ZW5jeSA9IGRwbHlyOjpuKCkKICApIHw+IAogIGRwbHlyOjpyZW5hbWUoCiAgICAiUENhIEdyYWRlIiA9IGdyb3VwaW5nCiAgKSB8PiAKICB2dGhlbWVzOjpwcmV0dHlfRFQoCiAgICByb3duYW1lcyA9IEZBTFNFLAogICAgb3B0aW9ucyA9IGxpc3QoZG9tID0gInQiLCBvcmRlcmluZyA9IEZBTFNFKQogICkKdnRoZW1lczo6c3ViY2h1bmtpZnkoCiAgdGFiLCBpID0gc3ViY2h1bmtfaWR4LCBhZGRfY2xhc3MgPSBwYW5lbF9jbGFzcywKICBjYXB0aW9uID0gIidOdW1iZXIgb2YgaGlnaC1ncmFkZSBhbmQgbG93LWdyYWRlIHByb3N0YXRlIGNhbmNlciAoUENhKSBwYXRpZW50cyBpbiBEZXZlbG9wbWVudCBDb2hvcnQuJyIKKQpzdWJjaHVua19pZHggPC0gc3ViY2h1bmtfaWR4ICsgMQoKY2F0KCJcblxuIyMgR2VuZSBFeHByZXNzaW9uIERhdGEgey51bm51bWJlcmVkfVxuXG4iKQpnZW5lX2RhdGEgPC0gZGF0YSB8PiAKICBkcGx5cjo6c2VsZWN0KAogICAgLXRpZHlzZWxlY3Q6OmFsbF9vZihjbGluX3ZhcnMpCiAgKQpwbHQgPC0gZ2VuZV9kYXRhIHw+IAogIHRpZHlyOjpwaXZvdF9sb25nZXIoCiAgICBjb2xzID0gLWdyb3VwaW5nLAogICAgbmFtZXNfdG8gPSAiR2VuZSIsIAogICAgdmFsdWVzX3RvID0gIkN0IFZhbHVlIgogICkgfD4gCiAgdmRvY3M6OnBsb3RfZGVuc2l0eSgKICAgIHhfc3RyID0gIkN0IFZhbHVlIiwgZmlsbF9zdHIgPSAiZ3JvdXBpbmciLCAKICAgIHRoZW1lX29wdGlvbnMgPSBsaXN0KHNpemVfcHJlc2V0ID0gIm1lZGl1bSIpCiAgKSArCiAgZ2dwbG90Mjo6ZmFjZXRfd3JhcCh+IEdlbmUsIHNjYWxlcyA9ICJmcmVlIikgKwogIGdncGxvdDI6OmxhYnMoZmlsbCA9ICJQQ2EgR3JhZGUiKQp2dGhlbWVzOjpzdWJjaHVua2lmeSgKICBwbHQsIGkgPSBzdWJjaHVua19pZHgsCiAgZmlnX2hlaWdodCA9IDE1LCBmaWdfd2lkdGggPSAxOCwgCiAgYWRkX2NsYXNzID0gcGFuZWxfY2xhc3MsCiAgY2FwdGlvbiA9ICInRGlzdHJpYnV0aW9uIG9mIEN0IHZhbHVlcyBpbiBEZXZlbG9wbWVudCBDb2hvcnQgZm9yIGVhY2ggZ2VuZSBieSBwcm9zdGF0ZSBjYW5jZXIgKFBDYSkgZ3JhZGUuJyIKKQpzdWJjaHVua19pZHggPC0gc3ViY2h1bmtfaWR4ICsgMQoKcGx0IDwtIGdlbmVfZGF0YSB8PiAKICBkcGx5cjo6c2VsZWN0KC1ncm91cGluZykgfD4gCiAgdmRvY3M6OnBsb3RfY29yX2hlYXRtYXAoCiAgICB4X3RleHRfYW5nbGUgPSBUUlVFLCBzaXplX3ByZXNldCA9ICJtZWRpdW0iCiAgKSArCiAgZ2dwbG90Mjo6bGFicygKICAgIHggPSAiR2VuZSIsIHkgPSAiR2VuZSIsIGZpbGwgPSAiUGVhcnNvblxuQ29ycmVsYXRpb24iCiAgKQp2dGhlbWVzOjpzdWJjaHVua2lmeSgKICBwbG90bHk6OmdncGxvdGx5KHBsdCksIGkgPSBzdWJjaHVua19pZHgsCiAgZmlnX2hlaWdodCA9IDksIGZpZ193aWR0aCA9IGZpZ193aWR0aCwgCiAgYWRkX2NsYXNzID0gcGFkZGVkX3BhbmVsX2NsYXNzLCBvdGhlcl9hcmdzID0gIm91dC53aWR0aD0nMTAwJSciLAogIGNhcHRpb24gPSAiJ0NvcnJlbGF0aW9uIGhlYXRtYXAgb2YgZ2VuZSBleHByZXNzaW9uIChDdCB2YWx1ZXMpIGluIERldmVsb3BtZW50IENvaG9ydCBkYXRhLiBHZW5lcyBoYXZlIGJlZW4gY2x1c3RlcmVkIHVzaW5nIGhpZXJhcmNoaWNhbCBjbHVzdGVyaW5nLiciCikKc3ViY2h1bmtfaWR4IDwtIHN1YmNodW5rX2lkeCArIDEKCmNhdCgiXG5cbiMjIENsaW5pY2FsIFZhcmlhYmxlcyB7LnVubnVtYmVyZWR9XG5cbiIpCmNsaW5fZGF0YSA8LSBkYXRhIHw+IAogIGRwbHlyOjpzZWxlY3QoCiAgICB0aWR5c2VsZWN0OjphbGxfb2YoY2xpbl92YXJzKSwgZ3JvdXBpbmcKICApCmNvbnRpbnVvdXNfY2xpbl92YXJzIDwtIGMoCiAgIkFnZSIsCiAgIlBTQSIsCiAgIlByb3N0YXRlIFZvbHVtZSIKKQpkaXNjcmV0ZV9jbGluX3ZhcnMgPC0gYygKICAiQWZyaWNhbi1BbWVyaWNhbiIsIAogICJGYW1pbHkgSGlzdG9yeSBvZiBQQ2EiLAogICJBYm5vcm1hbCBEUkUiLCAKICAiUHJpb3IgTmVnYXRpdmUgQmlvcHN5IgopCnBsdF9scyA8LSBsaXN0KCkKZm9yICh2YXJfbmFtZSBpbiBkaXNjcmV0ZV9jbGluX3ZhcnMpIHsKICBwbHRfbHNbW3Zhcl9uYW1lXV0gPC0gY2xpbl9kYXRhIHw+IAogICAgZHBseXI6Om11dGF0ZSgKICAgICAgZHBseXI6OmFjcm9zcygKICAgICAgICB0aWR5c2VsZWN0OjphbGxfb2YodmFyX25hbWUpLCAKICAgICAgICB+IGFzLmZhY3RvcigueCkKICAgICAgKQogICAgKSB8PiAKICAgIHZkb2NzOjpwbG90X2JhcigKICAgICAgeF9zdHIgPSB2YXJfbmFtZSwgZmlsbF9zdHIgPSAiZ3JvdXBpbmciLAogICAgICB0aGVtZV9vcHRpb25zID0gbGlzdChzaXplX3ByZXNldCA9ICJtZWRpdW0iKQogICAgKSArCiAgICBnZ3Bsb3QyOjpsYWJzKAogICAgICBmaWxsID0gIlBDYSBHcmFkZSIKICAgICkgKwogICAgZ2dwbG90Mjo6Z3VpZGVzKGZpbGwgPSAibm9uZSIpCn0KZm9yICh2YXJfbmFtZSBpbiBjb250aW51b3VzX2NsaW5fdmFycykgewogIHBsdF9sc1tbdmFyX25hbWVdXSA8LSBjbGluX2RhdGEgfD4gCiAgICB2ZG9jczo6cGxvdF9kZW5zaXR5KAogICAgICB4X3N0ciA9IHZhcl9uYW1lLCBmaWxsX3N0ciA9ICJncm91cGluZyIsIAogICAgICB0aGVtZV9vcHRpb25zID0gbGlzdChzaXplX3ByZXNldCA9ICJtZWRpdW0iKQogICAgKSArCiAgICBnZ3Bsb3QyOjpsYWJzKAogICAgICBmaWxsID0gIlBDYSBHcmFkZSIKICAgICkKfQpwbHQgPC0gcGF0Y2h3b3JrOjp3cmFwX3Bsb3RzKHBsdF9scywgZ3VpZGVzID0gImNvbGxlY3QiLCBucm93ID0gMikKdnRoZW1lczo6c3ViY2h1bmtpZnkoCiAgcGx0LCBpID0gc3ViY2h1bmtfaWR4LAogIGZpZ19oZWlnaHQgPSA4LCBmaWdfd2lkdGggPSAxNCwgCiAgYWRkX2NsYXNzID0gcGFuZWxfY2xhc3MsCiAgY2FwdGlvbiA9ICInRGlzdHJpYnV0aW9uIG9mIGNsaW5pY2FsIGZlYXR1cmVzIGluIERldmVsb3BtZW50IENvaG9ydCBieSBwcm9zdGF0ZSBjYW5jZXIgKFBDYSkgZ3JhZGUuJyIKKQpzdWJjaHVua19pZHggPC0gc3ViY2h1bmtfaWR4ICsgMQpgYGAKCiMgRGF0YSBQcmVwcm9jZXNzaW5nIENob2ljZXMgey50YWJzZXQgLnRhYnNldC12bW9kZXJufQoKPGRpdiBjbGFzcz0icGFuZWwgcGFuZWwtZGVmYXVsdCBwYWRkZWQtcGFuZWwiPgpBcyBkaXNjdXNzZWQgaW4gW0B0YW5nMjAyNHNpbXBsaWZpZWRdKGh0dHBzOi8vam91cm5hbHMuc2FnZXB1Yi5jb20vZG9pLzEwLjExNzcvMTg3NTg1OTIyNDEzMDg3NTUpLCBnZW5lIGV4cHJlc3Npb24gaW4gZWFjaCB1cmluZSBzYW1wbGUgd2FzIG1lYXN1cmVkIHZpYSB0aGUgY3ljbGUgdGhyZXNob2xkIChDdCkgdXNpbmcgcVBDUiBwcm9maWxpbmcgYWNyb3NzIDU0IGdlbmVzLiAKVGhlc2UgNTQgZ2VuZXMgd2VyZSBwcmV2aW91c2x5IG5vbWluYXRlZCBhcyBwb3RlbnRpYWwgYmlvbWFya2VycyBmb3IgcHJvc3RhdGUgY2FuY2VyIChQQ2EpIGRldGVjdGlvbiBpbiB0aGUgTVBTMiBzdHVkeSBbQHRvc29pYW4yMDI0ZGV2ZWxvcG1lbnRdIGFuZCBhcmUgdGh1cyBvZiBpbnRlcmVzdCBoZXJlLiAKSW4gd2hhdCBmb2xsb3dzLCB3ZSByZWNhcCB0aGUgZGF0YSBwcmVwcm9jZXNzaW5nIHByb2NlZHVyZSB1c2VkIGluIHRoaXMgc3R1ZHkgKGFsc28gZGVzY3JpYmVkIGluIFtAdGFuZzIwMjRzaW1wbGlmaWVkXShodHRwczovL2pvdXJuYWxzLnNhZ2VwdWIuY29tL2RvaS8xMC4xMTc3LzE4NzU4NTkyMjQxMzA4NzU1KSkgYW5kIHByb3ZpZGUgYWRkaXRpb25hbCBqdXN0aWZpY2F0aW9uIGZvciBvdXIganVkZ21lbnQgY2FsbHMgd2hlcmV2ZXIgcG9zc2libGUuCgpBcyBhIHN0YXJ0aW5nIHBvaW50LCB3ZSBwcmVwcm9jZXNzZWQgdGhlIGV4cHJlc3Npb24gZGF0YSBhcyBpbiB0aGUgb3JpZ2luYWwgTVBTMiBzdHVkeSBbQHRvc29pYW4yMDI0ZGV2ZWxvcG1lbnRdOgoKMS4gV2Ugc2V0IHRoZSB1cHBlciBDdCB2YWx1ZSBsaW1pdCB0byAzNS4gU3BlY2lmaWNhbGx5LCBDdCB2YWx1ZXMgZ3JlYXRlciB0aGFuIHRoaXMgbGltaXQgd2VyZSBjb25zaWRlcmVkIHVuZGV0ZWN0ZWQgYW5kIHNldCB0byAzNS4gQ3QgdmFsdWVzIGZyb20gT3BlbkFycmF5IHRoYXQgd2VyZSAiVW5kZXRlcm1pbmVkIiBvciAiSW5jb25jbHVzaXZlL05vIEFtcCIgd2VyZSBhbHNvIGNvbnNpZGVyZWQgdG8gYmUgdW5kZXRlY3RlZCBhbmQgc2V0IHRvIHRoZSB1cHBlciBDdCB2YWx1ZSBsaW1pdCBvZiAzNS4gCgogICAgLSBXaGlsZSBpdCBpcyBhcmd1YWJseSBjb21tb24gcHJhY3RpY2UgdG8gc2V0IHRoZSB1cHBlciBDdCB2YWx1ZSBsaW1pdCB0byA0MCwgcHJldmlvdXMgd29yayBoYXMgc2hvd24gdGhhdCBzZXR0aW5nIHRoZSBDdCB2YWx1ZSBsaW1pdCB0byA0MCBjYW4gb2Z0ZW4gaW50cm9kdWNlIHVud2FudGVkIGJpYXNlcyBhbmQgdGhhdCBzZXR0aW5nIHRoaXMgbGltaXQgdG8gMzUgY2FuIGVmZmVjdGl2ZWx5IHJlZHVjZSB0aGlzIGJpYXMgW0BtY2NhbGwyMDE0bm9uXS4KICAKMi4gV2UgY29tcHV0ZWQgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiAoU0QpIGFjcm9zcyAzIHRlY2huaWNhbCByZXBsaWNhdGVzLiBJZiBTRCAkXGdlcSQgMSwgdGhlIHJlcGxpY2F0ZSBmYXJ0aGVzdCBmcm9tIHRoZSBtZWFuIHdhcyByZW1vdmVkOyBvdGhlcndpc2UsIGFsbCAzIHJlcGxpY2F0ZXMgd2VyZSBrZXB0LiBUaGlzIGlzIHRvIGhlbHAgZmlsdGVyIG91dCBwb29yIHF1YWxpdHkgcmVwbGljYXRlcy4KMy4gV2UgY29tcHV0ZWQgdGhlIGF2ZXJhZ2UgQ3QgdmFsdWUgYWNyb3NzIHRoZSByZW1haW5pbmcgdGVjaG5pY2FsIHJlcGxpY2F0ZXMuCjQuIEFsbCBzYW1wbGVzIHdpdGggYW4gYXZlcmFnZSBDdCB2YWx1ZSBvZiB0aGUgcmVmZXJlbmNlIGdlbmUgKktMSzMqIGFib3ZlIHRoZSA5NXRoIHBlcmNlbnRpbGUgd2VyZSByZW1vdmVkLiAKCiAgICAtIE5vdGUgdGhhdCAqS0xLMyogaXMgYSB3ZWxsLWtub3duIHByb3N0YXRlIG1hcmtlci4gSGVuY2UsIGlmIHRoZSB1cmluZSBzYW1wbGUgZG9lcyBub3QgY29udGFpbiBkZXRlY3RhYmxlIGxldmVscyBvZiAqS0xLMyogKGkuZS4sIHRoZSBhdmVyYWdlIEN0IHZhbHVlIGZvciAqS0xLMyogaXMgaGlnaCksIGl0IGlzIHVubGlrZWx5IHRoYXQgdGhlIHNhbXBsZSB3aWxsIGNvbnRhaW4gZGV0ZWN0YWJsZSBsZXZlbHMgb2Ygb3RoZXIgcHJvc3RhdGUgY2FuY2VyIGJpb21hcmtlcnMuIFdlIHRodXMgcGVyZm9ybWVkIHRoaXMgZmlsdGVyaW5nIHN0ZXAgdG8gcmVtb3ZlIHBvb3IgcXVhbGl0eSBzYW1wbGVzLiAKICAKNS4gV2Ugbm9ybWFsaXplZCB0aGUgYXZlcmFnZSBDdCB2YWx1ZXMgZm9yIGVhY2ggdGFyZ2V0IGdlbmUgYnkgKktMSzMqIHVzaW5nIHRoZSBmb3JtdWxhIC1bIGF2ZXJhZ2UgQ3Qgb2YgZ2VuZSAqWCogLSBhdmVyYWdlIEN0IG9mICpLTEszKiBdLiAKNi4gRmluYWxseSwgei1zY29yZSBzY2FsaW5nIHdhcyBhcHBsaWVkIHRvIHRoZSBub3JtYWxpemVkIGF2ZXJhZ2UgQ3QgYmVmb3JlIGRvd25zdHJlYW0gbW9kZWwgZGV2ZWxvcG1lbnQgYW5kIGZlYXR1cmUgc2VsZWN0aW9uLgoKV2UgcmVmZXIgdG8gdGhpcyBkYXRhIHByZXByb2Nlc3NpbmcgcGlwZWxpbmUgYXMgdGhlICoqYmFzZSBwcmVwcm9jZXNzaW5nIHBpcGVsaW5lKiouIEhvd2V2ZXIsIHRoZXJlIGFyZSBzZXZlcmFsIGFsdGVybmF0aXZlLCBidXQgZXF1YWxseS1yZWFzb25hYmxlIHdheXMgdG8gZGVhbCB3aXRoIHVuZGV0ZWN0YWJsZSBDdCB2YWx1ZXMgYW5kIHBvb3IgcXVhbGl0eSBzYW1wbGVzIGluIHRoZSBkYXRhIHByZXByb2Nlc3NpbmcuIFdoaWxlIHdlIGNhbm5vdCBleHBsb3JlIGFsbCBwb3NzaWJsZSBwcmVwcm9jZXNzaW5nIGNob2ljZXMsIHdlIGRvIGV4cGxvcmUgYSBmZXcgYWx0ZXJuYXRpdmVzIGluIHRoaXMgd29yayBpbiBvcmRlciB0byBpbXByb3ZlIHRoZSByb2J1c3RuZXNzIG9mIG91ciBtb2RlbCBhbmQgY29uY2x1c2lvbnMuIE5hbWVseSwgd2UgY29uc2lkZXJlZCB0aGUgZm9sbG93aW5nIGFsdGVybmF0aXZlIHByZXByb2Nlc3NpbmcgcGlwZWxpbmVzOgoKLSAqKkN0IGxpbWl0ID0gNDAgcHJlcHJvY2Vzc2luZyBwaXBlbGluZSoqOiBSYXRoZXIgdGhhbiBzZXR0aW5nIHRoZSB1cHBlciBDdCB2YWx1ZSBsaW1pdCB0byAzNSBmb3IgdW5kZXRlY3RlZCByZXBsaWNhdGVzLCB3ZSBpbnN0ZWFkIGZvbGxvdyBwb3B1bGFyIHByYWN0aWNlIGFuZCBzZXQgdGhlIHVwcGVyIEN0IHZhbHVlIGxpbWl0IHRvIDQwLiBBbGwgb3RoZXIgcHJlcHJvY2Vzc2luZyBzdGVwcyByZW1haW4gdW5jaGFuZ2VkIGZyb20gdGhlIGJhc2UgcHJlcHJvY2Vzc2luZyBwaXBlbGluZS4KLSAqKk5vcm1hbGl6ZWQgQ3QgbGltaXQgPSAtMjEgcHJlcHJvY2Vzc2luZyBwaXBlbGluZSoqOiBJbiB0aGUgYWZvcmVtZW50aW9uZWQgZGF0YSBwcmVwcm9jZXNzaW5nIHBpcGVsaW5lcywgdGhlIEN0IHZhbHVlcyBmb3IgdW5kZXRlY3RlZCByZXBsaWNhdGVzIHdlcmUgc2V0IHByaW9yIHRvIHRoZSBub3JtYWxpemF0aW9uIG9mIHRoZSBDdCB2YWx1ZXMuIFRodXMsIHRoZSBub3JtYWxpemVkIEN0IHZhbHVlIGZvciB1bmRldGVjdGVkIHJlcGxpY2F0ZXMgZGlmZmVycyBiZXR3ZWVuIGdlbmVzLiBGb3IgY29tcGFyaXNvbiwgaW4gdGhpcyBwcmVwcm9jZXNzaW5nIHBpcGVsaW5lLCB3ZSBpbnN0ZWFkIHJlcGxhY2UgdGhlIEN0IHZhbHVlcyBmb3IgYWxsIHVuZGV0ZWN0ZWQgcmVwbGljYXRlcyBhZnRlciBDdCBub3JtYWxpemF0aW9uIHRvIGhhdmUgYSBjb25zdGFudCB2YWx1ZSBvZiAtMjEgKHdoaWNoIHdhcyB0aGUgbG93ZXN0IEN0IHZhbHVlIHBvc3Qtbm9ybWFsaXphdGlvbikuIEFsbCBvdGhlciBwcmVwcm9jZXNzaW5nIHN0ZXBzIHJlbWFpbiB1bmNoYW5nZWQgZnJvbSB0aGUgYmFzZSBwcmVwcm9jZXNzaW5nIHBpcGVsaW5lLgotICoqTm8gc2FtcGxlIGV4Y2x1c2lvbiBwcmVwcm9jZXNzaW5nIHBpcGVsaW5lKio6IFJhdGhlciB0aGFuIGV4Y2x1ZGluZyBhbGwgc2FtcGxlcyB3aXRoIGFuIGF2ZXJhZ2UgQ3QgdmFsdWUgb2YgdGhlIHJlZmVyZW5jZSBnZW5lICpLTEszKiBhYm92ZSB0aGUgOTV0aCBwZXJjZW50aWxlLCB0aGlzIHByZXByb2Nlc3NpbmcgcGlwZWxpbmUgZG9lcyBub3QgZXhjbHVkZSBhbnkgc2FtcGxlcyBiYXNlZCB1cG9uIHRoZWlyIEN0IHZhbHVlIGZvciB0aGUgcmVmZXJlbmNlIGdlbmUgKktMSzMqLiBUaGlzIGlzIHRvIGFzc2VzcyB3aGV0aGVyIG9yIG5vdCB0aGUgZXhjbHVzaW9uIG9mIHNhbXBsZXMgYmFzZWQgdXBvbiB0aGVpciBDdCB2YWx1ZSBmb3IgdGhlIHJlZmVyZW5jZSBnZW5lIEtMSzMgaW1wYWN0cyBkb3duc3RyZWFtIGNvbmNsdXNpb25zLiBBbGwgb3RoZXIgZGF0YSBwcmVwcm9jZXNzaW5nIHN0ZXBzIHJlbWFpbiB1bmNoYW5nZWQgZnJvbSB0aGUgYmFzZSBwcmVwcm9jZXNzaW5nIHBpcGVsaW5lLgoKSW4gYWRkaXRpb24gdG8gdGhlc2UgcHJlcHJvY2Vzc2VkIGdlbmUgZXhwcmVzc2lvbiBkYXRhLCB3ZSBhbHNvIGhhdmUgYWNjZXNzIHRvIHZhcmlvdXMgY2xpbmljYWwgZGF0YSBmb3IgZWFjaCBzYW1wbGUuIFdlIGNob3NlIHRvIGZvY3VzIG9uIHRoZSBmb2xsb3dpbmcgY2xpbmljYWwgdmFyaWFibGVzIGZvciBtb2RlbCBkZXZlbG9wbWVudCwgYXMgdGhleSBhcmUgYm90aCBrbm93biB0byBiZSBhc3NvY2lhdGVkIHdpdGggaGlnaC1ncmFkZSBwcm9zdGF0ZSBjYW5jZXIgYW5kIGdlbmVyYWxseSBhdmFpbGFibGUgaW4gY2xpbmljYWwgcHJhY3RpY2U6IGFnZSwgcmFjZSwgZmFtaWx5IGhpc3Rvcnkgb2YgcHJvc3RhdGUgY2FuY2VyLCBhYm5vcm1hbCBEUkUsIHByaW9yIG5lZ2F0aXZlIGJpb3BzeSwgYW5kIHByb3N0YXRlIHNwZWNpZmljIGFudGlnZW4gKFBTQSkgW0B0aG9tcHNvbjIwMDZhc3Nlc3NpbmddLgo8L2Rpdj4KCiMgTW9kZWxpbmcgQ2hvaWNlcyB7LnRhYnNldCAudGFic2V0LXZtb2Rlcm59Cgo8ZGl2IGNsYXNzPSJwYW5lbCBwYW5lbC1kZWZhdWx0IHBhZGRlZC1wYW5lbCI+CkZvciBlYWNoIHByZXByb2Nlc3NlZCBkYXRhc2V0LCB3ZSB0cmFpbmVkIG1hbnkgZGlmZmVyZW50IHN0YXRpc3RpY2FsL21hY2hpbmUgbGVhcm5pbmcgbW9kZWxzIHRvIHByZWRpY3QgaGlnaC1ncmFkZSBwcm9zdGF0ZSBjYW5jZXIgKFBDYSkuIFNwZWNpZmljYWxseSwgd2UgY29uc2lkZXJlZCB0aGUgZm9sbG93aW5nIG1vZGVsczoKCioqTG9naXN0aWMtYmFzZWQgTW9kZWxzKio6CgotIExvZ2lzdGljIHJlZ3Jlc3Npb24KLSBMb2dpc3RpYyByZWdyZXNzaW9uIHdpdGggJExfMSQgKExBU1NPKSByZWd1bGFyaXphdGlvbgotIExvZ2lzdGljIHJlZ3Jlc3Npb24gd2l0aCAkTF8yJCAocmlkZ2UpIHJlZ3VsYXJpemF0aW9uCi0gTG9naXN0aWMgcmVncmVzc2lvbiB3aXRoIGNvbWJpbmVkICRMXzEkICsgJExfMiQgKGVsYXN0aWMgbmV0KSByZWd1bGFyaXphdGlvbgoKKipUcmVlLWJhc2VkIE1vZGVscyoqOgoKLSBSYW5kb20gZm9yZXN0cyAoUkYpCi0gR3JhZGllbnQgYm9vc3RpbmcgZGVjaXNpb24gdHJlZXMgKEdCRFQpCi0gUnVsZUZpdAotIFJhbmRvbSBmb3Jlc3RzKyAoUkYrKQotIEZhc3QgaW50ZXJwcmV0YWJsZSBncmVlZHktdHJlZSBzdW1zIChGSUdTKQoKV2UgZm9jdXNlZCBvbiB0aGVzZSBsb2dpc3RpYy0gYW5kIHRyZWUtYmFzZWQgbW9kZWxzIGdpdmVuIHRoZSBpbXBvcnRhbmNlIG9mIGludGVycHJldGFiaWxpdHkgYW5kIG91ciBnb2FsIG9mIGlkZW50aWZ5aW5nIGltcG9ydGFudCBnZW5lcyBmb3IgcmVsaWFibGUgYmlvbWFya2VyIGRldmVsb3BtZW50LiAKV2hpbGUgdGhlIGxvZ2lzdGljLWJhc2VkIG1vZGVscyBhcmUgZ2VuZXJhbGx5IHRob3VnaHQgdG8gc2VydmUgYXMgYmFzZWxpbmUgbW9kZWxzLCB0aGUgdHJlZS1iYXNlZCBtb2RlbHMgY2FuIHByb3ZpZGUgZ3JlYXRlciBmbGV4aWJpbGl0eSB0byBjYXB0dXJlIG1vcmUgY29tcGxleCByZWxhdGlvbnNoaXBzIGJldHdlZW4gZ2VuZXMgYW5kIHRoZSBvdXRjb21lIG9mIGludGVyZXN0IHdpdGhvdXQgc2FjcmlmaWNpbmcgaW50ZXJwcmV0YWJpbGl0eS4gCldlIG5vdGUgdGhhdCBvdGhlciBmbGV4aWJsZSBidXQgaW50ZXJwcmV0YWJsZSBtYWNoaW5lIGxlYXJuaW5nIG1vZGVscyBjb3VsZCBhbHNvIGJlIGNvbnNpZGVyZWQgYW5kIG1heSBiZSBvZiBpbnRlcmVzdCBpbiBmdXR1cmUgd29yay4gCkhvd2V2ZXIsIGluIHRoaXMgY3VycmVudCB3b3JrLCB3ZSBjaG9zZSB0byBmaXJzdCBmb2N1cyBvbiB0aGVzZSBsb2dpc3RpYy1iYXNlZCBtb2RlbHMgYW5kIHRyZWUtYmFzZWQgbW9kZWxzIC0tIHRoZSBsYXR0ZXIgb2Ygd2hpY2ggaXMgb2Z0ZW4gdW5pcXVlbHkgc3VpdGVkIGZvciBiaW9sb2dpY2FsIHRhc2tzIHN1Y2ggYXMgdGhpcywgaW4gcGFydCBkdWUgdG8gdGhlIHJlc2VtYmxhbmNlIGJldHdlZW4gdGhlIHRocmVzaG9sZGluZyBiZWhhdmlvciBvZiBkZWNpc2lvbiB0cmVlcyBhbmQgdGhlIG9uLW9mZiBzd2l0Y2gtbGlrZSBiZWhhdmlvciBjb21tb25seSB0aG91Z2h0IHRvIGdvdmVybiBnZW5ldGljIHByb2Nlc3NlcyBbQG5lbHNvbjIwMDhsZWhuaW5nZXJdLgoKV2UgZGV0YWlsZWQgdGhlIGh5cGVycGFyYW1ldGVycyBhbmQgcHl0aG9uIGltcGxlbWVudGF0aW9uIHVzZWQgZm9yIGVhY2ggbW9kZWwgaW4gVGFibGUgMSBpbiBbQHRhbmcyMDI0c2ltcGxpZmllZF0oaHR0cHM6Ly9qb3VybmFscy5zYWdlcHViLmNvbS9kb2kvMTAuMTE3Ny8xODc1ODU5MjI0MTMwODc1NSkuIEh5cGVycGFyYW1ldGVycyB3ZXJlIHR1bmVkIHVzaW5nIDUtZm9sZCBjcm9zcy12YWxpZGF0aW9uLgo8L2Rpdj4KCiMgUHJlZGljdGlvbiBDaGVjayB7LnRhYnNldCAudGFic2V0LXZtb2Rlcm59Cgo8ZGl2IGNsYXNzPSJwYW5lbCBwYW5lbC1kZWZhdWx0IHBhZGRlZC1wYW5lbCI+CkFzIHRoZSBmaXJzdCBzdGVwIGluIHRoZSBzTVBTMiBtb2RlbCBkZXZlbG9wbWVudCBwaXBlbGluZSwgd2UgcGVyZm9ybWVkIGEgcHJlZGljdGlvbiBjaGVjayB0byBmaWx0ZXIgb3V0IG1vZGVscyB3aGljaCBoYXZlIHBvb3IgcHJlZGljdGlvbiBwZXJmb3JtYW5jZSBhbmQgdGh1cyBtYXkgbm90IGFjY3VyYXRlbHkgcmVmbGVjdCByZWFsaXR5IFtAeXUyMDIwdmVyaWRpY2FsXS4gSGVyZSwgZ3VpZGVkIGJ5IHRoZSBQQ1MgZnJhbWV3b3JrLCB3ZSB1c2UgcHJlZGljdGlvbiBwZXJmb3JtYW5jZSBhcyBhIHJlYWxpdHkgY2hlY2sgYW5kIGEgbWluaW11bSByZXF1aXJlbWVudCBmb3IgaW50ZXJwcmV0YWJpbGl0eS4gTW9yZW92ZXIsIHdlIGFzc2VzcyB0aGUgcHJlZGljdGlvbiBwZXJmb3JtYW5jZSwgbm90IG9ubHkgZm9yIGRpZmZlcmVudCBtb2RlbHMgYnV0IGFsc28gZm9yIGRpZmZlcmVudCBkYXRhIHByZXByb2Nlc3NpbmcgcGlwZWxpbmVzLiBFeGFtaW5pbmcgbXVsdGlwbGUgcHJlZGljdGlvbiBtZXRyaWNzIChpLmUuLCBhcmVhIHVuZGVyIHRoZSByZWNlaXZlciBvcGVyYXRpbmcgY2hhcmFjdGVyaXN0aWMgKEFVUk9DKSwgYXJlYSB1bmRlciB0aGUgcHJlY2lzaW9uLXJlY2FsbCBjdXJ2ZSAoQVVQUkMpLCBhbmQgY2xhc3NpZmljYXRpb24gYWNjdXJhY3kpLCB3ZSBmb3VuZCB0aGF0OgoKLSBUaGUgcHJlZGljdGlvbiBwZXJmb3JtYW5jZSB3YXMgcXVpdGUgc3RhYmxlIGFjcm9zcyBkaWZmZXJlbnQgZGF0YSBwcmVwcm9jZXNzaW5nIHBpcGVsaW5lcy4gTm90YWJseSwgdGhlIHZhcmlhdGlvbiBpbiBwcmVkaWN0aW9uIHBlcmZvcm1hbmNlIGFjcm9zcyBkYXRhIHByZXByb2Nlc3NpbmcgcGlwZWxpbmVzIChibHVlIGJhcnBsb3QpIHdhcyBzdWJzdGFudGlhbGx5IHNtYWxsZXIgdGhhbiB0aGUgdmFyaWF0aW9uIGluIHByZWRpY3Rpb24gcGVyZm9ybWFuY2UgYWNyb3NzIG1vZGVscyAocGluayBiYXJwbG90KS4gVGhlc2Ugb2JzZXJ2YXRpb25zIHN1Z2dlc3QgdGhhdCBkb3duc3RyZWFtIGNvbmNsdXNpb25zIGFyZSByb2J1c3QgdG8gdGhlc2UgZGF0YSBwcmVwcm9jZXNzaW5nIGNob2ljZXMuIAotIE9yZGluYXJ5IGxvZ2lzdGljIHJlZ3Jlc3Npb24gYXBwZWFycyB0byBoYXZlIHJlYXNvbmFibGUgcHJlZGljdGlvbiBwZXJmb3JtYW5jZSAob25seSAkXHNpbSAxXCUkIGxvd2VyIHRoYW4gdGhlIGJlc3QtcGVyZm9ybWluZyBtb2RlbCBpbiB0ZXJtcyBvZiBBVVJPQykuIEdpdmVuIGl0cyBzaW1wbGljaXR5LCB3ZSBjaG9zZSB0byB1c2UgbG9naXN0aWMgcmVncmVzc2lvbiBhcyB0aGUgYmFzZWxpbmUgbW9kZWwgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgb3Igbm90IG90aGVyIG1vZGVscyBwYXNzZWQgdGhlIHByZWRpY3Rpb24gY2hlY2suCi0gUnVsZUZpdCwgR0JEVCwgYW5kIEZJR1MsIG9uIGF2ZXJhZ2UsIHBlcmZvcm1lZCB3b3JzZSB0aGFuIGxvZ2lzdGljIHJlZ3Jlc3Npb24gYWNyb3NzIHRoZSBkaWZmZXJlbnQgcHJlZGljdGlvbiBwZXJmb3JtYW5jZSBtZXRyaWNzLCBzdWdnZXN0aW5nIHRoYXQgdGhleSBtYXkgbm90IGJlIGFwcHJvcHJpYXRlIGZpdHMgZm9yIHRoaXMgZGF0YS4gUkYgYWxzbyBwZXJmb3JtZWQgc2xpZ2h0bHkgd29yc2UgdGhhbiBsb2dpc3RpYyByZWdyZXNzaW9uIG9uIGF2ZXJhZ2UuIEhvd2V2ZXIsIHVubGlrZSBSdWxlRml0LCBHQkRULCBhbmQgRklHUywgUkYgeWllbGRlZCBoaWdoZXIgcHJlZGljdGlvbiBwZXJmb3JtYW5jZSAobWVhc3VyZWQgdmlhIEFVUk9DLCBBVVBSQywgYW5kIGNsYXNzaWZpY2F0aW9uIGFjY3VyYWN5KSB0aGFuIGxvZ2lzdGljIHJlZ3Jlc3Npb24gaW4gYXQgbGVhc3Qgb25lIGRhdGEgcHJlcHJvY2Vzc2luZyBwaXBlbGluZS4gV2UgdGh1cyBleGNsdWRlZCBSdWxlRml0LCBHQkRULCBhbmQgRklHUyAoYnV0IG5vdCBSRikgZnJvbSB0aGUgcmVtYWluZGVyIG9mIHRoZSBtb2RlbCBkZXZlbG9wbWVudCBwaXBlbGluZS4KCldlIGRlZmVyIGFkZGl0aW9uYWwgbWV0aG9kb2xvZ2ljYWwgZGV0YWlscyBvbiBob3cgdGhpcyBwcmVkaWN0aW9uIGNoZWNrIHdhcyBjb25kdWN0ZWQgdG8gW0B0YW5nMjAyNHNpbXBsaWZpZWRdKGh0dHBzOi8vam91cm5hbHMuc2FnZXB1Yi5jb20vZG9pLzEwLjExNzcvMTg3NTg1OTIyNDEzMDg3NTUpLgo8L2Rpdj4KCmBgYHtyIGxvYWQtcGNoZWNrLXJlc3VsdHMsIHJlc3VsdHMgPSAiYXNpcyJ9CmN2X2VycnNfbHMgPC0gbGlzdCgpCnZpbXBzX2xzIDwtIGxpc3QoKQpmb3IgKHBpcGVsaW5lX2lkeCBpbiBzZXFfYWxvbmcoUElQRUxJTkVTKSkgewogIHBpcGVsaW5lX25hbWUgPC0gbmFtZXMoUElQRUxJTkVTKVtwaXBlbGluZV9pZHhdCiAgcGlwZWxpbmUgPC0gUElQRUxJTkVTW3BpcGVsaW5lX2lkeF0KICBwaXBlbGluZV9kaXIgPC0gZmlsZS5wYXRoKFJFU1VMVFNfUEFUSCwgcGlwZWxpbmUsICJ0cmFpbl93aXRoX2NsaW5pY2FsIikKICBjdl9lcnJzIDwtIGRhdGEudGFibGU6OmZyZWFkKAogICAgZmlsZS5wYXRoKHBpcGVsaW5lX2RpciwgImN2X2VycnNfc2NhbGVkLmNzdiIpCiAgKSB8PgogICAgdGliYmxlOjphc190aWJibGUoKSB8PgogICAgZHBseXI6Om11dGF0ZSgKICAgICAgbWV0aG9kID0gcmVuYW1lX21ldGhvZHMobWV0aG9kKQogICAgKSB8PgogICAgZHBseXI6OnJlbmFtZV93aXRoKH4gcmVuYW1lX2NvbHMoLngpKQogIGN2X2VycnNfdGliIDwtIGN2X2VycnMgfD4KICAgIGRwbHlyOjptdXRhdGUoCiAgICAgIFBpcGVsaW5lID0gcGlwZWxpbmVfbmFtZQogICAgKQogIGN2X2VycnNfbHMgPC0gYyhjdl9lcnJzX2xzLCBsaXN0KGN2X2VycnNfdGliKSkKICAKICBhZ2dfdmltcHMgPC0gZGF0YS50YWJsZTo6ZnJlYWQoCiAgICBmaWxlLnBhdGgocGlwZWxpbmVfZGlyLCAiYWdnX3ZpbXBzX3NjYWxlZC5jc3YiKQogICkgfD4KICAgIGRwbHlyOjptdXRhdGUoCiAgICAgIG1ldGhvZCA9IHJlbmFtZV9tZXRob2RzKG1ldGhvZCkKICAgICkgfD4KICAgIHRpYmJsZTo6YXNfdGliYmxlKCkgfD4KICAgIGRwbHlyOjpyZW5hbWVfd2l0aCh+IHJlbmFtZV9jb2xzKC54KSkKICBhZ2dfdmltcHNfdGliIDwtIGFnZ192aW1wcyB8PgogICAgZHBseXI6Om11dGF0ZSgKICAgICAgUGlwZWxpbmUgPSBwaXBlbGluZV9uYW1lCiAgICApCiAgdmltcHNfbHMgPC0gYyh2aW1wc19scywgbGlzdChhZ2dfdmltcHNfdGliKSkKfQpgYGAKCmBgYHtyIGN2LWVycnMsIHJlc3VsdHMgPSAiYXNpcyJ9CmFscGhhIDwtIDAuMDUKY3ZfZXJyc19kZiA8LSBkcGx5cjo6YmluZF9yb3dzKGN2X2VycnNfbHMpIHw+IAogIGRwbHlyOjptdXRhdGUoCiAgICBQaXBlbGluZSA9IGZhY3RvcihQaXBlbGluZSwgbGV2ZWxzID0gcmV2KG5hbWVzKFBJUEVMSU5FUykpKQogICkKCmZvciAobWV0cmljIGluIG1ldHJpY3MpIHsKICBjYXQoCiAgICBzcHJpbnRmKAogICAgICAiXG5cbiMjICVzIHsudW5udW1iZXJlZCAudGFic2V0IC50YWJzZXQtcGlsbHMgLnRhYnNldC1zcXVhcmV9XG5cbiIsIAogICAgICBtZXRyaWMKICAgICkKICApCiAgCiAgbWV0aG9kX29yZGVyIDwtIGN2X2VycnNfZGYgfD4KICAgIGRwbHlyOjpncm91cF9ieShNZXRob2QpIHw+CiAgICBkcGx5cjo6c3VtbWFyaXNlKAogICAgICBtZWFuID0gbWVhbiguZGF0YVtbbWV0cmljXV0pCiAgICApIHw+CiAgICBkcGx5cjo6YXJyYW5nZShtZWFuKSB8PgogICAgZHBseXI6OnB1bGwoTWV0aG9kKQogIAogIGN2X2VycnNfc3VtbWFyeSA8LSBjdl9lcnJzX2RmIHw+CiAgICBkcGx5cjo6Z3JvdXBfYnkoUGlwZWxpbmUsIE1ldGhvZCkgfD4KICAgIGRwbHlyOjpzdW1tYXJpc2UoCiAgICAgIG1lYW4gPSBtZWFuKC5kYXRhW1ttZXRyaWNdXSksCiAgICAgIGhpcSA9IHF1YW50aWxlKC5kYXRhW1ttZXRyaWNdXSwgMSAtIGFscGhhIC8gMiksCiAgICAgIGxvcSA9IHF1YW50aWxlKC5kYXRhW1ttZXRyaWNdXSwgYWxwaGEgLyAyKSwKICAgICAgLmdyb3VwcyA9ICJkcm9wIgogICAgKQogIAogIGVycl9wbHQgPC0gY3ZfZXJyc19zdW1tYXJ5IHw+CiAgICBkcGx5cjo6bXV0YXRlKAogICAgICBNZXRob2QgPSBmYWN0b3IoTWV0aG9kLCBsZXZlbHMgPSByZXYobWV0aG9kX29yZGVyKSkKICAgICkgfD4gCiAgICB2ZG9jczo6cGxvdF9wb2ludCgKICAgICAgeF9zdHIgPSAibWVhbiIsIHlfc3RyID0gIlBpcGVsaW5lIiwKICAgICAgdGhlbWVfb3B0aW9ucyA9IGxpc3Qoc2l6ZV9wcmVzZXQgPSAibWVkaXVtIikKICAgICkgKwogICAgZ2dwbG90Mjo6Z2VvbV9lcnJvcmJhcigKICAgICAgZ2dwbG90Mjo6YWVzKHhtaW4gPSBsb3EsIHhtYXggPSBoaXEsIHkgPSBQaXBlbGluZSkKICAgICkgKwogICAgZ2dwbG90Mjo6ZmFjZXRfZ3JpZChNZXRob2QgfiAuKSArCiAgICBnZ3Bsb3QyOjpsYWJzKHggPSBtZXRyaWMsIHkgPSAiRGF0YSBQcmVwcm9jZXNzaW5nIFBpcGVsaW5lIikgKwogICAgZ2dwbG90Mjo6dGhlbWUoCiAgICAgIHN0cmlwLnRleHQueSA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dCgKICAgICAgICBmYWNlID0gImJvbGQiLCBjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSA5CiAgICAgICkKICAgICkKICBwbHRfbHNbW21ldHJpY11dIDwtIGVycl9wbHQKICAKICBjdl9lcnJzX3N1bW1hcnlfYnlfbWV0aG9kIDwtIGN2X2VycnNfc3VtbWFyeSB8PiAKICAgIGRwbHlyOjpncm91cF9ieShNZXRob2QpIHw+IAogICAgZHBseXI6OnN1bW1hcmlzZSgKICAgICAgcmFuZ2UgPSBtYXgobWVhbikgLSBtaW4obWVhbiksCiAgICAgIG1lYW4gPSBtZWFuKG1lYW4pCiAgICApIHw+IAogICAgZHBseXI6Om11dGF0ZSgKICAgICAgbWVhbiA9IG1heChtZWFuKSAtIG1lYW4KICAgICkKICB5X2xpbWl0cyA8LSBjKDAsIG1heChjdl9lcnJzX3N1bW1hcnlfYnlfbWV0aG9kJG1lYW4pKQogIAogIGRwX3JhbmdlX3BsdCA8LSBjdl9lcnJzX3N1bW1hcnlfYnlfbWV0aG9kIHw+IAogICAgZHBseXI6Om11dGF0ZSgKICAgICAgTWV0aG9kID0gZmFjdG9yKE1ldGhvZCwgbGV2ZWxzID0gbWV0aG9kX29yZGVyKQogICAgKSB8PiAKICAgIHZkb2NzOjpwbG90X2JhcigKICAgICAgeF9zdHIgPSAiTWV0aG9kIiwgeV9zdHIgPSAicmFuZ2UiLCBzdGF0ID0gImlkZW50aXR5IiwKICAgICAgdGhlbWVfb3B0aW9ucyA9IGxpc3Qoc2l6ZV9wcmVzZXQgPSAibWVkaXVtIikKICAgICkgKwogICAgZ2dwbG90Mjo6c2NhbGVfeF9kaXNjcmV0ZShleHBhbmQgPSBjKDAsIDApKSArCiAgICBnZ3Bsb3QyOjpzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLCAwKSwgbGltaXRzID0geV9saW1pdHMpICsKICAgIGdncGxvdDI6OmNvb3JkX2ZsaXAoKSArCiAgICBnZ3Bsb3QyOjpsYWJzKAogICAgICB5ID0gc3ByaW50ZigiRGlmZmVyZW5jZSBpbiBNZWFuICVzXG5BY3Jvc3MgUHJlcHJvY2Vzc2luZyBQaXBlbGluZXMiLCBtZXRyaWMpCiAgICApICsKICAgIGdncGxvdDI6OnRoZW1lKAogICAgICBheGlzLnRleHQueSA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChzaXplID0gMTIpCiAgICApCiAgCiAgbWV0aG9kX3JhbmdlX3BsdCA8LSBjdl9lcnJzX3N1bW1hcnlfYnlfbWV0aG9kIHw+IAogICAgZHBseXI6Om11dGF0ZSgKICAgICAgTWV0aG9kID0gZmFjdG9yKE1ldGhvZCwgbGV2ZWxzID0gbWV0aG9kX29yZGVyKQogICAgKSB8PiAKICAgIHZkb2NzOjpwbG90X2JhcigKICAgICAgeF9zdHIgPSAiTWV0aG9kIiwgeV9zdHIgPSAibWVhbiIsIHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gIiNFODk5OEQiLAogICAgICB0aGVtZV9vcHRpb25zID0gbGlzdChzaXplX3ByZXNldCA9ICJtZWRpdW0iKQogICAgKSArCiAgICBnZ3Bsb3QyOjpzY2FsZV94X2Rpc2NyZXRlKGV4cGFuZCA9IGMoMCwgMCkpICsKICAgIGdncGxvdDI6OnNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsIDApLCBsaW1pdHMgPSB5X2xpbWl0cykgKwogICAgZ2dwbG90Mjo6Y29vcmRfZmxpcCgpICsKICAgIGdncGxvdDI6OmxhYnMoCiAgICAgIHkgPSBzcHJpbnRmKCJEaWZmZXJlbmNlIGluIE1lYW4gJXNcbkFjcm9zcyBNZXRob2RzIiwgbWV0cmljKQogICAgKSArCiAgICBnZ3Bsb3QyOjp0aGVtZSgKICAgICAgYXhpcy50aXRsZS55ID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpLAogICAgICBheGlzLnRleHQueSA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKSwKICAgICAgYXhpcy50aWNrcy55ID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpCiAgICApCiAgCiAgcGx0IDwtIHBhdGNod29yazo6d3JhcF9wbG90cygKICAgIGVycl9wbHQsIGRwX3JhbmdlX3BsdCwgbWV0aG9kX3JhbmdlX3BsdCwgd2lkdGhzID0gYygxLCAwLjUsIDAuNSkKICApCiAgdnRoZW1lczo6c3ViY2h1bmtpZnkoCiAgICBwbHQsIGkgPSBzdWJjaHVua19pZHgsCiAgICBjYXB0aW9uID0gc3ByaW50ZigiJyhMZWZ0KSBGb3IgZWFjaCBjaG9pY2Ugb2YgZGF0YSBwcmVwcm9jZXNzaW5nIGFuZCBwcmVkaWN0aW9uIG1vZGVsLCB0aGUgdmFsaWRhdGlvbiAlMSRzLCBhdmVyYWdlZCBhY3Jvc3MgNCBDViBmb2xkcyBhbmQgMTAgcmVwZWF0ZWQgRGV2ZWxvcG1lbnQtVGVzdCBzcGxpdHMsIGlzIHNob3duLiBUaGUgZXJyb3IgYmFycyByZXByZXNlbnQgdGhlIGlubmVyICUyJHMlJSBxdWFudGlsZSByYW5nZSBvZiB0aGUgZGlzdHJpYnV0aW9uIG9mICUxJHNzLiAoTWlkZGxlLCBSaWdodCkgV2UgY29tcGFyZSB0aGUgdmFyaWF0aW9uIGluICUxJHMgYWNyb3NzIGRhdGEgcHJlcHJvY2Vzc2luZyBwaXBlbGluZXMgYW5kIG1ldGhvZHMuIEluIHRoZSBtaWRkbGUgc3VicGxvdCwgd2Ugc2hvdyB0aGUgcmFuZ2Ugb2YgbWVhbiAlMSRzcyBhY3Jvc3MgdGhlIGZvdXIgZGF0YSBwcmVwcm9jZXNzaW5nIHBpcGVsaW5lcyBmb3IgZWFjaCBtZXRob2QuIEluIHRoZSByaWdodCBzdWJwbG90LCB3ZSBzaG93IHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIG1lYW4gJTEkcyBmcm9tIGVhY2ggbWV0aG9kIGFuZCB0aGUgYmVzdCBwZXJmb3JtaW5nIG1ldGhvZCAoaS5lLiwgbG9naXN0aWMgcmVncmVzc2lvbiB3aXRoIHRoZSBlbGFzdGljIG5ldCBwZW5hbHR5KSBhY3Jvc3MgYWxsIGRhdGEgcHJlcHJvY2Vzc2luZyBwaXBlbGluZXMuIFRoZSBkaWZmZXJlbmNlIGluICUxJHNzIGFjcm9zcyBkYXRhIHByZXByb2Nlc3NpbmcgcGlwZWxpbmVzIGlzIHN1YnN0YW50aWFsbHkgc21hbGxlciB0aGFuIHRoYXQgYWNyb3NzIHByZWRpY3Rpb24gbWV0aG9kcywgc3VnZ2VzdGluZyB0aGF0IHRoZSBkZXZlbG9wbWVudCBwaXBlbGluZSBhbmQgZG93bnN0cmVhbSBmaW5kaW5ncyBhcmUgcm9idXN0IHRvIGRhdGEgcHJlcHJvY2Vzc2luZyBjaG9pY2VzLiciLCBtZXRyaWMsICgxIC0gYWxwaGEpICogMTAwKSwKICAgIGZpZ19oZWlnaHQgPSA3LjUsIGZpZ193aWR0aCA9IDE1LCBhZGRfY2xhc3MgPSBwYW5lbF9jbGFzcwogICkKICBzdWJjaHVua19pZHggPC0gc3ViY2h1bmtfaWR4ICsgMQogIAogIGZvciAoaW1nX3R5cGUgaW4gaW1nX3R5cGVzKSB7CiAgICBnZ3Bsb3QyOjpnZ3NhdmUoCiAgICAgIHBsdCwgCiAgICAgIGZpbGVuYW1lID0gZmlsZS5wYXRoKEZJR1VSRVNfUEFUSCwgc3ByaW50ZigiY3ZfZXJyb3JzXyVzLiVzIiwgbWV0cmljLCBpbWdfdHlwZSkpLCAKICAgICAgd2lkdGggPSAxNSwgCiAgICAgIGhlaWdodCA9IDcuNQogICAgKQogIH0KfQpgYGAKCiMgU3RhYmlsaXR5LWRyaXZlbiBHZW5lIFJhbmtpbmcgey50YWJzZXQgLnRhYnNldC12bW9kZXJufQoKPGRpdiBjbGFzcz0icGFuZWwgcGFuZWwtZGVmYXVsdCBwYWRkZWQtcGFuZWwiPgpBZnRlciBmaWx0ZXJpbmcgb3V0IHRoZSBwb29yLXBlcmZvcm1pbmcgcHJlZGljdGlvbiBtb2RlbHMsIHdlIHNvdWdodCBuZXh0IHRvIGlkZW50aWZ5IHRoZSB0b3Btb3N0IGltcG9ydGFudCBnZW5lcywgd2hpY2ggd2VyZSBzdGFibHkgaW1wb3J0YW50IGFjcm9zcyBhbGwgZm91ciBkYXRhIHByZXByb2Nlc3NpbmcgcGlwZWxpbmVzLCBzaXggcHJlZGljdGlvbi1jaGVja2VkIG1vZGVscywgYW5kIHRlbiBEZXZlbG9wbWVudC1UZXN0IHNwbGl0cyAoaS5lLiwgJDQgXHRpbWVzIDYgXHRpbWVzIDEwID0gMjQwJCBjb21iaW5hdGlvbnMpLiBEZXRhaWxzIG9uIGhvdyB3ZSBjb21wdXRlZCB0aGUgZ2VuZSBpbXBvcnRhbmNlcyBmb3IgZWFjaCBtb2RlbCBhcmUgZGlzY3Vzc2VkIGluIFtAdGFuZzIwMjRzaW1wbGlmaWVkXShodHRwczovL2pvdXJuYWxzLnNhZ2VwdWIuY29tL2RvaS8xMC4xMTc3LzE4NzU4NTkyMjQxMzA4NzU1KS4gCgpXZSBpbnN0ZWFkIHVzZSB0aGlzIG9wcG9ydHVuaXR5IHRvIGNvbmR1Y3QgYSBzdGFiaWxpdHkgYW5hbHlzaXMgb2YgdGhlIFBDUy1lbnNlbWJsZWQgZ2VuZSByYW5raW5ncy4gQXMgZGlzY3Vzc2VkIGluIFtAdGFuZzIwMjRzaW1wbGlmaWVkXShodHRwczovL2pvdXJuYWxzLnNhZ2VwdWIuY29tL2RvaS8xMC4xMTc3LzE4NzU4NTkyMjQxMzA4NzU1KSwgdGhlIG9idGFpbmVkIFBDUy1lbnNlbWJsZWQgZ2VuZSByYW5raW5ncyBhcmUgYW4gZW5zZW1ibGUgb2YgZ2VuZSByYW5raW5ncyBhY3Jvc3MgZm91ciBkaWZmZXJlbnQgZGF0YSBwcmVwcm9jZXNzaW5nIHBpcGVsaW5lcyBhbmQgc2l4IHByZWRpY3Rpb24tY2hlY2tlZCBtb2RlbHMgKFJGLCBSRissIGxvZ2lzdGljIGVsYXN0aWMgbmV0LCBsb2dpc3RpYyBMQVNTTywgbG9naXN0aWMgcmlkZ2UsIGFuZCBvcmRpbmFyeSBsb2dpc3RpYyByZWdyZXNzaW9uKS4gV2UgY2hvc2UgdG8gdXNlIHRoZXNlIHNpeCBwcmVkaWN0aW9uIG1vZGVscyBzaW5jZSBlYWNoIHBhc3NlZCB0aGUgcHJlZGljdGlvbiBjaGVjay4gSG93ZXZlciwgaXQgaXMgbmF0dXJhbCB0byB3b25kZXIgd2hldGhlciB0aGUgUENTLWVuc2VtYmxlZCBnZW5lIHJhbmtpbmdzIHdvdWxkIGNoYW5nZSBpZiBhIGRpZmZlcmVudCBzdWJzZXQgb2YgdGhlIHByZWRpY3Rpb24tY2hlY2tlZCBwcmVkaWN0aW9uIG1vZGVscyB3ZXJlIHVzZWQuIEluIHBhcnRpY3VsYXIsIHNpbmNlIHRoZSBvcmlnaW5hbCBzZXQgb2YgcHJlZGljdGlvbiBtb2RlbHMgY29uc2lzdGVkIG9mIGZvdXIgbG9naXN0aWMtYmFzZWQgbW9kZWxzIGFuZCB0d28gdHJlZS1iYXNlZCBtb2RlbHMsIHdlIGludmVzdGlnYXRlZCBob3cgdGhlIFBDUy1lbnNlbWJsZWQgZ2VuZSByYW5raW5ncyB3b3VsZCBjaGFuZ2UgaWYgd2UgdXNlZCBhICJiYWxhbmNlZCIgc2V0IG9mIHByZWRpY3Rpb24gbW9kZWxzLCBjb21wb3NlZCBvZiB0d28gbG9naXN0aWMtYmFzZWQgbW9kZWxzIGFuZCB0d28gdHJlZS1iYXNlZCBtb2RlbHMuIAoKQmVsb3cgaW4gdGhlIGBHZW5lIFJhbmtpbmcgU3VtbWFyeWAgdGFiLCB3ZSBleGFtaW5lZCB0aGUgUENTLWVuc2VtYmxlZCBnZW5lIHJhbmtpbmdzLCBlbnNlbWJsZWQgYWNyb3NzIGFsbCBmb3VyIGRhdGEgcHJlcHJvY2Vzc2luZyBwaXBlbGluZXMgYW5kCgotIGFsbCBzaXggcHJlZGljdGlvbi1jaGVja2VkIG1vZGVscyAoUkYsIFJGKywgbG9naXN0aWMgZWxhc3RpYyBuZXQsIGxvZ2lzdGljIExBU1NPLCBsb2dpc3RpYyByaWRnZSwgYW5kIG9yZGluYXJ5IGxvZ2lzdGljIHJlZ3Jlc3Npb24pCi0gdHdvIGxvZ2lzdGljLWJhc2VkIG1vZGVscyAobG9naXN0aWMgZWxhc3RpYyBuZXQgYW5kIGxvZ2lzdGljIHJpZGdlKSBhbmQgdGhlIHR3byB0cmVlLWJhc2VkIG1vZGVscyAoUkYgYW5kIFJGKykKLSB0d28gbG9naXN0aWMtYmFzZWQgbW9kZWxzIHdpdGggKGxvZ2lzdGljIGVsYXN0aWMgbmV0IGFuZCBsb2dpc3RpYyBMQVNTTykgYW5kIHRoZSB0d28gdHJlZS1iYXNlZCBtb2RlbHMgKFJGIGFuZCBSRispCi0gdHdvIGxvZ2lzdGljLWJhc2VkIG1vZGVscyB3aXRoIChsb2dpc3RpYyBlbGFzdGljIG5ldCBhbmQgbG9naXN0aWMpIGFuZCB0aGUgdHdvIHRyZWUtYmFzZWQgbW9kZWxzIChSRiBhbmQgUkYrKQoKSGVyZSwgd2UgY2hvc2UgdG8gYWx3YXlzIGluY2x1ZGUgbG9naXN0aWMgZWxhc3RpYyBuZXQgaW4gdGhlIFBDUyBlbnNlbWJsZSBhcyBpdCBkZW1vbnN0cmF0ZWQgdGhlIGhpZ2hlc3QgcHJlZGljdGl2ZSBwb3dlciBpbiB0aGUgcHJlZGljdGlvbiBjaGVjayBzdGVwLgoKVGFrZWF3YXlzIGZyb20gdGhpcyBzdGFiaWxpdHkgYW5hbHlzaXMgb2YgdGhlIFBDUy1lbnNlbWJsZWQgZ2VuZSByYW5raW5nczoKCi0gQmVzaWRlcyB0aGUgc2h1ZmZsZWQgcmFua2luZyBvZiAqUENBMyosIHRoZSB0b3AgZ2VuZSByYW5raW5ncyBhcmUgdGhlIHNhbWUgYWNyb3NzIHRoZSBkaWZmZXJlbnQgUENTIGVuc2VtYmxlczoKICAtIE9yZGVyIG9mIHRvcC1yYW5rZWQgZ2VuZXMgd2hlbiBpbmNsdWRpbmcgYWxsIG1ldGhvZHMgb3IgdGhlIGJhbGFuY2VkIGVuc2VtYmxlIHdpdGggbG9naXN0aWMgZWxhc3RpYyBuZXQsIGxvZ2lzdGljLCBSRiwgYW5kIFJGKzogKlQyOkVSRyosICpTQ0hMQVAxKiwgKk9SNTFFMiosICpQQ0FUMTQqLCAqVEZGMyosICpQQ0EzKiwgKkFQT0MxKgogIC0gT3JkZXIgb2YgdG9wLXJhbmtlZCBnZW5lcyB1c2luZyB0aGUgdHdvIGJhbGFuY2VkIG1ldGhvZCBlbnNlbWJsZXMsIGV4Y2x1ZGluZyBsb2dpc3RpYyByZWdyZXNzaW9uOiAqVDI6RVJHKiwgKlNDSExBUDEqLCAqUENBMyosICpPUjUxRTIqLCAqUENBVDE0KiwgKlRGRjMqLCAqQVBPQzEqCi0gV2hlbiBlbnNlbWJsaW5nIGFjcm9zcyBhbGwgc2l4IHByZWRpY3Rpb24tY2hlY2tlZCBtb2RlbHMsICpQQ0EzKiB3YXMgdGhlIDV0aCByYW5rZWQgZ2VuZSBhY2NvcmRpbmcgdG8gaXRzIG1lYW4gcmFuaywgcmFua2VkIGluIHRoZSB0b3AgNSBpbiBhbG1vc3QgNTBcJSBvZiB0aGUgZml0cywgYnV0IGFwcGVhcmVkIHRvIGhhdmUgbWlsZCBpbnN0YWJpbGl0eSAoc2VlbiBieSB0aGUgbW9kZXJhdGUgU0Qgb2YgaXRzIHJhbmtpbmcgZGlzdHJpYnV0aW9uKSAoRmlndXJlIFxAcmVmKGZpZzpzdWJjaHVuay04KSkuIEhvd2V2ZXIsIHdoZW4gZXhjbHVkaW5nIHRoZSBvcmRpbmFyeSBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsICh3aGljaCBwZXJmb3JtZWQgd29yc2UgdGhhbiB0aGUgcmVndWxhcml6ZWQgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbHMgaW4gdGhlIHByZWRpY3Rpb24gY2hlY2sgKEZpZ3VyZSBcQHJlZihmaWc6c3ViY2h1bmstNSkpKSBmcm9tIHRoZSBiYWxhbmNlZCBQQ1MgZW5zZW1ibGVzLCAqUENBMyogYmVjYW1lIHRoZSAzcmQgcmFua2VkIGdlbmUgYWNjb3JkaW5nIHRvIGl0cyBtZWFuIHJhbmssIHJhbmtlZCBpbiB0aGUgdG9wIDUgaW4gb3ZlciA2MFwlIG9mIHRoZSBmaXRzLCBhbmQgZXhoaWJpdGVkIGZhciBncmVhdGVyIHN0YWJpbGl0eSB0aGFuIGJlZm9yZSAoRmlndXJlcyBcQHJlZihmaWc6c3ViY2h1bmstOSktXEByZWYoZmlnOnN1YmNodW5rLTEwKSkuIFRoaXMgYm9vc3QgaW4gcmFua2luZyBhbmQgc3RhYmlsaXR5IHN1cHBvcnRzIHRoZSBjYXNlIGZvciBpbmNsdWRpbmcgKlBDQTMqIGluIHRoZSBmaW5hbCBzTVBTMiBtb2RlbC4KLSBXaGlsZSAqQVBPQzEqIGFwcGVhcnMgdG8gYmUgYSBzdGFibHkgcmFua2VkIHRvcCAxMCBnZW5lIGluIHRoZSBpbml0aWFsIFBDUyBlbnNlbWJsZSB1c2luZyBhbGwgc2l4IHByZWRpY3Rpb24tY2hlY2tlZCBtb2RlbHMsIHdlIGZvdW5kIHRoYXQgKkFQT0MxKiBvbmx5IGFwcGVhcmVkIGluIHRoZSB0b3AgMTAgaW4gYXBwcm94aW1hdGVseSA1MFwlIG9mIHRoZSBmaXRzIHdoZW4gdXNpbmcgdGhlIGJhbGFuY2VkIFBDUyBlbnNlbWJsZXMgKEZpZ3VyZXMgXEByZWYoZmlnOnN1YmNodW5rLTkpLVxAcmVmKGZpZzpzdWJjaHVuay0xMSkpLiBUaGUgdG9wIDYgZ2VuZXMsIGluIGNvbnRyYXN0LCBhcHBlYXJlZCBpbiB0aGUgdG9wIDEwIGluID43MFwlIChhbmQgb2Z0ZW4gPjg1XCUpIG9mIHRoZSBmaXRzIHdoZW4gdXNpbmcgdGhlIGJhbGFuY2VkIFBDUyBlbnNlbWJsZXMuIFRoaXMgY29udHJhc3QgaXMgZnVydGhlciBzZWVuIGJ5IHRoZSBzdGFyayBkcm9wIGluIHRoZSB0b3AgMTAgc3RhYmlsaXR5IHBsb3QgYmV0d2VlbiAqVEZGMyogYW5kICpBUE9DMSosIHBvc3NpYmx5IHN1Z2dlc3RpbmcgdGhhdCAqQVBPQzEqIGlzIG5vdCBhcyBzdGFibHkgaW1wb3J0YW50IGFzIHRoZSBvdGhlciB0b3AgZ2VuZXMgYW5kIHBlcmhhcHMgc2hvdWxkIGJlIGV4Y2x1ZGVkIGZyb20gdGhlIGZpbmFsIHNNUFMyIG1vZGVsLgotIEFjcm9zcyB0aGUgZGlmZmVyZW50IFBDUyBlbnNlbWJsZXMsIHRoZSA3dGgtcmFua2VkIGdlbmUgKCpDQU1LSzIqIGluIHRoZSBvcmlnaW5hbCBQQ1MgZW5zZW1ibGUgYW5kICpFUkcqIGluIHRoZSBiYWxhbmNlZCBQQ1MgZW5zZW1ibGVzKSBhbmQgb253YXJkIGFwcGVhciB0byBoYXZlIHN1YnN0YW50aWFsbHkgbW9yZSB1bnN0YWJsZSBnZW5lIHJhbmtpbmdzIGNvbXBhcmVkIHRvIHRoZSB0b3AgNiBnZW5lcyAoYXMgbWFkZSBldmlkZW50IGluIHRoZSBTRCBSYW5rIHN1YnBsb3RzKS4gRm9yIHRoaXMgcmVhc29uLCB3ZSBjaG9zZSBub3QgdG8gaW5jbHVkZSB0aGVzZSBnZW5lcyBpbiB0aGUgZmluYWwgc01QUzIgbW9kZWwuCi0gT3ZlcmFsbCwgdGhpcyBzdGFiaWxpdHkgYW5hbHlzaXMgcHJvdmlkZWQgY3J1Y2lhbCBpbmZvcm1hdGlvbiB0byBoZWxwIHVzIGRlY2lkZSB3aGljaCBnZW5lcyB0byBpbmNsdWRlIGluIHRoZSBmaW5hbCBzTVBTMiBtb2RlbC4gTW9yZSBzcGVjaWZpY2FsbHksIHVzaW5nIGV2aWRlbmNlIHByb3ZpZGVkIGJ5IHRoaXMgc3RhYmlsaXR5IGFuYWx5c2lzLCB3ZSBkZWNpZGVkIHRvIGluY2x1ZGUgKlQyOkVSRyosICpTQ0hMQVAxKiwgKk9SNTFFMiosICpQQ0FUMTQqLCAqVEZGMyosIGFuZCAqUENBMyogaW4gdGhlIGZpbmFsIHM8c3VwPjc8L3N1cD5NUFMyIG1vZGVsLiBHaXZlbiB0aGUgYm9yZGVybGluZSBzdGF0dXMgb2YgKkFQT0MxKiwgd2UgYWxzbyBkZXZlbG9wZWQgdGhlIHM8c3VwPjg8L3N1cD5NUFMyIG1vZGVsLCB3aGljaCBpbmNsdWRlcyBhbGwgb2YgdGhlIGdlbmVzIGZyb20gczxzdXA+Nzwvc3VwPk1QUzIgYW5kICpBUE9DMSouCgpUbyBzdXBwbGVtZW50IHRoaXMgc3RhYmlsaXR5IGFuYWx5c2lzLCB3ZSBhbHNvIHByb3ZpZGUgYSBtb3JlIGdyYW51bGFyIHZpZXcgb2YgdGhlIGdlbmUgcmFua2luZ3MgcGVyIGRhdGEgcHJlcHJvY2Vzc2luZyBwaXBlbGluZSBhbmQgbW9kZWwgaW4gdGhlIGBHZW5lIFJhbmtpbmcgSGVhdG1hcGAgdGFiLiBUaGVzZSBoZWF0bWFwcyBzaG93Y2FzZSBib3RoIGdlbmVzIHRoYXQgYXJlIHN0YWJseSBpbXBvcnRhbnQgYWNyb3NzIGFsbCBkYXRhIHByZXByb2Nlc3NpbmcgcGlwZWxpbmVzIGFuZCBtZXRob2RzIGFzIHdlbGwgYXMgZ2VuZXMgdGhhdCBhcmUgc3RhYmx5IGltcG9ydGFudCBhY3Jvc3Mgb25seSBhIHN1YnNldCBvZiBkYXRhIHByZXByb2Nlc3NpbmcgcGlwZWxpbmVzIGFuZC9vciBtZXRob2RzLiBJbiBwYXJ0aWN1bGFyLCB0aGVzZSBoZWF0bWFwcyBjb25maXJtIHRoYXQgdGhlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwgZHJpdmVzIG11Y2ggb2YgdGhlIGluc3RhYmlsaXR5IHRoYXQgd2Ugb2JzZXJ2ZWQgcHJldmlvdXNseSBpbiB0aGUgKlBDQTMqIGdlbmUgcmFua2luZ3MuCgo8L2Rpdj4KCmBgYHtyIGZlYXR1cmUtcmFua2luZ3MsIHJlc3VsdHMgPSAiYXNpcyJ9Cm1heF92YXJzIDwtIDE1CnRvcF92YXJzIDwtIGMoIlQyOkVSRyIsICJTQ0hMQVAxIiwgIk9SNTFFMiIsICJURkYzIiwgIlBDQVQxNCIsICJQQ0EzIikKbWlkX3ZhcnMgPC0gYygiQVBPQzEiKQpmYWNldF92YXJzX29yZGVyIDwtIGMoCiAgIk1lYW4gUmFuayIsIAogICJTRCBSYW5rIiwgCiAgIlRvcCA1IFN0YWJpbGl0eSIsIAogICJUb3AgMTAgU3RhYmlsaXR5IiwgCiAgIlRvcCAxNyBTdGFiaWxpdHkiCikKCnZpbXBzX2RmIDwtIGRwbHlyOjpiaW5kX3Jvd3ModmltcHNfbHMpIHw+CiAgZHBseXI6Om11dGF0ZSgKICAgIGBWYXJpYWJsZSBOYW1lYCA9IGRwbHlyOjpjYXNlX3doZW4oCiAgICAgIGBWYXJpYWJsZSBOYW1lYCA9PSAiVDJFUkciIH4gIlQyOkVSRyIsCiAgICAgIFRSVUUgfiBgVmFyaWFibGUgTmFtZWAKICAgICksCiAgICBgVG9wIDE3YCA9IFJhbmsgPD0gMTcsCiAgICBgVG9wIDEwYCA9IFJhbmsgPD0gMTAsCiAgICBgVG9wIDVgID0gUmFuayA8PSA1CiAgKQoKY2F0KCJcblxuIyMgR2VuZSBSYW5raW5nIFN1bW1hcnkgey51bm51bWJlcmVkIC50YWJzZXQgLnRhYnNldC1waWxscyAudGFic2V0LXNxdWFyZX1cblxuIikKCmtlZXBfbWV0aG9kc19scyA8LSBsaXN0KAogICJBbGwgTWV0aG9kcyIgPSB1bmlxdWUodmltcHNfZGYkTWV0aG9kKSwKICAiUkYsIFJGKywgRWxhc3RpYyBOZXQsIFJpZGdlIiA9IGMoCiAgICAiUkYiLCAiUkYrIiwgIkxvZ2lzdGljXG5SaWRnZSIsICJMb2dpc3RpY1xuRWxhc3RpYyBOZXQiCiAgKSwKICAiUkYsIFJGKywgRWxhc3RpYyBOZXQsIExhc3NvIiA9IGMoCiAgICAiUkYiLCAiUkYrIiwgIkxvZ2lzdGljXG5MYXNzbyIsICJMb2dpc3RpY1xuRWxhc3RpYyBOZXQiCiAgKSwKICAiUkYsIFJGKywgRWxhc3RpYyBOZXQsIExvZ2lzdGljIiA9IGMoCiAgICAiUkYiLCAiUkYrIiwgIkxvZ2lzdGljIiwgIkxvZ2lzdGljXG5FbGFzdGljIE5ldCIKICApCikKCnBsdF9scyA8LSBsaXN0KCkKZm9yIChrZWVwX21ldGhvZHNfbmFtZSBpbiBuYW1lcyhrZWVwX21ldGhvZHNfbHMpKSB7CiAgY2F0KHNwcmludGYoIlxuXG4jIyMgQWdncmVnYXRpbmcgJXMgey51bm51bWJlcmVkfVxuXG4iLCBrZWVwX21ldGhvZHNfbmFtZSkpCiAgcGx0X2RmIDwtIHZpbXBzX2RmIHw+CiAgICBkcGx5cjo6ZmlsdGVyKAogICAgICBNZXRob2QgJWluJSAhIWtlZXBfbWV0aG9kc19sc1tba2VlcF9tZXRob2RzX25hbWVdXQogICAgKSB8PgogICAgZHBseXI6Omdyb3VwX2J5KGBWYXJpYWJsZSBOYW1lYCkgfD4KICAgIGRwbHlyOjpzdW1tYXJpc2UoCiAgICAgIGBNZWFuIFJhbmtgID0gbWVhbihSYW5rKSwKICAgICAgYFNEIFJhbmtgID0gc2QoUmFuayksCiAgICAgIGBUb3AgMTcgU3RhYmlsaXR5YCA9IG1lYW4oYFRvcCAxN2ApLAogICAgICBgVG9wIDEwIFN0YWJpbGl0eWAgPSBtZWFuKGBUb3AgMTBgKSwKICAgICAgYFRvcCA1IFN0YWJpbGl0eWAgPSBtZWFuKGBUb3AgNWApLAogICAgICAuZ3JvdXBzID0gImtlZXAiCiAgICApIHw+CiAgICBkcGx5cjo6YXJyYW5nZShgTWVhbiBSYW5rYCkgfD4KICAgIGRwbHlyOjp1bmdyb3VwKCkKICBkdW1teV9kYXRhIDwtIHRpYmJsZTo6dGliYmxlKAogICAgcmFuZ2UgPSByZXAoYygwLCAxKSwgdGltZXMgPSAzKSwKICAgIGBOYW1lYCA9IHJlcCgKICAgICAgYygiVG9wIDUgU3RhYmlsaXR5IiwgIlRvcCAxMCBTdGFiaWxpdHkiLCAiVG9wIDE3IFN0YWJpbGl0eSIpLCAKICAgICAgZWFjaCA9IDIKICAgICkgfD4gCiAgICAgIGZhY3RvcihsZXZlbHMgPSBmYWNldF92YXJzX29yZGVyKQogICkKICAKICBwbHQgPC0gcGx0X2RmIHw+CiAgICBkcGx5cjo6bXV0YXRlKAogICAgICBgVmFyaWFibGUgTmFtZWAgPSBmb3JjYXRzOjpmY3RfaW5vcmRlcihgVmFyaWFibGUgTmFtZWApLAogICAgICBgVmFyaWFibGUgQ29sb3JgID0gZHBseXI6OmNhc2Vfd2hlbigKICAgICAgICBgVmFyaWFibGUgTmFtZWAgJWluJSAhIXRvcF92YXJzIH4gInRvcCIsCiAgICAgICAgYFZhcmlhYmxlIE5hbWVgICVpbiUgISFtaWRfdmFycyB+ICJtaWQiLAogICAgICAgIFRSVUUgfiAibm9uZSIKICAgICAgKQogICAgKSB8PgogICAgdGlkeXI6OnBpdm90X2xvbmdlcigKICAgICAgY29scyA9IC1jKGBWYXJpYWJsZSBOYW1lYCwgYFZhcmlhYmxlIENvbG9yYCksCiAgICAgIG5hbWVzX3RvID0gIk5hbWUiLCB2YWx1ZXNfdG8gPSAiVmFsdWUiCiAgICApIHw+CiAgICBkcGx5cjo6bXV0YXRlKAogICAgICBOYW1lID0gZmFjdG9yKE5hbWUsIGxldmVscyA9IGZhY2V0X3ZhcnNfb3JkZXIpCiAgICApIHw+IAogICAgdmRvY3M6OnBsb3RfYmFyKAogICAgICB4X3N0ciA9ICJWYXJpYWJsZSBOYW1lIiwgeV9zdHIgPSAiVmFsdWUiLCBmaWxsX3N0ciA9ICJWYXJpYWJsZSBDb2xvciIsCiAgICAgIHN0YXQgPSAiaWRlbnRpdHkiLCAKICAgICAgdGhlbWVfb3B0aW9ucyA9IGxpc3QoCiAgICAgICAgc2l6ZV9wcmVzZXQgPSAibGFyZ2UiLAogICAgICAgIHhfdGV4dF9hbmdsZSA9IFRSVUUsIAogICAgICAgIHN0cmlwX2JnX2NvbG9yID0gIndoaXRlIgogICAgICApCiAgICApICsKICAgIGdncGxvdDI6OmZhY2V0X2dyaWQoTmFtZSB+IC4sIHNjYWxlcyA9ICJmcmVlX3kiLCBzd2l0Y2ggPSAieSIpICsKICAgIGdncGxvdDI6Omdlb21fYmxhbmsoCiAgICAgIGdncGxvdDI6OmFlcyh5ID0gcmFuZ2UpLCAKICAgICAgaW5oZXJpdC5hZXMgPSBGQUxTRSwKICAgICAgZGF0YSA9IGR1bW15X2RhdGEKICAgICkgKwogICAgZ2dwbG90Mjo6bGFicyh4ID0gIkdlbmUiLCB5ID0gIiIpICsKICAgIGdncGxvdDI6OnNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNjN2RhZGIiLCAiZ3JheSIsICIjNTY5Mjk3IikpICsKICAgIGdncGxvdDI6Omd1aWRlcyhmaWxsID0gIm5vbmUiKSArCiAgICBnZ3Bsb3QyOjp0aGVtZSgKICAgICAgYXhpcy50ZXh0LnkgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgYXhpcy50ZXh0LnggPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0ID0gMSksCiAgICAgIHN0cmlwLnRleHQueSA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChjb2xvciA9ICJibGFjayIpLAogICAgICBzdHJpcC5wbGFjZW1lbnQgPSAib3V0c2lkZSIKICAgICkKICBwbHRfbHNbW2tlZXBfbWV0aG9kc19uYW1lXV0gPC0gcGx0CiAgdnRoZW1lczo6c3ViY2h1bmtpZnkoCiAgICBwbG90bHk6OmdncGxvdGx5KHBsdCksIGkgPSBzdWJjaHVua19pZHgsCiAgICBmaWdfaGVpZ2h0ID0gMTIsIGZpZ193aWR0aCA9IDE0LCAKICAgIGFkZF9jbGFzcyA9IHBhZGRlZF9wYW5lbF9jbGFzcywgb3RoZXJfYXJncyA9ICJvdXQud2lkdGg9JzEwMCUnIiwKICAgIGNhcHRpb24gPSBzcHJpbnRmKAogICAgICAiJ1N1bW1hcnkgb2YgdGhlIGdlbmUgaW1wb3J0YW5jZSByYW5raW5ncywgYXMgbWVhc3VlcmQgYnkgdGhlaXIgbWVhbiBnZW5lIHJhbmtpbmcgYWNyb3NzIGZvdXIgZGF0YSBwcmVwcm9jZXNzaW5nIHBpcGVsaW5lcyBhbmQgJTEkcyBwcmVkaWN0aW9uLWNoZWNrZWQgbW9kZWxzICglMiRzKSwgdGhlIHZhcmlhYmlsaXR5IG9mIHRoZWlyIGdlbmUgcmFua2luZ3MgYXMgbWVhc3VyZWQgYnkgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiAoU0QpIG9mIHRoaXMgZGlzdHJpYnV0aW9uLCBhbmQgdGhlIHByb3BvcnRpb24gb2YgdGltZXMgdGhhdCB0aGUgZ2VuZSBhcHBlYXJlZCBpbnQgaGUgdG9wIDUsIDEwLCBhbmQgMTcgZ2VuZXMuIFRoZSBzaXggZ2VuZXMgaGlnaGxpZ2h0ZWQgaW4gZGFyayB0ZWFsIHdlcmUgdXNlZCBpbiB0aGUgczxzdXA+Nzwvc3VwPk1QUzIgbW9kZWwuIFRoZSBBUE9DMSBnZW5lLCBoaWdobGlnaHRlZCBpbiBsaWdodCB0ZWFsLCB3YXMgdXNlZCBpbiB0aGUgczxzdXA+ODwvc3VwPk1QUzIgbW9kZWwuJyIsCiAgICAgIGxlbmd0aChrZWVwX21ldGhvZHNfbHNbW2tlZXBfbWV0aG9kc19uYW1lXV0pLAogICAgICBwYXN0ZSgKICAgICAgICBzb3J0KHN0cmluZ3I6OnN0cl9yZXBsYWNlKGtlZXBfbWV0aG9kc19sc1tba2VlcF9tZXRob2RzX25hbWVdXSwgIlxuIiwgIiAiKSksCiAgICAgICAgY29sbGFwc2UgPSAiLCAiCiAgICAgICkKICAgICkKICApCiAgc3ViY2h1bmtfaWR4IDwtIHN1YmNodW5rX2lkeCArIDEKICAKICBwbHQgPC0gcGx0X2RmIHw+CiAgICBkcGx5cjo6c2xpY2VfbWluKGBNZWFuIFJhbmtgLCBuID0gbWF4X3ZhcnMpIHw+IAogICAgZHBseXI6Om11dGF0ZSgKICAgICAgYFZhcmlhYmxlIE5hbWVgID0gZm9yY2F0czo6ZmN0X2lub3JkZXIoYFZhcmlhYmxlIE5hbWVgKSwKICAgICAgYFZhcmlhYmxlIENvbG9yYCA9IGRwbHlyOjpjYXNlX3doZW4oCiAgICAgICAgYFZhcmlhYmxlIE5hbWVgICVpbiUgISF0b3BfdmFycyB+ICJ0b3AiLAogICAgICAgIGBWYXJpYWJsZSBOYW1lYCAlaW4lICEhbWlkX3ZhcnMgfiAibWlkIiwKICAgICAgICBUUlVFIH4gIm5vbmUiCiAgICAgICkKICAgICkgfD4KICAgIHRpZHlyOjpwaXZvdF9sb25nZXIoCiAgICAgIGNvbHMgPSAtYyhgVmFyaWFibGUgTmFtZWAsIGBWYXJpYWJsZSBDb2xvcmApLAogICAgICBuYW1lc190byA9ICJOYW1lIiwgdmFsdWVzX3RvID0gIlZhbHVlIgogICAgKSB8PgogICAgZHBseXI6Om11dGF0ZSgKICAgICAgTmFtZSA9IHN0cmluZ3I6OnN0cl9yZXBsYWNlKE5hbWUsICIgU3RhYmlsaXR5IiwgIlxuU3RhYmlsaXR5IikgfD4KICAgICAgICBmYWN0b3IoCiAgICAgICAgICBsZXZlbHMgPSBzdHJpbmdyOjpzdHJfcmVwbGFjZShmYWNldF92YXJzX29yZGVyLCAiIFN0YWJpbGl0eSIsICJcblN0YWJpbGl0eSIpCiAgICAgICAgKQogICAgKSB8PiAKICAgIHZkb2NzOjpwbG90X2JhcigKICAgICAgeF9zdHIgPSAiVmFyaWFibGUgTmFtZSIsIHlfc3RyID0gIlZhbHVlIiwgZmlsbF9zdHIgPSAiVmFyaWFibGUgQ29sb3IiLAogICAgICBzdGF0ID0gImlkZW50aXR5IiwgCiAgICAgIHRoZW1lX29wdGlvbnMgPSBsaXN0KAogICAgICAgIHNpemVfcHJlc2V0ID0gImxhcmdlIiwKICAgICAgICB4X3RleHRfYW5nbGUgPSBUUlVFLCAKICAgICAgICBzdHJpcF9iZ19jb2xvciA9ICJ3aGl0ZSIKICAgICAgKQogICAgKSArCiAgICBnZ3Bsb3QyOjpmYWNldF9ncmlkKE5hbWUgfiAuLCBzY2FsZXMgPSAiZnJlZV95Iiwgc3dpdGNoID0gInkiKSArCiAgICBnZ3Bsb3QyOjpnZW9tX2JsYW5rKAogICAgICBnZ3Bsb3QyOjphZXMoeSA9IHJhbmdlKSwgCiAgICAgIGluaGVyaXQuYWVzID0gRkFMU0UsCiAgICAgIGRhdGEgPSBkdW1teV9kYXRhIHw+IAogICAgICAgIGRwbHlyOjptdXRhdGUoCiAgICAgICAgICBOYW1lID0gc3RyaW5ncjo6c3RyX3JlcGxhY2UoTmFtZSwgIiBTdGFiaWxpdHkiLCAiXG5TdGFiaWxpdHkiKSB8PgogICAgICAgICAgICBmYWN0b3IoCiAgICAgICAgICAgICAgbGV2ZWxzID0gc3RyaW5ncjo6c3RyX3JlcGxhY2UoZmFjZXRfdmFyc19vcmRlciwgIiBTdGFiaWxpdHkiLCAiXG5TdGFiaWxpdHkiKQogICAgICAgICAgICApCiAgICAgICAgKQogICAgKSArCiAgICBnZ3Bsb3QyOjpsYWJzKHggPSAiR2VuZSIsIHkgPSAiIikgKwogICAgZ2dwbG90Mjo6c2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI2M3ZGFkYiIsICJncmF5IiwgIiM1NjkyOTciKSkgKwogICAgZ2dwbG90Mjo6Z3VpZGVzKGZpbGwgPSAibm9uZSIpICsKICAgIGdncGxvdDI6OnRoZW1lKAogICAgICBheGlzLnRleHQueSA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICBheGlzLnRleHQueCA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSwKICAgICAgc3RyaXAudGV4dC55ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KGNvbG9yID0gImJsYWNrIiksCiAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIgogICAgKQogIGZvciAoaW1nX3R5cGUgaW4gaW1nX3R5cGVzKSB7CiAgICBnZ3Bsb3QyOjpnZ3NhdmUoCiAgICAgIHBsdCwgCiAgICAgIGZpbGVuYW1lID0gZmlsZS5wYXRoKAogICAgICAgIEZJR1VSRVNfUEFUSCwgCiAgICAgICAgc3ByaW50ZigiZmVhdHVyZV9zdGFiaWxpdHlfJXMuJXMiLCBrZWVwX21ldGhvZHNfbmFtZSwgaW1nX3R5cGUpCiAgICAgICksIAogICAgICB3aWR0aCA9IDYsIAogICAgICBoZWlnaHQgPSAxMAogICAgKQogIH0KfQoKY2F0KCJcblxuIyMgR2VuZSBSYW5raW5nIEhlYXRtYXAgey51bm51bWJlcmVkIC50YWJzZXQgLnRhYnNldC1waWxscyAudGFic2V0LXNxdWFyZX1cblxuIikKCnZhcl9vcmRlciA8LSBsZXZlbHMocGx0X2xzW1siQWxsIE1ldGhvZHMiXV0kZGF0YVtbIlZhcmlhYmxlIE5hbWUiXV0pCgpwbHRfZGYgPC0gdmltcHNfZGYgfD4gCiAgZHBseXI6OnNlbGVjdChSZXAsIE1ldGhvZCwgUGlwZWxpbmUsIGBWYXJpYWJsZSBOYW1lYCwgUmFuaykgfD4gCiAgZHBseXI6Omdyb3VwX2J5KE1ldGhvZCwgUGlwZWxpbmUsIGBWYXJpYWJsZSBOYW1lYCkgfD4gCiAgZHBseXI6OnN1bW1hcmlzZSgKICAgIFJhbmsgPSBtZWFuKFJhbmspLAogICAgLmdyb3VwcyA9ICJkcm9wIgogICkKcGx0X2RmX3dpZGUgPC0gcGx0X2RmIHw+IAogIHRpZHlyOjpwaXZvdF93aWRlcigKICAgIGlkX2NvbHMgPSBjKE1ldGhvZCwgUGlwZWxpbmUpLAogICAgbmFtZXNfZnJvbSA9IGBWYXJpYWJsZSBOYW1lYCwgCiAgICB2YWx1ZXNfZnJvbSA9IFJhbmsKICApIHw+IAogIGRwbHlyOjptdXRhdGUoCiAgICBgUGlwZWxpbmUgTmFtZWAgPSBwYXN0ZShNZXRob2QsIFBpcGVsaW5lLCBzZXAgPSAiLCAiKSB8PiAKICAgICAgc3RyaW5ncjo6c3RyX3JlcGxhY2UoIlxuIiwgIiAiKSwKICAgIE1ldGhvZCA9IHN0cmluZ3I6OnN0cl9yZXBsYWNlKE1ldGhvZCwgIlxuIiwgIiAiKQogICkgfD4gCiAgdGliYmxlOjpjb2x1bW5fdG9fcm93bmFtZXMoIlBpcGVsaW5lIE5hbWUiKQpwbHQgPC0gdmRvY3M6OnBsb3RfaGVhdG1hcCgKICBwbHRfZGZfd2lkZVssIHZhcl9vcmRlcl0sIHlfZ3JvdXBzID0gcGx0X2RmX3dpZGUkTWV0aG9kLAogIHNpemVfcHJlc2V0ID0gIm1lZGl1bSIKKSArCiAgdmlyaWRpczo6c2NhbGVfZmlsbF92aXJpZGlzKAogICAgb3B0aW9uID0gIm1hZ21hIiwgZGlyZWN0aW9uID0gLTEsIGJlZ2luID0gMC4yNSwgZW5kID0gMQogICkgKwogIGdncGxvdDI6OmxhYnMoCiAgICB4ID0gIkdlbmUiLCB5ID0gIkRhdGEgUHJlcHJvY2Vzc2luZyBQaXBlbGluZSIsIGZpbGwgPSAiUmFuayIKICApICsKICBnZ3Bsb3QyOjp0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdCA9IDEpCiAgKQp2dGhlbWVzOjpzdWJjaHVua2lmeSgKICBwbG90bHk6OmdncGxvdGx5KHBsdCksIGkgPSBzdWJjaHVua19pZHgsCiAgZmlnX2hlaWdodCA9IDEzLCBmaWdfd2lkdGggPSAxNCwgCiAgYWRkX2NsYXNzID0gcGFkZGVkX3BhbmVsX2NsYXNzLCBvdGhlcl9hcmdzID0gIm91dC53aWR0aD0nMTAwJSciLAogIGNhcHRpb24gPSAiJ0hlYXRtYXAgb2YgdGhlIG1lYW4gZ2VuZSByYW5raW5nIChhdmVyYWdlZCBhY3Jvc3MgMTAgRGV2ZWxvcG1lbnQtVGVzdCBzcGxpdHMpIHBlciBkYXRhIHByZXByb2Nlc3NpbmcgcGlwZWxpbmUgYW5kIG1vZGVsIGNob2ljZS4nIgopCnN1YmNodW5rX2lkeCA8LSBzdWJjaHVua19pZHggKyAxCgpwbHQgPC0gdmRvY3M6OnBsb3RfaGVhdG1hcCgKICBwbHRfZGZfd2lkZVssIHZhcl9vcmRlclsxOjE1XV0sIHlfZ3JvdXBzID0gcGx0X2RmX3dpZGUkTWV0aG9kLCB0ZXh0X3NpemUgPSA0LAogIHNpemVfcHJlc2V0ID0gIm1lZGl1bSIKKSArCiAgdmlyaWRpczo6c2NhbGVfZmlsbF92aXJpZGlzKAogICAgb3B0aW9uID0gIm1hZ21hIiwgZGlyZWN0aW9uID0gLTEsIGJlZ2luID0gMC4yNSwgZW5kID0gMQogICkgKwogIGdncGxvdDI6OmxhYnMoCiAgICB4ID0gIkdlbmUiLCB5ID0gIkRhdGEgUHJlcHJvY2Vzc2luZyBQaXBlbGluZSIsIGZpbGwgPSAiUmFuayIKICApICsKICBnZ3Bsb3QyOjp0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdCA9IDEpCiAgKQpmb3IgKGltZ190eXBlIGluIGltZ190eXBlcykgewogIGdncGxvdDI6Omdnc2F2ZSgKICAgIHBsdCwgCiAgICBmaWxlbmFtZSA9IGZpbGUucGF0aCgKICAgICAgRklHVVJFU19QQVRILCAKICAgICAgc3ByaW50ZigiZmVhdHVyZV9yYW5raW5nX3N1bW1hcnkuJXMiLCBpbWdfdHlwZSkKICAgICksIAogICAgd2lkdGggPSAxMywgCiAgICBoZWlnaHQgPSAxMAogICkKfQoKcGx0X2RmIDwtIHZpbXBzX2RmIHw+IAogIGRwbHlyOjpzZWxlY3QoUmVwLCBNZXRob2QsIFBpcGVsaW5lLCBgVmFyaWFibGUgTmFtZWAsIFJhbmspCnBsdF9kZl93aWRlIDwtIHBsdF9kZiB8PiAKICB0aWR5cjo6cGl2b3Rfd2lkZXIoCiAgICBpZF9jb2xzID0gYyhNZXRob2QsIFBpcGVsaW5lLCBSZXApLAogICAgbmFtZXNfZnJvbSA9IGBWYXJpYWJsZSBOYW1lYCwgCiAgICB2YWx1ZXNfZnJvbSA9IFJhbmsKICApIHw+IAogIGRwbHlyOjptdXRhdGUoCiAgICBgUGlwZWxpbmUgTmFtZWAgPSBwYXN0ZShNZXRob2QsIFBpcGVsaW5lLCBzZXAgPSAiLCAiKSB8PiAKICAgICAgICBzdHJpbmdyOjpzdHJfcmVwbGFjZSgiXG4iLCAiICIpCiAgKQpwbHQgPC0gdmRvY3M6OnBsb3RfaGVhdG1hcCgKICBwbHRfZGZfd2lkZVssIHZhcl9vcmRlcl0sIHlfZ3JvdXBzID0gcGx0X2RmX3dpZGUkYFBpcGVsaW5lIE5hbWVgLCAKICBzaG93X3l0ZXh0ID0gRkFMU0UsIHNpemVfcHJlc2V0ID0gImxhcmdlIiwgc3RyaXBfYmdfY29sb3IgPSAid2hpdGUiCikgKwogIHZpcmlkaXM6OnNjYWxlX2ZpbGxfdmlyaWRpcygKICAgIG9wdGlvbiA9ICJtYWdtYSIsIGRpcmVjdGlvbiA9IC0xLCBiZWdpbiA9IDAuMjUsIGVuZCA9IDEKICApICsKICBnZ3Bsb3QyOjpsYWJzKAogICAgeCA9ICJHZW5lIiwgeSA9ICJSZXBsaWNhdGUiLCBmaWxsID0gIlJhbmsiCiAgKSArCiAgZ2dwbG90Mjo6dGhlbWUoCiAgICBheGlzLnRleHQueCA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSwKICAgIHN0cmlwLnRleHQueSA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChjb2xvciA9ICJibGFjayIsIGFuZ2xlID0gMCkKICApCnZ0aGVtZXM6OnN1YmNodW5raWZ5KAogIHBsdCwgaSA9IHN1YmNodW5rX2lkeCwKICBmaWdfaGVpZ2h0ID0gMTQsIGZpZ193aWR0aCA9IDE4LCAKICBhZGRfY2xhc3MgPSBwYW5lbF9jbGFzcywgCiAgY2FwdGlvbiA9ICInSGVhdG1hcCBvZiB0aGUgZ2VuZSByYW5raW5nIHBlciBkYXRhIHByZXByb2Nlc3NpbmcgcGlwZWxpbmUsIG1vZGVsLCBhbmQgRGV2ZWxvcG1lbnQtVGVzdCBzcGxpdC4gRWFjaCByb3cgY29ycmVzcG9uZHMgdG8gYSBkaWZmZXJlbnQgRGV2ZWxvcG1lbnQtVGVzdCBzcGxpdCBmb3IgdGhlIGRhdGEgcHJlcHJvY2Vzc2luZyBwaXBlbGluZSBhbmQgbW9kZWwgY2hvaWNlIGxhYmVsZWQgb24gdGhlIHJpZ2h0LiciCikKc3ViY2h1bmtfaWR4IDwtIHN1YmNodW5rX2lkeCArIDEKYGBgCgojIFZhbGlkYXRpb24gey50YWJzZXQgLnRhYnNldC12bW9kZXJufQoKPGRpdiBjbGFzcz0icGFuZWwgcGFuZWwtZGVmYXVsdCBwYWRkZWQtcGFuZWwiPgpXZSBuZXh0IGFzc2Vzc2VkIHRoZSBpbXBhY3Qgb2YgdGhlIGNob2ljZSBvZiBnZW5lIHBhbmVsIHNpemUgKGkuZSwuIHRoZSBudW1iZXIgb2YgdG9wLXJhbmtlZCBnZW5lcyB1c2VkIGluIHRoZSBzTVBTMiBtb2RlbCkgYW5kIHRoZSBnZW5lIHJhbmtpbmcgc3RyYXRlZ3kgKGkuZS4sIG1vZGVsLXNwZWNpZmljIHZlcnN1cyBtb2RlbC1lbnNlbWJsZWQgdmVyc3VzIFBDUy1lbnNlbWJsZWQpIG9uIHRoZSBwcmVkaWN0aW9uIGFjY3VyYWN5LCBldmFsdWF0ZWQgb24gdGhlIHRlc3Qgc2V0IChmcm9tIHRoZSBEZXZlbG9wbWVudC1UZXN0IHNwbGl0KS4gVGVzdCBwcmVkaWN0aW9uIGFjY3VyYWNpZXMgYXJlIGF2ZXJhZ2VkIGFjcm9zcyAxMCBkaWZmZXJlbnQgRGV2ZWxvcG1lbnQtVGVzdCBzcGxpdHMuIEluIHRoaXMgc2VjdGlvbiwgd2Ugc3VtbWFyaXplIHRoZXNlIHRlc3QgcHJlZGljdGlvbiByZXN1bHRzIChtZWFzdXJlZCB2aWEgQVVST0MsIEFVUFJDLCBhbmQgY2xhc3NpZmljYXRpb24gYWNjdXJhY3kpIGFjcm9zcyB0aGUgZGlmZmVyZW50IGdlbmUgcGFuZWwgc2l6ZXMsIGdlbmUgcmFua2luZyBzdHJhdGVnaWVzLCBkYXRhIHByZXByb2Nlc3NpbmcgcGlwZWxpbmVzLCBhbmQgbW9kZWwgY2hvaWNlcy4gSW4gZ2VuZXJhbCwgdGhlIHJlc3VsdHMgc3VnZ2VzdCB0aGF0IDYgb3IgNyBnZW5lcyBhcmUgc3VmZmljaWVudCB0byBhY2hpZXZlIGNvbXBldGl0aXZlIHByZWRpY3Rpb24gcGVyZm9ybWFuY2UsIGFuZCB0aGF0IHRoZSBQQ1MtZW5zZW1ibGVkIGdlbmUgcmFua2luZyBzdHJhdGVneSBpcyB0aGUgbW9zdCByb2J1c3QgYWNyb3NzIGRpZmZlcmVudCBkYXRhIHByZXByb2Nlc3NpbmcgcGlwZWxpbmVzIGFuZCBtb2RlbCBjaG9pY2VzLgoKSW4gW0B0YW5nMjAyNHNpbXBsaWZpZWRdKGh0dHBzOi8vam91cm5hbHMuc2FnZXB1Yi5jb20vZG9pLzEwLjExNzcvMTg3NTg1OTIyNDEzMDg3NTUpLCB3ZSBhZGRpdGlvbmFsbHkgY29uZHVjdGVkIGFuZCBkZXRhaWxlZCBhbiBleHRlcm5hbCB2YWxpZGF0aW9uIHN0dWR5LCB3aGljaCBjb25maXJtZWQgdGhlIHN0cm9uZyBwcmVkaWN0aW9uIGFjY3VyYWN5IG9mIHRoZSBzTVBTMiBtb2RlbHMuIEhvd2V2ZXIsIGdpdmVuIHRoZSBibGluZGVkIG5hdHVyZSBvZiB0aGUgZXh0ZXJuYWwgdmFsaWRhdGlvbiBzdHVkeSwgdGhlIGRhdGEgaXMgbm90IGFjY2Vzc2libGUgYnkgdGhlIGNvLWZpcnN0IGF1dGhvcnMgZm9yIHVzZSBpbiB0aGlzIFBDUyBkb2N1bWVudGF0aW9uLiBXZSByZWZlciB0aGUgcmVhZGVyIHRvIHRoZSBvcmlnaW5hbCBwdWJsaWNhdGlvbiBmb3IgZGV0YWlscy4KPC9kaXY+CgpgYGB7ciBsb2FkLXZhbGlkYXRpb24tcmVzdWx0cywgcmVzdWx0cyA9ICJhc2lzIn0KdGVzdF9lcnJzX2xzIDwtIGxpc3QoKQpmb3IgKHRvcGtfbW9kZV9pZHggaW4gc2VxX2Fsb25nKFRPUEtfTU9ERVMpKSB7CiAgdG9wa19tb2RlX25hbWUgPC0gbmFtZXMoVE9QS19NT0RFUylbdG9wa19tb2RlX2lkeF0KICB0b3BrX21vZGUgPC0gVE9QS19NT0RFU1t0b3BrX21vZGVfaWR4XQogIHRlc3RfZXJycyA8LSBkYXRhLnRhYmxlOjpmcmVhZCgKICAgIGZpbGUucGF0aCgKICAgICAgUkVTVUxUU19QQVRILCAKICAgICAgInRyYWluX3dpdGhfY2xpbmljYWwiLCAKICAgICAgc3ByaW50ZigidGVzdF9lcnJvcnNfJXNfc2NhbGVkLmNzdiIsIHRvcGtfbW9kZSkKICAgICkKICApIHw+CiAgICB0aWJibGU6OmFzX3RpYmJsZSgpIHw+CiAgICBkcGx5cjo6bXV0YXRlKAogICAgICBwaXBlbGluZSA9IHJlbmFtZV9waXBlbGluZXMocGlwZWxpbmUpLAogICAgICBtZXRob2QgPSByZW5hbWVfbWV0aG9kcyhtZXRob2QpCiAgICApIHw+CiAgICBkcGx5cjo6ZmlsdGVyKAogICAgICBldmFsX3R5cGUgPT0gImV2YWxfd2l0aF9jbGluaWNhbCIKICAgICkgfD4gCiAgICBkcGx5cjo6cmVuYW1lX3dpdGgofiByZW5hbWVfY29scygueCkpIHw+CiAgICB0aWR5cjo6cGl2b3RfbG9uZ2VyKAogICAgICBjb2xzID0gdGlkeXNlbGVjdDo6YWxsX29mKG1ldHJpY3MpLCAKICAgICAgbmFtZXNfdG8gPSAiTWV0cmljIiwgdmFsdWVzX3RvID0gIlZhbHVlIgogICAgKQogIHRlc3RfZXJyc19zdW1tYXJ5IDwtIHRlc3RfZXJycyB8PgogICAgZHBseXI6Omdyb3VwX2J5KAogICAgICBQaXBlbGluZSwgYCMgVG9wIEZlYXR1cmVzYCwgTWV0aG9kLCBNZXRyaWMKICAgICkgfD4KICAgIGRwbHlyOjpzdW1tYXJpc2UoCiAgICAgIE1lYW4gPSBtZWFuKFZhbHVlKSwKICAgICAgU0QgPSBzZChWYWx1ZSksCiAgICAgIC5ncm91cHMgPSAia2VlcCIKICAgICkKICB0ZXN0X2VycnNfbHNbW3RvcGtfbW9kZV9uYW1lXV0gPC0gdGVzdF9lcnJzX3N1bW1hcnkKfQpgYGAKCmBgYHtyIHRlc3QtZXJycy1zdW1tYXJ5LCByZXN1bHRzID0gImFzaXMifQp0ZXN0X2VycnNfZGYgPC0gZHBseXI6OmJpbmRfcm93cyh0ZXN0X2VycnNfbHMsIC5pZCA9ICJUb3AgSyBNb2RlIikgfD4gCiAgZHBseXI6Om11dGF0ZSgKICAgIGBUb3AgSyBNb2RlYCA9IGZhY3RvcihgVG9wIEsgTW9kZWAsIGxldmVscyA9IG5hbWVzKFRPUEtfTU9ERVMpKSwKICAgIFBpcGVsaW5lID0gZmFjdG9yKFBpcGVsaW5lLCBsZXZlbHMgPSBuYW1lcyhQSVBFTElORVMpKQogICkKZm9yIChtZXRyaWMgaW4gbWV0cmljcykgewogIGNhdCgKICAgIHNwcmludGYoCiAgICAgICJcblxuIyMgJXMgey51bm51bWJlcmVkIC50YWJzZXQgLnRhYnNldC1waWxscyAudGFic2V0LXNxdWFyZX1cblxuIiwgCiAgICAgIG1ldHJpYwogICAgKQogICkKICAKICBwbHRfZGYgPC0gdGVzdF9lcnJzX2RmIHw+IAogICAgZHBseXI6OmZpbHRlcigKICAgICAgTWV0cmljID09ICEhbWV0cmljCiAgICApCiAgcGx0IDwtIHBsdF9kZiB8PgogICAgdmRvY3M6OnBsb3RfbGluZSgKICAgICAgeF9zdHIgPSAiIyBUb3AgRmVhdHVyZXMiLCB5X3N0ciA9ICJNZWFuIiwgY29sb3Jfc3RyID0gIlRvcCBLIE1vZGUiLCAKICAgICAgc2l6ZSA9IDAuNzUsCiAgICAgIHRoZW1lX29wdGlvbnMgPSBsaXN0KAogICAgICAgIHNpemVfcHJlc2V0ID0gIm1lZGl1bSIKICAgICAgKQogICAgKSArCiAgICBnZ3Bsb3QyOjpnZW9tX3ZsaW5lKAogICAgICB4aW50ZXJjZXB0ID0gNiwgbGluZXR5cGUgPSAiZG90dGVkIiwgY29sb3IgPSAiIzQwNDA0MCIKICAgICkgKwogICAgZ2dwbG90Mjo6Z2VvbV92bGluZSgKICAgICAgeGludGVyY2VwdCA9IDcsIGxpbmV0eXBlID0gImxvbmdkYXNoIiwgY29sb3IgPSAiIzQwNDA0MCIKICAgICkgKwogICAgZ2dwbG90Mjo6ZmFjZXRfZ3JpZChNZXRob2QgfiBQaXBlbGluZSwgc2NhbGVzID0gImZyZWUiKSArCiAgICBnZ3Bsb3QyOjpsYWJzKAogICAgICB4ID0gIk51bWJlciBvZiBQcmVkaWN0b3IgR2VuZXMiLAogICAgICB5ID0gc3ByaW50ZigiTWVhbiAlcyIsIG1ldHJpYyksCiAgICAgIGNvbG9yID0gIkdlbmUgUmFua2luZ1xuTW9kZSIsIAogICAgICBmaWxsID0gIkdlbmUgUmFua2luZ1xuTW9kZSIsCiAgICAgIGxpbmV0eXBlID0gIkdlbmUgUmFua2luZ1xuTW9kZSIKICAgICkgKwogICAgZ2dwbG90Mjo6c2NhbGVfY29sb3JfbWFudWFsKAogICAgICB2YWx1ZXMgPSByZXYoYygiYmxhY2siLCAib3JhbmdlIiwgIiM3MUJFQjciKSkKICAgICkgKwogICAgZ2dwbG90Mjo6c2NhbGVfZmlsbF9tYW51YWwoCiAgICAgIHZhbHVlcyA9IHJldihjKCJibGFjayIsICJvcmFuZ2UiLCAiIzcxQkVCNyIpKQogICAgKSArCiAgICBnZ3Bsb3QyOjpndWlkZXMoCiAgICAgIGNvbG9yID0gZ2dwbG90Mjo6Z3VpZGVfbGVnZW5kKHJldmVyc2UgPSBUUlVFKSwKICAgICAgZmlsbCA9IGdncGxvdDI6Omd1aWRlX2xlZ2VuZChyZXZlcnNlID0gVFJVRSkKICAgICkKICB2dGhlbWVzOjpzdWJjaHVua2lmeSgKICAgIHBsdCwgaSA9IHN1YmNodW5rX2lkeCwKICAgIGZpZ19oZWlnaHQgPSAxMiwgZmlnX3dpZHRoID0gMTIsIAogICAgYWRkX2NsYXNzID0gcGFuZWxfY2xhc3MsCiAgICBjYXB0aW9uID0gc3ByaW50ZigKICAgICAgIidNZWFuICUxJHMsIGV2YWx1YXRlZCBvbiB0ZXN0IHNldCwgd2hlbiB0cmFpbmluZyB2YXJpb3VzIG1vZGVscyAocm93cykgdXNpbmcgdmFyaW91cyBjaG9pY2VzIG9mIGdlbmUgcGFuZWwgc2l6ZXMgKHgtYXhpcyksIGRhdGEgcHJlcHJvY2Vzc2luZyBwaXBlbGluZXMgKGNvbHVtbnMpLCBhbmQgZ2VuZSByYW5raW5ncyAoY29sb3IpLiBUaGUgUENTLWVuc2VtYmxlZCBnZW5lIHJhbmtpbmdzIChpbiBibGFjaykgZ2VuZXJhbGx5IHlpZWxkIHRoZSBoaWdoZXN0IHRlc3QgJTEkc3MgY29tcGFyZWQgdG8gb3RoZXIgcHJvY2VkdXJlcyBmb3Igb2J0YWluaW5nIHRoZSBnZW5lIHJhbmtpbmdzLiBNb3Jlb3ZlciwgdXNpbmcgNiBvciA3IHByZWRpY3RvciBnZW5lcyAodmVydGljYWwgZG90dGVkIGFuZCBkYXNoZWQgbGluZXMsIHJlc3BlY3RpdmVseSkgeWllbGRzIHZlcnkgY29tcGV0aXRpdmUgdGVzdCBwcmVkaWN0aW9uIHBlcmZvcm1hbmNlIGFuZCBpcyBvZnRlbiBjb21wYXJhYmxlIHRvIHRoZSBoaWdoIGFjaGlldmVkICUxJHMuJyIsCiAgICAgIG1ldHJpYwogICAgKQogICkKICBzdWJjaHVua19pZHggPC0gc3ViY2h1bmtfaWR4ICsgMQogIAogIGZvciAoaW1nX3R5cGUgaW4gaW1nX3R5cGVzKSB7CiAgICBnZ3Bsb3QyOjpnZ3NhdmUoCiAgICAgIHBsdCwgCiAgICAgIGZpbGVuYW1lID0gZmlsZS5wYXRoKAogICAgICAgIEZJR1VSRVNfUEFUSCwgCiAgICAgICAgc3ByaW50ZigidGVzdF9lcnJzXyVzLiVzIiwgbWV0cmljLCBpbWdfdHlwZSkKICAgICAgKSwgCiAgICAgIHdpZHRoID0gMTMsIAogICAgICBoZWlnaHQgPSAxMgogICAgKQogIH0KfQpgYGAKCiMgRmluYWwgUmVtYXJrcwoKPGRpdiBjbGFzcz0icGFuZWwgcGFuZWwtZGVmYXVsdCBwYWRkZWQtcGFuZWwiPgpJbiB0aGlzIFBDUyBkb2N1bWVudGF0aW9uIFtAeXUyMDIwdmVyaWRpY2FsXSwgd2UgaGF2ZSBzaGVkIGFkZGl0aW9uYWwgbGlnaHQgb24gdGhlIHZhcmlvdXMgZGVjaXNpb25zIHRoYXQgd2VyZSBtYWRlIHRocm91Z2hvdXQgdGhlIGRldmVsb3BtZW50IG9mIHRoZSBzTVBTMiBtb2RlbCBhbmQgaGF2ZSBqdXN0aWZpZWQgbWFueSBvZiB0aGVzZSBjaG9pY2VzIHRvIHRoZSBiZXN0IG9mIG91ciBhYmlsaXR5LiBXaGlsZSB3ZSBhY2tub3dsZWRnZSB0aGF0IG90aGVyIGVxdWFsbHktcmVhc29uYWJsZSBjaG9pY2VzIGNvdWxkIGhhdmUgYmVlbiBtYWRlLCB3ZSBob3BlIHRoYXQgdGhpcyBkb2N1bWVudGF0aW9uIHdpbGwgYmUgYSB1c2VmdWwgcmVzb3VyY2UgZm9yIHJlc2VhcmNoZXJzIGFuZCBjbGluaWNpYW5zIHdobyBhcmUgaW50ZXJlc3RlZCBpbiBidWlsZGluZyB1cG9uIHRoaXMgd29yay4gCjwvZGl2PgoKIyBCaWJsaW9ncmFwaHkgey51bm51bWJlcmVkfQoKPGRpdiBjbGFzcz0icGFuZWwgcGFuZWwtZGVmYXVsdCBwYWRkZWQtcGFuZWwiPgo8ZGl2IGlkPSJyZWZzIj48L2Rpdj4KPC9kaXY+