1 Introduction

The results here accompany the paper “Effective Ways to Build and Evaluate Individual Survival Distributions” by Haider et al. In total, 33 additional datasets were tested to validate the findings given by Table 7 in Section 5 of the paper. For each of (Low-Censoring, Low-Dimensional), (High-Censoring, Low-Dimensional), (Low-Censoring, High-Dimensional), and (High-Censoring, High-Dimensional) we have 16, 12, 4, and 1 additional datasets to check the generalization of the findings. Each following section gives further details about the corresponding datasets used. Here we have defined “High-Censoring” to be \(\geq\) 70%. Additionally, “High-Dimensional” datasets all have at least 274 features.


2 Low-Censoring, Low-Dimensional

All datasets in this category were collected from the TCGA website (details given in the paper). Specifically, here we have 16 datasets corresponding to survival time from different cancer types: Adrenocortical carcinoma (ACC), Bladder Urothelial Carcinoma (BLCA), Cholangiocarcinoma (CHOL), Esophageal carcinoma (ESCA), Head and Neck squamous cell carcinoma (HNSC), Kidney renal clear cell carcinoma (KIRC), Liver hepatocellular carcinoma (LIHC), Lung adenocarcinoma (LUAD), Lung squamous cell carcinoma (LUSC), Ovarian serous cystadenocarcinoma (OV), Pancreatic adenocarcinoma (PAAD), Sarcoma (SARC), Skin Cutaneous Melanoma (SKCM), Stomach adenocarcinoma (STAD), Stomach and Esophageal carcinoma (STES), and Uterine Carcinosarcoma (UCS). Table 1 gives summary statistics for each of the 16 datasets.

Table 1: Summary statistics for the 16 (Low-Censoring, Low-Dimensional) datasets. From top to bottom we have (1) the total number of patients, (2) the % of censored patients, and (3) the total number of features used (after feature selection).
ACC BLCA CHOL ESCA HNSC KIRC LIHC LUAD LUSC OV PAAD SARC SKCM STAD STES UCS
N 92 409 45 185 526 537 376 513 498 576 185 261 460 436 621 57
% Censored 63.04 55.99 51.11 58.38 57.6 67.04 64.89 64.13 56.83 40.45 45.95 62.07 51.96 61.01 60.23 38.6
Number of Features 9 13 5 13 20 14 12 14 12 2 10 5 18 17 18 4

2.1 Calibration

Concerning calibration for the (Low-Censoring, Low-Dimensional) datasets, our findings were that MTLR was superior to other models. The D-Calibration (Table 2) results support this as MTLR is D-Calibrated for all 16 datasets (though AFT and Cox are also D-Calibrated for all datasets). The 1-Calibration results (Table 3) are more discriminative showing MTLR and CoxEN-KP to outperform all other models. Although CoxEN-KP shows to be competitive with MTLR with these datasets, when combined with the results from the paper, MTLR has a general better performance leading us to recommend MTLR when measuring calibration on (Low-Censoring, Low-Dimensional) datasets.

Note we only include the accumulated 1-Calibration results here (the exact \(p\)-values are available upon request.)

Table 2: D-Calibration results for the 16 (Low-Censoring, Low-Dimensional) datasets. The Total column gives the total number of datasets for which each model was D-Calibrated.
ACC BLCA CHOL ESCA HNSC KIRC LIHC LUAD LUSC OV PAAD SARC SKCM STAD STES UCS Total
KM 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 0.998 16
AFT 0.985 0.471 0.456 0.948 0.136 0.934 0.959 0.970 0.947 0.134 0.641 0.939 0.412 0.726 0.826 0.817 16
Cox-KP 0.929 0.984 0.610 0.973 0.745 0.927 0.986 0.999 0.989 0.939 0.635 0.956 0.128 0.969 0.958 0.518 16
CoxEN-KP 0.664 0.995 0.971 1.000 0.935 0.598 0.981 0.999 1.000 0.985 0.413 1.000 0.018 0.967 0.999 0.819 15
RSF-KM 0.982 0.562 0.859 0.661 0.253 0.508 0.312 0.996 0.000 0.000 0.490 0.000 0.661 0.063 0.000 0.607 12
MTLR 0.974 1.000 0.994 0.984 0.583 0.994 0.986 0.997 0.869 0.886 0.702 0.963 0.106 0.991 0.978 0.852 16
Table 3: The 1-Calibration results for the 16 (Low-Censoring, Low-Dimensional) datasets. Each column represents the 10th, 25th, 50th, 75th, and 90th percentiles of event times. Each row represents the total number of datasets for which each model was 1-Calibrated (the maximum being 16).
10th 25th 50th 75th 90th
AFT 10 10 5 5 3
Cox-KP 12 11 6 4 6
CoxEN-KP 16 14 12 7 5
RSF-KM 0 0 0 0 0
MTLR 16 15 11 10 2

2.2 Discrimination

Since discrimination is primarily evaluated with concordance we only present this result and omit the Integrated Brier score and the L1-loss (though these results are available from the authors upon request). Table 4 presents these concordance results, and we see results consistent with the findings of the paper – although other models (here MTLR and CoxEN-KP) generally outperform AFT and Cox-KP, the performance gain is not significant. Further, we again see the poor performance of RSF-KM on these Low-Dimensional models. Due to model simplicity of AFT and Cox-KP we suggest using these models for discrimination on (Low-Censoring, Low-Dimensional) datasets.

Table 4: Concordance results for the 16 (Low-Censoring, Low-Dimensional) datasets. Here we present the mean and standard deviation of the Concordance across the 5 cross-validation folds. Bolded values represent the best (highest Concordance) performing models.
ACC BLCA CHOL ESCA HNSC KIRC LIHC LUAD LUSC OV PAAD SARC SKCM STAD STES UCS
KM 0.5 (0) 0.5 (0) 0.5 (0) 0.5 (0) 0.5 (0) 0.5 (0) 0.5 (0) 0.5 (0) 0.5 (0) 0.5 (0) 0.5 (0) 0.5 (0) 0.5 (0) 0.5 (0) 0.5 (0) 0.5 (0)
AFT 0.793 (0.07) 0.642 (0.032) 0.568 (0.259) 0.582 (0.087) 0.659 (0.02) 0.742 (0.032) 0.621 (0.038) 0.676 (0.021) 0.578 (0.019) 0.601 (0.022) 0.634 (0.052) 0.646 (0.07) 0.749 (0.023) 0.697 (0.039) 0.646 (0.034) 0.683 (0.088)
Cox-KP 0.796 (0.084) 0.648 (0.042) 0.568 (0.259) 0.575 (0.085) 0.662 (0.025) 0.74 (0.033) 0.622 (0.035) 0.675 (0.021) 0.578 (0.02) 0.602 (0.023) 0.635 (0.048) 0.646 (0.071) 0.754 (0.021) 0.697 (0.032) 0.644 (0.032) 0.692 (0.084)
CoxEN-KP 0.749 (0.096) 0.66 (0.045) 0.69 (0.16) 0.539 (0.089) 0.647 (0.029) 0.752 (0.021) 0.592 (0.053) 0.687 (0.027) 0.508 (0.047) 0.6 (0.022) 0.631 (0.056) 0.623 (0.08) 0.757 (0.022) 0.698 (0.033) 0.623 (0.034) 0.697 (0.088)
RSF-KM 0.762 (0.131) 0.589 (0.032) 0.691 (0.073) 0.628 (0.113) 0.641 (0.051) 0.741 (0.021) 0.628 (0.044) 0.642 (0.052) 0.541 (0.034) 0.517 (0.016) 0.619 (0.057) 0.604 (0.065) 0.622 (0.011) 0.634 (0.028) 0.616 (0.052) 0.604 (0.086)
MTLR 0.803 (0.097) 0.661 (0.041) 0.764 (0.132) 0.634 (0.083) 0.676 (0.017) 0.756 (0.007) 0.623 (0.029) 0.694 (0.029) 0.595 (0.009) 0.601 (0.021) 0.618 (0.071) 0.646 (0.073) 0.758 (0.027) 0.709 (0.032) 0.656 (0.031) 0.697 (0.089)

3 High-Censor, Low Dimensional

All datasets in this category were collected from the TCGA website (details given in the paper). Specifically, here we have 12 datasets corresponding to survival time from different cancer types: Cervical squamous cell carcinoma and endocervical adenocarcinoma [CESC], Colon adenocarcinoma [COAD], Colorectal adenocarcinoma (COADREAD), FFPE Pilot Phase II [FPPP], Kidney Chromophobe [KICH], Pan-kidney cohort (KIPAN), Kidney renal papillary cell carcinoma [KIRP], Lower Grade Glinoma (LGG), Prostate adenocarcinoma [PRAD], Thyroid carcinoma [THCA], Uterine Corpus Endometrial Carcinoma [UCEC], and Uveal Melanoma [UVM]. Table 5 gives summary statistics for each of the 12 datasets.

Table 5: Summary statistics for the 12 (High-Censoring, Low-Dimensional) datasets. From top to bottom we have (1) the total number of patients, (2) the % of censored patients, and (3) the total number of features used (after feature selection).
CESC COAD COADREAD FPPP KICH KIPAN KIRP LGG PRAD THCA UCEC UVM
N 307 456 626 38 112 939 290 513 499 503 546 80
% Censored 76.55 77.63 79.39 81.58 89.29 75.19 84.83 75.63 98 96.82 83.33 71.25
Number of Features 15 12 13 3 7 20 12 4 6 14 6 6

3.1 Calibration

For calibration on (High-Censoring, Low-Dimensional) datasets, our findings were that MTLR and CoxEN-KP outperformed other models. The D-Calibration (Table 6) results are inconclusive as nearly all models are D-Calibrated for all datasets (recall D-Calibration is optimistic when data is highly censored). The 1-Calibration results (Table 7) show MTLR and CoxEN-KP to outperform all other models with CoxEN-KP slightly outperforming MTLR. Given MTLR’s better performance on the datasets given in the paper, these results support the finding that MTLR and CoxEN-KP are the best (and generally equivalent) models for calibration on (High-Censoring, Low-Dimensional) datasets.

Table 6: D-Calibration results for the 12 (High-Censoring, Low-Dimensional) datasets. The Total column gives the total number of datasets for which each model was D-Calibrated.
CESC COAD COADREAD FPPP KICH KIPAN KIRP LGG PRAD THCA UCEC UVM Total
KM 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1 1 1.000 1.000 12
AFT 0.999 0.978 1.000 0.899 0.997 0.899 0.957 0.955 1 1 0.966 0.988 12
Cox-KP 0.995 0.980 1.000 0.930 0.996 0.844 0.988 0.938 1 0 0.998 0.969 11
CoxEN-KP 0.979 0.904 0.987 1.000 0.999 0.593 1.000 0.819 1 1 0.998 0.998 12
RSF-KM 0.934 0.800 0.897 0.999 1.000 0.441 0.940 0.556 1 1 0.366 0.940 12
MTLR 0.947 0.696 0.967 0.999 1.000 0.783 0.999 0.993 1 1 0.965 0.994 12
Table 7: The 1-Calibration results for the 12 (High-Censoring, Low-Dimensional) datasets. Each column represents the 10th, 25th, 50th, 75th, and 90th percentiles of event times. Each row represents the total number of datasets for which each model was 1-Calibrated (the maximum being 12).
10th 25th 50th 75th 90th
AFT 4 7 5 2 1
Cox-KP 5 5 6 2 1
CoxEN-KP 8 10 10 5 3
RSF-KM 3 2 1 0 0
MTLR 9 10 6 3 2

3.2 Discrimination

Table 8 presents concordance results for (High-Censoring, Low-Dimensional) datasets and we see results consistent with the findings of the paper – (1) CoxEN-KP and MTLR are superior to AFT and Cox and (2) RSF-KM typically sees noticeably worse performance. This supports our recommendation to use MTLR or CoxEN-KP when evaluating discrimination on (High-Censoring, Low-Dimensional) datasets.

Table 8: Concordance results for the 12 (High-Censoring, Low-Dimensional) datasets. Here we present the mean and standard deviation of the Concordance across the 5 cross-validation folds. Bolded values represent the best (highest Concordance) performing models.
CESC COAD COADREAD FPPP KICH KIPAN KIRP LGG PRAD THCA UCEC UVM
KM 0.5 (0) 0.5 (0) 0.5 (0) 0.5 (0) 0.5 (0) 0.5 (0) 0.5 (0) 0.5 (0) 0.5 (0) 0.5 (0) 0.5 (0) 0.5 (0)
AFT 0.816 (0.015) 0.73 (0.042) 0.731 (0.036) 0.531 (0.386) 0.752 (0.422) 0.782 (0.058) 0.689 (0.169) 0.781 (0.08) 0.778 (0.273) 0.705 (0.285) 0.696 (0.079) 0.736 (0.157)
Cox-KP 0.817 (0.018) 0.731 (0.04) 0.732 (0.037) 0.531 (0.386) 0.836 (0.242) 0.78 (0.06) 0.683 (0.165) 0.781 (0.078) 0.774 (0.277) 0.675 (0.3) 0.695 (0.08) 0.711 (0.134)
CoxEN-KP 0.826 (0.032) 0.741 (0.044) 0.743 (0.038) 0.641 (0.267) 0.958 (0.052) 0.794 (0.051) 0.787 (0.104) 0.779 (0.078) 0.755 (0.282) 0.955 (0.032) 0.694 (0.081) 0.733 (0.145)
RSF-KM 0.829 (0.017) 0.682 (0.041) 0.709 (0.062) 0.539 (0.376) 0.923 (0.073) 0.772 (0.058) 0.801 (0.091) 0.709 (0.066) 0.778 (0.291) 0.950 (0.027) 0.614 (0.042) 0.712 (0.077)
MTLR 0.823 (0.036) 0.746 (0.043) 0.747 (0.037) 0.721 (0.287) 0.952 (0.047) 0.795 (0.05) 0.826 (0.069) 0.781 (0.073) 0.672 (0.4) 0.913 (0.08) 0.693 (0.078) 0.737 (0.218)

