Question 1
Download and import the Nitrate.csv file from Moodle. The dataset
includes results of an agricultural researcher who measured soil nitrate
levels (\(\text{mg/kg}\)) in 15
agricultural plots before (Pre_Nitrate) and after (Post_Nitrate)
planting a cover crop. We are interested whether nitrates level changed
significantly before and after the plantation.
- State your hypotheses.
- Choose the relevent test after testing all required hypotheses.
- Run the test and discuss the results.
Solution
I use a significance level of 0.05 throughout. A small p-value
provides evidence against the null hypothesis. A large p-value does not
prove that the null hypothesis is true. Independence between sampling
units depends on the study design and cannot be established using a
normality test. I assume that different plots, samples, and lakes are
independent as appropriate to each question.
Hypotheses. Let the difference be post-planting
minus pre-planting nitrate. My null hypothesis is that the population
mean difference equals zero. My alternative hypothesis is that the mean
difference is not zero (a two-sided test).
nitrate <- read.csv("Nitrate.csv", row.names = 1)
stopifnot(nrow(nitrate) == 15, !anyNA(nitrate),
!anyDuplicated(nitrate$Plot_ID))
nitrate$Difference <- nitrate$Post_Nitrate - nitrate$Pre_Nitrate
summary(nitrate$Difference)
Min. 1st Qu. Median Mean 3rd Qu. Max.
-8.280 -4.610 -3.140 -2.025 0.645 8.430
shapiro.test(nitrate$Difference)
Shapiro-Wilk normality test
data: nitrate$Difference
W = 0.94607, p-value = 0.4648
qqnorm(nitrate$Difference, main = "Normal Q-Q plot of nitrate differences")
qqline(nitrate$Difference)

Test choice. The measurements are paired because the
same 15 plots were measured twice. For a paired t-test, normality
concerns the differences, rather than the two sets of measurements
separately. The Shapiro-Wilk test gives p = 0.4648, so it does not
indicate a departure from normality. Equal pre- and post-planting
variances are not required. I use a paired t-test, assuming that the
differences from separate plots are independent.
colMeans(nitrate[c("Pre_Nitrate", "Post_Nitrate")])
Pre_Nitrate Post_Nitrate
25.68133 23.65667
t.test(nitrate$Post_Nitrate, nitrate$Pre_Nitrate, paired = TRUE)
Paired t-test
data: nitrate$Post_Nitrate and nitrate$Pre_Nitrate
t = -1.8384, df = 14, p-value = 0.08731
alternative hypothesis: true mean difference is not equal to 0
95 percent confidence interval:
-4.3867546 0.3374213
sample estimates:
mean difference
-2.024667
Conclusion. Mean nitrate decreased from 25.68 to
23.66 mg/kg, a mean change of -2.02 mg/kg. However, the paired t-test
gives t(14) = -1.84, p = 0.0873. The 95% confidence interval for the
mean change is [-4.39, 0.34] mg/kg. I fail to reject the null
hypothesis: these data do not provide sufficient evidence of a change in
mean nitrate at the 5% level.
Question 2
Microplastic particle concentrations (particles/L) were sampled from
two independent rivers: River A and River B. Import the dataset
Microplastics.csv from Moodle and test whether the Microplastic particle
concentrations differ significantly in the 2 sites.
- State your hypotheses.
- Choose the relevent test after testing all required hypotheses.
- Run the test and discuss the results.
Solution
Hypotheses. H0: the population mean microplastic
concentration is equal in River A and River B. H1: the population means
differ.
micro <- read.csv("Microplastics.csv", row.names = 1)
micro$River <- factor(micro$River)
stopifnot(!anyNA(micro))
table(micro$River)
River_A River_B
15 15
by(micro$Microplastics_per_L, micro$River, shapiro.test)
micro$River: River_A
Shapiro-Wilk normality test
data: dd[x, ]
W = 0.92683, p-value = 0.2445
------------------------------------------------------------
micro$River: River_B
Shapiro-Wilk normality test
data: dd[x, ]
W = 0.89249, p-value = 0.07314
fligner.test(Microplastics_per_L ~ River, data = micro)
Fligner-Killeen test of homogeneity of variances
data: Microplastics_per_L by River
Fligner-Killeen:med chi-squared = 6.7388, df = 1, p-value = 0.009434
par(mfrow = c(1, 2))
for (river in levels(micro$River)) {
values <- micro$Microplastics_per_L[micro$River == river]
qqnorm(values, main = river)
qqline(values)
}

par(mfrow = c(1, 1))
Test choice. There are 15 observations per river,
and the two groups are independent according to the question.
Shapiro-Wilk p-values are 0.2445 and 0.0731. Neither rejects normality,
although the small sample sizes mean these checks have limited power.
The Fligner-Killeen variance test gives p = 0.00943, indicating unequal
variances. I therefore use Welch’s independent-samples t-test, which
does not require equal variances.
aggregate(Microplastics_per_L ~ River, data = micro, FUN = mean)
t.test(Microplastics_per_L ~ River, data = micro, var.equal = FALSE)
Welch Two Sample t-test
data: Microplastics_per_L by River
t = 2.8754, df = 19.58, p-value = 0.009488
alternative hypothesis: true difference in means between group River_A and group River_B is not equal to 0
95 percent confidence interval:
1.376911 8.689756
sample estimates:
mean in group River_A mean in group River_B
9.513333 4.480000
Conclusion. River A has a mean of 9.51 particles/L
and River B has a mean of 4.48 particles/L. Welch’s test gives t = 2.88,
df = 19.58, p = 0.00949. I reject H0. River A has a significantly higher
mean concentration, with an estimated difference of 5.03 particles/L
(95% CI: 1.38 to 8.69 particles/L). This comparison concerns the sampled
rivers; it does not establish why they differ.
Question 3
Dissolved Organic Carbon (DOC) was sampled across four distinct
wetland habitat types: Bog, Fen, Marsh, and Swamp. Choose and perform
the correct test (after checking all assumptions) to determine whether
DOC levels differ significantly across wetland types. Dataset (DOC.csv)
is available on Moodle.
Solution
Hypotheses. For the rank-based test, H0 is that DOC
distributions are the same across Bog, Fen, Marsh, and Swamp. H1 is that
at least one distribution differs. If the distributions have similar
shapes, this can be interpreted as a difference in location or
medians.
doc <- read.csv("DOC.csv", row.names = 1)
doc$Wetland_Type <- factor(doc$Wetland_Type)
stopifnot(!anyNA(doc))
table(doc$Wetland_Type)
Bog Fen Marsh Swamp
10 10 10 10
doc_model <- lm(DOC_mgL ~ Wetland_Type, data = doc)
shapiro.test(residuals(doc_model))
Shapiro-Wilk normality test
data: residuals(doc_model)
W = 0.84492, p-value = 6.788e-05
fligner.test(DOC_mgL ~ Wetland_Type, data = doc)
Fligner-Killeen test of homogeneity of variances
data: DOC_mgL by Wetland_Type
Fligner-Killeen:med chi-squared = 4.6936, df = 3, p-value = 0.1957
boxplot(DOC_mgL ~ Wetland_Type, data = doc,
main = "DOC across wetland types", xlab = "Wetland type",
ylab = "DOC (mg/L)", col = "lightblue")

qqnorm(residuals(doc_model), main = "Normal Q-Q plot of DOC residuals")
qqline(residuals(doc_model))

Test choice. Each habitat has 10 observations. The
normality test on one-way ANOVA residuals gives p = 0.0000679,
indicating non-normal residuals. The variance test gives p = 0.1957 and
does not detect unequal variances. Given the non-normality and high DOC
observations, I use the Kruskal-Wallis test for four independent groups.
It does not require normally distributed residuals. I interpret it as a
test of distributions because equal distribution shapes have not been
established.
aggregate(DOC_mgL ~ Wetland_Type, data = doc, FUN = median)
kruskal.test(DOC_mgL ~ Wetland_Type, data = doc)
Kruskal-Wallis rank sum test
data: DOC_mgL by Wetland_Type
Kruskal-Wallis chi-squared = 16.639, df = 3, p-value = 0.0008385
pairwise.wilcox.test(doc$DOC_mgL, doc$Wetland_Type,
p.adjust.method = "holm", exact = FALSE)
Pairwise comparisons using Wilcoxon rank sum test with continuity correction
data: doc$DOC_mgL and doc$Wetland_Type
Bog Fen Marsh
Fen 0.6776 - -
Marsh 0.0026 0.0364 -
Swamp 0.0453 0.2270 0.2270
P value adjustment method: holm
Conclusion. The Kruskal-Wallis test gives
chi-squared = 16.64, df = 3, p = 0.000839. I reject H0: DOC differs
across wetland types. Pairwise Wilcoxon tests with Holm correction
identify differences between Bog and Marsh (adjusted p = 0.0026), Fen
and Marsh (0.0364), and Bog and Swamp (0.0453). The sample DOC values
tend to be higher in Bog than in Marsh and Swamp, and higher in Fen than
in Marsh. The remaining pairs are not significant after correction.
Question 4
An ecology experiment measured native grass biomass under two
temperature conditions (Ambient vs. Warmed) and two nitrogen levels
(Control vs. Enriched). You can find the results in biomass.csv on
Moodle.
Create a ggplot2 scatter plot showing biomass across the 2
temperature states, and add Nitrogen levels in different colors. Make
sure you add the respective graph and axes titles.
Perform the correct test (based on your hypotheses and assumption
testing) to check for impact of temperature, nitrogen, and their
interaction on plant biomass. If needed, perform a post-hoc test to
determine exactly which combinations produce significant
results.
Solution
Scatter plot
biomass <- read.csv("biomass.csv", row.names = 1)
biomass$Temperature <- factor(biomass$Temperature,
levels = c("Ambient", "Warmed"))
biomass$Nitrogen <- factor(biomass$Nitrogen,
levels = c("Control", "Enriched"))
stopifnot(!anyNA(biomass))
ggplot(biomass, aes(x = Temperature, y = Plant_Biomass, color = Nitrogen)) +
geom_point(position = position_jitterdodge(jitter.width = 0.15,
dodge.width = 0.55, seed = 103),
size = 2.6, alpha = 0.85) +
labs(title = "Native grass biomass under temperature and nitrogen treatments",
x = "Temperature condition", y = "Plant biomass (reported units)",
color = "Nitrogen treatment") +
theme_minimal(base_size = 12)

