diff --git a/RNA-seq/02-gastric_cancer_tximeta.nb.html b/RNA-seq/02-gastric_cancer_tximeta.nb.html index 5ad82e07..778bfb98 100644 --- a/RNA-seq/02-gastric_cancer_tximeta.nb.html +++ b/RNA-seq/02-gastric_cancer_tximeta.nb.html @@ -3264,8 +3264,8 @@

Summarize to gene

# Summarize to the gene level
 gene_summarized <- summarizeToGene(txi_data)
- -
loading existing EnsDb created: 2024-08-08 16:10:27
+ +
loading existing EnsDb created: 2024-12-04 21:59:44
obtaining transcript-to-gene mapping from database
diff --git a/scRNA-seq-advanced/01-read_filter_normalize_scRNA-live.Rmd b/scRNA-seq-advanced/01-read_filter_normalize_scRNA-live.Rmd index e5407a46..e5877fe2 100644 --- a/scRNA-seq-advanced/01-read_filter_normalize_scRNA-live.Rmd +++ b/scRNA-seq-advanced/01-read_filter_normalize_scRNA-live.Rmd @@ -90,9 +90,7 @@ Finally, we will set up the our output directory, creating it if it does not yet normalized_dir <- file.path(data_dir, "normalized") # create the directory if it does not exist -if (!dir.exists(normalized_dir)) { - dir.create(normalized_dir, recursive = TRUE) -} +fs::dir_create(normalized_dir) # output RDS file for normalized data output_sce_file <- file.path(normalized_dir, diff --git a/scRNA-seq-advanced/01-read_filter_normalize_scRNA.nb.html b/scRNA-seq-advanced/01-read_filter_normalize_scRNA.nb.html index 98d9521c..5668bd50 100644 --- a/scRNA-seq-advanced/01-read_filter_normalize_scRNA.nb.html +++ b/scRNA-seq-advanced/01-read_filter_normalize_scRNA.nb.html @@ -3107,16 +3107,14 @@

Directories and files

- +
# Outputs ------------------------------------
 
 # Directory and file to save output
 normalized_dir <- file.path(data_dir, "normalized")
 
 # create the directory if it does not exist
-if (!dir.exists(normalized_dir)) {
-  dir.create(normalized_dir, recursive = TRUE)
-}
+fs::dir_create(normalized_dir)
 
 # output RDS file for normalized data
 output_sce_file <- file.path(normalized_dir,
@@ -3144,9 +3142,12 @@ 

Reading Cell Ranger data

other common data formats are discussed in [Chapter 3 of OSCA] (http://bioconductor.org/books/3.16/OSCA.intro/getting-scrna-seq-datasets.html#reading-counts-into-r).

- +
# read SCE from matrix directory
-raw_sce <- DropletUtils::read10xCounts(raw_matrix_dir)
+raw_sce <- DropletUtils::read10xCounts( + raw_matrix_dir, + col.names = TRUE # ensure barcodes are set as column names in the SCE object +)
Warning: replacing previous import 'S4Arrays::makeNindexFromArrayViewport' by
@@ -3161,7 +3162,7 @@ 

Reading Cell Ranger data

# view SCE object
 raw_sce
- +
class: SingleCellExperiment 
 dim: 36601 734492 
 metadata(1): Samples
@@ -3169,7 +3170,8 @@ 

Reading Cell Ranger data

rownames(36601): ENSG00000243485 ENSG00000237613 ... ENSG00000278817 ENSG00000277196 rowData names(3): ID Symbol Type -colnames: NULL +colnames(734492): AAACCCAAGAAACCCA-1 AAACCCAAGAAATTCG-1 ... + TTTGTTGTCTTTCTAG-1 TTTGTTGTCTTTGCAT-1 colData names(2): Sample Barcode reducedDimNames(0): mainExpName: NULL @@ -3251,16 +3253,16 @@

Structure of the SingleCellExperiment object

# view colData (cell barcodes)
 head(colData(raw_sce))
- +
DataFrame with 6 rows and 2 columns
-                  Sample            Barcode
-             <character>        <character>
-1 data/glioblastoma-10.. AAACCCAAGAAACCCA-1
-2 data/glioblastoma-10.. AAACCCAAGAAATTCG-1
-3 data/glioblastoma-10.. AAACCCAAGAACTGAT-1
-4 data/glioblastoma-10.. AAACCCAAGAAGAACG-1
-5 data/glioblastoma-10.. AAACCCAAGAAGCGCT-1
-6 data/glioblastoma-10.. AAACCCAAGAAGGATG-1
+ Sample Barcode + <character> <character> +AAACCCAAGAAACCCA-1 data/glioblastoma-10.. AAACCCAAGAAACCCA-1 +AAACCCAAGAAATTCG-1 data/glioblastoma-10.. AAACCCAAGAAATTCG-1 +AAACCCAAGAACTGAT-1 data/glioblastoma-10.. AAACCCAAGAACTGAT-1 +AAACCCAAGAAGAACG-1 data/glioblastoma-10.. AAACCCAAGAAGAACG-1 +AAACCCAAGAAGCGCT-1 data/glioblastoma-10.. AAACCCAAGAAGCGCT-1 +AAACCCAAGAAGGATG-1 data/glioblastoma-10.. AAACCCAAGAAGGATG-1
@@ -3313,7 +3315,7 @@

Filtering empty droplets

raw_sce
- +
class: SingleCellExperiment 
 dim: 36601 462027 
 metadata(1): Samples
@@ -3321,7 +3323,8 @@ 

Filtering empty droplets

rownames(36601): ENSG00000243485 ENSG00000237613 ... ENSG00000278817 ENSG00000277196 rowData names(3): ID Symbol Type -colnames: NULL +colnames(462027): AAACCCAAGAAACCCA-1 AAACCCAAGAAATTCG-1 ... + TTTGTTGTCTTTCTAG-1 TTTGTTGTCTTTGCAT-1 colData names(2): Sample Barcode reducedDimNames(0): mainExpName: NULL @@ -3370,21 +3373,21 @@

Filtering empty droplets

# view rows where FDR is not `NA`
 droplet_df[!is.na(droplet_df$FDR), ]
- +
DataFrame with 2176 rows and 5 columns
-         Total   LogProb     PValue   Limited         FDR
-     <integer> <numeric>  <numeric> <logical>   <numeric>
-1        15622        NA         NA        NA   0.0000000
-2          589  -1614.42  0.6597340     FALSE   0.7664609
-3          507  -1343.92  0.9993001     FALSE   1.0000000
-4        19899        NA         NA        NA   0.0000000
-5          881  -2262.85  0.0237976     FALSE   0.0311013
-...        ...       ...        ...       ...         ...
-2172       867  -2361.80 0.00009999      TRUE 0.000139922
-2173      1245  -2840.48 0.04199580     FALSE 0.054297601
-2174       770  -2046.57 0.05659434     FALSE 0.072654445
-2175      1011  -2876.13 0.00009999      TRUE 0.000139922
-2176      9987        NA         NA        NA 0.000000000
+ Total LogProb PValue Limited FDR + <integer> <numeric> <numeric> <logical> <numeric> +AAACCCACATGTGTCA-1 15622 NA NA NA 0.0000000 +AAACCCAGTGGTAATA-1 589 -1614.42 0.6597340 FALSE 0.7664609 +AAACGAAAGAAACTAC-1 507 -1343.92 0.9993001 FALSE 1.0000000 +AAACGAAAGAGAACCC-1 19899 NA NA NA 0.0000000 +AAACGAATCCCTTCCC-1 881 -2262.85 0.0237976 FALSE 0.0311013 +... ... ... ... ... ... +TTTGGTTTCCCGGTAG-1 867 -2361.80 0.00009999 TRUE 0.000139922 +TTTGGTTTCCGGACTG-1 1245 -2840.48 0.04199580 FALSE 0.054297601 +TTTGGTTTCTGTCCCA-1 770 -2046.57 0.05659434 FALSE 0.072654445 +TTTGTTGGTCAGGCAA-1 1011 -2876.13 0.00009999 TRUE 0.000139922 +TTTGTTGTCAGATTGC-1 9987 NA NA NA 0.000000000
@@ -3411,7 +3414,7 @@

Filtering empty droplets

filtered_sce
- +
class: SingleCellExperiment 
 dim: 36601 1626 
 metadata(1): Samples
@@ -3419,7 +3422,8 @@ 

Filtering empty droplets

rownames(36601): ENSG00000243485 ENSG00000237613 ... ENSG00000278817 ENSG00000277196 rowData names(3): ID Symbol Type -colnames: NULL +colnames(1626): AAACCCACATGTGTCA-1 AAACGAAAGAGAACCC-1 ... + TTTGTTGGTCAGGCAA-1 TTTGTTGTCAGATTGC-1 colData names(2): Sample Barcode reducedDimNames(0): mainExpName: NULL @@ -3498,24 +3502,32 @@

Calculating summary QC statistics

head(colData(filtered_sce))
- +
DataFrame with 6 rows and 8 columns
-                  Sample            Barcode       sum  detected
-             <character>        <character> <numeric> <integer>
-1 data/glioblastoma-10.. AAACCCACATGTGTCA-1     15622      2822
-2 data/glioblastoma-10.. AAACGAAAGAGAACCC-1     19899      3503
-3 data/glioblastoma-10.. AAACGCTAGATTAGAC-1      2858      1367
-4 data/glioblastoma-10.. AAACGCTGTACGCTAT-1     31363      4354
-5 data/glioblastoma-10.. AAAGAACAGTACAGCG-1     12636      2780
-6 data/glioblastoma-10.. AAAGGATAGATTGTGA-1     13489      2533
-  subsets_mito_sum subsets_mito_detected subsets_mito_percent     total
-         <numeric>             <integer>            <numeric> <numeric>
-1             1699                    13             10.87569     15622
-2             1141                    11              5.73396     19899
-3              108                    10              3.77887      2858
-4             1887                    13              6.01664     31363
-5             1008                    11              7.97721     12636
-6             1145                    13              8.48840     13489
+ Sample Barcode sum + <character> <character> <numeric> +AAACCCACATGTGTCA-1 data/glioblastoma-10.. AAACCCACATGTGTCA-1 15622 +AAACGAAAGAGAACCC-1 data/glioblastoma-10.. AAACGAAAGAGAACCC-1 19899 +AAACGCTAGATTAGAC-1 data/glioblastoma-10.. AAACGCTAGATTAGAC-1 2858 +AAACGCTGTACGCTAT-1 data/glioblastoma-10.. AAACGCTGTACGCTAT-1 31363 +AAAGAACAGTACAGCG-1 data/glioblastoma-10.. AAAGAACAGTACAGCG-1 12636 +AAAGGATAGATTGTGA-1 data/glioblastoma-10.. AAAGGATAGATTGTGA-1 13489 + detected subsets_mito_sum subsets_mito_detected + <integer> <numeric> <integer> +AAACCCACATGTGTCA-1 2822 1699 13 +AAACGAAAGAGAACCC-1 3503 1141 11 +AAACGCTAGATTAGAC-1 1367 108 10 +AAACGCTGTACGCTAT-1 4354 1887 13 +AAAGAACAGTACAGCG-1 2780 1008 11 +AAAGGATAGATTGTGA-1 2533 1145 13 + subsets_mito_percent total + <numeric> <numeric> +AAACCCACATGTGTCA-1 10.87569 15622 +AAACGAAAGAGAACCC-1 5.73396 19899 +AAACGCTAGATTAGAC-1 3.77887 2858 +AAACGCTGTACGCTAT-1 6.01664 31363 +AAAGAACAGTACAGCG-1 7.97721 12636 +AAAGGATAGATTGTGA-1 8.48840 13489
@@ -3649,7 +3661,7 @@

One more filter: unique gene count

qcfiltered_sce <- qcfiltered_sce[, which(qcfiltered_sce$detected >= 200)] qcfiltered_sce
- +
class: SingleCellExperiment 
 dim: 36601 1233 
 metadata(1): Samples
@@ -3657,7 +3669,8 @@ 

One more filter: unique gene count

rownames(36601): ENSG00000243485 ENSG00000237613 ... ENSG00000278817 ENSG00000277196 rowData names(3): ID Symbol Type -colnames: NULL +colnames(1233): AAACCCACATGTGTCA-1 AAACGAAAGAGAACCC-1 ... + TTTGGTTTCATCTACT-1 TTTGTTGTCAGATTGC-1 colData names(9): Sample Barcode ... total prob_compromised reducedDimNames(0): mainExpName: NULL @@ -3717,7 +3730,7 @@

Normalization

normalized_sce
- +
class: SingleCellExperiment 
 dim: 36601 1233 
 metadata(1): Samples
@@ -3725,7 +3738,8 @@ 

Normalization

rownames(36601): ENSG00000243485 ENSG00000237613 ... ENSG00000278817 ENSG00000277196 rowData names(3): ID Symbol Type -colnames: NULL +colnames(1233): AAACCCACATGTGTCA-1 AAACGAAAGAGAACCC-1 ... + TTTGGTTTCATCTACT-1 TTTGTTGTCAGATTGC-1 colData names(10): Sample Barcode ... prob_compromised sizeFactor reducedDimNames(0): mainExpName: NULL @@ -3832,7 +3846,7 @@

Principal components analysis

normalized_sce
- +
class: SingleCellExperiment 
 dim: 36601 1233 
 metadata(1): Samples
@@ -3840,7 +3854,8 @@ 

Principal components analysis

rownames(36601): ENSG00000243485 ENSG00000237613 ... ENSG00000278817 ENSG00000277196 rowData names(3): ID Symbol Type -colnames: NULL +colnames(1233): AAACCCACATGTGTCA-1 AAACGAAAGAGAACCC-1 ... + TTTGGTTTCATCTACT-1 TTTGTTGTCAGATTGC-1 colData names(10): Sample Barcode ... prob_compromised sizeFactor reducedDimNames(1): PCA mainExpName: NULL @@ -3903,12 +3918,12 @@

UMAP

results using the plotReducedDim() function.

- +
# plot the UMAP
 scater::plotReducedDim(normalized_sce,
                        "UMAP",
                        # color by the most variable gene
-                       colour_by = hv_genes[1])
+ color_by = hv_genes[1])

@@ -3985,10 +4000,10 @@

Unsupervised clustering

we can skip that argument.

- +
# plot UMAP with assigned clusters
 scater::plotUMAP(normalized_sce,
-                 colour_by = "nn_cluster")
+ color_by = "nn_cluster")

@@ -4033,7 +4048,7 @@

Print session info

sessionInfo()
- +
R version 4.4.1 (2024-06-14)
 Platform: x86_64-pc-linux-gnu
 Running under: Ubuntu 22.04.4 LTS
@@ -4103,27 +4118,27 @@ 

Print session info

[69] glue_1.7.0 metapod_1.12.0 [71] tools_4.4.1 BiocNeighbors_1.22.0 [73] ScaledMatrix_1.12.0 locfit_1.5-9.9 - [75] scran_1.32.0 cowplot_1.1.3 - [77] rhdf5_2.48.0 grid_4.4.1 - [79] DropletUtils_1.24.0 edgeR_4.2.0 - [81] colorspace_2.1-0 GenomeInfoDbData_1.2.12 - [83] beeswarm_0.4.0 BiocSingular_1.20.0 - [85] HDF5Array_1.32.0 vipor_0.4.7 - [87] cli_3.6.2 rsvd_1.0.5 - [89] fansi_1.0.6 viridisLite_0.4.2 - [91] S4Arrays_1.4.0 dplyr_1.1.4 - [93] uwot_0.2.2 gtable_0.3.5 - [95] R.methodsS3_1.8.2 sass_0.4.9 - [97] digest_0.6.35 ggrepel_0.9.5 - [99] SparseArray_1.4.0 dqrng_0.3.2 - [ reached getOption("max.print") -- omitted 7 entries ]
+ [75] fs_1.6.4 scran_1.32.0 + [77] cowplot_1.1.3 rhdf5_2.48.0 + [79] grid_4.4.1 DropletUtils_1.24.0 + [81] edgeR_4.2.0 colorspace_2.1-0 + [83] GenomeInfoDbData_1.2.12 beeswarm_0.4.0 + [85] BiocSingular_1.20.0 HDF5Array_1.32.0 + [87] vipor_0.4.7 rsvd_1.0.5 + [89] cli_3.6.2 fansi_1.0.6 + [91] viridisLite_0.4.2 S4Arrays_1.4.0 + [93] dplyr_1.1.4 uwot_0.2.2 + [95] gtable_0.3.5 R.methodsS3_1.8.2 + [97] sass_0.4.9 digest_0.6.35 + [99] ggrepel_0.9.5 SparseArray_1.4.0 + [ reached getOption("max.print") -- omitted 8 entries ]
-
LS0tCnRpdGxlOiAiUmVhZGluZywgZmlsdGVyaW5nLCBhbmQgbm9ybWFsaXppbmcgc2NSTkEtc2VxIGRhdGEiCmF1dGhvcjogRGF0YSBMYWIgZm9yIEFMU0YKZGF0ZTogMjAyMwpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCi0tLQoKIyMgT2JqZWN0aXZlcwoKVGhpcyBub3RlYm9vayB3aWxsIGRlbW9uc3RyYXRlIGhvdyB0bzoKCi0gUmVhZCBDZWxsIFJhbmdlciBkYXRhIGludG8gUgotIEZpbHRlciB0byBjZWxscyB1c2luZyBgZW1wdHlEcm9wc0NlbGxSYW5nZXIoKWAKLSBDYWxjdWxhdGUgcXVhbGl0eSBjb250cm9sIG1lYXN1cmVzIG9uIHNjUk5BLXNlcSBkYXRhCi0gUmVtb3ZlIGxpa2VseSBjb21wcm9taXNlZCBjZWxscyB3aXRoIGBtaVFDKClgCi0gTm9ybWFsaXplIGV4cHJlc3Npb24gZGF0YSBhY3Jvc3MgY2VsbHMKLSBDYWxjdWxhdGUgYW5kIHBsb3QgcmVkdWNlZCBkaW1lbnNpb24gcmVwcmVzZW50YXRpb25zIG9mIGV4cHJlc3Npb24gZGF0YSAoUENBLCBVTUFQKQoKLS0tCgpJbiB0aGlzIG5vdGVib29rLCB3ZSB3aWxsIHJldmlldyBiYXNpYyBwcm9jZXNzaW5nIGZvciBzaW5nbGUtY2VsbCBSTkEtc2VxIGRhdGEsIHN0YXJ0aW5nIHdpdGggdGhlIG91dHB1dCBmcm9tIENlbGwgUmFuZ2VyLCBhbmQgcHJvY2VlZGluZyB0aHJvdWdoIGZpbHRlcmluZywgcXVhbGl0eSBjb250cm9sLCBub3JtYWxpemF0aW9uLCBhbmQgZGltZW5zaW9uIHJlZHVjdGlvbi4gV2Ugd2lsbCBwZXJmb3JtIHRoZXNlIHRhc2tzIHVzaW5nIHRvb2xzIGZyb20gdGhlIFtCaW9jb25kdWN0b3IgcHJvamVjdF0oaHR0cHM6Ly9iaW9jb25kdWN0b3Iub3JnKSwgaW4gcGFydGljdWxhciBbYFNpbmdsZUNlbGxFeHBlcmltZW50YCBvYmplY3RzXShodHRwczovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvcmVsZWFzZS9iaW9jL2h0bWwvU2luZ2xlQ2VsbEV4cGVyaW1lbnQuaHRtbCkgYW5kIGZ1bmN0aW9ucyB0aGF0IHdvcmsgd2l0aCB0aG9zZSBvYmplY3RzLgpNdWNoIG9mIHRoZSBtYXRlcmlhbCBpbiB0aGlzIG5vdGVib29rIGlzIGRpcmVjdGx5IGluc3BpcmVkIGJ5LCBhbmQgZHJhd3MgaGVhdmlseSBvbiwgbWF0ZXJpYWwgcHJlc2VudGVkIGluIHRoZSBib29rIFtfT3JjaGVzdHJhdGluZyBTaW5nbGUgQ2VsbCBBbmFseXNpcyB3aXRoIEJpb2NvbmR1Y3Rvcl8gKE9TQ0EpXShodHRwOi8vYmlvY29uZHVjdG9yLm9yZy9ib29rcy8zLjE2L09TQ0EvKS4KCiFbU2luZ2xlLWNlbGwgcm9hZG1hcDogT3ZlcnZpZXddKGRpYWdyYW1zL3JvYWRtYXBfc2luZ2xlX292ZXJ2aWV3LnBuZykKClRoZSBkYXRhIHdlIHdpbGwgdXNlIGZvciB0aGlzIG5vdGVib29rIGlzIGRlcml2ZWQgZnJvbSBhIGh1bWFuIGdsaW9ibGFzdG9tYSBzcGVjaW1lbi4KVGhlIHNhbXBsZSB3YXMgcHJvY2Vzc2VkIGJ5IDEweCBHZW5vbWljcyB1c2luZyBhIDMnIFJOQSBraXQgKHYzLjEpLCBzZXF1ZW5jZWQsIGFuZCBxdWFudGlmaWVkIHdpdGggQ2VsbCBSYW5nZXIgNi4wLgpGdXJ0aGVyIGRldGFpbHMgYWJvdXQgdGhlIHNhbXBsZSBhbmQgcHJvY2Vzc2luZyBjYW4gYmUgZm91bmQgb24gdGhlIFsxMHggd2Vic2l0ZV0oaHR0cHM6Ly93d3cuMTB4Z2Vub21pY3MuY29tL3Jlc291cmNlcy9kYXRhc2V0cy8yLWstc29ydGVkLWNlbGxzLWZyb20taHVtYW4tZ2xpb2JsYXN0b21hLW11bHRpZm9ybWUtMy12LTMtMS0zLTEtc3RhbmRhcmQtNi0wLTApLgoKCiMjIFNldCBVcAoKVG8gc3RhcnQsIHdlIHdpbGwgbG9hZCBzb21lIG9mIHRoZSBsaWJyYXJpZXMgd2Ugd2lsbCBuZWVkIGxhdGVyLCBhbmQgc2V0IGEgcmFuZG9tIG51bWJlciBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkuCgpgYGB7ciBzZXR1cH0KIyBMb2FkIGxpYnJhcmllcwoKIyBQbG90dGluZyBmdW5jdGlvbnMKbGlicmFyeShnZ3Bsb3QyKQoKIyBUaGUgbWFpbiBjbGFzcyB3ZSB3aWxsIHVzZSBmb3IgU2luZ2xlIENlbGwgZGF0YQpsaWJyYXJ5KFNpbmdsZUNlbGxFeHBlcmltZW50KQoKIyBTZXR0aW5nIHRoZSBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkKc2V0LnNlZWQoMTIzNDUpCmBgYAoKIyMjIERpcmVjdG9yaWVzIGFuZCBmaWxlcwoKQmVmb3JlIHdlIGdldCB0b28gZmFyLCB3ZSBsaWtlIHRvIGRlZmluZSB0aGUgaW5wdXQgYW5kIG91dHB1dCBmaWxlcyB0aGF0IHRoZSBub3RlYm9vayB3aWxsIHVzZSBuZWFyIHRoZSB0b3Agb2YgdGhlIGRvY3VtZW50LgpXaGlsZSB5b3UgbWlnaHQgbm90IGtub3cgdGhlIG5hbWVzIG9mIGFsbCBvZiB0aGUgZmlsZXMgeW91IHdpbGwgbmVlZCBvciBjcmVhdGUgb3V0cHV0IGZpbGVzIHdoZW4geW91IHN0YXJ0IGFuIGFuYWx5c2lzLCB3ZSBoYXZlIGZvdW5kIGl0IGhlbHBmdWwgdG8ga2VlcCBhbGwgZmlsZSBhbmQgZGlyZWN0b3J5IG5hbWVzIGluIGEgc2luZ2xlIHBsYWNlIG5lYXIgdGhlIHRvcCBvZiB0aGUgZG9jdW1lbnQuClRoaXMgbWFrZXMgaXQgZWFzaWVyIGZvciBzb21lYm9keSBjb21pbmcgdG8gdGhlIGNvZGUgbGF0ZXIgdG8gcXVpY2tseSBzZWUgd2hhdCBmaWxlcyBhcmUgbmVlZGVkIGFzIGlucHV0IGFuZCB3aGF0IHdpbGwgYmUgcHJvZHVjZWQgYXMgb3V0cHV0LgpNb3JlIG9mdGVuIHRoYW4gbm90LCB0aGF0IHNvbWVib2R5IGlzIHlvdSEKClRoZSBnZW5lIGV4cHJlc3Npb24gZGF0YSB3ZXJlIHByb2Nlc3NlZCB0byBjcmVhdGUgYSBnZW5lLWJ5LWNlbGwgZXhwcmVzc2lvbiBtYXRyaXggb2YgY291bnRzIGZvciB1c2luZyBDZWxsIFJhbmdlciA2LjAuCldlIGhhdmUgcHJvdmlkZWQgdGhlIHJhdyBkYXRhIGRpcmVjdG9yeSwgYHJhd19mZWF0dXJlX2JjX21hdHJpeGAsIHdoaWNoIGlzIHVzdWFsbHkgcHJvZHVjZWQgYnkgQ2VsbCBSYW5nZXIgYW5kIHBsYWNlZCBpbiBpdHMgYG91dHNgIGRpcmVjdG9yeS4KVGhpcyBkaXJlY3RvcnkgdXN1YWxseSBjb250YWlucyB0aHJlZSBmaWxlczoKLSBgYmFyY29kZXMudHN2Lmd6YCwgYSB0YWJsZSBvZiB0aGUgY2VsbCBiYXJjb2RlcyB0aGF0IDEweCB1c2VzLCBjb3JyZXNwb25kaW5nIHRvIHRoZSBjb2x1bW5zIG9mIHRoZSBjb3VudCBtYXRyaXguCi0gYGZlYXR1cmVzLnRzdi5nemAsIGEgdGFibGUgb2YgdGhlIGZlYXR1cmVzIChnZW5lcyBpbiB0aGlzIGNhc2UpIGZvciB3aGljaCBleHByZXNzaW9uIHdhcyBxdWFudGlmaWVkLgpUaGlzIHdpbGwgdXN1YWxseSBhbHNvIGluY2x1ZGUgYSBiaXQgb2YgbWV0YWRhdGEgYWJvdXQgdGhlIGZlYXR1cmVzLCBpbmNsdWRpbmcgZ2VuZSBzeW1ib2xzIChpZiB0aGUgZmVhdHVyZXMgYXJlIGdlbmVzKSBhbmQgdGhlIHR5cGUgb2YgZGF0YSB0aGV5IHJlcHJlc2VudCAoZS5nLiwgZ2VuZSBleHByZXNzaW9uIG9yIGFudGlib2R5IGNhcHR1cmUpLgotIGBtYXRyaXgubXR4Lmd6YCwgVGhlIGNvdW50cyB0aGVtc2VsdmVzLCBzdG9yZWQgaW4gYSBzcGFyc2UgWyJNYXRyaXggRXhjaGFuZ2UiIGZvcm1hdF0oaHR0cHM6Ly9tYXRoLm5pc3QuZ292L01hdHJpeE1hcmtldC9mb3JtYXRzLmh0bWwpLgoKQ2VsbCBSYW5nZXIgd2lsbCBhbHNvIGV4cG9ydCB0aGVzZSBkYXRhIGluIGEgc2luZ2xlIGBIREY1YCBmb3JtYXQgZmlsZSB3aXRoIGEgYC5oNWAgZXh0ZW5zaW9uLCB3aGljaCBjYW4gYWxzbyBiZSBpbXBvcnRlZCB3aXRoIHRoZSBzYW1lIGNvbW1hbmRzIHdlIHdpbGwgdXNlIGJlbG93LgpIb3dldmVyLCB3ZSBoYXZlIGZvdW5kIHRoYXQgcHJvY2Vzc2luZyBsYXJnZSBgLmg1YCBmaWxlcyBpcyBvZnRlbiBfbXVjaF8gbGVzcyBlZmZpY2llbnQgaW4gUiwgc28gd2UgcHJlZmVyIHRvIHN0YXJ0IHdpdGggdGhlIG1hdHJpeCBmaWxlcyB3aGVuIHBvc3NpYmxlLgpJbiBwYXJ0aWN1bGFyLCB3ZSB3b3VsZCBub3QgcmVjb21tZW5kIHdvcmtpbmcgd2l0aCBgLmg1YCBmaWxlcyBmb3IgcmF3IGRhdGE7IHRoZSBmaWx0ZXJpbmcgc3RlcHMgd2Ugd2lsbCB1c2UgYmVsb3cgY2FuIHNvbWV0aW1lcyB0YWtlIGhvdXJzIHdoZW4gdXNpbmcgdGhvc2UgZmlsZXMgYXMgaW5wdXQuCgpXZSB3aWxsIGFsc28gbmVlZCBhIHRhYmxlIG9mIG1pdG9jaG9uZHJpYWwgZ2VuZXMsIHdoaWNoIHdlIGhhdmUgc3RvcmVkIGluIHRoZSBgZGF0YS9yZWZlcmVuY2UvYCBkaXJlY3RvcnkuCgpGaW5hbGx5LCB3ZSB3aWxsIHNldCB1cCB0aGUgb3VyIG91dHB1dCBkaXJlY3RvcnksIGNyZWF0aW5nIGl0IGlmIGl0IGRvZXMgbm90IHlldCBleGlzdCwgYW5kIGRlZmluZSB0aGUgbmFtZSBmb3IgdGhlIGZpbGVzIHdlIHdpbGwgc2F2ZSBhZnRlciBhbGwgb2Ygb3VyIGluaXRpYWwgcHJvY2Vzc2luZyBpcyBjb21wbGV0ZS4KCmBgYHtyIGlucHV0cywgbGl2ZT1UUlVFfQojIElucHV0cyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIG1haW4gZGF0YSBkaXJlY3RvcnkKZGF0YV9kaXIgPC0gZmlsZS5wYXRoKCJkYXRhIiwgImdsaW9ibGFzdG9tYS0xMHgiKQoKIyBQYXRoIHRvIHRoZSBDZWxsIFJhbmdlciBtYXRyaXggZmlsZQpyYXdfbWF0cml4X2RpciA8LSBmaWxlLnBhdGgoZGF0YV9kaXIsICJyYXdfZmVhdHVyZV9iY19tYXRyaXgiKQoKIyByZWZlcmVuY2UgZGF0YSBkaXJlY3RvcnkKcmVmX2RpciA8LSBmaWxlLnBhdGgoImRhdGEiLCAicmVmZXJlbmNlIikKCiMgUGF0aCB0byBtaXRvY2hvbmRyaWFsIGdlbmVzIHRhYmxlCm1pdG9fZmlsZSA8LSBmaWxlLnBhdGgocmVmX2RpciwgImhzX21pdG9jaG9uZHJpYWxfZ2VuZXMudHN2IikKYGBgCgpgYGB7ciBvdXRwdXRzfQojIE91dHB1dHMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIERpcmVjdG9yeSBhbmQgZmlsZSB0byBzYXZlIG91dHB1dApub3JtYWxpemVkX2RpciA8LSBmaWxlLnBhdGgoZGF0YV9kaXIsICJub3JtYWxpemVkIikKCiMgY3JlYXRlIHRoZSBkaXJlY3RvcnkgaWYgaXQgZG9lcyBub3QgZXhpc3QKaWYgKCFkaXIuZXhpc3RzKG5vcm1hbGl6ZWRfZGlyKSkgewogIGRpci5jcmVhdGUobm9ybWFsaXplZF9kaXIsIHJlY3Vyc2l2ZSA9IFRSVUUpCn0KCiMgb3V0cHV0IFJEUyBmaWxlIGZvciBub3JtYWxpemVkIGRhdGEKb3V0cHV0X3NjZV9maWxlIDwtIGZpbGUucGF0aChub3JtYWxpemVkX2RpciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ2xpb2JsYXN0b21hX25vcm1hbGl6ZWRfc2NlLnJkcyIpCmBgYAoKCiMjIFJlYWRpbmcgQ2VsbCBSYW5nZXIgZGF0YQoKIVtTaW5nbGUtY2VsbCByb2FkbWFwOiBQcmVwcm9jZXNzIGFuZCBJbXBvcnRdKGRpYWdyYW1zL3JvYWRtYXBfc2luZ2xlX3ByZXByb2Nlc3MucG5nKQoKV2hldGhlciB0aGUgMTB4IENlbGwgUmFuZ2VyIGRhdGEgaXMgaW4gTWF0cml4IEV4Y2hhbmdlIGZvcm1hdCBvciBpbiBhbiBIREY1IGZpbGUsIHdlIGNhbiB1c2UgdGhlIGByZWFkMTB4Q291bnRzKClgIGZ1bmN0aW9uIGZyb20gdGhlIGBEcm9wbGV0VXRpbHNgIHBhY2thZ2UgdG8gcmVhZCB0aGUgZGF0YSBpbnRvIFIgYW5kIGNyZWF0ZSBhIGBTaW5nbGVDZWxsRXhwZXJpbWVudGAgb2JqZWN0LgooVGhvdWdoIGFnYWluLCB3ZSBkbyBub3QgcmVjb21tZW5kIHVzaW5nIHRoZSBgLmg1YCBmaWxlIGlmIHlvdSBjYW4gYXZvaWQgaXQsIF9lc3BlY2lhbGx5XyBmb3IgcmF3ICh1bmZpbHRlcmVkKSBkYXRhLikKCklmIHlvdSB1c2VkIHNvbWV0aGluZyBvdGhlciB0aGFuIENlbGwgUmFuZ2VyIHRvIHByb2Nlc3MgdGhlIHJhdyBkYXRhLCB5b3Ugd291bGQgbmVlZCB0byB1c2UgYSBkaWZmZXJlbnQgZnVuY3Rpb24gdG8gcmVhZCBpdCBpbiBhbmQgY3JlYXRlIHRoZSBgU2luZ2xlQ2VsbEV4cGVyaW1lbnRgIG9iamVjdC4KU29tZSBvZiB0aGVzZSBmdW5jdGlvbnMgZm9yIG90aGVyIGNvbW1vbiBkYXRhIGZvcm1hdHMgYXJlIGRpc2N1c3NlZCBpbiBbQ2hhcHRlciAzIG9mIE9TQ0FdIChodHRwOi8vYmlvY29uZHVjdG9yLm9yZy9ib29rcy8zLjE2L09TQ0EuaW50cm8vZ2V0dGluZy1zY3JuYS1zZXEtZGF0YXNldHMuaHRtbCNyZWFkaW5nLWNvdW50cy1pbnRvLXIpLgoKYGBge3IgcmVhZCBTQ0UsIGxpdmU9VFJVRX0KIyByZWFkIFNDRSBmcm9tIG1hdHJpeCBkaXJlY3RvcnkKcmF3X3NjZSA8LSBEcm9wbGV0VXRpbHM6OnJlYWQxMHhDb3VudHMocmF3X21hdHJpeF9kaXIpCmBgYAoKTGV0J3MgbG9vayBhdCB0aGUgY29udGVudHMgb2YgdGhlIG9iamVjdCBhZnRlciByZWFkaW5nIGl0IGluOgoKYGBge3IgdmlldyBTQ0UsIGxpdmU9VFJVRX0KIyB2aWV3IFNDRSBvYmplY3QKcmF3X3NjZQpgYGAKCldlIGNhbiBzZWUgZnJvbSB0aGlzIHN1bW1hcnkgdGhhdCB0aGlzIGBTaW5nbGVDZWxsRXhwZXJpbWVudGAgKFNDRSkgb2JqZWN0IGNvbnRhaW5zIDM2LDYwMSByb3dzLCB3aGljaCBjb3JyZXNwb25kIHRvIHRoZSBmZWF0dXJlcyAoZ2VuZXMpIHRoYXQgd2VyZSBhbmFseXplZCwgYW5kIDczNCw0OTIgY29sdW1ucywgd2hpY2ggY29ycmVzcG9uZCB0byB0aGUgcG9zc2libGUgYmFyY29kZSB0YWdzIHRoYXQgd2VyZSB1c2VkIGluIHRoZSBleHBlcmltZW50LgpOb3RlIHRoYXQgbm90IGFsbCBvZiB0aGVzZSBiYXJjb2RlIHRhZ3Mgd2lsbCBoYXZlIGJlZW4gdXNlZCwgYW5kIG1hbnkgb2YgdGhlIGZlYXR1cmVzIG1heSBuZXZlciBoYXZlIGJlZW4gc2VlbiBlaXRoZXIuCk9uZSBvZiBvdXIgZmlyc3Qgc3RlcHMgd2lsbCBiZSB0byBmaWx0ZXIgb3V0IGJhcmNvZGVzIHRoYXQgd2VyZSBuZXZlciBzZWVuLCBvciB0aGF0IG1heSBoYXZlIG9ubHkgYmVlbiBzZWVuIGluIGEgZHJvcGxldCB0aGF0IGRpZCBub3QgY29udGFpbiBhIGNlbGwgKGFuICJlbXB0eSBkcm9wbGV0IikuCgojIyMgU3RydWN0dXJlIG9mIHRoZSBgU2luZ2xlQ2VsbEV4cGVyaW1lbnRgIG9iamVjdAoKSW4gYWRkaXRpb24gdG8gdGhlIG1haW4gYGNvdW50c2AgbWF0cml4LCBsaXN0ZWQgYXMgYW4gYGFzc2F5YCBpbiB0aGUgU0NFIHN1bW1hcnkgYWJvdmUsIHRoZSBTQ0Ugb2JqZWN0IGNhbiBjb250YWluIGEgbnVtYmVyIG9mIG90aGVyIHRhYmxlcyBhbmQgbWF0cmljZXMsIGVhY2ggc3RvcmVkIGluIGEgInNsb3QiIHdpdGggYSBwYXJ0aWN1bGFyIGZvcm1hdC4KVGhlIG92ZXJhbGwgc3RydWN0dXJlIG9mIHRoZSBvYmplY3QgY2FuIGJlIHNlZW4gaW4gdGhlIGZpZ3VyZSBiZWxvdywgd2hpY2ggY29tZXMgZnJvbSBhbiBbT1NDQSBJbnRyb2R1Y3Rpb24gY2hhcHRlcl0oaHR0cDovL2Jpb2NvbmR1Y3Rvci5vcmcvYm9va3MvMy4xNi9PU0NBLmludHJvL3RoZS1zaW5nbGVjZWxsZXhwZXJpbWVudC1jbGFzcy5odG1sKS4KCiFbU3RydWN0dXJlIG9mIGEgU2luZ2xlQ2VsbEV4cGVyaW1lbnQgb2JqZWN0XShkaWFncmFtcy9TaW5nbGVDZWxsRXhwZXJpbWVudC5wbmcpCgpXZSBoYXZlIGp1c3QgbWVudGlvbmVkIHRoZSBtYWluIGBhc3NheWAgc2xvdCwgd2hpY2ggY29udGFpbnMgZnVsbCBtYXRyaWNlcyBvZiBkYXRhIChzdWNoIGFzIHRyYW5zY3JpcHQgY291bnRzKSB3aXRoIGVhY2ggcm93IGEgZmVhdHVyZSBhbmQgZWFjaCBjb2x1bW4gYSBjZWxsLgpUaGVyZSBhcmUgYWxzbyBhIGNvdXBsZSBvZiB0YWJsZXMgZm9yIG1ldGFkYXRhLCBhbmQgYSBzbG90IHRvIHN0b3JlIHJlZHVjZWQtZGltZW5zaW9uIHJlcHJlc2VudGF0aW9ucyAoZS5nLiwgUENBIGFuZC9vciBVTUFQKSBvZiB0aGUgZXhwcmVzc2lvbiBkYXRhLgoKV2UnbGwgc3RhcnQgd2l0aCB0aGUgYHJvd0RhdGFgIHNsb3QsIHdoaWNoIGlzIGEgdGFibGUgb2YgbWV0YWRhdGEgZm9yIGVhY2ggZmVhdHVyZSBpbiBvdXIgb2JqZWN0LgpGb3Igbm93IHRoYXQgY29udGFpbnMgdGhlIGNvbnRlbnRzIG9mIHRoZSBgZmVhdHVyZXMudHN2Lmd6YCBmaWxlIHRoYXQgd2UgZGlzY3Vzc2VkIGVhcmxpZXIuCklmIHdlIGhhZCByZWFkIHRoZSBkYXRhIGZyb20gc29tZXRoaW5nIG90aGVyIHRoYW4gQ2VsbCBSYW5nZXIgb3V0cHV0LCB3ZSBtaWdodCBoYXZlIGRpZmZlcmVudCBjb250ZW50cywgYnV0IGVhY2ggcm93IHdvdWxkIHN0aWxsIGNvcnJlc3BvbmQgdG8gYSBzaW5nbGUgZmVhdHVyZSBvZiB0aGUgU0NFIG9iamVjdC4KCkxldCdzIGxvb2sgYXQgdGhpcyB0YWJsZSwgZXh0cmFjdGluZyBpdCBmcm9tIHRoZSBTQ0Ugb2JqZWN0IHdpdGggdGhlIGByb3dEYXRhKClgIGZ1bmN0aW9uIGFuZCB1c2luZyBgaGVhZCgpYCB0byB2aWV3IG9ubHkgdGhlIGZpcnN0IDYgcm93cy4KCmBgYHtyIHJvd2RhdGF9CiMgdmlldyByb3dEYXRhIChmZWF0dXJlcykKaGVhZChyb3dEYXRhKHJhd19zY2UpKQpgYGAKCllvdSBjYW4gc2VlIHRoYXQgdGhpcyB0YWJsZSBpbmNsdWRlcyBhbiBgSURgIGZvciBlYWNoIGZlYXR1cmUsIHdoaWNoIGlzIHVzdWFsbHkgdGhlIEVuc2VtYmwgZ2VuZSBJRCwgYXMgd2VsbCBhcyB0aGUgY29ycmVzcG9uZGluZyBnZW5lIHN5bWJvbCBpbiB0aGUgYFN5bWJvbGAgY29sdW1uLgpGaW5hbGx5IHRoZXJlIGlzIGEgY29sdW1uIGZvciBgVHlwZWAsIHdoaWNoIGluIHRoaXMgY2FzZSBpcyBhbHdheXMgIkdlbmUgRXhwcmVzc2lvbiIsIGFzIGFsbCBvZiB0aGUgZmVhdHVyZXMgaW4gdGhpcyBkYXRhIHNldCBhcmUgZ2VuZXMuCklmIHRoZXJlIHdlcmUgYW5vdGhlciBtb2RhbGl0eSBvZiBkYXRhIHRoYXQgaGFkIGJlZW4gYXNzYXllZCBpbiB0aGlzIGV4cGVyaW1lbnQsIHRoZXJlIG1pZ2h0IGJlIG90aGVyIHZhbHVlcyBpbiB0aGlzIGNvbHVtbiwgc3VjaCBhcyAiQW50aWJvZHkgQ2FwdHVyZSIgZm9yIENJVEUtc2VxIGV4cGVyaW1lbnRzLgoKVGhlIHNlY29uZCBzbG90IGlzIHRoZSBgY29sRGF0YWAgdGFibGUsIHdoaWNoIG5vdyBjb3JyZXNwb25kcyB0byB0aGUgYGJhcmNvZGVzLnRzdi5nemAgZmlsZSwgY29udGFpbmluZyBvbmUgcm93IHBlciBjZWxsIGJhcmNvZGUsIG9yLCBtb3JlIGdlbmVyYWxseSwgb25lIHJvdyBwZXIgY29sdW1uIG9mIHRoZSBgY291bnRzYCBhc3NheS4KV2UgY2FuIGxvb2sgYXQgdGhpcyB0YWJsZSB1c2luZyB0aGUgYGNvbERhdGEoKWAgZnVuY3Rpb24gKGFuZCBgaGVhZCgpYCBhZ2FpbiB0byBwcmV2ZW50IHByaW50aW5nIHRoZSB3aG9sZSB0YWJsZSk6CgpgYGB7ciBjb2xkYXRhfQojIHZpZXcgY29sRGF0YSAoY2VsbCBiYXJjb2RlcykKaGVhZChjb2xEYXRhKHJhd19zY2UpKQpgYGAKCkhlcmUgd2Ugc2VlIHRoYXQgdGhlcmUgYXJlIGN1cnJlbnRseSB0d28gY29sdW1uczoKCi0gdGhlIGBTYW1wbGVgIGNvbHVtbiBoYXMgdGhlIHBhdGggb2YgdGhlIGZpbGUgdGhhdCB3ZSByZWFkIGluICh5b3UgbWF5IG5vdCBzZWUgdGhlIHdob2xlIHBhdGggaW4gdGhpcyBkaXNwbGF5KTsgdGhpcyBzaG91bGQgYmUgaWRlbnRpY2FsIGluIGFsbCByb3dzIGZyb20gYSBzaW5nbGUgc2FtcGxlLgotIHRoZSBgQmFyY29kZWAgY29sdW1uIGNvbnRhaW5zIHRoZSBzZXF1ZW5jZSB0aGF0IHdhcyB1c2VkIHRvIGlkZW50aWZ5IGVhY2ggcG90ZW50aWFsIGRyb3BsZXQgZm9yIHNlcXVlbmNpbmcgKGFuZCBhIG51bWVyaWMgdGFnLCBpbiB0aGlzIGNhc2UpLgpUaGVzZSB3aWxsIGJlIHVuaXF1ZSB3aXRoaW4gYSBzYW1wbGUuCgpBcyB3ZSBwcm9jZWVkIHRvIGNhbGN1bGF0ZSBwZXItY2VsbCBzdGF0aXN0aWNzLCB3ZSB3aWxsIGJlIGFkZGluZyBuZXcgZGF0YSB0byB0aGlzIHRhYmxlLgoKIyMgUXVhbGl0eSBjb250cm9sIGFuZCBmaWx0ZXJpbmcKCiFbU2luZ2xlLWNlbGwgcm9hZG1hcDogUUMsIEZpbHRlciwgYW5kIE5vcm1hbGl6ZV0oZGlhZ3JhbXMvcm9hZG1hcF9zaW5nbGVfcWNfbm9ybS5wbmcpCgojIyMgRmlsdGVyaW5nIGVtcHR5IGRyb3BsZXRzCgpNb3N0IG9mIHRoZSBiYXJjb2RlcyBpbiBhbnkgZ2l2ZW4gMTB4IGV4cGVyaW1lbnQgd2lsbCBub3QgYmUgc2VlbiBhdCBhbGwsIHNvIG91ciBmaXJzdCBzdGVwIGNhbiBiZSB0byBmaWx0ZXIgdGhpcyByYXcgZGF0YSB0byBvbmx5IHRoZSBjZWxscyB3aGVyZSB0aGVyZSBpcyBhdCBsZWFzdCBvbmUgdHJhbnNjcmlwdCB0aGF0IHdhcyBjb3VudGVkIHdpdGggdGhhdCBiYXJjb2RlLgoKVG8gZG8gdGhpcywgd2Ugd2lsbCB1c2UgdGhlIGBjb2xTdW1zKClgIGZ1bmN0aW9uIHRvIHF1aWNrbHkgYWRkIHVwIGFsbCB0aGUgY291bnRzIHRoYXQgY29ycmVzcG9uZCB0byBlYWNoIHBvc3NpYmxlIGNlbGwgYmFyY29kZSwgdGhlbiBmaWx0ZXIgb3VyIGByYXdfc2NlYCBkb3duIHRvIGp1c3QgdGhvc2UgY29sdW1ucyB3aGVyZSB0aGVyZSBhcmUgbm9uLXplcm8gdG90YWwgY291bnRzLgpXZSB3aWxsIG5lZWQgdG8gZXh0cmFjdCB0aGUgYGNvdW50c2AgbWF0cml4IGZyb20gb3VyIFNDRSBvYmplY3QsIHdoaWNoIHdlIGNhbiBkbyB1c2luZyB0aGUgYGNvdW50cygpYCBmdW5jdGlvbiwgY29udmVuaWVudGx5IGVub3VnaC4KCmBgYHtyIHJlbW92ZSB6ZXJvcywgbGl2ZT1UUlVFfQojIHN1bSBjb2x1bW5zIGZyb20gY291bnRzIG1hdHJpeApiYXJjb2RlX2NvdW50cyA8LSBjb2xTdW1zKGNvdW50cyhyYXdfc2NlKSkKCiMgZmlsdGVyIFNDRSBvYmplY3QgdG8gb25seSByb3dzIHdpdGggY291bnRzID4gMApyYXdfc2NlIDwtIHJhd19zY2VbLCB3aGljaChiYXJjb2RlX2NvdW50cyA+IDApXQpgYGAKCk5vdyB3ZSBjYW4gbG9vayBhdCBob3cgb3VyIFNDRSBvYmplY3QgaGFzIGNoYW5nZWQ6CgpgYGB7ciB6ZXJvLWZpbHRlcmVkIFNDRX0KcmF3X3NjZQpgYGAKCkJ1dCBiYXJjb2RlcyB3aXRoIHplcm8gY291bnRzIGFyZSBub3QgdGhlIG9ubHkgb25lcyB0aGF0IGNvcnJlc3BvbmQgdG8gZHJvcGxldHMgd2l0aG91dCBjZWxscyBpbiB0aGVtIQpFdmVuIGlmIGEgZHJvcGxldCBkb2VzIG5vdCBoYXZlIGEgY2VsbCBpbiBpdCwgdGhlcmUgd2lsbCBvZnRlbiBiZSBzcHVyaW91cyByZWFkcyBmcm9tIFJOQSBzZXF1ZW5jZXMgdGhhdCB3ZXJlIHByZXNlbnQgaW4gdGhlIGV4dHJhY2VsbHVsYXIgc29sdXRpb24sIHdoZXRoZXIgZnJvbSB0aGUgb3JpZ2luYWwgc2FtcGxlIG9yIGZyb20gY2VsbHMgdGhhdCB3ZXJlIGRhbWFnZWQgZHVyaW5nIHNpbmdsZS1jZWxsIGxpYnJhcnkgcHJlcGFyYXRpb24uCgpXZSBjb3VsZCBpZGVudGlmeSB0aGVzZSBiYXJjb2RlcyBzaW1wbHkgYXMgdGhvc2Ugd2l0aCBsb3cgdHJhbnNjcmlwdCBjb3VudHMuCk9yLCB3ZSBjYW4gYmUgYSBiaXQgbW9yZSBjbGV2ZXIhCldlIGNhbiBsb29rIGF0IHRoZSB0cmFuc2NyaXB0IGNvdW50cyBfZnJvbV8gdGhlIGxvd2VzdC1jb3VudCBkcm9wbGV0cyB0byBjcmVhdGUgYW4gZXhwZWN0ZWQgZGlzdHJpYnV0aW9uIG9mIHRyYW5zY3JpcHRzIGluIGRyb3BsZXRzIHRoYXQgZG9uJ3QgY29udGFpbiBjZWxscy4KVGhlbiB3ZSBjYW4gdGVzdCBlYWNoIGRyb3BsZXQgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgb3Igbm90IGl0cyB0cmFuc2NyaXB0IGRpc3RyaWJ1dGlvbiBkZXZpYXRlcyBmcm9tIHRoYXQgZXhwZWN0YXRpb24uCklmIGl0IGRvZXMsIHRoZW4gd2UgaGF2ZSBwcmV0dHkgZ29vZCBldmlkZW5jZSB0aGF0IHRoZXJlIF9pc18gYSBjZWxsIGluIHRoZXJlLgoKVGhpcyB0ZXN0IHdhcyBmaXJzdCBwcm9wb3NlZCBieSBbTHVuIF9ldCBhbC5fICgyMDE5KV0oaHR0cHM6Ly9kb2kub3JnLzEwLjExODYvczEzMDU5LTAxOS0xNjYyLXkpIGFuZCBpbXBsZW1lbnRlZCBhcyBgZW1wdHlEcm9wcygpYCBpbiB0aGUgYERyb3BsZXRVdGlsc2AgcGFja2FnZS4KVGhpcyBtZXRob2Qgd2FzIHRoZW4gYWRvcHRlZCwgd2l0aCBzb21lIG1vZGlmaWNhdGlvbnMsIGFzIHRoZSBkZWZhdWx0IGNlbGwgZmlsdGVyaW5nIG1ldGhvZCB1c2VkIGJ5IENlbGwgUmFuZ2VyLgpIZXJlIHdlIHdpbGwgdXNlIHRoZSBbYGVtcHR5RHJvcHNDZWxsUmFuZ2VyKClgIGZ1bmN0aW9uXShodHRwczovL3JkcnIuaW8vZ2l0aHViL01hcmlvbmlMYWIvRHJvcGxldFV0aWxzL21hbi9lbXB0eURyb3BzQ2VsbFJhbmdlci5odG1sKSB0byBwZXJmb3JtIGZpbHRlcmluZyB0aGF0IG1vcmUgY2xvc2VseSBtYXRjaGVzIHRoZSBDZWxsIFJhbmdlciBpbXBsZW1lbnRhdGlvbi4KCgpgYGB7ciBjYWxjdWxhdGUgZHJvcGxldCBzdGF0cywgbGl2ZT1UUlVFfQojIGNyZWF0ZSBhIHRhYmxlIG9mIHN0YXRpc3RpY3MgdXNpbmcgZW1wdHlEcm9wc0NlbGxSYW5nZXIKZHJvcGxldF9kZiA8LSBEcm9wbGV0VXRpbHM6OmVtcHR5RHJvcHNDZWxsUmFuZ2VyKHJhd19zY2UpCmBgYAoKTW9zdCB2YWx1ZXMgaW4gdGhpcyB0YWJsZSBhcmUgYE5BYCwgYmVjYXVzZSBpbmRpdmlkdWFsIHN0YXRpc3RpY3Mgd2VyZSBub3QgY2FsY3VsYXRlZCBmb3IgdGhlIGxvdy1jb3VudCBkcm9wbGV0cyB0aGF0IHdlcmUgdXNlZCB0byBnZW5lcmF0ZSB0aGUgYmFja2dyb3VuZCBkaXN0cmlidXRpb24uCihNb3N0IGRyb3BsZXRzIGRvbid0IGhhdmUgY2VsbHMsIHNvIHRoaXMgbWFrZXMgc29tZSBzZW5zZSEpCgpXZSBjYW4gbG9vayBhdCBqdXN0IHRoZSByb3dzIHdpdGhvdXQgYE5BYCB2YWx1ZXMgYnkgc2VsZWN0ZWQgdGhlIG9uZXMgd2hlcmUgdGhlIEZEUiAod2hpY2ggd2Ugd2lsbCB1c2UgYWdhaW4gc29vbiksIGlzIG5vdCBgTkFgLgoKYGBge3IgZHJvcGxldCBzdGF0c30KIyB2aWV3IHJvd3Mgd2hlcmUgRkRSIGlzIG5vdCBgTkFgCmRyb3BsZXRfZGZbIWlzLm5hKGRyb3BsZXRfZGYkRkRSKSwgXQpgYGAKWW91IHdpbGwgbm90aWNlIHRoYXQgc29tZSBjZWxscyB3aXRoIGhpZ2ggY291bnRzIGFsc28gaGF2ZSBgTkFgIHZhbHVlcyBmb3IgbWFueSBzdGF0aXN0aWNzLgpJbiB0aG9zZSBjYXNlcywgYE5BYCB2YWx1ZXMgYXJlIGFjdHVhbGx5IHByZXNlbnQgX2JlY2F1c2VfIG9mIHRoZSBoaWdoIGNvdW50cyAtIGBlbXB0eURyb3BzQ2VsbFJhbmdlcigpYCBhdXRvbWF0aWNhbGx5IGFzc3VtZWQgY2VsbHMgd2VyZSBwcmVzZW50LCBzbyB0aGV5IHdlcmUgYWxzbyBub3QgdGVzdGVkLgoKTm93IHdlIGNhbiBmaWx0ZXIgb3VyIGByYXdfc2NlYCBvYmplY3QgX2J5IGNvbHVtbl8gdG8gb25seSBrZWVwIHRoZSBjZWxscyB3aXRoIGEgc21hbGwgRkRSOiB0aG9zZSB0aGF0IGFyZSBxdWl0ZSB1bmxpa2VseSB0byBiZSBlbXB0eSBkcm9wbGV0cy4KCmBgYHtyIGZpbHRlciBlbXB0eWRyb3BzLCBsaXZlPVRSVUV9CiMgZmlsdGVyIGRyb3BsZXRzIHVzaW5nIGB3aGljaGAgdG8gcHJldmVudCBOQSB0cm91YmxlCmNlbGxzX3RvX3JldGFpbiA8LSB3aGljaChkcm9wbGV0X2RmJEZEUiA8IDAuMDEpCmZpbHRlcmVkX3NjZSA8LSByYXdfc2NlWywgY2VsbHNfdG9fcmV0YWluXQpgYGAKCkhvdyBtYW55IGNlbGxzIGRvIHdlIGhhdmUgbm93PwoKYGBge3IgZmlsdGVyZWQgc3VtbWFyeX0KZmlsdGVyZWRfc2NlCmBgYAoKIyMjIEFkZGl0aW9uYWwgcXVhbGl0eSBjb250cm9sCgpJbiBhZGRpdGlvbiB0byBmaWx0ZXJpbmcgb3V0IGVtcHR5IGRyb3BsZXRzLCB3ZSBhbHNvIHdpbGwgd2FudCB0byBmaWx0ZXIgb3V0IGNlbGxzIHRoYXQgbWF5IGhhdmUgYmVlbiBkYW1hZ2VkIGR1cmluZyBsaWJyYXJ5IHByZXBhcmF0aW9uLgpUaGVzZSB3aWxsIG9mdGVuIGJlIGNoYXJhY3Rlcml6ZWQgYnkgYSBoaWdoIHByb3BvcnRpb24gb2YgbWl0b2Nob25kcmlhbCB0cmFuc2NyaXB0cyBhbmQgYSBzbWFsbGVyIG92ZXJhbGwgbnVtYmVyIG9mIHVuaXF1ZSB0cmFuc2NyaXB0cy4KV2hlbiBhIGNlbGwgcnVwdHVyZXMsIGN5dG9wbGFzbWljIHRyYW5zY3JpcHRzIHdpbGwgbGVhayBvdXQsIGJ1dCBtaXRvY2hvbmRyaWFsIHRyYW5zY3JpcHRzLCBzdGlsbCBwcm90ZWN0ZWQgYnkgdGhlIG1pdG9jaG9uZHJpYWwgbWVtYnJhbmUsIG1heSByZW1haW4uCkFzIGEgY29uc2VxdWVuY2UsIHRoZXJlIHdpbGwgYmUgYW4gb3Zlci1hYnVuZGFuY2Ugb2YgbWl0b2Nob25kcmlhbCByZWFkcywgYW5kIGZld2VyIHVuaXF1ZSB0cmFuc2NyaXB0cyBleHByZXNzZWQuCgpPdXIgZmlyc3Qgc3RlcCB0aGVuLCBpcyBjcmVhdGUgYSB2ZWN0b3Igb2YgdGhlIG1pdG9jaG9uZHJpYWwgZ2VuZXMgdGhhdCBhcmUgcHJlc2VudCBpbiBvdXIgZGF0YXNldC4KVGhlIG1pdG9jaG9uZHJpYWwgZmlsZSB3ZSBkZWZpbmVkIGR1cmluZyBzZXR1cCAoYG1pdG9fZmlsZWApIGlzIGEgVFNWIGZpbGUgY29udGFpbmluZyBhbGwgb2YgdGhlIGh1bWFuIG1pdG9jaG9uZHJpYWwgZ2VuZXMgd2l0aCBhZGRpdGlvbmFsIGFubm90YXRpb24gaW5mb3JtYXRpb24gZm9yIGVhY2ggZ2VuZSwgc3VjaCBhcyB0aGUgZ2VuZSBsb2NhdGlvbiBhbmQgYWx0ZXJuYXRpdmUgbmFtZXMuCihGb3IgbW9yZSBkZXRhaWwgb24gdGhlIHN0ZXBzIHdlIHRvb2sgdG8gY3JlYXRlIHRoaXMgZmlsZSwgeW91IGNhbiBsb29rIGF0IFtvbmUgb2Ygb3VyIHNldHVwIG5vdGVib29rc10oaHR0cHM6Ly9naXRodWIuY29tL0FsZXhzTGVtb25hZGUvdHJhaW5pbmctbW9kdWxlcy9ibG9iL21hc3Rlci9zY1JOQS1zZXEtYWR2YW5jZWQvc2V0dXAvbWl0b19nZW5lX2xpc3RzLlJtZCkpCgpBbGwgd2UgbmVlZCBub3cgaXMgdGhlIGBnZW5lX2lkYCwgYW5kIG9ubHkgZm9yIHRoZSBnZW5lcyB0aGF0IGFyZSBwcmVzZW50IGluIG91ciBTQ0UsIHNvIHdlIHdpbGwgZG8gc29tZSBmaWx0ZXJpbmcgd2l0aCBgZHBseXJgIHRvIHB1bGwgb3V0IGEgdmVjdG9yIHdpdGgganVzdCB0aG9zZSBpZHMuCgpgYGB7ciBnZXQgbWl0b2Nob25kcmlhbCBnZW5lc30KIyByZWFkIGluIGEgdGFibGUgb2YgbWl0b2Nob25kcmlhbCBnZW5lcyBhbmQgZXh0cmFjdCBpZHMKbWl0b19nZW5lcyA8LSByZWFkcjo6cmVhZF90c3YobWl0b19maWxlKSB8PgogICMgZmlsdGVyIHRvIG9ubHkgdGhlIGdlbmVzIHRoYXQgYXJlIGZvdW5kIGluIG91ciBkYXRhc2V0CiAgZHBseXI6OmZpbHRlcihnZW5lX2lkICVpbiUgcm93bmFtZXMoZmlsdGVyZWRfc2NlKSkgfD4KICAjIGNyZWF0ZSBhIHZlY3RvciBmcm9tIHRoZSBnZW5lX2lkIGNvbHVtbgogIGRwbHlyOjpwdWxsKGdlbmVfaWQpCmBgYAoKIyMjIENhbGN1bGF0aW5nIHN1bW1hcnkgUUMgc3RhdGlzdGljcwoKV2UgY2FuIG5vdyB1c2UgdGhlIGBzY3V0dGxlYCBmdW5jdGlvbiBgYWRkUGVyQ2VsbFFDKClgIHRvIGNhbGN1bGF0ZSBzb21lIHN0YXRpc3RpY3MgYmFzZWQgb24gdGhlIGNvdW50cyBtYXRyaXgsIHdoaWNoIHdpbGwgYmUgYWRkZWQgdG8gdGhlIGBjb2xEYXRhYCB0YWJsZS4KCkluIGFkZGl0aW9uIHRvIGNhbGN1bGF0aW5nIHN0YXRpc3RpY3MgbGlrZSB0aGUgdG90YWwgcmVhZCBjb3VudCBmb3IgZWFjaCBjZWxsIGFuZCB0aGUgbnVtYmVyIG9mIHRyYW5zY3JpcHRzIHRoYXQgYXJlIGRldGVjdGVkLCB3ZSBjYW4gYWxzbyBjYWxjdWxhdGUgdGhvc2Ugc3RhdGlzdGljcyBmb3IgZGVmaW5lZCBzdWJzZXRzIG9mIGdlbmVzLgpJbiB0aGlzIGNhc2UsIHdlIHdpbGwgdXNlIG91ciBgbWl0b19nZW5lc2AgdmVjdG9yIHRvIGRlZmluZSBhIHN1YnNldCBjYWxsZWQgYG1pdG9gLgpUaGUgYG1pdG9gIG5hbWUgaXMgaW1wb3J0YW50IGluIHRoYXQgaXQgaXMgdGhlIG5hbWUgdGhhdCB3aWxsIGJlIGV4cGVjdGVkIGJ5IGEgbGF0ZXIgZnVuY3Rpb24uCihXZSBjb3VsZCBkZWZpbmUgbW9yZSBzdWJzZXRzLCBidXQgZm9yIG5vdyB0aGlzIG9uZSB3aWxsIGRvLikKCmBgYHtyIHBlciBjZWxsIFFDLCBsaXZlPVRSVUV9CmZpbHRlcmVkX3NjZSA8LSBzY3V0dGxlOjphZGRQZXJDZWxsUUMoZmlsdGVyZWRfc2NlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YnNldHMgPSBsaXN0KG1pdG8gPSBtaXRvX2dlbmVzKSkKYGBgCgpOb3cgd2UgY2FuIGxvb2sgYXQgdGhlIGNvbERhdGEgdG8gc2VlIHdoYXQgd2FzIGFkZGVkOgoKYGBge3IgdmlldyBjb2xEYXRhIHN0YXRzfQpoZWFkKGNvbERhdGEoZmlsdGVyZWRfc2NlKSkKYGBgCgpXZSBjYW4gYWxzbyBwbG90IHNvbWUgb2YgdGhlc2Ugc3RhdGlzdGljcywgaGVyZSB1c2luZyB0aGUgYHBsb3RNZXRyaWNzKClgIGZ1bmN0aW9uIGZyb20gdGhlIGBtaVFDYCBwYWNrYWdlIHRvIHBsb3QgdGhlIHBlcmNlbnQgb2YgcmVhZHMgdGhhdCBhcmUgbWl0b2Nob25kcmlhbCAodGhlIGBzdWJzZXRzX21pdG9fcGVyY2VudGAgY29sdW1uKSBhZ2FpbnN0IHRoZSBudW1iZXIgb2YgdW5pcXVlIGdlbmVzIGRldGVjdGVkICh0aGUgYGRldGVjdGVkYCBjb2x1bW4pIGZvciBlYWNoIGNlbGwuCgpgYGB7ciBtaVFDIHBsb3RNZXRyaWNzfQojIHVzZSBtaVFDOjpwbG90TWV0cmljcygpCm1pUUM6OnBsb3RNZXRyaWNzKGZpbHRlcmVkX3NjZSkgKyB0aGVtZV9idygpCmBgYAoKV2UgY2FuIHNlZSB0aGF0IHRoZXJlIGlzIGEgcmFuZ2Ugb2YgbWl0b2Nob25kcmlhbCBwZXJjZW50YWdlcywgYW5kIGl0IGRvZXMgYWxzbyBzZWVtIHRoYXQgY2VsbHMgd2l0aCBoaWdoIHBlcmNlbnRhZ2VzIG9mIG1pdG9jaG9uZHJpYWwgZ2VuZXMgZG9uJ3Qgc2VlbSB0byBjb250YWluIHZlcnkgbWFueSB1bmlxdWUgZ2VuZXMuCgpIb3cgZG8gd2UgZmlsdGVyIHdpdGggdGhpcyBpbmZvcm1hdGlvbj8KT25lIG9wdGlvbiBpcyB0byBkZWZpbmUgYSBjdXRvZmYgZm9yIHRoZSBtaXRvY2hvbmRyaWFsIHBlcmNlbnRhZ2UgYWJvdmUgd2hpY2ggd2UgY2FsbCBhIGNlbGwgY29tcHJvbWlzZWQgYW5kIGV4Y2x1ZGUgaXQgZnJvbSBmdXJ0aGVyIGFuYWx5c2lzLgpIb3dldmVyLCBjaG9vc2luZyB0aGF0IGN1dG9mZiBjYW4gYmUgYSBiaXQgZnJhdWdodCwgYXMgdGhlIGV4cGVjdGVkIHBlcmNlbnRhZ2Ugb2YgbWl0b2Nob25kcmlhbCByZWFkcyBjYW4gdmFyeSBkZXBlbmRpbmcgb24gdGhlIGNlbGwgdHlwZSBhbmQgbGlicmFyeSBwcmVwYXJhdGlvbiBtZXRob2RzLgpTbyBpdCBtaWdodCBiZSBuaWNlIHRvIGhhdmUgYSBtZXRob2QgdG8gZGV0ZXJtaW5lIHRoYXQgY3V0b2ZmIGZyb20gdGhlIGRhdGEgaXRzZWxmLgoKIyMjIEZpbHRlcmluZyBjb21wcm9taXNlZCBjZWxscwoKRGV0ZXJtaW5pbmcgbWl0b2Nob25kcmlhbCBjdXRvZmZzIGlzIGV4YWN0bHkgd2hhdCB0aGUgYG1pUUNgIHBhY2thZ2UgZG9lcyAoW0hpcHBlbiBfZXQgYWwuXyAyMDIxXShodHRwczovL2RvaS5vcmcvMTAuMTM3MS9qb3VybmFsLnBjYmkuMTAwOTI5MCkpIQpJbiB0cnV0aCwgaXQgZG9lcyBzb21ldGhpbmcgcG9zc2libHkgZXZlbiBhIGJpdCBiZXR0ZXI6IGl0IGZpdHMgYSBtaXh0dXJlIG1vZGVsIHRvIHRoZSBkYXRhIHRoYXQgY29uc2lzdHMgb2YgZGlzdHJpYnV0aW9ucyBvZiBoZWFsdGh5IGNlbGxzIGFuZCBjb21wcm9taXNlZCBjZWxscy4KVGhlbiB3ZSBjYW4gY2FsY3VsYXRlIHdoZXRoZXIgZWFjaCBjZWxsIGlzIG1vcmUgbGlrZWx5IHRvIGJlbG9uZyB0byB0aGUgaGVhbHRoeSBvciBjb21wcm9taXNlZCBkaXN0cmlidXRpb24uCldlIGNhbiB0aGVuIGV4Y2x1ZGUgdGhlIGNlbGxzIHRoYXQgYXJlIG1vcmUgbGlrZWx5IHRvIGJlIGNvbXByb21pc2VkLgoKVG8gdXNlIGBtaVFDYCwgd2UgZmlyc3QgZml0IGEgbW9kZWwgdG8gdGhlIGRhdGEgaW4gb3VyIFNDRSBvYmplY3Q6CgpgYGB7ciBtaVFDIG1vZGVsLCBsaXZlPVRSVUV9CiMgZml0IHRoZSBtaVFDIG1vZGVsCm1pcWNfbW9kZWwgPC0gbWlRQzo6bWl4dHVyZU1vZGVsKGZpbHRlcmVkX3NjZSkKYGBgCgpOb3cgd2UgY2FuIHBsb3QgdGhlIG1vZGVsIHJlc3VsdHMgdXNpbmcgdGhlIGBwbG90TW9kZWwoKWAgZnVuY3Rpb24gdG8gc2VlIGhvdyBpdCBjb3JyZXNwb25kcyB0byBvdXIgZGF0YS4KV2Ugc2hvdWxkIGV4cGVjdCB0byBzZWUgdHdvIGZpdCBsaW5lczoKCi0gT25lIGxpbmUgd2lsbCBjb3JyZXNwb25kIHRoZSB0aGUgImhlYWx0aHkiIGNlbGxzIGFuZCBzaG91bGQgc2hvdyBsaXR0bGUgdG8gbm8gcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIG51bWJlciBvZiB1bmlxdWUgZ2VuZXMgZGV0ZWN0ZWQgYW5kIHRoZSBtaXRvY2hvbmRyaWFsIHBlcmNlbnRhZ2UuCi0gQnkgY29udHJhc3QsIHRoZSBsaW5lIHRoYXQgY29ycmVzcG9uZHMgdG8gImNvbXByb21pc2VkIiBjZWxscyB3aWxsIHNob3cgYSBuZWdhdGl2ZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgbnVtYmVyIG9mIHVuaXF1ZSBnZW5lcyBkZXRlY3RlZCBhbmQgdGhlIG1pdG9jaG9uZHJpYWwgcGVyY2VudGFnZS4KClRoaXMgcGxvdCB3aWxsIGFsc28gc2hvdywgZm9yIGVhY2ggY2VsbCwgdGhlIHBvc3RlcmlvciBwcm9iYWJpbGl0eSB0aGF0IHRoZSBjZWxsIGlzIGRlcml2ZWQgZnJvbSB0aGUgY29tcHJvbWlzZWQgZGlzdHJpYnV0aW9uOyBhIGhpZ2hlciBzY29yZSBpbmRpY2F0ZXMgdGhhdCBhIGNlbGwgaXMgbW9yZSBsaWtlbHkgdG8gYmUgY29tcHJvbWlzZWQuCgpJdCBpcyBhbHNvIGNyaXRpY2FsIHRvIG5vdGUgdGhhdCB0aGlzIG1vZGVsIGNhbiBfYW5kIGRvZXNfIGZhaWwgYXQgdGltZXMuClBsb3R0aW5nIHRoZSByZXN1bHRzIGFzIHdlIGhhdmUgZG9uZSBoZXJlIGlzIG5vdCBhIHN0ZXAgdG8gc2tpcC4KKipBbHdheXMgbG9vayBhdCB5b3VyIGRhdGEhKioKCmBgYHtyIG1pUUMgcGxvdE1vZGVsLCBsaXZlPVRSVUV9CiMgcGxvdCB0aGUgbWlRQyBtb2RlbAptaVFDOjpwbG90TW9kZWwoZmlsdGVyZWRfc2NlLCBtaXFjX21vZGVsKSArCiAgdGhlbWVfYncoKQpgYGAKCldlIGNhbiBub3cgZmlsdGVyIG91ciBkYXRhIGJhc2VkIG9uIHRoZSBwcm9iYWJpbGl0eSBjb21wcm9taXNlZCBhcyBjYWxjdWxhdGVkIGZyb20gdGhlIG1vZGVsLgpCdXQgYmVmb3JlIHdlIGRvIHRoYXQsIHdlIG1pZ2h0IHdhbnQgdG8gcXVpY2tseSBwbG90IHRvIHNlZSB3aGF0IHdvdWxkIGJlIGZpbHRlcmVkIG91dCB3aXRoIGEgZ2l2ZW4gY3V0b2ZmLCB1c2luZyB0aGUgYHBsb3RGaWx0ZXJpbmcoKWAgZnVuY3Rpb24uClRoZSBkZWZhdWx0IGlzIHRvIGV4Y2x1ZGUgY2VsbHMgdGhhdCBoYXZlIGEgcG9zdGVyaW9yIHByb2JhYmlsaXR5IG9mIDAuNzUgb3IgZ3JlYXRlciBvZiBiZWluZyBjb21wcm9taXNlZC4KV2Ugc3RpY2sgd2l0aCB0aGF0IGRlZmF1bHQsIGJ1dCBmb3IgY2xhcml0eSwgd2Ugd2lsbCBhbHNvIGluY2x1ZGUgaXQgaW4gb3VyIGNvZGUhCgoKYGBge3IgbWlRQyBwbG90RmlsdGVyaW5nfQojIGxvb2sgYXQgbWlRQyBmaWx0ZXJpbmcKbWlRQzo6cGxvdEZpbHRlcmluZyhmaWx0ZXJlZF9zY2UsIG1pcWNfbW9kZWwsCiAgICAgICAgICAgICAgICAgICAgcG9zdGVyaW9yX2N1dG9mZiA9IDAuNzUpICsKICB0aGVtZV9idygpCmBgYAoKSW4gdGhpcyBjYXNlLCB0aGUgbGluZSBiZXR3ZWVuIHRoZSBjZWxscyB0byBiZSBrZXB0IGFuZCB0aG9zZSB0aGF0IHdpbGwgYmUgcmVtb3ZlZCBzZWVtcyB0byBjb3JyZXNwb25kIHRvIGEgbWl0b2Nob25kcmlhbCBwZXJjZW50YWdlIG9mIGFib3V0IDEyLjUlLCBidXQgbm90ZSB0aGF0IHRoaXMgd2lsbCBub3QgYWx3YXlzIGJlIGNvbnN0YW50LgpUaGUgY3V0b2ZmIHBvaW50IGNhbiB2YXJ5IGZvciBkaWZmZXJlbnQgbnVtYmVycyBvZiB1bmlxdWUgZ2VuZXMgd2l0aGluIGEgc2FtcGxlLCBhbmQgaXQgd2lsbCBjZXJ0YWlubHkgdmFyeSBhbW9uZyBzYW1wbGVzIQoKQXQgdGhpcyBwb2ludCwgd2UgY2FuIHBlcmZvcm0gdGhlIGFjdHVhbCBmaWx0ZXJpbmcgdXNpbmcgdGhlIGBmaWx0ZXJDZWxscygpYCBmdW5jdGlvbiwgZ2l2aW5nIHVzIGEgZnVydGhlciBmaWx0ZXJlZCBTQ0Ugb2JqZWN0LgoKYGBge3IgbWlRQyBmaWx0ZXJjZWxscywgbGl2ZT1UUlVFfQojIHBlcmZvcm0gbWlRQyBmaWx0ZXJpbmcKcWNmaWx0ZXJlZF9zY2UgPC0gbWlRQzo6ZmlsdGVyQ2VsbHMoZmlsdGVyZWRfc2NlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbCA9IG1pcWNfbW9kZWwpCmBgYAoKIyMjIyBPbmUgbW9yZSBmaWx0ZXI6IHVuaXF1ZSBnZW5lIGNvdW50CgpXaGlsZSB0aGUgbWlRQyBmaWx0ZXJpbmcgaXMgcHJldHR5IGdvb2QsIHlvdSBtYXkgaGF2ZSBub3RpY2VkIHRoYXQgaXQgc3RpbGwgbGVmdCBzb21lIGNlbGxzIHRoYXQgaGFkIHZlcnkgbG93IG51bWJlcnMgb2YgdW5pcXVlIGdlbmVzLgpXaGlsZSB0aGVzZSBjZWxscyBtYXkgbm90IGJlIGNvbXByb21pc2VkLCB0aGUgaW5mb3JtYXRpb24gZnJvbSB0aGVtIGlzIGFsc28gbm90IGxpa2VseSB0byBiZSB1c2VmdWwsIHNvIHdlIHdpbGwgZmlsdGVyIHRob3NlIGFzIHdlbGwuCldlIHdpbGwgb25seSBrZWVwIGNlbGxzIHRoYXQgaGF2ZSBhdCBsZWFzdCAyMDAgdW5pcXVlIGdlbmVzLgoKYGBge3IgdW5pcXVlIGN1dG9mZiwgbGl2ZT1UUlVFfQojIGZpbHRlciBjZWxscyBieSB1bmlxdWUgZ2VuZSBjb3VudCAoYGRldGVjdGVkYCkKcWNmaWx0ZXJlZF9zY2UgPC0gcWNmaWx0ZXJlZF9zY2VbLCB3aGljaChxY2ZpbHRlcmVkX3NjZSRkZXRlY3RlZCA+PSAyMDApXQpxY2ZpbHRlcmVkX3NjZQpgYGAKCgojIyBOb3JtYWxpemF0aW9uCgpOb3cgdGhhdCB3ZSBoYXZlIGRvbmUgb3VyIGZpbHRlcmluZywgd2UgY2FuIHN0YXJ0IGFuYWx5emluZyB0aGUgZXhwcmVzc2lvbiBjb3VudHMgZm9yIHRoZSByZW1haW5pbmcgY2VsbHMuCgpUaGUgbmV4dCBzdGVwIGF0IHRoaXMgcG9pbnQgaXMgdG8gY29udmVydCB0aGUgcmF3IGNvdW50cyBpbnRvIGEgbWVhc3VyZSB0aGF0IGFjY291bnRzIGZvciBkaWZmZXJlbmNlcyBpbiBzZXF1ZW5jaW5nIGRlcHRoIGJldHdlZW4gY2VsbHMsIGFuZCB0byBjb252ZXJ0IHRoZSBkaXN0cmlidXRpb24gb2YgZXhwcmVzc2lvbiB2YWx1ZXMgZnJvbSB0aGUgc2tld2VkIGRpc3RyaWJ1dGlvbiB3ZSBleHBlY3QgdG8gc2VlIGluIHJhdyBjb3VudHMgdG8gb25lIHRoYXQgaXMgbW9yZSBub3JtYWxseSBkaXN0cmlidXRlZC4KCldlIHdpbGwgZG8gdGhpcyB1c2luZyBmdW5jdGlvbnMgZnJvbSB0aGUgYHNjcmFuYCBhbmQgYHNjdXR0bGVgIHBhY2thZ2VzLgpUaGUgcHJvY2VkdXJlIHdlIHdpbGwgdXNlIGhlcmUgaXMgZGVyaXZlZCBmcm9tIHRoZSBbT1NDQSBjaGFwdGVyIG9uIG5vcm1hbGl6YXRpb25dKGh0dHA6Ly9iaW9jb25kdWN0b3Iub3JnL2Jvb2tzLzMuMTYvT1NDQS5iYXNpYy9ub3JtYWxpemF0aW9uLmh0bWwjbm9ybWFsaXphdGlvbi1ieS1kZWNvbnZvbHV0aW9uKS4KVGhlIGlkZWEgaXMgdGhhdCB0aGUgdmFyeWluZyBleHByZXNzaW9uIHBhdHRlcm5zIHRoYXQgZGlmZmVyZW50IGNlbGwgdHlwZXMgZXhoaWJpdCB3aWxsIGFmZmVjdCB0aGUgc2NhbGluZyBmYWN0b3JzIHRoYXQgd2Ugd291bGQgYXBwbHkuClRvIGFjY291bnQgZm9yIHRoYXQgdmFyaWF0aW9uLCB3ZSBmaXJzdCBkbyBhIHJvdWdoIGNsdXN0ZXJpbmcgb2YgY2VsbHMgYnkgdGhlaXIgZXhwcmVzc2lvbiB3aXRoIGBzY3Jhbjo6cXVpY2tDbHVzdGVyKClgLCB0aGVuIHVzZSB0aGF0IGNsdXN0ZXJpbmcgdG8gY2FsY3VsYXRlIHRoZSBzY2FsaW5nIGZhY3RvciBmb3IgZWFjaCBjZWxsIHdpdGhpbiB0aGUgY2x1c3RlcnMgdXNpbmcgYHNjcmFuOjpjb21wdXRlU3VtRmFjdG9ycygpYC4KRmluYWxseSwgd2UgYXBwbHkgdGhlIHNjYWxpbmcgZmFjdG9yIHRvIHRoZSBleHByZXNzaW9uIHZhbHVlcyBmb3IgZWFjaCBjZWxsIGFuZCBjYWxjdWxhdGUgdGhlIGxvZy1zY2FsZWQgZXhwcmVzc2lvbiB2YWx1ZXMgdXNpbmcgdGhlIGBzY3V0dGxlOjpsb2dOb3JtQ291bnRzKClgIGZ1bmN0aW9uLgoKYGBge3Igbm9ybWFsaXphdGlvbiwgbGl2ZT1UUlVFfQojIFBlcmZvcm0gcm91Z2ggY2x1c3RlcmluZwpxY2x1c3QgPC0gc2NyYW46OnF1aWNrQ2x1c3RlcihxY2ZpbHRlcmVkX3NjZSkKCiMgdXNlIGNsdXN0ZXJzIHRvIGNvbXB1dGUgc2NhbGluZyBmYWN0b3JzIGFuZCBhZGQgdG8gU0NFIG9iamVjdApxY2ZpbHRlcmVkX3NjZSA8LSBzY3Jhbjo6Y29tcHV0ZVN1bUZhY3RvcnMocWNmaWx0ZXJlZF9zY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVycyA9IHFjbHVzdCkKCiMgcGVyZm9ybSBub3JtYWxpemF0aW9uIHVzaW5nIHNjYWxpbmcgZmFjdG9ycwojIGFuZCBzYXZlIGFzIGEgbmV3IFNDRSBvYmplY3QKbm9ybWFsaXplZF9zY2UgPC0gc2N1dHRsZTo6bG9nTm9ybUNvdW50cyhxY2ZpbHRlcmVkX3NjZSkKYGBgCgpUaGlzIGNyZWF0ZXMgYSBuZXcgImFzc2F5IiBpbiB0aGUgYG5vcm1hbGl6ZWRfc2NlYCBvYmplY3QsIGBsb2djb3VudHNgLCB3aGljaCBjb250YWlucyB0aGUgbm9ybWFsaXplZCBjb3VudCB2YWx1ZXMgZm9yIGVhY2ggY2VsbCBhbmQgZ2VuZS4KKFRoZSBkYXRhIGhlcmUgYXJlIG5vdCBfYWN0dWFsbHlfIHRoZSBsb2cgb2YgdGhlIGNvdW50cywgc2luY2Ugd2UgYWxzbyBhcHBsaWVkIHRoZSBzY2FsaW5nIGZhY3RvcnMsIGJ1dCB0aGF0IG5hbWUgaXMgdXNlZCBmb3IgaGlzdG9yaWNhbCByZWFzb25zLikKCkxldCdzIHRha2UgYSBsb29rOgoKYGBge3Igbm9ybWFsaXplZCBzY2V9Cm5vcm1hbGl6ZWRfc2NlCmBgYAoKIyMgRGltZW5zaW9uIHJlZHVjdGlvbgoKIVtTaW5nbGUtY2VsbCByb2FkbWFwOiBEaW1lbnNpb24gcmVkdWN0aW9uXShkaWFncmFtcy9yb2FkbWFwX3NpbmdsZV9kaW1lbnNpb25fcmVkdWN0aW9uLnBuZykKCk5vdyB0aGF0IHdlIGhhdmUgbm9ybWFsaXplZCBleHByZXNzaW9uIHZhbHVlcywgd2Ugd291bGQgbGlrZSB0byBwcm9kdWNlIHNvbWUgcmVkdWNlZC1kaW1lbnNpb24gcmVwcmVzZW50YXRpb25zIG9mIHRoZSBkYXRhLgpUaGVzZSB3aWxsIGFsbG93IHVzIHRvIHBlcmZvcm0gc29tZSBkb3duc3RyZWFtIGNhbGN1bGF0aW9ucyBtb3JlIHF1aWNrbHksIHJlZHVjZSBzb21lIG9mIHRoZSBub2lzZSBpbiB0aGUgZGF0YSwgYW5kIGFsbG93IHVzIHRvIHZpc3VhbGl6ZSBvdmVyYWxsIHJlbGF0aW9uc2hpcHMgYW1vbmcgY2VsbHMgbW9yZSBlYXNpbHkgKHRob3VnaCB3aXRoIG1hbnkgY2F2ZWF0cyEpLgoKIyMjIFNlbGVjdGluZyBoaWdobHkgdmFyaWFibGUgZ2VuZXMKCldoaWxlIHdlIGNvdWxkIGNhbGN1bGF0ZSB0aGUgcmVkdWNlZCBkaW1lbnNpb25zIHVzaW5nIGFsbCBvZiB0aGUgZ2VuZXMgdGhhdCB3ZSBoYXZlIGFzc2F5ZWQsIGluIHByYWN0aWNlIG1vc3Qgb2YgdGhlIGdlbmVzIHdpbGwgaGF2ZSB2ZXJ5IGxpdHRsZSB2YXJpYXRpb24gaW4gZXhwcmVzc2lvbiwgc28gZG9pbmcgc28gd2lsbCBub3QgcHJvdmlkZSBtdWNoIGFkZGl0aW9uYWwgc2lnbmFsLgpSZWR1Y2luZyB0aGUgbnVtYmVyIG9mIGdlbmVzIHdlIGluY2x1ZGUgd2lsbCBhbHNvIHNwZWVkIHVwIHNvbWUgb2YgdGhlIGNhbGN1bGF0aW9ucy4KClRvIGlkZW50aWZ5IHRoZSBtb3N0IHZhcmlhYmxlIGdlbmVzLCB3ZSB3aWxsIHVzZSBmdW5jdGlvbnMgZnJvbSB0aGUgYHNjcmFuYCBwYWNrYWdlLgpUaGUgZmlyc3QgZnVuY3Rpb24sIGBtb2RlbEdlbmVWYXIoKWAsIGF0dGVtcHRzIHRvIGRpdmlkZSB0aGUgdmFyaWF0aW9uIG9ic2VydmVkIGZvciBlYWNoIGdlbmUgaW50byBhIGJpb2xvZ2ljYWwgYW5kIHRlY2huaWNhbCBjb21wb25lbnQsIHdpdGggdGhlIGludHVpdGlvbiB0aGF0IGdlbmVzIHdpdGggbG93ZXIgbWVhbiBleHByZXNzaW9uIHRlbmQgdG8gaGF2ZSBsb3dlciB2YXJpYW5jZSBmb3IgcHVyZWx5IHRlY2huaWNhbCByZWFzb25zLgpXZSB0aGVuIHByb3ZpZGUgdGhlIGBtb2RlbEdlbmVWYXIoKWAgb3V0cHV0IHRvIHRoZSBgZ2V0VG9wSFZHcygpYCBmdW5jdGlvbiB0byBpZGVudGlmeSB0aGUgZ2VuZXMgd2l0aCB0aGUgaGlnaGVzdCBfYmlvbG9naWNhbF8gdmFyaWF0aW9uLCB3aGljaCBpcyB3aGF0IHdlIGFyZSBtb3N0IGludGVyZXN0ZWQgaW4uCgpgYGB7ciBzZWxlY3QgSFZHc30KIyBpZGVudGlmeSAyMDAwIGdlbmVzCm51bV9nZW5lcyA8LSAyMDAwCgojIG1vZGVsIHZhcmlhbmNlLCBwYXJ0aXRpb25pbmcgaW50byBiaW9sb2dpY2FsIGFuZCB0ZWNobmljYWwgdmFyaWF0aW9uCmdlbmVfdmFyaWFuY2UgPC0gc2NyYW46Om1vZGVsR2VuZVZhcihub3JtYWxpemVkX3NjZSkKCiMgZ2V0IHRoZSBtb3N0IHZhcmlhYmxlIGdlbmVzCmh2X2dlbmVzIDwtIHNjcmFuOjpnZXRUb3BIVkdzKGdlbmVfdmFyaWFuY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4gPSBudW1fZ2VuZXMpCmBgYAoKVGhlIHJlc3VsdCBpcyBhIHZlY3RvciBvZiBnZW5lIGlkcyAob3JkZXJlZCBmcm9tIG1vc3QgdG8gbGVhc3QgdmFyaWFibGUpOgoKYGBge3IgdmlldyBIVkdzfQpoZWFkKGh2X2dlbmVzKQpgYGAKCiMjIyBQcmluY2lwYWwgY29tcG9uZW50cyBhbmFseXNpcwoKTm93IHRoYXQgd2UgaGF2ZSBzZWxlY3RlZCB0aGUgZ2VuZXMgd2Ugd291bGQgbGlrZSB0byB1c2UgZm9yIHRoZSByZWR1Y2VkLWRpbWVuc2lvbiByZXByZXNlbnRhdGlvbnMgb2YgdGhlIGV4cHJlc3Npb24gZGF0YSwgd2UgY2FuIHN0YXJ0IHRvIGNhbGN1bGF0ZSB0aGVtLgpGaXJzdCB3ZSB3aWxsIHVzZSB0aGUgYHNjYXRlcjo6cnVuUENBKClgIGZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSB0aGUgcHJpbmNpcGFsIGNvbXBvbmVudHMgZnJvbSB0aGUgZXhwcmVzc2lvbiBtYXRyaXguClRoaXMgcmVwcmVzZW50YXRpb24gaXMgZmFzdCBhbmQgZmFpcmx5IHJvYnVzdCwgYnV0IHRoZSByZXN1bHQgaXMgc3RpbGwgcXVpdGUgbXVsdGlkaW1lbnNpb25hbC4KV2Ugd2FudCBrZWVwIGEgZmFpciBudW1iZXIgb2YgY29tcG9uZW50cyAoZGltZW5zaW9ucykgaW4gb3JkZXIgdG8gYWNjdXJhdGVseSByZXByZXNlbnQgdGhlIHZhcmlhdGlvbiBpbiB0aGUgZGF0YSwgYnV0IGRvaW5nIHNvIG1lYW5zIHRoYXQgcGxvdHRpbmcgb25seSBhIGZldyBvZiB0aGVzZSBkaW1lbnNpb25zIChpbiAyRCkgaXMgbm90IGxpa2VseSB0byBwcm92aWRlIGEgZnVsbCB2aWV3IG9mIHRoZSBkYXRhLgoKVGhlIGRlZmF1bHQgbnVtYmVyIG9mIGNvbXBvbmVudHMgaXMgNTAsIHdoaWNoIHdlIHdpbGwgc3RpY2sgd2l0aCwgYnV0IGxldCdzIGVudGVyIGl0IG1hbnVhbGx5IGp1c3QgZm9yIHRoZSByZWNvcmQuCgpgYGB7ciBydW5QQ0EsIGxpdmU9VFJVRX0KIyBjYWxjdWxhdGUgYW5kIHNhdmUgUENBIHJlc3VsdHMKbm9ybWFsaXplZF9zY2UgPC0gc2NhdGVyOjpydW5QQ0EoCiAgbm9ybWFsaXplZF9zY2UsCiAgbmNvbXBvbmVudHMgPSA1MCwgIyBob3cgbWFueSBjb21wb25lbnRzIHRvIGtlZXAKICBzdWJzZXRfcm93ID0gaHZfZ2VuZXMgIyB1c2Ugb25seSB0aGUgdmFyaWFibGUgZ2VuZXMgd2UgY2hvc2UKKQpgYGAKClRoZXNlIHJlZHVjZWQtZGltZW5zaW9uIHJlc3VsdHMgd2lsbCBiZSBzdG9yZWQgaW4gYSBgcmVkdWNlZERpbWAgc2xvdCBpbiB0aGUgU0NFIG9iamVjdC4KV2UgY2FuIHNlZSB0aGUgbmFtZXMgb2YgdGhlIGByZWR1Y2VkRGltYHMgdGhhdCB3ZSBoYXZlIGJ5IGxvb2tpbmcgYXQgdGhlIG9iamVjdCBzdW1tYXJ5OgoKYGBge3IgdmlldyByZWR1Y2VkIGRpbWVuc2lvbnN9Cm5vcm1hbGl6ZWRfc2NlCmBgYAoKSWYgd2Ugd2FudCB0byBleHRyYWN0IHRoZSBQQ0EgcmVzdWx0cywgd2UgY2FuIGRvIHRoYXQgd2l0aCB0aGUgYHJlZHVjZWREaW0oKWAgZnVuY3Rpb246Ck5vdGUgdGhhdCBmb3IgdGhlc2UgcmVkdWNlZC1kaW1lbnNpb25hbGl0eSBtYXRyaWNlcywgdGhlIHJvd3MgYXJlIHRoZSBjZWxscyBhbmQgdGhlIGNvbHVtbnMgYXJlIHRoZSBQQyBkaW1lbnNpb25zLgoKYGBge3IgZ2V0UmVkdWNlZERpbX0KIyBleHRyYWN0IHRoZSBQQ0EgbWF0cml4CnBjYV9tYXRyaXggPC0gcmVkdWNlZERpbShub3JtYWxpemVkX3NjZSwgIlBDQSIpCgojIGxvb2sgYXQgdGhlIHNoYXBlIG9mIHRoZSBtYXRyaXgKZGltKHBjYV9tYXRyaXgpCmBgYAoKIyMjIFVNQVAKCkZpbmFsbHksIHdlIHdpbGwgY2FsY3VsYXRlIGEgVU1BUCAoVW5pZm9ybSBNYW5pZm9sZCBBcHByb3hpbWF0aW9uIGFuZCBQcm9qZWN0aW9uKSByZXByZXNlbnRhdGlvbiBvZiBvdXIgZGF0YS4KVGhpcyBpcyBhIG1hY2hpbmUtbGVhcm5pbmctYmFzZWQgbWV0aG9kIHRoYXQgaXMgdXNlZnVsIGZvciBwZXJmb3JtaW5nIGRpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbiBzdWl0YWJsZSBmb3IgdmlzdWFsaXphdGlvbi4KSXQncyBnb2FsIGlzIHRvIHByb3ZpZGUgYSByZXByZXNlbnRhdGlvbiBvZiB0aGUgZGF0YSBpbiB0d28gZGltZW5zaW9ucyAodHlwaWNhbGx5LCBtb3JlIGFyZSBwb3NzaWJsZSkgdGhhdCBwcmVzZXJ2ZXMgYXMgbXVjaCBvZiB0aGUgZGlzdGFuY2UgcmVsYXRpb25zaGlwcyBhbW9uZyBjZWxscyBhcyBwb3NzaWJsZS4KV2hpbGUgdGhpcyBkb2VzIG1ha2UgZm9yIHZpc3VhbGx5IGFwcGVhbGluZyBhbmQgdXNlZnVsIHBsb3RzLCBpdCBpcyBpbXBvcnRhbnQgbm90IHRvIG92ZXJpbnRlcnByZXQgdGhlIHJlc3VsdHMhCkluIHBhcnRpY3VsYXIsIHdoaWxlIHlvdSB3aWxsIG9mdGVuIHNlZSBzb21lIGFwcGFyZW50IGNsdXN0ZXJpbmcgb2YgY2VsbHMgaW4gdGhlIHJlc3VsdGluZyBvdXRwdXQsIHRob3NlIGNsdXN0ZXJzIG1heSBub3QgYmUgcGFydGljdWxhcmx5IHZhbGlkLCBhbmQgdGhlIHNwYWNpbmcgd2l0aGluIG9yIGJldHdlZW4gY2x1c3RlcnMgbWF5IG5vdCByZWZsZWN0IHRydWUgZGlzdGFuY2VzLgoKSW4gbWFueSB3YXlzIHRoaXMgaXMgYW5hbG9nb3VzIHRvIHRoZSBwcm9ibGVtIG9mIHByb2plY3RpbmcgYSBtYXAgb2YgdGhlIGVhcnRoIG9udG8gYSBmbGF0IHN1cmZhY2U7IGFueSBjaG9pY2Ugd2lsbCByZXN1bHQgaW4gc29tZSBkaXN0b3J0aW9ucy4KSG93ZXZlciwgd2l0aCBVTUFQLCB3ZSByYXJlbHkga25vdyBleGFjdGx5IHdoYXQgY2hvaWNlcyB3ZXJlIG1hZGUgYW5kIHdoYXQgZGlzdG9ydGlvbnMgbWlnaHQgaGF2ZSByZXN1bHRlZC4KVGhlIFVNQVAgY29vcmRpbmF0ZXMgdGhlbXNlbHZlcyBzaG91bGQgbmV2ZXIgYmUgdXNlZCBmb3IgZG93bnN0cmVhbSBhbmFseXNpcy4KClNpbmNlIHRoZSBVTUFQIHByb2NlZHVyZSB3b3VsZCBiZSBzbG93IHRvIGNhbGN1bGF0ZSB3aXRoIHRoZSBmdWxsIGRhdGEsIHNvIHRoZSBgcnVuVU1BUCgpYCBmdW5jdGlvbiBmaXJzdCBjYWxjdWxhdGVzIGEgUENBIG1hdHJpeCBhbmQgdGhlbiB1c2VzIF90aGF0XyB0byBjYWxjdWxhdGUgdGhlIFVNQVAuClNpbmNlIHdlIGFscmVhZHkgaGF2ZSBhIFBDQSBtYXRyaXgsIHdlIHdpbGwgdGVsbCB0aGUgZnVuY3Rpb24gdXNlIHRoYXQgaW5zdGVhZCBvZiByZWNhbGN1bGF0aW5nIGl0LgoKYGBge3IgcnVuVU1BUCwgbGl2ZT1UUlVFfQpub3JtYWxpemVkX3NjZSA8LSBzY2F0ZXI6OnJ1blVNQVAobm9ybWFsaXplZF9zY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaW1yZWQgPSAiUENBIikKYGBgCgpBcyBiZWZvcmUsIHdlIGNvdWxkIGV4dHJhY3QgdGhlIFVNQVAgbWF0cml4IGZyb20gb3VyIFNDRSBvYmplY3Qgd2l0aCB0aGUgYHJlZHVjZWREaW0oKWAgZnVuY3Rpb24uCldlIGNhbiBhbHNvIHZpc3VhbGl6ZSB0aGUgVU1BUCByZXN1bHRzIHVzaW5nIHRoZSBgcGxvdFJlZHVjZWREaW0oKWAgZnVuY3Rpb24uCgpgYGB7ciBwbG90UmVkdWNlZERpbSwgbGl2ZT1UUlVFfQojIHBsb3QgdGhlIFVNQVAKc2NhdGVyOjpwbG90UmVkdWNlZERpbShub3JtYWxpemVkX3NjZSwKICAgICAgICAgICAgICAgICAgICAgICAiVU1BUCIsCiAgICAgICAgICAgICAgICAgICAgICAgIyBjb2xvciBieSB0aGUgbW9zdCB2YXJpYWJsZSBnZW5lCiAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyX2J5ID0gaHZfZ2VuZXNbMV0pCmBgYAoKCiMjIFVuc3VwZXJ2aXNlZCBjbHVzdGVyaW5nCgpBcyBhIGZpbmFsIGFuYWx5c2lzIHN0ZXAgYXQgdGhpcyBzdGFnZSwgd2Ugd2lsbCByZXR1cm4gdG8gdGhlIFBDQSByZXN1bHRzIHRvIHBlcmZvcm0gdW5zdXBlcnZpc2VkIGNsdXN0ZXJpbmcuCkhlcmUgd2Ugd2lsbCB1c2UgYSBncmFwaC1iYXNlZCBjbHVzdGVyaW5nIG1ldGhvZCwgd2hpY2ggc3RhcnRzIGJ5IGlkZW50aWZ5aW5nIGNlbGxzIHRoYXQgYXJlIGNsb3NlIHRvZ2V0aGVyIGluIHRoZSBtdWx0aWRpbWVuc2lvbmFsIHNwYWNlLgpJdCB0aGVuIGlkZW50aWZpZXMgImNvbW11bml0aWVzIiBvZiBoaWdobHkgY29ubmVjdGVkIGNlbGxzLCBhbmQgYnJlYWtzIHRoZW0gYXBhcnQgYnkgcmVnaW9ucyBvZiBsb3dlciBjb25uZWN0aW9uLgoKVGhlcmUgYXJlIGEgbnVtYmVyIG9mIGFsZ29yaXRobXMgdGhhdCBjYW4gcGVyZm9ybSB0aGlzIGNsdXN0ZXJpbmcsIGVhY2ggd2l0aCBwYXJhbWV0ZXJzIHRoYXQgY2FuIGFmZmVjdCBob3cgbWFueSBjbHVzdGVycyBhcmUgaWRlbnRpZmllZCBhbmQgd2hpY2ggY2VsbHMgYmVsb25nIHRvIGVhY2ggY2x1c3Rlci4KSXQgaXMgYWxzbyB3b3J0aCBub3RpbmcgdGhhdCB0aGVzZSBjbHVzdGVycyBtYXkgb3IgbWF5IG5vdCBjb3JyZXNwb25kIHRvICJjZWxsIHR5cGVzIiBieSB3aGF0ZXZlciBkZWZpbml0aW9uIHlvdSBtaWdodCBwcmVmZXIgdG8gdXNlLgpJbnRlcnByZXRhdGlvbiBvZiB0aGVzZSBjbHVzdGVycywgb3Igb3RoZXIgbWVhc3VyZXMgb2YgY2VsbCB0eXBlLCBhcmUgc29tZXRoaW5nIHRoYXQgd2lsbCByZXF1aXJlIG1vcmUgY2FyZWZ1bCBhbmQgbGlrZWx5IG1vcmUgY3VzdG9taXplZCBhbmFseXNpcy4KCldlIHdpbGwgcGVyZm9ybSBvdXIgY2x1c3RlcmluZyB1c2luZyB0aGUgYGJsdXN0ZXJgIHBhY2thZ2UsIHdoaWNoIGNhbiBwZXJmb3JtIG1hbnkgZGlmZmVyZW50IHR5cGVzIG9mIGNsdXN0ZXJpbmcuCkFzIG1lbnRpb25lZCBlYXJsaWVyLCB3ZSBhcmUgdXNpbmcgImdyYXBoIiBjbHVzdGVyaW5nLCB3aGljaCB3ZSBkZWZpbmUgdXNpbmcgdGhlIGBOTkdyYXBoUGFyYW0oKWAgZnVuY3Rpb24uCldpdGhpbiB0aGF0IGFyZSBhIG51bWJlciBvZiBmdXJ0aGVyIG9wdGlvbnMsIHN1Y2ggYXMgdGhlIHdlaWdodGluZyB1c2VkIGZvciBidWlsZGluZyB0aGUgbmV0d29yayBncmFwaCBhbmQgdGhlIGFsZ29yaXRobSB1c2VkIGZvciBkaXZpZGluZyB0aGUgZ3JhcGggaW50byBjbHVzdGVycy4KCk1vZGlmeWluZyB0aGVzZSBwYXJhbWV0ZXJzIGNhbiByZXN1bHQgaW4gcXVpdGUgZGlmZmVyZW50IGNsdXN0ZXIgYXNzaWdubWVudHMhCkZvciB0aGUgY2x1c3RlcmluZyBiZWxvdyB3ZSB3aWxsIHVzZSBKYWNjYXJkIHdlaWdodGluZyBhbmQgTG91dmFpbiBjbHVzdGVyaW5nLCB3aGljaCBjb3JyZXNwb25kIG1vcmUgY2xvc2VseSB0byB0aGUgZGVmYXVsdCBtZXRob2RzIHVzZWQgYnkgYFNldXJhdGAgdGhhbiB0aGUgZGVmYXVsdCBwYXJhbWV0ZXJzLgpJdCBpcyBhbHNvIHdvcnRoIG5vdGluZyB0aGF0IHRoZSB0aGUgY2x1c3RlciBhc3NpZ25tZW50cyBhcmUgc29tZXdoYXQgc3RvY2hhc3RpYy4KSW4gcGFydGljdWxhciwgdGhlIG5hbWVzL251bWJlcnMgb2YgdGhlIGNsdXN0ZXJzIGNhbiBiZSBxdWl0ZSBpbmNvbnNpc3RlbnQgYmV0d2VlbiBydW5zIQoKCmBgYHtyIGNsdXN0ZXJpbmcsIGxpdmU9VFJVRX0KIyBwZXJmb3JtIGdyYXBoLWJhc2VkIGNsdXN0ZXJpbmcKbm5fY2x1c3RlcnMgPC0gYmx1c3Rlcjo6Y2x1c3RlclJvd3MoCiAgcGNhX21hdHJpeCwKICBibHVzdGVyOjpOTkdyYXBoUGFyYW0oCiAgICAjIG51bWJlciBvZiBuZWlnaGJvcnMgdG8gdXNlIGluIG5ldHdvcmsgZ3JhcGgKICAgIGsgPSAyMCwKICAgICMgd2VpZ2h0aW5nIHNjaGVtZSBmb3IgYnVpbGRpbmcgdGhlIG5ldHdvcmsgZ3JhcGgKICAgICMgZGVmYXVsdCBpcyAicmFuayIKICAgIHR5cGUgPSAiamFjY2FyZCIsCiAgICAjIGNsdXN0ZXIgZGV0ZWN0aW9uIGFsZ29yaXRobQogICAgIyBkZWZhdWx0IGlzICJ3YWxrdHJhcCIKICAgIGNsdXN0ZXIuZnVuID0gImxvdXZhaW4iCiAgKQopCmBgYAoKV2UgY2FuIHNhdmUgdGhlIGNsdXN0ZXIgYXNzaWdubWVudHMgYmFjayBpbnRvIHRoZSBgY29sRGF0YWAgb2YgdGhlIFNDRSBvYmplY3Qgd2l0aCBhIGxpdHRsZSBzaG9ydGN1dDogdGhlIGAkYCBmb2xsb3dlZCBieSB0aGUgbmFtZSBvZiB0aGUgbmV3IGNvbHVtbiB3ZSB3YW50IHRvIGFkZC4KCmBgYHtyIGFkZCBjbHVzdGVycyB0byBTQ0UsIGxpdmU9VFJVRX0KIyBzYXZlIGNsdXN0ZXJzIHRvIFNDRSBjb2xEYXRhCm5vcm1hbGl6ZWRfc2NlJG5uX2NsdXN0ZXIgPC0gbm5fY2x1c3RlcnMKYGBgCgpOb3cgd2UgY2FuIHBsb3QgdGhlIFVNQVAgYWdhaW4sIHRoaXMgdGltZSBjb2xvcmVkIGJ5IHRoZSBjbHVzdGVyIGFzc2lnbm1lbnRzIHRoYXQgd2UganVzdCBjcmVhdGVkLgpIZXJlIHJhdGhlciB0aGFuIHRoZSBnZW5lcmFsIGBwbG90UmVkdWNlZERpbSgpYCBmdW5jdGlvbiwgd2Ugd2lsbCB1c2UgYHBsb3RVTUFQKClgLCB3aGljaCBpcyBleGFjdGx5IHRoZSBzYW1lLCBleGNlcHQgaXQgYWx3YXlzIHBsb3RzIGZyb20gdGhlIGByZWR1Y2VkRGltYCBzbG90IG5hbWVkIGBVTUFQYCwgc28gd2UgY2FuIHNraXAgdGhhdCBhcmd1bWVudC4KCmBgYHtyIHBsb3QgY2x1c3RlcnMsIGxpdmU9VFJVRX0KIyBwbG90IFVNQVAgd2l0aCBhc3NpZ25lZCBjbHVzdGVycwpzY2F0ZXI6OnBsb3RVTUFQKG5vcm1hbGl6ZWRfc2NlLAogICAgICAgICAgICAgICAgIGNvbG91cl9ieSA9ICJubl9jbHVzdGVyIikKYGBgCgpXaGF0IGRvIHlvdSBzZWUgaW4gdGhlc2UgcmVzdWx0cz8KCldoYXQgd291bGQgeW91IHdhbnQgdG8gZG8gbmV4dD8KCiMjIFNhdmUgU0NFIG9iamVjdCBmb3IgbGF0ZXIKCldlIHdpbGwgbm93IHNhdmUgb3VyIGZpbHRlcmVkIGFuZCBub3JtYWxpemVkIG9iamVjdCwgaW5jbHVkaW5nIHRoZSBkaW1lbnNpb24gcmVkdWN0aW9uIGFuZCBjbHVzdGVyaW5nIHJlc3VsdHMgdG8gYW4gYFJEU2AgZmlsZSwgdXNpbmcgdGhlIGZpbGUgcGF0aCB0aGF0IHdlIGRlZmluZWQgYXQgdGhlIHN0YXJ0IG9mIHRoZSBub3RlYm9vay4KSWYgd2Ugd2VyZSB0byB3YW50IHRvIHJldHVybiB0byB0aGlzIGRhdGEsIHdlIGNvdWxkIGxvYWQgdGhpcyBmaWxlIGRpcmVjdGx5IGludG8gYSBuZXcgUiBzZXNzaW9uIGFuZCBub3QgaGF2ZSB0byByZXBlYXQgdGhlIHByb2Nlc3NpbmcgdGhhdCB3ZSBoYXZlIGRvbmUgdXAgdG8gdGhpcyBwb2ludC4KClRoZSBkYXRhIGluIHRoZXNlIG9iamVjdHMgdGVuZHMgdG8gYmUgcXVpdGUgbGFyZ2UsIGJ1dCB2ZXJ5IGNvbXByZXNzaWJsZS4KVG8gc2F2ZSBzcGFjZSBvbiBkaXNrIChhdCB0aGUgZXhwZW5zZSBvZiB0aW1lKSwgd2Ugd2lsbCBtYWtlIHN1cmUgdGhhdCB0aGUgZGF0YSBpcyBjb21wcmVzc2VkIGludGVybmFsbHkgYmVmb3JlIHdyaXRpbmcgaXQgb3V0IHRvIGEgZmlsZS4KTm90ZSB0aGF0IHRoZSBmaWxlIHdlIHdyaXRlIGlzIHN0aWxsIGdvaW5nIHRvIGJlIGFuIGAucmRzYCBmaWxlIHdpdGggbm8gYWRkaXRpb25hbCBleHRlbnNpb24uCihGdXJ0aGVyIG5vdGU6IFRoZSBiYXNlIFIgZnVuY3Rpb24gYHNhdmVSRFMoKWAgdXNlcyBjb21wcmVzc2lvbiBieSBkZWZhdWx0LCBidXQgdGhlIGB0aWR5dmVyc2VgIGZ1bmN0aW9uIGByZWFkcjo6d3JpdGVfcmRzKClgIGRvZXMgbm90LikKCmBgYHtyIHNhdmUgU0NFLCBsaXZlPVRSVUV9CiMgd3JpdGUgUkRTIGZpbGUgd2l0aCBjb21wcmVzc2lvbgpyZWFkcjo6d3JpdGVfcmRzKG5vcm1hbGl6ZWRfc2NlLCBmaWxlID0gb3V0cHV0X3NjZV9maWxlLCBjb21wcmVzcyA9ICJneiIpCmBgYAoKCiMjIFByaW50IHNlc3Npb24gaW5mbwoKQXMgaXMgb3VyIGhhYml0IGF0IHRoZSBEYXRhIExhYiwgd2Ugd2lsbCBzYXZlIGluZm9ybWF0aW9uIGFib3V0IHRoZSBjb21wdXRpbmcgZW52aXJvbm1lbnQsIHRoZSBwYWNrYWdlcyB3ZSBoYXZlIHVzZWQgaW4gdGhpcyBub3RlYm9vaywgYW5kIHRoZWlyIHZlcnNpb25zIHVzaW5nIHRoZSBgc2Vzc2lvbkluZm8oKWAgY29tbWFuZC4KCmBgYHtyIHNlc3Npb24gaW5mb30Kc2Vzc2lvbkluZm8oKQpgYGAKCg==
+
LS0tCnRpdGxlOiAiUmVhZGluZywgZmlsdGVyaW5nLCBhbmQgbm9ybWFsaXppbmcgc2NSTkEtc2VxIGRhdGEiCmF1dGhvcjogRGF0YSBMYWIgZm9yIEFMU0YKZGF0ZTogMjAyMwpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCi0tLQoKIyMgT2JqZWN0aXZlcwoKVGhpcyBub3RlYm9vayB3aWxsIGRlbW9uc3RyYXRlIGhvdyB0bzoKCi0gUmVhZCBDZWxsIFJhbmdlciBkYXRhIGludG8gUgotIEZpbHRlciB0byBjZWxscyB1c2luZyBgZW1wdHlEcm9wc0NlbGxSYW5nZXIoKWAKLSBDYWxjdWxhdGUgcXVhbGl0eSBjb250cm9sIG1lYXN1cmVzIG9uIHNjUk5BLXNlcSBkYXRhCi0gUmVtb3ZlIGxpa2VseSBjb21wcm9taXNlZCBjZWxscyB3aXRoIGBtaVFDKClgCi0gTm9ybWFsaXplIGV4cHJlc3Npb24gZGF0YSBhY3Jvc3MgY2VsbHMKLSBDYWxjdWxhdGUgYW5kIHBsb3QgcmVkdWNlZCBkaW1lbnNpb24gcmVwcmVzZW50YXRpb25zIG9mIGV4cHJlc3Npb24gZGF0YSAoUENBLCBVTUFQKQoKLS0tCgpJbiB0aGlzIG5vdGVib29rLCB3ZSB3aWxsIHJldmlldyBiYXNpYyBwcm9jZXNzaW5nIGZvciBzaW5nbGUtY2VsbCBSTkEtc2VxIGRhdGEsIHN0YXJ0aW5nIHdpdGggdGhlIG91dHB1dCBmcm9tIENlbGwgUmFuZ2VyLCBhbmQgcHJvY2VlZGluZyB0aHJvdWdoIGZpbHRlcmluZywgcXVhbGl0eSBjb250cm9sLCBub3JtYWxpemF0aW9uLCBhbmQgZGltZW5zaW9uIHJlZHVjdGlvbi4gV2Ugd2lsbCBwZXJmb3JtIHRoZXNlIHRhc2tzIHVzaW5nIHRvb2xzIGZyb20gdGhlIFtCaW9jb25kdWN0b3IgcHJvamVjdF0oaHR0cHM6Ly9iaW9jb25kdWN0b3Iub3JnKSwgaW4gcGFydGljdWxhciBbYFNpbmdsZUNlbGxFeHBlcmltZW50YCBvYmplY3RzXShodHRwczovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvcmVsZWFzZS9iaW9jL2h0bWwvU2luZ2xlQ2VsbEV4cGVyaW1lbnQuaHRtbCkgYW5kIGZ1bmN0aW9ucyB0aGF0IHdvcmsgd2l0aCB0aG9zZSBvYmplY3RzLgpNdWNoIG9mIHRoZSBtYXRlcmlhbCBpbiB0aGlzIG5vdGVib29rIGlzIGRpcmVjdGx5IGluc3BpcmVkIGJ5LCBhbmQgZHJhd3MgaGVhdmlseSBvbiwgbWF0ZXJpYWwgcHJlc2VudGVkIGluIHRoZSBib29rIFtfT3JjaGVzdHJhdGluZyBTaW5nbGUgQ2VsbCBBbmFseXNpcyB3aXRoIEJpb2NvbmR1Y3Rvcl8gKE9TQ0EpXShodHRwOi8vYmlvY29uZHVjdG9yLm9yZy9ib29rcy8zLjE2L09TQ0EvKS4KCiFbU2luZ2xlLWNlbGwgcm9hZG1hcDogT3ZlcnZpZXddKGRpYWdyYW1zL3JvYWRtYXBfc2luZ2xlX292ZXJ2aWV3LnBuZykKClRoZSBkYXRhIHdlIHdpbGwgdXNlIGZvciB0aGlzIG5vdGVib29rIGlzIGRlcml2ZWQgZnJvbSBhIGh1bWFuIGdsaW9ibGFzdG9tYSBzcGVjaW1lbi4KVGhlIHNhbXBsZSB3YXMgcHJvY2Vzc2VkIGJ5IDEweCBHZW5vbWljcyB1c2luZyBhIDMnIFJOQSBraXQgKHYzLjEpLCBzZXF1ZW5jZWQsIGFuZCBxdWFudGlmaWVkIHdpdGggQ2VsbCBSYW5nZXIgNi4wLgpGdXJ0aGVyIGRldGFpbHMgYWJvdXQgdGhlIHNhbXBsZSBhbmQgcHJvY2Vzc2luZyBjYW4gYmUgZm91bmQgb24gdGhlIFsxMHggd2Vic2l0ZV0oaHR0cHM6Ly93d3cuMTB4Z2Vub21pY3MuY29tL3Jlc291cmNlcy9kYXRhc2V0cy8yLWstc29ydGVkLWNlbGxzLWZyb20taHVtYW4tZ2xpb2JsYXN0b21hLW11bHRpZm9ybWUtMy12LTMtMS0zLTEtc3RhbmRhcmQtNi0wLTApLgoKCiMjIFNldCBVcAoKVG8gc3RhcnQsIHdlIHdpbGwgbG9hZCBzb21lIG9mIHRoZSBsaWJyYXJpZXMgd2Ugd2lsbCBuZWVkIGxhdGVyLCBhbmQgc2V0IGEgcmFuZG9tIG51bWJlciBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkuCgpgYGB7ciBzZXR1cH0KIyBMb2FkIGxpYnJhcmllcwoKIyBQbG90dGluZyBmdW5jdGlvbnMKbGlicmFyeShnZ3Bsb3QyKQoKIyBUaGUgbWFpbiBjbGFzcyB3ZSB3aWxsIHVzZSBmb3IgU2luZ2xlIENlbGwgZGF0YQpsaWJyYXJ5KFNpbmdsZUNlbGxFeHBlcmltZW50KQoKIyBTZXR0aW5nIHRoZSBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkKc2V0LnNlZWQoMTIzNDUpCmBgYAoKIyMjIERpcmVjdG9yaWVzIGFuZCBmaWxlcwoKQmVmb3JlIHdlIGdldCB0b28gZmFyLCB3ZSBsaWtlIHRvIGRlZmluZSB0aGUgaW5wdXQgYW5kIG91dHB1dCBmaWxlcyB0aGF0IHRoZSBub3RlYm9vayB3aWxsIHVzZSBuZWFyIHRoZSB0b3Agb2YgdGhlIGRvY3VtZW50LgpXaGlsZSB5b3UgbWlnaHQgbm90IGtub3cgdGhlIG5hbWVzIG9mIGFsbCBvZiB0aGUgZmlsZXMgeW91IHdpbGwgbmVlZCBvciBjcmVhdGUgb3V0cHV0IGZpbGVzIHdoZW4geW91IHN0YXJ0IGFuIGFuYWx5c2lzLCB3ZSBoYXZlIGZvdW5kIGl0IGhlbHBmdWwgdG8ga2VlcCBhbGwgZmlsZSBhbmQgZGlyZWN0b3J5IG5hbWVzIGluIGEgc2luZ2xlIHBsYWNlIG5lYXIgdGhlIHRvcCBvZiB0aGUgZG9jdW1lbnQuClRoaXMgbWFrZXMgaXQgZWFzaWVyIGZvciBzb21lYm9keSBjb21pbmcgdG8gdGhlIGNvZGUgbGF0ZXIgdG8gcXVpY2tseSBzZWUgd2hhdCBmaWxlcyBhcmUgbmVlZGVkIGFzIGlucHV0IGFuZCB3aGF0IHdpbGwgYmUgcHJvZHVjZWQgYXMgb3V0cHV0LgpNb3JlIG9mdGVuIHRoYW4gbm90LCB0aGF0IHNvbWVib2R5IGlzIHlvdSEKClRoZSBnZW5lIGV4cHJlc3Npb24gZGF0YSB3ZXJlIHByb2Nlc3NlZCB0byBjcmVhdGUgYSBnZW5lLWJ5LWNlbGwgZXhwcmVzc2lvbiBtYXRyaXggb2YgY291bnRzIGZvciB1c2luZyBDZWxsIFJhbmdlciA2LjAuCldlIGhhdmUgcHJvdmlkZWQgdGhlIHJhdyBkYXRhIGRpcmVjdG9yeSwgYHJhd19mZWF0dXJlX2JjX21hdHJpeGAsIHdoaWNoIGlzIHVzdWFsbHkgcHJvZHVjZWQgYnkgQ2VsbCBSYW5nZXIgYW5kIHBsYWNlZCBpbiBpdHMgYG91dHNgIGRpcmVjdG9yeS4KVGhpcyBkaXJlY3RvcnkgdXN1YWxseSBjb250YWlucyB0aHJlZSBmaWxlczoKLSBgYmFyY29kZXMudHN2Lmd6YCwgYSB0YWJsZSBvZiB0aGUgY2VsbCBiYXJjb2RlcyB0aGF0IDEweCB1c2VzLCBjb3JyZXNwb25kaW5nIHRvIHRoZSBjb2x1bW5zIG9mIHRoZSBjb3VudCBtYXRyaXguCi0gYGZlYXR1cmVzLnRzdi5nemAsIGEgdGFibGUgb2YgdGhlIGZlYXR1cmVzIChnZW5lcyBpbiB0aGlzIGNhc2UpIGZvciB3aGljaCBleHByZXNzaW9uIHdhcyBxdWFudGlmaWVkLgpUaGlzIHdpbGwgdXN1YWxseSBhbHNvIGluY2x1ZGUgYSBiaXQgb2YgbWV0YWRhdGEgYWJvdXQgdGhlIGZlYXR1cmVzLCBpbmNsdWRpbmcgZ2VuZSBzeW1ib2xzIChpZiB0aGUgZmVhdHVyZXMgYXJlIGdlbmVzKSBhbmQgdGhlIHR5cGUgb2YgZGF0YSB0aGV5IHJlcHJlc2VudCAoZS5nLiwgZ2VuZSBleHByZXNzaW9uIG9yIGFudGlib2R5IGNhcHR1cmUpLgotIGBtYXRyaXgubXR4Lmd6YCwgVGhlIGNvdW50cyB0aGVtc2VsdmVzLCBzdG9yZWQgaW4gYSBzcGFyc2UgWyJNYXRyaXggRXhjaGFuZ2UiIGZvcm1hdF0oaHR0cHM6Ly9tYXRoLm5pc3QuZ292L01hdHJpeE1hcmtldC9mb3JtYXRzLmh0bWwpLgoKQ2VsbCBSYW5nZXIgd2lsbCBhbHNvIGV4cG9ydCB0aGVzZSBkYXRhIGluIGEgc2luZ2xlIGBIREY1YCBmb3JtYXQgZmlsZSB3aXRoIGEgYC5oNWAgZXh0ZW5zaW9uLCB3aGljaCBjYW4gYWxzbyBiZSBpbXBvcnRlZCB3aXRoIHRoZSBzYW1lIGNvbW1hbmRzIHdlIHdpbGwgdXNlIGJlbG93LgpIb3dldmVyLCB3ZSBoYXZlIGZvdW5kIHRoYXQgcHJvY2Vzc2luZyBsYXJnZSBgLmg1YCBmaWxlcyBpcyBvZnRlbiBfbXVjaF8gbGVzcyBlZmZpY2llbnQgaW4gUiwgc28gd2UgcHJlZmVyIHRvIHN0YXJ0IHdpdGggdGhlIG1hdHJpeCBmaWxlcyB3aGVuIHBvc3NpYmxlLgpJbiBwYXJ0aWN1bGFyLCB3ZSB3b3VsZCBub3QgcmVjb21tZW5kIHdvcmtpbmcgd2l0aCBgLmg1YCBmaWxlcyBmb3IgcmF3IGRhdGE7IHRoZSBmaWx0ZXJpbmcgc3RlcHMgd2Ugd2lsbCB1c2UgYmVsb3cgY2FuIHNvbWV0aW1lcyB0YWtlIGhvdXJzIHdoZW4gdXNpbmcgdGhvc2UgZmlsZXMgYXMgaW5wdXQuCgpXZSB3aWxsIGFsc28gbmVlZCBhIHRhYmxlIG9mIG1pdG9jaG9uZHJpYWwgZ2VuZXMsIHdoaWNoIHdlIGhhdmUgc3RvcmVkIGluIHRoZSBgZGF0YS9yZWZlcmVuY2UvYCBkaXJlY3RvcnkuCgpGaW5hbGx5LCB3ZSB3aWxsIHNldCB1cCB0aGUgb3VyIG91dHB1dCBkaXJlY3RvcnksIGNyZWF0aW5nIGl0IGlmIGl0IGRvZXMgbm90IHlldCBleGlzdCwgYW5kIGRlZmluZSB0aGUgbmFtZSBmb3IgdGhlIGZpbGVzIHdlIHdpbGwgc2F2ZSBhZnRlciBhbGwgb2Ygb3VyIGluaXRpYWwgcHJvY2Vzc2luZyBpcyBjb21wbGV0ZS4KCmBgYHtyIGlucHV0cywgbGl2ZT1UUlVFfQojIElucHV0cyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIG1haW4gZGF0YSBkaXJlY3RvcnkKZGF0YV9kaXIgPC0gZmlsZS5wYXRoKCJkYXRhIiwgImdsaW9ibGFzdG9tYS0xMHgiKQoKIyBQYXRoIHRvIHRoZSBDZWxsIFJhbmdlciBtYXRyaXggZmlsZQpyYXdfbWF0cml4X2RpciA8LSBmaWxlLnBhdGgoZGF0YV9kaXIsICJyYXdfZmVhdHVyZV9iY19tYXRyaXgiKQoKIyByZWZlcmVuY2UgZGF0YSBkaXJlY3RvcnkKcmVmX2RpciA8LSBmaWxlLnBhdGgoImRhdGEiLCAicmVmZXJlbmNlIikKCiMgUGF0aCB0byBtaXRvY2hvbmRyaWFsIGdlbmVzIHRhYmxlCm1pdG9fZmlsZSA8LSBmaWxlLnBhdGgocmVmX2RpciwgImhzX21pdG9jaG9uZHJpYWxfZ2VuZXMudHN2IikKYGBgCgpgYGB7ciBvdXRwdXRzfQojIE91dHB1dHMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIERpcmVjdG9yeSBhbmQgZmlsZSB0byBzYXZlIG91dHB1dApub3JtYWxpemVkX2RpciA8LSBmaWxlLnBhdGgoZGF0YV9kaXIsICJub3JtYWxpemVkIikKCiMgY3JlYXRlIHRoZSBkaXJlY3RvcnkgaWYgaXQgZG9lcyBub3QgZXhpc3QKZnM6OmRpcl9jcmVhdGUobm9ybWFsaXplZF9kaXIpCgojIG91dHB1dCBSRFMgZmlsZSBmb3Igbm9ybWFsaXplZCBkYXRhCm91dHB1dF9zY2VfZmlsZSA8LSBmaWxlLnBhdGgobm9ybWFsaXplZF9kaXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdsaW9ibGFzdG9tYV9ub3JtYWxpemVkX3NjZS5yZHMiKQpgYGAKCgojIyBSZWFkaW5nIENlbGwgUmFuZ2VyIGRhdGEKCiFbU2luZ2xlLWNlbGwgcm9hZG1hcDogUHJlcHJvY2VzcyBhbmQgSW1wb3J0XShkaWFncmFtcy9yb2FkbWFwX3NpbmdsZV9wcmVwcm9jZXNzLnBuZykKCldoZXRoZXIgdGhlIDEweCBDZWxsIFJhbmdlciBkYXRhIGlzIGluIE1hdHJpeCBFeGNoYW5nZSBmb3JtYXQgb3IgaW4gYW4gSERGNSBmaWxlLCB3ZSBjYW4gdXNlIHRoZSBgcmVhZDEweENvdW50cygpYCBmdW5jdGlvbiBmcm9tIHRoZSBgRHJvcGxldFV0aWxzYCBwYWNrYWdlIHRvIHJlYWQgdGhlIGRhdGEgaW50byBSIGFuZCBjcmVhdGUgYSBgU2luZ2xlQ2VsbEV4cGVyaW1lbnRgIG9iamVjdC4KKFRob3VnaCBhZ2Fpbiwgd2UgZG8gbm90IHJlY29tbWVuZCB1c2luZyB0aGUgYC5oNWAgZmlsZSBpZiB5b3UgY2FuIGF2b2lkIGl0LCBfZXNwZWNpYWxseV8gZm9yIHJhdyAodW5maWx0ZXJlZCkgZGF0YS4pCgpJZiB5b3UgdXNlZCBzb21ldGhpbmcgb3RoZXIgdGhhbiBDZWxsIFJhbmdlciB0byBwcm9jZXNzIHRoZSByYXcgZGF0YSwgeW91IHdvdWxkIG5lZWQgdG8gdXNlIGEgZGlmZmVyZW50IGZ1bmN0aW9uIHRvIHJlYWQgaXQgaW4gYW5kIGNyZWF0ZSB0aGUgYFNpbmdsZUNlbGxFeHBlcmltZW50YCBvYmplY3QuClNvbWUgb2YgdGhlc2UgZnVuY3Rpb25zIGZvciBvdGhlciBjb21tb24gZGF0YSBmb3JtYXRzIGFyZSBkaXNjdXNzZWQgaW4gW0NoYXB0ZXIgMyBvZiBPU0NBXSAoaHR0cDovL2Jpb2NvbmR1Y3Rvci5vcmcvYm9va3MvMy4xNi9PU0NBLmludHJvL2dldHRpbmctc2NybmEtc2VxLWRhdGFzZXRzLmh0bWwjcmVhZGluZy1jb3VudHMtaW50by1yKS4KCmBgYHtyIHJlYWQgU0NFLCBsaXZlPVRSVUV9CiMgcmVhZCBTQ0UgZnJvbSBtYXRyaXggZGlyZWN0b3J5CnJhd19zY2UgPC0gRHJvcGxldFV0aWxzOjpyZWFkMTB4Q291bnRzKAogIHJhd19tYXRyaXhfZGlyLAogIGNvbC5uYW1lcyA9IFRSVUUgIyBlbnN1cmUgYmFyY29kZXMgYXJlIHNldCBhcyBjb2x1bW4gbmFtZXMgaW4gdGhlIFNDRSBvYmplY3QKKQpgYGAKCkxldCdzIGxvb2sgYXQgdGhlIGNvbnRlbnRzIG9mIHRoZSBvYmplY3QgYWZ0ZXIgcmVhZGluZyBpdCBpbjoKCmBgYHtyIHZpZXcgU0NFLCBsaXZlPVRSVUV9CiMgdmlldyBTQ0Ugb2JqZWN0CnJhd19zY2UKYGBgCgpXZSBjYW4gc2VlIGZyb20gdGhpcyBzdW1tYXJ5IHRoYXQgdGhpcyBgU2luZ2xlQ2VsbEV4cGVyaW1lbnRgIChTQ0UpIG9iamVjdCBjb250YWlucyAzNiw2MDEgcm93cywgd2hpY2ggY29ycmVzcG9uZCB0byB0aGUgZmVhdHVyZXMgKGdlbmVzKSB0aGF0IHdlcmUgYW5hbHl6ZWQsIGFuZCA3MzQsNDkyIGNvbHVtbnMsIHdoaWNoIGNvcnJlc3BvbmQgdG8gdGhlIHBvc3NpYmxlIGJhcmNvZGUgdGFncyB0aGF0IHdlcmUgdXNlZCBpbiB0aGUgZXhwZXJpbWVudC4KTm90ZSB0aGF0IG5vdCBhbGwgb2YgdGhlc2UgYmFyY29kZSB0YWdzIHdpbGwgaGF2ZSBiZWVuIHVzZWQsIGFuZCBtYW55IG9mIHRoZSBmZWF0dXJlcyBtYXkgbmV2ZXIgaGF2ZSBiZWVuIHNlZW4gZWl0aGVyLgpPbmUgb2Ygb3VyIGZpcnN0IHN0ZXBzIHdpbGwgYmUgdG8gZmlsdGVyIG91dCBiYXJjb2RlcyB0aGF0IHdlcmUgbmV2ZXIgc2Vlbiwgb3IgdGhhdCBtYXkgaGF2ZSBvbmx5IGJlZW4gc2VlbiBpbiBhIGRyb3BsZXQgdGhhdCBkaWQgbm90IGNvbnRhaW4gYSBjZWxsIChhbiAiZW1wdHkgZHJvcGxldCIpLgoKIyMjIFN0cnVjdHVyZSBvZiB0aGUgYFNpbmdsZUNlbGxFeHBlcmltZW50YCBvYmplY3QKCkluIGFkZGl0aW9uIHRvIHRoZSBtYWluIGBjb3VudHNgIG1hdHJpeCwgbGlzdGVkIGFzIGFuIGBhc3NheWAgaW4gdGhlIFNDRSBzdW1tYXJ5IGFib3ZlLCB0aGUgU0NFIG9iamVjdCBjYW4gY29udGFpbiBhIG51bWJlciBvZiBvdGhlciB0YWJsZXMgYW5kIG1hdHJpY2VzLCBlYWNoIHN0b3JlZCBpbiBhICJzbG90IiB3aXRoIGEgcGFydGljdWxhciBmb3JtYXQuClRoZSBvdmVyYWxsIHN0cnVjdHVyZSBvZiB0aGUgb2JqZWN0IGNhbiBiZSBzZWVuIGluIHRoZSBmaWd1cmUgYmVsb3csIHdoaWNoIGNvbWVzIGZyb20gYW4gW09TQ0EgSW50cm9kdWN0aW9uIGNoYXB0ZXJdKGh0dHA6Ly9iaW9jb25kdWN0b3Iub3JnL2Jvb2tzLzMuMTYvT1NDQS5pbnRyby90aGUtc2luZ2xlY2VsbGV4cGVyaW1lbnQtY2xhc3MuaHRtbCkuCgohW1N0cnVjdHVyZSBvZiBhIFNpbmdsZUNlbGxFeHBlcmltZW50IG9iamVjdF0oZGlhZ3JhbXMvU2luZ2xlQ2VsbEV4cGVyaW1lbnQucG5nKQoKV2UgaGF2ZSBqdXN0IG1lbnRpb25lZCB0aGUgbWFpbiBgYXNzYXlgIHNsb3QsIHdoaWNoIGNvbnRhaW5zIGZ1bGwgbWF0cmljZXMgb2YgZGF0YSAoc3VjaCBhcyB0cmFuc2NyaXB0IGNvdW50cykgd2l0aCBlYWNoIHJvdyBhIGZlYXR1cmUgYW5kIGVhY2ggY29sdW1uIGEgY2VsbC4KVGhlcmUgYXJlIGFsc28gYSBjb3VwbGUgb2YgdGFibGVzIGZvciBtZXRhZGF0YSwgYW5kIGEgc2xvdCB0byBzdG9yZSByZWR1Y2VkLWRpbWVuc2lvbiByZXByZXNlbnRhdGlvbnMgKGUuZy4sIFBDQSBhbmQvb3IgVU1BUCkgb2YgdGhlIGV4cHJlc3Npb24gZGF0YS4KCldlJ2xsIHN0YXJ0IHdpdGggdGhlIGByb3dEYXRhYCBzbG90LCB3aGljaCBpcyBhIHRhYmxlIG9mIG1ldGFkYXRhIGZvciBlYWNoIGZlYXR1cmUgaW4gb3VyIG9iamVjdC4KRm9yIG5vdyB0aGF0IGNvbnRhaW5zIHRoZSBjb250ZW50cyBvZiB0aGUgYGZlYXR1cmVzLnRzdi5nemAgZmlsZSB0aGF0IHdlIGRpc2N1c3NlZCBlYXJsaWVyLgpJZiB3ZSBoYWQgcmVhZCB0aGUgZGF0YSBmcm9tIHNvbWV0aGluZyBvdGhlciB0aGFuIENlbGwgUmFuZ2VyIG91dHB1dCwgd2UgbWlnaHQgaGF2ZSBkaWZmZXJlbnQgY29udGVudHMsIGJ1dCBlYWNoIHJvdyB3b3VsZCBzdGlsbCBjb3JyZXNwb25kIHRvIGEgc2luZ2xlIGZlYXR1cmUgb2YgdGhlIFNDRSBvYmplY3QuCgpMZXQncyBsb29rIGF0IHRoaXMgdGFibGUsIGV4dHJhY3RpbmcgaXQgZnJvbSB0aGUgU0NFIG9iamVjdCB3aXRoIHRoZSBgcm93RGF0YSgpYCBmdW5jdGlvbiBhbmQgdXNpbmcgYGhlYWQoKWAgdG8gdmlldyBvbmx5IHRoZSBmaXJzdCA2IHJvd3MuCgpgYGB7ciByb3dkYXRhfQojIHZpZXcgcm93RGF0YSAoZmVhdHVyZXMpCmhlYWQocm93RGF0YShyYXdfc2NlKSkKYGBgCgpZb3UgY2FuIHNlZSB0aGF0IHRoaXMgdGFibGUgaW5jbHVkZXMgYW4gYElEYCBmb3IgZWFjaCBmZWF0dXJlLCB3aGljaCBpcyB1c3VhbGx5IHRoZSBFbnNlbWJsIGdlbmUgSUQsIGFzIHdlbGwgYXMgdGhlIGNvcnJlc3BvbmRpbmcgZ2VuZSBzeW1ib2wgaW4gdGhlIGBTeW1ib2xgIGNvbHVtbi4KRmluYWxseSB0aGVyZSBpcyBhIGNvbHVtbiBmb3IgYFR5cGVgLCB3aGljaCBpbiB0aGlzIGNhc2UgaXMgYWx3YXlzICJHZW5lIEV4cHJlc3Npb24iLCBhcyBhbGwgb2YgdGhlIGZlYXR1cmVzIGluIHRoaXMgZGF0YSBzZXQgYXJlIGdlbmVzLgpJZiB0aGVyZSB3ZXJlIGFub3RoZXIgbW9kYWxpdHkgb2YgZGF0YSB0aGF0IGhhZCBiZWVuIGFzc2F5ZWQgaW4gdGhpcyBleHBlcmltZW50LCB0aGVyZSBtaWdodCBiZSBvdGhlciB2YWx1ZXMgaW4gdGhpcyBjb2x1bW4sIHN1Y2ggYXMgIkFudGlib2R5IENhcHR1cmUiIGZvciBDSVRFLXNlcSBleHBlcmltZW50cy4KClRoZSBzZWNvbmQgc2xvdCBpcyB0aGUgYGNvbERhdGFgIHRhYmxlLCB3aGljaCBub3cgY29ycmVzcG9uZHMgdG8gdGhlIGBiYXJjb2Rlcy50c3YuZ3pgIGZpbGUsIGNvbnRhaW5pbmcgb25lIHJvdyBwZXIgY2VsbCBiYXJjb2RlLCBvciwgbW9yZSBnZW5lcmFsbHksIG9uZSByb3cgcGVyIGNvbHVtbiBvZiB0aGUgYGNvdW50c2AgYXNzYXkuCldlIGNhbiBsb29rIGF0IHRoaXMgdGFibGUgdXNpbmcgdGhlIGBjb2xEYXRhKClgIGZ1bmN0aW9uIChhbmQgYGhlYWQoKWAgYWdhaW4gdG8gcHJldmVudCBwcmludGluZyB0aGUgd2hvbGUgdGFibGUpOgoKYGBge3IgY29sZGF0YX0KIyB2aWV3IGNvbERhdGEgKGNlbGwgYmFyY29kZXMpCmhlYWQoY29sRGF0YShyYXdfc2NlKSkKYGBgCgpIZXJlIHdlIHNlZSB0aGF0IHRoZXJlIGFyZSBjdXJyZW50bHkgdHdvIGNvbHVtbnM6CgotIHRoZSBgU2FtcGxlYCBjb2x1bW4gaGFzIHRoZSBwYXRoIG9mIHRoZSBmaWxlIHRoYXQgd2UgcmVhZCBpbiAoeW91IG1heSBub3Qgc2VlIHRoZSB3aG9sZSBwYXRoIGluIHRoaXMgZGlzcGxheSk7IHRoaXMgc2hvdWxkIGJlIGlkZW50aWNhbCBpbiBhbGwgcm93cyBmcm9tIGEgc2luZ2xlIHNhbXBsZS4KLSB0aGUgYEJhcmNvZGVgIGNvbHVtbiBjb250YWlucyB0aGUgc2VxdWVuY2UgdGhhdCB3YXMgdXNlZCB0byBpZGVudGlmeSBlYWNoIHBvdGVudGlhbCBkcm9wbGV0IGZvciBzZXF1ZW5jaW5nIChhbmQgYSBudW1lcmljIHRhZywgaW4gdGhpcyBjYXNlKS4KVGhlc2Ugd2lsbCBiZSB1bmlxdWUgd2l0aGluIGEgc2FtcGxlLgoKQXMgd2UgcHJvY2VlZCB0byBjYWxjdWxhdGUgcGVyLWNlbGwgc3RhdGlzdGljcywgd2Ugd2lsbCBiZSBhZGRpbmcgbmV3IGRhdGEgdG8gdGhpcyB0YWJsZS4KCiMjIFF1YWxpdHkgY29udHJvbCBhbmQgZmlsdGVyaW5nCgohW1NpbmdsZS1jZWxsIHJvYWRtYXA6IFFDLCBGaWx0ZXIsIGFuZCBOb3JtYWxpemVdKGRpYWdyYW1zL3JvYWRtYXBfc2luZ2xlX3FjX25vcm0ucG5nKQoKIyMjIEZpbHRlcmluZyBlbXB0eSBkcm9wbGV0cwoKTW9zdCBvZiB0aGUgYmFyY29kZXMgaW4gYW55IGdpdmVuIDEweCBleHBlcmltZW50IHdpbGwgbm90IGJlIHNlZW4gYXQgYWxsLCBzbyBvdXIgZmlyc3Qgc3RlcCBjYW4gYmUgdG8gZmlsdGVyIHRoaXMgcmF3IGRhdGEgdG8gb25seSB0aGUgY2VsbHMgd2hlcmUgdGhlcmUgaXMgYXQgbGVhc3Qgb25lIHRyYW5zY3JpcHQgdGhhdCB3YXMgY291bnRlZCB3aXRoIHRoYXQgYmFyY29kZS4KClRvIGRvIHRoaXMsIHdlIHdpbGwgdXNlIHRoZSBgY29sU3VtcygpYCBmdW5jdGlvbiB0byBxdWlja2x5IGFkZCB1cCBhbGwgdGhlIGNvdW50cyB0aGF0IGNvcnJlc3BvbmQgdG8gZWFjaCBwb3NzaWJsZSBjZWxsIGJhcmNvZGUsIHRoZW4gZmlsdGVyIG91ciBgcmF3X3NjZWAgZG93biB0byBqdXN0IHRob3NlIGNvbHVtbnMgd2hlcmUgdGhlcmUgYXJlIG5vbi16ZXJvIHRvdGFsIGNvdW50cy4KV2Ugd2lsbCBuZWVkIHRvIGV4dHJhY3QgdGhlIGBjb3VudHNgIG1hdHJpeCBmcm9tIG91ciBTQ0Ugb2JqZWN0LCB3aGljaCB3ZSBjYW4gZG8gdXNpbmcgdGhlIGBjb3VudHMoKWAgZnVuY3Rpb24sIGNvbnZlbmllbnRseSBlbm91Z2guCgpgYGB7ciByZW1vdmUgemVyb3MsIGxpdmU9VFJVRX0KIyBzdW0gY29sdW1ucyBmcm9tIGNvdW50cyBtYXRyaXgKYmFyY29kZV9jb3VudHMgPC0gY29sU3Vtcyhjb3VudHMocmF3X3NjZSkpCgojIGZpbHRlciBTQ0Ugb2JqZWN0IHRvIG9ubHkgcm93cyB3aXRoIGNvdW50cyA+IDAKcmF3X3NjZSA8LSByYXdfc2NlWywgd2hpY2goYmFyY29kZV9jb3VudHMgPiAwKV0KYGBgCgpOb3cgd2UgY2FuIGxvb2sgYXQgaG93IG91ciBTQ0Ugb2JqZWN0IGhhcyBjaGFuZ2VkOgoKYGBge3IgemVyby1maWx0ZXJlZCBTQ0V9CnJhd19zY2UKYGBgCgpCdXQgYmFyY29kZXMgd2l0aCB6ZXJvIGNvdW50cyBhcmUgbm90IHRoZSBvbmx5IG9uZXMgdGhhdCBjb3JyZXNwb25kIHRvIGRyb3BsZXRzIHdpdGhvdXQgY2VsbHMgaW4gdGhlbSEKRXZlbiBpZiBhIGRyb3BsZXQgZG9lcyBub3QgaGF2ZSBhIGNlbGwgaW4gaXQsIHRoZXJlIHdpbGwgb2Z0ZW4gYmUgc3B1cmlvdXMgcmVhZHMgZnJvbSBSTkEgc2VxdWVuY2VzIHRoYXQgd2VyZSBwcmVzZW50IGluIHRoZSBleHRyYWNlbGx1bGFyIHNvbHV0aW9uLCB3aGV0aGVyIGZyb20gdGhlIG9yaWdpbmFsIHNhbXBsZSBvciBmcm9tIGNlbGxzIHRoYXQgd2VyZSBkYW1hZ2VkIGR1cmluZyBzaW5nbGUtY2VsbCBsaWJyYXJ5IHByZXBhcmF0aW9uLgoKV2UgY291bGQgaWRlbnRpZnkgdGhlc2UgYmFyY29kZXMgc2ltcGx5IGFzIHRob3NlIHdpdGggbG93IHRyYW5zY3JpcHQgY291bnRzLgpPciwgd2UgY2FuIGJlIGEgYml0IG1vcmUgY2xldmVyIQpXZSBjYW4gbG9vayBhdCB0aGUgdHJhbnNjcmlwdCBjb3VudHMgX2Zyb21fIHRoZSBsb3dlc3QtY291bnQgZHJvcGxldHMgdG8gY3JlYXRlIGFuIGV4cGVjdGVkIGRpc3RyaWJ1dGlvbiBvZiB0cmFuc2NyaXB0cyBpbiBkcm9wbGV0cyB0aGF0IGRvbid0IGNvbnRhaW4gY2VsbHMuClRoZW4gd2UgY2FuIHRlc3QgZWFjaCBkcm9wbGV0IHRvIGRldGVybWluZSB3aGV0aGVyIG9yIG5vdCBpdHMgdHJhbnNjcmlwdCBkaXN0cmlidXRpb24gZGV2aWF0ZXMgZnJvbSB0aGF0IGV4cGVjdGF0aW9uLgpJZiBpdCBkb2VzLCB0aGVuIHdlIGhhdmUgcHJldHR5IGdvb2QgZXZpZGVuY2UgdGhhdCB0aGVyZSBfaXNfIGEgY2VsbCBpbiB0aGVyZS4KClRoaXMgdGVzdCB3YXMgZmlyc3QgcHJvcG9zZWQgYnkgW0x1biBfZXQgYWwuXyAoMjAxOSldKGh0dHBzOi8vZG9pLm9yZy8xMC4xMTg2L3MxMzA1OS0wMTktMTY2Mi15KSBhbmQgaW1wbGVtZW50ZWQgYXMgYGVtcHR5RHJvcHMoKWAgaW4gdGhlIGBEcm9wbGV0VXRpbHNgIHBhY2thZ2UuClRoaXMgbWV0aG9kIHdhcyB0aGVuIGFkb3B0ZWQsIHdpdGggc29tZSBtb2RpZmljYXRpb25zLCBhcyB0aGUgZGVmYXVsdCBjZWxsIGZpbHRlcmluZyBtZXRob2QgdXNlZCBieSBDZWxsIFJhbmdlci4KSGVyZSB3ZSB3aWxsIHVzZSB0aGUgW2BlbXB0eURyb3BzQ2VsbFJhbmdlcigpYCBmdW5jdGlvbl0oaHR0cHM6Ly9yZHJyLmlvL2dpdGh1Yi9NYXJpb25pTGFiL0Ryb3BsZXRVdGlscy9tYW4vZW1wdHlEcm9wc0NlbGxSYW5nZXIuaHRtbCkgdG8gcGVyZm9ybSBmaWx0ZXJpbmcgdGhhdCBtb3JlIGNsb3NlbHkgbWF0Y2hlcyB0aGUgQ2VsbCBSYW5nZXIgaW1wbGVtZW50YXRpb24uCgoKYGBge3IgY2FsY3VsYXRlIGRyb3BsZXQgc3RhdHMsIGxpdmU9VFJVRX0KIyBjcmVhdGUgYSB0YWJsZSBvZiBzdGF0aXN0aWNzIHVzaW5nIGVtcHR5RHJvcHNDZWxsUmFuZ2VyCmRyb3BsZXRfZGYgPC0gRHJvcGxldFV0aWxzOjplbXB0eURyb3BzQ2VsbFJhbmdlcihyYXdfc2NlKQpgYGAKCk1vc3QgdmFsdWVzIGluIHRoaXMgdGFibGUgYXJlIGBOQWAsIGJlY2F1c2UgaW5kaXZpZHVhbCBzdGF0aXN0aWNzIHdlcmUgbm90IGNhbGN1bGF0ZWQgZm9yIHRoZSBsb3ctY291bnQgZHJvcGxldHMgdGhhdCB3ZXJlIHVzZWQgdG8gZ2VuZXJhdGUgdGhlIGJhY2tncm91bmQgZGlzdHJpYnV0aW9uLgooTW9zdCBkcm9wbGV0cyBkb24ndCBoYXZlIGNlbGxzLCBzbyB0aGlzIG1ha2VzIHNvbWUgc2Vuc2UhKQoKV2UgY2FuIGxvb2sgYXQganVzdCB0aGUgcm93cyB3aXRob3V0IGBOQWAgdmFsdWVzIGJ5IHNlbGVjdGVkIHRoZSBvbmVzIHdoZXJlIHRoZSBGRFIgKHdoaWNoIHdlIHdpbGwgdXNlIGFnYWluIHNvb24pLCBpcyBub3QgYE5BYC4KCmBgYHtyIGRyb3BsZXQgc3RhdHN9CiMgdmlldyByb3dzIHdoZXJlIEZEUiBpcyBub3QgYE5BYApkcm9wbGV0X2RmWyFpcy5uYShkcm9wbGV0X2RmJEZEUiksIF0KYGBgCllvdSB3aWxsIG5vdGljZSB0aGF0IHNvbWUgY2VsbHMgd2l0aCBoaWdoIGNvdW50cyBhbHNvIGhhdmUgYE5BYCB2YWx1ZXMgZm9yIG1hbnkgc3RhdGlzdGljcy4KSW4gdGhvc2UgY2FzZXMsIGBOQWAgdmFsdWVzIGFyZSBhY3R1YWxseSBwcmVzZW50IF9iZWNhdXNlXyBvZiB0aGUgaGlnaCBjb3VudHMgLSBgZW1wdHlEcm9wc0NlbGxSYW5nZXIoKWAgYXV0b21hdGljYWxseSBhc3N1bWVkIGNlbGxzIHdlcmUgcHJlc2VudCwgc28gdGhleSB3ZXJlIGFsc28gbm90IHRlc3RlZC4KCk5vdyB3ZSBjYW4gZmlsdGVyIG91ciBgcmF3X3NjZWAgb2JqZWN0IF9ieSBjb2x1bW5fIHRvIG9ubHkga2VlcCB0aGUgY2VsbHMgd2l0aCBhIHNtYWxsIEZEUjogdGhvc2UgdGhhdCBhcmUgcXVpdGUgdW5saWtlbHkgdG8gYmUgZW1wdHkgZHJvcGxldHMuCgpgYGB7ciBmaWx0ZXIgZW1wdHlkcm9wcywgbGl2ZT1UUlVFfQojIGZpbHRlciBkcm9wbGV0cyB1c2luZyBgd2hpY2hgIHRvIHByZXZlbnQgTkEgdHJvdWJsZQpjZWxsc190b19yZXRhaW4gPC0gd2hpY2goZHJvcGxldF9kZiRGRFIgPCAwLjAxKQpmaWx0ZXJlZF9zY2UgPC0gcmF3X3NjZVssIGNlbGxzX3RvX3JldGFpbl0KYGBgCgpIb3cgbWFueSBjZWxscyBkbyB3ZSBoYXZlIG5vdz8KCmBgYHtyIGZpbHRlcmVkIHN1bW1hcnl9CmZpbHRlcmVkX3NjZQpgYGAKCiMjIyBBZGRpdGlvbmFsIHF1YWxpdHkgY29udHJvbAoKSW4gYWRkaXRpb24gdG8gZmlsdGVyaW5nIG91dCBlbXB0eSBkcm9wbGV0cywgd2UgYWxzbyB3aWxsIHdhbnQgdG8gZmlsdGVyIG91dCBjZWxscyB0aGF0IG1heSBoYXZlIGJlZW4gZGFtYWdlZCBkdXJpbmcgbGlicmFyeSBwcmVwYXJhdGlvbi4KVGhlc2Ugd2lsbCBvZnRlbiBiZSBjaGFyYWN0ZXJpemVkIGJ5IGEgaGlnaCBwcm9wb3J0aW9uIG9mIG1pdG9jaG9uZHJpYWwgdHJhbnNjcmlwdHMgYW5kIGEgc21hbGxlciBvdmVyYWxsIG51bWJlciBvZiB1bmlxdWUgdHJhbnNjcmlwdHMuCldoZW4gYSBjZWxsIHJ1cHR1cmVzLCBjeXRvcGxhc21pYyB0cmFuc2NyaXB0cyB3aWxsIGxlYWsgb3V0LCBidXQgbWl0b2Nob25kcmlhbCB0cmFuc2NyaXB0cywgc3RpbGwgcHJvdGVjdGVkIGJ5IHRoZSBtaXRvY2hvbmRyaWFsIG1lbWJyYW5lLCBtYXkgcmVtYWluLgpBcyBhIGNvbnNlcXVlbmNlLCB0aGVyZSB3aWxsIGJlIGFuIG92ZXItYWJ1bmRhbmNlIG9mIG1pdG9jaG9uZHJpYWwgcmVhZHMsIGFuZCBmZXdlciB1bmlxdWUgdHJhbnNjcmlwdHMgZXhwcmVzc2VkLgoKT3VyIGZpcnN0IHN0ZXAgdGhlbiwgaXMgY3JlYXRlIGEgdmVjdG9yIG9mIHRoZSBtaXRvY2hvbmRyaWFsIGdlbmVzIHRoYXQgYXJlIHByZXNlbnQgaW4gb3VyIGRhdGFzZXQuClRoZSBtaXRvY2hvbmRyaWFsIGZpbGUgd2UgZGVmaW5lZCBkdXJpbmcgc2V0dXAgKGBtaXRvX2ZpbGVgKSBpcyBhIFRTViBmaWxlIGNvbnRhaW5pbmcgYWxsIG9mIHRoZSBodW1hbiBtaXRvY2hvbmRyaWFsIGdlbmVzIHdpdGggYWRkaXRpb25hbCBhbm5vdGF0aW9uIGluZm9ybWF0aW9uIGZvciBlYWNoIGdlbmUsIHN1Y2ggYXMgdGhlIGdlbmUgbG9jYXRpb24gYW5kIGFsdGVybmF0aXZlIG5hbWVzLgooRm9yIG1vcmUgZGV0YWlsIG9uIHRoZSBzdGVwcyB3ZSB0b29rIHRvIGNyZWF0ZSB0aGlzIGZpbGUsIHlvdSBjYW4gbG9vayBhdCBbb25lIG9mIG91ciBzZXR1cCBub3RlYm9va3NdKGh0dHBzOi8vZ2l0aHViLmNvbS9BbGV4c0xlbW9uYWRlL3RyYWluaW5nLW1vZHVsZXMvYmxvYi9tYXN0ZXIvc2NSTkEtc2VxLWFkdmFuY2VkL3NldHVwL21pdG9fZ2VuZV9saXN0cy5SbWQpKQoKQWxsIHdlIG5lZWQgbm93IGlzIHRoZSBgZ2VuZV9pZGAsIGFuZCBvbmx5IGZvciB0aGUgZ2VuZXMgdGhhdCBhcmUgcHJlc2VudCBpbiBvdXIgU0NFLCBzbyB3ZSB3aWxsIGRvIHNvbWUgZmlsdGVyaW5nIHdpdGggYGRwbHlyYCB0byBwdWxsIG91dCBhIHZlY3RvciB3aXRoIGp1c3QgdGhvc2UgaWRzLgoKYGBge3IgZ2V0IG1pdG9jaG9uZHJpYWwgZ2VuZXN9CiMgcmVhZCBpbiBhIHRhYmxlIG9mIG1pdG9jaG9uZHJpYWwgZ2VuZXMgYW5kIGV4dHJhY3QgaWRzCm1pdG9fZ2VuZXMgPC0gcmVhZHI6OnJlYWRfdHN2KG1pdG9fZmlsZSkgfD4KICAjIGZpbHRlciB0byBvbmx5IHRoZSBnZW5lcyB0aGF0IGFyZSBmb3VuZCBpbiBvdXIgZGF0YXNldAogIGRwbHlyOjpmaWx0ZXIoZ2VuZV9pZCAlaW4lIHJvd25hbWVzKGZpbHRlcmVkX3NjZSkpIHw+CiAgIyBjcmVhdGUgYSB2ZWN0b3IgZnJvbSB0aGUgZ2VuZV9pZCBjb2x1bW4KICBkcGx5cjo6cHVsbChnZW5lX2lkKQpgYGAKCiMjIyBDYWxjdWxhdGluZyBzdW1tYXJ5IFFDIHN0YXRpc3RpY3MKCldlIGNhbiBub3cgdXNlIHRoZSBgc2N1dHRsZWAgZnVuY3Rpb24gYGFkZFBlckNlbGxRQygpYCB0byBjYWxjdWxhdGUgc29tZSBzdGF0aXN0aWNzIGJhc2VkIG9uIHRoZSBjb3VudHMgbWF0cml4LCB3aGljaCB3aWxsIGJlIGFkZGVkIHRvIHRoZSBgY29sRGF0YWAgdGFibGUuCgpJbiBhZGRpdGlvbiB0byBjYWxjdWxhdGluZyBzdGF0aXN0aWNzIGxpa2UgdGhlIHRvdGFsIHJlYWQgY291bnQgZm9yIGVhY2ggY2VsbCBhbmQgdGhlIG51bWJlciBvZiB0cmFuc2NyaXB0cyB0aGF0IGFyZSBkZXRlY3RlZCwgd2UgY2FuIGFsc28gY2FsY3VsYXRlIHRob3NlIHN0YXRpc3RpY3MgZm9yIGRlZmluZWQgc3Vic2V0cyBvZiBnZW5lcy4KSW4gdGhpcyBjYXNlLCB3ZSB3aWxsIHVzZSBvdXIgYG1pdG9fZ2VuZXNgIHZlY3RvciB0byBkZWZpbmUgYSBzdWJzZXQgY2FsbGVkIGBtaXRvYC4KVGhlIGBtaXRvYCBuYW1lIGlzIGltcG9ydGFudCBpbiB0aGF0IGl0IGlzIHRoZSBuYW1lIHRoYXQgd2lsbCBiZSBleHBlY3RlZCBieSBhIGxhdGVyIGZ1bmN0aW9uLgooV2UgY291bGQgZGVmaW5lIG1vcmUgc3Vic2V0cywgYnV0IGZvciBub3cgdGhpcyBvbmUgd2lsbCBkby4pCgpgYGB7ciBwZXIgY2VsbCBRQywgbGl2ZT1UUlVFfQpmaWx0ZXJlZF9zY2UgPC0gc2N1dHRsZTo6YWRkUGVyQ2VsbFFDKGZpbHRlcmVkX3NjZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWJzZXRzID0gbGlzdChtaXRvID0gbWl0b19nZW5lcykpCmBgYAoKTm93IHdlIGNhbiBsb29rIGF0IHRoZSBjb2xEYXRhIHRvIHNlZSB3aGF0IHdhcyBhZGRlZDoKCmBgYHtyIHZpZXcgY29sRGF0YSBzdGF0c30KaGVhZChjb2xEYXRhKGZpbHRlcmVkX3NjZSkpCmBgYAoKV2UgY2FuIGFsc28gcGxvdCBzb21lIG9mIHRoZXNlIHN0YXRpc3RpY3MsIGhlcmUgdXNpbmcgdGhlIGBwbG90TWV0cmljcygpYCBmdW5jdGlvbiBmcm9tIHRoZSBgbWlRQ2AgcGFja2FnZSB0byBwbG90IHRoZSBwZXJjZW50IG9mIHJlYWRzIHRoYXQgYXJlIG1pdG9jaG9uZHJpYWwgKHRoZSBgc3Vic2V0c19taXRvX3BlcmNlbnRgIGNvbHVtbikgYWdhaW5zdCB0aGUgbnVtYmVyIG9mIHVuaXF1ZSBnZW5lcyBkZXRlY3RlZCAodGhlIGBkZXRlY3RlZGAgY29sdW1uKSBmb3IgZWFjaCBjZWxsLgoKYGBge3IgbWlRQyBwbG90TWV0cmljc30KIyB1c2UgbWlRQzo6cGxvdE1ldHJpY3MoKQptaVFDOjpwbG90TWV0cmljcyhmaWx0ZXJlZF9zY2UpICsgdGhlbWVfYncoKQpgYGAKCldlIGNhbiBzZWUgdGhhdCB0aGVyZSBpcyBhIHJhbmdlIG9mIG1pdG9jaG9uZHJpYWwgcGVyY2VudGFnZXMsIGFuZCBpdCBkb2VzIGFsc28gc2VlbSB0aGF0IGNlbGxzIHdpdGggaGlnaCBwZXJjZW50YWdlcyBvZiBtaXRvY2hvbmRyaWFsIGdlbmVzIGRvbid0IHNlZW0gdG8gY29udGFpbiB2ZXJ5IG1hbnkgdW5pcXVlIGdlbmVzLgoKSG93IGRvIHdlIGZpbHRlciB3aXRoIHRoaXMgaW5mb3JtYXRpb24/Ck9uZSBvcHRpb24gaXMgdG8gZGVmaW5lIGEgY3V0b2ZmIGZvciB0aGUgbWl0b2Nob25kcmlhbCBwZXJjZW50YWdlIGFib3ZlIHdoaWNoIHdlIGNhbGwgYSBjZWxsIGNvbXByb21pc2VkIGFuZCBleGNsdWRlIGl0IGZyb20gZnVydGhlciBhbmFseXNpcy4KSG93ZXZlciwgY2hvb3NpbmcgdGhhdCBjdXRvZmYgY2FuIGJlIGEgYml0IGZyYXVnaHQsIGFzIHRoZSBleHBlY3RlZCBwZXJjZW50YWdlIG9mIG1pdG9jaG9uZHJpYWwgcmVhZHMgY2FuIHZhcnkgZGVwZW5kaW5nIG9uIHRoZSBjZWxsIHR5cGUgYW5kIGxpYnJhcnkgcHJlcGFyYXRpb24gbWV0aG9kcy4KU28gaXQgbWlnaHQgYmUgbmljZSB0byBoYXZlIGEgbWV0aG9kIHRvIGRldGVybWluZSB0aGF0IGN1dG9mZiBmcm9tIHRoZSBkYXRhIGl0c2VsZi4KCiMjIyBGaWx0ZXJpbmcgY29tcHJvbWlzZWQgY2VsbHMKCkRldGVybWluaW5nIG1pdG9jaG9uZHJpYWwgY3V0b2ZmcyBpcyBleGFjdGx5IHdoYXQgdGhlIGBtaVFDYCBwYWNrYWdlIGRvZXMgKFtIaXBwZW4gX2V0IGFsLl8gMjAyMV0oaHR0cHM6Ly9kb2kub3JnLzEwLjEzNzEvam91cm5hbC5wY2JpLjEwMDkyOTApKSEKSW4gdHJ1dGgsIGl0IGRvZXMgc29tZXRoaW5nIHBvc3NpYmx5IGV2ZW4gYSBiaXQgYmV0dGVyOiBpdCBmaXRzIGEgbWl4dHVyZSBtb2RlbCB0byB0aGUgZGF0YSB0aGF0IGNvbnNpc3RzIG9mIGRpc3RyaWJ1dGlvbnMgb2YgaGVhbHRoeSBjZWxscyBhbmQgY29tcHJvbWlzZWQgY2VsbHMuClRoZW4gd2UgY2FuIGNhbGN1bGF0ZSB3aGV0aGVyIGVhY2ggY2VsbCBpcyBtb3JlIGxpa2VseSB0byBiZWxvbmcgdG8gdGhlIGhlYWx0aHkgb3IgY29tcHJvbWlzZWQgZGlzdHJpYnV0aW9uLgpXZSBjYW4gdGhlbiBleGNsdWRlIHRoZSBjZWxscyB0aGF0IGFyZSBtb3JlIGxpa2VseSB0byBiZSBjb21wcm9taXNlZC4KClRvIHVzZSBgbWlRQ2AsIHdlIGZpcnN0IGZpdCBhIG1vZGVsIHRvIHRoZSBkYXRhIGluIG91ciBTQ0Ugb2JqZWN0OgoKYGBge3IgbWlRQyBtb2RlbCwgbGl2ZT1UUlVFfQojIGZpdCB0aGUgbWlRQyBtb2RlbAptaXFjX21vZGVsIDwtIG1pUUM6Om1peHR1cmVNb2RlbChmaWx0ZXJlZF9zY2UpCmBgYAoKTm93IHdlIGNhbiBwbG90IHRoZSBtb2RlbCByZXN1bHRzIHVzaW5nIHRoZSBgcGxvdE1vZGVsKClgIGZ1bmN0aW9uIHRvIHNlZSBob3cgaXQgY29ycmVzcG9uZHMgdG8gb3VyIGRhdGEuCldlIHNob3VsZCBleHBlY3QgdG8gc2VlIHR3byBmaXQgbGluZXM6CgotIE9uZSBsaW5lIHdpbGwgY29ycmVzcG9uZCB0aGUgdGhlICJoZWFsdGh5IiBjZWxscyBhbmQgc2hvdWxkIHNob3cgbGl0dGxlIHRvIG5vIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBudW1iZXIgb2YgdW5pcXVlIGdlbmVzIGRldGVjdGVkIGFuZCB0aGUgbWl0b2Nob25kcmlhbCBwZXJjZW50YWdlLgotIEJ5IGNvbnRyYXN0LCB0aGUgbGluZSB0aGF0IGNvcnJlc3BvbmRzIHRvICJjb21wcm9taXNlZCIgY2VsbHMgd2lsbCBzaG93IGEgbmVnYXRpdmUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIG51bWJlciBvZiB1bmlxdWUgZ2VuZXMgZGV0ZWN0ZWQgYW5kIHRoZSBtaXRvY2hvbmRyaWFsIHBlcmNlbnRhZ2UuCgpUaGlzIHBsb3Qgd2lsbCBhbHNvIHNob3csIGZvciBlYWNoIGNlbGwsIHRoZSBwb3N0ZXJpb3IgcHJvYmFiaWxpdHkgdGhhdCB0aGUgY2VsbCBpcyBkZXJpdmVkIGZyb20gdGhlIGNvbXByb21pc2VkIGRpc3RyaWJ1dGlvbjsgYSBoaWdoZXIgc2NvcmUgaW5kaWNhdGVzIHRoYXQgYSBjZWxsIGlzIG1vcmUgbGlrZWx5IHRvIGJlIGNvbXByb21pc2VkLgoKSXQgaXMgYWxzbyBjcml0aWNhbCB0byBub3RlIHRoYXQgdGhpcyBtb2RlbCBjYW4gX2FuZCBkb2VzXyBmYWlsIGF0IHRpbWVzLgpQbG90dGluZyB0aGUgcmVzdWx0cyBhcyB3ZSBoYXZlIGRvbmUgaGVyZSBpcyBub3QgYSBzdGVwIHRvIHNraXAuCioqQWx3YXlzIGxvb2sgYXQgeW91ciBkYXRhISoqCgpgYGB7ciBtaVFDIHBsb3RNb2RlbCwgbGl2ZT1UUlVFfQojIHBsb3QgdGhlIG1pUUMgbW9kZWwKbWlRQzo6cGxvdE1vZGVsKGZpbHRlcmVkX3NjZSwgbWlxY19tb2RlbCkgKwogIHRoZW1lX2J3KCkKYGBgCgpXZSBjYW4gbm93IGZpbHRlciBvdXIgZGF0YSBiYXNlZCBvbiB0aGUgcHJvYmFiaWxpdHkgY29tcHJvbWlzZWQgYXMgY2FsY3VsYXRlZCBmcm9tIHRoZSBtb2RlbC4KQnV0IGJlZm9yZSB3ZSBkbyB0aGF0LCB3ZSBtaWdodCB3YW50IHRvIHF1aWNrbHkgcGxvdCB0byBzZWUgd2hhdCB3b3VsZCBiZSBmaWx0ZXJlZCBvdXQgd2l0aCBhIGdpdmVuIGN1dG9mZiwgdXNpbmcgdGhlIGBwbG90RmlsdGVyaW5nKClgIGZ1bmN0aW9uLgpUaGUgZGVmYXVsdCBpcyB0byBleGNsdWRlIGNlbGxzIHRoYXQgaGF2ZSBhIHBvc3RlcmlvciBwcm9iYWJpbGl0eSBvZiAwLjc1IG9yIGdyZWF0ZXIgb2YgYmVpbmcgY29tcHJvbWlzZWQuCldlIHN0aWNrIHdpdGggdGhhdCBkZWZhdWx0LCBidXQgZm9yIGNsYXJpdHksIHdlIHdpbGwgYWxzbyBpbmNsdWRlIGl0IGluIG91ciBjb2RlIQoKCmBgYHtyIG1pUUMgcGxvdEZpbHRlcmluZ30KIyBsb29rIGF0IG1pUUMgZmlsdGVyaW5nCm1pUUM6OnBsb3RGaWx0ZXJpbmcoZmlsdGVyZWRfc2NlLCBtaXFjX21vZGVsLAogICAgICAgICAgICAgICAgICAgIHBvc3Rlcmlvcl9jdXRvZmYgPSAwLjc1KSArCiAgdGhlbWVfYncoKQpgYGAKCkluIHRoaXMgY2FzZSwgdGhlIGxpbmUgYmV0d2VlbiB0aGUgY2VsbHMgdG8gYmUga2VwdCBhbmQgdGhvc2UgdGhhdCB3aWxsIGJlIHJlbW92ZWQgc2VlbXMgdG8gY29ycmVzcG9uZCB0byBhIG1pdG9jaG9uZHJpYWwgcGVyY2VudGFnZSBvZiBhYm91dCAxMi41JSwgYnV0IG5vdGUgdGhhdCB0aGlzIHdpbGwgbm90IGFsd2F5cyBiZSBjb25zdGFudC4KVGhlIGN1dG9mZiBwb2ludCBjYW4gdmFyeSBmb3IgZGlmZmVyZW50IG51bWJlcnMgb2YgdW5pcXVlIGdlbmVzIHdpdGhpbiBhIHNhbXBsZSwgYW5kIGl0IHdpbGwgY2VydGFpbmx5IHZhcnkgYW1vbmcgc2FtcGxlcyEKCkF0IHRoaXMgcG9pbnQsIHdlIGNhbiBwZXJmb3JtIHRoZSBhY3R1YWwgZmlsdGVyaW5nIHVzaW5nIHRoZSBgZmlsdGVyQ2VsbHMoKWAgZnVuY3Rpb24sIGdpdmluZyB1cyBhIGZ1cnRoZXIgZmlsdGVyZWQgU0NFIG9iamVjdC4KCmBgYHtyIG1pUUMgZmlsdGVyY2VsbHMsIGxpdmU9VFJVRX0KIyBwZXJmb3JtIG1pUUMgZmlsdGVyaW5nCnFjZmlsdGVyZWRfc2NlIDwtIG1pUUM6OmZpbHRlckNlbGxzKGZpbHRlcmVkX3NjZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWwgPSBtaXFjX21vZGVsKQpgYGAKCiMjIyMgT25lIG1vcmUgZmlsdGVyOiB1bmlxdWUgZ2VuZSBjb3VudAoKV2hpbGUgdGhlIG1pUUMgZmlsdGVyaW5nIGlzIHByZXR0eSBnb29kLCB5b3UgbWF5IGhhdmUgbm90aWNlZCB0aGF0IGl0IHN0aWxsIGxlZnQgc29tZSBjZWxscyB0aGF0IGhhZCB2ZXJ5IGxvdyBudW1iZXJzIG9mIHVuaXF1ZSBnZW5lcy4KV2hpbGUgdGhlc2UgY2VsbHMgbWF5IG5vdCBiZSBjb21wcm9taXNlZCwgdGhlIGluZm9ybWF0aW9uIGZyb20gdGhlbSBpcyBhbHNvIG5vdCBsaWtlbHkgdG8gYmUgdXNlZnVsLCBzbyB3ZSB3aWxsIGZpbHRlciB0aG9zZSBhcyB3ZWxsLgpXZSB3aWxsIG9ubHkga2VlcCBjZWxscyB0aGF0IGhhdmUgYXQgbGVhc3QgMjAwIHVuaXF1ZSBnZW5lcy4KCmBgYHtyIHVuaXF1ZSBjdXRvZmYsIGxpdmU9VFJVRX0KIyBmaWx0ZXIgY2VsbHMgYnkgdW5pcXVlIGdlbmUgY291bnQgKGBkZXRlY3RlZGApCnFjZmlsdGVyZWRfc2NlIDwtIHFjZmlsdGVyZWRfc2NlWywgd2hpY2gocWNmaWx0ZXJlZF9zY2UkZGV0ZWN0ZWQgPj0gMjAwKV0KcWNmaWx0ZXJlZF9zY2UKYGBgCgoKIyMgTm9ybWFsaXphdGlvbgoKTm93IHRoYXQgd2UgaGF2ZSBkb25lIG91ciBmaWx0ZXJpbmcsIHdlIGNhbiBzdGFydCBhbmFseXppbmcgdGhlIGV4cHJlc3Npb24gY291bnRzIGZvciB0aGUgcmVtYWluaW5nIGNlbGxzLgoKVGhlIG5leHQgc3RlcCBhdCB0aGlzIHBvaW50IGlzIHRvIGNvbnZlcnQgdGhlIHJhdyBjb3VudHMgaW50byBhIG1lYXN1cmUgdGhhdCBhY2NvdW50cyBmb3IgZGlmZmVyZW5jZXMgaW4gc2VxdWVuY2luZyBkZXB0aCBiZXR3ZWVuIGNlbGxzLCBhbmQgdG8gY29udmVydCB0aGUgZGlzdHJpYnV0aW9uIG9mIGV4cHJlc3Npb24gdmFsdWVzIGZyb20gdGhlIHNrZXdlZCBkaXN0cmlidXRpb24gd2UgZXhwZWN0IHRvIHNlZSBpbiByYXcgY291bnRzIHRvIG9uZSB0aGF0IGlzIG1vcmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuCgpXZSB3aWxsIGRvIHRoaXMgdXNpbmcgZnVuY3Rpb25zIGZyb20gdGhlIGBzY3JhbmAgYW5kIGBzY3V0dGxlYCBwYWNrYWdlcy4KVGhlIHByb2NlZHVyZSB3ZSB3aWxsIHVzZSBoZXJlIGlzIGRlcml2ZWQgZnJvbSB0aGUgW09TQ0EgY2hhcHRlciBvbiBub3JtYWxpemF0aW9uXShodHRwOi8vYmlvY29uZHVjdG9yLm9yZy9ib29rcy8zLjE2L09TQ0EuYmFzaWMvbm9ybWFsaXphdGlvbi5odG1sI25vcm1hbGl6YXRpb24tYnktZGVjb252b2x1dGlvbikuClRoZSBpZGVhIGlzIHRoYXQgdGhlIHZhcnlpbmcgZXhwcmVzc2lvbiBwYXR0ZXJucyB0aGF0IGRpZmZlcmVudCBjZWxsIHR5cGVzIGV4aGliaXQgd2lsbCBhZmZlY3QgdGhlIHNjYWxpbmcgZmFjdG9ycyB0aGF0IHdlIHdvdWxkIGFwcGx5LgpUbyBhY2NvdW50IGZvciB0aGF0IHZhcmlhdGlvbiwgd2UgZmlyc3QgZG8gYSByb3VnaCBjbHVzdGVyaW5nIG9mIGNlbGxzIGJ5IHRoZWlyIGV4cHJlc3Npb24gd2l0aCBgc2NyYW46OnF1aWNrQ2x1c3RlcigpYCwgdGhlbiB1c2UgdGhhdCBjbHVzdGVyaW5nIHRvIGNhbGN1bGF0ZSB0aGUgc2NhbGluZyBmYWN0b3IgZm9yIGVhY2ggY2VsbCB3aXRoaW4gdGhlIGNsdXN0ZXJzIHVzaW5nIGBzY3Jhbjo6Y29tcHV0ZVN1bUZhY3RvcnMoKWAuCkZpbmFsbHksIHdlIGFwcGx5IHRoZSBzY2FsaW5nIGZhY3RvciB0byB0aGUgZXhwcmVzc2lvbiB2YWx1ZXMgZm9yIGVhY2ggY2VsbCBhbmQgY2FsY3VsYXRlIHRoZSBsb2ctc2NhbGVkIGV4cHJlc3Npb24gdmFsdWVzIHVzaW5nIHRoZSBgc2N1dHRsZTo6bG9nTm9ybUNvdW50cygpYCBmdW5jdGlvbi4KCmBgYHtyIG5vcm1hbGl6YXRpb24sIGxpdmU9VFJVRX0KIyBQZXJmb3JtIHJvdWdoIGNsdXN0ZXJpbmcKcWNsdXN0IDwtIHNjcmFuOjpxdWlja0NsdXN0ZXIocWNmaWx0ZXJlZF9zY2UpCgojIHVzZSBjbHVzdGVycyB0byBjb21wdXRlIHNjYWxpbmcgZmFjdG9ycyBhbmQgYWRkIHRvIFNDRSBvYmplY3QKcWNmaWx0ZXJlZF9zY2UgPC0gc2NyYW46OmNvbXB1dGVTdW1GYWN0b3JzKHFjZmlsdGVyZWRfc2NlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3RlcnMgPSBxY2x1c3QpCgojIHBlcmZvcm0gbm9ybWFsaXphdGlvbiB1c2luZyBzY2FsaW5nIGZhY3RvcnMKIyBhbmQgc2F2ZSBhcyBhIG5ldyBTQ0Ugb2JqZWN0Cm5vcm1hbGl6ZWRfc2NlIDwtIHNjdXR0bGU6OmxvZ05vcm1Db3VudHMocWNmaWx0ZXJlZF9zY2UpCmBgYAoKVGhpcyBjcmVhdGVzIGEgbmV3ICJhc3NheSIgaW4gdGhlIGBub3JtYWxpemVkX3NjZWAgb2JqZWN0LCBgbG9nY291bnRzYCwgd2hpY2ggY29udGFpbnMgdGhlIG5vcm1hbGl6ZWQgY291bnQgdmFsdWVzIGZvciBlYWNoIGNlbGwgYW5kIGdlbmUuCihUaGUgZGF0YSBoZXJlIGFyZSBub3QgX2FjdHVhbGx5XyB0aGUgbG9nIG9mIHRoZSBjb3VudHMsIHNpbmNlIHdlIGFsc28gYXBwbGllZCB0aGUgc2NhbGluZyBmYWN0b3JzLCBidXQgdGhhdCBuYW1lIGlzIHVzZWQgZm9yIGhpc3RvcmljYWwgcmVhc29ucy4pCgpMZXQncyB0YWtlIGEgbG9vazoKCmBgYHtyIG5vcm1hbGl6ZWQgc2NlfQpub3JtYWxpemVkX3NjZQpgYGAKCiMjIERpbWVuc2lvbiByZWR1Y3Rpb24KCiFbU2luZ2xlLWNlbGwgcm9hZG1hcDogRGltZW5zaW9uIHJlZHVjdGlvbl0oZGlhZ3JhbXMvcm9hZG1hcF9zaW5nbGVfZGltZW5zaW9uX3JlZHVjdGlvbi5wbmcpCgpOb3cgdGhhdCB3ZSBoYXZlIG5vcm1hbGl6ZWQgZXhwcmVzc2lvbiB2YWx1ZXMsIHdlIHdvdWxkIGxpa2UgdG8gcHJvZHVjZSBzb21lIHJlZHVjZWQtZGltZW5zaW9uIHJlcHJlc2VudGF0aW9ucyBvZiB0aGUgZGF0YS4KVGhlc2Ugd2lsbCBhbGxvdyB1cyB0byBwZXJmb3JtIHNvbWUgZG93bnN0cmVhbSBjYWxjdWxhdGlvbnMgbW9yZSBxdWlja2x5LCByZWR1Y2Ugc29tZSBvZiB0aGUgbm9pc2UgaW4gdGhlIGRhdGEsIGFuZCBhbGxvdyB1cyB0byB2aXN1YWxpemUgb3ZlcmFsbCByZWxhdGlvbnNoaXBzIGFtb25nIGNlbGxzIG1vcmUgZWFzaWx5ICh0aG91Z2ggd2l0aCBtYW55IGNhdmVhdHMhKS4KCiMjIyBTZWxlY3RpbmcgaGlnaGx5IHZhcmlhYmxlIGdlbmVzCgpXaGlsZSB3ZSBjb3VsZCBjYWxjdWxhdGUgdGhlIHJlZHVjZWQgZGltZW5zaW9ucyB1c2luZyBhbGwgb2YgdGhlIGdlbmVzIHRoYXQgd2UgaGF2ZSBhc3NheWVkLCBpbiBwcmFjdGljZSBtb3N0IG9mIHRoZSBnZW5lcyB3aWxsIGhhdmUgdmVyeSBsaXR0bGUgdmFyaWF0aW9uIGluIGV4cHJlc3Npb24sIHNvIGRvaW5nIHNvIHdpbGwgbm90IHByb3ZpZGUgbXVjaCBhZGRpdGlvbmFsIHNpZ25hbC4KUmVkdWNpbmcgdGhlIG51bWJlciBvZiBnZW5lcyB3ZSBpbmNsdWRlIHdpbGwgYWxzbyBzcGVlZCB1cCBzb21lIG9mIHRoZSBjYWxjdWxhdGlvbnMuCgpUbyBpZGVudGlmeSB0aGUgbW9zdCB2YXJpYWJsZSBnZW5lcywgd2Ugd2lsbCB1c2UgZnVuY3Rpb25zIGZyb20gdGhlIGBzY3JhbmAgcGFja2FnZS4KVGhlIGZpcnN0IGZ1bmN0aW9uLCBgbW9kZWxHZW5lVmFyKClgLCBhdHRlbXB0cyB0byBkaXZpZGUgdGhlIHZhcmlhdGlvbiBvYnNlcnZlZCBmb3IgZWFjaCBnZW5lIGludG8gYSBiaW9sb2dpY2FsIGFuZCB0ZWNobmljYWwgY29tcG9uZW50LCB3aXRoIHRoZSBpbnR1aXRpb24gdGhhdCBnZW5lcyB3aXRoIGxvd2VyIG1lYW4gZXhwcmVzc2lvbiB0ZW5kIHRvIGhhdmUgbG93ZXIgdmFyaWFuY2UgZm9yIHB1cmVseSB0ZWNobmljYWwgcmVhc29ucy4KV2UgdGhlbiBwcm92aWRlIHRoZSBgbW9kZWxHZW5lVmFyKClgIG91dHB1dCB0byB0aGUgYGdldFRvcEhWR3MoKWAgZnVuY3Rpb24gdG8gaWRlbnRpZnkgdGhlIGdlbmVzIHdpdGggdGhlIGhpZ2hlc3QgX2Jpb2xvZ2ljYWxfIHZhcmlhdGlvbiwgd2hpY2ggaXMgd2hhdCB3ZSBhcmUgbW9zdCBpbnRlcmVzdGVkIGluLgoKYGBge3Igc2VsZWN0IEhWR3N9CiMgaWRlbnRpZnkgMjAwMCBnZW5lcwpudW1fZ2VuZXMgPC0gMjAwMAoKIyBtb2RlbCB2YXJpYW5jZSwgcGFydGl0aW9uaW5nIGludG8gYmlvbG9naWNhbCBhbmQgdGVjaG5pY2FsIHZhcmlhdGlvbgpnZW5lX3ZhcmlhbmNlIDwtIHNjcmFuOjptb2RlbEdlbmVWYXIobm9ybWFsaXplZF9zY2UpCgojIGdldCB0aGUgbW9zdCB2YXJpYWJsZSBnZW5lcwpodl9nZW5lcyA8LSBzY3Jhbjo6Z2V0VG9wSFZHcyhnZW5lX3ZhcmlhbmNlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuID0gbnVtX2dlbmVzKQpgYGAKClRoZSByZXN1bHQgaXMgYSB2ZWN0b3Igb2YgZ2VuZSBpZHMgKG9yZGVyZWQgZnJvbSBtb3N0IHRvIGxlYXN0IHZhcmlhYmxlKToKCmBgYHtyIHZpZXcgSFZHc30KaGVhZChodl9nZW5lcykKYGBgCgojIyMgUHJpbmNpcGFsIGNvbXBvbmVudHMgYW5hbHlzaXMKCk5vdyB0aGF0IHdlIGhhdmUgc2VsZWN0ZWQgdGhlIGdlbmVzIHdlIHdvdWxkIGxpa2UgdG8gdXNlIGZvciB0aGUgcmVkdWNlZC1kaW1lbnNpb24gcmVwcmVzZW50YXRpb25zIG9mIHRoZSBleHByZXNzaW9uIGRhdGEsIHdlIGNhbiBzdGFydCB0byBjYWxjdWxhdGUgdGhlbS4KRmlyc3Qgd2Ugd2lsbCB1c2UgdGhlIGBzY2F0ZXI6OnJ1blBDQSgpYCBmdW5jdGlvbiB0byBjYWxjdWxhdGUgdGhlIHByaW5jaXBhbCBjb21wb25lbnRzIGZyb20gdGhlIGV4cHJlc3Npb24gbWF0cml4LgpUaGlzIHJlcHJlc2VudGF0aW9uIGlzIGZhc3QgYW5kIGZhaXJseSByb2J1c3QsIGJ1dCB0aGUgcmVzdWx0IGlzIHN0aWxsIHF1aXRlIG11bHRpZGltZW5zaW9uYWwuCldlIHdhbnQga2VlcCBhIGZhaXIgbnVtYmVyIG9mIGNvbXBvbmVudHMgKGRpbWVuc2lvbnMpIGluIG9yZGVyIHRvIGFjY3VyYXRlbHkgcmVwcmVzZW50IHRoZSB2YXJpYXRpb24gaW4gdGhlIGRhdGEsIGJ1dCBkb2luZyBzbyBtZWFucyB0aGF0IHBsb3R0aW5nIG9ubHkgYSBmZXcgb2YgdGhlc2UgZGltZW5zaW9ucyAoaW4gMkQpIGlzIG5vdCBsaWtlbHkgdG8gcHJvdmlkZSBhIGZ1bGwgdmlldyBvZiB0aGUgZGF0YS4KClRoZSBkZWZhdWx0IG51bWJlciBvZiBjb21wb25lbnRzIGlzIDUwLCB3aGljaCB3ZSB3aWxsIHN0aWNrIHdpdGgsIGJ1dCBsZXQncyBlbnRlciBpdCBtYW51YWxseSBqdXN0IGZvciB0aGUgcmVjb3JkLgoKYGBge3IgcnVuUENBLCBsaXZlPVRSVUV9CiMgY2FsY3VsYXRlIGFuZCBzYXZlIFBDQSByZXN1bHRzCm5vcm1hbGl6ZWRfc2NlIDwtIHNjYXRlcjo6cnVuUENBKAogIG5vcm1hbGl6ZWRfc2NlLAogIG5jb21wb25lbnRzID0gNTAsICMgaG93IG1hbnkgY29tcG9uZW50cyB0byBrZWVwCiAgc3Vic2V0X3JvdyA9IGh2X2dlbmVzICMgdXNlIG9ubHkgdGhlIHZhcmlhYmxlIGdlbmVzIHdlIGNob3NlCikKYGBgCgpUaGVzZSByZWR1Y2VkLWRpbWVuc2lvbiByZXN1bHRzIHdpbGwgYmUgc3RvcmVkIGluIGEgYHJlZHVjZWREaW1gIHNsb3QgaW4gdGhlIFNDRSBvYmplY3QuCldlIGNhbiBzZWUgdGhlIG5hbWVzIG9mIHRoZSBgcmVkdWNlZERpbWBzIHRoYXQgd2UgaGF2ZSBieSBsb29raW5nIGF0IHRoZSBvYmplY3Qgc3VtbWFyeToKCmBgYHtyIHZpZXcgcmVkdWNlZCBkaW1lbnNpb25zfQpub3JtYWxpemVkX3NjZQpgYGAKCklmIHdlIHdhbnQgdG8gZXh0cmFjdCB0aGUgUENBIHJlc3VsdHMsIHdlIGNhbiBkbyB0aGF0IHdpdGggdGhlIGByZWR1Y2VkRGltKClgIGZ1bmN0aW9uOgpOb3RlIHRoYXQgZm9yIHRoZXNlIHJlZHVjZWQtZGltZW5zaW9uYWxpdHkgbWF0cmljZXMsIHRoZSByb3dzIGFyZSB0aGUgY2VsbHMgYW5kIHRoZSBjb2x1bW5zIGFyZSB0aGUgUEMgZGltZW5zaW9ucy4KCmBgYHtyIGdldFJlZHVjZWREaW19CiMgZXh0cmFjdCB0aGUgUENBIG1hdHJpeApwY2FfbWF0cml4IDwtIHJlZHVjZWREaW0obm9ybWFsaXplZF9zY2UsICJQQ0EiKQoKIyBsb29rIGF0IHRoZSBzaGFwZSBvZiB0aGUgbWF0cml4CmRpbShwY2FfbWF0cml4KQpgYGAKCiMjIyBVTUFQCgpGaW5hbGx5LCB3ZSB3aWxsIGNhbGN1bGF0ZSBhIFVNQVAgKFVuaWZvcm0gTWFuaWZvbGQgQXBwcm94aW1hdGlvbiBhbmQgUHJvamVjdGlvbikgcmVwcmVzZW50YXRpb24gb2Ygb3VyIGRhdGEuClRoaXMgaXMgYSBtYWNoaW5lLWxlYXJuaW5nLWJhc2VkIG1ldGhvZCB0aGF0IGlzIHVzZWZ1bCBmb3IgcGVyZm9ybWluZyBkaW1lbnNpb25hbGl0eSByZWR1Y3Rpb24gc3VpdGFibGUgZm9yIHZpc3VhbGl6YXRpb24uCkl0J3MgZ29hbCBpcyB0byBwcm92aWRlIGEgcmVwcmVzZW50YXRpb24gb2YgdGhlIGRhdGEgaW4gdHdvIGRpbWVuc2lvbnMgKHR5cGljYWxseSwgbW9yZSBhcmUgcG9zc2libGUpIHRoYXQgcHJlc2VydmVzIGFzIG11Y2ggb2YgdGhlIGRpc3RhbmNlIHJlbGF0aW9uc2hpcHMgYW1vbmcgY2VsbHMgYXMgcG9zc2libGUuCldoaWxlIHRoaXMgZG9lcyBtYWtlIGZvciB2aXN1YWxseSBhcHBlYWxpbmcgYW5kIHVzZWZ1bCBwbG90cywgaXQgaXMgaW1wb3J0YW50IG5vdCB0byBvdmVyaW50ZXJwcmV0IHRoZSByZXN1bHRzIQpJbiBwYXJ0aWN1bGFyLCB3aGlsZSB5b3Ugd2lsbCBvZnRlbiBzZWUgc29tZSBhcHBhcmVudCBjbHVzdGVyaW5nIG9mIGNlbGxzIGluIHRoZSByZXN1bHRpbmcgb3V0cHV0LCB0aG9zZSBjbHVzdGVycyBtYXkgbm90IGJlIHBhcnRpY3VsYXJseSB2YWxpZCwgYW5kIHRoZSBzcGFjaW5nIHdpdGhpbiBvciBiZXR3ZWVuIGNsdXN0ZXJzIG1heSBub3QgcmVmbGVjdCB0cnVlIGRpc3RhbmNlcy4KCkluIG1hbnkgd2F5cyB0aGlzIGlzIGFuYWxvZ291cyB0byB0aGUgcHJvYmxlbSBvZiBwcm9qZWN0aW5nIGEgbWFwIG9mIHRoZSBlYXJ0aCBvbnRvIGEgZmxhdCBzdXJmYWNlOyBhbnkgY2hvaWNlIHdpbGwgcmVzdWx0IGluIHNvbWUgZGlzdG9ydGlvbnMuCkhvd2V2ZXIsIHdpdGggVU1BUCwgd2UgcmFyZWx5IGtub3cgZXhhY3RseSB3aGF0IGNob2ljZXMgd2VyZSBtYWRlIGFuZCB3aGF0IGRpc3RvcnRpb25zIG1pZ2h0IGhhdmUgcmVzdWx0ZWQuClRoZSBVTUFQIGNvb3JkaW5hdGVzIHRoZW1zZWx2ZXMgc2hvdWxkIG5ldmVyIGJlIHVzZWQgZm9yIGRvd25zdHJlYW0gYW5hbHlzaXMuCgpTaW5jZSB0aGUgVU1BUCBwcm9jZWR1cmUgd291bGQgYmUgc2xvdyB0byBjYWxjdWxhdGUgd2l0aCB0aGUgZnVsbCBkYXRhLCBzbyB0aGUgYHJ1blVNQVAoKWAgZnVuY3Rpb24gZmlyc3QgY2FsY3VsYXRlcyBhIFBDQSBtYXRyaXggYW5kIHRoZW4gdXNlcyBfdGhhdF8gdG8gY2FsY3VsYXRlIHRoZSBVTUFQLgpTaW5jZSB3ZSBhbHJlYWR5IGhhdmUgYSBQQ0EgbWF0cml4LCB3ZSB3aWxsIHRlbGwgdGhlIGZ1bmN0aW9uIHVzZSB0aGF0IGluc3RlYWQgb2YgcmVjYWxjdWxhdGluZyBpdC4KCmBgYHtyIHJ1blVNQVAsIGxpdmU9VFJVRX0Kbm9ybWFsaXplZF9zY2UgPC0gc2NhdGVyOjpydW5VTUFQKG5vcm1hbGl6ZWRfc2NlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGltcmVkID0gIlBDQSIpCmBgYAoKQXMgYmVmb3JlLCB3ZSBjb3VsZCBleHRyYWN0IHRoZSBVTUFQIG1hdHJpeCBmcm9tIG91ciBTQ0Ugb2JqZWN0IHdpdGggdGhlIGByZWR1Y2VkRGltKClgIGZ1bmN0aW9uLgpXZSBjYW4gYWxzbyB2aXN1YWxpemUgdGhlIFVNQVAgcmVzdWx0cyB1c2luZyB0aGUgYHBsb3RSZWR1Y2VkRGltKClgIGZ1bmN0aW9uLgoKYGBge3IgcGxvdFJlZHVjZWREaW0sIGxpdmU9VFJVRX0KIyBwbG90IHRoZSBVTUFQCnNjYXRlcjo6cGxvdFJlZHVjZWREaW0obm9ybWFsaXplZF9zY2UsCiAgICAgICAgICAgICAgICAgICAgICAgIlVNQVAiLAogICAgICAgICAgICAgICAgICAgICAgICMgY29sb3IgYnkgdGhlIG1vc3QgdmFyaWFibGUgZ2VuZQogICAgICAgICAgICAgICAgICAgICAgIGNvbG9yX2J5ID0gaHZfZ2VuZXNbMV0pCmBgYAoKCiMjIFVuc3VwZXJ2aXNlZCBjbHVzdGVyaW5nCgpBcyBhIGZpbmFsIGFuYWx5c2lzIHN0ZXAgYXQgdGhpcyBzdGFnZSwgd2Ugd2lsbCByZXR1cm4gdG8gdGhlIFBDQSByZXN1bHRzIHRvIHBlcmZvcm0gdW5zdXBlcnZpc2VkIGNsdXN0ZXJpbmcuCkhlcmUgd2Ugd2lsbCB1c2UgYSBncmFwaC1iYXNlZCBjbHVzdGVyaW5nIG1ldGhvZCwgd2hpY2ggc3RhcnRzIGJ5IGlkZW50aWZ5aW5nIGNlbGxzIHRoYXQgYXJlIGNsb3NlIHRvZ2V0aGVyIGluIHRoZSBtdWx0aWRpbWVuc2lvbmFsIHNwYWNlLgpJdCB0aGVuIGlkZW50aWZpZXMgImNvbW11bml0aWVzIiBvZiBoaWdobHkgY29ubmVjdGVkIGNlbGxzLCBhbmQgYnJlYWtzIHRoZW0gYXBhcnQgYnkgcmVnaW9ucyBvZiBsb3dlciBjb25uZWN0aW9uLgoKVGhlcmUgYXJlIGEgbnVtYmVyIG9mIGFsZ29yaXRobXMgdGhhdCBjYW4gcGVyZm9ybSB0aGlzIGNsdXN0ZXJpbmcsIGVhY2ggd2l0aCBwYXJhbWV0ZXJzIHRoYXQgY2FuIGFmZmVjdCBob3cgbWFueSBjbHVzdGVycyBhcmUgaWRlbnRpZmllZCBhbmQgd2hpY2ggY2VsbHMgYmVsb25nIHRvIGVhY2ggY2x1c3Rlci4KSXQgaXMgYWxzbyB3b3J0aCBub3RpbmcgdGhhdCB0aGVzZSBjbHVzdGVycyBtYXkgb3IgbWF5IG5vdCBjb3JyZXNwb25kIHRvICJjZWxsIHR5cGVzIiBieSB3aGF0ZXZlciBkZWZpbml0aW9uIHlvdSBtaWdodCBwcmVmZXIgdG8gdXNlLgpJbnRlcnByZXRhdGlvbiBvZiB0aGVzZSBjbHVzdGVycywgb3Igb3RoZXIgbWVhc3VyZXMgb2YgY2VsbCB0eXBlLCBhcmUgc29tZXRoaW5nIHRoYXQgd2lsbCByZXF1aXJlIG1vcmUgY2FyZWZ1bCBhbmQgbGlrZWx5IG1vcmUgY3VzdG9taXplZCBhbmFseXNpcy4KCldlIHdpbGwgcGVyZm9ybSBvdXIgY2x1c3RlcmluZyB1c2luZyB0aGUgYGJsdXN0ZXJgIHBhY2thZ2UsIHdoaWNoIGNhbiBwZXJmb3JtIG1hbnkgZGlmZmVyZW50IHR5cGVzIG9mIGNsdXN0ZXJpbmcuCkFzIG1lbnRpb25lZCBlYXJsaWVyLCB3ZSBhcmUgdXNpbmcgImdyYXBoIiBjbHVzdGVyaW5nLCB3aGljaCB3ZSBkZWZpbmUgdXNpbmcgdGhlIGBOTkdyYXBoUGFyYW0oKWAgZnVuY3Rpb24uCldpdGhpbiB0aGF0IGFyZSBhIG51bWJlciBvZiBmdXJ0aGVyIG9wdGlvbnMsIHN1Y2ggYXMgdGhlIHdlaWdodGluZyB1c2VkIGZvciBidWlsZGluZyB0aGUgbmV0d29yayBncmFwaCBhbmQgdGhlIGFsZ29yaXRobSB1c2VkIGZvciBkaXZpZGluZyB0aGUgZ3JhcGggaW50byBjbHVzdGVycy4KCk1vZGlmeWluZyB0aGVzZSBwYXJhbWV0ZXJzIGNhbiByZXN1bHQgaW4gcXVpdGUgZGlmZmVyZW50IGNsdXN0ZXIgYXNzaWdubWVudHMhCkZvciB0aGUgY2x1c3RlcmluZyBiZWxvdyB3ZSB3aWxsIHVzZSBKYWNjYXJkIHdlaWdodGluZyBhbmQgTG91dmFpbiBjbHVzdGVyaW5nLCB3aGljaCBjb3JyZXNwb25kIG1vcmUgY2xvc2VseSB0byB0aGUgZGVmYXVsdCBtZXRob2RzIHVzZWQgYnkgYFNldXJhdGAgdGhhbiB0aGUgZGVmYXVsdCBwYXJhbWV0ZXJzLgpJdCBpcyBhbHNvIHdvcnRoIG5vdGluZyB0aGF0IHRoZSB0aGUgY2x1c3RlciBhc3NpZ25tZW50cyBhcmUgc29tZXdoYXQgc3RvY2hhc3RpYy4KSW4gcGFydGljdWxhciwgdGhlIG5hbWVzL251bWJlcnMgb2YgdGhlIGNsdXN0ZXJzIGNhbiBiZSBxdWl0ZSBpbmNvbnNpc3RlbnQgYmV0d2VlbiBydW5zIQoKCmBgYHtyIGNsdXN0ZXJpbmcsIGxpdmU9VFJVRX0KIyBwZXJmb3JtIGdyYXBoLWJhc2VkIGNsdXN0ZXJpbmcKbm5fY2x1c3RlcnMgPC0gYmx1c3Rlcjo6Y2x1c3RlclJvd3MoCiAgcGNhX21hdHJpeCwKICBibHVzdGVyOjpOTkdyYXBoUGFyYW0oCiAgICAjIG51bWJlciBvZiBuZWlnaGJvcnMgdG8gdXNlIGluIG5ldHdvcmsgZ3JhcGgKICAgIGsgPSAyMCwKICAgICMgd2VpZ2h0aW5nIHNjaGVtZSBmb3IgYnVpbGRpbmcgdGhlIG5ldHdvcmsgZ3JhcGgKICAgICMgZGVmYXVsdCBpcyAicmFuayIKICAgIHR5cGUgPSAiamFjY2FyZCIsCiAgICAjIGNsdXN0ZXIgZGV0ZWN0aW9uIGFsZ29yaXRobQogICAgIyBkZWZhdWx0IGlzICJ3YWxrdHJhcCIKICAgIGNsdXN0ZXIuZnVuID0gImxvdXZhaW4iCiAgKQopCmBgYAoKV2UgY2FuIHNhdmUgdGhlIGNsdXN0ZXIgYXNzaWdubWVudHMgYmFjayBpbnRvIHRoZSBgY29sRGF0YWAgb2YgdGhlIFNDRSBvYmplY3Qgd2l0aCBhIGxpdHRsZSBzaG9ydGN1dDogdGhlIGAkYCBmb2xsb3dlZCBieSB0aGUgbmFtZSBvZiB0aGUgbmV3IGNvbHVtbiB3ZSB3YW50IHRvIGFkZC4KCmBgYHtyIGFkZCBjbHVzdGVycyB0byBTQ0UsIGxpdmU9VFJVRX0KIyBzYXZlIGNsdXN0ZXJzIHRvIFNDRSBjb2xEYXRhCm5vcm1hbGl6ZWRfc2NlJG5uX2NsdXN0ZXIgPC0gbm5fY2x1c3RlcnMKYGBgCgpOb3cgd2UgY2FuIHBsb3QgdGhlIFVNQVAgYWdhaW4sIHRoaXMgdGltZSBjb2xvcmVkIGJ5IHRoZSBjbHVzdGVyIGFzc2lnbm1lbnRzIHRoYXQgd2UganVzdCBjcmVhdGVkLgpIZXJlIHJhdGhlciB0aGFuIHRoZSBnZW5lcmFsIGBwbG90UmVkdWNlZERpbSgpYCBmdW5jdGlvbiwgd2Ugd2lsbCB1c2UgYHBsb3RVTUFQKClgLCB3aGljaCBpcyBleGFjdGx5IHRoZSBzYW1lLCBleGNlcHQgaXQgYWx3YXlzIHBsb3RzIGZyb20gdGhlIGByZWR1Y2VkRGltYCBzbG90IG5hbWVkIGBVTUFQYCwgc28gd2UgY2FuIHNraXAgdGhhdCBhcmd1bWVudC4KCmBgYHtyIHBsb3QgY2x1c3RlcnMsIGxpdmU9VFJVRX0KIyBwbG90IFVNQVAgd2l0aCBhc3NpZ25lZCBjbHVzdGVycwpzY2F0ZXI6OnBsb3RVTUFQKG5vcm1hbGl6ZWRfc2NlLAogICAgICAgICAgICAgICAgIGNvbG9yX2J5ID0gIm5uX2NsdXN0ZXIiKQpgYGAKCldoYXQgZG8geW91IHNlZSBpbiB0aGVzZSByZXN1bHRzPwoKV2hhdCB3b3VsZCB5b3Ugd2FudCB0byBkbyBuZXh0PwoKIyMgU2F2ZSBTQ0Ugb2JqZWN0IGZvciBsYXRlcgoKV2Ugd2lsbCBub3cgc2F2ZSBvdXIgZmlsdGVyZWQgYW5kIG5vcm1hbGl6ZWQgb2JqZWN0LCBpbmNsdWRpbmcgdGhlIGRpbWVuc2lvbiByZWR1Y3Rpb24gYW5kIGNsdXN0ZXJpbmcgcmVzdWx0cyB0byBhbiBgUkRTYCBmaWxlLCB1c2luZyB0aGUgZmlsZSBwYXRoIHRoYXQgd2UgZGVmaW5lZCBhdCB0aGUgc3RhcnQgb2YgdGhlIG5vdGVib29rLgpJZiB3ZSB3ZXJlIHRvIHdhbnQgdG8gcmV0dXJuIHRvIHRoaXMgZGF0YSwgd2UgY291bGQgbG9hZCB0aGlzIGZpbGUgZGlyZWN0bHkgaW50byBhIG5ldyBSIHNlc3Npb24gYW5kIG5vdCBoYXZlIHRvIHJlcGVhdCB0aGUgcHJvY2Vzc2luZyB0aGF0IHdlIGhhdmUgZG9uZSB1cCB0byB0aGlzIHBvaW50LgoKVGhlIGRhdGEgaW4gdGhlc2Ugb2JqZWN0cyB0ZW5kcyB0byBiZSBxdWl0ZSBsYXJnZSwgYnV0IHZlcnkgY29tcHJlc3NpYmxlLgpUbyBzYXZlIHNwYWNlIG9uIGRpc2sgKGF0IHRoZSBleHBlbnNlIG9mIHRpbWUpLCB3ZSB3aWxsIG1ha2Ugc3VyZSB0aGF0IHRoZSBkYXRhIGlzIGNvbXByZXNzZWQgaW50ZXJuYWxseSBiZWZvcmUgd3JpdGluZyBpdCBvdXQgdG8gYSBmaWxlLgpOb3RlIHRoYXQgdGhlIGZpbGUgd2Ugd3JpdGUgaXMgc3RpbGwgZ29pbmcgdG8gYmUgYW4gYC5yZHNgIGZpbGUgd2l0aCBubyBhZGRpdGlvbmFsIGV4dGVuc2lvbi4KKEZ1cnRoZXIgbm90ZTogVGhlIGJhc2UgUiBmdW5jdGlvbiBgc2F2ZVJEUygpYCB1c2VzIGNvbXByZXNzaW9uIGJ5IGRlZmF1bHQsIGJ1dCB0aGUgYHRpZHl2ZXJzZWAgZnVuY3Rpb24gYHJlYWRyOjp3cml0ZV9yZHMoKWAgZG9lcyBub3QuKQoKYGBge3Igc2F2ZSBTQ0UsIGxpdmU9VFJVRX0KIyB3cml0ZSBSRFMgZmlsZSB3aXRoIGNvbXByZXNzaW9uCnJlYWRyOjp3cml0ZV9yZHMobm9ybWFsaXplZF9zY2UsIGZpbGUgPSBvdXRwdXRfc2NlX2ZpbGUsIGNvbXByZXNzID0gImd6IikKYGBgCgoKIyMgUHJpbnQgc2Vzc2lvbiBpbmZvCgpBcyBpcyBvdXIgaGFiaXQgYXQgdGhlIERhdGEgTGFiLCB3ZSB3aWxsIHNhdmUgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGNvbXB1dGluZyBlbnZpcm9ubWVudCwgdGhlIHBhY2thZ2VzIHdlIGhhdmUgdXNlZCBpbiB0aGlzIG5vdGVib29rLCBhbmQgdGhlaXIgdmVyc2lvbnMgdXNpbmcgdGhlIGBzZXNzaW9uSW5mbygpYCBjb21tYW5kLgoKYGBge3Igc2Vzc2lvbiBpbmZvfQpzZXNzaW9uSW5mbygpCmBgYAoK
diff --git a/scRNA-seq-advanced/02-dataset_integration-live.Rmd b/scRNA-seq-advanced/02-dataset_integration-live.Rmd index 8dfb894f..107bc35c 100644 --- a/scRNA-seq-advanced/02-dataset_integration-live.Rmd +++ b/scRNA-seq-advanced/02-dataset_integration-live.Rmd @@ -525,13 +525,12 @@ Now, let's see how this new `merged_UMAP` looks compared to the `UMAP` calculate # UMAPs scaled together when calculated from the merged SCE scater::plotReducedDim(merged_sce, dimred = "merged_UMAP", - colour_by = "sample", + color_by = "sample", # Some styling to help us see the points: point_size = 0.5, point_alpha = 0.2) + - # Modify the legend key so its points are larger and easier to see - guides(colour = guide_legend(override.aes = list(size = 3, alpha = 1))) + - # Add a plot title + scale_color_brewer(palette = "Dark2", name = "sample") + + guides(color = guide_legend(override.aes = list(size = 3, alpha = 1))) + ggtitle("UMAP calculated on merged_sce") ``` @@ -596,13 +595,12 @@ scater::plotReducedDim(merged_sce, # plot the fastMNN coordinates dimred = "fastmnn_UMAP", # color by sample - colour_by = "sample", + color_by = "sample", # Some styling to help us see the points: point_size = 0.5, point_alpha = 0.2) + - # Modify legend so they key is larger and easier to see - guides(colour = guide_legend(override.aes = list(size = 3, alpha = 1))) + - # add plot title + scale_color_brewer(palette = "Dark2", name = "sample") + + guides(color = guide_legend(override.aes = list(size = 3, alpha = 1))) + ggtitle("UMAP after integration with fastMNN") ``` @@ -642,10 +640,12 @@ Let's re-plot this UMAP to highlight cell types: scater::plotReducedDim(merged_sce, dimred = "fastmnn_UMAP", # color by broad celltypes - colour_by = "celltype_broad", + color_by = "celltype_broad", point_size = 0.5, point_alpha = 0.2) + - guides(colour = guide_legend(override.aes = list(size = 3, alpha = 1))) + + # include argument to specify color of NA values + scale_color_brewer(palette = "Dark2", name = "Broad celltype", na.value = "grey80") + + guides(color = guide_legend(override.aes = list(size = 3, alpha = 1))) + ggtitle("UMAP after integration with fastMNN") ``` @@ -658,12 +658,13 @@ One way we can see all the points a bit better is to facet the plot by sample, u ```{r plot fastmnn umap celltypes faceted} scater::plotReducedDim(merged_sce, dimred = "fastmnn_UMAP", - colour_by = "celltype_broad", + color_by = "celltype_broad", point_size = 0.5, point_alpha = 0.2, # Allow for faceting by a variable using `other_fields`: other_fields = "sample") + - guides(colour = guide_legend(override.aes = list(size = 3, alpha = 1))) + + scale_color_brewer(palette = "Dark2", name = "Broad celltype", na.value = "grey80") + + guides(color = guide_legend(override.aes = list(size = 3, alpha = 1))) + ggtitle("UMAP after integration with fastMNN") + # Facet by sample facet_wrap(vars(sample)) + @@ -743,11 +744,12 @@ Let's see how the `harmony` UMAP, colored by sample, looks compared to the `fast ```{r plot harmony umap batches} scater::plotReducedDim(merged_sce, dimred = "harmony_UMAP", - colour_by = "sample", + color_by = "sample", point_size = 0.5, point_alpha = 0.2) + - ggtitle("UMAP after integration with harmony") + - guides(colour = guide_legend(override.aes = list(size = 3, alpha = 1))) + scale_color_brewer(palette = "Dark2", name = "sample") + + guides(color = guide_legend(override.aes = list(size = 3, alpha = 1))) + + ggtitle("UMAP after integration with harmony") ``` How do you think this `harmony` UMAP compares to that from `fastMNN` integration? @@ -757,19 +759,19 @@ Let's see how this UMAP looks colored by cell type, and faceted for visibility: ```{r plot harmony umap celltypes} scater::plotReducedDim(merged_sce, dimred = "harmony_UMAP", - colour_by = "celltype_broad", + color_by = "celltype_broad", point_size = 0.5, point_alpha = 0.2, # Specify variable for faceting other_fields = "sample") + + scale_color_brewer(palette = "Dark2", name = "Broad celltype", na.value = "grey80") + + guides(color = guide_legend(override.aes = list(size = 3))) + ggtitle("UMAP after integration with harmony") + - guides(colour = guide_legend(override.aes = list(size = 3))) + facet_wrap(vars(sample)) ``` -With the faceted view, we can now see that the small amounts of `Tumor_Myocyte` from other samples are "pulled" towards those cells in `SCPCL000481`. - -What other patterns do you see that are similar or different from the `fastMNN` UMAP? +What do you now notice in this faceted view that wasn't clear previously? +Are there other patterns you see that are similar or different from the `fastMNN` UMAP? How do you think `fastMNN` vs. `harmony` performed in integrating these samples? ### Export diff --git a/scRNA-seq-advanced/02-dataset_integration.nb.html b/scRNA-seq-advanced/02-dataset_integration.nb.html index 0a991051..ff74f293 100644 --- a/scRNA-seq-advanced/02-dataset_integration.nb.html +++ b/scRNA-seq-advanced/02-dataset_integration.nb.html @@ -3091,7 +3091,7 @@

Directories and files

To begin, let’s set up our directories and files:

- +
# Define directory where processed SCE objects to be integrated are stored
 input_dir <- file.path("data", "rms", "processed")
 
@@ -3099,9 +3099,7 @@ 

Directories and files

output_dir <- file.path("data", "rms", "integrated") # Create output directory if it doesn't exist -if (!(dir.exists(output_dir))) { - dir.create(output_dir) -} +fs::dir_create(output_dir) # Define output file name for the integrated object integrated_sce_file <- file.path(output_dir, "rms_integrated_subset.rds")
@@ -4116,18 +4114,23 @@

Integration

let’s look at the UMAP when calculated from individual samples:

- +
# Plot UMAP calculated from individual samples with separate scaling
 scater::plotReducedDim(merged_sce,
                        dimred = "UMAP",
-                       colour_by = "sample",
+                       color_by = "sample",
                        point_size = 0.5,
                        point_alpha = 0.2) +
-  guides(colour = guide_legend(override.aes = list(size = 3, alpha = 1))) +
+  scale_color_brewer(palette = "Dark2", name = "sample") + # Use a CVD-friendly color scheme and specify legend name
+  guides(color = guide_legend(override.aes = list(size = 3, alpha = 1))) + # Modify the legend key with larger, easier to see points
   ggtitle("UMAP calculated on each sample separately")
+ +
Scale for colour is already present.
+Adding another scale for colour, which will replace the existing scale.
+ -

+

@@ -4252,21 +4255,24 @@

Integration

to the UMAP calculated from individual samples:

- +
# UMAPs scaled together when calculated from the merged SCE
 scater::plotReducedDim(merged_sce,
                        dimred = "merged_UMAP",
-                       colour_by = "sample",
+                       color_by = "sample",
                        # Some styling to help us see the points:
                        point_size = 0.5,
                        point_alpha = 0.2) +
-  # Modify the legend key so its points are larger and easier to see
-  guides(colour = guide_legend(override.aes = list(size = 3, alpha = 1))) +
-  # Add a plot title
+  scale_color_brewer(palette = "Dark2", name = "sample") +
+  guides(color = guide_legend(override.aes = list(size = 3, alpha = 1))) +
   ggtitle("UMAP calculated on merged_sce")
+ +
Scale for colour is already present.
+Adding another scale for colour, which will replace the existing scale.
+ -

+

@@ -4382,22 +4388,25 @@

Integration with fastMNN

chapter of OSCA.

- +
scater::plotReducedDim(merged_sce,
                        # plot the fastMNN coordinates
                        dimred = "fastmnn_UMAP",
                        # color by sample
-                       colour_by = "sample",
+                       color_by = "sample",
                        # Some styling to help us see the points:
                        point_size = 0.5,
                        point_alpha = 0.2) +
-  # Modify legend so they key is larger and easier to see
-  guides(colour = guide_legend(override.aes = list(size = 3, alpha = 1))) +
-  # add plot title
+  scale_color_brewer(palette = "Dark2", name = "sample") +
+  guides(color = guide_legend(override.aes = list(size = 3, alpha = 1))) +
   ggtitle("UMAP after integration with fastMNN")
+ +
Scale for colour is already present.
+Adding another scale for colour, which will replace the existing scale.
+ -

+

@@ -4444,18 +4453,24 @@

Integration with fastMNN

Let’s re-plot this UMAP to highlight cell types:

- +
scater::plotReducedDim(merged_sce,
                        dimred = "fastmnn_UMAP",
                        # color by broad celltypes
-                       colour_by = "celltype_broad",
+                       color_by = "celltype_broad",
                        point_size = 0.5,
                        point_alpha = 0.2) +
-  guides(colour = guide_legend(override.aes = list(size = 3, alpha = 1))) +
+  # include argument to specify color of NA values
+  scale_color_brewer(palette = "Dark2", name = "Broad celltype", na.value = "grey80") +
+  guides(color = guide_legend(override.aes = list(size = 3, alpha = 1))) +
   ggtitle("UMAP after integration with fastMNN")
+ +
Scale for colour is already present.
+Adding another scale for colour, which will replace the existing scale.
+ -

+

@@ -4473,23 +4488,28 @@

Integration with fastMNN

object):

- +
scater::plotReducedDim(merged_sce,
                        dimred = "fastmnn_UMAP",
-                       colour_by = "celltype_broad",
+                       color_by = "celltype_broad",
                        point_size = 0.5,
                        point_alpha = 0.2,
                        # Allow for faceting by a variable using `other_fields`:
                        other_fields = "sample") +
-  guides(colour = guide_legend(override.aes = list(size = 3, alpha = 1))) +
+  scale_color_brewer(palette = "Dark2", name = "Broad celltype", na.value = "grey80") +
+  guides(color = guide_legend(override.aes = list(size = 3, alpha = 1))) +
   ggtitle("UMAP after integration with fastMNN") +
   # Facet by sample
   facet_wrap(vars(sample)) +
   # Use a theme with background grid to more easily compare panel coordinates
   theme_bw()
+ +
Scale for colour is already present.
+Adding another scale for colour, which will replace the existing scale.
+ -

+

@@ -4639,17 +4659,22 @@

Integration with harmony

compared to the fastMNN UMAP:

- +
scater::plotReducedDim(merged_sce,
                        dimred = "harmony_UMAP",
-                       colour_by = "sample",
+                       color_by = "sample",
                        point_size = 0.5,
                        point_alpha = 0.2) +
-  ggtitle("UMAP after integration with harmony") +
-  guides(colour = guide_legend(override.aes = list(size = 3, alpha = 1)))
+ scale_color_brewer(palette = "Dark2", name = "sample") + + guides(color = guide_legend(override.aes = list(size = 3, alpha = 1))) + + ggtitle("UMAP after integration with harmony") + +
Scale for colour is already present.
+Adding another scale for colour, which will replace the existing scale.
+ -

+

@@ -4659,29 +4684,33 @@

Integration with harmony

visibility:

- +
scater::plotReducedDim(merged_sce,
                        dimred = "harmony_UMAP",
-                       colour_by = "celltype_broad",
+                       color_by = "celltype_broad",
                        point_size = 0.5,
                        point_alpha = 0.2,
                        # Specify variable for faceting
                        other_fields = "sample") +
+  scale_color_brewer(palette = "Dark2", name = "Broad celltype", na.value = "grey80") +
+  guides(color = guide_legend(override.aes = list(size = 3))) +
   ggtitle("UMAP after integration with harmony") +
-  guides(colour = guide_legend(override.aes = list(size = 3))) +
   facet_wrap(vars(sample))
+ +
Scale for colour is already present.
+Adding another scale for colour, which will replace the existing scale.
+ -

+

-

With the faceted view, we can now see that the small amounts of -Tumor_Myocyte from other samples are “pulled” towards those -cells in SCPCL000481.

-

What other patterns do you see that are similar or different from the -fastMNN UMAP? How do you think fastMNN -vs. harmony performed in integrating these samples?

+

What do you now notice in this faceted view that wasn’t clear +previously? Are there other patterns you see that are similar or +different from the fastMNN UMAP? How do you think +fastMNN vs. harmony performed in integrating +these samples?

Export

@@ -4712,7 +4741,7 @@

Print session info

sessionInfo()
- +
R version 4.4.1 (2024-06-14)
 Platform: x86_64-pc-linux-gnu
 Running under: Ubuntu 22.04.4 LTS
@@ -4763,8 +4792,8 @@ 

Print session info

[31] DelayedArray_0.30.0 BiocParallel_1.38.0 [33] irlba_2.3.5.1 parallel_4.4.1 [35] cluster_2.1.6 R6_2.5.1 - [37] RColorBrewer_1.1-3 bslib_0.7.0 - [39] stringi_1.8.3 limma_3.60.0 + [37] bslib_0.7.0 stringi_1.8.3 + [39] RColorBrewer_1.1-3 limma_3.60.0 [41] jquerylib_0.1.4 Rcpp_1.0.12 [43] knitr_1.46 readr_2.1.5 [45] batchelor_1.20.0 Matrix_1.7-0 @@ -4781,26 +4810,26 @@

Print session info

[67] RhpcBLASctl_0.23-42 glue_1.7.0 [69] metapod_1.12.0 tools_4.4.1 [71] BiocNeighbors_1.22.0 ScaledMatrix_1.12.0 - [73] locfit_1.5-9.9 scran_1.32.0 - [75] cowplot_1.1.3 grid_4.4.1 - [77] edgeR_4.2.0 colorspace_2.1-0 - [79] GenomeInfoDbData_1.2.12 beeswarm_0.4.0 - [81] BiocSingular_1.20.0 vipor_0.4.7 - [83] cli_3.6.2 rsvd_1.0.5 - [85] fansi_1.0.6 S4Arrays_1.4.0 - [87] viridisLite_0.4.2 dplyr_1.1.4 - [89] uwot_0.2.2 ResidualMatrix_1.14.0 - [91] gtable_0.3.5 sass_0.4.9 - [93] digest_0.6.35 SparseArray_1.4.0 - [95] ggrepel_0.9.5 dqrng_0.3.2 - [97] farver_2.1.1 htmltools_0.5.8.1 - [99] lifecycle_1.0.4 httr_1.4.7 - [ reached getOption("max.print") -- omitted 2 entries ]
+ [73] locfit_1.5-9.9 fs_1.6.4 + [75] scran_1.32.0 cowplot_1.1.3 + [77] grid_4.4.1 edgeR_4.2.0 + [79] colorspace_2.1-0 GenomeInfoDbData_1.2.12 + [81] beeswarm_0.4.0 BiocSingular_1.20.0 + [83] vipor_0.4.7 cli_3.6.2 + [85] rsvd_1.0.5 fansi_1.0.6 + [87] S4Arrays_1.4.0 viridisLite_0.4.2 + [89] dplyr_1.1.4 uwot_0.2.2 + [91] ResidualMatrix_1.14.0 gtable_0.3.5 + [93] sass_0.4.9 digest_0.6.35 + [95] SparseArray_1.4.0 ggrepel_0.9.5 + [97] dqrng_0.3.2 farver_2.1.1 + [99] htmltools_0.5.8.1 lifecycle_1.0.4 + [ reached getOption("max.print") -- omitted 3 entries ]
-
LS0tCnRpdGxlOiAiSW50ZWdyYXRpbmcgc2NSTkEtc2VxIGRhdGFzZXRzIgphdXRob3I6IERhdGEgTGFiIGZvciBBTFNGCmRhdGU6IDIwMjMKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMwogICAgdG9jX2Zsb2F0OiB0cnVlCi0tLQoKIyMgT2JqZWN0aXZlcwoKVGhpcyBub3RlYm9vayB3aWxsIGRlbW9uc3RyYXRlIGhvdyB0bzoKCi0gUHJlcGFyZSBTQ0Ugb2JqZWN0cyBmb3IgaW50ZWdyYXRpb24KLSBBcHBseSBpbnRlZ3JhdGlvbiBtZXRob2RzIGluY2x1ZGluZyBgZmFzdE1OTmAgYW5kIGBoYXJtb255YAotIFZpc3VhbGx5IGV4cGxvcmUgdGhlIHJlc3VsdHMgb2YgaW50ZWdyYXRpb24KLSBVc2UgYHB1cnJyOjptYXAoKWAgZnVuY3Rpb25zIGZvciBpdGVyYXRpbmcgb3ZlciBsaXN0cwoKLS0tCgpJbiB0aGlzIG5vdGVib29rLCB3ZSdsbCBwZXJmb3JtIGludGVncmF0aW9uIG9uIHNjUk5BLXNlcSBkYXRhc2V0cyBmcm9tIHRoZSBbU2luZ2xlLWNlbGwgUGVkaWF0cmljIENhbmNlciBBdGxhcyAoYFNjUENBYCldKGh0dHBzOi8vc2NwY2EuYWxleHNsZW1vbmFkZS5vcmcvKSwgYSBkYXRhYmFzZSBvZiB1bmlmb3JtbHktcHJvY2Vzc2VkIHBlZGlhdHJpYyBzY1JOQS1zZXEgZGF0YSBidWlsdCBhbmQgbWFpbnRhaW5lZCBieSB0aGUgRGF0YSBMYWIuClRoZSBgU2NQQ0FgIGRhdGFiYXNlIGN1cnJlbnRseSBob3N0cyBzaW5nbGUtY2VsbCBwZWRpYXRyaWMgY2FuY2VyIHRyYW5zY3JpcHRvbWljIGRhdGEgZ2VuZXJhdGVkIGJ5IEFMU0YtZnVuZGVkIGxhYnMsIHdpdGggdGhlIGdvYWwgb2YgbWFraW5nIHRoaXMgZGF0YSBlYXNpbHkgYWNjZXNzaWJsZSB0byBpbnZlc3RpZ2F0b3JzIChsaWtlIHlvdSEpLgpUaGUgZXhwcmVzc2lvbiBkYXRhIGluIGBTY1BDQWAgd2VyZSBtYXBwaW5nIGFuZCBxdWFudGlmaWVkIHdpdGggW2BhbGV2aW4tZnJ5YF0oaHR0cHM6Ly9kb2kub3JnLzEwLjEwMzgvczQxNTkyLTAyMi0wMTQwOC0zKSwgZm9sbG93ZWQgYnkgcHJvY2Vzc2luZyB3aXRoIEJpb2NvbmR1Y3RvciB0b29scyB1c2luZyB0aGUgc2FtZSBnZW5lcmFsIHByb2NlZHVyZXMgdGhhdCB3ZSBoYXZlIGNvdmVyZWQgaW4gdGhpcyB3b3Jrc2hvcC4KVGhlIHByb2Nlc3NpbmcgcGlwZWxpbmUgdXNlZCBgZW1wdHlEcm9wc0NlbGxSYW5nZXIoKWAgYW5kIGBtaVFDYCB0byBmaWx0ZXIgdGhlIHJhdyBjb3VudHMgbWF0cml4LCBgc2N1dHRsZWAgdG8gbG9nLW5vcm1hbGl6ZSB0aGUgY291bnRzLCBhbmQgYHNjYXRlcmAgZm9yIGRpbWVuc2lvbiByZWR1Y3Rpb24uClRoZSBwcm9jZXNzZWQgZGF0YSBhcmUgc3RvcmVkIGFzIGAucmRzYCBmaWxlcyBjb250YWluaW5nIGBTaW5nbGVDZWxsRXhwZXJpbWVudGAgb2JqZWN0cy4KWW91IGNhbiByZWFkIG1vcmUgYWJvdXQgaG93IGRhdGEgaW4gdGhlIGBTY1BDQWAgaXMgcHJvY2Vzc2VkIGluIFt0aGUgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uXShodHRwczovL3NjcGNhLnJlYWR0aGVkb2NzLmlvL2VuL2xhdGVzdC8pLgoKCiFbU2luZ2xlLWNlbGwgcm9hZG1hcDogSW50ZWdyYXRpb24gT3ZlcnZpZXddKGRpYWdyYW1zL3JvYWRtYXBfbXVsdGlfbWVyZ2UtaW50ZWdyYXRlLnBuZykKClRvIGxlYXJuIGFib3V0IGludGVncmF0aW9uLCB3ZSdsbCBoYXZlIGEgbG9vayBhdCBmb3VyIHNhbXBsZXMgZnJvbSB0aGUgW2BTQ1BDUDAwMDAwNWAgcHJvamVjdF0oaHR0cHM6Ly9zY3BjYS5hbGV4c2xlbW9uYWRlLm9yZy9wcm9qZWN0cy9TQ1BDUDAwMDAwNSkgKFtQYXRlbCBfZXQgYWwuXyAyMDIyXShodHRwczovL2RvaS5vcmcvMTAuMTAxNi9qLmRldmNlbC4yMDIyLjA0LjAwMykpLCBhbiBpbnZlc3RpZ2F0aW9uIG9mIHBlZGlhdHJpYyBzb2xpZCB0dW1vcnMgbGVkIGJ5IHRoZSBbRHllcl0oaHR0cHM6Ly93d3cuc3RqdWRlLm9yZy9yZXNlYXJjaC9sYWJzL2R5ZXItbGFiLmh0bWwpIGFuZCBbQ2hlbl0oaHR0cHM6Ly93d3cuc3RqdWRlLm9yZy9yZXNlYXJjaC9sYWJzL2NoZW4tbGFiLXRhb3NoZW5nLmh0bWwpIGxhYnMgYXQgU3QuIEp1ZGUgQ2hpbGRyZW4ncyBSZXNlYXJjaCBIb3NwaXRhbC4KVGhlIHBhcnRpY3VsYXIgbGlicmFyaWVzIHdlJ2xsIGludGVncmF0ZSBjb21lIGZyb20gdHdvIHJoYWJkb215b3NhcmNvbWEgKFJNUykgcGF0aWVudHMsIHdpdGggdHdvIHNhbXBsZXMgZnJvbSBlYWNoIG9mIHR3byBwYXRpZW50cywgYWxsIHNlcXVlbmNlZCB3aXRoIDEweCBDaHJvbWl1bSB2MyB0ZWNobm9sb2d5LgpFYWNoIGxpYnJhcnkgaXMgZnJvbSBhIHNlcGFyYXRlIGJpb2xvZ2ljYWwgc2FtcGxlLgoKV2UnbGwgYmUgaW50ZWdyYXRpbmcgdGhlc2Ugc2FtcGxlcyB3aXRoIHR3byBkaWZmZXJlbnQgdG9vbHMsIFtgZmFzdE1OTmBdKGh0dHA6Ly93d3cuYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy8zLjE2L2Jpb2MvaHRtbC9iYXRjaGVsb3IuaHRtbCkgKFtIYWdodmVyZGkgX2V0IGFsLl8gMjAxOF0oaHR0cHM6Ly9kb2kub3JnLzEwLjEwMzgvbmJ0LjQwOTEpKSBhbmQgW2BoYXJtb255YF0oaHR0cHM6Ly9wb3J0YWxzLmJyb2FkaW5zdGl0dXRlLm9yZy9oYXJtb255LykgKFtLb3JzdW5za3kgX2V0IGFsLl8gMjAxOV0oaHR0cHM6Ly9kb2kub3JnLzEwLjEwMzgvczQxNTkyLTAxOS0wNjE5LTApKS4KSW50ZWdyYXRpb24gY29ycmVjdHMgZm9yIGJhdGNoIGVmZmVjdHMgdGhhdCBhcmlzZSBmcm9tIGRpZmZlcmVudCBsaWJyYXJ5IHByZXBhcmF0aW9ucywgZ2VuZXRpYyBiYWNrZ3JvdW5kcywgYW5kIG90aGVyIHNhbXBsZS1zcGVjaWZpYyBmYWN0b3JzLCBzbyB0aGF0IGRhdGFzZXRzIGNhbiBiZSBqb2ludGx5IGFuYWx5emVkIGF0IHRoZSBjZWxsIGxldmVsLgpgZmFzdE1OTmAgY29ycmVjdHMgZm9yIGJhdGNoIGVmZmVjdHMgdXNpbmcgYSBmYXN0ZXIgdmFyaWFudCBvZiB0aGUgbXV0dWFsLW5lYXJlc3QgbmVpZ2hib3JzIGFsZ29yaXRobSwgdGhlIHRlY2huaWNhbCBkZXRhaWxzIG9mIHdoaWNoIHlvdSBjYW4gbGVhcm4gbW9yZSBhYm91dCBmcm9tIHRoaXMgW3ZpZ25ldHRlIGJ5IEx1biAoMjAxOSldKGh0dHBzOi8vbWFyaW9uaWxhYi5naXRodWIuaW8vRnVydGhlck1OTjIwMTgvdGhlb3J5L2Rlc2NyaXB0aW9uLmh0bWwpLgpgaGFybW9ueWAsIG9uIHRoZSBvdGhlciBoYW5kLCBjb3JyZWN0cyBmb3IgYmF0Y2ggZWZmZWN0cyB1c2luZyBhbiBpdGVyYXRpdmUgY2x1c3RlcmluZyBhcHByb2FjaCwgYW5kIHVubGlrZSBgZmFzdE1OTmAsIGl0IGlzIGFsc28gYWJsZSB0byBjb25zaWRlciBhZGRpdGlvbmFsIGNvdmFyaWF0ZXMgYmV5b25kIGp1c3QgdGhlIGJhdGNoIGdyb3VwaW5ncy4KClJlZ2FyZGxlc3Mgb2Ygd2hpY2ggaW50ZWdyYXRpb24gdG9vbCBpcyB1c2VkLCB0aGUgYFNpbmdsZUNlbGxFeHBlcmltZW50YCAoU0NFKSBvYmplY3RzIGZpcnN0IG5lZWQgdG8gYmUgcmVmb3JtYXR0ZWQgYW5kIG1lcmdlZCBpbnRvIGEgc2luZ2xlICh1bmNvcnJlY3RlZCEpIFNDRSBvYmplY3QgdGhhdCBjb250YWlucyBhbGwgY2VsbHMgZnJvbSBhbGwgc2FtcGxlcy4KVGhpcyBtZXJnZWQgU0NFIGNhbiB0aGVuIGJlIHVzZWQgZm9yIGludGVncmF0aW9uIHRvIG9idGFpbiBhIGZvcm1hbGx5IGJhdGNoLWNvcnJlY3RlZCBTQ0Ugb2JqZWN0LgoKCiMjIFNldCB1cAoKYGBge3Igc2V0dXB9CiMgTG9hZCBsaWJyYXJpZXMKbGlicmFyeShnZ3Bsb3QyKSAgIyBwbG90dGluZyB0b29scwpsaWJyYXJ5KFNpbmdsZUNlbGxFeHBlcmltZW50KSAjIHdvcmsgd2l0aCBTQ0Ugb2JqZWN0cwoKIyBTZXQgdGhlIHNlZWQgZm9yIHJlcHJvZHVjaWJpbGl0eQpzZXQuc2VlZCgxMjM0NSkKYGBgCgoKIyMjIERpcmVjdG9yaWVzIGFuZCBmaWxlcwoKCldlIGhhdmUgYWxyZWFkeSBwcmVwYXJlZCBjb3VudCBkYXRhIGZvciB0aGUgZm91ciBzYW1wbGVzIHdlJ2xsIGJlIGludGVncmF0aW5nIChpLmUuLCBmaWx0ZXJlZCBjZWxscywgbm9ybWFsaXplZCBjb3VudHMsIGFuZCBjYWxjdWxhdGVkIFBDQSAmIFVNQVApLgpUaGVzZSBTQ0Ugb2JqZWN0cywgc3RvcmVkIGFzIFJEUyBmaWxlcywgYXJlIGF2YWlsYWJsZSBpbiB0aGUgYGRhdGEvcm1zL3Byb2Nlc3NlZC9gIGRpcmVjdG9yeSBhbmQgYXJlIG5hbWVkIGFjY29yZGluZyB0byB0aGVpciBgU2NQQ0FgIGxpYnJhcnkgaWRzIDoKCi0gYFNDUENMMDAwNDc5LnJkc2AgKFBhdGllbnQgQSkKLSBgU0NQQ0wwMDA0ODAucmRzYCAoUGF0aWVudCBBKQotIGBTQ1BDTDAwMDQ4MS5yZHNgIChQYXRpZW50IEIpCi0gYFNDUENMMDAwNDgyLnJkc2AgKFBhdGllbnQgQikKClRvIGJlZ2luLCBsZXQncyBzZXQgdXAgb3VyIGRpcmVjdG9yaWVzIGFuZCBmaWxlczoKCmBgYHtyIGRpcmVjdG9yaWVzLCBsaXZlID0gVFJVRX0KIyBEZWZpbmUgZGlyZWN0b3J5IHdoZXJlIHByb2Nlc3NlZCBTQ0Ugb2JqZWN0cyB0byBiZSBpbnRlZ3JhdGVkIGFyZSBzdG9yZWQKaW5wdXRfZGlyIDwtIGZpbGUucGF0aCgiZGF0YSIsICJybXMiLCAicHJvY2Vzc2VkIikKCiMgRGVmaW5lIGRpcmVjdG9yeSB0byBzYXZlIGludGVncmF0ZWQgU0NFIG9iamVjdCB0bwpvdXRwdXRfZGlyIDwtIGZpbGUucGF0aCgiZGF0YSIsICJybXMiLCAiaW50ZWdyYXRlZCIpCgojIENyZWF0ZSBvdXRwdXQgZGlyZWN0b3J5IGlmIGl0IGRvZXNuJ3QgZXhpc3QKaWYgKCEoZGlyLmV4aXN0cyhvdXRwdXRfZGlyKSkpIHsKICBkaXIuY3JlYXRlKG91dHB1dF9kaXIpCn0KCiMgRGVmaW5lIG91dHB1dCBmaWxlIG5hbWUgZm9yIHRoZSBpbnRlZ3JhdGVkIG9iamVjdAppbnRlZ3JhdGVkX3NjZV9maWxlIDwtIGZpbGUucGF0aChvdXRwdXRfZGlyLCAicm1zX2ludGVncmF0ZWRfc3Vic2V0LnJkcyIpCmBgYAoKCldlIGNhbiB1c2UgdGhlIGBkaXIoKWAgZnVuY3Rpb24gdG8gbGlzdCBhbGwgY29udGVudHMgb2YgYSBnaXZlbiBkaXJlY3RvcnksIGZvciBleGFtcGxlIHRvIHNlZSBhbGwgdGhlIGZpbGVzIGluIG91ciBgaW5wdXRfZGlyYDoKCmBgYHtyIGlucHV0IGRpciwgbGl2ZSA9IFRSVUV9CmRpcihpbnB1dF9kaXIpCmBgYAoKV2Ugd2FudCB0byByZWFkIGluIGp1c3QgZm91ciBvZiB0aGVzZSBmaWxlcywgYXMgbGlzdGVkIHByZXZpb3VzbHkuClRvIHJlYWQgaW4gdGhlc2UgZmlsZXMsIHdlIGNvdWxkIHVzZSB0aGUgYHJlYWRyOjpyZWFkX3JkcygpYCBmdW5jdGlvbiAob3IgdGhlIGJhc2UgUiBgcmVhZFJEUygpYCkgZm91ciB0aW1lcywgb25jZSBmb3IgZWFjaCBvZiB0aGUgZmlsZXMuCldlIGNvdWxkIGFsc28gdXNlIGEgYGZvcmAgbG9vcCwgd2hpY2ggaXMgdGhlIGFwcHJvYWNoIHRoYXQgbWFueSBwcm9ncmFtbWluZyBsYW5ndWFnZXMgd291bGQgbGVhbiB0b3dhcmQuCkEgZGlmZmVyZW50IGFuZCBtb3JlIG1vZHVsYXIgY29kaW5nIGFwcHJvYWNoIHRvIHJlYWRpbmcgaW4gdGhlc2UgZmlsZXMgKGFuZCBtb3JlISkgaXMgdG8gbGV2ZXJhZ2UgdGhlIFtgcHVycnJgXShodHRwczovL3B1cnJyLnRpZHl2ZXJzZS5vcmcvKSBgdGlkeXZlcnNlYCBwYWNrYWdlLCB3aGljaCBwcm92aWRlcyBhIGNvbnZlbmllbnQgc2V0IG9mIGZ1bmN0aW9ucyBmb3Igb3BlcmF0aW5nIG9uIGxpc3RzLgpZb3UgY2FuIHJlYWQgbW9yZSBhYm91dCB0aGUgYHB1cnJyYCBmdW5jdGlvbnMgYW5kIHRoZWlyIHBvd2VyIGFuZCB1dGlsaXR5IGluIFIgaW4gW3RoZSAiRnVuY3Rpb25hbHMiIGNoYXB0ZXIgb2YgdGhlIF9BZHZhbmNlZCBSXyBlLWJvb2tdKGh0dHBzOi8vYWR2LXIuaGFkbGV5Lm56L2Z1bmN0aW9uYWxzLmh0bWwpLgoKT2YgcGFydGljdWxhciBpbnRlcmVzdCBpcyB0aGUgW2BwdXJycjo6bWFwKClgXShodHRwczovL3B1cnJyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL21hcC5odG1sKSBmYW1pbHkgb2YgZnVuY3Rpb25zLCB3aGljaCBjYW4gYmUgdXNlZCB0byBydW4gYSBnaXZlbiBmdW5jdGlvbiBvbiBlYWNoIGVsZW1lbnQgb2YgYSBsaXN0IChvciB2ZWN0b3IpIGluIG9uZSBjYWxsLgpUaGUgZ2VuZXJhbCBzeW50YXggZm9yIGBwdXJycjo6bWFwKClgIGFuZCBmcmllbmRzIGlzOgoKYGBgCiMgU3ludGF4IGZvciB1c2luZyB0aGUgbWFwIGZ1bmN0aW9uOgpwdXJycjo6bWFwKDxpbnB1dCBsaXN0IG9yIHZlY3Rvcj4sCiAgICAgICAgICAgPGZ1bmN0aW9uIHRvIGFwcGx5IHRvIGVhY2ggaXRlbSBpbiB0aGUgaW5wdXQ+LAogICAgICAgICAgIDxhbnkgYWRkaXRpb25hbCBhcmd1bWVudHMgdG8gdGhlIGZ1bmN0aW9uIGNhbiBnbyBoZXJlPiwKICAgICAgICAgICA8YW5kIGFsc28gaGVyZSBpZiB0aGVyZSBhcmUgZXZlbiBtb3JlIGFyZ3VtZW50cywgYW5kIHNvIG9uPikKYGBgCgoKVGhlIG91dHB1dCBmcm9tIHJ1bm5pbmcgYHB1cnJyOjptYXAoKWAgaXMgYWx3YXlzIGEgbGlzdCAoYnV0IG5vdGUgdGhhdCB0aGVyZSBhcmUgb3RoZXIgYHB1cnJyOjptYXAoKWAgcmVsYXRpdmVzIHdoaWNoIHJldHVybiBvdGhlciBvYmplY3QgdHlwZXMsIGFzIHlvdSBjYW4gcmVhZCBhYm91dCBpbiBbdGhlIGBwdXJycjo6bWFwKClgIGRvY3VtZW50YXRpb25dKGh0dHBzOi8vcHVycnIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvaW5kZXguaHRtbCkpLgpJZiB0aGlzIGNvbmNlcHQgc291bmRzIGEgbGl0dGxlIGZhbWlsaWFyIHRvIHlvdSwgdGhhdCdzIGJlY2F1c2UgaXQgcHJvYmFibHkgaXMhCkJhc2UgUidzIGBsYXBwbHkoKWAgZnVuY3Rpb24gY2FuIHByb3ZpZGUgc2ltaWxhciB1dGlsaXR5LCBhbmQgdGhlIGBwdXJycjo6bWFwKClgIGZhbWlseSBvZiBmdW5jdGlvbnMgY2FuIChpbiBwYXJ0KSBiZSB0aG91Z2h0IG9mIGFzIGFuIGFsdGVybmF0aXZlIHRvIHNvbWUgb2YgdGhlIGJhc2UgUiBgYXBwbHlgIGZ1bmN0aW9ucywgd2l0aCBtb3JlIGNvbnNpc3RlbnQgYmVoYXZpb3IuCgpMZXQncyBzZWUgYSB2ZXJ5IHNpbXBsZSBleGFtcGxlIG9mIGBwdXJycjo6bWFwKClgIGluIGFjdGlvbiwgaW5zcGlyZWQgYnkgY2FuY2VyIGdyb3VwcyB0aGUgRGF0YSBMYWIgaGFzIGFuYWx5emVkIHRocm91Z2ggdGhlIFtPcGVuUEJUQV0oaHR0cHM6Ly9naXRodWIuY29tL0FsZXhzTGVtb25hZGUvT3BlblBCVEEtYW5hbHlzaXMvKSBwcm9qZWN0OgoKYGBge3IgbWFwIGV4YW1wbGV9CiMgRGVmaW5lIGEgbGlzdCBvZiBjYW5jZXIgaGlzdG9sb2dpZXMKaGlzdG9sb2dpZXMgPC0gbGlzdCgKICAibG93LWdyYWRlIGdsaW9tYXMiICA9IGMoIlNFR0EiLCAiUEEiLCAiR05HIiwgIlBYQSIpLAogICJoaWdoLWdyYWRlIGdsaW9tYXMiID0gYygiRE1HIiwgIkRJUEciKSwKICAiZW1icnlvbmFsIHR1bW9ycyIgICA9IGMoIk1CIiwgIkFUUlQiLCAiRVRNUiIpCiApCgojIFRoZSBvdmVyYWxsIGxlbmd0aCBvZiB0aGUgbGlzdCBpcyAzCmxlbmd0aChoaXN0b2xvZ2llcykKCiMgSG93IGNhbiB3ZSBydW4gYGxlbmd0aCgpYCBvbiBlYWNoIGl0ZW0gb2YgdGhlIGxpc3Q/CiMgV2UgY2FuIHVzZSBvdXIgbmV3IGZyaWVuZCBwdXJycjo6bWFwKCk6CnB1cnJyOjptYXAoaGlzdG9sb2dpZXMsIGxlbmd0aCkKYGBgCgpPbmUgb3RoZXIgbmV3IGNvZGluZyBzdHJhdGVneSB3ZSdsbCBsZWFybiBpbiB0aGlzIG5vdGVib29rIGlzIHVzaW5nIHRoZSBbYGdsdWVgXShodHRwczovL2dsdWUudGlkeXZlcnNlLm9yZy8pIHBhY2thZ2UgdG8gY29tYmluZSBzdHJpbmdzLgpUaGlzIHBhY2thZ2Ugb2ZmZXJzIGEgY29udmVuaWVudCBmdW5jdGlvbiBgZ2x1ZTo6Z2x1ZSgpYCB0aGF0IGNhbiBiZSB1c2VkIGluc3RlYWQgb2YgdGhlIGJhc2UgUiBgcGFzdGUoKWAgZnVuY3Rpb24uCgpgYGB7ciBwYXN0ZX0KIyBEZWZpbmUgYSB2YXJpYWJsZSBmb3IgZXhhbXBsZToKb3JnX25hbWUgPC0gIkRhdGEgTGFiIgoKIyBXZSBjYW4gdXNlIHBhc3RlIHRvIGNvbWJpbmUgc3RyaW5ncyBhbmQgdmFyaWFibGVzOgpwYXN0ZSgiV2VsY29tZSB0byB0aGUiLCBvcmdfbmFtZSwgIndvcmtzaG9wIG9uIEFkdmFuY2VkIHNjUk5BLXNlcSEiKQpgYGAKCldlIGNhbiB1c2UgYGdsdWU6OmdsdWUoKWAgdG8gYWNjb21wbGlzaCB0aGUgc2FtZSBnb2FsIHdpdGggc29tZSBkaWZmZXJlbnQgc3ludGF4OgoKYGBge3IgZ2x1ZX0KIyBnbHVlOjpnbHVlIHRha2VzIGEgc2luZ2xlIHN0cmluZyBhcmd1bWVudCAob25seSBvbmUgc2V0IG9mIHF1b3RlcyEpLCBhbmQKIyAgdmFyaWFibGVzIGNhbiBlYXNpbHkgYmUgaW5jbHVkZWQgaW5zaWRlIHtjdXJseSBicmFjZXN9CmdsdWU6OmdsdWUoIldlbGNvbWUgdG8gdGhlIHtvcmdfbmFtZX0gd29ya3Nob3Agb24gQWR2YW5jZWQgc2NSTkEtc2VxISIpCmBgYAoKKE5vdGUgdGhhdCBldmVuIHRob3VnaCB0aGUgYGdsdWU6OmdsdWUoKWAgb3V0cHV0IGlzbid0IGluIHF1b3RlcywgaXQgc3RpbGwgYmVoYXZlcyBsaWtlIGEgc3RyaW5nISkKCgpBbHJpZ2h0LCB0aW1lIGZvciB0aGUgZ29vZCBzdHVmZiEKTGV0J3MgdXNlIGBwdXJycjo6bWFwKClgIHRvIHJlYWQgaW4gb3VyIFNDRSBvYmplY3RzIHNvIHRoYXQgdGhleSBhcmUgaW1tZWRpYXRlbHkgc3RvcmVkIHRvZ2V0aGVyIGluIGEgbGlzdC4KCgpXZSdsbCBmaXJzdCBuZWVkIHRvIGRlZmluZSBhIHZlY3RvciBvZiB0aGUgZmlsZSBwYXRocyB0byByZWFkIGluLgpXZSdsbCBzdGFydCBieSBjcmVhdGluZyBhIHZlY3RvciBvZiBzYW1wbGUgbmFtZXMgdGhlbXNlbHZlcyBhbmQgdGhlbiBmb3JtYXR0aW5nIHRoZW0gaW50byB0aGUgY29ycmVjdCBwYXRocy4KVGhpcyB3YXkgKGZvcmVzaGFkb3dpbmchKSB3ZSBhbHNvIGhhdmUgYSBzdGFuZC1hbG9uZSB2ZWN0b3Igb2YganVzdCBzYW1wbGUgbmFtZXMsIHdoaWNoIHdpbGwgY29tZSBpbiBoYW5keSEKCmBgYHtyIHNhbXBsZSBuYW1lc30KIyBWZWN0b3Igb2YgYWxsIHRoZSBzYW1wbGVzIHRvIHJlYWQgaW46CnNhbXBsZV9uYW1lcyA8LSBjKCJTQ1BDTDAwMDQ3OSIsCiAgICAgICAgICAgICAgICAgICJTQ1BDTDAwMDQ4MCIsCiAgICAgICAgICAgICAgICAgICJTQ1BDTDAwMDQ4MSIsCiAgICAgICAgICAgICAgICAgICJTQ1BDTDAwMDQ4MiIpCmBgYAoKCmBgYHtyIGRlZmluZSBzY2VfcGF0aHMsIGxpdmUgPSBUUlVFfQojIE5vdywgY29udmVydCB0aGVzZSB0byBmaWxlIHBhdGhzOiA8aW5wdXRfZGlyPi88c2FtcGxlX25hbWU+LnJkcwpzY2VfcGF0aHMgPC0gZmlsZS5wYXRoKGlucHV0X2RpciwKICAgICAgICAgICAgICAgICAgICAgICBnbHVlOjpnbHVlKCJ7c2FtcGxlX25hbWVzfS5yZHMiKQopCiMgUHJpbnQgdGhlIHNjZV9wYXRocyB2ZWN0b3IKc2NlX3BhdGhzCmBgYAoKV2UgY2FuIG5vdyByZWFkIHRoZXNlIGZpbGVzIGluIGFuZCBjcmVhdGUgYSBsaXN0IG9mIGZvdXIgU0NFIG9iamVjdHMuClNpbmNlIGByZWFkcjo6cmVhZF9yZHMoKWAgY2FuIG9ubHkgb3BlcmF0ZSBvbiBvbmUgaW5wdXQgYXQgYSB0aW1lLCB3ZSdsbCBuZWVkIHRvIHVzZSBgcHVycnI6Om1hcCgpYCB0byBydW4gaXQgb24gYWxsIGlucHV0IGZpbGUgcGF0aHMgaW4gb25lIGNvbW1hbmQuCkFsdGhvdWdoIGBzY2VfcGF0aHNgIGlzIGEgdmVjdG9yIChub3QgYSBsaXN0KSwgaXQgd2lsbCBzdGlsbCB3b3JrIGFzIGlucHV0IHRvIGBwdXJycjptYXAoKWAuClRoZSBvdXRwdXQgZnJvbSB0aGlzIGNvZGUgd2lsbCBzdGlsbCBiZSBhIGxpc3QsIHNpbmNlIHRoYXQncyB3aGF0IGBwdXJycjo6bWFwKClgIGFsd2F5cyByZXR1cm5zLgoKYGBge3IgcmVhZCBzY2UgcGF0aHMsIGxpdmUgPSBUUlVFfQojIFVzZSBwdXJycjo6bWFwKCkgdG8gcmVhZCBhbGwgZmlsZXMgaW50byBhIGxpc3QgYXQgb25jZQpzY2VfbGlzdCA8LSBwdXJycjo6bWFwKAogIHNjZV9wYXRocywKICByZWFkcjo6cmVhZF9yZHMKKQpgYGAKCkxldCdzIGhhdmUgYSBsb29rIGF0IG91ciBsaXN0IG9mIFNDRSBvYmplY3RzOgoKYGBge3IgcHJpbnQgc2NlIGxpc3QsIGxpdmU9VFJVRX0KIyBQcmludCBzY2VfbGlzdApzY2VfbGlzdApgYGAKCldlIG5vdyBoYXZlIGEgbGlzdCBvZiBsZW5ndGggZm91ciwgd2hlcmUgZWFjaCBpdGVtIGlzIGEgcHJvY2Vzc2VkIFNDRSBvYmplY3QhCkhvd2V2ZXIsIHdlJ2xsIG5lZWQgdG8ga2VlcCB0cmFjayBvZiB3aGljaCBzYW1wbGUgZWFjaCBpdGVtIGlzLCBzbyBpdCdzIGhlbHBmdWwgdG8gYWRkIF9uYW1lc18gdG8gdGhpcyBsaXN0IHJlcHJlc2VudGluZyB0aGUgcmVsZXZhbnQgc2FtcGxlIG5hbWVzLgoKYGBge3IgYWRkIGxpc3QgbmFtZXMsIGxpdmUgPSBUUlVFfQojIEFzc2lnbiB0aGUgc2FtcGxlIG5hbWVzIGFzIHRoZSBuYW1lcyBmb3Igc2NlX2xpc3QKbmFtZXMoc2NlX2xpc3QpIDwtIHNhbXBsZV9uYW1lcwpgYGAKCmBgYHtyIHByaW50IG5hbWVkIGxpc3QsIGxpdmU9VFJVRX0KIyBQcmludCB0aGUgbGlzdCB0byBzZWUgaXQgd2l0aCBuYW1lcwpzY2VfbGlzdApgYGAKCklmIHlvdSBsb29rIGNsb3NlbHkgYXQgdGhlIHByaW50ZWQgU0NFIG9iamVjdHMsIHlvdSBtYXkgbm90aWNlIHRoYXQgdGhleSBhbGwgY29udGFpbiBgY29sRGF0YWAgdGFibGUgY29sdW1ucyBgY2VsbHR5cGVfZmluZWAgYW5kIGBjZWxsdHlwZV9icm9hZGAuClRoZXNlIGNvbHVtbnMgKHdoaWNoIHdlIGFkZGVkIHRvIFNDRSBvYmplY3RzIGR1cmluZyBbcHJlLXByb2Nlc3NpbmddKGh0dHBzOi8vZ2l0aHViLmNvbS9BbGV4c0xlbW9uYWRlL3RyYWluaW5nLW1vZHVsZXMvdHJlZS9tYXN0ZXIvc2NSTkEtc2VxLWFkdmFuY2VkL3NldHVwL3JtcykpIGNvbnRhaW4gcHV0YXRpdmUgX2NlbGwgdHlwZSBhbm5vdGF0aW9uc18gYXMgYXNzaWduZWQgaW4gW1BhdGVsIF9ldCBhbC5fICgyMDIyKV0oaHR0cHM6Ly9kb2kub3JnLzEwLjEwMTYvai5kZXZjZWwuMjAyMi4wNC4wMDMpLgpXZSB3aWxsIGVuZCB1cCBsZXZlcmFnaW5nIHRoZXNlIGNlbGwgdHlwZSBhbm5vdGF0aW9ucyB0byBleHBsb3JlIGhvdyBzdWNjZXNzZnVsIG91ciBpbnRlZ3JhdGlvbiBpczsgYWZ0ZXIgaW50ZWdyYXRpb24sIHdlIGV4cGVjdCBjZWxsIHR5cGVzIGZyb20gZGlmZmVyZW50IHNhbXBsZXMgdG8gZ3JvdXAgdG9nZXRoZXIsIHJhdGhlciB0aGFuIGJlaW5nIHNlcGFyYXRlZCBieSBiYXRjaGVzLgoKVGhhdCBzYWlkLCB0aGUgaW50ZWdyYXRpb24gbWV0aG9kcyB3ZSB3aWxsIGJlIGFwcGx5aW5nIF9kbyBub3QgYWN0dWFsbHkgdXNlXyB0aGVzZSBjZWxsIHR5cGUgYW5ub3RhdGlvbnMuCklmIHdlIGhhdmUgYW5ub3RhdGlvbnMsIHRoZXkgYXJlIGEgaGVscGZ1bCAiYm9udXMiIGZvciBhc3Nlc3NpbmcgdGhlIGludGVncmF0aW9uJ3Mgc3VjY2VzcywgYnV0IHRoZXkgYXJlIG5vdCBwYXJ0IG9mIHRoZSBpbnRlZ3JhdGlvbiBpdHNlbGYuCgoKIyMgUHJlcGFyZSB0aGUgU0NFIGxpc3QgZm9yIGludGVncmF0aW9uCgohW1NpbmdsZS1jZWxsIHJvYWRtYXA6IE1lcmdlXShkaWFncmFtcy9yb2FkbWFwX211bHRpX21lcmdlLnBuZykKCgpOb3cgdGhhdCB3ZSBoYXZlIGEgbGlzdCBvZiBwcm9jZXNzZWQgU0NFIG9iamVjdHMsIHdlIG5lZWQgdG8gbWVyZ2UgdGhlIG9iamVjdHMgaW50byBvbmUgb3ZlcmFsbCBTQ0Ugb2JqZWN0IGZvciBpbnB1dCB0byBpbnRlZ3JhdGlvbi4KQSB3b3JkIG9mIGNhdXRpb24gYmVmb3JlIHdlIGJlZ2luOiAqKlRoaXMgbWVyZ2VkIFNDRSBvYmplY3QgaXMgTk9UIGFuIGludGVncmF0ZWQgU0NFISoqCk1lcmdpbmcgU0NFcyBkb2VzIG5vdCBwZXJmb3JtIGFueSBiYXRjaCBjb3JyZWN0aW9uLCBidXQganVzdCByZW9yZ2FuaXplcyB0aGUgZGF0YSB0byBhbGxvdyB1cyB0byBwcm9jZWVkIHRvIGludGVncmF0aW9uIG5leHQuCgpUbyBtZXJnZSBTQ0Ugb2JqZWN0cywgd2UgZG8gbmVlZCB0byBkbyBzb21lIHdyYW5nbGluZyBhbmQgYm9va2tlZXBpbmcgdG8gZW5zdXJlIGNvbXBhdGliaWxpdHkgYW5kIHRoYXQgd2UgZG9uJ3QgbG9zZSBpbXBvcnRhbnQgaW5mb3JtYXRpb24uCk92ZXJhbGwgd2UnbGwgd2FudCB0byB0YWtlIGNhcmUgb2YgdGhlc2UgaXRlbXM6CgoxLiBXZSBzaG91bGQgYmUgYWJsZSB0byB0cmFjZSBzYW1wbGUtc3BlY2lmaWMgaW5mb3JtYXRpb24gYmFjayB0byB0aGUgb3JpZ2luYXRpbmcgc2FtcGxlLCBpbmNsdWRpbmcuLi4KICAgIC0gQ2VsbC1sZXZlbCBpbmZvcm1hdGlvbjogV2hpY2ggc2FtcGxlIGlzIGVhY2ggY2VsbCBmcm9tPwogICAgLSBMaWJyYXJ5LXNwZWNpZmljIGZlYXR1cmUgc3RhdGlzdGljcywgZS5nLiwgZ2VuZS1sZXZlbCBzdGF0aXN0aWNzIGZvciBhIGdpdmVuIGxpYnJhcnkgZm91bmQgaW4gYHJvd0RhdGFgLgogICAgV2hpY2ggc2FtcGxlIGlzIGEgZ2l2ZW4gZmVhdHVyZSBzdGF0aXN0aWMgZnJvbT8KMi4gU0NFIG9iamVjdHMgc2hvdWxkIGNvbnRhaW4gdGhlIHNhbWUgZ2VuZXM6IEVhY2ggU0NFIG9iamVjdCBzaG91bGQgaGF2ZSB0aGUgc2FtZSByb3cgbmFtZXMuCjMuIFNDRSBjZWxsIG1ldGFkYXRhIGNvbHVtbnMgc2hvdWxkIG1hdGNoOiBUaGUgYGNvbERhdGFgIGZvciBlYWNoIFNDRSBvYmplY3Qgc2hvdWxkIGhhdmUgdGhlIHNhbWUgY29sdW1uIG5hbWVzLgoKCldlJ2xsIGJlZ2luIGJ5IHRha2luZyBzb21lIHRpbWUgdG8gdGhvcm91Z2hseSBleHBsb3JlIG91ciBTQ0Ugb2JqZWN0cyBhbmQgZmlndXJlIG91dCB3aGF0IHdyYW5nbGluZyBzdGVwcyB3ZSBuZWVkIHRvIHRha2UgZm9yIHRoZXNlIHNwZWNpZmljIGRhdGEuCkRvbid0IHNraXAgdGhpcyBleHBsb3JhdGlvbiEKQmVhciBpbiBtaW5kIHRoYXQgdGhlIGV4YWN0IHdyYW5nbGluZyBzaG93biBoZXJlIHdpbGwgbm90IGJlIHRoZSBzYW1lIGZvciBvdGhlciBTQ0Ugb2JqZWN0cyB5b3Ugd29yayB3aXRoLCBidXQgdGhlIHNhbWUgZ2VuZXJhbCBwcmluY2lwbGVzIGFwcGx5LgoKCiMjIyMgUHJlc2VydmluZyBzYW1wbGUgaW5mb3JtYXRpb24gYXQgdGhlIGNlbGwgbGV2ZWwKCkhvdyB3aWxsIHdlIGJlIGFibGUgdG8gdGVsbCB3aGljaCBzYW1wbGUgYSBnaXZlbiBjZWxsIGNhbWUgZnJvbT8KClRoZSBiZXN0IHdheSB0byBkbyB0aGlzIGlzIHNpbXBseSB0byBhZGQgYSBgY29sRGF0YWAgY29sdW1uIHdpdGggdGhlIHNhbXBsZSBpbmZvcm1hdGlvbiwgc28gdGhhdCB3ZSBjYW4ga25vdyB3aGljaCBzYW1wbGUgZWFjaCByb3cgY2FtZSBmcm9tLgoKSW4gYWRkaXRpb24sIHdlIHdhbnQgdG8gcGF5IHNvbWUgYXR0ZW50aW9uIHRvIHRoZSBTQ0Ugb2JqZWN0J3MgY29sdW1uIG5hbWVzICh0aGUgY2VsbCBpZHMpLCB3aGljaCBtdXN0IHJlbWFpbiB1bmlxdWUgYWZ0ZXIgbWVyZ2luZyBzaW5jZSBkdXBsaWNhdGUgaWRzIHdpbGwgY2F1c2UgYW4gUiBlcnJvci4KSW4gdGhpcyBjYXNlLCB0aGUgU0NFIGNvbHVtbiBuYW1lcyBhcmUgYmFyY29kZXMgKHdoaWNoIGlzIHVzdWFsbHkgYnV0IG5vdCBhbHdheXMgdGhlIGNhc2UgaW4gU0NFIG9iamVjdHMpLCB3aGljaCBhcmUgb25seSBndWFyYW50ZWVkIHRvIGJlIHVuaXF1ZSBfd2l0aGluXyBhIHNhbXBsZSBidXQgbWF5IGJlIHJlcGVhdGVkIGFjcm9zcyBzYW1wbGVzLgpTbywgYWZ0ZXIgbWVyZ2luZywgaXQncyB0ZWNobmljYWxseSBwb3NzaWJsZSB0aGF0IG11bHRpcGxlIGNlbGxzIHdpbGwgaGF2ZSB0aGUgc2FtZSBiYXJjb2RlLgpUaGlzIHdvdWxkIGJlIGEgcHJvYmxlbSBmb3IgdHdvIHJlYXNvbnM6CkZpcnN0LCB0aGUgY2VsbCBpZCB3b3VsZCBub3QgYmUgYWJsZSB0byBwb2ludCB1cyBiYWNrIHRvIGNlbGwncyBvcmlnaW5hdGluZyBzYW1wbGUuClNlY29uZCwgaXQgd291bGQgbGl0ZXJhbGx5IGNhdXNlIGFuIGVycm9yIGluIFIsIHdoaWNoIGRvZXMgbm90IGFsbG93IGR1cGxpY2F0ZSBjb2x1bW4gbmFtZXMuCgoKT25lIHdheSB0byBlbnN1cmUgdGhhdCBjZWxsIGlkcyByZW1haW4gdW5pcXVlIGV2ZW4gYWZ0ZXIgbWVyZ2luZyBpcyB0byBhY3R1YWxseSBtb2RpZnkgdGhlbSBieSBfcHJlcGVuZGluZ18gdGhlIHJlbGV2YW50IHNhbXBsZSBuYW1lLgpGb3IgZXhhbXBsZSwgY29uc2lkZXIgdGhlc2UgYmFyY29kZXMgZm9yIHRoZSBgU0NQQ0wwMDA0NzlgIHNhbXBsZToKCmBgYHtyIGJhcmNvZGVzfQojIExvb2sgYXQgdGhlIGNvbHVtbiBuYW1lcyBmb3IgdGhlIGBTQ1BDTDAwMDQ3OWAgc2FtcGxlLCBmb3IgZXhhbXBsZQpjb2xuYW1lcyhzY2VfbGlzdCRTQ1BDTDAwMDQ3OSkgfD4KICAjIE9ubHkgcHJpbnQgb3V0IHRoZSBmaXJzdCA2IGZvciBjb252ZW5pZW5jZQogIGhlYWQoKQpgYGAKClRoZXNlIGlkcyB3aWxsIGJlIHVwZGF0ZWQgdG8gYFNDUENMMDAwNDc5LUdHR0FDQ1RDQUFHQ0dHQVRgLCBgU0NQQ0wwMDA0NzktQ0FDQUdBVEFHVEdBR1RHQ2AsIGFuZCBzbyBvbiwgdGhlcmVieSBlbnN1cmluZyBmdWxseSB1bmlxdWUgaWRzIGZvciBhbGwgY2VsbHMgYWNyb3NzIGFsbCBzYW1wbGVzLgoKIyMjIyBQcmVzZXJ2aW5nIHNhbXBsZSBpbmZvcm1hdGlvbiBhdCB0aGUgZ2VuZSBsZXZlbAoKVGhlIGByb3dEYXRhYCB0YWJsZSBpbiBTQ0Ugb2JqZWN0cyB3aWxsIG9mdGVuIGNvbnRhaW4gYm90aCAiZ2VuZXJhbCIgYW5kICJsaWJyYXJ5LXNwZWNpZmljIiBpbmZvcm1hdGlvbiwgZm9yIGV4YW1wbGU6CgpgYGB7ciByb3dkYXRhfQpyb3dEYXRhKHNjZV9saXN0JFNDUENMMDAwNDc5KSB8PgogIGhlYWQoKQpgYGAKCkhlcmUsIHRoZSByb3duYW1lcyBhcmUgRW5zZW1ibCBnZW5lIGlkcywgYW5kIGNvbHVtbnMgYXJlIGBnZW5lX3N5bWJvbGAsIGBtZWFuYCwgYW5kIGBkZXRlY3RlZGAuClRoZSBgZ2VuZV9zeW1ib2xgIGNvbHVtbiBpcyBnZW5lcmFsIGluZm9ybWF0aW9uIGFib3V0IGFsbCBnZW5lcywgbm90IHNwZWNpZmljIHRvIGFueSBsaWJyYXJ5IG9yIGV4cGVyaW1lbnQsIGJ1dCBgbWVhbmAgYW5kIGBkZXRlY3RlZGAgYXJlIGxpYnJhcnktc3BlY2lmaWMgZ2VuZSBzdGF0aXN0aWNzLgpTbywgYGdlbmVfc3ltYm9sYCBkb2VzIG5vdCBuZWVkIHRvIGJlIHRyYWNlZCBiYWNrIHRvIGl0cyBvcmlnaW5hdGluZyBzYW1wbGUsIGJ1dCBgbWVhbmAgYW5kIGBkZXRlY3RlZGAgZG8uClRvIHRoaXMgZW5kLCB3ZSBjYW4gdGFrZSBhIHNpbWlsYXIgYXBwcm9hY2ggdG8gd2hhdCB3ZSdsbCBkbyBmb3IgY2VsbCBpZHM6CldlIGNhbiBjaGFuZ2UgdGhlIHNhbXBsZS1zcGVjaWZpYyBgcm93RGF0YWAgY29sdW1uIG5hbWVzIGJ5IHByZXBlbmRpbmcgdGhlIHNhbXBsZSBuYW1lLgpGb3IgZXhhbXBsZSwgcmF0aGVyIHRoYW4gYmVpbmcgY2FsbGVkIGBtZWFuYCwgdGhpcyBjb2x1bW4gd2lsbCBiZSBuYW1lZCBgU0NQQ0wwMDA0NzktbWVhbmAgZm9yIHRoZSBgU0NQQ0wwMDA0NzlgIHNhbXBsZS4KCkFsbCBvdXIgU0NFIG9iamVjdHMgaGF2ZSB0aGUgc2FtZSBgcm93RGF0YWAgY29sdW1ucyAoYXMgd2UgY2FuIHNlZSBpbiB0aGUgbmV4dCBjaHVuayksIHNvIHdlJ2xsIHBlcmZvcm0gdGhpcyByZW5hbWluZyBhY3Jvc3MgYWxsIFNDRXMuCgpgYGB7ciBjb21wYXJlIHJvd2RhdGEsIGxpdmUgPSBUUlVFfQojIFVzZSBgcHVycnI6Om1hcCgpYCB0byBxdWlja2x5IGV4dHJhY3Qgcm93RGF0YSBjb2x1bW4gbmFtZXMgZm9yIGFsbCBTQ0VzCnB1cnJyOjptYXAoc2NlX2xpc3QsCiAgICAgICAgICAgXCh4KSBjb2xuYW1lcyhyb3dEYXRhKHgpKSkKYGBgCgoKIyMjIyBFbnN1cmluZyB0aGF0IG9ubHkgc2hhcmVkIGdlbmVzIGFyZSB1c2VkCgpUaGUgbmV4dCBzdGVwIGluIGVuc3VyaW5nIFNDRSBjb21wYXRpYmlsaXR5IGlzIHRvIG1ha2Ugc3VyZSB0aGV5IGFsbCBjb250YWluIHRoZSBzYW1lIGdlbmVzLCB3aGljaCBhcmUgc3RvcmVkIGFzIHRoZSBTQ0Ugb2JqZWN0J3Mgcm93IG5hbWVzICh0aGVzZSBuYW1lcyBhcmUgYWxzbyBmb3VuZCB0aGUgYHJvd0RhdGFgIHNsb3QncyByb3cgbmFtZXMpLgpIZXJlLCB0aG9zZSBnZW5lIGlkcyBhcmUgdW5pcXVlIEVuc2VtYmwgZ2VuZSBpZHMuCgpXZSBjYW4gdXNlIHNvbWUgYHB1cnJyYCBtYWdpYyB0byBxdWlja2x5IGZpbmQgdGhlIHNldCBvZiBzaGFyZWQgZ2VuZXMgYW1vbmcgb3VyIHNhbXBsZXM6CgpgYGB7ciBzaGFyZWQgZ2VuZXN9CiMgRGVmaW5lIHZlY3RvciBvZiBzaGFyZWQgZ2VuZXMKc2hhcmVkX2dlbmVzIDwtIHNjZV9saXN0IHw+CiAgIyBnZXQgcm93bmFtZXMgKGdlbmVzKSBmb3IgZWFjaCBTQ0UgaW4gc2NlX2xpc3QKICBwdXJycjo6bWFwKHJvd25hbWVzKSB8PgogICMgcmVkdWNlIHRvIHRoZSBfaW50ZXJzZWN0aW9uXyBhbW9uZyBsaXN0cwogIHB1cnJyOjpyZWR1Y2UoaW50ZXJzZWN0KQpgYGAKCmBgYHtyIHByaW50IHNoYXJlZCBnZW5lcywgbGl2ZSA9IFRSVUV9CiMgVXNlIGhlYWQgdG8gbG9vayBhdCB0aGUgdmVjdG9yIG9mIHNoYXJlZCBnZW5lczoKaGVhZChzaGFyZWRfZ2VuZXMpCmBgYAoKSW4gdGhpcyBjYXNlLCB3ZSBoYXBwZW4gdG8ga25vdyB0aGF0IGFsbCBTQ0Ugb2JqZWN0cyB3ZSdyZSB3b3JraW5nIHdpdGggYWxyZWFkeSBjb250YWluZWQgdGhlIHNhbWUgZ2VuZXMuCldlIGRvIGEgcXVpY2stYW5kLWRpcnR5IGNoZWNrIGZvciB0aGlzIGJ5IGxvb2tpbmcgYXQgdGhlIG51bWJlciBvZiByb3dzIGFjcm9zcyBTQ0Ugb2JqZWN0cywgYW5kIHdlJ2xsIHNlZSB0aGF0IHRoZXkgYXJlIGFsbCB0aGUgc2FtZToKCmBgYHtyIGNoZWNrIHNoYXJlZCBnZW5lcywgbGl2ZSA9IFRSVUV9CiMgVGhlIG51bWJlciBvZiBnZW5lcyBpbiBhbiBTQ0UgY29ycmVzcG9uZHMgdG8gaXRzIG51bWJlciBvZiByb3dzOgpzY2VfbGlzdCB8PgogIHB1cnJyOjptYXAobnJvdykKYGBgCgpTbywgZm9yIG91ciBkYXRhLCB3ZSB3aWxsIG5vdCBoYXZlIHRvIHN1YnNldCB0byBzaGFyZWQgZ2VuZXMgc2luY2UgdGhleSBhcmUgYWxyZWFkeSBzaGFyZWQhCgojIyMjIEVuc3VyaW5nIG1hdGNoaW5nIGNvbHVtbnMgaW4gYGNvbERhdGFgCgpGaW5hbGx5LCB3ZSdsbCBuZWVkIHRvIGhhdmUgdGhlIHNhbWUgY29sdW1uIG5hbWVzIGFjcm9zcyBhbGwgU0NFIGBjb2xEYXRhYCB0YWJsZXMsIHNvIGxldCdzIGxvb2sgYXQgYWxsIHRob3NlIGNvbHVtbiBuYW1lcy4KV2UgY2FuIHVzZSBzaW1pbGFyIHN5bnRheCBoZXJlIHRvIHdoYXQgd2UgdXNlZCB0byBsb29rIGF0IGFsbCB0aGUgYHJvd0RhdGFgIGNvbHVtbiBuYW1lcy4KCmBgYHtyIGNvbXBhcmUgY29sZGF0YX0KcHVycnI6Om1hcChzY2VfbGlzdCwKICAgICAgICAgICBcKHgpIGNvbG5hbWVzKGNvbERhdGEoeCkpICkKYGBgCgpJdCBsb29rcyBsaWtlIHRoZSBjb2x1bW4gbmFtZXMgYXJlIGFsbCBhbHJlYWR5IG1hdGNoaW5nIGFtb25nIFNDRXMsIHNvIHRoZXJlJ3Mgbm8gc3BlY2lmaWMgcHJlcGFyYXRpb24gd2UnbGwgbmVlZCB0byBkbyB0aGVyZS4KCiMjIyBQZXJmb3JtIFNDRSBtZXJnaW5nCgpBcyB5b3UgY2FuIHNlZSwgdGhlcmUncyBhIGxvdCBvZiBtb3ZpbmcgcGFydHMgdG8gY29uc2lkZXIhCkFnYWluLCB0aGVzZSBtb3ZpbmcgcGFydHMgbWF5ICh3aWxsISkgZGlmZmVyIGZvciBTQ0VzIHRoYXQgeW91IGFyZSB3b3JraW5nIHdpdGgsIHNvIHlvdSBoYXZlIHRvIGV4cGxvcmUgeW91ciBvd24gU0NFcyBpbiBkZXB0aCB0byBwcmVwYXJlIGZvciBtZXJnaW5nLgoKQmFzZWQgb24gb3VyIGV4cGxvcmF0aW9uLCBoZXJlIGlzIGEgc2NoZW1hdGljIG9mIGhvdyBvbmUgb2YgdGhlIFNDRSBvYmplY3RzIHdpbGwgdWx0aW1hdGVseSBiZSBtb2RpZmllZCBpbnRvIHRoZSBmaW5hbCBtZXJnZWQgU0NFOgoKIVtdKGRpYWdyYW1zL3RlY2huaWNhbF9tZXJnZV9zY2UucG5nKQoKCldlJ2xsIHdyaXRlIGEgX2N1c3RvbSBmdW5jdGlvbl8gKHNlZW4gaW4gdGhlIGNodW5rIGJlbG93KSB0YWlsb3JlZCB0byBvdXIgd3JhbmdsaW5nIHN0ZXBzIHRoYXQgcHJlcGFyZXMgYSBzaW5nbGUgU0NFIG9iamVjdCBmb3IgbWVyZ2luZy4KV2UnbGwgdGhlbiB1c2Ugb3VyIG5ldyBgcHVycnI6Om1hcCgpYCBwcm9ncmFtbWluZyBza2lsbHMgdG8gcnVuIHRoaXMgZnVuY3Rpb24gb3ZlciB0aGUgYHNjZV9saXN0YC4KVGhpcyB3aWxsIGdpdmUgdXMgYSBuZXcgbGlzdCBvZiBmb3JtYXR0ZWQgU0NFcyB0aGF0IHdlIGNhbiBwcm9jZWVkIHRvIG1lcmdlLgpJdCdzIGltcG9ydGFudCB0byByZW1lbWJlciB0aGF0IHRoZSBgZm9ybWF0X3NjZSgpYCBmdW5jdGlvbiB3cml0dGVuIGJlbG93IGlzIG5vdCBhIGZ1bmN0aW9uIGZvciBnZW5lcmFsIHVzZSDigJMgaXQncyBiZWVuIHByZWNpc2VseSB3cml0dGVuIHRvIG1hdGNoIHRoZSBwcm9jZXNzaW5nIHdlIG5lZWQgdG8gZG8gZm9yIF90aGVzZV8gU0NFcywgYW5kIGRpZmZlcmVudCBTQ0VzIHlvdSB3b3JrIHdpdGggd2lsbCByZXF1aXJlIGRpZmZlcmVudCB0eXBlcyBvZiBwcm9jZXNzaW5nLgoKYGBge3IgZm9ybWF0X3NjZSBmdW5jdGlvbn0KZm9ybWF0X3NjZSA8LSBmdW5jdGlvbihzY2UsIHNhbXBsZV9uYW1lKSB7CiAgIyBJbnB1dCBhcmd1bWVudHM6CiAgIyMgc2NlOiBBbiBTQ0Ugb2JqZWN0IHRvIGZvcm1hdAogICMjIHNhbXBsZV9uYW1lOiBUaGUgU0NFIG9iamVjdCdzIG5hbWUKICAjIFRoaXMgZnVuY3Rpb24gcmV0dXJucyBhIGZvcm1hdHRlZCBTQ0Ugb2JqZWN0LgoKICAjIyMjIyMgRW5zdXJlIHRoYXQgd2UgY2FuIGlkZW50aWZ5IHRoZSBvcmlnaW5hdGluZyBzYW1wbGUgaW5mb3JtYXRpb24gIyMjIyMjCiAgIyBBZGQgYSBjb2x1bW4gY2FsbGVkIGBzYW1wbGVgIHRoYXQgc3RvcmVzIHRoaXMgaW5mb3JtYXRpb24KICAjIFRoaXMgd2lsbCBiZSBzdG9yZWQgaW4gYGNvbERhdGFgCiAgc2NlJHNhbXBsZSA8LSBzYW1wbGVfbmFtZQoKCiAgIyMjIyMjIEVuc3VyZSBjZWxsIGlkcyB3aWxsIGJlIHVuaXF1ZSAjIyMjIyMKICAjIFVwZGF0ZSB0aGUgU0NFIG9iamVjdCBjb2x1bW4gbmFtZXMgKGNlbGwgaWRzKSBieSBwcmVwZW5kaW5nIGBzYW1wbGVfbmFtZWAKICBjb2xuYW1lcyhzY2UpIDwtIGdsdWU6OmdsdWUoIntzYW1wbGVfbmFtZX0te2NvbG5hbWVzKHNjZSl9IikKCgogICMjIyMjIyBFbnN1cmUgZ2VuZS1sZXZlbCBzdGF0aXN0aWNzIGNhbiBiZSBpZGVudGlmaWVkIGluIGByb3dEYXRhYCAjIyMjIyMKICAjIFdlIHdhbnQgdG8gcmVuYW1lIHRoZSBjb2x1bW5zIGBtZWFuYCBhbmQgYGRldGVjdGVkYCB0byBjb250YWluIHRoZSBgc2FtcGxlX25hbWVgCiAgIyBSZWNhbGwgdGhlIG5hbWVzIGFyZTogImdlbmVfc3ltYm9sIiwgIm1lYW4iLCAiZGV0ZWN0ZWQiCiAgY29sbmFtZXMocm93RGF0YShzY2UpKSA8LSBjKCJnZW5lX3N5bWJvbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdsdWU6OmdsdWUoIntzYW1wbGVfbmFtZX0tbWVhbiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnbHVlOjpnbHVlKCJ7c2FtcGxlX25hbWV9LWRldGVjdGVkIikpCgogICMgUmV0dXJuIHRoZSBmb3JtYXR0ZWQgU0NFIG9iamVjdAogIHJldHVybihzY2UpCn0KYGBgCgpUbyBydW4gdGhpcyBmdW5jdGlvbiwgd2UnbGwgdXNlIHRoZSBgcHVycnI6Om1hcDIoKWAgZnVuY3Rpb24sIGEgcmVsYXRpdmUgb2YgYHB1cnJyOjptYXAoKWAgdGhhdCBhbGxvd3MgeW91IHRvIGxvb3Agb3ZlciBfdHdvXyBpbnB1dCBsaXN0cy92ZWN0b3JzLgpJbiBvdXIgY2FzZSwgd2Ugd2FudCB0byBydW4gYGZvcm1hdF9zY2UoKWAgb3ZlciBwYWlyZWQgYHNjZV9saXN0YCBpdGVtcyBhbmQgYHNjZV9saXN0YCBuYW1lcy4KCmBgYHtyIGZvcm1hdCBzY2VzIGZvciBtZXJnZSwgbGl2ZSA9IFRSVUV9CiMgV2UgY2FuIHVzZSBgcHVycnI6Om1hcDIoKWAgdG8gbG9vcCBvdmVyIHR3byBsaXN0L3ZlY3RvciBhcmd1bWVudHMKc2NlX2xpc3RfZm9ybWF0dGVkIDwtIHB1cnJyOjptYXAyKAogICMgRWFjaCAiaXRlcmF0aW9uIiB3aWxsIG1hcmNoIGRvd24gdGhlIGZpcnN0IHR3bwogICMgIGFyZ3VtZW50cyBgc2NlX2xpc3RgIGFuZCBgbmFtZXMoc2NlX2xpc3QpYCBpbiBvcmRlcgogIHNjZV9saXN0LAogIG5hbWVzKHNjZV9saXN0KSwKICAjIE5hbWUgb2YgdGhlIGZ1bmN0aW9uIHRvIHJ1bgogIGZvcm1hdF9zY2UKKQoKIyBQcmludCByZXN1bHRpbmcgbGlzdApzY2VfbGlzdF9mb3JtYXR0ZWQKYGBgCgooUHNzdCwgbGlrZSBgcHVycnJgIGFuZCB3YW50IHRvIGRpdmUgZGVlcGVyPyBDaGVjayBvdXQgW3RoZSBgcHVycnI6OmltYXAoKWAgZnVuY3Rpb25dKGh0dHBzOi8vcHVycnIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvaW1hcC5odG1sKSEpCgoKQXQgbG9uZyBsYXN0LCB3ZSBhcmUgcmVhZHkgdG8gbWVyZ2UgdGhlIFNDRXMsIHdoaWNoIHdlJ2xsIGRvIHVzaW5nIHRoZSBSIGZ1bmN0aW9uIGBjYmluZCgpYC4KVGhlIGBjYmluZCgpYCBmdW5jdGlvbiBpcyBvZnRlbiB1c2VkIHRvIGNvbWJpbmUgZGF0YSBmcmFtZXMgb3IgbWF0cmljZXMgYnkgY29sdW1uLCBpLmUuICJzdGFjayIgdGhlbSBuZXh0IHRvIGVhY2ggb3RoZXIuClRoZSBzYW1lIHByaW5jaXBsZSBhcHBsaWVzIGhlcmUsIGJ1dCB3aGVuIHJ1biBvbiBTQ0Ugb2JqZWN0cywgYGNiaW5kKClgIHdpbGwgY3JlYXRlIGEgbmV3IFNDRSBvYmplY3QgYnkgY29tYmluaW5nIGBjb3VudHNgIGFuZCBgbG9nY291bnRzYCBtYXRyaWNlcyBieSBjb2x1bW4uCkZvbGxvd2luZyB0aGF0IHN0cnVjdHVyZSwgb3RoZXIgU0NFIHNsb3RzIChgY29sRGF0YWAsIGByb3dEYXRhYCwgcmVkdWNlZCBkaW1lbnNpb25zLCBhbmQgb3RoZXIgbWV0YWRhdGEpIGFyZSBjb21iaW5lZCBhcHByb3ByaWF0ZWx5LgoKU2luY2Ugd2UgbmVlZCB0byBhcHBseSBgY2JpbmQoKWAgdG8gYSBfbGlzdF8gb2Ygb2JqZWN0cywgd2UgbmVlZCB0byB1c2Ugc29tZSBzbGlnaHRseS1nbmFybHkgc3ludGF4OiBXZSdsbCB1c2UgdGhlIGZ1bmN0aW9uIGBkby5jYWxsKClgLCB3aGljaCBhbGxvd3MgdGhlIGBjYmluZCgpYCBpbnB1dCB0byBiZSBhIGxpc3Qgb2Ygb2JqZWN0cyB0byBjb21iaW5lLgoKYGBge3IgbWVyZ2VzIHNjZXMsIGxpdmUgPSBUUlVFfQojIE1lcmdlIFNDRSBvYmplY3RzCm1lcmdlZF9zY2UgPC0gZG8uY2FsbChjYmluZCwgc2NlX2xpc3RfZm9ybWF0dGVkKQoKIyBQcmludCB0aGUgbWVyZ2VkX3NjZSBvYmplY3QKbWVyZ2VkX3NjZQpgYGAKCldlIG5vdyBoYXZlIGEgc2luZ2xlIFNDRSBvYmplY3QgdGhhdCBjb250YWlucyBhbGwgY2VsbHMgZnJvbSBhbGwgc2FtcGxlcyB3ZSdkIGxpa2UgdG8gaW50ZWdyYXRlLgoKTGV0J3MgdGFrZSBhIHBlZWsgYXQgc29tZSBvZiB0aGUgaW5uYXJkcyBvZiB0aGlzIG5ldyBTQ0Ugb2JqZWN0OgoKYGBge3IgZXhwbG9yZSBtZXJnZWRfc2NlLCBsaXZlID0gVFJVRX0KIyBXaGF0IGFyZSB0aGUgdW5pcXVlIHZhbHVlcyBpbiB0aGUgYHNhbXBsZWAgY29sdW1uPwp1bmlxdWUoIGNvbERhdGEobWVyZ2VkX3NjZSkkc2FtcGxlICkKCiMgV2hhdCBhcmUgdGhlIG5ldyBjZWxsIGlkcyAoY29sdW1uIG5hbWVzKT8KaGVhZCggY29sbmFtZXMobWVyZ2VkX3NjZSkgKQoKIyBXaGF0IGRvZXMgcm93RGF0YSBsb29rIGxpa2U/CmhlYWQoIHJvd0RhdGEobWVyZ2VkX3NjZSkgKQpgYGAKCgojIyBJbnRlZ3JhdGlvbgoKIVtTaW5nbGUtY2VsbCByb2FkbWFwOiBJbnRlZ3JhdGVdKGRpYWdyYW1zL3JvYWRtYXBfbXVsdGlfaW50ZWdyYXRlLnBuZykKCgpTbyBmYXIsIHdlJ3ZlIGNyZWF0ZWQgYSBgbWVyZ2VkX3NjZWAgb2JqZWN0IHdoaWNoIGlzIChhbG1vc3QhKSByZWFkeSBmb3IgaW50ZWdyYXRpb24uCgpUaGUgaW50ZWdyYXRpb24gbWV0aG9kcyB3ZSdsbCBiZSB1c2luZyBoZXJlIGFjdHVhbGx5IHBlcmZvcm0gYmF0Y2ggY29ycmVjdGlvbiBvbiBhIHJlZHVjZWQgZGltZW5zaW9uIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBub3JtYWxpemVkIGdlbmUgZXhwcmVzc2lvbiB2YWx1ZXMsIHdoaWNoIGlzIG1vcmUgZWZmaWNpZW50LgpgZmFzdE1OTmAgYW5kIGBoYXJtb255YCBzcGVjaWZpY2FsbHkgdXNlIFBDQSBmb3IgdGhpcywgYnV0IGJlIGF3YXJlIHRoYXQgZGlmZmVyZW50IGludGVncmF0aW9uIG1ldGhvZHMgbWF5IHVzZSBvdGhlciBraW5kcyBvZiByZWR1Y2VkIGRpbWVuc2lvbnMuCgpZb3UnbGwgbm90aWNlIHRoYXQgdGhlIG1lcmdlZCBTQ0Ugb2JqZWN0IG9iamVjdCBhbHJlYWR5IGNvbnRhaW5zIFBDQSBhbmQgVU1BUCByZWR1Y2VkIGRpbWVuc2lvbnMsIHdoaWNoIHdlcmUgY2FsY3VsYXRlZCBkdXJpbmcgb3VyIHByZS1wcm9jZXNzaW5nOgoKYGBge3IgbWVyZ2VkX3NjZSByZWRkaW0sIGxpdmUgPSBUUlVFfQojIFByaW50IHRoZSByZWR1Y2VkRGltTmFtZXMgb2YgdGhlIG1lcmdlZF9zY2UKcmVkdWNlZERpbU5hbWVzKG1lcmdlZF9zY2UpCmBgYAoKVGhlc2UgcmVwcmVzZW50IHRoZSBvcmlnaW5hbCBkaW1lbnNpb24gcmVkdWN0aW9ucyB0aGF0IHdlcmUgcGVyZm9ybWVkIG9uIF9lYWNoIGluZGl2aWR1YWwgU0NFXyBiZWZvcmUgbWVyZ2luZywgYnV0IHdlIGFjdHVhbGx5IG5lZWQgdG8gY2FsY3VsYXRlIFBDQSAoYW5kIFVNQVAgZm9yIHZpc3VhbGl6YXRpb24pIGZyb20gdGhlIG1lcmdlZCBvYmplY3QgZGlyZWN0bHkuCgpXaHkgY2FuJ3Qgd2UgdXNlIHRoZSBzYW1wbGUtc3BlY2lmaWMgUENBIGFuZCBVTUFQIG1hdHJpY2VzPwpQYXJ0IG9mIHRoZXNlIGNhbGN1bGF0aW9ucyB0aGVtc2VsdmVzIGludm9sdmVzIHNjYWxpbmcgdGhlIHJhdyBkYXRhIHRvIGNlbnRlciB0aGUgbWVhbi4KV2hlbiBzYW1wbGVzIGFyZSBzZXBhcmF0ZWx5IGNlbnRlcmVkIGJ1dCBwbG90dGluZyB0b2dldGhlciwgeW91IHdpbGwgc2VlIHNhbXBsZXMgIm92ZXJsYXBwaW5nIiBpbiBzcGFjZSwgYnV0IHRoaXMgcGxhY2VtZW50IGlzIGFjdHVhbGx5IGp1c3QgYW4gYXJ0aWZhY3Qgb2YgdGhlIGluZGl2aWR1YWwgY2VudGVyaW5nLgpJbiBhZGRpdGlvbiwgdGhlIG1hdGhlbWF0aWNhbCByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgb3JpZ2luYWwgZXhwcmVzc2lvbiBkYXRhIGFuZCByZWR1Y2VkIGRpbWVuc2lvbiB2ZXJzaW9uIG9mIHRoYXQgZGF0YSB3aWxsIGRpZmZlciBhY3Jvc3Mgc2FtcGxlcywgbWVhbmluZyB3ZSBjYW4ndCBpbnRlcnByZXQgdGhlbSBhbGwgdG9nZXRoZXIuClRvIHNlZSBob3cgdGhpcyBsb29rcywgbGV0J3MgbG9vayBhdCB0aGUgVU1BUCB3aGVuIGNhbGN1bGF0ZWQgZnJvbSBpbmRpdmlkdWFsIHNhbXBsZXM6CgpgYGB7ciBwbG90IGluZGl2aWR1YWwgVU1BUHMsIGxpdmUgPSBUUlVFfQojIFBsb3QgVU1BUCBjYWxjdWxhdGVkIGZyb20gaW5kaXZpZHVhbCBzYW1wbGVzIHdpdGggc2VwYXJhdGUgc2NhbGluZwpzY2F0ZXI6OnBsb3RSZWR1Y2VkRGltKG1lcmdlZF9zY2UsCiAgICAgICAgICAgICAgICAgICAgICAgZGltcmVkID0gIlVNQVAiLAogICAgICAgICAgICAgICAgICAgICAgIGNvbG91cl9ieSA9ICJzYW1wbGUiLAogICAgICAgICAgICAgICAgICAgICAgIHBvaW50X3NpemUgPSAwLjUsCiAgICAgICAgICAgICAgICAgICAgICAgcG9pbnRfYWxwaGEgPSAwLjIpICsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDMsIGFscGhhID0gMSkpKSArCiAgZ2d0aXRsZSgiVU1BUCBjYWxjdWxhdGVkIG9uIGVhY2ggc2FtcGxlIHNlcGFyYXRlbHkiKQpgYGAKCgpBcyB3ZSBzZWUgaW4gdGhpcyBVTUFQLCBhbGwgc2FtcGxlcyBhcmUgY2VudGVyZWQgYXQgemVybyBhbmQgYWxsIG92ZXJsYXBwaW5nLgpUaGlzIHZpc3VhbCBhcnRpZmFjdCBjYW4gZ2l2ZSB0aGUgX2luY29ycmVjdCBpbXByZXNzaW9uXyB0aGF0IGRhdGEgaXMgaW50ZWdyYXRlZCAtIHRvIGJlIGNsZWFyLCB0aGlzIGRhdGEgaXMgTk9UIGludGVncmF0ZWQhCgpGb3IgaW5wdXQgdG8gaW50ZWdyYXRpb24sIHdlJ2xsIHdhbnQgdGhlIHJlZHVjZWQgZGltZW5zaW9uIGNhbGN1bGF0aW9ucyB0byBjb25zaWRlciBub3JtYWxpemVkIGdlbmUgZXhwcmVzc2lvbiB2YWx1ZXMgZnJvbSBhbGwgc2FtcGxlcyBzaW11bHRhbmVvdXNseS4KU28gd2UnbGwgbmVlZCB0byByZWNhbGN1bGF0ZSBQQ0EgKGFuZCBVTUFQIGZvciB2aXN1YWxpemF0aW9uKSBvbiB0aGUgbWVyZ2VkIG9iamVjdC4KV2UnbGwgYWxzbyBzYXZlIHRoZXNlIG5ldyByZWR1Y2VkIGRpbWVuc2lvbnMgd2l0aCBkaWZmZXJlbnQgbmFtZXMsIGBtZXJnZWRfUENBYCBhbmQgYG1lcmdlZF9VTUFQYCwgdG8gZGlzdGluZ3Vpc2ggdGhlbSBmcm9tIGFscmVhZHktcHJlc2VudCBgUENBYCBhbmQgYFVNQVBgLgoKRmlyc3QsIGFzIHVzdWFsLCB3ZSdsbCBkZXRlcm1pbmUgdGhlIGhpZ2gtdmFyaWFuY2UgZ2VuZXMgdG8gdXNlIGZvciBQQ0EgZnJvbSB0aGUgYG1lcmdlZF9zY2VgIG9iamVjdC4KRm9yIHRoaXMsIHdlJ2xsIG5lZWQgdG8gcHJvdmlkZSB0aGUgYXJndW1lbnQgYGJsb2NrID0gbWVyZ2VkX3NjZSRzYW1wbGVgIHdoZW4gbW9kZWxpbmcgZ2VuZSB2YXJpYW5jZSwgd2hpY2ggdGVsbHMgYHNjcmFuOjptb2RlbEdlbmVWYXIoKWAgdG8gZmlyc3QgbW9kZWwgdmFyaWFuY2Ugc2VwYXJhdGVseSBmb3IgZWFjaCBiYXRjaCBhbmQgdGhlbiBjb21iaW5lIHRob3NlIG1vZGVsaW5nIHN0YXRpc3RpY3MuCgpgYGB7ciBjYWxjIG1lcmdlZCBodiBnZW5lc30KIyBTcGVjaWZ5IHRoZSBudW1iZXIgb2YgZ2VuZXMgdG8gaWRlbnRpZnkKbnVtX2dlbmVzIDwtIDIwMDAKCiMgQ2FsY3VsYXRlIHZhcmlhdGlvbiBmb3IgZWFjaCBnZW5lCmdlbmVfdmFyaWFuY2UgPC0gc2NyYW46Om1vZGVsR2VuZVZhcihtZXJnZWRfc2NlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBzcGVjaWZ5IHRoZSBncm91cGluZyBjb2x1bW46CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBibG9jayA9IG1lcmdlZF9zY2Ukc2FtcGxlKQoKIyBHZXQgdGhlIHRvcCBgbnVtX2dlbmVzYCBoaWdoLXZhcmlhbmNlIGdlbmVzIHRvIHVzZSBmb3IgZGltZW5zaW9uIHJlZHVjdGlvbgpodl9nZW5lcyA8LSBzY3Jhbjo6Z2V0VG9wSFZHcyhnZW5lX3ZhcmlhbmNlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuID0gbnVtX2dlbmVzKQpgYGAKClRvIGNhbGN1bGF0ZSB0aGUgUENBIG1hdHJpeCBpdHNlbGYsIHdlJ2xsIHVzZSBhbiBhcHByb2FjaCBmcm9tIHRoZSBgYmF0Y2hlbG9yYCBwYWNrYWdlLCB3aGljaCBpcyB0aGUgUiBwYWNrYWdlIHRoYXQgY29udGFpbnMgdGhlIGBmYXN0TU5OYCBtZXRob2QuClRoZSBbYGJhdGNoZWxvcjo6bXVsdGlCYXRjaFBDQSgpYF0oaHR0cHM6Ly9yZHJyLmlvL2Jpb2MvYmF0Y2hlbG9yL21hbi9tdWx0aUJhdGNoUENBLmh0bWwpIGZ1bmN0aW9uIGNhbGN1bGF0ZXMgYSBiYXRjaC13ZWlnaHRlZCBQQ0EgbWF0cml4LgpUaGlzIHdlaWdodGluZyBlbnN1cmVzIHRoYXQgYWxsIGJhdGNoZXMsIHdoaWNoIG1heSBoYXZlIHZlcnkgZGlmZmVyZW50IG51bWJlcnMgb2YgY2VsbHMsIGNvbnRyaWJ1dGUgZXF1YWxseSB0byB0aGUgb3ZlcmFsbCBzY2FsaW5nLgoKYGBge3IgbWFrZSBtZXJnZWRfcGNhLCBsaXZlID0gVFJVRX0KIyBVc2UgYmF0Y2hlbG9yIHRvIGNhbGN1bGF0ZSBQQ0EgZm9yIG1lcmdlZF9zY2UsIGNvbnNpZGVyaW5nIG9ubHkKIyAgdGhlIGhpZ2gtdmFyaWFuY2UgZ2VuZXMKIyBXZSdsbCBuZWVkIHRvIGluY2x1ZGUgdGhlIGFyZ3VtZW50IGBwcmVzZXJ2ZS5zaW5nbGUgPSBUUlVFYCB0byBnZXQKIyAgYSBzaW5nbGUgbWF0cml4IHdpdGggYWxsIHNhbXBsZXMgYW5kIG5vdCBzZXBhcmF0ZSBtYXRyaWNlcyBmb3IgZWFjaCBzYW1wbGUKbWVyZ2VkX3BjYSA8LSBiYXRjaGVsb3I6Om11bHRpQmF0Y2hQQ0EobWVyZ2VkX3NjZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3Vic2V0LnJvdyA9IGh2X2dlbmVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYXRjaCA9IG1lcmdlZF9zY2Ukc2FtcGxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmVzZXJ2ZS5zaW5nbGUgPSBUUlVFKQpgYGAKCkxldCdzIGhhdmUgYSBsb29rIGF0IHRoZSBvdXRwdXQ6CmBgYHtyIHByaW50IG1lcmdlZF9wY2EsIGxpdmUgPSBUUlVFfQojIFRoaXMgb3V0cHV0IGlzIG5vdCB2ZXJ5IGludGVyZXN0aW5nIQptZXJnZWRfcGNhCmBgYAoKV2UgY2FuIHVzZSBpbmRleGluZyBgW1sxXV1gIHRvIHNlZSB0aGUgUENBIG1hdHJpeCBjYWxjdWxhdGVkLCBsb29raW5nIGF0IGEgc21hbGwgc3Vic2V0IGZvciBjb252ZW5pZW5jZToKCmBgYHtyIHByaW50IG1lcmdlZF9wY2EgaW5kZXhlZCwgbGl2ZSA9IFRSVUV9Cm1lcmdlZF9wY2FbWzFdXVsxOjUsMTo1XQpgYGAKCldlIGNhbiBub3cgaW5jbHVkZSB0aGlzIFBDQSBtYXRyaXggaW4gb3VyIGBtZXJnZWRfc2NlYCBvYmplY3Q6CgpgYGB7ciBhZGQgbWVyZ2VkX3BjYSwgbGl2ZSA9IFRSVUV9CiMgYWRkIFBDQSByZXN1bHRzIHRvIG1lcmdlZCBTQ0Ugb2JqZWN0CnJlZHVjZWREaW0obWVyZ2VkX3NjZSwgIm1lcmdlZF9QQ0EiKSA8LSBtZXJnZWRfcGNhW1sxXV0KYGBgCgpOb3cgdGhhdCB3ZSBoYXZlIHRoZSBQQ0EgbWF0cml4LCB3ZSBjYW4gcHJvY2VlZCB0byBjYWxjdWxhdGUgVU1BUCB0byB2aXN1YWxpemUgdGhlIHVuY29ycmVjdGVkIG1lcmdlZCBkYXRhLgoKV2UnbGwgY2FsY3VsYXRlIFVNQVAgYXMgInVzdWFsIiwgYnV0IGluIHRoaXMgY2FzZSB3ZSdsbCBzcGVjaWZ5IHR3byBhZGRpdGlvbmFsIGFyZ3VtZW50czoKCi0gYGRpbXJlZCA9ICJtZXJnZWRfUENBImAsIHdoaWNoIHNwZWNpZmllcyB3aGljaCBleGlzdGluZyByZWR1Y2VkIGRpbWVuc2lvbiBzaG91bGQgYmUgdXNlZCBmb3IgdGhlIGNhbGN1bGF0aW9uLgpXZSB3YW50IHRvIHVzZSB0aGUgYmF0Y2gtd2VpZ2h0ZWQgUENBLCB3aGljaCB3ZSBuYW1lZCBhYm92ZSBhcyBgIm1lcmdlZF9QQ0EiYC4KLSBgbmFtZSA9ICJtZXJnZWRfVU1BUCJgLCB3aGljaCBuYW1lcyB0aGUgZmluYWwgVU1BUCB0aGF0IHRoaXMgZnVuY3Rpb24gY2FsY3VsYXRlcy4KVGhpcyBhcmd1bWVudCB3aWxsIHByZXZlbnQgdXMgZnJvbSBvdmVyd3JpdGluZyB0aGUgZXhpc3RpbmcgVU1BUCB3aGljaCBpcyBhbHJlYWR5IG5hbWVkICJVTUFQIiBhbmQgaW5zdGVhZCBjcmVhdGUgYSBzZXBhcmF0ZSBgIm1lcmdlZF9VTUFQImAuCgpgYGB7ciBjYWxjdWxhdGUgbWVyZ2VkIHVtYXAsIGxpdmUgPSBUUlVFfQojIGFkZCBtZXJnZWRfVU1BUCBmcm9tIG1lcmdlZF9QQ0EKbWVyZ2VkX3NjZSA8LSBzY2F0ZXI6OnJ1blVNQVAobWVyZ2VkX3NjZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGltcmVkID0gIm1lcmdlZF9QQ0EiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIm1lcmdlZF9VTUFQIikKYGBgCgpOb3csIGxldCdzIHNlZSBob3cgdGhpcyBuZXcgYG1lcmdlZF9VTUFQYCBsb29rcyBjb21wYXJlZCB0byB0aGUgYFVNQVBgIGNhbGN1bGF0ZWQgZnJvbSBpbmRpdmlkdWFsIHNhbXBsZXM6CgpgYGB7ciBwbG90IHVuY29ycmVjdGVkIG1lcmdlZCBVTUFQfQojIFVNQVBzIHNjYWxlZCB0b2dldGhlciB3aGVuIGNhbGN1bGF0ZWQgZnJvbSB0aGUgbWVyZ2VkIFNDRQpzY2F0ZXI6OnBsb3RSZWR1Y2VkRGltKG1lcmdlZF9zY2UsCiAgICAgICAgICAgICAgICAgICAgICAgZGltcmVkID0gIm1lcmdlZF9VTUFQIiwKICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXJfYnkgPSAic2FtcGxlIiwKICAgICAgICAgICAgICAgICAgICAgICAjIFNvbWUgc3R5bGluZyB0byBoZWxwIHVzIHNlZSB0aGUgcG9pbnRzOgogICAgICAgICAgICAgICAgICAgICAgIHBvaW50X3NpemUgPSAwLjUsCiAgICAgICAgICAgICAgICAgICAgICAgcG9pbnRfYWxwaGEgPSAwLjIpICsKICAjIE1vZGlmeSB0aGUgbGVnZW5kIGtleSBzbyBpdHMgcG9pbnRzIGFyZSBsYXJnZXIgYW5kIGVhc2llciB0byBzZWUKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDMsIGFscGhhID0gMSkpKSArCiAgIyBBZGQgYSBwbG90IHRpdGxlCiAgZ2d0aXRsZSgiVU1BUCBjYWxjdWxhdGVkIG9uIG1lcmdlZF9zY2UiKQpgYGAKClNhbXBsZXMgYXJlIG5vdyBzZXBhcmF0ZWQsIHdoaWNoIG1vcmUgcmVhc29uYWJseSByZWZsZWN0cyB0aGF0IHRoaXMgZGF0YSBpcyBfbm90IHlldCBiYXRjaC1jb3JyZWN0ZWRfLgpXZSBjYW4gdGhpbmsgb2YgdGhpcyBVTUFQIGFzIG91ciAiYmVmb3JlIiBVTUFQLCBhbmQgd2UgY2FuIGNvbXBhcmUgdGhpcyB0byB0aGUgImFmdGVyIiBVTUFQIHdlIHNlZSBwb3N0LWludGVncmF0aW9uLgoKTGV0J3MgZGlzY3VzcyBhIGxpdHRsZSBmaXJzdDogV2hhdCB2aXN1YWwgZGlmZmVyZW5jZXMgZG8geW91IHRoaW5rIHRoZSBVTUFQIG9uIHRoZSBpbnRlZ3JhdGVkIHZlcnNpb24gb2YgZGF0YSB3aWxsIGhhdmU/CldoYXQgc2ltaWxhcml0aWVzIGRvIHlvdSB0aGluayB0aGUgaW50ZWdyYXRlZCBVTUFQIHdpbGwgaGF2ZSB0byB0aGlzIHBsb3Q/CgoKIyMjIEludGVncmF0aW9uIHdpdGggYGZhc3RNTk5gCgpGaW5hbGx5LCB3ZSdyZSByZWFkeSB0byBpbnRlZ3JhdGUhClRvIHN0YXJ0LCB3ZSdsbCB1c2UgdGhlIGBmYXN0TU5OYCBhcHByb2FjaCBmcm9tIHRoZSBCaW9jb25kdWN0b3IgW2BiYXRjaGVsb3JgIHBhY2thZ2VdKGh0dHA6Ly93d3cuYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy8zLjE2L2Jpb2MvaHRtbC9iYXRjaGVsb3IuaHRtbCkuCgpgZmFzdE1OTmAgdGFrZXMgYXMgaW5wdXQgdGhlIGBtZXJnZWRfc2NlYCBvYmplY3QgdG8gaW50ZWdyYXRlLCBhbmQgdGhlIGZpcnN0IHN0ZXAgaXQgcGVyZm9ybXMgaXMgYWN0dWFsbHkgdG8gcnVuIGBiYXRjaGVsb3I6Om11bHRpQmF0Y2hQQ0EoKWAgb24gdGhhdCBTQ0UuCkl0IHRoZW4gdXNlcyB0aGF0IGJhdGNoLXdlaWdodGVkIFBDQSBtYXRyaXggdG8gcGVyZm9ybSB0aGUgYWN0dWFsIGJhdGNoIGNvcnJlY3Rpb24uClRoZSBgYmF0Y2hgIGFyZ3VtZW50IGlzIHVzZWQgdG8gc3BlY2lmeSB0aGUgZGlmZmVyZW50IGdyb3VwaW5ncyB3aXRoaW4gdGhlIGBtZXJnZWRfc2NlYCAoaS5lLiB0aGUgb3JpZ2luYWwgc2FtcGxlIHRoYXQgZWFjaCBjZWxsIGJlbG9uZ3MgdG8pLCBhbmQgdGhlIGBzdWJzZXQucm93YCBhcmd1bWVudCBjYW4gb3B0aW9uYWxseSBiZSB1c2VkIHRvIHByb3ZpZGUgYSB2ZWN0b3Igb2YgaGlnaC12YXJpYW5jZSBnZW5lcyB0aGF0IHNob3VsZCBiZSBjb25zaWRlcmVkIGZvciB0aGlzIFBDQSBjYWxjdWxhdGlvbi4KYGZhc3RNTk5gIHdpbGwgcmV0dXJuIGFuIFNDRSBvYmplY3QgdGhhdCBjb250YWlucyBhIGJhdGNoLWNvcnJlY3RlZCBQQ0EuCkxldCdzIHJ1biBpdCBhbmQgc2F2ZSB0aGUgcmVzdWx0IHRvIGEgdmFyaWFibGUgY2FsbGVkIGBpbnRlZ3JhdGVkX3NjZWAuCgoKYGBge3IgcnVuIGZhc3Rtbm4sIGxpdmUgPSBUUlVFfQojIGludGVncmF0ZSB3aXRoIGZhc3RNTk4sIGFnYWluIHNwZWNpZnlpbmcgb25seSBvdXIgaGlnaC12YXJpYW5jZSBnZW5lcwppbnRlZ3JhdGVkX3NjZSA8LSBiYXRjaGVsb3I6OmZhc3RNTk4oCiAgbWVyZ2VkX3NjZSwKICBiYXRjaCA9IG1lcmdlZF9zY2Ukc2FtcGxlLAogIHN1YnNldC5yb3cgPSBodl9nZW5lcwopCmBgYAoKTGV0J3MgaGF2ZSBhIGxvb2sgYXQgdGhlIHJlc3VsdDoKCmBgYHtyIGZhc3Rtbm4gcmVzdWx0LCBsaXZlID0gVFJVRX0KIyBQcmludCB0aGUgaW50ZWdyYXRlZF9zY2Ugb2JqZWN0CmludGVncmF0ZWRfc2NlCmBgYAoKVGhlcmUgYXJlIGNvdXBsZSBwaWVjZXMgb2YgaW5mb3JtYXRpb24gaGVyZSBvZiBpbnRlcmVzdDoKCi0gVGhlIGBjb3JyZWN0ZWRgIHJlZHVjZWQgZGltZW5zaW9uIHJlcHJlc2VudHMgdGhlIGJhdGNoLWNvcnJlY3RlZCBQQ0EgdGhhdCBgZmFzdE1OTmAgY2FsY3VsYXRlZC4KLSBUaGUgYHJlY29uc3RydWN0ZWRgIGFzc2F5IHJlcHJlc2VudHMgdGhlIGJhdGNoLWNvcnJlY3RlZCBub3JtYWxpemVkIGV4cHJlc3Npb24gdmFsdWVzLCB3aGljaCBgZmFzdE1OTmAgImJhY2stY2FsY3VsYXRlZCIgZnJvbSB0aGUgYmF0Y2gtY29ycmVjdGVkIFBDQSAoYGNvcnJlY3RlZGApLgpHZW5lcmFsbHkgc3BlYWtpbmcsIHRoZXNlIGV4cHJlc3Npb24gdmFsdWVzIGFyZSBub3Qgc3RhbmQtYWxvbmUgdmFsdWVzIHRoYXQgeW91IHNob3VsZCB1c2UgZm9yIG90aGVyIGFwcGxpY2F0aW9ucyBsaWtlIGRpZmZlcmVudGlhbCBnZW5lIGV4cHJlc3Npb24sIGFzIGRlc2NyaWJlZCBpbiBbX09yY2hlc3RyYXRpbmcgU2luZ2xlIENlbGwgQW5hbHlzZXNfXShodHRwOi8vYmlvY29uZHVjdG9yLm9yZy9ib29rcy8zLjE2L09TQ0EubXVsdGlzYW1wbGUvdXNpbmctY29ycmVjdGVkLXZhbHVlcy5odG1sKS4KSWYgdGhlIGBzdWJzZXQucm93YCBhcmd1bWVudCBpcyBwcm92aWRlZCAoYXMgaXQgd2FzIGhlcmUpLCBvbmx5IGdlbmVzIHByZXNlbnQgaW4gYHN1YnNldC5yb3dgIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlc2UgcmVjb25zdHJ1Y3RlZCBleHByZXNzaW9uIHZhbHVlcywgYnV0IHRoaXMgc2V0dGluZyBjYW4gYmUgb3ZlcnJpZGRlbiBzbyB0aGF0IGFsbCBnZW5lcyBoYXZlIHJlY29uc3RydWN0ZWQgZXhwcmVzc2lvbiB3aXRoIHRoZSBhcmd1bWVudCBgY29ycmVjdC5hbGwgPSBUUlVFYC4KCldlJ3JlIG1vc3RseSBpbnRlcmVzdGVkIGluIHRoZSBQQ0EgdGhhdCBgZmFzdE1OTmAgY2FsY3VsYXRlZCwgc28gbGV0J3Mgc2F2ZSB0aGF0IGluZm9ybWF0aW9uICh3aXRoIGFuIGluZm9ybWF0aXZlIGFuZCB1bmlxdWUgbmFtZSkgaW50byBvdXIgYG1lcmdlZF9zY2VgIG9iamVjdDoKCmBgYHtyIGZhc3Rtbm4gcGNzLCBsaXZlID0gVFJVRX0KIyBNYWtlIGEgbmV3IHJlZHVjZWREaW0gbmFtZWQgZmFzdG1ubl9QQ0EgZnJvbSB0aGUgY29ycmVjdGVkIHJlZHVjZWREaW0gaW4gaW50ZWdyYXRlZF9zY2UKcmVkdWNlZERpbShtZXJnZWRfc2NlLCAiZmFzdG1ubl9QQ0EiKSA8LSByZWR1Y2VkRGltKGludGVncmF0ZWRfc2NlLCAiY29ycmVjdGVkIikKYGBgCgpGaW5hbGx5LCB3ZSdsbCBjYWxjdWxhdGUgVU1BUCBmcm9tIHRoZXNlIGNvcnJlY3RlZCBQQ0EgbWF0cml4IGZvciB2aXN1YWxpemF0aW9uLgoKYGBge3IgY2FsY3VsYXRlIGZhc3Rtbm4gdW1hcCwgbGl2ZSA9IFRSVUV9CiMgQ2FsY3VsYXRlIFVNQVAKbWVyZ2VkX3NjZSA8LSBzY2F0ZXI6OnJ1blVNQVAoCiAgbWVyZ2VkX3NjZSwKICBkaW1yZWQgPSAiZmFzdG1ubl9QQ0EiLAogIG5hbWUgPSAiZmFzdG1ubl9VTUFQIgopCmBgYAoKRmlyc3QsIGxldCdzIHBsb3QgdGhlIGludGVncmF0ZWQgVU1BUCBoaWdobGlnaHRpbmcgdGhlIGRpZmZlcmVudCBiYXRjaGVzLgpBIHdlbGwtaW50ZWdyYXRlZCBkYXRhc2V0IHdpbGwgc2hvdyBiYXRjaCBtaXhpbmcsIGJ1dCBhIHBvb3JseS1pbnRlZ3JhdGVkIGRhdGFzZXQgd2lsbCBzaG93IG1vcmUgc2VwYXJhdGlvbiBhbW9uZyBiYXRjaGVzLCBzaW1pbGFyIHRvIHRoZSB1bmNvcnJlY3RlZCBVTUFQLgpOb3RlIHRoYXQgdGhpcyBpcyBhIG1vcmUgcXVhbGl0YXRpdmUgd2F5IHRvIGFzc2VzcyB0aGUgc3VjY2VzcyBvZiBpbnRlZ3JhdGlvbiwgYnV0IHRoZXJlIGFyZSBmb3JtYWwgbWV0cmljcyBvbmUgY2FuIHVzZSB0byBhc3Nlc3MgYmF0Y2ggbWl4aW5nLCB3aGljaCB5b3UgY2FuIHJlYWQgbW9yZSBhYm91dCBpbiBbdGhpcyBjaGFwdGVyIG9mIE9TQ0FdKGh0dHA6Ly9iaW9jb25kdWN0b3Iub3JnL2Jvb2tzLzMuMTYvT1NDQS5tdWx0aXNhbXBsZS9jb3JyZWN0aW9uLWRpYWdub3N0aWNzLmh0bWwpLgoKYGBge3IgcGxvdCBmYXN0bW5uIHVtYXAgYmF0Y2hlc30Kc2NhdGVyOjpwbG90UmVkdWNlZERpbShtZXJnZWRfc2NlLAogICAgICAgICAgICAgICAgICAgICAgICMgcGxvdCB0aGUgZmFzdE1OTiBjb29yZGluYXRlcwogICAgICAgICAgICAgICAgICAgICAgIGRpbXJlZCA9ICJmYXN0bW5uX1VNQVAiLAogICAgICAgICAgICAgICAgICAgICAgICMgY29sb3IgYnkgc2FtcGxlCiAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyX2J5ID0gInNhbXBsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgIyBTb21lIHN0eWxpbmcgdG8gaGVscCB1cyBzZWUgdGhlIHBvaW50czoKICAgICAgICAgICAgICAgICAgICAgICBwb2ludF9zaXplID0gMC41LAogICAgICAgICAgICAgICAgICAgICAgIHBvaW50X2FscGhhID0gMC4yKSArCiAgIyBNb2RpZnkgbGVnZW5kIHNvIHRoZXkga2V5IGlzIGxhcmdlciBhbmQgZWFzaWVyIHRvIHNlZQogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMywgYWxwaGEgPSAxKSkpICsKICAjIGFkZCBwbG90IHRpdGxlCiAgZ2d0aXRsZSgiVU1BUCBhZnRlciBpbnRlZ3JhdGlvbiB3aXRoIGZhc3RNTk4iKQpgYGAKClRoaXMgYGZhc3Rtbm5fVU1BUGAgY2VydGFpbmx5IGxvb2tzIGRpZmZlcmVudCBmcm9tIHRoZSBvbmUgd2UgbWFkZSBmcm9tIGBtZXJnZWRfVU1BUGAhCldoYXQgZGlmZmVyZW50IHRyZW5kcyBkbyB5b3Ugc2VlPwpEbyBhbGwgc2FtcGxlcyBsb29rICJlcXVhbGx5IHdlbGwiIGludGVncmF0ZWQsIGZyb20gYSBmaXJzdCBsb29rPwoKSW1wb3J0YW50bHksIG9uZSByZWFzb24gdGhhdCBiYXRjaGVzIG1heSBzdGlsbCBhcHBlYXIgc2VwYXJhdGVkIGluIHRoZSBjb3JyZWN0ZWQgVU1BUCBpcyBpZiB0aGV5IF9zaG91bGRfIGJlIHNlcGFyYXRlZCAtIGZvciBleGFtcGxlLCBtYXliZSB0d28gYmF0Y2hlcyBjb250YWluIHZlcnkgZGlmZmVyZW50IGNlbGwgdHlwZXMsIGhhdmUgdmVyeSBkaWZmZXJlbnQgZGlhZ25vc2VzLCBvciBtYXkgYmUgZnJvbSBkaWZmZXJlbnQgcGF0aWVudHMuCgpSZWNhbGwgZnJvbSBlYXJsaWVyIHRoYXQgd2UgY29udmVuaWVudGx5IGhhdmUgY2VsbCB0eXBlIGFubm90YXRpb25zIGluIG91ciBTQ0VzLCBzbyB3ZSBjYW4gZXhwbG9yZSB0aG9zZSBoZXJlIQpMZXQncyB0YWtlIGEgcXVpY2sgZGV0b3VyIHRvIHNlZSB3aGF0IGtpbmRzIG9mIGNlbGwgdHlwZXMgYXJlIGluIHRoaXMgZGF0YSBieSBtYWtpbmcgYSBiYXJwbG90IG9mIHRoZSBjZWxsIHR5cGVzIGFjcm9zcyBzYW1wbGVzOgoKYGBge3IgZXhwbG9yZSBjZWxsdHlwZXN9CiMgQ2VsbCB0eXBlcyBhcmUgaW4gdGhlIGBjZWxsdHlwZV9icm9hZGAgYW5kIGBjZWxsdHlwZV9maW5lYCBjb2x1bW5zCm1lcmdlZF9zY2VfZGYgPC0gYXMuZGF0YS5mcmFtZShjb2xEYXRhKG1lcmdlZF9zY2UpKQoKIyBVc2UgZ2dwbG90MiB0byBtYWtlIGEgYmFycGxvdCB0aGUgY2VsbCB0eXBlcyBhY3Jvc3Mgc2FtcGxlcwpnZ3Bsb3QobWVyZ2VkX3NjZV9kZiwKICAgICAgIGFlcyh4ID0gc2FtcGxlLAogICAgICAgICAgIGZpbGwgPSBjZWxsdHlwZV9icm9hZCkpICsKICAjIEJhcnBsb3Qgb2YgY2VsbHR5cGUgcHJvcG9ydGlvbnMKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJmaWxsIikgKwogICMgVXNlIGEgQ1ZELWZyaWVuZGx5IGNvbG9yIHNjaGVtZQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiLCBuYS52YWx1ZSA9ICJncmV5ODAiKSArCiAgIyBuaWNlciB0aGVtZQogIHRoZW1lX2J3KCkKYGBgCgpXZSBzZWUgdGhhdCBUdW1vciBjZWxsIHR5cGVzIGFyZSBieSBmYXIgdGhlIG1vc3QgcHJldmFsZW50IGFjcm9zcyBhbGwgc2FtcGxlcywgYW5kIG5vcm1hbCB0aXNzdWUgY2VsbCB0eXBlcyBhcmUgbm90IHZlcnkgY29tbW9uLgpXZSBzZWUgYWxzbyB0aGF0IGBTQ1BDTDAwMDQ4MWAgaGFzIGEgbGFyZ2VyIGBUdW1vcl9NeW9jeXRlYCBwb3B1bGF0aW9uLCB3aGlsZSBhbGwgb3RoZXIgc2FtcGxlcyBoYXZlIGxhcmdlciBgVHVtb3JfTWVzb2Rlcm1gIHBvcHVsYXRpb25zLgpUaGlzIGRpZmZlcmVuY2UgX21heV8gZXhwbGFpbiB3aHkgd2Ugb2JzZXJ2ZSB0aGF0IGBTQ1BDTDAwMDQ4MWAgaXMgc29tZXdoYXQgbW9yZSBzZXBhcmF0ZWQgZnJvbSB0aGUgb3RoZXIgc2FtcGxlcyBpbiB0aGUgYGZhc3RNTk5gIFVNQVAuCgpMZXQncyByZS1wbG90IHRoaXMgVU1BUCB0byBoaWdobGlnaHQgY2VsbCB0eXBlczoKCgpgYGB7ciBwbG90IGZhc3Rtbm4gdW1hcCBjZWxsdHlwZXN9CnNjYXRlcjo6cGxvdFJlZHVjZWREaW0obWVyZ2VkX3NjZSwKICAgICAgICAgICAgICAgICAgICAgICBkaW1yZWQgPSAiZmFzdG1ubl9VTUFQIiwKICAgICAgICAgICAgICAgICAgICAgICAjIGNvbG9yIGJ5IGJyb2FkIGNlbGx0eXBlcwogICAgICAgICAgICAgICAgICAgICAgIGNvbG91cl9ieSA9ICJjZWxsdHlwZV9icm9hZCIsCiAgICAgICAgICAgICAgICAgICAgICAgcG9pbnRfc2l6ZSA9IDAuNSwKICAgICAgICAgICAgICAgICAgICAgICBwb2ludF9hbHBoYSA9IDAuMikgKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMywgYWxwaGEgPSAxKSkpICsKICBnZ3RpdGxlKCJVTUFQIGFmdGVyIGludGVncmF0aW9uIHdpdGggZmFzdE1OTiIpCmBgYAoKVGhpcyBVTUFQIHNob3dzIHRoYXQgdGhlIG5vcm1hbCB0aXNzdWUgY2VsbCB0eXBlcyAobW9zdGx5IHZhc2N1bGFyIGVuZG90aGVsaXVtLCBtdXNjbGUgY2VsbHMsIGFuZCBtb25vY3l0ZXMpIHRlbmQgdG8gY2x1c3RlciB0b2dldGhlciBhbmQgYXJlIGdlbmVyYWxseSBzZXBhcmF0ZWQgZnJvbSB0aGUgdHVtb3IgY2VsbCB0eXBlcywgd2hpY2ggaXMgYW4gZW5jb3VyYWdpbmcgcGF0dGVybiEKVHVtb3IgY2VsbCB0eXBlcyBmcm9tIGRpZmZlcmVudCBzYW1wbGVzIGFyZSBhbGwgYWxzbyBjbHVzdGVyaW5nIHRvZ2V0aGVyLCB3aGljaCBpcyBldmVuIG1vcmUgZW5jb3VyYWdpbmcgdGhhdCB3ZSBoYWQgc3VjY2Vzc2Z1bCBpbnRlZ3JhdGlvbi4KCkhvd2V2ZXIsIGl0J3MgYSBiaXQgY2hhbGxlbmdpbmcgdG8gc2VlIGFsbCB0aGUgcG9pbnRzIGdpdmVuIHRoZSBhbW91bnQgb2Ygb3ZlcmxhcCBpbiB0aGUgcGxvdC4KT25lIHdheSB3ZSBjYW4gc2VlIGFsbCB0aGUgcG9pbnRzIGEgYml0IGJldHRlciBpcyB0byBmYWNldCB0aGUgcGxvdCBieSBzYW1wbGUsIHVzaW5nIGBmYWNldF93cmFwKClgIGZyb20gdGhlIGBnZ3Bsb3QyYCBwYWNrYWdlICh3aGljaCB3ZSBjYW4gZG8gYmVjYXVzZSBgc2NhdGVyOjpwbG90UmVkdWNlZERpbSgpYCByZXR1cm5zIGEgYGdncGxvdDJgIG9iamVjdCk6CgpgYGB7ciBwbG90IGZhc3Rtbm4gdW1hcCBjZWxsdHlwZXMgZmFjZXRlZH0Kc2NhdGVyOjpwbG90UmVkdWNlZERpbShtZXJnZWRfc2NlLAogICAgICAgICAgICAgICAgICAgICAgIGRpbXJlZCA9ICJmYXN0bW5uX1VNQVAiLAogICAgICAgICAgICAgICAgICAgICAgIGNvbG91cl9ieSA9ICJjZWxsdHlwZV9icm9hZCIsCiAgICAgICAgICAgICAgICAgICAgICAgcG9pbnRfc2l6ZSA9IDAuNSwKICAgICAgICAgICAgICAgICAgICAgICBwb2ludF9hbHBoYSA9IDAuMiwKICAgICAgICAgICAgICAgICAgICAgICAjIEFsbG93IGZvciBmYWNldGluZyBieSBhIHZhcmlhYmxlIHVzaW5nIGBvdGhlcl9maWVsZHNgOgogICAgICAgICAgICAgICAgICAgICAgIG90aGVyX2ZpZWxkcyA9ICJzYW1wbGUiKSArCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzLCBhbHBoYSA9IDEpKSkgKwogIGdndGl0bGUoIlVNQVAgYWZ0ZXIgaW50ZWdyYXRpb24gd2l0aCBmYXN0TU5OIikgKwogICMgRmFjZXQgYnkgc2FtcGxlCiAgZmFjZXRfd3JhcCh2YXJzKHNhbXBsZSkpICsKICAjIFVzZSBhIHRoZW1lIHdpdGggYmFja2dyb3VuZCBncmlkIHRvIG1vcmUgZWFzaWx5IGNvbXBhcmUgcGFuZWwgY29vcmRpbmF0ZXMKICB0aGVtZV9idygpCmBgYAoKV2hhdCB0cmVuZHMgZG8geW91IG9ic2VydmUgYmV0d2VlbiB0dW1vciBhbmQgaGVhbHRoeSB0aXNzdWVzIGFtb25nIHRoZXNlIGludGVncmF0ZWQgc2FtcGxlcz8KCgojIyMgSW50ZWdyYXRpb24gd2l0aCBgaGFybW9ueWAKCmBmYXN0TU5OYCBpcyBvbmx5IG9uZSBvZiBtYW55IGFwcHJvYWNoZXMgdG8gcGVyZm9ybSBpbnRlZ3JhdGlvbiwgYW5kIGRpZmZlcmVudCBtZXRob2RzIGhhdmUgZGlmZmVyZW50IGNhcGFiaWxpdGllcyBhbmQgbWF5IGdpdmUgZGlmZmVyZW50IHJlc3VsdHMuCkZvciBleGFtcGxlLCBzb21lIG1ldGhvZHMgY2FuIGFjY29tbW9kYXRlIGFkZGl0aW9uYWwgY292YXJpYXRlcyAoZS5nLiwgdGVjaG5vbG9neSwgcGF0aWVudCwgZGlhZ25vc2lzLCBldGMuKSB0aGF0IGNhbiBpbmZsdWVuY2UgaW50ZWdyYXRpb24uCkluIGZhY3QgdGhlIGRhdGEgd2UgYXJlIHVzaW5nIGhhcyBhIGtub3duIF9wYXRpZW50XyBjb3ZhcmlhdGU7IGBTQ1BDTDAwMDQ3OWAgYW5kIGBTQ1BDTDAwMDQ4MGAgYXJlIGZyb20gdGhlIGZpcnN0IHBhdGllbnQsIGFuZCBgU0NQQ0wwMDA0ODFgIGFuZCBgU0NQQ0wwMDA0ODJgIGFyZSBmcm9tIHRoZSBzZWNvbmQgcGF0aWVudC4KClNvLCBsZXQncyBwZXJmb3JtIGludGVncmF0aW9uIHdpdGggYSBtZXRob2QgdGhhdCBjYW4gdXNlIHRoaXMgaW5mb3JtYXRpb24gLSBbYGhhcm1vbnlgXShodHRwczovL3BvcnRhbHMuYnJvYWRpbnN0aXR1dGUub3JnL2hhcm1vbnkvKSEKClRvIGJlZ2luIHNldHRpbmcgdXAgZm9yIGBoYXJtb255YCBpbnRlZ3JhdGlvbiwgd2UgbmVlZCB0byBhZGQgZXhwbGljaXQgcGF0aWVudCBpbmZvcm1hdGlvbiBpbnRvIG91ciBtZXJnZWQgU0NFLgpXZSdsbCBjcmVhdGUgYSBuZXcgY29sdW1uIGBwYXRpZW50YCB3aG9zZSB2YWx1ZSBpcyBlaXRoZXIgIkEiIG9yICJCIiBkZXBlbmRpbmcgb24gdGhlIGdpdmVuIHNhbXBsZSBuYW1lLCB1c2luZyB0aGUgW2BkcGx5cjo6Y2FzZV93aGVuKClgXShodHRwczovL2RwbHlyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL2Nhc2Vfd2hlbi5odG1sKSBmdW5jdGlvbi4KV2UgcHJvdmlkZSB0aGlzIGZ1bmN0aW9uIHdpdGggYSBzZXQgb2YgbG9naWNhbCBleHByZXNzaW9ucyBhbmQgZWFjaCBhc3NpZ25lZCB2YWx1ZSBpcyBkZXNpZ25hdGVkIGJ5IGB+YC4KVGhlIGV4cHJlc3Npb25zIGFyZSBldmFsdWF0ZWQgaW4gb3JkZXIsIHN0b3BwaW5nIGF0IHRoZSBfZmlyc3RfIG9uZSB0aGF0IGV2YWx1YXRlcyBhcyBgVFJVRWAgYW5kIHJldHVybmluZyB0aGUgYXNzb2NpYXRlZCB2YWx1ZS4KCmBgYHtyIGFkZCBwYXRpZW50IGluZm99CiMgQ3JlYXRlIHBhdGllbnQgY29sdW1uIHdpdGggdmFsdWVzICJBIiBvciAiQiIgZm9yIHRoZSB0d28gcGF0aWVudHMKbWVyZ2VkX3NjZSRwYXRpZW50IDwtIGRwbHlyOjpjYXNlX3doZW4oCiAgbWVyZ2VkX3NjZSRzYW1wbGUgJWluJSBjKCJTQ1BDTDAwMDQ3OSIsICJTQ1BDTDAwMDQ4MCIpIH4gIkEiLAogIG1lcmdlZF9zY2Ukc2FtcGxlICVpbiUgYygiU0NQQ0wwMDA0ODEiLCAiU0NQQ0wwMDA0ODIiKSB+ICJCIiwKKQpgYGAKCgpVbmxpa2UgYGZhc3RNTk5gLCBgaGFybW9ueWAgZG9lcyBub3QgY2FsY3VsYXRlIGNvcnJlY3RlZCBleHByZXNzaW9uIHZhbHVlcyBub3IgZG9lcyBpdCByZXR1cm4gYW4gU0NFIG9iamVjdC4KTGlrZSBgZmFzdE1OTmAsIGBoYXJtb255YCBwZXJmb3JtcyBpbnRlZ3JhdGlvbiBvbiBhIG1lcmdlZCBQQ0EgbWF0cml4LgpIb3dldmVyLCB1bmxpa2UgYGZhc3RNTk5gLCBgaGFybW9ueWAgZG9lcyBub3QgImJhY2stY2FsY3VsYXRlIiBjb3JyZWN0ZWQgZXhwcmVzc2lvbiBmcm9tIHRoZSBjb3JyZWN0ZWQgUENBIG1hdHJpeCBhbmQgaXQgb25seSByZXR1cm5zIHRoZSBjb3JyZWN0ZWQgUENBIG1hdHJpeCBpdHNlbGYuCkZvciBpbnB1dCwgYGhhcm1vbnlgIG5lZWRzIGEgY291cGxlIHBpZWNlcyBvZiBpbmZvcm1hdGlvbjoKCi0gRmlyc3QsIGBoYXJtb255YCBjYW4gZWl0aGVyIHRha2UgYSBtYXRyaXggb2Ygbm9ybWFsaXplZCBleHByZXNzaW9uIHZhbHVlcywgZnJvbSB3aGljaCBpdCB3aWxsIGNhbGN1bGF0ZSBhIGJhdGNoLXdlaWdodGVkIFBDQSBtYXRyaXggdG8gaW50ZWdyYXRlLCBvciBpdCBjYW4gdGFrZSBhIGJhdGNoLXdlaWdodGVkIFBDQSBtYXRyaXggZGlyZWN0bHkgdG8gcGVyZm9ybSBpbnRlZ3JhdGlvbi4KU2luY2Ugd2UgYWxyZWFkeSBjYWxjdWxhdGVkIGEgYmF0Y2gtd2VpZ2h0ZWQgUENBIG1hdHJpeCAob3VyIGBtZXJnZWRfUENBYCByZWR1Y2VkIGRpbWVuc2lvbiksIHdlJ2xsIHByb3ZpZGUgdGhpcyBpbmZvcm1hdGlvbiBkaXJlY3RseS4KICAtIFdlIHdpbGwgbmVlZCB0byBzcGVjaWZ5IHRoZSBhZGRpdGlvbmFsIGFyZ3VtZW50IGBkb19wY2E9RkFMU0VgIHRvIHRlbGwgYGhhcm1vbnlgIHRoYXQgdGhlIGlucHV0IG1hdHJpeCB3ZSBwcm92aWRlZCBhbHJlYWR5IGlzIGEgUENBIG1hdHJpeC4KLSBTZWNvbmQsIHdlIG5lZWQgdG8gdGVsbCBgaGFybW9ueWAgYWJvdXQgdGhlIGNvdmFyaWF0ZXMgdG8gdXNlIC0gYHNhbXBsZWAgYW5kIGBwYXRpZW50YC4KVG8gZG8gdGhpcywgd2UgcHJvdmlkZSB0d28gYXJndW1lbnRzOgogIC0gYG1ldGFfZGF0YWAsIGEgZGF0YSBmcmFtZSB0aGF0IGNvbnRhaW5zIGNvdmFyaWF0ZXMgYWNyb3NzIHNhbXBsZXMuCiAgV2UgY2FuIHNpbXBseSBzcGVjaWZ5IHRoZSBTQ0UgYGNvbERhdGFgIGhlcmUgc2luY2UgaXQgY29udGFpbnMgYHNhbXBsZWAgYW5kIGBwYXRpZW50YCBjb2x1bW5zLgogIC0gYHZhcnNfdXNlYCwgYSB2ZWN0b3Igb2Ygd2hpY2ggY29sdW1uIG5hbWVzIGluIGBtZXRhX2RhdGFgIHNob3VsZCBhY3R1YWxseSBiZSB1c2VkIGFzIGNvdmFyaWF0ZXMuCiAgT3RoZXIgY29sdW1ucyBpbiBgbWV0YV9kYXRhYCB3aGljaCBhcmUgbm90IGluIGB2YXJzX3VzZWAgYXJlIGlnbm9yZWQuCgpMZXQncyBnbyEKCmBgYHtyIHJ1biBoYXJtb255LCBsaXZlID0gVFJVRX0KIyBpbnRlZ3JhdGUgd2l0aCBoYXJtb255LCBzZXR0aW5nIHRoZSBhcmd1bWVudCBgZG9fcGNhID0gRkFMU0VgCiMgIHNpbmNlIHdlIGFyZSBwcm92aWRpbmcgYSBQQ0EgbWF0cml4IGRpcmVjdGx5Cmhhcm1vbnlfcGNhIDwtIGhhcm1vbnk6Okhhcm1vbnlNYXRyaXgoCiAgZGF0YV9tYXQgPSByZWR1Y2VkRGltKG1lcmdlZF9zY2UsICJtZXJnZWRfUENBIiksCiAgZG9fcGNhID0gRkFMU0UsCiAgbWV0YV9kYXRhID0gY29sRGF0YShtZXJnZWRfc2NlKSwKICB2YXJzX3VzZSA9IGMoInNhbXBsZSIsICJwYXRpZW50IikKKQpgYGAKClRoZSByZXN1bHQgaXMgYSBQQ0EgbWF0cml4LgpMZXQncyBwcmludCBhIHN1YnNldCBvZiB0aGlzIG1hdHJpeCB0byBzZWUgaXQ6CgpgYGB7ciBwcmludCBoYXJtb255IHJlc3VsdCwgbGl2ZSA9IFRSVUV9CiMgUHJpbnQgdGhlIGhhcm1vbnkgcmVzdWx0Cmhhcm1vbnlfcGNhWzE6NSwgMTo1XQpgYGAKCkFzIHdlIGRpZCB3aXRoIGBmYXN0TU5OYCByZXN1bHRzLCBsZXQncyBzdG9yZSB0aGlzIFBDQSBtYXRyaXggZGlyZWN0bHkgaW4gb3VyIGBtZXJnZWRfc2NlYCBvYmplY3Qgd2l0aCBhbiBpbmZvcm1hdGl2ZSBuYW1lIHRoYXQgd29uJ3Qgb3ZlcndyaXRlIGFueSBvZiB0aGUgZXhpc3RpbmcgUENBIG1hdHJpY2VzLgpXZSdsbCBhbHNvIGNhbGN1bGF0ZSBVTUFQIGZyb20gaXQuCgpgYGB7ciBzYXZlIGhhcm1vbnksIGxpdmUgPSBUUlVFfQojIFN0b3JlIFBDQSBhcyBgaGFybW9ueV9QQ0FgCnJlZHVjZWREaW0obWVyZ2VkX3NjZSwgImhhcm1vbnlfUENBIikgPC0gaGFybW9ueV9wY2EKCiMgQXMgYmVmb3JlLCBjYWxjdWxhdGUgVU1BUCBvbiB0aGlzIFBDQSBtYXRyaXggd2l0aCBhcHByb3ByaWF0ZSBuYW1lcwptZXJnZWRfc2NlIDwtIHNjYXRlcjo6cnVuVU1BUChtZXJnZWRfc2NlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaW1yZWQgPSAiaGFybW9ueV9QQ0EiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lICAgPSAiaGFybW9ueV9VTUFQIikKYGBgCgoKTGV0J3Mgc2VlIGhvdyB0aGUgYGhhcm1vbnlgIFVNQVAsIGNvbG9yZWQgYnkgc2FtcGxlLCBsb29rcyBjb21wYXJlZCB0byB0aGUgYGZhc3RNTk5gIFVNQVA6CgpgYGB7ciBwbG90IGhhcm1vbnkgdW1hcCBiYXRjaGVzfQpzY2F0ZXI6OnBsb3RSZWR1Y2VkRGltKG1lcmdlZF9zY2UsCiAgICAgICAgICAgICAgICAgICAgICAgZGltcmVkID0gImhhcm1vbnlfVU1BUCIsCiAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyX2J5ID0gInNhbXBsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgcG9pbnRfc2l6ZSA9IDAuNSwKICAgICAgICAgICAgICAgICAgICAgICBwb2ludF9hbHBoYSA9IDAuMikgKwogIGdndGl0bGUoIlVNQVAgYWZ0ZXIgaW50ZWdyYXRpb24gd2l0aCBoYXJtb255IikgKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMywgYWxwaGEgPSAxKSkpCmBgYAoKSG93IGRvIHlvdSB0aGluayB0aGlzIGBoYXJtb255YCBVTUFQIGNvbXBhcmVzIHRvIHRoYXQgZnJvbSBgZmFzdE1OTmAgaW50ZWdyYXRpb24/CgpMZXQncyBzZWUgaG93IHRoaXMgVU1BUCBsb29rcyBjb2xvcmVkIGJ5IGNlbGwgdHlwZSwgYW5kIGZhY2V0ZWQgZm9yIHZpc2liaWxpdHk6CgpgYGB7ciBwbG90IGhhcm1vbnkgdW1hcCBjZWxsdHlwZXN9CnNjYXRlcjo6cGxvdFJlZHVjZWREaW0obWVyZ2VkX3NjZSwKICAgICAgICAgICAgICAgICAgICAgICBkaW1yZWQgPSAiaGFybW9ueV9VTUFQIiwKICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXJfYnkgPSAiY2VsbHR5cGVfYnJvYWQiLAogICAgICAgICAgICAgICAgICAgICAgIHBvaW50X3NpemUgPSAwLjUsCiAgICAgICAgICAgICAgICAgICAgICAgcG9pbnRfYWxwaGEgPSAwLjIsCiAgICAgICAgICAgICAgICAgICAgICAgIyBTcGVjaWZ5IHZhcmlhYmxlIGZvciBmYWNldGluZwogICAgICAgICAgICAgICAgICAgICAgIG90aGVyX2ZpZWxkcyA9ICJzYW1wbGUiKSArCiAgZ2d0aXRsZSgiVU1BUCBhZnRlciBpbnRlZ3JhdGlvbiB3aXRoIGhhcm1vbnkiKSArCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzKSkpICsKICBmYWNldF93cmFwKHZhcnMoc2FtcGxlKSkKYGBgCgpXaXRoIHRoZSBmYWNldGVkIHZpZXcsIHdlIGNhbiBub3cgc2VlIHRoYXQgdGhlIHNtYWxsIGFtb3VudHMgb2YgYFR1bW9yX015b2N5dGVgIGZyb20gb3RoZXIgc2FtcGxlcyBhcmUgInB1bGxlZCIgdG93YXJkcyB0aG9zZSBjZWxscyBpbiBgU0NQQ0wwMDA0ODFgLgoKV2hhdCBvdGhlciBwYXR0ZXJucyBkbyB5b3Ugc2VlIHRoYXQgYXJlIHNpbWlsYXIgb3IgZGlmZmVyZW50IGZyb20gdGhlIGBmYXN0TU5OYCBVTUFQPwpIb3cgZG8geW91IHRoaW5rIGBmYXN0TU5OYCB2cy4gYGhhcm1vbnlgIHBlcmZvcm1lZCBpbiBpbnRlZ3JhdGluZyB0aGVzZSBzYW1wbGVzPwoKIyMjIEV4cG9ydAoKRmluYWxseSwgd2UnbGwgZXhwb3J0IHRoZSBmaW5hbCBTQ0Ugb2JqZWN0IHdpdGggYm90aCBgZmFzdE1OTmAgYW5kIGBoYXJtb255YCBpbnRlZ3JhdGlvbiB0byBhIGZpbGUuClNpbmNlIHRoaXMgb2JqZWN0IGlzIHZlcnkgbGFyZ2UgKG92ZXIgMSBHQiEpLCB3ZSdsbCBleHBvcnQgaXQgdG8gYSBmaWxlIHdpdGggc29tZSBjb21wcmVzc2lvbiwgd2hpY2gsIGluIHRoaXMgY2FzZSwgd2lsbCByZWR1Y2UgdGhlIGZpbmFsIHNpemUgdG8gYSBzbWFsbGVyIH4zNjAgTUIuClRoaXMgd2lsbCB0YWtlIGEgY291cGxlIG1pbnV0ZXMgdG8gc2F2ZSB3aGlsZSBjb21wcmVzc2lvbiBpcyBwZXJmb3JtZWQuCgpgYGB7ciBzYXZlIGludGVncmF0aW9uLCBsaXZlID0gVFJVRX0KIyBFeHBvcnQgdG8gUkRTIGZpbGUgd2l0aCAiZ3oiIGNvbXByZXNzaW9uCnJlYWRyOjp3cml0ZV9yZHMobWVyZ2VkX3NjZSwKICAgICAgICAgICAgICAgICBpbnRlZ3JhdGVkX3NjZV9maWxlLAogICAgICAgICAgICAgICAgIGNvbXByZXNzID0gImd6IikKYGBgCgoKIyMgUHJpbnQgc2Vzc2lvbiBpbmZvCgpBcyBhbHdheXMsIHdlJ2xsIHByaW50IHRoZSBzZXNzaW9uIGluZm8gdG8gYmUgdHJhbnNwYXJlbnQgYWJvdXQgd2hhdCBwYWNrYWdlcywgYW5kIHdoaWNoIHZlcnNpb25zLCB3ZXJlIHVzZWQgZHVyaW5nIHRoaXMgUiBzZXNzaW9uLgoKYGBge3Igc2Vzc2lvbmluZm99CnNlc3Npb25JbmZvKCkKYGBgCg==
+
LS0tCnRpdGxlOiAiSW50ZWdyYXRpbmcgc2NSTkEtc2VxIGRhdGFzZXRzIgphdXRob3I6IERhdGEgTGFiIGZvciBBTFNGCmRhdGU6IDIwMjMKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMwogICAgdG9jX2Zsb2F0OiB0cnVlCi0tLQoKIyMgT2JqZWN0aXZlcwoKVGhpcyBub3RlYm9vayB3aWxsIGRlbW9uc3RyYXRlIGhvdyB0bzoKCi0gUHJlcGFyZSBTQ0Ugb2JqZWN0cyBmb3IgaW50ZWdyYXRpb24KLSBBcHBseSBpbnRlZ3JhdGlvbiBtZXRob2RzIGluY2x1ZGluZyBgZmFzdE1OTmAgYW5kIGBoYXJtb255YAotIFZpc3VhbGx5IGV4cGxvcmUgdGhlIHJlc3VsdHMgb2YgaW50ZWdyYXRpb24KLSBVc2UgYHB1cnJyOjptYXAoKWAgZnVuY3Rpb25zIGZvciBpdGVyYXRpbmcgb3ZlciBsaXN0cwoKLS0tCgpJbiB0aGlzIG5vdGVib29rLCB3ZSdsbCBwZXJmb3JtIGludGVncmF0aW9uIG9uIHNjUk5BLXNlcSBkYXRhc2V0cyBmcm9tIHRoZSBbU2luZ2xlLWNlbGwgUGVkaWF0cmljIENhbmNlciBBdGxhcyAoYFNjUENBYCldKGh0dHBzOi8vc2NwY2EuYWxleHNsZW1vbmFkZS5vcmcvKSwgYSBkYXRhYmFzZSBvZiB1bmlmb3JtbHktcHJvY2Vzc2VkIHBlZGlhdHJpYyBzY1JOQS1zZXEgZGF0YSBidWlsdCBhbmQgbWFpbnRhaW5lZCBieSB0aGUgRGF0YSBMYWIuClRoZSBgU2NQQ0FgIGRhdGFiYXNlIGN1cnJlbnRseSBob3N0cyBzaW5nbGUtY2VsbCBwZWRpYXRyaWMgY2FuY2VyIHRyYW5zY3JpcHRvbWljIGRhdGEgZ2VuZXJhdGVkIGJ5IEFMU0YtZnVuZGVkIGxhYnMsIHdpdGggdGhlIGdvYWwgb2YgbWFraW5nIHRoaXMgZGF0YSBlYXNpbHkgYWNjZXNzaWJsZSB0byBpbnZlc3RpZ2F0b3JzIChsaWtlIHlvdSEpLgpUaGUgZXhwcmVzc2lvbiBkYXRhIGluIGBTY1BDQWAgd2VyZSBtYXBwaW5nIGFuZCBxdWFudGlmaWVkIHdpdGggW2BhbGV2aW4tZnJ5YF0oaHR0cHM6Ly9kb2kub3JnLzEwLjEwMzgvczQxNTkyLTAyMi0wMTQwOC0zKSwgZm9sbG93ZWQgYnkgcHJvY2Vzc2luZyB3aXRoIEJpb2NvbmR1Y3RvciB0b29scyB1c2luZyB0aGUgc2FtZSBnZW5lcmFsIHByb2NlZHVyZXMgdGhhdCB3ZSBoYXZlIGNvdmVyZWQgaW4gdGhpcyB3b3Jrc2hvcC4KVGhlIHByb2Nlc3NpbmcgcGlwZWxpbmUgdXNlZCBgZW1wdHlEcm9wc0NlbGxSYW5nZXIoKWAgYW5kIGBtaVFDYCB0byBmaWx0ZXIgdGhlIHJhdyBjb3VudHMgbWF0cml4LCBgc2N1dHRsZWAgdG8gbG9nLW5vcm1hbGl6ZSB0aGUgY291bnRzLCBhbmQgYHNjYXRlcmAgZm9yIGRpbWVuc2lvbiByZWR1Y3Rpb24uClRoZSBwcm9jZXNzZWQgZGF0YSBhcmUgc3RvcmVkIGFzIGAucmRzYCBmaWxlcyBjb250YWluaW5nIGBTaW5nbGVDZWxsRXhwZXJpbWVudGAgb2JqZWN0cy4KWW91IGNhbiByZWFkIG1vcmUgYWJvdXQgaG93IGRhdGEgaW4gdGhlIGBTY1BDQWAgaXMgcHJvY2Vzc2VkIGluIFt0aGUgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uXShodHRwczovL3NjcGNhLnJlYWR0aGVkb2NzLmlvL2VuL2xhdGVzdC8pLgoKCiFbU2luZ2xlLWNlbGwgcm9hZG1hcDogSW50ZWdyYXRpb24gT3ZlcnZpZXddKGRpYWdyYW1zL3JvYWRtYXBfbXVsdGlfbWVyZ2UtaW50ZWdyYXRlLnBuZykKClRvIGxlYXJuIGFib3V0IGludGVncmF0aW9uLCB3ZSdsbCBoYXZlIGEgbG9vayBhdCBmb3VyIHNhbXBsZXMgZnJvbSB0aGUgW2BTQ1BDUDAwMDAwNWAgcHJvamVjdF0oaHR0cHM6Ly9zY3BjYS5hbGV4c2xlbW9uYWRlLm9yZy9wcm9qZWN0cy9TQ1BDUDAwMDAwNSkgKFtQYXRlbCBfZXQgYWwuXyAyMDIyXShodHRwczovL2RvaS5vcmcvMTAuMTAxNi9qLmRldmNlbC4yMDIyLjA0LjAwMykpLCBhbiBpbnZlc3RpZ2F0aW9uIG9mIHBlZGlhdHJpYyBzb2xpZCB0dW1vcnMgbGVkIGJ5IHRoZSBbRHllcl0oaHR0cHM6Ly93d3cuc3RqdWRlLm9yZy9yZXNlYXJjaC9sYWJzL2R5ZXItbGFiLmh0bWwpIGFuZCBbQ2hlbl0oaHR0cHM6Ly93d3cuc3RqdWRlLm9yZy9yZXNlYXJjaC9sYWJzL2NoZW4tbGFiLXRhb3NoZW5nLmh0bWwpIGxhYnMgYXQgU3QuIEp1ZGUgQ2hpbGRyZW4ncyBSZXNlYXJjaCBIb3NwaXRhbC4KVGhlIHBhcnRpY3VsYXIgbGlicmFyaWVzIHdlJ2xsIGludGVncmF0ZSBjb21lIGZyb20gdHdvIHJoYWJkb215b3NhcmNvbWEgKFJNUykgcGF0aWVudHMsIHdpdGggdHdvIHNhbXBsZXMgZnJvbSBlYWNoIG9mIHR3byBwYXRpZW50cywgYWxsIHNlcXVlbmNlZCB3aXRoIDEweCBDaHJvbWl1bSB2MyB0ZWNobm9sb2d5LgpFYWNoIGxpYnJhcnkgaXMgZnJvbSBhIHNlcGFyYXRlIGJpb2xvZ2ljYWwgc2FtcGxlLgoKV2UnbGwgYmUgaW50ZWdyYXRpbmcgdGhlc2Ugc2FtcGxlcyB3aXRoIHR3byBkaWZmZXJlbnQgdG9vbHMsIFtgZmFzdE1OTmBdKGh0dHA6Ly93d3cuYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy8zLjE2L2Jpb2MvaHRtbC9iYXRjaGVsb3IuaHRtbCkgKFtIYWdodmVyZGkgX2V0IGFsLl8gMjAxOF0oaHR0cHM6Ly9kb2kub3JnLzEwLjEwMzgvbmJ0LjQwOTEpKSBhbmQgW2BoYXJtb255YF0oaHR0cHM6Ly9wb3J0YWxzLmJyb2FkaW5zdGl0dXRlLm9yZy9oYXJtb255LykgKFtLb3JzdW5za3kgX2V0IGFsLl8gMjAxOV0oaHR0cHM6Ly9kb2kub3JnLzEwLjEwMzgvczQxNTkyLTAxOS0wNjE5LTApKS4KSW50ZWdyYXRpb24gY29ycmVjdHMgZm9yIGJhdGNoIGVmZmVjdHMgdGhhdCBhcmlzZSBmcm9tIGRpZmZlcmVudCBsaWJyYXJ5IHByZXBhcmF0aW9ucywgZ2VuZXRpYyBiYWNrZ3JvdW5kcywgYW5kIG90aGVyIHNhbXBsZS1zcGVjaWZpYyBmYWN0b3JzLCBzbyB0aGF0IGRhdGFzZXRzIGNhbiBiZSBqb2ludGx5IGFuYWx5emVkIGF0IHRoZSBjZWxsIGxldmVsLgpgZmFzdE1OTmAgY29ycmVjdHMgZm9yIGJhdGNoIGVmZmVjdHMgdXNpbmcgYSBmYXN0ZXIgdmFyaWFudCBvZiB0aGUgbXV0dWFsLW5lYXJlc3QgbmVpZ2hib3JzIGFsZ29yaXRobSwgdGhlIHRlY2huaWNhbCBkZXRhaWxzIG9mIHdoaWNoIHlvdSBjYW4gbGVhcm4gbW9yZSBhYm91dCBmcm9tIHRoaXMgW3ZpZ25ldHRlIGJ5IEx1biAoMjAxOSldKGh0dHBzOi8vbWFyaW9uaWxhYi5naXRodWIuaW8vRnVydGhlck1OTjIwMTgvdGhlb3J5L2Rlc2NyaXB0aW9uLmh0bWwpLgpgaGFybW9ueWAsIG9uIHRoZSBvdGhlciBoYW5kLCBjb3JyZWN0cyBmb3IgYmF0Y2ggZWZmZWN0cyB1c2luZyBhbiBpdGVyYXRpdmUgY2x1c3RlcmluZyBhcHByb2FjaCwgYW5kIHVubGlrZSBgZmFzdE1OTmAsIGl0IGlzIGFsc28gYWJsZSB0byBjb25zaWRlciBhZGRpdGlvbmFsIGNvdmFyaWF0ZXMgYmV5b25kIGp1c3QgdGhlIGJhdGNoIGdyb3VwaW5ncy4KClJlZ2FyZGxlc3Mgb2Ygd2hpY2ggaW50ZWdyYXRpb24gdG9vbCBpcyB1c2VkLCB0aGUgYFNpbmdsZUNlbGxFeHBlcmltZW50YCAoU0NFKSBvYmplY3RzIGZpcnN0IG5lZWQgdG8gYmUgcmVmb3JtYXR0ZWQgYW5kIG1lcmdlZCBpbnRvIGEgc2luZ2xlICh1bmNvcnJlY3RlZCEpIFNDRSBvYmplY3QgdGhhdCBjb250YWlucyBhbGwgY2VsbHMgZnJvbSBhbGwgc2FtcGxlcy4KVGhpcyBtZXJnZWQgU0NFIGNhbiB0aGVuIGJlIHVzZWQgZm9yIGludGVncmF0aW9uIHRvIG9idGFpbiBhIGZvcm1hbGx5IGJhdGNoLWNvcnJlY3RlZCBTQ0Ugb2JqZWN0LgoKCiMjIFNldCB1cAoKYGBge3Igc2V0dXB9CiMgTG9hZCBsaWJyYXJpZXMKbGlicmFyeShnZ3Bsb3QyKSAgIyBwbG90dGluZyB0b29scwpsaWJyYXJ5KFNpbmdsZUNlbGxFeHBlcmltZW50KSAjIHdvcmsgd2l0aCBTQ0Ugb2JqZWN0cwoKIyBTZXQgdGhlIHNlZWQgZm9yIHJlcHJvZHVjaWJpbGl0eQpzZXQuc2VlZCgxMjM0NSkKYGBgCgoKIyMjIERpcmVjdG9yaWVzIGFuZCBmaWxlcwoKCldlIGhhdmUgYWxyZWFkeSBwcmVwYXJlZCBjb3VudCBkYXRhIGZvciB0aGUgZm91ciBzYW1wbGVzIHdlJ2xsIGJlIGludGVncmF0aW5nIChpLmUuLCBmaWx0ZXJlZCBjZWxscywgbm9ybWFsaXplZCBjb3VudHMsIGFuZCBjYWxjdWxhdGVkIFBDQSAmIFVNQVApLgpUaGVzZSBTQ0Ugb2JqZWN0cywgc3RvcmVkIGFzIFJEUyBmaWxlcywgYXJlIGF2YWlsYWJsZSBpbiB0aGUgYGRhdGEvcm1zL3Byb2Nlc3NlZC9gIGRpcmVjdG9yeSBhbmQgYXJlIG5hbWVkIGFjY29yZGluZyB0byB0aGVpciBgU2NQQ0FgIGxpYnJhcnkgaWRzIDoKCi0gYFNDUENMMDAwNDc5LnJkc2AgKFBhdGllbnQgQSkKLSBgU0NQQ0wwMDA0ODAucmRzYCAoUGF0aWVudCBBKQotIGBTQ1BDTDAwMDQ4MS5yZHNgIChQYXRpZW50IEIpCi0gYFNDUENMMDAwNDgyLnJkc2AgKFBhdGllbnQgQikKClRvIGJlZ2luLCBsZXQncyBzZXQgdXAgb3VyIGRpcmVjdG9yaWVzIGFuZCBmaWxlczoKCmBgYHtyIGRpcmVjdG9yaWVzLCBsaXZlID0gVFJVRX0KIyBEZWZpbmUgZGlyZWN0b3J5IHdoZXJlIHByb2Nlc3NlZCBTQ0Ugb2JqZWN0cyB0byBiZSBpbnRlZ3JhdGVkIGFyZSBzdG9yZWQKaW5wdXRfZGlyIDwtIGZpbGUucGF0aCgiZGF0YSIsICJybXMiLCAicHJvY2Vzc2VkIikKCiMgRGVmaW5lIGRpcmVjdG9yeSB0byBzYXZlIGludGVncmF0ZWQgU0NFIG9iamVjdCB0bwpvdXRwdXRfZGlyIDwtIGZpbGUucGF0aCgiZGF0YSIsICJybXMiLCAiaW50ZWdyYXRlZCIpCgojIENyZWF0ZSBvdXRwdXQgZGlyZWN0b3J5IGlmIGl0IGRvZXNuJ3QgZXhpc3QKZnM6OmRpcl9jcmVhdGUob3V0cHV0X2RpcikKCiMgRGVmaW5lIG91dHB1dCBmaWxlIG5hbWUgZm9yIHRoZSBpbnRlZ3JhdGVkIG9iamVjdAppbnRlZ3JhdGVkX3NjZV9maWxlIDwtIGZpbGUucGF0aChvdXRwdXRfZGlyLCAicm1zX2ludGVncmF0ZWRfc3Vic2V0LnJkcyIpCmBgYAoKCldlIGNhbiB1c2UgdGhlIGBkaXIoKWAgZnVuY3Rpb24gdG8gbGlzdCBhbGwgY29udGVudHMgb2YgYSBnaXZlbiBkaXJlY3RvcnksIGZvciBleGFtcGxlIHRvIHNlZSBhbGwgdGhlIGZpbGVzIGluIG91ciBgaW5wdXRfZGlyYDoKCmBgYHtyIGlucHV0IGRpciwgbGl2ZSA9IFRSVUV9CmRpcihpbnB1dF9kaXIpCmBgYAoKV2Ugd2FudCB0byByZWFkIGluIGp1c3QgZm91ciBvZiB0aGVzZSBmaWxlcywgYXMgbGlzdGVkIHByZXZpb3VzbHkuClRvIHJlYWQgaW4gdGhlc2UgZmlsZXMsIHdlIGNvdWxkIHVzZSB0aGUgYHJlYWRyOjpyZWFkX3JkcygpYCBmdW5jdGlvbiAob3IgdGhlIGJhc2UgUiBgcmVhZFJEUygpYCkgZm91ciB0aW1lcywgb25jZSBmb3IgZWFjaCBvZiB0aGUgZmlsZXMuCldlIGNvdWxkIGFsc28gdXNlIGEgYGZvcmAgbG9vcCwgd2hpY2ggaXMgdGhlIGFwcHJvYWNoIHRoYXQgbWFueSBwcm9ncmFtbWluZyBsYW5ndWFnZXMgd291bGQgbGVhbiB0b3dhcmQuCkEgZGlmZmVyZW50IGFuZCBtb3JlIG1vZHVsYXIgY29kaW5nIGFwcHJvYWNoIHRvIHJlYWRpbmcgaW4gdGhlc2UgZmlsZXMgKGFuZCBtb3JlISkgaXMgdG8gbGV2ZXJhZ2UgdGhlIFtgcHVycnJgXShodHRwczovL3B1cnJyLnRpZHl2ZXJzZS5vcmcvKSBgdGlkeXZlcnNlYCBwYWNrYWdlLCB3aGljaCBwcm92aWRlcyBhIGNvbnZlbmllbnQgc2V0IG9mIGZ1bmN0aW9ucyBmb3Igb3BlcmF0aW5nIG9uIGxpc3RzLgpZb3UgY2FuIHJlYWQgbW9yZSBhYm91dCB0aGUgYHB1cnJyYCBmdW5jdGlvbnMgYW5kIHRoZWlyIHBvd2VyIGFuZCB1dGlsaXR5IGluIFIgaW4gW3RoZSAiRnVuY3Rpb25hbHMiIGNoYXB0ZXIgb2YgdGhlIF9BZHZhbmNlZCBSXyBlLWJvb2tdKGh0dHBzOi8vYWR2LXIuaGFkbGV5Lm56L2Z1bmN0aW9uYWxzLmh0bWwpLgoKT2YgcGFydGljdWxhciBpbnRlcmVzdCBpcyB0aGUgW2BwdXJycjo6bWFwKClgXShodHRwczovL3B1cnJyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL21hcC5odG1sKSBmYW1pbHkgb2YgZnVuY3Rpb25zLCB3aGljaCBjYW4gYmUgdXNlZCB0byBydW4gYSBnaXZlbiBmdW5jdGlvbiBvbiBlYWNoIGVsZW1lbnQgb2YgYSBsaXN0IChvciB2ZWN0b3IpIGluIG9uZSBjYWxsLgpUaGUgZ2VuZXJhbCBzeW50YXggZm9yIGBwdXJycjo6bWFwKClgIGFuZCBmcmllbmRzIGlzOgoKYGBgCiMgU3ludGF4IGZvciB1c2luZyB0aGUgbWFwIGZ1bmN0aW9uOgpwdXJycjo6bWFwKDxpbnB1dCBsaXN0IG9yIHZlY3Rvcj4sCiAgICAgICAgICAgPGZ1bmN0aW9uIHRvIGFwcGx5IHRvIGVhY2ggaXRlbSBpbiB0aGUgaW5wdXQ+LAogICAgICAgICAgIDxhbnkgYWRkaXRpb25hbCBhcmd1bWVudHMgdG8gdGhlIGZ1bmN0aW9uIGNhbiBnbyBoZXJlPiwKICAgICAgICAgICA8YW5kIGFsc28gaGVyZSBpZiB0aGVyZSBhcmUgZXZlbiBtb3JlIGFyZ3VtZW50cywgYW5kIHNvIG9uPikKYGBgCgoKVGhlIG91dHB1dCBmcm9tIHJ1bm5pbmcgYHB1cnJyOjptYXAoKWAgaXMgYWx3YXlzIGEgbGlzdCAoYnV0IG5vdGUgdGhhdCB0aGVyZSBhcmUgb3RoZXIgYHB1cnJyOjptYXAoKWAgcmVsYXRpdmVzIHdoaWNoIHJldHVybiBvdGhlciBvYmplY3QgdHlwZXMsIGFzIHlvdSBjYW4gcmVhZCBhYm91dCBpbiBbdGhlIGBwdXJycjo6bWFwKClgIGRvY3VtZW50YXRpb25dKGh0dHBzOi8vcHVycnIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvaW5kZXguaHRtbCkpLgpJZiB0aGlzIGNvbmNlcHQgc291bmRzIGEgbGl0dGxlIGZhbWlsaWFyIHRvIHlvdSwgdGhhdCdzIGJlY2F1c2UgaXQgcHJvYmFibHkgaXMhCkJhc2UgUidzIGBsYXBwbHkoKWAgZnVuY3Rpb24gY2FuIHByb3ZpZGUgc2ltaWxhciB1dGlsaXR5LCBhbmQgdGhlIGBwdXJycjo6bWFwKClgIGZhbWlseSBvZiBmdW5jdGlvbnMgY2FuIChpbiBwYXJ0KSBiZSB0aG91Z2h0IG9mIGFzIGFuIGFsdGVybmF0aXZlIHRvIHNvbWUgb2YgdGhlIGJhc2UgUiBgYXBwbHlgIGZ1bmN0aW9ucywgd2l0aCBtb3JlIGNvbnNpc3RlbnQgYmVoYXZpb3IuCgpMZXQncyBzZWUgYSB2ZXJ5IHNpbXBsZSBleGFtcGxlIG9mIGBwdXJycjo6bWFwKClgIGluIGFjdGlvbiwgaW5zcGlyZWQgYnkgY2FuY2VyIGdyb3VwcyB0aGUgRGF0YSBMYWIgaGFzIGFuYWx5emVkIHRocm91Z2ggdGhlIFtPcGVuUEJUQV0oaHR0cHM6Ly9naXRodWIuY29tL0FsZXhzTGVtb25hZGUvT3BlblBCVEEtYW5hbHlzaXMvKSBwcm9qZWN0OgoKYGBge3IgbWFwIGV4YW1wbGV9CiMgRGVmaW5lIGEgbGlzdCBvZiBjYW5jZXIgaGlzdG9sb2dpZXMKaGlzdG9sb2dpZXMgPC0gbGlzdCgKICAibG93LWdyYWRlIGdsaW9tYXMiICA9IGMoIlNFR0EiLCAiUEEiLCAiR05HIiwgIlBYQSIpLAogICJoaWdoLWdyYWRlIGdsaW9tYXMiID0gYygiRE1HIiwgIkRJUEciKSwKICAiZW1icnlvbmFsIHR1bW9ycyIgICA9IGMoIk1CIiwgIkFUUlQiLCAiRVRNUiIpCiApCgojIFRoZSBvdmVyYWxsIGxlbmd0aCBvZiB0aGUgbGlzdCBpcyAzCmxlbmd0aChoaXN0b2xvZ2llcykKCiMgSG93IGNhbiB3ZSBydW4gYGxlbmd0aCgpYCBvbiBlYWNoIGl0ZW0gb2YgdGhlIGxpc3Q/CiMgV2UgY2FuIHVzZSBvdXIgbmV3IGZyaWVuZCBwdXJycjo6bWFwKCk6CnB1cnJyOjptYXAoaGlzdG9sb2dpZXMsIGxlbmd0aCkKYGBgCgpPbmUgb3RoZXIgbmV3IGNvZGluZyBzdHJhdGVneSB3ZSdsbCBsZWFybiBpbiB0aGlzIG5vdGVib29rIGlzIHVzaW5nIHRoZSBbYGdsdWVgXShodHRwczovL2dsdWUudGlkeXZlcnNlLm9yZy8pIHBhY2thZ2UgdG8gY29tYmluZSBzdHJpbmdzLgpUaGlzIHBhY2thZ2Ugb2ZmZXJzIGEgY29udmVuaWVudCBmdW5jdGlvbiBgZ2x1ZTo6Z2x1ZSgpYCB0aGF0IGNhbiBiZSB1c2VkIGluc3RlYWQgb2YgdGhlIGJhc2UgUiBgcGFzdGUoKWAgZnVuY3Rpb24uCgpgYGB7ciBwYXN0ZX0KIyBEZWZpbmUgYSB2YXJpYWJsZSBmb3IgZXhhbXBsZToKb3JnX25hbWUgPC0gIkRhdGEgTGFiIgoKIyBXZSBjYW4gdXNlIHBhc3RlIHRvIGNvbWJpbmUgc3RyaW5ncyBhbmQgdmFyaWFibGVzOgpwYXN0ZSgiV2VsY29tZSB0byB0aGUiLCBvcmdfbmFtZSwgIndvcmtzaG9wIG9uIEFkdmFuY2VkIHNjUk5BLXNlcSEiKQpgYGAKCldlIGNhbiB1c2UgYGdsdWU6OmdsdWUoKWAgdG8gYWNjb21wbGlzaCB0aGUgc2FtZSBnb2FsIHdpdGggc29tZSBkaWZmZXJlbnQgc3ludGF4OgoKYGBge3IgZ2x1ZX0KIyBnbHVlOjpnbHVlIHRha2VzIGEgc2luZ2xlIHN0cmluZyBhcmd1bWVudCAob25seSBvbmUgc2V0IG9mIHF1b3RlcyEpLCBhbmQKIyAgdmFyaWFibGVzIGNhbiBlYXNpbHkgYmUgaW5jbHVkZWQgaW5zaWRlIHtjdXJseSBicmFjZXN9CmdsdWU6OmdsdWUoIldlbGNvbWUgdG8gdGhlIHtvcmdfbmFtZX0gd29ya3Nob3Agb24gQWR2YW5jZWQgc2NSTkEtc2VxISIpCmBgYAoKKE5vdGUgdGhhdCBldmVuIHRob3VnaCB0aGUgYGdsdWU6OmdsdWUoKWAgb3V0cHV0IGlzbid0IGluIHF1b3RlcywgaXQgc3RpbGwgYmVoYXZlcyBsaWtlIGEgc3RyaW5nISkKCgpBbHJpZ2h0LCB0aW1lIGZvciB0aGUgZ29vZCBzdHVmZiEKTGV0J3MgdXNlIGBwdXJycjo6bWFwKClgIHRvIHJlYWQgaW4gb3VyIFNDRSBvYmplY3RzIHNvIHRoYXQgdGhleSBhcmUgaW1tZWRpYXRlbHkgc3RvcmVkIHRvZ2V0aGVyIGluIGEgbGlzdC4KCgpXZSdsbCBmaXJzdCBuZWVkIHRvIGRlZmluZSBhIHZlY3RvciBvZiB0aGUgZmlsZSBwYXRocyB0byByZWFkIGluLgpXZSdsbCBzdGFydCBieSBjcmVhdGluZyBhIHZlY3RvciBvZiBzYW1wbGUgbmFtZXMgdGhlbXNlbHZlcyBhbmQgdGhlbiBmb3JtYXR0aW5nIHRoZW0gaW50byB0aGUgY29ycmVjdCBwYXRocy4KVGhpcyB3YXkgKGZvcmVzaGFkb3dpbmchKSB3ZSBhbHNvIGhhdmUgYSBzdGFuZC1hbG9uZSB2ZWN0b3Igb2YganVzdCBzYW1wbGUgbmFtZXMsIHdoaWNoIHdpbGwgY29tZSBpbiBoYW5keSEKCmBgYHtyIHNhbXBsZSBuYW1lc30KIyBWZWN0b3Igb2YgYWxsIHRoZSBzYW1wbGVzIHRvIHJlYWQgaW46CnNhbXBsZV9uYW1lcyA8LSBjKCJTQ1BDTDAwMDQ3OSIsCiAgICAgICAgICAgICAgICAgICJTQ1BDTDAwMDQ4MCIsCiAgICAgICAgICAgICAgICAgICJTQ1BDTDAwMDQ4MSIsCiAgICAgICAgICAgICAgICAgICJTQ1BDTDAwMDQ4MiIpCmBgYAoKCmBgYHtyIGRlZmluZSBzY2VfcGF0aHMsIGxpdmUgPSBUUlVFfQojIE5vdywgY29udmVydCB0aGVzZSB0byBmaWxlIHBhdGhzOiA8aW5wdXRfZGlyPi88c2FtcGxlX25hbWU+LnJkcwpzY2VfcGF0aHMgPC0gZmlsZS5wYXRoKGlucHV0X2RpciwKICAgICAgICAgICAgICAgICAgICAgICBnbHVlOjpnbHVlKCJ7c2FtcGxlX25hbWVzfS5yZHMiKQopCiMgUHJpbnQgdGhlIHNjZV9wYXRocyB2ZWN0b3IKc2NlX3BhdGhzCmBgYAoKV2UgY2FuIG5vdyByZWFkIHRoZXNlIGZpbGVzIGluIGFuZCBjcmVhdGUgYSBsaXN0IG9mIGZvdXIgU0NFIG9iamVjdHMuClNpbmNlIGByZWFkcjo6cmVhZF9yZHMoKWAgY2FuIG9ubHkgb3BlcmF0ZSBvbiBvbmUgaW5wdXQgYXQgYSB0aW1lLCB3ZSdsbCBuZWVkIHRvIHVzZSBgcHVycnI6Om1hcCgpYCB0byBydW4gaXQgb24gYWxsIGlucHV0IGZpbGUgcGF0aHMgaW4gb25lIGNvbW1hbmQuCkFsdGhvdWdoIGBzY2VfcGF0aHNgIGlzIGEgdmVjdG9yIChub3QgYSBsaXN0KSwgaXQgd2lsbCBzdGlsbCB3b3JrIGFzIGlucHV0IHRvIGBwdXJycjptYXAoKWAuClRoZSBvdXRwdXQgZnJvbSB0aGlzIGNvZGUgd2lsbCBzdGlsbCBiZSBhIGxpc3QsIHNpbmNlIHRoYXQncyB3aGF0IGBwdXJycjo6bWFwKClgIGFsd2F5cyByZXR1cm5zLgoKYGBge3IgcmVhZCBzY2UgcGF0aHMsIGxpdmUgPSBUUlVFfQojIFVzZSBwdXJycjo6bWFwKCkgdG8gcmVhZCBhbGwgZmlsZXMgaW50byBhIGxpc3QgYXQgb25jZQpzY2VfbGlzdCA8LSBwdXJycjo6bWFwKAogIHNjZV9wYXRocywKICByZWFkcjo6cmVhZF9yZHMKKQpgYGAKCkxldCdzIGhhdmUgYSBsb29rIGF0IG91ciBsaXN0IG9mIFNDRSBvYmplY3RzOgoKYGBge3IgcHJpbnQgc2NlIGxpc3QsIGxpdmU9VFJVRX0KIyBQcmludCBzY2VfbGlzdApzY2VfbGlzdApgYGAKCldlIG5vdyBoYXZlIGEgbGlzdCBvZiBsZW5ndGggZm91ciwgd2hlcmUgZWFjaCBpdGVtIGlzIGEgcHJvY2Vzc2VkIFNDRSBvYmplY3QhCkhvd2V2ZXIsIHdlJ2xsIG5lZWQgdG8ga2VlcCB0cmFjayBvZiB3aGljaCBzYW1wbGUgZWFjaCBpdGVtIGlzLCBzbyBpdCdzIGhlbHBmdWwgdG8gYWRkIF9uYW1lc18gdG8gdGhpcyBsaXN0IHJlcHJlc2VudGluZyB0aGUgcmVsZXZhbnQgc2FtcGxlIG5hbWVzLgoKYGBge3IgYWRkIGxpc3QgbmFtZXMsIGxpdmUgPSBUUlVFfQojIEFzc2lnbiB0aGUgc2FtcGxlIG5hbWVzIGFzIHRoZSBuYW1lcyBmb3Igc2NlX2xpc3QKbmFtZXMoc2NlX2xpc3QpIDwtIHNhbXBsZV9uYW1lcwpgYGAKCmBgYHtyIHByaW50IG5hbWVkIGxpc3QsIGxpdmU9VFJVRX0KIyBQcmludCB0aGUgbGlzdCB0byBzZWUgaXQgd2l0aCBuYW1lcwpzY2VfbGlzdApgYGAKCklmIHlvdSBsb29rIGNsb3NlbHkgYXQgdGhlIHByaW50ZWQgU0NFIG9iamVjdHMsIHlvdSBtYXkgbm90aWNlIHRoYXQgdGhleSBhbGwgY29udGFpbiBgY29sRGF0YWAgdGFibGUgY29sdW1ucyBgY2VsbHR5cGVfZmluZWAgYW5kIGBjZWxsdHlwZV9icm9hZGAuClRoZXNlIGNvbHVtbnMgKHdoaWNoIHdlIGFkZGVkIHRvIFNDRSBvYmplY3RzIGR1cmluZyBbcHJlLXByb2Nlc3NpbmddKGh0dHBzOi8vZ2l0aHViLmNvbS9BbGV4c0xlbW9uYWRlL3RyYWluaW5nLW1vZHVsZXMvdHJlZS9tYXN0ZXIvc2NSTkEtc2VxLWFkdmFuY2VkL3NldHVwL3JtcykpIGNvbnRhaW4gcHV0YXRpdmUgX2NlbGwgdHlwZSBhbm5vdGF0aW9uc18gYXMgYXNzaWduZWQgaW4gW1BhdGVsIF9ldCBhbC5fICgyMDIyKV0oaHR0cHM6Ly9kb2kub3JnLzEwLjEwMTYvai5kZXZjZWwuMjAyMi4wNC4wMDMpLgpXZSB3aWxsIGVuZCB1cCBsZXZlcmFnaW5nIHRoZXNlIGNlbGwgdHlwZSBhbm5vdGF0aW9ucyB0byBleHBsb3JlIGhvdyBzdWNjZXNzZnVsIG91ciBpbnRlZ3JhdGlvbiBpczsgYWZ0ZXIgaW50ZWdyYXRpb24sIHdlIGV4cGVjdCBjZWxsIHR5cGVzIGZyb20gZGlmZmVyZW50IHNhbXBsZXMgdG8gZ3JvdXAgdG9nZXRoZXIsIHJhdGhlciB0aGFuIGJlaW5nIHNlcGFyYXRlZCBieSBiYXRjaGVzLgoKVGhhdCBzYWlkLCB0aGUgaW50ZWdyYXRpb24gbWV0aG9kcyB3ZSB3aWxsIGJlIGFwcGx5aW5nIF9kbyBub3QgYWN0dWFsbHkgdXNlXyB0aGVzZSBjZWxsIHR5cGUgYW5ub3RhdGlvbnMuCklmIHdlIGhhdmUgYW5ub3RhdGlvbnMsIHRoZXkgYXJlIGEgaGVscGZ1bCAiYm9udXMiIGZvciBhc3Nlc3NpbmcgdGhlIGludGVncmF0aW9uJ3Mgc3VjY2VzcywgYnV0IHRoZXkgYXJlIG5vdCBwYXJ0IG9mIHRoZSBpbnRlZ3JhdGlvbiBpdHNlbGYuCgoKIyMgUHJlcGFyZSB0aGUgU0NFIGxpc3QgZm9yIGludGVncmF0aW9uCgohW1NpbmdsZS1jZWxsIHJvYWRtYXA6IE1lcmdlXShkaWFncmFtcy9yb2FkbWFwX211bHRpX21lcmdlLnBuZykKCgpOb3cgdGhhdCB3ZSBoYXZlIGEgbGlzdCBvZiBwcm9jZXNzZWQgU0NFIG9iamVjdHMsIHdlIG5lZWQgdG8gbWVyZ2UgdGhlIG9iamVjdHMgaW50byBvbmUgb3ZlcmFsbCBTQ0Ugb2JqZWN0IGZvciBpbnB1dCB0byBpbnRlZ3JhdGlvbi4KQSB3b3JkIG9mIGNhdXRpb24gYmVmb3JlIHdlIGJlZ2luOiAqKlRoaXMgbWVyZ2VkIFNDRSBvYmplY3QgaXMgTk9UIGFuIGludGVncmF0ZWQgU0NFISoqCk1lcmdpbmcgU0NFcyBkb2VzIG5vdCBwZXJmb3JtIGFueSBiYXRjaCBjb3JyZWN0aW9uLCBidXQganVzdCByZW9yZ2FuaXplcyB0aGUgZGF0YSB0byBhbGxvdyB1cyB0byBwcm9jZWVkIHRvIGludGVncmF0aW9uIG5leHQuCgpUbyBtZXJnZSBTQ0Ugb2JqZWN0cywgd2UgZG8gbmVlZCB0byBkbyBzb21lIHdyYW5nbGluZyBhbmQgYm9va2tlZXBpbmcgdG8gZW5zdXJlIGNvbXBhdGliaWxpdHkgYW5kIHRoYXQgd2UgZG9uJ3QgbG9zZSBpbXBvcnRhbnQgaW5mb3JtYXRpb24uCk92ZXJhbGwgd2UnbGwgd2FudCB0byB0YWtlIGNhcmUgb2YgdGhlc2UgaXRlbXM6CgoxLiBXZSBzaG91bGQgYmUgYWJsZSB0byB0cmFjZSBzYW1wbGUtc3BlY2lmaWMgaW5mb3JtYXRpb24gYmFjayB0byB0aGUgb3JpZ2luYXRpbmcgc2FtcGxlLCBpbmNsdWRpbmcuLi4KICAgIC0gQ2VsbC1sZXZlbCBpbmZvcm1hdGlvbjogV2hpY2ggc2FtcGxlIGlzIGVhY2ggY2VsbCBmcm9tPwogICAgLSBMaWJyYXJ5LXNwZWNpZmljIGZlYXR1cmUgc3RhdGlzdGljcywgZS5nLiwgZ2VuZS1sZXZlbCBzdGF0aXN0aWNzIGZvciBhIGdpdmVuIGxpYnJhcnkgZm91bmQgaW4gYHJvd0RhdGFgLgogICAgV2hpY2ggc2FtcGxlIGlzIGEgZ2l2ZW4gZmVhdHVyZSBzdGF0aXN0aWMgZnJvbT8KMi4gU0NFIG9iamVjdHMgc2hvdWxkIGNvbnRhaW4gdGhlIHNhbWUgZ2VuZXM6IEVhY2ggU0NFIG9iamVjdCBzaG91bGQgaGF2ZSB0aGUgc2FtZSByb3cgbmFtZXMuCjMuIFNDRSBjZWxsIG1ldGFkYXRhIGNvbHVtbnMgc2hvdWxkIG1hdGNoOiBUaGUgYGNvbERhdGFgIGZvciBlYWNoIFNDRSBvYmplY3Qgc2hvdWxkIGhhdmUgdGhlIHNhbWUgY29sdW1uIG5hbWVzLgoKCldlJ2xsIGJlZ2luIGJ5IHRha2luZyBzb21lIHRpbWUgdG8gdGhvcm91Z2hseSBleHBsb3JlIG91ciBTQ0Ugb2JqZWN0cyBhbmQgZmlndXJlIG91dCB3aGF0IHdyYW5nbGluZyBzdGVwcyB3ZSBuZWVkIHRvIHRha2UgZm9yIHRoZXNlIHNwZWNpZmljIGRhdGEuCkRvbid0IHNraXAgdGhpcyBleHBsb3JhdGlvbiEKQmVhciBpbiBtaW5kIHRoYXQgdGhlIGV4YWN0IHdyYW5nbGluZyBzaG93biBoZXJlIHdpbGwgbm90IGJlIHRoZSBzYW1lIGZvciBvdGhlciBTQ0Ugb2JqZWN0cyB5b3Ugd29yayB3aXRoLCBidXQgdGhlIHNhbWUgZ2VuZXJhbCBwcmluY2lwbGVzIGFwcGx5LgoKCiMjIyMgUHJlc2VydmluZyBzYW1wbGUgaW5mb3JtYXRpb24gYXQgdGhlIGNlbGwgbGV2ZWwKCkhvdyB3aWxsIHdlIGJlIGFibGUgdG8gdGVsbCB3aGljaCBzYW1wbGUgYSBnaXZlbiBjZWxsIGNhbWUgZnJvbT8KClRoZSBiZXN0IHdheSB0byBkbyB0aGlzIGlzIHNpbXBseSB0byBhZGQgYSBgY29sRGF0YWAgY29sdW1uIHdpdGggdGhlIHNhbXBsZSBpbmZvcm1hdGlvbiwgc28gdGhhdCB3ZSBjYW4ga25vdyB3aGljaCBzYW1wbGUgZWFjaCByb3cgY2FtZSBmcm9tLgoKSW4gYWRkaXRpb24sIHdlIHdhbnQgdG8gcGF5IHNvbWUgYXR0ZW50aW9uIHRvIHRoZSBTQ0Ugb2JqZWN0J3MgY29sdW1uIG5hbWVzICh0aGUgY2VsbCBpZHMpLCB3aGljaCBtdXN0IHJlbWFpbiB1bmlxdWUgYWZ0ZXIgbWVyZ2luZyBzaW5jZSBkdXBsaWNhdGUgaWRzIHdpbGwgY2F1c2UgYW4gUiBlcnJvci4KSW4gdGhpcyBjYXNlLCB0aGUgU0NFIGNvbHVtbiBuYW1lcyBhcmUgYmFyY29kZXMgKHdoaWNoIGlzIHVzdWFsbHkgYnV0IG5vdCBhbHdheXMgdGhlIGNhc2UgaW4gU0NFIG9iamVjdHMpLCB3aGljaCBhcmUgb25seSBndWFyYW50ZWVkIHRvIGJlIHVuaXF1ZSBfd2l0aGluXyBhIHNhbXBsZSBidXQgbWF5IGJlIHJlcGVhdGVkIGFjcm9zcyBzYW1wbGVzLgpTbywgYWZ0ZXIgbWVyZ2luZywgaXQncyB0ZWNobmljYWxseSBwb3NzaWJsZSB0aGF0IG11bHRpcGxlIGNlbGxzIHdpbGwgaGF2ZSB0aGUgc2FtZSBiYXJjb2RlLgpUaGlzIHdvdWxkIGJlIGEgcHJvYmxlbSBmb3IgdHdvIHJlYXNvbnM6CkZpcnN0LCB0aGUgY2VsbCBpZCB3b3VsZCBub3QgYmUgYWJsZSB0byBwb2ludCB1cyBiYWNrIHRvIGNlbGwncyBvcmlnaW5hdGluZyBzYW1wbGUuClNlY29uZCwgaXQgd291bGQgbGl0ZXJhbGx5IGNhdXNlIGFuIGVycm9yIGluIFIsIHdoaWNoIGRvZXMgbm90IGFsbG93IGR1cGxpY2F0ZSBjb2x1bW4gbmFtZXMuCgoKT25lIHdheSB0byBlbnN1cmUgdGhhdCBjZWxsIGlkcyByZW1haW4gdW5pcXVlIGV2ZW4gYWZ0ZXIgbWVyZ2luZyBpcyB0byBhY3R1YWxseSBtb2RpZnkgdGhlbSBieSBfcHJlcGVuZGluZ18gdGhlIHJlbGV2YW50IHNhbXBsZSBuYW1lLgpGb3IgZXhhbXBsZSwgY29uc2lkZXIgdGhlc2UgYmFyY29kZXMgZm9yIHRoZSBgU0NQQ0wwMDA0NzlgIHNhbXBsZToKCmBgYHtyIGJhcmNvZGVzfQojIExvb2sgYXQgdGhlIGNvbHVtbiBuYW1lcyBmb3IgdGhlIGBTQ1BDTDAwMDQ3OWAgc2FtcGxlLCBmb3IgZXhhbXBsZQpjb2xuYW1lcyhzY2VfbGlzdCRTQ1BDTDAwMDQ3OSkgfD4KICAjIE9ubHkgcHJpbnQgb3V0IHRoZSBmaXJzdCA2IGZvciBjb252ZW5pZW5jZQogIGhlYWQoKQpgYGAKClRoZXNlIGlkcyB3aWxsIGJlIHVwZGF0ZWQgdG8gYFNDUENMMDAwNDc5LUdHR0FDQ1RDQUFHQ0dHQVRgLCBgU0NQQ0wwMDA0NzktQ0FDQUdBVEFHVEdBR1RHQ2AsIGFuZCBzbyBvbiwgdGhlcmVieSBlbnN1cmluZyBmdWxseSB1bmlxdWUgaWRzIGZvciBhbGwgY2VsbHMgYWNyb3NzIGFsbCBzYW1wbGVzLgoKIyMjIyBQcmVzZXJ2aW5nIHNhbXBsZSBpbmZvcm1hdGlvbiBhdCB0aGUgZ2VuZSBsZXZlbAoKVGhlIGByb3dEYXRhYCB0YWJsZSBpbiBTQ0Ugb2JqZWN0cyB3aWxsIG9mdGVuIGNvbnRhaW4gYm90aCAiZ2VuZXJhbCIgYW5kICJsaWJyYXJ5LXNwZWNpZmljIiBpbmZvcm1hdGlvbiwgZm9yIGV4YW1wbGU6CgpgYGB7ciByb3dkYXRhfQpyb3dEYXRhKHNjZV9saXN0JFNDUENMMDAwNDc5KSB8PgogIGhlYWQoKQpgYGAKCkhlcmUsIHRoZSByb3duYW1lcyBhcmUgRW5zZW1ibCBnZW5lIGlkcywgYW5kIGNvbHVtbnMgYXJlIGBnZW5lX3N5bWJvbGAsIGBtZWFuYCwgYW5kIGBkZXRlY3RlZGAuClRoZSBgZ2VuZV9zeW1ib2xgIGNvbHVtbiBpcyBnZW5lcmFsIGluZm9ybWF0aW9uIGFib3V0IGFsbCBnZW5lcywgbm90IHNwZWNpZmljIHRvIGFueSBsaWJyYXJ5IG9yIGV4cGVyaW1lbnQsIGJ1dCBgbWVhbmAgYW5kIGBkZXRlY3RlZGAgYXJlIGxpYnJhcnktc3BlY2lmaWMgZ2VuZSBzdGF0aXN0aWNzLgpTbywgYGdlbmVfc3ltYm9sYCBkb2VzIG5vdCBuZWVkIHRvIGJlIHRyYWNlZCBiYWNrIHRvIGl0cyBvcmlnaW5hdGluZyBzYW1wbGUsIGJ1dCBgbWVhbmAgYW5kIGBkZXRlY3RlZGAgZG8uClRvIHRoaXMgZW5kLCB3ZSBjYW4gdGFrZSBhIHNpbWlsYXIgYXBwcm9hY2ggdG8gd2hhdCB3ZSdsbCBkbyBmb3IgY2VsbCBpZHM6CldlIGNhbiBjaGFuZ2UgdGhlIHNhbXBsZS1zcGVjaWZpYyBgcm93RGF0YWAgY29sdW1uIG5hbWVzIGJ5IHByZXBlbmRpbmcgdGhlIHNhbXBsZSBuYW1lLgpGb3IgZXhhbXBsZSwgcmF0aGVyIHRoYW4gYmVpbmcgY2FsbGVkIGBtZWFuYCwgdGhpcyBjb2x1bW4gd2lsbCBiZSBuYW1lZCBgU0NQQ0wwMDA0NzktbWVhbmAgZm9yIHRoZSBgU0NQQ0wwMDA0NzlgIHNhbXBsZS4KCkFsbCBvdXIgU0NFIG9iamVjdHMgaGF2ZSB0aGUgc2FtZSBgcm93RGF0YWAgY29sdW1ucyAoYXMgd2UgY2FuIHNlZSBpbiB0aGUgbmV4dCBjaHVuayksIHNvIHdlJ2xsIHBlcmZvcm0gdGhpcyByZW5hbWluZyBhY3Jvc3MgYWxsIFNDRXMuCgpgYGB7ciBjb21wYXJlIHJvd2RhdGEsIGxpdmUgPSBUUlVFfQojIFVzZSBgcHVycnI6Om1hcCgpYCB0byBxdWlja2x5IGV4dHJhY3Qgcm93RGF0YSBjb2x1bW4gbmFtZXMgZm9yIGFsbCBTQ0VzCnB1cnJyOjptYXAoc2NlX2xpc3QsCiAgICAgICAgICAgXCh4KSBjb2xuYW1lcyhyb3dEYXRhKHgpKSkKYGBgCgoKIyMjIyBFbnN1cmluZyB0aGF0IG9ubHkgc2hhcmVkIGdlbmVzIGFyZSB1c2VkCgpUaGUgbmV4dCBzdGVwIGluIGVuc3VyaW5nIFNDRSBjb21wYXRpYmlsaXR5IGlzIHRvIG1ha2Ugc3VyZSB0aGV5IGFsbCBjb250YWluIHRoZSBzYW1lIGdlbmVzLCB3aGljaCBhcmUgc3RvcmVkIGFzIHRoZSBTQ0Ugb2JqZWN0J3Mgcm93IG5hbWVzICh0aGVzZSBuYW1lcyBhcmUgYWxzbyBmb3VuZCB0aGUgYHJvd0RhdGFgIHNsb3QncyByb3cgbmFtZXMpLgpIZXJlLCB0aG9zZSBnZW5lIGlkcyBhcmUgdW5pcXVlIEVuc2VtYmwgZ2VuZSBpZHMuCgpXZSBjYW4gdXNlIHNvbWUgYHB1cnJyYCBtYWdpYyB0byBxdWlja2x5IGZpbmQgdGhlIHNldCBvZiBzaGFyZWQgZ2VuZXMgYW1vbmcgb3VyIHNhbXBsZXM6CgpgYGB7ciBzaGFyZWQgZ2VuZXN9CiMgRGVmaW5lIHZlY3RvciBvZiBzaGFyZWQgZ2VuZXMKc2hhcmVkX2dlbmVzIDwtIHNjZV9saXN0IHw+CiAgIyBnZXQgcm93bmFtZXMgKGdlbmVzKSBmb3IgZWFjaCBTQ0UgaW4gc2NlX2xpc3QKICBwdXJycjo6bWFwKHJvd25hbWVzKSB8PgogICMgcmVkdWNlIHRvIHRoZSBfaW50ZXJzZWN0aW9uXyBhbW9uZyBsaXN0cwogIHB1cnJyOjpyZWR1Y2UoaW50ZXJzZWN0KQpgYGAKCmBgYHtyIHByaW50IHNoYXJlZCBnZW5lcywgbGl2ZSA9IFRSVUV9CiMgVXNlIGhlYWQgdG8gbG9vayBhdCB0aGUgdmVjdG9yIG9mIHNoYXJlZCBnZW5lczoKaGVhZChzaGFyZWRfZ2VuZXMpCmBgYAoKSW4gdGhpcyBjYXNlLCB3ZSBoYXBwZW4gdG8ga25vdyB0aGF0IGFsbCBTQ0Ugb2JqZWN0cyB3ZSdyZSB3b3JraW5nIHdpdGggYWxyZWFkeSBjb250YWluZWQgdGhlIHNhbWUgZ2VuZXMuCldlIGRvIGEgcXVpY2stYW5kLWRpcnR5IGNoZWNrIGZvciB0aGlzIGJ5IGxvb2tpbmcgYXQgdGhlIG51bWJlciBvZiByb3dzIGFjcm9zcyBTQ0Ugb2JqZWN0cywgYW5kIHdlJ2xsIHNlZSB0aGF0IHRoZXkgYXJlIGFsbCB0aGUgc2FtZToKCmBgYHtyIGNoZWNrIHNoYXJlZCBnZW5lcywgbGl2ZSA9IFRSVUV9CiMgVGhlIG51bWJlciBvZiBnZW5lcyBpbiBhbiBTQ0UgY29ycmVzcG9uZHMgdG8gaXRzIG51bWJlciBvZiByb3dzOgpzY2VfbGlzdCB8PgogIHB1cnJyOjptYXAobnJvdykKYGBgCgpTbywgZm9yIG91ciBkYXRhLCB3ZSB3aWxsIG5vdCBoYXZlIHRvIHN1YnNldCB0byBzaGFyZWQgZ2VuZXMgc2luY2UgdGhleSBhcmUgYWxyZWFkeSBzaGFyZWQhCgojIyMjIEVuc3VyaW5nIG1hdGNoaW5nIGNvbHVtbnMgaW4gYGNvbERhdGFgCgpGaW5hbGx5LCB3ZSdsbCBuZWVkIHRvIGhhdmUgdGhlIHNhbWUgY29sdW1uIG5hbWVzIGFjcm9zcyBhbGwgU0NFIGBjb2xEYXRhYCB0YWJsZXMsIHNvIGxldCdzIGxvb2sgYXQgYWxsIHRob3NlIGNvbHVtbiBuYW1lcy4KV2UgY2FuIHVzZSBzaW1pbGFyIHN5bnRheCBoZXJlIHRvIHdoYXQgd2UgdXNlZCB0byBsb29rIGF0IGFsbCB0aGUgYHJvd0RhdGFgIGNvbHVtbiBuYW1lcy4KCmBgYHtyIGNvbXBhcmUgY29sZGF0YX0KcHVycnI6Om1hcChzY2VfbGlzdCwKICAgICAgICAgICBcKHgpIGNvbG5hbWVzKGNvbERhdGEoeCkpICkKYGBgCgpJdCBsb29rcyBsaWtlIHRoZSBjb2x1bW4gbmFtZXMgYXJlIGFsbCBhbHJlYWR5IG1hdGNoaW5nIGFtb25nIFNDRXMsIHNvIHRoZXJlJ3Mgbm8gc3BlY2lmaWMgcHJlcGFyYXRpb24gd2UnbGwgbmVlZCB0byBkbyB0aGVyZS4KCiMjIyBQZXJmb3JtIFNDRSBtZXJnaW5nCgpBcyB5b3UgY2FuIHNlZSwgdGhlcmUncyBhIGxvdCBvZiBtb3ZpbmcgcGFydHMgdG8gY29uc2lkZXIhCkFnYWluLCB0aGVzZSBtb3ZpbmcgcGFydHMgbWF5ICh3aWxsISkgZGlmZmVyIGZvciBTQ0VzIHRoYXQgeW91IGFyZSB3b3JraW5nIHdpdGgsIHNvIHlvdSBoYXZlIHRvIGV4cGxvcmUgeW91ciBvd24gU0NFcyBpbiBkZXB0aCB0byBwcmVwYXJlIGZvciBtZXJnaW5nLgoKQmFzZWQgb24gb3VyIGV4cGxvcmF0aW9uLCBoZXJlIGlzIGEgc2NoZW1hdGljIG9mIGhvdyBvbmUgb2YgdGhlIFNDRSBvYmplY3RzIHdpbGwgdWx0aW1hdGVseSBiZSBtb2RpZmllZCBpbnRvIHRoZSBmaW5hbCBtZXJnZWQgU0NFOgoKIVtdKGRpYWdyYW1zL3RlY2huaWNhbF9tZXJnZV9zY2UucG5nKQoKCldlJ2xsIHdyaXRlIGEgX2N1c3RvbSBmdW5jdGlvbl8gKHNlZW4gaW4gdGhlIGNodW5rIGJlbG93KSB0YWlsb3JlZCB0byBvdXIgd3JhbmdsaW5nIHN0ZXBzIHRoYXQgcHJlcGFyZXMgYSBzaW5nbGUgU0NFIG9iamVjdCBmb3IgbWVyZ2luZy4KV2UnbGwgdGhlbiB1c2Ugb3VyIG5ldyBgcHVycnI6Om1hcCgpYCBwcm9ncmFtbWluZyBza2lsbHMgdG8gcnVuIHRoaXMgZnVuY3Rpb24gb3ZlciB0aGUgYHNjZV9saXN0YC4KVGhpcyB3aWxsIGdpdmUgdXMgYSBuZXcgbGlzdCBvZiBmb3JtYXR0ZWQgU0NFcyB0aGF0IHdlIGNhbiBwcm9jZWVkIHRvIG1lcmdlLgpJdCdzIGltcG9ydGFudCB0byByZW1lbWJlciB0aGF0IHRoZSBgZm9ybWF0X3NjZSgpYCBmdW5jdGlvbiB3cml0dGVuIGJlbG93IGlzIG5vdCBhIGZ1bmN0aW9uIGZvciBnZW5lcmFsIHVzZSDigJMgaXQncyBiZWVuIHByZWNpc2VseSB3cml0dGVuIHRvIG1hdGNoIHRoZSBwcm9jZXNzaW5nIHdlIG5lZWQgdG8gZG8gZm9yIF90aGVzZV8gU0NFcywgYW5kIGRpZmZlcmVudCBTQ0VzIHlvdSB3b3JrIHdpdGggd2lsbCByZXF1aXJlIGRpZmZlcmVudCB0eXBlcyBvZiBwcm9jZXNzaW5nLgoKYGBge3IgZm9ybWF0X3NjZSBmdW5jdGlvbn0KZm9ybWF0X3NjZSA8LSBmdW5jdGlvbihzY2UsIHNhbXBsZV9uYW1lKSB7CiAgIyBJbnB1dCBhcmd1bWVudHM6CiAgIyMgc2NlOiBBbiBTQ0Ugb2JqZWN0IHRvIGZvcm1hdAogICMjIHNhbXBsZV9uYW1lOiBUaGUgU0NFIG9iamVjdCdzIG5hbWUKICAjIFRoaXMgZnVuY3Rpb24gcmV0dXJucyBhIGZvcm1hdHRlZCBTQ0Ugb2JqZWN0LgoKICAjIyMjIyMgRW5zdXJlIHRoYXQgd2UgY2FuIGlkZW50aWZ5IHRoZSBvcmlnaW5hdGluZyBzYW1wbGUgaW5mb3JtYXRpb24gIyMjIyMjCiAgIyBBZGQgYSBjb2x1bW4gY2FsbGVkIGBzYW1wbGVgIHRoYXQgc3RvcmVzIHRoaXMgaW5mb3JtYXRpb24KICAjIFRoaXMgd2lsbCBiZSBzdG9yZWQgaW4gYGNvbERhdGFgCiAgc2NlJHNhbXBsZSA8LSBzYW1wbGVfbmFtZQoKCiAgIyMjIyMjIEVuc3VyZSBjZWxsIGlkcyB3aWxsIGJlIHVuaXF1ZSAjIyMjIyMKICAjIFVwZGF0ZSB0aGUgU0NFIG9iamVjdCBjb2x1bW4gbmFtZXMgKGNlbGwgaWRzKSBieSBwcmVwZW5kaW5nIGBzYW1wbGVfbmFtZWAKICBjb2xuYW1lcyhzY2UpIDwtIGdsdWU6OmdsdWUoIntzYW1wbGVfbmFtZX0te2NvbG5hbWVzKHNjZSl9IikKCgogICMjIyMjIyBFbnN1cmUgZ2VuZS1sZXZlbCBzdGF0aXN0aWNzIGNhbiBiZSBpZGVudGlmaWVkIGluIGByb3dEYXRhYCAjIyMjIyMKICAjIFdlIHdhbnQgdG8gcmVuYW1lIHRoZSBjb2x1bW5zIGBtZWFuYCBhbmQgYGRldGVjdGVkYCB0byBjb250YWluIHRoZSBgc2FtcGxlX25hbWVgCiAgIyBSZWNhbGwgdGhlIG5hbWVzIGFyZTogImdlbmVfc3ltYm9sIiwgIm1lYW4iLCAiZGV0ZWN0ZWQiCiAgY29sbmFtZXMocm93RGF0YShzY2UpKSA8LSBjKCJnZW5lX3N5bWJvbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdsdWU6OmdsdWUoIntzYW1wbGVfbmFtZX0tbWVhbiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnbHVlOjpnbHVlKCJ7c2FtcGxlX25hbWV9LWRldGVjdGVkIikpCgogICMgUmV0dXJuIHRoZSBmb3JtYXR0ZWQgU0NFIG9iamVjdAogIHJldHVybihzY2UpCn0KYGBgCgpUbyBydW4gdGhpcyBmdW5jdGlvbiwgd2UnbGwgdXNlIHRoZSBgcHVycnI6Om1hcDIoKWAgZnVuY3Rpb24sIGEgcmVsYXRpdmUgb2YgYHB1cnJyOjptYXAoKWAgdGhhdCBhbGxvd3MgeW91IHRvIGxvb3Agb3ZlciBfdHdvXyBpbnB1dCBsaXN0cy92ZWN0b3JzLgpJbiBvdXIgY2FzZSwgd2Ugd2FudCB0byBydW4gYGZvcm1hdF9zY2UoKWAgb3ZlciBwYWlyZWQgYHNjZV9saXN0YCBpdGVtcyBhbmQgYHNjZV9saXN0YCBuYW1lcy4KCmBgYHtyIGZvcm1hdCBzY2VzIGZvciBtZXJnZSwgbGl2ZSA9IFRSVUV9CiMgV2UgY2FuIHVzZSBgcHVycnI6Om1hcDIoKWAgdG8gbG9vcCBvdmVyIHR3byBsaXN0L3ZlY3RvciBhcmd1bWVudHMKc2NlX2xpc3RfZm9ybWF0dGVkIDwtIHB1cnJyOjptYXAyKAogICMgRWFjaCAiaXRlcmF0aW9uIiB3aWxsIG1hcmNoIGRvd24gdGhlIGZpcnN0IHR3bwogICMgIGFyZ3VtZW50cyBgc2NlX2xpc3RgIGFuZCBgbmFtZXMoc2NlX2xpc3QpYCBpbiBvcmRlcgogIHNjZV9saXN0LAogIG5hbWVzKHNjZV9saXN0KSwKICAjIE5hbWUgb2YgdGhlIGZ1bmN0aW9uIHRvIHJ1bgogIGZvcm1hdF9zY2UKKQoKIyBQcmludCByZXN1bHRpbmcgbGlzdApzY2VfbGlzdF9mb3JtYXR0ZWQKYGBgCgooUHNzdCwgbGlrZSBgcHVycnJgIGFuZCB3YW50IHRvIGRpdmUgZGVlcGVyPyBDaGVjayBvdXQgW3RoZSBgcHVycnI6OmltYXAoKWAgZnVuY3Rpb25dKGh0dHBzOi8vcHVycnIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvaW1hcC5odG1sKSEpCgoKQXQgbG9uZyBsYXN0LCB3ZSBhcmUgcmVhZHkgdG8gbWVyZ2UgdGhlIFNDRXMsIHdoaWNoIHdlJ2xsIGRvIHVzaW5nIHRoZSBSIGZ1bmN0aW9uIGBjYmluZCgpYC4KVGhlIGBjYmluZCgpYCBmdW5jdGlvbiBpcyBvZnRlbiB1c2VkIHRvIGNvbWJpbmUgZGF0YSBmcmFtZXMgb3IgbWF0cmljZXMgYnkgY29sdW1uLCBpLmUuICJzdGFjayIgdGhlbSBuZXh0IHRvIGVhY2ggb3RoZXIuClRoZSBzYW1lIHByaW5jaXBsZSBhcHBsaWVzIGhlcmUsIGJ1dCB3aGVuIHJ1biBvbiBTQ0Ugb2JqZWN0cywgYGNiaW5kKClgIHdpbGwgY3JlYXRlIGEgbmV3IFNDRSBvYmplY3QgYnkgY29tYmluaW5nIGBjb3VudHNgIGFuZCBgbG9nY291bnRzYCBtYXRyaWNlcyBieSBjb2x1bW4uCkZvbGxvd2luZyB0aGF0IHN0cnVjdHVyZSwgb3RoZXIgU0NFIHNsb3RzIChgY29sRGF0YWAsIGByb3dEYXRhYCwgcmVkdWNlZCBkaW1lbnNpb25zLCBhbmQgb3RoZXIgbWV0YWRhdGEpIGFyZSBjb21iaW5lZCBhcHByb3ByaWF0ZWx5LgoKU2luY2Ugd2UgbmVlZCB0byBhcHBseSBgY2JpbmQoKWAgdG8gYSBfbGlzdF8gb2Ygb2JqZWN0cywgd2UgbmVlZCB0byB1c2Ugc29tZSBzbGlnaHRseS1nbmFybHkgc3ludGF4OiBXZSdsbCB1c2UgdGhlIGZ1bmN0aW9uIGBkby5jYWxsKClgLCB3aGljaCBhbGxvd3MgdGhlIGBjYmluZCgpYCBpbnB1dCB0byBiZSBhIGxpc3Qgb2Ygb2JqZWN0cyB0byBjb21iaW5lLgoKYGBge3IgbWVyZ2VzIHNjZXMsIGxpdmUgPSBUUlVFfQojIE1lcmdlIFNDRSBvYmplY3RzCm1lcmdlZF9zY2UgPC0gZG8uY2FsbChjYmluZCwgc2NlX2xpc3RfZm9ybWF0dGVkKQoKIyBQcmludCB0aGUgbWVyZ2VkX3NjZSBvYmplY3QKbWVyZ2VkX3NjZQpgYGAKCldlIG5vdyBoYXZlIGEgc2luZ2xlIFNDRSBvYmplY3QgdGhhdCBjb250YWlucyBhbGwgY2VsbHMgZnJvbSBhbGwgc2FtcGxlcyB3ZSdkIGxpa2UgdG8gaW50ZWdyYXRlLgoKTGV0J3MgdGFrZSBhIHBlZWsgYXQgc29tZSBvZiB0aGUgaW5uYXJkcyBvZiB0aGlzIG5ldyBTQ0Ugb2JqZWN0OgoKYGBge3IgZXhwbG9yZSBtZXJnZWRfc2NlLCBsaXZlID0gVFJVRX0KIyBXaGF0IGFyZSB0aGUgdW5pcXVlIHZhbHVlcyBpbiB0aGUgYHNhbXBsZWAgY29sdW1uPwp1bmlxdWUoIGNvbERhdGEobWVyZ2VkX3NjZSkkc2FtcGxlICkKCiMgV2hhdCBhcmUgdGhlIG5ldyBjZWxsIGlkcyAoY29sdW1uIG5hbWVzKT8KaGVhZCggY29sbmFtZXMobWVyZ2VkX3NjZSkgKQoKIyBXaGF0IGRvZXMgcm93RGF0YSBsb29rIGxpa2U/CmhlYWQoIHJvd0RhdGEobWVyZ2VkX3NjZSkgKQpgYGAKCgojIyBJbnRlZ3JhdGlvbgoKIVtTaW5nbGUtY2VsbCByb2FkbWFwOiBJbnRlZ3JhdGVdKGRpYWdyYW1zL3JvYWRtYXBfbXVsdGlfaW50ZWdyYXRlLnBuZykKCgpTbyBmYXIsIHdlJ3ZlIGNyZWF0ZWQgYSBgbWVyZ2VkX3NjZWAgb2JqZWN0IHdoaWNoIGlzIChhbG1vc3QhKSByZWFkeSBmb3IgaW50ZWdyYXRpb24uCgpUaGUgaW50ZWdyYXRpb24gbWV0aG9kcyB3ZSdsbCBiZSB1c2luZyBoZXJlIGFjdHVhbGx5IHBlcmZvcm0gYmF0Y2ggY29ycmVjdGlvbiBvbiBhIHJlZHVjZWQgZGltZW5zaW9uIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBub3JtYWxpemVkIGdlbmUgZXhwcmVzc2lvbiB2YWx1ZXMsIHdoaWNoIGlzIG1vcmUgZWZmaWNpZW50LgpgZmFzdE1OTmAgYW5kIGBoYXJtb255YCBzcGVjaWZpY2FsbHkgdXNlIFBDQSBmb3IgdGhpcywgYnV0IGJlIGF3YXJlIHRoYXQgZGlmZmVyZW50IGludGVncmF0aW9uIG1ldGhvZHMgbWF5IHVzZSBvdGhlciBraW5kcyBvZiByZWR1Y2VkIGRpbWVuc2lvbnMuCgpZb3UnbGwgbm90aWNlIHRoYXQgdGhlIG1lcmdlZCBTQ0Ugb2JqZWN0IG9iamVjdCBhbHJlYWR5IGNvbnRhaW5zIFBDQSBhbmQgVU1BUCByZWR1Y2VkIGRpbWVuc2lvbnMsIHdoaWNoIHdlcmUgY2FsY3VsYXRlZCBkdXJpbmcgb3VyIHByZS1wcm9jZXNzaW5nOgoKYGBge3IgbWVyZ2VkX3NjZSByZWRkaW0sIGxpdmUgPSBUUlVFfQojIFByaW50IHRoZSByZWR1Y2VkRGltTmFtZXMgb2YgdGhlIG1lcmdlZF9zY2UKcmVkdWNlZERpbU5hbWVzKG1lcmdlZF9zY2UpCmBgYAoKVGhlc2UgcmVwcmVzZW50IHRoZSBvcmlnaW5hbCBkaW1lbnNpb24gcmVkdWN0aW9ucyB0aGF0IHdlcmUgcGVyZm9ybWVkIG9uIF9lYWNoIGluZGl2aWR1YWwgU0NFXyBiZWZvcmUgbWVyZ2luZywgYnV0IHdlIGFjdHVhbGx5IG5lZWQgdG8gY2FsY3VsYXRlIFBDQSAoYW5kIFVNQVAgZm9yIHZpc3VhbGl6YXRpb24pIGZyb20gdGhlIG1lcmdlZCBvYmplY3QgZGlyZWN0bHkuCgpXaHkgY2FuJ3Qgd2UgdXNlIHRoZSBzYW1wbGUtc3BlY2lmaWMgUENBIGFuZCBVTUFQIG1hdHJpY2VzPwpQYXJ0IG9mIHRoZXNlIGNhbGN1bGF0aW9ucyB0aGVtc2VsdmVzIGludm9sdmVzIHNjYWxpbmcgdGhlIHJhdyBkYXRhIHRvIGNlbnRlciB0aGUgbWVhbi4KV2hlbiBzYW1wbGVzIGFyZSBzZXBhcmF0ZWx5IGNlbnRlcmVkIGJ1dCBwbG90dGluZyB0b2dldGhlciwgeW91IHdpbGwgc2VlIHNhbXBsZXMgIm92ZXJsYXBwaW5nIiBpbiBzcGFjZSwgYnV0IHRoaXMgcGxhY2VtZW50IGlzIGFjdHVhbGx5IGp1c3QgYW4gYXJ0aWZhY3Qgb2YgdGhlIGluZGl2aWR1YWwgY2VudGVyaW5nLgpJbiBhZGRpdGlvbiwgdGhlIG1hdGhlbWF0aWNhbCByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgb3JpZ2luYWwgZXhwcmVzc2lvbiBkYXRhIGFuZCByZWR1Y2VkIGRpbWVuc2lvbiB2ZXJzaW9uIG9mIHRoYXQgZGF0YSB3aWxsIGRpZmZlciBhY3Jvc3Mgc2FtcGxlcywgbWVhbmluZyB3ZSBjYW4ndCBpbnRlcnByZXQgdGhlbSBhbGwgdG9nZXRoZXIuClRvIHNlZSBob3cgdGhpcyBsb29rcywgbGV0J3MgbG9vayBhdCB0aGUgVU1BUCB3aGVuIGNhbGN1bGF0ZWQgZnJvbSBpbmRpdmlkdWFsIHNhbXBsZXM6CgpgYGB7ciBwbG90IGluZGl2aWR1YWwgVU1BUHMsIGxpdmUgPSBUUlVFfQojIFBsb3QgVU1BUCBjYWxjdWxhdGVkIGZyb20gaW5kaXZpZHVhbCBzYW1wbGVzIHdpdGggc2VwYXJhdGUgc2NhbGluZwpzY2F0ZXI6OnBsb3RSZWR1Y2VkRGltKG1lcmdlZF9zY2UsCiAgICAgICAgICAgICAgICAgICAgICAgZGltcmVkID0gIlVNQVAiLAogICAgICAgICAgICAgICAgICAgICAgIGNvbG9yX2J5ID0gInNhbXBsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgcG9pbnRfc2l6ZSA9IDAuNSwKICAgICAgICAgICAgICAgICAgICAgICBwb2ludF9hbHBoYSA9IDAuMikgKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIiwgbmFtZSA9ICJzYW1wbGUiKSArICMgVXNlIGEgQ1ZELWZyaWVuZGx5IGNvbG9yIHNjaGVtZSBhbmQgc3BlY2lmeSBsZWdlbmQgbmFtZQogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzLCBhbHBoYSA9IDEpKSkgKyAjIE1vZGlmeSB0aGUgbGVnZW5kIGtleSB3aXRoIGxhcmdlciwgZWFzaWVyIHRvIHNlZSBwb2ludHMKICBnZ3RpdGxlKCJVTUFQIGNhbGN1bGF0ZWQgb24gZWFjaCBzYW1wbGUgc2VwYXJhdGVseSIpCgpgYGAKCgpBcyB3ZSBzZWUgaW4gdGhpcyBVTUFQLCBhbGwgc2FtcGxlcyBhcmUgY2VudGVyZWQgYXQgemVybyBhbmQgYWxsIG92ZXJsYXBwaW5nLgpUaGlzIHZpc3VhbCBhcnRpZmFjdCBjYW4gZ2l2ZSB0aGUgX2luY29ycmVjdCBpbXByZXNzaW9uXyB0aGF0IGRhdGEgaXMgaW50ZWdyYXRlZCAtIHRvIGJlIGNsZWFyLCB0aGlzIGRhdGEgaXMgTk9UIGludGVncmF0ZWQhCgpGb3IgaW5wdXQgdG8gaW50ZWdyYXRpb24sIHdlJ2xsIHdhbnQgdGhlIHJlZHVjZWQgZGltZW5zaW9uIGNhbGN1bGF0aW9ucyB0byBjb25zaWRlciBub3JtYWxpemVkIGdlbmUgZXhwcmVzc2lvbiB2YWx1ZXMgZnJvbSBhbGwgc2FtcGxlcyBzaW11bHRhbmVvdXNseS4KU28gd2UnbGwgbmVlZCB0byByZWNhbGN1bGF0ZSBQQ0EgKGFuZCBVTUFQIGZvciB2aXN1YWxpemF0aW9uKSBvbiB0aGUgbWVyZ2VkIG9iamVjdC4KV2UnbGwgYWxzbyBzYXZlIHRoZXNlIG5ldyByZWR1Y2VkIGRpbWVuc2lvbnMgd2l0aCBkaWZmZXJlbnQgbmFtZXMsIGBtZXJnZWRfUENBYCBhbmQgYG1lcmdlZF9VTUFQYCwgdG8gZGlzdGluZ3Vpc2ggdGhlbSBmcm9tIGFscmVhZHktcHJlc2VudCBgUENBYCBhbmQgYFVNQVBgLgoKRmlyc3QsIGFzIHVzdWFsLCB3ZSdsbCBkZXRlcm1pbmUgdGhlIGhpZ2gtdmFyaWFuY2UgZ2VuZXMgdG8gdXNlIGZvciBQQ0EgZnJvbSB0aGUgYG1lcmdlZF9zY2VgIG9iamVjdC4KRm9yIHRoaXMsIHdlJ2xsIG5lZWQgdG8gcHJvdmlkZSB0aGUgYXJndW1lbnQgYGJsb2NrID0gbWVyZ2VkX3NjZSRzYW1wbGVgIHdoZW4gbW9kZWxpbmcgZ2VuZSB2YXJpYW5jZSwgd2hpY2ggdGVsbHMgYHNjcmFuOjptb2RlbEdlbmVWYXIoKWAgdG8gZmlyc3QgbW9kZWwgdmFyaWFuY2Ugc2VwYXJhdGVseSBmb3IgZWFjaCBiYXRjaCBhbmQgdGhlbiBjb21iaW5lIHRob3NlIG1vZGVsaW5nIHN0YXRpc3RpY3MuCgpgYGB7ciBjYWxjIG1lcmdlZCBodiBnZW5lc30KIyBTcGVjaWZ5IHRoZSBudW1iZXIgb2YgZ2VuZXMgdG8gaWRlbnRpZnkKbnVtX2dlbmVzIDwtIDIwMDAKCiMgQ2FsY3VsYXRlIHZhcmlhdGlvbiBmb3IgZWFjaCBnZW5lCmdlbmVfdmFyaWFuY2UgPC0gc2NyYW46Om1vZGVsR2VuZVZhcihtZXJnZWRfc2NlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBzcGVjaWZ5IHRoZSBncm91cGluZyBjb2x1bW46CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBibG9jayA9IG1lcmdlZF9zY2Ukc2FtcGxlKQoKIyBHZXQgdGhlIHRvcCBgbnVtX2dlbmVzYCBoaWdoLXZhcmlhbmNlIGdlbmVzIHRvIHVzZSBmb3IgZGltZW5zaW9uIHJlZHVjdGlvbgpodl9nZW5lcyA8LSBzY3Jhbjo6Z2V0VG9wSFZHcyhnZW5lX3ZhcmlhbmNlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuID0gbnVtX2dlbmVzKQpgYGAKClRvIGNhbGN1bGF0ZSB0aGUgUENBIG1hdHJpeCBpdHNlbGYsIHdlJ2xsIHVzZSBhbiBhcHByb2FjaCBmcm9tIHRoZSBgYmF0Y2hlbG9yYCBwYWNrYWdlLCB3aGljaCBpcyB0aGUgUiBwYWNrYWdlIHRoYXQgY29udGFpbnMgdGhlIGBmYXN0TU5OYCBtZXRob2QuClRoZSBbYGJhdGNoZWxvcjo6bXVsdGlCYXRjaFBDQSgpYF0oaHR0cHM6Ly9yZHJyLmlvL2Jpb2MvYmF0Y2hlbG9yL21hbi9tdWx0aUJhdGNoUENBLmh0bWwpIGZ1bmN0aW9uIGNhbGN1bGF0ZXMgYSBiYXRjaC13ZWlnaHRlZCBQQ0EgbWF0cml4LgpUaGlzIHdlaWdodGluZyBlbnN1cmVzIHRoYXQgYWxsIGJhdGNoZXMsIHdoaWNoIG1heSBoYXZlIHZlcnkgZGlmZmVyZW50IG51bWJlcnMgb2YgY2VsbHMsIGNvbnRyaWJ1dGUgZXF1YWxseSB0byB0aGUgb3ZlcmFsbCBzY2FsaW5nLgoKYGBge3IgbWFrZSBtZXJnZWRfcGNhLCBsaXZlID0gVFJVRX0KIyBVc2UgYmF0Y2hlbG9yIHRvIGNhbGN1bGF0ZSBQQ0EgZm9yIG1lcmdlZF9zY2UsIGNvbnNpZGVyaW5nIG9ubHkKIyAgdGhlIGhpZ2gtdmFyaWFuY2UgZ2VuZXMKIyBXZSdsbCBuZWVkIHRvIGluY2x1ZGUgdGhlIGFyZ3VtZW50IGBwcmVzZXJ2ZS5zaW5nbGUgPSBUUlVFYCB0byBnZXQKIyAgYSBzaW5nbGUgbWF0cml4IHdpdGggYWxsIHNhbXBsZXMgYW5kIG5vdCBzZXBhcmF0ZSBtYXRyaWNlcyBmb3IgZWFjaCBzYW1wbGUKbWVyZ2VkX3BjYSA8LSBiYXRjaGVsb3I6Om11bHRpQmF0Y2hQQ0EobWVyZ2VkX3NjZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3Vic2V0LnJvdyA9IGh2X2dlbmVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYXRjaCA9IG1lcmdlZF9zY2Ukc2FtcGxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmVzZXJ2ZS5zaW5nbGUgPSBUUlVFKQpgYGAKCkxldCdzIGhhdmUgYSBsb29rIGF0IHRoZSBvdXRwdXQ6CmBgYHtyIHByaW50IG1lcmdlZF9wY2EsIGxpdmUgPSBUUlVFfQojIFRoaXMgb3V0cHV0IGlzIG5vdCB2ZXJ5IGludGVyZXN0aW5nIQptZXJnZWRfcGNhCmBgYAoKV2UgY2FuIHVzZSBpbmRleGluZyBgW1sxXV1gIHRvIHNlZSB0aGUgUENBIG1hdHJpeCBjYWxjdWxhdGVkLCBsb29raW5nIGF0IGEgc21hbGwgc3Vic2V0IGZvciBjb252ZW5pZW5jZToKCmBgYHtyIHByaW50IG1lcmdlZF9wY2EgaW5kZXhlZCwgbGl2ZSA9IFRSVUV9Cm1lcmdlZF9wY2FbWzFdXVsxOjUsMTo1XQpgYGAKCldlIGNhbiBub3cgaW5jbHVkZSB0aGlzIFBDQSBtYXRyaXggaW4gb3VyIGBtZXJnZWRfc2NlYCBvYmplY3Q6CgpgYGB7ciBhZGQgbWVyZ2VkX3BjYSwgbGl2ZSA9IFRSVUV9CiMgYWRkIFBDQSByZXN1bHRzIHRvIG1lcmdlZCBTQ0Ugb2JqZWN0CnJlZHVjZWREaW0obWVyZ2VkX3NjZSwgIm1lcmdlZF9QQ0EiKSA8LSBtZXJnZWRfcGNhW1sxXV0KYGBgCgpOb3cgdGhhdCB3ZSBoYXZlIHRoZSBQQ0EgbWF0cml4LCB3ZSBjYW4gcHJvY2VlZCB0byBjYWxjdWxhdGUgVU1BUCB0byB2aXN1YWxpemUgdGhlIHVuY29ycmVjdGVkIG1lcmdlZCBkYXRhLgoKV2UnbGwgY2FsY3VsYXRlIFVNQVAgYXMgInVzdWFsIiwgYnV0IGluIHRoaXMgY2FzZSB3ZSdsbCBzcGVjaWZ5IHR3byBhZGRpdGlvbmFsIGFyZ3VtZW50czoKCi0gYGRpbXJlZCA9ICJtZXJnZWRfUENBImAsIHdoaWNoIHNwZWNpZmllcyB3aGljaCBleGlzdGluZyByZWR1Y2VkIGRpbWVuc2lvbiBzaG91bGQgYmUgdXNlZCBmb3IgdGhlIGNhbGN1bGF0aW9uLgpXZSB3YW50IHRvIHVzZSB0aGUgYmF0Y2gtd2VpZ2h0ZWQgUENBLCB3aGljaCB3ZSBuYW1lZCBhYm92ZSBhcyBgIm1lcmdlZF9QQ0EiYC4KLSBgbmFtZSA9ICJtZXJnZWRfVU1BUCJgLCB3aGljaCBuYW1lcyB0aGUgZmluYWwgVU1BUCB0aGF0IHRoaXMgZnVuY3Rpb24gY2FsY3VsYXRlcy4KVGhpcyBhcmd1bWVudCB3aWxsIHByZXZlbnQgdXMgZnJvbSBvdmVyd3JpdGluZyB0aGUgZXhpc3RpbmcgVU1BUCB3aGljaCBpcyBhbHJlYWR5IG5hbWVkICJVTUFQIiBhbmQgaW5zdGVhZCBjcmVhdGUgYSBzZXBhcmF0ZSBgIm1lcmdlZF9VTUFQImAuCgpgYGB7ciBjYWxjdWxhdGUgbWVyZ2VkIHVtYXAsIGxpdmUgPSBUUlVFfQojIGFkZCBtZXJnZWRfVU1BUCBmcm9tIG1lcmdlZF9QQ0EKbWVyZ2VkX3NjZSA8LSBzY2F0ZXI6OnJ1blVNQVAobWVyZ2VkX3NjZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGltcmVkID0gIm1lcmdlZF9QQ0EiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIm1lcmdlZF9VTUFQIikKYGBgCgpOb3csIGxldCdzIHNlZSBob3cgdGhpcyBuZXcgYG1lcmdlZF9VTUFQYCBsb29rcyBjb21wYXJlZCB0byB0aGUgYFVNQVBgIGNhbGN1bGF0ZWQgZnJvbSBpbmRpdmlkdWFsIHNhbXBsZXM6CgpgYGB7ciBwbG90IHVuY29ycmVjdGVkIG1lcmdlZCBVTUFQfQojIFVNQVBzIHNjYWxlZCB0b2dldGhlciB3aGVuIGNhbGN1bGF0ZWQgZnJvbSB0aGUgbWVyZ2VkIFNDRQpzY2F0ZXI6OnBsb3RSZWR1Y2VkRGltKG1lcmdlZF9zY2UsCiAgICAgICAgICAgICAgICAgICAgICAgZGltcmVkID0gIm1lcmdlZF9VTUFQIiwKICAgICAgICAgICAgICAgICAgICAgICBjb2xvcl9ieSA9ICJzYW1wbGUiLAogICAgICAgICAgICAgICAgICAgICAgICMgU29tZSBzdHlsaW5nIHRvIGhlbHAgdXMgc2VlIHRoZSBwb2ludHM6CiAgICAgICAgICAgICAgICAgICAgICAgcG9pbnRfc2l6ZSA9IDAuNSwKICAgICAgICAgICAgICAgICAgICAgICBwb2ludF9hbHBoYSA9IDAuMikgKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIiwgbmFtZSA9ICJzYW1wbGUiKSArCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDMsIGFscGhhID0gMSkpKSArCiAgZ2d0aXRsZSgiVU1BUCBjYWxjdWxhdGVkIG9uIG1lcmdlZF9zY2UiKQpgYGAKClNhbXBsZXMgYXJlIG5vdyBzZXBhcmF0ZWQsIHdoaWNoIG1vcmUgcmVhc29uYWJseSByZWZsZWN0cyB0aGF0IHRoaXMgZGF0YSBpcyBfbm90IHlldCBiYXRjaC1jb3JyZWN0ZWRfLgpXZSBjYW4gdGhpbmsgb2YgdGhpcyBVTUFQIGFzIG91ciAiYmVmb3JlIiBVTUFQLCBhbmQgd2UgY2FuIGNvbXBhcmUgdGhpcyB0byB0aGUgImFmdGVyIiBVTUFQIHdlIHNlZSBwb3N0LWludGVncmF0aW9uLgoKTGV0J3MgZGlzY3VzcyBhIGxpdHRsZSBmaXJzdDogV2hhdCB2aXN1YWwgZGlmZmVyZW5jZXMgZG8geW91IHRoaW5rIHRoZSBVTUFQIG9uIHRoZSBpbnRlZ3JhdGVkIHZlcnNpb24gb2YgZGF0YSB3aWxsIGhhdmU/CldoYXQgc2ltaWxhcml0aWVzIGRvIHlvdSB0aGluayB0aGUgaW50ZWdyYXRlZCBVTUFQIHdpbGwgaGF2ZSB0byB0aGlzIHBsb3Q/CgoKIyMjIEludGVncmF0aW9uIHdpdGggYGZhc3RNTk5gCgpGaW5hbGx5LCB3ZSdyZSByZWFkeSB0byBpbnRlZ3JhdGUhClRvIHN0YXJ0LCB3ZSdsbCB1c2UgdGhlIGBmYXN0TU5OYCBhcHByb2FjaCBmcm9tIHRoZSBCaW9jb25kdWN0b3IgW2BiYXRjaGVsb3JgIHBhY2thZ2VdKGh0dHA6Ly93d3cuYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy8zLjE2L2Jpb2MvaHRtbC9iYXRjaGVsb3IuaHRtbCkuCgpgZmFzdE1OTmAgdGFrZXMgYXMgaW5wdXQgdGhlIGBtZXJnZWRfc2NlYCBvYmplY3QgdG8gaW50ZWdyYXRlLCBhbmQgdGhlIGZpcnN0IHN0ZXAgaXQgcGVyZm9ybXMgaXMgYWN0dWFsbHkgdG8gcnVuIGBiYXRjaGVsb3I6Om11bHRpQmF0Y2hQQ0EoKWAgb24gdGhhdCBTQ0UuCkl0IHRoZW4gdXNlcyB0aGF0IGJhdGNoLXdlaWdodGVkIFBDQSBtYXRyaXggdG8gcGVyZm9ybSB0aGUgYWN0dWFsIGJhdGNoIGNvcnJlY3Rpb24uClRoZSBgYmF0Y2hgIGFyZ3VtZW50IGlzIHVzZWQgdG8gc3BlY2lmeSB0aGUgZGlmZmVyZW50IGdyb3VwaW5ncyB3aXRoaW4gdGhlIGBtZXJnZWRfc2NlYCAoaS5lLiB0aGUgb3JpZ2luYWwgc2FtcGxlIHRoYXQgZWFjaCBjZWxsIGJlbG9uZ3MgdG8pLCBhbmQgdGhlIGBzdWJzZXQucm93YCBhcmd1bWVudCBjYW4gb3B0aW9uYWxseSBiZSB1c2VkIHRvIHByb3ZpZGUgYSB2ZWN0b3Igb2YgaGlnaC12YXJpYW5jZSBnZW5lcyB0aGF0IHNob3VsZCBiZSBjb25zaWRlcmVkIGZvciB0aGlzIFBDQSBjYWxjdWxhdGlvbi4KYGZhc3RNTk5gIHdpbGwgcmV0dXJuIGFuIFNDRSBvYmplY3QgdGhhdCBjb250YWlucyBhIGJhdGNoLWNvcnJlY3RlZCBQQ0EuCkxldCdzIHJ1biBpdCBhbmQgc2F2ZSB0aGUgcmVzdWx0IHRvIGEgdmFyaWFibGUgY2FsbGVkIGBpbnRlZ3JhdGVkX3NjZWAuCgoKYGBge3IgcnVuIGZhc3Rtbm4sIGxpdmUgPSBUUlVFfQojIGludGVncmF0ZSB3aXRoIGZhc3RNTk4sIGFnYWluIHNwZWNpZnlpbmcgb25seSBvdXIgaGlnaC12YXJpYW5jZSBnZW5lcwppbnRlZ3JhdGVkX3NjZSA8LSBiYXRjaGVsb3I6OmZhc3RNTk4oCiAgbWVyZ2VkX3NjZSwKICBiYXRjaCA9IG1lcmdlZF9zY2Ukc2FtcGxlLAogIHN1YnNldC5yb3cgPSBodl9nZW5lcwopCmBgYAoKTGV0J3MgaGF2ZSBhIGxvb2sgYXQgdGhlIHJlc3VsdDoKCmBgYHtyIGZhc3Rtbm4gcmVzdWx0LCBsaXZlID0gVFJVRX0KIyBQcmludCB0aGUgaW50ZWdyYXRlZF9zY2Ugb2JqZWN0CmludGVncmF0ZWRfc2NlCmBgYAoKVGhlcmUgYXJlIGNvdXBsZSBwaWVjZXMgb2YgaW5mb3JtYXRpb24gaGVyZSBvZiBpbnRlcmVzdDoKCi0gVGhlIGBjb3JyZWN0ZWRgIHJlZHVjZWQgZGltZW5zaW9uIHJlcHJlc2VudHMgdGhlIGJhdGNoLWNvcnJlY3RlZCBQQ0EgdGhhdCBgZmFzdE1OTmAgY2FsY3VsYXRlZC4KLSBUaGUgYHJlY29uc3RydWN0ZWRgIGFzc2F5IHJlcHJlc2VudHMgdGhlIGJhdGNoLWNvcnJlY3RlZCBub3JtYWxpemVkIGV4cHJlc3Npb24gdmFsdWVzLCB3aGljaCBgZmFzdE1OTmAgImJhY2stY2FsY3VsYXRlZCIgZnJvbSB0aGUgYmF0Y2gtY29ycmVjdGVkIFBDQSAoYGNvcnJlY3RlZGApLgpHZW5lcmFsbHkgc3BlYWtpbmcsIHRoZXNlIGV4cHJlc3Npb24gdmFsdWVzIGFyZSBub3Qgc3RhbmQtYWxvbmUgdmFsdWVzIHRoYXQgeW91IHNob3VsZCB1c2UgZm9yIG90aGVyIGFwcGxpY2F0aW9ucyBsaWtlIGRpZmZlcmVudGlhbCBnZW5lIGV4cHJlc3Npb24sIGFzIGRlc2NyaWJlZCBpbiBbX09yY2hlc3RyYXRpbmcgU2luZ2xlIENlbGwgQW5hbHlzZXNfXShodHRwOi8vYmlvY29uZHVjdG9yLm9yZy9ib29rcy8zLjE2L09TQ0EubXVsdGlzYW1wbGUvdXNpbmctY29ycmVjdGVkLXZhbHVlcy5odG1sKS4KSWYgdGhlIGBzdWJzZXQucm93YCBhcmd1bWVudCBpcyBwcm92aWRlZCAoYXMgaXQgd2FzIGhlcmUpLCBvbmx5IGdlbmVzIHByZXNlbnQgaW4gYHN1YnNldC5yb3dgIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlc2UgcmVjb25zdHJ1Y3RlZCBleHByZXNzaW9uIHZhbHVlcywgYnV0IHRoaXMgc2V0dGluZyBjYW4gYmUgb3ZlcnJpZGRlbiBzbyB0aGF0IGFsbCBnZW5lcyBoYXZlIHJlY29uc3RydWN0ZWQgZXhwcmVzc2lvbiB3aXRoIHRoZSBhcmd1bWVudCBgY29ycmVjdC5hbGwgPSBUUlVFYC4KCldlJ3JlIG1vc3RseSBpbnRlcmVzdGVkIGluIHRoZSBQQ0EgdGhhdCBgZmFzdE1OTmAgY2FsY3VsYXRlZCwgc28gbGV0J3Mgc2F2ZSB0aGF0IGluZm9ybWF0aW9uICh3aXRoIGFuIGluZm9ybWF0aXZlIGFuZCB1bmlxdWUgbmFtZSkgaW50byBvdXIgYG1lcmdlZF9zY2VgIG9iamVjdDoKCmBgYHtyIGZhc3Rtbm4gcGNzLCBsaXZlID0gVFJVRX0KIyBNYWtlIGEgbmV3IHJlZHVjZWREaW0gbmFtZWQgZmFzdG1ubl9QQ0EgZnJvbSB0aGUgY29ycmVjdGVkIHJlZHVjZWREaW0gaW4gaW50ZWdyYXRlZF9zY2UKcmVkdWNlZERpbShtZXJnZWRfc2NlLCAiZmFzdG1ubl9QQ0EiKSA8LSByZWR1Y2VkRGltKGludGVncmF0ZWRfc2NlLCAiY29ycmVjdGVkIikKYGBgCgpGaW5hbGx5LCB3ZSdsbCBjYWxjdWxhdGUgVU1BUCBmcm9tIHRoZXNlIGNvcnJlY3RlZCBQQ0EgbWF0cml4IGZvciB2aXN1YWxpemF0aW9uLgoKYGBge3IgY2FsY3VsYXRlIGZhc3Rtbm4gdW1hcCwgbGl2ZSA9IFRSVUV9CiMgQ2FsY3VsYXRlIFVNQVAKbWVyZ2VkX3NjZSA8LSBzY2F0ZXI6OnJ1blVNQVAoCiAgbWVyZ2VkX3NjZSwKICBkaW1yZWQgPSAiZmFzdG1ubl9QQ0EiLAogIG5hbWUgPSAiZmFzdG1ubl9VTUFQIgopCmBgYAoKRmlyc3QsIGxldCdzIHBsb3QgdGhlIGludGVncmF0ZWQgVU1BUCBoaWdobGlnaHRpbmcgdGhlIGRpZmZlcmVudCBiYXRjaGVzLgpBIHdlbGwtaW50ZWdyYXRlZCBkYXRhc2V0IHdpbGwgc2hvdyBiYXRjaCBtaXhpbmcsIGJ1dCBhIHBvb3JseS1pbnRlZ3JhdGVkIGRhdGFzZXQgd2lsbCBzaG93IG1vcmUgc2VwYXJhdGlvbiBhbW9uZyBiYXRjaGVzLCBzaW1pbGFyIHRvIHRoZSB1bmNvcnJlY3RlZCBVTUFQLgpOb3RlIHRoYXQgdGhpcyBpcyBhIG1vcmUgcXVhbGl0YXRpdmUgd2F5IHRvIGFzc2VzcyB0aGUgc3VjY2VzcyBvZiBpbnRlZ3JhdGlvbiwgYnV0IHRoZXJlIGFyZSBmb3JtYWwgbWV0cmljcyBvbmUgY2FuIHVzZSB0byBhc3Nlc3MgYmF0Y2ggbWl4aW5nLCB3aGljaCB5b3UgY2FuIHJlYWQgbW9yZSBhYm91dCBpbiBbdGhpcyBjaGFwdGVyIG9mIE9TQ0FdKGh0dHA6Ly9iaW9jb25kdWN0b3Iub3JnL2Jvb2tzLzMuMTYvT1NDQS5tdWx0aXNhbXBsZS9jb3JyZWN0aW9uLWRpYWdub3N0aWNzLmh0bWwpLgoKYGBge3IgcGxvdCBmYXN0bW5uIHVtYXAgYmF0Y2hlc30Kc2NhdGVyOjpwbG90UmVkdWNlZERpbShtZXJnZWRfc2NlLAogICAgICAgICAgICAgICAgICAgICAgICMgcGxvdCB0aGUgZmFzdE1OTiBjb29yZGluYXRlcwogICAgICAgICAgICAgICAgICAgICAgIGRpbXJlZCA9ICJmYXN0bW5uX1VNQVAiLAogICAgICAgICAgICAgICAgICAgICAgICMgY29sb3IgYnkgc2FtcGxlCiAgICAgICAgICAgICAgICAgICAgICAgY29sb3JfYnkgPSAic2FtcGxlIiwKICAgICAgICAgICAgICAgICAgICAgICAjIFNvbWUgc3R5bGluZyB0byBoZWxwIHVzIHNlZSB0aGUgcG9pbnRzOgogICAgICAgICAgICAgICAgICAgICAgIHBvaW50X3NpemUgPSAwLjUsCiAgICAgICAgICAgICAgICAgICAgICAgcG9pbnRfYWxwaGEgPSAwLjIpICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIsIG5hbWUgPSAic2FtcGxlIikgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzLCBhbHBoYSA9IDEpKSkgKwogIGdndGl0bGUoIlVNQVAgYWZ0ZXIgaW50ZWdyYXRpb24gd2l0aCBmYXN0TU5OIikKYGBgCgpUaGlzIGBmYXN0bW5uX1VNQVBgIGNlcnRhaW5seSBsb29rcyBkaWZmZXJlbnQgZnJvbSB0aGUgb25lIHdlIG1hZGUgZnJvbSBgbWVyZ2VkX1VNQVBgIQpXaGF0IGRpZmZlcmVudCB0cmVuZHMgZG8geW91IHNlZT8KRG8gYWxsIHNhbXBsZXMgbG9vayAiZXF1YWxseSB3ZWxsIiBpbnRlZ3JhdGVkLCBmcm9tIGEgZmlyc3QgbG9vaz8KCkltcG9ydGFudGx5LCBvbmUgcmVhc29uIHRoYXQgYmF0Y2hlcyBtYXkgc3RpbGwgYXBwZWFyIHNlcGFyYXRlZCBpbiB0aGUgY29ycmVjdGVkIFVNQVAgaXMgaWYgdGhleSBfc2hvdWxkXyBiZSBzZXBhcmF0ZWQgLSBmb3IgZXhhbXBsZSwgbWF5YmUgdHdvIGJhdGNoZXMgY29udGFpbiB2ZXJ5IGRpZmZlcmVudCBjZWxsIHR5cGVzLCBoYXZlIHZlcnkgZGlmZmVyZW50IGRpYWdub3Nlcywgb3IgbWF5IGJlIGZyb20gZGlmZmVyZW50IHBhdGllbnRzLgoKUmVjYWxsIGZyb20gZWFybGllciB0aGF0IHdlIGNvbnZlbmllbnRseSBoYXZlIGNlbGwgdHlwZSBhbm5vdGF0aW9ucyBpbiBvdXIgU0NFcywgc28gd2UgY2FuIGV4cGxvcmUgdGhvc2UgaGVyZSEKTGV0J3MgdGFrZSBhIHF1aWNrIGRldG91ciB0byBzZWUgd2hhdCBraW5kcyBvZiBjZWxsIHR5cGVzIGFyZSBpbiB0aGlzIGRhdGEgYnkgbWFraW5nIGEgYmFycGxvdCBvZiB0aGUgY2VsbCB0eXBlcyBhY3Jvc3Mgc2FtcGxlczoKCmBgYHtyIGV4cGxvcmUgY2VsbHR5cGVzfQojIENlbGwgdHlwZXMgYXJlIGluIHRoZSBgY2VsbHR5cGVfYnJvYWRgIGFuZCBgY2VsbHR5cGVfZmluZWAgY29sdW1ucwptZXJnZWRfc2NlX2RmIDwtIGFzLmRhdGEuZnJhbWUoY29sRGF0YShtZXJnZWRfc2NlKSkKCiMgVXNlIGdncGxvdDIgdG8gbWFrZSBhIGJhcnBsb3QgdGhlIGNlbGwgdHlwZXMgYWNyb3NzIHNhbXBsZXMKZ2dwbG90KG1lcmdlZF9zY2VfZGYsCiAgICAgICBhZXMoeCA9IHNhbXBsZSwKICAgICAgICAgICBmaWxsID0gY2VsbHR5cGVfYnJvYWQpKSArCiAgIyBCYXJwbG90IG9mIGNlbGx0eXBlIHByb3BvcnRpb25zCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZmlsbCIpICsKICAjIFVzZSBhIENWRC1mcmllbmRseSBjb2xvciBzY2hlbWUKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIiwgbmEudmFsdWUgPSAiZ3JleTgwIikgKwogICMgbmljZXIgdGhlbWUKICB0aGVtZV9idygpCmBgYAoKV2Ugc2VlIHRoYXQgVHVtb3IgY2VsbCB0eXBlcyBhcmUgYnkgZmFyIHRoZSBtb3N0IHByZXZhbGVudCBhY3Jvc3MgYWxsIHNhbXBsZXMsIGFuZCBub3JtYWwgdGlzc3VlIGNlbGwgdHlwZXMgYXJlIG5vdCB2ZXJ5IGNvbW1vbi4KV2Ugc2VlIGFsc28gdGhhdCBgU0NQQ0wwMDA0ODFgIGhhcyBhIGxhcmdlciBgVHVtb3JfTXlvY3l0ZWAgcG9wdWxhdGlvbiwgd2hpbGUgYWxsIG90aGVyIHNhbXBsZXMgaGF2ZSBsYXJnZXIgYFR1bW9yX01lc29kZXJtYCBwb3B1bGF0aW9ucy4KVGhpcyBkaWZmZXJlbmNlIF9tYXlfIGV4cGxhaW4gd2h5IHdlIG9ic2VydmUgdGhhdCBgU0NQQ0wwMDA0ODFgIGlzIHNvbWV3aGF0IG1vcmUgc2VwYXJhdGVkIGZyb20gdGhlIG90aGVyIHNhbXBsZXMgaW4gdGhlIGBmYXN0TU5OYCBVTUFQLgoKTGV0J3MgcmUtcGxvdCB0aGlzIFVNQVAgdG8gaGlnaGxpZ2h0IGNlbGwgdHlwZXM6CgoKYGBge3IgcGxvdCBmYXN0bW5uIHVtYXAgY2VsbHR5cGVzfQpzY2F0ZXI6OnBsb3RSZWR1Y2VkRGltKG1lcmdlZF9zY2UsCiAgICAgICAgICAgICAgICAgICAgICAgZGltcmVkID0gImZhc3Rtbm5fVU1BUCIsCiAgICAgICAgICAgICAgICAgICAgICAgIyBjb2xvciBieSBicm9hZCBjZWxsdHlwZXMKICAgICAgICAgICAgICAgICAgICAgICBjb2xvcl9ieSA9ICJjZWxsdHlwZV9icm9hZCIsCiAgICAgICAgICAgICAgICAgICAgICAgcG9pbnRfc2l6ZSA9IDAuNSwKICAgICAgICAgICAgICAgICAgICAgICBwb2ludF9hbHBoYSA9IDAuMikgKwogICMgaW5jbHVkZSBhcmd1bWVudCB0byBzcGVjaWZ5IGNvbG9yIG9mIE5BIHZhbHVlcwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIiwgbmFtZSA9ICJCcm9hZCBjZWxsdHlwZSIsIG5hLnZhbHVlID0gImdyZXk4MCIpICsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMywgYWxwaGEgPSAxKSkpICsKICBnZ3RpdGxlKCJVTUFQIGFmdGVyIGludGVncmF0aW9uIHdpdGggZmFzdE1OTiIpCmBgYAoKVGhpcyBVTUFQIHNob3dzIHRoYXQgdGhlIG5vcm1hbCB0aXNzdWUgY2VsbCB0eXBlcyAobW9zdGx5IHZhc2N1bGFyIGVuZG90aGVsaXVtLCBtdXNjbGUgY2VsbHMsIGFuZCBtb25vY3l0ZXMpIHRlbmQgdG8gY2x1c3RlciB0b2dldGhlciBhbmQgYXJlIGdlbmVyYWxseSBzZXBhcmF0ZWQgZnJvbSB0aGUgdHVtb3IgY2VsbCB0eXBlcywgd2hpY2ggaXMgYW4gZW5jb3VyYWdpbmcgcGF0dGVybiEKVHVtb3IgY2VsbCB0eXBlcyBmcm9tIGRpZmZlcmVudCBzYW1wbGVzIGFyZSBhbGwgYWxzbyBjbHVzdGVyaW5nIHRvZ2V0aGVyLCB3aGljaCBpcyBldmVuIG1vcmUgZW5jb3VyYWdpbmcgdGhhdCB3ZSBoYWQgc3VjY2Vzc2Z1bCBpbnRlZ3JhdGlvbi4KCkhvd2V2ZXIsIGl0J3MgYSBiaXQgY2hhbGxlbmdpbmcgdG8gc2VlIGFsbCB0aGUgcG9pbnRzIGdpdmVuIHRoZSBhbW91bnQgb2Ygb3ZlcmxhcCBpbiB0aGUgcGxvdC4KT25lIHdheSB3ZSBjYW4gc2VlIGFsbCB0aGUgcG9pbnRzIGEgYml0IGJldHRlciBpcyB0byBmYWNldCB0aGUgcGxvdCBieSBzYW1wbGUsIHVzaW5nIGBmYWNldF93cmFwKClgIGZyb20gdGhlIGBnZ3Bsb3QyYCBwYWNrYWdlICh3aGljaCB3ZSBjYW4gZG8gYmVjYXVzZSBgc2NhdGVyOjpwbG90UmVkdWNlZERpbSgpYCByZXR1cm5zIGEgYGdncGxvdDJgIG9iamVjdCk6CgpgYGB7ciBwbG90IGZhc3Rtbm4gdW1hcCBjZWxsdHlwZXMgZmFjZXRlZH0Kc2NhdGVyOjpwbG90UmVkdWNlZERpbShtZXJnZWRfc2NlLAogICAgICAgICAgICAgICAgICAgICAgIGRpbXJlZCA9ICJmYXN0bW5uX1VNQVAiLAogICAgICAgICAgICAgICAgICAgICAgIGNvbG9yX2J5ID0gImNlbGx0eXBlX2Jyb2FkIiwKICAgICAgICAgICAgICAgICAgICAgICBwb2ludF9zaXplID0gMC41LAogICAgICAgICAgICAgICAgICAgICAgIHBvaW50X2FscGhhID0gMC4yLAogICAgICAgICAgICAgICAgICAgICAgICMgQWxsb3cgZm9yIGZhY2V0aW5nIGJ5IGEgdmFyaWFibGUgdXNpbmcgYG90aGVyX2ZpZWxkc2A6CiAgICAgICAgICAgICAgICAgICAgICAgb3RoZXJfZmllbGRzID0gInNhbXBsZSIpICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIsIG5hbWUgPSAiQnJvYWQgY2VsbHR5cGUiLCBuYS52YWx1ZSA9ICJncmV5ODAiKSArCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDMsIGFscGhhID0gMSkpKSArCiAgZ2d0aXRsZSgiVU1BUCBhZnRlciBpbnRlZ3JhdGlvbiB3aXRoIGZhc3RNTk4iKSArCiAgIyBGYWNldCBieSBzYW1wbGUKICBmYWNldF93cmFwKHZhcnMoc2FtcGxlKSkgKwogICMgVXNlIGEgdGhlbWUgd2l0aCBiYWNrZ3JvdW5kIGdyaWQgdG8gbW9yZSBlYXNpbHkgY29tcGFyZSBwYW5lbCBjb29yZGluYXRlcwogIHRoZW1lX2J3KCkKYGBgCgpXaGF0IHRyZW5kcyBkbyB5b3Ugb2JzZXJ2ZSBiZXR3ZWVuIHR1bW9yIGFuZCBoZWFsdGh5IHRpc3N1ZXMgYW1vbmcgdGhlc2UgaW50ZWdyYXRlZCBzYW1wbGVzPwoKCiMjIyBJbnRlZ3JhdGlvbiB3aXRoIGBoYXJtb255YAoKYGZhc3RNTk5gIGlzIG9ubHkgb25lIG9mIG1hbnkgYXBwcm9hY2hlcyB0byBwZXJmb3JtIGludGVncmF0aW9uLCBhbmQgZGlmZmVyZW50IG1ldGhvZHMgaGF2ZSBkaWZmZXJlbnQgY2FwYWJpbGl0aWVzIGFuZCBtYXkgZ2l2ZSBkaWZmZXJlbnQgcmVzdWx0cy4KRm9yIGV4YW1wbGUsIHNvbWUgbWV0aG9kcyBjYW4gYWNjb21tb2RhdGUgYWRkaXRpb25hbCBjb3ZhcmlhdGVzIChlLmcuLCB0ZWNobm9sb2d5LCBwYXRpZW50LCBkaWFnbm9zaXMsIGV0Yy4pIHRoYXQgY2FuIGluZmx1ZW5jZSBpbnRlZ3JhdGlvbi4KSW4gZmFjdCB0aGUgZGF0YSB3ZSBhcmUgdXNpbmcgaGFzIGEga25vd24gX3BhdGllbnRfIGNvdmFyaWF0ZTsgYFNDUENMMDAwNDc5YCBhbmQgYFNDUENMMDAwNDgwYCBhcmUgZnJvbSB0aGUgZmlyc3QgcGF0aWVudCwgYW5kIGBTQ1BDTDAwMDQ4MWAgYW5kIGBTQ1BDTDAwMDQ4MmAgYXJlIGZyb20gdGhlIHNlY29uZCBwYXRpZW50LgoKU28sIGxldCdzIHBlcmZvcm0gaW50ZWdyYXRpb24gd2l0aCBhIG1ldGhvZCB0aGF0IGNhbiB1c2UgdGhpcyBpbmZvcm1hdGlvbiAtIFtgaGFybW9ueWBdKGh0dHBzOi8vcG9ydGFscy5icm9hZGluc3RpdHV0ZS5vcmcvaGFybW9ueS8pIQoKVG8gYmVnaW4gc2V0dGluZyB1cCBmb3IgYGhhcm1vbnlgIGludGVncmF0aW9uLCB3ZSBuZWVkIHRvIGFkZCBleHBsaWNpdCBwYXRpZW50IGluZm9ybWF0aW9uIGludG8gb3VyIG1lcmdlZCBTQ0UuCldlJ2xsIGNyZWF0ZSBhIG5ldyBjb2x1bW4gYHBhdGllbnRgIHdob3NlIHZhbHVlIGlzIGVpdGhlciAiQSIgb3IgIkIiIGRlcGVuZGluZyBvbiB0aGUgZ2l2ZW4gc2FtcGxlIG5hbWUsIHVzaW5nIHRoZSBbYGRwbHlyOjpjYXNlX3doZW4oKWBdKGh0dHBzOi8vZHBseXIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvY2FzZV93aGVuLmh0bWwpIGZ1bmN0aW9uLgpXZSBwcm92aWRlIHRoaXMgZnVuY3Rpb24gd2l0aCBhIHNldCBvZiBsb2dpY2FsIGV4cHJlc3Npb25zIGFuZCBlYWNoIGFzc2lnbmVkIHZhbHVlIGlzIGRlc2lnbmF0ZWQgYnkgYH5gLgpUaGUgZXhwcmVzc2lvbnMgYXJlIGV2YWx1YXRlZCBpbiBvcmRlciwgc3RvcHBpbmcgYXQgdGhlIF9maXJzdF8gb25lIHRoYXQgZXZhbHVhdGVzIGFzIGBUUlVFYCBhbmQgcmV0dXJuaW5nIHRoZSBhc3NvY2lhdGVkIHZhbHVlLgoKYGBge3IgYWRkIHBhdGllbnQgaW5mb30KIyBDcmVhdGUgcGF0aWVudCBjb2x1bW4gd2l0aCB2YWx1ZXMgIkEiIG9yICJCIiBmb3IgdGhlIHR3byBwYXRpZW50cwptZXJnZWRfc2NlJHBhdGllbnQgPC0gZHBseXI6OmNhc2Vfd2hlbigKICBtZXJnZWRfc2NlJHNhbXBsZSAlaW4lIGMoIlNDUENMMDAwNDc5IiwgIlNDUENMMDAwNDgwIikgfiAiQSIsCiAgbWVyZ2VkX3NjZSRzYW1wbGUgJWluJSBjKCJTQ1BDTDAwMDQ4MSIsICJTQ1BDTDAwMDQ4MiIpIH4gIkIiLAopCmBgYAoKClVubGlrZSBgZmFzdE1OTmAsIGBoYXJtb255YCBkb2VzIG5vdCBjYWxjdWxhdGUgY29ycmVjdGVkIGV4cHJlc3Npb24gdmFsdWVzIG5vciBkb2VzIGl0IHJldHVybiBhbiBTQ0Ugb2JqZWN0LgpMaWtlIGBmYXN0TU5OYCwgYGhhcm1vbnlgIHBlcmZvcm1zIGludGVncmF0aW9uIG9uIGEgbWVyZ2VkIFBDQSBtYXRyaXguCkhvd2V2ZXIsIHVubGlrZSBgZmFzdE1OTmAsIGBoYXJtb255YCBkb2VzIG5vdCAiYmFjay1jYWxjdWxhdGUiIGNvcnJlY3RlZCBleHByZXNzaW9uIGZyb20gdGhlIGNvcnJlY3RlZCBQQ0EgbWF0cml4IGFuZCBpdCBvbmx5IHJldHVybnMgdGhlIGNvcnJlY3RlZCBQQ0EgbWF0cml4IGl0c2VsZi4KRm9yIGlucHV0LCBgaGFybW9ueWAgbmVlZHMgYSBjb3VwbGUgcGllY2VzIG9mIGluZm9ybWF0aW9uOgoKLSBGaXJzdCwgYGhhcm1vbnlgIGNhbiBlaXRoZXIgdGFrZSBhIG1hdHJpeCBvZiBub3JtYWxpemVkIGV4cHJlc3Npb24gdmFsdWVzLCBmcm9tIHdoaWNoIGl0IHdpbGwgY2FsY3VsYXRlIGEgYmF0Y2gtd2VpZ2h0ZWQgUENBIG1hdHJpeCB0byBpbnRlZ3JhdGUsIG9yIGl0IGNhbiB0YWtlIGEgYmF0Y2gtd2VpZ2h0ZWQgUENBIG1hdHJpeCBkaXJlY3RseSB0byBwZXJmb3JtIGludGVncmF0aW9uLgpTaW5jZSB3ZSBhbHJlYWR5IGNhbGN1bGF0ZWQgYSBiYXRjaC13ZWlnaHRlZCBQQ0EgbWF0cml4IChvdXIgYG1lcmdlZF9QQ0FgIHJlZHVjZWQgZGltZW5zaW9uKSwgd2UnbGwgcHJvdmlkZSB0aGlzIGluZm9ybWF0aW9uIGRpcmVjdGx5LgogIC0gV2Ugd2lsbCBuZWVkIHRvIHNwZWNpZnkgdGhlIGFkZGl0aW9uYWwgYXJndW1lbnQgYGRvX3BjYT1GQUxTRWAgdG8gdGVsbCBgaGFybW9ueWAgdGhhdCB0aGUgaW5wdXQgbWF0cml4IHdlIHByb3ZpZGVkIGFscmVhZHkgaXMgYSBQQ0EgbWF0cml4LgotIFNlY29uZCwgd2UgbmVlZCB0byB0ZWxsIGBoYXJtb255YCBhYm91dCB0aGUgY292YXJpYXRlcyB0byB1c2UgLSBgc2FtcGxlYCBhbmQgYHBhdGllbnRgLgpUbyBkbyB0aGlzLCB3ZSBwcm92aWRlIHR3byBhcmd1bWVudHM6CiAgLSBgbWV0YV9kYXRhYCwgYSBkYXRhIGZyYW1lIHRoYXQgY29udGFpbnMgY292YXJpYXRlcyBhY3Jvc3Mgc2FtcGxlcy4KICBXZSBjYW4gc2ltcGx5IHNwZWNpZnkgdGhlIFNDRSBgY29sRGF0YWAgaGVyZSBzaW5jZSBpdCBjb250YWlucyBgc2FtcGxlYCBhbmQgYHBhdGllbnRgIGNvbHVtbnMuCiAgLSBgdmFyc191c2VgLCBhIHZlY3RvciBvZiB3aGljaCBjb2x1bW4gbmFtZXMgaW4gYG1ldGFfZGF0YWAgc2hvdWxkIGFjdHVhbGx5IGJlIHVzZWQgYXMgY292YXJpYXRlcy4KICBPdGhlciBjb2x1bW5zIGluIGBtZXRhX2RhdGFgIHdoaWNoIGFyZSBub3QgaW4gYHZhcnNfdXNlYCBhcmUgaWdub3JlZC4KCkxldCdzIGdvIQoKYGBge3IgcnVuIGhhcm1vbnksIGxpdmUgPSBUUlVFfQojIGludGVncmF0ZSB3aXRoIGhhcm1vbnksIHNldHRpbmcgdGhlIGFyZ3VtZW50IGBkb19wY2EgPSBGQUxTRWAKIyAgc2luY2Ugd2UgYXJlIHByb3ZpZGluZyBhIFBDQSBtYXRyaXggZGlyZWN0bHkKaGFybW9ueV9wY2EgPC0gaGFybW9ueTo6SGFybW9ueU1hdHJpeCgKICBkYXRhX21hdCA9IHJlZHVjZWREaW0obWVyZ2VkX3NjZSwgIm1lcmdlZF9QQ0EiKSwKICBkb19wY2EgPSBGQUxTRSwKICBtZXRhX2RhdGEgPSBjb2xEYXRhKG1lcmdlZF9zY2UpLAogIHZhcnNfdXNlID0gYygic2FtcGxlIiwgInBhdGllbnQiKQopCmBgYAoKVGhlIHJlc3VsdCBpcyBhIFBDQSBtYXRyaXguCkxldCdzIHByaW50IGEgc3Vic2V0IG9mIHRoaXMgbWF0cml4IHRvIHNlZSBpdDoKCmBgYHtyIHByaW50IGhhcm1vbnkgcmVzdWx0LCBsaXZlID0gVFJVRX0KIyBQcmludCB0aGUgaGFybW9ueSByZXN1bHQKaGFybW9ueV9wY2FbMTo1LCAxOjVdCmBgYAoKQXMgd2UgZGlkIHdpdGggYGZhc3RNTk5gIHJlc3VsdHMsIGxldCdzIHN0b3JlIHRoaXMgUENBIG1hdHJpeCBkaXJlY3RseSBpbiBvdXIgYG1lcmdlZF9zY2VgIG9iamVjdCB3aXRoIGFuIGluZm9ybWF0aXZlIG5hbWUgdGhhdCB3b24ndCBvdmVyd3JpdGUgYW55IG9mIHRoZSBleGlzdGluZyBQQ0EgbWF0cmljZXMuCldlJ2xsIGFsc28gY2FsY3VsYXRlIFVNQVAgZnJvbSBpdC4KCmBgYHtyIHNhdmUgaGFybW9ueSwgbGl2ZSA9IFRSVUV9CiMgU3RvcmUgUENBIGFzIGBoYXJtb255X1BDQWAKcmVkdWNlZERpbShtZXJnZWRfc2NlLCAiaGFybW9ueV9QQ0EiKSA8LSBoYXJtb255X3BjYQoKIyBBcyBiZWZvcmUsIGNhbGN1bGF0ZSBVTUFQIG9uIHRoaXMgUENBIG1hdHJpeCB3aXRoIGFwcHJvcHJpYXRlIG5hbWVzCm1lcmdlZF9zY2UgPC0gc2NhdGVyOjpydW5VTUFQKG1lcmdlZF9zY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpbXJlZCA9ICJoYXJtb255X1BDQSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgICA9ICJoYXJtb255X1VNQVAiKQpgYGAKCgpMZXQncyBzZWUgaG93IHRoZSBgaGFybW9ueWAgVU1BUCwgY29sb3JlZCBieSBzYW1wbGUsIGxvb2tzIGNvbXBhcmVkIHRvIHRoZSBgZmFzdE1OTmAgVU1BUDoKCmBgYHtyIHBsb3QgaGFybW9ueSB1bWFwIGJhdGNoZXN9CnNjYXRlcjo6cGxvdFJlZHVjZWREaW0obWVyZ2VkX3NjZSwKICAgICAgICAgICAgICAgICAgICAgICBkaW1yZWQgPSAiaGFybW9ueV9VTUFQIiwKICAgICAgICAgICAgICAgICAgICAgICBjb2xvcl9ieSA9ICJzYW1wbGUiLAogICAgICAgICAgICAgICAgICAgICAgIHBvaW50X3NpemUgPSAwLjUsCiAgICAgICAgICAgICAgICAgICAgICAgcG9pbnRfYWxwaGEgPSAwLjIpICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIsIG5hbWUgPSAic2FtcGxlIikgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzLCBhbHBoYSA9IDEpKSkgKwogIGdndGl0bGUoIlVNQVAgYWZ0ZXIgaW50ZWdyYXRpb24gd2l0aCBoYXJtb255IikKYGBgCgpIb3cgZG8geW91IHRoaW5rIHRoaXMgYGhhcm1vbnlgIFVNQVAgY29tcGFyZXMgdG8gdGhhdCBmcm9tIGBmYXN0TU5OYCBpbnRlZ3JhdGlvbj8KCkxldCdzIHNlZSBob3cgdGhpcyBVTUFQIGxvb2tzIGNvbG9yZWQgYnkgY2VsbCB0eXBlLCBhbmQgZmFjZXRlZCBmb3IgdmlzaWJpbGl0eToKCmBgYHtyIHBsb3QgaGFybW9ueSB1bWFwIGNlbGx0eXBlc30Kc2NhdGVyOjpwbG90UmVkdWNlZERpbShtZXJnZWRfc2NlLAogICAgICAgICAgICAgICAgICAgICAgIGRpbXJlZCA9ICJoYXJtb255X1VNQVAiLAogICAgICAgICAgICAgICAgICAgICAgIGNvbG9yX2J5ID0gImNlbGx0eXBlX2Jyb2FkIiwKICAgICAgICAgICAgICAgICAgICAgICBwb2ludF9zaXplID0gMC41LAogICAgICAgICAgICAgICAgICAgICAgIHBvaW50X2FscGhhID0gMC4yLAogICAgICAgICAgICAgICAgICAgICAgICMgU3BlY2lmeSB2YXJpYWJsZSBmb3IgZmFjZXRpbmcKICAgICAgICAgICAgICAgICAgICAgICBvdGhlcl9maWVsZHMgPSAic2FtcGxlIikgKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIiwgbmFtZSA9ICJCcm9hZCBjZWxsdHlwZSIsIG5hLnZhbHVlID0gImdyZXk4MCIpICsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMykpKSArCiAgZ2d0aXRsZSgiVU1BUCBhZnRlciBpbnRlZ3JhdGlvbiB3aXRoIGhhcm1vbnkiKSArCiAgZmFjZXRfd3JhcCh2YXJzKHNhbXBsZSkpCmBgYAoKV2hhdCBkbyB5b3Ugbm93IG5vdGljZSBpbiB0aGlzIGZhY2V0ZWQgdmlldyB0aGF0IHdhc24ndCBjbGVhciBwcmV2aW91c2x5PwpBcmUgdGhlcmUgb3RoZXIgcGF0dGVybnMgeW91IHNlZSB0aGF0IGFyZSBzaW1pbGFyIG9yIGRpZmZlcmVudCBmcm9tIHRoZSBgZmFzdE1OTmAgVU1BUD8KSG93IGRvIHlvdSB0aGluayBgZmFzdE1OTmAgdnMuIGBoYXJtb255YCBwZXJmb3JtZWQgaW4gaW50ZWdyYXRpbmcgdGhlc2Ugc2FtcGxlcz8KCiMjIyBFeHBvcnQKCkZpbmFsbHksIHdlJ2xsIGV4cG9ydCB0aGUgZmluYWwgU0NFIG9iamVjdCB3aXRoIGJvdGggYGZhc3RNTk5gIGFuZCBgaGFybW9ueWAgaW50ZWdyYXRpb24gdG8gYSBmaWxlLgpTaW5jZSB0aGlzIG9iamVjdCBpcyB2ZXJ5IGxhcmdlIChvdmVyIDEgR0IhKSwgd2UnbGwgZXhwb3J0IGl0IHRvIGEgZmlsZSB3aXRoIHNvbWUgY29tcHJlc3Npb24sIHdoaWNoLCBpbiB0aGlzIGNhc2UsIHdpbGwgcmVkdWNlIHRoZSBmaW5hbCBzaXplIHRvIGEgc21hbGxlciB+MzYwIE1CLgpUaGlzIHdpbGwgdGFrZSBhIGNvdXBsZSBtaW51dGVzIHRvIHNhdmUgd2hpbGUgY29tcHJlc3Npb24gaXMgcGVyZm9ybWVkLgoKYGBge3Igc2F2ZSBpbnRlZ3JhdGlvbiwgbGl2ZSA9IFRSVUV9CiMgRXhwb3J0IHRvIFJEUyBmaWxlIHdpdGggImd6IiBjb21wcmVzc2lvbgpyZWFkcjo6d3JpdGVfcmRzKG1lcmdlZF9zY2UsCiAgICAgICAgICAgICAgICAgaW50ZWdyYXRlZF9zY2VfZmlsZSwKICAgICAgICAgICAgICAgICBjb21wcmVzcyA9ICJneiIpCmBgYAoKCiMjIFByaW50IHNlc3Npb24gaW5mbwoKQXMgYWx3YXlzLCB3ZSdsbCBwcmludCB0aGUgc2Vzc2lvbiBpbmZvIHRvIGJlIHRyYW5zcGFyZW50IGFib3V0IHdoYXQgcGFja2FnZXMsIGFuZCB3aGljaCB2ZXJzaW9ucywgd2VyZSB1c2VkIGR1cmluZyB0aGlzIFIgc2Vzc2lvbi4KCmBgYHtyIHNlc3Npb25pbmZvfQpzZXNzaW9uSW5mbygpCmBgYAo=
diff --git a/scRNA-seq-advanced/03-differential_expression-live.Rmd b/scRNA-seq-advanced/03-differential_expression-live.Rmd index 485227ad..ad6033ae 100644 --- a/scRNA-seq-advanced/03-differential_expression-live.Rmd +++ b/scRNA-seq-advanced/03-differential_expression-live.Rmd @@ -26,7 +26,7 @@ In this notebook, we will work with multiple samples to identify differentially ![Single-cell roadmap: Differential expression](diagrams/roadmap_differential_expression.png) We will continue working with samples from the [`SCPCP000005` project](https://scpca.alexslemonade.org/projects/SCPCP000005), an investigation of pediatric solid tumors led by the Dyer and Chen labs at St. Jude Children's Research Hospital. -This particular dataset contains 10 different samples that have been integrated using `fastMNN`, following the same procedure we outlined in `03-dataset_integration.Rmd`. +This particular dataset contains 10 different samples that have been integrated using `fastMNN`, following the same procedure we outlined in `02-dataset_integration.Rmd`. These 10 samples represent two different types of rhabdomyosarcoma (RMS): embryonal rhabdomyosarcoma (ERMS) and alveolar rhabdomyosarcoma (ARMS). These two subtypes are distinguished by the presence of the `PAX3/PAX7-FOXO1` fusion gene, which is present only in ARMS patients. Additionally, cells found in ARMS tumors tend to have an increased mutational burden with cells in a more differentiated state compared to ERMS tumor cells ([Shern _et al._ 2014](https://doi.org/10.1158/2159-8290.CD-13-0639); [Stewart _et al._ 2018](https://doi.org/10.1016/j.ccell.2018.07.012)). @@ -79,9 +79,7 @@ sample_metadata_file <- file.path(data_dir, # directory to store output deseq_dir <- file.path("analysis", "rms", "deseq") -if(!dir.exists(deseq_dir)){ - dir.create(deseq_dir, recursive = TRUE) -} +fs::dir_create(deseq_dir) # results file to output from DE analysis deseq_output_file <- file.path(deseq_dir, @@ -223,7 +221,7 @@ The samples which could be further classified have a mix of `Tumor_Mesoderm`, `T scater::plotReducedDim(integrated_sce, dimred = "fastmnn_UMAP", # color each point by cell type - colour_by = "celltype_broad", + color_by = "celltype_broad", point_size= 0.5, point_alpha = 0.4) ``` @@ -267,6 +265,7 @@ ggplot(tumor_cells_df, aes(x = sample, fill = celltype_broad)) + y = "Proportion of cells", fill = "Cell type" ) + + scale_fill_brewer(palette = "Dark2") + theme_bw() + theme(axis.text.x = element_text(angle = 90, vjust = 0.5))+ # facet by diagnosis group @@ -694,7 +693,7 @@ scater::plotExpression(tumor_sce, # a vector of genes to plot features = genes_to_plot, x = "diagnosis_group", - colour_by = "diagnosis_group", + color_by = "diagnosis_group", other_fields = "celltype_broad", point_size = 0.1) + # each celltype is its own column @@ -703,7 +702,7 @@ scater::plotExpression(tumor_sce, rows = vars(Feature)) + # change the font size of the facet labels theme(strip.text = element_text(size = 7)) + - guides(colour = guide_legend( + guides(color = guide_legend( title = "Subtype", # update the legend title # change the size of the legend colors override.aes = list(size = 3, alpha = 1)) diff --git a/scRNA-seq-advanced/03-differential_expression.nb.html b/scRNA-seq-advanced/03-differential_expression.nb.html index 19ee419c..f484865b 100644 --- a/scRNA-seq-advanced/03-differential_expression.nb.html +++ b/scRNA-seq-advanced/03-differential_expression.nb.html @@ -2919,7 +2919,7 @@

Objectives

and Chen labs at St. Jude Children’s Research Hospital. This particular dataset contains 10 different samples that have been integrated using fastMNN, following the same procedure we outlined in -03-dataset_integration.Rmd. These 10 samples represent two +02-dataset_integration.Rmd. These 10 samples represent two different types of rhabdomyosarcoma (RMS): embryonal rhabdomyosarcoma (ERMS) and alveolar rhabdomyosarcoma (ARMS). These two subtypes are distinguished by the presence of the PAX3/PAX7-FOXO1 fusion @@ -2979,7 +2979,7 @@

Directories and files

To begin, let’s set up our directories and files:

- +
# set up file paths 
 # data directory for RMS data
 data_dir <- file.path("data", "rms")
@@ -2996,9 +2996,7 @@ 

Directories and files

# directory to store output deseq_dir <- file.path("analysis", "rms", "deseq") -if(!dir.exists(deseq_dir)){ - dir.create(deseq_dir, recursive = TRUE) -} +fs::dir_create(deseq_dir) # results file to output from DE analysis deseq_output_file <- file.path(deseq_dir, @@ -3232,11 +3230,11 @@

Plotting with annotations

multiple libraries or samples.

- +
# UMAP of all samples, separating by diagnosis group
 scater::plotReducedDim(integrated_sce,
                        dimred = "fastmnn_UMAP",
-                       colour_by = "diagnosis_group",
+                       color_by = "diagnosis_group",
                        point_size= 0.5,
                        point_alpha = 0.2) 
@@ -3264,12 +3262,12 @@

Plotting with annotations

Tumor_Myocyte.

- +
# UMAP of all samples labeled by cell type
 scater::plotReducedDim(integrated_sce,
                        dimred = "fastmnn_UMAP",
                        # color each point by cell type
-                       colour_by = "celltype_broad",
+                       color_by = "celltype_broad",
                        point_size= 0.5, 
                        point_alpha = 0.4)
@@ -3298,13 +3296,13 @@

Plotting with annotations

be in their own plot panel.

- +
# UMAP of all samples
 # separating by diagnosis group and labeling cell type
 scater::plotReducedDim(integrated_sce,
                        dimred = "fastmnn_UMAP",
                        # color each point by cell type
-                       colour_by = "celltype_broad",
+                       color_by = "celltype_broad",
                        point_size= 0.5, 
                        point_alpha = 0.4,
                        # tell scater to use diagnosis_group for plotting
@@ -3324,7 +3322,7 @@ 

Plotting with annotations

first.

- +
# filter coldata to only include tumor cells
 tumor_cells_df <- coldata_df |>
   # find rows where the cell type name contains the string "Tumor"
@@ -3338,6 +3336,7 @@ 

Plotting with annotations

y = "Proportion of cells", fill = "Cell type" ) + + scale_fill_brewer(palette = "Dark2") + theme_bw() + theme(axis.text.x = element_text(angle = 90, vjust = 0.5))+ # facet by diagnosis group @@ -3354,7 +3353,7 @@

Plotting with annotations

generated.
-

+

@@ -4050,7 +4049,7 @@

Exploring the identified differentially expressed genes

increasing max.overlaps
-

+

@@ -4066,14 +4065,14 @@

Exploring the identified differentially expressed genes

interest on a single-cell level.

- +
# filter to just myoblast cells and remove any NA's before plotting
 myoblast_combined_sce <- rms_sce[, which(rms_sce$celltype_broad == "Tumor_Myoblast")]
 
 # plot PTPRT (ENSG00000196090) expression in ARMS vs. ERMS
 scater::plotReducedDim(myoblast_combined_sce,
                        dimred = "fastmnn_UMAP",
-                       colour_by = "ENSG00000196090", #PTPRT
+                       color_by = "ENSG00000196090", #PTPRT
                        point_size= 0.5,
                        point_alpha = 0.4,
                        other_fields = "diagnosis_group") +
@@ -4120,7 +4119,7 @@ 

Exploring the identified differentially expressed genes

previously.

- +
# pick a couple genes to look at 
 genes_to_plot <- c("ENSG00000196090", #PTPRT
                    "ENSG00000148935") #GAS2
@@ -4130,7 +4129,7 @@ 

Exploring the identified differentially expressed genes

# a vector of genes to plot features = genes_to_plot, x = "diagnosis_group", - colour_by = "diagnosis_group", + color_by = "diagnosis_group", other_fields = "celltype_broad", point_size = 0.1) + # each celltype is its own column @@ -4139,7 +4138,7 @@

Exploring the identified differentially expressed genes

rows = vars(Feature)) + # change the font size of the facet labels theme(strip.text = element_text(size = 7)) + - guides(colour = guide_legend( + guides(color = guide_legend( title = "Subtype", # update the legend title # change the size of the legend colors override.aes = list(size = 3, alpha = 1)) @@ -4172,7 +4171,7 @@

Print session info

sessionInfo()
- +
R version 4.4.1 (2024-06-14)
 Platform: x86_64-pc-linux-gnu
 Running under: Ubuntu 22.04.4 LTS
@@ -4206,62 +4205,63 @@ 

Print session info

[13] ggplot2_3.5.1 optparse_1.7.5 loaded via a namespace (and not attached): - [1] gridExtra_2.3 rlang_1.1.3 - [3] magrittr_2.0.3 scater_1.32.0 - [5] compiler_4.4.1 flexmix_2.3-19 - [7] DelayedMatrixStats_1.26.0 vctrs_0.6.5 - [9] stringr_1.5.1 pkgconfig_2.0.3 -[11] crayon_1.5.2 fastmap_1.1.1 -[13] XVector_0.44.0 scuttle_1.14.0 -[15] labeling_0.4.3 utf8_1.2.4 -[17] rmarkdown_2.26 tzdb_0.4.0 -[19] UCSC.utils_1.0.0 ggbeeswarm_0.7.2 -[21] bit_4.0.5 xfun_0.43 -[23] modeltools_0.2-23 zlibbioc_1.50.0 -[25] cachem_1.0.8 beachmat_2.20.0 -[27] jsonlite_1.8.8 highr_0.10 -[29] DelayedArray_0.30.0 BiocParallel_1.38.0 -[31] irlba_2.3.5.1 parallel_4.4.1 -[33] R6_2.5.1 bslib_0.7.0 -[35] stringi_1.8.3 numDeriv_2016.8-1.1 -[37] jquerylib_0.1.4 Rcpp_1.0.12 -[39] knitr_1.46 readr_2.1.5 -[41] Matrix_1.7-0 splines_4.4.1 -[43] nnet_7.3-19 tidyselect_1.2.1 -[45] abind_1.4-5 yaml_2.3.8 -[47] viridis_0.6.5 codetools_0.2-20 -[49] plyr_1.8.9 lattice_0.22-6 -[51] tibble_3.2.1 withr_3.0.0 -[53] coda_0.19-4.1 evaluate_0.23 -[55] getopt_1.20.4 pillar_1.9.0 -[57] generics_0.1.3 vroom_1.6.5 -[59] emdbook_1.3.13 hms_1.1.3 -[61] sparseMatrixStats_1.16.0 munsell_0.5.1 -[63] scales_1.3.0 miQC_1.12.0 -[65] glue_1.7.0 apeglm_1.26.0 -[67] tools_4.4.1 BiocNeighbors_1.22.0 -[69] ScaledMatrix_1.12.0 locfit_1.5-9.9 -[71] forcats_1.0.0 mvtnorm_1.2-4 -[73] cowplot_1.1.3 grid_4.4.1 -[75] bbmle_1.0.25.1 bdsmatrix_1.3-7 -[77] colorspace_2.1-0 GenomeInfoDbData_1.2.12 -[79] beeswarm_0.4.0 vipor_0.4.7 -[81] cli_3.6.2 rsvd_1.0.5 -[83] fansi_1.0.6 S4Arrays_1.4.0 -[85] viridisLite_0.4.2 dplyr_1.1.4 -[87] gtable_0.3.5 EnhancedVolcano_1.22.0 -[89] sass_0.4.9 digest_0.6.35 -[91] SparseArray_1.4.0 ggrepel_0.9.5 -[93] farver_2.1.1 htmltools_0.5.8.1 -[95] lifecycle_1.0.4 httr_1.4.7 -[97] MASS_7.3-60.2 bit64_4.0.5
+ [1] gridExtra_2.3 rlang_1.1.3 + [3] magrittr_2.0.3 scater_1.32.0 + [5] compiler_4.4.1 flexmix_2.3-19 + [7] DelayedMatrixStats_1.26.0 vctrs_0.6.5 + [9] stringr_1.5.1 pkgconfig_2.0.3 + [11] crayon_1.5.2 fastmap_1.1.1 + [13] XVector_0.44.0 scuttle_1.14.0 + [15] labeling_0.4.3 utf8_1.2.4 + [17] rmarkdown_2.26 tzdb_0.4.0 + [19] UCSC.utils_1.0.0 ggbeeswarm_0.7.2 + [21] bit_4.0.5 xfun_0.43 + [23] modeltools_0.2-23 zlibbioc_1.50.0 + [25] cachem_1.0.8 beachmat_2.20.0 + [27] jsonlite_1.8.8 highr_0.10 + [29] DelayedArray_0.30.0 BiocParallel_1.38.0 + [31] irlba_2.3.5.1 parallel_4.4.1 + [33] R6_2.5.1 RColorBrewer_1.1-3 + [35] bslib_0.7.0 stringi_1.8.3 + [37] numDeriv_2016.8-1.1 jquerylib_0.1.4 + [39] Rcpp_1.0.12 knitr_1.46 + [41] readr_2.1.5 Matrix_1.7-0 + [43] splines_4.4.1 nnet_7.3-19 + [45] tidyselect_1.2.1 abind_1.4-5 + [47] yaml_2.3.8 viridis_0.6.5 + [49] codetools_0.2-20 plyr_1.8.9 + [51] lattice_0.22-6 tibble_3.2.1 + [53] withr_3.0.0 coda_0.19-4.1 + [55] evaluate_0.23 getopt_1.20.4 + [57] pillar_1.9.0 generics_0.1.3 + [59] vroom_1.6.5 emdbook_1.3.13 + [61] hms_1.1.3 sparseMatrixStats_1.16.0 + [63] munsell_0.5.1 scales_1.3.0 + [65] miQC_1.12.0 glue_1.7.0 + [67] apeglm_1.26.0 tools_4.4.1 + [69] BiocNeighbors_1.22.0 ScaledMatrix_1.12.0 + [71] locfit_1.5-9.9 forcats_1.0.0 + [73] mvtnorm_1.2-4 fs_1.6.4 + [75] cowplot_1.1.3 grid_4.4.1 + [77] bbmle_1.0.25.1 bdsmatrix_1.3-7 + [79] colorspace_2.1-0 GenomeInfoDbData_1.2.12 + [81] beeswarm_0.4.0 vipor_0.4.7 + [83] cli_3.6.2 rsvd_1.0.5 + [85] fansi_1.0.6 S4Arrays_1.4.0 + [87] viridisLite_0.4.2 dplyr_1.1.4 + [89] gtable_0.3.5 EnhancedVolcano_1.22.0 + [91] sass_0.4.9 digest_0.6.35 + [93] SparseArray_1.4.0 ggrepel_0.9.5 + [95] farver_2.1.1 htmltools_0.5.8.1 + [97] lifecycle_1.0.4 httr_1.4.7 + [99] MASS_7.3-60.2 bit64_4.0.5
-
LS0tCnRpdGxlOiAiRGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMgZm9yIHNjUk5BLXNlcSBkYXRhIgphdXRob3I6ICJEYXRhIExhYiBmb3IgQUxTRiIKZGF0ZTogMjAyMwpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwotLS0KCiMjIE9iamVjdGl2ZXMgCgpUaGlzIG5vdGVib29rIHdpbGwgZGVtb25zdHJhdGUgaG93IHRvOgoKLSBVc2UgcHNldWRvLWJ1bGtpbmcgdG8gcHJlcGFyZSBzY1JOQS1zZXEgbGlicmFyaWVzIGZvciBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbgotIFBlcmZvcm0gZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gd2l0aCB0aGUgYERFU2VxMmAgcGFja2FnZQotIFVzZSBgZ2dwbG90MmAgYW5kIGBFbmhhbmNlZFZvbGNhbm9gIHRvIHZpc3VhbGl6ZSBnZW5lIGV4cHJlc3Npb24gY2hhbmdlcyBhY3Jvc3MgY2VsbCB0eXBlcyBhbmQgc2FtcGxlcwoKLS0tCgpKdXN0IGxpa2UgYnVsayBSTkEtc2VxLCBpdCBpcyBsaWtlbHkgdGhhdCBvbmUgb2YgdGhlIGdvYWxzIHdoZW4gcGVyZm9ybWluZyBzY1JOQS1zZXEgd2lsbCBiZSB0byBjb21wYXJlIHRoZSBnZW5lIGV4cHJlc3Npb24gb2YgbXVsdGlwbGUgc2FtcGxlcyB0byBlYWNoIG90aGVyLgpVbmxpa2UgYnVsayBSTkEtc2VxIGFuYWx5c2lzLCBzY1JOQS1zZXEgYW5hbHlzaXMgYWxsb3dzIHVzIHRvIGlkZW50aWZ5IGFuZCBhbm5vdGF0ZSBjZWxsIHR5cGVzIG9yIHN1YnBvcHVsYXRpb25zIG9mIGNlbGxzIHByZXNlbnQgaW4gZWFjaCBvZiBvdXIgc2FtcGxlcy4KVGhpcyBtZWFucyB0aGF0IHdlIGNhbiBhY2NvdW50IGZvciBkaWZmZXJlbmNlcyBpbiBjZWxsIHR5cGUgY29tcG9zaXRpb24gYWNyb3NzIHNhbXBsZXMgYW5kIHNwZWNpZmljYWxseSBmb2N1cyBvbiBjZWxsIHR5cGVzIG9yIHBvcHVsYXRpb25zIG9mIGludGVyZXN0IHdoZW4gcGVyZm9ybWluZyBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiAoREUpIGFuYWx5c2lzLgpJbiB0aGlzIG5vdGVib29rLCB3ZSB3aWxsIHdvcmsgd2l0aCBtdWx0aXBsZSBzYW1wbGVzIHRvIGlkZW50aWZ5IGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyBhY3Jvc3MgY2VsbCB0eXBlcyBvZiBpbnRlcmVzdCB1c2luZyB0aGUgW2BERVNlcTJgXShodHRwczovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvMy4xNi9iaW9jL2h0bWwvREVTZXEyLmh0bWwpIHBhY2thZ2UuIAoKIVtTaW5nbGUtY2VsbCByb2FkbWFwOiBEaWZmZXJlbnRpYWwgZXhwcmVzc2lvbl0oZGlhZ3JhbXMvcm9hZG1hcF9kaWZmZXJlbnRpYWxfZXhwcmVzc2lvbi5wbmcpCgpXZSB3aWxsIGNvbnRpbnVlIHdvcmtpbmcgd2l0aCBzYW1wbGVzIGZyb20gdGhlIFtgU0NQQ1AwMDAwMDVgIHByb2plY3RdKGh0dHBzOi8vc2NwY2EuYWxleHNsZW1vbmFkZS5vcmcvcHJvamVjdHMvU0NQQ1AwMDAwMDUpLCBhbiBpbnZlc3RpZ2F0aW9uIG9mIHBlZGlhdHJpYyBzb2xpZCB0dW1vcnMgbGVkIGJ5IHRoZSBEeWVyIGFuZCBDaGVuIGxhYnMgYXQgU3QuIEp1ZGUgQ2hpbGRyZW4ncyBSZXNlYXJjaCBIb3NwaXRhbC4KVGhpcyBwYXJ0aWN1bGFyIGRhdGFzZXQgY29udGFpbnMgMTAgZGlmZmVyZW50IHNhbXBsZXMgdGhhdCBoYXZlIGJlZW4gaW50ZWdyYXRlZCB1c2luZyBgZmFzdE1OTmAsIGZvbGxvd2luZyB0aGUgc2FtZSBwcm9jZWR1cmUgd2Ugb3V0bGluZWQgaW4gYDAzLWRhdGFzZXRfaW50ZWdyYXRpb24uUm1kYC4KVGhlc2UgMTAgc2FtcGxlcyByZXByZXNlbnQgdHdvIGRpZmZlcmVudCB0eXBlcyBvZiByaGFiZG9teW9zYXJjb21hIChSTVMpOiBlbWJyeW9uYWwgcmhhYmRvbXlvc2FyY29tYSAoRVJNUykgYW5kIGFsdmVvbGFyIHJoYWJkb215b3NhcmNvbWEgKEFSTVMpLgpUaGVzZSB0d28gc3VidHlwZXMgYXJlIGRpc3Rpbmd1aXNoZWQgYnkgdGhlIHByZXNlbmNlIG9mIHRoZSBgUEFYMy9QQVg3LUZPWE8xYCBmdXNpb24gZ2VuZSwgd2hpY2ggaXMgcHJlc2VudCBvbmx5IGluIEFSTVMgcGF0aWVudHMuCkFkZGl0aW9uYWxseSwgY2VsbHMgZm91bmQgaW4gQVJNUyB0dW1vcnMgdGVuZCB0byBoYXZlIGFuIGluY3JlYXNlZCBtdXRhdGlvbmFsIGJ1cmRlbiB3aXRoIGNlbGxzIGluIGEgbW9yZSBkaWZmZXJlbnRpYXRlZCBzdGF0ZSBjb21wYXJlZCB0byBFUk1TIHR1bW9yIGNlbGxzIChbU2hlcm4gX2V0IGFsLl8gMjAxNF0oaHR0cHM6Ly9kb2kub3JnLzEwLjExNTgvMjE1OS04MjkwLkNELTEzLTA2MzkpOyBbU3Rld2FydCBfZXQgYWwuXyAyMDE4XShodHRwczovL2RvaS5vcmcvMTAuMTAxNi9qLmNjZWxsLjIwMTguMDcuMDEyKSkuClJNUyB0dW1vcnMsIHJlZ2FyZGxlc3Mgb2Ygc3VidHlwZSwgYXJlIG1hZGUgdXAgb2YgY2VsbHMgdHlwaWNhbGx5IGFzc29jaWF0ZWQgd2l0aCBkZXZlbG9wbWVudCBvZiBza2VsZXRhbCBtdXNjbGU6IG1lc29kZXJtLCBteW9ibGFzdHMsIGFuZCBteW9jeXRlcyAoW1NlYmlyZSBhbmQgTWFsb25lIDIwMDNdKGh0dHBzOi8vZG9pLm9yZy8xMC4xMTM2L2pjcC41Ni42LjQxMikpLgpbUGF0ZWwgX2V0IGFsLl8gKDIwMjIpXShodHRwczovL2RvaS5vcmcvMTAuMTAxNi9qLmRldmNlbC4yMDIyLjA0LjAwMykgdGVzdGVkIHRoZSBoeXBvdGhlc2lzIHRoYXQgY2VsbCB0eXBlcyBoYXZlIGRpc3RpbmN0IGdlbmUgZXhwcmVzc2lvbiBwYXR0ZXJucyBpbiBBUk1TIHZzLiBFUk1TIHNhbXBsZXMuCkhlcmUgd2Ugd2lsbCBsb29rIGF0IGEgc3Vic2V0IG9mIHRoZSBzYW1wbGVzIHRoZXkgc2VxdWVuY2VkIGFuZCBpZGVudGlmeSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMgaW4gdHVtb3IgY2VsbHMgYmV0d2VlbiBBUk1TIGFuZCBFUk1TIHNhbXBsZXMuCgojIyBTZXQgdXAKCmBgYHtyIHNldHVwLCBtZXNzYWdlPUZBTFNFfQojIHNldCBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkKc2V0LnNlZWQoMjAyMikKCiMgbG9hZCBsaWJyYXJpZXMKbGlicmFyeShnZ3Bsb3QyKSAjIHBsb3R0aW5nIGZ1bmN0aW9ucwpsaWJyYXJ5KFNpbmdsZUNlbGxFeHBlcmltZW50KSAKCiMgcGFja2FnZSB1c2VkIGZvciBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcwpsaWJyYXJ5KERFU2VxMikKYGBgCgojIyMgRGlyZWN0b3JpZXMgYW5kIGZpbGVzCgpXZSB3aWxsIHN0YXJ0IGJ5IHJlYWRpbmcgaW4gYSBgU2luZ2xlQ2VsbEV4cGVyaW1lbnRgIChTQ0UpIG9iamVjdCB0aGF0IGNvbnRhaW5zIGJvdGggdGhlIHVuY29ycmVjdGVkIChtZXJnZWQgYnV0IG5vdCBpbnRlZ3JhdGVkKSBhbmQgY29ycmVjdGVkIChpbnRlZ3JhdGVkKSBnZW5lIGV4cHJlc3Npb24gZGF0YSBmb3IgYWxsIDEwIHNhbXBsZXMuCgpQcmlvciB0byBpbnRlZ3JhdGlvbiwgYWxsIDEwIHNhbXBsZXMgd2VudCB0aHJvdWdoIHRoZSBzYW1lIGZpbHRlcmluZywgbm9ybWFsaXphdGlvbiwgYW5kIGRpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbi4KVGhlc2UgMTAgc2FtcGxlcyB3ZXJlIHRoZW4gbWVyZ2VkIGludG8gb25lIGBTaW5nbGVDZWxsRXhwZXJpbWVudGAgb2JqZWN0IGZvbGxvd2luZyB0aGUgc2FtZSBzdGVwcyBvdXRsaW5lZCBpbiBgMDMtZGF0YXNldF9pbnRlZ3JhdGlvbi5SbWRgLgpUaGUgbWVyZ2VkIG9iamVjdCB3YXMgdGhlbiBpbnRlZ3JhdGVkIHdpdGggYGZhc3RNTk5gIHRvIG9idGFpbiBhIGNvcnJlY3RlZCBnZW5lIGV4cHJlc3Npb24gYXNzYXkgYW5kIGNvcnJlY3RlZCByZWR1Y2VkIGRpbWVuc2lvbmFsaXR5IHJlc3VsdHMuClRoZSBmaW5hbCBTQ0Ugb2JqZWN0IHdhcyBzdG9yZWQgaW4gYGRhdGEvcm1zL2ludGVncmF0ZWQvcm1zX2FsbF9zY2UucmRzYC4KCldlIGFsc28gaGF2ZSBwcm92aWRlZCBhIG1ldGFkYXRhIGZpbGUsIGBkYXRhL3Jtcy9hbm5vdGF0aW9ucy9ybXNfc2FtcGxlX21ldGFkYXRhLnRzdmAsIHRoYXQgY29udGFpbnMgaW5mb3JtYXRpb24gZnJvbSBlYWNoIHNhbXBsZSwgc3VjaCBhcyBkaWFnbm9zaXMsIHNleCwgYWdlLCBldGMuCkVhY2ggcm93IGluIHRoaXMgZmlsZSBjb3JyZXNwb25kcyB0byBhIHNhbXBsZSBmb3VuZCBpbiB0aGUgaW50ZWdyYXRlZCBTQ0Ugb2JqZWN0LgoKVG8gYmVnaW4sIGxldCdzIHNldCB1cCBvdXIgZGlyZWN0b3JpZXMgYW5kIGZpbGVzOgoKYGBge3IgZmlsZXBhdGhzfQojIHNldCB1cCBmaWxlIHBhdGhzIAojIGRhdGEgZGlyZWN0b3J5IGZvciBSTVMgZGF0YQpkYXRhX2RpciA8LSBmaWxlLnBhdGgoImRhdGEiLCAicm1zIikKCiMgaW50ZWdyYXRlZCBmaWxlIGNvbnRhaW5pbmcgc2FtcGxlcyB0byB1c2UgZm9yIERFIGFuYWx5c2lzCmludGVncmF0ZWRfc2NlX2ZpbGUgPC0gZmlsZS5wYXRoKGRhdGFfZGlyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImludGVncmF0ZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInJtc19hbGxfc2NlLnJkcyIpCgojIHNhbXBsZSBtZXRhZGF0YSB0byBzZXQgdXAgREUgYW5hbHlzaXMKc2FtcGxlX21ldGFkYXRhX2ZpbGUgPC0gZmlsZS5wYXRoKGRhdGFfZGlyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJhbm5vdGF0aW9ucyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInJtc19zYW1wbGVfbWV0YWRhdGEudHN2IikKCiMgZGlyZWN0b3J5IHRvIHN0b3JlIG91dHB1dApkZXNlcV9kaXIgPC0gZmlsZS5wYXRoKCJhbmFseXNpcyIsICJybXMiLCAiZGVzZXEiKQppZighZGlyLmV4aXN0cyhkZXNlcV9kaXIpKXsKICBkaXIuY3JlYXRlKGRlc2VxX2RpciwgcmVjdXJzaXZlID0gVFJVRSkKfQoKIyByZXN1bHRzIGZpbGUgdG8gb3V0cHV0IGZyb20gREUgYW5hbHlzaXMKZGVzZXFfb3V0cHV0X2ZpbGUgPC0gZmlsZS5wYXRoKGRlc2VxX2RpciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicm1zX215b2JsYXN0X2Rlc2VxX3Jlc3VsdHMudHN2IikKCiMgb3V0cHV0IGludGVncmF0ZWQgc2NlIG9iamVjdApvdXRwdXRfc2NlX2ZpbGUgPC0gZmlsZS5wYXRoKGRhdGFfZGlyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiaW50ZWdyYXRlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJybXNfc3Vic2V0X3NjZS5yZHMiKQpgYGAKCldlIGNhbiBnbyBhaGVhZCBhbmQgcmVhZCBpbiB0aGUgU0NFIG9iamVjdCBhbmQgdGhlIG1ldGFkYXRhIGZpbGUuCgpgYGB7ciByZWFkIGZpbGVzLCBsaXZlPVRSVUV9CiMgcmVhZCBpbiB0aGUgU0NFIG9iamVjdCB0aGF0IGhhcyBhbHJlYWR5IGJlZW4gaW50ZWdyYXRlZAppbnRlZ3JhdGVkX3NjZSA8LSByZWFkcjo6cmVhZF9yZHMoaW50ZWdyYXRlZF9zY2VfZmlsZSkKCiMgcmVhZCBpbiBzYW1wbGUgbWV0YWRhdGEgZmlsZSAKc2FtcGxlX21ldGFkYXRhIDwtIHJlYWRyOjpyZWFkX3RzdihzYW1wbGVfbWV0YWRhdGFfZmlsZSkKYGBgCgojIyBEYXRhc2V0IGV4cGxvcmF0aW9uCgpCZWZvcmUgd2UgZGl2ZSBpbnRvIGRpZmZlcmVudGlhbCBleHByZXNzaW9uLCBsZXQncyBleHBsb3JlIG91ciBpbnRlZ3JhdGVkIFNDRSBvYmplY3QgYW5kIHRoZSBkYXRhc2V0IGEgbGl0dGxlIG1vcmUuCgpXZSdsbCBzdGFydCBieSBsb29raW5nIGF0IHdoYXQncyBpbnNpZGUgdGhlIG9iamVjdC4KSGVyZSB3ZSBzaG91bGQgaGF2ZSBib3RoIHRoZSBvcmlnaW5hbCAodW5jb3JyZWN0ZWQpIGRhdGEgYW5kIHRoZSBpbnRlZ3JhdGVkIChjb3JyZWN0ZWQpIGRhdGEgZm9yIGJvdGggdGhlIGdlbmUgZXhwcmVzc2lvbiBhbmQgdGhlIHJlZHVjZWQgZGltZW5zaW9uYWxpdHkgcmVzdWx0cy4KSG93IGFyZSB0aG9zZSBzdG9yZWQgaW4gb3VyIG9iamVjdD8KCmBgYHtyIHByaW50IHNjZSwgbGl2ZT1UUlVFfQojIHByaW50IG91dCBlbnRpcmUgb2JqZWN0CmludGVncmF0ZWRfc2NlCmBgYAoKCmBgYHtyIHByaW50IGFzc2F5IG5hbWVzLCBsaXZlPVRSVUV9CiMgbG9vayBhdCB0aGUgYXNzYXkgbmFtZXMgaW4gb3VyIG9iamVjdAphc3NheU5hbWVzKGludGVncmF0ZWRfc2NlKQpgYGAKCldoZW4gd2UgbG9vayBhdCB0aGUgYXNzYXkgbmFtZXMgd2Ugc2hvdWxkIHNlZSB0aGF0IHRoZXJlIGFyZSAzIG1hdHJpY2VzLCBgY291bnRzYCwgYGxvZ2NvdW50c2AsIGFuZCBgZmFzdG1ubl9jb3JyZWN0ZWRgLiAKVGhlIGBjb3VudHNgIGFuZCBgbG9nY291bnRzYCBhc3NheXMgY29ycmVzcG9uZCB0byB0aGUgdW5jb3JyZWN0ZWQgZ2VuZSBleHByZXNzaW9uIGRhdGEgdGhhdCBoYXMgYmVlbiBtZXJnZWQgYnV0IE5PVCBpbnRlZ3JhdGVkLgpUaGUgYGZhc3Rtbm5fY29ycmVjdGVkYCBkYXRhIGNvbnRhaW5zIHRoZSBjb3JyZWN0ZWQgZ2VuZSBleHByZXNzaW9uIGRhdGEgb2J0YWluZWQgZnJvbSBpbnRlZ3JhdGlvbi4gCkZvciB0aGlzIGV4ZXJjaXNlIHdlIHdpbGwgbm90IGJlIHVzaW5nIHRoZSBgZmFzdG1ubl9jb3JyZWN0ZWRgIGRhdGEgKG1vcmUgb24gd2h5IG5vdCBvbmNlIHdlIGdldCB0byBzZXR0aW5nIHVwIHRoZSBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiksIGJ1dCB3ZSBuZWVkIHRvIGJlIGF3YXJlIHRoYXQgaXQgaXMgcHJlc2VudCBhbmQgYmUgYWJsZSB0byBkaXN0aW5ndWlzaCBpdCBmcm9tIG91ciB1bmNvcnJlY3RlZCBkYXRhLiAKCgpgYGB7ciBwcmludCByZWR1Y2VkRGltIG5hbWVzLCBsaXZlPVRSVUV9CiMgbG9vayBhdCB0aGUgbmFtZXMgb2YgdGhlIGRpbWVuc2lvbiByZWR1Y3Rpb25zCnJlZHVjZWREaW1OYW1lcyhpbnRlZ3JhdGVkX3NjZSkKYGBgCgpJbiB0aGUgYHJlZHVjZWREaW1gIHNsb3RzIHlvdSBzaG91bGQgc2VlIGBQQ0FgIGFuZCBgVU1BUGAsIHdoaWNoIHdlcmUgYm90aCBjYWxjdWxhdGVkIGZyb20gdGhlIGNvbWJpbmVkIGRhdGEgX2JlZm9yZV8gaW50ZWdyYXRpb24uCllvdSBzaG91bGQgYWxzbyBzZWUgYGZhc3Rtbm5fUENBYCBhbmQgYGZhc3Rtbm5fVU1BUGAgcmVkdWNlZCBkaW1lbnNpb25zLCB3aGljaCBjb3JyZXNwb25kIHRvIHRoZSBpbnRlZ3JhdGVkIHJlc3VsdHMuCgojIyMgQ2VsbCB0eXBlIGFubm90YXRpb25zCgpKdXN0IGxpa2UgaW4gdGhlIGludGVncmF0aW9uIG5vdGVib29rLCB0aGlzIGRhdGFzZXQgYWxzbyBjb250YWlucyB0aGUgY2VsbCB0eXBlIGFubm90YXRpb25zIGZvdW5kIGluIHRoZSBgY2VsbHR5cGVfZmluZWAgYW5kIGBjZWxsdHlwZV9icm9hZGAgY29sdW1ucyBvZiB0aGUgYGNvbERhdGFgLgpUaGVzZSBjZWxsIHR5cGVzIHdlcmUgb3JpZ2luYWxseSBhc3NpZ25lZCBpbiBbUGF0ZWwgX2V0IGFsLl8gKDIwMjIpXShodHRwczovL2RvaS5vcmcvMTAuMTAxNi9qLmRldmNlbC4yMDIyLjA0LjAwMykuCldlIHdpbGwgdXNlIHRoZXNlIGNlbGwgdHlwZSBhc3NpZ25tZW50cyB0byBzZXQgdXAgdGhlIERFIGFuYWx5c2lzIGJlbG93LCBidXQgdGhleSBhcmUgbm90IHJlcXVpcmVkIGZvciBERSBhbmFseXNpcyBpdHNlbGYuCkl0J3MgaW1wb3J0YW50IHRvIG5vdGUgdGhhdCBERSBhbmFseXNpcyBjYW4gYmUgYXBwbGllZCB0byBhbnkgc3VicG9wdWxhdGlvbiBvZiBpbnRlcmVzdCB0aGF0IGlzIHNoYXJlZCBhY3Jvc3Mgc2FtcGxlcyBiZXNpZGVzIGp1c3QgY2VsbCB0eXBlcy4KCkJlY2F1c2Ugd2UgYXJlIGdvaW5nIHRvIGJlIGRvaW5nIERFIGFuYWx5c2lzIGJldHdlZW4gQVJNUyBhbmQgRVJNUyBzYW1wbGVzLCBsZXQncyBzdGFydCBieSBsYWJlbGluZyBjZWxscyBpbiB0aGUgaW50ZWdyYXRlZCBkYXRhc2V0IGJhc2VkIG9uIHRoZWlyIFJNUyBzdWJ0eXBlLgpUbyBkbyB0aGlzIHdlIHdpbGwgbmVlZCB0byBiZSBzdXJlIHRoYXQgdGhlIHN1YnR5cGUgaXMgcHJlc2VudCBpbiB0aGUgYGNvbERhdGFgIG9mIHRoZSBpbnRlZ3JhdGVkIFNDRSBvYmplY3QuCklmIGl0J3Mgbm90IHRoZXJlLCB3ZSBuZWVkIHRvIGFkZCBpdCBpbi4KCmBgYHtyIGNvbGRhdGEgaGVhZCwgbGl2ZT1UUlVFfQojIGxvb2sgYXQgdGhlIGhlYWQgb2YgdGhlIGNvbGRhdGEKaGVhZChjb2xEYXRhKGludGVncmF0ZWRfc2NlKSkgfD4KICBhcy5kYXRhLmZyYW1lKCkKYGBgCgpVaCBvaCwgaXQgbG9va3MgbGlrZSB0aGUgUk1TIHN1YnR5cGUgaXMgbm90IGZvdW5kIGluIHRoZSBTQ0Ugb2JqZWN0LgpGb3J0dW5hdGVseSB3ZSBhbHNvIGhhdmUgdGhlIHNhbXBsZSBtZXRhZGF0YSB0YWJsZSB0aGF0IHdlIHJlYWQgaW4gZWFybGllciwgd2hpY2ggY29udGFpbnMgaW5mb3JtYXRpb24gYWJvdXQgZWFjaCBvZiB0aGUgc2FtcGxlcyBwcmVzZW50IGluIHRoZSBkYXRhc2V0LgoKYGBge3Igc2FtcGxlIG1ldGFkYXRhLCBsaXZlPVRSVUV9CiMgcHJpbnQgb3V0IHNhbXBsZSBtZXRhZGF0YQpoZWFkKHNhbXBsZV9tZXRhZGF0YSkKYGBgCgpMb29raW5nIGF0IHRoaXMgc2FtcGxlIHRhYmxlLCB3ZSBzZWUgYSBjb2x1bW4gbmFtZWQgYHN1YmRpYWdub3Npc2Agd2hpY2ggYWNjb3VudHMgZm9yIHRoZSBSTVMgc3VidHlwZSwgQVJNUyBvciBFUk1TLgpXZSBhbHNvIHNlZSBvdGhlciBjb2x1bW5zIHRoYXQgY29udGFpbiBpbmZvcm1hdGlvbiBhYm91dCBlYWNoIHNwZWNpZmljIHNhbXBsZS4KCldlIGNhbiBpbmNvcnBvcmF0ZSB0aGUgaW5mb3JtYXRpb24gaW4gdGhpcyBzYW1wbGUgbWV0YWRhdGEgdGFibGUgaW50byB0aGUgYGNvbERhdGFgIG9mIHRoZSBpbnRlZ3JhdGVkIFNDRSBvYmplY3QuClRoaXMgd2lsbCBhbGxvdyB1cyB0byBtYXRjaCBlYWNoIG9mIHRoZSBzYW1wbGVzIGluIHRoZSBTQ0Ugb2JqZWN0IHdpdGggdGhlIFJNUyBzdWJ0eXBlIGFuZCBhbHNvIGFsbG93IHVzIHRvIHVzZSBhbnkgb2YgdGhlIGNvbHVtbnMgaW4gdGhlIHNhbXBsZSBtZXRhZGF0YSBmb3IgcGxvdHRpbmcuCgpgYGB7ciBtb2RpZnkgY29sZGF0YX0KIyBhZGQgc2FtcGxlIG1ldGFkYXRhIHRvIGNvbERhdGEgZnJvbSB0aGUgaW50ZWdyYXRlZCBTQ0Ugb2JqZWN0CmNvbGRhdGFfZGYgPC0gY29sRGF0YShpbnRlZ3JhdGVkX3NjZSkgfD4KICAjIGNvbnZlcnQgZnJvbSBEYXRhRnJhbWUgdG8gZGF0YS5mcmFtZQogIGFzLmRhdGEuZnJhbWUoKSB8PgogICMgbWVyZ2Ugd2l0aCBzYW1wbGUgbWV0YWRhdGEgCiAgZHBseXI6OmxlZnRfam9pbihzYW1wbGVfbWV0YWRhdGEsIGJ5ID0gYygic2FtcGxlIiA9ICJsaWJyYXJ5X2lkIikpIHw+CiAgIyBjcmVhdGUgbmV3IGNvbHVtbnMKICAjIGNlbGxfaWQgaXMgYSBjb21iaW5hdGlvbiBvZiBiYXJjb2RlIGFuZCBzYW1wbGUKICBkcGx5cjo6bXV0YXRlKGNlbGxfaWQgPSBnbHVlOjpnbHVlKCJ7c2FtcGxlfS17YmFyY29kZX0iKSwKICAgICAgICAgICAgICAgICMgc2ltcGxpZnkgc3ViZGlhZ25vc2lzCiAgICAgICAgICAgICAgICBkaWFnbm9zaXNfZ3JvdXAgPSBmb3JjYXRzOjpmY3RfcmVjb2RlKAogICAgICAgICAgICAgICAgICBzdWJkaWFnbm9zaXMsCiAgICAgICAgICAgICAgICAgICJBUk1TIiA9ICJBbHZlb2xhciByaGFiZG9teW9zYXJjb21hIiwKICAgICAgICAgICAgICAgICAgIkVSTVMiID0gIkVtYnJ5b25hbCByaGFiZG9teW9zYXJjb21hIgogICAgICAgICAgICAgICAgKSkKCiMgYWRkIG1vZGlmaWVkIGRhdGEgZnJhbWUgYmFjayB0byBTQ0UgYXMgRGF0YUZyYW1lCmNvbERhdGEoaW50ZWdyYXRlZF9zY2UpIDwtIERhdGFGcmFtZShjb2xkYXRhX2RmLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9IGNvbGRhdGFfZGYkY2VsbF9pZCkKYGBgCgpOb3cgd2hlbiB3ZSBsb29rIGF0IHRoZSBgY29sRGF0YWAgb2YgdGhlIFNDRSBvYmplY3Qgd2Ugc2hvdWxkIHNlZSBuZXcgY29sdW1ucywgaW5jbHVkaW5nIHRoZSBgZGlhZ25vc2lzX2dyb3VwYCBjb2x1bW4gd2hpY2ggaW5kaWNhdGVzIGlmIGVhY2ggY2VsbCBjb21lcyBmcm9tIGFuIEVSTVMgb3IgQVJNUyBzYW1wbGUuCgpgYGB7ciBwcmludCBuZXcgY29sZGF0YSwgbGl2ZT1UUlVFfQojIHRha2UgYSBsb29rIGF0IHRoZSBuZXcgbW9kaWZpZWQgY29sRGF0YQpoZWFkKGNvbERhdGEoaW50ZWdyYXRlZF9zY2UpKSB8PgogIGFzLmRhdGEuZnJhbWUoKQpgYGAKCiMjIyBQbG90dGluZyB3aXRoIGFubm90YXRpb25zCgpXZSBjYW4gbm93IHVzZSB0aGF0IGNvbHVtbiB0byBsYWJlbCBhbnkgVU1BUCBwbG90cyAob3Igb3RoZXIgcGxvdCB0eXBlcykgdGhhdCB3ZSBtYWtlLgpJbiB0aGUgY2h1bmsgYmVsb3cgd2Ugd2lsbCBzdGFydCBieSB0YWtpbmcgYSBsb29rIGF0IG91ciBpbnRlZ3JhdGlvbiByZXN1bHRzIGFuZCBjb2xvciBvdXIgY2VsbHMgYnkgUk1TIHN1YnR5cGUuCgoqKlJlbWluZGVyOiBZb3Ugc2hvdWxkIGFsd2F5cyB1c2UgdGhlIGJhdGNoLWNvcnJlY3RlZCBkaW1lbnNpb25hbGl0eSByZWR1Y3Rpb24gcmVzdWx0cyBmb3IgdmlzdWFsaXppbmcgZGF0YXNldHMgY29udGFpbmluZyBtdWx0aXBsZSBsaWJyYXJpZXMgb3Igc2FtcGxlcy4qKgoKYGBge3IgZGlhZ25vc2lzIGdyb3VwIFVNQVAsIGxpdmU9VFJVRX0KIyBVTUFQIG9mIGFsbCBzYW1wbGVzLCBzZXBhcmF0aW5nIGJ5IGRpYWdub3NpcyBncm91cApzY2F0ZXI6OnBsb3RSZWR1Y2VkRGltKGludGVncmF0ZWRfc2NlLAogICAgICAgICAgICAgICAgICAgICAgIGRpbXJlZCA9ICJmYXN0bW5uX1VNQVAiLAogICAgICAgICAgICAgICAgICAgICAgIGNvbG91cl9ieSA9ICJkaWFnbm9zaXNfZ3JvdXAiLAogICAgICAgICAgICAgICAgICAgICAgIHBvaW50X3NpemU9IDAuNSwKICAgICAgICAgICAgICAgICAgICAgICBwb2ludF9hbHBoYSA9IDAuMikgCmBgYAoKSW50ZXJlc3RpbmdseSwgaXQgbG9va3MgbGlrZSBzYW1wbGVzIGZyb20gdGhlIEFSTVMgYW5kIEVSTVMgc3VidHlwZXMgdGVuZCB0byBncm91cCB3aXRoIHNhbXBsZXMgb2YgdGhlIHNhbWUgc3VidHlwZSByYXRoZXIgdGhhbiBhbGwgdG9nZXRoZXIuIAoKSW4gdGhlIGludGVncmF0aW9uIG5vdGVib29rIHdlIGFsc28gbG9va2VkIGF0IHRoZSBkaXN0cmlidXRpb24gb2YgY2VsbCB0eXBlcyBhZnRlciBpbnRlZ3JhdGlvbi4KSW4gdGhhdCBub3RlYm9vaywgd2UgZGlzY3Vzc2VkIHRoYXQgY2VsbHMgb2YgdGhlIHNhbWUgY2VsbCB0eXBlIGFyZSBleHBlY3RlZCB0byBpbnRlZ3JhdGUgd2l0aCBvdGhlciBjZWxscyBvZiB0aGUgc2FtZSB0eXBlLgpJcyB0aGF0IHRoZSBjYXNlIHdpdGggdGhpcyBkYXRhc2V0PwoKQSB3b3JkIG9mIGNhdXRpb24gd2hlbiBldmFsdWF0aW5nIHRoZSBjZWxsIHR5cGUgcmVzdWx0cyBmb3IgdGhpcyBkYXRhc2V0OiBUaGUgY2VsbCB0eXBlcyBmb3IgdGhpcyBkYXRhc2V0IHdlcmUgYXNzaWduZWQgaW4gYSB0d28gc3RhZ2UgcHJvY2VzcyBhcyBkZXNjcmliZWQgaW4gW1BhdGVsIF9ldCBhbC5fICgyMDIyKV0oaHR0cHM6Ly9kb2kub3JnLzEwLjEwMTYvai5kZXZjZWwuMjAyMi4wNC4wMDMpLgpUaGUgZmlyc3Qgc3RhZ2UgYXNzaWduZWQgY2VsbHMgYXMgdHVtb3Igb3Igbm9uLXR1bW9yLgpUaGUgbmV4dCBzdGFnZSBmdXJ0aGVyIGNsYXNzaWZpZWQgdHVtb3IgY2VsbHMgaW50byBvbmUgb2YgdGhyZWUgdHlwZXMgb2YgdHVtb3IgY2VsbHM6IG15b2JsYXN0LCBteW9jeXRlLCBvciBtZXNvZGVybS4KU29tZSBzYW1wbGVzIGNvdWxkIG5vdCBiZSBmdXJ0aGVyIGNsYXNzaWZpZWQsIHNvIGFsbCBvZiB0aGVpciB0dW1vciBjZWxscyBhcmUgZGVub3RlZCBgVHVtb3JgLgpUaGUgc2FtcGxlcyB3aGljaCBjb3VsZCBiZSBmdXJ0aGVyIGNsYXNzaWZpZWQgaGF2ZSBhIG1peCBvZiBgVHVtb3JfTWVzb2Rlcm1gLCBgVHVtb3JfTXlvYmxhc3RgLCBhbmQgYFR1bW9yX015b2N5dGVgLgoKYGBge3IgY2VsbHR5cGUgVU1BUH0KIyBVTUFQIG9mIGFsbCBzYW1wbGVzIGxhYmVsZWQgYnkgY2VsbCB0eXBlCnNjYXRlcjo6cGxvdFJlZHVjZWREaW0oaW50ZWdyYXRlZF9zY2UsCiAgICAgICAgICAgICAgICAgICAgICAgZGltcmVkID0gImZhc3Rtbm5fVU1BUCIsCiAgICAgICAgICAgICAgICAgICAgICAgIyBjb2xvciBlYWNoIHBvaW50IGJ5IGNlbGwgdHlwZQogICAgICAgICAgICAgICAgICAgICAgIGNvbG91cl9ieSA9ICJjZWxsdHlwZV9icm9hZCIsCiAgICAgICAgICAgICAgICAgICAgICAgcG9pbnRfc2l6ZT0gMC41LCAKICAgICAgICAgICAgICAgICAgICAgICBwb2ludF9hbHBoYSA9IDAuNCkKYGBgCgpVbmxpa2Ugd2l0aCB0aGUgcHJldmlvdXMgZGF0YXNldHMgd2UgaGF2ZSBzZWVuIHdoZXJlIGFsbCBjZWxscyBvZiB0aGUgc2FtZSBjZWxsIHR5cGUgYWx3YXlzIGdyb3VwZWQgdG9nZXRoZXIsIHRoaXMgZGF0YXNldCBzaG93cyBzb21lIHNsaWdodGx5IGRpZmZlcmVudCBwYXR0ZXJucyBhbmQgbm90IGFsbCBjZWxscyBvZiB0aGUgc2FtZSBjZWxsIHR5cGUgY2x1c3RlciB0b2dldGhlci4KT25lIHJlYXNvbiBpcyB0aGF0IHR1bW9yIGRhdGEgY2FuIGJlIGhldGVyb2dlbmVvdXMgYW5kIGV2ZXJ5IHR1bW9yIGlzIHVuaXF1ZS4KRGVwZW5kaW5nIG9uIHRoZSB0dW1vciB0eXBlIHdlIG1heSBub3QgZXhwZWN0IGV2ZXJ5IHNhbXBsZSB0byBpbnRlZ3JhdGUgcGVyZmVjdGx5IGFuZCBtb3JlIGhldGVyb2dlbmVvdXMgdHVtb3IgdHlwZXMgd2lsbCBiZSBtb3JlIGRpZmZpY3VsdCB0byBpbnRlZ3JhdGUgdG9nZXRoZXIuCkluIHRoaXMgcGFydGljdWxhciBjYXNlIHdlIGFyZSBsb29raW5nIGF0IHR3byBzdWJ0eXBlcyBvZiBSTVMgdGhhdCBoYXZlIGRpc3RpbmN0IG11dGF0aW9uIGJ1cmRlbnMgYW5kIGRpZmZlcmVudGlhdGlvbiBzdGF0ZXMsIHNvIGl0J3MgbGlrZWx5IHRoYXQgdGhvc2UgZGlmZmVyZW5jZXMgY29udHJpYnV0ZSB0byBob3cgd2VsbCB0aGV5IGludGVncmF0ZS4KClRvIGV4cGxvcmUgd2hldGhlciBjZWxscyBhcmUgZ3JvdXBpbmcgdG9nZXRoZXIgYm90aCBieSBjZWxsIHR5cGUgYW5kIGJ5IFJNUyBzdWJ0eXBlLCB3ZSBjYW4gY3JlYXRlIGEgcGxvdCB0aGF0IGluY29ycG9yYXRlcyBib3RoIHBpZWNlcyBvZiBtZXRhZGF0YS4KV2Ugd2lsbCB0YWtlIGFkdmFudGFnZSBvZiB0aGUgYGZhY2V0X2dyaWQoKWAgZnVuY3Rpb24gZnJvbSBgZ2dwbG90MmAgdG8gbG9vayBhdCB0d28gdmFyaWFibGVzIGluIHRoZSBgY29sRGF0YWAgYXQgb25jZSAtIHRoZSBjZWxsIHR5cGUgYW5kIHRoZSBzdWJkaWFnbm9zaXMuCkluIHRoZSBiZWxvdyBwbG90IHdlIHdpbGwgY29sb3Igb3VyIGNlbGxzIGJ5IGNlbGwgdHlwZSB3aGlsZSBhbHNvIHVzaW5nIGBmYWNldF9ncmlkKClgIHNvIHRoYXQgY2VsbHMgZnJvbSBkaWZmZXJlbnQgc3ViZGlhZ25vc2VzIHdpbGwgYmUgaW4gdGhlaXIgb3duIHBsb3QgcGFuZWwuCgpgYGB7ciBjZWxsdHlwZSBzdWJkaWFnbm9zaXMgVU1BUCwgbGl2ZT1UUlVFfQojIFVNQVAgb2YgYWxsIHNhbXBsZXMKIyBzZXBhcmF0aW5nIGJ5IGRpYWdub3NpcyBncm91cCBhbmQgbGFiZWxpbmcgY2VsbCB0eXBlCnNjYXRlcjo6cGxvdFJlZHVjZWREaW0oaW50ZWdyYXRlZF9zY2UsCiAgICAgICAgICAgICAgICAgICAgICAgZGltcmVkID0gImZhc3Rtbm5fVU1BUCIsCiAgICAgICAgICAgICAgICAgICAgICAgIyBjb2xvciBlYWNoIHBvaW50IGJ5IGNlbGwgdHlwZQogICAgICAgICAgICAgICAgICAgICAgIGNvbG91cl9ieSA9ICJjZWxsdHlwZV9icm9hZCIsCiAgICAgICAgICAgICAgICAgICAgICAgcG9pbnRfc2l6ZT0gMC41LCAKICAgICAgICAgICAgICAgICAgICAgICBwb2ludF9hbHBoYSA9IDAuNCwKICAgICAgICAgICAgICAgICAgICAgICAjIHRlbGwgc2NhdGVyIHRvIHVzZSBkaWFnbm9zaXNfZ3JvdXAgZm9yIHBsb3R0aW5nCiAgICAgICAgICAgICAgICAgICAgICAgb3RoZXJfZmllbGRzID0gImRpYWdub3Npc19ncm91cCIpICsKICAjIGluY2x1ZGUgZWFjaCBkaWFnbm9zaXMgZ3JvdXAgYXMgaXRzIG93biBjb2x1bW4KICBmYWNldF9ncmlkKGNvbHMgPSB2YXJzKGRpYWdub3Npc19ncm91cCkpCmBgYAoKQXMgZXhwZWN0ZWQsIHdlIHNlZSB0aGF0IGNlbGwgdHlwZXMgYXJlIHNlcGFyYXRlZCwgbW9zdCBsaWtlbHkgZHVlIHRvIGRpZmZlcmVudCBSTVMgc3VidHlwZXMuCgpXZSBjYW4gYWxzbyB1c2UgYSBzdGFja2VkIGJhcnBsb3QgdG8gbG9vayBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIGNlbGwgdHlwZXMgYWNyb3NzIGVhY2ggc2FtcGxlLCB3aGljaCB3aWxsIHJlcXVpcmUgYSBiaXQgb2Ygd3JhbmdsaW5nIGZpcnN0LgoKYGBge3IgY2VsbHR5cGUgYmFycGxvdH0KIyBmaWx0ZXIgY29sZGF0YSB0byBvbmx5IGluY2x1ZGUgdHVtb3IgY2VsbHMKdHVtb3JfY2VsbHNfZGYgPC0gY29sZGF0YV9kZiB8PgogICMgZmluZCByb3dzIHdoZXJlIHRoZSBjZWxsIHR5cGUgbmFtZSBjb250YWlucyB0aGUgc3RyaW5nICJUdW1vciIKICBkcGx5cjo6ZmlsdGVyKHN0cmluZ3I6OnN0cl9kZXRlY3QoY2VsbHR5cGVfYnJvYWQsICJUdW1vciIpKQoKIyBjcmVhdGUgYSBzdGFja2VkIGJhcnBsb3QKZ2dwbG90KHR1bW9yX2NlbGxzX2RmLCBhZXMoeCA9IHNhbXBsZSwgZmlsbCA9IGNlbGx0eXBlX2Jyb2FkKSkgKyAKICAgIGdlb21fYmFyKHBvc2l0aW9uID0gImZpbGwiLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSAwLjIpICsKICAgIGxhYnMoCiAgICAgIHggPSAiU2FtcGxlIiwKICAgICAgeSA9ICJQcm9wb3J0aW9uIG9mIGNlbGxzIiwgCiAgICAgIGZpbGwgPSAiQ2VsbCB0eXBlIgogICAgKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUpKSsKICAjIGZhY2V0IGJ5IGRpYWdub3NpcyBncm91cCAKICBmYWNldF9ncmlkKGNvbHMgPSB2YXJzKGRpYWdub3Npc19ncm91cCksIAogICAgICAgICAgICAgIyBvbmx5IHNob3cgbm9uLU5BIHZhbHVlcyBvbiB4LWF4aXMKICAgICAgICAgICAgIHNjYWxlcyA9ICJmcmVlX3giLAogICAgICAgICAgICAgc3BhY2UgPSAiZnJlZV94IikKYGBgCgpTaW1pbGFyIHRvIHRoZSBVTUFQLCB0aGlzIHBsb3Qgc2hvd3MgdGhhdCBBUk1TIGFuZCBFUk1TIHNoYXJlIGEgbG90IG9mIHRoZSBzYW1lIGNlbGwgdHlwZXMuCgpXZSBhbHNvIHNlZSB0aGF0IG9ubHkgNiBvZiB0aGVzZSBsaWJyYXJpZXMgaGF2ZSB0dW1vciBjZWxscyB0aGF0IGhhdmUgYmVlbiBmdXJ0aGVyIGNsYXNzaWZpZWQgaW50byBtZXNvZGVybSwgbXlvYmxhc3QsIGFuZCBteW9jeXRlLiAKMyBsaWJyYXJpZXMgY29udGFpbiBjZWxscyB0aGF0IGFyZSBvbmx5IGNsYXNzaWZpZWQgYXMgdHVtb3Igb3Igbm9uLXR1bW9yLCBhbmQgdHVtb3IgY2VsbHMgYXJlIG5vdCBmdXJ0aGVyIGNsYXNzaWZpZWQsIGFuZCB0aGUgcmVtYWluaW5nIGxpYnJhcnkgaXMgbm90IGV2ZW4gcHJlc2VudCBpbiBvdXIgcGxvdCBiZWNhdXNlIGl0IHdhcyBub3QgYXNzaWduZWQgYW55IGNlbGwgdHlwZXMgKGFsbCBhcmUgYE5BYCkuCldlIHdpbGwgY29udGludWUgb3VyIGFuYWx5c2lzIG9ubHkgdXNpbmcgdGhlIDYgbGlicmFyaWVzIHdpdGggZnVsbHkgY2xhc3NpZmllZCBjZWxsIHR5cGVzLCByZW1vdmluZyB0aGUgb3RoZXIgNCBiZWZvcmUgd2UgcHJvY2VlZCB3aXRoIGRpZmZlcmVudGlhbCBleHByZXNzaW9uLgoKIyMjIEZpbHRlcmluZyBzYW1wbGVzCgpUaGUgcmVhc29uIHdlIHdhbnQgdG8gcGFyZSBkb3duIG91ciBsaXN0IG9mIHNhbXBsZXMgdG8gY29uc2lkZXIgaXMgdGhhdCB3ZSB3YW50IHRvIGVuc3VyZSB0aGF0IHRoZSBjZWxsIHR5cGVzIChvciBzdWJwb3B1bGF0aW9ucykgdGhhdCB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBhcmUgcHJlc2VudCBpbiBhbGwgc2FtcGxlcyBpbmNsdWRlZCBpbiBvdXIgREUgYW5hbHlzaXMuIApXZSB3YW50IHRvIHJlbW92ZSBhbnkgc2FtcGxlcyB0aGF0IGRvIG5vdCBjb250YWluIG91ciBjZWxsIHBvcHVsYXRpb24ocykgb2YgaW50ZXJlc3QgYXMgdGhleSBoYXZlIG5vIGNvdW50cyB0byBjb250cmlidXRlIHRvIHRoZSBERSBhbmFseXNpcy4KCmBgYHtyIHN1YnNldCBzY2V9CiMgZGVmaW5lIHNhbXBsZXMgdG8ga2VlcApsaWJyYXJ5X2lkcyA8LSBjKAogICJTQ1BDTDAwMDQ3OSIsCiAgIlNDUENMMDAwNDgwIiwKICAiU0NQQ0wwMDA0ODEiLAogICJTQ1BDTDAwMDQ4NCIsCiAgIlNDUENMMDAwNDg4IiwKICAiU0NQQ0wwMDA0OTEiCikKCiMgc3Vic2V0IHNjZSB0byBvbmx5IGNvbnRhaW4gc2FtcGxlcyBvZiBpbnRlcmVzdCAKc2FtcGxlc190b19rZWVwIDwtIGludGVncmF0ZWRfc2NlJHNhbXBsZSAlaW4lIGxpYnJhcnlfaWRzCnJtc19zY2UgPC0gaW50ZWdyYXRlZF9zY2VbLCBzYW1wbGVzX3RvX2tlZXBdCgojIHByaW50IG91dCBvdXIgbmV3IFNDRSAKcm1zX3NjZQpgYGAKCkJlZm9yZSB3ZSBtb3ZlIG9uLCB3ZSdsbCByZW1vdmUgdGhlIG9yaWdpbmFsIGludGVncmF0ZWQgb2JqZWN0IGZyb20gb3VyIGVudmlyb25tZW50IHRvIHNhdmUgc29tZSBtZW1vcnkuIAoKYGBge3IgcmVtb3ZlIHNjZX0Kcm0oaW50ZWdyYXRlZF9zY2UpCmBgYAoKV2Ugd2lsbCBhbHNvIHNhdmUgb3VyIG5ldyBvYmplY3QgaW4gY2FzZSB3ZSB3YW50IHRvIHVzZSBpdCBmb3Igb3RoZXIgYW5hbHlzaXMgbGF0ZXIgb24uCgpgYGB7ciBzYXZlIHNjZX0KIyB3cml0ZSBSRFMgZmlsZSB3aXRoIGNvbXByZXNzaW9uCnJlYWRyOjp3cml0ZV9yZHMocm1zX3NjZSwgZmlsZSA9IG91dHB1dF9zY2VfZmlsZSwgY29tcHJlc3MgPSAiZ3oiKQpgYGAKCldlIG5vdyBoYXZlIGFuIHVwZGF0ZWQgU0NFIG9iamVjdCB0aGF0IGNvbnRhaW5zIDYgc2FtcGxlcyB0aGF0IHdlcmUgb2J0YWluZWQgZnJvbSBhIG1peCBvZiBBUk1TIGFuZCBFUk1TIHBhdGllbnRzLgpXZSBjYW4gdGhlbiBhc2sgdGhlIHF1ZXN0aW9uLCBkbyBzcGVjaWZpYyB0dW1vciBjZWxsIHR5cGVzIGNvbnRhaW4gc2V0cyBvZiBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMgYmV0d2VlbiBBUk1TIGFuZCBFUk1TIHNhbXBsZXM/CgpXZSBzaG91bGQgbWFrZSBzdXJlIHRoYXQgd2UgaGF2ZSBlbm91Z2ggYmlvbG9naWNhbCByZXBsaWNhdGVzIGZyb20gZWFjaCBncm91cCB0byBzZXQgdXAgb3VyIGV4cGVyaW1lbnQuIApJdCBpcyBpbXBlcmF0aXZlIHRvIGNvbnNpZGVyIGdvb2QgZXhwZXJpbWVudGFsIGRlc2lnbiBhbmQgZW5zdXJlIHRoYXQgd2UgaGF2ZSBlbm91Z2ggYmlvbG9naWNhbCByZXBsaWNhdGVzIChhdCBsZWFzdCAzIGZvciBlYWNoIGdyb3VwKSB3aGVuIHBlcmZvcm1pbmcgZGlmZmVyZW50aWFsIGdlbmUgZXhwcmVzc2lvbiBhbmFseXNpcy4KCklmIHdlIGxvb2sgYmFjayBhdCBvdXIgc3RhY2tlZCBiYXJwbG90IHdlIHNlZSB0aGF0IHdlIHBpY2tlZCAzIEFSTVMgYW5kIDMgRVJNUyBzYW1wbGVzLgpXZSBjYW4gYWxzbyBzZWUgdGhhdCB0aGUgbWFqb3JpdHkgb2YgY2VsbHMgYXJlIHR1bW9yIGNlbGxzLCBpbiBwYXJ0aWN1bGFyIHRoZSBsYXJnZXN0IHBvcHVsYXRpb24gb2YgY2VsbHMgYXBwZWFycyB0byBiZSB0aGUgYFR1bW9yX015b2JsYXN0YC4gCkZvciB0aGlzIGV4YW1wbGUgd2Ugd2lsbCBmb2N1cyBvbiBpZGVudGlmeWluZyBERSBnZW5lcyBpbiB0aGVzZSBgVHVtb3JfTXlvYmxhc3RgIGNlbGxzLCBidXQgdGhlIHByaW5jaXBsZXMgYXBwbGllZCBiZWxvdyBjYW4gYmUgYXBwbGllZCB0byBhbnkgY2VsbCB0eXBlcyBvciBzdWJwb3B1bGF0aW9ucyBvZiBpbnRlcmVzdC4KCiMjIERpZmZlcmVudGlhbCBleHByZXNzaW9uIGFuYWx5c2lzCgpOb3cgd2UgYXJlIHJlYWR5IHRvIHN0YXJ0IHByZXBhcmluZyBmb3Igb3VyIERFIGFuYWx5c2lzLCB3aGVyZSB3ZSB3aWxsIGNvbXBhcmUgdGhlIGdlbmUgZXhwcmVzc2lvbiBvZiB0dW1vciBteW9ibGFzdCBjZWxscyBiZXR3ZWVuIEFSTVMgYW5kIEVSTVMgc2FtcGxlcy4KClRocm91Z2hvdXQgdGhlIG5vdGVib29rIHdlIGhhdmUgYmVlbiB3b3JraW5nIHdpdGggYW4gaW50ZWdyYXRlZCBkYXRhc2V0IHRoYXQgY29udGFpbnMgY29ycmVjdGVkIGdlbmUgZXhwcmVzc2lvbiBkYXRhIChgZmFzdG1ubl9jb3JyZWN0ZWRgIGFzc2F5KSBhbmQgYSBjb3JyZWN0ZWQgVU1BUC4KQXMgYSByZW1pbmRlciwgdGhlIHVuY29ycmVjdGVkIGdlbmUgZXhwcmVzc2lvbiBkYXRhLCBmb3VuZCBpbiB0aGUgYGNvdW50c2AgYW5kIGBsb2djb3VudHNgIGFzc2F5cywgY29ycmVzcG9uZCB0byBkYXRhIHRoYXQgaGFzIGJlZW4gbWVyZ2VkICh0aGUgZmlyc3Qgc3RlcCB3ZSB3YWxrZWQgdGhyb3VnaCBwcmlvciB0byBpbnRlZ3JhdGlvbikgaW50byB0aGUgc2FtZSBTQ0UgYnV0IG5vdCB5ZXQgaW50ZWdyYXRlZC4KV2UgZG8gbm90IHdhbnQgdG8gdXNlIGNvcnJlY3RlZCBnZW5lIGV4cHJlc3Npb24gdmFsdWVzIGZvciBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbjsgYERFU2VxMmAgZXhwZWN0cyB0aGUgb3JpZ2luYWwgcmF3IGNvdW50cyBhcyBpbnB1dCBzbyB3ZSB3aWxsIGJlIHVzaW5nIGRhdGEgZm91bmQgaW4gdGhlIGBjb3VudHNgIGFzc2F5IG9mIHRoZSBgU2luZ2xlQ2VsbEV4cGVyaW1lbnRgIG9iamVjdC4gCgpJdCBpcyBhZHZpc2VkIHRvIG9ubHkgdXNlIHRoZSBjb3JyZWN0ZWQgdmFsdWVzIGZvciBhbnkgYW5hbHlzZXMgYmVpbmcgcGVyZm9ybWVkIGF0IHRoZSBjZWxsIGxldmVsLCBlLmcuLCBkaW1lbnNpb25hbGl0eSByZWR1Y3Rpb24uCkluIGNvbnRyYXN0LCBpdCBpcyBub3QgYWR2aXNlZCB0byB1c2UgY29ycmVjdGVkIHZhbHVlcyBmb3IgYW55IGFuYWx5c2VzIHRoYXQgYXJlIGdlbmUtYmFzZWQsIHN1Y2ggYXMgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gb3IgbWFya2VyIGdlbmUgZGV0ZWN0aW9uLCBiZWNhdXNlIHdpdGhpbi1iYXRjaCBhbmQgYmV0d2Vlbi1iYXRjaCBnZW5lIGV4cHJlc3Npb24gZGlmZmVyZW5jZXMgYXJlIG5vIGxvbmdlciBwcmVzZXJ2ZWQuClRoZSByZWFzb24gZm9yIHRoaXMgaXMgdHdvLWZvbGQg4oCTIG1hbnkgb2YgdGhlIERFIG1vZGVscyB3aWxsIGV4cGVjdCB1bmNvcnJlY3RlZCBjb3VudHMgYmVjYXVzZSB0aGV5IHdpbGwgYWNjb3VudCBmb3IgYmV0d2Vlbi1zYW1wbGUgdmFyaWF0aW9uIHdpdGhpbiB0aGUgbW9kZWwsIGFuZCB3ZSB3YW50IHRvIGVuc3VyZSB3ZSBhcmUgcHJlc2VydmluZyB2YXJpYXRpb24gdGhhdCBpcyBwcmVzZW50IHNvIGFzIG5vdCB0byBhcnRpZmljaWFsbHkgaW5mbGF0ZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIHBvcHVsYXRpb25zLgpTZWUgdGhlIFtPU0NBIGNoYXB0ZXIgb24gVXNpbmcgdGhlIGNvcnJlY3RlZCB2YWx1ZXNdKGh0dHBzOi8vYmlvY29uZHVjdG9yLm9yZy9ib29rcy8zLjE2L09TQ0EubXVsdGlzYW1wbGUvdXNpbmctY29ycmVjdGVkLXZhbHVlcy5odG1sI3VzaW5nLWNvcnJlY3RlZC12YWx1ZXMpIGZvciBtb3JlIGluc2lnaHQuCgojIyMgUHNldWRvLWJ1bGtpbmcgCgpCZWZvcmUgd2UgY2FuIGNvbXBhcmUgdGhlIGdlbmUgZXhwcmVzc2lvbiBwcm9maWxlcyBvZiBteW9ibGFzdHMgaW4gQVJNUyB2cy4gRVJNUyBzYW1wbGVzLCB3ZSB3aWxsIG5lZWQgdG8gInBzZXVkby1idWxrIiB0aGUgZ2VuZSBjb3VudHMuIApQc2V1ZG8tYnVsa2luZyBjcmVhdGVzIGEgbmV3IGNvdW50cyBtYXRyaXggdGhhdCBjb250YWlucyB0aGUgc3VtIG9mIHRoZSBjb3VudHMgZnJvbSBhbGwgY2VsbHMgd2l0aCBhIGdpdmVuIGxhYmVsIChlLmcuLCBjZWxsIHR5cGUpIGZvciBlYWNoIHNhbXBsZSAoW1R1bmcgX2V0IGFsLl8gMjAxN10oaHR0cHM6Ly9kb2kub3JnLzEwLjEwMzgvc3JlcDM5OTIxKSkuIApJZiB3ZSB3ZXJlIHRvIGtlZXAgZWFjaCBjZWxsJ3MgY291bnRzIHNlcGFyYXRlLCB0aGV5IHdvdWxkIGJlIHRyZWF0ZWQgYXMgcmVwbGljYXRlcywgbGVhZGluZyB0byBpbmZsYXRlZCBzdGF0aXN0aWNzLiAKQnkgcHNldWRvLWJ1bGtpbmcgZmlyc3QsIHdlIHdpbGwgbm93IGhhdmUgb25lIGNvdW50IGZvciBlYWNoIGdlbmUgZm9yIGVhY2ggc2FtcGxlIGFuZCB3ZSBjYW4gdGFrZSBhZHZhbnRhZ2Ugb2Ygd2VsbC1lc3RhYmxpc2hlZCBtZXRob2RzIGZvciBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiB3aXRoIGJ1bGsgUk5BLXNlcS4KClBzZXVkby1idWxraW5nIGlzIGltcGxlbWVudGVkIHByaW9yIHRvIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGFuYWx5c2lzIG9uIHNpbmdsZS1jZWxsIGRhdGEgYmVjYXVzZSBpdDogCgotIFByb2R1Y2VzIGxhcmdlciBhbmQgbGVzcyBzcGFyc2UgY291bnRzLCB3aGljaCBhbGxvd3MgdXMgdG8gdXNlIHN0YW5kYXJkIG5vcm1hbGl6YXRpb24gYW5kIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIG1ldGhvZHMgdXNlZCBieSBidWxrIFJOQS1zZXEuIAotIENvbGxhcHNlcyBnZW5lIGV4cHJlc3Npb24gY291bnRzIGJ5IHNhbXBsZSwgc28gdGhhdCBzYW1wbGVzLCByYXRoZXIgdGhhbiBjZWxscywgcmVwcmVzZW50IHJlcGxpY2F0ZXMuCi0gTWFza3MgdmFyaWFuY2Ugd2l0aGluIGEgc2FtcGxlIHRvIGVtcGhhc2l6ZSB2YXJpYW5jZSBhY3Jvc3Mgc2FtcGxlcy4KVGhpcyBjYW4gYmUgYm90aCBnb29kIGFuZCBiYWQhIApNYXNraW5nIGludHJhLXNhbXBsZSB2YXJpYXRpb24gbWVhbnMgeW91IG1pZ2h0IG5vdCBpZGVudGlmeSBnZW5lcyB3aGVyZSBhdmVyYWdlIGV4cHJlc3Npb24gZG9lc24ndCBjaGFuZ2UgYmV0d2VlbiBzYW1wbGVzIGJ1dCB0aGUgZGVncmVlIG9mIGNlbGwtdG8tY2VsbCB2YXJpYXRpb24gZG9lcy4KCkJlZm9yZSB3ZSBhcHBseSBwc2V1ZG8tYnVsa2luZyB0byBvdXIgZGF0YXNldCwgbGV0J3MgbG9vayBhdCBhIHNpbXBsZSBleGFtcGxlIG9mIGhvdyBwc2V1ZG8tYnVsa2luZyB3b3Jrcy4KV2UnbGwgc3RhcnQgYnkgY3JlYXRpbmcgYSBmYWtlIG1hdHJpeCBvZiBjb3VudHMuCgpgYGB7ciBjcmVhdGUgbWF0cml4fQojIGNyZWF0ZSBhbiBleGFtcGxlIGNvdW50cyBtYXRyaXgKY291bnRzX210eCA8LSBtYXRyaXgoCiAgMToxMiwgCiAgbmNvbCA9IDQsCiAgZGltbmFtZXMgPSBsaXN0KGMoImdlbmVBIiwgImdlbmVCIiwgImdlbmVDIiksCiAgICAgICAgICAgICAgICAgIGMoIkEtY2VsbDEiLCAiQS1jZWxsMiIsICJCLWNlbGwxIiwgIkItY2VsbDIiKSkKKQpjb3VudHNfbXR4CmBgYAoKTmV4dCB3ZSB3aWxsIGNyZWF0ZSBhIHBzZXVkby1idWxrZWQgdmVyc2lvbiBvZiB0aGlzIG1hdHJpeCB3aXRoIG9ubHkgMiBjb2x1bW5zOiAxIGZvciBncm91cCBgQWAgYW5kIDEgZm9yIGdyb3VwIGBCYC4KVG8gZG8gdGhpcyB3ZSB3aWxsIHVzZSB0aGUgYERlbGF5ZWRBcnJheTo6Y29sc3VtKClgIGZ1bmN0aW9uLCB3aGljaCBhbGxvd3MgdXMgdG8gc3VtIHRoZSBjb3VudHMgZm9yIGVhY2ggcm93IGFjcm9zcyBncm91cHMgb2YgY29sdW1ucy4KCmBgYHtyIHBzZXVkb2J1bGsgbWF0cml4LCBsaXZlPVRSVUV9CiMgZGVmaW5lIHRoZSBncm91cCB0aGF0IGVhY2ggY29sdW1uIGJlbG9uZ3MgdG8KZ3JvdXBzIDwtIGMoIkEiLCAiQSIsICJCIiwgIkIiKQoKIyBzdW0gY291bnRzIGFjcm9zcyBjZWxscyAoY29sdW1ucykgYnkgZ3JvdXAgbGFiZWwKcGJfY291bnRzIDwtIERlbGF5ZWRBcnJheTo6Y29sc3VtKGNvdW50c19tdHgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBzKQpwYl9jb3VudHMgIApgYGAKCkxvb2tpbmcgYXQgdGhpcyBvdXRwdXQsIHlvdSBzaG91bGQgc2VlIHRoYXQgdGhlIG9yaWdpbmFsIDQgY29sdW1ucyBoYXZlIGJlZW4gY29uZGVuc2VkIHRvIG9ubHkgMiBjb2x1bW5zOiAxIGNvbHVtbiB0byByZXByZXNlbnQgYWxsIGNlbGxzIGZyb20gZ3JvdXAgYEFgLCBhbmQgMSBjb2x1bW4gdG8gcmVwcmVzZW50IGFsbCBjZWxscyBmcm9tIGdyb3VwIGBCYC4KCk5vdyB0aGUgYWN0dWFsIHBzZXVkby1idWxraW5nIGZvciBvdXIgZGF0YXNldCEgCgpXZSB3aWxsIHVzZSB0aGUgW2BzY3V0dGxlOjphZ2dyZWdhdGVBY3Jvc3NDZWxscygpYCBmdW5jdGlvbl0oaHR0cHM6Ly9yZHJyLmlvL2dpdGh1Yi9MVExBL3NjdXR0bGUvbWFuL2FnZ3JlZ2F0ZUFjcm9zc0NlbGxzLmh0bWwpIHRvIHBzZXVkby1idWxrIG91ciBkYXRhc2V0LgpUaGlzIGZ1bmN0aW9uIHRha2VzIGFzIGlucHV0IGFuIFNDRSBvYmplY3QgYW5kIHRoZSBncm91cGluZyBhc3NpZ25tZW50cyBmb3IgZWFjaCBjZWxsLgpUaGUgb3V0cHV0IHdpbGwgYmUgYW4gU0NFIG9iamVjdCB0aGF0IGNvbnRhaW5zIG9ubHkgdGhlIHBzZXVkby1idWxrZWQgY291bnRzIGZvciBhbGwgZ2VuZXMgYWNyb3NzIGFsbCBzcGVjaWZpZWQgZ3JvdXBzLCByYXRoZXIgdGhhbiBhY3Jvc3MgYWxsIGNlbGxzLiAKV2UgY2FuIHRoZW4gc3Vic2V0IHRoaXMgU0NFIHRvIGp1c3QgaW5jbHVkZSBvdXIgY2VsbCB0eXBlIG9mIGludGVyZXN0ICh0dW1vciBteW9ibGFzdHMpIGZvciBpbnB1dCB0byB0aGUgREUgYW5hbHlzaXMuIAoKV2UgY2FuIHBzZXVkby1idWxrIHVzaW5nIGFueSBncm91cGluZyB0aGF0IHdlIGFyZSBpbnRlcmVzdGVkIGluLgpGb3IgcmlnaHQgbm93LCB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBsb29raW5nIGF0IGdlbmUgZXhwcmVzc2lvbiBhY3Jvc3MgY2VsbCB0eXBlcywgc28gd2Ugd2FudCB0byBncm91cCB0aGUgcHNldWRvLWJ1bGtlZCBjb3VudHMgbWF0cml4IGJ5IGJvdGggY2VsbCB0eXBlIGFuZCBvcmlnaW5hbCBzYW1wbGUuIAoKYGBge3IgcHNldWRvYnVsayBzY2V9CiMgZmlyc3Qgc3Vic2V0IHRoZSBjb2xkYXRhIAojIHRvIG9ubHkgaGF2ZSB0aGUgY29sdW1ucyB3ZSBjYXJlIGFib3V0IGZvciBwc2V1ZG8tYnVsa2luZyAKcGJfZ3JvdXBzIDwtIGNvbERhdGEocm1zX3NjZSlbLCBjKCJjZWxsdHlwZV9icm9hZCIsICJzYW1wbGUiKV0KCiMgY3JlYXRlIGEgbmV3IFNDRSBvYmplY3QgdGhhdCBjb250YWlucyAKIyB0aGUgcHNldWRvLWJ1bGtlZCBjb3VudHMgYWNyb3NzIHRoZSBwcm92aWRlZCBncm91cHMgCnBiX3NjZSA8LSBzY3V0dGxlOjphZ2dyZWdhdGVBY3Jvc3NDZWxscyhybXNfc2NlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlkID0gcGJfZ3JvdXBzKQoKIyBjb2x1bW4gbmFtZXMgYXJlbid0IGF1dG9tYXRpY2FsbHkgYWRkZWQgdG8gdGhlIHBzZXVkby1idWxrZWQgc2NlLCAKIyBzbyBsZXQncyBhZGQgdGhlbSBpbiAKY29sbmFtZXMocGJfc2NlKSA8LSBnbHVlOjpnbHVlKAogICJ7cGJfc2NlJGNlbGx0eXBlX2Jyb2FkfV97cGJfc2NlJHNhbXBsZX0iCikKCnBiX3NjZQpgYGAKCkhvdyBkb2VzIHRoZSBuZXcgcHNldWRvLWJ1bGtlZCBgU2luZ2xlQ2VsbEV4cGVyaW1lbnRgIGxvb2sgZGlmZmVyZW50PyAKSG93IG1hbnkgY29sdW1ucyBkb2VzIGl0IGhhdmU/IAoKTGV0J3MgdGFrZSBhIGxvb2sgYXQgd2hhdCB0aGUgYGNvbERhdGFgIGxvb2tzIGxpa2UgaW4gdGhlIHBzZXVkby1idWxrZWQgU0NFIG9iamVjdC4gCgpgYGB7ciBwc2V1ZG9idWxrIGNvbERhdGEsIGxpdmU9VFJVRX0KIyBub3RlIHRoZSBuZXcgY29sdW1uIHdpdGggbnVtYmVyIG9mIGNlbGxzIHBlciBncm91cCAKaGVhZChjb2xEYXRhKHBiX3NjZSkpIHw+CiAgYXMuZGF0YS5mcmFtZSgpCmBgYAoKWW91IHNob3VsZCBzZWUgdGhhdCBjb2x1bW5zIHN1Y2ggYXMgYHN1bWAsIGBkZXRlY3RlZGAsIGBzdWJzZXRzX21pdG9fc3VtYCwgYW5kIG90aGVyIGNvbHVtbnMgdGhhdCB0eXBpY2FsbHkgY29udGFpbiBwZXIgY2VsbCBRQyBzdGF0aXN0aWNzIG5vdyBjb250YWluIGBOQWAgcmF0aGVyIHRoYW4gbnVtZXJpYyB2YWx1ZXMuIApUaGlzIGlzIGJlY2F1c2UgdGhlc2UgdmFsdWVzIHdlcmUgaW5pdGlhbGx5IGNhbGN1bGF0ZWQgb24gYSBwZXIgY2VsbCBsZXZlbCAod2UgZGlkIHRoaXMgdXNpbmcgYHNjdXR0bGU6OmFkZFBlckNlbGxRQ01ldHJpY3MoKWApLCBidXQgd2Ugbm8gbG9uZ2VyIGhhdmUgYSBzaW5nbGUgY29sdW1uIHBlciBjZWxsLgpJbnN0ZWFkLCBlYWNoIGNvbHVtbiBub3cgcmVwcmVzZW50cyBhIF9ncm91cF8gb2YgY2VsbHMsIGluIHRoaXMgY2FzZSBjb21wcmlzZWQgb2YgY2VsbHMgb2YgYSBnaXZlbiBjZWxsIHR5cGUgYW5kIHNhbXBsZSBjb21iaW5hdGlvbi4KVGhlcmVmb3JlLCB0aGUgdmFsdWVzIHRoYXQgd2UgY2FsY3VsYXRlZCBvbiBhIHBlci1jZWxsIGxldmVsIGFyZSBubyBsb25nZXIgYXBwbGljYWJsZSB0byB0aGlzIHBzZXVkby1idWxrZWQgU0NFIG9iamVjdC4KCllvdSBzaG91bGQgYWxzbyBzZWUgYSBuZXcgY29sdW1uIHRoYXQgd2Fzbid0IHByZXNlbnQgcHJldmlvdXNseSwgdGhlIGBuY2VsbHNgIGNvbHVtbi4KVGhpcyBjb2x1bW4gd2FzIGFkZGVkIGR1cmluZyBwc2V1ZG8tYnVsa2luZyBhbmQgaW5kaWNhdGVzIHRoZSB0b3RhbCBudW1iZXIgb2YgY2VsbHMgdGhhdCB3ZXJlIHN1bW1lZCB0b2dldGhlciB0byBmb3JtIGVhY2ggY29sdW1uIG9mIHRoZSBTQ0Ugb2JqZWN0LgoKQmVmb3JlIHdlIHByb2NlZWQgd2Ugd2lsbCB3YW50IHRvIGZpbHRlciBvdXQgYW55IGNvbHVtbnMgdGhhdCBoYXZlIGEgbG93IG51bWJlciBvZiBjZWxscy4KQSBsb3cgbnVtYmVyIG9mIGNlbGxzIHdpbGwgdXN1YWxseSByZXN1bHQgaW4gc21hbGwgY291bnRzIHRoYXQgY2FuIGNhdXNlIGlzc3VlcyB3aXRoIHRoZSBzdGF0aXN0aWNhbCBhcHByb3hpbWF0aW9ucyBtYWRlIGR1cmluZyBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcy4KVGhpcyBpcyBlcXVpdmFsZW50IHRvIGZpbHRlcmluZyBvdXQgYW55IGxpYnJhcmllcyBpbiBidWxrIFJOQS1zZXEgYW5hbHlzaXMgdGhhdCBoYXZlIGxvdyBsaWJyYXJ5IHNpemVzLgoKV2UgY2FuIHNldCBhIHRocmVzaG9sZCBmb3IgdGhlIG51bWJlciBvZiBjZWxscyByZXF1aXJlZCB0byBjb250aW51ZSB3aXRoIG91ciBhbmFseXNpcyBhbmQgcmVtb3ZlIGFueSBncm91cHMgdGhhdCBkbyBub3QgbWVldCB0aGUgbWluaW11bSB0aHJlc2hvbGQuCkhlcmUgd2Ugd2lsbCB1c2UgMTAsIGJ1dCB0aGUgdGhyZXNob2xkIHlvdSB1c2UgZm9yIHlvdXIgZGF0YXNldCBjYW4gdmFyeSBkZXBlbmRpbmcgb24gdGhlIGNvbXBvc2l0aW9uIG9mIGNlbGwgdHlwZXMuCgpgYGB7ciBmaWx0ZXIgcHNldWRvYnVsaywgbGl2ZT1UUlVFfQojIHJlbW92ZSBhbnkgZ3JvdXBzIHdpdGggZmV3ZXIgdGhhbiAxMCBjZWxscwpmaWx0ZXJfcGJfc2NlIDwtIHBiX3NjZVssIHBiX3NjZSRuY2VsbHMgPj0gMTBdCmBgYAoKV2UgY2FuIHRoZW4gdGFrZSBhIGxvb2sgYW5kIHNlZSBob3cgbWFueSBjZWxsIHR5cGUtc2FtcGxlIGNvbHVtbnMgd2UgcmVtb3ZlZCwgaWYgYW55LgoKYGBge3IgcHJpbnQgZGltLCBsaXZlPVRSVUV9CiMgcHJpbnQgb3V0IGRpbWVuc2lvbnMgb2YgdW5maWx0ZXJlZCBwc2V1ZG9idWxrIHNjZQpkaW0ocGJfc2NlKQoKIyBkaW1lbnNpb25zIG9mIGZpbHRlcmVkIHBzZXVkb2J1bGsgc2NlIApkaW0oZmlsdGVyX3BiX3NjZSkKYGBgCgpJdCBsb29rcyBsaWtlIHdlIG9ubHkgZ290IHJpZCBvZiBvbmUgZ3JvdXAuCldlIGNhbiBkbyBhIHF1aWNrIGNoZWNrIHRvIHNlZSB3aGljaCBncm91cCB3YXMgcmVtb3ZlZCBieSBmaW5kaW5nIHdoaWNoIGNvbHVtbiBpcyBubyBsb25nZXIgcHJlc2VudCBpbiB0aGUgZmlsdGVyZWQgb2JqZWN0LgoKYGBge3IgcmVtb3ZlZCBjb2x1bW5zLCBsaXZlPVRSVUV9CiMgZmluZCByZW1vdmVkIGNvbHVtbnMKcmVtb3ZlZF9jb2xzIDwtICEoY29sbmFtZXMocGJfc2NlKSAlaW4lIGNvbG5hbWVzKGZpbHRlcl9wYl9zY2UpKQoKIyBwcmludCBvdXQgbWlzc2luZyBjb2x1bW5zCmNvbG5hbWVzKHBiX3NjZSlbcmVtb3ZlZF9jb2xzXQpgYGAKClRoZSBsYXN0IHN0ZXAgd2Ugd2FudCB0byBkbyB0byBwcmVwYXJlIG91ciBkYXRhc2V0IGZvciBERSBpcyB0byBzdWJzZXQgdGhlIHBzZXVkby1idWxrZWQgU0NFIG9iamVjdCB0byBjb250YWluIG9ubHkgdGhlIGNlbGwgdHlwZSB0aGF0IHdlIGFyZSBpbnRlcmVzdGVkIGluIGNvbXBhcmluZyBhY3Jvc3MgdGhlIHR3byBSTVMgc3VidHlwZXMuCkFzIG1lbnRpb25lZCBwcmV2aW91c2x5LCB3ZSBhcmUgc3BlY2lmaWNhbGx5IGludGVyZXN0ZWQgaW4gdGhlIGBUdW1vcl9NeW9ibGFzdGAgY2VsbCB0eXBlLgoKYGBge3IgZmlsdGVyIGNlbGx0eXBlfQojIGxvZ2ljYWwgdmVjdG9yIGluZGljYXRpbmcgaWYgY2VsbHMgYXJlIHR1bW9yIG15b2JsYXN0IG9yIG5vdApteW9ibGFzdF9jZWxscyA8LSBmaWx0ZXJfcGJfc2NlJGNlbGx0eXBlX2Jyb2FkID09ICJUdW1vcl9NeW9ibGFzdCIKCiMgY3JlYXRlIGEgbmV3IHNjZSB3aXRoIG9ubHkgdGhlIHR1bW9yIG15b2JsYXN0cwp0dW1vcl9teW9ibGFzdF9zY2UgPC0gZmlsdGVyX3BiX3NjZVssIG15b2JsYXN0X2NlbGxzXQpgYGAKCkFmdGVyIGZpbHRlcmluZyBmb3Igb3VyIGNlbGwgdHlwZSBvZiBpbnRlcmVzdCB3ZSBzaG91bGQgaGF2ZSBhIGRhdGFzZXQgd2l0aCA2IGNvbHVtbnMsIDEgZm9yIGVhY2ggZ3JvdXAgb2YgYFR1bW9yX015b2JsYXN0YCBjZWxscyBpbiBlYWNoIG9mIG91ciA2IHNhbXBsZXMuCgojIyMgUGVyZm9ybSBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiB3aXRoIGBERVNlcTJgCgpOb3cgd2Ugd2lsbCB1c2UgdGhlIGBERVNlcTJgIHBhY2thZ2UgdG8gcGVyZm9ybSBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiAoREUpIGFuYWx5c2lzIG9uIG91ciBwc2V1ZG8tYnVsa2VkIFNDRSBvYmplY3QuCkZyb20gdGhpcyBwb2ludCwgd2UgY2FuIHByb2NlZWQgaW4gdGhlIHNhbWUgd2F5IHdlIHdvdWxkIGlmIHdlIGhhZCBhIGJ1bGsgUk5BLXNlcSBkYXRhc2V0IHdpdGggNiBzYW1wbGVzLgpXZSB3aWxsIHN0YXJ0IHdpdGggdGhlIHVubm9ybWFsaXplZCByYXcgY291bnRzIGluIHRoZSBgY291bnRzYCBhc3NheSBvZiB0aGUgcHNldWRvLWJ1bGtlZCBTQ0UgYW5kIGRvIHRoZSBmb2xsb3dpbmcgd2l0aCBgREVTZXEyYDoKCi0gQ3JlYXRlIGEgYERFU2VxRGF0YVNldGAgb2JqZWN0Ci0gTm9ybWFsaXplIGFuZCBsb2cgdHJhbnNmb3JtIHRoZSBjb3VudHMgZGF0YQotIEVzdGltYXRlIGRpc3BlcnNpb25zIGFuZCBzaHJpbmsgZXN0aW1hdGVzCi0gRml0IGEgbmVnYXRpdmUgYmlub21pYWwgbW9kZWwgYW5kIHBlcmZvcm0gaHlwb3RoZXNpcyB0ZXN0aW5nIHVzaW5nIFdhbGQgc3RhdGlzdGljcwoKWW91IGNhbiBhbHNvIHJlZmVyIHRvIG91ciBbbWF0ZXJpYWxzIGZyb20gb3VyIHByZXZpb3VzIHdvcmtzaG9wcyBjb3ZlcmluZyBidWxrIFJOQS1zZXFdKGh0dHBzOi8vZ2l0aHViLmNvbS9BbGV4c0xlbW9uYWRlL3RyYWluaW5nLW1vZHVsZXMvdHJlZS9tYXN0ZXIvUk5BLXNlcSNyZWFkbWUpIGZvciBtb3JlIGluZm9ybWF0aW9uIG9uIHVzaW5nIGBERVNlcWAuCgojIyMjIENyZWF0ZSB0aGUgYERFU2VxRGF0YVNldGAgb2JqZWN0CgpUbyBjcmVhdGUgdGhlIGBERVNlcURhdGFTZXRgIG9iamVjdCB3ZSB3aWxsIG5lZWQgdGhlIHVubm9ybWFsaXplZCBjb3VudHMgbWF0cml4LCB0aGUgbWV0YWRhdGEgYXNzb2NpYXRlZCB3aXRoIHRoZSBzYW1wbGVzLCBhbmQgYSBkZXNpZ24gZm9ybXVsYS4KVGhlIGZpcnN0IHR3byBpdGVtcyBhcmUgYWxyZWFkeSBzdG9yZWQgaW4gb3VyIFNDRSBvYmplY3QsIHNvIHdlIGNhbiBjcmVhdGUgYSBgREVTZXFEYXRhU2V0YCBvYmplY3QgZGlyZWN0bHkgZnJvbSB0aGF0IG9iamVjdCB1c2luZyB0aGUgYERFU2VxRGF0YVNldCgpYCBmdW5jdGlvbi4KVGhlIGRlc2lnbiBmb3JtdWxhIGlzIHVzZWQgdG8gaW5kaWNhdGUgd2hpY2ggY29sdW1ucyBvZiB0aGUgbWV0YWRhdGEgbmVlZCB0byBiZSBjb25zaWRlcmVkIGluIHRoZSBERSBjb21wYXJpc29uLgpGb3Igb3VyIGV4cGVyaW1lbnQgd2UgYXJlIGNvbXBhcmluZyBnZW5lIGV4cHJlc3Npb24gYmV0d2VlbiBkaWZmZXJlbnQgUk1TIHN1YnR5cGVzLgpUaGUgc3VidHlwZSBpbmZvcm1hdGlvbiBpcyBzdG9yZWQgaW4gdGhlIGBkaWFnbm9zaXNfZ3JvdXBgIGNvbHVtbiBvZiB0aGUgYGNvbERhdGFgIGluIHRoZSBwc2V1ZG8tYnVsa2VkIFNDRS4KCmBgYHtyIGRlc2VxIG9iamVjdCwgbGl2ZT1UUlVFfQojIHNldCB1cCB0aGUgZGVzZXEgb2JqZWN0LCBncm91cCBieSBkaWFnbm9zaXMKZGVzZXFfb2JqZWN0IDwtIERFU2VxMjo6REVTZXFEYXRhU2V0KHR1bW9yX215b2JsYXN0X3NjZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbiA9IH4gZGlhZ25vc2lzX2dyb3VwKQpgYGAKClRoZSBwc2V1ZG8tYnVsa2VkIFNDRSBvYmplY3QgY29udGFpbnMgb25seSBvbmUgYXNzYXk6IHRoZSBgY291bnRzYCBhc3NheS4KVGhpcyBpcyBiZWNhdXNlIGBERVNlcTJgIGV4cGVjdHMgcmF3IGNvdW50cy4KV2hlbiB3ZSBydW4gYERFU2VxMmAgb24gb3VyIGRhdGFzZXQsIHJhdyBjb3VudHMgd2lsbCBmaXJzdCBiZSBub3JtYWxpemVkIHVzaW5nIHNpemUgZmFjdG9ycyB0byBhY2NvdW50IGZvciBkaWZmZXJlbmNlcyBpbiB0b3RhbCBzYW1wbGUgY291bnRzLgpUaGVyZWZvcmUgd2UgZG9uJ3QgaGF2ZSB0byBkbyBhbnkgbm9ybWFsaXphdGlvbiBvbiBvdXIgb3duIOKAkyB3ZSdsbCBsZXQgYERFU2VxMmAgZG8gYWxsIHRoZSB3b3JrIGZvciB1cy4KCkhvd2V2ZXIsIGJlZm9yZSB3ZSBkaXZlIGludG8gREUgYW5hbHlzaXMsIHdlIGNhbiBkbyBzb21lIGluaXRpYWwgZXhwbG9yYXRpb24gYW5kIHZpc3VhbGl6YXRpb24gb2Ygb3VyIGRhdGEgdG8gc2VlIGlmIG91ciBzYW1wbGVzIHNlcGFyYXRlIGJ5IG91ciBrbm93biBmYWN0b3Igb2YgaW50ZXJlc3QsIFJNUyBzdWJ0eXBlLgpJbiBwYXJ0aWN1bGFyLCB3ZSBjYW4gdXNlIHByaW5jaXBhbCBjb21wb25lbnQgYW5hbHlzaXMgKFBDQSkgb2Ygb3VyIHBzZXVkby1idWxrZWQgZGF0YXNldCB0byB2aXN1YWxpemUgYW55IHZhcmlhdGlvbiBiZXR3ZWVuIHNhbXBsZXMuCklmIHRoZXJlIGlzIHZhcmlhdGlvbiBiZXR3ZWVuIFJNUyBzdWJ0eXBlcywgd2UgZXhwZWN0IHRoZWlyIHJlc3BlY3RpdmUgc2FtcGxlcyB0byBzZXBhcmF0ZSBpbiBQQyBzcGFjZSwgbGlrZWx5IGluZGljYXRpbmcgcHJlc2VuY2Ugb2YgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzLgpXZSBjYW4gZXZhbHVhdGUgdGhpcyBieSBwbG90dGluZyBQQzEgYW5kIFBDMi4KCkluIG9yZGVyIHRvIGNyZWF0ZSBvdXIgUENBIHBsb3QsIHdlIHdpbGwgZmlyc3QgbmVlZCB0byBub3JtYWxpemUgb3VyIGRhdGEgdG8gYWNjb3VudCBmb3IgYW55IHRlY2huaWNhbCB2YXJpYXRpb25zIGFjcm9zcyBzYW1wbGVzLgpBcyBhIHJlbWluZGVyLCB0aGlzIGlzIE5PVCByZXF1aXJlZCBmb3IgcnVubmluZyBgREVTZXEyYCBhbmFseXNpczsgd2UgYXJlIGp1c3QgdXNpbmcgaXQgdG8gdmlzdWFsaXplIG91ciBkYXRhIHByaW9yIHRvIERFIGFuYWx5c2lzLgoKYGBge3Igbm9ybWFsaXplfQojIGVzdGltYXRlIHNpemUgZmFjdG9ycyBmaXJzdApkZXNlcV9vYmplY3QgPC0gREVTZXEyOjplc3RpbWF0ZVNpemVGYWN0b3JzKGRlc2VxX29iamVjdCkKCiMgbm9ybWFsaXplIGFuZCBsb2cgdHJhbnNmb3JtIHRvIHVzZSBmb3IgdmlzdWFsaXphdGlvbgpub3JtYWxpemVkX29iamVjdCA8LSBERVNlcTI6OnJsb2coZGVzZXFfb2JqZWN0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJsaW5kID0gVFJVRSkKbm9ybWFsaXplZF9vYmplY3QKYGBgCgpXZSBub3cgaGF2ZSBhIG5vcm1hbGl6ZWQgYW5kIHRyYW5zZm9ybWVkIG9iamVjdCB0aGF0IGNhbiBiZSBkaXJlY3RseSBpbnB1dCB0byB0aGUgYERFU2VxMjo6cGxvdFBDQSgpYCBmdW5jdGlvbiwgd2hpY2ggd2lsbCBib3RoIGNhbGN1bGF0ZSBhbmQgcGxvdCB0aGUgUEMgcmVzdWx0cy4KCmBgYHtyIHBsb3RQQ0EsIGxpdmU9VFJVRX0KREVTZXEyOjpwbG90UENBKG5vcm1hbGl6ZWRfb2JqZWN0LCBpbnRncm91cCA9ICJkaWFnbm9zaXNfZ3JvdXAiKQpgYGAKCkFzIGV4cGVjdGVkIHdlIHNlZSB0aGF0IHNhbXBsZXMgZ3JvdXAgdG9nZXRoZXIgYmFzZWQgb24gUk1TIHN1YnR5cGUgYW5kIGFyZSBzZXBhcmF0ZWQgYWxvbmcgdGhlIFBDMSBheGlzLCB0aGUgUEMgY29udHJpYnV0aW5nIHRoZSBoaWdoZXN0IGFtb3VudCBvZiB2YXJpYXRpb24uCgojIyMjIFJ1biBgREVTZXFgCgpXZSdsbCBub3cgdXNlIHRoZSBjb252ZW5pZW5jZSBmdW5jdGlvbiBgREVTZXEoKWAgdG8gcGVyZm9ybSBvdXIgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMuClRoaXMgZnVuY3Rpb24gY2FsY3VsYXRlcyBub3JtYWxpemF0aW9uIGZhY3RvcnMsIGVzdGltYXRlcyBnZW5lLXdpc2UgZGlzcGVyc2lvbnMsIGZpdHMgYSBuZWdhdGl2ZSBiaW5vbWlhbCBtb2RlbCBhbmQgcGVyZm9ybXMgaHlwb3RoZXNpcyB0ZXN0aW5nIHVzaW5nIFdhbGQgc3RhdGlzdGljcy4KCmBgYHtyIGRlc2VxLCBsaXZlPVRSVUV9CiMgcnVuIERFU2VxCmRlc2VxX29iamVjdCA8LSBERVNlcTI6OkRFU2VxKGRlc2VxX29iamVjdCkKYGBgCgpXZSBjYW4gZXZhbHVhdGUgaG93IHdlbGwgdGhlIG1vZGVsIGZpdCBvdXIgZGF0YSBieSBsb29raW5nIGF0IHRoZSBkaXNwZXJzaW9uIGVzdGltYXRlcy4KV2UgZXhwZWN0IHRvIHNlZSB0aGUgZGlzcGVyc2lvbiBlc3RpbWF0ZXMgZGVjcmVhc2UgYXMgbWVhbnMgYXJlIGluY3JlYXNpbmcgYW5kIGZvbGxvdyB0aGUgbGluZSBvZiBiZXN0IGZpdC4gCgpgYGB7ciBwbG90IGRpc3BlcnNpb24sIGxpdmU9VFJVRX0KcGxvdERpc3BFc3RzKGRlc2VxX29iamVjdCkKYGBgCgpOb3cgd2UgY2FuIGV4dHJhY3QgdGhlIHJlc3VsdHMgZnJvbSB0aGUgb2JqZWN0LCBzcGVjaWZ5aW5nIHRoZSBwLXZhbHVlIHRocmVzaG9sZCB0aGF0IHdlIHdvdWxkIGxpa2UgdG8gdXNlLgoKYGBge3IgcmVzdWx0cywgbGl2ZT1UUlVFfQojIGV4dHJhY3QgdGhlIHJlc3VsdHMgYXMgYSBEYXRhRnJhbWUKZGVzZXFfcmVzdWx0cyA8LSBERVNlcTI6OnJlc3VsdHMoZGVzZXFfb2JqZWN0LCBhbHBoYSA9IDAuMDUpCmBgYAoKQnV0IHdlIGFyZW4ndCBkb25lIHlldCEKClRoZSBlc3RpbWF0ZXMgb2YgbG9nMiBmb2xkIGNoYW5nZSBjYWxjdWxhdGVkIGJ5IGBERVNlcSgpYCBhcmUgbm90IGNvcnJlY3RlZCBmb3IgZXhwcmVzc2lvbiBsZXZlbC4KVGhpcyBtZWFucyB0aGF0IHdoZW4gY291bnRzIGFyZSBzbWFsbCwgd2UgYXJlIGxpa2VseSB0byBlbmQgdXAgd2l0aCBzb21lIGxhcmdlIGZvbGQgY2hhbmdlIHZhbHVlcyB0aGF0IG92ZXJlc3RpbWF0ZSB0aGUgdHJ1ZSBleHRlbnQgb2YgdGhlIGNoYW5nZSBiZXR3ZWVuIGNvbmRpdGlvbnMuCgpXZSBjYW4gY29ycmVjdCB0aGlzIGJ5IGFwcGx5aW5nIGEgInNocmlua2FnZSIgcHJvY2VkdXJlLCB3aGljaCB3aWxsIGFkanVzdCBsYXJnZSB2YWx1ZXMgd2l0aCBzbWFsbCBjb3VudHMgZG93bndhcmQsIHdoaWxlIHByZXNlcnZpbmcgdmFsdWVzIHdpdGggbGFyZ2VyIGNvdW50cywgd2hpY2ggYXJlIGxpa2VseSB0byBiZSBtb3JlIGFjY3VyYXRlLgoKVG8gZG8gdGhpcywgd2Ugd2lsbCB1c2UgdGhlIGBsZmNTaHJpbmsoKWAgZnVuY3Rpb24sIGJ1dCBmaXJzdCB3ZSBuZWVkIHRvIGtub3cgdGhlIG5hbWUgYW5kL29yIHBvc2l0aW9uIG9mIHRoZSAiY29lZmZpY2llbnQiIHRoYXQgd2FzIGNhbGN1bGF0ZWQgYnkgYERFU2VxKClgLCB3aGljaCB3ZSBjYW4gZG8gd2l0aCB0aGUgYHJlc3VsdHNOYW1lcygpYCBmdW5jdGlvbi4KCmBgYHtyIGNvZWZmaWNpZW50LCBsaXZlPVRSVUV9CiMgaWRlbnRpZnkgcG9zaXRpb24gb2YgY29lZmZpY2llbnQKREVTZXEyOjpyZXN1bHRzTmFtZXMoZGVzZXFfb2JqZWN0KQpgYGAKCgpgYGB7ciBzaHJpbmthZ2V9CiMgYXBweWx5IGxvZ0ZDIHNocmlua2FnZSB1c2luZyB0aGUgZGVmYXVsdCBtb2RlbApzaHJpbmtfcmVzdWx0cyA8LSBERVNlcTI6OmxmY1NocmluaygKICBkZXNlcV9vYmplY3QsIAogIHJlcyA9IGRlc2VxX3Jlc3VsdHMsIAogIGNvZWYgPSAyLAogIHR5cGUgPSAiYXBlZ2xtIgopCmhlYWQoc2hyaW5rX3Jlc3VsdHMpCmBgYAoKSWYgeW91IGxvb2sgYXQgb3VyIGBzaHJpbmtfcmVzdWx0c2Agb2JqZWN0LCB3ZSBzZWUgdGhhdCB0aGUgZ2VuZXMgYXJlIGxhYmVsZWQgd2l0aCB0aGUgRW5zZW1ibCBnZW5lIGlkZW50aWZpZXJzLCBhcyB0aG9zZSB3ZXJlIHRoZSByb3cgbmFtZXMgb2YgdGhlIHBzZXVkby1idWxrZWQgU0NFIHdlIHVzZWQgYXMgaW5wdXQgdG8gYnVpbGQgb3VyIGBERVNlcTJgIG9iamVjdC4KQWx0aG91Z2ggc29tZSBvZiB1cyBtYXkgaGF2ZSBhbGwgb2YgdGhlIGlkZW50aWZpZXJzIG1lbW9yaXplZCBieSBoZWFydCwgaXQgY2FuIGJlIHVzZWZ1bCB0byBoYXZlIGEgaHVtYW4gcmVhZGFibGUgc3ltYm9sIGluIG91ciByZXN1bHRzLgpCZWZvcmUgd2Ugc2F2ZSB0aGUgcmVzdWx0cyBhcyBhIGZpbGUsIHdlIHdpbGwgZ3JhYiB0aGUgZ2VuZSBzeW1ib2xzIGZyb20gdGhlIGByb3dEYXRhYCBvZiBvdXIgb3JpZ2luYWwgU0NFIG9iamVjdCBhbmQgYWRkIHRoZW0gYXMgYSBuZXcgY29sdW1uLgoKYGBge3IgYWRkIGdlbmUgc3ltYm9sfQpkZXNlcV9yZXN1bHRzIDwtIHNocmlua19yZXN1bHRzIHw+CiAgIyBkaXJlY3RseSBhZGQgRW5zZW1ibCBpZCBhcyBhIGNvbHVtbgogICMgY29udmVydGluZyByZXN1bHRzIGludG8gYSBkYXRhIGZyYW1lCiAgdGliYmxlOjphc190aWJibGUocm93bmFtZXMgPSAiZW5zZW1ibF9pZCIpCgojIGNvbnZlcnQgcm93ZGF0YSB0byBkYXRhIGZyYW1lIApzY2Vfcm93ZGF0YV9kZiA8LSByb3dEYXRhKHR1bW9yX215b2JsYXN0X3NjZSkgfD4KICAjIGNyZWF0ZSBhIGNvbHVtbiB3aXRoIHJvd25hbWVzIHN0b3JlZCBhcyBlbnNlbWJsIGlkCiAgIyB1c2UgZm9yIGpvaW5pbmcgd2l0aCBkZXNlcSByZXN1bHRzCiAgdGliYmxlOjphc190aWJibGUocm93bmFtZXMgPSAiZW5zZW1ibF9pZCIpCgojIGNvbWJpbmUgZGVzZXEgcmVzdWx0cyB3aXRoIHJvd2RhdGEgYnkgZW5zZW1ibCBpZCAKZGVzZXFfcmVzdWx0cyA8LSBkZXNlcV9yZXN1bHRzIHw+CiAgZHBseXI6OmxlZnRfam9pbihzY2Vfcm93ZGF0YV9kZiwgYnkgPSAiZW5zZW1ibF9pZCIpCgpoZWFkKGRlc2VxX3Jlc3VsdHMpCmBgYAoKV2UgY2FuIHNhdmUgdGhlIG5ldyBkYXRhIGZyYW1lIHRoYXQgd2UgaGF2ZSBjcmVhdGVkIHdpdGggdGhlIEVuc2VtYmwgaWRlbnRpZmllcnMsIGdlbmUgc3ltYm9scywgYW5kIHRoZSBgREVTZXEyYCByZXN1bHRzIGFzIGEgdGFiIHNlcGFyYXRlZCAoYHRzdmApIGZpbGUuCgpgYGB7ciBzYXZlIGRlc2VxLCBsaXZlPVRSVUV9CiMgc2F2ZSBvdXIgcmVzdWx0cyBhcyB0c3YKcmVhZHI6OndyaXRlX3RzdihkZXNlcV9yZXN1bHRzLCBkZXNlcV9vdXRwdXRfZmlsZSkKYGBgCgpUaGUgbGFzdCB0aGluZyB0aGF0IHdlIHdpbGwgZG8gaXMgdGFrZSBhIGxvb2sgYXQgaG93IG1hbnkgZ2VuZXMgYXJlIHNpZ25pZmljYW50LgpIZXJlIHdlIHdpbGwgd2FudCB0byB1c2UgdGhlIGFkanVzdGVkIHAtdmFsdWUsIGZvdW5kIGluIHRoZSBgcGFkamAgY29sdW1uIG9mIHRoZSByZXN1bHRzLCBhcyB0aGlzIGFjY291bnRzIGZvciBtdWx0aXBsZSB0ZXN0IGNvcnJlY3Rpb24uCgpgYGB7ciBzaWduaWZpY2FudCByZXN1bHRzLCBsaXZlPVRSVUV9CiMgZmlyc3QgbG9vayBhdCB0aGUgc2lnbmlmaWNhbnQgcmVzdWx0cyAKZGVzZXFfcmVzdWx0c19zaWcgPC0gZGVzZXFfcmVzdWx0cyB8PgogICMgZmlsdGVyIGJhc2VkIG9uIGFkanVzdGVkIHB2YWx1ZQogIGRwbHlyOjpmaWx0ZXIocGFkaiA8PSAwLjA1KQoKaGVhZChkZXNlcV9yZXN1bHRzX3NpZykKYGBgCgoKIyMjIEV4cGxvcmluZyB0aGUgaWRlbnRpZmllZCBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMgCgpOb3cgdGhhdCB3ZSBoYXZlIGlkZW50aWZpZWQgYSBzZXQgb2YgZ2VuZXMgdGhhdCBhcmUgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGluIHRoZSB0dW1vciBteW9ibGFzdHMgYmV0d2VlbiBBUk1TIGFuZCBFUk1TIHN1YnR5cGVzLCBsZXRzIGFjdHVhbGx5IHRha2UgYSBsb29rIGF0IHRoZW0gYW5kIHNlZSBpZiB3ZSBjYW4gbWFrZSBzb21lIGluZm9ybWF0aXZlIHBsb3RzLgpUaGUgZmlyc3QgcGxvdCB3ZSdsbCBtYWtlIGlzIGEgdm9sY2FubyBwbG90IHVzaW5nIHRoZSBbYEVuaGFuY2VkVm9sY2Fub2AgcGFja2FnZV0oaHR0cHM6Ly9naXRodWIuY29tL2tldmluYmxpZ2hlL0VuaGFuY2VkVm9sY2FubykuClRoaXMgcGFja2FnZSBhdXRvbWF0aWNhbGx5IGNvbG9ycyB0aGUgcG9pbnRzIGJ5IGN1dG9mZnMgZm9yIGJvdGggc2lnbmlmaWNhbmNlIGFuZCBmb2xkIGNoYW5nZSBhbmQgbGFiZWxzIG1hbnkgb2YgdGhlIHNpZ25pZmljYW50IGdlbmVzIChzdWJqZWN0IHRvIHNwYWNpbmcpLgpgRW5oYW5jZWRWb2xjYW5vYCBoYXMgbWFueSwgbWFueSBvcHRpb25zLCB3aGljaCBpcyBhIGdvb2QgdGhpbmcgaWYgeW91IGRvbid0IGxpa2UgYWxsIG9mIGl0cyBkZWZhdWx0IHNldHRpbmdzLgpFdmVuIGJldHRlciwgaXQgb3V0cHV0cyBhIGBnZ3Bsb3QyYCBvYmplY3QsIHNvIGlmIHdlIHdhbnQgdG8gY3VzdG9taXplIHRoZSBwbG90IGZ1cnRoZXIsIHdlIGNhbiB1c2UgdGhlIHNhbWUgYGdncGxvdDJgIGNvbW1hbmRzIHdlIGhhdmUgdXNlZCBiZWZvcmUuCgpgYGB7ciB2b2xjYW5vfQpFbmhhbmNlZFZvbGNhbm86OkVuaGFuY2VkVm9sY2FubyhkZXNlcV9yZXN1bHRzLAogICAgICAgICAgICAgICAgeCA9ICdsb2cyRm9sZENoYW5nZScsICMgZm9sZCBjaGFuZ2Ugc3RhdGlzdGljIHRvIHBsb3QKICAgICAgICAgICAgICAgIHkgPSAncHZhbHVlJywgIyBzaWduaWZpY2FuY2UgdmFsdWVzCiAgICAgICAgICAgICAgICBsYWIgPSBkZXNlcV9yZXN1bHRzJGdlbmVfc3ltYm9sLCAjIGxhYmVscyBmb3IgcG9pbnRzCiAgICAgICAgICAgICAgICBwQ3V0b2ZmID0gMWUtMDUsICMgcCB2YWx1ZSBjdXRvZmYgKGRlZmF1bHQpCiAgICAgICAgICAgICAgICBGQ2N1dG9mZiA9IDEsICMgZm9sZCBjaGFuZ2UgY3V0b2ZmIChkZWZhdWx0KQogICAgICAgICAgICAgICAgdGl0bGUgPSBOVUxMLCAjIG5vIHRpdGxlCiAgICAgICAgICAgICAgICBzdWJ0aXRsZSA9IE5VTEwsICMgb3Igc3VidGl0bGUKICAgICAgICAgICAgICAgIGNhcHRpb24gPSBOVUxMLCAjIG9yIGNhcHRpb24KICAgICAgICAgICAgICAgIGRyYXdDb25uZWN0b3JzID0gVFJVRSwgIyBhZGQgc29tZSBmdW4gYXJyb3dzCiAgICAgICAgICAgICAgICBsYWJTaXplID0gMyAgIyBzbWFsbGVyIGxhYmVscwogICAgICAgICAgICAgICAgKSArCiAgIyBjaGFuZ2UgdGhlIG92ZXJhbGwgdGhlbWUKICB0aGVtZV9idygpICsKICAjIG1vdmUgdGhlIGxlZ2VuZCB0byB0aGUgYm90dG9tCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCmBgYAoKCldlIGNhbiBhbHNvIHJldHVybiBiYWNrIHRvIHRoZSBTQ0Ugb2JqZWN0IHRoYXQgd2UgdXNlZCB0byBjcmVhdGUgb3VyIHBzZXVkby1idWxrZWQgU0NFIGFuZCBsb29rIGF0IGdlbmUgZXhwcmVzc2lvbiBvZiBzb21lIG9mIHRoZSBzaWduaWZpY2FudCBnZW5lcy4gCldlIGNhbiBjcmVhdGUgVU1BUCBwbG90cyBhcyB3ZSBkaWQgcHJldmlvdXNseSwgYnV0IGluc3RlYWQgb2YgbGFiZWxpbmcgZWFjaCBjZWxsIHdpdGggbWV0YWRhdGEsIHdlIGNhbiBjb2xvciBjZWxscyBieSBhIHNwZWNpZmllZCBnZW5lJ3MgZXhwcmVzc2lvbiBsZXZlbHMuCldlIHdpbGwgYWxzbyB1c2Ugc29tZSBvZiB0aGUgYGdncGxvdDJgIHNraWxscyB3ZSBwaWNrZWQgdXAgZWFybGllciwgbGlrZSBgZmFjZXRfZ3JpZCgpYCB0byBwbG90IGNlbGxzIGZyb20gZGlmZmVyZW50IFJNUyBzdWJ0eXBlcyBzZXBhcmF0ZWx5LgpUaGlzIGNhbiBoZWxwIHVzIHZhbGlkYXRlIHRoZSBgREVTZXEyYCByZXN1bHRzIHNvIHRoYXQgd2UgY2FuIHZpc3VhbGl6ZSBnZW5lIGV4cHJlc3Npb24gY2hhbmdlcyBhY3Jvc3Mgb3VyIGNlbGwgdHlwZSBvZiBpbnRlcmVzdCBvbiBhIHNpbmdsZS1jZWxsIGxldmVsLiAKCmBgYHtyIGV4cHJlc3Npb24gdW1hcCwgbGl2ZT1UUlVFfQojIGZpbHRlciB0byBqdXN0IG15b2JsYXN0IGNlbGxzIGFuZCByZW1vdmUgYW55IE5BJ3MgYmVmb3JlIHBsb3R0aW5nCm15b2JsYXN0X2NvbWJpbmVkX3NjZSA8LSBybXNfc2NlWywgd2hpY2gocm1zX3NjZSRjZWxsdHlwZV9icm9hZCA9PSAiVHVtb3JfTXlvYmxhc3QiKV0KCiMgcGxvdCBQVFBSVCAoRU5TRzAwMDAwMTk2MDkwKSBleHByZXNzaW9uIGluIEFSTVMgdnMuIEVSTVMKc2NhdGVyOjpwbG90UmVkdWNlZERpbShteW9ibGFzdF9jb21iaW5lZF9zY2UsCiAgICAgICAgICAgICAgICAgICAgICAgZGltcmVkID0gImZhc3Rtbm5fVU1BUCIsCiAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyX2J5ID0gIkVOU0cwMDAwMDE5NjA5MCIsICNQVFBSVAogICAgICAgICAgICAgICAgICAgICAgIHBvaW50X3NpemU9IDAuNSwKICAgICAgICAgICAgICAgICAgICAgICBwb2ludF9hbHBoYSA9IDAuNCwKICAgICAgICAgICAgICAgICAgICAgICBvdGhlcl9maWVsZHMgPSAiZGlhZ25vc2lzX2dyb3VwIikgKwogIGZhY2V0X2dyaWQoY29scyA9IHZhcnMoZGlhZ25vc2lzX2dyb3VwKSkKYGBgCgpJbiB0aGUgYWJvdmUgcGxvdCB3ZSBvbmx5IHBsb3R0ZWQgdGhlIHR1bW9yIG15b2JsYXN0IGNlbGxzIHRoYXQgd2UgdXNlZCBpbiBvdXIgREUgYW5hbHlzaXMuIApIb3dldmVyLCB3ZSBtaWdodCBiZSBpbnRlcmVzdGVkIHRvIHNlZSB0aGUgZXhwcmVzc2lvbiBvZiBnZW5lcyB0aGF0IGFyZSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgaW4gb3RoZXIgY2VsbCB0eXBlcyBwcmVzZW50IGluIG91ciBzYW1wbGVzLgoKYGBge3IgY2VsbHR5cGUgY29tcGFyaXNvbn0KIyBsZXQncyBjb21wYXJlIGdlbmUgZXhwcmVzc2lvbiBhY3Jvc3Mgc29tZSBvdGhlciBjZWxsIHR5cGVzCiMgbG9vayBhdCBhbGwgdHVtb3IgY2VsbHMgYW5kIHBpY2sgb25lIG5vcm1hbCBjZWxsIHR5cGUKY2VsbHR5cGVzIDwtIGMoIlR1bW9yX015b2JsYXN0IiwgCiAgICAgICAgICAgICAgICJUdW1vcl9NZXNvZGVybSIsIAogICAgICAgICAgICAgICAiVHVtb3JfTXlvY3l0ZSIsIAogICAgICAgICAgICAgICAiVmFzY3VsYXIgRW5kb3RoZWxpdW0iKQoKIyBzdWJzZXQgdG8ganVzdCBjZWxsdHlwZXMgdGhhdCB3ZSBhcmUgaW50ZXJlc3RlZCBpbgp0dW1vcl9zY2UgPC0gcm1zX3NjZVssIHdoaWNoKHJtc19zY2UkY2VsbHR5cGVfYnJvYWQgJWluJSBjZWxsdHlwZXMpXQpgYGAKCk5leHQgd2Ugd2lsbCBsb29rIGF0IGEgZmV3IERFIGdlbmVzIHRoYXQgd2UgaWRlbnRpZmllZCwgb25lIHVwIHJlZ3VsYXRlZCBnZW5lIGFuZCBvbmUgZG93biByZWd1bGF0ZWQgZ2VuZSwgYW5kIGNvbXBhcmUgdGhlaXIgZXhwcmVzc2lvbiBpbiBteW9ibGFzdHMgdG8gb3RoZXIgY2VsbCB0eXBlcyBpbiBBUk1TIGFuZCBFUk1TIHNhbXBsZXMuCldlIHdpbGwgdXNlIHRoZSBgc2NhdGVyOjpwbG90RXhwcmVzc2lvbigpYCBmdW5jdGlvbiB0byBjcmVhdGUgYSB2aW9saW4gcGxvdCB3aXRoIFJNUyBzdWJ0eXBlIG9uIHRoZSB4LWF4aXMgYW5kIGdlbmUgZXhwcmVzc2lvbiBvbiB0aGUgeS1heGlzLgpXZSBjYW4gY29udGludWUgdXNpbmcgYGZhY2V0X2dyaWQoKWAgdG8gc2hvdyBzZXBhcmF0ZSBwYW5lbHMgZm9yIGVhY2ggY2VsbCB0eXBlLgpCZWNhdXNlIHdlIHdhbnQgdG8gc2hvdyBtdWx0aXBsZSBnZW5lcyBoZXJlLCB3ZSBhcmUgZ29pbmcgdG8gYWRkIGFuIGFkZGl0aW9uYWwgb3B0aW9uIHRvIGBmYWNldF9ncmlkKClgIHRvIGluY2x1ZGUgbXVsdGlwbGUgcm93cyBpbiBvdXIgcGxvdCBncmlkLCBvbmUgZm9yIGVhY2ggZ2VuZSBvZiBpbnRlcmVzdC4KT25lIG5lYXQgdHJpY2sgb2YgdGhlIGBzY2F0ZXI6OnBsb3RFeHByZXNzaW9uKClgIGZ1bmN0aW9uIGlzIHRoYXQgaXQgYWN0dWFsbHkgY3JlYXRlcyBhIGBGZWF0dXJlYCBjb2x1bW4gd2hpY2ggY29ycmVzcG9uZHMgdG8gdGhlIGZlYXR1cmVzIChpbiB0aGlzIGNhc2UgZ2VuZXMpIGJlaW5nIHVzZWQgaW4gcGxvdHRpbmcuCldlIGNhbiB0aGVuIGRpcmVjdGx5IHJlZmVyZW5jZSB0aGF0IGBGZWF0dXJlYCBjb2x1bW4gd2hlbiBwbG90dGluZywgaW5zdGVhZCBvZiB1c2luZyB0aGUgYG90aGVyX2ZpZWxkc2Agb3B0aW9uIHdlIHVzZWQgcHJldmlvdXNseS4KCmBgYHtyIG11bHRpLWdlbmUgcGxvdH0KIyBwaWNrIGEgY291cGxlIGdlbmVzIHRvIGxvb2sgYXQgCmdlbmVzX3RvX3Bsb3QgPC0gYygiRU5TRzAwMDAwMTk2MDkwIiwgI1BUUFJUCiAgICAgICAgICAgICAgICAgICAiRU5TRzAwMDAwMTQ4OTM1IikgI0dBUzIKCiMgY3JlYXRlIGEgdmlvbGluIHBsb3QgCnNjYXRlcjo6cGxvdEV4cHJlc3Npb24odHVtb3Jfc2NlLAogICAgICAgICAgICAgICAgICAgICAgICMgYSB2ZWN0b3Igb2YgZ2VuZXMgdG8gcGxvdAogICAgICAgICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gZ2VuZXNfdG9fcGxvdCwgCiAgICAgICAgICAgICAgICAgICAgICAgeCA9ICJkaWFnbm9zaXNfZ3JvdXAiLCAKICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXJfYnkgPSAiZGlhZ25vc2lzX2dyb3VwIiwKICAgICAgICAgICAgICAgICAgICAgICBvdGhlcl9maWVsZHMgPSAiY2VsbHR5cGVfYnJvYWQiLAogICAgICAgICAgICAgICAgICAgICAgIHBvaW50X3NpemUgPSAwLjEpICsKICAjIGVhY2ggY2VsbHR5cGUgaXMgaXRzIG93biBjb2x1bW4KICBmYWNldF9ncmlkKGNvbHMgPSB2YXJzKGNlbGx0eXBlX2Jyb2FkKSwKICAgICAgICAgICAgICMgZWFjaCBmZWF0dXJlIChnZW5lKSBpcyBpdHMgb3duIHJvdwogICAgICAgICAgICAgcm93cyA9IHZhcnMoRmVhdHVyZSkpICsgCiAgIyBjaGFuZ2UgdGhlIGZvbnQgc2l6ZSBvZiB0aGUgZmFjZXQgbGFiZWxzCiAgdGhlbWUoc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNykpICsgCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZCgKICAgIHRpdGxlID0gIlN1YnR5cGUiLCAjIHVwZGF0ZSB0aGUgbGVnZW5kIHRpdGxlCiAgICAjIGNoYW5nZSB0aGUgc2l6ZSBvZiB0aGUgbGVnZW5kIGNvbG9ycwogICAgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMywgYWxwaGEgPSAxKSkKICAgICkKYGBgCgpIb3cgZG8gdGhlIGV4cHJlc3Npb24gb2YgdGhlc2UgZ2VuZXMgY2hhbmdlIGFjcm9zcyBjZWxsIHR5cGVzIGFuZCBSTVMgc3VidHlwZXM/CgpHbyBhaGVhZCBhbmQgZXhwbG9yZSBzb21lIGdlbmVzIG9uIHlvdXIgb3duISAKRmVlbCBmcmVlIHRvIHBsb3QgYW55IG9mIHRoZSBnZW5lcyB0aGF0IGFyZSBpZGVudGlmaWVkIGFzIHNpZ25pZmljYW50LCBmb3VuZCBpbiB0aGUgREUgcmVzdWx0cyB0YWJsZSwgb3IgeW91ciBmYXZvcml0ZSBnZW5lLgpSZW1lbWJlciwgeW91IG5lZWQgdG8gdXNlIHRoZSBFbnNlbWJsIGdlbmUgaWRlbnRpZmllciB0byByZWZlciB0byBlYWNoIGdlbmUuCgpgYGB7ciBleHBsb3JlfQojIG5vdyBkbyBzb21lIGV4cGxvcmF0aW9uIG9mIG90aGVyIGdlbmVzIG9uIHlvdXIgb3duISAKYGBgCgojIyBQcmludCBzZXNzaW9uIGluZm8gCgpgYGB7ciBzZXNzaW9uIGluZm99CnNlc3Npb25JbmZvKCkKYGBgCgo=
+
LS0tCnRpdGxlOiAiRGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMgZm9yIHNjUk5BLXNlcSBkYXRhIgphdXRob3I6ICJEYXRhIExhYiBmb3IgQUxTRiIKZGF0ZTogMjAyMwpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwotLS0KCiMjIE9iamVjdGl2ZXMgCgpUaGlzIG5vdGVib29rIHdpbGwgZGVtb25zdHJhdGUgaG93IHRvOgoKLSBVc2UgcHNldWRvLWJ1bGtpbmcgdG8gcHJlcGFyZSBzY1JOQS1zZXEgbGlicmFyaWVzIGZvciBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbgotIFBlcmZvcm0gZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gd2l0aCB0aGUgYERFU2VxMmAgcGFja2FnZQotIFVzZSBgZ2dwbG90MmAgYW5kIGBFbmhhbmNlZFZvbGNhbm9gIHRvIHZpc3VhbGl6ZSBnZW5lIGV4cHJlc3Npb24gY2hhbmdlcyBhY3Jvc3MgY2VsbCB0eXBlcyBhbmQgc2FtcGxlcwoKLS0tCgpKdXN0IGxpa2UgYnVsayBSTkEtc2VxLCBpdCBpcyBsaWtlbHkgdGhhdCBvbmUgb2YgdGhlIGdvYWxzIHdoZW4gcGVyZm9ybWluZyBzY1JOQS1zZXEgd2lsbCBiZSB0byBjb21wYXJlIHRoZSBnZW5lIGV4cHJlc3Npb24gb2YgbXVsdGlwbGUgc2FtcGxlcyB0byBlYWNoIG90aGVyLgpVbmxpa2UgYnVsayBSTkEtc2VxIGFuYWx5c2lzLCBzY1JOQS1zZXEgYW5hbHlzaXMgYWxsb3dzIHVzIHRvIGlkZW50aWZ5IGFuZCBhbm5vdGF0ZSBjZWxsIHR5cGVzIG9yIHN1YnBvcHVsYXRpb25zIG9mIGNlbGxzIHByZXNlbnQgaW4gZWFjaCBvZiBvdXIgc2FtcGxlcy4KVGhpcyBtZWFucyB0aGF0IHdlIGNhbiBhY2NvdW50IGZvciBkaWZmZXJlbmNlcyBpbiBjZWxsIHR5cGUgY29tcG9zaXRpb24gYWNyb3NzIHNhbXBsZXMgYW5kIHNwZWNpZmljYWxseSBmb2N1cyBvbiBjZWxsIHR5cGVzIG9yIHBvcHVsYXRpb25zIG9mIGludGVyZXN0IHdoZW4gcGVyZm9ybWluZyBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiAoREUpIGFuYWx5c2lzLgpJbiB0aGlzIG5vdGVib29rLCB3ZSB3aWxsIHdvcmsgd2l0aCBtdWx0aXBsZSBzYW1wbGVzIHRvIGlkZW50aWZ5IGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyBhY3Jvc3MgY2VsbCB0eXBlcyBvZiBpbnRlcmVzdCB1c2luZyB0aGUgW2BERVNlcTJgXShodHRwczovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvMy4xNi9iaW9jL2h0bWwvREVTZXEyLmh0bWwpIHBhY2thZ2UuIAoKIVtTaW5nbGUtY2VsbCByb2FkbWFwOiBEaWZmZXJlbnRpYWwgZXhwcmVzc2lvbl0oZGlhZ3JhbXMvcm9hZG1hcF9kaWZmZXJlbnRpYWxfZXhwcmVzc2lvbi5wbmcpCgpXZSB3aWxsIGNvbnRpbnVlIHdvcmtpbmcgd2l0aCBzYW1wbGVzIGZyb20gdGhlIFtgU0NQQ1AwMDAwMDVgIHByb2plY3RdKGh0dHBzOi8vc2NwY2EuYWxleHNsZW1vbmFkZS5vcmcvcHJvamVjdHMvU0NQQ1AwMDAwMDUpLCBhbiBpbnZlc3RpZ2F0aW9uIG9mIHBlZGlhdHJpYyBzb2xpZCB0dW1vcnMgbGVkIGJ5IHRoZSBEeWVyIGFuZCBDaGVuIGxhYnMgYXQgU3QuIEp1ZGUgQ2hpbGRyZW4ncyBSZXNlYXJjaCBIb3NwaXRhbC4KVGhpcyBwYXJ0aWN1bGFyIGRhdGFzZXQgY29udGFpbnMgMTAgZGlmZmVyZW50IHNhbXBsZXMgdGhhdCBoYXZlIGJlZW4gaW50ZWdyYXRlZCB1c2luZyBgZmFzdE1OTmAsIGZvbGxvd2luZyB0aGUgc2FtZSBwcm9jZWR1cmUgd2Ugb3V0bGluZWQgaW4gYDAyLWRhdGFzZXRfaW50ZWdyYXRpb24uUm1kYC4KVGhlc2UgMTAgc2FtcGxlcyByZXByZXNlbnQgdHdvIGRpZmZlcmVudCB0eXBlcyBvZiByaGFiZG9teW9zYXJjb21hIChSTVMpOiBlbWJyeW9uYWwgcmhhYmRvbXlvc2FyY29tYSAoRVJNUykgYW5kIGFsdmVvbGFyIHJoYWJkb215b3NhcmNvbWEgKEFSTVMpLgpUaGVzZSB0d28gc3VidHlwZXMgYXJlIGRpc3Rpbmd1aXNoZWQgYnkgdGhlIHByZXNlbmNlIG9mIHRoZSBgUEFYMy9QQVg3LUZPWE8xYCBmdXNpb24gZ2VuZSwgd2hpY2ggaXMgcHJlc2VudCBvbmx5IGluIEFSTVMgcGF0aWVudHMuCkFkZGl0aW9uYWxseSwgY2VsbHMgZm91bmQgaW4gQVJNUyB0dW1vcnMgdGVuZCB0byBoYXZlIGFuIGluY3JlYXNlZCBtdXRhdGlvbmFsIGJ1cmRlbiB3aXRoIGNlbGxzIGluIGEgbW9yZSBkaWZmZXJlbnRpYXRlZCBzdGF0ZSBjb21wYXJlZCB0byBFUk1TIHR1bW9yIGNlbGxzIChbU2hlcm4gX2V0IGFsLl8gMjAxNF0oaHR0cHM6Ly9kb2kub3JnLzEwLjExNTgvMjE1OS04MjkwLkNELTEzLTA2MzkpOyBbU3Rld2FydCBfZXQgYWwuXyAyMDE4XShodHRwczovL2RvaS5vcmcvMTAuMTAxNi9qLmNjZWxsLjIwMTguMDcuMDEyKSkuClJNUyB0dW1vcnMsIHJlZ2FyZGxlc3Mgb2Ygc3VidHlwZSwgYXJlIG1hZGUgdXAgb2YgY2VsbHMgdHlwaWNhbGx5IGFzc29jaWF0ZWQgd2l0aCBkZXZlbG9wbWVudCBvZiBza2VsZXRhbCBtdXNjbGU6IG1lc29kZXJtLCBteW9ibGFzdHMsIGFuZCBteW9jeXRlcyAoW1NlYmlyZSBhbmQgTWFsb25lIDIwMDNdKGh0dHBzOi8vZG9pLm9yZy8xMC4xMTM2L2pjcC41Ni42LjQxMikpLgpbUGF0ZWwgX2V0IGFsLl8gKDIwMjIpXShodHRwczovL2RvaS5vcmcvMTAuMTAxNi9qLmRldmNlbC4yMDIyLjA0LjAwMykgdGVzdGVkIHRoZSBoeXBvdGhlc2lzIHRoYXQgY2VsbCB0eXBlcyBoYXZlIGRpc3RpbmN0IGdlbmUgZXhwcmVzc2lvbiBwYXR0ZXJucyBpbiBBUk1TIHZzLiBFUk1TIHNhbXBsZXMuCkhlcmUgd2Ugd2lsbCBsb29rIGF0IGEgc3Vic2V0IG9mIHRoZSBzYW1wbGVzIHRoZXkgc2VxdWVuY2VkIGFuZCBpZGVudGlmeSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMgaW4gdHVtb3IgY2VsbHMgYmV0d2VlbiBBUk1TIGFuZCBFUk1TIHNhbXBsZXMuCgojIyBTZXQgdXAKCmBgYHtyIHNldHVwLCBtZXNzYWdlPUZBTFNFfQojIHNldCBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkKc2V0LnNlZWQoMjAyMikKCiMgbG9hZCBsaWJyYXJpZXMKbGlicmFyeShnZ3Bsb3QyKSAjIHBsb3R0aW5nIGZ1bmN0aW9ucwpsaWJyYXJ5KFNpbmdsZUNlbGxFeHBlcmltZW50KSAKCiMgcGFja2FnZSB1c2VkIGZvciBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcwpsaWJyYXJ5KERFU2VxMikKYGBgCgojIyMgRGlyZWN0b3JpZXMgYW5kIGZpbGVzCgpXZSB3aWxsIHN0YXJ0IGJ5IHJlYWRpbmcgaW4gYSBgU2luZ2xlQ2VsbEV4cGVyaW1lbnRgIChTQ0UpIG9iamVjdCB0aGF0IGNvbnRhaW5zIGJvdGggdGhlIHVuY29ycmVjdGVkIChtZXJnZWQgYnV0IG5vdCBpbnRlZ3JhdGVkKSBhbmQgY29ycmVjdGVkIChpbnRlZ3JhdGVkKSBnZW5lIGV4cHJlc3Npb24gZGF0YSBmb3IgYWxsIDEwIHNhbXBsZXMuCgpQcmlvciB0byBpbnRlZ3JhdGlvbiwgYWxsIDEwIHNhbXBsZXMgd2VudCB0aHJvdWdoIHRoZSBzYW1lIGZpbHRlcmluZywgbm9ybWFsaXphdGlvbiwgYW5kIGRpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbi4KVGhlc2UgMTAgc2FtcGxlcyB3ZXJlIHRoZW4gbWVyZ2VkIGludG8gb25lIGBTaW5nbGVDZWxsRXhwZXJpbWVudGAgb2JqZWN0IGZvbGxvd2luZyB0aGUgc2FtZSBzdGVwcyBvdXRsaW5lZCBpbiBgMDMtZGF0YXNldF9pbnRlZ3JhdGlvbi5SbWRgLgpUaGUgbWVyZ2VkIG9iamVjdCB3YXMgdGhlbiBpbnRlZ3JhdGVkIHdpdGggYGZhc3RNTk5gIHRvIG9idGFpbiBhIGNvcnJlY3RlZCBnZW5lIGV4cHJlc3Npb24gYXNzYXkgYW5kIGNvcnJlY3RlZCByZWR1Y2VkIGRpbWVuc2lvbmFsaXR5IHJlc3VsdHMuClRoZSBmaW5hbCBTQ0Ugb2JqZWN0IHdhcyBzdG9yZWQgaW4gYGRhdGEvcm1zL2ludGVncmF0ZWQvcm1zX2FsbF9zY2UucmRzYC4KCldlIGFsc28gaGF2ZSBwcm92aWRlZCBhIG1ldGFkYXRhIGZpbGUsIGBkYXRhL3Jtcy9hbm5vdGF0aW9ucy9ybXNfc2FtcGxlX21ldGFkYXRhLnRzdmAsIHRoYXQgY29udGFpbnMgaW5mb3JtYXRpb24gZnJvbSBlYWNoIHNhbXBsZSwgc3VjaCBhcyBkaWFnbm9zaXMsIHNleCwgYWdlLCBldGMuCkVhY2ggcm93IGluIHRoaXMgZmlsZSBjb3JyZXNwb25kcyB0byBhIHNhbXBsZSBmb3VuZCBpbiB0aGUgaW50ZWdyYXRlZCBTQ0Ugb2JqZWN0LgoKVG8gYmVnaW4sIGxldCdzIHNldCB1cCBvdXIgZGlyZWN0b3JpZXMgYW5kIGZpbGVzOgoKYGBge3IgZmlsZXBhdGhzfQojIHNldCB1cCBmaWxlIHBhdGhzIAojIGRhdGEgZGlyZWN0b3J5IGZvciBSTVMgZGF0YQpkYXRhX2RpciA8LSBmaWxlLnBhdGgoImRhdGEiLCAicm1zIikKCiMgaW50ZWdyYXRlZCBmaWxlIGNvbnRhaW5pbmcgc2FtcGxlcyB0byB1c2UgZm9yIERFIGFuYWx5c2lzCmludGVncmF0ZWRfc2NlX2ZpbGUgPC0gZmlsZS5wYXRoKGRhdGFfZGlyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImludGVncmF0ZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInJtc19hbGxfc2NlLnJkcyIpCgojIHNhbXBsZSBtZXRhZGF0YSB0byBzZXQgdXAgREUgYW5hbHlzaXMKc2FtcGxlX21ldGFkYXRhX2ZpbGUgPC0gZmlsZS5wYXRoKGRhdGFfZGlyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJhbm5vdGF0aW9ucyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInJtc19zYW1wbGVfbWV0YWRhdGEudHN2IikKCiMgZGlyZWN0b3J5IHRvIHN0b3JlIG91dHB1dApkZXNlcV9kaXIgPC0gZmlsZS5wYXRoKCJhbmFseXNpcyIsICJybXMiLCAiZGVzZXEiKQpmczo6ZGlyX2NyZWF0ZShkZXNlcV9kaXIpCgojIHJlc3VsdHMgZmlsZSB0byBvdXRwdXQgZnJvbSBERSBhbmFseXNpcwpkZXNlcV9vdXRwdXRfZmlsZSA8LSBmaWxlLnBhdGgoZGVzZXFfZGlyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJybXNfbXlvYmxhc3RfZGVzZXFfcmVzdWx0cy50c3YiKQoKIyBvdXRwdXQgaW50ZWdyYXRlZCBzY2Ugb2JqZWN0Cm91dHB1dF9zY2VfZmlsZSA8LSBmaWxlLnBhdGgoZGF0YV9kaXIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJpbnRlZ3JhdGVkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInJtc19zdWJzZXRfc2NlLnJkcyIpCmBgYAoKV2UgY2FuIGdvIGFoZWFkIGFuZCByZWFkIGluIHRoZSBTQ0Ugb2JqZWN0IGFuZCB0aGUgbWV0YWRhdGEgZmlsZS4KCmBgYHtyIHJlYWQgZmlsZXMsIGxpdmU9VFJVRX0KIyByZWFkIGluIHRoZSBTQ0Ugb2JqZWN0IHRoYXQgaGFzIGFscmVhZHkgYmVlbiBpbnRlZ3JhdGVkCmludGVncmF0ZWRfc2NlIDwtIHJlYWRyOjpyZWFkX3JkcyhpbnRlZ3JhdGVkX3NjZV9maWxlKQoKIyByZWFkIGluIHNhbXBsZSBtZXRhZGF0YSBmaWxlIApzYW1wbGVfbWV0YWRhdGEgPC0gcmVhZHI6OnJlYWRfdHN2KHNhbXBsZV9tZXRhZGF0YV9maWxlKQpgYGAKCiMjIERhdGFzZXQgZXhwbG9yYXRpb24KCkJlZm9yZSB3ZSBkaXZlIGludG8gZGlmZmVyZW50aWFsIGV4cHJlc3Npb24sIGxldCdzIGV4cGxvcmUgb3VyIGludGVncmF0ZWQgU0NFIG9iamVjdCBhbmQgdGhlIGRhdGFzZXQgYSBsaXR0bGUgbW9yZS4KCldlJ2xsIHN0YXJ0IGJ5IGxvb2tpbmcgYXQgd2hhdCdzIGluc2lkZSB0aGUgb2JqZWN0LgpIZXJlIHdlIHNob3VsZCBoYXZlIGJvdGggdGhlIG9yaWdpbmFsICh1bmNvcnJlY3RlZCkgZGF0YSBhbmQgdGhlIGludGVncmF0ZWQgKGNvcnJlY3RlZCkgZGF0YSBmb3IgYm90aCB0aGUgZ2VuZSBleHByZXNzaW9uIGFuZCB0aGUgcmVkdWNlZCBkaW1lbnNpb25hbGl0eSByZXN1bHRzLgpIb3cgYXJlIHRob3NlIHN0b3JlZCBpbiBvdXIgb2JqZWN0PwoKYGBge3IgcHJpbnQgc2NlLCBsaXZlPVRSVUV9CiMgcHJpbnQgb3V0IGVudGlyZSBvYmplY3QKaW50ZWdyYXRlZF9zY2UKYGBgCgoKYGBge3IgcHJpbnQgYXNzYXkgbmFtZXMsIGxpdmU9VFJVRX0KIyBsb29rIGF0IHRoZSBhc3NheSBuYW1lcyBpbiBvdXIgb2JqZWN0CmFzc2F5TmFtZXMoaW50ZWdyYXRlZF9zY2UpCmBgYAoKV2hlbiB3ZSBsb29rIGF0IHRoZSBhc3NheSBuYW1lcyB3ZSBzaG91bGQgc2VlIHRoYXQgdGhlcmUgYXJlIDMgbWF0cmljZXMsIGBjb3VudHNgLCBgbG9nY291bnRzYCwgYW5kIGBmYXN0bW5uX2NvcnJlY3RlZGAuIApUaGUgYGNvdW50c2AgYW5kIGBsb2djb3VudHNgIGFzc2F5cyBjb3JyZXNwb25kIHRvIHRoZSB1bmNvcnJlY3RlZCBnZW5lIGV4cHJlc3Npb24gZGF0YSB0aGF0IGhhcyBiZWVuIG1lcmdlZCBidXQgTk9UIGludGVncmF0ZWQuClRoZSBgZmFzdG1ubl9jb3JyZWN0ZWRgIGRhdGEgY29udGFpbnMgdGhlIGNvcnJlY3RlZCBnZW5lIGV4cHJlc3Npb24gZGF0YSBvYnRhaW5lZCBmcm9tIGludGVncmF0aW9uLiAKRm9yIHRoaXMgZXhlcmNpc2Ugd2Ugd2lsbCBub3QgYmUgdXNpbmcgdGhlIGBmYXN0bW5uX2NvcnJlY3RlZGAgZGF0YSAobW9yZSBvbiB3aHkgbm90IG9uY2Ugd2UgZ2V0IHRvIHNldHRpbmcgdXAgdGhlIGRpZmZlcmVudGlhbCBleHByZXNzaW9uKSwgYnV0IHdlIG5lZWQgdG8gYmUgYXdhcmUgdGhhdCBpdCBpcyBwcmVzZW50IGFuZCBiZSBhYmxlIHRvIGRpc3Rpbmd1aXNoIGl0IGZyb20gb3VyIHVuY29ycmVjdGVkIGRhdGEuIAoKCmBgYHtyIHByaW50IHJlZHVjZWREaW0gbmFtZXMsIGxpdmU9VFJVRX0KIyBsb29rIGF0IHRoZSBuYW1lcyBvZiB0aGUgZGltZW5zaW9uIHJlZHVjdGlvbnMKcmVkdWNlZERpbU5hbWVzKGludGVncmF0ZWRfc2NlKQpgYGAKCkluIHRoZSBgcmVkdWNlZERpbWAgc2xvdHMgeW91IHNob3VsZCBzZWUgYFBDQWAgYW5kIGBVTUFQYCwgd2hpY2ggd2VyZSBib3RoIGNhbGN1bGF0ZWQgZnJvbSB0aGUgY29tYmluZWQgZGF0YSBfYmVmb3JlXyBpbnRlZ3JhdGlvbi4KWW91IHNob3VsZCBhbHNvIHNlZSBgZmFzdG1ubl9QQ0FgIGFuZCBgZmFzdG1ubl9VTUFQYCByZWR1Y2VkIGRpbWVuc2lvbnMsIHdoaWNoIGNvcnJlc3BvbmQgdG8gdGhlIGludGVncmF0ZWQgcmVzdWx0cy4KCiMjIyBDZWxsIHR5cGUgYW5ub3RhdGlvbnMKCkp1c3QgbGlrZSBpbiB0aGUgaW50ZWdyYXRpb24gbm90ZWJvb2ssIHRoaXMgZGF0YXNldCBhbHNvIGNvbnRhaW5zIHRoZSBjZWxsIHR5cGUgYW5ub3RhdGlvbnMgZm91bmQgaW4gdGhlIGBjZWxsdHlwZV9maW5lYCBhbmQgYGNlbGx0eXBlX2Jyb2FkYCBjb2x1bW5zIG9mIHRoZSBgY29sRGF0YWAuClRoZXNlIGNlbGwgdHlwZXMgd2VyZSBvcmlnaW5hbGx5IGFzc2lnbmVkIGluIFtQYXRlbCBfZXQgYWwuXyAoMjAyMildKGh0dHBzOi8vZG9pLm9yZy8xMC4xMDE2L2ouZGV2Y2VsLjIwMjIuMDQuMDAzKS4KV2Ugd2lsbCB1c2UgdGhlc2UgY2VsbCB0eXBlIGFzc2lnbm1lbnRzIHRvIHNldCB1cCB0aGUgREUgYW5hbHlzaXMgYmVsb3csIGJ1dCB0aGV5IGFyZSBub3QgcmVxdWlyZWQgZm9yIERFIGFuYWx5c2lzIGl0c2VsZi4KSXQncyBpbXBvcnRhbnQgdG8gbm90ZSB0aGF0IERFIGFuYWx5c2lzIGNhbiBiZSBhcHBsaWVkIHRvIGFueSBzdWJwb3B1bGF0aW9uIG9mIGludGVyZXN0IHRoYXQgaXMgc2hhcmVkIGFjcm9zcyBzYW1wbGVzIGJlc2lkZXMganVzdCBjZWxsIHR5cGVzLgoKQmVjYXVzZSB3ZSBhcmUgZ29pbmcgdG8gYmUgZG9pbmcgREUgYW5hbHlzaXMgYmV0d2VlbiBBUk1TIGFuZCBFUk1TIHNhbXBsZXMsIGxldCdzIHN0YXJ0IGJ5IGxhYmVsaW5nIGNlbGxzIGluIHRoZSBpbnRlZ3JhdGVkIGRhdGFzZXQgYmFzZWQgb24gdGhlaXIgUk1TIHN1YnR5cGUuClRvIGRvIHRoaXMgd2Ugd2lsbCBuZWVkIHRvIGJlIHN1cmUgdGhhdCB0aGUgc3VidHlwZSBpcyBwcmVzZW50IGluIHRoZSBgY29sRGF0YWAgb2YgdGhlIGludGVncmF0ZWQgU0NFIG9iamVjdC4KSWYgaXQncyBub3QgdGhlcmUsIHdlIG5lZWQgdG8gYWRkIGl0IGluLgoKYGBge3IgY29sZGF0YSBoZWFkLCBsaXZlPVRSVUV9CiMgbG9vayBhdCB0aGUgaGVhZCBvZiB0aGUgY29sZGF0YQpoZWFkKGNvbERhdGEoaW50ZWdyYXRlZF9zY2UpKSB8PgogIGFzLmRhdGEuZnJhbWUoKQpgYGAKClVoIG9oLCBpdCBsb29rcyBsaWtlIHRoZSBSTVMgc3VidHlwZSBpcyBub3QgZm91bmQgaW4gdGhlIFNDRSBvYmplY3QuCkZvcnR1bmF0ZWx5IHdlIGFsc28gaGF2ZSB0aGUgc2FtcGxlIG1ldGFkYXRhIHRhYmxlIHRoYXQgd2UgcmVhZCBpbiBlYXJsaWVyLCB3aGljaCBjb250YWlucyBpbmZvcm1hdGlvbiBhYm91dCBlYWNoIG9mIHRoZSBzYW1wbGVzIHByZXNlbnQgaW4gdGhlIGRhdGFzZXQuCgpgYGB7ciBzYW1wbGUgbWV0YWRhdGEsIGxpdmU9VFJVRX0KIyBwcmludCBvdXQgc2FtcGxlIG1ldGFkYXRhCmhlYWQoc2FtcGxlX21ldGFkYXRhKQpgYGAKCkxvb2tpbmcgYXQgdGhpcyBzYW1wbGUgdGFibGUsIHdlIHNlZSBhIGNvbHVtbiBuYW1lZCBgc3ViZGlhZ25vc2lzYCB3aGljaCBhY2NvdW50cyBmb3IgdGhlIFJNUyBzdWJ0eXBlLCBBUk1TIG9yIEVSTVMuCldlIGFsc28gc2VlIG90aGVyIGNvbHVtbnMgdGhhdCBjb250YWluIGluZm9ybWF0aW9uIGFib3V0IGVhY2ggc3BlY2lmaWMgc2FtcGxlLgoKV2UgY2FuIGluY29ycG9yYXRlIHRoZSBpbmZvcm1hdGlvbiBpbiB0aGlzIHNhbXBsZSBtZXRhZGF0YSB0YWJsZSBpbnRvIHRoZSBgY29sRGF0YWAgb2YgdGhlIGludGVncmF0ZWQgU0NFIG9iamVjdC4KVGhpcyB3aWxsIGFsbG93IHVzIHRvIG1hdGNoIGVhY2ggb2YgdGhlIHNhbXBsZXMgaW4gdGhlIFNDRSBvYmplY3Qgd2l0aCB0aGUgUk1TIHN1YnR5cGUgYW5kIGFsc28gYWxsb3cgdXMgdG8gdXNlIGFueSBvZiB0aGUgY29sdW1ucyBpbiB0aGUgc2FtcGxlIG1ldGFkYXRhIGZvciBwbG90dGluZy4KCmBgYHtyIG1vZGlmeSBjb2xkYXRhfQojIGFkZCBzYW1wbGUgbWV0YWRhdGEgdG8gY29sRGF0YSBmcm9tIHRoZSBpbnRlZ3JhdGVkIFNDRSBvYmplY3QKY29sZGF0YV9kZiA8LSBjb2xEYXRhKGludGVncmF0ZWRfc2NlKSB8PgogICMgY29udmVydCBmcm9tIERhdGFGcmFtZSB0byBkYXRhLmZyYW1lCiAgYXMuZGF0YS5mcmFtZSgpIHw+CiAgIyBtZXJnZSB3aXRoIHNhbXBsZSBtZXRhZGF0YSAKICBkcGx5cjo6bGVmdF9qb2luKHNhbXBsZV9tZXRhZGF0YSwgYnkgPSBjKCJzYW1wbGUiID0gImxpYnJhcnlfaWQiKSkgfD4KICAjIGNyZWF0ZSBuZXcgY29sdW1ucwogICMgY2VsbF9pZCBpcyBhIGNvbWJpbmF0aW9uIG9mIGJhcmNvZGUgYW5kIHNhbXBsZQogIGRwbHlyOjptdXRhdGUoY2VsbF9pZCA9IGdsdWU6OmdsdWUoIntzYW1wbGV9LXtiYXJjb2RlfSIpLAogICAgICAgICAgICAgICAgIyBzaW1wbGlmeSBzdWJkaWFnbm9zaXMKICAgICAgICAgICAgICAgIGRpYWdub3Npc19ncm91cCA9IGZvcmNhdHM6OmZjdF9yZWNvZGUoCiAgICAgICAgICAgICAgICAgIHN1YmRpYWdub3NpcywKICAgICAgICAgICAgICAgICAgIkFSTVMiID0gIkFsdmVvbGFyIHJoYWJkb215b3NhcmNvbWEiLAogICAgICAgICAgICAgICAgICAiRVJNUyIgPSAiRW1icnlvbmFsIHJoYWJkb215b3NhcmNvbWEiCiAgICAgICAgICAgICAgICApKQoKIyBhZGQgbW9kaWZpZWQgZGF0YSBmcmFtZSBiYWNrIHRvIFNDRSBhcyBEYXRhRnJhbWUKY29sRGF0YShpbnRlZ3JhdGVkX3NjZSkgPC0gRGF0YUZyYW1lKGNvbGRhdGFfZGYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID0gY29sZGF0YV9kZiRjZWxsX2lkKQpgYGAKCk5vdyB3aGVuIHdlIGxvb2sgYXQgdGhlIGBjb2xEYXRhYCBvZiB0aGUgU0NFIG9iamVjdCB3ZSBzaG91bGQgc2VlIG5ldyBjb2x1bW5zLCBpbmNsdWRpbmcgdGhlIGBkaWFnbm9zaXNfZ3JvdXBgIGNvbHVtbiB3aGljaCBpbmRpY2F0ZXMgaWYgZWFjaCBjZWxsIGNvbWVzIGZyb20gYW4gRVJNUyBvciBBUk1TIHNhbXBsZS4KCmBgYHtyIHByaW50IG5ldyBjb2xkYXRhLCBsaXZlPVRSVUV9CiMgdGFrZSBhIGxvb2sgYXQgdGhlIG5ldyBtb2RpZmllZCBjb2xEYXRhCmhlYWQoY29sRGF0YShpbnRlZ3JhdGVkX3NjZSkpIHw+CiAgYXMuZGF0YS5mcmFtZSgpCmBgYAoKIyMjIFBsb3R0aW5nIHdpdGggYW5ub3RhdGlvbnMKCldlIGNhbiBub3cgdXNlIHRoYXQgY29sdW1uIHRvIGxhYmVsIGFueSBVTUFQIHBsb3RzIChvciBvdGhlciBwbG90IHR5cGVzKSB0aGF0IHdlIG1ha2UuCkluIHRoZSBjaHVuayBiZWxvdyB3ZSB3aWxsIHN0YXJ0IGJ5IHRha2luZyBhIGxvb2sgYXQgb3VyIGludGVncmF0aW9uIHJlc3VsdHMgYW5kIGNvbG9yIG91ciBjZWxscyBieSBSTVMgc3VidHlwZS4KCioqUmVtaW5kZXI6IFlvdSBzaG91bGQgYWx3YXlzIHVzZSB0aGUgYmF0Y2gtY29ycmVjdGVkIGRpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbiByZXN1bHRzIGZvciB2aXN1YWxpemluZyBkYXRhc2V0cyBjb250YWluaW5nIG11bHRpcGxlIGxpYnJhcmllcyBvciBzYW1wbGVzLioqCgpgYGB7ciBkaWFnbm9zaXMgZ3JvdXAgVU1BUCwgbGl2ZT1UUlVFfQojIFVNQVAgb2YgYWxsIHNhbXBsZXMsIHNlcGFyYXRpbmcgYnkgZGlhZ25vc2lzIGdyb3VwCnNjYXRlcjo6cGxvdFJlZHVjZWREaW0oaW50ZWdyYXRlZF9zY2UsCiAgICAgICAgICAgICAgICAgICAgICAgZGltcmVkID0gImZhc3Rtbm5fVU1BUCIsCiAgICAgICAgICAgICAgICAgICAgICAgY29sb3JfYnkgPSAiZGlhZ25vc2lzX2dyb3VwIiwKICAgICAgICAgICAgICAgICAgICAgICBwb2ludF9zaXplPSAwLjUsCiAgICAgICAgICAgICAgICAgICAgICAgcG9pbnRfYWxwaGEgPSAwLjIpIApgYGAKCkludGVyZXN0aW5nbHksIGl0IGxvb2tzIGxpa2Ugc2FtcGxlcyBmcm9tIHRoZSBBUk1TIGFuZCBFUk1TIHN1YnR5cGVzIHRlbmQgdG8gZ3JvdXAgd2l0aCBzYW1wbGVzIG9mIHRoZSBzYW1lIHN1YnR5cGUgcmF0aGVyIHRoYW4gYWxsIHRvZ2V0aGVyLiAKCkluIHRoZSBpbnRlZ3JhdGlvbiBub3RlYm9vayB3ZSBhbHNvIGxvb2tlZCBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIGNlbGwgdHlwZXMgYWZ0ZXIgaW50ZWdyYXRpb24uCkluIHRoYXQgbm90ZWJvb2ssIHdlIGRpc2N1c3NlZCB0aGF0IGNlbGxzIG9mIHRoZSBzYW1lIGNlbGwgdHlwZSBhcmUgZXhwZWN0ZWQgdG8gaW50ZWdyYXRlIHdpdGggb3RoZXIgY2VsbHMgb2YgdGhlIHNhbWUgdHlwZS4KSXMgdGhhdCB0aGUgY2FzZSB3aXRoIHRoaXMgZGF0YXNldD8KCkEgd29yZCBvZiBjYXV0aW9uIHdoZW4gZXZhbHVhdGluZyB0aGUgY2VsbCB0eXBlIHJlc3VsdHMgZm9yIHRoaXMgZGF0YXNldDogVGhlIGNlbGwgdHlwZXMgZm9yIHRoaXMgZGF0YXNldCB3ZXJlIGFzc2lnbmVkIGluIGEgdHdvIHN0YWdlIHByb2Nlc3MgYXMgZGVzY3JpYmVkIGluIFtQYXRlbCBfZXQgYWwuXyAoMjAyMildKGh0dHBzOi8vZG9pLm9yZy8xMC4xMDE2L2ouZGV2Y2VsLjIwMjIuMDQuMDAzKS4KVGhlIGZpcnN0IHN0YWdlIGFzc2lnbmVkIGNlbGxzIGFzIHR1bW9yIG9yIG5vbi10dW1vci4KVGhlIG5leHQgc3RhZ2UgZnVydGhlciBjbGFzc2lmaWVkIHR1bW9yIGNlbGxzIGludG8gb25lIG9mIHRocmVlIHR5cGVzIG9mIHR1bW9yIGNlbGxzOiBteW9ibGFzdCwgbXlvY3l0ZSwgb3IgbWVzb2Rlcm0uClNvbWUgc2FtcGxlcyBjb3VsZCBub3QgYmUgZnVydGhlciBjbGFzc2lmaWVkLCBzbyBhbGwgb2YgdGhlaXIgdHVtb3IgY2VsbHMgYXJlIGRlbm90ZWQgYFR1bW9yYC4KVGhlIHNhbXBsZXMgd2hpY2ggY291bGQgYmUgZnVydGhlciBjbGFzc2lmaWVkIGhhdmUgYSBtaXggb2YgYFR1bW9yX01lc29kZXJtYCwgYFR1bW9yX015b2JsYXN0YCwgYW5kIGBUdW1vcl9NeW9jeXRlYC4KCmBgYHtyIGNlbGx0eXBlIFVNQVB9CiMgVU1BUCBvZiBhbGwgc2FtcGxlcyBsYWJlbGVkIGJ5IGNlbGwgdHlwZQpzY2F0ZXI6OnBsb3RSZWR1Y2VkRGltKGludGVncmF0ZWRfc2NlLAogICAgICAgICAgICAgICAgICAgICAgIGRpbXJlZCA9ICJmYXN0bW5uX1VNQVAiLAogICAgICAgICAgICAgICAgICAgICAgICMgY29sb3IgZWFjaCBwb2ludCBieSBjZWxsIHR5cGUKICAgICAgICAgICAgICAgICAgICAgICBjb2xvcl9ieSA9ICJjZWxsdHlwZV9icm9hZCIsCiAgICAgICAgICAgICAgICAgICAgICAgcG9pbnRfc2l6ZT0gMC41LCAKICAgICAgICAgICAgICAgICAgICAgICBwb2ludF9hbHBoYSA9IDAuNCkKYGBgCgpVbmxpa2Ugd2l0aCB0aGUgcHJldmlvdXMgZGF0YXNldHMgd2UgaGF2ZSBzZWVuIHdoZXJlIGFsbCBjZWxscyBvZiB0aGUgc2FtZSBjZWxsIHR5cGUgYWx3YXlzIGdyb3VwZWQgdG9nZXRoZXIsIHRoaXMgZGF0YXNldCBzaG93cyBzb21lIHNsaWdodGx5IGRpZmZlcmVudCBwYXR0ZXJucyBhbmQgbm90IGFsbCBjZWxscyBvZiB0aGUgc2FtZSBjZWxsIHR5cGUgY2x1c3RlciB0b2dldGhlci4KT25lIHJlYXNvbiBpcyB0aGF0IHR1bW9yIGRhdGEgY2FuIGJlIGhldGVyb2dlbmVvdXMgYW5kIGV2ZXJ5IHR1bW9yIGlzIHVuaXF1ZS4KRGVwZW5kaW5nIG9uIHRoZSB0dW1vciB0eXBlIHdlIG1heSBub3QgZXhwZWN0IGV2ZXJ5IHNhbXBsZSB0byBpbnRlZ3JhdGUgcGVyZmVjdGx5IGFuZCBtb3JlIGhldGVyb2dlbmVvdXMgdHVtb3IgdHlwZXMgd2lsbCBiZSBtb3JlIGRpZmZpY3VsdCB0byBpbnRlZ3JhdGUgdG9nZXRoZXIuCkluIHRoaXMgcGFydGljdWxhciBjYXNlIHdlIGFyZSBsb29raW5nIGF0IHR3byBzdWJ0eXBlcyBvZiBSTVMgdGhhdCBoYXZlIGRpc3RpbmN0IG11dGF0aW9uIGJ1cmRlbnMgYW5kIGRpZmZlcmVudGlhdGlvbiBzdGF0ZXMsIHNvIGl0J3MgbGlrZWx5IHRoYXQgdGhvc2UgZGlmZmVyZW5jZXMgY29udHJpYnV0ZSB0byBob3cgd2VsbCB0aGV5IGludGVncmF0ZS4KClRvIGV4cGxvcmUgd2hldGhlciBjZWxscyBhcmUgZ3JvdXBpbmcgdG9nZXRoZXIgYm90aCBieSBjZWxsIHR5cGUgYW5kIGJ5IFJNUyBzdWJ0eXBlLCB3ZSBjYW4gY3JlYXRlIGEgcGxvdCB0aGF0IGluY29ycG9yYXRlcyBib3RoIHBpZWNlcyBvZiBtZXRhZGF0YS4KV2Ugd2lsbCB0YWtlIGFkdmFudGFnZSBvZiB0aGUgYGZhY2V0X2dyaWQoKWAgZnVuY3Rpb24gZnJvbSBgZ2dwbG90MmAgdG8gbG9vayBhdCB0d28gdmFyaWFibGVzIGluIHRoZSBgY29sRGF0YWAgYXQgb25jZSAtIHRoZSBjZWxsIHR5cGUgYW5kIHRoZSBzdWJkaWFnbm9zaXMuCkluIHRoZSBiZWxvdyBwbG90IHdlIHdpbGwgY29sb3Igb3VyIGNlbGxzIGJ5IGNlbGwgdHlwZSB3aGlsZSBhbHNvIHVzaW5nIGBmYWNldF9ncmlkKClgIHNvIHRoYXQgY2VsbHMgZnJvbSBkaWZmZXJlbnQgc3ViZGlhZ25vc2VzIHdpbGwgYmUgaW4gdGhlaXIgb3duIHBsb3QgcGFuZWwuCgpgYGB7ciBjZWxsdHlwZSBzdWJkaWFnbm9zaXMgVU1BUCwgbGl2ZT1UUlVFfQojIFVNQVAgb2YgYWxsIHNhbXBsZXMKIyBzZXBhcmF0aW5nIGJ5IGRpYWdub3NpcyBncm91cCBhbmQgbGFiZWxpbmcgY2VsbCB0eXBlCnNjYXRlcjo6cGxvdFJlZHVjZWREaW0oaW50ZWdyYXRlZF9zY2UsCiAgICAgICAgICAgICAgICAgICAgICAgZGltcmVkID0gImZhc3Rtbm5fVU1BUCIsCiAgICAgICAgICAgICAgICAgICAgICAgIyBjb2xvciBlYWNoIHBvaW50IGJ5IGNlbGwgdHlwZQogICAgICAgICAgICAgICAgICAgICAgIGNvbG9yX2J5ID0gImNlbGx0eXBlX2Jyb2FkIiwKICAgICAgICAgICAgICAgICAgICAgICBwb2ludF9zaXplPSAwLjUsIAogICAgICAgICAgICAgICAgICAgICAgIHBvaW50X2FscGhhID0gMC40LAogICAgICAgICAgICAgICAgICAgICAgICMgdGVsbCBzY2F0ZXIgdG8gdXNlIGRpYWdub3Npc19ncm91cCBmb3IgcGxvdHRpbmcKICAgICAgICAgICAgICAgICAgICAgICBvdGhlcl9maWVsZHMgPSAiZGlhZ25vc2lzX2dyb3VwIikgKwogICMgaW5jbHVkZSBlYWNoIGRpYWdub3NpcyBncm91cCBhcyBpdHMgb3duIGNvbHVtbgogIGZhY2V0X2dyaWQoY29scyA9IHZhcnMoZGlhZ25vc2lzX2dyb3VwKSkKYGBgCgpBcyBleHBlY3RlZCwgd2Ugc2VlIHRoYXQgY2VsbCB0eXBlcyBhcmUgc2VwYXJhdGVkLCBtb3N0IGxpa2VseSBkdWUgdG8gZGlmZmVyZW50IFJNUyBzdWJ0eXBlcy4KCldlIGNhbiBhbHNvIHVzZSBhIHN0YWNrZWQgYmFycGxvdCB0byBsb29rIGF0IHRoZSBkaXN0cmlidXRpb24gb2YgY2VsbCB0eXBlcyBhY3Jvc3MgZWFjaCBzYW1wbGUsIHdoaWNoIHdpbGwgcmVxdWlyZSBhIGJpdCBvZiB3cmFuZ2xpbmcgZmlyc3QuCgpgYGB7ciBjZWxsdHlwZSBiYXJwbG90fQojIGZpbHRlciBjb2xkYXRhIHRvIG9ubHkgaW5jbHVkZSB0dW1vciBjZWxscwp0dW1vcl9jZWxsc19kZiA8LSBjb2xkYXRhX2RmIHw+CiAgIyBmaW5kIHJvd3Mgd2hlcmUgdGhlIGNlbGwgdHlwZSBuYW1lIGNvbnRhaW5zIHRoZSBzdHJpbmcgIlR1bW9yIgogIGRwbHlyOjpmaWx0ZXIoc3RyaW5ncjo6c3RyX2RldGVjdChjZWxsdHlwZV9icm9hZCwgIlR1bW9yIikpCgojIGNyZWF0ZSBhIHN0YWNrZWQgYmFycGxvdApnZ3Bsb3QodHVtb3JfY2VsbHNfZGYsIGFlcyh4ID0gc2FtcGxlLCBmaWxsID0gY2VsbHR5cGVfYnJvYWQpKSArIAogICAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZmlsbCIsIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDAuMikgKwogICAgbGFicygKICAgICAgeCA9ICJTYW1wbGUiLAogICAgICB5ID0gIlByb3BvcnRpb24gb2YgY2VsbHMiLCAKICAgICAgZmlsbCA9ICJDZWxsIHR5cGUiCiAgICApICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41KSkrCiAgIyBmYWNldCBieSBkaWFnbm9zaXMgZ3JvdXAgCiAgZmFjZXRfZ3JpZChjb2xzID0gdmFycyhkaWFnbm9zaXNfZ3JvdXApLCAKICAgICAgICAgICAgICMgb25seSBzaG93IG5vbi1OQSB2YWx1ZXMgb24geC1heGlzCiAgICAgICAgICAgICBzY2FsZXMgPSAiZnJlZV94IiwKICAgICAgICAgICAgIHNwYWNlID0gImZyZWVfeCIpCmBgYAoKU2ltaWxhciB0byB0aGUgVU1BUCwgdGhpcyBwbG90IHNob3dzIHRoYXQgQVJNUyBhbmQgRVJNUyBzaGFyZSBhIGxvdCBvZiB0aGUgc2FtZSBjZWxsIHR5cGVzLgoKV2UgYWxzbyBzZWUgdGhhdCBvbmx5IDYgb2YgdGhlc2UgbGlicmFyaWVzIGhhdmUgdHVtb3IgY2VsbHMgdGhhdCBoYXZlIGJlZW4gZnVydGhlciBjbGFzc2lmaWVkIGludG8gbWVzb2Rlcm0sIG15b2JsYXN0LCBhbmQgbXlvY3l0ZS4gCjMgbGlicmFyaWVzIGNvbnRhaW4gY2VsbHMgdGhhdCBhcmUgb25seSBjbGFzc2lmaWVkIGFzIHR1bW9yIG9yIG5vbi10dW1vciwgYW5kIHR1bW9yIGNlbGxzIGFyZSBub3QgZnVydGhlciBjbGFzc2lmaWVkLCBhbmQgdGhlIHJlbWFpbmluZyBsaWJyYXJ5IGlzIG5vdCBldmVuIHByZXNlbnQgaW4gb3VyIHBsb3QgYmVjYXVzZSBpdCB3YXMgbm90IGFzc2lnbmVkIGFueSBjZWxsIHR5cGVzIChhbGwgYXJlIGBOQWApLgpXZSB3aWxsIGNvbnRpbnVlIG91ciBhbmFseXNpcyBvbmx5IHVzaW5nIHRoZSA2IGxpYnJhcmllcyB3aXRoIGZ1bGx5IGNsYXNzaWZpZWQgY2VsbCB0eXBlcywgcmVtb3ZpbmcgdGhlIG90aGVyIDQgYmVmb3JlIHdlIHByb2NlZWQgd2l0aCBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbi4KCiMjIyBGaWx0ZXJpbmcgc2FtcGxlcwoKVGhlIHJlYXNvbiB3ZSB3YW50IHRvIHBhcmUgZG93biBvdXIgbGlzdCBvZiBzYW1wbGVzIHRvIGNvbnNpZGVyIGlzIHRoYXQgd2Ugd2FudCB0byBlbnN1cmUgdGhhdCB0aGUgY2VsbCB0eXBlcyAob3Igc3VicG9wdWxhdGlvbnMpIHRoYXQgd2UgYXJlIGludGVyZXN0ZWQgaW4gYXJlIHByZXNlbnQgaW4gYWxsIHNhbXBsZXMgaW5jbHVkZWQgaW4gb3VyIERFIGFuYWx5c2lzLiAKV2Ugd2FudCB0byByZW1vdmUgYW55IHNhbXBsZXMgdGhhdCBkbyBub3QgY29udGFpbiBvdXIgY2VsbCBwb3B1bGF0aW9uKHMpIG9mIGludGVyZXN0IGFzIHRoZXkgaGF2ZSBubyBjb3VudHMgdG8gY29udHJpYnV0ZSB0byB0aGUgREUgYW5hbHlzaXMuCgpgYGB7ciBzdWJzZXQgc2NlfQojIGRlZmluZSBzYW1wbGVzIHRvIGtlZXAKbGlicmFyeV9pZHMgPC0gYygKICAiU0NQQ0wwMDA0NzkiLAogICJTQ1BDTDAwMDQ4MCIsCiAgIlNDUENMMDAwNDgxIiwKICAiU0NQQ0wwMDA0ODQiLAogICJTQ1BDTDAwMDQ4OCIsCiAgIlNDUENMMDAwNDkxIgopCgojIHN1YnNldCBzY2UgdG8gb25seSBjb250YWluIHNhbXBsZXMgb2YgaW50ZXJlc3QgCnNhbXBsZXNfdG9fa2VlcCA8LSBpbnRlZ3JhdGVkX3NjZSRzYW1wbGUgJWluJSBsaWJyYXJ5X2lkcwpybXNfc2NlIDwtIGludGVncmF0ZWRfc2NlWywgc2FtcGxlc190b19rZWVwXQoKIyBwcmludCBvdXQgb3VyIG5ldyBTQ0UgCnJtc19zY2UKYGBgCgpCZWZvcmUgd2UgbW92ZSBvbiwgd2UnbGwgcmVtb3ZlIHRoZSBvcmlnaW5hbCBpbnRlZ3JhdGVkIG9iamVjdCBmcm9tIG91ciBlbnZpcm9ubWVudCB0byBzYXZlIHNvbWUgbWVtb3J5LiAKCmBgYHtyIHJlbW92ZSBzY2V9CnJtKGludGVncmF0ZWRfc2NlKQpgYGAKCldlIHdpbGwgYWxzbyBzYXZlIG91ciBuZXcgb2JqZWN0IGluIGNhc2Ugd2Ugd2FudCB0byB1c2UgaXQgZm9yIG90aGVyIGFuYWx5c2lzIGxhdGVyIG9uLgoKYGBge3Igc2F2ZSBzY2V9CiMgd3JpdGUgUkRTIGZpbGUgd2l0aCBjb21wcmVzc2lvbgpyZWFkcjo6d3JpdGVfcmRzKHJtc19zY2UsIGZpbGUgPSBvdXRwdXRfc2NlX2ZpbGUsIGNvbXByZXNzID0gImd6IikKYGBgCgpXZSBub3cgaGF2ZSBhbiB1cGRhdGVkIFNDRSBvYmplY3QgdGhhdCBjb250YWlucyA2IHNhbXBsZXMgdGhhdCB3ZXJlIG9idGFpbmVkIGZyb20gYSBtaXggb2YgQVJNUyBhbmQgRVJNUyBwYXRpZW50cy4KV2UgY2FuIHRoZW4gYXNrIHRoZSBxdWVzdGlvbiwgZG8gc3BlY2lmaWMgdHVtb3IgY2VsbCB0eXBlcyBjb250YWluIHNldHMgb2YgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIGJldHdlZW4gQVJNUyBhbmQgRVJNUyBzYW1wbGVzPwoKV2Ugc2hvdWxkIG1ha2Ugc3VyZSB0aGF0IHdlIGhhdmUgZW5vdWdoIGJpb2xvZ2ljYWwgcmVwbGljYXRlcyBmcm9tIGVhY2ggZ3JvdXAgdG8gc2V0IHVwIG91ciBleHBlcmltZW50LiAKSXQgaXMgaW1wZXJhdGl2ZSB0byBjb25zaWRlciBnb29kIGV4cGVyaW1lbnRhbCBkZXNpZ24gYW5kIGVuc3VyZSB0aGF0IHdlIGhhdmUgZW5vdWdoIGJpb2xvZ2ljYWwgcmVwbGljYXRlcyAoYXQgbGVhc3QgMyBmb3IgZWFjaCBncm91cCkgd2hlbiBwZXJmb3JtaW5nIGRpZmZlcmVudGlhbCBnZW5lIGV4cHJlc3Npb24gYW5hbHlzaXMuCgpJZiB3ZSBsb29rIGJhY2sgYXQgb3VyIHN0YWNrZWQgYmFycGxvdCB3ZSBzZWUgdGhhdCB3ZSBwaWNrZWQgMyBBUk1TIGFuZCAzIEVSTVMgc2FtcGxlcy4KV2UgY2FuIGFsc28gc2VlIHRoYXQgdGhlIG1ham9yaXR5IG9mIGNlbGxzIGFyZSB0dW1vciBjZWxscywgaW4gcGFydGljdWxhciB0aGUgbGFyZ2VzdCBwb3B1bGF0aW9uIG9mIGNlbGxzIGFwcGVhcnMgdG8gYmUgdGhlIGBUdW1vcl9NeW9ibGFzdGAuIApGb3IgdGhpcyBleGFtcGxlIHdlIHdpbGwgZm9jdXMgb24gaWRlbnRpZnlpbmcgREUgZ2VuZXMgaW4gdGhlc2UgYFR1bW9yX015b2JsYXN0YCBjZWxscywgYnV0IHRoZSBwcmluY2lwbGVzIGFwcGxpZWQgYmVsb3cgY2FuIGJlIGFwcGxpZWQgdG8gYW55IGNlbGwgdHlwZXMgb3Igc3VicG9wdWxhdGlvbnMgb2YgaW50ZXJlc3QuCgojIyBEaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcwoKTm93IHdlIGFyZSByZWFkeSB0byBzdGFydCBwcmVwYXJpbmcgZm9yIG91ciBERSBhbmFseXNpcywgd2hlcmUgd2Ugd2lsbCBjb21wYXJlIHRoZSBnZW5lIGV4cHJlc3Npb24gb2YgdHVtb3IgbXlvYmxhc3QgY2VsbHMgYmV0d2VlbiBBUk1TIGFuZCBFUk1TIHNhbXBsZXMuCgpUaHJvdWdob3V0IHRoZSBub3RlYm9vayB3ZSBoYXZlIGJlZW4gd29ya2luZyB3aXRoIGFuIGludGVncmF0ZWQgZGF0YXNldCB0aGF0IGNvbnRhaW5zIGNvcnJlY3RlZCBnZW5lIGV4cHJlc3Npb24gZGF0YSAoYGZhc3Rtbm5fY29ycmVjdGVkYCBhc3NheSkgYW5kIGEgY29ycmVjdGVkIFVNQVAuCkFzIGEgcmVtaW5kZXIsIHRoZSB1bmNvcnJlY3RlZCBnZW5lIGV4cHJlc3Npb24gZGF0YSwgZm91bmQgaW4gdGhlIGBjb3VudHNgIGFuZCBgbG9nY291bnRzYCBhc3NheXMsIGNvcnJlc3BvbmQgdG8gZGF0YSB0aGF0IGhhcyBiZWVuIG1lcmdlZCAodGhlIGZpcnN0IHN0ZXAgd2Ugd2Fsa2VkIHRocm91Z2ggcHJpb3IgdG8gaW50ZWdyYXRpb24pIGludG8gdGhlIHNhbWUgU0NFIGJ1dCBub3QgeWV0IGludGVncmF0ZWQuCldlIGRvIG5vdCB3YW50IHRvIHVzZSBjb3JyZWN0ZWQgZ2VuZSBleHByZXNzaW9uIHZhbHVlcyBmb3IgZGlmZmVyZW50aWFsIGV4cHJlc3Npb247IGBERVNlcTJgIGV4cGVjdHMgdGhlIG9yaWdpbmFsIHJhdyBjb3VudHMgYXMgaW5wdXQgc28gd2Ugd2lsbCBiZSB1c2luZyBkYXRhIGZvdW5kIGluIHRoZSBgY291bnRzYCBhc3NheSBvZiB0aGUgYFNpbmdsZUNlbGxFeHBlcmltZW50YCBvYmplY3QuIAoKSXQgaXMgYWR2aXNlZCB0byBvbmx5IHVzZSB0aGUgY29ycmVjdGVkIHZhbHVlcyBmb3IgYW55IGFuYWx5c2VzIGJlaW5nIHBlcmZvcm1lZCBhdCB0aGUgY2VsbCBsZXZlbCwgZS5nLiwgZGltZW5zaW9uYWxpdHkgcmVkdWN0aW9uLgpJbiBjb250cmFzdCwgaXQgaXMgbm90IGFkdmlzZWQgdG8gdXNlIGNvcnJlY3RlZCB2YWx1ZXMgZm9yIGFueSBhbmFseXNlcyB0aGF0IGFyZSBnZW5lLWJhc2VkLCBzdWNoIGFzIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIG9yIG1hcmtlciBnZW5lIGRldGVjdGlvbiwgYmVjYXVzZSB3aXRoaW4tYmF0Y2ggYW5kIGJldHdlZW4tYmF0Y2ggZ2VuZSBleHByZXNzaW9uIGRpZmZlcmVuY2VzIGFyZSBubyBsb25nZXIgcHJlc2VydmVkLgpUaGUgcmVhc29uIGZvciB0aGlzIGlzIHR3by1mb2xkIOKAkyBtYW55IG9mIHRoZSBERSBtb2RlbHMgd2lsbCBleHBlY3QgdW5jb3JyZWN0ZWQgY291bnRzIGJlY2F1c2UgdGhleSB3aWxsIGFjY291bnQgZm9yIGJldHdlZW4tc2FtcGxlIHZhcmlhdGlvbiB3aXRoaW4gdGhlIG1vZGVsLCBhbmQgd2Ugd2FudCB0byBlbnN1cmUgd2UgYXJlIHByZXNlcnZpbmcgdmFyaWF0aW9uIHRoYXQgaXMgcHJlc2VudCBzbyBhcyBub3QgdG8gYXJ0aWZpY2lhbGx5IGluZmxhdGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBwb3B1bGF0aW9ucy4KU2VlIHRoZSBbT1NDQSBjaGFwdGVyIG9uIFVzaW5nIHRoZSBjb3JyZWN0ZWQgdmFsdWVzXShodHRwczovL2Jpb2NvbmR1Y3Rvci5vcmcvYm9va3MvMy4xNi9PU0NBLm11bHRpc2FtcGxlL3VzaW5nLWNvcnJlY3RlZC12YWx1ZXMuaHRtbCN1c2luZy1jb3JyZWN0ZWQtdmFsdWVzKSBmb3IgbW9yZSBpbnNpZ2h0LgoKIyMjIFBzZXVkby1idWxraW5nIAoKQmVmb3JlIHdlIGNhbiBjb21wYXJlIHRoZSBnZW5lIGV4cHJlc3Npb24gcHJvZmlsZXMgb2YgbXlvYmxhc3RzIGluIEFSTVMgdnMuIEVSTVMgc2FtcGxlcywgd2Ugd2lsbCBuZWVkIHRvICJwc2V1ZG8tYnVsayIgdGhlIGdlbmUgY291bnRzLiAKUHNldWRvLWJ1bGtpbmcgY3JlYXRlcyBhIG5ldyBjb3VudHMgbWF0cml4IHRoYXQgY29udGFpbnMgdGhlIHN1bSBvZiB0aGUgY291bnRzIGZyb20gYWxsIGNlbGxzIHdpdGggYSBnaXZlbiBsYWJlbCAoZS5nLiwgY2VsbCB0eXBlKSBmb3IgZWFjaCBzYW1wbGUgKFtUdW5nIF9ldCBhbC5fIDIwMTddKGh0dHBzOi8vZG9pLm9yZy8xMC4xMDM4L3NyZXAzOTkyMSkpLiAKSWYgd2Ugd2VyZSB0byBrZWVwIGVhY2ggY2VsbCdzIGNvdW50cyBzZXBhcmF0ZSwgdGhleSB3b3VsZCBiZSB0cmVhdGVkIGFzIHJlcGxpY2F0ZXMsIGxlYWRpbmcgdG8gaW5mbGF0ZWQgc3RhdGlzdGljcy4gCkJ5IHBzZXVkby1idWxraW5nIGZpcnN0LCB3ZSB3aWxsIG5vdyBoYXZlIG9uZSBjb3VudCBmb3IgZWFjaCBnZW5lIGZvciBlYWNoIHNhbXBsZSBhbmQgd2UgY2FuIHRha2UgYWR2YW50YWdlIG9mIHdlbGwtZXN0YWJsaXNoZWQgbWV0aG9kcyBmb3IgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gd2l0aCBidWxrIFJOQS1zZXEuCgpQc2V1ZG8tYnVsa2luZyBpcyBpbXBsZW1lbnRlZCBwcmlvciB0byBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcyBvbiBzaW5nbGUtY2VsbCBkYXRhIGJlY2F1c2UgaXQ6IAoKLSBQcm9kdWNlcyBsYXJnZXIgYW5kIGxlc3Mgc3BhcnNlIGNvdW50cywgd2hpY2ggYWxsb3dzIHVzIHRvIHVzZSBzdGFuZGFyZCBub3JtYWxpemF0aW9uIGFuZCBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBtZXRob2RzIHVzZWQgYnkgYnVsayBSTkEtc2VxLiAKLSBDb2xsYXBzZXMgZ2VuZSBleHByZXNzaW9uIGNvdW50cyBieSBzYW1wbGUsIHNvIHRoYXQgc2FtcGxlcywgcmF0aGVyIHRoYW4gY2VsbHMsIHJlcHJlc2VudCByZXBsaWNhdGVzLgotIE1hc2tzIHZhcmlhbmNlIHdpdGhpbiBhIHNhbXBsZSB0byBlbXBoYXNpemUgdmFyaWFuY2UgYWNyb3NzIHNhbXBsZXMuClRoaXMgY2FuIGJlIGJvdGggZ29vZCBhbmQgYmFkISAKTWFza2luZyBpbnRyYS1zYW1wbGUgdmFyaWF0aW9uIG1lYW5zIHlvdSBtaWdodCBub3QgaWRlbnRpZnkgZ2VuZXMgd2hlcmUgYXZlcmFnZSBleHByZXNzaW9uIGRvZXNuJ3QgY2hhbmdlIGJldHdlZW4gc2FtcGxlcyBidXQgdGhlIGRlZ3JlZSBvZiBjZWxsLXRvLWNlbGwgdmFyaWF0aW9uIGRvZXMuCgpCZWZvcmUgd2UgYXBwbHkgcHNldWRvLWJ1bGtpbmcgdG8gb3VyIGRhdGFzZXQsIGxldCdzIGxvb2sgYXQgYSBzaW1wbGUgZXhhbXBsZSBvZiBob3cgcHNldWRvLWJ1bGtpbmcgd29ya3MuCldlJ2xsIHN0YXJ0IGJ5IGNyZWF0aW5nIGEgZmFrZSBtYXRyaXggb2YgY291bnRzLgoKYGBge3IgY3JlYXRlIG1hdHJpeH0KIyBjcmVhdGUgYW4gZXhhbXBsZSBjb3VudHMgbWF0cml4CmNvdW50c19tdHggPC0gbWF0cml4KAogIDE6MTIsIAogIG5jb2wgPSA0LAogIGRpbW5hbWVzID0gbGlzdChjKCJnZW5lQSIsICJnZW5lQiIsICJnZW5lQyIpLAogICAgICAgICAgICAgICAgICBjKCJBLWNlbGwxIiwgIkEtY2VsbDIiLCAiQi1jZWxsMSIsICJCLWNlbGwyIikpCikKY291bnRzX210eApgYGAKCk5leHQgd2Ugd2lsbCBjcmVhdGUgYSBwc2V1ZG8tYnVsa2VkIHZlcnNpb24gb2YgdGhpcyBtYXRyaXggd2l0aCBvbmx5IDIgY29sdW1uczogMSBmb3IgZ3JvdXAgYEFgIGFuZCAxIGZvciBncm91cCBgQmAuClRvIGRvIHRoaXMgd2Ugd2lsbCB1c2UgdGhlIGBEZWxheWVkQXJyYXk6OmNvbHN1bSgpYCBmdW5jdGlvbiwgd2hpY2ggYWxsb3dzIHVzIHRvIHN1bSB0aGUgY291bnRzIGZvciBlYWNoIHJvdyBhY3Jvc3MgZ3JvdXBzIG9mIGNvbHVtbnMuCgpgYGB7ciBwc2V1ZG9idWxrIG1hdHJpeCwgbGl2ZT1UUlVFfQojIGRlZmluZSB0aGUgZ3JvdXAgdGhhdCBlYWNoIGNvbHVtbiBiZWxvbmdzIHRvCmdyb3VwcyA8LSBjKCJBIiwgIkEiLCAiQiIsICJCIikKCiMgc3VtIGNvdW50cyBhY3Jvc3MgY2VsbHMgKGNvbHVtbnMpIGJ5IGdyb3VwIGxhYmVsCnBiX2NvdW50cyA8LSBEZWxheWVkQXJyYXk6OmNvbHN1bShjb3VudHNfbXR4LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwcykKcGJfY291bnRzICAKYGBgCgpMb29raW5nIGF0IHRoaXMgb3V0cHV0LCB5b3Ugc2hvdWxkIHNlZSB0aGF0IHRoZSBvcmlnaW5hbCA0IGNvbHVtbnMgaGF2ZSBiZWVuIGNvbmRlbnNlZCB0byBvbmx5IDIgY29sdW1uczogMSBjb2x1bW4gdG8gcmVwcmVzZW50IGFsbCBjZWxscyBmcm9tIGdyb3VwIGBBYCwgYW5kIDEgY29sdW1uIHRvIHJlcHJlc2VudCBhbGwgY2VsbHMgZnJvbSBncm91cCBgQmAuCgpOb3cgdGhlIGFjdHVhbCBwc2V1ZG8tYnVsa2luZyBmb3Igb3VyIGRhdGFzZXQhIAoKV2Ugd2lsbCB1c2UgdGhlIFtgc2N1dHRsZTo6YWdncmVnYXRlQWNyb3NzQ2VsbHMoKWAgZnVuY3Rpb25dKGh0dHBzOi8vcmRyci5pby9naXRodWIvTFRMQS9zY3V0dGxlL21hbi9hZ2dyZWdhdGVBY3Jvc3NDZWxscy5odG1sKSB0byBwc2V1ZG8tYnVsayBvdXIgZGF0YXNldC4KVGhpcyBmdW5jdGlvbiB0YWtlcyBhcyBpbnB1dCBhbiBTQ0Ugb2JqZWN0IGFuZCB0aGUgZ3JvdXBpbmcgYXNzaWdubWVudHMgZm9yIGVhY2ggY2VsbC4KVGhlIG91dHB1dCB3aWxsIGJlIGFuIFNDRSBvYmplY3QgdGhhdCBjb250YWlucyBvbmx5IHRoZSBwc2V1ZG8tYnVsa2VkIGNvdW50cyBmb3IgYWxsIGdlbmVzIGFjcm9zcyBhbGwgc3BlY2lmaWVkIGdyb3VwcywgcmF0aGVyIHRoYW4gYWNyb3NzIGFsbCBjZWxscy4gCldlIGNhbiB0aGVuIHN1YnNldCB0aGlzIFNDRSB0byBqdXN0IGluY2x1ZGUgb3VyIGNlbGwgdHlwZSBvZiBpbnRlcmVzdCAodHVtb3IgbXlvYmxhc3RzKSBmb3IgaW5wdXQgdG8gdGhlIERFIGFuYWx5c2lzLiAKCldlIGNhbiBwc2V1ZG8tYnVsayB1c2luZyBhbnkgZ3JvdXBpbmcgdGhhdCB3ZSBhcmUgaW50ZXJlc3RlZCBpbi4KRm9yIHJpZ2h0IG5vdywgd2UgYXJlIGludGVyZXN0ZWQgaW4gbG9va2luZyBhdCBnZW5lIGV4cHJlc3Npb24gYWNyb3NzIGNlbGwgdHlwZXMsIHNvIHdlIHdhbnQgdG8gZ3JvdXAgdGhlIHBzZXVkby1idWxrZWQgY291bnRzIG1hdHJpeCBieSBib3RoIGNlbGwgdHlwZSBhbmQgb3JpZ2luYWwgc2FtcGxlLiAKCmBgYHtyIHBzZXVkb2J1bGsgc2NlfQojIGZpcnN0IHN1YnNldCB0aGUgY29sZGF0YSAKIyB0byBvbmx5IGhhdmUgdGhlIGNvbHVtbnMgd2UgY2FyZSBhYm91dCBmb3IgcHNldWRvLWJ1bGtpbmcgCnBiX2dyb3VwcyA8LSBjb2xEYXRhKHJtc19zY2UpWywgYygiY2VsbHR5cGVfYnJvYWQiLCAic2FtcGxlIildCgojIGNyZWF0ZSBhIG5ldyBTQ0Ugb2JqZWN0IHRoYXQgY29udGFpbnMgCiMgdGhlIHBzZXVkby1idWxrZWQgY291bnRzIGFjcm9zcyB0aGUgcHJvdmlkZWQgZ3JvdXBzIApwYl9zY2UgPC0gc2N1dHRsZTo6YWdncmVnYXRlQWNyb3NzQ2VsbHMocm1zX3NjZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZCA9IHBiX2dyb3VwcykKCiMgY29sdW1uIG5hbWVzIGFyZW4ndCBhdXRvbWF0aWNhbGx5IGFkZGVkIHRvIHRoZSBwc2V1ZG8tYnVsa2VkIHNjZSwgCiMgc28gbGV0J3MgYWRkIHRoZW0gaW4gCmNvbG5hbWVzKHBiX3NjZSkgPC0gZ2x1ZTo6Z2x1ZSgKICAie3BiX3NjZSRjZWxsdHlwZV9icm9hZH1fe3BiX3NjZSRzYW1wbGV9IgopCgpwYl9zY2UKYGBgCgpIb3cgZG9lcyB0aGUgbmV3IHBzZXVkby1idWxrZWQgYFNpbmdsZUNlbGxFeHBlcmltZW50YCBsb29rIGRpZmZlcmVudD8gCkhvdyBtYW55IGNvbHVtbnMgZG9lcyBpdCBoYXZlPyAKCkxldCdzIHRha2UgYSBsb29rIGF0IHdoYXQgdGhlIGBjb2xEYXRhYCBsb29rcyBsaWtlIGluIHRoZSBwc2V1ZG8tYnVsa2VkIFNDRSBvYmplY3QuIAoKYGBge3IgcHNldWRvYnVsayBjb2xEYXRhLCBsaXZlPVRSVUV9CiMgbm90ZSB0aGUgbmV3IGNvbHVtbiB3aXRoIG51bWJlciBvZiBjZWxscyBwZXIgZ3JvdXAgCmhlYWQoY29sRGF0YShwYl9zY2UpKSB8PgogIGFzLmRhdGEuZnJhbWUoKQpgYGAKCllvdSBzaG91bGQgc2VlIHRoYXQgY29sdW1ucyBzdWNoIGFzIGBzdW1gLCBgZGV0ZWN0ZWRgLCBgc3Vic2V0c19taXRvX3N1bWAsIGFuZCBvdGhlciBjb2x1bW5zIHRoYXQgdHlwaWNhbGx5IGNvbnRhaW4gcGVyIGNlbGwgUUMgc3RhdGlzdGljcyBub3cgY29udGFpbiBgTkFgIHJhdGhlciB0aGFuIG51bWVyaWMgdmFsdWVzLiAKVGhpcyBpcyBiZWNhdXNlIHRoZXNlIHZhbHVlcyB3ZXJlIGluaXRpYWxseSBjYWxjdWxhdGVkIG9uIGEgcGVyIGNlbGwgbGV2ZWwgKHdlIGRpZCB0aGlzIHVzaW5nIGBzY3V0dGxlOjphZGRQZXJDZWxsUUNNZXRyaWNzKClgKSwgYnV0IHdlIG5vIGxvbmdlciBoYXZlIGEgc2luZ2xlIGNvbHVtbiBwZXIgY2VsbC4KSW5zdGVhZCwgZWFjaCBjb2x1bW4gbm93IHJlcHJlc2VudHMgYSBfZ3JvdXBfIG9mIGNlbGxzLCBpbiB0aGlzIGNhc2UgY29tcHJpc2VkIG9mIGNlbGxzIG9mIGEgZ2l2ZW4gY2VsbCB0eXBlIGFuZCBzYW1wbGUgY29tYmluYXRpb24uClRoZXJlZm9yZSwgdGhlIHZhbHVlcyB0aGF0IHdlIGNhbGN1bGF0ZWQgb24gYSBwZXItY2VsbCBsZXZlbCBhcmUgbm8gbG9uZ2VyIGFwcGxpY2FibGUgdG8gdGhpcyBwc2V1ZG8tYnVsa2VkIFNDRSBvYmplY3QuCgpZb3Ugc2hvdWxkIGFsc28gc2VlIGEgbmV3IGNvbHVtbiB0aGF0IHdhc24ndCBwcmVzZW50IHByZXZpb3VzbHksIHRoZSBgbmNlbGxzYCBjb2x1bW4uClRoaXMgY29sdW1uIHdhcyBhZGRlZCBkdXJpbmcgcHNldWRvLWJ1bGtpbmcgYW5kIGluZGljYXRlcyB0aGUgdG90YWwgbnVtYmVyIG9mIGNlbGxzIHRoYXQgd2VyZSBzdW1tZWQgdG9nZXRoZXIgdG8gZm9ybSBlYWNoIGNvbHVtbiBvZiB0aGUgU0NFIG9iamVjdC4KCkJlZm9yZSB3ZSBwcm9jZWVkIHdlIHdpbGwgd2FudCB0byBmaWx0ZXIgb3V0IGFueSBjb2x1bW5zIHRoYXQgaGF2ZSBhIGxvdyBudW1iZXIgb2YgY2VsbHMuCkEgbG93IG51bWJlciBvZiBjZWxscyB3aWxsIHVzdWFsbHkgcmVzdWx0IGluIHNtYWxsIGNvdW50cyB0aGF0IGNhbiBjYXVzZSBpc3N1ZXMgd2l0aCB0aGUgc3RhdGlzdGljYWwgYXBwcm94aW1hdGlvbnMgbWFkZSBkdXJpbmcgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMuClRoaXMgaXMgZXF1aXZhbGVudCB0byBmaWx0ZXJpbmcgb3V0IGFueSBsaWJyYXJpZXMgaW4gYnVsayBSTkEtc2VxIGFuYWx5c2lzIHRoYXQgaGF2ZSBsb3cgbGlicmFyeSBzaXplcy4KCldlIGNhbiBzZXQgYSB0aHJlc2hvbGQgZm9yIHRoZSBudW1iZXIgb2YgY2VsbHMgcmVxdWlyZWQgdG8gY29udGludWUgd2l0aCBvdXIgYW5hbHlzaXMgYW5kIHJlbW92ZSBhbnkgZ3JvdXBzIHRoYXQgZG8gbm90IG1lZXQgdGhlIG1pbmltdW0gdGhyZXNob2xkLgpIZXJlIHdlIHdpbGwgdXNlIDEwLCBidXQgdGhlIHRocmVzaG9sZCB5b3UgdXNlIGZvciB5b3VyIGRhdGFzZXQgY2FuIHZhcnkgZGVwZW5kaW5nIG9uIHRoZSBjb21wb3NpdGlvbiBvZiBjZWxsIHR5cGVzLgoKYGBge3IgZmlsdGVyIHBzZXVkb2J1bGssIGxpdmU9VFJVRX0KIyByZW1vdmUgYW55IGdyb3VwcyB3aXRoIGZld2VyIHRoYW4gMTAgY2VsbHMKZmlsdGVyX3BiX3NjZSA8LSBwYl9zY2VbLCBwYl9zY2UkbmNlbGxzID49IDEwXQpgYGAKCldlIGNhbiB0aGVuIHRha2UgYSBsb29rIGFuZCBzZWUgaG93IG1hbnkgY2VsbCB0eXBlLXNhbXBsZSBjb2x1bW5zIHdlIHJlbW92ZWQsIGlmIGFueS4KCmBgYHtyIHByaW50IGRpbSwgbGl2ZT1UUlVFfQojIHByaW50IG91dCBkaW1lbnNpb25zIG9mIHVuZmlsdGVyZWQgcHNldWRvYnVsayBzY2UKZGltKHBiX3NjZSkKCiMgZGltZW5zaW9ucyBvZiBmaWx0ZXJlZCBwc2V1ZG9idWxrIHNjZSAKZGltKGZpbHRlcl9wYl9zY2UpCmBgYAoKSXQgbG9va3MgbGlrZSB3ZSBvbmx5IGdvdCByaWQgb2Ygb25lIGdyb3VwLgpXZSBjYW4gZG8gYSBxdWljayBjaGVjayB0byBzZWUgd2hpY2ggZ3JvdXAgd2FzIHJlbW92ZWQgYnkgZmluZGluZyB3aGljaCBjb2x1bW4gaXMgbm8gbG9uZ2VyIHByZXNlbnQgaW4gdGhlIGZpbHRlcmVkIG9iamVjdC4KCmBgYHtyIHJlbW92ZWQgY29sdW1ucywgbGl2ZT1UUlVFfQojIGZpbmQgcmVtb3ZlZCBjb2x1bW5zCnJlbW92ZWRfY29scyA8LSAhKGNvbG5hbWVzKHBiX3NjZSkgJWluJSBjb2xuYW1lcyhmaWx0ZXJfcGJfc2NlKSkKCiMgcHJpbnQgb3V0IG1pc3NpbmcgY29sdW1ucwpjb2xuYW1lcyhwYl9zY2UpW3JlbW92ZWRfY29sc10KYGBgCgpUaGUgbGFzdCBzdGVwIHdlIHdhbnQgdG8gZG8gdG8gcHJlcGFyZSBvdXIgZGF0YXNldCBmb3IgREUgaXMgdG8gc3Vic2V0IHRoZSBwc2V1ZG8tYnVsa2VkIFNDRSBvYmplY3QgdG8gY29udGFpbiBvbmx5IHRoZSBjZWxsIHR5cGUgdGhhdCB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBjb21wYXJpbmcgYWNyb3NzIHRoZSB0d28gUk1TIHN1YnR5cGVzLgpBcyBtZW50aW9uZWQgcHJldmlvdXNseSwgd2UgYXJlIHNwZWNpZmljYWxseSBpbnRlcmVzdGVkIGluIHRoZSBgVHVtb3JfTXlvYmxhc3RgIGNlbGwgdHlwZS4KCmBgYHtyIGZpbHRlciBjZWxsdHlwZX0KIyBsb2dpY2FsIHZlY3RvciBpbmRpY2F0aW5nIGlmIGNlbGxzIGFyZSB0dW1vciBteW9ibGFzdCBvciBub3QKbXlvYmxhc3RfY2VsbHMgPC0gZmlsdGVyX3BiX3NjZSRjZWxsdHlwZV9icm9hZCA9PSAiVHVtb3JfTXlvYmxhc3QiCgojIGNyZWF0ZSBhIG5ldyBzY2Ugd2l0aCBvbmx5IHRoZSB0dW1vciBteW9ibGFzdHMKdHVtb3JfbXlvYmxhc3Rfc2NlIDwtIGZpbHRlcl9wYl9zY2VbLCBteW9ibGFzdF9jZWxsc10KYGBgCgpBZnRlciBmaWx0ZXJpbmcgZm9yIG91ciBjZWxsIHR5cGUgb2YgaW50ZXJlc3Qgd2Ugc2hvdWxkIGhhdmUgYSBkYXRhc2V0IHdpdGggNiBjb2x1bW5zLCAxIGZvciBlYWNoIGdyb3VwIG9mIGBUdW1vcl9NeW9ibGFzdGAgY2VsbHMgaW4gZWFjaCBvZiBvdXIgNiBzYW1wbGVzLgoKIyMjIFBlcmZvcm0gZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gd2l0aCBgREVTZXEyYAoKTm93IHdlIHdpbGwgdXNlIHRoZSBgREVTZXEyYCBwYWNrYWdlIHRvIHBlcmZvcm0gZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gKERFKSBhbmFseXNpcyBvbiBvdXIgcHNldWRvLWJ1bGtlZCBTQ0Ugb2JqZWN0LgpGcm9tIHRoaXMgcG9pbnQsIHdlIGNhbiBwcm9jZWVkIGluIHRoZSBzYW1lIHdheSB3ZSB3b3VsZCBpZiB3ZSBoYWQgYSBidWxrIFJOQS1zZXEgZGF0YXNldCB3aXRoIDYgc2FtcGxlcy4KV2Ugd2lsbCBzdGFydCB3aXRoIHRoZSB1bm5vcm1hbGl6ZWQgcmF3IGNvdW50cyBpbiB0aGUgYGNvdW50c2AgYXNzYXkgb2YgdGhlIHBzZXVkby1idWxrZWQgU0NFIGFuZCBkbyB0aGUgZm9sbG93aW5nIHdpdGggYERFU2VxMmA6CgotIENyZWF0ZSBhIGBERVNlcURhdGFTZXRgIG9iamVjdAotIE5vcm1hbGl6ZSBhbmQgbG9nIHRyYW5zZm9ybSB0aGUgY291bnRzIGRhdGEKLSBFc3RpbWF0ZSBkaXNwZXJzaW9ucyBhbmQgc2hyaW5rIGVzdGltYXRlcwotIEZpdCBhIG5lZ2F0aXZlIGJpbm9taWFsIG1vZGVsIGFuZCBwZXJmb3JtIGh5cG90aGVzaXMgdGVzdGluZyB1c2luZyBXYWxkIHN0YXRpc3RpY3MKCllvdSBjYW4gYWxzbyByZWZlciB0byBvdXIgW21hdGVyaWFscyBmcm9tIG91ciBwcmV2aW91cyB3b3Jrc2hvcHMgY292ZXJpbmcgYnVsayBSTkEtc2VxXShodHRwczovL2dpdGh1Yi5jb20vQWxleHNMZW1vbmFkZS90cmFpbmluZy1tb2R1bGVzL3RyZWUvbWFzdGVyL1JOQS1zZXEjcmVhZG1lKSBmb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiB1c2luZyBgREVTZXFgLgoKIyMjIyBDcmVhdGUgdGhlIGBERVNlcURhdGFTZXRgIG9iamVjdAoKVG8gY3JlYXRlIHRoZSBgREVTZXFEYXRhU2V0YCBvYmplY3Qgd2Ugd2lsbCBuZWVkIHRoZSB1bm5vcm1hbGl6ZWQgY291bnRzIG1hdHJpeCwgdGhlIG1ldGFkYXRhIGFzc29jaWF0ZWQgd2l0aCB0aGUgc2FtcGxlcywgYW5kIGEgZGVzaWduIGZvcm11bGEuClRoZSBmaXJzdCB0d28gaXRlbXMgYXJlIGFscmVhZHkgc3RvcmVkIGluIG91ciBTQ0Ugb2JqZWN0LCBzbyB3ZSBjYW4gY3JlYXRlIGEgYERFU2VxRGF0YVNldGAgb2JqZWN0IGRpcmVjdGx5IGZyb20gdGhhdCBvYmplY3QgdXNpbmcgdGhlIGBERVNlcURhdGFTZXQoKWAgZnVuY3Rpb24uClRoZSBkZXNpZ24gZm9ybXVsYSBpcyB1c2VkIHRvIGluZGljYXRlIHdoaWNoIGNvbHVtbnMgb2YgdGhlIG1ldGFkYXRhIG5lZWQgdG8gYmUgY29uc2lkZXJlZCBpbiB0aGUgREUgY29tcGFyaXNvbi4KRm9yIG91ciBleHBlcmltZW50IHdlIGFyZSBjb21wYXJpbmcgZ2VuZSBleHByZXNzaW9uIGJldHdlZW4gZGlmZmVyZW50IFJNUyBzdWJ0eXBlcy4KVGhlIHN1YnR5cGUgaW5mb3JtYXRpb24gaXMgc3RvcmVkIGluIHRoZSBgZGlhZ25vc2lzX2dyb3VwYCBjb2x1bW4gb2YgdGhlIGBjb2xEYXRhYCBpbiB0aGUgcHNldWRvLWJ1bGtlZCBTQ0UuCgpgYGB7ciBkZXNlcSBvYmplY3QsIGxpdmU9VFJVRX0KIyBzZXQgdXAgdGhlIGRlc2VxIG9iamVjdCwgZ3JvdXAgYnkgZGlhZ25vc2lzCmRlc2VxX29iamVjdCA8LSBERVNlcTI6OkRFU2VxRGF0YVNldCh0dW1vcl9teW9ibGFzdF9zY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXNpZ24gPSB+IGRpYWdub3Npc19ncm91cCkKYGBgCgpUaGUgcHNldWRvLWJ1bGtlZCBTQ0Ugb2JqZWN0IGNvbnRhaW5zIG9ubHkgb25lIGFzc2F5OiB0aGUgYGNvdW50c2AgYXNzYXkuClRoaXMgaXMgYmVjYXVzZSBgREVTZXEyYCBleHBlY3RzIHJhdyBjb3VudHMuCldoZW4gd2UgcnVuIGBERVNlcTJgIG9uIG91ciBkYXRhc2V0LCByYXcgY291bnRzIHdpbGwgZmlyc3QgYmUgbm9ybWFsaXplZCB1c2luZyBzaXplIGZhY3RvcnMgdG8gYWNjb3VudCBmb3IgZGlmZmVyZW5jZXMgaW4gdG90YWwgc2FtcGxlIGNvdW50cy4KVGhlcmVmb3JlIHdlIGRvbid0IGhhdmUgdG8gZG8gYW55IG5vcm1hbGl6YXRpb24gb24gb3VyIG93biDigJMgd2UnbGwgbGV0IGBERVNlcTJgIGRvIGFsbCB0aGUgd29yayBmb3IgdXMuCgpIb3dldmVyLCBiZWZvcmUgd2UgZGl2ZSBpbnRvIERFIGFuYWx5c2lzLCB3ZSBjYW4gZG8gc29tZSBpbml0aWFsIGV4cGxvcmF0aW9uIGFuZCB2aXN1YWxpemF0aW9uIG9mIG91ciBkYXRhIHRvIHNlZSBpZiBvdXIgc2FtcGxlcyBzZXBhcmF0ZSBieSBvdXIga25vd24gZmFjdG9yIG9mIGludGVyZXN0LCBSTVMgc3VidHlwZS4KSW4gcGFydGljdWxhciwgd2UgY2FuIHVzZSBwcmluY2lwYWwgY29tcG9uZW50IGFuYWx5c2lzIChQQ0EpIG9mIG91ciBwc2V1ZG8tYnVsa2VkIGRhdGFzZXQgdG8gdmlzdWFsaXplIGFueSB2YXJpYXRpb24gYmV0d2VlbiBzYW1wbGVzLgpJZiB0aGVyZSBpcyB2YXJpYXRpb24gYmV0d2VlbiBSTVMgc3VidHlwZXMsIHdlIGV4cGVjdCB0aGVpciByZXNwZWN0aXZlIHNhbXBsZXMgdG8gc2VwYXJhdGUgaW4gUEMgc3BhY2UsIGxpa2VseSBpbmRpY2F0aW5nIHByZXNlbmNlIG9mIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcy4KV2UgY2FuIGV2YWx1YXRlIHRoaXMgYnkgcGxvdHRpbmcgUEMxIGFuZCBQQzIuCgpJbiBvcmRlciB0byBjcmVhdGUgb3VyIFBDQSBwbG90LCB3ZSB3aWxsIGZpcnN0IG5lZWQgdG8gbm9ybWFsaXplIG91ciBkYXRhIHRvIGFjY291bnQgZm9yIGFueSB0ZWNobmljYWwgdmFyaWF0aW9ucyBhY3Jvc3Mgc2FtcGxlcy4KQXMgYSByZW1pbmRlciwgdGhpcyBpcyBOT1QgcmVxdWlyZWQgZm9yIHJ1bm5pbmcgYERFU2VxMmAgYW5hbHlzaXM7IHdlIGFyZSBqdXN0IHVzaW5nIGl0IHRvIHZpc3VhbGl6ZSBvdXIgZGF0YSBwcmlvciB0byBERSBhbmFseXNpcy4KCmBgYHtyIG5vcm1hbGl6ZX0KIyBlc3RpbWF0ZSBzaXplIGZhY3RvcnMgZmlyc3QKZGVzZXFfb2JqZWN0IDwtIERFU2VxMjo6ZXN0aW1hdGVTaXplRmFjdG9ycyhkZXNlcV9vYmplY3QpCgojIG5vcm1hbGl6ZSBhbmQgbG9nIHRyYW5zZm9ybSB0byB1c2UgZm9yIHZpc3VhbGl6YXRpb24Kbm9ybWFsaXplZF9vYmplY3QgPC0gREVTZXEyOjpybG9nKGRlc2VxX29iamVjdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBibGluZCA9IFRSVUUpCm5vcm1hbGl6ZWRfb2JqZWN0CmBgYAoKV2Ugbm93IGhhdmUgYSBub3JtYWxpemVkIGFuZCB0cmFuc2Zvcm1lZCBvYmplY3QgdGhhdCBjYW4gYmUgZGlyZWN0bHkgaW5wdXQgdG8gdGhlIGBERVNlcTI6OnBsb3RQQ0EoKWAgZnVuY3Rpb24sIHdoaWNoIHdpbGwgYm90aCBjYWxjdWxhdGUgYW5kIHBsb3QgdGhlIFBDIHJlc3VsdHMuCgpgYGB7ciBwbG90UENBLCBsaXZlPVRSVUV9CkRFU2VxMjo6cGxvdFBDQShub3JtYWxpemVkX29iamVjdCwgaW50Z3JvdXAgPSAiZGlhZ25vc2lzX2dyb3VwIikKYGBgCgpBcyBleHBlY3RlZCB3ZSBzZWUgdGhhdCBzYW1wbGVzIGdyb3VwIHRvZ2V0aGVyIGJhc2VkIG9uIFJNUyBzdWJ0eXBlIGFuZCBhcmUgc2VwYXJhdGVkIGFsb25nIHRoZSBQQzEgYXhpcywgdGhlIFBDIGNvbnRyaWJ1dGluZyB0aGUgaGlnaGVzdCBhbW91bnQgb2YgdmFyaWF0aW9uLgoKIyMjIyBSdW4gYERFU2VxYAoKV2UnbGwgbm93IHVzZSB0aGUgY29udmVuaWVuY2UgZnVuY3Rpb24gYERFU2VxKClgIHRvIHBlcmZvcm0gb3VyIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGFuYWx5c2lzLgpUaGlzIGZ1bmN0aW9uIGNhbGN1bGF0ZXMgbm9ybWFsaXphdGlvbiBmYWN0b3JzLCBlc3RpbWF0ZXMgZ2VuZS13aXNlIGRpc3BlcnNpb25zLCBmaXRzIGEgbmVnYXRpdmUgYmlub21pYWwgbW9kZWwgYW5kIHBlcmZvcm1zIGh5cG90aGVzaXMgdGVzdGluZyB1c2luZyBXYWxkIHN0YXRpc3RpY3MuCgpgYGB7ciBkZXNlcSwgbGl2ZT1UUlVFfQojIHJ1biBERVNlcQpkZXNlcV9vYmplY3QgPC0gREVTZXEyOjpERVNlcShkZXNlcV9vYmplY3QpCmBgYAoKV2UgY2FuIGV2YWx1YXRlIGhvdyB3ZWxsIHRoZSBtb2RlbCBmaXQgb3VyIGRhdGEgYnkgbG9va2luZyBhdCB0aGUgZGlzcGVyc2lvbiBlc3RpbWF0ZXMuCldlIGV4cGVjdCB0byBzZWUgdGhlIGRpc3BlcnNpb24gZXN0aW1hdGVzIGRlY3JlYXNlIGFzIG1lYW5zIGFyZSBpbmNyZWFzaW5nIGFuZCBmb2xsb3cgdGhlIGxpbmUgb2YgYmVzdCBmaXQuIAoKYGBge3IgcGxvdCBkaXNwZXJzaW9uLCBsaXZlPVRSVUV9CnBsb3REaXNwRXN0cyhkZXNlcV9vYmplY3QpCmBgYAoKTm93IHdlIGNhbiBleHRyYWN0IHRoZSByZXN1bHRzIGZyb20gdGhlIG9iamVjdCwgc3BlY2lmeWluZyB0aGUgcC12YWx1ZSB0aHJlc2hvbGQgdGhhdCB3ZSB3b3VsZCBsaWtlIHRvIHVzZS4KCmBgYHtyIHJlc3VsdHMsIGxpdmU9VFJVRX0KIyBleHRyYWN0IHRoZSByZXN1bHRzIGFzIGEgRGF0YUZyYW1lCmRlc2VxX3Jlc3VsdHMgPC0gREVTZXEyOjpyZXN1bHRzKGRlc2VxX29iamVjdCwgYWxwaGEgPSAwLjA1KQpgYGAKCkJ1dCB3ZSBhcmVuJ3QgZG9uZSB5ZXQhCgpUaGUgZXN0aW1hdGVzIG9mIGxvZzIgZm9sZCBjaGFuZ2UgY2FsY3VsYXRlZCBieSBgREVTZXEoKWAgYXJlIG5vdCBjb3JyZWN0ZWQgZm9yIGV4cHJlc3Npb24gbGV2ZWwuClRoaXMgbWVhbnMgdGhhdCB3aGVuIGNvdW50cyBhcmUgc21hbGwsIHdlIGFyZSBsaWtlbHkgdG8gZW5kIHVwIHdpdGggc29tZSBsYXJnZSBmb2xkIGNoYW5nZSB2YWx1ZXMgdGhhdCBvdmVyZXN0aW1hdGUgdGhlIHRydWUgZXh0ZW50IG9mIHRoZSBjaGFuZ2UgYmV0d2VlbiBjb25kaXRpb25zLgoKV2UgY2FuIGNvcnJlY3QgdGhpcyBieSBhcHBseWluZyBhICJzaHJpbmthZ2UiIHByb2NlZHVyZSwgd2hpY2ggd2lsbCBhZGp1c3QgbGFyZ2UgdmFsdWVzIHdpdGggc21hbGwgY291bnRzIGRvd253YXJkLCB3aGlsZSBwcmVzZXJ2aW5nIHZhbHVlcyB3aXRoIGxhcmdlciBjb3VudHMsIHdoaWNoIGFyZSBsaWtlbHkgdG8gYmUgbW9yZSBhY2N1cmF0ZS4KClRvIGRvIHRoaXMsIHdlIHdpbGwgdXNlIHRoZSBgbGZjU2hyaW5rKClgIGZ1bmN0aW9uLCBidXQgZmlyc3Qgd2UgbmVlZCB0byBrbm93IHRoZSBuYW1lIGFuZC9vciBwb3NpdGlvbiBvZiB0aGUgImNvZWZmaWNpZW50IiB0aGF0IHdhcyBjYWxjdWxhdGVkIGJ5IGBERVNlcSgpYCwgd2hpY2ggd2UgY2FuIGRvIHdpdGggdGhlIGByZXN1bHRzTmFtZXMoKWAgZnVuY3Rpb24uCgpgYGB7ciBjb2VmZmljaWVudCwgbGl2ZT1UUlVFfQojIGlkZW50aWZ5IHBvc2l0aW9uIG9mIGNvZWZmaWNpZW50CkRFU2VxMjo6cmVzdWx0c05hbWVzKGRlc2VxX29iamVjdCkKYGBgCgoKYGBge3Igc2hyaW5rYWdlfQojIGFwcHlseSBsb2dGQyBzaHJpbmthZ2UgdXNpbmcgdGhlIGRlZmF1bHQgbW9kZWwKc2hyaW5rX3Jlc3VsdHMgPC0gREVTZXEyOjpsZmNTaHJpbmsoCiAgZGVzZXFfb2JqZWN0LCAKICByZXMgPSBkZXNlcV9yZXN1bHRzLCAKICBjb2VmID0gMiwKICB0eXBlID0gImFwZWdsbSIKKQpoZWFkKHNocmlua19yZXN1bHRzKQpgYGAKCklmIHlvdSBsb29rIGF0IG91ciBgc2hyaW5rX3Jlc3VsdHNgIG9iamVjdCwgd2Ugc2VlIHRoYXQgdGhlIGdlbmVzIGFyZSBsYWJlbGVkIHdpdGggdGhlIEVuc2VtYmwgZ2VuZSBpZGVudGlmaWVycywgYXMgdGhvc2Ugd2VyZSB0aGUgcm93IG5hbWVzIG9mIHRoZSBwc2V1ZG8tYnVsa2VkIFNDRSB3ZSB1c2VkIGFzIGlucHV0IHRvIGJ1aWxkIG91ciBgREVTZXEyYCBvYmplY3QuCkFsdGhvdWdoIHNvbWUgb2YgdXMgbWF5IGhhdmUgYWxsIG9mIHRoZSBpZGVudGlmaWVycyBtZW1vcml6ZWQgYnkgaGVhcnQsIGl0IGNhbiBiZSB1c2VmdWwgdG8gaGF2ZSBhIGh1bWFuIHJlYWRhYmxlIHN5bWJvbCBpbiBvdXIgcmVzdWx0cy4KQmVmb3JlIHdlIHNhdmUgdGhlIHJlc3VsdHMgYXMgYSBmaWxlLCB3ZSB3aWxsIGdyYWIgdGhlIGdlbmUgc3ltYm9scyBmcm9tIHRoZSBgcm93RGF0YWAgb2Ygb3VyIG9yaWdpbmFsIFNDRSBvYmplY3QgYW5kIGFkZCB0aGVtIGFzIGEgbmV3IGNvbHVtbi4KCmBgYHtyIGFkZCBnZW5lIHN5bWJvbH0KZGVzZXFfcmVzdWx0cyA8LSBzaHJpbmtfcmVzdWx0cyB8PgogICMgZGlyZWN0bHkgYWRkIEVuc2VtYmwgaWQgYXMgYSBjb2x1bW4KICAjIGNvbnZlcnRpbmcgcmVzdWx0cyBpbnRvIGEgZGF0YSBmcmFtZQogIHRpYmJsZTo6YXNfdGliYmxlKHJvd25hbWVzID0gImVuc2VtYmxfaWQiKQoKIyBjb252ZXJ0IHJvd2RhdGEgdG8gZGF0YSBmcmFtZSAKc2NlX3Jvd2RhdGFfZGYgPC0gcm93RGF0YSh0dW1vcl9teW9ibGFzdF9zY2UpIHw+CiAgIyBjcmVhdGUgYSBjb2x1bW4gd2l0aCByb3duYW1lcyBzdG9yZWQgYXMgZW5zZW1ibCBpZAogICMgdXNlIGZvciBqb2luaW5nIHdpdGggZGVzZXEgcmVzdWx0cwogIHRpYmJsZTo6YXNfdGliYmxlKHJvd25hbWVzID0gImVuc2VtYmxfaWQiKQoKIyBjb21iaW5lIGRlc2VxIHJlc3VsdHMgd2l0aCByb3dkYXRhIGJ5IGVuc2VtYmwgaWQgCmRlc2VxX3Jlc3VsdHMgPC0gZGVzZXFfcmVzdWx0cyB8PgogIGRwbHlyOjpsZWZ0X2pvaW4oc2NlX3Jvd2RhdGFfZGYsIGJ5ID0gImVuc2VtYmxfaWQiKQoKaGVhZChkZXNlcV9yZXN1bHRzKQpgYGAKCldlIGNhbiBzYXZlIHRoZSBuZXcgZGF0YSBmcmFtZSB0aGF0IHdlIGhhdmUgY3JlYXRlZCB3aXRoIHRoZSBFbnNlbWJsIGlkZW50aWZpZXJzLCBnZW5lIHN5bWJvbHMsIGFuZCB0aGUgYERFU2VxMmAgcmVzdWx0cyBhcyBhIHRhYiBzZXBhcmF0ZWQgKGB0c3ZgKSBmaWxlLgoKYGBge3Igc2F2ZSBkZXNlcSwgbGl2ZT1UUlVFfQojIHNhdmUgb3VyIHJlc3VsdHMgYXMgdHN2CnJlYWRyOjp3cml0ZV90c3YoZGVzZXFfcmVzdWx0cywgZGVzZXFfb3V0cHV0X2ZpbGUpCmBgYAoKVGhlIGxhc3QgdGhpbmcgdGhhdCB3ZSB3aWxsIGRvIGlzIHRha2UgYSBsb29rIGF0IGhvdyBtYW55IGdlbmVzIGFyZSBzaWduaWZpY2FudC4KSGVyZSB3ZSB3aWxsIHdhbnQgdG8gdXNlIHRoZSBhZGp1c3RlZCBwLXZhbHVlLCBmb3VuZCBpbiB0aGUgYHBhZGpgIGNvbHVtbiBvZiB0aGUgcmVzdWx0cywgYXMgdGhpcyBhY2NvdW50cyBmb3IgbXVsdGlwbGUgdGVzdCBjb3JyZWN0aW9uLgoKYGBge3Igc2lnbmlmaWNhbnQgcmVzdWx0cywgbGl2ZT1UUlVFfQojIGZpcnN0IGxvb2sgYXQgdGhlIHNpZ25pZmljYW50IHJlc3VsdHMgCmRlc2VxX3Jlc3VsdHNfc2lnIDwtIGRlc2VxX3Jlc3VsdHMgfD4KICAjIGZpbHRlciBiYXNlZCBvbiBhZGp1c3RlZCBwdmFsdWUKICBkcGx5cjo6ZmlsdGVyKHBhZGogPD0gMC4wNSkKCmhlYWQoZGVzZXFfcmVzdWx0c19zaWcpCmBgYAoKCiMjIyBFeHBsb3JpbmcgdGhlIGlkZW50aWZpZWQgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIAoKTm93IHRoYXQgd2UgaGF2ZSBpZGVudGlmaWVkIGEgc2V0IG9mIGdlbmVzIHRoYXQgYXJlIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBpbiB0aGUgdHVtb3IgbXlvYmxhc3RzIGJldHdlZW4gQVJNUyBhbmQgRVJNUyBzdWJ0eXBlcywgbGV0cyBhY3R1YWxseSB0YWtlIGEgbG9vayBhdCB0aGVtIGFuZCBzZWUgaWYgd2UgY2FuIG1ha2Ugc29tZSBpbmZvcm1hdGl2ZSBwbG90cy4KVGhlIGZpcnN0IHBsb3Qgd2UnbGwgbWFrZSBpcyBhIHZvbGNhbm8gcGxvdCB1c2luZyB0aGUgW2BFbmhhbmNlZFZvbGNhbm9gIHBhY2thZ2VdKGh0dHBzOi8vZ2l0aHViLmNvbS9rZXZpbmJsaWdoZS9FbmhhbmNlZFZvbGNhbm8pLgpUaGlzIHBhY2thZ2UgYXV0b21hdGljYWxseSBjb2xvcnMgdGhlIHBvaW50cyBieSBjdXRvZmZzIGZvciBib3RoIHNpZ25pZmljYW5jZSBhbmQgZm9sZCBjaGFuZ2UgYW5kIGxhYmVscyBtYW55IG9mIHRoZSBzaWduaWZpY2FudCBnZW5lcyAoc3ViamVjdCB0byBzcGFjaW5nKS4KYEVuaGFuY2VkVm9sY2Fub2AgaGFzIG1hbnksIG1hbnkgb3B0aW9ucywgd2hpY2ggaXMgYSBnb29kIHRoaW5nIGlmIHlvdSBkb24ndCBsaWtlIGFsbCBvZiBpdHMgZGVmYXVsdCBzZXR0aW5ncy4KRXZlbiBiZXR0ZXIsIGl0IG91dHB1dHMgYSBgZ2dwbG90MmAgb2JqZWN0LCBzbyBpZiB3ZSB3YW50IHRvIGN1c3RvbWl6ZSB0aGUgcGxvdCBmdXJ0aGVyLCB3ZSBjYW4gdXNlIHRoZSBzYW1lIGBnZ3Bsb3QyYCBjb21tYW5kcyB3ZSBoYXZlIHVzZWQgYmVmb3JlLgoKYGBge3Igdm9sY2Fub30KRW5oYW5jZWRWb2xjYW5vOjpFbmhhbmNlZFZvbGNhbm8oZGVzZXFfcmVzdWx0cywKICAgICAgICAgICAgICAgIHggPSAnbG9nMkZvbGRDaGFuZ2UnLCAjIGZvbGQgY2hhbmdlIHN0YXRpc3RpYyB0byBwbG90CiAgICAgICAgICAgICAgICB5ID0gJ3B2YWx1ZScsICMgc2lnbmlmaWNhbmNlIHZhbHVlcwogICAgICAgICAgICAgICAgbGFiID0gZGVzZXFfcmVzdWx0cyRnZW5lX3N5bWJvbCwgIyBsYWJlbHMgZm9yIHBvaW50cwogICAgICAgICAgICAgICAgcEN1dG9mZiA9IDFlLTA1LCAjIHAgdmFsdWUgY3V0b2ZmIChkZWZhdWx0KQogICAgICAgICAgICAgICAgRkNjdXRvZmYgPSAxLCAjIGZvbGQgY2hhbmdlIGN1dG9mZiAoZGVmYXVsdCkKICAgICAgICAgICAgICAgIHRpdGxlID0gTlVMTCwgIyBubyB0aXRsZQogICAgICAgICAgICAgICAgc3VidGl0bGUgPSBOVUxMLCAjIG9yIHN1YnRpdGxlCiAgICAgICAgICAgICAgICBjYXB0aW9uID0gTlVMTCwgIyBvciBjYXB0aW9uCiAgICAgICAgICAgICAgICBkcmF3Q29ubmVjdG9ycyA9IFRSVUUsICMgYWRkIHNvbWUgZnVuIGFycm93cwogICAgICAgICAgICAgICAgbGFiU2l6ZSA9IDMgICMgc21hbGxlciBsYWJlbHMKICAgICAgICAgICAgICAgICkgKwogICMgY2hhbmdlIHRoZSBvdmVyYWxsIHRoZW1lCiAgdGhlbWVfYncoKSArCiAgIyBtb3ZlIHRoZSBsZWdlbmQgdG8gdGhlIGJvdHRvbQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQpgYGAKCgpXZSBjYW4gYWxzbyByZXR1cm4gYmFjayB0byB0aGUgU0NFIG9iamVjdCB0aGF0IHdlIHVzZWQgdG8gY3JlYXRlIG91ciBwc2V1ZG8tYnVsa2VkIFNDRSBhbmQgbG9vayBhdCBnZW5lIGV4cHJlc3Npb24gb2Ygc29tZSBvZiB0aGUgc2lnbmlmaWNhbnQgZ2VuZXMuIApXZSBjYW4gY3JlYXRlIFVNQVAgcGxvdHMgYXMgd2UgZGlkIHByZXZpb3VzbHksIGJ1dCBpbnN0ZWFkIG9mIGxhYmVsaW5nIGVhY2ggY2VsbCB3aXRoIG1ldGFkYXRhLCB3ZSBjYW4gY29sb3IgY2VsbHMgYnkgYSBzcGVjaWZpZWQgZ2VuZSdzIGV4cHJlc3Npb24gbGV2ZWxzLgpXZSB3aWxsIGFsc28gdXNlIHNvbWUgb2YgdGhlIGBnZ3Bsb3QyYCBza2lsbHMgd2UgcGlja2VkIHVwIGVhcmxpZXIsIGxpa2UgYGZhY2V0X2dyaWQoKWAgdG8gcGxvdCBjZWxscyBmcm9tIGRpZmZlcmVudCBSTVMgc3VidHlwZXMgc2VwYXJhdGVseS4KVGhpcyBjYW4gaGVscCB1cyB2YWxpZGF0ZSB0aGUgYERFU2VxMmAgcmVzdWx0cyBzbyB0aGF0IHdlIGNhbiB2aXN1YWxpemUgZ2VuZSBleHByZXNzaW9uIGNoYW5nZXMgYWNyb3NzIG91ciBjZWxsIHR5cGUgb2YgaW50ZXJlc3Qgb24gYSBzaW5nbGUtY2VsbCBsZXZlbC4gCgpgYGB7ciBleHByZXNzaW9uIHVtYXAsIGxpdmU9VFJVRX0KIyBmaWx0ZXIgdG8ganVzdCBteW9ibGFzdCBjZWxscyBhbmQgcmVtb3ZlIGFueSBOQSdzIGJlZm9yZSBwbG90dGluZwpteW9ibGFzdF9jb21iaW5lZF9zY2UgPC0gcm1zX3NjZVssIHdoaWNoKHJtc19zY2UkY2VsbHR5cGVfYnJvYWQgPT0gIlR1bW9yX015b2JsYXN0IildCgojIHBsb3QgUFRQUlQgKEVOU0cwMDAwMDE5NjA5MCkgZXhwcmVzc2lvbiBpbiBBUk1TIHZzLiBFUk1TCnNjYXRlcjo6cGxvdFJlZHVjZWREaW0obXlvYmxhc3RfY29tYmluZWRfc2NlLAogICAgICAgICAgICAgICAgICAgICAgIGRpbXJlZCA9ICJmYXN0bW5uX1VNQVAiLAogICAgICAgICAgICAgICAgICAgICAgIGNvbG9yX2J5ID0gIkVOU0cwMDAwMDE5NjA5MCIsICNQVFBSVAogICAgICAgICAgICAgICAgICAgICAgIHBvaW50X3NpemU9IDAuNSwKICAgICAgICAgICAgICAgICAgICAgICBwb2ludF9hbHBoYSA9IDAuNCwKICAgICAgICAgICAgICAgICAgICAgICBvdGhlcl9maWVsZHMgPSAiZGlhZ25vc2lzX2dyb3VwIikgKwogIGZhY2V0X2dyaWQoY29scyA9IHZhcnMoZGlhZ25vc2lzX2dyb3VwKSkKYGBgCgpJbiB0aGUgYWJvdmUgcGxvdCB3ZSBvbmx5IHBsb3R0ZWQgdGhlIHR1bW9yIG15b2JsYXN0IGNlbGxzIHRoYXQgd2UgdXNlZCBpbiBvdXIgREUgYW5hbHlzaXMuIApIb3dldmVyLCB3ZSBtaWdodCBiZSBpbnRlcmVzdGVkIHRvIHNlZSB0aGUgZXhwcmVzc2lvbiBvZiBnZW5lcyB0aGF0IGFyZSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgaW4gb3RoZXIgY2VsbCB0eXBlcyBwcmVzZW50IGluIG91ciBzYW1wbGVzLgoKYGBge3IgY2VsbHR5cGUgY29tcGFyaXNvbn0KIyBsZXQncyBjb21wYXJlIGdlbmUgZXhwcmVzc2lvbiBhY3Jvc3Mgc29tZSBvdGhlciBjZWxsIHR5cGVzCiMgbG9vayBhdCBhbGwgdHVtb3IgY2VsbHMgYW5kIHBpY2sgb25lIG5vcm1hbCBjZWxsIHR5cGUKY2VsbHR5cGVzIDwtIGMoIlR1bW9yX015b2JsYXN0IiwgCiAgICAgICAgICAgICAgICJUdW1vcl9NZXNvZGVybSIsIAogICAgICAgICAgICAgICAiVHVtb3JfTXlvY3l0ZSIsIAogICAgICAgICAgICAgICAiVmFzY3VsYXIgRW5kb3RoZWxpdW0iKQoKIyBzdWJzZXQgdG8ganVzdCBjZWxsdHlwZXMgdGhhdCB3ZSBhcmUgaW50ZXJlc3RlZCBpbgp0dW1vcl9zY2UgPC0gcm1zX3NjZVssIHdoaWNoKHJtc19zY2UkY2VsbHR5cGVfYnJvYWQgJWluJSBjZWxsdHlwZXMpXQpgYGAKCk5leHQgd2Ugd2lsbCBsb29rIGF0IGEgZmV3IERFIGdlbmVzIHRoYXQgd2UgaWRlbnRpZmllZCwgb25lIHVwIHJlZ3VsYXRlZCBnZW5lIGFuZCBvbmUgZG93biByZWd1bGF0ZWQgZ2VuZSwgYW5kIGNvbXBhcmUgdGhlaXIgZXhwcmVzc2lvbiBpbiBteW9ibGFzdHMgdG8gb3RoZXIgY2VsbCB0eXBlcyBpbiBBUk1TIGFuZCBFUk1TIHNhbXBsZXMuCldlIHdpbGwgdXNlIHRoZSBgc2NhdGVyOjpwbG90RXhwcmVzc2lvbigpYCBmdW5jdGlvbiB0byBjcmVhdGUgYSB2aW9saW4gcGxvdCB3aXRoIFJNUyBzdWJ0eXBlIG9uIHRoZSB4LWF4aXMgYW5kIGdlbmUgZXhwcmVzc2lvbiBvbiB0aGUgeS1heGlzLgpXZSBjYW4gY29udGludWUgdXNpbmcgYGZhY2V0X2dyaWQoKWAgdG8gc2hvdyBzZXBhcmF0ZSBwYW5lbHMgZm9yIGVhY2ggY2VsbCB0eXBlLgpCZWNhdXNlIHdlIHdhbnQgdG8gc2hvdyBtdWx0aXBsZSBnZW5lcyBoZXJlLCB3ZSBhcmUgZ29pbmcgdG8gYWRkIGFuIGFkZGl0aW9uYWwgb3B0aW9uIHRvIGBmYWNldF9ncmlkKClgIHRvIGluY2x1ZGUgbXVsdGlwbGUgcm93cyBpbiBvdXIgcGxvdCBncmlkLCBvbmUgZm9yIGVhY2ggZ2VuZSBvZiBpbnRlcmVzdC4KT25lIG5lYXQgdHJpY2sgb2YgdGhlIGBzY2F0ZXI6OnBsb3RFeHByZXNzaW9uKClgIGZ1bmN0aW9uIGlzIHRoYXQgaXQgYWN0dWFsbHkgY3JlYXRlcyBhIGBGZWF0dXJlYCBjb2x1bW4gd2hpY2ggY29ycmVzcG9uZHMgdG8gdGhlIGZlYXR1cmVzIChpbiB0aGlzIGNhc2UgZ2VuZXMpIGJlaW5nIHVzZWQgaW4gcGxvdHRpbmcuCldlIGNhbiB0aGVuIGRpcmVjdGx5IHJlZmVyZW5jZSB0aGF0IGBGZWF0dXJlYCBjb2x1bW4gd2hlbiBwbG90dGluZywgaW5zdGVhZCBvZiB1c2luZyB0aGUgYG90aGVyX2ZpZWxkc2Agb3B0aW9uIHdlIHVzZWQgcHJldmlvdXNseS4KCmBgYHtyIG11bHRpLWdlbmUgcGxvdH0KIyBwaWNrIGEgY291cGxlIGdlbmVzIHRvIGxvb2sgYXQgCmdlbmVzX3RvX3Bsb3QgPC0gYygiRU5TRzAwMDAwMTk2MDkwIiwgI1BUUFJUCiAgICAgICAgICAgICAgICAgICAiRU5TRzAwMDAwMTQ4OTM1IikgI0dBUzIKCiMgY3JlYXRlIGEgdmlvbGluIHBsb3QgCnNjYXRlcjo6cGxvdEV4cHJlc3Npb24odHVtb3Jfc2NlLAogICAgICAgICAgICAgICAgICAgICAgICMgYSB2ZWN0b3Igb2YgZ2VuZXMgdG8gcGxvdAogICAgICAgICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gZ2VuZXNfdG9fcGxvdCwgCiAgICAgICAgICAgICAgICAgICAgICAgeCA9ICJkaWFnbm9zaXNfZ3JvdXAiLCAKICAgICAgICAgICAgICAgICAgICAgICBjb2xvcl9ieSA9ICJkaWFnbm9zaXNfZ3JvdXAiLAogICAgICAgICAgICAgICAgICAgICAgIG90aGVyX2ZpZWxkcyA9ICJjZWxsdHlwZV9icm9hZCIsCiAgICAgICAgICAgICAgICAgICAgICAgcG9pbnRfc2l6ZSA9IDAuMSkgKwogICMgZWFjaCBjZWxsdHlwZSBpcyBpdHMgb3duIGNvbHVtbgogIGZhY2V0X2dyaWQoY29scyA9IHZhcnMoY2VsbHR5cGVfYnJvYWQpLAogICAgICAgICAgICAgIyBlYWNoIGZlYXR1cmUgKGdlbmUpIGlzIGl0cyBvd24gcm93CiAgICAgICAgICAgICByb3dzID0gdmFycyhGZWF0dXJlKSkgKyAKICAjIGNoYW5nZSB0aGUgZm9udCBzaXplIG9mIHRoZSBmYWNldCBsYWJlbHMKICB0aGVtZShzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KSkgKyAKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQoCiAgICB0aXRsZSA9ICJTdWJ0eXBlIiwgIyB1cGRhdGUgdGhlIGxlZ2VuZCB0aXRsZQogICAgIyBjaGFuZ2UgdGhlIHNpemUgb2YgdGhlIGxlZ2VuZCBjb2xvcnMKICAgIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDMsIGFscGhhID0gMSkpCiAgICApCmBgYAoKSG93IGRvIHRoZSBleHByZXNzaW9uIG9mIHRoZXNlIGdlbmVzIGNoYW5nZSBhY3Jvc3MgY2VsbCB0eXBlcyBhbmQgUk1TIHN1YnR5cGVzPwoKR28gYWhlYWQgYW5kIGV4cGxvcmUgc29tZSBnZW5lcyBvbiB5b3VyIG93biEgCkZlZWwgZnJlZSB0byBwbG90IGFueSBvZiB0aGUgZ2VuZXMgdGhhdCBhcmUgaWRlbnRpZmllZCBhcyBzaWduaWZpY2FudCwgZm91bmQgaW4gdGhlIERFIHJlc3VsdHMgdGFibGUsIG9yIHlvdXIgZmF2b3JpdGUgZ2VuZS4KUmVtZW1iZXIsIHlvdSBuZWVkIHRvIHVzZSB0aGUgRW5zZW1ibCBnZW5lIGlkZW50aWZpZXIgdG8gcmVmZXIgdG8gZWFjaCBnZW5lLgoKYGBge3IgZXhwbG9yZX0KIyBub3cgZG8gc29tZSBleHBsb3JhdGlvbiBvZiBvdGhlciBnZW5lcyBvbiB5b3VyIG93biEgCmBgYAoKIyMgUHJpbnQgc2Vzc2lvbiBpbmZvIAoKYGBge3Igc2Vzc2lvbiBpbmZvfQpzZXNzaW9uSW5mbygpCmBgYAoK
diff --git a/scRNA-seq-advanced/04-gene_set_enrichment_analysis-live.Rmd b/scRNA-seq-advanced/04-gene_set_enrichment_analysis-live.Rmd new file mode 100644 index 00000000..2f9122b6 --- /dev/null +++ b/scRNA-seq-advanced/04-gene_set_enrichment_analysis-live.Rmd @@ -0,0 +1,281 @@ +--- +title: "Pathway analysis: Gene Set Enrichment Analysis (GSEA)" +output: + html_notebook: + toc: true + toc_float: true +author: CCDL for ALSF +date: 2024 +--- + +## Objectives + +This notebook will demonstrate how to: + +- Prepare tabular data of gene-level statistics for use with Gene Set Enrichment Analysis (GSEA) +- Access [Molecular Signatures Database gene set collections](https://www.gsea-msigdb.org/gsea/msigdb/collections.jsp) via the `msigdbr` package +- Perform GSEA with the `clusterProfiler` package +- Visualize GSEA results with the `enrichplot` package + +--- + +In this notebook, we'll analyze the differential expression results from the last notebook. + +GSEA is a functional class scoring (FCS) approach to pathway analysis that was first introduced in [Subramanian _et al._ (2005)](https://doi.org/10.1073/pnas.0506580102). +The rationale behind FCS approaches is that small changes in individual genes that participate in the same biological process or pathway can be significant and of biological interest. + +There are 3 general steps in FCS methods ([Khatri _et al._ 2012](https://doi.org/10.1371/journal.pcbi.1002375)): + +1. Calculate a gene-level statistic (here, we'll use the summary log fold changes in our DESeq2 results) +2. Aggregate gene-level statistics into a pathway-level statistic +3. Assess the statistical significance of the pathway-level statistic + +#### Other resources + +* For another example using `clusterProfiler` for GSEA, see [_Intro to DGE: Functional Analysis._ from Harvard Chan Bioinformatics Core Training.](https://hbctraining.github.io/Training-modules/DGE-functional-analysis/lessons/02_functional_analysis.html) +* The way we'll use `clusterProfiler` here uses `fgsea` (Fast Gene Set Enrichment Analysis) under the hood. +You can read more about `fgsea` in [Korotkevich _et al._ (2021)](https://doi.org/10.1101/060012). +* See the [refine.bio examples for "Gene set enrichment analysis - RNA-seq"](https://alexslemonade.github.io/refinebio-examples/03-rnaseq/pathway-analysis_rnaseq_02_gsea.html) from which this material has been adapted. + +## Set up + +### Libraries + +```{r libraries} +# Package to run GSEA +library(clusterProfiler) +# Package that contains the MSigDB gene sets in tidy format +library(msigdbr) +``` + +### Directories and Files + +#### Directories + +```{r create_dir, live = TRUE} +# We'll use the marker genes as GSEA input + +# We'll create a directory to specifically hold the pathway results if it doesn't +# exist yet + +``` + +#### Input files + + +```{r input_files} +input_file <- file.path(rms_analysis_dir, + "deseq", + "rms_myoblast_deseq_results.tsv") +``` + +#### Output files + +We'll save our table of GSEA results as a TSV. + +```{r output_files} +output_file <- file.path(results_dir, + "rms_myoblast_gsea_results.tsv") +``` + +## Gene sets + +We will use gene sets from the [Molecular Signatures Database (MSigDB)](https://www.gsea-msigdb.org/gsea/msigdb/index.jsp) from the Broad Institute ([Subramanian, Tamayo *et al.* 2005](https://doi.org/10.1073/pnas.0506580102)). +The [`msigdbr`](https://cran.r-project.org/web/packages/msigdbr/index.html) package contains MSigDB datasets already in the tidy format required by `clusterProfiler` and supports multiple organisms. + +Let's take a look at what organisms the package supports. + +```{r show_species} +msigdbr_species() +``` + +MSigDB contains 8 different gene set collections. + + H: hallmark gene sets + C1: positional gene sets + C2: curated gene sets + C3: motif gene sets + C4: computational gene sets + C5: GO gene sets + C6: oncogenic signatures + C7: immunologic signatures + +We'll use the Hallmark collection for GSEA. +Here's an excerpt of the [collection description](https://www.gsea-msigdb.org/gsea/msigdb/collection_details.jsp#H): + +> Hallmark gene sets summarize and represent specific well-defined biological states or processes and display coherent expression. These gene sets were generated by a computational methodology based on identifying gene set overlaps and retaining genes that display coordinate expression. The hallmarks reduce noise and redundancy and provide a better delineated biological space for GSEA. + +Notably, there are only 50 gene sets included in this collection. +The fewer gene sets we test, the lower our multiple hypothesis testing burden. + +We can retrieve only the Hallmark gene sets by specifying `category = "H"` to the `msigdbr()` function. + +```{r immunologic_sets, live = TRUE} + +``` + +## Gene Set Enrichment Analysis + +_Adapted from [refine.bio examples](https://github.com/AlexsLemonade/refinebio-examples/blob/33cdeff66d57f9fe8ee4fcb5156aea4ac2dce07f/03-rnaseq/pathway-analysis_rnaseq_02_gsea.Rmd)_ + +![](diagrams/subramanian_fig1.jpg) + +**Figure 1. [Subramanian _et al._ (2005)](https://doi.org/10.1073/pnas.0506580102).** + +GSEA calculates a pathway-level metric, called an enrichment score (sometimes abbreviated as ES), by ranking genes by a gene-level statistic. +This score reflects whether or not a gene set or pathway is over-represented at the top or bottom of the gene rankings ([Subramanian _et al._ 2005](https://doi.org/10.1073/pnas.0506580102); [Yu](http://yulab-smu.top/clusterProfiler-book/chapter2.html#gene-set-enrichment-analysis)) + +Specifically, all genes are ranked from most positive to most negative based on their statistic and a running sum is calculated: +Starting with the most highly ranked genes, the running sum increases for each gene in the pathway and decreases for each gene not in the pathway. +The enrichment score for a pathway is the running sum's maximum deviation from zero. +GSEA also assesses statistical significance of the scores for each pathway through permutation testing. +As a result, each input pathway will have a p-value associated with it that is then corrected for multiple hypothesis testing ([Subramanian _et al._ 2005](https://doi.org/10.1073/pnas.0506580102); [Yu](http://yulab-smu.top/clusterProfiler-book/chapter2.html#gene-set-enrichment-analysis)). + +The implementation of GSEA we use in here examples requires a gene list ordered by some statistic and input gene sets. +When you use previously computed gene-level statistics with GSEA, it is called GSEA pre-ranked. + +## DESeq2 results + +```{r read_in_markers, live = TRUE} + +``` + +```{r deseq_head} +head(deseq_df) +``` + +This data frame uses Ensembl gene identifiers. +We'll need to make sure our gene sets use the same identifiers. +Let's take a look at the first few rows of the data frame that contains the hallmark gene sets. + +```{r hallmark_head, live = TRUE} + +``` + +We can see that the gene sets from `msigdbr` have Ensembl gene identifiers associated with them, so we don't need to do any conversion. +However, we'll need to pass the correct column to the function that runs GSEA. + +If we needed to do gene identifier conversion, we would likely use the `AnnotationDbi` package. +You can see an example in this Harvard Chan Bioinformatics Core Training material: + +One good thing about Ensembl gene identifiers is that they are less likely to be duplicated than, for example, gene symbols. +(Multiple Ensembl gene identifiers can map to the same symbol.) + +The GSEA approach requires on discriminating between genes that are in a gene set and those that are not. +Practically speaking, gene sets are just collections of gene identifiers! +When the function we use for GSEA pre-ranked gets a list with duplicated gene identifiers, it can produce unexpected results. +So, let's check for duplicates in the data frame of DESeq2 results. + +```{r check_duplicates, live = TRUE} + +``` + +There are no duplicates for us to worry about! + +### Pre-ranked list + +The `GSEA()` function takes a pre-ranked (sorted) named vector of statistics, where the names in the vector are gene identifiers. +This is step 1 -- gene-level statistics. + +```{r lfc_vector} +lfc_vector <- deseq_df |> + # Extract a vector of `log2FoldChange` named by `ensembl_id` + dplyr::pull(log2FoldChange, name = ensembl_id) +lfc_vector <- sort(lfc_vector, decreasing = TRUE) +``` + +Let's look at the top ranked values. + +```{r head_lfc, live = TRUE} +# Look at first entries of the log fold change vector + +``` + +And the bottom of the list. + +```{r tail_lfc, live = TRUE} +# Look at the last entries of the log fold change vector + +``` + +## Run GSEA + +Now for the analysis! + +We can use the `GSEA()` function to perform GSEA with any generic set of gene sets, but there are several functions for using specific, commonly used gene sets (e.g., `gseKEGG()`). + +```{r run_gsea} +gsea_results <- GSEA(geneList = lfc_vector, # ordered ranked gene list + minGSSize = 25, # minimum gene set size + maxGSSize = 500, # maximum gene set set + pvalueCutoff = 0.05, + pAdjustMethod = "BH", # correction for multiple hypothesis testing + TERM2GENE = dplyr::select(hs_hallmarks_df, + gs_name, + ensembl_gene)) # pass the correct identifier column +``` +Let's take a look at the GSEA results. + +```{r view_gsea, live = TRUE, eval = FALSE} + +``` + +Normalized enrichment scores (NES) are enrichment scores that are scaled to make gene sets that contain different number of genes comparable. + +Pathways with significant, highly positive NES are enriched in ERMS myoblasts, whereas pathways with significant, highly negative NES are enriched in ARMS myoblasts. + +Let's write these results to file. + +```{r write_gsea} +gsea_results@result |> readr::write_tsv(output_file) +``` + +### Visualizing GSEA results + +We can visualize GSEA results for individual pathways or gene sets using `enrichplot::gseaplot()`. +Let's take a look at 3 different pathways -- one with a highly positive NES, one with a highly negative NES, and one that was not a significant result -- to get more insight into how ES are calculated. + +#### Highly Positive NES + +Let's take look at a pathway with a highly positive NES (`HALLMARK_MYC_TARGETS_V2`) using a GSEA plot. + +```{r highly_pos} +enrichplot::gseaplot(gsea_results, + geneSetID = "HALLMARK_MYC_TARGETS_V2", + title = "HALLMARK_MYC_TARGETS_V2", + color.line = "#0066FF") +``` + +Notice how the genes that are in the gene set, indicated by the black bars, tend to be on the left side of the graph indicating that they have positive gene-level scores. + +#### Highly Negative NES + +The gene set `HALLMARK_MYOGENESIS` had a highly negative NES. + +```{r highly_neg} +enrichplot::gseaplot(gsea_results, + geneSetID = "HALLMARK_MYOGENESIS", + title = "HALLMARK_MYOGENESIS", + color.line = "#0066FF") +``` + +This gene set shows the opposite pattern -- genes in the pathway tend to be on the right side of the graph. + +#### A non-significant result + +The `@results` slot will only show gene sets that pass the `pvalueCutoff` threshold we supplied to `GSEA()`, but we can plot any gene set so long as we know its name. +Let's look at `HALLMARK_P53_PATHWAY`, which was not in the results we viewed earlier. + +```{r p53, live = TRUE} + +``` + +Genes in the pathway are distributed more evenly throughout the ranked list, resulting in a more "middling" score. + +*Note: The plots returned by `enrichplot::gseaplot` are ggplots, so we could use `ggplot2::ggsave()` to save them to file if we wanted to.* + +## Session Info + +```{r session_info} +sessionInfo() +``` diff --git a/scRNA-seq-advanced/04-gene_set_enrichment_analysis.nb.html b/scRNA-seq-advanced/04-gene_set_enrichment_analysis.nb.html index 5197164f..306d4f57 100644 --- a/scRNA-seq-advanced/04-gene_set_enrichment_analysis.nb.html +++ b/scRNA-seq-advanced/04-gene_set_enrichment_analysis.nb.html @@ -2938,27 +2938,29 @@

Set up

Libraries

- +
# Package to run GSEA
 library(clusterProfiler)
- -

-Registered S3 method overwritten by 'data.table':
-  method           from
-  print.data.table     
-clusterProfiler v4.12.0  For help: https://yulab-smu.top/biomedical-knowledge-mining-book/
+
+
+ + +
clusterProfiler v4.12.0  For help: https://yulab-smu.top/biomedical-knowledge-mining-book/
 
 If you use clusterProfiler in published research, please cite:
-T Wu, E Hu, S Xu, M Chen, P Guo, Z Dai, T Feng, L Zhou, W Tang, L Zhan, X Fu, S Liu, X Bo, and G Yu. clusterProfiler 4.0: A universal enrichment tool for interpreting omics data. The Innovation. 2021, 2(3):100141
-
-Attaching package: ‘clusterProfiler’
-
-The following object is masked from ‘package:stats’:
+T Wu, E Hu, S Xu, M Chen, P Guo, Z Dai, T Feng, L Zhou, W Tang, L Zhan, X Fu, S Liu, X Bo, and G Yu. clusterProfiler 4.0: A universal enrichment tool for interpreting omics data. The Innovation. 2021, 2(3):100141
+ + +

+Attaching package: 'clusterProfiler'
+ + +
The following object is masked from 'package:stats':
 
     filter
- - + +
# Package that contains the MSigDB gene sets in tidy format
 library(msigdbr)
@@ -2971,7 +2973,7 @@

Directories and Files

Directories

- +
# We'll use the marker genes as GSEA input
 rms_analysis_dir <- file.path("analysis", "rms")
 
@@ -2987,7 +2989,7 @@ 

Directories

Input files

- +
input_file <- file.path(rms_analysis_dir,
                         "deseq",
                         "rms_myoblast_deseq_results.tsv")
@@ -3000,7 +3002,7 @@

Output files

We’ll save our table of GSEA results as a TSV.

- +
output_file <- file.path(results_dir,
                          "rms_myoblast_gsea_results.tsv")
@@ -3019,16 +3021,14 @@

Gene sets

Let’s take a look at what organisms the package supports.

- +
msigdbr_species()
-
-

MSigDB contains 8 different gene set collections.

@@ -3058,7 +3058,7 @@

Gene sets

category = "H" to the msigdbr() function.

- +
hs_hallmarks_df <- msigdbr(species = "Homo sapiens",
                            category = "H")
@@ -3069,7 +3069,7 @@

Gene sets

Gene Set Enrichment Analysis

Adapted from refine.bio examples

-

+

Figure 1. Subramanian et al. (2005).

GSEA calculates a pathway-level metric, called an enrichment score @@ -3096,33 +3096,31 @@

Gene Set Enrichment Analysis

DESeq2 results

- +
deseq_df <- readr::read_tsv(input_file)
- +
Rows: 60319 Columns: 27
-── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────────────────────
+── Column specification ────────────────────────────────────────────────────────
 Delimiter: "\t"
 chr  (2): ensembl_id, gene_symbol
-dbl (25): baseMean, log2FoldChange, lfcSE, pvalue, padj, SCPCL000478.mean, SCPCL000478.detected, SCPCL000479.mean, SCPCL000479.de...
+dbl (25): baseMean, log2FoldChange, lfcSE, pvalue, padj, SCPCL000478.mean, S...
 
 ℹ Use `spec()` to retrieve the full column specification for this data.
 ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
- + - +
head(deseq_df)
-
-

This data frame uses Ensembl gene identifiers. We’ll need to make @@ -3131,16 +3129,14 @@

DESeq2 results

sets.

- +
head(hs_hallmarks_df)
-
-

We can see that the gene sets from msigdbr have Ensembl @@ -3161,7 +3157,7 @@

DESeq2 results

frame of DESeq2 results.

- +
any(duplicated(deseq_df$ensembl_id))
@@ -3177,7 +3173,7 @@

Pre-ranked list

identifiers. This is step 1 – gene-level statistics.

- +
lfc_vector <- deseq_df |>
   # Extract a vector of `log2FoldChange` named by `ensembl_id`
   dplyr::pull(log2FoldChange, name = ensembl_id)
@@ -3188,26 +3184,30 @@ 

Pre-ranked list

Let’s look at the top ranked values.

- +
# Look at first entries of the log fold change vector
 head(lfc_vector)
- -
ENSG00000263366 ENSG00000223760 ENSG00000253377 ENSG00000265843 ENSG00000104722 ENSG00000228835 
-      11.364714       10.573752       10.476990       10.199449       10.019651        9.898818 
+ +
ENSG00000263366 ENSG00000223760 ENSG00000253377 ENSG00000265843 ENSG00000104722 
+      11.364714       10.573752       10.476990       10.199449       10.019651 
+ENSG00000228835 
+       9.898818 

And the bottom of the list.

- +
# Look at the last entries of the log fold change vector
 tail(lfc_vector)
- -
ENSG00000269186 ENSG00000268388 ENSG00000165606 ENSG00000285640 ENSG00000118432 ENSG00000184221 
-      -10.93216       -11.35119       -11.36925       -11.90034       -11.92082       -12.12577 
+ +
ENSG00000269186 ENSG00000268388 ENSG00000165606 ENSG00000285640 ENSG00000118432 
+      -10.93216       -11.35119       -11.36925       -11.90034       -11.92082 
+ENSG00000184221 
+      -12.12577 
@@ -3221,7 +3221,7 @@

Run GSEA

specific, commonly used gene sets (e.g., gseKEGG()).

- +
gsea_results <- GSEA(geneList = lfc_vector,  # ordered ranked gene list
                      minGSSize = 25,  # minimum gene set size
                      maxGSSize = 500,  # maximum gene set set
@@ -3231,17 +3231,25 @@ 

Run GSEA

gs_name, ensembl_gene)) # pass the correct identifier column
- -
using 'fgsea' for GSEA analysis, please cite Korotkevich et al (2019).
-
-preparing geneSet collections...
-GSEA analysis...
-Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
-  There are ties in the preranked stats (20.32% of the list).
-The order of those tied genes will be arbitrary, which may produce unexpected results.
-leading edge analysis...
-done...
- + +
using 'fgsea' for GSEA analysis, please cite Korotkevich et al (2019).
+ + +
preparing geneSet collections...
+ + +
GSEA analysis...
+ + +
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam, : There are ties in the preranked stats (20.32% of the list).
+The order of those tied genes will be arbitrary, which may produce unexpected results.
+ + +
leading edge analysis...
+ + +
done...
+

Let’s take a look at the GSEA results.

@@ -3263,7 +3271,7 @@

Run GSEA

Let’s write these results to file.

- +
gsea_results@result |> readr::write_tsv(output_file)
@@ -3281,14 +3289,14 @@

Highly Positive NES

(HALLMARK_MYC_TARGETS_V2) using a GSEA plot.

- +
enrichplot::gseaplot(gsea_results,
                      geneSetID = "HALLMARK_MYC_TARGETS_V2",
                      title = "HALLMARK_MYC_TARGETS_V2",
                      color.line = "#0066FF")
- -

+ +

@@ -3302,14 +3310,14 @@

Highly Negative NES

NES.

- +
enrichplot::gseaplot(gsea_results,
                      geneSetID = "HALLMARK_MYOGENESIS",
                      title = "HALLMARK_MYOGENESIS",
                      color.line = "#0066FF")
- -

+ +

@@ -3325,14 +3333,14 @@

A non-significant result

viewed earlier.

- +
enrichplot::gseaplot(gsea_results,
                      geneSetID = "HALLMARK_P53_PATHWAY",
                      title = "HALLMARK_P53_PATHWAY",
                      color.line = "#0066FF")
- -

+ +

@@ -3348,11 +3356,11 @@

A non-significant result

Session Info

- +
sessionInfo()
- -
R version 4.4.0 (2024-04-24)
+
+
R version 4.4.1 (2024-06-14)
 Platform: x86_64-pc-linux-gnu
 Running under: Ubuntu 22.04.4 LTS
 
@@ -3361,43 +3369,58 @@ 

Session Info

LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.20.so; LAPACK version 3.10.0 locale: - [1] LC_CTYPE=C.UTF-8 LC_NUMERIC=C LC_TIME=C.UTF-8 LC_COLLATE=C.UTF-8 LC_MONETARY=C.UTF-8 - [6] LC_MESSAGES=C.UTF-8 LC_PAPER=C.UTF-8 LC_NAME=C LC_ADDRESS=C LC_TELEPHONE=C -[11] LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C + [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C + [3] 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 + [7] LC_PAPER=en_US.UTF-8 LC_NAME=C + [9] LC_ADDRESS=C LC_TELEPHONE=C +[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C time zone: Etc/UTC tzcode source: system (glibc) attached base packages: -[1] stats graphics grDevices datasets utils methods base +[1] stats graphics grDevices utils datasets methods base other attached packages: -[1] msigdbr_7.5.1 clusterProfiler_4.12.0 +[1] msigdbr_7.5.1 clusterProfiler_4.12.0 optparse_1.7.5 loaded via a namespace (and not attached): - [1] DBI_1.2.2 gson_0.1.0 shadowtext_0.1.3 gridExtra_2.3 rlang_1.1.3 - [6] magrittr_2.0.3 DOSE_3.30.0 compiler_4.4.0 RSQLite_2.3.6 png_0.1-8 - [11] vctrs_0.6.5 reshape2_1.4.4 stringr_1.5.1 pkgconfig_2.0.3 crayon_1.5.2 - [16] fastmap_1.1.1 XVector_0.44.0 labeling_0.4.3 ggraph_2.2.1 utf8_1.2.4 - [21] HDO.db_0.99.1 tzdb_0.4.0 enrichplot_1.24.0 UCSC.utils_1.0.0 purrr_1.0.2 - [26] bit_4.0.5 xfun_0.43 zlibbioc_1.50.0 cachem_1.0.8 aplot_0.2.2 - [31] GenomeInfoDb_1.40.0 jsonlite_1.8.8 blob_1.2.4 BiocParallel_1.38.0 tweenr_2.0.3 - [36] parallel_4.4.0 R6_2.5.1 stringi_1.8.3 RColorBrewer_1.1-3 GOSemSim_2.30.0 - [41] Rcpp_1.0.12 knitr_1.46 readr_2.1.5 IRanges_2.38.0 Matrix_1.7-0 - [46] splines_4.4.0 igraph_2.0.3 tidyselect_1.2.1 qvalue_2.36.0 rstudioapi_0.16.0 - [51] yaml_2.3.8 viridis_0.6.5 codetools_0.2-20 lattice_0.22-6 tibble_3.2.1 - [56] plyr_1.8.9 treeio_1.28.0 Biobase_2.64.0 withr_3.0.0 KEGGREST_1.44.0 - [61] gridGraphics_0.5-1 scatterpie_0.2.2 polyclip_1.10-6 Biostrings_2.72.0 pillar_1.9.0 - [66] BiocManager_1.30.22 ggtree_3.12.0 renv_1.0.7 stats4_4.4.0 ggfun_0.1.4 - [71] generics_0.1.3 vroom_1.6.5 hms_1.1.3 S4Vectors_0.42.0 ggplot2_3.5.1 - [76] tidytree_0.4.6 munsell_0.5.1 scales_1.3.0 glue_1.7.0 lazyeval_0.2.2 - [81] tools_4.4.0 data.table_1.15.4 fgsea_1.30.0 babelgene_22.9 fs_1.6.4 - [86] graphlayouts_1.1.1 fastmatch_1.1-4 tidygraph_1.3.1 cowplot_1.1.3 grid_4.4.0 - [91] ape_5.8 tidyr_1.3.1 AnnotationDbi_1.66.0 colorspace_2.1-0 nlme_3.1-164 - [96] GenomeInfoDbData_1.2.12 patchwork_1.2.0 ggforce_0.4.2 cli_3.6.2 fansi_1.0.6 -[101] viridisLite_0.4.2 dplyr_1.1.4 gtable_0.3.5 yulab.utils_0.1.4 digest_0.6.35 -[106] BiocGenerics_0.50.0 ggrepel_0.9.5 ggplotify_0.1.2 farver_2.1.1 memoise_2.0.1 -[111] lifecycle_1.0.4 httr_1.4.7 GO.db_3.19.1 bit64_4.0.5 MASS_7.3-60.2
+ [1] DBI_1.2.2 gson_0.1.0 shadowtext_0.1.3 + [4] gridExtra_2.3 rlang_1.1.3 magrittr_2.0.3 + [7] DOSE_3.30.0 compiler_4.4.1 RSQLite_2.3.6 + [10] png_0.1-8 vctrs_0.6.5 reshape2_1.4.4 + [13] stringr_1.5.1 pkgconfig_2.0.3 crayon_1.5.2 + [16] fastmap_1.1.1 XVector_0.44.0 labeling_0.4.3 + [19] ggraph_2.2.1 utf8_1.2.4 HDO.db_0.99.1 + [22] rmarkdown_2.26 tzdb_0.4.0 enrichplot_1.24.0 + [25] UCSC.utils_1.0.0 purrr_1.0.2 bit_4.0.5 + [28] xfun_0.43 zlibbioc_1.50.0 cachem_1.0.8 + [31] aplot_0.2.2 GenomeInfoDb_1.40.0 jsonlite_1.8.8 + [34] blob_1.2.4 highr_0.10 BiocParallel_1.38.0 + [37] tweenr_2.0.3 parallel_4.4.1 R6_2.5.1 + [40] bslib_0.7.0 stringi_1.8.3 RColorBrewer_1.1-3 + [43] jquerylib_0.1.4 GOSemSim_2.30.0 Rcpp_1.0.12 + [46] knitr_1.46 readr_2.1.5 IRanges_2.38.0 + [49] Matrix_1.7-0 splines_4.4.1 igraph_2.0.3 + [52] tidyselect_1.2.1 qvalue_2.36.0 yaml_2.3.8 + [55] viridis_0.6.5 codetools_0.2-20 lattice_0.22-6 + [58] tibble_3.2.1 plyr_1.8.9 treeio_1.28.0 + [61] Biobase_2.64.0 withr_3.0.0 KEGGREST_1.44.0 + [64] evaluate_0.23 gridGraphics_0.5-1 scatterpie_0.2.2 + [67] getopt_1.20.4 polyclip_1.10-6 Biostrings_2.72.0 + [70] ggtree_3.12.0 pillar_1.9.0 stats4_4.4.1 + [73] ggfun_0.1.4 generics_0.1.3 vroom_1.6.5 + [76] hms_1.1.3 S4Vectors_0.42.0 ggplot2_3.5.1 + [79] tidytree_0.4.6 munsell_0.5.1 scales_1.3.0 + [82] glue_1.7.0 lazyeval_0.2.2 tools_4.4.1 + [85] data.table_1.15.4 fgsea_1.30.0 babelgene_22.9 + [88] fs_1.6.4 graphlayouts_1.1.1 fastmatch_1.1-4 + [91] tidygraph_1.3.1 cowplot_1.1.3 grid_4.4.1 + [94] ape_5.8 tidyr_1.3.1 AnnotationDbi_1.66.0 + [97] colorspace_2.1-0 nlme_3.1-164 patchwork_1.2.0 +[100] GenomeInfoDbData_1.2.12 + [ reached getOption("max.print") -- omitted 20 entries ]
diff --git a/scRNA-seq-advanced/05-aucell-live.Rmd b/scRNA-seq-advanced/05-aucell-live.Rmd new file mode 100644 index 00000000..93d9e48a --- /dev/null +++ b/scRNA-seq-advanced/05-aucell-live.Rmd @@ -0,0 +1,422 @@ +--- +title: "Pathway Analysis: AUCell" +output: + html_notebook: + toc: true + toc_float: true +author: CCDL for ALSF +date: 2024 +--- + +*Adapted from [the AUCell vignette](https://bioconductor.org/packages/release/bioc/vignettes/AUCell/inst/doc/AUCell.html) and [the `cell-type-ewings` module](https://github.com/AlexsLemonade/OpenScPCA-analysis/tree/main/analyses/cell-type-ewings) that is part of the Open Single-cell Pediatric Cancer Atlas project.* + +## Objectives + +- Introduce the `AUCell` R package +- Illustrate how AUC values are calculated +- Demonstrate how AUC values can be used for cell assignment and plotting + +--- + +In this notebook, we'll demonstrate how to use the AUCell method, introduced in [Aibar _et al_. 2017.](https://doi.org/10.1038/nmeth.4463). + +We can use AUCell when we are interested in a gene set's relative expression or activity in an individual cell. +Gene sets can come from a curated collection of prior knowledge, like the Hallmark collection we used in the last notebook, or we can use our own custom gene sets (e.g., a set of marker genes for a cell type of interest). + +A nice feature of AUCell is that it is based on ranking genes from highest to lowest expression value in an individual cell, which is helpful in the following ways ([AUCell vignette](https://bioconductor.org/packages/release/bioc/vignettes/AUCell/inst/doc/AUCell.html)): + +- It can take a number of different values as input (e.g., raw counts, TPM) +- It compensates for differences in library size, where something like averaging raw count values of genes in a gene set would not +- It scales to larger datasets, since creating rankings is not as resource-intensive as something like permutation testing, and we could split up the object into subsets of cells if needed + +AUCell calculates the area under the recovery curve (AUC), which "represents the proportion of expressed genes in the signature and their relative expression value compared to the other genes within the cell" ([Aibar _et al_. 2017.](https://doi.org/10.1038/nmeth.4463)). +We will visualize some recovery curves in the notebook to give you a better intuition about the AUC and its meaning. + +The AUC values we get out of AUCell can be used in a number of ways ([Aibar _et al_. 2017.](https://doi.org/10.1038/nmeth.4463)): + +- As continuous values we can use for visualization or clustering +- For binary assignment (i.e., "on" and "off" or "expressed" and "not expressed") if we pick a threshold either automatically using built-in functionality or manually by inspecting the distribution of scores ourselves + +We will use an snRNA-seq of a Ewing sarcoma sample from the [`SCPCP000015` project](https://scpca.alexslemonade.org/projects/SCPCP000015) on the Single-cell Pediatric Cancer Atlas Portal and two relevant gene sets from the Molecular Signatures Database (MSigDB) to demonstrate this method. + +## Set up + +### Libraries + +```{r libraries} +# We will be loading a SingleCellExperiment object into our environment but don't need to see the startup messages +suppressPackageStartupMessages({ + library(SingleCellExperiment) +}) + +# Library we'll use for the gene set analysis itself +library(AUCell) + +# Libraries for accessing and working with gene sets +library(GSEABase) +library(msigdbr) +``` + +### Directories and files + +#### Directories + +```{r setup_directories} +# Input data +ewing_data_dir <- fs::path("data", "ewing-sarcoma") +processed_dir <- fs::path(ewing_data_dir, "processed") + +# Directory for holding pathway analysis results +analysis_dir <- fs::path("analysis", "ewing-sarcoma", "pathway-analysis") +# Create if it doesn't exist yet +fs::dir_create(analysis_dir) +``` + +#### Files + +The input will be a `SingleCellExperiment` for an individual Ewing sarcoma library. + +```{r setup_input_files} +sce_file <- fs::path(processed_dir, + "SCPCS000490", + "SCPCL000822_processed.rds") +``` + +We will save the AUCell results as a table in the analysis directory. + +```{r setup_output_files, live = TRUE} + +``` + + +### Functions + +The `source()` function allows us to load in custom functions we saved in an `.R` file. + +```{r source_functions} +source(fs::path("util", "aucell_functions.R")) +``` + +This loads one custom function, called `plot_recovery_curve()`, into our environment. +This function is adapted from [the AUCell vignette](https://github.com/aertslab/AUCell/blob/91753b327a39dc7a4bbed46408ec2271c485f2f0/vignettes/AUCell.Rmd#L295-L316). + +## Set up gene sets + +We are going to use two gene sets pertaining to Ewing sarcoma. + +* [`ZHANG_TARGETS_OF_EWSR1_FLI1_FUSION`](https://www.gsea-msigdb.org/gsea/msigdb/geneset_page.jsp?geneSetName=ZHANG_TARGETS_OF_EWSR1_FLI1_FUSION), which are genes that were highly expressed in a rhabdomyosarcoma cell line engineered to express the EWSR1-FLI1 fusion. +* [`RIGGI_EWING_SARCOMA_PROGENITOR_UP`](https://www.gsea-msigdb.org/gsea/msigdb/cards/RIGGI_EWING_SARCOMA_PROGENITOR_UP), which are genes that were highly expressed in mesenchymal stem cells engineered to express the EWS-FLI1 fusion protein. + +We would expect both of these gene sets to have high expression in tumor cells. + +```{r genesets} +# Create a named vector with the relevant gene set names +ewing_gene_set_names <- c(zhang = "ZHANG_TARGETS_OF_EWSR1_FLI1_FUSION", + riggi = "RIGGI_EWING_SARCOMA_PROGENITOR_UP") + +ewing_gene_set_names +``` + +These gene sets come from the C2 gene set collection from MSigDB. +Let's retrieve them using `msigdbr()`. + +```{r extract_genesets, live = TRUE} + +``` + +`AUCell` uses gene sets in a particular format that comes from the `GSEABase` package. +We need to create a `GeneSetCollection`. + +```{r gene_set_collection} +ewing_gene_set_collection <- ewing_gene_set_names |> + purrr::map( + # For each gene set + \(gene_set_name) { + ewing_gene_sets_df |> + # Subset to the rows in that gene set + dplyr::filter(gs_name == gene_set_name) |> + # Grab the Ensembl gene identifiers + dplyr::pull(ensembl_gene) |> + # Create a GeneSet object + GeneSet(setName = gene_set_name, + geneIdType = ENSEMBLIdentifier()) + } + ) |> + # Turn the list of GeneSet objects into a GeneSet collection + GeneSetCollection() +``` + +## Read in and prepare SingleCellExperiment + +```{r read_in_sce, live = TRUE} + +``` + +The `AUCell` functions takes an expression matrix with genes as rows and cells as column. +We can extract a counts matrix in sparse format for use with `AUCell`. + +```{r counts_matrix} +# Extract counts matrix +counts_matrix <- counts(sce) +``` + +There may be genes in our gene set that do not appear in the SingleCellExperiment object. +We can remove them using the `subsetGeneSets()` function. + +```{r subset_gene_sets, live = TRUE} +# Remove genes from gene sets if they are not in the SCE + +``` + +## AUCell + +AUCell relies on ranking genes from highest to lowest expression value to calculate the AUC. +The AUC is the area under the recovery curve, which captures the number of genes in a gene set that are present in the rankings above some threshold (i.e., it is the area under the curve to the left of this gene rank). +By default, the top 5% of genes are used as the threshold. + +Some genes will not be detected (i.e., have 0 counts). +Genes can also have the same expression level (i.e., ties). +These undetected genes and ties will be randomly ordered in our ranking. +To make our rankings – and therefore results – reproducible, we will set a seed. + +```{r set_seed, live = TRUE} + +``` + +### Cell ranking + +The first step in AUCell is to rank genes for each cell from highest to lowest expression value. +We can do this using the `AUCell_buildRankings()` function, which will output a visualization showing the distribution of the number of genes detected in the cells in our SingleCellExperiment object. + +```{r cell_rankings, live = TRUE} + +``` + +The AUCell authors recommend making sure most cells have at least the number of genes we will use as the max rank to calculate the AUC. + +The AUC max rank value tells AUCell the cutoff in the gene rankings to use for calculating AUC; we will visualize this curve and max rank in just a moment. +If we picked a max rank higher than the number of genes detected in most cells, the non-detected genes that are randomly ordered would play an outsized role in our AUC values. + +By default, the max rank is the top 5% highest expressed genes. +We can calculate the default max rank by taking into account the number of genes. + +```{r explore_auc_max_rank} +nrow(cell_rankings) * 0.05 +``` + +This number is probably too high, given the distribution of the number of genes detected by cell we visualized with `AUCell_buildRankings()`. + +What if we chose a 1% threshold? + +```{r lower_max_rank, live = TRUE} + +``` + +That is probably a more reasonable choice for this dataset. + +We can use a function called `ceiling()` to round this and save it to a variable for later use. + +```{r auc_max_rank, live = TRUE} + +``` + +### Plotting AUC + +The AUC values we get out of AUCell are the area under a recovery curve and estimate the proportion of genes in the gene set that are highly expressed (i.e., highly ranked). + +Let's plot the recovery curve for a cell with high AUC and a cell with low AUC to get a better intuition about AUC values. +Earlier, we loaded a custom function we adapted from [the AUCell vignette](https://github.com/aertslab/AUCell/blob/91753b327a39dc7a4bbed46408ec2271c485f2f0/vignettes/AUCell.Rmd) called `plot_recovery_curve()` with `source()`. + +First, we'll start with a cell with a high AUC. +We picked this barcode ahead of time when we wrote the notebook. + +```{r high_recovery_curve} +plot_recovery_curve(cell_rankings, + ewing_gene_set_collection, + gene_set_name = "ZHANG_TARGETS_OF_EWSR1_FLI1_FUSION", + barcode = "CTGAGCGGTCTTTATC", + auc_max_rank = auc_max_rank) # 1% threshold +``` + +The x-axis is the gene ranks for all genes. +The y-axis is the number of genes in the signature at a given point in the gene ranking – the line will rise when a gene in the gene set is encountered in the ranking from highest to lowest. +The AUC is the area under this recovery curve at the max rank threshold chosen for this dataset. + +Now, let's look at an example with a low AUC. + +```{r low_recovery_curve} +plot_recovery_curve(cell_rankings, + ewing_gene_set_collection, + gene_set_name = "ZHANG_TARGETS_OF_EWSR1_FLI1_FUSION", + barcode = "AGATAGAGTCACAATC", + auc_max_rank = auc_max_rank) # 1% threshold +``` + +Far fewer genes in the gene set are ranked above the threshold, yielding a lower AUC value. + +### Calculating the AUC + +Once we have the rankings, we can calculate the AUC scores for both gene sets in all cells with the `AUCell_calcAUC()` function. + +```{r calc_auc, live = TRUE} + +``` + +This function returns an `aucellResults` object. + +```{r check_str, live = TRUE} + +``` + +It can be much more convenient to work with this in a tabular format. + +```{r auc_to_table} +# Extract AUC +auc_df <- cell_auc@assays@data$AUC |> + # Transpose + t() |> + # Convert to data frame + as.data.frame() |> + # Make the barcodes a column + tibble::rownames_to_column("barcodes") + +# Look at first few rows +head(auc_df) +``` + +### Assignments + +AUCell can assign cells as having an active gene set or not by picking a threshold automatically. +We'll explore these in a later plot, but for now, let's calculate the threshold and assign cells with `AUCell_exploreThresholds()`. + +```{r auc_assignments, live = TRUE} + +``` + +We're going to plot the distribution of AUC values with `ggplot2`, so we will want the AUC values in a longer format. + +```{r auc_plotting_df} +auc_plotting_df <- auc_df |> + tidyr::pivot_longer(!barcodes, + names_to = "gene_set", + values_to = "auc") |> + dplyr::mutate( + # Create a new logical column called assigned + assigned = dplyr::case_when( + # For Zhang gene set rows, set to TRUE when the barcode is in the + # assignment list + gene_set == ewing_gene_set_names[["zhang"]] & + barcodes %in% auc_assignments[[ewing_gene_set_names[["zhang"]]]]$assignment ~ TRUE, + # For Riggi gene set rows, set to TRUE when the barcode is in the + # assignment list + gene_set == ewing_gene_set_names[["riggi"]] & + barcodes %in% auc_assignments[[ewing_gene_set_names[["riggi"]]]]$assignment ~ TRUE, + # Otherwise, set to FALSE + .default = FALSE + ) + ) + +auc_plotting_df +``` + +To draw vertical lines representing the automatically chosen threshold, we can create a separate data frame. + +```{r auc_threshold_df} +auc_threshold_df <- data.frame( + gene_set = ewing_gene_set_names, + # Grab thresholds associated with each gene set from assignements object + threshold = c(auc_assignments[[ewing_gene_set_names["zhang"]]]$aucThr$selected, + auc_assignments[[ewing_gene_set_names["riggi"]]]$aucThr$selected) +) + +auc_threshold_df +``` + +Now let's make a density plot, plotting the density of the assigned and unassigned cells separately and drawing a vertical line for the threshold. + +```{r auc_density_plot} +auc_plotting_df |> + ggplot2::ggplot( + ggplot2::aes( + x = auc, # AUC values + color = assigned, # Group by assignment + fill = assigned, # Group by assignment + ) + ) + + ggplot2::geom_density(alpha = 0.2) + + # Draw a vertical dotted line showing the threshold for each gene set + ggplot2::geom_vline(data = auc_threshold_df, + mapping = ggplot2::aes(xintercept = threshold), + lty = 2) + + # Plot each gene set in its own facet + ggplot2::facet_grid(cols = ggplot2::vars(gene_set)) + + # Use a built-in theme + ggplot2::theme_bw() +``` + +For these particular gene sets, the AUC values appear to be bimodally distributed, and we can easily identify cells where the genes are highly expressed. + +Let's write this table to the output file. + +```{r save_auc} +auc_plotting_df |> + readr::write_tsv(output_file) +``` + +### UMAPs + +#### Adding AUC to `colData` + +We can also add the AUC values back into the SingleCellExperiment for convenience, e.g., for plotting. +We'll add it to the existing `colData`. + +First, let's rename the gene set columns to something more easily typed. + +```{r rename_gene_set} +auc_df <- auc_df |> + # Use shorter names + dplyr::rename(zhang_auc = ewing_gene_set_names[["zhang"]], + riggi_auc = ewing_gene_set_names[["riggi"]]) + +``` + +And join it to the existing `colData`. + +```{r coldata, live = TRUE} +# Extract the existing colData, and left join it with the AUC values by the +# barcodes + +``` + +Now, we're ready to add it back to the object. + +```{r add_back_colData, live = TRUE} +# We need to save this as a DataFrame + +``` + +#### Plotting UMAPs + +We can use the `plotUMAP()` function from the `scater` package to plot a UMAP with the points colored by the AUC value + +```{r plot_umap_zhang} +scater::plotUMAP(sce, colour_by = "zhang_auc") + + # Use the gene set name, replacing underscores with spaces + ggplot2::ggtitle(stringr::str_replace_all(ewing_gene_set_names[["zhang"]], + "\\_", + " ")) +``` + +Let's color the points by the AUC values for the other gene set. + +```{r plot_umap_riggi, live = TRUE} + +``` + +We would want to do something more formal to confirm, but it seems like the same cells have high AUC values for both gene sets! + +## Session Info + +```{r session_info} +sessionInfo() +``` diff --git a/scRNA-seq-advanced/05-aucell.nb.html b/scRNA-seq-advanced/05-aucell.nb.html index 696c8222..9bb6719d 100644 --- a/scRNA-seq-advanced/05-aucell.nb.html +++ b/scRNA-seq-advanced/05-aucell.nb.html @@ -2946,41 +2946,45 @@

Set up

Libraries

- +
# We will be loading a SingleCellExperiment object into our environment but don't need to see the startup messages
 suppressPackageStartupMessages({
   library(SingleCellExperiment)
 })
- -
Warning: replacing previous import ‘S4Arrays::makeNindexFromArrayViewport’ by ‘DelayedArray::makeNindexFromArrayViewport’ when loading ‘SummarizedExperiment’
- - + +
Warning: replacing previous import 'S4Arrays::makeNindexFromArrayViewport' by
+'DelayedArray::makeNindexFromArrayViewport' when loading 'SummarizedExperiment'
+ +
# Library we'll use for the gene set analysis itself
-library(AUCell)
- - -
Registered S3 method overwritten by 'data.table':
-  method           from
-  print.data.table     
- - -
# Libraries for accessing and working with gene sets
+library(AUCell)
+
+# Libraries for accessing and working with gene sets
 library(GSEABase)
- -
Loading required package: annotate
-Loading required package: AnnotationDbi
-Loading required package: XML
-Loading required package: graph
-
-Attaching package: ‘graph’
-
-The following object is masked from ‘package:XML’:
+
+
Loading required package: annotate
+ + +
Loading required package: AnnotationDbi
+ + +
Loading required package: XML
+ + +
Loading required package: graph
+ + +

+Attaching package: 'graph'
+ + +
The following object is masked from 'package:XML':
 
     addNode
- - + +
library(msigdbr)
@@ -2992,7 +2996,7 @@

Directories and files

Directories

- +
# Input data 
 ewing_data_dir <- fs::path("data", "ewing-sarcoma")
 processed_dir <- fs::path(ewing_data_dir, "processed")
@@ -3011,7 +3015,7 @@ 

Files

individual Ewing sarcoma library.

- +
sce_file <- fs::path(processed_dir, 
                      "SCPCS000490", 
                      "SCPCL000822_processed.rds")
@@ -3022,7 +3026,7 @@

Files

directory.

- +
output_file <- fs::path(analysis_dir,
                         "ewing_sarcoma_aucell_results.tsv")
@@ -3036,7 +3040,7 @@

Functions

functions we saved in an .R file.

- +
source(fs::path("util", "aucell_functions.R"))
@@ -3062,7 +3066,7 @@

Set up gene sets

tumor cells.

- +
# Create a named vector with the relevant gene set names
 ewing_gene_set_names <- c(zhang = "ZHANG_TARGETS_OF_EWSR1_FLI1_FUSION",
                           riggi = "RIGGI_EWING_SARCOMA_PROGENITOR_UP")
@@ -3073,13 +3077,17 @@ 

Set up gene sets

                               zhang                                riggi 
 "ZHANG_TARGETS_OF_EWSR1_FLI1_FUSION"  "RIGGI_EWING_SARCOMA_PROGENITOR_UP" 
+ +
ZHANG_TARGETS_OF_EWSR1_FLI1_FUSION
+RIGGI_EWING_SARCOMA_PROGENITOR_UP
+

These gene sets come from the C2 gene set collection from MSigDB. Let’s retrieve them using msigdbr().

- +
ewing_gene_sets_df <- msigdbr(species = "Homo sapiens",
                               category = "C2",
                               subcategory = "CGP") |>
@@ -3092,7 +3100,7 @@ 

Set up gene sets

GeneSetCollection.

- +
ewing_gene_set_collection <- ewing_gene_set_names |>
   purrr::map(
     # For each gene set
@@ -3117,7 +3125,7 @@ 

Set up gene sets

Read in and prepare SingleCellExperiment

- +
sce <- readr::read_rds(sce_file)
@@ -3127,7 +3135,7 @@

Read in and prepare SingleCellExperiment

sparse format for use with AUCell.

- +
# Extract counts matrix
 counts_matrix <- counts(sce)
@@ -3138,7 +3146,7 @@

Read in and prepare SingleCellExperiment

subsetGeneSets() function.

- +
# Remove genes from gene sets if they are not in the SCE
 ewing_gene_set_collection <- subsetGeneSets(ewing_gene_set_collection,
                                             rownames(counts_matrix))
@@ -3160,7 +3168,7 @@

AUCell

therefore results – reproducible, we will set a seed.

- +
set.seed(2024)
@@ -3174,20 +3182,20 @@

Cell ranking

in the cells in our SingleCellExperiment object.

- +
cell_rankings <- AUCell_buildRankings(counts_matrix)
- +
Quantiles for the number of genes detected by cell: 
 (Non-detected genes are shuffled at the end of the ranking. Keep it in mind when choosing the threshold for calculating the AUC).
- + + +

+
    min      1%      5%     10%     50%    100% 
  213.00  465.76  795.80 1102.20 2238.00 6608.00 
- -

-

The AUCell authors recommend making sure most cells have at least the @@ -3202,7 +3210,7 @@

Cell ranking

genes.

- +
nrow(cell_rankings) * 0.05
@@ -3216,7 +3224,7 @@

Cell ranking

What if we chose a 1% threshold?

- +
nrow(cell_rankings) * 0.01
@@ -3229,7 +3237,7 @@

Cell ranking

save it to a variable for later use.

- +
auc_max_rank <- ceiling(nrow(cell_rankings) * 0.01)
@@ -3249,15 +3257,15 @@

Plotting AUC

barcode ahead of time when we wrote the notebook.

- +
plot_recovery_curve(cell_rankings,
                     ewing_gene_set_collection,
                     gene_set_name = "ZHANG_TARGETS_OF_EWSR1_FLI1_FUSION",
                     barcode = "CTGAGCGGTCTTTATC",
                     auc_max_rank = auc_max_rank)  # 1% threshold 
- -

+ +

@@ -3269,15 +3277,15 @@

Plotting AUC

Now, let’s look at an example with a low AUC.

- +
plot_recovery_curve(cell_rankings,
                     ewing_gene_set_collection,
                     gene_set_name = "ZHANG_TARGETS_OF_EWSR1_FLI1_FUSION",
                     barcode = "AGATAGAGTCACAATC",
                     auc_max_rank = auc_max_rank)  # 1% threshold
- -

+ +

@@ -3291,7 +3299,7 @@

Calculating the AUC

function.

- +
cell_auc <- AUCell_calcAUC(geneSets = ewing_gene_set_collection, 
                            rankings = cell_rankings,
                            aucMaxRank = auc_max_rank)
@@ -3301,7 +3309,7 @@

Calculating the AUC

This function returns an aucellResults object.

- +
str(cell_auc)
@@ -3340,7 +3348,7 @@

Calculating the AUC

format.

- +
# Extract AUC
 auc_df <- cell_auc@assays@data$AUC |>
   # Transpose
@@ -3353,13 +3361,11 @@ 

Calculating the AUC

# Look at first few rows head(auc_df)
-
- @@ -3371,21 +3377,11 @@

Assignments

AUCell_exploreThresholds().

- +
auc_assignments <- AUCell_exploreThresholds(cell_auc, 
                                             plotHist = FALSE, 
                                             assignCells = TRUE)
- -
Registered S3 methods overwritten by 'htmltools':
-  method               from         
-  print.html           tools:rstudio
-  print.shiny.tag      tools:rstudio
-  print.shiny.tag.list tools:rstudio
-Registered S3 method overwritten by 'htmlwidgets':
-  method           from         
-  print.htmlwidget tools:rstudio
-

We’re going to plot the distribution of AUC values with @@ -3393,7 +3389,7 @@

Assignments

format.

- +
auc_plotting_df <- auc_df |>
   tidyr::pivot_longer(!barcodes,
                       names_to = "gene_set",
@@ -3416,20 +3412,18 @@ 

Assignments

auc_plotting_df
-
-

To draw vertical lines representing the automatically chosen threshold, we can create a separate data frame.

- +
auc_threshold_df <- data.frame(
   gene_set = ewing_gene_set_names,
   # Grab thresholds associated with each gene set from assignements object
@@ -3439,13 +3433,11 @@ 

Assignments

auc_threshold_df
-
-

Now let’s make a density plot, plotting the density of the assigned @@ -3453,7 +3445,7 @@

Assignments

threshold.

- +
auc_plotting_df |>
   ggplot2::ggplot(
     ggplot2::aes(
@@ -3472,8 +3464,8 @@ 

Assignments

# Use a built-in theme ggplot2::theme_bw()
- -

+ +

@@ -3483,7 +3475,7 @@

Assignments

Let’s write this table to the output file.

- +
auc_plotting_df |> 
   readr::write_tsv(output_file)
@@ -3501,19 +3493,18 @@

Adding AUC to colData

typed.

- +
auc_df <- auc_df |>
   # Use shorter names
   dplyr::rename(zhang_auc = ewing_gene_set_names[["zhang"]],
-                riggi_auc = ewing_gene_set_names[["riggi"]])
-
+ riggi_auc = ewing_gene_set_names[["riggi"]])

And join it to the existing colData.

- +
# Extract the existing colData, and left join it with the AUC values by the
 # barcodes
 coldata_df <- colData(sce) |>
@@ -3528,7 +3519,7 @@ 

Adding AUC to colData

Now, we’re ready to add it back to the object.

- +
# We need to save this as a DataFrame
 colData(sce) <- DataFrame(
   coldata_df,
@@ -3545,29 +3536,29 @@ 

Plotting UMAPs

the AUC value

- +
scater::plotUMAP(sce, colour_by = "zhang_auc") +
   # Use the gene set name, replacing underscores with spaces
   ggplot2::ggtitle(stringr::str_replace_all(ewing_gene_set_names[["zhang"]], 
                                             "\\_", 
                                             " "))
- -

+ +

Let’s color the points by the AUC values for the other gene set.

- +
scater::plotUMAP(sce, colour_by = "riggi_auc") + 
   ggplot2::ggtitle(stringr::str_replace_all(ewing_gene_set_names[["riggi"]], 
                                             "\\_", 
                                             " "))
- -

+ +

@@ -3580,11 +3571,11 @@

Plotting UMAPs

Session Info

- +
sessionInfo()
- -
R version 4.4.0 (2024-04-24)
+
+
R version 4.4.1 (2024-06-14)
 Platform: x86_64-pc-linux-gnu
 Running under: Ubuntu 22.04.4 LTS
 
@@ -3593,48 +3584,88 @@ 

Session Info

LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.20.so; LAPACK version 3.10.0 locale: - [1] LC_CTYPE=C.UTF-8 LC_NUMERIC=C LC_TIME=C.UTF-8 LC_COLLATE=C.UTF-8 LC_MONETARY=C.UTF-8 LC_MESSAGES=C.UTF-8 - [7] LC_PAPER=C.UTF-8 LC_NAME=C LC_ADDRESS=C LC_TELEPHONE=C LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C + [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C + [3] 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 + [7] LC_PAPER=en_US.UTF-8 LC_NAME=C + [9] LC_ADDRESS=C LC_TELEPHONE=C +[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C time zone: Etc/UTC tzcode source: system (glibc) attached base packages: -[1] stats4 stats graphics grDevices datasets utils methods base +[1] stats4 stats graphics grDevices utils datasets methods +[8] base other attached packages: - [1] msigdbr_7.5.1 GSEABase_1.66.0 graph_1.82.0 annotate_1.82.0 XML_3.99-0.16.1 - [6] AnnotationDbi_1.66.0 AUCell_1.26.0 SingleCellExperiment_1.26.0 SummarizedExperiment_1.34.0 Biobase_2.64.0 -[11] GenomicRanges_1.56.0 GenomeInfoDb_1.40.0 IRanges_2.38.0 S4Vectors_0.42.0 BiocGenerics_0.50.0 -[16] MatrixGenerics_1.16.0 matrixStats_1.3.0 + [1] msigdbr_7.5.1 GSEABase_1.66.0 + [3] graph_1.82.0 annotate_1.82.0 + [5] XML_3.99-0.16.1 AnnotationDbi_1.66.0 + [7] AUCell_1.26.0 SingleCellExperiment_1.26.0 + [9] SummarizedExperiment_1.34.0 Biobase_2.64.0 +[11] GenomicRanges_1.56.0 GenomeInfoDb_1.40.0 +[13] IRanges_2.38.0 S4Vectors_0.42.0 +[15] BiocGenerics_0.50.0 MatrixGenerics_1.16.0 +[17] matrixStats_1.3.0 optparse_1.7.5 loaded via a namespace (and not attached): - [1] DBI_1.2.2 gridExtra_2.3 rlang_1.1.3 magrittr_2.0.3 scater_1.32.0 - [6] compiler_4.4.0 RSQLite_2.3.6 DelayedMatrixStats_1.26.0 png_0.1-8 vctrs_0.6.5 - [11] stringr_1.5.1 pkgconfig_2.0.3 crayon_1.5.2 fastmap_1.1.1 XVector_0.44.0 - [16] scuttle_1.14.0 labeling_0.4.3 utf8_1.2.4 tzdb_0.4.0 ggbeeswarm_0.7.2 - [21] UCSC.utils_1.0.0 purrr_1.0.2 bit_4.0.5 xfun_0.43 beachmat_2.20.0 - [26] zlibbioc_1.50.0 cachem_1.0.8 jsonlite_1.8.8 blob_1.2.4 DelayedArray_0.30.0 - [31] BiocParallel_1.38.0 irlba_2.3.5.1 parallel_4.4.0 R6_2.5.1 stringi_1.8.3 - [36] Rcpp_1.0.12 knitr_1.46 mixtools_2.0.0 R.utils_2.12.3 readr_2.1.5 - [41] Matrix_1.7-0 splines_4.4.0 tidyselect_1.2.1 viridis_0.6.5 rstudioapi_0.16.0 - [46] abind_1.4-5 yaml_2.3.8 codetools_0.2-20 lattice_0.22-6 tibble_3.2.1 - [51] withr_3.0.0 KEGGREST_1.44.0 survival_3.5-8 kernlab_0.9-33 Biostrings_2.72.0 - [56] pillar_1.9.0 BiocManager_1.30.22 renv_1.0.7 plotly_4.10.4 generics_0.1.3 - [61] vroom_1.6.5 hms_1.1.3 ggplot2_3.5.1 sparseMatrixStats_1.16.0 munsell_0.5.1 - [66] scales_1.3.0 xtable_1.8-4 glue_1.7.0 lazyeval_0.2.2 tools_4.4.0 - [71] BiocNeighbors_1.22.0 data.table_1.15.4 ScaledMatrix_1.12.0 babelgene_22.9 fs_1.6.4 - [76] cowplot_1.1.3 grid_4.4.0 tidyr_1.3.1 colorspace_2.1-0 nlme_3.1-164 - [81] GenomeInfoDbData_1.2.12 beeswarm_0.4.0 BiocSingular_1.20.0 vipor_0.4.7 rsvd_1.0.5 - [86] cli_3.6.2 fansi_1.0.6 segmented_2.1-3 S4Arrays_1.4.0 viridisLite_0.4.2 - [91] dplyr_1.1.4 gtable_0.3.5 R.methodsS3_1.8.2 digest_0.6.35 ggrepel_0.9.5 - [96] SparseArray_1.4.0 farver_2.1.1 htmlwidgets_1.6.4 memoise_2.0.1 htmltools_0.5.8.1 -[101] R.oo_1.26.0 lifecycle_1.0.4 httr_1.4.7 bit64_4.0.5 MASS_7.3-60.2
+ [1] jsonlite_1.8.8 magrittr_2.0.3 + [3] ggbeeswarm_0.7.2 farver_2.1.1 + [5] rmarkdown_2.26 fs_1.6.4 + [7] zlibbioc_1.50.0 vctrs_0.6.5 + [9] memoise_2.0.1 DelayedMatrixStats_1.26.0 + [11] htmltools_0.5.8.1 S4Arrays_1.4.0 + [13] BiocNeighbors_1.22.0 SparseArray_1.4.0 + [15] sass_0.4.9 bslib_0.7.0 + [17] htmlwidgets_1.6.4 plotly_4.10.4 + [19] cachem_1.0.8 lifecycle_1.0.4 + [21] pkgconfig_2.0.3 rsvd_1.0.5 + [23] Matrix_1.7-0 R6_2.5.1 + [25] fastmap_1.1.1 GenomeInfoDbData_1.2.12 + [27] digest_0.6.35 colorspace_2.1-0 + [29] scater_1.32.0 irlba_2.3.5.1 + [31] RSQLite_2.3.6 beachmat_2.20.0 + [33] labeling_0.4.3 fansi_1.0.6 + [35] httr_1.4.7 abind_1.4-5 + [37] compiler_4.4.1 bit64_4.0.5 + [39] withr_3.0.0 BiocParallel_1.38.0 + [41] viridis_0.6.5 DBI_1.2.2 + [43] highr_0.10 R.utils_2.12.3 + [45] MASS_7.3-60.2 DelayedArray_0.30.0 + [47] tools_4.4.1 vipor_0.4.7 + [49] beeswarm_0.4.0 R.oo_1.26.0 + [51] glue_1.7.0 nlme_3.1-164 + [53] grid_4.4.1 generics_0.1.3 + [55] gtable_0.3.5 tzdb_0.4.0 + [57] R.methodsS3_1.8.2 tidyr_1.3.1 + [59] data.table_1.15.4 hms_1.1.3 + [61] BiocSingular_1.20.0 ScaledMatrix_1.12.0 + [63] utf8_1.2.4 XVector_0.44.0 + [65] ggrepel_0.9.5 pillar_1.9.0 + [67] stringr_1.5.1 babelgene_22.9 + [69] vroom_1.6.5 splines_4.4.1 + [71] dplyr_1.1.4 getopt_1.20.4 + [73] lattice_0.22-6 survival_3.5-8 + [75] bit_4.0.5 tidyselect_1.2.1 + [77] Biostrings_2.72.0 scuttle_1.14.0 + [79] knitr_1.46 gridExtra_2.3 + [81] xfun_0.43 mixtools_2.0.0 + [83] stringi_1.8.3 UCSC.utils_1.0.0 + [85] lazyeval_0.2.2 yaml_2.3.8 + [87] evaluate_0.23 codetools_0.2-20 + [89] kernlab_0.9-33 tibble_3.2.1 + [91] cli_3.6.2 xtable_1.8-4 + [93] segmented_2.1-3 munsell_0.5.1 + [95] jquerylib_0.1.4 Rcpp_1.0.12 + [97] png_0.1-8 parallel_4.4.1 + [99] ggplot2_3.5.1 readr_2.1.5 + [ reached getOption("max.print") -- omitted 9 entries ]
-
LS0tCnRpdGxlOiAiUGF0aHdheSBBbmFseXNpczogQVVDZWxsIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCmF1dGhvcjogQ0NETCBmb3IgQUxTRgpkYXRlOiAyMDI0Ci0tLQoKKkFkYXB0ZWQgZnJvbSBbdGhlIEFVQ2VsbCB2aWduZXR0ZV0oaHR0cHM6Ly9iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL3JlbGVhc2UvYmlvYy92aWduZXR0ZXMvQVVDZWxsL2luc3QvZG9jL0FVQ2VsbC5odG1sKSBhbmQgW3RoZSBgY2VsbC10eXBlLWV3aW5nc2AgbW9kdWxlXShodHRwczovL2dpdGh1Yi5jb20vQWxleHNMZW1vbmFkZS9PcGVuU2NQQ0EtYW5hbHlzaXMvdHJlZS9tYWluL2FuYWx5c2VzL2NlbGwtdHlwZS1ld2luZ3MpIHRoYXQgaXMgcGFydCBvZiB0aGUgT3BlbiBTaW5nbGUtY2VsbCBQZWRpYXRyaWMgQ2FuY2VyIEF0bGFzIHByb2plY3QuKgoKIyMgT2JqZWN0aXZlcwoKLSBJbnRyb2R1Y2UgdGhlIGBBVUNlbGxgIFIgcGFja2FnZQotIElsbHVzdHJhdGUgaG93IEFVQyB2YWx1ZXMgYXJlIGNhbGN1bGF0ZWQKLSBEZW1vbnN0cmF0ZSBob3cgQVVDIHZhbHVlcyBjYW4gYmUgdXNlZCBmb3IgY2VsbCBhc3NpZ25tZW50IGFuZCBwbG90dGluZwoKLS0tCgpJbiB0aGlzIG5vdGVib29rLCB3ZSdsbCBkZW1vbnN0cmF0ZSBob3cgdG8gdXNlIHRoZSBBVUNlbGwgbWV0aG9kLCBpbnRyb2R1Y2VkIGluIFtBaWJhciBfZXQgYWxfLiAyMDE3Ll0oaHR0cHM6Ly9kb2kub3JnLzEwLjEwMzgvbm1ldGguNDQ2MykuCgpXZSBjYW4gdXNlIEFVQ2VsbCB3aGVuIHdlIGFyZSBpbnRlcmVzdGVkIGluIGEgZ2VuZSBzZXQncyByZWxhdGl2ZSBleHByZXNzaW9uIG9yIGFjdGl2aXR5IGluIGFuIGluZGl2aWR1YWwgY2VsbC4KR2VuZSBzZXRzIGNhbiBjb21lIGZyb20gYSBjdXJhdGVkIGNvbGxlY3Rpb24gb2YgcHJpb3Iga25vd2xlZGdlLCBsaWtlIHRoZSBIYWxsbWFyayBjb2xsZWN0aW9uIHdlIHVzZWQgaW4gdGhlIGxhc3Qgbm90ZWJvb2ssIG9yIHdlIGNhbiB1c2Ugb3VyIG93biBjdXN0b20gZ2VuZSBzZXRzIChlLmcuLCBhIHNldCBvZiBtYXJrZXIgZ2VuZXMgZm9yIGEgY2VsbCB0eXBlIG9mIGludGVyZXN0KS4KCkEgbmljZSBmZWF0dXJlIG9mIEFVQ2VsbCBpcyB0aGF0IGl0IGlzIGJhc2VkIG9uIHJhbmtpbmcgZ2VuZXMgZnJvbSBoaWdoZXN0IHRvIGxvd2VzdCBleHByZXNzaW9uIHZhbHVlIGluIGFuIGluZGl2aWR1YWwgY2VsbCwgd2hpY2ggaXMgaGVscGZ1bCBpbiB0aGUgZm9sbG93aW5nIHdheXMgKFtBVUNlbGwgdmlnbmV0dGVdKGh0dHBzOi8vYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9yZWxlYXNlL2Jpb2MvdmlnbmV0dGVzL0FVQ2VsbC9pbnN0L2RvYy9BVUNlbGwuaHRtbCkpOgoKLSBJdCBjYW4gdGFrZSBhIG51bWJlciBvZiBkaWZmZXJlbnQgdmFsdWVzIGFzIGlucHV0IChlLmcuLCByYXcgY291bnRzLCBUUE0pIAotIEl0IGNvbXBlbnNhdGVzIGZvciBkaWZmZXJlbmNlcyBpbiBsaWJyYXJ5IHNpemUsIHdoZXJlIHNvbWV0aGluZyBsaWtlIGF2ZXJhZ2luZyByYXcgY291bnQgdmFsdWVzIG9mIGdlbmVzIGluIGEgZ2VuZSBzZXQgd291bGQgbm90IAotIEl0IHNjYWxlcyB0byBsYXJnZXIgZGF0YXNldHMsIHNpbmNlIGNyZWF0aW5nIHJhbmtpbmdzIGlzIG5vdCBhcyByZXNvdXJjZS1pbnRlbnNpdmUgYXMgc29tZXRoaW5nIGxpa2UgcGVybXV0YXRpb24gdGVzdGluZywgYW5kIHdlIGNvdWxkIHNwbGl0IHVwIHRoZSBvYmplY3QgaW50byBzdWJzZXRzIG9mIGNlbGxzIGlmIG5lZWRlZAoKQVVDZWxsIGNhbGN1bGF0ZXMgdGhlIGFyZWEgdW5kZXIgdGhlIHJlY292ZXJ5IGN1cnZlIChBVUMpLCB3aGljaCAicmVwcmVzZW50cyB0aGUgcHJvcG9ydGlvbiBvZiBleHByZXNzZWQgZ2VuZXMgaW4gdGhlIHNpZ25hdHVyZSBhbmQgdGhlaXIgcmVsYXRpdmUgZXhwcmVzc2lvbiB2YWx1ZSBjb21wYXJlZCB0byB0aGUgb3RoZXIgZ2VuZXMgd2l0aGluIHRoZSBjZWxsIiAoW0FpYmFyIF9ldCBhbF8uIDIwMTcuXShodHRwczovL2RvaS5vcmcvMTAuMTAzOC9ubWV0aC40NDYzKSkuCldlIHdpbGwgdmlzdWFsaXplIHNvbWUgcmVjb3ZlcnkgY3VydmVzIGluIHRoZSBub3RlYm9vayB0byBnaXZlIHlvdSBhIGJldHRlciBpbnR1aXRpb24gYWJvdXQgdGhlIEFVQyBhbmQgaXRzIG1lYW5pbmcuCgpUaGUgQVVDIHZhbHVlcyB3ZSBnZXQgb3V0IG9mIEFVQ2VsbCBjYW4gYmUgdXNlZCBpbiBhIG51bWJlciBvZiB3YXlzIChbQWliYXIgX2V0IGFsXy4gMjAxNy5dKGh0dHBzOi8vZG9pLm9yZy8xMC4xMDM4L25tZXRoLjQ0NjMpKToKCi0gQXMgY29udGludW91cyB2YWx1ZXMgd2UgY2FuIHVzZSBmb3IgdmlzdWFsaXphdGlvbiBvciBjbHVzdGVyaW5nCi0gRm9yIGJpbmFyeSBhc3NpZ25tZW50IChpLmUuLCAib24iIGFuZCAib2ZmIiBvciAiZXhwcmVzc2VkIiBhbmQgIm5vdCBleHByZXNzZWQiKSBpZiB3ZSBwaWNrIGEgdGhyZXNob2xkIGVpdGhlciBhdXRvbWF0aWNhbGx5IHVzaW5nIGJ1aWx0LWluIGZ1bmN0aW9uYWxpdHkgb3IgbWFudWFsbHkgYnkgaW5zcGVjdGluZyB0aGUgZGlzdHJpYnV0aW9uIG9mIHNjb3JlcyBvdXJzZWx2ZXMKCldlIHdpbGwgdXNlIGFuIHNuUk5BLXNlcSBvZiBhIEV3aW5nIHNhcmNvbWEgc2FtcGxlIGZyb20gdGhlIFtgU0NQQ1AwMDAwMTVgIHByb2plY3RdKGh0dHBzOi8vc2NwY2EuYWxleHNsZW1vbmFkZS5vcmcvcHJvamVjdHMvU0NQQ1AwMDAwMTUpIG9uIHRoZSBTaW5nbGUtY2VsbCBQZWRpYXRyaWMgQ2FuY2VyIEF0bGFzIFBvcnRhbCBhbmQgdHdvIHJlbGV2YW50IGdlbmUgc2V0cyBmcm9tIHRoZSBNb2xlY3VsYXIgU2lnbmF0dXJlcyBEYXRhYmFzZSAoTVNpZ0RCKSB0byBkZW1vbnN0cmF0ZSB0aGlzIG1ldGhvZC4KCiMjIFNldCB1cAoKIyMjIExpYnJhcmllcwoKYGBge3IgbGlicmFyaWVzfQojIFdlIHdpbGwgYmUgbG9hZGluZyBhIFNpbmdsZUNlbGxFeHBlcmltZW50IG9iamVjdCBpbnRvIG91ciBlbnZpcm9ubWVudCBidXQgZG9uJ3QgbmVlZCB0byBzZWUgdGhlIHN0YXJ0dXAgbWVzc2FnZXMKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKICBsaWJyYXJ5KFNpbmdsZUNlbGxFeHBlcmltZW50KQp9KQoKIyBMaWJyYXJ5IHdlJ2xsIHVzZSBmb3IgdGhlIGdlbmUgc2V0IGFuYWx5c2lzIGl0c2VsZgpsaWJyYXJ5KEFVQ2VsbCkKCiMgTGlicmFyaWVzIGZvciBhY2Nlc3NpbmcgYW5kIHdvcmtpbmcgd2l0aCBnZW5lIHNldHMKbGlicmFyeShHU0VBQmFzZSkKbGlicmFyeShtc2lnZGJyKQpgYGAKCiMjIyBEaXJlY3RvcmllcyBhbmQgZmlsZXMKCiMjIyMgRGlyZWN0b3JpZXMKCmBgYHtyIHNldHVwX2RpcmVjdG9yaWVzfQojIElucHV0IGRhdGEgCmV3aW5nX2RhdGFfZGlyIDwtIGZzOjpwYXRoKCJkYXRhIiwgImV3aW5nLXNhcmNvbWEiKQpwcm9jZXNzZWRfZGlyIDwtIGZzOjpwYXRoKGV3aW5nX2RhdGFfZGlyLCAicHJvY2Vzc2VkIikKCiMgRGlyZWN0b3J5IGZvciBob2xkaW5nIHBhdGh3YXkgYW5hbHlzaXMgcmVzdWx0cwphbmFseXNpc19kaXIgPC0gZnM6OnBhdGgoImFuYWx5c2lzIiwgImV3aW5nLXNhcmNvbWEiLCAicGF0aHdheS1hbmFseXNpcyIpCiMgQ3JlYXRlIGlmIGl0IGRvZXNuJ3QgZXhpc3QgeWV0CmZzOjpkaXJfY3JlYXRlKGFuYWx5c2lzX2RpcikKYGBgCgojIyMjIEZpbGVzCgpUaGUgaW5wdXQgd2lsbCBiZSBhIGBTaW5nbGVDZWxsRXhwZXJpbWVudGAgZm9yIGFuIGluZGl2aWR1YWwgRXdpbmcgc2FyY29tYSBsaWJyYXJ5LgoKYGBge3Igc2V0dXBfaW5wdXRfZmlsZXN9CnNjZV9maWxlIDwtIGZzOjpwYXRoKHByb2Nlc3NlZF9kaXIsIAogICAgICAgICAgICAgICAgICAgICAiU0NQQ1MwMDA0OTAiLCAKICAgICAgICAgICAgICAgICAgICAgIlNDUENMMDAwODIyX3Byb2Nlc3NlZC5yZHMiKQpgYGAKCldlIHdpbGwgc2F2ZSB0aGUgQVVDZWxsIHJlc3VsdHMgYXMgYSB0YWJsZSBpbiB0aGUgYW5hbHlzaXMgZGlyZWN0b3J5LgoKYGBge3Igc2V0dXBfb3V0cHV0X2ZpbGVzLCBsaXZlID0gVFJVRX0Kb3V0cHV0X2ZpbGUgPC0gZnM6OnBhdGgoYW5hbHlzaXNfZGlyLAogICAgICAgICAgICAgICAgICAgICAgICAiZXdpbmdfc2FyY29tYV9hdWNlbGxfcmVzdWx0cy50c3YiKQpgYGAKCgojIyMgRnVuY3Rpb25zCgpUaGUgYHNvdXJjZSgpYCBmdW5jdGlvbiBhbGxvd3MgdXMgdG8gbG9hZCBpbiBjdXN0b20gZnVuY3Rpb25zIHdlIHNhdmVkIGluIGFuIGAuUmAgZmlsZS4KCmBgYHtyIHNvdXJjZV9mdW5jdGlvbnN9CnNvdXJjZShmczo6cGF0aCgidXRpbCIsICJhdWNlbGxfZnVuY3Rpb25zLlIiKSkKYGBgCgpUaGlzIGxvYWRzIG9uZSBjdXN0b20gZnVuY3Rpb24sIGNhbGxlZCBgcGxvdF9yZWNvdmVyeV9jdXJ2ZSgpYCwgaW50byBvdXIgZW52aXJvbm1lbnQuClRoaXMgZnVuY3Rpb24gaXMgYWRhcHRlZCBmcm9tIFt0aGUgQVVDZWxsIHZpZ25ldHRlXShodHRwczovL2dpdGh1Yi5jb20vYWVydHNsYWIvQVVDZWxsL2Jsb2IvOTE3NTNiMzI3YTM5ZGM3YTRiYmVkNDY0MDhlYzIyNzFjNDg1ZjJmMC92aWduZXR0ZXMvQVVDZWxsLlJtZCNMMjk1LUwzMTYpLgoKIyMgU2V0IHVwIGdlbmUgc2V0cwoKV2UgYXJlIGdvaW5nIHRvIHVzZSB0d28gZ2VuZSBzZXRzIHBlcnRhaW5pbmcgdG8gRXdpbmcgc2FyY29tYS4KCiogW2BaSEFOR19UQVJHRVRTX09GX0VXU1IxX0ZMSTFfRlVTSU9OYF0oaHR0cHM6Ly93d3cuZ3NlYS1tc2lnZGIub3JnL2dzZWEvbXNpZ2RiL2dlbmVzZXRfcGFnZS5qc3A/Z2VuZVNldE5hbWU9WkhBTkdfVEFSR0VUU19PRl9FV1NSMV9GTEkxX0ZVU0lPTiksIHdoaWNoIGFyZSBnZW5lcyB0aGF0IHdlcmUgaGlnaGx5IGV4cHJlc3NlZCBpbiBhIHJoYWJkb215b3NhcmNvbWEgY2VsbCBsaW5lIGVuZ2luZWVyZWQgdG8gZXhwcmVzcyB0aGUgRVdTUjEtRkxJMSBmdXNpb24uCiogW2BSSUdHSV9FV0lOR19TQVJDT01BX1BST0dFTklUT1JfVVBgXShodHRwczovL3d3dy5nc2VhLW1zaWdkYi5vcmcvZ3NlYS9tc2lnZGIvY2FyZHMvUklHR0lfRVdJTkdfU0FSQ09NQV9QUk9HRU5JVE9SX1VQKSwgd2hpY2ggYXJlIGdlbmVzIHRoYXQgd2VyZSBoaWdobHkgZXhwcmVzc2VkIGluIG1lc2VuY2h5bWFsIHN0ZW0gY2VsbHMgZW5naW5lZXJlZCB0byBleHByZXNzIHRoZSBFV1MtRkxJMSBmdXNpb24gcHJvdGVpbi4KCldlIHdvdWxkIGV4cGVjdCBib3RoIG9mIHRoZXNlIGdlbmUgc2V0cyB0byBoYXZlIGhpZ2ggZXhwcmVzc2lvbiBpbiB0dW1vciBjZWxscy4KCmBgYHtyIGdlbmVzZXRzfQojIENyZWF0ZSBhIG5hbWVkIHZlY3RvciB3aXRoIHRoZSByZWxldmFudCBnZW5lIHNldCBuYW1lcwpld2luZ19nZW5lX3NldF9uYW1lcyA8LSBjKHpoYW5nID0gIlpIQU5HX1RBUkdFVFNfT0ZfRVdTUjFfRkxJMV9GVVNJT04iLAogICAgICAgICAgICAgICAgICAgICAgICAgIHJpZ2dpID0gIlJJR0dJX0VXSU5HX1NBUkNPTUFfUFJPR0VOSVRPUl9VUCIpCgpld2luZ19nZW5lX3NldF9uYW1lcwpgYGAKClRoZXNlIGdlbmUgc2V0cyBjb21lIGZyb20gdGhlIEMyIGdlbmUgc2V0IGNvbGxlY3Rpb24gZnJvbSBNU2lnREIuCkxldCdzIHJldHJpZXZlIHRoZW0gdXNpbmcgYG1zaWdkYnIoKWAuCgpgYGB7ciBleHRyYWN0X2dlbmVzZXRzLCBsaXZlID0gVFJVRX0KZXdpbmdfZ2VuZV9zZXRzX2RmIDwtIG1zaWdkYnIoc3BlY2llcyA9ICJIb21vIHNhcGllbnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXRlZ29yeSA9ICJDMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YmNhdGVnb3J5ID0gIkNHUCIpIHw+CiAgZHBseXI6OmZpbHRlcihnc19uYW1lICVpbiUgZXdpbmdfZ2VuZV9zZXRfbmFtZXMpCmBgYAoKYEFVQ2VsbGAgdXNlcyBnZW5lIHNldHMgaW4gYSBwYXJ0aWN1bGFyIGZvcm1hdCB0aGF0IGNvbWVzIGZyb20gdGhlIGBHU0VBQmFzZWAgcGFja2FnZS4KV2UgbmVlZCB0byBjcmVhdGUgYSBgR2VuZVNldENvbGxlY3Rpb25gLgoKYGBge3IgZ2VuZV9zZXRfY29sbGVjdGlvbn0KZXdpbmdfZ2VuZV9zZXRfY29sbGVjdGlvbiA8LSBld2luZ19nZW5lX3NldF9uYW1lcyB8PgogIHB1cnJyOjptYXAoCiAgICAjIEZvciBlYWNoIGdlbmUgc2V0CiAgICBcKGdlbmVfc2V0X25hbWUpIHsKICAgICAgZXdpbmdfZ2VuZV9zZXRzX2RmIHw+CiAgICAgICAgIyBTdWJzZXQgdG8gdGhlIHJvd3MgaW4gdGhhdCBnZW5lIHNldAogICAgICAgIGRwbHlyOjpmaWx0ZXIoZ3NfbmFtZSA9PSBnZW5lX3NldF9uYW1lKSB8PgogICAgICAgICMgR3JhYiB0aGUgRW5zZW1ibCBnZW5lIGlkZW50aWZpZXJzCiAgICAgICAgZHBseXI6OnB1bGwoZW5zZW1ibF9nZW5lKSB8PgogICAgICAgICMgQ3JlYXRlIGEgR2VuZVNldCBvYmplY3QKICAgICAgICBHZW5lU2V0KHNldE5hbWUgPSBnZW5lX3NldF9uYW1lLAogICAgICAgICAgICAgICAgZ2VuZUlkVHlwZSA9IEVOU0VNQkxJZGVudGlmaWVyKCkpCiAgICB9CiAgKSB8PgogICMgVHVybiB0aGUgbGlzdCBvZiBHZW5lU2V0IG9iamVjdHMgaW50byBhIEdlbmVTZXQgY29sbGVjdGlvbgogIEdlbmVTZXRDb2xsZWN0aW9uKCkKYGBgCgojIyBSZWFkIGluIGFuZCBwcmVwYXJlIFNpbmdsZUNlbGxFeHBlcmltZW50CgpgYGB7ciByZWFkX2luX3NjZSwgbGl2ZSA9IFRSVUV9CnNjZSA8LSByZWFkcjo6cmVhZF9yZHMoc2NlX2ZpbGUpCmBgYAoKVGhlIGBBVUNlbGxgIGZ1bmN0aW9ucyB0YWtlcyBhbiBleHByZXNzaW9uIG1hdHJpeCB3aXRoIGdlbmVzIGFzIHJvd3MgYW5kIGNlbGxzIGFzIGNvbHVtbi4KV2UgY2FuIGV4dHJhY3QgYSBjb3VudHMgbWF0cml4IGluIHNwYXJzZSBmb3JtYXQgZm9yIHVzZSB3aXRoIGBBVUNlbGxgLgoKYGBge3IgY291bnRzX21hdHJpeH0KIyBFeHRyYWN0IGNvdW50cyBtYXRyaXgKY291bnRzX21hdHJpeCA8LSBjb3VudHMoc2NlKQpgYGAKClRoZXJlIG1heSBiZSBnZW5lcyBpbiBvdXIgZ2VuZSBzZXQgdGhhdCBkbyBub3QgYXBwZWFyIGluIHRoZSBTaW5nbGVDZWxsRXhwZXJpbWVudCBvYmplY3QuCldlIGNhbiByZW1vdmUgdGhlbSB1c2luZyB0aGUgYHN1YnNldEdlbmVTZXRzKClgIGZ1bmN0aW9uLgoKYGBge3Igc3Vic2V0X2dlbmVfc2V0cywgbGl2ZSA9IFRSVUV9CiMgUmVtb3ZlIGdlbmVzIGZyb20gZ2VuZSBzZXRzIGlmIHRoZXkgYXJlIG5vdCBpbiB0aGUgU0NFCmV3aW5nX2dlbmVfc2V0X2NvbGxlY3Rpb24gPC0gc3Vic2V0R2VuZVNldHMoZXdpbmdfZ2VuZV9zZXRfY29sbGVjdGlvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lcyhjb3VudHNfbWF0cml4KSkKYGBgCgojIyBBVUNlbGwKCkFVQ2VsbCByZWxpZXMgb24gcmFua2luZyBnZW5lcyBmcm9tIGhpZ2hlc3QgdG8gbG93ZXN0IGV4cHJlc3Npb24gdmFsdWUgdG8gY2FsY3VsYXRlIHRoZSBBVUMuClRoZSBBVUMgaXMgdGhlIGFyZWEgdW5kZXIgdGhlIHJlY292ZXJ5IGN1cnZlLCB3aGljaCBjYXB0dXJlcyB0aGUgbnVtYmVyIG9mIGdlbmVzIGluIGEgZ2VuZSBzZXQgdGhhdCBhcmUgcHJlc2VudCBpbiB0aGUgcmFua2luZ3MgYWJvdmUgc29tZSB0aHJlc2hvbGQgKGkuZS4sIGl0IGlzIHRoZSBhcmVhIHVuZGVyIHRoZSBjdXJ2ZSB0byB0aGUgbGVmdCBvZiB0aGlzIGdlbmUgcmFuaykuCkJ5IGRlZmF1bHQsIHRoZSB0b3AgNSUgb2YgZ2VuZXMgYXJlIHVzZWQgYXMgdGhlIHRocmVzaG9sZC4KClNvbWUgZ2VuZXMgd2lsbCBub3QgYmUgZGV0ZWN0ZWQgKGkuZS4sIGhhdmUgMCBjb3VudHMpLgpHZW5lcyBjYW4gYWxzbyBoYXZlIHRoZSBzYW1lIGV4cHJlc3Npb24gbGV2ZWwgKGkuZS4sIHRpZXMpLgpUaGVzZSB1bmRldGVjdGVkIGdlbmVzIGFuZCB0aWVzIHdpbGwgYmUgcmFuZG9tbHkgb3JkZXJlZCBpbiBvdXIgcmFua2luZy4KVG8gbWFrZSBvdXIgcmFua2luZ3Mg4oCTIGFuZCB0aGVyZWZvcmUgcmVzdWx0cyDigJMgcmVwcm9kdWNpYmxlLCB3ZSB3aWxsIHNldCBhIHNlZWQuCgpgYGB7ciBzZXRfc2VlZCwgbGl2ZSA9IFRSVUV9CnNldC5zZWVkKDIwMjQpCmBgYAoKIyMjIENlbGwgcmFua2luZwoKVGhlIGZpcnN0IHN0ZXAgaW4gQVVDZWxsIGlzIHRvIHJhbmsgZ2VuZXMgZm9yIGVhY2ggY2VsbCBmcm9tIGhpZ2hlc3QgdG8gbG93ZXN0IGV4cHJlc3Npb24gdmFsdWUuCldlIGNhbiBkbyB0aGlzIHVzaW5nIHRoZSBgQVVDZWxsX2J1aWxkUmFua2luZ3MoKWAgZnVuY3Rpb24sIHdoaWNoIHdpbGwgb3V0cHV0IGEgdmlzdWFsaXphdGlvbiBzaG93aW5nIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIG51bWJlciBvZiBnZW5lcyBkZXRlY3RlZCBpbiB0aGUgY2VsbHMgaW4gb3VyIFNpbmdsZUNlbGxFeHBlcmltZW50IG9iamVjdC4KCmBgYHtyIGNlbGxfcmFua2luZ3MsIGxpdmUgPSBUUlVFfQpjZWxsX3JhbmtpbmdzIDwtIEFVQ2VsbF9idWlsZFJhbmtpbmdzKGNvdW50c19tYXRyaXgpCmBgYAoKVGhlIEFVQ2VsbCBhdXRob3JzIHJlY29tbWVuZCBtYWtpbmcgc3VyZSBtb3N0IGNlbGxzIGhhdmUgYXQgbGVhc3QgdGhlIG51bWJlciBvZiBnZW5lcyB3ZSB3aWxsIHVzZSBhcyB0aGUgbWF4IHJhbmsgdG8gY2FsY3VsYXRlIHRoZSBBVUMuCgpUaGUgQVVDIG1heCByYW5rIHZhbHVlIHRlbGxzIEFVQ2VsbCB0aGUgY3V0b2ZmIGluIHRoZSBnZW5lIHJhbmtpbmdzIHRvIHVzZSBmb3IgY2FsY3VsYXRpbmcgQVVDOyB3ZSB3aWxsIHZpc3VhbGl6ZSB0aGlzIGN1cnZlIGFuZCBtYXggcmFuayBpbiBqdXN0IGEgbW9tZW50LgpJZiB3ZSBwaWNrZWQgYSBtYXggcmFuayBoaWdoZXIgdGhhbiB0aGUgbnVtYmVyIG9mIGdlbmVzIGRldGVjdGVkIGluIG1vc3QgY2VsbHMsIHRoZSBub24tZGV0ZWN0ZWQgZ2VuZXMgdGhhdCBhcmUgcmFuZG9tbHkgb3JkZXJlZCB3b3VsZCBwbGF5IGFuIG91dHNpemVkIHJvbGUgaW4gb3VyIEFVQyB2YWx1ZXMuCgpCeSBkZWZhdWx0LCB0aGUgbWF4IHJhbmsgaXMgdGhlIHRvcCA1JSBoaWdoZXN0IGV4cHJlc3NlZCBnZW5lcy4KV2UgY2FuIGNhbGN1bGF0ZSB0aGUgZGVmYXVsdCBtYXggcmFuayBieSB0YWtpbmcgaW50byBhY2NvdW50IHRoZSBudW1iZXIgb2YgZ2VuZXMuCgpgYGB7ciBleHBsb3JlX2F1Y19tYXhfcmFua30KbnJvdyhjZWxsX3JhbmtpbmdzKSAqIDAuMDUKYGBgCgpUaGlzIG51bWJlciBpcyBwcm9iYWJseSB0b28gaGlnaCwgZ2l2ZW4gdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgbnVtYmVyIG9mIGdlbmVzIGRldGVjdGVkIGJ5IGNlbGwgd2UgdmlzdWFsaXplZCB3aXRoIGBBVUNlbGxfYnVpbGRSYW5raW5ncygpYC4KCldoYXQgaWYgd2UgY2hvc2UgYSAxJSB0aHJlc2hvbGQ/CgpgYGB7ciBsb3dlcl9tYXhfcmFuaywgbGl2ZSA9IFRSVUV9Cm5yb3coY2VsbF9yYW5raW5ncykgKiAwLjAxCmBgYAoKVGhhdCBpcyBwcm9iYWJseSBhIG1vcmUgcmVhc29uYWJsZSBjaG9pY2UgZm9yIHRoaXMgZGF0YXNldC4KCldlIGNhbiB1c2UgYSBmdW5jdGlvbiBjYWxsZWQgYGNlaWxpbmcoKWAgdG8gcm91bmQgdGhpcyBhbmQgc2F2ZSBpdCB0byBhIHZhcmlhYmxlIGZvciBsYXRlciB1c2UuCgpgYGB7ciBhdWNfbWF4X3JhbmssIGxpdmUgPSBUUlVFfQphdWNfbWF4X3JhbmsgPC0gY2VpbGluZyhucm93KGNlbGxfcmFua2luZ3MpICogMC4wMSkKYGBgCgojIyMgUGxvdHRpbmcgQVVDCgpUaGUgQVVDIHZhbHVlcyB3ZSBnZXQgb3V0IG9mIEFVQ2VsbCBhcmUgdGhlIGFyZWEgdW5kZXIgYSByZWNvdmVyeSBjdXJ2ZSBhbmQgZXN0aW1hdGUgdGhlIHByb3BvcnRpb24gb2YgZ2VuZXMgaW4gdGhlIGdlbmUgc2V0IHRoYXQgYXJlIGhpZ2hseSBleHByZXNzZWQgKGkuZS4sIGhpZ2hseSByYW5rZWQpLgoKTGV0J3MgcGxvdCB0aGUgcmVjb3ZlcnkgY3VydmUgZm9yIGEgY2VsbCB3aXRoIGhpZ2ggQVVDIGFuZCBhIGNlbGwgd2l0aCBsb3cgQVVDIHRvIGdldCBhIGJldHRlciBpbnR1aXRpb24gYWJvdXQgQVVDIHZhbHVlcy4KRWFybGllciwgd2UgbG9hZGVkIGEgY3VzdG9tIGZ1bmN0aW9uIHdlIGFkYXB0ZWQgZnJvbSBbdGhlIEFVQ2VsbCB2aWduZXR0ZV0oaHR0cHM6Ly9naXRodWIuY29tL2FlcnRzbGFiL0FVQ2VsbC9ibG9iLzkxNzUzYjMyN2EzOWRjN2E0YmJlZDQ2NDA4ZWMyMjcxYzQ4NWYyZjAvdmlnbmV0dGVzL0FVQ2VsbC5SbWQpIGNhbGxlZCBgcGxvdF9yZWNvdmVyeV9jdXJ2ZSgpYCB3aXRoIGBzb3VyY2UoKWAuCgpGaXJzdCwgd2UnbGwgc3RhcnQgd2l0aCBhIGNlbGwgd2l0aCBhIGhpZ2ggQVVDLgpXZSBwaWNrZWQgdGhpcyBiYXJjb2RlIGFoZWFkIG9mIHRpbWUgd2hlbiB3ZSB3cm90ZSB0aGUgbm90ZWJvb2suCgpgYGB7ciBoaWdoX3JlY292ZXJ5X2N1cnZlfQpwbG90X3JlY292ZXJ5X2N1cnZlKGNlbGxfcmFua2luZ3MsCiAgICAgICAgICAgICAgICAgICAgZXdpbmdfZ2VuZV9zZXRfY29sbGVjdGlvbiwKICAgICAgICAgICAgICAgICAgICBnZW5lX3NldF9uYW1lID0gIlpIQU5HX1RBUkdFVFNfT0ZfRVdTUjFfRkxJMV9GVVNJT04iLAogICAgICAgICAgICAgICAgICAgIGJhcmNvZGUgPSAiQ1RHQUdDR0dUQ1RUVEFUQyIsCiAgICAgICAgICAgICAgICAgICAgYXVjX21heF9yYW5rID0gYXVjX21heF9yYW5rKSAgIyAxJSB0aHJlc2hvbGQgCmBgYAoKVGhlIHgtYXhpcyBpcyB0aGUgZ2VuZSByYW5rcyBmb3IgYWxsIGdlbmVzLgpUaGUgeS1heGlzIGlzIHRoZSBudW1iZXIgb2YgZ2VuZXMgaW4gdGhlIHNpZ25hdHVyZSBhdCBhIGdpdmVuIHBvaW50IGluIHRoZSBnZW5lIHJhbmtpbmcg4oCTIHRoZSBsaW5lIHdpbGwgcmlzZSB3aGVuIGEgZ2VuZSBpbiB0aGUgZ2VuZSBzZXQgaXMgZW5jb3VudGVyZWQgaW4gdGhlIHJhbmtpbmcgZnJvbSBoaWdoZXN0IHRvIGxvd2VzdC4KVGhlIEFVQyBpcyB0aGUgYXJlYSB1bmRlciB0aGlzIHJlY292ZXJ5IGN1cnZlIGF0IHRoZSBtYXggcmFuayB0aHJlc2hvbGQgY2hvc2VuIGZvciB0aGlzIGRhdGFzZXQuCgpOb3csIGxldCdzIGxvb2sgYXQgYW4gZXhhbXBsZSB3aXRoIGEgbG93IEFVQy4KCmBgYHtyIGxvd19yZWNvdmVyeV9jdXJ2ZX0KcGxvdF9yZWNvdmVyeV9jdXJ2ZShjZWxsX3JhbmtpbmdzLAogICAgICAgICAgICAgICAgICAgIGV3aW5nX2dlbmVfc2V0X2NvbGxlY3Rpb24sCiAgICAgICAgICAgICAgICAgICAgZ2VuZV9zZXRfbmFtZSA9ICJaSEFOR19UQVJHRVRTX09GX0VXU1IxX0ZMSTFfRlVTSU9OIiwKICAgICAgICAgICAgICAgICAgICBiYXJjb2RlID0gIkFHQVRBR0FHVENBQ0FBVEMiLAogICAgICAgICAgICAgICAgICAgIGF1Y19tYXhfcmFuayA9IGF1Y19tYXhfcmFuaykgICMgMSUgdGhyZXNob2xkCmBgYAoKRmFyIGZld2VyIGdlbmVzIGluIHRoZSBnZW5lIHNldCBhcmUgcmFua2VkIGFib3ZlIHRoZSB0aHJlc2hvbGQsIHlpZWxkaW5nIGEgbG93ZXIgQVVDIHZhbHVlLgoKIyMjIENhbGN1bGF0aW5nIHRoZSBBVUMKCk9uY2Ugd2UgaGF2ZSB0aGUgcmFua2luZ3MsIHdlIGNhbiBjYWxjdWxhdGUgdGhlIEFVQyBzY29yZXMgZm9yIGJvdGggZ2VuZSBzZXRzIGluIGFsbCBjZWxscyB3aXRoIHRoZSBgQVVDZWxsX2NhbGNBVUMoKWAgZnVuY3Rpb24uCgpgYGB7ciBjYWxjX2F1YywgbGl2ZT1UUlVFfQpjZWxsX2F1YyA8LSBBVUNlbGxfY2FsY0FVQyhnZW5lU2V0cyA9IGV3aW5nX2dlbmVfc2V0X2NvbGxlY3Rpb24sIAogICAgICAgICAgICAgICAgICAgICAgICAgICByYW5raW5ncyA9IGNlbGxfcmFua2luZ3MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGF1Y01heFJhbmsgPSBhdWNfbWF4X3JhbmspCmBgYAoKVGhpcyBmdW5jdGlvbiByZXR1cm5zIGFuIGBhdWNlbGxSZXN1bHRzYCBvYmplY3QuCgpgYGB7ciBjaGVja19zdHIsIGxpdmUgPSBUUlVFfQpzdHIoY2VsbF9hdWMpCmBgYAoKSXQgY2FuIGJlIG11Y2ggbW9yZSBjb252ZW5pZW50IHRvIHdvcmsgd2l0aCB0aGlzIGluIGEgdGFidWxhciBmb3JtYXQuCgpgYGB7ciBhdWNfdG9fdGFibGV9CiMgRXh0cmFjdCBBVUMKYXVjX2RmIDwtIGNlbGxfYXVjQGFzc2F5c0BkYXRhJEFVQyB8PgogICMgVHJhbnNwb3NlCiAgdCgpIHw+CiAgIyBDb252ZXJ0IHRvIGRhdGEgZnJhbWUKICBhcy5kYXRhLmZyYW1lKCkgfD4KICAjIE1ha2UgdGhlIGJhcmNvZGVzIGEgY29sdW1uCiAgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4oImJhcmNvZGVzIikgCgojIExvb2sgYXQgZmlyc3QgZmV3IHJvd3MKaGVhZChhdWNfZGYpCmBgYAoKIyMjIEFzc2lnbm1lbnRzCgpBVUNlbGwgY2FuIGFzc2lnbiBjZWxscyBhcyBoYXZpbmcgYW4gYWN0aXZlIGdlbmUgc2V0IG9yIG5vdCBieSBwaWNraW5nIGEgdGhyZXNob2xkIGF1dG9tYXRpY2FsbHkuCldlJ2xsIGV4cGxvcmUgdGhlc2UgaW4gYSBsYXRlciBwbG90LCBidXQgZm9yIG5vdywgbGV0J3MgY2FsY3VsYXRlIHRoZSB0aHJlc2hvbGQgYW5kIGFzc2lnbiBjZWxscyB3aXRoIGBBVUNlbGxfZXhwbG9yZVRocmVzaG9sZHMoKWAuCgpgYGB7ciBhdWNfYXNzaWdubWVudHMsIGxpdmUgPSBUUlVFfQphdWNfYXNzaWdubWVudHMgPC0gQVVDZWxsX2V4cGxvcmVUaHJlc2hvbGRzKGNlbGxfYXVjLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90SGlzdCA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NpZ25DZWxscyA9IFRSVUUpCmBgYAoKV2UncmUgZ29pbmcgdG8gcGxvdCB0aGUgZGlzdHJpYnV0aW9uIG9mIEFVQyB2YWx1ZXMgd2l0aCBgZ2dwbG90MmAsIHNvIHdlIHdpbGwgd2FudCB0aGUgQVVDIHZhbHVlcyBpbiBhIGxvbmdlciBmb3JtYXQuCgpgYGB7ciBhdWNfcGxvdHRpbmdfZGZ9CmF1Y19wbG90dGluZ19kZiA8LSBhdWNfZGYgfD4KICB0aWR5cjo6cGl2b3RfbG9uZ2VyKCFiYXJjb2RlcywKICAgICAgICAgICAgICAgICAgICAgIG5hbWVzX3RvID0gImdlbmVfc2V0IiwKICAgICAgICAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJhdWMiKSB8PgogIGRwbHlyOjptdXRhdGUoCiAgICAjIENyZWF0ZSBhIG5ldyBsb2dpY2FsIGNvbHVtbiBjYWxsZWQgYXNzaWduZWQKICAgIGFzc2lnbmVkID0gZHBseXI6OmNhc2Vfd2hlbigKICAgICAgIyBGb3IgWmhhbmcgZ2VuZSBzZXQgcm93cywgc2V0IHRvIFRSVUUgd2hlbiB0aGUgYmFyY29kZSBpcyBpbiB0aGUgCiAgICAgICMgYXNzaWdubWVudCBsaXN0CiAgICAgIGdlbmVfc2V0ID09IGV3aW5nX2dlbmVfc2V0X25hbWVzW1siemhhbmciXV0gJiAKICAgICAgICBiYXJjb2RlcyAlaW4lIGF1Y19hc3NpZ25tZW50c1tbZXdpbmdfZ2VuZV9zZXRfbmFtZXNbWyJ6aGFuZyJdXV1dJGFzc2lnbm1lbnQgfiBUUlVFLAogICAgICAjIEZvciBSaWdnaSBnZW5lIHNldCByb3dzLCBzZXQgdG8gVFJVRSB3aGVuIHRoZSBiYXJjb2RlIGlzIGluIHRoZSAKICAgICAgIyBhc3NpZ25tZW50IGxpc3QKICAgICAgZ2VuZV9zZXQgPT0gZXdpbmdfZ2VuZV9zZXRfbmFtZXNbWyJyaWdnaSJdXSAmIAogICAgICAgIGJhcmNvZGVzICVpbiUgYXVjX2Fzc2lnbm1lbnRzW1tld2luZ19nZW5lX3NldF9uYW1lc1tbInJpZ2dpIl1dXV0kYXNzaWdubWVudCB+IFRSVUUsCiAgICAgICMgT3RoZXJ3aXNlLCBzZXQgdG8gRkFMU0UKICAgICAgLmRlZmF1bHQgPSBGQUxTRQogICAgKQogICkKCmF1Y19wbG90dGluZ19kZgpgYGAKClRvIGRyYXcgdmVydGljYWwgbGluZXMgcmVwcmVzZW50aW5nIHRoZSBhdXRvbWF0aWNhbGx5IGNob3NlbiB0aHJlc2hvbGQsIHdlIGNhbiBjcmVhdGUgYSBzZXBhcmF0ZSBkYXRhIGZyYW1lLgoKYGBge3IgYXVjX3RocmVzaG9sZF9kZn0KYXVjX3RocmVzaG9sZF9kZiA8LSBkYXRhLmZyYW1lKAogIGdlbmVfc2V0ID0gZXdpbmdfZ2VuZV9zZXRfbmFtZXMsCiAgIyBHcmFiIHRocmVzaG9sZHMgYXNzb2NpYXRlZCB3aXRoIGVhY2ggZ2VuZSBzZXQgZnJvbSBhc3NpZ25lbWVudHMgb2JqZWN0CiAgdGhyZXNob2xkID0gYyhhdWNfYXNzaWdubWVudHNbW2V3aW5nX2dlbmVfc2V0X25hbWVzWyJ6aGFuZyJdXV0kYXVjVGhyJHNlbGVjdGVkLCAKICAgICAgICAgICAgICAgIGF1Y19hc3NpZ25tZW50c1tbZXdpbmdfZ2VuZV9zZXRfbmFtZXNbInJpZ2dpIl1dXSRhdWNUaHIkc2VsZWN0ZWQpCikKCmF1Y190aHJlc2hvbGRfZGYKYGBgCgpOb3cgbGV0J3MgbWFrZSBhIGRlbnNpdHkgcGxvdCwgcGxvdHRpbmcgdGhlIGRlbnNpdHkgb2YgdGhlIGFzc2lnbmVkIGFuZCB1bmFzc2lnbmVkIGNlbGxzIHNlcGFyYXRlbHkgYW5kIGRyYXdpbmcgYSB2ZXJ0aWNhbCBsaW5lIGZvciB0aGUgdGhyZXNob2xkLgoKYGBge3IgYXVjX2RlbnNpdHlfcGxvdH0KYXVjX3Bsb3R0aW5nX2RmIHw+CiAgZ2dwbG90Mjo6Z2dwbG90KAogICAgZ2dwbG90Mjo6YWVzKAogICAgICB4ID0gYXVjLCAgIyBBVUMgdmFsdWVzCiAgICAgIGNvbG9yID0gYXNzaWduZWQsICAjIEdyb3VwIGJ5IGFzc2lnbm1lbnQKICAgICAgZmlsbCA9IGFzc2lnbmVkLCAgICMgR3JvdXAgYnkgYXNzaWdubWVudAogICAgKQogICkgKwogIGdncGxvdDI6Omdlb21fZGVuc2l0eShhbHBoYSA9IDAuMikgKwogICMgRHJhdyBhIHZlcnRpY2FsIGRvdHRlZCBsaW5lIHNob3dpbmcgdGhlIHRocmVzaG9sZCBmb3IgZWFjaCBnZW5lIHNldAogIGdncGxvdDI6Omdlb21fdmxpbmUoZGF0YSA9IGF1Y190aHJlc2hvbGRfZGYsCiAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gZ2dwbG90Mjo6YWVzKHhpbnRlcmNlcHQgPSB0aHJlc2hvbGQpLAogICAgICAgICAgICAgICAgICAgICAgbHR5ID0gMikgKwogICMgUGxvdCBlYWNoIGdlbmUgc2V0IGluIGl0cyBvd24gZmFjZXQKICBnZ3Bsb3QyOjpmYWNldF9ncmlkKGNvbHMgPSBnZ3Bsb3QyOjp2YXJzKGdlbmVfc2V0KSkgKwogICMgVXNlIGEgYnVpbHQtaW4gdGhlbWUKICBnZ3Bsb3QyOjp0aGVtZV9idygpCmBgYAoKRm9yIHRoZXNlIHBhcnRpY3VsYXIgZ2VuZSBzZXRzLCB0aGUgQVVDIHZhbHVlcyBhcHBlYXIgdG8gYmUgYmltb2RhbGx5IGRpc3RyaWJ1dGVkLCBhbmQgd2UgY2FuIGVhc2lseSBpZGVudGlmeSBjZWxscyB3aGVyZSB0aGUgZ2VuZXMgYXJlIGhpZ2hseSBleHByZXNzZWQuCgpMZXQncyB3cml0ZSB0aGlzIHRhYmxlIHRvIHRoZSBvdXRwdXQgZmlsZS4KCmBgYHtyfQphdWNfcGxvdHRpbmdfZGYgfD4gCiAgcmVhZHI6OndyaXRlX3RzdihvdXRwdXRfZmlsZSkKYGBgCgojIyMgVU1BUHMKCiMjIyMgQWRkaW5nIEFVQyB0byBgY29sRGF0YWAKCldlIGNhbiBhbHNvIGFkZCB0aGUgQVVDIHZhbHVlcyBiYWNrIGludG8gdGhlIFNpbmdsZUNlbGxFeHBlcmltZW50IGZvciBjb252ZW5pZW5jZSwgZS5nLiwgZm9yIHBsb3R0aW5nLgpXZSdsbCBhZGQgaXQgdG8gdGhlIGV4aXN0aW5nIGBjb2xEYXRhYC4KCkZpcnN0LCBsZXQncyByZW5hbWUgdGhlIGdlbmUgc2V0IGNvbHVtbnMgdG8gc29tZXRoaW5nIG1vcmUgZWFzaWx5IHR5cGVkLgoKYGBge3IgcmVuYW1lX2dlbmVfc2V0fQphdWNfZGYgPC0gYXVjX2RmIHw+CiAgIyBVc2Ugc2hvcnRlciBuYW1lcwogIGRwbHlyOjpyZW5hbWUoemhhbmdfYXVjID0gZXdpbmdfZ2VuZV9zZXRfbmFtZXNbWyJ6aGFuZyJdXSwKICAgICAgICAgICAgICAgIHJpZ2dpX2F1YyA9IGV3aW5nX2dlbmVfc2V0X25hbWVzW1sicmlnZ2kiXV0pCgpgYGAKCkFuZCBqb2luIGl0IHRvIHRoZSBleGlzdGluZyBgY29sRGF0YWAuCgpgYGB7ciBjb2xkYXRhLCBsaXZlID0gVFJVRX0KIyBFeHRyYWN0IHRoZSBleGlzdGluZyBjb2xEYXRhLCBhbmQgbGVmdCBqb2luIGl0IHdpdGggdGhlIEFVQyB2YWx1ZXMgYnkgdGhlCiMgYmFyY29kZXMKY29sZGF0YV9kZiA8LSBjb2xEYXRhKHNjZSkgfD4KICBhcy5kYXRhLmZyYW1lKCkgfD4KICBkcGx5cjo6bGVmdF9qb2luKAogICAgYXVjX2RmLAogICAgYnkgPSAiYmFyY29kZXMiCiAgKQpgYGAKCk5vdywgd2UncmUgcmVhZHkgdG8gYWRkIGl0IGJhY2sgdG8gdGhlIG9iamVjdC4KCmBgYHtyIGFkZF9iYWNrX2NvbERhdGEsIGxpdmUgPSBUUlVFfQojIFdlIG5lZWQgdG8gc2F2ZSB0aGlzIGFzIGEgRGF0YUZyYW1lCmNvbERhdGEoc2NlKSA8LSBEYXRhRnJhbWUoCiAgY29sZGF0YV9kZiwKICByb3cubmFtZXMgPSBjb2xEYXRhKHNjZSkkYmFyY29kZXMKKQpgYGAKCiMjIyMgUGxvdHRpbmcgVU1BUHMKCldlIGNhbiB1c2UgdGhlIGBwbG90VU1BUCgpYCBmdW5jdGlvbiBmcm9tIHRoZSBgc2NhdGVyYCBwYWNrYWdlIHRvIHBsb3QgYSBVTUFQIHdpdGggdGhlIHBvaW50cyBjb2xvcmVkIGJ5IHRoZSBBVUMgdmFsdWUKCmBgYHtyIHBsb3RfdW1hcF96aGFuZ30Kc2NhdGVyOjpwbG90VU1BUChzY2UsIGNvbG91cl9ieSA9ICJ6aGFuZ19hdWMiKSArCiAgIyBVc2UgdGhlIGdlbmUgc2V0IG5hbWUsIHJlcGxhY2luZyB1bmRlcnNjb3JlcyB3aXRoIHNwYWNlcwogIGdncGxvdDI6OmdndGl0bGUoc3RyaW5ncjo6c3RyX3JlcGxhY2VfYWxsKGV3aW5nX2dlbmVfc2V0X25hbWVzW1siemhhbmciXV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJcXF8iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiICIpKQpgYGAKCkxldCdzIGNvbG9yIHRoZSBwb2ludHMgYnkgdGhlIEFVQyB2YWx1ZXMgZm9yIHRoZSBvdGhlciBnZW5lIHNldC4KCmBgYHtyIHBsb3RfdW1hcF9yaWdnaSwgbGl2ZSA9IFRSVUV9CnNjYXRlcjo6cGxvdFVNQVAoc2NlLCBjb2xvdXJfYnkgPSAicmlnZ2lfYXVjIikgKyAKICBnZ3Bsb3QyOjpnZ3RpdGxlKHN0cmluZ3I6OnN0cl9yZXBsYWNlX2FsbChld2luZ19nZW5lX3NldF9uYW1lc1tbInJpZ2dpIl1dLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXFxfIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiAiKSkKYGBgCgpXZSB3b3VsZCB3YW50IHRvIGRvIHNvbWV0aGluZyBtb3JlIGZvcm1hbCB0byBjb25maXJtLCBidXQgaXQgc2VlbXMgbGlrZSB0aGUgc2FtZSBjZWxscyBoYXZlIGhpZ2ggQVVDIHZhbHVlcyBmb3IgYm90aCBnZW5lIHNldHMhCgojIyBTZXNzaW9uIEluZm8KCmBgYHtyIHNlc3Npb25faW5mb30Kc2Vzc2lvbkluZm8oKQpgYGAK
+
LS0tCnRpdGxlOiAiUGF0aHdheSBBbmFseXNpczogQVVDZWxsIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCmF1dGhvcjogQ0NETCBmb3IgQUxTRgpkYXRlOiAyMDI0Ci0tLQoKKkFkYXB0ZWQgZnJvbSBbdGhlIEFVQ2VsbCB2aWduZXR0ZV0oaHR0cHM6Ly9iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL3JlbGVhc2UvYmlvYy92aWduZXR0ZXMvQVVDZWxsL2luc3QvZG9jL0FVQ2VsbC5odG1sKSBhbmQgW3RoZSBgY2VsbC10eXBlLWV3aW5nc2AgbW9kdWxlXShodHRwczovL2dpdGh1Yi5jb20vQWxleHNMZW1vbmFkZS9PcGVuU2NQQ0EtYW5hbHlzaXMvdHJlZS9tYWluL2FuYWx5c2VzL2NlbGwtdHlwZS1ld2luZ3MpIHRoYXQgaXMgcGFydCBvZiB0aGUgT3BlbiBTaW5nbGUtY2VsbCBQZWRpYXRyaWMgQ2FuY2VyIEF0bGFzIHByb2plY3QuKgoKIyMgT2JqZWN0aXZlcwoKLSBJbnRyb2R1Y2UgdGhlIGBBVUNlbGxgIFIgcGFja2FnZQotIElsbHVzdHJhdGUgaG93IEFVQyB2YWx1ZXMgYXJlIGNhbGN1bGF0ZWQKLSBEZW1vbnN0cmF0ZSBob3cgQVVDIHZhbHVlcyBjYW4gYmUgdXNlZCBmb3IgY2VsbCBhc3NpZ25tZW50IGFuZCBwbG90dGluZwoKLS0tCgpJbiB0aGlzIG5vdGVib29rLCB3ZSdsbCBkZW1vbnN0cmF0ZSBob3cgdG8gdXNlIHRoZSBBVUNlbGwgbWV0aG9kLCBpbnRyb2R1Y2VkIGluIFtBaWJhciBfZXQgYWxfLiAyMDE3Ll0oaHR0cHM6Ly9kb2kub3JnLzEwLjEwMzgvbm1ldGguNDQ2MykuCgpXZSBjYW4gdXNlIEFVQ2VsbCB3aGVuIHdlIGFyZSBpbnRlcmVzdGVkIGluIGEgZ2VuZSBzZXQncyByZWxhdGl2ZSBleHByZXNzaW9uIG9yIGFjdGl2aXR5IGluIGFuIGluZGl2aWR1YWwgY2VsbC4KR2VuZSBzZXRzIGNhbiBjb21lIGZyb20gYSBjdXJhdGVkIGNvbGxlY3Rpb24gb2YgcHJpb3Iga25vd2xlZGdlLCBsaWtlIHRoZSBIYWxsbWFyayBjb2xsZWN0aW9uIHdlIHVzZWQgaW4gdGhlIGxhc3Qgbm90ZWJvb2ssIG9yIHdlIGNhbiB1c2Ugb3VyIG93biBjdXN0b20gZ2VuZSBzZXRzIChlLmcuLCBhIHNldCBvZiBtYXJrZXIgZ2VuZXMgZm9yIGEgY2VsbCB0eXBlIG9mIGludGVyZXN0KS4KCkEgbmljZSBmZWF0dXJlIG9mIEFVQ2VsbCBpcyB0aGF0IGl0IGlzIGJhc2VkIG9uIHJhbmtpbmcgZ2VuZXMgZnJvbSBoaWdoZXN0IHRvIGxvd2VzdCBleHByZXNzaW9uIHZhbHVlIGluIGFuIGluZGl2aWR1YWwgY2VsbCwgd2hpY2ggaXMgaGVscGZ1bCBpbiB0aGUgZm9sbG93aW5nIHdheXMgKFtBVUNlbGwgdmlnbmV0dGVdKGh0dHBzOi8vYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9yZWxlYXNlL2Jpb2MvdmlnbmV0dGVzL0FVQ2VsbC9pbnN0L2RvYy9BVUNlbGwuaHRtbCkpOgoKLSBJdCBjYW4gdGFrZSBhIG51bWJlciBvZiBkaWZmZXJlbnQgdmFsdWVzIGFzIGlucHV0IChlLmcuLCByYXcgY291bnRzLCBUUE0pIAotIEl0IGNvbXBlbnNhdGVzIGZvciBkaWZmZXJlbmNlcyBpbiBsaWJyYXJ5IHNpemUsIHdoZXJlIHNvbWV0aGluZyBsaWtlIGF2ZXJhZ2luZyByYXcgY291bnQgdmFsdWVzIG9mIGdlbmVzIGluIGEgZ2VuZSBzZXQgd291bGQgbm90IAotIEl0IHNjYWxlcyB0byBsYXJnZXIgZGF0YXNldHMsIHNpbmNlIGNyZWF0aW5nIHJhbmtpbmdzIGlzIG5vdCBhcyByZXNvdXJjZS1pbnRlbnNpdmUgYXMgc29tZXRoaW5nIGxpa2UgcGVybXV0YXRpb24gdGVzdGluZywgYW5kIHdlIGNvdWxkIHNwbGl0IHVwIHRoZSBvYmplY3QgaW50byBzdWJzZXRzIG9mIGNlbGxzIGlmIG5lZWRlZAoKQVVDZWxsIGNhbGN1bGF0ZXMgdGhlIGFyZWEgdW5kZXIgdGhlIHJlY292ZXJ5IGN1cnZlIChBVUMpLCB3aGljaCAicmVwcmVzZW50cyB0aGUgcHJvcG9ydGlvbiBvZiBleHByZXNzZWQgZ2VuZXMgaW4gdGhlIHNpZ25hdHVyZSBhbmQgdGhlaXIgcmVsYXRpdmUgZXhwcmVzc2lvbiB2YWx1ZSBjb21wYXJlZCB0byB0aGUgb3RoZXIgZ2VuZXMgd2l0aGluIHRoZSBjZWxsIiAoW0FpYmFyIF9ldCBhbF8uIDIwMTcuXShodHRwczovL2RvaS5vcmcvMTAuMTAzOC9ubWV0aC40NDYzKSkuCldlIHdpbGwgdmlzdWFsaXplIHNvbWUgcmVjb3ZlcnkgY3VydmVzIGluIHRoZSBub3RlYm9vayB0byBnaXZlIHlvdSBhIGJldHRlciBpbnR1aXRpb24gYWJvdXQgdGhlIEFVQyBhbmQgaXRzIG1lYW5pbmcuCgpUaGUgQVVDIHZhbHVlcyB3ZSBnZXQgb3V0IG9mIEFVQ2VsbCBjYW4gYmUgdXNlZCBpbiBhIG51bWJlciBvZiB3YXlzIChbQWliYXIgX2V0IGFsXy4gMjAxNy5dKGh0dHBzOi8vZG9pLm9yZy8xMC4xMDM4L25tZXRoLjQ0NjMpKToKCi0gQXMgY29udGludW91cyB2YWx1ZXMgd2UgY2FuIHVzZSBmb3IgdmlzdWFsaXphdGlvbiBvciBjbHVzdGVyaW5nCi0gRm9yIGJpbmFyeSBhc3NpZ25tZW50IChpLmUuLCAib24iIGFuZCAib2ZmIiBvciAiZXhwcmVzc2VkIiBhbmQgIm5vdCBleHByZXNzZWQiKSBpZiB3ZSBwaWNrIGEgdGhyZXNob2xkIGVpdGhlciBhdXRvbWF0aWNhbGx5IHVzaW5nIGJ1aWx0LWluIGZ1bmN0aW9uYWxpdHkgb3IgbWFudWFsbHkgYnkgaW5zcGVjdGluZyB0aGUgZGlzdHJpYnV0aW9uIG9mIHNjb3JlcyBvdXJzZWx2ZXMKCldlIHdpbGwgdXNlIGFuIHNuUk5BLXNlcSBvZiBhIEV3aW5nIHNhcmNvbWEgc2FtcGxlIGZyb20gdGhlIFtgU0NQQ1AwMDAwMTVgIHByb2plY3RdKGh0dHBzOi8vc2NwY2EuYWxleHNsZW1vbmFkZS5vcmcvcHJvamVjdHMvU0NQQ1AwMDAwMTUpIG9uIHRoZSBTaW5nbGUtY2VsbCBQZWRpYXRyaWMgQ2FuY2VyIEF0bGFzIFBvcnRhbCBhbmQgdHdvIHJlbGV2YW50IGdlbmUgc2V0cyBmcm9tIHRoZSBNb2xlY3VsYXIgU2lnbmF0dXJlcyBEYXRhYmFzZSAoTVNpZ0RCKSB0byBkZW1vbnN0cmF0ZSB0aGlzIG1ldGhvZC4KCiMjIFNldCB1cAoKIyMjIExpYnJhcmllcwoKYGBge3IgbGlicmFyaWVzfQojIFdlIHdpbGwgYmUgbG9hZGluZyBhIFNpbmdsZUNlbGxFeHBlcmltZW50IG9iamVjdCBpbnRvIG91ciBlbnZpcm9ubWVudCBidXQgZG9uJ3QgbmVlZCB0byBzZWUgdGhlIHN0YXJ0dXAgbWVzc2FnZXMKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKICBsaWJyYXJ5KFNpbmdsZUNlbGxFeHBlcmltZW50KQp9KQoKIyBMaWJyYXJ5IHdlJ2xsIHVzZSBmb3IgdGhlIGdlbmUgc2V0IGFuYWx5c2lzIGl0c2VsZgpsaWJyYXJ5KEFVQ2VsbCkKCiMgTGlicmFyaWVzIGZvciBhY2Nlc3NpbmcgYW5kIHdvcmtpbmcgd2l0aCBnZW5lIHNldHMKbGlicmFyeShHU0VBQmFzZSkKbGlicmFyeShtc2lnZGJyKQpgYGAKCiMjIyBEaXJlY3RvcmllcyBhbmQgZmlsZXMKCiMjIyMgRGlyZWN0b3JpZXMKCmBgYHtyIHNldHVwX2RpcmVjdG9yaWVzfQojIElucHV0IGRhdGEgCmV3aW5nX2RhdGFfZGlyIDwtIGZzOjpwYXRoKCJkYXRhIiwgImV3aW5nLXNhcmNvbWEiKQpwcm9jZXNzZWRfZGlyIDwtIGZzOjpwYXRoKGV3aW5nX2RhdGFfZGlyLCAicHJvY2Vzc2VkIikKCiMgRGlyZWN0b3J5IGZvciBob2xkaW5nIHBhdGh3YXkgYW5hbHlzaXMgcmVzdWx0cwphbmFseXNpc19kaXIgPC0gZnM6OnBhdGgoImFuYWx5c2lzIiwgImV3aW5nLXNhcmNvbWEiLCAicGF0aHdheS1hbmFseXNpcyIpCiMgQ3JlYXRlIGlmIGl0IGRvZXNuJ3QgZXhpc3QgeWV0CmZzOjpkaXJfY3JlYXRlKGFuYWx5c2lzX2RpcikKYGBgCgojIyMjIEZpbGVzCgpUaGUgaW5wdXQgd2lsbCBiZSBhIGBTaW5nbGVDZWxsRXhwZXJpbWVudGAgZm9yIGFuIGluZGl2aWR1YWwgRXdpbmcgc2FyY29tYSBsaWJyYXJ5LgoKYGBge3Igc2V0dXBfaW5wdXRfZmlsZXN9CnNjZV9maWxlIDwtIGZzOjpwYXRoKHByb2Nlc3NlZF9kaXIsIAogICAgICAgICAgICAgICAgICAgICAiU0NQQ1MwMDA0OTAiLCAKICAgICAgICAgICAgICAgICAgICAgIlNDUENMMDAwODIyX3Byb2Nlc3NlZC5yZHMiKQpgYGAKCldlIHdpbGwgc2F2ZSB0aGUgQVVDZWxsIHJlc3VsdHMgYXMgYSB0YWJsZSBpbiB0aGUgYW5hbHlzaXMgZGlyZWN0b3J5LgoKYGBge3Igc2V0dXBfb3V0cHV0X2ZpbGVzLCBsaXZlID0gVFJVRX0Kb3V0cHV0X2ZpbGUgPC0gZnM6OnBhdGgoYW5hbHlzaXNfZGlyLAogICAgICAgICAgICAgICAgICAgICAgICAiZXdpbmdfc2FyY29tYV9hdWNlbGxfcmVzdWx0cy50c3YiKQpgYGAKCgojIyMgRnVuY3Rpb25zCgpUaGUgYHNvdXJjZSgpYCBmdW5jdGlvbiBhbGxvd3MgdXMgdG8gbG9hZCBpbiBjdXN0b20gZnVuY3Rpb25zIHdlIHNhdmVkIGluIGFuIGAuUmAgZmlsZS4KCmBgYHtyIHNvdXJjZV9mdW5jdGlvbnN9CnNvdXJjZShmczo6cGF0aCgidXRpbCIsICJhdWNlbGxfZnVuY3Rpb25zLlIiKSkKYGBgCgpUaGlzIGxvYWRzIG9uZSBjdXN0b20gZnVuY3Rpb24sIGNhbGxlZCBgcGxvdF9yZWNvdmVyeV9jdXJ2ZSgpYCwgaW50byBvdXIgZW52aXJvbm1lbnQuClRoaXMgZnVuY3Rpb24gaXMgYWRhcHRlZCBmcm9tIFt0aGUgQVVDZWxsIHZpZ25ldHRlXShodHRwczovL2dpdGh1Yi5jb20vYWVydHNsYWIvQVVDZWxsL2Jsb2IvOTE3NTNiMzI3YTM5ZGM3YTRiYmVkNDY0MDhlYzIyNzFjNDg1ZjJmMC92aWduZXR0ZXMvQVVDZWxsLlJtZCNMMjk1LUwzMTYpLgoKIyMgU2V0IHVwIGdlbmUgc2V0cwoKV2UgYXJlIGdvaW5nIHRvIHVzZSB0d28gZ2VuZSBzZXRzIHBlcnRhaW5pbmcgdG8gRXdpbmcgc2FyY29tYS4KCiogW2BaSEFOR19UQVJHRVRTX09GX0VXU1IxX0ZMSTFfRlVTSU9OYF0oaHR0cHM6Ly93d3cuZ3NlYS1tc2lnZGIub3JnL2dzZWEvbXNpZ2RiL2dlbmVzZXRfcGFnZS5qc3A/Z2VuZVNldE5hbWU9WkhBTkdfVEFSR0VUU19PRl9FV1NSMV9GTEkxX0ZVU0lPTiksIHdoaWNoIGFyZSBnZW5lcyB0aGF0IHdlcmUgaGlnaGx5IGV4cHJlc3NlZCBpbiBhIHJoYWJkb215b3NhcmNvbWEgY2VsbCBsaW5lIGVuZ2luZWVyZWQgdG8gZXhwcmVzcyB0aGUgRVdTUjEtRkxJMSBmdXNpb24uCiogW2BSSUdHSV9FV0lOR19TQVJDT01BX1BST0dFTklUT1JfVVBgXShodHRwczovL3d3dy5nc2VhLW1zaWdkYi5vcmcvZ3NlYS9tc2lnZGIvY2FyZHMvUklHR0lfRVdJTkdfU0FSQ09NQV9QUk9HRU5JVE9SX1VQKSwgd2hpY2ggYXJlIGdlbmVzIHRoYXQgd2VyZSBoaWdobHkgZXhwcmVzc2VkIGluIG1lc2VuY2h5bWFsIHN0ZW0gY2VsbHMgZW5naW5lZXJlZCB0byBleHByZXNzIHRoZSBFV1MtRkxJMSBmdXNpb24gcHJvdGVpbi4KCldlIHdvdWxkIGV4cGVjdCBib3RoIG9mIHRoZXNlIGdlbmUgc2V0cyB0byBoYXZlIGhpZ2ggZXhwcmVzc2lvbiBpbiB0dW1vciBjZWxscy4KCmBgYHtyIGdlbmVzZXRzfQojIENyZWF0ZSBhIG5hbWVkIHZlY3RvciB3aXRoIHRoZSByZWxldmFudCBnZW5lIHNldCBuYW1lcwpld2luZ19nZW5lX3NldF9uYW1lcyA8LSBjKHpoYW5nID0gIlpIQU5HX1RBUkdFVFNfT0ZfRVdTUjFfRkxJMV9GVVNJT04iLAogICAgICAgICAgICAgICAgICAgICAgICAgIHJpZ2dpID0gIlJJR0dJX0VXSU5HX1NBUkNPTUFfUFJPR0VOSVRPUl9VUCIpCgpld2luZ19nZW5lX3NldF9uYW1lcwpgYGAKClRoZXNlIGdlbmUgc2V0cyBjb21lIGZyb20gdGhlIEMyIGdlbmUgc2V0IGNvbGxlY3Rpb24gZnJvbSBNU2lnREIuCkxldCdzIHJldHJpZXZlIHRoZW0gdXNpbmcgYG1zaWdkYnIoKWAuCgpgYGB7ciBleHRyYWN0X2dlbmVzZXRzLCBsaXZlID0gVFJVRX0KZXdpbmdfZ2VuZV9zZXRzX2RmIDwtIG1zaWdkYnIoc3BlY2llcyA9ICJIb21vIHNhcGllbnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXRlZ29yeSA9ICJDMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YmNhdGVnb3J5ID0gIkNHUCIpIHw+CiAgZHBseXI6OmZpbHRlcihnc19uYW1lICVpbiUgZXdpbmdfZ2VuZV9zZXRfbmFtZXMpCmBgYAoKYEFVQ2VsbGAgdXNlcyBnZW5lIHNldHMgaW4gYSBwYXJ0aWN1bGFyIGZvcm1hdCB0aGF0IGNvbWVzIGZyb20gdGhlIGBHU0VBQmFzZWAgcGFja2FnZS4KV2UgbmVlZCB0byBjcmVhdGUgYSBgR2VuZVNldENvbGxlY3Rpb25gLgoKYGBge3IgZ2VuZV9zZXRfY29sbGVjdGlvbn0KZXdpbmdfZ2VuZV9zZXRfY29sbGVjdGlvbiA8LSBld2luZ19nZW5lX3NldF9uYW1lcyB8PgogIHB1cnJyOjptYXAoCiAgICAjIEZvciBlYWNoIGdlbmUgc2V0CiAgICBcKGdlbmVfc2V0X25hbWUpIHsKICAgICAgZXdpbmdfZ2VuZV9zZXRzX2RmIHw+CiAgICAgICAgIyBTdWJzZXQgdG8gdGhlIHJvd3MgaW4gdGhhdCBnZW5lIHNldAogICAgICAgIGRwbHlyOjpmaWx0ZXIoZ3NfbmFtZSA9PSBnZW5lX3NldF9uYW1lKSB8PgogICAgICAgICMgR3JhYiB0aGUgRW5zZW1ibCBnZW5lIGlkZW50aWZpZXJzCiAgICAgICAgZHBseXI6OnB1bGwoZW5zZW1ibF9nZW5lKSB8PgogICAgICAgICMgQ3JlYXRlIGEgR2VuZVNldCBvYmplY3QKICAgICAgICBHZW5lU2V0KHNldE5hbWUgPSBnZW5lX3NldF9uYW1lLAogICAgICAgICAgICAgICAgZ2VuZUlkVHlwZSA9IEVOU0VNQkxJZGVudGlmaWVyKCkpCiAgICB9CiAgKSB8PgogICMgVHVybiB0aGUgbGlzdCBvZiBHZW5lU2V0IG9iamVjdHMgaW50byBhIEdlbmVTZXQgY29sbGVjdGlvbgogIEdlbmVTZXRDb2xsZWN0aW9uKCkKYGBgCgojIyBSZWFkIGluIGFuZCBwcmVwYXJlIFNpbmdsZUNlbGxFeHBlcmltZW50CgpgYGB7ciByZWFkX2luX3NjZSwgbGl2ZSA9IFRSVUV9CnNjZSA8LSByZWFkcjo6cmVhZF9yZHMoc2NlX2ZpbGUpCmBgYAoKVGhlIGBBVUNlbGxgIGZ1bmN0aW9ucyB0YWtlcyBhbiBleHByZXNzaW9uIG1hdHJpeCB3aXRoIGdlbmVzIGFzIHJvd3MgYW5kIGNlbGxzIGFzIGNvbHVtbi4KV2UgY2FuIGV4dHJhY3QgYSBjb3VudHMgbWF0cml4IGluIHNwYXJzZSBmb3JtYXQgZm9yIHVzZSB3aXRoIGBBVUNlbGxgLgoKYGBge3IgY291bnRzX21hdHJpeH0KIyBFeHRyYWN0IGNvdW50cyBtYXRyaXgKY291bnRzX21hdHJpeCA8LSBjb3VudHMoc2NlKQpgYGAKClRoZXJlIG1heSBiZSBnZW5lcyBpbiBvdXIgZ2VuZSBzZXQgdGhhdCBkbyBub3QgYXBwZWFyIGluIHRoZSBTaW5nbGVDZWxsRXhwZXJpbWVudCBvYmplY3QuCldlIGNhbiByZW1vdmUgdGhlbSB1c2luZyB0aGUgYHN1YnNldEdlbmVTZXRzKClgIGZ1bmN0aW9uLgoKYGBge3Igc3Vic2V0X2dlbmVfc2V0cywgbGl2ZSA9IFRSVUV9CiMgUmVtb3ZlIGdlbmVzIGZyb20gZ2VuZSBzZXRzIGlmIHRoZXkgYXJlIG5vdCBpbiB0aGUgU0NFCmV3aW5nX2dlbmVfc2V0X2NvbGxlY3Rpb24gPC0gc3Vic2V0R2VuZVNldHMoZXdpbmdfZ2VuZV9zZXRfY29sbGVjdGlvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lcyhjb3VudHNfbWF0cml4KSkKYGBgCgojIyBBVUNlbGwKCkFVQ2VsbCByZWxpZXMgb24gcmFua2luZyBnZW5lcyBmcm9tIGhpZ2hlc3QgdG8gbG93ZXN0IGV4cHJlc3Npb24gdmFsdWUgdG8gY2FsY3VsYXRlIHRoZSBBVUMuClRoZSBBVUMgaXMgdGhlIGFyZWEgdW5kZXIgdGhlIHJlY292ZXJ5IGN1cnZlLCB3aGljaCBjYXB0dXJlcyB0aGUgbnVtYmVyIG9mIGdlbmVzIGluIGEgZ2VuZSBzZXQgdGhhdCBhcmUgcHJlc2VudCBpbiB0aGUgcmFua2luZ3MgYWJvdmUgc29tZSB0aHJlc2hvbGQgKGkuZS4sIGl0IGlzIHRoZSBhcmVhIHVuZGVyIHRoZSBjdXJ2ZSB0byB0aGUgbGVmdCBvZiB0aGlzIGdlbmUgcmFuaykuCkJ5IGRlZmF1bHQsIHRoZSB0b3AgNSUgb2YgZ2VuZXMgYXJlIHVzZWQgYXMgdGhlIHRocmVzaG9sZC4KClNvbWUgZ2VuZXMgd2lsbCBub3QgYmUgZGV0ZWN0ZWQgKGkuZS4sIGhhdmUgMCBjb3VudHMpLgpHZW5lcyBjYW4gYWxzbyBoYXZlIHRoZSBzYW1lIGV4cHJlc3Npb24gbGV2ZWwgKGkuZS4sIHRpZXMpLgpUaGVzZSB1bmRldGVjdGVkIGdlbmVzIGFuZCB0aWVzIHdpbGwgYmUgcmFuZG9tbHkgb3JkZXJlZCBpbiBvdXIgcmFua2luZy4KVG8gbWFrZSBvdXIgcmFua2luZ3Mg4oCTIGFuZCB0aGVyZWZvcmUgcmVzdWx0cyDigJMgcmVwcm9kdWNpYmxlLCB3ZSB3aWxsIHNldCBhIHNlZWQuCgpgYGB7ciBzZXRfc2VlZCwgbGl2ZSA9IFRSVUV9CnNldC5zZWVkKDIwMjQpCmBgYAoKIyMjIENlbGwgcmFua2luZwoKVGhlIGZpcnN0IHN0ZXAgaW4gQVVDZWxsIGlzIHRvIHJhbmsgZ2VuZXMgZm9yIGVhY2ggY2VsbCBmcm9tIGhpZ2hlc3QgdG8gbG93ZXN0IGV4cHJlc3Npb24gdmFsdWUuCldlIGNhbiBkbyB0aGlzIHVzaW5nIHRoZSBgQVVDZWxsX2J1aWxkUmFua2luZ3MoKWAgZnVuY3Rpb24sIHdoaWNoIHdpbGwgb3V0cHV0IGEgdmlzdWFsaXphdGlvbiBzaG93aW5nIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIG51bWJlciBvZiBnZW5lcyBkZXRlY3RlZCBpbiB0aGUgY2VsbHMgaW4gb3VyIFNpbmdsZUNlbGxFeHBlcmltZW50IG9iamVjdC4KCmBgYHtyIGNlbGxfcmFua2luZ3MsIGxpdmUgPSBUUlVFfQpjZWxsX3JhbmtpbmdzIDwtIEFVQ2VsbF9idWlsZFJhbmtpbmdzKGNvdW50c19tYXRyaXgpCmBgYAoKVGhlIEFVQ2VsbCBhdXRob3JzIHJlY29tbWVuZCBtYWtpbmcgc3VyZSBtb3N0IGNlbGxzIGhhdmUgYXQgbGVhc3QgdGhlIG51bWJlciBvZiBnZW5lcyB3ZSB3aWxsIHVzZSBhcyB0aGUgbWF4IHJhbmsgdG8gY2FsY3VsYXRlIHRoZSBBVUMuCgpUaGUgQVVDIG1heCByYW5rIHZhbHVlIHRlbGxzIEFVQ2VsbCB0aGUgY3V0b2ZmIGluIHRoZSBnZW5lIHJhbmtpbmdzIHRvIHVzZSBmb3IgY2FsY3VsYXRpbmcgQVVDOyB3ZSB3aWxsIHZpc3VhbGl6ZSB0aGlzIGN1cnZlIGFuZCBtYXggcmFuayBpbiBqdXN0IGEgbW9tZW50LgpJZiB3ZSBwaWNrZWQgYSBtYXggcmFuayBoaWdoZXIgdGhhbiB0aGUgbnVtYmVyIG9mIGdlbmVzIGRldGVjdGVkIGluIG1vc3QgY2VsbHMsIHRoZSBub24tZGV0ZWN0ZWQgZ2VuZXMgdGhhdCBhcmUgcmFuZG9tbHkgb3JkZXJlZCB3b3VsZCBwbGF5IGFuIG91dHNpemVkIHJvbGUgaW4gb3VyIEFVQyB2YWx1ZXMuCgpCeSBkZWZhdWx0LCB0aGUgbWF4IHJhbmsgaXMgdGhlIHRvcCA1JSBoaWdoZXN0IGV4cHJlc3NlZCBnZW5lcy4KV2UgY2FuIGNhbGN1bGF0ZSB0aGUgZGVmYXVsdCBtYXggcmFuayBieSB0YWtpbmcgaW50byBhY2NvdW50IHRoZSBudW1iZXIgb2YgZ2VuZXMuCgpgYGB7ciBleHBsb3JlX2F1Y19tYXhfcmFua30KbnJvdyhjZWxsX3JhbmtpbmdzKSAqIDAuMDUKYGBgCgpUaGlzIG51bWJlciBpcyBwcm9iYWJseSB0b28gaGlnaCwgZ2l2ZW4gdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgbnVtYmVyIG9mIGdlbmVzIGRldGVjdGVkIGJ5IGNlbGwgd2UgdmlzdWFsaXplZCB3aXRoIGBBVUNlbGxfYnVpbGRSYW5raW5ncygpYC4KCldoYXQgaWYgd2UgY2hvc2UgYSAxJSB0aHJlc2hvbGQ/CgpgYGB7ciBsb3dlcl9tYXhfcmFuaywgbGl2ZSA9IFRSVUV9Cm5yb3coY2VsbF9yYW5raW5ncykgKiAwLjAxCmBgYAoKVGhhdCBpcyBwcm9iYWJseSBhIG1vcmUgcmVhc29uYWJsZSBjaG9pY2UgZm9yIHRoaXMgZGF0YXNldC4KCldlIGNhbiB1c2UgYSBmdW5jdGlvbiBjYWxsZWQgYGNlaWxpbmcoKWAgdG8gcm91bmQgdGhpcyBhbmQgc2F2ZSBpdCB0byBhIHZhcmlhYmxlIGZvciBsYXRlciB1c2UuCgpgYGB7ciBhdWNfbWF4X3JhbmssIGxpdmUgPSBUUlVFfQphdWNfbWF4X3JhbmsgPC0gY2VpbGluZyhucm93KGNlbGxfcmFua2luZ3MpICogMC4wMSkKYGBgCgojIyMgUGxvdHRpbmcgQVVDCgpUaGUgQVVDIHZhbHVlcyB3ZSBnZXQgb3V0IG9mIEFVQ2VsbCBhcmUgdGhlIGFyZWEgdW5kZXIgYSByZWNvdmVyeSBjdXJ2ZSBhbmQgZXN0aW1hdGUgdGhlIHByb3BvcnRpb24gb2YgZ2VuZXMgaW4gdGhlIGdlbmUgc2V0IHRoYXQgYXJlIGhpZ2hseSBleHByZXNzZWQgKGkuZS4sIGhpZ2hseSByYW5rZWQpLgoKTGV0J3MgcGxvdCB0aGUgcmVjb3ZlcnkgY3VydmUgZm9yIGEgY2VsbCB3aXRoIGhpZ2ggQVVDIGFuZCBhIGNlbGwgd2l0aCBsb3cgQVVDIHRvIGdldCBhIGJldHRlciBpbnR1aXRpb24gYWJvdXQgQVVDIHZhbHVlcy4KRWFybGllciwgd2UgbG9hZGVkIGEgY3VzdG9tIGZ1bmN0aW9uIHdlIGFkYXB0ZWQgZnJvbSBbdGhlIEFVQ2VsbCB2aWduZXR0ZV0oaHR0cHM6Ly9naXRodWIuY29tL2FlcnRzbGFiL0FVQ2VsbC9ibG9iLzkxNzUzYjMyN2EzOWRjN2E0YmJlZDQ2NDA4ZWMyMjcxYzQ4NWYyZjAvdmlnbmV0dGVzL0FVQ2VsbC5SbWQpIGNhbGxlZCBgcGxvdF9yZWNvdmVyeV9jdXJ2ZSgpYCB3aXRoIGBzb3VyY2UoKWAuCgpGaXJzdCwgd2UnbGwgc3RhcnQgd2l0aCBhIGNlbGwgd2l0aCBhIGhpZ2ggQVVDLgpXZSBwaWNrZWQgdGhpcyBiYXJjb2RlIGFoZWFkIG9mIHRpbWUgd2hlbiB3ZSB3cm90ZSB0aGUgbm90ZWJvb2suCgpgYGB7ciBoaWdoX3JlY292ZXJ5X2N1cnZlfQpwbG90X3JlY292ZXJ5X2N1cnZlKGNlbGxfcmFua2luZ3MsCiAgICAgICAgICAgICAgICAgICAgZXdpbmdfZ2VuZV9zZXRfY29sbGVjdGlvbiwKICAgICAgICAgICAgICAgICAgICBnZW5lX3NldF9uYW1lID0gIlpIQU5HX1RBUkdFVFNfT0ZfRVdTUjFfRkxJMV9GVVNJT04iLAogICAgICAgICAgICAgICAgICAgIGJhcmNvZGUgPSAiQ1RHQUdDR0dUQ1RUVEFUQyIsCiAgICAgICAgICAgICAgICAgICAgYXVjX21heF9yYW5rID0gYXVjX21heF9yYW5rKSAgIyAxJSB0aHJlc2hvbGQgCmBgYAoKVGhlIHgtYXhpcyBpcyB0aGUgZ2VuZSByYW5rcyBmb3IgYWxsIGdlbmVzLgpUaGUgeS1heGlzIGlzIHRoZSBudW1iZXIgb2YgZ2VuZXMgaW4gdGhlIHNpZ25hdHVyZSBhdCBhIGdpdmVuIHBvaW50IGluIHRoZSBnZW5lIHJhbmtpbmcg4oCTIHRoZSBsaW5lIHdpbGwgcmlzZSB3aGVuIGEgZ2VuZSBpbiB0aGUgZ2VuZSBzZXQgaXMgZW5jb3VudGVyZWQgaW4gdGhlIHJhbmtpbmcgZnJvbSBoaWdoZXN0IHRvIGxvd2VzdC4KVGhlIEFVQyBpcyB0aGUgYXJlYSB1bmRlciB0aGlzIHJlY292ZXJ5IGN1cnZlIGF0IHRoZSBtYXggcmFuayB0aHJlc2hvbGQgY2hvc2VuIGZvciB0aGlzIGRhdGFzZXQuCgpOb3csIGxldCdzIGxvb2sgYXQgYW4gZXhhbXBsZSB3aXRoIGEgbG93IEFVQy4KCmBgYHtyIGxvd19yZWNvdmVyeV9jdXJ2ZX0KcGxvdF9yZWNvdmVyeV9jdXJ2ZShjZWxsX3JhbmtpbmdzLAogICAgICAgICAgICAgICAgICAgIGV3aW5nX2dlbmVfc2V0X2NvbGxlY3Rpb24sCiAgICAgICAgICAgICAgICAgICAgZ2VuZV9zZXRfbmFtZSA9ICJaSEFOR19UQVJHRVRTX09GX0VXU1IxX0ZMSTFfRlVTSU9OIiwKICAgICAgICAgICAgICAgICAgICBiYXJjb2RlID0gIkFHQVRBR0FHVENBQ0FBVEMiLAogICAgICAgICAgICAgICAgICAgIGF1Y19tYXhfcmFuayA9IGF1Y19tYXhfcmFuaykgICMgMSUgdGhyZXNob2xkCmBgYAoKRmFyIGZld2VyIGdlbmVzIGluIHRoZSBnZW5lIHNldCBhcmUgcmFua2VkIGFib3ZlIHRoZSB0aHJlc2hvbGQsIHlpZWxkaW5nIGEgbG93ZXIgQVVDIHZhbHVlLgoKIyMjIENhbGN1bGF0aW5nIHRoZSBBVUMKCk9uY2Ugd2UgaGF2ZSB0aGUgcmFua2luZ3MsIHdlIGNhbiBjYWxjdWxhdGUgdGhlIEFVQyBzY29yZXMgZm9yIGJvdGggZ2VuZSBzZXRzIGluIGFsbCBjZWxscyB3aXRoIHRoZSBgQVVDZWxsX2NhbGNBVUMoKWAgZnVuY3Rpb24uCgpgYGB7ciBjYWxjX2F1YywgbGl2ZSA9IFRSVUV9CmNlbGxfYXVjIDwtIEFVQ2VsbF9jYWxjQVVDKGdlbmVTZXRzID0gZXdpbmdfZ2VuZV9zZXRfY29sbGVjdGlvbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmtpbmdzID0gY2VsbF9yYW5raW5ncywKICAgICAgICAgICAgICAgICAgICAgICAgICAgYXVjTWF4UmFuayA9IGF1Y19tYXhfcmFuaykKYGBgCgpUaGlzIGZ1bmN0aW9uIHJldHVybnMgYW4gYGF1Y2VsbFJlc3VsdHNgIG9iamVjdC4KCmBgYHtyIGNoZWNrX3N0ciwgbGl2ZSA9IFRSVUV9CnN0cihjZWxsX2F1YykKYGBgCgpJdCBjYW4gYmUgbXVjaCBtb3JlIGNvbnZlbmllbnQgdG8gd29yayB3aXRoIHRoaXMgaW4gYSB0YWJ1bGFyIGZvcm1hdC4KCmBgYHtyIGF1Y190b190YWJsZX0KIyBFeHRyYWN0IEFVQwphdWNfZGYgPC0gY2VsbF9hdWNAYXNzYXlzQGRhdGEkQVVDIHw+CiAgIyBUcmFuc3Bvc2UKICB0KCkgfD4KICAjIENvbnZlcnQgdG8gZGF0YSBmcmFtZQogIGFzLmRhdGEuZnJhbWUoKSB8PgogICMgTWFrZSB0aGUgYmFyY29kZXMgYSBjb2x1bW4KICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigiYmFyY29kZXMiKSAKCiMgTG9vayBhdCBmaXJzdCBmZXcgcm93cwpoZWFkKGF1Y19kZikKYGBgCgojIyMgQXNzaWdubWVudHMKCkFVQ2VsbCBjYW4gYXNzaWduIGNlbGxzIGFzIGhhdmluZyBhbiBhY3RpdmUgZ2VuZSBzZXQgb3Igbm90IGJ5IHBpY2tpbmcgYSB0aHJlc2hvbGQgYXV0b21hdGljYWxseS4KV2UnbGwgZXhwbG9yZSB0aGVzZSBpbiBhIGxhdGVyIHBsb3QsIGJ1dCBmb3Igbm93LCBsZXQncyBjYWxjdWxhdGUgdGhlIHRocmVzaG9sZCBhbmQgYXNzaWduIGNlbGxzIHdpdGggYEFVQ2VsbF9leHBsb3JlVGhyZXNob2xkcygpYC4KCmBgYHtyIGF1Y19hc3NpZ25tZW50cywgbGl2ZSA9IFRSVUV9CmF1Y19hc3NpZ25tZW50cyA8LSBBVUNlbGxfZXhwbG9yZVRocmVzaG9sZHMoY2VsbF9hdWMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RIaXN0ID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2lnbkNlbGxzID0gVFJVRSkKYGBgCgpXZSdyZSBnb2luZyB0byBwbG90IHRoZSBkaXN0cmlidXRpb24gb2YgQVVDIHZhbHVlcyB3aXRoIGBnZ3Bsb3QyYCwgc28gd2Ugd2lsbCB3YW50IHRoZSBBVUMgdmFsdWVzIGluIGEgbG9uZ2VyIGZvcm1hdC4KCmBgYHtyIGF1Y19wbG90dGluZ19kZn0KYXVjX3Bsb3R0aW5nX2RmIDwtIGF1Y19kZiB8PgogIHRpZHlyOjpwaXZvdF9sb25nZXIoIWJhcmNvZGVzLAogICAgICAgICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiZ2VuZV9zZXQiLAogICAgICAgICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gImF1YyIpIHw+CiAgZHBseXI6Om11dGF0ZSgKICAgICMgQ3JlYXRlIGEgbmV3IGxvZ2ljYWwgY29sdW1uIGNhbGxlZCBhc3NpZ25lZAogICAgYXNzaWduZWQgPSBkcGx5cjo6Y2FzZV93aGVuKAogICAgICAjIEZvciBaaGFuZyBnZW5lIHNldCByb3dzLCBzZXQgdG8gVFJVRSB3aGVuIHRoZSBiYXJjb2RlIGlzIGluIHRoZSAKICAgICAgIyBhc3NpZ25tZW50IGxpc3QKICAgICAgZ2VuZV9zZXQgPT0gZXdpbmdfZ2VuZV9zZXRfbmFtZXNbWyJ6aGFuZyJdXSAmIAogICAgICAgIGJhcmNvZGVzICVpbiUgYXVjX2Fzc2lnbm1lbnRzW1tld2luZ19nZW5lX3NldF9uYW1lc1tbInpoYW5nIl1dXV0kYXNzaWdubWVudCB+IFRSVUUsCiAgICAgICMgRm9yIFJpZ2dpIGdlbmUgc2V0IHJvd3MsIHNldCB0byBUUlVFIHdoZW4gdGhlIGJhcmNvZGUgaXMgaW4gdGhlIAogICAgICAjIGFzc2lnbm1lbnQgbGlzdAogICAgICBnZW5lX3NldCA9PSBld2luZ19nZW5lX3NldF9uYW1lc1tbInJpZ2dpIl1dICYgCiAgICAgICAgYmFyY29kZXMgJWluJSBhdWNfYXNzaWdubWVudHNbW2V3aW5nX2dlbmVfc2V0X25hbWVzW1sicmlnZ2kiXV1dXSRhc3NpZ25tZW50IH4gVFJVRSwKICAgICAgIyBPdGhlcndpc2UsIHNldCB0byBGQUxTRQogICAgICAuZGVmYXVsdCA9IEZBTFNFCiAgICApCiAgKQoKYXVjX3Bsb3R0aW5nX2RmCmBgYAoKVG8gZHJhdyB2ZXJ0aWNhbCBsaW5lcyByZXByZXNlbnRpbmcgdGhlIGF1dG9tYXRpY2FsbHkgY2hvc2VuIHRocmVzaG9sZCwgd2UgY2FuIGNyZWF0ZSBhIHNlcGFyYXRlIGRhdGEgZnJhbWUuCgpgYGB7ciBhdWNfdGhyZXNob2xkX2RmfQphdWNfdGhyZXNob2xkX2RmIDwtIGRhdGEuZnJhbWUoCiAgZ2VuZV9zZXQgPSBld2luZ19nZW5lX3NldF9uYW1lcywKICAjIEdyYWIgdGhyZXNob2xkcyBhc3NvY2lhdGVkIHdpdGggZWFjaCBnZW5lIHNldCBmcm9tIGFzc2lnbmVtZW50cyBvYmplY3QKICB0aHJlc2hvbGQgPSBjKGF1Y19hc3NpZ25tZW50c1tbZXdpbmdfZ2VuZV9zZXRfbmFtZXNbInpoYW5nIl1dXSRhdWNUaHIkc2VsZWN0ZWQsIAogICAgICAgICAgICAgICAgYXVjX2Fzc2lnbm1lbnRzW1tld2luZ19nZW5lX3NldF9uYW1lc1sicmlnZ2kiXV1dJGF1Y1RociRzZWxlY3RlZCkKKQoKYXVjX3RocmVzaG9sZF9kZgpgYGAKCk5vdyBsZXQncyBtYWtlIGEgZGVuc2l0eSBwbG90LCBwbG90dGluZyB0aGUgZGVuc2l0eSBvZiB0aGUgYXNzaWduZWQgYW5kIHVuYXNzaWduZWQgY2VsbHMgc2VwYXJhdGVseSBhbmQgZHJhd2luZyBhIHZlcnRpY2FsIGxpbmUgZm9yIHRoZSB0aHJlc2hvbGQuCgpgYGB7ciBhdWNfZGVuc2l0eV9wbG90fQphdWNfcGxvdHRpbmdfZGYgfD4KICBnZ3Bsb3QyOjpnZ3Bsb3QoCiAgICBnZ3Bsb3QyOjphZXMoCiAgICAgIHggPSBhdWMsICAjIEFVQyB2YWx1ZXMKICAgICAgY29sb3IgPSBhc3NpZ25lZCwgICMgR3JvdXAgYnkgYXNzaWdubWVudAogICAgICBmaWxsID0gYXNzaWduZWQsICAgIyBHcm91cCBieSBhc3NpZ25tZW50CiAgICApCiAgKSArCiAgZ2dwbG90Mjo6Z2VvbV9kZW5zaXR5KGFscGhhID0gMC4yKSArCiAgIyBEcmF3IGEgdmVydGljYWwgZG90dGVkIGxpbmUgc2hvd2luZyB0aGUgdGhyZXNob2xkIGZvciBlYWNoIGdlbmUgc2V0CiAgZ2dwbG90Mjo6Z2VvbV92bGluZShkYXRhID0gYXVjX3RocmVzaG9sZF9kZiwKICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBnZ3Bsb3QyOjphZXMoeGludGVyY2VwdCA9IHRocmVzaG9sZCksCiAgICAgICAgICAgICAgICAgICAgICBsdHkgPSAyKSArCiAgIyBQbG90IGVhY2ggZ2VuZSBzZXQgaW4gaXRzIG93biBmYWNldAogIGdncGxvdDI6OmZhY2V0X2dyaWQoY29scyA9IGdncGxvdDI6OnZhcnMoZ2VuZV9zZXQpKSArCiAgIyBVc2UgYSBidWlsdC1pbiB0aGVtZQogIGdncGxvdDI6OnRoZW1lX2J3KCkKYGBgCgpGb3IgdGhlc2UgcGFydGljdWxhciBnZW5lIHNldHMsIHRoZSBBVUMgdmFsdWVzIGFwcGVhciB0byBiZSBiaW1vZGFsbHkgZGlzdHJpYnV0ZWQsIGFuZCB3ZSBjYW4gZWFzaWx5IGlkZW50aWZ5IGNlbGxzIHdoZXJlIHRoZSBnZW5lcyBhcmUgaGlnaGx5IGV4cHJlc3NlZC4KCkxldCdzIHdyaXRlIHRoaXMgdGFibGUgdG8gdGhlIG91dHB1dCBmaWxlLgoKYGBge3Igc2F2ZV9hdWN9CmF1Y19wbG90dGluZ19kZiB8PiAKICByZWFkcjo6d3JpdGVfdHN2KG91dHB1dF9maWxlKQpgYGAKCiMjIyBVTUFQcwoKIyMjIyBBZGRpbmcgQVVDIHRvIGBjb2xEYXRhYAoKV2UgY2FuIGFsc28gYWRkIHRoZSBBVUMgdmFsdWVzIGJhY2sgaW50byB0aGUgU2luZ2xlQ2VsbEV4cGVyaW1lbnQgZm9yIGNvbnZlbmllbmNlLCBlLmcuLCBmb3IgcGxvdHRpbmcuCldlJ2xsIGFkZCBpdCB0byB0aGUgZXhpc3RpbmcgYGNvbERhdGFgLgoKRmlyc3QsIGxldCdzIHJlbmFtZSB0aGUgZ2VuZSBzZXQgY29sdW1ucyB0byBzb21ldGhpbmcgbW9yZSBlYXNpbHkgdHlwZWQuCgpgYGB7ciByZW5hbWVfZ2VuZV9zZXR9CmF1Y19kZiA8LSBhdWNfZGYgfD4KICAjIFVzZSBzaG9ydGVyIG5hbWVzCiAgZHBseXI6OnJlbmFtZSh6aGFuZ19hdWMgPSBld2luZ19nZW5lX3NldF9uYW1lc1tbInpoYW5nIl1dLAogICAgICAgICAgICAgICAgcmlnZ2lfYXVjID0gZXdpbmdfZ2VuZV9zZXRfbmFtZXNbWyJyaWdnaSJdXSkKCmBgYAoKQW5kIGpvaW4gaXQgdG8gdGhlIGV4aXN0aW5nIGBjb2xEYXRhYC4KCmBgYHtyIGNvbGRhdGEsIGxpdmUgPSBUUlVFfQojIEV4dHJhY3QgdGhlIGV4aXN0aW5nIGNvbERhdGEsIGFuZCBsZWZ0IGpvaW4gaXQgd2l0aCB0aGUgQVVDIHZhbHVlcyBieSB0aGUKIyBiYXJjb2Rlcwpjb2xkYXRhX2RmIDwtIGNvbERhdGEoc2NlKSB8PgogIGFzLmRhdGEuZnJhbWUoKSB8PgogIGRwbHlyOjpsZWZ0X2pvaW4oCiAgICBhdWNfZGYsCiAgICBieSA9ICJiYXJjb2RlcyIKICApCmBgYAoKTm93LCB3ZSdyZSByZWFkeSB0byBhZGQgaXQgYmFjayB0byB0aGUgb2JqZWN0LgoKYGBge3IgYWRkX2JhY2tfY29sRGF0YSwgbGl2ZSA9IFRSVUV9CiMgV2UgbmVlZCB0byBzYXZlIHRoaXMgYXMgYSBEYXRhRnJhbWUKY29sRGF0YShzY2UpIDwtIERhdGFGcmFtZSgKICBjb2xkYXRhX2RmLAogIHJvdy5uYW1lcyA9IGNvbERhdGEoc2NlKSRiYXJjb2RlcwopCmBgYAoKIyMjIyBQbG90dGluZyBVTUFQcwoKV2UgY2FuIHVzZSB0aGUgYHBsb3RVTUFQKClgIGZ1bmN0aW9uIGZyb20gdGhlIGBzY2F0ZXJgIHBhY2thZ2UgdG8gcGxvdCBhIFVNQVAgd2l0aCB0aGUgcG9pbnRzIGNvbG9yZWQgYnkgdGhlIEFVQyB2YWx1ZQoKYGBge3IgcGxvdF91bWFwX3poYW5nfQpzY2F0ZXI6OnBsb3RVTUFQKHNjZSwgY29sb3VyX2J5ID0gInpoYW5nX2F1YyIpICsKICAjIFVzZSB0aGUgZ2VuZSBzZXQgbmFtZSwgcmVwbGFjaW5nIHVuZGVyc2NvcmVzIHdpdGggc3BhY2VzCiAgZ2dwbG90Mjo6Z2d0aXRsZShzdHJpbmdyOjpzdHJfcmVwbGFjZV9hbGwoZXdpbmdfZ2VuZV9zZXRfbmFtZXNbWyJ6aGFuZyJdXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlxcXyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIgIikpCmBgYAoKTGV0J3MgY29sb3IgdGhlIHBvaW50cyBieSB0aGUgQVVDIHZhbHVlcyBmb3IgdGhlIG90aGVyIGdlbmUgc2V0LgoKYGBge3IgcGxvdF91bWFwX3JpZ2dpLCBsaXZlID0gVFJVRX0Kc2NhdGVyOjpwbG90VU1BUChzY2UsIGNvbG91cl9ieSA9ICJyaWdnaV9hdWMiKSArIAogIGdncGxvdDI6OmdndGl0bGUoc3RyaW5ncjo6c3RyX3JlcGxhY2VfYWxsKGV3aW5nX2dlbmVfc2V0X25hbWVzW1sicmlnZ2kiXV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJcXF8iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiICIpKQpgYGAKCldlIHdvdWxkIHdhbnQgdG8gZG8gc29tZXRoaW5nIG1vcmUgZm9ybWFsIHRvIGNvbmZpcm0sIGJ1dCBpdCBzZWVtcyBsaWtlIHRoZSBzYW1lIGNlbGxzIGhhdmUgaGlnaCBBVUMgdmFsdWVzIGZvciBib3RoIGdlbmUgc2V0cyEKCiMjIFNlc3Npb24gSW5mbwoKYGBge3Igc2Vzc2lvbl9pbmZvfQpzZXNzaW9uSW5mbygpCmBgYAo=
diff --git a/scRNA-seq/04-dimension_reduction_scRNA.nb.html b/scRNA-seq/04-dimension_reduction_scRNA.nb.html index d6199227..9c93c837 100644 --- a/scRNA-seq/04-dimension_reduction_scRNA.nb.html +++ b/scRNA-seq/04-dimension_reduction_scRNA.nb.html @@ -3106,8 +3106,11 @@

Reading Cell Ranger data

- -
hodgkins_sce <- DropletUtils::read10xCounts(raw_matrix_dir)
+ +
hodgkins_sce <- DropletUtils::read10xCounts(
+  raw_matrix_dir, 
+  col.names = TRUE # ensure barcodes are set as column names in the SCE object
+)
Warning: replacing previous import 'S4Arrays::makeNindexFromArrayViewport' by
@@ -3489,18 +3492,18 @@ 

Storing PCA results with the raw data

# print the top corner of the PCA matrix
 reducedDim(normalized_sce, "PCA")[1:10, 1:5]
- -
            PC1        PC2        PC3         PC4        PC5
- [1,] 15.379889   7.929537  11.790972   3.9845847   8.232603
- [2,] -1.220424   6.053443   2.100161 -10.7532071  -6.769888
- [3,]  0.647626  -7.566098 -12.004547  -0.9862535   8.936328
- [4,]  7.922958 -21.975167   4.156634 -10.0798546   5.383158
- [5,]  1.577685 -26.510992  11.089218  10.5259441 -11.660812
- [6,]  5.676435 -27.571708  13.655945  -9.3006045   2.594320
- [7,] -3.623704  -2.052362  -9.061048  -5.7941810   9.112434
- [8,]  9.577588  12.977445  -4.125885  -0.1949252 -10.757970
- [9,]  9.393483  -7.288896 -12.661552   6.4502827  -2.371315
-[10,] -7.917621  -8.052548  -9.061915   0.8675157   9.034390
+ +
                         PC1        PC2        PC3         PC4        PC5
+AAACCCACAGGTTCGC-1 15.379889   7.929537  11.790972   3.9845847   8.232603
+AAACCCACATCGATCA-1 -1.220424   6.053443   2.100161 -10.7532071  -6.769888
+AAACCCAGTATTTCCT-1  0.647626  -7.566098 -12.004547  -0.9862535   8.936328
+AAACGAAGTGGGTATG-1  7.922958 -21.975167   4.156634 -10.0798546   5.383158
+AAACGAATCCTTATCA-1  1.577685 -26.510992  11.089218  10.5259441 -11.660812
+AAACGCTAGTCTTCGA-1  5.676435 -27.571708  13.655945  -9.3006045   2.594320
+AAACGCTGTTCTTGTT-1 -3.623704  -2.052362  -9.061048  -5.7941810   9.112434
+AAAGAACAGATTCGAA-1  9.577588  12.977445  -4.125885  -0.1949252 -10.757970
+AAAGAACCAGGCACAA-1  9.393483  -7.288896 -12.661552   6.4502827  -2.371315
+AAAGAACTCCAACACA-1 -7.917621  -8.052548  -9.061915   0.8675157   9.034390
@@ -3978,7 +3981,7 @@

Session Info

-
LS0tCnRpdGxlOiAiRGltZW5zaW9uIFJlZHVjdGlvbiB3aXRoIHNjUk5BLXNlcSBkYXRhIgphdXRob3I6IENDREwgZm9yIEFMU0YKZGF0ZTogMjAyMQpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCi0tLQoKIyMgT2JqZWN0aXZlcwoKVGhpcyBub3RlYm9vayB3aWxsIGRlbW9uc3RyYXRlIGhvdyB0bzoKCi0gUmVhZCBDZWxsIFJhbmdlciBkYXRhIGludG8gUgotIEZpbHRlciBwb3N0LXF1YW50aWZpY2F0aW9uIGNlbGxzIHVzaW5nIGBlbXB0eURyb3BzQ2VsbFJhbmdlcigpYAotIEFwcGx5IGRpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbiBtZXRob2RzIHRvIHNpbmdsZSBjZWxsIGRhdGEKLSBWaXN1YWxpemUgc2FtcGxlcyBpbiByZWR1Y2VkIGRpbWVuc2lvbmFsIHNwYWNlCgotLS0KCkluIHRoaXMgbm90ZWJvb2ssIHdlJ2xsIHRyeSBvdXQgc29tZSBkaW1lbnNpb24gcmVkdWN0aW9uIHRlY2huaXF1ZXMgb24gc2luZ2xlLWNlbGwgUk5BLXNlcSBkYXRhLgoKVmlzdWFsaXppbmcgaGlnaGx5IGRpbWVuc2lvbmFsIGRhdGEgaXMgYSBjb21tb24gY2hhbGxlbmdlIGluIGdlbm9taWNzLCBhbmQgZXNwZWNpYWxseSB3aXRoIFJOQS1zZXEgZGF0YS4KVGhlIGV4cHJlc3Npb24gb2YgZXZlcnkgZ2VuZSB3ZSBsb29rIGF0IGlzIGFub3RoZXIgZGltZW5zaW9uIGRlc2NyaWJpbmcgYSBzYW1wbGUuCldoZW4gd2UgYWxzbyBoYXZlIGh1bmRyZWRzIG9yIHRob3VzYW5kcyBvZiBpbmRpdmlkdWFsIHNhbXBsZXMsIGFzIGluIHRoZSBjYXNlIG9mIHNpbmdsZS1jZWxsIGFuYWx5c2lzLCBmaWd1cmluZyBvdXQgaG93IHRvIGNsZWFybHkgZGlzcGxheSBhbGwgb2YgdGhlIGRhdGEgaW4gYSBtZWFuaW5nZnVsIHdheSBpcyBkaWZmaWN1bHQuCgpBIGNvbW1vbiBwcmFjdGljZSBpcyB0byBjb21tb24gdG8gdXNlIGRpbWVuc2lvbiByZWR1Y3Rpb24gdGVjaG5pcXVlcyBzbyBhbGwgb2YgdGhlIGRhdGEgaXMgaW4gYSBtb3JlIG1hbmFnZWFibGUgZm9ybSBmb3IgcGxvdHRpbmcsIGNsdXN0ZXJpbmcsIGFuZCBvdGhlciBkb3duc3RyZWFtIGFuYWx5c2VzLgoKIyMgU2V0IFVwCgpgYGB7ciBzZXR1cH0KIyBMb2FkIGxpYnJhcmllcwpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoc2NhdGVyKQpsaWJyYXJ5KHNjcmFuKQoKIyBTZXR0aW5nIHRoZSBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkKc2V0LnNlZWQoMTIzNDUpCmBgYAoKIyMjIERpcmVjdG9yaWVzIGFuZCBmaWxlcwoKVGhlIGRhdGEgd2Ugd2lsbCBiZSB1c2luZyBmb3IgdGhpcyBtb2R1bGUgY29tZXMgZnJvbSBhIGEgMTB4IEdlbm9taWNzIGRhdGEgc2V0IG9mIFtleHByZXNzaW9uIGRhdGEgZnJvbSBhIEhvZGdraW4ncyBMeW1waG9tYSB0dW1vcl0oaHR0cHM6Ly9zdXBwb3J0LjEweGdlbm9taWNzLmNvbS9zaW5nbGUtY2VsbC1nZW5lLWV4cHJlc3Npb24vZGF0YXNldHMvNC4wLjAvUGFyZW50X05HU0MzX0RJX0hvZGdraW5zTHltcGhvbWEpLgpUaGUgZGF0YSB3YXMgZ2VuZXJhdGVkIHdpdGggdGhlIDEwWHYzLjEgY2hlbWlzdHJ5LCBhbmQgcHJvY2Vzc2VkIHdpdGggQ2VsbCBSYW5nZXIgYW5kIDEweCBHZW5vbWljcyBzdGFuZGFyZCBwaXBlbGluZS4KCgpUaGVyZSBhcmUgYSB2YXJpZXR5IG9mIGZpbGVzIHRoYXQgeW91IHdpbGwgb2Z0ZW4gc2VlIGFzIHBhcnQgb2YgdGhlIHN0YW5kYXJkIG91dHB1dCBmcm9tIENlbGwgUmFuZ2VyLCB3aGljaCBhcmUgZGVzY3JpYmVkIGluIGRldGFpbCBpbiBbMTB4IEdlbm9taWNzIGRvY3VtZW50YXRpb25dKGh0dHBzOi8vc3VwcG9ydC4xMHhnZW5vbWljcy5jb20vc2luZ2xlLWNlbGwtZ2VuZS1leHByZXNzaW9uL3NvZnR3YXJlL3BpcGVsaW5lcy9sYXRlc3Qvb3V0cHV0L292ZXJ2aWV3KS4KV2UgaGF2ZSBpbmNsdWRlZCBzb21lIG9mIHRoZXNlIGluIHRoZSBgZGF0YS9ob2RraW5zL2NlbGxyYW5nZXJgIGRpcmVjdG9yeSwgaW5jbHVkaW5nIHRoZSBgd2ViX3N1bW1hcnkuaHRtbGAgZmlsZSB0aGF0IGluY2x1ZGVzIHNvbWUgc2ltaWxhciBRQyBzdGF0aXN0aWNzIHRvIHRob3NlIHdlIGdlbmVyYXRlZCB3aXRoIGBhbGV2aW5RQ2AuClRoZSBtYWluIGZpbGUgd2Ugd2lsbCBiZSB3b3JraW5nIHdpdGggYXJlIHRoZSBmZWF0dXJlIGJ5IGJhcmNvZGUgbWF0cmljZXMuCkNlbGwgUmFuZ2VyIGRvZXMgc29tZSBmaWx0ZXJpbmcgb24gaXRzIG93biwgYnV0IHdlIHdpbGwgc3RhcnQgd2l0aCB0aGUgcmF3IGRhdGEuCgpgYGB7ciBmaWxlcGF0aHN9CiMgbWFpbiBkYXRhIGRpcmVjdG9yeQpkYXRhX2RpciA8LSBmaWxlLnBhdGgoImRhdGEiLCAiaG9kZ2tpbnMiKQojIHJlZmVyZW5jZSBmaWxlcwpyZWZfZGlyIDwtIGZpbGUucGF0aCgiZGF0YSIsICJyZWZlcmVuY2UiKQoKIyBQYXRoIHRvIHRoZSBDZWxsIFJhbmdlciBtYXRyaXgKcmF3X21hdHJpeF9kaXIgPC0gZmlsZS5wYXRoKGRhdGFfZGlyLCAiY2VsbHJhbmdlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAicmF3X2ZlYXR1cmVfYmNfbWF0cml4IikKCiMgUGF0aCB0byBtaXRvY2hvbmRyaWFsIGdlbmVzIHRhYmxlCm1pdG9fZmlsZSA8LSBmaWxlLnBhdGgocmVmX2RpciwgImhzX21pdG9jaG9uZHJpYWxfZ2VuZXMudHN2IikKCiMgRGlyZWN0b3J5IGFuZCBmaWxlIHRvIHNhdmUgb3V0cHV0Cm5vcm1hbGl6ZWRfZGlyIDwtIGZpbGUucGF0aChkYXRhX2RpciwgIm5vcm1hbGl6ZWQiKQpmczo6ZGlyX2NyZWF0ZShub3JtYWxpemVkX2RpcikKCm91dHB1dF9zY2VfZmlsZSA8LSBmaWxlLnBhdGgobm9ybWFsaXplZF9kaXIsICJub3JtYWxpemVkX2hvZGdraW5zX3NjZS5yZHMiKQoKYGBgCgojIyBSZWFkaW5nIENlbGwgUmFuZ2VyIGRhdGEKCkNlbGwgUmFuZ2VyIG91dHB1dCBpbmNsdWRlcyBjb3VudCBkYXRhIGluIHR3byBtYWluIGZvcm1hdHMuClRoZSBmaXJzdCBpcyBhIGZvbGRlciB3aXRoIGEgZmVhdHVyZSBsaXN0LCBhIGJhcmNvZGUgbGlzdCwgYW5kIGEgc3BhcnNlIG1hdHJpeCBpbiBbIk1hdHJpeCBFeGNoYW5nZSIgZm9ybWF0XShodHRwczovL21hdGgubmlzdC5nb3YvTWF0cml4TWFya2V0L2Zvcm1hdHMuaHRtbCkuClRoZSBgRHJvcGxldFV0aWxzOjpyZWFkMTB4Q291bnRzKClgIGZ1bmN0aW9uIHRha2VzIHRoaXMgZGlyZWN0b3J5IGFuZCByZWFkcyBpbiB0aGUgZGF0YSBmcm9tIHRoZXNlIHRocmVlIGZpbGVzLCBhc3NlbWJsaW5nIHRoZSBgU2luZ2xlQ2VsbEV4cGVyaW1lbnRgIG9iamVjdCB3ZSBoYXZlIHdvcmtlZCB3aXRoIGJlZm9yZS4KCkFsdGVybmF0aXZlbHksIHdlIGNvdWxkIHVzZSB0aGUgYEhERjVgIGZvcm1hdCBmaWxlIHRoYXQgQ2VsbCBSYW5nZXIgb3V0cHV0cyBhcyBhIGZpbGUgd2l0aCB0aGUgYC5oNWAgZXh0ZW5zaW9uLCB3aGljaCBjb250YWlucyB0aGUgc2FtZSBkYXRhLgpGb3Igd2hhdGV2ZXIgcmVhc29uLCB0aGUgd2F5IHlvdSByZWFkIHRoZSBkYXRhIGFmZmVjdHMgaG93IGl0IGlzIHN0b3JlZCBpbiBSLgpSZWFkaW5nIGZyb20gdGhlIGRpcmVjdG9yeSByZXN1bHRzIGluIHNtYWxsZXIgb2JqZWN0cyBpbiBSLCBzbyB0aGF0IGlzIHdoYXQgd2Ugd2lsbCBkbyBoZXJlLgoKQ2VsbCBSYW5nZXIgYWxzbyBvdXRwdXRzIGJvdGggZmlsdGVyZWQgYW5kIHJhdyBtYXRyaWNlczsgdG9kYXkgd2Ugd2lsbCBzdGFydCB3aXRoIHRoZSByYXcgbWF0cml4IGFuZCBwZXJmb3JtIG91ciBvd24gZmlsdGVyaW5nLgoKIVtSb2FkbWFwOiBQcmVwcm9jZXNzaW5nIGFuZCBJbXBvcnRdKGRpYWdyYW1zL3JvYWRtYXBfc2luZ2xlX3ByZXByb2Nlc3NfYWxldmluLnBuZykKCmBgYHtyIHJlYWQxMHgsIGxpdmUgPSBUUlVFfQpob2Rna2luc19zY2UgPC0gRHJvcGxldFV0aWxzOjpyZWFkMTB4Q291bnRzKHJhd19tYXRyaXhfZGlyKQpgYGAKCkhvdyBtYW55IHBvdGVudGlhbCBjZWxscyBhcmUgdGhlcmUgaGVyZT8KCmBgYHtyIGNlbGxjb3VudCwgbGl2ZSA9IFRSVUV9CmRpbShob2Rna2luc19zY2UpCmBgYAoKVGhhdCBpcyBhIGxvdCBvZiBjZWxscyEKSW4gZmFjdCwgaXQgaXMgcmVhbGx5IGV2ZXJ5IHBvc3NpYmxlIGJhcmNvZGUsIHdoZXRoZXIgdGhlcmUgd2VyZSByZWFkcyBhc3NvY2lhdGVkIHdpdGggaXQgb3Igbm90LgpXZSBzaG91bGQgcHJvYmFibHkgZG8gc29tZXRoaW5nIGFib3V0IHRoYXQuCgoKIyMgUUMgYW5kIG5vcm1hbGl6YXRpb24KCiFbUm9hZG1hcDogUUMgYW5kIGZpbHRlcmluZ10oZGlhZ3JhbXMvcm9hZG1hcF9zaW5nbGVfcWNfbm9ybS5wbmcpCgojIyMgQmFzaWMgUUMgc3RhdHMKCldlIHdpbGwgc3RhcnQgYnkgY2FsY3VsYXRpbmcgdGhlIGJhc2ljIFFDIHN0YXRzIGFzIHdlIGhhdmUgZG9uZSBwcmV2aW91c2x5LCBhZGRpbmcgdGhvc2UgdG8gb3VyIGBTaW5nbGVDZWxsRXhwZXJpbWVudGAgb2JqZWN0LgoKVGhlIGZpcnN0IHN0ZXAgYWdhaW4gaXMgcmVhZGluZyBpbiBvdXIgdGFibGUgb2YgbWl0b2Nob25kcmlhbCBnZW5lcyBhbmQgZmluZGluZyB0aGUgb25lcyB0aGF0IHdlcmUgcXVhbnRpZmllZCBvdXIgZGF0YSBzZXQuCgpgYGB7ciBtaXRvZ2VuZXN9Cm1pdG9fZ2VuZXMgPC0gcmVhZHI6OnJlYWRfdHN2KG1pdG9fZmlsZSkgfD4KICBkcGx5cjo6ZmlsdGVyKGdlbmVfaWQgJWluJSByb3duYW1lcyhob2Rna2luc19zY2UpKSB8PgogIGRwbHlyOjpwdWxsKGdlbmVfaWQpCmBgYAoKTmV4dCB3ZSB3aWxsIGNhbGN1bGF0ZSB0aGUgUUMgc3RhdHMgdGhhdCB3ZSB1c2VkIGJlZm9yZS4KTm90ZSB0aGF0IHRoaXMgaXMgbXVjaCBzbG93ZXIgdGhhbiBiZWZvcmUsIGFzIHdlIGhhdmUgbWFueSBtb3JlIGdlbmVzIGluIHRoZSB1bmZpbHRlcmVkIHNldCEKCmBgYHtyIGNhbGN1bGF0ZVFDfQpob2Rna2luc19zY2UgPC0gc2NhdGVyOjphZGRQZXJDZWxsUUMoCiAgaG9kZ2tpbnNfc2NlLAogIHN1YnNldHMgPSBsaXN0KG1pdG8gPSBtaXRvX2dlbmVzKSkKYGBgCgpXZSBjYW4gbm93IGRvIHRoZSBtb3N0IGJhc2ljIGxldmVsIG9mIGZpbHRlcmluZzogZ2V0dGluZyByaWQgb2YgImNlbGxzIiB3aXRoIG5vIHJlYWRzLgoKYGBge3IgcmVtb3ZlX3plcm8sIGxpdmUgPSBUUlVFfQpob2Rna2luc19zY2UgPC0gaG9kZ2tpbnNfc2NlWywgaG9kZ2tpbnNfc2NlJHRvdGFsID4gMF0KZGltKGhvZGdraW5zX3NjZSkKYGBgCgojIyMgRmlsdGVyaW5nIHdpdGggYGVtcHR5RHJvcHNDZWxsUmFuZ2VyKClgCgpUaGUgYERyb3BsZXRVdGlsc2AgcGFja2FnZSB0aGF0IHdlIHVzZWQgdG8gcmVhZCBpbiB0aGUgMTB4IGRhdGEgaGFzIGEgbnVtYmVyIG9mIG90aGVyIHVzZWZ1bCBmZWF0dXJlcy4KT25lIGlzIHRoZSBgZW1wdHlEcm9wc0NlbGxSYW5nZXIoKWAgZnVuY3Rpb24sIHdoaWNoIHVzZXMgdGhlIG92ZXJhbGwgZ2VuZSBleHByZXNzaW9uIHBhdHRlcm5zIGluIHRoZSBzYW1wbGUgdG8gaWRlbnRpZnkgZHJvcGxldHMgdGhhdCBhcmUgbGlrZWx5IHRvIG5vdCBjb250YWluIGFuIGludGFjdCBjZWxsLCBidXQgbWF5IHNpbXBseSBoYXZlIGNvbnRhaW5lZCBsb29zZSBhbWJpZW50IFJOQSByZWxlYXNlZCBkdXJpbmcgY2VsbCBzZXBhcmF0aW9uLgpUaGlzIG1ldGhvZCB3YXMgb3JpZ2luYWxseSBkZXZlbG9wZWQgYnkgW0x1biAqZXQgYWwuKiAoMjAxOSldKGh0dHBzOi8vZG9pLm9yZy8xMC4xMTg2L3MxMzA1OS0wMTktMTY2Mi15KSBhbmQgaW1wbGVtZW50ZWQgYXMgdGhlIGZ1bmN0aW9uIGBlbXB0eURyb3BzKClgLCBidXQgaGFzIHNpbmNlIGJlZW4gYWRhcHRlZCBhcyB0aGUgbWFpbiBmaWx0ZXJpbmcgbWV0aG9kIHVzZWQgYnkgQ2VsbCBSYW5nZXIuIApUaGUgYGVtcHR5RHJvcHNDZWxsUmFuZ2VyKClgIGZ1bmN0aW9uIGVtdWxhdGVzIHRoZSB2YXJpYW50IG9mIHRoaXMgZnVuY3Rpb24gdGhhdCB1c2VkIGJ5IENlbGwgUmFuZ2VyLCBtYWtpbmcgdGhlIHJlc3VsdHMgbW9yZSBjb21wYXJhYmxlIGJldHdlZW4gdGhlIHR3byBtZXRob2RzLgoKVGhlIEVtcHR5IERyb3BzIG1ldGhvZCB1c2VzIHRoZSBkcm9wbGV0cyB3aXRoIHZlcnkgbG93IFVNSSBjb3VudHMgdG8gZXN0aW1hdGUgdGhlICJhbWJpZW50IiBleHByZXNzaW9uIHBhdHRlcm4gb2YgUk5BIGNvbnRlbnQgb3V0c2lkZSBvZiBjZWxscy4KSXQgdGhlbiBzY29yZXMgdGhlIHJlbWFpbmluZyBjZWxscyBiYXNlZCBob3cgbXVjaCB0aGV5IGRldmlhdGUgZnJvbSB0aGF0IHBhdHRlcm4sIGFzc2lnbmluZyBhIHNtYWxsIFAgdmFsdWUgd2hlbiB0aGUgZHJvcGxldCdzIGV4cHJlc3Npb24gZGV2aWF0ZXMgZnJvbSB0aGUgYW1iaWVudCBleHByZXNzaW9uIHBhdHRlcm4uCkJlY2F1c2UgaXQgdXNlcyB0aGUgbG93IFVNSSBjb3VudCBkcm9wbGV0cywgdGhpcyBtZXRob2Qgc2hvdWxkIG5vdCBiZSB1c2VkIHdoZW4gb3RoZXIgZmlsdGVyaW5nIGhhcyBhbHJlYWR5IGJlZW4gcGVyZm9ybWVkICh3aGljaCBpcyB1bmZvcnR1bmF0ZWx5IHRoZSBjYXNlIHdpdGggdGhlIHZlcnNpb24gb2YgYHNhbG1vbiBhbGV2aW5gIHdlIHVzZWQpLgoKVGhpcyBtZXRob2Qgc2VlbXMgdG8gcGVyZm9ybSB3ZWxsIHRvIGV4Y2x1ZGUgZmFsc2UgImNlbGxzIiB3aGlsZSByZXRhaW5pbmcgY2VsbHMgd2l0aCBkaXN0aW5jdCBleHByZXNzaW9uIHByb2ZpbGVzIGJ1dCBsb3cgY291bnRzIHRoYXQgbWlnaHQgaGF2ZSBmYWlsZWQgYSBzaW1wbGUgY3V0b2ZmLgpOb3RlIHRoYXQgdGhpcyBtZXRob2QgYWxzbyByZXF1aXJlcyB0aGF0IHRoZSBkYXRhIGhhcyBhbHJlYWR5IGJlZW4gcXVhbnRpZmllZCwgd2l0aCByZWFkcyBhc3NpZ25lZCB0byBnZW5lcywgYXMgY29tcGFyZWQgdG8gYSBzaW1wbGUgdG90YWwgVU1JIGNvdW50IGZpbHRlciB3aGljaCBjYW4gYmUgcGVyZm9ybWVkIG11Y2ggZWFybGllciBpbiB0aGUgcGlwZWxpbmUuCgpUaGUgYGVtcHR5RHJvcHNDZWxsUmFuZ2VyKClgIGZ1bmN0aW9uIHRha2VzIHRoZSBgY291bnRzYCBtYXRyaXggZnJvbSBvdXIgU2luZ2xlQ2VsbEV4cGVyaW1lbnQsIGFuZCByZXR1cm5zIGEgZGF0YSBmcmFtZSB3aXRoIHRoZSBzdGF0aXN0aWNzIGl0IGNhbGN1bGF0ZXMuClRoaXMgd2lsbCB0YWtlIGEgZmV3IG1pbnV0ZXMgdG8gcnVuLCBidXQgd2UgY2FuIHNwZWVkIGl0IHVwIGJ5IGFsbG93aW5nIHBhcmFsbGVsIHByb2Nlc3NpbmcuCgpgYGB7ciBlbXB0eWRyb3BzLCBsaXZlID0gVFJVRX0KZHJvcGxldF9zdGF0cyA8LSBEcm9wbGV0VXRpbHM6OmVtcHR5RHJvcHNDZWxsUmFuZ2VyKAogIGNvdW50cyhob2Rna2luc19zY2UpLAogIEJQUEFSQU0gPSBCaW9jUGFyYWxsZWw6Ok11bHRpY29yZVBhcmFtKDQpKSAjIHVzZSBtdWx0aXByb2Nlc3NpbmcKYGBgCgpXZSB3aWxsIHVzZSBhIGZhbHNlIGRpc2NvdmVyeSByYXRlIChGRFIpIG9mIDAuMDEgYXMgb3VyIGN1dG9mZiBmb3IgInJlYWwiIGNlbGxzLgpTaW5jZSBgZW1wdHlEcm9wc0NlbGxSYW5nZXIoKWAgdXNlcyBsb3cgY291bnQgY2VsbHMgdG8gZXN0aW1hdGUgdGhlICJhbWJpZW50IiBleHByZXNzaW9uIHBhdHRlcm4sIHRob3NlIGNlbGxzIGFyZSBub3QgYXNzaWduZWQgYW4gRkRSIHZhbHVlLCBhbmQgaGF2ZSBhIHZhbHVlIG9mIE5BLgpUaGVzZSBOQXMgY2FuIGJlIGEgcHJvYmxlbSBmb3IgZmlsdGVyaW5nIHdpdGggYSBCb29sZWFuIHZlY3RvciwgYXMgd2UgZGlkIGFib3ZlLCBzbyBpbnN0ZWFkIHdlIHdpbGwgdXNlIHRoZSBgd2hpY2goKWAgZnVuY3Rpb24gdG8gZ2V0IHRoZSAqcG9zaXRpb25zKiBvZiB0aGUgY2VsbHMgdGhhdCBwYXNzIG91ciBmaWx0ZXIgYW5kIHNlbGVjdCB0aGUgY29sdW1ucyB3ZSB3YW50IHVzaW5nIHRoYXQuCgpgYGB7ciBmaWx0ZXJfZW1wdHksIGxpdmUgPSBUUlVFfQpjZWxsc190b19yZXRhaW4gPC0gd2hpY2goZHJvcGxldF9zdGF0cyRGRFIgPD0gMC4wMSkKCmZpbHRlcmVkX3NjZSA8LSBob2Rna2luc19zY2VbLCBjZWxsc190b19yZXRhaW5dCmRpbShmaWx0ZXJlZF9zY2UpCmBgYAoKSG93IGRvZXMgdGhpcyBjb21wYXJlIHRvIHRoZSBudW1iZXIgb2YgY2VsbHMgaW4gdGhlIENlbGwgUmFuZ2VyIGZpbHRlcmVkIGRhdGE/Ckxvb2tpbmcgdGhlIGB3ZWJfc3VtbWFyeS5odG1sYCByZXBvcnQgZnJvbSBDZWxsIFJhbmdlciwgaXQgc2VlbXMgdGhhdCBpdCB3b3VsZCBoYXZlIGtlcHQgMywzOTQgY2VsbHMsIHNvIHdlIHNlZW0gdG8gYmUgZ2V0dGluZyBicm9hZGx5IHNpbWlsYXIgcmVzdWx0cy4KCiMjIyBDaGVja2luZyBtaXRvY2hvbmRyaWFsIGNvbnRlbnQKCldoaWxlIGBlbXB0eURyb3BzQ2VsbFJhbmdlcigpYCBzaG91bGQgaGF2ZSBmaWx0ZXJlZCBvdXQgZHJvcGxldHMgY29udGFpbmluZyBubyBjZWxscywgaXQgd2lsbCBub3QgbmVjZXNzYXJpbHkgZmlsdGVyIG91dCBkYW1hZ2VkIGNlbGxzLgpGb3IgdGhhdCB3ZSB3aWxsIHN0aWxsIHdhbnQgdG8gbG9vayBhdCBtaXRvY2hvbmRyaWFsIGNvbnRlbnQsIGFzIHdlIGRpZCBwcmV2aW91c2x5LgpUaGUgc3RhdGlzdGljcyB3ZSBjYWxjdWxhdGVkIGVhcmxpZXIgd2l0aCBgYWRkUGVyQ2VsbFFDKClgIGFyZSByZXRhaW5lZCBpbiBvdXIgbmV3IG9iamVjdCwgc28gd2UgY2FuIHBsb3QgdGhvc2UgZGlyZWN0bHkuCgpgYGB7ciBtaXRvX3BlcmNlbnRfcGxvdH0KIyBQbG90IHRoZSBtaXRvY2hvbmRyaWFsIHBlcmNlbnRzIHN0b3JlZCBpbiBgZmlsdGVyZWRfc2NlYApnZ3Bsb3QobWFwcGluZyA9IGFlcyh4ID0gZmlsdGVyZWRfc2NlJHN1YnNldHNfbWl0b19wZXJjZW50KSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAxMDApCmBgYApUaGVyZSBhcmUgY2VydGFpbmx5IHNvbWUgY2VsbHMgd2l0aCBoaWdoIG1pdG9jaG9uZHJpYWwgcGVyY2VudGFnZXMhCkZvciBub3csIHdlIHdpbGwgdXNlIGEgY3V0b2ZmIG9mIDIwJSB0byBmaWx0ZXIgb3V0IHRoZSB3b3JzdCBvZiB0aGUgY2VsbHMuCgpgYGB7ciBsaXZlID0gVFJVRX0KZmlsdGVyZWRfc2NlIDwtIGZpbHRlcmVkX3NjZVssIGZpbHRlcmVkX3NjZSRzdWJzZXRzX21pdG9fcGVyY2VudCA8IDIwXQpgYGAKCgpXZSBjYW4gYWxzbyBmaWx0ZXIgYnkgZmVhdHVyZXMgKGdlbmVzIGluIG91ciBjYXNlKSB1c2luZyBgc2NhdGVyOjphZGRQZXJGZWF0dXJlUUMoKWAgd2hpY2ggd2lsbCBjb21wdXRlIHRoZSBudW1iZXIgb2Ygc2FtcGxlcyB3aGVyZSBlYWNoIGdlbmUgaXMgZGV0ZWN0ZWQgYW5kIHRoZSBtZWFuIGNvdW50IGFjcm9zcyBhbGwgZ2VuZXMuCldlIGNhbiB0aGVuIHVzZSB0aG9zZSBkYXRhIChzdG9yZWQgaW4gYHJvd0RhdGFgKSB0byBmaWx0ZXIgYnkgcm93IHRvIG9ubHkgdGhlIGdlbmVzIHRoYXQgYXJlIGRldGVjdGVkIGluIGF0IGxlYXN0IDUlIG9mIGNlbGxzLCBhbmQgd2l0aCBhIG1lYW4gY291bnQgPiAwLjEuCgpgYGB7ciBnZW5lX3FjfQpmaWx0ZXJlZF9zY2UgPC0gc2NhdGVyOjphZGRQZXJGZWF0dXJlUUMoZmlsdGVyZWRfc2NlKQpkZXRlY3RlZCA8LSByb3dEYXRhKGZpbHRlcmVkX3NjZSkkZGV0ZWN0ZWQgPiA1CmV4cHJlc3NlZCA8LSByb3dEYXRhKGZpbHRlcmVkX3NjZSkkbWVhbiA+IDAuMQoKIyBmaWx0ZXIgdGhlIGdlbmVzIChyb3dzKSB0aGlzIHRpbWUKZmlsdGVyZWRfc2NlIDwtIGZpbHRlcmVkX3NjZVtkZXRlY3RlZCAmIGV4cHJlc3NlZCwgXQpgYGAKCkhvdyBtYW55IGNlbGxzIGRvIHdlIGhhdmUgbm93PwoKYGBge3IgZmlsdGVyZWRfZGltfQpkaW0oZmlsdGVyZWRfc2NlKQpgYGAKCgojIyMgTm9ybWFsaXplCgpOb3cgd2Ugd2lsbCBwZXJmb3JtIHRoZSBzYW1lIG5vcm1hbGl6YXRpb24gc3RlcHMgd2UgZGlkIGluIGEgcHJldmlvdXMgZGF0YXNldCwgdXNpbmcgYHNjcmFuOjpjb21wdXRlU3VtRmFjdG9ycygpYCBhbmQgYHNjYXRlcjo6bG9nTm9ybUNvdW50cygpYC4KWW91IG1pZ2h0IHJlY2FsbCB0aGF0IHRoZXJlIGlzIGEgYml0IG9mIHJhbmRvbW5lc3MgaW4gc29tZSBvZiB0aGVzZSBjYWxjdWxhdGlvbnMsIHNvIHdlIHNob3VsZCBiZSBzdXJlIHRvIGhhdmUgdXNlZCBgc2V0LnNlZWQoKWAgZWFybGllciBpbiB0aGUgbm90ZWJvb2sgZm9yIHJlcHJvZHVjaWJpbGl0eS4KCmBgYHtyIHN1bWZhY3RvcnN9CiMgQ2x1c3RlciBzaW1pbGFyIGNlbGxzCnFjbHVzdCA8LSBzY3Jhbjo6cXVpY2tDbHVzdGVyKGZpbHRlcmVkX3NjZSkKCiMgQ29tcHV0ZSBzdW0gZmFjdG9ycyBmb3IgZWFjaCBjZWxsIGNsdXN0ZXIgZ3JvdXBpbmcuCmZpbHRlcmVkX3NjZSA8LSBzY3Jhbjo6Y29tcHV0ZVN1bUZhY3RvcnMoZmlsdGVyZWRfc2NlLCBjbHVzdGVycyA9IHFjbHVzdCwgcG9zaXRpdmUgPSBGQUxTRSkKYGBgCgpJdCB0dXJucyBvdXQgaW4gdGhpcyBjYXNlIHdlIGVuZCB1cCB3aXRoIHNvbWUgbmVnYXRpdmUgc2l6ZSBmYWN0b3JzLgpUaGlzIGlzIHVzdWFsbHkgYW4gaW5kaWNhdGlvbiB0aGF0IG91ciBmaWx0ZXJpbmcgd2FzIG5vdCBzdHJpbmdlbnQgZW5vdWdoLCBhbmQgdGhlcmUgcmVtYWluIGEgbnVtYmVyIG9mIGNlbGxzIG9yIGdlbmVzIHdpdGggbmVhcmx5IHplcm8gY291bnRzLgpUaGlzIHByb2JhYmx5IGhhcHBlbmVkIHdoZW4gd2UgcmVtb3ZlZCB0aGUgaW5mcmVxdWVudGx5LWV4cHJlc3NlZCBnZW5lczsgY2VsbHMgd2hpY2ggaGFkIGhpZ2ggY291bnRzIGZyb20gdGhvc2UgcGFydGljdWxhciBnZW5lcyAoYW5kIGZldyBvdGhlcnMpIGNvdWxkIGhhdmUgaGFkIHRoZWlyIHRvdGFsIGNvdW50cyBkcmFtYXRpY2FsbHkgcmVkdWNlZC4KClRvIGFjY291bnQgZm9yIHRoaXMsIHdlIHdpbGwgcmVjYWxjdWxhdGUgdGhlIHBlci1jZWxsIHN0YXRzIGFuZCBmaWx0ZXIgb3V0IGxvdyBjb3VudHMuClVuZm9ydHVuYXRlbHksIHRvIGRvIHRoaXMsIHdlIG5lZWQgdG8gZmlyc3QgcmVtb3ZlIHRoZSBwcmV2aW91c2x5IGNhbGN1bGF0ZWQgc3RhdGlzdGljcywgd2hpY2ggd2Ugd2lsbCBkbyBieSBzZXR0aW5nIHRoZW0gdG8gYE5VTExgLgoKYGBge3IgcmVRQ30KIyByZW1vdmUgcHJldmlvdXMgY2FsY3VsYXRpb25zCmZpbHRlcmVkX3NjZSRzdW0gPC0gTlVMTApmaWx0ZXJlZF9zY2UkZGV0ZWN0ZWQgPC0gTlVMTApmaWx0ZXJlZF9zY2UkdG90YWwgPC0gTlVMTApmaWx0ZXJlZF9zY2Ukc3Vic2V0c19taXRvX3N1bSA8LSBOVUxMCmZpbHRlcmVkX3NjZSRzdWJzZXRzX21pdG9fZGV0ZWN0ZWQgPC0gTlVMTApmaWx0ZXJlZF9zY2Ukc3Vic2V0c19taXRvX3N1bSA8LSBOVUxMCgojIHJlY2FsY3VsYXRlIGNlbGwgc3RhdHMKZmlsdGVyZWRfc2NlIDwtIHNjYXRlcjo6YWRkUGVyQ2VsbFFDKGZpbHRlcmVkX3NjZSwgc3Vic2V0cyA9IGxpc3QobWl0byA9IG1pdG9fZ2VuZXMpKQoKIyBwcmludCB0aGUgbnVtYmVyIG9mIGNlbGxzIHdpdGggZmV3ZXIgdGhhbiA1MDAgVU1JcwpzdW0oZmlsdGVyZWRfc2NlJHN1bSA8IDUwMCkKYGBgCgpOb3cgd2UgY2FuIGZpbHRlciBhZ2Fpbi4KSW4gdGhpcyBjYXNlLCB3ZSB3aWxsIGtlZXAgY2VsbHMgd2l0aCBhdCBsZWFzdCA1MDAgVU1JcyBhZnRlciByZW1vdmluZyB0aGUgbG93bHkgZXhwcmVzc2VkIGdlbmVzLgpUaGVuIHdlIHdpbGwgcmVkbyB0aGUgc2l6ZSBmYWN0b3IgY2FsY3VsYXRpb24sIGhvcGVmdWxseSB3aXRoIG5vIG1vcmUgd2FybmluZ3MuCgoKYGBge3IgcmVmaWx0ZXJ9CmZpbHRlcmVkX3NjZSA8LSBmaWx0ZXJlZF9zY2VbLCBmaWx0ZXJlZF9zY2Ukc3VtID49IDUwMF0KCnFjbHVzdCA8LSBzY3Jhbjo6cXVpY2tDbHVzdGVyKGZpbHRlcmVkX3NjZSkKCmZpbHRlcmVkX3NjZSA8LSBzY3Jhbjo6Y29tcHV0ZVN1bUZhY3RvcnMoZmlsdGVyZWRfc2NlLCBjbHVzdGVycyA9IHFjbHVzdCkKYGBgCgpMb29rcyBnb29kISBOb3cgd2UnbGwgZG8gdGhlIG5vcm1hbGl6YXRpb24uCgpgYGB7ciBub3JtYWxpemV9CiMgTm9ybWFsaXplIGFuZCBsb2cgdHJhbnNmb3JtLgpub3JtYWxpemVkX3NjZSA8LSBzY2F0ZXI6OmxvZ05vcm1Db3VudHMoZmlsdGVyZWRfc2NlKQpgYGAKCkF0IHRoaXMgcG9pbnQsIHdlIGhhdmUgYSBmZXcgZGlmZmVyZW50IHZlcnNpb25zIG9mIG91ciBgU2luZ2xlQ2VsbEV4cGVyaW1lbnRgIG9iamVjdC4KVGhlIG9yaWdpbmFsIChtb3N0bHkpIHVuZmlsdGVyZWQgdmVyc2lvbiBpcyBpbiBgaG9kZ2tpbnNfc2NlYCwgdGhlIGZpbHRlcmVkIHZlcnNpb24gaW4gYGZpbHRlcmVkX3NjZWAsIGFuZCB0aGUgbm9ybWFsaXplZCB2ZXJzaW9uIGluIGBub3JtYWxpemVkX3NjZWAuCldlIGNhbiBjbGVhbiB0aG9zZSB1cCBhIGJpdCB0byBzYXZlIG1lbW9yeSwga2VlcGluZyBvbmx5IHRoZSBsYXRlc3QgYG5vcm1hbGl6ZWRfc2NlYCB2ZXJzaW9uLCB3aGljaCBub3cgaGFzIHR3byBgYXNzYXlgczoKYGNvdW50c2Agd2l0aCB0aGUgcmF3IGRhdGEgYW5kIGBsb2djb3VudHNgIHdpdGggdGhlIG5vcm1hbGl6ZWQgYW5kIHRyYW5zZm9ybWVkIGRhdGEuCgpgYGB7ciBjbGVhbl91cCwgbGl2ZSA9IFRSVUV9CmFzc2F5TmFtZXMobm9ybWFsaXplZF9zY2UpCnJtKGhvZGdraW5zX3NjZSwgZmlsdGVyZWRfc2NlKQpgYGAKCgojIyBEaW1lbnNpb25hbGl0eSByZWR1Y3Rpb24gYW5kIGRpc3BsYXkKCiFbUm9hZG1hcDogRGltZW5zaW9uYWxpdHkgcmVkdWN0aW9uXShkaWFncmFtcy9yb2FkbWFwX3NpbmdsZV9kaW1lbnNpb25fcmVkdWN0aW9uLnBuZykKCiMjIyBQcmluY2lwYWwgQ29tcG9uZW50cyBBbmFseXNpcwoKUHJpbmNpcGFsIGNvbXBvbmVudCBhbmFseXNpcyAoUENBKSBpcyBhIGRpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbiB0ZWNobmlxdWUgdGhhdCBhbGxvd3MgdXMgdG8gaWRlbnRpZnkgdGhlIGxhcmdlc3QgY29tcG9uZW50cyBvZiB2YXJpYXRpb24gaW4gYSBjb21wbGV4IGRhdGFzZXQuCk91ciBleHByZXNzaW9uIGRhdGEgY2FuIGJlIHRob3VnaHQgb2YgYXMgbWFwcGluZyBlYWNoIHNhbXBsZSBpbiBhIG11bHRpZGltZW5zaW9uYWwgc3BhY2UgZGVmaW5lZCBieSB0aGUgZXhwcmVzc2lvbiBsZXZlbCBvZiBlYWNoIGdlbmUuClRoZSBleHByZXNzaW9uIG9mIG1hbnkgb2YgdGhvc2UgZ2VuZXMgYXJlIGNvcnJlbGF0ZWQsIHNvIHdlIGNhbiBvZnRlbiBnZXQgYSBiZXR0ZXIsIHNpbXBsZXIgcGljdHVyZSBvZiB0aGUgZGF0YSBieSBjb21iaW5pbmcgdGhlIGluZm9ybWF0aW9uIGZyb20gdGhvc2UgY29ycmVsYXRlZCBnZW5lcy4KClBDQSByb3RhdGVzIGFuZCB0cmFuc2Zvcm1zIHRoaXMgc3BhY2Ugc28gdGhhdCBlYWNoIGF4aXMgaXMgbm93IGEgY29tYmluYXRpb24gb2YgbXVsdGlwbGUgY29ycmVsYXRlZCBnZW5lcywgb3JkZXJlZCBzbyB0aGUgZmlyc3QgYXhlcyBjYXB0dXJlIHRoZSBtb3N0IHZhcmlhdGlvbiBmcm9tIHRoZSBkYXRhLgpUaGVzZSBuZXcgYXhlcyBhcmUgdGhlICJwcmluY2lwYWwgY29tcG9uZW50cy4iCklmIHdlIGxvb2sgYXQgdGhlIGZpcnN0IGZldyBjb21wb25lbnRzLCB3ZSBjYW4gb2Z0ZW4gZ2V0IGEgbmljZSBvdmVydmlldyBvZiByZWxhdGlvbnNoaXBzIGFtb25nIHRoZSBzYW1wbGVzIGluIHRoZSBkYXRhLgoKIyMjIyBTdG9yaW5nIFBDQSByZXN1bHRzIHdpdGggdGhlIHJhdyBkYXRhCgpXZSB3aWxsIHN0b3JlIHRoZSBQQ0EgcmVzdWx0cyBpbiBvdXIgYFNpbmdsZUNlbGxFeHBlcmltZW50YCBvYmplY3QsIGFzIHdlIHdpbGwgd2FudCB0byB1c2UgdGhlbSBsYXRlci4KVG8gZG8gdGhpcywgd2Ugd2lsbCB1c2UgdGhlIGBydW5QQ0EoKWAgZnVuY3Rpb24gZnJvbSBgc2NhdGVyYCwgd2hpY2ggcGVyZm9ybXMgdGhlIFBDQSBjYWxjdWxhdGlvbnMgYW5kIHJldHVybnMgYSBuZXcgb2JqZWN0IHdpdGggdGhlIHJlc3VsdHMgc3RvcmVkIGluIHRoZSBgcmVkdWNlZERpbWAgc2xvdC4KSWYgd2Ugd2FudGVkIHRvLCB3ZSBjb3VsZCBnZXQgdGhlIHJhdyByZXN1bHRzIGFzIGEgbWF0cml4IGluc3RlYWQgd2l0aCBgY2FsY3VsYXRlUENBKClgIGZ1bmN0aW9uLCBhcyB3ZSBkaWQgaW4gYSBwcmV2aW91cyBub3RlYm9vay4KCldlIHdpbGwgYWxzbyB1c2UgdGhlIGBudG9wYCBhcmd1bWVudCB0byBjYWxjdWxhdGUgdGhlIFBDQSB1c2luZyAyMDAwIGdlbmVzIHdpdGggdGhlIGhpZ2hlc3QgdmFyaWFuY2UuClRoZSBkZWZhdWx0IGlzIGBudG9wID0gNTAwYC4KCmBgYHtyIHJ1blBDQSwgbGl2ZSA9IFRSVUV9CiMgY2FsY3VsYXRlIFBDQSB1c2luZyB0aGUgdG9wIDIwMDAgZ2VuZXMKbm9ybWFsaXplZF9zY2UgPC0gcnVuUENBKG5vcm1hbGl6ZWRfc2NlLCBudG9wID0gMjAwMCkKYGBgCgpXZSBjYW4gc2VlIHdoYXQgcmVkdWNlZCBkaW1lbnNpb25hbGl0eSBtYXRyaWNlcyBhcmUgc3RvcmVkIGluIHRoZSBvYmplY3Qgd2l0aCB0aGUgYHJlZHVjZWREaW1OYW1lcygpYCBmdW5jdGlvbi4KCmBgYHtyIHJlZHVjZWRfZGltX25hbWVzLCBsaXZlID0gVFJVRX0KIyBwcmludCB0aGUgcmVkdWNlZCBkaW1lbnNpb25hbGl0eSB0YWJsZXMgYXZhaWxhYmxlCnJlZHVjZWREaW1OYW1lcyhub3JtYWxpemVkX3NjZSkKYGBgCgpUbyBleHRyYWN0IHRoZW0gYnkgbmFtZSwgd2UgdXNlIHRoZSBgcmVkdWNlZERpbSgpYCBmdW5jdGlvbiwgbXVjaCBsaWtlIHRoZSBgYXNzYXkoKWAgZnVuY3Rpb24gdG8gZXh0cmFjdCBvcmlnaW5hbCBkYXRhLgoKYGBge3IgZXh0cmFjdF9yZWR1Y2VkLCBsaXZlID0gVFJVRX0KIyBwcmludCB0aGUgdG9wIGNvcm5lciBvZiB0aGUgUENBIG1hdHJpeApyZWR1Y2VkRGltKG5vcm1hbGl6ZWRfc2NlLCAiUENBIilbMToxMCwgMTo1XQpgYGAKCiMjIyMgUGxvdHRpbmcgUENBIHJlc3VsdHMKCklmIHdlIGhhdmUgdGhlIFBDQSByZXN1bHRzIHN0b3JlZCBpbiB0aGUgYFNpbmdsZUNlbGxFeHBlcmltZW50YCBvYmplY3QsIHdlIGNhbiB1c2UgdGhlIGBzY2F0ZXI6OnBsb3RSZWR1Y2VkRGltKClgIGZ1bmN0aW9uIHRvIHBsb3QgaXQgd2l0aCBzb21lIG5pY2UgZGVmYXVsdHMgZWFzaWx5LgpPbmUgbmljZSB0aGluZyBhYm91dCB0aGlzIGZ1bmN0aW9uIGlzIHRoYXQgaXQgdXNlcyBgZ2dwbG90MmAgdW5kZXIgdGhlIGhvb2QsIHNvIGlmIHdlIHdhbnRlZCB0byBjdXN0b21pemUgaXQgbGF0ZXIsIHdlIGNvdWxkLgoKYGBge3IgcGxvdFBDQSwgbGl2ZSA9IFRSVUV9CiMgcGxvdCBQQ0EgcmVzdWx0cwpwbG90UmVkdWNlZERpbShub3JtYWxpemVkX3NjZSwgIlBDQSIpCmBgYApQQ0EgZ2l2ZXMgdXMgYSBtYXRyaXggd2l0aCBtb3JlIHRoYW4ganVzdCB0d28gZGltZW5zaW9ucywgYW5kIHdlIG1pZ2h0IHdhbnQgdG8gbG9vayBhdCBzb21lIGhpZ2hlciBkaW1lbnNpb25zIHRvby4KV2UgY2FuIGRvIHRoYXQgd2l0aCB0aGUgYG5jb21wb25lbnRzYCBhcmd1bWVudC4KCmBgYHtyIHBsb3RQQ0EzNCwgbGl2ZSA9IFRSVUV9CiMgcGxvdCBQQzMgYW5kIFBDNApwbG90UmVkdWNlZERpbShub3JtYWxpemVkX3NjZSwgIlBDQSIsIG5jb21wb25lbnRzID0gYygzLDQpKQpgYGAKCiMjIyBNb2RlbGluZyB2YXJpYW5jZQoKVGhlIHZhcmlhdGlvbiBpbiBnZW5lIGV4cHJlc3Npb24gd2Ugc2VlIGFtb25nIGNlbGxzIGNvbWVzIGZyb20gYSBjb21iaW5hdGlvbiBvZiB2YXJpYXRpb24gZHVlIHRvIHRlY2huaWNhbCBlZmZlY3RzIGFuZCB0aGUgYmlvbG9neSB3ZSByZWFsbHkgY2FyZSBhYm91dC4KSW4gb3JkZXIgdG8gcm91Z2hseSBhY2NvdW50IGZvciB0aGlzIHdlIGNvdWxkIGp1c3QgdGFrZSB0aGUgbGFyZ2VzdCB2YXJpYW5jZSBnZW5lcywgb24gdGhlIGFzc3VtcHRpb24gdGhhdCBsb3cgdmFyaWFuY2UgZ2VuZXMgYXJlIG1vc3RseSBqdXN0IG5vaXNlLgpUaGlzIGlzIHRoZSBkZWZhdWx0IGFwcHJvYWNoIHRoYXQgYHJ1blBDQSgpYCBhbmQgYGNhbGN1bGF0ZVBDQSgpYCB0YWtlLCB1c2luZyB0aGUgZ2VuZXMgd2l0aCB0aGUgZ3JlYXRlc3QgdmFyaWFuY2UgYWNyb3NzIGNlbGxzIHRvIGNhbGN1bGF0ZSB0aGUgUENBIG1hdHJpeC4KCklmIHdlIHdhbnQgdG8gYmUgYSBiaXQgbW9yZSBjYXJlZnVsIGFib3V0IGl0LCB3ZSBjYW4gbW9kZWwgdGhlIHZhcmlhbmNlIGluIGV4cHJlc3Npb24gb2YgZWFjaCBnZW5lIGFzIGEgZnVuY3Rpb24gb2YgdGhlIG1lYW4gZXhwcmVzc2lvbiBmb3IgdGhhdCBnZW5lLgpUaGlzIGlzIHVzZWZ1bCBiZWNhdXNlIHdlIGdlbmVyYWxseSBleHBlY3QgdGhlIHZhcmlhbmNlIHRvIGluY3JlYXNlIGFzIG1lYW4gZXhwcmVzc2lvbiBpbmNyZWFzZXMsIGV2ZW4gaWYgdGhlcmUgaXMgbm8gYmlvbG9naWNhbCBzaWduYWwgaW4gdGhlIGV4cHJlc3Npb24gdmFyaWF0aW9uLgoKV2Ugd2lsbCBkbyB0aGlzIG1vZGVsaW5nIG9mIHZhcmlhbmNlIGJ5IGV4cHJlc3Npb24gd2l0aCB0aGUgYHNjcmFuOjptb2RlbEdlbmVWYXIoKWAgZnVuY3Rpb24sIHNhdmluZyB0aGUgcmVzdWx0cyB0byBhIG5ldyB2YXJpYWJsZS4KCmBgYHtyIG1vZGVsX3ZhcmlhbmNlfQpnZW5lX3ZhcmlhbmNlIDwtIHNjcmFuOjptb2RlbEdlbmVWYXIobm9ybWFsaXplZF9zY2UpCmBgYAoKTm93IGxldCdzIHBsb3QgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGdlbmUgZXhwcmVzc2lvbiBhbmQgdmFyaWFuY2Ugd2Ugd2VyZSBkaXNjdXNzaW5nLgpIZXJlIHdlIHdpbGwgYWxzbyBhZGQgdGhlIGZpdHRpbmcgY3VydmUgdGhhdCBgc2NyYW46Om1vZGVsR2VuZVZhcigpYCBjcmVhdGVkLCB3aGljaCBpcyBzdG9yZWQgYXMgZnVuY3Rpb24gaW4gdGhlICBgJHRyZW5kYCBzbG90IG9mIHRoZSBgZ2VuZV92YXJpYW5jZWAgb2JqZWN0LgpXZSBjYW4gYWRkIGEgZnVuY3Rpb24gbGlrZSB0aGF0IGN1cnZlIHRvIGEgYGdncGxvdGAgd2l0aCBhIGBzdGF0X2Z1bmN0aW9uYCBsYXllci4KCmBgYHtyIHBsb3RfdmFyaWFuY2V9CmdncGxvdChhcy5kYXRhLmZyYW1lKGdlbmVfdmFyaWFuY2UpLCBhZXMoeCA9IG1lYW4sIHkgPSB0b3RhbCkpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC4xKSArCiAgc3RhdF9mdW5jdGlvbihmdW4gPSBtZXRhZGF0YShnZW5lX3ZhcmlhbmNlKSR0cmVuZCwgY29sb3IgPSAiYmx1ZSIpICsKICBsYWJzKAogICAgeCA9ICJNZWFuIGxvZy1leHByZXNzaW9uIiwKICAgIHkgPSAiVmFyaWFuY2UiKSArCiAgdGhlbWVfYncoKQpgYGAKCk5vdyB3ZSBjYW4gdXNlIGBzY3Jhbjo6Z2V0VG9wSFZHcygpYCB0byBzZWxlY3QgdGhlIGdlbmVzIHRoYXQgaGF2ZSB0aGUgbW9zdCBiaW9sb2dpY2FsIHZhcmlhdGlvbiAoYWNjb3JkaW5nIHRvIHRoZSBtb2RlbCkgYW5kIHJlY2FsY3VsYXRlIFBDQSBzY29yZXMgdXNpbmcgb25seSB0aG9zZSBnZW5lcy4KKEluIHByYWN0aWNlLCB3ZSBhcmUgc2VsZWN0aW5nIHRoZSBnZW5lcyB3aXRoIHRoZSBsYXJnZXN0IHJlc2lkdWFsIHZhcmlhdGlvbiBhZnRlciByZW1vdmluZyB0ZWNobmljYWwgdmFyaWF0aW9uIG1vZGVsZWQgYnkgdGhlIG1lYW4vdmFyaWFuY2UgcmVsYXRpb25zaGlwLikKCkhlcmUgd2UgYXJlIHBpY2tpbmcgdGhlIDIwMDAgdG9wIGdlbmVzIHRvIG1hdGNoIHRoZSBudW1iZXIgb2YgZ2VuZXMgZnJvbSBvdXIgZWFybGllciBjYWxjdWxhdGlvbnMuCgpgYGB7ciBnZXRfaGlnaHZhciwgbGl2ZSA9IFRSVUV9CiMgc2VsZWN0IHRoZSBtb3N0IHZhcmlhYmxlIGdlbmVzCmhpZ2h2YXJfZ2VuZXMgPC0gc2NyYW46OmdldFRvcEhWR3MoZ2VuZV92YXJpYW5jZSwgbiA9IDIwMDApCiMgY2FsY3VsYXRlIGEgUENBIG1hdHJpeCB1c2luZyB0aG9zZSBnZW5lcwpub3JtYWxpemVkX3NjZSA8LSBydW5QQ0Eobm9ybWFsaXplZF9zY2UsIHN1YnNldF9yb3cgPSBoaWdodmFyX2dlbmVzKQpgYGAKCk5vdyB3ZSBjYW4gcGxvdCBvdXIgbmV3IFBDQSB2YWx1ZXMgZm9yIGNvbXBhcmlzb24uCllvdSBtaWdodCByZWFsaXplIHRoYXQgb3VyIG9sZCBQQ0EgdmFsdWVzIHdlcmUgcmVwbGFjZWQgd2hlbiB3ZSByYW4gYHJ1blBDQSgpYCBhZ2Fpbiwgc28gd2UgY2FuJ3QgcmVjcmVhdGUgdGhlIGVhcmxpZXIgcGxvdHMgYXQgdGhpcyBzdGFnZSBvZiB0aGUgbm90ZWJvb2suCllvdSB3aWxsIGhhdmUgdG8gc2Nyb2xsIHVwIHRvIHlvdXIgZWFybGllciBwbG90cyB0byBjb21wYXJlLgoKYGBge3IgcGxvdFBDQV9oaWdodmFyLCBsaXZlID0gVFJVRX0KIyBwbG90IHRoZSBuZXcgUENBIHJlc3VsdHMKcGxvdFJlZHVjZWREaW0obm9ybWFsaXplZF9zY2UsICJQQ0EiKQpwbG90UmVkdWNlZERpbShub3JtYWxpemVkX3NjZSwgIlBDQSIsIG5jb21wb25lbnRzID0gYygzLDQpKQpgYGAKCiMjIyBVTUFQCgoqKlVNQVAqKiAoVW5pZm9ybSBNYW5pZm9sZCBBcHByb3hpbWF0aW9uIGFuZCBQcm9qZWN0aW9uKSBpcyBhIG1hY2hpbmUgbGVhcm5pbmcgdGVjaG5pcXVlIGRlc2lnbmVkIHRvIHByb3ZpZGUgbW9yZSBkZXRhaWwgaW4gaGlnaGx5IGRpbWVuc2lvbmFsIGRhdGEgdGhhbiBhIHR5cGljYWwgcHJpbmNpcGFsIGNvbXBvbmVudHMgYW5hbHlzaXMuCldoaWxlIFBDQSBhc3N1bWVzIHRoYXQgdGhlIHZhcmlhdGlvbiB3ZSBjYXJlIGFib3V0IGhhcyBhIHBhcnRpY3VsYXIgZGlzdHJpYnV0aW9uIChub3JtYWwsIGJyb2FkbHkgc3BlYWtpbmcpLCBVTUFQIGFsbG93cyBtb3JlIGNvbXBsaWNhdGVkIGRpc3RyaWJ1dGlvbnMgdGhhdCBpdCBsZWFybnMgZnJvbSB0aGUgZGF0YS4KVGhlIHVuZGVybHlpbmcgbWF0aGVtYXRpY3MgYXJlIGJleW9uZCBtZSwgYnV0IGlmIHlvdSBhcmUgbW9yZSBhbWJpdGlvdXMgdGhhbiBJLCB5b3UgY2FuIGxvb2sgYXQgdGhlIHBhcGVyIGJ5IFtNY0lubmVzLCBIZWFseSwgJiBNZWx2aWxsZSAoMjAxOCldKGh0dHBzOi8vYXJ4aXYub3JnL2Ficy8xODAyLjAzNDI2KS4KVGhlIG1haW4gYWR2YW50YWdlIG9mIHRoaXMgY2hhbmdlIGluIHVuZGVybHlpbmcgYXNzdW1wdGlvbnMgaXMgdGhhdCBVTUFQIGNhbiBkbyBhIGJldHRlciBqb2Igc2VwYXJhdGluZyBjbHVzdGVycywgZXNwZWNpYWxseSB3aGVuIHNvbWUgb2YgdGhvc2UgY2x1c3RlcnMgbWF5IGJlIG1vcmUgc2ltaWxhciB0byBlYWNoIG90aGVyIHRoYW4gb3RoZXJzLgoKQW5vdGhlciBkaW1lbnNpb25hbGl0eSByZWR1Y3Rpb24gdGVjaG5pcXVlIHRoYXQgeW91IG1heSBoYXZlIGhlYXJkIG9mIGlzICoqdC1TTkUqKiAodC1kaXN0cmlidXRlZCBTdG9jaGFzdGljIE5laWdoYm9yIEVtYmVkZGluZyksIHdoaWNoIGhhcyBzaW1pbGFyIHByb3BlcnRpZXMgdG8gVU1BUCwgYW5kIG9mdGVuIHByb2R1Y2VzIHNpbWlsYXIgcmVzdWx0cy4KVGhlcmUgaXMgc29tZSBvbmdvaW5nIGRlYmF0ZSBhYm91dCB3aGljaCBvZiB0aGVzZSB0d28gdGVjaG5pcXVlcyBpcyBzdXBlcmlvciwgYW5kIHdoZXRoZXIgdGhlIGRpZmZlcmVuY2VzIGFyZSBkdWUgdG8gdGhlIHVuZGVybHlpbmcgYWxnb3JpdGhtIG9yIHRvIGltcGxlbWVudGF0aW9uIGFuZCBwYXJhbWV0ZXIgaW5pdGlhbGl6YXRpb24gZGVmYXVsdHMuClJlZ2FyZGxlc3Mgb2Ygd2h5LCBpbiBvdXIgZXhwZXJpZW5jZSwgVU1BUCBzZWVtcyB0byBwcm9kdWNlIHNsaWdodGx5IGJldHRlciByZXN1bHRzIGFuZCBydW4gYSBiaXQgZmFzdGVyLCBidXQgdGhlIGRpZmZlcmVuY2VzIGNhbiBiZSBzdWJ0bGUuCgojIyMjIERlZmF1bHQgcGFyYW1ldGVycwoKRm9yIGVhc2Ugb2YgdXNlIHdpdGggdGhpcyBkYXRhLCB3ZSB3aWxsIGJlIHVzaW5nIHRoZSBgc2NhdGVyOjpjYWxjdWxhdGVVTUFQKClgIGFuZCBgc2NhdGVyOjpydW5VTUFQKClgIGZ1bmN0aW9uIHRvIGFwcGx5IFVNQVAgdG8gb3VyIHNpbmdsZSBjZWxsIGRhdGEsIGJ1dCBzaW1pbGFyIGZ1bmN0aW9ucyB0aGUgYHV3b3RgIHBhY2thZ2UgKG5vdGFibHkgYHV3b3Q6OnVtYXAoKWApIGNhbiBiZSB1c2VkIHRvIGFwcGx5IFVNQVAgdG8gYW55IG51bWVyaWNhbCBtYXRyaXguCgpVTUFQIGNhbiBiZSBzbG93IGZvciBhIGxhcmdlIGRhdGEgc2V0IHdpdGggbG90cyBvZiBwYXJhbWV0ZXJzLgpJdCBpcyB3b3J0aCBub3RpbmcgdGhhdCB0aGUgYHNjYXRlcjo6Y2FsY3VsYXRlVU1BUCgpYCBpbXBsZW1lbnRhdGlvbiBhY3R1YWxseSBkb2VzIFBDQSBmaXJzdCwgYW5kIHRoZW4gcnVucyBVTUFQIG9uIHRoZSB0b3AgNTAgUENzLgpJZiB3ZSBoYXZlIGFscmVhZHkgY2FsY3VsYXRlZCBQQ0EgKGFzIHdlIGhhdmUpIHdlIGNhbiB0ZWxsIGl0IHRvIHVzZSB0aG9zZSByZXN1bHRzIHdpdGggdGhlIGBkaW1yZWRgIGFyZ3VtZW50LgoKQXMgd2l0aCBQQ0EsIHRoZXJlIGFyZSB0d28gZnVuY3Rpb25zIHdlIGNvdWxkIHVzZToKYHNjYXRlcjo6Y2FsY3VsYXRlVU1BUCgpYCB3aWxsIHJldHVybiBhIG1hdHJpeCBvZiByZXN1bHRzLCB3aXRoIG9uZSByb3cgZm9yIGVhY2ggc2FtcGxlLCBhbmQgYSBjb2x1bW4gZm9yIGVhY2ggb2YgdGhlIFVNQVAgZGltZW5zaW9ucyByZXR1cm5lZC4KYHNjYXRlcjo6cnVuVU1BUCgpYCBwZXJmb3JtcyB0aGUgc2FtZSBmdW5jdGlvbiwgYnV0IHJldHVybnMgdGhlIHJlc3VsdHMgaW4gYSBTaW5nbGVDZWxsRXhwZXJpbWVudCBvYmplY3QuCgpMZXQncyBzZWUgaG93IGl0IGxvb2tzIHdpdGggdGhlIChtb3N0bHkpIGRlZmF1bHQgcGFyYW1ldGVyczoKCmBgYHtyIGNhbGN1bGF0ZV91bWFwLCBsaXZlID0gVFJVRX0KIyBSdW4gVU1BUApub3JtYWxpemVkX3NjZSA8LSBydW5VTUFQKG5vcm1hbGl6ZWRfc2NlLAogICAgICAgICAgICAgICAgICAgICAgICAgIGRpbXJlZCA9ICJQQ0EiKSAjIHVzZSBhbHJlYWR5IHN0b3JlZCBQQ0EgcmVzdWx0cwpgYGAKCk5vdyB3ZSBjYW4gcGxvdCB3aXRoIHRoZSBzYW1lIGBwbG90UmVkdWNlZERpbSgpYCBmdW5jdGlvbiwgc3BlY2lmeWluZyB3ZSB3YW50IHRvIHBsb3QgdGhlIFVNQVAgcmVzdWx0cyB0aGlzIHRpbWUuCldlIHdpbGwgYWxzbyBhZGQgc29tZSBjb2xvciB0aGlzIHRpbWUgd2l0aCB0aGUgYGNvbG9yX2J5YCBhcmd1bWVudCwgdXNpbmcgdGhlIG51bWJlciBvZiBnZW5lcyBkZXRlY3RlZCBpbiBlYWNoIGNlbGwgdG8gYXNzaWduIGEgaHVlLgoKYGBge3IgcGxvdF91bWFwLCBsaXZlID0gVFJVRX0KIyBtYWtlIGEgVU1BUCBwbG90IHdpdGggYHBsb3RSZWR1Y2VkRGltKClgCnBsb3RSZWR1Y2VkRGltKG5vcm1hbGl6ZWRfc2NlLCAiVU1BUCIsIGNvbG9yX2J5ID0gImRldGVjdGVkIikKYGBgCgpUaGVyZSBpcyBjbGVhcmx5IGEgbG90IG9mIHN0cnVjdHVyZSBpbiB0aGVyZSwgYnV0IGlzIGl0IG1lYW5pbmdmdWw/CkRvIHRoZSBjbHVzdGVycyB3ZSBzZWUgZGlmZmVyZW50aWF0ZSBjZWxsIHR5cGVzPyBIb3cgc2hvdWxkIHdlIGRpdmlkZSB0aGVtIHVwPwoKV2Ugd2lsbCBjb21lIGJhY2sgdG8gdGhpcyBxdWVzdGlvbiBsYXRlciEKCiMjIyBVTUFQIGV4cGVyaW1lbnRzCgpOb3cgdGhhdCB3ZSBoYXZlIGFuIGlkZWEgb2Ygd2hhdCBhIFVNQVAgcGxvdCB3aXRoIHRoZSBkZWZhdWx0IHBhcmFtZXRlcnMgbG9va3MgbGlrZSwgbGV0J3MgdHJ5IGV4cGVyaW1lbnRpbmcgd2l0aCB0aGUgYG5fbmVpZ2hib3JzYCBwYXJhbWV0ZXIuCkZpcnN0LCB3ZSBzaG91bGQgc2VlIHdoYXQgdGhpcyBwYXJhbWV0ZXIgaXMsIGFuZCB3aGF0IHRoZSBkZWZhdWx0IHZhbHVlIGlzLgpJbiB0aGUgY29uc29sZSwgcnVuIGA/c2NhdGVyOjpjYWxjdWxhdGVVTUFQYCB0byBzZWUgd2hhdCB0aGlzIChhbmQgb3RoZXIgcGFyYW1ldGVycykgYXJlLgpGb3IgZXZlbiBtb3JlIHBhcmFtZXRlcnMsIHlvdSBjYW4gbG9vayBhdCB0aGUgdW5kZXJseWluZyBpbXBsZW1lbnRhdGlvbiBjb2RlIHRoYXQgYGNhbGN1bGF0ZVVNQVAoKWAgdXNlcywgd2hpY2ggaXMgdGhlIGZ1bmN0aW9uIGB1d290Ojp1bWFwKClgCgpJbiBvcmRlciB0byBtYWtlIG91ciBleHBlcmltZW50YXRpb24gZWFzaWVyLCB3ZSB3aWxsIGNyZWF0ZSBhICpmdW5jdGlvbiogdGhhdCBhbGxvd3MgdXMgdG8gcmVydW4gdGhlIHNhbWUgY29kZSBlYXNpbHksIGJ1dCBjcmVhdGUgYW4gYXJndW1lbnQgdGhhdCBhbGxvd3MgdXMgdG8gY2hhbmdlIG9uZSB2YXJpYWJsZTogdGhlIGBuX25laWdoYm9yc2AgdmFyaWFibGUuCkhlcmUgd2UgYXJlIHNhdmluZyBvbmx5IGEgbGluZSBvZiBjb2RlLCBidXQgd2UgY291bGQgYXBwbHkgdGhpcyB0byBhIG11Y2ggbW9yZSBjb21wbGV4IHNlcmllcyBvZiBvcGVyYXRpb25zIGlmIHdlIHdhbnRlZCB0byEKCmBgYHtyIFVNQVAtZnVuY3Rpb259ClVNQVBfcGxvdF93cmFwcGVyIDwtIGZ1bmN0aW9uKHNjZSA9IG5vcm1hbGl6ZWRfc2NlLCBubl9wYXJhbSA9IDE1KSB7CiAgIyBQdXJwb3NlOiBSdW4gVU1BUCBhbmQgcGxvdCB0aGUgb3V0cHV0CiAgIyBBcmdzOiBubl9wYXJhbTogYSBzaW5nbGUgbnVtZXJpYyBhcmd1bWVudCB0aGF0IHdpbGwgY2hhbmdlIHRoZQogICMgICAgICAgICAgICAgICAgIG5fbmVpZ2hib3JzIHZhcmlhYmxlIGluIHRoZSBjYWxjdWxhdGVVTUFQKCkgZnVuY3Rpb24uCiAgIyBPdXRwdXQ6IGEgc2NhdHRlcnBsb3Qgd2l0aCB0aGUgdHdvIFVNQVAgY29vcmRpbmF0ZXMgcGxvdHRlZCBhbmQKICAjICAgICAgICAgY2VsbC10eXBlcyBsYWJlbGVkIHdpdGggZGF0YSBwb2ludCBjb2xvcnMuCgogICMgUnVuIFVNQVAgd2l0aCBhIHNwZWNpZmllZCBuX25laWdoYm9ycyBwYXJhbWV0ZXIKICBzY2VfdW1hcCA8LSBzY2F0ZXI6OnJ1blVNQVAoc2NlLCBkaW1yZWQgPSAiUENBIiwgbl9uZWlnaGJvcnMgPSBubl9wYXJhbSkKICBzY2F0ZXI6OnBsb3RSZWR1Y2VkRGltKHNjZV91bWFwLCAiVU1BUCIsIGNvbG9yX2J5ID0gImRldGVjdGVkIikgKwogICAgIyBtYWtlIHRoZSBsZWdlbmQgbGFiZWwgbW9yZSBpbmZvcm1hdGl2ZSAodGhpcyBpcyBnZ3Bsb3QyIGNvZGUhKQogICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfY29sb3JiYXIodGl0bGU9ImdlbmVzXG5leHByZXNzZWQiKSkKfQpgYGAKCkxldCdzIG1ha2Ugc3VyZSB0aGF0IHdvcmtzIGFuZCBnaXZlcyB0aGUgc2FtZSByZXN1bHQgYXMgYmVmb3JlIHdoZW4gd2UgdXNlIHRoZSBkZWZhdWx0IHBhcmFtZXRlcnMuCgpgYGB7ciBmdW5jdGlvbi10ZXN0fQpVTUFQX3Bsb3Rfd3JhcHBlcihubl9wYXJhbSA9IDE1KQpgYGAKCipLaW5kIG9mPyoKClRoaXMgaXNuJ3QgeW91ciBmYXVsdCEKVU1BUCBpcyBhIG5vbi1kZXRlcm1pbmlzdGljIGZ1bmN0aW9uLCB3aGljaCBtZWFucyB0aGF0IHRoZXJlIGlzIGEgcmFuZG9tIGNvbXBvbmVudCB0byB0aGUgcmVzdWx0cy4KV2UgY2FuIHVzZSBgc2V0LnNlZWQoKWAgdG8gYmUgc3VyZSB0aGF0IGFuIGluZGl2aWR1YWwgcnVuIChvciBzZXQgb2YgcnVucykgaXMgdGhlIHNhbWUgZXZlcnkgdGltZSB5b3UgcnVuIHlvdXIgYW5hbHlzaXMsIGJ1dCBpdCBpcyBpbXBvcnRhbnQgdG8gY2hlY2sgeW91ciByZXN1bHRzIGEgZmV3IHRpbWVzIHdpdGggZGlmZmVyZW50IHJhbmRvbSBzdGFydGluZyBwb2ludHMgdG8gYmUgc3VyZSB0aGF0IHRoZSByYW5kb20gY29tcG9uZW50IGlzIG5vdCBnaXZpbmcgeW91IGFub21hbG91cyByZXN1bHRzLgpTZXR0aW5nIGEgZGlmZmVyZW50IHJhbmRvbSBudW1iZXIgc2VlZCB3aXRoIGBzZXQuc2VlZCgpYCBpcyBvbmUgd2F5IHRvIGRvIHRoaXMsIG9yIHlvdSBjYW4gcnVuIHRoZSBhbmFseXNpcyBtdWx0aXBsZSB0aW1lcyBpbiB0aGUgc2FtZSBzZXNzaW9uLCBhcyB3ZSBoYXZlIGRvbmUgaGVyZS4KCkZpbGwgaW4gdGhlIG5leHQgZmV3IGNvZGUgY2h1bmtzIHdpdGggdGhlIGZ1bmN0aW9uIGFuZCB0aGUgYG5fbmVpZ2hib3JzYCBhcmd1bWVudCB5b3Ugd291bGQgbGlrZSB0byB1c2UgZm9yIGVhY2guCihGZWVsIGZyZWUgdG8gYWRkIG1vcmUgdGVzdHMhKQpUaGVuIHJ1biB0aGUgY2h1bmtzIGFuZCBjb21wYXJlIHlvdXIgb3V0cHV0IGdyYXBocy4KCmBgYHtyIHJ1bi1VTUFQLTEsIGxpdmUgPSBUUlVFfQojIFRyeSBzb21ldGhpbmcgbG93PwpVTUFQX3Bsb3Rfd3JhcHBlcihubl9wYXJhbSA9IDMpCmBgYAoKYGBge3IgcnVuLVVNQVAtMiwgbGl2ZSA9IFRSVUV9CiMgVHJ5IHNvbWV0aGluZyBoaWdoPwpVTUFQX3Bsb3Rfd3JhcHBlcihubl9wYXJhbSA9IDEwMCkKYGBgCgpgYGB7ciBydW4tVU1BUC0zLCBsaXZlID0gVFJVRX0KIyBUcnkgd2hhdGV2ZXIgeW91IGxpa2UhClVNQVBfcGxvdF93cmFwcGVyKG5uX3BhcmFtID0gNSkKYGBgCgojIyMjIFNvbWUgJ2JpZyBwaWN0dXJlJyB0aG91Z2h0cyB0byB0YWtlIGZyb20gdGhpcyBleHBlcmltZW50OgoKMS4gQW5hbHlzZXMgc3VjaCBhcyBVTUFQIGhhdmUgdmFyaW91cyBsaW1pdGF0aW9ucyBmb3IgaW50ZXJwcmV0YWJpbGl0eS4KVGhlIGNvb3JkaW5hdGVzIG9mIFVNQVAgb3V0cHV0IGZvciBhbnkgZ2l2ZW4gY2VsbCBjYW4gY2hhbmdlIGRyYW1hdGljYWxseSBkZXBlbmRpbmcgb24gcGFyYW1ldGVycywgYW5kIGV2ZW4gcnVuIHRvIHJ1biB3aXRoIHRoZSBzYW1lIHBhcmFtZXRlcnMuClRoaXMgcHJvYmFibHkgbWVhbnMgdGhhdCB5b3Ugc2hvdWxkbid0IHJlbHkgb24gdGhlIGV4YWN0IHZhbHVlcyBvZiBVTUFQJ3Mgb3V0cHV0LgoKICAgIC0gT25lIHBhcnRpY3VsYXIgbGltaXRhdGlvbiBvZiBVTUFQIChhbmQgdC1TTkUpIGlzIHRoYXQgd2hpbGUgb2JzZXJ2ZWQgY2x1c3RlcnMgaGF2ZSBzb21lIG1lYW5pbmcsIHRoZSBkaXN0YW5jZSAqYmV0d2VlbiogY2x1c3RlcnMgdXN1YWxseSBkb2VzIG5vdCAobm9yIGRvZXMgY2x1c3RlciBkZW5zaXR5KS4KICAgIFRoZSBmYWN0IHRoYXQgdHdvIGNsdXN0ZXJzIGFyZSBuZWFyIGVhY2ggb3RoZXIgc2hvdWxkIE5PVCBiZSBpbnRlcnByZXRlZCB0byBtZWFuIHRoYXQgdGhleSBhcmUgbW9yZSByZWxhdGVkIHRvIGVhY2ggb3RoZXIgdGhhbiB0byBtb3JlIGRpc3RhbnQgY2x1c3RlcnMuCiAgICAoVGhlcmUgaXMgc29tZSBkaXNhZ3JlZW1lbnQgYWJvdXQgd2hldGhlciBVTUFQIGRpc3RhbmNlcyBoYXZlIG1vcmUgbWVhbmluZywgYnV0IGl0IGlzIHByb2JhYmx5IHNhZmVyIHRvIGFzc3VtZSB0aGV5IGRvbid0LikKCgoyLiBQbGF5aW5nIHdpdGggcGFyYW1ldGVycyBzbyB5b3UgY2FuIGZpbmUtdHVuZSB0aGVtIGlzIGEgZ29vZCB3YXkgdG8gZ2l2ZSB5b3UgbW9yZSBpbmZvcm1hdGlvbiBhYm91dCBhIHBhcnRpY3VsYXIgYW5hbHlzaXMgYXMgd2VsbCBhcyB0aGUgZGF0YSBpdHNlbGYuCgozLiBXaGVyZSByZXN1bHRzIGFyZSBjb25zaXN0ZW50LCB0aGV5IGFyZSBtb3JlIGxpa2VseSB0byBoYXZlIG1lYW5pbmcuCldoaWxlIHdlIGRvIG5vdCBoYXZlIGxhYmVsZWQgY2VsbCB0eXBlcyBpbiB0aGlzIGNhc2UsIHRoZXJlIGRvZXMgc2VlbSB0byBiZSBzb21lIGNvbnNpc3RlbmN5IG9mIHRoZSBvdmVyYWxsIHBhdHRlcm5zIHRoYXQgd2Ugc2VlIChpZiBub3QgcHJlY2lzZSB2YWx1ZXMpLCBhbmQgdGhpcyBsaWtlbHkgcmVmbGVjdHMgYmlvbG9naWNhbCBpbmZvcm1hdGlvbiAob3IgdGVjaG5pY2FsIGFydGlmYWN0cykuCgpJbiBzdW1tYXJ5LCBpZiB0aGUgcmVzdWx0cyBvZiBhbiBhbmFseXNpcyBjYW4gYmUgY29tcGxldGVseSBjaGFuZ2VkIGJ5IGNoYW5naW5nIGl0cyBwYXJhbWV0ZXJzLCB5b3Ugc2hvdWxkIGJlIG1vcmUgY2F1dGlvdXMgd2hlbiBpdCBjb21lcyB0byB0aGUgY29uY2x1c2lvbnMgeW91IGRyYXcgZnJvbSBpdCBhcyB3ZWxsIGFzIGhhdmluZyBnb29kIHJhdGlvbmFsZSBmb3IgdGhlIHBhcmFtZXRlcnMgeW91IGNob29zZS4KCiMjIyB0LVNORSBjb21wYXJpc29uCgpJbiB0aGUgYmxvY2sgYmVsb3cgaXMgYSBzaW1pbGFyIGFuYWx5c2lzIGFuZCBwbG90IHdpdGggdC1TTkUgKHQtZGlzdHJpYnV0ZWQgU3RvY2hhc3RpYyBOZWlnaGJvciBFbWJlZGRpbmcpLgpOb3RlIHRoYXQgdGhpcyBhbmFseXNpcyBhbHNvIHVzZXMgUENBIGJlZm9yZSBtb3Zpbmcgb24gdG8gdGhlIGZhbmN5IG1hY2hpbmUgbGVhcm5pbmcuCgpgYGB7ciB0c25lLCBsaXZlID0gVFJVRX0KIyBSdW4gVFNORQpub3JtYWxpemVkX3NjZSA8LSBydW5UU05FKG5vcm1hbGl6ZWRfc2NlLCBkaW1yZWQgPSAiUENBIikKCiMgcGxvdCB3aXRoIHNjYXRlciBmdW5jdGlvbgpwbG90UmVkdWNlZERpbShub3JtYWxpemVkX3NjZSwgIlRTTkUiLCBjb2xvcl9ieSA9ICJkZXRlY3RlZCIpCmBgYAoKRGlmZmVyZW50ISAoU2xvd2VyISkgSXMgaXQgYmV0dGVyIG9yIHdvcnNlPyBIYXJkIHRvIHNheSEKRGlmZmVyZW50IHBlb3BsZSBsaWtlIGRpZmZlcmVudCB0aGluZ3MsIGFuZCBvbmUgcGxvdCBtaWdodCBpbGx1c3RyYXRlIGEgcGFydGljdWxhciBwb2ludCBiZXR0ZXIgdGhhbiBhbm90aGVyLgoKIyMgU2F2ZSByZXN1bHRzCgpXZSBhcmUgZ29pbmcgdG8gdXNlIHRoaXMgZGF0YSBtb3JlIGluIHRoZSBuZXh0IG5vdGVib29rLCBzbyBsZXQncyBzYXZlIGl0IGFzIGFuIGBSRFNgIGZpbGUuCgpgYGB7ciBzYXZlfQpyZWFkcjo6d3JpdGVfcmRzKG5vcm1hbGl6ZWRfc2NlLCBmaWxlID0gb3V0cHV0X3NjZV9maWxlKQpgYGAKCgojIyMgU29tZSBmdXJ0aGVyIHJlYWRpbmcgb24gZGltZW5zaW9uIHJlZHVjdGlvbjoKCi0gVGhpcyB3ZWJzaXRlIGV4cGxhaW5zIFtQQ0EgdmlzdWFsbHldKGh0dHA6Ly9zZXRvc2EuaW8vZXYvcHJpbmNpcGFsLWNvbXBvbmVudC1hbmFseXNpcy8pLgotIFtCZWNodCAqZXQgYWwuKiAoMjAxOCldKGh0dHBzOi8vd3d3Lm5hdHVyZS5jb20vYXJ0aWNsZXMvbmJ0LjQzMTQpIGRpc2N1c3NlcyB1c2luZyBbVU1BUF0oaHR0cHM6Ly9naXRodWIuY29tL2xtY2lubmVzL3VtYXApIGZvciBzaW5nbGUtY2VsbCBkYXRhLgotIFtXYXR0ZW5iZXJnICpldCBhbC4qICgyMDE2KV0oaHR0cHM6Ly9kaXN0aWxsLnB1Yi8yMDE2L21pc3JlYWQtdHNuZS8pIGRpc2N1c3MgaG93IHRvIHVzZSB0LVNORSBwcm9wZXJseSB3aXRoIGdyZWF0IHZpc3VhbHMuCihUaGUgbGVzc29ucyBhcHBseSB0byBVTUFQIGFzIHdlbGwsIHdpdGggYSBicm9hZCBzdWJzdGl0dXRpb24gb2YgdGhlIGBuX25laWdoYm9yc2AgcGFyYW1ldGVyIGZvciBgcGVycGxleGl0eWAuKQotIFtOZ3V5ZW4gJiBIb2xtZXMgKDIwMTkpXShodHRwczovL2pvdXJuYWxzLnBsb3Mub3JnL3Bsb3Njb21wYmlvbC9hcnRpY2xlP2lkPTEwLjEzNzEvam91cm5hbC5wY2JpLjEwMDY5MDcpIGxheSBvdXQgZ3VpZGVsaW5lcyBvbiBjaG9vc2luZyBkaW1lbnNpb25zIHJlZHVjdGlvbiBtZXRob2RzLgotIFtGcmVpdGFnICgyMDE5KV0oaHR0cHM6Ly9ycHVicy5jb20vU2Fza2lhLzUyMDIxNikgaXMgYSBuaWNlIGV4cGxhbmF0aW9uIGFuZCBjb21wYXJpc29uIG9mIG1hbnkgZGlmZmVyZW50IGRpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbiB0ZWNobmlxdWVzIHRoYXQgeW91IG1heSBlbmNvdW50ZXIuCgoKIyMgU2Vzc2lvbiBJbmZvCgpgYGB7ciBzZXNzaW9ufQpzZXNzaW9uSW5mbygpCmBgYAo=
+
LS0tCnRpdGxlOiAiRGltZW5zaW9uIFJlZHVjdGlvbiB3aXRoIHNjUk5BLXNlcSBkYXRhIgphdXRob3I6IENDREwgZm9yIEFMU0YKZGF0ZTogMjAyMQpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCi0tLQoKIyMgT2JqZWN0aXZlcwoKVGhpcyBub3RlYm9vayB3aWxsIGRlbW9uc3RyYXRlIGhvdyB0bzoKCi0gUmVhZCBDZWxsIFJhbmdlciBkYXRhIGludG8gUgotIEZpbHRlciBwb3N0LXF1YW50aWZpY2F0aW9uIGNlbGxzIHVzaW5nIGBlbXB0eURyb3BzQ2VsbFJhbmdlcigpYAotIEFwcGx5IGRpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbiBtZXRob2RzIHRvIHNpbmdsZSBjZWxsIGRhdGEKLSBWaXN1YWxpemUgc2FtcGxlcyBpbiByZWR1Y2VkIGRpbWVuc2lvbmFsIHNwYWNlCgotLS0KCkluIHRoaXMgbm90ZWJvb2ssIHdlJ2xsIHRyeSBvdXQgc29tZSBkaW1lbnNpb24gcmVkdWN0aW9uIHRlY2huaXF1ZXMgb24gc2luZ2xlLWNlbGwgUk5BLXNlcSBkYXRhLgoKVmlzdWFsaXppbmcgaGlnaGx5IGRpbWVuc2lvbmFsIGRhdGEgaXMgYSBjb21tb24gY2hhbGxlbmdlIGluIGdlbm9taWNzLCBhbmQgZXNwZWNpYWxseSB3aXRoIFJOQS1zZXEgZGF0YS4KVGhlIGV4cHJlc3Npb24gb2YgZXZlcnkgZ2VuZSB3ZSBsb29rIGF0IGlzIGFub3RoZXIgZGltZW5zaW9uIGRlc2NyaWJpbmcgYSBzYW1wbGUuCldoZW4gd2UgYWxzbyBoYXZlIGh1bmRyZWRzIG9yIHRob3VzYW5kcyBvZiBpbmRpdmlkdWFsIHNhbXBsZXMsIGFzIGluIHRoZSBjYXNlIG9mIHNpbmdsZS1jZWxsIGFuYWx5c2lzLCBmaWd1cmluZyBvdXQgaG93IHRvIGNsZWFybHkgZGlzcGxheSBhbGwgb2YgdGhlIGRhdGEgaW4gYSBtZWFuaW5nZnVsIHdheSBpcyBkaWZmaWN1bHQuCgpBIGNvbW1vbiBwcmFjdGljZSBpcyB0byBjb21tb24gdG8gdXNlIGRpbWVuc2lvbiByZWR1Y3Rpb24gdGVjaG5pcXVlcyBzbyBhbGwgb2YgdGhlIGRhdGEgaXMgaW4gYSBtb3JlIG1hbmFnZWFibGUgZm9ybSBmb3IgcGxvdHRpbmcsIGNsdXN0ZXJpbmcsIGFuZCBvdGhlciBkb3duc3RyZWFtIGFuYWx5c2VzLgoKIyMgU2V0IFVwCgpgYGB7ciBzZXR1cH0KIyBMb2FkIGxpYnJhcmllcwpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoc2NhdGVyKQpsaWJyYXJ5KHNjcmFuKQoKIyBTZXR0aW5nIHRoZSBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkKc2V0LnNlZWQoMTIzNDUpCmBgYAoKIyMjIERpcmVjdG9yaWVzIGFuZCBmaWxlcwoKVGhlIGRhdGEgd2Ugd2lsbCBiZSB1c2luZyBmb3IgdGhpcyBtb2R1bGUgY29tZXMgZnJvbSBhIGEgMTB4IEdlbm9taWNzIGRhdGEgc2V0IG9mIFtleHByZXNzaW9uIGRhdGEgZnJvbSBhIEhvZGdraW4ncyBMeW1waG9tYSB0dW1vcl0oaHR0cHM6Ly9zdXBwb3J0LjEweGdlbm9taWNzLmNvbS9zaW5nbGUtY2VsbC1nZW5lLWV4cHJlc3Npb24vZGF0YXNldHMvNC4wLjAvUGFyZW50X05HU0MzX0RJX0hvZGdraW5zTHltcGhvbWEpLgpUaGUgZGF0YSB3YXMgZ2VuZXJhdGVkIHdpdGggdGhlIDEwWHYzLjEgY2hlbWlzdHJ5LCBhbmQgcHJvY2Vzc2VkIHdpdGggQ2VsbCBSYW5nZXIgYW5kIDEweCBHZW5vbWljcyBzdGFuZGFyZCBwaXBlbGluZS4KCgpUaGVyZSBhcmUgYSB2YXJpZXR5IG9mIGZpbGVzIHRoYXQgeW91IHdpbGwgb2Z0ZW4gc2VlIGFzIHBhcnQgb2YgdGhlIHN0YW5kYXJkIG91dHB1dCBmcm9tIENlbGwgUmFuZ2VyLCB3aGljaCBhcmUgZGVzY3JpYmVkIGluIGRldGFpbCBpbiBbMTB4IEdlbm9taWNzIGRvY3VtZW50YXRpb25dKGh0dHBzOi8vc3VwcG9ydC4xMHhnZW5vbWljcy5jb20vc2luZ2xlLWNlbGwtZ2VuZS1leHByZXNzaW9uL3NvZnR3YXJlL3BpcGVsaW5lcy9sYXRlc3Qvb3V0cHV0L292ZXJ2aWV3KS4KV2UgaGF2ZSBpbmNsdWRlZCBzb21lIG9mIHRoZXNlIGluIHRoZSBgZGF0YS9ob2RraW5zL2NlbGxyYW5nZXJgIGRpcmVjdG9yeSwgaW5jbHVkaW5nIHRoZSBgd2ViX3N1bW1hcnkuaHRtbGAgZmlsZSB0aGF0IGluY2x1ZGVzIHNvbWUgc2ltaWxhciBRQyBzdGF0aXN0aWNzIHRvIHRob3NlIHdlIGdlbmVyYXRlZCB3aXRoIGBhbGV2aW5RQ2AuClRoZSBtYWluIGZpbGUgd2Ugd2lsbCBiZSB3b3JraW5nIHdpdGggYXJlIHRoZSBmZWF0dXJlIGJ5IGJhcmNvZGUgbWF0cmljZXMuCkNlbGwgUmFuZ2VyIGRvZXMgc29tZSBmaWx0ZXJpbmcgb24gaXRzIG93biwgYnV0IHdlIHdpbGwgc3RhcnQgd2l0aCB0aGUgcmF3IGRhdGEuCgpgYGB7ciBmaWxlcGF0aHN9CiMgbWFpbiBkYXRhIGRpcmVjdG9yeQpkYXRhX2RpciA8LSBmaWxlLnBhdGgoImRhdGEiLCAiaG9kZ2tpbnMiKQojIHJlZmVyZW5jZSBmaWxlcwpyZWZfZGlyIDwtIGZpbGUucGF0aCgiZGF0YSIsICJyZWZlcmVuY2UiKQoKIyBQYXRoIHRvIHRoZSBDZWxsIFJhbmdlciBtYXRyaXgKcmF3X21hdHJpeF9kaXIgPC0gZmlsZS5wYXRoKGRhdGFfZGlyLCAiY2VsbHJhbmdlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAicmF3X2ZlYXR1cmVfYmNfbWF0cml4IikKCiMgUGF0aCB0byBtaXRvY2hvbmRyaWFsIGdlbmVzIHRhYmxlCm1pdG9fZmlsZSA8LSBmaWxlLnBhdGgocmVmX2RpciwgImhzX21pdG9jaG9uZHJpYWxfZ2VuZXMudHN2IikKCiMgRGlyZWN0b3J5IGFuZCBmaWxlIHRvIHNhdmUgb3V0cHV0Cm5vcm1hbGl6ZWRfZGlyIDwtIGZpbGUucGF0aChkYXRhX2RpciwgIm5vcm1hbGl6ZWQiKQpmczo6ZGlyX2NyZWF0ZShub3JtYWxpemVkX2RpcikKCm91dHB1dF9zY2VfZmlsZSA8LSBmaWxlLnBhdGgobm9ybWFsaXplZF9kaXIsICJub3JtYWxpemVkX2hvZGdraW5zX3NjZS5yZHMiKQoKYGBgCgojIyBSZWFkaW5nIENlbGwgUmFuZ2VyIGRhdGEKCkNlbGwgUmFuZ2VyIG91dHB1dCBpbmNsdWRlcyBjb3VudCBkYXRhIGluIHR3byBtYWluIGZvcm1hdHMuClRoZSBmaXJzdCBpcyBhIGZvbGRlciB3aXRoIGEgZmVhdHVyZSBsaXN0LCBhIGJhcmNvZGUgbGlzdCwgYW5kIGEgc3BhcnNlIG1hdHJpeCBpbiBbIk1hdHJpeCBFeGNoYW5nZSIgZm9ybWF0XShodHRwczovL21hdGgubmlzdC5nb3YvTWF0cml4TWFya2V0L2Zvcm1hdHMuaHRtbCkuClRoZSBgRHJvcGxldFV0aWxzOjpyZWFkMTB4Q291bnRzKClgIGZ1bmN0aW9uIHRha2VzIHRoaXMgZGlyZWN0b3J5IGFuZCByZWFkcyBpbiB0aGUgZGF0YSBmcm9tIHRoZXNlIHRocmVlIGZpbGVzLCBhc3NlbWJsaW5nIHRoZSBgU2luZ2xlQ2VsbEV4cGVyaW1lbnRgIG9iamVjdCB3ZSBoYXZlIHdvcmtlZCB3aXRoIGJlZm9yZS4KCkFsdGVybmF0aXZlbHksIHdlIGNvdWxkIHVzZSB0aGUgYEhERjVgIGZvcm1hdCBmaWxlIHRoYXQgQ2VsbCBSYW5nZXIgb3V0cHV0cyBhcyBhIGZpbGUgd2l0aCB0aGUgYC5oNWAgZXh0ZW5zaW9uLCB3aGljaCBjb250YWlucyB0aGUgc2FtZSBkYXRhLgpGb3Igd2hhdGV2ZXIgcmVhc29uLCB0aGUgd2F5IHlvdSByZWFkIHRoZSBkYXRhIGFmZmVjdHMgaG93IGl0IGlzIHN0b3JlZCBpbiBSLgpSZWFkaW5nIGZyb20gdGhlIGRpcmVjdG9yeSByZXN1bHRzIGluIHNtYWxsZXIgb2JqZWN0cyBpbiBSLCBzbyB0aGF0IGlzIHdoYXQgd2Ugd2lsbCBkbyBoZXJlLgoKQ2VsbCBSYW5nZXIgYWxzbyBvdXRwdXRzIGJvdGggZmlsdGVyZWQgYW5kIHJhdyBtYXRyaWNlczsgdG9kYXkgd2Ugd2lsbCBzdGFydCB3aXRoIHRoZSByYXcgbWF0cml4IGFuZCBwZXJmb3JtIG91ciBvd24gZmlsdGVyaW5nLgoKIVtSb2FkbWFwOiBQcmVwcm9jZXNzaW5nIGFuZCBJbXBvcnRdKGRpYWdyYW1zL3JvYWRtYXBfc2luZ2xlX3ByZXByb2Nlc3NfYWxldmluLnBuZykKCmBgYHtyIHJlYWQxMHgsIGxpdmUgPSBUUlVFfQpob2Rna2luc19zY2UgPC0gRHJvcGxldFV0aWxzOjpyZWFkMTB4Q291bnRzKAogIHJhd19tYXRyaXhfZGlyLCAKICBjb2wubmFtZXMgPSBUUlVFICMgZW5zdXJlIGJhcmNvZGVzIGFyZSBzZXQgYXMgY29sdW1uIG5hbWVzIGluIHRoZSBTQ0Ugb2JqZWN0CikKYGBgCgpIb3cgbWFueSBwb3RlbnRpYWwgY2VsbHMgYXJlIHRoZXJlIGhlcmU/CgpgYGB7ciBjZWxsY291bnQsIGxpdmUgPSBUUlVFfQpkaW0oaG9kZ2tpbnNfc2NlKQpgYGAKClRoYXQgaXMgYSBsb3Qgb2YgY2VsbHMhCkluIGZhY3QsIGl0IGlzIHJlYWxseSBldmVyeSBwb3NzaWJsZSBiYXJjb2RlLCB3aGV0aGVyIHRoZXJlIHdlcmUgcmVhZHMgYXNzb2NpYXRlZCB3aXRoIGl0IG9yIG5vdC4KV2Ugc2hvdWxkIHByb2JhYmx5IGRvIHNvbWV0aGluZyBhYm91dCB0aGF0LgoKCiMjIFFDIGFuZCBub3JtYWxpemF0aW9uCgohW1JvYWRtYXA6IFFDIGFuZCBmaWx0ZXJpbmddKGRpYWdyYW1zL3JvYWRtYXBfc2luZ2xlX3FjX25vcm0ucG5nKQoKIyMjIEJhc2ljIFFDIHN0YXRzCgpXZSB3aWxsIHN0YXJ0IGJ5IGNhbGN1bGF0aW5nIHRoZSBiYXNpYyBRQyBzdGF0cyBhcyB3ZSBoYXZlIGRvbmUgcHJldmlvdXNseSwgYWRkaW5nIHRob3NlIHRvIG91ciBgU2luZ2xlQ2VsbEV4cGVyaW1lbnRgIG9iamVjdC4KClRoZSBmaXJzdCBzdGVwIGFnYWluIGlzIHJlYWRpbmcgaW4gb3VyIHRhYmxlIG9mIG1pdG9jaG9uZHJpYWwgZ2VuZXMgYW5kIGZpbmRpbmcgdGhlIG9uZXMgdGhhdCB3ZXJlIHF1YW50aWZpZWQgb3VyIGRhdGEgc2V0LgoKYGBge3IgbWl0b2dlbmVzfQptaXRvX2dlbmVzIDwtIHJlYWRyOjpyZWFkX3RzdihtaXRvX2ZpbGUpIHw+CiAgZHBseXI6OmZpbHRlcihnZW5lX2lkICVpbiUgcm93bmFtZXMoaG9kZ2tpbnNfc2NlKSkgfD4KICBkcGx5cjo6cHVsbChnZW5lX2lkKQpgYGAKCk5leHQgd2Ugd2lsbCBjYWxjdWxhdGUgdGhlIFFDIHN0YXRzIHRoYXQgd2UgdXNlZCBiZWZvcmUuCk5vdGUgdGhhdCB0aGlzIGlzIG11Y2ggc2xvd2VyIHRoYW4gYmVmb3JlLCBhcyB3ZSBoYXZlIG1hbnkgbW9yZSBnZW5lcyBpbiB0aGUgdW5maWx0ZXJlZCBzZXQhCgpgYGB7ciBjYWxjdWxhdGVRQ30KaG9kZ2tpbnNfc2NlIDwtIHNjYXRlcjo6YWRkUGVyQ2VsbFFDKAogIGhvZGdraW5zX3NjZSwKICBzdWJzZXRzID0gbGlzdChtaXRvID0gbWl0b19nZW5lcykpCmBgYAoKV2UgY2FuIG5vdyBkbyB0aGUgbW9zdCBiYXNpYyBsZXZlbCBvZiBmaWx0ZXJpbmc6IGdldHRpbmcgcmlkIG9mICJjZWxscyIgd2l0aCBubyByZWFkcy4KCmBgYHtyIHJlbW92ZV96ZXJvLCBsaXZlID0gVFJVRX0KaG9kZ2tpbnNfc2NlIDwtIGhvZGdraW5zX3NjZVssIGhvZGdraW5zX3NjZSR0b3RhbCA+IDBdCmRpbShob2Rna2luc19zY2UpCmBgYAoKIyMjIEZpbHRlcmluZyB3aXRoIGBlbXB0eURyb3BzQ2VsbFJhbmdlcigpYAoKVGhlIGBEcm9wbGV0VXRpbHNgIHBhY2thZ2UgdGhhdCB3ZSB1c2VkIHRvIHJlYWQgaW4gdGhlIDEweCBkYXRhIGhhcyBhIG51bWJlciBvZiBvdGhlciB1c2VmdWwgZmVhdHVyZXMuCk9uZSBpcyB0aGUgYGVtcHR5RHJvcHNDZWxsUmFuZ2VyKClgIGZ1bmN0aW9uLCB3aGljaCB1c2VzIHRoZSBvdmVyYWxsIGdlbmUgZXhwcmVzc2lvbiBwYXR0ZXJucyBpbiB0aGUgc2FtcGxlIHRvIGlkZW50aWZ5IGRyb3BsZXRzIHRoYXQgYXJlIGxpa2VseSB0byBub3QgY29udGFpbiBhbiBpbnRhY3QgY2VsbCwgYnV0IG1heSBzaW1wbHkgaGF2ZSBjb250YWluZWQgbG9vc2UgYW1iaWVudCBSTkEgcmVsZWFzZWQgZHVyaW5nIGNlbGwgc2VwYXJhdGlvbi4KVGhpcyBtZXRob2Qgd2FzIG9yaWdpbmFsbHkgZGV2ZWxvcGVkIGJ5IFtMdW4gKmV0IGFsLiogKDIwMTkpXShodHRwczovL2RvaS5vcmcvMTAuMTE4Ni9zMTMwNTktMDE5LTE2NjIteSkgYW5kIGltcGxlbWVudGVkIGFzIHRoZSBmdW5jdGlvbiBgZW1wdHlEcm9wcygpYCwgYnV0IGhhcyBzaW5jZSBiZWVuIGFkYXB0ZWQgYXMgdGhlIG1haW4gZmlsdGVyaW5nIG1ldGhvZCB1c2VkIGJ5IENlbGwgUmFuZ2VyLiAKVGhlIGBlbXB0eURyb3BzQ2VsbFJhbmdlcigpYCBmdW5jdGlvbiBlbXVsYXRlcyB0aGUgdmFyaWFudCBvZiB0aGlzIGZ1bmN0aW9uIHRoYXQgdXNlZCBieSBDZWxsIFJhbmdlciwgbWFraW5nIHRoZSByZXN1bHRzIG1vcmUgY29tcGFyYWJsZSBiZXR3ZWVuIHRoZSB0d28gbWV0aG9kcy4KClRoZSBFbXB0eSBEcm9wcyBtZXRob2QgdXNlcyB0aGUgZHJvcGxldHMgd2l0aCB2ZXJ5IGxvdyBVTUkgY291bnRzIHRvIGVzdGltYXRlIHRoZSAiYW1iaWVudCIgZXhwcmVzc2lvbiBwYXR0ZXJuIG9mIFJOQSBjb250ZW50IG91dHNpZGUgb2YgY2VsbHMuCkl0IHRoZW4gc2NvcmVzIHRoZSByZW1haW5pbmcgY2VsbHMgYmFzZWQgaG93IG11Y2ggdGhleSBkZXZpYXRlIGZyb20gdGhhdCBwYXR0ZXJuLCBhc3NpZ25pbmcgYSBzbWFsbCBQIHZhbHVlIHdoZW4gdGhlIGRyb3BsZXQncyBleHByZXNzaW9uIGRldmlhdGVzIGZyb20gdGhlIGFtYmllbnQgZXhwcmVzc2lvbiBwYXR0ZXJuLgpCZWNhdXNlIGl0IHVzZXMgdGhlIGxvdyBVTUkgY291bnQgZHJvcGxldHMsIHRoaXMgbWV0aG9kIHNob3VsZCBub3QgYmUgdXNlZCB3aGVuIG90aGVyIGZpbHRlcmluZyBoYXMgYWxyZWFkeSBiZWVuIHBlcmZvcm1lZCAod2hpY2ggaXMgdW5mb3J0dW5hdGVseSB0aGUgY2FzZSB3aXRoIHRoZSB2ZXJzaW9uIG9mIGBzYWxtb24gYWxldmluYCB3ZSB1c2VkKS4KClRoaXMgbWV0aG9kIHNlZW1zIHRvIHBlcmZvcm0gd2VsbCB0byBleGNsdWRlIGZhbHNlICJjZWxscyIgd2hpbGUgcmV0YWluaW5nIGNlbGxzIHdpdGggZGlzdGluY3QgZXhwcmVzc2lvbiBwcm9maWxlcyBidXQgbG93IGNvdW50cyB0aGF0IG1pZ2h0IGhhdmUgZmFpbGVkIGEgc2ltcGxlIGN1dG9mZi4KTm90ZSB0aGF0IHRoaXMgbWV0aG9kIGFsc28gcmVxdWlyZXMgdGhhdCB0aGUgZGF0YSBoYXMgYWxyZWFkeSBiZWVuIHF1YW50aWZpZWQsIHdpdGggcmVhZHMgYXNzaWduZWQgdG8gZ2VuZXMsIGFzIGNvbXBhcmVkIHRvIGEgc2ltcGxlIHRvdGFsIFVNSSBjb3VudCBmaWx0ZXIgd2hpY2ggY2FuIGJlIHBlcmZvcm1lZCBtdWNoIGVhcmxpZXIgaW4gdGhlIHBpcGVsaW5lLgoKVGhlIGBlbXB0eURyb3BzQ2VsbFJhbmdlcigpYCBmdW5jdGlvbiB0YWtlcyB0aGUgYGNvdW50c2AgbWF0cml4IGZyb20gb3VyIFNpbmdsZUNlbGxFeHBlcmltZW50LCBhbmQgcmV0dXJucyBhIGRhdGEgZnJhbWUgd2l0aCB0aGUgc3RhdGlzdGljcyBpdCBjYWxjdWxhdGVzLgpUaGlzIHdpbGwgdGFrZSBhIGZldyBtaW51dGVzIHRvIHJ1biwgYnV0IHdlIGNhbiBzcGVlZCBpdCB1cCBieSBhbGxvd2luZyBwYXJhbGxlbCBwcm9jZXNzaW5nLgoKYGBge3IgZW1wdHlkcm9wcywgbGl2ZSA9IFRSVUV9CmRyb3BsZXRfc3RhdHMgPC0gRHJvcGxldFV0aWxzOjplbXB0eURyb3BzQ2VsbFJhbmdlcigKICBjb3VudHMoaG9kZ2tpbnNfc2NlKSwKICBCUFBBUkFNID0gQmlvY1BhcmFsbGVsOjpNdWx0aWNvcmVQYXJhbSg0KSkgIyB1c2UgbXVsdGlwcm9jZXNzaW5nCmBgYAoKV2Ugd2lsbCB1c2UgYSBmYWxzZSBkaXNjb3ZlcnkgcmF0ZSAoRkRSKSBvZiAwLjAxIGFzIG91ciBjdXRvZmYgZm9yICJyZWFsIiBjZWxscy4KU2luY2UgYGVtcHR5RHJvcHNDZWxsUmFuZ2VyKClgIHVzZXMgbG93IGNvdW50IGNlbGxzIHRvIGVzdGltYXRlIHRoZSAiYW1iaWVudCIgZXhwcmVzc2lvbiBwYXR0ZXJuLCB0aG9zZSBjZWxscyBhcmUgbm90IGFzc2lnbmVkIGFuIEZEUiB2YWx1ZSwgYW5kIGhhdmUgYSB2YWx1ZSBvZiBOQS4KVGhlc2UgTkFzIGNhbiBiZSBhIHByb2JsZW0gZm9yIGZpbHRlcmluZyB3aXRoIGEgQm9vbGVhbiB2ZWN0b3IsIGFzIHdlIGRpZCBhYm92ZSwgc28gaW5zdGVhZCB3ZSB3aWxsIHVzZSB0aGUgYHdoaWNoKClgIGZ1bmN0aW9uIHRvIGdldCB0aGUgKnBvc2l0aW9ucyogb2YgdGhlIGNlbGxzIHRoYXQgcGFzcyBvdXIgZmlsdGVyIGFuZCBzZWxlY3QgdGhlIGNvbHVtbnMgd2Ugd2FudCB1c2luZyB0aGF0LgoKYGBge3IgZmlsdGVyX2VtcHR5LCBsaXZlID0gVFJVRX0KY2VsbHNfdG9fcmV0YWluIDwtIHdoaWNoKGRyb3BsZXRfc3RhdHMkRkRSIDw9IDAuMDEpCgpmaWx0ZXJlZF9zY2UgPC0gaG9kZ2tpbnNfc2NlWywgY2VsbHNfdG9fcmV0YWluXQpkaW0oZmlsdGVyZWRfc2NlKQpgYGAKCkhvdyBkb2VzIHRoaXMgY29tcGFyZSB0byB0aGUgbnVtYmVyIG9mIGNlbGxzIGluIHRoZSBDZWxsIFJhbmdlciBmaWx0ZXJlZCBkYXRhPwpMb29raW5nIHRoZSBgd2ViX3N1bW1hcnkuaHRtbGAgcmVwb3J0IGZyb20gQ2VsbCBSYW5nZXIsIGl0IHNlZW1zIHRoYXQgaXQgd291bGQgaGF2ZSBrZXB0IDMsMzk0IGNlbGxzLCBzbyB3ZSBzZWVtIHRvIGJlIGdldHRpbmcgYnJvYWRseSBzaW1pbGFyIHJlc3VsdHMuCgojIyMgQ2hlY2tpbmcgbWl0b2Nob25kcmlhbCBjb250ZW50CgpXaGlsZSBgZW1wdHlEcm9wc0NlbGxSYW5nZXIoKWAgc2hvdWxkIGhhdmUgZmlsdGVyZWQgb3V0IGRyb3BsZXRzIGNvbnRhaW5pbmcgbm8gY2VsbHMsIGl0IHdpbGwgbm90IG5lY2Vzc2FyaWx5IGZpbHRlciBvdXQgZGFtYWdlZCBjZWxscy4KRm9yIHRoYXQgd2Ugd2lsbCBzdGlsbCB3YW50IHRvIGxvb2sgYXQgbWl0b2Nob25kcmlhbCBjb250ZW50LCBhcyB3ZSBkaWQgcHJldmlvdXNseS4KVGhlIHN0YXRpc3RpY3Mgd2UgY2FsY3VsYXRlZCBlYXJsaWVyIHdpdGggYGFkZFBlckNlbGxRQygpYCBhcmUgcmV0YWluZWQgaW4gb3VyIG5ldyBvYmplY3QsIHNvIHdlIGNhbiBwbG90IHRob3NlIGRpcmVjdGx5LgoKYGBge3IgbWl0b19wZXJjZW50X3Bsb3R9CiMgUGxvdCB0aGUgbWl0b2Nob25kcmlhbCBwZXJjZW50cyBzdG9yZWQgaW4gYGZpbHRlcmVkX3NjZWAKZ2dwbG90KG1hcHBpbmcgPSBhZXMoeCA9IGZpbHRlcmVkX3NjZSRzdWJzZXRzX21pdG9fcGVyY2VudCkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMTAwKQpgYGAKVGhlcmUgYXJlIGNlcnRhaW5seSBzb21lIGNlbGxzIHdpdGggaGlnaCBtaXRvY2hvbmRyaWFsIHBlcmNlbnRhZ2VzIQpGb3Igbm93LCB3ZSB3aWxsIHVzZSBhIGN1dG9mZiBvZiAyMCUgdG8gZmlsdGVyIG91dCB0aGUgd29yc3Qgb2YgdGhlIGNlbGxzLgoKYGBge3IgbGl2ZSA9IFRSVUV9CmZpbHRlcmVkX3NjZSA8LSBmaWx0ZXJlZF9zY2VbLCBmaWx0ZXJlZF9zY2Ukc3Vic2V0c19taXRvX3BlcmNlbnQgPCAyMF0KYGBgCgoKV2UgY2FuIGFsc28gZmlsdGVyIGJ5IGZlYXR1cmVzIChnZW5lcyBpbiBvdXIgY2FzZSkgdXNpbmcgYHNjYXRlcjo6YWRkUGVyRmVhdHVyZVFDKClgIHdoaWNoIHdpbGwgY29tcHV0ZSB0aGUgbnVtYmVyIG9mIHNhbXBsZXMgd2hlcmUgZWFjaCBnZW5lIGlzIGRldGVjdGVkIGFuZCB0aGUgbWVhbiBjb3VudCBhY3Jvc3MgYWxsIGdlbmVzLgpXZSBjYW4gdGhlbiB1c2UgdGhvc2UgZGF0YSAoc3RvcmVkIGluIGByb3dEYXRhYCkgdG8gZmlsdGVyIGJ5IHJvdyB0byBvbmx5IHRoZSBnZW5lcyB0aGF0IGFyZSBkZXRlY3RlZCBpbiBhdCBsZWFzdCA1JSBvZiBjZWxscywgYW5kIHdpdGggYSBtZWFuIGNvdW50ID4gMC4xLgoKYGBge3IgZ2VuZV9xY30KZmlsdGVyZWRfc2NlIDwtIHNjYXRlcjo6YWRkUGVyRmVhdHVyZVFDKGZpbHRlcmVkX3NjZSkKZGV0ZWN0ZWQgPC0gcm93RGF0YShmaWx0ZXJlZF9zY2UpJGRldGVjdGVkID4gNQpleHByZXNzZWQgPC0gcm93RGF0YShmaWx0ZXJlZF9zY2UpJG1lYW4gPiAwLjEKCiMgZmlsdGVyIHRoZSBnZW5lcyAocm93cykgdGhpcyB0aW1lCmZpbHRlcmVkX3NjZSA8LSBmaWx0ZXJlZF9zY2VbZGV0ZWN0ZWQgJiBleHByZXNzZWQsIF0KYGBgCgpIb3cgbWFueSBjZWxscyBkbyB3ZSBoYXZlIG5vdz8KCmBgYHtyIGZpbHRlcmVkX2RpbX0KZGltKGZpbHRlcmVkX3NjZSkKYGBgCgoKIyMjIE5vcm1hbGl6ZQoKTm93IHdlIHdpbGwgcGVyZm9ybSB0aGUgc2FtZSBub3JtYWxpemF0aW9uIHN0ZXBzIHdlIGRpZCBpbiBhIHByZXZpb3VzIGRhdGFzZXQsIHVzaW5nIGBzY3Jhbjo6Y29tcHV0ZVN1bUZhY3RvcnMoKWAgYW5kIGBzY2F0ZXI6OmxvZ05vcm1Db3VudHMoKWAuCllvdSBtaWdodCByZWNhbGwgdGhhdCB0aGVyZSBpcyBhIGJpdCBvZiByYW5kb21uZXNzIGluIHNvbWUgb2YgdGhlc2UgY2FsY3VsYXRpb25zLCBzbyB3ZSBzaG91bGQgYmUgc3VyZSB0byBoYXZlIHVzZWQgYHNldC5zZWVkKClgIGVhcmxpZXIgaW4gdGhlIG5vdGVib29rIGZvciByZXByb2R1Y2liaWxpdHkuCgpgYGB7ciBzdW1mYWN0b3JzfQojIENsdXN0ZXIgc2ltaWxhciBjZWxscwpxY2x1c3QgPC0gc2NyYW46OnF1aWNrQ2x1c3RlcihmaWx0ZXJlZF9zY2UpCgojIENvbXB1dGUgc3VtIGZhY3RvcnMgZm9yIGVhY2ggY2VsbCBjbHVzdGVyIGdyb3VwaW5nLgpmaWx0ZXJlZF9zY2UgPC0gc2NyYW46OmNvbXB1dGVTdW1GYWN0b3JzKGZpbHRlcmVkX3NjZSwgY2x1c3RlcnMgPSBxY2x1c3QsIHBvc2l0aXZlID0gRkFMU0UpCmBgYAoKSXQgdHVybnMgb3V0IGluIHRoaXMgY2FzZSB3ZSBlbmQgdXAgd2l0aCBzb21lIG5lZ2F0aXZlIHNpemUgZmFjdG9ycy4KVGhpcyBpcyB1c3VhbGx5IGFuIGluZGljYXRpb24gdGhhdCBvdXIgZmlsdGVyaW5nIHdhcyBub3Qgc3RyaW5nZW50IGVub3VnaCwgYW5kIHRoZXJlIHJlbWFpbiBhIG51bWJlciBvZiBjZWxscyBvciBnZW5lcyB3aXRoIG5lYXJseSB6ZXJvIGNvdW50cy4KVGhpcyBwcm9iYWJseSBoYXBwZW5lZCB3aGVuIHdlIHJlbW92ZWQgdGhlIGluZnJlcXVlbnRseS1leHByZXNzZWQgZ2VuZXM7IGNlbGxzIHdoaWNoIGhhZCBoaWdoIGNvdW50cyBmcm9tIHRob3NlIHBhcnRpY3VsYXIgZ2VuZXMgKGFuZCBmZXcgb3RoZXJzKSBjb3VsZCBoYXZlIGhhZCB0aGVpciB0b3RhbCBjb3VudHMgZHJhbWF0aWNhbGx5IHJlZHVjZWQuCgpUbyBhY2NvdW50IGZvciB0aGlzLCB3ZSB3aWxsIHJlY2FsY3VsYXRlIHRoZSBwZXItY2VsbCBzdGF0cyBhbmQgZmlsdGVyIG91dCBsb3cgY291bnRzLgpVbmZvcnR1bmF0ZWx5LCB0byBkbyB0aGlzLCB3ZSBuZWVkIHRvIGZpcnN0IHJlbW92ZSB0aGUgcHJldmlvdXNseSBjYWxjdWxhdGVkIHN0YXRpc3RpY3MsIHdoaWNoIHdlIHdpbGwgZG8gYnkgc2V0dGluZyB0aGVtIHRvIGBOVUxMYC4KCmBgYHtyIHJlUUN9CiMgcmVtb3ZlIHByZXZpb3VzIGNhbGN1bGF0aW9ucwpmaWx0ZXJlZF9zY2Ukc3VtIDwtIE5VTEwKZmlsdGVyZWRfc2NlJGRldGVjdGVkIDwtIE5VTEwKZmlsdGVyZWRfc2NlJHRvdGFsIDwtIE5VTEwKZmlsdGVyZWRfc2NlJHN1YnNldHNfbWl0b19zdW0gPC0gTlVMTApmaWx0ZXJlZF9zY2Ukc3Vic2V0c19taXRvX2RldGVjdGVkIDwtIE5VTEwKZmlsdGVyZWRfc2NlJHN1YnNldHNfbWl0b19zdW0gPC0gTlVMTAoKIyByZWNhbGN1bGF0ZSBjZWxsIHN0YXRzCmZpbHRlcmVkX3NjZSA8LSBzY2F0ZXI6OmFkZFBlckNlbGxRQyhmaWx0ZXJlZF9zY2UsIHN1YnNldHMgPSBsaXN0KG1pdG8gPSBtaXRvX2dlbmVzKSkKCiMgcHJpbnQgdGhlIG51bWJlciBvZiBjZWxscyB3aXRoIGZld2VyIHRoYW4gNTAwIFVNSXMKc3VtKGZpbHRlcmVkX3NjZSRzdW0gPCA1MDApCmBgYAoKTm93IHdlIGNhbiBmaWx0ZXIgYWdhaW4uCkluIHRoaXMgY2FzZSwgd2Ugd2lsbCBrZWVwIGNlbGxzIHdpdGggYXQgbGVhc3QgNTAwIFVNSXMgYWZ0ZXIgcmVtb3ZpbmcgdGhlIGxvd2x5IGV4cHJlc3NlZCBnZW5lcy4KVGhlbiB3ZSB3aWxsIHJlZG8gdGhlIHNpemUgZmFjdG9yIGNhbGN1bGF0aW9uLCBob3BlZnVsbHkgd2l0aCBubyBtb3JlIHdhcm5pbmdzLgoKCmBgYHtyIHJlZmlsdGVyfQpmaWx0ZXJlZF9zY2UgPC0gZmlsdGVyZWRfc2NlWywgZmlsdGVyZWRfc2NlJHN1bSA+PSA1MDBdCgpxY2x1c3QgPC0gc2NyYW46OnF1aWNrQ2x1c3RlcihmaWx0ZXJlZF9zY2UpCgpmaWx0ZXJlZF9zY2UgPC0gc2NyYW46OmNvbXB1dGVTdW1GYWN0b3JzKGZpbHRlcmVkX3NjZSwgY2x1c3RlcnMgPSBxY2x1c3QpCmBgYAoKTG9va3MgZ29vZCEgTm93IHdlJ2xsIGRvIHRoZSBub3JtYWxpemF0aW9uLgoKYGBge3Igbm9ybWFsaXplfQojIE5vcm1hbGl6ZSBhbmQgbG9nIHRyYW5zZm9ybS4Kbm9ybWFsaXplZF9zY2UgPC0gc2NhdGVyOjpsb2dOb3JtQ291bnRzKGZpbHRlcmVkX3NjZSkKYGBgCgpBdCB0aGlzIHBvaW50LCB3ZSBoYXZlIGEgZmV3IGRpZmZlcmVudCB2ZXJzaW9ucyBvZiBvdXIgYFNpbmdsZUNlbGxFeHBlcmltZW50YCBvYmplY3QuClRoZSBvcmlnaW5hbCAobW9zdGx5KSB1bmZpbHRlcmVkIHZlcnNpb24gaXMgaW4gYGhvZGdraW5zX3NjZWAsIHRoZSBmaWx0ZXJlZCB2ZXJzaW9uIGluIGBmaWx0ZXJlZF9zY2VgLCBhbmQgdGhlIG5vcm1hbGl6ZWQgdmVyc2lvbiBpbiBgbm9ybWFsaXplZF9zY2VgLgpXZSBjYW4gY2xlYW4gdGhvc2UgdXAgYSBiaXQgdG8gc2F2ZSBtZW1vcnksIGtlZXBpbmcgb25seSB0aGUgbGF0ZXN0IGBub3JtYWxpemVkX3NjZWAgdmVyc2lvbiwgd2hpY2ggbm93IGhhcyB0d28gYGFzc2F5YHM6CmBjb3VudHNgIHdpdGggdGhlIHJhdyBkYXRhIGFuZCBgbG9nY291bnRzYCB3aXRoIHRoZSBub3JtYWxpemVkIGFuZCB0cmFuc2Zvcm1lZCBkYXRhLgoKYGBge3IgY2xlYW5fdXAsIGxpdmUgPSBUUlVFfQphc3NheU5hbWVzKG5vcm1hbGl6ZWRfc2NlKQpybShob2Rna2luc19zY2UsIGZpbHRlcmVkX3NjZSkKYGBgCgoKIyMgRGltZW5zaW9uYWxpdHkgcmVkdWN0aW9uIGFuZCBkaXNwbGF5CgohW1JvYWRtYXA6IERpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbl0oZGlhZ3JhbXMvcm9hZG1hcF9zaW5nbGVfZGltZW5zaW9uX3JlZHVjdGlvbi5wbmcpCgojIyMgUHJpbmNpcGFsIENvbXBvbmVudHMgQW5hbHlzaXMKClByaW5jaXBhbCBjb21wb25lbnQgYW5hbHlzaXMgKFBDQSkgaXMgYSBkaW1lbnNpb25hbGl0eSByZWR1Y3Rpb24gdGVjaG5pcXVlIHRoYXQgYWxsb3dzIHVzIHRvIGlkZW50aWZ5IHRoZSBsYXJnZXN0IGNvbXBvbmVudHMgb2YgdmFyaWF0aW9uIGluIGEgY29tcGxleCBkYXRhc2V0LgpPdXIgZXhwcmVzc2lvbiBkYXRhIGNhbiBiZSB0aG91Z2h0IG9mIGFzIG1hcHBpbmcgZWFjaCBzYW1wbGUgaW4gYSBtdWx0aWRpbWVuc2lvbmFsIHNwYWNlIGRlZmluZWQgYnkgdGhlIGV4cHJlc3Npb24gbGV2ZWwgb2YgZWFjaCBnZW5lLgpUaGUgZXhwcmVzc2lvbiBvZiBtYW55IG9mIHRob3NlIGdlbmVzIGFyZSBjb3JyZWxhdGVkLCBzbyB3ZSBjYW4gb2Z0ZW4gZ2V0IGEgYmV0dGVyLCBzaW1wbGVyIHBpY3R1cmUgb2YgdGhlIGRhdGEgYnkgY29tYmluaW5nIHRoZSBpbmZvcm1hdGlvbiBmcm9tIHRob3NlIGNvcnJlbGF0ZWQgZ2VuZXMuCgpQQ0Egcm90YXRlcyBhbmQgdHJhbnNmb3JtcyB0aGlzIHNwYWNlIHNvIHRoYXQgZWFjaCBheGlzIGlzIG5vdyBhIGNvbWJpbmF0aW9uIG9mIG11bHRpcGxlIGNvcnJlbGF0ZWQgZ2VuZXMsIG9yZGVyZWQgc28gdGhlIGZpcnN0IGF4ZXMgY2FwdHVyZSB0aGUgbW9zdCB2YXJpYXRpb24gZnJvbSB0aGUgZGF0YS4KVGhlc2UgbmV3IGF4ZXMgYXJlIHRoZSAicHJpbmNpcGFsIGNvbXBvbmVudHMuIgpJZiB3ZSBsb29rIGF0IHRoZSBmaXJzdCBmZXcgY29tcG9uZW50cywgd2UgY2FuIG9mdGVuIGdldCBhIG5pY2Ugb3ZlcnZpZXcgb2YgcmVsYXRpb25zaGlwcyBhbW9uZyB0aGUgc2FtcGxlcyBpbiB0aGUgZGF0YS4KCiMjIyMgU3RvcmluZyBQQ0EgcmVzdWx0cyB3aXRoIHRoZSByYXcgZGF0YQoKV2Ugd2lsbCBzdG9yZSB0aGUgUENBIHJlc3VsdHMgaW4gb3VyIGBTaW5nbGVDZWxsRXhwZXJpbWVudGAgb2JqZWN0LCBhcyB3ZSB3aWxsIHdhbnQgdG8gdXNlIHRoZW0gbGF0ZXIuClRvIGRvIHRoaXMsIHdlIHdpbGwgdXNlIHRoZSBgcnVuUENBKClgIGZ1bmN0aW9uIGZyb20gYHNjYXRlcmAsIHdoaWNoIHBlcmZvcm1zIHRoZSBQQ0EgY2FsY3VsYXRpb25zIGFuZCByZXR1cm5zIGEgbmV3IG9iamVjdCB3aXRoIHRoZSByZXN1bHRzIHN0b3JlZCBpbiB0aGUgYHJlZHVjZWREaW1gIHNsb3QuCklmIHdlIHdhbnRlZCB0bywgd2UgY291bGQgZ2V0IHRoZSByYXcgcmVzdWx0cyBhcyBhIG1hdHJpeCBpbnN0ZWFkIHdpdGggYGNhbGN1bGF0ZVBDQSgpYCBmdW5jdGlvbiwgYXMgd2UgZGlkIGluIGEgcHJldmlvdXMgbm90ZWJvb2suCgpXZSB3aWxsIGFsc28gdXNlIHRoZSBgbnRvcGAgYXJndW1lbnQgdG8gY2FsY3VsYXRlIHRoZSBQQ0EgdXNpbmcgMjAwMCBnZW5lcyB3aXRoIHRoZSBoaWdoZXN0IHZhcmlhbmNlLgpUaGUgZGVmYXVsdCBpcyBgbnRvcCA9IDUwMGAuCgpgYGB7ciBydW5QQ0EsIGxpdmUgPSBUUlVFfQojIGNhbGN1bGF0ZSBQQ0EgdXNpbmcgdGhlIHRvcCAyMDAwIGdlbmVzCm5vcm1hbGl6ZWRfc2NlIDwtIHJ1blBDQShub3JtYWxpemVkX3NjZSwgbnRvcCA9IDIwMDApCmBgYAoKV2UgY2FuIHNlZSB3aGF0IHJlZHVjZWQgZGltZW5zaW9uYWxpdHkgbWF0cmljZXMgYXJlIHN0b3JlZCBpbiB0aGUgb2JqZWN0IHdpdGggdGhlIGByZWR1Y2VkRGltTmFtZXMoKWAgZnVuY3Rpb24uCgpgYGB7ciByZWR1Y2VkX2RpbV9uYW1lcywgbGl2ZSA9IFRSVUV9CiMgcHJpbnQgdGhlIHJlZHVjZWQgZGltZW5zaW9uYWxpdHkgdGFibGVzIGF2YWlsYWJsZQpyZWR1Y2VkRGltTmFtZXMobm9ybWFsaXplZF9zY2UpCmBgYAoKVG8gZXh0cmFjdCB0aGVtIGJ5IG5hbWUsIHdlIHVzZSB0aGUgYHJlZHVjZWREaW0oKWAgZnVuY3Rpb24sIG11Y2ggbGlrZSB0aGUgYGFzc2F5KClgIGZ1bmN0aW9uIHRvIGV4dHJhY3Qgb3JpZ2luYWwgZGF0YS4KCmBgYHtyIGV4dHJhY3RfcmVkdWNlZCwgbGl2ZSA9IFRSVUV9CiMgcHJpbnQgdGhlIHRvcCBjb3JuZXIgb2YgdGhlIFBDQSBtYXRyaXgKcmVkdWNlZERpbShub3JtYWxpemVkX3NjZSwgIlBDQSIpWzE6MTAsIDE6NV0KYGBgCgojIyMjIFBsb3R0aW5nIFBDQSByZXN1bHRzCgpJZiB3ZSBoYXZlIHRoZSBQQ0EgcmVzdWx0cyBzdG9yZWQgaW4gdGhlIGBTaW5nbGVDZWxsRXhwZXJpbWVudGAgb2JqZWN0LCB3ZSBjYW4gdXNlIHRoZSBgc2NhdGVyOjpwbG90UmVkdWNlZERpbSgpYCBmdW5jdGlvbiB0byBwbG90IGl0IHdpdGggc29tZSBuaWNlIGRlZmF1bHRzIGVhc2lseS4KT25lIG5pY2UgdGhpbmcgYWJvdXQgdGhpcyBmdW5jdGlvbiBpcyB0aGF0IGl0IHVzZXMgYGdncGxvdDJgIHVuZGVyIHRoZSBob29kLCBzbyBpZiB3ZSB3YW50ZWQgdG8gY3VzdG9taXplIGl0IGxhdGVyLCB3ZSBjb3VsZC4KCmBgYHtyIHBsb3RQQ0EsIGxpdmUgPSBUUlVFfQojIHBsb3QgUENBIHJlc3VsdHMKcGxvdFJlZHVjZWREaW0obm9ybWFsaXplZF9zY2UsICJQQ0EiKQpgYGAKUENBIGdpdmVzIHVzIGEgbWF0cml4IHdpdGggbW9yZSB0aGFuIGp1c3QgdHdvIGRpbWVuc2lvbnMsIGFuZCB3ZSBtaWdodCB3YW50IHRvIGxvb2sgYXQgc29tZSBoaWdoZXIgZGltZW5zaW9ucyB0b28uCldlIGNhbiBkbyB0aGF0IHdpdGggdGhlIGBuY29tcG9uZW50c2AgYXJndW1lbnQuCgpgYGB7ciBwbG90UENBMzQsIGxpdmUgPSBUUlVFfQojIHBsb3QgUEMzIGFuZCBQQzQKcGxvdFJlZHVjZWREaW0obm9ybWFsaXplZF9zY2UsICJQQ0EiLCBuY29tcG9uZW50cyA9IGMoMyw0KSkKYGBgCgojIyMgTW9kZWxpbmcgdmFyaWFuY2UKClRoZSB2YXJpYXRpb24gaW4gZ2VuZSBleHByZXNzaW9uIHdlIHNlZSBhbW9uZyBjZWxscyBjb21lcyBmcm9tIGEgY29tYmluYXRpb24gb2YgdmFyaWF0aW9uIGR1ZSB0byB0ZWNobmljYWwgZWZmZWN0cyBhbmQgdGhlIGJpb2xvZ3kgd2UgcmVhbGx5IGNhcmUgYWJvdXQuCkluIG9yZGVyIHRvIHJvdWdobHkgYWNjb3VudCBmb3IgdGhpcyB3ZSBjb3VsZCBqdXN0IHRha2UgdGhlIGxhcmdlc3QgdmFyaWFuY2UgZ2VuZXMsIG9uIHRoZSBhc3N1bXB0aW9uIHRoYXQgbG93IHZhcmlhbmNlIGdlbmVzIGFyZSBtb3N0bHkganVzdCBub2lzZS4KVGhpcyBpcyB0aGUgZGVmYXVsdCBhcHByb2FjaCB0aGF0IGBydW5QQ0EoKWAgYW5kIGBjYWxjdWxhdGVQQ0EoKWAgdGFrZSwgdXNpbmcgdGhlIGdlbmVzIHdpdGggdGhlIGdyZWF0ZXN0IHZhcmlhbmNlIGFjcm9zcyBjZWxscyB0byBjYWxjdWxhdGUgdGhlIFBDQSBtYXRyaXguCgpJZiB3ZSB3YW50IHRvIGJlIGEgYml0IG1vcmUgY2FyZWZ1bCBhYm91dCBpdCwgd2UgY2FuIG1vZGVsIHRoZSB2YXJpYW5jZSBpbiBleHByZXNzaW9uIG9mIGVhY2ggZ2VuZSBhcyBhIGZ1bmN0aW9uIG9mIHRoZSBtZWFuIGV4cHJlc3Npb24gZm9yIHRoYXQgZ2VuZS4KVGhpcyBpcyB1c2VmdWwgYmVjYXVzZSB3ZSBnZW5lcmFsbHkgZXhwZWN0IHRoZSB2YXJpYW5jZSB0byBpbmNyZWFzZSBhcyBtZWFuIGV4cHJlc3Npb24gaW5jcmVhc2VzLCBldmVuIGlmIHRoZXJlIGlzIG5vIGJpb2xvZ2ljYWwgc2lnbmFsIGluIHRoZSBleHByZXNzaW9uIHZhcmlhdGlvbi4KCldlIHdpbGwgZG8gdGhpcyBtb2RlbGluZyBvZiB2YXJpYW5jZSBieSBleHByZXNzaW9uIHdpdGggdGhlIGBzY3Jhbjo6bW9kZWxHZW5lVmFyKClgIGZ1bmN0aW9uLCBzYXZpbmcgdGhlIHJlc3VsdHMgdG8gYSBuZXcgdmFyaWFibGUuCgpgYGB7ciBtb2RlbF92YXJpYW5jZX0KZ2VuZV92YXJpYW5jZSA8LSBzY3Jhbjo6bW9kZWxHZW5lVmFyKG5vcm1hbGl6ZWRfc2NlKQpgYGAKCk5vdyBsZXQncyBwbG90IHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBnZW5lIGV4cHJlc3Npb24gYW5kIHZhcmlhbmNlIHdlIHdlcmUgZGlzY3Vzc2luZy4KSGVyZSB3ZSB3aWxsIGFsc28gYWRkIHRoZSBmaXR0aW5nIGN1cnZlIHRoYXQgYHNjcmFuOjptb2RlbEdlbmVWYXIoKWAgY3JlYXRlZCwgd2hpY2ggaXMgc3RvcmVkIGFzIGZ1bmN0aW9uIGluIHRoZSAgYCR0cmVuZGAgc2xvdCBvZiB0aGUgYGdlbmVfdmFyaWFuY2VgIG9iamVjdC4KV2UgY2FuIGFkZCBhIGZ1bmN0aW9uIGxpa2UgdGhhdCBjdXJ2ZSB0byBhIGBnZ3Bsb3RgIHdpdGggYSBgc3RhdF9mdW5jdGlvbmAgbGF5ZXIuCgpgYGB7ciBwbG90X3ZhcmlhbmNlfQpnZ3Bsb3QoYXMuZGF0YS5mcmFtZShnZW5lX3ZhcmlhbmNlKSwgYWVzKHggPSBtZWFuLCB5ID0gdG90YWwpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMSkgKwogIHN0YXRfZnVuY3Rpb24oZnVuID0gbWV0YWRhdGEoZ2VuZV92YXJpYW5jZSkkdHJlbmQsIGNvbG9yID0gImJsdWUiKSArCiAgbGFicygKICAgIHggPSAiTWVhbiBsb2ctZXhwcmVzc2lvbiIsCiAgICB5ID0gIlZhcmlhbmNlIikgKwogIHRoZW1lX2J3KCkKYGBgCgpOb3cgd2UgY2FuIHVzZSBgc2NyYW46OmdldFRvcEhWR3MoKWAgdG8gc2VsZWN0IHRoZSBnZW5lcyB0aGF0IGhhdmUgdGhlIG1vc3QgYmlvbG9naWNhbCB2YXJpYXRpb24gKGFjY29yZGluZyB0byB0aGUgbW9kZWwpIGFuZCByZWNhbGN1bGF0ZSBQQ0Egc2NvcmVzIHVzaW5nIG9ubHkgdGhvc2UgZ2VuZXMuCihJbiBwcmFjdGljZSwgd2UgYXJlIHNlbGVjdGluZyB0aGUgZ2VuZXMgd2l0aCB0aGUgbGFyZ2VzdCByZXNpZHVhbCB2YXJpYXRpb24gYWZ0ZXIgcmVtb3ZpbmcgdGVjaG5pY2FsIHZhcmlhdGlvbiBtb2RlbGVkIGJ5IHRoZSBtZWFuL3ZhcmlhbmNlIHJlbGF0aW9uc2hpcC4pCgpIZXJlIHdlIGFyZSBwaWNraW5nIHRoZSAyMDAwIHRvcCBnZW5lcyB0byBtYXRjaCB0aGUgbnVtYmVyIG9mIGdlbmVzIGZyb20gb3VyIGVhcmxpZXIgY2FsY3VsYXRpb25zLgoKYGBge3IgZ2V0X2hpZ2h2YXIsIGxpdmUgPSBUUlVFfQojIHNlbGVjdCB0aGUgbW9zdCB2YXJpYWJsZSBnZW5lcwpoaWdodmFyX2dlbmVzIDwtIHNjcmFuOjpnZXRUb3BIVkdzKGdlbmVfdmFyaWFuY2UsIG4gPSAyMDAwKQojIGNhbGN1bGF0ZSBhIFBDQSBtYXRyaXggdXNpbmcgdGhvc2UgZ2VuZXMKbm9ybWFsaXplZF9zY2UgPC0gcnVuUENBKG5vcm1hbGl6ZWRfc2NlLCBzdWJzZXRfcm93ID0gaGlnaHZhcl9nZW5lcykKYGBgCgpOb3cgd2UgY2FuIHBsb3Qgb3VyIG5ldyBQQ0EgdmFsdWVzIGZvciBjb21wYXJpc29uLgpZb3UgbWlnaHQgcmVhbGl6ZSB0aGF0IG91ciBvbGQgUENBIHZhbHVlcyB3ZXJlIHJlcGxhY2VkIHdoZW4gd2UgcmFuIGBydW5QQ0EoKWAgYWdhaW4sIHNvIHdlIGNhbid0IHJlY3JlYXRlIHRoZSBlYXJsaWVyIHBsb3RzIGF0IHRoaXMgc3RhZ2Ugb2YgdGhlIG5vdGVib29rLgpZb3Ugd2lsbCBoYXZlIHRvIHNjcm9sbCB1cCB0byB5b3VyIGVhcmxpZXIgcGxvdHMgdG8gY29tcGFyZS4KCmBgYHtyIHBsb3RQQ0FfaGlnaHZhciwgbGl2ZSA9IFRSVUV9CiMgcGxvdCB0aGUgbmV3IFBDQSByZXN1bHRzCnBsb3RSZWR1Y2VkRGltKG5vcm1hbGl6ZWRfc2NlLCAiUENBIikKcGxvdFJlZHVjZWREaW0obm9ybWFsaXplZF9zY2UsICJQQ0EiLCBuY29tcG9uZW50cyA9IGMoMyw0KSkKYGBgCgojIyMgVU1BUAoKKipVTUFQKiogKFVuaWZvcm0gTWFuaWZvbGQgQXBwcm94aW1hdGlvbiBhbmQgUHJvamVjdGlvbikgaXMgYSBtYWNoaW5lIGxlYXJuaW5nIHRlY2huaXF1ZSBkZXNpZ25lZCB0byBwcm92aWRlIG1vcmUgZGV0YWlsIGluIGhpZ2hseSBkaW1lbnNpb25hbCBkYXRhIHRoYW4gYSB0eXBpY2FsIHByaW5jaXBhbCBjb21wb25lbnRzIGFuYWx5c2lzLgpXaGlsZSBQQ0EgYXNzdW1lcyB0aGF0IHRoZSB2YXJpYXRpb24gd2UgY2FyZSBhYm91dCBoYXMgYSBwYXJ0aWN1bGFyIGRpc3RyaWJ1dGlvbiAobm9ybWFsLCBicm9hZGx5IHNwZWFraW5nKSwgVU1BUCBhbGxvd3MgbW9yZSBjb21wbGljYXRlZCBkaXN0cmlidXRpb25zIHRoYXQgaXQgbGVhcm5zIGZyb20gdGhlIGRhdGEuClRoZSB1bmRlcmx5aW5nIG1hdGhlbWF0aWNzIGFyZSBiZXlvbmQgbWUsIGJ1dCBpZiB5b3UgYXJlIG1vcmUgYW1iaXRpb3VzIHRoYW4gSSwgeW91IGNhbiBsb29rIGF0IHRoZSBwYXBlciBieSBbTWNJbm5lcywgSGVhbHksICYgTWVsdmlsbGUgKDIwMTgpXShodHRwczovL2FyeGl2Lm9yZy9hYnMvMTgwMi4wMzQyNikuClRoZSBtYWluIGFkdmFudGFnZSBvZiB0aGlzIGNoYW5nZSBpbiB1bmRlcmx5aW5nIGFzc3VtcHRpb25zIGlzIHRoYXQgVU1BUCBjYW4gZG8gYSBiZXR0ZXIgam9iIHNlcGFyYXRpbmcgY2x1c3RlcnMsIGVzcGVjaWFsbHkgd2hlbiBzb21lIG9mIHRob3NlIGNsdXN0ZXJzIG1heSBiZSBtb3JlIHNpbWlsYXIgdG8gZWFjaCBvdGhlciB0aGFuIG90aGVycy4KCkFub3RoZXIgZGltZW5zaW9uYWxpdHkgcmVkdWN0aW9uIHRlY2huaXF1ZSB0aGF0IHlvdSBtYXkgaGF2ZSBoZWFyZCBvZiBpcyAqKnQtU05FKiogKHQtZGlzdHJpYnV0ZWQgU3RvY2hhc3RpYyBOZWlnaGJvciBFbWJlZGRpbmcpLCB3aGljaCBoYXMgc2ltaWxhciBwcm9wZXJ0aWVzIHRvIFVNQVAsIGFuZCBvZnRlbiBwcm9kdWNlcyBzaW1pbGFyIHJlc3VsdHMuClRoZXJlIGlzIHNvbWUgb25nb2luZyBkZWJhdGUgYWJvdXQgd2hpY2ggb2YgdGhlc2UgdHdvIHRlY2huaXF1ZXMgaXMgc3VwZXJpb3IsIGFuZCB3aGV0aGVyIHRoZSBkaWZmZXJlbmNlcyBhcmUgZHVlIHRvIHRoZSB1bmRlcmx5aW5nIGFsZ29yaXRobSBvciB0byBpbXBsZW1lbnRhdGlvbiBhbmQgcGFyYW1ldGVyIGluaXRpYWxpemF0aW9uIGRlZmF1bHRzLgpSZWdhcmRsZXNzIG9mIHdoeSwgaW4gb3VyIGV4cGVyaWVuY2UsIFVNQVAgc2VlbXMgdG8gcHJvZHVjZSBzbGlnaHRseSBiZXR0ZXIgcmVzdWx0cyBhbmQgcnVuIGEgYml0IGZhc3RlciwgYnV0IHRoZSBkaWZmZXJlbmNlcyBjYW4gYmUgc3VidGxlLgoKIyMjIyBEZWZhdWx0IHBhcmFtZXRlcnMKCkZvciBlYXNlIG9mIHVzZSB3aXRoIHRoaXMgZGF0YSwgd2Ugd2lsbCBiZSB1c2luZyB0aGUgYHNjYXRlcjo6Y2FsY3VsYXRlVU1BUCgpYCBhbmQgYHNjYXRlcjo6cnVuVU1BUCgpYCBmdW5jdGlvbiB0byBhcHBseSBVTUFQIHRvIG91ciBzaW5nbGUgY2VsbCBkYXRhLCBidXQgc2ltaWxhciBmdW5jdGlvbnMgdGhlIGB1d290YCBwYWNrYWdlIChub3RhYmx5IGB1d290Ojp1bWFwKClgKSBjYW4gYmUgdXNlZCB0byBhcHBseSBVTUFQIHRvIGFueSBudW1lcmljYWwgbWF0cml4LgoKVU1BUCBjYW4gYmUgc2xvdyBmb3IgYSBsYXJnZSBkYXRhIHNldCB3aXRoIGxvdHMgb2YgcGFyYW1ldGVycy4KSXQgaXMgd29ydGggbm90aW5nIHRoYXQgdGhlIGBzY2F0ZXI6OmNhbGN1bGF0ZVVNQVAoKWAgaW1wbGVtZW50YXRpb24gYWN0dWFsbHkgZG9lcyBQQ0EgZmlyc3QsIGFuZCB0aGVuIHJ1bnMgVU1BUCBvbiB0aGUgdG9wIDUwIFBDcy4KSWYgd2UgaGF2ZSBhbHJlYWR5IGNhbGN1bGF0ZWQgUENBIChhcyB3ZSBoYXZlKSB3ZSBjYW4gdGVsbCBpdCB0byB1c2UgdGhvc2UgcmVzdWx0cyB3aXRoIHRoZSBgZGltcmVkYCBhcmd1bWVudC4KCkFzIHdpdGggUENBLCB0aGVyZSBhcmUgdHdvIGZ1bmN0aW9ucyB3ZSBjb3VsZCB1c2U6CmBzY2F0ZXI6OmNhbGN1bGF0ZVVNQVAoKWAgd2lsbCByZXR1cm4gYSBtYXRyaXggb2YgcmVzdWx0cywgd2l0aCBvbmUgcm93IGZvciBlYWNoIHNhbXBsZSwgYW5kIGEgY29sdW1uIGZvciBlYWNoIG9mIHRoZSBVTUFQIGRpbWVuc2lvbnMgcmV0dXJuZWQuCmBzY2F0ZXI6OnJ1blVNQVAoKWAgcGVyZm9ybXMgdGhlIHNhbWUgZnVuY3Rpb24sIGJ1dCByZXR1cm5zIHRoZSByZXN1bHRzIGluIGEgU2luZ2xlQ2VsbEV4cGVyaW1lbnQgb2JqZWN0LgoKTGV0J3Mgc2VlIGhvdyBpdCBsb29rcyB3aXRoIHRoZSAobW9zdGx5KSBkZWZhdWx0IHBhcmFtZXRlcnM6CgpgYGB7ciBjYWxjdWxhdGVfdW1hcCwgbGl2ZSA9IFRSVUV9CiMgUnVuIFVNQVAKbm9ybWFsaXplZF9zY2UgPC0gcnVuVU1BUChub3JtYWxpemVkX3NjZSwKICAgICAgICAgICAgICAgICAgICAgICAgICBkaW1yZWQgPSAiUENBIikgIyB1c2UgYWxyZWFkeSBzdG9yZWQgUENBIHJlc3VsdHMKYGBgCgpOb3cgd2UgY2FuIHBsb3Qgd2l0aCB0aGUgc2FtZSBgcGxvdFJlZHVjZWREaW0oKWAgZnVuY3Rpb24sIHNwZWNpZnlpbmcgd2Ugd2FudCB0byBwbG90IHRoZSBVTUFQIHJlc3VsdHMgdGhpcyB0aW1lLgpXZSB3aWxsIGFsc28gYWRkIHNvbWUgY29sb3IgdGhpcyB0aW1lIHdpdGggdGhlIGBjb2xvcl9ieWAgYXJndW1lbnQsIHVzaW5nIHRoZSBudW1iZXIgb2YgZ2VuZXMgZGV0ZWN0ZWQgaW4gZWFjaCBjZWxsIHRvIGFzc2lnbiBhIGh1ZS4KCmBgYHtyIHBsb3RfdW1hcCwgbGl2ZSA9IFRSVUV9CiMgbWFrZSBhIFVNQVAgcGxvdCB3aXRoIGBwbG90UmVkdWNlZERpbSgpYApwbG90UmVkdWNlZERpbShub3JtYWxpemVkX3NjZSwgIlVNQVAiLCBjb2xvcl9ieSA9ICJkZXRlY3RlZCIpCmBgYAoKVGhlcmUgaXMgY2xlYXJseSBhIGxvdCBvZiBzdHJ1Y3R1cmUgaW4gdGhlcmUsIGJ1dCBpcyBpdCBtZWFuaW5nZnVsPwpEbyB0aGUgY2x1c3RlcnMgd2Ugc2VlIGRpZmZlcmVudGlhdGUgY2VsbCB0eXBlcz8gSG93IHNob3VsZCB3ZSBkaXZpZGUgdGhlbSB1cD8KCldlIHdpbGwgY29tZSBiYWNrIHRvIHRoaXMgcXVlc3Rpb24gbGF0ZXIhCgojIyMgVU1BUCBleHBlcmltZW50cwoKTm93IHRoYXQgd2UgaGF2ZSBhbiBpZGVhIG9mIHdoYXQgYSBVTUFQIHBsb3Qgd2l0aCB0aGUgZGVmYXVsdCBwYXJhbWV0ZXJzIGxvb2tzIGxpa2UsIGxldCdzIHRyeSBleHBlcmltZW50aW5nIHdpdGggdGhlIGBuX25laWdoYm9yc2AgcGFyYW1ldGVyLgpGaXJzdCwgd2Ugc2hvdWxkIHNlZSB3aGF0IHRoaXMgcGFyYW1ldGVyIGlzLCBhbmQgd2hhdCB0aGUgZGVmYXVsdCB2YWx1ZSBpcy4KSW4gdGhlIGNvbnNvbGUsIHJ1biBgP3NjYXRlcjo6Y2FsY3VsYXRlVU1BUGAgdG8gc2VlIHdoYXQgdGhpcyAoYW5kIG90aGVyIHBhcmFtZXRlcnMpIGFyZS4KRm9yIGV2ZW4gbW9yZSBwYXJhbWV0ZXJzLCB5b3UgY2FuIGxvb2sgYXQgdGhlIHVuZGVybHlpbmcgaW1wbGVtZW50YXRpb24gY29kZSB0aGF0IGBjYWxjdWxhdGVVTUFQKClgIHVzZXMsIHdoaWNoIGlzIHRoZSBmdW5jdGlvbiBgdXdvdDo6dW1hcCgpYAoKSW4gb3JkZXIgdG8gbWFrZSBvdXIgZXhwZXJpbWVudGF0aW9uIGVhc2llciwgd2Ugd2lsbCBjcmVhdGUgYSAqZnVuY3Rpb24qIHRoYXQgYWxsb3dzIHVzIHRvIHJlcnVuIHRoZSBzYW1lIGNvZGUgZWFzaWx5LCBidXQgY3JlYXRlIGFuIGFyZ3VtZW50IHRoYXQgYWxsb3dzIHVzIHRvIGNoYW5nZSBvbmUgdmFyaWFibGU6IHRoZSBgbl9uZWlnaGJvcnNgIHZhcmlhYmxlLgpIZXJlIHdlIGFyZSBzYXZpbmcgb25seSBhIGxpbmUgb2YgY29kZSwgYnV0IHdlIGNvdWxkIGFwcGx5IHRoaXMgdG8gYSBtdWNoIG1vcmUgY29tcGxleCBzZXJpZXMgb2Ygb3BlcmF0aW9ucyBpZiB3ZSB3YW50ZWQgdG8hCgpgYGB7ciBVTUFQLWZ1bmN0aW9ufQpVTUFQX3Bsb3Rfd3JhcHBlciA8LSBmdW5jdGlvbihzY2UgPSBub3JtYWxpemVkX3NjZSwgbm5fcGFyYW0gPSAxNSkgewogICMgUHVycG9zZTogUnVuIFVNQVAgYW5kIHBsb3QgdGhlIG91dHB1dAogICMgQXJnczogbm5fcGFyYW06IGEgc2luZ2xlIG51bWVyaWMgYXJndW1lbnQgdGhhdCB3aWxsIGNoYW5nZSB0aGUKICAjICAgICAgICAgICAgICAgICBuX25laWdoYm9ycyB2YXJpYWJsZSBpbiB0aGUgY2FsY3VsYXRlVU1BUCgpIGZ1bmN0aW9uLgogICMgT3V0cHV0OiBhIHNjYXR0ZXJwbG90IHdpdGggdGhlIHR3byBVTUFQIGNvb3JkaW5hdGVzIHBsb3R0ZWQgYW5kCiAgIyAgICAgICAgIGNlbGwtdHlwZXMgbGFiZWxlZCB3aXRoIGRhdGEgcG9pbnQgY29sb3JzLgoKICAjIFJ1biBVTUFQIHdpdGggYSBzcGVjaWZpZWQgbl9uZWlnaGJvcnMgcGFyYW1ldGVyCiAgc2NlX3VtYXAgPC0gc2NhdGVyOjpydW5VTUFQKHNjZSwgZGltcmVkID0gIlBDQSIsIG5fbmVpZ2hib3JzID0gbm5fcGFyYW0pCiAgc2NhdGVyOjpwbG90UmVkdWNlZERpbShzY2VfdW1hcCwgIlVNQVAiLCBjb2xvcl9ieSA9ICJkZXRlY3RlZCIpICsKICAgICMgbWFrZSB0aGUgbGVnZW5kIGxhYmVsIG1vcmUgaW5mb3JtYXRpdmUgKHRoaXMgaXMgZ2dwbG90MiBjb2RlISkKICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2NvbG9yYmFyKHRpdGxlPSJnZW5lc1xuZXhwcmVzc2VkIikpCn0KYGBgCgpMZXQncyBtYWtlIHN1cmUgdGhhdCB3b3JrcyBhbmQgZ2l2ZXMgdGhlIHNhbWUgcmVzdWx0IGFzIGJlZm9yZSB3aGVuIHdlIHVzZSB0aGUgZGVmYXVsdCBwYXJhbWV0ZXJzLgoKYGBge3IgZnVuY3Rpb24tdGVzdH0KVU1BUF9wbG90X3dyYXBwZXIobm5fcGFyYW0gPSAxNSkKYGBgCgoqS2luZCBvZj8qCgpUaGlzIGlzbid0IHlvdXIgZmF1bHQhClVNQVAgaXMgYSBub24tZGV0ZXJtaW5pc3RpYyBmdW5jdGlvbiwgd2hpY2ggbWVhbnMgdGhhdCB0aGVyZSBpcyBhIHJhbmRvbSBjb21wb25lbnQgdG8gdGhlIHJlc3VsdHMuCldlIGNhbiB1c2UgYHNldC5zZWVkKClgIHRvIGJlIHN1cmUgdGhhdCBhbiBpbmRpdmlkdWFsIHJ1biAob3Igc2V0IG9mIHJ1bnMpIGlzIHRoZSBzYW1lIGV2ZXJ5IHRpbWUgeW91IHJ1biB5b3VyIGFuYWx5c2lzLCBidXQgaXQgaXMgaW1wb3J0YW50IHRvIGNoZWNrIHlvdXIgcmVzdWx0cyBhIGZldyB0aW1lcyB3aXRoIGRpZmZlcmVudCByYW5kb20gc3RhcnRpbmcgcG9pbnRzIHRvIGJlIHN1cmUgdGhhdCB0aGUgcmFuZG9tIGNvbXBvbmVudCBpcyBub3QgZ2l2aW5nIHlvdSBhbm9tYWxvdXMgcmVzdWx0cy4KU2V0dGluZyBhIGRpZmZlcmVudCByYW5kb20gbnVtYmVyIHNlZWQgd2l0aCBgc2V0LnNlZWQoKWAgaXMgb25lIHdheSB0byBkbyB0aGlzLCBvciB5b3UgY2FuIHJ1biB0aGUgYW5hbHlzaXMgbXVsdGlwbGUgdGltZXMgaW4gdGhlIHNhbWUgc2Vzc2lvbiwgYXMgd2UgaGF2ZSBkb25lIGhlcmUuCgpGaWxsIGluIHRoZSBuZXh0IGZldyBjb2RlIGNodW5rcyB3aXRoIHRoZSBmdW5jdGlvbiBhbmQgdGhlIGBuX25laWdoYm9yc2AgYXJndW1lbnQgeW91IHdvdWxkIGxpa2UgdG8gdXNlIGZvciBlYWNoLgooRmVlbCBmcmVlIHRvIGFkZCBtb3JlIHRlc3RzISkKVGhlbiBydW4gdGhlIGNodW5rcyBhbmQgY29tcGFyZSB5b3VyIG91dHB1dCBncmFwaHMuCgpgYGB7ciBydW4tVU1BUC0xLCBsaXZlID0gVFJVRX0KIyBUcnkgc29tZXRoaW5nIGxvdz8KVU1BUF9wbG90X3dyYXBwZXIobm5fcGFyYW0gPSAzKQpgYGAKCmBgYHtyIHJ1bi1VTUFQLTIsIGxpdmUgPSBUUlVFfQojIFRyeSBzb21ldGhpbmcgaGlnaD8KVU1BUF9wbG90X3dyYXBwZXIobm5fcGFyYW0gPSAxMDApCmBgYAoKYGBge3IgcnVuLVVNQVAtMywgbGl2ZSA9IFRSVUV9CiMgVHJ5IHdoYXRldmVyIHlvdSBsaWtlIQpVTUFQX3Bsb3Rfd3JhcHBlcihubl9wYXJhbSA9IDUpCmBgYAoKIyMjIyBTb21lICdiaWcgcGljdHVyZScgdGhvdWdodHMgdG8gdGFrZSBmcm9tIHRoaXMgZXhwZXJpbWVudDoKCjEuIEFuYWx5c2VzIHN1Y2ggYXMgVU1BUCBoYXZlIHZhcmlvdXMgbGltaXRhdGlvbnMgZm9yIGludGVycHJldGFiaWxpdHkuClRoZSBjb29yZGluYXRlcyBvZiBVTUFQIG91dHB1dCBmb3IgYW55IGdpdmVuIGNlbGwgY2FuIGNoYW5nZSBkcmFtYXRpY2FsbHkgZGVwZW5kaW5nIG9uIHBhcmFtZXRlcnMsIGFuZCBldmVuIHJ1biB0byBydW4gd2l0aCB0aGUgc2FtZSBwYXJhbWV0ZXJzLgpUaGlzIHByb2JhYmx5IG1lYW5zIHRoYXQgeW91IHNob3VsZG4ndCByZWx5IG9uIHRoZSBleGFjdCB2YWx1ZXMgb2YgVU1BUCdzIG91dHB1dC4KCiAgICAtIE9uZSBwYXJ0aWN1bGFyIGxpbWl0YXRpb24gb2YgVU1BUCAoYW5kIHQtU05FKSBpcyB0aGF0IHdoaWxlIG9ic2VydmVkIGNsdXN0ZXJzIGhhdmUgc29tZSBtZWFuaW5nLCB0aGUgZGlzdGFuY2UgKmJldHdlZW4qIGNsdXN0ZXJzIHVzdWFsbHkgZG9lcyBub3QgKG5vciBkb2VzIGNsdXN0ZXIgZGVuc2l0eSkuCiAgICBUaGUgZmFjdCB0aGF0IHR3byBjbHVzdGVycyBhcmUgbmVhciBlYWNoIG90aGVyIHNob3VsZCBOT1QgYmUgaW50ZXJwcmV0ZWQgdG8gbWVhbiB0aGF0IHRoZXkgYXJlIG1vcmUgcmVsYXRlZCB0byBlYWNoIG90aGVyIHRoYW4gdG8gbW9yZSBkaXN0YW50IGNsdXN0ZXJzLgogICAgKFRoZXJlIGlzIHNvbWUgZGlzYWdyZWVtZW50IGFib3V0IHdoZXRoZXIgVU1BUCBkaXN0YW5jZXMgaGF2ZSBtb3JlIG1lYW5pbmcsIGJ1dCBpdCBpcyBwcm9iYWJseSBzYWZlciB0byBhc3N1bWUgdGhleSBkb24ndC4pCgoKMi4gUGxheWluZyB3aXRoIHBhcmFtZXRlcnMgc28geW91IGNhbiBmaW5lLXR1bmUgdGhlbSBpcyBhIGdvb2Qgd2F5IHRvIGdpdmUgeW91IG1vcmUgaW5mb3JtYXRpb24gYWJvdXQgYSBwYXJ0aWN1bGFyIGFuYWx5c2lzIGFzIHdlbGwgYXMgdGhlIGRhdGEgaXRzZWxmLgoKMy4gV2hlcmUgcmVzdWx0cyBhcmUgY29uc2lzdGVudCwgdGhleSBhcmUgbW9yZSBsaWtlbHkgdG8gaGF2ZSBtZWFuaW5nLgpXaGlsZSB3ZSBkbyBub3QgaGF2ZSBsYWJlbGVkIGNlbGwgdHlwZXMgaW4gdGhpcyBjYXNlLCB0aGVyZSBkb2VzIHNlZW0gdG8gYmUgc29tZSBjb25zaXN0ZW5jeSBvZiB0aGUgb3ZlcmFsbCBwYXR0ZXJucyB0aGF0IHdlIHNlZSAoaWYgbm90IHByZWNpc2UgdmFsdWVzKSwgYW5kIHRoaXMgbGlrZWx5IHJlZmxlY3RzIGJpb2xvZ2ljYWwgaW5mb3JtYXRpb24gKG9yIHRlY2huaWNhbCBhcnRpZmFjdHMpLgoKSW4gc3VtbWFyeSwgaWYgdGhlIHJlc3VsdHMgb2YgYW4gYW5hbHlzaXMgY2FuIGJlIGNvbXBsZXRlbHkgY2hhbmdlZCBieSBjaGFuZ2luZyBpdHMgcGFyYW1ldGVycywgeW91IHNob3VsZCBiZSBtb3JlIGNhdXRpb3VzIHdoZW4gaXQgY29tZXMgdG8gdGhlIGNvbmNsdXNpb25zIHlvdSBkcmF3IGZyb20gaXQgYXMgd2VsbCBhcyBoYXZpbmcgZ29vZCByYXRpb25hbGUgZm9yIHRoZSBwYXJhbWV0ZXJzIHlvdSBjaG9vc2UuCgojIyMgdC1TTkUgY29tcGFyaXNvbgoKSW4gdGhlIGJsb2NrIGJlbG93IGlzIGEgc2ltaWxhciBhbmFseXNpcyBhbmQgcGxvdCB3aXRoIHQtU05FICh0LWRpc3RyaWJ1dGVkIFN0b2NoYXN0aWMgTmVpZ2hib3IgRW1iZWRkaW5nKS4KTm90ZSB0aGF0IHRoaXMgYW5hbHlzaXMgYWxzbyB1c2VzIFBDQSBiZWZvcmUgbW92aW5nIG9uIHRvIHRoZSBmYW5jeSBtYWNoaW5lIGxlYXJuaW5nLgoKYGBge3IgdHNuZSwgbGl2ZSA9IFRSVUV9CiMgUnVuIFRTTkUKbm9ybWFsaXplZF9zY2UgPC0gcnVuVFNORShub3JtYWxpemVkX3NjZSwgZGltcmVkID0gIlBDQSIpCgojIHBsb3Qgd2l0aCBzY2F0ZXIgZnVuY3Rpb24KcGxvdFJlZHVjZWREaW0obm9ybWFsaXplZF9zY2UsICJUU05FIiwgY29sb3JfYnkgPSAiZGV0ZWN0ZWQiKQpgYGAKCkRpZmZlcmVudCEgKFNsb3dlciEpIElzIGl0IGJldHRlciBvciB3b3JzZT8gSGFyZCB0byBzYXkhCkRpZmZlcmVudCBwZW9wbGUgbGlrZSBkaWZmZXJlbnQgdGhpbmdzLCBhbmQgb25lIHBsb3QgbWlnaHQgaWxsdXN0cmF0ZSBhIHBhcnRpY3VsYXIgcG9pbnQgYmV0dGVyIHRoYW4gYW5vdGhlci4KCiMjIFNhdmUgcmVzdWx0cwoKV2UgYXJlIGdvaW5nIHRvIHVzZSB0aGlzIGRhdGEgbW9yZSBpbiB0aGUgbmV4dCBub3RlYm9vaywgc28gbGV0J3Mgc2F2ZSBpdCBhcyBhbiBgUkRTYCBmaWxlLgoKYGBge3Igc2F2ZX0KcmVhZHI6OndyaXRlX3Jkcyhub3JtYWxpemVkX3NjZSwgZmlsZSA9IG91dHB1dF9zY2VfZmlsZSkKYGBgCgoKIyMjIFNvbWUgZnVydGhlciByZWFkaW5nIG9uIGRpbWVuc2lvbiByZWR1Y3Rpb246CgotIFRoaXMgd2Vic2l0ZSBleHBsYWlucyBbUENBIHZpc3VhbGx5XShodHRwOi8vc2V0b3NhLmlvL2V2L3ByaW5jaXBhbC1jb21wb25lbnQtYW5hbHlzaXMvKS4KLSBbQmVjaHQgKmV0IGFsLiogKDIwMTgpXShodHRwczovL3d3dy5uYXR1cmUuY29tL2FydGljbGVzL25idC40MzE0KSBkaXNjdXNzZXMgdXNpbmcgW1VNQVBdKGh0dHBzOi8vZ2l0aHViLmNvbS9sbWNpbm5lcy91bWFwKSBmb3Igc2luZ2xlLWNlbGwgZGF0YS4KLSBbV2F0dGVuYmVyZyAqZXQgYWwuKiAoMjAxNildKGh0dHBzOi8vZGlzdGlsbC5wdWIvMjAxNi9taXNyZWFkLXRzbmUvKSBkaXNjdXNzIGhvdyB0byB1c2UgdC1TTkUgcHJvcGVybHkgd2l0aCBncmVhdCB2aXN1YWxzLgooVGhlIGxlc3NvbnMgYXBwbHkgdG8gVU1BUCBhcyB3ZWxsLCB3aXRoIGEgYnJvYWQgc3Vic3RpdHV0aW9uIG9mIHRoZSBgbl9uZWlnaGJvcnNgIHBhcmFtZXRlciBmb3IgYHBlcnBsZXhpdHlgLikKLSBbTmd1eWVuICYgSG9sbWVzICgyMDE5KV0oaHR0cHM6Ly9qb3VybmFscy5wbG9zLm9yZy9wbG9zY29tcGJpb2wvYXJ0aWNsZT9pZD0xMC4xMzcxL2pvdXJuYWwucGNiaS4xMDA2OTA3KSBsYXkgb3V0IGd1aWRlbGluZXMgb24gY2hvb3NpbmcgZGltZW5zaW9ucyByZWR1Y3Rpb24gbWV0aG9kcy4KLSBbRnJlaXRhZyAoMjAxOSldKGh0dHBzOi8vcnB1YnMuY29tL1Nhc2tpYS81MjAyMTYpIGlzIGEgbmljZSBleHBsYW5hdGlvbiBhbmQgY29tcGFyaXNvbiBvZiBtYW55IGRpZmZlcmVudCBkaW1lbnNpb25hbGl0eSByZWR1Y3Rpb24gdGVjaG5pcXVlcyB0aGF0IHlvdSBtYXkgZW5jb3VudGVyLgoKCiMjIFNlc3Npb24gSW5mbwoKYGBge3Igc2Vzc2lvbn0Kc2Vzc2lvbkluZm8oKQpgYGAK