Visualizing Distributions (2024)

University of Iowa College of Liberal Arts and Sciences

  • STAT:4580
  • Syllabus
  • Outline
  • Homework
  • Notes
  • Resources
  • -->
  • Show All Code
  • Hide All Code
  • Download Rmd
  • Introduction
  • Strip Plots
    • Strip Plot Basics
    • Multiple Groups
    • Scalability
    • Some Notes
  • Histograms
    • Histogram Basics
    • Histograms in R
    • Superimposing a Density
    • Multiple Groups
    • Scalability
  • Density Plots
    • Density Plot Basics
    • Scalability
    • Multiple Groups
    • Some Notes
    • Interactive Bandwidth Choice
  • Boxplots
  • Violin Plots
  • Swarm Plots
  • Effectiveness and Scalability
  • Ridgeline Plots
  • Reading
  • Interactive Tutorial
  • Exercises

Introduction

Once there are more than a handful of numeric data values it is often useful to step back and look at the distribution of the data values:

  • Where is the bulk of the data located?

  • Is there a single area of concentration or are there several?

  • Is the data distribution symmetric or is it skewed, i.e.trails off more slowly in one direction or another?

  • Are there extreme, or outlying, values?

  • Are there any suspicious or impossible values?

  • Are there gaps in the data?

  • Is there rounding, e.g.to integer values, or heaping, i.e.a few particular values occur very frequently?

Plots for visualizing distributions include

  • Strip plots.

  • Histograms.

  • Density plots.

  • Box plots.

  • Violin plots.

  • Swarm plots.

  • Density ridges

Strip Plots

Strip Plot Basics

A variant of the dot plot is known as a strip plot.

A strip plot for the city temperature data is

thm <- theme_minimal() + theme(text = element_text(size = 16))ggplot(citytemps) + geom_point(aes(x = temp, y = "All")) + thm + theme(axis.title.y = element_blank(), axis.text.y = element_blank())

Visualizing Distributions (2)

The strip plot can reveal gaps and outliers.

After looking at the plot we might want to examine the high and low values:

filter(citytemps, temp > 85)## city temp## 1 Asuncion 95## 2 Caracas 90## 3 Dar es Salaam 86## 4 Kinshasa 86## 5 Lagos 91## 6 Managua 88## 7 Rio de Janeiro 88## 8 São Paulo 90filter(citytemps, temp < 10)## city temp## 1 Anadyr 3## 2 Calgary 1## 3 Edmonton -11## 4 Kyiv 9## 5 Minsk 0## 6 Moscow 3## 7 Winnipeg 8

For the eruption durations in the faithful data a strip plot shows the two modes around 2 and 4 minutes:

ggplot(faithful) + geom_point(aes(x = eruptions, y = "All")) + thm + theme(axis.title.y = element_blank(), axis.text.y = element_blank())

Visualizing Distributions (3)

Multiple Groups

Strip plots are most useful for showing subsets corresponding to a categorical variable.

A strip plot for the yields for different varieties in the barley data is

ggplot(barley) + geom_point(aes(x = yield, y = variety)) + theme_minimal() + thm

Visualizing Distributions (4)

Scalability

Scalability in this form is limited due to over-plotting.

A simple strip plot of price within the different cut levels in the diamonds data is not very helpful:

ggplot(diamonds) + geom_point(aes(x = price, y = cut)) + thm + theme(axis.title.y = element_blank())

Visualizing Distributions (5)

Several approaches are available to reduce the impact of over-plotting:

  • reduce the point size;

  • random displacement of points, called jittering;

  • making the points translucent, or alpha blending.

Combining all three for examining price within cut for the diamonds data produces

ggplot(diamonds) + geom_point(aes(x = price, y = cut), size = 0.2, position = position_jitter(width = 0), alpha = 0.2) + thm + theme(axis.title.y = element_blank())

Visualizing Distributions (6)

Skewness of the price distributions can be seen in this plot, though other approaches will show this more clearly.

A peculiar feature reveled by this plot is the gap below 2000.

Examining the subset with price < 2000 shows the gap is roughly symmetric around 1500:

ggplot(filter(diamonds, price < 2000)) + geom_point(aes(x = price, y = cut), size = 0.2, position = position_jitter(width = 0), alpha = 0.2) + thm + theme(axis.title.y = element_blank())

Visualizing Distributions (7)

A plot along these lines was used on the New York Times front page for February 21, 2021.

Visualizing Distributions (8)

Some Notes

  • With a good combination of point size choice, jittering, and alpha blending the strip plot for groups of data can scale to several hundred thousand observations and ten to twenty of groups.

  • For very large datat sets it can be useful to look at a strip plot of a sample of the data.

  • Strip plots can reveal gaps, outliers, and data outside of the expected range.

  • Skewness and multi-modality can be seen, but other visualizations show these more clearly.

  • Storage needed for vector graphics images grows linearly with the number of observations.

  • Base graphics provides stripchart and lattice provides stripplot.

Histograms

Histogram Basics

Historams are constructed by binning the data and counting the number of observations in each bin.

The objective is usually to visualize the shape of the distribution.

The number of bins needs to be

  • small enough to reveal interesting features;

  • large enough not to be too noisy.

A very small bin width can be used to look for rounding or heaping.

Common choices for the vertical scale are:

The count scale is more intepretable for lay viewers.

The density scale is more suited for comparison to mathematical density models.

Constructing histograms with unequal bin widths is possible but rarely a good idea.

Histograms in R

There are many ways to plot histograms in R:

  • the hist() function in the base graphics package;

  • truehist() in package MASS;

  • histogram() in package lattice;

  • geom_histogram() in package ggplot2.

A histogram of eruption durations for another data set on Old Faithful eruptions, this one from package MASS:

data(geyser, package = "MASS")ggplot(geyser) + geom_histogram(aes(x = duration)) + thm## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Visualizing Distributions (9)

The default settings using geom_histogram are less than ideal.

Using a binwidth of 0.5 and customized fill and color settings produces a better result:

ggplot(geyser) + geom_histogram(aes(x = duration), binwidth = 0.5, fill = "grey", color = "black") + thm

Visualizing Distributions (10)

Reducing the bin width shows an interesting feature:

ggplot(geyser) + geom_histogram(aes(x = duration), binwidth = 0.05, fill = "grey", color = "black") + thm

Visualizing Distributions (11)

  • Eruptions were sometimes classified as short or long; these were coded as 2 and 4 minutes.

  • For many purposes this kind of heaping or rounding does not matter.

  • It would matter if we wanted to estimate means and standard deviations of the durations of the long and short eruptions.

  • More data and information about geysers is available at https://geysertimes.org/.

  • For exploration there is no one “correct” bin width or number of bins.

  • It would be very useful to be able to change this parameter interactively.

Superimposing a Density

A histogram can be used to compare the data distribution to a theoretical model, such as a normal distribution.

This requires using a density scale for the vertical axis.

The Galton data frame in the HistData package is one of several data sets used by Galton to study the heights of parents and their children.

Adding a normal density curve to a ggplot histogram involves:

  • computing the parameters of the density;

  • creating the histogram with a density scale using the computed variable after_stat(density);

  • adding the function curve using geom_function, stat_function, or geom_line.

Create the histogram with a density scale using the computed varlable after_stat(density):

data(Galton, package = "HistData")ggplot(Galton) + geom_histogram(aes(x = parent, y = after_stat(density)), binwidth = 1, fill = "grey", color = "black") + thm

Visualizing Distributions (12)

Then compute the mean and standard deviation and add the normal density curve:

data(Galton, package = "HistData")p_mean <- mean(Galton$parent)p_sd <- sd(Galton$parent)p_dens <- function(x) dnorm(x, p_mean, p_sd)ggplot(Galton) + geom_histogram(aes(x = parent, y = after_stat(density)), binwidth = 1, fill = "grey", color = "black") + geom_function(fun = p_dens, color = "red") + thm

Visualizing Distributions (13)

Multiple Groups

Faceting works well for showing comparative histograms for multiple groups.

Histograms of price within cut for the diamonds data:

ggplot(diamonds) + geom_histogram(aes(x = price), binwidth = 1000, color = "black", fill = "grey") + facet_wrap(~ cut) + thm

Visualizing Distributions (14)

These histograms show counts on the vertical axis, and their sizes reflect the total counts for the groups.

Together the plots represent a view of the joint distribution of cut and price.

Switching to a density scale by using after_stat(density) for the y aesthetic allows the conditional distributions of price within groups to be compared:

p <- ggplot(diamonds) + geom_histogram(aes(x = price, y = after_stat(density)), binwidth = 1000, color = "black", fill = "grey") + thmp + facet_wrap(~ cut)

Visualizing Distributions (15)

By mapping the fill aesthetic to cut it is possible to produce a stacked histogram or a superimposed histogram

  • position = "stack", the default, for stacked;
  • position = "identity" for superimposed.

But neither works very well visually.

For comparing locations of features it can help to facet with a single column.

But this may create aspect ratios that are not ideal.

Visualizing Distributions (16)

Scalability

Histograms scale very well.

  • The visual performance does not deteriorate with increasing numbers of observations.

  • The computational effort needed is linear in the number of observations.

  • The amount of storage needed for an image object is linear in the number of bins.

Density Plots

Density Plot Basics

Density plots can be thought of as plots of smoothed histograms.

The smoothness is controlled by a bandwidth parameter that is analogous to the histogram binwidth.

Most density plots use a kernel density estimate, but there are other possible strategies; qualitatively the particular strategy rarely matters.

A density plot of the geyser duration variable with default bandwidth:

ggplot(geyser) + geom_density(aes(x = duration)) + thm

Visualizing Distributions (17)

Using a smaller bandwidth shows the heaping at 2 and 4 minutes:

ggplot(geyser) + geom_density(aes(x = duration), bw = 0.05) + thm

Visualizing Distributions (18)

For a moderate number of observations a useful addition is a jittered rug plot:

ggplot(geyser) + geom_density(aes(x = duration)) + geom_rug(aes(x = duration, y = 0), position = position_jitter(height = 0)) + thm

Visualizing Distributions (19)

Scalability

Visual scalability is very good.

For the diamonds data price variable:

ggplot(diamonds) + geom_density(aes(x = price)) + thm

Visualizing Distributions (20)

Density estimates are generally computed at a grid of points and interpolated.

Defaults in R vary from 50 to 512 points.

Computational effort for a density estimate at a point is proportional to the number of observations.

Storage needed for an image is proportional to the number of points where the density is estimated.

Multiple Groups

Density estimates for several groups can be shown in a single plot by mapping a group index to an aesthetic, such as color:

ggplot(barley) + geom_density(aes(x = yield, color = site)) + thm

Visualizing Distributions (21)

Using fill and alpha can also be useful:

ggplot(barley) + geom_density(aes(x = yield, fill = site), alpha = 0.2)

Visualizing Distributions (22)

Multiple densities in a single plot works best with a smaller number of categories, say 2 or 3:

ggplot(barley) + geom_density(aes(x = yield, fill = year), alpha = 0.4) + thm

Visualizing Distributions (23)

Using small multiples, or faceting, may be a better option:

ggplot(barley) + geom_density(aes(x = yield)) + facet_wrap(~ site) + thm

Visualizing Distributions (24)

These ideas can be combined:

ggplot(barley) + geom_density(aes(x = yield, color = year)) + facet_wrap(~ site) + thm

Visualizing Distributions (25)

These plots again show lower yields for 1932 than for 1931 for all sites except Morris.

Density plots default to using the density scale.

For the diamonds data a density plot of price faceted on cut shows the conditional distributions of price at the different cut levels:

ggplot(diamonds) + geom_density(aes(x = price)) + facet_wrap(~ cut) + thm

Visualizing Distributions (26)

Mapping the y aesthetic to after_stat(count) shows the joint distribution of price and cut:

ggplot(diamonds) + geom_density(aes(x = price, y = after_stat(count))) + facet_wrap(~ cut) + thm

Visualizing Distributions (27)

A stacked density plot is sometimes useful but often hard to read:

ggplot(diamonds) + geom_density(aes(x = price, y = after_stat(count), fill = cut), position = "stack") + thm

Visualizing Distributions (28)

An intermediate option: A faceted plot on the count scale with a muted plot for the full data to allow proportions of the whole to be assessed:

ggplot(diamonds) + geom_density(aes(x = price, y = after_stat(count)), fill = "lightgrey", color = NA, data = mutate(diamonds, cut = NULL)) + geom_density(aes(x = price, y = after_stat(count), fill = cut), position = "stack", color = NA) + facet_wrap(~ cut) + scale_fill_viridis_d(guide = "none") + thm

Visualizing Distributions (29)

A filled density plot provides a vew of the conditional distribution of cut at the different price levels:

ggplot(diamonds) + geom_density(aes(x = price, y = after_stat(count), fill = cut), position = "fill") + ylab(NULL) + thm

Visualizing Distributions (30)

This is called a CD plot, or a conditional density plot.

Some Notes

Computations are generally done with the base R function density.

plot has a method for the results returned by this function, so a density plot can be created with

plot(density(geyser$duration))

The lattice package provides the function densityplot.

Interactive Bandwidth Choice

Being able to chose the bandwidth of a density plot, or the binwidth of a histogram, interactively is useful for exploration.

One way to do this in R (which unfortunately does not work on the RStudio server):

data(geyser, package = "MASS")source("https://stat.uiowa.edu/~luke/classes/STAT7400/examples/tkdens.R")tkdens(geyser$duration, tkrplot = TRUE)

Another option:

data(geyser, package = "MASS")source("https://stat.uiowa.edu/~luke/classes/STAT7400/examples/shinydens.R")shinyDens(geyser$duration)

Boxplots

Boxplots, or box-and-whisker plots, provide a skeletal representation of a distribution.

They are very well suited for showing distributions for multiple groups.

There are many variations of boxplots:

  • Most start with a box from the first to the third quartiles and divided by the median.

  • The simplest form then adds a whisker from the lower quartile to the minimum and from the upper quartile to the maximum.

  • More common is to draw the upper whisker to the largest point below the upper quartile \(+ 1.5 * IQR\), and the lower whisker analogously.

  • Outliers falling outside the range of the whiskers are then drawn directly:

library(gapminder)library(ggplot2)ggplot(gapminder) + geom_boxplot(aes(x = continent, y = gdpPercap)) + xlab(NULL) + thm

Visualizing Distributions (31)

There are variants that distinguish between mild outliers and extreme outliers.

A common variant is to show an approximate 95% confidence interval for the population median as a notch:

ggplot(gapminder) + geom_boxplot(aes(x = continent, y = gdpPercap), notch = TRUE) + xlab(NULL) + thm

Visualizing Distributions (32)

Another variant is to use a width proportional to the square root of the sample size to reflect the strength of evidence in the data:

ggplot(gapminder) + geom_boxplot(aes(x = continent, y = gdpPercap), notch = TRUE, varwidth = TRUE) + xlab(NULL) + thm

