Extract Apical progenitors and compute Pseudo-DorsoVentral score

Extract apical progenitors and filter the gene expression matrix

We perform K-means clustering on the 2 cell state scores :

  • Apical progenitors AP
  • Basal progenitors BP

We then extract Apical progenitor as the cluster with the highest mean Apical progenitor signature

Import Spring dimensionality reduction

Cell cycle associated genes were excluded for PCA dimensionality reduction and Spring plot was generating using these parameters:

Number of cells: 1648
Number of genes that passed filter: 857
Min expressing cells (gene filtering): 3
Min number of UMIs (gene filtering): 3
Gene variability %ile (gene filtering): 90
Number of principal components: 7
Number of nearest neighbors: 20
Number of force layout iterations: 500

Fit a principal curve over the AP in the Spring space

## Starting curve---distance^2: 2022449778
## Iteration 1---distance^2: 745172
## Iteration 2---distance^2: 696270.5
## Iteration 3---distance^2: 677509.1
## Iteration 4---distance^2: 668251.7
## Iteration 5---distance^2: 663393.6
## Iteration 6---distance^2: 660928.6
## Iteration 7---distance^2: 659586.4
## Iteration 8---distance^2: 658917.8
## Iteration 9---distance^2: 658638.8

Manuscript Fig. 5A

Manuscript Fig. 5A

Find differentially expressed genes along the pseudo DV axis

Cluster genes by similar profiles over pseudo-DV axis

Assign domain identity

We assign domains identity based on clusters’ transcriptional profile by setting boundaries over pseudo-DV score

Manuscript Fig. 5D

Manuscript Fig. 5D

Transfert identities on the full dataset (Manuscript Fig. 2A)

## [1] "Cluster_Sub.Pallium.2: 363 Cells"
## [1] "Cluster_Ventral.Pallium: 312 Cells"
## [1] "Cluster_Sub.Pallium.3: 197 Cells"
## [1] "Cluster_lateral.Pallium.1: 219 Cells"
## [1] "Cluster_Dorsal.Pallium: 201 Cells"
## [1] "Cluster_lateral.Pallium.2: 113 Cells"
## [1] "Cluster_Sub.Pallium.1: 241 Cells"
Manuscript Fig. 2A

Manuscript Fig. 2A

Perform iterative graph-based clustering to find if discrete pallial sub-domains exist

Perform iterative clustering implemented in scrattch.hicat package

For more detail on the scrattch.hicat please refer to the package page.

Prepare the dataset for clustering with scrattch.hicat

Iterative clustering

Run the iterative clustering

The default iter_clust function use in this version of the scrattch.hicat package does not allow to set the k.param argument. We modified this function to allow this argument to be set to other values.

## [1] "test-iter_clust"
##   Finding nearest neighbors...DONE ~ 0.022 s
##   Compute jaccard coefficient between nearest-neighbor sets...DONE ~ 0.047 s
##   Build undirected graph from the weighted links...DONE ~ 0.052 s
##   Run louvain clustering on the graph ...DONE ~ 0.031 s
##   Return a community class
##   -Modularity value: 0.6822028 
##   -Number of clusters: 12[1] "test-iter_clust.1"
##   Finding nearest neighbors...DONE ~ 0.016 s
##   Compute jaccard coefficient between nearest-neighbor sets...DONE ~ 0.043 s
##   Build undirected graph from the weighted links...DONE ~ 0.046 s
##   Run louvain clustering on the graph ...DONE ~ 0.021 s
##   Return a community class
##   -Modularity value: 0.6939065 
##   -Number of clusters: 12[1] "test-iter_clust.2"
##   Finding nearest neighbors...DONE ~ 0.001 s
##   Compute jaccard coefficient between nearest-neighbor sets...DONE ~ 0.008 s
##   Build undirected graph from the weighted links...DONE ~ 0.008 s
##   Run louvain clustering on the graph ...DONE ~ 0.003 s
##   Return a community class
##   -Modularity value: 0.7585217 
##   -Number of clusters: 7

Session Info

## [1] "30 novembre, 2020, 10,52"
## R version 3.6.3 (2020-02-29)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 18.04.5 LTS
## 
## Matrix products: default
## BLAS:   /usr/lib/x86_64-linux-gnu/atlas/libblas.so.3.10.3
## LAPACK: /usr/lib/x86_64-linux-gnu/atlas/liblapack.so.3.10.3
## 
## locale:
##  [1] LC_CTYPE=fr_FR.UTF-8       LC_NUMERIC=C              
##  [3] LC_TIME=fr_FR.UTF-8        LC_COLLATE=fr_FR.UTF-8    
##  [5] LC_MONETARY=fr_FR.UTF-8    LC_MESSAGES=fr_FR.UTF-8   
##  [7] LC_PAPER=fr_FR.UTF-8       LC_NAME=C                 
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
## [11] LC_MEASUREMENT=fr_FR.UTF-8 LC_IDENTIFICATION=C       
## 
## attached base packages:
##  [1] splines   stats4    parallel  stats     graphics  grDevices utils    
##  [8] datasets  methods   base     
## 
## other attached packages:
##  [1] limma_3.42.0          Rphenograph_0.99.1    igraph_1.2.5         
##  [4] matrixStats_0.55.0    viridis_0.5.1         viridisLite_0.3.0    
##  [7] wesanderson_0.3.6     RColorBrewer_1.1-2    gridExtra_2.3        
## [10] reshape_0.8.8         ggExtra_0.9           scrattch.vis_0.0.210 
## [13] purrr_0.3.3           ggbeeswarm_0.6.0      dplyr_0.8.3          
## [16] scrattch.hicat_0.0.16 cluster_2.1.0         princurve_2.1.4      
## [19] monocle_2.14.0        DDRTree_0.1.5         irlba_2.3.3          
## [22] VGAM_1.1-2            Biobase_2.46.0        BiocGenerics_0.32.0  
## [25] Seurat_2.3.4          Matrix_1.2-17         cowplot_1.0.0        
## [28] ggplot2_3.2.1        
## 
## loaded via a namespace (and not attached):
##   [1] snow_0.4-3           backports_1.1.5      Hmisc_4.3-0         
##   [4] plyr_1.8.4           lazyeval_0.2.2       densityClust_0.3    
##   [7] fastICA_1.2-2        digest_0.6.25        foreach_1.4.7       
##  [10] htmltools_0.5.0      lars_1.2             gdata_2.18.0        
##  [13] magrittr_1.5         checkmate_1.9.4      gclus_1.3.2         
##  [16] mixtools_1.1.0       ROCR_1.0-7           R.utils_2.9.0       
##  [19] docopt_0.6.1         colorspace_1.4-1     ggrepel_0.8.1       
##  [22] xfun_0.18            sparsesvd_0.2        crayon_1.3.4        
##  [25] jsonlite_1.7.0       zeallot_0.1.0        survival_2.44-1.1   
##  [28] zoo_1.8-6            iterators_1.0.12     ape_5.3             
##  [31] glue_1.4.1           registry_0.5-1       gtable_0.3.0        
##  [34] kernlab_0.9-29       prabclus_2.3-1       DEoptimR_1.0-8      
##  [37] scales_1.1.0         pheatmap_1.0.12      bibtex_0.4.2        
##  [40] miniUI_0.1.1.1       Rcpp_1.0.5           metap_1.1           
##  [43] dtw_1.21-3           xtable_1.8-4         htmlTable_1.13.2    
##  [46] reticulate_1.13      foreign_0.8-72       bit_4.0.4           
##  [49] proxy_0.4-23         mclust_5.4.5         SDMTools_1.1-221.1  
##  [52] Formula_1.2-3        tsne_0.1-3           htmlwidgets_1.5.1   
##  [55] httr_1.4.1           FNN_1.1.3            gplots_3.0.1.1      
##  [58] fpc_2.2-3            acepack_1.4.1        modeltools_0.2-22   
##  [61] ica_1.0-2            farver_2.0.1         pkgconfig_2.0.3     
##  [64] R.methodsS3_1.7.1    flexmix_2.3-15       nnet_7.3-14         
##  [67] labeling_0.3         later_1.0.0          tidyselect_0.2.5    
##  [70] rlang_0.4.7          reshape2_1.4.3       munsell_0.5.0       
##  [73] tools_3.6.3          ggridges_0.5.1       fastmap_1.0.1       
##  [76] evaluate_0.14        stringr_1.4.0        yaml_2.2.1          
##  [79] npsurv_0.4-0         knitr_1.26           bit64_4.0.2         
##  [82] fitdistrplus_1.0-14  robustbase_0.93-5    caTools_1.17.1.2    
##  [85] RANN_2.6.1           dendextend_1.12.0    pbapply_1.4-2       
##  [88] nlme_3.1-141         mime_0.7             slam_0.1-46         
##  [91] R.oo_1.23.0          hdf5r_1.3.2.9000     compiler_3.6.3      
##  [94] rstudioapi_0.11      beeswarm_0.2.3       png_0.1-7           
##  [97] lsei_1.2-0           tibble_2.1.3         stringi_1.4.6       
## [100] highr_0.8            lattice_0.20-41      HSMMSingleCell_1.6.0
## [103] vctrs_0.2.0          pillar_1.4.2         lifecycle_0.1.0     
## [106] combinat_0.0-8       Rdpack_0.11-0        lmtest_0.9-37       
## [109] data.table_1.12.6    bitops_1.0-6         seriation_1.2-9     
## [112] gbRd_0.4-11          httpuv_1.5.2         R6_2.4.1            
## [115] latticeExtra_0.6-28  TSP_1.1-10           promises_1.1.0      
## [118] KernSmooth_2.23-15   vipor_0.4.5          codetools_0.2-16    
## [121] MASS_7.3-53          gtools_3.8.1         assertthat_0.2.1    
## [124] withr_2.1.2          qlcMatrix_0.9.7      mgcv_1.8-33         
## [127] diptest_0.75-7       doSNOW_1.0.18        grid_3.6.3          
## [130] rpart_4.1-15         tidyr_1.0.0          class_7.3-17        
## [133] rmarkdown_2.5        segmented_1.0-0      Rtsne_0.15          
## [136] shiny_1.4.0          base64enc_0.1-3

  1. Institute of Psychiatry and Neuroscience of Paris, INSERM U1266, 75014, Paris, France,