4 Low-Censoring, High-Dimensional

Here we examine a number of (Low-Censoring, High-Dimensional) datasets which contain gene-expression data relating the survival of cancer patients – see “A Multi-Task Learning Formulation for Survival Analysis” by Li et al. for details regarding dataset access. Specifically we use (1) the Norway/Stanford breast cancer data (NBSCD) which contains the gene-expression data for 115 female breast cancer patients, (2) the Van de Vijver’s microarray breast cancer data (VDV) which again contains gene-expression data for 78 breast cancer patients, (3) gene-expression data for adult myeloid leukemia (AML) on 116 patients, and (4) gene-expression data for 92 mantle cell lymphoma (MCL) patients. Table 9 gives the summary statistics for each of these 4 datasets.

Table 9: Summary statistics for the 4 (Low-Censoring, High-Dimensional) datasets. From top to bottom we have (1) the total number of patients, (2) the % of censored patients, and (3) the total number of features used (after feature selection).
AML MCL NSBCD VDV
N 116 92 115 78
% Censored 42.24 30.43 66.96 56.41
Number of Features 1616 2176 274 1319

4.1 Calibration

For calibration on (Low-Censoring, High-Dimensional) datasets, our findings were that MTLR, CoxEN-KP, and RSF-KM were all equivalent. The D-Calibration (Table 10) results are show that AFT fails D-Calibration across all datasets (and Cox fails to finish on these datasets). The 1-Calibration results (Table 11) show that MTLR, CoxEN-KP and RSF-KM are roughly equivalent across the different percentiles supporting our initial finding – MTLR, CoxEN-KP, and RSF-KM are equivalent for calibration on (Low-Censoring, High-Dimensional) datasets.

Table 10: D-Calibration results for the 4 (Low-Censoring, High-Dimensional) datasets. The Total column gives the total number of datasets for which each model was D-Calibrated. Note there is no results for Cox as it failed to run for all datasets.
AML MCL NSBCD VDV Total
KM 1.000 1.000 1.000 1.000 4
AFT 0.000 0.000 0.000 0.000 0
CoxEN-KP 0.897 0.228 0.992 0.998 4
RSF-KM 0.759 0.577 0.977 0.000 3
MTLR 0.529 0.391 0.981 0.996 4
Table 11: The 1-Calibration results for the 4 (Low-Censoring, High-Dimensional) datasets. Each column represents the 10th, 25th, 50th, 75th, and 90th percentiles of event times. Each row represents the total number of datasets for which each model was 1-Calibrated (the maximum being 4). Note there are no results for Cox as it failed to run on all datasets.
10th 25th 50th 75th 90th
AFT 0 0 0 0 0
CoxEN-KP 4 4 4 2 1
RSF-KM 4 4 3 3 1
MTLR 2 3 4 4 3

4.2 Discrimination

Table 12 presents the concordance results for (Low-Censoring, High-Dimensional) datasets. The findings in the paper (that MTLR/CoxEN-KP are superior to AFT and RSF-KM) are generally supported (actually always supported for being better than AFT). Except for VDV CoxEN-KP does better than RSF-KM and MTLR either matches or performs better than RSF-KM for all datasets.

Table 12: Concordance results for the 4 (Low-Censoring, High-Dimensional) datasets. Here we present the mean and standard deviation of the Concordance across the 5 cross-validation folds. Bolded values represent the best (highest Concordance) performing models. Note there are no results for Cox as it failed to run on all datasets.
AML MCL NSBCD VDV
KM 0.5 (0) 0.5 (0) 0.5 (0) 0.5 (0)
AFT 0.531 (0.074) 0.496 (0.063) 0.568 (0.129) 0.469 (0.084)
CoxEN-KP 0.656 (0.124) 0.788 (0.042) 0.784 (0.086) 0.679 (0.187)
RSF-KM 0.652 (0.089) 0.764 (0.058) 0.736 (0.101) 0.725 (0.13)
MTLR 0.651 (0.092) 0.805 (0.034) 0.776 (0.071) 0.733 (0.157)

5 High-Censoring, High-Dimensional

Here we examine 1 additional (High-Censoring, High-Dimensional) dataset, namely gene-expression data for 86 early lung adenocarcinoma (Lung) patients. – see “A Multi-Task Learning Formulation for Survival Analysis” by Li et al. for details regarding dataset access. Table 12 gives the summary statistics for this dataset.

Table 12: Summary statistics for the (High-Censoring, High-Dimensional) dataset. From top to bottom we have (1) the total number of patients, (2) the % of censored patients, and (3) the total number of features used (after feature selection).
Lung
N 86
% Censored 72.09
Number of Features 1121

5.1 Calibration

For calibration on (High-Censoring, High-Dimensional) datasets, our findings were that MTLR, CoxEN-KP, and RSF-KM were all equivalent. The D-Calibration results (Table 13) show that AFT is the only model to fail D-Calibration (note Cox failed to finish). Similarly, the 1-Calibration results (Table 14) show that MTLR, CoxEN-KP and RSF-KM are equivalent across the different percentiles suggesting our finding is consistent for this dataset as well.

Table 13: D-Calibration results for the 4 (Low-Censoring, High-Dimensional) datasets. The Total column gives the total number of datasets for which each model was D-Calibrated. Note the Cox model does not appear as it failed to finish on this dataset.
Lung
KM 1.000
AFT 0.000
CoxEN-KP 0.922
RSF-KM 0.887
MTLR 0.986
Table 14: The 1-Calibration results for the 4 (Low-Censoring, High-Dimensional) datasets. Each column represents the 10th, 25th, 50th, 75th, and 90th percentiles of event times. Each row represents the total number of datasets for which each model was 1-Calibrated (the maximum being 4). Note the Cox model does not appear as it failed to finish on this dataset.
10th 25th 50th 75th 90th
AFT 0 0 0 0 0
CoxEN-KP 1 1 1 1 0
RSF-KM 1 1 1 1 0
MTLR 1 1 1 1 0

5.2 Discrimination

Table 15 presents the concordance results for the (High-Censoring, High-Dimensional) dataset. The findings in the paper (that MTLR, CoxEN-KP, and RSF-KM are equivalent and also superior to AFT) are supported (although RSF-KM has much higher variance).

