Stack Overflow Developer Survey 2020
Each year, Stack Overflow surveys its users, who are primarily
software developers, about themselves, how they use Stack Overflow,
their work, and the development tools they use. In this analysis we’ll
look at a subset of the survey responses, from users who identified as
Data Scientists.
# Load libraries
library(tidyr)
library(dplyr)
library(ggplot2)
library(fst)
library(tibble)
library(readr)
stack_overflow <- read_rds(ruta_stckov)
stack_overflow
colnames(stack_overflow)
[1] "respondent" "age_first_code_cut" "converted_comp" "job_sat" "purple_link" "age_cat" "age"
[8] "hobbyist"
glimpse(stack_overflow)
Rows: 2,261
Columns: 8
$ respondent <dbl> 36, 47, 69, 125, 147, 152, 166, 170, 187, 196, 221, 235, 262, 265, 271, 277, 322, 349, 414, 448, 518, 559, 563, 587, 607, 637, 653, 6…
$ age_first_code_cut <chr> "adult", "child", "child", "adult", "adult", "adult", "child", "adult", "child", "adult", "adult", "adult", "child", "adult", "adult"…
$ converted_comp <dbl> 77556, 74970, 594539, 2000000, 37816, 121980, 48644, 130000, 94539, 1920000, 48644, 54049, 171000, 125000, 85000, 165000, 4188, 13000…
$ job_sat <fct> Slightly satisfied, Very satisfied, Very satisfied, Very satisfied, Very satisfied, Very satisfied, Neither, Very satisfied, Slightly…
$ purple_link <chr> "Hello, old friend", "Hello, old friend", "Hello, old friend", "Amused", "Hello, old friend", "Hello, old friend", "Hello, old friend…
$ age_cat <chr> "At least 30", "At least 30", "Under 30", "At least 30", "Under 30", "Under 30", "Under 30", "Under 30", "At least 30", "Under 30", "…
$ age <dbl> 34, 53, 25, 41, 28, 30, 28, 26, 43, 23, 24, 35, 37, 51, 22, 43, 24, 27, 24, 41, 27, 37, 29, 28, 25, 46, 36, 31, 28, 31, 21, 54, 32, 3…
$ hobbyist <chr> "Yes", "Yes", "Yes", "Yes", "No", "Yes", "Yes", "Yes", "Yes", "Yes", "Yes", "Yes", "Yes", "Yes", "Yes", "No", "Yes", "Yes", "Yes", "Y…
Hypothesizing about the mean
Let’s hypothesize that the mean annual compensation of the population
of data scientists is $110000. The first thing we can do to check this
is to examine the sample data in the survey. Annual compensation,
converted to dollars, is included in the converted_comp column. The
sample mean is a type of point estimate, which is another name for a
summary statistic. You can calculate it with base-R, or more verbosely
with dplyr. Either way, the answer is $122000. That’s different from our
hypothesis, but is it meaningfully different?
mean_comp_samp <- mean(stack_overflow$converted_comp)
mean_comp_samp
[1] 119574.7
mean_comp_samp <- stack_overflow %>%
summarise(mean_compensation = mean(converted_comp)) %>%
pull(mean_compensation)
mean_comp_samp
[1] 119574.7
Generating a bootstrap distribution
To answer this, we need to generate a bootstrap distribution of
sample means. This is done by resampling the dataset, calculating the
sample mean for that resample, then repeating those steps.
# Repeat steps 1 & 2 many times
so_boot_distn <- replicate(
n = 5000,
expr = {
#Step 1. Resample
stack_overflow %>%
slice_sample(prop = 1, replace = TRUE) %>%
# Step 2. Calculate point estimate
summarise(mean_compensation = mean(converted_comp)) %>%
pull(mean_compensation)
}
)
head(so_boot_distn)
[1] 121172.8 122346.3 115986.9 120278.9 115449.6 118904.6
Visualizing the bootstrap distribution
Here’s a histogram of the bootstrap distribution. Its bell shape
means it’s roughly normally distributed. Notice that \(110000\) is on the left of the
distribution.
tibble(resample_mean = so_boot_distn) %>%
ggplot(aes(resample_mean)) +
geom_histogram(binwidth = 1000)

Standard Error
Recall that the standard deviation of the sample statistics in the
bootstrap distribution estimates the standard error of the
statistic.
std_error <- sd(so_boot_distn)
std_error
[1] 5508.39
Z-scores
Since variables have arbitrary units and ranges, before we test our
hypothesis, we need to standardize the values. A common way of
standardizing values is to subtract the mean, and
divide by the standard deviation. For hypothesis
testing, we use a variation where we take the sample statistic,
subtract the hypothesized parameter value, and divide by the standard
deviation of the statistic, which is the standard
error. The result is called a z-score. The
sample mean annual compensation for data scientists of $122000 , minus
the hypothesized compensation for data scientists of $110000, divided by
the bootstrap standard error of $5590 gives a z-score 1.71
mean_comp_hyp <- 110000
mean_comp_samp
[1] 119574.7
z_score <- (mean_comp_samp - mean_comp_hyp) / std_error
z_score
[1] 1.738206
Testing the hypothesis
Is that a big or small number? Determining that is the goal of this
course. In particular, we can now state one of the uses of hypothesis
testing. Determining whether a sample statistic is close to or far away
from an expected value.
Standard normal (z) distribution
Here’s a density plot of the probability density function for the
standard normal distribution. That is, a normal distribution with mean
zero and standard deviation one. It’s often called the z-distribution.
As you might guess, z-scores are related to the z-distribution.
# Create a dataset of z-distribution and plot it
tibble(x = seq(-4, 4, 0.01)) %>%
ggplot(aes(x)) +
stat_function(fun = dnorm) +
ylab("PDF(x)")

P-values
Hypothesis tests are like criminal trials.
The true situation is that the defendant committed the crime, or they
didn’t. There are also two possible outcomes. The judge gives a guilty
or a not guilty verdict. The initial assumption is that the defendant is
not guilty. It’s up to the prosecution team to come up with evidence
beyond a reasonable doubt that the defendant committed the crime in
order for a guilty verdict to be given.
Age of first programming experience
Let’s return to our survey. The age_first_code_cut
variable classifies when the user began programming. If they were 14 or
older, they are classified as “adult”; otherwise
“child”.
Suppose previous research suggests that 35% of software developers
programmed as children. This raises a question answerable with our
dataset.
Does our sample provide evidence that data scientists have a
greater proportion starting programming as a child?
Definitions
Hypothesis is a statement about a population
parameter. We don’t know the true value of this population
parameter; we can only make inferences about it from the data.
Hypothesis tests compare two competing hypotheses.
These two hypotheses are the null hypothesis,
representing the existing idea, and the alternative
hypothesis, representing a new idea.
They are denoted \(H_{0}\) and \(H_{A}\) respectively. The null
hypothesis is like the current champion, and the alternative hypothesis
is like a challenger trying to overthrow that champion. Here,
the null hypothesis is that our data won’t tell us anything new, and
that the proportion of data scientists starting programming as children
follows the previous research on software developers, at 35%. The
alternative hypothesis is that our hunch is correct, and that the
percentage is greater than 35%.
Criminal trials vs. Hypothesis Testing
Let’s compare the criminal trial with the hypothesis test. The
defendant committing the crime is equivalent to the alternative
hypothesis being true, and the defendant not committing the
crime is equivalent to the null hypothesis being true.
Rather than saying we accept the alternative hypothesis, the
verdicts are rejecting the null hypothesis, or failing
to reject the null hypothesis. Initially, we assume that the
null hypothesis is true, and this only changes if the sample provides
enough evidence to reject it.
The hypothesis testing equivalent of “beyond a reasonable doubt” is
known as the significance level.
One-tailed & two-tailed tests
The tails of a distribution are the left and right edges of its PDF.
Hypothesis tests determine whether the sample statistics lie in
the tails of the distribution. There are three types of tests,
and the phrasing of the alternative hypothesis determines which type you
should use. In this case, we need a right-tailed
test.
P-values
p-values measure the strength of support for the
null hypothesis. Small p-values mean our statistic is producing
an unlikely result in a tail of our null distribution.
p-values are probabilities, so they are always
between zero and one.
Defining p-values
The definition of a p-value has four parts. It’s a probability
related to where the statistic from our sample lies on the null
distribution. It measures how many values fall farther away than
what we observed in the direction of the alternative
hypothesis. It is based on the null distribution, which assumes
that the null hypothesis is true. The p-value measures
evidence. Does it favor the original assumption or the new
alternative?
Calculating the z-score
To calculate the p-value, we need to run through the
same steps as before. We get the sample statistic, in
this case the proportion of data scientists who started
programming as children. We get the hypothesized value from the
null hypothesis, \(35\%\). We get the
standard error from the bootstrap distribution. The
z-score is the difference between the proportions,
divided by the standard error.
prop_child_samp <- stack_overflow %>%
summarise(point_estimate = mean(age_first_code_cut == "child")) %>%
pull(point_estimate)
prop_child_samp
[1] 0.3914197
sd_boot_distn <- replicate(
n = 5000,
expr = {
#Step 1. Resample
stack_overflow %>%
slice_sample(prop = 1, replace = TRUE) %>%
# Step 2. Calculate point estimate
summarise(sample_mean = mean(age_first_code_cut == "child")) %>%
pull(sample_mean)
}
)
head(sd_boot_distn)
[1] 0.3958425 0.3918620 0.4073419 0.3808050 0.3927466 0.3900929
std_err = sd(sd_boot_distn)
std_err
[1] 0.01026421
prop_child_hyp <- 0.35
#std_err <- 0.0096028
z_score <- (prop_child_samp - prop_child_hyp) / std_err
z_score
[1] 4.035356
Calculating the p-value
The last step is new. We pass the z-score to the normal cumulative
distribution function, pnorm. Since we want the right-hand tail for this
test, we set lower-dot-tail to FALSE. The p-value is 8.04 e -10 That’s a
very small number, but is it small enough to reject the null
hypothesis?
p_value <- pnorm(z_score, lower.tail = FALSE)
p_value
[1] 2.725982e-05
Statistical significance
p-values quantify how much evidence there is for the
null hypothesis. Large p-values lead us to not have enough
evidence for the alternative hypothesis, sticking with the
assumed null hypothesis instead. Small p-values make us doubt
this original assumption in favor of the alternative
hypothesis. What defines the cutoff point between a small
p-value and a large one?
Significance level
The cutoff point is known as the significance level,
and is denoted alpha (α). The appropriate significance
level depends on the dataset and the discipline you are working in.
5% is the most common choice, but 10%
and 1% are also popular. The significance level gives
us a decision process for which hypothesis to support. If the
p-value is less than alpha, we reject the null
hypothesis. Otherwise we fail to reject it.
It’s important that you decide what the appropriate significance
level should be before you run your test. Otherwise there is a
temptation to decide on a significance level that lets you choose the
hypothesis you want.
Calculating the p-value
The workflow is now to set the significance level, in this case 0.05.
Then calculate the z-score and use the standard normal CDF to get the
p-value. In this case, the p-value of 8 e-06 is less
than or equal to point-zero-five, so we reject the null hypothesis. We
have strong evidence for the alternative hypothesis that the proportion
of data scientists starting programming as children is greater than
35%.
alpha <- 0.05
prop_child_samp <- stack_overflow %>%
summarise(point_estimate = mean(age_first_code_cut == "child")) %>%
pull(point_estimate)
prop_child_hyp <- 0.35
std_error <- 0.0096028
z_score <- (prop_child_samp - prop_child_hyp) / std_error
p_value = pnorm(z_score, lower.tail = FALSE)
p_value
[1] 8.041901e-06
p_value <= alpha
[1] TRUE
\[
p-value \ is \ less \ than \ or \ equal \ to \ \alpha, so \ reject \
H_{0} \ and \ accept \ H_{A}
\]
Confidence intervals
To get a sense as to potential values of the population parameter,
it’s common to choose a confidence interval of one minus the
significance level. For a significance level of 0.05,
we’d use a 95% confidence interval. Here’s the calculation using the
quantile method. The interval runs from 0.37 to
0.41 giving a range of plausible values for the
proportion of data scientists starting programming as children.
first_code_boot_samp <- replicate(
n = 5000,
expr = {
stack_overflow %>%
slice_sample(prop = 0.25, replace = TRUE) %>%
summarise(point_estimate = mean(age_first_code_cut == "child")) %>%
pull(point_estimate)
}
)
first_code_boot_distn <- tibble(first_code_child_rate = first_code_boot_samp)
head(first_code_boot_distn)
conf_int <- first_code_boot_distn %>%
summarise(lower = quantile(first_code_child_rate, 0.025),
upper = quantile(first_code_child_rate, 0.975))
conf_int
Types of errors
Returning to the criminal trial analogy, there are two possible truth
states and two possible outcomes, for four combinations in total. Two of
these indicate that the verdict was correct. If a defendant didn’t
commit the crime, but the verdict was guilty, they are wrongfully
convicted. If the defendant committed the crime but the verdict was not
guilty, they got away with it. These are both errors in justice.
Similarly, for hypothesis testing, there are two ways to get it right,
and two types of error. If you support the alternative hypothesis when
the null hypothesis was correct, you made a false positive error. If you
support the null hypothesis when the alternative hypothesis was correct,
you made a false negative error. These errors are sometimes known as
type one and type two errors.
Choosen H0 |
correct |
false negative |
Choosen HA |
false positive |
correct |
Possible errors in our example
\[
if \ p \leqslant \alpha, we \ reject \ \ H_{0}
\]
A false positive (Type I) error could have ocurred: We thought that
data scientists starting coding as children at a higher rate when in
reality they did not
\[
if \ p > \alpha, \ we \ fail \ to \ reject \ H_{0}
\]
A false negative (Type II) error could have ocurred: we thought that
data scientists coded as children at the same rate as software engineers
when in reality they coded as children at a higher rate.
Hypotheses
The null hypothesis is that the sample mean for the two
groups is the same, and the alternative hypothesis is that
the sample statistic for users who started coding as children is
greater than for users who started coding as adults. We can
write these hypotheses using equations. Mu (µ)
represents an unknown population mean, and we use subscripts to denote
which group the sample mean belongs to. An alternate way of writing the
equations is to compare the differences in sample means to zero.
Calculating group wise summary statistics
Calculating the summary statistics for each group is straightforward.
You start with the sample, group by the categorical variable, then
summarize the numeric variable. A dplyr
way of doing this
is shown, but there are many possibilities. Pause the video for a moment
and think about different ways of solving this. Here, the child
programmers have a mean compensation of $132419.6 dollars compared to
$111313.3 for adult programmers. Is that increase statistically
significant or could it be explained by sampling variability?
stack_overflow %>%
group_by(age_first_code_cut) %>%
summarise(mean_compensation = mean(converted_comp))
Test statistics
Although we don’t know the population mean, we estimate it
using the sample mean. x-bar is used to denote
a sample mean. Then we use subscripts to denote which group a sample
mean corresponds to. The difference between these two sample
means is called the test statistic for the hypothesis test. The
z-scores are another type of test statistic.
Standardizing the test statistic
z-scores are calculated by taking the sample statistic, subtracting
the mean of this statistic as the population parameter of interest, then
dividing by the standard error. In the two sample case, the test
statistic, denoted t, uses a similar equation. You take the difference
between the sample statistics for the two groups, subtract the
hypothesized difference between the two groups, then divide by the
standard error. \[
x =
\frac{sample \ stat + population \ parameter}{standard \ error}
\]
\[
t = \frac{difference \ in \ sample \ stats \ - difference \ in \
population \ parameters}{standard \ error}
\]
\[
t = \frac{(\bar{x}_{child} \ - \bar{x}_{adult}) \ - (\mu_{child} \ -
\mu_{adult})}{SE(\bar{x}_{child} \ - \bar{x}_{adult})}
\]
Standard Error
To calculate the standard error, needed for the denominator of the
test statistic equation, bootstrapping is most accurate. However, there
is an easier way to approximate it. You calculate the standard deviation
of the numeric variable for each group in the sample, and the number of
observations for each group. Then it’s just some arithmetic.
Assuming the null hypothesis is true
Here’s the test statistic equation again. If we assume that the
null hypothesis is true, there’s a simplification we
can make. The null hypothesis assumes that the population means
are equal. That makes one term in the numerator disappear.
Using the approximation for the standard error, we now have a way of
calculating the test statistic using only calculations on the sample
dataset. We need the mean, standard deviation, and number of
observations for each group. This is another group-by and summarize
combination. \[
SE(\bar{x}_{child} \ - \bar{x}_{adult}) \approx
\sqrt{\frac{s^2_{child}}{n_{child}} \ + \frac{s^2_{adult}}{n_{adult}}}
\] \[
H_{0}: \mu_{child} \ - \mu_{adult} = 0
\]
\[
t = \frac{(\bar{x}_{child} \ - \bar{x}_{adult})}{SE(\bar{x}_{child} \ -
\bar{x}_{adult})}
\]
\[
t = \frac{(\bar{x}_{child} \ -
\bar{x}_{adult})}{\sqrt{\frac{s^2_{child}}{n_{child}}} \ +
\frac{s^2_{adult}}{n_{adult}}}
\]
group_tests <- stack_overflow %>%
group_by(age_first_code_cut) %>%
summarise(x_bar = mean(converted_comp), s = sd(converted_comp), n = n())
# See the results
group_tests
Calculating the test statistic
Annoyingly, it requires some grim data manipulation code to calculate
the test statistic from this data frame. Since this isn’t a course on
data manipulation, let’s do the calculation with separate variables. The
numerator is a simple subtraction, and the denominator is like a
weighted hypotenuse. The t-statistic is 1.86. Just as
with z-scores, we can’t do anything with that number yet
\[
t = \frac{(\bar{x}_{child} \ -
\bar{x}_{adult})}{\sqrt{\frac{s^2_{child}}{n_{child}} \ +
\frac{s^2_{adult}}{n_{adult}}}}
\]
numerator <- group_tests$x_bar[2] - group_tests$x_bar[1]
denominator <- sqrt((group_tests$s[2]^2 / group_tests$n[2]) + (group_tests$s[1]^2 / group_tests$n[1]))
t_stat <- numerator / denominator
t_stat
[1] 1.869931
Hypothesis testing workflow
Identify population parameter that is hypothesized about
Specify the null & alternative hypothesis
Determine (standardized) test statistic & corresponding null
distribution
Conduct hypothesis test in R
Measure evidence against the null hypothesis
Make a decision comparing evidence to significance level
Interpret the results in the context of the original
problem
Calculating p-values from t-statistics
The test statistic, t, follows a t-distribution. t-distributions have
a parameter called the degrees of freedom, or
df for short. Here’s a line plot of the PDF of a
t-distribution with one degree of freedom in yellow, and the PDF of a
normal distribution in blue dashes. Notice that the t-distribution for
small degrees of freedom has fatter tails than the normal distribution,
but otherwise they look similar.
Degrees of freedom
As you increase the degrees of freedom, the t-distribution gets
closer to the normal distribution. In fact, a normal
distribution is a t-distribution with infinite degrees of
freedom. Degrees of freedom are defined as the maximum
number of logically independent values in the data sample.
That’s a fairly tricky concept, so let’s try an example.
Calculating degrees of freedom
Suppose your dataset has 5 independent observations. Four of the
values are 2, 6, 8, and 5. You also know the sample mean is 5. The last
value is no longer independent; it must be 4. Even though all five
observations in the sample were independent, because you know an
additional fact about it, you only have 4 degrees of freedom. In our two
sample case, there are as many degrees of freedom as observations, minus
two because we know two sample statistics.
Hypotheses
Recall the hypotheses for our Stack Overflow question about
compensation for the two age groups. Since this is a “greater than”
alternative hypothesis, we need a right-tailed test.
\(H_{0}:\) The mean compensation
(in USD) is the same for those that coded first as a child and those
that coded first as an adult.
\(H_{A}:\) The mean compensation
(in USD) is greater for those that coded first as a
child compared to those that coded first as an adult.
Use a right-tailed test
Significance level
We’re going to calculate a p-value in a moment. We need to decide on
a significance level before we do that. There are several possibilities;
I’m going to use 0.1
That means that if the p-value is less than point-one, we reject the
null hypothesis in favor of the alternative.
\[\alpha = 0.1\]
\[
if \ p \leqslant \alpha \ then \ reject \ H_{0}
\]
Calculating p-values: One proportion vs. a
value
p_value <- pnorm(z_score, loer.tail = FALSE)
Calculating p-values: Two means from different
groups
\[
t = \frac{(\bar{x}_{child} \ -
\bar{x}_{adult})}{\sqrt{\frac{s^2_{child}}{n_{child}} \ +
\frac{s^2_{adult}}{n_{adult}}}}
\]
Now we are calculating means rather than proportions, the z-score is
replaced with a t-test statistic. The calculation also needs the degrees
of freedom, which is the number of observations in both groups, minus
two.
In the previous steps, we used an approximation using sample
information (not bootstrapping) for the test statistic standard error. A
consequence of this is that to calculate the p-value, we need to
transform the test statistic using the t-distribution CDF instead of the
normal distribution CDF. Using this approximation adds more uncertainty
and that’s why this is a t instead of a z problem.
The t distribution allows for more uncertainty when using multiple
estimates in a single statistic calculation. Notice the use of
pt()
instead of pnorm()
, and that the df
argument is set to the degrees of freedom. This p-value is less than the
significance level of 0.1, we should reject the null
hypothesis in favor of the alternative hypothesis that Stack Overflow
data scientists who started coding as a child earn more.
numerator <- group_tests$x_bar[2] - group_tests$x_bar[1]
denominator <- sqrt((group_tests$s[2]^2 / group_tests$n[2]) + (group_tests$s[1]^2 / group_tests$n[1]))
t_stat <- numerator / denominator
t_stat
[1] 1.869931
degrees_of_freedom <- group_tests$n[2] + group_tests$n[1] - 2
degrees_of_freedom
[1] 2259
p_value <- pt(t_stat, df = degrees_of_freedom, lower.tail = FALSE)
p_value
[1] 0.0308113
Why is t needed?
The process for calculating p-values is to start with the sample
statistic, standardize it to get a test statistic, then transform it via
a cumulative distribution function. Previously, that final
transformation was denoted z
, and the CDF transformation
used the (standard normal) z-distribution. The test statistic was
denoted t
, and the transformation used the
t-distribution.
In which hypothesis testing scenario is a t-distribution needed
instead of the z-distribution?
Using a sample standard deviation to estimate the standard
error is computationally easier than using bootstrapping. However, to
correct for the approximation, you need to use a t-distribution when
transforming the test statistic to get the p-value.
One-sample proportion tests
The previous example tested a single proportion against a specific
value. As with means, we can also test differences between proportions
in two populations.
Recap
The previous hypothesis tests measured whether or not an
unknown population proportion was equal to some value. We used
a bootstrap distribution of the sample to estimate the standard
error of the sample statistic. The standard error was used to
calculate a standardized test statistic, which was used to get a
p-value, which was used to decide whether or not to reject the null
hypothesis. Bootstrap distributions can be computationally intensive to
calculate, so this time we’ll calculate the test statistic without
it.
Standardized test statistic for proportions
An unknown population parameter that is a proportion, or
population proportion for short, is denoted p
. The
sample proportion is denoted \(\hat{p}\), and the hypothesized value for
the population proportion is denoted \(p_{0}\) . As seen previously, the
standardized test statistic is a z-score. You calculate it by
starting with the sample statistic, subtracting its mean, then dividing
by its standard error.
\(\hat{p}\) minus the mean of \(\hat{p}\) , divided by the standard error
of \(\hat{p}\) .
Recall from Sampling in R, the mean of \(\hat{p}\) is \(p\). Under the null hypothesis, the unknown
proportion p is assumed to be the hypothesized population parameter
\(p_{0}\). The z-score is now \(\hat{p}\) minus \(p_{0}\), divided by the standard error of
\(\hat{p}\).
\(p\) : Sample proportion
\(\hat{p}\) : sample proportion
(sample statistic)
\(p_{0}\) : hypothesized population
proportion
\[ z = \frac{\hat{p} \ -
mean(\hat{p})}{standard \ error(\hat{p})} = \frac{\hat{p} \ -
p}{standard \ error(\hat{p})} \]
Assuming \(H_{0}\) is true. \(p = p_{0}\). so
\[ z = \frac{\hat{p} \ - p_{0}}{standard \
error(\hat{p})} \]
Easier standard error calculations
Here’s the approximate standard error for two sample means. For
proportions, under \(H_{0}\), the
standard error of \(\hat{p}\) is \(p_{0}\) times \(1
- p_{0}\) , divided by the number of observations, then
square-rooted. We can substitute this into our equation for the z-score.
This is easy to calculate because it only uses \(\hat{p}\) and \(n\), which we get from the sample, and
\(p_{0}\), which we chose.
\[ SE(\bar{x}_{child} \ - \bar{x}_{adult})
\approx \sqrt{\frac{s^2_{child}}{n_{child}} \ +
\frac{s^2_{adult}}{n_{adult}}} \]
\[ SE_{\hat{p}} \ = \sqrt{\frac{p_{0} \ *
(1 - p_{0})}{n}} \]
Assuming \(H_{0}\) is TRUE,
\[ z \ = \frac{\hat{p} \ -
p_{0}}{\sqrt{\frac{p_{0} \ * \ (1 \ - p_{0})}{n}}} \]
This only uses sample information (\(\hat{p}\) and \(n\)) and the hypothesized parameter (\(p_{0}\))
Why z instead of t?
Why we used a z-distribution here, but a t-distribution previously?.
This is the test statistic equation for the two sample mean
case. The standard deviation of the sample, s,
is calculated from the sample mean, \(\bar{x}\). That means that \(\bar{x}\) is used in the numerator to
estimate the population mean, and in the denominator to estimate the
population standard deviation. This dual usage causes an increase in our
uncertainty about the estimate of the population parameter. Since
t-distributions are effectively a normal distribution with fatter tails,
we can use them to account for this extra uncertainty. In effect, the
t-distribution provides extra caution against mistakenly rejecting the
null hypothesis. For proportions, we only use \(\hat{p}\) in the numerator, thus avoiding
the problem with uncertainty, and a z-distribution is fine.
\[ t \ = \frac{(\bar{x}_{child} \ -
\bar{x}_{adult})}{\sqrt{\frac{a^2_{child}}{n_{child}} \ +
\frac{s^2_{adult}}{n_{adult}}}} \]
\(s\) is calculated from \(\bar{x}\), so \(\bar{x}\) is used to estimate the
population mean and to estimate the population standard
deviation
This increases the uncertainty in our estimate of the population
parameter.
t-distribution has fatter tails than a normal
distribution
This gives an extra level of caution
\(\hat{p}\) only appears in the
numerator, so z-scores are fine
Stack overflow age categories
Let’s hypothesize that half the users are under thirty. We’ll set a
significance level of 0.01. Just over half the users are under
thirty.
\(H_{0}\) : The proportion of SO
users under thirty is equal to 0.5
\(H_{A}\) : The proportion of SO
users under thirty is not equal to 0.5
alpha <- 0.01
stack_overflow %>%
count(age_cat)
Variables for z
Let’s get the numbers needed for the z-score. \(\hat{p}\) is the proportion of rows in the
sample where age_cat equals under thirty. \(p_{0}\) is 0.5 according to the null
hypothesis. n is the number of rows in the dataset.
p_hat <- stack_overflow %>%
summarise(prop_under_30 = mean(age_cat == "Under 30")) %>%
pull(prop_under_30)
p_hat
[1] 0.5356037
p_0 <- 0.5
n <- nrow(stack_overflow)
n
[1] 2261
Calculating the z-score
Calculating the z-score is just arithmetic; the value is
three-point-five.
\[ z \ = \frac{\hat{p} \ -
p_{0}}{\sqrt{\frac{p_{0} \ * \ (1 \ - p_{0})}{n}}} \]
numerator <- p_hat - p_0
denominator <- sqrt((p_0 * (1 - p_0)) / n)
z_score <- numerator / denominator
z_score
[1] 3.385911
Calculating the p-value
For left-tailed alternative hypotheses, you transform the z-score
into a p-value using the pnorm with the default of lower-dot-tail equals
TRUE. For right-tailed alternative hypotheses you set lower-dot-tail to
FALSE. For two-tailed alternative hypotheses, you check whether the test
statistic lies in either tail, so the p-value is the sum of these two
values. Since the normal distribution PDF is symmetric, here this
simplifies to twice the left-tailed p-value. Here, the p-value is less
than the significance level of point-zero-one, so we reject the null
hypothesis and conclude that the proportion of users under thirty is not
equal to point-five.
# Left tailed ("less than")
p_value_less <- pnorm(z_score)
p_value_less
[1] 0.9996453
# Right tailed ("greater than")
p_value <- pnorm(z_score, lower.tail = FALSE)
p_value
[1] 0.0003547114
# Two-tailed ("not equal")
p_value_2t <- pnorm(z_score) + pnorm(z_score, lower.tail = FALSE)
p_value_2t
[1] 1
p_value_a <- 2 * pnorm(z_score)
p_value_a
[1] 1.999291
p_value <= alpha
[1] TRUE
Two sample proportion tests
The previous example tested a single proportion against a
specific value. As with means, we can also test differences
between proportions in two populations.
Comparing two proportions
The Stack Overflow survey contains a hobbyist variable. The value
“Yes” means the user described themself as a hobbyist; “No” means they
described themself as a professional. We can hypothesize that
the proportion of users who are hobbyists is the same for the under
thirty age category as the at least thirty category.
More formally, the null hypothesis is that the difference
between the population parameters for each group is zero. I’ve
set a significance level of 0.05.
\(H_{0}\) : The proportion of SO
users who are hobbyists is the same for those under thirty as those at
least thirty
\[
H_{0}: p_{\geq 30} \ - p_{< 30} \ = 0
\]
\(H_{A}\) : The proportion of SO
users who are hobbyists is different for those under thirty as those at
least thirty
\[
H_{A}: p_{\geq 30} \ - p_{<30} \neq 0
\]
Calculating the z-score
Let’s break down this z-score equation. The sample statistic is the
difference in the proportions for each category \((\hat{p}_{\geq30} \ - \hat{p}_{<30}) \ -
0\). That’s the two \(\hat{p}\)
values on the numerator. We subtract the hypothesized value of the
population parameter. Assuming the null hypothesis is true,
that’s just zero, so the term disappears. The
denominator is the standard error of the sample statistic \(SE(\hat{p}_{\geq30} \ -
\hat{p}_{<30})\).
Again we can avoid having to generate a bootstrap distribution. The
equation for the standard error is a slightly more complicated version
of the equation for the one sample case. In this equation, note that
p-hat is the sample proportion for the whole dataset, not for each
category. This whole dataset \(\hat{p}\) is known as a pooled
estimate of the population proportion. We need one more
equation to get \(\hat{p}\). It’s a
weighted mean of the p-hats for each category. This looks horrendous,
but it’s just arithmetic, and R is pretty good at that. The good news is
that we only need four numbers from the sample dataset to do these
calculations.
\[
z = \frac{(\hat{p}_{\geq30} \ - \hat{p}_{<30}) \ -
0}{SE(\hat{p}_{\geq30} \ - \hat{p}_{<30})}
\]
\[
SE(\hat{p}_{\geq0} \ - \hat{p}_{<0}) \ = \sqrt{\frac{\hat{p} \times \
(1 \ - \hat{p})}{n_{\geq30}} \ + \frac{\hat{p} \times \ (1 \ -
\hat{p})}{n_{<30}}}
\]
\(\hat{p}\) is a pooled estimate for
\(p\) (common unknown proportion of
successes)
\[
\hat{p} \ = \frac{n_{\geq30} \times \hat{p}_{\geq30} \ + n_{<30}
\times \hat{p}_{<30}}{n_{\geq30} \ + n_{<30}}
\]
We only need to calculate 4 numbers: \(\hat{p}_{\geq30}, \ \hat{p}_{<30}, \
n_{\geq30}, \ n_{<30}\)
Getting the numbers for the z-score
To calculate these four numbers you group_by()
the
categories, and summarize to calculate the sample proportion and row
counts. After that, you can do the arithmetic to get the test statistic
- the z-score is minus four-point-two - and call pnorm to get the
p-value. I’m not going to run through these steps because it’s exactly
the same as you’ve seen already. Instead, I’ll show you an easier
way.
stack_overflow %>%
group_by(age_cat) %>%
summarise(p_hat = mean(hobbyist == "Yes"), n = n())
Proportion tests using
prop_test()
Naturally, R has at least two functions for performing this
type of hypothesis test, known as a proportion
test. Base-R has a function named prop.test()
,
though unfortunately, its interface is somewhat peculiar. To
make your life easier it’s best to use prop_test()
from
infer. This takes a formula, with your numeric variable
on the left and the categories on the right. The order argument
specifies which \(\hat{p}\) should be
subtracted from the other. Here, it is specified so that you start with
the “at least thirty” \(\hat{p}_{\geq30}\) , then subtract the
“under thirty” \(\hat{p}_{<30}\)
The success
argument specifies which of the two
response levels to get the proportion of.
alternative
takes the same values as t-test. Here,
we have a two-sided alternative hypothesis. The
correct
argument specifies whether or not to apply
Yates’ continuity correction. This is a fudge factor
needed for technical reasons when the sample size is very
small. Since each group has over one thousand
observations, we don’t need it. The p-value is in the third
column of the resulting tibble. It’s smaller than the significance level
we specified earlier, so we can conclude that there is a
difference in the proportion of Stack Overflow hobbyists between the
under and over thirty groups.
library(infer)
stack_overflow %>%
prop_test(hobbyist ~ age_cat, order = c("At least 30", "Under 30"), success = "Yes",
alternative = "two-sided", correct = FALSE)
Chi-square test of independence
Just as ANOVA extends t-tests to more than two groups, chi-square
tests of independence extend proportion tests to more than two
groups.
Revisiting the proportion test
Here’s the proportion test from last time. In the first column, the
test statistic is the square of the z-score. Minus four-point-two-two
squared is seventeen-point-eight. In the second column, chisq_df means
the degrees of freedom of a chi-square test. Its value is one.
library(infer)
stack_overflow %>%
prop_test(hobbyist ~ age_cat, order = c("At least 30", "Under 30"), alternative = "two-sided", correct = FALSE)
Independence of variables
That proportion test had a positive result. There was evidence that
the hobbyist and age category variables had an association. If that
wasn’t the case, and the proportion of hobbyists was the same for each
age category, the variables would be considered statistically
independent. More formally, statistical independence of two
categorical variables is when the proportion of successes in the
response variable is the same across all categories of the explanatory
variable.
Job satisfaction and age category
Recall that the Stack Overflow sample has an age category variable
with two categories and a job satisfaction variable with five
categories.
stack_overflow %>%
count(age_cat)
stack_overflow %>%
count(job_sat)
Declaring the hypothesis
We can declare hypotheses to test for independence of these
variables. Here, age category is the response variable,
and job satisfaction is the explanatory variable.
The null hypothesis is that independence occurs. I’ve
set a significance level of 0.1. The test statistic is
denoted chi-square. It quantifies how far away the observed
results are from the values you’d expect if independence was
true.
\(H_{0}\) : Age categories are
independent of job satisfaction levels
\(H_{A}\) : Age categories are not
independent of job satisfaction levels
Test statistic denoted \(\chi^2\)
Assuming the independence, how far away are the observed results from
the expected values?
alpha = 0.1
Exploratory visualization: Proportional stacked bar
plot
Let’s explore the data using a proportional stacked bar plot.
fill
means two different things here. In the aesthetics,
fill
refers to the fill color of the bars. In
geom_bar
’s position argument, "fill"
makes
each bar the same height, so you can compare proportions. If the age
category was independent of the job satisfaction, the split between the
age categories would be at the same height in each of the five bars.
There’s some variation here, but we’ll need the hypothesis test to
determine whether it’s a significant difference.
ggplot(stack_overflow, aes(job_sat, fill = age_cat)) +
geom_bar(position = "fill") +
ylab("proportion")