Visualizing Distributions (33)

With moderate sample sizes it can be useful to super-impose the original data, perhaps with jittering and alpha blending.

The outliers in the box plot can be turned off with outlier.color = NA so they are not shown twice:

p <- ggplot(gapminder) + geom_boxplot(aes(x = continent, y = gdpPercap), notch = TRUE, varwidth = TRUE, outlier.color = NA) + xlab(NULL) + thmp + geom_point(aes(x = continent, y = gdpPercap), position = position_jitter(width = 0.1), alpha = 0.1)

Visualizing Distributions (34)

Violin Plots

A variant of the boxplot is the violin plot:

Hintze, J. L., Nelson, R. D. (1998), “Violin Plots: A Box Plot-Density Trace Synergism,” The American Statistician 52, 181-184.

The violin plot uses density estimates to show the distributions:

ggplot(gapminder) + geom_violin(aes(x = continent, y = gdpPercap)) + xlab(NULL) + thm

Visualizing Distributions (35)

By default the “violins” are scaled to have the same area.

They can also be scaled to have the same maximum height or to have areas proportional to sample sizes.

This is done by adding

  • scale = "width" or
  • scale = "count"

to the geom_violin call.

A comparison of boxplots and violin plots:

ggplot(gapminder) + geom_boxplot(aes(x = continent, y = gdpPercap)) + geom_violin(aes(x = continent, y = gdpPercap), fill = NA, scale = "width", linetype = 2) + xlab(NULL) + thm

Visualizing Distributions (36)

A combination of boxplots and violin plots:

ggplot(gapminder) + geom_violin(aes(x = continent, y = gdpPercap), scale = "width") + geom_boxplot(aes(x = continent, y = gdpPercap), width = .1) + xlab(NULL) + thm

Visualizing Distributions (37)

There are other variations, e.g.vase plots.

Boxplots do not reflect the shape of a distribution.

For the eruptions in the faithful data set:

ggplot(faithful) + geom_boxplot(aes(y = eruptions, x = "Box")) + geom_violin(aes(y = eruptions, x = "Violin"), trim = FALSE) + xlab(NULL) + thm

Visualizing Distributions (38)

Swarm Plots

Swarm plots show the full data in a form that also shows the density.

There are a number of variations and names, including beeswarm plots, violin scatterplots, violin strip charts, and sina plots

Sina plots are available as geom_sina in the ggforce package:

library(ggforce)ggplot(gapminder, aes(x = continent, y = gdpPercap)) + geom_sina(size = 0.2) + xlab(NULL) + thm

Visualizing Distributions (39)

Combined with a width-scaled violin plot:

ggplot(gapminder, aes(x = continent, y = gdpPercap)) + geom_violin(scale = "width") + geom_sina(color = "blue", size = 0.4, scale = FALSE) + xlab(NULL) + thm

Visualizing Distributions (40)

Effectiveness and Scalability

  • Boxplots are very simple and easy to compare.

  • Boxplots strongly emphasize the middle half of the data.

  • Boxplots may not be easy for a lay viewer to understand.

  • Box plots scale fairly well visually and computationally in the number of observations; over-plotting/storage of outliers becomes an issue for larger data sets

  • Violin plots scale well both visually and computationally in the number of observations.

library(patchwork)p1 <- ggplot(diamonds) + geom_boxplot(aes(x = cut, y = price)) + xlab(NULL) + thmp2 <- ggplot(diamonds) + geom_violin(aes(x = cut, y = price)) + xlab(NULL) + thmp1 + p2

Visualizing Distributions (41)

  • Scalability in the number of cases for swarm or sina plots is more limited.

  • The number of groups that can be handled for comparison by these plots is in the range of a few dozen.

library(lattice)p1 <- ggplot(barley) + geom_boxplot(aes(x = site, y = yield, fill = year)) + xlab(NULL) + thmp2 <- ggplot(barley) + geom_violin(aes(x = site, y = yield, fill = year)) + xlab(NULL) + thmp1 + p2

Visualizing Distributions (42)

Axes can be flipped to avoid overplotting of labels:

library(lattice)p3 <- p1 + coord_flip() + guides(fill = "none")p4 <- p2 + coord_flip()p3 + p4

Visualizing Distributions (43)

Faceting can also be used to arrange groups of boxplots or violin plots.

For life expectancy by continent over the years in the gapminder data:

library(dplyr)ggplot(filter(gapminder, year %% 10 == 2, continent != "Oceania")) + geom_boxplot(aes(x = lifeExp, y = factor(year))) + facet_wrap(~ continent, ncol = 1) + theme_minimal() + theme(text = element_text(size = 12)) + theme(strip.text.x = element_text(hjust = 0)) + ylab(NULL)

Visualizing Distributions (44)

A related visualization motivated by a graph in the Economist is available here.

Ridgeline Plots

Ridgeline plots, also called ridge plots or joy plots, are another way to show density estimates for a number of groups that has become popular recently.

An early example appears in this NYT article.

The package ggridges defines geom_density_ridges for creating these plots:

library(ggridges)ggplot(barley) + geom_density_ridges(aes(x = yield, y = site, group = site)) + ylab(NULL) + thm

Visualizing Distributions (45)

Grouping by an interaction with a categorical variable, year, produces separate density estimates for each level.

Mapping the fill aesthetic to year allows the separate densities to be identified:

ggplot(barley) + geom_density_ridges( aes(x = yield, y = site, group = interaction(year, site), fill = year)) + ylab(NULL) + thm

Visualizing Distributions (46)

Alpha blending may sometimes help:

ggplot(barley) + geom_density_ridges( aes(x = yield, y = site, group = interaction(year, site), fill = year), alpha = 0.8) + ylab(NULL) + thm

Visualizing Distributions (47)

Adjusting the vertical scale may also help:

ggplot(barley) + geom_density_ridges( aes(x = yield, y = site, group = interaction(year, site), fill = year), scale = 0.8) + ylab(NULL) + thm

Visualizing Distributions (48)

Sometimes reordering the grouping variable, year in this case, can help.

The factor levels of year can be reordered to match the order of average yealds within each year by

reorder(year, yield)

Using -yield produces the reverse order.

library(dplyr)ggplot(mutate(barley, year = reorder(year, -yield))) + geom_density_ridges(aes(x = yield, y = site, group = interaction(year, site), fill = year), scale = 0.8) + ylab(NULL) + thm

Visualizing Distributions (49)

With some tuning ridgeline plots can scale well to many distributions. An example from Claus Wilke’s book:

The ggplot2movies package provides data from IMDB on a large number of movies, including their lengths, in a tibble movies:

library(ggplot2movies)dim(movies)## [1] 58788 24head(movies)## # A tibble: 6 × 24## title year length budget rating votes r1 r2 r3 r4 r5 r6## <chr> <int> <int> <int> <dbl> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>## 1 $ 1971 121 NA 6.4 348 4.5 4.5 4.5 4.5 14.5 24.5## 2 $1000 a … 1939 71 NA 6 20 0 14.5 4.5 24.5 14.5 14.5## 3 $21 a Da… 1941 7 NA 8.2 5 0 0 0 0 0 24.5## 4 $40,000 1996 70 NA 8.2 6 14.5 0 0 0 0 0 ## 5 $50,000 … 1975 71 NA 3.4 17 24.5 4.5 0 14.5 14.5 4.5## 6 $pent 2000 91 NA 4.3 45 4.5 4.5 4.5 14.5 14.5 14.5## # ℹ 12 more variables: r7 <dbl>, r8 <dbl>, r9 <dbl>, r10 <dbl>, mpaa <chr>,## # Action <int>, Animation <int>, Comedy <int>, Drama <int>,## # Documentary <int>, Romance <int>, Short <int>

A ridgeline plot of the movie lengths for each year:

library(dplyr)mv12 <- filter(movies, year > 1912)ggplot(mv12, aes(x = length, y = year, group = year)) + geom_density_ridges(scale = 10, size = 0.25, rel_min_height = 0.03) + scale_x_continuous(limits = c(0, 200)) + scale_y_reverse(breaks = c(2000, 1980, 1960, 1940, 1920)) + theme_minimal()## Warning in geom_density_ridges(scale = 10, size = 0.25, rel_min_height = 0.03):## Ignoring unknown parameters: `size`## Warning: Removed 250 rows containing non-finite outside the scale range## (`stat_density_ridges()`).

Visualizing Distributions (50)

This shows that since the early 1960’s feature film lengths have stabilized to a distribution centered around 90 minutes:

Another nice example: DW-NOMINATE scores for measuring political position of members of congress over the years:

Visualizing Distributions (51)

Original code by Ian McDonald; another version is provided in Claus Wilke’s book.

Interactive Tutorial

An interactive learnr tutorial for these notes is available.

You can run the tutorial with

STAT4580::runTutorial("dists")

You can install the current version of the STAT4580 package with

remotes::install_gitlab("luke-tierney/STAT4580")

You may need to install the remotes package from CRAN first.

Exercises

  1. Consider the code
```rlibrary(ggplot2)data(Galton, package = "HistData")ggplot(Galton, aes(x = parent)) + geom_histogram(---, fill = "grey", color = "black")```
Which of the following replacements for `---` produces a histogramwith bins that are one inch wide and start at whole integers?a. `binwidth = 1`b. `binwidth = 1, center = 66.5`c. `binwidth = 2, center = 66`d. `center = 66`
  1. Consider the code

    library(ggplot2)ggplot(faithful, aes(x = eruptions)) + geom_density(---)

    Which of the following replacements for --- produces a density plot with the area under the density in blue and no black border?

    1. color = "lightblue"
    2. fill = "black", color = "lightblue"
    3. fill = "lightblue", color = NA
    4. fill = NA, color = "black"
  2. Consider the code

    library(ggplot2)library(gapminder)p <- ggplot(gapminder, aes(y = continent, x = lifeExp))

    Which of the following produces violin plots without trimming at the smallest and largest observations, and including a line at the median?

    1. p + geom_violin(trim = FALSE)
    2. p + geom_violin(trim = TRUE, show_median = TRUE)
    3. p + geom_violin(trim = FALSE, draw_quantiles = 0.5)
    4. p + geom_violin(trim = TRUE, show_quantiles = 0.5)
  3. Density ridges can also show quantiles, but the details of how to request this are different. Consider this code:

    library(ggplot2)library(ggridges)library(gapminder)ggplot(gapminder, aes(x = lifeExp, y = year, group = year)) + geom_density_ridges(---)

    Which of the following replacements for --- produces density ridges with lines showing the locations of the medians?

    1. quantiles = 0.5
    2. quantile_lines = TRUE, quantiles = 0.5
    3. quantile_lines = TRUE
    4. draw_quantiles = 0.5

