The lettuce dataset
In a previous tutorial, we analysed the dataset on
lettuce plants using ANOVA. However, it was not clear
if all the assumptions of ANOVA were met. Indeed, with
only 7 datapoints per group, it is very hard to assess
the assumptions of normality and equal variances.
Therefore, we will re-analyse the dataset by using the
non-parametric alternative to ANOVA, the Kruskal-Wallis test
.
We will first give a concise overview of what we saw in the
ANOVA analysis, which can be found in the
ANOVA_lettuce_plants.Rmd
file.
The researchers want to find out if biochar, compost and
a combination of both biochar and compost have an influence
on the growth of lettuce plants. To this end, they grew up
lettuce plants in a greenhouse. The pots were filled with
one of four soil types;
- Soil only (control)
- Soil supplemented with biochar (refoak)
- Soil supplemented with compost (compost)
- Soil supplemented with both biochar and compost (cobc)
The dataset freshweight_lettuce.txt
contains the freshweight
(in grams) for 28 lettuce plants (7 per condition).
Load the required libraries
library(tidyverse)
library(car)
## Warning: package 'car' was built under R version 4.4.1
Data import
lettuce <- read_csv("https://raw.githubusercontent.com/statOmics/PSLSData/main/freshweight_lettuce.txt")
# Take a glimpse at the data
glimpse(lettuce)
## Rows: 28
## Columns: 3
## $ id <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,…
## $ treatment <chr> "control", "control", "control", "control", "control", "co…
## $ freshweight <dbl> 38, 34, 41, 43, 43, 29, 38, 59, 64, 57, 56, 50, 64, 62, 38…
# treatment to factor
lettuce <- lettuce %>%
mutate(treatment = as.factor(treatment))
Data exploration
# Count the number of observations per treatment
table(lettuce$treatment)
##
## cobc compost control refoak
## 7 7 7 7
Now let’s make a boxplot displaying the freshweight
of each treatment condition:
lettuce %>%
ggplot(aes(x = treatment, y = freshweight, fill = treatment)) +
scale_fill_brewer(palette = "RdGy") +
theme_bw() +
geom_boxplot(outlier.shape = NA) +
geom_jitter(width = 0.2) +
ggtitle("Boxplot of the freshweigth for each treatment condition") +
ylab("freshweight (gram)") +
stat_summary(fun = mean, geom = "point", shape = 5, size = 3, color = "black", fill = "black")

Note that there are no clear outliers in the data.
We can see that the mean freshweight is very comparable
between the control and refoak treatments and between the
compost and cobc treatments. We can also see that the mean
freshweight is much higher in the cobc and control treatments
than in the control and refoak treatments. But is this
observed difference significant?
ANOVA
To study whether or not the observed difference between the
average freshweight values of the differentt treatment groups
are significant, we may perform an ANOVA.
Hypotheses
The null hypothesis of ANOVA states that:
The mean freshweigth is equal between the different treatment groups.
The alternative hypothesis of ANOVA states that:
The mean freshweigth for at least one treatment group is different
than the mean freshweight in at least one other treatment group.
Checking the assumptions of ANOVA
Before we may proceed with the analysis, we must make sure that all
assumptions for ANOVA are met. ANOVA has three assumptions:
- The observations are independent of each other (in all groups)
- The data (freshweigth) must be normally distributed (in all groups)
- The variability within all groups is similar
Assumption of independence
The first assumption is met; we started of with 28 lettuce plants and
we randomly submitted them to one of four treatment conditions. There
is no reason to believe that the plants display systematic differences
between ttreatment groups, other than the actual treatment.
Assumption of normality
For the second assumption, we must check normality in each group.
## get qqplots for each individual treatment group
par(mfrow = c(2, 2))
for (i in levels(lettuce$treatment)) {
qqPlot(subset(lettuce, treatment == i)$freshweight, main = i, ylab = "")
}