Chi-square independence test using
chisq_test()
The hypothesis test for independence is called a chi-square
independence test. There’s a base-R function for it called
chisq.test()
, but like prop.test()
, it’s
fiddly to use. The easiest option is to use infer’s
chisq_test()
. Pipe from the sample dataset, passing
a formula with the response variable on the left and the explanatory
variable on the right. The p-value is 0.23,
which is above the significance level we set, so
we conclude that age categories are independent of job
satisfaction. The chi-square distribution, whose CDF is used to
calculate the p-value from the test statistic, has a degrees of freedom
argument, just like the t-distribution. The results show that there are
four degrees of freedom. This is the number of response categories minus
one, times the number of explanatory categories minus one. Two minus one
times five minus one is four.
stack_overflow %>%
chisq_test(age_cat ~ job_sat)
Degrees of freedom
\[
(No. \ of \ response \ categories \ - 1) \times (No. \ of \ explanatory
\ categories \ - 1)
\\(2 \ - 1) \times (5 \ - 1) \ = 4
\]
Swapping the variables
If we swap the variables, so age category is the response, and job
satisfaction is the explanatory variable, the visual inspection
technique is the same: see if the splits for each bar are in similar
places.
ggplot(stack_overflow, aes(age_cat, fill = job_sat)) +
geom_bar(position = "fill") +
ylab("proportion")

Chi-square both ways
If we run the chi-square test with the variables swapped, then the
results are identical. We should ask questions like “are
variables X and Y independent?”, not “is variable X independent
from variable Y?”, since the order doesn’t matter.
stack_overflow %>%
chisq_test(age_cat ~ job_sat)
stack_overflow %>%
chisq_test(job_sat ~ age_cat)
What about directions and tails?
We didn’t worry about tails in this test, and in fact
chisq_test()
doesn’t have an alternative
argument. This is because the test statistic is based
on the square of observed and expected counts, and square
numbers are non-negative. That means that chi-square tests tend
to be right-tailed tests.
1 Left-tailed chi-square tests are used in statistical
forensics to detect is a fit is suspiciously good because the data was
fabricated. Chi-square tests of variance can be two-tailed. These are
niche uses though.
args(chisq_test)
function (x, formula, response = NULL, explanatory = NULL, ...)
NULL
Chi-square goodness of fitness test
Last time you used a chi-square test to compare proportions in two
categorical variables. This time, we’ll use another variant of the
chi-square test to compare a single categorical variable to a
hypothesized distribution.
Purple links
The Stack Overflow survey contains a fun question about how the user
feels when they discover that they already visited the top resource when
trying to solve a coding problem. There are four possible answers,
stored in the purple_link variable.
purple_link_counts <- stack_overflow %>%
count(purple_link) %>%
arrange(desc(n))
purple_link_counts
Declaring the hypothesis
Let’s hypothesize that half the users in the population would respond
“Hello old friend”, and the other three responses would get one sixth
each. The tribble
function provides a convenient way of
manually entering values for a data frame, and returns a standard
tibble. We can specify the hypotheses as whether or not the sample
matches this hypothesized distribution. The test statistic measures how
far the distribution of proportions observed in the sample is from the
hypothesized distribution of proportions. I’ll set a significance level
of point-zero-one.
1 tribble is short for “row-wise tibble”; not to be
confused with the alien species from Star Trek
hypothesized <- tribble(~ purple_link, ~ prop,
"Hello, old friend", 1/2,
"Amused", 1/6,
"Indifferent", 1/6,
"Indifferent", 1/6,
"Annoyed", 1/6)
hypothesized
Hypothesized counts by category
To visualize the distribution of the purple links, it will help to
have the hypothesized counts. These are the hypothesized proportions
times the total number of observations in the sample.
n_total <- nrow(stack_overflow)
hypothesized <- tribble(~ purple_link, ~ prop,
"Hello, old friend", 1/2,
"Amused", 1/6,
"Indifferent", 1/6,
"Indifferent", 1/6,
"Annoyed", 1/6) %>%
mutate(n = prop * n_total)
hypothesized
Visualizing counts
The natural way to visualize the categories is with a bar plot. We’re
using geom_col()
here since we already calculated the
counts. The purple points show the hypothesized counts, so you can
compare the sample distribution to the hypothesized distribution. Two of
the bars are close to the values we hypothesized and two are slightly
different. We’ll need to run the hypothesis test to see if the
differences are statistically significant.
ggplot(purple_link_counts, aes(purple_link, n)) +
geom_col() +
geom_point(data = hypothesized, color = "red")

