Data Availability

All you need to do to run this workflow is to install the appropriate R packages and download the following file:

  • 10.6084/m9.figshare.7357178: DOI for this workflow. Includes output from the DADA2 workflow, the phyloseq script, and other necessary input files.

We made several additional data products and processing scripts available.


Preamble

This document is interactive. You can sort and scroll through most of the tables and the phylogenetic tree is zoomable. In the upper right hand corner of the front page is a Code button. Use this to show or hide all the code in the document (default is hide) as well as download the .Rmd file which you can use to extract the code. Data products from the final paper are highlighted in Red.

Definitions & Abbreviations

  • Amplicon Sequence Variant (ASV): Exact sequence variant—analogous to an OTU—but with single nucleotide resolution.
  • Differentially abundant (DA) feature: Taxa, ASV, etc. that is disproportionately abundant in a group of samples and statistically different than other groups.

Study goals

  1. Assess the taxonomic composition of intestinal communities from herbivorous reef fish.
  2. Determine the diversity of these communities and their similarity/dissimilarity.
  3. Identify differentially abundant ASVs across the host species.
  4. Predict the specificity of differentially abundant ASVs.

Workflow overview

Part I: Field Observations

Before we proceed with microbial community analysis, we will run some analyses on field-based behavioral assays of the different herbivorous reef fish species.

Part II: Data Preparation

In this first part we go through the steps of defining sample groups, creating phyloseq objects, removing unwanted samples, and removing contaminant ASVs. Various parts of this section can easily be modified to perform different analyses. For example, if you were only interested in a specific taxa or group of samples, you could change the code here to create new phyloseq objects.

Part III: Community Composition & Diversity

In the second part, we assess taxonomic composition as well as alpha and beta diversity. Phyloseq offers many options for assessing diversity, including several alpha diversity metrics, additional ordination and distance methods, and so on. You can play around with these settings to how it affects the results.

Part IV: Differentially Abundant ASVs

We wanted to understand how ASVs partitioned across host species. We also wanted to assess the specificity of each ASV to determine habitat preference. To our knowledge there is no quantitative way to do this. The only attempt we are aware of was MetaMetaDB but it is based on a 454 database and no longer seems to be in active development. So we used an approach based on the work of Sullam et. al., first identifying differentially abundant ASVs, then searching for closest database hits, and finally using phylogenetic analysis and top hit metadata (isolation source, natural host) to infer habitat preference.

Part V: Synthesis

In this section we pull together the results from Part III and try to make sense of the microbiomes from these herbivorous reef fish. How are ASVs partitioning across host? How similar are these ASVs to sequences from other studies? What can these patterns tell us about host specificity?

All tables and figures presented below are named as they appeared in the original publication. We also include many additional data productes that were not part of the original publication.


Color & graphics

Throughout this workflow we are going to rely on color to help us tell our story. We will use color to delineate host fish species, but more importantly, to delineate microbial taxa. Microbial diversity is pretty vast and it can be difficult to display all of this diversity in a single, static figure. Additionally, many of us have a decreased ability to see color or differences in color. So it is not only important to use relatively few colors but also a color blind friendly palette. For our figures, we generated a palettes based on Bang Wong’s scheme described in this paper. Wong’s color scheme uses contrasting colors that can be distinguished by folks with color vision deficiency—roughly 8% of people (mostly males) are color blind. Do want Keanu Reeves to understand your figures or not?

This scheme is conservative—there are only 7 colors. We added black and grey to give us a little wiggle room. Others have developed 12 and 15 color palette schemes, but be careful—figures with too many colors can inhibit our ability to discern patterns. Our conservative palette forces us to choose carefully when deciding which taxa to target or how many groups to display. Here we will create two palettes—one for microbial taxa with all the colors and another for the five host fish species. The latter is just a subset of the full palette. Here is the code:


Part I: Field Observations

back to top

To characterize the foraging ecology of the different species of herbivorous fishes, we characterized in detail individual bites by each species at three sites in the Florida Keys (Conch, French, Molasses reefs) during the Boreal summers of 2014 and 2016. At each site, we haphazardly selected focal fish over a wide range of sizes and then randomly selected a single bite by each individual to describe (see Supplementary Table 2 for sample sizes). For each bite, we identified the food item(s) targeted as well as characteristics of the substrate (e.g., hard bottom vs. other common substrates such as sponges, gorgonians, etc.) at the precise location of the bite. For hard substrates, we recorded whether a bite was on a convex, concave, or flat surface, and whether that surface was oriented horizontally (< 45 degrees) or vertically (> 45 degrees). In addition, we framed each bite within a 5 x 5 cm micro-quadrat and measured the depth of the sediment and height of the algae at several points to determine the average sediment depth and algal height within the vicinity of the bite. We then manually removed sediments and determined whether the fish left a distinct grazing scar (i.e., where calcium carbonate had been removed from the reef framework in addition to epilithic algae).

To visualize the multivariate patterns of herbivory we used non-metric multidimensional scaling (NMDS) as implemented via the metaMDS function in the vegan package. For each species of herbivorous fish at each site we calculated the proportion of bites focused on each prey item (‘prey variables’) as well as the proportion of bites targeting substrates with different characteristics (e.g., convex vs. concave vs. flat). We also calculated the proportion of bites resulting in a grazing scar. For bites on turf assemblages, we calculated the mean turf height and sediment depth directly adjacent to each bite. Prior to analysis, quantitative variables (e.g., sediment depth and turf height) were rescaled to the range of 0 to 1. In addition, quantitative and categorical variables were rescaled such that they would have similar influence to the ‘prey variables’ by dividing each variable by the number of prey categories. Rescaled data were then analysed via NMDS using a Bray-Curtis dissimilarity matrix.

Observational data

First, we read in and display the table describing the foraging ecology of these fish.

Supplementary Table 1

Note Table scrolls horizontally.

Data scaling & NMDS analysis

Next we conduct the NMDS analysis of the feeding data using standardize the variables so that they have similar weights. Our process is as follows: a) rescale quantitative traits to be in the range 0 to 1 and divide by the number of diet categories to have similar influence as the diet variables; b) rescale all ‘non diet’ traits to have similar influence to the diet traits by dividing by the number of diet categories divided by the number of categories for each substrate characteristic; c) combine these data into a single data frame for NMDS analysis; d) run NMDS analysis

Then we convert the NMDS data into a dataframe and inspect the Sheppard plot.

Finally, we generate the environmental vectors (correlations of variables with ordination axes).

Now we can plot the results and generate Figure 1 from the manuscript. For all figures generated in this workflow, we coded as much formatting as we could with R and then made minor stylistic changes in Inskscape. Thus, what you see here and throughout, are the raw figures.

Part II: Data Preparation

back to top

Define groupings

0k, on to the microbial data. First, we load the data packet produced by the final step of the DADA2 workflow (Combine_Runs.Rmd), format sample names, and define groupings. We will use the sample names to define the different groups.

Groups

  • 53 individuals
  • 3 genera
  • 7 species

And finally we define a sample data frame that holds the different groups we extracted from the sample names. On the right are a few samples and their different groups names.

SamName Gen Sp
AcCoe01 Ac AcCoe
AcTra05 Ac AcTra
ScTae03 Sc ScTae
SpAur02 Sp SpAur
SpVir07 Sp SpVir

Abbreviations:

  • AcCoe = Acanthurus coeuleus
  • AcTra = Acanthurus tractus
  • ScTae = Scarus taeniopterus
  • SpAur = Sparisoma aurofrenatum
  • SpVir = Sparisoma viride
  • ScVet = Scarus vetula
  • SpChr = Sparisoma chrysopterum

Create & modify a phyloseq object

Next we create a phyloseq (ps) object with the Silva (slv) taxonomy. There is also a Greengenes (gg) annotation in the output file from DADA2 which can be used instead of the Silva annotation. Just change tax_silva to tax_gg. At this point we rename the amplicon sequence variants (ASVs) so the designations are a bit more user friendly. By default, DADA2 names each ASV by its unique sequence so that data can be directly compared across studies (which is great). But this convention can get cumbersome downstream, so we rename the ASVs using a simpler convention—ASV1, ASV2, ASV3, and so on, while retaining the exact sequences.

The phyloseq object looks like this:

## phyloseq-class experiment-level object
## otu_table()   OTU Table:         [ 12479 taxa and 53 samples ]
## sample_data() Sample Data:       [ 53 samples by 3 sample variables ]
## tax_table()   Taxonomy Table:    [ 12479 taxa by 8 taxonomic ranks ]

While the ASV names look like this: ASV1, ASV2, ASV3, ASV4, ASV5, ASV6 and so on…

At this point we have a completely unadulterated phyloseq object because it contains all ASVs and all samples. We add two final columns with the actual ASV sequences and ASV IDs. This will be useful later when trying to export a fasta file. Finally, we export the sequence and taxonomy tables, for posterity sake.

Remember three of these samples were omitted because we did not have replicates for the host species. Lets remove those samples. The only way we could figure out how to do this was by selecting the samples we wanted to keep. If you want to change the group of samples, modify the script accordingly.

## phyloseq-class experiment-level object
## otu_table()   OTU Table:         [ 12479 taxa and 50 samples ]
## sample_data() Sample Data:       [ 50 samples by 3 sample variables ]
## tax_table()   Taxonomy Table:    [ 12479 taxa by 8 taxonomic ranks ]

0K, three samples gone. But we probably lost some ASVs when use we removed samples. So we need to get rid of any ASVs that have now a total of 0 reads. This will be our working phyloseq object.

## phyloseq-class experiment-level object
## otu_table()   OTU Table:         [ 12040 taxa and 50 samples ]
## sample_data() Sample Data:       [ 50 samples by 3 sample variables ]
## tax_table()   Taxonomy Table:    [ 12040 taxa by 8 taxonomic ranks ]

Great, there were 439 ASVs found only in those three samples.

We can also export seq and tax tables for our trimmed dataset and get a quick summary of the trimmed dataset before removing unwanted reads. .

Looks like the total number of reads in the dataset (after removing unwanted samples) is 3120211; range of 12178 to 182696 reads per sample and an average of 62404 reads per sample.

Remove contaminants

These samples are intestinal communities and we assume that Chloroplast are not contributing to metabolism. These data could be useful later but for now lets create a phyloseq object without Chloroplast.

WARNING: the subset_taxa command removes anything that is NA for the specified taxonomic level or above. For example, lets say you run the subset_taxa command using Order != "Chloroplast". Seems like you should get a phyloseq object with everything except Chloroplast. But actually the command not only gets rid Chloroplast but everything else that has NA for Order and above. In our experience this is not well documented and we had to dig through the files to figure out what was happening.

Our dataset has 590 Chloroplast ASVs and running the command as is removed an additional 1244 ASVs. So lets see if we can get rid of just Chloroplast ASVs without removing everything that is unclassified at Order and above. To do this, we subset the taxa to generate a ps object of just Chloroplast, selected the ASV column only, turned it into a factor, and used this to remove Chloroplast from the ps object.

## phyloseq-class experiment-level object
## otu_table()   OTU Table:         [ 11450 taxa and 50 samples ]
## sample_data() Sample Data:       [ 50 samples by 3 sample variables ]
## tax_table()   Taxonomy Table:    [ 11450 taxa by 8 taxonomic ranks ]

This step removed 590 Chloroplast ASVs encompassing 149274 total reads. Perfect.

And now we use the same approach to remove Mitochondria.

## phyloseq-class experiment-level object
## otu_table()   OTU Table:         [ 11144 taxa and 50 samples ]
## sample_data() Sample Data:       [ 50 samples by 3 sample variables ]
## tax_table()   Taxonomy Table:    [ 11144 taxa by 8 taxonomic ranks ]

Sweet, looks like this removed 306 Mitochondria ASVs encompassing 35941 total reads.

After removing contaminants here is what the final dataset looks like:

  • Total number of reads in the dataset is 2934996.
  • Range of 11686 to 180159 reads per sample.
  • Average of 58699 reads per sample.

Phyloseq object merged by species

One last thing to do is to create a merged phyloseq object where samples are grouped by host species. This will come in handy later for some analyses.

## phyloseq-class experiment-level object
## otu_table()   OTU Table:         [ 11144 taxa and 5 samples ]
## sample_data() Sample Data:       [ 5 samples by 3 sample variables ]
## tax_table()   Taxonomy Table:    [ 11144 taxa by 8 taxonomic ranks ]

Great, still the same number of ASVs and now only 5 “samples” corresponding to the 5 species: AcCoe, AcTra, ScTae, SpAur, SpVir.

There are now the several phyloseq objects to chose from and, using the above methods, additional objects can easily be created.

  • ps_slv –> phyloseq dataset with all 53 samples, all ASVs.
  • ps_slv_base –> phyloseq dataset with 50 samples, all ASVs (this is not very useful).
  • ps_slv_work –> phyloseq dataset with 50 samples, zero-read ASVs removed.
  • ps_slv_work_filt –> phyloseq dataset with 50 samples, ASVs and reads from Mitochondria and Chloroplast removed.
  • mergedGP –> ps_slv_work_filt phyloseq dataset collapsed by host species.

Here we can save some phyloseq objects so we can make some Shiny Apps at some point.

Host Information

Before we do anything else, lets generate summary data for each host. We can generate a summary report for any ps object but we will use the object with mitochondria and chlorplasts removed, as well as the low replicate host species removed. We will also add details about each host. The table is displayed below. We can use these data when we upload the original fastq files to sequence read archives. Later on we will also add alpha diversity stats and save the table.


Host details

total_reads <- sample_sums(ps_slv_work_filt)
total_reads <- as.data.frame(total_reads, make.names = TRUE)
total_reads <- total_reads %>% rownames_to_column("host_ID")

total_asvs <- estimate_richness(ps_slv_work_filt, measures = "Observed")
total_asvs <- total_asvs %>% rownames_to_column("host_ID")

sam_details <- sample_data(ps_slv)
sam_details <- sam_details %>% mutate(genus = case_when(
    Gen == "Ac" ~ "Acanthurus", 
    Gen == "Sc" ~ "Scarus",
    Gen == "Sp" ~ "Sparisoma"))

sam_details <- sam_details %>% mutate(species = case_when(
    Sp == "AcCoe"~ "coeruleus",
    Sp == "AcTra"~ "tractus",
    Sp == "ScTae"~ "taeniopterus",
    Sp == "SpAur"~ "aurofrenatum",
    Sp == "SpVir"~ "viride"))
#Sp == "SpChr"~ "chrysopterum",
#Sp == "ScVet"~ "vetula"
sam_details <- sam_details %>% mutate(common_name = case_when(
    Sp == "AcCoe" ~ "blue tang surgeonfish",
    Sp == "AcTra" ~ "fiveband surgeonfish",
    Sp == "ScTae" ~ "princess parrotfish",
    Sp == "SpAur" ~ "redband parrotfish", 
    Sp == "SpVir" ~ "stoplight parrotfish"))

#Sp == "SpChr" ~ "redtail parrotfish",
#Sp == "ScVet" ~ "queen parrotfish"))

sam_details <- sam_details %>% mutate(NCBI_txid = case_when(
    Sp == "AcCoe" ~ "157585",
    Sp == "AcTra" ~ "1316013",
    Sp == "ScTae" ~ "544418",
    Sp == "SpAur" ~ "59663",
    Sp == "SpVir" ~ "59666"))
#Sp == "SpChr" ~ "51766",
#Sp == "ScVet" ~ "84543"))

sam_details <- sam_details[-c(2, 3)]
colnames(sam_details) <- c("host_ID", "host_genus",
                           "host_species", "full_name",
                           "NCBI_txid")

merge_tab <- merge(sam_details, total_reads, by = "host_ID")
merge_tab2 <- merge(merge_tab, total_asvs, by = "host_ID")
colnames(merge_tab2) <- c("host_ID", "host_genus",
                          "host_species", "common_name",
                          "NCBI_txid",  "total_reads",
                          "total_ASVs")

# We also have a datatable containing metrics for each host. Lets bring this in 
# and merge with  the summary table
metrics <- read.table("TABLES/INPUT/host_metrics.txt", 
                      sep = "\t", header = TRUE)
host_details <- merge(merge_tab2, metrics, by = "host_ID")
colnames(host_details) <- c("host_ID", "host_genus", "host_species",
                            "common_name", "NCBI_txid",  "total_reads",
                            "total_ASVs", "collection_date", "phase",
                            "weight", "total_length", "foregut_length",
                            "midgut_length", "hindgut_length",
                            "total_gut_length")

datatable(host_details, rownames = FALSE, width = "100%",
          colnames = c("host_ID", "host_genus", "host_species",
                       "common_name", "NCBI_txid",  "total_reads",
                       "total_ASVs", "Collection_date", "Phase", 
                       "Weight (g)", "Total length (cm)", 
                       "Fore gut length (cm)", "Mid gut length (cm)", 
                       "Hind gut length (cm)", "Total gut length (cm)"), 
          caption = htmltools::tags$caption(style = "caption-side: 
                                            bottom; text-align: left;", 
                                            "Table: ", 
                                            htmltools::em("Sample summary.")), 
          extensions = "Buttons", 
          options = list(columnDefs = 
                           list(list(className = "dt-left", targets = 0)), 
                         dom = "Blfrtip", pageLength = 5, 
                         lengthMenu = c(5, 10, 25, 50), 
                         buttons = c("csv", "copy"), 
                         scrollX = TRUE, scrollCollapse = TRUE))

Now we have a nice little summary table about each sample—genus/species, common name, number of reads, number of ASVs, etc. All of this info can be used when submitting samples to sequence read archives. Once we conduct alpha diversity estimates below, we will add that data to the table above and export as Supplementary Table 3.


Part III: Community Composition & Diversity

back to top

What are the dominant taxa in this system? How diverse are these communities? How similar are samples to each other?

Here we look at a) Taxonomic diversity, b) \(\alpha\)-diversity, and c) \(\beta\)-diversity


Taxonomic composition

Total reads & ASVs by Class

Before we can start to understand a system, we need to know something about its parts. So lets start with a quick look at Class-level diversity. Of course, you can change this to any taxonomic rank you wish. Here we created a sortable table that has the total number of reads and ASVs for each class

# generate the ASV table
tax_asv <- table(tax_table(ps_slv_work_filt)[, "Class"], 
                 exclude = NULL, dnn = "Taxa")
tax_asv <- as.data.frame(tax_asv, make.names = TRUE)

#### change <NA> to Unclassified
# Get levels and add "None"
levels <- levels(tax_asv$Taxa)
levels[length(levels) + 1] <- "Unclassified"
# refactor Taxa to include "Unclassified" as a factor level
# and replace NA with "Unclassified"
tax_asv$Taxa <- factor(tax_asv$Taxa, levels = levels)
tax_asv$Taxa[is.na(tax_asv$Taxa)] <- "Unclassified"

# generate the reads table
tax_reads <- factor(tax_table(ps_slv_work_filt)[, "Class"], exclude = NULL)
tax_reads <- apply(otu_table(ps_slv_work_filt), MARGIN = 1, 
                   function(x) {
                     tapply(x, INDEX = tax_reads, 
                                       FUN = sum, na.rm = FALSE, 
                                       simplify = TRUE)})

#RENAME NA --> Unclassified
rownames(tax_reads)[72] <- "Unclassified"

tax_reads <- as.data.frame(tax_reads, make.names = TRUE)
tax_reads <- cbind(tax_reads, reads = rowSums(tax_reads))
#DELETE all but last column
tax_reads <- tax_reads[51]
tax_reads <- setDT(tax_reads, keep.rownames = TRUE)[]
# merge the two tables and make everything look pretty
# in an interactive table

taxa_read_asv_tab <- merge(tax_reads, tax_asv, by.x = "rn", by.y = "Taxa")
taxa_read_asv_tab <- mutate(taxa_read_asv_tab, 
                            prop_of_ASVs = Freq / sum(Freq), 
                            prop_of_reads = reads / sum(reads))
taxa_read_asv_tab <- taxa_read_asv_tab[c(1, 2, 5, 3, 4)]

names(taxa_read_asv_tab) <- c("Class", "total_reads", "prop_of_reads", 
                              "total_ASVs", "prop_of_ASVs")

taxa_read_asv_tab2 <- taxa_read_asv_tab
taxa_read_asv_tab2$prop_of_reads <- round(taxa_read_asv_tab2$prop_of_reads, 
                                          digits = 6)
taxa_read_asv_tab2$prop_of_ASVs <- round(taxa_read_asv_tab2$prop_of_ASVs, 
                                         digits = 6)

For your information, the dataset has a total of 2934996 reads across 11144 ASVs.

Supplementary Table 4

Looks like Proteobacteria, Firmicutes, Fusobacteria, Planctomycetes, and Bacteroidetes dominate in the read department. Curiously, Fusobacteria has comparatively low ASV richness.


Much of the analyses we do from here on out will be at the Class & Family levels. We chose not to focus on the Genus level because there simply is not enough resolution in our dataset to build a cohesive story. This is because these fish are (microbially) understudied and we are dealing with short read data. On the other hand, Phylum level is too coarse for groups like Proteobacteria and Firmicutes. Order did not provide any additional information and can be cumbersome for taxa with poorly resolved lineages. Depending on the dataset, you may want to change your strategy.

Lets take a closer look Class-level taxonomic content of these communities. There are numerous ways to do this but here we chose to collapse samples by host species and display the relative abundance of the most dominant taxa. We also generated alternative views of taxonomic composition for individual samples—a box-and-whisker plot as well as separate bar plots–that are included as Supplementary Figure 1 (see below for code).

Stacked bar charts are not the best but we like them for a birds eye view of the data. Here we calculate the relative abundance of taxa for each host species at the Class level. It turns out this is not too easy in phyloseq and there is a lot of (messy) code.

Since our goal is to generate a figure and we only have 9 colors, some taxa will need to be put into an Other category. We can define ‘Other’ however we like so lets take a look at the overall relative abundance of each Class.


Taxonomic composition: Class-level relative abundance

Inspecting the table it looks like if we choose a cutoff of 2% (0.02) we get 9 taxa—sounds pretty good. The rest go into the ‘Other’ category. No matter what, we will always gloss over some groups using such a coarse approach. But as we will see later, some of these low abundance groups will reappear when we look at the level of individual ASVs.

Here we define the Other category by combining all taxa with less than 2% of total reads.

At a 2% abundance cutoff, 63 Classes are grouped into the ‘Other’ category. Next we will melt all these classes into the Other category and then craft the bar chart. It took some tweaking to get the bar chart to look just right—so there is a lot of code here—and it could most certainly be better. While we’re at it, we will also save a copy of the figure so we can tweak it later and make it look pretty.


Taxonomic composition: Class abundance across host species

\(\alpha\)-diversity

\(\alpha\)-diversity statistical tests

Alpha diversity describes the diversity in a sample or site. There are several alpha diversity metrics available in phyloseq: Observed, Chao1, ACE, Shannon, Simpson, InvSimpson, Fisher. Play around to see how different metrics change or confirm these results.

Here we want to know if diversity is significantly different across host species. In order to do that we need to know if we should run a parametric or non-parametric test, and for that we need to know if our data is normally distributed. Most of the ideas/code for alpha (and subsequent beta) diversity statistics come from this workshop tutorial by Kim Dill-McFarland and Madison Cox.

First we run the diversity estimates, add these data to our summary table, and save a copy of this table.

Supplementary Table 3

diversity <- estimate_richness(ps_slv_work_filt, 
                               measures = c("Observed", "Chao1", "ACE", 
                                          "Shannon", "Simpson", "InvSimpson", 
                                          "Fisher"))

diversity_calc <- diversity %>% rownames_to_column("host_ID")
# round values
diversity_calc[c(3, 5, 10)] <- round(diversity_calc[c(3, 5, 10)], 1)
diversity_calc[c(4, 6, 7, 9)] <- round(diversity_calc[c(4, 6, 7, 9)], 2)
diversity_calc[8] <- round(diversity_calc[8], 3)

host_summary <- merge(host_details, diversity_calc)
host_summary$Observed <- NULL
host_summary <- host_summary[c(1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13,
                               14, 15, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23)]

write.table(host_summary, "TABLES/OUTPUT/SUPP/Table_S3.txt", 
            sep = "\t", row.names = FALSE, quote = FALSE, 
            col.names = c("Sample ID", "Host genus", "Host species", 
                          "Common name", "NCBI tAxID", "Collection date", 
                          "Life phase", "Weight (g)", "Total length (cm)", 
                          "Foregut length (cm)", "Midgut length (cm)", 
                          "Hindgut length (cm)", "Total gut length (cm)", 
                          "Total reads", "Total ASVs", "Chao1", "Chao1 (se)", 
                          "ACE", "ACE (se)", "Shannon", "Simpson", 
                          "InvSimpson", "Fisher"))

datatable(host_summary, rownames = FALSE, width = "100%", 
          colnames = c("Sample ID", "Host genus", "Host species", 
                       "Common name", "NCBI tAxID", "Collection date", 
                       "Life phase", "Weight (g)", "Total length (cm)", 
                       "Foregut length (cm)", "Midgut length (cm)", 
                       "Hindgut length (cm)", "Total gut length (cm)", 
                       "Total reads", "Total ASVs", "Chao1", "Chao1 (se)", 
                       "ACE", "ACE (se)", "Shannon", "Simpson", "InvSimpson", 
                       "Fisher"), 
            caption = 
            htmltools::tags$caption(style = 
                                      "caption-side: bottom; text-align: 
                                    left;", "Table: ", 
                                    htmltools::em("Host-associated metadata & 
                                                  microbial diversity")), 
          extensions = "Buttons", options = 
            list(columnDefs = list(list(className = "dt-left", targets = 0)), 
                 dom = "Blfrtip", pageLength = 5, lengthMenu = c(5, 10, 50), 
                 buttons = c("csv", "copy"), scrollX = TRUE, 
                 scrollCollapse = TRUE))

Next, we add the diversity estimates to our phyloseq object, and test if the data are normally distributed using Shapiro-Wilk Normality test. We will focus on the inverse Simpson and Shannon diversity estimates and Chao’s richness estimate but this approach can be used for any metric.

Shapiro-Wilk Normality Test for Shannon index.

## 
##  Shapiro-Wilk normality test
## 
## data:  sample_data(ps_slv_work_filt_div)$Shannon
## W = 0.98228, p-value = 0.6513

Shapiro-Wilk Normality Test for inverse Simpson index.

## 
##  Shapiro-Wilk normality test
## 
## data:  sample_data(ps_slv_work_filt_div)$InvSimpson
## W = 0.60454, p-value = 0.0000000002276

Shapiro-Wilk Normality Test for Chao1 richness estimator.

## 
##  Shapiro-Wilk normality test
## 
## data:  sample_data(ps_slv_work_filt_div)$Chao1
## W = 0.89305, p-value = 0.0002855

Shapiro-Wilk Normality Test for Observed ASV richness estimator.

## 
##  Shapiro-Wilk normality test
## 
## data:  sample_data(ps_slv_work_filt_div)$Observed
## W = 0.89591, p-value = 0.0003531

Ok, since the p-values are significant for the inverse Simpson, Chao richness, and Observed ASV richness we reject the null hypothesis that these data are normally distributed. However, the Shannon estimates appear normally distributed. So lets see if diversity is significantly different between host species based on the Shannon index.

Normally distributed metrics

Since the Shannon data is normally distributed we can test for significance using ANOVA (a parametric test).

##             Df Sum Sq Mean Sq F value  Pr(>F)   
## Sp           4  19.13   4.782   3.906 0.00833 **
## Residuals   45  55.10   1.224                   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Ok, the results of the ANOVA are significant. Here we use the Tukey’s HSD (honestly significant difference) post-hoc test to determine which pairwise comparisons are different.

##   Tukey multiple comparisons of means
##     95% family-wise confidence level
## 
## Fit: aov(formula = Shannon ~ Sp, data = sampledataDF)
## 
## $Sp
##                   diff         lwr         upr     p adj
## AcTra-AcCoe  0.7421379 -0.78560423  2.26987998 0.6431490
## ScTae-AcCoe  0.4727303 -1.05501185  2.00047236 0.9030495
## SpAur-AcCoe -0.9230990 -2.33591246  0.48971439 0.3551484
## SpVir-AcCoe  0.3323910 -1.12853187  1.79331396 0.9664219
## ScTae-AcTra -0.2694076 -1.75153517  1.21271993 0.9852679
## SpAur-AcTra -1.6652369 -3.02859596 -0.30187785 0.0096995
## SpVir-AcTra -0.4097468 -1.82289999  1.00340634 0.9218562
## SpAur-ScTae -1.3958293 -2.75918834 -0.03247023 0.0424253
## SpVir-ScTae -0.1403392 -1.55349237  1.27281396 0.9985589
## SpVir-SpAur  1.2554901 -0.03255018  2.54353034 0.0593081

Looks like Sparisoma aurofrenatum is significantly different from Scarus taeniopterus and Acanthurus tractus.

Non-normally distributed metrics

Now we can look at the results on the inverse Simpson diversity and Chao’s richness. Since host species is categorical, we use Kruskal-Wallis (non-parametric equivalent of ANOVA) to test for significance.


Kruskal-Wallis of inverse Simpson index.

## 
##  Kruskal-Wallis rank sum test
## 
## data:  InvSimpson by Sp
## Kruskal-Wallis chi-squared = 13.779, df = 4, p-value = 0.008034

Kruskal-Wallis of Chao1 richness estimator.

## 
##  Kruskal-Wallis rank sum test
## 
## data:  Chao1 by Sp
## Kruskal-Wallis chi-squared = 13.992, df = 4, p-value = 0.007321

Kruskal-Wallis of Observed ASV richness index.

## 
##  Kruskal-Wallis rank sum test
## 
## data:  Observed by Sp
## Kruskal-Wallis chi-squared = 14.153, df = 4, p-value = 0.006822

For the inverse Simpson, Chao1, and Observed richness the results of the Kruskal-Wallis rank sum test are significant. So we can look at pairwise comparisons using Wilcoxon rank sum test for post-hoc analysis.

Pairwise significance test for inverse Simpson index.

## 
##  Pairwise comparisons using Wilcoxon rank sum test 
## 
## data:  sampledataDF$InvSimpson and sampledataDF$Sp 
## 
##       AcCoe AcTra ScTae SpAur
## AcTra 0.545 -     -     -    
## ScTae 0.963 0.545 -     -    
## SpAur 0.042 0.042 0.108 -    
## SpVir 0.545 0.789 0.545 0.004
## 
## P value adjustment method: fdr

Pairwise significance test for Chao1 richness estimator.

## 
##  Pairwise comparisons using Wilcoxon rank sum test 
## 
## data:  sampledataDF$Chao1 and sampledataDF$Sp 
## 
##       AcCoe AcTra ScTae SpAur
## AcTra 0.628 -     -     -    
## ScTae 0.617 0.666 -     -    
## SpAur 0.030 0.030 0.019 -    
## SpVir 0.666 0.628 0.304 0.046
## 
## P value adjustment method: fdr

Pairwise significance test for Observed ASV richness index.

## 
##  Pairwise comparisons using Wilcoxon rank sum test 
## 
## data:  sampledataDF$Observed and sampledataDF$Sp 
## 
##       AcCoe AcTra ScTae SpAur
## AcTra 0.677 -     -     -    
## ScTae 0.677 0.730 -     -    
## SpAur 0.026 0.026 0.019 -    
## SpVir 0.730 0.677 0.304 0.039
## 
## P value adjustment method: fdr

Again we see that only Sp. aurofrenatum is significantly different from the other hosts. For the inverse Simpson index, Sp. aurofrenatum is significantly different from three of the four host species and Chao1 richness estimator, Sp. aurofrenatum is significantly different from all other host species. Now we can plot the results.


\(\alpha\)-diversity plots

Here we plot the results of Shannon diversity index. We will save a copy of the figure for later tweaking. We use the color palette described above to delineate host species.

Correlations with \(\alpha\)-diversity

Next we wanted to know if any alpha-diversity metrics were correlated with host physical characteristics. At the time of collection, we recorded host weight, total length, total gut length, as well as the length of individual gut segments (fore, mid, hind).

When considering the dataset as a whole (i.e., all samples), we found no correlation between any physical characteristics and any diversity metrics. If we split samples by genera we found that neither Acanthurus nor Scarus were not significant for any parameters while Sparisoma showed significant results for all parameters except hindgut_length.

dt <- read.table("TABLES/OUTPUT/SUPP/Table_S3.txt", 
                 sep = "\t", header = TRUE)
library(ggpubr)
scarus <- host_summary[host_summary$host_genus %in% "Scarus", ]
sparisoma <- host_summary[host_summary$host_genus %in% "Sparisoma", ]
acanthurus <- host_summary[host_summary$host_genus %in% "Acanthurus", ]
alphametric <- c("total_ASVs", "Chao1", "ACE", "Shannon", 
                "Simpson",  "InvSimpson", "Fisher")
physical_char <- c("weight", "total_length", "foregut_length", 
                   "midgut_length", "hindgut_length", "total_gut_length")

# Full set: not significant -> "weight", "total_length"
            #"foregut_length", R = 0.32
            #"midgut_length", R = 0.50
            #"hindgut_length", R = 0.17-0.34
            #"total_gut_length" R = 0.50

#By genus and midgut_length :
          # scarus NS
          # sparisoma R = 0.8
          # acanthurus NS

# acanthurus not significant for any parameters
# scarus not significant for any parameters
# sparisoma  significant for all parameters except hindgut_length was a bit weak
# "weight", "total_length" "foregut_length" "midgut_length" 
# "hindgut_length" "total_gut_length"

# To do all diversity metric  change "y = " to y = alphametric and
# ylab = alphametric

par(mfrow = c(2, 3))
shan_by_length <- ggscatter(host_summary, x = "total_gut_length", 
                            y = "Shannon", add = "reg.line", 
                            conf.int = FALSE,cor.coef = TRUE, 
                            cor.method = "spearman",
                            xlab = "total_length (cm)", ylab = "Shannon", 
                            color = "host_genus", palette = samp_pal,
                            legend = "bottom")

shan_by_weight <- ggscatter(host_summary, x = "weight", y = "Shannon", 
          add = "reg.line", conf.int = FALSE, 
          cor.coef = TRUE, cor.method = "spearman",
          xlab = "weight (g)", ylab = "Shannon", 
          color = "host_genus", palette = samp_pal, legend = "top")

grid.arrange(shan_by_length, shan_by_weight, ncol = 2)

\(\beta\)-diversity

\(\beta\)-diversity plots

Beta diversity basically tells us how similar or dissimilar samples are to one another. Phyloseq offers several ordination methods and distance metrics. Here we use non metric multidimensional scaling (NMDS) coupled with Jensen–Shannon divergence. We also save a copy of the figure for later tweaking. To see the full output of the NMDS analysis, remove the results = 'hide' tag from the code chunk.

## 
## Call:
## metaMDS(comm = ps.dist) 
## 
## global Multidimensional Scaling using monoMDS
## 
## Data:     ps.dist 
## Distance: user supplied 
## 
## Dimensions: 2 
## Stress:     0.1646318 
## Stress type 1, weak ties
## Two convergent solutions found after 20 tries
## Scaling: centring, PC rotation 
## Species: scores missing

We see that a convergent solution was reached around 20 iterations and our stress is below 0.20, meaning that 2-axes are sufficient to view the data. Generally, we are looking for stress values below 0.2. If the stress values are high, you may need to add more axes to the ordination. Lets visualize the plot.

\(\beta\)-diversity statistical tests

To test whether microbial communities differ by host species we can use permutational analysis of variance (PERMANOVA) or analysis of similarity (ANOSIM). PERMANOVA does not assume normality but does assume equal beta dispersion between groups. We will test beta dispersion below.

First we use the adonis function in vegan to run a PERMANOVA test. This will tell us whether host species have similar centroids or not.

## 
## Call:
## adonis(formula = fish.jsd ~ Sp, data = sampledf, permutations = 1000) 
## 
## Permutation: free
## Number of permutations: 1000
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2   Pr(>F)    
## Sp         4    4.4045 1.10113   16.52 0.59489 0.000999 ***
## Residuals 45    2.9995 0.06665         0.40511             
## Total     49    7.4040                 1.00000             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

These results indicate that centroids are significantly different across host species meaning that communities are different by host species.

We can also use the pairwiseAdonis package for pair-wise PERMANOVA analysis.

Here we see again we see that communities are different by host species.

However, PERMANOVA assumes equal beta dispersion so we will use the betadisper function from the vegan package to calculate beta dispersion values.

## 
##  Homogeneity of multivariate dispersions
## 
## Call: betadisper(d = fish.jsd, group = sampledf$Sp, bias.adjust =
## TRUE)
## 
## No. of Positive Eigenvalues: 34
## No. of Negative Eigenvalues: 15
## 
## Average distance to median:
##  AcCoe  AcTra  ScTae  SpAur  SpVir 
## 0.2980 0.3098 0.1845 0.1816 0.2570 
## 
## Eigenvalues for PCoA axes:
## (Showing 8 of 49 eigenvalues)
##  PCoA1  PCoA2  PCoA3  PCoA4  PCoA5  PCoA6  PCoA7  PCoA8 
## 1.8547 1.5977 0.9602 0.7234 0.5659 0.3413 0.2609 0.2427

And then a pair-wise Permutation test for homogeneity of multivariate dispersions using permutest (again from the vegan package).

## 
## Permutation test for homogeneity of multivariate dispersions
## Permutation: free
## Number of permutations: 1000
## 
## Response: Distances
##           Df  Sum Sq  Mean Sq      F N.Perm   Pr(>F)   
## Groups     4 0.14600 0.036500 4.1891   1000 0.007992 **
## Residuals 45 0.39209 0.008713                          
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Pairwise comparisons:
## (Observed p-value below diagonal, permuted p-value above diagonal)
##           AcCoe     AcTra     ScTae     SpAur  SpVir
## AcCoe           0.8051948 0.0029970 0.0119880 0.2797
## AcTra 0.8147277           0.0159840 0.0139860 0.2557
## ScTae 0.0040024 0.0160930           0.9440559 0.0420
## SpAur 0.0125449 0.0160815 0.9425028           0.0699
## SpVir 0.2735320 0.2661694 0.0479863 0.0669727

These results are significant, meaning that host species have different dispersions. Looking at the pairwise p-values and permuted p-value, we see that the significant differences (p-value < 0.05) are between:

  • SpAur & AcCoe, AcTra
  • ScTae & AcCoe, AcTra, SpVir

This means we are less confident that the PERMANOVA result is a real result, and that the result is possibly due to differences in group dispersions.

We can also use Analysis of Similarity (ANOSIM)—which does not assume equal group variances—to test whether overall microbial communities differ by host species.

## 
## Call:
## anosim(x = distance(ps_slv_work_filt, "jsd"), grouping = spgroup) 
## Dissimilarity: 
## 
## ANOSIM statistic R: 0.8544 
##       Significance: 0.001 
## 
## Permutation: free
## Number of permutations: 999
## 
## Upper quantiles of permutations (null model):
##    90%    95%  97.5%    99% 
## 0.0556 0.0758 0.0873 0.1111 
## 
## Dissimilarity ranks between and within classes:
##         0%    25%   50%    75% 100%   N
## Between 94 462.50 726.5 977.25 1225 992
## AcCoe   36 185.50 290.5 360.00  582  28
## AcTra   14 162.25 322.0 510.50  789  36
## ScTae    9  34.75  74.5 122.00  419  36
## SpAur    1  30.50  76.0 137.50  562  78
## SpVir   13  95.00 177.0 273.00  584  55

And the AN0SIM result is significant meaning that host species influences microbial community composition.


Part IV: Differentially Abundant ASVs

back to top

At this point we have a good handle on the diversity of the intestinal microbiomes of these herbivorous reef fish. We know that communities are dominated by the same broad-level taxonomic groups. The beta diversity analysis demonstrates that communities partition along host species. Now we want to determine which ASVs are driving these patterns and assess their distribution in nature using publicly available data. To accomplish this task we leave the R environment and employ some additional tools. To summarize, our goals here are to:

  1. identify differentially abundant (DA) ASVs across host species,
  2. find closest database matches to DA ASVs, and
  3. perform phylogenetic reconstruction on DA ASVs and top hits.

Differential abundance (DA)

We used LDA Effect Size (LEfSe) to identify differentially abundant (DA) ASVs across host species and the MicrobiomeAnalyst webserver to run the analysis. There are also many other great tools on the MicrobiomeAnalyst webserver by the way. We needed three files for the input—an ‘OTU’ table, a metadata file containing sample information, and a taxonomy table. We generate these tables with the code below.

And once we have the three files, we head over to the MicrobiomeAnalyst webserver and upload the files. Be sure to select Silva taxonomy in the drop-down menu.
Check the data summary after uploading the files:

  • OTU annotation: SILVA
  • OTU number: 11144
  • OTU with ≥ 2 counts: 4121
  • Sample number: 50
  • Number of experimental factors: 2
  • Total read counts: 2828112
  • Average counts per sample: 56562
  • Maximum counts per sample: 175116
  • Minimum counts per sample: 11568

Cool, all looks good. Hit Proceed. Here are the settings we used for the different step:

  • Filter the data: Minimum count = 20, Prevalence in samples (%) = 20, and Percentage to remove (%) = 0. This removed 3796 low abundant ASVs.
  • Data Normalization: Data rarefying = Do not rarefy my data,
    Data scaling = Total sum scaling (TSS), and
    Data transformation = Do not transform my data.
  • LEfSe analysis Log LDA score = 4 & Adjusted p-value cutoff = 0.0001. We specifically chose these values because we found that they eliminated spurious results such as DA ASVs that were really abundant in a few samples but not consistent across an entire group.

The result was 59 differentially abundant (DA) ASVs.


Results of LEfSe analysis

We can inspect and save the results of the LEfSe analysis. The table shows the Linear discriminant analysis (LDA) scores, P-values adjusted for multiple testing, and False Discovery Rate (FDR) values from the LEfSe analysis. Normalized read abundance values for each host species are also given.

Supplementary Table 5


Core microbiome

Before getting knee deep in the DA ASV analysis lets see if we can’t identify some core elements, or ASVs, to these fish. First we need a mothur-formatted .shared file. This is the code …

cm <- read.table("TABLES/OUTPUT/OTHER/seq_tab_for_core.txt", 
                 sep = "\t", header = TRUE, row.names = 1)
cm_t <- t(cm) 
cm_df <- as.data.frame(cm_t)
numcols <- ncol(cm_df)
cm_df <- cm_df %>% tibble::rownames_to_column("Group")
cm_df <- cm_df %>% 
  mutate(label = 0.03, numOtus = numcols) %>% 
  select(label, Group, numOtus, everything())

write.table(cm_df, "TABLES/OUTPUT/OTHER/ps_slv_work_filt.txt", 
            quote = FALSE, sep = "\t", row.names = FALSE)

####COMBINE by fish species

cm_Merge <- cm %>% tibble::rownames_to_column("ASV")

cm_Merge <- cm_Merge %>% mutate(AcCoe = 
                                  AcCoe01 + AcCoe02 + AcCoe03 + AcCoe04 + 
                                  AcCoe05 + AcCoe06 + AcCoe07 + AcCoe08)
cm_Merge <- cm_Merge %>% mutate(AcTra = 
                                  AcTra01 + AcTra02 + AcTra03 + AcTra04 + 
                                  AcTra05 + AcTra06 + AcTra07 + AcTra08 + 
                                  AcTra09)
cm_Merge <- cm_Merge %>% mutate(ScTra = 
                                  ScTae01 + ScTae02 + ScTae03 + ScTae04 + 
                                  ScTae05 + ScTae06 + ScTae07 + ScTae08 + 
                                  ScTae09)
cm_Merge <- cm_Merge %>% mutate(SpAur = 
                                  SpAur01 + SpAur02 + SpAur03 + SpAur04 + 
                                  SpAur05 + SpAur06 + SpAur07 + SpAur08 + 
                                  SpAur09 + SpAur10 + SpAur11 + SpAur12 + 
                                  SpAur13)
cm_Merge <- cm_Merge %>% mutate(SpVir = 
                                  SpVir01 + SpVir02 + SpVir03 + SpVir04 + 
                                  SpVir05 + SpVir06 + SpVir07 + SpVir08 + 
                                  SpVir09 + SpVir10 + SpVir11)

cm_Merge <- cm_Merge %>% select(ASV, AcCoe, AcTra, ScTra, SpAur, SpVir)
cm_Merge_2 <- cm_Merge[, -1]
rownames(cm_Merge_2) <- cm_Merge[, 1]

cm_Merge_2_t <- t(cm_Merge_2)
cm_Merge_2_df <- as.data.frame(cm_Merge_2_t)

cm_Merge_2_df <- cm_Merge_2_df %>% 
  tibble::rownames_to_column("Group")
cm_Merge_2_df <- cm_Merge_2_df %>% 
  mutate(label = 0.03, numOtus = numcols) %>% 
  select(label, Group, numOtus, everything())
write.table(cm_Merge_2_df, "TABLES/OUTPUT/OTHER/ps_slv_work_filt_combine.txt", 
            quote = FALSE, sep = "\t", row.names = FALSE)

Next we use the output to run get.coremicrobiome in mothur.

Searching public databases

Next we wanted to know where else these ASVs had been detected in nature. There is a huge wealth of publicly available sequence information from many studies and habitats. We can use this information to get a better idea of the distribution and habitat specificity of the DA ASVs. To accomplish this we performed the following steps:

  1. First we needed a phyloseq object that only contained the DA ASVs. To do this, we passed an object consisting of just these 59 ASVs (from the LEfSe analysis) to the phyloseq function prune_taxa. We needed two different ps objects, one from the unmerged object (ps_slv_work_filt) and the other from the merged-by-genus object (mergedGP).

  2. Next we needed a fasta file of our DA ASVs. We could not find an easy way to export a fasta file from the new ps objects. So we tried this using the tax_table. This approach works but, well, it is not very elegant. If you want a fasta file from any other ps objects just swipe out the name of the ps object in the code below. Anyway, we will generate and save a fasta file.

Please note that on the mac we used to analyze the data, for some reason, saves the fasta file with Line Break Type as Legacy Mac(CR). This may be incompatible with other programs and needs to be changed to UNIX (LS). I know, don’t quit my day job, except this is my day job :/
  1. With our newly created DA ASV fasta file we can move on to database searching. We used BLASTn against the nr database to search publicly available sequence data. We used these settings:
    • optimized for highly similar sequences (megablast)
    • Expect threshold = 10
    • Word size = 28
    • Match/Mismatch Scores = 1, -2
    • Gap Costs = linear.
    • retain top 10 hits

Here are the top BLAST hits for each DA ASV. The table displays a lot of information about each BLAST search (it scrolls along the x-axis by the way). Most importantly are the accession numbers of top BLAST hits (subject acc.var), number of 100% identical matches (num perfect hits), the percent identity, and some info on where/when the hit sequence was originally found. Where applicable, there is also PubMedIDs so you can find the paper that reported the sequence. Looking at this table will give you a preliminary sense of the ecology of these ASVs. For example, most hits come from intestinal communities, many of which are marine herbivorous fish. But the low percent identity of several ASVs indicates that these sequences have been poorly sampled. This is not surprising given the geographic skew of sampling.


Top hits from BLASTn analysis

Note This table also scrolls horizontally.


Several ASVs returned more than one match at 100%. For some ASVs, the 100% matches were from the same study/study organism, so we just selected one as the representative. ASVs 6, 12, 224, and 398 returned numerous 100% matches (out of 50 total). These data were impractical to summarize and not very informative anyway. So we elected to leave these data out. If you want to see what these hits are, just grab the ASV sequence and BLAST away.

Also, some ASVs shared the same to hit. Since the table is ‘by ASV’ we retained all duplicate hits.

  1. For phylogenetic inference we used the Silva Alignment, Classification and Tree Service to obtain neighbors of DA ASVs. We used these settings:
    • Search and classify: min identity = 0.95; Number of neighbors = 5.
    • Default parameters for the remainder of the workflow.
  2. We then combined the results of the BLASTn and Silva ACT analyses and omitted duplicate hits, resulting in 297 top hit sequences for phylogenetic analysis.

Phylogenetic inference

Short read sequences are not ideal for phylogenetic analysis, but given the data we have, we felt this was a good place to start. This analysis required several steps.

  1. We used mothur (v.1.40.4, Last updated: 07/25/2018) and the Silva full length sequences and taxonomy references (release 132) to align the DA ASVs and our new reference db, and also classify the sequences. We used a hard mask to trim all long reads to the same length (~373bp) and 16S region as the ASVs.
mothur "#align.seqs(candidate=sequence_tree.fasta, template=silva.nr_v132.align, processors=20, flip=t)"  
mothur "#filter.seqs(fasta=sequence_tree.fasta, vertical = =F, hard=mask.txt)"  
mothur "#classify.seqs(fasta=sequence_tree.filter.fasta, template=silva.nr_v132.align, taxonomy=silva.nr_v132.tax, processors=10)"  
  1. Now that we had our 59 DA ASVs and the top database hits, its was time for phylogenetic inference. We used RAxML-HPC to generate a phylogenetic tree (with Aquifex as the outgroup)
raxmlHPC-PTHREADS-SSE3 -T 24 -f a -p 2345 -x 3456 -m GTRGAMMA  -N 1000 -s sequence_tree.filter.fasta -n fish_arb_align_1000BS_B.tre

Part V: Synthesis

back to top

Now it was time to put the pieces together and determine…

What these patterns tell us about specificity?

Visualizing the phylogenetic tree

IMNGS analysis

To dig just a little deeper, we screened our DA ASVs against the IMNGS database. IMNGS hosts a curated database of short-read sequences scraped from the International Nucleotide Sequence Database Collaboration (GenBank, DDBJ and EMBL). The database is rebuilt monthly and at the time of this analysis, contained 271,237 samples. IMNG is really designed to screen full-length 16S rRNA sequences and is not ideal for shorter reads. This is because the database is built from short reads, and different studies target different regions of the gene. For example, if we get no hits to an ASV it could mean the organisms it came from has really not been detected before or that it is in the database but is represented by a different 16S region. So take these data with a grain of salt.

IMNGS is not a high-throughput system. User may only submit a maximum of 10 sequences per query and this can (and will) take weeks to run. So choose your ASVs carefully.

IMNGS will return a lot of useful data for each query sequence. All we were interested in here was the number of hits, but there much more really useful data here. Among other data products, IMNGS returns report tables that tally the number of samples that were positive for the presence of query-like sequences for each sample category—categories like shrimp gut metagenome and seawater metagenome. Each category has a number of short-read samples, which could originate from a single study or multiple studies.

A report includes values for several percent identity cutoff values. We set a minimum threshold at 97% so our reports have values for 97 and 99%. You can set the threshold as low as 90%.

IMNGS provides three such reports based on the abundance of your query sequence.

  1. An SRA-derived sample is considered positive if the query-like sequences sum up to more than 0% of the total number of sequences in that sample (i.e. any abundance).

  2. An SRA-derived sample is considered positive if the query-like sequences sum up to more than 0.1% of the total number of sequences in that sample (i.e. excluding rare abundances).

  3. An SRA-derived sample is considered positive if the query-like sequences sum up to more than 1% of the total number of sequences in that sample (i.e. including only dominant OTUs).

We report data from 97% cutoff identity and 0.1% of total reads in a sample. I think this is a little confusing so let me explain by example. In the tree below, ASV398 is most closely related to an Alphaproteobacteria associated with the toxic benthic marine dinoflagellate, Ostreopsis ovata. We retrieved this sequence during the BLASTn analysis discussed above. Anyway, ASV398 was screened against IMNGS and returned 2460 hits. This means that at 97% identity, 2460 samples had an ASV398-like sequence comprising greater than 0.1% of a given samples total number of sequences. If for example we increase the percent identity to 99% the number of sample hits drops to 138. If instead we look at the 0% report (97% identity), the number of sample hits increases to 6323.

Sullam lifestyle categories

We also compared the final list of top hits to the Sullam et. al. paper, specifically Table S1 from that paper. Because this paper was published in 2012, there were many sequence hits in our db that did not appear in the original paper. However, for those that did, we added the Sullam lifestyle category designations to the tree metadata.

Putting the pieces together

We took all of these data and used iTOL to visualize the tree. For each top hit, we added the isolation source/natural host information, taxonomic affiliation, and Sullam lifestyle category. We also overlaid the number of hits to the IMNGS database for each ASV.

To view a full, interactive version of the tree go this iTOL page.


Zoomable iTOL tree

Figure 3


Inferring lifestyle category

We used the tree to infer the lifestyle category of each ASVs based on the closest relatives in their clade. This was not a quantitative, but rather a user guided determination. Aside from MetaMetaDb (discussed above) we are not aware of any tool currently available to quantitatively assess habitat preference of a 16S rRNA sequence.

For simplicity we focused on three lifestyle catagories (though we have seven categories in the tree). Our reasoning—again based on the work of Sullam et. al.—was that fish intestines contain microbes that are generalists and possibly of environmental origin (what they eat, where they live), microbes that are there because fish are animals with guts, and microbes that are there because fish are fish and have a physiology and evolutionary history that select specific organisms. Sullam et.al. were also looking at fish from different habitats (freshwater, estuary, marine) and tropic levels (carnivores, herbivores, omnivores) while our study was more narrow in scope.

  • fish associated: ASVs most closely related to sequences from the intestinal tract of marine fish.
  • animal associated: ASVs most closely related to sequences from other animals, including one freshwater fish, other vertebrates, and a few non-marine invertebrates.
  • generalists: ASVs most closely related to sequences are widespread and possibly from the environment. By and large these are marine or marine-like (e.g., hypersaline mats, saline lakes) in origin including sediments, water, and potential prey (algae, plants, coral, sponge). However there are some leaves in the tree from non-marine environments (e.g., activated sludge) that we grouped in the environmental category.

Assessing habitat specificity.

We combined these habitat predictions with the results of the BLASTn analysis, scan of the IMNGS database, Sullam lifestyle categories, etc. and put it all in one editable table. So if you disagree with a habitat prediction, you can feel free to change it.

Supplementary Table 6

Description of table headings

  • ASV: ASV id.
  • Total Reads: Total reads of ASV.
  • Putative habitat: Our habitat designation based on the analyses.
  • Enriched: Which of the five herbivorous reef fish the ASV was enriched in.
  • Taxon: Taxonomic classification of the ASV.
  • closest db match: Host or environment of top hit.
  • % identity: Percent identity of top hit.
  • subject acc Accession number of top BLAST hit
  • IMNGS hits: Number of hits to the IMNGS database. Value indicates the number of samples that scored a hit to an ASV.
  • Sullam lifestyle: Lifestyle category as defined by Sullam et. al., 2012. NLC indicates no hit to the Sullam db.
  • num perfect hits Number of 100% BLAST matches out of 50 top hits.

Note This table also scrolls horizontally.

habi_tab <- read.table("TABLES/INPUT/habitat_specificity.txt", 
                       header = TRUE, sep = "\t", check.names = FALSE)
# order by habitat and host enriched
habi_tab2 <- habi_tab[order(habi_tab$habitat_code, habi_tab$Enriched), ] 
#habi_tab <- habi_tab[, -2] #delete code column
da_asvs_counts <- as.data.frame(taxa_sums(da_asvs))
colnames(da_asvs_counts) <- c("total_reads")
# make rownames a column
da_asvs_counts <- cbind(ASV = rownames(da_asvs_counts), da_asvs_counts) 
temp_table <- merge(da_asvs_counts, blast_tab, by = "ASV", 
                    all = TRUE, sort = FALSE) 

summ_table <- merge(temp_table, habi_tab2, by = "ASV", 
                    all = TRUE, sort = FALSE, no.dups = TRUE) 

summ_table <- summ_table[-c(22, 26, 27, 28, 29, 31)]
summ_table <- summ_table[c(1, 22, 23, 2, 24, 4, 3, 5, 6, 7, 8, 18, 19, 20,
                           9, 10, 11, 12, 13, 14, 15, 16, 17, 21, 25)]

datatable(summ_table, rownames = FALSE, 
          colnames = c(
            "ASV", "Putative habitat", "Enriched", "Total reads", 
            "Taxon", "Num perfect hits", "Top hit acc", "% identity", 
            "Isolation source", "Nat host", "Common name", "Collection year", 
            "Country", "PubMed ID", "Alignment length", "Mismatches", 
            "Gap opens", "Q. start", "Q. end", "S. start", "S. end", 
            "Evalue", "Bit score", "Num IMNGS hits", "Sullam lifestyle"),
          editable = TRUE, caption = 
            htmltools::tags$caption(
              style = "caption-side: bottom; text-align: left;", 
              "Supplementary Table 6: ", 
              htmltools::em("Assessing habitat specificity.")), 
          extensions = "Buttons", 
          options = list(columnDefs = 
                           list(list(className = "dt-center", 
                                     targets = c(1, 2, 3, 4, 5, 
                                                 6, 7, 8, 9, 10))), 
                         dom = "Blfrtip", pageLength = 5, 
                         lengthMenu = c(5, 10, 25, 60), 
                         buttons = c("csv", "copy"), 
                         scrollX = TRUE, scrollCollapse = TRUE))

NR Indicates Not Recorded. Four ASVs had numerous hits at 100% identity. We did not include top hit data for these ASVs.


Summary of habitat diversity

Now we can summarize the data for each lifestyle category. This table was constructed in a text file and read into R.


Taxa distribution by host

So we know that Host X is enriched for some ASV from taxa Y. Is this part of a larger pattern or an isolated case? For a given taxonomic group and rank, what proportion of total reads (from all ASVs) were found in a particular host species? At some point it would be nice if this were an interactive step, but for now we must modify the code below to look at different taxa. This example will look at the family Desulfovibrionaceae (Deltaproteopbacteria)

Proportion of total reads for a given taxon & rank

## phyloseq-class experiment-level object
## otu_table()   OTU Table:         [ 71 taxa and 5 samples ]
## sample_data() Sample Data:       [ 5 samples by 3 sample variables ]
## tax_table()   Taxonomy Table:    [ 71 taxa by 8 taxonomic ranks ]

Great. Looks like there are 71 Desulfovibrionaceae ASVs and the majority (> 90%) of the reads are from Acanthurus. This is interesting. We can do this with any taxa we wish.

Proportion of total reads for Cyanobacteria

So lets do this to also look at the proportion of Cyanobacteria reads by host species.

## phyloseq-class experiment-level object
## otu_table()   OTU Table:         [ 484 taxa and 5 samples ]
## sample_data() Sample Data:       [ 5 samples by 3 sample variables ]
## tax_table()   Taxonomy Table:    [ 484 taxa by 8 taxonomic ranks ]

There were a total of 484 Cyanobacteria ASVs across 72079 reads.


DA ASV distribution by host

At this point we know which ASVs are enriched in which host species, the lineage of those ASVs, and something about where else these sequences have been detected in nature. Next we would like to know the proportion of total reads for each ASV that is found in each host species. We start with a summary table of these data.

Proportion of total ASV reads per host species

# calculate the averages and merge by species
# grab the da_asv ps object & merge by samples
daASV_mergedGP_BAR <- merge_samples(da_asvs_full, "Sp")
#daASV_SD_BAR <- merge_samples(sample_data(da_asvs_full), "Sp")
# calculate percent proportion
daASV_AVG <- apply(t(otu_table(daASV_mergedGP_BAR)), 1, function(x) x / sum(x)) 
# transpose
daASV_t_AVG <- t(daASV_AVG)
daASV_t_AVG_df <- as.data.frame(daASV_t_AVG)

######################
# choose columns of interest
da_ASV_tax <- habi_tab[c("ASV", "Taxon", "Putative_habitat")] 
da_ASV_tax2 <- da_ASV_tax[, -1]
rownames(da_ASV_tax2) <- da_ASV_tax[, 1]

######################
# combine based on ASV column
daASV_work <- merge(daASV_t_AVG_df, da_ASV_tax2, by = 0, sort = FALSE)

rownames(daASV_work) <- daASV_work[, 1]
daASV_work[, 1] <- NULL
#daASV_work

# then make column row.names
daASV_work2 <- cbind(ASV = rownames(daASV_work), daASV_work)
# melt the df
# wide to long format?
daASV_work3 <- melt(daASV_work2, value.name = "ASV") 
colnames(daASV_work3) <- c("ASV", "Taxon", "Putative_habitat", 
                           "Sample", "Proportion")
daASV_work3$Proportion <- round(daASV_work3$Proportion, digits = 4)

datatable(daASV_work3, 
          rownames = TRUE, editable = FALSE, 
          caption = 
            htmltools::tags$caption(
              style = "caption-side: bottom; text-align: left;", "Table 8: ", 
              htmltools::em("DA ASV sample proportion.")), 
          extensions = "Buttons", 
          options = list(columnDefs = list(list(className = "dt-center", 
                                                targets = c(1, 2, 3, 4, 5))), 
                         dom = "Blfrtip", pageLength = 5, 
                         lengthMenu = c(5, 10, 50, 100, 300), 
                         buttons = c("csv", "copy"), scrollX = TRUE, 
                         scrollCollapse = TRUE))

Now that we have a list of DA ASVs and their assigned habitat preference, we want to create a R object that organizes these in some logical fashion. We can then use this object to order subsequent graphs and tables. So lets order the ASVs by putative habitat preference and then by the host species in which that ASV was enriched. Seems reasonable enough? Depending on the R command, some objects need to be in ascending order, others in descending order.

Lets see if we can overlay all of this information in one “easy” to understand plot. The first thing is to do is plot the proportion of reads for a given ASV from each host species.

Graphical representation of proportion of total ASV reads per host species

Next, we created a bar plot of read proportion by host species for each ASV. And save a copy to the FIGURES/ directory.

Code for proportional bar chart

Code for heatmap

# Heatmap
library(ComplexHeatmap)
library(circlize)
library(heatmap3)
library(gdata)
fig4_heat <- as.data.frame(t(otu_table(da_asvs)))
# Convert habi_table to df and store in new variable
fig4_tax <- as.data.frame(habi_tab2) 
# eliminate 1st column so can combine based on row names
fig4_tax_tab <- fig4_tax[, -1] 
# Make new row.names from original table
rownames(fig4_tax_tab) <- fig4_tax[, 1] 
# Reorder
fig4_tax_tab <- fig4_tax_tab[c(4, 2, 3, 1, 5, 6, 7, 8)] 
# Select columns
fig4_tax_tab <- fig4_tax_tab[c(1:4)] 

# Combine the two df by rowname If the matching involved row names, 
# an extra character column called Row.names 
# is added at the left, and in all cases the result has ‘automatic’ row names.
fig4_heatmap2 <- merge(fig4_tax_tab, fig4_heat, by = 0, all = TRUE) 

fig4_heatmap <- subset(fig4_heatmap2, select = -c(Row.names))
rownames(fig4_heatmap) <- fig4_heatmap2[, "Row.names"]
# make rownames a column
fig4_heatmap <- cbind(ASV = rownames(fig4_heatmap), fig4_heatmap) 

fig4_heatmap$ASV <- factor(fig4_heatmap$ASV, levels = rev(asv_order)) 
fig4_heatmap <- fig4_heatmap[order(fig4_heatmap$ASV), ] 
# combine the columns to make one name
fig4_heatmap$ID <- paste(fig4_heatmap$ASV, fig4_heatmap$Taxon, 
                         fig4_heatmap$Putative_habitat, 
                         fig4_heatmap$Enriched, sep = "_") 
# delete the original columns
fig4_heatmap2 <- fig4_heatmap[-c(1:5)] 
# reorder
fig4_heatmap2 <- fig4_heatmap2[c(6, 1, 2, 3, 4, 5)] 
rownames(fig4_heatmap2) <- fig4_heatmap2[, 1]
fig4_heatmap2 <- fig4_heatmap2[-1]

####Define Colors
taxa_colors <- unlist(lapply(row.names(fig4_heatmap2), function(x) {
  if (grepl
     
     # generalists
               ("Alphaproteobacteria", x)) "#000000"
  else if (grepl("Pirellulaceae", x)) "#000000"
  else if (grepl("Rubritaleaceae", x)) "#000000" 
  else if (grepl("Flavobacteriaceae", x)) "#000000" 
    
   # fish/animal
  else if (grepl("Desulfovibrionaceae", x)) "#0072b2" 
  else if (grepl("Lachnospiraceae", x)) "#f0e442" 
  else if (grepl("Erysipelotrichaceae", x)) "#009e73" 
  else if (grepl("Ruminococcaceae", x)) "#e69f00"
  else if (grepl("Bacteroidales", x)) "#d55e00"
  else if (grepl("Fusobacteriaceae", x)) "#56b4e9"
  else if (grepl("Vibrionaceae", x)) "#cc79a7"
  
  # other
  else if (grepl("Family_XIII", x)) "#808080"
  else if (grepl("Mollicutes", x)) "#808080" 
  else if (grepl("Brevinemataceae", x)) "#808080"
  else if (grepl("Peptostreptococcaceae", x)) "#808080"
}))    

habitat_colors <- unlist(lapply(row.names(fig4_heatmap2), function(x) {
  if (grepl
               ("fish", x)) "#808080"
  else if (grepl("animal", x)) "#000000"
  else if (grepl("generalist", x)) "#808080"
  #else if (grepl("undetermined", x)) "#000000"
}))    
heatColors <- cbind(taxa_colors, habitat_colors)
colnames(heatColors)[1] <- "Taxa"
colnames(heatColors)[2] <- "Habitat"
### SAVE/display heatmap
col <- colorRampPalette(bias = 1, c("#000033", "#66CCFF"))(16)
pdf(file = "FIGURES/OUTPUT/Figure_4B.pdf")
heatmap3(fig4_heatmap2, cexRow = 0.5, cexCol = 1,
         margins = c(3, 13), RowSideColors = heatColors, scale = "row", 
         Colv = NA, Rowv = NA, revC = TRUE, balanceColor = FALSE, col = col)
invisible(dev.off())
heatmap3(fig4_heatmap2, cexRow = 0.5, cexCol = 1, 
         margins = c(3, 13), RowSideColors = heatColors, scale = "row", 
         Colv = NA, Rowv = NA, revC = TRUE, balanceColor = FALSE, col = col)

Combine the two charts.

Either do outside R or figure out a way to ‘bolb’ the heatmap. grid::grid.grab seemed promising.


Association between ASVs, host phylogeny, & foraging behaviour

To test whether intestinal microbes were associated with a) phylogenetic history and/or b) foraging ecology of each herbivore, we used a series of simple and partial Mantel tests. Because we expected the relationships to potentially differ for putative resident symbionts vs. ingested environmental generalist microbes, we constructed separate dissimilarity matrices for host- and environment-associated ASVs. These matrices were constructed using the vegan package in R and were based on Bray-Curtis dissimilarity of Hellinger transformed data. The ecological dissimilarity matrix was based on the behavioural data collected to quantify herbivore trophic niche space. The phylogenetic dissimilarity matrix was based on a phylogenetic tree of the five fish species used in this study. We constructed the tree using cytochrome oxidase subunit 1 (COI) genes retrieved from NCBI’s Nucleotide Database. Clustal Omega was used to align sequences (default settings for DNA). We then used Jalview to manually curate and trim the final alignment to 593 bp. This alignment contained COI genes from n = 5 Scarus taeniopterus, 22 Sparisoma aurofrenatum, 21 Sparisoma viride, 28 Acanthurus coeruleus, and 23 Acanthurus tractus. We used members of the Gerridae (2 Eucinostomus and 4 Gerres) as the outgroup. We used RAxML and the GTR model for tree computation and the GAMMA rate model for likelihoods. The tree was then transformed into a distance matrix using the cophenetic function in R.

Next, we pruned the tree to one member of each species, removed the outgroup, and changed the names to species names.


We then transformed the tree into a distance matrix and generated a dendrogram.


Next we grab the ecological data and standardize the variables so that they have similar weights.

First, rescale quantitative traits to be in the range 0 to 1 and then devide by the number of diet categories to have similar influence as the diet variables. Then rescale all ‘non diet’ traits to have similar influence to the diet traits by dividing by the number of diet categories divided by the number of categories for each substrate characteristic. Now combine into a single data frame for analysis get averages for each species.

And begin with a Hellinger transformation of Ecological traits.

So, is ecological data correlated with phylogeny?

## 
## Mantel statistic based on Pearson's product-moment correlation 
## 
## Call:
## mantel(xdis = traits_dist, ydis = T, method = "pearson", permutations = 9999) 
## 
## Mantel statistic r: 0.4816 
##       Significance: 0.175 
## 
## Upper quantiles of permutations (null model):
##   90%   95% 97.5%   99% 
## 0.593 0.654 0.751 0.817 
## Permutation: free
## Number of permutations: 119

0K, looks like there is no correlation between ecological data and phylogeny. Next, we looked at differentially abundant ASVs split into host-associated vs environmentally associated

So is the distance matrix (based on host associated ASVs) correlated with ecological data or phylogeny?

## 
## Mantel statistic based on Pearson's product-moment correlation 
## 
## Call:
## mantel(xdis = Gut_dist_host, ydis = T, method = "pearson", permutations = 9999) 
## 
## Mantel statistic r: 0.8448 
##       Significance: 0.0083333 
## 
## Upper quantiles of permutations (null model):
##   90%   95% 97.5%   99% 
## 0.556 0.711 0.754 0.820 
## Permutation: free
## Number of permutations: 119

Yes, highly correlated with phylogeny…

## 
## Mantel statistic based on Pearson's product-moment correlation 
## 
## Call:
## mantel(xdis = Gut_dist_host, ydis = traits_dist, method = "pearson",      permutations = 9999) 
## 
## Mantel statistic r: 0.2511 
##       Significance: 0.25833 
## 
## Upper quantiles of permutations (null model):
##   90%   95% 97.5%   99% 
## 0.490 0.585 0.662 0.752 
## Permutation: free
## Number of permutations: 119

…but not associated with ecological traits.

What about the distnace matrix based on environment associated ASVs? Is it correlated with ecological data or phylogeny?

## 
## Mantel statistic based on Pearson's product-moment correlation 
## 
## Call:
## mantel(xdis = Gut_dist_env, ydis = T, method = "pearson", permutations = 9999) 
## 
## Mantel statistic r: 0.8313 
##       Significance: 0.075 
## 
## Upper quantiles of permutations (null model):
##   90%   95% 97.5%   99% 
## 0.455 0.862 0.893 0.931 
## Permutation: free
## Number of permutations: 119

Doesn’t look correlated with phylogeny…

## 
## Mantel statistic based on Pearson's product-moment correlation 
## 
## Call:
## mantel(xdis = Gut_dist_env, ydis = traits_dist, method = "pearson",      permutations = 9999) 
## 
## Mantel statistic r: 0.5963 
##       Significance: 0.083333 
## 
## Upper quantiles of permutations (null model):
##   90%   95% 97.5%   99% 
## 0.531 0.690 0.765 0.788 
## Permutation: free
## Number of permutations: 119

…or ecological data.

We could also do partial Mantel tests.

## 
## Partial Mantel statistic based on Pearson's product-moment correlation 
## 
## Call:
## mantel.partial(xdis = Gut_dist_env, ydis = T, zdis = traits_dist,      method = "pearson", permutations = 9999) 
## 
## Mantel statistic r: 0.7734 
##       Significance: 0.091667 
## 
## Upper quantiles of permutations (null model):
##   90%   95% 97.5%   99% 
## 0.497 0.829 0.871 0.914 
## Permutation: free
## Number of permutations: 119
## 
## Partial Mantel statistic based on Pearson's product-moment correlation 
## 
## Call:
## mantel.partial(xdis = Gut_dist_env, ydis = traits_dist, zdis = T,      method = "pearson", permutations = 9999) 
## 
## Mantel statistic r: 0.4022 
##       Significance: 0.15 
## 
## Upper quantiles of permutations (null model):
##   90%   95% 97.5%   99% 
## 0.516 0.632 0.830 0.839 
## Permutation: free
## Number of permutations: 119

But again, no significance detected…

Appendix A: Other analyses & visualizations

back to top

Here is code for other representation of taxa abundance. These are raw R images that have not been gussied up.

We will create two different representations of relative abundance for each sample (arranged by host species) by major Classes—facet grid box-and-whisker plots and bar charts. We will generate each separately (and save) using an earlier relative abundance phyloseq object and then display the combined output.

Code for box-and-whisker plot.

library(phyloseq)
mdata_phy_all <- tax_glom(ps_slv_filt_AVG, taxrank = "Class", NArm = FALSE)
# You can choose any taxonomic level here
mdata_phyrel_all <- transform_sample_counts(
  mdata_phy_all, function(x) x / sum(x)
  )
meltd_all <- psmelt(mdata_phyrel_all)
meltd_all$Class <- as.character(meltd_all$Class)

means <- ddply(meltd_all, ~Class, function(x) c(mean = mean(x$Abundance)))
# decending order
taxa_means <- means[order(-means$mean), ]  
# ditch the sci notation 
taxa_means <- format(taxa_means, scientific = FALSE)  

# Here we conglomerate at 2%.
Other <- means[means$mean <= 0.026, ]$Class  

meltd_all[meltd_all$Class %in% Other, ]$Class <- "Other"
samp_names <- aggregate(meltd_all$Abundance, 
                        by = list(meltd_all$Sample), FUN = sum)[, 1]
.e <- environment()
meltd_all[, "Class"] <- factor(meltd_all[, "Class"], 
                               sort(unique(meltd_all[, "Class"])))
meltd_all <- meltd_all[order(meltd_all[, "Class"]), ]
levels(meltd_all$Class)

# Here we order Classes by the Phylum they belong to.
meltd_all$Class <- factor(meltd_all$Class, 
                          levels = c(
                            "Bacteroidia", "Clostridia", "Erysipelotrichia", 
                            "Fusobacteriia", "Alphaproteobacteria", 
                            "Deltaproteobacteria", "Gammaproteobacteria", 
                            "Planctomycetacia", "Oxyphotobacteria", "Other"))  

sup_fig1 <- qplot(data = meltd_all, x = Sp, y = Abundance, fill = Class, 
                  geom = "boxplot", ylab = "Relative Abundance") +
  theme(legend.position = "bottom") + 
  facet_grid(Class ~ ., scales = "free_y", space = "free_y") + 
  geom_jitter(width = 0.05) + 
  geom_point(colour = "black", fill = "white")  
#+ guides(guide_legend(reverse = FALSE) )

sup_fig1 <- sup_fig1 + 
  scale_fill_manual(values = friend_pal) + 
  labs(x = "Host species", y = "Relative abundance (% total reads)")

pdf("FIGURES/OUTPUT/box_and_whisker.pdf")
sup_fig1
invisible(dev.off())

Code for bar plot.

Figure S1

Figure S1. Relative abundance of major Classes by sample

Figure S1. Relative abundance of major Classes by sample

return to Figure 2A

Appendix B: Tools & resources used in this workflow

back to top

Specific tools

phyloseq as the primary analytical package.
LEfSe to identify differentially abundant (DA) amplicon sequence variants (ASV) across host fish species.
MicrobiomeAnalyst to conduct LEfSe analysis.
BLASTn and Silva ACT to identify closest hits to DA ASVs.
RAxML for phylogenetic inference of DA ASVs and closest hits.
iTOL for visualization of tree and associated metadata.

Other valuable resources

R Markdown: The Definitive Guide
knitr tutorials. Fantastic site!
Microbiota analysis in R, UCR Workshop 2018 nicely documented workflow with examples.

Appendix C: Submitting sequencing data to public archives

back to top

It is now time to submit the data to your favorite sequence read archive. We submitted out data to the European Nucleotide Archive (ENA). The ENA does not like RAW data and prefers to have primers removed. So we submitted the trimmed Fastq files to the ENA. You can find these data under the study accession number PRJEB28397. The RAW files on our figshare site. TODO INSERT DOI/LINK

To submit to the ENA you need two data tables (plus your sequence data). The first file describes the samples and the second file describes the sequencing data. The original files can be found on the figshare site.

Appendix D: Specific R package & versions

back to top

Below are the specific packages and versions used in this workflow using both sessionInfo() and devtools::session_info().

##      user    system   elapsed 
## -8057.647  -115.817 -3044.500
## R version 3.6.0 (2019-04-26)
## Platform: x86_64-apple-darwin15.6.0 (64-bit)
## Running under: macOS Mojave 10.14.6
## 
## Matrix products: default
## BLAS:   /Library/Frameworks/R.framework/Versions/3.6/Resources/lib/libRblas.0.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/3.6/Resources/lib/libRlapack.dylib
## 
## Random number generation:
##  RNG:     Mersenne-Twister 
##  Normal:  Inversion 
##  Sample:  Rounding 
##  
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## attached base packages:
##  [1] grid      stats4    parallel  stats     graphics  grDevices utils    
##  [8] datasets  methods   base     
## 
## other attached packages:
##  [1] phyloseq_1.28.0             treeio_1.8.2               
##  [3] tidytree_0.2.7              ggtree_1.16.6              
##  [5] picante_1.8                 nlme_3.1-141               
##  [7] ape_5.3                     gdata_2.18.0               
##  [9] heatmap3_1.1.6              circlize_0.4.8             
## [11] ComplexHeatmap_2.1.0        ggpubr_0.2.3               
## [13] magrittr_1.5                ggthemes_4.2.0             
## [15] pairwiseAdonis_0.0.1        cluster_2.1.0              
## [17] plotly_4.9.0                RCurl_1.95-4.12            
## [19] bitops_1.0-6                svgPanZoom_0.3.3           
## [21] gridExtra_2.3               forcats_0.4.0              
## [23] stringr_1.4.0               dplyr_0.8.3                
## [25] purrr_0.3.2                 readr_1.3.1                
## [27] tidyr_0.8.3                 tibble_2.1.3               
## [29] tidyverse_1.2.1             formatR_1.7                
## [31] pander_0.6.3                rmarkdown_1.16             
## [33] DT_0.8                      data.table_1.12.2          
## [35] kableExtra_1.1.0            knitr_1.25                 
## [37] rstudioapi_0.10             reshape2_1.4.3             
## [39] scales_1.0.0                vegan_2.5-6                
## [41] lattice_0.20-38             permute_0.9-5              
## [43] plyr_1.8.4                  ggplot2_3.2.1              
## [45] ShortRead_1.42.0            GenomicAlignments_1.20.1   
## [47] SummarizedExperiment_1.14.1 DelayedArray_0.10.0        
## [49] matrixStats_0.55.0          Biobase_2.44.0             
## [51] Rsamtools_2.0.0             GenomicRanges_1.36.1       
## [53] GenomeInfoDb_1.20.0         Biostrings_2.52.0          
## [55] XVector_0.24.0              IRanges_2.18.2             
## [57] S4Vectors_0.22.1            BiocParallel_1.18.1        
## [59] BiocGenerics_0.30.0         dada2_1.12.1               
## [61] Rcpp_1.0.2                 
## 
## loaded via a namespace (and not attached):
##  [1] readxl_1.3.1           backports_1.1.5        igraph_1.2.4.1        
##  [4] lazyeval_0.2.2         splines_3.6.0          crosstalk_1.0.0       
##  [7] digest_0.6.21          foreach_1.4.7          htmltools_0.3.6       
## [10] fastcluster_1.1.25     modelr_0.1.5           RcppParallel_4.4.3    
## [13] colorspace_1.4-1       rvest_0.3.4            haven_2.1.1           
## [16] xfun_0.10              crayon_1.3.4           jsonlite_1.6          
## [19] zeallot_0.1.0          survival_2.44-1.1      iterators_1.0.12      
## [22] glue_1.3.1             gtable_0.3.0           zlibbioc_1.30.0       
## [25] webshot_0.5.1          GetoptLong_0.1.7       Rhdf5lib_1.6.1        
## [28] shape_1.4.4            viridisLite_0.3.0      xtable_1.8-4          
## [31] clue_0.3-57            htmlwidgets_1.3        httr_1.4.1            
## [34] RColorBrewer_1.1-2     pkgconfig_2.0.3        tidyselect_0.2.5      
## [37] labeling_0.3           rlang_0.4.0            later_0.8.0           
## [40] munsell_0.5.0          cellranger_1.1.0       tools_3.6.0           
## [43] cli_1.1.0              generics_0.0.2         ade4_1.7-13           
## [46] broom_0.5.2            evaluate_0.14          biomformat_1.12.0     
## [49] yaml_2.2.0             mime_0.7               xml2_1.2.2            
## [52] compiler_3.6.0         png_0.1-7              ggsignif_0.6.0        
## [55] stringi_1.4.3          highr_0.8              Matrix_1.2-17         
## [58] multtest_2.40.0        vctrs_0.2.0            pillar_1.4.2          
## [61] GlobalOptions_0.1.0    httpuv_1.5.1           R6_2.4.0              
## [64] latticeExtra_0.6-28    hwriter_1.3.2          promises_1.0.1        
## [67] codetools_0.2-16       MASS_7.3-51.4          gtools_3.8.1          
## [70] assertthat_0.2.1       rhdf5_2.28.0           rjson_0.2.20          
## [73] withr_2.1.2            GenomeInfoDbData_1.2.1 mgcv_1.8-28           
## [76] hms_0.5.1              rvcheck_0.1.3          shiny_1.3.2           
## [79] lubridate_1.7.4        base64enc_0.1-3
## ─ Session info ──────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 3.6.0 (2019-04-26)
##  os       macOS Mojave 10.14.6        
##  system   x86_64, darwin15.6.0        
##  ui       X11                         
##  language (EN)                        
##  collate  en_US.UTF-8                 
##  ctype    en_US.UTF-8                 
##  tz       America/Panama              
##  date     2019-10-08                  
## 
## ─ Packages ──────────────────────────────────────────────────────────────
##  package              * version   date       lib
##  ade4                   1.7-13    2018-08-31 [1]
##  ape                  * 5.3       2019-03-17 [1]
##  assertthat             0.2.1     2019-03-21 [1]
##  backports              1.1.5     2019-10-02 [1]
##  base64enc              0.1-3     2015-07-28 [1]
##  Biobase              * 2.44.0    2019-05-02 [1]
##  BiocGenerics         * 0.30.0    2019-05-02 [1]
##  BiocParallel         * 1.18.1    2019-08-06 [1]
##  biomformat             1.12.0    2019-05-02 [1]
##  Biostrings           * 2.52.0    2019-05-02 [1]
##  bitops               * 1.0-6     2013-08-17 [1]
##  broom                  0.5.2     2019-04-07 [1]
##  callr                  3.3.1     2019-07-18 [1]
##  cellranger             1.1.0     2016-07-27 [1]
##  circlize             * 0.4.8     2019-09-08 [1]
##  cli                    1.1.0     2019-03-19 [1]
##  clue                   0.3-57    2019-02-25 [1]
##  cluster              * 2.1.0     2019-06-19 [1]
##  codetools              0.2-16    2018-12-24 [1]
##  colorspace             1.4-1     2019-03-18 [1]
##  ComplexHeatmap       * 2.1.0     2019-09-10 [1]
##  crayon                 1.3.4     2017-09-16 [1]
##  crosstalk              1.0.0     2016-12-21 [1]
##  dada2                * 1.12.1    2019-05-14 [1]
##  data.table           * 1.12.2    2019-04-07 [1]
##  DelayedArray         * 0.10.0    2019-05-02 [1]
##  desc                   1.2.0     2018-05-01 [1]
##  devtools               2.2.0     2019-09-07 [1]
##  digest                 0.6.21    2019-09-20 [1]
##  dplyr                * 0.8.3     2019-07-04 [1]
##  DT                   * 0.8       2019-08-07 [1]
##  ellipsis               0.3.0     2019-09-20 [1]
##  evaluate               0.14      2019-05-28 [1]
##  fastcluster            1.1.25    2018-06-07 [1]
##  forcats              * 0.4.0     2019-02-17 [1]
##  foreach                1.4.7     2019-07-27 [1]
##  formatR              * 1.7       2019-06-11 [1]
##  fs                     1.3.1     2019-05-06 [1]
##  gdata                * 2.18.0    2017-06-06 [1]
##  generics               0.0.2     2018-11-29 [1]
##  GenomeInfoDb         * 1.20.0    2019-05-02 [1]
##  GenomeInfoDbData       1.2.1     2019-09-10 [1]
##  GenomicAlignments    * 1.20.1    2019-06-18 [1]
##  GenomicRanges        * 1.36.1    2019-09-06 [1]
##  GetoptLong             0.1.7     2018-06-10 [1]
##  ggplot2              * 3.2.1     2019-08-10 [1]
##  ggpubr               * 0.2.3     2019-09-03 [1]
##  ggsignif               0.6.0     2019-08-08 [1]
##  ggthemes             * 4.2.0     2019-05-13 [1]
##  ggtree               * 1.16.6    2019-08-26 [1]
##  GlobalOptions          0.1.0     2018-06-09 [1]
##  glue                   1.3.1     2019-03-12 [1]
##  gridExtra            * 2.3       2017-09-09 [1]
##  gtable                 0.3.0     2019-03-25 [1]
##  gtools                 3.8.1     2018-06-26 [1]
##  haven                  2.1.1     2019-07-04 [1]
##  heatmap3             * 1.1.6     2019-03-22 [1]
##  highr                  0.8       2019-03-20 [1]
##  hms                    0.5.1     2019-08-23 [1]
##  htmltools              0.3.6     2017-04-28 [1]
##  htmlwidgets            1.3       2018-09-30 [1]
##  httpuv                 1.5.1     2019-04-05 [1]
##  httr                   1.4.1     2019-08-05 [1]
##  hwriter                1.3.2     2014-09-10 [1]
##  igraph                 1.2.4.1   2019-04-22 [1]
##  IRanges              * 2.18.2    2019-08-24 [1]
##  iterators              1.0.12    2019-07-26 [1]
##  jsonlite               1.6       2018-12-07 [1]
##  kableExtra           * 1.1.0     2019-03-16 [1]
##  knitr                * 1.25      2019-09-18 [1]
##  labeling               0.3       2014-08-23 [1]
##  later                  0.8.0     2019-02-11 [1]
##  lattice              * 0.20-38   2018-11-04 [1]
##  latticeExtra           0.6-28    2016-02-09 [1]
##  lazyeval               0.2.2     2019-03-15 [1]
##  lubridate              1.7.4     2018-04-11 [1]
##  magrittr             * 1.5       2014-11-22 [1]
##  MASS                   7.3-51.4  2019-03-31 [1]
##  Matrix                 1.2-17    2019-03-22 [1]
##  matrixStats          * 0.55.0    2019-09-07 [1]
##  memoise                1.1.0     2017-04-21 [1]
##  mgcv                   1.8-28    2019-03-21 [1]
##  mime                   0.7       2019-06-11 [1]
##  modelr                 0.1.5     2019-08-08 [1]
##  multtest               2.40.0    2019-05-02 [1]
##  munsell                0.5.0     2018-06-12 [1]
##  nlme                 * 3.1-141   2019-08-01 [1]
##  pairwiseAdonis       * 0.0.1     2019-09-10 [1]
##  pander               * 0.6.3     2018-11-06 [1]
##  permute              * 0.9-5     2019-03-12 [1]
##  phyloseq             * 1.28.0    2019-05-02 [1]
##  picante              * 1.8       2019-03-21 [1]
##  pillar                 1.4.2     2019-06-29 [1]
##  pkgbuild               1.0.5     2019-08-26 [1]
##  pkgconfig              2.0.3     2019-09-22 [1]
##  pkgload                1.0.2     2018-10-29 [1]
##  plotly               * 4.9.0     2019-04-10 [1]
##  plyr                 * 1.8.4     2016-06-08 [1]
##  png                    0.1-7     2013-12-03 [1]
##  prettyunits            1.0.2     2015-07-13 [1]
##  processx               3.4.1     2019-07-18 [1]
##  promises               1.0.1     2018-04-13 [1]
##  ps                     1.3.0     2018-12-21 [1]
##  purrr                * 0.3.2     2019-03-15 [1]
##  R6                     2.4.0     2019-02-14 [1]
##  RColorBrewer           1.1-2     2014-12-07 [1]
##  Rcpp                 * 1.0.2     2019-07-25 [1]
##  RcppParallel           4.4.3     2019-05-22 [1]
##  RCurl                * 1.95-4.12 2019-03-04 [1]
##  readr                * 1.3.1     2018-12-21 [1]
##  readxl                 1.3.1     2019-03-13 [1]
##  remotes                2.1.0     2019-06-24 [1]
##  reshape2             * 1.4.3     2017-12-11 [1]
##  rhdf5                  2.28.0    2019-05-02 [1]
##  Rhdf5lib               1.6.1     2019-09-09 [1]
##  rjson                  0.2.20    2018-06-08 [1]
##  rlang                  0.4.0     2019-06-25 [1]
##  rmarkdown            * 1.16      2019-10-01 [1]
##  rprojroot              1.3-2     2018-01-03 [1]
##  Rsamtools            * 2.0.0     2019-05-02 [1]
##  rstudioapi           * 0.10      2019-03-19 [1]
##  rvcheck                0.1.3     2018-12-06 [1]
##  rvest                  0.3.4     2019-05-15 [1]
##  S4Vectors            * 0.22.1    2019-09-09 [1]
##  scales               * 1.0.0     2018-08-09 [1]
##  sessioninfo            1.1.1     2018-11-05 [1]
##  shape                  1.4.4     2018-02-07 [1]
##  shiny                  1.3.2     2019-04-22 [1]
##  ShortRead            * 1.42.0    2019-05-02 [1]
##  stringi                1.4.3     2019-03-12 [1]
##  stringr              * 1.4.0     2019-02-10 [1]
##  SummarizedExperiment * 1.14.1    2019-07-31 [1]
##  survival               2.44-1.1  2019-04-01 [1]
##  svgPanZoom           * 0.3.3     2016-09-26 [1]
##  testthat               2.2.1     2019-07-25 [1]
##  tibble               * 2.1.3     2019-06-06 [1]
##  tidyr                * 0.8.3     2019-03-01 [1]
##  tidyselect             0.2.5     2018-10-11 [1]
##  tidytree             * 0.2.7     2019-09-12 [1]
##  tidyverse            * 1.2.1     2017-11-14 [1]
##  treeio               * 1.8.2     2019-08-21 [1]
##  usethis                1.5.1     2019-07-04 [1]
##  vctrs                  0.2.0     2019-07-05 [1]
##  vegan                * 2.5-6     2019-09-01 [1]
##  viridisLite            0.3.0     2018-02-01 [1]
##  webshot                0.5.1     2018-09-28 [1]
##  withr                  2.1.2     2018-03-15 [1]
##  xfun                   0.10      2019-10-01 [1]
##  xml2                   1.2.2     2019-08-09 [1]
##  xtable                 1.8-4     2019-04-21 [1]
##  XVector              * 0.24.0    2019-05-02 [1]
##  yaml                   2.2.0     2018-07-25 [1]
##  zeallot                0.1.0     2018-01-28 [1]
##  zlibbioc               1.30.0    2019-05-02 [1]
##  source                                         
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  Bioconductor                                   
##  Bioconductor                                   
##  Bioconductor                                   
##  Bioconductor                                   
##  Bioconductor                                   
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  Github (jokergoo/ComplexHeatmap@35d1d20)       
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  Bioconductor                                   
##  CRAN (R 3.6.0)                                 
##  Bioconductor                                   
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  Bioconductor                                   
##  Bioconductor                                   
##  Bioconductor                                   
##  Bioconductor                                   
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  Bioconductor                                   
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  Bioconductor                                   
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  Bioconductor                                   
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  Github (pmartinezarbizu/pairwiseAdonis@6e09713)
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  Bioconductor                                   
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  Bioconductor                                   
##  Bioconductor                                   
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  Bioconductor                                   
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  Bioconductor                                   
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  Bioconductor                                   
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  Bioconductor                                   
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  Bioconductor                                   
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  Bioconductor                                   
##  CRAN (R 3.6.0)                                 
##  CRAN (R 3.6.0)                                 
##  Bioconductor                                   
## 
## [1] /Library/Frameworks/R.framework/Versions/3.6/Resources/library
## Time difference of 1.353919 mins

back to top

LS0tCnRpdGxlOiAiSW50ZXN0aW5hbCBtaWNyb2JlczogYW4gYXhpcyBvZiBmdW5jdGlvbmFsIGRpdmVyc2l0eSBhbW9uZyBsYXJnZSBtYXJpbmUgY29uc3VtZXJzIgpzdWJ0aXRsZTogUGh5bG9zZXEgd29ya2Zsb3cgCmF1dGhvcjogfAogIHwgSmFycm9kIEouIFNjb3R0XmEsMV4sIFRob21hcyBDLiBBZGFtXmJeLCBBbGFpbiBEdXJhbl5jXiwgRGVyb24gRS4gQnVya2VwaWxlXmIsZF4sICYgRG91Z2xhcyBCLiBSYXNoZXJeZSwxXiAgCiAgPHA+IDwvcD4gCiAgPGZvbnQgc2l6ZT0iMiI+IF5hXlNtaXRoc29uaWFuIFRyb3BpY2FsIFJlc2VhcmNoIEluc3RpdHV0ZSwgQXBhcnRhZG8gMDg0My0wMzA5MiBCYWxib2EsIFJlcMO6YmxpY2EgZGUgUGFuYW3DoTwvZm9udD4gIAogIDxmb250IHNpemU9IjIiPiBeYl5NYXJpbmUgU2NpZW5jZSBJbnN0aXR1dGUsIFVuaXZlcnNpdHkgb2YgQ2FsaWZvcm5pYSwgU2FudGEgQmFyYmFyYSwgQ0EgOTMxMDYsIFVTQTwvZm9udD4gIAogIDxmb250IHNpemU9IjIiPiBeY15EZXBhcnRtZW50IG9mIEJpb2xvZ2ljYWwgU2NpZW5jZXMsIEZsb3JpZGEgSW50ZXJuYXRpb25hbCBVbml2ZXJzaXR5LCBNaWFtaSwgRkwgMzMxOTksIFVTQTwvZm9udD4gIAogIDxmb250IHNpemU9IjIiPiBeZF5EZXBhcnRtZW50IG9mIEVjb2xvZ3kgJiBFdm9sdXRpb24sIFVuaXZlcnNpdHkgb2YgQ2FsaWZvcm5pYSwgU2FudGEgQmFyYmFyYSwgQ0EgOTMxMDYsIFVTQTwvZm9udD4gIAogIDxmb250IHNpemU9IjIiPiBeZV5CaWdlbG93IExhYm9yYXRvcnkgZm9yIE9jZWFuIFNjaWVuY2VzLCBFYXN0IEJvb3RoYmF5LCBNRSAwNDU0NCwgVVNBPC9mb250PgogIDxwPiA8L3A+IAogIDxmb250IHNpemU9IjMiPiBeMV5UbyB3aG9tIGNvcnJlc3BvbmRlbmNlIHNob3VsZCBiZSBhZGRyZXNzZWQuIEUtbWFpbDogamFycm9kLmp1ZGUuc2NvdHRAZ21haWwuY29tIG9yIGRyYXNoZXJAYmlnZWxvdy5vcmc8L2ZvbnQ+ICAKCmFic3RyYWN0OiAiV29ya2Zsb3cgdG8gZ2VuZXJhdGUgcGh5bG9zZXEgb2JqZWN0cywgYW5hbHl6ZSBkYXRhLCBhbmQgY3JlYXRlIGZpZ3VyZXMgZm9yIHRoZSBmaXNoIG1pY3JvYmlvbWUgcGFwZXIsIHByb2Nlc3NlZCB1c2luZyB0aGUgcHJldmlvdXMgREFEQTIgd29ya2Zsb3cuIEhlcmUgd2UgcmVwb3J0IGJvdGggbWV0aG9kcyBhbmQgcmVzdWx0cyBpbiBwbGFpbiB0ZXh0IGFuZCBSIGNvZGUuIFlvdSBjYW4gY2hvb3NlIHRvIHNob3cgYWxsIGNvZGUgb3IgaGlkZSB0aGUgY29kZSB1c2luZyB0aGUgYnV0dG9uIGluIHRoZSB1cHBlciByaWdodCBoYW5kIGNvcm5lciBvZiB0aGUgZnJvbiBwYWdlIChkZWZhdWx0IGlzIGhpZGUpIGFzIHdlbGwgYXMgZG93bmxvYWQgdGhlIC5SbWQgZmlsZSB0byB0d2VhayB0aGUgY29kZS4gVGhlIGRvY3VtZW50IHJlcHJlc2VudHMgYSAqKmNvbXBsZXRlbHkgcmVwcm9kdWNpYmxlIHdvcmtmbG93Kiogb2Ygb3VyIHN0dWR5LiIKI2RhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6IAogICAga2VlcF9tZDogZmFsc2UKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdG9jOiBUUlVFCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRvY19kZXB0aDogMwogICAgdGhlbWU6IGNvc21vCiAgICBoaWdobGlnaHQ6IGhhZGRvY2sKICAgIGRmX3ByaW50OiBwYWdlZAogICAgbnVtYmVyX3NlY3Rpb25zOiBmYWxzZQogIHBkZl9kb2N1bWVudDogZGVmYXVsdAojY29vbF90aGVtZXM6IGRlZmF1bHQsIGNlcnVsZWFuLCBjb3NtbywgZGFya2x5LCBmbGF0bHksIGpvdXJuYWwsIGx1bWVuLCBzYW5kc3RvbmUsIHNpbXBsZXgsIHNwYWNlbGFiLCB1bml0ZWQsIHlldGkKI25lZWQgQ1NTIGZpbGU6IGN5Ym9yZywgbGl0ZXJhLCBsdXgsIG1hdGVyaWEsIG1pbnR5LCBwdWxzZSwgc2tldGNoeSwgc2xhdGUsIHNvbGFyLCBzdXBlcmhlcm8KLS0tCiAKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CnJlbW92ZShsaXN0ID0gbHMoKSkKbGlicmFyeShkYWRhMik7IHBhY2thZ2VWZXJzaW9uKCJkYWRhMiIpCmxpYnJhcnkoU2hvcnRSZWFkKTsgcGFja2FnZVZlcnNpb24oIlNob3J0UmVhZCIpCmxpYnJhcnkocGh5bG9zZXEpOyBwYWNrYWdlVmVyc2lvbigicGh5bG9zZXEiKQpsaWJyYXJ5KGdncGxvdDIpOyBwYWNrYWdlVmVyc2lvbigiZ2dwbG90MiIpCmxpYnJhcnkoInBseXIiKTsgcGFja2FnZVZlcnNpb24oInBseXIiKQpsaWJyYXJ5KHZlZ2FuKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShncmlkKQpsaWJyYXJ5KHJlc2hhcGUyKQpsaWJyYXJ5KHJzdHVkaW9hcGkpCmxpYnJhcnkoa25pdHIpCmxpYnJhcnkoa2FibGVFeHRyYSkKbGlicmFyeShkYXRhLnRhYmxlKQpsaWJyYXJ5KERUKQpsaWJyYXJ5KHJtYXJrZG93bikKbGlicmFyeShwYW5kZXIpCmxpYnJhcnkoZm9ybWF0UikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KGdyaWQpCmxpYnJhcnkoZ3JEZXZpY2VzKQpsaWJyYXJ5KHN2Z1Bhblpvb20pCmxpYnJhcnkoUkN1cmwpCmxpYnJhcnkocGxvdGx5KQpsaWJyYXJ5KHBhaXJ3aXNlQWRvbmlzKQpzZXNzaW9uSW5mbygpCnNldC5zZWVkKDAxOTkpCmBgYAoKYGBge3Igc2V0X3dkLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19rbml0JHNldChyb290LmRpciA9IGdldHdkKCkpCiMgVGhpcyB3aWxsIHNldHdkIHRvIHdoZXJldmVyIHRoZSAuUm1kIGZpbGUgaXMgb3BlbmVkLgpwdG0gPC0gcHJvYy50aW1lKCkKc3RhcnRfdGltZSA8LSBTeXMudGltZSgpCiNvcHRzX2NodW5rJHNldChjYWNoZT1UUlVFKQojZm9ybWF0Ujo6dGlkeV9hcHAoKSBydW4gdGhpcyBpbiBSIHRvIHRpZHkgY29kZS4gSG93IHRvIGRvIGl0IGhlcmU/CgojIyBVTkNPTU1FTlQgVE8gUlVOIGxpbnRyCiNybShsaXN0PWxzKCkpCiNsaWJyYXJ5KGxpbnRyKQojbmFtZXMobGludHI6OmRlZmF1bHRfbGludGVycykKI2xpbnRyOjpsaW50KAojICBmaWxlbmFtZSA9ICJQaHlsb3NlcV93b3JrZmxvdy5SbWQiLAojICBsaW50ZXJzID0gbGludHI6OndpdGhfZGVmYXVsdHMoCiMgICAgdHJhaWxpbmdfd2hpdGVzcGFjZV9saW50ZXIgPSBOVUxMLAojICAgIGNvbW1lbnRlZF9jb2RlX2xpbnRlciA9IE5VTEwKIyAgKQojKQpgYGAKCmBgYHtyIG1rZGlycywgaW5jbHVkZT1GQUxTRX0KZGlyLmNyZWF0ZSgiVEFCTEVTL09VVFBVVC9QUy8iLCByZWN1cnNpdmUgPSBUUlVFKQpkaXIuY3JlYXRlKCJUQUJMRVMvT1VUUFVUL09USEVSLyIsIHJlY3Vyc2l2ZSA9IFRSVUUpCmRpci5jcmVhdGUoIlRBQkxFUy9PVVRQVVQvTEVmU2UvIiwgcmVjdXJzaXZlID0gVFJVRSkKZGlyLmNyZWF0ZSgiVEFCTEVTL09VVFBVVC9TVVBQLyIsIHJlY3Vyc2l2ZSA9IFRSVUUpCmRpci5jcmVhdGUoIkZJR1VSRVMvT1VUUFVULyIsIHJlY3Vyc2l2ZSA9IFRSVUUpCmRpci5jcmVhdGUoIlBTX09CSkVDVFMvIiwgcmVjdXJzaXZlID0gVFJVRSkKYGBgCgoqKioKCiMjIERhdGEgQXZhaWxhYmlsaXR5CgpBbGwgeW91IG5lZWQgdG8gZG8gdG8gcnVuIHRoaXMgd29ya2Zsb3cgaXMgdG8gaW5zdGFsbCB0aGUgYXBwcm9wcmlhdGUgUiBwYWNrYWdlcyBhbmQgZG93bmxvYWQgdGhlIGZvbGxvd2luZyBmaWxlOiAgCgoqIFsxMC42MDg0L205LmZpZ3NoYXJlLjczNTcxNzhdKGh0dHBzOi8vZG9pLm9yZy8xMC42MDg0L205LmZpZ3NoYXJlLjczNTcxNzgpe3RhcmdldD0iX2JsYW5rIn06IERPSSBmb3IgdGhpcyB3b3JrZmxvdy4gSW5jbHVkZXMgb3V0cHV0IGZyb20gdGhlIERBREEyIHdvcmtmbG93LCB0aGUgcGh5bG9zZXEgc2NyaXB0LCBhbmQgb3RoZXIgbmVjZXNzYXJ5IGlucHV0IGZpbGVzLiAgIAoKV2UgbWFkZSBzZXZlcmFsIGFkZGl0aW9uYWwgZGF0YSBwcm9kdWN0cyBhbmQgcHJvY2Vzc2luZyBzY3JpcHRzIGF2YWlsYWJsZS4gICAKCiogWzEwLjYwODQvbTkuZmlnc2hhcmUuNjg3NTUyMl0oaHR0cHM6Ly9kb2kub3JnLzEwLjYwODQvbTkuZmlnc2hhcmUuNjg3NTUyMil7dGFyZ2V0PSJfYmxhbmsifTogUmF3IGRhdGEgZm9yIGVhY2ggc2FtcGxlIChiZWZvcmUgcmVtb3ZpbmcgcHJpbWVycykuICAgIAoqIFtQUkpFQjI4Mzk3XShodHRwczovL3d3dy5lYmkuYWMudWsvZW5hL2RhdGEvdmlldy9QUkpFQjI4Mzk3KXt0YXJnZXQ9Il9ibGFuayJ9OiBTdHVkeSBhY2Nlc3Npb24gbnVtYmVyIGZvciB0cmltbWVkIGRhdGEgKHByaW1lcnMgcmVtb3ZlZCkgIGRlcG9zaXRlZCBhdCB0aGUgRXVyb3BlYW4gTnVjbGVvdGlkZSBBcmNoaXZlLiAgICAKKiBbMTAuNjA4NC9tOS5maWdzaGFyZS42OTk3MjUzXShodHRwczovL2RvaS5vcmcvMTAuNjA4NC9tOS5maWdzaGFyZS42OTk3MjUzKXt0YXJnZXQ9Il9ibGFuayJ9OiBEQURBMiB3b3JrZmxvdyBmb3IgcHJvY2Vzc2luZyAxNlMgclJOQSByZWFkcy4gICAgCiogWzEwLjYwODQvbTkuZmlnc2hhcmUuNzM3OTkzMF0oaHR0cHM6Ly9kb2kub3JnLzEwLjYwODQvbTkuZmlnc2hhcmUuNzM3OTkzMCl7dGFyZ2V0PSJfYmxhbmsifTogRGF0YSBwcm9kdWN0cyBmcm9tIHRoZSB3b3JrZmxvd3MgaW5jbHVkaW5nIHNlcXVlbmNlIHRhYmxlcywgdGF4b25vbXkgdGFibGVzLCBhbmQgQVNWIGZhc3RhIGZpbGVzLiAgICAgCiogWzEwLjYwODQvbTkuZmlnc2hhcmUuNzM3OTkzNl0oaHR0cHM6Ly9kb2kub3JnLzEwLjYwODQvbTkuZmlnc2hhcmUuNzM3OTkzNil7dGFyZ2V0PSJfYmxhbmsifTogRmFzdGEgZmlsZSBmb3IgdGhlIDU5IERBIEFTVnMsIEJMQVNUIHJlc3VsdHMsIGFuZCBhbGlnbm1lbnQgZmlsZSBpbmNsdWRpbmcgdG9wIEJMQVNUIGhpdHMuICAgICAKKiBbMTAuNjA4NC9tOS5maWdzaGFyZS43Mzc5NTk3XShodHRwczovL2RvaS5vcmcvMTAuNjA4NC9tOS5maWdzaGFyZS43Mzc5NTk3KXt0YXJnZXQ9Il9ibGFuayJ9OiBTdXBwbGVtZW50YXJ5IGZpbGUgZnJvbSB0aGUgcGFwZXIuICAgCgoqKioKCiMjIFByZWFtYmxlCgo8c3R5bGU+CmRpdi5ibHVlIHsgYmFja2dyb3VuZC1jb2xvcjojRkJERkI0OyBib3JkZXItcmFkaXVzOiA1cHg7IHBhZGRpbmc6IDIwcHg7fQo8L3N0eWxlPgo8ZGl2IGNsYXNzID0gImJsdWUiPgo8Zm9udCBzaXplPSI0Ij5UaGlzIGRvY3VtZW50IGlzICAqKmludGVyYWN0aXZlKiouIFlvdSBjYW4gKipzb3J0IGFuZCBzY3JvbGwqKiB0aHJvdWdoIG1vc3Qgb2YgdGhlIHRhYmxlcyBhbmQgdGhlICoqcGh5bG9nZW5ldGljIHRyZWUgaXMgem9vbWFibGUqKi4gSW4gdGhlIHVwcGVyIHJpZ2h0IGhhbmQgY29ybmVyIG9mIHRoZSBmcm9udCBwYWdlIGlzIGEgYENvZGVgIGJ1dHRvbi4gVXNlIHRoaXMgdG8gc2hvdyBvciBoaWRlIGFsbCB0aGUgY29kZSBpbiB0aGUgZG9jdW1lbnQgKGRlZmF1bHQgaXMgaGlkZSkgYXMgd2VsbCBhcyBkb3dubG9hZCB0aGUgYC5SbWRgIGZpbGUgd2hpY2ggeW91IGNhbiB1c2UgdG8gZXh0cmFjdCB0aGUgY29kZS4gRGF0YSBwcm9kdWN0cyBmcm9tIHRoZSBmaW5hbCBwYXBlciBhcmUgaGlnaGxpZ2h0ZWQgaW4gPGZvbnQgc2l6ZT0iMyIgY29sb3I9InJlZCI+UmVkPC9mb250Pi48L2ZvbnQ+CjwvZGl2PgoKIyMjIERlZmluaXRpb25zICYgQWJicmV2aWF0aW9ucyAgCgoqIFtBbXBsaWNvbiBTZXF1ZW5jZSBWYXJpYW50XShodHRwczovL3d3dy5uYXR1cmUuY29tL2FydGljbGVzL2lzbWVqMjAxNzExOSl7dGFyZ2V0PSJfYmxhbmsifSAoKipBU1YqKik6IEV4YWN0IHNlcXVlbmNlIHZhcmlhbnQtLS1hbmFsb2dvdXMgdG8gYW4gT1RVLS0tYnV0IHdpdGggc2luZ2xlIG51Y2xlb3RpZGUgcmVzb2x1dGlvbi4gIAoqIERpZmZlcmVudGlhbGx5IGFidW5kYW50ICgqKkRBKiopIGZlYXR1cmU6IFRheGEsIEFTViwgZXRjLiB0aGF0IGlzIGRpc3Byb3BvcnRpb25hdGVseSBhYnVuZGFudCBpbiBhIGdyb3VwIG9mIHNhbXBsZXMgYW5kIHN0YXRpc3RpY2FsbHkgZGlmZmVyZW50IHRoYW4gb3RoZXIgZ3JvdXBzLiAKCiMjIyBTdHVkeSBnb2FscwoKMS4gQXNzZXNzIHRoZSB0YXhvbm9taWMgY29tcG9zaXRpb24gb2YgaW50ZXN0aW5hbCBjb21tdW5pdGllcyBmcm9tIGhlcmJpdm9yb3VzIHJlZWYgZmlzaC4gIAoyLiBEZXRlcm1pbmUgdGhlIGRpdmVyc2l0eSBvZiB0aGVzZSBjb21tdW5pdGllcyBhbmQgdGhlaXIgc2ltaWxhcml0eS9kaXNzaW1pbGFyaXR5LiAgCjMuIElkZW50aWZ5IGRpZmZlcmVudGlhbGx5IGFidW5kYW50IEFTVnMgYWNyb3NzIHRoZSBob3N0IHNwZWNpZXMuICAKNC4gUHJlZGljdCB0aGUgc3BlY2lmaWNpdHkgb2YgZGlmZmVyZW50aWFsbHkgYWJ1bmRhbnQgQVNWcy4gIAoKKioqCgo8YSBpZD0iYmFjayB0byB0b3AiPjwvYT4gIAoKIyMgV29ya2Zsb3cgb3ZlcnZpZXcKCiMjIyMgW1BhcnQgSTogRmllbGQgT2JzZXJ2YXRpb25zXSgjUGFydCBJOiBGaWVsZCBPYnNlcnZhdGlvbnMpCgpCZWZvcmUgd2UgcHJvY2VlZCB3aXRoIG1pY3JvYmlhbCBjb21tdW5pdHkgYW5hbHlzaXMsIHdlIHdpbGwgcnVuIHNvbWUgYW5hbHlzZXMgb24gZmllbGQtYmFzZWQgYmVoYXZpb3JhbCBhc3NheXMgb2YgdGhlIGRpZmZlcmVudCBoZXJiaXZvcm91cyByZWVmIGZpc2ggc3BlY2llcy4KCgojIyMjIFtQYXJ0IElJOiBEYXRhIFByZXBhcmF0aW9uXSgjUGFydCBJSTogRGF0YSBQcmVwYXJhdGlvbikKCkluIHRoaXMgZmlyc3QgcGFydCB3ZSBnbyB0aHJvdWdoIHRoZSBzdGVwcyBvZiBkZWZpbmluZyBzYW1wbGUgZ3JvdXBzLCBjcmVhdGluZyBwaHlsb3NlcSBvYmplY3RzLCByZW1vdmluZyB1bndhbnRlZCBzYW1wbGVzLCBhbmQgcmVtb3ZpbmcgY29udGFtaW5hbnQgQVNWcy4gVmFyaW91cyBwYXJ0cyBvZiB0aGlzIHNlY3Rpb24gY2FuIGVhc2lseSBiZSBtb2RpZmllZCB0byBwZXJmb3JtIGRpZmZlcmVudCBhbmFseXNlcy4gRm9yIGV4YW1wbGUsIGlmIHlvdSB3ZXJlIG9ubHkgaW50ZXJlc3RlZCBpbiBhIHNwZWNpZmljIHRheGEgb3IgZ3JvdXAgb2Ygc2FtcGxlcywgeW91IGNvdWxkIGNoYW5nZSB0aGUgY29kZSBoZXJlIHRvIGNyZWF0ZSBuZXcgcGh5bG9zZXEgb2JqZWN0cy4KCiMjIyMgW1BhcnQgSUlJOiBDb21tdW5pdHkgQ29tcG9zaXRpb24gJiBEaXZlcnNpdHldKCNQYXJ0IElJSTogQ29tbXVuaXR5IENvbXBvc2l0aW9uICYgRGl2ZXJzaXR5KSAgCgpJbiB0aGUgc2Vjb25kIHBhcnQsIHdlIGFzc2VzcyB0YXhvbm9taWMgY29tcG9zaXRpb24gYXMgd2VsbCBhcyBhbHBoYSBhbmQgYmV0YSBkaXZlcnNpdHkuIFBoeWxvc2VxIG9mZmVycyBtYW55IG9wdGlvbnMgZm9yIGFzc2Vzc2luZyBkaXZlcnNpdHksIGluY2x1ZGluZyBzZXZlcmFsIGFscGhhIGRpdmVyc2l0eSBtZXRyaWNzLCBhZGRpdGlvbmFsIG9yZGluYXRpb24gIGFuZCBkaXN0YW5jZSBtZXRob2RzLCBhbmQgc28gb24uIFlvdSBjYW4gcGxheSBhcm91bmQgd2l0aCB0aGVzZSBzZXR0aW5ncyB0byBob3cgaXQgYWZmZWN0cyB0aGUgcmVzdWx0cy4KCiMjIyMgW1BhcnQgSVY6IERpZmZlcmVudGlhbGx5IEFidW5kYW50IEFTVnNdKCNQYXJ0IElWOiBEaWZmZXJlbnRpYWxseSBBYnVuZGFudCBBU1ZzKSAKCldlIHdhbnRlZCB0byB1bmRlcnN0YW5kIGhvdyBBU1ZzIHBhcnRpdGlvbmVkIGFjcm9zcyBob3N0IHNwZWNpZXMuIFdlIGFsc28gd2FudGVkIHRvIGFzc2VzcyB0aGUgc3BlY2lmaWNpdHkgb2YgZWFjaCBBU1YgdG8gZGV0ZXJtaW5lIGhhYml0YXQgcHJlZmVyZW5jZS4gVG8gb3VyIGtub3dsZWRnZSB0aGVyZSBpcyBubyBxdWFudGl0YXRpdmUgd2F5IHRvIGRvIHRoaXMuIFRoZSBvbmx5IGF0dGVtcHQgd2UgYXJlIGF3YXJlIG9mIHdhcyBbTWV0YU1ldGFEQl0oaHR0cDovL21tZGIuYW9yaS51LXRva3lvLmFjLmpwLyl7dGFyZ2V0PSJfYmxhbmsifSBidXQgaXQgaXMgYmFzZWQgb24gYSA0NTQgZGF0YWJhc2UgYW5kIG5vIGxvbmdlciBzZWVtcyB0byBiZSBpbiBhY3RpdmUgZGV2ZWxvcG1lbnQuIFNvIHdlIHVzZWQgYW4gYXBwcm9hY2ggYmFzZWQgb24gdGhlIHdvcmsgb2YgW1N1bGxhbSAqZXQuIGFsLipdKGh0dHBzOi8vZG9pLm9yZy8xMC4xMTExL2ouMTM2NS0yOTRYLjIwMTIuMDU1NTIueCl7dGFyZ2V0PSJfYmxhbmsifSwgZmlyc3QgaWRlbnRpZnlpbmcgZGlmZmVyZW50aWFsbHkgYWJ1bmRhbnQgQVNWcywgdGhlbiBzZWFyY2hpbmcgZm9yIGNsb3Nlc3QgZGF0YWJhc2UgaGl0cywgYW5kIGZpbmFsbHkgdXNpbmcgcGh5bG9nZW5ldGljIGFuYWx5c2lzIGFuZCB0b3AgaGl0IG1ldGFkYXRhIChpc29sYXRpb24gc291cmNlLCBuYXR1cmFsIGhvc3QpIHRvIGluZmVyIGhhYml0YXQgcHJlZmVyZW5jZS4KCiMjIyMgW1BhcnQgVjogU3ludGhlc2lzXSgjUGFydCBWOiBTeW50aGVzaXMpCgpJbiB0aGlzIHNlY3Rpb24gd2UgcHVsbCB0b2dldGhlciB0aGUgcmVzdWx0cyBmcm9tICoqUGFydCBJSUkqKiBhbmQgdHJ5IHRvIG1ha2Ugc2Vuc2Ugb2YgdGhlIG1pY3JvYmlvbWVzIGZyb20gdGhlc2UgaGVyYml2b3JvdXMgcmVlZiBmaXNoLiBIb3cgYXJlIEFTVnMgcGFydGl0aW9uaW5nIGFjcm9zcyBob3N0PyBIb3cgc2ltaWxhciBhcmUgdGhlc2UgQVNWcyB0byBzZXF1ZW5jZXMgZnJvbSBvdGhlciBzdHVkaWVzPyBXaGF0IGNhbiB0aGVzZSBwYXR0ZXJucyB0ZWxsIHVzIGFib3V0IGhvc3Qgc3BlY2lmaWNpdHk/Cgo+IEFsbCB0YWJsZXMgYW5kIGZpZ3VyZXMgcHJlc2VudGVkIGJlbG93IGFyZSBuYW1lZCBhcyB0aGV5IGFwcGVhcmVkIGluIHRoZSBvcmlnaW5hbCBwdWJsaWNhdGlvbi4gV2UgYWxzbyBpbmNsdWRlIG1hbnkgYWRkaXRpb25hbCBkYXRhIHByb2R1Y3RlcyB0aGF0IHdlcmUgbm90IHBhcnQgb2YgdGhlIG9yaWdpbmFsIHB1YmxpY2F0aW9uLiAgCgoqKioKCiMjIyBDb2xvciAmIGdyYXBoaWNzCgpUaHJvdWdob3V0IHRoaXMgd29ya2Zsb3cgd2UgYXJlIGdvaW5nIHRvIHJlbHkgb24gY29sb3IgdG8gaGVscCB1cyB0ZWxsIG91ciBzdG9yeS4gV2Ugd2lsbCB1c2UgY29sb3IgdG8gZGVsaW5lYXRlIGhvc3QgZmlzaCBzcGVjaWVzLCBidXQgbW9yZSBpbXBvcnRhbnRseSwgdG8gZGVsaW5lYXRlIG1pY3JvYmlhbCB0YXhhLiBNaWNyb2JpYWwgZGl2ZXJzaXR5IGlzIHByZXR0eSB2YXN0IGFuZCBpdCBjYW4gYmUgZGlmZmljdWx0IHRvIGRpc3BsYXkgYWxsIG9mIHRoaXMgZGl2ZXJzaXR5IGluIGEgc2luZ2xlLCBzdGF0aWMgZmlndXJlLiBBZGRpdGlvbmFsbHksIG1hbnkgb2YgdXMgaGF2ZSBhIGRlY3JlYXNlZCBhYmlsaXR5IHRvIHNlZSBjb2xvciBvciBkaWZmZXJlbmNlcyBpbiBjb2xvci4gU28gaXQgaXMgbm90IG9ubHkgaW1wb3J0YW50IHRvIHVzZSByZWxhdGl2ZWx5IGZldyBjb2xvcnMgYnV0IGFsc28gYSBjb2xvciBibGluZCBmcmllbmRseSBwYWxldHRlLiBGb3Igb3VyIGZpZ3VyZXMsIHdlIGdlbmVyYXRlZCBhIHBhbGV0dGVzIGJhc2VkIG9uIEJhbmcgV29uZydzIHNjaGVtZSBkZXNjcmliZWQgaW4gdGhpcyBbcGFwZXJdKGh0dHA6Ly9keC5kb2kub3JnLzEwLjEwMzgvbm1ldGguMTYxOCl7dGFyZ2V0PSJfYmxhbmsifS4gV29uZydzIGNvbG9yIHNjaGVtZSB1c2VzIGNvbnRyYXN0aW5nIGNvbG9ycyB0aGF0IGNhbiBiZSBkaXN0aW5ndWlzaGVkIGJ5IGZvbGtzIHdpdGggY29sb3IgdmlzaW9uIGRlZmljaWVuY3ktLS1yb3VnaGx5IDglIG9mIHBlb3BsZSAobW9zdGx5IG1hbGVzKSBhcmUgY29sb3IgYmxpbmQuIERvIHdhbnQgS2VhbnUgUmVldmVzIHRvIHVuZGVyc3RhbmQgeW91ciBmaWd1cmVzIG9yIG5vdD8gCgpUaGlzIHNjaGVtZSBpcyBjb25zZXJ2YXRpdmUtLS10aGVyZSBhcmUgb25seSA3IGNvbG9ycy4gV2UgYWRkZWQgYmxhY2sgYW5kIGdyZXkgdG8gZ2l2ZSB1cyBhIGxpdHRsZSB3aWdnbGUgcm9vbS4gT3RoZXJzIGhhdmUgZGV2ZWxvcGVkIFsxMiBhbmQgMTUgY29sb3IgcGFsZXR0ZSBzY2hlbWVzXShodHRwOi8vbWt3ZWIuYmNnc2MuY2EvY29sb3JibGluZC8pe3RhcmdldD0iX2JsYW5rIn0sIGJ1dCBiZSBjYXJlZnVsLS0tZmlndXJlcyB3aXRoIHRvbyBtYW55IGNvbG9ycyBjYW4gaW5oaWJpdCBvdXIgYWJpbGl0eSB0byBkaXNjZXJuIHBhdHRlcm5zLiBPdXIgY29uc2VydmF0aXZlIHBhbGV0dGUgZm9yY2VzIHVzIHRvIGNob29zZSBjYXJlZnVsbHkgd2hlbiBkZWNpZGluZyB3aGljaCB0YXhhIHRvIHRhcmdldCBvciBob3cgbWFueSBncm91cHMgdG8gZGlzcGxheS4gSGVyZSB3ZSB3aWxsIGNyZWF0ZSB0d28gcGFsZXR0ZXMtLS1vbmUgZm9yIG1pY3JvYmlhbCB0YXhhIHdpdGggYWxsIHRoZSBjb2xvcnMgYW5kIGFub3RoZXIgZm9yIHRoZSBmaXZlIGhvc3QgZmlzaCBzcGVjaWVzLiBUaGUgbGF0dGVyIGlzIGp1c3QgYSBzdWJzZXQgb2YgdGhlIGZ1bGwgcGFsZXR0ZS4gSGVyZSBpcyB0aGUgY29kZToKCmBgYHtyIGRlZmluZV9jb2xvcl9ibGluZF9zY2hlbWV9CiNGdWxsIHBhbGV0dGUKZnJpZW5kX3BhbCA8LSBjKCIjMDA5RTczIiwgIiNENTVFMDAiLCAiI0YwRTQ0MiIsICIjQ0M3OUE3IiwgIiM1NkI0RTkiLAogICAgIiNFNjlGMDAiLCAiIzAwNzJCMiIsICIjN0Y3RjdGIiwgIiNCNkRCRkYiLCAiIzAwMDAwMCIpCiNGaXNoIHBhbGV0dGUKc2FtcF9wYWwgPC0gYygiI0NDNzlBNyIsICIjMDA3MkIyIiwgIiMwMDlFNzMiLCAiIzU2QjRFOSIsICIjRTY5RjAwIikKYGBgCgoKKioqCjxhIGlkPSJQYXJ0IEk6IEZpZWxkIE9ic2VydmF0aW9ucyI+PC9hPiAgCgojIyBQYXJ0IEk6IEZpZWxkIE9ic2VydmF0aW9ucwpbYmFjayB0byB0b3BdKCNiYWNrIHRvIHRvcCkKClRvIGNoYXJhY3Rlcml6ZSB0aGUgZm9yYWdpbmcgZWNvbG9neSBvZiB0aGUgZGlmZmVyZW50IHNwZWNpZXMgb2YgaGVyYml2b3JvdXMgZmlzaGVzLCB3ZSBjaGFyYWN0ZXJpemVkIGluIGRldGFpbCBpbmRpdmlkdWFsIGJpdGVzIGJ5IGVhY2ggc3BlY2llcyBhdCB0aHJlZSBzaXRlcyBpbiB0aGUgRmxvcmlkYSBLZXlzIChDb25jaCwgRnJlbmNoLCBNb2xhc3NlcyByZWVmcykgZHVyaW5nIHRoZSBCb3JlYWwgc3VtbWVycyBvZiAyMDE0IGFuZCAyMDE2LiBBdCBlYWNoIHNpdGUsIHdlIGhhcGhhemFyZGx5IHNlbGVjdGVkIGZvY2FsIGZpc2ggb3ZlciBhIHdpZGUgcmFuZ2Ugb2Ygc2l6ZXMgYW5kIHRoZW4gcmFuZG9tbHkgc2VsZWN0ZWQgYSBzaW5nbGUgYml0ZSBieSBlYWNoIGluZGl2aWR1YWwgdG8gZGVzY3JpYmUgKHNlZSBTdXBwbGVtZW50YXJ5IFRhYmxlIDIgZm9yIHNhbXBsZSBzaXplcykuIEZvciBlYWNoIGJpdGUsIHdlIGlkZW50aWZpZWQgdGhlIGZvb2QgaXRlbShzKSB0YXJnZXRlZCBhcyB3ZWxsIGFzIGNoYXJhY3RlcmlzdGljcyBvZiB0aGUgc3Vic3RyYXRlIChlLmcuLCBoYXJkIGJvdHRvbSB2cy4gb3RoZXIgY29tbW9uIHN1YnN0cmF0ZXMgc3VjaCBhcyBzcG9uZ2VzLCBnb3Jnb25pYW5zLCBldGMuKSBhdCB0aGUgcHJlY2lzZSBsb2NhdGlvbiBvZiB0aGUgYml0ZS4gRm9yIGhhcmQgc3Vic3RyYXRlcywgd2UgcmVjb3JkZWQgd2hldGhlciBhIGJpdGUgd2FzIG9uIGEgY29udmV4LCBjb25jYXZlLCBvciBmbGF0IHN1cmZhY2UsIGFuZCB3aGV0aGVyIHRoYXQgc3VyZmFjZSB3YXMgb3JpZW50ZWQgaG9yaXpvbnRhbGx5ICg8IDQ1IGRlZ3JlZXMpIG9yIHZlcnRpY2FsbHkgKD4gNDUgZGVncmVlcykuIEluIGFkZGl0aW9uLCB3ZSBmcmFtZWQgZWFjaCBiaXRlIHdpdGhpbiBhIDUgeCA1IGNtIG1pY3JvLXF1YWRyYXQgYW5kIG1lYXN1cmVkIHRoZSBkZXB0aCBvZiB0aGUgc2VkaW1lbnQgYW5kIGhlaWdodCBvZiB0aGUgYWxnYWUgYXQgc2V2ZXJhbCBwb2ludHMgdG8gZGV0ZXJtaW5lIHRoZSBhdmVyYWdlIHNlZGltZW50IGRlcHRoIGFuZCBhbGdhbCBoZWlnaHQgd2l0aGluIHRoZSB2aWNpbml0eSBvZiB0aGUgYml0ZS4gV2UgdGhlbiBtYW51YWxseSByZW1vdmVkIHNlZGltZW50cyBhbmQgZGV0ZXJtaW5lZCB3aGV0aGVyIHRoZSBmaXNoIGxlZnQgYSBkaXN0aW5jdCBncmF6aW5nIHNjYXIgKGkuZS4sIHdoZXJlIGNhbGNpdW0gY2FyYm9uYXRlIGhhZCBiZWVuIHJlbW92ZWQgZnJvbSB0aGUgcmVlZiBmcmFtZXdvcmsgaW4gYWRkaXRpb24gdG8gZXBpbGl0aGljIGFsZ2FlKS4gCgpUbyB2aXN1YWxpemUgdGhlIG11bHRpdmFyaWF0ZSBwYXR0ZXJucyBvZiBoZXJiaXZvcnkgd2UgdXNlZCBub24tbWV0cmljIG11bHRpZGltZW5zaW9uYWwgc2NhbGluZyAoTk1EUykgYXMgaW1wbGVtZW50ZWQgdmlhIHRoZSBtZXRhTURTIGZ1bmN0aW9uIGluIHRoZSB2ZWdhbiBwYWNrYWdlLiBGb3IgZWFjaCBzcGVjaWVzIG9mIGhlcmJpdm9yb3VzIGZpc2ggYXQgZWFjaCBzaXRlIHdlIGNhbGN1bGF0ZWQgdGhlIHByb3BvcnRpb24gb2YgYml0ZXMgZm9jdXNlZCBvbiBlYWNoIHByZXkgaXRlbSAo4oCYcHJleSB2YXJpYWJsZXPigJkpIGFzIHdlbGwgYXMgdGhlIHByb3BvcnRpb24gb2YgYml0ZXMgdGFyZ2V0aW5nIHN1YnN0cmF0ZXMgd2l0aCBkaWZmZXJlbnQgY2hhcmFjdGVyaXN0aWNzIChlLmcuLCBjb252ZXggdnMuIGNvbmNhdmUgdnMuIGZsYXQpLiBXZSBhbHNvIGNhbGN1bGF0ZWQgdGhlIHByb3BvcnRpb24gb2YgYml0ZXMgcmVzdWx0aW5nIGluIGEgZ3JhemluZyBzY2FyLiBGb3IgYml0ZXMgb24gdHVyZiBhc3NlbWJsYWdlcywgd2UgY2FsY3VsYXRlZCB0aGUgbWVhbiB0dXJmIGhlaWdodCBhbmQgc2VkaW1lbnQgZGVwdGggZGlyZWN0bHkgYWRqYWNlbnQgdG8gZWFjaCBiaXRlLiBQcmlvciB0byBhbmFseXNpcywgcXVhbnRpdGF0aXZlIHZhcmlhYmxlcyAoZS5nLiwgc2VkaW1lbnQgZGVwdGggYW5kIHR1cmYgaGVpZ2h0KSB3ZXJlIHJlc2NhbGVkIHRvIHRoZSByYW5nZSBvZiAwIHRvIDEuIEluIGFkZGl0aW9uLCBxdWFudGl0YXRpdmUgYW5kIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyB3ZXJlIHJlc2NhbGVkIHN1Y2ggdGhhdCB0aGV5IHdvdWxkIGhhdmUgc2ltaWxhciBpbmZsdWVuY2UgdG8gdGhlIOKAmHByZXkgdmFyaWFibGVz4oCZIGJ5IGRpdmlkaW5nIGVhY2ggdmFyaWFibGUgYnkgdGhlIG51bWJlciBvZiBwcmV5IGNhdGVnb3JpZXMuIFJlc2NhbGVkIGRhdGEgd2VyZSB0aGVuIGFuYWx5c2VkIHZpYSBOTURTIHVzaW5nIGEgQnJheS1DdXJ0aXMgZGlzc2ltaWxhcml0eSBtYXRyaXguIAoKIyMjIE9ic2VydmF0aW9uYWwgZGF0YQoKRmlyc3QsIHdlIHJlYWQgaW4gYW5kIGRpc3BsYXkgdGhlIHRhYmxlIGRlc2NyaWJpbmcgdGhlIGZvcmFnaW5nIGVjb2xvZ3kgb2YgdGhlc2UgZmlzaC4KCiMjIyMgPGZvbnQgY29sb3I9InJlZCI+U3VwcGxlbWVudGFyeSBUYWJsZSAxPC9mb250PgoKYGBge3IgbWVhbl9iaXRlX2FuYWx5c2lzfQpsaWJyYXJ5KGdndGhlbWVzKQphbGxfdHJhaXRzIDwtIHJlYWQuY3N2KCJUQUJMRVMvSU5QVVQvTWVhbl9iaXRlX2NoYXJhY3RlcmlzdGljcy50eHQiLAogIGhlYWRlciA9IFRSVUUsIHNlcCA9ICJcdCIpCmlkcyA8LSBhbGxfdHJhaXRzWywgMToyXQoKd3JpdGUudGFibGUoYWxsX3RyYWl0cywgIlRBQkxFUy9PVVRQVVQvU1VQUC9UYWJsZV9TMS50eHQiLAogICAgICAgICAgICBzZXAgPSAiXHQiLCByb3cubmFtZXMgPSBGQUxTRSwgcXVvdGUgPSBGQUxTRSwKICAgICAgICAgICAgY29sLm5hbWVzID0gYygiSG9zdCBzcGVjaWVzIiwgIlNpdGUiLCAiU2VkaW1lbnQgZGVwdGggKG1tKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIlR1cmYgaGVpZ2h0KG1tKSIsICJQcm9wLiBtYXJrIG9uIHN1YnN0cmF0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIlByb3AuIHZlcnRpY2FsIiwgIlByb3AuIGNvbmNhdmUiLCAiUHJvcC4gY29udmV4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiQXJ0aWN1bGF0ZWQgcmVkIGNvcmFsbGluZSIsICJDQ0EvVHVyZiBvbiBDQ0EiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJEaWN0eW90YSIsICJFcGlwaHl0ZXMiLCAiR29yZ29uaWFuIiwgIkhhbGltZWRhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiTGF1cmVuY2lhIiwgIlNwb25nZSIsICJTdHlwb3BvZGl1bSIsICJUdXJmIikpCgpkYXRhdGFibGUoYWxsX3RyYWl0cywgcm93bmFtZXMgPSBGQUxTRSwgd2lkdGggPSAiMTAwJSIsCiAgICAgICAgICBjb2xuYW1lcyA9IGMoIkhvc3Qgc3BlY2llcyIsICJTaXRlIiwgIlNlZGltZW50IGRlcHRoIChtbSkiLAogICAgICAgICAgICAgICAgICAgICAgICJUdXJmIGhlaWdodChtbSkiLCAiUHJvcC4gbWFyayBvbiBzdWJzdHJhdGUiLAogICAgICAgICAgICAgICAgICAgICAgICJQcm9wLiB2ZXJ0aWNhbCIsICJQcm9wLiBjb25jYXZlIiwgIlByb3AuIGNvbnZleCIsCiAgICAgICAgICAgICAgICAgICAgICAgIkFydGljdWxhdGVkIHJlZCBjb3JhbGxpbmUiLCAiQ0NBL1R1cmYgb24gQ0NBIiwKICAgICAgICAgICAgICAgICAgICAgICAiRGljdHlvdGEiLCAiRXBpcGh5dGVzIiwgIkdvcmdvbmlhbiIsICJIYWxpbWVkYSIsCiAgICAgICAgICAgICAgICAgICAgICAgIkxhdXJlbmNpYSIsICJTcG9uZ2UiLCAiU3R5cG9wb2RpdW0iLCAidHVyZiIpLAogICAgICAgICAgY2FwdGlvbiA9IGh0bWx0b29sczo6dGFncyRjYXB0aW9uKAogICAgICAgICAgICBzdHlsZSA9ICJjYXB0aW9uLXNpZGU6IGJvdHRvbTsgdGV4dC1hbGlnbjogbGVmdDsiLAogICAgICAgICAgICAiU3VwcGxlbWVudGFyeSBUYWJsZSAxOiAiLAogICAgICAgICAgICBodG1sdG9vbHM6OmVtKCJJTlNFUlQgREVTQ1JJUFRJT04uIikpLAogICAgICAgICAgZXh0ZW5zaW9ucyA9ICJCdXR0b25zIiwKICAgICAgICAgIG9wdGlvbnMgPSBsaXN0KGNvbHVtbkRlZnMgPSBsaXN0KGxpc3QoCiAgICAgICAgICAgIGNsYXNzTmFtZSA9ICJkdC1sZWZ0IiwgdGFyZ2V0cyA9IDApKSwgZG9tID0gIkJscnRpcCIsCiAgICAgICAgICAgIHBhZ2VMZW5ndGggPSA1LCBsZW5ndGhNZW51ID0gYyg1LCAxMCwgMTUpLAogICAgICAgICAgICBidXR0b25zID0gYygiY3N2IiwgImNvcHkiKSwgc2Nyb2xsWCA9IFRSVUUsCiAgICAgICAgICAgIHNjcm9sbENvbGxhcHNlID0gVFJVRSkpCmBgYAoqKk5vdGUqKiBUYWJsZSBzY3JvbGxzIGhvcml6b250YWxseS4KCiMjIyBEYXRhIHNjYWxpbmcgJiBOTURTIGFuYWx5c2lzCgpOZXh0IHdlIGNvbmR1Y3QgdGhlICoqTk1EUyBhbmFseXNpcyoqIG9mIHRoZSBmZWVkaW5nIGRhdGEgdXNpbmcgICoqc3RhbmRhcmRpemUgdGhlIHZhcmlhYmxlcyoqIHNvIHRoYXQgdGhleSBoYXZlIHNpbWlsYXIgd2VpZ2h0cy4gT3VyIHByb2Nlc3MgaXMgYXMgZm9sbG93czogKiphKiopIHJlc2NhbGUgcXVhbnRpdGF0aXZlIHRyYWl0cyB0byBiZSBpbiB0aGUgcmFuZ2UgMCB0byAxIGFuZCBkaXZpZGUgYnkgdGhlIG51bWJlciBvZiBkaWV0IGNhdGVnb3JpZXMgdG8gaGF2ZSBzaW1pbGFyIGluZmx1ZW5jZSBhcyB0aGUgZGlldCB2YXJpYWJsZXM7ICoqYioqKSAgcmVzY2FsZSBhbGwgJ25vbiBkaWV0JyB0cmFpdHMgdG8gaGF2ZSBzaW1pbGFyIGluZmx1ZW5jZSB0byB0aGUgZGlldCB0cmFpdHMgYnkgZGl2aWRpbmcgYnkgdGhlIG51bWJlciBvZiBkaWV0IGNhdGVnb3JpZXMgZGl2aWRlZCBieSB0aGUgbnVtYmVyIG9mIGNhdGVnb3JpZXMgZm9yIGVhY2ggc3Vic3RyYXRlIGNoYXJhY3RlcmlzdGljOyAqKmMqKikgIGNvbWJpbmUgdGhlc2UgZGF0YSBpbnRvIGEgc2luZ2xlIGRhdGEgZnJhbWUgZm9yIE5NRFMgYW5hbHlzaXM7ICoqZCoqKSBydW4gKipOTURTIGFuYWx5c2lzKiogCgpgYGB7ciBzdGFuZGFyZGl6ZV9kaWV0X3ZhcmlhYmxlcywgcmVzdWx0cyA9ICdoaWRlJ30KIyBGaXJzdApxdWFudF90cmFpdHNfc3RkIDwtIGRlY29zdGFuZChhbGxfdHJhaXRzWywgMzo0XSwgInJhbmdlIikgLyAxMAojIFNlY29uZApNZWFuX3Byb3BfbWFya19vbl9zdWJzdHJhdGVfc3RkIDwtIGFsbF90cmFpdHNbLCA1XSAvICgxMCAvIDIpCnByb3BfdmVydGljYWxfc3RkIDwtIGFsbF90cmFpdHNbLCA2XSAvICgxMCAvIDIpCnByb3BfY29uY2F2ZV9zdGQgPC0gYWxsX3RyYWl0c1ssIDddIC8gKDEwIC8gMykKcHJvcF9jb252ZXhfc3RkIDwtIGFsbF90cmFpdHNbLCA4XSAvICgxMCAvIDMpCgphbGxfdHJhaXRzX3N0ZCA8LSBjYmluZChxdWFudF90cmFpdHNfc3RkLAogICAgICAgICAgICAgICAgICAgICAgICBNZWFuX3Byb3BfbWFya19vbl9zdWJzdHJhdGVfc3RkLAogICAgICAgICAgICAgICAgICAgICAgICBwcm9wX3ZlcnRpY2FsX3N0ZCwgcHJvcF9jb25jYXZlX3N0ZCwKICAgICAgICAgICAgICAgICAgICAgICAgcHJvcF9jb252ZXhfc3RkLCBhbGxfdHJhaXRzWywgOToxOF0pCm5tZHMgPC0gbWV0YU1EUyhhbGxfdHJhaXRzX3N0ZCwgZGlzdGFuY2UgPSAiYnJheSIsIGsgPSAzLCB0cnltYXggPSA0MCkKYGBgCgoKVGhlbiB3ZSBjb252ZXJ0IHRoZSBOTURTIGRhdGEgaW50byBhIGRhdGFmcmFtZSBhbmQgKippbnNwZWN0IHRoZSBTaGVwcGFyZCBwbG90KiouIAoKYGBge3IgZGlldF9OTURTX21vZHN9Ck5NRFMgPC0gZGF0YS5mcmFtZShOTURTMSA9IG5tZHMkcG9pbnRzWywgMV0sCiAgICAgICAgICAgICAgICAgICBOTURTMiA9IG5tZHMkcG9pbnRzWywgMl0sCiAgICAgICAgICAgICAgICAgICBNRFMzID0gbm1kcyRwb2ludHNbLCAzXSkKc3RyZXNzcGxvdChubWRzKQpgYGAKCkZpbmFsbHksIHdlICAqKmdlbmVyYXRlIHRoZSBlbnZpcm9ubWVudGFsIHZlY3RvcnMqKiAoY29ycmVsYXRpb25zIG9mIHZhcmlhYmxlcyB3aXRoIG9yZGluYXRpb24gYXhlcykuCgpgYGB7ciBnZXRfZW52X3ZlY3RvcnN9CnNldC5zZWVkKDEpCnZlY19zcCA8LSBlbnZmaXQobm1kcyRwb2ludHMsIGFsbF90cmFpdHNbLCAzOjE4XSwKICAgICAgICAgICAgICAgICBwZXJtID0gMTAwMCwgY2hvaWNlcyA9IGMoMSwgMiwgMykpCnNwcF9zY3JzIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKHZlY19zcCwgZGlzcGxheSA9ICJ2ZWN0b3JzIikpCnNwcF9zY3JzJHNwZWNpZXMgPC0gcm93bmFtZXMoc3BwX3NjcnMpCmNvbG5hbWVzKHNwcF9zY3JzKSA8LSBjKCJTX01EUzEiLCAiU19NRFMyIiwgIlNNRFMzIiwgInNwZWNpZXMiKQpgYGAKCk5vdyB3ZSBjYW4gIHBsb3QgdGhlIHJlc3VsdHMgYW5kIGdlbmVyYXRlICoqRmlndXJlIDEqKiBmcm9tIHRoZSBtYW51c2NyaXB0LiBGb3IgYWxsIGZpZ3VyZXMgZ2VuZXJhdGVkIGluIHRoaXMgd29ya2Zsb3csIHdlIGNvZGVkIGFzIG11Y2ggZm9ybWF0dGluZyBhcyB3ZSBjb3VsZCB3aXRoIFIgYW5kIHRoZW4gbWFkZSBtaW5vciBzdHlsaXN0aWMgY2hhbmdlcyBpbiBJbnNrc2NhcGUuIFRodXMsIHdoYXQgeW91IHNlZSBoZXJlIGFuZCB0aHJvdWdob3V0LCBhcmUgdGhlIHJhdyBmaWd1cmVzLiAKCmBgYHtyIG1lYW5fYml0ZV9pbml0aWFsX3Bsb3R9CiNQbG90IHJlc3VsdHMgdXNpbmcgZ2dwbG90MgojTWVyZ2Ugd2l0aCBkYXRhIHRoYXQgd2Ugd2FudCB0byB1c2UgaW4gcGxvdHRpbmcKTk1EUyA8LSBjYmluZChpZHMsIE5NRFMpCnN0dWZmIDwtIGdncGxvdChOTURTKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBOTURTMSwgeSA9IE5NRFMyLAogICAgICAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IFNpdGUsIGNvbG91ciA9IFNwZWNpZXMpLCBzaXplID0gNCkgKwogIGdlb21fc2VnbWVudChhZXMoeCA9IDAsIHkgPSAwLCB4ZW5kID0gU19NRFMxLCB5ZW5kID0gU19NRFMyKSwKICAgICAgICAgICAgICAgZGF0YSA9IHNwcF9zY3JzLCBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC41LCAiY20iKSksCiAgICAgICAgICAgICAgIGNvbG91ciA9ICJibGFjayIsIGluaGVyaXQuYWVzID0gRkFMU0UpICsKICBnZW9tX3RleHQoZGF0YSA9IHNwcF9zY3JzLCBhZXMoeCA9IFNfTURTMSwgeSA9IFNfTURTMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBzcGVjaWVzKSwgc2l6ZSA9IDMpICsKICBsYWJzKHRpdGxlID0gImJyYXkgZGlzdGFuY2Ugb24gYWxsIHRyYWl0cyAoc3RhbmRhcmRpemVkKSIsCiAgICAgICBzdWJ0aXRsZSA9ICJTdHJlc3MgPSAwLjA0IikKCiMjIyMjTm93IHN1YnNldCBqdXN0IHRoZSBzcHAuIHNjcnMgd2l0aCB0aGUgaGlnaGVzdCBjb3JyZWxhdGlvbnMKc3BwX3NjcnNfc3ViIDwtIHNwcF9zY3JzWy1jKDUsIDExLCAxMiksIF0KI0NhdGVnb3JpemUgc3BlY2llcyBzY29yZXMgaW50byBkaWZmZXJlbnQgdmFyaWFibGUgdHlwZXMgZm9yIHBsb3R0aW5nCnZhcmlhYmxlX3R5cGUgPC0gYXMuZmFjdG9yKGMocmVwKCJzdWJzdHJhdGUiLCA1KSwgcmVwKCJhbGdhZSIsIDgpKSkKc3BwX3NjcnNfc3ViIDwtIGNiaW5kKHZhcmlhYmxlX3R5cGUsIHNwcF9zY3JzX3N1YikKc3BwX3NjcnNfc3Vic3RyYXRlIDwtIHN1YnNldChzcHBfc2Nyc19zdWIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BwX3NjcnNfc3ViJHZhcmlhYmxlX3R5cGUgPT0gInN1YnN0cmF0ZSIpCnNwcF9zY3JzX2FsZ2FlIDwtIHN1YnNldChzcHBfc2Nyc19zdWIsCiAgICAgICAgICAgICAgICAgICAgICAgICBzcHBfc2Nyc19zdWIkdmFyaWFibGVfdHlwZSA9PSAiYWxnYWUiKQpgYGAKCgojIyMjIDxmb250IGNvbG9yPSJyZWQiPkZpZ3VyZSAxPC9mb250PgoKYGBge3IgbWVhbl9iaXRlX2ZpZ3VyZSwgZmlnLmFsaWduID0gImNlbnRlciIsIGZpZy5jYXAgPSAiRmlndXJlIDE6IEJyYXkgY3VydGlzIGRpc3RhbmNlIG9uIGFsbCB0cmFpdHM7IHN0cmVzcyA9IDAuMDQiLCBvdXQud2lkdGggPSAiOTAlIn0KZmlnXzEgPC0gZ2dwbG90KE5NRFMpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IE5NRFMxLCB5ID0gTk1EUzIsIHNoYXBlID0gU2l0ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gU3BlY2llcyksIHNpemUgPSA0KSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBzYW1wX3BhbCkgKwogIGdlb21fc2VnbWVudChhZXMoeCA9IDAsIHkgPSAwLCB4ZW5kID0gU19NRFMxLCB5ZW5kID0gU19NRFMyKSwKICAgICAgICAgICAgICAgZGF0YSA9IHNwcF9zY3JzX3N1YnN0cmF0ZSwKICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuNSwgImNtIikpLCBjb2xvciA9ICJyZWQiKSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBzcHBfc2Nyc19zdWJzdHJhdGUsIGFlcyh4ID0gU19NRFMxLCB5ID0gU19NRFMyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBzcGVjaWVzKSwKICAgICAgICAgICAgbnVkZ2VfeSA9IGMoLTAuMDI1LCAtMC4wMjUsIC0wLjA1LCAwLjA1LCAwLjA1KSkgKwogIGdlb21fc2VnbWVudChhZXMoeCA9IDAsIHkgPSAwLCB4ZW5kID0gU19NRFMxLCB5ZW5kID0gU19NRFMyKSwKICAgICAgICAgICAgICAgZGF0YSA9IHNwcF9zY3JzX2FsZ2FlLAogICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC41LCAiY20iKSksIGNvbG9yID0gImJsYWNrIikgKwogIGdlb21fdGV4dChkYXRhID0gc3BwX3NjcnNfYWxnYWUsIGFlcyh4ID0gU19NRFMxLCB5ID0gU19NRFMyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IHNwZWNpZXMpLAogICAgICAgICAgICBudWRnZV95ID0gYygtMC4wMjUsIDAuMDI1LCAwLjAyNSwgMC4wMjUsCiAgICAgICAgICAgICAgICAgICAgICAgIDAuMDI1LCAtMC4wMjUsIC0wLjA1LCAtMC4wMjUpKSArCiAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAxNSkKZmlnXzEgPC0gZmlnXzEgKyBjb29yZF9maXhlZCgpCmZpZ18xCnBkZigiRklHVVJFUy9PVVRQVVQvRmlndXJlXzEucGRmIikKZmlnXzEKaW52aXNpYmxlKGRldi5vZmYoKSkKYGBgCgoqKioKCjxhIGlkPSJQYXJ0IElJOiAxNlMgclJOQSBEYXRhIFByZXBhcmF0aW9uIj48L2E+IAoKIyMgUGFydCBJSTogRGF0YSBQcmVwYXJhdGlvbiAgCltiYWNrIHRvIHRvcF0oI2JhY2sgdG8gdG9wKQoKIyMjIERlZmluZSBncm91cGluZ3MKCjBrLCBvbiB0byB0aGUgbWljcm9iaWFsIGRhdGEuIEZpcnN0LCB3ZSBsb2FkIHRoZSBkYXRhIHBhY2tldCBwcm9kdWNlZCBieSB0aGUgZmluYWwgc3RlcCBvZiB0aGUgREFEQTIgd29ya2Zsb3cgKENvbWJpbmVfUnVucy5SbWQpLCBmb3JtYXQgc2FtcGxlIG5hbWVzLCBhbmQgZGVmaW5lIGdyb3VwaW5ncy4gV2Ugd2lsbCB1c2UgdGhlIHNhbXBsZSBuYW1lcyB0byBkZWZpbmUgdGhlIGRpZmZlcmVudCBncm91cHMuCgpgYGB7ciBkZWxpbmlhdGVfc2FtcGxlX3R5cGVzfQpsb2FkKCJjb21ib19waXBlbGluZS5yZGF0YSIpCnNhbXBsZXMub3V0IDwtIHJvd25hbWVzKHNlcXRhYikKc3ViamVjdCA8LSBzYXBwbHkoc3Ryc3BsaXQoc2FtcGxlcy5vdXQsICJbWzpkaWdpdDpdXSIpLCBgW2AsIDEpCiMgdGhpcyBzcGxpdHMgdGhlIHN0cmluZyBhdCBmaXJzdCBpbnN0YW5jZSBvZiBhIGRpZ2l0CiMgdXNlIHRoZSB3aG9sZSBzdHJpbmcgZm9yIGluZGl2aWR1YWxzCiMgdXNlIHRoZSBmaXJzdCB0d28gbGV0dGVycyBmb3IgZ2VudXMKIyB1c2UgdGhlIG5leHQgdGhyZWUgbGV0dGVycyBmb3Igc3BlY2llcwpzYW1wbGVfbmFtZSA8LSBzdWJzdHIoc2FtcGxlcy5vdXQsIDEsIDk5OSkKZ2VudXMgPC0gc3Vic3RyKHNhbXBsZXMub3V0LCAxLCAyKQpzcGVjaWVzIDwtIHN1YnN0cihzYW1wbGVzLm91dCwgMSwgNSkKYGBgCgo+IEdyb3VwcwoKKiBgciBsZW5ndGgoc2FtcGxlX25hbWUpYCBpbmRpdmlkdWFscwoqIGByIGxlbmd0aCh1bmlxdWUoZ2VudXMpKWAgZ2VuZXJhCiogYHIgbGVuZ3RoKHVuaXF1ZShzcGVjaWVzKSlgIHNwZWNpZXMKCkFuZCBmaW5hbGx5IHdlIGRlZmluZSBhIHNhbXBsZSBkYXRhIGZyYW1lIHRoYXQgaG9sZHMgdGhlIGRpZmZlcmVudCBncm91cHMgd2UgZXh0cmFjdGVkIGZyb20gdGhlIHNhbXBsZSBuYW1lcy4gT24gdGhlIHJpZ2h0IGFyZSBhIGZldyBzYW1wbGVzIGFuZCB0aGVpciBkaWZmZXJlbnQgZ3JvdXBzIG5hbWVzLiAKCmBgYHtyIGRlZmluZV92YXJpYWJsZXN9CiNkZWZpbmUgYSBzYW1wbGUgZGF0YSBmcmFtZQpzYW1kZiA8LSBkYXRhLmZyYW1lKFNhbU5hbWUgPSBzYW1wbGVfbmFtZSwgR2VuID0gZ2VudXMsIFNwID0gc3BlY2llcykKcm93bmFtZXMoc2FtZGYpIDwtIHNhbXBsZXMub3V0CmthYmxlKHNhbWRmW2MoMSwgMTMsIDIwLCAzMCwgNDQpLCAxOjNdLCByb3cubmFtZXMgPSBGQUxTRSkgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9ICJzdHJpcGVkIiwKICAgICAgICAgICAgICAgIGZ1bGxfd2lkdGggPSBGQUxTRSwgcG9zaXRpb24gPSAiZmxvYXRfcmlnaHQiKSAgJT4lCiAgY29sdW1uX3NwZWMoMTozLCB3aWR0aCA9ICIzLjVjbSIpCmBgYAoKCj4gQWJicmV2aWF0aW9uczogCgoqIEFjQ29lID0gKkFjYW50aHVydXMgY29ldWxldXMqCiogQWNUcmEgPSAqQWNhbnRodXJ1cyB0cmFjdHVzKgoqIFNjVGFlID0gKlNjYXJ1cyB0YWVuaW9wdGVydXMqCiogU3BBdXIgPSAqU3Bhcmlzb21hIGF1cm9mcmVuYXR1bSoKKiBTcFZpciA9ICpTcGFyaXNvbWEgdmlyaWRlKgoqIFNjVmV0ID0gKlNjYXJ1cyB2ZXR1bGEqCiogU3BDaHIgPSAqU3Bhcmlzb21hIGNocnlzb3B0ZXJ1bSoKCiMjIyBDcmVhdGUgJiBtb2RpZnkgYSBwaHlsb3NlcSBvYmplY3QKCk5leHQgd2UgY3JlYXRlIGEgcGh5bG9zZXEgKHBzKSBvYmplY3Qgd2l0aCB0aGUgU2lsdmEgKHNsdikgdGF4b25vbXkuIFRoZXJlIGlzIGFsc28gYSBHcmVlbmdlbmVzIChnZykgYW5ub3RhdGlvbiBpbiB0aGUgb3V0cHV0IGZpbGUgZnJvbSBEQURBMiB3aGljaCBjYW4gYmUgdXNlZCBpbnN0ZWFkIG9mICB0aGUgU2lsdmEgYW5ub3RhdGlvbi4gSnVzdCBjaGFuZ2UgYHRheF9zaWx2YWAgdG8gYHRheF9nZ2AuIEF0IHRoaXMgcG9pbnQgd2UgcmVuYW1lIHRoZSBhbXBsaWNvbiBzZXF1ZW5jZSB2YXJpYW50cyAoQVNWcykgc28gdGhlIGRlc2lnbmF0aW9ucyBhcmUgYSBiaXQgbW9yZSB1c2VyIGZyaWVuZGx5LiBCeSBkZWZhdWx0LCBEQURBMiBuYW1lcyBlYWNoIEFTViBieSBpdHMgdW5pcXVlIHNlcXVlbmNlIHNvIHRoYXQgZGF0YSBjYW4gYmUgZGlyZWN0bHkgY29tcGFyZWQgYWNyb3NzIHN0dWRpZXMgKHdoaWNoIGlzIGdyZWF0KS4gQnV0IHRoaXMgY29udmVudGlvbiBjYW4gIGdldCBjdW1iZXJzb21lIGRvd25zdHJlYW0sIHNvIHdlIHJlbmFtZSB0aGUgQVNWcyB1c2luZyBhIHNpbXBsZXIgY29udmVudGlvbi0tLUFTVjEsIEFTVjIsIEFTVjMsIGFuZCBzbyBvbiwgd2hpbGUgcmV0YWluaW5nIHRoZSBleGFjdCBzZXF1ZW5jZXMuIAoKClRoZSBwaHlsb3NlcSBvYmplY3QgbG9va3MgbGlrZSB0aGlzOgoKYGBge3IgY3JlYXRlX3BzX29iamVjdH0KIyB0aGlzIGNyZWF0ZSB0aGUgcGh5bG9zZXEgb2JqZWN0CnBzX3NsdiA8LSBwaHlsb3NlcShvdHVfdGFibGUoc2VxdGFiLCB0YXhhX2FyZV9yb3dzID0gRkFMU0UpLAogICAgICAgICAgICAgICAgICAgc2FtcGxlX2RhdGEoc2FtZGYpLCB0YXhfdGFibGUodGF4X3NpbHZhKSkKdGF4X3RhYmxlKHBzX3NsdikgPC0gY2JpbmQodGF4X3RhYmxlKHBzX3NsdiksIHJvd25hbWVzKHRheF90YWJsZShwc19zbHYpKSkKIyBhZGRpbmcgdW5pcXVlIEFTViBuYW1lcwp0YXhhX25hbWVzKHBzX3NsdikgPC0gcGFzdGUwKCJBU1YiLCBzZXEobnRheGEocHNfc2x2KSkpCnRheF90YWJsZShwc19zbHYpIDwtIGNiaW5kKHRheF90YWJsZShwc19zbHYpLCByb3duYW1lcyh0YXhfdGFibGUocHNfc2x2KSkpCnBzX3NsdgpgYGAKCldoaWxlIHRoZSBBU1YgbmFtZXMgbG9vayBsaWtlIHRoaXM6IGByIGhlYWQodGF4YV9uYW1lcyhwc19zbHYpKWAgYW5kIHNvIG9uLi4uCgpBdCB0aGlzIHBvaW50IHdlIGhhdmUgYSBjb21wbGV0ZWx5IHVuYWR1bHRlcmF0ZWQgcGh5bG9zZXEgb2JqZWN0IGJlY2F1c2UgaXQgY29udGFpbnMgYWxsICBBU1ZzIGFuZCBhbGwgc2FtcGxlcy4gV2UgYWRkIHR3byBmaW5hbCBjb2x1bW5zIHdpdGggdGhlIGFjdHVhbCBBU1Ygc2VxdWVuY2VzIGFuZCBBU1YgSURzLiBUaGlzIHdpbGwgYmUgdXNlZnVsIGxhdGVyIHdoZW4gdHJ5aW5nIHRvIGV4cG9ydCBhIGZhc3RhIGZpbGUuIEZpbmFsbHksIHdlIGV4cG9ydCB0aGUgc2VxdWVuY2UgYW5kIHRheG9ub215IHRhYmxlcywgZm9yIHBvc3Rlcml0eSBzYWtlLiAKCmBgYHtyIGV4cG9ydF9zZXFfdGF4X3RhYmxlc30KY29sbmFtZXModGF4X3RhYmxlKHBzX3NsdikpIDwtIGMoIktpbmdkb20iLCAiUGh5bHVtIiwgIkNsYXNzIiwgIk9yZGVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkZhbWlseSIsICJHZW51cyIsICJBU1ZfU0VRIiwgIkFTVl9JRCIpCndyaXRlLnRhYmxlKHRheF90YWJsZShwc19zbHYpLCAiVEFCTEVTL09VVFBVVC9QUy9mdWxsX3RheF90YWJsZS50eHQiLAogICAgICAgICAgICBzZXAgPSAiXHQiLCBxdW90ZSA9IEZBTFNFLCBjb2wubmFtZXMgPSBOQSkKd3JpdGUudGFibGUodChvdHVfdGFibGUocHNfc2x2KSksICJUQUJMRVMvT1VUUFVUL1BTL2Z1bGxfc2VxX3RhYmxlLnR4dCIsCiAgICAgICAgICAgIHNlcCA9ICJcdCIsIHF1b3RlID0gRkFMU0UsIGNvbC5uYW1lcyA9IE5BKQp3cml0ZS50YWJsZShzYW1wbGVfZGF0YShwc19zbHYpLCAiVEFCTEVTL09VVFBVVC9QUy9mdWxsX3NhbXBsZV9kYXRhLnR4dCIsCiAgICAgICAgICAgIHNlcCA9ICJcdCIsIHF1b3RlID0gRkFMU0UsIHJvdy5uYW1lcyA9ICBGQUxTRSkKYGBgCgpSZW1lbWJlciB0aHJlZSBvZiB0aGVzZSBzYW1wbGVzIHdlcmUgb21pdHRlZCBiZWNhdXNlIHdlIGRpZCBub3QgaGF2ZSByZXBsaWNhdGVzIGZvciB0aGUgaG9zdCBzcGVjaWVzLiBMZXRzIHJlbW92ZSB0aG9zZSBzYW1wbGVzLiBUaGUgb25seSB3YXkgd2UgY291bGQgZmlndXJlIG91dCBob3cgdG8gZG8gdGhpcyB3YXMgYnkgc2VsZWN0aW5nIHRoZSBzYW1wbGVzIHdlICp3YW50ZWQgdG8ga2VlcCouIElmIHlvdSB3YW50IHRvIGNoYW5nZSB0aGUgZ3JvdXAgb2Ygc2FtcGxlcywgbW9kaWZ5IHRoZSBzY3JpcHQgYWNjb3JkaW5nbHkuCgpgYGB7ciBzZWxlY3Rfc2FtcGxlc30KcHNfc2x2X2Jhc2UgPC0gcHJ1bmVfc2FtcGxlcyhjKCJTcEF1cjAxIiwgIlNwQXVyMDIiLCAiU3BBdXIwMyIsICJTcEF1cjA0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTcEF1cjEwIiwgIlNwQXVyMTEiLCAiU3BBdXIxMiIsICJTcEF1cjEzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTcFZpcjAxIiwgIlNwVmlyMDIiLCAiU3BWaXIwMyIsICJTcFZpcjA0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTcFZpcjA1IiwgIlNwVmlyMDYiLCAiU3BWaXIwNyIsICJTcFZpcjA4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTcFZpcjA5IiwgIlNwVmlyMTAiLCAiU3BWaXIxMSIsICJBY0NvZTAxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBY0NvZTAyIiwgIkFjQ29lMDMiLCAiQWNDb2UwNCIsICJBY0NvZTA1IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBY0NvZTA2IiwgIkFjQ29lMDciLCAiQWNDb2UwOCIsICJBY1RyYTAxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBY1RyYTAyIiwgIkFjVHJhMDMiLCAiQWNUcmEwNCIsICJBY1RyYTA1IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBY1RyYTA2IiwgIkFjVHJhMDciLCAiQWNUcmEwOCIsICJBY1RyYTA5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTY1RhZTAxIiwgIlNjVGFlMDIiLCAiU2NUYWUwMyIsICJTY1RhZTA0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTY1RhZTA1IiwgIlNjVGFlMDYiLCAiU2NUYWUwNyIsICJTY1RhZTA4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTY1RhZTA5IiwgIlNwQXVyMDUiLCAiU3BBdXIwNiIsICJTcEF1cjA3IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTcEF1cjA4IiwgIlNwQXVyMDkiKSwgcHNfc2x2KQpwc19zbHZfYmFzZQpgYGAKCjBLLCB0aHJlZSBzYW1wbGVzIGdvbmUuIEJ1dCB3ZSBwcm9iYWJseSBsb3N0IHNvbWUgQVNWcyB3aGVuIHVzZSB3ZSByZW1vdmVkIHNhbXBsZXMuIFNvIHdlIG5lZWQgdG8gZ2V0IHJpZCBvZiBhbnkgQVNWcyB0aGF0IGhhdmUgbm93IGEgdG90YWwgb2YgKiowIHJlYWRzKiouIFRoaXMgd2lsbCBiZSBvdXIgd29ya2luZyBwaHlsb3NlcSBvYmplY3QuIAoKYGBge3IgcmVtb3ZlX0FTVl93aXRoX3plcm9zX3JlYWRzfQpwc19zbHZfd29yayA8LSBwcnVuZV90YXhhKHRheGFfc3Vtcyhwc19zbHZfYmFzZSkgPiAwLCBwc19zbHZfYmFzZSkKcHNfc2x2X3dvcmsKYGBgCgpHcmVhdCwgdGhlcmUgd2VyZSAgKipgciBudGF4YShwc19zbHZfYmFzZSkgLSBudGF4YShwc19zbHZfd29yaylgIEFTVnMqKiBmb3VuZCBvbmx5IGluIHRob3NlIHRocmVlIHNhbXBsZXMuIAoKV2UgY2FuIGFsc28gZXhwb3J0IHNlcSBhbmQgdGF4IHRhYmxlcyBmb3Igb3VyIHRyaW1tZWQgZGF0YXNldCBhbmQgZ2V0IGEgcXVpY2sgc3VtbWFyeSBvZiB0aGUgdHJpbW1lZCBkYXRhc2V0IGJlZm9yZSByZW1vdmluZyB1bndhbnRlZCByZWFkcy4gLgoKYGBge3IgZ2VuX3N0YXRzX3JhdywgZXZhbCA9IFRSVUUsIGluY2x1ZGUgPSBUUlVFfQp3cml0ZS50YWJsZSh0YXhfdGFibGUocHNfc2x2X3dvcmspLCAiVEFCTEVTL09VVFBVVC9QUy90cmltX3RheF90YWJsZS50eHQiLCAKICAgICAgICAgICAgc2VwID0gIlx0IiwgcXVvdGUgPSBGQUxTRSwgY29sLm5hbWVzID0gTkEpCndyaXRlLnRhYmxlKHQob3R1X3RhYmxlKHBzX3Nsdl93b3JrKSksICJUQUJMRVMvT1VUUFVUL1BTL3RyaW1fc2VxX3RhYmxlLnR4dCIsIAogICAgICAgICAgICBzZXAgPSAiXHQiLCBxdW90ZSA9IEZBTFNFLCBjb2wubmFtZXMgPSBOQSkKd3JpdGUudGFibGUoc2FtcGxlX2RhdGEocHNfc2x2X3dvcmspLCAiVEFCTEVTL09VVFBVVC9QUy90cmltX3NhbXBsZV9kYXRhLnR4dCIsIAogICAgICAgICAgICBzZXAgPSAiXHQiLCBxdW90ZSA9IEZBTFNFLCByb3cubmFtZXMgPSAgRkFMU0UpCgojIGdlbmVyYWwgc3RhdHMgZm9yIHRoZSBkYXRhc2V0LgoKc2FtcGxlX3N1bV9kZl9yYXcgPC0gZGF0YS5mcmFtZShzdW0gPSBzYW1wbGVfc3Vtcyhwc19zbHZfd29yaykpCnRvdGFsX3JlYWRzX3JhdyA8LSBzdW0ob3R1X3RhYmxlKHBzX3Nsdl93b3JrKSkKc21pbl9yYXcgPC0gYXMuaW50ZWdlcihtaW4oc2FtcGxlX3N1bXMocHNfc2x2X3dvcmspKSkKc21lYW5fcmF3IDwtIGFzLmludGVnZXIobWVhbihzYW1wbGVfc3Vtcyhwc19zbHZfd29yaykpKQpzbWF4X3JhdyA8LSBhcy5pbnRlZ2VyKG1heChzYW1wbGVfc3Vtcyhwc19zbHZfd29yaykpKQpgYGAKCkxvb2tzIGxpa2UgdGhlIHRvdGFsIG51bWJlciBvZiByZWFkcyBpbiB0aGUgZGF0YXNldCAoYWZ0ZXIgcmVtb3ZpbmcgdW53YW50ZWQgc2FtcGxlcykgaXMgKipgciB0b3RhbF9yZWFkc19yYXdgKio7IHJhbmdlIG9mIGByIHNtaW5fcmF3YCB0byBgciBzbWF4X3Jhd2AgcmVhZHMgcGVyIHNhbXBsZSBhbmQgYW4gYXZlcmFnZSBvZiBgciBzbWVhbl9yYXdgIHJlYWRzIHBlciBzYW1wbGUuCgojIyMgUmVtb3ZlIGNvbnRhbWluYW50cwoKVGhlc2Ugc2FtcGxlcyBhcmUgaW50ZXN0aW5hbCBjb21tdW5pdGllcyBhbmQgd2UgYXNzdW1lIHRoYXQgQ2hsb3JvcGxhc3QgYXJlIG5vdCBjb250cmlidXRpbmcgdG8gbWV0YWJvbGlzbS4gVGhlc2UgZGF0YSBjb3VsZCBiZSB1c2VmdWwgbGF0ZXIgYnV0IGZvciBub3cgbGV0cyBjcmVhdGUgYSBwaHlsb3NlcSBvYmplY3Qgd2l0aG91dCBDaGxvcm9wbGFzdC4KCjxmb250IHNpemU9IjMiIGNvbG9yPSJyZWQiPldBUk5JTkc8L2ZvbnQ+OiB0aGUgYHN1YnNldF90YXhhYCBjb21tYW5kICByZW1vdmVzIGFueXRoaW5nIHRoYXQgaXMgYE5BYCBmb3IgdGhlIHNwZWNpZmllZCB0YXhvbm9taWMgbGV2ZWwgb3IgYWJvdmUuICoqRm9yIGV4YW1wbGUqKiwgbGV0cyBzYXkgeW91IHJ1biAgdGhlICBgc3Vic2V0X3RheGFgIGNvbW1hbmQgdXNpbmcgYE9yZGVyICE9ICJDaGxvcm9wbGFzdCJgLiBTZWVtcyBsaWtlIHlvdSBzaG91bGQgZ2V0IGEgcGh5bG9zZXEgb2JqZWN0IHdpdGggZXZlcnl0aGluZyBleGNlcHQgIENobG9yb3BsYXN0LiBCdXQgYWN0dWFsbHkgdGhlIGNvbW1hbmQgbm90IG9ubHkgZ2V0cyByaWQgQ2hsb3JvcGxhc3QgYnV0IGV2ZXJ5dGhpbmcgIGVsc2UgdGhhdCBoYXMgYE5BYCBmb3IgT3JkZXIgYW5kIGFib3ZlLiBJbiBvdXIgZXhwZXJpZW5jZSB0aGlzIGlzIG5vdCB3ZWxsIGRvY3VtZW50ZWQgYW5kIHdlIGhhZCB0byAgZGlnIHRocm91Z2ggdGhlIGZpbGVzIHRvIGZpZ3VyZSBvdXQgd2hhdCB3YXMgaGFwcGVuaW5nLgoKT3VyIGRhdGFzZXQgaGFzIDU5MCBDaGxvcm9wbGFzdCBBU1ZzIGFuZCBydW5uaW5nIHRoZSAgY29tbWFuZCBhcyBpcyByZW1vdmVkIGFuIGFkZGl0aW9uYWwgMTI0NCBBU1ZzLiAgU28gbGV0cyBzZWUgaWYgd2UgY2FuIGdldCByaWQgb2YganVzdCBDaGxvcm9wbGFzdCBBU1ZzIHdpdGhvdXQgcmVtb3ZpbmcgZXZlcnl0aGluZyB0aGF0IGlzIHVuY2xhc3NpZmllZCBhdCBPcmRlciBhbmQgYWJvdmUuIFRvIGRvIHRoaXMsIHdlIHN1YnNldCB0aGUgdGF4YSB0byBnZW5lcmF0ZSBhIHBzIG9iamVjdCBvZiBqdXN0IENobG9yb3BsYXN0LCBzZWxlY3RlZCB0aGUgQVNWIGNvbHVtbiBvbmx5LCB0dXJuZWQgaXQgaW50byBhIGZhY3RvciwgYW5kIHVzZWQgdGhpcyB0byByZW1vdmUgQ2hsb3JvcGxhc3QgZnJvbSB0aGUgcHMgb2JqZWN0LiAKCmBgYHtyIHJlbW92ZV9jeWFub30KIyBnZW5lcmF0ZSBhIGZpbGUgd2l0aCBDaGxvcm9wbGFzdCBBU1ZzCmNobG9yb19wX3BzIDwtIHN1YnNldF90YXhhKHBzX3Nsdl93b3JrLCBPcmRlciA9PSAiQ2hsb3JvcGxhc3QiKQpjaGxvcm9fcF90YWIgPC0gIGFzKHRheF90YWJsZShjaGxvcm9fcF9wcyksICJtYXRyaXgiKQpjaGxvcm9fcF90YWIgPC0gY2hsb3JvX3BfdGFiWywgOF0KY2hsb3JvX3BfZGYgPC0gYXMuZmFjdG9yKGNobG9yb19wX3RhYikKZ29vZFRheGFDSCA8LSBzZXRkaWZmKHRheGFfbmFtZXMocHNfc2x2X3dvcmspLCBjaGxvcm9fcF9kZikKcHNfc2x2X3dvcmtfbm9fY3lhbm8gPC0gcHJ1bmVfdGF4YShnb29kVGF4YUNILCBwc19zbHZfd29yaykKcHNfc2x2X3dvcmtfbm9fY3lhbm8KIyMjIyMjIFN1bW1hcml6ZSBkYXRhCnRvdGFsX2Fzdl9jaGxvcm9fcCA8LSBsZW5ndGgoY2hsb3JvX3BfZGYpCgpzYW1wbGVfc3VtX2NobG9yb19wX3BzIDwtIGRhdGEuZnJhbWUoc3VtID0gc2FtcGxlX3N1bXMoY2hsb3JvX3BfcHMpKQp0b3RhbF9yZWFkc19jaGxvcm9fcF9wcyA8LSBzdW0ob3R1X3RhYmxlKGNobG9yb19wX3BzKSkKc21pbl9jaGxvcm9fcF9wcyA8LSBtaW4oc2FtcGxlX3N1bXMoY2hsb3JvX3BfcHMpKQpzbWVhbl9jaGxvcm9fcF9wcyA8LSBtZWFuKHNhbXBsZV9zdW1zKGNobG9yb19wX3BzKSkKc21heF9jaGxvcm9fcF9wcyA8LSBtYXgoc2FtcGxlX3N1bXMoY2hsb3JvX3BfcHMpKQoKd3JpdGUudGFibGUodGF4X3RhYmxlKGNobG9yb19wX3BzKSwgCiAgICAgICAgICAgICJUQUJMRVMvT1VUUFVUL1BTL2NobG9yb3BsYXN0X3RheF90YWJsZS50eHQiLCAKICAgICAgICAgICAgc2VwID0gIlx0IiwgcXVvdGUgPSBGQUxTRSwgY29sLm5hbWVzID0gTkEpCndyaXRlLnRhYmxlKHQob3R1X3RhYmxlKGNobG9yb19wX3BzKSksIAogICAgICAgICAgICAiVEFCTEVTL09VVFBVVC9QUy9jaGxvcm9wbGFzdF9zZXFfdGFibGUudHh0IiwgCiAgICAgICAgICAgIHNlcCA9ICJcdCIsIHF1b3RlID0gRkFMU0UsIGNvbC5uYW1lcyA9IE5BKQp3cml0ZS50YWJsZShzYW1wbGVfZGF0YShjaGxvcm9fcF9wcyksIAogICAgICAgICAgICAiVEFCTEVTL09VVFBVVC9QUy9jaGxvcm9wbGFzdF9zYW1wbGVfZGF0YS50eHQiLCAKICAgICAgICAgICAgc2VwID0gIlx0IiwgcXVvdGUgPSBGQUxTRSwgcm93Lm5hbWVzID0gIEZBTFNFKQoKYGBgCgpUaGlzIHN0ZXAgcmVtb3ZlZCAqKmByIHRvdGFsX2Fzdl9jaGxvcm9fcGAgQ2hsb3JvcGxhc3QgQVNWcyoqIGVuY29tcGFzc2luZyAqKmByIHRvdGFsX3JlYWRzX2NobG9yb19wX3BzYCB0b3RhbCByZWFkcyoqLiBQZXJmZWN0LgoKQW5kIG5vdyB3ZSB1c2UgdGhlIHNhbWUgYXBwcm9hY2ggdG8gcmVtb3ZlIE1pdG9jaG9uZHJpYS4gCgpgYGB7ciByZW1vdmVfc3BlY2lmaWNfdGF4YX0KIyBnZW5lcmF0ZSBhIGZpbGUgd2l0aCBtaXRvY2hvbmRyaWEgQVNWcwpNVDFfcHMgPC0gc3Vic2V0X3RheGEocHNfc2x2X3dvcmtfbm9fY3lhbm8sIEZhbWlseSA9PSAiTWl0b2Nob25kcmlhIikKTVQxIDwtICBhcyh0YXhfdGFibGUoTVQxX3BzKSwgIm1hdHJpeCIpCk1UMSA8LSBNVDFbLCA4XQpNVDFkZiA8LSBhcy5mYWN0b3IoTVQxKQpnb29kVGF4YSA8LSBzZXRkaWZmKHRheGFfbmFtZXMocHNfc2x2X3dvcmtfbm9fY3lhbm8pLCBNVDFkZikKcHNfc2x2X3dvcmtfZmlsdCA8LSBwcnVuZV90YXhhKGdvb2RUYXhhLCBwc19zbHZfd29ya19ub19jeWFubykKcHNfc2x2X3dvcmtfZmlsdAojIyMjIyMgU3VtbWFyaXplIGRhdGEKdG90YWxfYXN2X01UMSA8LSBsZW5ndGgoTVQxZGYpCiMgY29sbmFtZXModGF4X3RhYmxlKE1UMV9wcykpCnNhbXBsZV9zdW1fTVQxX3BzIDwtIGRhdGEuZnJhbWUoc3VtID0gc2FtcGxlX3N1bXMoTVQxX3BzKSkKdG90YWxfcmVhZHNfTVQxX3BzIDwtIHN1bShvdHVfdGFibGUoTVQxX3BzKSkKc21pbl9NVDFfcHMgPC0gbWluKHNhbXBsZV9zdW1zKE1UMV9wcykpCnNtZWFuX01UMV9wcyA8LSBtZWFuKHNhbXBsZV9zdW1zKE1UMV9wcykpCnNtYXhfTVQxX3BzIDwtIG1heChzYW1wbGVfc3VtcyhNVDFfcHMpKQpgYGAKClN3ZWV0LCBsb29rcyBsaWtlIHRoaXMgcmVtb3ZlZCAqKmByIHRvdGFsX2Fzdl9NVDFgIE1pdG9jaG9uZHJpYSBBU1ZzKiogZW5jb21wYXNzaW5nICoqYHIgdG90YWxfcmVhZHNfTVQxX3BzYCB0b3RhbCByZWFkcyoqLiAKCmBgYHtyIGdlbl9zdGF0cywgZXZhbCA9IFRSVUUsIGluY2x1ZGUgPSBUUlVFfQojIGdlbmVyYWwgc3RhdHMgZm9yIHRoZSBkYXRhc2V0LgojY29sbmFtZXModGF4X3RhYmxlKHBzX3Nsdl93b3JrX2ZpbHQpKQpzYW1wbGVfc3VtX2RmIDwtIGRhdGEuZnJhbWUoc3VtID0gc2FtcGxlX3N1bXMocHNfc2x2X3dvcmtfZmlsdCkpCnRvdGFsX3JlYWRzIDwtIHN1bShvdHVfdGFibGUocHNfc2x2X3dvcmtfZmlsdCkpCnNtaW4gPC0gYXMuaW50ZWdlcihtaW4oc2FtcGxlX3N1bXMocHNfc2x2X3dvcmtfZmlsdCkpKQpzbWVhbiA8LSBhcy5pbnRlZ2VyKG1lYW4oc2FtcGxlX3N1bXMocHNfc2x2X3dvcmtfZmlsdCkpKQpzbWF4IDwtIGFzLmludGVnZXIobWF4KHNhbXBsZV9zdW1zKHBzX3Nsdl93b3JrX2ZpbHQpKSkKYGBgCgpBZnRlciByZW1vdmluZyBjb250YW1pbmFudHMgaGVyZSBpcyB3aGF0IHRoZSBmaW5hbCBkYXRhc2V0IGxvb2tzIGxpa2U6CgoqIFRvdGFsIG51bWJlciBvZiByZWFkcyBpbiB0aGUgZGF0YXNldCBpcyAqKmByIHRvdGFsX3JlYWRzYCoqLgoqIFJhbmdlIG9mICoqYHIgc21pbmAqKiB0byAqKmByIHNtYXhgKiogcmVhZHMgcGVyIHNhbXBsZS4KKiBBdmVyYWdlIG9mICoqYHIgc21lYW5gKiogcmVhZHMgcGVyIHNhbXBsZS4KCiMjIyBQaHlsb3NlcSBvYmplY3QgbWVyZ2VkIGJ5IHNwZWNpZXMKCk9uZSBsYXN0IHRoaW5nIHRvIGRvIGlzIHRvIGNyZWF0ZSBhIG1lcmdlZCBwaHlsb3NlcSBvYmplY3Qgd2hlcmUgc2FtcGxlcyBhcmUgZ3JvdXBlZCBieSBob3N0IHNwZWNpZXMuIFRoaXMgd2lsbCBjb21lIGluIGhhbmR5IGxhdGVyIGZvciBzb21lIGFuYWx5c2VzLiAgCgpgYGB7ciBtZXJnZX0KbWVyZ2VkR1AgPC0gbWVyZ2Vfc2FtcGxlcyhwc19zbHZfd29ya19maWx0LCAiU3AiKQpTRCA8LSBtZXJnZV9zYW1wbGVzKHNhbXBsZV9kYXRhKHBzX3Nsdl93b3JrX2ZpbHQpLCAiU3AiKQptZXJnZWRHUApgYGAKCkdyZWF0LCBzdGlsbCB0aGUgc2FtZSBudW1iZXIgb2YgQVNWcyBhbmQgbm93IG9ubHkgNSAic2FtcGxlcyIgY29ycmVzcG9uZGluZyB0byB0aGUgNSBzcGVjaWVzOiBgciBzYW1wbGVfbmFtZXMobWVyZ2VkR1ApYC4gCgpUaGVyZSBhcmUgbm93IHRoZSBzZXZlcmFsIHBoeWxvc2VxIG9iamVjdHMgdG8gY2hvc2UgZnJvbSBhbmQsIHVzaW5nIHRoZSBhYm92ZSBtZXRob2RzLCBhZGRpdGlvbmFsIG9iamVjdHMgY2FuIGVhc2lseSBiZSBjcmVhdGVkLiAKCiogYHBzX3NsdmAgLS0+IHBoeWxvc2VxIGRhdGFzZXQgd2l0aCBhbGwgYHIgbnNhbXBsZXMocHNfc2x2KWAgc2FtcGxlcywgYWxsIEFTVnMuCiogYHBzX3Nsdl9iYXNlYCAtLT4gcGh5bG9zZXEgZGF0YXNldCB3aXRoIGByIG5zYW1wbGVzKHBzX3Nsdl9iYXNlKWAgc2FtcGxlcywgYWxsIEFTVnMgKHRoaXMgaXMgbm90IHZlcnkgdXNlZnVsKS4KKiBgcHNfc2x2X3dvcmtgIC0tPiBwaHlsb3NlcSBkYXRhc2V0IHdpdGggYHIgbnNhbXBsZXMocHNfc2x2X3dvcmspYCBzYW1wbGVzLCB6ZXJvLXJlYWQgQVNWcyByZW1vdmVkLgoqIGBwc19zbHZfd29ya19maWx0YCAtLT4gcGh5bG9zZXEgZGF0YXNldCB3aXRoIGByIG5zYW1wbGVzKHBzX3Nsdl93b3JrX2ZpbHQpYCBzYW1wbGVzLCBBU1ZzIGFuZCByZWFkcyBmcm9tIE1pdG9jaG9uZHJpYSBhbmQgQ2hsb3JvcGxhc3QgcmVtb3ZlZC4KKiBgbWVyZ2VkR1BgIC0tPiBgcHNfc2x2X3dvcmtfZmlsdGAgcGh5bG9zZXEgZGF0YXNldCBjb2xsYXBzZWQgYnkgaG9zdCBzcGVjaWVzLgoKSGVyZSB3ZSBjYW4gc2F2ZSBzb21lIHBoeWxvc2VxIG9iamVjdHMgc28gd2UgY2FuIG1ha2Ugc29tZSBTaGlueSBBcHBzIGF0IHNvbWUgcG9pbnQuCgpgYGB7ciBzYXZlX3BzX29iamVjdHN9CnNhdmUocHNfc2x2X3dvcmtfZmlsdCwgbWVyZ2VkR1AsIGZpbGUgPSAiUFNfT0JKRUNUUy9wcy5SRGF0YSIpCnNhdmVSRFMocHNfc2x2X3dvcmtfZmlsdCwgIlBTX09CSkVDVFMvcHNfc2x2X3dvcmtfZmlsdC5yZHMiKQpzYXZlUkRTKG1lcmdlZEdQLCAiUFNfT0JKRUNUUy9tZXJnZWRHUC5yZHMiKQpgYGAKCiMjIyBIb3N0IEluZm9ybWF0aW9uCgpCZWZvcmUgd2UgZG8gYW55dGhpbmcgZWxzZSwgbGV0cyBnZW5lcmF0ZSBzdW1tYXJ5IGRhdGEgZm9yIGVhY2ggaG9zdC4gV2UgY2FuIGdlbmVyYXRlIGEgIHN1bW1hcnkgcmVwb3J0IGZvciBhbnkgIHBzIG9iamVjdCBidXQgd2Ugd2lsbCB1c2UgdGhlIG9iamVjdCB3aXRoIG1pdG9jaG9uZHJpYSBhbmQgY2hsb3JwbGFzdHMgcmVtb3ZlZCwgYXMgd2VsbCBhcyB0aGUgbG93IHJlcGxpY2F0ZSBob3N0IHNwZWNpZXMgcmVtb3ZlZC4gV2Ugd2lsbCBhbHNvIGFkZCBkZXRhaWxzIGFib3V0IGVhY2ggaG9zdC4gVGhlIHRhYmxlIGlzIGRpc3BsYXllZCBiZWxvdy4gV2UgY2FuIHVzZSB0aGVzZSBkYXRhIHdoZW4gd2UgdXBsb2FkIHRoZSBvcmlnaW5hbCBmYXN0cSBmaWxlcyB0byBzZXF1ZW5jZSByZWFkIGFyY2hpdmVzLiBMYXRlciBvbiB3ZSB3aWxsIGFsc28gYWRkIGFscGhhIGRpdmVyc2l0eSBzdGF0cyBhbmQgc2F2ZSB0aGUgdGFibGUuCgoqKioKCiMjIyMgSG9zdCBkZXRhaWxzCgpgYGB7ciBzYW1wbGVfc3VtbWFyeV90YWJsZSwgd2FybmluZyA9IEZBTFNFLCBmaWcuYWxpZ24gPSAiY2VudGVyIn0KdG90YWxfcmVhZHMgPC0gc2FtcGxlX3N1bXMocHNfc2x2X3dvcmtfZmlsdCkKdG90YWxfcmVhZHMgPC0gYXMuZGF0YS5mcmFtZSh0b3RhbF9yZWFkcywgbWFrZS5uYW1lcyA9IFRSVUUpCnRvdGFsX3JlYWRzIDwtIHRvdGFsX3JlYWRzICU+JSByb3duYW1lc190b19jb2x1bW4oImhvc3RfSUQiKQoKdG90YWxfYXN2cyA8LSBlc3RpbWF0ZV9yaWNobmVzcyhwc19zbHZfd29ya19maWx0LCBtZWFzdXJlcyA9ICJPYnNlcnZlZCIpCnRvdGFsX2FzdnMgPC0gdG90YWxfYXN2cyAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCJob3N0X0lEIikKCnNhbV9kZXRhaWxzIDwtIHNhbXBsZV9kYXRhKHBzX3NsdikKc2FtX2RldGFpbHMgPC0gc2FtX2RldGFpbHMgJT4lIG11dGF0ZShnZW51cyA9IGNhc2Vfd2hlbigKICAgIEdlbiA9PSAiQWMiIH4gIkFjYW50aHVydXMiLCAKICAgIEdlbiA9PSAiU2MiIH4gIlNjYXJ1cyIsCiAgICBHZW4gPT0gIlNwIiB+ICJTcGFyaXNvbWEiKSkKCnNhbV9kZXRhaWxzIDwtIHNhbV9kZXRhaWxzICU+JSBtdXRhdGUoc3BlY2llcyA9IGNhc2Vfd2hlbigKICAgIFNwID09ICJBY0NvZSJ+ICJjb2VydWxldXMiLAogICAgU3AgPT0gIkFjVHJhIn4gInRyYWN0dXMiLAogICAgU3AgPT0gIlNjVGFlIn4gInRhZW5pb3B0ZXJ1cyIsCiAgICBTcCA9PSAiU3BBdXIifiAiYXVyb2ZyZW5hdHVtIiwKICAgIFNwID09ICJTcFZpciJ+ICJ2aXJpZGUiKSkKI1NwID09ICJTcENociJ+ICJjaHJ5c29wdGVydW0iLAojU3AgPT0gIlNjVmV0In4gInZldHVsYSIKc2FtX2RldGFpbHMgPC0gc2FtX2RldGFpbHMgJT4lIG11dGF0ZShjb21tb25fbmFtZSA9IGNhc2Vfd2hlbigKICAgIFNwID09ICJBY0NvZSIgfiAiYmx1ZSB0YW5nIHN1cmdlb25maXNoIiwKICAgIFNwID09ICJBY1RyYSIgfiAiZml2ZWJhbmQgc3VyZ2VvbmZpc2giLAogICAgU3AgPT0gIlNjVGFlIiB+ICJwcmluY2VzcyBwYXJyb3RmaXNoIiwKICAgIFNwID09ICJTcEF1ciIgfiAicmVkYmFuZCBwYXJyb3RmaXNoIiwgCiAgICBTcCA9PSAiU3BWaXIiIH4gInN0b3BsaWdodCBwYXJyb3RmaXNoIikpCgojU3AgPT0gIlNwQ2hyIiB+ICJyZWR0YWlsIHBhcnJvdGZpc2giLAojU3AgPT0gIlNjVmV0IiB+ICJxdWVlbiBwYXJyb3RmaXNoIikpCgpzYW1fZGV0YWlscyA8LSBzYW1fZGV0YWlscyAlPiUgbXV0YXRlKE5DQklfdHhpZCA9IGNhc2Vfd2hlbigKICAgIFNwID09ICJBY0NvZSIgfiAiMTU3NTg1IiwKICAgIFNwID09ICJBY1RyYSIgfiAiMTMxNjAxMyIsCiAgICBTcCA9PSAiU2NUYWUiIH4gIjU0NDQxOCIsCiAgICBTcCA9PSAiU3BBdXIiIH4gIjU5NjYzIiwKICAgIFNwID09ICJTcFZpciIgfiAiNTk2NjYiKSkKI1NwID09ICJTcENociIgfiAiNTE3NjYiLAojU3AgPT0gIlNjVmV0IiB+ICI4NDU0MyIpKQoKc2FtX2RldGFpbHMgPC0gc2FtX2RldGFpbHNbLWMoMiwgMyldCmNvbG5hbWVzKHNhbV9kZXRhaWxzKSA8LSBjKCJob3N0X0lEIiwgImhvc3RfZ2VudXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiaG9zdF9zcGVjaWVzIiwgImZ1bGxfbmFtZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJOQ0JJX3R4aWQiKQoKbWVyZ2VfdGFiIDwtIG1lcmdlKHNhbV9kZXRhaWxzLCB0b3RhbF9yZWFkcywgYnkgPSAiaG9zdF9JRCIpCm1lcmdlX3RhYjIgPC0gbWVyZ2UobWVyZ2VfdGFiLCB0b3RhbF9hc3ZzLCBieSA9ICJob3N0X0lEIikKY29sbmFtZXMobWVyZ2VfdGFiMikgPC0gYygiaG9zdF9JRCIsICJob3N0X2dlbnVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiaG9zdF9zcGVjaWVzIiwgImNvbW1vbl9uYW1lIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiTkNCSV90eGlkIiwgICJ0b3RhbF9yZWFkcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgInRvdGFsX0FTVnMiKQoKIyBXZSBhbHNvIGhhdmUgYSBkYXRhdGFibGUgY29udGFpbmluZyBtZXRyaWNzIGZvciBlYWNoIGhvc3QuIExldHMgYnJpbmcgdGhpcyBpbiAKIyBhbmQgbWVyZ2Ugd2l0aCAgdGhlIHN1bW1hcnkgdGFibGUKbWV0cmljcyA8LSByZWFkLnRhYmxlKCJUQUJMRVMvSU5QVVQvaG9zdF9tZXRyaWNzLnR4dCIsIAogICAgICAgICAgICAgICAgICAgICAgc2VwID0gIlx0IiwgaGVhZGVyID0gVFJVRSkKaG9zdF9kZXRhaWxzIDwtIG1lcmdlKG1lcmdlX3RhYjIsIG1ldHJpY3MsIGJ5ID0gImhvc3RfSUQiKQpjb2xuYW1lcyhob3N0X2RldGFpbHMpIDwtIGMoImhvc3RfSUQiLCAiaG9zdF9nZW51cyIsICJob3N0X3NwZWNpZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbW1vbl9uYW1lIiwgIk5DQklfdHhpZCIsICAidG90YWxfcmVhZHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgInRvdGFsX0FTVnMiLCAiY29sbGVjdGlvbl9kYXRlIiwgInBoYXNlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ3ZWlnaHQiLCAidG90YWxfbGVuZ3RoIiwgImZvcmVndXRfbGVuZ3RoIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJtaWRndXRfbGVuZ3RoIiwgImhpbmRndXRfbGVuZ3RoIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ0b3RhbF9ndXRfbGVuZ3RoIikKCmRhdGF0YWJsZShob3N0X2RldGFpbHMsIHJvd25hbWVzID0gRkFMU0UsIHdpZHRoID0gIjEwMCUiLAogICAgICAgICAgY29sbmFtZXMgPSBjKCJob3N0X0lEIiwgImhvc3RfZ2VudXMiLCAiaG9zdF9zcGVjaWVzIiwKICAgICAgICAgICAgICAgICAgICAgICAiY29tbW9uX25hbWUiLCAiTkNCSV90eGlkIiwgICJ0b3RhbF9yZWFkcyIsCiAgICAgICAgICAgICAgICAgICAgICAgInRvdGFsX0FTVnMiLCAiQ29sbGVjdGlvbl9kYXRlIiwgIlBoYXNlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgIldlaWdodCAoZykiLCAiVG90YWwgbGVuZ3RoIChjbSkiLCAKICAgICAgICAgICAgICAgICAgICAgICAiRm9yZSBndXQgbGVuZ3RoIChjbSkiLCAiTWlkIGd1dCBsZW5ndGggKGNtKSIsIAogICAgICAgICAgICAgICAgICAgICAgICJIaW5kIGd1dCBsZW5ndGggKGNtKSIsICJUb3RhbCBndXQgbGVuZ3RoIChjbSkiKSwgCiAgICAgICAgICBjYXB0aW9uID0gaHRtbHRvb2xzOjp0YWdzJGNhcHRpb24oc3R5bGUgPSAiY2FwdGlvbi1zaWRlOiAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3R0b207IHRleHQtYWxpZ246IGxlZnQ7IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRhYmxlOiAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBodG1sdG9vbHM6OmVtKCJTYW1wbGUgc3VtbWFyeS4iKSksIAogICAgICAgICAgZXh0ZW5zaW9ucyA9ICJCdXR0b25zIiwgCiAgICAgICAgICBvcHRpb25zID0gbGlzdChjb2x1bW5EZWZzID0gCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3QobGlzdChjbGFzc05hbWUgPSAiZHQtbGVmdCIsIHRhcmdldHMgPSAwKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgZG9tID0gIkJsZnJ0aXAiLCBwYWdlTGVuZ3RoID0gNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGhNZW51ID0gYyg1LCAxMCwgMjUsIDUwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBidXR0b25zID0gYygiY3N2IiwgImNvcHkiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBzY3JvbGxYID0gVFJVRSwgc2Nyb2xsQ29sbGFwc2UgPSBUUlVFKSkKYGBgCgpOb3cgd2UgaGF2ZSBhIG5pY2UgbGl0dGxlIHN1bW1hcnkgdGFibGUgYWJvdXQgZWFjaCBzYW1wbGUtLS1nZW51cy9zcGVjaWVzLCBjb21tb24gbmFtZSwgbnVtYmVyIG9mIHJlYWRzLCBudW1iZXIgb2YgQVNWcywgZXRjLiBBbGwgb2YgdGhpcyBpbmZvIGNhbiBiZSB1c2VkIHdoZW4gc3VibWl0dGluZyBzYW1wbGVzIHRvIHNlcXVlbmNlIHJlYWQgYXJjaGl2ZXMuIE9uY2Ugd2UgY29uZHVjdCBhbHBoYSBkaXZlcnNpdHkgZXN0aW1hdGVzIGJlbG93LCB3ZSB3aWxsIGFkZCB0aGF0IGRhdGEgdG8gdGhlIHRhYmxlIGFib3ZlIGFuZCBleHBvcnQgYXMgKipTdXBwbGVtZW50YXJ5IFRhYmxlIDMqKi4KCioqKgoKPGEgaWQ9IlBhcnQgSUlJOiBDb21tdW5pdHkgQ29tcG9zaXRpb24gJiBEaXZlcnNpdHkiPjwvYT4gIAoKIyMgUGFydCBJSUk6IENvbW11bml0eSBDb21wb3NpdGlvbiAmIERpdmVyc2l0eQoKW2JhY2sgdG8gdG9wXSgjYmFjayB0byB0b3ApCgo+IFdoYXQgYXJlIHRoZSBkb21pbmFudCB0YXhhIGluIHRoaXMgc3lzdGVtPyBIb3cgZGl2ZXJzZSBhcmUgdGhlc2UgY29tbXVuaXRpZXM/IEhvdyBzaW1pbGFyIGFyZSBzYW1wbGVzIHRvIGVhY2ggb3RoZXI/IAoKSGVyZSB3ZSBsb29rIGF0ICoqYSoqKSBUYXhvbm9taWMgZGl2ZXJzaXR5LCAqKmIqKikgJFxhbHBoYSQtZGl2ZXJzaXR5LCBhbmQgKipjKiopICRcYmV0YSQtZGl2ZXJzaXR5CgoqKioKCiMjIyBUYXhvbm9taWMgY29tcG9zaXRpb24gCgojIyMjIFRvdGFsIHJlYWRzICYgQVNWcyBieSBDbGFzcwoKQmVmb3JlIHdlIGNhbiBzdGFydCB0byB1bmRlcnN0YW5kIGEgc3lzdGVtLCB3ZSBuZWVkIHRvIGtub3cgc29tZXRoaW5nIGFib3V0IGl0cyBwYXJ0cy4gU28gbGV0cyBzdGFydCB3aXRoIGEgcXVpY2sgbG9vayBhdCBDbGFzcy1sZXZlbCBkaXZlcnNpdHkuIE9mIGNvdXJzZSwgeW91IGNhbiBjaGFuZ2UgdGhpcyB0byBhbnkgdGF4b25vbWljIHJhbmsgeW91IHdpc2guIEhlcmUgd2UgY3JlYXRlZCBhICoqc29ydGFibGUqKiB0YWJsZSB0aGF0IGhhcyB0aGUgdG90YWwgbnVtYmVyIG9mIHJlYWRzIGFuZCBBU1ZzIGZvciBlYWNoIGNsYXNzCgpgYGB7ciBkaXZlcnNpdHlfdGFibGUsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQojIGdlbmVyYXRlIHRoZSBBU1YgdGFibGUKdGF4X2FzdiA8LSB0YWJsZSh0YXhfdGFibGUocHNfc2x2X3dvcmtfZmlsdClbLCAiQ2xhc3MiXSwgCiAgICAgICAgICAgICAgICAgZXhjbHVkZSA9IE5VTEwsIGRubiA9ICJUYXhhIikKdGF4X2FzdiA8LSBhcy5kYXRhLmZyYW1lKHRheF9hc3YsIG1ha2UubmFtZXMgPSBUUlVFKQoKIyMjIyBjaGFuZ2UgPE5BPiB0byBVbmNsYXNzaWZpZWQKIyBHZXQgbGV2ZWxzIGFuZCBhZGQgIk5vbmUiCmxldmVscyA8LSBsZXZlbHModGF4X2FzdiRUYXhhKQpsZXZlbHNbbGVuZ3RoKGxldmVscykgKyAxXSA8LSAiVW5jbGFzc2lmaWVkIgojIHJlZmFjdG9yIFRheGEgdG8gaW5jbHVkZSAiVW5jbGFzc2lmaWVkIiBhcyBhIGZhY3RvciBsZXZlbAojIGFuZCByZXBsYWNlIE5BIHdpdGggIlVuY2xhc3NpZmllZCIKdGF4X2FzdiRUYXhhIDwtIGZhY3Rvcih0YXhfYXN2JFRheGEsIGxldmVscyA9IGxldmVscykKdGF4X2FzdiRUYXhhW2lzLm5hKHRheF9hc3YkVGF4YSldIDwtICJVbmNsYXNzaWZpZWQiCgojIGdlbmVyYXRlIHRoZSByZWFkcyB0YWJsZQp0YXhfcmVhZHMgPC0gZmFjdG9yKHRheF90YWJsZShwc19zbHZfd29ya19maWx0KVssICJDbGFzcyJdLCBleGNsdWRlID0gTlVMTCkKdGF4X3JlYWRzIDwtIGFwcGx5KG90dV90YWJsZShwc19zbHZfd29ya19maWx0KSwgTUFSR0lOID0gMSwgCiAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KSB7CiAgICAgICAgICAgICAgICAgICAgIHRhcHBseSh4LCBJTkRFWCA9IHRheF9yZWFkcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZVTiA9IHN1bSwgbmEucm0gPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpbXBsaWZ5ID0gVFJVRSl9KQoKI1JFTkFNRSBOQSAtLT4gVW5jbGFzc2lmaWVkCnJvd25hbWVzKHRheF9yZWFkcylbNzJdIDwtICJVbmNsYXNzaWZpZWQiCgp0YXhfcmVhZHMgPC0gYXMuZGF0YS5mcmFtZSh0YXhfcmVhZHMsIG1ha2UubmFtZXMgPSBUUlVFKQp0YXhfcmVhZHMgPC0gY2JpbmQodGF4X3JlYWRzLCByZWFkcyA9IHJvd1N1bXModGF4X3JlYWRzKSkKI0RFTEVURSBhbGwgYnV0IGxhc3QgY29sdW1uCnRheF9yZWFkcyA8LSB0YXhfcmVhZHNbNTFdCnRheF9yZWFkcyA8LSBzZXREVCh0YXhfcmVhZHMsIGtlZXAucm93bmFtZXMgPSBUUlVFKVtdCiMgbWVyZ2UgdGhlIHR3byB0YWJsZXMgYW5kIG1ha2UgZXZlcnl0aGluZyBsb29rIHByZXR0eQojIGluIGFuIGludGVyYWN0aXZlIHRhYmxlCgp0YXhhX3JlYWRfYXN2X3RhYiA8LSBtZXJnZSh0YXhfcmVhZHMsIHRheF9hc3YsIGJ5LnggPSAicm4iLCBieS55ID0gIlRheGEiKQp0YXhhX3JlYWRfYXN2X3RhYiA8LSBtdXRhdGUodGF4YV9yZWFkX2Fzdl90YWIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvcF9vZl9BU1ZzID0gRnJlcSAvIHN1bShGcmVxKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9wX29mX3JlYWRzID0gcmVhZHMgLyBzdW0ocmVhZHMpKQp0YXhhX3JlYWRfYXN2X3RhYiA8LSB0YXhhX3JlYWRfYXN2X3RhYltjKDEsIDIsIDUsIDMsIDQpXQoKbmFtZXModGF4YV9yZWFkX2Fzdl90YWIpIDwtIGMoIkNsYXNzIiwgInRvdGFsX3JlYWRzIiwgInByb3Bfb2ZfcmVhZHMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInRvdGFsX0FTVnMiLCAicHJvcF9vZl9BU1ZzIikKCnRheGFfcmVhZF9hc3ZfdGFiMiA8LSB0YXhhX3JlYWRfYXN2X3RhYgp0YXhhX3JlYWRfYXN2X3RhYjIkcHJvcF9vZl9yZWFkcyA8LSByb3VuZCh0YXhhX3JlYWRfYXN2X3RhYjIkcHJvcF9vZl9yZWFkcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpZ2l0cyA9IDYpCnRheGFfcmVhZF9hc3ZfdGFiMiRwcm9wX29mX0FTVnMgPC0gcm91bmQodGF4YV9yZWFkX2Fzdl90YWIyJHByb3Bfb2ZfQVNWcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlnaXRzID0gNikKYGBgCgpGb3IgeW91ciBpbmZvcm1hdGlvbiwgdGhlIGRhdGFzZXQgaGFzIGEgdG90YWwgb2YgKipgciBmb3JtYXQoc3VtKHRheF9yZWFkcyRyZWFkcyksIHNjaWVudGlmaWMgPSBGQUxTRSlgKiogcmVhZHMgYWNyb3NzICoqYHIgc3VtKHRheF9hc3YkRnJlcSlgKiogQVNWcy4gCgojIyMjIDxmb250IGNvbG9yPSJyZWQiPlN1cHBsZW1lbnRhcnkgVGFibGUgNDwvZm9udD4KCmBgYHtyfQoja2lsbHMgc2NpIG5vdGF0aW9uICAgICAKb3B0aW9ucyhzY2lwZW4gPSA5OTkpIAp3cml0ZS50YWJsZSh0YXhhX3JlYWRfYXN2X3RhYjIsICJUQUJMRVMvT1VUUFVUL1NVUFAvVGFibGVfUzQudHh0IiwgCiAgICAgICAgICAgIHNlcCA9ICJcdCIsIHJvdy5uYW1lcyA9IEZBTFNFLCBxdW90ZSA9IEZBTFNFKQoKZGF0YXRhYmxlKHRheGFfcmVhZF9hc3ZfdGFiMiwgcm93bmFtZXMgPSBGQUxTRSwgd2lkdGggPSAiMTAwJSIsIAogICAgICAgICAgY29sbmFtZXMgPSBjKCJDbGFzcyIsICJ0b3RhbF9yZWFkcyIsICJwcm9wX29mX3JlYWRzIiwgCiAgICAgICAgICAgICAgICAgICAgICAgInRvdGFsX0FTVnMiLCAicHJvcF9vZl9BU1ZzIiksIAogICAgICAgICAgY2FwdGlvbiA9IAogICAgICAgICAgICBodG1sdG9vbHM6OnRhZ3MkY2FwdGlvbigKICAgICAgICAgICAgICBzdHlsZSA9ICJjYXB0aW9uLXNpZGU6IGJvdHRvbTsgdGV4dC1hbGlnbjogbGVmdDsiLCAKICAgICAgICAgICAgICAiVGFibGU6ICIsIAogICAgICAgICAgICAgIGh0bWx0b29sczo6ZW0oIlRvdGFsIHJlYWRzICYgQVNWcyBieSBDbGFzcyIpKSwgCiAgICAgICAgICBleHRlbnNpb25zID0gIkJ1dHRvbnMiLCAKICAgICAgICAgIG9wdGlvbnMgPSBsaXN0KGNvbHVtbkRlZnMgPSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdChsaXN0KGNsYXNzTmFtZSA9ICJkdC1sZWZ0IiwgdGFyZ2V0cyA9IDApKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBkb20gPSAiQmxmcnRpcCIsIHBhZ2VMZW5ndGggPSA1LCAKICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aE1lbnUgPSBjKDUsIDEwLCAzNSwgNzApLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGJ1dHRvbnMgPSBjKCJjc3YiLCAiY29weSIpKSkKYGBgCgoKTG9va3MgbGlrZSBQcm90ZW9iYWN0ZXJpYSwgRmlybWljdXRlcywgRnVzb2JhY3RlcmlhLCBQbGFuY3RvbXljZXRlcywgYW5kIEJhY3Rlcm9pZGV0ZXMgZG9taW5hdGUgaW4gdGhlIHJlYWQgZGVwYXJ0bWVudC4gQ3VyaW91c2x5LCBGdXNvYmFjdGVyaWEgaGFzIGNvbXBhcmF0aXZlbHkgbG93IEFTViByaWNobmVzcy4gCgoqKioKCk11Y2ggb2YgdGhlIGFuYWx5c2VzIHdlIGRvIGZyb20gaGVyZSBvbiBvdXQgd2lsbCBiZSBhdCB0aGUgKipDbGFzcyoqICYgKipGYW1pbHkqKiBsZXZlbHMuIFdlIGNob3NlIG5vdCB0byBmb2N1cyBvbiB0aGUgR2VudXMgbGV2ZWwgYmVjYXVzZSB0aGVyZSBzaW1wbHkgaXMgbm90IGVub3VnaCByZXNvbHV0aW9uIGluIG91ciBkYXRhc2V0IHRvIGJ1aWxkIGEgY29oZXNpdmUgc3RvcnkuIFRoaXMgaXMgYmVjYXVzZSB0aGVzZSBmaXNoIGFyZSAobWljcm9iaWFsbHkpIHVuZGVyc3R1ZGllZCAqYW5kKiB3ZSBhcmUgZGVhbGluZyB3aXRoIHNob3J0IHJlYWQgZGF0YS4gT24gdGhlIG90aGVyIGhhbmQsIFBoeWx1bSBsZXZlbCBpcyB0b28gY29hcnNlIGZvciBncm91cHMgbGlrZSBQcm90ZW9iYWN0ZXJpYSBhbmQgRmlybWljdXRlcy4gT3JkZXIgZGlkIG5vdCBwcm92aWRlIGFueSBhZGRpdGlvbmFsIGluZm9ybWF0aW9uIGFuZCBjYW4gYmUgY3VtYmVyc29tZSBmb3IgdGF4YSB3aXRoIHBvb3JseSByZXNvbHZlZCBsaW5lYWdlcy4gRGVwZW5kaW5nIG9uIHRoZSBkYXRhc2V0LCB5b3UgbWF5IHdhbnQgdG8gY2hhbmdlIHlvdXIgc3RyYXRlZ3kuIAoKTGV0cyB0YWtlIGEgY2xvc2VyIGxvb2sgQ2xhc3MtbGV2ZWwgdGF4b25vbWljIGNvbnRlbnQgb2YgdGhlc2UgY29tbXVuaXRpZXMuIFRoZXJlIGFyZSBudW1lcm91cyB3YXlzIHRvIGRvIHRoaXMgYnV0IGhlcmUgd2UgY2hvc2UgdG8gY29sbGFwc2Ugc2FtcGxlcyBieSBob3N0IHNwZWNpZXMgYW5kIGRpc3BsYXkgdGhlIHJlbGF0aXZlIGFidW5kYW5jZSBvZiB0aGUgbW9zdCBkb21pbmFudCB0YXhhLiBXZSBhbHNvIGdlbmVyYXRlZCBhbHRlcm5hdGl2ZSB2aWV3cyBvZiB0YXhvbm9taWMgY29tcG9zaXRpb24gZm9yIGluZGl2aWR1YWwgc2FtcGxlcy0tLWEgW2JveC1hbmQtd2hpc2tlciBwbG90XSgjYm94LWFuZC13aGlza2VyLXBsb3QpIGFzIHdlbGwgYXMgW3NlcGFyYXRlIGJhciBwbG90c10oI3NlcGFyYXRlLWJhci1wbG90cyktLXRoYXQgYXJlIGluY2x1ZGVkIGFzICoqU3VwcGxlbWVudGFyeSBGaWd1cmUgMSoqIChzZWUgYmVsb3cgZm9yIGNvZGUpLiAKClN0YWNrZWQgYmFyIGNoYXJ0cyBhcmUgbm90IHRoZSBiZXN0IGJ1dCB3ZSBsaWtlIHRoZW0gZm9yIGEgYmlyZHMgZXllIHZpZXcgb2YgdGhlIGRhdGEuIEhlcmUgd2UgY2FsY3VsYXRlIHRoZSByZWxhdGl2ZSBhYnVuZGFuY2Ugb2YgdGF4YSBmb3IgZWFjaCBob3N0IHNwZWNpZXMgYXQgdGhlICoqQ2xhc3MqKiBsZXZlbC4gSXQgdHVybnMgb3V0IHRoaXMgaXMgbm90IHRvbyBlYXN5IGluIHBoeWxvc2VxIGFuZCB0aGVyZSBpcyBhIGxvdCBvZiAobWVzc3kpIGNvZGUuIAoKYGBge3IgY2FsY19yZWxfYWJ1bmRfYW5kX21lcmdlfQojIGNhbGN1bGF0ZSB0aGUgYXZlcmFnZXMgYW5kIG1lcmdlIGJ5IHNwZWNpZXMKcHNfc2x2X2ZpbHRfQVZHIDwtIHRyYW5zZm9ybV9zYW1wbGVfY291bnRzKHBzX3Nsdl93b3JrX2ZpbHQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgeCAvIHN1bSh4KSkKbWVyZ2VkR1BfQkFSIDwtIG1lcmdlX3NhbXBsZXMocHNfc2x2X2ZpbHRfQVZHLCAiU3AiKQpTRF9CQVIgPC0gbWVyZ2Vfc2FtcGxlcyhzYW1wbGVfZGF0YShwc19zbHZfZmlsdF9BVkcpLCAiU3AiKQoKIyBtZXJnZSB0YXhhIGJ5IHJhbmsuIElmIHlvdSBjaG9vc2UgYSBkaWZmZXJlbnQgcmFuayBiZSBzdXJlIHRvIGNoYW5nZQojIHRoZSByYW5rIHRocm91Z2hvdXQgdGhpcyBjb2RlIGNodW5rCm1kYXRhX3BoeSA8LSB0YXhfZ2xvbShtZXJnZWRHUF9CQVIsIHRheHJhbmsgPSAiQ2xhc3MiLCBOQXJtID0gRkFMU0UpICAKbWRhdGFfcGh5cmVsIDwtIHRyYW5zZm9ybV9zYW1wbGVfY291bnRzKG1kYXRhX3BoeSwgZnVuY3Rpb24oeCkgeCAvIHN1bSh4KSkKbWVsdGQgPC0gcHNtZWx0KG1kYXRhX3BoeXJlbCkKbWVsdGQkQ2xhc3MgPC0gYXMuY2hhcmFjdGVyKG1lbHRkJENsYXNzKQoKIyBjYWxjdWxhdGUgdGhlIHRvdGFsIHJlbGF0aXZlIGFidW5kYW5jZSBmb3IgYWxsIHRheGEKbWVhbnMgPC0gZGRwbHkobWVsdGQsIH5DbGFzcywgZnVuY3Rpb24oeCkgYyhtZWFuID0gbWVhbih4JEFidW5kYW5jZSkpKQptZWFucyRtZWFuIDwtIHJvdW5kKG1lYW5zJG1lYW4sIGRpZ2l0cyA9IDgpCiMgdGhpcyBvcmRlciBpbiBkZWNlbmRpbmcgZmFzaGlvbgp0YXhhX21lYW5zIDwtIG1lYW5zW29yZGVyKC1tZWFucyRtZWFuKSwgXSAgCiMgZGl0Y2ggdGhlIHNjaSBub3RhdGlvbiAKdGF4YV9tZWFucyA8LSBmb3JtYXQodGF4YV9tZWFucywgc2NpZW50aWZpYyA9IEZBTFNFKQojUkVOQU1FIE5BIHRvIFVOQ0xBU1NJRklFRAp0YXhhX21lYW5zJENsYXNzIDwtIGdzdWIoIk5BIiwgIlVuY2xhc3NpZmllZCIsIHRheGFfbWVhbnMkQ2xhc3MpCmBgYAoKU2luY2Ugb3VyIGdvYWwgaXMgdG8gZ2VuZXJhdGUgYSBmaWd1cmUgYW5kIHdlIG9ubHkgaGF2ZSA5IGNvbG9ycywgc29tZSB0YXhhIHdpbGwgbmVlZCB0byBiZSBwdXQgaW50byBhbiAqKk90aGVyKiogY2F0ZWdvcnkuIFdlIGNhbiBkZWZpbmUgJ090aGVyJyBob3dldmVyIHdlIGxpa2Ugc28gbGV0cyB0YWtlIGEgbG9vayBhdCB0aGUgb3ZlcmFsbCByZWxhdGl2ZSBhYnVuZGFuY2Ugb2YgZWFjaCBDbGFzcy4gCgoqKioKCiMjIyMgVGF4b25vbWljIGNvbXBvc2l0aW9uOiBDbGFzcy1sZXZlbCByZWxhdGl2ZSBhYnVuZGFuY2UKCjxhIGlkPSJyZWxhdGl2ZSBhYnVuZGFuY2UgcGh5bG9zZXEgb2JqZWN0Ij48L2E+CgoKYGBge3IgcmVsX2FidW5kX3RhYmxlLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30KCmRhdGF0YWJsZSh0YXhhX21lYW5zLCByb3duYW1lcyA9IEZBTFNFLCB3aWR0aCA9ICI2NSUiLCAKICAgICAgICAgIGNvbG5hbWVzID0gYygiQ2xhc3MiLCAibWVhbiIpLCBjYXB0aW9uID0gCiAgICAgICAgICAgIGh0bWx0b29sczo6dGFncyRjYXB0aW9uKHN0eWxlID0gImNhcHRpb24tc2lkZTogYm90dG9tOyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGV4dC1hbGlnbjogbGVmdDsiLCAiVGFibGU6ICIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGh0bWx0b29sczo6ZW0oIkNsYXNzLWxldmVsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbGF0aXZlIGFidW5kYW5jZS4iKSksIAogICAgICAgICAgZXh0ZW5zaW9ucyA9ICJCdXR0b25zIiwgCiAgICAgICAgICBvcHRpb25zID0gbGlzdChjb2x1bW5EZWZzID0gbGlzdChsaXN0KGNsYXNzTmFtZSA9ICJkdC1jZW50ZXIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0cyA9ICJfYWxsIikpLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGRvbSA9ICJCbGZydGlwIiwgcGFnZUxlbmd0aCA9IDEwLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aE1lbnUgPSBjKDUsIDEwLCA1MCwgNzApLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGJ1dHRvbnMgPSBjKCJjc3YiLCAiY29weSIpKSkKYGBgCgpJbnNwZWN0aW5nIHRoZSB0YWJsZSBpdCBsb29rcyBsaWtlIGlmIHdlIGNob29zZSBhIGN1dG9mZiBvZiAyJSAoMC4wMikgd2UgZ2V0IDkgdGF4YS0tLXNvdW5kcyBwcmV0dHkgZ29vZC4gVGhlIHJlc3QgZ28gaW50byB0aGUgJ090aGVyJyBjYXRlZ29yeS4gTm8gbWF0dGVyIHdoYXQsIHdlIHdpbGwgYWx3YXlzIGdsb3NzIG92ZXIgc29tZSBncm91cHMgdXNpbmcgc3VjaCBhIGNvYXJzZSBhcHByb2FjaC4gQnV0IGFzIHdlIHdpbGwgc2VlIGxhdGVyLCBzb21lIG9mIHRoZXNlIGxvdyBhYnVuZGFuY2UgZ3JvdXBzIHdpbGwgcmVhcHBlYXIgd2hlbiB3ZSBsb29rIGF0IHRoZSBsZXZlbCBvZiBpbmRpdmlkdWFsIEFTVnMuIAoKSGVyZSB3ZSBkZWZpbmUgdGhlICoqT3RoZXIqKiBjYXRlZ29yeSBieSBjb21iaW5pbmcgYWxsIHRheGEgd2l0aCBsZXNzIHRoYW4gMiUgb2YgdG90YWwgcmVhZHMuCgoKYGBge3IgZGVmaW5lX290aGVyfQpPdGhlciA8LSBtZWFuc1ttZWFucyRtZWFuIDw9IDAuMDIsIF0kQ2xhc3MgIAojIG9yIHlvdSBjYW4gY2hvc2Ugc3BlY2lmYyB0YXhhIGxpa2UgdGhpcwojIE90aGVyX21hbnVhbCA8LSBjKCJsaXN0IiwgInRheGEiLCAiaW4iLCAidGhpcyIsICJmb3JtYXQiKQpgYGAKCkF0IGEgMiUgYWJ1bmRhbmNlIGN1dG9mZiwgYHIgbGVuZ3RoKE90aGVyKWAgQ2xhc3NlcyBhcmUgZ3JvdXBlZCBpbnRvIHRoZSAnT3RoZXInIGNhdGVnb3J5LiBOZXh0IHdlIHdpbGwgbWVsdCBhbGwgdGhlc2UgY2xhc3NlcyBpbnRvIHRoZSAqKk90aGVyKiogY2F0ZWdvcnkgYW5kIHRoZW4gY3JhZnQgdGhlIGJhciBjaGFydC4gSXQgdG9vayBzb21lIHR3ZWFraW5nIHRvIGdldCB0aGUgYmFyIGNoYXJ0IHRvIGxvb2sganVzdCByaWdodC0tLXNvIHRoZXJlIGlzIGEgbG90IG9mIGNvZGUgaGVyZS0tLWFuZCBpdCBjb3VsZCBtb3N0IGNlcnRhaW5seSBiZSBiZXR0ZXIuIFdoaWxlIHdlJ3JlIGF0IGl0LCB3ZSB3aWxsIGFsc28gc2F2ZSBhIGNvcHkgb2YgdGhlIGZpZ3VyZSBzbyB3ZSBjYW4gdHdlYWsgaXQgbGF0ZXIgYW5kIG1ha2UgaXQgbG9vayBwcmV0dHkuCgoKYGBge3IgbWV0bGRfYmFyfQptZWx0ZFttZWx0ZCRDbGFzcyAlaW4lIE90aGVyLCBdJENsYXNzIDwtICJPdGhlciIKc2FtcF9uYW1lcyA8LSBhZ2dyZWdhdGUobWVsdGQkQWJ1bmRhbmNlLCAKICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSBsaXN0KG1lbHRkJFNhbXBsZSksIEZVTiA9IHN1bSlbLCAxXQouZSA8LSBlbnZpcm9ubWVudCgpCm1lbHRkWywgIkNsYXNzIl0gPC0gZmFjdG9yKG1lbHRkWywgIkNsYXNzIl0sIHNvcnQodW5pcXVlKG1lbHRkWywgIkNsYXNzIl0pKSkKbWVsdGQgPC0gbWVsdGRbb3JkZXIobWVsdGRbLCAiQ2xhc3MiXSksIF0KIyBIZXJlIHdlIG9yZGVyIENsYXNzZXMgYnkgdGhlIFBoeWx1bSB0aGV5IGJlbG9uZyB0by4KbWVsdGQkQ2xhc3MgPC0gZmFjdG9yKG1lbHRkJENsYXNzLCAKICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkJhY3Rlcm9pZGlhIiwgIkNsb3N0cmlkaWEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkVyeXNpcGVsb3RyaWNoaWEiLCAiRnVzb2JhY3RlcmlpYSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQWxwaGFwcm90ZW9iYWN0ZXJpYSIsICJEZWx0YXByb3Rlb2JhY3RlcmlhIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHYW1tYXByb3Rlb2JhY3RlcmlhIiwgIlBsYW5jdG9teWNldGFjaWEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk94eXBob3RvYmFjdGVyaWEiLCAiT3RoZXIiKSkgIApgYGAKCioqKgoKIyMjIyBUYXhvbm9taWMgY29tcG9zaXRpb246IENsYXNzIGFidW5kYW5jZSBhY3Jvc3MgaG9zdCBzcGVjaWVzICAKCiMjIyMgPGZvbnQgY29sb3I9InJlZCI+RmlndXJlIDJBPC9mb250PgoKYGBge3IgcGxvdF9iYXJfZmlnMkEsIGZpZy5hbGlnbiA9ICJjZW50ZXIiLCBmaWcuY2FwID0gIkZpZ3VyZSAyQSIsIGZpZy5oZWlnaHQgPSAzfQpmaWcyQSA8LSBnZ3Bsb3QobWVsdGQsIAogICAgICAgICAgICAgICAgYWVzX3N0cmluZyh4ID0gIlNhbXBsZSIsIHkgPSAiQWJ1bmRhbmNlIiwgZmlsbCA9ICJDbGFzcyIpLCAKICAgICAgICAgICAgICAgIGVudmlyb25tZW50ID0gLmUsIAogICAgICAgICAgICAgICAgb3JkZXJlZCA9IFRSVUUsIAogICAgICAgICAgICAgICAgeGxhYiA9ICJ4LWF4aXMgbGFiZWwiLCB5bGFiID0gInktYXhpcyBsYWJlbCIpIAoKCmZpZzJBIDwtIGZpZzJBICsgZ2VvbV9iYXIoc3RhdCA9IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgImlkZW50aXR5IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayhyZXZlcnNlID0gVFJVRSksIAogICAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoID0gMC45NSkgKyAKICBjb29yZF9mbGlwKCkgKyAKICB0aGVtZShhc3BlY3QucmF0aW8gPSAxIC8gMikKCmZpZzJBIDwtIGZpZzJBICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gZnJpZW5kX3BhbCkKCmZpZzJBIDwtIGZpZzJBICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDAuNDUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0ID0gMSkpCgpmaWcyQSA8LSBmaWcyQSArIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3QoY29sb3VyID0gTlVMTCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldmVyc2UgPSBGQUxTRSkpICsgCiAgdGhlbWUobGVnZW5kLmtleSA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiYmxhY2siKSkKCmZpZzJBIDwtIGZpZzJBICsgbGFicyh4ID0gIkhvc3Qgc3BlY2llcyIsIAogICAgICAgICAgICAgICAgICAgICAgeSA9ICJSZWxhdGl2ZSBhYnVuZGFuY2UgKCUgdG90YWwgcmVhZHMpIiwgCiAgICAgICAgICAgICAgICAgICAgICB0aXRsZSA9ICJBYnVuZGFuY2Ugb2YgYmFjdGVyaWFsIHRheGEgYWNyb3NzIGhvc3Qgc3BlY2llcyIpCgpmaWcyQSA8LSBmaWcyQSArIHRoZW1lKGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiYmxhY2siKSwgCiAgICAgICAgICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgICAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJibGFjayIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gTkEsIHNpemUgPSAxKSkKCmZpZzJBCnBkZigiRklHVVJFUy9PVVRQVVQvRmlndXJlXzJBLnBkZiIpCmZpZzJBCmludmlzaWJsZShkZXYub2ZmKCkpCmBgYAoKKioqCgpBcm1lZCB3aXRoIGEgcGljdHVyZSBvZiB0YXhvbm9taWMgY29tcG9zaXRpb24gd2UgY2FuIG1vdmUgb24gdG8gZGl2ZXJzaXR5IGVzdGltYXRlcy4KCiMjIyAkXGFscGhhJC1kaXZlcnNpdHkKCiMjIyMgJFxhbHBoYSQtZGl2ZXJzaXR5IHN0YXRpc3RpY2FsIHRlc3RzCgoKQWxwaGEgZGl2ZXJzaXR5IGRlc2NyaWJlcyB0aGUgZGl2ZXJzaXR5IGluIGEgc2FtcGxlIG9yIHNpdGUuICBUaGVyZSBhcmUgc2V2ZXJhbCBhbHBoYSBkaXZlcnNpdHkgbWV0cmljcyBhdmFpbGFibGUgaW4gcGh5bG9zZXE6IGBPYnNlcnZlZGAsIGBDaGFvMWAsIGBBQ0VgLCBgU2hhbm5vbmAsIGBTaW1wc29uYCwgYEludlNpbXBzb25gLCBgRmlzaGVyYC4gUGxheSBhcm91bmQgdG8gc2VlIGhvdyBkaWZmZXJlbnQgbWV0cmljcyBjaGFuZ2Ugb3IgY29uZmlybSB0aGVzZSByZXN1bHRzLiAKCkhlcmUgd2Ugd2FudCB0byBrbm93IGlmIGRpdmVyc2l0eSBpcyBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBhY3Jvc3MgaG9zdCBzcGVjaWVzLiBJbiBvcmRlciB0byBkbyB0aGF0IHdlIG5lZWQgdG8ga25vdyBpZiB3ZSBzaG91bGQgcnVuIGEgcGFyYW1ldHJpYyBvciBub24tcGFyYW1ldHJpYyB0ZXN0LCBhbmQgZm9yIHRoYXQgd2UgbmVlZCB0byBrbm93IGlmIG91ciBkYXRhIGlzIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLiBNb3N0IG9mIHRoZSBpZGVhcy9jb2RlIGZvciBhbHBoYSAoYW5kIHN1YnNlcXVlbnQgYmV0YSkgZGl2ZXJzaXR5IHN0YXRpc3RpY3MgY29tZSBmcm9tIHRoaXMgW3dvcmtzaG9wIHR1dG9yaWFsXShodHRwczovL3JwdWJzLmNvbS9tYWRkaWVTQy9SX1NPUF9VQ1JfSmFuXzIwMTgpe3RhcmdldD0iX2JsYW5rIn0gYnkgS2ltIERpbGwtTWNGYXJsYW5kIGFuZCBNYWRpc29uIENveC4KCkZpcnN0IHdlIHJ1biB0aGUgZGl2ZXJzaXR5IGVzdGltYXRlcywgYWRkIHRoZXNlIGRhdGEgdG8gb3VyIHN1bW1hcnkgdGFibGUsIGFuZCBzYXZlIGEgY29weSBvZiB0aGlzIHRhYmxlLiAKCiMjIyMgPGZvbnQgY29sb3I9InJlZCI+U3VwcGxlbWVudGFyeSBUYWJsZSAzPC9mb250PgoKYGBge3IgZ2VuX3N1bW1hcnlfdGFibGUsIHdhcm5pbmcgPSBGQUxTRX0KZGl2ZXJzaXR5IDwtIGVzdGltYXRlX3JpY2huZXNzKHBzX3Nsdl93b3JrX2ZpbHQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhc3VyZXMgPSBjKCJPYnNlcnZlZCIsICJDaGFvMSIsICJBQ0UiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNoYW5ub24iLCAiU2ltcHNvbiIsICJJbnZTaW1wc29uIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJGaXNoZXIiKSkKCmRpdmVyc2l0eV9jYWxjIDwtIGRpdmVyc2l0eSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCJob3N0X0lEIikKIyByb3VuZCB2YWx1ZXMKZGl2ZXJzaXR5X2NhbGNbYygzLCA1LCAxMCldIDwtIHJvdW5kKGRpdmVyc2l0eV9jYWxjW2MoMywgNSwgMTApXSwgMSkKZGl2ZXJzaXR5X2NhbGNbYyg0LCA2LCA3LCA5KV0gPC0gcm91bmQoZGl2ZXJzaXR5X2NhbGNbYyg0LCA2LCA3LCA5KV0sIDIpCmRpdmVyc2l0eV9jYWxjWzhdIDwtIHJvdW5kKGRpdmVyc2l0eV9jYWxjWzhdLCAzKQoKaG9zdF9zdW1tYXJ5IDwtIG1lcmdlKGhvc3RfZGV0YWlscywgZGl2ZXJzaXR5X2NhbGMpCmhvc3Rfc3VtbWFyeSRPYnNlcnZlZCA8LSBOVUxMCmhvc3Rfc3VtbWFyeSA8LSBob3N0X3N1bW1hcnlbYygxLCAyLCAzLCA0LCA1LCA4LCA5LCAxMCwgMTEsIDEyLCAxMywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDE0LCAxNSwgNiwgNywgMTYsIDE3LCAxOCwgMTksIDIwLCAyMSwgMjIsIDIzKV0KCndyaXRlLnRhYmxlKGhvc3Rfc3VtbWFyeSwgIlRBQkxFUy9PVVRQVVQvU1VQUC9UYWJsZV9TMy50eHQiLCAKICAgICAgICAgICAgc2VwID0gIlx0Iiwgcm93Lm5hbWVzID0gRkFMU0UsIHF1b3RlID0gRkFMU0UsIAogICAgICAgICAgICBjb2wubmFtZXMgPSBjKCJTYW1wbGUgSUQiLCAiSG9zdCBnZW51cyIsICJIb3N0IHNwZWNpZXMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAiQ29tbW9uIG5hbWUiLCAiTkNCSSB0QXhJRCIsICJDb2xsZWN0aW9uIGRhdGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAiTGlmZSBwaGFzZSIsICJXZWlnaHQgKGcpIiwgIlRvdGFsIGxlbmd0aCAoY20pIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIkZvcmVndXQgbGVuZ3RoIChjbSkiLCAiTWlkZ3V0IGxlbmd0aCAoY20pIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIkhpbmRndXQgbGVuZ3RoIChjbSkiLCAiVG90YWwgZ3V0IGxlbmd0aCAoY20pIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvdGFsIHJlYWRzIiwgIlRvdGFsIEFTVnMiLCAiQ2hhbzEiLCAiQ2hhbzEgKHNlKSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICJBQ0UiLCAiQUNFIChzZSkiLCAiU2hhbm5vbiIsICJTaW1wc29uIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIkludlNpbXBzb24iLCAiRmlzaGVyIikpCgpkYXRhdGFibGUoaG9zdF9zdW1tYXJ5LCByb3duYW1lcyA9IEZBTFNFLCB3aWR0aCA9ICIxMDAlIiwgCiAgICAgICAgICBjb2xuYW1lcyA9IGMoIlNhbXBsZSBJRCIsICJIb3N0IGdlbnVzIiwgIkhvc3Qgc3BlY2llcyIsIAogICAgICAgICAgICAgICAgICAgICAgICJDb21tb24gbmFtZSIsICJOQ0JJIHRBeElEIiwgIkNvbGxlY3Rpb24gZGF0ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICJMaWZlIHBoYXNlIiwgIldlaWdodCAoZykiLCAiVG90YWwgbGVuZ3RoIChjbSkiLCAKICAgICAgICAgICAgICAgICAgICAgICAiRm9yZWd1dCBsZW5ndGggKGNtKSIsICJNaWRndXQgbGVuZ3RoIChjbSkiLCAKICAgICAgICAgICAgICAgICAgICAgICAiSGluZGd1dCBsZW5ndGggKGNtKSIsICJUb3RhbCBndXQgbGVuZ3RoIChjbSkiLCAKICAgICAgICAgICAgICAgICAgICAgICAiVG90YWwgcmVhZHMiLCAiVG90YWwgQVNWcyIsICJDaGFvMSIsICJDaGFvMSAoc2UpIiwgCiAgICAgICAgICAgICAgICAgICAgICAgIkFDRSIsICJBQ0UgKHNlKSIsICJTaGFubm9uIiwgIlNpbXBzb24iLCAiSW52U2ltcHNvbiIsIAogICAgICAgICAgICAgICAgICAgICAgICJGaXNoZXIiKSwgCiAgICAgICAgICAgIGNhcHRpb24gPSAKICAgICAgICAgICAgaHRtbHRvb2xzOjp0YWdzJGNhcHRpb24oc3R5bGUgPSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY2FwdGlvbi1zaWRlOiBib3R0b207IHRleHQtYWxpZ246IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWZ0OyIsICJUYWJsZTogIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGh0bWx0b29sczo6ZW0oIkhvc3QtYXNzb2NpYXRlZCBtZXRhZGF0YSAmIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pY3JvYmlhbCBkaXZlcnNpdHkiKSksIAogICAgICAgICAgZXh0ZW5zaW9ucyA9ICJCdXR0b25zIiwgb3B0aW9ucyA9IAogICAgICAgICAgICBsaXN0KGNvbHVtbkRlZnMgPSBsaXN0KGxpc3QoY2xhc3NOYW1lID0gImR0LWxlZnQiLCB0YXJnZXRzID0gMCkpLCAKICAgICAgICAgICAgICAgICBkb20gPSAiQmxmcnRpcCIsIHBhZ2VMZW5ndGggPSA1LCBsZW5ndGhNZW51ID0gYyg1LCAxMCwgNTApLCAKICAgICAgICAgICAgICAgICBidXR0b25zID0gYygiY3N2IiwgImNvcHkiKSwgc2Nyb2xsWCA9IFRSVUUsIAogICAgICAgICAgICAgICAgIHNjcm9sbENvbGxhcHNlID0gVFJVRSkpCmBgYAoKTmV4dCwgd2UgYWRkIHRoZSBkaXZlcnNpdHkgZXN0aW1hdGVzIHRvIG91ciBwaHlsb3NlcSBvYmplY3QsIGFuZCB0ZXN0IGlmIHRoZSBkYXRhIGFyZSBub3JtYWxseSBkaXN0cmlidXRlZCB1c2luZyBTaGFwaXJvLVdpbGsgTm9ybWFsaXR5IHRlc3QuIFdlIHdpbGwgZm9jdXMgb24gdGhlIGludmVyc2UgU2ltcHNvbiBhbmQgU2hhbm5vbiBkaXZlcnNpdHkgZXN0aW1hdGVzIGFuZCBDaGFv4oCZcyByaWNobmVzcyBlc3RpbWF0ZSAgYnV0IHRoaXMgYXBwcm9hY2ggY2FuIGJlIHVzZWQgZm9yIGFueSBtZXRyaWMuCgpgYGB7ciBhbHBoYV9kaXZfdGVzdF9ub3JtLCB3YXJuaW5nID0gRkFMU0V9CiMgQ29udmVydCB0byBwcyBvYmplY3QKc2FtcGxlX2RpdiA8LSBzYW1wbGVfZGF0YShkaXZlcnNpdHkpIAojIENyZWF0ZSBuZXcgcHMgb2JqZWN0IHdpdGggZGl2ZXJzaXR5IGVzdGltYXRlcyBhZGRlZCB0byBzYW1wbGVfZGF0YQpwc19zbHZfd29ya19maWx0X2RpdiA8LSBtZXJnZV9waHlsb3NlcShwc19zbHZfd29ya19maWx0LCBzYW1wbGVfZGl2KQojIFJ1biBTaGFwaXJvIHRlc3QKc2hhcGlyb190ZXN0X1NoYW4gPC0gc2hhcGlyby50ZXN0KHNhbXBsZV9kYXRhKHBzX3Nsdl93b3JrX2ZpbHRfZGl2KSRTaGFubm9uKQpzaGFwaXJvX3Rlc3RfaW52U2ltcCA8LSBzaGFwaXJvLnRlc3Qoc2FtcGxlX2RhdGEocHNfc2x2X3dvcmtfZmlsdF9kaXYpJEludlNpbXBzb24pCnNoYXBpcm9fdGVzdF9DaGFvMSA8LSBzaGFwaXJvLnRlc3Qoc2FtcGxlX2RhdGEocHNfc2x2X3dvcmtfZmlsdF9kaXYpJENoYW8xKQpzaGFwaXJvX3Rlc3RfT2JzZXJ2ZWQgPC0gc2hhcGlyby50ZXN0KHNhbXBsZV9kYXRhKHBzX3Nsdl93b3JrX2ZpbHRfZGl2KSRPYnNlcnZlZCkKYGBgCgpTaGFwaXJvLVdpbGsgTm9ybWFsaXR5IFRlc3QgZm9yICoqU2hhbm5vbioqIGluZGV4LgpgYGB7ciBzaGFwX1NoYW4sIGVjaG8gPSBGQUxTRX0Kc2hhcGlyb190ZXN0X1NoYW4KYGBgCgpTaGFwaXJvLVdpbGsgTm9ybWFsaXR5IFRlc3QgZm9yICoqaW52ZXJzZSBTaW1wc29uKiogaW5kZXguCmBgYHtyIHNoYXBfaW52UywgZWNobyA9IEZBTFNFfQpzaGFwaXJvX3Rlc3RfaW52U2ltcApgYGAKClNoYXBpcm8tV2lsayBOb3JtYWxpdHkgVGVzdCBmb3IgKipDaGFvMSByaWNobmVzcyoqIGVzdGltYXRvci4KYGBge3Igc2hhcF9DaG9hMSwgZWNobyA9IEZBTFNFfQpzaGFwaXJvX3Rlc3RfQ2hhbzEKYGBgCgpTaGFwaXJvLVdpbGsgTm9ybWFsaXR5IFRlc3QgZm9yICoqT2JzZXJ2ZWQgQVNWIHJpY2huZXNzKiogZXN0aW1hdG9yLgpgYGB7ciBzaGFwX09ic2VydmVkLCBlY2hvID0gRkFMU0V9CnNoYXBpcm9fdGVzdF9PYnNlcnZlZApgYGAKCk9rLCBzaW5jZSB0aGUgcC12YWx1ZXMgYXJlIHNpZ25pZmljYW50IGZvciB0aGUgaW52ZXJzZSBTaW1wc29uLCBDaGFvIHJpY2huZXNzLCBhbmQgT2JzZXJ2ZWQgQVNWIHJpY2huZXNzIHdlIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzIHRoYXQgdGhlc2UgZGF0YSBhcmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuIEhvd2V2ZXIsIHRoZSBTaGFubm9uIGVzdGltYXRlcyBhcHBlYXIgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuIFNvIGxldHMgc2VlIGlmIGRpdmVyc2l0eSBpcyBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBiZXR3ZWVuIGhvc3Qgc3BlY2llcyBiYXNlZCBvbiB0aGUgU2hhbm5vbiBpbmRleC4gCgojIyMjIE5vcm1hbGx5IGRpc3RyaWJ1dGVkIG1ldHJpY3MKClNpbmNlIHRoZSBTaGFubm9uIGRhdGEgaXMgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgd2UgY2FuIHRlc3QgZm9yIHNpZ25pZmljYW5jZSB1c2luZyBBTk9WQSAoYSBwYXJhbWV0cmljIHRlc3QpLgoKYGBge3Igbm9ybWFsfQpzYW1wbGVkYXRhREYgPC0gZGF0YS5mcmFtZShzYW1wbGVfZGF0YShwc19zbHZfd29ya19maWx0X2RpdikpCmFvdi5zaGFubm9uIDwtIGFvdihTaGFubm9uIH4gU3AsIGRhdGEgPSBzYW1wbGVkYXRhREYpCiNDYWxsIGZvciB0aGUgc3VtbWFyeSBvZiB0aGF0IEFOT1ZBLCB3aGljaCB3aWxsIGluY2x1ZGUgUC12YWx1ZXMKc3VtbWFyeShhb3Yuc2hhbm5vbikKYGBgCgpPaywgdGhlIHJlc3VsdHMgb2YgdGhlIEFOT1ZBIGFyZSBzaWduaWZpY2FudC4gIEhlcmUgd2UgdXNlIHRoZSBUdWtleSdzIEhTRCAoaG9uZXN0bHkgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSkgcG9zdC1ob2MgdGVzdCB0byBkZXRlcm1pbmUgd2hpY2ggcGFpcndpc2UgY29tcGFyaXNvbnMgYXJlIGRpZmZlcmVudC4KYGBge3IgdHVrZXl9ClR1a2V5SFNEKGFvdi5zaGFubm9uKQpgYGAKCkxvb2tzIGxpa2UgKlNwYXJpc29tYSBhdXJvZnJlbmF0dW0qIGlzIHNpZ25pZmljYW50bHkgZGlmZmVyZW50IGZyb20gKlNjYXJ1cyB0YWVuaW9wdGVydXMqIGFuZCAqQWNhbnRodXJ1cyB0cmFjdHVzKi4gIAoKIyMjIyBOb24tbm9ybWFsbHkgZGlzdHJpYnV0ZWQgbWV0cmljcwoKTm93IHdlIGNhbiBsb29rIGF0IHRoZSByZXN1bHRzIG9uIHRoZSAgaW52ZXJzZSBTaW1wc29uIGRpdmVyc2l0eSBhbmQgQ2hhb+KAmXMgcmljaG5lc3MuIFNpbmNlIGhvc3Qgc3BlY2llcyBpcyBjYXRlZ29yaWNhbCwgd2UgdXNlIEtydXNrYWwtV2FsbGlzIChub24tcGFyYW1ldHJpYyBlcXVpdmFsZW50IG9mIEFOT1ZBKSB0byB0ZXN0IGZvciBzaWduaWZpY2FuY2UuCgoqKioKCktydXNrYWwtV2FsbGlzIG9mICoqaW52ZXJzZSBTaW1wc29uKiogaW5kZXguCgpgYGB7ciBrcnVza19pbnZzaW1wfQojbGlicmFyeShGU0EpCiNkdW5uVGVzdChJbnZTaW1wc29uIH4gU3AsIGRhdGEgPSBzYW1wbGVkYXRhREYsIG1ldGhvZD0iYmgiKSAKa3J1c2thbC50ZXN0KEludlNpbXBzb24gfiBTcCwgZGF0YSA9IHNhbXBsZWRhdGFERikKYGBgCgpLcnVza2FsLVdhbGxpcyBvZiAqKkNoYW8xIHJpY2huZXNzKiogZXN0aW1hdG9yLgoKYGBge3Iga3J1c2tfY2hhb30KI2R1bm5UZXN0KENoYW8xIH4gU3AsIGRhdGEgPSBzYW1wbGVkYXRhREYsIG1ldGhvZD0iYmgiKSAKa3J1c2thbC50ZXN0KENoYW8xIH4gU3AsIGRhdGEgPSBzYW1wbGVkYXRhREYpCmBgYAoKS3J1c2thbC1XYWxsaXMgb2YgKipPYnNlcnZlZCBBU1YgcmljaG5lc3MqKiBpbmRleC4KCmBgYHtyIGtydXNrX29ic2VydmVkfQojbGlicmFyeShGU0EpCiNkdW5uVGVzdChPYnNlcnZlZCB+IFNwLCBkYXRhID0gc2FtcGxlZGF0YURGLCBtZXRob2Q9ImJoIikgCmtydXNrYWwudGVzdChPYnNlcnZlZCB+IFNwLCBkYXRhID0gc2FtcGxlZGF0YURGKQpgYGAKCioqKgoKRm9yIHRoZSBpbnZlcnNlIFNpbXBzb24sIENoYW8xLCBhbmQgT2JzZXJ2ZWQgcmljaG5lc3MgdGhlIHJlc3VsdHMgb2YgdGhlIEtydXNrYWwtV2FsbGlzIHJhbmsgc3VtIHRlc3QgYXJlIHNpZ25pZmljYW50LiBTbyB3ZSBjYW4gbG9vayBhdCBwYWlyd2lzZSBjb21wYXJpc29ucyB1c2luZyBXaWxjb3hvbiByYW5rIHN1bSB0ZXN0IGZvciBwb3N0LWhvYyBhbmFseXNpcy4KClBhaXJ3aXNlIHNpZ25pZmljYW5jZSB0ZXN0IGZvciAqKmludmVyc2UgU2ltcHNvbioqIGluZGV4LgoKYGBge3Igd2lsY294X2ludnNpbXB9CnBhaXJ3aXNlLndpbGNveC50ZXN0KHNhbXBsZWRhdGFERiRJbnZTaW1wc29uLCBzYW1wbGVkYXRhREYkU3AsIAogICAgICAgICAgICAgICAgICAgICBwLmFkanVzdC5tZXRob2QgPSAiZmRyIikKYGBgCgpQYWlyd2lzZSBzaWduaWZpY2FuY2UgdGVzdCBmb3IgKipDaGFvMSByaWNobmVzcyoqIGVzdGltYXRvci4KYGBge3Igd2lsY294X2NoYW99CnBhaXJ3aXNlLndpbGNveC50ZXN0KHNhbXBsZWRhdGFERiRDaGFvMSwgc2FtcGxlZGF0YURGJFNwLCAKICAgICAgICAgICAgICAgICAgICAgcC5hZGp1c3QubWV0aG9kID0gImZkciIpCmBgYAoKUGFpcndpc2Ugc2lnbmlmaWNhbmNlIHRlc3QgZm9yICoqT2JzZXJ2ZWQgQVNWIHJpY2huZXNzKiogaW5kZXguCgpgYGB7ciB3aWxjb3hfb2JzZXJ2ZWQsIHdhcm5pbmcgPSBGQUxTRX0KcGFpcndpc2Uud2lsY294LnRlc3Qoc2FtcGxlZGF0YURGJE9ic2VydmVkLCBzYW1wbGVkYXRhREYkU3AsIAogICAgICAgICAgICAgICAgICAgICBwLmFkanVzdC5tZXRob2QgPSAiZmRyIikKYGBgCgpBZ2FpbiB3ZSBzZWUgdGhhdCBvbmx5ICpTcC4gYXVyb2ZyZW5hdHVtKiBpcyBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBmcm9tIHRoZSBvdGhlciBob3N0cy4gRm9yIHRoZSBpbnZlcnNlIFNpbXBzb24gaW5kZXgsICpTcC4gYXVyb2ZyZW5hdHVtKiBpcyAgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgZnJvbSB0aHJlZSBvZiB0aGUgZm91ciBob3N0IHNwZWNpZXMgYW5kIENoYW8xIHJpY2huZXNzIGVzdGltYXRvciwgKlNwLiBhdXJvZnJlbmF0dW0qIGlzIHNpZ25pZmljYW50bHkgZGlmZmVyZW50IGZyb20gYWxsIG90aGVyIGhvc3Qgc3BlY2llcy4gTm93IHdlIGNhbiBwbG90IHRoZSByZXN1bHRzLiAKCioqKgoKIyMjIyAkXGFscGhhJC1kaXZlcnNpdHkgcGxvdHMKCkhlcmUgd2UgcGxvdCB0aGUgcmVzdWx0cyBvZiBTaGFubm9uIGRpdmVyc2l0eSBpbmRleC4gV2Ugd2lsbCBzYXZlIGEgY29weSBvZiB0aGUgZmlndXJlIGZvciBsYXRlciB0d2Vha2luZy4gV2UgdXNlIHRoZSBjb2xvciBwYWxldHRlIGRlc2NyaWJlZCBhYm92ZSB0byBkZWxpbmVhdGUgaG9zdCBzcGVjaWVzLgoKIyMjIyA8Zm9udCBjb2xvcj0icmVkIj5GaWd1cmUgMkI8L2ZvbnQ+CgpgYGB7ciBhbHBoYV9kaXZfZmlnXzJCLCBmaWcuYWxpZ24gPSAiY2VudGVyIiwgZmlnLmNhcCA9ICJGaWd1cmUgMkIiLCB3YXJuaW5nID0gRkFMU0V9CmZpZzJCIDwtIHBsb3RfcmljaG5lc3MocHNfc2x2X3dvcmtfZmlsdCwgeCA9ICJTcCIsIAogICAgICAgICAgICAgICAgICAgICAgIG1lYXN1cmVzID0gYygiT2JzZXJ2ZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2hhbm5vbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSW52U2ltcHNvbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ2hhbzEiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiU3AiLCBucm93ID0gMSkKZmlnMkIgPC0gZmlnMkIgKyBnZW9tX2JveHBsb3QoKSArIGdlb21faml0dGVyKHdpZHRoID0gMC4wNSkKZmlnMkIgPC0gZmlnMkIgKyBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IHNhbXBfcGFsKSArIAogICAgICAgICBsYWJzKHggPSAiSG9zdCBzcGVjaWVzIiwgCiAgICAgICAgIHkgPSAiRGl2ZXJzaXR5IiwgCiAgICAgICAgIHRpdGxlID0gIkFscGhhIGRpdmVyc2l0eSBvZiBiYWN0ZXJpYWwgCiAgICAgICAgIGNvbW11bml0aWVzIGluIGhlcmJpdm9yb3VzIHJlZWYgZmlzaCIpCiNmaWcyQiArIGdlb21fYm94cGxvdChhZXMoY29sb3VyID0gYmxhY2spKQojZmlnMkIgPC0gZmlnMkIgKyB0aGVtZV9idygpICsgZ2VvbV9wb2ludChzaXplID0gMi41LCBhZXMoY29sb3IgPSBTcCkpICsgCmZpZzJCCnBkZigiRklHVVJFUy9PVVRQVVQvRmlndXJlXzJCLnBkZiIpCmZpZzJCCmludmlzaWJsZShpbnZpc2libGUoZGV2Lm9mZigpKSkKYGBgCgoqKioKCiMjIyMgQ29ycmVsYXRpb25zIHdpdGggJFxhbHBoYSQtZGl2ZXJzaXR5CgpOZXh0IHdlIHdhbnRlZCB0byBrbm93IGlmIGFueSBhbHBoYS1kaXZlcnNpdHkgbWV0cmljcyB3ZXJlIGNvcnJlbGF0ZWQgd2l0aCBob3N0IHBoeXNpY2FsIGNoYXJhY3RlcmlzdGljcy4gQXQgdGhlIHRpbWUgb2YgY29sbGVjdGlvbiwgd2UgcmVjb3JkZWQgaG9zdCB3ZWlnaHQsIHRvdGFsIGxlbmd0aCwgdG90YWwgZ3V0IGxlbmd0aCwgYXMgd2VsbCBhcyB0aGUgbGVuZ3RoIG9mIGluZGl2aWR1YWwgZ3V0IHNlZ21lbnRzIChmb3JlLCBtaWQsIGhpbmQpLgoKV2hlbiBjb25zaWRlcmluZyB0aGUgZGF0YXNldCBhcyBhIHdob2xlIChpLmUuLCBhbGwgc2FtcGxlcyksIHdlIGZvdW5kIG5vIGNvcnJlbGF0aW9uIGJldHdlZW4gYW55IHBoeXNpY2FsIGNoYXJhY3RlcmlzdGljcyBhbmQgYW55IGRpdmVyc2l0eSBtZXRyaWNzLiBJZiB3ZSBzcGxpdCBzYW1wbGVzIGJ5IGdlbmVyYSB3ZSBmb3VuZCB0aGF0IG5laXRoZXIgKkFjYW50aHVydXMqIG5vciAqU2NhcnVzKiB3ZXJlIG5vdCBzaWduaWZpY2FudCBmb3IgYW55IHBhcmFtZXRlcnMgd2hpbGUgKlNwYXJpc29tYSogc2hvd2VkIHNpZ25pZmljYW50IHJlc3VsdHMgZm9yIGFsbCBwYXJhbWV0ZXJzIGV4Y2VwdCBoaW5kZ3V0X2xlbmd0aC4gCgoKYGBge3IgcnVuX2NvcnJlbGF0aW9ucywgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0V9CmR0IDwtIHJlYWQudGFibGUoIlRBQkxFUy9PVVRQVVQvU1VQUC9UYWJsZV9TMy50eHQiLCAKICAgICAgICAgICAgICAgICBzZXAgPSAiXHQiLCBoZWFkZXIgPSBUUlVFKQpsaWJyYXJ5KGdncHVicikKc2NhcnVzIDwtIGhvc3Rfc3VtbWFyeVtob3N0X3N1bW1hcnkkaG9zdF9nZW51cyAlaW4lICJTY2FydXMiLCBdCnNwYXJpc29tYSA8LSBob3N0X3N1bW1hcnlbaG9zdF9zdW1tYXJ5JGhvc3RfZ2VudXMgJWluJSAiU3Bhcmlzb21hIiwgXQphY2FudGh1cnVzIDwtIGhvc3Rfc3VtbWFyeVtob3N0X3N1bW1hcnkkaG9zdF9nZW51cyAlaW4lICJBY2FudGh1cnVzIiwgXQphbHBoYW1ldHJpYyA8LSBjKCJ0b3RhbF9BU1ZzIiwgIkNoYW8xIiwgIkFDRSIsICJTaGFubm9uIiwgCiAgICAgICAgICAgICAgICAiU2ltcHNvbiIsICAiSW52U2ltcHNvbiIsICJGaXNoZXIiKQpwaHlzaWNhbF9jaGFyIDwtIGMoIndlaWdodCIsICJ0b3RhbF9sZW5ndGgiLCAiZm9yZWd1dF9sZW5ndGgiLCAKICAgICAgICAgICAgICAgICAgICJtaWRndXRfbGVuZ3RoIiwgImhpbmRndXRfbGVuZ3RoIiwgInRvdGFsX2d1dF9sZW5ndGgiKQoKIyBGdWxsIHNldDogbm90IHNpZ25pZmljYW50IC0+ICJ3ZWlnaHQiLCAidG90YWxfbGVuZ3RoIgogICAgICAgICAgICAjImZvcmVndXRfbGVuZ3RoIiwgUiA9IDAuMzIKICAgICAgICAgICAgIyJtaWRndXRfbGVuZ3RoIiwgUiA9IDAuNTAKICAgICAgICAgICAgIyJoaW5kZ3V0X2xlbmd0aCIsIFIgPSAwLjE3LTAuMzQKICAgICAgICAgICAgIyJ0b3RhbF9ndXRfbGVuZ3RoIiBSID0gMC41MAoKI0J5IGdlbnVzIGFuZCBtaWRndXRfbGVuZ3RoIDoKICAgICAgICAgICMgc2NhcnVzIE5TCiAgICAgICAgICAjIHNwYXJpc29tYSBSID0gMC44CiAgICAgICAgICAjIGFjYW50aHVydXMgTlMKCiMgYWNhbnRodXJ1cyBub3Qgc2lnbmlmaWNhbnQgZm9yIGFueSBwYXJhbWV0ZXJzCiMgc2NhcnVzIG5vdCBzaWduaWZpY2FudCBmb3IgYW55IHBhcmFtZXRlcnMKIyBzcGFyaXNvbWEgIHNpZ25pZmljYW50IGZvciBhbGwgcGFyYW1ldGVycyBleGNlcHQgaGluZGd1dF9sZW5ndGggd2FzIGEgYml0IHdlYWsKIyAid2VpZ2h0IiwgInRvdGFsX2xlbmd0aCIgImZvcmVndXRfbGVuZ3RoIiAibWlkZ3V0X2xlbmd0aCIgCiMgImhpbmRndXRfbGVuZ3RoIiAidG90YWxfZ3V0X2xlbmd0aCIKCiMgVG8gZG8gYWxsIGRpdmVyc2l0eSBtZXRyaWMgIGNoYW5nZSAieSA9ICIgdG8geSA9IGFscGhhbWV0cmljIGFuZAojIHlsYWIgPSBhbHBoYW1ldHJpYwoKcGFyKG1mcm93ID0gYygyLCAzKSkKc2hhbl9ieV9sZW5ndGggPC0gZ2dzY2F0dGVyKGhvc3Rfc3VtbWFyeSwgeCA9ICJ0b3RhbF9ndXRfbGVuZ3RoIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gIlNoYW5ub24iLCBhZGQgPSAicmVnLmxpbmUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmYuaW50ID0gRkFMU0UsY29yLmNvZWYgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvci5tZXRob2QgPSAic3BlYXJtYW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgeGxhYiA9ICJ0b3RhbF9sZW5ndGggKGNtKSIsIHlsYWIgPSAiU2hhbm5vbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiaG9zdF9nZW51cyIsIHBhbGV0dGUgPSBzYW1wX3BhbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZCA9ICJib3R0b20iKQoKc2hhbl9ieV93ZWlnaHQgPC0gZ2dzY2F0dGVyKGhvc3Rfc3VtbWFyeSwgeCA9ICJ3ZWlnaHQiLCB5ID0gIlNoYW5ub24iLCAKICAgICAgICAgIGFkZCA9ICJyZWcubGluZSIsIGNvbmYuaW50ID0gRkFMU0UsIAogICAgICAgICAgY29yLmNvZWYgPSBUUlVFLCBjb3IubWV0aG9kID0gInNwZWFybWFuIiwKICAgICAgICAgIHhsYWIgPSAid2VpZ2h0IChnKSIsIHlsYWIgPSAiU2hhbm5vbiIsIAogICAgICAgICAgY29sb3IgPSAiaG9zdF9nZW51cyIsIHBhbGV0dGUgPSBzYW1wX3BhbCwgbGVnZW5kID0gInRvcCIpCgpncmlkLmFycmFuZ2Uoc2hhbl9ieV9sZW5ndGgsIHNoYW5fYnlfd2VpZ2h0LCBuY29sID0gMikKCiNnZ3NjYXR0ZXIoaG9zdF9zdW1tYXJ5LCB4ID0gInRvdGFsX2d1dF9sZW5ndGgiLCB5ID0gYWxwaGFtZXRyaWMsIAojICAgICAgICAgIGFkZCA9ICJyZWcubGluZSIsIGNvbmYuaW50ID0gRkFMU0UsIAojICAgICAgICAgIGNvci5jb2VmID0gVFJVRSwgY29yLm1ldGhvZCA9ICJzcGVhcm1hbiIsCiMgICAgICAgICAgeGxhYiA9ICJtaWQtZ3V0IGxlbmd0aCAoY20pIiwgeWxhYiA9IGFscGhhbWV0cmljLCAKIyAgICAgICAgICBjb2xvciA9ICJob3N0X2dlbnVzIiwgcGFsZXR0ZSA9IHNhbXBfcGFsKQoKCiMsIGZhY2V0LmJ5ID0gImhvc3Rfc3BlY2llcyIpCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojc2hhcGlyby50ZXN0KGhvc3Rfc3VtbWFyeSRTaGFubm9uKSAjID0+IHAgPSAwLjEyMjkKIyMgU2hhcGlyby1XaWxrIG5vcm1hbGl0eSB0ZXN0IGZvciB3dAojc2hhcGlyby50ZXN0KGhvc3Rfc3VtbWFyeSRtaWRndXRfbGVuZ3RoKSAjID0+IHAgPSAwLjA5CiNnZ3FxcGxvdChob3N0X3N1bW1hcnkkU2hhbm5vbikgIyA9PiBwID0gMC4xMjI5CiMjIFNoYXBpcm8tV2lsayBub3JtYWxpdHkgdGVzdCBmb3Igd3QKI2dncXFwbG90KGhvc3Rfc3VtbWFyeSRtaWRndXRfbGVuZ3RoKSAjID0+IHAgPSAwLjA5CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpgYGAKCjwhLS1UT0RPOiBjaGFuZ2UgYm94ZXMgYW5kIGxpbmVzIHRvIGJsYWNrLS1hZGQgcG9pbnQgYm9hcmRlcnMtLT4KCiMjIyAkXGJldGEkLWRpdmVyc2l0eQoKIyMjIyAkXGJldGEkLWRpdmVyc2l0eSBwbG90cwoKQmV0YSBkaXZlcnNpdHkgYmFzaWNhbGx5IHRlbGxzIHVzIGhvdyBzaW1pbGFyIG9yIGRpc3NpbWlsYXIgc2FtcGxlcyBhcmUgdG8gb25lIGFub3RoZXIuIFBoeWxvc2VxIG9mZmVycyBzZXZlcmFsIG9yZGluYXRpb24gYG1ldGhvZHNgIGFuZCBgZGlzdGFuY2VgIG1ldHJpY3MuIEhlcmUgd2UgdXNlIG5vbiBtZXRyaWMgbXVsdGlkaW1lbnNpb25hbCBzY2FsaW5nIChOTURTKSBjb3VwbGVkIHdpdGggSmVuc2Vu4oCTU2hhbm5vbiBkaXZlcmdlbmNlLiBXZSBhbHNvIHNhdmUgYSBjb3B5IG9mIHRoZSBmaWd1cmUgZm9yIGxhdGVyIHR3ZWFraW5nLiBUbyBzZWUgdGhlIGZ1bGwgb3V0cHV0IG9mIHRoZSBOTURTIGFuYWx5c2lzLCByZW1vdmUgdGhlIGByZXN1bHRzID0gJ2hpZGUnYCB0YWcgZnJvbSB0aGUgY29kZSBjaHVuay4KCmBgYHtyIHJ1bl9ubWRzLCByZXN1bHRzID0gJ2hpZGUnfSAKc2V0LnNlZWQoMzEzMSkKb3JkLm5tZHMuanNkX3NsdiA8LSBvcmRpbmF0ZShwc19zbHZfd29ya19maWx0LCBtZXRob2QgPSAiTk1EUyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpc3RhbmNlID0gImpzZCIpCnN0cmVzc3Bsb3Qob3JkLm5tZHMuanNkX3NsdikKYGBgCgpgYGB7ciBvcmRfcmVzdWx0cywgZWNobyA9IEZBTFNFfQpvcmQubm1kcy5qc2Rfc2x2CmBgYApXZSBzZWUgdGhhdCBhIGNvbnZlcmdlbnQgc29sdXRpb24gd2FzIHJlYWNoZWQgYXJvdW5kIDIwIGl0ZXJhdGlvbnMgYW5kIG91ciBzdHJlc3MgaXMgYmVsb3cgMC4yMCwgbWVhbmluZyB0aGF0IDItYXhlcyBhcmUgc3VmZmljaWVudCB0byB2aWV3IHRoZSBkYXRhLiBHZW5lcmFsbHksIHdlIGFyZSBsb29raW5nIGZvciBzdHJlc3MgdmFsdWVzIGJlbG93IDAuMi4gSWYgdGhlIHN0cmVzcyB2YWx1ZXMgYXJlIGhpZ2gsIHlvdSBtYXkgbmVlZCB0byBhZGQgbW9yZSBheGVzIHRvIHRoZSBvcmRpbmF0aW9uLiBMZXRzIHZpc3VhbGl6ZSB0aGUgcGxvdC4KCiMjIyMgPGZvbnQgY29sb3I9InJlZCI+RmlndXJlIDJDPC9mb250PgoKYGBge3IgYmV0YV9kaXZfZmlnXzJDLCBmaWcuYWxpZ24gPSAiY2VudGVyIiwgZmlnLmNhcCA9ICJGaWd1cmUgMkMifQpmaWcyQyA8LSBwbG90X29yZGluYXRpb24ocHNfc2x2X3dvcmtfZmlsdCwgb3JkLm5tZHMuanNkX3NsdiwgCiAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJTcCIsIGxhYmVsID0gIlNhbU5hbWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIkplbnNlbi1TaGFubm9uIGRpdmVyZ2VuY2UiKQoKZmlnMkMgPC0gZmlnMkMgKyBnZW9tX3BvaW50KHNpemUgPSA0KSArIAogIGdlb21fcG9pbnQoc2hhcGUgPSAxLCBzaXplID0gMy42LCBjb2xvdXIgPSAiYmxhY2siLCBzdHJva2UgPSAwLjc1KSAKIyArICB4bGltKC0wLjQsIDAuNCkgKyB5bGltKC0wLjQsIDAuNCkKCmZpZzJDIDwtIGZpZzJDICsgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBzYW1wX3BhbCkKCmZpZzJDIDwtIGZpZzJDICsgdGhlbWUoYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJibGFjayIpLCAKICAgICAgICAgICAgICAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgICAgICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKCJncmV5IiksIAogICAgICAgICAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2xpbmUoImdyZXkiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgcGFuZWwuYm9yZGVyID0gCiAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIiwgZmlsbCA9IE5BLCBzaXplID0gMSkpICsgCiAgdGhlbWUobGVnZW5kLmtleSA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiYmxhY2siKSkKCmZpZzJDIDwtIGZpZzJDICsgY29vcmRfZml4ZWQoKQpmaWcyQyA8LSBmaWcyQyAgKyBzdGF0X2VsbGlwc2UodHlwZSA9ICJ0IikgKyB0aGVtZV9idygpCmZpZzJDCnBkZigiRklHVVJFUy9PVVRQVVQvRmlndXJlXzJDLnBkZiIpCmZpZzJDCmludmlzaWJsZShkZXYub2ZmKCkpCmBgYAoKU28gd2UgY2FuIHNlZSBzb21lIGNsdXN0ZXJpbmcgd2l0aGluIGdyb3VwcyBhbmQgc3ByZWFkIGJldHdlZW4gZ3JvdXBzLCBidXQgdGhpcyBpcyBub3QgYSB0ZXN0IGZvciBzdGF0aXN0aWNhbCBkaWZmZXJlbmNlcy4gRG8gbWljcm9iaWFsIGNvbW11bml0aWVzIGRpZmZlciBzaWduaWZpY2FudGx5IGJ5IGhvc3QgdGF4YT8gCgojIyMjICRcYmV0YSQtZGl2ZXJzaXR5IHN0YXRpc3RpY2FsIHRlc3RzCgpUbyB0ZXN0IHdoZXRoZXIgbWljcm9iaWFsIGNvbW11bml0aWVzIGRpZmZlciBieSBob3N0IHNwZWNpZXMgd2UgY2FuIHVzZSBwZXJtdXRhdGlvbmFsIGFuYWx5c2lzIG9mIHZhcmlhbmNlIChQRVJNQU5PVkEpIG9yIGFuYWx5c2lzIG9mIHNpbWlsYXJpdHkgKEFOT1NJTSkuIFBFUk1BTk9WQSBkb2VzIG5vdCBhc3N1bWUgbm9ybWFsaXR5IGJ1dCBkb2VzIGFzc3VtZSBlcXVhbCBiZXRhIGRpc3BlcnNpb24gYmV0d2VlbiBncm91cHMuIFdlIHdpbGwgdGVzdCBiZXRhIGRpc3BlcnNpb24gYmVsb3cuCgpGaXJzdCAgd2UgdXNlIHRoZSBgYWRvbmlzYCBmdW5jdGlvbiBpbiB2ZWdhbiB0byBydW4gYSBQRVJNQU5PVkEgdGVzdC4gVGhpcyB3aWxsIHRlbGwgdXMgd2hldGhlciBob3N0IHNwZWNpZXMgaGF2ZSBzaW1pbGFyIGNlbnRyb2lkcyBvciBub3QuIAoKYGBge3Igb3JkaW5hdGlvbl9zdGF0c19hZG9uaXN9CnNldC5zZWVkKDE5MTEpCmZpc2guanNkIDwtIHBoeWxvc2VxOjpkaXN0YW5jZShwc19zbHZfd29ya19maWx0LCBtZXRob2QgPSAianNkIikKc2FtcGxlZGYgPC0gZGF0YS5mcmFtZShzYW1wbGVfZGF0YShwc19zbHZfd29ya19maWx0KSkKZmlzaF9hZG9uaXMgPC0gYWRvbmlzKGZpc2guanNkIH4gU3AsIGRhdGEgPSBzYW1wbGVkZiwgcGVybXV0YXRpb25zID0gMTAwMCkKZmlzaF9hZG9uaXMKYGBgCgpUaGVzZSByZXN1bHRzIGluZGljYXRlIHRoYXQgY2VudHJvaWRzIGFyZSBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBhY3Jvc3MgaG9zdCBzcGVjaWVzIG1lYW5pbmcgdGhhdCBjb21tdW5pdGllcyBhcmUgZGlmZmVyZW50IGJ5IGhvc3Qgc3BlY2llcy4gCgpXZSBjYW4gYWxzbyB1c2UgdGhlIGBwYWlyd2lzZUFkb25pc2AgcGFja2FnZSBmb3IgcGFpci13aXNlIFBFUk1BTk9WQSBhbmFseXNpcy4KCmBgYHtyIHBhaXJ3aXNlX2Fkb25pc30KcGFpcndpc2UuYWRvbmlzKGZpc2guanNkLCBmYWN0b3JzID0gc2FtcGxlZGYkU3AsIHAuYWRqdXN0Lm0gPSAiYm9uZmVycm9uaSIpCmBgYAoKSGVyZSB3ZSBzZWUgIGFnYWluIHdlIHNlZSB0aGF0IGNvbW11bml0aWVzIGFyZSBkaWZmZXJlbnQgYnkgaG9zdCBzcGVjaWVzLiAKCkhvd2V2ZXIsIFBFUk1BTk9WQSBhc3N1bWVzIGVxdWFsIGJldGEgZGlzcGVyc2lvbiBzbyB3ZSB3aWxsICB1c2UgdGhlIGBiZXRhZGlzcGVyYCBmdW5jdGlvbiBmcm9tIHRoZSBgdmVnYW5gIHBhY2thZ2UgdG8gY2FsY3VsYXRlIGJldGEgZGlzcGVyc2lvbiB2YWx1ZXMuIAoKYGBge3IgYmV0YWRpc3Blcn0KYmV0YV9hZG9uaXMgPC0gYmV0YWRpc3BlcihmaXNoLmpzZCwgc2FtcGxlZGYkU3AsIGJpYXMuYWRqdXN0ID0gVFJVRSkKYmV0YV9hZG9uaXMKYGBgCgpBbmQgdGhlbiBhIHBhaXItd2lzZSBQZXJtdXRhdGlvbiB0ZXN0IGZvciBob21vZ2VuZWl0eSBvZiBtdWx0aXZhcmlhdGUgZGlzcGVyc2lvbnMgdXNpbmcgYHBlcm11dGVzdGAgKGFnYWluIGZyb20gdGhlIGB2ZWdhbmAgcGFja2FnZSkuIApgYGB7ciBwZXJtdXRlc3R9CnBlcm11dGVzdChiZXRhX2Fkb25pcywgcGFpcndpc2UgPSBUUlVFLCBwZXJtdXRhdGlvbnMgPSAxMDAwKQpgYGAKClRoZXNlIHJlc3VsdHMgYXJlIHNpZ25pZmljYW50LCBtZWFuaW5nIHRoYXQgIGhvc3Qgc3BlY2llcyBoYXZlIGRpZmZlcmVudCBkaXNwZXJzaW9ucy4gTG9va2luZyBhdCB0aGUgcGFpcndpc2UgcC12YWx1ZXMgYW5kIHBlcm11dGVkIHAtdmFsdWUsIHdlIHNlZSB0aGF0IHRoZSAgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZXMgKHAtdmFsdWUgPCAwLjA1KSBhcmUgYmV0d2VlbjogCgoqIFNwQXVyICYgQWNDb2UsIEFjVHJhCiogU2NUYWUgJiBBY0NvZSwgQWNUcmEsIFNwVmlyCgpUaGlzIG1lYW5zIHdlIGFyZSBsZXNzIGNvbmZpZGVudCB0aGF0IHRoZSBQRVJNQU5PVkEgcmVzdWx0IGlzIGEgcmVhbCByZXN1bHQsIGFuZCB0aGF0IHRoZSByZXN1bHQgaXMgcG9zc2libHkgZHVlIHRvIGRpZmZlcmVuY2VzIGluIGdyb3VwIGRpc3BlcnNpb25zLgoKV2UgY2FuIGFsc28gdXNlIEFuYWx5c2lzIG9mIFNpbWlsYXJpdHkgKEFOT1NJTSktLS13aGljaCBkb2VzIG5vdCBhc3N1bWUgZXF1YWwgZ3JvdXAgdmFyaWFuY2VzLS0tdG8gdGVzdCB3aGV0aGVyIG92ZXJhbGwgbWljcm9iaWFsIGNvbW11bml0aWVzIGRpZmZlciBieSBob3N0IHNwZWNpZXMuCgpgYGB7ciBvcmRpbmF0aW9uX3N0YXRzX2Fub3NpbX0Kc3Bncm91cCA8LSBnZXRfdmFyaWFibGUocHNfc2x2X3dvcmtfZmlsdCwgIlNwIikKZmlzaF9hbm9zaW0gPC0gYW5vc2ltKGRpc3RhbmNlKHBzX3Nsdl93b3JrX2ZpbHQsICJqc2QiKSwgZ3JvdXBpbmcgPSBzcGdyb3VwKQpzdW1tYXJ5KGZpc2hfYW5vc2ltKQpgYGAKCkFuZCB0aGUgQU4wU0lNIHJlc3VsdCBpcyBzaWduaWZpY2FudCBtZWFuaW5nIHRoYXQgaG9zdCBzcGVjaWVzIGluZmx1ZW5jZXMgbWljcm9iaWFsIGNvbW11bml0eSBjb21wb3NpdGlvbi4gCgpgYGB7ciBzaW1wZXIsIGV2YWwgPSBGQUxTRSwgZWNobyA9IEZBTFNFLCBpbmNsdWRlID0gRkFMU0V9CnNvdXJjZSgiSEVMUEVSX1NDUklQVFMvc2ltcGVyX3ByZXR0eS5SIikKI1VzaW5nIHRoZSBmdW5jdGlvbgpvdHV0YWIgPC0gYXMudGFibGUob3R1X3RhYmxlKHBzX3Nsdl93b3JrX2ZpbHQpKQpzdHVmZiA8LSBzaW1wZXIucHJldHR5KG90dV90YWJsZShwc19zbHZfd29ya19maWx0KSwgCiAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlX2RhdGEocHNfc2x2X3dvcmtfZmlsdCksICJTcCIsIAogICAgICAgICAgICAgICAgICAgICAgIHBlcmNfY3V0b2ZmID0gMC41LCBsb3dfY3V0b2ZmID0gInkiLAogICAgICAgICAgICAgICAgICAgICAgIGxvd192YWwgPSAwLjAxLCAibmFtZSIpCmBgYAoKCioqKgoKPGEgaWQ9IlBhcnQgSVY6IERpZmZlcmVudGlhbGx5IEFidW5kYW50IEFTVnMiPjwvYT4gIAoKIyMgUGFydCBJVjogRGlmZmVyZW50aWFsbHkgQWJ1bmRhbnQgQVNWcyAKCltiYWNrIHRvIHRvcF0oI2JhY2sgdG8gdG9wKQoKQXQgdGhpcyBwb2ludCB3ZSBoYXZlIGEgZ29vZCBoYW5kbGUgb24gdGhlIGRpdmVyc2l0eSBvZiB0aGUgaW50ZXN0aW5hbCBtaWNyb2Jpb21lcyBvZiB0aGVzZSBoZXJiaXZvcm91cyByZWVmIGZpc2guIFdlIGtub3cgdGhhdCBjb21tdW5pdGllcyBhcmUgZG9taW5hdGVkIGJ5IHRoZSBzYW1lIGJyb2FkLWxldmVsIHRheG9ub21pYyBncm91cHMuIFRoZSBiZXRhIGRpdmVyc2l0eSBhbmFseXNpcyBkZW1vbnN0cmF0ZXMgdGhhdCBjb21tdW5pdGllcyBwYXJ0aXRpb24gYWxvbmcgaG9zdCBzcGVjaWVzLiBOb3cgd2Ugd2FudCB0byBkZXRlcm1pbmUgd2hpY2ggQVNWcyBhcmUgZHJpdmluZyB0aGVzZSBwYXR0ZXJucyBhbmQgYXNzZXNzIHRoZWlyIGRpc3RyaWJ1dGlvbiBpbiBuYXR1cmUgdXNpbmcgcHVibGljbHkgYXZhaWxhYmxlIGRhdGEuIFRvIGFjY29tcGxpc2ggdGhpcyB0YXNrIHdlIGxlYXZlIHRoZSBgUmAgZW52aXJvbm1lbnQgYW5kIGVtcGxveSBzb21lIGFkZGl0aW9uYWwgdG9vbHMuIFRvIHN1bW1hcml6ZSwgb3VyIGdvYWxzIGhlcmUgYXJlIHRvOgoKPiBBKSBpZGVudGlmeSBkaWZmZXJlbnRpYWxseSBhYnVuZGFudCAoREEpIEFTVnMgYWNyb3NzIGhvc3Qgc3BlY2llcywgCj4gQikgZmluZCBjbG9zZXN0IGRhdGFiYXNlIG1hdGNoZXMgdG8gREEgQVNWcywgYW5kIAo+IEMpIHBlcmZvcm0gcGh5bG9nZW5ldGljIHJlY29uc3RydWN0aW9uIG9uIERBIEFTVnMgYW5kIHRvcCBoaXRzLgoKCiMjIyBEaWZmZXJlbnRpYWwgYWJ1bmRhbmNlIChEQSkKCldlIHVzZWQgW0xEQSBFZmZlY3QgU2l6ZSAoTEVmU2UpXShodHRwczovL2R4LmRvaS5vcmcvMTAuMTAzOCUyRm5tZXRoLjI2NTgpe3RhcmdldD0iX2JsYW5rIn0gdG8gaWRlbnRpZnkgZGlmZmVyZW50aWFsbHkgYWJ1bmRhbnQgKERBKSBBU1ZzIGFjcm9zcyBob3N0IHNwZWNpZXMgYW5kIHRoZSBbTWljcm9iaW9tZUFuYWx5c3Qgd2Vic2VydmVyXShodHRwOi8vd3d3Lm1pY3JvYmlvbWVhbmFseXN0LmNhLyl7dGFyZ2V0PSJfYmxhbmsifSB0byBydW4gdGhlIGFuYWx5c2lzLiBUaGVyZSBhcmUgYWxzbyBtYW55IG90aGVyIGdyZWF0IHRvb2xzIG9uIHRoZSBNaWNyb2Jpb21lQW5hbHlzdCB3ZWJzZXJ2ZXIgYnkgdGhlIHdheS4gV2UgbmVlZGVkIHRocmVlIGZpbGVzIGZvciB0aGUgaW5wdXQtLS1hbiAnT1RVJyB0YWJsZSwgYSBtZXRhZGF0YSBmaWxlIGNvbnRhaW5pbmcgc2FtcGxlIGluZm9ybWF0aW9uLCBhbmQgYSB0YXhvbm9teSB0YWJsZS4gV2UgZ2VuZXJhdGUgdGhlc2UgdGFibGVzIHdpdGggdGhlIGNvZGUgYmVsb3cuCgoKYGBge3IgZ2VuX2xlZnNlX2lucHV0X2ZpbGVzLCByZXN1bHRzPSdoaWRlJ30KIyMjIyMjIyMjIyBPVFUgdGFibGUKT1RVMSA8LSAgYXMob3R1X3RhYmxlKHBzX3Nsdl93b3JrX2ZpbHQpLCAibWF0cml4IikKIyB0cmFuc3Bvc2UgaWYgbmVjZXNzYXJ5CiMgQ29lcmNlIHRvIGRhdGEuZnJhbWUKT1RVZGYgPC0gYXMuZGF0YS5mcmFtZSh0KE9UVTEpKQpzZXREVChPVFVkZiwga2VlcC5yb3duYW1lcyA9IFRSVUUpW10Kd3JpdGUudGFibGUoT1RVZGYsICJUQUJMRVMvT1VUUFVUL09USEVSL3NlcV90YWJfZm9yX2NvcmUudHh0IiwgCiAgICBzZXAgPSAiXHQiLCByb3cubmFtZXMgPSBGQUxTRSwgcXVvdGUgPSBGQUxTRSkKY29sbmFtZXMoT1RVZGYpWzFdIDwtICIjTkFNRSIKd3JpdGUudGFibGUoT1RVZGYsICJUQUJMRVMvT1VUUFVUL0xFZlNlL0xFZlNlX0lOUFVUX3NlcV90YWIudHh0IiwgCiAgICAgICAgICAgIHNlcCA9ICJcdCIsIHJvdy5uYW1lcyA9IEZBTFNFLCBxdW90ZSA9IEZBTFNFKQojIyMjIyMjIyMjIyMgVEFYIFRhYmxlCiMgUmVtZW1iZXIgaW4gdGhlIGB0YXhfdGFibGVgIHdlIGFkZGVkIHRoZSBsYXN0IGNvbHVtbnMgYXMgdGhlIGFjdHVhbCBzZXF1ZW5jZSAKIyBvZiBlYWNoIEFTViBhbmQgdGhlIEFTVl9JRC4gV2UgZG8gbm90IG5lZWQgdGhvc2UgaGVyZS4KIyBTbyBsZXRzIG9ubHkga2VlcCB0aGUgZmlyc3QgNiBjb2x1bW5zICh0aGUgdGF4b25vbWljIGxpbmVhZ2UpClRBWDEgPC0gYXModGF4X3RhYmxlKHBzX3Nsdl93b3JrX2ZpbHQpLCAibWF0cml4IikKVEFYZGYgPC0gYXMuZGF0YS5mcmFtZShUQVgxKQpzZXREVChUQVhkZiwga2VlcC5yb3duYW1lcyA9IFRSVUUpW10KY29sbmFtZXMoVEFYZGYpWzFdIDwtICIjVEFYT05PTVkiClRBWGRmIDwtIFRBWGRmWywgMTo2XQp3cml0ZS50YWJsZShUQVhkZiwgIlRBQkxFUy9PVVRQVVQvTEVmU2UvTEVmU2VfSU5QVVRfdGF4X3RhYi50eHQiLCAKICAgICAgICAgICAgc2VwID0gIlx0Iiwgcm93Lm5hbWVzID0gRkFMU0UsIHF1b3RlID0gRkFMU0UpCiMjIyMjIyMjIyMjIyBNZXRhZGF0YSBmaWxlCm1ldGFfZmlsZSA8LSBkYXRhLmZyYW1lKE5BTUUgPSBzYW1wbGVfbmFtZSwgU2FtcGxlVHlwZSA9IHNwZWNpZXMsIEdlbiA9IGdlbnVzKQpyb3duYW1lcyhtZXRhX2ZpbGUpIDwtIHNhbXBsZXMub3V0CmNvbG5hbWVzKG1ldGFfZmlsZSkgPC0gIGMoIiNOQU1FIiwgIlNwZWNpZXMiLCAiR2VudXMiKQojIGJ1dCB3ZSBzdGlsbCBoYXZlIHRob3NlIHRocmVlIHNhbXBsZXMgdGhhdCBuZWVkIHRvIGJlIHJlbW92ZWQKbWV0YV9maWxlIDwtIGZpbHRlcihtZXRhX2ZpbGUsIFNwZWNpZXMgIT0gIlNwQ2hyIiAmIFNwZWNpZXMgIT0gIlNjVmV0IikKd3JpdGUudGFibGUobWV0YV9maWxlLCAiVEFCTEVTL09VVFBVVC9MRWZTZS9MRWZTZV9JTlBVVF9tZXRhZGF0YS50eHQiLCAKICAgICAgICAgICAgc2VwID0gIlx0Iiwgcm93Lm5hbWVzID0gRkFMU0UsIHF1b3RlID0gRkFMU0UpCmBgYAoKCkFuZCBvbmNlIHdlIGhhdmUgdGhlIHRocmVlIGZpbGVzLCB3ZSBoZWFkIG92ZXIgdG8gdGhlIFtNaWNyb2Jpb21lQW5hbHlzdCB3ZWJzZXJ2ZXJdKGh0dHA6Ly93d3cubWljcm9iaW9tZWFuYWx5c3QuY2EvKXt0YXJnZXQ9Il9ibGFuayJ9IGFuZCB1cGxvYWQgdGhlIGZpbGVzLiBCZSBzdXJlIHRvIHNlbGVjdCBgU2lsdmEgdGF4b25vbXlgIGluIHRoZSBkcm9wLWRvd24gbWVudS4gIApDaGVjayB0aGUgZGF0YSBzdW1tYXJ5IGFmdGVyIHVwbG9hZGluZyB0aGUgZmlsZXM6IAoKKiBPVFUgYW5ub3RhdGlvbjoJU0lMVkEKKiBPVFUgbnVtYmVyOgkxMTE0NAoqIE9UVSB3aXRoIOKJpSAyIGNvdW50czoJNDEyMQoqIFNhbXBsZSBudW1iZXI6CTUwCiogTnVtYmVyIG9mIGV4cGVyaW1lbnRhbCBmYWN0b3JzOgkyCiogVG90YWwgcmVhZCBjb3VudHM6CTI4MjgxMTIKKiBBdmVyYWdlIGNvdW50cyBwZXIgc2FtcGxlOgk1NjU2MgoqIE1heGltdW0gY291bnRzIHBlciBzYW1wbGU6CTE3NTExNgoqIE1pbmltdW0gY291bnRzIHBlciBzYW1wbGU6CTExNTY4CgpDb29sLCBhbGwgbG9va3MgZ29vZC4gSGl0IGBQcm9jZWVkYC4gSGVyZSBhcmUgdGhlIHNldHRpbmdzIHdlIHVzZWQgZm9yIHRoZSBkaWZmZXJlbnQgc3RlcDoKCiogKipGaWx0ZXIgdGhlIGRhdGEqKjogYE1pbmltdW0gY291bnQgPSAyMGAsIGBQcmV2YWxlbmNlIGluIHNhbXBsZXMgKCUpID0gMjBgLCBhbmQgYFBlcmNlbnRhZ2UgdG8gcmVtb3ZlICglKSA9IDBgLiBUaGlzIHJlbW92ZWQgKiozNzk2KiogbG93IGFidW5kYW50IEFTVnMuICAgCiogKipEYXRhIE5vcm1hbGl6YXRpb24qKjogCmBEYXRhIHJhcmVmeWluZyA9IERvIG5vdCByYXJlZnkgbXkgZGF0YWAsICAgCmBEYXRhIHNjYWxpbmcgPSBUb3RhbCBzdW0gc2NhbGluZyAoVFNTKWAsIGFuZCAgIApgRGF0YSB0cmFuc2Zvcm1hdGlvbiA9IERvIG5vdCB0cmFuc2Zvcm0gbXkgZGF0YWAuICAgCiogKipMRWZTZSBhbmFseXNpcyoqICBgTG9nIExEQSBzY29yZSA9IDRgICYgYEFkanVzdGVkIHAtdmFsdWUgY3V0b2ZmID0gMC4wMDAxYC4gV2Ugc3BlY2lmaWNhbGx5IGNob3NlIHRoZXNlIHZhbHVlcyBiZWNhdXNlIHdlIGZvdW5kIHRoYXQgdGhleSBlbGltaW5hdGVkIHNwdXJpb3VzIHJlc3VsdHMgc3VjaCBhcyBEQSBBU1ZzIHRoYXQgd2VyZSByZWFsbHkgYWJ1bmRhbnQgaW4gYSBmZXcgc2FtcGxlcyBidXQgbm90IGNvbnNpc3RlbnQgYWNyb3NzIGFuIGVudGlyZSBncm91cC4KCj4gVGhlIHJlc3VsdCB3YXMgKio1OSoqIGRpZmZlcmVudGlhbGx5IGFidW5kYW50ICgqKkRBKiopIEFTVnMuICAKCioqKgoKIyMjIyBSZXN1bHRzIG9mIExFZlNlIGFuYWx5c2lzCgpXZSBjYW4gaW5zcGVjdCBhbmQgc2F2ZSB0aGUgcmVzdWx0cyBvZiB0aGUgTEVmU2UgYW5hbHlzaXMuIFRoZSB0YWJsZSBzaG93cyB0aGUgTGluZWFyIGRpc2NyaW1pbmFudCBhbmFseXNpcyAoTERBKSBzY29yZXMsIFAtdmFsdWVzIGFkanVzdGVkIGZvciBtdWx0aXBsZSB0ZXN0aW5nLCBhbmQgRmFsc2UgRGlzY292ZXJ5IFJhdGUgKEZEUikgdmFsdWVzIGZyb20gdGhlIExFZlNlIGFuYWx5c2lzLiBOb3JtYWxpemVkIHJlYWQgYWJ1bmRhbmNlIHZhbHVlcyBmb3IgZWFjaCBob3N0IHNwZWNpZXMgYXJlIGFsc28gZ2l2ZW4uCgojIyMjIDxmb250IGNvbG9yPSJyZWQiPlN1cHBsZW1lbnRhcnkgVGFibGUgNTwvZm9udD4KCmBgYHtyIGxlZnNlX3RhYmxlfQpsZWZzZV90YWIgPC0gcmVhZC50YWJsZSgiVEFCTEVTL0lOUFVUL2xlZnNlX3Jlc3VsdHMudHh0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFRSVUUsIHNlcCA9ICJcdCIsIGNoZWNrLm5hbWVzID0gRkFMU0UpCndyaXRlLnRhYmxlKGxlZnNlX3RhYiwgIlRBQkxFUy9PVVRQVVQvU1VQUC9UYWJsZV9TNS50eHQiLCAKICAgICAgICAgICAgcXVvdGUgPSBGQUxTRSwgc2VwID0gIlx0Iiwgcm93Lm5hbWVzID0gRkFMU0UpCgpkYXRhdGFibGUobGVmc2VfdGFiLCByb3duYW1lcyA9IEZBTFNFLCB3aWR0aCA9ICIxMDAlIiwgCiAgICAgICAgICBjYXB0aW9uID0gCiAgICAgICAgICAgIGh0bWx0b29sczo6dGFncyRjYXB0aW9uKAogICAgICAgICAgICAgIHN0eWxlID0gImNhcHRpb24tc2lkZTogYm90dG9tOyB0ZXh0LWFsaWduOiBsZWZ0OyIsIAogICAgICAgICAgICAgICJUYWJsZSA0OiAiLCBodG1sdG9vbHM6OmVtKCJSZXN1bHRzIG9mIExFZlNlIGFuYWx5c2lzLiIpKSwgCiAgICAgICAgICBleHRlbnNpb25zID0gIkZpeGVkQ29sdW1ucyIsICJCdXR0b25zIiwgCiAgICAgICAgICBvcHRpb25zID0gbGlzdChjb2x1bW5EZWZzID0gCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3QobGlzdChjbGFzc05hbWUgPSAiZHQtY2VudGVyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXJnZXRzID0gYygxLCAyLCAzLCA0LCA1LCA2LCA3LCA4KSkpLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGRvbSA9ICJCbGZydGlwIiwgcGFnZUxlbmd0aCA9IDUsIAogICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoTWVudSA9IGMoNSwgMTAsIDI1LCA2MCksIAogICAgICAgICAgICAgICAgICAgICAgICAgYnV0dG9ucyA9IGMoImNzdiIsICJjb3B5IiksIAogICAgICAgICAgICAgICAgICAgICAgICAgc2Nyb2xsWCA9IFRSVUUsIHNjcm9sbENvbGxhcHNlID0gVFJVRSkpCmBgYAoKKioqCgojIyMgQ29yZSBtaWNyb2Jpb21lCgpCZWZvcmUgZ2V0dGluZyBrbmVlIGRlZXAgaW4gdGhlIERBIEFTViBhbmFseXNpcyBsZXRzIHNlZSBpZiB3ZSBjYW4ndCBpZGVudGlmeSBzb21lIGNvcmUgZWxlbWVudHMsIG9yIEFTVnMsIHRvIHRoZXNlIGZpc2guIEZpcnN0IHdlIG5lZWQgYSBtb3RodXItZm9ybWF0dGVkIGAuc2hhcmVkYCBmaWxlLiBUaGlzIGlzIHRoZSBjb2RlIC4uLgoKYGBge3IgZ2V0X2NvcmVfc2hhcmVkX2ZpbGV9CmNtIDwtIHJlYWQudGFibGUoIlRBQkxFUy9PVVRQVVQvT1RIRVIvc2VxX3RhYl9mb3JfY29yZS50eHQiLCAKICAgICAgICAgICAgICAgICBzZXAgPSAiXHQiLCBoZWFkZXIgPSBUUlVFLCByb3cubmFtZXMgPSAxKQpjbV90IDwtIHQoY20pIApjbV9kZiA8LSBhcy5kYXRhLmZyYW1lKGNtX3QpCm51bWNvbHMgPC0gbmNvbChjbV9kZikKY21fZGYgPC0gY21fZGYgJT4lIHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKCJHcm91cCIpCmNtX2RmIDwtIGNtX2RmICU+JSAKICBtdXRhdGUobGFiZWwgPSAwLjAzLCBudW1PdHVzID0gbnVtY29scykgJT4lIAogIHNlbGVjdChsYWJlbCwgR3JvdXAsIG51bU90dXMsIGV2ZXJ5dGhpbmcoKSkKCndyaXRlLnRhYmxlKGNtX2RmLCAiVEFCTEVTL09VVFBVVC9PVEhFUi9wc19zbHZfd29ya19maWx0LnR4dCIsIAogICAgICAgICAgICBxdW90ZSA9IEZBTFNFLCBzZXAgPSAiXHQiLCByb3cubmFtZXMgPSBGQUxTRSkKCiMjIyNDT01CSU5FIGJ5IGZpc2ggc3BlY2llcwoKY21fTWVyZ2UgPC0gY20gJT4lIHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKCJBU1YiKQoKY21fTWVyZ2UgPC0gY21fTWVyZ2UgJT4lIG11dGF0ZShBY0NvZSA9IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQWNDb2UwMSArIEFjQ29lMDIgKyBBY0NvZTAzICsgQWNDb2UwNCArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQWNDb2UwNSArIEFjQ29lMDYgKyBBY0NvZTA3ICsgQWNDb2UwOCkKY21fTWVyZ2UgPC0gY21fTWVyZ2UgJT4lIG11dGF0ZShBY1RyYSA9IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQWNUcmEwMSArIEFjVHJhMDIgKyBBY1RyYTAzICsgQWNUcmEwNCArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQWNUcmEwNSArIEFjVHJhMDYgKyBBY1RyYTA3ICsgQWNUcmEwOCArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQWNUcmEwOSkKY21fTWVyZ2UgPC0gY21fTWVyZ2UgJT4lIG11dGF0ZShTY1RyYSA9IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2NUYWUwMSArIFNjVGFlMDIgKyBTY1RhZTAzICsgU2NUYWUwNCArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2NUYWUwNSArIFNjVGFlMDYgKyBTY1RhZTA3ICsgU2NUYWUwOCArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2NUYWUwOSkKY21fTWVyZ2UgPC0gY21fTWVyZ2UgJT4lIG11dGF0ZShTcEF1ciA9IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU3BBdXIwMSArIFNwQXVyMDIgKyBTcEF1cjAzICsgU3BBdXIwNCArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU3BBdXIwNSArIFNwQXVyMDYgKyBTcEF1cjA3ICsgU3BBdXIwOCArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU3BBdXIwOSArIFNwQXVyMTAgKyBTcEF1cjExICsgU3BBdXIxMiArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU3BBdXIxMykKY21fTWVyZ2UgPC0gY21fTWVyZ2UgJT4lIG11dGF0ZShTcFZpciA9IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU3BWaXIwMSArIFNwVmlyMDIgKyBTcFZpcjAzICsgU3BWaXIwNCArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU3BWaXIwNSArIFNwVmlyMDYgKyBTcFZpcjA3ICsgU3BWaXIwOCArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU3BWaXIwOSArIFNwVmlyMTAgKyBTcFZpcjExKQoKY21fTWVyZ2UgPC0gY21fTWVyZ2UgJT4lIHNlbGVjdChBU1YsIEFjQ29lLCBBY1RyYSwgU2NUcmEsIFNwQXVyLCBTcFZpcikKY21fTWVyZ2VfMiA8LSBjbV9NZXJnZVssIC0xXQpyb3duYW1lcyhjbV9NZXJnZV8yKSA8LSBjbV9NZXJnZVssIDFdCgpjbV9NZXJnZV8yX3QgPC0gdChjbV9NZXJnZV8yKQpjbV9NZXJnZV8yX2RmIDwtIGFzLmRhdGEuZnJhbWUoY21fTWVyZ2VfMl90KQoKY21fTWVyZ2VfMl9kZiA8LSBjbV9NZXJnZV8yX2RmICU+JSAKICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigiR3JvdXAiKQpjbV9NZXJnZV8yX2RmIDwtIGNtX01lcmdlXzJfZGYgJT4lIAogIG11dGF0ZShsYWJlbCA9IDAuMDMsIG51bU90dXMgPSBudW1jb2xzKSAlPiUgCiAgc2VsZWN0KGxhYmVsLCBHcm91cCwgbnVtT3R1cywgZXZlcnl0aGluZygpKQp3cml0ZS50YWJsZShjbV9NZXJnZV8yX2RmLCAiVEFCTEVTL09VVFBVVC9PVEhFUi9wc19zbHZfd29ya19maWx0X2NvbWJpbmUudHh0IiwgCiAgICAgICAgICAgIHF1b3RlID0gRkFMU0UsIHNlcCA9ICJcdCIsIHJvdy5uYW1lcyA9IEZBTFNFKQpgYGAKCk5leHQgd2UgdXNlIHRoZSBvdXRwdXQgdG8gcnVuIGBnZXQuY29yZW1pY3JvYmlvbWVgIGluIG1vdGh1ci4KCgojIyMgU2VhcmNoaW5nIHB1YmxpYyBkYXRhYmFzZXMKCk5leHQgd2Ugd2FudGVkIHRvIGtub3cgd2hlcmUgZWxzZSB0aGVzZSBBU1ZzIGhhZCBiZWVuIGRldGVjdGVkIGluIG5hdHVyZS4gVGhlcmUgaXMgYSBodWdlIHdlYWx0aCBvZiBwdWJsaWNseSBhdmFpbGFibGUgc2VxdWVuY2UgaW5mb3JtYXRpb24gZnJvbSBtYW55IHN0dWRpZXMgYW5kIGhhYml0YXRzLiBXZSBjYW4gdXNlIHRoaXMgaW5mb3JtYXRpb24gdG8gZ2V0IGEgYmV0dGVyIGlkZWEgb2YgdGhlIGRpc3RyaWJ1dGlvbiBhbmQgaGFiaXRhdCBzcGVjaWZpY2l0eSBvZiB0aGUgREEgQVNWcy4gVG8gYWNjb21wbGlzaCB0aGlzIHdlIHBlcmZvcm1lZCB0aGUgZm9sbG93aW5nIHN0ZXBzOgoKMS4gRmlyc3Qgd2UgbmVlZGVkIGEgcGh5bG9zZXEgb2JqZWN0IHRoYXQgb25seSBjb250YWluZWQgdGhlIERBIEFTVnMuIFRvIGRvIHRoaXMsIHdlIHBhc3NlZCBhbiBvYmplY3QgY29uc2lzdGluZyBvZiBqdXN0IHRoZXNlIDU5IEFTVnMgKGZyb20gdGhlIExFZlNlIGFuYWx5c2lzKSB0byB0aGUgcGh5bG9zZXEgZnVuY3Rpb24gYHBydW5lX3RheGFgLiAgV2UgbmVlZGVkIHR3byBkaWZmZXJlbnQgYHBzYCBvYmplY3RzLCBvbmUgZnJvbSB0aGUgdW5tZXJnZWQgb2JqZWN0IChgcHNfc2x2X3dvcmtfZmlsdGApIGFuZCB0aGUgb3RoZXIgZnJvbSB0aGUgbWVyZ2VkLWJ5LWdlbnVzIG9iamVjdCAoYG1lcmdlZEdQYCkuIAoKMi4gTmV4dCB3ZSBuZWVkZWQgYSBmYXN0YSBmaWxlIG9mIG91ciBEQSBBU1ZzLiBXZSBjb3VsZCBub3QgZmluZCBhbiBlYXN5IHdheSB0byBleHBvcnQgYSBmYXN0YSBmaWxlIGZyb20gdGhlIG5ldyBgcHNgIG9iamVjdHMuIFNvIHdlIHRyaWVkIHRoaXMgdXNpbmcgdGhlIGB0YXhfdGFibGVgLiBUaGlzIGFwcHJvYWNoIHdvcmtzIGJ1dCwgd2VsbCwgaXQgaXMgbm90IHZlcnkgZWxlZ2FudC4gSWYgeW91IHdhbnQgYSBmYXN0YSBmaWxlIGZyb20gYW55IG90aGVyIGBwc2Agb2JqZWN0cyBqdXN0IHN3aXBlIG91dCB0aGUgbmFtZSBvZiB0aGUgYHBzYCBvYmplY3QgaW4gdGhlIGNvZGUgYmVsb3cuIEFueXdheSwgd2Ugd2lsbCBnZW5lcmF0ZSBhbmQgc2F2ZSBhIGZhc3RhIGZpbGUuCgojIyMjIyAqKlBsZWFzZSBub3RlKiogdGhhdCBvbiB0aGUgbWFjIHdlIHVzZWQgdG8gYW5hbHl6ZSB0aGUgZGF0YSwgZm9yIHNvbWUgcmVhc29uLCBzYXZlcyB0aGUgZmFzdGEgZmlsZSB3aXRoIGBMaW5lIEJyZWFrIFR5cGVgIGFzIGBMZWdhY3kgTWFjKENSKWAuIFRoaXMgbWF5IGJlIGluY29tcGF0aWJsZSB3aXRoIG90aGVyIHByb2dyYW1zIGFuZCBuZWVkcyB0byBiZSBjaGFuZ2VkIHRvIGBVTklYIChMUylgLiBJIGtub3csIGRvbid0IHF1aXQgbXkgZGF5IGpvYiwgZXhjZXB0IHRoaXMgaXMgbXkgZGF5IGpvYiA6LwoKYGBge3IgZmlsZXNfZm9yX3B1YmxpY19zZWFyY2h9CiMgT2JqZWN0IG9mIERBIEFTVnMKbGVmc2VfYXN2cyA8LSBjKCJBU1YyMSIsICJBU1YyNSIsICJBU1YzNSIsICJBU1Y0NCIsICJBU1YxNTkiLCAKICAgICAgICAgICAgICAgICJBU1YxNyIsICJBU1YxNzQiLCAiQVNWMjIiLCAiQVNWMjM0IiwgIkFTVjYwIiwgCiAgICAgICAgICAgICAgICAiQVNWMTE0IiwgIkFTVjI2OCIsICJBU1YxNCIsICJBU1YyMjYiLCAiQVNWMjMiLCAKICAgICAgICAgICAgICAgICJBU1YyOSIsICJBU1YzMCIsICJBU1Y0OCIsICJBU1Y5MCIsICJBU1Y5OCIsICJBU1YxOCIsIAogICAgICAgICAgICAgICAgIkFTVjQxIiwgIkFTVjciLCAiQVNWNDMiLCAiQVNWNSIsICJBU1Y1NCIsICJBU1Y4IiwgCiAgICAgICAgICAgICAgICAiQVNWOSIsICJBU1YyNTAiLCAiQVNWMTIiLCAiQVNWMzIiLCAiQVNWMzQiLCAiQVNWMzkiLCAKICAgICAgICAgICAgICAgICJBU1YyMjQiLCAiQVNWMzk4IiwgIkFTVjEyNyIsICJBU1YxMjgiLCAiQVNWMTUxIiwgCiAgICAgICAgICAgICAgICAiQVNWMzIzIiwgIkFTVjM1OSIsICJBU1YzNzQiLCAiQVNWOTEiLCAiQVNWNTYiLCAiQVNWNiIsIAogICAgICAgICAgICAgICAgIkFTVjE2NSIsICJBU1YyODQiLCAiQVNWMzk1IiwgIkFTVjQ1MCIsICJBU1YxNSIsICJBU1YyIiwgCiAgICAgICAgICAgICAgICAiQVNWMjAiLCAiQVNWMjk4IiwgIkFTVjU3IiwgIkFTVjY5IiwgIkFTVjc1IiwgIkFTVjgyIiwgCiAgICAgICAgICAgICAgICAiQVNWMSIsICJBU1Y3MCIsICJBU1Y0OSIpCgojIENyZWF0ZSBwcyBvYmplY3RzCmRhX2FzdnMgPC0gcHJ1bmVfdGF4YShsZWZzZV9hc3ZzLCBtZXJnZWRHUCkKZGFfYXN2c19mdWxsIDwtIHBydW5lX3RheGEobGVmc2VfYXN2cywgcHNfc2x2X3dvcmtfZmlsdCkKIyBDcmVhdGUgZmFzdGEgZmlsZSBmcm9tIHRheF90YWJsZQp0YWJsZTJmb3JtYXQgPC0gdGF4X3RhYmxlKGRhX2FzdnMpCiNyZXRhaW4gb25seSB0aGUgY29sdW1uIHdpdGggdGhlIHNlcXVlbmNlcwp0YWJsZTJmb3JtYXRfdHJpbSA8LSB0YWJsZTJmb3JtYXRbLCA3XSAgCnRhYmxlMmZvcm1hdF90cmltX2RmIDwtIGRhdGEuZnJhbWUocm93Lm5hbWVzKHRhYmxlMmZvcm1hdF90cmltKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFibGUyZm9ybWF0X3RyaW0pCmNvbG5hbWVzKHRhYmxlMmZvcm1hdF90cmltX2RmKSA8LSBjKCJBU1ZfSUQiLCAiQVNWX1NFUSIpCiNmb3JtYXQgZmFzdGEKdGFibGUyZm9ybWF0X3RyaW1fZGYkQVNWX0lEIDwtIHN1YigiQVNWIiwgIj5BU1YiLCB0YWJsZTJmb3JtYXRfdHJpbV9kZiRBU1ZfSUQpCgp3cml0ZS50YWJsZSh0YWJsZTJmb3JtYXRfdHJpbV9kZiwgIlRBQkxFUy9PVVRQVVQvQVNWX0ZPUl9CTEFTVC5mYXN0YSIsIAogICAgICAgICAgICBzZXAgPSAiXHIiLCBjb2wubmFtZXMgPSBGQUxTRSwgcm93Lm5hbWVzID0gRkFMU0UsIAogICAgICAgICAgICBxdW90ZSA9IEZBTFNFLCBmaWxlRW5jb2RpbmcgPSAiVVRGLTgiKQpgYGAKCjMuIFdpdGggb3VyIG5ld2x5IGNyZWF0ZWQgREEgQVNWIGZhc3RhIGZpbGUgd2UgY2FuIG1vdmUgb24gdG8gZGF0YWJhc2Ugc2VhcmNoaW5nLiBXZSB1c2VkICBbQkxBU1RuXShodHRwczovL2JsYXN0Lm5jYmkubmxtLm5paC5nb3YvQmxhc3QuY2dpP1BST0dSQU09Ymxhc3RuJlBBR0VfVFlQRT1CbGFzdFNlYXJjaCZMSU5LX0xPQz1ibGFzdGhvbWUpe3RhcmdldD0iX2JsYW5rIn0gYWdhaW5zdCB0aGUgKm5yKiBkYXRhYmFzZSB0byBzZWFyY2ggcHVibGljbHkgYXZhaWxhYmxlIHNlcXVlbmNlIGRhdGEuIFdlIHVzZWQgdGhlc2Ugc2V0dGluZ3M6IAogICAgKyBvcHRpbWl6ZWQgZm9yIGhpZ2hseSBzaW1pbGFyIHNlcXVlbmNlcyAobWVnYWJsYXN0KSAKICAgICsgRXhwZWN0IHRocmVzaG9sZCA9IDEwCiAgICArIFdvcmQgc2l6ZSA9IDI4CiAgICArIE1hdGNoL01pc21hdGNoIFNjb3JlcyA9IDEsIC0yCiAgICArIEdhcCBDb3N0cyA9IGxpbmVhci4KICAgICsgcmV0YWluIHRvcCAxMCBoaXRzCiAgICAKSGVyZSBhcmUgdGhlIHRvcCBCTEFTVCBoaXRzIGZvciBlYWNoIERBIEFTVi4gVGhlIHRhYmxlIGRpc3BsYXlzIGEgbG90IG9mIGluZm9ybWF0aW9uIGFib3V0IGVhY2ggQkxBU1Qgc2VhcmNoIChpdCBzY3JvbGxzIGFsb25nIHRoZSB4LWF4aXMgYnkgdGhlIHdheSkuIE1vc3QgaW1wb3J0YW50bHkgYXJlIHRoZSBhY2Nlc3Npb24gbnVtYmVycyBvZiB0b3AgQkxBU1QgaGl0cyAoc3ViamVjdCBhY2MudmFyKSwgbnVtYmVyIG9mIDEwMCUgaWRlbnRpY2FsIG1hdGNoZXMgKG51bSBwZXJmZWN0IGhpdHMpLCB0aGUgcGVyY2VudCBpZGVudGl0eSwgYW5kIHNvbWUgaW5mbyBvbiB3aGVyZS93aGVuIHRoZSBoaXQgc2VxdWVuY2Ugd2FzIG9yaWdpbmFsbHkgZm91bmQuIFdoZXJlIGFwcGxpY2FibGUsIHRoZXJlIGlzIGFsc28gUHViTWVkSURzIHNvIHlvdSBjYW4gZmluZCB0aGUgcGFwZXIgdGhhdCByZXBvcnRlZCB0aGUgc2VxdWVuY2UuIExvb2tpbmcgYXQgdGhpcyB0YWJsZSB3aWxsIGdpdmUgeW91IGEgcHJlbGltaW5hcnkgc2Vuc2Ugb2YgdGhlIGVjb2xvZ3kgb2YgdGhlc2UgQVNWcy4gRm9yIGV4YW1wbGUsIG1vc3QgaGl0cyBjb21lIGZyb20gaW50ZXN0aW5hbCBjb21tdW5pdGllcywgbWFueSBvZiB3aGljaCBhcmUgbWFyaW5lIGhlcmJpdm9yb3VzIGZpc2guIEJ1dCB0aGUgbG93IHBlcmNlbnQgaWRlbnRpdHkgb2Ygc2V2ZXJhbCBBU1ZzIGluZGljYXRlcyB0aGF0IHRoZXNlIHNlcXVlbmNlcyBoYXZlIGJlZW4gcG9vcmx5IHNhbXBsZWQuIFRoaXMgaXMgbm90IHN1cnByaXNpbmcgZ2l2ZW4gdGhlIGdlb2dyYXBoaWMgc2tldyBvZiBzYW1wbGluZy4KCioqKgoKIyMjIyBUb3AgaGl0cyBmcm9tICBCTEFTVG4gYW5hbHlzaXMKCioqTm90ZSoqICpUaGlzIHRhYmxlIGFsc28gc2Nyb2xscyBob3Jpem9udGFsbHkuKiAKCmBgYHtyIGJsYXN0X3RhYmxlfQpibGFzdF90YWIgPC0gcmVhZC50YWJsZSgiVEFCTEVTL0lOUFVUL0JMQVNUX3Jlc3VsdHMudHh0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFRSVUUsIHNlcCA9ICJcdCIsIGNoZWNrLm5hbWVzID0gRkFMU0UpCndyaXRlLnRhYmxlKGJsYXN0X3RhYiwgIlRBQkxFUy9PVVRQVVQvQkxBU1RfUkVTVUxUUy50eHQiLCAKICAgICAgICAgICAgcm93Lm5hbWVzID0gRkFMU0UsIHNlcCA9ICJcdCIsIHF1b3RlID0gRkFMU0UpCgpkYXRhdGFibGUoYmxhc3RfdGFiLCByb3duYW1lcyA9IEZBTFNFLCAKICAgICAgICAgIGNhcHRpb24gPSAKICAgICAgICAgICAgaHRtbHRvb2xzOjp0YWdzJGNhcHRpb24oCiAgICAgICAgICAgICAgc3R5bGUgPSAiY2FwdGlvbi1zaWRlOiBib3R0b207IHRleHQtYWxpZ246IGxlZnQ7IiwgCiAgICAgICAgICAgICAgIlN1cHBsZW1lbnRhcnkgVGFibGUgNjogIiwgCiAgICAgICAgICAgICAgaHRtbHRvb2xzOjplbSgiUmVzdWx0cyBvZiBCTEFTVG4gYW5hbHlzaXMuIikpLCAKICAgICAgICAgIGV4dGVuc2lvbnMgPSAiRml4ZWRDb2x1bW5zIiwgIkJ1dHRvbnMiLCAKICAgICAgICAgIG9wdGlvbnMgPSBsaXN0KGNvbHVtbkRlZnMgPSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdChsaXN0KGNsYXNzTmFtZSA9ICJkdC1jZW50ZXIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhcmdldHMgPSBjKDEsIDIsIDMsIDQsIDUsIDYsIDcsIDgpKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgZG9tID0gIkJsZnJ0aXAiLCBwYWdlTGVuZ3RoID0gNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGhNZW51ID0gYyg1LCAxMCwgMjUsIDY1KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBidXR0b25zID0gYygiY3N2IiwgImNvcHkiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBzY3JvbGxYID0gVFJVRSwgc2Nyb2xsQ29sbGFwc2UgPSBUUlVFKSkKYGBgCgoKKioqCgpTZXZlcmFsIEFTVnMgcmV0dXJuZWQgbW9yZSB0aGFuIG9uZSBtYXRjaCBhdCAxMDAlLiBGb3Igc29tZSBBU1ZzLCB0aGUgMTAwJSBtYXRjaGVzIHdlcmUgZnJvbSB0aGUgc2FtZSBzdHVkeS9zdHVkeSBvcmdhbmlzbSwgc28gd2UganVzdCBzZWxlY3RlZCBvbmUgYXMgdGhlIHJlcHJlc2VudGF0aXZlLiBBU1ZzIDYsIDEyLCAyMjQsIGFuZCAzOTggcmV0dXJuZWQgbnVtZXJvdXMgMTAwJSBtYXRjaGVzIChvdXQgb2YgNTAgdG90YWwpLiBUaGVzZSBkYXRhIHdlcmUgaW1wcmFjdGljYWwgIHRvIHN1bW1hcml6ZSBhbmQgbm90IHZlcnkgaW5mb3JtYXRpdmUgYW55d2F5LiBTbyB3ZSBlbGVjdGVkIHRvIGxlYXZlIHRoZXNlIGRhdGEgb3V0LiBJZiB5b3Ugd2FudCB0byBzZWUgd2hhdCB0aGVzZSBoaXRzIGFyZSwganVzdCBncmFiIHRoZSBBU1Ygc2VxdWVuY2UgYW5kIEJMQVNUIGF3YXkuIAoKQWxzbywgc29tZSBBU1ZzIHNoYXJlZCB0aGUgc2FtZSB0byBoaXQuIFNpbmNlIHRoZSB0YWJsZSBpcyAnYnkgQVNWJyB3ZSByZXRhaW5lZCBhbGwgZHVwbGljYXRlIGhpdHMuCgo0LiBGb3IgcGh5bG9nZW5ldGljIGluZmVyZW5jZSB3ZSB1c2VkIHRoZSBbU2lsdmEgQWxpZ25tZW50LCBDbGFzc2lmaWNhdGlvbiBhbmQgVHJlZSBTZXJ2aWNlXShodHRwczovL3d3dy5hcmItc2lsdmEuZGUvYWxpZ25lci8pe3RhcmdldD0iX2JsYW5rIn0gdG8gb2J0YWluIG5laWdoYm9ycyBvZiBEQSBBU1ZzLiBXZSB1c2VkIHRoZXNlIHNldHRpbmdzOiAKICAgICsgU2VhcmNoIGFuZCBjbGFzc2lmeTogbWluIGlkZW50aXR5ID0gMC45NTsgTnVtYmVyIG9mIG5laWdoYm9ycyA9IDUuIAogICAgKyBEZWZhdWx0IHBhcmFtZXRlcnMgZm9yIHRoZSByZW1haW5kZXIgb2YgdGhlIHdvcmtmbG93LgoKNS4gV2UgdGhlbiBjb21iaW5lZCB0aGUgcmVzdWx0cyBvZiB0aGUgQkxBU1RuIGFuZCBTaWx2YSBBQ1QgYW5hbHlzZXMgYW5kIG9taXR0ZWQgZHVwbGljYXRlIGhpdHMsIHJlc3VsdGluZyBpbiAqKjI5NyoqIHRvcCBoaXQgc2VxdWVuY2VzIGZvciBwaHlsb2dlbmV0aWMgYW5hbHlzaXMuCgoKIyMjIFBoeWxvZ2VuZXRpYyBpbmZlcmVuY2UKClNob3J0IHJlYWQgc2VxdWVuY2VzIGFyZSBub3QgaWRlYWwgZm9yIHBoeWxvZ2VuZXRpYyBhbmFseXNpcywgYnV0IGdpdmVuIHRoZSBkYXRhIHdlIGhhdmUsIHdlIGZlbHQgdGhpcyB3YXMgYSBnb29kIHBsYWNlIHRvIHN0YXJ0LiBUaGlzIGFuYWx5c2lzIHJlcXVpcmVkIHNldmVyYWwgc3RlcHMuCgoxLiBXZSB1c2VkIFttb3RodXJdKGh0dHBzOi8vd3d3Lm1vdGh1ci5vcmcvd2lraS8pe3RhcmdldD0iX2JsYW5rIn0gKHYuMS40MC40LCBMYXN0IHVwZGF0ZWQ6IDA3LzI1LzIwMTgpIGFuZCB0aGUgW1NpbHZhIGZ1bGwgbGVuZ3RoIHNlcXVlbmNlcyBhbmQgdGF4b25vbXkgcmVmZXJlbmNlcyAocmVsZWFzZSAxMzIpXShodHRwczovL3d3dy5tb3RodXIub3JnL3dpa2kvU2lsdmFfcmVmZXJlbmNlX2ZpbGVzKXt0YXJnZXQ9Il9ibGFuayJ9IHRvIGFsaWduIHRoZSBEQSBBU1ZzIGFuZCBvdXIgbmV3IHJlZmVyZW5jZSBkYiwgYW5kIGFsc28gY2xhc3NpZnkgdGhlIHNlcXVlbmNlcy4gV2UgdXNlZCBhIFtoYXJkIG1hc2tdKGh0dHBzOi8vd3d3Lm1vdGh1ci5vcmcvd2lraS9GaWx0ZXIuc2VxcyNoYXJkKXt0YXJnZXQ9Il9ibGFuayJ9IHRvIHRyaW0gYWxsIGxvbmcgcmVhZHMgdG8gdGhlIHNhbWUgbGVuZ3RoICh+MzczYnApIGFuZCAxNlMgcmVnaW9uIGFzIHRoZSBBU1ZzLiAKCmBgYAptb3RodXIgIiNhbGlnbi5zZXFzKGNhbmRpZGF0ZT1zZXF1ZW5jZV90cmVlLmZhc3RhLCB0ZW1wbGF0ZT1zaWx2YS5ucl92MTMyLmFsaWduLCBwcm9jZXNzb3JzPTIwLCBmbGlwPXQpIiAgCm1vdGh1ciAiI2ZpbHRlci5zZXFzKGZhc3RhPXNlcXVlbmNlX3RyZWUuZmFzdGEsIHZlcnRpY2FsID0gPUYsIGhhcmQ9bWFzay50eHQpIiAgCm1vdGh1ciAiI2NsYXNzaWZ5LnNlcXMoZmFzdGE9c2VxdWVuY2VfdHJlZS5maWx0ZXIuZmFzdGEsIHRlbXBsYXRlPXNpbHZhLm5yX3YxMzIuYWxpZ24sIHRheG9ub215PXNpbHZhLm5yX3YxMzIudGF4LCBwcm9jZXNzb3JzPTEwKSIgIApgYGAKMi4gTm93IHRoYXQgd2UgaGFkIG91ciA1OSBEQSBBU1ZzIGFuZCB0aGUgdG9wIGRhdGFiYXNlIGhpdHMsIGl0cyB3YXMgdGltZSBmb3IgcGh5bG9nZW5ldGljIGluZmVyZW5jZS4gV2UgdXNlZCBbUkF4TUwtSFBDXShodHRwczovL3Njby5oLWl0cy5vcmcvZXhlbGl4aXMvd2ViL3NvZnR3YXJlL3JheG1sL2luZGV4Lmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gdG8gZ2VuZXJhdGUgYSBwaHlsb2dlbmV0aWMgdHJlZSAod2l0aCAqQXF1aWZleCogYXMgdGhlIG91dGdyb3VwKQoKYGBgCnJheG1sSFBDLVBUSFJFQURTLVNTRTMgLVQgMjQgLWYgYSAtcCAyMzQ1IC14IDM0NTYgLW0gR1RSR0FNTUEgIC1OIDEwMDAgLXMgc2VxdWVuY2VfdHJlZS5maWx0ZXIuZmFzdGEgLW4gZmlzaF9hcmJfYWxpZ25fMTAwMEJTX0IudHJlCmBgYAoKPGEgaWQ9IlBhcnQgVjogU3ludGhlc2lzIj48L2E+ICAKCiMjIFBhcnQgVjogU3ludGhlc2lzCgpbYmFjayB0byB0b3BdKCNiYWNrIHRvIHRvcCkKCk5vdyBpdCB3YXMgdGltZSB0byBwdXQgdGhlIHBpZWNlcyB0b2dldGhlciBhbmQgZGV0ZXJtaW5lLi4uCgo+IFdoYXQgdGhlc2UgcGF0dGVybnMgdGVsbCB1cyBhYm91dCBzcGVjaWZpY2l0eT8gCgojIyMgVmlzdWFsaXppbmcgdGhlIHBoeWxvZ2VuZXRpYyB0cmVlCgojIyMjIElNTkdTIGFuYWx5c2lzCgpUbyBkaWcganVzdCBhIGxpdHRsZSBkZWVwZXIsIHdlIHNjcmVlbmVkIG91ciBEQSBBU1ZzIGFnYWluc3QgdGhlIFtJTU5HUyBkYXRhYmFzZV0oaHR0cHM6Ly93d3cuaW1uZ3Mub3JnLyl7dGFyZ2V0PSJfYmxhbmsifS4gSU1OR1MgaG9zdHMgYSBjdXJhdGVkIGRhdGFiYXNlIG9mIHNob3J0LXJlYWQgc2VxdWVuY2VzIHNjcmFwZWQgZnJvbSB0aGUgSW50ZXJuYXRpb25hbCBOdWNsZW90aWRlIFNlcXVlbmNlIERhdGFiYXNlIENvbGxhYm9yYXRpb24gKEdlbkJhbmssIEREQkogYW5kIEVNQkwpLiBUaGUgZGF0YWJhc2UgaXMgcmVidWlsdCBtb250aGx5IGFuZCBhdCB0aGUgdGltZSBvZiB0aGlzIGFuYWx5c2lzLCBjb250YWluZWQgMjcxLDIzNyBzYW1wbGVzLiBJTU5HIGlzIHJlYWxseSBkZXNpZ25lZCB0byBzY3JlZW4gZnVsbC1sZW5ndGggMTZTIHJSTkEgc2VxdWVuY2VzIGFuZCBpcyBub3QgaWRlYWwgZm9yIHNob3J0ZXIgcmVhZHMuIFRoaXMgaXMgYmVjYXVzZSB0aGUgZGF0YWJhc2UgaXMgYnVpbHQgZnJvbSBzaG9ydCByZWFkcywgYW5kIGRpZmZlcmVudCBzdHVkaWVzIHRhcmdldCBkaWZmZXJlbnQgcmVnaW9ucyBvZiB0aGUgZ2VuZS4gRm9yIGV4YW1wbGUsIGlmIHdlIGdldCBubyBoaXRzIHRvIGFuIEFTViBpdCBjb3VsZCBtZWFuIHRoZSBvcmdhbmlzbXMgaXQgY2FtZSBmcm9tIGhhcyByZWFsbHkgbm90IGJlZW4gZGV0ZWN0ZWQgYmVmb3JlIG9yIHRoYXQgaXQgaXMgaW4gdGhlIGRhdGFiYXNlIGJ1dCBpcyByZXByZXNlbnRlZCBieSBhIGRpZmZlcmVudCAxNlMgcmVnaW9uLiBTbyB0YWtlIHRoZXNlIGRhdGEgd2l0aCBhIGdyYWluIG9mIHNhbHQuIAoKKipJTU5HUyBpcyBub3QgYSBoaWdoLXRocm91Z2hwdXQgc3lzdGVtKiouIFVzZXIgbWF5IG9ubHkgc3VibWl0IGEgbWF4aW11bSBvZiAxMCBzZXF1ZW5jZXMgcGVyIHF1ZXJ5IGFuZCB0aGlzIGNhbiAoYW5kIHdpbGwpIHRha2Ugd2Vla3MgdG8gcnVuLiBTbyBjaG9vc2UgeW91ciBBU1ZzIGNhcmVmdWxseS4gCgpJTU5HUyB3aWxsIHJldHVybiBhIGxvdCBvZiB1c2VmdWwgZGF0YSBmb3IgZWFjaCBxdWVyeSBzZXF1ZW5jZS4gQWxsIHdlIHdlcmUgaW50ZXJlc3RlZCBpbiBoZXJlIHdhcyB0aGUgbnVtYmVyIG9mIGhpdHMsIGJ1dCB0aGVyZSBtdWNoIG1vcmUgcmVhbGx5IHVzZWZ1bCBkYXRhIGhlcmUuIEFtb25nIG90aGVyIGRhdGEgcHJvZHVjdHMsIElNTkdTIHJldHVybnMgcmVwb3J0IHRhYmxlcyB0aGF0IHRhbGx5IHRoZSAqbnVtYmVyIG9mIHNhbXBsZXMgdGhhdCB3ZXJlIHBvc2l0aXZlIGZvciB0aGUgcHJlc2VuY2Ugb2YgcXVlcnktbGlrZSBzZXF1ZW5jZXMgZm9yIGVhY2ggc2FtcGxlIGNhdGVnb3J5Ki0tLWNhdGVnb3JpZXMgbGlrZSAqc2hyaW1wIGd1dCBtZXRhZ2Vub21lKiBhbmQgKnNlYXdhdGVyIG1ldGFnZW5vbWUqLiBFYWNoIGNhdGVnb3J5IGhhcyBhIG51bWJlciBvZiBzaG9ydC1yZWFkIHNhbXBsZXMsIHdoaWNoIGNvdWxkIG9yaWdpbmF0ZSBmcm9tIGEgc2luZ2xlIHN0dWR5IG9yIG11bHRpcGxlIHN0dWRpZXMuIAoKQSByZXBvcnQgaW5jbHVkZXMgdmFsdWVzIGZvciBzZXZlcmFsIHBlcmNlbnQgaWRlbnRpdHkgY3V0b2ZmIHZhbHVlcy4gV2Ugc2V0IGEgbWluaW11bSB0aHJlc2hvbGQgYXQgOTclIHNvIG91ciByZXBvcnRzIGhhdmUgdmFsdWVzIGZvciA5NyBhbmQgOTklLiBZb3UgY2FuIHNldCB0aGUgdGhyZXNob2xkIGFzIGxvdyBhcyA5MCUuIAoKSU1OR1MgcHJvdmlkZXMgdGhyZWUgc3VjaCByZXBvcnRzIGJhc2VkIG9uIHRoZSBhYnVuZGFuY2Ugb2YgeW91ciBxdWVyeSBzZXF1ZW5jZS4gCgoxLiBBbiBTUkEtZGVyaXZlZCBzYW1wbGUgaXMgY29uc2lkZXJlZCBwb3NpdGl2ZSBpZiB0aGUgcXVlcnktbGlrZSBzZXF1ZW5jZXMgc3VtIHVwIHRvIG1vcmUgdGhhbiAqKjAlKiogb2YgdGhlIHRvdGFsIG51bWJlciBvZiBzZXF1ZW5jZXMgaW4gdGhhdCBzYW1wbGUgKGkuZS4gYW55IGFidW5kYW5jZSkuCgoyLiBBbiBTUkEtZGVyaXZlZCBzYW1wbGUgaXMgY29uc2lkZXJlZCBwb3NpdGl2ZSBpZiB0aGUgcXVlcnktbGlrZSBzZXF1ZW5jZXMgc3VtIHVwIHRvIG1vcmUgdGhhbiAqKjAuMSUqKiBvZiB0aGUgdG90YWwgbnVtYmVyIG9mIHNlcXVlbmNlcyBpbiB0aGF0IHNhbXBsZSAoaS5lLiBleGNsdWRpbmcgcmFyZSBhYnVuZGFuY2VzKS4KCjMuIEFuIFNSQS1kZXJpdmVkIHNhbXBsZSBpcyBjb25zaWRlcmVkIHBvc2l0aXZlIGlmIHRoZSBxdWVyeS1saWtlIHNlcXVlbmNlcyBzdW0gdXAgdG8gbW9yZSB0aGFuICoqMSUqKiBvZiB0aGUgdG90YWwgbnVtYmVyIG9mIHNlcXVlbmNlcyBpbiB0aGF0IHNhbXBsZSAoaS5lLiBpbmNsdWRpbmcgb25seSBkb21pbmFudCBPVFVzKS4KCldlIHJlcG9ydCBkYXRhIGZyb20gOTclIGN1dG9mZiBpZGVudGl0eSBhbmQgMC4xJSBvZiB0b3RhbCByZWFkcyBpbiBhIHNhbXBsZS4gSSB0aGluayB0aGlzIGlzIGEgbGl0dGxlIGNvbmZ1c2luZyBzbyBsZXQgbWUgZXhwbGFpbiBieSBleGFtcGxlLiBJbiB0aGUgdHJlZSBiZWxvdywgQVNWMzk4IGlzIG1vc3QgY2xvc2VseSByZWxhdGVkIHRvIGFuIEFscGhhcHJvdGVvYmFjdGVyaWEgYXNzb2NpYXRlZCB3aXRoIHRoZSB0b3hpYyBiZW50aGljIG1hcmluZSBkaW5vZmxhZ2VsbGF0ZSwgKk9zdHJlb3BzaXMgb3ZhdGEqLiBXZSByZXRyaWV2ZWQgdGhpcyBzZXF1ZW5jZSBkdXJpbmcgdGhlIEJMQVNUbiBhbmFseXNpcyBkaXNjdXNzZWQgYWJvdmUuIEFueXdheSwgQVNWMzk4IHdhcyBzY3JlZW5lZCBhZ2FpbnN0IElNTkdTIGFuZCByZXR1cm5lZCAyNDYwIGhpdHMuIFRoaXMgbWVhbnMgdGhhdCBhdCA5NyUgaWRlbnRpdHksIDI0NjAgc2FtcGxlcyBoYWQgYW4gQVNWMzk4LWxpa2Ugc2VxdWVuY2UgY29tcHJpc2luZyBncmVhdGVyIHRoYW4gMC4xJSBvZiBhIGdpdmVuIHNhbXBsZXMgdG90YWwgbnVtYmVyIG9mIHNlcXVlbmNlcy4gSWYgZm9yIGV4YW1wbGUgd2UgaW5jcmVhc2UgdGhlIHBlcmNlbnQgaWRlbnRpdHkgdG8gOTklIHRoZSBudW1iZXIgb2Ygc2FtcGxlIGhpdHMgZHJvcHMgdG8gMTM4LiBJZiBpbnN0ZWFkIHdlIGxvb2sgYXQgdGhlIDAlIHJlcG9ydCAoOTclIGlkZW50aXR5KSwgdGhlIG51bWJlciBvZiBzYW1wbGUgaGl0cyBpbmNyZWFzZXMgdG8gNjMyMy4gCgojIyMjIFN1bGxhbSBsaWZlc3R5bGUgY2F0ZWdvcmllcwoKV2UgYWxzbyBjb21wYXJlZCB0aGUgZmluYWwgbGlzdCBvZiB0b3AgaGl0cyB0byB0aGUgW1N1bGxhbSBldC4gYWwuXShodHRwczovL2RvaS5vcmcvMTAuMTExMS9qLjEzNjUtMjk0WC4yMDEyLjA1NTUyLngpe3RhcmdldD0iX2JsYW5rIn0gcGFwZXIsIHNwZWNpZmljYWxseSAqKlRhYmxlIFMxICoqIGZyb20gdGhhdCBwYXBlci4gQmVjYXVzZSB0aGlzIHBhcGVyIHdhcyBwdWJsaXNoZWQgaW4gMjAxMiwgdGhlcmUgd2VyZSBtYW55IHNlcXVlbmNlIGhpdHMgaW4gb3VyIGRiIHRoYXQgZGlkIG5vdCBhcHBlYXIgaW4gdGhlIG9yaWdpbmFsIHBhcGVyLiBIb3dldmVyLCBmb3IgdGhvc2UgdGhhdCBkaWQsIHdlIGFkZGVkIHRoZSBTdWxsYW0gKmxpZmVzdHlsZSBjYXRlZ29yeSogZGVzaWduYXRpb25zIHRvIHRoZSB0cmVlIG1ldGFkYXRhLiAKCiMjIyMgUHV0dGluZyB0aGUgcGllY2VzIHRvZ2V0aGVyCgpXZSB0b29rIGFsbCBvZiB0aGVzZSBkYXRhIGFuZCB1c2VkIFtpVE9MXShodHRwczovL2l0b2wuZW1ibC5kZS8pe3RhcmdldD0iX2JsYW5rIn0gdG8gdmlzdWFsaXplIHRoZSB0cmVlLiBGb3IgZWFjaCB0b3AgaGl0LCB3ZSBhZGRlZCB0aGUgaXNvbGF0aW9uIHNvdXJjZS9uYXR1cmFsIGhvc3QgaW5mb3JtYXRpb24sIHRheG9ub21pYyBhZmZpbGlhdGlvbiwgYW5kIFN1bGxhbSAqbGlmZXN0eWxlIGNhdGVnb3J5Ki4gV2UgYWxzbyBvdmVybGFpZCB0aGUgbnVtYmVyIG9mIGhpdHMgdG8gdGhlIElNTkdTIGRhdGFiYXNlIGZvciBlYWNoIEFTVi4KClRvIHZpZXcgYSBmdWxsLCBpbnRlcmFjdGl2ZSB2ZXJzaW9uIG9mIHRoZSB0cmVlIGdvIHRoaXMgW2lUT0wgcGFnZV0oaHR0cHM6Ly9pdG9sLmVtYmwuZGUvdHJlZS8xODYxNDg5ODE4NjM5MjIwMTUzNTQ5NjU0MSl7dGFyZ2V0PSJfYmxhbmsifS4KCioqKgoKIyMjIyBab29tYWJsZSBpVE9MIHRyZWUKCiMjIyMgPGZvbnQgY29sb3I9InJlZCI+RmlndXJlIDM8L2ZvbnQ+CgpgYGB7ciBpbnNlcnRfaXRvbCwgb3V0LndpZHRoID0gIjEwMCUiLCBmaWcuY2FwID0gIkZpZ3VyZSAzIiwgZXZhbCA9IEZBTFNFLCBlY2hvID0gRkFMU0V9CiMgVGhpcyBpcyB0byBpbmNsdWRlIGEgc3RhdGljIGltYWdlCml0b2xfdHJlZSA8LSBrbml0cjo6aW5jbHVkZV9ncmFwaGljcygiRklHVVJFUy9JTlBVVC9GaWd1cmVfM0Euc3ZnIikKaXRvbF90cmVlCmBgYAoKKioqCgpgYGB7ciB6b29tLCBlY2hvID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwgZmlnLmFsaWduID0gImNlbnRlciIsIG91dC53aWR0aCA9ICIxMDAlIn0KIyBOb3RlOiBpbiBvcmRlciBmb3IgdGhpcyB0byB3b3JrLCBlc3BlY2lhbGx5IGlmIHRoZSBTVkcgZmllIAojIGhhcyBiZWVuIG1hbmlwdWxhdGVkIGluIElua3NjYXBlLCAKIyBpdCBpcyB3aXNlIHRvIGRvIHRoZSBmb2xsb3dpbmc6IAojIDEuIGRvIHdoYXRldmVyIHlvdSBuZWVkIGRvLCAKIyAyLiByZXNpemUgdG8gZHJhd2luZywgCiMgMy4gU2F2ZSBhIGNvcHksICAKIyA0LiBzYXZlIGFzIE9wdGltaXplZCBTVkcKaXRvbF90cmVlIDwtIHN2Z1Bhblpvb20oIkZJR1VSRVMvSU5QVVQvRmlndXJlXzNfVHJlZUFfMi5zdmciLCAKICAgICAgICAgICAgICAgICAgICAgICAgY29udHJvbEljb25zRW5hYmxlZCA9IFRSVUUsIHZpZXdCb3ggPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoID0gIjEwMCUiKQppdG9sX3RyZWUKYGBgCgpgYGB7ciB0cmVlX2xlZ2VuZCwgZWNobyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQppdG9sX2xlZ2VuZCA8LSBrbml0cjo6aW5jbHVkZV9ncmFwaGljcygiRklHVVJFUy9JTlBVVC9GaWd1cmVfM19MZWdlbmRfQS5zdmciKQppdG9sX2xlZ2VuZApgYGAKCgojIyMgSW5mZXJyaW5nIGxpZmVzdHlsZSBjYXRlZ29yeQoKV2UgdXNlZCB0aGUgdHJlZSB0byBpbmZlciB0aGUgKmxpZmVzdHlsZSBjYXRlZ29yeSogb2YgZWFjaCBBU1ZzIGJhc2VkIG9uIHRoZSAgY2xvc2VzdCByZWxhdGl2ZXMgaW4gdGhlaXIgY2xhZGUuIFRoaXMgd2FzIG5vdCBhIHF1YW50aXRhdGl2ZSwgYnV0IHJhdGhlciBhIHVzZXIgZ3VpZGVkIGRldGVybWluYXRpb24uIEFzaWRlIGZyb20gTWV0YU1ldGFEYiAoZGlzY3Vzc2VkIGFib3ZlKSB3ZSBhcmUgbm90IGF3YXJlIG9mIGFueSB0b29sIGN1cnJlbnRseSBhdmFpbGFibGUgdG8gcXVhbnRpdGF0aXZlbHkgYXNzZXNzIGhhYml0YXQgcHJlZmVyZW5jZSBvZiBhIDE2UyByUk5BIHNlcXVlbmNlLgoKRm9yIHNpbXBsaWNpdHkgd2UgZm9jdXNlZCBvbiB0aHJlZSAqbGlmZXN0eWxlIGNhdGFnb3JpZXMqICh0aG91Z2ggd2UgaGF2ZSBzZXZlbiBjYXRlZ29yaWVzIGluIHRoZSB0cmVlKS4gT3VyIHJlYXNvbmluZy0tLWFnYWluIGJhc2VkIG9uIHRoZSB3b3JrIG9mIFN1bGxhbSBldC4gYWwuLS0td2FzIHRoYXQgZmlzaCBpbnRlc3RpbmVzIGNvbnRhaW4gbWljcm9iZXMgdGhhdCBhcmUgZ2VuZXJhbGlzdHMgYW5kIHBvc3NpYmx5IG9mIGVudmlyb25tZW50YWwgb3JpZ2luICh3aGF0IHRoZXkgZWF0LCB3aGVyZSB0aGV5IGxpdmUpLCBtaWNyb2JlcyB0aGF0IGFyZSB0aGVyZSBiZWNhdXNlIGZpc2ggYXJlIGFuaW1hbHMgd2l0aCBndXRzLCBhbmQgbWljcm9iZXMgdGhhdCBhcmUgdGhlcmUgYmVjYXVzZSBmaXNoIGFyZSBmaXNoIGFuZCBoYXZlIGEgcGh5c2lvbG9neSBhbmQgZXZvbHV0aW9uYXJ5IGhpc3RvcnkgdGhhdCBzZWxlY3Qgc3BlY2lmaWMgb3JnYW5pc21zLiAgU3VsbGFtIGV0LmFsLiB3ZXJlIGFsc28gbG9va2luZyBhdCBmaXNoIGZyb20gZGlmZmVyZW50IGhhYml0YXRzIChmcmVzaHdhdGVyLCBlc3R1YXJ5LCBtYXJpbmUpIGFuZCB0cm9waWMgbGV2ZWxzIChjYXJuaXZvcmVzLCBoZXJiaXZvcmVzLCBvbW5pdm9yZXMpIHdoaWxlIG91ciBzdHVkeSB3YXMgbW9yZSBuYXJyb3cgaW4gc2NvcGUuCgoqICAgKipmaXNoIGFzc29jaWF0ZWQqKjogQVNWcyBtb3N0IGNsb3NlbHkgcmVsYXRlZCB0byBzZXF1ZW5jZXMgZnJvbSB0aGUgaW50ZXN0aW5hbCB0cmFjdCBvZiBtYXJpbmUgZmlzaC4gCiogICAqKmFuaW1hbCBhc3NvY2lhdGVkKio6IEFTVnMgbW9zdCBjbG9zZWx5IHJlbGF0ZWQgdG8gc2VxdWVuY2VzIGZyb20gb3RoZXIgYW5pbWFscywgaW5jbHVkaW5nIG9uZSBmcmVzaHdhdGVyIGZpc2gsIG90aGVyIHZlcnRlYnJhdGVzLCBhbmQgYSBmZXcgbm9uLW1hcmluZSBpbnZlcnRlYnJhdGVzLiAgCiogICAqKmdlbmVyYWxpc3RzKio6IEFTVnMgbW9zdCBjbG9zZWx5IHJlbGF0ZWQgdG8gc2VxdWVuY2VzIGFyZSB3aWRlc3ByZWFkIGFuZCBwb3NzaWJseSBmcm9tIHRoZSBlbnZpcm9ubWVudC4gQnkgYW5kIGxhcmdlIHRoZXNlIGFyZSBtYXJpbmUgb3IgbWFyaW5lLWxpa2UgKGUuZy4sIGh5cGVyc2FsaW5lIG1hdHMsIHNhbGluZSBsYWtlcykgaW4gb3JpZ2luIGluY2x1ZGluZyBzZWRpbWVudHMsIHdhdGVyLCBhbmQgcG90ZW50aWFsIHByZXkgKGFsZ2FlLCBwbGFudHMsIGNvcmFsLCBzcG9uZ2UpLiBIb3dldmVyIHRoZXJlIGFyZSBzb21lIGxlYXZlcyBpbiB0aGUgdHJlZSBmcm9tIG5vbi1tYXJpbmUgZW52aXJvbm1lbnRzIChlLmcuLCBhY3RpdmF0ZWQgc2x1ZGdlKSB0aGF0IHdlIGdyb3VwZWQgaW4gdGhlIGVudmlyb25tZW50YWwgY2F0ZWdvcnkuIAoKKioqCgojIyMjIEFzc2Vzc2luZyBoYWJpdGF0IHNwZWNpZmljaXR5LgoKV2UgY29tYmluZWQgdGhlc2UgaGFiaXRhdCBwcmVkaWN0aW9ucyB3aXRoIHRoZSByZXN1bHRzIG9mIHRoZSBCTEFTVG4gYW5hbHlzaXMsIHNjYW4gb2YgdGhlIElNTkdTIGRhdGFiYXNlLCBTdWxsYW0gbGlmZXN0eWxlIGNhdGVnb3JpZXMsIGV0Yy4gYW5kIHB1dCBpdCBhbGwgaW4gb25lICAqKmVkaXRhYmxlKiogdGFibGUuIFNvIGlmIHlvdSBkaXNhZ3JlZSB3aXRoIGEgaGFiaXRhdCBwcmVkaWN0aW9uLCB5b3UgY2FuIGZlZWwgZnJlZSB0byBjaGFuZ2UgaXQuIAoKIyMjIyA8Zm9udCBjb2xvcj0icmVkIj5TdXBwbGVtZW50YXJ5IFRhYmxlIDY8L2ZvbnQ+Cgo+IERlc2NyaXB0aW9uIG9mIHRhYmxlIGhlYWRpbmdzCgoqICoqQVNWKio6IEFTViBpZC4KKiAqKlRvdGFsIFJlYWRzKio6IFRvdGFsIHJlYWRzIG9mIEFTVi4KKiAqKlB1dGF0aXZlIGhhYml0YXQqKjogT3VyIGhhYml0YXQgZGVzaWduYXRpb24gYmFzZWQgb24gdGhlIGFuYWx5c2VzLgoqICoqRW5yaWNoZWQqKjogV2hpY2ggb2YgdGhlIGZpdmUgaGVyYml2b3JvdXMgcmVlZiBmaXNoIHRoZSBBU1Ygd2FzIGVucmljaGVkIGluLgoqICoqVGF4b24qKjogVGF4b25vbWljIGNsYXNzaWZpY2F0aW9uIG9mIHRoZSBBU1YuCiogKipjbG9zZXN0IGRiIG1hdGNoKio6IEhvc3Qgb3IgZW52aXJvbm1lbnQgb2YgdG9wIGhpdC4KKiAqKiUgaWRlbnRpdHkqKjogUGVyY2VudCBpZGVudGl0eSBvZiB0b3AgaGl0LgoqICoqc3ViamVjdCBhY2MqKiBBY2Nlc3Npb24gbnVtYmVyIG9mIHRvcCBCTEFTVCBoaXQgCiogKipJTU5HUyBoaXRzKio6IE51bWJlciBvZiBoaXRzIHRvIHRoZSBJTU5HUyBkYXRhYmFzZS4gVmFsdWUgaW5kaWNhdGVzIHRoZSBudW1iZXIgb2Ygc2FtcGxlcyB0aGF0IHNjb3JlZCBhIGhpdCB0byBhbiBBU1YuCiogKipTdWxsYW0gbGlmZXN0eWxlKio6IExpZmVzdHlsZSBjYXRlZ29yeSBhcyBkZWZpbmVkIGJ5IFN1bGxhbSBldC4gYWwuLCAyMDEyLiAqKk5MQyoqIGluZGljYXRlcyBubyBoaXQgdG8gdGhlIFN1bGxhbSBkYi4KKiAqKm51bSBwZXJmZWN0IGhpdHMqKiBOdW1iZXIgb2YgMTAwJSBCTEFTVCBtYXRjaGVzIG91dCBvZiA1MCB0b3AgaGl0cy4KCioqTm90ZSoqICpUaGlzIHRhYmxlIGFsc28gc2Nyb2xscyBob3Jpem9udGFsbHkuKiAKCmBgYHtyIGhhYml0YXRfdGFibGV9CmhhYmlfdGFiIDwtIHJlYWQudGFibGUoIlRBQkxFUy9JTlBVVC9oYWJpdGF0X3NwZWNpZmljaXR5LnR4dCIsIAogICAgICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFRSVUUsIHNlcCA9ICJcdCIsIGNoZWNrLm5hbWVzID0gRkFMU0UpCiMgb3JkZXIgYnkgaGFiaXRhdCBhbmQgaG9zdCBlbnJpY2hlZApoYWJpX3RhYjIgPC0gaGFiaV90YWJbb3JkZXIoaGFiaV90YWIkaGFiaXRhdF9jb2RlLCBoYWJpX3RhYiRFbnJpY2hlZCksIF0gCiNoYWJpX3RhYiA8LSBoYWJpX3RhYlssIC0yXSAjZGVsZXRlIGNvZGUgY29sdW1uCmRhX2FzdnNfY291bnRzIDwtIGFzLmRhdGEuZnJhbWUodGF4YV9zdW1zKGRhX2FzdnMpKQpjb2xuYW1lcyhkYV9hc3ZzX2NvdW50cykgPC0gYygidG90YWxfcmVhZHMiKQojIG1ha2Ugcm93bmFtZXMgYSBjb2x1bW4KZGFfYXN2c19jb3VudHMgPC0gY2JpbmQoQVNWID0gcm93bmFtZXMoZGFfYXN2c19jb3VudHMpLCBkYV9hc3ZzX2NvdW50cykgCnRlbXBfdGFibGUgPC0gbWVyZ2UoZGFfYXN2c19jb3VudHMsIGJsYXN0X3RhYiwgYnkgPSAiQVNWIiwgCiAgICAgICAgICAgICAgICAgICAgYWxsID0gVFJVRSwgc29ydCA9IEZBTFNFKSAKCnN1bW1fdGFibGUgPC0gbWVyZ2UodGVtcF90YWJsZSwgaGFiaV90YWIyLCBieSA9ICJBU1YiLCAKICAgICAgICAgICAgICAgICAgICBhbGwgPSBUUlVFLCBzb3J0ID0gRkFMU0UsIG5vLmR1cHMgPSBUUlVFKSAKCnN1bW1fdGFibGUgPC0gc3VtbV90YWJsZVstYygyMiwgMjYsIDI3LCAyOCwgMjksIDMxKV0Kc3VtbV90YWJsZSA8LSBzdW1tX3RhYmxlW2MoMSwgMjIsIDIzLCAyLCAyNCwgNCwgMywgNSwgNiwgNywgOCwgMTgsIDE5LCAyMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgOSwgMTAsIDExLCAxMiwgMTMsIDE0LCAxNSwgMTYsIDE3LCAyMSwgMjUpXQoKZGF0YXRhYmxlKHN1bW1fdGFibGUsIHJvd25hbWVzID0gRkFMU0UsIAogICAgICAgICAgY29sbmFtZXMgPSBjKAogICAgICAgICAgICAiQVNWIiwgIlB1dGF0aXZlIGhhYml0YXQiLCAiRW5yaWNoZWQiLCAiVG90YWwgcmVhZHMiLCAKICAgICAgICAgICAgIlRheG9uIiwgIk51bSBwZXJmZWN0IGhpdHMiLCAiVG9wIGhpdCBhY2MiLCAiJSBpZGVudGl0eSIsIAogICAgICAgICAgICAiSXNvbGF0aW9uIHNvdXJjZSIsICJOYXQgaG9zdCIsICJDb21tb24gbmFtZSIsICJDb2xsZWN0aW9uIHllYXIiLCAKICAgICAgICAgICAgIkNvdW50cnkiLCAiUHViTWVkIElEIiwgIkFsaWdubWVudCBsZW5ndGgiLCAiTWlzbWF0Y2hlcyIsIAogICAgICAgICAgICAiR2FwIG9wZW5zIiwgIlEuIHN0YXJ0IiwgIlEuIGVuZCIsICJTLiBzdGFydCIsICJTLiBlbmQiLCAKICAgICAgICAgICAgIkV2YWx1ZSIsICJCaXQgc2NvcmUiLCAiTnVtIElNTkdTIGhpdHMiLCAiU3VsbGFtIGxpZmVzdHlsZSIpLAogICAgICAgICAgZWRpdGFibGUgPSBUUlVFLCBjYXB0aW9uID0gCiAgICAgICAgICAgIGh0bWx0b29sczo6dGFncyRjYXB0aW9uKAogICAgICAgICAgICAgIHN0eWxlID0gImNhcHRpb24tc2lkZTogYm90dG9tOyB0ZXh0LWFsaWduOiBsZWZ0OyIsIAogICAgICAgICAgICAgICJTdXBwbGVtZW50YXJ5IFRhYmxlIDY6ICIsIAogICAgICAgICAgICAgIGh0bWx0b29sczo6ZW0oIkFzc2Vzc2luZyBoYWJpdGF0IHNwZWNpZmljaXR5LiIpKSwgCiAgICAgICAgICBleHRlbnNpb25zID0gIkJ1dHRvbnMiLCAKICAgICAgICAgIG9wdGlvbnMgPSBsaXN0KGNvbHVtbkRlZnMgPSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdChsaXN0KGNsYXNzTmFtZSA9ICJkdC1jZW50ZXIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhcmdldHMgPSBjKDEsIDIsIDMsIDQsIDUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgNiwgNywgOCwgOSwgMTApKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgZG9tID0gIkJsZnJ0aXAiLCBwYWdlTGVuZ3RoID0gNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGhNZW51ID0gYyg1LCAxMCwgMjUsIDYwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBidXR0b25zID0gYygiY3N2IiwgImNvcHkiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBzY3JvbGxYID0gVFJVRSwgc2Nyb2xsQ29sbGFwc2UgPSBUUlVFKSkKCndyaXRlLnRhYmxlKHN1bW1fdGFibGUsICJUQUJMRVMvT1VUUFVUL1NVUFAvVGFibGVfUzYudHh0IiwgCiAgICAgICAgICAgIHNlcCA9ICJcdCIsIGNvbC5uYW1lcyA9IGMoCiAgICAgICAgICAgICAgIkFTViIsICJQdXRhdGl2ZSBoYWJpdGF0IiwgIkVucmljaGVkIiwgIlRvdGFsIHJlYWRzIiwgCiAgICAgICAgICAgICAgIlRheG9uIiwgIk51bSBwZXJmZWN0IGhpdHMiLCAiVG9wIGhpdCBhY2MiLCAiJSBpZGVudGl0eSIsIAogICAgICAgICAgICAgICJJc29sYXRpb24gc291cmNlIiwgIk5hdCBob3N0IiwgIkNvbW1vbiBuYW1lIiwgCiAgICAgICAgICAgICAgIkNvbGxlY3Rpb24geWVhciIsICJDb3VudHJ5IiwgIlB1Yk1lZCBJRCIsICJBbGlnbm1lbnQgbGVuZ3RoIiwgCiAgICAgICAgICAgICAgIk1pc21hdGNoZXMiLCAiR2FwIG9wZW5zIiwgIlEuIHN0YXJ0IiwgIlEuIGVuZCIsICJTLiBzdGFydCIsIAogICAgICAgICAgICAgICJTLiBlbmQiLCAiRXZhbHVlIiwgIkJpdCBzY29yZSIsICJOdW0gSU1OR1MgaGl0cyIsIAogICAgICAgICAgICAgICJTdWxsYW0gbGlmZXN0eWxlIiksIAogICAgICAgICAgICByb3cubmFtZXMgPSBGQUxTRSwgcXVvdGUgPSBGQUxTRSwgZmlsZUVuY29kaW5nID0gIlVURi04IikKYGBgCioqTlIqKiBJbmRpY2F0ZXMgTm90IFJlY29yZGVkLiBGb3VyIEFTVnMgaGFkIG51bWVyb3VzIGhpdHMgYXQgMTAwJSBpZGVudGl0eS4gV2UgZGlkIG5vdCBpbmNsdWRlIHRvcCBoaXQgZGF0YSBmb3IgdGhlc2UgQVNWcy4KCioqKgoKIyMjIyBTdW1tYXJ5IG9mIGhhYml0YXQgZGl2ZXJzaXR5CgpOb3cgd2UgY2FuIHN1bW1hcml6ZSB0aGUgZGF0YSBmb3IgZWFjaCBsaWZlc3R5bGUgY2F0ZWdvcnkuIFRoaXMgdGFibGUgd2FzIGNvbnN0cnVjdGVkIGluIGEgdGV4dCBmaWxlIGFuZCByZWFkIGludG8gUi4gCgpgYGB7ciBoYWJpdGF0X3RhYmxlX3N1bW1hcnl9CmhhYmlfc3VtbWFyeSA8LSByZWFkLnRhYmxlKCJUQUJMRVMvSU5QVVQvVGFibGVfMS50eHQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVFJVRSwgc2VwID0gIlx0IiwgY2hlY2submFtZXMgPSBGQUxTRSkKCmRhdGF0YWJsZShoYWJpX3N1bW1hcnksIAogICAgICAgICAgcm93bmFtZXMgPSBGQUxTRSwgZWRpdGFibGUgPSBUUlVFLCAKICAgICAgICAgIGNhcHRpb24gPSBodG1sdG9vbHM6OnRhZ3MkY2FwdGlvbigKICAgICAgICAgICAgc3R5bGUgPSAiY2FwdGlvbi1zaWRlOiBib3R0b207IHRleHQtYWxpZ246IGxlZnQ7IiwgCiAgICAgICAgICAgICJUYWJsZSAxOiAiLCBodG1sdG9vbHM6OmVtKCJTdW1tYXJ5IG9mIGhhYml0YXQgc3BlY2lmaWNpdHkuIikpLCAKICAgICAgICAgIGV4dGVuc2lvbnMgPSAiQnV0dG9ucyIsIAogICAgICAgICAgb3B0aW9ucyA9IGxpc3QoY29sdW1uRGVmcyA9IGxpc3QobGlzdChjbGFzc05hbWUgPSAiZHQtY2VudGVyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhcmdldHMgPSBjKDEsIDIsIDMsIDQsIDUpKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgZG9tID0gIkJydGkiLCBidXR0b25zID0gYygiY3N2IiwgImNvcHkiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBzY3JvbGxYID0gVFJVRSwgc2Nyb2xsQ29sbGFwc2UgPSBUUlVFKSkKYGBgCgoqKioKCiMjIyBUYXhhIGRpc3RyaWJ1dGlvbiBieSBob3N0CgpTbyB3ZSBrbm93IHRoYXQgSG9zdCBYIGlzIGVucmljaGVkIGZvciBzb21lIEFTViBmcm9tIHRheGEgWS4gSXMgdGhpcyBwYXJ0IG9mIGEgbGFyZ2VyIHBhdHRlcm4gb3IgYW4gaXNvbGF0ZWQgY2FzZT8gRm9yIGEgZ2l2ZW4gdGF4b25vbWljIGdyb3VwIGFuZCByYW5rLCB3aGF0IHByb3BvcnRpb24gb2YgdG90YWwgcmVhZHMgKGZyb20gYWxsIEFTVnMpIHdlcmUgZm91bmQgaW4gYSBwYXJ0aWN1bGFyIGhvc3Qgc3BlY2llcz8gIEF0IHNvbWUgcG9pbnQgaXQgd291bGQgYmUgbmljZSBpZiB0aGlzIHdlcmUgYW4gaW50ZXJhY3RpdmUgc3RlcCwgYnV0IGZvciBub3cgd2UgbXVzdCBtb2RpZnkgdGhlIGNvZGUgYmVsb3cgdG8gbG9vayBhdCBkaWZmZXJlbnQgdGF4YS4gVGhpcyBleGFtcGxlIHdpbGwgbG9vayBhdCB0aGUgZmFtaWx5ICoqRGVzdWxmb3ZpYnJpb25hY2VhZSoqIChEZWx0YXByb3Rlb3BiYWN0ZXJpYSkKCiMjIyMgUHJvcG9ydGlvbiBvZiB0b3RhbCByZWFkcyBmb3IgYSBnaXZlbiB0YXhvbiAmIHJhbmsKCmBgYHtyIHByb3BvcnRpb25fb2ZfdGF4YX0KIyBDaGFuZ2UgdGhpcyB0byBzZWxlY3QgZGlmZmVyZW50IHRheGEKY2FsY190YXhfcHJvcCA8LSBzdWJzZXRfdGF4YShtZXJnZWRHUCwgRmFtaWx5ID09ICJEZXN1bGZvdmlicmlvbmFjZWFlIikgCmNhbGNfdGF4X3Byb3AKc2FtcGxlX3N1bXNfYnlfdGF4YSA8LSBzYW1wbGVfc3VtcyhjYWxjX3RheF9wcm9wKQoKdG90YWxfdGF4YV9yZWFkcyA8LSBzdW0oc2FtcGxlX3N1bXNfYnlfdGF4YSkKc2FtcGxlX3N1bXNfYnlfdGF4YSA8LSBhcy5kYXRhLmZyYW1lKHNhbXBsZV9zdW1zX2J5X3RheGEpCgpzYW1wbGVfc3Vtc19ieV90YXhhJHByb3BvcnRpb24gPC0gCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChzYW1wbGVfc3Vtc19ieV90YXhhJHNhbXBsZV9zdW1zX2J5X3RheGEgLyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG90YWxfdGF4YV9yZWFkcykgKiAxMDAKY29sbmFtZXMoc2FtcGxlX3N1bXNfYnlfdGF4YSkgPC0gYygidG90YWwgdGF4YSByZWFkcyIsICJQcm9wb3J0aW9uIikKc2FtcGxlX3N1bXNfYnlfdGF4YSRQcm9wb3J0aW9uIDwtIHJvdW5kKHNhbXBsZV9zdW1zX2J5X3RheGEkUHJvcG9ydGlvbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWdpdHMgPSAyKQp0b3RhbF90YXhhX3JlYWRzX2ludCA8LSBhcy5pbnRlZ2VyKHRvdGFsX3RheGFfcmVhZHMpCnNhbXBsZV9zdW1zX2J5X3RheGEKCmBgYAoKR3JlYXQuIExvb2tzIGxpa2UgdGhlcmUgYXJlIDcxIERlc3VsZm92aWJyaW9uYWNlYWUgQVNWcyBhbmQgdGhlIG1ham9yaXR5ICg+IDkwJSkgb2YgdGhlIHJlYWRzIGFyZSBmcm9tICpBY2FudGh1cnVzKi4gVGhpcyBpcyBpbnRlcmVzdGluZy4gV2UgY2FuIGRvIHRoaXMgd2l0aCBhbnkgdGF4YSB3ZSB3aXNoLiAKCiMjIyMgUHJvcG9ydGlvbiBvZiB0b3RhbCByZWFkcyBmb3IgQ3lhbm9iYWN0ZXJpYQoKU28gbGV0cyBkbyB0aGlzIHRvIGFsc28gbG9vayBhdCB0aGUgKipwcm9wb3J0aW9uIG9mIEN5YW5vYmFjdGVyaWEqKiByZWFkcyBieSBob3N0IHNwZWNpZXMuIAoKYGBge3IgcHJvcG9ydGlvbl9vZl90YXhhX2N5YW5vfQojIENoYW5nZSB0aGlzIHRvIHNlbGVjdCBkaWZmZXJlbnQgdGF4YQpjYWxjX3RheF9wcm9wX0N5YW4gPC0gc3Vic2V0X3RheGEobWVyZ2VkR1AsIFBoeWx1bSA9PSAiQ3lhbm9iYWN0ZXJpYSIpIApjYWxjX3RheF9wcm9wX0N5YW4Kc2FtcGxlX3N1bXNfYnlfdGF4YV9DeWFuIDwtIHNhbXBsZV9zdW1zKGNhbGNfdGF4X3Byb3BfQ3lhbikKCnRvdGFsX3RheGFfcmVhZHNfQ3lhbiA8LSBzdW0oc2FtcGxlX3N1bXNfYnlfdGF4YV9DeWFuKQpzYW1wbGVfc3Vtc19ieV90YXhhX0N5YW4gPC0gYXMuZGF0YS5mcmFtZShzYW1wbGVfc3Vtc19ieV90YXhhX0N5YW4pCgpzYW1wbGVfc3Vtc19ieV90YXhhX0N5YW4kcHJvcG9ydGlvbiA8LSAKICAoc2FtcGxlX3N1bXNfYnlfdGF4YV9DeWFuJHNhbXBsZV9zdW1zX2J5X3RheGFfQ3lhbiAvIHRvdGFsX3RheGFfcmVhZHNfQ3lhbikgKiAxMDAKCmNvbG5hbWVzKHNhbXBsZV9zdW1zX2J5X3RheGFfQ3lhbikgPC0gYygidG90YWwgdGF4YSByZWFkcyIsICJQcm9wb3J0aW9uIikKc2FtcGxlX3N1bXNfYnlfdGF4YV9DeWFuJFByb3BvcnRpb24gPC0gcm91bmQoc2FtcGxlX3N1bXNfYnlfdGF4YV9DeWFuJFByb3BvcnRpb24sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWdpdHMgPSAyKQp0b3RhbF90YXhhX3JlYWRzX0N5YW5faW50IDwtIGFzLmludGVnZXIodG90YWxfdGF4YV9yZWFkc19DeWFuKQpzYW1wbGVfc3Vtc19ieV90YXhhX0N5YW4KYGBgCgpUaGVyZSB3ZXJlIGEgdG90YWwgb2YgKio0ODQqKiBDeWFub2JhY3RlcmlhIEFTVnMgYWNyb3NzICoqYHIgdG90YWxfdGF4YV9yZWFkc19DeWFuX2ludGAqKiByZWFkcy4KCioqKgoKIyMjIERBIEFTViBkaXN0cmlidXRpb24gYnkgaG9zdAoKQXQgdGhpcyBwb2ludCB3ZSBrbm93IHdoaWNoIEFTVnMgYXJlIGVucmljaGVkIGluIHdoaWNoIGhvc3Qgc3BlY2llcywgdGhlIGxpbmVhZ2Ugb2YgdGhvc2UgQVNWcywgYW5kIHNvbWV0aGluZyBhYm91dCB3aGVyZSBlbHNlIHRoZXNlIHNlcXVlbmNlcyBoYXZlIGJlZW4gZGV0ZWN0ZWQgaW4gbmF0dXJlLiBOZXh0IHdlIHdvdWxkIGxpa2UgdG8ga25vdyB0aGUgcHJvcG9ydGlvbiBvZiB0b3RhbCByZWFkcyBmb3IgZWFjaCBBU1YgdGhhdCBpcyBmb3VuZCBpbiBlYWNoIGhvc3Qgc3BlY2llcy4gV2Ugc3RhcnQgd2l0aCBhIHN1bW1hcnkgdGFibGUgb2YgdGhlc2UgZGF0YS4gCgojIyMjIFByb3BvcnRpb24gb2YgdG90YWwgQVNWIHJlYWRzIHBlciBob3N0IHNwZWNpZXMKCmBgYHtyIGRhX2Fzdl9iYXJfc2V0dXAsIG1lc3NhZ2UgPSBGQUxTRX0KIyBjYWxjdWxhdGUgdGhlIGF2ZXJhZ2VzIGFuZCBtZXJnZSBieSBzcGVjaWVzCiMgZ3JhYiB0aGUgZGFfYXN2IHBzIG9iamVjdCAmIG1lcmdlIGJ5IHNhbXBsZXMKZGFBU1ZfbWVyZ2VkR1BfQkFSIDwtIG1lcmdlX3NhbXBsZXMoZGFfYXN2c19mdWxsLCAiU3AiKQojZGFBU1ZfU0RfQkFSIDwtIG1lcmdlX3NhbXBsZXMoc2FtcGxlX2RhdGEoZGFfYXN2c19mdWxsKSwgIlNwIikKIyBjYWxjdWxhdGUgcGVyY2VudCBwcm9wb3J0aW9uCmRhQVNWX0FWRyA8LSBhcHBseSh0KG90dV90YWJsZShkYUFTVl9tZXJnZWRHUF9CQVIpKSwgMSwgZnVuY3Rpb24oeCkgeCAvIHN1bSh4KSkgCiMgdHJhbnNwb3NlCmRhQVNWX3RfQVZHIDwtIHQoZGFBU1ZfQVZHKQpkYUFTVl90X0FWR19kZiA8LSBhcy5kYXRhLmZyYW1lKGRhQVNWX3RfQVZHKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIGNob29zZSBjb2x1bW5zIG9mIGludGVyZXN0CmRhX0FTVl90YXggPC0gaGFiaV90YWJbYygiQVNWIiwgIlRheG9uIiwgIlB1dGF0aXZlX2hhYml0YXQiKV0gCmRhX0FTVl90YXgyIDwtIGRhX0FTVl90YXhbLCAtMV0Kcm93bmFtZXMoZGFfQVNWX3RheDIpIDwtIGRhX0FTVl90YXhbLCAxXQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIGNvbWJpbmUgYmFzZWQgb24gQVNWIGNvbHVtbgpkYUFTVl93b3JrIDwtIG1lcmdlKGRhQVNWX3RfQVZHX2RmLCBkYV9BU1ZfdGF4MiwgYnkgPSAwLCBzb3J0ID0gRkFMU0UpCgpyb3duYW1lcyhkYUFTVl93b3JrKSA8LSBkYUFTVl93b3JrWywgMV0KZGFBU1Zfd29ya1ssIDFdIDwtIE5VTEwKI2RhQVNWX3dvcmsKCiMgdGhlbiBtYWtlIGNvbHVtbiByb3cubmFtZXMKZGFBU1Zfd29yazIgPC0gY2JpbmQoQVNWID0gcm93bmFtZXMoZGFBU1Zfd29yayksIGRhQVNWX3dvcmspCiMgbWVsdCB0aGUgZGYKIyB3aWRlIHRvIGxvbmcgZm9ybWF0PwpkYUFTVl93b3JrMyA8LSBtZWx0KGRhQVNWX3dvcmsyLCB2YWx1ZS5uYW1lID0gIkFTViIpIApjb2xuYW1lcyhkYUFTVl93b3JrMykgPC0gYygiQVNWIiwgIlRheG9uIiwgIlB1dGF0aXZlX2hhYml0YXQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNhbXBsZSIsICJQcm9wb3J0aW9uIikKZGFBU1Zfd29yazMkUHJvcG9ydGlvbiA8LSByb3VuZChkYUFTVl93b3JrMyRQcm9wb3J0aW9uLCBkaWdpdHMgPSA0KQoKZGF0YXRhYmxlKGRhQVNWX3dvcmszLCAKICAgICAgICAgIHJvd25hbWVzID0gVFJVRSwgZWRpdGFibGUgPSBGQUxTRSwgCiAgICAgICAgICBjYXB0aW9uID0gCiAgICAgICAgICAgIGh0bWx0b29sczo6dGFncyRjYXB0aW9uKAogICAgICAgICAgICAgIHN0eWxlID0gImNhcHRpb24tc2lkZTogYm90dG9tOyB0ZXh0LWFsaWduOiBsZWZ0OyIsICJUYWJsZSA4OiAiLCAKICAgICAgICAgICAgICBodG1sdG9vbHM6OmVtKCJEQSBBU1Ygc2FtcGxlIHByb3BvcnRpb24uIikpLCAKICAgICAgICAgIGV4dGVuc2lvbnMgPSAiQnV0dG9ucyIsIAogICAgICAgICAgb3B0aW9ucyA9IGxpc3QoY29sdW1uRGVmcyA9IGxpc3QobGlzdChjbGFzc05hbWUgPSAiZHQtY2VudGVyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhcmdldHMgPSBjKDEsIDIsIDMsIDQsIDUpKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgZG9tID0gIkJsZnJ0aXAiLCBwYWdlTGVuZ3RoID0gNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGhNZW51ID0gYyg1LCAxMCwgNTAsIDEwMCwgMzAwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBidXR0b25zID0gYygiY3N2IiwgImNvcHkiKSwgc2Nyb2xsWCA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgc2Nyb2xsQ29sbGFwc2UgPSBUUlVFKSkKCndyaXRlLnRhYmxlKGRhQVNWX3dvcmszLCAiVEFCTEVTL09VVFBVVC9wcm9wX0FTVl9yZWFkc19ieV9ob3N0LnR4dCIsIAogICAgICAgICAgICBzZXAgPSAiXHQiLCByb3cubmFtZXMgPSBGQUxTRSwgcXVvdGUgPSBGQUxTRSkKYGBgCgpOb3cgdGhhdCB3ZSBoYXZlIGEgbGlzdCBvZiBEQSBBU1ZzIGFuZCB0aGVpciBhc3NpZ25lZCAgaGFiaXRhdCBwcmVmZXJlbmNlLCB3ZSB3YW50IHRvIGNyZWF0ZSBhIFIgb2JqZWN0IHRoYXQgb3JnYW5pemVzIHRoZXNlIGluIHNvbWUgbG9naWNhbCBmYXNoaW9uLiBXZSBjYW4gdGhlbiB1c2UgdGhpcyBvYmplY3QgdG8gb3JkZXIgc3Vic2VxdWVudCBncmFwaHMgYW5kIHRhYmxlcy4gU28gbGV0cyBvcmRlciB0aGUgQVNWcyBieSBwdXRhdGl2ZSBoYWJpdGF0IHByZWZlcmVuY2UgYW5kIHRoZW4gYnkgdGhlIGhvc3Qgc3BlY2llcyBpbiB3aGljaCB0aGF0IEFTViB3YXMgZW5yaWNoZWQuIFNlZW1zIHJlYXNvbmFibGUgZW5vdWdoPyBEZXBlbmRpbmcgb24gdGhlIFIgY29tbWFuZCwgc29tZSAgb2JqZWN0cyBuZWVkIHRvIGJlIGluIGFzY2VuZGluZyBvcmRlciwgb3RoZXJzIGluIGRlc2NlbmRpbmcgb3JkZXIuCgpgYGB7ciBzZXRfbGVmc2Vfb3JkZXJfYXN2c30KYXN2X29yZGVyIDwtIGMoIkFTVjQ1MCIsICJBU1YxNjUiLCAiQVNWMzk1IiwgIkFTVjI4NCIsICJBU1Y1NiIsIAogICAgICAgICAgICAgICAiQVNWNiIsICJBU1YzNTkiLCAiQVNWMTI4IiwgIkFTVjEyNyIsICJBU1Y5MSIsIAogICAgICAgICAgICAgICAiQVNWMzc0IiwgIkFTVjE1MSIsICJBU1YzMjMiLCAiQVNWMzk4IiwgIkFTVjIyNCIsIAogICAgICAgICAgICAgICAiQVNWMzkiLCAiQVNWMzQiLCAiQVNWMTIiLCAiQVNWMzIiLCAiQVNWMjUwIiwgCiAgICAgICAgICAgICAgICJBU1Y0MyIsICJBU1Y1NCIsICJBU1Y5IiwgIkFTVjUiLCAiQVNWNDkiLCAiQVNWOCIsIAogICAgICAgICAgICAgICAiQVNWNDEiLCAiQVNWMTgiLCAiQVNWNyIsICJBU1Y5MCIsICJBU1YyOSIsICJBU1Y5OCIsIAogICAgICAgICAgICAgICAiQVNWMjMiLCAiQVNWMzAiLCAiQVNWMjI2IiwgIkFTVjQ4IiwgIkFTVjcwIiwgIkFTVjEiLCAKICAgICAgICAgICAgICAgIkFTVjE0IiwgIkFTVjI5OCIsICJBU1Y4MiIsICJBU1Y3NSIsICJBU1Y2OSIsICJBU1Y1NyIsIAogICAgICAgICAgICAgICAiQVNWMjAiLCAiQVNWMTUiLCAiQVNWMiIsICJBU1YyNjgiLCAiQVNWMTE0IiwgIkFTVjIzNCIsIAogICAgICAgICAgICAgICAiQVNWMTc0IiwgIkFTVjYwIiwgIkFTVjE3IiwgIkFTVjIyIiwgIkFTVjE1OSIsICJBU1Y0NCIsIAogICAgICAgICAgICAgICAiQVNWMjUiLCAiQVNWMjEiLCAiQVNWMzUiKQphc3Zfb3JkZXJfcmV2IDwtIHJldihhc3Zfb3JkZXIpCmBgYAoKTGV0cyBzZWUgaWYgd2UgY2FuIG92ZXJsYXkgYWxsIG9mIHRoaXMgaW5mb3JtYXRpb24gaW4gb25lICJlYXN5IiB0byB1bmRlcnN0YW5kIHBsb3QuIFRoZSBmaXJzdCB0aGluZyBpcyB0byBkbyBpcyBwbG90IHRoZSBwcm9wb3J0aW9uIG9mIHJlYWRzIGZvciBhIGdpdmVuIEFTViBmcm9tIGVhY2ggaG9zdCBzcGVjaWVzLgoKIyMjIyBHcmFwaGljYWwgcmVwcmVzZW50YXRpb24gb2YgcHJvcG9ydGlvbiBvZiB0b3RhbCBBU1YgcmVhZHMgcGVyIGhvc3Qgc3BlY2llcwoKYGBge3Igb3JkZXJfYXN2c30KZGFBU1Zfd29yazMkQVNWIDwtIGFzLmNoYXJhY3RlcihkYUFTVl93b3JrMyRBU1YpCmRhQVNWX3dvcmszJEFTViA8LSBmYWN0b3IoZGFBU1Zfd29yazMkQVNWLCBsZXZlbHMgPSB1bmlxdWUoZGFBU1Zfd29yazMkQVNWKSkKZGFBU1Zfd29yazMkQVNWIDwtIGZhY3RvcihkYUFTVl93b3JrMyRBU1YsIGxldmVscyA9IGFzdl9vcmRlcikKYGBgCgpOZXh0LCB3ZSBjcmVhdGVkIGEgYmFyIHBsb3Qgb2YgcmVhZCBwcm9wb3J0aW9uIGJ5IGhvc3Qgc3BlY2llcyBmb3IgZWFjaCBBU1YuIEFuZCBzYXZlIGEgY29weSB0byB0aGUgYEZJR1VSRVMvYCBkaXJlY3RvcnkuCgpDb2RlIGZvciBwcm9wb3J0aW9uYWwgYmFyIGNoYXJ0CgpgYGB7ciBkYV9hc3ZfYmFyX2NoYXJ0LCBtZXNzYWdlID0gRkFMU0V9CiNCYXIgY2hhcnRzCkFTVl9iYXIgPC0gZ2dwbG90KGRhQVNWX3dvcmszLCBhZXNfc3RyaW5nKHggPSAiQVNWIiwgeSA9ICJQcm9wb3J0aW9uIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiU2FtcGxlIiksIAogICAgICAgICAgICAgICAgICBlbnZpcm9ubWVudCA9IC5lLCBvcmRlcmVkID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgIHhsYWIgPSAieC1heGlzIGxhYmVsIiwgeWxhYiA9ICJ5LWF4aXMgbGFiZWwiKSAKCkFTVl9iYXIgPC0gQVNWX2JhciArIAogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHJldmVyc2UgPSBUUlVFKSwgCiAgICAgICAgICAgd2lkdGggPSAwLjk1KSArIAogIGNvb3JkX2ZsaXAoKSArIAogIHRoZW1lKGFzcGVjdC5yYXRpbyA9IDIgLyAxKQoKQVNWX2JhciA8LSBBU1ZfYmFyICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gc2FtcF9wYWwpCgpBU1ZfYmFyIDwtIEFTVl9iYXIgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGhqdXN0ID0gMC45NSwgdmp1c3QgPSAxKSkKCkFTVl9iYXIgPC0gQVNWX2JhciArIAogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3QoY29sb3VyID0gTlVMTCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldmVyc2UgPSBGQUxTRSkpICsgCiAgdGhlbWUobGVnZW5kLmtleSA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiYmxhY2siKSkKCkFTVl9iYXIgPC0gQVNWX2JhciArIAogIGxhYnMoeCA9ICJIb3N0IHNwZWNpZXMiLCB5ID0gIlByb3BvcnRpb24gKCUgdG90YWwgcmVhZHMpIiwgCiAgICAgICB0aXRsZSA9ICJBU1YgUHJvcG9ydGlvbiBieSBob3N0IHNwZWNpZXMiKQoKQVNWX2JhciA8LSBBU1ZfYmFyICsgCiAgdGhlbWUoYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJibGFjayIpLCAKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIiwgZmlsbCA9IE5BLCBzaXplID0gMSkpCkFTVl9iYXIKYGBgCgoKYGBge3IgbWVzc2FnZSA9IEZBTFNFLCBpbmNsdWRlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0KcGRmKCJGSUdVUkVTL09VVFBVVC9GaWd1cmVfNEEucGRmIikKQVNWX2JhcgppbnZpc2libGUoZGV2Lm9mZigpKQpgYGAKCkNvZGUgZm9yIGhlYXRtYXAKCmBgYHtyIGhlYXRtYXBfYWx0X3NldHVwLCB3YXJuaW5nPUZBTFNFLCAgbWVzc2FnZSA9IEZBTFNFfQojIEhlYXRtYXAKbGlicmFyeShDb21wbGV4SGVhdG1hcCkKbGlicmFyeShjaXJjbGl6ZSkKbGlicmFyeShoZWF0bWFwMykKbGlicmFyeShnZGF0YSkKZmlnNF9oZWF0IDwtIGFzLmRhdGEuZnJhbWUodChvdHVfdGFibGUoZGFfYXN2cykpKQojIENvbnZlcnQgaGFiaV90YWJsZSB0byBkZiBhbmQgc3RvcmUgaW4gbmV3IHZhcmlhYmxlCmZpZzRfdGF4IDwtIGFzLmRhdGEuZnJhbWUoaGFiaV90YWIyKSAKIyBlbGltaW5hdGUgMXN0IGNvbHVtbiBzbyBjYW4gY29tYmluZSBiYXNlZCBvbiByb3cgbmFtZXMKZmlnNF90YXhfdGFiIDwtIGZpZzRfdGF4WywgLTFdIAojIE1ha2UgbmV3IHJvdy5uYW1lcyBmcm9tIG9yaWdpbmFsIHRhYmxlCnJvd25hbWVzKGZpZzRfdGF4X3RhYikgPC0gZmlnNF90YXhbLCAxXSAKIyBSZW9yZGVyCmZpZzRfdGF4X3RhYiA8LSBmaWc0X3RheF90YWJbYyg0LCAyLCAzLCAxLCA1LCA2LCA3LCA4KV0gCiMgU2VsZWN0IGNvbHVtbnMKZmlnNF90YXhfdGFiIDwtIGZpZzRfdGF4X3RhYltjKDE6NCldIAoKIyBDb21iaW5lIHRoZSB0d28gZGYgYnkgcm93bmFtZSBJZiB0aGUgbWF0Y2hpbmcgaW52b2x2ZWQgcm93IG5hbWVzLCAKIyBhbiBleHRyYSBjaGFyYWN0ZXIgY29sdW1uIGNhbGxlZCBSb3cubmFtZXMgCiMgaXMgYWRkZWQgYXQgdGhlIGxlZnQsIGFuZCBpbiBhbGwgY2FzZXMgdGhlIHJlc3VsdCBoYXMg4oCYYXV0b21hdGlj4oCZIHJvdyBuYW1lcy4KZmlnNF9oZWF0bWFwMiA8LSBtZXJnZShmaWc0X3RheF90YWIsIGZpZzRfaGVhdCwgYnkgPSAwLCBhbGwgPSBUUlVFKSAKCmZpZzRfaGVhdG1hcCA8LSBzdWJzZXQoZmlnNF9oZWF0bWFwMiwgc2VsZWN0ID0gLWMoUm93Lm5hbWVzKSkKcm93bmFtZXMoZmlnNF9oZWF0bWFwKSA8LSBmaWc0X2hlYXRtYXAyWywgIlJvdy5uYW1lcyJdCiMgbWFrZSByb3duYW1lcyBhIGNvbHVtbgpmaWc0X2hlYXRtYXAgPC0gY2JpbmQoQVNWID0gcm93bmFtZXMoZmlnNF9oZWF0bWFwKSwgZmlnNF9oZWF0bWFwKSAKCmZpZzRfaGVhdG1hcCRBU1YgPC0gZmFjdG9yKGZpZzRfaGVhdG1hcCRBU1YsIGxldmVscyA9IHJldihhc3Zfb3JkZXIpKSAKZmlnNF9oZWF0bWFwIDwtIGZpZzRfaGVhdG1hcFtvcmRlcihmaWc0X2hlYXRtYXAkQVNWKSwgXSAKIyBjb21iaW5lIHRoZSBjb2x1bW5zIHRvIG1ha2Ugb25lIG5hbWUKZmlnNF9oZWF0bWFwJElEIDwtIHBhc3RlKGZpZzRfaGVhdG1hcCRBU1YsIGZpZzRfaGVhdG1hcCRUYXhvbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICBmaWc0X2hlYXRtYXAkUHV0YXRpdmVfaGFiaXRhdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICBmaWc0X2hlYXRtYXAkRW5yaWNoZWQsIHNlcCA9ICJfIikgCiMgZGVsZXRlIHRoZSBvcmlnaW5hbCBjb2x1bW5zCmZpZzRfaGVhdG1hcDIgPC0gZmlnNF9oZWF0bWFwWy1jKDE6NSldIAojIHJlb3JkZXIKZmlnNF9oZWF0bWFwMiA8LSBmaWc0X2hlYXRtYXAyW2MoNiwgMSwgMiwgMywgNCwgNSldIApyb3duYW1lcyhmaWc0X2hlYXRtYXAyKSA8LSBmaWc0X2hlYXRtYXAyWywgMV0KZmlnNF9oZWF0bWFwMiA8LSBmaWc0X2hlYXRtYXAyWy0xXQoKIyMjI0RlZmluZSBDb2xvcnMKdGF4YV9jb2xvcnMgPC0gdW5saXN0KGxhcHBseShyb3cubmFtZXMoZmlnNF9oZWF0bWFwMiksIGZ1bmN0aW9uKHgpIHsKICBpZiAoZ3JlcGwKICAgICAKICAgICAjIGdlbmVyYWxpc3RzCiAgICAgICAgICAgICAgICgiQWxwaGFwcm90ZW9iYWN0ZXJpYSIsIHgpKSAiIzAwMDAwMCIKICBlbHNlIGlmIChncmVwbCgiUGlyZWxsdWxhY2VhZSIsIHgpKSAiIzAwMDAwMCIKICBlbHNlIGlmIChncmVwbCgiUnVicml0YWxlYWNlYWUiLCB4KSkgIiMwMDAwMDAiIAogIGVsc2UgaWYgKGdyZXBsKCJGbGF2b2JhY3RlcmlhY2VhZSIsIHgpKSAiIzAwMDAwMCIgCiAgICAKICAgIyBmaXNoL2FuaW1hbAogIGVsc2UgaWYgKGdyZXBsKCJEZXN1bGZvdmlicmlvbmFjZWFlIiwgeCkpICIjMDA3MmIyIiAKICBlbHNlIGlmIChncmVwbCgiTGFjaG5vc3BpcmFjZWFlIiwgeCkpICIjZjBlNDQyIiAKICBlbHNlIGlmIChncmVwbCgiRXJ5c2lwZWxvdHJpY2hhY2VhZSIsIHgpKSAiIzAwOWU3MyIgCiAgZWxzZSBpZiAoZ3JlcGwoIlJ1bWlub2NvY2NhY2VhZSIsIHgpKSAiI2U2OWYwMCIKICBlbHNlIGlmIChncmVwbCgiQmFjdGVyb2lkYWxlcyIsIHgpKSAiI2Q1NWUwMCIKICBlbHNlIGlmIChncmVwbCgiRnVzb2JhY3RlcmlhY2VhZSIsIHgpKSAiIzU2YjRlOSIKICBlbHNlIGlmIChncmVwbCgiVmlicmlvbmFjZWFlIiwgeCkpICIjY2M3OWE3IgogIAogICMgb3RoZXIKICBlbHNlIGlmIChncmVwbCgiRmFtaWx5X1hJSUkiLCB4KSkgIiM4MDgwODAiCiAgZWxzZSBpZiAoZ3JlcGwoIk1vbGxpY3V0ZXMiLCB4KSkgIiM4MDgwODAiIAogIGVsc2UgaWYgKGdyZXBsKCJCcmV2aW5lbWF0YWNlYWUiLCB4KSkgIiM4MDgwODAiCiAgZWxzZSBpZiAoZ3JlcGwoIlBlcHRvc3RyZXB0b2NvY2NhY2VhZSIsIHgpKSAiIzgwODA4MCIKfSkpICAgIAoKaGFiaXRhdF9jb2xvcnMgPC0gdW5saXN0KGxhcHBseShyb3cubmFtZXMoZmlnNF9oZWF0bWFwMiksIGZ1bmN0aW9uKHgpIHsKICBpZiAoZ3JlcGwKICAgICAgICAgICAgICAgKCJmaXNoIiwgeCkpICIjODA4MDgwIgogIGVsc2UgaWYgKGdyZXBsKCJhbmltYWwiLCB4KSkgIiMwMDAwMDAiCiAgZWxzZSBpZiAoZ3JlcGwoImdlbmVyYWxpc3QiLCB4KSkgIiM4MDgwODAiCiAgI2Vsc2UgaWYgKGdyZXBsKCJ1bmRldGVybWluZWQiLCB4KSkgIiMwMDAwMDAiCn0pKSAgICAKaGVhdENvbG9ycyA8LSBjYmluZCh0YXhhX2NvbG9ycywgaGFiaXRhdF9jb2xvcnMpCmNvbG5hbWVzKGhlYXRDb2xvcnMpWzFdIDwtICJUYXhhIgpjb2xuYW1lcyhoZWF0Q29sb3JzKVsyXSA8LSAiSGFiaXRhdCIKIyMjIFNBVkUvZGlzcGxheSBoZWF0bWFwCmNvbCA8LSBjb2xvclJhbXBQYWxldHRlKGJpYXMgPSAxLCBjKCIjMDAwMDMzIiwgIiM2NkNDRkYiKSkoMTYpCnBkZihmaWxlID0gIkZJR1VSRVMvT1VUUFVUL0ZpZ3VyZV80Qi5wZGYiKQpoZWF0bWFwMyhmaWc0X2hlYXRtYXAyLCBjZXhSb3cgPSAwLjUsIGNleENvbCA9IDEsCiAgICAgICAgIG1hcmdpbnMgPSBjKDMsIDEzKSwgUm93U2lkZUNvbG9ycyA9IGhlYXRDb2xvcnMsIHNjYWxlID0gInJvdyIsIAogICAgICAgICBDb2x2ID0gTkEsIFJvd3YgPSBOQSwgcmV2QyA9IFRSVUUsIGJhbGFuY2VDb2xvciA9IEZBTFNFLCBjb2wgPSBjb2wpCmludmlzaWJsZShkZXYub2ZmKCkpCmhlYXRtYXAzKGZpZzRfaGVhdG1hcDIsIGNleFJvdyA9IDAuNSwgY2V4Q29sID0gMSwgCiAgICAgICAgIG1hcmdpbnMgPSBjKDMsIDEzKSwgUm93U2lkZUNvbG9ycyA9IGhlYXRDb2xvcnMsIHNjYWxlID0gInJvdyIsIAogICAgICAgICBDb2x2ID0gTkEsIFJvd3YgPSBOQSwgcmV2QyA9IFRSVUUsIGJhbGFuY2VDb2xvciA9IEZBTFNFLCBjb2wgPSBjb2wpCmBgYAoKCmBgYHtyIGZpbGVzX2Zvcl9uZXR3b3JrX2FuYWx5c2lzLCBldmFsPUZBTFNFLCBpbmNsdWRlID0gRkFMU0V9CiMjI01ha2UgYSBncmFwaAojbWFrZSBhIGRmIGZyb20gb3R1X3RhYmxlCmRhX2FzdnNfZGYgPC0gYXMuZGF0YS5mcmFtZSh0KG90dV90YWJsZShkYV9hc3ZzKSkpCiNjb3B5IHJvd25hbWVzIGFzIG5ldyBjb2x1bW4Kc2V0RFQoZGFfYXN2c19kZiwga2VlcC5yb3duYW1lcyA9IFRSVUUpCiNjaGFuZ2UgdGhlIG5hbWUKY29sbmFtZXMoZGFfYXN2c19kZikgWzFdIDwtICJBU1YiCiNtZWx0IGZyb20gd2lkZSB0byBsb25nIGZvcm0KZGFfYXN2c19kZjIgPC0gbWVsdChkYV9hc3ZzX2RmLCB2YWx1ZS5uYW1lID0gIkFTViIpICMgd2lkZSB0byBsb25nIGZvcm1hdD8KI3JlbmFtZSBjb2x1bW5zCmNvbG5hbWVzKGRhX2FzdnNfZGYyKSA8LSBjKCJTb3VyY2UiLCAiVGFyZ2V0IiwgInRvdGFsX3JlYWRzIikKIyByZW1vdmUgcm93cyB3aXRoIHRvdGFsX3JlYWRzID09IDAKZGFfYXN2c19kZjIgPC0gZGFfYXN2c19kZjJbIShkYV9hc3ZzX2RmMiR0b3RhbF9yZWFkcyA9PSAwKV0KZGFfYXN2c19kZjIgPC0gZGFfYXN2c19kZjJbLCBjKDEsIDMsIDIpXQp3cml0ZS5jc3YoZGFfYXN2c19kZjIsICJORVRXT1JLUy9ncmFwaC5jc3YiLCBxdW90ZSA9IEZBTFNFLCByb3cubmFtZXMgPSBGQUxTRSkKCiMjI01ha2UgYXR0cmlidXRlCmRhX2FzdnNfdGF4IDwtIHRheF90YWJsZShkYV9hc3ZzKQojcmV0YWluIG9ubHkgdGhlIGNvbHVtbnMgd2l0aCB0YXhhIGluZm8KZGFfYXN2c190YXggPC0gZGFfYXN2c190YXhbLCAxOjVdICAKZGFfYXN2c190YXhfZGYgPC0gZGF0YS5mcmFtZShyb3cubmFtZXMoZGFfYXN2c190YXgpLCBkYV9hc3ZzX3RheCkKY29sbmFtZXMoZGFfYXN2c190YXhfZGYpIFsxXSA8LSAiSWQiCmRhX2FzdnNfdGF4X2RmJExhYmVsIDwtIGRhX2FzdnNfdGF4X2RmJElkCmRhX2FzdnNfdGF4X2RmJHR5cGUgPC0gIkFTViIKIyBSZW9yZGVyCmRhX2FzdnNfdGF4X2RmIDwtIGRhX2FzdnNfdGF4X2RmW2MoMSwgNywgOCwgMiwgMywgNCwgNSwgNildIAoKZGFfYXN2c19zYW1wIDwtIHNhbXBsZV9kYXRhKGRhX2FzdnMpCmRhX2FzdnNfc2FtcF9kZiA8LSBkYXRhLmZyYW1lKHJvdy5uYW1lcyhkYV9hc3ZzX3NhbXApLCBkYV9hc3ZzX3NhbXApCmNvbG5hbWVzKGRhX2FzdnNfc2FtcF9kZikgWzFdIDwtICJJZCIKZGFfYXN2c19zYW1wX2RmJExhYmVsIDwtIGRhX2FzdnNfc2FtcF9kZiRJZApkYV9hc3ZzX3NhbXBfZGYgPC0gZGFfYXN2c19zYW1wX2RmWy1jKDI6NCldCmRhX2FzdnNfc2FtcF9kZiR0eXBlIDwtICJIb3N0IgplbXB0eV9jb2x1bW5zIDwtIGMoIktpbmdkb20iLCAiUGh5bHVtIiwgIkNsYXNzIiwgIk9yZGVyIiwgIkZhbWlseSIpCmRhX2FzdnNfc2FtcF9kZltlbXB0eV9jb2x1bW5zXSA8LSBOQQojIGNvbWJpbmUgYW5kIHNhdmUKZ3JhcGhfYXR0cmlidXRlcyA8LSByYmluZChkYV9hc3ZzX3RheF9kZiwgZGFfYXN2c19zYW1wX2RmKQp3cml0ZS5jc3YoZ3JhcGhfYXR0cmlidXRlcywgIk5FVFdPUktTL2F0dHJpYnV0ZXMuY3N2IiwgcXVvdGUgPSBGQUxTRSwgCiAgICAgICAgICByb3cubmFtZXMgPSBGQUxTRSkKYGBgCgpDb21iaW5lIHRoZSB0d28gY2hhcnRzLgoKRWl0aGVyIGRvIG91dHNpZGUgUiBvciBmaWd1cmUgb3V0IGEgd2F5IHRvICdib2xiJyB0aGUgaGVhdG1hcC4gYGdyaWQ6OmdyaWQuZ3JhYmAgc2VlbWVkIHByb21pc2luZy4KCmBgYHtyIGhlYXRtYXBfYWx0X3ByaW50LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlID0gRkFMU0UsIGVjaG8gPSBGQUxTRSwgZXZhbCA9IEZBTFNFfQpmaWc0X2hlYXRtYXAyX2Rpc3AgPC0gaGVhdG1hcDMoZmlnNF9oZWF0bWFwMiwgdHJhY2UgPSAibm9uZSIsIGRlbnNpdHkgPSAibm9uZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2V4Um93ID0gMC41LCBjZXhDb2wgPSAxLCBtYXJnaW5zID0gYygzLCAxNSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUm93U2lkZUNvbG9ycyA9IGhlYXRDb2xvcnMsIHNjYWxlID0gInJvdyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ29sdiA9IE5BLCBSb3d2ID0gTkEsIHJldkMgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhbGFuY2VDb2xvciA9IEZBTFNFLCBjb2wgPSBjb2wpCmBgYAoKKioqCgojIyMgQXNzb2NpYXRpb24gYmV0d2VlbiBBU1ZzLCBob3N0IHBoeWxvZ2VueSwgJiBmb3JhZ2luZyBiZWhhdmlvdXIKClRvIHRlc3Qgd2hldGhlciBpbnRlc3RpbmFsIG1pY3JvYmVzIHdlcmUgYXNzb2NpYXRlZCB3aXRoICoqYSoqKSBwaHlsb2dlbmV0aWMgaGlzdG9yeSBhbmQvb3IgKipiKiopIGZvcmFnaW5nIGVjb2xvZ3kgb2YgZWFjaCBoZXJiaXZvcmUsIHdlIHVzZWQgYSBzZXJpZXMgb2Ygc2ltcGxlIGFuZCBwYXJ0aWFsIE1hbnRlbCB0ZXN0cy4gQmVjYXVzZSB3ZSBleHBlY3RlZCB0aGUgcmVsYXRpb25zaGlwcyB0byBwb3RlbnRpYWxseSBkaWZmZXIgZm9yIHB1dGF0aXZlIHJlc2lkZW50IHN5bWJpb250cyB2cy4gaW5nZXN0ZWQgZW52aXJvbm1lbnRhbCBnZW5lcmFsaXN0IG1pY3JvYmVzLCB3ZSBjb25zdHJ1Y3RlZCBzZXBhcmF0ZSBkaXNzaW1pbGFyaXR5IG1hdHJpY2VzIGZvciBob3N0LSBhbmQgZW52aXJvbm1lbnQtYXNzb2NpYXRlZCBBU1ZzLiBUaGVzZSBtYXRyaWNlcyB3ZXJlIGNvbnN0cnVjdGVkIHVzaW5nIHRoZSB2ZWdhbiBwYWNrYWdlIGluIFIgYW5kIHdlcmUgYmFzZWQgb24gQnJheS1DdXJ0aXMgZGlzc2ltaWxhcml0eSBvZiBIZWxsaW5nZXIgdHJhbnNmb3JtZWQgZGF0YS4gVGhlIGVjb2xvZ2ljYWwgZGlzc2ltaWxhcml0eSBtYXRyaXggd2FzIGJhc2VkIG9uIHRoZSBiZWhhdmlvdXJhbCBkYXRhIGNvbGxlY3RlZCB0byBxdWFudGlmeSBoZXJiaXZvcmUgdHJvcGhpYyBuaWNoZSBzcGFjZS4gVGhlIHBoeWxvZ2VuZXRpYyBkaXNzaW1pbGFyaXR5IG1hdHJpeCB3YXMgYmFzZWQgb24gYSBwaHlsb2dlbmV0aWMgdHJlZSBvZiB0aGUgZml2ZSBmaXNoIHNwZWNpZXMgdXNlZCBpbiB0aGlzIHN0dWR5LiBXZSBjb25zdHJ1Y3RlZCB0aGUgdHJlZSB1c2luZyBjeXRvY2hyb21lIG94aWRhc2Ugc3VidW5pdCAxIChDT0kpIGdlbmVzIHJldHJpZXZlZCBmcm9tIE5DQknigJlzIE51Y2xlb3RpZGUgRGF0YWJhc2UuIENsdXN0YWwgT21lZ2Egd2FzIHVzZWQgdG8gYWxpZ24gc2VxdWVuY2VzIChkZWZhdWx0IHNldHRpbmdzIGZvciBETkEpLiBXZSB0aGVuIHVzZWQgSmFsdmlldyB0byBtYW51YWxseSBjdXJhdGUgYW5kIHRyaW0gdGhlIGZpbmFsIGFsaWdubWVudCB0byA1OTMgYnAuIFRoaXMgYWxpZ25tZW50IGNvbnRhaW5lZCBDT0kgZ2VuZXMgZnJvbSBuID0gNSAqU2NhcnVzIHRhZW5pb3B0ZXJ1cyosIDIyICpTcGFyaXNvbWEgYXVyb2ZyZW5hdHVtKiwgMjEgKlNwYXJpc29tYSB2aXJpZGUqLCAyOCAqQWNhbnRodXJ1cyBjb2VydWxldXMqLCBhbmQgMjMgKkFjYW50aHVydXMgdHJhY3R1cyouIFdlIHVzZWQgbWVtYmVycyBvZiB0aGUgR2VycmlkYWUgKDIgKkV1Y2lub3N0b211cyogYW5kIDQgKkdlcnJlcyopIGFzIHRoZSBvdXRncm91cC4gV2UgdXNlZCBSQXhNTCBhbmQgdGhlIEdUUiBtb2RlbCBmb3IgdHJlZSBjb21wdXRhdGlvbiBhbmQgdGhlIEdBTU1BIHJhdGUgbW9kZWwgZm9yIGxpa2VsaWhvb2RzLiBUaGUgdHJlZSB3YXMgdGhlbiB0cmFuc2Zvcm1lZCBpbnRvIGEgZGlzdGFuY2UgbWF0cml4IHVzaW5nIHRoZSBjb3BoZW5ldGljIGZ1bmN0aW9uIGluIFIuICAgCgpgYGB7ciBtYW50ZWxfdGVzdF9hLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlID0gRkFMU0UsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQpkZXRhY2goInBhY2thZ2U6cGh5bG9zZXEiLCB1bmxvYWQ9VFJVRSkKbGlicmFyeShhcGUpCmxpYnJhcnkocGljYW50ZSkKbGlicmFyeShnZ3RyZWUpCmxpYnJhcnkodGlkeXRyZWUpCmxpYnJhcnkodHJlZWlvKQojIEdldCBwaHlsb2dlbmV0aWMgZGF0YSAtLS0tLS0tLS0tLS0tLS0tLS0KIyBSZWFkIG5ld2ljayB0cmVlIC0tLS0tLS0tLS0tLS0tLS0tLQp0cmVlIDwtIHJlYWQudHJlZSgiVEFCTEVTL0lOUFVUL01BTlRFTF9URVNUL2l0ZW1fb3JkZXJzLnR4dCIpCiNnZ3RyZWUodHJlZSkgKyBnZW9tX3RpcGxhYihjb2xvciA9ICJibHVlIikKCmhvc3RfdHJlZSA8LSBrbml0cjo6aW5jbHVkZV9ncmFwaGljcygiRklHVVJFUy9JTlBVVC9jb2xsYXBzZV90cmVlLnN2ZyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHBpID0gMzAwKQpob3N0X3RyZWUKYGBgCgpOZXh0LCB3ZSBwcnVuZWQgdGhlIHRyZWUgdG8gb25lIG1lbWJlciBvZiBlYWNoIHNwZWNpZXMsIHJlbW92ZWQgdGhlIG91dGdyb3VwLCBhbmQgY2hhbmdlZCB0aGUgbmFtZXMgdG8gc3BlY2llcyBuYW1lcy4KIApgYGB7ciBmaWcuYWxpZ24gPSAiY2VudGVyIiwgd2FybmluZz1GQUxTRSwgbWVzc2FnZSA9IEZBTFNFfQpkIDwtIG1hdHJpeChucm93ID0gMSwgbmNvbCA9IDUpCmNvbG5hbWVzKGQpIDwtIGMoIkhNMzc5ODI2X0FjYW50aHVydXNfY29lcnVsZXVzIiwKICAgICAgICAgICAgICAgIkxJRE01NDQtMDdfQWNhbnRodXJ1c190cmFjdHVzIiwgCiAgICAgICAgICAgICAgICJNWElWNDgwLTEwX1NjYXJ1c190YWVuaW9wdGVydXMiLCAKICAgICAgICAgICAgICAgIkpRODQxMzkwX1NwYXJpc29tYV9hdXJvZnJlbmF0dW0iLCAKICAgICAgICAgICAgICAgIkpRODM5NTk1X1NwYXJpc29tYV92aXJpZGUiKQp0cmVlLnAgPC0gcHJ1bmUuc2FtcGxlKHBoeWxvID0gdHJlZSwgc2FtcCA9IGQpCiNwbG90KHRyZWUucCkKIyBDaGFuZ2UgdGhlIG5hbWVzIHRvIHNwZWNpZXMgbmFtZXMKdHJlZS5wJHRpcC5sYWJlbFsxXSA8LSAiU3Bhcmlzb21hX2F1cm9mcmVuYXR1bSIKdHJlZS5wJHRpcC5sYWJlbFsyXSA8LSAiU3Bhcmlzb21hX3ZpcmlkZSIKdHJlZS5wJHRpcC5sYWJlbFszXSA8LSAiU2NhcnVzX3RhZW5pb3B0ZXJ1cyIKdHJlZS5wJHRpcC5sYWJlbFs0XSA8LSAiQWNhbnRodXJ1c190cmFjdHVzIgp0cmVlLnAkdGlwLmxhYmVsWzVdIDwtICJBY2FudGh1cnVzX2NvZXJ1bGV1cyIKcGxvdCh0cmVlLnApCmBgYAoKKioqCgpXZSB0aGVuIHRyYW5zZm9ybWVkIHRoZSB0cmVlIGludG8gYSBkaXN0YW5jZSBtYXRyaXggYW5kIGdlbmVyYXRlZCBhIGRlbmRyb2dyYW0uIAoKYGBge3IgbWFudGVsX3Rlc3RfYiwgZmlnLmFsaWduID0gImNlbnRlciIsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2UgPSBGQUxTRX0KI1RyYW5zZm9ybSB0cmVlIGludG8gYSBkaXN0YW5jZSBtYXRyaXgKdHJ4IDwtIGNvcGhlbmV0aWModHJlZS5wKQojdGhhdCB3b3JrcyBidXQgSSBuZWVkIHRoZXNlIGluIGFscGhhYmV0aWNhbCBvcmRlciBieSBzcGVjaWVzClQgPC0gZGlzdChjb3BoZW5ldGljKHRyZWUucCkpCm9yZGVyaW5nIDwtIHNvcnQoYXR0cihULCAiTGFiZWxzIikpClQubWF0IDwtIGFzLm1hdHJpeChUKVtvcmRlcmluZywgb3JkZXJpbmddClQgIDwtIGFzLmRpc3QoVC5tYXQpCiNwbG90IGNsdXN0ZXIgb2YgZGlzdGFuY2UgbWF0cml4CmNsdXN0ZXJfcGh5bG8gPC0gaGNsdXN0KFQsIG1ldGhvZCA9ICJ3YXJkLkQiKQkKcGxvdChjbHVzdGVyX3BoeWxvLCBtYWluID0gIlBoeWxvZ2VuZXRpYyBjbHVzdGVyaW5nIiwgCiAgICAgeGxhYiA9ICJIb3N0IHNwZWNpZXMiLCB5bGFiID0gIkRpc3RhbmNlIiwgCiAgICAgc3ViID0gImhlbGxpbmdlci9icmF5LWN1cnRpcy93YXJkIikKYGBgCgoqKioKCk5leHQgd2UgZ3JhYiB0aGUgZWNvbG9naWNhbCBkYXRhIGFuZCBzdGFuZGFyZGl6ZSB0aGUgdmFyaWFibGVzIHNvIHRoYXQgdGhleSBoYXZlIHNpbWlsYXIgd2VpZ2h0cy4KCkZpcnN0LCByZXNjYWxlIHF1YW50aXRhdGl2ZSB0cmFpdHMgdG8gYmUgaW4gdGhlIHJhbmdlIDAgdG8gMSBhbmQgdGhlbiBkZXZpZGUgYnkgdGhlIG51bWJlciBvZiBkaWV0IGNhdGVnb3JpZXMgdG8gaGF2ZSBzaW1pbGFyIGluZmx1ZW5jZSBhcyB0aGUgZGlldCB2YXJpYWJsZXMuIFRoZW4gcmVzY2FsZSBhbGwgJ25vbiBkaWV0JyB0cmFpdHMgdG8gaGF2ZSBzaW1pbGFyIGluZmx1ZW5jZSB0byB0aGUgZGlldCB0cmFpdHMgYnkgZGl2aWRpbmcgYnkgdGhlIG51bWJlciBvZiBkaWV0IGNhdGVnb3JpZXMgZGl2aWRlZCBieSB0aGUgbnVtYmVyIG9mIGNhdGVnb3JpZXMgZm9yIGVhY2ggc3Vic3RyYXRlIGNoYXJhY3RlcmlzdGljLiBOb3cgY29tYmluZSBpbnRvIGEgc2luZ2xlIGRhdGEgZnJhbWUgZm9yIGFuYWx5c2lzIGdldCBhdmVyYWdlcyBmb3IgZWFjaCBzcGVjaWVzLgoKYGBge3IgbWFudGVsX3Rlc3RfYywgd2FybmluZz1GQUxTRSwgbWVzc2FnZSA9IEZBTFNFfQphbGxfdHJhaXRzIDwtIHJlYWQuY3N2KAogICJUQUJMRVMvSU5QVVQvTUFOVEVMX1RFU1QvTWVhbl9iaXRlX2NoYXJhY3RlcmlzdGljcy5jc3YiLCAKICBoZWFkZXIgPSBUUlVFCiAgKQppZHMgPC0gYWxsX3RyYWl0c1ssIDE6Ml0KCnF1YW50X3RyYWl0c19zdGQgPC0gZGVjb3N0YW5kKGFsbF90cmFpdHNbLCAzOjRdLCAicmFuZ2UiKSAvIDEwCgpNZWFuX3Byb3BfbWFya19vbl9zdWJzdHJhdGVfc3RkIDwtIGFsbF90cmFpdHNbLCA1XSAvICgxMCAvIDIpCnByb3BfdmVydGljYWxfc3RkIDwtIGFsbF90cmFpdHNbLCA2XSAvICgxMCAvIDIpCnByb3BfY29uY2F2ZV9zdGQgPC0gYWxsX3RyYWl0c1ssIDddIC8gKDEwIC8gMykKcHJvcF9jb252ZXhfc3RkIDwtIGFsbF90cmFpdHNbLCA4XSAvICgxMCAvIDMpCgphbGxfdHJhaXRzX3N0ZCA8LSBjYmluZChxdWFudF90cmFpdHNfc3RkLCAKICAgICAgICAgICAgICAgICAgICAgIE1lYW5fcHJvcF9tYXJrX29uX3N1YnN0cmF0ZV9zdGQsIAogICAgICAgICAgICAgICAgICAgICAgcHJvcF92ZXJ0aWNhbF9zdGQsIHByb3BfY29uY2F2ZV9zdGQsIAogICAgICAgICAgICAgICAgICAgICAgcHJvcF9jb252ZXhfc3RkLCAKICAgICAgICAgICAgICAgICAgICAgIGFsbF90cmFpdHNbLCA5OjE4XQogICAgICAgICAgICAgICAgICAgICAgKQoKbWVhbl90cmFpdHMgPC0gYWdncmVnYXRlKGFsbF90cmFpdHNbLCAzOjE4XSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBieSA9IGxpc3QoYWxsX3RyYWl0cyRTcGVjaWVzKSwgbWVhbikKdHJhaXRzIDwtIG1lYW5fdHJhaXRzWywgMjoxN10Kcm93bmFtZXModHJhaXRzKSA8LSBhcy52ZWN0b3IobWVhbl90cmFpdHNbLCAxXSkKRmlzaF9zcGVjaWVzIDwtIGFzLnZlY3RvcihtZWFuX3RyYWl0c1ssIDFdKQpgYGAKCkFuZCBiZWdpbiB3aXRoIGEgSGVsbGluZ2VyIHRyYW5zZm9ybWF0aW9uIG9mIEVjb2xvZ2ljYWwgdHJhaXRzLgoKYGBge3IgbWFudGVsX3Rlc3RfZCwgZmlnLmFsaWduID0gImNlbnRlciIsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2UgPSBGQUxTRX0KdHJhaXRzX3RyYW5zIDwtIGRlY29zdGFuZCh0cmFpdHMsIG1ldGhvZCA9ICJoZWxsaW5nZXIiKQp0cmFpdHNfZGlzdCA8LSB2ZWdkaXN0KHRyYWl0c190cmFucywgbWV0aG9kID0gImJyYXkiKQpjbHVzdGVyX3RyYWl0cyA8LSBoY2x1c3QodHJhaXRzX2Rpc3QsIG1ldGhvZCA9ICJ3YXJkLkQiKQkKcGxvdChjbHVzdGVyX3RyYWl0cywgCiAgICAgbGFiZWxzID0gRmlzaF9zcGVjaWVzLCBtYWluID0gIkVjb2xvZ2ljYWwgdHJhaXRzIiwgCiAgICAgeGxhYiA9ICJIb3N0IHNwZWNpZXMiLCB5bGFiID0gIkRpc3RhbmNlIiwgCiAgICAgc3ViID0gImhlbGxpbmdlci9icmF5LWN1cnRpcy93YXJkIikKYGBgCgpTbywgaXMgZWNvbG9naWNhbCBkYXRhIGNvcnJlbGF0ZWQgd2l0aCBwaHlsb2dlbnk/IAoKYGBge3IgbWVzc2FnZSA9IEZBTFNFfQojIElzIGVjb2xvZ2ljYWwgZGF0YSBjb3JyZWxhdGVkIHdpdGggcGh5bG9nZW55Cm1hbnRlbCh0cmFpdHNfZGlzdCwgVCwgbWV0aG9kID0gInBlYXJzb24iLCBwZXJtdXRhdGlvbnMgPSA5OTk5KQpgYGAKCjBLLCBsb29rcyBsaWtlIHRoZXJlIGlzIG5vIGNvcnJlbGF0aW9uIGJldHdlZW4gZWNvbG9naWNhbCBkYXRhIGFuZCBwaHlsb2dlbnkuIE5leHQsIHdlIGxvb2tlZCBhdCBkaWZmZXJlbnRpYWxseSBhYnVuZGFudCBBU1ZzIHNwbGl0IGludG8gaG9zdC1hc3NvY2lhdGVkIHZzIGVudmlyb25tZW50YWxseSBhc3NvY2lhdGVkCgpgYGB7ciBtYW50ZWxfdGVzdF9lLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQphc3Y0IDwtIHJlYWQuZGVsaW0oCiAgIlRBQkxFUy9JTlBVVC9NQU5URUxfVEVTVC8yX2RhX2Fzdl9tZXJnZWRfZmlzaC50eHQiLCAKICBoZWFkZXIgPSBUCiAgKQphc3Y1IDwtIHJlYWQuZGVsaW0oCiAgIlRBQkxFUy9JTlBVVC9NQU5URUxfVEVTVC8yX2RhX2Fzdl9tZXJnZWRfYW5pbWFsLnR4dCIsIAogIGhlYWRlciA9IFQKICApCmFzdl9ob3N0IDwtIHJiaW5kKGFzdjQsIGFzdjUpCgojIE1lcmdlIHRoZSBmaXNoIGFuZCBhbmltYWwgZGF0YXNldHMgdG9nZXRoZXIKIyBUcmFuc3Bvc2UgZGF0YWZyYW1lCmFzdl9ob3N0X3QgPC0gZGF0YS5mcmFtZSh0KGFzdl9ob3N0Wy0xXSkpCmNvbG5hbWVzKGFzdl9ob3N0X3QpIDwtIGFzdl9ob3N0WywgMV0KCmxpYnJhcnkodmVnYW4pCiMgQ3JlYXRlIGRlbmRyb2dyYW0gYmFzZWQgb24gc2ltaWxhcml0eSBpbiBhc3YKCkZpc2hfc3BlY2llcyA8LSBhcy52ZWN0b3IoY29sbmFtZXMoYXN2X2hvc3RbMjo2XSkpCkd1dF9jb250ZW50cyA8LSBzcXJ0KGFzdl9ob3N0X3RbXSkKI1RyeSBoZWxsaW5nZXIgdHJhbnNmb3JtYXRpb24KR3V0X2NvbnRlbnRzIDwtIGRlY29zdGFuZChhc3ZfaG9zdF90LCBtZXRob2QgPSAiaGVsbGluZ2VyIikKR3V0X2Rpc3RfaG9zdCA8LSB2ZWdkaXN0KEd1dF9jb250ZW50cywgbWV0aG9kID0gImJyYXkiKQpjbHVzdGVyX2d1dF9ob3N0IDwtIGhjbHVzdChHdXRfZGlzdF9ob3N0LCBtZXRob2QgPSAid2FyZC5EIikJCnBsb3QoY2x1c3Rlcl9ndXRfaG9zdCwgbGFiZWxzID0gRmlzaF9zcGVjaWVzLCBtYWluID0gIkhvc3QtYXNzb2NpYXRlZCBBU1ZzIiwgCiAgICAgeGxhYiA9ICJIb3N0IHNwZWNpZXMiLCB5bGFiID0gIkRpc3RhbmNlIiwgc3ViID0gImhlbGxpbmdlci9icmF5LWN1cnRpcy93YXJkIikKYGBgCgpTbyBpcyB0aGUgZGlzdGFuY2UgbWF0cml4IChiYXNlZCBvbiBob3N0IGFzc29jaWF0ZWQgQVNWcykgY29ycmVsYXRlZCB3aXRoIGVjb2xvZ2ljYWwgZGF0YSBvciBwaHlsb2dlbnk/CgpgYGB7ciBtYW50ZWxfdGVzdF9mLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQptYW50ZWwoR3V0X2Rpc3RfaG9zdCwgVCwgbWV0aG9kID0gInBlYXJzb24iLCBwZXJtdXRhdGlvbnMgPSA5OTk5KQpgYGAKCioqWWVzLCBoaWdobHkgY29ycmVsYXRlZCB3aXRoIHBoeWxvZ2VueS4uLioqCgpgYGB7ciBtYW50ZWxfdGVzdF9nLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQptYW50ZWwoR3V0X2Rpc3RfaG9zdCwgdHJhaXRzX2Rpc3QsIG1ldGhvZCA9ICJwZWFyc29uIiwgcGVybXV0YXRpb25zID0gOTk5OSkKIyBOb3QgYXNzb2NpYXRlZCB3aXRoIGVjb2xvZ2ljYWwgdHJhaXRzCmBgYAoKKiouLi5idXQgbm90IGFzc29jaWF0ZWQgd2l0aCBlY29sb2dpY2FsIHRyYWl0cy4qKgoKV2hhdCBhYm91dCB0aGUgZGlzdG5hY2UgbWF0cml4IGJhc2VkIG9uIGVudmlyb25tZW50IGFzc29jaWF0ZWQgQVNWcz8gSXMgaXQgY29ycmVsYXRlZCB3aXRoIGVjb2xvZ2ljYWwgZGF0YSBvciBwaHlsb2dlbnk/CgpgYGB7ciBtYW50ZWxfdGVzdF9oLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuYWxpZ24gPSAiY2VudGVyIn0KYXN2NiA8LSByZWFkLmRlbGltKAogICJUQUJMRVMvSU5QVVQvTUFOVEVMX1RFU1QvMl9kYV9hc3ZfbWVyZ2VkX2Vudmlyb25tZW50YWwudHh0IiwgCiAgaGVhZGVyID0gVCkKIyBUcmFuc3Bvc2UgZGF0YWZyYW1lCmFzdl9lbnZfdCA8LSBkYXRhLmZyYW1lKHQoYXN2NlstMV0pKQpjb2xuYW1lcyhhc3ZfZW52X3QpIDwtIGFzdjZbLCAxXQoKIyBDcmVhdGUgZGVuZHJvZ3JhbSBiYXNlZCBvbiBzaW1pbGFyaXR5IGluIGFzdgpGaXNoX3NwZWNpZXMgPC0gYXMudmVjdG9yKGNvbG5hbWVzKGFzdjZbMjo2XSkpCkd1dF9jb250ZW50cyA8LSBzcXJ0KGFzdl9lbnZfdFtdKQojVHJ5IGhlbGxpbmdlciB0cmFuc2Zvcm1hdGlvbgpHdXRfY29udGVudHMgPC0gZGVjb3N0YW5kKGFzdl9lbnZfdCwgbWV0aG9kID0gImhlbGxpbmdlciIpCkd1dF9kaXN0X2VudiA8LSB2ZWdkaXN0KEd1dF9jb250ZW50cywgbWV0aG9kID0gImJyYXkiKQpjbHVzdGVyX2d1dF9lbnYgPC0gaGNsdXN0KEd1dF9kaXN0X2VudiwgbWV0aG9kID0gIndhcmQuRCIpCQpwbG90KGNsdXN0ZXJfZ3V0X2VudiwgbGFiZWxzID0gRmlzaF9zcGVjaWVzLCAKICAgICBtYWluID0gIkVudmlyb25tZW50LWFzc29jaWF0ZWQgQVNWcyIsIAogICAgIHhsYWIgPSAiSG9zdCBzcGVjaWVzIiwgeWxhYiA9ICJEaXN0YW5jZSIsIAogICAgIHN1YiA9ICJoZWxsaW5nZXIvYnJheS1jdXJ0aXMvd2FyZCIpCmBgYAoKYGBge3IgbWFudGVsX3Rlc3RfaSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KbWFudGVsKEd1dF9kaXN0X2VudiwgVCwgCiAgICAgICBtZXRob2QgPSAicGVhcnNvbiIsIHBlcm11dGF0aW9ucyA9IDk5OTkKICAgICAgICkKIyBNYXJnaW5hbGx5IHNpZ25pZmljYW50IGNvcnJlbGF0aW9uCmBgYAoKRG9lc24ndCBsb29rIGNvcnJlbGF0ZWQgd2l0aCBwaHlsb2dlbnkuLi4KCmBgYHtyIG1hbnRlbF90ZXN0X2osIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9Cm1hbnRlbChHdXRfZGlzdF9lbnYsIHRyYWl0c19kaXN0LCAKICAgICAgIG1ldGhvZCA9ICJwZWFyc29uIiwgcGVybXV0YXRpb25zID0gOTk5OQogICAgICAgKQpgYGAKCi4uLm9yIGVjb2xvZ2ljYWwgZGF0YS4gCgpXZSBjb3VsZCBhbHNvIGRvICoqcGFydGlhbCBNYW50ZWwgdGVzdHMqKi4KCmBgYHtyIG1hbnRlbF90ZXN0X2ssIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UgfQptYW50ZWwucGFydGlhbChHdXRfZGlzdF9lbnYsIFQsIHRyYWl0c19kaXN0LCAKICAgICAgICAgICAgICAgbWV0aG9kID0gInBlYXJzb24iLCBwZXJtdXRhdGlvbnMgPSA5OTk5CiAgICAgICAgICAgICAgICkKbWFudGVsLnBhcnRpYWwoR3V0X2Rpc3RfZW52LCB0cmFpdHNfZGlzdCwgVCwgCiAgICAgICAgICAgICAgIG1ldGhvZCA9ICJwZWFyc29uIiwgcGVybXV0YXRpb25zID0gOTk5OQogICAgICAgICAgICAgICApCmBgYAoKQnV0IGFnYWluLCBubyBzaWduaWZpY2FuY2UgZGV0ZWN0ZWQuLi4KCiMjIEFwcGVuZGl4IEE6IE90aGVyIGFuYWx5c2VzICYgdmlzdWFsaXphdGlvbnMKCltiYWNrIHRvIHRvcF0oI2JhY2sgdG8gdG9wKQoKSGVyZSBpcyBjb2RlIGZvciBvdGhlciByZXByZXNlbnRhdGlvbiBvZiB0YXhhIGFidW5kYW5jZS4gVGhlc2UgYXJlIHJhdyBgUmAgaW1hZ2VzIHRoYXQgaGF2ZSBub3QgYmVlbiBndXNzaWVkIHVwLgoKV2Ugd2lsbCBjcmVhdGUgdHdvIGRpZmZlcmVudCByZXByZXNlbnRhdGlvbnMgb2YgcmVsYXRpdmUgYWJ1bmRhbmNlIGZvciBlYWNoIHNhbXBsZSAoYXJyYW5nZWQgYnkgaG9zdCBzcGVjaWVzKSBieSBtYWpvciBDbGFzc2VzLS0tZmFjZXQgZ3JpZCBib3gtYW5kLXdoaXNrZXIgcGxvdHMgYW5kIGJhciBjaGFydHMuIFdlIHdpbGwgZ2VuZXJhdGUgZWFjaCBzZXBhcmF0ZWx5IChhbmQgc2F2ZSkgdXNpbmcgYW4gZWFybGllciAgcmVsYXRpdmUgYWJ1bmRhbmNlIHBoeWxvc2VxIG9iamVjdCBhbmQgdGhlbiBkaXNwbGF5IHRoZSBjb21iaW5lZCBvdXRwdXQuIAoKKipDb2RlIGZvciBib3gtYW5kLXdoaXNrZXIgcGxvdC4qKgoKYGBge3Igc3VwcF9maWcxX2NhbGMsIHJlc3VsdHMgPSAiaGlkZSIsIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkocGh5bG9zZXEpCm1kYXRhX3BoeV9hbGwgPC0gdGF4X2dsb20ocHNfc2x2X2ZpbHRfQVZHLCB0YXhyYW5rID0gIkNsYXNzIiwgTkFybSA9IEZBTFNFKQojIFlvdSBjYW4gY2hvb3NlIGFueSB0YXhvbm9taWMgbGV2ZWwgaGVyZQptZGF0YV9waHlyZWxfYWxsIDwtIHRyYW5zZm9ybV9zYW1wbGVfY291bnRzKAogIG1kYXRhX3BoeV9hbGwsIGZ1bmN0aW9uKHgpIHggLyBzdW0oeCkKICApCm1lbHRkX2FsbCA8LSBwc21lbHQobWRhdGFfcGh5cmVsX2FsbCkKbWVsdGRfYWxsJENsYXNzIDwtIGFzLmNoYXJhY3RlcihtZWx0ZF9hbGwkQ2xhc3MpCgptZWFucyA8LSBkZHBseShtZWx0ZF9hbGwsIH5DbGFzcywgZnVuY3Rpb24oeCkgYyhtZWFuID0gbWVhbih4JEFidW5kYW5jZSkpKQojIGRlY2VuZGluZyBvcmRlcgp0YXhhX21lYW5zIDwtIG1lYW5zW29yZGVyKC1tZWFucyRtZWFuKSwgXSAgCiMgZGl0Y2ggdGhlIHNjaSBub3RhdGlvbiAKdGF4YV9tZWFucyA8LSBmb3JtYXQodGF4YV9tZWFucywgc2NpZW50aWZpYyA9IEZBTFNFKSAgCgojIEhlcmUgd2UgY29uZ2xvbWVyYXRlIGF0IDIlLgpPdGhlciA8LSBtZWFuc1ttZWFucyRtZWFuIDw9IDAuMDI2LCBdJENsYXNzICAKCm1lbHRkX2FsbFttZWx0ZF9hbGwkQ2xhc3MgJWluJSBPdGhlciwgXSRDbGFzcyA8LSAiT3RoZXIiCnNhbXBfbmFtZXMgPC0gYWdncmVnYXRlKG1lbHRkX2FsbCRBYnVuZGFuY2UsIAogICAgICAgICAgICAgICAgICAgICAgICBieSA9IGxpc3QobWVsdGRfYWxsJFNhbXBsZSksIEZVTiA9IHN1bSlbLCAxXQouZSA8LSBlbnZpcm9ubWVudCgpCm1lbHRkX2FsbFssICJDbGFzcyJdIDwtIGZhY3RvcihtZWx0ZF9hbGxbLCAiQ2xhc3MiXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzb3J0KHVuaXF1ZShtZWx0ZF9hbGxbLCAiQ2xhc3MiXSkpKQptZWx0ZF9hbGwgPC0gbWVsdGRfYWxsW29yZGVyKG1lbHRkX2FsbFssICJDbGFzcyJdKSwgXQpsZXZlbHMobWVsdGRfYWxsJENsYXNzKQoKIyBIZXJlIHdlIG9yZGVyIENsYXNzZXMgYnkgdGhlIFBoeWx1bSB0aGV5IGJlbG9uZyB0by4KbWVsdGRfYWxsJENsYXNzIDwtIGZhY3RvcihtZWx0ZF9hbGwkQ2xhc3MsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQmFjdGVyb2lkaWEiLCAiQ2xvc3RyaWRpYSIsICJFcnlzaXBlbG90cmljaGlhIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRnVzb2JhY3RlcmlpYSIsICJBbHBoYXByb3Rlb2JhY3RlcmlhIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRGVsdGFwcm90ZW9iYWN0ZXJpYSIsICJHYW1tYXByb3Rlb2JhY3RlcmlhIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUGxhbmN0b215Y2V0YWNpYSIsICJPeHlwaG90b2JhY3RlcmlhIiwgIk90aGVyIikpICAKCnN1cF9maWcxIDwtIHFwbG90KGRhdGEgPSBtZWx0ZF9hbGwsIHggPSBTcCwgeSA9IEFidW5kYW5jZSwgZmlsbCA9IENsYXNzLCAKICAgICAgICAgICAgICAgICAgZ2VvbSA9ICJib3hwbG90IiwgeWxhYiA9ICJSZWxhdGl2ZSBBYnVuZGFuY2UiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsgCiAgZmFjZXRfZ3JpZChDbGFzcyB+IC4sIHNjYWxlcyA9ICJmcmVlX3kiLCBzcGFjZSA9ICJmcmVlX3kiKSArIAogIGdlb21faml0dGVyKHdpZHRoID0gMC4wNSkgKyAKICBnZW9tX3BvaW50KGNvbG91ciA9ICJibGFjayIsIGZpbGwgPSAid2hpdGUiKSAgCiMrIGd1aWRlcyhndWlkZV9sZWdlbmQocmV2ZXJzZSA9IEZBTFNFKSApCgpzdXBfZmlnMSA8LSBzdXBfZmlnMSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGZyaWVuZF9wYWwpICsgCiAgbGFicyh4ID0gIkhvc3Qgc3BlY2llcyIsIHkgPSAiUmVsYXRpdmUgYWJ1bmRhbmNlICglIHRvdGFsIHJlYWRzKSIpCgpwZGYoIkZJR1VSRVMvT1VUUFVUL2JveF9hbmRfd2hpc2tlci5wZGYiKQpzdXBfZmlnMQppbnZpc2libGUoZGV2Lm9mZigpKQpgYGAKCioqQ29kZSBmb3IgYmFyIHBsb3QuKioKCiMjIyMgPGZvbnQgY29sb3I9InJlZCI+U3VwcGxlbWVudGFyeSBGaWd1cmUgMTwvZm9udD4KCmBgYHtyIHNlcGFyYXRlX2JhcnNfc3RhY2tlZCwgZmlnLmFsaWduID0gImNlbnRlciIsIGZpZy5jYXAgPSAiU3VwcGxlbWVudGFyeSBGaWd1cmUgMS4gUmVsYXRpdmUgYWJ1bmRhbmNlIG9mIG1ham9yIENsYXNzZXMgYnkgc2FtcGxlIiwgb3V0LndpZHRoID0gIjkwJSJ9CnN1cF9maWcyIDwtIGdncGxvdChtZWx0ZF9hbGwsIGFlc19zdHJpbmcoeCA9ICJTYW1wbGUiLCB5ID0gIkFidW5kYW5jZSIsIAogICAgZmlsbCA9ICJDbGFzcyIpLCBlbnZpcm9ubWVudCA9IC5lLCBPcmRlcmVkID0gVFJVRSkKc3VwX2ZpZzIgPC0gc3VwX2ZpZzIgKyBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAic3RhY2siKSArIAogICAgZmFjZXRfZ3JpZChDbGFzcyB+IFNwLCBzY2FsZXMgPSAiZnJlZSIsIHNwYWNlID0gImZyZWUiKQpzdXBfZmlnMiA8LSBzdXBfZmlnMiArIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGZyaWVuZF9wYWwpCgojIHN1cF9maWcyIDwtIHN1cF9maWcyICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAtOTAsCiMgaGp1c3QgPSAwKSkKc3VwX2ZpZzIgPC0gc3VwX2ZpZzIgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSkKCnN1cF9maWcyIDwtIHN1cF9maWcyICsgCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChjb2xvdXIgPSBOVUxMKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV2ZXJzZSA9IEZBTFNFKSkgKyAKICB0aGVtZShsZWdlbmQua2V5ID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJibGFjayIpLCAKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKyAKICBsYWJzKHggPSAiSW5kaXZpZHVhbCBzYW1wbGVzIiwgeSA9ICJSZWxhdGl2ZSBhYnVuZGFuY2UgKCUgdG90YWwgcmVhZHMpIikKCnBkZigiRklHVVJFUy9PVVRQVVQvRmlndXJlX1MxLnBkZiIpCnN1cF9maWcyCmludmlzaWJsZShkZXYub2ZmKCkpCmBgYAo8YSBpZD0iYm94LWFuZC13aGlza2VyLXBsb3QiPjwvYT4KCjxhIGlkPSJzZXBhcmF0ZS1iYXItcGxvdHMiPjwvYT4KCiMjIyMgRmlndXJlIFMxCgpgYGB7ciBncmlkLmFycmFuZ2VfcGxvdHMsIGZpZy5hbGlnbiA9ICJjZW50ZXIiLCBmaWcuY2FwID0gIkZpZ3VyZSBTMS4gUmVsYXRpdmUgYWJ1bmRhbmNlIG9mIG1ham9yIENsYXNzZXMgYnkgc2FtcGxlIiwgb3V0LndpZHRoID0gIjkwJSJ9CmdyaWQuYXJyYW5nZShzdXBfZmlnMSwgc3VwX2ZpZzIsIG5jb2wgPSAyKQpgYGAKCltyZXR1cm4gdG8gRmlndXJlIDJBXSgjcmVsYXRpdmUgYWJ1bmRhbmNlIHBoeWxvc2VxIG9iamVjdCkKCmBgYHtyIHBsb3RfZGFfYXN2X2hlYXRtYXBfZnVsbCwgd2FybmluZz1GQUxTRSwgZmlnLmNhcCA9ICJGaWd1cmUgNCIsIG1lc3NhZ2UgPSBGQUxTRSwgZXZhbCA9IEZBTFNFLCBlY2hvID0gRkFMU0V9CiNPbGQgaGVhdCBtYXAgdXNpbmcgcGh5bG9zZXEuIApmaWc0X2hlYXQgPC0gcGxvdF9oZWF0bWFwKGRhX2FzdnMsICJQQ29BIiwgImpzZCIsICJTcCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbG93ID0gIiMwMDAwMzMiLCBoaWdoID0gIiM2NkNDRkYiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zID0gbG9nX3RyYW5zKDEwKSwgc2FtcGxlLm9yZGVyID0gIlNwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBtYXgubGFiZWwgPSAyNTAsIHRheGEub3JkZXIgPSBhc3Zfb3JkZXIpCmZpZzRfaGVhdCA8LSBmaWc0X2hlYXQgKyBjb29yZF9maXhlZChyYXRpbyA9IDEgLyAxMikgKwogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gYygiQWNDb2UiLCAiQWNUcmEiLCAiU2NUYWUiLCAiU3BBdXIiLCAiU3BWaXIiKSkKCmZpZzRfaGVhdApwZGYoIkZJR1VSRVMvT1VUUFVUL2ZpZzRfZGFfYXN2c19oZWF0LnBkZiIpCmZpZzRfaGVhdAppbnZpc2libGUoZGV2Lm9mZigpKQpgYGAKCgpgYGB7ciBwaWNydXN0LCBldmFsID0gRkFMU0UsIGVjaG8gPSBGQUxTRSwgaW5jbHVkZSA9IEZBTFNFfQojbWFrZSBzaGFyZWQgZmlrZQp0YWJibGUgPC0gYXMob3R1X3RhYmxlKHBzX3Nsdl93b3JrX2ZpbHQpLCAibWF0cml4IikKdGFiYmxlZGYgPC0gYXMuZGF0YS5mcmFtZSh0YWJibGUpCm51bU90dXMgPC0gIjEwNTY1IgpkZjEgPC0gY2JpbmQobnVtT3R1cywgdGFiYmxlZGYpCmRmMSA8LSBkZjEgJT4lIHJvd25hbWVzX3RvX2NvbHVtbigiR3JvdXAiKQpsYWJlbCA8LSAwLjAzCmRmMiA8LSBjYmluZChsYWJlbCwgZGYxKQp3cml0ZS50YWJsZShkZjIsICJUQUJMRVMvT1VUUFVUL09USEVSL3BzX3Nsdl93b3JrX2ZpbHQuc2hhcmVkIiwgCiAgICAgICAgICAgIHNlcCA9ICJcdCIsIHF1b3RlID0gRkFMU0UsIHJvdy5uYW1lcyA9IEZBTFNFKQpmYXN0YSA8LSB0YXhfdGFibGUocHNfc2x2X3dvcmtfZmlsdCkKd3JpdGUudGFibGUoZmFzdGEyZm9ybWF0X3RyaW0sIAogICAgICAgICAgICAiVEFCTEVTL09VVFBVVC9PVEhFUi9wc19zbHZfd29ya19maWx0LmZhc3RhIiwgCiAgICAgICAgICAgIHNlcCA9ICJcdCIsIHF1b3RlID0gRkFMU0UsIGNvbC5uYW1lcyA9IE5BKQojIGZpeCB0aGUgZmlsZQojIG1vdGh1cgpjbGFzc2lmeS5zZXFzKGZhc3RhPXBzX3Nsdl93b3JrX2ZpbHQuZmFzdGEsIHRlbXBsYXRlPWdnXzEzXzVfOTkuZmFzdGEsIAogICAgICAgICAgICAgIHRheG9ub215PWdnXzEzXzVfOTkuZ2cudGF4LCBwcm9jZXNzb3JzPTgpCm1ha2UuYmlvbShzaGFyZWQ9cHNfc2x2X3dvcmtfZmlsdC5zaGFyZWQsIGxhYmVsPTAuMDMsCiAgICAgICAgICBjb25zdGF4b25vbXk9cHNfc2x2X3dvcmtfZmlsdC5nZy53YW5nLmNvbnMudGF4b25vbXksIAogICAgICAgICAgcGljcnVzdD05N19vdHVfbWFwLnR4dCwgcmVmdGF4b25vbXk9Z2dfMTNfNV85OS5nZy50YXgpCgp0YXhzdW1zIDwtIGFzLmRhdGEuZnJhbWUodGF4YV9zdW1zKHBzX3Nsdl93b3JrX2ZpbHQpKQp3cml0ZS50YWJsZSh0YXhzdW1zLCAiVEFCTEVTL09VVFBVVC9PVEhFUi90YXhzdW1zLnR4dCIsIAogICAgICAgICAgICBzZXA9Ilx0IiwgcXVvdGUgPSBGQUxTRSkKYGBgCgojIyBBcHBlbmRpeCBCOiBUb29scyAmIHJlc291cmNlcyB1c2VkIGluIHRoaXMgd29ya2Zsb3cgCgpbYmFjayB0byB0b3BdKCNiYWNrIHRvIHRvcCkKCioqU3BlY2lmaWMgdG9vbHMqKgoKLS0gW3BoeWxvc2VxXShodHRwczovL2pvZXk3MTEuZ2l0aHViLmlvL3BoeWxvc2VxLyl7dGFyZ2V0PSJfYmxhbmsifSBhcyB0aGUgcHJpbWFyeSBhbmFseXRpY2FsIHBhY2thZ2UuICAKLS0gW0xFZlNlXShodHRwczovL2R4LmRvaS5vcmcvMTAuMTAzOCUyRm5tZXRoLjI2NTgpe3RhcmdldD0iX2JsYW5rIn0gdG8gaWRlbnRpZnkgZGlmZmVyZW50aWFsbHkgYWJ1bmRhbnQgKERBKSBhbXBsaWNvbiBzZXF1ZW5jZSB2YXJpYW50cyAoQVNWKSBhY3Jvc3MgaG9zdCBmaXNoIHNwZWNpZXMuICAKLS0gW01pY3JvYmlvbWVBbmFseXN0XShodHRwOi8vd3d3Lm1pY3JvYmlvbWVhbmFseXN0LmNhLyl7dGFyZ2V0PSJfYmxhbmsifSAgdG8gY29uZHVjdCBMRWZTZSBhbmFseXNpcy4gIAotLSBbQkxBU1RuXShodHRwczovL2JsYXN0Lm5jYmkubmxtLm5paC5nb3YvQmxhc3QuY2dpKXt0YXJnZXQ9Il9ibGFuayJ9IGFuZCBbU2lsdmEgQUNUXShodHRwczovL3d3dy5hcmItc2lsdmEuZGUvYWxpZ25lci8pe3RhcmdldD0iX2JsYW5rIn0gdG8gaWRlbnRpZnkgY2xvc2VzdCBoaXRzIHRvIERBIEFTVnMuICAKLS0gW1JBeE1MXShodHRwczovL3Njby5oLWl0cy5vcmcvZXhlbGl4aXMvd2ViL3NvZnR3YXJlL3JheG1sLyl7dGFyZ2V0PSJfYmxhbmsifSBmb3IgcGh5bG9nZW5ldGljIGluZmVyZW5jZSBvZiBEQSBBU1ZzIGFuZCBjbG9zZXN0IGhpdHMuICAKLS0gW2lUT0xdKGh0dHBzOi8vaXRvbC5lbWJsLmRlLyl7dGFyZ2V0PSJfYmxhbmsifSBmb3IgdmlzdWFsaXphdGlvbiBvZiB0cmVlIGFuZCBhc3NvY2lhdGVkIG1ldGFkYXRhLiAgCgoqKk90aGVyIHZhbHVhYmxlIHJlc291cmNlcyoqCgotLSBbUiBNYXJrZG93bjogVGhlIERlZmluaXRpdmUgR3VpZGVdKGh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL3JtYXJrZG93bi8pe3RhcmdldD0iX2JsYW5rIn0gIAotLSBba25pdHJdKGh0dHA6Ly95aWh1aS5uYW1lL2tuaXRyLyl7dGFyZ2V0PSJfYmxhbmsifSB0dXRvcmlhbHMuIEZhbnRhc3RpYyBzaXRlISAgCi0tIFtNaWNyb2Jpb3RhIGFuYWx5c2lzIGluIFIsIFVDUiBXb3Jrc2hvcCAyMDE4XShodHRwczovL3JwdWJzLmNvbS9tYWRkaWVTQy9SX1NPUF9VQ1JfSmFuXzIwMTgpe3RhcmdldD0iX2JsYW5rIn0gbmljZWx5IGRvY3VtZW50ZWQgd29ya2Zsb3cgd2l0aCBleGFtcGxlcy4gCgojIyBBcHBlbmRpeCBDOiBTdWJtaXR0aW5nIHNlcXVlbmNpbmcgZGF0YSB0byBwdWJsaWMgYXJjaGl2ZXMgIAoKW2JhY2sgdG8gdG9wXSgjYmFjayB0byB0b3ApCgpJdCBpcyBub3cgdGltZSB0byBzdWJtaXQgdGhlIGRhdGEgdG8geW91ciBmYXZvcml0ZSBzZXF1ZW5jZSByZWFkIGFyY2hpdmUuIFdlIHN1Ym1pdHRlZCBvdXQgZGF0YSB0byB0aGUgW0V1cm9wZWFuIE51Y2xlb3RpZGUgQXJjaGl2ZSAoRU5BKV0oaHR0cHM6Ly93d3cuZWJpLmFjLnVrL2VuYSkuIFRoZSBFTkEgZG9lcyBub3QgbGlrZSBSQVcgZGF0YSBhbmQgcHJlZmVycyB0byBoYXZlIHByaW1lcnMgcmVtb3ZlZC4gU28gd2Ugc3VibWl0dGVkIHRoZSB0cmltbWVkIEZhc3RxIGZpbGVzIHRvIHRoZSBFTkEuIFlvdSBjYW4gZmluZCB0aGVzZSBkYXRhIHVuZGVyIHRoZSBzdHVkeSBhY2Nlc3Npb24gbnVtYmVyICoqUFJKRUIyODM5NyoqLiBUaGUgUkFXIGZpbGVzIG9uIG91ciBmaWdzaGFyZSBzaXRlLiAgVE9ETyBJTlNFUlQgRE9JL0xJTksKClRvIHN1Ym1pdCB0byB0aGUgRU5BIHlvdSBuZWVkIHR3byBkYXRhIHRhYmxlcyAocGx1cyB5b3VyIHNlcXVlbmNlIGRhdGEpLiBUaGUgZmlyc3QgZmlsZSBkZXNjcmliZXMgdGhlIHNhbXBsZXMgYW5kIHRoZSBzZWNvbmQgZmlsZSBkZXNjcmliZXMgdGhlIHNlcXVlbmNpbmcgZGF0YS4gVGhlIG9yaWdpbmFsIGZpbGVzIGNhbiBiZSBmb3VuZCBvbiB0aGUgZmlnc2hhcmUgc2l0ZS4gCgojIyBBcHBlbmRpeCBEOiBTcGVjaWZpYyBSIHBhY2thZ2UgJiB2ZXJzaW9ucyAKCltiYWNrIHRvIHRvcF0oI2JhY2sgdG8gdG9wKQoKQmVsb3cgYXJlIHRoZSBzcGVjaWZpYyBwYWNrYWdlcyBhbmQgdmVyc2lvbnMgdXNlZCBpbiB0aGlzIHdvcmtmbG93IHVzaW5nIGJvdGggYHNlc3Npb25JbmZvKClgIGFuZCBgZGV2dG9vbHM6OnNlc3Npb25faW5mbygpYC4KCmBgYHtyIHNlc3Npb25JbmZvLCBpbmNsdWRlPVRSVUV9CnByb2MudGltZSgpIC0gcHRtCnNlc3Npb25JbmZvKCkKZGV2dG9vbHM6OnNlc3Npb25faW5mbygpCmVuZF90aW1lIDwtIFN5cy50aW1lKCkKZW5kX3RpbWUgLSBzdGFydF90aW1lCmBgYAoKW2JhY2sgdG8gdG9wXSgjYmFjayB0byB0b3ApCgo=