Workflow Overview
Introduction
A frequent bottleneck in the single-cell RNA-seq analysis workflow is
annotating our clustering results, as it requires bridging the gap
between the data and prior knowledge (source).
While generating markers for each cluster and evaluating the expression
of known marker genes is important, it may or may not be sufficient to
assign cell-type or sub-type labels.
|
For each cell-type (A), the marker genes we derived in the prior step
(B) are compared with known marker genes for different cell types (C).
Concordance between derived marker genes and known cell markers produces
a suggested annotation for that cell type.
|
In this section, our goal is to use an automated annotation tool to
generate cell type predictions for our clusters.
Like the previous sections, the process to assign cell-types to
clusters can be very iterative. In addition, the steps to reach a
“Figure 1” level of labeled clusters may not be presented in detail, can
be very dataset dependent, and often is more challenging for less
characterized tissues.
Objectives
- Understand the complexities of cell-type annotation
- Use
scCATCH
cell-type predictions to annotate our
clusters
Cell type predictions
Automated tools have the advantage of being able to compare between
the expression patterns in our dataset and large numbers of reference
datasets or databases at a scale that is not feasible to do
manually.
As described in
more detail by the Ouyang Lab and summarized in the figure below,
there are many computational tools that aim to assign cell type labels
for single-cell data. These methods generally fall into three
categories:
- Marker based approaches that use gene sets drawn from the
literature, including previous single-cell studies,
- Correlation based approaches that estimate the similarity between
the cells or clusters in the input data and some reference data
- Machine learning approaches that include training on a single-cell
reference atlas.
Image: Diagram of types of cell annotation
approaches (from Oyang materials).
However, across any of these approaches the quality of the reference
data (and reliability of the authors labels) and relevancy to your
specific tissue/experiment (and the resolution of your biological
question) is crucial. Additionally, it’s important to consider that rare
or novel cell populations may not be present or well-characterized in
available references and that even after filtering, some clusters might
correspond to stressed or dying cells and not a particular cell-type or
subtype. Therefore, any prediction should be reviewed and considered in
the context both marker gene expression for the dataset and knowledge of
the biological system and broader literature.
Some tools and references are available solely or primarily for human
tissues (and not mouse or rat), particular for tissues other than PBMCs
and the brain. For human data, if a relevant reference is available for
your experiment, we would recommend trying Azimuth (created by authors
of Seurat). 10x
has a tutorial that includes example of using Azimuth, including a
feature of the tool that allows for first pass of cell-type assignment
of more common cell-types followed by identifying rarer populations that
may not be identified in the first pass.
Additional automated annotation resources
Automated cell-type annotation is an active area of research and
development and many other tools and resources are available, including
OSCA’s
demonstration of the SingleR method, a Tutorial by Clarke et
al. for cell-type annotations, and an entire
chapter of the SC best practices book.
Using scCATCH
A tool we often use for both mouse and human data cell-type
predictions is called scCATCH which, per
the author’s description in Shao et al
(2020), annotates cell-types using a “tissue-specific cellular
taxonomy reference database (CellMatch) and [an] evidence-based scoring
(ES) protocol”. The CellMatch reference is compiled from CellMarker (Zhang
et al., 2019b), MCA (Han
et al., 2018), CancerSEA (Yuan
et al., 2019), and the CD
Marker Handbook and PMIDs for relevant literature are reported in
the prediction results.
Image: scCATCH summary from Shao et al
(2020).
First, we need to load the scCATCH library. Then, we’ll double check
that we are using the expected resolution cluster results (this is
particularly important if we generated multiple resolutions in our
clustering steps), before creating a new object from our
counts
data with createscCATCH()
and adding
our marker genes to the scCATCCH object.
To increase the speed and accuracy of our predictions, we’ll create
query of relevant tissues (which requires some prior knowledge of the
experiment and using the scCATCH wiki to
select tissues from the species) before we run the tool:
##### Day 3 - Cell Type Annotation
# Annotate clusters using scCATCH ----------------------------------------
library(scCATCH)
# check that cell identities are set to expected resolution
all(Idents(geo_so) == geo_so$integrated.sct.rpca.clusters)
[1] TRUE
# create scCATCH object, using count data
geo_catch = createscCATCH(data = geo_so@assays$SCT@counts, cluster = as.character(Idents(geo_so)))
# add marker genes to use for predictions
geo_catch@markergene = geo_markers
# specify tissues/cell-types from the scCATCH reference
geo_catch@marker = cellmatch[cellmatch$species == 'Mouse' & cellmatch$tissue %in% c('Blood', 'Peripheral Blood', 'Muscle', 'Skeletal muscle', 'Epidermis', 'Skin'), ]
# run scCATCH to generate predictions
geo_catch = findcelltype(geo_catch)
# look at the predictions
geo_catch@celltype %>% select(cluster, cell_type, celltype_score)
cluster cell_type celltype_score
1 0 Pericyte 0.75
2 1 Hematopoietic Stem Cell 0.86
3 2 Muscle Progenitor Cell 0.71
4 3 Macrophage 0.82
5 4 Monocyte 0.82
6 5 Dendritic Cell 0.86
7 6 Stem Cell 0.88
8 7 Hematopoietic Stem Cell 0.9
9 8 Hematopoietic Stem Cell 0.91
10 9 Hematopoietic Stem Cell 0.86
11 10 Dendritic Cell 0.84
12 11 Regulatory T Cell 0.9
13 12 Dendritic Cell 0.85
14 13 Muscle Satellite Cell 0.94
15 14 Dendritic Cell, Monocyte, Progenitor Cell 0.71, 0.71, 0.71
16 15 Hematopoietic Stem Cell 0.87
17 16 Stem Cell 0.84
18 17 CD8+ T Cell 0.88
19 18 Hematopoietic Stem Cell 0.87
20 19 Muscle Cell 0.69
When we look at our results we can see the cell type score, which
gives us an idea of the confidence of that prediction. Not shown here
but the full celltype
table also includes marker genes and
PMIDs for relevant literature for each prediction.
In our experience, these kinds of results often help guide cluster
annotation but scores can vary and the predictions may need to be
revised based on researcher’s knowledge of the biological system. As
these cell-types correspond to the cell-types and subtypes we’d expect
to be present in these data and most of the prediction scores are quite
high, we can reasonably use these results to annotate our clusters with
some minor adjustments.
Using known cell-type markers
To confirm and refine the scCATCH predictions, we’ll spot check some
known markers for immune populations. Then we’ll look look at some other
key marker genes from some other relevant resources like Chen et al
(2021), Buechler et al
(2021) Roman
(2023), Li
et al (2022) and Nestorowa
et al (2016) to see if other modifications should be made to the
scCATCH predictions:
# Plot other markers/features to assist with identification ---------------
# spot check known immune markers
immune_markers = list()
immune_markers[['Inflam. Macrophage']] = c('Cd14', 'Cxcl2') # Cd14 a- monocyte/macrophage cells
immune_markers[['Platelet']] = c('Pf4')
immune_markers[['Mast cells']] = c('Gata2', 'Kit')
immune_markers[['NK cells']] = c('Nkg7', 'Klrd1')
immune_markers[['B-cell']] = c( 'Ly6d', 'Cd19', 'Cd79b', 'Ms4a1')
immune_markers[['T-cell']] = c( 'Cd3d','Cd3e','Cd3g') # also Thy1
immune_markers_plot = DotPlot(geo_so, features = immune_markers, assay = 'SCT') +
theme(text=element_text(size=10), axis.text.x = element_text(angle = 45, vjust = 0.5))
Warning: The `facets` argument of `facet_grid()` is deprecated as of ggplot2 2.2.0.
ℹ Please use the `rows` argument instead.
ℹ The deprecated feature was likely used in the Seurat package.
Please report the issue at <https://github.com/satijalab/seurat/issues>.
This warning is displayed once every 8 hours.
Call `lifecycle::last_lifecycle_warnings()` to see where this warning was generated.
immune_markers_plot
# save to file
ggsave(filename = 'results/figures/immune_markers_sct_dot_plot.png', plot = immune_markers_plot, width = 10, height = 5, units = 'in')
# plot some known cell-type markers
other_markers = list()
other_markers[['Pericyte']] = c('Acan','Sox9')
other_markers[['SMC']] = c('Acta2', 'Myh11') # SMC = mesenchymal smooth-muscle cell/mesenchymal lineage
other_markers[['Keratinocytes']] = c('Thy1', 'Dlk1') # fibro progenitors aso=Thy1
other_markers[['Myofibroblasts']] = c('Tmem100', 'Cd34', 'Ly6c1') # hematopoetic stem/activated fibroblast=Cd34
other_markers[['Fibroblast']] = c('Dpt', 'Fn1', 'Col3a1') # activated fib = Fn1
other_markers[['Endothelial']] = c('Pecam1', 'Cd38') # from wound healing; Pecam1 also exp in endothelial
other_markers[['HSC']] = c('Ltb', 'Cd74') # less well defined/conflicting definitions
other_markers[['Erythroid']] = c('Hba-a1')
other_markers_dot_plot = DotPlot(geo_so, features = other_markers, assay = 'SCT') +
theme(text=element_text(size=10), axis.text.x = element_text(angle = 45, vjust = 0.5))
other_markers_dot_plot
# save to file
ggsave(filename = 'results/figures/other_markers_sct_dot_plot.png', plot = other_markers_dot_plot, width = 12, height = 5, units = 'in')
In the first plot, B-cell and T-cell markers seem to line up with the
predictions and are limited to single clusters. However, macrophage and
dendrocyte markers match to multiple clusters including some annotated
with different cell types, so we can consider modifying those cluster
labels.
From the other marker genes, the patterns are less clear so we may
want to test other clustering parameters and discuss the results with a
researcher familiar with the expected cell types. However, we can notice
some patterns that we can use to refine our cluster annotations.
Utilizing genes of interest from the original paper
Plotting the expression of genes of interest from Sorkin, Huber et
al
Often we have prior information about what cell types are expected in
our samples and key marker genes for those populations. This can be an
important part of evaluating our clusters, since if genes that are known
markers for a specific cell type are found in too many or too few
clusters as that can suggest that re-clustering is needed or that some
of the clusters should be manually combined before annotating. We can
create lists of markers used in figures from the original
paper before using the same DotPlot()
function to
visualize the expression level and frequency of these genes in our
current clusters:
# Visualize manually selected marker genes --------------------------------
# Create lists of genes from paper
fig1g_markers = c('Cxcl1', 'Cxcl2', 'Ccl2', 'Ccl3', 'Ccl4', 'Il1b', 'Il6b', 'Tnf', 'Tgfb1', 'Tgfb2', 'Tgfb3', 'Cxcl5')
fig1h_markers = c('Cxcr2', 'Csf1r', 'Csf3r', 'Tgfbr1', 'Tgfbr3', 'Il1r1', 'Il6ra', 'Lifr', 'Tgfbr2')
# create DotPlots for genes from paper
fig1g_sct_dot_plot = DotPlot(geo_so, features = fig1g_markers, assay = 'SCT')
Warning: The following requested variables were not found: Il6b
fig1h_sct_dot_plot = DotPlot(geo_so, features = fig1h_markers, assay = 'SCT')
fig1g_sct_dot_plot
fig1h_sct_dot_plot
# save plots to file
ggsave(filename = 'results/figures/markers_fig1g_sct_dot_plot.png', plot = fig1g_sct_dot_plot, width = 8, height = 6, units = 'in')
ggsave(filename = 'results/figures/markers_fig1h_sct_dot_plot.png', plot = fig1h_sct_dot_plot, width = 8, height = 6, units = 'in')
For known marker genes, it’s important to note that since scRNA-seq is
only measuring transcriptional signals that markers at the protein level
(e.g used for approaches like FACS) may be less effective. An
alternative or complement to using marker genes could be methods like
using gene set enrichment (GSEA) as
demonstrated in the OSCA book to aid in annotations. However, the
book “Best
practices for single-cell analysis across modalities” by Heumos, Schaar,
Lance, et al. points out that “it is often useful to work together
with experts … [like a] biologist who has more extensive knowledge of
the tissue, the biology, the expected cell types and markers etc.”. In
our experience, we find that experience and knowledge of the researchers
we work with is invaluable.
Using raw RNA values for genes of interest from Sorkin, Huber et
al
We can also generate the same plots, but using the unintegrated data
by specifying the RNA
assay:
# Visualize manually selected marker genes (from unintegrated data) ------
rna_dot_plot = DotPlot(geo_so, features = fig1g_markers, assay = 'RNA')
fig1h_rna_dot_plot = DotPlot(geo_so, features = fig1h_markers, assay = 'RNA')
ggsave(filename = 'results/figures/markers_fig1g_rna_dot_plot.png', plot = fig1g_rna_dot_plot, width = 8, height = 6, units = 'in')
ggsave(filename = 'results/figures/markers_fig1h_rna_dot_plot.png', plot = fig1h_rna_dot_plot, width = 8, height = 6, units = 'in')
Annotate clusters
Next, we’ll modify the cell type predictions and add the labels to
our Seurat object to replace our clusters’ numerical identities. Note:
we will create a new metadata object where we join cell types. However,
this will destroy the row names - which will cause a problem in Seurat -
so we have to add them back.
# Annotate clusters using modified predictions ----------------------------
# First - Extract the cell types only from the predictions
celltype_annos = geo_catch@celltype %>% select(cluster, cell_type) %>%
mutate(cluster = factor(cluster, levels = c(0:19))) %>% arrange(cluster)
celltype_annos
cluster cell_type
1 0 Pericyte
2 1 Hematopoietic Stem Cell
3 2 Muscle Progenitor Cell
4 3 Macrophage
5 4 Monocyte
6 5 Dendritic Cell
7 6 Stem Cell
8 7 Hematopoietic Stem Cell
9 8 Hematopoietic Stem Cell
10 9 Hematopoietic Stem Cell
11 10 Dendritic Cell
12 11 Regulatory T Cell
13 12 Dendritic Cell
14 13 Muscle Satellite Cell
15 14 Dendritic Cell, Monocyte, Progenitor Cell
16 15 Hematopoietic Stem Cell
17 16 Stem Cell
18 17 CD8+ T Cell
19 18 Hematopoietic Stem Cell
20 19 Muscle Cell
# Customize annotations, remembering that cluster 0 = row 1 in table
celltype_annos$cell_type[c(3,15)] <- "Inflammatory macrophage" # resolves cluster 2 and 14
celltype_annos$cell_type[c(11)] <- "Macrophage"
celltype_annos$cell_type[c(2)] <- "Fibroblast" # revise clusters 1,6 based on markers
celltype_annos$cell_type[c(6)] <- "Myofibroblast"
celltype_annos$cell_type[c(8,9)] <- "Endothelial" # revise cluster 7,8; also have weaker mast cell signal
celltype_annos$cell_type[c(6,13)] <- "Hematopoietic stem cell" # based on markers but could further revise
celltype_annos$cell_type[c(10,19)] <- "Mesenchymal stem/stromal cell" # based on Acta2 signal
celltype_annos$cell_type[c(16)] <- "Erythroid" # cluster 15, less confident but not near other dendritic cells
celltype_annos$cell_type[c(20, 17)] <- "Unknown" # since such small populations, reset cluster 16 & 19 as unknown for now
# Merge cell types in but as a new table to slide into @meta.data
new_metadata = geo_so@meta.data %>% left_join(celltype_annos, by = c('integrated.sct.rpca.clusters' = 'cluster'))
rownames(new_metadata) = rownames(geo_so@meta.data) # We are implicitly relying on the same row order!
# Replace the meta.data
geo_so@meta.data = new_metadata
head(geo_so@meta.data)
orig.ident nCount_RNA nFeature_RNA day replicate percent.mt nCount_SCT nFeature_SCT integrated.sct.rpca.clusters seurat_clusters unintegrated.sct.pca.clusters
HODay0replicate1_AAACCTGAGAGAACAG-1 HO.Day0.replicate1 10234 3226 Day0 replicate1 1.240962 6062 2867 1 2 2
HODay0replicate1_AAACCTGGTCATGCAT-1 HO.Day0.replicate1 3158 1499 Day0 replicate1 7.536415 4607 1509 1 2 2
HODay0replicate1_AAACCTGTCAGAGCTT-1 HO.Day0.replicate1 13464 4102 Day0 replicate1 3.112002 5314 2370 6 2 2
HODay0replicate1_AAACGGGAGAGACTTA-1 HO.Day0.replicate1 577 346 Day0 replicate1 1.559792 3877 1031 10 9 9
HODay0replicate1_AAACGGGAGGCCCGTT-1 HO.Day0.replicate1 1189 629 Day0 replicate1 3.700589 4166 915 0 2 2
HODay0replicate1_AAACGGGCAACTGGCC-1 HO.Day0.replicate1 7726 2602 Day0 replicate1 2.938131 5865 2588 1 2 2
cell_type
HODay0replicate1_AAACCTGAGAGAACAG-1 Fibroblast
HODay0replicate1_AAACCTGGTCATGCAT-1 Fibroblast
HODay0replicate1_AAACCTGTCAGAGCTT-1 Stem Cell
HODay0replicate1_AAACGGGAGAGACTTA-1 Macrophage
HODay0replicate1_AAACGGGAGGCCCGTT-1 Pericyte
HODay0replicate1_AAACGGGCAACTGGCC-1 Fibroblast
Checkpoint : Has the metadata for your
geo_so
object been updated?
We have now added a “cell_type” column to the meta.data
table:
Image: Schematic after adding cell_type
column.
Visualise annotated clusters
Lastly, we can generate a revised UMAP plot with our descriptive
cluster labels by using our updated Seurat object and providing the new
cell_type
label for the group.by
argument:
# Make a labeled UMAP plot of clusters ------------------------------------
catch_umap_plot = DimPlot(geo_so, group.by = 'cell_type', label = TRUE, reduction = 'umap.integrated.sct.rpca')
catch_umap_plot
ggsave(filename = 'results/figures/umap_integrated_catch.png', plot = catch_umap_plot, width = 10, height = 8, units = 'in')
catch_umap_condition_plot = DimPlot(geo_so, group.by = 'cell_type', split.by = 'day', label = TRUE, reduction = 'umap.integrated.sct.rpca')
catch_umap_condition_plot
ggsave(filename = 'results/figures/umap_integrated_catch_byCondition.png', plot = catch_umap_plot, width = 10, height = 8, units = 'in')
Save our progress
We’ll save the scCATCH object. The Seurat object has not been changed
in this module.
# Save Seurat object and annotations --------------------------------------
saveRDS(geo_so, file = 'results/rdata/geo_so_sct_integrated_with_catch.rds')
saveRDS(geo_catch, file = 'results/rdata/geo_catch.rds')
Summary
Now that we have generated reasonable annotations for our clusters,
we can proceed with the step of differential expression which is
essential to addressing our biological question for this experiment.
Next steps: Differential Expression
These materials have been adapted and extended from materials listed
above. These are open access materials distributed under the terms of
the Creative
Commons Attribution license (CC BY 4.0), which permits unrestricted
use, distribution, and reproduction in any medium, provided the original
author and source are credited.
LS0tCnRpdGxlOiAiQ2VsbCBUeXBlIEFubm90YXRpb24iCmF1dGhvcjogIlVNIEJpb2luZm9ybWF0aWNzIENvcmUiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogICAgICAgIGh0bWxfZG9jdW1lbnQ6CiAgICAgICAgICAgIGluY2x1ZGVzOgogICAgICAgICAgICAgICAgaW5faGVhZGVyOiBoZWFkZXIuaHRtbAogICAgICAgICAgICB0aGVtZTogcGFwZXIKICAgICAgICAgICAgdG9jOiB0cnVlCiAgICAgICAgICAgIHRvY19kZXB0aDogNAogICAgICAgICAgICB0b2NfZmxvYXQ6IHRydWUKICAgICAgICAgICAgbnVtYmVyX3NlY3Rpb25zOiBmYWxzZQogICAgICAgICAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgICAgICAgICBtYXJrZG93bjogR0ZNCiAgICAgICAgICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKLS0tCgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgpib2R5LCB0ZCB7CiAgIGZvbnQtc2l6ZTogMThweDsKfQpjb2RlLnJ7CiAgZm9udC1zaXplOiAxMnB4Owp9CnByZSB7CiAgZm9udC1zaXplOiAxMnB4Cn0KCnRhYmxlLmZpZywgdGguZmlnLCB0ZC5maWcgewogIGJvcmRlcjogMXB4IHNvbGlkIGJsYWNrOwogIGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7CiAgcGFkZGluZzogMTVweDsKfQo8L3N0eWxlPgoKYGBge3Iga2xpcHB5LCBlY2hvPUZBTFNFLCBpbmNsdWRlPVRSVUV9CmtsaXBweTo6a2xpcHB5KGxhbmcgPSBjKCJyIiwgIm1hcmtkb3duIiwgImJhc2giKSwgcG9zaXRpb24gPSBjKCJ0b3AiLCAicmlnaHQiKSkKYGBgCgpgYGB7ciwgaW5jbHVkZSA9IEZBTFNFfQpzb3VyY2UoIi4uL2Jpbi9jaHVuay1vcHRpb25zLlIiKQprbml0cl9maWdfcGF0aCgiMDctQ2VsbFR5cGVBbm5vdGF0aW9uLzA3LSIpCmBgYAoKIyBXb3JrZmxvdyBPdmVydmlldyB7LnVubGlzdGVkIC51bm51bWJlcmVkfQoKPGJyLz4KPGltZyBzcmM9ImltYWdlcy93YXlmaW5kZXIvd2F5ZmluZGVyLnBuZyIgYWx0PSJ3YXlmaW5kZXIiIHN0eWxlPSJoZWlnaHQ6IDQwMHB4OyIvPgo8YnIvPgo8YnIvPgoKIyBJbnRyb2R1Y3Rpb24KCkEgZnJlcXVlbnQgYm90dGxlbmVjayBpbiB0aGUgc2luZ2xlLWNlbGwgUk5BLXNlcSBhbmFseXNpcyB3b3JrZmxvdyBpcyBhbm5vdGF0aW5nIG91ciBjbHVzdGVyaW5nIHJlc3VsdHMsIGFzIGl0IHJlcXVpcmVzIGJyaWRnaW5nIHRoZSBnYXAgYmV0d2VlbiB0aGUgZGF0YSBhbmQgcHJpb3Iga25vd2xlZGdlIChbc291cmNlXShodHRwczovL2Jpb2NvbmR1Y3Rvci5vcmcvYm9va3MvMy4xNS9PU0NBLmJhc2ljL2NlbGwtdHlwZS1hbm5vdGF0aW9uLmh0bWwpKS4gV2hpbGUgZ2VuZXJhdGluZyBtYXJrZXJzIGZvciBlYWNoIGNsdXN0ZXIgYW5kIGV2YWx1YXRpbmcgdGhlIGV4cHJlc3Npb24gb2Yga25vd24gbWFya2VyIGdlbmVzIGlzIGltcG9ydGFudCwgaXQgbWF5IG9yIG1heSBub3QgYmUgc3VmZmljaWVudCB0byBhc3NpZ24gY2VsbC10eXBlIG9yIHN1Yi10eXBlIGxhYmVscy4gCgo8dGFibGUgY2xhc3M9J2ZpZyc+Cjx0ciBjbGFzcz0nZmlnJz48dGQgY2xhc3M9J2ZpZyc+IVtdKGltYWdlcy9ncmFwaGljYWxfYWJzdHJhY3RzL2dyYXBoaWNhbF9hYnN0cmFjdF9hbm5vdGF0aW9uLnBuZyk8L3RkPjwvdHI+Cjx0ciBjbGFzcz0nZmlnJz48dGQgY2xhc3M9J2ZpZyc+Rm9yIGVhY2ggY2VsbC10eXBlIChBKSwgdGhlIG1hcmtlciBnZW5lcyB3ZSBkZXJpdmVkIGluIHRoZSBwcmlvciBzdGVwIChCKSBhcmUgY29tcGFyZWQgd2l0aCBrbm93biBtYXJrZXIgZ2VuZXMgZm9yIGRpZmZlcmVudCBjZWxsIHR5cGVzIChDKS4gQ29uY29yZGFuY2UgYmV0d2VlbiBkZXJpdmVkIG1hcmtlciBnZW5lcyBhbmQga25vd24gY2VsbCBtYXJrZXJzIHByb2R1Y2VzIGEgc3VnZ2VzdGVkIGFubm90YXRpb24gZm9yIHRoYXQgY2VsbCB0eXBlLgo8L3RkPjwvdHI+CjwvdGFibGU+CgpJbiB0aGlzIHNlY3Rpb24sIG91ciBnb2FsIGlzIHRvIHVzZSBhbiBhdXRvbWF0ZWQgYW5ub3RhdGlvbiB0b29sIHRvIGdlbmVyYXRlIGNlbGwgdHlwZSBwcmVkaWN0aW9ucyBmb3Igb3VyIGNsdXN0ZXJzLiAKCkxpa2UgdGhlIHByZXZpb3VzIHNlY3Rpb25zLCB0aGUgcHJvY2VzcyB0byBhc3NpZ24gY2VsbC10eXBlcyB0byBjbHVzdGVycyBjYW4gYmUgdmVyeSBpdGVyYXRpdmUuIEluIGFkZGl0aW9uLCB0aGUgc3RlcHMgdG8gcmVhY2ggYSAiRmlndXJlIDEiIGxldmVsIG9mIGxhYmVsZWQgY2x1c3RlcnMgbWF5IG5vdCBiZSBwcmVzZW50ZWQgaW4gZGV0YWlsLCBjYW4gYmUgdmVyeSBkYXRhc2V0IGRlcGVuZGVudCwgYW5kIG9mdGVuIGlzIG1vcmUgY2hhbGxlbmdpbmcgZm9yIGxlc3MgY2hhcmFjdGVyaXplZCB0aXNzdWVzLiAKCiMjIE9iamVjdGl2ZXMKCi0gIFVuZGVyc3RhbmQgdGhlIGNvbXBsZXhpdGllcyBvZiBjZWxsLXR5cGUgYW5ub3RhdGlvbiAgICAKLSAgVXNlIGBzY0NBVENIYCBjZWxsLXR5cGUgcHJlZGljdGlvbnMgdG8gYW5ub3RhdGUgb3VyIGNsdXN0ZXJzICAgIAoKLS0tLQoKYGBge3IsIHJlYWRfcmRzX2hpZGRlbiwgZWNobyA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRX0KaWYoIWV4aXN0cygnZ2VvX3NvJykpIHsKICBsaWJyYXJ5KFNldXJhdCkKICBsaWJyYXJ5KEJQQ2VsbHMpCiAgbGlicmFyeSh0aWR5dmVyc2UpCgogIG9wdGlvbnMoZnV0dXJlLmdsb2JhbHMubWF4U2l6ZSA9IDFlOSkKCiAgZ2VvX3NvID0gcmVhZFJEUygncmVzdWx0cy9yZGF0YS9nZW9fc29fc2N0X2ludGVncmF0ZWRfd2l0aF9tYXJrZXJzLnJkcycpCn0KCmlmKCFleGlzdHMoJ2dlb19tYXJrZXJzJykpIHsKICBsaWJyYXJ5KFNldXJhdCkKICBsaWJyYXJ5KEJQQ2VsbHMpCiAgbGlicmFyeSh0aWR5dmVyc2UpCgogIG9wdGlvbnMoZnV0dXJlLmdsb2JhbHMubWF4U2l6ZSA9IDFlOSkKCiAgZ2VvX21hcmtlcnMgPSByZWFkUkRTKCdyZXN1bHRzL3JkYXRhL2dlb19tYXJrZXJzLnJkcycpCn0KYGBgCgojIENlbGwgdHlwZSBwcmVkaWN0aW9ucwoKQXV0b21hdGVkIHRvb2xzIGhhdmUgdGhlIGFkdmFudGFnZSBvZiBiZWluZyBhYmxlIHRvIGNvbXBhcmUgYmV0d2VlbiB0aGUgZXhwcmVzc2lvbiBwYXR0ZXJucyBpbiBvdXIgZGF0YXNldCBhbmQgbGFyZ2UgbnVtYmVycyBvZiByZWZlcmVuY2UgZGF0YXNldHMgb3IgZGF0YWJhc2VzIGF0IGEgc2NhbGUgdGhhdCBpcyBub3QgZmVhc2libGUgdG8gZG8gbWFudWFsbHkuCgpBcyBkZXNjcmliZWQgW2luIG1vcmUgZGV0YWlsIGJ5IHRoZSBPdXlhbmcgTGFiXShodHRwczovL291eWFuZ2xhYi5jb20vc2luZ2xlY2VsbC9jbHVzdC5odG1sI2Fubm90YXRpbmctY2x1c3RlcnMpIGFuZCBzdW1tYXJpemVkIGluIHRoZSBmaWd1cmUgYmVsb3csIHRoZXJlIGFyZSBtYW55IGNvbXB1dGF0aW9uYWwgdG9vbHMgdGhhdCBhaW0gdG8gYXNzaWduIGNlbGwgdHlwZSBsYWJlbHMgZm9yIHNpbmdsZS1jZWxsIGRhdGEuIFRoZXNlIG1ldGhvZHMgZ2VuZXJhbGx5IGZhbGwgaW50byB0aHJlZSBjYXRlZ29yaWVzOiAKCjEuIE1hcmtlciBiYXNlZCBhcHByb2FjaGVzIHRoYXQgdXNlIGdlbmUgc2V0cyBkcmF3biBmcm9tIHRoZSBsaXRlcmF0dXJlLCBpbmNsdWRpbmcgcHJldmlvdXMgc2luZ2xlLWNlbGwgc3R1ZGllcywgCjIuIENvcnJlbGF0aW9uIGJhc2VkIGFwcHJvYWNoZXMgdGhhdCBlc3RpbWF0ZSB0aGUgc2ltaWxhcml0eSBiZXR3ZWVuIHRoZSBjZWxscyBvciBjbHVzdGVycyBpbiB0aGUgaW5wdXQgZGF0YSBhbmQgc29tZSByZWZlcmVuY2UgZGF0YQozLiBNYWNoaW5lIGxlYXJuaW5nIGFwcHJvYWNoZXMgdGhhdCBpbmNsdWRlIHRyYWluaW5nIG9uIGEgc2luZ2xlLWNlbGwgcmVmZXJlbmNlIGF0bGFzLiAKCiFbSW1hZ2U6IERpYWdyYW0gb2YgdHlwZXMgb2YgY2VsbCBhbm5vdGF0aW9uIGFwcHJvYWNoZXMgKGZyb20gT3lhbmcgbWF0ZXJpYWxzKS5dKC4vaW1hZ2VzL2N1cnJpY3VsdW0vMDctQ2VsbFR5cGVBbm5vdGF0aW9uL091eWFuZ19jbHVzdC1jZWxsdHlwZS5wbmcpICAgCgpIb3dldmVyLCBhY3Jvc3MgYW55IG9mIHRoZXNlIGFwcHJvYWNoZXMgdGhlIHF1YWxpdHkgb2YgdGhlIHJlZmVyZW5jZSBkYXRhIChhbmQgcmVsaWFiaWxpdHkgb2YgdGhlIGF1dGhvcnMgbGFiZWxzKSBhbmQgcmVsZXZhbmN5IHRvIHlvdXIgc3BlY2lmaWMgdGlzc3VlL2V4cGVyaW1lbnQgKGFuZCB0aGUgcmVzb2x1dGlvbiBvZiB5b3VyIGJpb2xvZ2ljYWwgcXVlc3Rpb24pIGlzIGNydWNpYWwuIEFkZGl0aW9uYWxseSwgaXQncyBpbXBvcnRhbnQgdG8gY29uc2lkZXIgdGhhdCByYXJlIG9yIG5vdmVsIGNlbGwgcG9wdWxhdGlvbnMgbWF5IG5vdCBiZSBwcmVzZW50IG9yIHdlbGwtY2hhcmFjdGVyaXplZCBpbiBhdmFpbGFibGUgcmVmZXJlbmNlcyBhbmQgdGhhdCBldmVuIGFmdGVyIGZpbHRlcmluZywgc29tZSBjbHVzdGVycyBtaWdodCBjb3JyZXNwb25kIHRvIHN0cmVzc2VkIG9yIGR5aW5nIGNlbGxzIGFuZCBub3QgYSBwYXJ0aWN1bGFyIGNlbGwtdHlwZSBvciBzdWJ0eXBlLiBUaGVyZWZvcmUsIGFueSBwcmVkaWN0aW9uIHNob3VsZCBiZSByZXZpZXdlZCBhbmQgY29uc2lkZXJlZCBpbiB0aGUgY29udGV4dCBib3RoIG1hcmtlciBnZW5lIGV4cHJlc3Npb24gZm9yIHRoZSBkYXRhc2V0IGFuZCBrbm93bGVkZ2Ugb2YgdGhlIGJpb2xvZ2ljYWwgc3lzdGVtIGFuZCBicm9hZGVyIGxpdGVyYXR1cmUuIAoKU29tZSB0b29scyBhbmQgcmVmZXJlbmNlcyBhcmUgYXZhaWxhYmxlIHNvbGVseSBvciBwcmltYXJpbHkgZm9yIGh1bWFuIHRpc3N1ZXMgKGFuZCBub3QgbW91c2Ugb3IgcmF0KSwgcGFydGljdWxhciBmb3IgdGlzc3VlcyBvdGhlciB0aGFuIFBCTUNzIGFuZCB0aGUgYnJhaW4uIEZvciBodW1hbiBkYXRhLCBpZiBhIHJlbGV2YW50IHJlZmVyZW5jZSBpcyBhdmFpbGFibGUgZm9yIHlvdXIgZXhwZXJpbWVudCwgd2Ugd291bGQgcmVjb21tZW5kIHRyeWluZyBbQXppbXV0aCAoY3JlYXRlZCBieSBhdXRob3JzIG9mIFNldXJhdCldKGh0dHBzOi8vYXppbXV0aC5odWJtYXBjb25zb3J0aXVtLm9yZy8pLiBbMTB4IGhhcyBhIHR1dG9yaWFsXShodHRwczovL3d3dy4xMHhnZW5vbWljcy5jb20vYW5hbHlzaXMtZ3VpZGVzL2F1dG9tYXRlZC1jZWxsLXR5cGUtYW5ub3RhdGlvbi1mcm9tLXItdG8tbG91cGUtdXNpbmctbG91cGVyKSB0aGF0IGluY2x1ZGVzIGV4YW1wbGUgb2YgdXNpbmcgQXppbXV0aCwgaW5jbHVkaW5nIGEgZmVhdHVyZSBvZiB0aGUgdG9vbCB0aGF0IGFsbG93cyBmb3IgZmlyc3QgcGFzcyBvZiBjZWxsLXR5cGUgYXNzaWdubWVudCBvZiBtb3JlIGNvbW1vbiBjZWxsLXR5cGVzIGZvbGxvd2VkIGJ5IGlkZW50aWZ5aW5nIHJhcmVyIHBvcHVsYXRpb25zIHRoYXQgbWF5IG5vdCBiZSBpZGVudGlmaWVkIGluIHRoZSBmaXJzdCBwYXNzLiAKCjxkZXRhaWxzPgogICAgPHN1bW1hcnk+KkFkZGl0aW9uYWwgYXV0b21hdGVkIGFubm90YXRpb24gcmVzb3VyY2VzKjwvc3VtbWFyeT4KICAgIEF1dG9tYXRlZCBjZWxsLXR5cGUgYW5ub3RhdGlvbiBpcyBhbiBhY3RpdmUgYXJlYSBvZiByZXNlYXJjaCBhbmQgZGV2ZWxvcG1lbnQgYW5kIG1hbnkgb3RoZXIgdG9vbHMgYW5kIHJlc291cmNlcyBhcmUgYXZhaWxhYmxlLCBpbmNsdWRpbmcgW09TQ0EncyBkZW1vbnN0cmF0aW9uIG9mIHRoZSBTaW5nbGVSIG1ldGhvZF0oaHR0cHM6Ly9iaW9jb25kdWN0b3Iub3JnL2Jvb2tzLzMuMTUvT1NDQS5iYXNpYy9jZWxsLXR5cGUtYW5ub3RhdGlvbi5odG1sKSwgYSBbVHV0b3JpYWwgYnkgQ2xhcmtlIGV0IGFsLiBmb3IgY2VsbC10eXBlIGFubm90YXRpb25zXShodHRwczovL3B1Ym1lZC5uY2JpLm5sbS5uaWguZ292LzM0MDMxNjEyLyksIGFuZCBhbiBbZW50aXJlIGNoYXB0ZXIgb2YgdGhlIFNDIGJlc3QgcHJhY3RpY2VzIGJvb2tdKGh0dHBzOi8vd3d3LnNjLWJlc3QtcHJhY3RpY2VzLm9yZy9jZWxsdWxhcl9zdHJ1Y3R1cmUvYW5ub3RhdGlvbi5odG1sI2F1dG9tYXRlZC1hbm5vdGF0aW9uKS4KPC9kZXRhaWxzPgo8YnI+CgojIFVzaW5nIHNjQ0FUQ0gKCkEgdG9vbCB3ZSBvZnRlbiB1c2UgZm9yIGJvdGggbW91c2UgYW5kIGh1bWFuIGRhdGEgY2VsbC10eXBlIHByZWRpY3Rpb25zIGlzIGNhbGxlZCBbc2NDQVRDSF0oaHR0cHM6Ly9naXRodWIuY29tL1pKVUZhbkxhYi9zY0NBVENIL3dpa2kpIHdoaWNoLCBwZXIgdGhlIGF1dGhvcidzIGRlc2NyaXB0aW9uIGluIFtTaGFvIGV0IGFsICgyMDIwKV0oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wbWMvYXJ0aWNsZXMvUE1DNzAzMTMxMi8pLCBhbm5vdGF0ZXMgY2VsbC10eXBlcyB1c2luZyBhICJ0aXNzdWUtc3BlY2lmaWMgY2VsbHVsYXIgdGF4b25vbXkgcmVmZXJlbmNlIGRhdGFiYXNlIChDZWxsTWF0Y2gpIGFuZCBbYW5dIGV2aWRlbmNlLWJhc2VkIHNjb3JpbmcgKEVTKSBwcm90b2NvbCIuIFRoZSBDZWxsTWF0Y2ggcmVmZXJlbmNlIGlzIGNvbXBpbGVkIGZyb20gQ2VsbE1hcmtlciAoW1poYW5nIGV0IGFsLiwgMjAxOWJdKGh0dHBzOi8vd3d3LmNlbGwuY29tL3NlcnZsZXQvbGlua291dD9zdWZmaXg9ZV8xXzVfMV8yXzMzXzImZGJpZD04JmRvaT0xMC4xMDE2L2ouaXNjaS4yMDIwLjEwMDg4MiZrZXk9MzAyODk1NDkmY2Y9KSksIE1DQSAoW0hhbiBldCBhbC4sIDIwMThdKGh0dHBzOi8vd3d3LmNlbGwuY29tL3NlcnZsZXQvbGlua291dD9zdWZmaXg9ZV8xXzVfMV8yXzEwXzImZGJpZD04JmRvaT0xMC4xMDE2L2ouaXNjaS4yMDIwLjEwMDg4MiZrZXk9Mjk3NzU1OTcmY2Y9KSksIENhbmNlclNFQSAoW1l1YW4gZXQgYWwuLCAyMDE5XShodHRwczovL3d3dy5jZWxsLmNvbS9zZXJ2bGV0L2xpbmtvdXQ/c3VmZml4PWVfMV81XzFfMl8yOV8yJmRiaWQ9OCZkb2k9MTAuMTAxNi9qLmlzY2kuMjAyMC4xMDA4ODIma2V5PTMwMzI5MTQyJmNmPSkpLCBhbmQgdGhlIFtDRCBNYXJrZXIgSGFuZGJvb2tdKGh0dHBzOi8vd3d3LmFiY2FtLmNvbS9wcmltYXJ5LWFudGlib2RpZXMvaHVtYW4tY2QtYW50aWdlbi1ndWlkZSkgYW5kIFBNSURzIGZvciByZWxldmFudCBsaXRlcmF0dXJlIGFyZSByZXBvcnRlZCBpbiB0aGUgcHJlZGljdGlvbiByZXN1bHRzLiAKCjwhLS0gY29uc2lkZXIgYWRkaW5nIFtzY1R5cGVdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9zY0NBVENIL3ZpZ25ldHRlcy90dXRvcmlhbC5odG1sKSBhcyBhbiBhbHRlcm5hdGl2ZSAtLT4KCiFbSW1hZ2U6IHNjQ0FUQ0ggc3VtbWFyeSBmcm9tIFNoYW8gZXQgYWwgKDIwMjApLl0oLi9pbWFnZXMvY3VycmljdWx1bS8wNy1DZWxsVHlwZUFubm90YXRpb24vc2NDQVRDSC1wYXBlci1WaXpBYnN0cmFjdC5qcGVnKSAKCkZpcnN0LCB3ZSBuZWVkIHRvIGxvYWQgdGhlIHNjQ0FUQ0ggbGlicmFyeS4gVGhlbiwgd2UnbGwgZG91YmxlIGNoZWNrIHRoYXQgd2UgYXJlIHVzaW5nIHRoZSBleHBlY3RlZCByZXNvbHV0aW9uIGNsdXN0ZXIgcmVzdWx0cyAodGhpcyBpcyBwYXJ0aWN1bGFybHkgaW1wb3J0YW50IGlmIHdlIGdlbmVyYXRlZCBtdWx0aXBsZSByZXNvbHV0aW9ucyBpbiBvdXIgY2x1c3RlcmluZyBzdGVwcyksIGJlZm9yZSBjcmVhdGluZyBhIG5ldyBvYmplY3QgZnJvbSBvdXIgYGNvdW50c2AgZGF0YSB3aXRoIGBjcmVhdGVzY0NBVENIKClgIGFuZCBhZGRpbmcgb3VyIG1hcmtlciBnZW5lcyB0byB0aGUgc2NDQVRDQ0ggb2JqZWN0LgoKVG8gaW5jcmVhc2UgdGhlIHNwZWVkIGFuZCBhY2N1cmFjeSBvZiBvdXIgcHJlZGljdGlvbnMsIHdlJ2xsIGNyZWF0ZSBxdWVyeSBvZiByZWxldmFudCB0aXNzdWVzICh3aGljaCByZXF1aXJlcyBzb21lIHByaW9yIGtub3dsZWRnZSBvZiB0aGUgZXhwZXJpbWVudCBhbmQgdXNpbmcgdGhlIFtzY0NBVENIIHdpa2ldKGh0dHBzOi8vZ2l0aHViLmNvbS9aSlVGYW5MYWIvc2NDQVRDSC93aWtpKSB0byBzZWxlY3QgdGlzc3VlcyBmcm9tIHRoZSBzcGVjaWVzKSBiZWZvcmUgd2UgcnVuIHRoZSB0b29sOgoKYGBge3IsIHNjY2F0Y2gsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQojIyMjIyBEYXkgMyAtIENlbGwgVHlwZSBBbm5vdGF0aW9uCgojIEFubm90YXRlIGNsdXN0ZXJzIHVzaW5nIHNjQ0FUQ0ggIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KbGlicmFyeShzY0NBVENIKQoKIyBjaGVjayB0aGF0IGNlbGwgaWRlbnRpdGllcyBhcmUgc2V0IHRvIGV4cGVjdGVkIHJlc29sdXRpb24gCmFsbChJZGVudHMoZ2VvX3NvKSA9PSBnZW9fc28kaW50ZWdyYXRlZC5zY3QucnBjYS5jbHVzdGVycykKCiMgY3JlYXRlIHNjQ0FUQ0ggb2JqZWN0LCB1c2luZyBjb3VudCBkYXRhCmdlb19jYXRjaCA9IGNyZWF0ZXNjQ0FUQ0goZGF0YSA9IGdlb19zb0Bhc3NheXMkU0NUQGNvdW50cywgY2x1c3RlciA9IGFzLmNoYXJhY3RlcihJZGVudHMoZ2VvX3NvKSkpCgojIGFkZCBtYXJrZXIgZ2VuZXMgdG8gdXNlIGZvciBwcmVkaWN0aW9ucwpnZW9fY2F0Y2hAbWFya2VyZ2VuZSA9IGdlb19tYXJrZXJzCgojIHNwZWNpZnkgdGlzc3Vlcy9jZWxsLXR5cGVzIGZyb20gdGhlIHNjQ0FUQ0ggcmVmZXJlbmNlCmdlb19jYXRjaEBtYXJrZXIgPSBjZWxsbWF0Y2hbY2VsbG1hdGNoJHNwZWNpZXMgPT0gJ01vdXNlJyAmIGNlbGxtYXRjaCR0aXNzdWUgJWluJSBjKCdCbG9vZCcsICdQZXJpcGhlcmFsIEJsb29kJywgJ011c2NsZScsICdTa2VsZXRhbCBtdXNjbGUnLCAnRXBpZGVybWlzJywgJ1NraW4nKSwgXQoKIyBydW4gc2NDQVRDSCB0byBnZW5lcmF0ZSBwcmVkaWN0aW9ucwpnZW9fY2F0Y2ggPSBmaW5kY2VsbHR5cGUoZ2VvX2NhdGNoKQoKIyBsb29rIGF0IHRoZSBwcmVkaWN0aW9ucwpnZW9fY2F0Y2hAY2VsbHR5cGUgJT4lIHNlbGVjdChjbHVzdGVyLCBjZWxsX3R5cGUsIGNlbGx0eXBlX3Njb3JlKQpgYGAKCldoZW4gd2UgbG9vayBhdCBvdXIgcmVzdWx0cyB3ZSBjYW4gc2VlIHRoZSBjZWxsIHR5cGUgc2NvcmUsIHdoaWNoIGdpdmVzIHVzIGFuIGlkZWEgb2YgdGhlIGNvbmZpZGVuY2Ugb2YgdGhhdCBwcmVkaWN0aW9uLiBOb3Qgc2hvd24gaGVyZSBidXQgdGhlIGZ1bGwgYGNlbGx0eXBlYCB0YWJsZSBhbHNvIGluY2x1ZGVzIG1hcmtlciBnZW5lcyBhbmQgUE1JRHMgZm9yIHJlbGV2YW50IGxpdGVyYXR1cmUgZm9yIGVhY2ggcHJlZGljdGlvbi4KCkluIG91ciBleHBlcmllbmNlLCB0aGVzZSBraW5kcyBvZiByZXN1bHRzIG9mdGVuIGhlbHAgZ3VpZGUgY2x1c3RlciBhbm5vdGF0aW9uIGJ1dCBzY29yZXMgY2FuIHZhcnkgYW5kIHRoZSBwcmVkaWN0aW9ucyBtYXkgbmVlZCB0byBiZSByZXZpc2VkIGJhc2VkIG9uIHJlc2VhcmNoZXIncyBrbm93bGVkZ2Ugb2YgdGhlIGJpb2xvZ2ljYWwgc3lzdGVtLiBBcyB0aGVzZSBjZWxsLXR5cGVzIGNvcnJlc3BvbmQgdG8gdGhlIGNlbGwtdHlwZXMgYW5kIHN1YnR5cGVzIHdlJ2QgZXhwZWN0IHRvIGJlIHByZXNlbnQgaW4gdGhlc2UgZGF0YSBhbmQgbW9zdCBvZiB0aGUgcHJlZGljdGlvbiBzY29yZXMgYXJlIHF1aXRlIGhpZ2gsIHdlIGNhbiByZWFzb25hYmx5IHVzZSB0aGVzZSByZXN1bHRzIHRvIGFubm90YXRlIG91ciBjbHVzdGVycyB3aXRoIHNvbWUgbWlub3IgYWRqdXN0bWVudHMuIAoKIyMgVXNpbmcga25vd24gY2VsbC10eXBlIG1hcmtlcnMKClRvIGNvbmZpcm0gYW5kIHJlZmluZSB0aGUgc2NDQVRDSCBwcmVkaWN0aW9ucywgd2UnbGwgc3BvdCBjaGVjayBzb21lIGtub3duIG1hcmtlcnMgZm9yIGltbXVuZSBwb3B1bGF0aW9ucy4gVGhlbiB3ZSdsbCBsb29rIGxvb2sgYXQgc29tZSBvdGhlciBrZXkgbWFya2VyIGdlbmVzIGZyb20gc29tZSBvdGhlciByZWxldmFudCByZXNvdXJjZXMgbGlrZSBbQ2hlbiBldCBhbCAoMjAyMSldKGh0dHBzOi8vd3d3Lm5hdHVyZS5jb20vYXJ0aWNsZXMvczQxNDY3LTAyMS0yNzU2My0zKSwgW0J1ZWNobGVyIGV0IGFsICgyMDIxKV0oaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9zNDE1ODYtMDIxLTAzNTQ5LTUpIFtSb21hbiAoMjAyMyldKGh0dHBzOi8vcG1jLm5jYmkubmxtLm5paC5nb3YvYXJ0aWNsZXMvUE1DMTAyOTY0MDkvI3NlYzMtYmlvbW9sZWN1bGVzLTEzLTAwOTQ1ICksICBbTGkgZXQgYWwgKDIwMjIpXShodHRwczovL2JtY2Jpb2luZm9ybWF0aWNzLmJpb21lZGNlbnRyYWwuY29tL2FydGljbGVzLzEwLjExODYvczEyODU5LTAyMi0wNDgxNy01L2ZpZ3VyZXMvMikgYW5kIFtOZXN0b3Jvd2EgZXQgYWwgKDIwMTYpXShodHRwczovL2FzaHB1YmxpY2F0aW9ucy5vcmcvYmxvb2QvYXJ0aWNsZS8xMjgvOC9lMjAvMzU3NDkvQS1zaW5nbGUtY2VsbC1yZXNvbHV0aW9uLW1hcC1vZi1tb3VzZSkgdG8gc2VlIGlmIG90aGVyIG1vZGlmaWNhdGlvbnMgc2hvdWxkIGJlIG1hZGUgdG8gdGhlIHNjQ0FUQ0ggcHJlZGljdGlvbnM6CmBgYHtyLCBtYXJrZXJfZ2VuZV9jaGVjaywgZmlnLnNob3c9J2hvbGQnfQojIFBsb3Qgb3RoZXIgbWFya2Vycy9mZWF0dXJlcyB0byBhc3Npc3Qgd2l0aCBpZGVudGlmaWNhdGlvbiAtLS0tLS0tLS0tLS0tLS0KIyBzcG90IGNoZWNrIGtub3duIGltbXVuZSBtYXJrZXJzCmltbXVuZV9tYXJrZXJzID0gbGlzdCgpCmltbXVuZV9tYXJrZXJzW1snSW5mbGFtLiBNYWNyb3BoYWdlJ11dID0gYygnQ2QxNCcsICdDeGNsMicpICMgQ2QxNCBhLSBtb25vY3l0ZS9tYWNyb3BoYWdlIGNlbGxzCmltbXVuZV9tYXJrZXJzW1snUGxhdGVsZXQnXV0gPSBjKCdQZjQnKQppbW11bmVfbWFya2Vyc1tbJ01hc3QgY2VsbHMnXV0gPSBjKCdHYXRhMicsICdLaXQnKQppbW11bmVfbWFya2Vyc1tbJ05LIGNlbGxzJ11dID0gYygnTmtnNycsICdLbHJkMScpCmltbXVuZV9tYXJrZXJzW1snQi1jZWxsJ11dID0gYyggJ0x5NmQnLCAnQ2QxOScsICdDZDc5YicsICdNczRhMScpCmltbXVuZV9tYXJrZXJzW1snVC1jZWxsJ11dID0gYyggJ0NkM2QnLCdDZDNlJywnQ2QzZycpICMgYWxzbyBUaHkxCgppbW11bmVfbWFya2Vyc19wbG90ID0gRG90UGxvdChnZW9fc28sIGZlYXR1cmVzID0gaW1tdW5lX21hcmtlcnMsIGFzc2F5ID0gJ1NDVCcpICArCiAgdGhlbWUodGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMCksIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIHZqdXN0ID0gMC41KSkKaW1tdW5lX21hcmtlcnNfcGxvdAoKIyBzYXZlIHRvIGZpbGUKZ2dzYXZlKGZpbGVuYW1lID0gJ3Jlc3VsdHMvZmlndXJlcy9pbW11bmVfbWFya2Vyc19zY3RfZG90X3Bsb3QucG5nJywgcGxvdCA9IGltbXVuZV9tYXJrZXJzX3Bsb3QsIHdpZHRoID0gMTAsIGhlaWdodCA9IDUsIHVuaXRzID0gJ2luJykKCiMgcGxvdCBzb21lIGtub3duIGNlbGwtdHlwZSBtYXJrZXJzIApvdGhlcl9tYXJrZXJzID0gbGlzdCgpCm90aGVyX21hcmtlcnNbWydQZXJpY3l0ZSddXSA9IGMoJ0FjYW4nLCdTb3g5JykKb3RoZXJfbWFya2Vyc1tbJ1NNQyddXSA9IGMoJ0FjdGEyJywgJ015aDExJykgIyBTTUMgPSBtZXNlbmNoeW1hbCBzbW9vdGgtbXVzY2xlIGNlbGwvbWVzZW5jaHltYWwgbGluZWFnZQpvdGhlcl9tYXJrZXJzW1snS2VyYXRpbm9jeXRlcyddXSA9IGMoJ1RoeTEnLCAnRGxrMScpICMgZmlicm8gcHJvZ2VuaXRvcnMgYXNvPVRoeTEKb3RoZXJfbWFya2Vyc1tbJ015b2ZpYnJvYmxhc3RzJ11dID0gYygnVG1lbTEwMCcsICdDZDM0JywgJ0x5NmMxJykgIyBoZW1hdG9wb2V0aWMgc3RlbS9hY3RpdmF0ZWQgZmlicm9ibGFzdD1DZDM0Cm90aGVyX21hcmtlcnNbWydGaWJyb2JsYXN0J11dID0gYygnRHB0JywgJ0ZuMScsICdDb2wzYTEnKSAgIyBhY3RpdmF0ZWQgZmliID0gRm4xCm90aGVyX21hcmtlcnNbWydFbmRvdGhlbGlhbCddXSA9IGMoJ1BlY2FtMScsICdDZDM4JykgIyBmcm9tIHdvdW5kIGhlYWxpbmc7IFBlY2FtMSBhbHNvIGV4cCBpbiBlbmRvdGhlbGlhbApvdGhlcl9tYXJrZXJzW1snSFNDJ11dID0gYygnTHRiJywgJ0NkNzQnKSAjIGxlc3Mgd2VsbCBkZWZpbmVkL2NvbmZsaWN0aW5nIGRlZmluaXRpb25zCm90aGVyX21hcmtlcnNbWydFcnl0aHJvaWQnXV0gPSBjKCdIYmEtYTEnKQoKb3RoZXJfbWFya2Vyc19kb3RfcGxvdCA9IERvdFBsb3QoZ2VvX3NvLCBmZWF0dXJlcyA9IG90aGVyX21hcmtlcnMsIGFzc2F5ID0gJ1NDVCcpICsKICB0aGVtZSh0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTEwKSwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgdmp1c3QgPSAwLjUpKQpvdGhlcl9tYXJrZXJzX2RvdF9wbG90CgojIHNhdmUgdG8gZmlsZQpnZ3NhdmUoZmlsZW5hbWUgPSAncmVzdWx0cy9maWd1cmVzL290aGVyX21hcmtlcnNfc2N0X2RvdF9wbG90LnBuZycsIHBsb3QgPSBvdGhlcl9tYXJrZXJzX2RvdF9wbG90LCB3aWR0aCA9IDEyLCBoZWlnaHQgPSA1LCB1bml0cyA9ICdpbicpCgpgYGAKSW4gdGhlIGZpcnN0IHBsb3QsIEItY2VsbCBhbmQgVC1jZWxsIG1hcmtlcnMgc2VlbSB0byBsaW5lIHVwIHdpdGggdGhlIHByZWRpY3Rpb25zIGFuZCBhcmUgbGltaXRlZCB0byBzaW5nbGUgY2x1c3RlcnMuIEhvd2V2ZXIsIG1hY3JvcGhhZ2UgYW5kIGRlbmRyb2N5dGUgbWFya2VycyBtYXRjaCB0byBtdWx0aXBsZSBjbHVzdGVycyBpbmNsdWRpbmcgc29tZSBhbm5vdGF0ZWQgd2l0aCBkaWZmZXJlbnQgY2VsbCB0eXBlcywgc28gd2UgY2FuIGNvbnNpZGVyIG1vZGlmeWluZyB0aG9zZSBjbHVzdGVyIGxhYmVscy4gCgoKRnJvbSB0aGUgb3RoZXIgbWFya2VyIGdlbmVzLCB0aGUgcGF0dGVybnMgYXJlIGxlc3MgY2xlYXIgc28gd2UgbWF5IHdhbnQgdG8gdGVzdCBvdGhlciBjbHVzdGVyaW5nIHBhcmFtZXRlcnMgYW5kIGRpc2N1c3MgdGhlIHJlc3VsdHMgd2l0aCBhIHJlc2VhcmNoZXIgZmFtaWxpYXIgd2l0aCB0aGUgZXhwZWN0ZWQgY2VsbCB0eXBlcy4gSG93ZXZlciwgd2UgY2FuIG5vdGljZSBzb21lIHBhdHRlcm5zIHRoYXQgd2UgY2FuIHVzZSB0byByZWZpbmUgb3VyIGNsdXN0ZXIgYW5ub3RhdGlvbnMuIAoKIyMjIyBVdGlsaXppbmcgZ2VuZXMgb2YgaW50ZXJlc3QgZnJvbSB0aGUgb3JpZ2luYWwgcGFwZXIgCgo8ZGV0YWlscz4KICAgIDxzdW1tYXJ5PipQbG90dGluZyB0aGUgZXhwcmVzc2lvbiBvZiBnZW5lcyBvZiBpbnRlcmVzdCBmcm9tIFNvcmtpbiwgSHViZXIgZXQgYWwqPC9zdW1tYXJ5PgogICAgT2Z0ZW4gd2UgaGF2ZSBwcmlvciBpbmZvcm1hdGlvbiBhYm91dCB3aGF0IGNlbGwgdHlwZXMgYXJlIGV4cGVjdGVkIGluIG91ciBzYW1wbGVzIGFuZCBrZXkgbWFya2VyIGdlbmVzIGZvciB0aG9zZSBwb3B1bGF0aW9ucy4gVGhpcyBjYW4gYmUgYW4gaW1wb3J0YW50IHBhcnQgb2YgZXZhbHVhdGluZyBvdXIgY2x1c3RlcnMsIHNpbmNlIGlmIGdlbmVzIHRoYXQgYXJlIGtub3duIG1hcmtlcnMgZm9yIGEgc3BlY2lmaWMgY2VsbCB0eXBlIGFyZSBmb3VuZCBpbiB0b28gbWFueSBvciB0b28gZmV3IGNsdXN0ZXJzIGFzIHRoYXQgY2FuIHN1Z2dlc3QgdGhhdCByZS1jbHVzdGVyaW5nIGlzIG5lZWRlZCBvciB0aGF0IHNvbWUgb2YgdGhlIGNsdXN0ZXJzIHNob3VsZCBiZSBtYW51YWxseSBjb21iaW5lZCBiZWZvcmUgYW5ub3RhdGluZy4gV2UgY2FuIGNyZWF0ZSBsaXN0cyBvZiBtYXJrZXJzIHVzZWQgaW4gZmlndXJlcyBmcm9tIHRoZSBbb3JpZ2luYWwgcGFwZXJdKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvcG1jL2FydGljbGVzL1BNQzcwMDI0NTMvKSBiZWZvcmUgdXNpbmcgdGhlIHNhbWUgYERvdFBsb3QoKWAgZnVuY3Rpb24gdG8gdmlzdWFsaXplIHRoZSBleHByZXNzaW9uIGxldmVsIGFuZCBmcmVxdWVuY3kgb2YgdGhlc2UgZ2VuZXMgaW4gb3VyIGN1cnJlbnQgY2x1c3RlcnM6CgpgYGB7ciwga25vd25fZG90X3Bsb3RzX3NjdCwgZmlnLnNob3c9J2hvbGQnfQojIFZpc3VhbGl6ZSBtYW51YWxseSBzZWxlY3RlZCBtYXJrZXIgZ2VuZXMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyBDcmVhdGUgbGlzdHMgb2YgZ2VuZXMgZnJvbSBwYXBlciAKZmlnMWdfbWFya2VycyA9IGMoJ0N4Y2wxJywgJ0N4Y2wyJywgJ0NjbDInLCAnQ2NsMycsICdDY2w0JywgJ0lsMWInLCAnSWw2YicsICdUbmYnLCAnVGdmYjEnLCAnVGdmYjInLCAnVGdmYjMnLCAnQ3hjbDUnKQpmaWcxaF9tYXJrZXJzID0gYygnQ3hjcjInLCAnQ3NmMXInLCAnQ3NmM3InLCAnVGdmYnIxJywgJ1RnZmJyMycsICdJbDFyMScsICdJbDZyYScsICdMaWZyJywgJ1RnZmJyMicpCgojIGNyZWF0ZSBEb3RQbG90cyBmb3IgZ2VuZXMgZnJvbSBwYXBlcgpmaWcxZ19zY3RfZG90X3Bsb3QgPSBEb3RQbG90KGdlb19zbywgZmVhdHVyZXMgPSBmaWcxZ19tYXJrZXJzLCBhc3NheSA9ICdTQ1QnKQpmaWcxaF9zY3RfZG90X3Bsb3QgPSBEb3RQbG90KGdlb19zbywgZmVhdHVyZXMgPSBmaWcxaF9tYXJrZXJzLCBhc3NheSA9ICdTQ1QnKQoKZmlnMWdfc2N0X2RvdF9wbG90CmZpZzFoX3NjdF9kb3RfcGxvdAoKIyBzYXZlIHBsb3RzIHRvIGZpbGUKZ2dzYXZlKGZpbGVuYW1lID0gJ3Jlc3VsdHMvZmlndXJlcy9tYXJrZXJzX2ZpZzFnX3NjdF9kb3RfcGxvdC5wbmcnLCBwbG90ID0gZmlnMWdfc2N0X2RvdF9wbG90LCB3aWR0aCA9IDgsIGhlaWdodCA9IDYsIHVuaXRzID0gJ2luJykKZ2dzYXZlKGZpbGVuYW1lID0gJ3Jlc3VsdHMvZmlndXJlcy9tYXJrZXJzX2ZpZzFoX3NjdF9kb3RfcGxvdC5wbmcnLCBwbG90ID0gZmlnMWhfc2N0X2RvdF9wbG90LCB3aWR0aCA9IDgsIGhlaWdodCA9IDYsIHVuaXRzID0gJ2luJykKYGBgCkZvciBrbm93biBtYXJrZXIgZ2VuZXMsIGl0J3MgaW1wb3J0YW50IHRvIG5vdGUgdGhhdCBzaW5jZSBzY1JOQS1zZXEgaXMgb25seSBtZWFzdXJpbmcgdHJhbnNjcmlwdGlvbmFsIHNpZ25hbHMgdGhhdCBtYXJrZXJzIGF0IHRoZSBwcm90ZWluIGxldmVsIChlLmcgdXNlZCBmb3IgYXBwcm9hY2hlcyBsaWtlIEZBQ1MpIG1heSBiZSBsZXNzIGVmZmVjdGl2ZS4gQW4gYWx0ZXJuYXRpdmUgb3IgY29tcGxlbWVudCB0byB1c2luZyBtYXJrZXIgZ2VuZXMgY291bGQgYmUgbWV0aG9kcyBsaWtlIHVzaW5nIGdlbmUgc2V0IGVucmljaG1lbnQgKEdTRUEpIFthcyBkZW1vbnN0cmF0ZWQgaW4gdGhlIE9TQ0EgYm9va10oaHR0cHM6Ly9iaW9jb25kdWN0b3Iub3JnL2Jvb2tzLzMuMTUvT1NDQS5iYXNpYy9jZWxsLXR5cGUtYW5ub3RhdGlvbi5odG1sI2NvbXB1dGluZy1nZW5lLXNldC1hY3Rpdml0aWVzKSB0byBhaWQgaW4gYW5ub3RhdGlvbnMuIEhvd2V2ZXIsIHRoZSBib29rIFsiQmVzdCBwcmFjdGljZXMgZm9yIHNpbmdsZS1jZWxsIGFuYWx5c2lzIGFjcm9zcyBtb2RhbGl0aWVzIiBieSBIZXVtb3MsIFNjaGFhciwgTGFuY2UsIGV0IGFsLiBdKGh0dHBzOi8vd3d3LnNjLWJlc3QtcHJhY3RpY2VzLm9yZy9jZWxsdWxhcl9zdHJ1Y3R1cmUvYW5ub3RhdGlvbi5odG1sKSBwb2ludHMgb3V0IHRoYXQgIml0IGlzIG9mdGVuIHVzZWZ1bCB0byB3b3JrIHRvZ2V0aGVyIHdpdGggZXhwZXJ0cyAuLi4gW2xpa2UgYV0gYmlvbG9naXN0IHdobyBoYXMgbW9yZSBleHRlbnNpdmUga25vd2xlZGdlIG9mIHRoZSB0aXNzdWUsIHRoZSBiaW9sb2d5LCB0aGUgZXhwZWN0ZWQgY2VsbCB0eXBlcyBhbmQgbWFya2VycyBldGMuIi4gSW4gb3VyIGV4cGVyaWVuY2UsIHdlIGZpbmQgdGhhdCBleHBlcmllbmNlIGFuZCBrbm93bGVkZ2Ugb2YgdGhlIHJlc2VhcmNoZXJzIHdlIHdvcmsgd2l0aCBpcyBpbnZhbHVhYmxlLiAKCjwvZGV0YWlscz4KPGJyPgoKPGRldGFpbHM+CiAgICA8c3VtbWFyeT4qVXNpbmcgcmF3IFJOQSB2YWx1ZXMgZm9yIGdlbmVzIG9mIGludGVyZXN0IGZyb20gU29ya2luLCBIdWJlciBldCBhbCo8L3N1bW1hcnk+CiAgICBXZSBjYW4gYWxzbyBnZW5lcmF0ZSB0aGUgc2FtZSBwbG90cywgYnV0IHVzaW5nIHRoZSB1bmludGVncmF0ZWQgZGF0YSBieSBzcGVjaWZ5aW5nIHRoZSBgUk5BYCBhc3NheToKCmBgYHtyLCBrbm93bl9kb3RfcGxvdF9ybmEsIGV2YWw9RkFMU0V9CiMgVmlzdWFsaXplIG1hbnVhbGx5IHNlbGVjdGVkIG1hcmtlciBnZW5lcyAoZnJvbSB1bmludGVncmF0ZWQgZGF0YSkgLS0tLS0tCnJuYV9kb3RfcGxvdCA9IERvdFBsb3QoZ2VvX3NvLCBmZWF0dXJlcyA9IGZpZzFnX21hcmtlcnMsIGFzc2F5ID0gJ1JOQScpCmZpZzFoX3JuYV9kb3RfcGxvdCA9IERvdFBsb3QoZ2VvX3NvLCBmZWF0dXJlcyA9IGZpZzFoX21hcmtlcnMsIGFzc2F5ID0gJ1JOQScpCgpnZ3NhdmUoZmlsZW5hbWUgPSAncmVzdWx0cy9maWd1cmVzL21hcmtlcnNfZmlnMWdfcm5hX2RvdF9wbG90LnBuZycsIHBsb3QgPSBmaWcxZ19ybmFfZG90X3Bsb3QsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNiwgdW5pdHMgPSAnaW4nKQpnZ3NhdmUoZmlsZW5hbWUgPSAncmVzdWx0cy9maWd1cmVzL21hcmtlcnNfZmlnMWhfcm5hX2RvdF9wbG90LnBuZycsIHBsb3QgPSBmaWcxaF9ybmFfZG90X3Bsb3QsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNiwgdW5pdHMgPSAnaW4nKQpgYGAKPC9kZXRhaWxzPgo8YnI+CgoKIyBBbm5vdGF0ZSBjbHVzdGVycwoKTmV4dCwgd2UnbGwgbW9kaWZ5IHRoZSBjZWxsIHR5cGUgcHJlZGljdGlvbnMgYW5kIGFkZCB0aGUgbGFiZWxzIHRvIG91ciBTZXVyYXQgb2JqZWN0IHRvIHJlcGxhY2Ugb3VyIGNsdXN0ZXJzJyBudW1lcmljYWwgaWRlbnRpdGllcy4gTm90ZTogd2Ugd2lsbCBjcmVhdGUgYSBuZXcgbWV0YWRhdGEgb2JqZWN0IHdoZXJlIHdlIGpvaW4gY2VsbCB0eXBlcy4gSG93ZXZlciwgdGhpcyB3aWxsIGRlc3Ryb3kgdGhlIHJvdyBuYW1lcyAtIHdoaWNoIHdpbGwgY2F1c2UgYSBwcm9ibGVtIGluIFNldXJhdCAtIHNvIHdlIGhhdmUgdG8gYWRkIHRoZW0gYmFjay4gPCEtLS0gbW9kaWZ5IHRvIGhhdmUgYSBoaWRkZW4gYmxvY2sgdGhhdCBydW5zIGFmdGVyIHRvIGtlZXAgdGhpcyBsYXJnZSBibG9jayBpbnRhY3QgLS0+CgpgYGB7ciwgYW5ub3RhdGVfY2x1c3RlcnN9CiMgQW5ub3RhdGUgY2x1c3RlcnMgdXNpbmcgbW9kaWZpZWQgcHJlZGljdGlvbnMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIEZpcnN0IC0gRXh0cmFjdCB0aGUgY2VsbCB0eXBlcyBvbmx5IGZyb20gdGhlIHByZWRpY3Rpb25zCmNlbGx0eXBlX2Fubm9zID0gZ2VvX2NhdGNoQGNlbGx0eXBlICU+JSBzZWxlY3QoY2x1c3RlciwgY2VsbF90eXBlKSAlPiUgCiAgbXV0YXRlKGNsdXN0ZXIgPSBmYWN0b3IoY2x1c3RlciwgbGV2ZWxzID0gYygwOjE5KSkpICU+JSBhcnJhbmdlKGNsdXN0ZXIpCmNlbGx0eXBlX2Fubm9zCgojIEN1c3RvbWl6ZSBhbm5vdGF0aW9ucywgcmVtZW1iZXJpbmcgdGhhdCBjbHVzdGVyIDAgPSByb3cgMSBpbiB0YWJsZQpjZWxsdHlwZV9hbm5vcyRjZWxsX3R5cGVbYygzLDE1KV0gPC0gIkluZmxhbW1hdG9yeSBtYWNyb3BoYWdlIiAjIHJlc29sdmVzIGNsdXN0ZXIgMiBhbmQgMTQKY2VsbHR5cGVfYW5ub3MkY2VsbF90eXBlW2MoMTEpXSA8LSAiTWFjcm9waGFnZSIKCmNlbGx0eXBlX2Fubm9zJGNlbGxfdHlwZVtjKDIpXSA8LSAiRmlicm9ibGFzdCIgIyByZXZpc2UgY2x1c3RlcnMgMSw2IGJhc2VkIG9uIG1hcmtlcnMKY2VsbHR5cGVfYW5ub3MkY2VsbF90eXBlW2MoNildIDwtICJNeW9maWJyb2JsYXN0IgpjZWxsdHlwZV9hbm5vcyRjZWxsX3R5cGVbYyg4LDkpXSA8LSAiRW5kb3RoZWxpYWwiICMgcmV2aXNlIGNsdXN0ZXIgNyw4OyBhbHNvIGhhdmUgd2Vha2VyIG1hc3QgY2VsbCBzaWduYWwKY2VsbHR5cGVfYW5ub3MkY2VsbF90eXBlW2MoNiwxMyldIDwtICJIZW1hdG9wb2lldGljIHN0ZW0gY2VsbCIgIyBiYXNlZCBvbiBtYXJrZXJzIGJ1dCBjb3VsZCBmdXJ0aGVyIHJldmlzZQpjZWxsdHlwZV9hbm5vcyRjZWxsX3R5cGVbYygxMCwxOSldIDwtICJNZXNlbmNoeW1hbCBzdGVtL3N0cm9tYWwgY2VsbCIgIyBiYXNlZCBvbiBBY3RhMiBzaWduYWwKY2VsbHR5cGVfYW5ub3MkY2VsbF90eXBlW2MoMTYpXSA8LSAiRXJ5dGhyb2lkIiAjIGNsdXN0ZXIgMTUsIGxlc3MgY29uZmlkZW50IGJ1dCBub3QgbmVhciBvdGhlciBkZW5kcml0aWMgY2VsbHMKY2VsbHR5cGVfYW5ub3MkY2VsbF90eXBlW2MoMjAsIDE3KV0gPC0gIlVua25vd24iICMgc2luY2Ugc3VjaCBzbWFsbCBwb3B1bGF0aW9ucywgcmVzZXQgY2x1c3RlciAxNiAmIDE5IGFzIHVua25vd24gZm9yIG5vdwoKCiMgTWVyZ2UgY2VsbCB0eXBlcyBpbiBidXQgYXMgYSBuZXcgdGFibGUgdG8gc2xpZGUgaW50byBAbWV0YS5kYXRhCm5ld19tZXRhZGF0YSA9IGdlb19zb0BtZXRhLmRhdGEgJT4lIGxlZnRfam9pbihjZWxsdHlwZV9hbm5vcywgYnkgPSBjKCdpbnRlZ3JhdGVkLnNjdC5ycGNhLmNsdXN0ZXJzJyA9ICdjbHVzdGVyJykpCnJvd25hbWVzKG5ld19tZXRhZGF0YSkgPSByb3duYW1lcyhnZW9fc29AbWV0YS5kYXRhKSAjICBXZSBhcmUgaW1wbGljaXRseSByZWx5aW5nIG9uIHRoZSBzYW1lIHJvdyBvcmRlciEKCiMgUmVwbGFjZSB0aGUgbWV0YS5kYXRhCmdlb19zb0BtZXRhLmRhdGEgPSBuZXdfbWV0YWRhdGEgCgpoZWFkKGdlb19zb0BtZXRhLmRhdGEpCmBgYAoKKipDaGVja3BvaW50KiogOiBIYXMgdGhlIG1ldGFkYXRhIGZvciB5b3VyIGBnZW9fc29gIG9iamVjdCBiZWVuIHVwZGF0ZWQ/CgpXZSBoYXZlIG5vdyBhZGRlZCBhICJjZWxsX3R5cGUiIGNvbHVtbiB0byB0aGUgYG1ldGEuZGF0YWAgdGFibGU6CgohW0ltYWdlOiBTY2hlbWF0aWMgYWZ0ZXIgYWRkaW5nIGNlbGxfdHlwZSBjb2x1bW4uXShpbWFnZXMvc2V1cmF0X3NjaGVtYXRpYy9TbGlkZTEyLnBuZykKCiMjIFZpc3VhbGlzZSBhbm5vdGF0ZWQgY2x1c3RlcnMKCkxhc3RseSwgd2UgY2FuIGdlbmVyYXRlIGEgcmV2aXNlZCBVTUFQIHBsb3Qgd2l0aCBvdXIgZGVzY3JpcHRpdmUgY2x1c3RlciBsYWJlbHMgYnkgdXNpbmcgb3VyIHVwZGF0ZWQgU2V1cmF0IG9iamVjdCBhbmQgcHJvdmlkaW5nIHRoZSBuZXcgYGNlbGxfdHlwZWAgbGFiZWwgZm9yIHRoZSBgZ3JvdXAuYnlgIGFyZ3VtZW50OgoKYGBge3IsIGNhdGNoX3VtYXBfcGxvdCwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA4LCBmaWcuc2hvdz0naG9sZCd9CiMgTWFrZSBhIGxhYmVsZWQgVU1BUCBwbG90IG9mIGNsdXN0ZXJzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpjYXRjaF91bWFwX3Bsb3QgPSBEaW1QbG90KGdlb19zbywgZ3JvdXAuYnkgPSAnY2VsbF90eXBlJywgbGFiZWwgPSBUUlVFLCByZWR1Y3Rpb24gPSAndW1hcC5pbnRlZ3JhdGVkLnNjdC5ycGNhJykKY2F0Y2hfdW1hcF9wbG90CgpnZ3NhdmUoZmlsZW5hbWUgPSAncmVzdWx0cy9maWd1cmVzL3VtYXBfaW50ZWdyYXRlZF9jYXRjaC5wbmcnLCBwbG90ID0gY2F0Y2hfdW1hcF9wbG90LCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA4LCB1bml0cyA9ICdpbicpCgpjYXRjaF91bWFwX2NvbmRpdGlvbl9wbG90ID0gRGltUGxvdChnZW9fc28sIGdyb3VwLmJ5ID0gJ2NlbGxfdHlwZScsIHNwbGl0LmJ5ID0gJ2RheScsIGxhYmVsID0gVFJVRSwgcmVkdWN0aW9uID0gJ3VtYXAuaW50ZWdyYXRlZC5zY3QucnBjYScpCmNhdGNoX3VtYXBfY29uZGl0aW9uX3Bsb3QKCmdnc2F2ZShmaWxlbmFtZSA9ICdyZXN1bHRzL2ZpZ3VyZXMvdW1hcF9pbnRlZ3JhdGVkX2NhdGNoX2J5Q29uZGl0aW9uLnBuZycsIHBsb3QgPSBjYXRjaF91bWFwX3Bsb3QsIHdpZHRoID0gMTAsIGhlaWdodCA9IDgsIHVuaXRzID0gJ2luJykKYGBgCgo8IS0tIHRvIGFkZCAtIG51bWJlciBvZiBjZWxscyBwZXIgY2x1c3RlciBhbmQgY29uZGl0aW9uL3JlcGxpY2F0ZSBhZnRlciBhbm5vdGF0aW9uIC0tLT4KCiMgU2F2ZSBvdXIgcHJvZ3Jlc3MKCldlJ2xsIHNhdmUgdGhlIHNjQ0FUQ0ggb2JqZWN0LiBUaGUgU2V1cmF0IG9iamVjdCBoYXMgbm90IGJlZW4gY2hhbmdlZCBpbiB0aGlzIG1vZHVsZS4KCmBgYHtyLCBzYXZlX3Jkc19oaWRkZW4sIGVjaG8gPSBGQUxTRX0KaWYoIWZpbGUuZXhpc3RzKCdyZXN1bHRzL3JkYXRhL2dlb19zb19zY3RfaW50ZWdyYXRlZF93aXRoX2NhdGNoLnJkcycpKSB7CiAgc2F2ZVJEUyhnZW9fc28sIGZpbGUgPSAncmVzdWx0cy9yZGF0YS9nZW9fc29fc2N0X2ludGVncmF0ZWRfd2l0aF9jYXRjaC5yZHMnKQp9CgppZighZmlsZS5leGlzdHMoJ3Jlc3VsdHMvcmRhdGEvZ2VvX2NhdGNoLnJkcycpKSB7CiAgc2F2ZVJEUyhnZW9fY2F0Y2gsIGZpbGUgPSAncmVzdWx0cy9yZGF0YS9nZW9fY2F0Y2gucmRzJykKfQpgYGAKCmBgYHtyLCBzYXZlX3JkcywgZXZhbD1GQUxTRX0KIyBTYXZlIFNldXJhdCBvYmplY3QgYW5kIGFubm90YXRpb25zIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCnNhdmVSRFMoZ2VvX3NvLCBmaWxlID0gJ3Jlc3VsdHMvcmRhdGEvZ2VvX3NvX3NjdF9pbnRlZ3JhdGVkX3dpdGhfY2F0Y2gucmRzJykKc2F2ZVJEUyhnZW9fY2F0Y2gsIGZpbGUgPSAncmVzdWx0cy9yZGF0YS9nZW9fY2F0Y2gucmRzJykKYGBgCgojIFN1bW1hcnkKCk5vdyB0aGF0IHdlIGhhdmUgZ2VuZXJhdGVkIHJlYXNvbmFibGUgYW5ub3RhdGlvbnMgZm9yIG91ciBjbHVzdGVycywgd2UgY2FuIHByb2NlZWQgd2l0aCB0aGUgc3RlcCBvZiBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiB3aGljaCBpcyBlc3NlbnRpYWwgdG8gYWRkcmVzc2luZyBvdXIgYmlvbG9naWNhbCBxdWVzdGlvbiBmb3IgdGhpcyBleHBlcmltZW50LgoKTmV4dCBzdGVwczogRGlmZmVyZW50aWFsIEV4cHJlc3Npb24KCi0tLS0KClRoZXNlIG1hdGVyaWFscyBoYXZlIGJlZW4gYWRhcHRlZCBhbmQgZXh0ZW5kZWQgZnJvbSBtYXRlcmlhbHMgbGlzdGVkIGFib3ZlLiBUaGVzZSBhcmUgb3BlbiBhY2Nlc3MgbWF0ZXJpYWxzIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgW0NyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24gbGljZW5zZSAoQ0MgQlkgNC4wKV0oaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnkvNC4wLyksIHdoaWNoIHBlcm1pdHMgdW5yZXN0cmljdGVkIHVzZSwgZGlzdHJpYnV0aW9uLCBhbmQgcmVwcm9kdWN0aW9uIGluIGFueSBtZWRpdW0sIHByb3ZpZGVkIHRoZSBvcmlnaW5hbCBhdXRob3IgYW5kIHNvdXJjZSBhcmUgY3JlZGl0ZWQuCgo8YnIvPgo8YnIvPgo8aHIvPgp8IFtQcmV2aW91cyBsZXNzb25dKDA2LU1hcmtlclZpc3VhbGl6YXRpb24uaHRtbCkgfCBbVG9wIG9mIHRoaXMgbGVzc29uXSgjdG9wKSB8IFtOZXh0IGxlc3Nvbl0oMDgtRGlmZmVyZW50aWFsRXhwcmVzc2lvbi5odG1sKSB8CnwgOi0tLSB8IDotLS0tOiB8IC0tLTogfAo=