Chi-square goodness of fit test using
chisq_test()
The one sample chi-square test is called a goodness of fit test. To
run it, we need the hypothesized proportions in vector form rather than
in a tibble. Again we use chisq_test()
from
infer
. However, this time the arguments are different.
Piping from the dataset, we set response to the name of the column of
interest, and set \(p\) to the
hypothesized distribution. The degrees of freedom are one less
than the number of choices in the survey. Four minus one is
three. The p-value is very small, much lower than the
significance level we set. Thus we conclude that the
sample distribution of proportions is different than the hypothesized
distribution of proportions.
hypothesized_props <- c("Hello, old friend" = 1/2, Amused = 1/6, Indifferent = 1/6, Annoyed = 1/6)
stack_overflow %>%
chisq_test(response = purple_link, p = hypothesized_props)
Testing sample size
In order to conduct a hypothesis test, and be sure that the result is
fair, a sample must meet three requirements: it is a random sample of
the population; the observations are independent; and there are enough
observations. Of these, only the last condition is easily testable with
code.
The minimum sample size depends on the type of hypothesis tests you
want to perform. Let’s test some scenarios on the
late_shipments
dataset.
Using the late_shipments
dataset, get counts by the
freight_cost_group
columns.
Insert a suitable number to inspect whether the counts are “big
enough” for a two sample t-test.
# Get counts by freight_cost_group
counts <- late_shipments %>%
count(freight_cost_group)
Error in count(., freight_cost_group) : object 'late_shipments' not found
Using the late_shipments
dataset, get counts by the
late
column.
Insert a suitable number to inspect whether the counts are “big
enough” for a one sample proportion test.
Using the late_shipments
dataset, get counts by the
vendor_inco_term
and freight_cost_group
columns.
Insert a suitable number to inspect whether the counts are “big
enough” for a chi-square independence test.
Using the late_shipments
dataset, get counts by the
shipment_mode
column.
Insert a suitable number to inspect whether the counts are “big
enough” for an ANOVA test.
```r
# Count the values of shipment_mode
counts <- late_shipments %>%
count(shipment_mode)
# See the result
counts
```
<div data-pagedtable="false">
<script data-pagedtable-source type="application/json">
{"columns":[{"label":["shipment_mode"],"name":[1],"type":["chr"],"align":["left"]},{"label":["n"],"name":[2],"type":["int"],"align":["right"]}],"data":[{"1":"Air","2":"909"},{"1":"Air Charter","2":"6"},{"1":"Ocean","2":"84"},{"1":"NA","2":"1"}],"options":{"columns":{"min":{},"max":[10],"total":[2]},"rows":{"min":[10],"max":[10],"total":[4]},"pages":{}}}
</script>
</div>
```r
# Inspect whether the counts are big enough
all(counts$n >= 30)
```
```
[1] FALSE
```
The “There is only one test” framework
Traditional hypothesis tests make assumptions about the sample
dataset. Here, we’ll look at what to do when those assumptions don’t
hold.
Imbalance data
Sometimes you can’t get a sample representing all parts of your
population. Consider this subset of the Stack Overflow survey. There are
fewer users with hobbyist “No” than “Yes”, and fewer users with “At
least 30” ages than “Under 30”. In fact, there are no users with
hobbyist “No” and age “At least 30”. This is a problem for a proportion
test, since it requires that every group has at least ten observations.
I used count(…, .drop)
argument to include subgroups with a
zero count. A dataset where some group’s counts are much larger
than others is called “imbalanced”.
Hypotheses
We can declare hypotheses to test. I’ll set a significance level of
point-one.
\(H_{0}\) : The proportion of
hobbyists under 30 is the same as the proportion of hobbyists at least
30.
\(H_{A}\) : The proportion of
hobbists under 30 is different from the proportion of hobbyists at least
30
Proceeding with a proportion test regardless
Let’s ignore the small sample problems and run a proportion test. The
p-value is \(2.403 \times 10^{-5}\) ,
which is below the significance level. This test suggests that there is
enough evidence to reject the null hypothesis. We’ll revisit this
later.
A grammar of graphics
Traditionally, every type of plot has a name, like scatter plot or
line plot. In base-R you decide the plot type by specifying arguments to
the plot function, or by calling a dedicated function like hist. This is
fine until you want to draw a custom plot like a histogram with polar
coordinates. If a function to draw that doesn’t exist, you are stuck.
The beauty of the grammar of graphics system that ggplot2 implements is
that plots are broken down into components that can be combined in many
ways. It’s more flexible creating a new function for every plot type you
can think of. What if there was a grammar of hypothesis tests?
Scatter plot |
plot(, type = "p") |
ggplot( ) + geom_point( ) |
Line plot |
plot(, type = "l") |
ggplot( ) + geom_line( ) |
Histogram |
hist( ) |
ggplot( ) + geom_histogram( ) |
Box plot |
boxplot( ) |
ggplot( ) + geom_boxplot( ) |
Bar plot |
barplot( ) |
ggplot( ) + geom_bar( ) |
Pie plot |
pie( ) |
ggplot( ) + geom_bar( ) + coord_polar( ) |
A grammar of hypothesis tests
The good news is that there is a grammar of hypothesis tests. It was
invented by DataCamp instructor Allen Downey, and is called the
“There is only one test” framework. The framework was
implemented in R in the infer
package that you’ve used for
proportion and chi-square tests. All hypothesis tests can be performed
with this code flow, based on specify, hypothesize, generate, and
calculate. By changing the arguments to those functions you can run
standard tests like t-tests, or devise your own custom tests. We’ll
cover specify and hypothesize now, and the others in the next video.
generate is worth mentioning briefly. It creates simulated data
reflecting the null hypothesis. Using simulation rather than
arithmetic equations to get the test statistic is computationally
expensive, so it has only become accessible with modern
computing power. However, simulation has a benefit that it works well
even when you have small samples or imbalanced data.
1 Allen Downey teaches “Exploratory Data Analysis in
Python”.
Specifying the variables of interest
The Stack Overflow survey contains many variables, but for this test,
we only care about two of them. specify()
works like
dplyr’s select, returning only the response and explanatory columns.
specify()
To call specify, you pipe from the dataset, and pass a formula with
the response on the left and the explanatory variable on the right. In
the one sample case, use NULL for the explanatory value. Just as when
you called prop_test()
, you need to tell specify which
response value is regarded as a success. specify returns a tibble with
attributes noting the response and explanatory variable names.
hypothesize()
hypothesize()
declares the type of null hypothesis.
Proportion tests are a special case of the chi-square independence test,
so we choose “independence”. hypothesize doesn’t calculate anything; it
simply adds another attribute to the dataset.
For 2 sample tests, use "independence"
or
"point"
For 1 sample tests, use "point"
LS0tDQp0aXRsZTogIkh5cG90aGVzaXMgdGVzdGluZyAiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCmF1dGhvcjogSnVhbiBGZXJuYW5kbyBNb3NxdWVyYSBBcmF1am8NCmRhdGU6IDIwMjQtMDMtMTUNCi0tLQ0KDQojIyMgKipIeXBvdGhlc2lzIHRlc3QgYW5kIHotc2NvcmUqKg0KDQojIyMgKipBL0IgdGVzdGluZyoqDQoNClRoaXMgYW4gZXhwZXJpbWVudGFsIGRlc2lnbiB0ZWNobmlxdWUsIHdoaWNoIGhhcyByb290cyBpbiBoeXBvdGhlc2lzIHRlc3RpbmcsIHRvIHRlc3QgZGlmZmVyZW50IHNjZW5hcmlvcyBhbmQgc2VlIHdoaWNoIGhhcyB0aGUgYmVzdCBwZXJmb3JtYW5jZQ0KDQojIyAqKlN0YWNrIE92ZXJmbG93IERldmVsb3BlciBTdXJ2ZXkgMjAyMCoqDQoNCkVhY2ggeWVhciwgU3RhY2sgT3ZlcmZsb3cgc3VydmV5cyBpdHMgdXNlcnMsIHdobyBhcmUgcHJpbWFyaWx5IHNvZnR3YXJlIGRldmVsb3BlcnMsIGFib3V0IHRoZW1zZWx2ZXMsIGhvdyB0aGV5IHVzZSBTdGFjayBPdmVyZmxvdywgdGhlaXIgd29yaywgYW5kIHRoZSBkZXZlbG9wbWVudCB0b29scyB0aGV5IHVzZS4gSW4gdGhpcyBhbmFseXNpcyB3ZSdsbCBsb29rIGF0IGEgc3Vic2V0IG9mIHRoZSBzdXJ2ZXkgcmVzcG9uc2VzLCBmcm9tIHVzZXJzIHdobyBpZGVudGlmaWVkIGFzIERhdGEgU2NpZW50aXN0cy4NCg0KYGBge3J9DQojIExvYWQgbGlicmFyaWVzDQpsaWJyYXJ5KHRpZHlyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZnN0KQ0KbGlicmFyeSh0aWJibGUpDQpsaWJyYXJ5KHJlYWRyKQ0KYGBgDQoNCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQpydXRhX3N0Y2tvdiA8LSAiQzovVXNlcnMvSnVhbkZlciBNb3NxdWVyYS9Eb2N1bWVudHMvZGF0YXNldHMvc3RhY2tfb3ZlcmZsb3cucmRzIg0KYGBgDQoNCmBgYHtyfQ0Kc3RhY2tfb3ZlcmZsb3cgPC0gcmVhZF9yZHMocnV0YV9zdGNrb3YpDQpzdGFja19vdmVyZmxvdw0KY29sbmFtZXMoc3RhY2tfb3ZlcmZsb3cpDQpgYGANCg0KYGBge3J9DQpnbGltcHNlKHN0YWNrX292ZXJmbG93KQ0KYGBgDQoNCiMjIyAqKkh5cG90aGVzaXppbmcgYWJvdXQgdGhlIG1lYW4qKg0KDQpMZXQncyBoeXBvdGhlc2l6ZSB0aGF0IHRoZSBtZWFuIGFubnVhbCBjb21wZW5zYXRpb24gb2YgdGhlIHBvcHVsYXRpb24gb2YgZGF0YSBzY2llbnRpc3RzIGlzIFwkMTEwMDAwLiBUaGUgZmlyc3QgdGhpbmcgd2UgY2FuIGRvIHRvIGNoZWNrIHRoaXMgaXMgdG8gZXhhbWluZSB0aGUgc2FtcGxlIGRhdGEgaW4gdGhlIHN1cnZleS4gQW5udWFsIGNvbXBlbnNhdGlvbiwgY29udmVydGVkIHRvIGRvbGxhcnMsIGlzIGluY2x1ZGVkIGluIHRoZSBjb252ZXJ0ZWRfY29tcCBjb2x1bW4uIFRoZSBzYW1wbGUgbWVhbiBpcyBhIHR5cGUgb2YgcG9pbnQgZXN0aW1hdGUsIHdoaWNoIGlzIGFub3RoZXIgbmFtZSBmb3IgYSBzdW1tYXJ5IHN0YXRpc3RpYy4gWW91IGNhbiBjYWxjdWxhdGUgaXQgd2l0aCBiYXNlLVIsIG9yIG1vcmUgdmVyYm9zZWx5IHdpdGggZHBseXIuIEVpdGhlciB3YXksIHRoZSBhbnN3ZXIgaXMgXCQxMjIwMDAuIFRoYXQncyBkaWZmZXJlbnQgZnJvbSBvdXIgaHlwb3RoZXNpcywgYnV0IGlzIGl0IG1lYW5pbmdmdWxseSBkaWZmZXJlbnQ/DQoNCmBgYHtyfQ0KbWVhbl9jb21wX3NhbXAgPC0gbWVhbihzdGFja19vdmVyZmxvdyRjb252ZXJ0ZWRfY29tcCkNCm1lYW5fY29tcF9zYW1wDQpgYGANCg0KYGBge3J9DQptZWFuX2NvbXBfc2FtcCA8LSBzdGFja19vdmVyZmxvdyAlPiUNCiAgc3VtbWFyaXNlKG1lYW5fY29tcGVuc2F0aW9uID0gbWVhbihjb252ZXJ0ZWRfY29tcCkpICU+JQ0KICBwdWxsKG1lYW5fY29tcGVuc2F0aW9uKQ0KbWVhbl9jb21wX3NhbXANCmBgYA0KDQojIyMgKipHZW5lcmF0aW5nIGEgYm9vdHN0cmFwIGRpc3RyaWJ1dGlvbioqDQoNClRvIGFuc3dlciB0aGlzLCB3ZSBuZWVkIHRvIGdlbmVyYXRlIGEgYm9vdHN0cmFwIGRpc3RyaWJ1dGlvbiBvZiBzYW1wbGUgbWVhbnMuIFRoaXMgaXMgZG9uZSBieSByZXNhbXBsaW5nIHRoZSBkYXRhc2V0LCBjYWxjdWxhdGluZyB0aGUgc2FtcGxlIG1lYW4gZm9yIHRoYXQgcmVzYW1wbGUsIHRoZW4gcmVwZWF0aW5nIHRob3NlIHN0ZXBzLg0KDQpgYGB7cn0NCiMgUmVwZWF0IHN0ZXBzIDEgJiAyIG1hbnkgdGltZXMgDQpzb19ib290X2Rpc3RuIDwtIHJlcGxpY2F0ZSgNCiAgbiA9IDUwMDAsDQogIGV4cHIgPSB7DQogICAgI1N0ZXAgMS4gUmVzYW1wbGUNCiAgICBzdGFja19vdmVyZmxvdyAlPiUNCiAgICAgIHNsaWNlX3NhbXBsZShwcm9wID0gMSwgcmVwbGFjZSA9IFRSVUUpICU+JQ0KICAgICAgIyBTdGVwIDIuIENhbGN1bGF0ZSBwb2ludCBlc3RpbWF0ZQ0KICAgICAgc3VtbWFyaXNlKG1lYW5fY29tcGVuc2F0aW9uID0gbWVhbihjb252ZXJ0ZWRfY29tcCkpICU+JQ0KICAgICAgcHVsbChtZWFuX2NvbXBlbnNhdGlvbikNCiAgfQ0KKQ0KaGVhZChzb19ib290X2Rpc3RuKQ0KYGBgDQoNCiMjIyAqKlZpc3VhbGl6aW5nIHRoZSBib290c3RyYXAgZGlzdHJpYnV0aW9uKioNCg0KSGVyZSdzIGEgaGlzdG9ncmFtIG9mIHRoZSBib290c3RyYXAgZGlzdHJpYnV0aW9uLiBJdHMgYmVsbCBzaGFwZSBtZWFucyBpdCdzIHJvdWdobHkgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuIE5vdGljZSB0aGF0ICQxMTAwMDAkIGlzIG9uIHRoZSBsZWZ0IG9mIHRoZSBkaXN0cmlidXRpb24uDQoNCmBgYHtyfQ0KdGliYmxlKHJlc2FtcGxlX21lYW4gPSBzb19ib290X2Rpc3RuKSAlPiUNCiAgZ2dwbG90KGFlcyhyZXNhbXBsZV9tZWFuKSkgKyANCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxMDAwKQ0KYGBgDQoNCiMjIyAqKlN0YW5kYXJkIEVycm9yKioNCg0KUmVjYWxsIHRoYXQgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgc2FtcGxlIHN0YXRpc3RpY3MgaW4gdGhlIGJvb3RzdHJhcCBkaXN0cmlidXRpb24gZXN0aW1hdGVzIHRoZSBzdGFuZGFyZCBlcnJvciBvZiB0aGUgc3RhdGlzdGljLg0KDQpgYGB7cn0NCnN0ZF9lcnJvciA8LSBzZChzb19ib290X2Rpc3RuKQ0Kc3RkX2Vycm9yDQpgYGANCg0KIyMjICoqWi1zY29yZXMqKg0KDQpTaW5jZSB2YXJpYWJsZXMgaGF2ZSBhcmJpdHJhcnkgdW5pdHMgYW5kIHJhbmdlcywgYmVmb3JlIHdlIHRlc3Qgb3VyIGh5cG90aGVzaXMsIHdlIG5lZWQgdG8gc3RhbmRhcmRpemUgdGhlIHZhbHVlcy4gQSBjb21tb24gd2F5IG9mIHN0YW5kYXJkaXppbmcgdmFsdWVzIGlzIHRvICoqc3VidHJhY3QgdGhlIG1lYW4qKiwgYW5kICoqZGl2aWRlIGJ5IHRoZSBzdGFuZGFyZCBkZXZpYXRpb24qKi4gRm9yIGh5cG90aGVzaXMgdGVzdGluZywgd2UgdXNlIGEgdmFyaWF0aW9uIHdoZXJlIHdlIHRha2UgdGhlICoqc2FtcGxlIHN0YXRpc3RpYywgc3VidHJhY3QgdGhlIGh5cG90aGVzaXplZCBwYXJhbWV0ZXIgdmFsdWUsIGFuZCBkaXZpZGUgYnkgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgc3RhdGlzdGljKiosICoqd2hpY2ggaXMgdGhlIHN0YW5kYXJkIGVycm9yKiouIFRoZSByZXN1bHQgaXMgY2FsbGVkIGEgKip6LXNjb3JlKiouIFRoZSBzYW1wbGUgbWVhbiBhbm51YWwgY29tcGVuc2F0aW9uIGZvciBkYXRhIHNjaWVudGlzdHMgb2YgXCQxMjIwMDAgLCBtaW51cyB0aGUgaHlwb3RoZXNpemVkIGNvbXBlbnNhdGlvbiBmb3IgZGF0YSBzY2llbnRpc3RzIG9mIFwkMTEwMDAwLCBkaXZpZGVkIGJ5IHRoZSBib290c3RyYXAgc3RhbmRhcmQgZXJyb3Igb2YgXCQ1NTkwIGdpdmVzIGEgei1zY29yZSAxLjcxDQoNCmBgYHtyfQ0KbWVhbl9jb21wX2h5cCA8LSAxMTAwMDANCm1lYW5fY29tcF9zYW1wDQoNCnpfc2NvcmUgPC0gKG1lYW5fY29tcF9zYW1wIC0gbWVhbl9jb21wX2h5cCkgLyBzdGRfZXJyb3INCnpfc2NvcmUNCmBgYA0KDQojIyMgKipUZXN0aW5nIHRoZSBoeXBvdGhlc2lzKioNCg0KSXMgdGhhdCBhIGJpZyBvciBzbWFsbCBudW1iZXI/IERldGVybWluaW5nIHRoYXQgaXMgdGhlIGdvYWwgb2YgdGhpcyBjb3Vyc2UuIEluIHBhcnRpY3VsYXIsIHdlIGNhbiBub3cgc3RhdGUgb25lIG9mIHRoZSB1c2VzIG9mIGh5cG90aGVzaXMgdGVzdGluZy4gRGV0ZXJtaW5pbmcgd2hldGhlciBhIHNhbXBsZSBzdGF0aXN0aWMgaXMgY2xvc2UgdG8gb3IgZmFyIGF3YXkgZnJvbSBhbiBleHBlY3RlZCB2YWx1ZS4NCg0KIyMjICoqU3RhbmRhcmQgbm9ybWFsICh6KSBkaXN0cmlidXRpb24qKg0KDQpIZXJlJ3MgYSBkZW5zaXR5IHBsb3Qgb2YgdGhlIHByb2JhYmlsaXR5IGRlbnNpdHkgZnVuY3Rpb24gZm9yIHRoZSBzdGFuZGFyZCBub3JtYWwgZGlzdHJpYnV0aW9uLiBUaGF0IGlzLCBhIG5vcm1hbCBkaXN0cmlidXRpb24gd2l0aCBtZWFuIHplcm8gYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBvbmUuIEl0J3Mgb2Z0ZW4gY2FsbGVkIHRoZSB6LWRpc3RyaWJ1dGlvbi4gQXMgeW91IG1pZ2h0IGd1ZXNzLCB6LXNjb3JlcyBhcmUgcmVsYXRlZCB0byB0aGUgei1kaXN0cmlidXRpb24uDQoNCmBgYHtyfQ0KIyBDcmVhdGUgYSBkYXRhc2V0IG9mIHotZGlzdHJpYnV0aW9uIGFuZCBwbG90IGl0DQp0aWJibGUoeCA9IHNlcSgtNCwgNCwgMC4wMSkpICU+JQ0KICBnZ3Bsb3QoYWVzKHgpKSArIA0KICBzdGF0X2Z1bmN0aW9uKGZ1biA9IGRub3JtKSArIA0KICAgIHlsYWIoIlBERih4KSIpDQpgYGANCg0KIyMjICoqUC12YWx1ZXMqKg0KDQpIeXBvdGhlc2lzIHRlc3RzIGFyZSBsaWtlIGNyaW1pbmFsIHRyaWFscy4NCg0KVGhlIHRydWUgc2l0dWF0aW9uIGlzIHRoYXQgdGhlIGRlZmVuZGFudCBjb21taXR0ZWQgdGhlIGNyaW1lLCBvciB0aGV5IGRpZG4ndC4gVGhlcmUgYXJlIGFsc28gdHdvIHBvc3NpYmxlIG91dGNvbWVzLiBUaGUganVkZ2UgZ2l2ZXMgYSBndWlsdHkgb3IgYSBub3QgZ3VpbHR5IHZlcmRpY3QuIFRoZSBpbml0aWFsIGFzc3VtcHRpb24gaXMgdGhhdCB0aGUgZGVmZW5kYW50IGlzIG5vdCBndWlsdHkuIEl0J3MgdXAgdG8gdGhlIHByb3NlY3V0aW9uIHRlYW0gdG8gY29tZSB1cCB3aXRoIGV2aWRlbmNlIGJleW9uZCBhIHJlYXNvbmFibGUgZG91YnQgdGhhdCB0aGUgZGVmZW5kYW50IGNvbW1pdHRlZCB0aGUgY3JpbWUgaW4gb3JkZXIgZm9yIGEgZ3VpbHR5IHZlcmRpY3QgdG8gYmUgZ2l2ZW4uDQoNCiMjIyAqKkFnZSBvZiBmaXJzdCBwcm9ncmFtbWluZyBleHBlcmllbmNlKioNCg0KTGV0J3MgcmV0dXJuIHRvIG91ciBzdXJ2ZXkuIFRoZSBgYWdlX2ZpcnN0X2NvZGVfY3V0YCB2YXJpYWJsZSBjbGFzc2lmaWVzIHdoZW4gdGhlIHVzZXIgYmVnYW4gcHJvZ3JhbW1pbmcuIElmIHRoZXkgd2VyZSAxNCBvciBvbGRlciwgdGhleSBhcmUgY2xhc3NpZmllZCBhcyAqKiJhZHVsdCIqKjsgb3RoZXJ3aXNlICoqImNoaWxkIioqLg0KDQpTdXBwb3NlIHByZXZpb3VzIHJlc2VhcmNoIHN1Z2dlc3RzIHRoYXQgMzUlIG9mIHNvZnR3YXJlIGRldmVsb3BlcnMgcHJvZ3JhbW1lZCBhcyBjaGlsZHJlbi4gVGhpcyByYWlzZXMgYSBxdWVzdGlvbiBhbnN3ZXJhYmxlIHdpdGggb3VyIGRhdGFzZXQuDQoNCioqRG9lcyBvdXIgc2FtcGxlIHByb3ZpZGUgZXZpZGVuY2UgdGhhdCBkYXRhIHNjaWVudGlzdHMgaGF2ZSBhIGdyZWF0ZXIgcHJvcG9ydGlvbiBzdGFydGluZyBwcm9ncmFtbWluZyBhcyBhIGNoaWxkKio/DQoNCiMjIyAqKkRlZmluaXRpb25zKioNCg0KSHlwb3RoZXNpcyBpcyBhIHN0YXRlbWVudCBhYm91dCBhICoqcG9wdWxhdGlvbiBwYXJhbWV0ZXIqKi4gV2UgZG9uJ3Qga25vdyB0aGUgdHJ1ZSB2YWx1ZSBvZiB0aGlzIHBvcHVsYXRpb24gcGFyYW1ldGVyOyB3ZSBjYW4gb25seSBtYWtlIGluZmVyZW5jZXMgYWJvdXQgaXQgZnJvbSB0aGUgZGF0YS4gKipIeXBvdGhlc2lzIHRlc3RzIGNvbXBhcmUgdHdvIGNvbXBldGluZyBoeXBvdGhlc2VzKiouIFRoZXNlIHR3byBoeXBvdGhlc2VzIGFyZSB0aGUgKipudWxsIGh5cG90aGVzaXMqKiwgcmVwcmVzZW50aW5nIHRoZSBleGlzdGluZyBpZGVhLCBhbmQgdGhlICoqYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcyoqLCByZXByZXNlbnRpbmcgYSBuZXcgaWRlYS4NCg0KVGhleSBhcmUgZGVub3RlZCAkSF97MH0kIGFuZCAkSF97QX0kIHJlc3BlY3RpdmVseS4gKipUaGUgbnVsbCBoeXBvdGhlc2lzIGlzIGxpa2UgdGhlIGN1cnJlbnQgY2hhbXBpb24sIGFuZCB0aGUgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcyBpcyBsaWtlIGEgY2hhbGxlbmdlciB0cnlpbmcgdG8gb3ZlcnRocm93IHRoYXQgY2hhbXBpb24qKi4gSGVyZSwgdGhlIG51bGwgaHlwb3RoZXNpcyBpcyB0aGF0IG91ciBkYXRhIHdvbid0IHRlbGwgdXMgYW55dGhpbmcgbmV3LCBhbmQgdGhhdCB0aGUgcHJvcG9ydGlvbiBvZiBkYXRhIHNjaWVudGlzdHMgc3RhcnRpbmcgcHJvZ3JhbW1pbmcgYXMgY2hpbGRyZW4gZm9sbG93cyB0aGUgcHJldmlvdXMgcmVzZWFyY2ggb24gc29mdHdhcmUgZGV2ZWxvcGVycywgYXQgMzUlLiBUaGUgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcyBpcyB0aGF0IG91ciBodW5jaCBpcyBjb3JyZWN0LCBhbmQgdGhhdCB0aGUgcGVyY2VudGFnZSBpcyBncmVhdGVyIHRoYW4gMzUlLg0KDQojIyMgKipDcmltaW5hbCB0cmlhbHMgdnMuIEh5cG90aGVzaXMgVGVzdGluZyoqDQoNCkxldCdzIGNvbXBhcmUgdGhlIGNyaW1pbmFsIHRyaWFsIHdpdGggdGhlIGh5cG90aGVzaXMgdGVzdC4gVGhlIGRlZmVuZGFudCBjb21taXR0aW5nIHRoZSBjcmltZSBpcyBlcXVpdmFsZW50IHRvIHRoZSAqKmFsdGVybmF0aXZlIGh5cG90aGVzaXMgYmVpbmcgdHJ1ZSoqLCBhbmQgdGhlIGRlZmVuZGFudCBub3QgY29tbWl0dGluZyB0aGUgY3JpbWUgaXMgZXF1aXZhbGVudCB0byB0aGUgKipudWxsIGh5cG90aGVzaXMgYmVpbmcgdHJ1ZSoqLiBSYXRoZXIgdGhhbiBzYXlpbmcgd2UgYWNjZXB0IHRoZSBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzLCAqKnRoZSB2ZXJkaWN0cyBhcmUgcmVqZWN0aW5nIHRoZSBudWxsIGh5cG90aGVzaXMqKiwgb3IgKipmYWlsaW5nIHRvIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzKiouIEluaXRpYWxseSwgd2UgYXNzdW1lIHRoYXQgdGhlIG51bGwgaHlwb3RoZXNpcyBpcyB0cnVlLCBhbmQgdGhpcyBvbmx5IGNoYW5nZXMgaWYgdGhlIHNhbXBsZSBwcm92aWRlcyBlbm91Z2ggZXZpZGVuY2UgdG8gcmVqZWN0IGl0Lg0KDQpUaGUgaHlwb3RoZXNpcyB0ZXN0aW5nIGVxdWl2YWxlbnQgb2YgImJleW9uZCBhIHJlYXNvbmFibGUgZG91YnQiIGlzIGtub3duIGFzIHRoZSBzaWduaWZpY2FuY2UgbGV2ZWwuDQoNCiMjIyAqKk9uZS10YWlsZWQgJiB0d28tdGFpbGVkIHRlc3RzKioNCg0KVGhlIHRhaWxzIG9mIGEgZGlzdHJpYnV0aW9uIGFyZSB0aGUgbGVmdCBhbmQgcmlnaHQgZWRnZXMgb2YgaXRzIFBERi4gKipIeXBvdGhlc2lzIHRlc3RzIGRldGVybWluZSB3aGV0aGVyIHRoZSBzYW1wbGUgc3RhdGlzdGljcyBsaWUgaW4gdGhlIHRhaWxzIG9mIHRoZSBkaXN0cmlidXRpb24qKi4gVGhlcmUgYXJlIHRocmVlIHR5cGVzIG9mIHRlc3RzLCBhbmQgdGhlIHBocmFzaW5nIG9mIHRoZSBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzIGRldGVybWluZXMgd2hpY2ggdHlwZSB5b3Ugc2hvdWxkIHVzZS4gSW4gdGhpcyBjYXNlLCB3ZSBuZWVkIGEgKipyaWdodC10YWlsZWQgdGVzdCoqLg0KDQojIyMgKipQLXZhbHVlcyoqDQoNCioqcC12YWx1ZXMqKiBtZWFzdXJlIHRoZSBzdHJlbmd0aCBvZiBzdXBwb3J0IGZvciB0aGUgbnVsbCBoeXBvdGhlc2lzLiAqKlNtYWxsIHAtdmFsdWVzIG1lYW4gb3VyIHN0YXRpc3RpYyBpcyBwcm9kdWNpbmcgYW4gdW5saWtlbHkgcmVzdWx0IGluIGEgdGFpbCBvZiBvdXIgbnVsbCBkaXN0cmlidXRpb24qKi4gKipwLXZhbHVlcyoqIGFyZSBwcm9iYWJpbGl0aWVzLCBzbyB0aGV5IGFyZSBhbHdheXMgKipiZXR3ZWVuIHplcm8gYW5kIG9uZSoqLg0KDQojIyMgKipEZWZpbmluZyBwLXZhbHVlcyoqDQoNClRoZSBkZWZpbml0aW9uIG9mIGEgcC12YWx1ZSBoYXMgZm91ciBwYXJ0cy4gSXQncyBhIHByb2JhYmlsaXR5IHJlbGF0ZWQgdG8gd2hlcmUgdGhlIHN0YXRpc3RpYyBmcm9tIG91ciBzYW1wbGUgbGllcyBvbiB0aGUgbnVsbCBkaXN0cmlidXRpb24uICoqSXQgbWVhc3VyZXMgaG93IG1hbnkgdmFsdWVzIGZhbGwgZmFydGhlciBhd2F5IHRoYW4gd2hhdCB3ZSBvYnNlcnZlZCBpbiB0aGUgZGlyZWN0aW9uIG9mIHRoZSBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzKiouIEl0IGlzIGJhc2VkIG9uIHRoZSBudWxsIGRpc3RyaWJ1dGlvbiwgd2hpY2ggYXNzdW1lcyB0aGF0IHRoZSBudWxsIGh5cG90aGVzaXMgaXMgdHJ1ZS4gVGhlICoqcC12YWx1ZSoqIG1lYXN1cmVzIGV2aWRlbmNlLiBEb2VzIGl0IGZhdm9yIHRoZSBvcmlnaW5hbCBhc3N1bXB0aW9uIG9yIHRoZSBuZXcgYWx0ZXJuYXRpdmU/DQoNCiMjIyAqKkNhbGN1bGF0aW5nIHRoZSB6LXNjb3JlKioNCg0KVG8gY2FsY3VsYXRlIHRoZSAqKnAtdmFsdWUqKiwgd2UgbmVlZCB0byBydW4gdGhyb3VnaCB0aGUgc2FtZSBzdGVwcyBhcyBiZWZvcmUuIFdlIGdldCB0aGUgKipzYW1wbGUgc3RhdGlzdGljKiosIGluIHRoaXMgY2FzZSAqKnRoZSBwcm9wb3J0aW9uIG9mIGRhdGEgc2NpZW50aXN0cyB3aG8gc3RhcnRlZCBwcm9ncmFtbWluZyBhcyBjaGlsZHJlbioqLiBXZSBnZXQgdGhlIGh5cG90aGVzaXplZCB2YWx1ZSBmcm9tIHRoZSBudWxsIGh5cG90aGVzaXMsICQzNVwlJC4gV2UgZ2V0IHRoZSBzdGFuZGFyZCBlcnJvciBmcm9tIHRoZSBib290c3RyYXAgZGlzdHJpYnV0aW9uLiBUaGUgKip6LXNjb3JlKiogaXMgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgcHJvcG9ydGlvbnMsIGRpdmlkZWQgYnkgdGhlIHN0YW5kYXJkIGVycm9yLg0KDQpgYGB7cn0NCnByb3BfY2hpbGRfc2FtcCA8LSBzdGFja19vdmVyZmxvdyAlPiUNCiAgc3VtbWFyaXNlKHBvaW50X2VzdGltYXRlID0gbWVhbihhZ2VfZmlyc3RfY29kZV9jdXQgPT0gImNoaWxkIikpICU+JQ0KICBwdWxsKHBvaW50X2VzdGltYXRlKQ0KDQpwcm9wX2NoaWxkX3NhbXANCmBgYA0KDQpgYGB7cn0NCnNkX2Jvb3RfZGlzdG4gPC0gcmVwbGljYXRlKA0KICBuID0gNTAwMCwNCiAgZXhwciA9IHsNCiAgICAjU3RlcCAxLiBSZXNhbXBsZQ0KICAgIHN0YWNrX292ZXJmbG93ICU+JQ0KICAgICAgc2xpY2Vfc2FtcGxlKHByb3AgPSAxLCByZXBsYWNlID0gVFJVRSkgJT4lDQogICAgICAjIFN0ZXAgMi4gQ2FsY3VsYXRlIHBvaW50IGVzdGltYXRlDQogICAgICBzdW1tYXJpc2Uoc2FtcGxlX21lYW4gPSBtZWFuKGFnZV9maXJzdF9jb2RlX2N1dCA9PSAiY2hpbGQiKSkgJT4lDQogICAgICBwdWxsKHNhbXBsZV9tZWFuKQ0KICB9DQopDQpoZWFkKHNkX2Jvb3RfZGlzdG4pDQpgYGANCg0KYGBge3J9DQpzdGRfZXJyID0gc2Qoc2RfYm9vdF9kaXN0bikNCnN0ZF9lcnINCmBgYA0KDQpgYGB7cn0NCnByb3BfY2hpbGRfaHlwIDwtIDAuMzUNCiNzdGRfZXJyIDwtIDAuMDA5NjAyOA0Kel9zY29yZSA8LSAocHJvcF9jaGlsZF9zYW1wIC0gcHJvcF9jaGlsZF9oeXApIC8gc3RkX2Vycg0Kel9zY29yZQ0KYGBgDQoNCiMjIyAqKkNhbGN1bGF0aW5nIHRoZSBwLXZhbHVlKioNCg0KVGhlIGxhc3Qgc3RlcCBpcyBuZXcuIFdlIHBhc3MgdGhlIHotc2NvcmUgdG8gdGhlIG5vcm1hbCBjdW11bGF0aXZlIGRpc3RyaWJ1dGlvbiBmdW5jdGlvbiwgcG5vcm0uIFNpbmNlIHdlIHdhbnQgdGhlIHJpZ2h0LWhhbmQgdGFpbCBmb3IgdGhpcyB0ZXN0LCB3ZSBzZXQgbG93ZXItZG90LXRhaWwgdG8gRkFMU0UuIFRoZSBwLXZhbHVlIGlzIDguMDQgZSAtMTAgVGhhdCdzIGEgdmVyeSBzbWFsbCBudW1iZXIsIGJ1dCBpcyBpdCBzbWFsbCBlbm91Z2ggdG8gcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXM/DQoNCmBgYHtyfQ0KcF92YWx1ZSA8LSBwbm9ybSh6X3Njb3JlLCBsb3dlci50YWlsID0gRkFMU0UpDQpwX3ZhbHVlDQpgYGANCg0KIyMjICoqU3RhdGlzdGljYWwgc2lnbmlmaWNhbmNlKioNCg0KKipwLXZhbHVlcyoqIHF1YW50aWZ5IGhvdyBtdWNoIGV2aWRlbmNlIHRoZXJlIGlzIGZvciB0aGUgbnVsbCBoeXBvdGhlc2lzLiAqKkxhcmdlIHAtdmFsdWVzIGxlYWQgdXMgdG8gbm90IGhhdmUgZW5vdWdoIGV2aWRlbmNlIGZvciB0aGUgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcyoqLCBzdGlja2luZyB3aXRoIHRoZSBhc3N1bWVkIG51bGwgaHlwb3RoZXNpcyBpbnN0ZWFkLiAqKlNtYWxsIHAtdmFsdWVzIG1ha2UgdXMgZG91YnQgdGhpcyBvcmlnaW5hbCBhc3N1bXB0aW9uIGluIGZhdm9yIG9mIHRoZSBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzKiouIFdoYXQgZGVmaW5lcyB0aGUgY3V0b2ZmIHBvaW50IGJldHdlZW4gYSBzbWFsbCBwLXZhbHVlIGFuZCBhIGxhcmdlIG9uZT8NCg0KIyMjICoqU2lnbmlmaWNhbmNlIGxldmVsKioNCg0KVGhlIGN1dG9mZiBwb2ludCBpcyBrbm93biBhcyB0aGUgKipzaWduaWZpY2FuY2UgbGV2ZWwqKiwgYW5kIGlzIGRlbm90ZWQgYWxwaGEgKCoqzrEqKikuIFRoZSBhcHByb3ByaWF0ZSBzaWduaWZpY2FuY2UgbGV2ZWwgZGVwZW5kcyBvbiB0aGUgZGF0YXNldCBhbmQgdGhlIGRpc2NpcGxpbmUgeW91IGFyZSB3b3JraW5nIGluLiAqKjUlKiogaXMgdGhlIG1vc3QgY29tbW9uIGNob2ljZSwgYnV0ICoqMTAlKiogYW5kICoqMSUqKiBhcmUgYWxzbyBwb3B1bGFyLiBUaGUgc2lnbmlmaWNhbmNlIGxldmVsIGdpdmVzIHVzIGEgZGVjaXNpb24gcHJvY2VzcyBmb3Igd2hpY2ggaHlwb3RoZXNpcyB0byBzdXBwb3J0LiAqKklmIHRoZSBwLXZhbHVlIGlzIGxlc3MgdGhhbiBhbHBoYSoqLCB3ZSAqKnJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzKiouICoqT3RoZXJ3aXNlIHdlIGZhaWwgdG8gcmVqZWN0IGl0KiouIEl0J3MgaW1wb3J0YW50IHRoYXQgeW91ICoqZGVjaWRlIHdoYXQgdGhlIGFwcHJvcHJpYXRlIHNpZ25pZmljYW5jZSBsZXZlbCBzaG91bGQgYmUgYmVmb3JlIHlvdSBydW4geW91ciB0ZXN0KiouIE90aGVyd2lzZSB0aGVyZSBpcyBhIHRlbXB0YXRpb24gdG8gZGVjaWRlIG9uIGEgc2lnbmlmaWNhbmNlIGxldmVsIHRoYXQgbGV0cyB5b3UgY2hvb3NlIHRoZSBoeXBvdGhlc2lzIHlvdSB3YW50Lg0KDQojIyMgKipDYWxjdWxhdGluZyB0aGUgcC12YWx1ZSoqDQoNClRoZSB3b3JrZmxvdyBpcyBub3cgdG8gc2V0IHRoZSBzaWduaWZpY2FuY2UgbGV2ZWwsIGluIHRoaXMgY2FzZSAwLjA1LiBUaGVuIGNhbGN1bGF0ZSB0aGUgei1zY29yZSBhbmQgdXNlIHRoZSBzdGFuZGFyZCBub3JtYWwgQ0RGIHRvIGdldCB0aGUgcC12YWx1ZS4gSW4gdGhpcyBjYXNlLCB0aGUgcC12YWx1ZSBvZiAqKjggZS0wNioqIGlzIGxlc3MgdGhhbiBvciBlcXVhbCB0byBwb2ludC16ZXJvLWZpdmUsIHNvIHdlIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzLiBXZSBoYXZlIHN0cm9uZyBldmlkZW5jZSBmb3IgdGhlIGFsdGVybmF0aXZlIGh5cG90aGVzaXMgdGhhdCB0aGUgcHJvcG9ydGlvbiBvZiBkYXRhIHNjaWVudGlzdHMgc3RhcnRpbmcgcHJvZ3JhbW1pbmcgYXMgY2hpbGRyZW4gaXMgZ3JlYXRlciB0aGFuICoqMzUlKiouDQoNCmBgYHtyfQ0KYWxwaGEgPC0gMC4wNQ0KDQpwcm9wX2NoaWxkX3NhbXAgPC0gc3RhY2tfb3ZlcmZsb3cgJT4lDQogIHN1bW1hcmlzZShwb2ludF9lc3RpbWF0ZSA9IG1lYW4oYWdlX2ZpcnN0X2NvZGVfY3V0ID09ICJjaGlsZCIpKSAlPiUNCiAgcHVsbChwb2ludF9lc3RpbWF0ZSkNCg0KcHJvcF9jaGlsZF9oeXAgPC0gMC4zNSANCnN0ZF9lcnJvciA8LSAwLjAwOTYwMjgNCnpfc2NvcmUgPC0gKHByb3BfY2hpbGRfc2FtcCAtIHByb3BfY2hpbGRfaHlwKSAvIHN0ZF9lcnJvcg0KcF92YWx1ZSA9IHBub3JtKHpfc2NvcmUsIGxvd2VyLnRhaWwgPSBGQUxTRSkNCnBfdmFsdWUNCmBgYA0KDQpgYGB7cn0NCnBfdmFsdWUgPD0gYWxwaGENCmBgYA0KDQojIyMjIA0KDQokJA0KcC12YWx1ZSBcIGlzIFwgbGVzcyBcIHRoYW4gXCBvciBcIGVxdWFsIFwgdG8gXCBcYWxwaGEsIHNvIFwgcmVqZWN0IFwgSF97MH0gXCBhbmQgXCBhY2NlcHQgXCBIX3tBfQ0KJCQNCg0KIyMjICoqQ29uZmlkZW5jZSBpbnRlcnZhbHMqKg0KDQpUbyBnZXQgYSBzZW5zZSBhcyB0byBwb3RlbnRpYWwgdmFsdWVzIG9mIHRoZSBwb3B1bGF0aW9uIHBhcmFtZXRlciwgaXQncyBjb21tb24gdG8gY2hvb3NlIGEgY29uZmlkZW5jZSBpbnRlcnZhbCBvZiBvbmUgbWludXMgdGhlIHNpZ25pZmljYW5jZSBsZXZlbC4gRm9yIGEgc2lnbmlmaWNhbmNlIGxldmVsIG9mICoqMC4wNSoqLCB3ZSdkIHVzZSBhIDk1JSBjb25maWRlbmNlIGludGVydmFsLiBIZXJlJ3MgdGhlIGNhbGN1bGF0aW9uIHVzaW5nIHRoZSBxdWFudGlsZSBtZXRob2QuIFRoZSBpbnRlcnZhbCBydW5zIGZyb20gKiowLjM3KiogdG8gKiowLjQxKiogZ2l2aW5nIGEgcmFuZ2Ugb2YgcGxhdXNpYmxlIHZhbHVlcyBmb3IgdGhlIHByb3BvcnRpb24gb2YgZGF0YSBzY2llbnRpc3RzIHN0YXJ0aW5nIHByb2dyYW1taW5nIGFzIGNoaWxkcmVuLg0KDQpgYGB7cn0NCmZpcnN0X2NvZGVfYm9vdF9zYW1wIDwtIHJlcGxpY2F0ZSgNCiAgbiA9IDUwMDAsDQogIGV4cHIgPSB7DQogICAgc3RhY2tfb3ZlcmZsb3cgJT4lDQogICAgICBzbGljZV9zYW1wbGUocHJvcCA9IDAuMjUsIHJlcGxhY2UgPSBUUlVFKSAlPiUNCiAgICAgIHN1bW1hcmlzZShwb2ludF9lc3RpbWF0ZSA9IG1lYW4oYWdlX2ZpcnN0X2NvZGVfY3V0ID09ICJjaGlsZCIpKSAlPiUNCiAgICAgIHB1bGwocG9pbnRfZXN0aW1hdGUpDQogIH0NCikNCg0KZmlyc3RfY29kZV9ib290X2Rpc3RuIDwtIHRpYmJsZShmaXJzdF9jb2RlX2NoaWxkX3JhdGUgPSBmaXJzdF9jb2RlX2Jvb3Rfc2FtcCkNCmhlYWQoZmlyc3RfY29kZV9ib290X2Rpc3RuKQ0KYGBgDQoNCmBgYHtyfQ0KY29uZl9pbnQgPC0gZmlyc3RfY29kZV9ib290X2Rpc3RuICU+JQ0KICBzdW1tYXJpc2UobG93ZXIgPSBxdWFudGlsZShmaXJzdF9jb2RlX2NoaWxkX3JhdGUsIDAuMDI1KSwNCiAgICAgICAgICAgIHVwcGVyID0gcXVhbnRpbGUoZmlyc3RfY29kZV9jaGlsZF9yYXRlLCAwLjk3NSkpDQoNCmNvbmZfaW50DQpgYGANCg0KIyMjICoqVHlwZXMgb2YgZXJyb3JzKioNCg0KUmV0dXJuaW5nIHRvIHRoZSBjcmltaW5hbCB0cmlhbCBhbmFsb2d5LCB0aGVyZSBhcmUgdHdvIHBvc3NpYmxlIHRydXRoIHN0YXRlcyBhbmQgdHdvIHBvc3NpYmxlIG91dGNvbWVzLCBmb3IgZm91ciBjb21iaW5hdGlvbnMgaW4gdG90YWwuIFR3byBvZiB0aGVzZSBpbmRpY2F0ZSB0aGF0IHRoZSB2ZXJkaWN0IHdhcyBjb3JyZWN0LiBJZiBhIGRlZmVuZGFudCBkaWRuJ3QgY29tbWl0IHRoZSBjcmltZSwgYnV0IHRoZSB2ZXJkaWN0IHdhcyBndWlsdHksIHRoZXkgYXJlIHdyb25nZnVsbHkgY29udmljdGVkLiBJZiB0aGUgZGVmZW5kYW50IGNvbW1pdHRlZCB0aGUgY3JpbWUgYnV0IHRoZSB2ZXJkaWN0IHdhcyBub3QgZ3VpbHR5LCB0aGV5IGdvdCBhd2F5IHdpdGggaXQuIFRoZXNlIGFyZSBib3RoIGVycm9ycyBpbiBqdXN0aWNlLiBTaW1pbGFybHksIGZvciBoeXBvdGhlc2lzIHRlc3RpbmcsIHRoZXJlIGFyZSB0d28gd2F5cyB0byBnZXQgaXQgcmlnaHQsIGFuZCB0d28gdHlwZXMgb2YgZXJyb3IuIElmIHlvdSBzdXBwb3J0IHRoZSBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzIHdoZW4gdGhlIG51bGwgaHlwb3RoZXNpcyB3YXMgY29ycmVjdCwgeW91IG1hZGUgYSBmYWxzZSBwb3NpdGl2ZSBlcnJvci4gSWYgeW91IHN1cHBvcnQgdGhlIG51bGwgaHlwb3RoZXNpcyB3aGVuIHRoZSBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzIHdhcyBjb3JyZWN0LCB5b3UgbWFkZSBhIGZhbHNlIG5lZ2F0aXZlIGVycm9yLiBUaGVzZSBlcnJvcnMgYXJlIHNvbWV0aW1lcyBrbm93biBhcyB0eXBlIG9uZSBhbmQgdHlwZSB0d28gZXJyb3JzLg0KDQp8ICAgICAgICAgICAgICAgIHwgQWN0dWFsIEgwICAgICAgfCBBY3R1YWwgSEEgICAgICB8DQp8LS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS18DQp8ICoqQ2hvb3NlbiBIMCoqIHwgY29ycmVjdCAgICAgICAgfCBmYWxzZSBuZWdhdGl2ZSB8DQp8ICoqQ2hvb3NlbiBIQSoqIHwgZmFsc2UgcG9zaXRpdmUgfCBjb3JyZWN0ICAgICAgICB8DQoNCiMjIyAqKlBvc3NpYmxlIGVycm9ycyBpbiBvdXIgZXhhbXBsZSoqDQoNCiMjIyMgDQoNCiQkDQppZiBcIHAgXGxlcXNsYW50IFxhbHBoYSwgd2UgXCByZWplY3QgXCBcIEhfezB9IA0KJCQNCg0KQSBmYWxzZSBwb3NpdGl2ZSAoVHlwZSBJKSBlcnJvciBjb3VsZCBoYXZlIG9jdXJyZWQ6IFdlIHRob3VnaHQgdGhhdCBkYXRhIHNjaWVudGlzdHMgc3RhcnRpbmcgY29kaW5nIGFzIGNoaWxkcmVuIGF0IGEgaGlnaGVyIHJhdGUgd2hlbiBpbiByZWFsaXR5IHRoZXkgZGlkIG5vdA0KDQojIyMjIA0KDQokJA0KaWYgXCBwID4gXGFscGhhLCBcIHdlIFwgZmFpbCBcIHRvIFwgcmVqZWN0IFwgSF97MH0NCiQkDQoNCkEgZmFsc2UgbmVnYXRpdmUgKFR5cGUgSUkpIGVycm9yIGNvdWxkIGhhdmUgb2N1cnJlZDogd2UgdGhvdWdodCB0aGF0IGRhdGEgc2NpZW50aXN0cyBjb2RlZCBhcyBjaGlsZHJlbiBhdCB0aGUgc2FtZSByYXRlIGFzIHNvZnR3YXJlIGVuZ2luZWVycyB3aGVuIGluIHJlYWxpdHkgdGhleSBjb2RlZCBhcyBjaGlsZHJlbiBhdCBhIGhpZ2hlciByYXRlLg0KDQojIyMgKipQZXJmb3JtaW5nIHQtdGVzdHMqKg0KDQpIZXJlLCB3ZSdsbCBsb29rIGF0IHRoZSByZWxhdGVkIHByb2JsZW0gb2YgKipjb21wYXJpbmcgc2FtcGxlIHN0YXRpc3RpY3MgYWNyb3NzIGdyb3VwcyBvZiBhIHZhcmlhYmxlKiouIEluIHRoZSBTdGFjayBPdmVyZmxvdyBkYXRhc2V0LCBgY29udmVydGVkX2NvbXBgIGlzIGEgbnVtZXJpY2FsIHZhcmlhYmxlIG9mIGFubnVhbCBjb21wZW5zYXRpb24uIGBhZ2VfZmlyc3RfY29kZV9jdXRgIGlzIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUgd2l0aCB0d28gbGV2ZWxzOiAqKmNoaWxkIGFuZCBhZHVsdCoqLCB3aGljaCBkZXNjcmliZSB3aGVuIHRoZSB1c2VyIHN0YXJ0ZWQgcHJvZ3JhbW1pbmcuIFdlIGNhbiBhc2sgcXVlc3Rpb25zIGFib3V0IGRpZmZlcmVuY2VzIGluIGNvbXBlbnNhdGlvbiBhY3Jvc3MgdGhlIHR3byBhZ2UgZ3JvdXBzLiBUaGF0IGlzLCAqKmRvIHVzZXJzIHdobyBmaXJzdCBwcm9ncmFtbWVkIGFzIGEgY2hpbGQgdGVuZCB0byBiZSBjb21wZW5zYXRlZCBoaWdoZXIgdGhhbiB0aG9zZSB0aGF0IHN0YXJ0ZWQgYXMgYWR1bHRzKio/DQoNCiMjIyAqKkh5cG90aGVzZXMqKg0KDQpUaGUgbnVsbCBoeXBvdGhlc2lzIGlzIHRoYXQgKip0aGUgc2FtcGxlIG1lYW4gZm9yIHRoZSB0d28gZ3JvdXBzIGlzIHRoZSBzYW1lKiosIGFuZCB0aGUgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcyBpcyB0aGF0ICoqdGhlIHNhbXBsZSBzdGF0aXN0aWMgZm9yIHVzZXJzIHdobyBzdGFydGVkIGNvZGluZyBhcyBjaGlsZHJlbiBpcyBncmVhdGVyIHRoYW4gZm9yIHVzZXJzIHdobyBzdGFydGVkIGNvZGluZyBhcyBhZHVsdHMqKi4gV2UgY2FuIHdyaXRlIHRoZXNlIGh5cG90aGVzZXMgdXNpbmcgZXF1YXRpb25zLiBNdSAoKirCtSoqKSByZXByZXNlbnRzIGFuIHVua25vd24gcG9wdWxhdGlvbiBtZWFuLCBhbmQgd2UgdXNlIHN1YnNjcmlwdHMgdG8gZGVub3RlIHdoaWNoIGdyb3VwIHRoZSBzYW1wbGUgbWVhbiBiZWxvbmdzIHRvLiBBbiBhbHRlcm5hdGUgd2F5IG9mIHdyaXRpbmcgdGhlIGVxdWF0aW9ucyBpcyB0byBjb21wYXJlIHRoZSBkaWZmZXJlbmNlcyBpbiBzYW1wbGUgbWVhbnMgdG8gemVyby4NCg0KIyMjICoqQ2FsY3VsYXRpbmcgZ3JvdXAgd2lzZSBzdW1tYXJ5IHN0YXRpc3RpY3MqKg0KDQpDYWxjdWxhdGluZyB0aGUgc3VtbWFyeSBzdGF0aXN0aWNzIGZvciBlYWNoIGdyb3VwIGlzIHN0cmFpZ2h0Zm9yd2FyZC4gWW91IHN0YXJ0IHdpdGggdGhlIHNhbXBsZSwgZ3JvdXAgYnkgdGhlIGNhdGVnb3JpY2FsIHZhcmlhYmxlLCB0aGVuIHN1bW1hcml6ZSB0aGUgbnVtZXJpYyB2YXJpYWJsZS4gQSBgZHBseXJgIHdheSBvZiBkb2luZyB0aGlzIGlzIHNob3duLCBidXQgdGhlcmUgYXJlIG1hbnkgcG9zc2liaWxpdGllcy4gUGF1c2UgdGhlIHZpZGVvIGZvciBhIG1vbWVudCBhbmQgdGhpbmsgYWJvdXQgZGlmZmVyZW50IHdheXMgb2Ygc29sdmluZyB0aGlzLiBIZXJlLCB0aGUgY2hpbGQgcHJvZ3JhbW1lcnMgaGF2ZSBhIG1lYW4gY29tcGVuc2F0aW9uIG9mIFwkMTMyNDE5LjYgZG9sbGFycyBjb21wYXJlZCB0byBcJDExMTMxMy4zIGZvciBhZHVsdCBwcm9ncmFtbWVycy4gSXMgdGhhdCBpbmNyZWFzZSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IG9yIGNvdWxkIGl0IGJlIGV4cGxhaW5lZCBieSBzYW1wbGluZyB2YXJpYWJpbGl0eT8NCg0KYGBge3J9DQpzdGFja19vdmVyZmxvdyAlPiUNCiAgZ3JvdXBfYnkoYWdlX2ZpcnN0X2NvZGVfY3V0KSAlPiUNCiAgc3VtbWFyaXNlKG1lYW5fY29tcGVuc2F0aW9uID0gbWVhbihjb252ZXJ0ZWRfY29tcCkpDQpgYGANCg0KIyMjICoqVGVzdCBzdGF0aXN0aWNzKioNCg0KQWx0aG91Z2ggd2UgZG9uJ3Qga25vdyB0aGUgcG9wdWxhdGlvbiBtZWFuLCAqKndlIGVzdGltYXRlIGl0IHVzaW5nIHRoZSBzYW1wbGUgbWVhbioqLiAqKngtYmFyKiogaXMgdXNlZCB0byBkZW5vdGUgYSBzYW1wbGUgbWVhbi4gVGhlbiB3ZSB1c2Ugc3Vic2NyaXB0cyB0byBkZW5vdGUgd2hpY2ggZ3JvdXAgYSBzYW1wbGUgbWVhbiBjb3JyZXNwb25kcyB0by4gKipUaGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZXNlIHR3byBzYW1wbGUgbWVhbnMgaXMgY2FsbGVkIHRoZSB0ZXN0IHN0YXRpc3RpYyBmb3IgdGhlIGh5cG90aGVzaXMgdGVzdCoqLiBUaGUgei1zY29yZXMgYXJlIGFub3RoZXIgdHlwZSBvZiB0ZXN0IHN0YXRpc3RpYy4NCg0KIyMjICoqU3RhbmRhcmRpemluZyB0aGUgdGVzdCBzdGF0aXN0aWMqKg0KDQp6LXNjb3JlcyBhcmUgY2FsY3VsYXRlZCBieSB0YWtpbmcgdGhlIHNhbXBsZSBzdGF0aXN0aWMsIHN1YnRyYWN0aW5nIHRoZSBtZWFuIG9mIHRoaXMgc3RhdGlzdGljIGFzIHRoZSBwb3B1bGF0aW9uIHBhcmFtZXRlciBvZiBpbnRlcmVzdCwgdGhlbiBkaXZpZGluZyBieSB0aGUgc3RhbmRhcmQgZXJyb3IuIEluIHRoZSB0d28gc2FtcGxlIGNhc2UsIHRoZSB0ZXN0IHN0YXRpc3RpYywgZGVub3RlZCB0LCB1c2VzIGEgc2ltaWxhciBlcXVhdGlvbi4gWW91IHRha2UgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgc2FtcGxlIHN0YXRpc3RpY3MgZm9yIHRoZSB0d28gZ3JvdXBzLCBzdWJ0cmFjdCB0aGUgaHlwb3RoZXNpemVkIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgdHdvIGdyb3VwcywgdGhlbiBkaXZpZGUgYnkgdGhlIHN0YW5kYXJkIGVycm9yLiAkJA0KeCA9IA0KXGZyYWN7c2FtcGxlIFwgc3RhdCArIHBvcHVsYXRpb24gXCBwYXJhbWV0ZXJ9e3N0YW5kYXJkIFwgZXJyb3J9DQokJA0KDQokJA0KdCA9IFxmcmFje2RpZmZlcmVuY2UgXCBpbiBcIHNhbXBsZSBcIHN0YXRzIFwgLSBkaWZmZXJlbmNlIFwgaW4gXCBwb3B1bGF0aW9uIFwgcGFyYW1ldGVyc317c3RhbmRhcmQgXCBlcnJvcn0NCiQkDQoNCiQkDQp0ID0gXGZyYWN7KFxiYXJ7eH1fe2NoaWxkfSBcIC0gXGJhcnt4fV97YWR1bHR9KSBcIC0gKFxtdV97Y2hpbGR9IFwgLSBcbXVfe2FkdWx0fSl9e1NFKFxiYXJ7eH1fe2NoaWxkfSBcIC0gXGJhcnt4fV97YWR1bHR9KX0NCiQkDQoNCiMjIyAqKlN0YW5kYXJkIEVycm9yKioNCg0KVG8gY2FsY3VsYXRlIHRoZSBzdGFuZGFyZCBlcnJvciwgbmVlZGVkIGZvciB0aGUgZGVub21pbmF0b3Igb2YgdGhlIHRlc3Qgc3RhdGlzdGljIGVxdWF0aW9uLCBib290c3RyYXBwaW5nIGlzIG1vc3QgYWNjdXJhdGUuIEhvd2V2ZXIsIHRoZXJlIGlzIGFuIGVhc2llciB3YXkgdG8gYXBwcm94aW1hdGUgaXQuIFlvdSBjYWxjdWxhdGUgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgbnVtZXJpYyB2YXJpYWJsZSBmb3IgZWFjaCBncm91cCBpbiB0aGUgc2FtcGxlLCBhbmQgdGhlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgZm9yIGVhY2ggZ3JvdXAuIFRoZW4gaXQncyBqdXN0IHNvbWUgYXJpdGhtZXRpYy4NCg0KIyMjICoqQXNzdW1pbmcgdGhlIG51bGwgaHlwb3RoZXNpcyBpcyB0cnVlKioNCg0KSGVyZSdzIHRoZSB0ZXN0IHN0YXRpc3RpYyBlcXVhdGlvbiBhZ2Fpbi4gSWYgd2UgYXNzdW1lIHRoYXQgdGhlICoqbnVsbCBoeXBvdGhlc2lzIGlzIHRydWUqKiwgdGhlcmUncyBhIHNpbXBsaWZpY2F0aW9uIHdlIGNhbiBtYWtlLiAqKlRoZSBudWxsIGh5cG90aGVzaXMgYXNzdW1lcyB0aGF0IHRoZSBwb3B1bGF0aW9uIG1lYW5zIGFyZSBlcXVhbCoqLiBUaGF0IG1ha2VzIG9uZSB0ZXJtIGluIHRoZSBudW1lcmF0b3IgZGlzYXBwZWFyLiBVc2luZyB0aGUgYXBwcm94aW1hdGlvbiBmb3IgdGhlIHN0YW5kYXJkIGVycm9yLCB3ZSBub3cgaGF2ZSBhIHdheSBvZiBjYWxjdWxhdGluZyB0aGUgdGVzdCBzdGF0aXN0aWMgdXNpbmcgb25seSBjYWxjdWxhdGlvbnMgb24gdGhlIHNhbXBsZSBkYXRhc2V0LiBXZSBuZWVkIHRoZSBtZWFuLCBzdGFuZGFyZCBkZXZpYXRpb24sIGFuZCBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zIGZvciBlYWNoIGdyb3VwLiBUaGlzIGlzIGFub3RoZXIgZ3JvdXAtYnkgYW5kIHN1bW1hcml6ZSBjb21iaW5hdGlvbi4gJCQNClNFKFxiYXJ7eH1fe2NoaWxkfSBcIC0gXGJhcnt4fV97YWR1bHR9KSBcYXBwcm94IFxzcXJ0e1xmcmFje3NeMl97Y2hpbGR9fXtuX3tjaGlsZH19IFwgKyBcZnJhY3tzXjJfe2FkdWx0fX17bl97YWR1bHR9fX0NCiQkICQkDQpIX3swfTogXG11X3tjaGlsZH0gXCAtIFxtdV97YWR1bHR9ID0gMA0KJCQNCg0KJCQNCnQgPSBcZnJhY3soXGJhcnt4fV97Y2hpbGR9IFwgLSBcYmFye3h9X3thZHVsdH0pfXtTRShcYmFye3h9X3tjaGlsZH0gXCAtIFxiYXJ7eH1fe2FkdWx0fSl9DQokJA0KDQokJA0KdCA9IFxmcmFjeyhcYmFye3h9X3tjaGlsZH0gXCAtIFxiYXJ7eH1fe2FkdWx0fSl9e1xzcXJ0e1xmcmFje3NeMl97Y2hpbGR9fXtuX3tjaGlsZH19fSBcICsgXGZyYWN7c14yX3thZHVsdH19e25fe2FkdWx0fX19DQokJA0KDQpgYGB7cn0NCmdyb3VwX3Rlc3RzIDwtIHN0YWNrX292ZXJmbG93ICU+JQ0KICBncm91cF9ieShhZ2VfZmlyc3RfY29kZV9jdXQpICU+JQ0KICBzdW1tYXJpc2UoeF9iYXIgPSBtZWFuKGNvbnZlcnRlZF9jb21wKSwgcyA9IHNkKGNvbnZlcnRlZF9jb21wKSwgbiA9IG4oKSkNCg0KIyBTZWUgdGhlIHJlc3VsdHMNCmdyb3VwX3Rlc3RzDQpgYGANCg0KIyMjICoqQ2FsY3VsYXRpbmcgdGhlIHRlc3Qgc3RhdGlzdGljKioNCg0KQW5ub3lpbmdseSwgaXQgcmVxdWlyZXMgc29tZSBncmltIGRhdGEgbWFuaXB1bGF0aW9uIGNvZGUgdG8gY2FsY3VsYXRlIHRoZSB0ZXN0IHN0YXRpc3RpYyBmcm9tIHRoaXMgZGF0YSBmcmFtZS4gU2luY2UgdGhpcyBpc24ndCBhIGNvdXJzZSBvbiBkYXRhIG1hbmlwdWxhdGlvbiwgbGV0J3MgZG8gdGhlIGNhbGN1bGF0aW9uIHdpdGggc2VwYXJhdGUgdmFyaWFibGVzLiBUaGUgbnVtZXJhdG9yIGlzIGEgc2ltcGxlIHN1YnRyYWN0aW9uLCBhbmQgdGhlIGRlbm9taW5hdG9yIGlzIGxpa2UgYSB3ZWlnaHRlZCBoeXBvdGVudXNlLiBUaGUgdC1zdGF0aXN0aWMgaXMgKioxLjg2KiouIEp1c3QgYXMgd2l0aCB6LXNjb3Jlcywgd2UgY2FuJ3QgZG8gYW55dGhpbmcgd2l0aCB0aGF0IG51bWJlciB5ZXQNCg0KIyMjIyANCg0KJCQNCnQgPSBcZnJhY3soXGJhcnt4fV97Y2hpbGR9IFwgLSBcYmFye3h9X3thZHVsdH0pfXtcc3FydHtcZnJhY3tzXjJfe2NoaWxkfX17bl97Y2hpbGR9fSBcICsgXGZyYWN7c14yX3thZHVsdH19e25fe2FkdWx0fX19fQ0KJCQNCg0KYGBge3J9DQpudW1lcmF0b3IgPC0gZ3JvdXBfdGVzdHMkeF9iYXJbMl0gLSBncm91cF90ZXN0cyR4X2JhclsxXQ0KZGVub21pbmF0b3IgPC0gc3FydCgoZ3JvdXBfdGVzdHMkc1syXV4yIC8gZ3JvdXBfdGVzdHMkblsyXSkgKyAoZ3JvdXBfdGVzdHMkc1sxXV4yIC8gZ3JvdXBfdGVzdHMkblsxXSkpDQp0X3N0YXQgPC0gbnVtZXJhdG9yIC8gZGVub21pbmF0b3INCnRfc3RhdA0KYGBgDQoNCiMjIyAqKkh5cG90aGVzaXMgdGVzdGluZyB3b3JrZmxvdyoqDQoNCjEuICBJZGVudGlmeSBwb3B1bGF0aW9uIHBhcmFtZXRlciB0aGF0IGlzIGh5cG90aGVzaXplZCBhYm91dA0KDQoyLiAgU3BlY2lmeSB0aGUgbnVsbCAmIGFsdGVybmF0aXZlIGh5cG90aGVzaXMNCg0KMy4gIERldGVybWluZSAoc3RhbmRhcmRpemVkKSB0ZXN0IHN0YXRpc3RpYyAmIGNvcnJlc3BvbmRpbmcgbnVsbCBkaXN0cmlidXRpb24NCg0KNC4gIENvbmR1Y3QgaHlwb3RoZXNpcyB0ZXN0IGluIFINCg0KNS4gIE1lYXN1cmUgZXZpZGVuY2UgYWdhaW5zdCB0aGUgbnVsbCBoeXBvdGhlc2lzDQoNCjYuICBNYWtlIGEgZGVjaXNpb24gY29tcGFyaW5nIGV2aWRlbmNlIHRvIHNpZ25pZmljYW5jZSBsZXZlbA0KDQo3LiAgSW50ZXJwcmV0IHRoZSByZXN1bHRzIGluIHRoZSBjb250ZXh0IG9mIHRoZSBvcmlnaW5hbCBwcm9ibGVtDQoNCiMjIyAqKkNhbGN1bGF0aW5nIHAtdmFsdWVzIGZyb20gdC1zdGF0aXN0aWNzKioNCg0KVGhlIHRlc3Qgc3RhdGlzdGljLCB0LCBmb2xsb3dzIGEgdC1kaXN0cmlidXRpb24uIHQtZGlzdHJpYnV0aW9ucyBoYXZlIGEgcGFyYW1ldGVyIGNhbGxlZCB0aGUgKipkZWdyZWVzIG9mIGZyZWVkb20qKiwgb3IgKipkZioqIGZvciBzaG9ydC4gSGVyZSdzIGEgbGluZSBwbG90IG9mIHRoZSBQREYgb2YgYSB0LWRpc3RyaWJ1dGlvbiB3aXRoIG9uZSBkZWdyZWUgb2YgZnJlZWRvbSBpbiB5ZWxsb3csIGFuZCB0aGUgUERGIG9mIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiBpbiBibHVlIGRhc2hlcy4gTm90aWNlIHRoYXQgdGhlIHQtZGlzdHJpYnV0aW9uIGZvciBzbWFsbCBkZWdyZWVzIG9mIGZyZWVkb20gaGFzIGZhdHRlciB0YWlscyB0aGFuIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uLCBidXQgb3RoZXJ3aXNlIHRoZXkgbG9vayBzaW1pbGFyLg0KDQojIyMgKipEZWdyZWVzIG9mIGZyZWVkb20qKg0KDQpBcyB5b3UgaW5jcmVhc2UgdGhlIGRlZ3JlZXMgb2YgZnJlZWRvbSwgdGhlIHQtZGlzdHJpYnV0aW9uIGdldHMgY2xvc2VyIHRvIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uLiBJbiBmYWN0LCAqKmEgbm9ybWFsIGRpc3RyaWJ1dGlvbiBpcyBhIHQtZGlzdHJpYnV0aW9uIHdpdGggaW5maW5pdGUgZGVncmVlcyBvZiBmcmVlZG9tKiouIERlZ3JlZXMgb2YgZnJlZWRvbSBhcmUgZGVmaW5lZCBhcyAqKnRoZSBtYXhpbXVtIG51bWJlciBvZiBsb2dpY2FsbHkgaW5kZXBlbmRlbnQgdmFsdWVzIGluIHRoZSBkYXRhIHNhbXBsZSoqLiBUaGF0J3MgYSBmYWlybHkgdHJpY2t5IGNvbmNlcHQsIHNvIGxldCdzIHRyeSBhbiBleGFtcGxlLg0KDQojIyMgKipDYWxjdWxhdGluZyBkZWdyZWVzIG9mIGZyZWVkb20qKg0KDQpTdXBwb3NlIHlvdXIgZGF0YXNldCBoYXMgNSBpbmRlcGVuZGVudCBvYnNlcnZhdGlvbnMuIEZvdXIgb2YgdGhlIHZhbHVlcyBhcmUgMiwgNiwgOCwgYW5kIDUuIFlvdSBhbHNvIGtub3cgdGhlIHNhbXBsZSBtZWFuIGlzIDUuIFRoZSBsYXN0IHZhbHVlIGlzIG5vIGxvbmdlciBpbmRlcGVuZGVudDsgaXQgbXVzdCBiZSA0LiBFdmVuIHRob3VnaCBhbGwgZml2ZSBvYnNlcnZhdGlvbnMgaW4gdGhlIHNhbXBsZSB3ZXJlIGluZGVwZW5kZW50LCBiZWNhdXNlIHlvdSBrbm93IGFuIGFkZGl0aW9uYWwgZmFjdCBhYm91dCBpdCwgeW91IG9ubHkgaGF2ZSA0IGRlZ3JlZXMgb2YgZnJlZWRvbS4gSW4gb3VyIHR3byBzYW1wbGUgY2FzZSwgdGhlcmUgYXJlIGFzIG1hbnkgZGVncmVlcyBvZiBmcmVlZG9tIGFzIG9ic2VydmF0aW9ucywgbWludXMgdHdvIGJlY2F1c2Ugd2Uga25vdyB0d28gc2FtcGxlIHN0YXRpc3RpY3MuDQoNCiMjIyAqKkh5cG90aGVzZXMqKg0KDQpSZWNhbGwgdGhlIGh5cG90aGVzZXMgZm9yIG91ciBTdGFjayBPdmVyZmxvdyBxdWVzdGlvbiBhYm91dCBjb21wZW5zYXRpb24gZm9yIHRoZSB0d28gYWdlIGdyb3Vwcy4gU2luY2UgdGhpcyBpcyBhICJncmVhdGVyIHRoYW4iIGFsdGVybmF0aXZlIGh5cG90aGVzaXMsIHdlIG5lZWQgYSByaWdodC10YWlsZWQgdGVzdC4NCg0KJEhfezB9OiQgKlRoZSBtZWFuIGNvbXBlbnNhdGlvbiAoaW4gVVNEKSBpcyB0aGUgc2FtZSBmb3IgdGhvc2UgdGhhdCBjb2RlZCBmaXJzdCBhcyBhIGNoaWxkIGFuZCB0aG9zZSB0aGF0IGNvZGVkIGZpcnN0IGFzIGFuIGFkdWx0LioNCg0KJEhfe0F9OiQgKlRoZSBtZWFuIGNvbXBlbnNhdGlvbiAoaW4gVVNEKSBpcyAqKmdyZWF0ZXIqKiBmb3IgdGhvc2UgdGhhdCBjb2RlZCBmaXJzdCBhcyBhIGNoaWxkIGNvbXBhcmVkIHRvIHRob3NlIHRoYXQgY29kZWQgZmlyc3QgYXMgYW4gYWR1bHQuKg0KDQpVc2UgYSAqKnJpZ2h0LXRhaWxlZCB0ZXN0KioNCg0KIyMjICoqU2lnbmlmaWNhbmNlIGxldmVsKioNCg0KV2UncmUgZ29pbmcgdG8gY2FsY3VsYXRlIGEgcC12YWx1ZSBpbiBhIG1vbWVudC4gV2UgbmVlZCB0byBkZWNpZGUgb24gYSBzaWduaWZpY2FuY2UgbGV2ZWwgYmVmb3JlIHdlIGRvIHRoYXQuIFRoZXJlIGFyZSBzZXZlcmFsIHBvc3NpYmlsaXRpZXM7IEknbSBnb2luZyB0byB1c2UgMC4xDQoNClRoYXQgbWVhbnMgdGhhdCBpZiB0aGUgcC12YWx1ZSBpcyBsZXNzIHRoYW4gcG9pbnQtb25lLCB3ZSByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBpbiBmYXZvciBvZiB0aGUgYWx0ZXJuYXRpdmUuDQoNCiQkXGFscGhhID0gMC4xJCQNCg0KJCQNCmlmIFwgcCBcbGVxc2xhbnQgXGFscGhhIFwgdGhlbiBcIHJlamVjdCBcIEhfezB9DQokJA0KDQojIyMgKipDYWxjdWxhdGluZyBwLXZhbHVlczogT25lIHByb3BvcnRpb24gdnMuIGEgdmFsdWUqKg0KDQoqKmBwX3ZhbHVlIDwtIHBub3JtKHpfc2NvcmUsIGxvZXIudGFpbCA9IEZBTFNFKWAqKg0KDQojIyMgKipDYWxjdWxhdGluZyBwLXZhbHVlczogVHdvIG1lYW5zIGZyb20gZGlmZmVyZW50IGdyb3VwcyoqDQoNCiQkDQp0ID0gXGZyYWN7KFxiYXJ7eH1fe2NoaWxkfSBcIC0gXGJhcnt4fV97YWR1bHR9KX17XHNxcnR7XGZyYWN7c14yX3tjaGlsZH19e25fe2NoaWxkfX0gXCArIFxmcmFje3NeMl97YWR1bHR9fXtuX3thZHVsdH19fX0NCiQkDQoNCk5vdyB3ZSBhcmUgY2FsY3VsYXRpbmcgbWVhbnMgcmF0aGVyIHRoYW4gcHJvcG9ydGlvbnMsIHRoZSB6LXNjb3JlIGlzIHJlcGxhY2VkIHdpdGggYSB0LXRlc3Qgc3RhdGlzdGljLiBUaGUgY2FsY3VsYXRpb24gYWxzbyBuZWVkcyB0aGUgZGVncmVlcyBvZiBmcmVlZG9tLCB3aGljaCBpcyB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBpbiBib3RoIGdyb3VwcywgbWludXMgdHdvLg0KDQpJbiB0aGUgcHJldmlvdXMgc3RlcHMsIHdlIHVzZWQgYW4gYXBwcm94aW1hdGlvbiB1c2luZyBzYW1wbGUgaW5mb3JtYXRpb24gKG5vdCBib290c3RyYXBwaW5nKSBmb3IgdGhlIHRlc3Qgc3RhdGlzdGljIHN0YW5kYXJkIGVycm9yLiBBIGNvbnNlcXVlbmNlIG9mIHRoaXMgaXMgdGhhdCB0byBjYWxjdWxhdGUgdGhlIHAtdmFsdWUsIHdlIG5lZWQgdG8gdHJhbnNmb3JtIHRoZSB0ZXN0IHN0YXRpc3RpYyB1c2luZyB0aGUgdC1kaXN0cmlidXRpb24gQ0RGIGluc3RlYWQgb2YgdGhlIG5vcm1hbCBkaXN0cmlidXRpb24gQ0RGLiBVc2luZyB0aGlzIGFwcHJveGltYXRpb24gYWRkcyBtb3JlIHVuY2VydGFpbnR5IGFuZCB0aGF0J3Mgd2h5IHRoaXMgaXMgYSB0IGluc3RlYWQgb2YgYSB6IHByb2JsZW0uDQoNClRoZSB0IGRpc3RyaWJ1dGlvbiBhbGxvd3MgZm9yIG1vcmUgdW5jZXJ0YWludHkgd2hlbiB1c2luZyBtdWx0aXBsZSBlc3RpbWF0ZXMgaW4gYSBzaW5nbGUgc3RhdGlzdGljIGNhbGN1bGF0aW9uLiBOb3RpY2UgdGhlIHVzZSBvZiBgcHQoKWAgaW5zdGVhZCBvZiBgcG5vcm0oKWAsIGFuZCB0aGF0IHRoZSBkZiBhcmd1bWVudCBpcyBzZXQgdG8gdGhlIGRlZ3JlZXMgb2YgZnJlZWRvbS4gVGhpcyBwLXZhbHVlIGlzIGxlc3MgdGhhbiB0aGUgc2lnbmlmaWNhbmNlIGxldmVsIG9mICoqMC4xKiosIHdlIHNob3VsZCByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBpbiBmYXZvciBvZiB0aGUgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcyB0aGF0IFN0YWNrIE92ZXJmbG93IGRhdGEgc2NpZW50aXN0cyB3aG8gc3RhcnRlZCBjb2RpbmcgYXMgYSBjaGlsZCBlYXJuIG1vcmUuDQoNCmBgYHtyfQ0KbnVtZXJhdG9yIDwtIGdyb3VwX3Rlc3RzJHhfYmFyWzJdIC0gZ3JvdXBfdGVzdHMkeF9iYXJbMV0NCmRlbm9taW5hdG9yIDwtIHNxcnQoKGdyb3VwX3Rlc3RzJHNbMl1eMiAvIGdyb3VwX3Rlc3RzJG5bMl0pICsgKGdyb3VwX3Rlc3RzJHNbMV1eMiAvIGdyb3VwX3Rlc3RzJG5bMV0pKQ0KdF9zdGF0IDwtIG51bWVyYXRvciAvIGRlbm9taW5hdG9yDQp0X3N0YXQNCmBgYA0KDQpgYGB7cn0NCmRlZ3JlZXNfb2ZfZnJlZWRvbSA8LSBncm91cF90ZXN0cyRuWzJdICsgZ3JvdXBfdGVzdHMkblsxXSAtIDINCmRlZ3JlZXNfb2ZfZnJlZWRvbQ0KYGBgDQoNCmBgYHtyfQ0KcF92YWx1ZSA8LSBwdCh0X3N0YXQsIGRmID0gZGVncmVlc19vZl9mcmVlZG9tLCBsb3dlci50YWlsID0gRkFMU0UpDQpwX3ZhbHVlDQpgYGANCg0KIyMjICoqV2h5IGlzIHQgbmVlZGVkPyoqDQoNClRoZSBwcm9jZXNzIGZvciBjYWxjdWxhdGluZyBwLXZhbHVlcyBpcyB0byBzdGFydCB3aXRoIHRoZSBzYW1wbGUgc3RhdGlzdGljLCBzdGFuZGFyZGl6ZSBpdCB0byBnZXQgYSB0ZXN0IHN0YXRpc3RpYywgdGhlbiB0cmFuc2Zvcm0gaXQgdmlhIGEgY3VtdWxhdGl2ZSBkaXN0cmlidXRpb24gZnVuY3Rpb24uIFByZXZpb3VzbHksIHRoYXQgZmluYWwgdHJhbnNmb3JtYXRpb24gd2FzIGRlbm90ZWTCoGB6YCwgYW5kIHRoZSBDREYgdHJhbnNmb3JtYXRpb24gdXNlZCB0aGUgKHN0YW5kYXJkIG5vcm1hbCkgei1kaXN0cmlidXRpb24uIFRoZSB0ZXN0IHN0YXRpc3RpYyB3YXMgZGVub3RlZMKgYHRgLCBhbmQgdGhlIHRyYW5zZm9ybWF0aW9uIHVzZWQgdGhlIHQtZGlzdHJpYnV0aW9uLg0KDQpJbiB3aGljaCBoeXBvdGhlc2lzIHRlc3Rpbmcgc2NlbmFyaW8gaXMgYSB0LWRpc3RyaWJ1dGlvbiBuZWVkZWQgaW5zdGVhZCBvZiB0aGUgei1kaXN0cmlidXRpb24/DQoNCioqVXNpbmcgYSBzYW1wbGUgc3RhbmRhcmQgZGV2aWF0aW9uIHRvIGVzdGltYXRlIHRoZSBzdGFuZGFyZCBlcnJvciBpcyBjb21wdXRhdGlvbmFsbHkgZWFzaWVyIHRoYW4gdXNpbmcgYm9vdHN0cmFwcGluZy4gSG93ZXZlciwgdG8gY29ycmVjdCBmb3IgdGhlIGFwcHJveGltYXRpb24sIHlvdSBuZWVkIHRvIHVzZSBhIHQtZGlzdHJpYnV0aW9uIHdoZW4gdHJhbnNmb3JtaW5nIHRoZSB0ZXN0IHN0YXRpc3RpYyB0byBnZXQgdGhlIHAtdmFsdWUuKioNCg0KIyMgKipBTk9WQSB0ZXN0cyoqDQoNCldlwrR2ZSBzZWVuIGhvdyB0byBjb21wYXJlIHR3byBncm91cHMgaW4gdGhlIHVucGFpcmVkIGFuZCBwYWlyZWQgY2FzZXMuIFdoYXQgaWYgdGhlcmUgYXJlIG1vcmUgdGhhbiB0d28gZ3JvdXBzPw0KDQojIyMgKipKb2Igc2F0aXNmYWN0aW9uOiA1IGNhdGVnb3JpZXMqKg0KDQpUaGUgU3RhY2sgT3ZlcmZsb3cgc3VydmV5IGluY2x1ZGVzIGEgam9iIHNhdGlzZmFjdGlvbiB2YXJpYWJsZSwgd2l0aCBmaXZlIGNhdGVnb3JpZXMgZnJvbSAiVmVyeSBkaXNzYXRpc2ZpZWQiIHRvICJWZXJ5IHNhdGlzZmllZCIuDQoNCmBgYHtyfQ0Kc3RhY2tfb3ZlcmZsb3cgJT4lDQogIGNvdW50KGpvYl9zYXQpDQpgYGANCg0KIyMjICoqVmlzdWFsaXppbmcgbXVsdGlwbGUgZGlzdHJpYnV0aW9ucyoqDQoNClN1cHBvc2Ugd2Ugd2FudCB0byBrbm93IGlmIG1lYW4gYW5udWFsIGNvbXBlbnNhdGlvbiBpcyBkaWZmZXJlbnQgZm9yIGVhY2ggb2YgdGhlIGxldmVscyBvZiBqb2Igc2F0aXNmYWN0aW9uLiBUaGUgZmlyc3QgdGhpbmcgdG8gZG8gaXMgdmlzdWFsaXplIHRoZSBkaXN0cmlidXRpb25zIHdpdGggYm94IHBsb3RzLiBJJ3ZlIHVzZWQgY29vcmRfZmxpcCB0byBzd2FwIHRoZSB4IGFuZCB5IGF4ZXMsIG1ha2luZyB0aGUgY2F0ZWdvcnkgbGFiZWxzIGVhc2llciB0byByZWFkLiAiVmVyeSBzYXRpc2ZpZWQiIGxvb2tzIHNsaWdodGx5IGhpZ2hlciB0aGFuIHRoZSBvdGhlcnMsIGJ1dCB0byBzZWUgaWYgdGhleSBhcmUgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQsIHdlJ2xsIG5lZWQgdG8gdXNlIGh5cG90aGVzaXMgdGVzdHMuDQoNCiMjIyMgUXVlc3Rpb246IElzIG1lYW4gYW5udWFsIGNvbXBlbnNhdGlvbiBkaWZmZXJlbnQgZm9yIGRpZmZlcmVudCBsZXZlbHMgb2Ygam9iIHNhdGlzZmFjdGlvbj8NCg0KYGBge3J9DQpzdGFja19vdmVyZmxvdyAlPiUgDQogIGdncGxvdChhZXMoeCA9IGpvYl9zYXQsIHkgPSBjb252ZXJ0ZWRfY29tcCkpICsgDQogIGdlb21fYm94cGxvdCgpICsgDQogIGNvb3JkX2ZsaXAoKQ0KYGBgDQoNCiMjIyAqKkFuYWx5c2lzIG9mIHZhcmlhbmNlIChBTk9WQSkqKg0KDQoqKkFOT1ZBIHRlc3RzIGRldGVybWluZSB3aGV0aGVyIHRoZXJlIGFyZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZSBncm91cHMqKi4gRmlyc3QsIHlvdSBmaXQgYSBsaW5lYXIgcmVncmVzc2lvbi4gWW91IGNhbGwgYGxtKClgLCAqKnNwZWNpZnlpbmcgdGhlIG51bWVyaWMgdmFyaWFibGUgYXMgdGhlIHJlc3BvbnNlIG9uIHRoZSBsZWZ0LWhhbmQtc2lkZSBvZiB0aGUgZm9ybXVsYSwgYW5kIHRoZSBjYXRlZ29yaWVzIGFzIHRoZSBleHBsYW5hdG9yeSB2YXJpYWJsZSBvbiB0aGUgcmlnaHQtaGFuZCBzaWRlKiouIFRoZW4geW91IGNhbGwgYGFub3ZhKClgIHRvIHBlcmZvcm0gYW4gYW5hbHlzaXMgb2YgdmFyaWFuY2UgdGVzdC4NCg0KSW4gdGhlIGBqb2Jfc2F0YCByb3csIHRoZSByaWdodC1oYW5kIGNvbHVtbiBjb250YWlucyBhIHAtdmFsdWUsIHdoaWNoIGlzICoqMC4wMDEzKiouIFRoZSB0d28gc3RhcnMgbmV4dCB0byBpdCB0ZWxsIHlvdSB0aGF0ICoqdGhpcyBwLXZhbHVlIGlzIHNpZ25pZmljYW50IGF0IHRoZSBwb2ludC16ZXJvLW9uZSBsZXZlbCoqLiBUaGF0IG1lYW5zIHRoYXQgYXQgbGVhc3QgdHdvIG9mIHRoZSBjYXRlZ29yaWVzIG9mIGpvYiBzYXRpc2ZhY3Rpb24gaGF2ZSBzaWduaWZpY2FudCBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZWlyIGNvbXBlbnNhdGlvbiBsZXZlbHMuIFRoZSBwcm9ibGVtIGlzIHRoYXQgdGhpcyBtZXRob2QgZG9lc24ndCB0ZWxsIHlvdSB3aGljaCB0d28gY2F0ZWdvcmllcyB0aGV5IGFyZS4gRm9yIHRoaXMgcmVhc29uLCBBTk9WQSBpcyBsZXNzIHVzZWZ1bCB0aGFuIHBhaXJ3aXNlIHQtdGVzdHMuDQoNCmBgYHtyfQ0KbWRsX2NvbXBfdnNfc2F0IDwtIGxtKGNvbnZlcnRlZF9jb21wIH4gam9iX3NhdCwgZGF0YSA9IHN0YWNrX292ZXJmbG93KQ0KbWRsX2NvbXBfdnNfc2F0DQpgYGANCg0KYGBge3J9DQphbm92YShtZGxfY29tcF92c19zYXQpDQpgYGANCg0KIyMjICoqUGFpcndpc2UgdGVzdHMqKg0KDQpUbyBjb21wYXJlIGFsbCBmaXZlIGNhdGVnb3JpZXMgb2Ygam9iIHNhdGlzZmFjdGlvbiB1c2luZyBoeXBvdGhlc2lzIHRlc3RzLCB3ZSBjYW4gdGVzdCBlYWNoIHBhaXIuIFRoZXJlIGFyZSB0ZW4gd2F5cyBvZiBjaG9vc2luZyB0d28gaXRlbXMgZnJvbSBhIHNldCBvZiBmaXZlLCBzbyB3ZSBoYXZlIHRlbiB0ZXN0cyB0byBwZXJmb3JtLiBXZSdsbCBzZXQgdGhlIHNpZ25pZmljYW5jZSBsZXZlbCB0byBwb2ludC10d28uDQoNCi0gICAkXG11X3t2ZXJ5IFwgZGlzc2F0aXNmaWVkfSBcbmVxIFxtdV97c2xpZ2h0bHkgXCBkaXNzYXRpc2ZpZWR9JA0KDQotICAgJFxtdV97dmVyeSBcIGRpc3NhdGlzZmllZH0gXG5lcSBcbXVfe05laXRoZXJ9JA0KDQotICAgJFxtdV97dmVyeSBcIGRpc3NhdGlzZmllZH0gXG5lcSBcbXVfe1NsaWdodGx5IFwgc2F0aXNmaWVkfSQNCg0KLSAgICRcbXVfe3ZlcnkgXCBkaXNzYXRpc2ZpZWR9IFxuZXEgXG11X3tWZXJ5IFwgc2F0aXNmaWVkfSQNCg0KLSAgICRcbXVfe1NsaWdodGx5IFwgZGlzc2F0aXNmaWVkfSBcbmVxIFxtdV97TmVpdGhlcn0kDQoNCi0gICAkXG11X3tTbGlnaHRseSBcIGRpc3NhdGlzZmllZH0gXG5lcSBcbXVfe1NsaWdodGx5IFwgc2F0aXNmaWVkfSQNCg0KLSAgICRcbXVfe1NsaWdodGx5IFwgZGlzc2F0aXNmaWVkfSBcbmVxIFxtdV97VmVyeSBcIHNhdGlzZmllZH0kDQoNCi0gICAkXG11X3tOZWl0aGVyfSBcbmVxIFxtdV97U2xpZ2h0bHkgXCBzYXRpc2ZpZWR9JA0KDQotICAgJFxtdV97TmVpdGhlcn0gXG5lcSBcbXVfe1ZlcnkgXCBzYXRpc2ZpZWR9JA0KDQotICAgJFxtdV97U2xpZ2h0bHkgXCBzYXRpc2ZpZWR9IFxuZXEgXG11X3tWZXJ5IFwgc2F0aXNmaWVkfSQNCg0KIyMjICoqcGFpcndpc2UudC50ZXN0KCkqKg0KDQpUbyBydW4gYWxsIHRoZXNlIGh5cG90aGVzaXMgdGVzdHMgaW4gb25lIGdvLCB5b3UgY2FuIHVzZSBgcGFpcndpc2UudC10ZXN0KClgLiBUaGUgZmlyc3QgYXJndW1lbnQgaXMgdGhlIG51bWVyaWMgdmFyaWFibGUgd2hvc2Ugc2FtcGxlIG1lYW5zIHlvdSBhcmUgaW50ZXJlc3RlZCBpbi4gVGhlIHNlY29uZCBhcmd1bWVudCBpcyB0aGUgY2F0ZWdvcmljYWwgdmFyaWFibGUgZGVmaW5pbmcgdGhlIGdyb3Vwcy4gV2UnbGwgZGlzY3VzcyBgcC5hZGp1c3QubWV0aG9kYCBzaG9ydGx5LiBUaGUgcmVzdWx0IHNob3dzIGEgbWF0cml4IG9mIHRlbiBwLXZhbHVlcy4gVGhyZWUgb2YgdGhlc2UgYXJlIGxlc3MgdGhhbiBvdXIgc2lnbmlmaWNhbmNlIGxldmVsIG9mIHBvaW50LXR3by4NCg0KYGBge3J9DQphbm92YV9yZXN1bHRzIDwtIHBhaXJ3aXNlLnQudGVzdChzdGFja19vdmVyZmxvdyRjb252ZXJ0ZWRfY29tcCwgc3RhY2tfb3ZlcmZsb3ckam9iX3NhdCwgcC5hZGp1c3QubWV0aG9kID0gIm5vbmUiKQ0KYW5vdmFfcmVzdWx0cw0KI3BfdmFsdWVzIDwtIGFzLnZlY3Rvcih1bmxpc3QobmEub21pdChhbm92YV9yZXN1bHRzJHAudmFsdWUpKSkNCnBfdmFsdWVzIDwtIGFzLnZlY3Rvcih1bmxpc3QoYW5vdmFfcmVzdWx0cyRwLnZhbHVlKSkNCnBfdmFsdWVzIDwtIG5hLm9taXQocF92YWx1ZXMpDQojcF92YWx1ZXMgPC0gYW5vdmFfcmVzdWx0cyRwLnZhbHVlW2NvbXBsZXRlLmNhc2VzKGFub3ZhX3Jlc3VsdHMkcC52YWx1ZSldDQpgYGANCg0KYGBge3J9DQpwX3ZhbHVlcw0KYGBgDQoNCiMjIyAqKkFzIHRoZSBuby4gb2YgZ3JvdXBzIGluY3JlYXNlcy4uLioqDQoNCkluIHRoaXMgY2FzZSB3ZSBoYXZlIGZpdmUgZ3JvdXBzLCByZXN1bHRpbmcgaW4gdGVuIHBhaXJzLiAqKkFzIHRoZSBudW1iZXIgb2YgZ3JvdXBzIGluY3JlYXNlcywgdGhlIG51bWJlciBvZiBwYWlycyAtIGFuZCBoZW5jZSB0aGUgbnVtYmVyIG9mIGh5cG90aGVzaXMgdGVzdHMgLSBpbmNyZWFzZXMgcXVhZHJhdGljYWxseSoqLiBUaGUgbW9yZSB0ZXN0cyB5b3UgcnVuLCB0aGUgaGlnaGVyIHRoZSBjaGFuY2UgdGhhdCBhdCBsZWFzdCBvbmUgb2YgdGhlbSB3aWxsIGdpdmUgYSBmYWxzZSBwb3NpdGl2ZSBzaWduaWZpY2FudCByZXN1bHQuIFdpdGggYSBzaWduaWZpY2FuY2UgbGV2ZWwgb2YgKiowLjIqKiwgaWYgeW91IHJ1biBvbmUgdGVzdCwgdGhlIGNoYW5jZSBvZiBhIGZhbHNlIHBvc2l0aXZlIHJlc3VsdCBpcyAqKjAuMioqLiBXaXRoIGZpdmUgZ3JvdXBzIGFuZCB0ZW4gdGVzdHMsIHRoZSBwcm9iYWJpbGl0eSBvZiBhdCBsZWFzdCBvbmUgZmFsc2UgcG9zaXRpdmUgaXMgYXJvdW5kIDAuNy4gV2l0aCB0d2VudHkgZ3JvdXBzLCBpdCdzIGFsbW9zdCBndWFyYW50ZWVkIHRoYXQgeW91J2xsIGdldCBhdCBsZWFzdCBvbmUgZmFsc2UgcG9zaXRpdmUuDQoNCiMjIyAqKkJvbmZlcnJvbmkgY29ycmVjdGlvbioqDQoNClRoZSBzb2x1dGlvbiB0byB0aGlzIGlzIHRvIGFwcGx5IGFuIGFkanVzdG1lbnQgdG8gaW5jcmVhc2UgdGhlIHAtdmFsdWVzLCByZWR1Y2luZyB0aGUgY2hhbmNlIG9mIGdldHRpbmcgYSBmYWxzZSBwb3NpdGl2ZS4gT25lIGNvbW1vbiBhZGp1c3RtZW50IGlzIHRoZSBCb25mZXJyb25pIGNvcnJlY3Rpb24uIE5vdyBvbmx5IHR3byBvZiB0aGUgcGFpcnMgYXBwZWFyIHRvIGhhdmUgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZXMuDQoNCmBgYHtyfQ0KcGFpcndpc2UudC50ZXN0KHN0YWNrX292ZXJmbG93JGNvbnZlcnRlZF9jb21wLCBzdGFja19vdmVyZmxvdyRqb2Jfc2F0LCBwLmFkanVzdC5tZXRob2QgPSAiYm9uZmVycm9uaSIpDQpgYGANCg0KIyMjICoqTW9yZSBtZXRob2RzKioNCg0KUiBwcm92aWRlcyBzZXZlcmFsIG1ldGhvZHMgZm9yIGFkanVzdGluZyB0aGUgcC12YWx1ZXMuIFlvdSBjYW4gbGlzdCB0aGVpciBuYW1lcyB3aXRoIGBwLmFkanVzdC5tZXRob2RzID1gLg0KDQoqKkhvbG0qKiBhZGp1c3RtZW50IGlzIHRoZSBkZWZhdWx0LiBJdCdzIGxlc3Mgc3RyaWN0IHRoYW4gKipCb25mZXJyb25pKiosIGJ1dCB3b3JrcyB3ZWxsIGluIG1vc3Qgc2l0dWF0aW9ucy4NCg0KYGBge3J9DQpwLmFkanVzdC5tZXRob2RzDQpgYGANCg0KIyMjICoqQm9uZmVycm9uaSBhbmQgSG9sZCBhZGp1c3RtZW50cyoqDQoNCklmIHlvdSBoYXZlIHRlbiB0ZXN0cywgQm9uZmVycm9uaSBqdXN0IG11bHRpcGxpZXMgdGhlIHAtdmFsdWVzIGJ5IHRlbiB1cCB0byBhIG1heGltdW0gb2Ygb25lLiBIb2xtIHdpbGwgbXVsdGlwbHkgdGhlIHNtYWxsZXN0IGJ5IHRlbiwgdGhlbiB0aGUgc2Vjb25kIHNtYWxsZXN0IGJ5IG5pbmUsIGFuZCBzbyBvbi4gVGhlcmUncyBhIHBvc3NpYmxlIGV4dHJhIGNvcnJlY3Rpb24gdG8gbWFrZSBzdXJlIHRoYXQgdGhlIG9yZGVyIG9mIHAtdmFsdWVzIGZyb20gc21hbGxlc3QgdG8gbGFyZ2VzdCBpcyBwcmVzZXJ2ZWQsIGJ1dCB0aGF0J3MgdGhlIGdpc3Qgb2YgaXQuDQoNCmBgYHtyfQ0KcF92YWx1ZXMNCmBgYA0KDQojIyMjICoqQm9uZmVycm9uaSoqDQoNCmBgYHtyfQ0KcG1pbigxLCAxMCAqIHBfdmFsdWVzKQ0KYGBgDQoNCiMjIyMgKipIb2xtKioNCg0KYGBge3J9DQpwbWluKDEsIDE6MTAgKiBzb3J0KHBfdmFsdWVzKSkNCmBgYA0KDQojIyAqKk9uZS1zYW1wbGUgcHJvcG9ydGlvbiB0ZXN0cyoqDQoNClRoZSBwcmV2aW91cyBleGFtcGxlIHRlc3RlZCBhIHNpbmdsZSBwcm9wb3J0aW9uIGFnYWluc3QgYSBzcGVjaWZpYyB2YWx1ZS4gQXMgd2l0aCBtZWFucywgd2UgY2FuIGFsc28gdGVzdCBkaWZmZXJlbmNlcyBiZXR3ZWVuIHByb3BvcnRpb25zIGluIHR3byBwb3B1bGF0aW9ucy4NCg0KIyMjICoqUmVjYXAqKg0KDQpUaGUgcHJldmlvdXMgaHlwb3RoZXNpcyB0ZXN0cyAqKm1lYXN1cmVkIHdoZXRoZXIgb3Igbm90IGFuIHVua25vd24gcG9wdWxhdGlvbiBwcm9wb3J0aW9uIHdhcyBlcXVhbCB0byBzb21lIHZhbHVlKiouIFdlIHVzZWQgYSBib290c3RyYXAgZGlzdHJpYnV0aW9uIG9mIHRoZSBzYW1wbGUgdG8gZSoqc3RpbWF0ZSB0aGUgc3RhbmRhcmQgZXJyb3Igb2YgdGhlIHNhbXBsZSBzdGF0aXN0aWMqKi4gVGhlIHN0YW5kYXJkIGVycm9yIHdhcyB1c2VkIHRvIGNhbGN1bGF0ZSBhIHN0YW5kYXJkaXplZCB0ZXN0IHN0YXRpc3RpYywgd2hpY2ggd2FzIHVzZWQgdG8gZ2V0IGEgcC12YWx1ZSwgd2hpY2ggd2FzIHVzZWQgdG8gZGVjaWRlIHdoZXRoZXIgb3Igbm90IHRvIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzLiBCb290c3RyYXAgZGlzdHJpYnV0aW9ucyBjYW4gYmUgY29tcHV0YXRpb25hbGx5IGludGVuc2l2ZSB0byBjYWxjdWxhdGUsIHNvIHRoaXMgdGltZSB3ZSdsbCBjYWxjdWxhdGUgdGhlIHRlc3Qgc3RhdGlzdGljIHdpdGhvdXQgaXQuDQoNCiMjIyAqKlN0YW5kYXJkaXplZCB0ZXN0IHN0YXRpc3RpYyBmb3IgcHJvcG9ydGlvbnMqKg0KDQpBbiB1bmtub3duIHBvcHVsYXRpb24gcGFyYW1ldGVyIHRoYXQgaXMgYSBwcm9wb3J0aW9uLCAqKm9yIHBvcHVsYXRpb24gcHJvcG9ydGlvbiBmb3Igc2hvcnQsKiogaXMgZGVub3RlZCBgcGAuIFRoZSBzYW1wbGUgcHJvcG9ydGlvbiBpcyBkZW5vdGVkICRcaGF0e3B9JCwgYW5kIHRoZSBoeXBvdGhlc2l6ZWQgdmFsdWUgZm9yIHRoZSBwb3B1bGF0aW9uIHByb3BvcnRpb24gaXMgZGVub3RlZCAkcF97MH0kIC4gQXMgc2VlbiBwcmV2aW91c2x5LCB0aGUgc3RhbmRhcmRpemVkIHRlc3Qgc3RhdGlzdGljIGlzIGEgei1zY29yZS4gKipZb3UgY2FsY3VsYXRlIGl0IGJ5IHN0YXJ0aW5nIHdpdGggdGhlIHNhbXBsZSBzdGF0aXN0aWMsIHN1YnRyYWN0aW5nIGl0cyBtZWFuLCB0aGVuIGRpdmlkaW5nIGJ5IGl0cyBzdGFuZGFyZCBlcnJvcioqLg0KDQokXGhhdHtwfSQgbWludXMgdGhlIG1lYW4gb2YgJFxoYXR7cH0kICwgZGl2aWRlZCBieSB0aGUgc3RhbmRhcmQgZXJyb3Igb2YgJFxoYXR7cH0kIC4NCg0KUmVjYWxsIGZyb20gU2FtcGxpbmcgaW4gUiwgdGhlIG1lYW4gb2YgJFxoYXR7cH0kIGlzICRwJC4gVW5kZXIgdGhlIG51bGwgaHlwb3RoZXNpcywgdGhlIHVua25vd24gcHJvcG9ydGlvbiBwIGlzIGFzc3VtZWQgdG8gYmUgdGhlIGh5cG90aGVzaXplZCBwb3B1bGF0aW9uIHBhcmFtZXRlciAkcF97MH0kLiBUaGUgei1zY29yZSBpcyBub3cgJFxoYXR7cH0kIG1pbnVzICRwX3swfSQsIGRpdmlkZWQgYnkgdGhlIHN0YW5kYXJkIGVycm9yIG9mICRcaGF0e3B9JC4NCg0KJHAkIDogU2FtcGxlIHByb3BvcnRpb24NCg0KJFxoYXR7cH0kIDogc2FtcGxlIHByb3BvcnRpb24gKHNhbXBsZSBzdGF0aXN0aWMpDQoNCiRwX3swfSQgOiBoeXBvdGhlc2l6ZWQgcG9wdWxhdGlvbiBwcm9wb3J0aW9uDQoNCiQkIHogPSBcZnJhY3tcaGF0e3B9IFwgLSBtZWFuKFxoYXR7cH0pfXtzdGFuZGFyZCBcIGVycm9yKFxoYXR7cH0pfSA9IFxmcmFje1xoYXR7cH0gXCAtIHB9e3N0YW5kYXJkIFwgZXJyb3IoXGhhdHtwfSl9ICQkDQoNCkFzc3VtaW5nICRIX3swfSQgaXMgdHJ1ZS4gJHAgPSBwX3swfSQuIHNvDQoNCiQkIHogPSBcZnJhY3tcaGF0e3B9IFwgLSBwX3swfX17c3RhbmRhcmQgXCBlcnJvcihcaGF0e3B9KX0gJCQNCg0KIyMjICoqRWFzaWVyIHN0YW5kYXJkIGVycm9yIGNhbGN1bGF0aW9ucyoqDQoNCkhlcmUncyB0aGUgYXBwcm94aW1hdGUgc3RhbmRhcmQgZXJyb3IgZm9yIHR3byBzYW1wbGUgbWVhbnMuIEZvciBwcm9wb3J0aW9ucywgdW5kZXIgJEhfezB9JCwgdGhlIHN0YW5kYXJkIGVycm9yIG9mICRcaGF0e3B9JCBpcyAkcF97MH0kIHRpbWVzICQxIC0gcF97MH0kICwgZGl2aWRlZCBieSB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucywgdGhlbiBzcXVhcmUtcm9vdGVkLiBXZSBjYW4gc3Vic3RpdHV0ZSB0aGlzIGludG8gb3VyIGVxdWF0aW9uIGZvciB0aGUgei1zY29yZS4gVGhpcyBpcyBlYXN5IHRvIGNhbGN1bGF0ZSBiZWNhdXNlIGl0IG9ubHkgdXNlcyAkXGhhdHtwfSQgYW5kICRuJCwgd2hpY2ggd2UgZ2V0IGZyb20gdGhlIHNhbXBsZSwgYW5kICRwX3swfSQsIHdoaWNoIHdlIGNob3NlLg0KDQokJCBTRShcYmFye3h9X3tjaGlsZH0gXCAtIFxiYXJ7eH1fe2FkdWx0fSkgXGFwcHJveCBcc3FydHtcZnJhY3tzXjJfe2NoaWxkfX17bl97Y2hpbGR9fSBcICsgXGZyYWN7c14yX3thZHVsdH19e25fe2FkdWx0fX19ICQkDQoNCiQkIFNFX3tcaGF0e3B9fSBcID0gXHNxcnR7XGZyYWN7cF97MH0gXCAqICgxIC0gcF97MH0pfXtufX0gJCQNCg0KQXNzdW1pbmcgJEhfezB9JCBpcyBUUlVFLA0KDQokJCB6IFwgPSBcZnJhY3tcaGF0e3B9IFwgLSBwX3swfX17XHNxcnR7XGZyYWN7cF97MH0gXCAqIFwgKDEgXCAtIHBfezB9KX17bn19fSAkJA0KDQpUaGlzIG9ubHkgdXNlcyBzYW1wbGUgaW5mb3JtYXRpb24gKCRcaGF0e3B9JCBhbmQgJG4kKSBhbmQgdGhlIGh5cG90aGVzaXplZCBwYXJhbWV0ZXIgKCRwX3swfSQpDQoNCiMjIyAqKldoeSB6IGluc3RlYWQgb2YgdD8qKg0KDQpXaHkgd2UgdXNlZCBhIHotZGlzdHJpYnV0aW9uIGhlcmUsIGJ1dCBhIHQtZGlzdHJpYnV0aW9uIHByZXZpb3VzbHk/LiAqKlRoaXMgaXMgdGhlIHRlc3Qgc3RhdGlzdGljIGVxdWF0aW9uIGZvciB0aGUgdHdvIHNhbXBsZSBtZWFuIGNhc2UqKi4gVGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgc2FtcGxlLCAqKnMqKiwgaXMgY2FsY3VsYXRlZCBmcm9tIHRoZSBzYW1wbGUgbWVhbiwgJFxiYXJ7eH0kLiBUaGF0IG1lYW5zIHRoYXQgJFxiYXJ7eH0kIGlzIHVzZWQgaW4gdGhlIG51bWVyYXRvciB0byBlc3RpbWF0ZSB0aGUgcG9wdWxhdGlvbiBtZWFuLCBhbmQgaW4gdGhlIGRlbm9taW5hdG9yIHRvIGVzdGltYXRlIHRoZSBwb3B1bGF0aW9uIHN0YW5kYXJkIGRldmlhdGlvbi4gVGhpcyBkdWFsIHVzYWdlIGNhdXNlcyBhbiBpbmNyZWFzZSBpbiBvdXIgdW5jZXJ0YWludHkgYWJvdXQgdGhlIGVzdGltYXRlIG9mIHRoZSBwb3B1bGF0aW9uIHBhcmFtZXRlci4gU2luY2UgdC1kaXN0cmlidXRpb25zIGFyZSBlZmZlY3RpdmVseSBhIG5vcm1hbCBkaXN0cmlidXRpb24gd2l0aCBmYXR0ZXIgdGFpbHMsIHdlIGNhbiB1c2UgdGhlbSB0byBhY2NvdW50IGZvciB0aGlzIGV4dHJhIHVuY2VydGFpbnR5LiBJbiBlZmZlY3QsIHRoZSB0LWRpc3RyaWJ1dGlvbiBwcm92aWRlcyBleHRyYSBjYXV0aW9uIGFnYWluc3QgbWlzdGFrZW5seSByZWplY3RpbmcgdGhlIG51bGwgaHlwb3RoZXNpcy4gRm9yIHByb3BvcnRpb25zLCB3ZSBvbmx5IHVzZSAkXGhhdHtwfSQgaW4gdGhlIG51bWVyYXRvciwgdGh1cyBhdm9pZGluZyB0aGUgcHJvYmxlbSB3aXRoIHVuY2VydGFpbnR5LCBhbmQgYSB6LWRpc3RyaWJ1dGlvbiBpcyBmaW5lLg0KDQokJCB0IFwgPSBcZnJhY3soXGJhcnt4fV97Y2hpbGR9IFwgLSBcYmFye3h9X3thZHVsdH0pfXtcc3FydHtcZnJhY3thXjJfe2NoaWxkfX17bl97Y2hpbGR9fSBcICsgXGZyYWN7c14yX3thZHVsdH19e25fe2FkdWx0fX19fSAkJA0KDQotICAgJHMkIGlzIGNhbGN1bGF0ZWQgZnJvbSAkXGJhcnt4fSQsIHNvICRcYmFye3h9JCBpcyB1c2VkIHRvIGVzdGltYXRlIHRoZSBwb3B1bGF0aW9uIG1lYW4gYW5kIHRvIGVzdGltYXRlIHRoZSBwb3B1bGF0aW9uIHN0YW5kYXJkIGRldmlhdGlvbg0KDQotICAgVGhpcyBpbmNyZWFzZXMgdGhlIHVuY2VydGFpbnR5IGluIG91ciBlc3RpbWF0ZSBvZiB0aGUgcG9wdWxhdGlvbiBwYXJhbWV0ZXIuDQoNCi0gICB0LWRpc3RyaWJ1dGlvbiBoYXMgZmF0dGVyIHRhaWxzIHRoYW4gYSBub3JtYWwgZGlzdHJpYnV0aW9uDQoNCi0gICBUaGlzIGdpdmVzIGFuIGV4dHJhIGxldmVsIG9mIGNhdXRpb24NCg0KLSAgICRcaGF0e3B9JCBvbmx5IGFwcGVhcnMgaW4gdGhlIG51bWVyYXRvciwgc28gei1zY29yZXMgYXJlIGZpbmUNCg0KIyMjICoqU3RhY2sgb3ZlcmZsb3cgYWdlIGNhdGVnb3JpZXMqKg0KDQpMZXQncyBoeXBvdGhlc2l6ZSB0aGF0IGhhbGYgdGhlIHVzZXJzIGFyZSB1bmRlciB0aGlydHkuIFdlJ2xsIHNldCBhIHNpZ25pZmljYW5jZSBsZXZlbCBvZiAwLjAxLiBKdXN0IG92ZXIgaGFsZiB0aGUgdXNlcnMgYXJlIHVuZGVyIHRoaXJ0eS4NCg0KJEhfezB9JCA6IFRoZSBwcm9wb3J0aW9uIG9mIFNPIHVzZXJzIHVuZGVyIHRoaXJ0eSBpcyBlcXVhbCB0byAwLjUNCg0KJEhfe0F9JCA6IFRoZSBwcm9wb3J0aW9uIG9mIFNPIHVzZXJzIHVuZGVyIHRoaXJ0eSBpcyBub3QgZXF1YWwgdG8gMC41DQoNCmBgYHtyfQ0KYWxwaGEgPC0gMC4wMQ0KDQpzdGFja19vdmVyZmxvdyAlPiUNCiAgY291bnQoYWdlX2NhdCkNCmBgYA0KDQojIyMgKipWYXJpYWJsZXMgZm9yIHoqKg0KDQpMZXQncyBnZXQgdGhlIG51bWJlcnMgbmVlZGVkIGZvciB0aGUgei1zY29yZS4gJFxoYXR7cH0kIGlzIHRoZSBwcm9wb3J0aW9uIG9mIHJvd3MgaW4gdGhlIHNhbXBsZSB3aGVyZSBhZ2VfY2F0IGVxdWFscyB1bmRlciB0aGlydHkuICRwX3swfSQgaXMgMC41IGFjY29yZGluZyB0byB0aGUgbnVsbCBoeXBvdGhlc2lzLiBuIGlzIHRoZSBudW1iZXIgb2Ygcm93cyBpbiB0aGUgZGF0YXNldC4NCg0KYGBge3J9DQpwX2hhdCA8LSBzdGFja19vdmVyZmxvdyAlPiUNCiAgc3VtbWFyaXNlKHByb3BfdW5kZXJfMzAgPSBtZWFuKGFnZV9jYXQgPT0gIlVuZGVyIDMwIikpICU+JQ0KICBwdWxsKHByb3BfdW5kZXJfMzApDQoNCnBfaGF0DQpgYGANCg0KYGBge3J9DQpwXzAgPC0gMC41DQpuIDwtIG5yb3coc3RhY2tfb3ZlcmZsb3cpDQpuDQpgYGANCg0KIyMjICoqQ2FsY3VsYXRpbmcgdGhlIHotc2NvcmUqKg0KDQpDYWxjdWxhdGluZyB0aGUgei1zY29yZSBpcyBqdXN0IGFyaXRobWV0aWM7IHRoZSB2YWx1ZSBpcyB0aHJlZS1wb2ludC1maXZlLg0KDQokJCB6IFwgPSBcZnJhY3tcaGF0e3B9IFwgLSBwX3swfX17XHNxcnR7XGZyYWN7cF97MH0gXCAqIFwgKDEgXCAtIHBfezB9KX17bn19fSAkJA0KDQpgYGB7cn0NCm51bWVyYXRvciA8LSBwX2hhdCAtIHBfMA0KZGVub21pbmF0b3IgPC0gc3FydCgocF8wICogKDEgLSBwXzApKSAvIG4pDQp6X3Njb3JlIDwtIG51bWVyYXRvciAvIGRlbm9taW5hdG9yDQp6X3Njb3JlDQpgYGANCg0KIyMjICoqQ2FsY3VsYXRpbmcgdGhlIHAtdmFsdWUqKg0KDQpGb3IgbGVmdC10YWlsZWQgYWx0ZXJuYXRpdmUgaHlwb3RoZXNlcywgeW91IHRyYW5zZm9ybSB0aGUgei1zY29yZSBpbnRvIGEgcC12YWx1ZSB1c2luZyB0aGUgcG5vcm0gd2l0aCB0aGUgZGVmYXVsdCBvZiBsb3dlci1kb3QtdGFpbCBlcXVhbHMgVFJVRS4gRm9yIHJpZ2h0LXRhaWxlZCBhbHRlcm5hdGl2ZSBoeXBvdGhlc2VzIHlvdSBzZXQgbG93ZXItZG90LXRhaWwgdG8gRkFMU0UuIEZvciB0d28tdGFpbGVkIGFsdGVybmF0aXZlIGh5cG90aGVzZXMsIHlvdSBjaGVjayB3aGV0aGVyIHRoZSB0ZXN0IHN0YXRpc3RpYyBsaWVzIGluIGVpdGhlciB0YWlsLCBzbyB0aGUgcC12YWx1ZSBpcyB0aGUgc3VtIG9mIHRoZXNlIHR3byB2YWx1ZXMuIFNpbmNlIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uIFBERiBpcyBzeW1tZXRyaWMsIGhlcmUgdGhpcyBzaW1wbGlmaWVzIHRvIHR3aWNlIHRoZSBsZWZ0LXRhaWxlZCBwLXZhbHVlLiBIZXJlLCB0aGUgcC12YWx1ZSBpcyBsZXNzIHRoYW4gdGhlIHNpZ25pZmljYW5jZSBsZXZlbCBvZiBwb2ludC16ZXJvLW9uZSwgc28gd2UgcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgYW5kIGNvbmNsdWRlIHRoYXQgdGhlIHByb3BvcnRpb24gb2YgdXNlcnMgdW5kZXIgdGhpcnR5IGlzIG5vdCBlcXVhbCB0byBwb2ludC1maXZlLg0KDQpgYGB7cn0NCiMgTGVmdCB0YWlsZWQgKCJsZXNzIHRoYW4iKQ0KcF92YWx1ZV9sZXNzIDwtIHBub3JtKHpfc2NvcmUpDQpwX3ZhbHVlX2xlc3MNCmBgYA0KDQpgYGB7cn0NCiMgUmlnaHQgdGFpbGVkICgiZ3JlYXRlciB0aGFuIikNCnBfdmFsdWUgPC0gcG5vcm0oel9zY29yZSwgbG93ZXIudGFpbCA9IEZBTFNFKQ0KcF92YWx1ZQ0KYGBgDQoNCmBgYHtyfQ0KIyBUd28tdGFpbGVkICgibm90IGVxdWFsIikNCnBfdmFsdWVfMnQgPC0gcG5vcm0oel9zY29yZSkgKyBwbm9ybSh6X3Njb3JlLCBsb3dlci50YWlsID0gRkFMU0UpDQpwX3ZhbHVlXzJ0DQpgYGANCg0KYGBge3J9DQpwX3ZhbHVlX2EgPC0gMiAqIHBub3JtKHpfc2NvcmUpDQpwX3ZhbHVlX2ENCmBgYA0KDQpgYGB7cn0NCnBfdmFsdWUgPD0gYWxwaGENCmBgYA0KDQojIyBUd28gc2FtcGxlIHByb3BvcnRpb24gdGVzdHMNCg0KVGhlIHByZXZpb3VzIGV4YW1wbGUgKip0ZXN0ZWQgYSBzaW5nbGUgcHJvcG9ydGlvbiBhZ2FpbnN0IGEgc3BlY2lmaWMgdmFsdWUqKi4gQXMgd2l0aCBtZWFucywgd2UgY2FuIGFsc28gdGVzdCBkaWZmZXJlbmNlcyBiZXR3ZWVuIHByb3BvcnRpb25zIGluIHR3byBwb3B1bGF0aW9ucy4NCg0KIyMjICoqQ29tcGFyaW5nIHR3byBwcm9wb3J0aW9ucyoqDQoNClRoZSBTdGFjayBPdmVyZmxvdyBzdXJ2ZXkgY29udGFpbnMgYSBob2JieWlzdCB2YXJpYWJsZS4gVGhlIHZhbHVlICJZZXMiIG1lYW5zIHRoZSB1c2VyIGRlc2NyaWJlZCB0aGVtc2VsZiBhcyBhIGhvYmJ5aXN0OyAiTm8iIG1lYW5zIHRoZXkgZGVzY3JpYmVkIHRoZW1zZWxmIGFzIGEgcHJvZmVzc2lvbmFsLiAqKldlIGNhbiBoeXBvdGhlc2l6ZSB0aGF0IHRoZSBwcm9wb3J0aW9uIG9mIHVzZXJzIHdobyBhcmUgaG9iYnlpc3RzIGlzIHRoZSBzYW1lIGZvciB0aGUgdW5kZXIgdGhpcnR5IGFnZSBjYXRlZ29yeSBhcyB0aGUgYXQgbGVhc3QgdGhpcnR5IGNhdGVnb3J5KiouDQoNCk1vcmUgZm9ybWFsbHksICoqdGhlIG51bGwgaHlwb3RoZXNpcyBpcyB0aGF0IHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHBvcHVsYXRpb24gcGFyYW1ldGVycyBmb3IgZWFjaCBncm91cCBpcyB6ZXJvKiouIEkndmUgc2V0IGEgc2lnbmlmaWNhbmNlIGxldmVsIG9mIDAuMDUuDQoNCiRIX3swfSQgOiBUaGUgcHJvcG9ydGlvbiBvZiBTTyB1c2VycyB3aG8gYXJlIGhvYmJ5aXN0cyBpcyB0aGUgc2FtZSBmb3IgdGhvc2UgdW5kZXIgdGhpcnR5IGFzIHRob3NlIGF0IGxlYXN0IHRoaXJ0eQ0KDQokJA0KSF97MH06IHBfe1xnZXEgMzB9IFwgLSBwX3s8IDMwfSBcID0gMA0KJCQNCg0KJEhfe0F9JCA6IFRoZSBwcm9wb3J0aW9uIG9mIFNPIHVzZXJzIHdobyBhcmUgaG9iYnlpc3RzIGlzIGRpZmZlcmVudCBmb3IgdGhvc2UgdW5kZXIgdGhpcnR5IGFzIHRob3NlIGF0IGxlYXN0IHRoaXJ0eQ0KDQokJA0KSF97QX06IHBfe1xnZXEgMzB9IFwgLSBwX3s8MzB9IFxuZXEgMA0KJCQNCg0KIyMjICoqQ2FsY3VsYXRpbmcgdGhlIHotc2NvcmUqKg0KDQpMZXQncyBicmVhayBkb3duIHRoaXMgei1zY29yZSBlcXVhdGlvbi4gVGhlIHNhbXBsZSBzdGF0aXN0aWMgaXMgdGhlIGRpZmZlcmVuY2UgaW4gdGhlIHByb3BvcnRpb25zIGZvciBlYWNoIGNhdGVnb3J5ICQoXGhhdHtwfV97XGdlcTMwfSBcIC0gXGhhdHtwfV97PDMwfSkgXCAtIDAkLiBUaGF0J3MgdGhlIHR3byAkXGhhdHtwfSQgdmFsdWVzIG9uIHRoZSBudW1lcmF0b3IuIFdlIHN1YnRyYWN0IHRoZSBoeXBvdGhlc2l6ZWQgdmFsdWUgb2YgdGhlIHBvcHVsYXRpb24gcGFyYW1ldGVyLiBBc3N1bWluZyB0aGUgbnVsbCBoeXBvdGhlc2lzIGlzIHRydWUsICoqdGhhdCdzIGp1c3QgemVybyoqLCBzbyB0aGUgdGVybSBkaXNhcHBlYXJzLiBUaGUgZGVub21pbmF0b3IgaXMgdGhlIHN0YW5kYXJkIGVycm9yIG9mIHRoZSBzYW1wbGUgc3RhdGlzdGljICRTRShcaGF0e3B9X3tcZ2VxMzB9IFwgLSBcaGF0e3B9X3s8MzB9KSQuDQoNCkFnYWluIHdlIGNhbiBhdm9pZCBoYXZpbmcgdG8gZ2VuZXJhdGUgYSBib290c3RyYXAgZGlzdHJpYnV0aW9uLiBUaGUgZXF1YXRpb24gZm9yIHRoZSBzdGFuZGFyZCBlcnJvciBpcyBhIHNsaWdodGx5IG1vcmUgY29tcGxpY2F0ZWQgdmVyc2lvbiBvZiB0aGUgZXF1YXRpb24gZm9yIHRoZSBvbmUgc2FtcGxlIGNhc2UuIEluIHRoaXMgZXF1YXRpb24sIG5vdGUgdGhhdCBwLWhhdCBpcyB0aGUgc2FtcGxlIHByb3BvcnRpb24gZm9yIHRoZSB3aG9sZSBkYXRhc2V0LCBub3QgZm9yIGVhY2ggY2F0ZWdvcnkuIFRoaXMgd2hvbGUgZGF0YXNldCAkXGhhdHtwfSQgaXMga25vd24gYXMgYSAqKnBvb2xlZCBlc3RpbWF0ZSBvZiB0aGUgcG9wdWxhdGlvbiBwcm9wb3J0aW9uKiouIFdlIG5lZWQgb25lIG1vcmUgZXF1YXRpb24gdG8gZ2V0ICRcaGF0e3B9JC4gSXQncyBhIHdlaWdodGVkIG1lYW4gb2YgdGhlIHAtaGF0cyBmb3IgZWFjaCBjYXRlZ29yeS4gVGhpcyBsb29rcyBob3JyZW5kb3VzLCBidXQgaXQncyBqdXN0IGFyaXRobWV0aWMsIGFuZCBSIGlzIHByZXR0eSBnb29kIGF0IHRoYXQuIFRoZSBnb29kIG5ld3MgaXMgdGhhdCB3ZSBvbmx5IG5lZWQgZm91ciBudW1iZXJzIGZyb20gdGhlIHNhbXBsZSBkYXRhc2V0IHRvIGRvIHRoZXNlIGNhbGN1bGF0aW9ucy4NCg0KJCQNCnogPSBcZnJhY3soXGhhdHtwfV97XGdlcTMwfSBcIC0gXGhhdHtwfV97PDMwfSkgXCAtIDB9e1NFKFxoYXR7cH1fe1xnZXEzMH0gXCAtIFxoYXR7cH1fezwzMH0pfQ0KJCQNCg0KJCQNClNFKFxoYXR7cH1fe1xnZXEwfSBcIC0gXGhhdHtwfV97PDB9KSBcID0gXHNxcnR7XGZyYWN7XGhhdHtwfSBcdGltZXMgXCAoMSBcIC0gXGhhdHtwfSl9e25fe1xnZXEzMH19IFwgKyBcZnJhY3tcaGF0e3B9IFx0aW1lcyBcICgxIFwgLSBcaGF0e3B9KX17bl97PDMwfX19IA0KJCQNCg0KJFxoYXR7cH0kIGlzIGEgcG9vbGVkIGVzdGltYXRlIGZvciAkcCQgKGNvbW1vbiB1bmtub3duIHByb3BvcnRpb24gb2Ygc3VjY2Vzc2VzKQ0KDQokJA0KXGhhdHtwfSBcID0gXGZyYWN7bl97XGdlcTMwfSBcdGltZXMgXGhhdHtwfV97XGdlcTMwfSBcICsgbl97PDMwfSBcdGltZXMgXGhhdHtwfV97PDMwfX17bl97XGdlcTMwfSBcICsgbl97PDMwfX0NCiQkDQoNCldlIG9ubHkgbmVlZCB0byBjYWxjdWxhdGUgNCBudW1iZXJzOiAkXGhhdHtwfV97XGdlcTMwfSwgXCBcaGF0e3B9X3s8MzB9LCBcIG5fe1xnZXEzMH0sIFwgbl97PDMwfSQNCg0KIyMjICoqR2V0dGluZyB0aGUgbnVtYmVycyBmb3IgdGhlIHotc2NvcmUqKg0KDQpUbyBjYWxjdWxhdGUgdGhlc2UgZm91ciBudW1iZXJzIHlvdSBgZ3JvdXBfYnkoKWAgdGhlIGNhdGVnb3JpZXMsIGFuZCBzdW1tYXJpemUgdG8gY2FsY3VsYXRlIHRoZSBzYW1wbGUgcHJvcG9ydGlvbiBhbmQgcm93IGNvdW50cy4gQWZ0ZXIgdGhhdCwgeW91IGNhbiBkbyB0aGUgYXJpdGhtZXRpYyB0byBnZXQgdGhlIHRlc3Qgc3RhdGlzdGljIC0gdGhlIHotc2NvcmUgaXMgbWludXMgZm91ci1wb2ludC10d28gLSBhbmQgY2FsbCBwbm9ybSB0byBnZXQgdGhlIHAtdmFsdWUuIEknbSBub3QgZ29pbmcgdG8gcnVuIHRocm91Z2ggdGhlc2Ugc3RlcHMgYmVjYXVzZSBpdCdzIGV4YWN0bHkgdGhlIHNhbWUgYXMgeW91J3ZlIHNlZW4gYWxyZWFkeS4gSW5zdGVhZCwgSSdsbCBzaG93IHlvdSBhbiBlYXNpZXIgd2F5Lg0KDQpgYGB7cn0NCnN0YWNrX292ZXJmbG93ICU+JQ0KICBncm91cF9ieShhZ2VfY2F0KSAlPiUNCiAgc3VtbWFyaXNlKHBfaGF0ID0gbWVhbihob2JieWlzdCA9PSAiWWVzIiksIG4gPSBuKCkpDQpgYGANCg0KIyMjICoqUHJvcG9ydGlvbiB0ZXN0cyB1c2luZyBgcHJvcF90ZXN0KClgKioNCg0KTmF0dXJhbGx5LCAqKlIgaGFzIGF0IGxlYXN0IHR3byBmdW5jdGlvbnMgZm9yIHBlcmZvcm1pbmcgdGhpcyB0eXBlIG9mIGh5cG90aGVzaXMgdGVzdCoqLCBrbm93biBhcyBhICoqcHJvcG9ydGlvbiB0ZXN0KiouIEJhc2UtUiBoYXMgYSBmdW5jdGlvbiBuYW1lZCBgcHJvcC50ZXN0KClgLCB0aG91Z2ggdW5mb3J0dW5hdGVseSwgaXRzIGludGVyZmFjZSBpcyBzb21ld2hhdCBwZWN1bGlhci4gKipUbyBtYWtlIHlvdXIgbGlmZSBlYXNpZXIgaXQncyBiZXN0IHRvIHVzZSBgcHJvcF90ZXN0KClgIGZyb20gaW5mZXIqKi4gVGhpcyB0YWtlcyBhIGZvcm11bGEsICoqd2l0aCB5b3VyIG51bWVyaWMgdmFyaWFibGUgb24gdGhlIGxlZnQgYW5kIHRoZSBjYXRlZ29yaWVzIG9uIHRoZSByaWdodCoqLiBUaGUgb3JkZXIgYXJndW1lbnQgc3BlY2lmaWVzIHdoaWNoICRcaGF0e3B9JCBzaG91bGQgYmUgc3VidHJhY3RlZCBmcm9tIHRoZSBvdGhlci4gSGVyZSwgaXQgaXMgc3BlY2lmaWVkIHNvIHRoYXQgeW91IHN0YXJ0IHdpdGggdGhlICJhdCBsZWFzdCB0aGlydHkiICRcaGF0e3B9X3tcZ2VxMzB9JCAsIHRoZW4gc3VidHJhY3QgdGhlICJ1bmRlciB0aGlydHkiICRcaGF0e3B9X3s8MzB9JA0KDQpUaGUgYHN1Y2Nlc3NgIGFyZ3VtZW50IHNwZWNpZmllcyAqKndoaWNoIG9mIHRoZSB0d28gcmVzcG9uc2UgbGV2ZWxzIHRvIGdldCB0aGUgcHJvcG9ydGlvbiBvZioqLiBgYWx0ZXJuYXRpdmVgIHRha2VzIHRoZSBzYW1lIHZhbHVlcyBhcyB0LXRlc3QuIEhlcmUsICoqd2UgaGF2ZSBhIHR3by1zaWRlZCBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzKiouIFRoZSBgY29ycmVjdGAgYXJndW1lbnQgKipzcGVjaWZpZXMgd2hldGhlciBvciBub3QgdG8gYXBwbHkgWWF0ZXMnIGNvbnRpbnVpdHkgY29ycmVjdGlvbioqLiBUaGlzIGlzIGEgZnVkZ2UgZmFjdG9yICoqbmVlZGVkIGZvciB0ZWNobmljYWwgcmVhc29ucyB3aGVuIHRoZSBzYW1wbGUgc2l6ZSBpcyB2ZXJ5IHNtYWxsKiouIFNpbmNlICoqZWFjaCBncm91cCBoYXMgb3ZlciBvbmUgdGhvdXNhbmQgb2JzZXJ2YXRpb25zLCB3ZSBkb24ndCBuZWVkIGl0KiouIFRoZSBwLXZhbHVlIGlzIGluIHRoZSB0aGlyZCBjb2x1bW4gb2YgdGhlIHJlc3VsdGluZyB0aWJibGUuIEl0J3Mgc21hbGxlciB0aGFuIHRoZSBzaWduaWZpY2FuY2UgbGV2ZWwgd2Ugc3BlY2lmaWVkIGVhcmxpZXIsIHNvICoqd2UgY2FuIGNvbmNsdWRlIHRoYXQgdGhlcmUgaXMgYSBkaWZmZXJlbmNlIGluIHRoZSBwcm9wb3J0aW9uIG9mIFN0YWNrIE92ZXJmbG93IGhvYmJ5aXN0cyBiZXR3ZWVuIHRoZSB1bmRlciBhbmQgb3ZlciB0aGlydHkgZ3JvdXBzKiouDQoNCmBgYHtyfQ0KbGlicmFyeShpbmZlcikNCnN0YWNrX292ZXJmbG93ICU+JQ0KICBwcm9wX3Rlc3QoaG9iYnlpc3QgfiBhZ2VfY2F0LCBvcmRlciA9IGMoIkF0IGxlYXN0IDMwIiwgIlVuZGVyIDMwIiksIHN1Y2Nlc3MgPSAiWWVzIiwgDQogICAgICAgICAgICBhbHRlcm5hdGl2ZSA9ICJ0d28tc2lkZWQiLCBjb3JyZWN0ID0gRkFMU0UpDQpgYGANCg0KIyMjICoqQ2hpLXNxdWFyZSB0ZXN0IG9mIGluZGVwZW5kZW5jZSoqDQoNCkp1c3QgYXMgQU5PVkEgZXh0ZW5kcyB0LXRlc3RzIHRvIG1vcmUgdGhhbiB0d28gZ3JvdXBzLCBjaGktc3F1YXJlIHRlc3RzIG9mIGluZGVwZW5kZW5jZSBleHRlbmQgcHJvcG9ydGlvbiB0ZXN0cyB0byBtb3JlIHRoYW4gdHdvIGdyb3Vwcy4NCg0KIyMjICoqUmV2aXNpdGluZyB0aGUgcHJvcG9ydGlvbiB0ZXN0KioNCg0KSGVyZSdzIHRoZSBwcm9wb3J0aW9uIHRlc3QgZnJvbSBsYXN0IHRpbWUuIEluIHRoZSBmaXJzdCBjb2x1bW4sIHRoZSB0ZXN0IHN0YXRpc3RpYyBpcyB0aGUgc3F1YXJlIG9mIHRoZSB6LXNjb3JlLiBNaW51cyBmb3VyLXBvaW50LXR3by10d28gc3F1YXJlZCBpcyBzZXZlbnRlZW4tcG9pbnQtZWlnaHQuIEluIHRoZSBzZWNvbmQgY29sdW1uLCBjaGlzcV9kZiBtZWFucyB0aGUgZGVncmVlcyBvZiBmcmVlZG9tIG9mIGEgY2hpLXNxdWFyZSB0ZXN0LiBJdHMgdmFsdWUgaXMgb25lLg0KDQpgYGB7cn0NCmxpYnJhcnkoaW5mZXIpDQpzdGFja19vdmVyZmxvdyAlPiUNCiAgcHJvcF90ZXN0KGhvYmJ5aXN0IH4gYWdlX2NhdCwgb3JkZXIgPSBjKCJBdCBsZWFzdCAzMCIsICJVbmRlciAzMCIpLCBhbHRlcm5hdGl2ZSA9ICJ0d28tc2lkZWQiLCBjb3JyZWN0ID0gRkFMU0UpDQpgYGANCg0KIyMjICoqSW5kZXBlbmRlbmNlIG9mIHZhcmlhYmxlcyoqDQoNClRoYXQgcHJvcG9ydGlvbiB0ZXN0IGhhZCBhIHBvc2l0aXZlIHJlc3VsdC4gVGhlcmUgd2FzIGV2aWRlbmNlIHRoYXQgdGhlIGhvYmJ5aXN0IGFuZCBhZ2UgY2F0ZWdvcnkgdmFyaWFibGVzIGhhZCBhbiBhc3NvY2lhdGlvbi4gSWYgdGhhdCB3YXNuJ3QgdGhlIGNhc2UsIGFuZCB0aGUgcHJvcG9ydGlvbiBvZiBob2JieWlzdHMgd2FzIHRoZSBzYW1lIGZvciBlYWNoIGFnZSBjYXRlZ29yeSwgdGhlIHZhcmlhYmxlcyB3b3VsZCBiZSBjb25zaWRlcmVkIHN0YXRpc3RpY2FsbHkgaW5kZXBlbmRlbnQuIE1vcmUgZm9ybWFsbHksICoqc3RhdGlzdGljYWwgaW5kZXBlbmRlbmNlIG9mIHR3byBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgaXMgd2hlbiB0aGUgcHJvcG9ydGlvbiBvZiBzdWNjZXNzZXMgaW4gdGhlIHJlc3BvbnNlIHZhcmlhYmxlIGlzIHRoZSBzYW1lIGFjcm9zcyBhbGwgY2F0ZWdvcmllcyBvZiB0aGUgZXhwbGFuYXRvcnkgdmFyaWFibGUqKi4NCg0KIyMjICoqSm9iIHNhdGlzZmFjdGlvbiBhbmQgYWdlIGNhdGVnb3J5KioNCg0KUmVjYWxsIHRoYXQgdGhlIFN0YWNrIE92ZXJmbG93IHNhbXBsZSBoYXMgYW4gYWdlIGNhdGVnb3J5IHZhcmlhYmxlIHdpdGggdHdvIGNhdGVnb3JpZXMgYW5kIGEgam9iIHNhdGlzZmFjdGlvbiB2YXJpYWJsZSB3aXRoIGZpdmUgY2F0ZWdvcmllcy4NCg0KYGBge3J9DQpzdGFja19vdmVyZmxvdyAlPiUNCiAgY291bnQoYWdlX2NhdCkNCmBgYA0KDQpgYGB7cn0NCnN0YWNrX292ZXJmbG93ICU+JQ0KICBjb3VudChqb2Jfc2F0KQ0KYGBgDQoNCiMjIyAqKkRlY2xhcmluZyB0aGUgaHlwb3RoZXNpcyoqDQoNCldlIGNhbiBkZWNsYXJlIGh5cG90aGVzZXMgdG8gdGVzdCBmb3IgaW5kZXBlbmRlbmNlIG9mIHRoZXNlIHZhcmlhYmxlcy4gSGVyZSwgKiphZ2UgY2F0ZWdvcnkgaXMgdGhlIHJlc3BvbnNlIHZhcmlhYmxlKiosIGFuZCAqKmpvYiBzYXRpc2ZhY3Rpb24gaXMgdGhlIGV4cGxhbmF0b3J5IHZhcmlhYmxlKiouICoqVGhlIG51bGwgaHlwb3RoZXNpcyBpcyB0aGF0IGluZGVwZW5kZW5jZSBvY2N1cnMuKiogSSd2ZSBzZXQgYSAqKnNpZ25pZmljYW5jZSBsZXZlbCBvZiAwLjEqKi4gVGhlIHRlc3Qgc3RhdGlzdGljIGlzIGRlbm90ZWQgY2hpLXNxdWFyZS4gKipJdCBxdWFudGlmaWVzIGhvdyBmYXIgYXdheSB0aGUgb2JzZXJ2ZWQgcmVzdWx0cyBhcmUgZnJvbSB0aGUgdmFsdWVzIHlvdSdkIGV4cGVjdCBpZiBpbmRlcGVuZGVuY2Ugd2FzIHRydWUqKi4NCg0KJEhfezB9JCA6IEFnZSBjYXRlZ29yaWVzIGFyZSBpbmRlcGVuZGVudCBvZiBqb2Igc2F0aXNmYWN0aW9uIGxldmVscw0KDQokSF97QX0kIDogQWdlIGNhdGVnb3JpZXMgYXJlIG5vdCBpbmRlcGVuZGVudCBvZiBqb2Igc2F0aXNmYWN0aW9uIGxldmVscw0KDQpUZXN0IHN0YXRpc3RpYyBkZW5vdGVkICRcY2hpXjIkDQoNCkFzc3VtaW5nIHRoZSBpbmRlcGVuZGVuY2UsIGhvdyBmYXIgYXdheSBhcmUgdGhlIG9ic2VydmVkIHJlc3VsdHMgZnJvbSB0aGUgZXhwZWN0ZWQgdmFsdWVzPw0KDQpgYGB7cn0NCmFscGhhID0gMC4xDQpgYGANCg0KIyMjICoqRXhwbG9yYXRvcnkgdmlzdWFsaXphdGlvbjogUHJvcG9ydGlvbmFsIHN0YWNrZWQgYmFyIHBsb3QqKg0KDQpMZXQncyBleHBsb3JlIHRoZSBkYXRhIHVzaW5nIGEgcHJvcG9ydGlvbmFsIHN0YWNrZWQgYmFyIHBsb3QuIGBmaWxsYCBtZWFucyB0d28gZGlmZmVyZW50IHRoaW5ncyBoZXJlLiBJbiB0aGUgYWVzdGhldGljcywgYGZpbGxgIHJlZmVycyB0byB0aGUgZmlsbCBjb2xvciBvZiB0aGUgYmFycy4gSW4gYGdlb21fYmFyYCdzIHBvc2l0aW9uIGFyZ3VtZW50LCBgImZpbGwiYCBtYWtlcyBlYWNoIGJhciB0aGUgc2FtZSBoZWlnaHQsIHNvIHlvdSBjYW4gY29tcGFyZSBwcm9wb3J0aW9ucy4gSWYgdGhlIGFnZSBjYXRlZ29yeSB3YXMgaW5kZXBlbmRlbnQgb2YgdGhlIGpvYiBzYXRpc2ZhY3Rpb24sIHRoZSBzcGxpdCBiZXR3ZWVuIHRoZSBhZ2UgY2F0ZWdvcmllcyB3b3VsZCBiZSBhdCB0aGUgc2FtZSBoZWlnaHQgaW4gZWFjaCBvZiB0aGUgZml2ZSBiYXJzLiBUaGVyZSdzIHNvbWUgdmFyaWF0aW9uIGhlcmUsIGJ1dCB3ZSdsbCBuZWVkIHRoZSBoeXBvdGhlc2lzIHRlc3QgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgaXQncyBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UuDQoNCmBgYHtyfQ0KZ2dwbG90KHN0YWNrX292ZXJmbG93LCBhZXMoam9iX3NhdCwgZmlsbCA9IGFnZV9jYXQpKSArIA0KICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJmaWxsIikgKw0KICB5bGFiKCJwcm9wb3J0aW9uIikNCmBgYA0KDQojIyMgKipDaGktc3F1YXJlIGluZGVwZW5kZW5jZSB0ZXN0IHVzaW5nIGBjaGlzcV90ZXN0KClgKioNCg0KVGhlIGh5cG90aGVzaXMgdGVzdCBmb3IgaW5kZXBlbmRlbmNlIGlzIGNhbGxlZCBhICoqY2hpLXNxdWFyZSBpbmRlcGVuZGVuY2UgdGVzdC4qKiBUaGVyZSdzIGEgYmFzZS1SIGZ1bmN0aW9uIGZvciBpdCBjYWxsZWQgYGNoaXNxLnRlc3QoKWAsIGJ1dCBsaWtlIGBwcm9wLnRlc3QoKWAsIGl0J3MgZmlkZGx5IHRvIHVzZS4gVGhlIGVhc2llc3Qgb3B0aW9uIGlzIHRvIHVzZSBpbmZlcidzIGBjaGlzcV90ZXN0KClgLiBQaXBlIGZyb20gdGhlIHNhbXBsZSBkYXRhc2V0LCAqKnBhc3NpbmcgYSBmb3JtdWxhIHdpdGggdGhlIHJlc3BvbnNlIHZhcmlhYmxlIG9uIHRoZSBsZWZ0IGFuZCB0aGUgZXhwbGFuYXRvcnkgdmFyaWFibGUgb24gdGhlIHJpZ2h0KiouIFRoZSBwLXZhbHVlIGlzICoqMC4yMyoqLCB3aGljaCBpcyAqKmFib3ZlIHRoZSBzaWduaWZpY2FuY2UgbGV2ZWwqKiB3ZSBzZXQsIHNvICoqd2UgY29uY2x1ZGUgdGhhdCBhZ2UgY2F0ZWdvcmllcyBhcmUgaW5kZXBlbmRlbnQgb2Ygam9iIHNhdGlzZmFjdGlvbioqLiBUaGUgY2hpLXNxdWFyZSBkaXN0cmlidXRpb24sIHdob3NlIENERiBpcyB1c2VkIHRvIGNhbGN1bGF0ZSB0aGUgcC12YWx1ZSBmcm9tIHRoZSB0ZXN0IHN0YXRpc3RpYywgaGFzIGEgZGVncmVlcyBvZiBmcmVlZG9tIGFyZ3VtZW50LCBqdXN0IGxpa2UgdGhlIHQtZGlzdHJpYnV0aW9uLiBUaGUgcmVzdWx0cyBzaG93IHRoYXQgdGhlcmUgYXJlIGZvdXIgZGVncmVlcyBvZiBmcmVlZG9tLiBUaGlzIGlzIHRoZSBudW1iZXIgb2YgcmVzcG9uc2UgY2F0ZWdvcmllcyBtaW51cyBvbmUsIHRpbWVzIHRoZSBudW1iZXIgb2YgZXhwbGFuYXRvcnkgY2F0ZWdvcmllcyBtaW51cyBvbmUuIFR3byBtaW51cyBvbmUgdGltZXMgZml2ZSBtaW51cyBvbmUgaXMgZm91ci4NCg0KYGBge3J9DQpzdGFja19vdmVyZmxvdyAlPiUNCiAgY2hpc3FfdGVzdChhZ2VfY2F0IH4gam9iX3NhdCkNCmBgYA0KDQojIyMjICoqRGVncmVlcyBvZiBmcmVlZG9tKioNCg0KJCQNCihOby4gXCBvZiBcIHJlc3BvbnNlIFwgY2F0ZWdvcmllcyBcIC0gMSkgXHRpbWVzIChOby4gXCBvZiBcIGV4cGxhbmF0b3J5IFwgY2F0ZWdvcmllcyBcIC0gMSkNClxcKDIgXCAtIDEpIFx0aW1lcyAoNSBcIC0gMSkgXCA9IDQNCiQkDQoNCiMjIyAqKlN3YXBwaW5nIHRoZSB2YXJpYWJsZXMqKg0KDQpJZiB3ZSBzd2FwIHRoZSB2YXJpYWJsZXMsIHNvIGFnZSBjYXRlZ29yeSBpcyB0aGUgcmVzcG9uc2UsIGFuZCBqb2Igc2F0aXNmYWN0aW9uIGlzIHRoZSBleHBsYW5hdG9yeSB2YXJpYWJsZSwgdGhlIHZpc3VhbCBpbnNwZWN0aW9uIHRlY2huaXF1ZSBpcyB0aGUgc2FtZTogc2VlIGlmIHRoZSBzcGxpdHMgZm9yIGVhY2ggYmFyIGFyZSBpbiBzaW1pbGFyIHBsYWNlcy4NCg0KYGBge3J9DQpnZ3Bsb3Qoc3RhY2tfb3ZlcmZsb3csIGFlcyhhZ2VfY2F0LCBmaWxsID0gam9iX3NhdCkpICsgDQogIGdlb21fYmFyKHBvc2l0aW9uID0gImZpbGwiKSArIA0KICB5bGFiKCJwcm9wb3J0aW9uIikNCmBgYA0KDQojIyMgKipDaGktc3F1YXJlIGJvdGggd2F5cyoqDQoNCklmIHdlIHJ1biB0aGUgY2hpLXNxdWFyZSB0ZXN0IHdpdGggdGhlIHZhcmlhYmxlcyBzd2FwcGVkLCB0aGVuIHRoZSByZXN1bHRzIGFyZSBpZGVudGljYWwuICoqV2Ugc2hvdWxkIGFzayBxdWVzdGlvbnMgbGlrZSAiYXJlIHZhcmlhYmxlcyBYIGFuZCBZIGluZGVwZW5kZW50PyIqKiwgbm90ICJpcyB2YXJpYWJsZSBYIGluZGVwZW5kZW50IGZyb20gdmFyaWFibGUgWT8iLCBzaW5jZSB0aGUgb3JkZXIgZG9lc24ndCBtYXR0ZXIuDQoNCmBgYHtyfQ0Kc3RhY2tfb3ZlcmZsb3cgJT4lDQogIGNoaXNxX3Rlc3QoYWdlX2NhdCB+IGpvYl9zYXQpDQpgYGANCg0KYGBge3J9DQpzdGFja19vdmVyZmxvdyAlPiUNCiAgY2hpc3FfdGVzdChqb2Jfc2F0IH4gYWdlX2NhdCkNCmBgYA0KDQojIyMgKipXaGF0IGFib3V0IGRpcmVjdGlvbnMgYW5kIHRhaWxzPyoqDQoNCldlIGRpZG4ndCB3b3JyeSBhYm91dCB0YWlscyBpbiB0aGlzIHRlc3QsIGFuZCBpbiBmYWN0IGBjaGlzcV90ZXN0KClgICoqZG9lc24ndCBoYXZlIGFuIGFsdGVybmF0aXZlIGFyZ3VtZW50KiouIFRoaXMgaXMgKipiZWNhdXNlIHRoZSB0ZXN0IHN0YXRpc3RpYyBpcyBiYXNlZCBvbiB0aGUgc3F1YXJlIG9mIG9ic2VydmVkIGFuZCBleHBlY3RlZCBjb3VudHMqKiwgYW5kIHNxdWFyZSBudW1iZXJzIGFyZSBub24tbmVnYXRpdmUuICoqVGhhdCBtZWFucyB0aGF0IGNoaS1zcXVhcmUgdGVzdHMgdGVuZCB0byBiZSByaWdodC10YWlsZWQgdGVzdHMqKi4NCg0KXjFeIExlZnQtdGFpbGVkIGNoaS1zcXVhcmUgdGVzdHMgYXJlIHVzZWQgaW4gc3RhdGlzdGljYWwgZm9yZW5zaWNzIHRvIGRldGVjdCBpcyBhIGZpdCBpcyBzdXNwaWNpb3VzbHkgZ29vZCBiZWNhdXNlIHRoZSBkYXRhIHdhcyBmYWJyaWNhdGVkLiBDaGktc3F1YXJlIHRlc3RzIG9mIHZhcmlhbmNlIGNhbiBiZSB0d28tdGFpbGVkLiBUaGVzZSBhcmUgbmljaGUgdXNlcyB0aG91Z2guDQoNCmBgYHtyfQ0KYXJncyhjaGlzcV90ZXN0KQ0KYGBgDQoNCiMjIyAqKkNoaS1zcXVhcmUgZ29vZG5lc3Mgb2YgZml0bmVzcyB0ZXN0KioNCg0KTGFzdCB0aW1lIHlvdSB1c2VkIGEgY2hpLXNxdWFyZSB0ZXN0IHRvIGNvbXBhcmUgcHJvcG9ydGlvbnMgaW4gdHdvIGNhdGVnb3JpY2FsIHZhcmlhYmxlcy4gVGhpcyB0aW1lLCB3ZSdsbCB1c2UgYW5vdGhlciB2YXJpYW50IG9mIHRoZSBjaGktc3F1YXJlIHRlc3QgdG8gY29tcGFyZSBhIHNpbmdsZSBjYXRlZ29yaWNhbCB2YXJpYWJsZSB0byBhIGh5cG90aGVzaXplZCBkaXN0cmlidXRpb24uDQoNCiMjIyAqKlB1cnBsZSBsaW5rcyoqDQoNClRoZSBTdGFjayBPdmVyZmxvdyBzdXJ2ZXkgY29udGFpbnMgYSBmdW4gcXVlc3Rpb24gYWJvdXQgaG93IHRoZSB1c2VyIGZlZWxzIHdoZW4gdGhleSBkaXNjb3ZlciB0aGF0IHRoZXkgYWxyZWFkeSB2aXNpdGVkIHRoZSB0b3AgcmVzb3VyY2Ugd2hlbiB0cnlpbmcgdG8gc29sdmUgYSBjb2RpbmcgcHJvYmxlbS4gVGhlcmUgYXJlIGZvdXIgcG9zc2libGUgYW5zd2Vycywgc3RvcmVkIGluIHRoZSBwdXJwbGVfbGluayB2YXJpYWJsZS4NCg0KYGBge3J9DQpwdXJwbGVfbGlua19jb3VudHMgPC0gc3RhY2tfb3ZlcmZsb3cgJT4lDQogIGNvdW50KHB1cnBsZV9saW5rKSAlPiUNCiAgYXJyYW5nZShkZXNjKG4pKQ0KDQpwdXJwbGVfbGlua19jb3VudHMNCmBgYA0KDQojIyMgKipEZWNsYXJpbmcgdGhlIGh5cG90aGVzaXMqKg0KDQpMZXQncyBoeXBvdGhlc2l6ZSB0aGF0IGhhbGYgdGhlIHVzZXJzIGluIHRoZSBwb3B1bGF0aW9uIHdvdWxkIHJlc3BvbmQgIkhlbGxvIG9sZCBmcmllbmQiLCBhbmQgdGhlIG90aGVyIHRocmVlIHJlc3BvbnNlcyB3b3VsZCBnZXQgb25lIHNpeHRoIGVhY2guIFRoZSBgdHJpYmJsZWAgZnVuY3Rpb24gcHJvdmlkZXMgYSBjb252ZW5pZW50IHdheSBvZiBtYW51YWxseSBlbnRlcmluZyB2YWx1ZXMgZm9yIGEgZGF0YSBmcmFtZSwgYW5kIHJldHVybnMgYSBzdGFuZGFyZCB0aWJibGUuIFdlIGNhbiBzcGVjaWZ5IHRoZSBoeXBvdGhlc2VzIGFzIHdoZXRoZXIgb3Igbm90IHRoZSBzYW1wbGUgbWF0Y2hlcyB0aGlzIGh5cG90aGVzaXplZCBkaXN0cmlidXRpb24uIFRoZSB0ZXN0IHN0YXRpc3RpYyBtZWFzdXJlcyBob3cgZmFyIHRoZSBkaXN0cmlidXRpb24gb2YgcHJvcG9ydGlvbnMgb2JzZXJ2ZWQgaW4gdGhlIHNhbXBsZSBpcyBmcm9tIHRoZSBoeXBvdGhlc2l6ZWQgZGlzdHJpYnV0aW9uIG9mIHByb3BvcnRpb25zLiBJJ2xsIHNldCBhIHNpZ25pZmljYW5jZSBsZXZlbCBvZiBwb2ludC16ZXJvLW9uZS4NCg0KXjFeIHRyaWJibGUgaXMgc2hvcnQgZm9yICJyb3ctd2lzZSB0aWJibGUiOyBub3QgdG8gYmUgY29uZnVzZWQgd2l0aCB0aGUgYWxpZW4gc3BlY2llcyBmcm9tIFN0YXIgVHJlaw0KDQpgYGB7cn0NCmh5cG90aGVzaXplZCA8LSB0cmliYmxlKH4gcHVycGxlX2xpbmssIH4gcHJvcCwNCiAgICAgICAgICAgICAgICAgICAgICAgICJIZWxsbywgb2xkIGZyaWVuZCIsIDEvMiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJBbXVzZWQiLCAxLzYsDQogICAgICAgICAgICAgICAgICAgICAgICAiSW5kaWZmZXJlbnQiLCAxLzYsDQogICAgICAgICAgICAgICAgICAgICAgICAiSW5kaWZmZXJlbnQiLCAxLzYsDQogICAgICAgICAgICAgICAgICAgICAgICAiQW5ub3llZCIsIDEvNikNCmh5cG90aGVzaXplZA0KYGBgDQoNCiMjIyAqKkh5cG90aGVzaXplZCBjb3VudHMgYnkgY2F0ZWdvcnkqKg0KDQpUbyB2aXN1YWxpemUgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgcHVycGxlIGxpbmtzLCBpdCB3aWxsIGhlbHAgdG8gaGF2ZSB0aGUgaHlwb3RoZXNpemVkIGNvdW50cy4gVGhlc2UgYXJlIHRoZSBoeXBvdGhlc2l6ZWQgcHJvcG9ydGlvbnMgdGltZXMgdGhlIHRvdGFsIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgaW4gdGhlIHNhbXBsZS4NCg0KYGBge3J9DQpuX3RvdGFsIDwtIG5yb3coc3RhY2tfb3ZlcmZsb3cpDQpoeXBvdGhlc2l6ZWQgPC0gdHJpYmJsZSh+IHB1cnBsZV9saW5rLCB+IHByb3AsDQogICAgICAgICAgICAgICAgICAgICAgICAiSGVsbG8sIG9sZCBmcmllbmQiLCAxLzIsDQogICAgICAgICAgICAgICAgICAgICAgICAiQW11c2VkIiwgMS82LA0KICAgICAgICAgICAgICAgICAgICAgICAgIkluZGlmZmVyZW50IiwgMS82LA0KICAgICAgICAgICAgICAgICAgICAgICAgIkluZGlmZmVyZW50IiwgMS82LA0KICAgICAgICAgICAgICAgICAgICAgICAgIkFubm95ZWQiLCAxLzYpICU+JQ0KICBtdXRhdGUobiA9IHByb3AgKiBuX3RvdGFsKQ0KDQpoeXBvdGhlc2l6ZWQNCmBgYA0KDQojIyMgKipWaXN1YWxpemluZyBjb3VudHMqKg0KDQpUaGUgbmF0dXJhbCB3YXkgdG8gdmlzdWFsaXplIHRoZSBjYXRlZ29yaWVzIGlzIHdpdGggYSBiYXIgcGxvdC4gV2UncmUgdXNpbmcgYGdlb21fY29sKClgIGhlcmUgc2luY2Ugd2UgYWxyZWFkeSBjYWxjdWxhdGVkIHRoZSBjb3VudHMuIFRoZSBwdXJwbGUgcG9pbnRzIHNob3cgdGhlIGh5cG90aGVzaXplZCBjb3VudHMsIHNvIHlvdSBjYW4gY29tcGFyZSB0aGUgc2FtcGxlIGRpc3RyaWJ1dGlvbiB0byB0aGUgaHlwb3RoZXNpemVkIGRpc3RyaWJ1dGlvbi4gVHdvIG9mIHRoZSBiYXJzIGFyZSBjbG9zZSB0byB0aGUgdmFsdWVzIHdlIGh5cG90aGVzaXplZCBhbmQgdHdvIGFyZSBzbGlnaHRseSBkaWZmZXJlbnQuIFdlJ2xsIG5lZWQgdG8gcnVuIHRoZSBoeXBvdGhlc2lzIHRlc3QgdG8gc2VlIGlmIHRoZSBkaWZmZXJlbmNlcyBhcmUgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudC4NCg0KYGBge3J9DQpnZ3Bsb3QocHVycGxlX2xpbmtfY291bnRzLCBhZXMocHVycGxlX2xpbmssIG4pKSArDQogIGdlb21fY29sKCkgKyANCiAgZ2VvbV9wb2ludChkYXRhID0gaHlwb3RoZXNpemVkLCBjb2xvciA9ICJyZWQiKQ0KYGBgDQoNCiMjIyAqKkNoaS1zcXVhcmUgZ29vZG5lc3Mgb2YgZml0IHRlc3QgdXNpbmcgYGNoaXNxX3Rlc3QoKWAqKg0KDQpUaGUgb25lIHNhbXBsZSBjaGktc3F1YXJlIHRlc3QgaXMgY2FsbGVkIGEgZ29vZG5lc3Mgb2YgZml0IHRlc3QuIFRvIHJ1biBpdCwgd2UgbmVlZCB0aGUgaHlwb3RoZXNpemVkIHByb3BvcnRpb25zIGluIHZlY3RvciBmb3JtIHJhdGhlciB0aGFuIGluIGEgdGliYmxlLiBBZ2FpbiB3ZSB1c2UgYGNoaXNxX3Rlc3QoKWAgZnJvbSBgaW5mZXJgLiBIb3dldmVyLCB0aGlzIHRpbWUgdGhlIGFyZ3VtZW50cyBhcmUgZGlmZmVyZW50LiBQaXBpbmcgZnJvbSB0aGUgZGF0YXNldCwgd2Ugc2V0IHJlc3BvbnNlIHRvIHRoZSBuYW1lIG9mIHRoZSBjb2x1bW4gb2YgaW50ZXJlc3QsIGFuZCBzZXQgJHAkIHRvIHRoZSBoeXBvdGhlc2l6ZWQgZGlzdHJpYnV0aW9uLiAqKlRoZSBkZWdyZWVzIG9mIGZyZWVkb20gYXJlIG9uZSBsZXNzIHRoYW4gdGhlIG51bWJlciBvZiBjaG9pY2VzIGluIHRoZSBzdXJ2ZXkqKi4gRm91ciBtaW51cyBvbmUgaXMgdGhyZWUuIFRoZSAqKnAtdmFsdWUgaXMgdmVyeSBzbWFsbCwgbXVjaCBsb3dlciB0aGFuIHRoZSBzaWduaWZpY2FuY2UgbGV2ZWwgd2Ugc2V0KiouIFRodXMgKip3ZSBjb25jbHVkZSB0aGF0IHRoZSBzYW1wbGUgZGlzdHJpYnV0aW9uIG9mIHByb3BvcnRpb25zIGlzIGRpZmZlcmVudCB0aGFuIHRoZSBoeXBvdGhlc2l6ZWQgZGlzdHJpYnV0aW9uIG9mIHByb3BvcnRpb25zKiouDQoNCmBgYHtyfQ0KaHlwb3RoZXNpemVkX3Byb3BzIDwtIGMoIkhlbGxvLCBvbGQgZnJpZW5kIiA9IDEvMiwgQW11c2VkID0gMS82LCBJbmRpZmZlcmVudCA9IDEvNiwgQW5ub3llZCA9IDEvNikNCmBgYA0KDQpgYGB7cn0NCnN0YWNrX292ZXJmbG93ICU+JQ0KICBjaGlzcV90ZXN0KHJlc3BvbnNlID0gcHVycGxlX2xpbmssIHAgPSBoeXBvdGhlc2l6ZWRfcHJvcHMpDQpgYGANCg0KIyMjIFRlc3Rpbmcgc2FtcGxlIHNpemUNCg0KSW4gb3JkZXIgdG8gY29uZHVjdCBhIGh5cG90aGVzaXMgdGVzdCwgYW5kIGJlIHN1cmUgdGhhdCB0aGUgcmVzdWx0IGlzIGZhaXIsIGEgc2FtcGxlIG11c3QgbWVldCB0aHJlZSByZXF1aXJlbWVudHM6IGl0IGlzIGEgcmFuZG9tIHNhbXBsZSBvZiB0aGUgcG9wdWxhdGlvbjsgdGhlIG9ic2VydmF0aW9ucyBhcmUgaW5kZXBlbmRlbnQ7IGFuZCB0aGVyZSBhcmUgZW5vdWdoIG9ic2VydmF0aW9ucy4gT2YgdGhlc2UsIG9ubHkgdGhlIGxhc3QgY29uZGl0aW9uIGlzIGVhc2lseSB0ZXN0YWJsZSB3aXRoIGNvZGUuDQoNClRoZSBtaW5pbXVtIHNhbXBsZSBzaXplIGRlcGVuZHMgb24gdGhlIHR5cGUgb2YgaHlwb3RoZXNpcyB0ZXN0cyB5b3Ugd2FudCB0byBwZXJmb3JtLiBMZXQncyB0ZXN0IHNvbWUgc2NlbmFyaW9zIG9uIHRoZSBgbGF0ZV9zaGlwbWVudHNgIGRhdGFzZXQuDQoNCi0gICBVc2luZyB0aGUgYGxhdGVfc2hpcG1lbnRzYCBkYXRhc2V0LCBnZXQgY291bnRzIGJ5IHRoZSBgZnJlaWdodF9jb3N0X2dyb3VwYCBjb2x1bW5zLg0KDQotICAgSW5zZXJ0IGEgc3VpdGFibGUgbnVtYmVyIHRvIGluc3BlY3Qgd2hldGhlciB0aGUgY291bnRzIGFyZSAiYmlnIGVub3VnaCIgZm9yIGEgdHdvIHNhbXBsZSB0LXRlc3QuDQoNCmBgYHtyfQ0KIyBHZXQgY291bnRzIGJ5IGZyZWlnaHRfY29zdF9ncm91cA0KY291bnRzIDwtIGxhdGVfc2hpcG1lbnRzICU+JQ0KICBjb3VudChmcmVpZ2h0X2Nvc3RfZ3JvdXApDQoNCiMgU2VlIHRoZSByZXN1bHQgDQpjb3VudHMNCg0KIyBJbnNwZWN0IHdoZXRoZXIgdGhlIGNvdW50cyBhcmUgYmlnIGVub3VnaA0KcHJpbnQoYWxsKGNvdW50cyRuID49IDMwKSkNCmBgYA0KDQotICAgVXNpbmcgdGhlIGBsYXRlX3NoaXBtZW50c2AgZGF0YXNldCwgZ2V0IGNvdW50cyBieSB0aGUgYGxhdGVgIGNvbHVtbi4NCg0KLSAgIEluc2VydCBhIHN1aXRhYmxlIG51bWJlciB0byBpbnNwZWN0IHdoZXRoZXIgdGhlIGNvdW50cyBhcmUgImJpZyBlbm91Z2giIGZvciBhIG9uZSBzYW1wbGUgcHJvcG9ydGlvbiB0ZXN0Lg0KDQpgYGB7cn0NCiMgR2V0IGNvdW50cyBieSBsYXRlDQpjb3VudHMgPC0gbGF0ZV9zaGlwbWVudHMgJT4lDQogIGNvdW50KGxhdGUpDQoNCiMgU2VlIHRoZSByZXN1bHRzIA0KY291bnRzDQoNCiMgSW5zcGVjdCB3aGV0aGVyIHRoZSBjb3VudHMgYXJlIGJpZyBlbm91Z2gNCmFsbChjb3VudHMkbiA+PSAxMCkNCmBgYA0KDQotICAgVXNpbmcgdGhlIGBsYXRlX3NoaXBtZW50c2AgZGF0YXNldCwgZ2V0IGNvdW50cyBieSB0aGUgYHZlbmRvcl9pbmNvX3Rlcm1gIGFuZCBgZnJlaWdodF9jb3N0X2dyb3VwYCBjb2x1bW5zLg0KDQotICAgSW5zZXJ0IGEgc3VpdGFibGUgbnVtYmVyIHRvIGluc3BlY3Qgd2hldGhlciB0aGUgY291bnRzIGFyZSAiYmlnIGVub3VnaCIgZm9yIGEgY2hpLXNxdWFyZSBpbmRlcGVuZGVuY2UgdGVzdC4NCg0KYGBge3J9DQojIENvdW50IHRoZSB2YWx1ZXMgb2YgdmVuZG9yX2luY29fdGVybSBhbmQgZnJlaWdodF9jb3N0X2dyb3VwDQpjb3VudHMgPC0gbGF0ZV9zaGlwbWVudHMgJT4lDQogIGNvdW50KHZlbmRvcl9pbmNvX3Rlcm0sIGZyZWlnaHRfY29zdF9ncm91cCkNCg0KIyBTZWUgdGhlIHJlc3VsdHMgDQpjb3VudHMNCg0KIyBJbnNwZWN0IHdoZXRoZXIgdGhlIGNvdW50cyBhcmUgYmlnIGVub3VnaA0KYWxsKGNvdW50cyRuID49IDUpDQpgYGANCg0KLSAgIFVzaW5nIHRoZSBgbGF0ZV9zaGlwbWVudHNgIGRhdGFzZXQsIGdldCBjb3VudHMgYnkgdGhlIGBzaGlwbWVudF9tb2RlYCBjb2x1bW4uDQoNCi0gICBJbnNlcnQgYSBzdWl0YWJsZSBudW1iZXIgdG8gaW5zcGVjdCB3aGV0aGVyIHRoZSBjb3VudHMgYXJlICJiaWcgZW5vdWdoIiBmb3IgYW4gQU5PVkEgdGVzdC4NCg0KICAgIGBgYHtyfQ0KICAgICMgQ291bnQgdGhlIHZhbHVlcyBvZiBzaGlwbWVudF9tb2RlDQogICAgY291bnRzIDwtIGxhdGVfc2hpcG1lbnRzICU+JQ0KICAgICAgY291bnQoc2hpcG1lbnRfbW9kZSkNCg0KICAgICMgU2VlIHRoZSByZXN1bHQNCiAgICBjb3VudHMNCg0KICAgICMgSW5zcGVjdCB3aGV0aGVyIHRoZSBjb3VudHMgYXJlIGJpZyBlbm91Z2gNCiAgICBhbGwoY291bnRzJG4gPj0gMzApDQogICAgYGBgDQoNCiMjIyAqKlRoZSAiVGhlcmUgaXMgb25seSBvbmUgdGVzdCIgZnJhbWV3b3JrKioNCg0KVHJhZGl0aW9uYWwgaHlwb3RoZXNpcyB0ZXN0cyBtYWtlIGFzc3VtcHRpb25zIGFib3V0IHRoZSBzYW1wbGUgZGF0YXNldC4gSGVyZSwgd2UnbGwgbG9vayBhdCB3aGF0IHRvIGRvIHdoZW4gdGhvc2UgYXNzdW1wdGlvbnMgZG9uJ3QgaG9sZC4NCg0KIyMjICoqSW1iYWxhbmNlIGRhdGEqKg0KDQpTb21ldGltZXMgeW91IGNhbid0IGdldCBhIHNhbXBsZSByZXByZXNlbnRpbmcgYWxsIHBhcnRzIG9mIHlvdXIgcG9wdWxhdGlvbi4gQ29uc2lkZXIgdGhpcyBzdWJzZXQgb2YgdGhlIFN0YWNrIE92ZXJmbG93IHN1cnZleS4gVGhlcmUgYXJlIGZld2VyIHVzZXJzIHdpdGggaG9iYnlpc3QgIk5vIiB0aGFuICJZZXMiLCBhbmQgZmV3ZXIgdXNlcnMgd2l0aCAiQXQgbGVhc3QgMzAiIGFnZXMgdGhhbiAiVW5kZXIgMzAiLiBJbiBmYWN0LCB0aGVyZSBhcmUgbm8gdXNlcnMgd2l0aCBob2JieWlzdCAiTm8iIGFuZCBhZ2UgIkF0IGxlYXN0IDMwIi4gVGhpcyBpcyBhIHByb2JsZW0gZm9yIGEgcHJvcG9ydGlvbiB0ZXN0LCBzaW5jZSBpdCByZXF1aXJlcyB0aGF0IGV2ZXJ5IGdyb3VwIGhhcyBhdCBsZWFzdCB0ZW4gb2JzZXJ2YXRpb25zLiBJIHVzZWQgYGNvdW50KOKApiwgLmRyb3ApYCBhcmd1bWVudCB0byBpbmNsdWRlIHN1Ymdyb3VwcyB3aXRoIGEgemVybyBjb3VudC4gKipBIGRhdGFzZXQgd2hlcmUgc29tZSBncm91cCdzIGNvdW50cyBhcmUgbXVjaCBsYXJnZXIgdGhhbiBvdGhlcnMgaXMgY2FsbGVkICJpbWJhbGFuY2VkKioiLg0KDQpgYGB7cn0NCnN0YWNrX292ZXJmbG93ICU+JSANCiAgY291bnQoaG9iYnlpc3QsIGFnZV9jYXQsIC5kcm9wID0gRkFMU0UpDQpgYGANCg0KIyMjICoqSHlwb3RoZXNlcyoqDQoNCldlIGNhbiBkZWNsYXJlIGh5cG90aGVzZXMgdG8gdGVzdC4gSSdsbCBzZXQgYSBzaWduaWZpY2FuY2UgbGV2ZWwgb2YgcG9pbnQtb25lLg0KDQokSF97MH0kIDogVGhlIHByb3BvcnRpb24gb2YgaG9iYnlpc3RzIHVuZGVyIDMwIGlzIHRoZSBzYW1lIGFzIHRoZSBwcm9wb3J0aW9uIG9mIGhvYmJ5aXN0cyBhdCBsZWFzdCAzMC4NCg0KJEhfe0F9JCA6IFRoZSBwcm9wb3J0aW9uIG9mIGhvYmJpc3RzIHVuZGVyIDMwIGlzIGRpZmZlcmVudCBmcm9tIHRoZSBwcm9wb3J0aW9uIG9mIGhvYmJ5aXN0cyBhdCBsZWFzdCAzMA0KDQpgYGB7cn0NCmFscGhhIDwtIDAuMQ0KYGBgDQoNCiMjIyAqKlByb2NlZWRpbmcgd2l0aCBhIHByb3BvcnRpb24gdGVzdCByZWdhcmRsZXNzKioNCg0KTGV0J3MgaWdub3JlIHRoZSBzbWFsbCBzYW1wbGUgcHJvYmxlbXMgYW5kIHJ1biBhIHByb3BvcnRpb24gdGVzdC4gVGhlIHAtdmFsdWUgaXMgJDIuNDAzIFx0aW1lcyAxMF57LTV9JCAsIHdoaWNoIGlzIGJlbG93IHRoZSBzaWduaWZpY2FuY2UgbGV2ZWwuIFRoaXMgdGVzdCBzdWdnZXN0cyB0aGF0IHRoZXJlIGlzIGVub3VnaCBldmlkZW5jZSB0byByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcy4gV2UnbGwgcmV2aXNpdCB0aGlzIGxhdGVyLg0KDQpgYGB7cn0NCnN0YWNrX292ZXJmbG93ICU+JQ0KICBwcm9wX3Rlc3QoaG9iYnlpc3QgfiBhZ2VfY2F0LCBvcmRlciA9IGMoIkF0IGxlYXN0IDMwIiwgIlVuZGVyIDMwIiksIHN1Y2Nlc3MgPSAiWWVzIiwNCiAgICAgICAgICAgIGFsdGVybmF0aXZlID0gInR3by5zaWRlZCIsIGNvcnJlY3QgPSBGQUxTRSkNCmBgYA0KDQojIyMgKipBIGdyYW1tYXIgb2YgZ3JhcGhpY3MqKg0KDQpUcmFkaXRpb25hbGx5LCBldmVyeSB0eXBlIG9mIHBsb3QgaGFzIGEgbmFtZSwgbGlrZSBzY2F0dGVyIHBsb3Qgb3IgbGluZSBwbG90LiBJbiBiYXNlLVIgeW91IGRlY2lkZSB0aGUgcGxvdCB0eXBlIGJ5IHNwZWNpZnlpbmcgYXJndW1lbnRzIHRvIHRoZSBwbG90IGZ1bmN0aW9uLCBvciBieSBjYWxsaW5nIGEgZGVkaWNhdGVkIGZ1bmN0aW9uIGxpa2UgaGlzdC4gVGhpcyBpcyBmaW5lIHVudGlsIHlvdSB3YW50IHRvIGRyYXcgYSBjdXN0b20gcGxvdCBsaWtlIGEgaGlzdG9ncmFtIHdpdGggcG9sYXIgY29vcmRpbmF0ZXMuIElmIGEgZnVuY3Rpb24gdG8gZHJhdyB0aGF0IGRvZXNuJ3QgZXhpc3QsIHlvdSBhcmUgc3R1Y2suIFRoZSBiZWF1dHkgb2YgdGhlIGdyYW1tYXIgb2YgZ3JhcGhpY3Mgc3lzdGVtIHRoYXQgZ2dwbG90MiBpbXBsZW1lbnRzIGlzIHRoYXQgcGxvdHMgYXJlIGJyb2tlbiBkb3duIGludG8gY29tcG9uZW50cyB0aGF0IGNhbiBiZSBjb21iaW5lZCBpbiBtYW55IHdheXMuIEl0J3MgbW9yZSBmbGV4aWJsZSBjcmVhdGluZyBhIG5ldyBmdW5jdGlvbiBmb3IgZXZlcnkgcGxvdCB0eXBlIHlvdSBjYW4gdGhpbmsgb2YuIFdoYXQgaWYgdGhlcmUgd2FzIGEgZ3JhbW1hciBvZiBoeXBvdGhlc2lzIHRlc3RzPw0KDQp8IFBsb3QgdHlwZSAgICAgICAgfCBCYXNlLVIgICAgICAgICAgICAgICB8IGdncGxvdDIgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8LS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18DQp8ICoqU2NhdHRlciBwbG90KiogfCBgcGxvdCgsIHR5cGUgPSAicCIpYCB8IGBnZ3Bsb3QoICkgKyBnZW9tX3BvaW50KCApYCAgICAgICAgICAgICAgICB8DQp8ICoqTGluZSBwbG90KiogICAgfCBgcGxvdCgsIHR5cGUgPSAibCIpYCB8IGBnZ3Bsb3QoICkgKyBnZW9tX2xpbmUoIClgICAgICAgICAgICAgICAgICB8DQp8ICoqSGlzdG9ncmFtKiogICAgfCBgaGlzdCggKWAgICAgICAgICAgICB8IGBnZ3Bsb3QoICkgKyBnZW9tX2hpc3RvZ3JhbSggKWAgICAgICAgICAgICB8DQp8ICoqQm94IHBsb3QqKiAgICAgfCBgYm94cGxvdCggKWAgICAgICAgICB8IGBnZ3Bsb3QoICkgKyBnZW9tX2JveHBsb3QoIClgICAgICAgICAgICAgICB8DQp8ICoqQmFyIHBsb3QqKiAgICAgfCBgYmFycGxvdCggKWAgICAgICAgICB8IGBnZ3Bsb3QoICkgKyBnZW9tX2JhciggKWAgICAgICAgICAgICAgICAgICB8DQp8ICoqUGllIHBsb3QqKiAgICAgfCBgcGllKCApYCAgICAgICAgICAgICB8IGBnZ3Bsb3QoICkgKyBnZW9tX2JhciggKSArIGNvb3JkX3BvbGFyKCApYCB8DQoNCiMjIyAqKkEgZ3JhbW1hciBvZiBoeXBvdGhlc2lzIHRlc3RzKioNCg0KVGhlIGdvb2QgbmV3cyBpcyB0aGF0IHRoZXJlIGlzIGEgZ3JhbW1hciBvZiBoeXBvdGhlc2lzIHRlc3RzLiBJdCB3YXMgaW52ZW50ZWQgYnkgRGF0YUNhbXAgaW5zdHJ1Y3RvciBBbGxlbiBEb3duZXksIGFuZCBpcyBjYWxsZWQgdGhlICoqIlRoZXJlIGlzIG9ubHkgb25lIHRlc3QiKiogZnJhbWV3b3JrLiBUaGUgZnJhbWV3b3JrIHdhcyBpbXBsZW1lbnRlZCBpbiBSIGluIHRoZSBgaW5mZXJgIHBhY2thZ2UgdGhhdCB5b3UndmUgdXNlZCBmb3IgcHJvcG9ydGlvbiBhbmQgY2hpLXNxdWFyZSB0ZXN0cy4gQWxsIGh5cG90aGVzaXMgdGVzdHMgY2FuIGJlIHBlcmZvcm1lZCB3aXRoIHRoaXMgY29kZSBmbG93LCBiYXNlZCBvbiBzcGVjaWZ5LCBoeXBvdGhlc2l6ZSwgZ2VuZXJhdGUsIGFuZCBjYWxjdWxhdGUuIEJ5IGNoYW5naW5nIHRoZSBhcmd1bWVudHMgdG8gdGhvc2UgZnVuY3Rpb25zIHlvdSBjYW4gcnVuIHN0YW5kYXJkIHRlc3RzIGxpa2UgdC10ZXN0cywgb3IgZGV2aXNlIHlvdXIgb3duIGN1c3RvbSB0ZXN0cy4gV2UnbGwgY292ZXIgc3BlY2lmeSBhbmQgaHlwb3RoZXNpemUgbm93LCBhbmQgdGhlIG90aGVycyBpbiB0aGUgbmV4dCB2aWRlby4gZ2VuZXJhdGUgaXMgd29ydGggbWVudGlvbmluZyBicmllZmx5LiBJdCBjcmVhdGVzIHNpbXVsYXRlZCBkYXRhIHJlZmxlY3RpbmcgdGhlIG51bGwgaHlwb3RoZXNpcy4gKipVc2luZyBzaW11bGF0aW9uIHJhdGhlciB0aGFuIGFyaXRobWV0aWMgZXF1YXRpb25zIHRvIGdldCB0aGUgdGVzdCBzdGF0aXN0aWMgaXMgY29tcHV0YXRpb25hbGx5IGV4cGVuc2l2ZSoqLCBzbyBpdCBoYXMgb25seSBiZWNvbWUgYWNjZXNzaWJsZSB3aXRoIG1vZGVybiBjb21wdXRpbmcgcG93ZXIuIEhvd2V2ZXIsIHNpbXVsYXRpb24gaGFzIGEgYmVuZWZpdCB0aGF0IGl0IHdvcmtzIHdlbGwgZXZlbiB3aGVuIHlvdSBoYXZlIHNtYWxsIHNhbXBsZXMgb3IgaW1iYWxhbmNlZCBkYXRhLg0KDQpeMV4gQWxsZW4gRG93bmV5IHRlYWNoZXMgIkV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMgaW4gUHl0aG9uIi4NCg0KYGBge3J9DQpudWxsX2Rpc3RuIDwtIGRhdGFzZXQgJT4lDQogIHNwZWNpZnkoKSAlPiUNCiAgaHlwb3RoZXNpemUoKSAlPiUNCiAgZ2VuZXJhdGUoKSAlPiUNCiAgY2FsY3VsYXRlKCkNCmBgYA0KDQpgYGB7cn0NCm9ic19zdGF0IDwtIGRhdGFzZXQgJT4lDQogIHNwZWNpZnkoKSAlPiUNCiAgY2FsY3VsYXRlKCkNCmBgYA0KDQpgYGB7cn0NCmdldF9wX3ZhbHVlKG51bGxfZGlzdG4gb2JzX3N0YXQpDQpgYGANCg0KIyMjICoqU3BlY2lmeWluZyB0aGUgdmFyaWFibGVzIG9mIGludGVyZXN0KioNCg0KVGhlIFN0YWNrIE92ZXJmbG93IHN1cnZleSBjb250YWlucyBtYW55IHZhcmlhYmxlcywgYnV0IGZvciB0aGlzIHRlc3QsIHdlIG9ubHkgY2FyZSBhYm91dCB0d28gb2YgdGhlbS4gYHNwZWNpZnkoKWAgd29ya3MgbGlrZSBkcGx5cidzIHNlbGVjdCwgcmV0dXJuaW5nIG9ubHkgdGhlIHJlc3BvbnNlIGFuZCBleHBsYW5hdG9yeSBjb2x1bW5zLg0KDQojIyMgKipzcGVjaWZ5KCkqKg0KDQpUbyBjYWxsIHNwZWNpZnksIHlvdSBwaXBlIGZyb20gdGhlIGRhdGFzZXQsIGFuZCBwYXNzIGEgZm9ybXVsYSB3aXRoIHRoZSByZXNwb25zZSBvbiB0aGUgbGVmdCBhbmQgdGhlIGV4cGxhbmF0b3J5IHZhcmlhYmxlIG9uIHRoZSByaWdodC4gSW4gdGhlIG9uZSBzYW1wbGUgY2FzZSwgdXNlIE5VTEwgZm9yIHRoZSBleHBsYW5hdG9yeSB2YWx1ZS4gSnVzdCBhcyB3aGVuIHlvdSBjYWxsZWQgYHByb3BfdGVzdCgpYCwgeW91IG5lZWQgdG8gdGVsbCBzcGVjaWZ5IHdoaWNoIHJlc3BvbnNlIHZhbHVlIGlzIHJlZ2FyZGVkIGFzIGEgc3VjY2Vzcy4gc3BlY2lmeSByZXR1cm5zIGEgdGliYmxlIHdpdGggYXR0cmlidXRlcyBub3RpbmcgdGhlIHJlc3BvbnNlIGFuZCBleHBsYW5hdG9yeSB2YXJpYWJsZSBuYW1lcy4NCg0KLSAgIEZvciAyIHNhbXBsZSB0ZXN0cywgdXNlOiBgcmVzcG9uc2UgfiBleHBsYW5hdG9yeWANCg0KLSAgIEZvciAxIHNhbXBsZSB0ZXN0cyB1c2UgYHJlc3BvbnNlIH4gTlVMTGANCg0KYGBge3J9DQpzdGFja19vdmVyZmxvdyAlPiUNCiAgc3BlY2lmeShob2JieWlzdCB+IGFnZV9jYXQsIHN1Y2Nlc3MgPSAiWWVzIikNCmBgYA0KDQojIyMgKipgaHlwb3RoZXNpemUoKWAqKg0KDQpgaHlwb3RoZXNpemUoKWAgZGVjbGFyZXMgdGhlIHR5cGUgb2YgbnVsbCBoeXBvdGhlc2lzLiBQcm9wb3J0aW9uIHRlc3RzIGFyZSBhIHNwZWNpYWwgY2FzZSBvZiB0aGUgY2hpLXNxdWFyZSBpbmRlcGVuZGVuY2UgdGVzdCwgc28gd2UgY2hvb3NlICJpbmRlcGVuZGVuY2UiLiBoeXBvdGhlc2l6ZSBkb2Vzbid0IGNhbGN1bGF0ZSBhbnl0aGluZzsgaXQgc2ltcGx5IGFkZHMgYW5vdGhlciBhdHRyaWJ1dGUgdG8gdGhlIGRhdGFzZXQuDQoNCi0gICBGb3IgMiBzYW1wbGUgdGVzdHMsIHVzZSBgImluZGVwZW5kZW5jZSJgIG9yIGAicG9pbnQiYA0KDQotICAgRm9yIDEgc2FtcGxlIHRlc3RzLCB1c2UgYCJwb2ludCJgDQoNCmBgYHtyfQ0Kc3RhY2tfb3ZlcmZsb3cgJT4lDQogIHNwZWNpZnkoaG9iYnlpc3QgfiBhZ2VfY2F0LCBzdWNjZXNzID0gIlllcyIpICU+JQ0KICBoeXBvdGhlc2lzZShudWxsID0gImluZGVwZW5kZW5jZSIpDQpgYGANCg0KIyMgKipDb250aW51aW5nIHRoZSBpbmZlciBwaXBlbGluZSoqDQoNClByZXZpb3VzbHkgd2Ugc2F3IHBhcnQgb2YgdGhlIGluZmVyIHBpcGVsaW5lIGZvciBzaW11bGF0aW9uLWJhc2VkIGh5cG90aGVzaXMgdGVzdHMuDQoNCiMjIyAqKlJlY2FwOiBoeXBvdGhlc2VzIGFuZCBkYXRhc2V0KioNCg0KV2Ugd2VyZSB0ZXN0aW5nIHRoZSBoeXBvdGhlc2lzIHRoYXQgdGhlIHByb3BvcnRpb24gb2YgaG9iYnlpc3RzIHdhcyB0aGUgc2FtZSBmb3IgdHdvIGFnZSBjYXRlZ29yaWVzLiBIb3dldmVyLCB0aGlzIHN1YnNldCBvZiB0aGUgU3RhY2sgT3ZlcmZsb3cgc3VydmV5IHdhcyBpbWJhbGFuY2VkLCB2aW9sYXRpbmcgdGhlIGFzc3VtcHRpb25zIG9mIHRoZSB0cmFkaXRpb25hbCBwcm9wb3J0aW9uIHRlc3QuDQoNCiRIX3swfSQgOiBUaGUgcHJvcG9ydGlvbiBvZiBob2JiaXlpc3RzIHVuZGVyIDMwIGlzIHRoZSBzYW1lIGFzIHRoZSBwcm9wwrRuIG9mIGhvYmJ5aXN0cyBhdCBsZWFzdCAzMC4NCg0KJEhfe0F9JCA6IFRoZSBwcm9wb3J0aW9uIG9mIGhvYmJ5aXN0cyB1bmRlciAzMCBpcyBkaWZmZXJlbnQgZnJvbSB0aGUgcHJvcMK0biBvZiBob2JieWlzdHMgYXQgbGVhc3QgMzAuDQoNCmBgYHtyfQ0KYWxwaGEgPC0gMC4xDQpgYGANCg0KIyMjICoqUmVjYXA6IHdvcmtmbG93KioNCg0KWW91IHNhdyB0aGUgY29tcGxldGUgd29ya2Zsb3cgZm9yIGEgY3VzdG9tIGh5cG90aGVzaXMgdGVzdC4gU28gZmFyLCB3ZSdkIGRvbmUgdGhlIHNwZWNpZnkgYW5kIGh5cG90aGVzaXplIHN0ZXBzLCByZXN1bHRpbmcgaW4gYSB0aWJibGUgd2l0aCB0d28gY29sdW1ucyBhbmQgc29tZSBleHRyYSBhdHRyaWJ1dGVzIGRlc2NyaWJpbmcgdGhlIHJlc3BvbnNlIGFuZCBleHBsYW5hdG9yeSB2YXJpYWJsZXMsIGFuZCB0aGUgdHlwZSBvZiBudWxsIGh5cG90aGVzaXMuDQoNCmBgYHtyfQ0KbnVsbF9kaXN0biA8LSBkYXRhc2V0ICU+JQ0KICBzcGVjaWZ5KCkgJT4lDQogIGh5cG90aGVzaXplKCkgJT4lDQogIGdlbmVyYXRlKCkgJT4lDQogIGNhbGN1bGF0ZSgpDQpgYGANCg0KYGBge3J9DQpvYnNlcnZlZF9zdGF0IDwtIGRhdGFzZXQgJT4lDQogIHNwZWNpZnkoKSAlPiUNCiAgY2FsY3VsYXRlKCkNCmBgYA0KDQpgYGB7cn0NCmdldF9wX3ZhbHVlKG51bGxfZGlzdG4sIG9ic2VydmVkX3N0YXQpDQpgYGANCg0KIyMjICoqTW90aXZhdGluZyBgZ2VuZXJhdGUoKWAqKg0KDQpJZiB3ZSBhc3N1bWUgdGhlIG51bGwgaHlwb3RoZXNpcyBpcyB0cnVlLCB0aGVuIGl0IHNob3VsZG4ndCBtYXR0ZXIgd2hpY2ggaG9iYnlpc3QgdmFsdWUgaXMgbWF0Y2hlZCB1cCB0byBlYWNoIGFnZSBjYXRlZ29yeSwgc2luY2UgdGhlIHByb3BvcnRpb24gb2YgaG9iYnlpc3RzIGlzIHRoZSBzYW1lIGluIGVhY2ggYWdlIGNhdGVnb3J5LiBXZSBjYW4gZ2VuZXJhdGUgYSBzaW11bGF0ZWQgZGF0YXNldCBieSBzaHVmZmxpbmcgdGhlIHJlc3BvbnNlIGhvYmJ5aXN0IHZhbHVlcyB3aGlsZSBrZWVwaW5nIHRoZSBleHBsYW5hdG9yeSBhZ2UgY2F0ZWdvcnkgdmFsdWVzIHRoZSBzYW1lLg0KDQokSF97MH0kIDogVGhlIHByb3BvcnRpb24gb2YgaG9iYml5aXN0cyB1bmRlciAzMCBpcyB0aGUgc2FtZSBhcyB0aGUgcHJvcMK0biBvZiBob2JieWlzdHMgYXQgbGVhc3QgMzAuDQoNCmlmICRIX3swfSQgaXMgdHJ1ZSwgdGhlbg0KDQotICAgSW4gZWFjaCByb3csIHRoZSBob2JiaXN0IHZhbHVlIGNvdWxkIGhhdmUgYXBwZWFyZWQgd2l0aCBlaXRoZXIgYWdlIGNhdGVnb3J5IHdpdGggZXF1YWwgcHJvYmFiaWxpdHkuDQoNCi0gICBUbyBzaW11bGF0ZSB0aGlzLCB3ZSBjYW4gcGVybXV0ZSAoc2h1ZmZsZSkgdGhlIGhvYmJ5aXN0IHZhbHVlcyB3aGlsZSBrZWVwaW5nIHRoZSBhZ2UgY2F0ZWdvcmllcyBmaXhlZA0KDQojIyMgKipPbmUgcGVybXV0YXRpb24qKg0KDQpDb25jZXB0dWFsbHksIHRoaXMgaXMgaG93IGdlbmVyYXRlIHNodWZmbGVzIHRoZSBkYXRhc2V0LiBJdCBzZWxlY3RzIHRoZSByZXNwb25zZSBjb2x1bW4sIHJhbmRvbWx5IHNhbXBsZXMgdGhlIHdob2xlIGNvbHVtbiB3aXRob3V0IHJlcGxhY2VtZW50LCB0aGVuIGJpbmRzIGl0IGJhY2sgdG8gdGhlIGV4cGxhbmF0b3J5IGNvbHVtbi4gQ29tcGFyZSB0aGUgb3JpZ2luYWwgZGF0YXNldCBvbiB0aGUgbGVmdCwgYW5kIHRoZSBzaHVmZmxlZCBkYXRhc2V0IG9uIHRoZSByaWdodC4gVGhlIGhvYmJ5aXN0IHZhbHVlcyBoYXZlIGNoYW5nZWQgYnV0IHRoZSBhZ2UgY2F0ZWdvcnkgdmFsdWVzIGhhdmUgbm90Lg0KDQpgYGB7cn0NCmJpbmRfY29scyhzdGFja19vdmVyZmxvdyAlPiUNCiAgICAgICAgICAgIHNlbGVjdChob2JieWlzdCkgJT4lDQogICAgICAgICAgICBzbGljZV9zYW1wbGUocHJvcCA9IDEpLA0KICAgICAgICAgIHN0YWNrX292ZXJmbG93ICU+JQ0KICAgICAgICAgICAgc2VsZWN0KGFnZV9jYXQpDQogICAgICAgICAgKQ0KYGBgDQoNCiMjIyAqKkdlbmVyYXRpbmcgbWFueSByZXBsaWNhdGVzKioNCg0KU2luY2UgcmFuZG9tbmVzcyBpcyB1c2VkIGluIHRoZSBzaHVmZmxpbmcgc3RlcCwgd2UgY2FuJ3QganVzdCBjcmVhdGUgb25lIHNpbXVsYXRlZCBkYXRhc2V0LCBvciB0aGUgcmVzdWx0cyB3b3VsZCBiZSB1bnJlbGlhYmxlLiBgZ2VuZXJhdGUoKWAgcGVyZm9ybXMgdGhlIHNpbXVsYXRpb24gc3RlcCBtYW55IHRpbWVzLiBFYWNoIHNpbXVsYXRlZCBkYXRhc2V0IGlzIGNhbGxlZCBhICoqcmVwbGljYXRlKiogYW5kIHJlcHJlc2VudHMgYW4gZXhhbXBsZSBvZiB3aGF0IHdlIG1pZ2h0IGV4cGVjdCB0aGUgdHdvIGNvbHVtbnMgdG8gbG9vayBsaWtlIGluIGEgdW5pdmVyc2Ugd2hlcmUgdGhlIG51bGwgaHlwb3RoZXNpcyBpcyB0cnVlLg0KDQojIyMgKipgZ2VuZXJhdGUoKWAqKg0KDQpUbyBjYWxsIGBnZW5lcmF0ZSgpYCwgdGVsbCBpdCBob3cgbWFueSByZXBsaWNhdGVzIHlvdSB3YW50LiBGb3IgaW5kZXBlbmRlbmNlIHRlc3RzLCB0aGUgZ2VuZXJhdGlvbiB0eXBlIHNob3VsZCBhbHdheXMgYmUgInBlcm11dGUiLiBGb3IgY29udmVuaWVuY2UsIGdlbmVyYXRlIGNvbWJpbmVzIGFsbCB0aGUgc2ltdWxhdGVkIGRhdGFzZXRzIGludG8gYSBzaW5nbGUgdGliYmxlLiBUaGlzIGlzIGJpZyEgSXQgaGFzIGFzIG1hbnkgcm93cyBhcyB0aGUgb3JpZ2luYWwgZGF0YXNldCwgdGltZXMgdGhlIG51bWJlciBvZiByZXBsaWNhdGVzLg0KDQotICAgRm9yICJpbmRlcGVuZGVuY2UiIG51bGwgaHlwb3RoZXNpcywgc2V0IGB0eXBlYCB0byBgInBlcm11dGUiYC4NCg0KLSAgIEZvciAicG9pbnQiIG51bGwgaHlwb3RoZXNlcywgc2V0IGB0eXBlYCB0byBgImJvb3RzdHJhcCJgIG9yIGAic2ltdWxhdGUiYA0KDQpgYGB7cn0NCnN0YWNrX292ZXJmbG93ICU+JQ0KICBzcGVjaWZ5KGhvYmJ5aXN0IH4gYWdlX2NhdCwgc3VjY2VzcyA9ICJZZXMiKSAlPiUNCiAgaHlwb3RoZXNpemUobnVsbCA9ICJpbmRlcGVuZGVuY2UiKSAlPiUNCiAgZ2VuZXJhdGUocmVwcyA9IDUwMDAsIHR5cGUgPSAicGVybXV0ZSIpDQpgYGANCg0KIyMjICoqQ2FsY3VsYXRpbmcgdGhlIHRlc3Qgc3RhdGlzdGljKioNCg0KRm9yIGVhY2ggcmVwbGljYXRlLCB3ZSBjYWxjdWxhdGUgdGhlIHRlc3Qgc3RhdGlzdGljLCBpbiB0aGlzIGNhc2UgdGhlIGRpZmZlcmVuY2UgaW4gcHJvcG9ydGlvbnMgb2YgaG9iYnlpc3RzIGJldHdlZW4gdGhlIHR3byBhZ2UgY2F0ZWdvcmllcy4gNTAwMCByZXBsaWNhdGVzIGdpdmVzIDUwMDB6IGRpZmZlcmVuY2VzIGluIHByb3BvcnRpb25zLiBXZSBoYXZlIGEgZGlzdHJpYnV0aW9uIG9mIHRlc3Qgc3RhdGlzdGljcy4gVGhpcyBpcyBrbm93biBhcyB0aGUgbnVsbCBkaXN0cmlidXRpb24uDQoNCiMjIyAqKmBjYWxjdWxhdGUoKWAqKg0KDQpUbyB1c2UgdGhlIGRpZmZlcmVuY2UgaW4gcHJvcG9ydGlvbnMgYXMgdGhlIHRlc3Qgc3RhdGlzdGljLCBzZXQgdGhlIHN0YXQgYXJndW1lbnQgdG8gImRpZmYgaW4gcHJvcHMiLiBXZSBuZWVkIHRvIHRlbGwgY2FsY3VsYXRlIHdoaWNoIHByb3BvcnRpb24gdG8gc3VidHJhY3QgZnJvbSB3aGljaCBieSBzZXR0aW5nIHRoZSBvcmRlci4NCg0KXjFeIFRoZSA/Y2FsY3VsYXRlIGhlbHAgcGFnZSBsaXN0cyBhbGwgcG9zc2libGUgdGVzdCBzdGF0aXN0aWNzLg0KDQpgY2FsY3VsYXRlKClgIGNhbGN1bGF0ZXMgYSBkaXN0cmlidXRpb24gb2YgdGVzdCBzdGF0aXN0aWNzIGtub3duIGFzIHRoZSAqbnVsbCBkaXN0cmlidXRpb24qDQoNCmBgYHtyfQ0KbnVsbF9kaXN0biA8LSBzdGFja19vdmVyZmxvdyAlPiUNCiAgc3BlY2lmeShob2JieWlzdCB+IGFnZV9jYXQsIHN1Y2Nlc3MgPSAiWWVzIikgJT4lDQogIGh5cG90aGVzaXplKG51bGwgPSAiaW5kZXBlbmRlbmNlIikgJT4lDQogIGdlbmVyYXRlKHJlcHMgPSA1MDAwLCB0eXBlID0gInBlcm11dGUiKSAlPiUNCiAgY2FsY3VsYXRlKHN0YXQgPSAiZGlmZiBpbiBwcm9wcyIsIG9yZGVyID0gYygiQXQgbGVhc3QgMzAiLCAiVW5kZXIgMzAiKSkNCg0KbnVsbF9kaXN0bg0KYGBgDQoNCiMjIyAqKlZpc3VhbGl6aW5nIHRoZSBudWxsIGRpc3RyaWJ1dGlvbioqDQoNClRvIHZpc3VhbGl6ZSB0aGlzIG51bGwgZGlzdHJpYnV0aW9uIGFzIGEgaGlzdG9ncmFtLCBjYWxsIHZpc3VhbGl6ZS4gVGhpcyBoaXN0b2dyYW0gZG9lc24ndCBoYXZlIGEgbm9ybWFsIGJlbGwgY3VydmUuIFRoYXQgbWVhbnMgdGhlIGFzc3VtcHRpb25zIGZvciB0aGUgcHJvcG9ydGlvbiB0ZXN0IGRpZG4ndCBob2xkLiBBbHNvIG5vdGljZSB0aGF0IHRoZSB0ZXN0IHN0YXRpc3RpYyBvbmx5IHRha2VzIG5pbmUgZGlzdGluY3QgdmFsdWVzLg0KDQpgYGB7cn0NCnZpc3VhbGlzZShudWxsX2Rpc3RuKQ0KYGBgDQoNCiMjIyAqKkNhbGN1bGF0aW5nIHRoZSB0ZXN0IHN0YXRpc3RpYyBvbiB0aGUgb3JpZ2luYWwgZGF0YXNldCoqDQoNClRvIGNhbGN1bGF0ZSBhIHAtdmFsdWUsIHdlIG5lZWQgdG8gY29tcGFyZSB0aGUgbnVsbCBkaXN0cmlidXRpb24gdG8gdGhlIHRlc3Qgc3RhdGlzdGljIGZyb20gdGhlIG9yaWdpbmFsIGRhdGFzZXQuDQoNCiMjIyAqKk9ic2VydmVkIHN0YXRpc3RpYzogYHNwZWNpZnkoKSAlPiUgY2FsY3VsYXRlKClgKioNCg0KVG8gY2FsY3VsYXRlIHRoZSB0ZXN0IHN0YXRpc3RpYyBvbiB0aGUgb3JpZ2luYWwgc2FtcGxlIGRhdGFzZXQsIHlvdSByZXVzZSB0aGUgc3BlY2lmeSBhbmQgY2FsY3VsYXRlIHN0ZXBzLiBDb3B5IGFuZCBwYXN0ZSB0aGUgbnVsbCBkaXN0cmlidXRpb24gY29kZSwgdGhlbiByZW1vdmUgdGhlIGh5cG90aGVzaXplIGFuZCBnZW5lcmF0ZSBzdGVwcy4gSGVyZSwgdGhlIG9ic2VydmVkIHN0YXRpc3RpYyBpcyAtMC4wNy4NCg0KYGBge3J9DQpvYnNfc3RhdCA8LSBzdGFja19vdmVyZmxvdyAlPiUNCiAgc3BlY2lmeShob2JieWlzdCB+IGFnZV9jYXQsIHN1Y2Nlc3MgPSAiWWVzIikgJT4lDQogICMgaHlwb3Rlc2l6ZShudWxsID0gImluZGVwZW5kZW5jZSIpICU+JQ0KICAjIGdlbmVyYXRlKHJlcHMgPSA1MDAwLCB0eXBlID0gInBlcm11dGUiKSAlPiUNCiAgY2FsY3VsYXRlKHN0YXQgPSAiZGlmZiBpbiBwcm9wcyIsIG9yZGVyID0gYygiQXQgbGVhc3QgMzAiLCAiVW5kZXIgMzAiKSkNCg0Kb2JzX3N0YXQNCmBgYA0KDQojIyMgKipWaXN1YWxpemluZyB0aGUgbnVsbCBkaXN0cmlidXRpb24gdnMuIHRoZSBvYnNlcnZlZCBzdGF0KioNCg0KSGVyZSdzIHRoZSBudWxsIGRpc3RyaWJ1dGlvbiBoaXN0b2dyYW0gd2l0aCBhIHZlcnRpY2FsIGxpbmUgYWRkZWQgYXQgdGhlIG9ic2VydmVkIHN0YXRpc3RpYy4gVGhlIG9ic2VydmVkIHN0YXRpc3RpYyBpcyBhdCBvbmUgZWRnZSBvZiB0aGUgZGlzdHJpYnV0aW9uLiBEb2VzIHRoaXMgbWFrZSBpdCBkaWZmZXJlbnQgZW5vdWdoIGZyb20gdGhlIG51bGwgZGlzdHJpYnV0aW9uIHRoYXQgd2Ugc2hvdWxkIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzPyBXZSdsbCBuZWVkIHRvIGNhbGN1bGF0ZSB0aGUgcC12YWx1ZSB0byBmaW5kIG91dC4NCg0KYGBge3J9DQp2aXN1YWxpc2UobnVsbF9kaXN0bikgKw0KICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gc3RhdCksIGRhdGEgPSBvYnNfc3RhdCwgY29sb3IgPSAicmVkIikNCmBgYA0KDQojIyMgKipHZXQgdGhlIHAtdmFsdWUqKg0KDQpUbyBnZXQgdGhlIHAtdmFsdWUsIGNhbGwgYGdldF9wX3ZhbHVlKClgLCBwYXNzaW5nIHRoZSBudWxsIGRpc3RyaWJ1dGlvbiBhbmQgb2JzZXJ2ZWQgc3RhdGlzdGljLiBZb3UgYWxzbyBuZWVkIHRvIHNldCB0aGUgdHlwZSBvZiBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzLiAqKlRoZSBhcmd1bWVudCBpcyBjYWxsZWQgZGlyZWN0aW9uIHJhdGhlciB0aGFuIGFsdGVybmF0aXZlKiosIGFuZCAidHdvIHNpZGVkIiBpcyBzZXBhcmF0ZWQgd2l0aCBhIHNwYWNlIHJhdGhlciB0aGFuIGEgZG90LiBUaGlzIHRpbWUgdGhlIHAtdmFsdWUgaXMgcG9pbnQtb25lLWZpdmUsIHdoaWNoIGlzIGdyZWF0ZXIgdGhhbiB0aGUgc2lnbmlmaWNhbmNlIGxldmVsIG9mIHBvaW50LW9uZS4gVGhhdCBtZWFucyB0aGF0IHdlIHNob3VsZCBmYWlsIHRvIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzIHN0aWNraW5nIHdpdGggdGhlcmUgYmVpbmcgbm8gZGlmZmVyZW5jZSBpbiBwcm9wb3J0aW9ucyBvZiBob2JieWlzdHMgYmV0d2VlbiBhZ2UgY2F0ZWdvcmllcy4gUmVjYWxsIHRoZSByZXN1bHRzIGZyb20gdGhlIGR1YmlvdXMgcHJvcG9ydGlvbiB0ZXN0IHdlIHVzZWQgYmVmb3JlLiBUaGF0IGhhZCB0aGUgb3Bwb3NpdGUgY29uY2x1c2lvbi4gSG9wZWZ1bGx5IHRoaXMgaWxsdXN0cmF0ZXMgdGhlIGRhbmdlciBvZiB1c2luZyB0cmFkaXRpb25hbCBoeXBvdGhlc2lzIHRlc3RzIHdoZW4gdGhlIGFzc3VtcHRpb25zIGFyZW4ndCBtZXQuIEFsdGhvdWdoIGl0IHRha2VzIG1vcmUgY29kZSwgdGhlIHNpbXVsYXRpb24tYmFzZWQgaHlwb3RoZXNpcyB0ZXN0cyBhcmUgbW9yZSByb2J1c3QgYWdhaW5zdCBzbWFsbCBzYW1wbGVzLCBhbmQgd2lsbCBoZWxwIHByZXZlbnQgeW91IHJlYWNoaW5nIHBvb3IgY29uY2x1c2lvbnMuDQoNCmBgYHtyfQ0KZ2V0X3BfdmFsdWUobnVsbF9kaXN0biwgb2JzX3N0YXQsIGRpcmVjdGlvbiA9ICJ0d28gc2lkZWQiKSAjIG5vdCBhbHRlcm5hdGl2ZSA9ICJ0d28uc2lkZWQiDQpgYGANCg0KIyMgKipOb24tcGFyYW1ldHJpYyBBTk9WQSBhbmQgdW5wYWlyZWQgdC10ZXN0cyoqDQoNClRoZSBzaW11bGF0aW9uLWJhc2VkIHByb3BvcnRpb24gdGVzdCB3ZSBwZXJmb3JtZWQgdXNpbmcgdGhlIGluZmVyIHBpcGVsaW5lIGF2b2lkZWQgdGhlIGFzc3VtcHRpb24gdGhhdCB0aGUgdGVzdCBzdGF0aXN0aWMgaXMgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuDQoNCiMjIyAqKk5vbi1wYXJhbWV0cmljIHRlc3RzKioNCg0KKipIeXBvdGhlc2lzIHRlc3RzIHRoYXQgZG9uJ3QgYXNzdW1lIGEgcHJvYmFiaWxpdHkgZGlzdHJpYnV0aW9uIGZvciB0aGUgdGVzdCBzdGF0aXN0aWMgYXJlIGNhbGxlZCBub24tcGFyYW1ldHJpYyB0ZXN0cyoqLiBUaGVyZSBhcmUgdHdvIHR5cGVzIG9mIG5vbi1wYXJhbWV0cmljIHRlc3QuIFRoZSBpbmZlciBwaXBlbGluZSBwZXJmb3JtcyBzaW11bGF0aW9uLWJhc2VkIHRlc3RzLiBPdGhlciB0ZXN0cyB1c2UgdGhlIHJhbmsgb2YgdGhlIGRhdGEuDQoNClR3byB0eXBlcyBvZiBub24tcGFyYW1ldHJpYyB0ZXN0czoNCg0KMS4gIFNpbXVsYXRpb24tYmFzZWQNCg0KMi4gIFJhbmstYmFzZWQNCg0KIyMjICoqYHRfdGVzdCgpYCoqDQoNCkhlcmUncyBhIHQtdGVzdC4gVGhpcyB0ZXN0ZWQgZGlmZmVyZW5jZXMgaW4gbWVhbiBhbm51YWwgY29tcGVuc2F0aW9uIGZvciBTdGFjayBPdmVyZmxvdyB1c2VycyBkZXBlbmRpbmcgb24gd2hldGhlciB0aGV5IGZpcnN0IGxlYXJuZWQgdG8gcHJvZ3JhbSBhcyBhIGNoaWxkIG9yIGFzIGFuIGFkdWx0LiBSYXRoZXIgdGhhbiBjYWxjdWxhdGluZyBpdCBzdGVwLWJ5IHN0ZXAsIFdlJ3ZlIHVzZWQgdF90ZXN0IGZyb20gaW5mZXIuIFRoZSBkZWdyZWVzIG9mIGZyZWVkb20gYXJlIGRpZmZlcmVudCBoZXJlIGJlY2F1c2UgdGhleSBhcmUgY2FsY3VsYXRlZCB1c2luZyBhbiBlcXVhdGlvbiBjYWxsZWQgdGhlICoqV2VsY2ggYXBwcm94aW1hdGlvbioqLCBpbnN0ZWFkIG9mIHRha2luZyB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBtaW51cyB0d28uIEluIHByYWN0aWNlLCB0aGUgZGlmZmVyZW5jZSBpc24ndCBpbXBvcnRhbnQuIFRoZSBwLXZhbHVlIGlzIDAuMDMwODIgaW5zdGVhZCBvZiAwLiBMZXQncyBleHBsb3JlIHNvbWUgbm9uLXBhcmFtZXRyaWMgYWx0ZXJuYXRpdmVzIHRvIHRoZSB0LXRlc3QsIHN0YXJ0aW5nIHdpdGggdGhlIHNpbXVsYXRpb24tYmFzZWQgaW5mZXIgcGlwZWxpbmUuDQoNCiQkDQpIX3swfSA6IFxtdV97Y2hpbGR9IFwgLSBcbXVfe2FkdWx0fSBcID0gMCBcIFwgXCAgSF97QX0gOiBcbXVfe2NoaWxkfSBcIC0gXG11X3thZHVsdH0gXCA+IDANCiQkDQoNCmBgYHtyfQ0Kc3RhY2tfb3ZlcmZsb3cgJT4lDQogIHRfdGVzdChjb252ZXJ0ZWRfY29tcCB+IGFnZV9maXJzdF9jb2RlX2N1dCwgb3JkZXIgPSBjKCJjaGlsZCIsICJhZHVsdCIpLCBhbHRlcm5hdGl2ZSA9ICJncmVhdGVyIikNCg0KYGBgDQoNCiMjIyAqKkNhbGN1bGF0aW5nIHRoZSBudWxsIGRpc3RyaWJ1dGlvbioqDQoNCkp1c3QgYXMgeW91IGRpZCB3aXRoIHRoZSBzaW11bGF0aW9uLWJhc2VkIHByb3BvcnRpb24gdGVzdCwgeW91IHN0YXJ0IGJ5IHNwZWNpZnlpbmcgdGhlIHZhcmlhYmxlcyBvZiBpbnRlcmVzdC4gSXQncyB0aGUgc2FtZSBmb3JtdWxhIHBhc3NlZCB0byB0X3Rlc3Q6IHRoZSBudW1lcmljIGNvbXBlbnNhdGlvbiBvbiB0aGUgbGVmdCBhbmQgdGhlIGFnZSBjYXRlZ29yaWVzIG9uIHRoZSByaWdodC4gTmV4dCB5b3UgZGVjbGFyZSB0aGUgbnVsbCBoeXBvdGhlc2lzLCAqKnRoYXQgY29tcGVuc2F0aW9uIGlzIGluZGVwZW5kZW50IG9mIHRoZSBhZ2UgY2F0ZWdvcnkqKi4gVGhpcmRseSwgeW91ICoqZ2VuZXJhdGUgcGVybXV0YXRpb24gcmVwbGljYXRlcyBvZiB0aGUgZGF0YSoqLiBGaW5hbGx5LCB5b3UgYyoqYWxjdWxhdGUgdGhlIG5vbi1zdGFuZGFyZGl6ZWQgdGVzdCBzdGF0aXN0aWMgZm9yIGVhY2ggcmVwbGljYXRlKiouIFRoZSBzdGF0IGFyZ3VtZW50IGlzIGAiZGlmZiBpbiBtZWFucyJgLiBUaGUgb3JkZXIgYXJndW1lbnQgaXMgdGhlIHNhbWUgYXMgaW4gdGhlIGNhbGwgdG8gdF90ZXN0Lg0KDQpgYGB7cn0NCiMgU2ltdWxhdGlvbi1iYXNlZCBwaXBlbGluZQ0KbnVsbF9kaXN0biA8LSBzdGFja19vdmVyZmxvdyAlPiUNCiAgc3BlY2lmeShjb252ZXJ0ZWRfY29tcCB+IGFnZV9maXJzdF9jb2RlX2N1dCkgJT4lDQogIGh5cG90aGVzaXplKG51bGwgPSAiaW5kZXBlbmRlbmNlIikgJT4lDQogIGdlbmVyYXRlKHJlcHMgPSA1MDAwLCB0eXBlID0gInBlcm11dGUiKSAlPiUNCiAgY2FsY3VsYXRlKHN0YXQgPSAiZGlmZiBpbiBtZWFucyIsIG9yZGVyID0gYygiY2hpbGQiLCAiYWR1bHQiKQ0KICApDQoNCm51bGxfZGlzdG4NCmBgYA0KDQpgYGB7cn0NCiMgdC10ZXN0LCBmb3IgY29tcGFyaXNvbiANCnN0YWNrX292ZXJmbG93ICU+JQ0KICB0X3Rlc3QoY29udmVydGVkX2NvbXAgfiBhZ2VfZmlyc3RfY29kZV9jdXQsIG9yZGVyID0gYygiY2hpbGQiLCAiYWR1bHQiKSwgYWx0ZXJuYXRpdmUgPSAiZ3JlYXRlciIpDQpgYGANCg0KIyMjICoqQ2FsY3VsYXRpbmcgdGhlIG9ic2VydmVkIHN0YXRpc3RpYyoqDQoNClRvIGNhbGN1bGF0ZSB0aGUgZGlmZmVyZW5jZSBpbiBtZWFucyBvYnNlcnZlZCBpbiB0aGUgU3RhY2sgT3ZlcmZsb3cgc3VydmV5LCB3ZSByZXVzZSB0aGUgc3BlY2lmeSBhbmQgY2FsY3VsYXRlIHN0ZXBzIGZyb20gdGhlIHByZXZpb3VzIHBpcGVsaW5lLg0KDQpgYGB7cn0NCiMgU2ltdWxhdGlvbi1iYXNlZCBwaXBlbGluZQ0Kb2JzX3N0YXQgPC0gc3RhY2tfb3ZlcmZsb3cgJT4lDQogIHNwZWNpZnkoY29udmVydGVkX2NvbXAgfiBhZ2VfZmlyc3RfY29kZV9jdXQpICU+JQ0KICBjYWxjdWxhdGUoc3RhdCA9ICJkaWZmIGluIG1lYW5zIiwgb3JkZXIgPSBjKCJjaGlsZCIsICJhZHVsdCIpKQ0KDQpvYnNfc3RhdA0KYGBgDQoNCmBgYHtyfQ0KIyB0LXRlc3QgZm9yIGNvbXBhcmlzb24NCnN0YWNrX292ZXJmbG93ICU+JQ0KICB0X3Rlc3QoY29udmVydGVkX2NvbXAgfmFnZV9maXJzdF9jb2RlX2N1dCwgb3JkZXIgPSBjKCJjaGlsZCIsICJhZHVsdCIpLCBhbHRlcm5hdGl2ZSA9ICJncmVhdGVyIikNCmBgYA0KDQojIyMgKipHZXQgdGhlIHAtdmFsdWUqKg0KDQpGaW5hbGx5LCB3ZSBnZXQgdGhlIHAtdmFsdWUgZnJvbSB0aGUgbnVsbCBkaXN0cmlidXRpb24gYW5kIG9ic2VydmVkIHN0YXRpc3RpYy4gVGhlIGRpcmVjdGlvbiBhcmd1bWVudCB0byBnZXRfcF92YWx1ZSBpcyB0aGUgc2FtZSBhcyB0aGUgYWx0ZXJuYXRpdmUgYXJndW1lbnQgaW4gdF90ZXN0LiBUaGUgcC12YWx1ZSBpcyAwLjAzNjIgcmF0aGVyIHRoYW4gMC4wMzA4DQoNCmBgYHtyfQ0KIyBTaW11bGF0aW9uLWJhc2VkIHBpcGVsaW5lDQpnZXRfcF92YWx1ZShudWxsX2Rpc3RuLCBvYnNfc3RhdCwgZGlyZWN0aW9uID0gImdyZWF0ZXIiKQ0KYGBgDQoNCmBgYHtyfQ0KIyB0LXRlc3QgZm9yIGNvbXBhcmlzb24NCnN0YWNrX292ZXJmbG93ICU+JQ0KICB0X3Rlc3QoY29udmVydGVkX2NvbXAgfiBhZ2VfZmlyc3RfY29kZV9jdXQsIG9yZGVyID0gYygiY2hpbGQiLCAiYWR1bHQiKSwgYWx0ZXJuYXRpdmUgPSAiZ3JlYXRlciIpDQpgYGANCg0KIyMjICoqUmFua3Mgb2YgdmVjdG9ycyoqDQoNCkNvbnNpZGVyIHRoaXMgbnVtZXJpYyB2ZWN0b3IsIHguIFRoZSBmaXJzdCB2YWx1ZSBvZiB4LCBvbmUsIGlzIHRoZSBzbWFsbGVzdC4gVGhlIHNlY29uZCB2YWx1ZSwgZmlmdGVlbiwgaXMgdGhlIGZpZnRoIHNtYWxsZXN0LiAqKlRoZXNlIG9yZGVyaW5ncyBmcm9tIHNtYWxsZXN0IHRvIGxhcmdlc3QgYXJlIGtub3duIGFzIHRoZSByYW5rcyBvZiB0aGUgZWxlbWVudHMgb2YgeCoqLiBZb3UgY2FuIGFjY2VzcyB0aGVtIHdpdGggdGhlIHJhbmsgZnVuY3Rpb24uIFlvdSBjYW4gYXZvaWQgYXNzdW1wdGlvbnMgYWJvdXQgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgZGF0YSBieSBwZXJmb3JtaW5nIGh5cG90aGVzaXMgdGVzdHMgb24gdGhlIHJhbmtzIG9mIGEgbnVtZXJpYyBpbnB1dC4gKioqVGhlIFdpbGNveG9uLU1hbm4tV2hpdG5leSoqKiB0ZXN0IGlzLCB2ZXJ5IHJvdWdobHkgc3BlYWtpbmcsIGEgdC10ZXN0IG9uIHJhbmtlZCBkYXRhLg0KDQpgYGB7cn0NCnggPSBjKDEsIDE1LCAzLCAxMCwgNikNCnJhbmsoeCkNCmBgYA0KDQojIyMgKipXaWxjb3hvbi1NYW5uLVdoaXRuZXkgdGVzdCoqDQoNCllvdSBjYW4gcnVuIGEgKioqV2lsY294b24tTWFubi1XaGl0bmV5KioqIHRlc3QgdXNpbmcgYHdpbGNveC50ZXN0KClgIGZyb20gYmFzZS1SLiAqKkl0IGFjY2VwdHMgYSBmb3JtdWxhIGFuZCBkYXRhIGFyZ3VtZW50KiosIHRob3VnaCB0aGVzZSBhcmUgc3dhcHBlZCBjb21wYXJlZCB0byB0aGUgaW5mZXIgZnVuY3Rpb25zLCBzbyB0aGV5IGFyZSBsZXNzIHBpcGUtZnJpZW5kbHkuIGFsdGVybmF0aXZlIHNldHMgdGhlIHR5cGUgb2YgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcywgYW5kIGNvcnJlY3QgZGV0ZXJtaW5lcyB3aGV0aGVyIG9yIG5vdCB0byBhcHBseSBhIGNvbnRpbnVpdHkgY29ycmVjdGlvbiB0byB0aGUgei1zY29yZXMuIFNpbmNlIHJhbmtzIGFyZSBpbnRlZ2VycyBhbmQgdGhlIG5vcm1hbCBkaXN0cmlidXRpb24gaXMgY29udGludW91cywgdGhpcyBjb3JyZWN0aW9uIGNhbiBpbXByb3ZlIHRoZSBhcHByb3hpbWF0aW9uLiBIb3dldmVyLCBmb3IgbGFyZ2Ugc2FtcGxlIHNpemVzIGl0cyBlZmZlY3QgaXMgdHJpdmlhbCBhbmQgbm90IG5lZWRlZC4gSGVyZSwgdGhlIHAtdmFsdWUgaXMgc2hvd24gYXMgbGVzcyB0aGFuIHR3byB0aW1lcyB0ZW4gdG8gdGhlIG1pbnVzIHNpeHRlZW4sIGxlc3MgdGhhbiB0aGUgc2lnbmlmaWNhbmNlIGxldmVsLg0KDQpeMV4gQWxzbyBrbm93biBhcyB0aGUgIldpbGNveG9uIHJhbmstc3VtIHRlc3QiIGFuZCB0aGUgIk1hbm4tV2hpdG5leSBVIHRlc3QiLg0KDQpgYGB7cn0NCndpbGNveC50ZXN0KGNvbnZlcnRlZF9jb21wIH4gYWdlX2ZpcnN0X2NvZGVfY3V0LCBkYXRhID0gc3RhY2tfb3ZlcmZsb3csIGFsdGVybmF0aXZlID0gImdyZWF0ZXIiLCBjb3JyZWN0ID0gRkFMU0UpDQpgYGANCg0KIyMjICoqS3J1c2thbC1XYWxsaXMgdGVzdCoqDQoNCkluIHRoZSBzYW1lIHdheSB0aGF0IEFOT1ZBIGV4dGVuZHMgdC10ZXN0cyB0byBtb3JlIHRoYW4gdHdvIGdyb3VwcywgdGhlICoqKktydXNrYWwtV2FsbGFjZSoqKiB0ZXN0IGV4dGVuZHMgdGhlICoqKldpbGNveG9uLU1hbm4tV2hpdG5leSoqKiB0byBtb3JlIHRoYW4gdHdvIGdyb3Vwcy4gVGhhdCBpcywgdGhlICoqKktydXNrYWwtV2FsbGFjZSoqKiB0ZXN0IGlzIGEgbm9uLXBhcmFtZXRyaWMgdmVyc2lvbiBvZiBBTk9WQS4gWW91IHBhc3MgYSBmb3JtdWxhIHdpdGggdGhlIG51bWVyaWNhbCB2YXJpYWJsZSBvbiB0aGUgbGVmdCBhbmQgdGhlIGNhdGVnb3JpY2FsIHZhcmlhYmxlIG9uIHRoZSByaWdodCwgYW5kIHNldCBkYXRhIHRvIHRoZSBzYW1wbGUgZGF0YSBmcmFtZS4gQWdhaW4sIHRoZSBwLXZhbHVlIGhlcmUgaXMgdmVyeSBzbWFsbC4NCg0KYGBge3J9DQprcnVza2FsLnRlc3QoY29udmVydGVkX2NvbXAgfiBqb2Jfc2F0LCBkYXRhID0gc3RhY2tfb3ZlcmZsb3cpDQpgYGANCg==