- surv.cindex.harrell surv.cindex.uno surv.uno_iauc surv.uno_auc.10 surv.graf
-1: 0.5679167 0.6090304 0.6628350 0.4719335 0.3255181
-2: 0.5422131 0.4884603 0.4023684 0.5652588 0.3148992
-3: 0.7604049 0.5740556 0.5941948 0.5235439 0.2855151
-4: 0.6610169 0.5277736 0.5360690 0.5110032 0.2972719
-5: 0.5800073 0.5655076 0.6160743 0.5388393 0.3518505
-6: 0.5427837 0.6975740 0.6494779 0.6400328 0.2035609
- surv.graf.10 surv.rcll surv.dcalib
-1: 0.6161825 6.038909 1.026901e+07
-2: 0.4473104 5.400253 1.050427e+04
-3: 0.2969766 4.953528 2.544116e+01
-4: 0.2365322 4.953830 2.275040e+01
-5: 0.4387165 4.943446 3.370510e+01
-6: 0.4228169 5.434970 4.223742e+02
+ task_id learner_id resampling_id iteration surv.cindex.harrell surv.cindex.uno
+1: BRCA-TCGA Lasso Cox subsampling 1 0.5679167 0.6090304
+2: BRCA-TCGA Lasso Cox subsampling 2 0.5524590 0.4969326
+3: BRCA-TCGA Lasso Cox subsampling 3 0.7502812 0.5682061
+4: BRCA-TCGA Lasso Cox subsampling 4 0.6591337 0.5294816
+5: BRCA-TCGA Lasso Cox subsampling 5 0.5752472 0.5553336
+6: BRCA-TCGA Lasso Cox subsampling 6 0.5427837 0.6975740
+ surv.uno_iauc surv.uno_auc.10 surv.graf surv.graf.10 surv.rcll surv.dcalib
+1: 0.6628350 0.4719335 0.3255181 0.6161825 6.038909 1.026901e+07
+2: 0.4038682 0.5712012 0.4815700 0.6666994 6.893425 3.342804e+08
+3: 0.5882995 0.5235439 0.2796580 0.2926334 4.955110 2.490982e+01
+4: 0.5356461 0.5082385 0.2915395 0.2324248 4.955409 2.222845e+01
+5: 0.6090615 0.5288752 0.3497189 0.4371144 4.943943 3.346780e+01
+6: 0.6494779 0.6400328 0.2035609 0.4228169 5.434970 4.223742e+02
+Hidden columns: task, learner, resampling, prediction
```
We extract and visualize the discrimination and calibration (resampled) performance of our Lasso Cox model using several evaluation metrics:
```{r}
@@ -1704,7 +1844,32 @@ res[, .(surv.cindex.harrell, surv.cindex.uno, surv.uno_iauc, surv.uno_auc.10)] %
labs(title = 'Discrimination Measures') +
theme(axis.text.x = element_blank())
```
-![_Discrimination performance of Lasso Cox on the TCGA-BRCA dataset (expression data of the PAM50 genes and the variables age and ethnicity). Performance metrics used are Harrell's C-index, Uno's C-index, Uno's Integrated AUC and Uno's AUC at 10 years. The dataset was split to training/validation sets 100 times to allow for the quantification of uncertainty in the different performance estimates._](fig/mlr3_discrimination_msrs.png){width=80%}
+```{r, echo=FALSE}
+pdf("mlr3_discrimination_msrs.pdf", width = 6, height = 3)
+res[, .(surv.cindex.harrell, surv.cindex.uno, surv.uno_iauc, surv.uno_auc.10)] %>%
+ tidyr::pivot_longer(cols = tidyselect::everything(),
+ names_to = 'Measure', values_to = 'Value') %>%
+ mutate(Measure = case_when(
+ Measure == 'surv.cindex.harrell' ~ 'Harrell\'s C-index',
+ Measure == 'surv.cindex.uno' ~ 'Uno\'s C-index',
+ Measure == 'surv.uno_iauc' ~ 'Uno\'s Integrated AUC',
+ Measure == 'surv.uno_auc.10' ~ 'Uno\'s AUC (t = 10 years)',
+ )) %>%
+ mutate(Measure = factor(Measure, levels = c(
+ 'Harrell\'s C-index',
+ 'Uno\'s C-index',
+ 'Uno\'s Integrated AUC',
+ 'Uno\'s AUC (t = 10 years)'))) %>%
+ ggplot(aes(x = Measure, y = Value, fill = Measure)) +
+ geom_boxplot() +
+ ylim(c(0.2, 0.8)) +
+ geom_hline(yintercept = 0.5, color = 'red', linetype = 'dashed') +
+ theme_bw(base_size = 14) +
+ labs(title = 'Discrimination Measures') +
+ theme(axis.text.x = element_blank())
+dev.off()
+```
+![_Discrimination performance of Lasso Cox on the TCGA-BRCA dataset (expression data of the PAM50 genes and the variables age and ethnicity). Performance metrics used are Harrell's C-index, Uno's C-index, Uno's Integrated AUC and Uno's AUC at 10 years. The dataset was split to training/validation sets 100 times to allow for the quantification of uncertainty in the different performance estimates._](fig/mlr3_discrimination_msrs.png){width=70%}
```{r, fig.show='hold', out.width='50%'}
# different scales for each measure, so we separate the plots
@@ -1739,6 +1904,39 @@ res[, .(surv.rcll)] %>%
theme_bw(base_size = 14) +
theme(axis.title.x = element_blank())
```
+```{r, echo=FALSE}
+pdf("mlr3_calibration_BS.pdf", width = 6, height = 5)
+set.seed(42)
+# Integrated Brier Score and Brier Score at t = 10 years
+res[, .(surv.graf, surv.graf.10)] %>%
+ tidyr::pivot_longer(cols = tidyselect::everything(),
+ names_to = 'Measure', values_to = 'Value') %>%
+ mutate(Measure = case_when(
+ Measure == 'surv.graf' ~ 'IBS',
+ Measure == 'surv.graf.10' ~ 'BS(t=10)'
+ )) %>%
+ ggplot(aes(x = Measure, y = Value, fill = Measure)) +
+ geom_boxplot(show.legend = FALSE) +
+ geom_jitter(color = 'blue', size = 0.5, alpha = 0.5, show.legend = FALSE) +
+ labs(title = 'Integrated Brier Score vs Brier Score (t = 10 years)') +
+ theme_bw(base_size = 14) +
+ theme(axis.title.x = element_blank())
+dev.off()
+pdf("mlr3_calibration_RCLL.pdf", width = 6, height = 5)
+res[, .(surv.rcll)] %>%
+ tidyr::pivot_longer(cols = tidyselect::everything(),
+ names_to = 'Measure', values_to = 'Value') %>%
+ mutate(Measure = case_when(
+ Measure == 'surv.rcll' ~ 'RCLL'
+ )) %>%
+ ggplot(aes(x = Measure, y = Value)) +
+ geom_boxplot(show.legend = FALSE) +
+ geom_jitter(color = 'blue', size = 0.5, alpha = 0.5, show.legend = FALSE) +
+ labs(title = 'Right-censored Log Loss') +
+ theme_bw(base_size = 14) +
+ theme(axis.title.x = element_blank())
+dev.off()
+```
@@ -1761,20 +1959,21 @@ times = as.vector(unname(fs_res))
tibble::tibble(feat_name = names(fs_res), times = times, freq = times/n)
```
```
-# A tibble: 35 × 3
+# A tibble: 33 × 3
feat_name times freq
1 age 100 1
2 ethnicity 100 1
- 3 UBE2T 53 0.53
- 4 ORC6L 48 0.48
- 5 ANLN 42 0.42
- 6 ERBB2 40 0.4
- 7 GPR160 35 0.35
- 8 FGFR4 33 0.33
- 9 CEP55 32 0.32
-10 UBE2C 30 0.3
-# … with 25 more rows
+ 3 ANLN 43 0.43
+ 4 BLVRA 41 0.41
+ 5 BAG1 37 0.37
+ 6 MIA 34 0.34
+ 7 TYMS 30 0.3
+ 8 KRT5 27 0.27
+ 9 MMP11 27 0.27
+10 BCL2 26 0.26
+# ℹ 23 more rows
+# ℹ Use `print(n = ...)` to see more rows
```
As `age` and `ethnicity` were not penalized, they have non-zero coefficients in all Lasso Cox models and therefore are included in all selected feature sets.
@@ -1802,7 +2001,7 @@ tibble::tibble(jaccard = jac, nogueira = nog, zucknick = zuck)
# A tibble: 1 × 3
jaccard nogueira zucknick
-1 0.439 0.412 0.402
+1 0.474 0.412 0.442
```
From the above values we conclude that the stability of Lasso Cox's feature selection is neither poor nor excellent but somewhere in between.
@@ -1843,102 +2042,104 @@ library("stabm")
sessionInfo()
```
```
-R version 4.2.1 (2022-06-23)
-Platform: x86_64-pc-linux-gnu (64-bit)
-Running under: Ubuntu 20.04.5 LTS
+R version 4.3.1 (2023-06-16)
+Platform: x86_64-apple-darwin20 (64-bit)
+Running under: macOS Monterey 12.7
Matrix products: default
-BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0
-LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.9.0
+BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
+LAPACK: /Library/Frameworks/R.framework/Versions/4.3-x86_64/Resources/lib/libRlapack.dylib; LAPACK version 3.11.0
locale:
- [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
- [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8 LC_PAPER=en_US.UTF-8 LC_NAME=C
- [9] LC_ADDRESS=C LC_TELEPHONE=C LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
+[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
+
+time zone: Europe/Oslo
+tzcode source: internal
attached base packages:
[1] stats4 stats graphics grDevices utils datasets methods base
other attached packages:
- [1] stabm_1.2.1 mlr3extralearners_0.6.1 mlr3proba_0.5.2
- [4] mlr3verse_0.2.7 mlr3_0.14.1 regplot_1.1
- [7] survAUC_1.1-1 rms_6.3-0 SparseM_1.81
-[10] Hmisc_4.7-1 lattice_0.20-45 c060_0.2-9
-[13] peperr_1.4 snowfall_1.84-6.2 snow_0.4-4
-[16] riskRegression_2022.09.23 risksetROC_1.0.4.1 MASS_7.3-57
-[19] BhGLM_1.1.0 GGally_2.1.2 psbcGroup_1.5
-[22] mvtnorm_1.1-3 SuppDists_1.1-9.7 LearnBayes_2.15.1
-[25] SGL_1.3 grpreg_3.4.0 plotmo_3.6.2
-[28] TeachingDemos_2.12 plotrix_3.8-2 Formula_1.2-4
-[31] glmnet_4.1-4 Matrix_1.5-1 M3C_1.20.0
-[34] survminer_0.4.9 ggpubr_0.4.0 survival_3.4-0
-[37] ggplot2_3.4.0 dplyr_1.0.10 DESeq2_1.38.3
-[40] SummarizedExperiment_1.28.0 Biobase_2.58.0 GenomicRanges_1.50.2
-[43] GenomeInfoDb_1.34.6 IRanges_2.32.0 S4Vectors_0.36.1
-[46] BiocGenerics_0.44.0 MatrixGenerics_1.10.0 matrixStats_0.63.0
-[49] TCGAbiolinks_2.25.3
+ [1] stabm_1.2.2 mlr3extralearners_0.7.0 mlr3proba_0.5.2
+ [4] mlr3verse_0.2.8 mlr3_0.16.1 regplot_1.1
+ [7] survAUC_1.2-0 rms_6.7-0 Hmisc_5.1-0
+[10] c060_0.3-0 peperr_1.5 snowfall_1.84-6.2
+[13] snow_0.4-4 riskRegression_2023.03.22 risksetROC_1.0.4.1
+[16] MASS_7.3-60 BhGLM_1.1.0 GGally_2.1.2
+[19] psbcGroup_1.5 mvtnorm_1.2-2 SuppDists_1.1-9.7
+[22] LearnBayes_2.15.1 SGL_1.3 grpreg_3.4.0
+[25] plotmo_3.6.2 TeachingDemos_2.12 plotrix_3.8-2
+[28] Formula_1.2-5 glmnet_4.1-7 Matrix_1.5-4.1
+[31] M3C_1.22.0 survminer_0.4.9 ggpubr_0.6.0
+[34] survival_3.5-5 ggplot2_3.4.2 dplyr_1.1.2
+[37] DESeq2_1.40.2 SummarizedExperiment_1.30.2 Biobase_2.60.0
+[40] GenomicRanges_1.52.0 GenomeInfoDb_1.36.1 IRanges_2.34.1
+[43] S4Vectors_0.38.1 BiocGenerics_0.46.0 MatrixGenerics_1.12.2
+[46] matrixStats_1.0.0 TCGAbiolinks_2.28.3
loaded via a namespace (and not attached):
- [1] rappdirs_0.3.3 vioplot_0.4.0 tidyr_1.2.1
- [4] bit64_4.0.5 knitr_1.40 multcomp_1.4-20
- [7] DelayedArray_0.24.0 data.table_1.14.6 rpart_4.1.19
- [10] KEGGREST_1.38.0 RCurl_1.98-1.9 doParallel_1.0.17
- [13] generics_0.1.3 timereg_2.0.4 tgp_2.4-21
- [16] TH.data_1.1-1 RSQLite_2.2.20 polspline_1.1.20
- [19] proxy_0.4-27 future_1.31.0 bit_4.0.4
- [22] tzdb_0.3.0 xml2_1.3.3 assertthat_0.2.1
- [25] xfun_0.33 hms_1.1.2 evaluate_0.20
- [28] fansi_1.0.3 progress_1.2.2 dbplyr_2.2.1
- [31] km.ci_0.5-6 DBI_1.1.3 geneplotter_1.76.0
- [34] htmlwidgets_1.5.4 reshape_0.8.9 purrr_1.0.1
- [37] ellipsis_0.3.2 mlr3data_0.6.1 RSpectra_0.16-1
- [40] backports_1.4.1 annotate_1.76.0 biomaRt_2.54.0
- [43] deldir_1.0-6 vctrs_0.5.1 quantreg_5.94
- [46] abind_1.4-5 cachem_1.0.6 withr_2.5.0
- [49] mlr3learners_0.5.6 checkmate_2.1.0 prettyunits_1.1.1
- [52] mlr3fselect_0.9.1 param6_0.2.4 cluster_2.1.3
- [55] crayon_1.5.2 pkgconfig_2.0.3 nlme_3.1-157
- [58] mlegp_3.1.9 nnet_7.3-17 rlang_1.0.6
- [61] globals_0.16.2 lifecycle_1.0.3 MatrixModels_0.5-1
- [64] sandwich_3.0-2 downloader_0.4 filelock_1.0.2
- [67] palmerpenguins_0.1.1 BiocFileCache_2.6.0 mets_1.3.1
- [70] doSNOW_1.0.20 KMsurv_0.1-5 carData_3.0-5
- [73] boot_1.3-28 zoo_1.8-11 base64enc_0.1-3
- [76] png_0.1-8 bitops_1.0-7 Biostrings_2.66.0
- [79] blob_1.2.3 shape_1.4.6 paradox_0.11.0
- [82] stringr_1.5.0 parallelly_1.34.0 readr_2.1.3
- [85] jpeg_0.1-9 rstatix_0.7.1 dictionar6_0.1.3
- [88] ggsignif_0.6.4 scales_1.2.1 memoise_2.0.1
- [91] magrittr_2.0.3 plyr_1.8.8 zlibbioc_1.44.0
- [94] compiler_4.2.1 RColorBrewer_1.1-3 clue_0.3-63
- [97] lme4_1.1-31 set6_0.2.5 cli_3.4.1
-[100] XVector_0.38.0 mlr3tuningspaces_0.3.3 mlr3filters_0.7.0
-[103] listenv_0.9.0 htmlTable_2.4.1 tidyselect_1.2.0
-[106] stringi_1.7.12 TCGAbiolinksGUI.data_1.18.0 distr6_1.6.13
-[109] yaml_2.3.5 askpass_1.1 locfit_1.5-9.6
-[112] latticeExtra_0.6-30 survMisc_0.5.6 grid_4.2.1
-[115] maptree_1.4-8 tools_4.2.1 mlr3misc_0.11.0
-[118] mlr3cluster_0.1.6 future.apply_1.10.0 parallel_4.2.1
-[121] matrixcalc_1.0-6 rstudioapi_0.14 uuid_1.1-0
-[124] foreach_1.5.2 foreign_0.8-82 gridExtra_2.3
-[127] prodlim_2019.11.13 Rtsne_0.16 digest_0.6.31
-[130] lava_1.7.0 cmprsk_2.2-11 Rcpp_1.0.10
-[133] car_3.1-1 broom_1.0.1 httr_1.4.4
-[136] AnnotationDbi_1.60.0 mlr3tuning_0.17.2 colorspace_2.0-3
-[139] rvest_1.0.3 XML_3.99-0.13 reticulate_1.26
-[142] umap_0.2.9.0 splines_4.2.1 lgr_0.4.4
-[145] bbotk_0.7.2 sm_2.2-5.7.1 statmod_1.4.37
-[148] mlr3pipelines_0.4.2 xtable_1.8-4 nloptr_2.0.3
-[151] jsonlite_1.8.3 corpcor_1.6.10 clusterCrit_1.2.8
-[154] R6_2.5.1 pillar_1.8.1 htmltools_0.5.3
-[157] minqa_1.2.5 glue_1.6.2 fastmap_1.1.0
-[160] BiocParallel_1.32.5 beanplot_1.3.1 class_7.3-20
-[163] ooplah_0.2.0 codetools_0.2-18 utf8_1.2.2
-[166] tibble_3.1.8 numDeriv_2016.8-1.1 curl_4.3.3
-[169] mlr3viz_0.6.1 openssl_2.0.3 interp_1.1-3
-[172] penalizedSVM_1.1.3 rmarkdown_2.17 munsell_0.5.0
-[175] e1071_1.7-12 GenomeInfoDbData_1.2.9 iterators_1.0.14
-[178] gtable_0.3.1
+ [1] tgp_2.4-21 progress_1.2.2 mlr3hyperband_0.4.5
+ [4] penalized_0.9-52 nnet_7.3-19 Biostrings_2.68.1
+ [7] TH.data_1.1-2 vctrs_0.6.3 digest_0.6.32
+ [10] png_0.1-8 corpcor_1.6.10 shape_1.4.6
+ [13] proxy_0.4-27 parallelly_1.36.0 reshape_0.8.9
+ [16] foreach_1.5.2 withr_2.5.0 param6_0.2.4
+ [19] xfun_0.39 memoise_2.0.1 diptest_0.76-0
+ [22] MatrixModels_0.5-1 zoo_1.8-12 DEoptimR_1.1-1
+ [25] distr6_1.8.0 prettyunits_1.1.1 prabclus_2.3-2
+ [28] KEGGREST_1.40.0 httr_1.4.6 downloader_0.4
+ [31] maptree_1.4-8 rstatix_0.7.2 globals_0.16.2
+ [34] fpc_2.2-10 rstudioapi_0.14 generics_0.1.3
+ [37] base64enc_0.1-3 curl_5.0.1 zlibbioc_1.46.0
+ [40] doSNOW_1.0.20 GenomeInfoDbData_1.2.10 lgr_0.4.4
+ [43] xtable_1.8-4 stringr_1.5.0 doParallel_1.0.17
+ [46] evaluate_0.21 S4Arrays_1.0.4 BiocFileCache_2.8.0
+ [49] hms_1.1.3 colorspace_2.1-0 filelock_1.0.2
+ [52] cmprsk_2.2-11 reticulate_1.30 flexmix_2.3-19
+ [55] magrittr_2.0.3 readr_2.1.4 modeltools_0.2-23
+ [58] lattice_0.21-8 palmerpenguins_0.1.1 future.apply_1.11.0
+ [61] robustbase_0.99-0 SparseM_1.81 XML_3.99-0.14
+ [64] class_7.3-22 pillar_1.9.0 nlme_3.1-162
+ [67] iterators_1.0.14 compiler_4.3.1 RSpectra_0.16-1
+ [70] stringi_1.7.12 paradox_0.11.1 minqa_1.2.5
+ [73] dictionar6_0.1.3 plyr_1.8.8 crayon_1.5.2
+ [76] abind_1.4-5 sm_2.2-5.7.1 locfit_1.5-9.8
+ [79] bit_4.0.5 sandwich_3.0-2 mlr3mbo_0.2.1
+ [82] codetools_0.2-19 multcomp_1.4-25 matrixcalc_1.0-6
+ [85] openssl_2.0.6 e1071_1.7-13 splines_4.3.1
+ [88] Rcpp_1.0.10 quantreg_5.95 dbplyr_2.3.2
+ [91] TCGAbiolinksGUI.data_1.20.0 knitr_1.43 blob_1.2.4
+ [94] utf8_1.2.3 clue_0.3-64 lme4_1.1-34
+ [97] listenv_0.9.0 checkmate_2.2.0 ggsignif_0.6.4
+[100] tibble_3.2.1 mlr3tuningspaces_0.4.0 statmod_1.5.0
+[103] tzdb_0.4.0 pkgconfig_2.0.3 tools_4.3.1
+[106] cachem_1.0.8 RSQLite_2.3.1 rvest_1.0.3
+[109] DBI_1.1.3 numDeriv_2016.8-1.1 mlr3filters_0.7.1
+[112] fastmap_1.1.1 rmarkdown_2.22 scales_1.2.1
+[115] mlegp_3.1.9 grid_4.3.1 mets_1.3.2
+[118] broom_1.0.5 carData_3.0-5 rpart_4.1.19
+[121] yaml_2.3.7 foreign_0.8-84 cli_3.6.1
+[124] purrr_1.0.1 lifecycle_1.0.3 askpass_1.1
+[127] bbotk_0.7.2 lava_1.7.2.1 kernlab_0.9-32
+[130] backports_1.4.1 mlr3tuning_0.19.0 BiocParallel_1.34.2
+[133] gtable_0.3.3 umap_0.2.10.0 parallel_4.3.1
+[136] mlr3cluster_0.1.8 jsonlite_1.8.7 bitops_1.0-7
+[139] bit64_4.0.5 Rtsne_0.16 mlr3learners_0.5.6
+[142] polspline_1.1.23 survMisc_0.5.6 spacefillr_0.3.2
+[145] htmltools_0.5.5 KMsurv_0.1-5 set6_0.2.6
+[148] rappdirs_0.3.3 mlr3pipelines_0.5.0-1 glue_1.6.2
+[151] penalizedSVM_1.1.4 mlr3viz_0.6.1 timereg_2.0.5
+[154] XVector_0.40.0 RCurl_1.98-1.12 mclust_6.0.0
+[157] gridExtra_2.3 boot_1.3-28.1 R6_2.5.1
+[160] tidyr_1.3.0 km.ci_0.5-6 ooplah_0.2.0
+[163] cluster_2.1.4 beanplot_1.3.1 nloptr_2.0.3
+[166] mlr3misc_0.13.0 vioplot_0.4.0 DelayedArray_0.26.3
+[169] tidyselect_1.2.0 htmlTable_2.4.1 xml2_1.3.4
+[172] mlr3fselect_0.11.0 car_3.1-2 AnnotationDbi_1.62.1
+[175] future_1.33.0 munsell_0.5.0 data.table_1.14.8
+[178] htmlwidgets_1.6.2 mlr3data_0.7.0 RColorBrewer_1.1-3
+[181] biomaRt_2.56.1 rlang_1.1.1 uuid_1.1-1
+[184] fansi_1.0.4 prodlim_2023.03.31
```
# References
diff --git a/survomics.html b/survomics.html
index b014ef0..7a21010 100644
--- a/survomics.html
+++ b/survomics.html
@@ -1667,7 +1667,7 @@
Supplemental information for ‘Tutorial on
survival modelling with omics data’
-Last updated: 20 July, 2023
+Last updated: 06 October, 2023
@@ -1717,6 +1717,7 @@ TCGA survival and clinical data
library("grpreg")
library("SGL")
library("psbcGroup")
+library("psbcSpeedUp")
library("GGally")
library("BhGLM")
library("risksetROC")
@@ -1743,7 +1744,7 @@ TCGA survival and clinical data
clin$age = clin$age_at_diagnosis / 365.25
clin$status = clin$vital_status
clin = clin[, c("project", "submitter_id", "status", "time", "gender", "age", "race", "ethnicity")]
-
+# extract patients with positive overall survival time
clin = clin[(clin$time > 0) & (clin$status %in% c("Alive", "Dead")), ]
# frequency table of the patients w.r.t. status, gender and ethnicity
@@ -1768,19 +1769,19 @@ TCGA survival and clinical data
11 Dead male not hispanic or latino 327 0.378
12 Dead male not reported 80 0.0925
# censoring plot by cancer types
+ID = 1:nrow(clin)
clin %>%
- mutate(index=1:n()) %>%
ggplot(
- aes(y = index, x = time, colour = project, shape = factor(status))) +
- geom_segment(aes(x = time, y = index, xend = 0, yend = index)) +
+ aes(y = ID, x = time, colour = project, shape = factor(status))) +
+ geom_segment(aes(x = time, y = ID, xend = 0, yend = ID)) +
geom_point() +
ggtitle("") +
- labs(x="Years", y="Patients") +
- scale_shape_discrete(name = "Status", labels = c("Censored","Dead")) +
+ labs(x = "Years", y = "Patients") +
+ scale_shape_discrete(name = "Status", labels = c("Censored", "Dead")) +
scale_color_discrete(name = "Cancer",
- labels = c("Bladder","Breast","Colon","Liver", "Lung adeno",
- "Pancreatic", "Prostate","Thyroid")) +
- theme(legend.position="top", legend.direction="vertical") +
+ labels = c("Bladder", "Breast", "Colon", "Liver", "Lung adeno",
+ "Pancreatic", "Prostate", "Thyroid")) +
+ theme(legend.position = "top", legend.direction = "vertical") +
guides(color = guide_legend(nrow = 2, byrow = TRUE))
@@ -1814,12 +1815,12 @@
TCGA omics data
dat = TCGAbiolinks::GDCprepare(query = query)
SummarizedExperiment::assays(dat)$unstranded[1:5, 1:2]
-
TCGA-LL-A73Y-01A-11R-A33J-07 TCGA-E2-A1IU-01A-11R-A14D-07
-ENSG00000000003.15 7015 850
-ENSG00000000005.6 16 5
-ENSG00000000419.13 2167 1680
-ENSG00000000457.14 2505 1559
-ENSG00000000460.17 726 402
+
TCGA-A7-A26E-01B-06R-A277-07 TCGA-A2-A0CU-01A-12R-A034-07
+ENSG00000000003.15 691 1429
+ENSG00000000005.6 20 73
+ENSG00000000419.13 335 1674
+ENSG00000000457.14 1292 1018
+ENSG00000000460.17 536 450
It is recommended to use DESeq2 or TMM normalization method for
RNA-seq data before further statistical analysis (Y. Zhao et al.
2021). Here we demonstrate how to use the R/Bioconductor
@@ -1827,17 +1828,17 @@
TCGA omics data
(Love, Huber, and Anders
2014) to normalize the RNA count data.
meta = colData(dat)[, c("project_id", "submitter_id", "age_at_diagnosis", "ethnicity", "gender", "days_to_death", "days_to_last_follow_up", "vital_status", "paper_BRCA_Subtype_PAM50", "treatments")]
-meta$treatments = unlist(lapply(meta$treatments, function(xx){any(xx$treatment_or_therapy == "yes")}))
+meta$treatments = unlist(lapply(meta$treatments, function(xx) {any(xx$treatment_or_therapy == "yes")}))
dds = DESeq2::DESeqDataSetFromMatrix(assays(dat)$unstranded, colData = meta, design = ~ 1)
dds2 = DESeq2::estimateSizeFactors(dds)
-RNA_count = DESeq2::counts(dds2, normalized=TRUE)
+RNA_count = DESeq2::counts(dds2, normalized = TRUE)
RNA_count[1:5, 1:2]
-
TCGA-LL-A73Y-01A-11R-A33J-07 TCGA-E2-A1IU-01A-11R-A14D-07
-ENSG00000000003.15 6034.27168 951.825764
-ENSG00000000005.6 13.76313 5.598975
-ENSG00000000419.13 1864.04373 1881.255628
-ENSG00000000457.14 2154.78982 1745.760431
-ENSG00000000460.17 624.50196 450.157597
+
TCGA-A7-A26E-01B-06R-A277-07 TCGA-A2-A0CU-01A-12R-A034-07
+ENSG00000000003.15 1899.76848 1419.51789
+ENSG00000000005.6 54.98606 72.51561
+ENSG00000000419.13 921.01656 1662.89219
+ENSG00000000457.14 3552.09968 1011.24507
+ENSG00000000460.17 1473.62649 447.01403
To perform survival analysis with both clinical/demographic variables
and omics data, in the following code we extract female breast cancer
patients with their corresponding survival outcomes,
@@ -1849,10 +1850,19 @@
TCGA omics data
clin = clin[order(clin$submitter_id), ]
RNA_count = RNA_count[, rownames(clin)]
-
The R/Bioconductor package TCGAbiolinks cannot
-retrieve any proteomics or metabolomics data. It is always useful to
-look at your data first, in particular the data type and dimensions
-(i.e. numbers of rows and columns for a data frame or matrix).
+
+Bioconductor
+might provide an old package version of TCGAbiolinks
+for Linux machines. Here, we use the version TCGAbiolinks_2.29.6. If you
+encounter some issues when using this tutorial, please check your
+installed TCGAbiolinks version. If necessary, you can
+re-install the package from its GitHub
+repository.
+The package TCGAbiolinks cannot retrieve any
+proteomics or metabolomics data. It is always useful to look at your
+data first, in particular the data type and dimensions (i.e. numbers of
+rows and columns for a data frame or matrix).
+
@@ -1873,12 +1883,12 @@ Nonparametric survival analysis
sfit = survival::survfit(Surv(time, status) ~ 1, data = clin)
# calculate survival probability at 1-, 3- and 5-year time points
-summary(sfit, times=c(1,3,5))
+summary(sfit, times = c(1, 3, 5))
theme_set(theme_bw())
ggsurv = survminer::ggsurvplot(sfit, conf.int = TRUE, risk.table = TRUE,
xlab = "Time since diagnosis (year)",
legend = "none", surv.median.line = "hv")
-ggsurv$plot = ggsurv$plot + annotate("text", x = 20, y = 0.9, label= "+ Censor")
+ggsurv$plot = ggsurv$plot + annotate("text", x = 20, y = 0.9, label = "+ Censor")
ggsurv
@@ -1901,12 +1911,12 @@
Nonparametric survival analysis
sfit2 = survfit(Surv(time, status) ~ treatments, data = clin)
ggsurv = ggsurvplot(sfit2, conf.int = TRUE, risk.table = TRUE,
- xlab = "Time since diagnosis (year)", legend = c(.6,.9),
+ xlab = "Time since diagnosis (year)", legend = c(.6, .9),
legend.labs = c("No", "Yes"), legend.title = "Treatment",
risk.table.y.text.col = TRUE, risk.table.y.text = FALSE)
ggsurv$plot = ggsurv$plot +
- annotate("text", x = 21, y = 1, label= "+ Censor") +
- annotate("text", x = 22, y = .88, label= paste0("Log-rank test:\n", surv_pvalue(sfit2)$pval.txt))
+ annotate("text", x = 21, y = 1, label = "+ Censor") +
+ annotate("text", x = 22, y = .88, label = paste0("Log-rank test:\n", surv_pvalue(sfit2)$pval.txt))
ggsurv
@@ -1961,8 +1971,7 @@
Nonparametric survival analysis
Theta= 0.828
Degrees of freedom for terms= 4
Likelihood ratio test=46.4 on 4.03 df, p=2e-09
-n= 1047, number of events= 149
- (14 observations deleted due to missingness)
+n= 1047, number of events= 149
To check proportional hazards of age, we can add a time-dependent
covariate \(age \times g(t)\), where
\(g(t)\) is a known function e.g. \(g(t) = \log t\). The following code shows
@@ -1989,12 +1998,20 @@
Feature preselection/filtering
suited for high dimensional omics features, it is better to filter the
omics features first. In addition, we perceive that not too many omics
features are relevant to one medical problem. We will demonstrate
-
two different filtering approaches for high-dimensional omics
+three different filtering approaches for high-dimensional omics
data:
+- Knowledge-based filtering
- P-value-based filtering
- Variance-based filtering
+
+
Knowledge filter
+
One can be interested in only some biologically meaningful genes or
+only protein-coding genes in a specific study. For example, the code
+below filters protein-coding genes.
+
filtered_rna = RNA_count[rowData(dat)$gene_type == "protein_coding", ]
+
P-value filter
Before joint analyzing the associations between the thousands of
@@ -2007,12 +2024,12 @@
P-value filter
previously, the code below filters omics features at the statistical
significance level
\(0.2\), i.e.
\(p < 0.2\).
RNA_log2count = log2(RNA_count[1:100, ] + 1)
-pvalues <- rep(NA, nrow(RNA_log2count))
-for(j in 1:nrow(RNA_log2count)) {
+pvalues = rep(NA, nrow(RNA_log2count))
+for (j in 1:nrow(RNA_log2count)) {
fit_cox = coxph(Surv(clin$time, clin$status) ~ RNA_log2count[j, ], data = clin)
pvalues[j] = summary(fit_cox)$coefficients[, "Pr(>|z|)"]
}
-filtered_rna <- RNA_log2count[which(pvalues < 0.2), ]
+filtered_rna = RNA_log2count[which(pvalues < 0.2), ]
Variance filter
@@ -2043,11 +2060,11 @@
Variance filter
performing calculations for variance
printing topN most variable features with statistics...
feature mean var sd
-ENSG00000166509.12 ENSG00000166509.12 6.084336 31.60450 5.621788
-ENSG00000110484.7 ENSG00000110484.7 11.004346 26.22686 5.121216
-ENSG00000153002.12 ENSG00000153002.12 8.222386 25.87780 5.087022
-ENSG00000134184.13 ENSG00000134184.13 5.371158 23.28756 4.825719
-ENSG00000160182.3 ENSG00000160182.3 9.901567 21.48403 4.635087
+ENSG00000166509.12 ENSG00000166509.12 6.086125 31.60384 5.621729
+ENSG00000110484.7 ENSG00000110484.7 11.005136 26.13755 5.112489
+ENSG00000153002.12 ENSG00000153002.12 8.212895 25.89105 5.088325
+ENSG00000134184.13 ENSG00000134184.13 5.371435 23.23511 4.820281
+ENSG00000160182.3 ENSG00000160182.3 9.902195 21.41407 4.627534
features remaining: 607
Another variance-type filter is to remain features with certain
percentage of cumulative variances, which will usually
@@ -2082,25 +2099,13 @@
Unsupervised learning (omics data)
(John et al.
2020) provides the analyses and visualization of all the
three methods.
-
# extract the PAM50 genes of TCGA-BRCA patients
-TCGA_PAM50 = RNA_count[sapply(strsplit(rownames(RNA_count), ".", fixed = TRUE), function(x) x[[1]]) %in% c(
- "ENSG00000077152", "ENSG00000089685", "ENSG00000143228", "ENSG00000094804", "ENSG00000134057",
- "ENSG00000176890", "ENSG00000101057", "ENSG00000138180", "ENSG00000165304", "ENSG00000080986",
- "ENSG00000171848", "ENSG00000175063", "ENSG00000117724", "ENSG00000164611", "ENSG00000174371",
- "ENSG00000091651", "ENSG00000011426", "ENSG00000105173", "ENSG00000117399", "ENSG00000148773",
- "ENSG00000142945", "ENSG00000133627", "ENSG00000136997", "ENSG00000146648", "ENSG00000186081",
- "ENSG00000092621", "ENSG00000062038", "ENSG00000261857", "ENSG00000128422", "ENSG00000054598",
- "ENSG00000104332", "ENSG00000186847", "ENSG00000091831", "ENSG00000141424", "ENSG00000107262",
- "ENSG00000186868", "ENSG00000082175", "ENSG00000171604", "ENSG00000115648", "ENSG00000171791",
- "ENSG00000135679", "ENSG00000171428", "ENSG00000129514", "ENSG00000106605", "ENSG00000099953",
- "ENSG00000173890", "ENSG00000160867", "ENSG00000141738", "ENSG00000151715", "ENSG00000141736"), ]
+# identify indexes of the PAM50 genes in the TCGA-BRCA data
+idx = which(rowData(dat)$gene_name %in%
+ c("UBE2T", "BIRC5", "NUF2", "CDC6", "CCNB1", "TYMS", "MYBL2", "CEP55", "MELK", "NDC80", "RRM2", "UBE2C", "CENPF", "PTTG1", "EXO1", "ORC6", "ANLN", "CCNE1", "CDC20", "MKI67", "KIF2C", "ACTR3B", "MYC", "EGFR", "KRT5", "PHGDH", "CDH3", "MIA", "KRT17", "FOXC1", "SFRP1", "KRT14", "ESR1", "SLC39A6", "BAG1", "MAPT", "PGR", "CXXC5", "MLPH", "BCL2", "MDM2", "NAT1", "FOXA1", "BLVRA", "MMP11", "GPR160", "FGFR4", "GRB7", "TMEM45B", "ERBB2"))
+# extract the PAM50 genes of TCGA-BRCA patients
+TCGA_PAM50 = RNA_count[idx, ]
# use gene symbols instead of Ensembl IDs
-rownames(TCGA_PAM50) =
- c("UBE2T", "BIRC5", "NUF2", "CDC6", "CCNB1", "TYMS", "MYBL2", "CEP55", "MELK", "NDC80", "RRM2",
- "UBE2C", "CENPF", "PTTG1", "EXO1", "ORC6L", "ANLN", "CCNE1", "CDC20", "MKI67", "KIF2C",
- "ACTR3B", "MYC", "EGFR", "KRT5", "PHGDH", "CDH3", "MIA", "KRT17", "FOXC1", "SFRP1", "KRT14",
- "ESR1", "SLC39A6", "BAG1", "MAPT", "PGR", "CXXC5", "MLPH", "BCL2", "MDM2", "NAT1", "FOXA1",
- "BLVRA", "MMP11", "GPR160", "FGFR4", "GRB7", "TMEM45B", "ERBB2")
+rownames(TCGA_PAM50) = rowData(dat)$gene_name[idx]
# log2-transformation of the normalized count data
TCGA_PAM50 = log2(TCGA_PAM50 + 1)
@@ -2163,19 +2168,19 @@ Dimension reduction for Cox models
n= 1047, number of events= 149
coef exp(coef) se(coef) z Pr(>|z|)
-PC1 0.004894 1.004906 0.009689 0.505 0.61348
-PC2 0.038269 1.039010 0.013224 2.894 0.00381 **
+PC1 0.004679 1.004690 0.009675 0.484 0.62862
+PC2 0.038179 1.038918 0.013233 2.885 0.00391 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
exp(coef) exp(-coef) lower .95 upper .95
-PC1 1.005 0.9951 0.986 1.024
-PC2 1.039 0.9625 1.012 1.066
+PC1 1.005 0.9953 0.9858 1.024
+PC2 1.039 0.9625 1.0123 1.066
Concordance= 0.58 (se = 0.028 )
-Likelihood ratio test= 8.62 on 2 df, p=0.01
-Wald test = 8.71 on 2 df, p=0.01
-Score (logrank) test = 8.73 on 2 df, p=0.01
+Likelihood ratio test= 8.54 on 2 df, p=0.01
+Wald test = 8.64 on 2 df, p=0.01
+Score (logrank) test = 8.66 on 2 df, p=0.01
Penalized Cox models
@@ -2217,7 +2222,7 @@
Penalized Cox models
#get ordered list of variables as they appear at smallest lambda
allnames = names(coef(mod)[, ncol(coef(mod))]
[order(coef(mod)[, ncol(coef(mod))], decreasing = TRUE)])
-# assign colors
+# assign colors for positive (pink) and negative (green) coefficients
cols = rep("gray80", length(allnames))
cols[allnames %in% beta.positive] = "seagreen3"
cols[allnames %in% beta.negative] = "hotpink"
@@ -2225,9 +2230,9 @@
Penalized Cox models
# drwa coefficient paths of a Lasso Cox model
plotmo::plot_glmnet(mod, label = TRUE, s = lambda_optimal, col = cols,
xlab = expression(log ~~ lambda), ylab = expression(beta))
-title("Lasso \n\n")
+title("Lasso \n\n")
-
+
Coefficient paths of a Lasso Cox model. The
verticle gray line indicates the optimal \(\lambda\) and its correspondingly selected
features are marked as green (positive coefficient) and red (negative
@@ -2248,7 +2253,7 @@ Penalized Cox models
alpha = seq(0.1, 1, length = 10)
fitEN = list()
set.seed(123)
-for(i in 1:length(alpha)) {
+for (i in 1:length(alpha)) {
fitEN[[i]] = cv.glmnet(x, y, family = "cox", alpha = alpha[i], nfolds = 5, penalty.factor = pf)
}
idx = which.min(sapply(fitEN, function(xx) {xx$cvm[xx$lambda == xx$lambda.min]}))
@@ -2271,7 +2276,7 @@ Penalized Cox models
xlab = expression(log ~~ lambda), ylab = expression(beta))
title("Elastic Net \n\n")
-
+
Coefficient paths of an Elastic Net Cox
model. The verticle gray line indicates the optimal \(\lambda\) and its correspondingly selected
features are marked as green (positive coefficient) and red (negative
@@ -2311,7 +2316,7 @@ Penalized Cox models
xlab = expression(log ~ lambda), ylab = expression(beta))
title("Adative Lasso \n\n")
-
+
Coefficient paths of an adaptive Lasso Cox
model. The verticle gray line indicates the optimal \(\lambda\) and its correspondingly selected
features are marked as green (positive coefficient) and red (negative
@@ -2356,58 +2361,58 @@ Penalized Cox models
cvfit = grpreg::cv.grpsurv(X = x, y = y, group = group, penalty = "grLasso", returnY = TRUE)
round(cvfit$fit$beta[, c(which.min(cvfit$cve), 10, 20)], digits = 4)
0.0143 0.0217 0.0108
-age 0.0219 0.0154 0.0247
-ethnicity -0.0542 -0.0425 -0.0569
-UBE2T 0.0209 0.0000 0.0732
-BIRC5 -0.0035 0.0000 -0.0109
-NUF2 -0.0031 0.0000 -0.0093
-CDC6 0.0155 0.0000 0.0546
-CCNB1 -0.0247 0.0000 -0.0846
-TYMS -0.0028 0.0000 -0.0086
-MYBL2 -0.0147 0.0000 -0.0522
-CEP55 0.0152 0.0000 0.0507
-MELK -0.0001 0.0000 -0.0006
-NDC80 0.0007 0.0000 0.0022
-RRM2 0.0000 0.0000 -0.0100
-UBE2C 0.0000 0.0000 0.0076
-CENPF 0.0000 0.0000 -0.0002
-PTTG1 0.0000 0.0000 0.0052
-EXO1 0.0000 0.0000 -0.0002
-ORC6L 0.0000 0.0000 -0.0464
-ANLN 0.0000 0.0000 -0.0175
-CCNE1 0.0000 0.0000 -0.0155
-CDC20 0.0000 0.0000 -0.0142
-MKI67 0.0000 0.0000 -0.0245
-KIF2C 0.0000 0.0000 -0.0123
-ACTR3B 0.0000 0.0000 0.0043
-MYC 0.0000 0.0000 -0.0137
-EGFR 0.0000 0.0000 0.0319
-KRT5 0.0000 0.0000 -0.0059
-PHGDH 0.0000 0.0000 0.0004
-CDH3 0.0000 0.0000 -0.0265
-MIA 0.0000 0.0000 0.0049
-KRT17 0.0000 0.0000 -0.0088
-FOXC1 0.0000 0.0000 0.0096
-SFRP1 0.0000 0.0000 0.0235
-KRT14 0.0000 0.0000 0.0218
-ESR1 0.0000 0.0000 -0.0158
-SLC39A6 0.0000 0.0000 0.0284
-BAG1 0.0000 0.0000 0.0104
-MAPT 0.0000 0.0000 0.0023
-PGR 0.0000 0.0000 0.0095
-CXXC5 0.0000 0.0000 -0.0182
-MLPH 0.0000 0.0000 -0.0059
-BCL2 0.0000 0.0000 0.0133
-MDM2 0.0000 0.0000 -0.0084
-NAT1 0.0000 0.0000 -0.0008
-FOXA1 0.0000 0.0000 -0.0055
-BLVRA 0.0000 0.0000 0.0053
-MMP11 0.0000 0.0000 -0.0037
-GPR160 0.0000 0.0000 -0.0328
-FGFR4 0.0000 0.0000 -0.0029
-GRB7 0.0000 0.0000 0.0086
-TMEM45B 0.0000 0.0000 -0.0078
-ERBB2 0.0000 0.0000 -0.0194
+age 0.0218 0.0154 0.0247
+ethnicity -0.0542 -0.0425 -0.0570
+ANLN 0.0193 0.0000 0.0713
+FOXC1 -0.0032 0.0000 -0.0104
+CDH3 -0.0028 0.0000 -0.0090
+UBE2T 0.0154 0.0000 0.0571
+NDC80 -0.0239 0.0000 -0.0862
+PGR -0.0027 0.0000 -0.0086
+BIRC5 -0.0133 0.0000 -0.0497
+ORC6 0.0140 0.0000 0.0489
+ESR1 -0.0002 0.0000 -0.0008
+PHGDH 0.0008 0.0000 0.0024
+CDC6 0.0000 0.0000 -0.0094
+MMP11 0.0000 0.0000 0.0074
+MYBL2 0.0000 0.0000 0.0018
+SFRP1 0.0000 0.0000 0.0049
+CCNE1 0.0000 0.0000 0.0000
+BLVRA 0.0000 0.0000 -0.0436
+BAG1 0.0000 0.0000 -0.0163
+MLPH 0.0000 0.0000 -0.0155
+CDC20 0.0000 0.0000 -0.0129
+CENPF 0.0000 0.0000 -0.0245
+KRT17 0.0000 0.0000 -0.0125
+FOXA1 0.0000 0.0000 0.0040
+ACTR3B 0.0000 0.0000 -0.0112
+CCNB1 0.0000 0.0000 0.0302
+MDM2 0.0000 0.0000 -0.0077
+MYC 0.0000 0.0000 0.0002
+CEP55 0.0000 0.0000 -0.0242
+SLC39A6 0.0000 0.0000 0.0053
+ERBB2 0.0000 0.0000 -0.0089
+GRB7 0.0000 0.0000 0.0099
+KIF2C 0.0000 0.0000 0.0219
+NUF2 0.0000 0.0000 0.0210
+EGFR 0.0000 0.0000 -0.0150
+MKI67 0.0000 0.0000 0.0266
+TMEM45B 0.0000 0.0000 0.0100
+FGFR4 0.0000 0.0000 0.0023
+PTTG1 0.0000 0.0000 0.0095
+MELK 0.0000 0.0000 -0.0188
+NAT1 0.0000 0.0000 -0.0052
+CXXC5 0.0000 0.0000 0.0131
+BCL2 0.0000 0.0000 -0.0082
+RRM2 0.0000 0.0000 -0.0003
+GPR160 0.0000 0.0000 -0.0043
+EXO1 0.0000 0.0000 0.0041
+UBE2C 0.0000 0.0000 -0.0052
+TYMS 0.0000 0.0000 -0.0298
+KRT5 0.0000 0.0000 -0.0025
+KRT14 0.0000 0.0000 0.0085
+MAPT 0.0000 0.0000 -0.0071
+MIA 0.0000 0.0000 -0.0180
Sparse group Lasso Cox model is implemented in the R
package SGL
(N. Simon et al.
@@ -2423,24 +2428,24 @@ Penalized Cox models
beta.hat = cvfit$fit$beta[, which.min(cvfit$lldiff)]
names(beta.hat) = paste0("group", as.numeric(group), ".", c(1:2, 1:10, 1:40))
beta.hat
- group1.1 group1.2 group2.1 group2.2 group2.3 group2.4
- 5.68387570 0.00000000 0.50711740 0.00000000 0.00000000 0.21522490
- group2.5 group2.6 group2.7 group2.8 group2.9 group2.10
- 0.00000000 0.00000000 0.00000000 0.34168669 0.00000000 0.00000000
- group3.1 group3.2 group3.3 group3.4 group3.5 group3.6
- 0.00000000 0.25691478 0.00000000 -0.37494726 0.00000000 -2.85110146
- group3.7 group3.8 group3.9 group3.10 group3.11 group3.12
--1.93556994 0.00000000 0.00000000 0.00000000 -1.77805542 0.00000000
- group3.13 group3.14 group3.15 group3.16 group3.17 group3.18
- 0.00000000 1.03819778 0.00000000 0.00000000 0.00000000 0.00000000
- group3.19 group3.20 group3.21 group3.22 group3.23 group3.24
- 0.00000000 0.00000000 0.00000000 0.00000000 -0.34496717 0.00000000
- group3.25 group3.26 group3.27 group3.28 group3.29 group3.30
- 1.01552095 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
- group3.31 group3.32 group3.33 group3.34 group3.35 group3.36
--2.13205587 0.00000000 0.00000000 0.00000000 0.00000000 -0.95048121
- group3.37 group3.38 group3.39 group3.40
--1.86222105 -0.01120573 -0.81157646 -2.14148900
+ group1.1 group1.2 group2.1 group2.2 group2.3 group2.4
+ 5.6584838488 0.0000000000 0.4812006103 0.0000000000 0.0000000000 0.2481830177
+ group2.5 group2.6 group2.7 group2.8 group2.9 group2.10
+ 0.0000000000 -0.0003042126 0.0000000000 0.3317385412 0.0000000000 0.0000000000
+ group3.1 group3.2 group3.3 group3.4 group3.5 group3.6
+ 0.0000000000 0.3037631224 0.0000000000 -0.3782338997 0.0000000000 -2.6805881347
+ group3.7 group3.8 group3.9 group3.10 group3.11 group3.12
+-1.8418523757 0.0000000000 0.0000000000 0.0000000000 -1.7849923007 0.0000000000
+ group3.13 group3.14 group3.15 group3.16 group3.17 group3.18
+ 0.0000000000 1.0290918041 0.0000000000 0.0000000000 0.0000000000 0.0000000000
+ group3.19 group3.20 group3.21 group3.22 group3.23 group3.24
+ 0.0000000000 0.0000000000 0.0000000000 0.0000000000 -0.3679980817 0.0000000000
+ group3.25 group3.26 group3.27 group3.28 group3.29 group3.30
+ 0.9925901529 0.0088469957 0.0000000000 0.0000000000 0.0000000000 0.0000000000
+ group3.31 group3.32 group3.33 group3.34 group3.35 group3.36
+-2.1975942364 0.0000000000 0.0000000000 0.0000000000 0.0000000000 -0.8407228093
+ group3.37 group3.38 group3.39 group3.40
+-1.8217490477 0.0000000000 -0.7323739107 -2.0111900380
Sparse Bayesian Cox models
@@ -2453,28 +2458,27 @@
Sparse Bayesian Cox models
priorPara$groupInd = 1:p
where
\(p\) is the total number of covariates. For
the group Lasso prior, set the hyperparameter
priorPara$groupInd
as a vector of size
\(p\), where each element denotes which group
-each covariate corresponds to. Note that
psbcGroup
-cannot distinguish mandatory (unpenalized) covariates with omics
-features, see
Zucknick, Saadati, and Benner (2015) for an extended Bayesian Lasso
-Cox model.
+each covariate corresponds to.
# Bayesian Cox model with Lasso prior
+
set.seed(123)
survObj = list(t = clin$time, di = clin$status, x = x)
p = ncol(x)
# set hyperparameters.
# For Lasso prior (i.e. 'groupInd'= 1:p), larger ratio r/delta tends to force the posterior betas to be more concentrated at 0
# For group Lasso prior (i.e. 'groupInd' as group indicator for covariates), larger ratio r/delta tends to force stronger grouping effect of covariates
-s = c(sort(survObj$t[survObj$di == 1]), 2 * max(survObj$t) - max(survObj$t[-which(survObj$t==max(survObj$t))]))
-priorPara = list('eta0' = 1, 'kappa0' = 1, 'c0'= 2, 'r' = 0.5,
- 'delta' = 0.0001, 's'= s, 'J'=length(s), 'groupInd'= 1:p)
+s = c(sort(survObj$t[survObj$di == 1]), 2 * max(survObj$t) - max(survObj$t[-which(survObj$t == max(survObj$t))]))
+priorPara = list('eta0' = 1, 'kappa0' = 1, 'c0' = 2, 'r' = 0.5,
+ 'delta' = 0.0001, 's' = s, 'J' = length(s), 'groupInd' = 1:p)
# set MCMC parameters
-mcmcPara = list('numBeta'= p, 'beta.prop.var'= 1)
+mcmcPara = list('numBeta' = p, 'beta.prop.var' = 1)
# set initial values of hyperparameters
lambdaSq = 1
-initial = list('beta.ini'= rep(0, p), 'lambdaSq' = 1, 'sigmaSq' = runif(1, 0.1, 10),
+initial = list('beta.ini' = rep(0, p), 'lambdaSq' = 1, 'sigmaSq' = runif(1, 0.1, 10),
'tauSq' = rexp(length(unique(priorPara$groupInd)), 'rate' = lambdaSq / 2),
'h' = rgamma(priorPara$J, 1, 1))
# in real applications, 'num.reps' should be large enough (e.g. 20000, 40000) and 'chain' to be > 1
+# argument 'rw' should be FALSE for high-dimensional covariates
BayesLassofit = psbcGroup::psbcGL(survObj, priorPara, initial, rw = TRUE, mcmcPara, num.reps = 100, thin = 1, chain = 1)
# burn-in the first half MCMC iterations
beta_p = BayesLassofit$beta.p[-(1:51), ]
@@ -2484,9 +2488,9 @@ Sparse Bayesian Cox models
tbl = data.frame(term = colnames(x), estimate = beta_mean, conf.low = beta_L, conf.high = beta_U)
tbl$term = factor(tbl$term, levels = tbl$term)
-GGally::ggcoef(tbl) + xlab(expression(Posterior~~beta)) + ylab("")
+GGally::ggcoef(tbl) + xlab(expression(Posterior ~~ beta)) + ylab("")
-
+
Estimates of regression coefficients by a
penalized semiparametric Bayesian Cox model with Lasso prior. Solid dots
indicate the posterior mean over MCMC iterations (excluding burn-in
@@ -2494,6 +2498,31 @@ Sparse Bayesian Cox models
intervals.
+
Note that psbcGroup cannot distinguish mandatory
+(unpenalized) covariates with omics features, see Zucknick, Saadati, and Benner (2015) for an extended Bayesian Lasso
+Cox model. The following code implements the Bayesian Lasso Cox model
+with mandatory covariates through the R
package psbcSpeedUp
+(Z. Zhao et al.
+2023).
+
# Bayesian Cox model with Lasso prior and mandatory covariates
+set.seed(123)
+survObjM = list(t = clin$time, di = clin$status, x = x[, c(3:52, 1:2)])
+priorPara = list('eta0' = 1, 'kappa0' = 1, 'c0' = 2, 'r' = 0.5, 'delta' = 0.0001)
+BayesLassoMfit <- psbcSpeedUp::psbcSpeedUp(survObjM, p = 50, q = 2, hyperpar = priorPara,
+ nIter = 100, burnin = 50, thin = 1, rw = FALSE, outFilePath = "tmp")
+plot(BayesLassoMfit)
+
Running MCMC iterations ...
+[##################################################] 100%
+DONE, exiting!
+
+
+
Estimates of regression coefficients by a
+penalized semiparametric Bayesian Cox model with Lasso prior and
+unpenalized covariates. Solid dots indicate the posterior mean over MCMC
+iterations (excluding burn-in period), and horizontal lines show the
+corresponding 95% credibility intervals.
+
+
In the R
package psbcGroup
(Lee, Chakraborty, and Sun
2021), function psbcEN()
implements Bayesian Cox
@@ -2505,26 +2534,21 @@
Sparse Bayesian Cox models
# set hyperparameters
# Larger ratio r1/delta1 forces the posterior betas to be more concentrated at 0
# Larger ratio r2/delta2 forces stronger grouping effect of covariates
-priorPara = list('eta0' = 1, 'kappa0' = 1, 'c0'= 2, 'r1' = 0.1, 'r2' = 1,
- 'delta1' = 0.1, 'delta2' = 1, 's'= s, 'J' = length(s))
+priorPara = list('eta0' = 1, 'kappa0' = 1, 'c0' = 2, 'r1' = 0.1, 'r2' = 1,
+ 'delta1' = 0.1, 'delta2' = 1, 's' = s, 'J' = length(s))
# set MCMC parameters
-mcmcPara = list('numBeta'= p, 'beta.prop.var'= 1)
+mcmcPara = list('numBeta' = p, 'beta.prop.var' = 1)
# set initial values of hyperparameters
-initial = list('beta.ini'= rep(0, p), 'lambda1Sq' = 1, 'lambda2' = 1, 'sigmaSq' = runif(1, 0.1, 10),
+initial = list('beta.ini' = rep(0, p), 'lambda1Sq' = 1, 'lambda2' = 1, 'sigmaSq' = runif(1, 0.1, 10),
'tauSq' = rexp(p, rate = 1 / 2), 'h' = rgamma(priorPara$J, 1, 1))
# in real application, 'num.reps' should be large enough (e.g. 20000, 40000) and 'chain' to be > 1
-BayesENfit = psbcEN(survObj, priorPara, initial, rw = TRUE, mcmcPara, num.reps = 100, thin = 1, chain = 1)
+BayesENfit = psbcEN(survObj, priorPara, initial, rw = FALSE, mcmcPara, num.reps = 100, thin = 1, chain = 1)
# burn-in the first half MCMC iterations
EN_beta_p = BayesENfit$beta.p[52:101, ]
-EN_beta_mean = colMeans(EN_beta_p)
-EN_beta_L = apply(EN_beta_p, 2, quantile, 0.025)
-EN_beta_U = apply(EN_beta_p, 2, quantile, 0.975)
-EN_tbl = data.frame(term = colnames(x), estimate = EN_beta_mean, conf.low = EN_beta_L, conf.high = EN_beta_U)
-EN_tbl$term = factor(EN_tbl$term, levels = EN_tbl$term)
-
-GGally::ggcoef(EN_tbl) + xlab(expression(Posterior~~beta)) + ylab("")
+colnames(EN_beta_p) = colnames(x)
+psbcSpeedUp:::plot.psbcSpeedUp(EN_beta_p)
-
+
Estimates of regression coefficients by a
penalized semiparametric Bayesian Cox model with Elastic Net prior.
Solid dots indicate the posterior mean over MCMC iterations (excluding
@@ -2544,7 +2568,7 @@ Sparse Bayesian Cox models
Bayesfit = BhGLM::bcoxph(y_surv ~ ., x_dataframe, prior = mde(0, 0.01, 0.8), control = coxph.control(iter.max = 200))
BhGLM::plot.bh(Bayesfit, col.pts = c("red", "blue"), main = "Cox with mixture double exponential\n")
-
+
Coefficient estimates of a penalized
semiparametric Bayesian Cox model with (double exponential)
spike-and-slab prior. Solid dots denote the posterior mode of the
@@ -2644,15 +2668,15 @@ Discrimination metrics
sfit = survfit(Surv(time, status) ~ group, data = dat_tmp)
ggsurv = ggsurvplot(sfit, conf.int = TRUE, risk.table = TRUE,
- xlab = "Time since diagnosis (year)", legend = c(.2,.3),
+ xlab = "Time since diagnosis (year)", legend = c(.2, .3),
legend.labs = c("Low risk", "High risk"), legend.title = "Dichotomized groups",
risk.table.y.text.col = TRUE, risk.table.y.text = FALSE)
ggsurv$plot = ggsurv$plot +
- annotate("text", x = 2.6, y = .03, label= paste0("Log-rank test:\n", surv_pvalue(sfit)$pval.txt))
+ annotate("text", x = 2.6, y = .03, label = paste0("Log-rank test:\n", surv_pvalue(sfit)$pval.txt))
ggsurv$table = ggsurv$table + labs(y = "Dichotomized\n groups")
ggsurv
-
+
Kaplan-Meier curves of the BRCA patients
data dichotomized by the median of prognostic scores (calculated from
the Lasso Cox model with patients’ survival and mRNA-Seq data) into two
@@ -2664,23 +2688,23 @@ Discrimination metrics
based on quantiles and the log-rank test can be used to compare the
difference of multiple survival curves.
group = pred_lp
-group[pred_lp >= quantile(pred_lp, 2/3)] = 3
-group[pred_lp >= quantile(pred_lp, 1/3) & pred_lp < quantile(pred_lp, 2/3)] = 2
-group[pred_lp < quantile(pred_lp, 1/3)] = 1
+group[pred_lp >= quantile(pred_lp, 2 / 3)] = 3
+group[pred_lp >= quantile(pred_lp, 1 / 3) & pred_lp < quantile(pred_lp, 2 / 3)] = 2
+group[pred_lp < quantile(pred_lp, 1 / 3)] = 1
# draw two survival curves based on KM estimation and compare them by a log-rank test
dat_tmp = data.frame(time = y_validate[, 1], status = y_validate[, 2], group = group)
sfit = survfit(Surv(time, status) ~ group, data = dat_tmp)
ggsurv = ggsurvplot(sfit, conf.int = TRUE, risk.table = TRUE,
- xlab = "Time since diagnosis (year)", legend = c(.2,.3),
+ xlab = "Time since diagnosis (year)", legend = c(.2, .3),
legend.labs = c("Low risk", "Middle risk", "High risk"), legend.title = "Groups",
risk.table.y.text.col = TRUE, risk.table.y.text = FALSE)
ggsurv$plot = ggsurv$plot +
- annotate("text", x = 3.5, y = .05, label= paste0("Log-rank test:\n", surv_pvalue(sfit)$pval.txt))
+ annotate("text", x = 3.5, y = .05, label = paste0("Log-rank test:\n", surv_pvalue(sfit)$pval.txt))
ggsurv
-
+
Kaplan-Meier curves of the BRCA patients
data divided by 33% and 67% quantiles of prognostic scores (calculated
from the Lasso Cox model with patients’ survival and mRNA-Seq data) into
@@ -2698,10 +2722,10 @@ Discrimination metrics
ROC = risksetROC(Stime = y_validate[, 1], status = y_validate[, 2],
marker = pred_lp, predict.time = 5, method = "Cox",
main = "ROC Curve", col = "seagreen3", type = "s",
- lwd = 2, xlab="1 - Specificity", ylab="Sensitivity")
+ lwd = 2, xlab = "1 - Specificity", ylab = "Sensitivity")
text(0.7, 0.2, paste("AUC =", round(ROC$AUC, 3)))
-
+
ROC curve estimated at 5-years survival
evaluation time point for the 20% TCGA validation data and based on a
Lasso Cox model learned from the 80% training data. The AUC value is the
@@ -2750,9 +2774,9 @@ Discrimination metrics
times = c(utimes_train, utimes_validate),
group = c(rep("AUC_train", length(AUC_train)), rep("AUC_validate", length(AUC_validate))))
ggplot(dat_AUC, aes(times, tAUC, group = group, color = group)) + xlab("Evaluation time points (year)") + ylab("AUC") + ylim(0.5, 1) +
- geom_step(direction = "vh") + theme(legend.position = c(0.7, 0.8), legend.title=element_blank())
+ geom_step(direction = "vh") + theme(legend.position = c(0.7, 0.8), legend.title = element_blank())
-
+
Time-dependent AUC based on a Lasso Cox
model applied to the BRCA patients data from TCGA. The red line shows
the Time-dependent AUC calculated from the 80% training data, and the
@@ -2771,10 +2795,10 @@ Discrimination metrics
## integrated AUC (e.g. over tmax=10 years) to get concordance measure based on training data
(iAUC_train = risksetROC::IntegrateAUC(AUC_train, utimes_train, surv_prob_train, tmax = 10))
-[1] 0.6281301
+[1] 0.6279646
## integrated AUC (e.g. over tmax=10 years) to get concordance measure based on validation data
-(iAUC_validate = risksetROC::IntegrateAUC( AUC_validate, utimes_validate, surv_prob_validate, tmax = 10))
-[1] 0.6318857
+(iAUC_validate = risksetROC::IntegrateAUC(AUC_validate, utimes_validate, surv_prob_validate, tmax = 10))
+[1] 0.6318253
Time-dependent C-index
The C-index is not proper for \(t\)-year predictions, see Blanche, Kattan, and Gerds (2019). Consider using time-dependent
AUC or time-dependent Brier score instead. For a time-dependent
@@ -2788,13 +2812,13 @@
Discrimination metrics
model below.
set.seed(123)
cvfit = cv.glmnet(x_train, y_train, family = "cox", nfolds = 5, penalty.factor = pf)
-pred = predict(cvfit, newx = x_validate, type = "response", s = cvfit$lambda.min)
+pred = predict(cvfit, newx = x_validate, type = "link", s = cvfit$lambda.min)
# Harrell's C-index
-(Cindex_Harrell = mean(apply(pred, 2, Cindex, y = y_validate)))
-[1] 0.7320221
+(Cindex_Harrell = Cindex(pred = pred[, 1], y = y_validate))
+[1] 0.7246466
# Uno's C-index
(Cindex_Uno = survAUC::UnoC(y_train, y_validate, pred))
-[1] 0.5786861
+[1] 0.5772041
@@ -2820,29 +2844,29 @@
Overall metrics
# use the (x_train, y_train) 80% samples for training
# and the (x_validate, y_validate) 20% samples for testing
-y_train_surv = Surv(y_train[,"time"], y_train[,"status"])
-y_validate_surv = Surv(y_validate[,"time"], y_validate[,"status"])
+y_train_surv = Surv(y_train[, "time"], y_train[, "status"])
+y_validate_surv = Surv(y_validate[, "time"], y_validate[, "status"])
set.seed(123)
cvfit = cv.glmnet(x_train, y_train_surv, family = "cox", nfolds = 5, penalty.factor = pf)
lp_train = predict(cvfit, newx = x_train, s = cvfit$lambda.min, type = "link")
lp_validate = predict(cvfit, newx = x_validate, s = cvfit$lambda.min, type = "link")
# prepare data format suited for function Score() from the riskRegression package
-data_train = data.frame(time = y_train[,"time"], status = y_train[,"status"], lp = as.vector(lp_train))
-data_validate = data.frame(time = y_validate[,"time"], status = y_validate[,"status"], lp = as.vector(lp_validate))
-lasso_train = coxph(Surv(time,status) ~ lp, data = data_train, y=TRUE, x = TRUE)
-lasso_validate = coxph(Surv(time,status) ~ lp, data = data_validate, y=TRUE, x = TRUE)
+data_train = data.frame(time = y_train[, "time"], status = y_train[, "status"], lp = as.vector(lp_train))
+data_validate = data.frame(time = y_validate[, "time"], status = y_validate[, "status"], lp = as.vector(lp_validate))
+lasso_train = coxph(Surv(time, status) ~ lp, data = data_train, y=TRUE, x = TRUE)
+lasso_validate = coxph(Surv(time, status) ~ lp, data = data_validate, y = TRUE, x = TRUE)
# calculate Brier scores based on both training and validation data
-Brier_train = riskRegression::Score(list("Brier_train" = lasso_train), formula = Surv(time, status) ~ 1, data = data_train, conf.int = FALSE, metrics = "brier", summary="ibs", times = sort(unique(data_train$time)))$Brier$score
-Brier_validate = riskRegression::Score(list("Brier_validate" = lasso_validate), formula = Surv(time, status) ~ 1, data = data_validate, conf.int = FALSE, metrics = "brier", summary="ibs", times = sort(unique(data_validate$time)))$Brier$score
+Brier_train = riskRegression::Score(list("Brier_train" = lasso_train), formula = Surv(time, status) ~ 1, data = data_train, conf.int = FALSE, metrics = "brier", summary = "ibs", times = sort(unique(data_train$time)))$Brier$score
+Brier_validate = riskRegression::Score(list("Brier_validate" = lasso_validate), formula = Surv(time, status) ~ 1, data = data_validate, conf.int = FALSE, metrics = "brier", summary = "ibs", times = sort(unique(data_validate$time)))$Brier$score
Brier_score = rbind(Brier_train, Brier_validate)
Brier_score = Brier_score[Brier_score$model != "Null model", ]
ggplot(Brier_score, aes(times, Brier, group = model, color = model)) + xlab("Evaluation time points (year)") + ylab("Brier score") +
- geom_step(direction = "vh") + theme(legend.position = c(0.15, 0.88), legend.title=element_blank())
+ geom_step(direction = "vh") + theme(legend.position = c(0.15, 0.88), legend.title = element_blank())
-
+
Time-dependent Brier score based on a Lasso
Cox model applied to the BRCA patients data from TCGA. The red line
shows the Time-dependent Brier score calculated from the 80% training
@@ -2857,7 +2881,7 @@ Overall metrics
the IBS corresponding to the largest evaluation time point.
Brier_validate_ibs = Brier_validate[Brier_validate$model == "Brier_validate", ]
Brier_validate_ibs$IBS[which.max(Brier_validate_ibs$times)]
-[1] 0.1711617
+[1] 0.1721158
@@ -2903,9 +2927,9 @@
Uncertainty Quantification
set.seed(123)
ggplot(dat_tmp, aes(x, y)) + geom_boxplot() + ylim(0.5, 1) + xlab("") + ylab("Integrated AUC") +
- geom_jitter(color="blue", size = 0.5, alpha = 0.5)
+ geom_jitter(color = "blue", size = 0.5, alpha = 0.5)
-
+
Integrated AUC based on randomly split
validation data 100 times. The blue dots are the 100 values of
integrated AUC.
@@ -2933,9 +2957,9 @@
Uncertainty Quantification
set.seed(123)
ggplot(dat_tmp, aes(x, y, col = x)) + geom_boxplot() + geom_jitter(size = 0.5, alpha = 0.5) +
- ylim(0, 1) + xlab("") + ylab("C-index") + theme(legend.position="none")
+ ylim(0, 1) + xlab("") + ylab("C-index") + theme(legend.position = "none")
-
+
C-index (Harrell’s and Uno’s) based on
randomly split validation data 100 times.
@@ -2961,10 +2985,10 @@
Uncertainty Quantification
args.fit = list(family = "cox", penalty.factor = pf),
complexity = complexity.glmnet,
args.complexity = list(family = "cox", nfolds = 5, penalty.factor = pf),
- indices = resample.indices(n = n, method="sub632", sample.n = 100))
+ indices = resample.indices(n = n, method = "sub632", sample.n = 100))
c060::Plot.peperr.curves(peperr_object)
-
+
Resampling-based prediction error curves
(time-dependent Brier score) a the Lasso Cox model applied to the BRCA
data set from TCGA. The gray area indicates the pointwise 2.5% and 97.5%
@@ -2999,9 +3023,15 @@ Feature stability analysis
}
(stable_features = colnames(x)[rowSums(beta_all != 0) >= 2])
- [1] "age" "ethnicity" "UBE2T" "CDC6" "CCNB1" "TYMS" "CEP55" "MELK" "NDC80" "UBE2C" "PTTG1" "EXO1" "ORC6L" "ANLN" "CCNE1" "KIF2C" "ACTR3B" "MYC" "EGFR" "KRT5" "PHGDH" "CDH3" "MIA" "FOXC1" "KRT14" "ESR1" "SLC39A6" "BAG1" "MAPT" "CXXC5" "MLPH" "BCL2" "MDM2" "FOXA1" "GPR160" "FGFR4" "TMEM45B" "ERBB2"
+ [1] "age" "ethnicity" "ANLN" "UBE2T" "NDC80" "PGR" "ORC6"
+ [8] "ESR1" "PHGDH" "MMP11" "SFRP1" "CCNE1" "BLVRA" "BAG1"
+[15] "MLPH" "CENPF" "KRT17" "FOXA1" "ACTR3B" "CCNB1" "MDM2"
+[22] "MYC" "CEP55" "SLC39A6" "GRB7" "NUF2" "EGFR" "MKI67"
+[29] "TMEM45B" "FGFR4" "MELK" "NAT1" "CXXC5" "BCL2" "GPR160"
+[36] "TYMS" "KRT5" "MAPT" "MIA"
(stable_features = colnames(x)[rowSums(beta_all != 0) >= 5])
- [1] "age" "ethnicity" "UBE2T" "CEP55" "UBE2C" "ORC6L" "ANLN" "ESR1" "BAG1" "MLPH" "MDM2" "GPR160" "FGFR4" "ERBB2"
+ [1] "age" "ethnicity" "ANLN" "ORC6" "MMP11" "BLVRA" "BAG1"
+ [8] "CCNB1" "EGFR" "TMEM45B" "BCL2" "TYMS" "KRT5" "MIA"
Alternatively for a Bayesian Cox model, its median probability model
(MPM) can be obtained based on the coefficient estimates over MCMC
iterations. The following code shows how to obtain the MPM’s
@@ -3011,15 +3041,24 @@
Feature stability analysis
beta_MPM = (gammas >= 0.5) * colMeans(EN_beta_p) / gammas
beta_MPM[is.na(beta_MPM)] = 0
beta_MPM
- [1] 0.0000000000 -0.0172015280 0.0304316616 -0.0114623308 0.0837824132 -0.0547983327
- [7] 0.1407439126 -0.0562438350 0.0233413258 0.0822548966 -0.0216956009 -0.0046531991
-[13] 0.0000000000 -0.0102432707 -0.0462764281 -0.0261233503 0.1204452692 0.0498380632
-[19] 0.0000000000 0.0000000000 0.0411354271 0.0008250959 -0.0747121328 0.3709996035
-[25] -0.0714123785 0.0531884491 -0.0263379552 -0.0278157511 0.0868213917 -0.0417584334
-[31] -0.0154609980 -1.7597763992 0.0248018172 0.1583448784 0.0000000000 -0.0270275080
-[37] 0.0316279851 0.1896061075 0.0359063687 -0.1373224621 -0.1648833174 0.0346494611
-[43] 0.1168334315 0.0224791857 0.1336344881 -0.0047435108 0.0187484228 0.1178996364
-[49] -0.1696531126 0.0573713694 -0.0308897787 -0.2130819387
+ age ethnicity ANLN FOXC1 CDH3 UBE2T
+ 1.305162e-02 5.348458e-03 -1.299443e-03 -1.857811e-02 -6.123574e-03 -5.467111e-03
+ NDC80 PGR BIRC5 ORC6 ESR1 PHGDH
+-6.652927e-03 -2.101243e-06 -1.640386e-02 -1.237153e-02 -1.077863e-02 2.483990e-02
+ CDC6 MMP11 MYBL2 SFRP1 CCNE1 BLVRA
+-9.079708e-03 -1.588726e-02 5.225344e-03 -1.383981e-02 -3.181265e-03 -2.632373e-02
+ BAG1 MLPH CDC20 CENPF KRT17 FOXA1
+-3.913529e-02 -1.435805e-02 -2.027232e-02 -2.476495e-02 -2.871143e-02 -3.017213e-03
+ ACTR3B CCNB1 MDM2 MYC CEP55 SLC39A6
+-2.504869e-03 -1.346817e-03 -2.156041e-02 1.431062e-02 1.421036e-02 -1.150196e-02
+ ERBB2 GRB7 KIF2C NUF2 EGFR MKI67
+-6.347367e-03 -1.008689e-02 6.033792e-03 -2.405689e-03 -1.964927e-02 1.956661e-02
+ TMEM45B FGFR4 PTTG1 MELK NAT1 CXXC5
+ 2.736216e-02 1.842323e-03 -5.651905e-03 2.894074e-02 -2.126163e-02 2.571472e-02
+ BCL2 RRM2 GPR160 EXO1 UBE2C TYMS
+-5.140894e-03 2.881004e-02 -3.927705e-02 -1.710419e-02 -1.343832e-02 -1.884342e-02
+ KRT5 KRT14 MAPT MIA
+-2.180294e-02 -1.386489e-03 -2.587557e-02 -1.033317e-02
@@ -3054,7 +3093,7 @@
Graphical representation
levels(x_stable$ethnicity) = c("Hispanic/latino", "Not hispanic/latino")
data_tmp = data.frame(times = yy[, "time"], status = yy[, "status"], x_stable)
-f = cph(formula = Surv(times, status) ~ age + ethnicity + UBE2T + ORC6L + ESR1,
+f = cph(formula = Surv(times, status) ~ age + ethnicity + ANLN + BLVRA + EGFR,
data = data_tmp, x = TRUE, y = TRUE, surv = TRUE)
ddist = datadist(data_tmp)
oldoption = options(datadist = 'ddist')
@@ -3067,7 +3106,7 @@
Graphical representation
regplot::regplot(f, observation = data_tmp[1,], failtime = c(1, 3, 5), title = "",
prfail = FALSE, points = TRUE, showP = FALSE, subticks = TRUE)
-
+
Nomogram developed to estimate the overall
survival probability for TCGA’s BRAC patients based on demographic and
Lasso Cox selected mRNA features. The red coloured symbols represent one
@@ -3093,27 +3132,25 @@ Graphical representation
data_validate = data_tmp[-train_id, ]
ddist = datadist(data_train)
-options(datadist='ddist')
-f_train = cph(formula = Surv(times, status) ~ age + ethnicity + UBE2T + ORC6L + ESR1,
+options(datadist = 'ddist')
+f_train = cph(formula = Surv(times, status) ~ age + ethnicity + ANLN + BLVRA + EGFR,
data = data_train, x = TRUE, y = TRUE, surv = TRUE, time.inc = 5)
f_validate = update(f_train, data = data_validate)
cal_train = calibrate(f_train, u = 5, cmethod = "KM", m = nrow(data_train) / 4, B = 200)
cal_validate = calibrate(f_validate, u = 5, cmethod = "KM", m = nrow(data_validate) / 4, B = 200)
-pdf("TCGA_surv_calibration.pdf", width=7, height=4)
layout(matrix(1:2, nrow = 1))
plot(cal_train, lwd = 2, lty = 1, errbar.col = "seagreen3",
xlab = 'Predicted survival probability', ylab = 'Actual survival probability',
- xlim = c(0,1), ylim = c(0,1), col = "seagreen3", subtitles = FALSE)
+ xlim = c(0, 1), ylim = c(0, 1), col = "seagreen3", subtitles = FALSE)
title(main = "Calibration on training data")
plot(cal_validate, lwd = 2, lty = 1, errbar.col = "seagreen3",
xlab = 'Predicted survival probability', ylab = 'Actual survival probability',
- xlim = c(0,1), ylim = c(0,1), col = "seagreen3", subtitles = FALSE)
-title(main = "Calibration on validation data")
-dev.off()
+ xlim = c(0, 1), ylim = c(0, 1), col = "seagreen3", subtitles = FALSE)
+title(main = "Calibration on validation data")
-
+
Nomogram model calibration curves for TCGA’s
BRAC patients at 5-year evaluation time-point.
@@ -3177,11 +3214,10 @@ Workflow
* Target: time, status
* Properties: -
* Features (52):
- - dbl (52): ACTR3B, ANLN, BAG1, BCL2, BIRC5, BLVRA, CCNB1, CCNE1,
- CDC20, CDC6, CDH3, CENPF, CEP55, CXXC5, EGFR, ERBB2, ESR1, EXO1,
- FGFR4, FOXA1, FOXC1, GPR160, GRB7, KIF2C, KRT14, KRT17, KRT5, MAPT,
- MDM2, MELK, MIA, MKI67, MLPH, MMP11, MYBL2, MYC, NAT1, NDC80, NUF2,
- ORC6L, PGR, PHGDH, PTTG1, RRM2, SFRP1, SLC39A6, TMEM45B, TYMS,
+ - dbl (52): ACTR3B, ANLN, BAG1, BCL2, BIRC5, BLVRA, CCNB1, CCNE1, CDC20, CDC6, CDH3,
+ CENPF, CEP55, CXXC5, EGFR, ERBB2, ESR1, EXO1, FGFR4, FOXA1, FOXC1, GPR160, GRB7,
+ KIF2C, KRT14, KRT17, KRT5, MAPT, MDM2, MELK, MIA, MKI67, MLPH, MMP11, MYBL2, MYC,
+ NAT1, NDC80, NUF2, ORC6, PGR, PHGDH, PTTG1, RRM2, SFRP1, SLC39A6, TMEM45B, TYMS,
UBE2C, UBE2T, age, ethnicity
We create a Lasso Cox mlr3 graph
learner (a wrapper around the glmnet::cv.glmnet()
@@ -3237,19 +3273,19 @@
Workflow
Measure: Partial Likelihood Deviance
Lambda Index Measure SE Nonzero
-min 0.00994 15 12.30 0.2719 15
-1se 0.03656 1 12.35 0.2562 2
+min 0.01082 14 12.31 0.2743 15
+1se 0.03626 1 12.35 0.2564 2
Get the survival distribution predictions (\(distr\)) along with the linear predictors
(\(lp\)):
pred = coxlasso_grlrn$predict(task, row_ids = split$test)
head(as.data.table(pred))
row_ids time status crank lp distr
-1: 5 0.9527721 FALSE -3.329133 -3.329133 <list[1]>
-2: 6 4.0438056 FALSE -3.800766 -3.800766 <list[1]>
-3: 15 1.7385352 FALSE -2.786662 -2.786662 <list[1]>
-4: 45 4.5804244 FALSE -2.761110 -2.761110 <list[1]>
-5: 50 5.1279945 FALSE -3.736211 -3.736211 <list[1]>
-6: 54 6.6858316 FALSE -3.499691 -3.499691 <list[1]>
+1: 5 0.9527721 FALSE -2.346574 -2.346574 <list[1]>
+2: 6 4.0438056 FALSE -2.806708 -2.806708 <list[1]>
+3: 15 1.7385352 FALSE -1.845042 -1.845042 <list[1]>
+4: 45 4.5804244 FALSE -1.715041 -1.715041 <list[1]>
+5: 50 5.1279945 FALSE -2.790122 -2.790122 <list[1]>
+6: 54 6.6858316 FALSE -2.466360 -2.466360 <list[1]>
So for every patient in the test set, the Lasso Cox model prediction
is a linear predictor of the form \(lp =
\hat{\beta} X_{new}\). \(crank\)
@@ -3268,10 +3304,10 @@
Workflow
# same logic for the cumulative hazard
# pred$distr$cumHazard(times)[,c(1,2)]
[,1] [,2]
-1 0.9993357 0.9995854
-5 0.9925989 0.9953754
-10 0.9804035 0.9877267
-20 0.9633548 0.9769738
+1 0.9982264 0.9988801
+5 0.9803515 0.9875526
+10 0.9485057 0.9671807
+20 0.9050832 0.9389918
@@ -3293,7 +3329,7 @@
Discrimination metrics
pred$score(harrell_c)
surv.cindex.harrell
- 0.6188244
+ 0.6224306
Uno’s C-index (Uno et al. 2011):
(across all time points of the test set):
@@ -3303,7 +3339,7 @@
Discrimination metrics
# Uno's C needs the train data
pred$score(uno_c, task = task, train_set = split$train)
surv.cindex.uno
- 0.6004459
+ 0.5932426
Uno’s Integrated AUC (Uno et al. 2007)
(across all time points of the test set):
@@ -3315,7 +3351,7 @@
Discrimination metrics
# uno_iauc$properties # needs the train data
pred$score(uno_iauc, task = task, train_set = split$train)
surv.uno_iauc
- 0.6645719
+ 0.6585791
Uno’s AUC at a specific time point,
e.g. \(10\) years:
@@ -3325,7 +3361,7 @@
Discrimination metrics
# needs the train data
pred$score(uno_auc, task = task, train_set = split$train)
surv.uno_auc.10
- 0.6749081
+ 0.667014
@@ -3340,7 +3376,7 @@
Calibration metrics
dcal = msr('surv.dcalib')
pred$score(dcal)
surv.dcalib
- 32.25961
+ 22.57035
@@ -3361,13 +3397,13 @@
Overall metrics
# better to use the train data for the Kaplan-Meier estimation of the censoring distribution, but can use the test set as well
pred$score(ibrier, task = task, train_set = split$train)
surv.graf
-0.4044287
+0.338386
We can also get the standard error of IBS (the above result
is the mean across all the test set’s patients) as follows:
ibrier_se = msr('surv.brier', proper = TRUE, se = TRUE)
pred$score(ibrier_se, task = task, train_set = split$train)
surv.graf
-0.02253927
+0.02106744
Brier Score at a specific time
point, e.g. \(10\) years:
@@ -3378,14 +3414,14 @@ Overall metrics
# better to use the train data for the Kaplan-Meier estimation of the censoring distribution, but can use the test set as well
pred$score(brier10, task = task, train_set = split$train)
surv.graf.10
- 0.4252442
+ 0.3751958
Right-censored Logarithmic Loss
score (RCLL) (Avati et al. 2020; Sonabend 2022):
rcll = msr('surv.rcll')
pred$score(rcll)
surv.rcll
- 4.684644
+ 4.686742
View all evaluation metrics for survival data implemented in mlr3proba here
@@ -3426,34 +3462,21 @@
Uncertainty Quantification
res = rr$score(measures = measures)
head(res)
-
task task_id learner learner_id
-1: <TaskSurv[55]> BRCA-TCGA <GraphLearner[38]> Lasso Cox
-2: <TaskSurv[55]> BRCA-TCGA <GraphLearner[38]> Lasso Cox
-3: <TaskSurv[55]> BRCA-TCGA <GraphLearner[38]> Lasso Cox
-4: <TaskSurv[55]> BRCA-TCGA <GraphLearner[38]> Lasso Cox
-5: <TaskSurv[55]> BRCA-TCGA <GraphLearner[38]> Lasso Cox
-6: <TaskSurv[55]> BRCA-TCGA <GraphLearner[38]> Lasso Cox
- resampling resampling_id iteration prediction
-1: <ResamplingSubsampling[20]> subsampling 1 <PredictionSurv[20]>
-2: <ResamplingSubsampling[20]> subsampling 2 <PredictionSurv[20]>
-3: <ResamplingSubsampling[20]> subsampling 3 <PredictionSurv[20]>
-4: <ResamplingSubsampling[20]> subsampling 4 <PredictionSurv[20]>
-5: <ResamplingSubsampling[20]> subsampling 5 <PredictionSurv[20]>
-6: <ResamplingSubsampling[20]> subsampling 6 <PredictionSurv[20]>
- surv.cindex.harrell surv.cindex.uno surv.uno_iauc surv.uno_auc.10 surv.graf
-1: 0.5679167 0.6090304 0.6628350 0.4719335 0.3255181
-2: 0.5422131 0.4884603 0.4023684 0.5652588 0.3148992
-3: 0.7604049 0.5740556 0.5941948 0.5235439 0.2855151
-4: 0.6610169 0.5277736 0.5360690 0.5110032 0.2972719
-5: 0.5800073 0.5655076 0.6160743 0.5388393 0.3518505
-6: 0.5427837 0.6975740 0.6494779 0.6400328 0.2035609
- surv.graf.10 surv.rcll surv.dcalib
-1: 0.6161825 6.038909 1.026901e+07
-2: 0.4473104 5.400253 1.050427e+04
-3: 0.2969766 4.953528 2.544116e+01
-4: 0.2365322 4.953830 2.275040e+01
-5: 0.4387165 4.943446 3.370510e+01
-6: 0.4228169 5.434970 4.223742e+02
+
task_id learner_id resampling_id iteration surv.cindex.harrell surv.cindex.uno
+1: BRCA-TCGA Lasso Cox subsampling 1 0.5679167 0.6090304
+2: BRCA-TCGA Lasso Cox subsampling 2 0.5524590 0.4969326
+3: BRCA-TCGA Lasso Cox subsampling 3 0.7502812 0.5682061
+4: BRCA-TCGA Lasso Cox subsampling 4 0.6591337 0.5294816
+5: BRCA-TCGA Lasso Cox subsampling 5 0.5752472 0.5553336
+6: BRCA-TCGA Lasso Cox subsampling 6 0.5427837 0.6975740
+ surv.uno_iauc surv.uno_auc.10 surv.graf surv.graf.10 surv.rcll surv.dcalib
+1: 0.6628350 0.4719335 0.3255181 0.6161825 6.038909 1.026901e+07
+2: 0.4038682 0.5712012 0.4815700 0.6666994 6.893425 3.342804e+08
+3: 0.5882995 0.5235439 0.2796580 0.2926334 4.955110 2.490982e+01
+4: 0.5356461 0.5082385 0.2915395 0.2324248 4.955409 2.222845e+01
+5: 0.6090615 0.5288752 0.3497189 0.4371144 4.943943 3.346780e+01
+6: 0.6494779 0.6400328 0.2035609 0.4228169 5.434970 4.223742e+02
+Hidden columns: task, learner, resampling, prediction
We extract and visualize the discrimination and calibration
(resampled) performance of our Lasso Cox model using several evaluation
metrics:
@@ -3482,7 +3505,7 @@
Uncertainty Quantification
labs(title = 'Discrimination Measures') +
theme(axis.text.x = element_blank())
-
+
Discrimination performance of Lasso Cox on
the TCGA-BRCA dataset (expression data of the PAM50 genes and the
variables age and ethnicity). Performance metrics used are Harrell’s
@@ -3523,8 +3546,8 @@ Uncertainty Quantification
theme_bw(base_size = 14) +
theme(axis.title.x = element_blank())
-
-
+
+
Calibration performance of Lasso Cox on the TCGA-BRCA dataset
(expression data of the PAM50 genes and the variables age and
ethnicity). Performance metrics used are the Integrated Brier Score
@@ -3548,20 +3571,21 @@ Feature stability analysis
fs_res = sort(table(unlist(sf_list)), decreasing = TRUE)
times = as.vector(unname(fs_res))
tibble::tibble(feat_name = names(fs_res), times = times, freq = times/n)
-# A tibble: 35 × 3
+# A tibble: 33 × 3
feat_name times freq
<chr> <int> <dbl>
1 age 100 1
2 ethnicity 100 1
- 3 UBE2T 53 0.53
- 4 ORC6L 48 0.48
- 5 ANLN 42 0.42
- 6 ERBB2 40 0.4
- 7 GPR160 35 0.35
- 8 FGFR4 33 0.33
- 9 CEP55 32 0.32
-10 UBE2C 30 0.3
-# … with 25 more rows
+ 3 ANLN 43 0.43
+ 4 BLVRA 41 0.41
+ 5 BAG1 37 0.37
+ 6 MIA 34 0.34
+ 7 TYMS 30 0.3
+ 8 KRT5 27 0.27
+ 9 MMP11 27 0.27
+10 BCL2 26 0.26
+# ℹ 23 more rows
+# ℹ Use `print(n = ...)` to see more rows
As age
and ethnicity
were not penalized,
they have non-zero coefficients in all Lasso Cox models and therefore
are included in all selected feature sets.
@@ -3593,7 +3617,7 @@ Feature stability analysis
# A tibble: 1 × 3
jaccard nogueira zucknick
<dbl> <dbl> <dbl>
-1 0.439 0.412 0.402
+1 0.474 0.412 0.442
From the above values we conclude that the stability of Lasso Cox’s
feature selection is neither poor nor excellent but somewhere in
between.
@@ -3603,102 +3627,104 @@ Feature stability analysis
R session info
sessionInfo()
-
R version 4.2.1 (2022-06-23)
-Platform: x86_64-pc-linux-gnu (64-bit)
-Running under: Ubuntu 20.04.5 LTS
+R version 4.3.1 (2023-06-16)
+Platform: x86_64-apple-darwin20 (64-bit)
+Running under: macOS Monterey 12.7
Matrix products: default
-BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0
-LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.9.0
+BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
+LAPACK: /Library/Frameworks/R.framework/Versions/4.3-x86_64/Resources/lib/libRlapack.dylib; LAPACK version 3.11.0
locale:
- [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
- [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8 LC_PAPER=en_US.UTF-8 LC_NAME=C
- [9] LC_ADDRESS=C LC_TELEPHONE=C LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
+[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
+
+time zone: Europe/Oslo
+tzcode source: internal
attached base packages:
[1] stats4 stats graphics grDevices utils datasets methods base
other attached packages:
- [1] stabm_1.2.1 mlr3extralearners_0.6.1 mlr3proba_0.5.2
- [4] mlr3verse_0.2.7 mlr3_0.14.1 regplot_1.1
- [7] survAUC_1.1-1 rms_6.3-0 SparseM_1.81
-[10] Hmisc_4.7-1 lattice_0.20-45 c060_0.2-9
-[13] peperr_1.4 snowfall_1.84-6.2 snow_0.4-4
-[16] riskRegression_2022.09.23 risksetROC_1.0.4.1 MASS_7.3-57
-[19] BhGLM_1.1.0 GGally_2.1.2 psbcGroup_1.5
-[22] mvtnorm_1.1-3 SuppDists_1.1-9.7 LearnBayes_2.15.1
-[25] SGL_1.3 grpreg_3.4.0 plotmo_3.6.2
-[28] TeachingDemos_2.12 plotrix_3.8-2 Formula_1.2-4
-[31] glmnet_4.1-4 Matrix_1.5-1 M3C_1.20.0
-[34] survminer_0.4.9 ggpubr_0.4.0 survival_3.4-0
-[37] ggplot2_3.4.0 dplyr_1.0.10 DESeq2_1.38.3
-[40] SummarizedExperiment_1.28.0 Biobase_2.58.0 GenomicRanges_1.50.2
-[43] GenomeInfoDb_1.34.6 IRanges_2.32.0 S4Vectors_0.36.1
-[46] BiocGenerics_0.44.0 MatrixGenerics_1.10.0 matrixStats_0.63.0
-[49] TCGAbiolinks_2.25.3
+ [1] stabm_1.2.2 mlr3extralearners_0.7.0 mlr3proba_0.5.2
+ [4] mlr3verse_0.2.8 mlr3_0.16.1 regplot_1.1
+ [7] survAUC_1.2-0 rms_6.7-0 Hmisc_5.1-0
+[10] c060_0.3-0 peperr_1.5 snowfall_1.84-6.2
+[13] snow_0.4-4 riskRegression_2023.03.22 risksetROC_1.0.4.1
+[16] MASS_7.3-60 BhGLM_1.1.0 GGally_2.1.2
+[19] psbcGroup_1.5 mvtnorm_1.2-2 SuppDists_1.1-9.7
+[22] LearnBayes_2.15.1 SGL_1.3 grpreg_3.4.0
+[25] plotmo_3.6.2 TeachingDemos_2.12 plotrix_3.8-2
+[28] Formula_1.2-5 glmnet_4.1-7 Matrix_1.5-4.1
+[31] M3C_1.22.0 survminer_0.4.9 ggpubr_0.6.0
+[34] survival_3.5-5 ggplot2_3.4.2 dplyr_1.1.2
+[37] DESeq2_1.40.2 SummarizedExperiment_1.30.2 Biobase_2.60.0
+[40] GenomicRanges_1.52.0 GenomeInfoDb_1.36.1 IRanges_2.34.1
+[43] S4Vectors_0.38.1 BiocGenerics_0.46.0 MatrixGenerics_1.12.2
+[46] matrixStats_1.0.0 TCGAbiolinks_2.28.3
loaded via a namespace (and not attached):
- [1] rappdirs_0.3.3 vioplot_0.4.0 tidyr_1.2.1
- [4] bit64_4.0.5 knitr_1.40 multcomp_1.4-20
- [7] DelayedArray_0.24.0 data.table_1.14.6 rpart_4.1.19
- [10] KEGGREST_1.38.0 RCurl_1.98-1.9 doParallel_1.0.17
- [13] generics_0.1.3 timereg_2.0.4 tgp_2.4-21
- [16] TH.data_1.1-1 RSQLite_2.2.20 polspline_1.1.20
- [19] proxy_0.4-27 future_1.31.0 bit_4.0.4
- [22] tzdb_0.3.0 xml2_1.3.3 assertthat_0.2.1
- [25] xfun_0.33 hms_1.1.2 evaluate_0.20
- [28] fansi_1.0.3 progress_1.2.2 dbplyr_2.2.1
- [31] km.ci_0.5-6 DBI_1.1.3 geneplotter_1.76.0
- [34] htmlwidgets_1.5.4 reshape_0.8.9 purrr_1.0.1
- [37] ellipsis_0.3.2 mlr3data_0.6.1 RSpectra_0.16-1
- [40] backports_1.4.1 annotate_1.76.0 biomaRt_2.54.0
- [43] deldir_1.0-6 vctrs_0.5.1 quantreg_5.94
- [46] abind_1.4-5 cachem_1.0.6 withr_2.5.0
- [49] mlr3learners_0.5.6 checkmate_2.1.0 prettyunits_1.1.1
- [52] mlr3fselect_0.9.1 param6_0.2.4 cluster_2.1.3
- [55] crayon_1.5.2 pkgconfig_2.0.3 nlme_3.1-157
- [58] mlegp_3.1.9 nnet_7.3-17 rlang_1.0.6
- [61] globals_0.16.2 lifecycle_1.0.3 MatrixModels_0.5-1
- [64] sandwich_3.0-2 downloader_0.4 filelock_1.0.2
- [67] palmerpenguins_0.1.1 BiocFileCache_2.6.0 mets_1.3.1
- [70] doSNOW_1.0.20 KMsurv_0.1-5 carData_3.0-5
- [73] boot_1.3-28 zoo_1.8-11 base64enc_0.1-3
- [76] png_0.1-8 bitops_1.0-7 Biostrings_2.66.0
- [79] blob_1.2.3 shape_1.4.6 paradox_0.11.0
- [82] stringr_1.5.0 parallelly_1.34.0 readr_2.1.3
- [85] jpeg_0.1-9 rstatix_0.7.1 dictionar6_0.1.3
- [88] ggsignif_0.6.4 scales_1.2.1 memoise_2.0.1
- [91] magrittr_2.0.3 plyr_1.8.8 zlibbioc_1.44.0
- [94] compiler_4.2.1 RColorBrewer_1.1-3 clue_0.3-63
- [97] lme4_1.1-31 set6_0.2.5 cli_3.4.1
-[100] XVector_0.38.0 mlr3tuningspaces_0.3.3 mlr3filters_0.7.0
-[103] listenv_0.9.0 htmlTable_2.4.1 tidyselect_1.2.0
-[106] stringi_1.7.12 TCGAbiolinksGUI.data_1.18.0 distr6_1.6.13
-[109] yaml_2.3.5 askpass_1.1 locfit_1.5-9.6
-[112] latticeExtra_0.6-30 survMisc_0.5.6 grid_4.2.1
-[115] maptree_1.4-8 tools_4.2.1 mlr3misc_0.11.0
-[118] mlr3cluster_0.1.6 future.apply_1.10.0 parallel_4.2.1
-[121] matrixcalc_1.0-6 rstudioapi_0.14 uuid_1.1-0
-[124] foreach_1.5.2 foreign_0.8-82 gridExtra_2.3
-[127] prodlim_2019.11.13 Rtsne_0.16 digest_0.6.31
-[130] lava_1.7.0 cmprsk_2.2-11 Rcpp_1.0.10
-[133] car_3.1-1 broom_1.0.1 httr_1.4.4
-[136] AnnotationDbi_1.60.0 mlr3tuning_0.17.2 colorspace_2.0-3
-[139] rvest_1.0.3 XML_3.99-0.13 reticulate_1.26
-[142] umap_0.2.9.0 splines_4.2.1 lgr_0.4.4
-[145] bbotk_0.7.2 sm_2.2-5.7.1 statmod_1.4.37
-[148] mlr3pipelines_0.4.2 xtable_1.8-4 nloptr_2.0.3
-[151] jsonlite_1.8.3 corpcor_1.6.10 clusterCrit_1.2.8
-[154] R6_2.5.1 pillar_1.8.1 htmltools_0.5.3
-[157] minqa_1.2.5 glue_1.6.2 fastmap_1.1.0
-[160] BiocParallel_1.32.5 beanplot_1.3.1 class_7.3-20
-[163] ooplah_0.2.0 codetools_0.2-18 utf8_1.2.2
-[166] tibble_3.1.8 numDeriv_2016.8-1.1 curl_4.3.3
-[169] mlr3viz_0.6.1 openssl_2.0.3 interp_1.1-3
-[172] penalizedSVM_1.1.3 rmarkdown_2.17 munsell_0.5.0
-[175] e1071_1.7-12 GenomeInfoDbData_1.2.9 iterators_1.0.14
-[178] gtable_0.3.1
+ [1] tgp_2.4-21 progress_1.2.2 mlr3hyperband_0.4.5
+ [4] penalized_0.9-52 nnet_7.3-19 Biostrings_2.68.1
+ [7] TH.data_1.1-2 vctrs_0.6.3 digest_0.6.32
+ [10] png_0.1-8 corpcor_1.6.10 shape_1.4.6
+ [13] proxy_0.4-27 parallelly_1.36.0 reshape_0.8.9
+ [16] foreach_1.5.2 withr_2.5.0 param6_0.2.4
+ [19] xfun_0.39 memoise_2.0.1 diptest_0.76-0
+ [22] MatrixModels_0.5-1 zoo_1.8-12 DEoptimR_1.1-1
+ [25] distr6_1.8.0 prettyunits_1.1.1 prabclus_2.3-2
+ [28] KEGGREST_1.40.0 httr_1.4.6 downloader_0.4
+ [31] maptree_1.4-8 rstatix_0.7.2 globals_0.16.2
+ [34] fpc_2.2-10 rstudioapi_0.14 generics_0.1.3
+ [37] base64enc_0.1-3 curl_5.0.1 zlibbioc_1.46.0
+ [40] doSNOW_1.0.20 GenomeInfoDbData_1.2.10 lgr_0.4.4
+ [43] xtable_1.8-4 stringr_1.5.0 doParallel_1.0.17
+ [46] evaluate_0.21 S4Arrays_1.0.4 BiocFileCache_2.8.0
+ [49] hms_1.1.3 colorspace_2.1-0 filelock_1.0.2
+ [52] cmprsk_2.2-11 reticulate_1.30 flexmix_2.3-19
+ [55] magrittr_2.0.3 readr_2.1.4 modeltools_0.2-23
+ [58] lattice_0.21-8 palmerpenguins_0.1.1 future.apply_1.11.0
+ [61] robustbase_0.99-0 SparseM_1.81 XML_3.99-0.14
+ [64] class_7.3-22 pillar_1.9.0 nlme_3.1-162
+ [67] iterators_1.0.14 compiler_4.3.1 RSpectra_0.16-1
+ [70] stringi_1.7.12 paradox_0.11.1 minqa_1.2.5
+ [73] dictionar6_0.1.3 plyr_1.8.8 crayon_1.5.2
+ [76] abind_1.4-5 sm_2.2-5.7.1 locfit_1.5-9.8
+ [79] bit_4.0.5 sandwich_3.0-2 mlr3mbo_0.2.1
+ [82] codetools_0.2-19 multcomp_1.4-25 matrixcalc_1.0-6
+ [85] openssl_2.0.6 e1071_1.7-13 splines_4.3.1
+ [88] Rcpp_1.0.10 quantreg_5.95 dbplyr_2.3.2
+ [91] TCGAbiolinksGUI.data_1.20.0 knitr_1.43 blob_1.2.4
+ [94] utf8_1.2.3 clue_0.3-64 lme4_1.1-34
+ [97] listenv_0.9.0 checkmate_2.2.0 ggsignif_0.6.4
+[100] tibble_3.2.1 mlr3tuningspaces_0.4.0 statmod_1.5.0
+[103] tzdb_0.4.0 pkgconfig_2.0.3 tools_4.3.1
+[106] cachem_1.0.8 RSQLite_2.3.1 rvest_1.0.3
+[109] DBI_1.1.3 numDeriv_2016.8-1.1 mlr3filters_0.7.1
+[112] fastmap_1.1.1 rmarkdown_2.22 scales_1.2.1
+[115] mlegp_3.1.9 grid_4.3.1 mets_1.3.2
+[118] broom_1.0.5 carData_3.0-5 rpart_4.1.19
+[121] yaml_2.3.7 foreign_0.8-84 cli_3.6.1
+[124] purrr_1.0.1 lifecycle_1.0.3 askpass_1.1
+[127] bbotk_0.7.2 lava_1.7.2.1 kernlab_0.9-32
+[130] backports_1.4.1 mlr3tuning_0.19.0 BiocParallel_1.34.2
+[133] gtable_0.3.3 umap_0.2.10.0 parallel_4.3.1
+[136] mlr3cluster_0.1.8 jsonlite_1.8.7 bitops_1.0-7
+[139] bit64_4.0.5 Rtsne_0.16 mlr3learners_0.5.6
+[142] polspline_1.1.23 survMisc_0.5.6 spacefillr_0.3.2
+[145] htmltools_0.5.5 KMsurv_0.1-5 set6_0.2.6
+[148] rappdirs_0.3.3 mlr3pipelines_0.5.0-1 glue_1.6.2
+[151] penalizedSVM_1.1.4 mlr3viz_0.6.1 timereg_2.0.5
+[154] XVector_0.40.0 RCurl_1.98-1.12 mclust_6.0.0
+[157] gridExtra_2.3 boot_1.3-28.1 R6_2.5.1
+[160] tidyr_1.3.0 km.ci_0.5-6 ooplah_0.2.0
+[163] cluster_2.1.4 beanplot_1.3.1 nloptr_2.0.3
+[166] mlr3misc_0.13.0 vioplot_0.4.0 DelayedArray_0.26.3
+[169] tidyselect_1.2.0 htmlTable_2.4.1 xml2_1.3.4
+[172] mlr3fselect_0.11.0 car_3.1-2 AnnotationDbi_1.62.1
+[175] future_1.33.0 munsell_0.5.0 data.table_1.14.8
+[178] htmlwidgets_1.6.2 mlr3data_0.7.0 RColorBrewer_1.1-3
+[181] biomaRt_2.56.1 rlang_1.1.1 uuid_1.1-1
+[184] fansi_1.0.4 prodlim_2023.03.31
-Zhao, Zhi, John Zobolas, Manuela Zucknick, and Tero Aittokallio. 2023.
-
“Tutorial on Survival Modelling with Omics Data.” arXiv.
https://doi.org/10.48550/ARXIV.2302.12542.
+Zhao, Zhi, Manuela Zucknick, Maral Saadati, and Axel Benner. 2023.
+
“Penalized Semiparametric Bayesian Survival Models.” R
+Package Version 2.0.4. https://CRAN.R-project.org/package=psbcSpeedUp.
Zucknick, Manuela, Sylvia Richardson, and Euan A Stronach. 2008.
@@ -3907,7 +3934,7 @@
References
-
LS0tCnRpdGxlOiAiU3VwcGxlbWVudGFsIGluZm9ybWF0aW9uIGZvciAnVHV0b3JpYWwgb24gc3Vydml2YWwgbW9kZWxsaW5nIHdpdGggb21pY3MgZGF0YSciCmRhdGU6ICJMYXN0IHVwZGF0ZWQ6IGByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIsICVZJylgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGNzczogc3R5bGUuY3NzCiAgICB0aGVtZTogdW5pdGVkCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiB0cnVlCiAgICAgIHNtb290aF9zY3JvbGw6IHRydWUKICAgIHRvY19kZXB0aDogNAogICAgbnVtYmVyX3NlY3Rpb25zOiBmYWxzZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCmJpYmxpb2dyYXBoeTogcmVmZXJlbmNlcy5iaWIKbGluay1jaXRhdGlvbnM6IHRydWUKLS0tCgpgYGB7ciwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGNvbW1lbnQgPSAnJywgZXZhbCA9IEZBTFNFCikKYGBgCjxicj4KVGhpcyBpcyBhbiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgc3VwcGxlbWVudCBmb3IgdGhlIGFydGljbGUgWyoqX1R1dG9yaWFsIG9uIHN1cnZpdmFsIG1vZGVsbGluZyB3aXRoIG9taWNzIGRhdGFfKipdKGh0dHBzOi8vYXJ4aXYub3JnL2Ficy8yMzAyLjEyNTQyKSBbQFpoYW8yMDIzXS4KCiMgSW50cm9kdWN0aW9uIHstfQoKW1RoZSBDYW5jZXIgR2Vub21lIEF0bGFzXShodHRwczovL3d3dy5jYW5jZXIuZ292L2Fib3V0LW5jaS9vcmdhbml6YXRpb24vY2NnL3Jlc2VhcmNoL3N0cnVjdHVyYWwtZ2Vub21pY3MvdGNnYSkgKFRDR0EpIHByb3ZpZGVzIGFuIGVub3Jtb3VzIGNvbGxlY3Rpb24gb2YgY2FuY2VyIGRhdGEgc2V0cywgaW5jbHVkaW5nIHN1cnZpdmFsLCBjbGluaWNhbCBhbmQgbXVsdGktb21pY3MgZGF0YS4KCjo6OnsuZ3JlZW4tYm94fQpXZSB3aWxsIHVzZSBUQ0dBIGRhdGEgdG8gZGVtb25zdHJhdGU6CgotIFRoZSBkaWZmZXJlbnQgZGF0YSB0eXBlcwotIFByZXByb2Nlc3Npbmcgb2Ygc3Vydml2YWwgYW5kIG9taWNzIGRhdGEKLSBBbmFseXNpcyBvZiBzdXJ2aXZhbCBkYXRhIGJ5IGNsYXNzaWNhbCBzdGF0aXN0aWNhbCBtZXRob2RzCi0gVW5zdXBlcnZpc2VkIGxlYXJuaW5nIGZvciBvbWljcyBkYXRhCi0gRnJlcXVlbnRpc3QgJiBCYXllc2lhbiBzdXBlcnZpc2VkIGxlYXJuaW5nIGZvciBzdXJ2aXZhbCBhbmQgb21pY3MgZGF0YQo6OjoKCiMgVENHQSBzdXJ2aXZhbCBhbmQgY2xpbmljYWwgZGF0YSB7LX0KClRoZSBSL0Jpb2NvbmR1Y3RvciBwYWNrYWdlIFsqKlRDR0FiaW9saW5rcyoqXShodHRwczovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvVENHQWJpb2xpbmtzLykgW0BNb3VuaXIyMDE5XSBwcm92aWRlcyBhIGZldyBmdW5jdGlvbnMgdG8gZG93bmxvYWQgYW5kIHByZXByb2Nlc3MgY2xpbmljYWwgYW5kIG11bHRpLW9taWNzIGRhdGEgZnJvbSB0aGUgW0dlbm9taWMgRGF0YSBDb21tb25zXShodHRwczovL2dkYy5jYW5jZXIuZ292LykgKEdEQykgRGF0YSBQb3J0YWwgZm9yIGZ1cnRoZXIgYW5hbHlzaXMuCgpGaXJzdCB3ZSBsb2FkIGFsbCBuZWNlc3NhcnkgbGlicmFyaWVzIHVzZWQgaW4gdGhpcyB0dXRvcmlhbCBleGNlcHQgWyoqbWxyMyoqIGxpYnJhcmllc10oI21scjMpIHdoaWNoIHdpbGwgYmUgaW50cm9kdWNlZCBsYXRlci4gClRoZW4gd2UgdXNlIGZ1bmN0aW9uIGBHRENxdWVyeV9jbGluaWMoKWAgZnJvbSAqKlRDR0FiaW9saW5rcyoqIHBhY2thZ2UgdG8gcXVlcnkgYW5kIGRvd25sb2FkIFRDR0Egc3Vydml2YWwgYW5kIGNsaW5pY2FsIGRhdGEgZnJvbSBtdWx0aXBsZSBjYW5jZXIgdHlwZXM6CgpgYGB7cn0KIyBsb2FkIGFsbCBsaWJyYXJpZXMgdXNlZCBpbiB0aGlzIHR1dG9yaWFsIGV4Y2VwdCBtbHIzCmxpYnJhcnkoIlRDR0FiaW9saW5rcyIpCmxpYnJhcnkoIlN1bW1hcml6ZWRFeHBlcmltZW50IikKbGlicmFyeSgiREVTZXEyIikKbGlicmFyeSgiZHBseXIiKQpsaWJyYXJ5KCJnZ3Bsb3QyIikKbGlicmFyeSgic3Vydml2YWwiKQpsaWJyYXJ5KCJzdXJ2bWluZXIiKQpsaWJyYXJ5KCJNM0MiKQpsaWJyYXJ5KCJnbG1uZXQiKQpsaWJyYXJ5KCJwbG90bW8iKQpsaWJyYXJ5KCJncnByZWciKQpsaWJyYXJ5KCJTR0wiKQpsaWJyYXJ5KCJwc2JjR3JvdXAiKQpsaWJyYXJ5KCJHR2FsbHkiKQpsaWJyYXJ5KCJCaEdMTSIpCmxpYnJhcnkoInJpc2tzZXRST0MiKQpsaWJyYXJ5KCJyaXNrUmVncmVzc2lvbiIpCmxpYnJhcnkoInBlcGVyciIpCmxpYnJhcnkoImMwNjAiKQpsaWJyYXJ5KCJybXMiKQpsaWJyYXJ5KCJzdXJ2QVVDIikKbGlicmFyeSgicmVncGxvdCIpCmBgYAoKYGBge3J9CiMgZG93bmxvYWQgdGhlIGNsaW5pY2FsIGRhdGEgYW5kIGV4dHJhY3QgZGF0YSBmb3IgbXVsdGlwbGUgY2FuY2VycyB1c2luZyBHREMgYXBpIG1ldGhvZApjYW5jZXJfdHlwZXMgPSBjKCJUQ0dBLUJMQ0EiLCAiVENHQS1CUkNBIiwgIlRDR0EtQ09BRCIsICJUQ0dBLUxJSEMiLCAKICAgICAgICAgICAgICAgICAgIlRDR0EtTFVBRCIsICJUQ0dBLVBBQUQiLCAiVENHQS1QUkFEIiwgIlRDR0EtVEhDQSIpCmNsaW4gPSBOVUxMCmZvciAoaSBpbiBzZXFfYWxvbmcoY2FuY2VyX3R5cGVzKSkgewogIHRtcCA9IFRDR0FiaW9saW5rczo6R0RDcXVlcnlfY2xpbmljKHByb2plY3QgPSBjYW5jZXJfdHlwZXNbaV0sIHR5cGUgPSAiY2xpbmljYWwiKQogIGNsaW4gPSByYmluZChjbGluLCB0bXBbLCBjKCJwcm9qZWN0IiwgInN1Ym1pdHRlcl9pZCIsICJ2aXRhbF9zdGF0dXMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImRheXNfdG9fbGFzdF9mb2xsb3dfdXAiLCAiZGF5c190b19kZWF0aCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYWdlX2F0X2RpYWdub3NpcyIsICJnZW5kZXIiLCAicmFjZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZXRobmljaXR5IiwgImFqY2NfcGF0aG9sb2dpY190IildKQp9CgojIGV4dHJhY3QgdGhlIG9ic2VydmVkIHRpbWUgZm9yIGVhY2ggcGF0aWVudCBhbmQgdXNlIHllYXJzIGFzIHVuaXQKY2xpbiR0aW1lID0gYXBwbHkoY2xpblssIGMoImRheXNfdG9fZGVhdGgiLCAiZGF5c190b19sYXN0X2ZvbGxvd191cCIpXSwgMSwgbWF4LCBuYS5ybSA9IFRSVUUpIC8gMzY1LjI1CmNsaW4kYWdlID0gY2xpbiRhZ2VfYXRfZGlhZ25vc2lzIC8gMzY1LjI1CmNsaW4kc3RhdHVzID0gY2xpbiR2aXRhbF9zdGF0dXMKY2xpbiA9IGNsaW5bLCBjKCJwcm9qZWN0IiwgInN1Ym1pdHRlcl9pZCIsICJzdGF0dXMiLCAidGltZSIsICJnZW5kZXIiLCAiYWdlIiwgInJhY2UiLCAiZXRobmljaXR5IildCgpjbGluID0gY2xpblsoY2xpbiR0aW1lID4gMCkgJiAoY2xpbiRzdGF0dXMgJWluJSBjKCJBbGl2ZSIsICJEZWFkIikpLCBdCgojIGZyZXF1ZW5jeSB0YWJsZSBvZiB0aGUgcGF0aWVudHMgdy5yLnQuIHN0YXR1cywgZ2VuZGVyIGFuZCBldGhuaWNpdHkKY2xpbiAlPiUKICBjb3VudChzdGF0dXMsIGdlbmRlciwgZXRobmljaXR5KSAlPiUKICBncm91cF9ieShzdGF0dXMpICU+JSAgICAgICAgCiAgbXV0YXRlKHByb3AgPSBwcm9wLnRhYmxlKG4pKQpgYGAKCmBgYAojIEEgdGliYmxlOiAxMiDDlyA1CiMgR3JvdXBzOiAgIHN0YXR1cyBbMl0KICAgc3RhdHVzIGdlbmRlciBldGhuaWNpdHkgICAgICAgICAgICAgICAgICBuICAgIHByb3AKICAgPGNocj4gIDxjaHI+ICA8Y2hyPiAgICAgICAgICAgICAgICAgIDxpbnQ+ICAgPGRibD4KIDEgQWxpdmUgIGZlbWFsZSBoaXNwYW5pYyBvciBsYXRpbm8gICAgICAgIDc1IDAuMDI0MCAKIDIgQWxpdmUgIGZlbWFsZSBub3QgaGlzcGFuaWMgb3IgbGF0aW5vICAxMzY3IDAuNDM4ICAKIDMgQWxpdmUgIGZlbWFsZSBub3QgcmVwb3J0ZWQgICAgICAgICAgICAgMzI4IDAuMTA1ICAKIDQgQWxpdmUgIG1hbGUgICBoaXNwYW5pYyBvciBsYXRpbm8gICAgICAgIDM0IDAuMDEwOSAKIDUgQWxpdmUgIG1hbGUgICBub3QgaGlzcGFuaWMgb3IgbGF0aW5vICAxMDQxIDAuMzM0ICAKIDYgQWxpdmUgIG1hbGUgICBub3QgcmVwb3J0ZWQgICAgICAgICAgICAgMjc2IDAuMDg4NCAKIDcgRGVhZCAgIGZlbWFsZSBoaXNwYW5pYyBvciBsYXRpbm8gICAgICAgICA3IDAuMDA4MDkKIDggRGVhZCAgIGZlbWFsZSBub3QgaGlzcGFuaWMgb3IgbGF0aW5vICAgMzc3IDAuNDM2ICAKIDkgRGVhZCAgIGZlbWFsZSBub3QgcmVwb3J0ZWQgICAgICAgICAgICAgIDY0IDAuMDc0MCAKMTAgRGVhZCAgIG1hbGUgICBoaXNwYW5pYyBvciBsYXRpbm8gICAgICAgIDEwIDAuMDExNiAKMTEgRGVhZCAgIG1hbGUgICBub3QgaGlzcGFuaWMgb3IgbGF0aW5vICAgMzI3IDAuMzc4ICAKMTIgRGVhZCAgIG1hbGUgICBub3QgcmVwb3J0ZWQgICAgICAgICAgICAgIDgwIDAuMDkyNSAKYGBgCgpgYGB7cn0KIyBjZW5zb3JpbmcgcGxvdCBieSBjYW5jZXIgdHlwZXMKY2xpbiAlPiUKICBtdXRhdGUoaW5kZXg9MTpuKCkpICU+JQogIGdncGxvdCgKICAgIGFlcyh5ID0gaW5kZXgsIHggPSB0aW1lLCBjb2xvdXIgPSBwcm9qZWN0LCBzaGFwZSA9IGZhY3RvcihzdGF0dXMpKSkgKwogICAgZ2VvbV9zZWdtZW50KGFlcyh4ID0gdGltZSwgeSA9IGluZGV4LCB4ZW5kID0gMCwgeWVuZCA9IGluZGV4KSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2d0aXRsZSgiIikgKwogIGxhYnMoeD0iWWVhcnMiLCB5PSJQYXRpZW50cyIpICsKICBzY2FsZV9zaGFwZV9kaXNjcmV0ZShuYW1lID0gIlN0YXR1cyIsIGxhYmVscyA9IGMoIkNlbnNvcmVkIiwiRGVhZCIpKSArCiAgc2NhbGVfY29sb3JfZGlzY3JldGUobmFtZSA9ICJDYW5jZXIiLCAKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJCbGFkZGVyIiwiQnJlYXN0IiwiQ29sb24iLCJMaXZlciIsICJMdW5nIGFkZW5vIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUGFuY3JlYXRpYyIsICJQcm9zdGF0ZSIsIlRoeXJvaWQiKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0idG9wIiwgbGVnZW5kLmRpcmVjdGlvbj0idmVydGljYWwiKSArIAogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMiwgYnlyb3cgPSBUUlVFKSkKYGBgCgohW19PdmVyYWxsIHN1cnZpdmFsIHRpbWVzIGFuZCBzdGF0dXMgb2YgcGFuLWNhbmNlciBwYXRpZW50cyBmcm9tIFRDR0EuX10oZmlnL1RDR0Ffc3Vydml2YWwucG5nKXt3aWR0aD02MCV9Cgo8YnI+CgojIFRDR0Egb21pY3MgZGF0YSB7LX0KCldlIHVzZSBmdW5jdGlvbiBgR0RDcXVlcnkoKWAgdG8gcXVlcnkgYW5kIHVzZSBgR0RDZG93bmxvYWQoKWAgYW5kIGBHRENwcmVwYXJlKClgIHRvIGRvd25sb2FkIFRDR0Egb21pY3MgZGF0YSBmcm9tIG9uZSBjYW5jZXIgdHlwZSAoYnJlYXN0IGNhbmNlcikuClRoZSBhcmd1bWVudCBgZGF0YS5jYXRlZ29yeWAgaW4gZnVuY3Rpb24gYEdEQ3F1ZXJ5KClgIHNwZWNpZmllcyB0aGUgdHlwZSBvZiBvbWljcyBkYXRhLCBzdWNoIGFzIGAiQ29weSBOdW1iZXIgVmFyaWF0aW9uImAsIGAiRE5BIE1ldGh5bGF0aW9uImAsIGAiVHJhbnNjcmlwdG9tZSBQcm9maWxpbmciYCwgYCJTaW1wbGUgTnVjbGVvdGlkZSBWYXJpYXRpb24iYC4KTm90ZSB0aGF0IHRoZSBkb3dubG9hZGVkIG9taWNzIGRhdGEgYXJlIGFjY29tcGFuaWVkIGJ5IG1ldGFkYXRhIGluY2x1ZGluZyBzdXJ2aXZhbCBvdXRjb21lcywgY2xpbmljYWwgYW5kIGRlbW9ncmFwaGljIHZhcmlhYmxlcy4gClRoZSBhY2NvbXBhbmllZCBtZXRhZGF0YSBhcmUgYWxtb3N0IHRoZSBzYW1lIGFzIHRoZSBjbGluaWNhbCBkYXRhIGRvd25sb2FkZWQgdmlhIGBHRENxdWVyeV9jbGluaWMoKWAgaW4gdGhlIHByZXZpb3VzIHNlY3Rpb24gYnV0IGhlcmUgb25seSBjb3JyZXNwb25kaW5nIHRvIG9uZSBjYW5jZXIgdHlwZS4KCmBgYHtyfQojIGRvd25sb2FkIFRDR0EgYnJlYXN0IGNhbmNlciAoQlJDQSkgbVJOQS1TZXEgZGF0YSB1c2luZyBHREMgYXBpIG1ldGhvZApxdWVyeSA9IFRDR0FiaW9saW5rczo6R0RDcXVlcnkocHJvamVjdCA9ICJUQ0dBLUJSQ0EiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YS5jYXRlZ29yeSA9ICJUcmFuc2NyaXB0b21lIFByb2ZpbGluZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhLnR5cGUgPSAiR2VuZSBFeHByZXNzaW9uIFF1YW50aWZpY2F0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtmbG93LnR5cGUgPSAiU1RBUiAtIENvdW50cyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHBlcmltZW50YWwuc3RyYXRlZ3kgPSAiUk5BLVNlcSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGUudHlwZSA9IGMoIlByaW1hcnkgVHVtb3IiKSkKVENHQWJpb2xpbmtzOjpHRENkb3dubG9hZChxdWVyeSA9IHF1ZXJ5LCBtZXRob2QgPSAiYXBpIikKZGF0ID0gVENHQWJpb2xpbmtzOjpHRENwcmVwYXJlKHF1ZXJ5ID0gcXVlcnkpCgpTdW1tYXJpemVkRXhwZXJpbWVudDo6YXNzYXlzKGRhdCkkdW5zdHJhbmRlZFsxOjUsIDE6Ml0KYGBgCmBgYAogICAgICAgICAgICAgICAgICAgVENHQS1MTC1BNzNZLTAxQS0xMVItQTMzSi0wNyBUQ0dBLUUyLUExSVUtMDFBLTExUi1BMTRELTA3CkVOU0cwMDAwMDAwMDAwMy4xNSAgICAgICAgICAgICAgICAgICAgICAgICA3MDE1ICAgICAgICAgICAgICAgICAgICAgICAgICA4NTAKRU5TRzAwMDAwMDAwMDA1LjYgICAgICAgICAgICAgICAgICAgICAgICAgICAgMTYgICAgICAgICAgICAgICAgICAgICAgICAgICAgNQpFTlNHMDAwMDAwMDA0MTkuMTMgICAgICAgICAgICAgICAgICAgICAgICAgMjE2NyAgICAgICAgICAgICAgICAgICAgICAgICAxNjgwCkVOU0cwMDAwMDAwMDQ1Ny4xNCAgICAgICAgICAgICAgICAgICAgICAgICAyNTA1ICAgICAgICAgICAgICAgICAgICAgICAgIDE1NTkKRU5TRzAwMDAwMDAwNDYwLjE3ICAgICAgICAgICAgICAgICAgICAgICAgICA3MjYgICAgICAgICAgICAgICAgICAgICAgICAgIDQwMgpgYGAKCkl0IGlzIHJlY29tbWVuZGVkIHRvIHVzZSBERVNlcTIgb3IgVE1NIG5vcm1hbGl6YXRpb24gbWV0aG9kIGZvciBSTkEtc2VxIGRhdGEgYmVmb3JlIGZ1cnRoZXIgc3RhdGlzdGljYWwgYW5hbHlzaXMgW0BaaGFvWTIwMjFdLgpIZXJlIHdlIGRlbW9uc3RyYXRlIGhvdyB0byB1c2UgdGhlIFIvQmlvY29uZHVjdG9yIHBhY2thZ2UgWyoqREVTZXEyKipdKGh0dHBzOi8vYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9ERVNlcTIvKSBbQExvdmUyMDE0XSB0byBub3JtYWxpemUgdGhlIFJOQSBjb3VudCBkYXRhLgoKYGBge3J9Cm1ldGEgPSBjb2xEYXRhKGRhdClbLCBjKCJwcm9qZWN0X2lkIiwgInN1Ym1pdHRlcl9pZCIsICJhZ2VfYXRfZGlhZ25vc2lzIiwgICJldGhuaWNpdHkiLCAiZ2VuZGVyIiwgImRheXNfdG9fZGVhdGgiLCAiZGF5c190b19sYXN0X2ZvbGxvd191cCIsICJ2aXRhbF9zdGF0dXMiLCAicGFwZXJfQlJDQV9TdWJ0eXBlX1BBTTUwIiwgInRyZWF0bWVudHMiKV0KbWV0YSR0cmVhdG1lbnRzID0gdW5saXN0KGxhcHBseShtZXRhJHRyZWF0bWVudHMsIGZ1bmN0aW9uKHh4KXthbnkoeHgkdHJlYXRtZW50X29yX3RoZXJhcHkgPT0gInllcyIpfSkpCmRkcyA9IERFU2VxMjo6REVTZXFEYXRhU2V0RnJvbU1hdHJpeChhc3NheXMoZGF0KSR1bnN0cmFuZGVkLCBjb2xEYXRhID0gbWV0YSwgZGVzaWduID0gfiAxKSAKZGRzMiA9IERFU2VxMjo6ZXN0aW1hdGVTaXplRmFjdG9ycyhkZHMpClJOQV9jb3VudCA9IERFU2VxMjo6Y291bnRzKGRkczIsIG5vcm1hbGl6ZWQ9VFJVRSkKUk5BX2NvdW50WzE6NSwgMToyXQpgYGAKCmBgYAogICAgICAgICAgICAgICAgICAgVENHQS1MTC1BNzNZLTAxQS0xMVItQTMzSi0wNyBUQ0dBLUUyLUExSVUtMDFBLTExUi1BMTRELTA3CkVOU0cwMDAwMDAwMDAwMy4xNSAgICAgICAgICAgICAgICAgICA2MDM0LjI3MTY4ICAgICAgICAgICAgICAgICAgIDk1MS44MjU3NjQKRU5TRzAwMDAwMDAwMDA1LjYgICAgICAgICAgICAgICAgICAgICAgMTMuNzYzMTMgICAgICAgICAgICAgICAgICAgICA1LjU5ODk3NQpFTlNHMDAwMDAwMDA0MTkuMTMgICAgICAgICAgICAgICAgICAgMTg2NC4wNDM3MyAgICAgICAgICAgICAgICAgIDE4ODEuMjU1NjI4CkVOU0cwMDAwMDAwMDQ1Ny4xNCAgICAgICAgICAgICAgICAgICAyMTU0Ljc4OTgyICAgICAgICAgICAgICAgICAgMTc0NS43NjA0MzEKRU5TRzAwMDAwMDAwNDYwLjE3ICAgICAgICAgICAgICAgICAgICA2MjQuNTAxOTYgICAgICAgICAgICAgICAgICAgNDUwLjE1NzU5NwpgYGAKClRvIHBlcmZvcm0gc3Vydml2YWwgYW5hbHlzaXMgd2l0aCBib3RoIGNsaW5pY2FsL2RlbW9ncmFwaGljIHZhcmlhYmxlcyBhbmQgb21pY3MgZGF0YSwgaW4gdGhlIGZvbGxvd2luZyBjb2RlIHdlIGV4dHJhY3QgZmVtYWxlIGJyZWFzdCBjYW5jZXIgcGF0aWVudHMgd2l0aCB0aGVpciBjb3JyZXNwb25kaW5nIHN1cnZpdmFsIG91dGNvbWVzLCBjbGluaWNhbC9kZW1vZ3JhcGhpYyB2YXJpYWJsZXMgYW5kIFJOQS1zZXEgZmVhdHVyZXMuCgpgYGB7cn0KbWV0YSR0aW1lID0gYXBwbHkobWV0YVssIGMoImRheXNfdG9fZGVhdGgiLCAiZGF5c190b19sYXN0X2ZvbGxvd191cCIpXSwgMSwgbWF4LCBuYS5ybSA9IFRSVUUpIC8gMzY1LjI1Cm1ldGEkc3RhdHVzID0gbWV0YSR2aXRhbF9zdGF0dXMKbWV0YSRhZ2UgPSBtZXRhJGFnZV9hdF9kaWFnbm9zaXMgLyAzNjUuMjUKY2xpbiA9IHN1YnNldChtZXRhLCBnZW5kZXIgPT0gImZlbWFsZSIgJiAhZHVwbGljYXRlZChzdWJtaXR0ZXJfaWQpICYgdGltZSA+IDAgJiAhaXMubmEoYWdlKSkKY2xpbiA9IGNsaW5bb3JkZXIoY2xpbiRzdWJtaXR0ZXJfaWQpLCBdClJOQV9jb3VudCA9IFJOQV9jb3VudFssIHJvd25hbWVzKGNsaW4pXQpgYGAKCjo6OnsuaW5mby1ib3ggLm5vdGV9ClRoZSBSL0Jpb2NvbmR1Y3RvciBwYWNrYWdlICoqVENHQWJpb2xpbmtzKiogY2Fubm90IHJldHJpZXZlIGFueSBwcm90ZW9taWNzIG9yIG1ldGFib2xvbWljcyBkYXRhLgpJdCBpcyBhbHdheXMgdXNlZnVsIHRvIGxvb2sgYXQgeW91ciBkYXRhIGZpcnN0LCBpbiBwYXJ0aWN1bGFyIHRoZSBkYXRhIHR5cGUgYW5kIGRpbWVuc2lvbnMgKGkuZS4gbnVtYmVycyBvZiByb3dzIGFuZCBjb2x1bW5zIGZvciBhIGRhdGEgZnJhbWUgb3IgbWF0cml4KS4KOjo6Cgo8YnI+CgojIFN1cnZpdmFsIGFuYWx5c2lzIHdpdGggbG93LWRpbWVuc2lvbmFsIGlucHV0IGRhdGEgey19CgojIyBOb25wYXJhbWV0cmljIHN1cnZpdmFsIGFuYWx5c2lzIHstfQoKRm9yIHRoZSBkYXRhIG9mIFRDR0EgYnJlYXN0IGNhbmNlciBwYXRpZW50cyB0aGF0IHdlIGV4dHJhY3RlZCBpbiB0aGUgcHJldmlvdXMgc2VjdGlvbiwgS2FwbGFuLU1laWVyIGVzdGltYXRlcyBvZiB0aGUgc3Vydml2YWwgcHJvYmFiaWxpdGllcyBjYW4gYmUgb2J0YWluZWQgdmlhIGZ1bmN0aW9uIGBzdXJ2Zml0KClgIGZyb20gWyoqc3Vydml2YWwqKl0oaHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT1zdXJ2aXZhbCkgcGFja2FnZS4KVGhlIGRhc2hlZCBsaW5lcyBpbiB0aGUgZm9sbG93aW5nIGZpZ3VyZSBpbmRpY2F0ZSB0aGUgbWVkaWFuIHN1cnZpdmFsIHRpbWUuCgpgYGB7cn0KIyBLYXBsYW4tTWVpZXIgKEtNKSBlc3RpbWF0aW9uCmNsaW4kc3RhdHVzW2NsaW4kc3RhdHVzID09ICJEZWFkIl0gPSAxCmNsaW4kc3RhdHVzW2NsaW4kc3RhdHVzID09ICJBbGl2ZSJdID0gMApjbGluJHN0YXR1cyA9IGFzLm51bWVyaWMoY2xpbiRzdGF0dXMpCnNmaXQgPSBzdXJ2aXZhbDo6c3VydmZpdChTdXJ2KHRpbWUsIHN0YXR1cykgfiAxLCBkYXRhID0gY2xpbikKCiMgY2FsY3VsYXRlIHN1cnZpdmFsIHByb2JhYmlsaXR5IGF0IDEtLCAzLSBhbmQgNS15ZWFyIHRpbWUgcG9pbnRzCnN1bW1hcnkoc2ZpdCwgdGltZXM9YygxLDMsNSkpCnRoZW1lX3NldCh0aGVtZV9idygpKQpnZ3N1cnYgPSBzdXJ2bWluZXI6Omdnc3VydnBsb3Qoc2ZpdCwgY29uZi5pbnQgPSBUUlVFLCByaXNrLnRhYmxlID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4bGFiID0gIlRpbWUgc2luY2UgZGlhZ25vc2lzICh5ZWFyKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQgPSAibm9uZSIsIHN1cnYubWVkaWFuLmxpbmUgPSAiaHYiKQpnZ3N1cnYkcGxvdCA9IGdnc3VydiRwbG90ICsgYW5ub3RhdGUoInRleHQiLCB4ID0gMjAsIHkgPSAwLjksIGxhYmVsPSAiKyAgQ2Vuc29yIikKZ2dzdXJ2CmBgYAohW19LYXBsYW4tTWVpZXIgY3VydmUgZm9yIDEwNjEgQlJDQSBwYXRpZW50cyBkYXRhIGZyb20gVENHQS5fXShmaWcvVENHQV9zdXJ2X2ttMS5wbmcpe3dpZHRoPTYwJX0KCjxicj4KClRvIGNvbXBhcmUgdGhlIHN1cnZpdmFsIGN1cnZlcyBvZiB0d28gZ3JvdXBzIG9mIHBhdGllbnRzLCBmb3IgZXhhbXBsZSwgdHJlYXRtZW50IChpLmUuIHBoYXJtYWNldXRpY2FsIG9yIHJhZGlhdGlvbiB0aGVyYXB5KSBvciBub250cmVhdG1lbnQsIHRoZSBgUmAgZnVuY3Rpb24gYHN1cnZpdmFsOjpzdXJ2ZGlmZigpYCBjYW4gcGVyZm9ybSB0aGUgbG9nLXJhbmsgdGVzdCB0byBjb21wYXJlIHR3byBzdXJ2aXZhbCBjdXJ2ZXMuCkFsdGVybmF0aXZlbHksIHRoZSBgUmAgZnVuY3Rpb24gYHN1cnZpdmFsOjpzdXJ2Zml0YCB3aXRoIGEgZm9ybXVsYSBpbmNsdWRpbmcgdGhlIHRyZWF0bWVudCBncm91cCBhcyBhIGNvdmFyaWF0ZSBjYW4gcmV0dXJuIHRoZSAoS00pIHN1cnZpdmFsIHByb2JhYmlsaXRpZXMgZm9yIGVhY2ggZ3JvdXBzLiAKVGhlbiB0aGUgYFJgIGZ1bmN0aW9uIGBzdXJ2bWluZXI6Omdnc3VydnBsb3QoKWAgd2l0aCBhIGBzdXJ2Zml0YCBvYmplY3Qgd2lsbCBkcmF3IHRoZSB0d28gc3Vydml2YWwgY3VydmVzIGFuZCBwZXJmb3JtIHRoZSBsb2ctcmFuayB0ZXN0IGFzIHNob3duIGluIHRoZSBmb2xsb3dpbmcgZmlndXJlLgoKYGBge3J9CnN1cnZpdmFsOjpzdXJ2ZGlmZihTdXJ2KHRpbWUsIHN0YXR1cykgfiB0cmVhdG1lbnRzLCBkYXRhID0gY2xpbikKCnNmaXQyID0gc3VydmZpdChTdXJ2KHRpbWUsIHN0YXR1cykgfiB0cmVhdG1lbnRzLCBkYXRhID0gY2xpbikKZ2dzdXJ2ID0gZ2dzdXJ2cGxvdChzZml0MiwgY29uZi5pbnQgPSBUUlVFLCByaXNrLnRhYmxlID0gVFJVRSwgCiAgICAgICAgICAgeGxhYiA9ICJUaW1lIHNpbmNlIGRpYWdub3NpcyAoeWVhcikiLCBsZWdlbmQgPSBjKC42LC45KSwKICAgICAgICAgICBsZWdlbmQubGFicyA9IGMoIk5vIiwgIlllcyIpLCBsZWdlbmQudGl0bGUgPSAiVHJlYXRtZW50IiwgIAogICAgICAgICAgIHJpc2sudGFibGUueS50ZXh0LmNvbCA9IFRSVUUsIHJpc2sudGFibGUueS50ZXh0ID0gRkFMU0UpCmdnc3VydiRwbG90ID0gZ2dzdXJ2JHBsb3QgKyAKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAyMSwgeSA9IDEsIGxhYmVsPSAiKyAgQ2Vuc29yIikgKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDIyLCB5ID0gLjg4LCBsYWJlbD0gcGFzdGUwKCJMb2ctcmFuayB0ZXN0OlxuIiwgc3Vydl9wdmFsdWUoc2ZpdDIpJHB2YWwudHh0KSkKZ2dzdXJ2CmBgYAohW19LYXBsYW4tTWVpZXIgY3VydmVzIG9mIHRoZSBCUkNBIHBhdGllbnRzJyBzdXJ2aXZhbCBkYXRhIGZyb20gVENHQSBncm91cGVkIGJ5IHRyZWF0bWVudCAoaS5lLiBwaGFybWFjZXV0aWNhbCBvciByYWRpYXRpb24gdGhlcmFweSkgb3Igbm9udHJlYXRtZW50LiBUaGUgbG9nLXJhbmsgdGVzdCBpcyB0byBjb21wYXJlIHRoZSB0d28gc3Vydml2YWwgZGlzdHJpYnV0aW9ucyBjb3JyZXNwb25kaW5nIHRvIHRoZSB0d28gZ3JvdXBzIG9mIHBhdGllbnRzLl9dKGZpZy9UQ0dBX3N1cnZfa20yLnBuZyl7d2lkdGg9NjAlfQoKPGJyPgoKVG8gYW5hbHl6ZSBpZiBhIGNvbnRpbnVvdXMgdmFyaWFibGUsIGUuZy4gYWdlLCBpcyBhc3NvY2lhdGVkIHdpdGggdGhlIHN1cnZpdmFsIG91dGNvbWVzLCB3ZSBjYW4gdXNlIHRoZSBgUmAgZnVuY3Rpb24gYGNveHBoKClgIGZvciBmaXR0aW5nIGEgQ294IG1vZGVsLCB3aGljaCBpcyBzaW1pbGFyIHRvIHRoZSBmdW5jdGlvbiBgbG0oKWAgZm9yIGZpdHRpbmcgbGluZWFyIG1vZGVscy4KCmBgYHtyfQpmaXRfY294ID0gY294cGgoU3Vydih0aW1lLCBzdGF0dXMpIH4gYWdlLCBkYXRhID0gY2xpbikKc3VtbWFyeShmaXRfY294KQpgYGAKYGBgCkNhbGw6CmNveHBoKGZvcm11bGEgPSBTdXJ2KHRpbWUsIHN0YXR1cykgfiBhZ2UsIGRhdGEgPSBjbGluKQoKICBuPSAxMDQ3LCBudW1iZXIgb2YgZXZlbnRzPSAxNDkgCiAgICgxNCBvYnNlcnZhdGlvbnMgZGVsZXRlZCBkdWUgdG8gbWlzc2luZ25lc3MpCgogICAgICAgIGNvZWYgZXhwKGNvZWYpIHNlKGNvZWYpICAgICB6IFByKD58enwpICAgIAphZ2UgMC4wMzQyNDQgIDEuMDM0ODM3IDAuMDA2NzAzIDUuMTA5IDMuMjRlLTA3ICoqKgotLS0KU2lnbmlmLiBjb2RlczogIDAg4oCYKioq4oCZIDAuMDAxIOKAmCoq4oCZIDAuMDEg4oCYKuKAmSAwLjA1IOKAmC7igJkgMC4xIOKAmCDigJkgMQoKICAgIGV4cChjb2VmKSBleHAoLWNvZWYpIGxvd2VyIC45NSB1cHBlciAuOTUKYWdlICAgICAxLjAzNSAgICAgMC45NjYzICAgICAxLjAyMSAgICAgMS4wNDkKCkNvbmNvcmRhbmNlPSAwLjYzOSAgKHNlID0gMC4wMjkgKQpMaWtlbGlob29kIHJhdGlvIHRlc3Q9IDI2LjM0ICBvbiAxIGRmLCAgIHA9M2UtMDcKV2FsZCB0ZXN0ICAgICAgICAgICAgPSAyNi4xICBvbiAxIGRmLCAgIHA9M2UtMDcKU2NvcmUgKGxvZ3JhbmspIHRlc3QgPSAyNi42MyAgb24gMSBkZiwgICBwPTJlLTA3CmBgYAoKVGhlIENveCBtb2RlbCBhc3N1bWVzIHByb3BvcnRpb25hbCBoYXphcmRzIGFuZCBsb2ctbGluZWFyaXR5IG9mIHRoZSBjb3ZhcmlhdGVzLgpUbyBjaGVjayB0aGUgbG9nLWxpbmVhcml0eSBmb3IgYSBjbGluaWNhbCBvciBkZW1vZ3JhcGhpYyB2YXJpYWJsZSwgZS5nLiBhZ2UsIHdlIGNhbiBmaXQgYSBwZW5hbGl6ZWQgc21vb3RoaW5nIHNwbGluZSBmb3IgYWdlIGVmZmVjdC4KVGhlIGZvbGxvd2luZyBjb2RlIHNob3dzIHRoYXQgdGhlIG5vbmxpbmVhciBwYXJ0IG9mIHRoZSBzbW9vdGhpbmcgc3BsaW5lIGhhcyBhIHNpZ25pZmljYW50IGVmZmVjdCAoJHAgPSAwLjAwMDEzJCkuClRodXMsIHRoZSBhc3N1bXB0aW9uIG9mIGxvZy1saW5lYXJpdHkgZm9yIGFnZSBpcyBub3Qgc2F0aXNmaWVkLgoKYGBge3J9CmZpdF9jb3hfc3BsaW5lID0gY294cGgoU3Vydih0aW1lLCBzdGF0dXMpIH4gcHNwbGluZShhZ2UpLCBkYXRhID0gY2xpbikKZml0X2NveF9zcGxpbmUKYGBgCmBgYApDYWxsOgpjb3hwaChmb3JtdWxhID0gU3Vydih0aW1lLCBzdGF0dXMpIH4gcHNwbGluZShhZ2UpLCBkYXRhID0gY2xpbikKCiAgICAgICAgICAgICAgICAgICAgICAgICBjb2VmIHNlKGNvZWYpICAgICAgc2UyICAgIENoaXNxICAgREYgICAgICAgcApwc3BsaW5lKGFnZSksIGxpbmVhciAgMC4wMzUwOSAgMC4wMDU3NyAgMC4wMDU3NyAzNi45ODMyMyAxLjAwIDEuMmUtMDkKcHNwbGluZShhZ2UpLCBub25saW4gICAgICAgICAgICAgICAgICAgICAgICAgICAgMjAuNjkxNDYgMy4wMyAwLjAwMDEzCgpJdGVyYXRpb25zOiA1IG91dGVyLCAxNSBOZXd0b24tUmFwaHNvbgogICAgIFRoZXRhPSAwLjgyOCAKRGVncmVlcyBvZiBmcmVlZG9tIGZvciB0ZXJtcz0gNCAKTGlrZWxpaG9vZCByYXRpbyB0ZXN0PTQ2LjQgIG9uIDQuMDMgZGYsIHA9MmUtMDkKbj0gMTA0NywgbnVtYmVyIG9mIGV2ZW50cz0gMTQ5IAogICAoMTQgb2JzZXJ2YXRpb25zIGRlbGV0ZWQgZHVlIHRvIG1pc3NpbmduZXNzKQpgYGAKClRvIGNoZWNrIHByb3BvcnRpb25hbCBoYXphcmRzIG9mIGFnZSwgd2UgY2FuIGFkZCBhIHRpbWUtZGVwZW5kZW50IGNvdmFyaWF0ZSAkYWdlIFx0aW1lcyBnKHQpJCwgd2hlcmUgJGcodCkkIGlzIGEga25vd24gZnVuY3Rpb24gZS5nLiAkZyh0KSA9IFxsb2cgdCQuClRoZSBmb2xsb3dpbmcgY29kZSBzaG93cyB0aGF0IHRoZSB0aW1lLWRlcGVuZGVudCBhZ2UgaXMgc2lnbmlmaWNhbnQgdXNpbmcgYSBzY29yZSB0ZXN0ICgkcCA9IDAuMDA4NyQpLgpUaHVzLCB0aGUgYXNzdW1wdGlvbiBvZiBwcm9wb3J0aW9uYWwgaGF6YXJkcyBmb3IgYWdlIGlzIG5vdCBzYXRpc2ZpZWQuIFRoZSBhYm92ZSB0d28gdGVzdHMgaW5kaWNhdGUgYSBub24tbG9nbGluZWFyIG9yIHRpbWUtZGVwZW5kZW50IGFzc29jaWF0aW9uIG9mIGFnZSB3aXRoIHRoZSBzdXJ2aXZhbCBvdXRjb21lcy4KCmBgYHtyfQpzdXJ2aXZhbDo6Y294LnpwaChmaXRfY294LCB0cmFuc2Zvcm0gPSAibG9nIikgCmBgYApgYGAKICAgICAgIGNoaXNxIGRmICAgIHAKYWdlICAgICA2Ljg4ICAxIDAuMDA4NwpHTE9CQUwgIDYuODggIDEgMC4wMDg3CmBgYAo6Ojp7LmluZm8tYm94IC5ub3RlfQpIZXJlIHRoZSBhcHByb2FjaGVzIGZvciBjaGVja2luZyBsb2ctbGluZWFyaXR5IG9yIHByb3BvcnRpb25hbCBoYXphcmRzIGNhbiBvbmx5IGJlIHVzZWQgaW4gbG93LWRpbWVuc2lvbmFsIGRhdGEgc2V0dGluZ3MuCldoZW4gaW5jbHVkaW5nIGhpZ2gtZGltZW5zaW9uYWwgb21pY3MgZGF0YSwgdGhlcmUgYXJlIG5vIHN0YW5kYXJkIGFwcHJvYWNoZXMgZm9yIGNoZWNraW5nIGxvZy1saW5lYXJpdHkgb3IgcHJvcG9ydGlvbmFsIGhhemFyZHMgY3VycmVudGx5Lgo6OjoKCjxicj4KCiMjIEZlYXR1cmUgcHJlc2VsZWN0aW9uL2ZpbHRlcmluZyB7LX0KCkZyb20gYSBwcmFjdGljYWwgcG9pbnQgb2Ygdmlldywgc2luY2UgbW9zdCBvbWljcyBwcm9maWxlcyBjb250YWluIHRob3VzYW5kcyBvZiB2YXJpYWJsZXMgYW5kIG1vc3Qgc3VwZXJ2aXNlZCBzdGF0aXN0aWNhbCBtZXRob2RzIGFyZSBub3Qgc3VpdGVkIGZvciBoaWdoIGRpbWVuc2lvbmFsIG9taWNzIGZlYXR1cmVzLCBpdCBpcyBiZXR0ZXIgdG8gZmlsdGVyIHRoZSBvbWljcyBmZWF0dXJlcyBmaXJzdC4KSW4gYWRkaXRpb24sIHdlIHBlcmNlaXZlIHRoYXQgbm90IHRvbyBtYW55IG9taWNzIGZlYXR1cmVzIGFyZSByZWxldmFudCB0byBvbmUgbWVkaWNhbCBwcm9ibGVtLgpXZSB3aWxsIGRlbW9uc3RyYXRlICoqdHdvIGRpZmZlcmVudCBmaWx0ZXJpbmcgYXBwcm9hY2hlcyBmb3IgaGlnaC1kaW1lbnNpb25hbCBvbWljcyBkYXRhKio6CgotIFAtdmFsdWUtYmFzZWQgZmlsdGVyaW5nCi0gVmFyaWFuY2UtYmFzZWQgZmlsdGVyaW5nCgojIyMgUC12YWx1ZSBmaWx0ZXIgey19CgpCZWZvcmUgam9pbnQgYW5hbHl6aW5nIHRoZSBhc3NvY2lhdGlvbnMgYmV0d2VlbiB0aGUgdGhvdXNhbmRzIG9mIG9taWNzIGZlYXR1cmVzIGFuZCBzdXJ2aXZhbCBvdXRjb21lcywgb25lIGNhbiBhbmFseXplIHRoZSBhc3NvY2lhdGlvbiBiZXR3ZWVuIGVhY2ggb21pY3MgZmVhdHVyZSBhbmQgdGhlIHN1cnZpdmFsIG91dGNvbWVzLCBhbmQgZmlsdGVyIG9taWNzIGZlYXR1cmVzIGF0IGEgc3RhdGlzdGljYWwgc2lnbmlmaWNhbmNlIGxldmVsICQwLjEkIG9yICQwLjIkIChsYXJnZXIgdGhhbiAwLjA1IHRvIHJlZHVjZSBmYWxzZSBuZWdhdGl2ZSBpZGVudGlmaWNhdGlvbiBvZiBvbWljcyBmZWF0dXJlcyBpbiBtdWx0aXZhcmlhdGUgYW5hbHlzaXMpLgpGb3IgZGVtb25zdHJhdGlvbiwgYmFzZWQgb24gdGhlICQxMDAkIG1STkEtU2VxIGZlYXR1cmVzIGZyb20gVENHQSBicmVhc3QgY2FuY2VyIHBhdGllbnRzIHByZXByb2Nlc3NlZCBwcmV2aW91c2x5LCB0aGUgY29kZSBiZWxvdyBmaWx0ZXJzIG9taWNzIGZlYXR1cmVzIGF0IHRoZSBzdGF0aXN0aWNhbCBzaWduaWZpY2FuY2UgbGV2ZWwgJDAuMiQsIGkuZS4gJHAgPCAwLjIkLgoKYGBge3J9ClJOQV9sb2cyY291bnQgPSBsb2cyKFJOQV9jb3VudFsxOjEwMCwgXSArIDEpCnB2YWx1ZXMgPC0gcmVwKE5BLCBucm93KFJOQV9sb2cyY291bnQpKQpmb3IoaiBpbiAxOm5yb3coUk5BX2xvZzJjb3VudCkpIHsKICBmaXRfY294ID0gY294cGgoU3VydihjbGluJHRpbWUsIGNsaW4kc3RhdHVzKSB+IFJOQV9sb2cyY291bnRbaiwgXSwgZGF0YSA9IGNsaW4pCiAgcHZhbHVlc1tqXSA9IHN1bW1hcnkoZml0X2NveCkkY29lZmZpY2llbnRzWywgIlByKD58enwpIl0KfQpmaWx0ZXJlZF9ybmEgPC0gUk5BX2xvZzJjb3VudFt3aGljaChwdmFsdWVzIDwgMC4yKSwgXQpgYGAKCiMjIyBWYXJpYW5jZSBmaWx0ZXIgey19CgpUaGUgb3RoZXIgY29tbW9uIGFuZCBlYXN5IHdheSB0byBkZWNyZWFzZSB0aGUgbnVtYmVyIG9mIG9taWNzIGZlYXR1cmVzIGlzIHRvIGZpbHRlciB0aGUgbW9zdCB2YXJpYWJsZSBvbmVzIGZvciBmdXJ0aGVyIGFuYWx5c2lzLgpOb3RlIHRoYXQgdGhlIHZhcmlhbmNlLWJhc2VkIGZpbHRlcmluZyBzdGVwIHNob3VsZCBiZSBkb25lIGJlZm9yZSBkYXRhIHN0YW5kYXJkaXphdGlvbiAoaS5lLiBjYWxjdWxhdGluZyAkeiQtc2NvcmUpLCBidXQgY2FuIGJlIHBlcmZvcm1lZCBhZnRlciBjb3VudCBkYXRhIG5vcm1hbGl6YXRpb24gYW5kIGxvZzItdHJhbnNmb3JtYXRpb24gZm9yIGluc3RhbmNlLgoKVGhlIGBSYCBwYWNrYWdlIFsqKk0zQyoqXShodHRwczovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvTTNDLykgW0BKb2huMjAyMF0gcHJvdmlkZXMgYSBmaWx0ZXIgZnVuY3Rpb24gYGZlYXR1cmVmaWx0ZXIoKWAgYnkgdXNpbmcgZGlmZmVyZW50IHZhcmlhbmNlLXR5cGUgbWV0cmljcywgZm9yIGV4YW1wbGUsIHZhcmlhbmNlLCBtZWRpYW4gYWJzb2x1dGUgZGV2aWF0aW9uIChNQUQpLCBjb2VmZmljaWVudCBvZiB2YXJpYXRpb24gKEEpIGFuZCBpdHMgc2Vjb25kIG9yZGVyIGRlcml2YXRpdmUgKEEyKS4KVGhlIHNpbXBsZSB2YXJpYW5jZSBmaWx0ZXIgY2FuIGJlIHVzZWQgaWYgdGhlIHZhcmlhbmNlIGRvZXMgbm90IGNoYW5nZSB3aXRoIHRoZSBjb3JyZXNwb25kaW5nIG1lYW4sIG90aGVyd2lzZSB0aGUgY29lZmZpY2llbnQgb2YgdmFyaWF0aW9uIGNhbiBiZSB1c2VkLgpJZiB0aGUgb21pY3MgZGF0YSBpbmNsdWRlIG91dGxpZXJzLCBNQUQgZmlsdGVyIGlzIG1vcmUgcm9idXN0IHRoYW4gdGhlIHZhcmlhbmNlIGZpbHRlci4KQmFzZWQgb24gdGhlICQ2MDY2MCQgbVJOQS1TZXEgZmVhdHVyZXMgZnJvbSBUQ0dBIGJyZWFzdCBjYW5jZXIgcGF0aWVudHMgcHJlcHJvY2Vzc2VkIHByZXZpb3VzbHksIHRoZSBjb2RlIGJlbG93IGV4dHJhY3RzIHRoZSAkMVwlJCBtb3N0IHZhcmlhYmxlIGZlYXR1cmVzIHVzaW5nIHZhcmlhbmNlIGFzIGEgZmlsdGVyaW5nIG1ldHJpYy4KCmBgYHtyfQpSTkFfbG9nMmNvdW50ID0gbG9nMihSTkFfY291bnQgKyAxKQpmaWx0ZXJlZCA9IE0zQzo6ZmVhdHVyZWZpbHRlcihSTkFfbG9nMmNvdW50LCBwZXJjZW50aWxlID0gMSwgbWV0aG9kID0gJ3ZhcicsIHRvcE4gPSA1KQpmaWx0ZXJlZF9ybmExID0gZmlsdGVyZWQkZmlsdGVyZWRfZGF0YQpgYGAKYGBgCioqKmZlYXR1cmUgZmlsdGVyIGZ1bmN0aW9uKioqCmV4dHJhY3RpbmcgdGhlIG1vc3QgdmFyaWFibGU6IDEgcGVyY2VudApmZWF0dXJlcyB0byBzdGFydCB3aXRoOiA2MDY2MApwZXJmb3JtaW5nIGNhbGN1bGF0aW9ucyBmb3IgdmFyaWFuY2UKcHJpbnRpbmcgdG9wTiBtb3N0IHZhcmlhYmxlIGZlYXR1cmVzIHdpdGggc3RhdGlzdGljcy4uLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmZWF0dXJlICAgICAgbWVhbiAgICAgIHZhciAgICAgICBzZApFTlNHMDAwMDAxNjY1MDkuMTIgRU5TRzAwMDAwMTY2NTA5LjEyICA2LjA4NDMzNiAzMS42MDQ1MCA1LjYyMTc4OApFTlNHMDAwMDAxMTA0ODQuNyAgIEVOU0cwMDAwMDExMDQ4NC43IDExLjAwNDM0NiAyNi4yMjY4NiA1LjEyMTIxNgpFTlNHMDAwMDAxNTMwMDIuMTIgRU5TRzAwMDAwMTUzMDAyLjEyICA4LjIyMjM4NiAyNS44Nzc4MCA1LjA4NzAyMgpFTlNHMDAwMDAxMzQxODQuMTMgRU5TRzAwMDAwMTM0MTg0LjEzICA1LjM3MTE1OCAyMy4yODc1NiA0LjgyNTcxOQpFTlNHMDAwMDAxNjAxODIuMyAgIEVOU0cwMDAwMDE2MDE4Mi4zICA5LjkwMTU2NyAyMS40ODQwMyA0LjYzNTA4NwpmZWF0dXJlcyByZW1haW5pbmc6IDYwNwpgYGAKCkFub3RoZXIgdmFyaWFuY2UtdHlwZSBmaWx0ZXIgaXMgdG8gcmVtYWluIGZlYXR1cmVzIHdpdGggY2VydGFpbiBwZXJjZW50YWdlIG9mICoqY3VtdWxhdGl2ZSB2YXJpYW5jZXMqKiwgd2hpY2ggd2lsbCB1c3VhbGx5IGZpbHRlciBmZXdlciBmZWF0dXJlcyB0aGFuIHRoZSBhcHByb2FjaGVzIGFib3ZlLgpUaGUgY29kZSBiZWxvdyBleHRyYWN0cyB0aGUgbW9zdCB2YXJpYWJsZSBmZWF0dXJlcyBleHBsYWluaW5nICQxXCUkICoqY3VtdWxhdGl2ZSB2YXJpYW5jZXMqKi4KCmBgYHtyfQpjdW1zdW1fdmFyID0gY3Vtc3VtKGZpbHRlcmVkJHN0YXRpc3RpY3MkdmFyKQpjdW1zdW1fY3V0b2ZmID0gY3Vtc3VtX3ZhcltsZW5ndGgoY3Vtc3VtX3ZhcildICogMC4wMQpmaWx0ZXJlZF9uYW1lcyA9IGZpbHRlcmVkJHN0YXRpc3RpY3MkZmVhdHVyZVtjdW1zdW1fdmFyIDwgY3Vtc3VtX2N1dG9mZl0KYGBgCgo8YnI+CgojIFN1cnZpdmFsIGFuYWx5c2lzIHdpdGggaGlnaC1kaW1lbnNpb25hbCBpbnB1dCBkYXRhIHstfQoKIyMgVW5zdXBlcnZpc2VkIGxlYXJuaW5nIChvbWljcyBkYXRhKSB7LX0KCkluIHRoaXMgc2VjdGlvbiB3ZSB3aWxsIHVzZSB0aGUgbVJOQS1TZXEgZGF0YSBvZiBicmVhc3QgY2FuY2VyIHBhdGllbnRzIGZyb20gVENHQS4KVGhlIGZvbGxvd2luZyB1bnN1cGVydmlzZWQgbWV0aG9kcyBjYW4gYmUgYXBwbGllZCB0byBvdGhlciBvbWljcyBkYXRhIGFzIHdlbGwgKHRoZSBzYW1lIGFwcGxpZXMgdG8gdGhlIHN1cGVydmlzZWQgbGVhcm5pbmcgbWV0aG9kcykuCk9uZSBpbXBvcnRhbnQgdGhpbmcgaXMgdGhhdCB0aGUgaW5wdXQgb21pY3MgZGF0YSwgZXNwZWNpYWxseSB0aGUgZGF0YSB0eXBlIGFuZCBkaW1lbnNpb25zLCBzaG91bGQgYmUgc3VpdGVkIHRvIHRoZSBtZXRob2RzLgoKVW5zdXBlcnZpc2VkIGxlYXJuaW5nIGZvciBvbWljcyBkYXRhIGNhbiBiZSBoZWxwZnVsIHRvIGV4cGxvcmUgc3VicG9wdWxhdGlvbnMgb2YgdGhlIGRhdGEsIGZvciBleGFtcGxlLCBwYXRpZW50cyBmcm9tIG9uZSBjYW5jZXIgdHlwZSBjYW4gYmUgZGl2aWRlZCB0byBzZXZlcmFsIG9taWNzLXJlbGF0ZWQgc3VidHlwZXMuCldlIGRlbW9uc3RyYXRlIHRocmVlIHVuc3VwZXJ2aXNlZCBsZWFybmluZyBtZXRob2RzLCBpLmUuIHByaW5jaXBhbCBjb21wb25lbnQgYW5hbHlzaXMgKFBDQSksICR0JC1zdG9jaGFzdGljIG5laWdoYm91ciBlbWJlZGRpbmcgKCR0JC1TTkUpIGFuZCB1bmlmb3JtIG1hbmlmb2xkIGFwcHJveGltYXRpb24gYW5kIHByb2plY3Rpb24gKFVNQVApLCBiYXNlZCBvbiB0aGUgUEFNNTAgZ2VuZXMgW0BQYXJrZXIyMDA5XS4KVGhlIGBSYCBwYWNrYWdlIFsqKk0zQyoqXShodHRwczovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvTTNDLykgW0BKb2huMjAyMF0gcHJvdmlkZXMgdGhlIGFuYWx5c2VzIGFuZCB2aXN1YWxpemF0aW9uIG9mIGFsbCB0aGUgdGhyZWUgbWV0aG9kcy4KCmBgYHtyfQojIGV4dHJhY3QgdGhlIFBBTTUwIGdlbmVzIG9mIFRDR0EtQlJDQSBwYXRpZW50cwpUQ0dBX1BBTTUwID0gUk5BX2NvdW50W3NhcHBseShzdHJzcGxpdChyb3duYW1lcyhSTkFfY291bnQpLCAiLiIsIGZpeGVkID0gVFJVRSksIGZ1bmN0aW9uKHgpIHhbWzFdXSkgJWluJSBjKAogICJFTlNHMDAwMDAwNzcxNTIiLCAiRU5TRzAwMDAwMDg5Njg1IiwgIkVOU0cwMDAwMDE0MzIyOCIsICJFTlNHMDAwMDAwOTQ4MDQiLCAiRU5TRzAwMDAwMTM0MDU3IiwKICAiRU5TRzAwMDAwMTc2ODkwIiwgIkVOU0cwMDAwMDEwMTA1NyIsICJFTlNHMDAwMDAxMzgxODAiLCAiRU5TRzAwMDAwMTY1MzA0IiwgIkVOU0cwMDAwMDA4MDk4NiIsCiAgIkVOU0cwMDAwMDE3MTg0OCIsICJFTlNHMDAwMDAxNzUwNjMiLCAiRU5TRzAwMDAwMTE3NzI0IiwgIkVOU0cwMDAwMDE2NDYxMSIsICJFTlNHMDAwMDAxNzQzNzEiLAogICJFTlNHMDAwMDAwOTE2NTEiLCAiRU5TRzAwMDAwMDExNDI2IiwgIkVOU0cwMDAwMDEwNTE3MyIsICJFTlNHMDAwMDAxMTczOTkiLCAiRU5TRzAwMDAwMTQ4NzczIiwKICAiRU5TRzAwMDAwMTQyOTQ1IiwgIkVOU0cwMDAwMDEzMzYyNyIsICJFTlNHMDAwMDAxMzY5OTciLCAiRU5TRzAwMDAwMTQ2NjQ4IiwgIkVOU0cwMDAwMDE4NjA4MSIsCiAgIkVOU0cwMDAwMDA5MjYyMSIsICJFTlNHMDAwMDAwNjIwMzgiLCAiRU5TRzAwMDAwMjYxODU3IiwgIkVOU0cwMDAwMDEyODQyMiIsICJFTlNHMDAwMDAwNTQ1OTgiLAogICJFTlNHMDAwMDAxMDQzMzIiLCAiRU5TRzAwMDAwMTg2ODQ3IiwgIkVOU0cwMDAwMDA5MTgzMSIsICJFTlNHMDAwMDAxNDE0MjQiLCAiRU5TRzAwMDAwMTA3MjYyIiwKICAiRU5TRzAwMDAwMTg2ODY4IiwgIkVOU0cwMDAwMDA4MjE3NSIsICJFTlNHMDAwMDAxNzE2MDQiLCAiRU5TRzAwMDAwMTE1NjQ4IiwgIkVOU0cwMDAwMDE3MTc5MSIsCiAgIkVOU0cwMDAwMDEzNTY3OSIsICJFTlNHMDAwMDAxNzE0MjgiLCAiRU5TRzAwMDAwMTI5NTE0IiwgIkVOU0cwMDAwMDEwNjYwNSIsICJFTlNHMDAwMDAwOTk5NTMiLAogICJFTlNHMDAwMDAxNzM4OTAiLCAiRU5TRzAwMDAwMTYwODY3IiwgIkVOU0cwMDAwMDE0MTczOCIsICJFTlNHMDAwMDAxNTE3MTUiLCAiRU5TRzAwMDAwMTQxNzM2IiksIF0KIyB1c2UgZ2VuZSBzeW1ib2xzIGluc3RlYWQgb2YgRW5zZW1ibCBJRHMKcm93bmFtZXMoVENHQV9QQU01MCkgPSAKICBjKCJVQkUyVCIsICJCSVJDNSIsICJOVUYyIiwgIkNEQzYiLCAiQ0NOQjEiLCAiVFlNUyIsICJNWUJMMiIsICJDRVA1NSIsICJNRUxLIiwgIk5EQzgwIiwgIlJSTTIiLCAKICAgICJVQkUyQyIsICJDRU5QRiIsICJQVFRHMSIsICJFWE8xIiwgIk9SQzZMIiwgIkFOTE4iLCAiQ0NORTEiLCAiQ0RDMjAiLCAiTUtJNjciLCAiS0lGMkMiLCAKICAgICJBQ1RSM0IiLCAiTVlDIiwgIkVHRlIiLCAiS1JUNSIsICJQSEdESCIsICJDREgzIiwgIk1JQSIsICJLUlQxNyIsICJGT1hDMSIsICJTRlJQMSIsICJLUlQxNCIsIAogICAgIkVTUjEiLCAiU0xDMzlBNiIsICJCQUcxIiwgIk1BUFQiLCAiUEdSIiwgIkNYWEM1IiwgIk1MUEgiLCAiQkNMMiIsICJNRE0yIiwgIk5BVDEiLCAiRk9YQTEiLCAKICAgICJCTFZSQSIsICJNTVAxMSIsICJHUFIxNjAiLCAiRkdGUjQiLCAiR1JCNyIsICJUTUVNNDVCIiwgIkVSQkIyIikKCiMgbG9nMi10cmFuc2Zvcm1hdGlvbiBvZiB0aGUgbm9ybWFsaXplZCBjb3VudCBkYXRhClRDR0FfUEFNNTAgPSBsb2cyKFRDR0FfUEFNNTAgKyAxKQpwYW01MCA9IGZhY3RvcihjbGluJHBhcGVyX0JSQ0FfU3VidHlwZV9QQU01MCkKCk0zQzo6cGNhKFRDR0FfUEFNNTAsIGxhYmVscyA9IHBhbTUwLCBkb3RzaXplID0gMywgIGxlZ2VuZHRpdGxlID0gIlN1YnR5cGUiKQpgYGAKIVtfVW5zdXBlcnZpc2VkIGNsdXN0ZXJpbmcgKHByaW5jaXBhbCBjb21wb25lbnQgYW5hbHlzaXMsIFBDQSkgb2YgdHJhbnNjcmlwdG9taWMgZGF0YSBmcm9tIFRDR0EgYnJlYXN0IGNhbmNlciBwYXRpZW50c19dKGZpZy9UQ0dBX3BjYS5wbmcpe3dpZHRoPTUwJX0KCmBgYHtyfQpNM0M6OnRzbmUoVENHQV9QQU01MCwgbGFiZWxzID0gcGFtNTAsIGRvdHNpemUgPSAzLCAgbGVnZW5kdGl0bGUgPSAiU3VidHlwZSIpCmBgYAohW19VbnN1cGVydmlzZWQgY2x1c3RlcmluZyAoJHQkLXN0b2NoYXN0aWMgbmVpZ2hib3VyIGVtYmVkZGluZywgJHQkLVNORSkgb2YgdHJhbnNjcmlwdG9taWMgZGF0YSBmcm9tIFRDR0EgYnJlYXN0IGNhbmNlciBwYXRpZW50c19dKGZpZy9UQ0dBX3RzbmUucG5nKXt3aWR0aD01MCV9CgpgYGB7cn0KTTNDOjp1bWFwKFRDR0FfUEFNNTAsIGxhYmVscyA9IHBhbTUwLCBkb3RzaXplID0gMywgIGxlZ2VuZHRpdGxlID0gIlN1YnR5cGUiKQpgYGAKIVtfVW5zdXBlcnZpc2VkIGNsdXN0ZXJpbmcgKHVuaWZvcm0gbWFuaWZvbGQgYXBwcm94aW1hdGlvbiBhbmQgcHJvamVjdGlvbiwgVU1BUCkgb2YgdHJhbnNjcmlwdG9taWMgZGF0YSBmcm9tIFRDR0EgYnJlYXN0IGNhbmNlciBwYXRpZW50c19dKGZpZy9UQ0dBX3VtYXAucG5nKXt3aWR0aD01MCV9Cgo8YnI+CgojIyBTdXBlcnZpc2VkIGxlYXJuaW5nIChvbWljcyBhbmQgc3Vydml2YWwgZGF0YSkgey19CgpUbyBpbnZlc3RpZ2F0ZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gb21pY3MgZmVhdHVyZXMgYW5kIHN1cnZpdmFsIG91dGNvbWVzLCByZWdyZXNzaW9uIG1ldGhvZHMgKGkuZS4gc3VwZXJ2aXNlZCBsZWFybmluZykgY2FuIGJlIGFwcGxpZWQuIApTaW5jZSBvbWljcyBkYXRhIGFyZSBoaWdoLWRpbWVuc2lvbmFsLCBvbmUgY2FuIHVzZSB1bnN1cGVydmlzZWQgbGVhcm5pbmcgbWV0aG9kcyB0byBzdW1tYXJpemUgYSBmZXcgY29tcG9uZW50cyAoZGltZW5zaW9uIHJlZHVjdGlvbikgYW5kIHJlZ3Jlc3MgdGhlIHN1cnZpdmFsIG91dGNvbWVzIG9uIHRoZSBsb3ctZGltZW5zaW9uYWwgY29tcG9uZW50cyBieSBzb21lIGNsYXNzaWNhbCBzdGF0aXN0aWNhbCBtZXRob2RzLCBlLmcuIGNsYXNzaWNhbCBDb3ggbW9kZWwuClRoZXJlIGFyZSBhbHNvIGZyZXF1ZW50aXN0IGFuZCBCYXllc2lhbiBzdXBlcnZpc2VkIGxlYXJuaW5nIG1ldGhvZHMgc3VpdGVkIHRvIGRpcmVjdGx5IHJlZ3Jlc3MgdGhlIHN1cnZpdmFsIG91dGNvbWVzIG9uIHRoZSBoaWdoLWRpbWVuc2lvbmFsIG9taWNzIGZlYXR1cmVzLgpOb3RlIHRoYXQgcHJlc2VsZWN0aW5nL2ZpbHRlcmluZyB1bHRyYWhpZ2gtZGltZW5zaW9uYWwgb21pY3MgZmVhdHVyZXMgY2FuIGJlIHVzZWZ1bCBiZWZvcmUgcnVubmluZyB0aGUgZnJlcXVlbnRpc3QgYW5kIEJheWVzaWFuIHN1cGVydmlzZWQgbGVhcm5pbmcgbWV0aG9kcy4KCiMjIyBEaW1lbnNpb24gcmVkdWN0aW9uIGZvciBDb3ggbW9kZWxzIHstfQoKVGhlIGZvbGxvd2luZyBjb2RlIGRlbW9uc3RyYXRlcyB0aGUgdXNlIG9mIHRoZSBmaXJzdCB0d28gcHJpbmNpcGFsIGNvbXBvbmVudHMgb2YgUENBIGFzIGNvdmFyaWF0ZXMgZm9yIHRoZSAqKnB1cnBvc2Ugb2Ygc3Vydml2YWwgcHJlZGljdGlvbioqLgpTaW1pbGFybHksIHRoZSBmaXJzdCBjb21wb25lbnRzIGZyb20gJHQkLVNORSBvciBVTUFQIGNhbiBhbHNvIGJlIGV4dHJhY3RlZCBhcyBjb3ZhcmlhdGVzLgoKYGBge3J9CiMgcHJpbmNpcGFsIGNvbXBvbmVudCByZWdyZXNzaW9uCnhfdG1wID0gcHJjb21wKHQoVENHQV9QQU01MCkpCgojIGNob29zZSB0aGUgdG9wIHR3byBjb21wb25lbnRzIChzdWJqZWN0aXZlKSBhcyBjb3ZhcmlhdGVzClhfUEMgPSB4X3RtcCR4WywgMToyXQojIGJ1aWxkIGNsYXNzaWNhbCBzdXJ2aXZhbCBtb2RlbCAoZS5nLiBQSCBDb3ggbW9kZWwpCmRhdGFfdG1wID0gZGF0YS5mcmFtZSh0aW1lID0gY2xpbiR0aW1lLCBzdGF0dXMgPSBjbGluJHN0YXR1cywgWF9QQykKZml0ID0gY294cGgoU3Vydih0aW1lLCBzdGF0dXMpIH4gUEMxICsgUEMyLCBkYXRhID0gZGF0YV90bXApCnN1bW1hcnkoZml0KQpgYGAKYGBgCkNhbGw6CmNveHBoKGZvcm11bGEgPSBTdXJ2KHRpbWUsIHN0YXR1cykgfiBQQzEgKyBQQzIsIGRhdGEgPSBkYXRhX3RtcCkKCiAgbj0gMTA0NywgbnVtYmVyIG9mIGV2ZW50cz0gMTQ5IAoKICAgICAgICBjb2VmIGV4cChjb2VmKSBzZShjb2VmKSAgICAgeiBQcig+fHp8KSAgIApQQzEgMC4wMDQ4OTQgIDEuMDA0OTA2IDAuMDA5Njg5IDAuNTA1ICAwLjYxMzQ4ICAgClBDMiAwLjAzODI2OSAgMS4wMzkwMTAgMC4wMTMyMjQgMi44OTQgIDAuMDAzODEgKioKLS0tClNpZ25pZi4gY29kZXM6ICAwIOKAmCoqKuKAmSAwLjAwMSDigJgqKuKAmSAwLjAxIOKAmCrigJkgMC4wNSDigJgu4oCZIDAuMSDigJgg4oCZIDEKCiAgICBleHAoY29lZikgZXhwKC1jb2VmKSBsb3dlciAuOTUgdXBwZXIgLjk1ClBDMSAgICAgMS4wMDUgICAgIDAuOTk1MSAgICAgMC45ODYgICAgIDEuMDI0ClBDMiAgICAgMS4wMzkgICAgIDAuOTYyNSAgICAgMS4wMTIgICAgIDEuMDY2CgpDb25jb3JkYW5jZT0gMC41OCAgKHNlID0gMC4wMjggKQpMaWtlbGlob29kIHJhdGlvIHRlc3Q9IDguNjIgIG9uIDIgZGYsICAgcD0wLjAxCldhbGQgdGVzdCAgICAgICAgICAgID0gOC43MSAgb24gMiBkZiwgICBwPTAuMDEKU2NvcmUgKGxvZ3JhbmspIHRlc3QgPSA4LjczICBvbiAyIGRmLCAgIHA9MC4wMQpgYGAKCiMjIyBQZW5hbGl6ZWQgQ294IG1vZGVscyB7LX0KCkZvciBjb21wdXRhdGlvbmFsIGVmZmljaWVuY3ksIHdlIHdpbGwgdXNlIG9ubHkgdGhlIG1STkEtU2VxIGZlYXR1cmVzIGNvcnJlc3BvbmRpbmcgdG8gdGhlIFBBTTUwIGdlbmVzIFtAUGFya2VyMjAwOV0gaW5zdGVhZCBvZiB0aGUgdmFyaWFuY2UgZmlsdGVyZWQgZ2VuZXMgZnJvbSB0aGUgcHJldmlvdXMgc2VjdGlvbi4KV2UgcGVyZm9ybSBhbiBpbnZlc3RpZ2F0aW9uIG9mIHRoZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gdGhlIG1STkEtU2VxIGZlYXR1cmVzLCB0d28gY2xpbmljYWwgdmFyaWFibGVzIChpLmUuIHRoZSBwYXRpZW50cycgYWdlIGF0IGRpYWdub3NpcyBhbmQgdGhlaXIgZXRobmljaXR5KSBhbmQgdGhlIHN1cnZpdmFsIG91dGNvbWVzLgoKVGhlIGBSYCBwYWNrYWdlIFsqKmdsbW5ldCoqXShodHRwczovL0NSQU4uUi1wcm9qZWN0Lm9yZy9wYWNrYWdlPWdsbW5ldCkgW0BGcmllZG1hbjIwMTBdIGlzIHZlcnkgY29tcHV0YXRpb25hbGx5IGVmZmljaWVudCB0byBydW4gTGFzc28gYW5kIEVsYXN0aWMgTmV0IENveCBtb2RlbHMuCkxhc3NvIGhhcyBhIHR1bmluZyBwYXJhbWV0ZXIgJFxsYW1iZGEkIHRvIGNvbnRyb2wgdGhlIHBlbmFsdHkgc3RyZW5ndGggb2YgdGhlIGNvZWZmaWNpZW50cyB3aGljaCBjYW4gYmUgb3B0aW1pemVkIGJ5IGNyb3NzLXZhbGlkYXRpb24gKENWKSB2aWEgZnVuY3Rpb24gYGN2LmdsbW5ldCgpYC4KVGhlIGBnbG1uZXQoKWAgYW5kIGBjdi5nbG1uZXQoKWAgZnVuY3Rpb25zIHByb3ZpZGUgdGhlIGFyZ3VtZW50IGBwZW5hbHR5LmZhY3RvcmAgdG8gYWxsb3cgZGlmZmVyZW50IHNocmlua2FnZXMgZm9yIGRpZmZlcmVudCBmZWF0dXJlcywgd2hpY2ggbWFrZXMgc2Vuc2UgaWYgb25lIGluY2x1ZGVzIGJvdGggY2xpbmljYWwvZGVtb2dyYXBoaWMgdmFyaWFibGVzIGFuZCBvbWljcyBmZWF0dXJlcyBhbmQgZG9lcyBub3Qgd2FudCB0byBwZXJmb3JtIGZlYXR1cmUgc2VsZWN0aW9uIGZvciB0aGUgY2xpbmljYWwvZGVtb2dyYXBoaWMgdmFyaWFibGVzLgoKYGBge3J9CiMjIExhc3NvIENveCBtb2RlbAoKIyMgZm9yIGRlbW9uc3RyYXRpb24gc2ltcGxpY2l0eSwgUEFNNTAgZ2VuZXMgYXJlIHVzZWQgaGVyZQp4ID0gY2JpbmQoYWdlID0gY2xpbiRhZ2UsIGV0aG5pY2l0eSA9IGZhY3RvcihjbGluJGV0aG5pY2l0eSksIHQoVENHQV9QQU01MCkpCnkgPSBjYmluZCh0aW1lID0gY2xpbiR0aW1lLCBzdGF0dXMgPSBjbGluJHN0YXR1cykKCiMgc2V0IHBlbmFsdHkgZmFjdG9yIHdpdGhvdXQgcGVuYWxpemluZyB0aGUgdHdvIGRlbW9ncmFwaGljYWwgdmFyaWFibGVzCnBmID0gYyhyZXAoMCwgMiksIHJlcCgxLCBuY29sKHgpIC0gMikpCgojIExhc3NvIENveCBieSB1c2luZyBjdi5nbG1uZXQgdG8gb2J0YWluIHRoZSA1LWZvbGQgQ1Ygb3B0aW1hbCBsYW1iZGEubWluIG9yIGxhbWJkYS4xc2UKc2V0LnNlZWQoMTIzKQpjdmZpdCA9IGdsbW5ldDo6Y3YuZ2xtbmV0KHgsIHksIGZhbWlseSA9ICJjb3giLCBuZm9sZHMgPSA1LCBwZW5hbHR5LmZhY3RvciA9IHBmKQptb2QgPSBjdmZpdCRnbG1uZXQuZml0CmxhbWJkYV9vcHRpbWFsID0gY3ZmaXQkbGFtYmRhLm1pbiAjIG9wdGltYWwgbGFtYmRhCgpiZXRhcyA9IGFzLnZlY3Rvcihjb2VmKG1vZCwgcyA9IGxhbWJkYV9vcHRpbWFsKSkKYmV0YS5wb3NpdGl2ZSA9IGNvbG5hbWVzKHgpW2JldGFzID4gMF0KYmV0YS5uZWdhdGl2ZSA9IGNvbG5hbWVzKHgpW2JldGFzIDwgMF0KI2dldCBvcmRlcmVkIGxpc3Qgb2YgdmFyaWFibGVzIGFzIHRoZXkgYXBwZWFyIGF0IHNtYWxsZXN0IGxhbWJkYQphbGxuYW1lcyA9IG5hbWVzKGNvZWYobW9kKVssIG5jb2woY29lZihtb2QpKV0KICAgICAgICAgICAgICAgIFtvcmRlcihjb2VmKG1vZClbLCBuY29sKGNvZWYobW9kKSldLCBkZWNyZWFzaW5nID0gVFJVRSldKQojIGFzc2lnbiBjb2xvcnMKY29scyA9IHJlcCgiZ3JheTgwIiwgbGVuZ3RoKGFsbG5hbWVzKSkKY29sc1thbGxuYW1lcyAlaW4lIGJldGEucG9zaXRpdmVdID0gInNlYWdyZWVuMyIKY29sc1thbGxuYW1lcyAlaW4lIGJldGEubmVnYXRpdmVdID0gImhvdHBpbmsiCgojIGRyd2EgY29lZmZpY2llbnQgcGF0aHMgb2YgYSBMYXNzbyBDb3ggbW9kZWwKcGxvdG1vOjpwbG90X2dsbW5ldChtb2QsIGxhYmVsID0gVFJVRSwgcyA9IGxhbWJkYV9vcHRpbWFsLCBjb2wgPSBjb2xzLAogICAgICAgICAgICB4bGFiID0gZXhwcmVzc2lvbihsb2cgfn4gbGFtYmRhKSwgeWxhYiA9IGV4cHJlc3Npb24oYmV0YSkpCnRpdGxlKCJMYXNzbyAgIFxuXG4iKQpgYGAKIVtfQ29lZmZpY2llbnQgcGF0aHMgb2YgYSBMYXNzbyBDb3ggbW9kZWwuIFRoZSB2ZXJ0aWNsZSBncmF5IGxpbmUgaW5kaWNhdGVzIHRoZSBvcHRpbWFsICRcbGFtYmRhJCBhbmQgaXRzIGNvcnJlc3BvbmRpbmdseSBzZWxlY3RlZCBmZWF0dXJlcyBhcmUgbWFya2VkIGFzIGdyZWVuIChwb3NpdGl2ZSBjb2VmZmljaWVudCkgYW5kIHJlZCAobmVnYXRpdmUgY29lZmZpY2llbnQpIGNvbG9ycy4gTm90ZSB0aGF0IHRoZSBkZW1vZ3JhcGhpYyB2YXJpYWJsZXMgYWdlIGFuZCBldGhuaWNpdHkgd2VyZSBub3QgcGVuYWxpemVkLCBzbyB0aGF0IHRoZWlyIGNvZWZmaWNpZW50IHBhdGhzIGRpZCBub3Qgc3RhcnQgZnJvbSB6ZXJvIGluIHRoZSBmaWd1cmUuX10oZmlnL1RDR0FfbGFzc28ucG5nKXt3aWR0aD02MCV9Cgo8YnI+CgpFbGFzdGljIE5ldCBDb3ggbW9kZWwgaW5jbHVkZXMgdGhlICRcbGFtYmRhJCBhbmQgYW4gYWRkaXRpb25hbCBwZW5hbHR5IHBhcmFtZXRlciAkXGFscGhhIFxpbiBbMCwxXSQuClRoZSBwYXJhbWV0ZXIgJFxhbHBoYSQgY2FuIGJlIGZpeGVkIGFzICQwJCAoUmlkZ2UpLCAkMSQgKExhc3NvKSBvciBhbnkgdmFsdWUgYmV0d2VlbiAkMCQgYW5kICQxJCBmb3IgbWFraW5nIGEgY29tcHJvbWlzZSBiZXR3ZWVuIFJpZGdlIGFuZCBMYXNzbywgd2hpY2ggY2FuIGFsc28gYmUgb3B0aW1pemVkIGJ5IGNyb3NzLXZhbGlkYXRpb24gbWFudWFsbHksIHNlZSB0aGUgZXhhbXBsZSBiZWxvdy4KCmBgYHtyfQojIyBFbGFzdGljIE5ldCBDb3ggbW9kZWwKCiMgc2V0IHBlbmFsdHkgcGFyYW1ldGVyIGFscGhhIHdoaWNoIGNvbXByaXNlcyBiZXR3ZWVuIExhc3NvIGFuZCByaWRnZSByZWdyZXNzaW9ucwphbHBoYSA9IHNlcSgwLjEsIDEsIGxlbmd0aCA9IDEwKQpmaXRFTiA9IGxpc3QoKQpzZXQuc2VlZCgxMjMpCmZvcihpIGluIDE6bGVuZ3RoKGFscGhhKSkgewogIGZpdEVOW1tpXV0gPSBjdi5nbG1uZXQoeCwgeSwgZmFtaWx5ID0gImNveCIsIGFscGhhID0gYWxwaGFbaV0sIG5mb2xkcyA9IDUsIHBlbmFsdHkuZmFjdG9yID0gcGYpCn0KaWR4ID0gd2hpY2gubWluKHNhcHBseShmaXRFTiwgZnVuY3Rpb24oeHgpIHt4eCRjdm1beHgkbGFtYmRhID09IHh4JGxhbWJkYS5taW5dfSkpCmN2Zml0ID0gZml0RU5bW2lkeF1dCgojIHRoZSBmb2xsb3dpbmcgY29kZSBpcyB0aGUgc2FtZSBhcyBMYXNzbyBwcmV2aW91c2x5Cm1vZCA9IGN2Zml0JGdsbW5ldC5maXQKbGFtYmRhX29wdGltYWwgPSBjdmZpdCRsYW1iZGEubWluICMgb3B0aW1hbCBsYW1iZGEKCmJldGFzID0gYXMudmVjdG9yKGNvZWYobW9kLCBzID0gbGFtYmRhX29wdGltYWwpKQpiZXRhLnBvc2l0aXZlID0gY29sbmFtZXMoeClbYmV0YXMgPiAwXQpiZXRhLm5lZ2F0aXZlID0gY29sbmFtZXMoeClbYmV0YXMgPCAwXQphbGxuYW1lcyA9IG5hbWVzKGNvZWYobW9kKVssIG5jb2woY29lZihtb2QpKV0KICAgICAgICAgICAgICAgIFtvcmRlcihjb2VmKG1vZClbLCBuY29sKGNvZWYobW9kKSldLCBkZWNyZWFzaW5nID0gVFJVRSldKQpjb2xzID0gcmVwKCJncmF5ODAiLCBsZW5ndGgoYWxsbmFtZXMpKQpjb2xzW2FsbG5hbWVzICVpbiUgYmV0YS5wb3NpdGl2ZV0gPSAic2VhZ3JlZW4zIiAKY29sc1thbGxuYW1lcyAlaW4lIGJldGEubmVnYXRpdmVdID0gImhvdHBpbmsiICAgCgpwbG90bW86OnBsb3RfZ2xtbmV0KG1vZCwgbGFiZWwgPSBUUlVFLCBzID0gbGFtYmRhX29wdGltYWwsIGNvbCA9IGNvbHMsCiAgICAgICAgICAgIHhsYWIgPSBleHByZXNzaW9uKGxvZyB+fiBsYW1iZGEpLCB5bGFiID0gZXhwcmVzc2lvbihiZXRhKSkKdGl0bGUoIkVsYXN0aWMgTmV0ICAgICBcblxuIikKYGBgCiFbX0NvZWZmaWNpZW50IHBhdGhzIG9mIGFuIEVsYXN0aWMgTmV0IENveCBtb2RlbC4gVGhlIHZlcnRpY2xlIGdyYXkgbGluZSBpbmRpY2F0ZXMgdGhlIG9wdGltYWwgJFxsYW1iZGEkIGFuZCBpdHMgY29ycmVzcG9uZGluZ2x5IHNlbGVjdGVkIGZlYXR1cmVzIGFyZSBtYXJrZWQgYXMgZ3JlZW4gKHBvc2l0aXZlIGNvZWZmaWNpZW50KSBhbmQgcmVkIChuZWdhdGl2ZSBjb2VmZmljaWVudCkgY29sb3JzLiBOb3RlIHRoYXQgdGhlIGRlbW9ncmFwaGljIHZhcmlhYmxlcyBhZ2UgYW5kIGV0aG5pY2l0eSB3ZXJlIG5vdCBwZW5hbGl6ZWQsIHNvIHRoYXQgdGhlaXIgY29lZmZpY2llbnQgcGF0aHMgZGlkIG5vdCBzdGFydCBmcm9tIHplcm8gaW4gdGhlIGZpZ3VyZS5fXShmaWcvVENHQV9lbGFzdGljLnBuZyl7d2lkdGg9NjAlfQoKPGJyPgoKQWRhcHRpdmUgTGFzc28gQ294IG1vZGVsIG5lZWRzIHRvIHByZS1lc3RpbWF0ZSBhbGwgY29lZmZpY2llbnRzIHdoaWNoIHdpbGwgYmUgdXNlZCBhcyB3ZWlnaHRzIHZpYSB0aGUgYXJndW1lbnQgYHBlbmFsdHkuZmFjdG9yYCBpbiB0aGUgYGdsbW5ldCgpYCBhbmQgYGN2LmdsbW5ldCgpYCBmdW5jdGlvbnMgdG8gZml0IGEgTGFzc28gQ294IG1vZGVsLgpUaGUgcHJlLWVzdGltYXRpb24gY2FuIGJlIGRvbmUgYnkgYSBSaWRnZSBDb3ggbW9kZWwsIHNlZSBhbiBleGFtcGxlIGJlbG93LgoKYGBge3J9CiMjIEFkYXB0aXZlIExhc3NvIENveCBtb2RlbAoKc2V0LnNlZWQoMTIzKQpmaXQgPSBjdi5nbG1uZXQoeCwgeSwgZmFtaWx5ID0gImNveCIsIGFscGhhID0gMCwgbmZvbGRzID0gNSkKd2VpZ2h0cyA9IGFicygxIC8gYXMudmVjdG9yKGNvZWYoZml0LCBzID0gImxhbWJkYS5taW4iKSkpCgojIGFkYXB0aXZlIExhc3NvIENveCBieSB1c2luZyBjdi5nbG1uZXQgdG8gb2J0YWluIHRoZSA1LWZvbGQgQ1Ygb3B0aW1hbCBsYW1iZGEubWluIG9yIGxhbWJkYS4xc2UKY3ZmaXQgPSBjdi5nbG1uZXQoeCwgeSwgZmFtaWx5ID0gImNveCIsIG5mb2xkcyA9IDUsIHBlbmFsdHkuZmFjdG9yID0gcGYpCm1vZCA9IGN2Zml0JGdsbW5ldC5maXQKbGFtYmRhX29wdGltYWwgPSBjdmZpdCRsYW1iZGEubWluICMgb3B0aW1hbCBsYW1iZGEKCmJldGFzID0gYXMudmVjdG9yKGNvZWYobW9kLCBzID0gbGFtYmRhX29wdGltYWwpKQpiZXRhLnBvc2l0aXZlID0gY29sbmFtZXMoeClbYmV0YXMgPiAwXQpiZXRhLm5lZ2F0aXZlID0gY29sbmFtZXMoeClbYmV0YXMgPCAwXQojZ2V0IG9yZGVyZWQgbGlzdCBvZiB2YXJpYWJsZXMgYXMgdGhleSBhcHBlYXIgYXQgc21hbGxlc3QgbGFtYmRhCmFsbG5hbWVzID0gbmFtZXMoY29lZihtb2QpWywgbmNvbChjb2VmKG1vZCkpXQogICAgICAgICAgICAgICAgW29yZGVyKGNvZWYobW9kKVssIG5jb2woY29lZihtb2QpKV0sIGRlY3JlYXNpbmcgPSBUUlVFKV0pCiNhc3NpZ24gY29sb3JzCmNvbHMgPSByZXAoImdyYXk4MCIsIGxlbmd0aChhbGxuYW1lcykpCmNvbHNbYWxsbmFtZXMgJWluJSBiZXRhLnBvc2l0aXZlXSA9ICJzZWFncmVlbjMiCmNvbHNbYWxsbmFtZXMgJWluJSBiZXRhLm5lZ2F0aXZlXSA9ICJob3RwaW5rIgoKcGxvdF9nbG1uZXQobW9kLCBsYWJlbCA9IFRSVUUsIHMgPSBsYW1iZGFfb3B0aW1hbCwgY29sID0gY29scywKICAgICAgICAgICAgeGxhYiA9IGV4cHJlc3Npb24obG9nIH4gbGFtYmRhKSwgeWxhYiA9IGV4cHJlc3Npb24oYmV0YSkpCnRpdGxlKCJBZGF0aXZlIExhc3NvICAgIFxuXG4iKQpgYGAKIVtfQ29lZmZpY2llbnQgcGF0aHMgb2YgYW4gYWRhcHRpdmUgTGFzc28gQ294IG1vZGVsLiBUaGUgdmVydGljbGUgZ3JheSBsaW5lIGluZGljYXRlcyB0aGUgb3B0aW1hbCAkXGxhbWJkYSQgYW5kIGl0cyBjb3JyZXNwb25kaW5nbHkgc2VsZWN0ZWQgZmVhdHVyZXMgYXJlIG1hcmtlZCBhcyBncmVlbiAocG9zaXRpdmUgY29lZmZpY2llbnQpIGFuZCByZWQgKG5lZ2F0aXZlIGNvZWZmaWNpZW50KSBjb2xvcnMuIE5vdGUgdGhhdCB0aGUgZGVtb2dyYXBoaWMgdmFyaWFibGVzIGFnZSBhbmQgZXRobmljaXR5IHdlcmUgbm90IHBlbmFsaXplZCwgc28gdGhhdCB0aGVpciBjb2VmZmljaWVudCBwYXRocyBkaWQgbm90IHN0YXJ0IGZyb20gemVybyBpbiB0aGUgZmlndXJlLl9dKGZpZy9UQ0dBX2FkYXB0aXZlbGFzc28ucG5nKXt3aWR0aD02MCV9Cgo8YnI+CgpHcm91cCBMYXNzbyBDb3ggbW9kZWwgY2FuIGJlIGltcGxlbWVudGVkIHRocm91Z2ggdGhlIGBSYCBwYWNrYWdlIFsqKmdycHJlZyoqXShodHRwczovL0NSQU4uUi1wcm9qZWN0Lm9yZy9wYWNrYWdlPWdycHJlZykgW0BCcmVoZW55MjAxNV0uCkZvciBhbiBpbGx1c3RyYXRpb24sIHdlIHNwZWNpZnkgdGhlIHR3byBkZW1vZ3JhcGhpYyB2YXJpYWJsZXMgYXMgdGhlIGZpcnN0IGdyb3VwLCB0aGUgZmlyc3QgJDEwJCBQQU01MCBnZW5lcyBhcyB0aGUgc2Vjb25kIGdyb3VwLCB0aGUgbGFzdCAkNDAkIFBBTTUwIGdlbmVzIGFzIHRoZSB0aGlyZCBncm91cC4KQSAkayQtZm9sZCBjcm9zcy12YWxpZGF0aW9uIChDVikgZm9yIHRoZSBncm91cCBMYXNzbyBDb3ggbW9kZWwgaXMgcGVyZm9ybWVkIHRocm91Z2ggZnVuY3Rpb24gYGN2LmdycHN1cnYoKWAuClRoZSByZXR1cm5lZCBvYmplY3QgYGN2Zml0JGxhbWJkYS5taW5gIGlzIHRoZSB2YWx1ZSBvZiBDVi1vcHRpbWl6ZWQgJFxsYW1iZGEkLgpUaGUgZm9sbG93aW5nIHJlc3VsdHMgc2hvdyB0aGF0IAoKLSB3aGVuIGNob29zaW5nIHRoZSBDVi1vcHRpbWl6ZWQgJFxsYW1iZGEgPSAwLjAxNDMkIChvdXRwdXQgbWF0cml4IGhhcyBsYW1iZGEgdmFsdWVzIGFzIGNvbHVtbiBuYW1lcyksIHRoZSBlc3RpbWF0ZWQgY29lZmZpY2llbnRzIG9mIHRoZSBmaXJzdCB0d28gZ3JvdXBzIGFyZSBub256ZXJvIChpLmUuIHNlbGVjdGluZyBmaXJzdCBhbmQgc2Vjb25kIGdyb3Vwcyk7Ci0gd2hlbiBjaG9vc2luZyB0aGUgJDEwJC10aCBsYW1iZGEgJFxsYW1iZGEgPSAwLjAyMTckLCBvbmx5IHRoZSBmaXJzdCBncm91cCBvZiBjb3ZhcmlhdGVzIGhhcyBub256ZXJvIGNvZWZmaWNpZW50cyAoaS5lLiBzZWxlY3RpbmcgZmlyc3QgZ3JvdXApOwotIHdoZW4gY2hvb3NpbmcgdGhlICQxNSQtdGggbGFtYmRhICRcbGFtYmRhID0gMC4wMTA4JCwgdGhlIGVzdGltYXRlZCBjb2VmZmljaWVudHMgb2YgYWxsIHRoZSB0aHJlZSBncm91cHMgYXJlIG5vbnplcm8gKGkuZS4gc2VsZWN0aW5nIGFsbCBncm91cHMpLiAKCk5vdGUgdGhhdCB0aGUgYFJgIHBhY2thZ2UgWyoqZ3JwcmVnKipdKGh0dHBzOi8vQ1JBTi5SLXByb2plY3Qub3JnL3BhY2thZ2U9Z3JwcmVnKSBbQEJyZWhlbnkyMDE1XSBhbHNvIGltcGxlbWVudHMgZ3JvdXAgc21vb3RobHkgY2xpcHBlZCBhYnNvbHV0ZSBkZXZpYXRpb24gKFNDQUQpIG1vZGVsIGFuZCBzb21lIG90aGVycywgc2VlIEBCcmVoZW55MjAyMSBmb3IgZGV0YWlscy4KCmBgYHtyfQojIGdyb3VwIExhc3NvIENveCBtb2RlbApncm91cCA9IGMocmVwKCJkZW1vZ3JhcGhpYyIsIDIpLCByZXAoIlBBTTUwXzEiLCAxMCksIHJlcCgiUEFNNTBfMiIsIDQwKSkKZ3JvdXAgPSBmYWN0b3IoZ3JvdXApCnNldC5zZWVkKDEyMykKY3ZmaXQgPSBncnByZWc6OmN2LmdycHN1cnYoWCA9IHgsIHkgPSB5LCBncm91cCA9IGdyb3VwLCBwZW5hbHR5ID0gImdyTGFzc28iLCByZXR1cm5ZID0gVFJVRSkKcm91bmQoY3ZmaXQkZml0JGJldGFbLCBjKHdoaWNoLm1pbihjdmZpdCRjdmUpLCAxMCwgMjApXSwgZGlnaXRzID0gNCkKYGBgCmBgYAogICAgICAgICAgIDAuMDE0MyAgMC4wMjE3ICAwLjAxMDgKYWdlICAgICAgICAwLjAyMTkgIDAuMDE1NCAgMC4wMjQ3CmV0aG5pY2l0eSAtMC4wNTQyIC0wLjA0MjUgLTAuMDU2OQpVQkUyVCAgICAgIDAuMDIwOSAgMC4wMDAwICAwLjA3MzIKQklSQzUgICAgIC0wLjAwMzUgIDAuMDAwMCAtMC4wMTA5Ck5VRjIgICAgICAtMC4wMDMxICAwLjAwMDAgLTAuMDA5MwpDREM2ICAgICAgIDAuMDE1NSAgMC4wMDAwICAwLjA1NDYKQ0NOQjEgICAgIC0wLjAyNDcgIDAuMDAwMCAtMC4wODQ2ClRZTVMgICAgICAtMC4wMDI4ICAwLjAwMDAgLTAuMDA4NgpNWUJMMiAgICAgLTAuMDE0NyAgMC4wMDAwIC0wLjA1MjIKQ0VQNTUgICAgICAwLjAxNTIgIDAuMDAwMCAgMC4wNTA3Ck1FTEsgICAgICAtMC4wMDAxICAwLjAwMDAgLTAuMDAwNgpOREM4MCAgICAgIDAuMDAwNyAgMC4wMDAwICAwLjAwMjIKUlJNMiAgICAgICAwLjAwMDAgIDAuMDAwMCAtMC4wMTAwClVCRTJDICAgICAgMC4wMDAwICAwLjAwMDAgIDAuMDA3NgpDRU5QRiAgICAgIDAuMDAwMCAgMC4wMDAwIC0wLjAwMDIKUFRURzEgICAgICAwLjAwMDAgIDAuMDAwMCAgMC4wMDUyCkVYTzEgICAgICAgMC4wMDAwICAwLjAwMDAgLTAuMDAwMgpPUkM2TCAgICAgIDAuMDAwMCAgMC4wMDAwIC0wLjA0NjQKQU5MTiAgICAgICAwLjAwMDAgIDAuMDAwMCAtMC4wMTc1CkNDTkUxICAgICAgMC4wMDAwICAwLjAwMDAgLTAuMDE1NQpDREMyMCAgICAgIDAuMDAwMCAgMC4wMDAwIC0wLjAxNDIKTUtJNjcgICAgICAwLjAwMDAgIDAuMDAwMCAtMC4wMjQ1CktJRjJDICAgICAgMC4wMDAwICAwLjAwMDAgLTAuMDEyMwpBQ1RSM0IgICAgIDAuMDAwMCAgMC4wMDAwICAwLjAwNDMKTVlDICAgICAgICAwLjAwMDAgIDAuMDAwMCAtMC4wMTM3CkVHRlIgICAgICAgMC4wMDAwICAwLjAwMDAgIDAuMDMxOQpLUlQ1ICAgICAgIDAuMDAwMCAgMC4wMDAwIC0wLjAwNTkKUEhHREggICAgICAwLjAwMDAgIDAuMDAwMCAgMC4wMDA0CkNESDMgICAgICAgMC4wMDAwICAwLjAwMDAgLTAuMDI2NQpNSUEgICAgICAgIDAuMDAwMCAgMC4wMDAwICAwLjAwNDkKS1JUMTcgICAgICAwLjAwMDAgIDAuMDAwMCAtMC4wMDg4CkZPWEMxICAgICAgMC4wMDAwICAwLjAwMDAgIDAuMDA5NgpTRlJQMSAgICAgIDAuMDAwMCAgMC4wMDAwICAwLjAyMzUKS1JUMTQgICAgICAwLjAwMDAgIDAuMDAwMCAgMC4wMjE4CkVTUjEgICAgICAgMC4wMDAwICAwLjAwMDAgLTAuMDE1OApTTEMzOUE2ICAgIDAuMDAwMCAgMC4wMDAwICAwLjAyODQKQkFHMSAgICAgICAwLjAwMDAgIDAuMDAwMCAgMC4wMTA0Ck1BUFQgICAgICAgMC4wMDAwICAwLjAwMDAgIDAuMDAyMwpQR1IgICAgICAgIDAuMDAwMCAgMC4wMDAwICAwLjAwOTUKQ1hYQzUgICAgICAwLjAwMDAgIDAuMDAwMCAtMC4wMTgyCk1MUEggICAgICAgMC4wMDAwICAwLjAwMDAgLTAuMDA1OQpCQ0wyICAgICAgIDAuMDAwMCAgMC4wMDAwICAwLjAxMzMKTURNMiAgICAgICAwLjAwMDAgIDAuMDAwMCAtMC4wMDg0Ck5BVDEgICAgICAgMC4wMDAwICAwLjAwMDAgLTAuMDAwOApGT1hBMSAgICAgIDAuMDAwMCAgMC4wMDAwIC0wLjAwNTUKQkxWUkEgICAgICAwLjAwMDAgIDAuMDAwMCAgMC4wMDUzCk1NUDExICAgICAgMC4wMDAwICAwLjAwMDAgLTAuMDAzNwpHUFIxNjAgICAgIDAuMDAwMCAgMC4wMDAwIC0wLjAzMjgKRkdGUjQgICAgICAwLjAwMDAgIDAuMDAwMCAtMC4wMDI5CkdSQjcgICAgICAgMC4wMDAwICAwLjAwMDAgIDAuMDA4NgpUTUVNNDVCICAgIDAuMDAwMCAgMC4wMDAwIC0wLjAwNzgKRVJCQjIgICAgICAwLjAwMDAgIDAuMDAwMCAtMC4wMTk0CmBgYAoKU3BhcnNlIGdyb3VwIExhc3NvIENveCBtb2RlbCBpcyBpbXBsZW1lbnRlZCBpbiB0aGUgYFJgIHBhY2thZ2UgWyoqU0dMKipdKGh0dHBzOi8vQ1JBTi5SLXByb2plY3Qub3JnL3BhY2thZ2U9U0dMKSBbQFNpbW9uMjAxOV0uIApUaGUgZnVuY3Rpb24gYGN2U0dMKClgIHVzZXMgY3Jvc3MgdmFsaWRhdGlvbiB0byBvcHRpbWl6ZSB0aGUgcGVuYWx0eSBwYXJhbWV0ZXIgJFxsYW1iZGEkLgpUaGUgZm9sbG93aW5nIGV4YW1wbGUgc2hvd3MgdGhhdCBpdCBpbmR1Y2VzIHNwYXJzaXR5IGluIGVhY2ggZ3JvdXAgb2YgY292YXJpYXRlcy4gCgpgYGB7cn0KIyBzcGFyc2UgZ3JvdXAgTGFzc28gQ294IG1vZGVsCmdyb3VwID0gYyhyZXAoImRlbW9ncmFwaGljIiwgMiksIHJlcCgiUEFNNTBfMSIsIDEwKSwgcmVwKCJQQU01MF8yIiwgNDApKQpncm91cCA9IGZhY3Rvcihncm91cCkKZGF0X3RtcCA9IGxpc3QoeCA9IHgsIHRpbWUgPSBjbGluJHRpbWUsIHN0YXR1cyA9IGNsaW4kc3RhdHVzKQpzZXQuc2VlZCgxMjMpCmN2Zml0ID0gU0dMOjpjdlNHTChkYXRfdG1wLCBpbmRleCA9IGdyb3VwLCB0eXBlID0gImNveCIsIG5mb2xkID0gNSkKYmV0YS5oYXQgPSBjdmZpdCRmaXQkYmV0YVssIHdoaWNoLm1pbihjdmZpdCRsbGRpZmYpXQpuYW1lcyhiZXRhLmhhdCkgPSBwYXN0ZTAoImdyb3VwIiwgYXMubnVtZXJpYyhncm91cCksICIuIiwgYygxOjIsIDE6MTAsIDE6NDApKQpiZXRhLmhhdApgYGAKYGBgCiAgIGdyb3VwMS4xICAgIGdyb3VwMS4yICAgIGdyb3VwMi4xICAgIGdyb3VwMi4yICAgIGdyb3VwMi4zICAgIGdyb3VwMi40IAogNS42ODM4NzU3MCAgMC4wMDAwMDAwMCAgMC41MDcxMTc0MCAgMC4wMDAwMDAwMCAgMC4wMDAwMDAwMCAgMC4yMTUyMjQ5MCAKICAgZ3JvdXAyLjUgICAgZ3JvdXAyLjYgICAgZ3JvdXAyLjcgICAgZ3JvdXAyLjggICAgZ3JvdXAyLjkgICBncm91cDIuMTAgCiAwLjAwMDAwMDAwICAwLjAwMDAwMDAwICAwLjAwMDAwMDAwICAwLjM0MTY4NjY5ICAwLjAwMDAwMDAwICAwLjAwMDAwMDAwIAogICBncm91cDMuMSAgICBncm91cDMuMiAgICBncm91cDMuMyAgICBncm91cDMuNCAgICBncm91cDMuNSAgICBncm91cDMuNiAKIDAuMDAwMDAwMDAgIDAuMjU2OTE0NzggIDAuMDAwMDAwMDAgLTAuMzc0OTQ3MjYgIDAuMDAwMDAwMDAgLTIuODUxMTAxNDYgCiAgIGdyb3VwMy43ICAgIGdyb3VwMy44ICAgIGdyb3VwMy45ICAgZ3JvdXAzLjEwICAgZ3JvdXAzLjExICAgZ3JvdXAzLjEyIAotMS45MzU1Njk5NCAgMC4wMDAwMDAwMCAgMC4wMDAwMDAwMCAgMC4wMDAwMDAwMCAtMS43NzgwNTU0MiAgMC4wMDAwMDAwMCAKICBncm91cDMuMTMgICBncm91cDMuMTQgICBncm91cDMuMTUgICBncm91cDMuMTYgICBncm91cDMuMTcgICBncm91cDMuMTggCiAwLjAwMDAwMDAwICAxLjAzODE5Nzc4ICAwLjAwMDAwMDAwICAwLjAwMDAwMDAwICAwLjAwMDAwMDAwICAwLjAwMDAwMDAwIAogIGdyb3VwMy4xOSAgIGdyb3VwMy4yMCAgIGdyb3VwMy4yMSAgIGdyb3VwMy4yMiAgIGdyb3VwMy4yMyAgIGdyb3VwMy4yNCAKIDAuMDAwMDAwMDAgIDAuMDAwMDAwMDAgIDAuMDAwMDAwMDAgIDAuMDAwMDAwMDAgLTAuMzQ0OTY3MTcgIDAuMDAwMDAwMDAgCiAgZ3JvdXAzLjI1ICAgZ3JvdXAzLjI2ICAgZ3JvdXAzLjI3ICAgZ3JvdXAzLjI4ICAgZ3JvdXAzLjI5ICAgZ3JvdXAzLjMwIAogMS4wMTU1MjA5NSAgMC4wMDAwMDAwMCAgMC4wMDAwMDAwMCAgMC4wMDAwMDAwMCAgMC4wMDAwMDAwMCAgMC4wMDAwMDAwMCAKICBncm91cDMuMzEgICBncm91cDMuMzIgICBncm91cDMuMzMgICBncm91cDMuMzQgICBncm91cDMuMzUgICBncm91cDMuMzYgCi0yLjEzMjA1NTg3ICAwLjAwMDAwMDAwICAwLjAwMDAwMDAwICAwLjAwMDAwMDAwICAwLjAwMDAwMDAwIC0wLjk1MDQ4MTIxIAogIGdyb3VwMy4zNyAgIGdyb3VwMy4zOCAgIGdyb3VwMy4zOSAgIGdyb3VwMy40MCAKLTEuODYyMjIxMDUgLTAuMDExMjA1NzMgLTAuODExNTc2NDYgLTIuMTQxNDg5MDAgCmBgYAoKIyMjIFNwYXJzZSBCYXllc2lhbiBDb3ggbW9kZWxzCgpUaGUgYFJgIHBhY2thZ2UgWyoqcHNiY0dyb3VwKipdKGh0dHBzOi8vQ1JBTi5SLXByb2plY3Qub3JnL3BhY2thZ2U9cHNiY0dyb3VwKSBbQExlZTIwMjFdIGludGVncmF0ZXMgYSBsYXJnZSBzZXQgb2Ygc3BhcnNlIEJheWVzaWFuIENveCBtb2RlbHMuClRoZSBmdW5jdGlvbiBgcHNiY0dMKClgIGltcGxlbWVudHMgQmF5ZXNpYW4gQ294IG1vZGVscyB3aXRoIExhc3NvIGFuZCBncm91cCBMYXNzbyBwcmlvcnMgZm9yIGZlYXR1cmUgc2VsZWN0aW9uIGFuZCBncm91cCBzZWxlY3Rpb24gcmVzcGVjdGl2ZWx5LgpGb3IgdGhlIExhc3NvIHByaW9yLCBzZXQgdGhlIGh5cGVycGFyYW1ldGVyIGBwcmlvclBhcmEkZ3JvdXBJbmQgPSAxOnBgIHdoZXJlICRwJCBpcyB0aGUgdG90YWwgbnVtYmVyIG9mIGNvdmFyaWF0ZXMuCkZvciB0aGUgZ3JvdXAgTGFzc28gcHJpb3IsIHNldCB0aGUgaHlwZXJwYXJhbWV0ZXIgYHByaW9yUGFyYSRncm91cEluZGAgYXMgYSB2ZWN0b3Igb2Ygc2l6ZSAkcCQsIHdoZXJlIGVhY2ggZWxlbWVudCBkZW5vdGVzIHdoaWNoIGdyb3VwIGVhY2ggY292YXJpYXRlIGNvcnJlc3BvbmRzIHRvLgpOb3RlIHRoYXQgKipwc2JjR3JvdXAqKiBjYW5ub3QgZGlzdGluZ3Vpc2ggbWFuZGF0b3J5ICh1bnBlbmFsaXplZCkgY292YXJpYXRlcyB3aXRoIG9taWNzIGZlYXR1cmVzLCBzZWUgQFp1Y2tuaWNrMjAxNSBmb3IgYW4gZXh0ZW5kZWQgQmF5ZXNpYW4gTGFzc28gQ294IG1vZGVsLgoKYGBge3J9CiMgQmF5ZXNpYW4gQ294IG1vZGVsIHdpdGggTGFzc28gcHJpb3IKc2V0LnNlZWQoMTIzKQpzdXJ2T2JqID0gbGlzdCh0ID0gY2xpbiR0aW1lLCBkaSA9IGNsaW4kc3RhdHVzLCB4ID0geCkKcCA9IG5jb2woeCkKIyBzZXQgaHlwZXJwYXJhbWV0ZXJzLiAKIyBGb3IgTGFzc28gcHJpb3IgKGkuZS4gJ2dyb3VwSW5kJz0gMTpwKSwgbGFyZ2VyIHJhdGlvIHIvZGVsdGEgdGVuZHMgdG8gZm9yY2UgdGhlIHBvc3RlcmlvciBiZXRhcyB0byBiZSBtb3JlIGNvbmNlbnRyYXRlZCBhdCAwCiMgRm9yIGdyb3VwIExhc3NvIHByaW9yIChpLmUuICdncm91cEluZCcgYXMgZ3JvdXAgaW5kaWNhdG9yIGZvciBjb3ZhcmlhdGVzKSwgbGFyZ2VyIHJhdGlvIHIvZGVsdGEgdGVuZHMgdG8gZm9yY2Ugc3Ryb25nZXIgZ3JvdXBpbmcgZWZmZWN0IG9mIGNvdmFyaWF0ZXMKcyA9IGMoc29ydChzdXJ2T2JqJHRbc3Vydk9iaiRkaSA9PSAxXSksIDIgKiBtYXgoc3Vydk9iaiR0KSAtIG1heChzdXJ2T2JqJHRbLXdoaWNoKHN1cnZPYmokdD09bWF4KHN1cnZPYmokdCkpXSkpCnByaW9yUGFyYSA9IGxpc3QoJ2V0YTAnID0gMSwgJ2thcHBhMCcgPSAxLCAnYzAnPSAyLCAncicgPSAwLjUsIAogICAgICAgICAgICAgICAgICAnZGVsdGEnID0gMC4wMDAxLCAncyc9IHMsICdKJz1sZW5ndGgocyksICdncm91cEluZCc9IDE6cCkKIyBzZXQgTUNNQyBwYXJhbWV0ZXJzCm1jbWNQYXJhID0gbGlzdCgnbnVtQmV0YSc9IHAsICdiZXRhLnByb3AudmFyJz0gMSkKIyBzZXQgaW5pdGlhbCB2YWx1ZXMgb2YgaHlwZXJwYXJhbWV0ZXJzCmxhbWJkYVNxID0gMQppbml0aWFsID0gbGlzdCgnYmV0YS5pbmknPSByZXAoMCwgcCksICdsYW1iZGFTcScgPSAxLCAnc2lnbWFTcScgPSBydW5pZigxLCAwLjEsIDEwKSwKICAgICAgICAgICAgICAgICd0YXVTcScgPSByZXhwKGxlbmd0aCh1bmlxdWUocHJpb3JQYXJhJGdyb3VwSW5kKSksICdyYXRlJyA9IGxhbWJkYVNxIC8gMiksCiAgICAgICAgICAgICAgICAnaCcgPSByZ2FtbWEocHJpb3JQYXJhJEosIDEsIDEpKQojIGluIHJlYWwgYXBwbGljYXRpb25zLCAnbnVtLnJlcHMnIHNob3VsZCBiZSBsYXJnZSBlbm91Z2ggKGUuZy4gMjAwMDAsIDQwMDAwKSBhbmQgJ2NoYWluJyB0byBiZSA+IDEKQmF5ZXNMYXNzb2ZpdCA9IHBzYmNHcm91cDo6cHNiY0dMKHN1cnZPYmosIHByaW9yUGFyYSwgaW5pdGlhbCwgcncgPSBUUlVFLCBtY21jUGFyYSwgbnVtLnJlcHMgPSAxMDAsIHRoaW4gPSAxLCBjaGFpbiA9IDEpCiMgYnVybi1pbiB0aGUgZmlyc3QgaGFsZiBNQ01DIGl0ZXJhdGlvbnMKYmV0YV9wID0gQmF5ZXNMYXNzb2ZpdCRiZXRhLnBbLSgxOjUxKSwgXQpiZXRhX21lYW4gPSBjb2xNZWFucyhiZXRhX3ApCmJldGFfTCA9IGFwcGx5KGJldGFfcCwgMiwgcXVhbnRpbGUsIDAuMDI1KQpiZXRhX1UgPSBhcHBseShiZXRhX3AsIDIsIHF1YW50aWxlLCAwLjk3NSkKdGJsID0gZGF0YS5mcmFtZSh0ZXJtID0gY29sbmFtZXMoeCksIGVzdGltYXRlID0gYmV0YV9tZWFuLCAgY29uZi5sb3cgPSBiZXRhX0wsICBjb25mLmhpZ2ggPSBiZXRhX1UpCnRibCR0ZXJtID0gZmFjdG9yKHRibCR0ZXJtLCBsZXZlbHMgPSB0YmwkdGVybSkKCkdHYWxseTo6Z2djb2VmKHRibCkgKyB4bGFiKGV4cHJlc3Npb24oUG9zdGVyaW9yfn5iZXRhKSkgKyB5bGFiKCIiKQpgYGAKIVtfRXN0aW1hdGVzIG9mIHJlZ3Jlc3Npb24gY29lZmZpY2llbnRzIGJ5IGEgcGVuYWxpemVkIHNlbWlwYXJhbWV0cmljIEJheWVzaWFuIENveCBtb2RlbCB3aXRoIExhc3NvIHByaW9yLiBTb2xpZCBkb3RzIGluZGljYXRlIHRoZSBwb3N0ZXJpb3IgbWVhbiBvdmVyIE1DTUMgaXRlcmF0aW9ucyAoZXhjbHVkaW5nIGJ1cm4taW4gcGVyaW9kKSwgYW5kIGhvcml6b250YWwgbGluZXMgc2hvdyB0aGUgY29ycmVzcG9uZGluZyA5NSUgY3JlZGliaWxpdHkgaW50ZXJ2YWxzLl9dKGZpZy9UQ0dBX2JheWVzbGFzc28ucG5nKXt3aWR0aD02MCV9Cgo8YnI+CgpJbiB0aGUgYFJgIHBhY2thZ2UgWyoqcHNiY0dyb3VwKipdKGh0dHBzOi8vQ1JBTi5SLXByb2plY3Qub3JnL3BhY2thZ2U9cHNiY0dyb3VwKSBbQExlZTIwMjFdLCBmdW5jdGlvbiBgcHNiY0VOKClgIGltcGxlbWVudHMgQmF5ZXNpYW4gQ294IG1vZGVscyB3aXRoIEVsYXN0aWMgTmV0IHByaW9yIGZvciBmZWF0dXJlIHNlbGVjdGlvbiB3aXRoIGdyb3VwaW5nIGVmZmVjdCBvZiBjb3JyZWxhdGVkIGZlYXR1cmVzLgpGdW5jdGlvbiBgcHNiY0ZMKClgIGltcGxlbWVudHMgQmF5ZXNpYW4gQ294IG1vZGVscyB3aXRoIGZ1c2VkIExhc3NvIHByaW9yLgoKYGBge3J9CiMgQmF5ZXNpYW4gQ294IG1vZGVsIHdpdGggRWxhc3RpYyBOZXQgcHJpb3IKc2V0LnNlZWQoMTIzKQojIHNldCBoeXBlcnBhcmFtZXRlcnMKIyBMYXJnZXIgcmF0aW8gcjEvZGVsdGExIGZvcmNlcyB0aGUgcG9zdGVyaW9yIGJldGFzIHRvIGJlIG1vcmUgY29uY2VudHJhdGVkIGF0IDAKIyBMYXJnZXIgcmF0aW8gcjIvZGVsdGEyIGZvcmNlcyBzdHJvbmdlciBncm91cGluZyBlZmZlY3Qgb2YgY292YXJpYXRlcwpwcmlvclBhcmEgPSBsaXN0KCdldGEwJyA9IDEsICdrYXBwYTAnID0gMSwgJ2MwJz0gMiwgJ3IxJyA9IDAuMSwgJ3IyJyA9IDEsIAogICAgICAgICAgICAgICAgICAnZGVsdGExJyA9IDAuMSwgJ2RlbHRhMicgPSAxLCAncyc9IHMsICdKJyA9IGxlbmd0aChzKSkKIyBzZXQgTUNNQyBwYXJhbWV0ZXJzCm1jbWNQYXJhID0gbGlzdCgnbnVtQmV0YSc9IHAsICdiZXRhLnByb3AudmFyJz0gMSkKIyBzZXQgaW5pdGlhbCB2YWx1ZXMgb2YgaHlwZXJwYXJhbWV0ZXJzCmluaXRpYWwgPSBsaXN0KCdiZXRhLmluaSc9IHJlcCgwLCBwKSwgJ2xhbWJkYTFTcScgPSAxLCAnbGFtYmRhMicgPSAxLCAnc2lnbWFTcScgPSBydW5pZigxLCAwLjEsIDEwKSwKICAgICAgICAgICAgICAgICd0YXVTcScgPSByZXhwKHAsIHJhdGUgPSAxIC8gMiksICdoJyA9IHJnYW1tYShwcmlvclBhcmEkSiwgMSwgMSkpCiMgaW4gcmVhbCBhcHBsaWNhdGlvbiwgJ251bS5yZXBzJyBzaG91bGQgYmUgbGFyZ2UgZW5vdWdoIChlLmcuIDIwMDAwLCA0MDAwMCkgYW5kICdjaGFpbicgdG8gYmUgPiAxCkJheWVzRU5maXQgPSBwc2JjRU4oc3Vydk9iaiwgcHJpb3JQYXJhLCBpbml0aWFsLCBydyA9IFRSVUUsIG1jbWNQYXJhLCBudW0ucmVwcyA9IDEwMCwgdGhpbiA9IDEsIGNoYWluID0gMSkKIyBidXJuLWluIHRoZSBmaXJzdCBoYWxmIE1DTUMgaXRlcmF0aW9ucwpFTl9iZXRhX3AgPSBCYXllc0VOZml0JGJldGEucFs1MjoxMDEsIF0KRU5fYmV0YV9tZWFuID0gY29sTWVhbnMoRU5fYmV0YV9wKQpFTl9iZXRhX0wgPSBhcHBseShFTl9iZXRhX3AsIDIsIHF1YW50aWxlLCAwLjAyNSkKRU5fYmV0YV9VID0gYXBwbHkoRU5fYmV0YV9wLCAyLCBxdWFudGlsZSwgMC45NzUpCkVOX3RibCA9IGRhdGEuZnJhbWUodGVybSA9IGNvbG5hbWVzKHgpLCBlc3RpbWF0ZSA9IEVOX2JldGFfbWVhbiwgY29uZi5sb3cgPSBFTl9iZXRhX0wsIGNvbmYuaGlnaCA9IEVOX2JldGFfVSkKRU5fdGJsJHRlcm0gPSBmYWN0b3IoRU5fdGJsJHRlcm0sIGxldmVscyA9IEVOX3RibCR0ZXJtKQoKR0dhbGx5OjpnZ2NvZWYoRU5fdGJsKSArIHhsYWIoZXhwcmVzc2lvbihQb3N0ZXJpb3J+fmJldGEpKSArIHlsYWIoIiIpCmBgYAohW19Fc3RpbWF0ZXMgb2YgcmVncmVzc2lvbiBjb2VmZmljaWVudHMgYnkgYSBwZW5hbGl6ZWQgc2VtaXBhcmFtZXRyaWMgQmF5ZXNpYW4gQ294IG1vZGVsIHdpdGggRWxhc3RpYyBOZXQgcHJpb3IuIFNvbGlkIGRvdHMgaW5kaWNhdGUgdGhlIHBvc3RlcmlvciBtZWFuIG92ZXIgTUNNQyBpdGVyYXRpb25zIChleGNsdWRpbmcgYnVybi1pbiBwZXJpb2QpLCBhbmQgaG9yaXpvbnRhbCBsaW5lcyBzaG93IHRoZSBjb3JyZXNwb25kaW5nIDk1JSBjcmVkaWJpbGl0eSBpbnRlcnZhbHMuX10oZmlnL1RDR0FfYmF5ZXNFTi5wbmcpe3dpZHRoPTYwJX0KCjxicj4KCkEgcGVuYWxpemVkIHNlbWlwYXJhbWV0cmljIEJheWVzaWFuIENveCBtb2RlbCB3aXRoIGRvdWJsZSBleHBvbmVudGlhbCBzcGlrZS1hbmQtc2xhYiBwcmlvciBpcyBpbXBsZW1lbnRlZCBpbiB0aGUgYFJgIHBhY2thZ2UgWyoqQmhHTE0qKl0oaHR0cHM6Ly9naXRodWIuY29tL255aXVhYi9CaEdMTS5naXQpIFtAWWkyMDE5XS4gTm90ZSB0aGF0ICoqQmhHTE0qKiBwcm92aWRlcyBmcmVxdWVudGlzdCBjb25maWRlbmNlIGludGVydmFscyBvZiB0aGUgcG9zdGVyaW9yIG1vZGUgb2YgdGhlIGNvZWZmaWNpZW50cy4KCmBgYHtyfQojIHBlbmFsaXplZCBzZW1pcGFyYW1ldHJpYyBCYXllc2lhbiBDb3ggbW9kZWwgd2l0aCAoZG91YmxlIGV4cG9uZW50aWFsKSBzcGlrZS1hbmQtc2xhYiBwcmlvcgp5X3N1cnYgPSBTdXJ2KGNsaW4kdGltZSwgY2xpbiRzdGF0dXMpCnhfZGF0YWZyYW1lID0gYXMuZGF0YS5mcmFtZSh4KQpzZXQuc2VlZCgxMjMpCkJheWVzZml0ID0gQmhHTE06OmJjb3hwaCh5X3N1cnYgfiAuLCB4X2RhdGFmcmFtZSwgcHJpb3IgPSBtZGUoMCwgMC4wMSwgMC44KSwgY29udHJvbCA9IGNveHBoLmNvbnRyb2woaXRlci5tYXggPSAyMDApKQpCaEdMTTo6cGxvdC5iaChCYXllc2ZpdCwgY29sLnB0cyA9IGMoInJlZCIsICJibHVlIiksIG1haW4gPSAiQ294IHdpdGggbWl4dHVyZSBkb3VibGUgZXhwb25lbnRpYWxcbiIpIApgYGAKIVtfQ29lZmZpY2llbnQgZXN0aW1hdGVzIG9mIGEgcGVuYWxpemVkIHNlbWlwYXJhbWV0cmljIEJheWVzaWFuIENveCBtb2RlbCB3aXRoIChkb3VibGUgZXhwb25lbnRpYWwpIHNwaWtlLWFuZC1zbGFiIHByaW9yLiBTb2xpZCBkb3RzIGRlbm90ZSB0aGUgcG9zdGVyaW9yIG1vZGUgb2YgdGhlIGNvZWZmaWNpZW50cyBhbmQgbGluZXMgZGVub3RlIHRoZSA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbHMuIFJlZCBjb2xvcmVkIHRleHQgb24gdGhlIHJpZ2h0IHNpZGUgbWFyayB0aGUgc2lnbmlmaWNhbnQgZmVhdHVyZXMgd2l0aCAkcCA8IDAuMDUkLl9dKGZpZy9UQ0dBX2JheWVzU3Bpa2VTbGFiLnBuZyl7d2lkdGg9NjAlfQoKPGJyPgoKIyBTdXJ2aXZhbCBtb2RlbCB2YWxpZGF0aW9uCgpUaGUgaWRlYWwgZXZhbHVhdGlvbiBvZiBhIHByb2dub3N0aWMgbW9kZWwgaXMgYmFzZWQgb24gY29tcGxldGVseSBpbmRlcGVuZGVudCB2YWxpZGF0aW9uIGRhdGEsIHNpbmNlIGhpZ2gtZGltZW5zaW9uYWwgc3Vydml2YWwgbW9kZWxzIGJ1aWx0IG9uIHRoZSB0cmFpbmluZyBkYXRhIGNhbiBiZSBvdmVyZml0dGVkLiAKSWYgdGhlcmUgYXJlIG5vIGluZGVwZW5kZW50IHZhbGlkYXRpb24gZGF0YSwgaXQgaXMgcmVjb21tZW5kZWQgdG8gdXNlIHJlc2FtcGxpbmctYmFzZWQgbWV0aG9kcyBmb3IgZXN0aW1hdGluZyB0aGUgKip1bmNlcnRhaW50eSoqIG9mIHRoZSBtb2RlbOKAmXMgcHJlZGljdGlvbiBwZXJmb3JtYW5jZS4gClRoaXMgY2FuIGJlIGRvbmUgZm9yIGV4YW1wbGUgYnkgcmVwZWF0ZWRseSBzcGxpdHRpbmcgdGhlIGRhdGFzZXQgdG8gdHJhaW5pbmcvdmFsaWRhdGlvbiBzZXRzIGFuZCBldmFsdWF0aW5nIGEgbW9kZWzigJlzIHBlcmZvcm1hbmNlIG9uIHRoZSBkaWZmZXJlbnQgdmFsaWRhdGlvbiBzZXRzIHVzaW5nIHZhcmlvdXMgZXZhbHVhdGlvbiBtZXRyaWNzLiAKCjo6OnsuZ3JlZW4tYm94fQpUbyB2YWxpZGF0ZSBhIHByZWRpY3Rpb24gbW9kZWwgc3lzdGVtYXRpY2FsbHksIHRoZSBwcmVkaWN0aXZlIHBlcmZvcm1hbmNlIG9mIHRoZSBtb2RlbCBpcyBjb21tb25seSBhZGRyZXNzZWQgYnkKCiAgLSAqKkRpc2NyaW1pbmF0aW9uKio6IHRoZSBhYmlsaXR5IG9mIHRoZSBtb2RlbCB0byBkaXN0aW5ndWlzaCBiZXR3ZWVuIGxvdyBhbmQgaGlnaCByaXNrIHBhdGllbnRzCiAgLSAqKkNhbGlicmF0aW9uKio6IHRoZSBhZ3JlZW1lbnQgYmV0d2VlbiB0aGUgb2JzZXJ2ZWQgYW5kIHByZWRpY3RlZCBzdXJ2aXZhbCBwcm9iYWJpbGl0aWVzCiAgLSAqKk92ZXJhbGwgcGVyZm9ybWFuY2UqKjogdGhlIGRpc3RhbmNlIGJldHdlZW4gdGhlIG9ic2VydmVkIGFuZCBwcmVkaWN0ZWQgc3Vydml2YWwgcHJvYmFiaWxpdGllcwo6OjoKClRoZSBwZXJmb3JtYW5jZSBtZXRyaWNzIGNhbiBiZSAqdGltZS1kZXBlbmRlbnQqIG9yICp0aW1lLWluZGVwZW5kZW50Kiwgd2l0aCB0aGUgdGltZS1kZXBlbmRlbnQgbWV0cmljcyBiZWluZyBtb3JlIGluZm9ybWF0aXZlIGluIGdlbmVyYWwgY29tcGFyZWQgdG8gaW50ZWdyYXRlZCBtZWFzdXJlcyAoaS5lLiBldmFsdWF0ZWQgYWNyb3NzIG1hbnkgdGltZSBwb2ludHMpLgpGb3Igc3Vydml2YWwgZGF0YSwgd2UgY2FuIGFzc2VzcyB0aGUgKipkaXNjcmltaW5hdG9yeSBwb3dlcioqIG9mIGEgbW9kZWwgKGkuZS4gaG93IHdlbGwgZG9lcyBpdCByYW5rcyBwYXRpZW50cykgb3IgaG93IHdlbGwgYSBtb2RlbCBpcyAqKmNhbGlicmF0ZWQqKiAoaS5lLiBob3cgY2xvc2VseSB0aGUgcHJlZGljdGVkIHN1cnZpdmFsIHByb2JhYmlsaXRpZXMgYWdyZWUgbnVtZXJpY2FsbHkgd2l0aCB0aGUgYWN0dWFsIHN1cnZpdmFsIG91dGNvbWVzKS4KRm9yIGV4YW1wbGUsIG1lYXN1cmVzIHN1Y2ggYXMgdGhlIHJlY2VpdmVyIG9wZXJhdGluZyBjaGFyYWN0ZXJpc3RpYyAoUk9DKSBjdXJ2ZSwgdGhlIChpbnRlZ3JhdGVkKSBhcmVhIHVuZGVyIHRpbWUtc3BlY2lmaWMgUk9DIGN1cnZlcyAoKipBVUMqKiwgQEhlYWdlcnR5MjAwNSkgYW5kIHRoZSBjb25jb3JkYW5jZSBpbmRleCAoKipDLWluZGV4KiosIEBIYXJyZWxsMTk4MikgYXJlIG1lYXN1cmVzIG9mIGRpc2NyaW1pbmF0aW9uLCB3aGlsZSB0aGUgcmlnaHQtY2Vuc29yZWQgbG9nYXJpdGhtaWMgbG9zcyAoKipSQ0xMKiosIEBBdmF0aTIwMjApIGFuZCB0aGUgd2VsbC1rbm93biAqKkJyaWVyIHNjb3JlKiogW0BHcmFmMTk5OV0gYXJlIHVzZWQgdG8gZXZhbHVhdGUgYm90aCBkaXNjcmltaW5hdGlvbiBhbmQgY2FsaWJyYXRpb24gcGVyZm9ybWFuY2UuCgojIyBNb2RlbCBldmFsdWF0aW9uIChjbGFzc2ljKSB7LX0KCjo6OnsuZ3JlZW4tYm94fQonQ2xhc3NpYycgaGVyZSByZWZlcnMgdG8gdGhlIHVzZSBvZiBtYW51YWwgYFJgIGNvZGUgaW4gY29tYmluYXRpb24gd2l0aCBtYW55IHNlcGFyYXRlIGBSYCBwYWNrYWdlcyB3aGljaCBoYXZlIGJlZW4gcm91dGluZWx5IHVzZWQgaW4gYWNhZGVtaWEgdGhlIGxhdGVzdCAxMCsgeWVhcnMgZm9yIGV2YWx1YXRpbmcgc3Vydml2YWwgbW9kZWxzLgo6OjoKClRvIGV2YWx1YXRlIHRoZSBwZXJmb3JtYW5jZSBvZiBhIHN0YXRpc3RpY2FsIG1vZGVsLCB3ZSBmaXJzdCBzcGxpdCB0aGUgZGF0YSBpbnRvIHRyYWluaW5nIGFuZCB2YWxpZGF0aW9uIGRhdGEgc2V0cy4KRm9yIGV4YW1wbGUsIHdlIGNhbiByYW5kb21seSBzcGxpdCB0aGUgMTA0NyBCUkNBIHBhdGllbnRzIGZyb20gVENHQSBpbnRvICQ4MFwlJCBhcyB0cmFpbmluZyBzZXQgYW5kICQyMFwlJCBhcyB2YWxpZGF0aW9uIHNldC4KCmBgYHtyfQpzZXQuc2VlZCgxMjMpCm4gPSBucm93KHgpCmlkeCA9IHNhbXBsZSgxOm4sIG4gKiAwLjgsIHJlcGxhY2UgPSBGQUxTRSkKeF90cmFpbiA9IHhbaWR4LCBdCnlfdHJhaW4gPSB5W2lkeCwgXQp4X3ZhbGlkYXRlID0geFstaWR4LCBdCnlfdmFsaWRhdGUgPSB5Wy1pZHgsIF0KYGBgCgo6Ojp7LmluZm8tYm94IC5ub3RlfQpUaGUgJDIwXCUkIHNwbGl0IG9mIGEgZGF0YXNldCBpcyBvZnRlbiBub3QgY29uc2lkZXJlZCBhbiAqKmluZGVwZW5kZW50KiogZGF0YXNldCBhbmQgKipyZXNhbXBsaW5nLWJhc2VkIG1ldGhvZHMqKiBzaG91bGQgYmUgdXNlZCBpbiBzdWNoIGNhc2VzIHRvIHByb3ZpZGUgYW4gdW5iaWFzZWQgZXN0aW1hdGUgb2YgdGhlIHByZWRpY3RpdmUgYWNjdXJhY3kgb2YgYSBwcm9nbm9zdGljIG1vZGVsLgo6OjoKCiMjIyBEaXNjcmltaW5hdGlvbiBtZXRyaWNzIHstfQoKPGZvbnQgc2l6ZT0iNCI+ICoqR29vZG5lc3Mtb2YtZml0KiogPC9mb250PiAKClRoZSBzaW1wbGVzdCB3YXkgdG8gZGVtb25zdHJhdGUgdGhlIHByb2dub3N0aWMgcG93ZXIgb2YgYSBzdXJ2aXZhbCBtb2RlbCBpcyB0byBkaWNob3RvbWl6ZSB0aGUgcHJvZ25vc3RpYyBzY29yZXMgKGkuZS4sIGxpbmVhciBwcmVkaWN0b3IgJGxwJCBpbiB0aGUgQ294IG1vZGVsKSBieSBtZWRpYW4gdmFsdWUsIGFuZCB0aGVuIHRvIHVzZSBhIGxvZy1yYW5rIHRlc3QgdG8gY29tcGFyZSB0aGUgc3Vydml2YWwgY3VydmVzIG9mIHRoZSBwYXRpZW50cyBpbiB0aGUgdHdvIGdyb3Vwcy4KV2UgdXNlIHRoZSBidWlsdCBtb2RlbCB0byBwcmVkaWN0IHRoZSBwcm9nbm9zdGljIHNjb3JlcyBiYXNlZCBvbiB0aGUgJDIwXCUkIHZhbGlkYXRpb24gZGF0YS4KVGhlIGZvbGxvd2luZyBjb2RlIHNob3dzIHRoZSAqKmdvb2RuZXNzLW9mLWZpdCoqIG9mIGEgTGFzc28gQ294IG1vZGVsIHdpdGggdGhlIEJSQ0EgcGF0aWVudHMgc3Vydml2YWwgYW5kIFBBTTUwIG1STkEtU2VxIGRhdGEgZnJvbSBUQ0dBLgoKYGBge3J9CiMgdHJhaW4gYSBMYXNzbyBDb3ggbW9kZWwsIHNpbWlsYXJseSBmb3Igb3RoZXIgQ294LXR5cGUgbW9kZWxzCnNldC5zZWVkKDEyMykKY3ZmaXQgPSBjdi5nbG1uZXQoeF90cmFpbiwgeV90cmFpbiwgZmFtaWx5ID0gImNveCIsIG5mb2xkcyA9IDUsIHBlbmFsdHkuZmFjdG9yID0gcGYpCnByZWRfbHAgPSBwcmVkaWN0KGN2Zml0LCBuZXd4ID0geF92YWxpZGF0ZSwgcyA9IGN2Zml0JGxhbWJkYS5taW4sIHR5cGUgPSAibGluayIpCgojIGRpY2hvdG9taXplIGJ5IHByb2dub3N0aWMgc2NvcmVzIChsaW5lYXIgcHJlZGljdG9yKSAgYnkgbWVkaWFuIHRvIGRpdmlkZSB0aGUgdmFsaWRhdGlvbiBwYXRpZW50cyBpbnRvIHR3byBncm91cHMKZ3JvdXBfZGljaG90b21pemUgPSBhcy5udW1lcmljKHByZWRfbHAgPiBtZWRpYW4ocHJlZF9scCkpCgojIGRyYXcgdHdvIHN1cnZpdmFsIGN1cnZlcyBiYXNlZCBvbiBLTSBlc3RpbWF0aW9uIGFuZCBjb21wYXJlIHRoZW0gYnkgYSBsb2ctcmFuayB0ZXN0CmRhdF90bXAgPSBkYXRhLmZyYW1lKHRpbWUgPSB5X3ZhbGlkYXRlWywgMV0sIHN0YXR1cyA9IHlfdmFsaWRhdGVbLCAyXSwgZ3JvdXAgPSBncm91cF9kaWNob3RvbWl6ZSkKc2ZpdCA9IHN1cnZmaXQoU3Vydih0aW1lLCBzdGF0dXMpIH4gZ3JvdXAsIGRhdGEgPSBkYXRfdG1wKQoKZ2dzdXJ2ID0gZ2dzdXJ2cGxvdChzZml0LCBjb25mLmludCA9IFRSVUUsIHJpc2sudGFibGUgPSBUUlVFLCAKICAgICAgICAgICB4bGFiID0gIlRpbWUgc2luY2UgZGlhZ25vc2lzICh5ZWFyKSIsIGxlZ2VuZCA9IGMoLjIsLjMpLAogICAgICAgICAgIGxlZ2VuZC5sYWJzID0gYygiTG93IHJpc2siLCAiSGlnaCByaXNrIiksIGxlZ2VuZC50aXRsZSA9ICJEaWNob3RvbWl6ZWQgZ3JvdXBzIiwgIAogICAgICAgICAgIHJpc2sudGFibGUueS50ZXh0LmNvbCA9IFRSVUUsIHJpc2sudGFibGUueS50ZXh0ID0gRkFMU0UpCmdnc3VydiRwbG90ID0gZ2dzdXJ2JHBsb3QgKyAKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAyLjYsIHkgPSAuMDMsIGxhYmVsPSBwYXN0ZTAoIkxvZy1yYW5rIHRlc3Q6XG4iLCBzdXJ2X3B2YWx1ZShzZml0KSRwdmFsLnR4dCkpCmdnc3VydiR0YWJsZSA9IGdnc3VydiR0YWJsZSArIGxhYnMoeSA9ICJEaWNob3RvbWl6ZWRcbiBncm91cHMiKQpnZ3N1cnYKYGBgCiFbX0thcGxhbi1NZWllciBjdXJ2ZXMgb2YgdGhlIEJSQ0EgcGF0aWVudHMgZGF0YSBkaWNob3RvbWl6ZWQgYnkgdGhlIG1lZGlhbiBvZiBwcm9nbm9zdGljIHNjb3JlcyAoY2FsY3VsYXRlZCBmcm9tIHRoZSBMYXNzbyBDb3ggbW9kZWwgd2l0aCBwYXRpZW50cycgc3Vydml2YWwgYW5kIG1STkEtU2VxIGRhdGEpIGludG8gdHdvIGdyb3Vwcy4gVGhlIGxvZy1yYW5rIHRlc3QgaXMgdG8gY29tcGFyZSB0aGUgdHdvIHN1cnZpdmFsIGRpc3RyaWJ1dGlvbnMgY29ycmVzcG9uZGluZyB0byB0aGUgdHdvIGdyb3VwcyBvZiBwYXRpZW50cy5fXShmaWcvVENHQV9zdXJ2X2ttX2xhc3NvLnBuZyl7d2lkdGg9NjAlfQoKPGJyPgoKVGhlIHByb2dub3N0aWMgc2NvcmVzIGNhbiBhbHNvIGJlIGRpdmlkZWQgaW50byB0aHJlZSBvciBtb3JlIGdyb3VwcyBiYXNlZCBvbiBxdWFudGlsZXMgYW5kIHRoZSBsb2ctcmFuayB0ZXN0IGNhbiBiZSB1c2VkIHRvIGNvbXBhcmUgdGhlIGRpZmZlcmVuY2Ugb2YgbXVsdGlwbGUgc3Vydml2YWwgY3VydmVzLgoKYGBge3J9Cmdyb3VwID0gcHJlZF9scApncm91cFtwcmVkX2xwID49IHF1YW50aWxlKHByZWRfbHAsIDIvMyldID0gMwpncm91cFtwcmVkX2xwID49IHF1YW50aWxlKHByZWRfbHAsIDEvMykgJiBwcmVkX2xwIDwgcXVhbnRpbGUocHJlZF9scCwgMi8zKV0gPSAyCmdyb3VwW3ByZWRfbHAgPCBxdWFudGlsZShwcmVkX2xwLCAxLzMpXSA9IDEKCiMgZHJhdyB0d28gc3Vydml2YWwgY3VydmVzIGJhc2VkIG9uIEtNIGVzdGltYXRpb24gYW5kIGNvbXBhcmUgdGhlbSBieSBhIGxvZy1yYW5rIHRlc3QKZGF0X3RtcCA9IGRhdGEuZnJhbWUodGltZSA9IHlfdmFsaWRhdGVbLCAxXSwgc3RhdHVzID0geV92YWxpZGF0ZVssIDJdLCBncm91cCA9IGdyb3VwKQpzZml0ID0gc3VydmZpdChTdXJ2KHRpbWUsIHN0YXR1cykgfiBncm91cCwgZGF0YSA9IGRhdF90bXApCgpnZ3N1cnYgPSBnZ3N1cnZwbG90KHNmaXQsIGNvbmYuaW50ID0gVFJVRSwgcmlzay50YWJsZSA9IFRSVUUsIAogICAgICAgICAgIHhsYWIgPSAiVGltZSBzaW5jZSBkaWFnbm9zaXMgKHllYXIpIiwgbGVnZW5kID0gYyguMiwuMyksCiAgICAgICAgICAgbGVnZW5kLmxhYnMgPSBjKCJMb3cgcmlzayIsICJNaWRkbGUgcmlzayIsICJIaWdoIHJpc2siKSwgbGVnZW5kLnRpdGxlID0gIkdyb3VwcyIsICAKICAgICAgICAgICByaXNrLnRhYmxlLnkudGV4dC5jb2wgPSBUUlVFLCByaXNrLnRhYmxlLnkudGV4dCA9IEZBTFNFKQpnZ3N1cnYkcGxvdCA9IGdnc3VydiRwbG90ICsgCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMy41LCB5ID0gLjA1LCBsYWJlbD0gcGFzdGUwKCJMb2ctcmFuayB0ZXN0OlxuIiwgc3Vydl9wdmFsdWUoc2ZpdCkkcHZhbC50eHQpKQpnZ3N1cnYKYGBgCiFbX0thcGxhbi1NZWllciBjdXJ2ZXMgb2YgdGhlIEJSQ0EgcGF0aWVudHMgZGF0YSBkaXZpZGVkIGJ5IDMzJSBhbmQgNjclIHF1YW50aWxlcyBvZiBwcm9nbm9zdGljIHNjb3JlcyAoY2FsY3VsYXRlZCBmcm9tIHRoZSBMYXNzbyBDb3ggbW9kZWwgd2l0aCBwYXRpZW50cycgc3Vydml2YWwgYW5kIG1STkEtU2VxIGRhdGEpIGludG8gdGhyZWUgZ3JvdXBzLiBUaGUgbG9nLXJhbmsgdGVzdCBpcyB0byBjb21wYXJlIHRoZSB0d28gc3Vydml2YWwgZGlzdHJpYnV0aW9ucyBjb3JyZXNwb25kaW5nIHRvIHRoZSB0aHJlZSBncm91cHMgb2YgcGF0aWVudHMuX10oZmlnL1RDR0Ffc3Vydl9rbV9sYXNzbzIucG5nKXt3aWR0aD02MCV9Cgo8YnI+Cgo8Zm9udCBzaXplPSI0Ij4gKipST0MgY3VydmUqKiA8L2ZvbnQ+IAoKVGhlIGBSYCBwYWNrYWdlIFsqKnJpc2tzZXRST0MqKl0oaHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT1yaXNrc2V0Uk9DKSBbQEhlYWdlcnR5MjAwNV0gY2FuIGVzdGltYXRlIGEgUk9DIGN1cnZlIGF0IGFuIGV2YWx1YXRpb24gdGltZSBwb2ludC4gClRoZSBmb2xsb3dpbmcgY29kZSBkcmF3cyBhIFJPQyBjdXJ2ZSBhdCA1LXllYXJzIHN1cnZpdmFsIGV2YWx1YXRpb24gdGltZSBwb2ludCBmb3IgdGhlIDIwJSBUQ0dBIHZhbGlkYXRpb24gZGF0YSBhbmQgYmFzZWQgb24gYSBMYXNzbyBDb3ggbW9kZWwgbGVhcm5lZCBmcm9tIHRoZSA4MCUgdHJhaW5pbmcgZGF0YS4KCmBgYHtyfQpST0MgPSByaXNrc2V0Uk9DKFN0aW1lID0geV92YWxpZGF0ZVssIDFdLCBzdGF0dXMgPSB5X3ZhbGlkYXRlWywgMl0sCiAgICAgICAgICAgICAgICAgbWFya2VyID0gcHJlZF9scCwgcHJlZGljdC50aW1lID0gNSwgbWV0aG9kID0gIkNveCIsIAogICAgICAgICAgICAgICAgIG1haW4gPSAiUk9DIEN1cnZlIiwgY29sID0gInNlYWdyZWVuMyIsIHR5cGUgPSAicyIsIAogICAgICAgICAgICAgICAgIGx3ZCA9IDIsIHhsYWI9IjEgLSBTcGVjaWZpY2l0eSIsIHlsYWI9IlNlbnNpdGl2aXR5IikgCnRleHQoMC43LCAwLjIsIHBhc3RlKCJBVUMgPSIsIHJvdW5kKFJPQyRBVUMsIDMpKSkKYGBgCgohW19ST0MgY3VydmUgZXN0aW1hdGVkIGF0IDUteWVhcnMgc3Vydml2YWwgZXZhbHVhdGlvbiB0aW1lIHBvaW50IGZvciB0aGUgMjAlIFRDR0EgdmFsaWRhdGlvbiBkYXRhIGFuZCBiYXNlZCBvbiBhIExhc3NvIENveCBtb2RlbCBsZWFybmVkIGZyb20gdGhlIDgwJSB0cmFpbmluZyBkYXRhLiBUaGUgQVVDIHZhbHVlIGlzIHRoZSBhcmVhIHVuZGVyIHRoZSBST0MgY3VydmUuIFRoZSBkaWFnb25hbCBsaW5lIHJlcHJlc2VudHMgdGhlIHBlcmZvcm1hbmNlIG9mIGEgcmFuZG9tIHByZWRpY3Rpb24gb2YgdGhlIG91dGNvbWUgZXZlbnQgd2l0aCBBVUMgPSAwLjUuX10oZmlnL1RDR0Ffc3Vydl9yb2MucG5nKXt3aWR0aD01MCV9Cgo8YnI+Cgo8Zm9udCBzaXplPSI0Ij4gKipUaW1lLWRlcGVuZGVudCBBVUMqKiA8L2ZvbnQ+IAoKQm90aCB0aW1lLWRlcGVuZGVudCBhbmQgaW50ZWdyYXRlZCBBVUNzIGNhbiBiZSBlc3RpbWF0ZWQgYnkgdGhlIGBSYCBwYWNrYWdlIFsqKnJpc2tzZXRST0MqKl0oaHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT1yaXNrc2V0Uk9DKS4gCldlIGRlbW9uc3RyYXRlIHRoZSBjYWxjdWxhdGlvbiBiYXNlZCBvbiBib3RoIHRyYWluaW5nIGFuZCB2YWxpZGF0aW9uIGRhdGEuCgo6Ojp7LmluZm8tYm94IC5ub3RlfQpBIENveCBwcm9wb3J0aW9uYWwgaGF6YXJkcyBtb2RlbCAoYW5kIExhc3NvIENveCBhcyBhIGNvbnNlcXVlbmNlKSBpcyBhIHNlbWktcGFyYW1ldHJpYyBtb2RlbCwgd2hpY2ggbWVhbnMgdGhhdCBpdCBkb2VzIG5vdCBwcm9kdWNlIHN1cnZpdmFsIGRpc3RyaWJ1dGlvbiBwcmVkaWN0aW9ucyBieSBkZWZhdWx0LgpIb3dldmVyLCB1c2luZyB0aGUgZnVuY3Rpb24gYHJpc2tzZXRST0M6OkNveFdlaWdodHMoKWAgeW91IGNhbiB0cmFuc2Zvcm0gdGhlIGBjdi5nbG1uZXRgJ3Mgb3V0cHV0IGxpbmVhciBwcmVkaWN0b3JzIChgbHBgKSB0byBzdXJ2aXZhbCBkaXN0cmlidXRpb24gcHJlZGljdGlvbnMuClRoaXMgdHJhbnNmb3JtYXRpb24gaW50ZXJuYWxseSB1c2VzIHRoZSBCcmVzbG93IGVzdGltYXRvciBmb3IgdGhlIGN1bXVsYXRpdmUgYmFzZWxpbmUgaGF6YXJkLgo6OjoKCmBgYHtyfQojIHVuaXF1ZSBldmVudCB0aW1lcyBmb3IgcGF0aWVudHMgaW4gdGhlIHRyYWluaW5nIGFuZCB2YWxpZGF0aW9uIGRhdGEgc2V0cwp1dGltZXNfdHJhaW4gPSBzb3J0KHVuaXF1ZSh5X3RyYWluW3lfdHJhaW5bLCAyXSA9PSAxLCAxXSkpCnV0aW1lc192YWxpZGF0ZSA9IHNvcnQodW5pcXVlKHlfdmFsaWRhdGVbeV92YWxpZGF0ZVssIDJdID09IDEsIDFdKSkKCiMgbWFya2VycyBmcm9tIHRoZSBlc3RpbWF0ZWQgbGluZWFyIHByZWRpY3RvcnMgb2YgYSBMYXNzbyBDb3ggbW9kZWwKcHJlZF9scF90cmFpbiA9IHByZWRpY3QoY3ZmaXQsIG5ld3ggPSB4X3RyYWluLCBzID0gY3ZmaXQkbGFtYmRhLm1pbiwgdHlwZSA9ICJsaW5rIikKcHJlZF9scF92YWxpZGF0ZSA9IHByZWRpY3QoY3ZmaXQsIG5ld3ggPSB4X3ZhbGlkYXRlLCBzID0gY3ZmaXQkbGFtYmRhLm1pbiwgdHlwZSA9ICJsaW5rIikKCiMjIGNvbXB1dGUgdGltZS1kZXBlbmRlbnQgQVVDCkFVQ190cmFpbiA9IHJlcChOQSwgbGVuZ3RoKHV0aW1lc190cmFpbikpCkFVQ192YWxpZGF0ZSA9IHJlcChOQSwgbGVuZ3RoKHV0aW1lc192YWxpZGF0ZSkpCmZvciAoaiBpbiAxOmxlbmd0aCh1dGltZXNfdHJhaW4pKSB7CiAgb3V0ID0gcmlza3NldFJPQzo6Q294V2VpZ2h0cyhtYXJrZXIgPSBwcmVkX2xwX3RyYWluLCBTdGltZSA9IHlfdHJhaW5bLCAxXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0dXMgPSB5X3RyYWluWywgMl0sIHByZWRpY3QudGltZSA9IHV0aW1lc190cmFpbltqXSkKICBBVUNfdHJhaW5bal0gPSBvdXQkQVVDCn0KZm9yIChqIGluIDE6bGVuZ3RoKHV0aW1lc192YWxpZGF0ZSkpIHsKICBvdXQgPSByaXNrc2V0Uk9DOjpDb3hXZWlnaHRzKG1hcmtlciA9IHByZWRfbHBfdmFsaWRhdGUsIFN0aW1lID0geV92YWxpZGF0ZVssIDFdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXR1cyA9IHlfdmFsaWRhdGVbLCAyXSwgcHJlZGljdC50aW1lID0gdXRpbWVzX3ZhbGlkYXRlW2pdKQogIEFVQ192YWxpZGF0ZVtqXSA9IG91dCRBVUMKfQoKIyBkcmF3IHRoZSB0aW1lLWRlcGVuZGVudCBBVUMgZnJvbSB0aGUgdHJhaW5pbmcgYW5kIHZhbGlkYXRpb24gZGF0YSBzZXRzCmRhdF9BVUMgPSBkYXRhLmZyYW1lKHRBVUMgPSBjKEFVQ190cmFpbiwgQVVDX3ZhbGlkYXRlKSwgCiAgICAgICAgICAgICAgICAgICAgICB0aW1lcyA9IGModXRpbWVzX3RyYWluLCB1dGltZXNfdmFsaWRhdGUpLAogICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBjKHJlcCgiQVVDX3RyYWluIiwgbGVuZ3RoKEFVQ190cmFpbikpLCByZXAoIkFVQ192YWxpZGF0ZSIsIGxlbmd0aChBVUNfdmFsaWRhdGUpKSkpCmdncGxvdChkYXRfQVVDLCBhZXModGltZXMsIHRBVUMsIGdyb3VwID0gZ3JvdXAsIGNvbG9yID0gZ3JvdXApKSArIHhsYWIoIkV2YWx1YXRpb24gdGltZSBwb2ludHMgKHllYXIpIikgKyB5bGFiKCJBVUMiKSArIHlsaW0oMC41LCAxKSArCiAgZ2VvbV9zdGVwKGRpcmVjdGlvbiA9ICJ2aCIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gYygwLjcsIDAuOCksIGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCkpCmBgYAohW19UaW1lLWRlcGVuZGVudCBBVUMgYmFzZWQgb24gYSBMYXNzbyBDb3ggbW9kZWwgYXBwbGllZCB0byB0aGUgQlJDQSBwYXRpZW50cyBkYXRhIGZyb20gVENHQS4gVGhlIHJlZCBsaW5lIHNob3dzIHRoZSBUaW1lLWRlcGVuZGVudCBBVUMgY2FsY3VsYXRlZCBmcm9tIHRoZSA4MCUgdHJhaW5pbmcgZGF0YSwgYW5kIHRoZSBncmVlbiBsaW5lIHNob3dzIHRoZSBUaW1lLWRlcGVuZGVudCBBVUMgY2FsY3VsYXRlZCBmcm9tIHRoZSAyMCUgdmFsaWRhdGlvbiBkYXRhLl9dKGZpZy9UQ0dBX3N1cnZfYXVjX2xhc3NvLnBuZyl7d2lkdGg9NTAlfQoKPGJyPgoKPGZvbnQgc2l6ZT0iNCI+ICoqSW50ZWdyYXRlZCBBVUMqKiA8L2ZvbnQ+IAoKVGhlIGBSYCBwYWNrYWdlIFsqKnJpc2tzZXRST0MqKl0oaHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT1yaXNrc2V0Uk9DKSBbQEhlYWdlcnR5MjAwNV0gcHJvdmlkZXMgZnVuY3Rpb24gYEludGVncmF0ZUFVQygpYCB0byBlc3RpbWF0ZSBpbnRlZ3JhdGVkIEFVQy4KCmBgYHtyfQojIEJlZm9yZSBjb21wdXRpbmcgaW50ZWdyYXRlZCBBVUMsIGZpcnN0IGVzdGltYXRlIHN1cnZpdmFsIHByb2JhYmlsaXRpZXMgYXQgdW5pcXVlIHN1cnZpdmFsIHRpbWVzCnN1cnZfcHJvYl90cmFpbiA9IHVuaXF1ZShzdXJ2Zml0KFN1cnYoeV90cmFpblssIDFdLCB5X3RyYWluWywgMl0pIH4gMSkkc3VydikKc3Vydl9wcm9iX3ZhbGlkYXRlID0gdW5pcXVlKHN1cnZmaXQoU3Vydih5X3ZhbGlkYXRlWywgMV0sIHlfdmFsaWRhdGVbLCAyXSkgfiAxKSRzdXJ2KQoKIyMgaW50ZWdyYXRlZCBBVUMgKGUuZy4gb3ZlciB0bWF4PTEwIHllYXJzKSB0byBnZXQgY29uY29yZGFuY2UgbWVhc3VyZSBiYXNlZCBvbiB0cmFpbmluZyBkYXRhCihpQVVDX3RyYWluID0gcmlza3NldFJPQzo6SW50ZWdyYXRlQVVDKEFVQ190cmFpbiwgdXRpbWVzX3RyYWluLCBzdXJ2X3Byb2JfdHJhaW4sIHRtYXggPSAxMCkpCmBgYApgYGAKWzFdIDAuNjI4MTMwMQpgYGAKYGBge3J9CiMjIGludGVncmF0ZWQgQVVDIChlLmcuIG92ZXIgdG1heD0xMCB5ZWFycykgdG8gZ2V0IGNvbmNvcmRhbmNlIG1lYXN1cmUgYmFzZWQgb24gdmFsaWRhdGlvbiBkYXRhCihpQVVDX3ZhbGlkYXRlID0gcmlza3NldFJPQzo6SW50ZWdyYXRlQVVDKCBBVUNfdmFsaWRhdGUsIHV0aW1lc192YWxpZGF0ZSwgc3Vydl9wcm9iX3ZhbGlkYXRlLCB0bWF4ID0gMTApKQpgYGAKYGBgClsxXSAwLjYzMTg4NTcKYGBgCgo8Zm9udCBzaXplPSI0Ij4gKipUaW1lLWRlcGVuZGVudCBDLWluZGV4KiogPC9mb250PiAKClRoZSBDLWluZGV4IGlzIG5vdCBwcm9wZXIgZm9yICR0JC15ZWFyIHByZWRpY3Rpb25zLCBzZWUgQEJsYW5jaGUyMDE5LgpDb25zaWRlciB1c2luZyB0aW1lLWRlcGVuZGVudCBBVUMgb3IgdGltZS1kZXBlbmRlbnQgQnJpZXIgc2NvcmUgaW5zdGVhZC4KRm9yIGEgdGltZS1kZXBlbmRlbnQgZGlzY3JpbWluYXRpb24gaW5kZXggZm9yIHN1cnZpdmFsIGRhdGEsIHNlZSBAQW50b2xpbmkyMDA1LgoKPGZvbnQgc2l6ZT0iNCI+ICoqQy1pbmRleCoqIDwvZm9udD4gCgpUaGUgYFJgIHBhY2thZ2UgWyoqZ2xtbmV0KipdKGh0dHBzOi8vQ1JBTi5SLXByb2plY3Qub3JnL3BhY2thZ2U9Z2xtbmV0KSBwcm92aWRlcyB0aGUgZnVuY3Rpb24gYGdsbW5ldDo6Q2luZGV4KClgIHRvIGVzdGltYXRlIEhhcnJlbGwncyBDLWluZGV4IGZyb20gYSAiY294bmV0IiBvYmplY3QuClRoZSBgUmAgcGFja2FnZSBbKipzdXJ2QVVDKipdKGh0dHBzOi8vQ1JBTi5SLXByb2plY3Qub3JnL3BhY2thZ2U9c3VydkFVQykgcHJvdmlkZXMgdGhlIGZ1bmN0aW9uIGBzdXJ2QVVDOjpVbm9DKClgIHRvIGVzdGltYXRlZCBVbm8ncyBDLWluZGV4LgpTZWUgYW4gZXhhbXBsZSBjYWxjdWxhdGlvbiBmb3IgYm90aCBDLWluZGV4ZXMgdXNpbmcgYSBMYXNzbyBDb3ggbW9kZWwgYmVsb3cuCgpgYGB7cn0Kc2V0LnNlZWQoMTIzKQpjdmZpdCA9IGN2LmdsbW5ldCh4X3RyYWluLCB5X3RyYWluLCBmYW1pbHkgPSAiY294IiwgbmZvbGRzID0gNSwgcGVuYWx0eS5mYWN0b3IgPSBwZikKcHJlZCA9IHByZWRpY3QoY3ZmaXQsIG5ld3ggPSB4X3ZhbGlkYXRlLCB0eXBlID0gInJlc3BvbnNlIiwgcyA9IGN2Zml0JGxhbWJkYS5taW4pCiMgSGFycmVsbCdzIEMtaW5kZXgKKENpbmRleF9IYXJyZWxsID0gbWVhbihhcHBseShwcmVkLCAyLCBDaW5kZXgsIHkgPSB5X3ZhbGlkYXRlKSkpCmBgYApgYGAKWzFdIDAuNzMyMDIyMQpgYGAKYGBge3J9CiMgVW5vJ3MgQy1pbmRleAooQ2luZGV4X1VubyA9IHN1cnZBVUM6OlVub0MoeV90cmFpbiwgeV92YWxpZGF0ZSwgcHJlZCkpCmBgYApgYGAKWzFdIDAuNTc4Njg2MQpgYGAKCjxicj4KCiMjIyBDYWxpYnJhdGlvbiBtZXRyaWNzIHstfQoKU2VlIGEgW2NhbGlicmF0aW9uIHBsb3RdKCNzbG9wZUNhbGkpIGluIHRoZSBmb2xsb3dpbmcgc2VjdGlvbiBbR3JhcGhpY2FsIGNvbXB1dGF0aW9uXSgjZ3JhcGhDb21wKS4KCjxicj4KCiMjIyBPdmVyYWxsIG1ldHJpY3Mgey19Cgo8Zm9udCBzaXplPSI0Ij4gKipUaW1lLWRlcGVuZGVudCBCcmllciBzY29yZSoqIDwvZm9udD4gCgpUaGUgYFJgIHBhY2thZ2UgWyoqcmlza1JlZ3Jlc3Npb24qKl0oaHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT1yaXNrUmVncmVzc2lvbikgY2FuIGFzc2VzcyB0aGUgcHJlZGljdGlvbiBlcnJvciBjdXJ2ZXMgb2Ygc3Vydml2YWwgbW9kZWxzIGJhc2VkIG9uIHRoZSB0aW1lLWRlcGVuZGVudCBCcmllciBzY29yZS4KU2ltaWxhciB0byB0aGUgdGltZS1kZXBlbmRlbnQgQVVDLCBvbmUgbmVlZHMgdG8gZmlyc3QgY2FsY3VsYXRlIHRoZSBsaW5lYXIgcHJlZGljdG9ycyAoJGxwJCkgZnJvbSBhIGZyZXF1ZW50aXN0IG9yIEJheWVzaWFuIENveCBtb2RlbCwgYW5kIHRoZW4gdXNlIGBzdXJ2aXZhbDo6Y294cGgoKWAgdG8gcmVncmVzcyB0aGUgc3Vydml2YWwgb3V0Y29tZXMgb24gdGhlIGxpbmVhciBwcmVkaWN0b3IsIHdoaWNoIGlzIHByZXBhcmVkIGFzIGlucHV0IG9mIGByaXNrUmVncmVzc2lvbjo6U2NvcmUoKWAgdG8gZXN0aW1hdGUgdGhlICh0aW1lLWRlcGVuZGVudCkgQnJpZXIgc2NvcmUuCgpgYGB7cn0KIyMgdGltZS1kZXBlbmRlbnQgQnJpZXIgc2NvcmUKCiMgdXNlIHRoZSAoeF90cmFpbiwgeV90cmFpbikgODAlIHNhbXBsZXMgZm9yIHRyYWluaW5nCiMgYW5kIHRoZSAoeF92YWxpZGF0ZSwgeV92YWxpZGF0ZSkgMjAlIHNhbXBsZXMgZm9yIHRlc3RpbmcKCnlfdHJhaW5fc3VydiA9IFN1cnYoeV90cmFpblssInRpbWUiXSwgeV90cmFpblssInN0YXR1cyJdKQp5X3ZhbGlkYXRlX3N1cnYgPSBTdXJ2KHlfdmFsaWRhdGVbLCJ0aW1lIl0sIHlfdmFsaWRhdGVbLCJzdGF0dXMiXSkKc2V0LnNlZWQoMTIzKQpjdmZpdCA9IGN2LmdsbW5ldCh4X3RyYWluLCB5X3RyYWluX3N1cnYsIGZhbWlseSA9ICJjb3giLCBuZm9sZHMgPSA1LCBwZW5hbHR5LmZhY3RvciA9IHBmKQpscF90cmFpbiA9IHByZWRpY3QoY3ZmaXQsIG5ld3ggPSB4X3RyYWluLCBzID0gY3ZmaXQkbGFtYmRhLm1pbiwgdHlwZSA9ICJsaW5rIikKbHBfdmFsaWRhdGUgPSBwcmVkaWN0KGN2Zml0LCBuZXd4ID0geF92YWxpZGF0ZSwgcyA9IGN2Zml0JGxhbWJkYS5taW4sIHR5cGUgPSAibGluayIpCgojIHByZXBhcmUgZGF0YSBmb3JtYXQgc3VpdGVkIGZvciBmdW5jdGlvbiBTY29yZSgpIGZyb20gdGhlIHJpc2tSZWdyZXNzaW9uIHBhY2thZ2UKZGF0YV90cmFpbiA9IGRhdGEuZnJhbWUodGltZSA9IHlfdHJhaW5bLCJ0aW1lIl0sIHN0YXR1cyA9IHlfdHJhaW5bLCJzdGF0dXMiXSwgbHAgPSBhcy52ZWN0b3IobHBfdHJhaW4pKQpkYXRhX3ZhbGlkYXRlID0gZGF0YS5mcmFtZSh0aW1lID0geV92YWxpZGF0ZVssInRpbWUiXSwgc3RhdHVzID0geV92YWxpZGF0ZVssInN0YXR1cyJdLCBscCA9IGFzLnZlY3RvcihscF92YWxpZGF0ZSkpCmxhc3NvX3RyYWluID0gY294cGgoU3Vydih0aW1lLHN0YXR1cykgfiBscCwgZGF0YSA9IGRhdGFfdHJhaW4sIHk9VFJVRSwgeCA9IFRSVUUpCmxhc3NvX3ZhbGlkYXRlID0gY294cGgoU3Vydih0aW1lLHN0YXR1cykgfiBscCwgZGF0YSA9IGRhdGFfdmFsaWRhdGUsIHk9VFJVRSwgeCA9IFRSVUUpCgojIGNhbGN1bGF0ZSBCcmllciBzY29yZXMgYmFzZWQgb24gYm90aCB0cmFpbmluZyBhbmQgdmFsaWRhdGlvbiBkYXRhCkJyaWVyX3RyYWluID0gcmlza1JlZ3Jlc3Npb246OlNjb3JlKGxpc3QoIkJyaWVyX3RyYWluIiA9IGxhc3NvX3RyYWluKSwgZm9ybXVsYSA9IFN1cnYodGltZSwgc3RhdHVzKSB+IDEsIGRhdGEgPSBkYXRhX3RyYWluLCBjb25mLmludCA9IEZBTFNFLCBtZXRyaWNzID0gImJyaWVyIiwgc3VtbWFyeT0iaWJzIiwgdGltZXMgPSBzb3J0KHVuaXF1ZShkYXRhX3RyYWluJHRpbWUpKSkkQnJpZXIkc2NvcmUKQnJpZXJfdmFsaWRhdGUgPSByaXNrUmVncmVzc2lvbjo6U2NvcmUobGlzdCgiQnJpZXJfdmFsaWRhdGUiID0gbGFzc29fdmFsaWRhdGUpLCBmb3JtdWxhID0gU3Vydih0aW1lLCBzdGF0dXMpIH4gMSwgZGF0YSA9IGRhdGFfdmFsaWRhdGUsIGNvbmYuaW50ID0gRkFMU0UsIG1ldHJpY3MgPSAiYnJpZXIiLCBzdW1tYXJ5PSJpYnMiLCB0aW1lcyA9IHNvcnQodW5pcXVlKGRhdGFfdmFsaWRhdGUkdGltZSkpKSRCcmllciRzY29yZQpCcmllcl9zY29yZSA9IHJiaW5kKEJyaWVyX3RyYWluLCBCcmllcl92YWxpZGF0ZSkKQnJpZXJfc2NvcmUgPSBCcmllcl9zY29yZVtCcmllcl9zY29yZSRtb2RlbCAhPSAiTnVsbCBtb2RlbCIsIF0KICAKZ2dwbG90KEJyaWVyX3Njb3JlLCBhZXModGltZXMsIEJyaWVyLCBncm91cCA9IG1vZGVsLCBjb2xvciA9IG1vZGVsKSkgKyB4bGFiKCJFdmFsdWF0aW9uIHRpbWUgcG9pbnRzICh5ZWFyKSIpICsgeWxhYigiQnJpZXIgc2NvcmUiKSArIAogIGdlb21fc3RlcChkaXJlY3Rpb24gPSAidmgiKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC4xNSwgMC44OCksIGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCkpCmBgYAohW19UaW1lLWRlcGVuZGVudCBCcmllciBzY29yZSBiYXNlZCBvbiBhIExhc3NvIENveCBtb2RlbCBhcHBsaWVkIHRvIHRoZSBCUkNBIHBhdGllbnRzIGRhdGEgZnJvbSBUQ0dBLiBUaGUgcmVkIGxpbmUgc2hvd3MgdGhlIFRpbWUtZGVwZW5kZW50IEJyaWVyIHNjb3JlIGNhbGN1bGF0ZWQgZnJvbSB0aGUgODAlIHRyYWluaW5nIGRhdGEsIGFuZCB0aGUgZ3JlZW4gbGluZSBzaG93cyB0aGUgVGltZS1kZXBlbmRlbnQgQnJpZXIgc2NvcmUgY2FsY3VsYXRlZCBmcm9tIHRoZSAyMCUgdmFsaWRhdGlvbiBkYXRhLl9dKGZpZy9UQ0dBX3N1cnZfYnJpZXJfdF9sYXNzby5wbmcpe3dpZHRoPTYwJX0KCjxicj4KCjxmb250IHNpemU9IjQiPiAqKkludGVncmF0ZWQgQnJpZXIgc2NvcmUgKElCUykqKiA8L2ZvbnQ+IAoKVGhlIGZ1bmN0aW9uIGByaXNrUmVncmVzc2lvbjo6U2NvcmUoKWAgYWxzbyBzdW1tYXJpemVzIElCUyB3aGVuIHNwZWNpZnlpbmcgYXJndW1lbnQgYHN1bW1hcnkgPSAiaWJzImAuCldlIGNhbiBleHRyYWN0IHRoZSBJQlMgY29ycmVzcG9uZGluZyB0byB0aGUgbGFyZ2VzdCBldmFsdWF0aW9uIHRpbWUgcG9pbnQuCgpgYGB7cn0KQnJpZXJfdmFsaWRhdGVfaWJzID0gQnJpZXJfdmFsaWRhdGVbQnJpZXJfdmFsaWRhdGUkbW9kZWwgPT0gIkJyaWVyX3ZhbGlkYXRlIiwgXQpCcmllcl92YWxpZGF0ZV9pYnMkSUJTW3doaWNoLm1heChCcmllcl92YWxpZGF0ZV9pYnMkdGltZXMpXQpgYGAKYGBgClsxXSAwLjE3MTE2MTcKYGBgCgo8YnI+CgojIyMgVW5jZXJ0YWludHkgUXVhbnRpZmljYXRpb24gey0jdXExfQoKOjo6ey5pbmZvLWJveCAuaW1wb3J0YW50fQoqKkl0IGlzIHJlY29tbWVuZGVkIHRvIHVzZSByZXNhbXBsaW5nLWJhc2VkIG1ldGhvZHMqKiBmb3IgZXN0aW1hdGluZyB0aGUgdW5jZXJ0YWludHkgb2YgdGhlIG1vZGVsJ3MgcGVyZm9ybWFuY2UsIGlmIHRoZXJlIGFyZSBubyAqKmluZGVwZW5kZW50KiogdmFsaWRhdGlvbiBkYXRhIGZvciBtb2RlbCBldmFsdWF0aW9uLgpUaGlzIGNhbiBiZSBkb25lIGZvciBleGFtcGxlIGJ5IHJlcGVhdGVkbHkgc3BsaXR0aW5nIHRoZSBkYXRhc2V0IHRvIHRyYWluaW5nL3ZhbGlkYXRpb24gc2V0cyBhbmQgZXZhbHVhdGluZyBhIG1vZGVsJ3MgcGVyZm9ybWFuY2Ugb24gdGhlIGRpZmZlcmVudCB2YWxpZGF0aW9uIHNldHMgdXNpbmcgdmFyaW91cyBkaXNjcmltaW5hdGlvbiBvciBjYWxpYnJhdGlvbiBtZXRyaWNzLgo6OjoKCldlIGRlbW9uc3RyYXRlIGhvdyB0byByYW5kb21seSBzcGxpdCB0aGUgZGF0YSwgZS5nLiAkMTAwJCB0aW1lcywgdHJhaW4gYSBMYXNzbyBDb3ggbW9kZWwgYW5kIGVzdGltYXRlIHRoZSBpbnRlZ3JhdGVkIEFVQyBiYXNlZCBvbiB0aGUgdmFsaWRhdGlvbiBkYXRhIGluIGVhY2ggcmVwbGljYXRpb24uCkZvciBvdGhlciBDb3gtdHlwZSBtb2RlbHMsIHdlIGNhbiBqdXN0IHJlcGxhY2UgdGhlIG1vZGVsIGZpdHRpbmcgcGFydCBgY3YuZ2xtbmV0KClgIChhbmQgYHByZWRpY3QoKWApIGluIHRoZSBgZm9yYCBsb29wIGJlbG93LgpIb3dldmVyLCBtb3N0IG9mIHRoZSBCYXllc2lhbiBDb3ggbW9kZWxzIGludHJvZHVjZWQgcHJldmlvdXNseSBhcmUgY29tcHV0YXRpb25hbGx5IHRpbWUtY29uc3VtaW5nIHdoZW4gcmFuZG9tbHkgc3BsaXR0aW5nIHRoZSBkYXRhIG1hbnkgdGltZXMuCgpgYGB7cn0KIyBzcGxpdCB0aGUgZGF0YSAxMDAgdGltZXMKc2V0LnNlZWQoMTIzKQprID0gMTAwCmlBVUMgPSByZXAoTkEsIGspCmZvciAoaSBpbiAxOmspIHsKICBpZHggPSBzYW1wbGUoMTpuLCBuICogMC44LCByZXBsYWNlID0gRkFMU0UpCiAgeF90cmFpbiA9IHhbaWR4LCBdCiAgeV90cmFpbiA9IHlbaWR4LCBdCiAgeF92YWxpZGF0ZSA9IHhbLWlkeCwgXQogIHlfdmFsaWRhdGUgPSB5Wy1pZHgsIF0KICBjdmZpdCA9IGN2LmdsbW5ldCh4X3RyYWluLCB5X3RyYWluLCBmYW1pbHkgPSAiY294IiwgbmZvbGRzID0gNSwgcGVuYWx0eS5mYWN0b3IgPSBwZikKICBwcmVkX2xwID0gcHJlZGljdChjdmZpdCwgbmV3eCA9IHhfdmFsaWRhdGUsIHMgPSBjdmZpdCRsYW1iZGEubWluLCB0eXBlID0gImxpbmsiKQogIHV0aW1lcyA9IHNvcnQodW5pcXVlKHlfdmFsaWRhdGVbeV92YWxpZGF0ZVssIDJdID09IDEsIDFdKSkKICBBVUMgPSByZXAoTkEsIGxlbmd0aCh1dGltZXMpKQogIGZvciAoaiBpbiAxOmxlbmd0aCh1dGltZXMpKSB7CiAgICBvdXQgPSBDb3hXZWlnaHRzKG1hcmtlciA9IHByZWRfbHAsIFN0aW1lID0geV92YWxpZGF0ZVssIDFdLCBzdGF0dXMgPSB5X3ZhbGlkYXRlWywgMl0sIHByZWRpY3QudGltZSA9IHV0aW1lc1tqXSkKICAgIEFVQ1tqXSA9IG91dCRBVUMKICB9CiAgc3Vydl9wcm9iID0gdW5pcXVlKHN1cnZmaXQoU3Vydih5X3ZhbGlkYXRlWywgMV0sIHlfdmFsaWRhdGVbLCAyXSkgfiAxKSRzdXJ2KQogIGlBVUNbaV0gPSBJbnRlZ3JhdGVBVUMoQVVDLCB1dGltZXMsIHN1cnZfcHJvYiwgdG1heCA9IDEwKQp9CmRhdF90bXAgPSBkYXRhLmZyYW1lKHggPSAiTGFzc28gQ294IiwgeSA9IGlBVUMpCgpzZXQuc2VlZCgxMjMpCmdncGxvdChkYXRfdG1wLCBhZXMoeCwgeSkpICsgZ2VvbV9ib3hwbG90KCkgKyB5bGltKDAuNSwgMSkgKyB4bGFiKCIiKSArIHlsYWIoIkludGVncmF0ZWQgQVVDIikgKwogIGdlb21faml0dGVyKGNvbG9yPSJibHVlIiwgc2l6ZSA9IDAuNSwgYWxwaGEgPSAwLjUpCmBgYAohW19JbnRlZ3JhdGVkIEFVQyBiYXNlZCBvbiByYW5kb21seSBzcGxpdCB2YWxpZGF0aW9uIGRhdGEgMTAwIHRpbWVzLiBUaGUgYmx1ZSBkb3RzIGFyZSB0aGUgMTAwIHZhbHVlcyBvZiBpbnRlZ3JhdGVkIEFVQy5fXShmaWcvVENHQV9zdXJ2X2lhdWNfbGFzc28ucG5nKXt3aWR0aD0zMCV9Cgo8YnI+CgpTaW1pbGFyIHRvIG9idGFpbmluZyB1bmNlcnRhaW50eSBvZiB0aGUgaW50ZWdyYXRlZCBBVUMsIHdlIGNhbiBhbHNvIGVzdGltYXRlIHRoZSB1bmNlcnRhaW50eSBvZiB0aGUgQy1pbmRleCBmb3IgZXZhbHVhdGluZyB0aGUgZ2xvYmFsIHBlcmZvcm1hbmNlIG9mIG91ciBtb2RlbCdzIGRpc2NyaW1pbmF0aW9uLgoKYGBge3J9CiMgc3BsaXQgdGhlIGRhdGEgMTAwIHRpbWVzCnNldC5zZWVkKDEyMykKayA9IDEwMApDaW5kZXhfYWxsID0gZGF0YS5mcmFtZShIYXJyZWxsID0gcmVwKE5BLCBrKSwgVW5vID0gcmVwKE5BLCBrKSkKZm9yIChpIGluIDE6aykgewogIGlkeCA9IHNhbXBsZSgxOm4sIG4gKiAwLjgsIHJlcGxhY2UgPSBGQUxTRSkKICB4X3RyYWluID0geFtpZHgsIF0KICB5X3RyYWluID0geVtpZHgsIF0KICB4X3ZhbGlkYXRlID0geFstaWR4LCBdCiAgeV92YWxpZGF0ZSA9IHlbLWlkeCwgXQogIGN2Zml0ID0gY3YuZ2xtbmV0KHhfdHJhaW4sIHlfdHJhaW4sIGZhbWlseSA9ICJjb3giLCBuZm9sZHMgPSA1LCBwZW5hbHR5LmZhY3RvciA9IHBmKQogIHByZWQgPSBwcmVkaWN0KGN2Zml0LCBuZXd4ID0geF92YWxpZGF0ZSwgdHlwZSA9ICJyZXNwb25zZSIsIHMgPSBjdmZpdCRsYW1iZGEubWluKQogIENpbmRleF9hbGwkSGFycmVsbFtpXSA9IG1lYW4oYXBwbHkocHJlZCwgMiwgQ2luZGV4LCB5ID0geV92YWxpZGF0ZSkpCiAgQ2luZGV4X2FsbCRVbm9baV0gPSBVbm9DKHlfdHJhaW4sIHlfdmFsaWRhdGUsIHByZWQpCn0KZGF0X3RtcCA9IGRhdGEuZnJhbWUoeCA9IHJlcChjKCJIYXJyZWxsIiwgIlVubyIpLCBlYWNoID0gayksIHkgPSB1bmxpc3QoQ2luZGV4X2FsbCkpCgpzZXQuc2VlZCgxMjMpCmdncGxvdChkYXRfdG1wLCBhZXMoeCwgeSwgY29sID0geCkpICsgZ2VvbV9ib3hwbG90KCkgKyBnZW9tX2ppdHRlcihzaXplID0gMC41LCBhbHBoYSA9IDAuNSkgKwogICB5bGltKDAsIDEpICsgeGxhYigiIikgKyB5bGFiKCJDLWluZGV4IikgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKQpgYGAKIVtfQy1pbmRleCAoSGFycmVsbCdzIGFuZCBVbm8ncykgYmFzZWQgb24gcmFuZG9tbHkgc3BsaXQgdmFsaWRhdGlvbiBkYXRhIDEwMCB0aW1lcy5fXShmaWcvVENHQV9zdXJ2X2NpbmRleF9sYXNzby5wbmcpe3dpZHRoPTQwJX0KCjxicj4KClRoZSBgUmAgcGFja2FnZSBbKipjMDYwKipdKGh0dHBzOi8vQ1JBTi5SLXByb2plY3Qub3JnL3BhY2thZ2U9YzA2MCkgW0BTaWxsMjAxNF0gaW5jbHVkZXMgd3JhcHBlciBmdW5jdGlvbnMgZm9yIHRoZSBbKipnbG1uZXQqKl0oaHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT1nbG1uZXQpIGFsZ29yaXRobSBhbmQgaW1wbGVtZW50cyByZXNhbXBsaW5nLWJhc2VkIG1ldGhvZHMgKGUuZy4gY3Jvc3MtdmFsaWRhdGlvbiBhbmQgYm9vdHN0cmFwIC0gd2l0aCBhbmQgd2l0aG91dCByZXBsYWNlbWVudCkgYmFzZWQgb24gdGhlIFsqKnBlcGVycioqXShodHRwczovL0NSQU4uUi1wcm9qZWN0Lm9yZy9wYWNrYWdlPXBlcGVycikgcGFja2FnZSB0byBjYWxjdWxhdGUgdGhlIHRpbWUtZGVwZW5kZW50IEJyaWVyIHNjb3JlLgpbKipjMDYwKipdKGh0dHBzOi8vQ1JBTi5SLXByb2plY3Qub3JnL3BhY2thZ2U9YzA2MCkgZXh0ZW5kcyBbKipwZXBlcnIqKl0oaHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT1wZXBlcnIpIHBhY2thZ2UgdG8gYWxsb3cgbWFuZGF0b3J5IGZlYXR1cmVzIHdpdGhvdXQgcGVuYWxpemF0aW9uLgpAQmluZGVyMjAwOCByZWNvbW1lbmRzIHRvIGRyYXcgYm9vdHN0cmFwIHNhbXBsZXMgd2l0aG91dCByZXBsYWNlbWVudCAoaS5lLiBzdWJzYW1wbGluZyksIGJlY2F1c2UgYm9vdHN0cmFwIHNhbXBsZXMgd2l0aCByZXBsYWNlbWVudCBvZnRlbiByZXN1bHQgaW4gdG9vIGNvbXBsZXggbW9kZWxzIGluIGhpZ2gtZGltZW5zaW9uYWwgc2V0dGluZ3MuClRvIHVzZSByZXNhbXBsaW5nIGJ5IENWIHByb3Blcmx5IGZvciBzdXJ2aXZhbCBkYXRhLCBzZWUgQFNpbW9uMjAxMS4KTm90ZSB0aGF0IHJlc2FtcGxpbmctYmFzZWQgbWV0aG9kcyBoZXJlIGFyZSBzaW1pbGFyIHRvIHNwbGl0dGluZyAkODBcJS8yMFwlJCB0aGUgZGF0YSBtYW55IHRpbWVzIHdoaWNoIGFsbG93cyB1cyB0byBxdWFudGlmeSB0aGUgdW5jZXJ0YWludHkgb2YgdGhlIHRpbWUtZGVwZW5kZW50IEJyaWVyIHNjb3JlLgoKYGBge3J9CiMjIHRpbWUtZGVwZW5kZW50IEJyaWVyIHNjb3JlIGJ5IHN1YnNhbXBsaW5nIGZyb20gdGhlIHdob2xlIGRhdGEKc2V0LnNlZWQoMTIzKQpwZXBlcnJfb2JqZWN0ID0gcGVwZXJyOjpwZXBlcnIocmVzcG9uc2UgPSB5X3N1cnYsIHggPSB4LCBmaXQuZnVuID0gZml0LmdsbW5ldCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcmdzLmZpdCA9IGxpc3QoZmFtaWx5ID0gImNveCIsIHBlbmFsdHkuZmFjdG9yID0gcGYpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbXBsZXhpdHkgPSBjb21wbGV4aXR5LmdsbW5ldCwgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXJncy5jb21wbGV4aXR5ID0gbGlzdChmYW1pbHkgPSAiY294IiwgbmZvbGRzID0gNSwgcGVuYWx0eS5mYWN0b3IgPSBwZiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmRpY2VzID0gcmVzYW1wbGUuaW5kaWNlcyhuID0gbiwgbWV0aG9kPSJzdWI2MzIiLCBzYW1wbGUubiA9IDEwMCkpCmMwNjA6OlBsb3QucGVwZXJyLmN1cnZlcyhwZXBlcnJfb2JqZWN0KQpgYGAKIVtfUmVzYW1wbGluZy1iYXNlZCBwcmVkaWN0aW9uIGVycm9yIGN1cnZlcyAodGltZS1kZXBlbmRlbnQgQnJpZXIgc2NvcmUpIGEgdGhlIExhc3NvIENveCBtb2RlbCBhcHBsaWVkIHRvIHRoZSBCUkNBIGRhdGEgc2V0IGZyb20gVENHQS4gVGhlIGdyYXkgYXJlYSBpbmRpY2F0ZXMgdGhlIHBvaW50d2lzZSAyLjUlIGFuZCA5Ny41JSBxdWFudGlsZXMgb2YgdGhlIDEwMCBvdXQtb2YtYmFnIGJvb3RzdHJhcCBzYW1wbGVzLiBUaGUgb3RoZXIgbGluZXMgc2hvdyB0aGUgcHJlZGljdGlvbiBlcnJvciBjdXJ2ZXMgb2YgdGhlIG51bGwgbW9kZWwgKGVzdGltYXRlZCBieSB0aGUgS2FwbGFuLU1laWVyIGVzdGltYXRvciB3aXRob3V0IGNvdmFyaWF0ZSBpbmZvcm1hdGlvbiksIHRoZSBmdWxsIGFwcGFyZW50IGVycm9yIGVzdGltYXRlcyAoaS5lLiwgdGhlIGVycm9ycyBhcyBlc3RpbWF0ZWQgd2hlbiBhcHBseWluZyB0aGUgbW9kZWwgdG8gdGhlIGVudGlyZSB0cmFpbmluZyBkYXRhIHNldCksIGFuZCB0aGUgLjYzMisgYm9vdHN0cmFwIGVycm9yIGVzdGltYXRlcy5fXShmaWcvVENHQV9zdXJ2X2JyaWVyX2xhc3NvLnBuZyl7d2lkdGg9NjAlfQoKPGJyPgoKIyMjIEZlYXR1cmUgc3RhYmlsaXR5IGFuYWx5c2lzIHstfQoKVG8gaWRlbnRpZnkgc3RhYmxlIG9taWNzIGZlYXR1cmVzLCBhIHN0cmFpZ2h0Zm9yd2FyZCB3YXkgaXMgdG8gZmluZCB0aGUgb3ZlcmxhcHBlZCBvbWljcyBmZWF0dXJlcyB3aXRoIG5vbnplcm8gY29lZmZpY2llbnRzIGFtb25nIGRpZmZlcmVudCBkYXRhIHN1YnNldHMgKGUuZy4gQ1YgZm9sZHMgb3IgcmVzYW1wbGVzKS4KVGhlIGZvbGxvd2luZyBjb2RlIHN1bW1hcml6ZXMgdGhlIExhc3NvIENveCBzZWxlY3RlZCBvbWljcyBmZWF0dXJlcyB3aGljaCB3ZXJlIGlkZW50aWZpZWQgYXQgbGVhc3QgJDIkIG9yICQ1JCBvdXQgb2YgJDEwJCByZXNhbXBsZXMuClNpbWlsYXJseSwgdGhpcyBhcHByb2FjaCBjYW4gYmUgYXBwbGllZCB0byBvdGhlciBMYXNzby10eXBlIG9yIEJheWVzaWFuIENveCBtb2RlbHMgdGhhdCBwZXJmb3JtIGZlYXR1cmUgc2VsZWN0aW9uIGZvciBpZGVudGlmeWluZyBzdGFibGUgc2VsZWN0ZWQgZmVhdHVyZXMuCgpgYGB7cn0KIyBzcGVjaWZ5IHRoZSBudW1iZXIgb2YgcmVzYW1wbGVzIGsKayA9IDEwCmJldGFfYWxsID0gbWF0cml4KG5yb3cgPSBuY29sKHgpLCBuY29sID0gaykKc2V0LnNlZWQoMTIzKQpmb3IgKGogaW4gMTprKSB7CiAgcmVzYW1wbGVfaWQgPSBzYW1wbGUoMTpucm93KHkpLCBucm93KHkpLCByZXBsYWNlID0gVFJVRSkKICByZXNhbXBsZV94ID0geFtyZXNhbXBsZV9pZCwgXQogIHJlc2FtcGxlX3kgPSB5W3Jlc2FtcGxlX2lkLCBdCiAgY3ZmaXQgPSBjdi5nbG1uZXQocmVzYW1wbGVfeCwgcmVzYW1wbGVfeSwgZmFtaWx5ID0gImNveCIsIG5mb2xkcyA9IDUsIHBlbmFsdHkuZmFjdG9yID0gcGYpCiAgYmV0YV9hbGxbLCBqXSA9IGFzLnZlY3Rvcihjb2VmKGN2Zml0LCBzID0gY3ZmaXQkbGFtYmRhLm1pbikpCn0KCihzdGFibGVfZmVhdHVyZXMgPSBjb2xuYW1lcyh4KVtyb3dTdW1zKGJldGFfYWxsICE9IDApID49IDJdKQpgYGAKYGBgCiBbMV0gImFnZSIgICAgICAgImV0aG5pY2l0eSIgIlVCRTJUIiAgICAgIkNEQzYiICAgICAgIkNDTkIxIiAgICAgIlRZTVMiICAgICAgIkNFUDU1IiAgICAgIk1FTEsiICAgICAiTkRDODAiICAgICAiVUJFMkMiICAgICAiUFRURzEiICAgICAiRVhPMSIgICAgICAiT1JDNkwiICAgICAiQU5MTiIgICAgICAiQ0NORTEiICAgICAiS0lGMkMiICAgICJBQ1RSM0IiICAgICJNWUMiICAgICAgICJFR0ZSIiAgICAgICJLUlQ1IiAgICAgICJQSEdESCIgICAgICJDREgzIiAgICAgICJNSUEiICAgICAgICJGT1hDMSIgICAgIktSVDE0IiAgICAgIkVTUjEiICAgICAgIlNMQzM5QTYiICAgIkJBRzEiICAgICAgIk1BUFQiICAgICAgIkNYWEM1IiAgICAgIk1MUEgiICAgICAgIkJDTDIiICAgICAiTURNMiIgICAgICAiRk9YQTEiICAgICAiR1BSMTYwIiAgICAiRkdGUjQiICAgICAiVE1FTTQ1QiIgICAiRVJCQjIiIApgYGAKYGBge3J9CihzdGFibGVfZmVhdHVyZXMgPSBjb2xuYW1lcyh4KVtyb3dTdW1zKGJldGFfYWxsICE9IDApID49IDVdKQpgYGAKYGBgCiBbMV0gImFnZSIgICAgICAgImV0aG5pY2l0eSIgIlVCRTJUIiAgICAgIkNFUDU1IiAgICAgIlVCRTJDIiAgICAgIk9SQzZMIiAgICAgIkFOTE4iICAgICAgIkVTUjEiICAgICAgIkJBRzEiICAgICAiTUxQSCIgICAgICAiTURNMiIgICAgICAiR1BSMTYwIiAgICAiRkdGUjQiICAgICAiRVJCQjIiCmBgYAoKQWx0ZXJuYXRpdmVseSBmb3IgYSBCYXllc2lhbiBDb3ggbW9kZWwsIGl0cyBtZWRpYW4gcHJvYmFiaWxpdHkgbW9kZWwgKE1QTSkgY2FuIGJlIG9idGFpbmVkIGJhc2VkIG9uIHRoZSBjb2VmZmljaWVudCBlc3RpbWF0ZXMgb3ZlciBNQ01DIGl0ZXJhdGlvbnMuClRoZSBmb2xsb3dpbmcgY29kZSBzaG93cyBob3cgdG8gb2J0YWluIHRoZSBNUE0ncyBjb2VmZmljaWVudHMgb2YgdGhlIHBlbmFsaXplZCBzZW1pcGFyYW1ldHJpYyBCYXllc2lhbiBDb3ggbW9kZWwgd2l0aCBFbGFzdGljIE5ldCBwcmlvciBydW4gcHJldmlvdXNseS4KCmBgYHtyfQpnYW1tYXMgPSBjb2xNZWFucyhtYXRyaXgoYXMubnVtZXJpYyhFTl9iZXRhX3AgIT0gMCksIG5jb2wgPSBuY29sKEVOX2JldGFfcCkpKQpiZXRhX01QTSA9IChnYW1tYXMgPj0gMC41KSAqIGNvbE1lYW5zKEVOX2JldGFfcCkgLyBnYW1tYXMKYmV0YV9NUE1baXMubmEoYmV0YV9NUE0pXSA9IDAKYmV0YV9NUE0KYGBgCmBgYAogWzFdICAwLjAwMDAwMDAwMDAgLTAuMDE3MjAxNTI4MCAgMC4wMzA0MzE2NjE2IC0wLjAxMTQ2MjMzMDggIDAuMDgzNzgyNDEzMiAtMC4wNTQ3OTgzMzI3CiBbN10gIDAuMTQwNzQzOTEyNiAtMC4wNTYyNDM4MzUwICAwLjAyMzM0MTMyNTggIDAuMDgyMjU0ODk2NiAtMC4wMjE2OTU2MDA5IC0wLjAwNDY1MzE5OTEKWzEzXSAgMC4wMDAwMDAwMDAwIC0wLjAxMDI0MzI3MDcgLTAuMDQ2Mjc2NDI4MSAtMC4wMjYxMjMzNTAzICAwLjEyMDQ0NTI2OTIgIDAuMDQ5ODM4MDYzMgpbMTldICAwLjAwMDAwMDAwMDAgIDAuMDAwMDAwMDAwMCAgMC4wNDExMzU0MjcxICAwLjAwMDgyNTA5NTkgLTAuMDc0NzEyMTMyOCAgMC4zNzA5OTk2MDM1ClsyNV0gLTAuMDcxNDEyMzc4NSAgMC4wNTMxODg0NDkxIC0wLjAyNjMzNzk1NTIgLTAuMDI3ODE1NzUxMSAgMC4wODY4MjEzOTE3IC0wLjA0MTc1ODQzMzQKWzMxXSAtMC4wMTU0NjA5OTgwIC0xLjc1OTc3NjM5OTIgIDAuMDI0ODAxODE3MiAgMC4xNTgzNDQ4Nzg0ICAwLjAwMDAwMDAwMDAgLTAuMDI3MDI3NTA4MApbMzddICAwLjAzMTYyNzk4NTEgIDAuMTg5NjA2MTA3NSAgMC4wMzU5MDYzNjg3IC0wLjEzNzMyMjQ2MjEgLTAuMTY0ODgzMzE3NCAgMC4wMzQ2NDk0NjExCls0M10gIDAuMTE2ODMzNDMxNSAgMC4wMjI0NzkxODU3ICAwLjEzMzYzNDQ4ODEgLTAuMDA0NzQzNTEwOCAgMC4wMTg3NDg0MjI4ICAwLjExNzg5OTYzNjQKWzQ5XSAtMC4xNjk2NTMxMTI2ICAwLjA1NzM3MTM2OTQgLTAuMDMwODg5Nzc4NyAtMC4yMTMwODE5Mzg3CmBgYAoKPGJyPgoKIyMjIEdyYXBoaWNhbCByZXByZXNlbnRhdGlvbiB7LSNncmFwaENvbXB9CgpBZnRlciBpZGVudGlmeWluZyBzdGFibGUgb21pY3MgZmVhdHVyZXMgcHJlZGljdGl2ZSBvZiBzdXJ2aXZhbCBvdXRjb21lcywgd2UgY2FuIGRyYXcgYSAqKm5vbW9ncmFtKiogdG8gYWxsb3dzIHRoZSBncmFwaGljYWwgY2FsY3VsYXRpb24gb2Ygc3Vydml2YWwgcHJvYmFiaWxpdGllcyBhbmQgcmVwb3J0IGEgKipjYWxpYnJhdGlvbiBwbG90KiogZm9yIHByYWN0aXRpb25lcnMuCgo8Zm9udCBzaXplPSI0Ij4gKipOb21vZ3JhbSoqIDwvZm9udD4gCgpXZSBkZW1vbnN0cmF0ZSBhIG5vbW9ncmFtIHVzaW5nIHRoZSBzdGFibGUgc2VsZWN0ZWQgZmVhdHVyZXMgZnJvbSBUQ0dBIGJyZWFzdCBjYW5jZXIgZGF0YSBwcmVwcm9jZXNzZWQgcHJldmlvdXNseS4KVGhlIGBSYCBwYWNrYWdlICoqcmVncGxvdCoqIGRyYXdzIGFuIGVuaGFuY2VkIHJlZ3Jlc3Npb24gbm9tb2dyYW0gYmFzZWQgb24gdGhlICoqcm1zKiogcGFja2FnZS4KCmBgYHtyfQojIHJlbW92ZSBwYXRpZW50cyB3aXRob3V0IHJlcG9ydGluZyBldGhuaWNpdHkKeXkgPSB5W3hbLCAyXSAhPSAzLCBdCnh4ID0geFt4WywgMl0gIT0gMywgXQojIHNwZWNpZnkgdGhlIG51bWJlciBvZiByZXNhbXBsZXMgawprID0gMTAKYmV0YV9hbGwgPSBtYXRyaXgobnJvdyA9IG5jb2woeHgpLCBuY29sID0gaykKc2V0LnNlZWQoMTIzKQpmb3IgKGogaW4gMTprKSB7CiAgcmVzYW1wbGVfaWQgPSBzYW1wbGUoMTpucm93KHl5KSwgbnJvdyh5eSksIHJlcGxhY2UgPSBUUlVFKQogIHJlc2FtcGxlX3ggPSB4eFtyZXNhbXBsZV9pZCwgXQogIHJlc2FtcGxlX3kgPSB5eVtyZXNhbXBsZV9pZCwgXQogIGN2Zml0ID0gY3YuZ2xtbmV0KHJlc2FtcGxlX3gsIHJlc2FtcGxlX3ksIGZhbWlseSA9ICJjb3giLCBuZm9sZHMgPSA1LCBwZW5hbHR5LmZhY3RvciA9IHBmKQogIGJldGFfYWxsWywgal0gPSBhcy52ZWN0b3IoY29lZihjdmZpdCwgcyA9IGN2Zml0JGxhbWJkYS5taW4pKQp9CgojIGlkZW50aWZ5IGZlYXR1cmVzIGF0IGxlYXN0IDgwJSBmcmVxdWVudGx5IHNlbGVjdGVkCnhfc3RhYmxlID0gZGF0YS5mcmFtZSh4eFssIHJvd1N1bXMoYmV0YV9hbGwgIT0gMCkgPj0gayAqIDAuOF0pCnhfc3RhYmxlJGV0aG5pY2l0eSA9IGZhY3Rvcih4X3N0YWJsZSRldGhuaWNpdHkpIApsZXZlbHMoeF9zdGFibGUkZXRobmljaXR5KSA9IGMoIkhpc3BhbmljL2xhdGlubyIsICJOb3QgaGlzcGFuaWMvbGF0aW5vIikKCmRhdGFfdG1wID0gZGF0YS5mcmFtZSh0aW1lcyA9IHl5WywgInRpbWUiXSwgc3RhdHVzID0geXlbLCAic3RhdHVzIl0sIHhfc3RhYmxlKQpmID0gY3BoKGZvcm11bGEgPSBTdXJ2KHRpbWVzLCBzdGF0dXMpIH4gYWdlICsgZXRobmljaXR5ICsgVUJFMlQgKyBPUkM2TCArIEVTUjEsICAKICAgICAgICAgICAgIGRhdGEgPSBkYXRhX3RtcCwgeCA9IFRSVUUsIHkgPSBUUlVFLCBzdXJ2ID0gVFJVRSkKZGRpc3QgPSBkYXRhZGlzdChkYXRhX3RtcCkKb2xkb3B0aW9uID0gb3B0aW9ucyhkYXRhZGlzdCA9ICdkZGlzdCcpCnN1cnYgPSBTdXJ2aXZhbChmKQpub20gPSBub21vZ3JhbShmLCBmdW4gPSBsaXN0KGZ1bmN0aW9uKHgpIHN1cnYoMSwgeCksIGZ1bmN0aW9uKHgpIHN1cnYoMywgeCksIGZ1bmN0aW9uKHgpIHN1cnYoNSwgeCkpLAogICAgICAgICAgICAgICAgICAgIGZ1bmxhYmVsID0gYygiMS1ZZWFyIFN1cnZpdmFsIFByb2JhYmlsaXR5IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIzLVllYXIgU3Vydml2YWwgUHJvYmFiaWxpdHkiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjUtWWVhciBTdXJ2aXZhbCBQcm9iYWJpbGl0eSIpLAogICAgICAgICAgICAgICAgICAgIGxwID0gRkFMU0UpCnJlZ3Bsb3Q6OnJlZ3Bsb3QoZiwgb2JzZXJ2YXRpb24gPSBkYXRhX3RtcFsxLF0sIGZhaWx0aW1lID0gYygxLCAzLCA1KSwgdGl0bGUgPSAiIiwKICAgICAgICAgICAgICAgICBwcmZhaWwgPSBGQUxTRSwgcG9pbnRzID0gVFJVRSwgc2hvd1AgPSBGQUxTRSwgc3VidGlja3MgPSBUUlVFKSAKYGBgCiFbX05vbW9ncmFtIGRldmVsb3BlZCB0byBlc3RpbWF0ZSB0aGUgb3ZlcmFsbCBzdXJ2aXZhbCBwcm9iYWJpbGl0eSBmb3IgVENHQSdzIEJSQUMgcGF0aWVudHMgYmFzZWQgb24gZGVtb2dyYXBoaWMgYW5kIExhc3NvIENveCBzZWxlY3RlZCBtUk5BIGZlYXR1cmVzLiBUaGUgcmVkIGNvbG91cmVkIHN5bWJvbHMgcmVwcmVzZW50IG9uZSBwYXRpZW504oCZcyBpbmZvcm1hdGlvbiBhbmQgcHJlZGljdGVkIHByb2JhYmlsaXRpZXMgb2YgMS15ZWFyLCAzLXllYXIgYW5kIDUteWVhciBzdXJ2aXZhbC5fXShmaWcvVENHQV9zdXJ2X25vbW9ncmFtLnBuZyl7d2lkdGg9ODAlfQoKPGJyPiAKCjxmb250IHNpemU9IjQiPiBbKipDYWxpYnJhdGlvbiBwbG90KipdeyNzbG9wZUNhbGl9IDwvZm9udD4gCgpBIGNhbGlicmF0aW9uIHBsb3QgaXMgYSBzdHJhaWdodGZvcndhcmQgdmlzdWFsaXphdGlvbiB0byBzaG93IHRoZSBwcmVkaWN0aW9uIGFiaWxpdHkgb2YgdGhlIG5vbW9ncmFtLCBpLmUuLCB0aGUgYWdyZWVtZW50IGJldHdlZW4gcHJlZGljdGVkIHN1cnZpdmFsIHByb2JhYmlsaXRpZXMgZnJvbSB0aGUgZmluYWwgbW9kZWwgYW5kIHRoZSBLTSBlc3RpbWF0ZWQgc3Vydml2YWwgcHJvYmFiaWxpdGllcyBpbiBkaWZmZXJlbnQgcGVyY2VudGlsZXMgb2YgdGhlIHByZWRpY3RlZCB2YWx1ZXMgYXQgYSB0aW1lIHBvaW50IG9mIGludGVyZXN0LiAKV2UgZGVtb25zdHJhdGUgYmVsb3cgY2FsaWJyYXRpb24gcGxvdHMgYmFzZWQgb24gdHJhaW5pbmcgYW5kIHZhbGlkYXRpb24gZGF0YSBzZXRzLCByZXNwZWN0aXZlbHkuCgpgYGB7cn0KIyBDYWxpYnJhdGlvbiBhdCA1LXllYXIgdGltZS1wb2ludAoKIyBwcmVwYXJlIHN1aXRhYmxlIGRhdGEgZm9ybWF0IGZvciBjYWxpYnJhdGlvbiBwbG90CnNldC5zZWVkKDEyMykKdHJhaW5faWQgPC0gc2FtcGxlKDE6bnJvdyh5eSksIG5yb3coeXkpICogMC44LCByZXBsYWNlID0gRkFMU0UpCmRhdGFfdHJhaW4gPSBkYXRhX3RtcFt0cmFpbl9pZCwgXQpkYXRhX3ZhbGlkYXRlID0gZGF0YV90bXBbLXRyYWluX2lkLCBdCgpkZGlzdCA9IGRhdGFkaXN0KGRhdGFfdHJhaW4pCm9wdGlvbnMoZGF0YWRpc3Q9J2RkaXN0JykKZl90cmFpbiA9IGNwaChmb3JtdWxhID0gU3Vydih0aW1lcywgc3RhdHVzKSB+IGFnZSArIGV0aG5pY2l0eSArIFVCRTJUICsgT1JDNkwgKyBFU1IxLAogICAgICAgICAgICAgIGRhdGEgPSBkYXRhX3RyYWluLCB4ID0gVFJVRSwgeSA9IFRSVUUsIHN1cnYgPSBUUlVFLCB0aW1lLmluYyA9IDUpCmZfdmFsaWRhdGUgPSB1cGRhdGUoZl90cmFpbiwgZGF0YSA9IGRhdGFfdmFsaWRhdGUpCmNhbF90cmFpbiA9IGNhbGlicmF0ZShmX3RyYWluLCB1ID0gNSwgY21ldGhvZCA9ICJLTSIsIG0gPSBucm93KGRhdGFfdHJhaW4pIC8gNCwgQiA9IDIwMCkKY2FsX3ZhbGlkYXRlID0gY2FsaWJyYXRlKGZfdmFsaWRhdGUsIHUgPSA1LCBjbWV0aG9kID0gIktNIiwgbSA9IG5yb3coZGF0YV92YWxpZGF0ZSkgLyA0LCBCID0gMjAwKQoKcGRmKCJUQ0dBX3N1cnZfY2FsaWJyYXRpb24ucGRmIiwgd2lkdGg9NywgaGVpZ2h0PTQpCmxheW91dChtYXRyaXgoMToyLCBucm93ID0gMSkpCnBsb3QoY2FsX3RyYWluLCBsd2QgPSAyLCBsdHkgPSAxLCBlcnJiYXIuY29sID0gInNlYWdyZWVuMyIsCiAgICAgeGxhYiA9ICdQcmVkaWN0ZWQgc3Vydml2YWwgcHJvYmFiaWxpdHknLCB5bGFiID0gJ0FjdHVhbCBzdXJ2aXZhbCBwcm9iYWJpbGl0eScsCiAgICAgeGxpbSA9IGMoMCwxKSwgeWxpbSA9IGMoMCwxKSwgY29sID0gInNlYWdyZWVuMyIsIHN1YnRpdGxlcyA9IEZBTFNFKQp0aXRsZShtYWluID0gIkNhbGlicmF0aW9uIG9uIHRyYWluaW5nIGRhdGEiKQoKcGxvdChjYWxfdmFsaWRhdGUsIGx3ZCA9IDIsIGx0eSA9IDEsIGVycmJhci5jb2wgPSAic2VhZ3JlZW4zIiwKICAgICB4bGFiID0gJ1ByZWRpY3RlZCBzdXJ2aXZhbCBwcm9iYWJpbGl0eScsIHlsYWIgPSAnQWN0dWFsIHN1cnZpdmFsIHByb2JhYmlsaXR5JywKICAgICB4bGltID0gYygwLDEpLCB5bGltID0gYygwLDEpLCBjb2wgPSAic2VhZ3JlZW4zIiwgc3VidGl0bGVzID0gRkFMU0UpCnRpdGxlKG1haW4gPSAiQ2FsaWJyYXRpb24gb24gdmFsaWRhdGlvbiBkYXRhIikKZGV2Lm9mZigpCmBgYAohW19Ob21vZ3JhbSBtb2RlbCBjYWxpYnJhdGlvbiBjdXJ2ZXMgZm9yIFRDR0EncyBCUkFDIHBhdGllbnRzIGF0IDUteWVhciBldmFsdWF0aW9uIHRpbWUtcG9pbnQuX10oZmlnL1RDR0Ffc3Vydl9jYWxpYnJhdGlvbi5wbmcpe3dpZHRoPTcwJX0KCjxicj4KCiMjIE1vZGVsIGV2YWx1YXRpb24gKG1scjMpIHstI21scjN9Cgo6Ojp7LmdyZWVuLWJveH0KVXNpbmcgdGhlIFsqKm1scjMqKl0oaHR0cHM6Ly9tbHIzLm1sci1vcmcuY29tKSBtYWNoaW5lIGxlYXJuaW5nIGZyYW1ld29yayBhbmQgdGhlIFsqKm1scjNwcm9iYSoqXShodHRwczovL21scjNwcm9iYS5tbHItb3JnLmNvbSkgYFJgIGxpYnJhcnksIHdlIHdpbGwgZGVtb25zdHJhdGUgaG93IHRvOgoKLSBDcmVhdGUgYSBzdXJ2aXZhbCB0YXNrIGZyb20gYSBkYXRhc2V0IGFuZCBzcGxpdCBpdCB0byB0cmFpbmluZyBhbmQgdGVzdCAodmFsaWRhdGlvbikgc2V0cwotIERlZmluZSBhIExhc3NvIENveCBtb2RlbCB0aGF0IGNhbiBvdXRwdXQgYm90aCBsaW5lYXIgcHJlZGljdG9ycyBhbmQgc3Vydml2YWwgZGlzdHJpYnV0aW9uIHByZWRpY3Rpb25zIGFuZCB0cmFpbi90dW5lIGl0IG9uIHRoZSB0cmFpbmluZyBzZXQKLSBNYWtlIHByZWRpY3Rpb25zIHVzaW5nIHRoZSB0cmFpbmVkIExhc3NvIENveCBtb2RlbCBvbiB0aGUgc2VwYXJhdGUgdGVzdCBzZXQKLSBNZWFzdXJlIHRoZSBwZXJmb3JtYW5jZSBvZiBvdXIgbW9kZWwgKGRpc2NyaW1pbmF0aW9uIGFuZCBjYWxpYnJhdGlvbikgdXNpbmcgc2V2ZXJhbCBldmFsdWF0aW9uIG1ldHJpY3MKLSBVc2luZyByZXNhbXBsaW5nIHRlY2huaXF1ZXMsIHdlIHdpbGwgYXNzZXNzIG91ciBtb2RlbCdzIGNhcGFjaXR5IGZvciBnZW5lcmFsaXphdGlvbiAocHJlZGljdGlvbiBvbiB1bnNlZW4gZGF0YSkgYW5kIHRoZSBzdGFiaWxpdHkgb2YgdGhlIG1vZGVsJ3Mgc2VsZWN0ZWQgZmVhdHVyZXMKOjo6CgpGb3IgdGhlIHJlc3Qgb2YgdGhlIGFuYWx5c2lzLCB3ZSB3aWxsIGJvcnJvdyB0aGUgdGVybWlub2xvZ3kgZnJvbSB0aGUgWyoqbWxyMyoqXShodHRwczovL21scjMubWxyLW9yZy5jb20pIGVjb3N5c3RlbSBvZiBtYWNoaW5lIGxlYXJuaW5nIHBhY2thZ2VzIChlLmcuICp0YXNrKiBpcyBhIGRhdGFzZXQsICpsZWFybmVyKiBpcyBhIG1vZGVsLCBldGMuKS4KU2VlIFttbHIzIGJvb2tdKGh0dHBzOi8vbWxyM2Jvb2subWxyLW9yZy5jb20vKSBmb3IgbW9yZSBkZXRhaWxzLgoKRmlyc3QsIHdlIGxvYWQgdGhlIG5lY2Vzc2FyeSBbKiptbHIzKipdKGh0dHBzOi8vbWxyMy5tbHItb3JnLmNvbSkgbGlicmFyaWVzIFtATGFuZzIwMTk7IEBTb25hYmVuZDIwMjFdIGFuZCBzb21lIG90aGVyIHVzZWZ1bCBvbmVzOgpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KbGlicmFyeSgibWxyM3ZlcnNlIikgIyBtbHIzLCBtbHIzcGlwZXBsaW5lcywgbWxyM2xlYXJuZXJzLCBtbHIzdHVuaW5nLCBwYXJhZG94LCBldGMuCmxpYnJhcnkoIm1scjNwcm9iYSIpICMgcHJvYmFiaWxpc3RpYyBsZWFybmluZyBhbmQgc3Vydml2YWwgYW5hbHlzaXMKbGlicmFyeSgibWxyM2V4dHJhbGVhcm5lcnMiKSAjIGZvciBscm4oJ3N1cnYuZ2xtbmV0JykKYGBgCgo8YnI+CgojIyMgV29ya2Zsb3cgey19CgpXZSBjb25zdHJ1Y3QgYW4gWyoqbWxyMyoqXShodHRwczovL21scjMubWxyLW9yZy5jb20pICpzdXJ2aXZhbCB0YXNrKiAoVENHQSBCUkNBIGRhdGFzZXQgZXNzZW50aWFsbHksIHdpdGggbm9ybWFsaXplZCBQQU01MCBnZW5lIGV4cHJlc3Npb24gZmVhdHVyZXMgYW5kIHR3byBjbGluaWNhbC9kZW1vZ3JhcGhpYyB2YXJpYWJsZXMpIGFuZCBzcGxpdCBpdCBpbnRvIHRyYWluaW5nIGFuZCB0ZXN0IHNldHMgKCQ4MFwlLzIwXCUkKToKYGBge3J9CiMgRnJvbSAnUGVuYWxpemVkIENveCBtb2RlbHMnIHNlY3Rpb246CiMgeCA9PiBnZW5lIGV4cHJlc3Npb24gbWF0cml4ICg1MCBQQU01MCBnZW5lcykgKyAyIGNsaW5pY2FsIHZhcmlhYmxlcwojIHkgPT4gKHRpbWUsIHN0YXR1cykgdGFyZ2V0IG1hdHJpeAoKZGF0YSA9IGNiaW5kLmRhdGEuZnJhbWUoeCwgeSkKIyBkYXRhID0gcmVhZFJEUyhmaWxlID0gJ2RhdGEucmRzJykKdGFzayA9IG1scjNwcm9iYTo6YXNfdGFza19zdXJ2KHggPSBkYXRhLCAKICB0aW1lID0gJ3RpbWUnLCBldmVudCA9ICdzdGF0dXMnLCBpZCA9ICdCUkNBLVRDR0EnKQp0YXNrICMgc2VlIHVzZWZ1bCBpbmZvIGFib3V0IHRoZSBkYXRhc2V0ICgjZmVhdHVyZXMsICNzYW1wbGVzLCB0YXJnZXQgdmFyaWFibGVzKQoKIyBzcGxpdCB0byB0cmFpbiBhbmQgdGVzdCBzZXRzCnNldC5zZWVkKDQyKQpzcGxpdCA9IG1scjM6OnBhcnRpdGlvbih0YXNrLCByYXRpbyA9IDAuOCkKIyBzcGxpdCR0cmFpbiAjIHRyYWluIGluZGljZXMKIyBzcGxpdCR0ZXN0ICMgdGVzdCBpbmRpY2VzCmBgYApgYGAKPFRhc2tTdXJ2OkJSQ0EtVENHQT4gKDEwNDcgeCA1NCkKKiBUYXJnZXQ6IHRpbWUsIHN0YXR1cwoqIFByb3BlcnRpZXM6IC0KKiBGZWF0dXJlcyAoNTIpOgogIC0gZGJsICg1Mik6IEFDVFIzQiwgQU5MTiwgQkFHMSwgQkNMMiwgQklSQzUsIEJMVlJBLCBDQ05CMSwgQ0NORTEsCiAgICBDREMyMCwgQ0RDNiwgQ0RIMywgQ0VOUEYsIENFUDU1LCBDWFhDNSwgRUdGUiwgRVJCQjIsIEVTUjEsIEVYTzEsCiAgICBGR0ZSNCwgRk9YQTEsIEZPWEMxLCBHUFIxNjAsIEdSQjcsIEtJRjJDLCBLUlQxNCwgS1JUMTcsIEtSVDUsIE1BUFQsCiAgICBNRE0yLCBNRUxLLCBNSUEsIE1LSTY3LCBNTFBILCBNTVAxMSwgTVlCTDIsIE1ZQywgTkFUMSwgTkRDODAsIE5VRjIsCiAgICBPUkM2TCwgUEdSLCBQSEdESCwgUFRURzEsIFJSTTIsIFNGUlAxLCBTTEMzOUE2LCBUTUVNNDVCLCBUWU1TLAogICAgVUJFMkMsIFVCRTJULCBhZ2UsIGV0aG5pY2l0eQpgYGAKCldlIGNyZWF0ZSBhIExhc3NvIENveCBbKiptbHIzKipdKGh0dHBzOi8vbWxyMy5tbHItb3JnLmNvbSkgKmdyYXBoIGxlYXJuZXIqIChhIHdyYXBwZXIgYXJvdW5kIHRoZSBgZ2xtbmV0Ojpjdi5nbG1uZXQoKWAgZnVuY3Rpb24gd2l0aCB0aGUgY2FwYWNpdHkgdG8gcHJvdmlkZSBzdXJ2aXZhbCBwcmVkaWN0aW9ucyksIHdoZXJlIHdlIHNwZWNpZnkgdGhlIHR3byBjbGluaWNhbCB2YXJpYWJsZXMgdG8gYmUgKm1hbmRhdG9yeSogKGkuZS4gbm8gcGVuYWxpemF0aW9uKSBhbmQgdGhlICRzJCB2YWx1ZSAoJFxsYW1iZGEkIHBhcmFtZXRlciB1c2VkIGZvciBwcmVkaWN0aW9uKSBlcXVhbCB0byBgbGFtYmRhLm1pbmA6CmBgYHtyfQojdGFpbCh0YXNrJGZlYXR1cmVfbmFtZXMpICMgYWdlLCBldGhuaWNpdHkgYXJlIHRoZSAyIGxhc3QgZmVhdHVyZXMKcGYgPSBjKHJlcCgxLCBsZW5ndGgodGFzayRmZWF0dXJlX25hbWVzKSAtIDIpLCByZXAoMCwgMikpCgojIGRlZmluZSBtb2RlbApjb3hsYXNzbyA9IGxybignc3Vydi5jdl9nbG1uZXQnLCBhbHBoYSA9IDEsIG5mb2xkcyA9IDUsIHMgPSAnbGFtYmRhLm1pbicsCiAgcGVuYWx0eS5mYWN0b3IgPSBwZikKIyBjb3hsYXNzbyAjIHNlZSBkZXRhaWxzIG9mIGNveGxhc3NvIGxlYXJuZXIKIyBjb3hsYXNzbyRoZWxwKCkgIyBmb3IgbW9yZSBkZXRhaWxzCgojID9tbHJfZ3JhcGhzX2Rpc3RyY29tcG9zaXRvcgpjb3hsYXNzb19ncmxybiA9IG1scjNwaXBlbGluZXM6OnBwbCgnZGlzdHJjb21wb3NpdG9yJywKICBsZWFybmVyID0gY294bGFzc28sCiAgZXN0aW1hdG9yID0gJ2thcGxhbicsICMgS00gZXN0aW1hdG9yIGZvciB0aGUgYmFzZWxpbmUKICBmb3JtID0gJ3BoJywgIyBQcm9wb3J0aW9uYWwgSGF6YXJkcyBmb3JtIHNpbmNlIHdlIHVzZSBhIExhc3NvIENveCBtb2RlbAogIGdyYXBoX2xlYXJuZXIgPSBUUlVFCikKY294bGFzc29fZ3Jscm4kaWQgPSAnTGFzc28gQ294JwojIGNveGxhc3NvX2dybHJuJGdyYXBoX21vZGVsJHBsb3QoaHRtbCA9IFRSVUUpICMgcGxvdCB0aGUgZ3JhcGggbGVhcm5lcgpgYGAKCjo6OnsuaW5mby1ib3ggLm5vdGV9CkEgQ294IHByb3BvcnRpb25hbCBoYXphcmRzIG1vZGVsIChhbmQgTGFzc28gQ294IGFzIGEgY29uc2VxdWVuY2UpIGlzIGEgc2VtaS1wYXJhbWV0cmljIG1vZGVsLCB3aGljaCBtZWFucyB0aGF0IGl0IGRvZXMgbm90IHByb2R1Y2Ugc3Vydml2YWwgZGlzdHJpYnV0aW9uIHByZWRpY3Rpb25zIGJ5IGRlZmF1bHQuCkhvd2V2ZXIsIHVzaW5nIHRoZSBmdW5jdGlvbiBgc3Vydml2YWw6OnN1cnZmaXQuY294cGgoKWAgeW91IGNhbiB0cmFuc2Zvcm0gdGhlIGBjdi5nbG1uZXRgJ3Mgb3V0cHV0IGxpbmVhciBwcmVkaWN0b3JzIChgbHBgKSB0byBzdXJ2aXZhbCBkaXN0cmlidXRpb24gcHJlZGljdGlvbnMuClRoaXMgdHJhbnNmb3JtYXRpb24gaW50ZXJuYWxseSB1c2VzIHRoZSBCcmVzbG93IGVzdGltYXRvciBmb3IgdGhlIGN1bXVsYXRpdmUgYmFzZWxpbmUgaGF6YXJkIChzZWUgYHN0eXBlYCBwYXJhbWV0ZXIpLgoKVXNpbmcgWyoqbWxyM3Byb2JhKipdKGh0dHBzOi8vbWxyM3Byb2JhLm1sci1vcmcuY29tKSBbQFNvbmFiZW5kMjAyMV0sIHdlIGNhbiBjb25zdHJ1Y3QgYSBwaXBlbGluZSBbQG1scjNwaXBlbGluZXMyMDIxXSB0aGF0IGNvbWJpbmVzIHRoZSBkaXN0cmlidXRpb24gcHJlZGljdGlvbnMgb2YgYSBiYXNlbGluZSBtb2RlbCAoZS5nLiBLYXBsYW4gTWVpZXIpIHdpdGggdGhlIGxpbmVhciBwcmVkaWN0b3JzIG9mIGEgQ294LXR5cGUgbW9kZWwgKGUuZy4gTGFzc28gQ294KS4KU2VlIGRldGFpbHMgc3VjaCBhcyB0aGUgdHJhbnNmb3JtYXRpb24gYXNzdW1wdGlvbnMsIHRoZSBjaG9pY2Ugb2YgdGhlIHN1cnZpdmFsIGZ1bmN0aW9uIGZvcm0gYW5kIHRoZSBhdmFpbGFibGUgYmFzZWxpbmUgc3Vydml2YWwgZGlzdHJpYnV0aW9uIGVzdGltYXRvcnMgb24gdGhlIHJlc3BlY3RpdmUgW2RvY3VtZW50YXRpb25dKGh0dHBzOi8vbWxyM3Byb2JhLm1sci1vcmcuY29tL3JlZmVyZW5jZS9tbHJfcGlwZW9wc19jb21wb3NlX2Rpc3RyLmh0bWwpLgo6OjoKCjxicj4KClRyYWluIHRoZSBMYXNzbyBDb3ggbW9kZWw6CmBgYHtyfQpzZXQuc2VlZCgzKQpjb3hsYXNzb19ncmxybiR0cmFpbih0YXNrLCByb3dfaWRzID0gc3BsaXQkdHJhaW4pCiMgdmlldyBgY3YuZ2xtbmV0YCBmaXQKY294bGFzc29fZ3Jscm4kbW9kZWwkc3Vydi5jdl9nbG1uZXQkbW9kZWwKYGBgCmBgYApDYWxsOiAgKGlmIChjdikgZ2xtbmV0Ojpjdi5nbG1uZXQgZWxzZSBnbG1uZXQ6OmdsbW5ldCkoeCA9IGRhdGEsIHkgPSB0YXJnZXQsICAgICAgbmZvbGRzID0gNUwsIGFscGhhID0gMSwgcGVuYWx0eS5mYWN0b3IgPSBjKDEsIC4uLiwgMCwgMCksIGZhbWlseSA9ICJjb3giKSAKCk1lYXN1cmU6IFBhcnRpYWwgTGlrZWxpaG9vZCBEZXZpYW5jZSAKCiAgICAgTGFtYmRhIEluZGV4IE1lYXN1cmUgICAgIFNFIE5vbnplcm8KbWluIDAuMDA5OTQgICAgMTUgICAxMi4zMCAwLjI3MTkgICAgICAxNQoxc2UgMC4wMzY1NiAgICAgMSAgIDEyLjM1IDAuMjU2MiAgICAgICAyCmBgYAoKR2V0IHRoZSBzdXJ2aXZhbCBkaXN0cmlidXRpb24gcHJlZGljdGlvbnMgKCRkaXN0ciQpIGFsb25nIHdpdGggdGhlIGxpbmVhciBwcmVkaWN0b3JzICgkbHAkKToKYGBge3J9CnByZWQgPSBjb3hsYXNzb19ncmxybiRwcmVkaWN0KHRhc2ssIHJvd19pZHMgPSBzcGxpdCR0ZXN0KQpoZWFkKGFzLmRhdGEudGFibGUocHJlZCkpCmBgYApgYGAKICAgcm93X2lkcyAgICAgIHRpbWUgc3RhdHVzICAgICBjcmFuayAgICAgICAgbHAgICAgIGRpc3RyCjE6ICAgICAgIDUgMC45NTI3NzIxICBGQUxTRSAtMy4zMjkxMzMgLTMuMzI5MTMzIDxsaXN0WzFdPgoyOiAgICAgICA2IDQuMDQzODA1NiAgRkFMU0UgLTMuODAwNzY2IC0zLjgwMDc2NiA8bGlzdFsxXT4KMzogICAgICAxNSAxLjczODUzNTIgIEZBTFNFIC0yLjc4NjY2MiAtMi43ODY2NjIgPGxpc3RbMV0+CjQ6ICAgICAgNDUgNC41ODA0MjQ0ICBGQUxTRSAtMi43NjExMTAgLTIuNzYxMTEwIDxsaXN0WzFdPgo1OiAgICAgIDUwIDUuMTI3OTk0NSAgRkFMU0UgLTMuNzM2MjExIC0zLjczNjIxMSA8bGlzdFsxXT4KNjogICAgICA1NCA2LjY4NTgzMTYgIEZBTFNFIC0zLjQ5OTY5MSAtMy40OTk2OTEgPGxpc3RbMV0+CmBgYAoKU28gZm9yIGV2ZXJ5IHBhdGllbnQgaW4gdGhlIHRlc3Qgc2V0LCB0aGUgTGFzc28gQ294IG1vZGVsIHByZWRpY3Rpb24gaXMgYSBsaW5lYXIgcHJlZGljdG9yIG9mIHRoZSBmb3JtICRscCA9IFxoYXR7XGJldGF9IFhfe25ld30kLgokY3JhbmskIHN0YW5kcyBmb3IgY29udGludW91cyByYW5raW5nIHNjb3JlIGFuZCBpdCdzIHRoZSBzYW1lIGFzICRscCQgZm9yIHRoZSBMYXNzbyBDb3ggbW9kZWwuClRoZSAkZGlzdHIkIHByZWRpY3Rpb25zIGFyZSB0aGUgcGVyLXBhdGllbnQgc3Vydml2YWwgZGlzdHJpYnV0aW9uIHByZWRpY3Rpb25zLCBpbXBsZW1lbnRlZCBieSB0aGUgYFJgIHBhY2thZ2UgW2Rpc3RyNl0oaHR0cHM6Ly9naXRodWIuY29tL2FsYW4tdHVyaW5nLWluc3RpdHV0ZS9kaXN0cjYpIHdoaWNoIHRoZSBbKiptbHIzcHJvYmEqKl0oaHR0cHM6Ly9tbHIzcHJvYmEubWxyLW9yZy5jb20pIGltcG9ydHMuClNlZSByZXNwZWN0aXZlIFtkb2N1bWVudGF0aW9uXShodHRwczovL21scjNwcm9iYS5tbHItb3JnLmNvbS9yZWZlcmVuY2UvUHJlZGljdGlvblN1cnYuaHRtbCkgb24gdGhlIGRpZmZlcmVudCBwcmVkaWN0aW9uIHR5cGVzIHN1cHBvcnRlZC4KCkFuIGV4YW1wbGUgb2YgdXNpbmcgdGhlIGBkaXN0cmAgcHJlZGljdGlvbnMgd291bGQgYmUgdG8gcmVxdWVzdCBmb3IgdGhlIHN1cnZpdmFsIHByb2JhYmlsaXR5IGF0IGUuZy4gJDEsNSwxMCwyMCQgeWVhcnMgZm9yIHRoZSBmaXJzdCB0d28gcGF0aWVudHMgaW4gdGhlIHRlc3Qgc2V0OgpgYGB7cn0KdGltZXMgPSBjKDEsNSwxMCwyMCkKcHJlZCRkaXN0ciRzdXJ2aXZhbCh0aW1lcylbLGMoMSwyKV0KCiMgc2FtZSBsb2dpYyBmb3IgdGhlIGN1bXVsYXRpdmUgaGF6YXJkCiMgcHJlZCRkaXN0ciRjdW1IYXphcmQodGltZXMpWyxjKDEsMildCmBgYApgYGAKICAgICAgICBbLDFdICAgICAgWywyXQoxICAwLjk5OTMzNTcgMC45OTk1ODU0CjUgIDAuOTkyNTk4OSAwLjk5NTM3NTQKMTAgMC45ODA0MDM1IDAuOTg3NzI2NwoyMCAwLjk2MzM1NDggMC45NzY5NzM4CmBgYAoKPGJyPgoKIyMjIERpc2NyaW1pbmF0aW9uIG1ldHJpY3Mgey19CgpXZSB3YW50IHRvIHRlc3Qgb3VyIExhc3NvIENveCBtb2RlbCBhbmQgc2VlIGhvdyB3ZWxsIGl0IHdhcyBhYmxlIHRvICoqZGlzY3JpbWluYXRlIHRoZSBwYXRpZW50cyBpbiB0aGUgdGVzdCBzZXQqKi4KRm9yIHRoaXMgd2UgY2FuIHVzZSB0aGUgJGxwJCBwcmVkaWN0aW9ucyBvZiBMYXNzbyBDb3ggbW9kZWwgYW5kIG1ldHJpY3Mgc3VjaCBhcyB0aGUgKHRpbWUtZGVwZW5kZW50KSBDLWluZGV4IGFuZCAodGltZS1kZXBlbmRlbnQpIEFVQy4KPGJyPgoKPGZvbnQgc2l6ZT0iNCI+ICoqSGFycmVsbCdzIEMtaW5kZXgqKiBbQEhhcnJlbGwxOTgyXTogPC9mb250PiAKYGBge3J9CmhhcnJlbGxfYyA9IG1zcignc3Vydi5jaW5kZXgnKQpoYXJyZWxsX2MkaWQgPSAnc3Vydi5jaW5kZXguaGFycmVsbCcKCiMgaGFycmVsbF9jICMgZ2V0IHNvbWUgZGV0YWlscyBhYm91dCB0aGUgbWVhc3VyZQojIGhhcnJlbGxfYyRtaW5pbWl6ZSAjIEZBTFNFID0+IGhpZ2hlciBDLWluZGV4IGlzIGJldHRlcgojIGhhcnJlbGxfYyRyYW5nZSAjIFswLCAxXSA9PiBbbWluLCBtYXhdCiMgaGFycmVsbF9jJHByZWRpY3RfdHlwZSAjIHVzZXMgdGhlICRjcmFuayQgcHJlZGljdGlvbnMgKGVxdWFsIHRvICRscCQgZm9yIExhc3NvIENveAoKcHJlZCRzY29yZShoYXJyZWxsX2MpCmBgYApgYGAKc3Vydi5jaW5kZXguaGFycmVsbCAKICAgICAgICAgIDAuNjE4ODI0NCAKYGBgCgo8YnI+Cgo8Zm9udCBzaXplPSI0Ij4gKipVbm8ncyBDLWluZGV4KiogW0BVbm8yMDExXTogKGFjcm9zcyBhbGwgdGltZSBwb2ludHMgb2YgdGhlIHRlc3Qgc2V0KTogPC9mb250PiAKYGBge3J9CnVub19jID0gbXNyKCdzdXJ2LmNpbmRleCcsIHdlaWdodF9tZXRoID0gJ0cyJykKdW5vX2MkaWQgPSAnc3Vydi5jaW5kZXgudW5vJwoKIyBVbm8ncyBDIG5lZWRzIHRoZSB0cmFpbiBkYXRhCnByZWQkc2NvcmUodW5vX2MsIHRhc2sgPSB0YXNrLCB0cmFpbl9zZXQgPSBzcGxpdCR0cmFpbikKYGBgCmBgYApzdXJ2LmNpbmRleC51bm8gCiAgICAgIDAuNjAwNDQ1OSAKYGBgCgo8YnI+Cgo8Zm9udCBzaXplPSI0Ij4gKipVbm8ncyBJbnRlZ3JhdGVkIEFVQyoqIFtAVW5vMjAwN10gKGFjcm9zcyBhbGwgdGltZSBwb2ludHMgb2YgdGhlIHRlc3Qgc2V0KTogPC9mb250PiAKYGBge3J9CnVub19pYXVjID0gbXNyKCdzdXJ2LnVub19hdWMnKQp1bm9faWF1YyRpZCA9ICdzdXJ2LnVub19pYXVjJwojIHVub19pYXVjJHBhcmFtX3NldCR2YWx1ZXMkaW50ZWdyYXRlZCAjIGludGVncmF0ZWQgPSBUUlVFIGJ5IGRlZmF1bHQKIyBzb3J0KHVuaXF1ZShwcmVkJHRydXRoWywxXSkpICMgdGltZSBwb2ludHMgdXNlZAoKIyB1bm9faWF1YyRwcm9wZXJ0aWVzICMgbmVlZHMgdGhlIHRyYWluIGRhdGEKcHJlZCRzY29yZSh1bm9faWF1YywgdGFzayA9IHRhc2ssIHRyYWluX3NldCA9IHNwbGl0JHRyYWluKQpgYGAKYGBgCnN1cnYudW5vX2lhdWMgCiAgICAwLjY2NDU3MTkgCmBgYAoKPGJyPgoKPGZvbnQgc2l6ZT0iNCI+ICoqVW5vJ3MgQVVDIGF0IGEgc3BlY2lmaWMgdGltZSBwb2ludCoqLCBlLmcuICQxMCQgeWVhcnM6IDwvZm9udD4gCmBgYHtyfQp1bm9fYXVjID0gbXNyKCdzdXJ2LnVub19hdWMnLCBpbnRlZ3JhdGVkID0gRkFMU0UsIHRpbWVzID0gMTApCnVub19hdWMkaWQgPSAnc3Vydi51bm9fYXVjLjEwJwoKIyBuZWVkcyB0aGUgdHJhaW4gZGF0YQpwcmVkJHNjb3JlKHVub19hdWMsIHRhc2sgPSB0YXNrLCB0cmFpbl9zZXQgPSBzcGxpdCR0cmFpbikKYGBgCmBgYApzdXJ2LnVub19hdWMuMTAgCiAgICAgIDAuNjc0OTA4MSAKYGBgCgo8YnI+CgojIyMgQ2FsaWJyYXRpb24gbWV0cmljcyB7LX0KCldlIHdhbnQgdG8gdGVzdCBob3cgd2VsbCBvdXIgTGFzc28gQ294IG1vZGVsIHdhcyAqKmNhbGlicmF0ZWQqKi4gQEFuZHJlczIwMTggYW5kIEBIYWlkZXIyMDIwIHN1Z2dlc3RlZCB0aGUgZGlzdHJpYnV0aW9uYWwgKEQpLWNhbGlicmF0aW9uIGFjY291bnRpbmcgc3Vydml2YWwgcHJvYmFiaWxpdGllcyBhY3Jvc3MgYWxsIHRpbWVzLiBUaGlzIGNhbiBiZSB1c2VmdWwgd2hlbiBhc3Nlc3NpbmcgdGhlIGVudGlyZSBwb3N0LXRyZWF0bWVudCBzdXJ2aXZhbCBwcm9nbm9zaXMsIGZvciBleGFtcGxlLCBhc3Nlc3NpbmcgdGhlIHBvc3QgbGl2ZXIgdHJhbnNwbGFudGF0aW9uIHN1cnZpdmFsIHV0aWxpdHkgaW4gQEFuZHJlczIwMTguCgo8Zm9udCBzaXplPSI0Ij4gKipELWNhbGlicmF0aW9uKiogPC9mb250PiAKYGBge3J9CmRjYWwgPSBtc3IoJ3N1cnYuZGNhbGliJykKcHJlZCRzY29yZShkY2FsKQpgYGAKYGBgCnN1cnYuZGNhbGliIAogICAzMi4yNTk2MSAKYGBgCgo8YnI+CgojIyMgT3ZlcmFsbCBtZXRyaWNzIHstfQoKVXN1YWxseSB3ZSBkZXJpdmUgYW4gZXN0aW1hdGlvbiBvZiB0aGUgZXJyb3IgYmV0d2VlbiB0aGUgc3Vydml2YWwgZGlzdHJpYnV0aW9ucyAoJGRpc3RyJCBwcmVkaWN0aW9ucykgb2YgdGhlIHBhdGllbnRzIGluIHRoZSB0ZXN0IHNldCBhbmQgdGhlaXIgYWN0dWFsIHN1cnZpdmFsIG91dGNvbWVzIChjb3JyZXNwb25kaW5nIHRvIHRoZSBzdXJ2aXZhbCB0YXNrJ3MgYHRpbWVgIGFuZCBgc3RhdHVzYCB2YXJpYWJsZXMpLgpUaGUgbW9zdCBmcmVxdWVudGx5IHVzZWQgbWV0cmljIGlzIHRoZSBCcmllciBTY29yZSBbQEdyYWYxOTk5XToKPGJyPgoKPGZvbnQgc2l6ZT0iNCI+ICoqSW50ZWdyYXRlZCBCcmllciBTY29yZSAoSUJTKSoqIChhY3Jvc3MgYWxsIHRpbWUgcG9pbnRzIG9mIHRoZSB0ZXN0IHNldCk6IDwvZm9udD4gCmBgYHtyfQppYnJpZXIgPSBtc3IoJ3N1cnYuYnJpZXInLCBwcm9wZXIgPSBUUlVFKQojIGlicmllciRoZWxwKCkgIyBzZWUgZG9jdW1lbnRhdGlvbgojIGlicmllciRwcmVkaWN0X3R5cGUgIyB1c2VzIHRoZSBgZGlzdHJgIHByZWRpY3Rpb25zCgojIGJldHRlciB0byB1c2UgdGhlIHRyYWluIGRhdGEgZm9yIHRoZSBLYXBsYW4tTWVpZXIgZXN0aW1hdGlvbiBvZiB0aGUgY2Vuc29yaW5nIGRpc3RyaWJ1dGlvbiwgYnV0IGNhbiB1c2UgdGhlIHRlc3Qgc2V0IGFzIHdlbGwKcHJlZCRzY29yZShpYnJpZXIsIHRhc2sgPSB0YXNrLCB0cmFpbl9zZXQgPSBzcGxpdCR0cmFpbikKYGBgCmBgYApzdXJ2LmdyYWYgCjAuNDA0NDI4NyAKYGBgCgpXZSBjYW4gYWxzbyBnZXQgdGhlICpzdGFuZGFyZCBlcnJvciogb2YgSUJTICh0aGUgYWJvdmUgcmVzdWx0IGlzIHRoZSBtZWFuIGFjcm9zcyBhbGwgdGhlIHRlc3Qgc2V0J3MgcGF0aWVudHMpIGFzIGZvbGxvd3M6CmBgYHtyfQppYnJpZXJfc2UgPSBtc3IoJ3N1cnYuYnJpZXInLCBwcm9wZXIgPSBUUlVFLCBzZSA9IFRSVUUpCnByZWQkc2NvcmUoaWJyaWVyX3NlLCB0YXNrID0gdGFzaywgdHJhaW5fc2V0ID0gc3BsaXQkdHJhaW4pCmBgYApgYGAKIHN1cnYuZ3JhZiAKMC4wMjI1MzkyNwpgYGAKCjxicj4KCjxmb250IHNpemU9IjQiPiAqKkJyaWVyIFNjb3JlIGF0IGEgc3BlY2lmaWMgdGltZSBwb2ludCoqLCBlLmcuICQxMCQgeWVhcnM6IDwvZm9udD4gCmBgYHtyfQpicmllcjEwID0gbXNyKCdzdXJ2LmJyaWVyJywgcHJvcGVyID0gVFJVRSwgaW50ZWdyYXRlZCA9IEZBTFNFLCB0aW1lcyA9IDEwKQpicmllcjEwJGlkID0gJ3N1cnYuZ3JhZi4xMCcKCiMgYmV0dGVyIHRvIHVzZSB0aGUgdHJhaW4gZGF0YSBmb3IgdGhlIEthcGxhbi1NZWllciBlc3RpbWF0aW9uIG9mIHRoZSBjZW5zb3JpbmcgZGlzdHJpYnV0aW9uLCBidXQgY2FuIHVzZSB0aGUgdGVzdCBzZXQgYXMgd2VsbApwcmVkJHNjb3JlKGJyaWVyMTAsIHRhc2sgPSB0YXNrLCB0cmFpbl9zZXQgPSBzcGxpdCR0cmFpbikKYGBgCmBgYApzdXJ2LmdyYWYuMTAgCiAgIDAuNDI1MjQ0MiAKYGBgCgo8YnI+Cgo8Zm9udCBzaXplPSI0Ij4gKipSaWdodC1jZW5zb3JlZCBMb2dhcml0aG1pYyBMb3NzIHNjb3JlKiogKFJDTEwpIFtAQXZhdGkyMDIwO0BTb25hYmVuZDIwMjJdOiA8L2ZvbnQ+IApgYGB7cn0KcmNsbCA9IG1zcignc3Vydi5yY2xsJykKcHJlZCRzY29yZShyY2xsKQpgYGAKYGBgCnN1cnYucmNsbCAKIDQuNjg0NjQ0IApgYGAKCjxicj4KCjo6OnsuaW5mby1ib3ggLm5vdGV9ClZpZXcgYWxsIGV2YWx1YXRpb24gbWV0cmljcyBmb3Igc3Vydml2YWwgZGF0YSBpbXBsZW1lbnRlZCBpbiBbKiptbHIzcHJvYmEqKl0oaHR0cHM6Ly9tbHIzcHJvYmEubWxyLW9yZy5jb20pIFtoZXJlXShodHRwczovL21scjNwcm9iYS5tbHItb3JnLmNvbS9yZWZlcmVuY2UvI3N1cnZpdmFsLW1lYXN1cmVzKQo6OjoKCjxicj4KCiMjIyBVbmNlcnRhaW50eSBRdWFudGlmaWNhdGlvbiB7LX0KClNpbWlsYXIgcHJvY2VkdXJlIGFzIGZvbGxvd2VkIGluIGEgW3ByZXZpb3VzIHNlY3Rpb25dKCN1cTEpLgoKV2Ugd2lsbCBwZXJmb3JtIGEgKipzdHJhdGlmaWVkIHNwbGl0Kiogb2YgdGhlIEJSQ0EtVENHQSBzdXJ2aXZhbCB0YXNrIHRvIHRyYWluaW5nIGFuZCB0ZXN0IHNldHMgKHdpdGggYSAkODBcJS8yMFwlJCByYXRpbyBhcyBiZWZvcmUpLgpTdHJhdGlmaWNhdGlvbiBvbiB0aGUgY2Vuc29yaW5nIGluZGljYXRvciBgc3RhdHVzYCBpcyBpbXBvcnRhbnQgYmVjYXVzZSB3ZSB3YW50IG91ciB0cmFpbmluZyBhbmQgdGVzdCBzZXRzIHRvIGhhdmUgdGhlIHNhbWUgY2Vuc29yaW5nIGRpc3RyaWJ1dGlvbiBhcyB0aGUgaW5pdGlhbCBkYXRhc2V0LgpUaHVzIHdlIGNhbiBhdm9pZCBtZWFzdXJpbmcgcGVyZm9ybWFuY2Ugb24gdGVzdCBzZXRzIHdpdGggc2V2ZXJlbHkgZGlmZmVyZW50IGNlbnNvcmluZyBkaXN0cmlidXRpb25zIHRoYXQgbWlnaHQgaW5mbHVlbmNlIHRoZSBwZXJmb3JtYW5jZSBzY29yZXMuCgpTdHJhdGlmeSBzdXJ2aXZhbCB0YXNrIGJ5IGBzdGF0dXNgOgpgYGB7cn0KY294bGFzc29fZ3Jscm4kcmVzZXQoKSAjIHVuLXRyYWluIG1vZGVsCgp0YXNrJGNvbF9yb2xlcyRzdHJhdHVtID0gJ3N0YXR1cycKIyB0YXNrCmBgYAoKTmV4dCwgd2UgZGVmaW5lIHRoZSB0eXBlIG9mIHJlc2FtcGxpbmcgKGA/bWxyX3Jlc2FtcGxpbmdzX3N1YnNhbXBsaW5nYCksIHRyYWluIHRoZSBMYXNzbyBDb3ggbW9kZWwgb24gYWxsIHRyYWluaW5nIHNldHMgKCQxMDAkKSBhbmQgc3RvcmUgdGhlIGZpdHRlZCBtb2RlbHMgZm9yIGZlYXR1cmUgc2VsZWN0aW9uIGFuZCBldmFsdWF0aW9uOgpgYGB7ciwgcmVzdWx0cz0naGlkZSd9CiMgMTAwIHRpbWVzIHRyYWluL3Rlc3Qgc3BsaXQgKDgwJSBmb3IgdHJhaW5pbmcsIDIwJSBmb3IgdmFsaWRhdGlvbikKc3Vic2FtcGxpbmcgPSByc21wKCdzdWJzYW1wbGluZycsIHJlcGVhdHMgPSAxMDAsIHJhdGlvID0gMC44KQoKc2V0LnNlZWQoNDIpCnJyID0gbWxyMzo6cmVzYW1wbGUodGFzayA9IHRhc2ssIGxlYXJuZXIgPSBjb3hsYXNzb19ncmxybiwgCiAgcmVzYW1wbGluZyA9IHN1YnNhbXBsaW5nLCBzdG9yZV9tb2RlbHMgPSBUUlVFLCBzdG9yZV9iYWNrZW5kcyA9IFRSVUUpCmBgYAoKV2UgY2FuIHVzZSBhbGwgdGhlIGFmb3JlbWVudGlvbmVkIGV2YWx1YXRpb24gbWV0cmljcyB0byBtZWFzdXJlIHRoZSBwZXJmb3JtYW5jZSBvZiB0aGUgTGFzc28gQ294IG1vZGVscyBvbiB0aGUgJDEwMCQgZGlmZmVyZW50IHRlc3Qgc2V0cy4KTm90ZSB0aGF0IGlmIGEgbWV0cmljIG5lZWRzIHRoZSB0cmFpbmluZyBkYXRhc2V0IGl0IGlzIGF1dG9tYXRpY2FsbHkgcHJvdmlkZWQgYnkgdGhlIGBSZXNhbXBsZVJlc3VsdGAgb2JqZWN0IChgcnJgKToKYGBge3J9Cm1lYXN1cmVzID0gbGlzdChoYXJyZWxsX2MsIHVub19jLCB1bm9faWF1YywgdW5vX2F1YywgaWJyaWVyLCBicmllcjEwLCByY2xsLCBkY2FsKQoKcmVzID0gcnIkc2NvcmUobWVhc3VyZXMgPSBtZWFzdXJlcykKaGVhZChyZXMpCmBgYApgYGAKICAgICAgICAgICAgIHRhc2sgICB0YXNrX2lkICAgICAgICAgICAgbGVhcm5lciBsZWFybmVyX2lkCjE6IDxUYXNrU3Vydls1NV0+IEJSQ0EtVENHQSA8R3JhcGhMZWFybmVyWzM4XT4gIExhc3NvIENveAoyOiA8VGFza1N1cnZbNTVdPiBCUkNBLVRDR0EgPEdyYXBoTGVhcm5lclszOF0+ICBMYXNzbyBDb3gKMzogPFRhc2tTdXJ2WzU1XT4gQlJDQS1UQ0dBIDxHcmFwaExlYXJuZXJbMzhdPiAgTGFzc28gQ294CjQ6IDxUYXNrU3Vydls1NV0+IEJSQ0EtVENHQSA8R3JhcGhMZWFybmVyWzM4XT4gIExhc3NvIENveAo1OiA8VGFza1N1cnZbNTVdPiBCUkNBLVRDR0EgPEdyYXBoTGVhcm5lclszOF0+ICBMYXNzbyBDb3gKNjogPFRhc2tTdXJ2WzU1XT4gQlJDQS1UQ0dBIDxHcmFwaExlYXJuZXJbMzhdPiAgTGFzc28gQ294CiAgICAgICAgICAgICAgICAgICAgcmVzYW1wbGluZyByZXNhbXBsaW5nX2lkIGl0ZXJhdGlvbiAgICAgICAgICAgcHJlZGljdGlvbgoxOiA8UmVzYW1wbGluZ1N1YnNhbXBsaW5nWzIwXT4gICBzdWJzYW1wbGluZyAgICAgICAgIDEgPFByZWRpY3Rpb25TdXJ2WzIwXT4KMjogPFJlc2FtcGxpbmdTdWJzYW1wbGluZ1syMF0+ICAgc3Vic2FtcGxpbmcgICAgICAgICAyIDxQcmVkaWN0aW9uU3VydlsyMF0+CjM6IDxSZXNhbXBsaW5nU3Vic2FtcGxpbmdbMjBdPiAgIHN1YnNhbXBsaW5nICAgICAgICAgMyA8UHJlZGljdGlvblN1cnZbMjBdPgo0OiA8UmVzYW1wbGluZ1N1YnNhbXBsaW5nWzIwXT4gICBzdWJzYW1wbGluZyAgICAgICAgIDQgPFByZWRpY3Rpb25TdXJ2WzIwXT4KNTogPFJlc2FtcGxpbmdTdWJzYW1wbGluZ1syMF0+ICAgc3Vic2FtcGxpbmcgICAgICAgICA1IDxQcmVkaWN0aW9uU3VydlsyMF0+CjY6IDxSZXNhbXBsaW5nU3Vic2FtcGxpbmdbMjBdPiAgIHN1YnNhbXBsaW5nICAgICAgICAgNiA8UHJlZGljdGlvblN1cnZbMjBdPgogICBzdXJ2LmNpbmRleC5oYXJyZWxsIHN1cnYuY2luZGV4LnVubyBzdXJ2LnVub19pYXVjIHN1cnYudW5vX2F1Yy4xMCBzdXJ2LmdyYWYKMTogICAgICAgICAgIDAuNTY3OTE2NyAgICAgICAwLjYwOTAzMDQgICAgIDAuNjYyODM1MCAgICAgICAwLjQ3MTkzMzUgMC4zMjU1MTgxCjI6ICAgICAgICAgICAwLjU0MjIxMzEgICAgICAgMC40ODg0NjAzICAgICAwLjQwMjM2ODQgICAgICAgMC41NjUyNTg4IDAuMzE0ODk5MgozOiAgICAgICAgICAgMC43NjA0MDQ5ICAgICAgIDAuNTc0MDU1NiAgICAgMC41OTQxOTQ4ICAgICAgIDAuNTIzNTQzOSAwLjI4NTUxNTEKNDogICAgICAgICAgIDAuNjYxMDE2OSAgICAgICAwLjUyNzc3MzYgICAgIDAuNTM2MDY5MCAgICAgICAwLjUxMTAwMzIgMC4yOTcyNzE5CjU6ICAgICAgICAgICAwLjU4MDAwNzMgICAgICAgMC41NjU1MDc2ICAgICAwLjYxNjA3NDMgICAgICAgMC41Mzg4MzkzIDAuMzUxODUwNQo2OiAgICAgICAgICAgMC41NDI3ODM3ICAgICAgIDAuNjk3NTc0MCAgICAgMC42NDk0Nzc5ICAgICAgIDAuNjQwMDMyOCAwLjIwMzU2MDkKICAgc3Vydi5ncmFmLjEwIHN1cnYucmNsbCAgc3Vydi5kY2FsaWIKMTogICAgMC42MTYxODI1ICA2LjAzODkwOSAxLjAyNjkwMWUrMDcKMjogICAgMC40NDczMTA0ICA1LjQwMDI1MyAxLjA1MDQyN2UrMDQKMzogICAgMC4yOTY5NzY2ICA0Ljk1MzUyOCAyLjU0NDExNmUrMDEKNDogICAgMC4yMzY1MzIyICA0Ljk1MzgzMCAyLjI3NTA0MGUrMDEKNTogICAgMC40Mzg3MTY1ICA0Ljk0MzQ0NiAzLjM3MDUxMGUrMDEKNjogICAgMC40MjI4MTY5ICA1LjQzNDk3MCA0LjIyMzc0MmUrMDIKYGBgCldlIGV4dHJhY3QgYW5kIHZpc3VhbGl6ZSB0aGUgZGlzY3JpbWluYXRpb24gYW5kIGNhbGlicmF0aW9uIChyZXNhbXBsZWQpIHBlcmZvcm1hbmNlIG9mIG91ciBMYXNzbyBDb3ggbW9kZWwgdXNpbmcgc2V2ZXJhbCBldmFsdWF0aW9uIG1ldHJpY3M6CmBgYHtyfQpzZXQuc2VlZCg0MikKCiMgQy1pbmRleGVzLCBBVUNzIChpbnRlZ3JhdGVkIGFuZCBhdCB0ID0gMTAgeWVhcnMpCnJlc1ssIC4oc3Vydi5jaW5kZXguaGFycmVsbCwgc3Vydi5jaW5kZXgudW5vLCBzdXJ2LnVub19pYXVjLCBzdXJ2LnVub19hdWMuMTApXSAlPiUgCiAgdGlkeXI6OnBpdm90X2xvbmdlcihjb2xzID0gdGlkeXNlbGVjdDo6ZXZlcnl0aGluZygpLCAKICAgIG5hbWVzX3RvID0gJ01lYXN1cmUnLCB2YWx1ZXNfdG8gPSAnVmFsdWUnKSAlPiUKICBtdXRhdGUoTWVhc3VyZSA9IGNhc2Vfd2hlbigKICAgIE1lYXN1cmUgPT0gJ3N1cnYuY2luZGV4LmhhcnJlbGwnIH4gJ0hhcnJlbGxcJ3MgQy1pbmRleCcsCiAgICBNZWFzdXJlID09ICdzdXJ2LmNpbmRleC51bm8nIH4gJ1Vub1wncyBDLWluZGV4JywKICAgIE1lYXN1cmUgPT0gJ3N1cnYudW5vX2lhdWMnIH4gJ1Vub1wncyBJbnRlZ3JhdGVkIEFVQycsCiAgICBNZWFzdXJlID09ICdzdXJ2LnVub19hdWMuMTAnIH4gJ1Vub1wncyBBVUMgKHQgPSAxMCB5ZWFycyknLAogICkpICU+JQogICBtdXRhdGUoTWVhc3VyZSA9IGZhY3RvcihNZWFzdXJlLCBsZXZlbHMgPSBjKAogICAgICdIYXJyZWxsXCdzIEMtaW5kZXgnLAogICAgICdVbm9cJ3MgQy1pbmRleCcsCiAgICAgJ1Vub1wncyBJbnRlZ3JhdGVkIEFVQycsCiAgICAgJ1Vub1wncyBBVUMgKHQgPSAxMCB5ZWFycyknKSkpICU+JQogIGdncGxvdChhZXMoeCA9IE1lYXN1cmUsIHkgPSBWYWx1ZSwgZmlsbCA9IE1lYXN1cmUpKSArCiAgICBnZW9tX2JveHBsb3QoKSArIAogICAgeWxpbShjKDAuMiwgMC44KSkgKyAKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuNSwgY29sb3IgPSAncmVkJywgbGluZXR5cGUgPSAnZGFzaGVkJykgKwogICAgdGhlbWVfYncoYmFzZV9zaXplID0gMTQpICsgCiAgICBsYWJzKHRpdGxlID0gJ0Rpc2NyaW1pbmF0aW9uIE1lYXN1cmVzJykgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkpCmBgYAohW19EaXNjcmltaW5hdGlvbiBwZXJmb3JtYW5jZSBvZiBMYXNzbyBDb3ggb24gdGhlIFRDR0EtQlJDQSBkYXRhc2V0IChleHByZXNzaW9uIGRhdGEgb2YgdGhlIFBBTTUwIGdlbmVzIGFuZCB0aGUgdmFyaWFibGVzIGFnZSBhbmQgZXRobmljaXR5KS4gUGVyZm9ybWFuY2UgbWV0cmljcyB1c2VkIGFyZSBIYXJyZWxsJ3MgQy1pbmRleCwgVW5vJ3MgQy1pbmRleCwgVW5vJ3MgSW50ZWdyYXRlZCBBVUMgYW5kIFVubydzIEFVQyBhdCAxMCB5ZWFycy4gVGhlIGRhdGFzZXQgd2FzIHNwbGl0IHRvIHRyYWluaW5nL3ZhbGlkYXRpb24gc2V0cyAxMDAgdGltZXMgdG8gYWxsb3cgZm9yIHRoZSBxdWFudGlmaWNhdGlvbiBvZiB1bmNlcnRhaW50eSBpbiB0aGUgZGlmZmVyZW50IHBlcmZvcm1hbmNlIGVzdGltYXRlcy5fXShmaWcvbWxyM19kaXNjcmltaW5hdGlvbl9tc3JzLnBuZyl7d2lkdGg9ODAlfQoKYGBge3IsIGZpZy5zaG93PSdob2xkJywgb3V0LndpZHRoPSc1MCUnfQojIGRpZmZlcmVudCBzY2FsZXMgZm9yIGVhY2ggbWVhc3VyZSwgc28gd2Ugc2VwYXJhdGUgdGhlIHBsb3RzCnNldC5zZWVkKDQyKQoKIyBJbnRlZ3JhdGVkIEJyaWVyIFNjb3JlIGFuZCBCcmllciBTY29yZSBhdCB0ID0gMTAgeWVhcnMKcmVzWywgLihzdXJ2LmdyYWYsIHN1cnYuZ3JhZi4xMCldICU+JSAKICB0aWR5cjo6cGl2b3RfbG9uZ2VyKGNvbHMgPSB0aWR5c2VsZWN0OjpldmVyeXRoaW5nKCksIAogICAgbmFtZXNfdG8gPSAnTWVhc3VyZScsIHZhbHVlc190byA9ICdWYWx1ZScpICU+JQogIG11dGF0ZShNZWFzdXJlID0gY2FzZV93aGVuKAogICAgTWVhc3VyZSA9PSAnc3Vydi5ncmFmJyB+ICdJQlMnLAogICAgTWVhc3VyZSA9PSAnc3Vydi5ncmFmLjEwJyB+ICdCUyh0PTEwKScKICApKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBNZWFzdXJlLCB5ID0gVmFsdWUsIGZpbGwgPSBNZWFzdXJlKSkgKwogICAgZ2VvbV9ib3hwbG90KHNob3cubGVnZW5kID0gRkFMU0UpICsgCiAgICBnZW9tX2ppdHRlcihjb2xvciA9ICdibHVlJywgc2l6ZSA9IDAuNSwgYWxwaGEgPSAwLjUsIHNob3cubGVnZW5kID0gRkFMU0UpICsKICAgIGxhYnModGl0bGUgPSAnSW50ZWdyYXRlZCBCcmllciBTY29yZSB2cyBCcmllciBTY29yZSAodCA9IDEwIHllYXJzKScpICsKICAgIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE0KSArIAogICAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKQoKIyBSQ0xMCnJlc1ssIC4oc3Vydi5yY2xsKV0gJT4lIAogIHRpZHlyOjpwaXZvdF9sb25nZXIoY29scyA9IHRpZHlzZWxlY3Q6OmV2ZXJ5dGhpbmcoKSwgCiAgICBuYW1lc190byA9ICdNZWFzdXJlJywgdmFsdWVzX3RvID0gJ1ZhbHVlJykgJT4lCiAgbXV0YXRlKE1lYXN1cmUgPSBjYXNlX3doZW4oCiAgICBNZWFzdXJlID09ICdzdXJ2LnJjbGwnIH4gJ1JDTEwnCiAgKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gTWVhc3VyZSwgeSA9IFZhbHVlKSkgKwogICAgZ2VvbV9ib3hwbG90KHNob3cubGVnZW5kID0gRkFMU0UpICsgCiAgICBnZW9tX2ppdHRlcihjb2xvciA9ICdibHVlJywgc2l6ZSA9IDAuNSwgYWxwaGEgPSAwLjUsIHNob3cubGVnZW5kID0gRkFMU0UpICsKICAgIGxhYnModGl0bGUgPSAnUmlnaHQtY2Vuc29yZWQgTG9nIExvc3MnKSArCiAgICB0aGVtZV9idyhiYXNlX3NpemUgPSAxNCkgKwogICAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKQpgYGAKPHAgYWxpZ249ImxlZnQiPgogIDxpbWcgYWx0PSIxIiBzcmM9Ii4vZmlnL21scjNfY2FsaWJyYXRpb25fQlMucG5nIiB3aWR0aD0iNDklIj4KICA8aW1nIGFsdD0iMiIgc3JjPSIuL2ZpZy9tbHIzX2NhbGlicmF0aW9uX1JDTEwucG5nIiB3aWR0aD0iNDklIj4KICA8aT5DYWxpYnJhdGlvbiBwZXJmb3JtYW5jZSBvZiBMYXNzbyBDb3ggb24gdGhlIFRDR0EtQlJDQSBkYXRhc2V0IChleHByZXNzaW9uIGRhdGEgb2YgdGhlIFBBTTUwIGdlbmVzIGFuZCB0aGUgdmFyaWFibGVzIGFnZSBhbmQgZXRobmljaXR5KS4gUGVyZm9ybWFuY2UgbWV0cmljcyB1c2VkIGFyZSB0aGUgSW50ZWdyYXRlZCBCcmllciBTY29yZSAoSUJTKSwgdGhlIEJyaWVyIFNjb3JlIGF0IDEwIHllYXJzIGFuZCB0aGUgUmlnaHQtQ2Vuc29yZWQgTG9nYXJpdGhtaWMgTG9zcyAoUkNMTCkuIFRoZSBkYXRhc2V0IHdhcyBzcGxpdCB0byB0cmFpbmluZy92YWxpZGF0aW9uIHNldHMgMTAwIHRpbWVzIHRvIGFsbG93IGZvciB0aGUgcXVhbnRpZmljYXRpb24gb2YgdW5jZXJ0YWludHkgaW4gdGhlIGRpZmZlcmVudCBwZXJmb3JtYW5jZSBlc3RpbWF0ZXMuPC9pPgo8L3A+CgojIyMgRmVhdHVyZSBzdGFiaWxpdHkgYW5hbHlzaXMgey19CgpXZSBjYW4gZXh0cmFjdCB0aGUgc2VsZWN0ZWQgZmVhdHVyZXMgZnJvbSBhbGwgJDEwMCQgdHJhaW5lZCBMYXNzbyBDb3ggbW9kZWxzIGFuZCBjcmVhdGUgYSBmcmVxdWVuY3kgc2VsZWN0aW9uIHRhYmxlOgpgYGB7cn0KIyBnZXQgc2VsZWN0ZWQgZmVhdHVyZXMgZnJvbSBhbGwgdHJhaW5lZCBsZWFybmVycyBpbiBhIGxpc3QKc2ZfbGlzdCA9IGxhcHBseShyciRsZWFybmVycywgZnVuY3Rpb24obGVhcm5lcikgewogIGxlYXJuZXIkZ3JhcGhfbW9kZWwkcGlwZW9wcyRzdXJ2LmN2X2dsbW5ldCRsZWFybmVyX21vZGVsJHNlbGVjdGVkX2ZlYXR1cmVzKCkKfSkKCiMgbWFrZSBmcmVxdWVuY3kgc2VsZWN0aW9uIHRhYmxlCm4gPSBsZW5ndGgoc2ZfbGlzdCkKZnNfcmVzID0gc29ydCh0YWJsZSh1bmxpc3Qoc2ZfbGlzdCkpLCBkZWNyZWFzaW5nID0gVFJVRSkKdGltZXMgPSBhcy52ZWN0b3IodW5uYW1lKGZzX3JlcykpCnRpYmJsZTo6dGliYmxlKGZlYXRfbmFtZSA9IG5hbWVzKGZzX3JlcyksIHRpbWVzID0gdGltZXMsIGZyZXEgPSB0aW1lcy9uKQpgYGAKYGBgCiMgQSB0aWJibGU6IDM1IMOXIDMKICAgZmVhdF9uYW1lIHRpbWVzICBmcmVxCiAgIDxjaHI+ICAgICA8aW50PiA8ZGJsPgogMSBhZ2UgICAgICAgICAxMDAgIDEgICAKIDIgZXRobmljaXR5ICAgMTAwICAxICAgCiAzIFVCRTJUICAgICAgICA1MyAgMC41MwogNCBPUkM2TCAgICAgICAgNDggIDAuNDgKIDUgQU5MTiAgICAgICAgIDQyICAwLjQyCiA2IEVSQkIyICAgICAgICA0MCAgMC40IAogNyBHUFIxNjAgICAgICAgMzUgIDAuMzUKIDggRkdGUjQgICAgICAgIDMzICAwLjMzCiA5IENFUDU1ICAgICAgICAzMiAgMC4zMgoxMCBVQkUyQyAgICAgICAgMzAgIDAuMyAKIyDigKYgd2l0aCAyNSBtb3JlIHJvd3MKYGBgCgpBcyBgYWdlYCBhbmQgYGV0aG5pY2l0eWAgd2VyZSBub3QgcGVuYWxpemVkLCB0aGV5IGhhdmUgbm9uLXplcm8gY29lZmZpY2llbnRzIGluIGFsbCBMYXNzbyBDb3ggbW9kZWxzIGFuZCB0aGVyZWZvcmUgYXJlIGluY2x1ZGVkIGluIGFsbCBzZWxlY3RlZCBmZWF0dXJlIHNldHMuCgpMYXN0bHksIHdlIGNhbiB1c2UgdGhlIGBSYCBwYWNrYWdlIFsqKnN0YWJtKipdKGh0dHBzOi8vQ1JBTi5SLXByb2plY3Qub3JnL3BhY2thZ2U9c3RhYm0pIFtAc3RhYm1dIHRvIGFzc2VzcyBob3cgc2ltaWxhciB0aGUgJDEwMCQgc2VsZWN0ZWQgZmVhdHVyZSBzZXRzIHdlcmUuCldlIHdpbGwgZGVtb25zdHJhdGUgdGhlIHVzZSBvZiB0aHJlZSBtZXRyaWNzIHdoaWNoIG1lYXN1cmUgdGhlICpzdGFiaWxpdHkqIG9mIHRoZSBMYXNzbyBDb3gncyBmZWF0dXJlIHNlbGVjdGlvbiBvbiB0aGUgVENHQS1CUkNBIGRhdGFzZXQ6CgoxLiBUaGUgSmFjY2FyZCBpbmRleAoyLiBOb2d1ZWlyYSdzIG1ldHJpYyAoY29ycmVjdGVkIGZvciBjaGFuY2UsIGkuZS4gaW5kZXBlbmRlbnQgb2YgdGhlIG51bWJlciBvZiBmZWF0dXJlczsgQE5vZ3VlaXJhMjAxOCkKMy4gWnVja25pY2sncyBtZXRyaWMgKGV4dGVuc2lvbiBvZiBKYWNjYXJkIGluZGV4IHRoYXQgY29uc2lkZXJzIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBmZWF0dXJlczsgQFp1Y2tuaWNrMjAwOCk6CgpgYGB7ciwgd2FybmluZz1GQUxTRX0Kc2V0LnNlZWQoNDIpCmphYyA9IHN0YWJtOjpzdGFiaWxpdHlKYWNjYXJkKGZlYXR1cmVzID0gc2ZfbGlzdCwgY29ycmVjdGlvbi5mb3IuY2hhbmNlID0gJ25vbmUnKQpub2cgPSBzdGFibTo6c3RhYmlsaXR5Tm9ndWVpcmEoZmVhdHVyZXMgPSBzZl9saXN0LCBwID0gbGVuZ3RoKHRhc2skZmVhdHVyZV9uYW1lcykpCgojIFNpbWlsYXJpdHkgb2YgZWFjaCBwYWlyIG9mIGZlYXR1cmVzIHVzaW5nIFBlYXJzb24gY29ycmVsYXRpb24Kc2ltLm1hdCA9IGFicyhzdGF0czo6Y29yKHggPSB0YXNrJGRhdGEoY29scyA9IHRhc2skZmVhdHVyZV9uYW1lcyksIG1ldGhvZCA9ICdwJykpCnp1Y2sgPSBzdGFibTo6c3RhYmlsaXR5WnVja25pY2soZmVhdHVyZXMgPSBzZl9saXN0LCBzaW0ubWF0ID0gc2ltLm1hdCwgCiAgdGhyZXNob2xkID0gMC45LCBjb3JyZWN0aW9uLmZvci5jaGFuY2UgPSAnZXN0aW1hdGUnLCBOID0gMTAwKQoKdGliYmxlOjp0aWJibGUoamFjY2FyZCA9IGphYywgbm9ndWVpcmEgPSBub2csIHp1Y2tuaWNrID0genVjaykKYGBgCmBgYAojIEEgdGliYmxlOiAxIMOXIDMKICBqYWNjYXJkIG5vZ3VlaXJhIHp1Y2tuaWNrCiAgICA8ZGJsPiAgICA8ZGJsPiAgICA8ZGJsPgoxICAgMC40MzkgICAgMC40MTIgICAgMC40MDIKYGBgCgpGcm9tIHRoZSBhYm92ZSB2YWx1ZXMgd2UgY29uY2x1ZGUgdGhhdCB0aGUgc3RhYmlsaXR5IG9mIExhc3NvIENveCdzIGZlYXR1cmUgc2VsZWN0aW9uIGlzIG5laXRoZXIgcG9vciBub3IgZXhjZWxsZW50IGJ1dCBzb21ld2hlcmUgaW4gYmV0d2Vlbi4KCiMgUiBzZXNzaW9uIGluZm8gey19CgpgYGB7ciwgaW5jbHVkZT1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KIyBwdXR0aW5nIGFsbCBsaWJyYXJpZXMgaGVyZSBmb3IgdGhlIHNlc3Npb24gaW5mbwpsaWJyYXJ5KCJUQ0dBYmlvbGlua3MiKQpsaWJyYXJ5KCJTdW1tYXJpemVkRXhwZXJpbWVudCIpCmxpYnJhcnkoIkRFU2VxMiIpCmxpYnJhcnkoImRwbHlyIikKbGlicmFyeSgiZ2dwbG90MiIpCmxpYnJhcnkoInN1cnZpdmFsIikKbGlicmFyeSgic3Vydm1pbmVyIikKbGlicmFyeSgiTTNDIikKbGlicmFyeSgiZ2xtbmV0IikKbGlicmFyeSgicGxvdG1vIikKbGlicmFyeSgiZ3JwcmVnIikKbGlicmFyeSgiU0dMIikKbGlicmFyeSgicHNiY0dyb3VwIikKbGlicmFyeSgiR0dhbGx5IikKbGlicmFyeSgiQmhHTE0iKQpsaWJyYXJ5KCJyaXNrc2V0Uk9DIikKbGlicmFyeSgicmlza1JlZ3Jlc3Npb24iKQpsaWJyYXJ5KCJwZXBlcnIiKQpsaWJyYXJ5KCJjMDYwIikKbGlicmFyeSgicm1zIikKbGlicmFyeSgic3VydkFVQyIpCmxpYnJhcnkoInJlZ3Bsb3QiKQpsaWJyYXJ5KCJtbHIzdmVyc2UiKQpsaWJyYXJ5KCJtbHIzcHJvYmEiKQpsaWJyYXJ5KCJtbHIzZXh0cmFsZWFybmVycyIpCmxpYnJhcnkoInN0YWJtIikKYGBgCgpgYGB7cn0Kc2Vzc2lvbkluZm8oKQpgYGAKYGBgClIgdmVyc2lvbiA0LjIuMSAoMjAyMi0wNi0yMykKUGxhdGZvcm06IHg4Nl82NC1wYy1saW51eC1nbnUgKDY0LWJpdCkKUnVubmluZyB1bmRlcjogVWJ1bnR1IDIwLjA0LjUgTFRTCgpNYXRyaXggcHJvZHVjdHM6IGRlZmF1bHQKQkxBUzogICAvdXNyL2xpYi94ODZfNjQtbGludXgtZ251L2JsYXMvbGliYmxhcy5zby4zLjkuMApMQVBBQ0s6IC91c3IvbGliL3g4Nl82NC1saW51eC1nbnUvbGFwYWNrL2xpYmxhcGFjay5zby4zLjkuMAoKbG9jYWxlOgogWzFdIExDX0NUWVBFPWVuX1VTLlVURi04ICAgICAgIExDX05VTUVSSUM9QyAgICAgICAgICAgICAgIExDX1RJTUU9ZW5fVVMuVVRGLTggICAgICAgIExDX0NPTExBVEU9ZW5fVVMuVVRGLTggICAgCiBbNV0gTENfTU9ORVRBUlk9ZW5fVVMuVVRGLTggICAgTENfTUVTU0FHRVM9ZW5fVVMuVVRGLTggICAgTENfUEFQRVI9ZW5fVVMuVVRGLTggICAgICAgTENfTkFNRT1DICAgICAgICAgICAgICAgICAKIFs5XSBMQ19BRERSRVNTPUMgICAgICAgICAgICAgICBMQ19URUxFUEhPTkU9QyAgICAgICAgICAgICBMQ19NRUFTVVJFTUVOVD1lbl9VUy5VVEYtOCBMQ19JREVOVElGSUNBVElPTj1DICAgICAgIAoKYXR0YWNoZWQgYmFzZSBwYWNrYWdlczoKWzFdIHN0YXRzNCAgICBzdGF0cyAgICAgZ3JhcGhpY3MgIGdyRGV2aWNlcyB1dGlscyAgICAgZGF0YXNldHMgIG1ldGhvZHMgICBiYXNlICAgICAKCm90aGVyIGF0dGFjaGVkIHBhY2thZ2VzOgogWzFdIHN0YWJtXzEuMi4xICAgICAgICAgICAgICAgICBtbHIzZXh0cmFsZWFybmVyc18wLjYuMSAgICAgbWxyM3Byb2JhXzAuNS4yICAgICAgICAgICAgCiBbNF0gbWxyM3ZlcnNlXzAuMi43ICAgICAgICAgICAgIG1scjNfMC4xNC4xICAgICAgICAgICAgICAgICByZWdwbG90XzEuMSAgICAgICAgICAgICAgICAKIFs3XSBzdXJ2QVVDXzEuMS0xICAgICAgICAgICAgICAgcm1zXzYuMy0wICAgICAgICAgICAgICAgICAgIFNwYXJzZU1fMS44MSAgICAgICAgICAgICAgIApbMTBdIEhtaXNjXzQuNy0xICAgICAgICAgICAgICAgICBsYXR0aWNlXzAuMjAtNDUgICAgICAgICAgICAgYzA2MF8wLjItOSAgICAgICAgICAgICAgICAgClsxM10gcGVwZXJyXzEuNCAgICAgICAgICAgICAgICAgIHNub3dmYWxsXzEuODQtNi4yICAgICAgICAgICBzbm93XzAuNC00ICAgICAgICAgICAgICAgICAKWzE2XSByaXNrUmVncmVzc2lvbl8yMDIyLjA5LjIzICAgcmlza3NldFJPQ18xLjAuNC4xICAgICAgICAgIE1BU1NfNy4zLTU3ICAgICAgICAgICAgICAgIApbMTldIEJoR0xNXzEuMS4wICAgICAgICAgICAgICAgICBHR2FsbHlfMi4xLjIgICAgICAgICAgICAgICAgcHNiY0dyb3VwXzEuNSAgICAgICAgICAgICAgClsyMl0gbXZ0bm9ybV8xLjEtMyAgICAgICAgICAgICAgIFN1cHBEaXN0c18xLjEtOS43ICAgICAgICAgICBMZWFybkJheWVzXzIuMTUuMSAgICAgICAgICAKWzI1XSBTR0xfMS4zICAgICAgICAgICAgICAgICAgICAgZ3JwcmVnXzMuNC4wICAgICAgICAgICAgICAgIHBsb3Rtb18zLjYuMiAgICAgICAgICAgICAgIApbMjhdIFRlYWNoaW5nRGVtb3NfMi4xMiAgICAgICAgICBwbG90cml4XzMuOC0yICAgICAgICAgICAgICAgRm9ybXVsYV8xLjItNCAgICAgICAgICAgICAgClszMV0gZ2xtbmV0XzQuMS00ICAgICAgICAgICAgICAgIE1hdHJpeF8xLjUtMSAgICAgICAgICAgICAgICBNM0NfMS4yMC4wICAgICAgICAgICAgICAgICAKWzM0XSBzdXJ2bWluZXJfMC40LjkgICAgICAgICAgICAgZ2dwdWJyXzAuNC4wICAgICAgICAgICAgICAgIHN1cnZpdmFsXzMuNC0wICAgICAgICAgICAgIApbMzddIGdncGxvdDJfMy40LjAgICAgICAgICAgICAgICBkcGx5cl8xLjAuMTAgICAgICAgICAgICAgICAgREVTZXEyXzEuMzguMyAgICAgICAgICAgICAgCls0MF0gU3VtbWFyaXplZEV4cGVyaW1lbnRfMS4yOC4wIEJpb2Jhc2VfMi41OC4wICAgICAgICAgICAgICBHZW5vbWljUmFuZ2VzXzEuNTAuMiAgICAgICAKWzQzXSBHZW5vbWVJbmZvRGJfMS4zNC42ICAgICAgICAgSVJhbmdlc18yLjMyLjAgICAgICAgICAgICAgIFM0VmVjdG9yc18wLjM2LjEgICAgICAgICAgIApbNDZdIEJpb2NHZW5lcmljc18wLjQ0LjAgICAgICAgICBNYXRyaXhHZW5lcmljc18xLjEwLjAgICAgICAgbWF0cml4U3RhdHNfMC42My4wICAgICAgICAgCls0OV0gVENHQWJpb2xpbmtzXzIuMjUuMyAgICAgICAgCgpsb2FkZWQgdmlhIGEgbmFtZXNwYWNlIChhbmQgbm90IGF0dGFjaGVkKToKICBbMV0gcmFwcGRpcnNfMC4zLjMgICAgICAgICAgICAgIHZpb3Bsb3RfMC40LjAgICAgICAgICAgICAgICB0aWR5cl8xLjIuMSAgICAgICAgICAgICAgICAKICBbNF0gYml0NjRfNC4wLjUgICAgICAgICAgICAgICAgIGtuaXRyXzEuNDAgICAgICAgICAgICAgICAgICBtdWx0Y29tcF8xLjQtMjAgICAgICAgICAgICAKICBbN10gRGVsYXllZEFycmF5XzAuMjQuMCAgICAgICAgIGRhdGEudGFibGVfMS4xNC42ICAgICAgICAgICBycGFydF80LjEuMTkgICAgICAgICAgICAgICAKIFsxMF0gS0VHR1JFU1RfMS4zOC4wICAgICAgICAgICAgIFJDdXJsXzEuOTgtMS45ICAgICAgICAgICAgICBkb1BhcmFsbGVsXzEuMC4xNyAgICAgICAgICAKIFsxM10gZ2VuZXJpY3NfMC4xLjMgICAgICAgICAgICAgIHRpbWVyZWdfMi4wLjQgICAgICAgICAgICAgICB0Z3BfMi40LTIxICAgICAgICAgICAgICAgICAKIFsxNl0gVEguZGF0YV8xLjEtMSAgICAgICAgICAgICAgIFJTUUxpdGVfMi4yLjIwICAgICAgICAgICAgICBwb2xzcGxpbmVfMS4xLjIwICAgICAgICAgICAKIFsxOV0gcHJveHlfMC40LTI3ICAgICAgICAgICAgICAgIGZ1dHVyZV8xLjMxLjAgICAgICAgICAgICAgICBiaXRfNC4wLjQgICAgICAgICAgICAgICAgICAKIFsyMl0gdHpkYl8wLjMuMCAgICAgICAgICAgICAgICAgIHhtbDJfMS4zLjMgICAgICAgICAgICAgICAgICBhc3NlcnR0aGF0XzAuMi4xICAgICAgICAgICAKIFsyNV0geGZ1bl8wLjMzICAgICAgICAgICAgICAgICAgIGhtc18xLjEuMiAgICAgICAgICAgICAgICAgICBldmFsdWF0ZV8wLjIwICAgICAgICAgICAgICAKIFsyOF0gZmFuc2lfMS4wLjMgICAgICAgICAgICAgICAgIHByb2dyZXNzXzEuMi4yICAgICAgICAgICAgICBkYnBseXJfMi4yLjEgICAgICAgICAgICAgICAKIFszMV0ga20uY2lfMC41LTYgICAgICAgICAgICAgICAgIERCSV8xLjEuMyAgICAgICAgICAgICAgICAgICBnZW5lcGxvdHRlcl8xLjc2LjAgICAgICAgICAKIFszNF0gaHRtbHdpZGdldHNfMS41LjQgICAgICAgICAgIHJlc2hhcGVfMC44LjkgICAgICAgICAgICAgICBwdXJycl8xLjAuMSAgICAgICAgICAgICAgICAKIFszN10gZWxsaXBzaXNfMC4zLjIgICAgICAgICAgICAgIG1scjNkYXRhXzAuNi4xICAgICAgICAgICAgICBSU3BlY3RyYV8wLjE2LTEgICAgICAgICAgICAKIFs0MF0gYmFja3BvcnRzXzEuNC4xICAgICAgICAgICAgIGFubm90YXRlXzEuNzYuMCAgICAgICAgICAgICBiaW9tYVJ0XzIuNTQuMCAgICAgICAgICAgICAKIFs0M10gZGVsZGlyXzEuMC02ICAgICAgICAgICAgICAgIHZjdHJzXzAuNS4xICAgICAgICAgICAgICAgICBxdWFudHJlZ181Ljk0ICAgICAgICAgICAgICAKIFs0Nl0gYWJpbmRfMS40LTUgICAgICAgICAgICAgICAgIGNhY2hlbV8xLjAuNiAgICAgICAgICAgICAgICB3aXRocl8yLjUuMCAgICAgICAgICAgICAgICAKIFs0OV0gbWxyM2xlYXJuZXJzXzAuNS42ICAgICAgICAgIGNoZWNrbWF0ZV8yLjEuMCAgICAgICAgICAgICBwcmV0dHl1bml0c18xLjEuMSAgICAgICAgICAKIFs1Ml0gbWxyM2ZzZWxlY3RfMC45LjEgICAgICAgICAgIHBhcmFtNl8wLjIuNCAgICAgICAgICAgICAgICBjbHVzdGVyXzIuMS4zICAgICAgICAgICAgICAKIFs1NV0gY3JheW9uXzEuNS4yICAgICAgICAgICAgICAgIHBrZ2NvbmZpZ18yLjAuMyAgICAgICAgICAgICBubG1lXzMuMS0xNTcgICAgICAgICAgICAgICAKIFs1OF0gbWxlZ3BfMy4xLjkgICAgICAgICAgICAgICAgIG5uZXRfNy4zLTE3ICAgICAgICAgICAgICAgICBybGFuZ18xLjAuNiAgICAgICAgICAgICAgICAKIFs2MV0gZ2xvYmFsc18wLjE2LjIgICAgICAgICAgICAgIGxpZmVjeWNsZV8xLjAuMyAgICAgICAgICAgICBNYXRyaXhNb2RlbHNfMC41LTEgICAgICAgICAKIFs2NF0gc2FuZHdpY2hfMy4wLTIgICAgICAgICAgICAgIGRvd25sb2FkZXJfMC40ICAgICAgICAgICAgICBmaWxlbG9ja18xLjAuMiAgICAgICAgICAgICAKIFs2N10gcGFsbWVycGVuZ3VpbnNfMC4xLjEgICAgICAgIEJpb2NGaWxlQ2FjaGVfMi42LjAgICAgICAgICBtZXRzXzEuMy4xICAgICAgICAgICAgICAgICAKIFs3MF0gZG9TTk9XXzEuMC4yMCAgICAgICAgICAgICAgIEtNc3Vydl8wLjEtNSAgICAgICAgICAgICAgICBjYXJEYXRhXzMuMC01ICAgICAgICAgICAgICAKIFs3M10gYm9vdF8xLjMtMjggICAgICAgICAgICAgICAgIHpvb18xLjgtMTEgICAgICAgICAgICAgICAgICBiYXNlNjRlbmNfMC4xLTMgICAgICAgICAgICAKIFs3Nl0gcG5nXzAuMS04ICAgICAgICAgICAgICAgICAgIGJpdG9wc18xLjAtNyAgICAgICAgICAgICAgICBCaW9zdHJpbmdzXzIuNjYuMCAgICAgICAgICAKIFs3OV0gYmxvYl8xLjIuMyAgICAgICAgICAgICAgICAgIHNoYXBlXzEuNC42ICAgICAgICAgICAgICAgICBwYXJhZG94XzAuMTEuMCAgICAgICAgICAgICAKIFs4Ml0gc3RyaW5ncl8xLjUuMCAgICAgICAgICAgICAgIHBhcmFsbGVsbHlfMS4zNC4wICAgICAgICAgICByZWFkcl8yLjEuMyAgICAgICAgICAgICAgICAKIFs4NV0ganBlZ18wLjEtOSAgICAgICAgICAgICAgICAgIHJzdGF0aXhfMC43LjEgICAgICAgICAgICAgICBkaWN0aW9uYXI2XzAuMS4zICAgICAgICAgICAKIFs4OF0gZ2dzaWduaWZfMC42LjQgICAgICAgICAgICAgIHNjYWxlc18xLjIuMSAgICAgICAgICAgICAgICBtZW1vaXNlXzIuMC4xICAgICAgICAgICAgICAKIFs5MV0gbWFncml0dHJfMi4wLjMgICAgICAgICAgICAgIHBseXJfMS44LjggICAgICAgICAgICAgICAgICB6bGliYmlvY18xLjQ0LjAgICAgICAgICAgICAKIFs5NF0gY29tcGlsZXJfNC4yLjEgICAgICAgICAgICAgIFJDb2xvckJyZXdlcl8xLjEtMyAgICAgICAgICBjbHVlXzAuMy02MyAgICAgICAgICAgICAgICAKIFs5N10gbG1lNF8xLjEtMzEgICAgICAgICAgICAgICAgIHNldDZfMC4yLjUgICAgICAgICAgICAgICAgICBjbGlfMy40LjEgICAgICAgICAgICAgICAgICAKWzEwMF0gWFZlY3Rvcl8wLjM4LjAgICAgICAgICAgICAgIG1scjN0dW5pbmdzcGFjZXNfMC4zLjMgICAgICBtbHIzZmlsdGVyc18wLjcuMCAgICAgICAgICAKWzEwM10gbGlzdGVudl8wLjkuMCAgICAgICAgICAgICAgIGh0bWxUYWJsZV8yLjQuMSAgICAgICAgICAgICB0aWR5c2VsZWN0XzEuMi4wICAgICAgICAgICAKWzEwNl0gc3RyaW5naV8xLjcuMTIgICAgICAgICAgICAgIFRDR0FiaW9saW5rc0dVSS5kYXRhXzEuMTguMCBkaXN0cjZfMS42LjEzICAgICAgICAgICAgICAKWzEwOV0geWFtbF8yLjMuNSAgICAgICAgICAgICAgICAgIGFza3Bhc3NfMS4xICAgICAgICAgICAgICAgICBsb2NmaXRfMS41LTkuNiAgICAgICAgICAgICAKWzExMl0gbGF0dGljZUV4dHJhXzAuNi0zMCAgICAgICAgIHN1cnZNaXNjXzAuNS42ICAgICAgICAgICAgICBncmlkXzQuMi4xICAgICAgICAgICAgICAgICAKWzExNV0gbWFwdHJlZV8xLjQtOCAgICAgICAgICAgICAgIHRvb2xzXzQuMi4xICAgICAgICAgICAgICAgICBtbHIzbWlzY18wLjExLjAgICAgICAgICAgICAKWzExOF0gbWxyM2NsdXN0ZXJfMC4xLjYgICAgICAgICAgIGZ1dHVyZS5hcHBseV8xLjEwLjAgICAgICAgICBwYXJhbGxlbF80LjIuMSAgICAgICAgICAgICAKWzEyMV0gbWF0cml4Y2FsY18xLjAtNiAgICAgICAgICAgIHJzdHVkaW9hcGlfMC4xNCAgICAgICAgICAgICB1dWlkXzEuMS0wICAgICAgICAgICAgICAgICAKWzEyNF0gZm9yZWFjaF8xLjUuMiAgICAgICAgICAgICAgIGZvcmVpZ25fMC44LTgyICAgICAgICAgICAgICBncmlkRXh0cmFfMi4zICAgICAgICAgICAgICAKWzEyN10gcHJvZGxpbV8yMDE5LjExLjEzICAgICAgICAgIFJ0c25lXzAuMTYgICAgICAgICAgICAgICAgICBkaWdlc3RfMC42LjMxICAgICAgICAgICAgICAKWzEzMF0gbGF2YV8xLjcuMCAgICAgICAgICAgICAgICAgIGNtcHJza18yLjItMTEgICAgICAgICAgICAgICBSY3BwXzEuMC4xMCAgICAgICAgICAgICAgICAKWzEzM10gY2FyXzMuMS0xICAgICAgICAgICAgICAgICAgIGJyb29tXzEuMC4xICAgICAgICAgICAgICAgICBodHRyXzEuNC40ICAgICAgICAgICAgICAgICAKWzEzNl0gQW5ub3RhdGlvbkRiaV8xLjYwLjAgICAgICAgIG1scjN0dW5pbmdfMC4xNy4yICAgICAgICAgICBjb2xvcnNwYWNlXzIuMC0zICAgICAgICAgICAKWzEzOV0gcnZlc3RfMS4wLjMgICAgICAgICAgICAgICAgIFhNTF8zLjk5LTAuMTMgICAgICAgICAgICAgICByZXRpY3VsYXRlXzEuMjYgICAgICAgICAgICAKWzE0Ml0gdW1hcF8wLjIuOS4wICAgICAgICAgICAgICAgIHNwbGluZXNfNC4yLjEgICAgICAgICAgICAgICBsZ3JfMC40LjQgICAgICAgICAgICAgICAgICAKWzE0NV0gYmJvdGtfMC43LjIgICAgICAgICAgICAgICAgIHNtXzIuMi01LjcuMSAgICAgICAgICAgICAgICBzdGF0bW9kXzEuNC4zNyAgICAgICAgICAgICAKWzE0OF0gbWxyM3BpcGVsaW5lc18wLjQuMiAgICAgICAgIHh0YWJsZV8xLjgtNCAgICAgICAgICAgICAgICBubG9wdHJfMi4wLjMgICAgICAgICAgICAgICAKWzE1MV0ganNvbmxpdGVfMS44LjMgICAgICAgICAgICAgIGNvcnBjb3JfMS42LjEwICAgICAgICAgICAgICBjbHVzdGVyQ3JpdF8xLjIuOCAgICAgICAgICAKWzE1NF0gUjZfMi41LjEgICAgICAgICAgICAgICAgICAgIHBpbGxhcl8xLjguMSAgICAgICAgICAgICAgICBodG1sdG9vbHNfMC41LjMgICAgICAgICAgICAKWzE1N10gbWlucWFfMS4yLjUgICAgICAgICAgICAgICAgIGdsdWVfMS42LjIgICAgICAgICAgICAgICAgICBmYXN0bWFwXzEuMS4wICAgICAgICAgICAgICAKWzE2MF0gQmlvY1BhcmFsbGVsXzEuMzIuNSAgICAgICAgIGJlYW5wbG90XzEuMy4xICAgICAgICAgICAgICBjbGFzc183LjMtMjAgICAgICAgICAgICAgICAKWzE2M10gb29wbGFoXzAuMi4wICAgICAgICAgICAgICAgIGNvZGV0b29sc18wLjItMTggICAgICAgICAgICB1dGY4XzEuMi4yICAgICAgICAgICAgICAgICAKWzE2Nl0gdGliYmxlXzMuMS44ICAgICAgICAgICAgICAgIG51bURlcml2XzIwMTYuOC0xLjEgICAgICAgICBjdXJsXzQuMy4zICAgICAgICAgICAgICAgICAKWzE2OV0gbWxyM3Zpel8wLjYuMSAgICAgICAgICAgICAgIG9wZW5zc2xfMi4wLjMgICAgICAgICAgICAgICBpbnRlcnBfMS4xLTMgICAgICAgICAgICAgICAKWzE3Ml0gcGVuYWxpemVkU1ZNXzEuMS4zICAgICAgICAgIHJtYXJrZG93bl8yLjE3ICAgICAgICAgICAgICBtdW5zZWxsXzAuNS4wICAgICAgICAgICAgICAKWzE3NV0gZTEwNzFfMS43LTEyICAgICAgICAgICAgICAgIEdlbm9tZUluZm9EYkRhdGFfMS4yLjkgICAgICBpdGVyYXRvcnNfMS4wLjE0ICAgICAgICAgICAKWzE3OF0gZ3RhYmxlXzAuMy4xICAgICAgICAgICAgICAgCmBgYAoKIyBSZWZlcmVuY2VzCgo=
+
LS0tCnRpdGxlOiAiU3VwcGxlbWVudGFsIGluZm9ybWF0aW9uIGZvciAnVHV0b3JpYWwgb24gc3Vydml2YWwgbW9kZWxsaW5nIHdpdGggb21pY3MgZGF0YSciCmRhdGU6ICJMYXN0IHVwZGF0ZWQ6IGByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIsICVZJylgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGNzczogc3R5bGUuY3NzCiAgICB0aGVtZTogdW5pdGVkCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiB0cnVlCiAgICAgIHNtb290aF9zY3JvbGw6IHRydWUKICAgIHRvY19kZXB0aDogNAogICAgbnVtYmVyX3NlY3Rpb25zOiBmYWxzZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCmJpYmxpb2dyYXBoeTogcmVmZXJlbmNlcy5iaWIKbGluay1jaXRhdGlvbnM6IHRydWUKLS0tCgpgYGB7ciwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KCAKICBjb21tZW50ID0gJycsIGV2YWwgPSBGQUxTRQopCmBgYAo8YnI+ClRoaXMgaXMgYW4gW1IgTWFya2Rvd25dKGh0dHA6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20pIHN1cHBsZW1lbnQgZm9yIHRoZSBhcnRpY2xlIFsqKl9UdXRvcmlhbCBvbiBzdXJ2aXZhbCBtb2RlbGxpbmcgd2l0aCBvbWljcyBkYXRhXyoqXShodHRwczovL2FyeGl2Lm9yZy9hYnMvMjMwMi4xMjU0MikgW0BaaGFvMjAyM10uCgojIEludHJvZHVjdGlvbiB7LX0KCltUaGUgQ2FuY2VyIEdlbm9tZSBBdGxhc10oaHR0cHM6Ly93d3cuY2FuY2VyLmdvdi9hYm91dC1uY2kvb3JnYW5pemF0aW9uL2NjZy9yZXNlYXJjaC9zdHJ1Y3R1cmFsLWdlbm9taWNzL3RjZ2EpIChUQ0dBKSBwcm92aWRlcyBhbiBlbm9ybW91cyBjb2xsZWN0aW9uIG9mIGNhbmNlciBkYXRhIHNldHMsIGluY2x1ZGluZyBzdXJ2aXZhbCwgY2xpbmljYWwgYW5kIG11bHRpLW9taWNzIGRhdGEuCgo6Ojp7LmdyZWVuLWJveH0KV2Ugd2lsbCB1c2UgVENHQSBkYXRhIHRvIGRlbW9uc3RyYXRlOgoKLSBUaGUgZGlmZmVyZW50IGRhdGEgdHlwZXMKLSBQcmVwcm9jZXNzaW5nIG9mIHN1cnZpdmFsIGFuZCBvbWljcyBkYXRhCi0gQW5hbHlzaXMgb2Ygc3Vydml2YWwgZGF0YSBieSBjbGFzc2ljYWwgc3RhdGlzdGljYWwgbWV0aG9kcwotIFVuc3VwZXJ2aXNlZCBsZWFybmluZyBmb3Igb21pY3MgZGF0YQotIEZyZXF1ZW50aXN0ICYgQmF5ZXNpYW4gc3VwZXJ2aXNlZCBsZWFybmluZyBmb3Igc3Vydml2YWwgYW5kIG9taWNzIGRhdGEKOjo6CgojIFRDR0Egc3Vydml2YWwgYW5kIGNsaW5pY2FsIGRhdGEgey19CgpUaGUgUi9CaW9jb25kdWN0b3IgcGFja2FnZSBbKipUQ0dBYmlvbGlua3MqKl0oaHR0cHM6Ly9iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL1RDR0FiaW9saW5rcy8pIFtATW91bmlyMjAxOV0gcHJvdmlkZXMgYSBmZXcgZnVuY3Rpb25zIHRvIGRvd25sb2FkIGFuZCBwcmVwcm9jZXNzIGNsaW5pY2FsIGFuZCBtdWx0aS1vbWljcyBkYXRhIGZyb20gdGhlIFtHZW5vbWljIERhdGEgQ29tbW9uc10oaHR0cHM6Ly9nZGMuY2FuY2VyLmdvdi8pIChHREMpIERhdGEgUG9ydGFsIGZvciBmdXJ0aGVyIGFuYWx5c2lzLgoKRmlyc3Qgd2UgbG9hZCBhbGwgbmVjZXNzYXJ5IGxpYnJhcmllcyB1c2VkIGluIHRoaXMgdHV0b3JpYWwgZXhjZXB0IFsqKm1scjMqKiBsaWJyYXJpZXNdKCNtbHIzKSB3aGljaCB3aWxsIGJlIGludHJvZHVjZWQgbGF0ZXIuIApUaGVuIHdlIHVzZSBmdW5jdGlvbiBgR0RDcXVlcnlfY2xpbmljKClgIGZyb20gKipUQ0dBYmlvbGlua3MqKiBwYWNrYWdlIHRvIHF1ZXJ5IGFuZCBkb3dubG9hZCBUQ0dBIHN1cnZpdmFsIGFuZCBjbGluaWNhbCBkYXRhIGZyb20gbXVsdGlwbGUgY2FuY2VyIHR5cGVzOgoKYGBge3J9CiMgbG9hZCBhbGwgbGlicmFyaWVzIHVzZWQgaW4gdGhpcyB0dXRvcmlhbCBleGNlcHQgbWxyMwpsaWJyYXJ5KCJUQ0dBYmlvbGlua3MiKQpsaWJyYXJ5KCJTdW1tYXJpemVkRXhwZXJpbWVudCIpCmxpYnJhcnkoIkRFU2VxMiIpCmxpYnJhcnkoImRwbHlyIikKbGlicmFyeSgiZ2dwbG90MiIpCmxpYnJhcnkoInN1cnZpdmFsIikKbGlicmFyeSgic3Vydm1pbmVyIikKbGlicmFyeSgiTTNDIikKbGlicmFyeSgiZ2xtbmV0IikKbGlicmFyeSgicGxvdG1vIikKbGlicmFyeSgiZ3JwcmVnIikKbGlicmFyeSgiU0dMIikKbGlicmFyeSgicHNiY0dyb3VwIikKbGlicmFyeSgicHNiY1NwZWVkVXAiKQpsaWJyYXJ5KCJHR2FsbHkiKQpsaWJyYXJ5KCJCaEdMTSIpCmxpYnJhcnkoInJpc2tzZXRST0MiKQpsaWJyYXJ5KCJyaXNrUmVncmVzc2lvbiIpCmxpYnJhcnkoInBlcGVyciIpCmxpYnJhcnkoImMwNjAiKQpsaWJyYXJ5KCJybXMiKQpsaWJyYXJ5KCJzdXJ2QVVDIikKbGlicmFyeSgicmVncGxvdCIpCmBgYAoKYGBge3J9CiMgZG93bmxvYWQgdGhlIGNsaW5pY2FsIGRhdGEgYW5kIGV4dHJhY3QgZGF0YSBmb3IgbXVsdGlwbGUgY2FuY2VycyB1c2luZyBHREMgYXBpIG1ldGhvZApjYW5jZXJfdHlwZXMgPSBjKCJUQ0dBLUJMQ0EiLCAiVENHQS1CUkNBIiwgIlRDR0EtQ09BRCIsICJUQ0dBLUxJSEMiLCAKICAgICAgICAgICAgICAgICAgIlRDR0EtTFVBRCIsICJUQ0dBLVBBQUQiLCAiVENHQS1QUkFEIiwgIlRDR0EtVEhDQSIpCmNsaW4gPSBOVUxMCmZvciAoaSBpbiBzZXFfYWxvbmcoY2FuY2VyX3R5cGVzKSkgewogIHRtcCA9IFRDR0FiaW9saW5rczo6R0RDcXVlcnlfY2xpbmljKHByb2plY3QgPSBjYW5jZXJfdHlwZXNbaV0sIHR5cGUgPSAiY2xpbmljYWwiKQogIGNsaW4gPSByYmluZChjbGluLCB0bXBbLCBjKCJwcm9qZWN0IiwgInN1Ym1pdHRlcl9pZCIsICJ2aXRhbF9zdGF0dXMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImRheXNfdG9fbGFzdF9mb2xsb3dfdXAiLCAiZGF5c190b19kZWF0aCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYWdlX2F0X2RpYWdub3NpcyIsICJnZW5kZXIiLCAicmFjZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZXRobmljaXR5IiwgImFqY2NfcGF0aG9sb2dpY190IildKQp9CgojIGV4dHJhY3QgdGhlIG9ic2VydmVkIHRpbWUgZm9yIGVhY2ggcGF0aWVudCBhbmQgdXNlIHllYXJzIGFzIHVuaXQKY2xpbiR0aW1lID0gYXBwbHkoY2xpblssIGMoImRheXNfdG9fZGVhdGgiLCAiZGF5c190b19sYXN0X2ZvbGxvd191cCIpXSwgMSwgbWF4LCBuYS5ybSA9IFRSVUUpIC8gMzY1LjI1CmNsaW4kYWdlID0gY2xpbiRhZ2VfYXRfZGlhZ25vc2lzIC8gMzY1LjI1CmNsaW4kc3RhdHVzID0gY2xpbiR2aXRhbF9zdGF0dXMKY2xpbiA9IGNsaW5bLCBjKCJwcm9qZWN0IiwgInN1Ym1pdHRlcl9pZCIsICJzdGF0dXMiLCAidGltZSIsICJnZW5kZXIiLCAiYWdlIiwgInJhY2UiLCAiZXRobmljaXR5IildCiMgZXh0cmFjdCBwYXRpZW50cyB3aXRoIHBvc2l0aXZlIG92ZXJhbGwgc3Vydml2YWwgdGltZQpjbGluID0gY2xpblsoY2xpbiR0aW1lID4gMCkgJiAoY2xpbiRzdGF0dXMgJWluJSBjKCJBbGl2ZSIsICJEZWFkIikpLCBdCgojIGZyZXF1ZW5jeSB0YWJsZSBvZiB0aGUgcGF0aWVudHMgdy5yLnQuIHN0YXR1cywgZ2VuZGVyIGFuZCBldGhuaWNpdHkKY2xpbiAlPiUKICBjb3VudChzdGF0dXMsIGdlbmRlciwgZXRobmljaXR5KSAlPiUKICBncm91cF9ieShzdGF0dXMpICU+JSAgICAgICAgCiAgbXV0YXRlKHByb3AgPSBwcm9wLnRhYmxlKG4pKQpgYGAKCmBgYAojIEEgdGliYmxlOiAxMiDDlyA1CiMgR3JvdXBzOiAgIHN0YXR1cyBbMl0KICAgc3RhdHVzIGdlbmRlciBldGhuaWNpdHkgICAgICAgICAgICAgICAgICBuICAgIHByb3AKICAgPGNocj4gIDxjaHI+ICA8Y2hyPiAgICAgICAgICAgICAgICAgIDxpbnQ+ICAgPGRibD4KIDEgQWxpdmUgIGZlbWFsZSBoaXNwYW5pYyBvciBsYXRpbm8gICAgICAgIDc1IDAuMDI0MCAKIDIgQWxpdmUgIGZlbWFsZSBub3QgaGlzcGFuaWMgb3IgbGF0aW5vICAxMzY3IDAuNDM4ICAKIDMgQWxpdmUgIGZlbWFsZSBub3QgcmVwb3J0ZWQgICAgICAgICAgICAgMzI4IDAuMTA1ICAKIDQgQWxpdmUgIG1hbGUgICBoaXNwYW5pYyBvciBsYXRpbm8gICAgICAgIDM0IDAuMDEwOSAKIDUgQWxpdmUgIG1hbGUgICBub3QgaGlzcGFuaWMgb3IgbGF0aW5vICAxMDQxIDAuMzM0ICAKIDYgQWxpdmUgIG1hbGUgICBub3QgcmVwb3J0ZWQgICAgICAgICAgICAgMjc2IDAuMDg4NCAKIDcgRGVhZCAgIGZlbWFsZSBoaXNwYW5pYyBvciBsYXRpbm8gICAgICAgICA3IDAuMDA4MDkKIDggRGVhZCAgIGZlbWFsZSBub3QgaGlzcGFuaWMgb3IgbGF0aW5vICAgMzc3IDAuNDM2ICAKIDkgRGVhZCAgIGZlbWFsZSBub3QgcmVwb3J0ZWQgICAgICAgICAgICAgIDY0IDAuMDc0MCAKMTAgRGVhZCAgIG1hbGUgICBoaXNwYW5pYyBvciBsYXRpbm8gICAgICAgIDEwIDAuMDExNiAKMTEgRGVhZCAgIG1hbGUgICBub3QgaGlzcGFuaWMgb3IgbGF0aW5vICAgMzI3IDAuMzc4ICAKMTIgRGVhZCAgIG1hbGUgICBub3QgcmVwb3J0ZWQgICAgICAgICAgICAgIDgwIDAuMDkyNSAKYGBgCgpgYGB7cn0KIyBjZW5zb3JpbmcgcGxvdCBieSBjYW5jZXIgdHlwZXMKSUQgPSAxOm5yb3coY2xpbikKY2xpbiAlPiUKICBnZ3Bsb3QoCiAgICBhZXMoeSA9IElELCB4ID0gdGltZSwgY29sb3VyID0gcHJvamVjdCwgc2hhcGUgPSBmYWN0b3Ioc3RhdHVzKSkpICsKICAgIGdlb21fc2VnbWVudChhZXMoeCA9IHRpbWUsIHkgPSBJRCwgeGVuZCA9IDAsIHllbmQgPSBJRCkpICsKICBnZW9tX3BvaW50KCkgKwogIGdndGl0bGUoIiIpICsKICBsYWJzKHggPSAiWWVhcnMiLCB5ID0gIlBhdGllbnRzIikgKwogIHNjYWxlX3NoYXBlX2Rpc2NyZXRlKG5hbWUgPSAiU3RhdHVzIiwgbGFiZWxzID0gYygiQ2Vuc29yZWQiLCAiRGVhZCIpKSArCiAgc2NhbGVfY29sb3JfZGlzY3JldGUobmFtZSA9ICJDYW5jZXIiLCAKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJCbGFkZGVyIiwgIkJyZWFzdCIsICJDb2xvbiIsICJMaXZlciIsICJMdW5nIGFkZW5vIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUGFuY3JlYXRpYyIsICJQcm9zdGF0ZSIsICJUaHlyb2lkIikpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgbGVnZW5kLmRpcmVjdGlvbiA9ICJ2ZXJ0aWNhbCIpICsgCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAyLCBieXJvdyA9IFRSVUUpKQpgYGAKCiFbX092ZXJhbGwgc3Vydml2YWwgdGltZXMgYW5kIHN0YXR1cyBvZiBwYW4tY2FuY2VyIHBhdGllbnRzIGZyb20gVENHQS5fXShmaWcvVENHQV9zdXJ2aXZhbC5wbmcpe3dpZHRoPTYwJX0KCjxicj4KCiMgVENHQSBvbWljcyBkYXRhIHstfQoKV2UgdXNlIGZ1bmN0aW9uIGBHRENxdWVyeSgpYCB0byBxdWVyeSBhbmQgdXNlIGBHRENkb3dubG9hZCgpYCBhbmQgYEdEQ3ByZXBhcmUoKWAgdG8gZG93bmxvYWQgVENHQSBvbWljcyBkYXRhIGZyb20gb25lIGNhbmNlciB0eXBlIChicmVhc3QgY2FuY2VyKS4KVGhlIGFyZ3VtZW50IGBkYXRhLmNhdGVnb3J5YCBpbiBmdW5jdGlvbiBgR0RDcXVlcnkoKWAgc3BlY2lmaWVzIHRoZSB0eXBlIG9mIG9taWNzIGRhdGEsIHN1Y2ggYXMgYCJDb3B5IE51bWJlciBWYXJpYXRpb24iYCwgYCJETkEgTWV0aHlsYXRpb24iYCwgYCJUcmFuc2NyaXB0b21lIFByb2ZpbGluZyJgLCBgIlNpbXBsZSBOdWNsZW90aWRlIFZhcmlhdGlvbiJgLgpOb3RlIHRoYXQgdGhlIGRvd25sb2FkZWQgb21pY3MgZGF0YSBhcmUgYWNjb21wYW5pZWQgYnkgbWV0YWRhdGEgaW5jbHVkaW5nIHN1cnZpdmFsIG91dGNvbWVzLCBjbGluaWNhbCBhbmQgZGVtb2dyYXBoaWMgdmFyaWFibGVzLiAKVGhlIGFjY29tcGFuaWVkIG1ldGFkYXRhIGFyZSBhbG1vc3QgdGhlIHNhbWUgYXMgdGhlIGNsaW5pY2FsIGRhdGEgZG93bmxvYWRlZCB2aWEgYEdEQ3F1ZXJ5X2NsaW5pYygpYCBpbiB0aGUgcHJldmlvdXMgc2VjdGlvbiBidXQgaGVyZSBvbmx5IGNvcnJlc3BvbmRpbmcgdG8gb25lIGNhbmNlciB0eXBlLgoKYGBge3J9CiMgZG93bmxvYWQgVENHQSBicmVhc3QgY2FuY2VyIChCUkNBKSBtUk5BLVNlcSBkYXRhIHVzaW5nIEdEQyBhcGkgbWV0aG9kCnF1ZXJ5ID0gVENHQWJpb2xpbmtzOjpHRENxdWVyeShwcm9qZWN0ID0gIlRDR0EtQlJDQSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhLmNhdGVnb3J5ID0gIlRyYW5zY3JpcHRvbWUgUHJvZmlsaW5nIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEudHlwZSA9ICJHZW5lIEV4cHJlc3Npb24gUXVhbnRpZmljYXRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3cudHlwZSA9ICJTVEFSIC0gQ291bnRzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cGVyaW1lbnRhbC5zdHJhdGVneSA9ICJSTkEtU2VxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZS50eXBlID0gYygiUHJpbWFyeSBUdW1vciIpKQpUQ0dBYmlvbGlua3M6OkdEQ2Rvd25sb2FkKHF1ZXJ5ID0gcXVlcnksIG1ldGhvZCA9ICJhcGkiKQpkYXQgPSBUQ0dBYmlvbGlua3M6OkdEQ3ByZXBhcmUocXVlcnkgPSBxdWVyeSkKClN1bW1hcml6ZWRFeHBlcmltZW50Ojphc3NheXMoZGF0KSR1bnN0cmFuZGVkWzE6NSwgMToyXQpgYGAKYGBge3IsIGVjaG89RkFMU0V9CiMgc2F2ZSB0aGUgZG93bmxvYWRlZCBsYXJnZSBkYXRhIG9uIHNldmVyCnNhdmUoZGF0LCBmaWxlPSJUQ0dBX2RhdGEucmRhIikKIyBsb2FkIHRoZSBkb3dubG9hZGVkIGxhcmdlIGRhdGEgYW5kIHdvcmsgb24gUEMKbG9hZCgiL1VzZXJzL3poaXovVENHQV9kYXRhLnJkYSIpCmBgYApgYGAKICAgICAgICAgICAgICAgICAgIFRDR0EtQTctQTI2RS0wMUItMDZSLUEyNzctMDcgVENHQS1BMi1BMENVLTAxQS0xMlItQTAzNC0wNwpFTlNHMDAwMDAwMDAwMDMuMTUgICAgICAgICAgICAgICAgICAgICAgICAgIDY5MSAgICAgICAgICAgICAgICAgICAgICAgICAxNDI5CkVOU0cwMDAwMDAwMDAwNS42ICAgICAgICAgICAgICAgICAgICAgICAgICAgIDIwICAgICAgICAgICAgICAgICAgICAgICAgICAgNzMKRU5TRzAwMDAwMDAwNDE5LjEzICAgICAgICAgICAgICAgICAgICAgICAgICAzMzUgICAgICAgICAgICAgICAgICAgICAgICAgMTY3NApFTlNHMDAwMDAwMDA0NTcuMTQgICAgICAgICAgICAgICAgICAgICAgICAgMTI5MiAgICAgICAgICAgICAgICAgICAgICAgICAxMDE4CkVOU0cwMDAwMDAwMDQ2MC4xNyAgICAgICAgICAgICAgICAgICAgICAgICAgNTM2ICAgICAgICAgICAgICAgICAgICAgICAgICA0NTAKYGBgCgpJdCBpcyByZWNvbW1lbmRlZCB0byB1c2UgREVTZXEyIG9yIFRNTSBub3JtYWxpemF0aW9uIG1ldGhvZCBmb3IgUk5BLXNlcSBkYXRhIGJlZm9yZSBmdXJ0aGVyIHN0YXRpc3RpY2FsIGFuYWx5c2lzIFtAWmhhb1kyMDIxXS4KSGVyZSB3ZSBkZW1vbnN0cmF0ZSBob3cgdG8gdXNlIHRoZSBSL0Jpb2NvbmR1Y3RvciBwYWNrYWdlIFsqKkRFU2VxMioqXShodHRwczovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvREVTZXEyLykgW0BMb3ZlMjAxNF0gdG8gbm9ybWFsaXplIHRoZSBSTkEgY291bnQgZGF0YS4KCmBgYHtyfQptZXRhID0gY29sRGF0YShkYXQpWywgYygicHJvamVjdF9pZCIsICJzdWJtaXR0ZXJfaWQiLCAiYWdlX2F0X2RpYWdub3NpcyIsICAiZXRobmljaXR5IiwgImdlbmRlciIsICJkYXlzX3RvX2RlYXRoIiwgImRheXNfdG9fbGFzdF9mb2xsb3dfdXAiLCAidml0YWxfc3RhdHVzIiwgInBhcGVyX0JSQ0FfU3VidHlwZV9QQU01MCIsICJ0cmVhdG1lbnRzIildCm1ldGEkdHJlYXRtZW50cyA9IHVubGlzdChsYXBwbHkobWV0YSR0cmVhdG1lbnRzLCBmdW5jdGlvbih4eCkge2FueSh4eCR0cmVhdG1lbnRfb3JfdGhlcmFweSA9PSAieWVzIil9KSkKZGRzID0gREVTZXEyOjpERVNlcURhdGFTZXRGcm9tTWF0cml4KGFzc2F5cyhkYXQpJHVuc3RyYW5kZWQsIGNvbERhdGEgPSBtZXRhLCBkZXNpZ24gPSB+IDEpIApkZHMyID0gREVTZXEyOjplc3RpbWF0ZVNpemVGYWN0b3JzKGRkcykKUk5BX2NvdW50ID0gREVTZXEyOjpjb3VudHMoZGRzMiwgbm9ybWFsaXplZCA9IFRSVUUpClJOQV9jb3VudFsxOjUsIDE6Ml0KYGBgCgpgYGAKICAgICAgICAgICAgICAgICAgIFRDR0EtQTctQTI2RS0wMUItMDZSLUEyNzctMDcgVENHQS1BMi1BMENVLTAxQS0xMlItQTAzNC0wNwpFTlNHMDAwMDAwMDAwMDMuMTUgICAgICAgICAgICAgICAgICAgMTg5OS43Njg0OCAgICAgICAgICAgICAgICAgICAxNDE5LjUxNzg5CkVOU0cwMDAwMDAwMDAwNS42ICAgICAgICAgICAgICAgICAgICAgIDU0Ljk4NjA2ICAgICAgICAgICAgICAgICAgICAgNzIuNTE1NjEKRU5TRzAwMDAwMDAwNDE5LjEzICAgICAgICAgICAgICAgICAgICA5MjEuMDE2NTYgICAgICAgICAgICAgICAgICAgMTY2Mi44OTIxOQpFTlNHMDAwMDAwMDA0NTcuMTQgICAgICAgICAgICAgICAgICAgMzU1Mi4wOTk2OCAgICAgICAgICAgICAgICAgICAxMDExLjI0NTA3CkVOU0cwMDAwMDAwMDQ2MC4xNyAgICAgICAgICAgICAgICAgICAxNDczLjYyNjQ5ICAgICAgICAgICAgICAgICAgICA0NDcuMDE0MDMKYGBgCgpUbyBwZXJmb3JtIHN1cnZpdmFsIGFuYWx5c2lzIHdpdGggYm90aCBjbGluaWNhbC9kZW1vZ3JhcGhpYyB2YXJpYWJsZXMgYW5kIG9taWNzIGRhdGEsIGluIHRoZSBmb2xsb3dpbmcgY29kZSB3ZSBleHRyYWN0IGZlbWFsZSBicmVhc3QgY2FuY2VyIHBhdGllbnRzIHdpdGggdGhlaXIgY29ycmVzcG9uZGluZyBzdXJ2aXZhbCBvdXRjb21lcywgY2xpbmljYWwvZGVtb2dyYXBoaWMgdmFyaWFibGVzIGFuZCBSTkEtc2VxIGZlYXR1cmVzLgoKYGBge3J9Cm1ldGEkdGltZSA9IGFwcGx5KG1ldGFbLCBjKCJkYXlzX3RvX2RlYXRoIiwgImRheXNfdG9fbGFzdF9mb2xsb3dfdXAiKV0sIDEsIG1heCwgbmEucm0gPSBUUlVFKSAvIDM2NS4yNQptZXRhJHN0YXR1cyA9IG1ldGEkdml0YWxfc3RhdHVzCm1ldGEkYWdlID0gbWV0YSRhZ2VfYXRfZGlhZ25vc2lzIC8gMzY1LjI1CmNsaW4gPSBzdWJzZXQobWV0YSwgZ2VuZGVyID09ICJmZW1hbGUiICYgIWR1cGxpY2F0ZWQoc3VibWl0dGVyX2lkKSAmIHRpbWUgPiAwICYgIWlzLm5hKGFnZSkpCmNsaW4gPSBjbGluW29yZGVyKGNsaW4kc3VibWl0dGVyX2lkKSwgXQpSTkFfY291bnQgPSBSTkFfY291bnRbLCByb3duYW1lcyhjbGluKV0KYGBgCgo6Ojp7LmluZm8tYm94IC5ub3RlfQotIFtCaW9jb25kdWN0b3JdKGh0dHBzOi8vYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9yZWxlYXNlL2Jpb2MvaHRtbC9UQ0dBYmlvbGlua3MuaHRtbCkgbWlnaHQgcHJvdmlkZSBhbiBvbGQgcGFja2FnZSB2ZXJzaW9uIG9mICoqVENHQWJpb2xpbmtzKiogZm9yIExpbnV4IG1hY2hpbmVzLiAKSGVyZSwgd2UgdXNlIHRoZSB2ZXJzaW9uIFRDR0FiaW9saW5rc18yLjI5LjYuIApJZiB5b3UgZW5jb3VudGVyIHNvbWUgaXNzdWVzIHdoZW4gdXNpbmcgdGhpcyB0dXRvcmlhbCwgcGxlYXNlIGNoZWNrIHlvdXIgaW5zdGFsbGVkICoqVENHQWJpb2xpbmtzKiogdmVyc2lvbi4gCklmIG5lY2Vzc2FyeSwgeW91IGNhbiByZS1pbnN0YWxsIHRoZSBwYWNrYWdlIGZyb20gaXRzIFtHaXRIdWIgcmVwb3NpdG9yeV0oaHR0cHM6Ly9naXRodWIuY29tL0Jpb2luZm9ybWF0aWNzRk1SUC9UQ0dBYmlvbGlua3MuZ2l0KS4gCgotIFRoZSBwYWNrYWdlICoqVENHQWJpb2xpbmtzKiogY2Fubm90IHJldHJpZXZlIGFueSBwcm90ZW9taWNzIG9yIG1ldGFib2xvbWljcyBkYXRhLgpJdCBpcyBhbHdheXMgdXNlZnVsIHRvIGxvb2sgYXQgeW91ciBkYXRhIGZpcnN0LCBpbiBwYXJ0aWN1bGFyIHRoZSBkYXRhIHR5cGUgYW5kIGRpbWVuc2lvbnMgKGkuZS4gbnVtYmVycyBvZiByb3dzIGFuZCBjb2x1bW5zIGZvciBhIGRhdGEgZnJhbWUgb3IgbWF0cml4KS4KOjo6Cgo8YnI+CgojIFN1cnZpdmFsIGFuYWx5c2lzIHdpdGggbG93LWRpbWVuc2lvbmFsIGlucHV0IGRhdGEgey19CgojIyBOb25wYXJhbWV0cmljIHN1cnZpdmFsIGFuYWx5c2lzIHstfQoKRm9yIHRoZSBkYXRhIG9mIFRDR0EgYnJlYXN0IGNhbmNlciBwYXRpZW50cyB0aGF0IHdlIGV4dHJhY3RlZCBpbiB0aGUgcHJldmlvdXMgc2VjdGlvbiwgS2FwbGFuLU1laWVyIGVzdGltYXRlcyBvZiB0aGUgc3Vydml2YWwgcHJvYmFiaWxpdGllcyBjYW4gYmUgb2J0YWluZWQgdmlhIGZ1bmN0aW9uIGBzdXJ2Zml0KClgIGZyb20gWyoqc3Vydml2YWwqKl0oaHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT1zdXJ2aXZhbCkgcGFja2FnZS4KVGhlIGRhc2hlZCBsaW5lcyBpbiB0aGUgZm9sbG93aW5nIGZpZ3VyZSBpbmRpY2F0ZSB0aGUgbWVkaWFuIHN1cnZpdmFsIHRpbWUuCgpgYGB7cn0KIyBLYXBsYW4tTWVpZXIgKEtNKSBlc3RpbWF0aW9uCmNsaW4kc3RhdHVzW2NsaW4kc3RhdHVzID09ICJEZWFkIl0gPSAxCmNsaW4kc3RhdHVzW2NsaW4kc3RhdHVzID09ICJBbGl2ZSJdID0gMApjbGluJHN0YXR1cyA9IGFzLm51bWVyaWMoY2xpbiRzdGF0dXMpCnNmaXQgPSBzdXJ2aXZhbDo6c3VydmZpdChTdXJ2KHRpbWUsIHN0YXR1cykgfiAxLCBkYXRhID0gY2xpbikKCiMgY2FsY3VsYXRlIHN1cnZpdmFsIHByb2JhYmlsaXR5IGF0IDEtLCAzLSBhbmQgNS15ZWFyIHRpbWUgcG9pbnRzCnN1bW1hcnkoc2ZpdCwgdGltZXMgPSBjKDEsIDMsIDUpKQp0aGVtZV9zZXQodGhlbWVfYncoKSkKZ2dzdXJ2ID0gc3Vydm1pbmVyOjpnZ3N1cnZwbG90KHNmaXQsIGNvbmYuaW50ID0gVFJVRSwgcmlzay50YWJsZSA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeGxhYiA9ICJUaW1lIHNpbmNlIGRpYWdub3NpcyAoeWVhcikiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kID0gIm5vbmUiLCBzdXJ2Lm1lZGlhbi5saW5lID0gImh2IikKZ2dzdXJ2JHBsb3QgPSBnZ3N1cnYkcGxvdCArIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDIwLCB5ID0gMC45LCBsYWJlbCA9ICIrICBDZW5zb3IiKQpnZ3N1cnYKYGBgCmBgYHtyLCBlY2hvPUZBTFNFfQpwZGYoIlRDR0Ffc3Vydl9rbTEucGRmIiwgd2lkdGggPSA1LCBoZWlnaHQgPSA1KQpnZ3N1cnYKZGV2Lm9mZigpCmBgYAohW19LYXBsYW4tTWVpZXIgY3VydmUgZm9yIDEwNjEgQlJDQSBwYXRpZW50cyBkYXRhIGZyb20gVENHQS5fXShmaWcvVENHQV9zdXJ2X2ttMS5wbmcpe3dpZHRoPTYwJX0KCjxicj4KClRvIGNvbXBhcmUgdGhlIHN1cnZpdmFsIGN1cnZlcyBvZiB0d28gZ3JvdXBzIG9mIHBhdGllbnRzLCBmb3IgZXhhbXBsZSwgdHJlYXRtZW50IChpLmUuIHBoYXJtYWNldXRpY2FsIG9yIHJhZGlhdGlvbiB0aGVyYXB5KSBvciBub250cmVhdG1lbnQsIHRoZSBgUmAgZnVuY3Rpb24gYHN1cnZpdmFsOjpzdXJ2ZGlmZigpYCBjYW4gcGVyZm9ybSB0aGUgbG9nLXJhbmsgdGVzdCB0byBjb21wYXJlIHR3byBzdXJ2aXZhbCBjdXJ2ZXMuCkFsdGVybmF0aXZlbHksIHRoZSBgUmAgZnVuY3Rpb24gYHN1cnZpdmFsOjpzdXJ2Zml0YCB3aXRoIGEgZm9ybXVsYSBpbmNsdWRpbmcgdGhlIHRyZWF0bWVudCBncm91cCBhcyBhIGNvdmFyaWF0ZSBjYW4gcmV0dXJuIHRoZSAoS00pIHN1cnZpdmFsIHByb2JhYmlsaXRpZXMgZm9yIGVhY2ggZ3JvdXBzLiAKVGhlbiB0aGUgYFJgIGZ1bmN0aW9uIGBzdXJ2bWluZXI6Omdnc3VydnBsb3QoKWAgd2l0aCBhIGBzdXJ2Zml0YCBvYmplY3Qgd2lsbCBkcmF3IHRoZSB0d28gc3Vydml2YWwgY3VydmVzIGFuZCBwZXJmb3JtIHRoZSBsb2ctcmFuayB0ZXN0IGFzIHNob3duIGluIHRoZSBmb2xsb3dpbmcgZmlndXJlLgoKYGBge3J9CnN1cnZpdmFsOjpzdXJ2ZGlmZihTdXJ2KHRpbWUsIHN0YXR1cykgfiB0cmVhdG1lbnRzLCBkYXRhID0gY2xpbikKCnNmaXQyID0gc3VydmZpdChTdXJ2KHRpbWUsIHN0YXR1cykgfiB0cmVhdG1lbnRzLCBkYXRhID0gY2xpbikKZ2dzdXJ2ID0gZ2dzdXJ2cGxvdChzZml0MiwgY29uZi5pbnQgPSBUUlVFLCByaXNrLnRhYmxlID0gVFJVRSwgCiAgICAgICAgICAgeGxhYiA9ICJUaW1lIHNpbmNlIGRpYWdub3NpcyAoeWVhcikiLCBsZWdlbmQgPSBjKC42LCAuOSksCiAgICAgICAgICAgbGVnZW5kLmxhYnMgPSBjKCJObyIsICJZZXMiKSwgbGVnZW5kLnRpdGxlID0gIlRyZWF0bWVudCIsICAKICAgICAgICAgICByaXNrLnRhYmxlLnkudGV4dC5jb2wgPSBUUlVFLCByaXNrLnRhYmxlLnkudGV4dCA9IEZBTFNFKQpnZ3N1cnYkcGxvdCA9IGdnc3VydiRwbG90ICsgCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMjEsIHkgPSAxLCBsYWJlbCA9ICIrICBDZW5zb3IiKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMjIsIHkgPSAuODgsIGxhYmVsID0gcGFzdGUwKCJMb2ctcmFuayB0ZXN0OlxuIiwgc3Vydl9wdmFsdWUoc2ZpdDIpJHB2YWwudHh0KSkKZ2dzdXJ2CmBgYApgYGB7ciwgZWNobz1GQUxTRX0KcGRmKCJUQ0dBX3N1cnZfa20yLnBkZiIsIHdpZHRoID0gNSwgaGVpZ2h0ID0gNSkKZ2dzdXJ2CmRldi5vZmYoKQpgYGAKIVtfS2FwbGFuLU1laWVyIGN1cnZlcyBvZiB0aGUgQlJDQSBwYXRpZW50cycgc3Vydml2YWwgZGF0YSBmcm9tIFRDR0EgZ3JvdXBlZCBieSB0cmVhdG1lbnQgKGkuZS4gcGhhcm1hY2V1dGljYWwgb3IgcmFkaWF0aW9uIHRoZXJhcHkpIG9yIG5vbnRyZWF0bWVudC4gVGhlIGxvZy1yYW5rIHRlc3QgaXMgdG8gY29tcGFyZSB0aGUgdHdvIHN1cnZpdmFsIGRpc3RyaWJ1dGlvbnMgY29ycmVzcG9uZGluZyB0byB0aGUgdHdvIGdyb3VwcyBvZiBwYXRpZW50cy5fXShmaWcvVENHQV9zdXJ2X2ttMi5wbmcpe3dpZHRoPTYwJX0KCjxicj4KClRvIGFuYWx5emUgaWYgYSBjb250aW51b3VzIHZhcmlhYmxlLCBlLmcuIGFnZSwgaXMgYXNzb2NpYXRlZCB3aXRoIHRoZSBzdXJ2aXZhbCBvdXRjb21lcywgd2UgY2FuIHVzZSB0aGUgYFJgIGZ1bmN0aW9uIGBjb3hwaCgpYCBmb3IgZml0dGluZyBhIENveCBtb2RlbCwgd2hpY2ggaXMgc2ltaWxhciB0byB0aGUgZnVuY3Rpb24gYGxtKClgIGZvciBmaXR0aW5nIGxpbmVhciBtb2RlbHMuCgpgYGB7cn0KZml0X2NveCA9IGNveHBoKFN1cnYodGltZSwgc3RhdHVzKSB+IGFnZSwgZGF0YSA9IGNsaW4pCnN1bW1hcnkoZml0X2NveCkKYGBgCmBgYApDYWxsOgpjb3hwaChmb3JtdWxhID0gU3Vydih0aW1lLCBzdGF0dXMpIH4gYWdlLCBkYXRhID0gY2xpbikKCiAgbj0gMTA0NywgbnVtYmVyIG9mIGV2ZW50cz0gMTQ5IAogICAoMTQgb2JzZXJ2YXRpb25zIGRlbGV0ZWQgZHVlIHRvIG1pc3NpbmduZXNzKQoKICAgICAgICBjb2VmIGV4cChjb2VmKSBzZShjb2VmKSAgICAgeiBQcig+fHp8KSAgICAKYWdlIDAuMDM0MjQ0ICAxLjAzNDgzNyAwLjAwNjcwMyA1LjEwOSAzLjI0ZS0wNyAqKioKLS0tClNpZ25pZi4gY29kZXM6ICAwIOKAmCoqKuKAmSAwLjAwMSDigJgqKuKAmSAwLjAxIOKAmCrigJkgMC4wNSDigJgu4oCZIDAuMSDigJgg4oCZIDEKCiAgICBleHAoY29lZikgZXhwKC1jb2VmKSBsb3dlciAuOTUgdXBwZXIgLjk1CmFnZSAgICAgMS4wMzUgICAgIDAuOTY2MyAgICAgMS4wMjEgICAgIDEuMDQ5CgpDb25jb3JkYW5jZT0gMC42MzkgIChzZSA9IDAuMDI5ICkKTGlrZWxpaG9vZCByYXRpbyB0ZXN0PSAyNi4zNCAgb24gMSBkZiwgICBwPTNlLTA3CldhbGQgdGVzdCAgICAgICAgICAgID0gMjYuMSAgb24gMSBkZiwgICBwPTNlLTA3ClNjb3JlIChsb2dyYW5rKSB0ZXN0ID0gMjYuNjMgIG9uIDEgZGYsICAgcD0yZS0wNwpgYGAKClRoZSBDb3ggbW9kZWwgYXNzdW1lcyBwcm9wb3J0aW9uYWwgaGF6YXJkcyBhbmQgbG9nLWxpbmVhcml0eSBvZiB0aGUgY292YXJpYXRlcy4KVG8gY2hlY2sgdGhlIGxvZy1saW5lYXJpdHkgZm9yIGEgY2xpbmljYWwgb3IgZGVtb2dyYXBoaWMgdmFyaWFibGUsIGUuZy4gYWdlLCB3ZSBjYW4gZml0IGEgcGVuYWxpemVkIHNtb290aGluZyBzcGxpbmUgZm9yIGFnZSBlZmZlY3QuClRoZSBmb2xsb3dpbmcgY29kZSBzaG93cyB0aGF0IHRoZSBub25saW5lYXIgcGFydCBvZiB0aGUgc21vb3RoaW5nIHNwbGluZSBoYXMgYSBzaWduaWZpY2FudCBlZmZlY3QgKCRwID0gMC4wMDAxMyQpLgpUaHVzLCB0aGUgYXNzdW1wdGlvbiBvZiBsb2ctbGluZWFyaXR5IGZvciBhZ2UgaXMgbm90IHNhdGlzZmllZC4KCmBgYHtyfQpmaXRfY294X3NwbGluZSA9IGNveHBoKFN1cnYodGltZSwgc3RhdHVzKSB+IHBzcGxpbmUoYWdlKSwgZGF0YSA9IGNsaW4pCmZpdF9jb3hfc3BsaW5lCmBgYApgYGAKQ2FsbDoKY294cGgoZm9ybXVsYSA9IFN1cnYodGltZSwgc3RhdHVzKSB+IHBzcGxpbmUoYWdlKSwgZGF0YSA9IGNsaW4pCgogICAgICAgICAgICAgICAgICAgICAgICAgY29lZiBzZShjb2VmKSAgICAgIHNlMiAgICBDaGlzcSAgIERGICAgICAgIHAKcHNwbGluZShhZ2UpLCBsaW5lYXIgIDAuMDM1MDkgIDAuMDA1NzcgIDAuMDA1NzcgMzYuOTgzMjMgMS4wMCAxLjJlLTA5CnBzcGxpbmUoYWdlKSwgbm9ubGluICAgICAgICAgICAgICAgICAgICAgICAgICAgIDIwLjY5MTQ2IDMuMDMgMC4wMDAxMwoKSXRlcmF0aW9uczogNSBvdXRlciwgMTUgTmV3dG9uLVJhcGhzb24KICAgICBUaGV0YT0gMC44MjggCkRlZ3JlZXMgb2YgZnJlZWRvbSBmb3IgdGVybXM9IDQgCkxpa2VsaWhvb2QgcmF0aW8gdGVzdD00Ni40ICBvbiA0LjAzIGRmLCBwPTJlLTA5Cm49IDEwNDcsIG51bWJlciBvZiBldmVudHM9IDE0OSAKYGBgCgpUbyBjaGVjayBwcm9wb3J0aW9uYWwgaGF6YXJkcyBvZiBhZ2UsIHdlIGNhbiBhZGQgYSB0aW1lLWRlcGVuZGVudCBjb3ZhcmlhdGUgJGFnZSBcdGltZXMgZyh0KSQsIHdoZXJlICRnKHQpJCBpcyBhIGtub3duIGZ1bmN0aW9uIGUuZy4gJGcodCkgPSBcbG9nIHQkLgpUaGUgZm9sbG93aW5nIGNvZGUgc2hvd3MgdGhhdCB0aGUgdGltZS1kZXBlbmRlbnQgYWdlIGlzIHNpZ25pZmljYW50IHVzaW5nIGEgc2NvcmUgdGVzdCAoJHAgPSAwLjAwODckKS4KVGh1cywgdGhlIGFzc3VtcHRpb24gb2YgcHJvcG9ydGlvbmFsIGhhemFyZHMgZm9yIGFnZSBpcyBub3Qgc2F0aXNmaWVkLiBUaGUgYWJvdmUgdHdvIHRlc3RzIGluZGljYXRlIGEgbm9uLWxvZ2xpbmVhciBvciB0aW1lLWRlcGVuZGVudCBhc3NvY2lhdGlvbiBvZiBhZ2Ugd2l0aCB0aGUgc3Vydml2YWwgb3V0Y29tZXMuCgpgYGB7cn0Kc3Vydml2YWw6OmNveC56cGgoZml0X2NveCwgdHJhbnNmb3JtID0gImxvZyIpIApgYGAKYGBgCiAgICAgICBjaGlzcSBkZiAgICBwCmFnZSAgICAgNi44OCAgMSAwLjAwODcKR0xPQkFMICA2Ljg4ICAxIDAuMDA4NwpgYGAKOjo6ey5pbmZvLWJveCAubm90ZX0KSGVyZSB0aGUgYXBwcm9hY2hlcyBmb3IgY2hlY2tpbmcgbG9nLWxpbmVhcml0eSBvciBwcm9wb3J0aW9uYWwgaGF6YXJkcyBjYW4gb25seSBiZSB1c2VkIGluIGxvdy1kaW1lbnNpb25hbCBkYXRhIHNldHRpbmdzLgpXaGVuIGluY2x1ZGluZyBoaWdoLWRpbWVuc2lvbmFsIG9taWNzIGRhdGEsIHRoZXJlIGFyZSBubyBzdGFuZGFyZCBhcHByb2FjaGVzIGZvciBjaGVja2luZyBsb2ctbGluZWFyaXR5IG9yIHByb3BvcnRpb25hbCBoYXphcmRzIGN1cnJlbnRseS4KOjo6Cgo8YnI+CgojIyBGZWF0dXJlIHByZXNlbGVjdGlvbi9maWx0ZXJpbmcgey19CgpGcm9tIGEgcHJhY3RpY2FsIHBvaW50IG9mIHZpZXcsIHNpbmNlIG1vc3Qgb21pY3MgcHJvZmlsZXMgY29udGFpbiB0aG91c2FuZHMgb2YgdmFyaWFibGVzIGFuZCBtb3N0IHN1cGVydmlzZWQgc3RhdGlzdGljYWwgbWV0aG9kcyBhcmUgbm90IHN1aXRlZCBmb3IgaGlnaCBkaW1lbnNpb25hbCBvbWljcyBmZWF0dXJlcywgaXQgaXMgYmV0dGVyIHRvIGZpbHRlciB0aGUgb21pY3MgZmVhdHVyZXMgZmlyc3QuCkluIGFkZGl0aW9uLCB3ZSBwZXJjZWl2ZSB0aGF0IG5vdCB0b28gbWFueSBvbWljcyBmZWF0dXJlcyBhcmUgcmVsZXZhbnQgdG8gb25lIG1lZGljYWwgcHJvYmxlbS4KV2Ugd2lsbCBkZW1vbnN0cmF0ZSAqKnRocmVlIGRpZmZlcmVudCBmaWx0ZXJpbmcgYXBwcm9hY2hlcyBmb3IgaGlnaC1kaW1lbnNpb25hbCBvbWljcyBkYXRhKio6CgotIEtub3dsZWRnZS1iYXNlZCBmaWx0ZXJpbmcKLSBQLXZhbHVlLWJhc2VkIGZpbHRlcmluZwotIFZhcmlhbmNlLWJhc2VkIGZpbHRlcmluZwoKIyMjIEtub3dsZWRnZSBmaWx0ZXIgey19CgpPbmUgY2FuIGJlIGludGVyZXN0ZWQgaW4gb25seSBzb21lIGJpb2xvZ2ljYWxseSBtZWFuaW5nZnVsIGdlbmVzIG9yIG9ubHkgcHJvdGVpbi1jb2RpbmcgZ2VuZXMgaW4gYSBzcGVjaWZpYyBzdHVkeS4gCkZvciBleGFtcGxlLCB0aGUgY29kZSBiZWxvdyBmaWx0ZXJzIHByb3RlaW4tY29kaW5nIGdlbmVzLiAKCmBgYHtyfQpmaWx0ZXJlZF9ybmEgPSBSTkFfY291bnRbcm93RGF0YShkYXQpJGdlbmVfdHlwZSA9PSAicHJvdGVpbl9jb2RpbmciLCBdCmBgYAoKIyMjIFAtdmFsdWUgZmlsdGVyIHstfQoKQmVmb3JlIGpvaW50IGFuYWx5emluZyB0aGUgYXNzb2NpYXRpb25zIGJldHdlZW4gdGhlIHRob3VzYW5kcyBvZiBvbWljcyBmZWF0dXJlcyBhbmQgc3Vydml2YWwgb3V0Y29tZXMsIG9uZSBjYW4gYW5hbHl6ZSB0aGUgYXNzb2NpYXRpb24gYmV0d2VlbiBlYWNoIG9taWNzIGZlYXR1cmUgYW5kIHRoZSBzdXJ2aXZhbCBvdXRjb21lcywgYW5kIGZpbHRlciBvbWljcyBmZWF0dXJlcyBhdCBhIHN0YXRpc3RpY2FsIHNpZ25pZmljYW5jZSBsZXZlbCAkMC4xJCBvciAkMC4yJCAobGFyZ2VyIHRoYW4gMC4wNSB0byByZWR1Y2UgZmFsc2UgbmVnYXRpdmUgaWRlbnRpZmljYXRpb24gb2Ygb21pY3MgZmVhdHVyZXMgaW4gbXVsdGl2YXJpYXRlIGFuYWx5c2lzKS4KRm9yIGRlbW9uc3RyYXRpb24sIGJhc2VkIG9uIHRoZSAkMTAwJCBtUk5BLVNlcSBmZWF0dXJlcyBmcm9tIFRDR0EgYnJlYXN0IGNhbmNlciBwYXRpZW50cyBwcmVwcm9jZXNzZWQgcHJldmlvdXNseSwgdGhlIGNvZGUgYmVsb3cgZmlsdGVycyBvbWljcyBmZWF0dXJlcyBhdCB0aGUgc3RhdGlzdGljYWwgc2lnbmlmaWNhbmNlIGxldmVsICQwLjIkLCBpLmUuICRwIDwgMC4yJC4KCmBgYHtyfQpSTkFfbG9nMmNvdW50ID0gbG9nMihSTkFfY291bnRbMToxMDAsIF0gKyAxKQpwdmFsdWVzID0gcmVwKE5BLCBucm93KFJOQV9sb2cyY291bnQpKQpmb3IgKGogaW4gMTpucm93KFJOQV9sb2cyY291bnQpKSB7CiAgZml0X2NveCA9IGNveHBoKFN1cnYoY2xpbiR0aW1lLCBjbGluJHN0YXR1cykgfiBSTkFfbG9nMmNvdW50W2osIF0sIGRhdGEgPSBjbGluKQogIHB2YWx1ZXNbal0gPSBzdW1tYXJ5KGZpdF9jb3gpJGNvZWZmaWNpZW50c1ssICJQcig+fHp8KSJdCn0KZmlsdGVyZWRfcm5hID0gUk5BX2xvZzJjb3VudFt3aGljaChwdmFsdWVzIDwgMC4yKSwgXQpgYGAKCiMjIyBWYXJpYW5jZSBmaWx0ZXIgey19CgpUaGUgb3RoZXIgY29tbW9uIGFuZCBlYXN5IHdheSB0byBkZWNyZWFzZSB0aGUgbnVtYmVyIG9mIG9taWNzIGZlYXR1cmVzIGlzIHRvIGZpbHRlciB0aGUgbW9zdCB2YXJpYWJsZSBvbmVzIGZvciBmdXJ0aGVyIGFuYWx5c2lzLgpOb3RlIHRoYXQgdGhlIHZhcmlhbmNlLWJhc2VkIGZpbHRlcmluZyBzdGVwIHNob3VsZCBiZSBkb25lIGJlZm9yZSBkYXRhIHN0YW5kYXJkaXphdGlvbiAoaS5lLiBjYWxjdWxhdGluZyAkeiQtc2NvcmUpLCBidXQgY2FuIGJlIHBlcmZvcm1lZCBhZnRlciBjb3VudCBkYXRhIG5vcm1hbGl6YXRpb24gYW5kIGxvZzItdHJhbnNmb3JtYXRpb24gZm9yIGluc3RhbmNlLgoKVGhlIGBSYCBwYWNrYWdlIFsqKk0zQyoqXShodHRwczovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvTTNDLykgW0BKb2huMjAyMF0gcHJvdmlkZXMgYSBmaWx0ZXIgZnVuY3Rpb24gYGZlYXR1cmVmaWx0ZXIoKWAgYnkgdXNpbmcgZGlmZmVyZW50IHZhcmlhbmNlLXR5cGUgbWV0cmljcywgZm9yIGV4YW1wbGUsIHZhcmlhbmNlLCBtZWRpYW4gYWJzb2x1dGUgZGV2aWF0aW9uIChNQUQpLCBjb2VmZmljaWVudCBvZiB2YXJpYXRpb24gKEEpIGFuZCBpdHMgc2Vjb25kIG9yZGVyIGRlcml2YXRpdmUgKEEyKS4KVGhlIHNpbXBsZSB2YXJpYW5jZSBmaWx0ZXIgY2FuIGJlIHVzZWQgaWYgdGhlIHZhcmlhbmNlIGRvZXMgbm90IGNoYW5nZSB3aXRoIHRoZSBjb3JyZXNwb25kaW5nIG1lYW4sIG90aGVyd2lzZSB0aGUgY29lZmZpY2llbnQgb2YgdmFyaWF0aW9uIGNhbiBiZSB1c2VkLgpJZiB0aGUgb21pY3MgZGF0YSBpbmNsdWRlIG91dGxpZXJzLCBNQUQgZmlsdGVyIGlzIG1vcmUgcm9idXN0IHRoYW4gdGhlIHZhcmlhbmNlIGZpbHRlci4KQmFzZWQgb24gdGhlICQ2MDY2MCQgbVJOQS1TZXEgZmVhdHVyZXMgZnJvbSBUQ0dBIGJyZWFzdCBjYW5jZXIgcGF0aWVudHMgcHJlcHJvY2Vzc2VkIHByZXZpb3VzbHksIHRoZSBjb2RlIGJlbG93IGV4dHJhY3RzIHRoZSAkMVwlJCBtb3N0IHZhcmlhYmxlIGZlYXR1cmVzIHVzaW5nIHZhcmlhbmNlIGFzIGEgZmlsdGVyaW5nIG1ldHJpYy4KCmBgYHtyfQpSTkFfbG9nMmNvdW50ID0gbG9nMihSTkFfY291bnQgKyAxKQpmaWx0ZXJlZCA9IE0zQzo6ZmVhdHVyZWZpbHRlcihSTkFfbG9nMmNvdW50LCBwZXJjZW50aWxlID0gMSwgbWV0aG9kID0gJ3ZhcicsIHRvcE4gPSA1KQpmaWx0ZXJlZF9ybmExID0gZmlsdGVyZWQkZmlsdGVyZWRfZGF0YQpgYGAKYGBgCioqKmZlYXR1cmUgZmlsdGVyIGZ1bmN0aW9uKioqCmV4dHJhY3RpbmcgdGhlIG1vc3QgdmFyaWFibGU6IDEgcGVyY2VudApmZWF0dXJlcyB0byBzdGFydCB3aXRoOiA2MDY2MApwZXJmb3JtaW5nIGNhbGN1bGF0aW9ucyBmb3IgdmFyaWFuY2UKcHJpbnRpbmcgdG9wTiBtb3N0IHZhcmlhYmxlIGZlYXR1cmVzIHdpdGggc3RhdGlzdGljcy4uLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmZWF0dXJlICAgICAgbWVhbiAgICAgIHZhciAgICAgICBzZApFTlNHMDAwMDAxNjY1MDkuMTIgRU5TRzAwMDAwMTY2NTA5LjEyICA2LjA4NjEyNSAzMS42MDM4NCA1LjYyMTcyOQpFTlNHMDAwMDAxMTA0ODQuNyAgIEVOU0cwMDAwMDExMDQ4NC43IDExLjAwNTEzNiAyNi4xMzc1NSA1LjExMjQ4OQpFTlNHMDAwMDAxNTMwMDIuMTIgRU5TRzAwMDAwMTUzMDAyLjEyICA4LjIxMjg5NSAyNS44OTEwNSA1LjA4ODMyNQpFTlNHMDAwMDAxMzQxODQuMTMgRU5TRzAwMDAwMTM0MTg0LjEzICA1LjM3MTQzNSAyMy4yMzUxMSA0LjgyMDI4MQpFTlNHMDAwMDAxNjAxODIuMyAgIEVOU0cwMDAwMDE2MDE4Mi4zICA5LjkwMjE5NSAyMS40MTQwNyA0LjYyNzUzNApmZWF0dXJlcyByZW1haW5pbmc6IDYwNwpgYGAKCkFub3RoZXIgdmFyaWFuY2UtdHlwZSBmaWx0ZXIgaXMgdG8gcmVtYWluIGZlYXR1cmVzIHdpdGggY2VydGFpbiBwZXJjZW50YWdlIG9mICoqY3VtdWxhdGl2ZSB2YXJpYW5jZXMqKiwgd2hpY2ggd2lsbCB1c3VhbGx5IGZpbHRlciBmZXdlciBmZWF0dXJlcyB0aGFuIHRoZSBhcHByb2FjaGVzIGFib3ZlLgpUaGUgY29kZSBiZWxvdyBleHRyYWN0cyB0aGUgbW9zdCB2YXJpYWJsZSBmZWF0dXJlcyBleHBsYWluaW5nICQxXCUkICoqY3VtdWxhdGl2ZSB2YXJpYW5jZXMqKi4KCmBgYHtyfQpjdW1zdW1fdmFyID0gY3Vtc3VtKGZpbHRlcmVkJHN0YXRpc3RpY3MkdmFyKQpjdW1zdW1fY3V0b2ZmID0gY3Vtc3VtX3ZhcltsZW5ndGgoY3Vtc3VtX3ZhcildICogMC4wMQpmaWx0ZXJlZF9uYW1lcyA9IGZpbHRlcmVkJHN0YXRpc3RpY3MkZmVhdHVyZVtjdW1zdW1fdmFyIDwgY3Vtc3VtX2N1dG9mZl0KYGBgCgo8YnI+CgojIFN1cnZpdmFsIGFuYWx5c2lzIHdpdGggaGlnaC1kaW1lbnNpb25hbCBpbnB1dCBkYXRhIHstfQoKIyMgVW5zdXBlcnZpc2VkIGxlYXJuaW5nIChvbWljcyBkYXRhKSB7LX0KCkluIHRoaXMgc2VjdGlvbiB3ZSB3aWxsIHVzZSB0aGUgbVJOQS1TZXEgZGF0YSBvZiBicmVhc3QgY2FuY2VyIHBhdGllbnRzIGZyb20gVENHQS4KVGhlIGZvbGxvd2luZyB1bnN1cGVydmlzZWQgbWV0aG9kcyBjYW4gYmUgYXBwbGllZCB0byBvdGhlciBvbWljcyBkYXRhIGFzIHdlbGwgKHRoZSBzYW1lIGFwcGxpZXMgdG8gdGhlIHN1cGVydmlzZWQgbGVhcm5pbmcgbWV0aG9kcykuCk9uZSBpbXBvcnRhbnQgdGhpbmcgaXMgdGhhdCB0aGUgaW5wdXQgb21pY3MgZGF0YSwgZXNwZWNpYWxseSB0aGUgZGF0YSB0eXBlIGFuZCBkaW1lbnNpb25zLCBzaG91bGQgYmUgc3VpdGVkIHRvIHRoZSBtZXRob2RzLgoKVW5zdXBlcnZpc2VkIGxlYXJuaW5nIGZvciBvbWljcyBkYXRhIGNhbiBiZSBoZWxwZnVsIHRvIGV4cGxvcmUgc3VicG9wdWxhdGlvbnMgb2YgdGhlIGRhdGEsIGZvciBleGFtcGxlLCBwYXRpZW50cyBmcm9tIG9uZSBjYW5jZXIgdHlwZSBjYW4gYmUgZGl2aWRlZCB0byBzZXZlcmFsIG9taWNzLXJlbGF0ZWQgc3VidHlwZXMuCldlIGRlbW9uc3RyYXRlIHRocmVlIHVuc3VwZXJ2aXNlZCBsZWFybmluZyBtZXRob2RzLCBpLmUuIHByaW5jaXBhbCBjb21wb25lbnQgYW5hbHlzaXMgKFBDQSksICR0JC1zdG9jaGFzdGljIG5laWdoYm91ciBlbWJlZGRpbmcgKCR0JC1TTkUpIGFuZCB1bmlmb3JtIG1hbmlmb2xkIGFwcHJveGltYXRpb24gYW5kIHByb2plY3Rpb24gKFVNQVApLCBiYXNlZCBvbiB0aGUgUEFNNTAgZ2VuZXMgW0BQYXJrZXIyMDA5XS4KVGhlIGBSYCBwYWNrYWdlIFsqKk0zQyoqXShodHRwczovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvTTNDLykgW0BKb2huMjAyMF0gcHJvdmlkZXMgdGhlIGFuYWx5c2VzIGFuZCB2aXN1YWxpemF0aW9uIG9mIGFsbCB0aGUgdGhyZWUgbWV0aG9kcy4KCmBgYHtyfQojIGlkZW50aWZ5IGluZGV4ZXMgb2YgdGhlIFBBTTUwIGdlbmVzIGluIHRoZSBUQ0dBLUJSQ0EgZGF0YQppZHggPSB3aGljaChyb3dEYXRhKGRhdCkkZ2VuZV9uYW1lICVpbiUgCiAgICAgICAgICAgICAgYygiVUJFMlQiLCAiQklSQzUiLCAiTlVGMiIsICJDREM2IiwgIkNDTkIxIiwgIlRZTVMiLCAiTVlCTDIiLCAiQ0VQNTUiLCAiTUVMSyIsICJOREM4MCIsICJSUk0yIiwgIlVCRTJDIiwgIkNFTlBGIiwgIlBUVEcxIiwgIkVYTzEiLCAiT1JDNiIsICJBTkxOIiwgIkNDTkUxIiwgIkNEQzIwIiwgIk1LSTY3IiwgIktJRjJDIiwgIkFDVFIzQiIsICJNWUMiLCAiRUdGUiIsICJLUlQ1IiwgIlBIR0RIIiwgIkNESDMiLCAiTUlBIiwgIktSVDE3IiwgIkZPWEMxIiwgIlNGUlAxIiwgIktSVDE0IiwgIkVTUjEiLCAiU0xDMzlBNiIsICJCQUcxIiwgIk1BUFQiLCAiUEdSIiwgIkNYWEM1IiwgIk1MUEgiLCAiQkNMMiIsICJNRE0yIiwgIk5BVDEiLCAiRk9YQTEiLCAiQkxWUkEiLCAiTU1QMTEiLCAiR1BSMTYwIiwgIkZHRlI0IiwgIkdSQjciLCAiVE1FTTQ1QiIsICJFUkJCMiIpKQojIGV4dHJhY3QgdGhlIFBBTTUwIGdlbmVzIG9mIFRDR0EtQlJDQSBwYXRpZW50cwpUQ0dBX1BBTTUwID0gUk5BX2NvdW50W2lkeCwgXQojIHVzZSBnZW5lIHN5bWJvbHMgaW5zdGVhZCBvZiBFbnNlbWJsIElEcwpyb3duYW1lcyhUQ0dBX1BBTTUwKSA9IHJvd0RhdGEoZGF0KSRnZW5lX25hbWVbaWR4XQoKIyBsb2cyLXRyYW5zZm9ybWF0aW9uIG9mIHRoZSBub3JtYWxpemVkIGNvdW50IGRhdGEKVENHQV9QQU01MCA9IGxvZzIoVENHQV9QQU01MCArIDEpCnBhbTUwID0gZmFjdG9yKGNsaW4kcGFwZXJfQlJDQV9TdWJ0eXBlX1BBTTUwKQoKTTNDOjpwY2EoVENHQV9QQU01MCwgbGFiZWxzID0gcGFtNTAsIGRvdHNpemUgPSAzLCAgbGVnZW5kdGl0bGUgPSAiU3VidHlwZSIpCmBgYAohW19VbnN1cGVydmlzZWQgY2x1c3RlcmluZyAocHJpbmNpcGFsIGNvbXBvbmVudCBhbmFseXNpcywgUENBKSBvZiB0cmFuc2NyaXB0b21pYyBkYXRhIGZyb20gVENHQSBicmVhc3QgY2FuY2VyIHBhdGllbnRzX10oZmlnL1RDR0FfcGNhLnBuZyl7d2lkdGg9NTAlfQoKYGBge3J9Ck0zQzo6dHNuZShUQ0dBX1BBTTUwLCBsYWJlbHMgPSBwYW01MCwgZG90c2l6ZSA9IDMsICBsZWdlbmR0aXRsZSA9ICJTdWJ0eXBlIikKYGBgCiFbX1Vuc3VwZXJ2aXNlZCBjbHVzdGVyaW5nICgkdCQtc3RvY2hhc3RpYyBuZWlnaGJvdXIgZW1iZWRkaW5nLCAkdCQtU05FKSBvZiB0cmFuc2NyaXB0b21pYyBkYXRhIGZyb20gVENHQSBicmVhc3QgY2FuY2VyIHBhdGllbnRzX10oZmlnL1RDR0FfdHNuZS5wbmcpe3dpZHRoPTUwJX0KCmBgYHtyfQpNM0M6OnVtYXAoVENHQV9QQU01MCwgbGFiZWxzID0gcGFtNTAsIGRvdHNpemUgPSAzLCAgbGVnZW5kdGl0bGUgPSAiU3VidHlwZSIpCmBgYAohW19VbnN1cGVydmlzZWQgY2x1c3RlcmluZyAodW5pZm9ybSBtYW5pZm9sZCBhcHByb3hpbWF0aW9uIGFuZCBwcm9qZWN0aW9uLCBVTUFQKSBvZiB0cmFuc2NyaXB0b21pYyBkYXRhIGZyb20gVENHQSBicmVhc3QgY2FuY2VyIHBhdGllbnRzX10oZmlnL1RDR0FfdW1hcC5wbmcpe3dpZHRoPTUwJX0KCjxicj4KCiMjIFN1cGVydmlzZWQgbGVhcm5pbmcgKG9taWNzIGFuZCBzdXJ2aXZhbCBkYXRhKSB7LX0KClRvIGludmVzdGlnYXRlIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBvbWljcyBmZWF0dXJlcyBhbmQgc3Vydml2YWwgb3V0Y29tZXMsIHJlZ3Jlc3Npb24gbWV0aG9kcyAoaS5lLiBzdXBlcnZpc2VkIGxlYXJuaW5nKSBjYW4gYmUgYXBwbGllZC4gClNpbmNlIG9taWNzIGRhdGEgYXJlIGhpZ2gtZGltZW5zaW9uYWwsIG9uZSBjYW4gdXNlIHVuc3VwZXJ2aXNlZCBsZWFybmluZyBtZXRob2RzIHRvIHN1bW1hcml6ZSBhIGZldyBjb21wb25lbnRzIChkaW1lbnNpb24gcmVkdWN0aW9uKSBhbmQgcmVncmVzcyB0aGUgc3Vydml2YWwgb3V0Y29tZXMgb24gdGhlIGxvdy1kaW1lbnNpb25hbCBjb21wb25lbnRzIGJ5IHNvbWUgY2xhc3NpY2FsIHN0YXRpc3RpY2FsIG1ldGhvZHMsIGUuZy4gY2xhc3NpY2FsIENveCBtb2RlbC4KVGhlcmUgYXJlIGFsc28gZnJlcXVlbnRpc3QgYW5kIEJheWVzaWFuIHN1cGVydmlzZWQgbGVhcm5pbmcgbWV0aG9kcyBzdWl0ZWQgdG8gZGlyZWN0bHkgcmVncmVzcyB0aGUgc3Vydml2YWwgb3V0Y29tZXMgb24gdGhlIGhpZ2gtZGltZW5zaW9uYWwgb21pY3MgZmVhdHVyZXMuCk5vdGUgdGhhdCBwcmVzZWxlY3RpbmcvZmlsdGVyaW5nIHVsdHJhaGlnaC1kaW1lbnNpb25hbCBvbWljcyBmZWF0dXJlcyBjYW4gYmUgdXNlZnVsIGJlZm9yZSBydW5uaW5nIHRoZSBmcmVxdWVudGlzdCBhbmQgQmF5ZXNpYW4gc3VwZXJ2aXNlZCBsZWFybmluZyBtZXRob2RzLgoKIyMjIERpbWVuc2lvbiByZWR1Y3Rpb24gZm9yIENveCBtb2RlbHMgey19CgpUaGUgZm9sbG93aW5nIGNvZGUgZGVtb25zdHJhdGVzIHRoZSB1c2Ugb2YgdGhlIGZpcnN0IHR3byBwcmluY2lwYWwgY29tcG9uZW50cyBvZiBQQ0EgYXMgY292YXJpYXRlcyBmb3IgdGhlICoqcHVycG9zZSBvZiBzdXJ2aXZhbCBwcmVkaWN0aW9uKiouClNpbWlsYXJseSwgdGhlIGZpcnN0IGNvbXBvbmVudHMgZnJvbSAkdCQtU05FIG9yIFVNQVAgY2FuIGFsc28gYmUgZXh0cmFjdGVkIGFzIGNvdmFyaWF0ZXMuCgpgYGB7cn0KIyBwcmluY2lwYWwgY29tcG9uZW50IHJlZ3Jlc3Npb24KeF90bXAgPSBwcmNvbXAodChUQ0dBX1BBTTUwKSkKCiMgY2hvb3NlIHRoZSB0b3AgdHdvIGNvbXBvbmVudHMgKHN1YmplY3RpdmUpIGFzIGNvdmFyaWF0ZXMKWF9QQyA9IHhfdG1wJHhbLCAxOjJdCiMgYnVpbGQgY2xhc3NpY2FsIHN1cnZpdmFsIG1vZGVsIChlLmcuIFBIIENveCBtb2RlbCkKZGF0YV90bXAgPSBkYXRhLmZyYW1lKHRpbWUgPSBjbGluJHRpbWUsIHN0YXR1cyA9IGNsaW4kc3RhdHVzLCBYX1BDKQpmaXQgPSBjb3hwaChTdXJ2KHRpbWUsIHN0YXR1cykgfiBQQzEgKyBQQzIsIGRhdGEgPSBkYXRhX3RtcCkKc3VtbWFyeShmaXQpCmBgYApgYGAKQ2FsbDoKY294cGgoZm9ybXVsYSA9IFN1cnYodGltZSwgc3RhdHVzKSB+IFBDMSArIFBDMiwgZGF0YSA9IGRhdGFfdG1wKQoKICBuPSAxMDQ3LCBudW1iZXIgb2YgZXZlbnRzPSAxNDkgCgogICAgICAgIGNvZWYgZXhwKGNvZWYpIHNlKGNvZWYpICAgICB6IFByKD58enwpICAgClBDMSAwLjAwNDY3OSAgMS4wMDQ2OTAgMC4wMDk2NzUgMC40ODQgIDAuNjI4NjIgICAKUEMyIDAuMDM4MTc5ICAxLjAzODkxOCAwLjAxMzIzMyAyLjg4NSAgMC4wMDM5MSAqKgotLS0KU2lnbmlmLiBjb2RlczogIDAg4oCYKioq4oCZIDAuMDAxIOKAmCoq4oCZIDAuMDEg4oCYKuKAmSAwLjA1IOKAmC7igJkgMC4xIOKAmCDigJkgMQoKICAgIGV4cChjb2VmKSBleHAoLWNvZWYpIGxvd2VyIC45NSB1cHBlciAuOTUKUEMxICAgICAxLjAwNSAgICAgMC45OTUzICAgIDAuOTg1OCAgICAgMS4wMjQKUEMyICAgICAxLjAzOSAgICAgMC45NjI1ICAgIDEuMDEyMyAgICAgMS4wNjYKCkNvbmNvcmRhbmNlPSAwLjU4ICAoc2UgPSAwLjAyOCApCkxpa2VsaWhvb2QgcmF0aW8gdGVzdD0gOC41NCAgb24gMiBkZiwgICBwPTAuMDEKV2FsZCB0ZXN0ICAgICAgICAgICAgPSA4LjY0ICBvbiAyIGRmLCAgIHA9MC4wMQpTY29yZSAobG9ncmFuaykgdGVzdCA9IDguNjYgIG9uIDIgZGYsICAgcD0wLjAxCmBgYAoKIyMjIFBlbmFsaXplZCBDb3ggbW9kZWxzIHstfQoKRm9yIGNvbXB1dGF0aW9uYWwgZWZmaWNpZW5jeSwgd2Ugd2lsbCB1c2Ugb25seSB0aGUgbVJOQS1TZXEgZmVhdHVyZXMgY29ycmVzcG9uZGluZyB0byB0aGUgUEFNNTAgZ2VuZXMgW0BQYXJrZXIyMDA5XSBpbnN0ZWFkIG9mIHRoZSB2YXJpYW5jZSBmaWx0ZXJlZCBnZW5lcyBmcm9tIHRoZSBwcmV2aW91cyBzZWN0aW9uLgpXZSBwZXJmb3JtIGFuIGludmVzdGlnYXRpb24gb2YgdGhlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB0aGUgbVJOQS1TZXEgZmVhdHVyZXMsIHR3byBjbGluaWNhbCB2YXJpYWJsZXMgKGkuZS4gdGhlIHBhdGllbnRzJyBhZ2UgYXQgZGlhZ25vc2lzIGFuZCB0aGVpciBldGhuaWNpdHkpIGFuZCB0aGUgc3Vydml2YWwgb3V0Y29tZXMuCgpUaGUgYFJgIHBhY2thZ2UgWyoqZ2xtbmV0KipdKGh0dHBzOi8vQ1JBTi5SLXByb2plY3Qub3JnL3BhY2thZ2U9Z2xtbmV0KSBbQEZyaWVkbWFuMjAxMF0gaXMgdmVyeSBjb21wdXRhdGlvbmFsbHkgZWZmaWNpZW50IHRvIHJ1biBMYXNzbyBhbmQgRWxhc3RpYyBOZXQgQ294IG1vZGVscy4KTGFzc28gaGFzIGEgdHVuaW5nIHBhcmFtZXRlciAkXGxhbWJkYSQgdG8gY29udHJvbCB0aGUgcGVuYWx0eSBzdHJlbmd0aCBvZiB0aGUgY29lZmZpY2llbnRzIHdoaWNoIGNhbiBiZSBvcHRpbWl6ZWQgYnkgY3Jvc3MtdmFsaWRhdGlvbiAoQ1YpIHZpYSBmdW5jdGlvbiBgY3YuZ2xtbmV0KClgLgpUaGUgYGdsbW5ldCgpYCBhbmQgYGN2LmdsbW5ldCgpYCBmdW5jdGlvbnMgcHJvdmlkZSB0aGUgYXJndW1lbnQgYHBlbmFsdHkuZmFjdG9yYCB0byBhbGxvdyBkaWZmZXJlbnQgc2hyaW5rYWdlcyBmb3IgZGlmZmVyZW50IGZlYXR1cmVzLCB3aGljaCBtYWtlcyBzZW5zZSBpZiBvbmUgaW5jbHVkZXMgYm90aCBjbGluaWNhbC9kZW1vZ3JhcGhpYyB2YXJpYWJsZXMgYW5kIG9taWNzIGZlYXR1cmVzIGFuZCBkb2VzIG5vdCB3YW50IHRvIHBlcmZvcm0gZmVhdHVyZSBzZWxlY3Rpb24gZm9yIHRoZSBjbGluaWNhbC9kZW1vZ3JhcGhpYyB2YXJpYWJsZXMuCgpgYGB7cn0KIyMgTGFzc28gQ294IG1vZGVsCgojIyBmb3IgZGVtb25zdHJhdGlvbiBzaW1wbGljaXR5LCBQQU01MCBnZW5lcyBhcmUgdXNlZCBoZXJlCnggPSBjYmluZChhZ2UgPSBjbGluJGFnZSwgZXRobmljaXR5ID0gZmFjdG9yKGNsaW4kZXRobmljaXR5KSwgdChUQ0dBX1BBTTUwKSkKeSA9IGNiaW5kKHRpbWUgPSBjbGluJHRpbWUsIHN0YXR1cyA9IGNsaW4kc3RhdHVzKQoKIyBzZXQgcGVuYWx0eSBmYWN0b3Igd2l0aG91dCBwZW5hbGl6aW5nIHRoZSB0d28gZGVtb2dyYXBoaWNhbCB2YXJpYWJsZXMKcGYgPSBjKHJlcCgwLCAyKSwgcmVwKDEsIG5jb2woeCkgLSAyKSkKCiMgTGFzc28gQ294IGJ5IHVzaW5nIGN2LmdsbW5ldCB0byBvYnRhaW4gdGhlIDUtZm9sZCBDViBvcHRpbWFsIGxhbWJkYS5taW4gb3IgbGFtYmRhLjFzZQpzZXQuc2VlZCgxMjMpCmN2Zml0ID0gZ2xtbmV0Ojpjdi5nbG1uZXQoeCwgeSwgZmFtaWx5ID0gImNveCIsIG5mb2xkcyA9IDUsIHBlbmFsdHkuZmFjdG9yID0gcGYpCm1vZCA9IGN2Zml0JGdsbW5ldC5maXQKbGFtYmRhX29wdGltYWwgPSBjdmZpdCRsYW1iZGEubWluICMgb3B0aW1hbCBsYW1iZGEKCmJldGFzID0gYXMudmVjdG9yKGNvZWYobW9kLCBzID0gbGFtYmRhX29wdGltYWwpKQpiZXRhLnBvc2l0aXZlID0gY29sbmFtZXMoeClbYmV0YXMgPiAwXQpiZXRhLm5lZ2F0aXZlID0gY29sbmFtZXMoeClbYmV0YXMgPCAwXQojZ2V0IG9yZGVyZWQgbGlzdCBvZiB2YXJpYWJsZXMgYXMgdGhleSBhcHBlYXIgYXQgc21hbGxlc3QgbGFtYmRhCmFsbG5hbWVzID0gbmFtZXMoY29lZihtb2QpWywgbmNvbChjb2VmKG1vZCkpXQogICAgICAgICAgICAgICAgW29yZGVyKGNvZWYobW9kKVssIG5jb2woY29lZihtb2QpKV0sIGRlY3JlYXNpbmcgPSBUUlVFKV0pCiMgYXNzaWduIGNvbG9ycyBmb3IgcG9zaXRpdmUgKHBpbmspIGFuZCBuZWdhdGl2ZSAoZ3JlZW4pIGNvZWZmaWNpZW50cwpjb2xzID0gcmVwKCJncmF5ODAiLCBsZW5ndGgoYWxsbmFtZXMpKQpjb2xzW2FsbG5hbWVzICVpbiUgYmV0YS5wb3NpdGl2ZV0gPSAic2VhZ3JlZW4zIgpjb2xzW2FsbG5hbWVzICVpbiUgYmV0YS5uZWdhdGl2ZV0gPSAiaG90cGluayIKCiMgZHJ3YSBjb2VmZmljaWVudCBwYXRocyBvZiBhIExhc3NvIENveCBtb2RlbApwbG90bW86OnBsb3RfZ2xtbmV0KG1vZCwgbGFiZWwgPSBUUlVFLCBzID0gbGFtYmRhX29wdGltYWwsIGNvbCA9IGNvbHMsCiAgICAgICAgICAgIHhsYWIgPSBleHByZXNzaW9uKGxvZyB+fiBsYW1iZGEpLCB5bGFiID0gZXhwcmVzc2lvbihiZXRhKSkKdGl0bGUoIkxhc3NvICAgIFxuXG4iKQpgYGAKYGBge3IsIGVjaG89RkFMU0V9CnBkZigiVENHQV9MYXNzby5wZGYiLCB3aWR0aCA9IDYsIGhlaWdodCA9IDUpCnBsb3Rtbzo6cGxvdF9nbG1uZXQobW9kLCBsYWJlbCA9IFRSVUUsIHMgPSBsYW1iZGFfb3B0aW1hbCwgY29sID0gY29scywKICAgICAgICAgICAgeGxhYiA9IGV4cHJlc3Npb24obG9nIH5+IGxhbWJkYSksIHlsYWIgPSBleHByZXNzaW9uKGJldGEpKQp0aXRsZSgiTGFzc28gICAgXG5cbiIpCmRldi5vZmYoKQpgYGAKIVtfQ29lZmZpY2llbnQgcGF0aHMgb2YgYSBMYXNzbyBDb3ggbW9kZWwuIFRoZSB2ZXJ0aWNsZSBncmF5IGxpbmUgaW5kaWNhdGVzIHRoZSBvcHRpbWFsICRcbGFtYmRhJCBhbmQgaXRzIGNvcnJlc3BvbmRpbmdseSBzZWxlY3RlZCBmZWF0dXJlcyBhcmUgbWFya2VkIGFzIGdyZWVuIChwb3NpdGl2ZSBjb2VmZmljaWVudCkgYW5kIHJlZCAobmVnYXRpdmUgY29lZmZpY2llbnQpIGNvbG9ycy4gTm90ZSB0aGF0IHRoZSBkZW1vZ3JhcGhpYyB2YXJpYWJsZXMgYWdlIGFuZCBldGhuaWNpdHkgd2VyZSBub3QgcGVuYWxpemVkLCBzbyB0aGF0IHRoZWlyIGNvZWZmaWNpZW50IHBhdGhzIGRpZCBub3Qgc3RhcnQgZnJvbSB6ZXJvIGluIHRoZSBmaWd1cmUuX10oZmlnL1RDR0FfbGFzc28ucG5nKXt3aWR0aD02MCV9Cgo8YnI+CgpFbGFzdGljIE5ldCBDb3ggbW9kZWwgaW5jbHVkZXMgdGhlICRcbGFtYmRhJCBhbmQgYW4gYWRkaXRpb25hbCBwZW5hbHR5IHBhcmFtZXRlciAkXGFscGhhIFxpbiBbMCwxXSQuClRoZSBwYXJhbWV0ZXIgJFxhbHBoYSQgY2FuIGJlIGZpeGVkIGFzICQwJCAoUmlkZ2UpLCAkMSQgKExhc3NvKSBvciBhbnkgdmFsdWUgYmV0d2VlbiAkMCQgYW5kICQxJCBmb3IgbWFraW5nIGEgY29tcHJvbWlzZSBiZXR3ZWVuIFJpZGdlIGFuZCBMYXNzbywgd2hpY2ggY2FuIGFsc28gYmUgb3B0aW1pemVkIGJ5IGNyb3NzLXZhbGlkYXRpb24gbWFudWFsbHksIHNlZSB0aGUgZXhhbXBsZSBiZWxvdy4KCmBgYHtyfQojIyBFbGFzdGljIE5ldCBDb3ggbW9kZWwKCiMgc2V0IHBlbmFsdHkgcGFyYW1ldGVyIGFscGhhIHdoaWNoIGNvbXByaXNlcyBiZXR3ZWVuIExhc3NvIGFuZCByaWRnZSByZWdyZXNzaW9ucwphbHBoYSA9IHNlcSgwLjEsIDEsIGxlbmd0aCA9IDEwKQpmaXRFTiA9IGxpc3QoKQpzZXQuc2VlZCgxMjMpCmZvciAoaSBpbiAxOmxlbmd0aChhbHBoYSkpIHsKICBmaXRFTltbaV1dID0gY3YuZ2xtbmV0KHgsIHksIGZhbWlseSA9ICJjb3giLCBhbHBoYSA9IGFscGhhW2ldLCBuZm9sZHMgPSA1LCBwZW5hbHR5LmZhY3RvciA9IHBmKQp9CmlkeCA9IHdoaWNoLm1pbihzYXBwbHkoZml0RU4sIGZ1bmN0aW9uKHh4KSB7eHgkY3ZtW3h4JGxhbWJkYSA9PSB4eCRsYW1iZGEubWluXX0pKQpjdmZpdCA9IGZpdEVOW1tpZHhdXQoKIyB0aGUgZm9sbG93aW5nIGNvZGUgaXMgdGhlIHNhbWUgYXMgTGFzc28gcHJldmlvdXNseQptb2QgPSBjdmZpdCRnbG1uZXQuZml0CmxhbWJkYV9vcHRpbWFsID0gY3ZmaXQkbGFtYmRhLm1pbiAjIG9wdGltYWwgbGFtYmRhCgpiZXRhcyA9IGFzLnZlY3Rvcihjb2VmKG1vZCwgcyA9IGxhbWJkYV9vcHRpbWFsKSkKYmV0YS5wb3NpdGl2ZSA9IGNvbG5hbWVzKHgpW2JldGFzID4gMF0KYmV0YS5uZWdhdGl2ZSA9IGNvbG5hbWVzKHgpW2JldGFzIDwgMF0KYWxsbmFtZXMgPSBuYW1lcyhjb2VmKG1vZClbLCBuY29sKGNvZWYobW9kKSldCiAgICAgICAgICAgICAgICBbb3JkZXIoY29lZihtb2QpWywgbmNvbChjb2VmKG1vZCkpXSwgZGVjcmVhc2luZyA9IFRSVUUpXSkKY29scyA9IHJlcCgiZ3JheTgwIiwgbGVuZ3RoKGFsbG5hbWVzKSkKY29sc1thbGxuYW1lcyAlaW4lIGJldGEucG9zaXRpdmVdID0gInNlYWdyZWVuMyIgCmNvbHNbYWxsbmFtZXMgJWluJSBiZXRhLm5lZ2F0aXZlXSA9ICJob3RwaW5rIiAgIAoKcGxvdG1vOjpwbG90X2dsbW5ldChtb2QsIGxhYmVsID0gVFJVRSwgcyA9IGxhbWJkYV9vcHRpbWFsLCBjb2wgPSBjb2xzLAogICAgICAgICAgICB4bGFiID0gZXhwcmVzc2lvbihsb2cgfn4gbGFtYmRhKSwgeWxhYiA9IGV4cHJlc3Npb24oYmV0YSkpCnRpdGxlKCJFbGFzdGljIE5ldCAgICAgXG5cbiIpCmBgYApgYGB7ciwgZWNobz1GQUxTRX0KcGRmKCJUQ0dBX2VsYXN0aWMucGRmIiwgd2lkdGggPSA2LCBoZWlnaHQgPSA1KQpwbG90bW86OnBsb3RfZ2xtbmV0KG1vZCwgbGFiZWwgPSBUUlVFLCBzID0gbGFtYmRhX29wdGltYWwsIGNvbCA9IGNvbHMsCiAgICAgICAgICAgIHhsYWIgPSBleHByZXNzaW9uKGxvZyB+fiBsYW1iZGEpLCB5bGFiID0gZXhwcmVzc2lvbihiZXRhKSkKdGl0bGUoIkVsYXN0aWMgTmV0ICAgICBcblxuIikKZGV2Lm9mZigpCmBgYAohW19Db2VmZmljaWVudCBwYXRocyBvZiBhbiBFbGFzdGljIE5ldCBDb3ggbW9kZWwuIFRoZSB2ZXJ0aWNsZSBncmF5IGxpbmUgaW5kaWNhdGVzIHRoZSBvcHRpbWFsICRcbGFtYmRhJCBhbmQgaXRzIGNvcnJlc3BvbmRpbmdseSBzZWxlY3RlZCBmZWF0dXJlcyBhcmUgbWFya2VkIGFzIGdyZWVuIChwb3NpdGl2ZSBjb2VmZmljaWVudCkgYW5kIHJlZCAobmVnYXRpdmUgY29lZmZpY2llbnQpIGNvbG9ycy4gTm90ZSB0aGF0IHRoZSBkZW1vZ3JhcGhpYyB2YXJpYWJsZXMgYWdlIGFuZCBldGhuaWNpdHkgd2VyZSBub3QgcGVuYWxpemVkLCBzbyB0aGF0IHRoZWlyIGNvZWZmaWNpZW50IHBhdGhzIGRpZCBub3Qgc3RhcnQgZnJvbSB6ZXJvIGluIHRoZSBmaWd1cmUuX10oZmlnL1RDR0FfZWxhc3RpYy5wbmcpe3dpZHRoPTYwJX0KCjxicj4KCkFkYXB0aXZlIExhc3NvIENveCBtb2RlbCBuZWVkcyB0byBwcmUtZXN0aW1hdGUgYWxsIGNvZWZmaWNpZW50cyB3aGljaCB3aWxsIGJlIHVzZWQgYXMgd2VpZ2h0cyB2aWEgdGhlIGFyZ3VtZW50IGBwZW5hbHR5LmZhY3RvcmAgaW4gdGhlIGBnbG1uZXQoKWAgYW5kIGBjdi5nbG1uZXQoKWAgZnVuY3Rpb25zIHRvIGZpdCBhIExhc3NvIENveCBtb2RlbC4KVGhlIHByZS1lc3RpbWF0aW9uIGNhbiBiZSBkb25lIGJ5IGEgUmlkZ2UgQ294IG1vZGVsLCBzZWUgYW4gZXhhbXBsZSBiZWxvdy4KCmBgYHtyfQojIyBBZGFwdGl2ZSBMYXNzbyBDb3ggbW9kZWwKCnNldC5zZWVkKDEyMykKZml0ID0gY3YuZ2xtbmV0KHgsIHksIGZhbWlseSA9ICJjb3giLCBhbHBoYSA9IDAsIG5mb2xkcyA9IDUpCndlaWdodHMgPSBhYnMoMSAvIGFzLnZlY3Rvcihjb2VmKGZpdCwgcyA9ICJsYW1iZGEubWluIikpKQoKIyBhZGFwdGl2ZSBMYXNzbyBDb3ggYnkgdXNpbmcgY3YuZ2xtbmV0IHRvIG9idGFpbiB0aGUgNS1mb2xkIENWIG9wdGltYWwgbGFtYmRhLm1pbiBvciBsYW1iZGEuMXNlCmN2Zml0ID0gY3YuZ2xtbmV0KHgsIHksIGZhbWlseSA9ICJjb3giLCBuZm9sZHMgPSA1LCBwZW5hbHR5LmZhY3RvciA9IHBmKQptb2QgPSBjdmZpdCRnbG1uZXQuZml0CmxhbWJkYV9vcHRpbWFsID0gY3ZmaXQkbGFtYmRhLm1pbiAjIG9wdGltYWwgbGFtYmRhCgpiZXRhcyA9IGFzLnZlY3Rvcihjb2VmKG1vZCwgcyA9IGxhbWJkYV9vcHRpbWFsKSkKYmV0YS5wb3NpdGl2ZSA9IGNvbG5hbWVzKHgpW2JldGFzID4gMF0KYmV0YS5uZWdhdGl2ZSA9IGNvbG5hbWVzKHgpW2JldGFzIDwgMF0KI2dldCBvcmRlcmVkIGxpc3Qgb2YgdmFyaWFibGVzIGFzIHRoZXkgYXBwZWFyIGF0IHNtYWxsZXN0IGxhbWJkYQphbGxuYW1lcyA9IG5hbWVzKGNvZWYobW9kKVssIG5jb2woY29lZihtb2QpKV0KICAgICAgICAgICAgICAgIFtvcmRlcihjb2VmKG1vZClbLCBuY29sKGNvZWYobW9kKSldLCBkZWNyZWFzaW5nID0gVFJVRSldKQojYXNzaWduIGNvbG9ycwpjb2xzID0gcmVwKCJncmF5ODAiLCBsZW5ndGgoYWxsbmFtZXMpKQpjb2xzW2FsbG5hbWVzICVpbiUgYmV0YS5wb3NpdGl2ZV0gPSAic2VhZ3JlZW4zIgpjb2xzW2FsbG5hbWVzICVpbiUgYmV0YS5uZWdhdGl2ZV0gPSAiaG90cGluayIKCnBsb3RfZ2xtbmV0KG1vZCwgbGFiZWwgPSBUUlVFLCBzID0gbGFtYmRhX29wdGltYWwsIGNvbCA9IGNvbHMsCiAgICAgICAgICAgIHhsYWIgPSBleHByZXNzaW9uKGxvZyB+IGxhbWJkYSksIHlsYWIgPSBleHByZXNzaW9uKGJldGEpKQp0aXRsZSgiQWRhdGl2ZSBMYXNzbyAgICBcblxuIikKYGBgCmBgYHtyLCBlY2hvPUZBTFNFfQpwZGYoIlRDR0FfYWRhcHRpdmVMYXNzby5wZGYiLCB3aWR0aCA9IDYsIGhlaWdodCA9IDUpCnBsb3RfZ2xtbmV0KG1vZCwgbGFiZWwgPSBUUlVFLCBzID0gbGFtYmRhX29wdGltYWwsIGNvbCA9IGNvbHMsCiAgICAgICAgICAgIHhsYWIgPSBleHByZXNzaW9uKGxvZyB+IGxhbWJkYSksIHlsYWIgPSBleHByZXNzaW9uKGJldGEpKQp0aXRsZSgiQWRhdGl2ZSBMYXNzbyAgICBcblxuIikKZGV2Lm9mZigpCmBgYAohW19Db2VmZmljaWVudCBwYXRocyBvZiBhbiBhZGFwdGl2ZSBMYXNzbyBDb3ggbW9kZWwuIFRoZSB2ZXJ0aWNsZSBncmF5IGxpbmUgaW5kaWNhdGVzIHRoZSBvcHRpbWFsICRcbGFtYmRhJCBhbmQgaXRzIGNvcnJlc3BvbmRpbmdseSBzZWxlY3RlZCBmZWF0dXJlcyBhcmUgbWFya2VkIGFzIGdyZWVuIChwb3NpdGl2ZSBjb2VmZmljaWVudCkgYW5kIHJlZCAobmVnYXRpdmUgY29lZmZpY2llbnQpIGNvbG9ycy4gTm90ZSB0aGF0IHRoZSBkZW1vZ3JhcGhpYyB2YXJpYWJsZXMgYWdlIGFuZCBldGhuaWNpdHkgd2VyZSBub3QgcGVuYWxpemVkLCBzbyB0aGF0IHRoZWlyIGNvZWZmaWNpZW50IHBhdGhzIGRpZCBub3Qgc3RhcnQgZnJvbSB6ZXJvIGluIHRoZSBmaWd1cmUuX10oZmlnL1RDR0FfYWRhcHRpdmVsYXNzby5wbmcpe3dpZHRoPTYwJX0KCjxicj4KCkdyb3VwIExhc3NvIENveCBtb2RlbCBjYW4gYmUgaW1wbGVtZW50ZWQgdGhyb3VnaCB0aGUgYFJgIHBhY2thZ2UgWyoqZ3JwcmVnKipdKGh0dHBzOi8vQ1JBTi5SLXByb2plY3Qub3JnL3BhY2thZ2U9Z3JwcmVnKSBbQEJyZWhlbnkyMDE1XS4KRm9yIGFuIGlsbHVzdHJhdGlvbiwgd2Ugc3BlY2lmeSB0aGUgdHdvIGRlbW9ncmFwaGljIHZhcmlhYmxlcyBhcyB0aGUgZmlyc3QgZ3JvdXAsIHRoZSBmaXJzdCAkMTAkIFBBTTUwIGdlbmVzIGFzIHRoZSBzZWNvbmQgZ3JvdXAsIHRoZSBsYXN0ICQ0MCQgUEFNNTAgZ2VuZXMgYXMgdGhlIHRoaXJkIGdyb3VwLgpBICRrJC1mb2xkIGNyb3NzLXZhbGlkYXRpb24gKENWKSBmb3IgdGhlIGdyb3VwIExhc3NvIENveCBtb2RlbCBpcyBwZXJmb3JtZWQgdGhyb3VnaCBmdW5jdGlvbiBgY3YuZ3Jwc3VydigpYC4KVGhlIHJldHVybmVkIG9iamVjdCBgY3ZmaXQkbGFtYmRhLm1pbmAgaXMgdGhlIHZhbHVlIG9mIENWLW9wdGltaXplZCAkXGxhbWJkYSQuClRoZSBmb2xsb3dpbmcgcmVzdWx0cyBzaG93IHRoYXQgCgotIHdoZW4gY2hvb3NpbmcgdGhlIENWLW9wdGltaXplZCAkXGxhbWJkYSA9IDAuMDE0MyQgKG91dHB1dCBtYXRyaXggaGFzIGxhbWJkYSB2YWx1ZXMgYXMgY29sdW1uIG5hbWVzKSwgdGhlIGVzdGltYXRlZCBjb2VmZmljaWVudHMgb2YgdGhlIGZpcnN0IHR3byBncm91cHMgYXJlIG5vbnplcm8gKGkuZS4gc2VsZWN0aW5nIGZpcnN0IGFuZCBzZWNvbmQgZ3JvdXBzKTsKLSB3aGVuIGNob29zaW5nIHRoZSAkMTAkLXRoIGxhbWJkYSAkXGxhbWJkYSA9IDAuMDIxNyQsIG9ubHkgdGhlIGZpcnN0IGdyb3VwIG9mIGNvdmFyaWF0ZXMgaGFzIG5vbnplcm8gY29lZmZpY2llbnRzIChpLmUuIHNlbGVjdGluZyBmaXJzdCBncm91cCk7Ci0gd2hlbiBjaG9vc2luZyB0aGUgJDE1JC10aCBsYW1iZGEgJFxsYW1iZGEgPSAwLjAxMDgkLCB0aGUgZXN0aW1hdGVkIGNvZWZmaWNpZW50cyBvZiBhbGwgdGhlIHRocmVlIGdyb3VwcyBhcmUgbm9uemVybyAoaS5lLiBzZWxlY3RpbmcgYWxsIGdyb3VwcykuIAoKTm90ZSB0aGF0IHRoZSBgUmAgcGFja2FnZSBbKipncnByZWcqKl0oaHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT1ncnByZWcpIFtAQnJlaGVueTIwMTVdIGFsc28gaW1wbGVtZW50cyBncm91cCBzbW9vdGhseSBjbGlwcGVkIGFic29sdXRlIGRldmlhdGlvbiAoU0NBRCkgbW9kZWwgYW5kIHNvbWUgb3RoZXJzLCBzZWUgQEJyZWhlbnkyMDIxIGZvciBkZXRhaWxzLgoKYGBge3J9CiMgZ3JvdXAgTGFzc28gQ294IG1vZGVsCmdyb3VwID0gYyhyZXAoImRlbW9ncmFwaGljIiwgMiksIHJlcCgiUEFNNTBfMSIsIDEwKSwgcmVwKCJQQU01MF8yIiwgNDApKQpncm91cCA9IGZhY3Rvcihncm91cCkKc2V0LnNlZWQoMTIzKQpjdmZpdCA9IGdycHJlZzo6Y3YuZ3Jwc3VydihYID0geCwgeSA9IHksIGdyb3VwID0gZ3JvdXAsIHBlbmFsdHkgPSAiZ3JMYXNzbyIsIHJldHVyblkgPSBUUlVFKQpyb3VuZChjdmZpdCRmaXQkYmV0YVssIGMod2hpY2gubWluKGN2Zml0JGN2ZSksIDEwLCAyMCldLCBkaWdpdHMgPSA0KQpgYGAKYGBgCiAgICAgICAgICAgMC4wMTQzICAwLjAyMTcgIDAuMDEwOAphZ2UgICAgICAgIDAuMDIxOCAgMC4wMTU0ICAwLjAyNDcKZXRobmljaXR5IC0wLjA1NDIgLTAuMDQyNSAtMC4wNTcwCkFOTE4gICAgICAgMC4wMTkzICAwLjAwMDAgIDAuMDcxMwpGT1hDMSAgICAgLTAuMDAzMiAgMC4wMDAwIC0wLjAxMDQKQ0RIMyAgICAgIC0wLjAwMjggIDAuMDAwMCAtMC4wMDkwClVCRTJUICAgICAgMC4wMTU0ICAwLjAwMDAgIDAuMDU3MQpOREM4MCAgICAgLTAuMDIzOSAgMC4wMDAwIC0wLjA4NjIKUEdSICAgICAgIC0wLjAwMjcgIDAuMDAwMCAtMC4wMDg2CkJJUkM1ICAgICAtMC4wMTMzICAwLjAwMDAgLTAuMDQ5NwpPUkM2ICAgICAgIDAuMDE0MCAgMC4wMDAwICAwLjA0ODkKRVNSMSAgICAgIC0wLjAwMDIgIDAuMDAwMCAtMC4wMDA4ClBIR0RIICAgICAgMC4wMDA4ICAwLjAwMDAgIDAuMDAyNApDREM2ICAgICAgIDAuMDAwMCAgMC4wMDAwIC0wLjAwOTQKTU1QMTEgICAgICAwLjAwMDAgIDAuMDAwMCAgMC4wMDc0Ck1ZQkwyICAgICAgMC4wMDAwICAwLjAwMDAgIDAuMDAxOApTRlJQMSAgICAgIDAuMDAwMCAgMC4wMDAwICAwLjAwNDkKQ0NORTEgICAgICAwLjAwMDAgIDAuMDAwMCAgMC4wMDAwCkJMVlJBICAgICAgMC4wMDAwICAwLjAwMDAgLTAuMDQzNgpCQUcxICAgICAgIDAuMDAwMCAgMC4wMDAwIC0wLjAxNjMKTUxQSCAgICAgICAwLjAwMDAgIDAuMDAwMCAtMC4wMTU1CkNEQzIwICAgICAgMC4wMDAwICAwLjAwMDAgLTAuMDEyOQpDRU5QRiAgICAgIDAuMDAwMCAgMC4wMDAwIC0wLjAyNDUKS1JUMTcgICAgICAwLjAwMDAgIDAuMDAwMCAtMC4wMTI1CkZPWEExICAgICAgMC4wMDAwICAwLjAwMDAgIDAuMDA0MApBQ1RSM0IgICAgIDAuMDAwMCAgMC4wMDAwIC0wLjAxMTIKQ0NOQjEgICAgICAwLjAwMDAgIDAuMDAwMCAgMC4wMzAyCk1ETTIgICAgICAgMC4wMDAwICAwLjAwMDAgLTAuMDA3NwpNWUMgICAgICAgIDAuMDAwMCAgMC4wMDAwICAwLjAwMDIKQ0VQNTUgICAgICAwLjAwMDAgIDAuMDAwMCAtMC4wMjQyClNMQzM5QTYgICAgMC4wMDAwICAwLjAwMDAgIDAuMDA1MwpFUkJCMiAgICAgIDAuMDAwMCAgMC4wMDAwIC0wLjAwODkKR1JCNyAgICAgICAwLjAwMDAgIDAuMDAwMCAgMC4wMDk5CktJRjJDICAgICAgMC4wMDAwICAwLjAwMDAgIDAuMDIxOQpOVUYyICAgICAgIDAuMDAwMCAgMC4wMDAwICAwLjAyMTAKRUdGUiAgICAgICAwLjAwMDAgIDAuMDAwMCAtMC4wMTUwCk1LSTY3ICAgICAgMC4wMDAwICAwLjAwMDAgIDAuMDI2NgpUTUVNNDVCICAgIDAuMDAwMCAgMC4wMDAwICAwLjAxMDAKRkdGUjQgICAgICAwLjAwMDAgIDAuMDAwMCAgMC4wMDIzClBUVEcxICAgICAgMC4wMDAwICAwLjAwMDAgIDAuMDA5NQpNRUxLICAgICAgIDAuMDAwMCAgMC4wMDAwIC0wLjAxODgKTkFUMSAgICAgICAwLjAwMDAgIDAuMDAwMCAtMC4wMDUyCkNYWEM1ICAgICAgMC4wMDAwICAwLjAwMDAgIDAuMDEzMQpCQ0wyICAgICAgIDAuMDAwMCAgMC4wMDAwIC0wLjAwODIKUlJNMiAgICAgICAwLjAwMDAgIDAuMDAwMCAtMC4wMDAzCkdQUjE2MCAgICAgMC4wMDAwICAwLjAwMDAgLTAuMDA0MwpFWE8xICAgICAgIDAuMDAwMCAgMC4wMDAwICAwLjAwNDEKVUJFMkMgICAgICAwLjAwMDAgIDAuMDAwMCAtMC4wMDUyClRZTVMgICAgICAgMC4wMDAwICAwLjAwMDAgLTAuMDI5OApLUlQ1ICAgICAgIDAuMDAwMCAgMC4wMDAwIC0wLjAwMjUKS1JUMTQgICAgICAwLjAwMDAgIDAuMDAwMCAgMC4wMDg1Ck1BUFQgICAgICAgMC4wMDAwICAwLjAwMDAgLTAuMDA3MQpNSUEgICAgICAgIDAuMDAwMCAgMC4wMDAwIC0wLjAxODAKYGBgCgpTcGFyc2UgZ3JvdXAgTGFzc28gQ294IG1vZGVsIGlzIGltcGxlbWVudGVkIGluIHRoZSBgUmAgcGFja2FnZSBbKipTR0wqKl0oaHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT1TR0wpIFtAU2ltb24yMDE5XS4gClRoZSBmdW5jdGlvbiBgY3ZTR0woKWAgdXNlcyBjcm9zcyB2YWxpZGF0aW9uIHRvIG9wdGltaXplIHRoZSBwZW5hbHR5IHBhcmFtZXRlciAkXGxhbWJkYSQuClRoZSBmb2xsb3dpbmcgZXhhbXBsZSBzaG93cyB0aGF0IGl0IGluZHVjZXMgc3BhcnNpdHkgaW4gZWFjaCBncm91cCBvZiBjb3ZhcmlhdGVzLiAKCmBgYHtyfQojIHNwYXJzZSBncm91cCBMYXNzbyBDb3ggbW9kZWwKZ3JvdXAgPSBjKHJlcCgiZGVtb2dyYXBoaWMiLCAyKSwgcmVwKCJQQU01MF8xIiwgMTApLCByZXAoIlBBTTUwXzIiLCA0MCkpCmdyb3VwID0gZmFjdG9yKGdyb3VwKQpkYXRfdG1wID0gbGlzdCh4ID0geCwgdGltZSA9IGNsaW4kdGltZSwgc3RhdHVzID0gY2xpbiRzdGF0dXMpCnNldC5zZWVkKDEyMykKY3ZmaXQgPSBTR0w6OmN2U0dMKGRhdF90bXAsIGluZGV4ID0gZ3JvdXAsIHR5cGUgPSAiY294IiwgbmZvbGQgPSA1KQpiZXRhLmhhdCA9IGN2Zml0JGZpdCRiZXRhWywgd2hpY2gubWluKGN2Zml0JGxsZGlmZildCm5hbWVzKGJldGEuaGF0KSA9IHBhc3RlMCgiZ3JvdXAiLCBhcy5udW1lcmljKGdyb3VwKSwgIi4iLCBjKDE6MiwgMToxMCwgMTo0MCkpCmJldGEuaGF0CmBgYApgYGAKICAgICBncm91cDEuMSAgICAgIGdyb3VwMS4yICAgICAgZ3JvdXAyLjEgICAgICBncm91cDIuMiAgICAgIGdyb3VwMi4zICAgICAgZ3JvdXAyLjQgCiA1LjY1ODQ4Mzg0ODggIDAuMDAwMDAwMDAwMCAgMC40ODEyMDA2MTAzICAwLjAwMDAwMDAwMDAgIDAuMDAwMDAwMDAwMCAgMC4yNDgxODMwMTc3IAogICAgIGdyb3VwMi41ICAgICAgZ3JvdXAyLjYgICAgICBncm91cDIuNyAgICAgIGdyb3VwMi44ICAgICAgZ3JvdXAyLjkgICAgIGdyb3VwMi4xMCAKIDAuMDAwMDAwMDAwMCAtMC4wMDAzMDQyMTI2ICAwLjAwMDAwMDAwMDAgIDAuMzMxNzM4NTQxMiAgMC4wMDAwMDAwMDAwICAwLjAwMDAwMDAwMDAgCiAgICAgZ3JvdXAzLjEgICAgICBncm91cDMuMiAgICAgIGdyb3VwMy4zICAgICAgZ3JvdXAzLjQgICAgICBncm91cDMuNSAgICAgIGdyb3VwMy42IAogMC4wMDAwMDAwMDAwICAwLjMwMzc2MzEyMjQgIDAuMDAwMDAwMDAwMCAtMC4zNzgyMzM4OTk3ICAwLjAwMDAwMDAwMDAgLTIuNjgwNTg4MTM0NyAKICAgICBncm91cDMuNyAgICAgIGdyb3VwMy44ICAgICAgZ3JvdXAzLjkgICAgIGdyb3VwMy4xMCAgICAgZ3JvdXAzLjExICAgICBncm91cDMuMTIgCi0xLjg0MTg1MjM3NTcgIDAuMDAwMDAwMDAwMCAgMC4wMDAwMDAwMDAwICAwLjAwMDAwMDAwMDAgLTEuNzg0OTkyMzAwNyAgMC4wMDAwMDAwMDAwIAogICAgZ3JvdXAzLjEzICAgICBncm91cDMuMTQgICAgIGdyb3VwMy4xNSAgICAgZ3JvdXAzLjE2ICAgICBncm91cDMuMTcgICAgIGdyb3VwMy4xOCAKIDAuMDAwMDAwMDAwMCAgMS4wMjkwOTE4MDQxICAwLjAwMDAwMDAwMDAgIDAuMDAwMDAwMDAwMCAgMC4wMDAwMDAwMDAwICAwLjAwMDAwMDAwMDAgCiAgICBncm91cDMuMTkgICAgIGdyb3VwMy4yMCAgICAgZ3JvdXAzLjIxICAgICBncm91cDMuMjIgICAgIGdyb3VwMy4yMyAgICAgZ3JvdXAzLjI0IAogMC4wMDAwMDAwMDAwICAwLjAwMDAwMDAwMDAgIDAuMDAwMDAwMDAwMCAgMC4wMDAwMDAwMDAwIC0wLjM2Nzk5ODA4MTcgIDAuMDAwMDAwMDAwMCAKICAgIGdyb3VwMy4yNSAgICAgZ3JvdXAzLjI2ICAgICBncm91cDMuMjcgICAgIGdyb3VwMy4yOCAgICAgZ3JvdXAzLjI5ICAgICBncm91cDMuMzAgCiAwLjk5MjU5MDE1MjkgIDAuMDA4ODQ2OTk1NyAgMC4wMDAwMDAwMDAwICAwLjAwMDAwMDAwMDAgIDAuMDAwMDAwMDAwMCAgMC4wMDAwMDAwMDAwIAogICAgZ3JvdXAzLjMxICAgICBncm91cDMuMzIgICAgIGdyb3VwMy4zMyAgICAgZ3JvdXAzLjM0ICAgICBncm91cDMuMzUgICAgIGdyb3VwMy4zNiAKLTIuMTk3NTk0MjM2NCAgMC4wMDAwMDAwMDAwICAwLjAwMDAwMDAwMDAgIDAuMDAwMDAwMDAwMCAgMC4wMDAwMDAwMDAwIC0wLjg0MDcyMjgwOTMgCiAgICBncm91cDMuMzcgICAgIGdyb3VwMy4zOCAgICAgZ3JvdXAzLjM5ICAgICBncm91cDMuNDAgCi0xLjgyMTc0OTA0NzcgIDAuMDAwMDAwMDAwMCAtMC43MzIzNzM5MTA3IC0yLjAxMTE5MDAzODAgCmBgYAoKIyMjIFNwYXJzZSBCYXllc2lhbiBDb3ggbW9kZWxzCgpUaGUgYFJgIHBhY2thZ2UgWyoqcHNiY0dyb3VwKipdKGh0dHBzOi8vQ1JBTi5SLXByb2plY3Qub3JnL3BhY2thZ2U9cHNiY0dyb3VwKSBbQExlZTIwMjFdIGludGVncmF0ZXMgYSBsYXJnZSBzZXQgb2Ygc3BhcnNlIEJheWVzaWFuIENveCBtb2RlbHMuIApUaGUgZnVuY3Rpb24gYHBzYmNHTCgpYCBpbXBsZW1lbnRzIEJheWVzaWFuIENveCBtb2RlbHMgd2l0aCBMYXNzbyBhbmQgZ3JvdXAgTGFzc28gcHJpb3JzIGZvciBmZWF0dXJlIHNlbGVjdGlvbiBhbmQgZ3JvdXAgc2VsZWN0aW9uIHJlc3BlY3RpdmVseS4gCkZvciB0aGUgTGFzc28gcHJpb3IsIHNldCB0aGUgaHlwZXJwYXJhbWV0ZXIgYHByaW9yUGFyYSRncm91cEluZCA9IDE6cGAgd2hlcmUgJHAkIGlzIHRoZSB0b3RhbCBudW1iZXIgb2YgY292YXJpYXRlcy4gCkZvciB0aGUgZ3JvdXAgTGFzc28gcHJpb3IsIHNldCB0aGUgaHlwZXJwYXJhbWV0ZXIgYHByaW9yUGFyYSRncm91cEluZGAgYXMgYSB2ZWN0b3Igb2Ygc2l6ZSAkcCQsIHdoZXJlIGVhY2ggZWxlbWVudCBkZW5vdGVzIHdoaWNoIGdyb3VwIGVhY2ggY292YXJpYXRlIGNvcnJlc3BvbmRzIHRvLiAKCmBgYHtyfQojIEJheWVzaWFuIENveCBtb2RlbCB3aXRoIExhc3NvIHByaW9yCgpzZXQuc2VlZCgxMjMpCnN1cnZPYmogPSBsaXN0KHQgPSBjbGluJHRpbWUsIGRpID0gY2xpbiRzdGF0dXMsIHggPSB4KQpwID0gbmNvbCh4KQojIHNldCBoeXBlcnBhcmFtZXRlcnMuIAojIEZvciBMYXNzbyBwcmlvciAoaS5lLiAnZ3JvdXBJbmQnPSAxOnApLCBsYXJnZXIgcmF0aW8gci9kZWx0YSB0ZW5kcyB0byBmb3JjZSB0aGUgcG9zdGVyaW9yIGJldGFzIHRvIGJlIG1vcmUgY29uY2VudHJhdGVkIGF0IDAKIyBGb3IgZ3JvdXAgTGFzc28gcHJpb3IgKGkuZS4gJ2dyb3VwSW5kJyBhcyBncm91cCBpbmRpY2F0b3IgZm9yIGNvdmFyaWF0ZXMpLCBsYXJnZXIgcmF0aW8gci9kZWx0YSB0ZW5kcyB0byBmb3JjZSBzdHJvbmdlciBncm91cGluZyBlZmZlY3Qgb2YgY292YXJpYXRlcwpzID0gYyhzb3J0KHN1cnZPYmokdFtzdXJ2T2JqJGRpID09IDFdKSwgMiAqIG1heChzdXJ2T2JqJHQpIC0gbWF4KHN1cnZPYmokdFstd2hpY2goc3Vydk9iaiR0ID09IG1heChzdXJ2T2JqJHQpKV0pKQpwcmlvclBhcmEgPSBsaXN0KCdldGEwJyA9IDEsICdrYXBwYTAnID0gMSwgJ2MwJyA9IDIsICdyJyA9IDAuNSwgCiAgICAgICAgICAgICAgICAgICdkZWx0YScgPSAwLjAwMDEsICdzJyA9IHMsICdKJyA9IGxlbmd0aChzKSwgJ2dyb3VwSW5kJyA9IDE6cCkKIyBzZXQgTUNNQyBwYXJhbWV0ZXJzCm1jbWNQYXJhID0gbGlzdCgnbnVtQmV0YScgPSBwLCAnYmV0YS5wcm9wLnZhcicgPSAxKQojIHNldCBpbml0aWFsIHZhbHVlcyBvZiBoeXBlcnBhcmFtZXRlcnMKbGFtYmRhU3EgPSAxCmluaXRpYWwgPSBsaXN0KCdiZXRhLmluaScgPSByZXAoMCwgcCksICdsYW1iZGFTcScgPSAxLCAnc2lnbWFTcScgPSBydW5pZigxLCAwLjEsIDEwKSwKICAgICAgICAgICAgICAgICd0YXVTcScgPSByZXhwKGxlbmd0aCh1bmlxdWUocHJpb3JQYXJhJGdyb3VwSW5kKSksICdyYXRlJyA9IGxhbWJkYVNxIC8gMiksCiAgICAgICAgICAgICAgICAnaCcgPSByZ2FtbWEocHJpb3JQYXJhJEosIDEsIDEpKQojIGluIHJlYWwgYXBwbGljYXRpb25zLCAnbnVtLnJlcHMnIHNob3VsZCBiZSBsYXJnZSBlbm91Z2ggKGUuZy4gMjAwMDAsIDQwMDAwKSBhbmQgJ2NoYWluJyB0byBiZSA+IDEKIyBhcmd1bWVudCAncncnIHNob3VsZCBiZSBGQUxTRSBmb3IgaGlnaC1kaW1lbnNpb25hbCBjb3ZhcmlhdGVzCkJheWVzTGFzc29maXQgPSBwc2JjR3JvdXA6OnBzYmNHTChzdXJ2T2JqLCBwcmlvclBhcmEsIGluaXRpYWwsIHJ3ID0gVFJVRSwgbWNtY1BhcmEsIG51bS5yZXBzID0gMTAwLCB0aGluID0gMSwgY2hhaW4gPSAxKQojIGJ1cm4taW4gdGhlIGZpcnN0IGhhbGYgTUNNQyBpdGVyYXRpb25zCmJldGFfcCA9IEJheWVzTGFzc29maXQkYmV0YS5wWy0oMTo1MSksIF0KYmV0YV9tZWFuID0gY29sTWVhbnMoYmV0YV9wKQpiZXRhX0wgPSBhcHBseShiZXRhX3AsIDIsIHF1YW50aWxlLCAwLjAyNSkKYmV0YV9VID0gYXBwbHkoYmV0YV9wLCAyLCBxdWFudGlsZSwgMC45NzUpCnRibCA9IGRhdGEuZnJhbWUodGVybSA9IGNvbG5hbWVzKHgpLCBlc3RpbWF0ZSA9IGJldGFfbWVhbiwgIGNvbmYubG93ID0gYmV0YV9MLCAgY29uZi5oaWdoID0gYmV0YV9VKQp0YmwkdGVybSA9IGZhY3Rvcih0YmwkdGVybSwgbGV2ZWxzID0gdGJsJHRlcm0pCgpHR2FsbHk6OmdnY29lZih0YmwpICsgeGxhYihleHByZXNzaW9uKFBvc3RlcmlvciB+fiBiZXRhKSkgKyB5bGFiKCIiKQpgYGAKYGBge3IsIGVjaG89RkFMU0V9CnBkZigiVENHQV9iYXllc0xhc3NvLnBkZiIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gNikKR0dhbGx5OjpnZ2NvZWYodGJsKSArIHhsYWIoZXhwcmVzc2lvbihQb3N0ZXJpb3Igfn4gYmV0YSkpICsgeWxhYigiIikKZGV2Lm9mZigpCmBgYAohW19Fc3RpbWF0ZXMgb2YgcmVncmVzc2lvbiBjb2VmZmljaWVudHMgYnkgYSBwZW5hbGl6ZWQgc2VtaXBhcmFtZXRyaWMgQmF5ZXNpYW4gQ294IG1vZGVsIHdpdGggTGFzc28gcHJpb3IuIFNvbGlkIGRvdHMgaW5kaWNhdGUgdGhlIHBvc3RlcmlvciBtZWFuIG92ZXIgTUNNQyBpdGVyYXRpb25zIChleGNsdWRpbmcgYnVybi1pbiBwZXJpb2QpLCBhbmQgaG9yaXpvbnRhbCBsaW5lcyBzaG93IHRoZSBjb3JyZXNwb25kaW5nIDk1JSBjcmVkaWJpbGl0eSBpbnRlcnZhbHMuX10oZmlnL1RDR0FfYmF5ZXNsYXNzby5wbmcpe3dpZHRoPTUwJX0KCjxicj4KCk5vdGUgdGhhdCAqKnBzYmNHcm91cCoqIGNhbm5vdCBkaXN0aW5ndWlzaCBtYW5kYXRvcnkgKHVucGVuYWxpemVkKSBjb3ZhcmlhdGVzIHdpdGggb21pY3MgZmVhdHVyZXMsIHNlZSBAWnVja25pY2syMDE1IGZvciBhbiBleHRlbmRlZCBCYXllc2lhbiBMYXNzbyBDb3ggbW9kZWwuIApUaGUgZm9sbG93aW5nIGNvZGUgaW1wbGVtZW50cyB0aGUgQmF5ZXNpYW4gTGFzc28gQ294IG1vZGVsIHdpdGggbWFuZGF0b3J5IGNvdmFyaWF0ZXMgdGhyb3VnaCB0aGUgYFJgIHBhY2thZ2UgWyoqcHNiY1NwZWVkVXAqKl0oaHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT1wc2JjU3BlZWRVcCkgW0BaaGFvMjAyM10uCgpgYGB7cn0KIyBCYXllc2lhbiBDb3ggbW9kZWwgd2l0aCBMYXNzbyBwcmlvciBhbmQgbWFuZGF0b3J5IGNvdmFyaWF0ZXMKc2V0LnNlZWQoMTIzKQpzdXJ2T2JqTSA9IGxpc3QodCA9IGNsaW4kdGltZSwgZGkgPSBjbGluJHN0YXR1cywgeCA9IHhbLCBjKDM6NTIsIDE6MildKQpwcmlvclBhcmEgPSBsaXN0KCdldGEwJyA9IDEsICdrYXBwYTAnID0gMSwgJ2MwJyA9IDIsICdyJyA9IDAuNSwgJ2RlbHRhJyA9IDAuMDAwMSkKQmF5ZXNMYXNzb01maXQgPC0gcHNiY1NwZWVkVXA6OnBzYmNTcGVlZFVwKHN1cnZPYmpNLCBwID0gNTAsIHEgPSAyLCBoeXBlcnBhciA9IHByaW9yUGFyYSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuSXRlciA9IDEwMCwgYnVybmluID0gNTAsIHRoaW4gPSAxLCBydyA9IEZBTFNFLCBvdXRGaWxlUGF0aCA9ICJ0bXAiKQpwbG90KEJheWVzTGFzc29NZml0KQpgYGAKYGBgClJ1bm5pbmcgTUNNQyBpdGVyYXRpb25zIC4uLgpbIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyNdIDEwMCUKRE9ORSwgZXhpdGluZyEgCmBgYApgYGB7ciwgZWNobz1GQUxTRX0KcGRmKCJUQ0dBX2JheWVzTGFzc29NLnBkZiIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gNikKcGxvdChCYXllc0xhc3NvTWZpdCkKZGV2Lm9mZigpCmBgYAohW19Fc3RpbWF0ZXMgb2YgcmVncmVzc2lvbiBjb2VmZmljaWVudHMgYnkgYSBwZW5hbGl6ZWQgc2VtaXBhcmFtZXRyaWMgQmF5ZXNpYW4gQ294IG1vZGVsIHdpdGggTGFzc28gcHJpb3IgYW5kIHVucGVuYWxpemVkIGNvdmFyaWF0ZXMuIFNvbGlkIGRvdHMgaW5kaWNhdGUgdGhlIHBvc3RlcmlvciBtZWFuIG92ZXIgTUNNQyBpdGVyYXRpb25zIChleGNsdWRpbmcgYnVybi1pbiBwZXJpb2QpLCBhbmQgaG9yaXpvbnRhbCBsaW5lcyBzaG93IHRoZSBjb3JyZXNwb25kaW5nIDk1JSBjcmVkaWJpbGl0eSBpbnRlcnZhbHMuX10oZmlnL1RDR0FfYmF5ZXNsYXNzb00ucG5nKXt3aWR0aD01MCV9Cgo8YnI+CgpJbiB0aGUgYFJgIHBhY2thZ2UgWyoqcHNiY0dyb3VwKipdKGh0dHBzOi8vQ1JBTi5SLXByb2plY3Qub3JnL3BhY2thZ2U9cHNiY0dyb3VwKSBbQExlZTIwMjFdLCBmdW5jdGlvbiBgcHNiY0VOKClgIGltcGxlbWVudHMgQmF5ZXNpYW4gQ294IG1vZGVscyB3aXRoIEVsYXN0aWMgTmV0IHByaW9yIGZvciBmZWF0dXJlIHNlbGVjdGlvbiB3aXRoIGdyb3VwaW5nIGVmZmVjdCBvZiBjb3JyZWxhdGVkIGZlYXR1cmVzLgpGdW5jdGlvbiBgcHNiY0ZMKClgIGltcGxlbWVudHMgQmF5ZXNpYW4gQ294IG1vZGVscyB3aXRoIGZ1c2VkIExhc3NvIHByaW9yLgoKYGBge3J9CiMgQmF5ZXNpYW4gQ294IG1vZGVsIHdpdGggRWxhc3RpYyBOZXQgcHJpb3IKc2V0LnNlZWQoMTIzKQojIHNldCBoeXBlcnBhcmFtZXRlcnMKIyBMYXJnZXIgcmF0aW8gcjEvZGVsdGExIGZvcmNlcyB0aGUgcG9zdGVyaW9yIGJldGFzIHRvIGJlIG1vcmUgY29uY2VudHJhdGVkIGF0IDAKIyBMYXJnZXIgcmF0aW8gcjIvZGVsdGEyIGZvcmNlcyBzdHJvbmdlciBncm91cGluZyBlZmZlY3Qgb2YgY292YXJpYXRlcwpwcmlvclBhcmEgPSBsaXN0KCdldGEwJyA9IDEsICdrYXBwYTAnID0gMSwgJ2MwJyA9IDIsICdyMScgPSAwLjEsICdyMicgPSAxLCAKICAgICAgICAgICAgICAgICAgJ2RlbHRhMScgPSAwLjEsICdkZWx0YTInID0gMSwgJ3MnID0gcywgJ0onID0gbGVuZ3RoKHMpKQojIHNldCBNQ01DIHBhcmFtZXRlcnMKbWNtY1BhcmEgPSBsaXN0KCdudW1CZXRhJyA9IHAsICdiZXRhLnByb3AudmFyJyA9IDEpCiMgc2V0IGluaXRpYWwgdmFsdWVzIG9mIGh5cGVycGFyYW1ldGVycwppbml0aWFsID0gbGlzdCgnYmV0YS5pbmknID0gcmVwKDAsIHApLCAnbGFtYmRhMVNxJyA9IDEsICdsYW1iZGEyJyA9IDEsICdzaWdtYVNxJyA9IHJ1bmlmKDEsIDAuMSwgMTApLAogICAgICAgICAgICAgICAgJ3RhdVNxJyA9IHJleHAocCwgcmF0ZSA9IDEgLyAyKSwgJ2gnID0gcmdhbW1hKHByaW9yUGFyYSRKLCAxLCAxKSkKIyBpbiByZWFsIGFwcGxpY2F0aW9uLCAnbnVtLnJlcHMnIHNob3VsZCBiZSBsYXJnZSBlbm91Z2ggKGUuZy4gMjAwMDAsIDQwMDAwKSBhbmQgJ2NoYWluJyB0byBiZSA+IDEKQmF5ZXNFTmZpdCA9IHBzYmNFTihzdXJ2T2JqLCBwcmlvclBhcmEsIGluaXRpYWwsIHJ3ID0gRkFMU0UsIG1jbWNQYXJhLCBudW0ucmVwcyA9IDEwMCwgdGhpbiA9IDEsIGNoYWluID0gMSkKIyBidXJuLWluIHRoZSBmaXJzdCBoYWxmIE1DTUMgaXRlcmF0aW9ucwpFTl9iZXRhX3AgPSBCYXllc0VOZml0JGJldGEucFs1MjoxMDEsIF0KY29sbmFtZXMoRU5fYmV0YV9wKSA9IGNvbG5hbWVzKHgpCnBzYmNTcGVlZFVwOjo6cGxvdC5wc2JjU3BlZWRVcChFTl9iZXRhX3ApCmBgYApgYGB7ciwgZWNobz1GQUxTRX0KcGRmKCJUQ0dBX2JheWVzRU4ucGRmIiwgd2lkdGggPSA0LCBoZWlnaHQgPSA2KQpwc2JjU3BlZWRVcDo6OnBsb3QucHNiY1NwZWVkVXAoRU5fYmV0YV9wKQpkZXYub2ZmKCkKYGBgCiFbX0VzdGltYXRlcyBvZiByZWdyZXNzaW9uIGNvZWZmaWNpZW50cyBieSBhIHBlbmFsaXplZCBzZW1pcGFyYW1ldHJpYyBCYXllc2lhbiBDb3ggbW9kZWwgd2l0aCBFbGFzdGljIE5ldCBwcmlvci4gU29saWQgZG90cyBpbmRpY2F0ZSB0aGUgcG9zdGVyaW9yIG1lYW4gb3ZlciBNQ01DIGl0ZXJhdGlvbnMgKGV4Y2x1ZGluZyBidXJuLWluIHBlcmlvZCksIGFuZCBob3Jpem9udGFsIGxpbmVzIHNob3cgdGhlIGNvcnJlc3BvbmRpbmcgOTUlIGNyZWRpYmlsaXR5IGludGVydmFscy5fXShmaWcvVENHQV9iYXllc0VOLnBuZyl7d2lkdGg9NTAlfQoKPGJyPgoKQSBwZW5hbGl6ZWQgc2VtaXBhcmFtZXRyaWMgQmF5ZXNpYW4gQ294IG1vZGVsIHdpdGggZG91YmxlIGV4cG9uZW50aWFsIHNwaWtlLWFuZC1zbGFiIHByaW9yIGlzIGltcGxlbWVudGVkIGluIHRoZSBgUmAgcGFja2FnZSBbKipCaEdMTSoqXShodHRwczovL2dpdGh1Yi5jb20vbnlpdWFiL0JoR0xNLmdpdCkgW0BZaTIwMTldLiBOb3RlIHRoYXQgKipCaEdMTSoqIHByb3ZpZGVzIGZyZXF1ZW50aXN0IGNvbmZpZGVuY2UgaW50ZXJ2YWxzIG9mIHRoZSBwb3N0ZXJpb3IgbW9kZSBvZiB0aGUgY29lZmZpY2llbnRzLgoKYGBge3J9CiMgcGVuYWxpemVkIHNlbWlwYXJhbWV0cmljIEJheWVzaWFuIENveCBtb2RlbCB3aXRoIChkb3VibGUgZXhwb25lbnRpYWwpIHNwaWtlLWFuZC1zbGFiIHByaW9yCnlfc3VydiA9IFN1cnYoY2xpbiR0aW1lLCBjbGluJHN0YXR1cykKeF9kYXRhZnJhbWUgPSBhcy5kYXRhLmZyYW1lKHgpCnNldC5zZWVkKDEyMykKQmF5ZXNmaXQgPSBCaEdMTTo6YmNveHBoKHlfc3VydiB+IC4sIHhfZGF0YWZyYW1lLCBwcmlvciA9IG1kZSgwLCAwLjAxLCAwLjgpLCBjb250cm9sID0gY294cGguY29udHJvbChpdGVyLm1heCA9IDIwMCkpCkJoR0xNOjpwbG90LmJoKEJheWVzZml0LCBjb2wucHRzID0gYygicmVkIiwgImJsdWUiKSwgbWFpbiA9ICJDb3ggd2l0aCBtaXh0dXJlIGRvdWJsZSBleHBvbmVudGlhbFxuIikgCmBgYApgYGB7ciwgZWNobz1GQUxTRX0KcGRmKCJUQ0dBX2JheWVzU3Bpa2VTbGFiLnBkZiIsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNSkKcGFyKG1hciA9IGMoMywgOCwgNCwgNCkpCkJoR0xNOjpwbG90LmJoKEJheWVzZml0LCBjb2wucHRzID0gYygicmVkIiwgImJsdWUiKSwgbWFpbiA9ICJDb3ggd2l0aCBtaXh0dXJlIGRvdWJsZSBleHBvbmVudGlhbFxuIikgCmRldi5vZmYoKQpgYGAKIVtfQ29lZmZpY2llbnQgZXN0aW1hdGVzIG9mIGEgcGVuYWxpemVkIHNlbWlwYXJhbWV0cmljIEJheWVzaWFuIENveCBtb2RlbCB3aXRoIChkb3VibGUgZXhwb25lbnRpYWwpIHNwaWtlLWFuZC1zbGFiIHByaW9yLiBTb2xpZCBkb3RzIGRlbm90ZSB0aGUgcG9zdGVyaW9yIG1vZGUgb2YgdGhlIGNvZWZmaWNpZW50cyBhbmQgbGluZXMgZGVub3RlIHRoZSA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbHMuIFJlZCBjb2xvcmVkIHRleHQgb24gdGhlIHJpZ2h0IHNpZGUgbWFyayB0aGUgc2lnbmlmaWNhbnQgZmVhdHVyZXMgd2l0aCAkcCA8IDAuMDUkLl9dKGZpZy9UQ0dBX2JheWVzU3Bpa2VTbGFiLnBuZyl7d2lkdGg9NjAlfQoKPGJyPgoKIyBTdXJ2aXZhbCBtb2RlbCB2YWxpZGF0aW9uCgpUaGUgaWRlYWwgZXZhbHVhdGlvbiBvZiBhIHByb2dub3N0aWMgbW9kZWwgaXMgYmFzZWQgb24gY29tcGxldGVseSBpbmRlcGVuZGVudCB2YWxpZGF0aW9uIGRhdGEsIHNpbmNlIGhpZ2gtZGltZW5zaW9uYWwgc3Vydml2YWwgbW9kZWxzIGJ1aWx0IG9uIHRoZSB0cmFpbmluZyBkYXRhIGNhbiBiZSBvdmVyZml0dGVkLiAKSWYgdGhlcmUgYXJlIG5vIGluZGVwZW5kZW50IHZhbGlkYXRpb24gZGF0YSwgaXQgaXMgcmVjb21tZW5kZWQgdG8gdXNlIHJlc2FtcGxpbmctYmFzZWQgbWV0aG9kcyBmb3IgZXN0aW1hdGluZyB0aGUgKip1bmNlcnRhaW50eSoqIG9mIHRoZSBtb2RlbOKAmXMgcHJlZGljdGlvbiBwZXJmb3JtYW5jZS4gClRoaXMgY2FuIGJlIGRvbmUgZm9yIGV4YW1wbGUgYnkgcmVwZWF0ZWRseSBzcGxpdHRpbmcgdGhlIGRhdGFzZXQgdG8gdHJhaW5pbmcvdmFsaWRhdGlvbiBzZXRzIGFuZCBldmFsdWF0aW5nIGEgbW9kZWzigJlzIHBlcmZvcm1hbmNlIG9uIHRoZSBkaWZmZXJlbnQgdmFsaWRhdGlvbiBzZXRzIHVzaW5nIHZhcmlvdXMgZXZhbHVhdGlvbiBtZXRyaWNzLiAKCjo6OnsuZ3JlZW4tYm94fQpUbyB2YWxpZGF0ZSBhIHByZWRpY3Rpb24gbW9kZWwgc3lzdGVtYXRpY2FsbHksIHRoZSBwcmVkaWN0aXZlIHBlcmZvcm1hbmNlIG9mIHRoZSBtb2RlbCBpcyBjb21tb25seSBhZGRyZXNzZWQgYnkKCiAgLSAqKkRpc2NyaW1pbmF0aW9uKio6IHRoZSBhYmlsaXR5IG9mIHRoZSBtb2RlbCB0byBkaXN0aW5ndWlzaCBiZXR3ZWVuIGxvdyBhbmQgaGlnaCByaXNrIHBhdGllbnRzCiAgLSAqKkNhbGlicmF0aW9uKio6IHRoZSBhZ3JlZW1lbnQgYmV0d2VlbiB0aGUgb2JzZXJ2ZWQgYW5kIHByZWRpY3RlZCBzdXJ2aXZhbCBwcm9iYWJpbGl0aWVzCiAgLSAqKk92ZXJhbGwgcGVyZm9ybWFuY2UqKjogdGhlIGRpc3RhbmNlIGJldHdlZW4gdGhlIG9ic2VydmVkIGFuZCBwcmVkaWN0ZWQgc3Vydml2YWwgcHJvYmFiaWxpdGllcwo6OjoKClRoZSBwZXJmb3JtYW5jZSBtZXRyaWNzIGNhbiBiZSAqdGltZS1kZXBlbmRlbnQqIG9yICp0aW1lLWluZGVwZW5kZW50Kiwgd2l0aCB0aGUgdGltZS1kZXBlbmRlbnQgbWV0cmljcyBiZWluZyBtb3JlIGluZm9ybWF0aXZlIGluIGdlbmVyYWwgY29tcGFyZWQgdG8gaW50ZWdyYXRlZCBtZWFzdXJlcyAoaS5lLiBldmFsdWF0ZWQgYWNyb3NzIG1hbnkgdGltZSBwb2ludHMpLgpGb3Igc3Vydml2YWwgZGF0YSwgd2UgY2FuIGFzc2VzcyB0aGUgKipkaXNjcmltaW5hdG9yeSBwb3dlcioqIG9mIGEgbW9kZWwgKGkuZS4gaG93IHdlbGwgZG9lcyBpdCByYW5rcyBwYXRpZW50cykgb3IgaG93IHdlbGwgYSBtb2RlbCBpcyAqKmNhbGlicmF0ZWQqKiAoaS5lLiBob3cgY2xvc2VseSB0aGUgcHJlZGljdGVkIHN1cnZpdmFsIHByb2JhYmlsaXRpZXMgYWdyZWUgbnVtZXJpY2FsbHkgd2l0aCB0aGUgYWN0dWFsIHN1cnZpdmFsIG91dGNvbWVzKS4KRm9yIGV4YW1wbGUsIG1lYXN1cmVzIHN1Y2ggYXMgdGhlIHJlY2VpdmVyIG9wZXJhdGluZyBjaGFyYWN0ZXJpc3RpYyAoUk9DKSBjdXJ2ZSwgdGhlIChpbnRlZ3JhdGVkKSBhcmVhIHVuZGVyIHRpbWUtc3BlY2lmaWMgUk9DIGN1cnZlcyAoKipBVUMqKiwgQEhlYWdlcnR5MjAwNSkgYW5kIHRoZSBjb25jb3JkYW5jZSBpbmRleCAoKipDLWluZGV4KiosIEBIYXJyZWxsMTk4MikgYXJlIG1lYXN1cmVzIG9mIGRpc2NyaW1pbmF0aW9uLCB3aGlsZSB0aGUgcmlnaHQtY2Vuc29yZWQgbG9nYXJpdGhtaWMgbG9zcyAoKipSQ0xMKiosIEBBdmF0aTIwMjApIGFuZCB0aGUgd2VsbC1rbm93biAqKkJyaWVyIHNjb3JlKiogW0BHcmFmMTk5OV0gYXJlIHVzZWQgdG8gZXZhbHVhdGUgYm90aCBkaXNjcmltaW5hdGlvbiBhbmQgY2FsaWJyYXRpb24gcGVyZm9ybWFuY2UuCgojIyBNb2RlbCBldmFsdWF0aW9uIChjbGFzc2ljKSB7LX0KCjo6OnsuZ3JlZW4tYm94fQonQ2xhc3NpYycgaGVyZSByZWZlcnMgdG8gdGhlIHVzZSBvZiBtYW51YWwgYFJgIGNvZGUgaW4gY29tYmluYXRpb24gd2l0aCBtYW55IHNlcGFyYXRlIGBSYCBwYWNrYWdlcyB3aGljaCBoYXZlIGJlZW4gcm91dGluZWx5IHVzZWQgaW4gYWNhZGVtaWEgdGhlIGxhdGVzdCAxMCsgeWVhcnMgZm9yIGV2YWx1YXRpbmcgc3Vydml2YWwgbW9kZWxzLgo6OjoKClRvIGV2YWx1YXRlIHRoZSBwZXJmb3JtYW5jZSBvZiBhIHN0YXRpc3RpY2FsIG1vZGVsLCB3ZSBmaXJzdCBzcGxpdCB0aGUgZGF0YSBpbnRvIHRyYWluaW5nIGFuZCB2YWxpZGF0aW9uIGRhdGEgc2V0cy4KRm9yIGV4YW1wbGUsIHdlIGNhbiByYW5kb21seSBzcGxpdCB0aGUgMTA0NyBCUkNBIHBhdGllbnRzIGZyb20gVENHQSBpbnRvICQ4MFwlJCBhcyB0cmFpbmluZyBzZXQgYW5kICQyMFwlJCBhcyB2YWxpZGF0aW9uIHNldC4KCmBgYHtyfQpzZXQuc2VlZCgxMjMpCm4gPSBucm93KHgpCmlkeCA9IHNhbXBsZSgxOm4sIG4gKiAwLjgsIHJlcGxhY2UgPSBGQUxTRSkKeF90cmFpbiA9IHhbaWR4LCBdCnlfdHJhaW4gPSB5W2lkeCwgXQp4X3ZhbGlkYXRlID0geFstaWR4LCBdCnlfdmFsaWRhdGUgPSB5Wy1pZHgsIF0KYGBgCgo6Ojp7LmluZm8tYm94IC5ub3RlfQpUaGUgJDIwXCUkIHNwbGl0IG9mIGEgZGF0YXNldCBpcyBvZnRlbiBub3QgY29uc2lkZXJlZCBhbiAqKmluZGVwZW5kZW50KiogZGF0YXNldCBhbmQgKipyZXNhbXBsaW5nLWJhc2VkIG1ldGhvZHMqKiBzaG91bGQgYmUgdXNlZCBpbiBzdWNoIGNhc2VzIHRvIHByb3ZpZGUgYW4gdW5iaWFzZWQgZXN0aW1hdGUgb2YgdGhlIHByZWRpY3RpdmUgYWNjdXJhY3kgb2YgYSBwcm9nbm9zdGljIG1vZGVsLgo6OjoKCiMjIyBEaXNjcmltaW5hdGlvbiBtZXRyaWNzIHstfQoKPGZvbnQgc2l6ZT0iNCI+ICoqR29vZG5lc3Mtb2YtZml0KiogPC9mb250PiAKClRoZSBzaW1wbGVzdCB3YXkgdG8gZGVtb25zdHJhdGUgdGhlIHByb2dub3N0aWMgcG93ZXIgb2YgYSBzdXJ2aXZhbCBtb2RlbCBpcyB0byBkaWNob3RvbWl6ZSB0aGUgcHJvZ25vc3RpYyBzY29yZXMgKGkuZS4sIGxpbmVhciBwcmVkaWN0b3IgJGxwJCBpbiB0aGUgQ294IG1vZGVsKSBieSBtZWRpYW4gdmFsdWUsIGFuZCB0aGVuIHRvIHVzZSBhIGxvZy1yYW5rIHRlc3QgdG8gY29tcGFyZSB0aGUgc3Vydml2YWwgY3VydmVzIG9mIHRoZSBwYXRpZW50cyBpbiB0aGUgdHdvIGdyb3Vwcy4KV2UgdXNlIHRoZSBidWlsdCBtb2RlbCB0byBwcmVkaWN0IHRoZSBwcm9nbm9zdGljIHNjb3JlcyBiYXNlZCBvbiB0aGUgJDIwXCUkIHZhbGlkYXRpb24gZGF0YS4KVGhlIGZvbGxvd2luZyBjb2RlIHNob3dzIHRoZSAqKmdvb2RuZXNzLW9mLWZpdCoqIG9mIGEgTGFzc28gQ294IG1vZGVsIHdpdGggdGhlIEJSQ0EgcGF0aWVudHMgc3Vydml2YWwgYW5kIFBBTTUwIG1STkEtU2VxIGRhdGEgZnJvbSBUQ0dBLgoKYGBge3J9CiMgdHJhaW4gYSBMYXNzbyBDb3ggbW9kZWwsIHNpbWlsYXJseSBmb3Igb3RoZXIgQ294LXR5cGUgbW9kZWxzCnNldC5zZWVkKDEyMykKY3ZmaXQgPSBjdi5nbG1uZXQoeF90cmFpbiwgeV90cmFpbiwgZmFtaWx5ID0gImNveCIsIG5mb2xkcyA9IDUsIHBlbmFsdHkuZmFjdG9yID0gcGYpCnByZWRfbHAgPSBwcmVkaWN0KGN2Zml0LCBuZXd4ID0geF92YWxpZGF0ZSwgcyA9IGN2Zml0JGxhbWJkYS5taW4sIHR5cGUgPSAibGluayIpCgojIGRpY2hvdG9taXplIGJ5IHByb2dub3N0aWMgc2NvcmVzIChsaW5lYXIgcHJlZGljdG9yKSAgYnkgbWVkaWFuIHRvIGRpdmlkZSB0aGUgdmFsaWRhdGlvbiBwYXRpZW50cyBpbnRvIHR3byBncm91cHMKZ3JvdXBfZGljaG90b21pemUgPSBhcy5udW1lcmljKHByZWRfbHAgPiBtZWRpYW4ocHJlZF9scCkpCgojIGRyYXcgdHdvIHN1cnZpdmFsIGN1cnZlcyBiYXNlZCBvbiBLTSBlc3RpbWF0aW9uIGFuZCBjb21wYXJlIHRoZW0gYnkgYSBsb2ctcmFuayB0ZXN0CmRhdF90bXAgPSBkYXRhLmZyYW1lKHRpbWUgPSB5X3ZhbGlkYXRlWywgMV0sIHN0YXR1cyA9IHlfdmFsaWRhdGVbLCAyXSwgZ3JvdXAgPSBncm91cF9kaWNob3RvbWl6ZSkKc2ZpdCA9IHN1cnZmaXQoU3Vydih0aW1lLCBzdGF0dXMpIH4gZ3JvdXAsIGRhdGEgPSBkYXRfdG1wKQoKZ2dzdXJ2ID0gZ2dzdXJ2cGxvdChzZml0LCBjb25mLmludCA9IFRSVUUsIHJpc2sudGFibGUgPSBUUlVFLCAKICAgICAgICAgICB4bGFiID0gIlRpbWUgc2luY2UgZGlhZ25vc2lzICh5ZWFyKSIsIGxlZ2VuZCA9IGMoLjIsIC4zKSwKICAgICAgICAgICBsZWdlbmQubGFicyA9IGMoIkxvdyByaXNrIiwgIkhpZ2ggcmlzayIpLCBsZWdlbmQudGl0bGUgPSAiRGljaG90b21pemVkIGdyb3VwcyIsICAKICAgICAgICAgICByaXNrLnRhYmxlLnkudGV4dC5jb2wgPSBUUlVFLCByaXNrLnRhYmxlLnkudGV4dCA9IEZBTFNFKQpnZ3N1cnYkcGxvdCA9IGdnc3VydiRwbG90ICsgCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMi42LCB5ID0gLjAzLCBsYWJlbCA9IHBhc3RlMCgiTG9nLXJhbmsgdGVzdDpcbiIsIHN1cnZfcHZhbHVlKHNmaXQpJHB2YWwudHh0KSkKZ2dzdXJ2JHRhYmxlID0gZ2dzdXJ2JHRhYmxlICsgbGFicyh5ID0gIkRpY2hvdG9taXplZFxuIGdyb3VwcyIpCmdnc3VydgpgYGAKYGBge3IsIGVjaG89RkFMU0V9CnBkZigiVENHQV9zdXJ2X2ttX2xhc3NvLnBkZiIsIHdpZHRoID0gNSwgaGVpZ2h0ID0gNSkKZ2dzdXJ2CmRldi5vZmYoKQpgYGAKIVtfS2FwbGFuLU1laWVyIGN1cnZlcyBvZiB0aGUgQlJDQSBwYXRpZW50cyBkYXRhIGRpY2hvdG9taXplZCBieSB0aGUgbWVkaWFuIG9mIHByb2dub3N0aWMgc2NvcmVzIChjYWxjdWxhdGVkIGZyb20gdGhlIExhc3NvIENveCBtb2RlbCB3aXRoIHBhdGllbnRzJyBzdXJ2aXZhbCBhbmQgbVJOQS1TZXEgZGF0YSkgaW50byB0d28gZ3JvdXBzLiBUaGUgbG9nLXJhbmsgdGVzdCBpcyB0byBjb21wYXJlIHRoZSB0d28gc3Vydml2YWwgZGlzdHJpYnV0aW9ucyBjb3JyZXNwb25kaW5nIHRvIHRoZSB0d28gZ3JvdXBzIG9mIHBhdGllbnRzLl9dKGZpZy9UQ0dBX3N1cnZfa21fbGFzc28ucG5nKXt3aWR0aD01MCV9Cgo8YnI+CgpUaGUgcHJvZ25vc3RpYyBzY29yZXMgY2FuIGFsc28gYmUgZGl2aWRlZCBpbnRvIHRocmVlIG9yIG1vcmUgZ3JvdXBzIGJhc2VkIG9uIHF1YW50aWxlcyBhbmQgdGhlIGxvZy1yYW5rIHRlc3QgY2FuIGJlIHVzZWQgdG8gY29tcGFyZSB0aGUgZGlmZmVyZW5jZSBvZiBtdWx0aXBsZSBzdXJ2aXZhbCBjdXJ2ZXMuCgpgYGB7cn0KZ3JvdXAgPSBwcmVkX2xwCmdyb3VwW3ByZWRfbHAgPj0gcXVhbnRpbGUocHJlZF9scCwgMiAvIDMpXSA9IDMKZ3JvdXBbcHJlZF9scCA+PSBxdWFudGlsZShwcmVkX2xwLCAxIC8gMykgJiBwcmVkX2xwIDwgcXVhbnRpbGUocHJlZF9scCwgMiAvIDMpXSA9IDIKZ3JvdXBbcHJlZF9scCA8IHF1YW50aWxlKHByZWRfbHAsIDEgLyAzKV0gPSAxCgojIGRyYXcgdHdvIHN1cnZpdmFsIGN1cnZlcyBiYXNlZCBvbiBLTSBlc3RpbWF0aW9uIGFuZCBjb21wYXJlIHRoZW0gYnkgYSBsb2ctcmFuayB0ZXN0CmRhdF90bXAgPSBkYXRhLmZyYW1lKHRpbWUgPSB5X3ZhbGlkYXRlWywgMV0sIHN0YXR1cyA9IHlfdmFsaWRhdGVbLCAyXSwgZ3JvdXAgPSBncm91cCkKc2ZpdCA9IHN1cnZmaXQoU3Vydih0aW1lLCBzdGF0dXMpIH4gZ3JvdXAsIGRhdGEgPSBkYXRfdG1wKQoKZ2dzdXJ2ID0gZ2dzdXJ2cGxvdChzZml0LCBjb25mLmludCA9IFRSVUUsIHJpc2sudGFibGUgPSBUUlVFLCAKICAgICAgICAgICB4bGFiID0gIlRpbWUgc2luY2UgZGlhZ25vc2lzICh5ZWFyKSIsIGxlZ2VuZCA9IGMoLjIsIC4zKSwKICAgICAgICAgICBsZWdlbmQubGFicyA9IGMoIkxvdyByaXNrIiwgIk1pZGRsZSByaXNrIiwgIkhpZ2ggcmlzayIpLCBsZWdlbmQudGl0bGUgPSAiR3JvdXBzIiwgIAogICAgICAgICAgIHJpc2sudGFibGUueS50ZXh0LmNvbCA9IFRSVUUsIHJpc2sudGFibGUueS50ZXh0ID0gRkFMU0UpCmdnc3VydiRwbG90ID0gZ2dzdXJ2JHBsb3QgKyAKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAzLjUsIHkgPSAuMDUsIGxhYmVsID0gcGFzdGUwKCJMb2ctcmFuayB0ZXN0OlxuIiwgc3Vydl9wdmFsdWUoc2ZpdCkkcHZhbC50eHQpKQpnZ3N1cnYKYGBgCmBgYHtyLCBlY2hvPUZBTFNFfQpwZGYoIlRDR0Ffc3Vydl9rbV9sYXNzbzIucGRmIiwgd2lkdGggPSA1LCBoZWlnaHQgPSA1KQpnZ3N1cnYKZGV2Lm9mZigpCmBgYAohW19LYXBsYW4tTWVpZXIgY3VydmVzIG9mIHRoZSBCUkNBIHBhdGllbnRzIGRhdGEgZGl2aWRlZCBieSAzMyUgYW5kIDY3JSBxdWFudGlsZXMgb2YgcHJvZ25vc3RpYyBzY29yZXMgKGNhbGN1bGF0ZWQgZnJvbSB0aGUgTGFzc28gQ294IG1vZGVsIHdpdGggcGF0aWVudHMnIHN1cnZpdmFsIGFuZCBtUk5BLVNlcSBkYXRhKSBpbnRvIHRocmVlIGdyb3Vwcy4gVGhlIGxvZy1yYW5rIHRlc3QgaXMgdG8gY29tcGFyZSB0aGUgdHdvIHN1cnZpdmFsIGRpc3RyaWJ1dGlvbnMgY29ycmVzcG9uZGluZyB0byB0aGUgdGhyZWUgZ3JvdXBzIG9mIHBhdGllbnRzLl9dKGZpZy9UQ0dBX3N1cnZfa21fbGFzc28yLnBuZyl7d2lkdGg9NTAlfQoKPGJyPgoKPGZvbnQgc2l6ZT0iNCI+ICoqUk9DIGN1cnZlKiogPC9mb250PiAKClRoZSBgUmAgcGFja2FnZSBbKipyaXNrc2V0Uk9DKipdKGh0dHBzOi8vQ1JBTi5SLXByb2plY3Qub3JnL3BhY2thZ2U9cmlza3NldFJPQykgW0BIZWFnZXJ0eTIwMDVdIGNhbiBlc3RpbWF0ZSBhIFJPQyBjdXJ2ZSBhdCBhbiBldmFsdWF0aW9uIHRpbWUgcG9pbnQuIApUaGUgZm9sbG93aW5nIGNvZGUgZHJhd3MgYSBST0MgY3VydmUgYXQgNS15ZWFycyBzdXJ2aXZhbCBldmFsdWF0aW9uIHRpbWUgcG9pbnQgZm9yIHRoZSAyMCUgVENHQSB2YWxpZGF0aW9uIGRhdGEgYW5kIGJhc2VkIG9uIGEgTGFzc28gQ294IG1vZGVsIGxlYXJuZWQgZnJvbSB0aGUgODAlIHRyYWluaW5nIGRhdGEuCgpgYGB7cn0KUk9DID0gcmlza3NldFJPQyhTdGltZSA9IHlfdmFsaWRhdGVbLCAxXSwgc3RhdHVzID0geV92YWxpZGF0ZVssIDJdLAogICAgICAgICAgICAgICAgIG1hcmtlciA9IHByZWRfbHAsIHByZWRpY3QudGltZSA9IDUsIG1ldGhvZCA9ICJDb3giLCAKICAgICAgICAgICAgICAgICBtYWluID0gIlJPQyBDdXJ2ZSIsIGNvbCA9ICJzZWFncmVlbjMiLCB0eXBlID0gInMiLCAKICAgICAgICAgICAgICAgICBsd2QgPSAyLCB4bGFiID0gIjEgLSBTcGVjaWZpY2l0eSIsIHlsYWIgPSAiU2Vuc2l0aXZpdHkiKSAKdGV4dCgwLjcsIDAuMiwgcGFzdGUoIkFVQyA9Iiwgcm91bmQoUk9DJEFVQywgMykpKQpgYGAKYGBge3IsIGVjaG89RkFMU0V9CnBkZigiVENHQV9zdXJ2X3JvYy5wZGYiLCBoZWlnaHQgPSAzLjksIHdpZHRoID0gMy40KQpST0MgPSByaXNrc2V0Uk9DKFN0aW1lID0geV92YWxpZGF0ZVssIDFdLCBzdGF0dXMgPSB5X3ZhbGlkYXRlWywgMl0sCiAgICAgICAgICAgICAgICAgbWFya2VyID0gcHJlZF9scCwgcHJlZGljdC50aW1lID0gNSwgbWV0aG9kID0gIkNveCIsIAogICAgICAgICAgICAgICAgIG1haW4gPSAiUk9DIEN1cnZlIiwgY29sID0gInNlYWdyZWVuMyIsIHR5cGUgPSAicyIsIAogICAgICAgICAgICAgICAgIGx3ZCA9IDIsIHhsYWIgPSAiMSAtIFNwZWNpZmljaXR5IiwgeWxhYiA9ICJTZW5zaXRpdml0eSIpIAp0ZXh0KDAuNywgMC4yLCBwYXN0ZSgiQVVDID0iLCByb3VuZChST0MkQVVDLCAzKSkpCmRldi5vZmYoKQpgYGAKIVtfUk9DIGN1cnZlIGVzdGltYXRlZCBhdCA1LXllYXJzIHN1cnZpdmFsIGV2YWx1YXRpb24gdGltZSBwb2ludCBmb3IgdGhlIDIwJSBUQ0dBIHZhbGlkYXRpb24gZGF0YSBhbmQgYmFzZWQgb24gYSBMYXNzbyBDb3ggbW9kZWwgbGVhcm5lZCBmcm9tIHRoZSA4MCUgdHJhaW5pbmcgZGF0YS4gVGhlIEFVQyB2YWx1ZSBpcyB0aGUgYXJlYSB1bmRlciB0aGUgUk9DIGN1cnZlLiBUaGUgZGlhZ29uYWwgbGluZSByZXByZXNlbnRzIHRoZSBwZXJmb3JtYW5jZSBvZiBhIHJhbmRvbSBwcmVkaWN0aW9uIG9mIHRoZSBvdXRjb21lIGV2ZW50IHdpdGggQVVDID0gMC41Ll9dKGZpZy9UQ0dBX3N1cnZfcm9jLnBuZyl7d2lkdGg9NDAlfQoKPGJyPgoKPGZvbnQgc2l6ZT0iNCI+ICoqVGltZS1kZXBlbmRlbnQgQVVDKiogPC9mb250PiAKCkJvdGggdGltZS1kZXBlbmRlbnQgYW5kIGludGVncmF0ZWQgQVVDcyBjYW4gYmUgZXN0aW1hdGVkIGJ5IHRoZSBgUmAgcGFja2FnZSBbKipyaXNrc2V0Uk9DKipdKGh0dHBzOi8vQ1JBTi5SLXByb2plY3Qub3JnL3BhY2thZ2U9cmlza3NldFJPQykuIApXZSBkZW1vbnN0cmF0ZSB0aGUgY2FsY3VsYXRpb24gYmFzZWQgb24gYm90aCB0cmFpbmluZyBhbmQgdmFsaWRhdGlvbiBkYXRhLgoKOjo6ey5pbmZvLWJveCAubm90ZX0KQSBDb3ggcHJvcG9ydGlvbmFsIGhhemFyZHMgbW9kZWwgKGFuZCBMYXNzbyBDb3ggYXMgYSBjb25zZXF1ZW5jZSkgaXMgYSBzZW1pLXBhcmFtZXRyaWMgbW9kZWwsIHdoaWNoIG1lYW5zIHRoYXQgaXQgZG9lcyBub3QgcHJvZHVjZSBzdXJ2aXZhbCBkaXN0cmlidXRpb24gcHJlZGljdGlvbnMgYnkgZGVmYXVsdC4KSG93ZXZlciwgdXNpbmcgdGhlIGZ1bmN0aW9uIGByaXNrc2V0Uk9DOjpDb3hXZWlnaHRzKClgIHlvdSBjYW4gdHJhbnNmb3JtIHRoZSBgY3YuZ2xtbmV0YCdzIG91dHB1dCBsaW5lYXIgcHJlZGljdG9ycyAoYGxwYCkgdG8gc3Vydml2YWwgZGlzdHJpYnV0aW9uIHByZWRpY3Rpb25zLgpUaGlzIHRyYW5zZm9ybWF0aW9uIGludGVybmFsbHkgdXNlcyB0aGUgQnJlc2xvdyBlc3RpbWF0b3IgZm9yIHRoZSBjdW11bGF0aXZlIGJhc2VsaW5lIGhhemFyZC4KOjo6CgpgYGB7cn0KIyB1bmlxdWUgZXZlbnQgdGltZXMgZm9yIHBhdGllbnRzIGluIHRoZSB0cmFpbmluZyBhbmQgdmFsaWRhdGlvbiBkYXRhIHNldHMKdXRpbWVzX3RyYWluID0gc29ydCh1bmlxdWUoeV90cmFpblt5X3RyYWluWywgMl0gPT0gMSwgMV0pKQp1dGltZXNfdmFsaWRhdGUgPSBzb3J0KHVuaXF1ZSh5X3ZhbGlkYXRlW3lfdmFsaWRhdGVbLCAyXSA9PSAxLCAxXSkpCgojIG1hcmtlcnMgZnJvbSB0aGUgZXN0aW1hdGVkIGxpbmVhciBwcmVkaWN0b3JzIG9mIGEgTGFzc28gQ294IG1vZGVsCnByZWRfbHBfdHJhaW4gPSBwcmVkaWN0KGN2Zml0LCBuZXd4ID0geF90cmFpbiwgcyA9IGN2Zml0JGxhbWJkYS5taW4sIHR5cGUgPSAibGluayIpCnByZWRfbHBfdmFsaWRhdGUgPSBwcmVkaWN0KGN2Zml0LCBuZXd4ID0geF92YWxpZGF0ZSwgcyA9IGN2Zml0JGxhbWJkYS5taW4sIHR5cGUgPSAibGluayIpCgojIyBjb21wdXRlIHRpbWUtZGVwZW5kZW50IEFVQwpBVUNfdHJhaW4gPSByZXAoTkEsIGxlbmd0aCh1dGltZXNfdHJhaW4pKQpBVUNfdmFsaWRhdGUgPSByZXAoTkEsIGxlbmd0aCh1dGltZXNfdmFsaWRhdGUpKQpmb3IgKGogaW4gMTpsZW5ndGgodXRpbWVzX3RyYWluKSkgewogIG91dCA9IHJpc2tzZXRST0M6OkNveFdlaWdodHMobWFya2VyID0gcHJlZF9scF90cmFpbiwgU3RpbWUgPSB5X3RyYWluWywgMV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHVzID0geV90cmFpblssIDJdLCBwcmVkaWN0LnRpbWUgPSB1dGltZXNfdHJhaW5bal0pCiAgQVVDX3RyYWluW2pdID0gb3V0JEFVQwp9CmZvciAoaiBpbiAxOmxlbmd0aCh1dGltZXNfdmFsaWRhdGUpKSB7CiAgb3V0ID0gcmlza3NldFJPQzo6Q294V2VpZ2h0cyhtYXJrZXIgPSBwcmVkX2xwX3ZhbGlkYXRlLCBTdGltZSA9IHlfdmFsaWRhdGVbLCAxXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0dXMgPSB5X3ZhbGlkYXRlWywgMl0sIHByZWRpY3QudGltZSA9IHV0aW1lc192YWxpZGF0ZVtqXSkKICBBVUNfdmFsaWRhdGVbal0gPSBvdXQkQVVDCn0KCiMgZHJhdyB0aGUgdGltZS1kZXBlbmRlbnQgQVVDIGZyb20gdGhlIHRyYWluaW5nIGFuZCB2YWxpZGF0aW9uIGRhdGEgc2V0cwpkYXRfQVVDID0gZGF0YS5mcmFtZSh0QVVDID0gYyhBVUNfdHJhaW4sIEFVQ192YWxpZGF0ZSksIAogICAgICAgICAgICAgICAgICAgICAgdGltZXMgPSBjKHV0aW1lc190cmFpbiwgdXRpbWVzX3ZhbGlkYXRlKSwKICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gYyhyZXAoIkFVQ190cmFpbiIsIGxlbmd0aChBVUNfdHJhaW4pKSwgcmVwKCJBVUNfdmFsaWRhdGUiLCBsZW5ndGgoQVVDX3ZhbGlkYXRlKSkpKQpnZ3Bsb3QoZGF0X0FVQywgYWVzKHRpbWVzLCB0QVVDLCBncm91cCA9IGdyb3VwLCBjb2xvciA9IGdyb3VwKSkgKyB4bGFiKCJFdmFsdWF0aW9uIHRpbWUgcG9pbnRzICh5ZWFyKSIpICsgeWxhYigiQVVDIikgKyB5bGltKDAuNSwgMSkgKwogIGdlb21fc3RlcChkaXJlY3Rpb24gPSAidmgiKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC43LCAwLjgpLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCmBgYApgYGB7ciwgZWNobz1GQUxTRX0KcGRmKCJUQ0dBX3N1cnZfYXVjX2xhc3NvLnBkZiIsIGhlaWdodCA9IDMsIHdpZHRoID0gMykKZ2dwbG90KGRhdF9BVUMsIGFlcyh0aW1lcywgdEFVQywgZ3JvdXAgPSBncm91cCwgY29sb3IgPSBncm91cCkpICsgeGxhYigiRXZhbHVhdGlvbiB0aW1lIHBvaW50cyAoeWVhcikiKSArIHlsYWIoIkFVQyIpICsgeWxpbSgwLjUsIDEpICsKICBnZW9tX3N0ZXAoZGlyZWN0aW9uID0gInZoIikgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuNywgMC44KSwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpkZXYub2ZmKCkKYGBgCiFbX1RpbWUtZGVwZW5kZW50IEFVQyBiYXNlZCBvbiBhIExhc3NvIENveCBtb2RlbCBhcHBsaWVkIHRvIHRoZSBCUkNBIHBhdGllbnRzIGRhdGEgZnJvbSBUQ0dBLiBUaGUgcmVkIGxpbmUgc2hvd3MgdGhlIFRpbWUtZGVwZW5kZW50IEFVQyBjYWxjdWxhdGVkIGZyb20gdGhlIDgwJSB0cmFpbmluZyBkYXRhLCBhbmQgdGhlIGdyZWVuIGxpbmUgc2hvd3MgdGhlIFRpbWUtZGVwZW5kZW50IEFVQyBjYWxjdWxhdGVkIGZyb20gdGhlIDIwJSB2YWxpZGF0aW9uIGRhdGEuX10oZmlnL1RDR0Ffc3Vydl9hdWNfbGFzc28ucG5nKXt3aWR0aD00MCV9Cgo8YnI+Cgo8Zm9udCBzaXplPSI0Ij4gKipJbnRlZ3JhdGVkIEFVQyoqIDwvZm9udD4gCgpUaGUgYFJgIHBhY2thZ2UgWyoqcmlza3NldFJPQyoqXShodHRwczovL0NSQU4uUi1wcm9qZWN0Lm9yZy9wYWNrYWdlPXJpc2tzZXRST0MpIFtASGVhZ2VydHkyMDA1XSBwcm92aWRlcyBmdW5jdGlvbiBgSW50ZWdyYXRlQVVDKClgIHRvIGVzdGltYXRlIGludGVncmF0ZWQgQVVDLgoKYGBge3J9CiMgQmVmb3JlIGNvbXB1dGluZyBpbnRlZ3JhdGVkIEFVQywgZmlyc3QgZXN0aW1hdGUgc3Vydml2YWwgcHJvYmFiaWxpdGllcyBhdCB1bmlxdWUgc3Vydml2YWwgdGltZXMKc3Vydl9wcm9iX3RyYWluID0gdW5pcXVlKHN1cnZmaXQoU3Vydih5X3RyYWluWywgMV0sIHlfdHJhaW5bLCAyXSkgfiAxKSRzdXJ2KQpzdXJ2X3Byb2JfdmFsaWRhdGUgPSB1bmlxdWUoc3VydmZpdChTdXJ2KHlfdmFsaWRhdGVbLCAxXSwgeV92YWxpZGF0ZVssIDJdKSB+IDEpJHN1cnYpCgojIyBpbnRlZ3JhdGVkIEFVQyAoZS5nLiBvdmVyIHRtYXg9MTAgeWVhcnMpIHRvIGdldCBjb25jb3JkYW5jZSBtZWFzdXJlIGJhc2VkIG9uIHRyYWluaW5nIGRhdGEKKGlBVUNfdHJhaW4gPSByaXNrc2V0Uk9DOjpJbnRlZ3JhdGVBVUMoQVVDX3RyYWluLCB1dGltZXNfdHJhaW4sIHN1cnZfcHJvYl90cmFpbiwgdG1heCA9IDEwKSkKYGBgCmBgYApbMV0gMC42Mjc5NjQ2CmBgYApgYGB7cn0KIyMgaW50ZWdyYXRlZCBBVUMgKGUuZy4gb3ZlciB0bWF4PTEwIHllYXJzKSB0byBnZXQgY29uY29yZGFuY2UgbWVhc3VyZSBiYXNlZCBvbiB2YWxpZGF0aW9uIGRhdGEKKGlBVUNfdmFsaWRhdGUgPSByaXNrc2V0Uk9DOjpJbnRlZ3JhdGVBVUMoQVVDX3ZhbGlkYXRlLCB1dGltZXNfdmFsaWRhdGUsIHN1cnZfcHJvYl92YWxpZGF0ZSwgdG1heCA9IDEwKSkKYGBgCmBgYApbMV0gMC42MzE4MjUzCmBgYAoKPGZvbnQgc2l6ZT0iNCI+ICoqVGltZS1kZXBlbmRlbnQgQy1pbmRleCoqIDwvZm9udD4gCgpUaGUgQy1pbmRleCBpcyBub3QgcHJvcGVyIGZvciAkdCQteWVhciBwcmVkaWN0aW9ucywgc2VlIEBCbGFuY2hlMjAxOS4KQ29uc2lkZXIgdXNpbmcgdGltZS1kZXBlbmRlbnQgQVVDIG9yIHRpbWUtZGVwZW5kZW50IEJyaWVyIHNjb3JlIGluc3RlYWQuCkZvciBhIHRpbWUtZGVwZW5kZW50IGRpc2NyaW1pbmF0aW9uIGluZGV4IGZvciBzdXJ2aXZhbCBkYXRhLCBzZWUgQEFudG9saW5pMjAwNS4KCjxmb250IHNpemU9IjQiPiAqKkMtaW5kZXgqKiA8L2ZvbnQ+IAoKVGhlIGBSYCBwYWNrYWdlIFsqKmdsbW5ldCoqXShodHRwczovL0NSQU4uUi1wcm9qZWN0Lm9yZy9wYWNrYWdlPWdsbW5ldCkgcHJvdmlkZXMgdGhlIGZ1bmN0aW9uIGBnbG1uZXQ6OkNpbmRleCgpYCB0byBlc3RpbWF0ZSBIYXJyZWxsJ3MgQy1pbmRleCBmcm9tIGEgImNveG5ldCIgb2JqZWN0LgpUaGUgYFJgIHBhY2thZ2UgWyoqc3VydkFVQyoqXShodHRwczovL0NSQU4uUi1wcm9qZWN0Lm9yZy9wYWNrYWdlPXN1cnZBVUMpIHByb3ZpZGVzIHRoZSBmdW5jdGlvbiBgc3VydkFVQzo6VW5vQygpYCB0byBlc3RpbWF0ZWQgVW5vJ3MgQy1pbmRleC4KU2VlIGFuIGV4YW1wbGUgY2FsY3VsYXRpb24gZm9yIGJvdGggQy1pbmRleGVzIHVzaW5nIGEgTGFzc28gQ294IG1vZGVsIGJlbG93LgoKYGBge3J9CnNldC5zZWVkKDEyMykKY3ZmaXQgPSBjdi5nbG1uZXQoeF90cmFpbiwgeV90cmFpbiwgZmFtaWx5ID0gImNveCIsIG5mb2xkcyA9IDUsIHBlbmFsdHkuZmFjdG9yID0gcGYpCnByZWQgPSBwcmVkaWN0KGN2Zml0LCBuZXd4ID0geF92YWxpZGF0ZSwgdHlwZSA9ICJsaW5rIiwgcyA9IGN2Zml0JGxhbWJkYS5taW4pCiMgSGFycmVsbCdzIEMtaW5kZXgKKENpbmRleF9IYXJyZWxsID0gQ2luZGV4KHByZWQgPSBwcmVkWywgMV0sIHkgPSB5X3ZhbGlkYXRlKSkKYGBgCmBgYApbMV0gMC43MjQ2NDY2CmBgYApgYGB7cn0KIyBVbm8ncyBDLWluZGV4CihDaW5kZXhfVW5vID0gc3VydkFVQzo6VW5vQyh5X3RyYWluLCB5X3ZhbGlkYXRlLCBwcmVkKSkKYGBgCmBgYApbMV0gMC41NzcyMDQxCmBgYAoKPGJyPgoKIyMjIENhbGlicmF0aW9uIG1ldHJpY3Mgey19CgpTZWUgYSBbY2FsaWJyYXRpb24gcGxvdF0oI3Nsb3BlQ2FsaSkgaW4gdGhlIGZvbGxvd2luZyBzZWN0aW9uIFtHcmFwaGljYWwgY29tcHV0YXRpb25dKCNncmFwaENvbXApLgoKPGJyPgoKIyMjIE92ZXJhbGwgbWV0cmljcyB7LX0KCjxmb250IHNpemU9IjQiPiAqKlRpbWUtZGVwZW5kZW50IEJyaWVyIHNjb3JlKiogPC9mb250PiAKClRoZSBgUmAgcGFja2FnZSBbKipyaXNrUmVncmVzc2lvbioqXShodHRwczovL0NSQU4uUi1wcm9qZWN0Lm9yZy9wYWNrYWdlPXJpc2tSZWdyZXNzaW9uKSBjYW4gYXNzZXNzIHRoZSBwcmVkaWN0aW9uIGVycm9yIGN1cnZlcyBvZiBzdXJ2aXZhbCBtb2RlbHMgYmFzZWQgb24gdGhlIHRpbWUtZGVwZW5kZW50IEJyaWVyIHNjb3JlLgpTaW1pbGFyIHRvIHRoZSB0aW1lLWRlcGVuZGVudCBBVUMsIG9uZSBuZWVkcyB0byBmaXJzdCBjYWxjdWxhdGUgdGhlIGxpbmVhciBwcmVkaWN0b3JzICgkbHAkKSBmcm9tIGEgZnJlcXVlbnRpc3Qgb3IgQmF5ZXNpYW4gQ294IG1vZGVsLCBhbmQgdGhlbiB1c2UgYHN1cnZpdmFsOjpjb3hwaCgpYCB0byByZWdyZXNzIHRoZSBzdXJ2aXZhbCBvdXRjb21lcyBvbiB0aGUgbGluZWFyIHByZWRpY3Rvciwgd2hpY2ggaXMgcHJlcGFyZWQgYXMgaW5wdXQgb2YgYHJpc2tSZWdyZXNzaW9uOjpTY29yZSgpYCB0byBlc3RpbWF0ZSB0aGUgKHRpbWUtZGVwZW5kZW50KSBCcmllciBzY29yZS4KCmBgYHtyfQojIyB0aW1lLWRlcGVuZGVudCBCcmllciBzY29yZQoKIyB1c2UgdGhlICh4X3RyYWluLCB5X3RyYWluKSA4MCUgc2FtcGxlcyBmb3IgdHJhaW5pbmcKIyBhbmQgdGhlICh4X3ZhbGlkYXRlLCB5X3ZhbGlkYXRlKSAyMCUgc2FtcGxlcyBmb3IgdGVzdGluZwoKeV90cmFpbl9zdXJ2ID0gU3Vydih5X3RyYWluWywgInRpbWUiXSwgeV90cmFpblssICJzdGF0dXMiXSkKeV92YWxpZGF0ZV9zdXJ2ID0gU3Vydih5X3ZhbGlkYXRlWywgInRpbWUiXSwgeV92YWxpZGF0ZVssICJzdGF0dXMiXSkKc2V0LnNlZWQoMTIzKQpjdmZpdCA9IGN2LmdsbW5ldCh4X3RyYWluLCB5X3RyYWluX3N1cnYsIGZhbWlseSA9ICJjb3giLCBuZm9sZHMgPSA1LCBwZW5hbHR5LmZhY3RvciA9IHBmKQpscF90cmFpbiA9IHByZWRpY3QoY3ZmaXQsIG5ld3ggPSB4X3RyYWluLCBzID0gY3ZmaXQkbGFtYmRhLm1pbiwgdHlwZSA9ICJsaW5rIikKbHBfdmFsaWRhdGUgPSBwcmVkaWN0KGN2Zml0LCBuZXd4ID0geF92YWxpZGF0ZSwgcyA9IGN2Zml0JGxhbWJkYS5taW4sIHR5cGUgPSAibGluayIpCgojIHByZXBhcmUgZGF0YSBmb3JtYXQgc3VpdGVkIGZvciBmdW5jdGlvbiBTY29yZSgpIGZyb20gdGhlIHJpc2tSZWdyZXNzaW9uIHBhY2thZ2UKZGF0YV90cmFpbiA9IGRhdGEuZnJhbWUodGltZSA9IHlfdHJhaW5bLCAidGltZSJdLCBzdGF0dXMgPSB5X3RyYWluWywgInN0YXR1cyJdLCBscCA9IGFzLnZlY3RvcihscF90cmFpbikpCmRhdGFfdmFsaWRhdGUgPSBkYXRhLmZyYW1lKHRpbWUgPSB5X3ZhbGlkYXRlWywgInRpbWUiXSwgc3RhdHVzID0geV92YWxpZGF0ZVssICJzdGF0dXMiXSwgbHAgPSBhcy52ZWN0b3IobHBfdmFsaWRhdGUpKQpsYXNzb190cmFpbiA9IGNveHBoKFN1cnYodGltZSwgc3RhdHVzKSB+IGxwLCBkYXRhID0gZGF0YV90cmFpbiwgeT1UUlVFLCB4ID0gVFJVRSkKbGFzc29fdmFsaWRhdGUgPSBjb3hwaChTdXJ2KHRpbWUsIHN0YXR1cykgfiBscCwgZGF0YSA9IGRhdGFfdmFsaWRhdGUsIHkgPSBUUlVFLCB4ID0gVFJVRSkKCiMgY2FsY3VsYXRlIEJyaWVyIHNjb3JlcyBiYXNlZCBvbiBib3RoIHRyYWluaW5nIGFuZCB2YWxpZGF0aW9uIGRhdGEKQnJpZXJfdHJhaW4gPSByaXNrUmVncmVzc2lvbjo6U2NvcmUobGlzdCgiQnJpZXJfdHJhaW4iID0gbGFzc29fdHJhaW4pLCBmb3JtdWxhID0gU3Vydih0aW1lLCBzdGF0dXMpIH4gMSwgZGF0YSA9IGRhdGFfdHJhaW4sIGNvbmYuaW50ID0gRkFMU0UsIG1ldHJpY3MgPSAiYnJpZXIiLCBzdW1tYXJ5ID0gImlicyIsIHRpbWVzID0gc29ydCh1bmlxdWUoZGF0YV90cmFpbiR0aW1lKSkpJEJyaWVyJHNjb3JlCkJyaWVyX3ZhbGlkYXRlID0gcmlza1JlZ3Jlc3Npb246OlNjb3JlKGxpc3QoIkJyaWVyX3ZhbGlkYXRlIiA9IGxhc3NvX3ZhbGlkYXRlKSwgZm9ybXVsYSA9IFN1cnYodGltZSwgc3RhdHVzKSB+IDEsIGRhdGEgPSBkYXRhX3ZhbGlkYXRlLCBjb25mLmludCA9IEZBTFNFLCBtZXRyaWNzID0gImJyaWVyIiwgc3VtbWFyeSA9ICJpYnMiLCB0aW1lcyA9IHNvcnQodW5pcXVlKGRhdGFfdmFsaWRhdGUkdGltZSkpKSRCcmllciRzY29yZQpCcmllcl9zY29yZSA9IHJiaW5kKEJyaWVyX3RyYWluLCBCcmllcl92YWxpZGF0ZSkKQnJpZXJfc2NvcmUgPSBCcmllcl9zY29yZVtCcmllcl9zY29yZSRtb2RlbCAhPSAiTnVsbCBtb2RlbCIsIF0KICAKZ2dwbG90KEJyaWVyX3Njb3JlLCBhZXModGltZXMsIEJyaWVyLCBncm91cCA9IG1vZGVsLCBjb2xvciA9IG1vZGVsKSkgKyB4bGFiKCJFdmFsdWF0aW9uIHRpbWUgcG9pbnRzICh5ZWFyKSIpICsgeWxhYigiQnJpZXIgc2NvcmUiKSArIAogIGdlb21fc3RlcChkaXJlY3Rpb24gPSAidmgiKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC4xNSwgMC44OCksIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCmBgYHtyLCBlY2hvPUZBTFNFfQpwZGYoIlRDR0Ffc3Vydl9icmllcl90X2xhc3NvLnBkZiIsIGhlaWdodCA9IDQsIHdpZHRoID0gNSkKZ2dwbG90KEJyaWVyX3Njb3JlLCBhZXModGltZXMsIEJyaWVyLCBncm91cCA9IG1vZGVsLCBjb2xvciA9IG1vZGVsKSkgKyB4bGFiKCJFdmFsdWF0aW9uIHRpbWUgcG9pbnRzICh5ZWFyKSIpICsgeWxhYigiQnJpZXIgc2NvcmUiKSArIAogIGdlb21fc3RlcChkaXJlY3Rpb24gPSAidmgiKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC4xNSwgMC44OCksIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKZGV2Lm9mZigpCmBgYAohW19UaW1lLWRlcGVuZGVudCBCcmllciBzY29yZSBiYXNlZCBvbiBhIExhc3NvIENveCBtb2RlbCBhcHBsaWVkIHRvIHRoZSBCUkNBIHBhdGllbnRzIGRhdGEgZnJvbSBUQ0dBLiBUaGUgcmVkIGxpbmUgc2hvd3MgdGhlIFRpbWUtZGVwZW5kZW50IEJyaWVyIHNjb3JlIGNhbGN1bGF0ZWQgZnJvbSB0aGUgODAlIHRyYWluaW5nIGRhdGEsIGFuZCB0aGUgZ3JlZW4gbGluZSBzaG93cyB0aGUgVGltZS1kZXBlbmRlbnQgQnJpZXIgc2NvcmUgY2FsY3VsYXRlZCBmcm9tIHRoZSAyMCUgdmFsaWRhdGlvbiBkYXRhLl9dKGZpZy9UQ0dBX3N1cnZfYnJpZXJfdF9sYXNzby5wbmcpe3dpZHRoPTYwJX0KCjxicj4KCjxmb250IHNpemU9IjQiPiAqKkludGVncmF0ZWQgQnJpZXIgc2NvcmUgKElCUykqKiA8L2ZvbnQ+IAoKVGhlIGZ1bmN0aW9uIGByaXNrUmVncmVzc2lvbjo6U2NvcmUoKWAgYWxzbyBzdW1tYXJpemVzIElCUyB3aGVuIHNwZWNpZnlpbmcgYXJndW1lbnQgYHN1bW1hcnkgPSAiaWJzImAuCldlIGNhbiBleHRyYWN0IHRoZSBJQlMgY29ycmVzcG9uZGluZyB0byB0aGUgbGFyZ2VzdCBldmFsdWF0aW9uIHRpbWUgcG9pbnQuCgpgYGB7cn0KQnJpZXJfdmFsaWRhdGVfaWJzID0gQnJpZXJfdmFsaWRhdGVbQnJpZXJfdmFsaWRhdGUkbW9kZWwgPT0gIkJyaWVyX3ZhbGlkYXRlIiwgXQpCcmllcl92YWxpZGF0ZV9pYnMkSUJTW3doaWNoLm1heChCcmllcl92YWxpZGF0ZV9pYnMkdGltZXMpXQpgYGAKYGBgClsxXSAwLjE3MjExNTgKYGBgCgo8YnI+CgojIyMgVW5jZXJ0YWludHkgUXVhbnRpZmljYXRpb24gey0jdXExfQoKOjo6ey5pbmZvLWJveCAuaW1wb3J0YW50fQoqKkl0IGlzIHJlY29tbWVuZGVkIHRvIHVzZSByZXNhbXBsaW5nLWJhc2VkIG1ldGhvZHMqKiBmb3IgZXN0aW1hdGluZyB0aGUgdW5jZXJ0YWludHkgb2YgdGhlIG1vZGVsJ3MgcGVyZm9ybWFuY2UsIGlmIHRoZXJlIGFyZSBubyAqKmluZGVwZW5kZW50KiogdmFsaWRhdGlvbiBkYXRhIGZvciBtb2RlbCBldmFsdWF0aW9uLgpUaGlzIGNhbiBiZSBkb25lIGZvciBleGFtcGxlIGJ5IHJlcGVhdGVkbHkgc3BsaXR0aW5nIHRoZSBkYXRhc2V0IHRvIHRyYWluaW5nL3ZhbGlkYXRpb24gc2V0cyBhbmQgZXZhbHVhdGluZyBhIG1vZGVsJ3MgcGVyZm9ybWFuY2Ugb24gdGhlIGRpZmZlcmVudCB2YWxpZGF0aW9uIHNldHMgdXNpbmcgdmFyaW91cyBkaXNjcmltaW5hdGlvbiBvciBjYWxpYnJhdGlvbiBtZXRyaWNzLgo6OjoKCldlIGRlbW9uc3RyYXRlIGhvdyB0byByYW5kb21seSBzcGxpdCB0aGUgZGF0YSwgZS5nLiAkMTAwJCB0aW1lcywgdHJhaW4gYSBMYXNzbyBDb3ggbW9kZWwgYW5kIGVzdGltYXRlIHRoZSBpbnRlZ3JhdGVkIEFVQyBiYXNlZCBvbiB0aGUgdmFsaWRhdGlvbiBkYXRhIGluIGVhY2ggcmVwbGljYXRpb24uCkZvciBvdGhlciBDb3gtdHlwZSBtb2RlbHMsIHdlIGNhbiBqdXN0IHJlcGxhY2UgdGhlIG1vZGVsIGZpdHRpbmcgcGFydCBgY3YuZ2xtbmV0KClgIChhbmQgYHByZWRpY3QoKWApIGluIHRoZSBgZm9yYCBsb29wIGJlbG93LgpIb3dldmVyLCBtb3N0IG9mIHRoZSBCYXllc2lhbiBDb3ggbW9kZWxzIGludHJvZHVjZWQgcHJldmlvdXNseSBhcmUgY29tcHV0YXRpb25hbGx5IHRpbWUtY29uc3VtaW5nIHdoZW4gcmFuZG9tbHkgc3BsaXR0aW5nIHRoZSBkYXRhIG1hbnkgdGltZXMuCgpgYGB7cn0KIyBzcGxpdCB0aGUgZGF0YSAxMDAgdGltZXMKc2V0LnNlZWQoMTIzKQprID0gMTAwCmlBVUMgPSByZXAoTkEsIGspCmZvciAoaSBpbiAxOmspIHsKICBpZHggPSBzYW1wbGUoMTpuLCBuICogMC44LCByZXBsYWNlID0gRkFMU0UpCiAgeF90cmFpbiA9IHhbaWR4LCBdCiAgeV90cmFpbiA9IHlbaWR4LCBdCiAgeF92YWxpZGF0ZSA9IHhbLWlkeCwgXQogIHlfdmFsaWRhdGUgPSB5Wy1pZHgsIF0KICBjdmZpdCA9IGN2LmdsbW5ldCh4X3RyYWluLCB5X3RyYWluLCBmYW1pbHkgPSAiY294IiwgbmZvbGRzID0gNSwgcGVuYWx0eS5mYWN0b3IgPSBwZikKICBwcmVkX2xwID0gcHJlZGljdChjdmZpdCwgbmV3eCA9IHhfdmFsaWRhdGUsIHMgPSBjdmZpdCRsYW1iZGEubWluLCB0eXBlID0gImxpbmsiKQogIHV0aW1lcyA9IHNvcnQodW5pcXVlKHlfdmFsaWRhdGVbeV92YWxpZGF0ZVssIDJdID09IDEsIDFdKSkKICBBVUMgPSByZXAoTkEsIGxlbmd0aCh1dGltZXMpKQogIGZvciAoaiBpbiAxOmxlbmd0aCh1dGltZXMpKSB7CiAgICBvdXQgPSBDb3hXZWlnaHRzKG1hcmtlciA9IHByZWRfbHAsIFN0aW1lID0geV92YWxpZGF0ZVssIDFdLCBzdGF0dXMgPSB5X3ZhbGlkYXRlWywgMl0sIHByZWRpY3QudGltZSA9IHV0aW1lc1tqXSkKICAgIEFVQ1tqXSA9IG91dCRBVUMKICB9CiAgc3Vydl9wcm9iID0gdW5pcXVlKHN1cnZmaXQoU3Vydih5X3ZhbGlkYXRlWywgMV0sIHlfdmFsaWRhdGVbLCAyXSkgfiAxKSRzdXJ2KQogIGlBVUNbaV0gPSBJbnRlZ3JhdGVBVUMoQVVDLCB1dGltZXMsIHN1cnZfcHJvYiwgdG1heCA9IDEwKQp9CmRhdF90bXAgPSBkYXRhLmZyYW1lKHggPSAiTGFzc28gQ294IiwgeSA9IGlBVUMpCgpzZXQuc2VlZCgxMjMpCmdncGxvdChkYXRfdG1wLCBhZXMoeCwgeSkpICsgZ2VvbV9ib3hwbG90KCkgKyB5bGltKDAuNSwgMSkgKyB4bGFiKCIiKSArIHlsYWIoIkludGVncmF0ZWQgQVVDIikgKwogIGdlb21faml0dGVyKGNvbG9yID0gImJsdWUiLCBzaXplID0gMC41LCBhbHBoYSA9IDAuNSkKYGBgCmBgYHtyLCBlY2hvPUZBTFNFfQpwZGYoIlRDR0Ffc3Vydl9pYXVjX2xhc3NvLnBkZiIsIGhlaWdodCA9IDMsIHdpZHRoID0gMikKc2V0LnNlZWQoMTIzKQpnZ3Bsb3QoZGF0X3RtcCwgYWVzKHgsIHkpKSArIGdlb21fYm94cGxvdCgpICsgeWxpbSgwLjUsIDEpICsgeGxhYigiIikgKyB5bGFiKCJJbnRlZ3JhdGVkIEFVQyIpICsKICBnZW9tX2ppdHRlcihjb2xvciA9ICJibHVlIiwgc2l6ZSA9IDAuNSwgYWxwaGEgPSAwLjUpCmRldi5vZmYoKQpgYGAKIVtfSW50ZWdyYXRlZCBBVUMgYmFzZWQgb24gcmFuZG9tbHkgc3BsaXQgdmFsaWRhdGlvbiBkYXRhIDEwMCB0aW1lcy4gVGhlIGJsdWUgZG90cyBhcmUgdGhlIDEwMCB2YWx1ZXMgb2YgaW50ZWdyYXRlZCBBVUMuX10oZmlnL1RDR0Ffc3Vydl9pYXVjX2xhc3NvLnBuZyl7d2lkdGg9MzAlfQoKPGJyPgoKU2ltaWxhciB0byBvYnRhaW5pbmcgdW5jZXJ0YWludHkgb2YgdGhlIGludGVncmF0ZWQgQVVDLCB3ZSBjYW4gYWxzbyBlc3RpbWF0ZSB0aGUgdW5jZXJ0YWludHkgb2YgdGhlIEMtaW5kZXggZm9yIGV2YWx1YXRpbmcgdGhlIGdsb2JhbCBwZXJmb3JtYW5jZSBvZiBvdXIgbW9kZWwncyBkaXNjcmltaW5hdGlvbi4KCmBgYHtyfQojIHNwbGl0IHRoZSBkYXRhIDEwMCB0aW1lcwpzZXQuc2VlZCgxMjMpCmsgPSAxMDAKQ2luZGV4X2FsbCA9IGRhdGEuZnJhbWUoSGFycmVsbCA9IHJlcChOQSwgayksIFVubyA9IHJlcChOQSwgaykpCmZvciAoaSBpbiAxOmspIHsKICBpZHggPSBzYW1wbGUoMTpuLCBuICogMC44LCByZXBsYWNlID0gRkFMU0UpCiAgeF90cmFpbiA9IHhbaWR4LCBdCiAgeV90cmFpbiA9IHlbaWR4LCBdCiAgeF92YWxpZGF0ZSA9IHhbLWlkeCwgXQogIHlfdmFsaWRhdGUgPSB5Wy1pZHgsIF0KICBjdmZpdCA9IGN2LmdsbW5ldCh4X3RyYWluLCB5X3RyYWluLCBmYW1pbHkgPSAiY294IiwgbmZvbGRzID0gNSwgcGVuYWx0eS5mYWN0b3IgPSBwZikKICBwcmVkID0gcHJlZGljdChjdmZpdCwgbmV3eCA9IHhfdmFsaWRhdGUsIHR5cGUgPSAicmVzcG9uc2UiLCBzID0gY3ZmaXQkbGFtYmRhLm1pbikKICBDaW5kZXhfYWxsJEhhcnJlbGxbaV0gPSBtZWFuKGFwcGx5KHByZWQsIDIsIENpbmRleCwgeSA9IHlfdmFsaWRhdGUpKQogIENpbmRleF9hbGwkVW5vW2ldID0gVW5vQyh5X3RyYWluLCB5X3ZhbGlkYXRlLCBwcmVkKQp9CmRhdF90bXAgPSBkYXRhLmZyYW1lKHggPSByZXAoYygiSGFycmVsbCIsICJVbm8iKSwgZWFjaCA9IGspLCB5ID0gdW5saXN0KENpbmRleF9hbGwpKQoKc2V0LnNlZWQoMTIzKQpnZ3Bsb3QoZGF0X3RtcCwgYWVzKHgsIHksIGNvbCA9IHgpKSArIGdlb21fYm94cGxvdCgpICsgZ2VvbV9qaXR0ZXIoc2l6ZSA9IDAuNSwgYWxwaGEgPSAwLjUpICsKICAgeWxpbSgwLCAxKSArIHhsYWIoIiIpICsgeWxhYigiQy1pbmRleCIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKYGBge3IsIGVjaG89RkFMU0V9CnBkZigiVENHQV9zdXJ2X2NpbmRleF9sYXNzby5wZGYiLCBoZWlnaHQgPSAzLCB3aWR0aCA9IDMpCnNldC5zZWVkKDEyMykKZ2dwbG90KGRhdF90bXAsIGFlcyh4LCB5LCBjb2wgPSB4KSkgKyBnZW9tX2JveHBsb3QoKSArIGdlb21faml0dGVyKHNpemUgPSAwLjUsIGFscGhhID0gMC41KSArCiAgIHlsaW0oMCwgMSkgKyB4bGFiKCIiKSArIHlsYWIoIkMtaW5kZXgiKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKZGV2Lm9mZigpCmBgYAohW19DLWluZGV4IChIYXJyZWxsJ3MgYW5kIFVubydzKSBiYXNlZCBvbiByYW5kb21seSBzcGxpdCB2YWxpZGF0aW9uIGRhdGEgMTAwIHRpbWVzLl9dKGZpZy9UQ0dBX3N1cnZfY2luZGV4X2xhc3NvLnBuZyl7d2lkdGg9NDAlfQoKPGJyPgoKVGhlIGBSYCBwYWNrYWdlIFsqKmMwNjAqKl0oaHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT1jMDYwKSBbQFNpbGwyMDE0XSBpbmNsdWRlcyB3cmFwcGVyIGZ1bmN0aW9ucyBmb3IgdGhlIFsqKmdsbW5ldCoqXShodHRwczovL0NSQU4uUi1wcm9qZWN0Lm9yZy9wYWNrYWdlPWdsbW5ldCkgYWxnb3JpdGhtIGFuZCBpbXBsZW1lbnRzIHJlc2FtcGxpbmctYmFzZWQgbWV0aG9kcyAoZS5nLiBjcm9zcy12YWxpZGF0aW9uIGFuZCBib290c3RyYXAgLSB3aXRoIGFuZCB3aXRob3V0IHJlcGxhY2VtZW50KSBiYXNlZCBvbiB0aGUgWyoqcGVwZXJyKipdKGh0dHBzOi8vQ1JBTi5SLXByb2plY3Qub3JnL3BhY2thZ2U9cGVwZXJyKSBwYWNrYWdlIHRvIGNhbGN1bGF0ZSB0aGUgdGltZS1kZXBlbmRlbnQgQnJpZXIgc2NvcmUuClsqKmMwNjAqKl0oaHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT1jMDYwKSBleHRlbmRzIFsqKnBlcGVycioqXShodHRwczovL0NSQU4uUi1wcm9qZWN0Lm9yZy9wYWNrYWdlPXBlcGVycikgcGFja2FnZSB0byBhbGxvdyBtYW5kYXRvcnkgZmVhdHVyZXMgd2l0aG91dCBwZW5hbGl6YXRpb24uCkBCaW5kZXIyMDA4IHJlY29tbWVuZHMgdG8gZHJhdyBib290c3RyYXAgc2FtcGxlcyB3aXRob3V0IHJlcGxhY2VtZW50IChpLmUuIHN1YnNhbXBsaW5nKSwgYmVjYXVzZSBib290c3RyYXAgc2FtcGxlcyB3aXRoIHJlcGxhY2VtZW50IG9mdGVuIHJlc3VsdCBpbiB0b28gY29tcGxleCBtb2RlbHMgaW4gaGlnaC1kaW1lbnNpb25hbCBzZXR0aW5ncy4KVG8gdXNlIHJlc2FtcGxpbmcgYnkgQ1YgcHJvcGVybHkgZm9yIHN1cnZpdmFsIGRhdGEsIHNlZSBAU2ltb24yMDExLgpOb3RlIHRoYXQgcmVzYW1wbGluZy1iYXNlZCBtZXRob2RzIGhlcmUgYXJlIHNpbWlsYXIgdG8gc3BsaXR0aW5nICQ4MFwlLzIwXCUkIHRoZSBkYXRhIG1hbnkgdGltZXMgd2hpY2ggYWxsb3dzIHVzIHRvIHF1YW50aWZ5IHRoZSB1bmNlcnRhaW50eSBvZiB0aGUgdGltZS1kZXBlbmRlbnQgQnJpZXIgc2NvcmUuCgpgYGB7cn0KIyMgdGltZS1kZXBlbmRlbnQgQnJpZXIgc2NvcmUgYnkgc3Vic2FtcGxpbmcgZnJvbSB0aGUgd2hvbGUgZGF0YQpzZXQuc2VlZCgxMjMpCnBlcGVycl9vYmplY3QgPSBwZXBlcnI6OnBlcGVycihyZXNwb25zZSA9IHlfc3VydiwgeCA9IHgsIGZpdC5mdW4gPSBmaXQuZ2xtbmV0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFyZ3MuZml0ID0gbGlzdChmYW1pbHkgPSAiY294IiwgcGVuYWx0eS5mYWN0b3IgPSBwZiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tcGxleGl0eSA9IGNvbXBsZXhpdHkuZ2xtbmV0LCAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcmdzLmNvbXBsZXhpdHkgPSBsaXN0KGZhbWlseSA9ICJjb3giLCBuZm9sZHMgPSA1LCBwZW5hbHR5LmZhY3RvciA9IHBmKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZGljZXMgPSByZXNhbXBsZS5pbmRpY2VzKG4gPSBuLCBtZXRob2QgPSAic3ViNjMyIiwgc2FtcGxlLm4gPSAxMDApKQpjMDYwOjpQbG90LnBlcGVyci5jdXJ2ZXMocGVwZXJyX29iamVjdCkKYGBgCmBgYHtyLCBlY2hvPUZBTFNFfQpwZGYoIlRDR0Ffc3Vydl9icmllcl9sYXNzby5wZGYiLCBoZWlnaHQgPSA1LCB3aWR0aCA9IDUpClBsb3QucGVwZXJyLmN1cnZlcyhwZXBlcnJfb2JqZWN0KQpkZXYub2ZmKCkKYGBgCiFbX1Jlc2FtcGxpbmctYmFzZWQgcHJlZGljdGlvbiBlcnJvciBjdXJ2ZXMgKHRpbWUtZGVwZW5kZW50IEJyaWVyIHNjb3JlKSBhIHRoZSBMYXNzbyBDb3ggbW9kZWwgYXBwbGllZCB0byB0aGUgQlJDQSBkYXRhIHNldCBmcm9tIFRDR0EuIFRoZSBncmF5IGFyZWEgaW5kaWNhdGVzIHRoZSBwb2ludHdpc2UgMi41JSBhbmQgOTcuNSUgcXVhbnRpbGVzIG9mIHRoZSAxMDAgb3V0LW9mLWJhZyBib290c3RyYXAgc2FtcGxlcy4gVGhlIG90aGVyIGxpbmVzIHNob3cgdGhlIHByZWRpY3Rpb24gZXJyb3IgY3VydmVzIG9mIHRoZSBudWxsIG1vZGVsIChlc3RpbWF0ZWQgYnkgdGhlIEthcGxhbi1NZWllciBlc3RpbWF0b3Igd2l0aG91dCBjb3ZhcmlhdGUgaW5mb3JtYXRpb24pLCB0aGUgZnVsbCBhcHBhcmVudCBlcnJvciBlc3RpbWF0ZXMgKGkuZS4sIHRoZSBlcnJvcnMgYXMgZXN0aW1hdGVkIHdoZW4gYXBwbHlpbmcgdGhlIG1vZGVsIHRvIHRoZSBlbnRpcmUgdHJhaW5pbmcgZGF0YSBzZXQpLCBhbmQgdGhlIC42MzIrIGJvb3RzdHJhcCBlcnJvciBlc3RpbWF0ZXMuX10oZmlnL1RDR0Ffc3Vydl9icmllcl9sYXNzby5wbmcpe3dpZHRoPTUwJX0KCjxicj4KCiMjIyBGZWF0dXJlIHN0YWJpbGl0eSBhbmFseXNpcyB7LX0KClRvIGlkZW50aWZ5IHN0YWJsZSBvbWljcyBmZWF0dXJlcywgYSBzdHJhaWdodGZvcndhcmQgd2F5IGlzIHRvIGZpbmQgdGhlIG92ZXJsYXBwZWQgb21pY3MgZmVhdHVyZXMgd2l0aCBub256ZXJvIGNvZWZmaWNpZW50cyBhbW9uZyBkaWZmZXJlbnQgZGF0YSBzdWJzZXRzIChlLmcuIENWIGZvbGRzIG9yIHJlc2FtcGxlcykuClRoZSBmb2xsb3dpbmcgY29kZSBzdW1tYXJpemVzIHRoZSBMYXNzbyBDb3ggc2VsZWN0ZWQgb21pY3MgZmVhdHVyZXMgd2hpY2ggd2VyZSBpZGVudGlmaWVkIGF0IGxlYXN0ICQyJCBvciAkNSQgb3V0IG9mICQxMCQgcmVzYW1wbGVzLgpTaW1pbGFybHksIHRoaXMgYXBwcm9hY2ggY2FuIGJlIGFwcGxpZWQgdG8gb3RoZXIgTGFzc28tdHlwZSBvciBCYXllc2lhbiBDb3ggbW9kZWxzIHRoYXQgcGVyZm9ybSBmZWF0dXJlIHNlbGVjdGlvbiBmb3IgaWRlbnRpZnlpbmcgc3RhYmxlIHNlbGVjdGVkIGZlYXR1cmVzLgoKYGBge3J9CiMgc3BlY2lmeSB0aGUgbnVtYmVyIG9mIHJlc2FtcGxlcyBrCmsgPSAxMApiZXRhX2FsbCA9IG1hdHJpeChucm93ID0gbmNvbCh4KSwgbmNvbCA9IGspCnNldC5zZWVkKDEyMykKZm9yIChqIGluIDE6aykgewogIHJlc2FtcGxlX2lkID0gc2FtcGxlKDE6bnJvdyh5KSwgbnJvdyh5KSwgcmVwbGFjZSA9IFRSVUUpCiAgcmVzYW1wbGVfeCA9IHhbcmVzYW1wbGVfaWQsIF0KICByZXNhbXBsZV95ID0geVtyZXNhbXBsZV9pZCwgXQogIGN2Zml0ID0gY3YuZ2xtbmV0KHJlc2FtcGxlX3gsIHJlc2FtcGxlX3ksIGZhbWlseSA9ICJjb3giLCBuZm9sZHMgPSA1LCBwZW5hbHR5LmZhY3RvciA9IHBmKQogIGJldGFfYWxsWywgal0gPSBhcy52ZWN0b3IoY29lZihjdmZpdCwgcyA9IGN2Zml0JGxhbWJkYS5taW4pKQp9Cgooc3RhYmxlX2ZlYXR1cmVzID0gY29sbmFtZXMoeClbcm93U3VtcyhiZXRhX2FsbCAhPSAwKSA+PSAyXSkKYGBgCmBgYAogWzFdICJhZ2UiICAgICAgICJldGhuaWNpdHkiICJBTkxOIiAgICAgICJVQkUyVCIgICAgICJOREM4MCIgICAgICJQR1IiICAgICAgICJPUkM2IiAgICAgCiBbOF0gIkVTUjEiICAgICAgIlBIR0RIIiAgICAgIk1NUDExIiAgICAgIlNGUlAxIiAgICAgIkNDTkUxIiAgICAgIkJMVlJBIiAgICAgIkJBRzEiICAgICAKWzE1XSAiTUxQSCIgICAgICAiQ0VOUEYiICAgICAiS1JUMTciICAgICAiRk9YQTEiICAgICAiQUNUUjNCIiAgICAiQ0NOQjEiICAgICAiTURNMiIgICAgIApbMjJdICJNWUMiICAgICAgICJDRVA1NSIgICAgICJTTEMzOUE2IiAgICJHUkI3IiAgICAgICJOVUYyIiAgICAgICJFR0ZSIiAgICAgICJNS0k2NyIgICAgClsyOV0gIlRNRU00NUIiICAgIkZHRlI0IiAgICAgIk1FTEsiICAgICAgIk5BVDEiICAgICAgIkNYWEM1IiAgICAgIkJDTDIiICAgICAgIkdQUjE2MCIgICAKWzM2XSAiVFlNUyIgICAgICAiS1JUNSIgICAgICAiTUFQVCIgICAgICAiTUlBIgpgYGAKYGBge3J9CihzdGFibGVfZmVhdHVyZXMgPSBjb2xuYW1lcyh4KVtyb3dTdW1zKGJldGFfYWxsICE9IDApID49IDVdKQpgYGAKYGBgCiBbMV0gImFnZSIgICAgICAgImV0aG5pY2l0eSIgIkFOTE4iICAgICAgIk9SQzYiICAgICAgIk1NUDExIiAgICAgIkJMVlJBIiAgICAgIkJBRzEiICAgICAKIFs4XSAiQ0NOQjEiICAgICAiRUdGUiIgICAgICAiVE1FTTQ1QiIgICAiQkNMMiIgICAgICAiVFlNUyIgICAgICAiS1JUNSIgICAgICAiTUlBIgpgYGAKCkFsdGVybmF0aXZlbHkgZm9yIGEgQmF5ZXNpYW4gQ294IG1vZGVsLCBpdHMgbWVkaWFuIHByb2JhYmlsaXR5IG1vZGVsIChNUE0pIGNhbiBiZSBvYnRhaW5lZCBiYXNlZCBvbiB0aGUgY29lZmZpY2llbnQgZXN0aW1hdGVzIG92ZXIgTUNNQyBpdGVyYXRpb25zLgpUaGUgZm9sbG93aW5nIGNvZGUgc2hvd3MgaG93IHRvIG9idGFpbiB0aGUgTVBNJ3MgY29lZmZpY2llbnRzIG9mIHRoZSBwZW5hbGl6ZWQgc2VtaXBhcmFtZXRyaWMgQmF5ZXNpYW4gQ294IG1vZGVsIHdpdGggRWxhc3RpYyBOZXQgcHJpb3IgcnVuIHByZXZpb3VzbHkuCgpgYGB7cn0KZ2FtbWFzID0gY29sTWVhbnMobWF0cml4KGFzLm51bWVyaWMoRU5fYmV0YV9wICE9IDApLCBuY29sID0gbmNvbChFTl9iZXRhX3ApKSkKYmV0YV9NUE0gPSAoZ2FtbWFzID49IDAuNSkgKiBjb2xNZWFucyhFTl9iZXRhX3ApIC8gZ2FtbWFzCmJldGFfTVBNW2lzLm5hKGJldGFfTVBNKV0gPSAwCmJldGFfTVBNCmBgYApgYGAKICAgICAgICAgIGFnZSAgICAgZXRobmljaXR5ICAgICAgICAgIEFOTE4gICAgICAgICBGT1hDMSAgICAgICAgICBDREgzICAgICAgICAgVUJFMlQgCiAxLjMwNTE2MmUtMDIgIDUuMzQ4NDU4ZS0wMyAtMS4yOTk0NDNlLTAzIC0xLjg1NzgxMWUtMDIgLTYuMTIzNTc0ZS0wMyAtNS40NjcxMTFlLTAzIAogICAgICAgIE5EQzgwICAgICAgICAgICBQR1IgICAgICAgICBCSVJDNSAgICAgICAgICBPUkM2ICAgICAgICAgIEVTUjEgICAgICAgICBQSEdESCAKLTYuNjUyOTI3ZS0wMyAtMi4xMDEyNDNlLTA2IC0xLjY0MDM4NmUtMDIgLTEuMjM3MTUzZS0wMiAtMS4wNzc4NjNlLTAyICAyLjQ4Mzk5MGUtMDIgCiAgICAgICAgIENEQzYgICAgICAgICBNTVAxMSAgICAgICAgIE1ZQkwyICAgICAgICAgU0ZSUDEgICAgICAgICBDQ05FMSAgICAgICAgIEJMVlJBIAotOS4wNzk3MDhlLTAzIC0xLjU4ODcyNmUtMDIgIDUuMjI1MzQ0ZS0wMyAtMS4zODM5ODFlLTAyIC0zLjE4MTI2NWUtMDMgLTIuNjMyMzczZS0wMiAKICAgICAgICAgQkFHMSAgICAgICAgICBNTFBIICAgICAgICAgQ0RDMjAgICAgICAgICBDRU5QRiAgICAgICAgIEtSVDE3ICAgICAgICAgRk9YQTEgCi0zLjkxMzUyOWUtMDIgLTEuNDM1ODA1ZS0wMiAtMi4wMjcyMzJlLTAyIC0yLjQ3NjQ5NWUtMDIgLTIuODcxMTQzZS0wMiAtMy4wMTcyMTNlLTAzIAogICAgICAgQUNUUjNCICAgICAgICAgQ0NOQjEgICAgICAgICAgTURNMiAgICAgICAgICAgTVlDICAgICAgICAgQ0VQNTUgICAgICAgU0xDMzlBNiAKLTIuNTA0ODY5ZS0wMyAtMS4zNDY4MTdlLTAzIC0yLjE1NjA0MWUtMDIgIDEuNDMxMDYyZS0wMiAgMS40MjEwMzZlLTAyIC0xLjE1MDE5NmUtMDIgCiAgICAgICAgRVJCQjIgICAgICAgICAgR1JCNyAgICAgICAgIEtJRjJDICAgICAgICAgIE5VRjIgICAgICAgICAgRUdGUiAgICAgICAgIE1LSTY3IAotNi4zNDczNjdlLTAzIC0xLjAwODY4OWUtMDIgIDYuMDMzNzkyZS0wMyAtMi40MDU2ODllLTAzIC0xLjk2NDkyN2UtMDIgIDEuOTU2NjYxZS0wMiAKICAgICAgVE1FTTQ1QiAgICAgICAgIEZHRlI0ICAgICAgICAgUFRURzEgICAgICAgICAgTUVMSyAgICAgICAgICBOQVQxICAgICAgICAgQ1hYQzUgCiAyLjczNjIxNmUtMDIgIDEuODQyMzIzZS0wMyAtNS42NTE5MDVlLTAzICAyLjg5NDA3NGUtMDIgLTIuMTI2MTYzZS0wMiAgMi41NzE0NzJlLTAyIAogICAgICAgICBCQ0wyICAgICAgICAgIFJSTTIgICAgICAgIEdQUjE2MCAgICAgICAgICBFWE8xICAgICAgICAgVUJFMkMgICAgICAgICAgVFlNUyAKLTUuMTQwODk0ZS0wMyAgMi44ODEwMDRlLTAyIC0zLjkyNzcwNWUtMDIgLTEuNzEwNDE5ZS0wMiAtMS4zNDM4MzJlLTAyIC0xLjg4NDM0MmUtMDIgCiAgICAgICAgIEtSVDUgICAgICAgICBLUlQxNCAgICAgICAgICBNQVBUICAgICAgICAgICBNSUEgCi0yLjE4MDI5NGUtMDIgLTEuMzg2NDg5ZS0wMyAtMi41ODc1NTdlLTAyIC0xLjAzMzMxN2UtMDIKYGBgCgo8YnI+CgojIyMgR3JhcGhpY2FsIHJlcHJlc2VudGF0aW9uIHstI2dyYXBoQ29tcH0KCkFmdGVyIGlkZW50aWZ5aW5nIHN0YWJsZSBvbWljcyBmZWF0dXJlcyBwcmVkaWN0aXZlIG9mIHN1cnZpdmFsIG91dGNvbWVzLCB3ZSBjYW4gZHJhdyBhICoqbm9tb2dyYW0qKiB0byBhbGxvd3MgdGhlIGdyYXBoaWNhbCBjYWxjdWxhdGlvbiBvZiBzdXJ2aXZhbCBwcm9iYWJpbGl0aWVzIGFuZCByZXBvcnQgYSAqKmNhbGlicmF0aW9uIHBsb3QqKiBmb3IgcHJhY3RpdGlvbmVycy4KCjxmb250IHNpemU9IjQiPiAqKk5vbW9ncmFtKiogPC9mb250PiAKCldlIGRlbW9uc3RyYXRlIGEgbm9tb2dyYW0gdXNpbmcgdGhlIHN0YWJsZSBzZWxlY3RlZCBmZWF0dXJlcyBmcm9tIFRDR0EgYnJlYXN0IGNhbmNlciBkYXRhIHByZXByb2Nlc3NlZCBwcmV2aW91c2x5LgpUaGUgYFJgIHBhY2thZ2UgKipyZWdwbG90KiogZHJhd3MgYW4gZW5oYW5jZWQgcmVncmVzc2lvbiBub21vZ3JhbSBiYXNlZCBvbiB0aGUgKipybXMqKiBwYWNrYWdlLgoKYGBge3J9CiMgcmVtb3ZlIHBhdGllbnRzIHdpdGhvdXQgcmVwb3J0aW5nIGV0aG5pY2l0eQp5eSA9IHlbeFssIDJdICE9IDMsIF0KeHggPSB4W3hbLCAyXSAhPSAzLCBdCiMgc3BlY2lmeSB0aGUgbnVtYmVyIG9mIHJlc2FtcGxlcyBrCmsgPSAxMApiZXRhX2FsbCA9IG1hdHJpeChucm93ID0gbmNvbCh4eCksIG5jb2wgPSBrKQpzZXQuc2VlZCgxMjMpCmZvciAoaiBpbiAxOmspIHsKICByZXNhbXBsZV9pZCA9IHNhbXBsZSgxOm5yb3coeXkpLCBucm93KHl5KSwgcmVwbGFjZSA9IFRSVUUpCiAgcmVzYW1wbGVfeCA9IHh4W3Jlc2FtcGxlX2lkLCBdCiAgcmVzYW1wbGVfeSA9IHl5W3Jlc2FtcGxlX2lkLCBdCiAgY3ZmaXQgPSBjdi5nbG1uZXQocmVzYW1wbGVfeCwgcmVzYW1wbGVfeSwgZmFtaWx5ID0gImNveCIsIG5mb2xkcyA9IDUsIHBlbmFsdHkuZmFjdG9yID0gcGYpCiAgYmV0YV9hbGxbLCBqXSA9IGFzLnZlY3Rvcihjb2VmKGN2Zml0LCBzID0gY3ZmaXQkbGFtYmRhLm1pbikpCn0KCiMgaWRlbnRpZnkgZmVhdHVyZXMgYXQgbGVhc3QgODAlIGZyZXF1ZW50bHkgc2VsZWN0ZWQKeF9zdGFibGUgPSBkYXRhLmZyYW1lKHh4Wywgcm93U3VtcyhiZXRhX2FsbCAhPSAwKSA+PSBrICogMC44XSkKeF9zdGFibGUkZXRobmljaXR5ID0gZmFjdG9yKHhfc3RhYmxlJGV0aG5pY2l0eSkgCmxldmVscyh4X3N0YWJsZSRldGhuaWNpdHkpID0gYygiSGlzcGFuaWMvbGF0aW5vIiwgIk5vdCBoaXNwYW5pYy9sYXRpbm8iKQoKZGF0YV90bXAgPSBkYXRhLmZyYW1lKHRpbWVzID0geXlbLCAidGltZSJdLCBzdGF0dXMgPSB5eVssICJzdGF0dXMiXSwgeF9zdGFibGUpCmYgPSBjcGgoZm9ybXVsYSA9IFN1cnYodGltZXMsIHN0YXR1cykgfiBhZ2UgKyBldGhuaWNpdHkgKyBBTkxOICsgQkxWUkEgKyBFR0ZSLCAgCiAgICAgICAgICAgICBkYXRhID0gZGF0YV90bXAsIHggPSBUUlVFLCB5ID0gVFJVRSwgc3VydiA9IFRSVUUpCmRkaXN0ID0gZGF0YWRpc3QoZGF0YV90bXApCm9sZG9wdGlvbiA9IG9wdGlvbnMoZGF0YWRpc3QgPSAnZGRpc3QnKQpzdXJ2ID0gU3Vydml2YWwoZikKbm9tID0gbm9tb2dyYW0oZiwgZnVuID0gbGlzdChmdW5jdGlvbih4KSBzdXJ2KDEsIHgpLCBmdW5jdGlvbih4KSBzdXJ2KDMsIHgpLCBmdW5jdGlvbih4KSBzdXJ2KDUsIHgpKSwKICAgICAgICAgICAgICAgICAgICBmdW5sYWJlbCA9IGMoIjEtWWVhciBTdXJ2aXZhbCBQcm9iYWJpbGl0eSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMy1ZZWFyIFN1cnZpdmFsIFByb2JhYmlsaXR5IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI1LVllYXIgU3Vydml2YWwgUHJvYmFiaWxpdHkiKSwKICAgICAgICAgICAgICAgICAgICBscCA9IEZBTFNFKQpyZWdwbG90OjpyZWdwbG90KGYsIG9ic2VydmF0aW9uID0gZGF0YV90bXBbMSxdLCBmYWlsdGltZSA9IGMoMSwgMywgNSksIHRpdGxlID0gIiIsCiAgICAgICAgICAgICAgICAgcHJmYWlsID0gRkFMU0UsIHBvaW50cyA9IFRSVUUsIHNob3dQID0gRkFMU0UsIHN1YnRpY2tzID0gVFJVRSkgCmBgYAohW19Ob21vZ3JhbSBkZXZlbG9wZWQgdG8gZXN0aW1hdGUgdGhlIG92ZXJhbGwgc3Vydml2YWwgcHJvYmFiaWxpdHkgZm9yIFRDR0EncyBCUkFDIHBhdGllbnRzIGJhc2VkIG9uIGRlbW9ncmFwaGljIGFuZCBMYXNzbyBDb3ggc2VsZWN0ZWQgbVJOQSBmZWF0dXJlcy4gVGhlIHJlZCBjb2xvdXJlZCBzeW1ib2xzIHJlcHJlc2VudCBvbmUgcGF0aWVudOKAmXMgaW5mb3JtYXRpb24gYW5kIHByZWRpY3RlZCBwcm9iYWJpbGl0aWVzIG9mIDEteWVhciwgMy15ZWFyIGFuZCA1LXllYXIgc3Vydml2YWwuX10oZmlnL1RDR0Ffc3Vydl9ub21vZ3JhbS5wbmcpe3dpZHRoPTgwJX0KCjxicj4gCgo8Zm9udCBzaXplPSI0Ij4gWyoqQ2FsaWJyYXRpb24gcGxvdCoqXXsjc2xvcGVDYWxpfSA8L2ZvbnQ+IAoKQSBjYWxpYnJhdGlvbiBwbG90IGlzIGEgc3RyYWlnaHRmb3J3YXJkIHZpc3VhbGl6YXRpb24gdG8gc2hvdyB0aGUgcHJlZGljdGlvbiBhYmlsaXR5IG9mIHRoZSBub21vZ3JhbSwgaS5lLiwgdGhlIGFncmVlbWVudCBiZXR3ZWVuIHByZWRpY3RlZCBzdXJ2aXZhbCBwcm9iYWJpbGl0aWVzIGZyb20gdGhlIGZpbmFsIG1vZGVsIGFuZCB0aGUgS00gZXN0aW1hdGVkIHN1cnZpdmFsIHByb2JhYmlsaXRpZXMgaW4gZGlmZmVyZW50IHBlcmNlbnRpbGVzIG9mIHRoZSBwcmVkaWN0ZWQgdmFsdWVzIGF0IGEgdGltZSBwb2ludCBvZiBpbnRlcmVzdC4gCldlIGRlbW9uc3RyYXRlIGJlbG93IGNhbGlicmF0aW9uIHBsb3RzIGJhc2VkIG9uIHRyYWluaW5nIGFuZCB2YWxpZGF0aW9uIGRhdGEgc2V0cywgcmVzcGVjdGl2ZWx5LgoKYGBge3J9CiMgQ2FsaWJyYXRpb24gYXQgNS15ZWFyIHRpbWUtcG9pbnQKCiMgcHJlcGFyZSBzdWl0YWJsZSBkYXRhIGZvcm1hdCBmb3IgY2FsaWJyYXRpb24gcGxvdApzZXQuc2VlZCgxMjMpCnRyYWluX2lkIDwtIHNhbXBsZSgxOm5yb3coeXkpLCBucm93KHl5KSAqIDAuOCwgcmVwbGFjZSA9IEZBTFNFKQpkYXRhX3RyYWluID0gZGF0YV90bXBbdHJhaW5faWQsIF0KZGF0YV92YWxpZGF0ZSA9IGRhdGFfdG1wWy10cmFpbl9pZCwgXQoKZGRpc3QgPSBkYXRhZGlzdChkYXRhX3RyYWluKQpvcHRpb25zKGRhdGFkaXN0ID0gJ2RkaXN0JykKZl90cmFpbiA9IGNwaChmb3JtdWxhID0gU3Vydih0aW1lcywgc3RhdHVzKSB+IGFnZSArIGV0aG5pY2l0eSArIEFOTE4gKyBCTFZSQSArIEVHRlIsIAogICAgICAgICAgICAgIGRhdGEgPSBkYXRhX3RyYWluLCB4ID0gVFJVRSwgeSA9IFRSVUUsIHN1cnYgPSBUUlVFLCB0aW1lLmluYyA9IDUpCmZfdmFsaWRhdGUgPSB1cGRhdGUoZl90cmFpbiwgZGF0YSA9IGRhdGFfdmFsaWRhdGUpCmNhbF90cmFpbiA9IGNhbGlicmF0ZShmX3RyYWluLCB1ID0gNSwgY21ldGhvZCA9ICJLTSIsIG0gPSBucm93KGRhdGFfdHJhaW4pIC8gNCwgQiA9IDIwMCkKY2FsX3ZhbGlkYXRlID0gY2FsaWJyYXRlKGZfdmFsaWRhdGUsIHUgPSA1LCBjbWV0aG9kID0gIktNIiwgbSA9IG5yb3coZGF0YV92YWxpZGF0ZSkgLyA0LCBCID0gMjAwKQoKbGF5b3V0KG1hdHJpeCgxOjIsIG5yb3cgPSAxKSkKcGxvdChjYWxfdHJhaW4sIGx3ZCA9IDIsIGx0eSA9IDEsIGVycmJhci5jb2wgPSAic2VhZ3JlZW4zIiwKICAgICB4bGFiID0gJ1ByZWRpY3RlZCBzdXJ2aXZhbCBwcm9iYWJpbGl0eScsIHlsYWIgPSAnQWN0dWFsIHN1cnZpdmFsIHByb2JhYmlsaXR5JywKICAgICB4bGltID0gYygwLCAxKSwgeWxpbSA9IGMoMCwgMSksIGNvbCA9ICJzZWFncmVlbjMiLCBzdWJ0aXRsZXMgPSBGQUxTRSkKdGl0bGUobWFpbiA9ICJDYWxpYnJhdGlvbiBvbiB0cmFpbmluZyBkYXRhIikKCnBsb3QoY2FsX3ZhbGlkYXRlLCBsd2QgPSAyLCBsdHkgPSAxLCBlcnJiYXIuY29sID0gInNlYWdyZWVuMyIsCiAgICAgeGxhYiA9ICdQcmVkaWN0ZWQgc3Vydml2YWwgcHJvYmFiaWxpdHknLCB5bGFiID0gJ0FjdHVhbCBzdXJ2aXZhbCBwcm9iYWJpbGl0eScsCiAgICAgeGxpbSA9IGMoMCwgMSksIHlsaW0gPSBjKDAsIDEpLCBjb2wgPSAic2VhZ3JlZW4zIiwgc3VidGl0bGVzID0gRkFMU0UpCnRpdGxlKG1haW4gPSAiQ2FsaWJyYXRpb24gb24gdmFsaWRhdGlvbiBkYXRhIikKYGBgCmBgYHtyLCBlY2hvPUZBTFNFfQpwZGYoIlRDR0Ffc3Vydl9jYWxpYnJhdGlvbi5wZGYiLCB3aWR0aCA9IDcsIGhlaWdodCA9IDQpCmxheW91dChtYXRyaXgoMToyLCBucm93ID0gMSkpCnBsb3QoY2FsX3RyYWluLCBsd2QgPSAyLCBsdHkgPSAxLCBlcnJiYXIuY29sID0gInNlYWdyZWVuMyIsCiAgICAgeGxhYiA9ICdQcmVkaWN0ZWQgc3Vydml2YWwgcHJvYmFiaWxpdHknLCB5bGFiID0gJ0FjdHVhbCBzdXJ2aXZhbCBwcm9iYWJpbGl0eScsCiAgICAgeGxpbSA9IGMoMCwxKSwgeWxpbSA9IGMoMCwxKSwgY29sID0gInNlYWdyZWVuMyIsIHN1YnRpdGxlcyA9IEZBTFNFKQp0aXRsZShtYWluID0gIkNhbGlicmF0aW9uIG9uIHRyYWluaW5nIGRhdGEiKQoKcGxvdChjYWxfdmFsaWRhdGUsIGx3ZCA9IDIsIGx0eSA9IDEsIGVycmJhci5jb2wgPSAic2VhZ3JlZW4zIiwKICAgICB4bGFiID0gJ1ByZWRpY3RlZCBzdXJ2aXZhbCBwcm9iYWJpbGl0eScsIHlsYWIgPSAnQWN0dWFsIHN1cnZpdmFsIHByb2JhYmlsaXR5JywKICAgICB4bGltID0gYygwLDEpLCB5bGltID0gYygwLDEpLCBjb2wgPSAic2VhZ3JlZW4zIiwgc3VidGl0bGVzID0gRkFMU0UpCnRpdGxlKG1haW4gPSAiQ2FsaWJyYXRpb24gb24gdmFsaWRhdGlvbiBkYXRhIikKZGV2Lm9mZigpCmBgYAohW19Ob21vZ3JhbSBtb2RlbCBjYWxpYnJhdGlvbiBjdXJ2ZXMgZm9yIFRDR0EncyBCUkFDIHBhdGllbnRzIGF0IDUteWVhciBldmFsdWF0aW9uIHRpbWUtcG9pbnQuX10oZmlnL1RDR0Ffc3Vydl9jYWxpYnJhdGlvbi5wbmcpe3dpZHRoPTcwJX0KCjxicj4KCiMjIE1vZGVsIGV2YWx1YXRpb24gKG1scjMpIHstI21scjN9Cgo6Ojp7LmdyZWVuLWJveH0KVXNpbmcgdGhlIFsqKm1scjMqKl0oaHR0cHM6Ly9tbHIzLm1sci1vcmcuY29tKSBtYWNoaW5lIGxlYXJuaW5nIGZyYW1ld29yayBhbmQgdGhlIFsqKm1scjNwcm9iYSoqXShodHRwczovL21scjNwcm9iYS5tbHItb3JnLmNvbSkgYFJgIGxpYnJhcnksIHdlIHdpbGwgZGVtb25zdHJhdGUgaG93IHRvOgoKLSBDcmVhdGUgYSBzdXJ2aXZhbCB0YXNrIGZyb20gYSBkYXRhc2V0IGFuZCBzcGxpdCBpdCB0byB0cmFpbmluZyBhbmQgdGVzdCAodmFsaWRhdGlvbikgc2V0cwotIERlZmluZSBhIExhc3NvIENveCBtb2RlbCB0aGF0IGNhbiBvdXRwdXQgYm90aCBsaW5lYXIgcHJlZGljdG9ycyBhbmQgc3Vydml2YWwgZGlzdHJpYnV0aW9uIHByZWRpY3Rpb25zIGFuZCB0cmFpbi90dW5lIGl0IG9uIHRoZSB0cmFpbmluZyBzZXQKLSBNYWtlIHByZWRpY3Rpb25zIHVzaW5nIHRoZSB0cmFpbmVkIExhc3NvIENveCBtb2RlbCBvbiB0aGUgc2VwYXJhdGUgdGVzdCBzZXQKLSBNZWFzdXJlIHRoZSBwZXJmb3JtYW5jZSBvZiBvdXIgbW9kZWwgKGRpc2NyaW1pbmF0aW9uIGFuZCBjYWxpYnJhdGlvbikgdXNpbmcgc2V2ZXJhbCBldmFsdWF0aW9uIG1ldHJpY3MKLSBVc2luZyByZXNhbXBsaW5nIHRlY2huaXF1ZXMsIHdlIHdpbGwgYXNzZXNzIG91ciBtb2RlbCdzIGNhcGFjaXR5IGZvciBnZW5lcmFsaXphdGlvbiAocHJlZGljdGlvbiBvbiB1bnNlZW4gZGF0YSkgYW5kIHRoZSBzdGFiaWxpdHkgb2YgdGhlIG1vZGVsJ3Mgc2VsZWN0ZWQgZmVhdHVyZXMKOjo6CgpGb3IgdGhlIHJlc3Qgb2YgdGhlIGFuYWx5c2lzLCB3ZSB3aWxsIGJvcnJvdyB0aGUgdGVybWlub2xvZ3kgZnJvbSB0aGUgWyoqbWxyMyoqXShodHRwczovL21scjMubWxyLW9yZy5jb20pIGVjb3N5c3RlbSBvZiBtYWNoaW5lIGxlYXJuaW5nIHBhY2thZ2VzIChlLmcuICp0YXNrKiBpcyBhIGRhdGFzZXQsICpsZWFybmVyKiBpcyBhIG1vZGVsLCBldGMuKS4KU2VlIFttbHIzIGJvb2tdKGh0dHBzOi8vbWxyM2Jvb2subWxyLW9yZy5jb20vKSBmb3IgbW9yZSBkZXRhaWxzLgoKRmlyc3QsIHdlIGxvYWQgdGhlIG5lY2Vzc2FyeSBbKiptbHIzKipdKGh0dHBzOi8vbWxyMy5tbHItb3JnLmNvbSkgbGlicmFyaWVzIFtATGFuZzIwMTk7IEBTb25hYmVuZDIwMjFdIGFuZCBzb21lIG90aGVyIHVzZWZ1bCBvbmVzOgpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KbGlicmFyeSgibWxyM3ZlcnNlIikgIyBtbHIzLCBtbHIzcGlwZXBsaW5lcywgbWxyM2xlYXJuZXJzLCBtbHIzdHVuaW5nLCBwYXJhZG94LCBldGMuCmxpYnJhcnkoIm1scjNwcm9iYSIpICMgcHJvYmFiaWxpc3RpYyBsZWFybmluZyBhbmQgc3Vydml2YWwgYW5hbHlzaXMKbGlicmFyeSgibWxyM2V4dHJhbGVhcm5lcnMiKSAjIGZvciBscm4oJ3N1cnYuZ2xtbmV0JykKYGBgCgo8YnI+CgojIyMgV29ya2Zsb3cgey19CgpXZSBjb25zdHJ1Y3QgYW4gWyoqbWxyMyoqXShodHRwczovL21scjMubWxyLW9yZy5jb20pICpzdXJ2aXZhbCB0YXNrKiAoVENHQSBCUkNBIGRhdGFzZXQgZXNzZW50aWFsbHksIHdpdGggbm9ybWFsaXplZCBQQU01MCBnZW5lIGV4cHJlc3Npb24gZmVhdHVyZXMgYW5kIHR3byBjbGluaWNhbC9kZW1vZ3JhcGhpYyB2YXJpYWJsZXMpIGFuZCBzcGxpdCBpdCBpbnRvIHRyYWluaW5nIGFuZCB0ZXN0IHNldHMgKCQ4MFwlLzIwXCUkKToKYGBge3J9CiMgRnJvbSAnUGVuYWxpemVkIENveCBtb2RlbHMnIHNlY3Rpb246CiMgeCA9PiBnZW5lIGV4cHJlc3Npb24gbWF0cml4ICg1MCBQQU01MCBnZW5lcykgKyAyIGNsaW5pY2FsIHZhcmlhYmxlcwojIHkgPT4gKHRpbWUsIHN0YXR1cykgdGFyZ2V0IG1hdHJpeAoKZGF0YSA9IGNiaW5kLmRhdGEuZnJhbWUoeCwgeSkKIyBkYXRhID0gcmVhZFJEUyhmaWxlID0gJ2RhdGEucmRzJykKdGFzayA9IG1scjNwcm9iYTo6YXNfdGFza19zdXJ2KHggPSBkYXRhLCAKICB0aW1lID0gJ3RpbWUnLCBldmVudCA9ICdzdGF0dXMnLCBpZCA9ICdCUkNBLVRDR0EnKQp0YXNrICMgc2VlIHVzZWZ1bCBpbmZvIGFib3V0IHRoZSBkYXRhc2V0ICgjZmVhdHVyZXMsICNzYW1wbGVzLCB0YXJnZXQgdmFyaWFibGVzKQoKIyBzcGxpdCB0byB0cmFpbiBhbmQgdGVzdCBzZXRzCnNldC5zZWVkKDQyKQpzcGxpdCA9IG1scjM6OnBhcnRpdGlvbih0YXNrLCByYXRpbyA9IDAuOCkKIyBzcGxpdCR0cmFpbiAjIHRyYWluIGluZGljZXMKIyBzcGxpdCR0ZXN0ICMgdGVzdCBpbmRpY2VzCmBgYApgYGAKPFRhc2tTdXJ2OkJSQ0EtVENHQT4gKDEwNDcgeCA1NCkKKiBUYXJnZXQ6IHRpbWUsIHN0YXR1cwoqIFByb3BlcnRpZXM6IC0KKiBGZWF0dXJlcyAoNTIpOgogIC0gZGJsICg1Mik6IEFDVFIzQiwgQU5MTiwgQkFHMSwgQkNMMiwgQklSQzUsIEJMVlJBLCBDQ05CMSwgQ0NORTEsIENEQzIwLCBDREM2LCBDREgzLAogICAgQ0VOUEYsIENFUDU1LCBDWFhDNSwgRUdGUiwgRVJCQjIsIEVTUjEsIEVYTzEsIEZHRlI0LCBGT1hBMSwgRk9YQzEsIEdQUjE2MCwgR1JCNywKICAgIEtJRjJDLCBLUlQxNCwgS1JUMTcsIEtSVDUsIE1BUFQsIE1ETTIsIE1FTEssIE1JQSwgTUtJNjcsIE1MUEgsIE1NUDExLCBNWUJMMiwgTVlDLAogICAgTkFUMSwgTkRDODAsIE5VRjIsIE9SQzYsIFBHUiwgUEhHREgsIFBUVEcxLCBSUk0yLCBTRlJQMSwgU0xDMzlBNiwgVE1FTTQ1QiwgVFlNUywKICAgIFVCRTJDLCBVQkUyVCwgYWdlLCBldGhuaWNpdHkKYGBgCgpXZSBjcmVhdGUgYSBMYXNzbyBDb3ggWyoqbWxyMyoqXShodHRwczovL21scjMubWxyLW9yZy5jb20pICpncmFwaCBsZWFybmVyKiAoYSB3cmFwcGVyIGFyb3VuZCB0aGUgYGdsbW5ldDo6Y3YuZ2xtbmV0KClgIGZ1bmN0aW9uIHdpdGggdGhlIGNhcGFjaXR5IHRvIHByb3ZpZGUgc3Vydml2YWwgcHJlZGljdGlvbnMpLCB3aGVyZSB3ZSBzcGVjaWZ5IHRoZSB0d28gY2xpbmljYWwgdmFyaWFibGVzIHRvIGJlICptYW5kYXRvcnkqIChpLmUuIG5vIHBlbmFsaXphdGlvbikgYW5kIHRoZSAkcyQgdmFsdWUgKCRcbGFtYmRhJCBwYXJhbWV0ZXIgdXNlZCBmb3IgcHJlZGljdGlvbikgZXF1YWwgdG8gYGxhbWJkYS5taW5gOgpgYGB7cn0KI3RhaWwodGFzayRmZWF0dXJlX25hbWVzKSAjIGFnZSwgZXRobmljaXR5IGFyZSB0aGUgMiBsYXN0IGZlYXR1cmVzCnBmID0gYyhyZXAoMSwgbGVuZ3RoKHRhc2skZmVhdHVyZV9uYW1lcykgLSAyKSwgcmVwKDAsIDIpKQoKIyBkZWZpbmUgbW9kZWwKY294bGFzc28gPSBscm4oJ3N1cnYuY3ZfZ2xtbmV0JywgYWxwaGEgPSAxLCBuZm9sZHMgPSA1LCBzID0gJ2xhbWJkYS5taW4nLAogIHBlbmFsdHkuZmFjdG9yID0gcGYpCiMgY294bGFzc28gIyBzZWUgZGV0YWlscyBvZiBjb3hsYXNzbyBsZWFybmVyCiMgY294bGFzc28kaGVscCgpICMgZm9yIG1vcmUgZGV0YWlscwoKIyA/bWxyX2dyYXBoc19kaXN0cmNvbXBvc2l0b3IKY294bGFzc29fZ3Jscm4gPSBtbHIzcGlwZWxpbmVzOjpwcGwoJ2Rpc3RyY29tcG9zaXRvcicsCiAgbGVhcm5lciA9IGNveGxhc3NvLAogIGVzdGltYXRvciA9ICdrYXBsYW4nLCAjIEtNIGVzdGltYXRvciBmb3IgdGhlIGJhc2VsaW5lCiAgZm9ybSA9ICdwaCcsICMgUHJvcG9ydGlvbmFsIEhhemFyZHMgZm9ybSBzaW5jZSB3ZSB1c2UgYSBMYXNzbyBDb3ggbW9kZWwKICBncmFwaF9sZWFybmVyID0gVFJVRQopCmNveGxhc3NvX2dybHJuJGlkID0gJ0xhc3NvIENveCcKIyBjb3hsYXNzb19ncmxybiRncmFwaF9tb2RlbCRwbG90KGh0bWwgPSBUUlVFKSAjIHBsb3QgdGhlIGdyYXBoIGxlYXJuZXIKYGBgCgo6Ojp7LmluZm8tYm94IC5ub3RlfQpBIENveCBwcm9wb3J0aW9uYWwgaGF6YXJkcyBtb2RlbCAoYW5kIExhc3NvIENveCBhcyBhIGNvbnNlcXVlbmNlKSBpcyBhIHNlbWktcGFyYW1ldHJpYyBtb2RlbCwgd2hpY2ggbWVhbnMgdGhhdCBpdCBkb2VzIG5vdCBwcm9kdWNlIHN1cnZpdmFsIGRpc3RyaWJ1dGlvbiBwcmVkaWN0aW9ucyBieSBkZWZhdWx0LgpIb3dldmVyLCB1c2luZyB0aGUgZnVuY3Rpb24gYHN1cnZpdmFsOjpzdXJ2Zml0LmNveHBoKClgIHlvdSBjYW4gdHJhbnNmb3JtIHRoZSBgY3YuZ2xtbmV0YCdzIG91dHB1dCBsaW5lYXIgcHJlZGljdG9ycyAoYGxwYCkgdG8gc3Vydml2YWwgZGlzdHJpYnV0aW9uIHByZWRpY3Rpb25zLgpUaGlzIHRyYW5zZm9ybWF0aW9uIGludGVybmFsbHkgdXNlcyB0aGUgQnJlc2xvdyBlc3RpbWF0b3IgZm9yIHRoZSBjdW11bGF0aXZlIGJhc2VsaW5lIGhhemFyZCAoc2VlIGBzdHlwZWAgcGFyYW1ldGVyKS4KClVzaW5nIFsqKm1scjNwcm9iYSoqXShodHRwczovL21scjNwcm9iYS5tbHItb3JnLmNvbSkgW0BTb25hYmVuZDIwMjFdLCB3ZSBjYW4gY29uc3RydWN0IGEgcGlwZWxpbmUgW0BtbHIzcGlwZWxpbmVzMjAyMV0gdGhhdCBjb21iaW5lcyB0aGUgZGlzdHJpYnV0aW9uIHByZWRpY3Rpb25zIG9mIGEgYmFzZWxpbmUgbW9kZWwgKGUuZy4gS2FwbGFuIE1laWVyKSB3aXRoIHRoZSBsaW5lYXIgcHJlZGljdG9ycyBvZiBhIENveC10eXBlIG1vZGVsIChlLmcuIExhc3NvIENveCkuClNlZSBkZXRhaWxzIHN1Y2ggYXMgdGhlIHRyYW5zZm9ybWF0aW9uIGFzc3VtcHRpb25zLCB0aGUgY2hvaWNlIG9mIHRoZSBzdXJ2aXZhbCBmdW5jdGlvbiBmb3JtIGFuZCB0aGUgYXZhaWxhYmxlIGJhc2VsaW5lIHN1cnZpdmFsIGRpc3RyaWJ1dGlvbiBlc3RpbWF0b3JzIG9uIHRoZSByZXNwZWN0aXZlIFtkb2N1bWVudGF0aW9uXShodHRwczovL21scjNwcm9iYS5tbHItb3JnLmNvbS9yZWZlcmVuY2UvbWxyX3BpcGVvcHNfY29tcG9zZV9kaXN0ci5odG1sKS4KOjo6Cgo8YnI+CgpUcmFpbiB0aGUgTGFzc28gQ294IG1vZGVsOgpgYGB7cn0Kc2V0LnNlZWQoMykKY294bGFzc29fZ3Jscm4kdHJhaW4odGFzaywgcm93X2lkcyA9IHNwbGl0JHRyYWluKQojIHZpZXcgYGN2LmdsbW5ldGAgZml0CmNveGxhc3NvX2dybHJuJG1vZGVsJHN1cnYuY3ZfZ2xtbmV0JG1vZGVsCmBgYApgYGAKQ2FsbDogIChpZiAoY3YpIGdsbW5ldDo6Y3YuZ2xtbmV0IGVsc2UgZ2xtbmV0OjpnbG1uZXQpKHggPSBkYXRhLCB5ID0gdGFyZ2V0LCAgICAgIG5mb2xkcyA9IDVMLCBhbHBoYSA9IDEsIHBlbmFsdHkuZmFjdG9yID0gYygxLCAuLi4sIDAsIDApLCBmYW1pbHkgPSAiY294IikgCgpNZWFzdXJlOiBQYXJ0aWFsIExpa2VsaWhvb2QgRGV2aWFuY2UgCgogICAgIExhbWJkYSBJbmRleCBNZWFzdXJlICAgICBTRSBOb256ZXJvCm1pbiAwLjAxMDgyICAgIDE0ICAgMTIuMzEgMC4yNzQzICAgICAgMTUKMXNlIDAuMDM2MjYgICAgIDEgICAxMi4zNSAwLjI1NjQgICAgICAgMgpgYGAKCkdldCB0aGUgc3Vydml2YWwgZGlzdHJpYnV0aW9uIHByZWRpY3Rpb25zICgkZGlzdHIkKSBhbG9uZyB3aXRoIHRoZSBsaW5lYXIgcHJlZGljdG9ycyAoJGxwJCk6CmBgYHtyfQpwcmVkID0gY294bGFzc29fZ3Jscm4kcHJlZGljdCh0YXNrLCByb3dfaWRzID0gc3BsaXQkdGVzdCkKaGVhZChhcy5kYXRhLnRhYmxlKHByZWQpKQpgYGAKYGBgCiAgIHJvd19pZHMgICAgICB0aW1lIHN0YXR1cyAgICAgY3JhbmsgICAgICAgIGxwICAgICBkaXN0cgoxOiAgICAgICA1IDAuOTUyNzcyMSAgRkFMU0UgLTIuMzQ2NTc0IC0yLjM0NjU3NCA8bGlzdFsxXT4KMjogICAgICAgNiA0LjA0MzgwNTYgIEZBTFNFIC0yLjgwNjcwOCAtMi44MDY3MDggPGxpc3RbMV0+CjM6ICAgICAgMTUgMS43Mzg1MzUyICBGQUxTRSAtMS44NDUwNDIgLTEuODQ1MDQyIDxsaXN0WzFdPgo0OiAgICAgIDQ1IDQuNTgwNDI0NCAgRkFMU0UgLTEuNzE1MDQxIC0xLjcxNTA0MSA8bGlzdFsxXT4KNTogICAgICA1MCA1LjEyNzk5NDUgIEZBTFNFIC0yLjc5MDEyMiAtMi43OTAxMjIgPGxpc3RbMV0+CjY6ICAgICAgNTQgNi42ODU4MzE2ICBGQUxTRSAtMi40NjYzNjAgLTIuNDY2MzYwIDxsaXN0WzFdPgpgYGAKClNvIGZvciBldmVyeSBwYXRpZW50IGluIHRoZSB0ZXN0IHNldCwgdGhlIExhc3NvIENveCBtb2RlbCBwcmVkaWN0aW9uIGlzIGEgbGluZWFyIHByZWRpY3RvciBvZiB0aGUgZm9ybSAkbHAgPSBcaGF0e1xiZXRhfSBYX3tuZXd9JC4KJGNyYW5rJCBzdGFuZHMgZm9yIGNvbnRpbnVvdXMgcmFua2luZyBzY29yZSBhbmQgaXQncyB0aGUgc2FtZSBhcyAkbHAkIGZvciB0aGUgTGFzc28gQ294IG1vZGVsLgpUaGUgJGRpc3RyJCBwcmVkaWN0aW9ucyBhcmUgdGhlIHBlci1wYXRpZW50IHN1cnZpdmFsIGRpc3RyaWJ1dGlvbiBwcmVkaWN0aW9ucywgaW1wbGVtZW50ZWQgYnkgdGhlIGBSYCBwYWNrYWdlIFtkaXN0cjZdKGh0dHBzOi8vZ2l0aHViLmNvbS9hbGFuLXR1cmluZy1pbnN0aXR1dGUvZGlzdHI2KSB3aGljaCB0aGUgWyoqbWxyM3Byb2JhKipdKGh0dHBzOi8vbWxyM3Byb2JhLm1sci1vcmcuY29tKSBpbXBvcnRzLgpTZWUgcmVzcGVjdGl2ZSBbZG9jdW1lbnRhdGlvbl0oaHR0cHM6Ly9tbHIzcHJvYmEubWxyLW9yZy5jb20vcmVmZXJlbmNlL1ByZWRpY3Rpb25TdXJ2Lmh0bWwpIG9uIHRoZSBkaWZmZXJlbnQgcHJlZGljdGlvbiB0eXBlcyBzdXBwb3J0ZWQuCgpBbiBleGFtcGxlIG9mIHVzaW5nIHRoZSBgZGlzdHJgIHByZWRpY3Rpb25zIHdvdWxkIGJlIHRvIHJlcXVlc3QgZm9yIHRoZSBzdXJ2aXZhbCBwcm9iYWJpbGl0eSBhdCBlLmcuICQxLDUsMTAsMjAkIHllYXJzIGZvciB0aGUgZmlyc3QgdHdvIHBhdGllbnRzIGluIHRoZSB0ZXN0IHNldDoKYGBge3J9CnRpbWVzID0gYygxLDUsMTAsMjApCnByZWQkZGlzdHIkc3Vydml2YWwodGltZXMpWyxjKDEsMildCgojIHNhbWUgbG9naWMgZm9yIHRoZSBjdW11bGF0aXZlIGhhemFyZAojIHByZWQkZGlzdHIkY3VtSGF6YXJkKHRpbWVzKVssYygxLDIpXQpgYGAKYGBgCiAgICAgICAgWywxXSAgICAgIFssMl0KMSAgMC45OTgyMjY0IDAuOTk4ODgwMQo1ICAwLjk4MDM1MTUgMC45ODc1NTI2CjEwIDAuOTQ4NTA1NyAwLjk2NzE4MDcKMjAgMC45MDUwODMyIDAuOTM4OTkxOApgYGAKCjxicj4KCiMjIyBEaXNjcmltaW5hdGlvbiBtZXRyaWNzIHstfQoKV2Ugd2FudCB0byB0ZXN0IG91ciBMYXNzbyBDb3ggbW9kZWwgYW5kIHNlZSBob3cgd2VsbCBpdCB3YXMgYWJsZSB0byAqKmRpc2NyaW1pbmF0ZSB0aGUgcGF0aWVudHMgaW4gdGhlIHRlc3Qgc2V0KiouCkZvciB0aGlzIHdlIGNhbiB1c2UgdGhlICRscCQgcHJlZGljdGlvbnMgb2YgTGFzc28gQ294IG1vZGVsIGFuZCBtZXRyaWNzIHN1Y2ggYXMgdGhlICh0aW1lLWRlcGVuZGVudCkgQy1pbmRleCBhbmQgKHRpbWUtZGVwZW5kZW50KSBBVUMuCjxicj4KCjxmb250IHNpemU9IjQiPiAqKkhhcnJlbGwncyBDLWluZGV4KiogW0BIYXJyZWxsMTk4Ml06IDwvZm9udD4gCmBgYHtyfQpoYXJyZWxsX2MgPSBtc3IoJ3N1cnYuY2luZGV4JykKaGFycmVsbF9jJGlkID0gJ3N1cnYuY2luZGV4LmhhcnJlbGwnCgojIGhhcnJlbGxfYyAjIGdldCBzb21lIGRldGFpbHMgYWJvdXQgdGhlIG1lYXN1cmUKIyBoYXJyZWxsX2MkbWluaW1pemUgIyBGQUxTRSA9PiBoaWdoZXIgQy1pbmRleCBpcyBiZXR0ZXIKIyBoYXJyZWxsX2MkcmFuZ2UgIyBbMCwgMV0gPT4gW21pbiwgbWF4XQojIGhhcnJlbGxfYyRwcmVkaWN0X3R5cGUgIyB1c2VzIHRoZSAkY3JhbmskIHByZWRpY3Rpb25zIChlcXVhbCB0byAkbHAkIGZvciBMYXNzbyBDb3gKCnByZWQkc2NvcmUoaGFycmVsbF9jKQpgYGAKYGBgCnN1cnYuY2luZGV4LmhhcnJlbGwgCiAgICAgICAgICAwLjYyMjQzMDYgCmBgYAoKPGJyPgoKPGZvbnQgc2l6ZT0iNCI+ICoqVW5vJ3MgQy1pbmRleCoqIFtAVW5vMjAxMV06IChhY3Jvc3MgYWxsIHRpbWUgcG9pbnRzIG9mIHRoZSB0ZXN0IHNldCk6IDwvZm9udD4gCmBgYHtyfQp1bm9fYyA9IG1zcignc3Vydi5jaW5kZXgnLCB3ZWlnaHRfbWV0aCA9ICdHMicpCnVub19jJGlkID0gJ3N1cnYuY2luZGV4LnVubycKCiMgVW5vJ3MgQyBuZWVkcyB0aGUgdHJhaW4gZGF0YQpwcmVkJHNjb3JlKHVub19jLCB0YXNrID0gdGFzaywgdHJhaW5fc2V0ID0gc3BsaXQkdHJhaW4pCmBgYApgYGAKc3Vydi5jaW5kZXgudW5vIAogICAgICAwLjU5MzI0MjYgCmBgYAoKPGJyPgoKPGZvbnQgc2l6ZT0iNCI+ICoqVW5vJ3MgSW50ZWdyYXRlZCBBVUMqKiBbQFVubzIwMDddIChhY3Jvc3MgYWxsIHRpbWUgcG9pbnRzIG9mIHRoZSB0ZXN0IHNldCk6IDwvZm9udD4gCmBgYHtyfQp1bm9faWF1YyA9IG1zcignc3Vydi51bm9fYXVjJykKdW5vX2lhdWMkaWQgPSAnc3Vydi51bm9faWF1YycKIyB1bm9faWF1YyRwYXJhbV9zZXQkdmFsdWVzJGludGVncmF0ZWQgIyBpbnRlZ3JhdGVkID0gVFJVRSBieSBkZWZhdWx0CiMgc29ydCh1bmlxdWUocHJlZCR0cnV0aFssMV0pKSAjIHRpbWUgcG9pbnRzIHVzZWQKCiMgdW5vX2lhdWMkcHJvcGVydGllcyAjIG5lZWRzIHRoZSB0cmFpbiBkYXRhCnByZWQkc2NvcmUodW5vX2lhdWMsIHRhc2sgPSB0YXNrLCB0cmFpbl9zZXQgPSBzcGxpdCR0cmFpbikKYGBgCmBgYApzdXJ2LnVub19pYXVjIAogICAgMC42NTg1NzkxIApgYGAKCjxicj4KCjxmb250IHNpemU9IjQiPiAqKlVubydzIEFVQyBhdCBhIHNwZWNpZmljIHRpbWUgcG9pbnQqKiwgZS5nLiAkMTAkIHllYXJzOiA8L2ZvbnQ+IApgYGB7cn0KdW5vX2F1YyA9IG1zcignc3Vydi51bm9fYXVjJywgaW50ZWdyYXRlZCA9IEZBTFNFLCB0aW1lcyA9IDEwKQp1bm9fYXVjJGlkID0gJ3N1cnYudW5vX2F1Yy4xMCcKCiMgbmVlZHMgdGhlIHRyYWluIGRhdGEKcHJlZCRzY29yZSh1bm9fYXVjLCB0YXNrID0gdGFzaywgdHJhaW5fc2V0ID0gc3BsaXQkdHJhaW4pCmBgYApgYGAKc3Vydi51bm9fYXVjLjEwIAogICAgICAwLjY2NzAxNCAKYGBgCgo8YnI+CgojIyMgQ2FsaWJyYXRpb24gbWV0cmljcyB7LX0KCldlIHdhbnQgdG8gdGVzdCBob3cgd2VsbCBvdXIgTGFzc28gQ294IG1vZGVsIHdhcyAqKmNhbGlicmF0ZWQqKi4gQEFuZHJlczIwMTggYW5kIEBIYWlkZXIyMDIwIHN1Z2dlc3RlZCB0aGUgZGlzdHJpYnV0aW9uYWwgKEQpLWNhbGlicmF0aW9uIGFjY291bnRpbmcgc3Vydml2YWwgcHJvYmFiaWxpdGllcyBhY3Jvc3MgYWxsIHRpbWVzLiBUaGlzIGNhbiBiZSB1c2VmdWwgd2hlbiBhc3Nlc3NpbmcgdGhlIGVudGlyZSBwb3N0LXRyZWF0bWVudCBzdXJ2aXZhbCBwcm9nbm9zaXMsIGZvciBleGFtcGxlLCBhc3Nlc3NpbmcgdGhlIHBvc3QgbGl2ZXIgdHJhbnNwbGFudGF0aW9uIHN1cnZpdmFsIHV0aWxpdHkgaW4gQEFuZHJlczIwMTguCgo8Zm9udCBzaXplPSI0Ij4gKipELWNhbGlicmF0aW9uKiogPC9mb250PiAKYGBge3J9CmRjYWwgPSBtc3IoJ3N1cnYuZGNhbGliJykKcHJlZCRzY29yZShkY2FsKQpgYGAKYGBgCnN1cnYuZGNhbGliIAogICAyMi41NzAzNSAKYGBgCgo8YnI+CgojIyMgT3ZlcmFsbCBtZXRyaWNzIHstfQoKVXN1YWxseSB3ZSBkZXJpdmUgYW4gZXN0aW1hdGlvbiBvZiB0aGUgZXJyb3IgYmV0d2VlbiB0aGUgc3Vydml2YWwgZGlzdHJpYnV0aW9ucyAoJGRpc3RyJCBwcmVkaWN0aW9ucykgb2YgdGhlIHBhdGllbnRzIGluIHRoZSB0ZXN0IHNldCBhbmQgdGhlaXIgYWN0dWFsIHN1cnZpdmFsIG91dGNvbWVzIChjb3JyZXNwb25kaW5nIHRvIHRoZSBzdXJ2aXZhbCB0YXNrJ3MgYHRpbWVgIGFuZCBgc3RhdHVzYCB2YXJpYWJsZXMpLgpUaGUgbW9zdCBmcmVxdWVudGx5IHVzZWQgbWV0cmljIGlzIHRoZSBCcmllciBTY29yZSBbQEdyYWYxOTk5XToKPGJyPgoKPGZvbnQgc2l6ZT0iNCI+ICoqSW50ZWdyYXRlZCBCcmllciBTY29yZSAoSUJTKSoqIChhY3Jvc3MgYWxsIHRpbWUgcG9pbnRzIG9mIHRoZSB0ZXN0IHNldCk6IDwvZm9udD4gCmBgYHtyfQppYnJpZXIgPSBtc3IoJ3N1cnYuYnJpZXInLCBwcm9wZXIgPSBUUlVFKQojIGlicmllciRoZWxwKCkgIyBzZWUgZG9jdW1lbnRhdGlvbgojIGlicmllciRwcmVkaWN0X3R5cGUgIyB1c2VzIHRoZSBgZGlzdHJgIHByZWRpY3Rpb25zCgojIGJldHRlciB0byB1c2UgdGhlIHRyYWluIGRhdGEgZm9yIHRoZSBLYXBsYW4tTWVpZXIgZXN0aW1hdGlvbiBvZiB0aGUgY2Vuc29yaW5nIGRpc3RyaWJ1dGlvbiwgYnV0IGNhbiB1c2UgdGhlIHRlc3Qgc2V0IGFzIHdlbGwKcHJlZCRzY29yZShpYnJpZXIsIHRhc2sgPSB0YXNrLCB0cmFpbl9zZXQgPSBzcGxpdCR0cmFpbikKYGBgCmBgYApzdXJ2LmdyYWYgCjAuMzM4Mzg2IApgYGAKCldlIGNhbiBhbHNvIGdldCB0aGUgKnN0YW5kYXJkIGVycm9yKiBvZiBJQlMgKHRoZSBhYm92ZSByZXN1bHQgaXMgdGhlIG1lYW4gYWNyb3NzIGFsbCB0aGUgdGVzdCBzZXQncyBwYXRpZW50cykgYXMgZm9sbG93czoKYGBge3J9Cmlicmllcl9zZSA9IG1zcignc3Vydi5icmllcicsIHByb3BlciA9IFRSVUUsIHNlID0gVFJVRSkKcHJlZCRzY29yZShpYnJpZXJfc2UsIHRhc2sgPSB0YXNrLCB0cmFpbl9zZXQgPSBzcGxpdCR0cmFpbikKYGBgCmBgYAogc3Vydi5ncmFmIAowLjAyMTA2NzQ0CmBgYAoKPGJyPgoKPGZvbnQgc2l6ZT0iNCI+ICoqQnJpZXIgU2NvcmUgYXQgYSBzcGVjaWZpYyB0aW1lIHBvaW50KiosIGUuZy4gJDEwJCB5ZWFyczogPC9mb250PiAKYGBge3J9CmJyaWVyMTAgPSBtc3IoJ3N1cnYuYnJpZXInLCBwcm9wZXIgPSBUUlVFLCBpbnRlZ3JhdGVkID0gRkFMU0UsIHRpbWVzID0gMTApCmJyaWVyMTAkaWQgPSAnc3Vydi5ncmFmLjEwJwoKIyBiZXR0ZXIgdG8gdXNlIHRoZSB0cmFpbiBkYXRhIGZvciB0aGUgS2FwbGFuLU1laWVyIGVzdGltYXRpb24gb2YgdGhlIGNlbnNvcmluZyBkaXN0cmlidXRpb24sIGJ1dCBjYW4gdXNlIHRoZSB0ZXN0IHNldCBhcyB3ZWxsCnByZWQkc2NvcmUoYnJpZXIxMCwgdGFzayA9IHRhc2ssIHRyYWluX3NldCA9IHNwbGl0JHRyYWluKQpgYGAKYGBgCnN1cnYuZ3JhZi4xMCAKICAgMC4zNzUxOTU4IApgYGAKCjxicj4KCjxmb250IHNpemU9IjQiPiAqKlJpZ2h0LWNlbnNvcmVkIExvZ2FyaXRobWljIExvc3Mgc2NvcmUqKiAoUkNMTCkgW0BBdmF0aTIwMjA7QFNvbmFiZW5kMjAyMl06IDwvZm9udD4gCmBgYHtyfQpyY2xsID0gbXNyKCdzdXJ2LnJjbGwnKQpwcmVkJHNjb3JlKHJjbGwpCmBgYApgYGAKc3Vydi5yY2xsIAogNC42ODY3NDIgCmBgYAoKPGJyPgoKOjo6ey5pbmZvLWJveCAubm90ZX0KVmlldyBhbGwgZXZhbHVhdGlvbiBtZXRyaWNzIGZvciBzdXJ2aXZhbCBkYXRhIGltcGxlbWVudGVkIGluIFsqKm1scjNwcm9iYSoqXShodHRwczovL21scjNwcm9iYS5tbHItb3JnLmNvbSkgW2hlcmVdKGh0dHBzOi8vbWxyM3Byb2JhLm1sci1vcmcuY29tL3JlZmVyZW5jZS8jc3Vydml2YWwtbWVhc3VyZXMpCjo6OgoKPGJyPgoKIyMjIFVuY2VydGFpbnR5IFF1YW50aWZpY2F0aW9uIHstfQoKU2ltaWxhciBwcm9jZWR1cmUgYXMgZm9sbG93ZWQgaW4gYSBbcHJldmlvdXMgc2VjdGlvbl0oI3VxMSkuCgpXZSB3aWxsIHBlcmZvcm0gYSAqKnN0cmF0aWZpZWQgc3BsaXQqKiBvZiB0aGUgQlJDQS1UQ0dBIHN1cnZpdmFsIHRhc2sgdG8gdHJhaW5pbmcgYW5kIHRlc3Qgc2V0cyAod2l0aCBhICQ4MFwlLzIwXCUkIHJhdGlvIGFzIGJlZm9yZSkuClN0cmF0aWZpY2F0aW9uIG9uIHRoZSBjZW5zb3JpbmcgaW5kaWNhdG9yIGBzdGF0dXNgIGlzIGltcG9ydGFudCBiZWNhdXNlIHdlIHdhbnQgb3VyIHRyYWluaW5nIGFuZCB0ZXN0IHNldHMgdG8gaGF2ZSB0aGUgc2FtZSBjZW5zb3JpbmcgZGlzdHJpYnV0aW9uIGFzIHRoZSBpbml0aWFsIGRhdGFzZXQuClRodXMgd2UgY2FuIGF2b2lkIG1lYXN1cmluZyBwZXJmb3JtYW5jZSBvbiB0ZXN0IHNldHMgd2l0aCBzZXZlcmVseSBkaWZmZXJlbnQgY2Vuc29yaW5nIGRpc3RyaWJ1dGlvbnMgdGhhdCBtaWdodCBpbmZsdWVuY2UgdGhlIHBlcmZvcm1hbmNlIHNjb3Jlcy4KClN0cmF0aWZ5IHN1cnZpdmFsIHRhc2sgYnkgYHN0YXR1c2A6CmBgYHtyfQpjb3hsYXNzb19ncmxybiRyZXNldCgpICMgdW4tdHJhaW4gbW9kZWwKCnRhc2skY29sX3JvbGVzJHN0cmF0dW0gPSAnc3RhdHVzJwojIHRhc2sKYGBgCgpOZXh0LCB3ZSBkZWZpbmUgdGhlIHR5cGUgb2YgcmVzYW1wbGluZyAoYD9tbHJfcmVzYW1wbGluZ3Nfc3Vic2FtcGxpbmdgKSwgdHJhaW4gdGhlIExhc3NvIENveCBtb2RlbCBvbiBhbGwgdHJhaW5pbmcgc2V0cyAoJDEwMCQpIGFuZCBzdG9yZSB0aGUgZml0dGVkIG1vZGVscyBmb3IgZmVhdHVyZSBzZWxlY3Rpb24gYW5kIGV2YWx1YXRpb246CmBgYHtyLCByZXN1bHRzPSdoaWRlJ30KIyAxMDAgdGltZXMgdHJhaW4vdGVzdCBzcGxpdCAoODAlIGZvciB0cmFpbmluZywgMjAlIGZvciB2YWxpZGF0aW9uKQpzdWJzYW1wbGluZyA9IHJzbXAoJ3N1YnNhbXBsaW5nJywgcmVwZWF0cyA9IDEwMCwgcmF0aW8gPSAwLjgpCgpzZXQuc2VlZCg0MikKcnIgPSBtbHIzOjpyZXNhbXBsZSh0YXNrID0gdGFzaywgbGVhcm5lciA9IGNveGxhc3NvX2dybHJuLCAKICByZXNhbXBsaW5nID0gc3Vic2FtcGxpbmcsIHN0b3JlX21vZGVscyA9IFRSVUUsIHN0b3JlX2JhY2tlbmRzID0gVFJVRSkKYGBgCgpXZSBjYW4gdXNlIGFsbCB0aGUgYWZvcmVtZW50aW9uZWQgZXZhbHVhdGlvbiBtZXRyaWNzIHRvIG1lYXN1cmUgdGhlIHBlcmZvcm1hbmNlIG9mIHRoZSBMYXNzbyBDb3ggbW9kZWxzIG9uIHRoZSAkMTAwJCBkaWZmZXJlbnQgdGVzdCBzZXRzLgpOb3RlIHRoYXQgaWYgYSBtZXRyaWMgbmVlZHMgdGhlIHRyYWluaW5nIGRhdGFzZXQgaXQgaXMgYXV0b21hdGljYWxseSBwcm92aWRlZCBieSB0aGUgYFJlc2FtcGxlUmVzdWx0YCBvYmplY3QgKGBycmApOgpgYGB7cn0KbWVhc3VyZXMgPSBsaXN0KGhhcnJlbGxfYywgdW5vX2MsIHVub19pYXVjLCB1bm9fYXVjLCBpYnJpZXIsIGJyaWVyMTAsIHJjbGwsIGRjYWwpCgpyZXMgPSByciRzY29yZShtZWFzdXJlcyA9IG1lYXN1cmVzKQpoZWFkKHJlcykKYGBgCmBgYAogICAgIHRhc2tfaWQgbGVhcm5lcl9pZCByZXNhbXBsaW5nX2lkIGl0ZXJhdGlvbiBzdXJ2LmNpbmRleC5oYXJyZWxsIHN1cnYuY2luZGV4LnVubwoxOiBCUkNBLVRDR0EgIExhc3NvIENveCAgIHN1YnNhbXBsaW5nICAgICAgICAgMSAgICAgICAgICAgMC41Njc5MTY3ICAgICAgIDAuNjA5MDMwNAoyOiBCUkNBLVRDR0EgIExhc3NvIENveCAgIHN1YnNhbXBsaW5nICAgICAgICAgMiAgICAgICAgICAgMC41NTI0NTkwICAgICAgIDAuNDk2OTMyNgozOiBCUkNBLVRDR0EgIExhc3NvIENveCAgIHN1YnNhbXBsaW5nICAgICAgICAgMyAgICAgICAgICAgMC43NTAyODEyICAgICAgIDAuNTY4MjA2MQo0OiBCUkNBLVRDR0EgIExhc3NvIENveCAgIHN1YnNhbXBsaW5nICAgICAgICAgNCAgICAgICAgICAgMC42NTkxMzM3ICAgICAgIDAuNTI5NDgxNgo1OiBCUkNBLVRDR0EgIExhc3NvIENveCAgIHN1YnNhbXBsaW5nICAgICAgICAgNSAgICAgICAgICAgMC41NzUyNDcyICAgICAgIDAuNTU1MzMzNgo2OiBCUkNBLVRDR0EgIExhc3NvIENveCAgIHN1YnNhbXBsaW5nICAgICAgICAgNiAgICAgICAgICAgMC41NDI3ODM3ICAgICAgIDAuNjk3NTc0MAogICBzdXJ2LnVub19pYXVjIHN1cnYudW5vX2F1Yy4xMCBzdXJ2LmdyYWYgc3Vydi5ncmFmLjEwIHN1cnYucmNsbCAgc3Vydi5kY2FsaWIKMTogICAgIDAuNjYyODM1MCAgICAgICAwLjQ3MTkzMzUgMC4zMjU1MTgxICAgIDAuNjE2MTgyNSAgNi4wMzg5MDkgMS4wMjY5MDFlKzA3CjI6ICAgICAwLjQwMzg2ODIgICAgICAgMC41NzEyMDEyIDAuNDgxNTcwMCAgICAwLjY2NjY5OTQgIDYuODkzNDI1IDMuMzQyODA0ZSswOAozOiAgICAgMC41ODgyOTk1ICAgICAgIDAuNTIzNTQzOSAwLjI3OTY1ODAgICAgMC4yOTI2MzM0ICA0Ljk1NTExMCAyLjQ5MDk4MmUrMDEKNDogICAgIDAuNTM1NjQ2MSAgICAgICAwLjUwODIzODUgMC4yOTE1Mzk1ICAgIDAuMjMyNDI0OCAgNC45NTU0MDkgMi4yMjI4NDVlKzAxCjU6ICAgICAwLjYwOTA2MTUgICAgICAgMC41Mjg4NzUyIDAuMzQ5NzE4OSAgICAwLjQzNzExNDQgIDQuOTQzOTQzIDMuMzQ2NzgwZSswMQo2OiAgICAgMC42NDk0Nzc5ICAgICAgIDAuNjQwMDMyOCAwLjIwMzU2MDkgICAgMC40MjI4MTY5ICA1LjQzNDk3MCA0LjIyMzc0MmUrMDIKSGlkZGVuIGNvbHVtbnM6IHRhc2ssIGxlYXJuZXIsIHJlc2FtcGxpbmcsIHByZWRpY3Rpb24KYGBgCldlIGV4dHJhY3QgYW5kIHZpc3VhbGl6ZSB0aGUgZGlzY3JpbWluYXRpb24gYW5kIGNhbGlicmF0aW9uIChyZXNhbXBsZWQpIHBlcmZvcm1hbmNlIG9mIG91ciBMYXNzbyBDb3ggbW9kZWwgdXNpbmcgc2V2ZXJhbCBldmFsdWF0aW9uIG1ldHJpY3M6CmBgYHtyfQpzZXQuc2VlZCg0MikKCiMgQy1pbmRleGVzLCBBVUNzIChpbnRlZ3JhdGVkIGFuZCBhdCB0ID0gMTAgeWVhcnMpCnJlc1ssIC4oc3Vydi5jaW5kZXguaGFycmVsbCwgc3Vydi5jaW5kZXgudW5vLCBzdXJ2LnVub19pYXVjLCBzdXJ2LnVub19hdWMuMTApXSAlPiUgCiAgdGlkeXI6OnBpdm90X2xvbmdlcihjb2xzID0gdGlkeXNlbGVjdDo6ZXZlcnl0aGluZygpLCAKICAgIG5hbWVzX3RvID0gJ01lYXN1cmUnLCB2YWx1ZXNfdG8gPSAnVmFsdWUnKSAlPiUKICBtdXRhdGUoTWVhc3VyZSA9IGNhc2Vfd2hlbigKICAgIE1lYXN1cmUgPT0gJ3N1cnYuY2luZGV4LmhhcnJlbGwnIH4gJ0hhcnJlbGxcJ3MgQy1pbmRleCcsCiAgICBNZWFzdXJlID09ICdzdXJ2LmNpbmRleC51bm8nIH4gJ1Vub1wncyBDLWluZGV4JywKICAgIE1lYXN1cmUgPT0gJ3N1cnYudW5vX2lhdWMnIH4gJ1Vub1wncyBJbnRlZ3JhdGVkIEFVQycsCiAgICBNZWFzdXJlID09ICdzdXJ2LnVub19hdWMuMTAnIH4gJ1Vub1wncyBBVUMgKHQgPSAxMCB5ZWFycyknLAogICkpICU+JQogICBtdXRhdGUoTWVhc3VyZSA9IGZhY3RvcihNZWFzdXJlLCBsZXZlbHMgPSBjKAogICAgICdIYXJyZWxsXCdzIEMtaW5kZXgnLAogICAgICdVbm9cJ3MgQy1pbmRleCcsCiAgICAgJ1Vub1wncyBJbnRlZ3JhdGVkIEFVQycsCiAgICAgJ1Vub1wncyBBVUMgKHQgPSAxMCB5ZWFycyknKSkpICU+JQogIGdncGxvdChhZXMoeCA9IE1lYXN1cmUsIHkgPSBWYWx1ZSwgZmlsbCA9IE1lYXN1cmUpKSArCiAgICBnZW9tX2JveHBsb3QoKSArIAogICAgeWxpbShjKDAuMiwgMC44KSkgKyAKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuNSwgY29sb3IgPSAncmVkJywgbGluZXR5cGUgPSAnZGFzaGVkJykgKwogICAgdGhlbWVfYncoYmFzZV9zaXplID0gMTQpICsgCiAgICBsYWJzKHRpdGxlID0gJ0Rpc2NyaW1pbmF0aW9uIE1lYXN1cmVzJykgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkpCmBgYApgYGB7ciwgZWNobz1GQUxTRX0KcGRmKCJtbHIzX2Rpc2NyaW1pbmF0aW9uX21zcnMucGRmIiwgd2lkdGggPSA2LCBoZWlnaHQgPSAzKQpyZXNbLCAuKHN1cnYuY2luZGV4LmhhcnJlbGwsIHN1cnYuY2luZGV4LnVubywgc3Vydi51bm9faWF1Yywgc3Vydi51bm9fYXVjLjEwKV0gJT4lIAogIHRpZHlyOjpwaXZvdF9sb25nZXIoY29scyA9IHRpZHlzZWxlY3Q6OmV2ZXJ5dGhpbmcoKSwgCiAgICBuYW1lc190byA9ICdNZWFzdXJlJywgdmFsdWVzX3RvID0gJ1ZhbHVlJykgJT4lCiAgbXV0YXRlKE1lYXN1cmUgPSBjYXNlX3doZW4oCiAgICBNZWFzdXJlID09ICdzdXJ2LmNpbmRleC5oYXJyZWxsJyB+ICdIYXJyZWxsXCdzIEMtaW5kZXgnLAogICAgTWVhc3VyZSA9PSAnc3Vydi5jaW5kZXgudW5vJyB+ICdVbm9cJ3MgQy1pbmRleCcsCiAgICBNZWFzdXJlID09ICdzdXJ2LnVub19pYXVjJyB+ICdVbm9cJ3MgSW50ZWdyYXRlZCBBVUMnLAogICAgTWVhc3VyZSA9PSAnc3Vydi51bm9fYXVjLjEwJyB+ICdVbm9cJ3MgQVVDICh0ID0gMTAgeWVhcnMpJywKICApKSAlPiUKICAgbXV0YXRlKE1lYXN1cmUgPSBmYWN0b3IoTWVhc3VyZSwgbGV2ZWxzID0gYygKICAgICAnSGFycmVsbFwncyBDLWluZGV4JywKICAgICAnVW5vXCdzIEMtaW5kZXgnLAogICAgICdVbm9cJ3MgSW50ZWdyYXRlZCBBVUMnLAogICAgICdVbm9cJ3MgQVVDICh0ID0gMTAgeWVhcnMpJykpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBNZWFzdXJlLCB5ID0gVmFsdWUsIGZpbGwgPSBNZWFzdXJlKSkgKwogICAgZ2VvbV9ib3hwbG90KCkgKyAKICAgIHlsaW0oYygwLjIsIDAuOCkpICsgCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLjUsIGNvbG9yID0gJ3JlZCcsIGxpbmV0eXBlID0gJ2Rhc2hlZCcpICsKICAgIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE0KSArIAogICAgbGFicyh0aXRsZSA9ICdEaXNjcmltaW5hdGlvbiBNZWFzdXJlcycpICsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKQpkZXYub2ZmKCkKYGBgCiFbX0Rpc2NyaW1pbmF0aW9uIHBlcmZvcm1hbmNlIG9mIExhc3NvIENveCBvbiB0aGUgVENHQS1CUkNBIGRhdGFzZXQgKGV4cHJlc3Npb24gZGF0YSBvZiB0aGUgUEFNNTAgZ2VuZXMgYW5kIHRoZSB2YXJpYWJsZXMgYWdlIGFuZCBldGhuaWNpdHkpLiBQZXJmb3JtYW5jZSBtZXRyaWNzIHVzZWQgYXJlIEhhcnJlbGwncyBDLWluZGV4LCBVbm8ncyBDLWluZGV4LCBVbm8ncyBJbnRlZ3JhdGVkIEFVQyBhbmQgVW5vJ3MgQVVDIGF0IDEwIHllYXJzLiBUaGUgZGF0YXNldCB3YXMgc3BsaXQgdG8gdHJhaW5pbmcvdmFsaWRhdGlvbiBzZXRzIDEwMCB0aW1lcyB0byBhbGxvdyBmb3IgdGhlIHF1YW50aWZpY2F0aW9uIG9mIHVuY2VydGFpbnR5IGluIHRoZSBkaWZmZXJlbnQgcGVyZm9ybWFuY2UgZXN0aW1hdGVzLl9dKGZpZy9tbHIzX2Rpc2NyaW1pbmF0aW9uX21zcnMucG5nKXt3aWR0aD03MCV9CgpgYGB7ciwgZmlnLnNob3c9J2hvbGQnLCBvdXQud2lkdGg9JzUwJSd9CiMgZGlmZmVyZW50IHNjYWxlcyBmb3IgZWFjaCBtZWFzdXJlLCBzbyB3ZSBzZXBhcmF0ZSB0aGUgcGxvdHMKc2V0LnNlZWQoNDIpCgojIEludGVncmF0ZWQgQnJpZXIgU2NvcmUgYW5kIEJyaWVyIFNjb3JlIGF0IHQgPSAxMCB5ZWFycwpyZXNbLCAuKHN1cnYuZ3JhZiwgc3Vydi5ncmFmLjEwKV0gJT4lIAogIHRpZHlyOjpwaXZvdF9sb25nZXIoY29scyA9IHRpZHlzZWxlY3Q6OmV2ZXJ5dGhpbmcoKSwgCiAgICBuYW1lc190byA9ICdNZWFzdXJlJywgdmFsdWVzX3RvID0gJ1ZhbHVlJykgJT4lCiAgbXV0YXRlKE1lYXN1cmUgPSBjYXNlX3doZW4oCiAgICBNZWFzdXJlID09ICdzdXJ2LmdyYWYnIH4gJ0lCUycsCiAgICBNZWFzdXJlID09ICdzdXJ2LmdyYWYuMTAnIH4gJ0JTKHQ9MTApJwogICkpICU+JQogIGdncGxvdChhZXMoeCA9IE1lYXN1cmUsIHkgPSBWYWx1ZSwgZmlsbCA9IE1lYXN1cmUpKSArCiAgICBnZW9tX2JveHBsb3Qoc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICAgIGdlb21faml0dGVyKGNvbG9yID0gJ2JsdWUnLCBzaXplID0gMC41LCBhbHBoYSA9IDAuNSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogICAgbGFicyh0aXRsZSA9ICdJbnRlZ3JhdGVkIEJyaWVyIFNjb3JlIHZzIEJyaWVyIFNjb3JlICh0ID0gMTAgeWVhcnMpJykgKwogICAgdGhlbWVfYncoYmFzZV9zaXplID0gMTQpICsgCiAgICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpCgojIFJDTEwKcmVzWywgLihzdXJ2LnJjbGwpXSAlPiUgCiAgdGlkeXI6OnBpdm90X2xvbmdlcihjb2xzID0gdGlkeXNlbGVjdDo6ZXZlcnl0aGluZygpLCAKICAgIG5hbWVzX3RvID0gJ01lYXN1cmUnLCB2YWx1ZXNfdG8gPSAnVmFsdWUnKSAlPiUKICBtdXRhdGUoTWVhc3VyZSA9IGNhc2Vfd2hlbigKICAgIE1lYXN1cmUgPT0gJ3N1cnYucmNsbCcgfiAnUkNMTCcKICApKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBNZWFzdXJlLCB5ID0gVmFsdWUpKSArCiAgICBnZW9tX2JveHBsb3Qoc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICAgIGdlb21faml0dGVyKGNvbG9yID0gJ2JsdWUnLCBzaXplID0gMC41LCBhbHBoYSA9IDAuNSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogICAgbGFicyh0aXRsZSA9ICdSaWdodC1jZW5zb3JlZCBMb2cgTG9zcycpICsKICAgIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE0KSArCiAgICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpCmBgYApgYGB7ciwgZWNobz1GQUxTRX0KcGRmKCJtbHIzX2NhbGlicmF0aW9uX0JTLnBkZiIsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNSkKc2V0LnNlZWQoNDIpCiMgSW50ZWdyYXRlZCBCcmllciBTY29yZSBhbmQgQnJpZXIgU2NvcmUgYXQgdCA9IDEwIHllYXJzCnJlc1ssIC4oc3Vydi5ncmFmLCBzdXJ2LmdyYWYuMTApXSAlPiUgCiAgdGlkeXI6OnBpdm90X2xvbmdlcihjb2xzID0gdGlkeXNlbGVjdDo6ZXZlcnl0aGluZygpLCAKICAgIG5hbWVzX3RvID0gJ01lYXN1cmUnLCB2YWx1ZXNfdG8gPSAnVmFsdWUnKSAlPiUKICBtdXRhdGUoTWVhc3VyZSA9IGNhc2Vfd2hlbigKICAgIE1lYXN1cmUgPT0gJ3N1cnYuZ3JhZicgfiAnSUJTJywKICAgIE1lYXN1cmUgPT0gJ3N1cnYuZ3JhZi4xMCcgfiAnQlModD0xMCknCiAgKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gTWVhc3VyZSwgeSA9IFZhbHVlLCBmaWxsID0gTWVhc3VyZSkpICsKICAgIGdlb21fYm94cGxvdChzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogICAgZ2VvbV9qaXR0ZXIoY29sb3IgPSAnYmx1ZScsIHNpemUgPSAwLjUsIGFscGhhID0gMC41LCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgICBsYWJzKHRpdGxlID0gJ0ludGVncmF0ZWQgQnJpZXIgU2NvcmUgdnMgQnJpZXIgU2NvcmUgKHQgPSAxMCB5ZWFycyknKSArCiAgICB0aGVtZV9idyhiYXNlX3NpemUgPSAxNCkgKyAKICAgIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkKZGV2Lm9mZigpCnBkZigibWxyM19jYWxpYnJhdGlvbl9SQ0xMLnBkZiIsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNSkKcmVzWywgLihzdXJ2LnJjbGwpXSAlPiUgCiAgdGlkeXI6OnBpdm90X2xvbmdlcihjb2xzID0gdGlkeXNlbGVjdDo6ZXZlcnl0aGluZygpLCAKICAgIG5hbWVzX3RvID0gJ01lYXN1cmUnLCB2YWx1ZXNfdG8gPSAnVmFsdWUnKSAlPiUKICBtdXRhdGUoTWVhc3VyZSA9IGNhc2Vfd2hlbigKICAgIE1lYXN1cmUgPT0gJ3N1cnYucmNsbCcgfiAnUkNMTCcKICApKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBNZWFzdXJlLCB5ID0gVmFsdWUpKSArCiAgICBnZW9tX2JveHBsb3Qoc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICAgIGdlb21faml0dGVyKGNvbG9yID0gJ2JsdWUnLCBzaXplID0gMC41LCBhbHBoYSA9IDAuNSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogICAgbGFicyh0aXRsZSA9ICdSaWdodC1jZW5zb3JlZCBMb2cgTG9zcycpICsKICAgIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE0KSArCiAgICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpCmRldi5vZmYoKQpgYGAKPHAgYWxpZ249ImxlZnQiPgogIDxpbWcgYWx0PSIxIiBzcmM9Ii4vZmlnL21scjNfY2FsaWJyYXRpb25fQlMucG5nIiB3aWR0aD0iNDklIj4KICA8aW1nIGFsdD0iMiIgc3JjPSIuL2ZpZy9tbHIzX2NhbGlicmF0aW9uX1JDTEwucG5nIiB3aWR0aD0iNDklIj4KICA8aT5DYWxpYnJhdGlvbiBwZXJmb3JtYW5jZSBvZiBMYXNzbyBDb3ggb24gdGhlIFRDR0EtQlJDQSBkYXRhc2V0IChleHByZXNzaW9uIGRhdGEgb2YgdGhlIFBBTTUwIGdlbmVzIGFuZCB0aGUgdmFyaWFibGVzIGFnZSBhbmQgZXRobmljaXR5KS4gUGVyZm9ybWFuY2UgbWV0cmljcyB1c2VkIGFyZSB0aGUgSW50ZWdyYXRlZCBCcmllciBTY29yZSAoSUJTKSwgdGhlIEJyaWVyIFNjb3JlIGF0IDEwIHllYXJzIGFuZCB0aGUgUmlnaHQtQ2Vuc29yZWQgTG9nYXJpdGhtaWMgTG9zcyAoUkNMTCkuIFRoZSBkYXRhc2V0IHdhcyBzcGxpdCB0byB0cmFpbmluZy92YWxpZGF0aW9uIHNldHMgMTAwIHRpbWVzIHRvIGFsbG93IGZvciB0aGUgcXVhbnRpZmljYXRpb24gb2YgdW5jZXJ0YWludHkgaW4gdGhlIGRpZmZlcmVudCBwZXJmb3JtYW5jZSBlc3RpbWF0ZXMuPC9pPgo8L3A+CgojIyMgRmVhdHVyZSBzdGFiaWxpdHkgYW5hbHlzaXMgey19CgpXZSBjYW4gZXh0cmFjdCB0aGUgc2VsZWN0ZWQgZmVhdHVyZXMgZnJvbSBhbGwgJDEwMCQgdHJhaW5lZCBMYXNzbyBDb3ggbW9kZWxzIGFuZCBjcmVhdGUgYSBmcmVxdWVuY3kgc2VsZWN0aW9uIHRhYmxlOgpgYGB7cn0KIyBnZXQgc2VsZWN0ZWQgZmVhdHVyZXMgZnJvbSBhbGwgdHJhaW5lZCBsZWFybmVycyBpbiBhIGxpc3QKc2ZfbGlzdCA9IGxhcHBseShyciRsZWFybmVycywgZnVuY3Rpb24obGVhcm5lcikgewogIGxlYXJuZXIkZ3JhcGhfbW9kZWwkcGlwZW9wcyRzdXJ2LmN2X2dsbW5ldCRsZWFybmVyX21vZGVsJHNlbGVjdGVkX2ZlYXR1cmVzKCkKfSkKCiMgbWFrZSBmcmVxdWVuY3kgc2VsZWN0aW9uIHRhYmxlCm4gPSBsZW5ndGgoc2ZfbGlzdCkKZnNfcmVzID0gc29ydCh0YWJsZSh1bmxpc3Qoc2ZfbGlzdCkpLCBkZWNyZWFzaW5nID0gVFJVRSkKdGltZXMgPSBhcy52ZWN0b3IodW5uYW1lKGZzX3JlcykpCnRpYmJsZTo6dGliYmxlKGZlYXRfbmFtZSA9IG5hbWVzKGZzX3JlcyksIHRpbWVzID0gdGltZXMsIGZyZXEgPSB0aW1lcy9uKQpgYGAKYGBgCiMgQSB0aWJibGU6IDMzIMOXIDMKICAgZmVhdF9uYW1lIHRpbWVzICBmcmVxCiAgIDxjaHI+ICAgICA8aW50PiA8ZGJsPgogMSBhZ2UgICAgICAgICAxMDAgIDEgICAKIDIgZXRobmljaXR5ICAgMTAwICAxICAgCiAzIEFOTE4gICAgICAgICA0MyAgMC40MwogNCBCTFZSQSAgICAgICAgNDEgIDAuNDEKIDUgQkFHMSAgICAgICAgIDM3ICAwLjM3CiA2IE1JQSAgICAgICAgICAzNCAgMC4zNAogNyBUWU1TICAgICAgICAgMzAgIDAuMyAKIDggS1JUNSAgICAgICAgIDI3ICAwLjI3CiA5IE1NUDExICAgICAgICAyNyAgMC4yNwoxMCBCQ0wyICAgICAgICAgMjYgIDAuMjYKIyDihLkgMjMgbW9yZSByb3dzCiMg4oS5IFVzZSBgcHJpbnQobiA9IC4uLilgIHRvIHNlZSBtb3JlIHJvd3MKYGBgCgpBcyBgYWdlYCBhbmQgYGV0aG5pY2l0eWAgd2VyZSBub3QgcGVuYWxpemVkLCB0aGV5IGhhdmUgbm9uLXplcm8gY29lZmZpY2llbnRzIGluIGFsbCBMYXNzbyBDb3ggbW9kZWxzIGFuZCB0aGVyZWZvcmUgYXJlIGluY2x1ZGVkIGluIGFsbCBzZWxlY3RlZCBmZWF0dXJlIHNldHMuCgpMYXN0bHksIHdlIGNhbiB1c2UgdGhlIGBSYCBwYWNrYWdlIFsqKnN0YWJtKipdKGh0dHBzOi8vQ1JBTi5SLXByb2plY3Qub3JnL3BhY2thZ2U9c3RhYm0pIFtAc3RhYm1dIHRvIGFzc2VzcyBob3cgc2ltaWxhciB0aGUgJDEwMCQgc2VsZWN0ZWQgZmVhdHVyZSBzZXRzIHdlcmUuCldlIHdpbGwgZGVtb25zdHJhdGUgdGhlIHVzZSBvZiB0aHJlZSBtZXRyaWNzIHdoaWNoIG1lYXN1cmUgdGhlICpzdGFiaWxpdHkqIG9mIHRoZSBMYXNzbyBDb3gncyBmZWF0dXJlIHNlbGVjdGlvbiBvbiB0aGUgVENHQS1CUkNBIGRhdGFzZXQ6CgoxLiBUaGUgSmFjY2FyZCBpbmRleAoyLiBOb2d1ZWlyYSdzIG1ldHJpYyAoY29ycmVjdGVkIGZvciBjaGFuY2UsIGkuZS4gaW5kZXBlbmRlbnQgb2YgdGhlIG51bWJlciBvZiBmZWF0dXJlczsgQE5vZ3VlaXJhMjAxOCkKMy4gWnVja25pY2sncyBtZXRyaWMgKGV4dGVuc2lvbiBvZiBKYWNjYXJkIGluZGV4IHRoYXQgY29uc2lkZXJzIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBmZWF0dXJlczsgQFp1Y2tuaWNrMjAwOCk6CgpgYGB7ciwgd2FybmluZz1GQUxTRX0Kc2V0LnNlZWQoNDIpCmphYyA9IHN0YWJtOjpzdGFiaWxpdHlKYWNjYXJkKGZlYXR1cmVzID0gc2ZfbGlzdCwgY29ycmVjdGlvbi5mb3IuY2hhbmNlID0gJ25vbmUnKQpub2cgPSBzdGFibTo6c3RhYmlsaXR5Tm9ndWVpcmEoZmVhdHVyZXMgPSBzZl9saXN0LCBwID0gbGVuZ3RoKHRhc2skZmVhdHVyZV9uYW1lcykpCgojIFNpbWlsYXJpdHkgb2YgZWFjaCBwYWlyIG9mIGZlYXR1cmVzIHVzaW5nIFBlYXJzb24gY29ycmVsYXRpb24Kc2ltLm1hdCA9IGFicyhzdGF0czo6Y29yKHggPSB0YXNrJGRhdGEoY29scyA9IHRhc2skZmVhdHVyZV9uYW1lcyksIG1ldGhvZCA9ICdwJykpCnp1Y2sgPSBzdGFibTo6c3RhYmlsaXR5WnVja25pY2soZmVhdHVyZXMgPSBzZl9saXN0LCBzaW0ubWF0ID0gc2ltLm1hdCwgCiAgdGhyZXNob2xkID0gMC45LCBjb3JyZWN0aW9uLmZvci5jaGFuY2UgPSAnZXN0aW1hdGUnLCBOID0gMTAwKQoKdGliYmxlOjp0aWJibGUoamFjY2FyZCA9IGphYywgbm9ndWVpcmEgPSBub2csIHp1Y2tuaWNrID0genVjaykKYGBgCmBgYAojIEEgdGliYmxlOiAxIMOXIDMKICBqYWNjYXJkIG5vZ3VlaXJhIHp1Y2tuaWNrCiAgICA8ZGJsPiAgICA8ZGJsPiAgICA8ZGJsPgoxICAgMC40NzQgICAgMC40MTIgICAgMC40NDIKYGBgCgpGcm9tIHRoZSBhYm92ZSB2YWx1ZXMgd2UgY29uY2x1ZGUgdGhhdCB0aGUgc3RhYmlsaXR5IG9mIExhc3NvIENveCdzIGZlYXR1cmUgc2VsZWN0aW9uIGlzIG5laXRoZXIgcG9vciBub3IgZXhjZWxsZW50IGJ1dCBzb21ld2hlcmUgaW4gYmV0d2Vlbi4KCiMgUiBzZXNzaW9uIGluZm8gey19CgpgYGB7ciwgaW5jbHVkZT1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KIyBwdXR0aW5nIGFsbCBsaWJyYXJpZXMgaGVyZSBmb3IgdGhlIHNlc3Npb24gaW5mbwpsaWJyYXJ5KCJUQ0dBYmlvbGlua3MiKQpsaWJyYXJ5KCJTdW1tYXJpemVkRXhwZXJpbWVudCIpCmxpYnJhcnkoIkRFU2VxMiIpCmxpYnJhcnkoImRwbHlyIikKbGlicmFyeSgiZ2dwbG90MiIpCmxpYnJhcnkoInN1cnZpdmFsIikKbGlicmFyeSgic3Vydm1pbmVyIikKbGlicmFyeSgiTTNDIikKbGlicmFyeSgiZ2xtbmV0IikKbGlicmFyeSgicGxvdG1vIikKbGlicmFyeSgiZ3JwcmVnIikKbGlicmFyeSgiU0dMIikKbGlicmFyeSgicHNiY0dyb3VwIikKbGlicmFyeSgiR0dhbGx5IikKbGlicmFyeSgiQmhHTE0iKQpsaWJyYXJ5KCJyaXNrc2V0Uk9DIikKbGlicmFyeSgicmlza1JlZ3Jlc3Npb24iKQpsaWJyYXJ5KCJwZXBlcnIiKQpsaWJyYXJ5KCJjMDYwIikKbGlicmFyeSgicm1zIikKbGlicmFyeSgic3VydkFVQyIpCmxpYnJhcnkoInJlZ3Bsb3QiKQpsaWJyYXJ5KCJtbHIzdmVyc2UiKQpsaWJyYXJ5KCJtbHIzcHJvYmEiKQpsaWJyYXJ5KCJtbHIzZXh0cmFsZWFybmVycyIpCmxpYnJhcnkoInN0YWJtIikKYGBgCgpgYGB7cn0Kc2Vzc2lvbkluZm8oKQpgYGAKYGBgClIgdmVyc2lvbiA0LjMuMSAoMjAyMy0wNi0xNikKUGxhdGZvcm06IHg4Nl82NC1hcHBsZS1kYXJ3aW4yMCAoNjQtYml0KQpSdW5uaW5nIHVuZGVyOiBtYWNPUyBNb250ZXJleSAxMi43CgpNYXRyaXggcHJvZHVjdHM6IGRlZmF1bHQKQkxBUzogICAvU3lzdGVtL0xpYnJhcnkvRnJhbWV3b3Jrcy9BY2NlbGVyYXRlLmZyYW1ld29yay9WZXJzaW9ucy9BL0ZyYW1ld29ya3MvdmVjTGliLmZyYW1ld29yay9WZXJzaW9ucy9BL2xpYkJMQVMuZHlsaWIgCkxBUEFDSzogL0xpYnJhcnkvRnJhbWV3b3Jrcy9SLmZyYW1ld29yay9WZXJzaW9ucy80LjMteDg2XzY0L1Jlc291cmNlcy9saWIvbGliUmxhcGFjay5keWxpYjsgIExBUEFDSyB2ZXJzaW9uIDMuMTEuMAoKbG9jYWxlOgpbMV0gZW5fVVMuVVRGLTgvZW5fVVMuVVRGLTgvZW5fVVMuVVRGLTgvQy9lbl9VUy5VVEYtOC9lbl9VUy5VVEYtOAoKdGltZSB6b25lOiBFdXJvcGUvT3Nsbwp0emNvZGUgc291cmNlOiBpbnRlcm5hbAoKYXR0YWNoZWQgYmFzZSBwYWNrYWdlczoKWzFdIHN0YXRzNCAgICBzdGF0cyAgICAgZ3JhcGhpY3MgIGdyRGV2aWNlcyB1dGlscyAgICAgZGF0YXNldHMgIG1ldGhvZHMgICBiYXNlICAgICAKCm90aGVyIGF0dGFjaGVkIHBhY2thZ2VzOgogWzFdIHN0YWJtXzEuMi4yICAgICAgICAgICAgICAgICBtbHIzZXh0cmFsZWFybmVyc18wLjcuMCAgICAgbWxyM3Byb2JhXzAuNS4yICAgICAgICAgICAgCiBbNF0gbWxyM3ZlcnNlXzAuMi44ICAgICAgICAgICAgIG1scjNfMC4xNi4xICAgICAgICAgICAgICAgICByZWdwbG90XzEuMSAgICAgICAgICAgICAgICAKIFs3XSBzdXJ2QVVDXzEuMi0wICAgICAgICAgICAgICAgcm1zXzYuNy0wICAgICAgICAgICAgICAgICAgIEhtaXNjXzUuMS0wICAgICAgICAgICAgICAgIApbMTBdIGMwNjBfMC4zLTAgICAgICAgICAgICAgICAgICBwZXBlcnJfMS41ICAgICAgICAgICAgICAgICAgc25vd2ZhbGxfMS44NC02LjIgICAgICAgICAgClsxM10gc25vd18wLjQtNCAgICAgICAgICAgICAgICAgIHJpc2tSZWdyZXNzaW9uXzIwMjMuMDMuMjIgICByaXNrc2V0Uk9DXzEuMC40LjEgICAgICAgICAKWzE2XSBNQVNTXzcuMy02MCAgICAgICAgICAgICAgICAgQmhHTE1fMS4xLjAgICAgICAgICAgICAgICAgIEdHYWxseV8yLjEuMiAgICAgICAgICAgICAgIApbMTldIHBzYmNHcm91cF8xLjUgICAgICAgICAgICAgICBtdnRub3JtXzEuMi0yICAgICAgICAgICAgICAgU3VwcERpc3RzXzEuMS05LjcgICAgICAgICAgClsyMl0gTGVhcm5CYXllc18yLjE1LjEgICAgICAgICAgIFNHTF8xLjMgICAgICAgICAgICAgICAgICAgICBncnByZWdfMy40LjAgICAgICAgICAgICAgICAKWzI1XSBwbG90bW9fMy42LjIgICAgICAgICAgICAgICAgVGVhY2hpbmdEZW1vc18yLjEyICAgICAgICAgIHBsb3RyaXhfMy44LTIgICAgICAgICAgICAgIApbMjhdIEZvcm11bGFfMS4yLTUgICAgICAgICAgICAgICBnbG1uZXRfNC4xLTcgICAgICAgICAgICAgICAgTWF0cml4XzEuNS00LjEgICAgICAgICAgICAgClszMV0gTTNDXzEuMjIuMCAgICAgICAgICAgICAgICAgIHN1cnZtaW5lcl8wLjQuOSAgICAgICAgICAgICBnZ3B1YnJfMC42LjAgICAgICAgICAgICAgICAKWzM0XSBzdXJ2aXZhbF8zLjUtNSAgICAgICAgICAgICAgZ2dwbG90Ml8zLjQuMiAgICAgICAgICAgICAgIGRwbHlyXzEuMS4yICAgICAgICAgICAgICAgIApbMzddIERFU2VxMl8xLjQwLjIgICAgICAgICAgICAgICBTdW1tYXJpemVkRXhwZXJpbWVudF8xLjMwLjIgQmlvYmFzZV8yLjYwLjAgICAgICAgICAgICAgCls0MF0gR2Vub21pY1Jhbmdlc18xLjUyLjAgICAgICAgIEdlbm9tZUluZm9EYl8xLjM2LjEgICAgICAgICBJUmFuZ2VzXzIuMzQuMSAgICAgICAgICAgICAKWzQzXSBTNFZlY3RvcnNfMC4zOC4xICAgICAgICAgICAgQmlvY0dlbmVyaWNzXzAuNDYuMCAgICAgICAgIE1hdHJpeEdlbmVyaWNzXzEuMTIuMiAgICAgIApbNDZdIG1hdHJpeFN0YXRzXzEuMC4wICAgICAgICAgICBUQ0dBYmlvbGlua3NfMi4yOC4zICAgICAgICAKCmxvYWRlZCB2aWEgYSBuYW1lc3BhY2UgKGFuZCBub3QgYXR0YWNoZWQpOgogIFsxXSB0Z3BfMi40LTIxICAgICAgICAgICAgICAgICAgcHJvZ3Jlc3NfMS4yLjIgICAgICAgICAgICAgIG1scjNoeXBlcmJhbmRfMC40LjUgICAgICAgIAogIFs0XSBwZW5hbGl6ZWRfMC45LTUyICAgICAgICAgICAgbm5ldF83LjMtMTkgICAgICAgICAgICAgICAgIEJpb3N0cmluZ3NfMi42OC4xICAgICAgICAgIAogIFs3XSBUSC5kYXRhXzEuMS0yICAgICAgICAgICAgICAgdmN0cnNfMC42LjMgICAgICAgICAgICAgICAgIGRpZ2VzdF8wLjYuMzIgICAgICAgICAgICAgIAogWzEwXSBwbmdfMC4xLTggICAgICAgICAgICAgICAgICAgY29ycGNvcl8xLjYuMTAgICAgICAgICAgICAgIHNoYXBlXzEuNC42ICAgICAgICAgICAgICAgIAogWzEzXSBwcm94eV8wLjQtMjcgICAgICAgICAgICAgICAgcGFyYWxsZWxseV8xLjM2LjAgICAgICAgICAgIHJlc2hhcGVfMC44LjkgICAgICAgICAgICAgIAogWzE2XSBmb3JlYWNoXzEuNS4yICAgICAgICAgICAgICAgd2l0aHJfMi41LjAgICAgICAgICAgICAgICAgIHBhcmFtNl8wLjIuNCAgICAgICAgICAgICAgIAogWzE5XSB4ZnVuXzAuMzkgICAgICAgICAgICAgICAgICAgbWVtb2lzZV8yLjAuMSAgICAgICAgICAgICAgIGRpcHRlc3RfMC43Ni0wICAgICAgICAgICAgIAogWzIyXSBNYXRyaXhNb2RlbHNfMC41LTEgICAgICAgICAgem9vXzEuOC0xMiAgICAgICAgICAgICAgICAgIERFb3B0aW1SXzEuMS0xICAgICAgICAgICAgIAogWzI1XSBkaXN0cjZfMS44LjAgICAgICAgICAgICAgICAgcHJldHR5dW5pdHNfMS4xLjEgICAgICAgICAgIHByYWJjbHVzXzIuMy0yICAgICAgICAgICAgIAogWzI4XSBLRUdHUkVTVF8xLjQwLjAgICAgICAgICAgICAgaHR0cl8xLjQuNiAgICAgICAgICAgICAgICAgIGRvd25sb2FkZXJfMC40ICAgICAgICAgICAgIAogWzMxXSBtYXB0cmVlXzEuNC04ICAgICAgICAgICAgICAgcnN0YXRpeF8wLjcuMiAgICAgICAgICAgICAgIGdsb2JhbHNfMC4xNi4yICAgICAgICAgICAgIAogWzM0XSBmcGNfMi4yLTEwICAgICAgICAgICAgICAgICAgcnN0dWRpb2FwaV8wLjE0ICAgICAgICAgICAgIGdlbmVyaWNzXzAuMS4zICAgICAgICAgICAgIAogWzM3XSBiYXNlNjRlbmNfMC4xLTMgICAgICAgICAgICAgY3VybF81LjAuMSAgICAgICAgICAgICAgICAgIHpsaWJiaW9jXzEuNDYuMCAgICAgICAgICAgIAogWzQwXSBkb1NOT1dfMS4wLjIwICAgICAgICAgICAgICAgR2Vub21lSW5mb0RiRGF0YV8xLjIuMTAgICAgIGxncl8wLjQuNCAgICAgICAgICAgICAgICAgIAogWzQzXSB4dGFibGVfMS44LTQgICAgICAgICAgICAgICAgc3RyaW5ncl8xLjUuMCAgICAgICAgICAgICAgIGRvUGFyYWxsZWxfMS4wLjE3ICAgICAgICAgIAogWzQ2XSBldmFsdWF0ZV8wLjIxICAgICAgICAgICAgICAgUzRBcnJheXNfMS4wLjQgICAgICAgICAgICAgIEJpb2NGaWxlQ2FjaGVfMi44LjAgICAgICAgIAogWzQ5XSBobXNfMS4xLjMgICAgICAgICAgICAgICAgICAgY29sb3JzcGFjZV8yLjEtMCAgICAgICAgICAgIGZpbGVsb2NrXzEuMC4yICAgICAgICAgICAgIAogWzUyXSBjbXByc2tfMi4yLTExICAgICAgICAgICAgICAgcmV0aWN1bGF0ZV8xLjMwICAgICAgICAgICAgIGZsZXhtaXhfMi4zLTE5ICAgICAgICAgICAgIAogWzU1XSBtYWdyaXR0cl8yLjAuMyAgICAgICAgICAgICAgcmVhZHJfMi4xLjQgICAgICAgICAgICAgICAgIG1vZGVsdG9vbHNfMC4yLTIzICAgICAgICAgIAogWzU4XSBsYXR0aWNlXzAuMjEtOCAgICAgICAgICAgICAgcGFsbWVycGVuZ3VpbnNfMC4xLjEgICAgICAgIGZ1dHVyZS5hcHBseV8xLjExLjAgICAgICAgIAogWzYxXSByb2J1c3RiYXNlXzAuOTktMCAgICAgICAgICAgU3BhcnNlTV8xLjgxICAgICAgICAgICAgICAgIFhNTF8zLjk5LTAuMTQgICAgICAgICAgICAgIAogWzY0XSBjbGFzc183LjMtMjIgICAgICAgICAgICAgICAgcGlsbGFyXzEuOS4wICAgICAgICAgICAgICAgIG5sbWVfMy4xLTE2MiAgICAgICAgICAgICAgIAogWzY3XSBpdGVyYXRvcnNfMS4wLjE0ICAgICAgICAgICAgY29tcGlsZXJfNC4zLjEgICAgICAgICAgICAgIFJTcGVjdHJhXzAuMTYtMSAgICAgICAgICAgIAogWzcwXSBzdHJpbmdpXzEuNy4xMiAgICAgICAgICAgICAgcGFyYWRveF8wLjExLjEgICAgICAgICAgICAgIG1pbnFhXzEuMi41ICAgICAgICAgICAgICAgIAogWzczXSBkaWN0aW9uYXI2XzAuMS4zICAgICAgICAgICAgcGx5cl8xLjguOCAgICAgICAgICAgICAgICAgIGNyYXlvbl8xLjUuMiAgICAgICAgICAgICAgIAogWzc2XSBhYmluZF8xLjQtNSAgICAgICAgICAgICAgICAgc21fMi4yLTUuNy4xICAgICAgICAgICAgICAgIGxvY2ZpdF8xLjUtOS44ICAgICAgICAgICAgIAogWzc5XSBiaXRfNC4wLjUgICAgICAgICAgICAgICAgICAgc2FuZHdpY2hfMy4wLTIgICAgICAgICAgICAgIG1scjNtYm9fMC4yLjEgICAgICAgICAgICAgIAogWzgyXSBjb2RldG9vbHNfMC4yLTE5ICAgICAgICAgICAgbXVsdGNvbXBfMS40LTI1ICAgICAgICAgICAgIG1hdHJpeGNhbGNfMS4wLTYgICAgICAgICAgIAogWzg1XSBvcGVuc3NsXzIuMC42ICAgICAgICAgICAgICAgZTEwNzFfMS43LTEzICAgICAgICAgICAgICAgIHNwbGluZXNfNC4zLjEgICAgICAgICAgICAgIAogWzg4XSBSY3BwXzEuMC4xMCAgICAgICAgICAgICAgICAgcXVhbnRyZWdfNS45NSAgICAgICAgICAgICAgIGRicGx5cl8yLjMuMiAgICAgICAgICAgICAgIAogWzkxXSBUQ0dBYmlvbGlua3NHVUkuZGF0YV8xLjIwLjAga25pdHJfMS40MyAgICAgICAgICAgICAgICAgIGJsb2JfMS4yLjQgICAgICAgICAgICAgICAgIAogWzk0XSB1dGY4XzEuMi4zICAgICAgICAgICAgICAgICAgY2x1ZV8wLjMtNjQgICAgICAgICAgICAgICAgIGxtZTRfMS4xLTM0ICAgICAgICAgICAgICAgIAogWzk3XSBsaXN0ZW52XzAuOS4wICAgICAgICAgICAgICAgY2hlY2ttYXRlXzIuMi4wICAgICAgICAgICAgIGdnc2lnbmlmXzAuNi40ICAgICAgICAgICAgIApbMTAwXSB0aWJibGVfMy4yLjEgICAgICAgICAgICAgICAgbWxyM3R1bmluZ3NwYWNlc18wLjQuMCAgICAgIHN0YXRtb2RfMS41LjAgICAgICAgICAgICAgIApbMTAzXSB0emRiXzAuNC4wICAgICAgICAgICAgICAgICAgcGtnY29uZmlnXzIuMC4zICAgICAgICAgICAgIHRvb2xzXzQuMy4xICAgICAgICAgICAgICAgIApbMTA2XSBjYWNoZW1fMS4wLjggICAgICAgICAgICAgICAgUlNRTGl0ZV8yLjMuMSAgICAgICAgICAgICAgIHJ2ZXN0XzEuMC4zICAgICAgICAgICAgICAgIApbMTA5XSBEQklfMS4xLjMgICAgICAgICAgICAgICAgICAgbnVtRGVyaXZfMjAxNi44LTEuMSAgICAgICAgIG1scjNmaWx0ZXJzXzAuNy4xICAgICAgICAgIApbMTEyXSBmYXN0bWFwXzEuMS4xICAgICAgICAgICAgICAgcm1hcmtkb3duXzIuMjIgICAgICAgICAgICAgIHNjYWxlc18xLjIuMSAgICAgICAgICAgICAgIApbMTE1XSBtbGVncF8zLjEuOSAgICAgICAgICAgICAgICAgZ3JpZF80LjMuMSAgICAgICAgICAgICAgICAgIG1ldHNfMS4zLjIgICAgICAgICAgICAgICAgIApbMTE4XSBicm9vbV8xLjAuNSAgICAgICAgICAgICAgICAgY2FyRGF0YV8zLjAtNSAgICAgICAgICAgICAgIHJwYXJ0XzQuMS4xOSAgICAgICAgICAgICAgIApbMTIxXSB5YW1sXzIuMy43ICAgICAgICAgICAgICAgICAgZm9yZWlnbl8wLjgtODQgICAgICAgICAgICAgIGNsaV8zLjYuMSAgICAgICAgICAgICAgICAgIApbMTI0XSBwdXJycl8xLjAuMSAgICAgICAgICAgICAgICAgbGlmZWN5Y2xlXzEuMC4zICAgICAgICAgICAgIGFza3Bhc3NfMS4xICAgICAgICAgICAgICAgIApbMTI3XSBiYm90a18wLjcuMiAgICAgICAgICAgICAgICAgbGF2YV8xLjcuMi4xICAgICAgICAgICAgICAgIGtlcm5sYWJfMC45LTMyICAgICAgICAgICAgIApbMTMwXSBiYWNrcG9ydHNfMS40LjEgICAgICAgICAgICAgbWxyM3R1bmluZ18wLjE5LjAgICAgICAgICAgIEJpb2NQYXJhbGxlbF8xLjM0LjIgICAgICAgIApbMTMzXSBndGFibGVfMC4zLjMgICAgICAgICAgICAgICAgdW1hcF8wLjIuMTAuMCAgICAgICAgICAgICAgIHBhcmFsbGVsXzQuMy4xICAgICAgICAgICAgIApbMTM2XSBtbHIzY2x1c3Rlcl8wLjEuOCAgICAgICAgICAganNvbmxpdGVfMS44LjcgICAgICAgICAgICAgIGJpdG9wc18xLjAtNyAgICAgICAgICAgICAgIApbMTM5XSBiaXQ2NF80LjAuNSAgICAgICAgICAgICAgICAgUnRzbmVfMC4xNiAgICAgICAgICAgICAgICAgIG1scjNsZWFybmVyc18wLjUuNiAgICAgICAgIApbMTQyXSBwb2xzcGxpbmVfMS4xLjIzICAgICAgICAgICAgc3Vydk1pc2NfMC41LjYgICAgICAgICAgICAgIHNwYWNlZmlsbHJfMC4zLjIgICAgICAgICAgIApbMTQ1XSBodG1sdG9vbHNfMC41LjUgICAgICAgICAgICAgS01zdXJ2XzAuMS01ICAgICAgICAgICAgICAgIHNldDZfMC4yLjYgICAgICAgICAgICAgICAgIApbMTQ4XSByYXBwZGlyc18wLjMuMyAgICAgICAgICAgICAgbWxyM3BpcGVsaW5lc18wLjUuMC0xICAgICAgIGdsdWVfMS42LjIgICAgICAgICAgICAgICAgIApbMTUxXSBwZW5hbGl6ZWRTVk1fMS4xLjQgICAgICAgICAgbWxyM3Zpel8wLjYuMSAgICAgICAgICAgICAgIHRpbWVyZWdfMi4wLjUgICAgICAgICAgICAgIApbMTU0XSBYVmVjdG9yXzAuNDAuMCAgICAgICAgICAgICAgUkN1cmxfMS45OC0xLjEyICAgICAgICAgICAgIG1jbHVzdF82LjAuMCAgICAgICAgICAgICAgIApbMTU3XSBncmlkRXh0cmFfMi4zICAgICAgICAgICAgICAgYm9vdF8xLjMtMjguMSAgICAgICAgICAgICAgIFI2XzIuNS4xICAgICAgICAgICAgICAgICAgIApbMTYwXSB0aWR5cl8xLjMuMCAgICAgICAgICAgICAgICAga20uY2lfMC41LTYgICAgICAgICAgICAgICAgIG9vcGxhaF8wLjIuMCAgICAgICAgICAgICAgIApbMTYzXSBjbHVzdGVyXzIuMS40ICAgICAgICAgICAgICAgYmVhbnBsb3RfMS4zLjEgICAgICAgICAgICAgIG5sb3B0cl8yLjAuMyAgICAgICAgICAgICAgIApbMTY2XSBtbHIzbWlzY18wLjEzLjAgICAgICAgICAgICAgdmlvcGxvdF8wLjQuMCAgICAgICAgICAgICAgIERlbGF5ZWRBcnJheV8wLjI2LjMgICAgICAgIApbMTY5XSB0aWR5c2VsZWN0XzEuMi4wICAgICAgICAgICAgaHRtbFRhYmxlXzIuNC4xICAgICAgICAgICAgIHhtbDJfMS4zLjQgICAgICAgICAgICAgICAgIApbMTcyXSBtbHIzZnNlbGVjdF8wLjExLjAgICAgICAgICAgY2FyXzMuMS0yICAgICAgICAgICAgICAgICAgIEFubm90YXRpb25EYmlfMS42Mi4xICAgICAgIApbMTc1XSBmdXR1cmVfMS4zMy4wICAgICAgICAgICAgICAgbXVuc2VsbF8wLjUuMCAgICAgICAgICAgICAgIGRhdGEudGFibGVfMS4xNC44ICAgICAgICAgIApbMTc4XSBodG1sd2lkZ2V0c18xLjYuMiAgICAgICAgICAgbWxyM2RhdGFfMC43LjAgICAgICAgICAgICAgIFJDb2xvckJyZXdlcl8xLjEtMyAgICAgICAgIApbMTgxXSBiaW9tYVJ0XzIuNTYuMSAgICAgICAgICAgICAgcmxhbmdfMS4xLjEgICAgICAgICAgICAgICAgIHV1aWRfMS4xLTEgICAgICAgICAgICAgICAgIApbMTg0XSBmYW5zaV8xLjAuNCAgICAgICAgICAgICAgICAgcHJvZGxpbV8yMDIzLjAzLjMxICAgICAgICAgICAgIApgYGAKCiMgUmVmZXJlbmNlcwoK