diff --git a/analyses/hello-clusters/01_perform-evaluate-clustering.Rmd b/analyses/hello-clusters/01_perform-evaluate-clustering.Rmd index d7f2fbb55..80268a302 100644 --- a/analyses/hello-clusters/01_perform-evaluate-clustering.Rmd +++ b/analyses/hello-clusters/01_perform-evaluate-clustering.Rmd @@ -2,8 +2,8 @@ title: "Performing graph-based clustering with rOpenScPCA" date: "`r Sys.Date()`" author: "Data Lab" -output: - html_notebook: +output: + html_notebook: toc: yes toc_float: yes df_print: paged @@ -76,7 +76,6 @@ set.seed(2024) ## Read in and prepare data To begin, we'll read in the `SingleCellExperiment` (SCE) object. -We'll also establish a corresponding processed Seurat object from its raw counts that we'll use for some examples. ```{r read data} # Read the SCE file @@ -94,7 +93,7 @@ pca_matrix <- reducedDim(sce, "PCA") ## Perform clustering -This section will show how to perform clustering with the function `rOpenScPCA::calculate_clusters()`. +This section will show how to perform clustering with the function `rOpenScPCA::calculate_clusters()`. This function takes a PCA matrix with rownames representing unique cell ids (e.g., barcodes) as its primary argument. By default it will calculate clusters using the following parameters: @@ -152,7 +151,7 @@ cluster_results_df <- rOpenScPCA::calculate_clusters( ## Calculate QC metrics on clusters -This section demonstrates how to use several functions for evaluating cluster quality and reliability. +This section demonstrates how to use several functions for evaluating cluster quality and reliability. It's important to note that a full evaluation of clustering results would compare these metrics across a set of clustering results, with the aim of identifying an optimal parameterization. All functions presented in this section take the following required arguments: @@ -236,7 +235,7 @@ ggplot(purity_results) + ### Cluster stability -Another approach to exploring cluster quality is how stable the clusters themselves are using bootstrapping. +Another approach to exploring cluster quality is how stable the clusters themselves are using bootstrapping. Given a set of original clusters, we can compare the bootstrapped cluster identities to original ones using the Adjusted Rand Index (ARI), which measures the similarity of two data clusterings. ARI ranges from -1 to 1, where: @@ -276,7 +275,7 @@ ggplot(stability_results) + #### Using non-default clustering parameters -When calculating bootstrap clusters, `rOpenScPCA::calculate_stability()` uses `rOpenScPCA::calculate_clusters()` with default parameters. +When calculating bootstrap clusters, `rOpenScPCA::calculate_stability()` uses `rOpenScPCA::calculate_clusters()` with default parameters. If your original clusters were not calculated with these defaults, you should pass those customized values into this function as well to ensure a fair comparison between your original clusters and the bootstrap clusters. @@ -331,7 +330,6 @@ If you are analyzing your data with a Seurat pipeline that includes calculating To demonstrate this, we'll convert our SCE object to a Seurat using the function `rOpenScPCA::sce_to_seurat()`. Then, we'll use a simple Seurat pipeline to obtain clusters. - ```{r sce to seurat, message = FALSE} # Convert the SCE to a Seurat object using rOpenScPCA @@ -380,8 +378,8 @@ We do not recommend using `rOpenScPCA::calculate_stability()` on Seurat clusters ### Evaluating ScPCA clusters -ScPCA cell metadata already contains a column called `cluster` with results from an automated clustering. -These clusters were calculated using `bluster`, the same tool that `rOpenScPCA` uses. +ScPCA cell metadata already contains a column called `cluster` with results from an automated clustering. +These clusters were calculated using `bluster`, the same tool that `rOpenScPCA` uses. The specifications used for this clustering are stored in the SCE object's metadata, as follows; note that all other clustering parameters were left at their default values. * `metadata(sce)$cluster_algorithm`: The clustering algorithm used @@ -446,7 +444,7 @@ scpca_stability_df <- rOpenScPCA::calculate_stability( ``` -## Saving clustering results +## Saving clustering results Results can either be directly exported as a TSV file (e.g., with `readr::write_tsv()`), or you can add the results into your SCE or Seurat object. The subsequent examples will demonstrate saving the cluster assignments stored in `cluster_results_df$cluster` to an SCE and a Seurat object. @@ -456,7 +454,7 @@ Objects from the ScPCA Portal already contain a column called `cluster` with res These automatic clusters were not evaluated, and their parameters were not optimized for any given library. To avoid ambiguity between the existing and new clustering results, we'll name the new column `ropenscpca_cluster`. -### Saving results to an SCE object +### Saving results to an SCE object We can add columns to an SCE object's `colData` table by directly creating a column in the object with `$`. Before we do so, we'll confirm that the clusters are in the same order as the SCE object by comparing cell ids: @@ -473,7 +471,7 @@ all.equal( sce$ropenscpca_cluster <- cluster_results_df$cluster ``` -### Saving results to a Seurat object +### Saving results to a Seurat object We can add columns to an Seurat object's cell metadata table by directly creating a column in the object with `$` (note that you can also use the Seurat function `AddMetaData()`). diff --git a/analyses/hello-clusters/01_perform-evaluate-clustering.nb.html b/analyses/hello-clusters/01_perform-evaluate-clustering.nb.html index 702a46da2..bc5d1fd95 100644 --- a/analyses/hello-clusters/01_perform-evaluate-clustering.nb.html +++ b/analyses/hello-clusters/01_perform-evaluate-clustering.nb.html @@ -11,7 +11,7 @@ - + Performing graph-based clustering with rOpenScPCA @@ -2901,7 +2901,7 @@

Performing graph-based clustering with rOpenScPCA

Data Lab

-

2024-12-17

+

2024-12-20

@@ -3005,8 +3005,7 @@

Set the random seed

Read in and prepare data

To begin, we’ll read in the SingleCellExperiment (SCE) -object. We’ll also establish a corresponding processed Seurat object -from its raw counts that we’ll use for some examples.

+object.

@@ -3062,7 +3061,7 @@

Clustering with default parameters

@@ -3175,7 +3174,7 @@

Silhouette width

@@ -3191,7 +3190,7 @@

Silhouette width

labs(x = "Cluster", y = "Silhouette width") -

+

@@ -3228,7 +3227,7 @@

Neighborhood purity

@@ -3244,7 +3243,7 @@

Neighborhood purity

labs(x = "Cluster", y = "Neighborhood purity") -

+

@@ -3286,7 +3285,7 @@

Cluster stability

@@ -3302,7 +3301,7 @@

Cluster stability

labs(x = "Adjusted rand index across bootstrap replicates") -

+

@@ -3360,7 +3359,7 @@

Working with objects directly

@@ -3385,8 +3384,7 @@

Evaluating Seurat clusters

them.

To demonstrate this, we’ll convert our SCE object to a Seurat using the function rOpenScPCA::sce_to_seurat(). Then, we’ll use a -simple Seurat pipeline to obtain clusters. -

+simple Seurat pipeline to obtain clusters.

@@ -3406,24 +3404,31 @@

Evaluating Seurat clusters

FindNeighbors() |> FindClusters() - + +
Warning in irlba(A = t(x = object), nv = npcs, ...): You're computing too large
+a percentage of total singular values, use a standard svd instead.
+ + +
Warning: Number of dimensions changing from 10 to 50
+ +
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck
 
-Number of nodes: 2623
-Number of edges: 78853
+Number of nodes: 100
+Number of edges: 4142
 
 Running Louvain algorithm...
-Maximum modularity in 10 random starts: 0.8478
-Number of communities: 13
+Maximum modularity in 10 random starts: 0.2147
+Number of communities: 2
 Elapsed time: 0 seconds
seurat_obj
- +
An object of class Seurat 
-145743 features across 2623 samples within 3 assays 
-Active assay: SCT (25105 features, 3000 variable features)
+126242 features across 100 samples within 3 assays 
+Active assay: SCT (5604 features, 3000 variable features)
  3 layers present: counts, data, scale.data
  2 other assays present: RNA, spliced
  2 dimensional reductions calculated: pca, umap
@@ -3446,7 +3451,7 @@

Evaluating Seurat clusters

@@ -3538,7 +3543,7 @@

Evaluating ScPCA clusters

@@ -3771,7 +3776,7 @@

Session Info