LS0tCnRpdGxlOiAiVmlzdWFsaXppbmcgRGlzdHJpYnV0aW9ucyIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCi0tLQoKPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJzdGF0NDU4MC5jc3MiIHR5cGU9InRleHQvY3NzIiAvPgo8IS0tIHRpdGxlIGJhc2VkIG9uIFdpbGtlJ3MgY2hhcHRlciAtLT4KCmBgYHtyIHNldHVwLCBpbmNsdWRlID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRX0Kc291cmNlKGhlcmU6OmhlcmUoInNldHVwLlIiKSkKa25pdHI6Om9wdHNfY2h1bmskc2V0KGNvbGxhcHNlID0gVFJVRSwgbWVzc2FnZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgZmlnLmhlaWdodCA9IDUsIGZpZy53aWR0aCA9IDYsIGZpZy5hbGlnbiA9ICJjZW50ZXIiKQoKc2V0LnNlZWQoMTIzNDUpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShsYXR0aWNlKQpsaWJyYXJ5KGdyaWRFeHRyYSkKc291cmNlKGhlcmU6OmhlcmUoImRhdGFzZXRzLlIiKSkKYGBgCgoKIyMgSW50cm9kdWN0aW9uCgpPbmNlIHRoZXJlIGFyZSBtb3JlIHRoYW4gYSBoYW5kZnVsIG9mIG51bWVyaWMgZGF0YSB2YWx1ZXMgaXQgaXMgb2Z0ZW4KdXNlZnVsIHRvIHN0ZXAgYmFjayBhbmQgbG9vayBhdCB0aGUgX2Rpc3RyaWJ1dGlvbl8gb2YgdGhlIGRhdGEgdmFsdWVzOgoKKiBXaGVyZSBpcyB0aGUgYnVsayBvZiB0aGUgZGF0YSBsb2NhdGVkPwoKKiBJcyB0aGVyZSBhIHNpbmdsZSBhcmVhIG9mIGNvbmNlbnRyYXRpb24gb3IgYXJlIHRoZXJlIHNldmVyYWw/CgoqIElzIHRoZSBkYXRhIGRpc3RyaWJ1dGlvbiBzeW1tZXRyaWMgb3IgaXMgaXQgc2tld2VkLCBpLmUuIHRyYWlscyBvZmYKICBtb3JlIHNsb3dseSBpbiBvbmUgZGlyZWN0aW9uIG9yIGFub3RoZXI/CgoqIEFyZSB0aGVyZSBleHRyZW1lLCBvciBvdXRseWluZywgdmFsdWVzPwoKKiBBcmUgdGhlcmUgYW55IHN1c3BpY2lvdXMgb3IgaW1wb3NzaWJsZSB2YWx1ZXM/CgoqIEFyZSB0aGVyZSBnYXBzIGluIHRoZSBkYXRhPwoKKiBJcyB0aGVyZSByb3VuZGluZywgZS5nLiB0byBpbnRlZ2VyIHZhbHVlcywgb3IgX2hlYXBpbmdfLCBpLmUuIGEKICBmZXcgcGFydGljdWxhciB2YWx1ZXMgb2NjdXIgdmVyeSBmcmVxdWVudGx5PwoKUGxvdHMgZm9yIHZpc3VhbGl6aW5nIGRpc3RyaWJ1dGlvbnMgaW5jbHVkZQoKKiBTdHJpcCBwbG90cy4KCiogSGlzdG9ncmFtcy4KCiogRGVuc2l0eSBwbG90cy4KCiogQm94IHBsb3RzLgoKKiBWaW9saW4gcGxvdHMuCgoqIFN3YXJtIHBsb3RzLgoKKiBEZW5zaXR5IHJpZGdlcwoKCiMjIFN0cmlwIFBsb3RzCgoKIyMjIFN0cmlwIFBsb3QgQmFzaWNzCgpBIHZhcmlhbnQgb2YgdGhlIGRvdCBwbG90IGlzIGtub3duIGFzIGEgX3N0cmlwIHBsb3RfLgoKQSBzdHJpcCBwbG90IGZvciB0aGUgY2l0eSB0ZW1wZXJhdHVyZSBkYXRhIGlzCgpgYGB7ciwgZmlnLmhlaWdodCA9IDIsIHdhcm5pbmcgPSBGQUxTRSwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CnRobSA8LSB0aGVtZV9taW5pbWFsKCkgKwogICAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpKQpnZ3Bsb3QoY2l0eXRlbXBzKSArCiAgICBnZW9tX3BvaW50KGFlcyh4ID0gdGVtcCwgeSA9ICJBbGwiKSkgKwogICAgdGhtICsKICAgIHRoZW1lKGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpKQpgYGAKClRoZSBzdHJpcCBwbG90IGNhbiByZXZlYWwgZ2FwcyBhbmQgb3V0bGllcnMuCgpBZnRlciBsb29raW5nIGF0IHRoZSBwbG90IHdlIG1pZ2h0IHdhbnQgdG8gZXhhbWluZSB0aGUgaGlnaCBhbmQKbG93IHZhbHVlczoKCmBgYHtyfQpmaWx0ZXIoY2l0eXRlbXBzLCB0ZW1wID4gODUpCmZpbHRlcihjaXR5dGVtcHMsIHRlbXAgPCAxMCkKYGBgCgpGb3IgdGhlIGVydXB0aW9uIGR1cmF0aW9ucyBpbiB0aGUgYGZhaXRoZnVsYCBkYXRhIGEgc3RyaXAgcGxvdCBzaG93cwp0aGUgdHdvIG1vZGVzIGFyb3VuZCAyIGFuZCA0IG1pbnV0ZXM6CgpgYGB7ciwgZmlnLmhlaWdodCA9IDIsIHdhcm5pbmcgPSBGQUxTRSwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmdncGxvdChmYWl0aGZ1bCkgKwogICAgZ2VvbV9wb2ludChhZXMoeCA9IGVydXB0aW9ucywgeSA9ICJBbGwiKSkgKwogICAgdGhtICsKICAgIHRoZW1lKGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCgojIyMgTXVsdGlwbGUgR3JvdXBzCgpTdHJpcCAgcGxvdHMgYXJlIG1vc3QgdXNlZnVsIGZvciBzaG93aW5nIHN1YnNldHMgY29ycmVzcG9uZGluZyB0byBhCmNhdGVnb3JpY2FsIHZhcmlhYmxlLgoKQSBzdHJpcCBwbG90IGZvciB0aGUgeWllbGRzIGZvciBkaWZmZXJlbnQgdmFyaWV0aWVzIGluIHRoZSBiYXJsZXkgZGF0YQppcwoKYGBge3IsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpnZ3Bsb3QoYmFybGV5KSArCiAgICBnZW9tX3BvaW50KGFlcyh4ID0geWllbGQsIHkgPSB2YXJpZXR5KSkgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIHRobQpgYGAKCgojIyMgU2NhbGFiaWxpdHkKClNjYWxhYmlsaXR5IGluIHRoaXMgZm9ybSBpcyBsaW1pdGVkIGR1ZSB0byBvdmVyLXBsb3R0aW5nLgoKQSBzaW1wbGUgc3RyaXAgcGxvdCBvZiBgcHJpY2VgIHdpdGhpbiB0aGUgZGlmZmVyZW50IGBjdXRgIGxldmVscyBpbgp0aGUgYGRpYW1vbmRzYCBkYXRhIGlzIG5vdCB2ZXJ5IGhlbHBmdWw6CgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmdncGxvdChkaWFtb25kcykgKwogICAgZ2VvbV9wb2ludChhZXMoeCA9IHByaWNlLCB5ID0gY3V0KSkgKwogICAgdGhtICsKICAgIHRoZW1lKGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgpTZXZlcmFsIGFwcHJvYWNoZXMgYXJlIGF2YWlsYWJsZSB0byByZWR1Y2UgdGhlIGltcGFjdCBvZiBvdmVyLXBsb3R0aW5nOgoKKiByZWR1Y2UgdGhlIHBvaW50IHNpemU7CgoqIHJhbmRvbSBkaXNwbGFjZW1lbnQgb2YgcG9pbnRzLCBjYWxsZWQgX2ppdHRlcmluZ187CgoqIG1ha2luZyB0aGUgcG9pbnRzIHRyYW5zbHVjZW50LCBvciBfYWxwaGEgYmxlbmRpbmdfLgoKQ29tYmluaW5nIGFsbCB0aHJlZSBmb3IgZXhhbWluaW5nIGBwcmljZWAgd2l0aGluIGBjdXRgIGZvciB0aGUKYGRpYW1vbmRzYCBkYXRhIHByb2R1Y2VzCgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmdncGxvdChkaWFtb25kcykgKwogICAgZ2VvbV9wb2ludChhZXMoeCA9IHByaWNlLCB5ID0gY3V0KSwKICAgICAgICAgICAgICAgc2l6ZSA9IDAuMiwKICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIod2lkdGggPSAwKSwKICAgICAgICAgICAgICAgYWxwaGEgPSAwLjIpICsKICAgIHRobSArIHRoZW1lKGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgpTa2V3bmVzcyBvZiB0aGUgcHJpY2UgZGlzdHJpYnV0aW9ucyBjYW4gYmUgc2VlbiBpbiB0aGlzIHBsb3QsIHRob3VnaApvdGhlciBhcHByb2FjaGVzIHdpbGwgc2hvdyB0aGlzIG1vcmUgY2xlYXJseS4KCkEgcGVjdWxpYXIgZmVhdHVyZSByZXZlbGVkIGJ5IHRoaXMgcGxvdCBpcyB0aGUgZ2FwIGJlbG93CjIwMDAuCgpFeGFtaW5pbmcgdGhlIHN1YnNldCB3aXRoIGBwcmljZSA8IDIwMDBgIHNob3dzIHRoZSBnYXAgaXMKcm91Z2hseSBzeW1tZXRyaWMgYXJvdW5kIDE1MDA6CgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmdncGxvdChmaWx0ZXIoZGlhbW9uZHMsIHByaWNlIDwgMjAwMCkpICsKICAgIGdlb21fcG9pbnQoYWVzKHggPSBwcmljZSwgeSA9IGN1dCksCiAgICAgICAgICAgICAgIHNpemUgPSAwLjIsCiAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyKHdpZHRoID0gMCksCiAgICAgICAgICAgICAgIGFscGhhID0gMC4yKSArCiAgICB0aG0gKwogICAgdGhlbWUoYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCkEgcGxvdCBhbG9uZyB0aGVzZSBsaW5lcyB3YXMgdXNlZCBvbiB0aGUgTmV3IFlvcmsgVGltZXMgW2Zyb250IHBhZ2UgZm9yCkZlYnJ1YXJ5IDIxLCAyMDIxXShgciBJTUcoIk5ZVC0yMDIxLTAyLTIxLmpwZWciKWApLgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoID0gIjU1JSJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKElNRygiTllULTIwMjEtMDItMjEuanBlZyIpKQpgYGAKCgojIyMgU29tZSBOb3RlcwoKKiBXaXRoIGEgZ29vZCBjb21iaW5hdGlvbiBvZiBwb2ludCBzaXplIGNob2ljZSwgaml0dGVyaW5nLCBhbmQgYWxwaGEKICBibGVuZGluZyB0aGUgc3RyaXAgcGxvdCBmb3IgZ3JvdXBzIG9mIGRhdGEgY2FuIHNjYWxlIHRvIHNldmVyYWwKICBodW5kcmVkIHRob3VzYW5kIG9ic2VydmF0aW9ucyBhbmQgdGVuIHRvIHR3ZW50eSBvZiBncm91cHMuCgoqIEZvciB2ZXJ5IGxhcmdlIGRhdGF0IHNldHMgaXQgY2FuIGJlIHVzZWZ1bCB0byBsb29rIGF0IGEgc3RyaXAgcGxvdAogIG9mIGEgc2FtcGxlIG9mIHRoZSBkYXRhLgoKKiBTdHJpcCBwbG90cyBjYW4gcmV2ZWFsIGdhcHMsIG91dGxpZXJzLCBhbmQgZGF0YSBvdXRzaWRlIG9mIHRoZQogIGV4cGVjdGVkIHJhbmdlLgoKKiBTa2V3bmVzcyBhbmQgbXVsdGktbW9kYWxpdHkgY2FuIGJlIHNlZW4sIGJ1dCBvdGhlciB2aXN1YWxpemF0aW9ucwogIHNob3cgdGhlc2UgbW9yZSBjbGVhcmx5LgoKKiBTdG9yYWdlIG5lZWRlZCBmb3IgdmVjdG9yIGdyYXBoaWNzIGltYWdlcyBncm93cyBsaW5lYXJseSB3aXRoIHRoZQogIG51bWJlciBvZiBvYnNlcnZhdGlvbnMuCgoqIEJhc2UgZ3JhcGhpY3MgcHJvdmlkZXMgYHN0cmlwY2hhcnRgIGFuZCBsYXR0aWNlIHByb3ZpZGVzIGBzdHJpcHBsb3RgLgoKCiMjIEhpc3RvZ3JhbXMKCgojIyMgSGlzdG9ncmFtIEJhc2ljcwoKSGlzdG9yYW1zIGFyZSBjb25zdHJ1Y3RlZCBieSBiaW5uaW5nIHRoZSBkYXRhIGFuZCBjb3VudGluZyB0aGUgbnVtYmVyCm9mIG9ic2VydmF0aW9ucyBpbiBlYWNoIGJpbi4KClRoZSBvYmplY3RpdmUgaXMgdXN1YWxseSB0byB2aXN1YWxpemUgdGhlIHNoYXBlIG9mIHRoZSBkaXN0cmlidXRpb24uCgpUaGUgbnVtYmVyIG9mIGJpbnMgbmVlZHMgdG8gYmUKCiogc21hbGwgZW5vdWdoIHRvIHJldmVhbCBpbnRlcmVzdGluZyBmZWF0dXJlczsKCiogbGFyZ2UgZW5vdWdoIG5vdCB0byBiZSB0b28gbm9pc3kuCgpBIHZlcnkgc21hbGwgYmluIHdpZHRoIGNhbiBiZSB1c2VkIHRvIGxvb2sgZm9yIHJvdW5kaW5nIG9yIGhlYXBpbmcuCgpDb21tb24gY2hvaWNlcyBmb3IgdGhlIHZlcnRpY2FsIHNjYWxlIGFyZToKCiogYmluIGNvdW50cywgb3IgZnJlcXVlbmNpZXM7CgoqIGNvdW50cyBwZXIgdW5pdCwgb3IgZGVuc2l0aWVzLgoKVGhlIGNvdW50IHNjYWxlIGlzIG1vcmUgaW50ZXByZXRhYmxlIGZvciBsYXkgdmlld2Vycy4KClRoZSBkZW5zaXR5IHNjYWxlIGlzIG1vcmUgc3VpdGVkIGZvciBjb21wYXJpc29uIHRvIG1hdGhlbWF0aWNhbApkZW5zaXR5IG1vZGVscy4KCkNvbnN0cnVjdGluZyBoaXN0b2dyYW1zIHdpdGggdW5lcXVhbCBiaW4gd2lkdGhzIGlzIHBvc3NpYmxlIGJ1dApyYXJlbHkgYSBnb29kIGlkZWEuCgoKIyMjIEhpc3RvZ3JhbXMgaW4gUgoKVGhlcmUgYXJlIG1hbnkgd2F5cyB0byBwbG90IGhpc3RvZ3JhbXMgaW4gUjoKCiogdGhlIGBoaXN0KClgIGZ1bmN0aW9uIGluIHRoZSBiYXNlIGBncmFwaGljc2AgcGFja2FnZTsKCiogYHRydWVoaXN0KClgIGluIHBhY2thZ2UgYE1BU1NgOwoKKiBgaGlzdG9ncmFtKClgIGluIHBhY2thZ2UgYGxhdHRpY2VgOwoKKiBgZ2VvbV9oaXN0b2dyYW0oKWAgaW4gcGFja2FnZSBgZ2dwbG90MmAuCgpBIGhpc3RvZ3JhbSBvZiBlcnVwdGlvbiBkdXJhdGlvbnMgZm9yIGFub3RoZXIgZGF0YSBzZXQgb24gT2xkIEZhaXRoZnVsCmVydXB0aW9ucywgdGhpcyBvbmUgZnJvbSBwYWNrYWdlIGBNQVNTYDoKCmBgYHtyLCBtZXNzYWdlID0gVFJVRSwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmRhdGEoZ2V5c2VyLCBwYWNrYWdlID0gIk1BU1MiKQpnZ3Bsb3QoZ2V5c2VyKSArCiAgICBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IGR1cmF0aW9uKSkgKwogICAgdGhtCmBgYAoKVGhlIGRlZmF1bHQgc2V0dGluZ3MgdXNpbmcgYGdlb21fa*glzdG9ncmFtYCBhcmUgbGVzcyB0aGFuIGlkZWFsLgoKVXNpbmcgYSBiaW53aWR0aCBvZiAwLjUgYW5kIGN1c3RvbWl6ZWQgYGZpbGxgIGFuZCBgY29sb3JgIHNldHRpbmdzCnByb2R1Y2VzIGEgYmV0dGVyIHJlc3VsdDoKCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KZ2dwbG90KGdleXNlcikgKwogICAgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBkdXJhdGlvbiksCiAgICAgICAgICAgICAgICAgICBiaW53aWR0aCA9IDAuNSwKICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiZ3JleSIsCiAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpICsKICAgIHRobQpgYGAKClJlZHVjaW5nIHRoZSBiaW4gd2lkdGggc2hvd3MgYW4gaW50ZXJlc3RpbmcgZmVhdHVyZToKCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KZ2dwbG90KGdleXNlcikgKwogICAgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBkdXJhdGlvbiksCiAgICAgICAgICAgICAgICAgICBiaW53aWR0aCA9IDAuMDUsCiAgICAgICAgICAgICAgICAgICBmaWxsID0gImdyZXkiLAogICAgICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siKSArCiAgICB0aG0KYGBgCgoqIEVydXB0aW9ucyB3ZXJlIHNvbWV0aW1lcyBjbGFzc2lmaWVkIGFzIF9zaG9ydF8gb3IgX2xvbmdfOyB0aGVzZSB3ZXJlCiAgY29kZWQgYXMgMiBhbmQgNCBtaW51dGVzLgoKKiBGb3IgbWFueSBwdXJwb3NlcyB0aGlzIGtpbmQgb2YgaGVhcGluZyBvciByb3VuZGluZyBkb2VzIG5vdCBtYXR0ZXIuCgoqIEl0IHdvdWxkIG1hdHRlciBpZiB3ZSB3YW50ZWQgdG8gZXN0aW1hdGUgbWVhbnMgYW5kIHN0YW5kYXJkCiAgZGV2aWF0aW9ucyBvZiB0aGUgZHVyYXRpb25zIG9mIHRoZSBsb25nIGFuZCBzaG9ydCBlcnVwdGlvbnMuCgoqIE1vcmUgZGF0YSBhbmQgaW5mb3JtYXRpb24gYWJvdXQgZ2V5c2VycyBpcyBhdmFpbGFibGUgYXQKICBodHRwczovL2dleXNlcnRpbWVzLm9yZy8uCiAgPCEtLSBUSGlzIHNlZW1zIG5vIGxvbmdlciBtYWludGFpbmVkOgogIGh0dHA6Ly93d3cuZ2V5c2Vyc3R1ZHkub3JnL2dleXNlci5hc3B4P3BHZXlzZXJObz1PTERGQUlUSEZVTC4gLS0+CgoqIEZvciBleHBsb3JhdGlvbiB0aGVyZSBpcyBubyBvbmUgImNvcnJlY3QiIGJpbiB3aWR0aCBvciBudW1iZXIgb2YKICBiaW5zLgoKKiBJdCB3b3VsZCBiZSB2ZXJ5IHVzZWZ1bCB0byBiZSBhYmxlIHRvIGNoYW5nZSB0aGlzIHBhcmFtZXRlcgogIGludGVyYWN0aXZlbHkuCgoKIyMjIFN1cGVyaW1wb3NpbmcgYSBEZW5zaXR5CgpBIGhpc3RvZ3JhbSBjYW4gYmUgdXNlZCB0byBjb21wYXJlIHRoZSBkYXRhIGRpc3RyaWJ1dGlvbiB0byBhCnRoZW9yZXRpY2FsIG1vZGVsLCBzdWNoIGFzIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbi4KClRoaXMgcmVxdWlyZXMgdXNpbmcgYSBfZGVuc2l0eSBzY2FsZV8gZm9yIHRoZSB2ZXJ0aWNhbCBheGlzLgoKVGhlIGBHYWx0b25gIGRhdGEgZnJhbWUgaW4gdGhlIGBIaXN0RGF0YWAgcGFja2FnZSBpcyBvbmUgb2Ygc2V2ZXJhbApkYXRhIHNldHMgdXNlZCBieSBHYWx0b24gdG8gc3R1ZHkgdGhlIGhlaWdodHMgb2YgcGFyZW50cyBhbmQgdGhlaXIKY2hpbGRyZW4uCgpBZGRpbmcgYSBub3JtYWwgZGVuc2l0eSBjdXJ2ZSB0byBhIGBnZ3Bsb3RgIGhpc3RvZ3JhbSBpbnZvbHZlczoKCiogY29tcHV0aW5nIHRoZSBwYXJhbWV0ZXJzIG9mIHRoZSBkZW5zaXR5OwoKKiBjcmVhdGluZyB0aGUgaGlzdG9ncmFtIHdpdGggYSBkZW5zaXR5IHNjYWxlIHVzaW5nIHRoZSBjb21wdXRlZAogIHZhcmlhYmxlIGBhZnRlcl9zdGF0KGRlbnNpdHkpYDsKCiogYWRkaW5nIHRoZSBmdW5jdGlvbiBjdXJ2ZSB1c2luZyBgZ2VvbV9mdW5jdGlvbmAsIGBzdGF0X2Z1bmN0aW9uYCwgb3IKICBgZ2VvbV9saW5lYC4KCkNyZWF0ZSB0aGUgaGlzdG9ncmFtIHdpdGggYSBkZW5zaXR5IHNjYWxlIHVzaW5nIHRoZSBfY29tcHV0ZWQgdmFybGFibGVfCmBhZnRlcl9zdGF0KGRlbnNpdHkpYDoKCjwhLS0gaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8yNTA3NTQyOC9nZ3Bsb3QyLXN0YXQtZnVuY3Rpb24td2l0aC1jYWxjdWxhdGVkLWFyZ3VtZW50LWZvci1kaWZmZXJlbnQtZGF0YS1zdWJzZXQtaW5zaWRlIC0tPgoKYGBge3IgZ2FsdG9uLWhpc3QsIGV2YWwgPSBGQUxTRX0KZGF0YShHYWx0b24sIHBhY2thZ2UgPSAiSGlzdERhdGEiKQpnZ3Bsb3QoR2FsdG9uKSArCiAgICBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IHBhcmVudCwKICAgICAgICAgICAgICAgICAgICAgICB5ID0gYWZ0ZXJfc3RhdChkZW5zaXR5KSksCiAgICAgICAgICAgICAgICAgICBiaW53aWR0aCA9IDEsCiAgICAgICAgICAgICAgICAgICBmaWxsID0gImdyZXkiLAogICAgICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siKSArCiAgICB0aG0KYGBgCgpgYGB7ciBnYWx0b24taGlzdCwgZWNobyA9IEZBTFNFfQpgYGAKClRoZW4gY29tcHV0ZSB0aGUgbWVhbiBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uIGFuZCBhZGQgdGhlIG5vcm1hbApkZW5zaXR5IGN1cnZlOgoKYGBge3IgZ2FsdG9uLWhpc3QtZGVucywgZXZhbCA9IEZBTFNFfQpkYXRhKEdhbHRvbiwgcGFja2FnZSA9ICJIaXN0RGF0YSIpCnBfbWVhbiA8LSBtZWf*ckEdhbHRvbiRwYXJlbnQpCnBfc2QgPC0gc2QoR2FsdG9uJHBhcmVudCkKcF9kZW5zIDwtIGZ1bmN0aW9uKHgpIGRub3JtKHgsIHBfbWVhbiwgcF9zZCkKZ2dwbG90KEdhbHRvbikgKwogICAgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBwYXJlbnQsCiAgICAgICAgICAgICAgICAgICAgICAgeSA9IGFmdGVyX3N0YXQoZGVuc2l0eSkpLAogICAgICAgICAgICAgICAgICAgYmlud2lkdGggPSAxLAogICAgICAgICAgICAgICAgICAgZmlsbCA9ICJncmV5IiwKICAgICAgICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIikgKwogICAgZ2VvbV9mdW5jdGlvbihmdW4gPSBwX2RlbnMsIGNvbG9yID0gInJlZCIpICsKICAgIHRobQpgYGAKCmBgYHtyIGdhbHRvbi1oaXN0LWRlbnMsIGVjaG8gPSBGQUxTRX0KYGBgCgoKIyMjIE11bHRpcGxlIEdyb3VwcwoKRmFjZXRpbmcgd29ya3Mgd2VsbCBmb3Igc2hvd2luZyBjb21wYXJhdGl2ZSBoaXN0b2dyYW1zIGZvciBtdWx0aXBsZQpncm91cHMuCgpIaXN0b2dyYW1zIG9mIGBwcmljZWAgd2l0aGluIGBjdXRgIGZvciB0aGUgYGRpYW1vbmRzYCBkYXRhOgoKYGBge3IsIGZpZy53aWR0aCA9IDgsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpnZ3Bsb3QoZGlhbW9uZHMpICsKICAgIGdlb21fa*glzdG9ncmFtKGFlcyh4ID0gcHJpY2UpLAogICAgICAgICAgICAgICAgICAgYmlud2lkdGggPSAxMDAwLAogICAgICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBmaWxsID0gImdyZXkiKSArCiAgICBmYWNldF93cmFwKH4gY3V0KSArCiAgICB0aG0KYGBgCgpUaGVzZSBoaXN0b2dyYW1zIHNob3cgY291bnRzIG9uIHRoZSB2ZXJ0aWNhbCBheGlzLCBhbmQgdGhlaXIgc2l6ZXMKcmVmbGVjdCB0aGUgdG90YWwgY291bnRzIGZvciB0aGUgZ3JvdXBzLgoKVG9nZXRoZXIgdGhlIHBsb3RzIHJlcHJlc2VudCBhIHZpZXcgb2YgdGhlIGpvaW50IGRpc3RyaWJ1dGlvbiBvZiBgY3V0YAphbmQgYHByaWNlYC4KClN3aXRjaGluZyB0byBhIGRlbnNpdHkgc2NhbGUgYnkgdXNpbmcgYGFmdGVyX3N0YXQoZGVuc2l0eSlgIGZvciB0aGUgYHlgCmFlc3RoZXRpYyBhbGxvd3MgdGhlIGNvbmRpdGlvbmFsIGRpc3RyaWJ1dGlvbnMgb2YgYHByaWNlYCB3aXRoaW4KZ3JvdXBzIHRvIGJlIGNvbXBhcmVkOgoKYGBge3IsIGZpZy53aWR0aCA9IDgsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpwIDwtIGdncGxvdChkaWFtb25kcykgKwogICAgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBwcmljZSwKICAgICAgICAgICAgICAgICAgICAgICB5ID0gYWZ0ZXJfc3RhdChkZW5zaXR5KSksCiAgICAgICAgICAgICAgICAgICBiaW53aWR0aCA9IDEwMDAsCiAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICAgICAgICBmaWxsID0gImdyZXkiKSArCiAgICB0aG0KcCArIGZhY2V0X3dyYXAofiBjdXQpCmBgYAoKQnkgbWFwcGluZyB0aGUgYGZpbGxgIGFlc3RoZXRpYyB0byBgY3V0YCBpdCBpcyBwb3NzaWJsZSB0byBwcm9kdWNlIGEKc3RhY2tlZCBoaXN0b2dyYW0gb3IgYSBzdXBlcmltcG9zZWQgaGlzdG9ncmFtCgoqIGBwb3NpdGlvbiA9ICJzdGFjayJgLCB0aGUgZGVmYXVsdCwgZm9yIHN0YWNrZWQ7CiogYHBvc2l0aW9uID0gImlkZW50aXR5ImAgZm9yIHN1cGVyaW1wb3NlZC4KCkJ1dCBuZWl0aGVyIHdvcmtzIHZlcnkgd2VsbCB2aXN1YWxseS4KCkZvciBjb21wYXJpbmcgbG9jYXRpb25zIG9mIGZlYXR1cmVzIGl0IGNhbiBoZWxwIHRvIGZhY2V0IHdpdGggYSBzaW5nbGUKY29sdW1uLgoKQnV0IHRoaXMgbWF5IGNyZWF0ZSBhc3BlY3QgcmF0aW9zIHRoYXQgYXJlIG5vdCBpZGVhbC4KCmBgYHtyIGhpc3QtZmFjZXQtb25lLWNvbCwgZWNobyA9IEZBTFNFLCBmaWcuaGVpZ2h0ID0gN30KcCArIGZhY2V0X3dyYXAofiBjdXQsIG5jb2wgPSAxKSArCiAgICBjb29yZF9maXhlZCgxLjUgKiAxZTcpCmBgYAoKCiMjIyBTY2FsYWJpbGl0eQoKSGlzdG9ncmFtcyBzY2FsZSB2ZXJ5IHdlbGwuCgoqIFRoZSB2aXN1YWwgcGVyZm9ybWFuY2UgZG9lcyBub3QgZGV0ZXJpb3JhdGUgd2l0aCBpbmNyZWFzaW5nIG51bWJlcnMKICBvZiBvYnNlcnZhdGlvbnMuCgoqIFRoZSBjb21wdXRhdGlvbmFsIGVmZm9ydCBuZWVkZWQgaXMgbGluZWFyIGluIHRoZSBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zLgoKKiBUaGUgYW1vdW50IG9mIHN0b3JhZ2UgbmVlZGVkIGZvciBhbiBpbWFnZSBvYmplY3QgaXMgbGluZWFyIGluIHRoZQogIG51bWJlciBvZiBiaW5zLgoKCiMjIERlbnNpdHkgUGxvdHMKCgojIyMgRGVuc2l0eSBQbG90IEJhc2ljcwoKRGVuc2l0eSBwbG90cyBjYW4gYmUgdGhvdWdodCBvZiBhcyBwbG90cyBvZiBzbW9vdGhlZCBoaXN0b2dyYW1zLgoKVGhlIHNtb290aG5lc3MgaXMgY29udHJvbGxlZCBieSBhIF9iYW5kd2lkdGhfIHBhcmFtZXRlciB0aGF0IGlzCmFuYWxvZ291cyB0byB0aGUgaGlzdG9ncmFtIGJpbndpZHRoLgoKTW9zdCBkZW5zaXR5IHBsb3RzIHVzZSBhIFtfa2VybmVsIGRlbnNpdHkKZXN0aW1hdGVfXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9LZXJuZWxfZGVuc2l0eV9lc3RpbWF0aW9uKSwKYnV0IHRoZXJlIGFyZSBvdGhlciBwb3NzaWJsZSBzdHJhdGVnaWVzOyBxdWFsaXRhdGl2ZWx5IHRoZSBwYXJ0aWN1bGFyCnN0cmF0ZWd5IHJhcmVseSBtYXR0ZXJzLgoKQSBkZW5zaXR5IHBsb3Qgb2YgdGhlIGBnZXlzZXJgIGBkdXJhdGlvbmAgdmFyaWFibGUgd2l0aCBkZWZhdWx0CmJhbmR3aWR0aDoKCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KZ2dwbG90KGdleXNlcikgKwogICAgZ2VvbV9kZW5zaXR5KGFlcyh4ID0gZHVyYXRpb24pKSArCiAgICB0aG0KYGBgCgpVc2luZyBhIHNtYWxsZXIgYmFuZHdpZHRoIHNob3dzIHRoZSBoZWFwaW5nIGF0IDIgYW5kIDQgbWludXRlczoKCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KZ2dwbG90KGdleXNlcikgKwogICAgZ2VvbV9kZW5zaXR5KGFlcyh4ID0gZHVyYXRpb24pLCBidyA9IDAuMDUpICsKICAgIHRobQpgYGAKCkZvciBhIG1vZGVyYXRlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgYSB1c2VmdWwgYWRkaXRpb24gaXMgYSBqaXR0ZXJlZApfcnVnIHBsb3RfOgoKYGBge3IsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpnZ3Bsb3QoZ2V5c2VyKSArCiAgICBnZW9tX2RlbnNpdHkoYWVzKHggPSBkdXJhdGlvbikpICsKICAgIGdlb21fcnVnKGFlcyh4ID0gZHVyYXRpb24sIHkgPSAwKSwKICAgICAgICAgICAgIHBvc2l0aW9uID0KICAgICAgICAgICAgICAgICBwb3NpdGlvbl9qaXR0ZXIoaGVpZ2h0ID0gMCkpICsKICAgIHRobQpgYGAKCgojIyMgU2NhbGFiaWxpdHkKClZpc3VhbCBzY2FsYWJpbGl0eSBpcyB2ZXJ5IGdvb2QuCgpGb3IgdGhlIGBkaWFtb25kc2AgZGF0YSBgcHJpY2VgIHZhcmlhYmxlOgoKYGBge3IsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpnZ3Bsb3QoZGlhbW9uZHMpICsKICAgIGdlb21fZGVuc2l0eShhZXMoeCA9IHByaWNlKSkgKwogICAgdGhtCmBgYAoKRGVuc2l0eSBlc3RpbWF0ZXMgYXJlIGdlbmVyYWxseSBjb21wdXRlZCBhdCBhIGdyaWQgb2YgcG9pbnRzIGFuZAppbnRlcnBvbGF0ZWQuCgpEZWZhdWx0cyBpbiBSIHZhcnkgZnJvbSA1MCB0byA1MTIgcG9pbnRzLgoKQ29tcHV0YXRpb25hbCBlZmZvcnQgZm9yIGEgZGVuc2l0eSBlc3RpbWF0ZSBhdCBhIHBvaW50IGlzIHByb3BvcnRpb25hbAp0byB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucy4KClN0b3JhZ2UgbmVlZGVkIGZvciBhbiBpbWFnZSBpcyBwcm9wb3J0aW9uYWwgdG8gdGhlIG51bWJlciBvZiBwb2ludHMKd2hlcmUgdGhlIGRlbnNpdHkgaXMgZXN0aW1hdGVkLgoKCiMjIyBNdWx0aXBsZSBHcm91cHMKCkRlbnNpdHkgZXN0aW1hdGVzIGZvciBzZXZlcmFsIGdyb3VwcyBjYW4gYmUgc2hvd24gaW4gYSBzaW5nbGUgcGxvdCBieQptYXBwaW5nIGEgZ3JvdXAgaW5kZXggdG8gYW4gYWVzdGhldGljLCBzdWNoIGFzIGBjb2xvcmA6CgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmdncGxvdChiYXJsZXkpICsKICAgIGdlb21fZGVuc2l0eShhZXMoeCA9IHlpZWxkLAogICAgICAgICAgICAgICAgICAgICBjb2xvciA9IHNpdGUpKSArCiAgICB0aG0KYGBgCgpVc2luZyBgZmlsbGAgYW5kIGBhbHBoYWAgY2FuIGFsc28gYmUgdXNlZnVsOgoKYGBge3IsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpnZ3Bsb3QoYmFybGV5KSArCiAgICBnZW9tX2RlbnNpdHkoYWVzKHggPSB5aWVsZCwKICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IHNpdGUpLAogICAgICAgICAgICAgICAgIGFscGhhID0gMC4yKQpgYGAKCk11bHRpcGxlIGRlbnNpdGllcyBpbiBhIHNpbmdsZSBwbG90IHdvcmtzIGJlc3Qgd2l0aCBhIHNtYWxsZXIgbnVtYmVyIG9mCmNhdGVnb3JpZXMsIHNheSAyIG9yIDM6CgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmdncGxvdChiYXJsZXkpICsKICAgIGdlb21fZGVuc2l0eShhZXMoeCA9IHlpZWxkLAogICAgICAgICAgICAgICAgICAgICBmaWxsID0geWVhciksCiAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjQpICsKICAgIHRobQpgYGAKClVzaW5nIHNtYWxsIG11bHRpcGxlcywgb3IgZmFjZXRpbmcsIG1heSBiZSBhIGJldHRlciBvcHRpb246CgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmdncGxvdChiYXJsZXkpICsgZ2VvbV9kZW5zaXR5KGFlcyh4ID0geWllbGQpKSArIGZhY2V0X3dyYXAofiBzaXRlKSArIHRobQpgYGAKClRoZXNlIGlkZWFzIGNhbiBiZSBjb21iaW5lZDoKCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KZ2dwbG90KGJhcmxleSkgKwogICAgZ2VvbV9kZW5zaXR5KGFlcyh4ID0geWllbGQsIGNvbG9yID0geWVhcikpICsKICAgIGZhY2V0X3dyYXAofiBzaXRlKSArCiAgICB0aG0KYGBgCgpUaGVzZSBwbG90cyBhZ2FpbiBzaG93IGxvd2VyIHlpZWxkcyBmb3IgMTkzMiB0aGFuIGZvciAxOTMxIGZvciBhbGwKc2l0ZXMgZXhjZXB0IE1vcnJpcy4KCkRlbnNpdHkgcGxvdHMgZGVmYXVsdCB0byB1c2luZyB0aGUgZGVuc2l0eSBzY2FsZS4KCkZvciB0aGUgZGlhbW9uZHMgZGF0YSBhIGRlbnNpdHkgcGxvdCBvZiBgcHJpY2VgIGZhY2V0ZWQgb24gYGN1dGAgc2hvd3MKdGhlIGNvbmRpdGlvbmFsIGRpc3RyaWJ1dGlvbnMgb2YgYHByaWNlYCBhdCB0aGUgZGlmZmVyZW50IGBjdXRgCmxldmVsczoKCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KZ2dwbG90KGRpYW1vbmRzKSArCiAgICBnZW9tX2RlbnNpdHkoYWVzKHggPSBwcmljZSkpICsKICAgIGZhY2V0X3dyYXAofiBjdXQpICsgdGhtCmBgYAoKTWFwcGluZyB0aGUgYHlgIGFlc3RoZXRpYyB0byBgYWZ0ZXJfc3RhdChjb3VudClgIHNob3dzIHRoZSBqb2ludCBkaXN0cmlidXRpb24Kb2YgYHByaWNlYCBhbmQgYGN1dGA6CgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmdncGxvdChkaWFtb25kcykgKwogICAgZ2VvbV9kZW5zaXR5KGFlcyh4ID0gcHJpY2UsCiAgICAgICAgICAgICAgICAgICAgIHkgPSBhZnRlcl9zdGF0KGNvdW50KSkpICsKICAgIGZhY2V0X3dyYXAofiBjdXQpICsgdGhtCmBgYAoKQSBzdGFja2VkIGRlbnNpdHkgcGxvdCBpcyBzb21ldGltZXMgdXNlZnVsIGJ1dCBvZnRlbiBoYXJkIHRvIHJlYWQ6CgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmdncGxvdChkaWFtb25kcykgKwogICAgZ2VvbV9kZW5zaXR5KGFlcyh4ID0gcHJpY2UsCiAgICAgICAgICAgICAgICAgICAgIHkgPSBhZnRlcl9zdGF0KGNvdW50KSwKICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGN1dCksCiAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSAic3RhY2siKSArCiAgICB0aG0KYGBgCgpBbiBpbnRlcm1lZGlhdGUgb3B0aW9uOiBBIGZhY2V0ZWQgcGxvdCBvbiB0aGUgY291bnQgc2NhbGUgd2l0aCBhIG11dGVkCnBsb3QgZm9yIHRoZSBmdWxsIGRhdGEgdG8gYWxsb3cgcHJvcG9ydGlvbnMgb2YgdGhlIHdob2xlIHRvIGJlCmFzc2Vzc2VkOgoKYGBge3IsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpnZ3Bsb3QoZGlhbW9uZHMpICsKICAgIGdlb21fZGVuc2l0eShhZXMoeCA9IHByaWNlLCB5ID0gYWZ0ZXJfc3RhdChjb3VudCkpLAogICAgICAgICAgICAgICAgIGZpbGwgPSAibGlnaHRncmV5IiwgY29sb3IgPSBOQSwKICAgICAgICAgICAgICAgICBkYXRhID0gbXV0YXRlKGRpYW1vbmRzLCBjdXQgPSBOVUxMKSkgKwogICAgZ2VvbV9kZW5zaXR5KGFlcyh4ID0gcHJpY2UsCiAgICAgICAgICAgICAgICAgICAgIHkgPSBhZnRlcl9zdGF0KGNvdW50KSwKICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGN1dCksCiAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSAic3RhY2siLCBjb2xvciA9IE5BKSArCiAgICBmYWNldF93cmFwKH4gY3V0KSArCiAgICBzY2FsZV9maWxsX3ZpcmlkaXNfZChndWlkZSA9ICJub25lIikgKwogICAgdGhtCmBgYAoKQSBmaWxsZWQgZGVuc2l0eSBwbG90IHByb3ZpZGVzIGEgdmV3IG9mIHRoZSBjb25kaXRpb25hbCBkaXN0cmlidXRpb24Kb2YgYGN1dGAgYXQgdGhlIGRpZmZlcmVudCBwcmljZSBsZXZlbHM6CgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmdncGxvdChkaWFtb25kcykgKwogICAgZ2VvbV9kZW5zaXR5KGFlcyh4ID0gcHJpY2UsIHkgPSBhZnRlcl9zdGF0KGNvdW50KSwgZmlsbCA9IGN1dCksCiAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSAiZmlsbCIpICsKICAgIHlsYWIoTlVMTCkgKwogICAgdGhtCmBgYAoKVGhpcyBpcyBjYWxsZWQgYSBfQ0QgcGxvdF8sIG9yIGEgX2NvbmRpdGlvbmFsIGRlbnNpdHkgcGxvdF8uCgoKIyMjIFNvbWUgTm90ZXMKCkNvbXB1dGF0aW9ucyBhcmUgZ2VuZXJhbGx5IGRvbmUgd2l0aCB0aGUgYmFzZSBSIGZ1bmN0aW9uIGBkZW5zaXR5YC4KCmBwbG90YCBoYXMgYSBtZXRob2QgZm9yIHRoZSByZXN1bHRzIHJldHVybmVkIGJ5IHRoaXMgZnVuY3Rpb24sIHNvIGEKZGVuc2l0eSBwbG90IGNhbiBiZSBjcmVhdGVkIHdpdGgKCmBgYHtyLCBldmFsID0gRkFMU0V9CnBsb3QoZGVuc2l0eShnZXlzZXIkZHVyYXRpb24pKQpgYGAKClRoZSBgbGF0dGljZWAgcGFja2FnZSBwcm92aWRlcyB0aGUgZnVuY3Rpb24gYGRlbnNpdHlwbG90YC4KCgojIyMgSW50ZXJhY3RpdmUgQmFuZHdpZHRoIENob2ljZQoKQmVpbmcgYWJsZSB0byBjaG9zZSB0aGUgYmFuZHdpZHRoIG9mIGEgZGVuc2l0eSBwbG90LCBvciB0aGUgYmlud2lkdGgKb2YgYSBoaXN0b2dyYW0sIGludGVyYWN0aXZlbHkgaXMgdXNlZnVsIGZvciBleHBsb3JhdGlvbi4KCk9uZSB3YXkgdG8gZG8gdGhpcyBpbiBSICh3aGljaCB1bmZvcnR1bmF0ZWx5IGRvZXMgbm90IHdvcmsgb24gdGhlClJTdHVkaW8gc2VydmVyKToKCmBgYHtyLCBldmFsID0gRkFMU0V9CmRhdGEoZ2V5c2VyLCBwYWNrYWdlID0gIk1BU1MiKQpzb3VyY2UoImh0dHBzOi8vc3RhdC51aW93YS5lZHUvfmx1a2UvY2xhc3Nlcy9TVEFUNzQwMC9leGFtcGxlcy90a2RlbnMuUiIpCnRrZGVucyhnZXlzZXIkZHVyYXRpb24sIHRrcnBsb3QgPSBUUlVFKQpgYGAKCkFub3RoZXIgb3B0aW9uOgoKYGBge3IsIGV2YWwgPSBGQUxTRX0KZGF0YShnZXlzZXIsIHBhY2thZ2UgPSAiTUFTUyIpCnNvdXJjZSgiaHR0cHM6Ly9zdGF0LnVpb3dhLmVkdS9+bHVrZS9jbGFzc2VzL1NUQVQ3NDAwL2V4YW1wbGVzL3NoaW55ZGVucy5SIikKc2hpbnlEZW5zKGdleXNlciRkdXJhdGlvbikKYGBgCgo8IS0tCgpnZ3Bsb3QoYmFybGV5KSArCiAgICBnZW9tX2RlbnNpdHkoYWVzKHggPSB5aWVsZCwgeSA9IC1hZnRlcl9zdGF0KGNvdW50KSwgZmlsbCA9IHllYXIpLAogICAgICAgICAgICAgICAgIGRhdGEgPSBmaWx0ZXIoYmFybGV5LCB5ZWFyID09IDE5MzEpKSArCiAgICBnZW9tX2RlbnNpdHkoYWVzKHggPSB5aWVsZCwgeSA9IGFmdGVyX3N0YXQoY291bnQpLCBmaWxsID0geWVhciksCiAgICAgICAgICAgICAgICAgZGF0YSA9IGZpbHRlcihiYXJsZXksIHllYXIgPT0gMTkzMikpICsKICAgIGNvb3JkX2ZsaXAoKQpnZ3Bsb3QoYmFybGV5KSArCiAgICBnZW9tX2RlbnNpdHkoYWVzKHggPSB5aWVsZCwgeSA9IC1hZnRlcl9zdGF0KGRlbnNpdHkpLCBmaWxsID0geWVhciksCiAgICAgICAgICAgICAgICAgZGF0YSA9IGZpbHRlcihiYXJsZXksIHllYXIgPT0gMTkzMSkpICsKICAgIGdlb21fZGVuc2l0eShhZXMoeCA9IHlpZWxkLCBmaWxsID0geWVhciksCiAgICAgICAgICAgICAgICAgZGF0YSA9IGZpbHRlcihiYXJsZXksIHllYXIgPT0gMTkzMikpICsKICAgIGNvb3JkX2ZsaXAoKSArCiAgICBmYWNldF93cmFwKH5zaXRlKQoKCiMjIEZyb20gQ2xhdXMgV2lsa2UncyBib29rOgpkYXRhKFRpdGFuaWMsIHBhY2thZ2UgPSAiU3RhdDJEYXRhIikKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5cikKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KGdncGxvdDIpCgpUaXRhbmljIHw+CiAgICBzZWxlY3QoLVNleENvZGUpIHw+CiAgICByZW5hbWUobmFtZSA9IE5hbWUsIGNsYXNzID0gUENsYXNzLCBhZ2UgPSBBZ2UsIHNleCA9IFNleCwKICAgICAgICAgICBzdXJ2aXZlZCA9IFN1cnZpdmVkKSB8PgogICAgbXV0YXRlKG5hbWUgPSBhcy5jaGFyYWN0ZXIobmFtZSksCiAgICAgICAgICAgY2xhc3MgPSBhcy5jaGFyYWN0ZXIoY2xhc3MpLAogICAgICAgICAgIHNleCA9IGFzLmNoYXJhY3RlcihzZXgpKSAtPiB0aXRhbmljX2FsbCAKCiMjdGl0YW5pYyA8LSBzZWxlY3QodGl0YW5pY190cmFpbiwgYWdlID0gQWdlLCBzZXggPSBTZXgpCnRpdGFuaWMgPC0gdGl0YW5pY19hbGwKCmRhdGEuZnJhbWUoCiAgICBhZ2UgPSAoMToyOCkqMyAtIDEuNSwgCiAgICBtYWxlID0gaGlzdChmaWx0ZXIodGl0YW5pYywgc2V4ID09ICJtYWxlIikkYWdlLAogICAgICAgICAgICAgICAgYnJlYWtzID0gKDA6MjgpKjMgKyAuMDEsIHBsb3QgPSBGQUxTRSkkY291bnRzLAogICAgZmVtYWxlID0gaGlzdChmaWx0ZXIodGl0YW5pYywgc2V4ID09ICJmZW1hbGUiKSRhZ2UsCiAgICAgICAgICAgICAgICAgIGJyZWFrcyA9ICgwOjI4KSozICsgLjAxLCBwbG90ID0gRkFMU0UpJGNvdW50cwopIHw+CiAgICBnYXRoZXIoZ2VuZGVyLCBjb3VudCwgLWFnZSkgLT4gZ2VuZGVyX2NvdW50cwoKZ2dwbG90KGdlbmRlcl9jb3VudHMsCiAgICAgICBhZXMoeCA9IGFnZSwgeSA9IGlmZWxzZShnZW5kZXIgPT0gIm1hbGUiLC0xLCAxKSpjb3VudCwgZmlsbCA9IGdlbmRlcikpICsgCiAgICBnZW9tX2NvbCgpICsKICAgIHNjYWxlX3hfY29udGludW91cyhuYW1lID0gImFnZSAoeWVhcnMpIiwgbGltaXRzID0gYygwLCA3NSksCiAgICAgICAgICAgICAgICAgICAgICAgZXhwYW5kID0gYygwLca*wkSkgKwogICAgc2NhbGVfeV9jb250aW51b3VzKG5hbWUgPSAiY291bnQiLCBicmVha3MgPSAyMCooLTI6MSksCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiNDAiLCAiMjAiLCAiMCIsICIyMCIpKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjRDU1RTAwIiwgIiMwMDcyQjIiKSwgZ3VpZGUgPSAibm9uZSIpICsKICAgIGRyYXdfdGV4dCh4ID0gNzAsIHkgPSAtMzksICJtYWxlIiwgaGp1c3QgPSAwKSArCiAgICBkcmF3X3RleHQoeCA9IDcwLCB5ID0gMjEsICJmZW1hbGUiLCBoanVzdCA9IDApICsKICAgIGNvb3JkX2ZsaXAoKQotLT4KCgojIyBCb3hwbG90cwoKX0JveHBsb3RzXywgb3IgX2JveC1hbmQtd2hpc2tlcl8gcGxvdHMsIHByb3ZpZGUgYSBza2VsZXRhbApyZXByZXNlbnRhdGlvbiBvZiBhIGRpc3RyaWJ1dGlvbi4KClRoZXkgYXJlIHZlcnkgd2VsbCBzdWl0ZWQgZm9yIHNob3dpbmcgZGlzdHJpYnV0aW9ucyBmb3IgbXVsdGlwbGUKZ3JvdXBzLgoKVGhlcmUgYXJlIG1hbnkgdmFyaWF0aW9ucyBvZiBib3hwbG90czoKCiogTW9zdCBzdGFydCB3aXRoIGEgYm94IGZyb20gdGhlIGZpcnN0IHRvIHRoZSB0aGlyZCBxdWFydGlsZXMgYW5kCiAgZGl2aWRlZCBieSB0aGUgbWVkaWFuLgoKKiBUaGUgc2ltcGxlc3QgZm9ybSB0aGVuIGFkZHMgYSB3aGlza2VyIGZyb20gdGhlIGxvd2VyIHF1YXJ0aWxlIHRvIHRoZQogIG1pbmltdW0gYW5kIGZyb20gdGhlIHVwcGVyIHF1YXJ0aWxlIHRvIHRoZSBtYXhpbXVtLgoKKiBNb3JlIGNvbW1vbiBpcyB0byBkcmF3IHRoZSB1cHBlciB3aGlza2VyIHRvIHRoZSBsYXJnZXN0IHBvaW50IGJlbG93CiAgdGhlIHVwcGVyIHF1YXJ0aWxlICQrIDEuNSAqIElRUiQsIGFuZCB0aGUgbG93ZXIgd2hpc2tlciBhbmFsb2dvdXNseS4KCiogX091dGxpZXJzXyBmYWxsaW5nIG91dHNpZGUgdGhlIHJhbmdlIG9mIHRoZSB3aGlza2VycyBhcmUgdGhlbiBkcmF3bgogIGRpcmVjdGx5OgoKYGBge3IsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpsaWJyYXJ5KGdhcG1pbmRlcikKbGlicmFyeShnZ3Bsb3QyKQpnZ3Bsb3QoZ2FwbWluZGVyKSArCiAgICBnZW9tX2JveHBsb3QoYWVzKHggPSBjb250aW5lbnQsIHkgPSBnZHBQZXJjYXApKSArCiAgICB4bGFiKE5VTEwpICsKICAgIHRobQpgYGAKClRoZXJlIGFyZSB2YXJpYW50cyB0aGF0IGRpc3Rpbmd1aXNoIGJldHdlZW4gX21pbGQgb3V0bGllcnNfIGFuZApfZXh0cmVtZSBvdXRsaWVyc18uCgpBIGNvbW1vbiB2YXJpYW50IGlzIHRvIHNob3cgYW4gYXBwcm94aW1hdGUgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgZm9yCnRoZSBwb3B1bGF0aW9uIG1lZGlhbiBhcyBhIF9ub3RjaF86CgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmdncGxvdChnYXBtaW5kZXIpICsKICAgIGdlb21fYm94cGxvdChhZXMoeCA9IGNvbnRpbmVudCwgeSA9IGdkcFBlcmNhcCksCiAgICAgICAgICAgICAgICAgbm90Y2ggPSBUUlVFKSArCiAgICB4bGFiKE5VTEwpICsKICAgIHRobQpgYGAKCkFub3RoZXIgdmFyaWFudCBpcyB0byB1c2UgYSB3aWR0aCBwcm9wb3J0aW9uYWwgdG8gdGhlIHNxdWFyZSByb290IG9mCnRoZSBzYW1wbGUgc2l6ZSB0byByZWZsZWN0IHRoZSBzdHJlbmd0aCBvZiBldmlkZW5jZSBpbiB0aGUgZGF0YToKCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KZ2dwbG90KGdhcG1pbmRlcikgKwogICAgZ2VvbV9ib3hwbG90KGFlcyh4ID0gY29udGluZW50LCB5ID0gZ2RwUGVyY2FwKSwKICAgICAgICAgICAgICAgICBub3RjaCA9IFRSVUUsIHZhcndpZHRoID0gVFJVRSkgKwogICAgeGxhYihOVUxMKSArCiAgICB0aG0KYGBgCgpXaXRoIG1vZGVyYXRlIHNhbXBsZSBzaXplcyBpdCBjYW4gYmUgdXNlZnVsIHRvIHN1cGVyLWltcG9zZSB0aGUKb3JpZ2luYWwgZGF0YSwgcGVyaGFwcyB3aXRoIGppdHRlcmluZyBhbmQgYWxwaGEgYmxlbmRpbmcuCgpUaGUgb3V0bGllcnMgaW4gdGhlIGJveCBwbG90IGNhbiBiZSB0dXJuZWQgb2ZmIHdpdGggYG91dGxpZXIuY29sb3IgPQpOQWAgc28gdGhleSBhcmUgbm90IHNob3duIHR3aWNlOgoKYGBge3IsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpwIDwtIGdncGxvdChnYXBtaW5kZXIpICsKICAgIGdlb21fYm94cGxvdChhZXMoeCA9IGNvbnRpbmVudCwgeSA9IGdkcFBlcmNhcCksCiAgICAgICAgICAgICAgICAgbm90Y2ggPSBUUlVFLCB2YXJ3aWR0aCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgb3V0bGllci5jb2xvciA9IE5BKSArCiAgICB4bGFiKE5VTEwpICsKICAgIHRobQpwICsgZ2VvbV9wb2ludChhZXMoeCA9IGNvbnRpbmVudCwgeSA9IGdkcFBlcmNhcCksCiAgICAgICAgICAgICAgIHBvc2l0aW9uID0KICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uX2ppdHRlcih3aWR0aCA9IDAuMSksCiAgICAgICAgICAgICAgIGFscGhhID0gMC4xKQpgYGAKCgojIyBWaW9saW4gUGxvdHMKCkEgdmFyaWFudCBvZiB0aGUgYm94cGxvdCBpcyB0aGUgX3Zpb2xpbiBwbG90XzoKCj4gSGludHplLCBKLiBMLiwgTmVsc29uLCBSLiBELiAoMTk5OCksICJWaW9saW4gUGxvdHM6IEEgQm94Cj4gUGxvdC1EZW5zaXR5IFRyYWNlIFN5bmVyZ2lzbSwiIF9UaGUgQW1lcmljYW4gU3RhdGlzdGljaWf*ckyA1MiwKPiAxODEtMTg0LgoKVGhlIHZpb2xpbiBwbG90IHVzZXMgZGVuc2l0eSBlc3RpbWF0ZXMgdG8gc2hvdyB0aGUgZGlzdHJpYnV0aW9uczoKCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KZ2dwbG90KGdhcG1pbmRlcikgKwogICAgZ2VvbV92aW9saW4oYWVzKHggPSBjb250aW5lbnQsIHkgPSBnZHBQZXJjYXApKSArCiAgICB4bGFiKE5VTEwpICsKICAgIHRobQpgYGAKCkJ5IGRlZmF1bHQgdGhlICJ2aW9saW5zIiBhcmUgc2NhbGVkIHRvIGhhdmUgdGhlIHNhbWUgYXJlYS4KClRoZXkgY2FuIGFsc28gYmUgc2NhbGVkIHRvIGhhdmUgdGhlIHNhbWUgbWF4aW11bSBoZWlnaHQgb3IgdG8gaGF2ZQphcmVhcyBwcm9wb3J0aW9uYWwgdG8gc2FtcGxlIHNpemVzLgoKVGhpcyBpcyBkb25lIGJ5IGFkZGluZwoKKiBgc2NhbGUgPSAid2lkdGgiYCBvcgoqIGBzY2FsZSA9ICJjb3VudCJgCgp0byB0aGUgYGdlb21fdmlvbGluYCBjYWxsLgoKQSBjb21wYXJpc29uIG9mIGJveHBsb3RzIGFuZCB2aW9saW4gcGxvdHM6CgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmdncGxvdChnYXBtaW5kZXIpICsKICAgIGdlb21fYm94cGxvdChhZXMoeCA9IGNvbnRpbmVudCwgeSA9IGdkcFBlcmNhcCkpICsKICAgIGdlb21fdmlvbGluKGFlcyh4ID0gY29udGluZW50LCB5ID0gZ2RwUGVyY2FwKSwKICAgICAgICAgICAgICAgIGZpbGwgPSBOQSwgc2NhbGUgPSAid2lkdGgiLAogICAgICAgICAgICAgICAgbGluZXR5cGUgPSAyKSArCiAgICB4bGFiKE5VTEwpICsKICAgIHRobQpgYGAKCkEgY29tYmluYXRpb24gb2YgYm94cGxvdHMgYW5kIHZpb2xpbiBwbG90czoKCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KZ2dwbG90KGdhcG1pbmRlcikgKwogICAgZ2VvbV92aW9saW4oYWVzKHggPSBjb250aW5lbnQsIHkgPSBnZHBQZXJjYXApLAogICAgICAgICAgICAgICAgc2NhbGUgPSAid2lkdGgiKSArCiAgICBnZW9tX2JveHBsb3QoYWVzKHggPSBjb250aW5lbnQsIHkgPSBnZHBQZXJjYXApLAogICAgICAgICAgICAgICAgIHdpZHRoID0gLjEpICsKICAgIHhsYWIoTlVMTCkgKwogICAgdGhtCmBgYAoKVGhlcmUgYXJlIG90aGVyIHZhcmlhdGlvbnMsIGUuZy4gX3Zhc2UgcGxvdHNfLgoKQm94cGxvdHMgZG8gbm90IHJlZmxlY3QgdGhlIHNoYXBlIG9mIGEgZGlzdHJpYnV0aW9uLgoKRm9yIHRoZSBgZXJ1cHRpb25zYCBpbiB0aGUgYGZhaXRoZnVsYCBkYXRhIHNldDoKCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KZ2dwbG90KGZhaXRoZnVsKSArCiAgICBnZW9tX2JveHBsb3QoYWVzKHkgPSBlcnVwdGlvbnMsIHggPSAiQm94IikpICsKICAgIGdlb21fdmlvbGluKGFlcyh5ID0gZXJ1cHRpb25zLCB4ID0gIlZpb2xpbiIpLAogICAgICAgICAgICAgICAgdHJpbSA9IEZBTFNFKSArCiAgICB4bGFiKE5VTEwpICsKICAgIHRobQpgYGAKCgojIyBTd2FybSBQbG90cwoKU3dhcm0gcGxvdHMgc2hvdyB0aGUgZnVsbCBkYXRhIGluIGEgZm9ybSB0aGF0IGFsc28gc2hvd3MgdGhlIGRlbnNpdHkuCgpUaGVyZSBhcmUgYSBudW1iZXIgb2YgdmFyaWF0aW9ucyBhbmQgbmFtZXMsIGluY2x1ZGluZyBfYmVlc3dhcm0KcGxvdHNfLCBfdmlvbGluIHNjYXR0ZXJwbG90c18sIF92aW9saW4gc3RyaXAgY2hhcnRzXywgYW5kIF9zaW5hIHBsb3RzXwoKW1NpbmEKcGxvdHNdKGh0dHBzOi8vd3d3LnRhbmRmb25saW5lLmNvbS9kb2kvZnVsbC8xMC4xMDgwLzEwNjE4NjAwLjIwMTcuMTM2NjkxNCkKYXJlIGF2YWlsYWJsZSBhcyBgZ2VvbV9zaW5hYCBpbiB0aGUgYGdnZm9yY2VgIHBhY2thZ2U6Cgo8IS0tIGh0dHA6Ly9tb2Rlcm5ncmFwaGljczExLnBid29ya3MuY29tL2Yvd2lsa2luc29uXzE5OTkuRG90UGxvdHMucGRmIC0tPgoKYGBge3IsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpsaWJyYXJ5KGdnZm9yY2UpCmdncGxvdChnYXBtaW5kZXIsCiAgICAgICBhZXMoeCA9IGNvbnRpbmVudCwgeSA9IGdkcFBlcmNhcCkpICsKICAgIGdlb21fc2luYShzaXplID0gMC4yKSArCiAgICB4bGFiKE5VTEwpICsKICAgIHRobQpgYGAKCkNvbWJpbmVkIHdpdGggYSB3aWR0aC1zY2FsZWQgdmlvbGluIHBsb3Q6CgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmdncGxvdChnYXBtaW5kZXIsCiAgICAgICBhZXMoeCA9IGNvbnRpbmVudCwgeSA9IGdkcFBlcmNhcCkpICsKICAgIGdlb21fdmlvbGluKHNjYWxlID0gIndpZHRoIikgKwogICAgZ2VvbV9zaW5hKGNvbG9yID0gImJsdWUiLAogICAgICAgICAgICAgIHNpemUgPSAwLjQsCiAgICAgICAgICAgICAgc2NhbGUgPSBGQUxTRSkgKwogICAgeGxhYihOVUxMKSArCiAgICB0aG0KYGBgCgoKIyMgRWZmZWN0aXZlbmVzcyBhbmQgU2NhbGFiaWxpdHkKCiogQm94cGxvdHMgYXJlIHZlcnkgc2ltcGxlIGFuZCBlYXN5IHRvIGNvbXBhcmUuCgoqIEJveHBsb3RzIHN0cm9uZ2x5IGVtcGhhc2l6ZSB0aGUgbWlkZGxlIGhhbGYgb2YgdGhlIGRhdGEuCgoqIEJveHBsb3RzIG1heSBub3QgYmUgZWFzeSBmb3IgYSBsYXkgdmlld2VyIHRvIHVuZGVyc3RhbmQuCgoqIEJveCBwbG90cyBzY2FsZSBmYWlybHkgd2VsbCB2aXN1YWxseSBhbmQgY29tcHV0YXRpb25hbGx5IGluIHRoZQogIG51bWJlciBvZiBvYnNlcnZhdGlvbnM7IG92ZXItcGxvdHRpbmcvc3RvcmFnZSBvZiBvdXRsaWVycyBiZWNvbWVzIGFuCiAgaXNzdWUgZm9yIGxhcmdlciBkYXRhIHNldHMKCiogVmlvbGluIHBsb3RzIHNjYWxlIHdlbGwgYm90aCB2aXN1YWxseSBhbmQgY29tcHV0YXRpb25hbGx5IGluIHRoZQogIG51bWJlciBvZiBvYnNlcnZhdGlvbnMuCgpgYGB7ciwgZmlnLndpZHRoID0gMTEsIGZpZy5oZWlnaHQgPSA0LCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KbGlicmFyeShwYXRjaHdvcmspCnAxIDwtIGdncGxvdChkaWFtb25kcykgKwogICAgZ2VvbV9ib3hwbG90KGFlcyh4ID0gY3V0LCB5ID0gcHJpY2UpKSArCiAgICB4bGFiKE5VTEwpICsKICAgIHRobQpwMiA8LSBnZ3Bsb3QoZGlhbW9uZHMpICsKICAgIGdlb21fdmlvbGluKGFlcyh4ID0gY3V0LCB5ID0gcHJpY2UpKSArCiAgICB4bGFiKE5VTEwpICsKICAgIHRobQpwMSArIHAyCmBgYAoKKiBTY2FsYWJpbGl0eSBpbiB0aGUgbnVtYmVyIG9mIGNhc2VzIGZvciBzd2FybSBvciBzaW5hIHBsb3RzIGlzIG1vcmUKICBsaW1pdGVkLgoKKiBUaGUgbnVtYmVyIG9mIGdyb3VwcyB0aGF0IGNhbiBiZSBoYW5kbGVkIGZvciBjb21wYXJpc29uIGJ5IHRoZXNlIHBsb3RzCiAgaXMgaW4gdGhlIHJhbmdlIG9mIGEgZmV3IGRvemVuLgoKYGBge3IsIGZpZy53aWR0aCA9IDExLCBmaWcuaGVpZ2h0ID0gNSwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmxpYnJhcnkobGF0dGljZSkKcDEgPC0gZ2dwbG90KGJhcmxleSkgKwogICAgZ2VvbV9ib3hwbG90KGFlcyh4ID0gc2l0ZSwgeSA9IHlpZWxkLCBmaWxsID0geWVhcikpICsKICAgIHhsYWIoTlVMTCkgKwogICAgdGhtCnAyIDwtIGdncGxvdChiYXJsZXkpICsKICAgIGdlb21fdmlvbGluKGFlcyh4ID0gc2l0ZSwgeSA9IHlpZWxkLCBmaWxsID0geWVhcikpICsKICAgIHhsYWIoTlVMTCkgKwogICAgdGhtCnAxICsgcDIKYGBgCgpBeGVzIGNhbiBiZSBmbGlwcGVkIHRvIGF2b2lkIG92ZXJwbG90dGluZyBvZiBsYWJlbHM6CgpgYGB7ciwgZmlnLndpZHRoID0gMTEsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpsaWJyYXJ5KGxhdHRpY2UpCnAzIDwtIHAxICsgY29vcmRfZmxpcCgpICsgZ3VpZGVzKGZpbGwgPSAibm9uZSIpCnA0IDwtIHAyICsgY29vcmRfZmxpcCgpCnAzICsgcDQKYGBgCgpGYWNldGluZyBjYW4gYWxzbyBiZSB1c2VkIHRvIGFycmFuZ2UgZ3JvdXBzIG9mIGJveHBsb3RzIG9yIHZpb2xpbiBwbG90cy4KCkZvciBsaWZlIGV4cGVjdGFuY3kgYnkgY29udGluZW50IG92ZXIgdGhlIHllYXJzIGluIHRoZSBgZ2FwbWluZGVyYCBkYXRhOgoKYGBge3IsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpsaWJyYXJ5KGRwbHlyKQpnZ3Bsb3QoZmlsdGVyKGdhcG1pbmRlciwKICAgICAgICAgICAgICB5ZWFyICUlIDEwID09IDIsCiAgICAgICAgICAgICAgY29udGluZW50ICE9ICJPY2VhbmlhIikpICsKICAgIGdlb21fYm94cGxvdChhZXMoeCA9IGxpZmVFeHAsIHkgPSBmYWN0b3IoeWVhcikpKSArCiAgICBmYWNldF93cmFwKH4gY29udGluZW50LCBuY29sID0gMSkgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkgKwogICAgdGhlbWUoc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMCkpICsKICAgIHlsYWIoTlVMTCkKYGBgCgpBIHJlbGF0ZWQgdmlzdWFsaXphdGlvbiBtb3RpdmF0ZWQgYnkgYSBncmFwaCBpbiB0aGUgRWNvbm9taXN0IGlzCmF2YWlsYWJsZSBbaGVyZV0oaHR0cHM6Ly9jaW5jLnJ1ZC5pcy93ZWIvcGFja2FnZXMvZ2dlY29ub2Rpc3QvKS4KCgojIyBSaWRnZWxpbmUgUGxvdHMKCltSaWRnZWxpbmUKcGxvdHNdKGh0dHBzOi8vYmxvZy5yZXZvbHV0aW9uYW5hbHl0aWNzLmNvbS8yMDE3LzA3L2pveXBsb3RzLmh0bWwpLAphbHNvIGNhbGxlZCBfcmlkZ2UgcGxvdHNfIG9yIF9qb3kgcGxvdHNfLCBhcmUgYW5vdGhlciB3YXkgdG8gc2hvdwpkZW5zaXR5IGVzdGltYXRlcyBmb3IgYSBudW1iZXIgb2YgZ3JvdXBzIHRoYXQgaGFzIGJlY29tZSBwb3B1bGFyCnJlY2VudGx5LgoKQW4gZWFybHkgZXhhbXBsZSBhcHBlYXJzIGluIFt0aGlzIE5ZVAphcnRpY2xlXShodHRwczovL3d3dy5ueXRpbWVzLmNvbS9pbnRlcmFjdGl2ZS8yMDE3LzA2LzEyL3Vwc2hvdC90aGUtcG9saXRpY3Mtb2YtYW1lcmljYXMtcmVsaWdpb3VzLWxlYWRlcnMuaHRtbCkuCjwhLS0gZWFybHkgUiB2ZXJzaW9uIGluIC0gaHR0cHM6Ly9sdWlzZHZhLmdpdGh1Yi5pby9yc3RhdHMvZGVuc2l0eS1zd2FybXMvIC0tPgoKVGhlIHBhY2thZ2UgYGdncmlkZ2VzYCBkZWZpbmVzIGBnZW9tX2RlbnNpdHlfcmlkZ2VzYCBmb3IgY3JlYXRpbmcKdGhlc2UgcGxvdHM6CgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KbGlicmFyeShnZ3JpZGdlcykKZ2dwbG90KGJhcmxleSkgKwogICAgZ2VvbV9kZW5zaXR5X3JpZGdlcyhhZXMoeCA9IHlpZWxkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHNpdGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IHNpdGUpKSArCiAgICB5bGFiKE5VTEwpICsKICAgIHRobQpgYGAKCkdyb3VwaW5nIGJ5IGFuIGludGVyYWN0aW9uIHdpdGggYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSwgYHllYXJgLApwcm9kdWNlcyBzZXBhcmF0ZSBkZW5zaXR5IGVzdGltYXRlcyBmb3IgZWFjaCBsZXZlbC4KCk1hcHBpbmcgdGhlIGBmaWxsYCBhZXN0aGV0aWMgdG8gYHllYXJgIGFsbG93cyB0aGUgc2VwYXJhdGUgZGVuc2l0aWVzCnRvIGJlIGlkZW50aWZpZWQ6CgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmdncGxvdChiYXJsZXkpICsKICAgIGdlb21fZGVuc2l0eV9yaWRnZXMoCiAgICAgICAgYWVzKHggPSB5aWVsZCwKICAgICAgICAgICAgeSA9IHNpdGUsCiAgICAgICAgICAgIGdyb3VwID0gaW50ZXJhY3Rpb24oeWVhciwgc2l0ZSksCiAgICAgICAgICAgIGZpbGwgPSB5ZWFyKSkgKwogICAgeWxhYihOVUxMKSArCiAgICB0aG0KYGBgCgpBbHBoYSBibGVuZGluZyBtYXkgc29tZXRpbWVzIGhlbHA6CgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmdncGxvdChiYXJsZXkpICsKICAgIGdlb21fZGVuc2l0eV9yaWRnZXMoCiAgICAgICAgYWVzKHggPSB5aWVsZCwKICAgICAgICAgICAgeSA9IHNpdGUsCiAgICAgICAgICAgIGdyb3VwID0gaW50ZXJhY3Rpb24oeWVhciwgc2l0ZSksCiAgICAgICAgICAgIGZpbGwgPSB5ZWFyKSwKICAgICAgICBhbHBoYSA9IDAuOCkgKwogICAgeWxhYihOVUxMKSArCiAgICB0aG0KYGBgCgpBZGp1c3RpbmcgdGhlIHZlcnRpY2FsIHNjYWxlIG1heSBhbHNvIGhlbHA6CgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmdncGxvdChiYXJsZXkpICsKICAgIGdlb21fZGVuc2l0eV9yaWRnZXMoCiAgICAgICAgYWVzKHggPSB5aWVsZCwKICAgICAgICAgICAgeSA9IHNpdGUsCiAgICAgICAgICAgIGdyb3VwID0gaW50ZXJhY3Rpb24oeWVhciwgc2l0ZSksCiAgICAgICAgICAgIGZpbGwgPSB5ZWFyKSwKICAgICAgICBzY2FsZSA9IDAuOCkgKwogICAgeWxhYihOVUxMKSArCiAgICB0aG0KYGBgCgpTb21ldGltZXMgcmVvcmRlcmluZyB0aGUgZ3JvdXBpbmcgdmFyaWFibGUsIGB5ZWFyYCBpbiB0aGlzIGNhc2UsIGNhbgpoZWxwLgoKVGhlIGZhY3RvciBsZXZlbHMgb2YgYHllYXJgIGNhbiBiZSByZW9yZGVyZWQgdG8gbWF0Y2ggdGhlIG9yZGVyIG9mCmF2ZXJhZ2UgeWVhbGRzIHdpdGhpbiBlYWNoIHllYXIgYnkKCmBgYHtyLCBldmFsID0gRkFMU0V9CnJlb3JkZXIoeWVhciwgeWllbGQpCmBgYAoKVXNpbmcgYC15aWVsZGAgcHJvZHVjZXMgdGhlIHJldmVyc2Ugb3JkZXIuCgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KbGlicmFyeShkcGx5cikKZ2dwbG90KG11dGF0ZShiYXJsZXksIHllYXIgPSByZW9yZGVyKHllYXIsIC15aWVsZCkpKSArCiAgICBnZW9tX2RlbnNpdHlfcmlkZ2VzKGFlcyh4ID0geWllbGQsIHkgPSBzaXRlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBpbnRlcmFjdGlvbih5ZWFyLCBzaXRlKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSB5ZWFyKSwgc2NhbGUgPSAwLjgpICsKICAgIHlsYWIoTlVMTCkgKwogICAgdGhtCmBgYAoKV2l0aCBzb21lIHR1bmluZyByaWRnZWxpbmUgcGxvdHMgY2FuIHNjYWxlIHdlbGwgdG8gbWFueSBkaXN0cmlidXRpb25zLgpBbiBleGFtcGxlIGZyb20gW0NsYXVzIFdpbGtlJ3MgYm9va10oaHR0cHM6Ly9jbGF1c3dpbGtlLmNvbS9kYXRhdml6Lyk6CgpUaGUgYGdncGxvdDJtb3ZpZXNgIHBhY2thZ2UgcHJvdmlkZXMgZGF0YSBmcm9tCltJTURCXShodHRwczovL2ltZGIuY29tLykgb24gYSBsYXJnZSBudW1iZXIgb2YgbW92aWVzLCBpbmNsdWRpbmcgdGhlaXIKbGVuZ3RocywgaW4gYSB0aWJibGUgYG1vdmllc2A6CgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QybW92aWVzKQpkaW0obW92aWVzKQpoZWFkKG1vdmllcykKYGBgCgpBIHJpZGdlbGluZSBwbG90IG9mIHRoZSBtb3ZpZSBsZW5ndGhzIGZvciBlYWNoIHllYXI6CgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KbGlicmFyeShkcGx5cikKbXYxMiA8LSBmaWx0ZXIobW92aWVzLCB5ZWFyID4gMTkxMikKZ2dwbG90KG12MTIsIGFlcyh4ID0gbGVuZ3RoLCB5ID0geWVhciwgZ3JvdXAgPSB5ZWFyKSkgKwogICAgZ2VvbV9kZW5zaXR5X3JpZGdlcyhzY2FsZSA9IDEwLCBzaXplID0gMC4yNSwgcmVsX21pbl9oZWlnaHQgPSAwLjAzKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAyMDApKSArCiAgICBzY2FsZV95X3JldmVyc2UoYnJlYWtzID0gYygyMDAwLCAxOTgwLCAxOTYwLCAxOTQwLCAxOTIwKSkgKwogICAgdGhlbWVfbWluaW1hbCgpCmBgYAoKVGhpcyBzaG93cyB0aGF0IHNpbmNlIHRoZSBlYXJseSAxOTYwJ3MgZmVhdHVyZSBmaWxtIGxlbmd0aHMgaGF2ZQpzdGFiaWxpemVkIHRvIGEgZGlzdHJpYnV0aW9uIGNlbnRlcmVkIGFyb3VuZCA5MCBtaW51dGVzOgoKQW5vdGhlciBuaWNlIGV4YW1wbGU6CltEVy1OT01JTkFURV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTk9NSU5BVEVfJTI4c2NhbGluZ19tZXRob2QlMjkpCnNjb3JlcyBmb3IgbWVhc3VyaW5nIHBvbGl0aWNhbCBwb3NpdGlvbiBvZiBtZW1iZXJzIG9mIGNvbmdyZXNzIG92ZXIKdGhlIHllYXJzOgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoID0gIjcwJSJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKElNRygicG9sYXJpemF0aW9uLmpwZWciKSkKYGBgCgpbT3JpZ2luYWwgY29kZV0oIGh0dHA6Ly9ycHVicy5jb20vaWFucm1jZG9uYWxkLzI5MzMwNCkgYnkgSWf*ck1jRG9uYWxkOyBhbm90aGVyIHZlcnNpb24gaXMgcHJvdmlkZWQgaW4gW0NsYXVzIFdpbGtlJ3MKYm9va10oaHR0cHM6Ly9jbGF1c3dpbGtlLmNvbS9kYXRhdml6LykuCgoKIyMgUmVhZGluZwoKQ2hhcHRlciBbX1Zpc3VhbGl6aW5nIGRpc3RyaWJ1dGlvbnM6IEhpc3RvZ3JhbXMgYW5kIGRlbnNpdHkKICBwbG90c19dKGh0dHBzOi8vY2xhdXN3aWxrZS5jb20vZGF0YXZpei9oaXN0b2dyYW1zLWRlbnNpdHktcGxvdHMuaHRtbCkKICBpbiBbX0Z1bmRhbWVudGFscyBvZiBEYXRhCiAgVmlzdWFsaXphdGlvbl9dKGh0dHBzOi8vY2xhdXN3aWxrZS5jb20vZGF0YXZpei8pLgoKU2VjdGlvbiBbX0hpc3RvZ3JhbXMgYW5kIGRlbnNpdHkKcGxvdHNfXShodHRwczovL3NvY3Zpei5jby9ncm91cGZhY2V0dHguaHRtbCNoaXN0b2dyYW1zKSBpbiBbX0RhdGEKVmlzdWFsaXphdGlvbl9dKGh0dHBzOi8vc29jdml6LmNvLykuCgpDaGFwdGVyIFtfVmlzdWFsaXppbmcgZGF0YSBkaXN0cmlidXRpb25zX10oaHR0cHM6Ly9yYWZhbGFiLmRmY2kuaGFydmFyZC5lZHUvZHNib29rLXBhcnQtMS9kYXRhdml6L2Rpc3RyaWJ1dGlvbnMuaHRtbCkKaW4gW19JbnRyb2R1Y3Rpb24gdG8gRGF0YSBTY2llbmNlOiBEYXRhIEFuYWx5c2lzIGFuZCBQcmVkaWN0aW9uCkFsZ29yaXRobXMgd2l0aCBSX10oaHR0cHM6Ly9yYWZhbGFiLmRmY2kuaGFydmFyZC5lZHUvZHNib29rLXBhcnQtMS8pLgoKCiMjIEludGVyYWN0aXZlIFR1dG9yaWFsCgpBbiBpbnRlcmFjdGl2ZSBbYGxlYXJucmBdKGh0dHBzOi8vcnN0dWRpby5naXRodWIuaW8vbGVhcm5yLykgdHV0b3JpYWwKZm9yIHRoZXNlIG5vdGVzIGlzIFthdmFpbGFibGVdKGByIFdMTksoInR1dG9yaWFscy9kaXN0cy5SbWQiKWApLgoKWW91IGNhbiBydW4gdGhlIHR1dG9yaWFsIHdpdGgKCmBgYHtyLCBldmFsID0gRkFMU0V9ClNUQVQ0NTgwOjpydW5UdXRvcmlhbCgiZGlzdHMiKQpgYGAKCllvdSBjYW4gaW5zdGFsbCB0aGUgY3VycmVudCB2ZXJzaW9uIG9mIHRoZSBgU1RBVDQ1ODBgIHBhY2thZ2Ugd2l0aAoKYGBge3IsIGV2YWwgPSBGQUxTRX0KcmVtb3Rlczo6aW5zdGFsbF9naXRsYWIoImx1a2UtdGllcm5leS9TVEFUNDU4MCIpCmBgYAoKWW91IG1heSBuZWVkIHRvIGluc3RhbGwgdGhlIGByZW1vdGVzYCBwYWNrYWdlIGZyb20gQ1JBTiBmaXJzdC4KCgojIyBFeGVyY2lzZXMKCjEuIENvbnNpZGVyIHRoZSBjb2RlCgo8IS0tICMjIG5vbGludCBzdGFydCAtLT4KICAgIGBgYHtyLCBldmFsID0gRkFMU0V9CiAgICBsaWJyYXJ5KGdncGxvdDIpCiAgICBkYXRhKEdhbHRvbiwgcGFja2FnZSA9ICJIaXN0RGF0YSIpCiAgICBnZ3Bsb3QoR2FsdG9uLCBhZXMoeCA9IHBhcmVudCkpICsKICAgICAgICBnZW9tX2hpc3RvZ3JhbSgtLS0sIGZpbGwgPSAiZ3JleSIsIGNvbG9yID0gImJsYWNrIikKICAgIGBgYAo8IS0tICMjIG5vbGludCBlbmQgLS0+CgogICAgV2hpY2ggb2YgdGhlIGZvbGxvd2luZyByZXBsYWNlbWVudHMgZm9yIGAtLS1gIHByb2R1Y2VzIGEgaGlzdG9ncmFtCiAgICB3aXRoIGJpbnMgdGhhdCBhcmUgb25lIGluY2ggd2lkZSBhbmQgc3RhcnQgYXQgd2hvbGUgaW50ZWdlcnM/CiAgICAKICAgIGEuIGBiaW53aWR0aCA9IDFgCiAgICBiLiBgYmlud2lkdGggPSAxLCBjZW50ZXIgPSA2Ni41YAogICAgYy4gYGJpbndpZHRoID0gMiwgY2VudGVyID0gNjZgCiAgICBkLiBgY2VudGVyID0gNjZgCgoyLiBDb25zaWRlciB0aGUgY29kZQoKICAgIGBgYHtyLCBldmFsID0gRkFMU0V9CiAgICBsaWJyYXJ5KGdncGxvdDIpCiAgICBnZ3Bsb3QoZmFpdGhmdWwsIGFlcyh4ID0gZXJ1cHRpb25zKSkgKyBnZW9tX2RlbnNpdHkoLS0tKQogICAgYGBgCiAgICAKICAgIFdoaWNoIG9mIHRoZSBmb2xsb3dpbmcgcmVwbGFjZW1lbnRzIGZvciBgLS0tYCBwcm9kdWNlcyBhIGRlbnNpdHkKICAgIHBsb3Qgd2l0aCB0aGUgYXJlYSB1bmRlciB0aGUgZGVuc2l0eSBpbiBibHVlIGFuZCBubyBibGFjayBib3JkZXI/CiAgICAKICAgIGEuIGBjb2xvciA9ICJsaWdodGJsdWUiYAogICAgYi4gYGZpbGwgPSAiYmxhY2siLCBjb2xvciA9ICJsaWdodGJsdWUiYAogICAgYy4gYGZpbGwgPSAibGlnaHRibHVlIiwgY29sb3IgPSBOQWAKICAgIGQuIGBmaWxsID0gTkEsIGNvbG9yID0gImJsYWNrImAKCjMuIENvbnNpZGVyIHRoZSBjb2RlCgogICAgYGBge3IsIGV2YWwgPSBGQUxTRX0KICAgIGxpYnJhcnkoZ2dwbG90MikKICAgIGxpYnJhcnkoZ2FwbWluZGVyKQogICAgcCA8LSBnZ3Bsb3QoZ2FwbWluZGVyLCBhZXMoeSA9IGNvbnRpbmVudCwgeCA9IGxpZmVFeHApKQogICAgYGBgCgogICAgV2hpY2ggb2YgdGhlIGZvbGxvd2luZyBwcm9kdWNlcyB2aW9saW4gcGxvdHMgd2l0aG91dCB0cmltbWluZyBhdAogICAgdGhlIHNtYWxsZXN0IGFuZCBsYXJnZXN0IG9ic2VydmF0aW9ucywgYW5kIGluY2x1ZGluZyBhIGxpbmUgYXQgdGhlCiAgICBtZWRpYW4/CgogICAgYS4gYHAgKyBnZW9tX3Zpb2xpbih0cmltID0gRkFMU0UpYAogICAgYi4gYHAgKyBnZW9tX3Zpb2xpbih0cmltID0gVFJVRSwgc2hvd19tZWRpYW4gPSBUUlVFKWAKICAgIGMuIGBwICsgZ2VvbV92aW9saW4odHJpbSA9IEZBTFNFLCBkcmF3X3F1YW50aWxlcyA9IDAuNSlgCiAgICBkLiBgcCArIGdlb21fdmlvbGluKHRyaW0gPSBUUlVFLCBzaG93X3F1YW50aWxlcyA9IDAuNSlgCgo0LiBEZW5zaXR5IHJpZGdlcyBjYW4gYWxzbyBzaG93IHF1YW50aWxlcywgYnV0IHRoZSBkZXRhaWxzIG9mIGhvdyB0bwogICByZXF1ZXN0IHRoaXMgYXJlIGRpZmZlcmVudC4gQ29uc2lkZXIgdGhpcyBjb2RlOgoKICAgIGBgYHtyLCBldmFsID0gRkFMU0V9CiAgICBsaWJyYXJ5KGdncGxvdDIpCiAgICBsaWJyYXJ5KGdncmlkZ2VzKQogICAgbGlicmFyeShnYXBtaW5kZXIpCiAgICBnZ3Bsb3QoZ2FwbWluZGVyLCBhZXMoeCA9IGxpZmVFeHAsIHkgPSB5ZWFyLCBncm91cCA9IHllYXIpKSArCiAgICAgICAgZ2VvbV9kZW5zaXR5X3JpZGdlcygtLS0pCiAgICBgYGAKICAgIAogICAgV2hpY2ggb2YgdGhlIGZvbGxvd2luZyByZXBsYWNlbWVudHMgZm9yIGAtLS1gIHByb2R1Y2VzIGRlbnNpdHkKICAgIHJpZGdlcyB3aXRoIGxpbmVzIHNob3dpbmcgdGhlIGxvY2F0aW9ucyBvZiB0aGUgbWVkaWFucz8KICAgIAogICAgYS4gYHF1YW50aWxlcyA9IDAuNWAKICAgIGIuIGBxdWFudGlsZV9saW5lcyA9IFRSVUUsIHF1YW50aWxlcyA9IDAuNWAKICAgIGMuIGBxdWFudGlsZV9saW5lcyA9IFRSVUVgCiAgICBkLiBgZHJhd19xdWFudGlsZXMgPSAwLjVgCgo8IS0tCmJveHBsb3RzCnZpb2xpbiBwbG90cwoKcG8gPC0gZnVuY3Rpb24ocHJvYiwgcXVhbnQpIHsKICAgIHEyNSA8LSBxdWFudCgwLjI1KQogICAgcTc1IDwtIHF1YW50KDAuNzUpCiAgICBtZCA8LSBxdWFudCgwLjUpCiAgICBJUVIgPC0gcTc1IC0gcTI1CiAgICB1b3AgPC0gcHJvYihxNzUgKyAxLjUgKiBJUVIsIGxvd2VyLnRhaWwgPSBGQUxTRSkKICAgIGxvcCA8LSBwcm9iKHEyNSAtIDEuNSAqIElRUikKICAgIGMobG9wLCB1b3ApCn0KLS0+Cg==