The file does not specify a biomass unit, so I do not assign an
unreported unit to the axis.
Hypotheses and assumptions
The temperature null hypothesis is that marginal mean biomass is
equal under ambient and warmed conditions. The nitrogen null hypothesis
is that marginal mean biomass is equal under control and enriched
conditions. The interaction null hypothesis is that the temperature
effect is the same at both nitrogen levels. Each alternative states that
the corresponding effect is present.
with(biomass, table(Temperature, Nitrogen))
Nitrogen
Temperature Control Enriched
Ambient 10 10
Warmed 10 10
biomass_model <- aov(Plant_Biomass ~ Temperature * Nitrogen, data = biomass)
shapiro.test(residuals(biomass_model))
Shapiro-Wilk normality test
data: residuals(biomass_model)
W = 0.94163, p-value = 0.03925
biomass$Group <- interaction(biomass$Temperature, biomass$Nitrogen)
fligner.test(Plant_Biomass ~ Group, data = biomass)
Fligner-Killeen test of homogeneity of variances
data: Plant_Biomass by Group
Fligner-Killeen:med chi-squared = 1.6302, df = 3, p-value = 0.6526
par(mfrow = c(1, 2))
plot(biomass_model, which = 1)
plot(biomass_model, which = 2)

par(mfrow = c(1, 1))
Test choice. I use a two-way ANOVA because there are
two categorical factors and a continuous response, and I need to test
their interaction. The design is balanced with 10 observations in each
combination. Equal variances are plausible (Fligner-Killeen p = 0.6526).
However, residual normality is rejected at the 5% level (Shapiro-Wilk p
= 0.0393). Thus, the normality assumption is imperfect. I retain the
original-scale ANOVA because a balanced design with similar variances is
reasonably robust to moderate non-normality, but its p-values should be
interpreted with that limitation. I assume each row represents a
separate experimental unit.
summary(biomass_model)
Df Sum Sq Mean Sq F value Pr(>F)
Temperature 1 855.2 855.2 269.01 < 2e-16 ***
Nitrogen 1 1170.4 1170.4 368.18 < 2e-16 ***
Temperature:Nitrogen 1 37.2 37.2 11.69 0.00158 **
Residuals 36 114.4 3.2
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
aggregate(Plant_Biomass ~ Temperature + Nitrogen, data = biomass, FUN = mean)
TukeyHSD(aov(Plant_Biomass ~ Group, data = biomass))
Tukey multiple comparisons of means
95% family-wise confidence level
Fit: aov(formula = Plant_Biomass ~ Group, data = biomass)
$Group
diff lwr upr p adj
Warmed.Control-Ambient.Control 7.320 5.1725466 9.467453 0.0000000
Ambient.Enriched-Ambient.Control 8.891 6.7435466 11.038453 0.0000000
Warmed.Enriched-Ambient.Control 20.066 17.9185466 22.213453 0.0000000
Ambient.Enriched-Warmed.Control 1.571 -0.5764534 3.718453 0.2180468
Warmed.Enriched-Warmed.Control 12.746 10.5985466 14.893453 0.0000000
Warmed.Enriched-Ambient.Enriched 11.175 9.0275466 13.322453 0.0000000
Conclusion. Temperature is significant, F(1,36) =
269.01, p < 0.001, and nitrogen is significant, F(1,36) = 368.18, p
< 0.001. Their interaction is also significant, F(1,36) = 11.69, p =
0.00158. Because the interaction is significant, I interpret the
treatment combinations rather than relying only on the main effects.
Mean biomass is 24.43 for Ambient-Control, 31.75 for Warmed-Control,
33.32 for Ambient-Enriched, and 44.49 for Warmed-Enriched. Warming
increases mean biomass by 7.32 units under control nitrogen and by 11.18
units under enriched nitrogen. This larger increase under enrichment
explains the positive interaction on the original biomass scale.
Tukey’s comparisons show that all pairs differ significantly except
Warmed-Control versus Ambient-Enriched (adjusted p = 0.218).
Warmed-Enriched produces the highest mean biomass. These ANOVA and Tukey
conclusions share the residual-normality limitation described above.
Question 5
Soil moisture content (%) was monitored across 12 forest plots
over four consecutive observation periods: Week 0, Week
2, Week 4, and Week 6. Data is found in soil_mosture.csv on Moodle.
- State your hypotheses
- Choose the correct test bearing in mind each plot was tested
multiple times. Check the assumptions.
- Interpret your findings.
Solution
Hypotheses. H0: the population mean soil moisture is
equal at Week 0, Week 2, Week 4, and Week 6. H1: at least one time-point
mean differs.
moisture <- read.csv("soil_moisture.csv", row.names = 1)
moisture$Subject <- factor(moisture$Subject)
moisture$Time <- factor(moisture$Time,
levels = c("Week0", "Week2", "Week4", "Week6"))
stopifnot(!anyNA(moisture), all(table(moisture$Subject, moisture$Time) == 1))
# Rows are plots and columns are observation times, preserving pairing.
moisture_wide <- as.matrix(xtabs(Moisture_Pct ~ Subject + Time, data = moisture))
colMeans(moisture_wide)
Week0 Week2 Week4 Week6
48.85167 44.26250 39.25000 34.59750
Test choice and assumptions. The same 12 plots were
measured four times, so an ordinary independent-groups ANOVA would be
inappropriate. I use a one-way repeated-measures ANOVA. This requires
independent plots, approximately normal within-plot contrasts, and
sphericity (equal variances of differences between time points). There
are no missing or duplicated plot-time measurements.
time_pairs <- combn(ncol(moisture_wide), 2, simplify = FALSE)
normality <- do.call(rbind, lapply(time_pairs, function(j) {
differences <- moisture_wide[, j[1]] - moisture_wide[, j[2]]
data.frame(Comparison = paste(colnames(moisture_wide)[j], collapse = " - "),
Shapiro_p = shapiro.test(differences)$p.value)
}))
normality
par(mfrow = c(2, 3))
for (j in time_pairs) {
differences <- moisture_wide[, j[1]] - moisture_wide[, j[2]]
qqnorm(differences, main = paste(colnames(moisture_wide)[j], collapse = " - "))
qqline(differences)
}

par(mfrow = c(1, 1))
# Multivariate representation of the repeated measurements.
moisture_multivariate <- lm(moisture_wide ~ 1)
mauchly.test(moisture_multivariate, X = ~ 1)
Mauchly's test of sphericity
Contrasts orthogonal to
~1
data: SSD matrix from lm(formula = moisture_wide ~ 1)
W = 0.79074, p-value = 0.8097
Mauchly’s test gives W = 0.7907, p = 0.8097, so there is no evidence
against sphericity. Five of six difference-normality tests have p >
0.05; Week 0 minus Week 2 is borderline at p = 0.0492. These
small-sample checks do not prove multivariate normality. I report
repeated-measures ANOVA and check whether a nonparametric Friedman test
supports the overall conclusion.
moisture_model <- aov(Moisture_Pct ~ Time + Error(Subject / Time), data = moisture)
summary(moisture_model)
Error: Subject
Df Sum Sq Mean Sq F value Pr(>F)
Residuals 11 552 50.18
Error: Subject:Time
Df Sum Sq Mean Sq F value Pr(>F)
Time 3 1369.9 456.6 185.5 <2e-16 ***
Residuals 33 81.2 2.5
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Also displays Greenhouse-Geisser and Huynh-Feldt corrections.
anova(moisture_multivariate, X = ~ 1, test = "Spherical")
friedman.test(Moisture_Pct ~ Time | Subject, data = moisture)
Friedman rank sum test
data: Moisture_Pct and Time and Subject
Friedman chi-squared = 36, df = 3, p-value = 7.488e-08
Conclusion. Mean moisture decreases from 48.85% to
44.26%, 39.25%, and 34.60% over the four observations. The
repeated-measures ANOVA gives F(3,33) = 185.49, p < 0.001, so I
reject H0. The Friedman sensitivity check also finds an overall time
effect (chi-squared = 36.00, df = 3, p = 7.49e-8). Moisture differs
significantly across time, with a clear decrease in the observed means.
An overall test alone does not establish that every pair of weeks
differs.
Question 6
A lake clarity index (scale 1 to 10) was measured across 10
monitoring lakes during three distinct seasons: Spring, Summer, and
Autumn. (The dataset is called water_clarity.csv).
- State your hypotheses.
- Report whether seasonal variations in water clarity are
statistically significant.
Solution
Hypotheses. For the Friedman test, H0 is that the
seasons have the same clarity rank distribution within lakes (no
systematic seasonal effect). H1 is that at least one season differs.
clarity <- read.csv("water_clarity.csv", row.names = 1)
clarity$Lake_ID <- factor(clarity$Lake_ID)
clarity$Season <- factor(clarity$Season, levels = c("Spring", "Summer", "Autumn"))
stopifnot(!anyNA(clarity), all(table(clarity$Lake_ID, clarity$Season) == 1))
by(clarity$Clarity_Index, clarity$Season, shapiro.test)
clarity$Season: Spring
Shapiro-Wilk normality test
data: dd[x, ]
W = 0.93989, p-value = 0.5518
------------------------------------------------------------
clarity$Season: Summer
Shapiro-Wilk normality test
data: dd[x, ]
W = 0.69944, p-value = 0.0008672
------------------------------------------------------------
clarity$Season: Autumn
Shapiro-Wilk normality test
data: dd[x, ]
W = 0.90737, p-value = 0.2634
range(clarity$Clarity_Index)
[1] 0.2 6.1
sum(clarity$Clarity_Index < 1 | clarity$Clarity_Index > 10)
[1] 7
boxplot(Clarity_Index ~ Season, data = clarity,
main = "Lake clarity across seasons", xlab = "Season",
ylab = "Clarity index", col = "lightblue")