Table 15: Concordance results for the 4 (Low-Censoring, High-Dimensional) datasets. Here we present the mean and standard deviation of the Concordance across the 5 cross-validation folds. Bolded values represent the best (highest Concordance) performing models. Note the Cox model does not appear as it failed to finish on this dataset.
Lung
KM 0.5 (0)
AFT 0.668 (0.172)
CoxEN-KP 0.932 (0.039)
RSF-KM 0.816 (0.173)
MTLR 0.934 (0.029)
LS0tCnRpdGxlOiAiSVNEIEV2YWx1YXRpb24gLS0gU3VwcGxlbWVudGFsIERhdGFzZXQgUmVzdWx0cyIKYXV0aG9yOiAiSHVtemEgSGFpZGVyLCBCcmV0IEhvZWhuLCBTYXJhaCBEYXZpcywgUnVzc2VsbCBHcmVpbmVyIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazogCiAgICB0b2M6IFRSVUUKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQotLS0KCiNJbnRyb2R1Y3Rpb24gCgpUaGUgcmVzdWx0cyBoZXJlIGFjY29tcGFueSB0aGUgcGFwZXIgIkVmZmVjdGl2ZSBXYXlzIHRvIEJ1aWxkIGFuZCBFdmFsdWF0ZSBJbmRpdmlkdWFsIFN1cnZpdmFsIERpc3RyaWJ1dGlvbnMiIGJ5IEhhaWRlciBldCBhbC4gSW4gdG90YWwsIDMzIGFkZGl0aW9uYWwgZGF0YXNldHMgd2VyZSB0ZXN0ZWQgdG8gdmFsaWRhdGUgdGhlIGZpbmRpbmdzIGdpdmVuIGJ5IFRhYmxlIDcgaW4gU2VjdGlvbiA1IG9mIHRoZSBwYXBlci4gRm9yIGVhY2ggb2YgKExvdy1DZW5zb3JpbmcsIExvdy1EaW1lbnNpb25hbCksIChIaWdoLUNlbnNvcmluZywgTG93LURpbWVuc2lvbmFsKSwgKExvdy1DZW5zb3JpbmcsIEhpZ2gtRGltZW5zaW9uYWwpLCBhbmQgKEhpZ2gtQ2Vuc29yaW5nLCBIaWdoLURpbWVuc2lvbmFsKSB3ZSBoYXZlIDE2LCAxMiwgNCwgYW5kIDEgYWRkaXRpb25hbCBkYXRhc2V0cyB0byBjaGVjayB0aGUgZ2VuZXJhbGl6YXRpb24gb2YgdGhlIGZpbmRpbmdzLiBFYWNoIGZvbGxvd2luZyBzZWN0aW9uIGdpdmVzIGZ1cnRoZXIgZGV0YWlscyBhYm91dCB0aGUgY29ycmVzcG9uZGluZyBkYXRhc2V0cyB1c2VkLiBIZXJlIHdlIGhhdmUgZGVmaW5lZCAiSGlnaC1DZW5zb3JpbmciIHRvIGJlICRcZ2VxJCA3MCUuIEFkZGl0aW9uYWxseSwgIkhpZ2gtRGltZW5zaW9uYWwiIGRhdGFzZXRzIGFsbCBoYXZlIGF0IGxlYXN0IDI3NCBmZWF0dXJlcy4KCgpgYGB7ciwgZWNobyA9IEZBTFNFLCBlcnJvcj1GQUxTRSwgd2FybmluZz1GQUxTRX0KTmFtZSA9IGMoKQpOID0gYygpCk51bUZlYXQgPSBjKCkKUGVyY2VuQ2VucyA9IGMoKQpEQ2FsID0gYygpCk9uZUNhbDEgPSBjKCkKT25lQ2FsMiA9IGMoKQpPbmVDYWwzID0gYygpCk9uZUNhbDQgPSBjKCkKT25lQ2FsNSA9IGMoKQpDb25jVW5jZW5zID0gYygpCkNvbmNVbmNlbnNTRCA9IGMoKQpJbnRlZ2VyYXRlZEJyaWVyID0gYygpCkludGVncmVhdGVkQnJpZXJTRD0gYygpCkwxTW9kID0gYygpCkwxTW9kU0QgPSBjKCkKRGF0PWMoKQptb2RlbD1jKCkKZm9yKGkgaW4gbGlzdC5maWxlcygiLi4vUFNTUC9SZXN1bHRzL2V4dHJhRGF0LyIpKXsKICAjZmlyc3RQZXJpb2QgPSBncmVnZXhwcihwYXR0ZXJuID0gJ1xcLicsaSlbWzFdXVsxXQogIGRhdGFzZXQgPSBzdWJzdHIoaSwxLDcpCiAgRGF0ID0gYyhEYXQsZGF0YXNldCkKICByZXBvcnQgPSByZWFkLmNzdihwYXN0ZSgiLi4vUFNTUC9SZXN1bHRzL2V4dHJhRGF0LyIsaSxzZXA9IiIpKQogIE5hbWUgPSBjKE5hbWUsdW5uYW1lKHNhcHBseShhcy5jaGFyYWN0ZXIocmVwb3J0JE1vZGVsKSwgZnVuY3Rpb24oeCkgcGFzdGUoZGF0YXNldCwiOiAiLHgsc2VwPSIiKSkpKQogIG1vZGVsID0gYyhtb2RlbCxhcy5jaGFyYWN0ZXIocmVwb3J0JE1vZGVsKSkKICBOID0gYyhOLCByZXBvcnQkTikKICBOdW1GZWF0ID0gYyhOdW1GZWF0LCByZXBvcnQkTnVtRmVhdHVyZXMpCiAgUGVyY2VuQ2VucyA9IGMoUGVyY2VuQ2VucywgcmVwb3J0JFBlcmNlbnRDZW5zb3JlZCkKICBEQ2FsID0gYyhEQ2FsLCByZXBvcnQkRENhbGlicmF0aW9uQ3VtdWxhdGl2ZSkKICBPbmVDYWwxID0gYyhPbmVDYWwxLCByZXBvcnQkT25lQ2FsaWJyYXRpb25DdW11bGF0aXZlMSkKICBPbmVDYWwyID0gYyhPbmVDYWwyLCByZXBvcnQkT25lQ2FsaWJyYXRpb25DdW11bGF0aXZlMikKICBPbmVDYWwzID0gYyhPbmVDYWwzLCByZXBvcnQkT25lQ2FsaWJyYXRpb25DdW11bGF0aXZlMykKICBPbmVDYWw0ID0gYyhPbmVDYWw0LCByZXBvcnQkT25lQ2FsaWJyYXRpb25DdW11bGF0aXZlNCkKICBPbmVDYWw1ID0gYyhPbmVDYWw1LCByZXBvcnQkT25lQ2FsaWJyYXRpb25DdW11bGF0aXZlNSkKICBDb25jVW5jZW5zID0gYyhDb25jVW5jZW5zLCByZXBvcnQkQ29uY29yZGFuY2VVbmNlbnNvcmVkTSkKICBDb25jVW5jZW5zU0QgPSBjKENvbmNVbmNlbnNTRCwgcmVwb3J0JENvbmNvcmRhbmNlVW5jZW5zb3JlZFNEKQogIEludGVnZXJhdGVkQnJpZXIgPSBjKEludGVnZXJhdGVkQnJpZXIsIHJlcG9ydCRJbnRlZ3JhdGVkQnJpZXJNKQogIEludGVncmVhdGVkQnJpZXJTRD0gYyhJbnRlZ3JlYXRlZEJyaWVyU0QsIHJlcG9ydCRJbnRlZ3JhdGVkQnJpZXJTRCkKICBMMU1vZCA9IGMoTDFNb2QsIHJlcG9ydCRMMU1hcmdpbk5vTG9nTSkKICBMMU1vZFNEID0gYyhMMU1vZFNELCByZXBvcnQkTDFNYXJnaW5Ob0xvZ1NEKQp9CkNvbmNVbmNlbnNDb21ibyA9IHBhc3RlKHJvdW5kKENvbmNVbmNlbnMsMyksIiAoIixyb3VuZChDb25jVW5jZW5zU0QsMyksICIpIiwgc2VwPSIiKQpJbnRlZ3JhdGVkQnJpZXJDb21ibyA9IHBhc3RlKHJvdW5kKEludGVnZXJhdGVkQnJpZXIsNCksIiAoIixyb3VuZChJbnRlZ3JlYXRlZEJyaWVyU0QsMyksICIpIiwgc2VwPSIiKQpMMUNvbWJvID0gcGFzdGUocm91bmQoTDFNb2QsMiksIiAoIixyb3VuZChMMU1vZFNELDIpLCAiKSIsIHNlcD0iIikKdGFiID0gbWF0cml4KGMoTmFtZSxOLE51bUZlYXQscm91bmQoUGVyY2VuQ2VucyoxMDAsMiksIHBhc3RlKHJvdW5kKERDYWwsMykpLHBhc3RlKHJvdW5kKE9uZUNhbDEsMykpLHBhc3RlKHJvdW5kKE9uZUNhbDIsMykpLAogICAgICAgICAgICAgICBwYXN0ZShyb3VuZChPbmVDYWwzLDMpKSxwYXN0ZShyb3VuZChPbmVDYWw0LDMpKSxwYXN0ZShyb3VuZChPbmVDYWw1LDMpKSxDb25jVW5jZW5zQ29tYm8sCiAgICAgICAgICAgICAgIEludGVncmF0ZWRCcmllckNvbWJvLEwxQ29tYm8pLGxlbmd0aChOYW1lKSwxMywKICAgICAgICAgICAgIGRpbW5hbWVzID0gbGlzdChOVUxMLGMoIk5hbWUiLCAiTiIsIk51bUZlYXQiLCAiUENlbnMiLCJEQ2FsIiwiT0NhbDEiLCJPQ2FsMiIsIk9DYWwzIiwiT0NhbDQiLCJPQ2FsNSIsICJDb25TdGFuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIklCUyIsICJMMSIpKSkKCmRhdDIgPSBkYXRhLmZyYW1lKHRhYikKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKZGF0YXNldE5hbWVzID0gYygpCmZvcihpIGluIGxpc3QuZmlsZXMoIi4uL1BTU1AvUmVzdWx0cy9leHRyYURhdC8iKSl7CiAgIGZpcnN0UGVyaW9kID0gZ3JlZ2V4cHIocGF0dGVybiA9ICdcXC4nLGkpW1sxXV1bMV0KICAgZGF0YXNldE5hbWVzID0gYyhkYXRhc2V0TmFtZXMsIHN1YnN0cihpLDEsZmlyc3RQZXJpb2QtMSkpCn0KCmFsZ05hbWVzID0gYygiQUZUIiwiQ294LUtQIiwiQ294RU4tS1AiLCJLTSIsIk1UTFIiLCJSU0YtS00iKQoKbGlicmFyeSh4dGFibGUpCmxpYnJhcnkoRGF0YUNvbWJpbmUpCnRvUGxheSA9IGRhdDIKI3RvUGxheSA9IEluc2VydFJvdyh0b1BsYXkscmVwKE5BLDEzKSwyKQojdG9QbGF5ID0gSW5zZXJ0Um93KHRvUGxheSxyZXAoTkEsMTMpLDgpCiN0b1BsYXkgPSB0b1BsYXlbYygxMzozNiwzNzo0OCwgMToxMiksXQpDZW5zID0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIodW5pcXVlKHRvUGxheSRQQ2VucylbIWlzLm5hKHVuaXF1ZSh0b1BsYXkkUENlbnMpKV0pKQpOcyAgPSBhcy5udW1lcmljKGFzLmNoYXJhY3Rlcih0b1BsYXkkTltzZXEoMSxucm93KHRvUGxheSksYnkgID0gNildKSkKRmVhdHVyZXNTZWxlY3RlZCAgPSBhcy5udW1lcmljKGFzLmNoYXJhY3Rlcih0b1BsYXkkTnVtRmVhdFtzZXEoMSxucm93KHRvUGxheSksYnkgID0gNildKSkKCkhDID0gQ2VucyA+PTcwCgpDZW5zSEMgPSBDZW5zW0hDXQpOc0hDID0gTnNbSENdCkZlYXR1cmVzU2VsZWN0ZWRIQyA9IEZlYXR1cmVzU2VsZWN0ZWRbSENdCgpDZW5zTEMgPSBDZW5zWyFIQ10KTnNMQyA9IE5zWyFIQ10KRmVhdHVyZXNTZWxlY3RlZExDID0gRmVhdHVyZXNTZWxlY3RlZFshSENdCgpoZWFkZXJIQyA9IGFzLmRhdGEuZnJhbWUobWF0cml4KGMoTnNIQyxDZW5zSEMsRmVhdHVyZXNTZWxlY3RlZEhDKSxuY29sID0gc3VtKEhDKSwgYnlyb3c9VCkpCiNoZWFkZXJIQyA9IHJvdW5kKGhlYWRlckhDKQpuYW1lcyhoZWFkZXJIQykgPSBkYXRhc2V0TmFtZXNbSENdCnJvdy5uYW1lcyhoZWFkZXJIQykgPSBjKCJOIiwiJSBDZW5zb3JlZCIsIk51bWJlciBvZiBGZWF0dXJlcyIpCmhlYWRlckhDWzEsXSA9IGZvcm1hdEMoaGVhZGVySENbMSxdLCBmb3JtYXQgPSAiZCIpCmhlYWRlckxDID0gYXMuZGF0YS5mcmFtZShtYXRyaXgoYyhOc0xDLENlbnNMQyxGZWF0dXJlc1NlbGVjdGVkTEMpLG5jb2wgPSBzdW0oIUhDKSwgYnlyb3c9VCkpCiNoZWFkZXJIQyA9IHJvdW5kKGhlYWRlckhDKQpuYW1lcyhoZWFkZXJMQykgPSBkYXRhc2V0TmFtZXNbIUhDXQpyb3cubmFtZXMoaGVhZGVyTEMpID0gYygiTiIsIiUgQ2Vuc29yZWQiLCJOdW1iZXIgb2YgRmVhdHVyZXMiKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCmBgYAoKPGhyIHN0eWxlPSJoZWlnaHQ6M3B4O2JvcmRlcjpub25lO2NvbG9yOiMzMzM7YmFja2dyb3VuZC1jb2xvcjojMzMzOyIgLz4KCgojTG93LUNlbnNvcmluZywgTG93LURpbWVuc2lvbmFsCgpBbGwgZGF0YXNldHMgaW4gdGhpcyBjYXRlZ29yeSB3ZXJlIGNvbGxlY3RlZCBmcm9tIHRoZSBUQ0dBIHdlYnNpdGUgKGRldGFpbHMgZ2l2ZW4gaW4gdGhlIHBhcGVyKS4gU3BlY2lmaWNhbGx5LCBoZXJlIHdlIGhhdmUgMTYgZGF0YXNldHMgY29ycmVzcG9uZGluZyB0byBzdXJ2aXZhbCB0aW1lIGZyb20gZGlmZmVyZW50IGNhbmNlciB0eXBlczogQWRyZW5vY29ydGljYWwgY2FyY2lub21hIChBQ0MpLCBCbGFkZGVyIFVyb3RoZWxpYWwgQ2FyY2lub21hIChCTENBKSwgQ2hvbGFuZ2lvY2FyY2lub21hIChDSE9MKSwgRXNvcGhhZ2VhbCBjYXJjaW5vbWEgKEVTQ0EpLCBIZWFkIGFuZCBOZWNrIHNxdWFtb3VzIGNlbGwgY2FyY2lub21hIChITlNDKSwgS2lkbmV5IHJlbmFsIGNsZWFyIGNlbGwgY2FyY2lub21hIChLSVJDKSwgTGl2ZXIgaGVwYXRvY2VsbHVsYXIgY2FyY2lub21hIChMSUhDKSwgTHVuZyBhZGVub2NhcmNpbm9tYSAoTFVBRCksIEx1bmcgc3F1YW1vdXMgY2VsbCBjYXJjaW5vbWEgKExVU0MpLCBPdmFyaWFuIHNlcm91cyBjeXN0YWRlbm9jYXJjaW5vbWEgKE9WKSwgUGFuY3JlYXRpYyBhZGVub2NhcmNpbm9tYSAoUEFBRCksIFNhcmNvbWEgKFNBUkMpLCBTa2luIEN1dGFuZW91cyBNZWxhbm9tYSAoU0tDTSksIFN0b21hY2ggYWRlbm9jYXJjaW5vbWEgKFNUQUQpLCBTdG9tYWNoIGFuZCBFc29waGFnZWFsIGNhcmNpbm9tYSAoU1RFUyksIGFuZCBVdGVyaW5lIENhcmNpbm9zYXJjb21hIChVQ1MpLiBUYWJsZSAxIGdpdmVzIHN1bW1hcnkgc3RhdGlzdGljcyBmb3IgZWFjaCBvZiB0aGUgMTYgZGF0YXNldHMuIAoKCmBgYHtyLCBlY2hvPUZBTFNFLCBlcnJvciA9IEZBTFNFLHdhcm5pbmc9RkFMU0V9CmhlYWRlckxDWzEsXSA9IGZvcm1hdEMoaGVhZGVyTENbMSxdLCBmb3JtYXQgPSAiZCIpCgprYWJsZShoZWFkZXJMQywgZm9ybWF0ID0gImh0bWwiLCBjYXB0aW9uID0gIlRhYmxlIDE6IFN1bW1hcnkgc3RhdGlzdGljcyBmb3IgdGhlIDE2IChMb3ctQ2Vuc29yaW5nLCBMb3ctRGltZW5zaW9uYWwpIGRhdGFzZXRzLiBGcm9tIHRvcCB0byBib3R0b20gd2UgaGF2ZSAoMSkgdGhlIHRvdGFsIG51bWJlciBvZiBwYXRpZW50cywgKDIpIHRoZSAlIG9mIGNlbnNvcmVkIHBhdGllbnRzLCBhbmQgKDMpIHRoZSB0b3RhbCBudW1iZXIgb2YgZmVhdHVyZXMgdXNlZCAoYWZ0ZXIgZmVhdHVyZSBzZWxlY3Rpb24pLiIsYWxpZ24gPSBjKCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycsJ2MnKSkgJT4lCiAgICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gInN0cmlwZWQiLCBmdWxsX3dpZHRoID0gRiApICU+JQogIGNvbHVtbl9zcGVjKDEsYm9sZD1ULCB3aWR0aF9taW4gPSAiNGNtIikKYGBgCgo8aHIgc3R5bGU9ImhlaWdodDoxcHg7Ym9yZGVyOm5vbmU7Y29sb3I6IzMzMztiYWNrZ3JvdW5kLWNvbG9yOiMzMzM7IiAvPgoKCiMjQ2FsaWJyYXRpb24KCkNvbmNlcm5pbmcgY2FsaWJyYXRpb24gZm9yIHRoZSAoTG93LUNlbnNvcmluZywgTG93LURpbWVuc2lvbmFsKSBkYXRhc2V0cywgb3VyIGZpbmRpbmdzIHdlcmUgdGhhdCBNVExSIHdhcyBzdXBlcmlvciB0byBvdGhlciBtb2RlbHMuIFRoZSBELUNhbGlicmF0aW9uIChUYWJsZSAyKSByZXN1bHRzIHN1cHBvcnQgdGhpcyBhcyBNVExSIGlzIEQtQ2FsaWJyYXRlZCBmb3IgYWxsIDE2IGRhdGFzZXRzICh0aG91Z2ggQUZUIGFuZCBDb3ggYXJlIGFsc28gRC1DYWxpYnJhdGVkIGZvciBhbGwgZGF0YXNldHMpLiBUaGUgMS1DYWxpYnJhdGlvbiByZXN1bHRzIChUYWJsZSAzKSBhcmUgbW9yZSBkaXNjcmltaW5hdGl2ZSBzaG93aW5nIE1UTFIgYW5kIENveEVOLUtQIHRvIG91dHBlcmZvcm0gYWxsIG90aGVyIG1vZGVscy4gQWx0aG91Z2ggQ294RU4tS1Agc2hvd3MgdG8gYmUgY29tcGV0aXRpdmUgd2l0aCBNVExSIHdpdGggdGhlc2UgZGF0YXNldHMsIHdoZW4gY29tYmluZWQgd2l0aCB0aGUgcmVzdWx0cyBmcm9tIHRoZSBwYXBlciwgTVRMUiBoYXMgYSBnZW5lcmFsIGJldHRlciBwZXJmb3JtYW5jZSBsZWFkaW5nIHVzIHRvIHJlY29tbWVuZCBNVExSIHdoZW4gbWVhc3VyaW5nIGNhbGlicmF0aW9uIG9uIChMb3ctQ2Vuc29yaW5nLCBMb3ctRGltZW5zaW9uYWwpIGRhdGFzZXRzLgoKTm90ZSB3ZSBvbmx5IGluY2x1ZGUgdGhlIGFjY3VtdWxhdGVkIDEtQ2FsaWJyYXRpb24gcmVzdWx0cyBoZXJlICh0aGUgZXhhY3QgJHAkLXZhbHVlcyBhcmUgYXZhaWxhYmxlIHVwb24gcmVxdWVzdC4pCgpgYGB7ciwgZWNobz1GQUxTRX0KSENJbmQgPSByZXAoSEMsZWFjaCA9IDYpCnRvVGFibGUgPSBhcy5kYXRhLmZyYW1lKG1hdHJpeChkYXRhID0gdG9QbGF5JERDYWxbIUhDSW5kXSwgbmNvbCA9IGxlbmd0aChkYXRhc2V0TmFtZXNbIUhDXSkpKQp0b1RhYmxlID0gYXMuZGF0YS5mcmFtZShhcHBseSh0b1RhYmxlLDIsZnVuY3Rpb24oeCkgYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoeCkpKSkKY29sbmFtZXModG9UYWJsZSkgPSBkYXRhc2V0TmFtZXNbIUhDXQp0b1RhYmxlID0gdG9UYWJsZVtjKDQsMSwyLDMsNiw1KSxdCnJvd25hbWVzKHRvVGFibGUpID0gYygiS00iLCJBRlQiLCJDb3gtS1AiLCJDb3hFTi1LUCIsIlJTRi1LTSIsIk1UTFIiKQoKdG9UYWJsZSRUb3RhbCA9IHJvd1N1bXMoYXBwbHkodG9UYWJsZSwgMiwgZnVuY3Rpb24oeCkgYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoeCkpKSA+PSAwLjA1KQprYWJsZSh0b1RhYmxlLCBkaWdpdHMgPSAzLGZvcm1hdCA9ICJodG1sIiwgY2FwdGlvbiA9ICJUYWJsZSAyOiBELUNhbGlicmF0aW9uIHJlc3VsdHMgZm9yIHRoZSAxNiAoTG93LUNlbnNvcmluZywgTG93LURpbWVuc2lvbmFsKSBkYXRhc2V0cy4gVGhlIFRvdGFsIGNvbHVtbiBnaXZlcyB0aGUgdG90YWwgbnVtYmVyIG9mIGRhdGFzZXRzIGZvciB3aGljaCBlYWNoIG1vZGVsIHdhcyBELUNhbGlicmF0ZWQuIixhbGlnbiA9IGMoJ2MnLCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycsJ2MnKSkgJT4lCiAgICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gInN0cmlwZWQiLCBmdWxsX3dpZHRoID0gVCkgJT4lCiAgICBjb2x1bW5fc3BlYyhjKDEsMTgpLGJvbGQ9VCx3aWR0aF9taW4gPSAiMi41Y20iKQoKYGBgCgpgYGB7cixlY2hvID0gRn0Kb25lQ2FsID0gYXMuZGF0YS5mcmFtZShhcHBseSh0b1BsYXlbNjoxMF1bIUhDSW5kLF0sMixmdW5jdGlvbih4KSBhcy5udW1lcmljKGFzLmNoYXJhY3Rlcih4KSkpKQpvbmVDYWwkTW9kZWwgPSByZXAoYWxnTmFtZXMsIGxlbmd0aChkYXRhc2V0TmFtZXNbIUhDXSkpCmxpYnJhcnkoZHBseXIpCnRvVGFibGUgPSBvbmVDYWwgJT4lIGdyb3VwX2J5KE1vZGVsKSAlPiUgc3VtbWFyaXplKE9DMSA9IHN1bShPQ2FsMSA+PTAuMDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9DMiA9IHN1bShPQ2FsMiA+PTAuMDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9DMyA9IHN1bShPQ2FsMyA+PTAuMDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9DNCA9IHN1bShPQ2FsNCA+PTAuMDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9DNSA9IHN1bShPQ2FsNSA+PTAuMDUpKQp0b1RhYmxlID0gYXMuZGF0YS5mcmFtZSh0b1RhYmxlKQp0b1RhYmxlID0gdG9UYWJsZVtjKDEsMywyLDYsNSksLTFdCnJvd25hbWVzKHRvVGFibGUpID0gYygiQUZUIiwiQ294LUtQIiwiQ294RU4tS1AiLCJSU0YtS00iLCJNVExSIikKY29sbmFtZXModG9UYWJsZSkgPSBjKCIxMHRoIiwiMjV0aCIsICI1MHRoIiwiNzV0aCIsIjkwdGgiKQogIAoKa2FibGUodG9UYWJsZSAsIGZvcm1hdCA9ICJodG1sIiwgY2FwdGlvbiA9ICJUYWJsZSAzOiBUaGUgMS1DYWxpYnJhdGlvbiByZXN1bHRzIGZvciB0aGUgMTYgKExvdy1DZW5zb3JpbmcsIExvdy1EaW1lbnNpb25hbCkgZGF0YXNldHMuIEVhY2ggY29sdW1uIHJlcHJlc2VudHMgdGhlIDEwdGgsIDI1dGgsIDUwdGgsIDc1dGgsIGFuZCA5MHRoIHBlcmNlbnRpbGVzIG9mIGV2ZW50IHRpbWVzLiBFYWNoIHJvdyByZXByZXNlbnRzIHRoZSB0b3RhbCBudW1iZXIgb2YgZGF0YXNldHMgZm9yIHdoaWNoIGVhY2ggbW9kZWwgd2FzIDEtQ2FsaWJyYXRlZCAodGhlIG1heGltdW0gYmVpbmcgMTYpLiIsYWxpZ24gPSBjKCdjJywnYycsJ2MnLCdjJywnYycpKSAlPiUKICAgIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSAic3RyaXBlZCIsIGZ1bGxfd2lkdGggPSBUICkgJT4lCiAgICBjb2x1bW5fc3BlYyhjKDEpLGJvbGQ9VCx3aWR0aF9taW4gPSAiMi41Y20iKQoKYGBgCgo8aHIgc3R5bGU9ImhlaWdodDoxcHg7Ym9yZGVyOm5vbmU7Y29sb3I6IzMzMztiYWNrZ3JvdW5kLWNvbG9yOiMzMzM7IiAvPgoKCiMjRGlzY3JpbWluYXRpb24KClNpbmNlIGRpc2NyaW1pbmF0aW9uIGlzIHByaW1hcmlseSBldmFsdWF0ZWQgd2l0aCBjb25jb3JkYW5jZSB3ZSBvbmx5IHByZXNlbnQgdGhpcyByZXN1bHQgYW5kIG9taXQgdGhlIEludGVncmF0ZWQgQnJpZXIgc2NvcmUgYW5kIHRoZSBMMS1sb3NzICh0aG91Z2ggdGhlc2UgcmVzdWx0cyBhcmUgYXZhaWxhYmxlIGZyb20gdGhlIGF1dGhvcnMgdXBvbiByZXF1ZXN0KS4gVGFibGUgNCBwcmVzZW50cyB0aGVzZSBjb25jb3JkYW5jZSByZXN1bHRzLCBhbmQgd2Ugc2VlIHJlc3VsdHMgY29uc2lzdGVudCB3aXRoIHRoZSBmaW5kaW5ncyBvZiB0aGUgcGFwZXIgLS0gYWx0aG91Z2ggb3RoZXIgbW9kZWxzIChoZXJlIE1UTFIgYW5kIENveEVOLUtQKSBnZW5lcmFsbHkgb3V0cGVyZm9ybSBBRlQgYW5kIENveC1LUCwgdGhlIHBlcmZvcm1hbmNlIGdhaW4gaXMgbm90IHNpZ25pZmljYW50LiBGdXJ0aGVyLCB3ZSBhZ2FpbiBzZWUgdGhlIHBvb3IgcGVyZm9ybWFuY2Ugb2YgUlNGLUtNIG9uIHRoZXNlIExvdy1EaW1lbnNpb25hbCBtb2RlbHMuIER1ZSB0byBtb2RlbCBzaW1wbGljaXR5IG9mIEFGVCBhbmQgQ294LUtQIHdlIHN1Z2dlc3QgdXNpbmcgdGhlc2UgbW9kZWxzIGZvciBkaXNjcmltaW5hdGlvbiBvbiAoTG93LUNlbnNvcmluZywgTG93LURpbWVuc2lvbmFsKSBkYXRhc2V0cy4KCgpgYGB7ciwgZWNobyA9IEZBTFNFLGVycm9yPUZBTFNFLHdhcm5pbmc9RkFMU0V9CnRvVGFibGUgPSBhcy5kYXRhLmZyYW1lKG1hdHJpeChkYXRhID0gdG9QbGF5JENvblN0YW5bIUhDSW5kXSwgbmNvbCA9IGxlbmd0aChkYXRhc2V0TmFtZXNbIUhDXSkpKQoKdG9UYWJsZSA9IHRvVGFibGVbYyg0LDEsMiwzLDYsNSksXQpyb3duYW1lcyh0b1RhYmxlKSA9IGMoIktNIiwiQUZUIiwiQ294LUtQIiwiQ294RU4tS1AiLCJSU0YtS00iLCJNVExSIikKY29sbmFtZXModG9UYWJsZSkgPSBkYXRhc2V0TmFtZXNbIUhDXQoKdG9UYWJsZSAgJT4lCmthYmxlKHRvVGFibGUsIGZvcm1hdCA9ICJodG1sIiwgY2FwdGlvbiA9ICJUYWJsZSA0OiBDb25jb3JkYW5jZSByZXN1bHRzIGZvciB0aGUgMTYgKExvdy1DZW5zb3JpbmcsIExvdy1EaW1lbnNpb25hbCkgZGF0YXNldHMuIEhlcmUgd2UgcHJlc2VudCB0aGUgbWVhbiBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIHRoZSBDb25jb3JkYW5jZSBhY3Jvc3MgdGhlIDUgY3Jvc3MtdmFsaWRhdGlvbiBmb2xkcy4gQm9sZGVkIHZhbHVlcyByZXByZXNlbnQgdGhlIGJlc3QgKGhpZ2hlc3QgQ29uY29yZGFuY2UpIHBlcmZvcm1pbmcgbW9kZWxzLiIsYWxpZ24gPSBjKCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJykpICU+JQogICAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9ICJzdHJpcGVkIiwgZnVsbF93aWR0aCA9IEYgKSAlPiUKICAgICAgY29sdW1uX3NwZWMoYygxKSxib2xkPVQsd2lkdGhfbWluID0gIjIuNWNtIikKCmBgYAoKCjxociBzdHlsZT0iaGVpZ2h0OjNweDtib3JkZXI6bm9uZTtjb2xvcjojMzMzO2JhY2tncm91bmQtY29sb3I6IzMzMzsiIC8+CgoKI0hpZ2gtQ2Vuc29yLCBMb3cgRGltZW5zaW9uYWwKCkFsbCBkYXRhc2V0cyBpbiB0aGlzIGNhdGVnb3J5IHdlcmUgY29sbGVjdGVkIGZyb20gdGhlIFRDR0Egd2Vic2l0ZSAoZGV0YWlscyBnaXZlbiBpbiB0aGUgcGFwZXIpLiBTcGVjaWZpY2FsbHksIGhlcmUgd2UgaGF2ZSAxMiBkYXRhc2V0cyBjb3JyZXNwb25kaW5nIHRvIHN1cnZpdmFsIHRpbWUgZnJvbSBkaWZmZXJlbnQgY2FuY2VyIHR5cGVzOiBDZXJ2aWNhbCBzcXVhbW91cyBjZWxsIGNhcmNpbm9tYSBhbmQgZW5kb2NlcnZpY2FsIGFkZW5vY2FyY2lub21hIFtDRVNDXSwgQ29sb24gYWRlbm9jYXJjaW5vbWEgW0NPQURdLCBDb2xvcmVjdGFsIGFkZW5vY2FyY2lub21hIChDT0FEUkVBRCksIEZGUEUgUGlsb3QgUGhhc2UgSUkgW0ZQUFBdLCBLaWRuZXkgQ2hyb21vcGhvYmUgW0tJQ0hdLCBQYW4ta2lkbmV5IGNvaG9ydCAoS0lQQU4pLCBLaWRuZXkgcmVuYWwgcGFwaWxsYXJ5IGNlbGwgY2FyY2lub21hIFtLSVJQXSwgTG93ZXIgR3JhZGUgR2xpbm9tYSAoTEdHKSwgUHJvc3RhdGUgYWRlbm9jYXJjaW5vbWEgW1BSQURdLCBUaHlyb2lkIGNhcmNpbm9tYSBbVEhDQV0sIFV0ZXJpbmUgQ29ycHVzIEVuZG9tZXRyaWFsIENhcmNpbm9tYSBbVUNFQ10sIGFuZCBVdmVhbCBNZWxhbm9tYSBbVVZNXS4gVGFibGUgNSBnaXZlcyBzdW1tYXJ5IHN0YXRpc3RpY3MgZm9yIGVhY2ggb2YgdGhlIDEyIGRhdGFzZXRzLiAKCgpgYGB7ciwgZWNobz1GQUxTRSwgZXJyb3IgPSBGQUxTRSx3YXJuaW5nPUZBTFNFfQpoZWFkZXJIQ1sxLF0gPSBmb3JtYXRDKGhlYWRlckhDWzEsXSwgZm9ybWF0ID0gImQiKQoKa2FibGUoaGVhZGVySEMsIGZvcm1hdCA9ICJodG1sIiwgY2FwdGlvbiA9ICJUYWJsZSA1OiBTdW1tYXJ5IHN0YXRpc3RpY3MgZm9yIHRoZSAxMiAoSGlnaC1DZW5zb3JpbmcsIExvdy1EaW1lbnNpb25hbCkgZGF0YXNldHMuIEZyb20gdG9wIHRvIGJvdHRvbSB3ZSBoYXZlICgxKSB0aGUgdG90YWwgbnVtYmVyIG9mIHBhdGllbnRzLCAoMikgdGhlICUgb2YgY2Vuc29yZWQgcGF0aWVudHMsIGFuZCAoMykgdGhlIHRvdGFsIG51bWJlciBvZiBmZWF0dXJlcyB1c2VkIChhZnRlciBmZWF0dXJlIHNlbGVjdGlvbikuIixhbGlnbiA9IGMoJ2MnLCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycpKSAlPiUKICAgIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSAic3RyaXBlZCIsIGZ1bGxfd2lkdGggPSBUICkgJT4lCiAgY29sdW1uX3NwZWMoMSxib2xkPVQpCmBgYAoKPGhyIHN0eWxlPSJoZWlnaHQ6MXB4O2JvcmRlcjpub25lO2NvbG9yOiMzMzM7YmFja2dyb3VuZC1jb2xvcjojMzMzOyIgLz4KCgojI0NhbGlicmF0aW9uCgpGb3IgY2FsaWJyYXRpb24gb24gKEhpZ2gtQ2Vuc29yaW5nLCBMb3ctRGltZW5zaW9uYWwpIGRhdGFzZXRzLCBvdXIgZmluZGluZ3Mgd2VyZSB0aGF0IE1UTFIgYW5kIENveEVOLUtQIG91dHBlcmZvcm1lZCBvdGhlciBtb2RlbHMuIFRoZSBELUNhbGlicmF0aW9uIChUYWJsZSA2KSByZXN1bHRzIGFyZSBpbmNvbmNsdXNpdmUgYXMgbmVhcmx5IGFsbCBtb2RlbHMgYXJlIEQtQ2FsaWJyYXRlZCBmb3IgYWxsIGRhdGFzZXRzIChyZWNhbGwgRC1DYWxpYnJhdGlvbiBpcyBvcHRpbWlzdGljIHdoZW4gZGF0YSBpcyBoaWdobHkgY2Vuc29yZWQpLiBUaGUgMS1DYWxpYnJhdGlvbiByZXN1bHRzIChUYWJsZSA3KSBzaG93IE1UTFIgYW5kIENveEVOLUtQIHRvIG91dHBlcmZvcm0gYWxsIG90aGVyIG1vZGVscyB3aXRoIENveEVOLUtQIHNsaWdodGx5IG91dHBlcmZvcm1pbmcgTVRMUi4gR2l2ZW4gTVRMUidzIGJldHRlciBwZXJmb3JtYW5jZSBvbiB0aGUgZGF0YXNldHMgZ2l2ZW4gaW4gdGhlIHBhcGVyLCB0aGVzZSByZXN1bHRzIHN1cHBvcnQgdGhlIGZpbmRpbmcgdGhhdCBNVExSIGFuZCBDb3hFTi1LUCBhcmUgdGhlIGJlc3QgKGFuZCBnZW5lcmFsbHkgZXF1aXZhbGVudCkgbW9kZWxzIGZvciBjYWxpYnJhdGlvbiBvbiAoSGlnaC1DZW5zb3JpbmcsIExvdy1EaW1lbnNpb25hbCkgZGF0YXNldHMuCgpgYGB7ciwgZWNobz1GQUxTRX0KSENJbmQgPSByZXAoSEMsZWFjaCA9IDYpCnRvVGFibGUgPSBhcy5kYXRhLmZyYW1lKG1hdHJpeChkYXRhID0gdG9QbGF5JERDYWxbSENJbmRdLCBuY29sID0gbGVuZ3RoKGRhdGFzZXROYW1lc1tIQ10pKSkKdG9UYWJsZSA9IGFzLmRhdGEuZnJhbWUoYXBwbHkodG9UYWJsZSwyLGZ1bmN0aW9uKHgpIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHgpKSkpCmNvbG5hbWVzKHRvVGFibGUpID0gZGF0YXNldE5hbWVzW0hDXQp0b1RhYmxlID0gdG9UYWJsZVtjKDQsMSwyLDMsNiw1KSxdCnJvd25hbWVzKHRvVGFibGUpID0gYygiS00iLCJBRlQiLCJDb3gtS1AiLCJDb3hFTi1LUCIsIlJTRi1LTSIsIk1UTFIiKQoKdG9UYWJsZSRUb3RhbCA9IHJvd1N1bXMoYXBwbHkodG9UYWJsZSwgMiwgZnVuY3Rpb24oeCkgYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoeCkpKSA+PSAwLjA1KQprYWJsZSh0b1RhYmxlLGRpZ2l0cyA9IDMsIGZvcm1hdCA9ICJodG1sIiwgY2FwdGlvbiA9ICJUYWJsZSA2OiBELUNhbGlicmF0aW9uIHJlc3VsdHMgZm9yIHRoZSAxMiAoSGlnaC1DZW5zb3JpbmcsIExvdy1EaW1lbnNpb25hbCkgZGF0YXNldHMuIFRoZSBUb3RhbCBjb2x1bW4gZ2l2ZXMgdGhlIHRvdGFsIG51bWJlciBvZiBkYXRhc2V0cyBmb3Igd2hpY2ggZWFjaCBtb2RlbCB3YXMgRC1DYWxpYnJhdGVkLiIsYWxpZ24gPSBjKCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJykpICU+JQogICAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9ICJzdHJpcGVkIiwgZnVsbF93aWR0aCA9IFQgKSAlPiUKICAgIGNvbHVtbl9zcGVjKGMoMSwxNCksYm9sZD1ULHdpZHRoX21pbiA9ICIyLjVjbSIpCgpgYGAKCgpgYGB7ciwgZWNobz1GfQpvbmVDYWwgPSBhcy5kYXRhLmZyYW1lKGFwcGx5KHRvUGxheVs2OjEwXVtIQ0luZCxdLDIsZnVuY3Rpb24oeCkgYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoeCkpKSkKb25lQ2FsJE1vZGVsID0gcmVwKGFsZ05hbWVzLCBsZW5ndGgoZGF0YXNldE5hbWVzW0hDXSkpCmxpYnJhcnkoZHBseXIpCnRvVGFibGUgPSBvbmVDYWwgJT4lIGdyb3VwX2J5KE1vZGVsKSAlPiUgc3VtbWFyaXplKE9DMSA9IHN1bShPQ2FsMSA+PTAuMDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9DMiA9IHN1bShPQ2FsMiA+PTAuMDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9DMyA9IHN1bShPQ2FsMyA+PTAuMDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9DNCA9IHN1bShPQ2FsNCA+PTAuMDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9DNSA9IHN1bShPQ2FsNSA+PTAuMDUpKQp0b1RhYmxlID0gYXMuZGF0YS5mcmFtZSh0b1RhYmxlKQp0b1RhYmxlID0gdG9UYWJsZVtjKDEsMywyLDYsNSksLTFdCnJvd25hbWVzKHRvVGFibGUpID0gYygiQUZUIiwiQ294LUtQIiwiQ294RU4tS1AiLCJSU0YtS00iLCJNVExSIikKY29sbmFtZXModG9UYWJsZSkgPSBjKCIxMHRoIiwiMjV0aCIsICI1MHRoIiwiNzV0aCIsIjkwdGgiKQogIAoKa2FibGUodG9UYWJsZSAsIGZvcm1hdCA9ICJodG1sIiwgY2FwdGlvbiA9ICJUYWJsZSA3OiBUaGUgMS1DYWxpYnJhdGlvbiByZXN1bHRzIGZvciB0aGUgMTIgKEhpZ2gtQ2Vuc29yaW5nLCBMb3ctRGltZW5zaW9uYWwpIGRhdGFzZXRzLiBFYWNoIGNvbHVtbiByZXByZXNlbnRzIHRoZSAxMHRoLCAyNXRoLCA1MHRoLCA3NXRoLCBhbmQgOTB0aCBwZXJjZW50aWxlcyBvZiBldmVudCB0aW1lcy4gRWFjaCByb3cgcmVwcmVzZW50cyB0aGUgdG90YWwgbnVtYmVyIG9mIGRhdGFzZXRzIGZvciB3aGljaCBlYWNoIG1vZGVsIHdhcyAxLUNhbGlicmF0ZWQgKHRoZSBtYXhpbXVtIGJlaW5nIDEyKS4iLGFsaWduID0gYygnYycsJ2MnLCdjJywnYycsJ2MnKSkgJT4lCiAgICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gInN0cmlwZWQiLCBmdWxsX3dpZHRoID0gVCApICU+JQogICAgY29sdW1uX3NwZWMoYygxKSxib2xkPVQsd2lkdGhfbWluID0gIjIuNWNtIikKCmBgYAoKPGhyIHN0eWxlPSJoZWlnaHQ6MXB4O2JvcmRlcjpub25lO2NvbG9yOiMzMzM7YmFja2dyb3VuZC1jb2xvcjojMzMzOyIgLz4KCgojI0Rpc2NyaW1pbmF0aW9uCgpUYWJsZSA4IHByZXNlbnRzIGNvbmNvcmRhbmNlIHJlc3VsdHMgZm9yIChIaWdoLUNlbnNvcmluZywgTG93LURpbWVuc2lvbmFsKSBkYXRhc2V0cyBhbmQgd2Ugc2VlIHJlc3VsdHMgY29uc2lzdGVudCB3aXRoIHRoZSBmaW5kaW5ncyBvZiB0aGUgcGFwZXIgLS0gKDEpIENveEVOLUtQIGFuZCBNVExSIGFyZSBzdXBlcmlvciB0byBBRlQgYW5kIENveCBhbmQgKDIpIFJTRi1LTSB0eXBpY2FsbHkgc2VlcyBub3RpY2VhYmx5IHdvcnNlIHBlcmZvcm1hbmNlLiBUaGlzIHN1cHBvcnRzIG91ciByZWNvbW1lbmRhdGlvbiB0byB1c2UgTVRMUiBvciBDb3hFTi1LUCB3aGVuIGV2YWx1YXRpbmcgZGlzY3JpbWluYXRpb24gb24gKEhpZ2gtQ2Vuc29yaW5nLCBMb3ctRGltZW5zaW9uYWwpIGRhdGFzZXRzLgoKYGBge3IsIGVjaG8gPSBGQUxTRSxlcnJvcj1GQUxTRSx3YXJuaW5nPUZBTFNFfQp0b1RhYmxlID0gYXMuZGF0YS5mcmFtZShtYXRyaXgoZGF0YSA9IHRvUGxheSRDb25TdGFuW0hDSW5kXSwgbmNvbCA9IGxlbmd0aChkYXRhc2V0TmFtZXNbSENdKSkpCnRvVGFibGUgPSB0b1RhYmxlW2MoNCwxLDIsMyw2LDUpLF0Kcm93bmFtZXModG9UYWJsZSkgPSBjKCJLTSIsIkFGVCIsIkNveC1LUCIsIkNveEVOLUtQIiwiUlNGLUtNIiwiTVRMUiIpCmNvbG5hbWVzKHRvVGFibGUpID0gZGF0YXNldE5hbWVzW0hDXQoKdG9UYWJsZSAgJT4lCmthYmxlKHRvVGFibGUsIGZvcm1hdCA9ICJodG1sIiwgY2FwdGlvbiA9ICJUYWJsZSA4OiBDb25jb3JkYW5jZSByZXN1bHRzIGZvciB0aGUgMTIgKEhpZ2gtQ2Vuc29yaW5nLCBMb3ctRGltZW5zaW9uYWwpIGRhdGFzZXRzLiBIZXJlIHdlIHByZXNlbnQgdGhlIG1lYW4gYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgQ29uY29yZGFuY2UgYWNyb3NzIHRoZSA1IGNyb3NzLXZhbGlkYXRpb24gZm9sZHMuIEJvbGRlZCB2YWx1ZXMgcmVwcmVzZW50IHRoZSBiZXN0IChoaWdoZXN0IENvbmNvcmRhbmNlKSBwZXJmb3JtaW5nIG1vZGVscy4iLGFsaWduID0gYygnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycpKSAlPiUKICAgIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSAic3RyaXBlZCIsIGZ1bGxfd2lkdGggPSBUICkgJT4lCiAgICAgIGNvbHVtbl9zcGVjKGMoMSksYm9sZD1ULHdpZHRoX21pbiA9ICIyLjVjbSIpCmBgYAoKCmBgYHtyLCBlY2hvID0gRkFMU0UsIGVycm9yPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpOYW1lID0gYygpCk4gPSBjKCkKTnVtRmVhdCA9IGMoKQpQZXJjZW5DZW5zID0gYygpCkRDYWwgPSBjKCkKT25lQ2FsMSA9IGMoKQpPbmVDYWwyID0gYygpCk9uZUNhbDMgPSBjKCkKT25lQ2FsNCA9IGMoKQpPbmVDYWw1ID0gYygpCkNvbmNVbmNlbnMgPSBjKCkKQ29uY1VuY2Vuc1NEID0gYygpCkludGVnZXJhdGVkQnJpZXIgPSBjKCkKSW50ZWdyZWF0ZWRCcmllclNEPSBjKCkKTDFNb2QgPSBjKCkKTDFNb2RTRCA9IGMoKQpEYXQ9YygpCm1vZGVsPWMoKQpmb3IoaSBpbiBsaXN0LmZpbGVzKCIuLi9QU1NQL1Jlc3VsdHMvSEQvIikpewogICNmaXJzdFBlcmlvZCA9IGdyZWdleHByKHBhdHRlcm4gPSAnXFwuJyxpKVtbMV1dWzFdCiAgZGF0YXNldCA9IHN1YnN0cihpLDEsNykKICBEYXQgPSBjKERhdCxkYXRhc2V0KQogIHJlcG9ydCA9IHJlYWQuY3N2KHBhc3RlKCIuLi9QU1NQL1Jlc3VsdHMvSEQvIixpLHNlcD0iIikpCiAgTmFtZSA9IGMoTmFtZSx1bm5hbWUoc2FwcGx5KGFzLmNoYXJhY3RlcihyZXBvcnQkTW9kZWwpLCBmdW5jdGlvbih4KSBwYXN0ZShkYXRhc2V0LCI6ICIseCxzZXA9IiIpKSkpCiAgbW9kZWwgPSBjKG1vZGVsLGFzLmNoYXJhY3RlcihyZXBvcnQkTW9kZWwpKQogIE4gPSBjKE4sIHJlcG9ydCROKQogIE51bUZlYXQgPSBjKE51bUZlYXQsIHJlcG9ydCROdW1GZWF0dXJlcykKICBQZXJjZW5DZW5zID0gYyhQZXJjZW5DZW5zLCByZXBvcnQkUGVyY2VudENlbnNvcmVkKQogIERDYWwgPSBjKERDYWwsIHJlcG9ydCREQ2FsaWJyYXRpb25DdW11bGF0aXZlKQogIE9uZUNhbDEgPSBjKE9uZUNhbDEsIHJlcG9ydCRPbmVDYWxpYnJhdGlvbkN1bXVsYXRpdmUxKQogIE9uZUNhbDIgPSBjKE9uZUNhbDIsIHJlcG9ydCRPbmVDYWxpYnJhdGlvbkN1bXVsYXRpdmUyKQogIE9uZUNhbDMgPSBjKE9uZUNhbDMsIHJlcG9ydCRPbmVDYWxpYnJhdGlvbkN1bXVsYXRpdmUzKQogIE9uZUNhbDQgPSBjKE9uZUNhbDQsIHJlcG9ydCRPbmVDYWxpYnJhdGlvbkN1bXVsYXRpdmU0KQogIE9uZUNhbDUgPSBjKE9uZUNhbDUsIHJlcG9ydCRPbmVDYWxpYnJhdGlvbkN1bXVsYXRpdmU1KQogIENvbmNVbmNlbnMgPSBjKENvbmNVbmNlbnMsIHJlcG9ydCRDb25jb3JkYW5jZVVuY2Vuc29yZWRNKQogIENvbmNVbmNlbnNTRCA9IGMoQ29uY1VuY2Vuc1NELCByZXBvcnQkQ29uY29yZGFuY2VVbmNlbnNvcmVkU0QpCiAgSW50ZWdlcmF0ZWRCcmllciA9IGMoSW50ZWdlcmF0ZWRCcmllciwgcmVwb3J0JEludGVncmF0ZWRCcmllck0pCiAgSW50ZWdyZWF0ZWRCcmllclNEPSBjKEludGVncmVhdGVkQnJpZXJTRCwgcmVwb3J0JEludGVncmF0ZWRCcmllclNEKQogIEwxTW9kID0gYyhMMU1vZCwgcmVwb3J0JEwxTWFyZ2luTm9Mb2dNKQogIEwxTW9kU0QgPSBjKEwxTW9kU0QsIHJlcG9ydCRMMU1hcmdpbk5vTG9nU0QpCn0KQ29uY1VuY2Vuc0NvbWJvID0gcGFzdGUocm91bmQoQ29uY1VuY2VucywzKSwiICgiLHJvdW5kKENvbmNVbmNlbnNTRCwzKSwgIikiLCBzZXA9IiIpCkludGVncmF0ZWRCcmllckNvbWJvID0gcGFzdGUocm91bmQoSW50ZWdlcmF0ZWRCcmllciw0KSwiICgiLHJvdW5kKEludGVncmVhdGVkQnJpZXJTRCwzKSwgIikiLCBzZXA9IiIpCkwxQ29tYm8gPSBwYXN0ZShyb3VuZChMMU1vZCwyKSwiICgiLHJvdW5kKEwxTW9kU0QsMiksICIpIiwgc2VwPSIiKQp0YWIgPSBtYXRyaXgoYyhOYW1lLE4sTnVtRmVhdCxyb3VuZChQZXJjZW5DZW5zKjEwMCwyKSwgcGFzdGUocm91bmQoRENhbCwzKSkscGFzdGUocm91bmQoT25lQ2FsMSwzKSkscGFzdGUocm91bmQoT25lQ2FsMiwzKSksCiAgICAgICAgICAgICAgIHBhc3RlKHJvdW5kKE9uZUNhbDMsMykpLHBhc3RlKHJvdW5kKE9uZUNhbDQsMykpLHBhc3RlKHJvdW5kKE9uZUNhbDUsMykpLENvbmNVbmNlbnNDb21ibywKICAgICAgICAgICAgICAgSW50ZWdyYXRlZEJyaWVyQ29tYm8sTDFDb21ibyksbGVuZ3RoKE5hbWUpLDEzLAogICAgICAgICAgICAgZGltbmFtZXMgPSBsaXN0KE5VTEwsYygiTmFtZSIsICJOIiwiTnVtRmVhdCIsICJQQ2VucyIsIkRDYWwiLCJPQ2FsMSIsIk9DYWwyIiwiT0NhbDMiLCJPQ2FsNCIsIk9DYWw1IiwgIkNvblN0YW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSUJTIiwgIkwxIikpKQoKZGF0MiA9IGRhdGEuZnJhbWUodGFiKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpkYXRhc2V0TmFtZXMgPSBjKCkKZm9yKGkgaW4gbGlzdC5maWxlcygiLi4vUFNTUC9SZXN1bHRzL0hELyIpKXsKICAgZmlyc3RQZXJpb2QgPSBncmVnZXhwcihwYXR0ZXJuID0gJ1xcLicsaSlbWzFdXVsxXQogICBkYXRhc2V0TmFtZXMgPSBjKGRhdGFzZXROYW1lcywgc3Vic3RyKGksMSxmaXJzdFBlcmlvZC0xKSkKfQoKYWxnTmFtZXMgPSBjKCJBRlQiLCJDb3hFTi1LUCIsIktNIiwiTVRMUiIsIlJTRi1LTSIpCgp0b1BsYXkgPSBkYXQyCgpDZW5zID0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIodW5pcXVlKHRvUGxheSRQQ2VucylbIWlzLm5hKHVuaXF1ZSh0b1BsYXkkUENlbnMpKV0pKQpOcyAgPSBhcy5udW1lcmljKGFzLmNoYXJhY3Rlcih0b1BsYXkkTltzZXEoMSxucm93KHRvUGxheSksYnkgID0gNildKSkKRmVhdHVyZXNTZWxlY3RlZCAgPSBhcy5udW1lcmljKGFzLmNoYXJhY3Rlcih0b1BsYXkkTnVtRmVhdFtzZXEoMSxucm93KHRvUGxheSksYnkgID0gNildKSkKCkhDID0gQ2VucyA+PTcwCgpDZW5zSEMgPSBDZW5zW0hDXQpOc0hDID0gTnNbSENdCkZlYXR1cmVzU2VsZWN0ZWRIQyA9IEZlYXR1cmVzU2VsZWN0ZWRbSENdCgpDZW5zTEMgPSBDZW5zWyFIQ10KTnNMQyA9IE5zWyFIQ10KRmVhdHVyZXNTZWxlY3RlZExDID0gRmVhdHVyZXNTZWxlY3RlZFshSENdCgpoZWFkZXJIQyA9IGFzLmRhdGEuZnJhbWUobWF0cml4KGMoTnNIQyxDZW5zSEMsRmVhdHVyZXNTZWxlY3RlZEhDKSxuY29sID0gc3VtKEhDKSwgYnlyb3c9VCkpCiNoZWFkZXJIQyA9IHJvdW5kKGhlYWRlckhDKQpuYW1lcyhoZWFkZXJIQykgPSBkYXRhc2V0TmFtZXNbSENdCnJvdy5uYW1lcyhoZWFkZXJIQykgPSBjKCJOIiwiJSBDZW5zb3JlZCIsIk51bWJlciBvZiBGZWF0dXJlcyIpCmhlYWRlckhDWzEsXSA9IGZvcm1hdEMoaGVhZGVySENbMSxdLCBmb3JtYXQgPSAiZCIpCgpgYGAKCjxociBzdHlsZT0iaGVpZ2h0OjNweDtib3JkZXI6bm9uZTtjb2xvcjojMzMzO2JhY2tncm91bmQtY29sb3I6IzMzMzsiIC8+CgoKI0xvdy1DZW5zb3JpbmcsIEhpZ2gtRGltZW5zaW9uYWwKCkhlcmUgd2UgZXhhbWluZSBhIG51bWJlciBvZiAoTG93LUNlbnNvcmluZywgSGlnaC1EaW1lbnNpb25hbCkgZGF0YXNldHMgd2hpY2ggY29udGFpbiBnZW5lLWV4cHJlc3Npb24gZGF0YSByZWxhdGluZyB0aGUgc3Vydml2YWwgb2YgY2FuY2VyIHBhdGllbnRzIC0tIHNlZSAiQSBNdWx0aS1UYXNrIExlYXJuaW5nIEZvcm11bGF0aW9uIGZvciBTdXJ2aXZhbCBBbmFseXNpcyIgYnkgTGkgZXQgYWwuIGZvciBkZXRhaWxzIHJlZ2FyZGluZyBkYXRhc2V0IGFjY2Vzcy4gU3BlY2lmaWNhbGx5IHdlIHVzZSAoMSkgdGhlIE5vcndheS9TdGFuZm9yZCBicmVhc3QgY2FuY2VyIGRhdGEgKE5CU0NEKSB3aGljaCBjb250YWlucyB0aGUgZ2VuZS1leHByZXNzaW9uIGRhdGEgZm9yIDExNSBmZW1hbGUgYnJlYXN0IGNhbmNlciBwYXRpZW50cywgKDIpIHRoZSBWYW4gZGUgVmlqdmVyJ3MgbWljcm9hcnJheSBicmVhc3QgY2FuY2VyIGRhdGEgKFZEVikgd2hpY2ggYWdhaW4gY29udGFpbnMgZ2VuZS1leHByZXNzaW9uIGRhdGEgZm9yIDc4IGJyZWFzdCBjYW5jZXIgcGF0aWVudHMsICgzKSBnZW5lLWV4cHJlc3Npb24gZGF0YSBmb3IgYWR1bHQgbXllbG9pZCBsZXVrZW1pYSAoQU1MKSBvbiAxMTYgcGF0aWVudHMsIGFuZCAoNCkgZ2VuZS1leHByZXNzaW9uIGRhdGEgZm9yIDkyIG1hbnRsZSBjZWxsIGx5bXBob21hIChNQ0wpIHBhdGllbnRzLiBUYWJsZSA5IGdpdmVzIHRoZSBzdW1tYXJ5IHN0YXRpc3RpY3MgZm9yIGVhY2ggb2YgdGhlc2UgNCBkYXRhc2V0cy4KCmBgYHtyLCBlY2hvPUZBTFNFLCBlcnJvciA9IEZBTFNFLHdhcm5pbmc9RkFMU0V9CmhlYWRlckxDID0gYXMuZGF0YS5mcmFtZShtYXRyaXgoYyhOc0xDLENlbnNMQyxGZWF0dXJlc1NlbGVjdGVkTEMpLG5jb2wgPSBzdW0oIUhDKSwgYnlyb3c9VCkpCiNoZWFkZXJIQyA9IHJvdW5kKGhlYWRlckhDKQpuYW1lcyhoZWFkZXJMQykgPSBkYXRhc2V0TmFtZXNbIUhDXQpyb3cubmFtZXMoaGVhZGVyTEMpID0gYygiTiIsIiUgQ2Vuc29yZWQiLCJOdW1iZXIgb2YgRmVhdHVyZXMiKQpoZWFkZXJMQ1sxLF0gPSBmb3JtYXRDKGhlYWRlckxDWzEsXSwgZm9ybWF0ID0gImQiKQoKa2FibGUoaGVhZGVyTEMsIGZvcm1hdCA9ICJodG1sIiwgY2FwdGlvbiA9ICJUYWJsZSA5OiBTdW1tYXJ5IHN0YXRpc3RpY3MgZm9yIHRoZSA0IChMb3ctQ2Vuc29yaW5nLCBIaWdoLURpbWVuc2lvbmFsKSBkYXRhc2V0cy4gRnJvbSB0b3AgdG8gYm90dG9tIHdlIGhhdmUgKDEpIHRoZSB0b3RhbCBudW1iZXIgb2YgcGF0aWVudHMsICgyKSB0aGUgJSBvZiBjZW5zb3JlZCBwYXRpZW50cywgYW5kICgzKSB0aGUgdG90YWwgbnVtYmVyIG9mIGZlYXR1cmVzIHVzZWQgKGFmdGVyIGZlYXR1cmUgc2VsZWN0aW9uKS4iLGFsaWduID0gYygnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJykpICU+JQogICAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9ICJzdHJpcGVkIiwgZnVsbF93aWR0aCA9IFQgKSAlPiUKICBjb2x1bW5fc3BlYygxLGJvbGQ9VCwgd2lkdGhfbWluID0gIjRjbSIpCmBgYAoKPGhyIHN0eWxlPSJoZWlnaHQ6MXB4O2JvcmRlcjpub25lO2NvbG9yOiMzMzM7YmFja2dyb3VuZC1jb2xvcjojMzMzOyIgLz4KCgojI0NhbGlicmF0aW9uCgpGb3IgY2FsaWJyYXRpb24gb24gKExvdy1DZW5zb3JpbmcsIEhpZ2gtRGltZW5zaW9uYWwpIGRhdGFzZXRzLCBvdXIgZmluZGluZ3Mgd2VyZSB0aGF0IE1UTFIsIENveEVOLUtQLCBhbmQgUlNGLUtNIHdlcmUgYWxsIGVxdWl2YWxlbnQuIFRoZSBELUNhbGlicmF0aW9uIChUYWJsZSAxMCkgcmVzdWx0cyBhcmUgc2hvdyB0aGF0IEFGVCBmYWlscyBELUNhbGlicmF0aW9uIGFjcm9zcyBhbGwgZGF0YXNldHMgKGFuZCBDb3ggZmFpbHMgdG8gZmluaXNoIG9uIHRoZXNlIGRhdGFzZXRzKS4gVGhlIDEtQ2FsaWJyYXRpb24gcmVzdWx0cyAoVGFibGUgMTEpIHNob3cgdGhhdCBNVExSLCBDb3hFTi1LUCBhbmQgUlNGLUtNIGFyZSByb3VnaGx5IGVxdWl2YWxlbnQgYWNyb3NzIHRoZSBkaWZmZXJlbnQgcGVyY2VudGlsZXMgc3VwcG9ydGluZyBvdXIgaW5pdGlhbCBmaW5kaW5nIC0tIE1UTFIsIENveEVOLUtQLCBhbmQgUlNGLUtNIGFyZSBlcXVpdmFsZW50IGZvciBjYWxpYnJhdGlvbiBvbiAoTG93LUNlbnNvcmluZywgSGlnaC1EaW1lbnNpb25hbCkgZGF0YXNldHMuCgpgYGB7ciwgZWNobz1GQUxTRX0KSENJbmQgPSByZXAoSEMsZWFjaCA9IDUpCnRvVGFibGUgPSBhcy5kYXRhLmZyYW1lKG1hdHJpeChkYXRhID0gdG9QbGF5JERDYWxbIUhDSW5kXSwgbmNvbCA9IGxlbmd0aChkYXRhc2V0TmFtZXNbIUhDXSkpKQp0b1RhYmxlID0gYXMuZGF0YS5mcmFtZShhcHBseSh0b1RhYmxlLDIsZnVuY3Rpb24oeCkgYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoeCkpKSkKY29sbmFtZXModG9UYWJsZSkgPSBkYXRhc2V0TmFtZXNbIUhDXQp0b1RhYmxlID0gdG9UYWJsZVtjKDMsMSwyLDUsNCksXQpyb3duYW1lcyh0b1RhYmxlKSA9IGMoIktNIiwiQUZUIiwiQ294RU4tS1AiLCJSU0YtS00iLCJNVExSIikKCnRvVGFibGUkVG90YWwgPSByb3dTdW1zKGFwcGx5KHRvVGFibGUsIDIsIGZ1bmN0aW9uKHgpIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHgpKSkgPj0gMC4wNSkKa2FibGUodG9UYWJsZSwgZGlnaXRzID0gMyxmb3JtYXQgPSAiaHRtbCIsIGNhcHRpb24gPSAiVGFibGUgMTA6IEQtQ2FsaWJyYXRpb24gcmVzdWx0cyBmb3IgdGhlIDQgKExvdy1DZW5zb3JpbmcsIEhpZ2gtRGltZW5zaW9uYWwpIGRhdGFzZXRzLiBUaGUgVG90YWwgY29sdW1uIGdpdmVzIHRoZSB0b3RhbCBudW1iZXIgb2YgZGF0YXNldHMgZm9yIHdoaWNoIGVhY2ggbW9kZWwgd2FzIEQtQ2FsaWJyYXRlZC4gTm90ZSB0aGVyZSBpcyBubyByZXN1bHRzIGZvciBDb3ggYXMgaXQgZmFpbGVkIHRvIHJ1biBmb3IgYWxsIGRhdGFzZXRzLiIsYWxpZ24gPSBjKCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJykpICU+JQogICAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9ICJzdHJpcGVkIiwgZnVsbF93aWR0aCA9IFQpICU+JQogICAgY29sdW1uX3NwZWMoYygxLDYpLGJvbGQ9VCx3aWR0aF9taW4gPSAiMi41Y20iKQoKYGBgCgpgYGB7cixlY2hvID0gRn0Kb25lQ2FsID0gYXMuZGF0YS5mcmFtZShhcHBseSh0b1BsYXlbNjoxMF1bIUhDSW5kLF0sMixmdW5jdGlvbih4KSBhcy5udW1lcmljKGFzLmNoYXJhY3Rlcih4KSkpKQpvbmVDYWwkTW9kZWwgPSByZXAoYWxnTmFtZXMsIGxlbmd0aChkYXRhc2V0TmFtZXNbIUhDXSkpCmxpYnJhcnkoZHBseXIpCnRvVGFibGUgPSBvbmVDYWwgJT4lIGdyb3VwX2J5KE1vZGVsKSAlPiUgc3VtbWFyaXplKE9DMSA9IHN1bShPQ2FsMSA+PTAuMDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9DMiA9IHN1bShPQ2FsMiA+PTAuMDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9DMyA9IHN1bShPQ2FsMyA+PTAuMDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9DNCA9IHN1bShPQ2FsNCA+PTAuMDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9DNSA9IHN1bShPQ2FsNSA+PTAuMDUpKQp0b1RhYmxlID0gYXMuZGF0YS5mcmFtZSh0b1RhYmxlKQp0b1RhYmxlID0gdG9UYWJsZVtjKDEsMiw1LDQpLC0xXQpyb3duYW1lcyh0b1RhYmxlKSA9IGMoIkFGVCIsIkNveEVOLUtQIiwiUlNGLUtNIiwiTVRMUiIpCmNvbG5hbWVzKHRvVGFibGUpID0gYygiMTB0aCIsIjI1dGgiLCAiNTB0aCIsIjc1dGgiLCI5MHRoIikKICAKCmthYmxlKHRvVGFibGUgLCBmb3JtYXQgPSAiaHRtbCIsIGNhcHRpb24gPSAiVGFibGUgMTE6IFRoZSAxLUNhbGlicmF0aW9uIHJlc3VsdHMgZm9yIHRoZSA0IChMb3ctQ2Vuc29yaW5nLCBIaWdoLURpbWVuc2lvbmFsKSBkYXRhc2V0cy4gRWFjaCBjb2x1bW4gcmVwcmVzZW50cyB0aGUgMTB0aCwgMjV0aCwgNTB0aCwgNzV0aCwgYW5kIDkwdGggcGVyY2VudGlsZXMgb2YgZXZlbnQgdGltZXMuIEVhY2ggcm93IHJlcHJlc2VudHMgdGhlIHRvdGFsIG51bWJlciBvZiBkYXRhc2V0cyBmb3Igd2hpY2ggZWFjaCBtb2RlbCB3YXMgMS1DYWxpYnJhdGVkICh0aGUgbWF4aW11bSBiZWluZyA0KS4gTm90ZSB0aGVyZSBhcmUgbm8gcmVzdWx0cyBmb3IgQ294IGFzIGl0IGZhaWxlZCB0byBydW4gb24gYWxsIGRhdGFzZXRzLiIsYWxpZ24gPSBjKCdjJywnYycsJ2MnLCdjJywnYycpKSAlPiUKICAgIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSAic3RyaXBlZCIsIGZ1bGxfd2lkdGggPSBUKSAlPiUKICAgIGNvbHVtbl9zcGVjKGMoMSksYm9sZD1ULHdpZHRoX21pbiA9ICIyLjVjbSIpCgpgYGAKCjxociBzdHlsZT0iaGVpZ2h0OjFweDtib3JkZXI6bm9uZTtjb2xvcjojMzMzO2JhY2tncm91bmQtY29sb3I6IzMzMzsiIC8+CgoKCiMjRGlzY3JpbWluYXRpb24KClRhYmxlIDEyIHByZXNlbnRzIHRoZSBjb25jb3JkYW5jZSByZXN1bHRzIGZvciAoTG93LUNlbnNvcmluZywgSGlnaC1EaW1lbnNpb25hbCkgZGF0YXNldHMuIFRoZSBmaW5kaW5ncyBpbiB0aGUgcGFwZXIgKHRoYXQgTVRMUi9Db3hFTi1LUCBhcmUgc3VwZXJpb3IgdG8gQUZUIGFuZCBSU0YtS00pIGFyZSBnZW5lcmFsbHkgc3VwcG9ydGVkIChhY3R1YWxseSBhbHdheXMgc3VwcG9ydGVkIGZvciBiZWluZyBiZXR0ZXIgdGhhbiBBRlQpLiBFeGNlcHQgZm9yIFZEViBDb3hFTi1LUCBkb2VzIGJldHRlciB0aGFuIFJTRi1LTSBhbmQgTVRMUiBlaXRoZXIgbWF0Y2hlcyBvciBwZXJmb3JtcyBiZXR0ZXIgdGhhbiBSU0YtS00gZm9yIGFsbCBkYXRhc2V0cy4KCmBgYHtyLCBlY2hvID0gRkFMU0UsZXJyb3I9RkFMU0Usd2FybmluZz1GQUxTRX0KdG9UYWJsZSA9IGFzLmRhdGEuZnJhbWUobWF0cml4KGRhdGEgPSB0b1BsYXkkQ29uU3RhblshSENJbmRdLCBuY29sID0gbGVuZ3RoKGRhdGFzZXROYW1lc1shSENdKSkpCgp0b1RhYmxlID0gdG9UYWJsZVtjKDMsMSwyLDUsNCksXQpyb3duYW1lcyh0b1RhYmxlKSA9IGMoIktNIiwiQUZUIiwiQ294RU4tS1AiLCJSU0YtS00iLCJNVExSIikKY29sbmFtZXModG9UYWJsZSkgPSBkYXRhc2V0TmFtZXNbIUhDXQoKdG9UYWJsZSAgJT4lCmthYmxlKHRvVGFibGUsIGZvcm1hdCA9ICJodG1sIiwgY2FwdGlvbiA9ICJUYWJsZSAxMjogQ29uY29yZGFuY2UgcmVzdWx0cyBmb3IgdGhlIDQgKExvdy1DZW5zb3JpbmcsIEhpZ2gtRGltZW5zaW9uYWwpIGRhdGFzZXRzLiBIZXJlIHdlIHByZXNlbnQgdGhlIG1lYW4gYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgQ29uY29yZGFuY2UgYWNyb3NzIHRoZSA1IGNyb3NzLXZhbGlkYXRpb24gZm9sZHMuIEJvbGRlZCB2YWx1ZXMgcmVwcmVzZW50IHRoZSBiZXN0IChoaWdoZXN0IENvbmNvcmRhbmNlKSBwZXJmb3JtaW5nIG1vZGVscy4gTm90ZSB0aGVyZSBhcmUgbm8gcmVzdWx0cyBmb3IgQ294IGFzIGl0IGZhaWxlZCB0byBydW4gb24gYWxsIGRhdGFzZXRzLiIsYWxpZ24gPSBjKCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJykpICU+JQogICAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9ICJzdHJpcGVkIiwgZnVsbF93aWR0aCA9IFQgKSAlPiUKICAgICAgY29sdW1uX3NwZWMoYygxKSxib2xkPVQsd2lkdGhfbWluID0gIjIuNWNtIikKCmBgYAoKCjxociBzdHlsZT0iaGVpZ2h0OjNweDtib3JkZXI6bm9uZTtjb2xvcjojMzMzO2JhY2tncm91bmQtY29sb3I6IzMzMzsiIC8+CgojSGlnaC1DZW5zb3JpbmcsIEhpZ2gtRGltZW5zaW9uYWwKCkhlcmUgd2UgZXhhbWluZSAxIGFkZGl0aW9uYWwgKEhpZ2gtQ2Vuc29yaW5nLCBIaWdoLURpbWVuc2lvbmFsKSBkYXRhc2V0LCBuYW1lbHkgZ2VuZS1leHByZXNzaW9uIGRhdGEgZm9yIDg2IGVhcmx5IGx1bmcgYWRlbm9jYXJjaW5vbWEgKEx1bmcpIHBhdGllbnRzLiAtLSBzZWUgIkEgTXVsdGktVGFzayBMZWFybmluZyBGb3JtdWxhdGlvbiBmb3IgU3Vydml2YWwgQW5hbHlzaXMiIGJ5IExpIGV0IGFsLiBmb3IgZGV0YWlscyByZWdhcmRpbmcgZGF0YXNldCBhY2Nlc3MuIFRhYmxlIDEyIGdpdmVzIHRoZSBzdW1tYXJ5IHN0YXRpc3RpY3MgZm9yIHRoaXMgZGF0YXNldC4KCmBgYHtyLCBlY2hvPUZBTFNFLCBlcnJvciA9IEZBTFNFLHdhcm5pbmc9RkFMU0V9CmhlYWRlckhDWzEsXSA9IGZvcm1hdEMoaGVhZGVySENbMSxdLCBmb3JtYXQgPSAiZCIpCm5hbWVzKGhlYWRlckhDKSA9IGRhdGFzZXROYW1lc1tIQ10Kcm93Lm5hbWVzKGhlYWRlckhDKSA9IGMoIk4iLCIlIENlbnNvcmVkIiwiTnVtYmVyIG9mIEZlYXR1cmVzIikKCmthYmxlKGhlYWRlckhDLCBmb3JtYXQgPSAiaHRtbCIsIGNhcHRpb24gPSAiVGFibGUgMTI6IFN1bW1hcnkgc3RhdGlzdGljcyBmb3IgdGhlICAoSGlnaC1DZW5zb3JpbmcsIEhpZ2gtRGltZW5zaW9uYWwpIGRhdGFzZXQuIEZyb20gdG9wIHRvIGJvdHRvbSB3ZSBoYXZlICgxKSB0aGUgdG90YWwgbnVtYmVyIG9mIHBhdGllbnRzLCAoMikgdGhlICUgb2YgY2Vuc29yZWQgcGF0aWVudHMsIGFuZCAoMykgdGhlIHRvdGFsIG51bWJlciBvZiBmZWF0dXJlcyB1c2VkIChhZnRlciBmZWF0dXJlIHNlbGVjdGlvbikuIixhbGlnbiA9IGMoJ2MnLCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycpKSAlPiUKICAgIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSAic3RyaXBlZCIsIGZ1bGxfd2lkdGggPSBUICkgJT4lCiAgY29sdW1uX3NwZWMoMSxib2xkPVQpCmBgYAoKPGhyIHN0eWxlPSJoZWlnaHQ6MXB4O2JvcmRlcjpub25lO2NvbG9yOiMzMzM7YmFja2dyb3VuZC1jb2xvcjojMzMzOyIgLz4KCgojI0NhbGlicmF0aW9uCgoKRm9yIGNhbGlicmF0aW9uIG9uIChIaWdoLUNlbnNvcmluZywgSGlnaC1EaW1lbnNpb25hbCkgZGF0YXNldHMsIG91ciBmaW5kaW5ncyB3ZXJlIHRoYXQgTVRMUiwgQ294RU4tS1AsIGFuZCBSU0YtS00gd2VyZSBhbGwgZXF1aXZhbGVudC4gVGhlIEQtQ2FsaWJyYXRpb24gcmVzdWx0cyAoVGFibGUgMTMpIHNob3cgdGhhdCBBRlQgaXMgdGhlIG9ubHkgbW9kZWwgdG8gZmFpbCBELUNhbGlicmF0aW9uIChub3RlIENveCBmYWlsZWQgdG8gZmluaXNoKS4gU2ltaWxhcmx5LCB0aGUgMS1DYWxpYnJhdGlvbiByZXN1bHRzIChUYWJsZSAxNCkgc2hvdyB0aGF0IE1UTFIsIENveEVOLUtQIGFuZCBSU0YtS00gYXJlIGVxdWl2YWxlbnQgYWNyb3NzIHRoZSBkaWZmZXJlbnQgcGVyY2VudGlsZXMgc3VnZ2VzdGluZyBvdXIgZmluZGluZyBpcyBjb25zaXN0ZW50IGZvciB0aGlzIGRhdGFzZXQgYXMgd2VsbC4KCgpgYGB7ciwgZWNobz1GQUxTRX0KSENJbmQgPSByZXAoSEMsZWFjaCA9IDUpCnRvVGFibGUgPSBhcy5kYXRhLmZyYW1lKG1hdHJpeChkYXRhID0gdG9QbGF5JERDYWxbSENJbmRdLCBuY29sID0gbGVuZ3RoKGRhdGFzZXROYW1lc1tIQ10pKSkKdG9UYWJsZSA9IGFzLmRhdGEuZnJhbWUoYXBwbHkodG9UYWJsZSwyLGZ1bmN0aW9uKHgpIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHgpKSkpCmNvbG5hbWVzKHRvVGFibGUpID0gZGF0YXNldE5hbWVzW0hDXQp0b1RhYmxlID0gdG9UYWJsZVtjKDMsMSwyLDUsNCksMSxkcm9wPUZdCnJvd25hbWVzKHRvVGFibGUpID0gYygiS00iLCJBRlQiLCJDb3hFTi1LUCIsIlJTRi1LTSIsIk1UTFIiKQoKa2FibGUodG9UYWJsZSwgZGlnaXRzID0gMyxmb3JtYXQgPSAiaHRtbCIsIGNhcHRpb24gPSAiVGFibGUgMTM6IEQtQ2FsaWJyYXRpb24gcmVzdWx0cyBmb3IgdGhlIDQgKExvdy1DZW5zb3JpbmcsIEhpZ2gtRGltZW5zaW9uYWwpIGRhdGFzZXRzLiBUaGUgVG90YWwgY29sdW1uIGdpdmVzIHRoZSB0b3RhbCBudW1iZXIgb2YgZGF0YXNldHMgZm9yIHdoaWNoIGVhY2ggbW9kZWwgd2FzIEQtQ2FsaWJyYXRlZC4gTm90ZSB0aGUgQ294IG1vZGVsIGRvZXMgbm90IGFwcGVhciBhcyBpdCBmYWlsZWQgdG8gZmluaXNoIG9uIHRoaXMgZGF0YXNldC4iLGFsaWduID0gYygnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycpKSAlPiUKICAgIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSAic3RyaXBlZCIsIGZ1bGxfd2lkdGggPSBUKSAlPiUKICAgIGNvbHVtbl9zcGVjKGMoMSksYm9sZD1ULHdpZHRoX21pbiA9ICIyLjVjbSIpCgpgYGAKCmBgYHtyLGVjaG8gPSBGfQpvbmVDYWwgPSBhcy5kYXRhLmZyYW1lKGFwcGx5KHRvUGxheVs2OjEwXVtIQ0luZCxdLDIsZnVuY3Rpb24oeCkgYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoeCkpKSkKb25lQ2FsJE1vZGVsID0gcmVwKGFsZ05hbWVzLCBsZW5ndGgoZGF0YXNldE5hbWVzW0hDXSkpCmxpYnJhcnkoZHBseXIpCnRvVGFibGUgPSBvbmVDYWwgJT4lIGdyb3VwX2J5KE1vZGVsKSAlPiUgc3VtbWFyaXplKE9DMSA9IHN1bShPQ2FsMSA+PTAuMDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9DMiA9IHN1bShPQ2FsMiA+PTAuMDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9DMyA9IHN1bShPQ2FsMyA+PTAuMDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9DNCA9IHN1bShPQ2FsNCA+PTAuMDUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9DNSA9IHN1bShPQ2FsNSA+PTAuMDUpKQp0b1RhYmxlID0gYXMuZGF0YS5mcmFtZSh0b1RhYmxlKQp0b1RhYmxlID0gdG9UYWJsZVtjKDMsMSwyLDUsNCksLTFdCnJvd25hbWVzKHRvVGFibGUpID0gYygiS00iLCJBRlQiLCJDb3hFTi1LUCIsIlJTRi1LTSIsIk1UTFIiKQpjb2xuYW1lcyh0b1RhYmxlKSA9IGMoIjEwdGgiLCIyNXRoIiwgIjUwdGgiLCI3NXRoIiwiOTB0aCIpCiAgCgprYWJsZSh0b1RhYmxlICwgZm9ybWF0ID0gImh0bWwiLCBjYXB0aW9uID0gIlRhYmxlIDE0OiBUaGUgMS1DYWxpYnJhdGlvbiByZXN1bHRzIGZvciB0aGUgNCAoTG93LUNlbnNvcmluZywgSGlnaC1EaW1lbnNpb25hbCkgZGF0YXNldHMuIEVhY2ggY29sdW1uIHJlcHJlc2VudHMgdGhlIDEwdGgsIDI1dGgsIDUwdGgsIDc1dGgsIGFuZCA5MHRoIHBlcmNlbnRpbGVzIG9mIGV2ZW50IHRpbWVzLiBFYWNoIHJvdyByZXByZXNlbnRzIHRoZSB0b3RhbCBudW1iZXIgb2YgZGF0YXNldHMgZm9yIHdoaWNoIGVhY2ggbW9kZWwgd2FzIDEtQ2FsaWJyYXRlZCAodGhlIG1heGltdW0gYmVpbmcgNCkuIE5vdGUgdGhlIENveCBtb2RlbCBkb2VzIG5vdCBhcHBlYXIgYXMgaXQgZmFpbGVkIHRvIGZpbmlzaCBvbiB0aGlzIGRhdGFzZXQuIixhbGlnbiA9IGMoJ2MnLCdjJywnYycsJ2MnLCdjJykpICU+JQogICAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9ICJzdHJpcGVkIiwgZnVsbF93aWR0aCA9IFQgKSAlPiUKICAgIGNvbHVtbl9zcGVjKGMoMSksYm9sZD1ULHdpZHRoX21pbiA9ICIyLjVjbSIpCgpgYGAKCjxociBzdHlsZT0iaGVpZ2h0OjFweDtib3JkZXI6bm9uZTtjb2xvcjojMzMzO2JhY2tncm91bmQtY29sb3I6IzMzMzsiIC8+CgoKIyNEaXNjcmltaW5hdGlvbgoKVGFibGUgMTUgcHJlc2VudHMgdGhlIGNvbmNvcmRhbmNlIHJlc3VsdHMgZm9yIHRoZSAoSGlnaC1DZW5zb3JpbmcsIEhpZ2gtRGltZW5zaW9uYWwpIGRhdGFzZXQuIFRoZSBmaW5kaW5ncyBpbiB0aGUgcGFwZXIgKHRoYXQgTVRMUiwgQ294RU4tS1AsIGFuZCBSU0YtS00gYXJlIGVxdWl2YWxlbnQgYW5kIGFsc28gc3VwZXJpb3IgdG8gQUZUKSBhcmUgc3VwcG9ydGVkIChhbHRob3VnaCBSU0YtS00gaGFzIG11Y2ggaGlnaGVyIHZhcmlhbmNlKS4gCgpgYGB7ciwgZWNobyA9IEZBTFNFLGVycm9yPUZBTFNFLHdhcm5pbmc9RkFMU0V9CnRvVGFibGUgPSBhcy5kYXRhLmZyYW1lKG1hdHJpeChkYXRhID0gdG9QbGF5JENvblN0YW5bSENJbmRdLCBuY29sID0gbGVuZ3RoKGRhdGFzZXROYW1lc1tIQ10pKSkKCnRvVGFibGUgPSB0b1RhYmxlW2MoMywxLDIsNSw0KSwxLCBkcm9wPUZdCnJvd25hbWVzKHRvVGFibGUpID0gYygiS00iLCJBRlQiLCJDb3hFTi1LUCIsIlJTRi1LTSIsIk1UTFIiKQpjb2xuYW1lcyh0b1RhYmxlKSA9IGRhdGFzZXROYW1lc1tIQ10KCnRvVGFibGUgICU+JQprYWJsZSh0b1RhYmxlLGZvcm1hdCA9ICJodG1sIiwgY2FwdGlvbiA9ICJUYWJsZSAxNTogQ29uY29yZGFuY2UgcmVzdWx0cyBmb3IgdGhlIDQgKExvdy1DZW5zb3JpbmcsIEhpZ2gtRGltZW5zaW9uYWwpIGRhdGFzZXRzLiBIZXJlIHdlIHByZXNlbnQgdGhlIG1lYW4gYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgQ29uY29yZGFuY2UgYWNyb3NzIHRoZSA1IGNyb3NzLXZhbGlkYXRpb24gZm9sZHMuIEJvbGRlZCB2YWx1ZXMgcmVwcmVzZW50IHRoZSBiZXN0IChoaWdoZXN0IENvbmNvcmRhbmNlKSBwZXJmb3JtaW5nIG1vZGVscy4gTm90ZSB0aGUgQ294IG1vZGVsIGRvZXMgbm90IGFwcGVhciBhcyBpdCBmYWlsZWQgdG8gZmluaXNoIG9uIHRoaXMgZGF0YXNldC4iLGFsaWduID0gYygnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycsJ2MnLCdjJywnYycpKSAlPiUKICAgIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSAic3RyaXBlZCIsIGZ1bGxfd2lkdGggPSBUICkgJT4lCiAgICAgIGNvbHVtbl9zcGVjKGMoMSksYm9sZD1ULHdpZHRoX21pbiA9ICIyLjVjbSIpCgpgYGAK