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 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 @@ # 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 ]
-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 @@ # 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 @@ 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 @@ fastMNN
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 @@ 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 @@ fastMNN
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 @@ harmony
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 @@ harmony
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?
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 ]
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 @@ 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