Test choice. These are repeated measurements on the
same 10 lakes. I use the Friedman test, with lake as the blocking
variable, because it accommodates paired measurements over three seasons
and does not require normality or sphericity. The index is bounded and
Summer values are strongly non-normal (Shapiro-Wilk p = 0.000867). I
assume different lakes are independent, and each lake has one
measurement in every season.
Data note. The question describes a 1-10 scale, but
the supplied file contains values below 1 (the observed range is
0.2-6.1). I keep the supplied values for this analysis; the scale
description should be checked against the original data source.
aggregate(Clarity_Index ~ Season, data = clarity, FUN = median)
friedman.test(Clarity_Index ~ Season | Lake_ID, data = clarity)
Friedman rank sum test
data: Clarity_Index and Season and Lake_ID
Friedman chi-squared = 11.4, df = 2, p-value = 0.003346
Conclusion. The Friedman test gives chi-squared =
11.40, df = 2, p = 0.00335. I reject H0 and conclude that seasonal
variation in clarity is statistically significant. The sample medians
are 2.70 in Spring, 0.65 in Summer, and 4.75 in Autumn. These summaries
suggest lower clarity in Summer and higher clarity in Autumn, but the
overall test does not determine which individual season pairs
differ.
LS0tCnRpdGxlOiAiUHJlLW1pZHRlcm0gcHJhY3RpY2UgYXNzaWdubWVudCIKc3VidGl0bGU6ICJFU1MgMTAzIgphdXRob3I6ICJSdWJlbiBNZWxpa3lhbiIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMjIyBRdWVzdGlvbiAxCgpEb3dubG9hZCBhbmQgaW1wb3J0IHRoZSBOaXRyYXRlLmNzdiBmaWxlIGZyb20gTW9vZGxlLiBUaGUgZGF0YXNldCBpbmNsdWRlcyByZXN1bHRzIG9mIGFuIGFncmljdWx0dXJhbCByZXNlYXJjaGVyIHdobyBtZWFzdXJlZCBzb2lsIG5pdHJhdGUgbGV2ZWxzICgkXHRleHR7bWcva2d9JCkgaW4gMTUgYWdyaWN1bHR1cmFsIHBsb3RzIGJlZm9yZSAoUHJlX05pdHJhdGUpIGFuZCBhZnRlciAoUG9zdF9OaXRyYXRlKSBwbGFudGluZyBhIGNvdmVyIGNyb3AuIFdlIGFyZSBpbnRlcmVzdGVkIHdoZXRoZXIgbml0cmF0ZXMgbGV2ZWwgY2hhbmdlZCBzaWduaWZpY2FudGx5IGJlZm9yZSBhbmQgYWZ0ZXIgdGhlIHBsYW50YXRpb24uCgoxLiBTdGF0ZSB5b3VyIGh5cG90aGVzZXMuCjIuIENob29zZSB0aGUgcmVsZXZlbnQgdGVzdCBhZnRlciB0ZXN0aW5nIGFsbCByZXF1aXJlZCBoeXBvdGhlc2VzLgozLiBSdW4gdGhlIHRlc3QgYW5kIGRpc2N1c3MgdGhlIHJlc3VsdHMuIAoKCioqU29sdXRpb24qKgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICBmaWcud2lkdGggPSA3LCBmaWcuaGVpZ2h0ID0gNC41KQpsaWJyYXJ5KGdncGxvdDIpCmBgYAoKSSB1c2UgYSBzaWduaWZpY2FuY2UgbGV2ZWwgb2YgMC4wNSB0aHJvdWdob3V0LiBBIHNtYWxsIHAtdmFsdWUgcHJvdmlkZXMgZXZpZGVuY2UgYWdhaW5zdCB0aGUgbnVsbCBoeXBvdGhlc2lzLiBBIGxhcmdlIHAtdmFsdWUgZG9lcyBub3QgcHJvdmUgdGhhdCB0aGUgbnVsbCBoeXBvdGhlc2lzIGlzIHRydWUuIEluZGVwZW5kZW5jZSBiZXR3ZWVuIHNhbXBsaW5nIHVuaXRzIGRlcGVuZHMgb24gdGhlIHN0dWR5IGRlc2lnbiBhbmQgY2Fubm90IGJlIGVzdGFibGlzaGVkIHVzaW5nIGEgbm9ybWFsaXR5IHRlc3QuIEkgYXNzdW1lIHRoYXQgZGlmZmVyZW50IHBsb3RzLCBzYW1wbGVzLCBhbmQgbGFrZXMgYXJlIGluZGVwZW5kZW50IGFzIGFwcHJvcHJpYXRlIHRvIGVhY2ggcXVlc3Rpb24uCgoqKkh5cG90aGVzZXMuKiogTGV0IHRoZSBkaWZmZXJlbmNlIGJlIHBvc3QtcGxhbnRpbmcgbWludXMgcHJlLXBsYW50aW5nIG5pdHJhdGUuIE15IG51bGwgaHlwb3RoZXNpcyBpcyB0aGF0IHRoZSBwb3B1bGF0aW9uIG1lYW4gZGlmZmVyZW5jZSBlcXVhbHMgemVyby4gTXkgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcyBpcyB0aGF0IHRoZSBtZWFuIGRpZmZlcmVuY2UgaXMgbm90IHplcm8gKGEgdHdvLXNpZGVkIHRlc3QpLgoKYGBge3Igbml0cmF0ZS1kYXRhfQpuaXRyYXRlIDwtIHJlYWQuY3N2KCJOaXRyYXRlLmNzdiIsIHJvdy5uYW1lcyA9IDEpCnN0b3BpZm5vdChucm93KG5pdHJhdGUpID09IDE1LCAhYW55TkEobml0cmF0ZSksCiAgICAgICAgICAhYW55RHVwbGljYXRlZChuaXRyYXRlJFBsb3RfSUQpKQpuaXRyYXRlJERpZmZlcmVuY2UgPC0gbml0cmF0ZSRQb3N0X05pdHJhdGUgLSBuaXRyYXRlJFByZV9OaXRyYXRlCnN1bW1hcnkobml0cmF0ZSREaWZmZXJlbmNlKQpzaGFwaXJvLnRlc3Qobml0cmF0ZSREaWZmZXJlbmNlKQpxcW5vcm0obml0cmF0ZSREaWZmZXJlbmNlLCBtYWluID0gIk5vcm1hbCBRLVEgcGxvdCBvZiBuaXRyYXRlIGRpZmZlcmVuY2VzIikKcXFsaW5lKG5pdHJhdGUkRGlmZmVyZW5jZSkKYGBgCgoqKlRlc3QgY2hvaWNlLioqIFRoZSBtZWFzdXJlbWVudHMgYXJlIHBhaXJlZCBiZWNhdXNlIHRoZSBzYW1lIDE1IHBsb3RzIHdlcmUgbWVhc3VyZWQgdHdpY2UuIEZvciBhIHBhaXJlZCB0LXRlc3QsIG5vcm1hbGl0eSBjb25jZXJucyB0aGUgZGlmZmVyZW5jZXMsIHJhdGhlciB0aGFuIHRoZSB0d28gc2V0cyBvZiBtZWFzdXJlbWVudHMgc2VwYXJhdGVseS4gVGhlIFNoYXBpcm8tV2lsayB0ZXN0IGdpdmVzIHAgPSAwLjQ2NDgsIHNvIGl0IGRvZXMgbm90IGluZGljYXRlIGEgZGVwYXJ0dXJlIGZyb20gbm9ybWFsaXR5LiBFcXVhbCBwcmUtIGFuZCBwb3N0LXBsYW50aW5nIHZhcmlhbmNlcyBhcmUgbm90IHJlcXVpcmVkLiBJIHVzZSBhIHBhaXJlZCB0LXRlc3QsIGFzc3VtaW5nIHRoYXQgdGhlIGRpZmZlcmVuY2VzIGZyb20gc2VwYXJhdGUgcGxvdHMgYXJlIGluZGVwZW5kZW50LgoKYGBge3Igbml0cmF0ZS10ZXN0fQpjb2xNZWFucyhuaXRyYXRlW2MoIlByZV9OaXRyYXRlIiwgIlBvc3RfTml0cmF0ZSIpXSkKdC50ZXN0KG5pdHJhdGUkUG9zdF9OaXRyYXRlLCBuaXRyYXRlJFByZV9OaXRyYXRlLCBwYWlyZWQgPSBUUlVFKQpgYGAKCioqQ29uY2x1c2lvbi4qKiBNZWFuIG5pdHJhdGUgZGVjcmVhc2VkIGZyb20gMjUuNjggdG8gMjMuNjYgbWcva2csIGEgbWVhbiBjaGFuZ2Ugb2YgLTIuMDIgbWcva2cuIEhvd2V2ZXIsIHRoZSBwYWlyZWQgdC10ZXN0IGdpdmVzIHQoMTQpID0gLTEuODQsIHAgPSAwLjA4NzMuIFRoZSA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbCBmb3IgdGhlIG1lYW4gY2hhbmdlIGlzIFstNC4zOSwgMC4zNF0gbWcva2cuIEkgZmFpbCB0byByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpczogdGhlc2UgZGF0YSBkbyBub3QgcHJvdmlkZSBzdWZmaWNpZW50IGV2aWRlbmNlIG9mIGEgY2hhbmdlIGluIG1lYW4gbml0cmF0ZSBhdCB0aGUgNSUgbGV2ZWwuCgojIyMjIFF1ZXN0aW9uIDIKCk1pY3JvcGxhc3RpYyBwYXJ0aWNsZSBjb25jZW50cmF0aW9ucyAocGFydGljbGVzL0wpIHdlcmUgc2FtcGxlZCBmcm9tIHR3byBpbmRlcGVuZGVudCByaXZlcnM6IFJpdmVyIEEgYW5kIFJpdmVyIEIuIEltcG9ydCB0aGUgZGF0YXNldCBNaWNyb3BsYXN0aWNzLmNzdiBmcm9tIE1vb2RsZSBhbmQgdGVzdCB3aGV0aGVyIHRoZSBNaWNyb3BsYXN0aWMgcGFydGljbGUgY29uY2VudHJhdGlvbnMgZGlmZmVyIHNpZ25pZmljYW50bHkgaW4gdGhlIDIgc2l0ZXMuIAoKMS4gU3RhdGUgeW91ciBoeXBvdGhlc2VzLgoyLiBDaG9vc2UgdGhlIHJlbGV2ZW50IHRlc3QgYWZ0ZXIgdGVzdGluZyBhbGwgcmVxdWlyZWQgaHlwb3RoZXNlcy4KMy4gUnVuIHRoZSB0ZXN0IGFuZCBkaXNjdXNzIHRoZSByZXN1bHRzLiAKIAoKKipTb2x1dGlvbioqCgoqKkh5cG90aGVzZXMuKiogSDA6IHRoZSBwb3B1bGF0aW9uIG1lYW4gbWljcm9wbGFzdGljIGNvbmNlbnRyYXRpb24gaXMgZXF1YWwgaW4gUml2ZXIgQSBhbmQgUml2ZXIgQi4gSDE6IHRoZSBwb3B1bGF0aW9uIG1lYW5zIGRpZmZlci4KCmBgYHtyIG1pY3JvcGxhc3RpY3MtYXNzdW1wdGlvbnN9Cm1pY3JvIDwtIHJlYWQuY3N2KCJNaWNyb3BsYXN0aWNzLmNzdiIsIHJvdy5uYW1lcyA9IDEpCm1pY3JvJFJpdmVyIDwtIGZhY3RvcihtaWNybyRSaXZlcikKc3RvcGlmbm90KCFhbnlOQShtaWNybykpCnRhYmxlKG1pY3JvJFJpdmVyKQpieShtaWNybyRNaWNyb3BsYXN0aWNzX3Blcl9MLCBtaWNybyRSaXZlciwgc2hhcGlyby50ZXN0KQpmbGlnbmVyLnRlc3QoTWljcm9wbGFzdGljc19wZXJfTCB+IFJpdmVyLCBkYXRhID0gbWljcm8pCnBhcihtZnJvdyA9IGMoMSwgMikpCmZvciAocml2ZXIgaW4gbGV2ZWxzKG1pY3JvJFJpdmVyKSkgewogIHZhbHVlcyA8LSBtaWNybyRNaWNyb3BsYXN0aWNzX3Blcl9MW21pY3JvJFJpdmVyID09IHJpdmVyXQogIHFxbm9ybSh2YWx1ZXMsIG1haW4gPSByaXZlcikKICBxcWxpbmUodmFsdWVzKQp9CnBhcihtZnJvdyA9IGMoMSwgMSkpCmBgYAoKKipUZXN0IGNob2ljZS4qKiBUaGVyZSBhcmUgMTUgb2JzZXJ2YXRpb25zIHBlciByaXZlciwgYW5kIHRoZSB0d28gZ3JvdXBzIGFyZSBpbmRlcGVuZGVudCBhY2NvcmRpbmcgdG8gdGhlIHF1ZXN0aW9uLiBTaGFwaXJvLVdpbGsgcC12YWx1ZXMgYXJlIDAuMjQ0NSBhbmQgMC4wNzMxLiBOZWl0aGVyIHJlamVjdHMgbm9ybWFsaXR5LCBhbHRob3VnaCB0aGUgc21hbGwgc2FtcGxlIHNpemVzIG1lYW4gdGhlc2UgY2hlY2tzIGhhdmUgbGltaXRlZCBwb3dlci4gVGhlIEZsaWduZXItS2lsbGVlbiB2YXJpYW5jZSB0ZXN0IGdpdmVzIHAgPSAwLjAwOTQzLCBpbmRpY2F0aW5nIHVuZXF1YWwgdmFyaWFuY2VzLiBJIHRoZXJlZm9yZSB1c2UgV2VsY2gncyBpbmRlcGVuZGVudC1zYW1wbGVzIHQtdGVzdCwgd2hpY2ggZG9lcyBub3QgcmVxdWlyZSBlcXVhbCB2YXJpYW5jZXMuCgpgYGB7ciBtaWNyb3BsYXN0aWNzLXRlc3R9CmFnZ3JlZ2F0ZShNaWNyb3BsYXN0aWNzX3Blcl9MIH4gUml2ZXIsIGRhdGEgPSBtaWNybywgRlVOID0gbWVhbikKdC50ZXN0KE1pY3JvcGxhc3RpY3NfcGVyX0wgfiBSaXZlciwgZGF0YSA9IG1pY3JvLCB2YXIuZXF1YWwgPSBGQUxTRSkKYGBgCgoqKkNvbmNsdXNpb24uKiogUml2ZXIgQSBoYXMgYSBtZWFuIG9mIDkuNTEgcGFydGljbGVzL0wgYW5kIFJpdmVyIEIgaGFzIGEgbWVhbiBvZiA0LjQ4IHBhcnRpY2xlcy9MLiBXZWxjaCdzIHRlc3QgZ2l2ZXMgdCA9IDIuODgsIGRmID0gMTkuNTgsIHAgPSAwLjAwOTQ5LiBJIHJlamVjdCBIMC4gUml2ZXIgQSBoYXMgYSBzaWduaWZpY2FudGx5IGhpZ2hlciBtZWFuIGNvbmNlbnRyYXRpb24sIHdpdGggYW4gZXN0aW1hdGVkIGRpZmZlcmVuY2Ugb2YgNS4wMyBwYXJ0aWNsZXMvTCAoOTUlIENJOiAxLjM4IHRvIDguNjkgcGFydGljbGVzL0wpLiBUaGlzIGNvbXBhcmlzb24gY29uY2VybnMgdGhlIHNhbXBsZWQgcml2ZXJzOyBpdCBkb2VzIG5vdCBlc3RhYmxpc2ggd2h5IHRoZXkgZGlmZmVyLgoKIyMjIyBRdWVzdGlvbiAzCgpEaXNzb2x2ZWQgT3JnYW5pYyBDYXJib24gKERPQykgd2FzIHNhbXBsZWQgYWNyb3NzIGZvdXIgZGlzdGluY3Qgd2V0bGFuZCBoYWJpdGF0IHR5cGVzOiBCb2csIEZlbiwgTWFyc2gsIGFuZCBTd2FtcC4gQ2hvb3NlIGFuZCBwZXJmb3JtIHRoZSBjb3JyZWN0IHRlc3QgKGFmdGVyIGNoZWNraW5nIGFsbCBhc3N1bXB0aW9ucykgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgRE9DIGxldmVscyBkaWZmZXIgc2lnbmlmaWNhbnRseSBhY3Jvc3Mgd2V0bGFuZCB0eXBlcy4gRGF0YXNldCAoRE9DLmNzdikgaXMgYXZhaWxhYmxlIG9uIE1vb2RsZS4KCgoqKlNvbHV0aW9uKioKCioqSHlwb3RoZXNlcy4qKiBGb3IgdGhlIHJhbmstYmFzZWQgdGVzdCwgSDAgaXMgdGhhdCBET0MgZGlzdHJpYnV0aW9ucyBhcmUgdGhlIHNhbWUgYWNyb3NzIEJvZywgRmVuLCBNYXJzaCwgYW5kIFN3YW1wLiBIMSBpcyB0aGF0IGF0IGxlYXN0IG9uZSBkaXN0cmlidXRpb24gZGlmZmVycy4gSWYgdGhlIGRpc3RyaWJ1dGlvbnMgaGF2ZSBzaW1pbGFyIHNoYXBlcywgdGhpcyBjYW4gYmUgaW50ZXJwcmV0ZWQgYXMgYSBkaWZmZXJlbmNlIGluIGxvY2F0aW9uIG9yIG1lZGlhbnMuCgpgYGB7ciBkb2MtYXNzdW1wdGlvbnN9CmRvYyA8LSByZWFkLmNzdigiRE9DLmNzdiIsIHJvdy5uYW1lcyA9IDEpCmRvYyRXZXRsYW5kX1R5cGUgPC0gZmFjdG9yKGRvYyRXZXRsYW5kX1R5cGUpCnN0b3BpZm5vdCghYW55TkEoZG9jKSkKdGFibGUoZG9jJFdldGxhbmRfVHlwZSkKZG9jX21vZGVsIDwtIGxtKERPQ19tZ0wgfiBXZXRsYW5kX1R5cGUsIGRhdGEgPSBkb2MpCnNoYXBpcm8udGVzdChyZXNpZHVhbHMoZG9jX21vZGVsKSkKZmxpZ25lci50ZXN0KERPQ19tZ0wgfiBXZXRsYW5kX1R5cGUsIGRhdGEgPSBkb2MpCmJveHBsb3QoRE9DX21nTCB+IFdldGxhbmRfVHlwZSwgZGF0YSA9IGRvYywKICAgICAgICBtYWluID0gIkRPQyBhY3Jvc3Mgd2V0bGFuZCB0eXBlcyIsIHhsYWIgPSAiV2V0bGFuZCB0eXBlIiwKICAgICAgICB5bGFiID0gIkRPQyAobWcvTCkiLCBjb2wgPSAibGlnaHRibHVlIikKcXFub3JtKHJlc2lkdWFscyhkb2NfbW9kZWwpLCBtYWluID0gIk5vcm1hbCBRLVEgcGxvdCBvZiBET0MgcmVzaWR1YWxzIikKcXFsaW5lKHJlc2lkdWFscyhkb2NfbW9kZWwpKQpgYGAKCioqVGVzdCBjaG9pY2UuKiogRWFjaCBoYWJpdGF0IGhhcyAxMCBvYnNlcnZhdGlvbnMuIFRoZSBub3JtYWxpdHkgdGVzdCBvbiBvbmUtd2F5IEFOT1ZBIHJlc2lkdWFscyBnaXZlcyBwID0gMC4wMDAwNjc5LCBpbmRpY2F0aW5nIG5vbi1ub3JtYWwgcmVzaWR1YWxzLiBUaGUgdmFyaWFuY2UgdGVzdCBnaXZlcyBwID0gMC4xOTU3IGFuZCBkb2VzIG5vdCBkZXRlY3QgdW5lcXVhbCB2YXJpYW5jZXMuIEdpdmVuIHRoZSBub24tbm9ybWFsaXR5IGFuZCBoaWdoIERPQyBvYnNlcnZhdGlvbnMsIEkgdXNlIHRoZSBLcnVza2FsLVdhbGxpcyB0ZXN0IGZvciBmb3VyIGluZGVwZW5kZW50IGdyb3Vwcy4gSXQgZG9lcyBub3QgcmVxdWlyZSBub3JtYWxseSBkaXN0cmlidXRlZCByZXNpZHVhbHMuIEkgaW50ZXJwcmV0IGl0IGFzIGEgdGVzdCBvZiBkaXN0cmlidXRpb25zIGJlY2F1c2UgZXF1YWwgZGlzdHJpYnV0aW9uIHNoYXBlcyBoYXZlIG5vdCBiZWVuIGVzdGFibGlzaGVkLgoKYGBge3IgZG9jLXRlc3R9CmFnZ3JlZ2F0ZShET0NfbWdMIH4gV2V0bGFuZF9UeXBlLCBkYXRhID0gZG9jLCBGVU4gPSBtZWRpYW4pCmtydXNrYWwudGVzdChET0NfbWdMIH4gV2V0bGFuZF9UeXBlLCBkYXRhID0gZG9jKQpwYWlyd2lzZS53aWxjb3gudGVzdChkb2MkRE9DX21nTCwgZG9jJFdldGxhbmRfVHlwZSwKICAgICAgICAgICAgICAgICAgICAgcC5hZGp1c3QubWV0aG9kID0gImhvbG0iLCBleGFjdCA9IEZBTFNFKQpgYGAKCioqQ29uY2x1c2lvbi4qKiBUaGUgS3J1c2thbC1XYWxsaXMgdGVzdCBnaXZlcyBjaGktc3F1YXJlZCA9IDE2LjY0LCBkZiA9IDMsIHAgPSAwLjAwMDgzOS4gSSByZWplY3QgSDA6IERPQyBkaWZmZXJzIGFjcm9zcyB3ZXRsYW5kIHR5cGVzLiBQYWlyd2lzZSBXaWxjb3hvbiB0ZXN0cyB3aXRoIEhvbG0gY29ycmVjdGlvbiBpZGVudGlmeSBkaWZmZXJlbmNlcyBiZXR3ZWVuIEJvZyBhbmQgTWFyc2ggKGFkanVzdGVkIHAgPSAwLjAwMjYpLCBGZW4gYW5kIE1hcnNoICgwLjAzNjQpLCBhbmQgQm9nIGFuZCBTd2FtcCAoMC4wNDUzKS4gVGhlIHNhbXBsZSBET0MgdmFsdWVzIHRlbmQgdG8gYmUgaGlnaGVyIGluIEJvZyB0aGFuIGluIE1hcnNoIGFuZCBTd2FtcCwgYW5kIGhpZ2hlciBpbiBGZW4gdGhhbiBpbiBNYXJzaC4gVGhlIHJlbWFpbmluZyBwYWlycyBhcmUgbm90IHNpZ25pZmljYW50IGFmdGVyIGNvcnJlY3Rpb24uCgojIyMjIFF1ZXN0aW9uIDQKCkFuIGVjb2xvZ3kgZXhwZXJpbWVudCBtZWFzdXJlZCBuYXRpdmUgZ3Jhc3MgYmlvbWFzcyB1bmRlciB0d28gdGVtcGVyYXR1cmUgY29uZGl0aW9ucyAoQW1iaWVudCB2cy4gV2FybWVkKSBhbmQgdHdvIG5pdHJvZ2VuIGxldmVscyAoQ29udHJvbCB2cy4gRW5yaWNoZWQpLiBZb3UgY2FuIGZpbmQgdGhlIHJlc3VsdHMgaW4gYmlvbWFzcy5jc3Ygb24gTW9vZGxlLgoKMS4gQ3JlYXRlIGEgZ2dwbG90MiBzY2F0dGVyIHBsb3Qgc2hvd2luZyBiaW9tYXNzIGFjcm9zcyB0aGUgMiB0ZW1wZXJhdHVyZSBzdGF0ZXMsIGFuZCBhZGQgTml0cm9nZW4gbGV2ZWxzIGluIGRpZmZlcmVudCBjb2xvcnMuIE1ha2Ugc3VyZSB5b3UgYWRkIHRoZSByZXNwZWN0aXZlIGdyYXBoIGFuZCBheGVzIHRpdGxlcy4KCjIuIFBlcmZvcm0gdGhlIGNvcnJlY3QgdGVzdCAoYmFzZWQgb24geW91ciBoeXBvdGhlc2VzIGFuZCBhc3N1bXB0aW9uIHRlc3RpbmcpIHRvIGNoZWNrIGZvciBpbXBhY3Qgb2YgdGVtcGVyYXR1cmUsIG5pdHJvZ2VuLCBhbmQgdGhlaXIgaW50ZXJhY3Rpb24gb24gcGxhbnQgYmlvbWFzcy4gSWYgbmVlZGVkLCBwZXJmb3JtIGEgcG9zdC1ob2MgdGVzdCB0byBkZXRlcm1pbmUgZXhhY3RseSB3aGljaCBjb21iaW5hdGlvbnMgcHJvZHVjZSBzaWduaWZpY2FudCByZXN1bHRzLiAKCgoKKipTb2x1dGlvbioqCgoqKlNjYXR0ZXIgcGxvdCoqCgpgYGB7ciBiaW9tYXNzLXBsb3R9CmJpb21hc3MgPC0gcmVhZC5jc3YoImJpb21hc3MuY3N2Iiwgcm93Lm5hbWVzID0gMSkKYmlvbWFzcyRUZW1wZXJhdHVyZSA8LSBmYWN0b3IoYmlvbWFzcyRUZW1wZXJhdHVyZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiQW1iaWVudCIsICJXYXJtZWQiKSkKYmlvbWFzcyROaXRyb2dlbiA8LSBmYWN0b3IoYmlvbWFzcyROaXRyb2dlbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiQ29udHJvbCIsICJFbnJpY2hlZCIpKQpzdG9waWZub3QoIWFueU5BKGJpb21hc3MpKQpnZ3Bsb3QoYmlvbWFzcywgYWVzKHggPSBUZW1wZXJhdHVyZSwgeSA9IFBsYW50X0Jpb21hc3MsIGNvbG9yID0gTml0cm9nZW4pKSArCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcmRvZGdlKGppdHRlci53aWR0aCA9IDAuMTUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZG9kZ2Uud2lkdGggPSAwLjU1LCBzZWVkID0gMTAzKSwKICAgICAgICAgICAgIHNpemUgPSAyLjYsIGFscGhhID0gMC44NSkgKwogIGxhYnModGl0bGUgPSAiTmF0aXZlIGdyYXNzIGJpb21hc3MgdW5kZXIgdGVtcGVyYXR1cmUgYW5kIG5pdHJvZ2VuIHRyZWF0bWVudHMiLAogICAgICAgeCA9ICJUZW1wZXJhdHVyZSBjb25kaXRpb24iLCB5ID0gIlBsYW50IGJpb21hc3MgKHJlcG9ydGVkIHVuaXRzKSIsCiAgICAgICBjb2xvciA9ICJOaXRyb2dlbiB0cmVhdG1lbnQiKSArCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMikKYGBgCgpUaGUgZmlsZSBkb2VzIG5vdCBzcGVjaWZ5IGEgYmlvbWFzcyB1bml0LCBzbyBJIGRvIG5vdCBhc3NpZ24gYW4gdW5yZXBvcnRlZCB1bml0IHRvIHRoZSBheGlzLgoKKipIeXBvdGhlc2VzIGFuZCBhc3N1bXB0aW9ucyoqCgpUaGUgdGVtcGVyYXR1cmUgbnVsbCBoeXBvdGhlc2lzIGlzIHRoYXQgbWFyZ2luYWwgbWVhbiBiaW9tYXNzIGlzIGVxdWFsIHVuZGVyIGFtYmllbnQgYW5kIHdhcm1lZCBjb25kaXRpb25zLiBUaGUgbml0cm9nZW4gbnVsbCBoeXBvdGhlc2lzIGlzIHRoYXQgbWFyZ2luYWwgbWVhbiBiaW9tYXNzIGlzIGVxdWFsIHVuZGVyIGNvbnRyb2wgYW5kIGVucmljaGVkIGNvbmRpdGlvbnMuIFRoZSBpbnRlcmFjdGlvbiBudWxsIGh5cG90aGVzaXMgaXMgdGhhdCB0aGUgdGVtcGVyYXR1cmUgZWZmZWN0IGlzIHRoZSBzYW1lIGF0IGJvdGggbml0cm9nZW4gbGV2ZWxzLiBFYWNoIGFsdGVybmF0aXZlIHN0YXRlcyB0aGF0IHRoZSBjb3JyZXNwb25kaW5nIGVmZmVjdCBpcyBwcmVzZW50LgoKYGBge3IgYmlvbWFzcy1hc3N1bXB0aW9uc30Kd2l0aChiaW9tYXNzLCB0YWJsZShUZW1wZXJhdHVyZSwgTml0cm9nZW4pKQpiaW9tYXNzX21vZGVsIDwtIGFvdihQbGFudF9CaW9tYXNzIH4gVGVtcGVyYXR1cmUgKiBOaXRyb2dlbiwgZGF0YSA9IGJpb21hc3MpCnNoYXBpcm8udGVzdChyZXNpZHVhbHMoYmlvbWFzc19tb2RlbCkpCmJpb21hc3MkR3JvdXAgPC0gaW50ZXJhY3Rpb24oYmlvbWFzcyRUZW1wZXJhdHVyZSwgYmlvbWFzcyROaXRyb2dlbikKZmxpZ25lci50ZXN0KFBsYW50X0Jpb21hc3MgfiBHcm91cCwgZGF0YSA9IGJpb21hc3MpCnBhcihtZnJvdyA9IGMoMSwgMikpCnBsb3QoYmlvbWFzc19tb2RlbCwgd2hpY2ggPSAxKQpwbG90KGJpb21hc3NfbW9kZWwsIHdoaWNoID0gMikKcGFyKG1mcm93ID0gYygxLCAxKSkKYGBgCgoqKlRlc3QgY2hvaWNlLioqIEkgdXNlIGEgdHdvLXdheSBBTk9WQSBiZWNhdXNlIHRoZXJlIGFyZSB0d28gY2F0ZWdvcmljYWwgZmFjdG9ycyBhbmQgYSBjb250aW51b3VzIHJlc3BvbnNlLCBhbmQgSSBuZWVkIHRvIHRlc3QgdGhlaXIgaW50ZXJhY3Rpb24uIFRoZSBkZXNpZ24gaXMgYmFsYW5jZWQgd2l0aCAxMCBvYnNlcnZhdGlvbnMgaW4gZWFjaCBjb21iaW5hdGlvbi4gRXF1YWwgdmFyaWFuY2VzIGFyZSBwbGF1c2libGUgKEZsaWduZXItS2lsbGVlbiBwID0gMC42NTI2KS4gSG93ZXZlciwgcmVzaWR1YWwgbm9ybWFsaXR5IGlzIHJlamVjdGVkIGF0IHRoZSA1JSBsZXZlbCAoU2hhcGlyby1XaWxrIHAgPSAwLjAzOTMpLiBUaHVzLCB0aGUgbm9ybWFsaXR5IGFzc3VtcHRpb24gaXMgaW1wZXJmZWN0LiBJIHJldGFpbiB0aGUgb3JpZ2luYWwtc2NhbGUgQU5PVkEgYmVjYXVzZSBhIGJhbGFuY2VkIGRlc2lnbiB3aXRoIHNpbWlsYXIgdmFyaWFuY2VzIGlzIHJlYXNvbmFibHkgcm9idXN0IHRvIG1vZGVyYXRlIG5vbi1ub3JtYWxpdHksIGJ1dCBpdHMgcC12YWx1ZXMgc2hvdWxkIGJlIGludGVycHJldGVkIHdpdGggdGhhdCBsaW1pdGF0aW9uLiBJIGFzc3VtZSBlYWNoIHJvdyByZXByZXNlbnRzIGEgc2VwYXJhdGUgZXhwZXJpbWVudGFsIHVuaXQuCgpgYGB7ciBiaW9tYXNzLXRlc3R9CnN1bW1hcnkoYmlvbWFzc19tb2RlbCkKYWdncmVnYXRlKFBsYW50X0Jpb21hc3MgfiBUZW1wZXJhdHVyZSArIE5pdHJvZ2VuLCBkYXRhID0gYmlvbWFzcywgRlVOID0gbWVhbikKVHVrZXlIU0QoYW92KFBsYW50X0Jpb21hc3MgfiBHcm91cCwgZGF0YSA9IGJpb21hc3MpKQpgYGAKCioqQ29uY2x1c2lvbi4qKiBUZW1wZXJhdHVyZSBpcyBzaWduaWZpY2FudCwgRigxLDM2KSA9IDI2OS4wMSwgcCA8IDAuMDAxLCBhbmQgbml0cm9nZW4gaXMgc2lnbmlmaWNhbnQsIEYoMSwzNikgPSAzNjguMTgsIHAgPCAwLjAwMS4gVGhlaXIgaW50ZXJhY3Rpb24gaXMgYWxzbyBzaWduaWZpY2FudCwgRigxLDM2KSA9IDExLjY5LCBwID0gMC4wMDE1OC4gQmVjYXVzZSB0aGUgaW50ZXJhY3Rpb24gaXMgc2lnbmlmaWNhbnQsIEkgaW50ZXJwcmV0IHRoZSB0cmVhdG1lbnQgY29tYmluYXRpb25zIHJhdGhlciB0aGFuIHJlbHlpbmcgb25seSBvbiB0aGUgbWFpbiBlZmZlY3RzLgoKTWVhbiBiaW9tYXNzIGlzIDI0LjQzIGZvciBBbWJpZW50LUNvbnRyb2wsIDMxLjc1IGZvciBXYXJtZWQtQ29udHJvbCwgMzMuMzIgZm9yIEFtYmllbnQtRW5yaWNoZWQsIGFuZCA0NC40OSBmb3IgV2FybWVkLUVucmljaGVkLiBXYXJtaW5nIGluY3JlYXNlcyBtZWFuIGJpb21hc3MgYnkgNy4zMiB1bml0cyB1bmRlciBjb250cm9sIG5pdHJvZ2VuIGFuZCBieSAxMS4xOCB1bml0cyB1bmRlciBlbnJpY2hlZCBuaXRyb2dlbi4gVGhpcyBsYXJnZXIgaW5jcmVhc2UgdW5kZXIgZW5yaWNobWVudCBleHBsYWlucyB0aGUgcG9zaXRpdmUgaW50ZXJhY3Rpb24gb24gdGhlIG9yaWdpbmFsIGJpb21hc3Mgc2NhbGUuCgpUdWtleSdzIGNvbXBhcmlzb25zIHNob3cgdGhhdCBhbGwgcGFpcnMgZGlmZmVyIHNpZ25pZmljYW50bHkgZXhjZXB0IFdhcm1lZC1Db250cm9sIHZlcnN1cyBBbWJpZW50LUVucmljaGVkIChhZGp1c3RlZCBwID0gMC4yMTgpLiBXYXJtZWQtRW5yaWNoZWQgcHJvZHVjZXMgdGhlIGhpZ2hlc3QgbWVhbiBiaW9tYXNzLiBUaGVzZSBBTk9WQSBhbmQgVHVrZXkgY29uY2x1c2lvbnMgc2hhcmUgdGhlIHJlc2lkdWFsLW5vcm1hbGl0eSBsaW1pdGF0aW9uIGRlc2NyaWJlZCBhYm92ZS4KCiMjIyMgUXVlc3Rpb24gNQoKU29pbCBtb2lzdHVyZSBjb250ZW50ICglKSB3YXMgbW9uaXRvcmVkIGFjcm9zcyAxMiBmb3Jlc3QgcGxvdHMgKipvdmVyIGZvdXIgY29uc2VjdXRpdmUgb2JzZXJ2YXRpb24gcGVyaW9kcyoqOiBXZWVrIDAsIFdlZWsgMiwgV2VlayA0LCBhbmQgV2VlayA2LiBEYXRhIGlzIGZvdW5kIGluIHNvaWxfbW9zdHVyZS5jc3Ygb24gTW9vZGxlLgoKMS4gU3RhdGUgeW91ciBoeXBvdGhlc2VzCjIuIENob29zZSB0aGUgY29ycmVjdCB0ZXN0IGJlYXJpbmcgaW4gbWluZCBlYWNoIHBsb3Qgd2FzIHRlc3RlZCBtdWx0aXBsZSB0aW1lcy4gQ2hlY2sgdGhlIGFzc3VtcHRpb25zLgozLiBJbnRlcnByZXQgeW91ciBmaW5kaW5ncy4KCgoqKlNvbHV0aW9uKioKCioqSHlwb3RoZXNlcy4qKiBIMDogdGhlIHBvcHVsYXRpb24gbWVhbiBzb2lsIG1vaXN0dXJlIGlzIGVxdWFsIGF0IFdlZWsgMCwgV2VlayAyLCBXZWVrIDQsIGFuZCBXZWVrIDYuIEgxOiBhdCBsZWFzdCBvbmUgdGltZS1wb2ludCBtZWFuIGRpZmZlcnMuCgpgYGB7ciBtb2lzdHVyZS1kYXRhfQptb2lzdHVyZSA8LSByZWFkLmNzdigic29pbF9tb2lzdHVyZS5jc3YiLCByb3cubmFtZXMgPSAxKQptb2lzdHVyZSRTdWJqZWN0IDwtIGZhY3Rvcihtb2lzdHVyZSRTdWJqZWN0KQptb2lzdHVyZSRUaW1lIDwtIGZhY3Rvcihtb2lzdHVyZSRUaW1lLAogICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJXZWVrMCIsICJXZWVrMiIsICJXZWVrNCIsICJXZWVrNiIpKQpzdG9waWZub3QoIWFueU5BKG1vaXN0dXJlKSwgYWxsKHRhYmxlKG1vaXN0dXJlJFN1YmplY3QsIG1vaXN0dXJlJFRpbWUpID09IDEpKQojIFJvd3MgYXJlIHBsb3RzIGFuZCBjb2x1bW5zIGFyZSBvYnNlcnZhdGlvbiB0aW1lcywgcHJlc2VydmluZyBwYWlyaW5nLgptb2lzdHVyZV93aWRlIDwtIGFzLm1hdHJpeCh4dGFicyhNb2lzdHVyZV9QY3QgfiBTdWJqZWN0ICsgVGltZSwgZGF0YSA9IG1vaXN0dXJlKSkKY29sTWVhbnMobW9pc3R1cmVfd2lkZSkKYGBgCgoqKlRlc3QgY2hvaWNlIGFuZCBhc3N1bXB0aW9ucy4qKiBUaGUgc2FtZSAxMiBwbG90cyB3ZXJlIG1lYXN1cmVkIGZvdXIgdGltZXMsIHNvIGFuIG9yZGluYXJ5IGluZGVwZW5kZW50LWdyb3VwcyBBTk9WQSB3b3VsZCBiZSBpbmFwcHJvcHJpYXRlLiBJIHVzZSBhIG9uZS13YXkgcmVwZWF0ZWQtbWVhc3VyZXMgQU5PVkEuIFRoaXMgcmVxdWlyZXMgaW5kZXBlbmRlbnQgcGxvdHMsIGFwcHJveGltYXRlbHkgbm9ybWFsIHdpdGhpbi1wbG90IGNvbnRyYXN0cywgYW5kIHNwaGVyaWNpdHkgKGVxdWFsIHZhcmlhbmNlcyBvZiBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRpbWUgcG9pbnRzKS4gVGhlcmUgYXJlIG5vIG1pc3Npbmcgb3IgZHVwbGljYXRlZCBwbG90LXRpbWUgbWVhc3VyZW1lbnRzLgoKYGBge3IgbW9pc3R1cmUtYXNzdW1wdGlvbnN9CnRpbWVfcGFpcnMgPC0gY29tYm4obmNvbChtb2lzdHVyZV93aWRlKSwgMiwgc2ltcGxpZnkgPSBGQUxTRSkKbm9ybWFsaXR5IDwtIGRvLmNhbGwocmJpbmQsIGxhcHBseSh0aW1lX3BhaXJzLCBmdW5jdGlvbihqKSB7CiAgZGlmZmVyZW5jZXMgPC0gbW9pc3R1cmVfd2lkZVssIGpbMV1dIC0gbW9pc3R1cmVfd2lkZVssIGpbMl1dCiAgZGF0YS5mcmFtZShDb21wYXJpc29uID0gcGFzdGUoY29sbmFtZXMobW9pc3R1cmVfd2lkZSlbal0sIGNvbGxhcHNlID0gIiAtICIpLAogICAgICAgICAgICAgU2hhcGlyb19wID0gc2hhcGlyby50ZXN0KGRpZmZlcmVuY2VzKSRwLnZhbHVlKQp9KSkKbm9ybWFsaXR5CnBhcihtZnJvdyA9IGMoMiwgMykpCmZvciAoaiBpbiB0aW1lX3BhaXJzKSB7CiAgZGlmZmVyZW5jZXMgPC0gbW9pc3R1cmVfd2lkZVssIGpbMV1dIC0gbW9pc3R1cmVfd2lkZVssIGpbMl1dCiAgcXFub3JtKGRpZmZlcmVuY2VzLCBtYWluID0gcGFzdGUoY29sbmFtZXMobW9pc3R1cmVfd2lkZSlbal0sIGNvbGxhcHNlID0gIiAtICIpKQogIHFxbGluZShkaWZmZXJlbmNlcykKfQpwYXIobWZyb3cgPSBjKDEsIDEpKQojIE11bHRpdmFyaWF0ZSByZXByZXNlbnRhdGlvbiBvZiB0aGUgcmVwZWF0ZWQgbWVhc3VyZW1lbnRzLgptb2lzdHVyZV9tdWx0aXZhcmlhdGUgPC0gbG0obW9pc3R1cmVfd2lkZSB+IDEpCm1hdWNobHkudGVzdChtb2lzdHVyZV9tdWx0aXZhcmlhdGUsIFggPSB+IDEpCmBgYAoKTWF1Y2hseSdzIHRlc3QgZ2l2ZXMgVyA9IDAuNzkwNywgcCA9IDAuODA5Nywgc28gdGhlcmUgaXMgbm8gZXZpZGVuY2UgYWdhaW5zdCBzcGhlcmljaXR5LiBGaXZlIG9mIHNpeCBkaWZmZXJlbmNlLW5vcm1hbGl0eSB0ZXN0cyBoYXZlIHAgPiAwLjA1OyBXZWVrIDAgbWludXMgV2VlayAyIGlzIGJvcmRlcmxpbmUgYXQgcCA9IDAuMDQ5Mi4gVGhlc2Ugc21hbGwtc2FtcGxlIGNoZWNrcyBkbyBub3QgcHJvdmUgbXVsdGl2YXJpYXRlIG5vcm1hbGl0eS4gSSByZXBvcnQgcmVwZWF0ZWQtbWVhc3VyZXMgQU5PVkEgYW5kIGNoZWNrIHdoZXRoZXIgYSBub25wYXJhbWV0cmljIEZyaWVkbWFuIHRlc3Qgc3VwcG9ydHMgdGhlIG92ZXJhbGwgY29uY2x1c2lvbi4KCmBgYHtyIG1vaXN0dXJlLXRlc3RzfQptb2lzdHVyZV9tb2RlbCA8LSBhb3YoTW9pc3R1cmVfUGN0IH4gVGltZSArIEVycm9yKFN1YmplY3QgLyBUaW1lKSwgZGF0YSA9IG1vaXN0dXJlKQpzdW1tYXJ5KG1vaXN0dXJlX21vZGVsKQojIEFsc28gZGlzcGxheXMgR3JlZW5ob3VzZS1HZWlzc2VyIGFuZCBIdXluaC1GZWxkdCBjb3JyZWN0aW9ucy4KYW5vdmEobW9pc3R1cmVfbXVsdGl2YXJpYXRlLCBYID0gfiAxLCB0ZXN0ID0gIlNwaGVyaWNhbCIpCmZyaWVkbWFuLnRlc3QoTW9pc3R1cmVfUGN0IH4gVGltZSB8IFN1YmplY3QsIGRhdGEgPSBtb2lzdHVyZSkKYGBgCgoqKkNvbmNsdXNpb24uKiogTWVhbiBtb2lzdHVyZSBkZWNyZWFzZXMgZnJvbSA0OC44NSUgdG8gNDQuMjYlLCAzOS4yNSUsIGFuZCAzNC42MCUgb3ZlciB0aGUgZm91ciBvYnNlcnZhdGlvbnMuIFRoZSByZXBlYXRlZC1tZWFzdXJlcyBBTk9WQSBnaXZlcyBGKDMsMzMpID0gMTg1LjQ5LCBwIDwgMC4wMDEsIHNvIEkgcmVqZWN0IEgwLiBUaGUgRnJpZWRtYW4gc2Vuc2l0aXZpdHkgY2hlY2sgYWxzbyBmaW5kcyBhbiBvdmVyYWxsIHRpbWUgZWZmZWN0IChjaGktc3F1YXJlZCA9IDM2LjAwLCBkZiA9IDMsIHAgPSA3LjQ5ZS04KS4gTW9pc3R1cmUgZGlmZmVycyBzaWduaWZpY2FudGx5IGFjcm9zcyB0aW1lLCB3aXRoIGEgY2xlYXIgZGVjcmVhc2UgaW4gdGhlIG9ic2VydmVkIG1lYW5zLiBBbiBvdmVyYWxsIHRlc3QgYWxvbmUgZG9lcyBub3QgZXN0YWJsaXNoIHRoYXQgZXZlcnkgcGFpciBvZiB3ZWVrcyBkaWZmZXJzLgoKIyMjIyBRdWVzdGlvbiA2CkEgbGFrZSBjbGFyaXR5IGluZGV4IChzY2FsZSAxIHRvIDEwKSB3YXMgbWVhc3VyZWQgYWNyb3NzIDEwIG1vbml0b3JpbmcgbGFrZXMgZHVyaW5nIHRocmVlIGRpc3RpbmN0IHNlYXNvbnM6IFNwcmluZywgU3VtbWVyLCBhbmQgQXV0dW1uLiAoVGhlIGRhdGFzZXQgaXMgY2FsbGVkIHdhdGVyX2NsYXJpdHkuY3N2KS4KCjEuIFN0YXRlIHlvdXIgaHlwb3RoZXNlcy4KMi4gUmVwb3J0IHdoZXRoZXIgc2Vhc29uYWwgdmFyaWF0aW9ucyBpbiB3YXRlciBjbGFyaXR5IGFyZSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LgoKKipTb2x1dGlvbioqCgoqKkh5cG90aGVzZXMuKiogRm9yIHRoZSBGcmllZG1hbiB0ZXN0LCBIMCBpcyB0aGF0IHRoZSBzZWFzb25zIGhhdmUgdGhlIHNhbWUgY2xhcml0eSByYW5rIGRpc3RyaWJ1dGlvbiB3aXRoaW4gbGFrZXMgKG5vIHN5c3RlbWF0aWMgc2Vhc29uYWwgZWZmZWN0KS4gSDEgaXMgdGhhdCBhdCBsZWFzdCBvbmUgc2Vhc29uIGRpZmZlcnMuCgpgYGB7ciBjbGFyaXR5LWFzc3VtcHRpb25zfQpjbGFyaXR5IDwtIHJlYWQuY3N2KCJ3YXRlcl9jbGFyaXR5LmNzdiIsIHJvdy5uYW1lcyA9IDEpCmNsYXJpdHkkTGFrZV9JRCA8LSBmYWN0b3IoY2xhcml0eSRMYWtlX0lEKQpjbGFyaXR5JFNlYXNvbiA8LSBmYWN0b3IoY2xhcml0eSRTZWFzb24sIGxldmVscyA9IGMoIlNwcmluZyIsICJTdW1tZXIiLCAiQXV0dW1uIikpCnN0b3BpZm5vdCghYW55TkEoY2xhcml0eSksIGFsbCh0YWJsZShjbGFyaXR5JExha2VfSUQsIGNsYXJpdHkkU2Vhc29uKSA9PSAxKSkKYnkoY2xhcml0eSRDbGFyaXR5X0luZGV4LCBjbGFyaXR5JFNlYXNvbiwgc2hhcGlyby50ZXN0KQpyYW5nZShjbGFyaXR5JENsYXJpdHlfSW5kZXgpCnN1bShjbGFyaXR5JENsYXJpdHlfSW5kZXggPCAxIHwgY2xhcml0eSRDbGFyaXR5X0luZGV4ID4gMTApCmJveHBsb3QoQ2xhcml0eV9JbmRleCB+IFNlYXNvbiwgZGF0YSA9IGNsYXJpdHksCiAgICAgICAgbWFpbiA9ICJMYWtlIGNsYXJpdHkgYWNyb3NzIHNlYXNvbnMiLCB4bGFiID0gIlNlYXNvbiIsCiAgICAgICAgeWxhYiA9ICJDbGFyaXR5IGluZGV4IiwgY29sID0gImxpZ2h0Ymx1ZSIpCmBgYAoKKipUZXN0IGNob2ljZS4qKiBUaGVzZSBhcmUgcmVwZWF0ZWQgbWVhc3VyZW1lbnRzIG9uIHRoZSBzYW1lIDEwIGxha2VzLiBJIHVzZSB0aGUgRnJpZWRtYW4gdGVzdCwgd2l0aCBsYWtlIGFzIHRoZSBibG9ja2luZyB2YXJpYWJsZSwgYmVjYXVzZSBpdCBhY2NvbW1vZGF0ZXMgcGFpcmVkIG1lYXN1cmVtZW50cyBvdmVyIHRocmVlIHNlYXNvbnMgYW5kIGRvZXMgbm90IHJlcXVpcmUgbm9ybWFsaXR5IG9yIHNwaGVyaWNpdHkuIFRoZSBpbmRleCBpcyBib3VuZGVkIGFuZCBTdW1tZXIgdmFsdWVzIGFyZSBzdHJvbmdseSBub24tbm9ybWFsIChTaGFwaXJvLVdpbGsgcCA9IDAuMDAwODY3KS4gSSBhc3N1bWUgZGlmZmVyZW50IGxha2VzIGFyZSBpbmRlcGVuZGVudCwgYW5kIGVhY2ggbGFrZSBoYXMgb25lIG1lYXN1cmVtZW50IGluIGV2ZXJ5IHNlYXNvbi4KCioqRGF0YSBub3RlLioqIFRoZSBxdWVzdGlvbiBkZXNjcmliZXMgYSAxLTEwIHNjYWxlLCBidXQgdGhlIHN1cHBsaWVkIGZpbGUgY29udGFpbnMgdmFsdWVzIGJlbG93IDEgKHRoZSBvYnNlcnZlZCByYW5nZSBpcyAwLjItNi4xKS4gSSBrZWVwIHRoZSBzdXBwbGllZCB2YWx1ZXMgZm9yIHRoaXMgYW5hbHlzaXM7IHRoZSBzY2FsZSBkZXNjcmlwdGlvbiBzaG91bGQgYmUgY2hlY2tlZCBhZ2FpbnN0IHRoZSBvcmlnaW5hbCBkYXRhIHNvdXJjZS4KCmBgYHtyIGNsYXJpdHktdGVzdH0KYWdncmVnYXRlKENsYXJpdHlfSW5kZXggfiBTZWFzb24sIGRhdGEgPSBjbGFyaXR5LCBGVU4gPSBtZWRpYW4pCmZyaWVkbWFuLnRlc3QoQ2xhcml0eV9JbmRleCB+IFNlYXNvbiB8IExha2VfSUQsIGRhdGEgPSBjbGFyaXR5KQpgYGAKCioqQ29uY2x1c2lvbi4qKiBUaGUgRnJpZWRtYW4gdGVzdCBnaXZlcyBjaGktc3F1YXJlZCA9IDExLjQwLCBkZiA9IDIsIHAgPSAwLjAwMzM1LiBJIHJlamVjdCBIMCBhbmQgY29uY2x1ZGUgdGhhdCBzZWFzb25hbCB2YXJpYXRpb24gaW4gY2xhcml0eSBpcyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LiBUaGUgc2FtcGxlIG1lZGlhbnMgYXJlIDIuNzAgaW4gU3ByaW5nLCAwLjY1IGluIFN1bW1lciwgYW5kIDQuNzUgaW4gQXV0dW1uLiBUaGVzZSBzdW1tYXJpZXMgc3VnZ2VzdCBsb3dlciBjbGFyaXR5IGluIFN1bW1lciBhbmQgaGlnaGVyIGNsYXJpdHkgaW4gQXV0dW1uLCBidXQgdGhlIG92ZXJhbGwgdGVzdCBkb2VzIG5vdCBkZXRlcm1pbmUgd2hpY2ggaW5kaXZpZHVhbCBzZWFzb24gcGFpcnMgZGlmZmVyLgoK