While in the ANOVA_lettuce_plants.Rmd
file we accepted
the assumption of normality, it must be noted that it is
tricky to assess the assumption with only 7 datapoints.
See ANOVA_lettuce_plants.Rmd
“` for more details on this.
Let’s say that here we decide not to assume normality.
Assumption of equal variances
We can check the assumption of equal variance with a boxplot:
lettuce %>%
ggplot(aes(x = treatment, y = freshweight, fill = treatment)) +
scale_fill_brewer(palette = "RdGy") +
theme_bw() +
geom_boxplot(outlier.shape = NA) +
geom_jitter(width = 0.2) +
ggtitle("Boxplot of the freshweigth for each treatment condition") +
ylab("freshweight (gram)") +
stat_summary(fun = mean, geom = "point", shape = 5, size = 3, color = "black", fill = "black")

As a measure of variability, we may take the height
of each boxplot’s box. This is the interval between
the 25% and 75% quantile. Here we can see that this
interval, as well as the length of the whiskers, is
approximately equal for most groups. However, the
variability of cobc does seem to be quite a bit larger
than the variability in the refoak group.
While we accepted the assumption of equal variances in the
ANOVA_lettuce_plants.Rmd
file, we will here reject the
assumption.
Not all assumptions for ANOVA are met. As such, we will rely
on the non-parametric alternative of ANOVA: the Kruskal-Wallis
test.
Kruskal-Wallis rank test
If we want to test for a difference in the median of the
different treatment groups, we have to assume a location shift,
saying that all treatment groups follow the same distribution,
but with a different median.
However, here, we might be not prepared for taking this assumption.
While the range and spread of the data is similar for most groups
(see boxplot), there is a quite a big difference between the IQR of
the refoak and cobc conditions.
When we reject the assuming the location shift, we can relax the
distributional assumptions even further and perform a test in terms
of probabilistic indices (see the Non_parametric_shrimps.Rmd
file).
With this Kruskal-Wallis test, we will test whether or not the chance
that a random value of one treatment group is larger than or equal to
(“\(\geq\)”) a random value of another treatment group is significantly
different from 50%.
Hypotheses
Null hypothesis:
\(H0\): The distribution of freshweights of lettuce plants are equal
for all treatment conditions.
Alternative hypothesis:
\(HA\): The chance that a random value of at least one treatment group
is larger than or equal to (“\(\geq\)”) a random value of at least
one other treatment group is significantly different from 50%.
Test
set.seed(1)
kwPerm <- kruskal_test(freshweight ~ treatment, lettuce,
distribution = approximate(nresample = 100000)
)
kwPerm
##
## Approximative Kruskal-Wallis Test
##
## data: freshweight by
## treatment (cobc, compost, control, refoak)
## chi-squared = 20.715, p-value < 1e-05
Note that here we are comparing the observed test statistic
(chi-squared = 20.715) with the test statistics derived from
an empirical distribution that was generated by taking 10.000
permutations of the original lettuce dataset.
We find an extremly significant (p < 1e-05) of the treatment
on the freshweight. On the 5% global significance level, we may
state that the chance that a random value of at least one treatment
group is larger than or equal to (“\(\geq\)”) a random value of at
least one other treatment group is significantly different from 50%.
Now, we will perform a post-hoc analysis to find out which specific
groups are different from each other.
Post-hoc analysis
We will perform a post-hoc analysis with pairwise Wilcoxon rank
sum test. As we did not want to assume the location shift, we
will interpret the outcome in terms of probabilistic indices.
Note that after the analysis, we will need to correct the acquired
p-values for multiple testing.
Hypotheses
For each pairwise test, we have the following hypotheses:
Null hopothesis:
\(H0\): The distribution of freshweights of lettuce plants are equal
for both treatment conditions.
Alternative hypothesis:
\(HA\): The chance that a random value of treatment group 1 is larger
than or equal to (“\(\geq\)”) a random value of treatment group 2
is significantly different from 50%.
Test
## initial attempt to perform the analysis
pairwise.wilcox.test(lettuce$freshweight, lettuce$treatment)
## Warning in wilcox.test.default(xi, xj, paired = paired, ...): cannot compute
## exact p-value with ties
## Warning in wilcox.test.default(xi, xj, paired = paired, ...): cannot compute
## exact p-value with ties
## Warning in wilcox.test.default(xi, xj, paired = paired, ...): cannot compute
## exact p-value with ties
## Warning in wilcox.test.default(xi, xj, paired = paired, ...): cannot compute
## exact p-value with ties
## Warning in wilcox.test.default(xi, xj, paired = paired, ...): cannot compute
## exact p-value with ties
## Warning in wilcox.test.default(xi, xj, paired = paired, ...): cannot compute
## exact p-value with ties
##
## Pairwise comparisons using Wilcoxon rank sum test with continuity correction
##
## data: lettuce$freshweight and lettuce$treatment
##
## cobc compost control
## compost 0.400 - -
## control 0.013 0.013 -
## refoak 0.013 0.013 0.400
##
## P value adjustment method: holm
We get the following warning message:
cannot compute exact p-value with ties
.
This is because the pairwise.wilcox.test()
use the
standard wilcox.test()
function. In the help file
of this function (?wilcox.test), we can read that in the
presence of ties in the data, the function will perform
an asymptotic test rather than an exact test.
Test (2)
If we do want to obtain exact p-values, we may use the
wilcox_test()
function from the coin
package for
each pairwise combination of treatments. The obtained
p-values must be corrected for multiple testing, e.g.
with the p.adjust()
function.
## caluclate the p-value for each treatment combination with wilcoxon_test
treatments <- levels(lettuce$treatment)
freshweight <- lettuce$freshweight
pvalues <- combn(treatments, 2, function(x) {
## Pairwise Wilcon test
test <- wilcox_test(freshweight ~ treatment, subset(lettuce, treatment %in% x), distribution = "exact")
## Get and store p-value of test
pvalue(test)
})
## Adjust for multiple testing
pvalues_holm <- p.adjust(pvalues, method = "holm")
## link the p-value with the correct pairwise test
names(pvalues_holm) <- combn(levels(lettuce$treatment), 2, paste, collapse = "_VS_")
pvalues_holm
## cobc_VS_compost cobc_VS_control cobc_VS_refoak compost_VS_control
## 0.393939394 0.005244755 0.003496503 0.003496503
## compost_VS_refoak control_VS_refoak
## 0.003496503 0.405594406
The exact p-values do indeed deviate from those calculated
with the pairwise.wilcox.test()
function. We will proceed
with the exact p-values.
Now we will compute the point estimation for the probabilistic
index (for each pairwise comparison). Note that we already
did this in the Non_parametric_shrimps.Rmd
file for a single comparison.
## Count the number of observations per group
nGroup <- table(lettuce$treatment)
## Compute the probabilistic index for each pairwise combination
treatments <- levels(lettuce$treatment)
probInd <- combn(treatments, 2, function(x) {
## Compute the U1 statistic
U1 <- wilcox.test(freshweight ~ treatment, subset(lettuce, treatment %in% x))$statistic
## Compute the probabilistic index
U1 / prod(nGroup[x])
})
## Warning in wilcox.test.default(x = DATA[[1L]], y = DATA[[2L]], ...): cannot
## compute exact p-value with ties
## Warning in wilcox.test.default(x = DATA[[1L]], y = DATA[[2L]], ...): cannot
## compute exact p-value with ties
## Warning in wilcox.test.default(x = DATA[[1L]], y = DATA[[2L]], ...): cannot
## compute exact p-value with ties
## Warning in wilcox.test.default(x = DATA[[1L]], y = DATA[[2L]], ...): cannot
## compute exact p-value with ties
## Warning in wilcox.test.default(x = DATA[[1L]], y = DATA[[2L]], ...): cannot
## compute exact p-value with ties
## Warning in wilcox.test.default(x = DATA[[1L]], y = DATA[[2L]], ...): cannot
## compute exact p-value with ties
## link the probabilistic index with the correct pairwise test
names(probInd) <- combn(levels(lettuce$treatment), 2, paste, collapse = "_VS_")
probInd
## cobc_VS_compost cobc_VS_control cobc_VS_refoak compost_VS_control
## 0.2857143 0.9795918 1.0000000 1.0000000
## compost_VS_refoak control_VS_refoak
## 1.0000000 0.6428571
We again see the same warning message. Here, this is not a
prblem, we are not interested in the p-values (which we
already computed), we only care about the probabilistic indices,
that are calculated from the U1 statistic. U1 is computed as
the number of times an observation of group 1 is larger than or
equal to an observation of group 2. This statistic is thus
defined even in the case of ties.
Conclusion
We find an extremly significant (p < 1e-05) of the treatment
on the freshweight. On the 5% global significance level, we may
state that the chance that a random value of at least one treatment
group is larger than or equal to (“\(\geq\)”) a random value of at
least one other treatment group is significantly different from 50%.
For the post-hoc analysis:
We find a highly significant difference in the distributions between
the compost treatment and the control treatment. The probability
that the freshweigth of plants grown in compost soil is higher than
or equal to (“\(\geq\)”) the freshweigth of plants grown in control
soil is 100%. This is highly significantly different from 50%
(adjusted p-value=0.003).
We find a highly significant difference in the distributions between
the cobc treatment and the control treatment. The probability
that the freshweigth of plants grown in compost soil is higher than
or equal to (“\(\geq\)”) the freshweigth of plants grown in control
soil is 98%. This is highly significantly different from 50%
(adjusted p-value=0.005).
We find a highly significant difference in the distributions between
the compost treatment and the refoak treatment. The probability
that the freshweigth of plants grown in compost soil is higher than
or equal to (“\(\geq\)”) the freshweigth of plants grown in control
soil is 100%. This is highly significantly different from 50%
(adjusted p-value=0.003).
We find a highly significant difference in the distributions between
the cobc treatment and the refoak treatment. The probability
that the freshweigth of plants grown in compost soil is higher than
or equal to (“\(\geq\)”) the freshweigth of plants grown in control
soil is 100%. This is highly significantly different from 50%
(adjusted p-value=0.003).
For the other contrast, we do not enough find evidence to suggest
significant differences between the treatment groups.
We may conclude that supplementing soil with compost or with
both compost and biochar has a positive effect on the freshweigth
of lettuce plants. Note that, qualitatively, these conclusion are
exactly the same as with the ANOVA analysis of the dataset in the
ANOVA_lettuce_plants.Rmd
file.
LS0tCnRpdGxlOiAiRXhlcmNpc2UgOS4yOiBOb24tcGFyYW1ldHJpYyBzdGF0aXN0aWNzIG9uIHRoZSBsZXR0dWNlIGRhdGFzZXQiCmF1dGhvcjogIkxpZXZlbiBDbGVtZW50IGFuZCBKZXJvZW4gR2lsaXMiCmRhdGU6ICJzdGF0T21pY3MsIEdoZW50IFVuaXZlcnNpdHkgKGh0dHBzOi8vc3RhdG9taWNzLmdpdGh1Yi5pbykiCi0tLQoKIyBUaGUgbGV0dHVjZSBkYXRhc2V0CgpJbiBhIHByZXZpb3VzIHR1dG9yaWFsLCB3ZSBhbmFseXNlZCB0aGUgZGF0YXNldCBvbgpsZXR0dWNlIHBsYW50cyB1c2luZyBBTk9WQS4gSG93ZXZlciwgaXQgd2FzIG5vdCBjbGVhcgppZiBhbGwgdGhlIGFzc3VtcHRpb25zIG9mIEFOT1ZBIHdlcmUgbWV0LiBJbmRlZWQsIHdpdGgKb25seSA3IGRhdGFwb2ludHMgcGVyIGdyb3VwLCBpdCBpcyB2ZXJ5IGhhcmQgdG8gYXNzZXNzCnRoZSBhc3N1bXB0aW9ucyBvZiBub3JtYWxpdHkgYW5kIGVxdWFsIHZhcmlhbmNlcy4KClRoZXJlZm9yZSwgd2Ugd2lsbCByZS1hbmFseXNlIHRoZSBkYXRhc2V0IGJ5IHVzaW5nIHRoZQpub24tcGFyYW1ldHJpYyBhbHRlcm5hdGl2ZSB0byBBTk9WQSwgdGhlIGBLcnVza2FsLVdhbGxpcyB0ZXN0YC4KV2Ugd2lsbCBmaXJzdCBnaXZlIGEgY29uY2lzZSBvdmVydmlldyBvZiB3aGF0IHdlIHNhdyBpbiB0aGUKQU5PVkEgYW5hbHlzaXMsIHdoaWNoIGNhbiBiZSBmb3VuZCBpbiB0aGUKYEFOT1ZBX2xldHR1Y2VfcGxhbnRzLlJtZGAgZmlsZS4KClRoZSByZXNlYXJjaGVycyB3YW50IHRvIGZpbmQgb3V0IGlmIGJpb2NoYXIsIGNvbXBvc3QgYW5kCmEgY29tYmluYXRpb24gb2YgYm90aCBiaW9jaGFyIGFuZCBjb21wb3N0IGhhdmUgYW4gaW5mbHVlbmNlCm9uIHRoZSBncm93dGggb2YgbGV0dHVjZSBwbGFudHMuIFRvIHRoaXMgZW5kLCB0aGV5IGdyZXcgdXAKbGV0dHVjZSBwbGFudHMgaW4gYSBncmVlbmhvdXNlLiBUaGUgcG90cyB3ZXJlIGZpbGxlZCB3aXRoCm9uZSBvZiBmb3VyIHNvaWwgdHlwZXM7CgoxLiBTb2lsIG9ubHkgKGNvbnRyb2wpCjIuIFNvaWwgc3VwcGxlbWVudGVkIHdpdGggYmlvY2hhciAocmVmb2FrKQozLiBTb2lsIHN1cHBsZW1lbnRlZCB3aXRoIGNvbXBvc3QgKGNvbXBvc3QpCjQuIFNvaWwgc3VwcGxlbWVudGVkIHdpdGggYm90aCBiaW9jaGFyIGFuZCBjb21wb3N0IChjb2JjKQoKVGhlIGRhdGFzZXQgYGZyZXNod2VpZ2h0X2xldHR1Y2UudHh0YCBjb250YWlucyB0aGUgZnJlc2h3ZWlnaHQKKGluIGdyYW1zKSBmb3IgMjggbGV0dHVjZSBwbGFudHMgKDcgcGVyIGNvbmRpdGlvbikuCgpMb2FkIHRoZSByZXF1aXJlZCBsaWJyYXJpZXMKCmBgYHtyLCBtZXNzYWdlID0gRkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGNhcikKbGlicmFyeShjb2luKQpgYGAKCiMgRGF0YSBpbXBvcnQKCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQpsZXR0dWNlIDwtIHJlYWRfY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vc3RhdE9taWNzL1BTTFNEYXRhL21haW4vZnJlc2h3ZWlnaHRfbGV0dHVjZS50eHQiKQojIFRha2UgYSBnbGltcHNlIGF0IHRoZSBkYXRhCmdsaW1wc2UobGV0dHVjZSkKYGBgCgpgYGB7cn0KIyB0cmVhdG1lbnQgdG8gZmFjdG9yCmxldHR1Y2UgPC0gbGV0dHVjZSAlPiUKICBtdXRhdGUodHJlYXRtZW50ID0gYXMuZmFjdG9yKHRyZWF0bWVudCkpCmBgYAoKIyBEYXRhIGV4cGxvcmF0aW9uCgpgYGB7cn0KIyBDb3VudCB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBwZXIgdHJlYXRtZW50CnRhYmxlKGxldHR1Y2UkdHJlYXRtZW50KQpgYGAKCk5vdyBsZXQncyBtYWtlIGEgYm94cGxvdCBkaXNwbGF5aW5nIHRoZSBmcmVzaHdlaWdodApvZiBlYWNoIHRyZWF0bWVudCBjb25kaXRpb246CgpgYGB7cn0KbGV0dHVjZSAlPiUKICBnZ3Bsb3QoYWVzKHggPSB0cmVhdG1lbnQsIHkgPSBmcmVzaHdlaWdodCwgZmlsbCA9IHRyZWF0bWVudCkpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlJkR3kiKSArCiAgdGhlbWVfYncoKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKwogIGdlb21faml0dGVyKHdpZHRoID0gMC4yKSArCiAgZ2d0aXRsZSgiQm94cGxvdCBvZiB0aGUgZnJlc2h3ZWlndGggZm9yIGVhY2ggdHJlYXRtZW50IGNvbmRpdGlvbiIpICsKICB5bGFiKCJmcmVzaHdlaWdodCAoZ3JhbSkiKSArCiAgc3RhdF9zdW1tYXJ5KGZ1biA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDUsIHNpemUgPSAzLCBjb2xvciA9ICJibGFjayIsIGZpbGwgPSAiYmxhY2siKQpgYGAKCk5vdGUgdGhhdCB0aGVyZSBhcmUgbm8gY2xlYXIgb3V0bGllcnMgaW4gdGhlIGRhdGEuCldlIGNhbiBzZWUgdGhhdCB0aGUgbWVhbiBmcmVzaHdlaWdodCBpcyB2ZXJ5IGNvbXBhcmFibGUKYmV0d2VlbiB0aGUgY29udHJvbCBhbmQgcmVmb2FrIHRyZWF0bWVudHMgYW5kIGJldHdlZW4gdGhlCmNvbXBvc3QgYW5kIGNvYmMgdHJlYXRtZW50cy4gV2UgY2FuIGFsc28gc2VlIHRoYXQgdGhlIG1lYW4KZnJlc2h3ZWlnaHQgaXMgbXVjaCBoaWdoZXIgaW4gdGhlIGNvYmMgYW5kIGNvbnRyb2wgdHJlYXRtZW50cwp0aGFuIGluIHRoZSBjb250cm9sIGFuZCByZWZvYWsgdHJlYXRtZW50cy4gQnV0IGlzIHRoaXMKb2JzZXJ2ZWQgZGlmZmVyZW5jZSBzaWduaWZpY2FudD8KCiMgQU5PVkEKClRvIHN0dWR5IHdoZXRoZXIgb3Igbm90IHRoZSBvYnNlcnZlZCBkaWZmZXJlbmNlIGJldHdlZW4gdGhlCmF2ZXJhZ2UgZnJlc2h3ZWlnaHQgdmFsdWVzIG9mIHRoZSBkaWZmZXJlbnR0IHRyZWF0bWVudCBncm91cHMKYXJlIHNpZ25pZmljYW50LCB3ZSBtYXkgcGVyZm9ybSBhbiBBTk9WQS4KCiMjIEh5cG90aGVzZXMKClRoZSBudWxsIGh5cG90aGVzaXMgb2YgQU5PVkEgc3RhdGVzIHRoYXQ6ClRoZSBtZWFuIGZyZXNod2VpZ3RoIGlzIGVxdWFsIGJldHdlZW4gdGhlIGRpZmZlcmVudCB0cmVhdG1lbnQgZ3JvdXBzLgoKVGhlIGFsdGVybmF0aXZlIGh5cG90aGVzaXMgb2YgQU5PVkEgc3RhdGVzIHRoYXQ6ClRoZSBtZWFuIGZyZXNod2VpZ3RoIGZvciBhdCBsZWFzdCBvbmUgdHJlYXRtZW50IGdyb3VwIGlzIGRpZmZlcmVudAp0aGFuIHRoZSBtZWFuIGZyZXNod2VpZ2h0IGluIGF0IGxlYXN0IG9uZSBvdGhlciB0cmVhdG1lbnQgZ3JvdXAuCgojIyBDaGVja2luZyB0aGUgYXNzdW1wdGlvbnMgb2YgQU5PVkEKCkJlZm9yZSB3ZSBtYXkgcHJvY2VlZCB3aXRoIHRoZSBhbmFseXNpcywgd2UgbXVzdCBtYWtlIHN1cmUgdGhhdCBhbGwKYXNzdW1wdGlvbnMgZm9yIEFOT1ZBIGFyZSBtZXQuIEFOT1ZBIGhhcyB0aHJlZSBhc3N1bXB0aW9uczoKCjEuIFRoZSBvYnNlcnZhdGlvbnMgYXJlIGluZGVwZW5kZW50IG9mIGVhY2ggb3RoZXIgKGluIGFsbCBncm91cHMpCjIuIFRoZSBkYXRhIChmcmVzaHdlaWd0aCkgbXVzdCBiZSBub3JtYWxseSBkaXN0cmlidXRlZCAoaW4gYWxsIGdyb3VwcykKMy4gVGhlIHZhcmlhYmlsaXR5IHdpdGhpbiBhbGwgZ3JvdXBzIGlzIHNpbWlsYXIKCiMjIyBBc3N1bXB0aW9uIG9mIGluZGVwZW5kZW5jZQoKVGhlIGZpcnN0IGFzc3VtcHRpb24gaXMgbWV0OyB3ZSBzdGFydGVkIG9mIHdpdGggMjggbGV0dHVjZSBwbGFudHMgYW5kCndlIHJhbmRvbWx5IHN1Ym1pdHRlZCB0aGVtIHRvIG9uZSBvZiBmb3VyIHRyZWF0bWVudCBjb25kaXRpb25zLiBUaGVyZQppcyBubyByZWFzb24gdG8gYmVsaWV2ZSB0aGF0IHRoZSBwbGFudHMgZGlzcGxheSBzeXN0ZW1hdGljIGRpZmZlcmVuY2VzCmJldHdlZW4gdHRyZWF0bWVudCBncm91cHMsIG90aGVyIHRoYW4gdGhlIGFjdHVhbCB0cmVhdG1lbnQuCgojIyMgQXNzdW1wdGlvbiBvZiBub3JtYWxpdHkKCkZvciB0aGUgc2Vjb25kIGFzc3VtcHRpb24sIHdlIG11c3QgY2hlY2sgbm9ybWFsaXR5IGluIGVhY2ggZ3JvdXAuCgpgYGB7cn0KIyMgZ2V0IHFxcGxvdHMgZm9yIGVhY2ggaW5kaXZpZHVhbCB0cmVhdG1lbnQgZ3JvdXAKcGFyKG1mcm93ID0gYygyLCAyKSkKZm9yIChpIGluIGxldmVscyhsZXR0dWNlJHRyZWF0bWVudCkpIHsKICBxcVBsb3Qoc3Vic2V0KGxldHR1Y2UsIHRyZWF0bWVudCA9PSBpKSRmcmVzaHdlaWdodCwgbWFpbiA9IGksIHlsYWIgPSAiIikKfQpgYGAKCldoaWxlIGluIHRoZSBgQU5PVkFfbGV0dHVjZV9wbGFudHMuUm1kYCBmaWxlIHdlIGFjY2VwdGVkCnRoZSBhc3N1bXB0aW9uIG9mIG5vcm1hbGl0eSwgaXQgbXVzdCBiZSBub3RlZCB0aGF0IGl0IGlzCnRyaWNreSB0byBhc3Nlc3MgdGhlIGFzc3VtcHRpb24gd2l0aCBvbmx5IDcgZGF0YXBvaW50cy4KU2VlIGBBTk9WQV9sZXR0dWNlX3BsYW50cy5SbWRgImAgZm9yIG1vcmUgZGV0YWlscyBvbiB0aGlzLgoKKipMZXQncyBzYXkgdGhhdCBoZXJlIHdlIGRlY2lkZSBub3QgdG8gYXNzdW1lIG5vcm1hbGl0eS4qKgoKIyMjIEFzc3VtcHRpb24gb2YgZXF1YWwgdmFyaWFuY2VzCgpXZSBjYW4gY2hlY2sgdGhlIGFzc3VtcHRpb24gb2YgZXF1YWwgdmFyaWFuY2Ugd2l0aCBhIGJveHBsb3Q6CgpgYGB7cn0KbGV0dHVjZSAlPiUKICBnZ3Bsb3QoYWVzKHggPSB0cmVhdG1lbnQsIHkgPSBmcmVzaHdlaWdodCwgZmlsbCA9IHRyZWF0bWVudCkpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlJkR3kiKSArCiAgdGhlbWVfYncoKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKwogIGdlb21faml0dGVyKHdpZHRoID0gMC4yKSArCiAgZ2d0aXRsZSgiQm94cGxvdCBvZiB0aGUgZnJlc2h3ZWlndGggZm9yIGVhY2ggdHJlYXRtZW50IGNvbmRpdGlvbiIpICsKICB5bGFiKCJmcmVzaHdlaWdodCAoZ3JhbSkiKSArCiAgc3RhdF9zdW1tYXJ5KGZ1biA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDUsIHNpemUgPSAzLCBjb2xvciA9ICJibGFjayIsIGZpbGwgPSAiYmxhY2siKQpgYGAKCkFzIGEgbWVhc3VyZSBvZiB2YXJpYWJpbGl0eSwgd2UgbWF5IHRha2UgdGhlIGhlaWdodApvZiBlYWNoIGJveHBsb3QncyBib3guIFRoaXMgaXMgdGhlIGludGVydmFsIGJldHdlZW4KdGhlIDI1JSBhbmQgNzUlIHF1YW50aWxlLiBIZXJlIHdlIGNhbiBzZWUgdGhhdCB0aGlzCmludGVydmFsLCBhcyB3ZWxsIGFzIHRoZSBsZW5ndGggb2YgdGhlIHdoaXNrZXJzLCBpcwphcHByb3hpbWF0ZWx5IGVxdWFsIGZvciBtb3N0IGdyb3Vwcy4gSG93ZXZlciwgdGhlCnZhcmlhYmlsaXR5IG9mIGNvYmMgZG9lcyBzZWVtIHRvIGJlIHF1aXRlIGEgYml0IGxhcmdlcgp0aGFuIHRoZSB2YXJpYWJpbGl0eSBpbiB0aGUgcmVmb2FrIGdyb3VwLgoKKipXaGlsZSB3ZSBhY2NlcHRlZCB0aGUgYXNzdW1wdGlvbiBvZiBlcXVhbCB2YXJpYW5jZXMgaW4gdGhlKioKKipgQU5PVkFfbGV0dHVjZV9wbGFudHMuUm1kYCBmaWxlLCB3ZSB3aWxsIGhlcmUgcmVqZWN0IHRoZSoqCioqYXNzdW1wdGlvbi4qKgoKTm90IGFsbCBhc3N1bXB0aW9ucyBmb3IgQU5PVkEgYXJlIG1ldC4gQXMgc3VjaCwgd2Ugd2lsbCByZWx5Cm9uIHRoZSBub24tcGFyYW1ldHJpYyBhbHRlcm5hdGl2ZSBvZiBBTk9WQTogdGhlIEtydXNrYWwtV2FsbGlzCnRlc3QuCgojIEtydXNrYWwtV2FsbGlzIHJhbmsgdGVzdAoKSWYgd2Ugd2FudCB0byB0ZXN0IGZvciBhIGRpZmZlcmVuY2UgaW4gdGhlIG1lZGlhbiBvZiB0aGUKZGlmZmVyZW50IHRyZWF0bWVudCBncm91cHMsIHdlIGhhdmUgdG8gKiphc3N1bWUgYSBsb2NhdGlvbiBzaGlmdCoqLApzYXlpbmcgdGhhdCBhbGwgdHJlYXRtZW50IGdyb3VwcyBmb2xsb3cgdGhlIHNhbWUgZGlzdHJpYnV0aW9uLApidXQgd2l0aCBhIGRpZmZlcmVudCBtZWRpYW4uCgpIb3dldmVyLCBoZXJlLCB3ZSBtaWdodCBiZSAqKm5vdCBwcmVwYXJlZCBmb3IgdGFraW5nIHRoaXMgYXNzdW1wdGlvbioqLgpXaGlsZSB0aGUgcmFuZ2UgYW5kIHNwcmVhZCBvZiB0aGUgZGF0YSBpcyBzaW1pbGFyIGZvciBtb3N0IGdyb3Vwcwooc2VlIGJveHBsb3QpLCB0aGVyZSBpcyBhIHF1aXRlIGEgYmlnIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgSVFSIG9mCnRoZSByZWZvYWsgYW5kIGNvYmMgY29uZGl0aW9ucy4KCldoZW4gd2UgcmVqZWN0IHRoZSBhc3N1bWluZyB0aGUgbG9jYXRpb24gc2hpZnQsIHdlIGNhbiByZWxheCB0aGUKZGlzdHJpYnV0aW9uYWwgYXNzdW1wdGlvbnMgZXZlbiBmdXJ0aGVyIGFuZCBwZXJmb3JtIGEgdGVzdCBpbiB0ZXJtcwpvZiBwcm9iYWJpbGlzdGljIGluZGljZXMgKHNlZSB0aGUgYE5vbl9wYXJhbWV0cmljX3NocmltcHMuUm1kYCBmaWxlKS4KCldpdGggdGhpcyBLcnVza2FsLVdhbGxpcyB0ZXN0LCB3ZSB3aWxsIHRlc3Qgd2hldGhlciBvciBub3QgdGhlIGNoYW5jZQp0aGF0IGEgcmFuZG9tIHZhbHVlIG9mIG9uZSB0cmVhdG1lbnQgZ3JvdXAgaXMgbGFyZ2VyIHRoYW4gb3IgZXF1YWwgdG8KKCIkXGdlcSQiKSBhIHJhbmRvbSB2YWx1ZSBvZiBhbm90aGVyIHRyZWF0bWVudCBncm91cCBpcyBzaWduaWZpY2FudGx5CmRpZmZlcmVudCBmcm9tIDUwJS4KCiMjIEh5cG90aGVzZXMKCi0gTnVsbCBoeXBvdGhlc2lzOgokSDAkOiBUaGUgZGlzdHJpYnV0aW9uIG9mIGZyZXNod2VpZ2h0cyBvZiBsZXR0dWNlIHBsYW50cyBhcmUgZXF1YWwKZm9yIGFsbCB0cmVhdG1lbnQgY29uZGl0aW9ucy4KCi0gQWx0ZXJuYXRpdmUgaHlwb3RoZXNpczoKJEhBJDogVGhlIGNoYW5jZSB0aGF0IGEgcmFuZG9tIHZhbHVlIG9mIGF0IGxlYXN0IG9uZSB0cmVhdG1lbnQgZ3JvdXAKaXMgbGFyZ2VyIHRoYW4gb3IgZXF1YWwgdG8gKCIkXGdlcSQiKSBhIHJhbmRvbSB2YWx1ZSBvZiBhdCBsZWFzdApvbmUgb3RoZXIgdHJlYXRtZW50IGdyb3VwIGlzIHNpZ25pZmljYW50bHkgZGlmZmVyZW50IGZyb20gNTAlLgoKIyMgVGVzdAoKYGBge3J9CnNldC5zZWVkKDEpCmt3UGVybSA8LSBrcnVza2FsX3Rlc3QoZnJlc2h3ZWlnaHQgfiB0cmVhdG1lbnQsIGxldHR1Y2UsCiAgZGlzdHJpYnV0aW9uID0gYXBwcm94aW1hdGUobnJlc2FtcGxlID0gMTAwMDAwKQopCmt3UGVybQpgYGAKCk5vdGUgdGhhdCBoZXJlIHdlIGFyZSBjb21wYXJpbmcgdGhlIG9ic2VydmVkIHRlc3Qgc3RhdGlzdGljCihjaGktc3F1YXJlZCA9IGByIGZvcm1hdChrd1Blcm1Ac3RhdGlzdGljQHRlc3RzdGF0aXN0aWMsIGRpZ2l0cz01KWApIHdpdGggdGhlIHRlc3Qgc3RhdGlzdGljcyBkZXJpdmVkIGZyb20KYW4gZW1waXJpY2FsIGRpc3RyaWJ1dGlvbiB0aGF0IHdhcyBnZW5lcmF0ZWQgYnkgdGFraW5nIDEwLjAwMApwZXJtdXRhdGlvbnMgb2YgdGhlIG9yaWdpbmFsIGxldHR1Y2UgZGF0YXNldC4KCldlIGZpbmQgYW4gZXh0cmVtbHkgc2lnbmlmaWNhbnQgKHAgPCAxZS0wNSkgb2YgdGhlIHRyZWF0bWVudApvbiB0aGUgZnJlc2h3ZWlnaHQuIE9uIHRoZSA1JSBnbG9iYWwgc2lnbmlmaWNhbmNlIGxldmVsLCB3ZSBtYXkKc3RhdGUgdGhhdCB0aGUgY2hhbmNlIHRoYXQgYSByYW5kb20gdmFsdWUgb2YgYXQgbGVhc3Qgb25lIHRyZWF0bWVudApncm91cCBpcyBsYXJnZXIgdGhhbiBvciBlcXVhbCB0byAoIiRcZ2VxJCIpIGEgcmFuZG9tIHZhbHVlIG9mIGF0CmxlYXN0IG9uZSBvdGhlciB0cmVhdG1lbnQgZ3JvdXAgaXMgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgZnJvbSA1MCUuCgpOb3csIHdlIHdpbGwgcGVyZm9ybSBhIHBvc3QtaG9jIGFuYWx5c2lzIHRvIGZpbmQgb3V0IHdoaWNoIHNwZWNpZmljCmdyb3VwcyBhcmUgZGlmZmVyZW50IGZyb20gZWFjaCBvdGhlci4KCiMgUG9zdC1ob2MgYW5hbHlzaXMKCldlIHdpbGwgcGVyZm9ybSBhIHBvc3QtaG9jIGFuYWx5c2lzIHdpdGggcGFpcndpc2UgV2lsY294b24gcmFuawpzdW0gdGVzdC4gQXMgd2UgZGlkIG5vdCB3YW50IHRvIGFzc3VtZSB0aGUgbG9jYXRpb24gc2hpZnQsIHdlCndpbGwgaW50ZXJwcmV0IHRoZSBvdXRjb21lIGluIHRlcm1zIG9mIHByb2JhYmlsaXN0aWMgaW5kaWNlcy4KTm90ZSB0aGF0IGFmdGVyIHRoZSBhbmFseXNpcywgd2Ugd2lsbCBuZWVkIHRvIGNvcnJlY3QgdGhlIGFjcXVpcmVkCnAtdmFsdWVzIGZvciBtdWx0aXBsZSB0ZXN0aW5nLgoKIyMgSHlwb3RoZXNlcwoKRm9yIGVhY2ggcGFpcndpc2UgdGVzdCwgd2UgaGF2ZSB0aGUgZm9sbG93aW5nIGh5cG90aGVzZXM6CgotIE51bGwgaG9wb3RoZXNpczoKJEgwJDogVGhlIGRpc3RyaWJ1dGlvbiBvZiBmcmVzaHdlaWdodHMgb2YgbGV0dHVjZSBwbGFudHMgYXJlIGVxdWFsCmZvciBib3RoIHRyZWF0bWVudCBjb25kaXRpb25zLgoKLSBBbHRlcm5hdGl2ZSBoeXBvdGhlc2lzOgokSEEkOiBUaGUgY2hhbmNlIHRoYXQgYSByYW5kb20gdmFsdWUgb2YgdHJlYXRtZW50IGdyb3VwIDEgaXMgbGFyZ2VyCnRoYW4gb3IgZXF1YWwgdG8gKCIkXGdlcSQiKSBhIHJhbmRvbSB2YWx1ZSBvZiB0cmVhdG1lbnQgZ3JvdXAgMgppcyBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBmcm9tIDUwJS4KCiMjIFRlc3QKCmBgYHtyfQojIyBpbml0aWFsIGF0dGVtcHQgdG8gcGVyZm9ybSB0aGUgYW5hbHlzaXMKcGFpcndpc2Uud2lsY294LnRlc3QobGV0dHVjZSRmcmVzaHdlaWdodCwgbGV0dHVjZSR0cmVhdG1lbnQpCmBgYAoKV2UgZ2V0IHRoZSBmb2xsb3dpbmcgd2FybmluZyBtZXNzYWdlOgpgY2Fubm90IGNvbXB1dGUgZXhhY3QgcC12YWx1ZSB3aXRoIHRpZXNgLgoKVGhpcyBpcyBiZWNhdXNlIHRoZSBgcGFpcndpc2Uud2lsY294LnRlc3QoKWAgdXNlIHRoZQpzdGFuZGFyZCBgd2lsY294LnRlc3QoKWAgZnVuY3Rpb24uIEluIHRoZSBoZWxwIGZpbGUKb2YgdGhpcyBmdW5jdGlvbiAoP3dpbGNveC50ZXN0KSwgd2UgY2FuIHJlYWQgdGhhdCBpbiB0aGUKcHJlc2VuY2Ugb2YgdGllcyBpbiB0aGUgZGF0YSwgdGhlIGZ1bmN0aW9uIHdpbGwgcGVyZm9ybQphbiBhc3ltcHRvdGljIHRlc3QgcmF0aGVyIHRoYW4gYW4gZXhhY3QgdGVzdC4KCiMjIFRlc3QgKDIpCgpJZiB3ZSBkbyB3YW50IHRvIG9idGFpbiBleGFjdCBwLXZhbHVlcywgd2UgbWF5IHVzZSB0aGUKYHdpbGNveF90ZXN0KClgIGZ1bmN0aW9uIGZyb20gdGhlIGBjb2luYCBwYWNrYWdlIGZvcgplYWNoIHBhaXJ3aXNlIGNvbWJpbmF0aW9uIG9mIHRyZWF0bWVudHMuIFRoZSBvYnRhaW5lZApwLXZhbHVlcyBtdXN0IGJlIGNvcnJlY3RlZCBmb3IgbXVsdGlwbGUgdGVzdGluZywgZS5nLgp3aXRoIHRoZSBgcC5hZGp1c3QoKWAgZnVuY3Rpb24uCgpgYGB7cn0KIyMgY2FsdWNsYXRlIHRoZSBwLXZhbHVlIGZvciBlYWNoIHRyZWF0bWVudCBjb21iaW5hdGlvbiB3aXRoIHdpbGNveG9uX3Rlc3QKdHJlYXRtZW50cyA8LSBsZXZlbHMobGV0dHVjZSR0cmVhdG1lbnQpCmZyZXNod2VpZ2h0IDwtIGxldHR1Y2UkZnJlc2h3ZWlnaHQKCnB2YWx1ZXMgPC0gY29tYm4odHJlYXRtZW50cywgMiwgZnVuY3Rpb24oeCkgewoKICAjIyBQYWlyd2lzZSBXaWxjb24gdGVzdAogIHRlc3QgPC0gd2lsY294X3Rlc3QoZnJlc2h3ZWlnaHQgfiB0cmVhdG1lbnQsIHN1YnNldChsZXR0dWNlLCB0cmVhdG1lbnQgJWluJSB4KSwgZGlzdHJpYnV0aW9uID0gImV4YWN0IikKCiAgIyMgR2V0IGFuZCBzdG9yZSBwLXZhbHVlIG9mIHRlc3QKICBwdmFsdWUodGVzdCkKfSkKCiMjIEFkanVzdCBmb3IgbXVsdGlwbGUgdGVzdGluZwpwdmFsdWVzX2hvbG0gPC0gcC5hZGp1c3QocHZhbHVlcywgbWV0aG9kID0gImhvbG0iKQoKIyMgbGluayB0aGUgcC12YWx1ZSB3aXRoIHRoZSBjb3JyZWN0IHBhaXJ3aXNlIHRlc3QKbmFtZXMocHZhbHVlc19ob2xtKSA8LSBjb21ibihsZXZlbHMobGV0dHVjZSR0cmVhdG1lbnQpLCAyLCBwYXN0ZSwgY29sbGFwc2UgPSAiX1ZTXyIpCnB2YWx1ZXNfaG9sbQpgYGAKClRoZSBleGFjdCBwLXZhbHVlcyBkbyBpbmRlZWQgZGV2aWF0ZSBmcm9tIHRob3NlIGNhbGN1bGF0ZWQKd2l0aCB0aGUgYHBhaXJ3aXNlLndpbGNveC50ZXN0KClgIGZ1bmN0aW9uLiBXZSB3aWxsIHByb2NlZWQKd2l0aCB0aGUgZXhhY3QgcC12YWx1ZXMuCgpOb3cgd2Ugd2lsbCBjb21wdXRlIHRoZSBwb2ludCBlc3RpbWF0aW9uIGZvciB0aGUgcHJvYmFiaWxpc3RpYwppbmRleCAoZm9yIGVhY2ggcGFpcndpc2UgY29tcGFyaXNvbikuIE5vdGUgdGhhdCB3ZSBhbHJlYWR5CmRpZCB0aGlzIGluIHRoZSBgTm9uX3BhcmFtZXRyaWNfc2hyaW1wcy5SbWRgIGZpbGUgZm9yIGEgc2luZ2xlIGNvbXBhcmlzb24uCgpgYGB7cn0KIyMgQ291bnQgdGhlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgcGVyIGdyb3VwCm5Hcm91cCA8LSB0YWJsZShsZXR0dWNlJHRyZWF0bWVudCkKCiMjIENvbXB1dGUgdGhlIHByb2JhYmlsaXN0aWMgaW5kZXggZm9yIGVhY2ggcGFpcndpc2UgY29tYmluYXRpb24KdHJlYXRtZW50cyA8LSBsZXZlbHMobGV0dHVjZSR0cmVhdG1lbnQpCgpwcm9iSW5kIDwtIGNvbWJuKHRyZWF0bWVudHMsIDIsIGZ1bmN0aW9uKHgpIHsKICAjIyBDb21wdXRlIHRoZSBVMSBzdGF0aXN0aWMKICBVMSA8LSB3aWxjb3gudGVzdChmcmVzaHdlaWdodCB+IHRyZWF0bWVudCwgc3Vic2V0KGxldHR1Y2UsIHRyZWF0bWVudCAlaW4lIHgpKSRzdGF0aXN0aWMKCiAgIyMgQ29tcHV0ZSB0aGUgcHJvYmFiaWxpc3RpYyBpbmRleAogIFUxIC8gcHJvZChuR3JvdXBbeF0pCn0pCgojIyBsaW5rIHRoZSBwcm9iYWJpbGlzdGljIGluZGV4IHdpdGggdGhlIGNvcnJlY3QgcGFpcndpc2UgdGVzdApuYW1lcyhwcm9iSW5kKSA8LSBjb21ibihsZXZlbHMobGV0dHVjZSR0cmVhdG1lbnQpLCAyLCBwYXN0ZSwgY29sbGFwc2UgPSAiX1ZTXyIpCnByb2JJbmQKYGBgCgpXZSBhZ2FpbiBzZWUgdGhlIHNhbWUgd2FybmluZyBtZXNzYWdlLiBIZXJlLCB0aGlzIGlzIG5vdCBhCnByYmxlbSwgd2UgYXJlIG5vdCBpbnRlcmVzdGVkIGluIHRoZSBwLXZhbHVlcyAod2hpY2ggd2UKYWxyZWFkeSBjb21wdXRlZCksIHdlIG9ubHkgY2FyZSBhYm91dCB0aGUgcHJvYmFiaWxpc3RpYyBpbmRpY2VzLAp0aGF0IGFyZSBjYWxjdWxhdGVkIGZyb20gdGhlIFUxIHN0YXRpc3RpYy4gVTEgaXMgY29tcHV0ZWQgYXMKdGhlIG51bWJlciBvZiB0aW1lcyBhbiBvYnNlcnZhdGlvbiBvZiBncm91cCAxIGlzIGxhcmdlciB0aGFuIG9yCmVxdWFsIHRvIGFuIG9ic2VydmF0aW9uIG9mIGdyb3VwIDIuIFRoaXMgc3RhdGlzdGljIGlzIHRodXMKZGVmaW5lZCBldmVuIGluIHRoZSBjYXNlIG9mIHRpZXMuCgojIENvbmNsdXNpb24KCldlIGZpbmQgYW4gZXh0cmVtbHkgc2lnbmlmaWNhbnQgKHAgPCAxZS0wNSkgb2YgdGhlIHRyZWF0bWVudApvbiB0aGUgZnJlc2h3ZWlnaHQuIE9uIHRoZSA1JSBnbG9iYWwgc2lnbmlmaWNhbmNlIGxldmVsLCB3ZSBtYXkKc3RhdGUgdGhhdCB0aGUgY2hhbmNlIHRoYXQgYSByYW5kb20gdmFsdWUgb2YgYXQgbGVhc3Qgb25lIHRyZWF0bWVudApncm91cCAgaXMgbGFyZ2VyIHRoYW4gb3IgZXF1YWwgdG8gKCIkXGdlcSQiKSBhIHJhbmRvbSB2YWx1ZSBvZiBhdApsZWFzdCBvbmUgb3RoZXIgdHJlYXRtZW50IGdyb3VwIGlzIHNpZ25pZmljYW50bHkgZGlmZmVyZW50IGZyb20gNTAlLgoKRm9yIHRoZSBwb3N0LWhvYyBhbmFseXNpczoKCi0gV2UgZmluZCBhIGhpZ2hseSBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGluIHRoZSBkaXN0cmlidXRpb25zIGJldHdlZW4KdGhlIGNvbXBvc3QgdHJlYXRtZW50IGFuZCB0aGUgY29udHJvbCB0cmVhdG1lbnQuIFRoZSBwcm9iYWJpbGl0eQp0aGF0IHRoZSBmcmVzaHdlaWd0aCBvZiBwbGFudHMgZ3Jvd24gaW4gY29tcG9zdCBzb2lsIGlzIGhpZ2hlciB0aGFuCm9yIGVxdWFsIHRvICgiJFxnZXEkIikgdGhlIGZyZXNod2VpZ3RoIG9mIHBsYW50cyBncm93biBpbiBjb250cm9sCnNvaWwgaXMgMTAwJS4gVGhpcyBpcyBoaWdobHkgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgZnJvbSA1MCUKKGFkanVzdGVkIHAtdmFsdWU9MC4wMDMpLgoKLSBXZSBmaW5kIGEgaGlnaGx5IHNpZ25pZmljYW50IGRpZmZlcmVuY2UgaW4gdGhlIGRpc3RyaWJ1dGlvbnMgYmV0d2Vlbgp0aGUgY29iYyB0cmVhdG1lbnQgYW5kIHRoZSBjb250cm9sIHRyZWF0bWVudC4gVGhlIHByb2JhYmlsaXR5CnRoYXQgdGhlIGZyZXNod2VpZ3RoIG9mIHBsYW50cyBncm93biBpbiBjb21wb3N0IHNvaWwgaXMgaGlnaGVyIHRoYW4Kb3IgZXF1YWwgdG8gKCIkXGdlcSQiKSB0aGUgZnJlc2h3ZWlndGggb2YgcGxhbnRzIGdyb3duIGluIGNvbnRyb2wKc29pbCBpcyA5OCUuIFRoaXMgaXMgaGlnaGx5IHNpZ25pZmljYW50bHkgZGlmZmVyZW50IGZyb20gNTAlCihhZGp1c3RlZCBwLXZhbHVlPTAuMDA1KS4KCi0gV2UgZmluZCBhIGhpZ2hseSBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGluIHRoZSBkaXN0cmlidXRpb25zIGJldHdlZW4KdGhlIGNvbXBvc3QgdHJlYXRtZW50IGFuZCB0aGUgcmVmb2FrIHRyZWF0bWVudC4gVGhlIHByb2JhYmlsaXR5CnRoYXQgdGhlIGZyZXNod2VpZ3RoIG9mIHBsYW50cyBncm93biBpbiBjb21wb3N0IHNvaWwgaXMgaGlnaGVyIHRoYW4Kb3IgZXF1YWwgdG8gKCIkXGdlcSQiKSB0aGUgZnJlc2h3ZWlndGggb2YgcGxhbnRzIGdyb3duIGluIGNvbnRyb2wKc29pbCBpcyAxMDAlLiBUaGlzIGlzIGhpZ2hseSBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBmcm9tIDUwJQooYWRqdXN0ZWQgcC12YWx1ZT0wLjAwMykuCgotIFdlIGZpbmQgYSBoaWdobHkgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBpbiB0aGUgZGlzdHJpYnV0aW9ucyBiZXR3ZWVuCnRoZSBjb2JjIHRyZWF0bWVudCBhbmQgdGhlIHJlZm9hayB0cmVhdG1lbnQuIFRoZSBwcm9iYWJpbGl0eQp0aGF0IHRoZSBmcmVzaHdlaWd0aCBvZiBwbGFudHMgZ3Jvd24gaW4gY29tcG9zdCBzb2lsIGlzIGhpZ2hlciB0aGFuCm9yIGVxdWFsIHRvICgiJFxnZXEkIikgdGhlIGZyZXNod2VpZ3RoIG9mIHBsYW50cyBncm93biBpbiBjb250cm9sCnNvaWwgaXMgMTAwJS4gVGhpcyBpcyBoaWdobHkgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgZnJvbSA1MCUKKGFkanVzdGVkIHAtdmFsdWU9MC4wMDMpLgoKRm9yIHRoZSBvdGhlciBjb250cmFzdCwgd2UgZG8gbm90IGVub3VnaCBmaW5kIGV2aWRlbmNlIHRvIHN1Z2dlc3QKc2lnbmlmaWNhbnQgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgdHJlYXRtZW50IGdyb3Vwcy4KCldlIG1heSBjb25jbHVkZSB0aGF0IHN1cHBsZW1lbnRpbmcgc29pbCB3aXRoIGNvbXBvc3Qgb3Igd2l0aApib3RoIGNvbXBvc3QgYW5kIGJpb2NoYXIgaGFzIGEgcG9zaXRpdmUgZWZmZWN0IG9uIHRoZSBmcmVzaHdlaWd0aApvZiBsZXR0dWNlIHBsYW50cy4gTm90ZSB0aGF0LCBxdWFsaXRhdGl2ZWx5LCB0aGVzZSBjb25jbHVzaW9uIGFyZQpleGFjdGx5IHRoZSBzYW1lIGFzIHdpdGggdGhlIEFOT1ZBIGFuYWx5c2lzIG9mIHRoZSBkYXRhc2V0IGluIHRoZQpgQU5PVkFfbGV0dHVjZV9wbGFudHMuUm1kYCBmaWxlLgo=