LS0tCnRpdGxlOiAiSW52ZXN0aWdhdGlvbiBvZiB0aGUgYXBpY2FsIHByb2dlbml0b3JzIGRpdmVyc2l0eSIKYXV0aG9yOgogICAtIE1hdHRoaWV1IE1vcmVhdV5bSW5zdGl0dXRlIG9mIFBzeWNoaWF0cnkgYW5kIE5ldXJvc2NpZW5jZSBvZiBQYXJpcywgSU5TRVJNIFUxMjY2LCA3NTAxNCwgUGFyaXMsIEZyYW5jZSwgbWF0dGhpZXUubW9yZWF1QGluc2VybS5mcl0gWyFbXShodHRwczovL29yY2lkLm9yZy9zaXRlcy9kZWZhdWx0L2ZpbGVzL2ltYWdlcy9vcmNpZF8xNngxNi5wbmcpXShodHRwczovL29yY2lkLm9yZy8wMDAwLTAwMDItMjU5Mi0yMzczKQpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlQiwgJVknKWAiCm91dHB1dDogCiAgaHRtbF9kb2N1bWVudDogCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKICAgIGRmX3ByaW50OiB0aWJibGUKICAgIGhpZ2hsaWdodDogaGFkZG9jawogICAgaW5jbHVkZXM6CiAgICAgIGluX2hlYWRlcjogaGVhZGVyLmh0bWwKICAgIHRoZW1lOiBjb3NtbwogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHllcwotLS0KCmBgYHtjc3MsIGVjaG89RkFMU0V9CmgxIHsKICBmb250LXNpemU6IDM0cHg7CiAgbWFyZ2luLXRvcDogMnJlbTsKICBtYXJnaW4tYm90dG9tOiAxcmVtOwogIGNvbG9yOiAjZTY0ZDAwOwogIHRleHQtZGVjb3JhdGlvbjogbm9uZTsKfQpoMS50aXRsZSB7CiAgZm9udC1zaXplOiA0MHB4OwogIG1hcmdpbi10b3A6IDJyZW07CiAgbWFyZ2luLWJvdHRvbTogMXJlbTsKICB0ZXh0LWFsaWduOiBjZW50ZXI7CiAgdGV4dC1kZWNvcmF0aW9uOiBub25lOwogIGNvbG9yOiAjMDAwMDAwOwp9CmgyIHsKICBmb250LXNpemU6IDMwcHg7CiAgbWFyZ2luLXRvcDogMnJlbTsKICBtYXJnaW4tYm90dG9tOiAxcmVtOwogIGNvbG9yOiAjMDAwMDAwOwp9CmgzIHsKICBmb250LXNpemU6IDI0cHg7CiAgbWFyZ2luLXRvcDogMnJlbTsKICBtYXJnaW4tYm90dG9tOiAxcmVtOwogIGNvbG9yOiAjMDAwMDAwOwp9Cmg0IHsKICBmb250LXNpemU6IDIwcHg7CiAgbWFyZ2luLXRvcDogMnJlbTsKICBtYXJnaW4tYm90dG9tOiAxcmVtOwogIGNvbG9yOiAjMDAwMDAwOwp9Cmg1IHsKICBmb250LXNpemU6IDE4cHg7CiAgbWFyZ2luLXRvcDogMnJlbTsKICBtYXJnaW4tYm90dG9tOiAxcmVtOwogIGNvbG9yOiAjMDAwMDAwOwp9Cgouc2Nyb2xsLTEwMCB7CiAgbWF4LWhlaWdodDogMjAwcHg7CiAgb3ZlcmZsb3cteTogYXV0bzsKICBiYWNrZ3JvdW5kLWNvbG9yOiBpbmhlcml0Owp9CgpwIHsKICBmb250LXNpemU6IDE2cHg7Cn0KYGBgCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBmaWcuYWxpZ24gPSAnY2VudGVyJywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSkKYGBgCgojIExvYWQgbGlicmFyaWVzIGFuZCBRQ0ZpbHRlcmVkIGRhdGFzZXQKCmBgYHtyIH0KIyBMb2FkIGxpYnJhcmllcwpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShtb25vY2xlKQpsaWJyYXJ5KHByaW5jdXJ2ZSkKbGlicmFyeShjbHVzdGVyKQpsaWJyYXJ5KHBhcmFsbGVsKQpsaWJyYXJ5KHNjcmF0dGNoLmhpY2F0KQpsaWJyYXJ5KHNjcmF0dGNoLnZpcykKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdnRXh0cmEpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkocmVzaGFwZSkKbGlicmFyeShncmlkRXh0cmEpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KHdlc2FuZGVyc29uKQpsaWJyYXJ5KHZpcmlkaXMpCgojU2V0IGdncGxvdCB0aGVtZSBhcyBjbGFzc2ljCnRoZW1lX3NldCh0aGVtZV9jbGFzc2ljKCkpCmBgYAoKYGBge3J9CiMgTG9hZCB0aGUgZnVsbCBhbm5vdGF0ZWQgZGF0YXNldApBbGxjZWxscy5kYXRhIDwtIHJlYWRSRFMoIi4vUUMuZmlsdGVyZWQuY2VsbHMuUkRTIikKYGBgCgojIEV4dHJhY3QgQXBpY2FsIHByb2dlbml0b3JzIGFuZCBjb21wdXRlIFBzZXVkby1Eb3Jzb1ZlbnRyYWwgc2NvcmUKCiMjIEV4dHJhY3QgYXBpY2FsIHByb2dlbml0b3JzIGFuZCBmaWx0ZXIgdGhlIGdlbmUgZXhwcmVzc2lvbiBtYXRyaXgKCldlIHBlcmZvcm0gSy1tZWFucyBjbHVzdGVyaW5nIG9uIHRoZSAyIGNlbGwgc3RhdGUgc2NvcmVzIDoKCi0gQXBpY2FsIHByb2dlbml0b3JzIGBBUGAKLSBCYXNhbCBwcm9nZW5pdG9ycyBgQlBgCgpgYGB7ciB9CnNldC5zZWVkKDEwMCkKIyBLLW1lYW5zIGNsdXN0ZXJpbmcgYmFzZWQgb24gQVAsIEJQIHNjb3JlcyBhY3Jvc3MgY2VsbHMKY2wgPC0ga21lYW5zKGNiaW5kKEFsbGNlbGxzLmRhdGFAbWV0YS5kYXRhJEFQX3NpZ25hdHVyZTEsIEFsbGNlbGxzLmRhdGFAbWV0YS5kYXRhJEJQX3NpZ25hdHVyZTEpLCAzKQpBbGxjZWxscy5kYXRhQG1ldGEuZGF0YSRrbWVhbkNsdXN0IDwtIHBhc3RlMCgiQ2x1c3QuIixjbCRjbHVzdGVyKQpgYGAKCgpgYGB7ciBmaWcuZGltPWMoNS4zLCA0KX0KY29sLnBhbCA8LSB3ZXNfcGFsZXR0ZSgiR3JhbmRCdWRhcGVzdDEiLCAzLCB0eXBlID0gImRpc2NyZXRlIikKCnAxIDwtIGdncGxvdChBbGxjZWxscy5kYXRhQG1ldGEuZGF0YSwgYWVzKHg9QVBfc2lnbmF0dXJlMSwgeT1CUF9zaWduYXR1cmUxLCBjb2xvdXIgPSBrbWVhbkNsdXN0KSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9Y29sLnBhbCkgKwogIGdlb21fcG9pbnQoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpCmdnTWFyZ2luYWwocDEsIHR5cGUgPSAiaGlzdG9ncmFtIiwgZmlsbD0ibGlnaHRncmV5IikgOyBybShwMSkKCkRpbVBsb3QoQWxsY2VsbHMuZGF0YSwKICAgICAgICBncm91cC5ieSA9ICJrbWVhbkNsdXN0IiwKICAgICAgICByZWR1Y3Rpb24udXNlID0gInNwcmluZyIsCiAgICAgICAgY29scy51c2UgPSBjb2wucGFsLAogICAgICAgIGRpbS4xID0gMSwKICAgICAgICBkaW0uMiA9IDIsCiAgICAgICAgZG8ubGFiZWw9VCwKICAgICAgICBsYWJlbC5zaXplID0gNCwKICAgICAgICBuby5sZWdlbmQgPSBGKQpgYGAKCldlIHRoZW4gZXh0cmFjdCBBcGljYWwgcHJvZ2VuaXRvciBhcyB0aGUgY2x1c3RlciB3aXRoIHRoZSBoaWdoZXN0IG1lYW4gYEFwaWNhbCBwcm9nZW5pdG9yYCBzaWduYXR1cmUKCmBgYHtyIGZpZy5kaW09Yyg1LjMsIDQpfQojIEZpbmQgY2x1c3RlcnMgd2lodCB0aGUgaGlnaGVzdCBtZWFuIEFQc2NvcmUKTWVhbktjbHVzdC5BUHNjb3JlIDwtIGFnZ3JlZ2F0ZShBUF9zaWduYXR1cmUxIH4ga21lYW5DbHVzdCwgQWxsY2VsbHMuZGF0YUBtZXRhLmRhdGEsIG1lYW4pCkFQY2x1c3QgPC0gTWVhbktjbHVzdC5BUHNjb3JlICU+JSBmaWx0ZXIoQVBfc2lnbmF0dXJlMSA9PSBtYXgoQVBfc2lnbmF0dXJlMSkpICU+JSBwdWxsKGttZWFuQ2x1c3QpCgojIEV4dHJhY3QgYXBpY2FsIHByb2dlbml0b3JzIApiYXJjb2RlcyA8LSBBbGxjZWxscy5kYXRhQG1ldGEuZGF0YSAlPiUgZmlsdGVyKGttZWFuQ2x1c3QgPT0gQVBjbHVzdCkgJT4lIHB1bGwoQmFyY29kZXMpCkFQLmRhdGEgPC0gIFN1YnNldERhdGEoQWxsY2VsbHMuZGF0YSwgY2VsbHMudXNlID0gYmFyY29kZXMgLCBzdWJzZXQucmF3ID0gVCwgIGRvLmNsZWFuID0gRikKCiMgRnVydGhlciBmaWx0ZXIgdGhlIDMgb3V0bGllciBjZWxscyBiYXNlZCBvbiBzcHJpbmcgY29vcmRpbmF0ZXMKY2VsbHMgPC0gcm93bmFtZXMoQVAuZGF0YUBkciRzcHJpbmdAY2VsbC5lbWJlZGRpbmdzW0FQLmRhdGFAZHIkc3ByaW5nQGNlbGwuZW1iZWRkaW5nc1ssMl0gPiAyNTAsXSkKQVAuZGF0YSA8LSAgU3Vic2V0RGF0YShBUC5kYXRhLCBjZWxscy51c2UgPSBjZWxscyAsIHN1YnNldC5yYXcgPSBULCAgZG8uY2xlYW4gPSBGKQoKRGltUGxvdChBUC5kYXRhLAogICAgICAgIGdyb3VwLmJ5ID0gImttZWFuQ2x1c3QiLAogICAgICAgIHJlZHVjdGlvbi51c2UgPSAic3ByaW5nIiwKICAgICAgICBjb2xzLnVzZSA9IGNvbC5wYWwsCiAgICAgICAgZGltLjEgPSAxLAogICAgICAgIGRpbS4yID0gMiwKICAgICAgICBkby5sYWJlbD1ULAogICAgICAgIGxhYmVsLnNpemUgPSA0LAogICAgICAgIG5vLmxlZ2VuZCA9IEYpCmBgYAoKIyMgRmlsdGVyIGdlbmUgY291bnRzIG1hdHJpeAoKYGBge3J9CiMgUmVtb3ZlIG5vbiBlcHJlc3NlZCBnZW5lcwpudW0uY2VsbHMgPC0gTWF0cml4Ojpyb3dTdW1zKEFQLmRhdGFAZGF0YSA+IDApCmdlbmVzLnVzZSA8LSBuYW1lcyh4ID0gbnVtLmNlbGxzW3doaWNoKHggPSBudW0uY2VsbHMgPj0gMjApXSkKQVAuZGF0YUByYXcuZGF0YSA8LSBBUC5kYXRhQHJhdy5kYXRhW2dlbmVzLnVzZSwgXQpBUC5kYXRhQGRhdGEgPC0gQVAuZGF0YUBkYXRhW2dlbmVzLnVzZSwgXQoKIyBOb3JtYWxpemUgYW5kIFNjYWxlIHRoZSBkYXRhCkFQLmRhdGEgPC0gTm9ybWFsaXplRGF0YShvYmplY3QgPSBBUC5kYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXphdGlvbi5tZXRob2QgPSAiTG9nTm9ybWFsaXplIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZS5mYWN0b3IgPSByb3VuZChtZWRpYW4oQVAuZGF0YUBtZXRhLmRhdGEkblVNSSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgZGlzcGxheS5wcm9ncmVzcyA9IEYpCgpBUC5kYXRhIDwtIEZpbmRWYXJpYWJsZUdlbmVzKG9iamVjdCA9IEFQLmRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFuLmZ1bmN0aW9uID0gRXhwTWVhbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpc3BlcnNpb24uZnVuY3Rpb24gPSBMb2dWTVIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4Lmxvdy5jdXRvZmYgPSAwLjAxMjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4LmhpZ2guY3V0b2ZmID0gMywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkuY3V0b2ZmID0gMSwgZG8ucGxvdCA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNwbGF5LnByb2dyZXNzID0gRikKCkFQLmRhdGEgPC0gU2NhbGVEYXRhKG9iamVjdCA9IEFQLmRhdGEsIHZhcnMudG8ucmVncmVzcyA9IGMoIkNDLkRpZmZlcmVuY2UiLCJwZXJjZW50Lm1pdG8iLCAiblVNSSIpLCBkaXNwbGF5LnByb2dyZXNzID0gRikKYGBgCgojIyBJbXBvcnQgU3ByaW5nIGRpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbgoKKipDZWxsIGN5Y2xlIGFzc29jaWF0ZWQgZ2VuZXMqKiB3ZXJlIGV4Y2x1ZGVkIGZvciBQQ0EgZGltZW5zaW9uYWxpdHkgcmVkdWN0aW9uIGFuZCBTcHJpbmcgcGxvdCB3YXMgZ2VuZXJhdGluZyB1c2luZyB0aGVzZSBwYXJhbWV0ZXJzOgoKYGBgCk51bWJlciBvZiBjZWxsczogMTY0OApOdW1iZXIgb2YgZ2VuZXMgdGhhdCBwYXNzZWQgZmlsdGVyOiA4NTcKTWluIGV4cHJlc3NpbmcgY2VsbHMgKGdlbmUgZmlsdGVyaW5nKTogMwpNaW4gbnVtYmVyIG9mIFVNSXMgKGdlbmUgZmlsdGVyaW5nKTogMwpHZW5lIHZhcmlhYmlsaXR5ICVpbGUgKGdlbmUgZmlsdGVyaW5nKTogOTAKTnVtYmVyIG9mIHByaW5jaXBhbCBjb21wb25lbnRzOiA3Ck51bWJlciBvZiBuZWFyZXN0IG5laWdoYm9yczogMjAKTnVtYmVyIG9mIGZvcmNlIGxheW91dCBpdGVyYXRpb25zOiA1MDAKYGBgCgpgYGB7cn0KIyBJbXBvcnQgU3ByaW5nIGNvb3JkaW5hdGVzIGNhbGN1bGF0ZWQgd2l0aG91dCBjZWxsIGN5Y2xlIGdlbmVzCkNvb3JkaW5hdGVzIDwtIHJlYWQudGFibGUoIi4vUHJvZ2VuaXRvcnMvRTEyLkFQLkNvb3JkaW5hdGVzLnR4dCIsIHNlcD0iLCIsIGhlYWRlciA9IEYpWyxjKDIsMyldCnJvd25hbWVzKENvb3JkaW5hdGVzKSA8LSByb3duYW1lcyhBUC5kYXRhQG1ldGEuZGF0YSkKQVAuZGF0YSA8LSBTZXREaW1SZWR1Y3Rpb24oQVAuZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVkdWN0aW9uLnR5cGUgPSAic3ByaW5nLkFQIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgc2xvdCA9ICJjZWxsLmVtYmVkZGluZ3MiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBuZXcuZGF0YSA9IGFzLm1hdHJpeChDb29yZGluYXRlcykpCkFQLmRhdGFAZHIkc3ByaW5nLkFQQGtleSA8LSAic3ByaW5nLkFQIgpjb2xuYW1lcyhBUC5kYXRhQGRyJHNwcmluZy5BUEBjZWxsLmVtYmVkZGluZ3MpIDwtIHBhc3RlMChHZXREaW1SZWR1Y3Rpb24ob2JqZWN0ID0gQVAuZGF0YSwgcmVkdWN0aW9uLnR5cGUgPSAic3ByaW5nLkFQIixzbG90ID0gImtleSIpLCBjKDEsMikpCgpgYGAKCiMjIEZpdCBhIHByaW5jaXBhbCBjdXJ2ZSBvdmVyIHRoZSBBUCBpbiB0aGUgU3ByaW5nIHNwYWNlCgpgYGB7cn0KZGF0YSA8LSBkYXRhLmZyYW1lKHNwcmluZ0FQLjEgPSBBUC5kYXRhQGRyJHNwcmluZy5BUEBjZWxsLmVtYmVkZGluZ3NbLDFdLAogICAgICAgICAgICAgICAgICAgc3ByaW5nQVAuMiA9IEFQLmRhdGFAZHIkc3ByaW5nLkFQQGNlbGwuZW1iZWRkaW5nc1ssMl0sCiAgICAgICAgICAgICAgICAgICBzcHJpbmcxID0gQVAuZGF0YUBkciRzcHJpbmdAY2VsbC5lbWJlZGRpbmdzWywxXSwKICAgICAgICAgICAgICAgICAgIHNwcmluZzIgPSBBUC5kYXRhQGRyJHNwcmluZ0BjZWxsLmVtYmVkZGluZ3NbLDJdKQoKIyBGaXQgdGhlIHByaW5jaXBhbCBjdXJ2ZQpmaXQgPC0gcHJpbmNpcGFsX2N1cnZlKGFzLm1hdHJpeChkYXRhWywxOjJdKSwKICAgICAgICAgICAgICAgICAgICAgICBzbW9vdGhlcj0nbG93ZXNzJywKICAgICAgICAgICAgICAgICAgICAgICB0cmFjZT1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgIGYgPSAwLjcsCiAgICAgICAgICAgICAgICAgICAgICAgc3RyZXRjaD0wLAogICAgICAgICAgICAgICAgICAgICAgIHBsb3RfaXRlcmF0aW9ucyA9IEYpCmBgYAoKYGBge3J9CkRvcnNvVmVudHJhbC5TY29yZSA8LSBmaXQkbGFtYmRhL21heChmaXQkbGFtYmRhKQpwYy5saW5lIDwtIGFzLmRhdGEuZnJhbWUoZml0JHNbb3JkZXIoZml0JGxhbWJkYSksXSkKCmRhdGEkUGhhc2UgPC0gYXMuY2hhcmFjdGVyKEFQLmRhdGFAbWV0YS5kYXRhJFBoYXNlKQpkYXRhJERvcnNvVmVudHJhbC5TY29yZSA8LSBEb3Jzb1ZlbnRyYWwuU2NvcmUKCiMgRGlyZWN0aW9uIG9mIHRoZSBtYXR1cmF0aW9uIHNjb3JlCmlmIChjb3IoZGF0YSREb3Jzb1ZlbnRyYWwuU2NvcmUsIEFQLmRhdGFAZGF0YVsnWmJ0YjIwJywgXSkgPiAwKSB7IGRhdGEkRG9yc29WZW50cmFsLlNjb3JlIDwtIC0oZGF0YSREb3Jzb1ZlbnRyYWwuU2NvcmUgLSBtYXgoZGF0YSREb3Jzb1ZlbnRyYWwuU2NvcmUpKX0KCkFQLmRhdGFAbWV0YS5kYXRhJERvcnNvVmVudHJhbC5TY29yZSA8LSBkYXRhJERvcnNvVmVudHJhbC5TY29yZQpgYGAKCmBgYHtyIGZpZy5kaW09Yyg1LjMsIDQpfQojIFBsb3QgQ2VsbCBvbnRvIFBDMSBhbmQgUEMyIHdpdGggcHJpbmNpcGFsIGN1cnZlCmdncGxvdChkYXRhLCBhZXMoc3ByaW5nQVAuMSwgc3ByaW5nQVAuMikpICsgCiAgZ2VvbV9wb2ludChhZXMoY29sb3I9UGhhc2UpLCBzaXplPTIsIHNoYXBlPTE2LCB2YWx1ZXM9Y29sLnBhbCkgKwogIGdlb21fbGluZShkYXRhPXBjLmxpbmUsIGNvbG9yPSdyZWQnLCBzaXplPTAuNzcpCmBgYAoKYGBge3IgZmlnLmRpbT1jKDUuMywgNCksIGZpZy5jYXA9ICJNYW51c2NyaXB0IEZpZy4gNUEifQojIFBsb3QgcHNldWRvdGltZSBjb2xvciBncmFkaWVudCBvbiB0aGUgY2VsbCBjeWNsZSBmaWx0ZXJlZCBTcHJpbmcgZW1iYmVkaW5nCmdncGxvdChkYXRhLCBhZXMoc3ByaW5nQVAuMSwgc3ByaW5nQVAuMikpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvcj1Eb3Jzb1ZlbnRyYWwuU2NvcmUpLCBzaXplPTIsIHNoYXBlPTE2KSArCiAgc2NhbGVfY29sb3JfdmlyaWRpcyhkaXJlY3Rpb24gPSAtMSkgKwogIGdlb21fbGluZShkYXRhPXBjLmxpbmUsIGNvbG9yPSdyZWQnLCBzaXplPTAuNzcpCmBgYAoKYGBge3IgZmlnLmRpbT1jKDUuMywgNCl9CiMgUGxvdCBwc2V1ZG90aW1lIGNvbG9yIGdyYWRpZW50IG9uIHRoZSBTcHJpbmcgZW1iYmVkaW5nIGNhbGN1bGF0ZWQgZnJvbSBmdWxsIGRhdGFzZXQKZ2dwbG90KGRhdGEsIGFlcyhzcHJpbmcxLCBzcHJpbmcyKSkgKyAKICBnZW9tX3BvaW50KGFlcyhjb2xvcj1Eb3Jzb1ZlbnRyYWwuU2NvcmUpLCBzaXplPTIsIHNoYXBlPTE2KSArCiAgc2NhbGVfY29sb3JfdmlyaWRpcyhkaXJlY3Rpb24gPSAtMSkgCmBgYAoKIyBGaW5kIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyBhbG9uZyB0aGUgcHNldWRvIERWIGF4aXMKCiMjIEluaXRpYWxpemUgYSBtb25vY2xlIG9iamVjdAoKYGBge3J9CiMgVHJhbnNmZXJ0IG1ldGFkYXRhIAptZXRhLmRhdGEgPC0gZGF0YS5mcmFtZShiYXJjb2RlID0gcm93bmFtZXMoQVAuZGF0YUBtZXRhLmRhdGEpLAogICAgICAgICAgICAgICAgICAgICAgICBDbHVzdGVyID0gQVAuZGF0YUBtZXRhLmRhdGEkb2xkLmlkZW50LAogICAgICAgICAgICAgICAgICAgICAgICBEb3Jzb1ZlbnRyYWwuU2NvcmUgPSAgQVAuZGF0YUBtZXRhLmRhdGEkRG9yc29WZW50cmFsLlNjb3JlLAogICAgICAgICAgICAgICAgICAgICAgICBDZWxsY3ljbGVQaGFzZSA9IEFQLmRhdGFAbWV0YS5kYXRhJFBoYXNlLAogICAgICAgICAgICAgICAgICAgICAgICByb3cubmFtZXMgPSByb3duYW1lcyhBUC5kYXRhQG1ldGEuZGF0YSkpCiAgICAgICAgICAgICAgICAgICAKQW5ub3QuZGF0YSAgPC0gbmV3KCdBbm5vdGF0ZWREYXRhRnJhbWUnLCBkYXRhID0gbWV0YS5kYXRhKQoKIyBUcmFuc2ZlcnQgY291bnQgZGF0YQpjb3VudC5kYXRhID0gZGF0YS5mcmFtZShnZW5lX3Nob3J0X25hbWUgPSByb3duYW1lcyhBUC5kYXRhQHJhdy5kYXRhKSwKICAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID0gcm93bmFtZXMoQVAuZGF0YUByYXcuZGF0YSkpCgpmZWF0dXJlLmRhdGEgPC0gbmV3KCdBbm5vdGF0ZWREYXRhRnJhbWUnLCBkYXRhID0gY291bnQuZGF0YSkKCiMgQ3JlYXRlIHRoZSBDZWxsRGF0YVNldCBvYmplY3QKZ2JtX2NkcyA8LSBuZXdDZWxsRGF0YVNldChhcy5tYXRyaXgoQVAuZGF0YUByYXcuZGF0YSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgcGhlbm9EYXRhID0gQW5ub3QuZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICBmZWF0dXJlRGF0YSA9IGZlYXR1cmUuZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlckRldGVjdGlvbkxpbWl0ID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICBleHByZXNzaW9uRmFtaWx5ID0gbmVnYmlub21pYWwoKSkKYGBgCgoKYGBge3J9CmdibV9jZHMgPC0gZXN0aW1hdGVTaXplRmFjdG9ycyhnYm1fY2RzKQpnYm1fY2RzIDwtIGVzdGltYXRlRGlzcGVyc2lvbnMoZ2JtX2NkcykKZ2JtX2NkcyA8LSBkZXRlY3RHZW5lcyhnYm1fY2RzLCBtaW5fZXhwciA9IDAuMSkKYGBgCgpgYGB7cn0Kcm0obGlzdCA9IGxzKClbIWxzKCkgJWluJSBjKCJBUC5kYXRhIiwgImdibV9jZHMiKV0pCmBgYAoKIyMgVGVzdCBlYWNoIGdlbmUgdHJlbmQgb3ZlciBwc2V1ZG8tRFYgc2NvcmUKCmBgYHtyfQojIEV4Y2x1ZGUgY2VsbCBjeWNsZSBhc3NvY2lhdGVkIGdlbmVzCkNDZ2VuZXMgPC0gYXMuY2hhcmFjdGVyKHJlYWQudGFibGUoIi4vUHJvZ2VuaXRvcnMvQ2VsbEN5Y2xlR2VuZXMuY3N2Iiwgc2VwID0gIlx0IiwgaGVhZGVyID0gRilbLDFdKQpJbnB1dC5nZW5lcyA8LSBBUC5kYXRhQHZhci5nZW5lc1shQVAuZGF0YUB2YXIuZ2VuZXMgJWluJSBDQ2dlbmVzXQpgYGAKCgpgYGB7cn0KIyBQZXJmb3JtIHRoZSB0ZXN0IGZvciBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhcyBhIGZ1bmN0aW9uIG9mIHBzZXVkby1EViBzY29yZQpEVi5BeGlzLmdlbmVzIDwtIGRpZmZlcmVudGlhbEdlbmVUZXN0KGdibV9jZHNbSW5wdXQuZ2VuZXMsXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVsbE1vZGVsRm9ybXVsYVN0ciA9ICJ+c20ubnMoRG9yc29WZW50cmFsLlNjb3JlLCBkZiA9IDMpKkNlbGxjeWNsZVBoYXNlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVkdWNlZE1vZGVsRm9ybXVsYVN0ciA9ICJ+Q2VsbGN5Y2xlUGhhc2UiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3JlcyA9IGRldGVjdENvcmVzKCkgLTIpCgojIEZpbHRlciBnZW5lcyB3aXRoIGEgRkRSIDwgMC4wMDEKRFYuQXhpcy5nZW5lcy5GRFIuZmlsdGVyZWQgPC0gRFYuQXhpcy5nZW5lcyAlPiUgZmlsdGVyKHF2YWwgPCAxZS0zKQpgYGAKCgojIyBTbW9vdGggc2lnbmlmaWNhdGl2ZSBnZW5lIGV4cHJlc3Npb24gcHNldWRvLURWIGF4aXMKCmBgYHtyfQojIENyZWF0ZSBhIG5ldyBwc2V1ZG8tRFYgdmVjdG9yIG9mIDUwMCBwb2ludHMKblBvaW50cyA8LSA1MDAKbmV3X2RhdGEgPC0gZGF0YS5mcmFtZShEb3Jzb1ZlbnRyYWwuU2NvcmUgPSBzZXEobWluKHBEYXRhKGdibV9jZHMpJERvcnNvVmVudHJhbC5TY29yZSksIG1heChwRGF0YShnYm1fY2RzKSREb3Jzb1ZlbnRyYWwuU2NvcmUpLCBsZW5ndGgub3V0ID0gblBvaW50cykpCgojIFNtb290aCBnZW5lIGV4cHJlc3Npb24KU21vb3RoLmN1cnZlLm1hdHJpeCA8LSBnZW5TbW9vdGhDdXJ2ZXMoZ2JtX2Nkc1thcy5jaGFyYWN0ZXIoRFYuQXhpcy5nZW5lcy5GRFIuZmlsdGVyZWQkZ2VuZV9zaG9ydF9uYW1lKSxdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmVuZF9mb3JtdWxhID0gIn5zbS5ucyhEb3Jzb1ZlbnRyYWwuU2NvcmUsIGRmID0gMykiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWxhdGl2ZV9leHByID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3X2RhdGEgPSBuZXdfZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29yZXM9IGRldGVjdENvcmVzKCkgLSAyKQpgYGAKCiMgQ2x1c3RlciBjZWxscyBieSBzaW1pbGFyIGV4cHJlc3Npb24gcHJvZmlsZXMgb24gdGhlIHBzZXVkby1EViBheGlzCgpgYGB7cn0Kc2V0LnNlZWQoMTAwKQojIENsdXN0ZXIgY2VsbHMgdXNpbmcgdGhlIFBhcnRpdGlvbmluZyBBcm91bmQgTWVkb2lkcyBhbGdvcml0aG0KQ2VsbHMuQ2x1c3QgPC0gcGFtKGFzLmRpc3QoKDEgLSBjb3IoU21vb3RoLmN1cnZlLm1hdHJpeCAsbWV0aG9kID0gInNwZWFybWFuIikpKSwgaz03KQpEb21haW5lcy5DbHVzdCA8LSBkYXRhLmZyYW1lKERvbWFpbmVzID0gcGFzdGUwKCJDbHVzdC4iLENlbGxzLkNsdXN0JGNsdXN0ZXJpbmcpKQpgYGAKCiMgQ2x1c3RlciBnZW5lcyBieSBzaW1pbGFyIHByb2ZpbGVzIG92ZXIgcHNldWRvLURWIGF4aXMKCiMjIFBlcmZvcm0gaGllcmFyY2hpY2FsIGNsdXN0ZXJpbmcKCmBgYHtyfQojIEJ1aWxkIGdlbmVzIGRlbmRyb2dyYW0KZHN0IDwtIGRpc3QodChzY2FsZSh0KFNtb290aC5jdXJ2ZS5tYXRyaXgpKSksIG1ldGhvZCA9ICJtYW5oYXR0YW4iKQpoYyA8LSBoY2x1c3QoZHN0LCBtZXRob2QgPSAid2FyZC5EIikKCiMgU2VyaWF0ZSB0aGUgZGVuZHJvZ3JhbQpkZW5kIDwtIGFzLmRlbmRyb2dyYW0oaGMpCmRlbmQgPC0gZGVuZGV4dGVuZDo6c2VyaWF0ZV9kZW5kcm9ncmFtKGRlbmQsIGRzdCwgbWV0aG9kPSJHVyIpCgojIEZpbmQgMTAgY2x1c3RlcnMgYmFzZWQgb24gaGllcmFyY2hpY2FsIGNsdXN0ZXJpbmcKY2x1c3RlcnMgPC0gY3V0cmVlKGhjLCBrPTEwKQoKR2VuZS5keW5hbWlxdWUgPC0gZGF0YS5mcmFtZShHZW5lPSBuYW1lcyhjbHVzdGVycyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHZhbD0gRFYuQXhpcy5nZW5lcy5GRFIuZmlsdGVyZWQkcHZhbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBxdmFsPURWLkF4aXMuZ2VuZXMuRkRSLmZpbHRlcmVkJHF2YWwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVtX2NlbGxzX2V4cHJlc3NlZD1EVi5BeGlzLmdlbmVzLkZEUi5maWx0ZXJlZCRudW1fY2VsbHNfZXhwcmVzc2VkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdhdmVzID0gYXMubnVtZXJpYyhjbHVzdGVycykpICU+JSBhcnJhbmdlKFdhdmVzKQoKcm93Lm5hbWVzKEdlbmUuZHluYW1pcXVlKSA8LSBHZW5lLmR5bmFtaXF1ZSRHZW5lCkdlbmUuZHluYW1pcXVlJEdlbmUuQ2x1c3RlcnMgPC0gcGFzdGUwKCJDbHVzdC4iLEdlbmUuZHluYW1pcXVlJFdhdmVzKQoKd3JpdGUudGFibGUoR2VuZS5keW5hbWlxdWUsICIuL1Byb2dlbml0b3JzL0dlbmUuZHluYW1pcXVlLmNzdiIsIHNlcCA9ICI7IiwgcXVvdGUgPSBGKQpgYGAKCgojIyBQbG90IGhlYXRtYXAKCmBgYHtyIGZpZy5kaW09Yyg3LCA5LjMpLCBmaWcuY2FwPSAiTWFudXNjcmlwdCBGaWcuIDVDIn0KYW5uby5jb2xvcnMgPC0gbGlzdChEb21haW5lcyA9IGMoQ2x1c3QuMT0iIzgzYzNiOCIsIENsdXN0LjI9IiMwMDlmZGEiLCBDbHVzdC4zPSIjM2U2OWFjIiwgQ2x1c3QuND0iI2U0NmI2YiIsIENsdXN0LjU9IiNlM2MxNDgiLCBDbHVzdC42PSIjYjdkMTc0IiwgQ2x1c3QuNz0iIzY4YjA0MSIpLAogICAgICAgICAgICAgICAgICAgIEdlbmUuQ2x1c3RlcnMgPSBjKENsdXN0LjEgPSIjZWM3NTZkIiAsIENsdXN0LjI9IiNlYmNiMmUiLCBDbHVzdC4zPSIjYjc5ZjBiIiwgQ2x1c3QuND0iIzcyOTNjOCIsIENsdXN0LjU9IiMzY2E3M2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENsdXN0LjY9IiM5ZWMyMmYiLCBDbHVzdC43PSIjY2MzYTFiIiwgQ2x1c3QuOD0iIzRjYWJkYyIsIENsdXN0Ljk9IiNjYzg3NzgiLCBDbHVzdC4xMD0iIzQ3ODRhMiIpKQoKcGhlYXRtYXA6OnBoZWF0bWFwKFNtb290aC5jdXJ2ZS5tYXRyaXgsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3M9IGFzLmhjbHVzdChkZW5kKSwKICAgICAgICAgICAgICAgICAgIHNjYWxlID0gInJvdyIsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX2NvbHMgPSBGLAogICAgICAgICAgICAgICAgICAgZ2Fwc19jb2wgPSBjdW1zdW0oYXMubnVtZXJpYyh0YWJsZShEb21haW5lcy5DbHVzdCREb21haW5lcykpKSwKICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fcm93ID0gR2VuZS5keW5hbWlxdWUgJT4lIGRwbHlyOjpzZWxlY3QoR2VuZS5DbHVzdGVycyksCiAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbCA9IERvbWFpbmVzLkNsdXN0LAogICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9jb2xvcnMgPSBhbm5vLmNvbG9ycywKICAgICAgICAgICAgICAgICAgIHNob3dfY29sbmFtZXMgPSBGLAogICAgICAgICAgICAgICAgICAgc2hvd19yb3duYW1lcyA9IFQsCiAgICAgICAgICAgICAgICAgICBmb250c2l6ZV9yb3cgPSAyLAogICAgICAgICAgICAgICAgICAgY29sb3IgPSByZXYoYnJld2VyLnBhbCgxMSwiUmRCdSIpKSwKICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgtMi41LDIuNSwgbGVuZ3RoLm91dCA9IDExKSwKICAgICAgICAgICAgICAgICAgIG1haW4gPSAiR2VuZXMgZXhwcmVzc2lvbiBhbG9uZyBEb3Jzby1WZW50cmFsIGF4aXMiKQpgYGAKRm9yIHZpc3VhbGl6YXRpb24gcHVycG9zZXMgd2UgbWFudWFsbHkgcm90YXRlZCB0aGUgdHdvIGxhc3QgYnJhbmNoZXMKCiMjIFBsb3QgZ2VuZSBjbHVzdGVycyB0cmVuZHMKYGBge3IgZmlnLmRpbT1jKDYsIDkpLCBmaWcuY2FwPSAiTWFudXNjcmlwdCBGaWcuIDVDIn0Kc291cmNlKCIuL2Z1bmN0aW9ucy9HZW5lc1RyZW5kUGxvdHMuUiIpCkNsdXN0ZXJzLnRyZW5kKEFQLmRhdGEsCiAgICAgICAgICAgICAgIFdoaWNoLmNsdXN0ZXIgPSAxOjEwLAogICAgICAgICAgICAgICBjbHVzdC5saXN0ID0gY2x1c3RlcnMsCiAgICAgICAgICAgICAgIGdyb3VwLmJ5ID0gImdsb2JhbCIsCiAgICAgICAgICAgICAgIHNwYW4gPSAxLAogICAgICAgICAgICAgICBTbW9vdGgubWV0aG9kID0gImF1dG8iLAogICAgICAgICAgICAgICBVc2Uuc2NhbGUuZGF0YSA9IFQpCmBgYAoKIyMgQXNzaWduIGRvbWFpbiBpZGVudGl0eQoKCldlIGFzc2lnbiBkb21haW5zIGlkZW50aXR5IGJhc2VkIG9uIGNsdXN0ZXJzJyB0cmFuc2NyaXB0aW9uYWwgcHJvZmlsZSBieSBzZXR0aW5nIGJvdW5kYXJpZXMgb3ZlciBwc2V1ZG8tRFYgc2NvcmUKYGBge3J9CiMgU2V0IHRoZSBib3VuZGFyaWVzIG92ZXIgcHNldWRvdGltZSBzY29yZQpuZXdfZGF0YSRjbHVzdGVyIDwtIERvbWFpbmVzLkNsdXN0JERvbWFpbmVzCkluZmVyZWQuRG9tYWluLmJvdW5kYXJ5IDwtIGFnZ3JlZ2F0ZShEb3Jzb1ZlbnRyYWwuU2NvcmUgfiBjbHVzdGVyLCBuZXdfZGF0YSwgbWF4KSAlPiUgcHVsbChEb3Jzb1ZlbnRyYWwuU2NvcmUpCgojIEFzc2lnbiBpZGVudGl0aWVzIGJhc2VkIG9uIHRoZSBwb3NpdGlvbiBvZiB0aGUgY2VsbCBvbiB0aGUgcHNldWRvLWR2IGF4aXMKRG9tYWluZS5JZGVudCA8LSBzYXBwbHkoQVAuZGF0YUBtZXRhLmRhdGEkRG9yc29WZW50cmFsLlNjb3JlLAogICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KXsgaWYoeDxJbmZlcmVkLkRvbWFpbi5ib3VuZGFyeVsxXSl7IHggPSAiU3ViLlBhbGxpdW0uMSIKICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmKHg+IEluZmVyZWQuRG9tYWluLmJvdW5kYXJ5WzFdICYgeDwgSW5mZXJlZC5Eb21haW4uYm91bmRhcnlbMl0peyB4ID0iU3ViLlBhbGxpdW0uMiIKICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmKHg+IEluZmVyZWQuRG9tYWluLmJvdW5kYXJ5WzJdICYgeDwgSW5mZXJlZC5Eb21haW4uYm91bmRhcnlbM10peyB4ID0gIlN1Yi5QYWxsaXVtLjMiIAogICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYoeD4gSW5mZXJlZC5Eb21haW4uYm91bmRhcnlbM10gJiB4PCBJbmZlcmVkLkRvbWFpbi5ib3VuZGFyeVs0XSl7IHggPSAiVmVudHJhbC5QYWxsaXVtIgogICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYoeD4gSW5mZXJlZC5Eb21haW4uYm91bmRhcnlbNF0gJiB4PCBJbmZlcmVkLkRvbWFpbi5ib3VuZGFyeVs1XSl7IHggPSAibGF0ZXJhbC5QYWxsaXVtLjEiCiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZih4PiBJbmZlcmVkLkRvbWFpbi5ib3VuZGFyeVs2XSl7IHggPSAiRG9yc2FsLlBhbGxpdW0iCiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB4PSJsYXRlcmFsLlBhbGxpdW0uMiJ9KQoKIyBUcmFuc2ZlcnQgdGhlIGlkZW50aXR5IHRvIHRoZSBTZXVyYXQgb2JqZWN0CkFQLmRhdGFAbWV0YS5kYXRhJERvbWFpbmUgPC0gRG9tYWluZS5JZGVudApBUC5kYXRhIDwtIFNldEFsbElkZW50KEFQLmRhdGEsIGlkID0gIkRvbWFpbmUiKQpgYGAKCgpgYGB7ciBmaWcuZGltPWMoMTAsNSksIGZpZy5jYXA9ICJNYW51c2NyaXB0IEZpZy4gNUQifQpQbG90LkdlbmVzLnRyZW5kKEFQLmRhdGEsCiAgICAgICAgICAgICAgICAgZ2VuZXMgPSBjKCJHc3gyIiwgIkRieDEiLCAiR20yOTI2MCIsICJUZmFwMmMiLCAiRW14MSIsICJMcnJuMSIpLAogICAgICAgICAgICAgICAgIFVzZS5zY2FsZS5kYXRhID0gRikKYGBgCgpgYGB7ciBmaWcuZGltPWMoNS4zLCA0KX0KRGltUGxvdChBUC5kYXRhLAogICAgICAgICBncm91cC5ieSA9ICJEb21haW5lIiwKICAgICAgICAgcmVkdWN0aW9uLnVzZSA9ICJzcHJpbmciLAogICAgICAgICBkaW0uMSA9IDEsCiAgICAgICAgIGRpbS4yID0gMiwKICAgICAgICAgZG8ubGFiZWw9RiwKICAgICAgICAgbGFiZWwuc2l6ZSA9IDQsCiAgICAgICAgIG5vLmxlZ2VuZCA9IEYsCiAgICAgICAgIGNvbHMudXNlID0gdG9sb3dlcihjKCIjNjhCMDQxIiwgIiNFM0MxNDgiLCAiI0I3RDE3NCIsICIjODNDM0I4IiwgIiMwMDlGREEiLCAiIzNFNjlBQyIsICIjRTQ2QjZCIikpCiAgICAgICAgICkKYGBgCgojIFBsb3QgRmlndXJlIDVCCgpgYGB7cn0KIyBMb2FkIGZ1bGwgZGF0YXNldApBbGxjZWxscy5kYXRhIDwtIHJlYWRSRFMoIi4vUUMuZmlsdGVyZWQuY2VsbHMuUkRTIikKCiMgVHJhbnNmZXIgdGhlIGlkZW50aXRpZXMKUmVuYW1lLkNsdXN0IDwtICBmdW5jdGlvbihDbHVzdGRhdGEsIFJhd1FDZGF0YSkgewogIHVuQ2x1c3RlcmVkLmNlbGxzIDwtIFJhd1FDZGF0YUBtZXRhLmRhdGEkQmFyY29kZXMKICBSYXdRQ2RhdGEgPC0gU2V0SWRlbnQoUmF3UUNkYXRhLCBjZWxscy51c2UgPSB1bkNsdXN0ZXJlZC5jZWxscywgaWRlbnQudXNlID0gIkFsbC5VbmNsdXN0ZXJlZC5DZWxscyIpCiAgCiAgZm9yKGkgaW4gdW5pcXVlKENsdXN0ZGF0YUBtZXRhLmRhdGEkRG9tYWluZSkpewogIE5ldy5pZGVudCA8LSBpCiAgQmFyY29kZXMgPC0gcm93bmFtZXMoc3Vic2V0KENsdXN0ZGF0YUBtZXRhLmRhdGEsIENsdXN0ZGF0YUBtZXRhLmRhdGEkRG9tYWluZSA9PSBpKSkKICBwcmludChwYXN0ZTAoIkNsdXN0ZXJfIixpLCI6ICIsbGVuZ3RoKEJhcmNvZGVzKSwgIiBDZWxscyIpKQogIEJhcmNvZGVzIDwtIEJhcmNvZGVzW0JhcmNvZGVzICVpbiUgcm93bmFtZXMoUmF3UUNkYXRhQG1ldGEuZGF0YSldCiAgUmF3UUNkYXRhIDwtIFNldElkZW50KFJhd1FDZGF0YSwgY2VsbHMudXNlID0gQmFyY29kZXMgLGlkZW50LnVzZSA9IHBhc3RlMCgiQVAuIixpKSkKICB9CiAgcmV0dXJuKFJhd1FDZGF0YSkKfQoKQWxsY2VsbHMuZGF0YSA8LSBSZW5hbWUuQ2x1c3QoQ2x1c3RkYXRhID0gQVAuZGF0YSwgUmF3UUNkYXRhID0gQWxsY2VsbHMuZGF0YSkKYGBgCgpgYGB7ciBmaWcuZGltPWMoNS4zLCA0KSwgLCBmaWcuY2FwPSAiTWFudXNjcmlwdCBGaWcuIDVCIn0KY29sb3JzIDwtICBjKCIjOTY5Njk2Iix0b2xvd2VyKGMoIiM2OEIwNDEiLCAiI0UzQzE0OCIsICIjQjdEMTc0IiwgIiM4M0MzQjgiLCAiIzAwOUZEQSIsICIjM0U2OUFDIiwgIiNFNDZCNkIiKSkpCgpEaW1QbG90KEFsbGNlbGxzLmRhdGEsCiAgICAgICAgcmVkdWN0aW9uLnVzZSA9ICJzcHJpbmciLCAKICAgICAgICBkaW0uMSA9IDEsCiAgICAgICAgZGltLjIgPSAyLAogICAgICAgIGRvLmxhYmVsPVQsCiAgICAgICAgbGFiZWwuc2l6ZSA9IDIsCiAgICAgICAgbm8ubGVnZW5kID0gVCwKICAgICAgICBjb2xzLnVzZSA9IGNvbG9ycykKYGBgCgpgYGB7cn0Kcm0obGlzdCA9IGxzKClbIWxzKCkgJWluJSBjKCJBUC5kYXRhIildKQpgYGAKCiMgUGxvdCB0aGUgcmVwcmVzZW50YXRpdmUgZ2VuZSBvZiB0aGUgRmlndXJlIFM2CgpgYGB7cn0KIyBMb2FkIGN1c3RvbSBwbG90dGluZyBmdW5jdGlvbnMKc291cmNlKCIuL2Z1bmN0aW9ucy9HZW5lc1RyZW5kUGxvdHMuUiIpCmBgYAoKYGBge3IgZmlnLmRpbT1jKDEwLDYpLCBmaWcuY2FwPSAiTWFudXNjcmlwdCBGaWcuUzZBIn0KUGxvdC5HZW5lcy50cmVuZChBUC5kYXRhLAogICAgICAgICAgICAgICAgIGdlbmVzID0gYygiRGx4MSIsICJBbm8xIiwgIkRseDIiLCAiT2xpZzIiKSwKICAgICAgICAgICAgICAgICBVc2Uuc2NhbGUuZGF0YSA9IEYpCmBgYAoKYGBge3IgZmlnLmRpbT1jKDEwLDYpLCBmaWcuY2FwPSAiTWFudXNjcmlwdCBGaWcuUzZCIn0KUGxvdC5HZW5lcy50cmVuZChBUC5kYXRhLAogICAgICAgICAgICAgICAgIGdlbmVzID0gYygiT3R4MiIsICJaYnRiMjAiLCAiU2l4MyIsICJBc2NsMSIpLAogICAgICAgICAgICAgICAgIFVzZS5zY2FsZS5kYXRhID0gRikKYGBgCgoKYGBge3IgZmlnLmRpbT1jKDEwLDYpLCBmaWcuY2FwPSAiTWFudXNjcmlwdCBGaWcuUzZDIn0KUGxvdC5HZW5lcy50cmVuZChBUC5kYXRhLAogICAgICAgICAgICAgICAgIGdlbmVzID0gYygiTWVpczEiLCAiUm9yYiIsICJFcGhhMyIpLAogICAgICAgICAgICAgICAgIFVzZS5zY2FsZS5kYXRhID0gRikKYGBgCgpgYGB7ciBmaWcuZGltPWMoMTAsNiksIGZpZy5jYXA9ICJNYW51c2NyaXB0IEZpZy5TNkQifQpQbG90LkdlbmVzLnRyZW5kKEFQLmRhdGEsCiAgICAgICAgICAgICAgICAgZ2VuZXMgPSBjKCJTZnJwMiIsICJFdmExYyIsICJTZW1hNWEiLCAiRmF0NCIpLAogICAgICAgICAgICAgICAgIFVzZS5zY2FsZS5kYXRhID0gRikKYGBgCgoKYGBge3IgZmlnLmRpbT1jKDEwLDYpLCBmaWcuY2FwPSAiTWFudXNjcmlwdCBGaWcuUzZFIn0KUGxvdC5HZW5lcy50cmVuZChBUC5kYXRhLAogICAgICAgICAgICAgICAgIGdlbmVzID0gYygiRG1ydGEyIiwiTHlwZDYiLCAiUGF4NiIsICJEbXJ0YTEiKSwKICAgICAgICAgICAgICAgICBVc2Uuc2NhbGUuZGF0YSA9IEYpCmBgYAoKYGBge3IgZmlnLmRpbT1jKDEwLDYpLCBmaWcuY2FwPSAiTWFudXNjcmlwdCBGaWcuUzZGIn0KUGxvdC5HZW5lcy50cmVuZChBUC5kYXRhLAogICAgICAgICAgICAgICAgIGdlbmVzID0gYygiRW14MSIsICJBcngiLCAiTG1vMyIpLAogICAgICAgICAgICAgICAgIFVzZS5zY2FsZS5kYXRhID0gRikKYGBgCgpgYGB7ciBmaWcuZGltPWMoMTAsNiksIGZpZy5jYXA9ICJNYW51c2NyaXB0IEZpZy5TNkcifQpQbG90LkdlbmVzLnRyZW5kKEFQLmRhdGEsCiAgICAgICAgICAgICAgICAgZ2VuZXMgPSBjKCJGZXpmMiIsICJFbXgyIiwgIlNwOCIpLAogICAgICAgICAgICAgICAgIFVzZS5zY2FsZS5kYXRhID0gRikKYGBgCgojIFRyYW5zZmVydCBpZGVudGl0aWVzIG9uIHRoZSBmdWxsIGRhdGFzZXQgKE1hbnVzY3JpcHQgRmlnLiAyQSkKCmBgYHtyfQojIGxvYWQgZnVsbCBkYXRhc2V0CkFsbGNlbGxzLmRhdGEgPC0gcmVhZFJEUygiLi9DbHVzdGVyZWQuY2VsbHMuUkRTIikKCiNUcmFuc2ZlciB0aGUgaWRlbnRpdGllcwpSZW5hbWUuQ2x1c3QgPC0gIGZ1bmN0aW9uKENsdXN0ZGF0YSwgUmF3UUNkYXRhKSB7CiAgZm9yKGkgaW4gdW5pcXVlKENsdXN0ZGF0YUBtZXRhLmRhdGEkRG9tYWluZSkpewogICAgTmV3LmlkZW50IDwtIGkKICAgIEJhcmNvZGVzIDwtIHJvd25hbWVzKHN1YnNldChDbHVzdGRhdGFAbWV0YS5kYXRhLCBDbHVzdGRhdGFAbWV0YS5kYXRhJERvbWFpbmUgPT0gaSkpCiAgICBwcmludChwYXN0ZTAoIkNsdXN0ZXJfIixpLCI6ICIsbGVuZ3RoKEJhcmNvZGVzKSwgIiBDZWxscyIpKQogICAgQmFyY29kZXMgPC0gQmFyY29kZXNbQmFyY29kZXMgJWluJSByb3duYW1lcyhSYXdRQ2RhdGFAbWV0YS5kYXRhKV0KICAgIFJhd1FDZGF0YSA8LSBTZXRJZGVudChSYXdRQ2RhdGEsIGNlbGxzLnVzZSA9IEJhcmNvZGVzICxpZGVudC51c2UgPSBwYXN0ZTAoIkFQLiIsaSkpCiAgfQogIHJldHVybihSYXdRQ2RhdGEpCn0KCkFsbGNlbGxzLmRhdGEgPC0gUmVuYW1lLkNsdXN0KENsdXN0ZGF0YSA9IEFQLmRhdGEsIFJhd1FDZGF0YSA9IEFsbGNlbGxzLmRhdGEpCmBgYAoKYGBge3IgZmlnLmRpbT1jKDgsIDYpLCBmaWcuY2FwPSAiTWFudXNjcmlwdCBGaWcuIDJBIn0KY29sb3JzMiA8LSAgYygiIzk2OTY5NiIsCiAgICAgICAgICAgICAgdG9sb3dlcihjKCIjNjhCMDQxIiwgIiNFM0MxNDgiLCAiI0I3RDE3NCIsICIjODNDM0I4IiwgIiMwMDlGREEiLCAiIzNFNjlBQyIsICIjRTQ2QjZCIikpLAogICAgICAgICAgICAgICIjZWM3NTZkIiwgIiNjNzczYTciLCAiIzcyOTNjOCIsICIjYjc5ZjBiIiwgIiMzY2E3M2YiLCIjMzFiNmJkIiwKICAgICAgICAgICAgICAiI2ViY2IyZSIsICIjOWVjMjJmIiwgIiNhOTk2MWIiLCAiI2NjM2ExYiIsICIjY2M4Nzc4IiAsICIjZDE0YzhkIiwgIiM0Y2FiZGMiLCAiIzVhYjc5MyIsICIjZTc4MjNhIiwiI2U2YmI5YiIsICIjMDQ2YzlhIiwgIiM0Nzg0YTIiICwgIiM0OTkwYzkiKQoKRGltUGxvdChBbGxjZWxscy5kYXRhLAogICAgICAgIHJlZHVjdGlvbi51c2UgPSAic3ByaW5nIiwgCiAgICAgICAgZGltLjEgPSAxLAogICAgICAgIGRpbS4yID0gMiwKICAgICAgICBkby5sYWJlbD1ULAogICAgICAgIGxhYmVsLnNpemUgPSAyLAogICAgICAgIG5vLmxlZ2VuZCA9IFQsCiAgICAgICAgY29scy51c2UgPSBjb2xvcnMyKQpgYGAKCmBgYHtyfQpBbGxjZWxscy5kYXRhIDwtIFN0YXNoSWRlbnQoQWxsY2VsbHMuZGF0YSwgc2F2ZS5uYW1lID0gIkNsdXN0ZXIuaWRlbnQiKQpzYXZlUkRTKEFsbGNlbGxzLmRhdGEsICIuL0NsdXN0ZXJlZC5jZWxscy5SRFMiKQpzYXZlUkRTKEFQLmRhdGEsICIuL0FQLmRhdGEuUkRTIikKYGBgCgpgYGB7cn0Kcm0obGlzdCA9IGxzKClbIWxzKCkgJWluJSBjKCJBUC5kYXRhIildKQpgYGAKCgojIFBlcmZvcm0gaXRlcmF0aXZlIGdyYXBoLWJhc2VkIGNsdXN0ZXJpbmcgdG8gZmluZCBpZiBkaXNjcmV0ZSBwYWxsaWFsIHN1Yi1kb21haW5zIGV4aXN0CgojIyBFeHRyYWN0IHBhbGxpYWwgcHJvZ2VuaXRvcnMKCmBgYHtyfQojIEZpbHRlciBzdWJwYWxsaWFsIHByb2dlbml0b3JzCkFQLmlkZW50IDwtIHVuaXF1ZShBUC5kYXRhQGlkZW50KQpBUC5kYXRhIDwtICBTdWJzZXREYXRhKEFQLmRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgaWRlbnQudXNlID0gZ3JlcCgiU3ViIiwgQVAuaWRlbnQsIHZhbHVlID0gVCwgaW52ZXJ0ID0gVCksCiAgICAgICAgICAgICAgICAgICAgICAgc3Vic2V0LnJhdyA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgZG8uY2xlYW4gPSBGKQoKIyBSZXNldCB0aGUgcHNldWRvLURWIHNjb3JlIHRvIFswLDFdCnNjb3JlIDwtIEFQLmRhdGFAbWV0YS5kYXRhJERvcnNvVmVudHJhbC5TY29yZQpBUC5kYXRhQG1ldGEuZGF0YSREb3Jzb1ZlbnRyYWwuU2NvcmUgPC0gKHNjb3JlIC0gbWluKHNjb3JlKSkgLyAobWF4KHNjb3JlKSAtIG1pbihzY29yZSkpCmBgYAoKIyMgUGVyZm9ybSBpdGVyYXRpdmUgY2x1c3RlcmluZyBpbXBsZW1lbnRlZCBpbiBzY3JhdHRjaC5oaWNhdCBwYWNrYWdlCgpGb3IgbW9yZSBkZXRhaWwgb24gdGhlIHNjcmF0dGNoLmhpY2F0IHBsZWFzZSByZWZlciB0byB0aGUgW3BhY2thZ2UgcGFnZV0oaHR0cHM6Ly9naXRodWIuY29tL0FsbGVuSW5zdGl0dXRlL3NjcmF0dGNoLmhpY2F0KS4gCgojIyMgUHJlcGFyZSB0aGUgZGF0YXNldCBmb3IgY2x1c3RlcmluZyB3aXRoIHNjcmF0dGNoLmhpY2F0CgojIyMjIEluZGVwZW5kZW50IGdlbmUgZmlsdGVyaW5nCgpXZSBkZWNpZGUgdG8gZXhjbHVkZSAqKkNlbGwgY3ljbGUqKiwgKipyaWJvc29tYWwqKiBhbmQgKiptaXRvY2hvbmRyaWFsKiogYXNzb2NpYXRlZCBnZW5lcywgYXMgd2VsbCBhcyAqKlhpc3QqKiBmb3IgdGhlIGNsdXN0ZXJpbmcgc3RlcC4KCmBgYHtyfQojIEV4Y2x1ZGUgY2VsbCBjeWNsZSBhc3NvY2lhdGVkIGdlbmVzCkNDZ2VuZXMgPC0gYXMuY2hhcmFjdGVyKHJlYWQudGFibGUoIi4vUHJvZ2VuaXRvcnMvQ2VsbEN5Y2xlR2VuZXMuY3N2Iiwgc2VwID0gIlx0IiwgaGVhZGVyID0gRilbLDFdKQoKIyBFeGNsdWRlIGdlbmVzIGRldGVjdGVkIGluIGxlc3MgdGhhbiAzIGNlbGxzCm51bS5jZWxscyA8LSBNYXRyaXg6OnJvd1N1bXMoQVAuZGF0YUBkYXRhID4gMCkKZ2VuZXMudXNlIDwtIG5hbWVzKHggPSBudW0uY2VsbHNbd2hpY2goeCA9IG51bS5jZWxscyA+PSAzKV0pCgpHZW5lc1RvUmVtb3ZlIDwtIGMoZ3JlcChwYXR0ZXJuID0gIiheUnBsfF5ScHN8Xk1ycCkiLCB4ID0gZ2VuZXMudXNlLCB2YWx1ZSA9IFRSVUUpLAogICAgICAgICAgICAgICAgICAgZ3JlcChwYXR0ZXJuID0gIl5tdC0iLCB4ID0gZ2VuZXMudXNlLCB2YWx1ZSA9IFRSVUUpLAogICAgICAgICAgICAgICAgICAgIlhpc3QiLCBDQ2dlbmVzKQoKZ2VuZXMudXNlIDwtIGdlbmVzLnVzZVshZ2VuZXMudXNlICVpbiUgR2VuZXNUb1JlbW92ZV0KYGBgCgojIyMjIE5vcm1hbGl6YXRpb24KYGBge3J9CmRnZU1hdHJpeF9jb3VudCA8LSBhcy5tYXRyaXgoQVAuZGF0YUByYXcuZGF0YSlbcm93bmFtZXMoQVAuZGF0YUByYXcuZGF0YSkgJWluJSBnZW5lcy51c2UsXQpkZ2VNYXRyaXhfY3BtIDwtIGNwbShkZ2VNYXRyaXhfY291bnQpCm5vcm0uZGF0IDwtIGxvZzIoZGdlTWF0cml4X2NwbSArIDEpCmBgYAoKYGBge3J9Cm5vcm0uZGF0IDwtIE1hdHJpeChub3JtLmRhdCwgc3BhcnNlID0gVFJVRSkKRGF0YS5tYXRyaXggPC0gbGlzdChyYXcuZGF0PWRnZU1hdHJpeF9jb3VudCwgbm9ybS5kYXQ9bm9ybS5kYXQpCmF0dGFjaChEYXRhLm1hdHJpeCkKYGBgCgpgYGB7cn0Kcm0obGlzdCA9IGxzKClbIWxzKCkgJWluJSBjKCJBUC5kYXRhIiwgIkRhdGEubWF0cml4IildKQpgYGAKCiMjIyMgU2VsZWN0IGZlYXR1cmVzIHVzZWQgdG8gcmVtb3ZlIFBDcyB3aGljaCB3b3VsZCBjb3JyZWxhdGUgd2l0aCB1bndhbnRlZCBzb3VyY2VzIG9mIHZhcmlhdGlvbgoKYGBge3J9CmdlbmUuY291bnRzIDwtIGxvZzIoY29sU3Vtcyhhcy5tYXRyaXgoRGF0YS5tYXRyaXgkbm9ybS5kYXQpID4gMCkpCm5VTUkgPC0gbG9nMihjb2xTdW1zKERhdGEubWF0cml4JHJhdy5kYXQpKQpwZXJjdE1pdG8gPC0gQVAuZGF0YUBtZXRhLmRhdGEkcGVyY2VudC5taXRvCnBlcmN0UmlibyA8LSBBUC5kYXRhQG1ldGEuZGF0YSRwZXJjZW50LnJpYm8KUHNldWRvRFZzY29yZSA8LSBBUC5kYXRhQG1ldGEuZGF0YSREb3Jzb1ZlbnRyYWwuU2NvcmUKCnJtLmVpZ2VuIDwtIGFzLm1hdHJpeChjYmluZChnZW5lLmNvdW50cywKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5VTUksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZXJjdE1pdG8sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZXJjdFJpYm8sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBQc2V1ZG9EVnNjb3JlKSkKCnJvdy5uYW1lcyhybS5laWdlbikgPC0gbmFtZXMoZ2VuZS5jb3VudHMpCgpjb2xuYW1lcyhybS5laWdlbikgPC0gYygibG9nMm5HZW5lcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICJsb2cyblVNSSIsCiAgICAgICAgICAgICAgICAgICAgICAgICJwZXJjdE1pdG8iLAogICAgICAgICAgICAgICAgICAgICAgICAicGVyY3RSaWJvIiwKICAgICAgICAgICAgICAgICAgICAgICAgIlBzZXVkb0RWc2NvcmUiKQoKcm0oZ2VuZS5jb3VudHMsIG5VTUksIHBlcmN0TWl0bywgcGVyY3RSaWJvLFBzZXVkb0RWc2NvcmUpCmBgYAoKIyMjIEl0ZXJhdGl2ZSBjbHVzdGVyaW5nCgpgYGB7cn0KIyBQYXJhbWV0ZXJzIGZvciBpdGVyYXRpdmUgY2x1c3RlcmluZwpkZS5wYXJhbSA8LSBkZV9wYXJhbShwYWRqLnRoICAgICA9IDAuMDEsIAogICAgICAgICAgICAgICAgICAgICBsZmMudGggICAgICA9IDAuOSwKICAgICAgICAgICAgICAgICAgICAgbG93LnRoICAgICAgPSAxLCAKICAgICAgICAgICAgICAgICAgICAgcTEudGggICAgICAgPSAwLjI1LCAKICAgICAgICAgICAgICAgICAgICAgcTIudGggICAgICAgPSBOVUxMLAogICAgICAgICAgICAgICAgICAgICBxLmRpZmYudGggICA9IDAuNywKICAgICAgICAgICAgICAgICAgICAgZGUuc2NvcmUudGggPSAxMDAsCiAgICAgICAgICAgICAgICAgICAgIG1pbi5jZWxscyA9IDEwKQpgYGAKCiMjIyMgUnVuIHRoZSBpdGVyYXRpdmUgY2x1c3RlcmluZwoKVGhlIGRlZmF1bHQgaXRlcl9jbHVzdCBmdW5jdGlvbiB1c2UgaW4gdGhpcyB2ZXJzaW9uIG9mIHRoZSBzY3JhdHRjaC5oaWNhdCBwYWNrYWdlIGRvZXMgbm90IGFsbG93IHRvIHNldCB0aGUgay5wYXJhbSBhcmd1bWVudC4gV2UgbW9kaWZpZWQgdGhpcyBmdW5jdGlvbiB0byBhbGxvdyB0aGlzIGFyZ3VtZW50IHRvIGJlIHNldCB0byBvdGhlciB2YWx1ZXMuCgpgYGB7ciBjbGFzcy5vdXRwdXQ9InNjcm9sbC0xMDAifQojIFBlcmZvcm0gdGhlIGl0ZXJhdGl2ZSBjbHVzdGVyaW5nIAppdGVyLnJlc3VsdCA8LSBpdGVyX2NsdXN0KG5vcm0uZGF0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICBjb3VudHMgPSByYXcuZGF0LAogICAgICAgICAgICAgICAgICAgICAgICAgIGRpbS5tZXRob2QgPSAicGNhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBtYXguZGltID0gMTUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZGUucGFyYW0gPSBkZS5wYXJhbSwKICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInVuZGlyZWN0aW9uYWwiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHJtLmVpZ2VuID0gcm0uZWlnZW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgay5wYXJhbSA9IDE1LAogICAgICAgICAgICAgICAgICAgICAgICAgIHJtLnRoID0gMC43LAogICAgICAgICAgICAgICAgICAgICAgICAgIHZnLnBhZGoudGggPSAwLjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gImxvdXZhaW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgIHByZWZpeCA9ICJ0ZXN0LWl0ZXJfY2x1c3QiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2UgPSBGKQoKYGBgCiMjIyMgTWVyZ2UgY2x1c3RlcnMgbm90IHNlcGVyYWJsZSBieSBERUdzCgpgYGB7cn0KIyBNZXJnZSBjbHVzdGVycyB3aGljaCBhcmUgbm90IHNlcGVyYWJsZSBieSBERUdzCnJkLmRhdCA8LSB0KG5vcm0uZGF0W2l0ZXIucmVzdWx0JG1hcmtlcnMsXSkKbWVyZ2UucmVzdWx0IDwtIG1lcmdlX2NsKG5vcm0uZGF0LCAKICAgICAgICAgICAgICAgICAgICAgICAgIGNsID0gaXRlci5yZXN1bHQkY2wsIAogICAgICAgICAgICAgICAgICAgICAgICAgcmQuZGF0ID0gcmQuZGF0LAogICAgICAgICAgICAgICAgICAgICAgICAgZGUucGFyYW0gPSBkZS5wYXJhbSkKCmNhdChsZW5ndGgodW5pcXVlKG1lcmdlLnJlc3VsdCRjbCkpLCIgQ2x1c3RlcnNcbiIpCmNhdChsZW5ndGgodW5pcXVlKG1lcmdlLnJlc3VsdCRtYXJrZXJzKSksICIgREUgZ2VuZXMiKQpgYGAKCiMjIyMgSW1wb3J0IGNlbGwgbGFiZWxzIGludG8gdGhlIFNldXJhdCBvYmoKCmBgYHtyIGZpZy5kaW09Yyg1LjMsIDQpfQpBUC5kYXRhQGlkZW50IDwtIGFzLmZhY3RvcihtZXJnZS5yZXN1bHQkY2wpCkFQLmRhdGFAbWV0YS5kYXRhJFBhbGxpYWwuc3ViRG9tYWluZSA8LWFzLmNoYXJhY3RlcihBUC5kYXRhQGlkZW50KQoKY29sb3JzIDwtICBjKCIjOTY5Njk2IiwgIiNlNzgyM2EiKQoKRGltUGxvdChBUC5kYXRhLAogICAgICAgIHJlZHVjdGlvbi51c2UgPSAic3ByaW5nIiwKICAgICAgICBkaW0uMSA9IDEsCiAgICAgICAgZGltLjIgPSAyLAogICAgICAgIGRvLmxhYmVsPVQsCiAgICAgICAgcHQuc2l6ZSA9IDIsCiAgICAgICAgbGFiZWwuc2l6ZSA9IDQsCiAgICAgICAgbm8ubGVnZW5kID0gRiwKICAgICAgICBjb2xzLnVzZSA9IGNvbG9ycykKYGBgCgojIyBGaW5kIHN1Yi1kb21haW4gbWFya2VyIGdlbmVzCmBgYHtyfQojIEZpbmQgZ2VuZXMgd2hpY2ggYmVzdCBkaXN0aW5ndWlzaCB0aGUgc3ViZG9tYWlucwpBbGxtYXJrZXJzIDwtIEZpbmRBbGxNYXJrZXJzKG9iamVjdCA9IEFQLmRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdC51c2UgPSAicm9jIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW4ucGN0ID0gMC4zLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2ZjLnRocmVzaG9sZCA9IDAuNiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmludC5iYXIgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ubHkucG9zID0gVCkKCkFsbG1hcmtlcnMkcS5kaWZmIDwtIGFicyhBbGxtYXJrZXJzJHBjdC4xIC0gQWxsbWFya2VycyRwY3QuMikvbWF4KEFsbG1hcmtlcnMkcGN0LjEsIEFsbG1hcmtlcnMkcGN0LjIpCkFsbG1hcmtlcnMkU3BlY2lmaWNpdHkuaW5kZXggPC0gQWxsbWFya2VycyRhdmdfbG9nRkMvICgxLUFsbG1hcmtlcnMkcS5kaWZmKQoKU2VsZWN0ZWQubWFya2VycyA8LSBBbGxtYXJrZXJzICU+JQogIGZpbHRlcihTcGVjaWZpY2l0eS5pbmRleCA+IDEpICU+JSBwdWxsKGdlbmUpCmBgYAoKYGBge3J9CiMgUHJlcGFyZSBhbm5vdGF0aW9uIGZvciBwbG90dGluZwpjb2xvcnMgPC0gIGMoIiM5Njk2OTYiLCAiI2U3ODIzYSIpCmNvbG9yc2lkZW50IDwtIGNiaW5kKGlkZW50ID0gdW5pcXVlKGFzLmNoYXJhY3RlcihBUC5kYXRhQGlkZW50KSksCiAgICAgICAgICAgICAgICAgICAgIGNvbG9ycyA9IGNvbG9ycywKICAgICAgICAgICAgICAgICAgICAgaWQgPSB1bmlxdWUoYXMuY2hhcmFjdGVyKEFQLmRhdGFAaWRlbnQpKSkKCiMgQ3JlYXRlIGFubm90YXRpb24gZGF0YS5mcmFtZQphbm5vLmRmIDwtIGFzLmRhdGEuZnJhbWUoY2JpbmQoCiAgc2FtcGxlX25hbWUgPSByb3cubmFtZXMoQVAuZGF0YUBtZXRhLmRhdGEpLAogIHByaW1hcnlfdHlwZV9pZCA9IGNvbG9yc2lkZW50W21hdGNoKGFzLmNoYXJhY3RlcihBUC5kYXRhQGlkZW50KSwgY29sb3JzaWRlbnRbLDFdKSwzXSwKICBwcmltYXJ5X3R5cGVfbGFiZWwgPSBhcy5jaGFyYWN0ZXIoQVAuZGF0YUBpZGVudCksCiAgcHJpbWFyeV90eXBlX2NvbG9yID0gY29sb3JzaWRlbnRbbWF0Y2goYXMuY2hhcmFjdGVyKEFQLmRhdGFAaWRlbnQpLCBjb2xvcnNpZGVudFssMV0pLDJdCikpCgoKIyBQbG90IGNlbGxzIGJhcnBsb3QKZGF0YSA8LSBjYmluZChzYW1wbGVfbmFtZSA9IGNvbG5hbWVzKEFQLmRhdGFAZGF0YSksCiAgICAgICAgICAgICAgYXMuZGF0YS5mcmFtZSh0KGFzLm1hdHJpeChBUC5kYXRhQGRhdGEpKSkpCgpzYW1wbGVfYmFyX3Bsb3QoZGF0YSwgCiAgICAgICAgICAgICAgICBhbm5vLmRmLCAKICAgICAgICAgICAgICAgIGdlbmVzID0gU2VsZWN0ZWQubWFya2VycywKICAgICAgICAgICAgICAgIGdyb3VwX29yZGVyID0gYygiMSIsIjMiKSwKICAgICAgICAgICAgICAgIGdyb3VwaW5nID0gInByaW1hcnlfdHlwZSIsCiAgICAgICAgICAgICAgICBsb2dfc2NhbGUgPSBGQUxTRSwKICAgICAgICAgICAgICAgIGZvbnRfc2l6ZSA9IDcsCiAgICAgICAgICAgICAgICBsYWJlbF9oZWlnaHQgPSAxMCwKICAgICAgICAgICAgICAgIGxhYmVsX3R5cGUgPSAiYW5nbGUiLAogICAgICAgICAgICAgICAgYmdfY29sb3IgPSIjZjdmN2Y3IikKYGBgCgoKIyBTZXNzaW9uIEluZm8KYGBge3J9CiNkYXRlCmZvcm1hdChTeXMudGltZSgpLCAiJWQgJUIsICVZLCAlSCwlTSIpCgojUGFja2FnZXMgdXNlZApzZXNzaW9uSW5mbygpCmBgYA==