Workflow Overview


wayfinder

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:

  1. Marker based approaches that use gene sets drawn from the literature, including previous single-cell studies,
  2. Correlation based approaches that estimate the similarity between the cells or clusters in the input data and some reference data
  3. Machine learning approaches that include training on a single-cell reference atlas.
Image: Diagram of types of cell annotation approaches (from Oyang materials).
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).
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.
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.




Previous lesson Top of this lesson Next lesson
LS0tCnRpdGxlOiAiQ2VsbCBUeXBlIEFubm90YXRpb24iCmF1dGhvcjogIlVNIEJpb2luZm9ybWF0aWNzIENvcmUiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogICAgICAgIGh0bWxfZG9jdW1lbnQ6CiAgICAgICAgICAgIGluY2x1ZGVzOgogICAgICAgICAgICAgICAgaW5faGVhZGVyOiBoZWFkZXIuaHRtbAogICAgICAgICAgICB0aGVtZTogcGFwZXIKICAgICAgICAgICAgdG9jOiB0cnVlCiAgICAgICAgICAgIHRvY19kZXB0aDogNAogICAgICAgICAgICB0b2NfZmxvYXQ6IHRydWUKICAgICAgICAgICAgbnVtYmVyX3NlY3Rpb25zOiBmYWxzZQogICAgICAgICAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgICAgICAgICBtYXJrZG93bjogR0ZNCiAgICAgICAgICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKLS0tCgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgpib2R5LCB0ZCB7CiAgIGZvbnQtc2l6ZTogMThweDsKfQpjb2RlLnJ7CiAgZm9udC1zaXplOiAxMnB4Owp9CnByZSB7CiAgZm9udC1zaXplOiAxMnB4Cn0KCnRhYmxlLmZpZywgdGguZmlnLCB0ZC5maWcgewogIGJvcmRlcjogMXB4IHNvbGlkIGJsYWNrOwogIGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7CiAgcGFkZGluZzogMTVweDsKfQo8L3N0eWxlPgoKYGBge3Iga2xpcHB5LCBlY2hvPUZBTFNFLCBpbmNsdWRlPVRSVUV9CmtsaXBweTo6a2xpcHB5KGxhbmcgPSBjKCJyIiwgIm1hcmtkb3duIiwgImJhc2giKSwgcG9zaXRpb24gPSBjKCJ0b3AiLCAicmlnaHQiKSkKYGBgCgpgYGB7ciwgaW5jbHVkZSA9IEZBTFNFfQpzb3VyY2UoIi4uL2Jpbi9jaHVuay1vcHRpb25zLlIiKQprbml0cl9maWdfcGF0aCgiMDctQ2VsbFR5cGVBbm5vdGF0aW9uLzA3LSIpCmBgYAoKIyBXb3JrZmxvdyBPdmVydmlldyB7LnVubGlzdGVkIC51bm51bWJlcmVkfQoKPGJyLz4KPGltZyBzcmM9ImltYWdlcy93YXlmaW5kZXIvd2F5ZmluZGVyLnBuZyIgYWx0PSJ3YXlmaW5kZXIiIHN0eWxlPSJoZWlnaHQ6IDQwMHB4OyIvPgo8YnIvPgo8YnIvPgoKIyBJbnRyb2R1Y3Rpb24KCkEgZnJlcXVlbnQgYm90dGxlbmVjayBpbiB0aGUgc2luZ2xlLWNlbGwgUk5BLXNlcSBhbmFseXNpcyB3b3JrZmxvdyBpcyBhbm5vdGF0aW5nIG91ciBjbHVzdGVyaW5nIHJlc3VsdHMsIGFzIGl0IHJlcXVpcmVzIGJyaWRnaW5nIHRoZSBnYXAgYmV0d2VlbiB0aGUgZGF0YSBhbmQgcHJpb3Iga25vd2xlZGdlIChbc291cmNlXShodHRwczovL2Jpb2NvbmR1Y3Rvci5vcmcvYm9va3MvMy4xNS9PU0NBLmJhc2ljL2NlbGwtdHlwZS1hbm5vdGF0aW9uLmh0bWwpKS4gV2hpbGUgZ2VuZXJhdGluZyBtYXJrZXJzIGZvciBlYWNoIGNsdXN0ZXIgYW5kIGV2YWx1YXRpbmcgdGhlIGV4cHJlc3Npb24gb2Yga25vd24gbWFya2VyIGdlbmVzIGlzIGltcG9ydGFudCwgaXQgbWF5IG9yIG1heSBub3QgYmUgc3VmZmljaWVudCB0byBhc3NpZ24gY2VsbC10eXBlIG9yIHN1Yi10eXBlIGxhYmVscy4gCgo8dGFibGUgY2xhc3M9J2ZpZyc+Cjx0ciBjbGFzcz0nZmlnJz48dGQgY2xhc3M9J2ZpZyc+IVtdKGltYWdlcy9ncmFwaGljYWxfYWJzdHJhY3RzL2dyYXBoaWNhbF9hYnN0cmFjdF9hbm5vdGF0aW9uLnBuZyk8L3RkPjwvdHI+Cjx0ciBjbGFzcz0nZmlnJz48dGQgY2xhc3M9J2ZpZyc+Rm9yIGVhY2ggY2VsbC10eXBlIChBKSwgdGhlIG1hcmtlciBnZW5lcyB3ZSBkZXJpdmVkIGluIHRoZSBwcmlvciBzdGVwIChCKSBhcmUgY29tcGFyZWQgd2l0aCBrbm93biBtYXJrZXIgZ2VuZXMgZm9yIGRpZmZlcmVudCBjZWxsIHR5cGVzIChDKS4gQ29uY29yZGFuY2UgYmV0d2VlbiBkZXJpdmVkIG1hcmtlciBnZW5lcyBhbmQga25vd24gY2VsbCBtYXJrZXJzIHByb2R1Y2VzIGEgc3VnZ2VzdGVkIGFubm90YXRpb24gZm9yIHRoYXQgY2VsbCB0eXBlLgo8L3RkPjwvdHI+CjwvdGFibGU+CgpJbiB0aGlzIHNlY3Rpb24sIG91ciBnb2FsIGlzIHRvIHVzZSBhbiBhdXRvbWF0ZWQgYW5ub3RhdGlvbiB0b29sIHRvIGdlbmVyYXRlIGNlbGwgdHlwZSBwcmVkaWN0aW9ucyBmb3Igb3VyIGNsdXN0ZXJzLiAKCkxpa2UgdGhlIHByZXZpb3VzIHNlY3Rpb25zLCB0aGUgcHJvY2VzcyB0byBhc3NpZ24gY2VsbC10eXBlcyB0byBjbHVzdGVycyBjYW4gYmUgdmVyeSBpdGVyYXRpdmUuIEluIGFkZGl0aW9uLCB0aGUgc3RlcHMgdG8gcmVhY2ggYSAiRmlndXJlIDEiIGxldmVsIG9mIGxhYmVsZWQgY2x1c3RlcnMgbWF5IG5vdCBiZSBwcmVzZW50ZWQgaW4gZGV0YWlsLCBjYW4gYmUgdmVyeSBkYXRhc2V0IGRlcGVuZGVudCwgYW5kIG9mdGVuIGlzIG1vcmUgY2hhbGxlbmdpbmcgZm9yIGxlc3MgY2hhcmFjdGVyaXplZCB0aXNzdWVzLiAKCiMjIE9iamVjdGl2ZXMKCi0gIFVuZGVyc3RhbmQgdGhlIGNvbXBsZXhpdGllcyBvZiBjZWxsLXR5cGUgYW5ub3RhdGlvbiAgICAKLSAgVXNlIGBzY0NBVENIYCBjZWxsLXR5cGUgcHJlZGljdGlvbnMgdG8gYW5ub3RhdGUgb3VyIGNsdXN0ZXJzICAgIAoKLS0tLQoKYGBge3IsIHJlYWRfcmRzX2hpZGRlbiwgZWNobyA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRX0KaWYoIWV4aXN0cygnZ2VvX3NvJykpIHsKICBsaWJyYXJ5KFNldXJhdCkKICBsaWJyYXJ5KEJQQ2VsbHMpCiAgbGlicmFyeSh0aWR5dmVyc2UpCgogIG9wdGlvbnMoZnV0dXJlLmdsb2JhbHMubWF4U2l6ZSA9IDFlOSkKCiAgZ2VvX3NvID0gcmVhZFJEUygncmVzdWx0cy9yZGF0YS9nZW9fc29fc2N0X2ludGVncmF0ZWRfd2l0aF9tYXJrZXJzLnJkcycpCn0KCmlmKCFleGlzdHMoJ2dlb19tYXJrZXJzJykpIHsKICBsaWJyYXJ5KFNldXJhdCkKICBsaWJyYXJ5KEJQQ2VsbHMpCiAgbGlicmFyeSh0aWR5dmVyc2UpCgogIG9wdGlvbnMoZnV0dXJlLmdsb2JhbHMubWF4U2l6ZSA9IDFlOSkKCiAgZ2VvX21hcmtlcnMgPSByZWFkUkRTKCdyZXN1bHRzL3JkYXRhL2dlb19tYXJrZXJzLnJkcycpCn0KYGBgCgojIENlbGwgdHlwZSBwcmVkaWN0aW9ucwoKQXV0b21hdGVkIHRvb2xzIGhhdmUgdGhlIGFkdmFudGFnZSBvZiBiZWluZyBhYmxlIHRvIGNvbXBhcmUgYmV0d2VlbiB0aGUgZXhwcmVzc2lvbiBwYXR0ZXJucyBpbiBvdXIgZGF0YXNldCBhbmQgbGFyZ2UgbnVtYmVycyBvZiByZWZlcmVuY2UgZGF0YXNldHMgb3IgZGF0YWJhc2VzIGF0IGEgc2NhbGUgdGhhdCBpcyBub3QgZmVhc2libGUgdG8gZG8gbWFudWFsbHkuCgpBcyBkZXNjcmliZWQgW2luIG1vcmUgZGV0YWlsIGJ5IHRoZSBPdXlhbmcgTGFiXShodHRwczovL291eWFuZ2xhYi5jb20vc2luZ2xlY2VsbC9jbHVzdC5odG1sI2Fubm90YXRpbmctY2x1c3RlcnMpIGFuZCBzdW1tYXJpemVkIGluIHRoZSBmaWd1cmUgYmVsb3csIHRoZXJlIGFyZSBtYW55IGNvbXB1dGF0aW9uYWwgdG9vbHMgdGhhdCBhaW0gdG8gYXNzaWduIGNlbGwgdHlwZSBsYWJlbHMgZm9yIHNpbmdsZS1jZWxsIGRhdGEuIFRoZXNlIG1ldGhvZHMgZ2VuZXJhbGx5IGZhbGwgaW50byB0aHJlZSBjYXRlZ29yaWVzOiAKCjEuIE1hcmtlciBiYXNlZCBhcHByb2FjaGVzIHRoYXQgdXNlIGdlbmUgc2V0cyBkcmF3biBmcm9tIHRoZSBsaXRlcmF0dXJlLCBpbmNsdWRpbmcgcHJldmlvdXMgc2luZ2xlLWNlbGwgc3R1ZGllcywgCjIuIENvcnJlbGF0aW9uIGJhc2VkIGFwcHJvYWNoZXMgdGhhdCBlc3RpbWF0ZSB0aGUgc2ltaWxhcml0eSBiZXR3ZWVuIHRoZSBjZWxscyBvciBjbHVzdGVycyBpbiB0aGUgaW5wdXQgZGF0YSBhbmQgc29tZSByZWZlcmVuY2UgZGF0YQozLiBNYWNoaW5lIGxlYXJuaW5nIGFwcHJvYWNoZXMgdGhhdCBpbmNsdWRlIHRyYWluaW5nIG9uIGEgc2luZ2xlLWNlbGwgcmVmZXJlbmNlIGF0bGFzLiAKCiFbSW1hZ2U6IERpYWdyYW0gb2YgdHlwZXMgb2YgY2VsbCBhbm5vdGF0aW9uIGFwcHJvYWNoZXMgKGZyb20gT3lhbmcgbWF0ZXJpYWxzKS5dKC4vaW1hZ2VzL2N1cnJpY3VsdW0vMDctQ2VsbFR5cGVBbm5vdGF0aW9uL091eWFuZ19jbHVzdC1jZWxsdHlwZS5wbmcpICAgCgpIb3dldmVyLCBhY3Jvc3MgYW55IG9mIHRoZXNlIGFwcHJvYWNoZXMgdGhlIHF1YWxpdHkgb2YgdGhlIHJlZmVyZW5jZSBkYXRhIChhbmQgcmVsaWFiaWxpdHkgb2YgdGhlIGF1dGhvcnMgbGFiZWxzKSBhbmQgcmVsZXZhbmN5IHRvIHlvdXIgc3BlY2lmaWMgdGlzc3VlL2V4cGVyaW1lbnQgKGFuZCB0aGUgcmVzb2x1dGlvbiBvZiB5b3VyIGJpb2xvZ2ljYWwgcXVlc3Rpb24pIGlzIGNydWNpYWwuIEFkZGl0aW9uYWxseSwgaXQncyBpbXBvcnRhbnQgdG8gY29uc2lkZXIgdGhhdCByYXJlIG9yIG5vdmVsIGNlbGwgcG9wdWxhdGlvbnMgbWF5IG5vdCBiZSBwcmVzZW50IG9yIHdlbGwtY2hhcmFjdGVyaXplZCBpbiBhdmFpbGFibGUgcmVmZXJlbmNlcyBhbmQgdGhhdCBldmVuIGFmdGVyIGZpbHRlcmluZywgc29tZSBjbHVzdGVycyBtaWdodCBjb3JyZXNwb25kIHRvIHN0cmVzc2VkIG9yIGR5aW5nIGNlbGxzIGFuZCBub3QgYSBwYXJ0aWN1bGFyIGNlbGwtdHlwZSBvciBzdWJ0eXBlLiBUaGVyZWZvcmUsIGFueSBwcmVkaWN0aW9uIHNob3VsZCBiZSByZXZpZXdlZCBhbmQgY29uc2lkZXJlZCBpbiB0aGUgY29udGV4dCBib3RoIG1hcmtlciBnZW5lIGV4cHJlc3Npb24gZm9yIHRoZSBkYXRhc2V0IGFuZCBrbm93bGVkZ2Ugb2YgdGhlIGJpb2xvZ2ljYWwgc3lzdGVtIGFuZCBicm9hZGVyIGxpdGVyYXR1cmUuIAoKU29tZSB0b29scyBhbmQgcmVmZXJlbmNlcyBhcmUgYXZhaWxhYmxlIHNvbGVseSBvciBwcmltYXJpbHkgZm9yIGh1bWFuIHRpc3N1ZXMgKGFuZCBub3QgbW91c2Ugb3IgcmF0KSwgcGFydGljdWxhciBmb3IgdGlzc3VlcyBvdGhlciB0aGFuIFBCTUNzIGFuZCB0aGUgYnJhaW4uIEZvciBodW1hbiBkYXRhLCBpZiBhIHJlbGV2YW50IHJlZmVyZW5jZSBpcyBhdmFpbGFibGUgZm9yIHlvdXIgZXhwZXJpbWVudCwgd2Ugd291bGQgcmVjb21tZW5kIHRyeWluZyBbQXppbXV0aCAoY3JlYXRlZCBieSBhdXRob3JzIG9mIFNldXJhdCldKGh0dHBzOi8vYXppbXV0aC5odWJtYXBjb25zb3J0aXVtLm9yZy8pLiBbMTB4IGhhcyBhIHR1dG9yaWFsXShodHRwczovL3d3dy4xMHhnZW5vbWljcy5jb20vYW5hbHlzaXMtZ3VpZGVzL2F1dG9tYXRlZC1jZWxsLXR5cGUtYW5ub3RhdGlvbi1mcm9tLXItdG8tbG91cGUtdXNpbmctbG91cGVyKSB0aGF0IGluY2x1ZGVzIGV4YW1wbGUgb2YgdXNpbmcgQXppbXV0aCwgaW5jbHVkaW5nIGEgZmVhdHVyZSBvZiB0aGUgdG9vbCB0aGF0IGFsbG93cyBmb3IgZmlyc3QgcGFzcyBvZiBjZWxsLXR5cGUgYXNzaWdubWVudCBvZiBtb3JlIGNvbW1vbiBjZWxsLXR5cGVzIGZvbGxvd2VkIGJ5IGlkZW50aWZ5aW5nIHJhcmVyIHBvcHVsYXRpb25zIHRoYXQgbWF5IG5vdCBiZSBpZGVudGlmaWVkIGluIHRoZSBmaXJzdCBwYXNzLiAKCjxkZXRhaWxzPgogICAgPHN1bW1hcnk+KkFkZGl0aW9uYWwgYXV0b21hdGVkIGFubm90YXRpb24gcmVzb3VyY2VzKjwvc3VtbWFyeT4KICAgIEF1dG9tYXRlZCBjZWxsLXR5cGUgYW5ub3RhdGlvbiBpcyBhbiBhY3RpdmUgYXJlYSBvZiByZXNlYXJjaCBhbmQgZGV2ZWxvcG1lbnQgYW5kIG1hbnkgb3RoZXIgdG9vbHMgYW5kIHJlc291cmNlcyBhcmUgYXZhaWxhYmxlLCBpbmNsdWRpbmcgW09TQ0EncyBkZW1vbnN0cmF0aW9uIG9mIHRoZSBTaW5nbGVSIG1ldGhvZF0oaHR0cHM6Ly9iaW9jb25kdWN0b3Iub3JnL2Jvb2tzLzMuMTUvT1NDQS5iYXNpYy9jZWxsLXR5cGUtYW5ub3RhdGlvbi5odG1sKSwgYSBbVHV0b3JpYWwgYnkgQ2xhcmtlIGV0IGFsLiBmb3IgY2VsbC10eXBlIGFubm90YXRpb25zXShodHRwczovL3B1Ym1lZC5uY2JpLm5sbS5uaWguZ292LzM0MDMxNjEyLyksIGFuZCBhbiBbZW50aXJlIGNoYXB0ZXIgb2YgdGhlIFNDIGJlc3QgcHJhY3RpY2VzIGJvb2tdKGh0dHBzOi8vd3d3LnNjLWJlc3QtcHJhY3RpY2VzLm9yZy9jZWxsdWxhcl9zdHJ1Y3R1cmUvYW5ub3RhdGlvbi5odG1sI2F1dG9tYXRlZC1hbm5vdGF0aW9uKS4KPC9kZXRhaWxzPgo8YnI+CgojIFVzaW5nIHNjQ0FUQ0gKCkEgdG9vbCB3ZSBvZnRlbiB1c2UgZm9yIGJvdGggbW91c2UgYW5kIGh1bWFuIGRhdGEgY2VsbC10eXBlIHByZWRpY3Rpb25zIGlzIGNhbGxlZCBbc2NDQVRDSF0oaHR0cHM6Ly9naXRodWIuY29tL1pKVUZhbkxhYi9zY0NBVENIL3dpa2kpIHdoaWNoLCBwZXIgdGhlIGF1dGhvcidzIGRlc2NyaXB0aW9uIGluIFtTaGFvIGV0IGFsICgyMDIwKV0oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wbWMvYXJ0aWNsZXMvUE1DNzAzMTMxMi8pLCBhbm5vdGF0ZXMgY2VsbC10eXBlcyB1c2luZyBhICJ0aXNzdWUtc3BlY2lmaWMgY2VsbHVsYXIgdGF4b25vbXkgcmVmZXJlbmNlIGRhdGFiYXNlIChDZWxsTWF0Y2gpIGFuZCBbYW5dIGV2aWRlbmNlLWJhc2VkIHNjb3JpbmcgKEVTKSBwcm90b2NvbCIuIFRoZSBDZWxsTWF0Y2ggcmVmZXJlbmNlIGlzIGNvbXBpbGVkIGZyb20gQ2VsbE1hcmtlciAoW1poYW5nIGV0IGFsLiwgMjAxOWJdKGh0dHBzOi8vd3d3LmNlbGwuY29tL3NlcnZsZXQvbGlua291dD9zdWZmaXg9ZV8xXzVfMV8yXzMzXzImZGJpZD04JmRvaT0xMC4xMDE2L2ouaXNjaS4yMDIwLjEwMDg4MiZrZXk9MzAyODk1NDkmY2Y9KSksIE1DQSAoW0hhbiBldCBhbC4sIDIwMThdKGh0dHBzOi8vd3d3LmNlbGwuY29tL3NlcnZsZXQvbGlua291dD9zdWZmaXg9ZV8xXzVfMV8yXzEwXzImZGJpZD04JmRvaT0xMC4xMDE2L2ouaXNjaS4yMDIwLjEwMDg4MiZrZXk9Mjk3NzU1OTcmY2Y9KSksIENhbmNlclNFQSAoW1l1YW4gZXQgYWwuLCAyMDE5XShodHRwczovL3d3dy5jZWxsLmNvbS9zZXJ2bGV0L2xpbmtvdXQ/c3VmZml4PWVfMV81XzFfMl8yOV8yJmRiaWQ9OCZkb2k9MTAuMTAxNi9qLmlzY2kuMjAyMC4xMDA4ODIma2V5PTMwMzI5MTQyJmNmPSkpLCBhbmQgdGhlIFtDRCBNYXJrZXIgSGFuZGJvb2tdKGh0dHBzOi8vd3d3LmFiY2FtLmNvbS9wcmltYXJ5LWFudGlib2RpZXMvaHVtYW4tY2QtYW50aWdlbi1ndWlkZSkgYW5kIFBNSURzIGZvciByZWxldmFudCBsaXRlcmF0dXJlIGFyZSByZXBvcnRlZCBpbiB0aGUgcHJlZGljdGlvbiByZXN1bHRzLiAKCjwhLS0gY29uc2lkZXIgYWRkaW5nIFtzY1R5cGVdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9zY0NBVENIL3ZpZ25ldHRlcy90dXRvcmlhbC5odG1sKSBhcyBhbiBhbHRlcm5hdGl2ZSAtLT4KCiFbSW1hZ2U6IHNjQ0FUQ0ggc3VtbWFyeSBmcm9tIFNoYW8gZXQgYWwgKDIwMjApLl0oLi9pbWFnZXMvY3VycmljdWx1bS8wNy1DZWxsVHlwZUFubm90YXRpb24vc2NDQVRDSC1wYXBlci1WaXpBYnN0cmFjdC5qcGVnKSAKCkZpcnN0LCB3ZSBuZWVkIHRvIGxvYWQgdGhlIHNjQ0FUQ0ggbGlicmFyeS4gVGhlbiwgd2UnbGwgZG91YmxlIGNoZWNrIHRoYXQgd2UgYXJlIHVzaW5nIHRoZSBleHBlY3RlZCByZXNvbHV0aW9uIGNsdXN0ZXIgcmVzdWx0cyAodGhpcyBpcyBwYXJ0aWN1bGFybHkgaW1wb3J0YW50IGlmIHdlIGdlbmVyYXRlZCBtdWx0aXBsZSByZXNvbHV0aW9ucyBpbiBvdXIgY2x1c3RlcmluZyBzdGVwcyksIGJlZm9yZSBjcmVhdGluZyBhIG5ldyBvYmplY3QgZnJvbSBvdXIgYGNvdW50c2AgZGF0YSB3aXRoIGBjcmVhdGVzY0NBVENIKClgIGFuZCBhZGRpbmcgb3VyIG1hcmtlciBnZW5lcyB0byB0aGUgc2NDQVRDQ0ggb2JqZWN0LgoKVG8gaW5jcmVhc2UgdGhlIHNwZWVkIGFuZCBhY2N1cmFjeSBvZiBvdXIgcHJlZGljdGlvbnMsIHdlJ2xsIGNyZWF0ZSBxdWVyeSBvZiByZWxldmFudCB0aXNzdWVzICh3aGljaCByZXF1aXJlcyBzb21lIHByaW9yIGtub3dsZWRnZSBvZiB0aGUgZXhwZXJpbWVudCBhbmQgdXNpbmcgdGhlIFtzY0NBVENIIHdpa2ldKGh0dHBzOi8vZ2l0aHViLmNvbS9aSlVGYW5MYWIvc2NDQVRDSC93aWtpKSB0byBzZWxlY3QgdGlzc3VlcyBmcm9tIHRoZSBzcGVjaWVzKSBiZWZvcmUgd2UgcnVuIHRoZSB0b29sOgoKYGBge3IsIHNjY2F0Y2gsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQojIyMjIyBEYXkgMyAtIENlbGwgVHlwZSBBbm5vdGF0aW9uCgojIEFubm90YXRlIGNsdXN0ZXJzIHVzaW5nIHNjQ0FUQ0ggIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KbGlicmFyeShzY0NBVENIKQoKIyBjaGVjayB0aGF0IGNlbGwgaWRlbnRpdGllcyBhcmUgc2V0IHRvIGV4cGVjdGVkIHJlc29sdXRpb24gCmFsbChJZGVudHMoZ2VvX3NvKSA9PSBnZW9fc28kaW50ZWdyYXRlZC5zY3QucnBjYS5jbHVzdGVycykKCiMgY3JlYXRlIHNjQ0FUQ0ggb2JqZWN0LCB1c2luZyBjb3VudCBkYXRhCmdlb19jYXRjaCA9IGNyZWF0ZXNjQ0FUQ0goZGF0YSA9IGdlb19zb0Bhc3NheXMkU0NUQGNvdW50cywgY2x1c3RlciA9IGFzLmNoYXJhY3RlcihJZGVudHMoZ2VvX3NvKSkpCgojIGFkZCBtYXJrZXIgZ2VuZXMgdG8gdXNlIGZvciBwcmVkaWN0aW9ucwpnZW9fY2F0Y2hAbWFya2VyZ2VuZSA9IGdlb19tYXJrZXJzCgojIHNwZWNpZnkgdGlzc3Vlcy9jZWxsLXR5cGVzIGZyb20gdGhlIHNjQ0FUQ0ggcmVmZXJlbmNlCmdlb19jYXRjaEBtYXJrZXIgPSBjZWxsbWF0Y2hbY2VsbG1hdGNoJHNwZWNpZXMgPT0gJ01vdXNlJyAmIGNlbGxtYXRjaCR0aXNzdWUgJWluJSBjKCdCbG9vZCcsICdQZXJpcGhlcmFsIEJsb29kJywgJ011c2NsZScsICdTa2VsZXRhbCBtdXNjbGUnLCAnRXBpZGVybWlzJywgJ1NraW4nKSwgXQoKIyBydW4gc2NDQVRDSCB0byBnZW5lcmF0ZSBwcmVkaWN0aW9ucwpnZW9fY2F0Y2ggPSBmaW5kY2VsbHR5cGUoZ2VvX2NhdGNoKQoKIyBsb29rIGF0IHRoZSBwcmVkaWN0aW9ucwpnZW9fY2F0Y2hAY2VsbHR5cGUgJT4lIHNlbGVjdChjbHVzdGVyLCBjZWxsX3R5cGUsIGNlbGx0eXBlX3Njb3JlKQpgYGAKCldoZW4gd2UgbG9vayBhdCBvdXIgcmVzdWx0cyB3ZSBjYW4gc2VlIHRoZSBjZWxsIHR5cGUgc2NvcmUsIHdoaWNoIGdpdmVzIHVzIGFuIGlkZWEgb2YgdGhlIGNvbmZpZGVuY2Ugb2YgdGhhdCBwcmVkaWN0aW9uLiBOb3Qgc2hvd24gaGVyZSBidXQgdGhlIGZ1bGwgYGNlbGx0eXBlYCB0YWJsZSBhbHNvIGluY2x1ZGVzIG1hcmtlciBnZW5lcyBhbmQgUE1JRHMgZm9yIHJlbGV2YW50IGxpdGVyYXR1cmUgZm9yIGVhY2ggcHJlZGljdGlvbi4KCkluIG91ciBleHBlcmllbmNlLCB0aGVzZSBraW5kcyBvZiByZXN1bHRzIG9mdGVuIGhlbHAgZ3VpZGUgY2x1c3RlciBhbm5vdGF0aW9uIGJ1dCBzY29yZXMgY2FuIHZhcnkgYW5kIHRoZSBwcmVkaWN0aW9ucyBtYXkgbmVlZCB0byBiZSByZXZpc2VkIGJhc2VkIG9uIHJlc2VhcmNoZXIncyBrbm93bGVkZ2Ugb2YgdGhlIGJpb2xvZ2ljYWwgc3lzdGVtLiBBcyB0aGVzZSBjZWxsLXR5cGVzIGNvcnJlc3BvbmQgdG8gdGhlIGNlbGwtdHlwZXMgYW5kIHN1YnR5cGVzIHdlJ2QgZXhwZWN0IHRvIGJlIHByZXNlbnQgaW4gdGhlc2UgZGF0YSBhbmQgbW9zdCBvZiB0aGUgcHJlZGljdGlvbiBzY29yZXMgYXJlIHF1aXRlIGhpZ2gsIHdlIGNhbiByZWFzb25hYmx5IHVzZSB0aGVzZSByZXN1bHRzIHRvIGFubm90YXRlIG91ciBjbHVzdGVycyB3aXRoIHNvbWUgbWlub3IgYWRqdXN0bWVudHMuIAoKIyMgVXNpbmcga25vd24gY2VsbC10eXBlIG1hcmtlcnMKClRvIGNvbmZpcm0gYW5kIHJlZmluZSB0aGUgc2NDQVRDSCBwcmVkaWN0aW9ucywgd2UnbGwgc3BvdCBjaGVjayBzb21lIGtub3duIG1hcmtlcnMgZm9yIGltbXVuZSBwb3B1bGF0aW9ucy4gVGhlbiB3ZSdsbCBsb29rIGxvb2sgYXQgc29tZSBvdGhlciBrZXkgbWFya2VyIGdlbmVzIGZyb20gc29tZSBvdGhlciByZWxldmFudCByZXNvdXJjZXMgbGlrZSBbQ2hlbiBldCBhbCAoMjAyMSldKGh0dHBzOi8vd3d3Lm5hdHVyZS5jb20vYXJ0aWNsZXMvczQxNDY3LTAyMS0yNzU2My0zKSwgW0J1ZWNobGVyIGV0IGFsICgyMDIxKV0oaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9zNDE1ODYtMDIxLTAzNTQ5LTUpIFtSb21hbiAoMjAyMyldKGh0dHBzOi8vcG1jLm5jYmkubmxtLm5paC5nb3YvYXJ0aWNsZXMvUE1DMTAyOTY0MDkvI3NlYzMtYmlvbW9sZWN1bGVzLTEzLTAwOTQ1ICksICBbTGkgZXQgYWwgKDIwMjIpXShodHRwczovL2JtY2Jpb2luZm9ybWF0aWNzLmJpb21lZGNlbnRyYWwuY29tL2FydGljbGVzLzEwLjExODYvczEyODU5LTAyMi0wNDgxNy01L2ZpZ3VyZXMvMikgYW5kIFtOZXN0b3Jvd2EgZXQgYWwgKDIwMTYpXShodHRwczovL2FzaHB1YmxpY2F0aW9ucy5vcmcvYmxvb2QvYXJ0aWNsZS8xMjgvOC9lMjAvMzU3NDkvQS1zaW5nbGUtY2VsbC1yZXNvbHV0aW9uLW1hcC1vZi1tb3VzZSkgdG8gc2VlIGlmIG90aGVyIG1vZGlmaWNhdGlvbnMgc2hvdWxkIGJlIG1hZGUgdG8gdGhlIHNjQ0FUQ0ggcHJlZGljdGlvbnM6CmBgYHtyLCBtYXJrZXJfZ2VuZV9jaGVjaywgZmlnLnNob3c9J2hvbGQnfQojIFBsb3Qgb3RoZXIgbWFya2Vycy9mZWF0dXJlcyB0byBhc3Npc3Qgd2l0aCBpZGVudGlmaWNhdGlvbiAtLS0tLS0tLS0tLS0tLS0KIyBzcG90IGNoZWNrIGtub3duIGltbXVuZSBtYXJrZXJzCmltbXVuZV9tYXJrZXJzID0gbGlzdCgpCmltbXVuZV9tYXJrZXJzW1snSW5mbGFtLiBNYWNyb3BoYWdlJ11dID0gYygnQ2QxNCcsICdDeGNsMicpICMgQ2QxNCBhLSBtb25vY3l0ZS9tYWNyb3BoYWdlIGNlbGxzCmltbXVuZV9tYXJrZXJzW1snUGxhdGVsZXQnXV0gPSBjKCdQZjQnKQppbW11bmVfbWFya2Vyc1tbJ01hc3QgY2VsbHMnXV0gPSBjKCdHYXRhMicsICdLaXQnKQppbW11bmVfbWFya2Vyc1tbJ05LIGNlbGxzJ11dID0gYygnTmtnNycsICdLbHJkMScpCmltbXVuZV9tYXJrZXJzW1snQi1jZWxsJ11dID0gYyggJ0x5NmQnLCAnQ2QxOScsICdDZDc5YicsICdNczRhMScpCmltbXVuZV9tYXJrZXJzW1snVC1jZWxsJ11dID0gYyggJ0NkM2QnLCdDZDNlJywnQ2QzZycpICMgYWxzbyBUaHkxCgppbW11bmVfbWFya2Vyc19wbG90ID0gRG90UGxvdChnZW9fc28sIGZlYXR1cmVzID0gaW1tdW5lX21hcmtlcnMsIGFzc2F5ID0gJ1NDVCcpICArCiAgdGhlbWUodGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMCksIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIHZqdXN0ID0gMC41KSkKaW1tdW5lX21hcmtlcnNfcGxvdAoKIyBzYXZlIHRvIGZpbGUKZ2dzYXZlKGZpbGVuYW1lID0gJ3Jlc3VsdHMvZmlndXJlcy9pbW11bmVfbWFya2Vyc19zY3RfZG90X3Bsb3QucG5nJywgcGxvdCA9IGltbXVuZV9tYXJrZXJzX3Bsb3QsIHdpZHRoID0gMTAsIGhlaWdodCA9IDUsIHVuaXRzID0gJ2luJykKCiMgcGxvdCBzb21lIGtub3duIGNlbGwtdHlwZSBtYXJrZXJzIApvdGhlcl9tYXJrZXJzID0gbGlzdCgpCm90aGVyX21hcmtlcnNbWydQZXJpY3l0ZSddXSA9IGMoJ0FjYW4nLCdTb3g5JykKb3RoZXJfbWFya2Vyc1tbJ1NNQyddXSA9IGMoJ0FjdGEyJywgJ015aDExJykgIyBTTUMgPSBtZXNlbmNoeW1hbCBzbW9vdGgtbXVzY2xlIGNlbGwvbWVzZW5jaHltYWwgbGluZWFnZQpvdGhlcl9tYXJrZXJzW1snS2VyYXRpbm9jeXRlcyddXSA9IGMoJ1RoeTEnLCAnRGxrMScpICMgZmlicm8gcHJvZ2VuaXRvcnMgYXNvPVRoeTEKb3RoZXJfbWFya2Vyc1tbJ015b2ZpYnJvYmxhc3RzJ11dID0gYygnVG1lbTEwMCcsICdDZDM0JywgJ0x5NmMxJykgIyBoZW1hdG9wb2V0aWMgc3RlbS9hY3RpdmF0ZWQgZmlicm9ibGFzdD1DZDM0Cm90aGVyX21hcmtlcnNbWydGaWJyb2JsYXN0J11dID0gYygnRHB0JywgJ0ZuMScsICdDb2wzYTEnKSAgIyBhY3RpdmF0ZWQgZmliID0gRm4xCm90aGVyX21hcmtlcnNbWydFbmRvdGhlbGlhbCddXSA9IGMoJ1BlY2FtMScsICdDZDM4JykgIyBmcm9tIHdvdW5kIGhlYWxpbmc7IFBlY2FtMSBhbHNvIGV4cCBpbiBlbmRvdGhlbGlhbApvdGhlcl9tYXJrZXJzW1snSFNDJ11dID0gYygnTHRiJywgJ0NkNzQnKSAjIGxlc3Mgd2VsbCBkZWZpbmVkL2NvbmZsaWN0aW5nIGRlZmluaXRpb25zCm90aGVyX21hcmtlcnNbWydFcnl0aHJvaWQnXV0gPSBjKCdIYmEtYTEnKQoKb3RoZXJfbWFya2Vyc19kb3RfcGxvdCA9IERvdFBsb3QoZ2VvX3NvLCBmZWF0dXJlcyA9IG90aGVyX21hcmtlcnMsIGFzc2F5ID0gJ1NDVCcpICsKICB0aGVtZSh0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTEwKSwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgdmp1c3QgPSAwLjUpKQpvdGhlcl9tYXJrZXJzX2RvdF9wbG90CgojIHNhdmUgdG8gZmlsZQpnZ3NhdmUoZmlsZW5hbWUgPSAncmVzdWx0cy9maWd1cmVzL290aGVyX21hcmtlcnNfc2N0X2RvdF9wbG90LnBuZycsIHBsb3QgPSBvdGhlcl9tYXJrZXJzX2RvdF9wbG90LCB3aWR0aCA9IDEyLCBoZWlnaHQgPSA1LCB1bml0cyA9ICdpbicpCgpgYGAKSW4gdGhlIGZpcnN0IHBsb3QsIEItY2VsbCBhbmQgVC1jZWxsIG1hcmtlcnMgc2VlbSB0byBsaW5lIHVwIHdpdGggdGhlIHByZWRpY3Rpb25zIGFuZCBhcmUgbGltaXRlZCB0byBzaW5nbGUgY2x1c3RlcnMuIEhvd2V2ZXIsIG1hY3JvcGhhZ2UgYW5kIGRlbmRyb2N5dGUgbWFya2VycyBtYXRjaCB0byBtdWx0aXBsZSBjbHVzdGVycyBpbmNsdWRpbmcgc29tZSBhbm5vdGF0ZWQgd2l0aCBkaWZmZXJlbnQgY2VsbCB0eXBlcywgc28gd2UgY2FuIGNvbnNpZGVyIG1vZGlmeWluZyB0aG9zZSBjbHVzdGVyIGxhYmVscy4gCgoKRnJvbSB0aGUgb3RoZXIgbWFya2VyIGdlbmVzLCB0aGUgcGF0dGVybnMgYXJlIGxlc3MgY2xlYXIgc28gd2UgbWF5IHdhbnQgdG8gdGVzdCBvdGhlciBjbHVzdGVyaW5nIHBhcmFtZXRlcnMgYW5kIGRpc2N1c3MgdGhlIHJlc3VsdHMgd2l0aCBhIHJlc2VhcmNoZXIgZmFtaWxpYXIgd2l0aCB0aGUgZXhwZWN0ZWQgY2VsbCB0eXBlcy4gSG93ZXZlciwgd2UgY2FuIG5vdGljZSBzb21lIHBhdHRlcm5zIHRoYXQgd2UgY2FuIHVzZSB0byByZWZpbmUgb3VyIGNsdXN0ZXIgYW5ub3RhdGlvbnMuIAoKIyMjIyBVdGlsaXppbmcgZ2VuZXMgb2YgaW50ZXJlc3QgZnJvbSB0aGUgb3JpZ2luYWwgcGFwZXIgCgo8ZGV0YWlscz4KICAgIDxzdW1tYXJ5PipQbG90dGluZyB0aGUgZXhwcmVzc2lvbiBvZiBnZW5lcyBvZiBpbnRlcmVzdCBmcm9tIFNvcmtpbiwgSHViZXIgZXQgYWwqPC9zdW1tYXJ5PgogICAgT2Z0ZW4gd2UgaGF2ZSBwcmlvciBpbmZvcm1hdGlvbiBhYm91dCB3aGF0IGNlbGwgdHlwZXMgYXJlIGV4cGVjdGVkIGluIG91ciBzYW1wbGVzIGFuZCBrZXkgbWFya2VyIGdlbmVzIGZvciB0aG9zZSBwb3B1bGF0aW9ucy4gVGhpcyBjYW4gYmUgYW4gaW1wb3J0YW50IHBhcnQgb2YgZXZhbHVhdGluZyBvdXIgY2x1c3RlcnMsIHNpbmNlIGlmIGdlbmVzIHRoYXQgYXJlIGtub3duIG1hcmtlcnMgZm9yIGEgc3BlY2lmaWMgY2VsbCB0eXBlIGFyZSBmb3VuZCBpbiB0b28gbWFueSBvciB0b28gZmV3IGNsdXN0ZXJzIGFzIHRoYXQgY2FuIHN1Z2dlc3QgdGhhdCByZS1jbHVzdGVyaW5nIGlzIG5lZWRlZCBvciB0aGF0IHNvbWUgb2YgdGhlIGNsdXN0ZXJzIHNob3VsZCBiZSBtYW51YWxseSBjb21iaW5lZCBiZWZvcmUgYW5ub3RhdGluZy4gV2UgY2FuIGNyZWF0ZSBsaXN0cyBvZiBtYXJrZXJzIHVzZWQgaW4gZmlndXJlcyBmcm9tIHRoZSBbb3JpZ2luYWwgcGFwZXJdKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvcG1jL2FydGljbGVzL1BNQzcwMDI0NTMvKSBiZWZvcmUgdXNpbmcgdGhlIHNhbWUgYERvdFBsb3QoKWAgZnVuY3Rpb24gdG8gdmlzdWFsaXplIHRoZSBleHByZXNzaW9uIGxldmVsIGFuZCBmcmVxdWVuY3kgb2YgdGhlc2UgZ2VuZXMgaW4gb3VyIGN1cnJlbnQgY2x1c3RlcnM6CgpgYGB7ciwga25vd25fZG90X3Bsb3RzX3NjdCwgZmlnLnNob3c9J2hvbGQnfQojIFZpc3VhbGl6ZSBtYW51YWxseSBzZWxlY3RlZCBtYXJrZXIgZ2VuZXMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyBDcmVhdGUgbGlzdHMgb2YgZ2VuZXMgZnJvbSBwYXBlciAKZmlnMWdfbWFya2VycyA9IGMoJ0N4Y2wxJywgJ0N4Y2wyJywgJ0NjbDInLCAnQ2NsMycsICdDY2w0JywgJ0lsMWInLCAnSWw2YicsICdUbmYnLCAnVGdmYjEnLCAnVGdmYjInLCAnVGdmYjMnLCAnQ3hjbDUnKQpmaWcxaF9tYXJrZXJzID0gYygnQ3hjcjInLCAnQ3NmMXInLCAnQ3NmM3InLCAnVGdmYnIxJywgJ1RnZmJyMycsICdJbDFyMScsICdJbDZyYScsICdMaWZyJywgJ1RnZmJyMicpCgojIGNyZWF0ZSBEb3RQbG90cyBmb3IgZ2VuZXMgZnJvbSBwYXBlcgpmaWcxZ19zY3RfZG90X3Bsb3QgPSBEb3RQbG90KGdlb19zbywgZmVhdHVyZXMgPSBmaWcxZ19tYXJrZXJzLCBhc3NheSA9ICdTQ1QnKQpmaWcxaF9zY3RfZG90X3Bsb3QgPSBEb3RQbG90KGdlb19zbywgZmVhdHVyZXMgPSBmaWcxaF9tYXJrZXJzLCBhc3NheSA9ICdTQ1QnKQoKZmlnMWdfc2N0X2RvdF9wbG90CmZpZzFoX3NjdF9kb3RfcGxvdAoKIyBzYXZlIHBsb3RzIHRvIGZpbGUKZ2dzYXZlKGZpbGVuYW1lID0gJ3Jlc3VsdHMvZmlndXJlcy9tYXJrZXJzX2ZpZzFnX3NjdF9kb3RfcGxvdC5wbmcnLCBwbG90ID0gZmlnMWdfc2N0X2RvdF9wbG90LCB3aWR0aCA9IDgsIGhlaWdodCA9IDYsIHVuaXRzID0gJ2luJykKZ2dzYXZlKGZpbGVuYW1lID0gJ3Jlc3VsdHMvZmlndXJlcy9tYXJrZXJzX2ZpZzFoX3NjdF9kb3RfcGxvdC5wbmcnLCBwbG90ID0gZmlnMWhfc2N0X2RvdF9wbG90LCB3aWR0aCA9IDgsIGhlaWdodCA9IDYsIHVuaXRzID0gJ2luJykKYGBgCkZvciBrbm93biBtYXJrZXIgZ2VuZXMsIGl0J3MgaW1wb3J0YW50IHRvIG5vdGUgdGhhdCBzaW5jZSBzY1JOQS1zZXEgaXMgb25seSBtZWFzdXJpbmcgdHJhbnNjcmlwdGlvbmFsIHNpZ25hbHMgdGhhdCBtYXJrZXJzIGF0IHRoZSBwcm90ZWluIGxldmVsIChlLmcgdXNlZCBmb3IgYXBwcm9hY2hlcyBsaWtlIEZBQ1MpIG1heSBiZSBsZXNzIGVmZmVjdGl2ZS4gQW4gYWx0ZXJuYXRpdmUgb3IgY29tcGxlbWVudCB0byB1c2luZyBtYXJrZXIgZ2VuZXMgY291bGQgYmUgbWV0aG9kcyBsaWtlIHVzaW5nIGdlbmUgc2V0IGVucmljaG1lbnQgKEdTRUEpIFthcyBkZW1vbnN0cmF0ZWQgaW4gdGhlIE9TQ0EgYm9va10oaHR0cHM6Ly9iaW9jb25kdWN0b3Iub3JnL2Jvb2tzLzMuMTUvT1NDQS5iYXNpYy9jZWxsLXR5cGUtYW5ub3RhdGlvbi5odG1sI2NvbXB1dGluZy1nZW5lLXNldC1hY3Rpdml0aWVzKSB0byBhaWQgaW4gYW5ub3RhdGlvbnMuIEhvd2V2ZXIsIHRoZSBib29rIFsiQmVzdCBwcmFjdGljZXMgZm9yIHNpbmdsZS1jZWxsIGFuYWx5c2lzIGFjcm9zcyBtb2RhbGl0aWVzIiBieSBIZXVtb3MsIFNjaGFhciwgTGFuY2UsIGV0IGFsLiBdKGh0dHBzOi8vd3d3LnNjLWJlc3QtcHJhY3RpY2VzLm9yZy9jZWxsdWxhcl9zdHJ1Y3R1cmUvYW5ub3RhdGlvbi5odG1sKSBwb2ludHMgb3V0IHRoYXQgIml0IGlzIG9mdGVuIHVzZWZ1bCB0byB3b3JrIHRvZ2V0aGVyIHdpdGggZXhwZXJ0cyAuLi4gW2xpa2UgYV0gYmlvbG9naXN0IHdobyBoYXMgbW9yZSBleHRlbnNpdmUga25vd2xlZGdlIG9mIHRoZSB0aXNzdWUsIHRoZSBiaW9sb2d5LCB0aGUgZXhwZWN0ZWQgY2VsbCB0eXBlcyBhbmQgbWFya2VycyBldGMuIi4gSW4gb3VyIGV4cGVyaWVuY2UsIHdlIGZpbmQgdGhhdCBleHBlcmllbmNlIGFuZCBrbm93bGVkZ2Ugb2YgdGhlIHJlc2VhcmNoZXJzIHdlIHdvcmsgd2l0aCBpcyBpbnZhbHVhYmxlLiAKCjwvZGV0YWlscz4KPGJyPgoKPGRldGFpbHM+CiAgICA8c3VtbWFyeT4qVXNpbmcgcmF3IFJOQSB2YWx1ZXMgZm9yIGdlbmVzIG9mIGludGVyZXN0IGZyb20gU29ya2luLCBIdWJlciBldCBhbCo8L3N1bW1hcnk+CiAgICBXZSBjYW4gYWxzbyBnZW5lcmF0ZSB0aGUgc2FtZSBwbG90cywgYnV0IHVzaW5nIHRoZSB1bmludGVncmF0ZWQgZGF0YSBieSBzcGVjaWZ5aW5nIHRoZSBgUk5BYCBhc3NheToKCmBgYHtyLCBrbm93bl9kb3RfcGxvdF9ybmEsIGV2YWw9RkFMU0V9CiMgVmlzdWFsaXplIG1hbnVhbGx5IHNlbGVjdGVkIG1hcmtlciBnZW5lcyAoZnJvbSB1bmludGVncmF0ZWQgZGF0YSkgLS0tLS0tCnJuYV9kb3RfcGxvdCA9IERvdFBsb3QoZ2VvX3NvLCBmZWF0dXJlcyA9IGZpZzFnX21hcmtlcnMsIGFzc2F5ID0gJ1JOQScpCmZpZzFoX3JuYV9kb3RfcGxvdCA9IERvdFBsb3QoZ2VvX3NvLCBmZWF0dXJlcyA9IGZpZzFoX21hcmtlcnMsIGFzc2F5ID0gJ1JOQScpCgpnZ3NhdmUoZmlsZW5hbWUgPSAncmVzdWx0cy9maWd1cmVzL21hcmtlcnNfZmlnMWdfcm5hX2RvdF9wbG90LnBuZycsIHBsb3QgPSBmaWcxZ19ybmFfZG90X3Bsb3QsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNiwgdW5pdHMgPSAnaW4nKQpnZ3NhdmUoZmlsZW5hbWUgPSAncmVzdWx0cy9maWd1cmVzL21hcmtlcnNfZmlnMWhfcm5hX2RvdF9wbG90LnBuZycsIHBsb3QgPSBmaWcxaF9ybmFfZG90X3Bsb3QsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNiwgdW5pdHMgPSAnaW4nKQpgYGAKPC9kZXRhaWxzPgo8YnI+CgoKIyBBbm5vdGF0ZSBjbHVzdGVycwoKTmV4dCwgd2UnbGwgbW9kaWZ5IHRoZSBjZWxsIHR5cGUgcHJlZGljdGlvbnMgYW5kIGFkZCB0aGUgbGFiZWxzIHRvIG91ciBTZXVyYXQgb2JqZWN0IHRvIHJlcGxhY2Ugb3VyIGNsdXN0ZXJzJyBudW1lcmljYWwgaWRlbnRpdGllcy4gTm90ZTogd2Ugd2lsbCBjcmVhdGUgYSBuZXcgbWV0YWRhdGEgb2JqZWN0IHdoZXJlIHdlIGpvaW4gY2VsbCB0eXBlcy4gSG93ZXZlciwgdGhpcyB3aWxsIGRlc3Ryb3kgdGhlIHJvdyBuYW1lcyAtIHdoaWNoIHdpbGwgY2F1c2UgYSBwcm9ibGVtIGluIFNldXJhdCAtIHNvIHdlIGhhdmUgdG8gYWRkIHRoZW0gYmFjay4gPCEtLS0gbW9kaWZ5IHRvIGhhdmUgYSBoaWRkZW4gYmxvY2sgdGhhdCBydW5zIGFmdGVyIHRvIGtlZXAgdGhpcyBsYXJnZSBibG9jayBpbnRhY3QgLS0+CgpgYGB7ciwgYW5ub3RhdGVfY2x1c3RlcnN9CiMgQW5ub3RhdGUgY2x1c3RlcnMgdXNpbmcgbW9kaWZpZWQgcHJlZGljdGlvbnMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIEZpcnN0IC0gRXh0cmFjdCB0aGUgY2VsbCB0eXBlcyBvbmx5IGZyb20gdGhlIHByZWRpY3Rpb25zCmNlbGx0eXBlX2Fubm9zID0gZ2VvX2NhdGNoQGNlbGx0eXBlICU+JSBzZWxlY3QoY2x1c3RlciwgY2VsbF90eXBlKSAlPiUgCiAgbXV0YXRlKGNsdXN0ZXIgPSBmYWN0b3IoY2x1c3RlciwgbGV2ZWxzID0gYygwOjE5KSkpICU+JSBhcnJhbmdlKGNsdXN0ZXIpCmNlbGx0eXBlX2Fubm9zCgojIEN1c3RvbWl6ZSBhbm5vdGF0aW9ucywgcmVtZW1iZXJpbmcgdGhhdCBjbHVzdGVyIDAgPSByb3cgMSBpbiB0YWJsZQpjZWxsdHlwZV9hbm5vcyRjZWxsX3R5cGVbYygzLDE1KV0gPC0gIkluZmxhbW1hdG9yeSBtYWNyb3BoYWdlIiAjIHJlc29sdmVzIGNsdXN0ZXIgMiBhbmQgMTQKY2VsbHR5cGVfYW5ub3MkY2VsbF90eXBlW2MoMTEpXSA8LSAiTWFjcm9waGFnZSIKCmNlbGx0eXBlX2Fubm9zJGNlbGxfdHlwZVtjKDIpXSA8LSAiRmlicm9ibGFzdCIgIyByZXZpc2UgY2x1c3RlcnMgMSw2IGJhc2VkIG9uIG1hcmtlcnMKY2VsbHR5cGVfYW5ub3MkY2VsbF90eXBlW2MoNildIDwtICJNeW9maWJyb2JsYXN0IgpjZWxsdHlwZV9hbm5vcyRjZWxsX3R5cGVbYyg4LDkpXSA8LSAiRW5kb3RoZWxpYWwiICMgcmV2aXNlIGNsdXN0ZXIgNyw4OyBhbHNvIGhhdmUgd2Vha2VyIG1hc3QgY2VsbCBzaWduYWwKY2VsbHR5cGVfYW5ub3MkY2VsbF90eXBlW2MoNiwxMyldIDwtICJIZW1hdG9wb2lldGljIHN0ZW0gY2VsbCIgIyBiYXNlZCBvbiBtYXJrZXJzIGJ1dCBjb3VsZCBmdXJ0aGVyIHJldmlzZQpjZWxsdHlwZV9hbm5vcyRjZWxsX3R5cGVbYygxMCwxOSldIDwtICJNZXNlbmNoeW1hbCBzdGVtL3N0cm9tYWwgY2VsbCIgIyBiYXNlZCBvbiBBY3RhMiBzaWduYWwKY2VsbHR5cGVfYW5ub3MkY2VsbF90eXBlW2MoMTYpXSA8LSAiRXJ5dGhyb2lkIiAjIGNsdXN0ZXIgMTUsIGxlc3MgY29uZmlkZW50IGJ1dCBub3QgbmVhciBvdGhlciBkZW5kcml0aWMgY2VsbHMKY2VsbHR5cGVfYW5ub3MkY2VsbF90eXBlW2MoMjAsIDE3KV0gPC0gIlVua25vd24iICMgc2luY2Ugc3VjaCBzbWFsbCBwb3B1bGF0aW9ucywgcmVzZXQgY2x1c3RlciAxNiAmIDE5IGFzIHVua25vd24gZm9yIG5vdwoKCiMgTWVyZ2UgY2VsbCB0eXBlcyBpbiBidXQgYXMgYSBuZXcgdGFibGUgdG8gc2xpZGUgaW50byBAbWV0YS5kYXRhCm5ld19tZXRhZGF0YSA9IGdlb19zb0BtZXRhLmRhdGEgJT4lIGxlZnRfam9pbihjZWxsdHlwZV9hbm5vcywgYnkgPSBjKCdpbnRlZ3JhdGVkLnNjdC5ycGNhLmNsdXN0ZXJzJyA9ICdjbHVzdGVyJykpCnJvd25hbWVzKG5ld19tZXRhZGF0YSkgPSByb3duYW1lcyhnZW9fc29AbWV0YS5kYXRhKSAjICBXZSBhcmUgaW1wbGljaXRseSByZWx5aW5nIG9uIHRoZSBzYW1lIHJvdyBvcmRlciEKCiMgUmVwbGFjZSB0aGUgbWV0YS5kYXRhCmdlb19zb0BtZXRhLmRhdGEgPSBuZXdfbWV0YWRhdGEgCgpoZWFkKGdlb19zb0BtZXRhLmRhdGEpCmBgYAoKKipDaGVja3BvaW50KiogOiBIYXMgdGhlIG1ldGFkYXRhIGZvciB5b3VyIGBnZW9fc29gIG9iamVjdCBiZWVuIHVwZGF0ZWQ/CgpXZSBoYXZlIG5vdyBhZGRlZCBhICJjZWxsX3R5cGUiIGNvbHVtbiB0byB0aGUgYG1ldGEuZGF0YWAgdGFibGU6CgohW0ltYWdlOiBTY2hlbWF0aWMgYWZ0ZXIgYWRkaW5nIGNlbGxfdHlwZSBjb2x1bW4uXShpbWFnZXMvc2V1cmF0X3NjaGVtYXRpYy9TbGlkZTEyLnBuZykKCiMjIFZpc3VhbGlzZSBhbm5vdGF0ZWQgY2x1c3RlcnMKCkxhc3RseSwgd2UgY2FuIGdlbmVyYXRlIGEgcmV2aXNlZCBVTUFQIHBsb3Qgd2l0aCBvdXIgZGVzY3JpcHRpdmUgY2x1c3RlciBsYWJlbHMgYnkgdXNpbmcgb3VyIHVwZGF0ZWQgU2V1cmF0IG9iamVjdCBhbmQgcHJvdmlkaW5nIHRoZSBuZXcgYGNlbGxfdHlwZWAgbGFiZWwgZm9yIHRoZSBgZ3JvdXAuYnlgIGFyZ3VtZW50OgoKYGBge3IsIGNhdGNoX3VtYXBfcGxvdCwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA4LCBmaWcuc2hvdz0naG9sZCd9CiMgTWFrZSBhIGxhYmVsZWQgVU1BUCBwbG90IG9mIGNsdXN0ZXJzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpjYXRjaF91bWFwX3Bsb3QgPSBEaW1QbG90KGdlb19zbywgZ3JvdXAuYnkgPSAnY2VsbF90eXBlJywgbGFiZWwgPSBUUlVFLCByZWR1Y3Rpb24gPSAndW1hcC5pbnRlZ3JhdGVkLnNjdC5ycGNhJykKY2F0Y2hfdW1hcF9wbG90CgpnZ3NhdmUoZmlsZW5hbWUgPSAncmVzdWx0cy9maWd1cmVzL3VtYXBfaW50ZWdyYXRlZF9jYXRjaC5wbmcnLCBwbG90ID0gY2F0Y2hfdW1hcF9wbG90LCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA4LCB1bml0cyA9ICdpbicpCgpjYXRjaF91bWFwX2NvbmRpdGlvbl9wbG90ID0gRGltUGxvdChnZW9fc28sIGdyb3VwLmJ5ID0gJ2NlbGxfdHlwZScsIHNwbGl0LmJ5ID0gJ2RheScsIGxhYmVsID0gVFJVRSwgcmVkdWN0aW9uID0gJ3VtYXAuaW50ZWdyYXRlZC5zY3QucnBjYScpCmNhdGNoX3VtYXBfY29uZGl0aW9uX3Bsb3QKCmdnc2F2ZShmaWxlbmFtZSA9ICdyZXN1bHRzL2ZpZ3VyZXMvdW1hcF9pbnRlZ3JhdGVkX2NhdGNoX2J5Q29uZGl0aW9uLnBuZycsIHBsb3QgPSBjYXRjaF91bWFwX3Bsb3QsIHdpZHRoID0gMTAsIGhlaWdodCA9IDgsIHVuaXRzID0gJ2luJykKYGBgCgo8IS0tIHRvIGFkZCAtIG51bWJlciBvZiBjZWxscyBwZXIgY2x1c3RlciBhbmQgY29uZGl0aW9uL3JlcGxpY2F0ZSBhZnRlciBhbm5vdGF0aW9uIC0tLT4KCiMgU2F2ZSBvdXIgcHJvZ3Jlc3MKCldlJ2xsIHNhdmUgdGhlIHNjQ0FUQ0ggb2JqZWN0LiBUaGUgU2V1cmF0IG9iamVjdCBoYXMgbm90IGJlZW4gY2hhbmdlZCBpbiB0aGlzIG1vZHVsZS4KCmBgYHtyLCBzYXZlX3Jkc19oaWRkZW4sIGVjaG8gPSBGQUxTRX0KaWYoIWZpbGUuZXhpc3RzKCdyZXN1bHRzL3JkYXRhL2dlb19zb19zY3RfaW50ZWdyYXRlZF93aXRoX2NhdGNoLnJkcycpKSB7CiAgc2F2ZVJEUyhnZW9fc28sIGZpbGUgPSAncmVzdWx0cy9yZGF0YS9nZW9fc29fc2N0X2ludGVncmF0ZWRfd2l0aF9jYXRjaC5yZHMnKQp9CgppZighZmlsZS5leGlzdHMoJ3Jlc3VsdHMvcmRhdGEvZ2VvX2NhdGNoLnJkcycpKSB7CiAgc2F2ZVJEUyhnZW9fY2F0Y2gsIGZpbGUgPSAncmVzdWx0cy9yZGF0YS9nZW9fY2F0Y2gucmRzJykKfQpgYGAKCmBgYHtyLCBzYXZlX3JkcywgZXZhbD1GQUxTRX0KIyBTYXZlIFNldXJhdCBvYmplY3QgYW5kIGFubm90YXRpb25zIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCnNhdmVSRFMoZ2VvX3NvLCBmaWxlID0gJ3Jlc3VsdHMvcmRhdGEvZ2VvX3NvX3NjdF9pbnRlZ3JhdGVkX3dpdGhfY2F0Y2gucmRzJykKc2F2ZVJEUyhnZW9fY2F0Y2gsIGZpbGUgPSAncmVzdWx0cy9yZGF0YS9nZW9fY2F0Y2gucmRzJykKYGBgCgojIFN1bW1hcnkKCk5vdyB0aGF0IHdlIGhhdmUgZ2VuZXJhdGVkIHJlYXNvbmFibGUgYW5ub3RhdGlvbnMgZm9yIG91ciBjbHVzdGVycywgd2UgY2FuIHByb2NlZWQgd2l0aCB0aGUgc3RlcCBvZiBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiB3aGljaCBpcyBlc3NlbnRpYWwgdG8gYWRkcmVzc2luZyBvdXIgYmlvbG9naWNhbCBxdWVzdGlvbiBmb3IgdGhpcyBleHBlcmltZW50LgoKTmV4dCBzdGVwczogRGlmZmVyZW50aWFsIEV4cHJlc3Npb24KCi0tLS0KClRoZXNlIG1hdGVyaWFscyBoYXZlIGJlZW4gYWRhcHRlZCBhbmQgZXh0ZW5kZWQgZnJvbSBtYXRlcmlhbHMgbGlzdGVkIGFib3ZlLiBUaGVzZSBhcmUgb3BlbiBhY2Nlc3MgbWF0ZXJpYWxzIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgW0NyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24gbGljZW5zZSAoQ0MgQlkgNC4wKV0oaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnkvNC4wLyksIHdoaWNoIHBlcm1pdHMgdW5yZXN0cmljdGVkIHVzZSwgZGlzdHJpYnV0aW9uLCBhbmQgcmVwcm9kdWN0aW9uIGluIGFueSBtZWRpdW0sIHByb3ZpZGVkIHRoZSBvcmlnaW5hbCBhdXRob3IgYW5kIHNvdXJjZSBhcmUgY3JlZGl0ZWQuCgo8YnIvPgo8YnIvPgo8aHIvPgp8IFtQcmV2aW91cyBsZXNzb25dKDA2LU1hcmtlclZpc3VhbGl6YXRpb24uaHRtbCkgfCBbVG9wIG9mIHRoaXMgbGVzc29uXSgjdG9wKSB8IFtOZXh0IGxlc3Nvbl0oMDgtRGlmZmVyZW50aWFsRXhwcmVzc2lvbi5odG1sKSB8CnwgOi0tLSB8IDotLS0tOiB8IC0tLTogfAo=