This work is licensed under the CC BY-NC 3.0 Creative Commons License.

Visualizing Distributions (2024)
Top Articles
How Do Banks Trade Forex - Insider Strategies Revealed
How to Find Your Money Corner
How To Start a Consignment Shop in 12 Steps (2024) - Shopify
Jail Inquiry | Polk County Sheriff's Office
The Largest Banks - ​​How to Transfer Money With Only Card Number and CVV (2024)
Alpha Kenny Buddy - Songs, Events and Music Stats | Viberate.com
His Lost Lycan Luna Chapter 5
سریال رویای شیرین جوانی قسمت 338
Local Dog Boarding Kennels Near Me
Panorama Charter Portal
Patrick Bateman Notebook
Carolina Aguilar Facebook
Walmart Car Department Phone Number
Icivics The Electoral Process Answer Key
Lakers Game Summary
Laveen Modern Dentistry And Orthodontics Laveen Village Az
Www.publicsurplus.com Motor Pool
Boston Dynamics’ new humanoid moves like no robot you’ve ever seen
Shadbase Get Out Of Jail
Southland Goldendoodles
Asteroid City Showtimes Near Violet Crown Charlottesville
Jesus Revolution Showtimes Near Regal Stonecrest
Hdmovie2 Sbs
800-695-2780
2023 Ford Bronco Raptor for sale - Dallas, TX - craigslist
Danielle Moodie-Mills Net Worth
Keshi with Mac Ayres and Starfall (Rescheduled from 11/1/2024) (POSTPONED) Tickets Thu, Nov 1, 2029 8:00 pm at Pechanga Arena - San Diego in San Diego, CA
WPoS's Content - Page 34
Funky Town Gore Cartel Video
FREE Houses! All You Have to Do Is Move Them. - CIRCA Old Houses
Street Fighter 6 Nexus
Slv Fed Routing Number
Gerber Federal Credit
Gideon Nicole Riddley Read Online Free
Appleton Post Crescent Today's Obituaries
Polk County Released Inmates
Personalised Handmade 50th, 60th, 70th, 80th Birthday Card, Sister, Mum, Friend | eBay
Marcus Roberts 1040 Answers
Jasgotgass2
Atom Tickets – Buy Movie Tickets, Invite Friends, Skip Lines
Bunkr Public Albums
SF bay area cars & trucks "chevrolet 50" - craigslist
Kutty Movie Net
Payrollservers.us Webclock
R: Getting Help with R
Arcanis Secret Santa
The Quiet Girl Showtimes Near Landmark Plaza Frontenac
Theater X Orange Heights Florida
Rubmaps H
Bumgarner Funeral Home Troy Nc Obituaries
Intuitive Astrology with Molly McCord
Latest Posts
Article information

Author: Aron Pacocha

Last Updated:

Views: 5758

Rating: 4.8 / 5 (68 voted)

Reviews: 91% of readers found this page helpful

Author information

Name: Aron Pacocha

Birthday: 1999-08-12

Address: 3808 Moen Corner, Gorczanyport, FL 67364-2074

Phone: +393457723392

Job: Retail Consultant

Hobby: Jewelry making, Cooking, Gaming, Reading, Juggling, Cabaret, Origami

Introduction: My name is Aron Pacocha, I am a happy, tasty, innocent, proud, talented, courageous, magnificent person who loves writing and wants to share my knowledge and understanding with you.