-
LS0tCnRpdGxlOiAiUGVyZm9ybWluZyBncmFwaC1iYXNlZCBjbHVzdGVyaW5nIHdpdGggck9wZW5TY1BDQSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgphdXRob3I6ICJEYXRhIExhYiIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogICAgZGZfcHJpbnQ6IHBhZ2VkCi0tLQoKIyMgSW50cm9kdWN0aW9uCgpUaGlzIG5vdGVib29rIHByb3ZpZGVzIGV4YW1wbGVzIG9mIGhvdyB0byB1c2UgZnVuY3Rpb25zIGluIGByT3BlblNjUENBYCB0aGF0OgoKKiBQZXJmb3JtIGNsdXN0ZXJpbmcKKiBDYWxjdWxhdGUgUUMgbWV0cmljcyBvbiBjbHVzdGVycywgaW5jbHVkaW5nOgogICogU2lsaG91ZXR0ZSB3aWR0aAogICogTmVpZ2hib3Job29kIHB1cml0eQogICogQ2x1c3RlciBzdGFiaWxpdHksIGFzIG1lYXN1cmVkIHdpdGggdGhlIEFkanVzdGVkIFJhbmQgSW5kZXgKKiBDYWxjdWxhdGUgUUMgbWV0cmljcyBvbiBjbHVzdGVycyBvYnRhaW5lZCB3aXRoIG90aGVyIHRvb2xzLCBzdWNoIGFzIGBTZXVyYXRgCiogU2F2ZSBjbHVzdGVyaW5nIHJlc3VsdHMgdG8gYW4gU0NFIG9yIGBTZXVyYXRgCgpXaGlsZSB0aGlzIG5vdGVib29rIGRlbW9uc3RyYXRlcyBob3cgdG8gdXNlIGluZGl2aWR1YWwgZnVuY3Rpb25zIHRoYXQgY2FsY3VsYXRlIGhlbHBmdWwgbWV0cmljcyBmb3IgZXZhbHVhdGluZyBjbHVzdGVyaW5nIHJlc3VsdHMsIGEgZnVsbCBldmFsdWF0aW9uIHdvdWxkIGNvbXBhcmUgdGhlc2UgbWV0cmljcyBhY3Jvc3MgZGlmZmVyZW50IGNsdXN0ZXJpbmdzIGZyb20gZGlmZmVyZW50IHBhcmFtZXRlcml6YXRpb25zLgoKVGhpcyBub3RlYm9vayB3aWxsIHVzZSB0aGUgc2FtcGxlIGBTQ1BDUzAwMDAwMWAgZnJvbSBwcm9qZWN0IGBTQ1BDUDAwMDAwMWAsIHdoaWNoIGlzIGFzc3VtZWQgcHJlc2VudCBpbiB0aGUgYE9wZW5TY1BDQS1hbmFseXNpcy9kYXRhL2N1cnJlbnQvU0NQQ1AwMDAwMDFgIGRpcmVjdG9yeSwgZm9yIGFsbCBleGFtcGxlcy4KUGxlYXNlIFtzZWUgdGhpcyBkb2N1bWVudGF0aW9uXShodHRwczovL29wZW5zY3BjYS5yZWFkdGhlZG9jcy5pby9lbi9sYXRlc3QvZ2V0dGluZy1zdGFydGVkL2FjY2Vzc2luZy1yZXNvdXJjZXMvZ2V0dGluZy1hY2Nlc3MtdG8tZGF0YS8pIGZvciBtb3JlIGluZm9ybWF0aW9uIGFib3V0IG9idGFpbmluZyBTY1BDQSBkYXRhLgoKIyMgU2V0dXAKCiMjIyBQYWNrYWdlcwoKCmBgYHtyIHBhY2thZ2VzfQpsaWJyYXJ5KHJPcGVuU2NQQ0EpCgpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMoewogIGxpYnJhcnkoU2luZ2xlQ2VsbEV4cGVyaW1lbnQpCiAgbGlicmFyeShTZXVyYXQpCiAgbGlicmFyeShkcGx5cikKICBsaWJyYXJ5KGdncGxvdDIpCn0pCgojIFNldCBnZ3Bsb3QgdGhlbWUgZm9yIHBsb3RzCnRoZW1lX3NldCh0aGVtZV9idygpKQpgYGAKCgojIyMgUGF0aHMKCmBgYHtyIGJhc2UgcGF0aHN9CiMgVGhlIGJhc2UgcGF0aCBmb3IgdGhlIE9wZW5TY1BDQSByZXBvc2l0b3J5CnJlcG9zaXRvcnlfYmFzZSA8LSBycHJvanJvb3Q6OmZpbmRfcm9vdChycHJvanJvb3Q6OmlzX2dpdF9yb290KQoKIyBUaGUgY3VycmVudCBkYXRhIGRpcmVjdG9yeSwgZm91bmQgd2l0aGluIHRoZSByZXBvc2l0b3J5IGJhc2UgZGlyZWN0b3J5CmRhdGFfZGlyIDwtIGZpbGUucGF0aChyZXBvc2l0b3J5X2Jhc2UsICJkYXRhIiwgImN1cnJlbnQiKQoKIyBUaGUgcGF0aCB0byB0aGlzIG1vZHVsZQptb2R1bGVfYmFzZSA8LSBmaWxlLnBhdGgocmVwb3NpdG9yeV9iYXNlLCAiYW5hbHlzZXMiLCAiaGVsbG8tY2x1c3RlcnMiKQpgYGAKCmBgYHtyIGlucHV0IGZpbGUgcGF0aH0KIyBQYXRoIHRvIHByb2Nlc3NlZCBTQ0UgZmlsZSBmb3Igc2FtcGxlIFNDUENTMDAwMDAxCmlucHV0X3NjZV9maWxlIDwtIGZpbGUucGF0aChkYXRhX2RpciwgIlNDUENQMDAwMDAxIiwgIlNDUENTMDAwMDAxIiwgIlNDUENMMDAwMDAxX3Byb2Nlc3NlZC5yZHMiKQpgYGAKCgojIyMgU2V0IHRoZSByYW5kb20gc2VlZAoKQmVjYXVzZSBjbHVzdGVyaW5nIGludm9sdmVzIHJhbmRvbSBzYW1wbGluZywgaXQgaXMgaW1wb3J0YW50IHRvIHNldCB0aGUgcmFuZG9tIHNlZWQgYXQgdGhlIHRvcCBvZiB5b3VyIGFuYWx5c2lzIHNjcmlwdCBvciBub3RlYm9vayB0byBlbnN1cmUgcmVwcm9kdWNpYmlsaXR5LgoKYGBge3Igc2V0IHNlZWR9CnNldC5zZWVkKDIwMjQpCmBgYAoKIyMgUmVhZCBpbiBhbmQgcHJlcGFyZSBkYXRhCgpUbyBiZWdpbiwgd2UnbGwgcmVhZCBpbiB0aGUgYFNpbmdsZUNlbGxFeHBlcmltZW50YCAoU0NFKSBvYmplY3QuCldlJ2xsIGFsc28gZXN0YWJsaXNoIGEgY29ycmVzcG9uZGluZyBwcm9jZXNzZWQgU2V1cmF0IG9iamVjdCBmcm9tIGl0cyByYXcgY291bnRzIHRoYXQgd2UnbGwgdXNlIGZvciBzb21lIGV4YW1wbGVzLgoKYGBge3IgcmVhZCBkYXRhfQojIFJlYWQgdGhlIFNDRSBmaWxlCnNjZSA8LSByZWFkUkRTKGlucHV0X3NjZV9maWxlKQpgYGAKCkZvciB0aGUgaW5pdGlhbCBjbHVzdGVyIGNhbGN1bGF0aW9ucyBhbmQgZXZhbHVhdGlvbnMsIHdlIHdpbGwgdXNlIHRoZSBQQ0EgbWF0cml4IGV4dHJhY3RlZCBmcm9tIHRoZSBTQ0Ugb2JqZWN0LgpJdCdzIGFsc28gcG9zc2libGUgdG8gdXNlIGFuIFNDRSBvYmplY3Qgb3IgYSBTZXVyYXQgb2JqZWN0IGRpcmVjdGx5LCB3aGljaCB3ZSB3aWxsIGRlbW9uc3RyYXRlIGxhdGVyLgoKCmBgYHtyIGV4dHJhY3QgcGNhIGRhdGF9CiMgRXh0cmFjdCB0aGUgUENBIG1hdHJpeCBmcm9tIGFuIFNDRSBvYmplY3QKcGNhX21hdHJpeCA8LSByZWR1Y2VkRGltKHNjZSwgIlBDQSIpCmBgYAoKIyMgUGVyZm9ybSBjbHVzdGVyaW5nCgpUaGlzIHNlY3Rpb24gd2lsbCBzaG93IGhvdyB0byBwZXJmb3JtIGNsdXN0ZXJpbmcgd2l0aCB0aGUgZnVuY3Rpb24gYHJPcGVuU2NQQ0E6OmNhbGN1bGF0ZV9jbHVzdGVycygpYC4gCgpUaGlzIGZ1bmN0aW9uIHRha2VzIGEgUENBIG1hdHJpeCB3aXRoIHJvd25hbWVzIHJlcHJlc2VudGluZyB1bmlxdWUgY2VsbCBpZHMgKGUuZy4sIGJhcmNvZGVzKSBhcyBpdHMgcHJpbWFyeSBhcmd1bWVudC4KQnkgZGVmYXVsdCBpdCB3aWxsIGNhbGN1bGF0ZSBjbHVzdGVycyB1c2luZyB0aGUgZm9sbG93aW5nIHBhcmFtZXRlcnM6CgoqIExvdXZhaW4gYWxnb3JpdGhtCiogSmFjY2FyZCB3ZWlnaHRpbmcKKiAxMCBuZWFyZXN0IG5laWdoYm9ycwoqIEEgcmVzb2x1dGlvbiBwYXJhbWV0ZXIgb2YgMQoKVGhpcyBmdW5jdGlvbiB3aWxsIHJldHVybiBhIHRhYmxlIHdpdGggdGhlIGZvbGxvd2luZyBjb2x1bW5zOgoKKiBgY2VsbF9pZGA6IFVuaXF1ZSBjZWxsIGlkZW50aWZpZXJzLCBvYnRhaW5lZCBmcm9tIHRoZSBQQ0EgbWF0cml4J3Mgcm93IG5hbWVzCiogYGNsdXN0ZXJgOiBBIGZhY3RvciBjb2x1bW4gd2l0aCB0aGUgY2x1c3RlciBpZGVudGl0aWVzCiogVGhlcmUgd2lsbCBiZSBvbmUgY29sdW1uIGZvciBlYWNoIGNsdXN0ZXJpbmcgcGFyYW1ldGVyIHVzZWQKCgojIyMgQ2x1c3RlcmluZyB3aXRoIGRlZmF1bHQgcGFyYW1ldGVycwoKYGBge3IgY2x1c3RlciBzY2V9CiMgQ2FsY3VsYXRlIGNsdXN0ZXJzIHdpdGggZGVmYXVsdCBwYXJhbWV0ZXJzCmNsdXN0ZXJfcmVzdWx0c19kZiA8LSByT3BlblNjUENBOjpjYWxjdWxhdGVfY2x1c3RlcnMocGNhX21hdHJpeCkKCiMgUHJpbnQgdGhlIGZpcnN0IHJvd3Mgb2YgdGhlIHJlc3VsdGluZyB0YWJsZQpoZWFkKGNsdXN0ZXJfcmVzdWx0c19kZikKYGBgCgojIyMgQ2x1c3RlcmluZyB3aXRoIG5vbi1kZWZhdWx0IHBhcmFtZXRlcnMKClBhcmFtZXRlcnMgdXNlZCBmb3IgY2x1c3RlcmluZyBjYW4gYmUgY3VzdG9taXplZCB3aXRoIHRoZXNlIGFyZ3VtZW50czoKCiogVGhlIGBhbGdvcml0aG1gIGNhbiBiZSBvbmUgb2Y6CiAgKiBgbG91dmFpbmAsIGB3YWxrdHJhcGAsIG9yIGBsZWlkZW5gCiogVGhlIGB3ZWlnaHRpbmdgIGNhbiBiZSBvbmUgb2Y6CiAgKiBgamFjY2FyZGAsIGByYW5rYCwgb3IgYG51bWJlcmAKKiBUaGUgbmVhcmVzdCBuZWlnaGJvcnMgcGFyYW1ldGVyIGNhbiBiZSBjdXN0b21pemVkIHdpdGggdGhlIGBubmAgYXJndW1lbnQKKiBUaGUgcmVzb2x1dGlvbiBwYXJhbWV0ZXIgY2FuIGJlIGN1c3RvbWl6ZWQgd2l0aCB0aGUgYHJlc29sdXRpb25gIGFyZ3VtZW50CiAgKiBUaGlzIHBhcmFtZXRlciBpcyBvbmx5IHVzZWQgYnkgTG91dmFpbiBhbmQgTGVpZGVuIGFsZ29yaXRobXMKKiBJZiB0aGUgTGVpZGVuIGFsZ29yaXRobSBpcyB1c2VkLCBpdHMgZGVmYXVsdCBvYmplY3RpdmUgZnVuY3Rpb24gcGFyYW1ldGVyIHdpbGwgYmUgYENQTWAsIGJ1dCB5b3UgY2FuIGFsc28gc2V0ICBgb2JqZWN0aXZlX2Z1bmN0aW9uID0gIm1vZHVsYXJpdHkiYCBpbnN0ZWFkLgoqIFlvdSBjYW4gcHJvdmlkZSBhZGRpdGlvbmFsIHBhcmFtZXRlcnMgYXMgYSBsaXN0IHRvIHRoZSBgY2x1c3Rlcl9hcmdzYCBhcmd1bWVudC4KICAqIFBsZWFzZSByZWZlciB0byB0aGUgW2BpZ3JhcGhgIGRvY3VtZW50YXRpb25dKGh0dHBzOi8vaWdyYXBoLm9yZy9yL2h0bWwvbGF0ZXN0KSB0byBsZWFybiBtb3JlIGFib3V0IHdoYXQgYWRkaXRpb25hbCBwYXJhbWV0ZXJzIGNhbiBiZSBwcm92aWRlZCB0byBlYWNoIGNsdXN0ZXJpbmcgYWxnb3JpdGhtLgogICogTm90ZSB0aGF0IGBjbHVzdGVyX2FyZ3NgIG9ubHkgYWNjZXB0cyBzaW5nbGUtbGVuZ3RoIGFyZ3VtZW50cyAobm8gdmVjdG9ycyBvciBsaXN0cykuCgpGb3IgZXhhbXBsZToKCmBgYHtyIGNsdXN0ZXIgc2NlIG5vbmRlZmF1bHR9CiMgQ2FsY3VsYXRlIGNsdXN0ZXJzIHdpdGggbm9uLWRlZmF1bHQgcGFyYW1ldGVycwpjbHVzdGVyX3Jlc3VsdHNfZGYgPC0gck9wZW5TY1BDQTo6Y2FsY3VsYXRlX2NsdXN0ZXJzKAogIHBjYV9tYXRyaXgsCiAgYWxnb3JpdGhtID0gImxlaWRlbiIsCiAgbm4gPSAxNSwKICBvYmplY3RpdmVfZnVuY3Rpb24gPSAibW9kdWxhcml0eSIKKQpgYGAKCgojIyBDYWxjdWxhdGUgUUMgbWV0cmljcyBvbiBjbHVzdGVycwoKVGhpcyBzZWN0aW9uIGRlbW9uc3RyYXRlcyBob3cgdG8gdXNlIHNldmVyYWwgZnVuY3Rpb25zIGZvciBldmFsdWF0aW5nIGNsdXN0ZXIgcXVhbGl0eSBhbmQgcmVsaWFiaWxpdHkuIApJdCdzIGltcG9ydGFudCB0byBub3RlIHRoYXQgYSBmdWxsIGV2YWx1YXRpb24gb2YgY2x1c3RlcmluZyByZXN1bHRzIHdvdWxkIGNvbXBhcmUgdGhlc2UgbWV0cmljcyBhY3Jvc3MgYSBzZXQgb2YgY2x1c3RlcmluZyByZXN1bHRzLCB3aXRoIHRoZSBhaW0gb2YgaWRlbnRpZnlpbmcgYW4gb3B0aW1hbCBwYXJhbWV0ZXJpemF0aW9uLgoKQWxsIGZ1bmN0aW9ucyBwcmVzZW50ZWQgaW4gdGhpcyBzZWN0aW9uIHRha2UgdGhlIGZvbGxvd2luZyByZXF1aXJlZCBhcmd1bWVudHM6CgoqIEEgUENBIG1hdHJpeCB3aXRoIHJvdyBuYW1lcyByZXByZXNlbnRpbmcgdW5pcXVlIGNlbGwgaWRzIChlLmcuLCBiYXJjb2RlcykKKiBBIGRhdGEgZnJhbWUgd2l0aCwgYXQgbGVhc3QsIGNvbHVtbnMgcmVwcmVzZW50aW5nIHVuaXF1ZSBjZWxsIGlkcyBhbmQgY2x1c3RlciBhc3NpZ25tZW50cwogICogQnkgZGVmYXVsdCwgdGhlc2UgY29sdW1ucyBzaG91bGQgYmUgbmFtZWQgYGNlbGxfaWRgIGFuZCBgY2x1c3RlcmAsIHJlc3BlY3RpdmVseSwgbWF0Y2hpbmcgdGhlIG91dHB1dCBvZiBgck9wZW5TY1BDQTo6Y2FsY3VsYXRlX2NsdXN0ZXJzKClgCiAgKiBZb3UgY2FuIG92ZXJyaWRlIHRoZXNlIGRlZmF1bHRzIHVzaW5nIHRoZSBhcmd1bWVudHMgYGNlbGxfaWRfY29sYCBhbmQgYGNsdXN0ZXJfY29sYAoKIyMjIFNpbGhvdWV0dGUgd2lkdGgKClNpbGhvdWV0dGUgd2lkdGggaXMgYSBjb21tb24gbWV0cmljIHRoYXQgbWVhc3VyZXMgaG93IHdlbGwgc2VwYXJhdGVkIGNsdXN0ZXJzIGFyZSBieSwgZm9yIGVhY2ggY2VsbCwgY29tcGFyaW5nIHRoZSBhdmVyYWdlIGRpc3RhbmNlIHRvIGFsbCBjZWxscyBpbiB0aGUgc2FtZSBjbHVzdGVyLCBhbmQgYWxsIGNlbGxzIGluIG90aGVyIGNsdXN0ZXJzLgpUaGlzIHZhbHVlIHJhbmdlcyBmcm9tIC0xIHRvIDEuCkNlbGxzIGluIHdlbGwtc2VwYXJhdGVkIGNsdXN0ZXJzIHNob3VsZCBoYXZlIGhpZ2ggc2lsaG91ZXR0ZSB2YWx1ZXMgY2xvc2VyIHRvIDEuCllvdSBjYW4gcmVhZCBtb3JlIGFib3V0IHNpbGhvdWV0dGUgd2lkdGggcHVyaXR5IGZyb20gdGhlIFtfT3JjaGVzdHJhdGluZyBTaW5nbGUgQ2VsbCBBbmFseXNpcyB3aXRoIEJpb2NvbmR1Y3Rvcl8gYm9va10oaHR0cHM6Ly9iaW9jb25kdWN0b3Iub3JnL2Jvb2tzLzMuMTkvT1NDQS5hZHZhbmNlZC9jbHVzdGVyaW5nLXJlZHV4Lmh0bWwjc2lsaG91ZXR0ZS13aWR0aCkuCgpXZSdsbCB1c2UgdGhlIGZ1bmN0aW9uIGByT3BlblNjUENBOjpjYWxjdWxhdGVfc2lsaG91ZXR0ZSgpYCB0byBjYWxjdWxhdGUgdGhlIHNpbGhvdWV0dGUgd2lkdGguCgpUaGlzIGZ1bmN0aW9uIHdpbGwgcmV0dXJuIHRoZSBpbnB1dHRlZCBkYXRhIGZyYW1lIHdpdGggdHdvIGFkZGl0aW9uYWwgY29sdW1uczoKCiogYHNpbGhvdWV0dGVfd2lkdGhgOiBUaGUgY2FsY3VsYXRlZCBzaWxob3VldHRlIHdpZHRoIGZvciB0aGUgY2VsbAoqIGBzaWxob3VldHRlX290aGVyYDogVGhlIGNsb3NldCBjbHVzdGVyIHRvIHRoZSBjZWxsIGJlc2lkZXMgdGhlIGNsdXN0ZXIgdG8gd2hpY2ggaXQgYmVsb25ncywgYXMgdXNlZCBpbiB0aGUgc2lsaG91ZXR0ZSB3aWR0aCBjYWxjdWxhdGlvbgoKCmBgYHtyIHNpbGhvdWV0dGV9CiMgY2FsY3VsYXRlIHRoZSBzaWxob3VldHRlIHdpZHRoIGZvciBlYWNoIGNlbGwKc2lsaG91ZXR0ZV9yZXN1bHRzIDwtIHJPcGVuU2NQQ0E6OmNhbGN1bGF0ZV9zaWxob3VldHRlKAogIHBjYV9tYXRyaXgsCiAgY2x1c3Rlcl9yZXN1bHRzX2RmCikKCiMgUHJpbnQgdGhlIGZpcnN0IHJvd3Mgb2YgdGhlIHJlc3VsdGluZyB0YWJsZQpoZWFkKHNpbGhvdWV0dGVfcmVzdWx0cykKYGBgCgoKV2UgY2FuIHZpc3VhbGl6ZSB0aGVzZSByZXN1bHRzIGJ5IHBsb3R0aW5nIHNpbGhvdWV0dGUgd2lkdGggYWNyb3NzIGNsdXN0ZXJzIGFzIHZpb2xpbiBwbG90cywgZm9yIGV4YW1wbGU6CgpgYGB7ciB2aW9saW4gc2lsaG91ZXR0ZX0KZ2dwbG90KHNpbGhvdWV0dGVfcmVzdWx0cykgKwogIGFlcyh4ID0gY2x1c3RlciwgeSA9IHNpbGhvdWV0dGVfd2lkdGgpICsKICBnZW9tX3Zpb2xpbihmaWxsID0gImRhcmttYWdlbnRhIikgKwogIGxhYnMoeCA9ICJDbHVzdGVyIiwgeSA9ICJTaWxob3VldHRlIHdpZHRoIikKYGBgCgojIyMgTmVpZ2hib3Job29kIHB1cml0eQoKTmVpZ2hib3Job29kIHB1cml0eSBpcyBkZWZpbmVkLCBmb3IgZWFjaCBjZWxsLCBhcyB0aGUgcHJvcG9ydGlvbiBvZiBuZWlnaGJvcmluZyBjZWxscyB0aGF0IGFyZSBhc3NpZ25lZCB0byB0aGUgc2FtZSBjbHVzdGVyLgpUaGlzIHZhbHVlIHJhbmdlcyBmcm9tIDAgdG8gMS4KQ2VsbHMgaW4gd2VsbC1zZXBhcmF0ZWQgY2x1c3RlcnMgc2hvdWxkIGhhdmUgaGlnaCBwdXJpdHkgdmFsdWVzIGNsb3NlciB0byAxLCBzaW5jZSB0aGVyZSBzaG91bGQgYmUgbWluaW1hbCBvdmVybGFwIGJldHdlZW4gbWVtYmVyIGFuZCBuZWlnaGJvcmluZyBjZWxscy4KWW91IGNhbiByZWFkIG1vcmUgYWJvdXQgbmVpZ2hib3Job29kIHB1cml0eSBmcm9tIHRoZSBbX09yY2hlc3RyYXRpbmcgU2luZ2xlIENlbGwgQW5hbHlzaXMgd2l0aCBCaW9jb25kdWN0b3JfIGJvb2tdKGh0dHBzOi8vYmlvY29uZHVjdG9yLm9yZy9ib29rcy8zLjE5L09TQ0EuYWR2YW5jZWQvY2x1c3RlcmluZy1yZWR1eC5odG1sI2NsdXN0ZXItcHVyaXR5KS4KCldlJ2xsIHVzZSB0aGUgZnVuY3Rpb24gYHJPcGVuU2NQQ0E6OmNhbGN1bGF0ZV9wdXJpdHkoKWAgdG8gY2FsY3VsYXRlIHRoZSBuZWlnaGJvcmhvb2QgcHVyaXR5LgoKVGhpcyBmdW5jdGlvbiB3aWxsIHJldHVybiB0aGUgaW5wdXR0ZWQgZGF0YSBmcmFtZSB3aXRoIHR3byBhZGRpdGlvbmFsIGNvbHVtbnM6CgoqIGBwdXJpdHlgOiBUaGUgbmVpZ2hib3Job29kIHB1cml0eSBmb3IgdGhlIGNlbGwKKiBgbWF4aW11bV9uZWlnaGJvcmA6IFRoZSBjbHVzdGVyIHdpdGggdGhlIGhpZ2hlc3QgcHJvcG9ydGlvbiBvZiBvYnNlcnZhdGlvbnMgbmVpZ2hib3JpbmcgdGhlIGNlbGwKCgpgYGB7ciBwdXJpdHl9CiMgY2FsY3VsYXRlIHRoZSBuZWlnaGJvcmhvb2QgcHVyaXR5IGZvciBlYWNoIGNlbGwKcHVyaXR5X3Jlc3VsdHMgPC0gck9wZW5TY1BDQTo6Y2FsY3VsYXRlX3B1cml0eSgKICBwY2FfbWF0cml4LAogIGNsdXN0ZXJfcmVzdWx0c19kZgopCgojIFByaW50IHRoZSBmaXJzdCByb3dzIG9mIHRoZSByZXN1bHRpbmcgdGFibGUKaGVhZChwdXJpdHlfcmVzdWx0cykKYGBgCgoKV2UgY2FuIHZpc3VhbGl6ZSB0aGVzZSByZXN1bHRzIGJ5IHBsb3R0aW5nIHB1cml0eSBjbHVzdGVycyBhcyB2aW9saW4gcGxvdHMsIGZvciBleGFtcGxlOgoKYGBge3IgdmlvbGluIHB1cml0eX0KZ2dwbG90KHB1cml0eV9yZXN1bHRzKSArCiAgYWVzKHggPSBjbHVzdGVyLCB5ID0gcHVyaXR5KSArCiAgZ2VvbV92aW9saW4oZmlsbCA9ICJkYXJrb2xpdmVncmVlbjMiKSArCiAgbGFicyh4ID0gIkNsdXN0ZXIiLCB5ID0gIk5laWdoYm9yaG9vZCBwdXJpdHkiKQpgYGAKCiMjIyBDbHVzdGVyIHN0YWJpbGl0eQoKQW5vdGhlciBhcHByb2FjaCB0byBleHBsb3JpbmcgY2x1c3RlciBxdWFsaXR5IGlzIGhvdyBzdGFibGUgdGhlIGNsdXN0ZXJzIHRoZW1zZWx2ZXMgYXJlIHVzaW5nIGJvb3RzdHJhcHBpbmcuIApHaXZlbiBhIHNldCBvZiBvcmlnaW5hbCBjbHVzdGVycywgd2UgY2FuIGNvbXBhcmUgdGhlIGJvb3RzdHJhcHBlZCBjbHVzdGVyIGlkZW50aXRpZXMgdG8gb3JpZ2luYWwgb25lcyB1c2luZyB0aGUgQWRqdXN0ZWQgUmFuZCBJbmRleCAoQVJJKSwgd2hpY2ggbWVhc3VyZXMgdGhlIHNpbWlsYXJpdHkgb2YgdHdvIGRhdGEgY2x1c3RlcmluZ3MuCkFSSSByYW5nZXMgZnJvbSAtMSB0byAxLCB3aGVyZToKCiogQSB2YWx1ZSBvZiAxIGluZGljYXRlcyB0aGV5IGFyZSBjb21wbGV0ZWx5IG92ZXJsYXBwaW5nCiogQSB2YWx1ZSBvZiAtMSBpbmRpY2F0ZXMgdGhleSBhcmUgY29tcGxldGVseSBkaXN0aW5jdAoqIEEgdmFsdWUgb2YgMCBpbmRpY2F0ZXMgYSByYW5kb20gcmVsYXRpb25zaGlwCgpXZSBleHBlY3QgdGhhdCBoaWdobHkgc3RhYmxlIGNsdXN0ZXJpbmdzIGhhdmUgQVJJIHZhbHVlcyBjbG9zZXIgdG8gMSBhY3Jvc3MgYSBzZXQgb2YgYm9vdHN0cmFwIHJlcGxpY2F0ZXMuCgpZb3UgY2FuIHJlYWQgbW9yZSBhYm91dCB0aGUgQWRqdXN0ZWQgUmFuZCBJbmRleCBmcm9tIHRoZSBbX09yY2hlc3RyYXRpbmcgU2luZ2xlIENlbGwgQW5hbHlzaXMgd2l0aCBCaW9jb25kdWN0b3JfIGJvb2tdKGh0dHBzOi8vYmlvY29uZHVjdG9yLm9yZy9ib29rcy9yZWxlYXNlL09TQ0EuYWR2YW5jZWQvY2x1c3RlcmluZy1yZWR1eC5odG1sI2FkanVzdGVkLXJhbmQtaW5kZXgpLgoKV2UnbGwgdXNlIHRoZSBmdW5jdGlvbiBgck9wZW5TY1BDQTo6Y2FsY3VsYXRlX3N0YWJpbGl0eSgpYCB0byBjYWxjdWxhdGUgdGhlIGNsdXN0ZXIgc3RhYmlsaXR5LgpCeSBkZWZhdWx0LCB0aGlzIGZ1bmN0aW9uIHBlcmZvcm1zIDIwIGJvb3RzdHJhcCByZXBsaWNhdGVzLCBidXQgdGhpcyBjYW4gYmUgY3VzdG9taXplZCB1c2luZyB0aGUgYXJndW1lbnQgYHJlcGxpY2F0ZXNgLgoKVGhpcyBmdW5jdGlvbiB3aWxsIHJldHVybiBhIGRhdGEgZnJhbWUgd2l0aCBjb2x1bW5zIGByZXBsaWNhdGVgLCBgYXJpYCwgYW5kIGFkZGl0aW9uYWwgY29sdW1ucyBmb3IgdGhlIGNsdXN0ZXJpbmcgcGFyYW1ldGVycyB1c2VkIHdoZW4gY2FsY3VsYXRpbmcgYm9vdHN0cmFwIGNsdXN0ZXJzLgoKYGBge3Igc3RhYmlsaXR5LCB3YXJuaW5nPUZBTFNFfQojIGNhbGN1bGF0ZSB0aGUgc3RhYmlsaXR5IG9mIGNsdXN0ZXJzCnN0YWJpbGl0eV9yZXN1bHRzIDwtIHJPcGVuU2NQQ0E6OmNhbGN1bGF0ZV9zdGFiaWxpdHkoCiAgcGNhX21hdHJpeCwKICBjbHVzdGVyX3Jlc3VsdHNfZGYKKQoKIyBwcmludCB0aGUgcmVzdWx0CnN0YWJpbGl0eV9yZXN1bHRzCmBgYAoKV2UgY2FuIHZpc3VhbGl6ZSB0aGVzZSByZXN1bHRzIGJ5IHBsb3R0aW5nIHN0YWJpbGl0eSBhcyBhIGRlbnNpdHkgcGxvdCwgZm9yIGV4YW1wbGU6CgpgYGB7ciBhcmkgZGVuc2l0eX0KZ2dwbG90KHN0YWJpbGl0eV9yZXN1bHRzKSArCiAgYWVzKHggPSBhcmkpICsKICBnZW9tX2RlbnNpdHkoY29sb3IgPSAiZ3JleTMwIiwgZmlsbCA9ICJsaWdodHNsYXRlYmx1ZSIpICsKICBsYWJzKHggPSAiQWRqdXN0ZWQgcmFuZCBpbmRleCBhY3Jvc3MgYm9vdHN0cmFwIHJlcGxpY2F0ZXMiKQpgYGAKCgojIyMjIFVzaW5nIG5vbi1kZWZhdWx0IGNsdXN0ZXJpbmcgcGFyYW1ldGVycwoKV2hlbiBjYWxjdWxhdGluZyBib290c3RyYXAgY2x1c3RlcnMsIGByT3BlblNjUENBOjpjYWxjdWxhdGVfc3RhYmlsaXR5KClgIHVzZXMgYHJPcGVuU2NQQ0E6OmNhbGN1bGF0ZV9jbHVzdGVycygpYCB3aXRoIGRlZmF1bHQgcGFyYW1ldGVycy4gCklmIHlvdXIgb3JpZ2luYWwgY2x1c3RlcnMgd2VyZSBub3QgY2FsY3VsYXRlZCB3aXRoIHRoZXNlIGRlZmF1bHRzLCB5b3Ugc2hvdWxkIHBhc3MgdGhvc2UgY3VzdG9taXplZCB2YWx1ZXMgaW50byB0aGlzIGZ1bmN0aW9uIGFzIHdlbGwgdG8gZW5zdXJlIGEgZmFpciBjb21wYXJpc29uIGJldHdlZW4geW91ciBvcmlnaW5hbCBjbHVzdGVycyBhbmQgdGhlIGJvb3RzdHJhcCBjbHVzdGVycy4KCgpgYGB7ciBzdGFiaWxpdHkgY3VzdG9tIHBhcmFtZXRlcnN9CiMgQ2FsY3VsYXRlIGNsdXN0ZXJzIHdpdGggbm9uLWRlZmF1bHQgcGFyYW1ldGVycwpjbHVzdGVyX2RmX2xlaWRlbiA8LSByT3BlblNjUENBOjpjYWxjdWxhdGVfY2x1c3RlcnMoCiAgcGNhX21hdHJpeCwKICBhbGdvcml0aG0gPSAibGVpZGVuIiwKICByZXNvbHV0aW9uID0gMC41LAogIG5uID0gMTUKKQoKIyBOb3csIHBhc3MgaW4gdGhlIHNhbWUgYXJndW1lbnRzIGN1c3RvbWl6aW5nIHBhcmFtZXRlcnMgaGVyZQpzdGFiaWxpdHlfcmVzdWx0c19sZWlkZW4gPC0gck9wZW5TY1BDQTo6Y2FsY3VsYXRlX3N0YWJpbGl0eSgKICBwY2FfbWF0cml4LAogIGNsdXN0ZXJfZGZfbGVpZGVuLAogIGFsZ29yaXRobSA9ICJsZWlkZW4iLAogIHJlc29sdXRpb24gPSAwLjUsCiAgbm4gPSAxNQopCmBgYAoKCiMjIFdvcmtpbmcgd2l0aCBvYmplY3RzIGRpcmVjdGx5CgpBcyBwcmVzZW50ZWQgYWJvdmUsIGByT3BlblNjUENBYCBjbHVzdGVyaW5nIGZ1bmN0aW9ucyB0YWtlIGEgUENBIG1hdHJpeCB3aXRoIHJvdyBuYW1lcyByZXByZXNlbnRpbmcgdW5pcXVlIGNlbGwgaWRzIGFzIHRoZWlyIGZpcnN0IGFyZ3VtZW50LgoKSW5zdGVhZCBvZiBhIG1hdHJpeCwgeW91IGNhbiBhbHRlcm5hdGl2ZWx5IHBhc3MgaW4gYW4gU0NFIG9yIFNldXJhdCBvYmplY3QgdGhhdCBjb250YWlucyBhIG1hdHJpeC4KCldlIHNob3cgYW4gZXhhbXBsZSBvZiB0aGlzIGJlbG93IHdpdGggYW5kIFNDRSBvYmplY3QgYW5kIGByT3BlblNjUENBOjpjYWxjdWxhdGVfY2x1c3RlcnMoKWAsIGJ1dCB0aGlzIHdpbGwgYWxzbyB3b3JrIGZvciBhbnkgb2YgdGhlIGV2YWx1YXRpb24gZnVuY3Rpb25zIGFzIHdlbGwgYW5kIGhhcyB0aGUgc2FtZSBzeW50YXggZm9yIFNldXJhdCBvYmplY3RzLgoKYGBge3IgcnVuIG9uIHNjZX0KIyBDYWxjdWxhdGUgY2x1c3RlcnMgZnJvbSBhbiBTQ0Ugb2JqZWN0IHVzaW5nIGRlZmF1bHQgcGFyYW1ldGVycwpjbHVzdGVyX3Jlc3VsdHNfZGYgPC0gck9wZW5TY1BDQTo6Y2FsY3VsYXRlX2NsdXN0ZXJzKHNjZSkKY2x1c3Rlcl9yZXN1bHRzX2RmCmBgYAoKCmByT3BlblNjUENBYCBhc3N1bWVzIHRoYXQgdGhlIFBDQSBtYXRyaXggaXMgbmFtZWQgYFBDQWAgaW4gU0NFIG9iamVjdHMsIGFuZCBgcGNhYCBpbiBTZXVyYXQgb2JqZWN0cy4KSWYgdGhlIFBDQSBtYXRyaXggeW91IHdhbnQgdG8gdXNlIGluIHRoZSBvYmplY3QgaGFzIGEgZGlmZmVyZW50IG5hbWUsIHlvdSBjYW4gcHJvdmlkZSB0aGUgYXJndW1lbnQgYHBjX25hbWVgLgoKCiMjIENhbGN1bGF0aW5nIFFDIG1ldHJpY3Mgb24gZXhpc3RpbmcgY2x1c3RlcnMKCklmIHlvdSBhbHJlYWR5IGhhdmUgY2x1c3RlcmluZyByZXN1bHRzIGNhbGN1bGF0ZWQgd2l0aCBvdGhlciB0b29scywgeW91IGNhbiBzdGlsbCB1c2UgdGhlIGByT3BlblNjUENBYCBmdW5jdGlvbnMgdG8gZXZhbHVhdGUgeW91ciBjbHVzdGVycy4KCkluIHRoaXMgc2VjdGlvbiwgd2UnbGwgcHJlc2VudCBleGFtcGxlcyBvZiBob3cgeW91IGNhbiBjYWxjdWxhdGUgdGhlIHNpbGhvdWV0dGUgd2lkdGgsIG5laWdoYm9yaG9vZCBwdXJpdHksIGFuZCBjbHVzdGVyIHN0YWJpbGl0eSBmcm9tIGV4aXN0aW5nIGNsdXN0ZXIgYXNzaWdubWVudHMgd2l0aGluIG9iamVjdHMuCgojIyMgRXZhbHVhdGluZyBTZXVyYXQgY2x1c3RlcnMKCklmIHlvdSBhcmUgYW5hbHl6aW5nIHlvdXIgZGF0YSB3aXRoIGEgU2V1cmF0IHBpcGVsaW5lIHRoYXQgaW5jbHVkZXMgY2FsY3VsYXRpbmcgY2x1c3RlcnMsIHlvdSBjYW4gdXNlIGByT3BlblNjUENBYCB0byBldmFsdWF0ZSB0aGVtLgoKVG8gZGVtb25zdHJhdGUgdGhpcywgd2UnbGwgY29udmVydCBvdXIgU0NFIG9iamVjdCB0byBhIFNldXJhdCB1c2luZyB0aGUgZnVuY3Rpb24gYHJPcGVuU2NQQ0E6OnNjZV90b19zZXVyYXQoKWAuClRoZW4sIHdlJ2xsIHVzZSBhIHNpbXBsZSBTZXVyYXQgcGlwZWxpbmUgdG8gb2J0YWluIGNsdXN0ZXJzLgo8IS0tIFRPRE86IFdlIHdpbGwgd2FudCB0byByZWZlcmVuY2UgdGhpcyBtb2R1bGUgZm9yIGZ1cnRoZXIgZG9jdW1lbnRhdGlvbiBvbiB0aGlzIGZ1bmN0aW9uOiBodHRwczovL2dpdGh1Yi5jb20vQWxleHNMZW1vbmFkZS9PcGVuU2NQQ0EtYW5hbHlzaXMvaXNzdWVzLzk0NSAtLT4KCmBgYHtyIHNjZSB0byBzZXVyYXQsIG1lc3NhZ2UgPSBGQUxTRX0KIyBDb252ZXJ0IHRoZSBTQ0UgdG8gYSBTZXVyYXQgb2JqZWN0IHVzaW5nIHJPcGVuU2NQQ0EKc2V1cmF0X29iaiA8LSByT3BlblNjUENBOjpzY2VfdG9fc2V1cmF0KHNjZSkKCiMgQ2FsY3VsYXRlIGNsdXN0ZXJzIHdpdGggU2V1cmF0IHVzaW5nIGEgc3RhbmRhcmQgU2V1cmF0IHBpcGVsaW5lLCBmb3IgZXhhbXBsZQpzZXVyYXRfb2JqIDwtIHNldXJhdF9vYmogfD4KICBTQ1RyYW5zZm9ybSgpIHw+CiAgUnVuUENBKCkgfD4KICBGaW5kTmVpZ2hib3JzKCkgfD4KICBGaW5kQ2x1c3RlcnMoKQoKc2V1cmF0X29iagpgYGAKCgpUbyBjYWxjdWxhdGUgUUMgbWV0cmljcyBvbiB0aGVzZSBjbHVzdGVycywgd2UnbGwgbmVlZCB0byBjcmVhdGUgYSBkYXRhIGZyYW1lIHdpdGggY29sdW1ucyBgY2VsbF9pZGAgYW5kIGBjbHVzdGVyYDoKCmBgYHtyIHByZXBhcmUgc2V1cmF0IGlucHV0fQojIENyZWF0ZSBhIGRhdGEgZnJhbWUgZm9yIGlucHV0CnNldXJhdF9jbHVzdGVyX2RmIDwtIGRhdGEuZnJhbWUoCiAgY2VsbF9pZCA9IGNvbG5hbWVzKHNldXJhdF9vYmopLAogIGNsdXN0ZXIgPSBzZXVyYXRfb2JqJHNldXJhdF9jbHVzdGVycwopCgpoZWFkKHNldXJhdF9jbHVzdGVyX2RmKQpgYGAKCk5vdywgd2UgY2FuIHJ1biBgck9wZW5TY1BDQTo6Y2FsY3VsYXRlX3NpbGhvdWV0dGUoKWAgYW5kIGByT3BlblNjUENBOjpjYWxjdWxhdGVfcHVyaXR5KClgIHVzaW5nIHRoaXMgZGF0YSBmcmFtZSBhbmQgdGhlIFNldXJhdCBvYmplY3Q6CgpgYGB7ciBzZXVyYXQgc2lsaG91ZXR0ZX0Kc2V1cmF0X3NpbGhvdWV0dGVfZGYgPC0gck9wZW5TY1BDQTo6Y2FsY3VsYXRlX3NpbGhvdWV0dGUoCiAgc2V1cmF0X29iaiwKICBzZXVyYXRfY2x1c3Rlcl9kZgopCmBgYAoKYGBge3Igc2V1cmF0IHB1cml0eX0Kc2V1cmF0X3B1cml0eV9kZiA8LSByT3BlblNjUENBOjpjYWxjdWxhdGVfcHVyaXR5KAogIHNldXJhdF9vYmosCiAgc2V1cmF0X2NsdXN0ZXJfZGYKKQpgYGAKCldlIGRvIG5vdCByZWNvbW1lbmQgdXNpbmcgYHJPcGVuU2NQQ0E6OmNhbGN1bGF0ZV9zdGFiaWxpdHkoKWAgb24gU2V1cmF0IGNsdXN0ZXJzIGR1ZSB0byBkaWZmZXJlbmNlcyBpbiB0aGUgdW5kZXJseWluZyBjbHVzdGVyaW5nIGFwcHJvYWNoIGJldHdlZW4gU2V1cmF0IGFuZCB0aGUgYGJsdXN0ZXJgIHBhY2thZ2Ugd2hpY2ggYHJPcGVuU2NQQ0FgIHVzZXMuCgojIyMgRXZhbHVhdGluZyBTY1BDQSBjbHVzdGVycwoKU2NQQ0EgY2VsbCBtZXRhZGF0YSBhbHJlYWR5IGNvbnRhaW5zIGEgY29sdW1uIGNhbGxlZCBgY2x1c3RlcmAgd2l0aCByZXN1bHRzIGZyb20gYW4gYXV0b21hdGVkIGNsdXN0ZXJpbmcuIApUaGVzZSBjbHVzdGVycyB3ZXJlIGNhbGN1bGF0ZWQgdXNpbmcgYGJsdXN0ZXJgLCB0aGUgc2FtZSB0b29sIHRoYXQgYHJPcGVuU2NQQ0FgIHVzZXMuIApUaGUgc3BlY2lmaWNhdGlvbnMgdXNlZCBmb3IgdGhpcyBjbHVzdGVyaW5nIGFyZSBzdG9yZWQgaW4gdGhlIFNDRSBvYmplY3QncyBtZXRhZGF0YSwgYXMgZm9sbG93czsgbm90ZSB0aGF0IGFsbCBvdGhlciBjbHVzdGVyaW5nIHBhcmFtZXRlcnMgd2VyZSBsZWZ0IGF0IHRoZWlyIGRlZmF1bHQgdmFsdWVzLgoKKiBgbWV0YWRhdGEoc2NlKSRjbHVzdGVyX2FsZ29yaXRobWA6IFRoZSBjbHVzdGVyaW5nIGFsZ29yaXRobSB1c2VkCiogYG1ldGFkYXRhKHNjZSkkY2x1c3Rlcl93ZWlnaHRpbmdgOiBUaGUgd2VpZ2h0aW5nIHNjaGVtZSB1c2VkCiogYG1ldGFkYXRhKHNjZSkkY2x1c3Rlcl9ubmA6IFRoZSBudW1iZXIgb2YgbmVhcmVzdCBuZWlnaGJvcnMgdXNlZAoKWW91IGNhbiBzZWUgYWxsIHRoZWlyIHZhbHVlcyBoZXJlOgoKCmBgYHtyIGV4dHJhY3QgY2x1c3RlciBwYXJhbXN9CiMgUHJpbnQgY2x1c3RlcmluZyBzcGVjaWZpY2F0aW9ucwptZXRhZGF0YShzY2UpW2MoImNsdXN0ZXJfYWxnb3JpdGhtIiwgImNsdXN0ZXJfd2VpZ2h0aW5nIiwgImNsdXN0ZXJfbm4iKV0KYGBgCgoKSW4gdGhpcyBleGFtcGxlLCB3ZSdsbCBzaG93IGhvdyB0byB1c2UgdGhlIGNsdXN0ZXIgZXZhbHVhdGlvbiBmdW5jdGlvbnMgb24gdGhlc2UgY2x1c3RlcnMuCgpUbyBiZWdpbiwgd2UnbGwgcHJlcGFyZSBhIGRhdGEgZnJhbWUgd2l0aCB0d28gY29sdW1uczogYGNlbGxfaWRgIGNvbnRhaW5pbmcgY2VsbCBiYXJjb2RlcywgYW5kIGBjbHVzdGVyYCBjb250YWluaW5nIHRoZSBjbHVzdGVyIGlkZW50aXRpZXMuCgpgYGB7ciBwcmVwYXJlIHNjcGNhIGRhdGEgZnJhbWV9CnNjcGNhX2NsdXN0ZXJfZGYgPC0gZGF0YS5mcmFtZSgKICBjZWxsX2lkID0gY29sbmFtZXMoc2NlKSwKICBjbHVzdGVyID0gc2NlJGNsdXN0ZXIKKQoKaGVhZChzY3BjYV9jbHVzdGVyX2RmKQpgYGAKCldlIGNhbiBydW4gZXZhbHVhdGlvbiBmdW5jdGlvbnMgdXNpbmcgdGhpcyBkYXRhIGZyYW1lIGFuZCB0aGUgU0NFIG9iamVjdC4KCmBgYHtyIHNjcGNhIHNpbGhvdWV0dGV9CiMgQ2FsY3VsYXRlIHNpbGhvdWV0dGUgd2lkdGgKc2NwY2Ffc2lsaG91ZXR0ZV9kZiA8LSByT3BlblNjUENBOjpjYWxjdWxhdGVfc2lsaG91ZXR0ZSgKICBzY2UsCiAgc2NwY2FfY2x1c3Rlcl9kZgopCmBgYAoKYGBge3Igc2NwY2EgcHVyaXR5fQojIENhbGN1bGF0ZSBuZWlnaGJvcmhvb2QgcHVyaXR5CnNjcGNhX3B1cml0eV9kZiA8LSByT3BlblNjUENBOjpjYWxjdWxhdGVfcHVyaXR5KAogIHNjZSwKICBzY3BjYV9jbHVzdGVyX2RmCikKYGBgCgpXaGVuIHJ1bm5pbmcgYHJPcGVuU2NQQ0E6OmNhbGN1bGF0ZV9zdGFiaWxpdHkoKWAsIHdlJ2xsIHNwZWNpZnkgdGhlIHNhbWUgcGFyYW1ldGVycyBvcmlnaW5hbGx5IHVzZWQgdG8gYnVpbGQgdGhlIGNsdXN0ZXJzIGJ5IGV4dHJhY3RpbmcgdGhlbSBmcm9tIHRoZSBtZXRhZGF0YS4KV2UnbGwgbmVlZCB0byBlbnN1cmUgdGhlIHByb3ZpZGVkIGFyZ3VtZW50cyBhcmUgbG93ZXJjYXNlLCBhcyB3ZWxsLgoKR2VuZXJhbGx5IHNwZWFraW5nLCB3ZSBvbmx5IHJlY29tbWVuZCBldmFsdWF0aW5nIGNsdXN0ZXJzIHdpdGggYHJPcGVuU2NQQ0E6OmNhbGN1bGF0ZV9zdGFiaWxpdHkoKWAgaWYgeW91IGtub3cgdGhlIG9yaWdpbmFsIHBhcmFtZXRlcnMgdXNlZC4KCgpgYGB7ciBzY3BjYSBzdGFiaWxpdHl9CnNjcGNhX3N0YWJpbGl0eV9kZiA8LSByT3BlblNjUENBOjpjYWxjdWxhdGVfc3RhYmlsaXR5KAogIHNjZSwKICBzY3BjYV9jbHVzdGVyX2RmLAogICMgcHJvdmlkZSBTY1BDQSBjbHVzdGVyaW5nIHBhcmFtZXRlcnMgYnkgZXh0cmFjdGluZyBmcm9tIHRoZSBTQ0UgbWV0YWRhdGEKICBhbGdvcml0aG0gPSB0b2xvd2VyKG1ldGFkYXRhKHNjZSkkY2x1c3Rlcl9hbGdvcml0aG0pLAogIHdlaWdodGluZyA9IHRvbG93ZXIobWV0YWRhdGEoc2NlKSRjbHVzdGVyX3dlaWdodGluZyksCiAgbm4gPSBtZXRhZGF0YShzY2UpJGNsdXN0ZXJfbm4KKQpgYGAKCgojIyBTYXZpbmcgY2x1c3RlcmluZyByZXN1bHRzIAoKUmVzdWx0cyBjYW4gZWl0aGVyIGJlIGRpcmVjdGx5IGV4cG9ydGVkIGFzIGEgVFNWIGZpbGUgKGUuZy4sIHdpdGggYHJlYWRyOjp3cml0ZV90c3YoKWApLCBvciB5b3UgY2FuIGFkZCB0aGUgcmVzdWx0cyBpbnRvIHlvdXIgU0NFIG9yIFNldXJhdCBvYmplY3QuClRoZSBzdWJzZXF1ZW50IGV4YW1wbGVzIHdpbGwgZGVtb25zdHJhdGUgc2F2aW5nIHRoZSBjbHVzdGVyIGFzc2lnbm1lbnRzIHN0b3JlZCBpbiBgY2x1c3Rlcl9yZXN1bHRzX2RmJGNsdXN0ZXJgIHRvIGFuIFNDRSBhbmQgYSBTZXVyYXQgb2JqZWN0LgoKX0Egd29yZCBvZiBjYXV0aW9uIV8KT2JqZWN0cyBmcm9tIHRoZSBTY1BDQSBQb3J0YWwgYWxyZWFkeSBjb250YWluIGEgY29sdW1uIGNhbGxlZCBgY2x1c3RlcmAgd2l0aCByZXN1bHRzIGZyb20gYW4gYXV0b21hdGVkIGNsdXN0ZXJpbmcuClRoZXNlIGF1dG9tYXRpYyBjbHVzdGVycyB3ZXJlIG5vdCBldmFsdWF0ZWQsIGFuZCB0aGVpciBwYXJhbWV0ZXJzIHdlcmUgbm90IG9wdGltaXplZCBmb3IgYW55IGdpdmVuIGxpYnJhcnkuClRvIGF2b2lkIGFtYmlndWl0eSBiZXR3ZWVuIHRoZSBleGlzdGluZyBhbmQgbmV3IGNsdXN0ZXJpbmcgcmVzdWx0cywgd2UnbGwgbmFtZSB0aGUgbmV3IGNvbHVtbiBgcm9wZW5zY3BjYV9jbHVzdGVyYC4KCiMjIyBTYXZpbmcgcmVzdWx0cyB0byBhbiBTQ0Ugb2JqZWN0IAoKV2UgY2FuIGFkZCBjb2x1bW5zIHRvIGFuIFNDRSBvYmplY3QncyBgY29sRGF0YWAgdGFibGUgYnkgZGlyZWN0bHkgY3JlYXRpbmcgYSBjb2x1bW4gaW4gdGhlIG9iamVjdCB3aXRoIGAkYC4KQmVmb3JlIHdlIGRvIHNvLCB3ZSdsbCBjb25maXJtIHRoYXQgdGhlIGNsdXN0ZXJzIGFyZSBpbiB0aGUgc2FtZSBvcmRlciBhcyB0aGUgU0NFIG9iamVjdCBieSBjb21wYXJpbmcgY2VsbCBpZHM6CgpgYGB7ciBjaGVjayBzY2Ugb3JkZXJ9CmFsbC5lcXVhbCgKICBjb2xuYW1lcyhzY2UpLAogIGNsdXN0ZXJfcmVzdWx0c19kZiRjZWxsX2lkCikKYGBgCgpgYGB7ciBhZGQgdG8gc2NlfQojIEFkZCBjbHVzdGVyIHJlc3VsdHMgdG8gdGhlIGNvbERhdGEKc2NlJHJvcGVuc2NwY2FfY2x1c3RlciA8LSBjbHVzdGVyX3Jlc3VsdHNfZGYkY2x1c3RlcgpgYGAKCiMjIyBTYXZpbmcgcmVzdWx0cyB0byBhIFNldXJhdCBvYmplY3QgCgoKV2UgY2FuIGFkZCBjb2x1bW5zIHRvIGFuIFNldXJhdCBvYmplY3QncyBjZWxsIG1ldGFkYXRhIHRhYmxlIGJ5IGRpcmVjdGx5IGNyZWF0aW5nIGEgY29sdW1uIGluIHRoZSBvYmplY3Qgd2l0aCBgJGAgKG5vdGUgdGhhdCB5b3UgY2FuIGFsc28gdXNlIHRoZSBTZXVyYXQgZnVuY3Rpb24gYEFkZE1ldGFEYXRhKClgKS4KQmVmb3JlIHdlIGRvIHNvLCB3ZSdsbCBjb25maXJtIHRoYXQgdGhlIGNsdXN0ZXJzIGFyZSBpbiB0aGUgc2FtZSBvcmRlciBhcyB0aGUgU2V1cmF0IG9iamVjdCBieSBjb21wYXJpbmcgY2VsbCBpZHM6CgoKYGBge3IgY2hlY2sgc2V1cmF0IG9yZGVyfQphbGwuZXF1YWwoCiAgY29sbmFtZXMoc2V1cmF0X29iaiksCiAgY2x1c3Rlcl9yZXN1bHRzX2RmJGNlbGxfaWQKKQpgYGAKCmBgYHtyIGFkZCB0byBzZXVyYXR9CiMgQWRkIGNsdXN0ZXIgcmVzdWx0cyB0byB0aGUgY2VsbCBtZXRhZGF0YQpzZXVyYXRfb2JqJHJvcGVuc2NwY2FfY2x1c3RlciA8LSBjbHVzdGVyX3Jlc3VsdHNfZGYkY2x1c3RlcgpgYGAKCgojIyBTZXNzaW9uIEluZm8KCmBgYHtyIHNlc3Npb24gaW5mb30KIyByZWNvcmQgdGhlIHZlcnNpb25zIG9mIHRoZSBwYWNrYWdlcyB1c2VkIGluIHRoaXMgYW5hbHlzaXMgYW5kIG90aGVyIGVudmlyb25tZW50IGluZm9ybWF0aW9uCnNlc3Npb25JbmZvKCkKYGBgCg==
+
LS0tCnRpdGxlOiAiUGVyZm9ybWluZyBncmFwaC1iYXNlZCBjbHVzdGVyaW5nIHdpdGggck9wZW5TY1BDQSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgphdXRob3I6ICJEYXRhIExhYiIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIGRmX3ByaW50OiBwYWdlZAotLS0KCiMjIEludHJvZHVjdGlvbgoKVGhpcyBub3RlYm9vayBwcm92aWRlcyBleGFtcGxlcyBvZiBob3cgdG8gdXNlIGZ1bmN0aW9ucyBpbiBgck9wZW5TY1BDQWAgdGhhdDoKCiogUGVyZm9ybSBjbHVzdGVyaW5nCiogQ2FsY3VsYXRlIFFDIG1ldHJpY3Mgb24gY2x1c3RlcnMsIGluY2x1ZGluZzoKICAqIFNpbGhvdWV0dGUgd2lkdGgKICAqIE5laWdoYm9yaG9vZCBwdXJpdHkKICAqIENsdXN0ZXIgc3RhYmlsaXR5LCBhcyBtZWFzdXJlZCB3aXRoIHRoZSBBZGp1c3RlZCBSYW5kIEluZGV4CiogQ2FsY3VsYXRlIFFDIG1ldHJpY3Mgb24gY2x1c3RlcnMgb2J0YWluZWQgd2l0aCBvdGhlciB0b29scywgc3VjaCBhcyBgU2V1cmF0YAoqIFNhdmUgY2x1c3RlcmluZyByZXN1bHRzIHRvIGFuIFNDRSBvciBgU2V1cmF0YAoKV2hpbGUgdGhpcyBub3RlYm9vayBkZW1vbnN0cmF0ZXMgaG93IHRvIHVzZSBpbmRpdmlkdWFsIGZ1bmN0aW9ucyB0aGF0IGNhbGN1bGF0ZSBoZWxwZnVsIG1ldHJpY3MgZm9yIGV2YWx1YXRpbmcgY2x1c3RlcmluZyByZXN1bHRzLCBhIGZ1bGwgZXZhbHVhdGlvbiB3b3VsZCBjb21wYXJlIHRoZXNlIG1ldHJpY3MgYWNyb3NzIGRpZmZlcmVudCBjbHVzdGVyaW5ncyBmcm9tIGRpZmZlcmVudCBwYXJhbWV0ZXJpemF0aW9ucy4KClRoaXMgbm90ZWJvb2sgd2lsbCB1c2UgdGhlIHNhbXBsZSBgU0NQQ1MwMDAwMDFgIGZyb20gcHJvamVjdCBgU0NQQ1AwMDAwMDFgLCB3aGljaCBpcyBhc3N1bWVkIHByZXNlbnQgaW4gdGhlIGBPcGVuU2NQQ0EtYW5hbHlzaXMvZGF0YS9jdXJyZW50L1NDUENQMDAwMDAxYCBkaXJlY3RvcnksIGZvciBhbGwgZXhhbXBsZXMuClBsZWFzZSBbc2VlIHRoaXMgZG9jdW1lbnRhdGlvbl0oaHR0cHM6Ly9vcGVuc2NwY2EucmVhZHRoZWRvY3MuaW8vZW4vbGF0ZXN0L2dldHRpbmctc3RhcnRlZC9hY2Nlc3NpbmctcmVzb3VyY2VzL2dldHRpbmctYWNjZXNzLXRvLWRhdGEvKSBmb3IgbW9yZSBpbmZvcm1hdGlvbiBhYm91dCBvYnRhaW5pbmcgU2NQQ0EgZGF0YS4KCiMjIFNldHVwCgojIyMgUGFja2FnZXMKCgpgYGB7ciBwYWNrYWdlc30KbGlicmFyeShyT3BlblNjUENBKQoKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKICBsaWJyYXJ5KFNpbmdsZUNlbGxFeHBlcmltZW50KQogIGxpYnJhcnkoU2V1cmF0KQogIGxpYnJhcnkoZHBseXIpCiAgbGlicmFyeShnZ3Bsb3QyKQp9KQoKIyBTZXQgZ2dwbG90IHRoZW1lIGZvciBwbG90cwp0aGVtZV9zZXQodGhlbWVfYncoKSkKYGBgCgoKIyMjIFBhdGhzCgpgYGB7ciBiYXNlIHBhdGhzfQojIFRoZSBiYXNlIHBhdGggZm9yIHRoZSBPcGVuU2NQQ0EgcmVwb3NpdG9yeQpyZXBvc2l0b3J5X2Jhc2UgPC0gcnByb2pyb290OjpmaW5kX3Jvb3QocnByb2pyb290Ojppc19naXRfcm9vdCkKCiMgVGhlIGN1cnJlbnQgZGF0YSBkaXJlY3RvcnksIGZvdW5kIHdpdGhpbiB0aGUgcmVwb3NpdG9yeSBiYXNlIGRpcmVjdG9yeQpkYXRhX2RpciA8LSBmaWxlLnBhdGgocmVwb3NpdG9yeV9iYXNlLCAiZGF0YSIsICJjdXJyZW50IikKCiMgVGhlIHBhdGggdG8gdGhpcyBtb2R1bGUKbW9kdWxlX2Jhc2UgPC0gZmlsZS5wYXRoKHJlcG9zaXRvcnlfYmFzZSwgImFuYWx5c2VzIiwgImhlbGxvLWNsdXN0ZXJzIikKYGBgCgpgYGB7ciBpbnB1dCBmaWxlIHBhdGh9CiMgUGF0aCB0byBwcm9jZXNzZWQgU0NFIGZpbGUgZm9yIHNhbXBsZSBTQ1BDUzAwMDAwMQppbnB1dF9zY2VfZmlsZSA8LSBmaWxlLnBhdGgoZGF0YV9kaXIsICJTQ1BDUDAwMDAwMSIsICJTQ1BDUzAwMDAwMSIsICJTQ1BDTDAwMDAwMV9wcm9jZXNzZWQucmRzIikKYGBgCgoKIyMjIFNldCB0aGUgcmFuZG9tIHNlZWQKCkJlY2F1c2UgY2x1c3RlcmluZyBpbnZvbHZlcyByYW5kb20gc2FtcGxpbmcsIGl0IGlzIGltcG9ydGFudCB0byBzZXQgdGhlIHJhbmRvbSBzZWVkIGF0IHRoZSB0b3Agb2YgeW91ciBhbmFseXNpcyBzY3JpcHQgb3Igbm90ZWJvb2sgdG8gZW5zdXJlIHJlcHJvZHVjaWJpbGl0eS4KCmBgYHtyIHNldCBzZWVkfQpzZXQuc2VlZCgyMDI0KQpgYGAKCiMjIFJlYWQgaW4gYW5kIHByZXBhcmUgZGF0YQoKVG8gYmVnaW4sIHdlJ2xsIHJlYWQgaW4gdGhlIGBTaW5nbGVDZWxsRXhwZXJpbWVudGAgKFNDRSkgb2JqZWN0LgoKYGBge3IgcmVhZCBkYXRhfQojIFJlYWQgdGhlIFNDRSBmaWxlCnNjZSA8LSByZWFkUkRTKGlucHV0X3NjZV9maWxlKQpgYGAKCkZvciB0aGUgaW5pdGlhbCBjbHVzdGVyIGNhbGN1bGF0aW9ucyBhbmQgZXZhbHVhdGlvbnMsIHdlIHdpbGwgdXNlIHRoZSBQQ0EgbWF0cml4IGV4dHJhY3RlZCBmcm9tIHRoZSBTQ0Ugb2JqZWN0LgpJdCdzIGFsc28gcG9zc2libGUgdG8gdXNlIGFuIFNDRSBvYmplY3Qgb3IgYSBTZXVyYXQgb2JqZWN0IGRpcmVjdGx5LCB3aGljaCB3ZSB3aWxsIGRlbW9uc3RyYXRlIGxhdGVyLgoKCmBgYHtyIGV4dHJhY3QgcGNhIGRhdGF9CiMgRXh0cmFjdCB0aGUgUENBIG1hdHJpeCBmcm9tIGFuIFNDRSBvYmplY3QKcGNhX21hdHJpeCA8LSByZWR1Y2VkRGltKHNjZSwgIlBDQSIpCmBgYAoKIyMgUGVyZm9ybSBjbHVzdGVyaW5nCgpUaGlzIHNlY3Rpb24gd2lsbCBzaG93IGhvdyB0byBwZXJmb3JtIGNsdXN0ZXJpbmcgd2l0aCB0aGUgZnVuY3Rpb24gYHJPcGVuU2NQQ0E6OmNhbGN1bGF0ZV9jbHVzdGVycygpYC4KClRoaXMgZnVuY3Rpb24gdGFrZXMgYSBQQ0EgbWF0cml4IHdpdGggcm93bmFtZXMgcmVwcmVzZW50aW5nIHVuaXF1ZSBjZWxsIGlkcyAoZS5nLiwgYmFyY29kZXMpIGFzIGl0cyBwcmltYXJ5IGFyZ3VtZW50LgpCeSBkZWZhdWx0IGl0IHdpbGwgY2FsY3VsYXRlIGNsdXN0ZXJzIHVzaW5nIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVyczoKCiogTG91dmFpbiBhbGdvcml0aG0KKiBKYWNjYXJkIHdlaWdodGluZwoqIDEwIG5lYXJlc3QgbmVpZ2hib3JzCiogQSByZXNvbHV0aW9uIHBhcmFtZXRlciBvZiAxCgpUaGlzIGZ1bmN0aW9uIHdpbGwgcmV0dXJuIGEgdGFibGUgd2l0aCB0aGUgZm9sbG93aW5nIGNvbHVtbnM6CgoqIGBjZWxsX2lkYDogVW5pcXVlIGNlbGwgaWRlbnRpZmllcnMsIG9idGFpbmVkIGZyb20gdGhlIFBDQSBtYXRyaXgncyByb3cgbmFtZXMKKiBgY2x1c3RlcmA6IEEgZmFjdG9yIGNvbHVtbiB3aXRoIHRoZSBjbHVzdGVyIGlkZW50aXRpZXMKKiBUaGVyZSB3aWxsIGJlIG9uZSBjb2x1bW4gZm9yIGVhY2ggY2x1c3RlcmluZyBwYXJhbWV0ZXIgdXNlZAoKCiMjIyBDbHVzdGVyaW5nIHdpdGggZGVmYXVsdCBwYXJhbWV0ZXJzCgpgYGB7ciBjbHVzdGVyIHNjZX0KIyBDYWxjdWxhdGUgY2x1c3RlcnMgd2l0aCBkZWZhdWx0IHBhcmFtZXRlcnMKY2x1c3Rlcl9yZXN1bHRzX2RmIDwtIHJPcGVuU2NQQ0E6OmNhbGN1bGF0ZV9jbHVzdGVycyhwY2FfbWF0cml4KQoKIyBQcmludCB0aGUgZmlyc3Qgcm93cyBvZiB0aGUgcmVzdWx0aW5nIHRhYmxlCmhlYWQoY2x1c3Rlcl9yZXN1bHRzX2RmKQpgYGAKCiMjIyBDbHVzdGVyaW5nIHdpdGggbm9uLWRlZmF1bHQgcGFyYW1ldGVycwoKUGFyYW1ldGVycyB1c2VkIGZvciBjbHVzdGVyaW5nIGNhbiBiZSBjdXN0b21pemVkIHdpdGggdGhlc2UgYXJndW1lbnRzOgoKKiBUaGUgYGFsZ29yaXRobWAgY2FuIGJlIG9uZSBvZjoKICAqIGBsb3V2YWluYCwgYHdhbGt0cmFwYCwgb3IgYGxlaWRlbmAKKiBUaGUgYHdlaWdodGluZ2AgY2FuIGJlIG9uZSBvZjoKICAqIGBqYWNjYXJkYCwgYHJhbmtgLCBvciBgbnVtYmVyYAoqIFRoZSBuZWFyZXN0IG5laWdoYm9ycyBwYXJhbWV0ZXIgY2FuIGJlIGN1c3RvbWl6ZWQgd2l0aCB0aGUgYG5uYCBhcmd1bWVudAoqIFRoZSByZXNvbHV0aW9uIHBhcmFtZXRlciBjYW4gYmUgY3VzdG9taXplZCB3aXRoIHRoZSBgcmVzb2x1dGlvbmAgYXJndW1lbnQKICAqIFRoaXMgcGFyYW1ldGVyIGlzIG9ubHkgdXNlZCBieSBMb3V2YWluIGFuZCBMZWlkZW4gYWxnb3JpdGhtcwoqIElmIHRoZSBMZWlkZW4gYWxnb3JpdGhtIGlzIHVzZWQsIGl0cyBkZWZhdWx0IG9iamVjdGl2ZSBmdW5jdGlvbiBwYXJhbWV0ZXIgd2lsbCBiZSBgQ1BNYCwgYnV0IHlvdSBjYW4gYWxzbyBzZXQgIGBvYmplY3RpdmVfZnVuY3Rpb24gPSAibW9kdWxhcml0eSJgIGluc3RlYWQuCiogWW91IGNhbiBwcm92aWRlIGFkZGl0aW9uYWwgcGFyYW1ldGVycyBhcyBhIGxpc3QgdG8gdGhlIGBjbHVzdGVyX2FyZ3NgIGFyZ3VtZW50LgogICogUGxlYXNlIHJlZmVyIHRvIHRoZSBbYGlncmFwaGAgZG9jdW1lbnRhdGlvbl0oaHR0cHM6Ly9pZ3JhcGgub3JnL3IvaHRtbC9sYXRlc3QpIHRvIGxlYXJuIG1vcmUgYWJvdXQgd2hhdCBhZGRpdGlvbmFsIHBhcmFtZXRlcnMgY2FuIGJlIHByb3ZpZGVkIHRvIGVhY2ggY2x1c3RlcmluZyBhbGdvcml0aG0uCiAgKiBOb3RlIHRoYXQgYGNsdXN0ZXJfYXJnc2Agb25seSBhY2NlcHRzIHNpbmdsZS1sZW5ndGggYXJndW1lbnRzIChubyB2ZWN0b3JzIG9yIGxpc3RzKS4KCkZvciBleGFtcGxlOgoKYGBge3IgY2x1c3RlciBzY2Ugbm9uZGVmYXVsdH0KIyBDYWxjdWxhdGUgY2x1c3RlcnMgd2l0aCBub24tZGVmYXVsdCBwYXJhbWV0ZXJzCmNsdXN0ZXJfcmVzdWx0c19kZiA8LSByT3BlblNjUENBOjpjYWxjdWxhdGVfY2x1c3RlcnMoCiAgcGNhX21hdHJpeCwKICBhbGdvcml0aG0gPSAibGVpZGVuIiwKICBubiA9IDE1LAogIG9iamVjdGl2ZV9mdW5jdGlvbiA9ICJtb2R1bGFyaXR5IgopCmBgYAoKCiMjIENhbGN1bGF0ZSBRQyBtZXRyaWNzIG9uIGNsdXN0ZXJzCgpUaGlzIHNlY3Rpb24gZGVtb25zdHJhdGVzIGhvdyB0byB1c2Ugc2V2ZXJhbCBmdW5jdGlvbnMgZm9yIGV2YWx1YXRpbmcgY2x1c3RlciBxdWFsaXR5IGFuZCByZWxpYWJpbGl0eS4KSXQncyBpbXBvcnRhbnQgdG8gbm90ZSB0aGF0IGEgZnVsbCBldmFsdWF0aW9uIG9mIGNsdXN0ZXJpbmcgcmVzdWx0cyB3b3VsZCBjb21wYXJlIHRoZXNlIG1ldHJpY3MgYWNyb3NzIGEgc2V0IG9mIGNsdXN0ZXJpbmcgcmVzdWx0cywgd2l0aCB0aGUgYWltIG9mIGlkZW50aWZ5aW5nIGFuIG9wdGltYWwgcGFyYW1ldGVyaXphdGlvbi4KCkFsbCBmdW5jdGlvbnMgcHJlc2VudGVkIGluIHRoaXMgc2VjdGlvbiB0YWtlIHRoZSBmb2xsb3dpbmcgcmVxdWlyZWQgYXJndW1lbnRzOgoKKiBBIFBDQSBtYXRyaXggd2l0aCByb3cgbmFtZXMgcmVwcmVzZW50aW5nIHVuaXF1ZSBjZWxsIGlkcyAoZS5nLiwgYmFyY29kZXMpCiogQSBkYXRhIGZyYW1lIHdpdGgsIGF0IGxlYXN0LCBjb2x1bW5zIHJlcHJlc2VudGluZyB1bmlxdWUgY2VsbCBpZHMgYW5kIGNsdXN0ZXIgYXNzaWdubWVudHMKICAqIEJ5IGRlZmF1bHQsIHRoZXNlIGNvbHVtbnMgc2hvdWxkIGJlIG5hbWVkIGBjZWxsX2lkYCBhbmQgYGNsdXN0ZXJgLCByZXNwZWN0aXZlbHksIG1hdGNoaW5nIHRoZSBvdXRwdXQgb2YgYHJPcGVuU2NQQ0E6OmNhbGN1bGF0ZV9jbHVzdGVycygpYAogICogWW91IGNhbiBvdmVycmlkZSB0aGVzZSBkZWZhdWx0cyB1c2luZyB0aGUgYXJndW1lbnRzIGBjZWxsX2lkX2NvbGAgYW5kIGBjbHVzdGVyX2NvbGAKCiMjIyBTaWxob3VldHRlIHdpZHRoCgpTaWxob3VldHRlIHdpZHRoIGlzIGEgY29tbW9uIG1ldHJpYyB0aGF0IG1lYXN1cmVzIGhvdyB3ZWxsIHNlcGFyYXRlZCBjbHVzdGVycyBhcmUgYnksIGZvciBlYWNoIGNlbGwsIGNvbXBhcmluZyB0aGUgYXZlcmFnZSBkaXN0YW5jZSB0byBhbGwgY2VsbHMgaW4gdGhlIHNhbWUgY2x1c3RlciwgYW5kIGFsbCBjZWxscyBpbiBvdGhlciBjbHVzdGVycy4KVGhpcyB2YWx1ZSByYW5nZXMgZnJvbSAtMSB0byAxLgpDZWxscyBpbiB3ZWxsLXNlcGFyYXRlZCBjbHVzdGVycyBzaG91bGQgaGF2ZSBoaWdoIHNpbGhvdWV0dGUgdmFsdWVzIGNsb3NlciB0byAxLgpZb3UgY2FuIHJlYWQgbW9yZSBhYm91dCBzaWxob3VldHRlIHdpZHRoIHB1cml0eSBmcm9tIHRoZSBbX09yY2hlc3RyYXRpbmcgU2luZ2xlIENlbGwgQW5hbHlzaXMgd2l0aCBCaW9jb25kdWN0b3JfIGJvb2tdKGh0dHBzOi8vYmlvY29uZHVjdG9yLm9yZy9ib29rcy8zLjE5L09TQ0EuYWR2YW5jZWQvY2x1c3RlcmluZy1yZWR1eC5odG1sI3NpbGhvdWV0dGUtd2lkdGgpLgoKV2UnbGwgdXNlIHRoZSBmdW5jdGlvbiBgck9wZW5TY1BDQTo6Y2FsY3VsYXRlX3NpbGhvdWV0dGUoKWAgdG8gY2FsY3VsYXRlIHRoZSBzaWxob3VldHRlIHdpZHRoLgoKVGhpcyBmdW5jdGlvbiB3aWxsIHJldHVybiB0aGUgaW5wdXR0ZWQgZGF0YSBmcmFtZSB3aXRoIHR3byBhZGRpdGlvbmFsIGNvbHVtbnM6CgoqIGBzaWxob3VldHRlX3dpZHRoYDogVGhlIGNhbGN1bGF0ZWQgc2lsaG91ZXR0ZSB3aWR0aCBmb3IgdGhlIGNlbGwKKiBgc2lsaG91ZXR0ZV9vdGhlcmA6IFRoZSBjbG9zZXQgY2x1c3RlciB0byB0aGUgY2VsbCBiZXNpZGVzIHRoZSBjbHVzdGVyIHRvIHdoaWNoIGl0IGJlbG9uZ3MsIGFzIHVzZWQgaW4gdGhlIHNpbGhvdWV0dGUgd2lkdGggY2FsY3VsYXRpb24KCgpgYGB7ciBzaWxob3VldHRlfQojIGNhbGN1bGF0ZSB0aGUgc2lsaG91ZXR0ZSB3aWR0aCBmb3IgZWFjaCBjZWxsCnNpbGhvdWV0dGVfcmVzdWx0cyA8LSByT3BlblNjUENBOjpjYWxjdWxhdGVfc2lsaG91ZXR0ZSgKICBwY2FfbWF0cml4LAogIGNsdXN0ZXJfcmVzdWx0c19kZgopCgojIFByaW50IHRoZSBmaXJzdCByb3dzIG9mIHRoZSByZXN1bHRpbmcgdGFibGUKaGVhZChzaWxob3VldHRlX3Jlc3VsdHMpCmBgYAoKCldlIGNhbiB2aXN1YWxpemUgdGhlc2UgcmVzdWx0cyBieSBwbG90dGluZyBzaWxob3VldHRlIHdpZHRoIGFjcm9zcyBjbHVzdGVycyBhcyB2aW9saW4gcGxvdHMsIGZvciBleGFtcGxlOgoKYGBge3IgdmlvbGluIHNpbGhvdWV0dGV9CmdncGxvdChzaWxob3VldHRlX3Jlc3VsdHMpICsKICBhZXMoeCA9IGNsdXN0ZXIsIHkgPSBzaWxob3VldHRlX3dpZHRoKSArCiAgZ2VvbV92aW9saW4oZmlsbCA9ICJkYXJrbWFnZW50YSIpICsKICBsYWJzKHggPSAiQ2x1c3RlciIsIHkgPSAiU2lsaG91ZXR0ZSB3aWR0aCIpCmBgYAoKIyMjIE5laWdoYm9yaG9vZCBwdXJpdHkKCk5laWdoYm9yaG9vZCBwdXJpdHkgaXMgZGVmaW5lZCwgZm9yIGVhY2ggY2VsbCwgYXMgdGhlIHByb3BvcnRpb24gb2YgbmVpZ2hib3JpbmcgY2VsbHMgdGhhdCBhcmUgYXNzaWduZWQgdG8gdGhlIHNhbWUgY2x1c3Rlci4KVGhpcyB2YWx1ZSByYW5nZXMgZnJvbSAwIHRvIDEuCkNlbGxzIGluIHdlbGwtc2VwYXJhdGVkIGNsdXN0ZXJzIHNob3VsZCBoYXZlIGhpZ2ggcHVyaXR5IHZhbHVlcyBjbG9zZXIgdG8gMSwgc2luY2UgdGhlcmUgc2hvdWxkIGJlIG1pbmltYWwgb3ZlcmxhcCBiZXR3ZWVuIG1lbWJlciBhbmQgbmVpZ2hib3JpbmcgY2VsbHMuCllvdSBjYW4gcmVhZCBtb3JlIGFib3V0IG5laWdoYm9yaG9vZCBwdXJpdHkgZnJvbSB0aGUgW19PcmNoZXN0cmF0aW5nIFNpbmdsZSBDZWxsIEFuYWx5c2lzIHdpdGggQmlvY29uZHVjdG9yXyBib29rXShodHRwczovL2Jpb2NvbmR1Y3Rvci5vcmcvYm9va3MvMy4xOS9PU0NBLmFkdmFuY2VkL2NsdXN0ZXJpbmctcmVkdXguaHRtbCNjbHVzdGVyLXB1cml0eSkuCgpXZSdsbCB1c2UgdGhlIGZ1bmN0aW9uIGByT3BlblNjUENBOjpjYWxjdWxhdGVfcHVyaXR5KClgIHRvIGNhbGN1bGF0ZSB0aGUgbmVpZ2hib3Job29kIHB1cml0eS4KClRoaXMgZnVuY3Rpb24gd2lsbCByZXR1cm4gdGhlIGlucHV0dGVkIGRhdGEgZnJhbWUgd2l0aCB0d28gYWRkaXRpb25hbCBjb2x1bW5zOgoKKiBgcHVyaXR5YDogVGhlIG5laWdoYm9yaG9vZCBwdXJpdHkgZm9yIHRoZSBjZWxsCiogYG1heGltdW1fbmVpZ2hib3JgOiBUaGUgY2x1c3RlciB3aXRoIHRoZSBoaWdoZXN0IHByb3BvcnRpb24gb2Ygb2JzZXJ2YXRpb25zIG5laWdoYm9yaW5nIHRoZSBjZWxsCgoKYGBge3IgcHVyaXR5fQojIGNhbGN1bGF0ZSB0aGUgbmVpZ2hib3Job29kIHB1cml0eSBmb3IgZWFjaCBjZWxsCnB1cml0eV9yZXN1bHRzIDwtIHJPcGVuU2NQQ0E6OmNhbGN1bGF0ZV9wdXJpdHkoCiAgcGNhX21hdHJpeCwKICBjbHVzdGVyX3Jlc3VsdHNfZGYKKQoKIyBQcmludCB0aGUgZmlyc3Qgcm93cyBvZiB0aGUgcmVzdWx0aW5nIHRhYmxlCmhlYWQocHVyaXR5X3Jlc3VsdHMpCmBgYAoKCldlIGNhbiB2aXN1YWxpemUgdGhlc2UgcmVzdWx0cyBieSBwbG90dGluZyBwdXJpdHkgY2x1c3RlcnMgYXMgdmlvbGluIHBsb3RzLCBmb3IgZXhhbXBsZToKCmBgYHtyIHZpb2xpbiBwdXJpdHl9CmdncGxvdChwdXJpdHlfcmVzdWx0cykgKwogIGFlcyh4ID0gY2x1c3RlciwgeSA9IHB1cml0eSkgKwogIGdlb21fdmlvbGluKGZpbGwgPSAiZGFya29saXZlZ3JlZW4zIikgKwogIGxhYnMoeCA9ICJDbHVzdGVyIiwgeSA9ICJOZWlnaGJvcmhvb2QgcHVyaXR5IikKYGBgCgojIyMgQ2x1c3RlciBzdGFiaWxpdHkKCkFub3RoZXIgYXBwcm9hY2ggdG8gZXhwbG9yaW5nIGNsdXN0ZXIgcXVhbGl0eSBpcyBob3cgc3RhYmxlIHRoZSBjbHVzdGVycyB0aGVtc2VsdmVzIGFyZSB1c2luZyBib290c3RyYXBwaW5nLgpHaXZlbiBhIHNldCBvZiBvcmlnaW5hbCBjbHVzdGVycywgd2UgY2FuIGNvbXBhcmUgdGhlIGJvb3RzdHJhcHBlZCBjbHVzdGVyIGlkZW50aXRpZXMgdG8gb3JpZ2luYWwgb25lcyB1c2luZyB0aGUgQWRqdXN0ZWQgUmFuZCBJbmRleCAoQVJJKSwgd2hpY2ggbWVhc3VyZXMgdGhlIHNpbWlsYXJpdHkgb2YgdHdvIGRhdGEgY2x1c3RlcmluZ3MuCkFSSSByYW5nZXMgZnJvbSAtMSB0byAxLCB3aGVyZToKCiogQSB2YWx1ZSBvZiAxIGluZGljYXRlcyB0aGV5IGFyZSBjb21wbGV0ZWx5IG92ZXJsYXBwaW5nCiogQSB2YWx1ZSBvZiAtMSBpbmRpY2F0ZXMgdGhleSBhcmUgY29tcGxldGVseSBkaXN0aW5jdAoqIEEgdmFsdWUgb2YgMCBpbmRpY2F0ZXMgYSByYW5kb20gcmVsYXRpb25zaGlwCgpXZSBleHBlY3QgdGhhdCBoaWdobHkgc3RhYmxlIGNsdXN0ZXJpbmdzIGhhdmUgQVJJIHZhbHVlcyBjbG9zZXIgdG8gMSBhY3Jvc3MgYSBzZXQgb2YgYm9vdHN0cmFwIHJlcGxpY2F0ZXMuCgpZb3UgY2FuIHJlYWQgbW9yZSBhYm91dCB0aGUgQWRqdXN0ZWQgUmFuZCBJbmRleCBmcm9tIHRoZSBbX09yY2hlc3RyYXRpbmcgU2luZ2xlIENlbGwgQW5hbHlzaXMgd2l0aCBCaW9jb25kdWN0b3JfIGJvb2tdKGh0dHBzOi8vYmlvY29uZHVjdG9yLm9yZy9ib29rcy9yZWxlYXNlL09TQ0EuYWR2YW5jZWQvY2x1c3RlcmluZy1yZWR1eC5odG1sI2FkanVzdGVkLXJhbmQtaW5kZXgpLgoKV2UnbGwgdXNlIHRoZSBmdW5jdGlvbiBgck9wZW5TY1BDQTo6Y2FsY3VsYXRlX3N0YWJpbGl0eSgpYCB0byBjYWxjdWxhdGUgdGhlIGNsdXN0ZXIgc3RhYmlsaXR5LgpCeSBkZWZhdWx0LCB0aGlzIGZ1bmN0aW9uIHBlcmZvcm1zIDIwIGJvb3RzdHJhcCByZXBsaWNhdGVzLCBidXQgdGhpcyBjYW4gYmUgY3VzdG9taXplZCB1c2luZyB0aGUgYXJndW1lbnQgYHJlcGxpY2F0ZXNgLgoKVGhpcyBmdW5jdGlvbiB3aWxsIHJldHVybiBhIGRhdGEgZnJhbWUgd2l0aCBjb2x1bW5zIGByZXBsaWNhdGVgLCBgYXJpYCwgYW5kIGFkZGl0aW9uYWwgY29sdW1ucyBmb3IgdGhlIGNsdXN0ZXJpbmcgcGFyYW1ldGVycyB1c2VkIHdoZW4gY2FsY3VsYXRpbmcgYm9vdHN0cmFwIGNsdXN0ZXJzLgoKYGBge3Igc3RhYmlsaXR5LCB3YXJuaW5nPUZBTFNFfQojIGNhbGN1bGF0ZSB0aGUgc3RhYmlsaXR5IG9mIGNsdXN0ZXJzCnN0YWJpbGl0eV9yZXN1bHRzIDwtIHJPcGVuU2NQQ0E6OmNhbGN1bGF0ZV9zdGFiaWxpdHkoCiAgcGNhX21hdHJpeCwKICBjbHVzdGVyX3Jlc3VsdHNfZGYKKQoKIyBwcmludCB0aGUgcmVzdWx0CnN0YWJpbGl0eV9yZXN1bHRzCmBgYAoKV2UgY2FuIHZpc3VhbGl6ZSB0aGVzZSByZXN1bHRzIGJ5IHBsb3R0aW5nIHN0YWJpbGl0eSBhcyBhIGRlbnNpdHkgcGxvdCwgZm9yIGV4YW1wbGU6CgpgYGB7ciBhcmkgZGVuc2l0eX0KZ2dwbG90KHN0YWJpbGl0eV9yZXN1bHRzKSArCiAgYWVzKHggPSBhcmkpICsKICBnZW9tX2RlbnNpdHkoY29sb3IgPSAiZ3JleTMwIiwgZmlsbCA9ICJsaWdodHNsYXRlYmx1ZSIpICsKICBsYWJzKHggPSAiQWRqdXN0ZWQgcmFuZCBpbmRleCBhY3Jvc3MgYm9vdHN0cmFwIHJlcGxpY2F0ZXMiKQpgYGAKCgojIyMjIFVzaW5nIG5vbi1kZWZhdWx0IGNsdXN0ZXJpbmcgcGFyYW1ldGVycwoKV2hlbiBjYWxjdWxhdGluZyBib290c3RyYXAgY2x1c3RlcnMsIGByT3BlblNjUENBOjpjYWxjdWxhdGVfc3RhYmlsaXR5KClgIHVzZXMgYHJPcGVuU2NQQ0E6OmNhbGN1bGF0ZV9jbHVzdGVycygpYCB3aXRoIGRlZmF1bHQgcGFyYW1ldGVycy4KSWYgeW91ciBvcmlnaW5hbCBjbHVzdGVycyB3ZXJlIG5vdCBjYWxjdWxhdGVkIHdpdGggdGhlc2UgZGVmYXVsdHMsIHlvdSBzaG91bGQgcGFzcyB0aG9zZSBjdXN0b21pemVkIHZhbHVlcyBpbnRvIHRoaXMgZnVuY3Rpb24gYXMgd2VsbCB0byBlbnN1cmUgYSBmYWlyIGNvbXBhcmlzb24gYmV0d2VlbiB5b3VyIG9yaWdpbmFsIGNsdXN0ZXJzIGFuZCB0aGUgYm9vdHN0cmFwIGNsdXN0ZXJzLgoKCmBgYHtyIHN0YWJpbGl0eSBjdXN0b20gcGFyYW1ldGVyc30KIyBDYWxjdWxhdGUgY2x1c3RlcnMgd2l0aCBub24tZGVmYXVsdCBwYXJhbWV0ZXJzCmNsdXN0ZXJfZGZfbGVpZGVuIDwtIHJPcGVuU2NQQ0E6OmNhbGN1bGF0ZV9jbHVzdGVycygKICBwY2FfbWF0cml4LAogIGFsZ29yaXRobSA9ICJsZWlkZW4iLAogIHJlc29sdXRpb24gPSAwLjUsCiAgbm4gPSAxNQopCgojIE5vdywgcGFzcyBpbiB0aGUgc2FtZSBhcmd1bWVudHMgY3VzdG9taXppbmcgcGFyYW1ldGVycyBoZXJlCnN0YWJpbGl0eV9yZXN1bHRzX2xlaWRlbiA8LSByT3BlblNjUENBOjpjYWxjdWxhdGVfc3RhYmlsaXR5KAogIHBjYV9tYXRyaXgsCiAgY2x1c3Rlcl9kZl9sZWlkZW4sCiAgYWxnb3JpdGhtID0gImxlaWRlbiIsCiAgcmVzb2x1dGlvbiA9IDAuNSwKICBubiA9IDE1CikKYGBgCgoKIyMgV29ya2luZyB3aXRoIG9iamVjdHMgZGlyZWN0bHkKCkFzIHByZXNlbnRlZCBhYm92ZSwgYHJPcGVuU2NQQ0FgIGNsdXN0ZXJpbmcgZnVuY3Rpb25zIHRha2UgYSBQQ0EgbWF0cml4IHdpdGggcm93IG5hbWVzIHJlcHJlc2VudGluZyB1bmlxdWUgY2VsbCBpZHMgYXMgdGhlaXIgZmlyc3QgYXJndW1lbnQuCgpJbnN0ZWFkIG9mIGEgbWF0cml4LCB5b3UgY2FuIGFsdGVybmF0aXZlbHkgcGFzcyBpbiBhbiBTQ0Ugb3IgU2V1cmF0IG9iamVjdCB0aGF0IGNvbnRhaW5zIGEgbWF0cml4LgoKV2Ugc2hvdyBhbiBleGFtcGxlIG9mIHRoaXMgYmVsb3cgd2l0aCBhbmQgU0NFIG9iamVjdCBhbmQgYHJPcGVuU2NQQ0E6OmNhbGN1bGF0ZV9jbHVzdGVycygpYCwgYnV0IHRoaXMgd2lsbCBhbHNvIHdvcmsgZm9yIGFueSBvZiB0aGUgZXZhbHVhdGlvbiBmdW5jdGlvbnMgYXMgd2VsbCBhbmQgaGFzIHRoZSBzYW1lIHN5bnRheCBmb3IgU2V1cmF0IG9iamVjdHMuCgpgYGB7ciBydW4gb24gc2NlfQojIENhbGN1bGF0ZSBjbHVzdGVycyBmcm9tIGFuIFNDRSBvYmplY3QgdXNpbmcgZGVmYXVsdCBwYXJhbWV0ZXJzCmNsdXN0ZXJfcmVzdWx0c19kZiA8LSByT3BlblNjUENBOjpjYWxjdWxhdGVfY2x1c3RlcnMoc2NlKQpjbHVzdGVyX3Jlc3VsdHNfZGYKYGBgCgoKYHJPcGVuU2NQQ0FgIGFzc3VtZXMgdGhhdCB0aGUgUENBIG1hdHJpeCBpcyBuYW1lZCBgUENBYCBpbiBTQ0Ugb2JqZWN0cywgYW5kIGBwY2FgIGluIFNldXJhdCBvYmplY3RzLgpJZiB0aGUgUENBIG1hdHJpeCB5b3Ugd2FudCB0byB1c2UgaW4gdGhlIG9iamVjdCBoYXMgYSBkaWZmZXJlbnQgbmFtZSwgeW91IGNhbiBwcm92aWRlIHRoZSBhcmd1bWVudCBgcGNfbmFtZWAuCgoKIyMgQ2FsY3VsYXRpbmcgUUMgbWV0cmljcyBvbiBleGlzdGluZyBjbHVzdGVycwoKSWYgeW91IGFscmVhZHkgaGF2ZSBjbHVzdGVyaW5nIHJlc3VsdHMgY2FsY3VsYXRlZCB3aXRoIG90aGVyIHRvb2xzLCB5b3UgY2FuIHN0aWxsIHVzZSB0aGUgYHJPcGVuU2NQQ0FgIGZ1bmN0aW9ucyB0byBldmFsdWF0ZSB5b3VyIGNsdXN0ZXJzLgoKSW4gdGhpcyBzZWN0aW9uLCB3ZSdsbCBwcmVzZW50IGV4YW1wbGVzIG9mIGhvdyB5b3UgY2FuIGNhbGN1bGF0ZSB0aGUgc2lsaG91ZXR0ZSB3aWR0aCwgbmVpZ2hib3Job29kIHB1cml0eSwgYW5kIGNsdXN0ZXIgc3RhYmlsaXR5IGZyb20gZXhpc3RpbmcgY2x1c3RlciBhc3NpZ25tZW50cyB3aXRoaW4gb2JqZWN0cy4KCiMjIyBFdmFsdWF0aW5nIFNldXJhdCBjbHVzdGVycwoKSWYgeW91IGFyZSBhbmFseXppbmcgeW91ciBkYXRhIHdpdGggYSBTZXVyYXQgcGlwZWxpbmUgdGhhdCBpbmNsdWRlcyBjYWxjdWxhdGluZyBjbHVzdGVycywgeW91IGNhbiB1c2UgYHJPcGVuU2NQQ0FgIHRvIGV2YWx1YXRlIHRoZW0uCgpUbyBkZW1vbnN0cmF0ZSB0aGlzLCB3ZSdsbCBjb252ZXJ0IG91ciBTQ0Ugb2JqZWN0IHRvIGEgU2V1cmF0IHVzaW5nIHRoZSBmdW5jdGlvbiBgck9wZW5TY1BDQTo6c2NlX3RvX3NldXJhdCgpYC4KVGhlbiwgd2UnbGwgdXNlIGEgc2ltcGxlIFNldXJhdCBwaXBlbGluZSB0byBvYnRhaW4gY2x1c3RlcnMuCgpgYGB7ciBzY2UgdG8gc2V1cmF0LCBtZXNzYWdlID0gRkFMU0V9CiMgQ29udmVydCB0aGUgU0NFIHRvIGEgU2V1cmF0IG9iamVjdCB1c2luZyByT3BlblNjUENBCnNldXJhdF9vYmogPC0gck9wZW5TY1BDQTo6c2NlX3RvX3NldXJhdChzY2UpCgojIENhbGN1bGF0ZSBjbHVzdGVycyB3aXRoIFNldXJhdCB1c2luZyBhIHN0YW5kYXJkIFNldXJhdCBwaXBlbGluZSwgZm9yIGV4YW1wbGUKc2V1cmF0X29iaiA8LSBzZXVyYXRfb2JqIHw+CiAgU0NUcmFuc2Zvcm0oKSB8PgogIFJ1blBDQSgpIHw+CiAgRmluZE5laWdoYm9ycygpIHw+CiAgRmluZENsdXN0ZXJzKCkKCnNldXJhdF9vYmoKYGBgCgoKVG8gY2FsY3VsYXRlIFFDIG1ldHJpY3Mgb24gdGhlc2UgY2x1c3RlcnMsIHdlJ2xsIG5lZWQgdG8gY3JlYXRlIGEgZGF0YSBmcmFtZSB3aXRoIGNvbHVtbnMgYGNlbGxfaWRgIGFuZCBgY2x1c3RlcmA6CgpgYGB7ciBwcmVwYXJlIHNldXJhdCBpbnB1dH0KIyBDcmVhdGUgYSBkYXRhIGZyYW1lIGZvciBpbnB1dApzZXVyYXRfY2x1c3Rlcl9kZiA8LSBkYXRhLmZyYW1lKAogIGNlbGxfaWQgPSBjb2xuYW1lcyhzZXVyYXRfb2JqKSwKICBjbHVzdGVyID0gc2V1cmF0X29iaiRzZXVyYXRfY2x1c3RlcnMKKQoKaGVhZChzZXVyYXRfY2x1c3Rlcl9kZikKYGBgCgpOb3csIHdlIGNhbiBydW4gYHJPcGVuU2NQQ0E6OmNhbGN1bGF0ZV9zaWxob3VldHRlKClgIGFuZCBgck9wZW5TY1BDQTo6Y2FsY3VsYXRlX3B1cml0eSgpYCB1c2luZyB0aGlzIGRhdGEgZnJhbWUgYW5kIHRoZSBTZXVyYXQgb2JqZWN0OgoKYGBge3Igc2V1cmF0IHNpbGhvdWV0dGV9CnNldXJhdF9zaWxob3VldHRlX2RmIDwtIHJPcGVuU2NQQ0E6OmNhbGN1bGF0ZV9zaWxob3VldHRlKAogIHNldXJhdF9vYmosCiAgc2V1cmF0X2NsdXN0ZXJfZGYKKQpgYGAKCmBgYHtyIHNldXJhdCBwdXJpdHl9CnNldXJhdF9wdXJpdHlfZGYgPC0gck9wZW5TY1BDQTo6Y2FsY3VsYXRlX3B1cml0eSgKICBzZXVyYXRfb2JqLAogIHNldXJhdF9jbHVzdGVyX2RmCikKYGBgCgpXZSBkbyBub3QgcmVjb21tZW5kIHVzaW5nIGByT3BlblNjUENBOjpjYWxjdWxhdGVfc3RhYmlsaXR5KClgIG9uIFNldXJhdCBjbHVzdGVycyBkdWUgdG8gZGlmZmVyZW5jZXMgaW4gdGhlIHVuZGVybHlpbmcgY2x1c3RlcmluZyBhcHByb2FjaCBiZXR3ZWVuIFNldXJhdCBhbmQgdGhlIGBibHVzdGVyYCBwYWNrYWdlIHdoaWNoIGByT3BlblNjUENBYCB1c2VzLgoKIyMjIEV2YWx1YXRpbmcgU2NQQ0EgY2x1c3RlcnMKClNjUENBIGNlbGwgbWV0YWRhdGEgYWxyZWFkeSBjb250YWlucyBhIGNvbHVtbiBjYWxsZWQgYGNsdXN0ZXJgIHdpdGggcmVzdWx0cyBmcm9tIGFuIGF1dG9tYXRlZCBjbHVzdGVyaW5nLgpUaGVzZSBjbHVzdGVycyB3ZXJlIGNhbGN1bGF0ZWQgdXNpbmcgYGJsdXN0ZXJgLCB0aGUgc2FtZSB0b29sIHRoYXQgYHJPcGVuU2NQQ0FgIHVzZXMuClRoZSBzcGVjaWZpY2F0aW9ucyB1c2VkIGZvciB0aGlzIGNsdXN0ZXJpbmcgYXJlIHN0b3JlZCBpbiB0aGUgU0NFIG9iamVjdCdzIG1ldGFkYXRhLCBhcyBmb2xsb3dzOyBub3RlIHRoYXQgYWxsIG90aGVyIGNsdXN0ZXJpbmcgcGFyYW1ldGVycyB3ZXJlIGxlZnQgYXQgdGhlaXIgZGVmYXVsdCB2YWx1ZXMuCgoqIGBtZXRhZGF0YShzY2UpJGNsdXN0ZXJfYWxnb3JpdGhtYDogVGhlIGNsdXN0ZXJpbmcgYWxnb3JpdGhtIHVzZWQKKiBgbWV0YWRhdGEoc2NlKSRjbHVzdGVyX3dlaWdodGluZ2A6IFRoZSB3ZWlnaHRpbmcgc2NoZW1lIHVzZWQKKiBgbWV0YWRhdGEoc2NlKSRjbHVzdGVyX25uYDogVGhlIG51bWJlciBvZiBuZWFyZXN0IG5laWdoYm9ycyB1c2VkCgpZb3UgY2FuIHNlZSBhbGwgdGhlaXIgdmFsdWVzIGhlcmU6CgoKYGBge3IgZXh0cmFjdCBjbHVzdGVyIHBhcmFtc30KIyBQcmludCBjbHVzdGVyaW5nIHNwZWNpZmljYXRpb25zCm1ldGFkYXRhKHNjZSlbYygiY2x1c3Rlcl9hbGdvcml0aG0iLCAiY2x1c3Rlcl93ZWlnaHRpbmciLCAiY2x1c3Rlcl9ubiIpXQpgYGAKCgpJbiB0aGlzIGV4YW1wbGUsIHdlJ2xsIHNob3cgaG93IHRvIHVzZSB0aGUgY2x1c3RlciBldmFsdWF0aW9uIGZ1bmN0aW9ucyBvbiB0aGVzZSBjbHVzdGVycy4KClRvIGJlZ2luLCB3ZSdsbCBwcmVwYXJlIGEgZGF0YSBmcmFtZSB3aXRoIHR3byBjb2x1bW5zOiBgY2VsbF9pZGAgY29udGFpbmluZyBjZWxsIGJhcmNvZGVzLCBhbmQgYGNsdXN0ZXJgIGNvbnRhaW5pbmcgdGhlIGNsdXN0ZXIgaWRlbnRpdGllcy4KCmBgYHtyIHByZXBhcmUgc2NwY2EgZGF0YSBmcmFtZX0Kc2NwY2FfY2x1c3Rlcl9kZiA8LSBkYXRhLmZyYW1lKAogIGNlbGxfaWQgPSBjb2xuYW1lcyhzY2UpLAogIGNsdXN0ZXIgPSBzY2UkY2x1c3RlcgopCgpoZWFkKHNjcGNhX2NsdXN0ZXJfZGYpCmBgYAoKV2UgY2FuIHJ1biBldmFsdWF0aW9uIGZ1bmN0aW9ucyB1c2luZyB0aGlzIGRhdGEgZnJhbWUgYW5kIHRoZSBTQ0Ugb2JqZWN0LgoKYGBge3Igc2NwY2Egc2lsaG91ZXR0ZX0KIyBDYWxjdWxhdGUgc2lsaG91ZXR0ZSB3aWR0aApzY3BjYV9zaWxob3VldHRlX2RmIDwtIHJPcGVuU2NQQ0E6OmNhbGN1bGF0ZV9zaWxob3VldHRlKAogIHNjZSwKICBzY3BjYV9jbHVzdGVyX2RmCikKYGBgCgpgYGB7ciBzY3BjYSBwdXJpdHl9CiMgQ2FsY3VsYXRlIG5laWdoYm9yaG9vZCBwdXJpdHkKc2NwY2FfcHVyaXR5X2RmIDwtIHJPcGVuU2NQQ0E6OmNhbGN1bGF0ZV9wdXJpdHkoCiAgc2NlLAogIHNjcGNhX2NsdXN0ZXJfZGYKKQpgYGAKCldoZW4gcnVubmluZyBgck9wZW5TY1BDQTo6Y2FsY3VsYXRlX3N0YWJpbGl0eSgpYCwgd2UnbGwgc3BlY2lmeSB0aGUgc2FtZSBwYXJhbWV0ZXJzIG9yaWdpbmFsbHkgdXNlZCB0byBidWlsZCB0aGUgY2x1c3RlcnMgYnkgZXh0cmFjdGluZyB0aGVtIGZyb20gdGhlIG1ldGFkYXRhLgpXZSdsbCBuZWVkIHRvIGVuc3VyZSB0aGUgcHJvdmlkZWQgYXJndW1lbnRzIGFyZSBsb3dlcmNhc2UsIGFzIHdlbGwuCgpHZW5lcmFsbHkgc3BlYWtpbmcsIHdlIG9ubHkgcmVjb21tZW5kIGV2YWx1YXRpbmcgY2x1c3RlcnMgd2l0aCBgck9wZW5TY1BDQTo6Y2FsY3VsYXRlX3N0YWJpbGl0eSgpYCBpZiB5b3Uga25vdyB0aGUgb3JpZ2luYWwgcGFyYW1ldGVycyB1c2VkLgoKCmBgYHtyIHNjcGNhIHN0YWJpbGl0eX0Kc2NwY2Ffc3RhYmlsaXR5X2RmIDwtIHJPcGVuU2NQQ0E6OmNhbGN1bGF0ZV9zdGFiaWxpdHkoCiAgc2NlLAogIHNjcGNhX2NsdXN0ZXJfZGYsCiAgIyBwcm92aWRlIFNjUENBIGNsdXN0ZXJpbmcgcGFyYW1ldGVycyBieSBleHRyYWN0aW5nIGZyb20gdGhlIFNDRSBtZXRhZGF0YQogIGFsZ29yaXRobSA9IHRvbG93ZXIobWV0YWRhdGEoc2NlKSRjbHVzdGVyX2FsZ29yaXRobSksCiAgd2VpZ2h0aW5nID0gdG9sb3dlcihtZXRhZGF0YShzY2UpJGNsdXN0ZXJfd2VpZ2h0aW5nKSwKICBubiA9IG1ldGFkYXRhKHNjZSkkY2x1c3Rlcl9ubgopCmBgYAoKCiMjIFNhdmluZyBjbHVzdGVyaW5nIHJlc3VsdHMKClJlc3VsdHMgY2FuIGVpdGhlciBiZSBkaXJlY3RseSBleHBvcnRlZCBhcyBhIFRTViBmaWxlIChlLmcuLCB3aXRoIGByZWFkcjo6d3JpdGVfdHN2KClgKSwgb3IgeW91IGNhbiBhZGQgdGhlIHJlc3VsdHMgaW50byB5b3VyIFNDRSBvciBTZXVyYXQgb2JqZWN0LgpUaGUgc3Vic2VxdWVudCBleGFtcGxlcyB3aWxsIGRlbW9uc3RyYXRlIHNhdmluZyB0aGUgY2x1c3RlciBhc3NpZ25tZW50cyBzdG9yZWQgaW4gYGNsdXN0ZXJfcmVzdWx0c19kZiRjbHVzdGVyYCB0byBhbiBTQ0UgYW5kIGEgU2V1cmF0IG9iamVjdC4KCl9BIHdvcmQgb2YgY2F1dGlvbiFfCk9iamVjdHMgZnJvbSB0aGUgU2NQQ0EgUG9ydGFsIGFscmVhZHkgY29udGFpbiBhIGNvbHVtbiBjYWxsZWQgYGNsdXN0ZXJgIHdpdGggcmVzdWx0cyBmcm9tIGFuIGF1dG9tYXRlZCBjbHVzdGVyaW5nLgpUaGVzZSBhdXRvbWF0aWMgY2x1c3RlcnMgd2VyZSBub3QgZXZhbHVhdGVkLCBhbmQgdGhlaXIgcGFyYW1ldGVycyB3ZXJlIG5vdCBvcHRpbWl6ZWQgZm9yIGFueSBnaXZlbiBsaWJyYXJ5LgpUbyBhdm9pZCBhbWJpZ3VpdHkgYmV0d2VlbiB0aGUgZXhpc3RpbmcgYW5kIG5ldyBjbHVzdGVyaW5nIHJlc3VsdHMsIHdlJ2xsIG5hbWUgdGhlIG5ldyBjb2x1bW4gYHJvcGVuc2NwY2FfY2x1c3RlcmAuCgojIyMgU2F2aW5nIHJlc3VsdHMgdG8gYW4gU0NFIG9iamVjdAoKV2UgY2FuIGFkZCBjb2x1bW5zIHRvIGFuIFNDRSBvYmplY3QncyBgY29sRGF0YWAgdGFibGUgYnkgZGlyZWN0bHkgY3JlYXRpbmcgYSBjb2x1bW4gaW4gdGhlIG9iamVjdCB3aXRoIGAkYC4KQmVmb3JlIHdlIGRvIHNvLCB3ZSdsbCBjb25maXJtIHRoYXQgdGhlIGNsdXN0ZXJzIGFyZSBpbiB0aGUgc2FtZSBvcmRlciBhcyB0aGUgU0NFIG9iamVjdCBieSBjb21wYXJpbmcgY2VsbCBpZHM6CgpgYGB7ciBjaGVjayBzY2Ugb3JkZXJ9CmFsbC5lcXVhbCgKICBjb2xuYW1lcyhzY2UpLAogIGNsdXN0ZXJfcmVzdWx0c19kZiRjZWxsX2lkCikKYGBgCgpgYGB7ciBhZGQgdG8gc2NlfQojIEFkZCBjbHVzdGVyIHJlc3VsdHMgdG8gdGhlIGNvbERhdGEKc2NlJHJvcGVuc2NwY2FfY2x1c3RlciA8LSBjbHVzdGVyX3Jlc3VsdHNfZGYkY2x1c3RlcgpgYGAKCiMjIyBTYXZpbmcgcmVzdWx0cyB0byBhIFNldXJhdCBvYmplY3QKCgpXZSBjYW4gYWRkIGNvbHVtbnMgdG8gYW4gU2V1cmF0IG9iamVjdCdzIGNlbGwgbWV0YWRhdGEgdGFibGUgYnkgZGlyZWN0bHkgY3JlYXRpbmcgYSBjb2x1bW4gaW4gdGhlIG9iamVjdCB3aXRoIGAkYCAobm90ZSB0aGF0IHlvdSBjYW4gYWxzbyB1c2UgdGhlIFNldXJhdCBmdW5jdGlvbiBgQWRkTWV0YURhdGEoKWApLgpCZWZvcmUgd2UgZG8gc28sIHdlJ2xsIGNvbmZpcm0gdGhhdCB0aGUgY2x1c3RlcnMgYXJlIGluIHRoZSBzYW1lIG9yZGVyIGFzIHRoZSBTZXVyYXQgb2JqZWN0IGJ5IGNvbXBhcmluZyBjZWxsIGlkczoKCgpgYGB7ciBjaGVjayBzZXVyYXQgb3JkZXJ9CmFsbC5lcXVhbCgKICBjb2xuYW1lcyhzZXVyYXRfb2JqKSwKICBjbHVzdGVyX3Jlc3VsdHNfZGYkY2VsbF9pZAopCmBgYAoKYGBge3IgYWRkIHRvIHNldXJhdH0KIyBBZGQgY2x1c3RlciByZXN1bHRzIHRvIHRoZSBjZWxsIG1ldGFkYXRhCnNldXJhdF9vYmokcm9wZW5zY3BjYV9jbHVzdGVyIDwtIGNsdXN0ZXJfcmVzdWx0c19kZiRjbHVzdGVyCmBgYAoKCiMjIFNlc3Npb24gSW5mbwoKYGBge3Igc2Vzc2lvbiBpbmZvfQojIHJlY29yZCB0aGUgdmVyc2lvbnMgb2YgdGhlIHBhY2thZ2VzIHVzZWQgaW4gdGhpcyBhbmFseXNpcyBhbmQgb3RoZXIgZW52aXJvbm1lbnQgaW5mb3JtYXRpb24Kc2Vzc2lvbkluZm8oKQpgYGAK