Data and Setup
data = rbind.data.frame(0.85, 1.23, 0.92, 3.45, 2.11, 1.56, 4.89, 2.34, 1.78, 6.72, 0.95, 1.34, 8.91,
2.67, 1.89, 5.43, 1.12, 3.78, 2.45, 7.65, 1.05, 1.45, 12.34, 2.89, 2.01, 4.56,
1.23, 4.32, 2.67, 9.87, 0.99, 1.56, 15.23, 3.12, 2.34, 3.89, 1.34, 5.67, 2.89,
11.45, 1.12, 1.67, 18.90, 3.45, 2.56, 3.45, 1.45, 6.78, 3.12, 14.56, 1.23, 1.78,
22.34, 3.78, 2.78)
colnames(data) = "soil"
For this analysis, we will be examining a dataset of 55 urban garden
sites’ soil lead concentrations. These concentrations of soil lead
(chemical prefix “Pb”) are measured in mg/kg. Moving forward in this
analysis, we will assume the data, and broader population of lead
concentrations in urban sites follow a log-normal
distribution. This assumption is predicated on the fact that
samples such as what we are working with are typically notably right
skewed and by nature must be non-negative.
Summary statistics and a histogram of the dataset at hand are
below.
sum_stats_table = function(variable){
table = cbind(
round(min(variable),2),
round(quantile(variable, 0.25),2),
round(median(variable),2),
round(mean(variable),2),
round(quantile(variable, 0.75),2),
round(max(variable),2)
)
colnames(table) = c("Min", "Q1", "Med", "Mean", "Q3", "Max")
rownames(table) = NULL
return(table)
}
Summary_Table = sum_stats_table(variable = data$soil)
kable(Summary_Table,align = "c",
caption = "<span style='color:##000000;'>
Summary Stats of Soil Times </span>") %>%
kable_styling(
bootstrap_options = c("striped", "bordered"),
full_width = FALSE,
position = "center")
Summary Stats of Soil Times
|
Min
|
Q1
|
Med
|
Mean
|
Q3
|
Max
|
|
0.85
|
1.5
|
2.67
|
4.4
|
4.72
|
22.34
|
hist(data$soil,
main = "Distribution of Concentrations",
xlab = "Concentrations (mg/kg)",
prob = TRUE,
col = "lightblue"
)
box(lwd=3)

Using our available sample data, and our presumption of
log-normality, the following sections will consist of attempts to
estimate the average lead concentrations (mg/kg) across
the broad population of urban sites similar to those
that were observed for our sample. For mathematical notation purposes,
this mean lead concentration will be denoted as E[X]. I
will perform both point estimation and interval estimation.
To find an initial point estimate for E[X], I utilized the MLE
estimation formulas for the log normal distribution as well as standard
algebraic substitution. The relevant formulas are visible below.
knitr::include_graphics("/Users/chrisbahm/Library/Mobile Documents/com~apple~CloudDocs/West Chester/Spring 2026/STA 506 - Grad Math Stat 2 /STA 506 R Folder/Week 9 - Bootstrap Confidence Intervals/MLE.png")

knitr::include_graphics("/Users/chrisbahm/Library/Mobile Documents/com~apple~CloudDocs/West Chester/Spring 2026/STA 506 - Grad Math Stat 2 /STA 506 R Folder/Week 9 - Bootstrap Confidence Intervals/EX.png")

sample_mean = mean(data$soil)
# based on GIVEN formula in assignment instructions for MLE estimator of mu
mu_hat = sum(log(data$soil))/nrow(data)
# based on GIVEN formula in assignment instructions for MLE estimator of theta squared
theta_squared_hat = sum((log(data$soil) - mu_hat)^2)/nrow(data)
Ex_hat = exp(mu_hat + (theta_squared_hat/2))
# E[x] = lognormal population mean
Per this mathematical setup, our starting estimate of population
average lead concentration is approximately 4.218.
a.) Bootstrap Sampling Distribution
Next, I used bootstrapping to acquire a broader sampling distribution
of the average lead concentration point estimate. After performing 5,000
iterations of bootstrap sampling, and calculating E[X] for each sample,
the sampling distribution of population mean estimates is visible
below.
library(boot)
set.seed(100) # setting seed now for entire program
bootstrap_Ex = function(data, b) {
n = length(data)
bootstrap_ex_estimates = numeric(b)
# START FOR LOOP
for (i in 1:b){
boot_sample = sample(data, size = n, replace= TRUE)
mu_hat[i] = sum(log(boot_sample))/n
# make sure to use boot_sample in this line, previously I was using data inside the log function and my output was the same value for every element of the vector
theta_squared_hat[i] = sum((log(boot_sample) - mu_hat[i])^2)/n
bootstrap_ex_estimates[i] = exp(mu_hat[i] +
(theta_squared_hat[i]/2))
}
# END FOR LOOP
return(bootstrap_ex_estimates) # final output
}
# always remember to set the seed for consistent repetition
Ex_sampling_distribution = bootstrap_Ex(data = data$soil, b = 5000)
hist(Ex_sampling_distribution,
main = "Sampling Distribution of Population Mean Estimates",
xlab = "Concentrations (mg/kg)",
prob = TRUE,
col = "lightblue"
)
box(lwd=3)

As we can see from our histogram, the sampling distribution of E[X]
estimates is roughly log-normal distributed, with a rightward skew. The
mean of our sampling distribution is roughly 4.248, which is
extraordinarily close to the population mean estimate acquired strictly
from our available sample data of 4.218.
b.) Bootstrap Percentile CI
After finding a sample distribution, I once again employ
bootstrapping, this time to construct a percentile confidence interval
for E[X]. Percentile intervals are a solid foundation for parameter
estimation. They are the least mathematically complex of all confidence
intervals, relying on the left and right quantile cutoffs of our
distribution, as per the chosen level of \(\alpha\). Since the confidence level for
this interval will be 95%, \(\alpha\) =
0.05 in this instance.
custom_ci_percentile = function(data, b, alpha){
n = length(data)
bootstrap_ex_estimates = numeric(b)
mu_hat = numeric(b)
theta_squared_hat = numeric(b)
# for this function can use the same bootstrapping procedure from above to obtain the bootstrap_ex estimates vector
# START FOR LOOP
for(i in 1:b){
boot_sample = sample(data, size = n, replace= TRUE)
mu_hat[i] = sum(log(boot_sample))/n
theta_squared_hat[i] = sum((log(boot_sample) - mu_hat[i])^2)/n
bootstrap_ex_estimates[i] = exp(mu_hat[i] +
(theta_squared_hat[i]/2))
} # END FOR LOOP
sort_bootstrap_ex_estimates = sort(bootstrap_ex_estimates)
lower_quant = (alpha/2)
higher_quant = (1-(alpha/2))
lower_estimate = quantile(sort_bootstrap_ex_estimates, lower_quant)
higher_estimate = quantile(sort_bootstrap_ex_estimates, higher_quant)
results = rbind(lower_estimate,
higher_estimate)
colnames(results) = "Custom Percent"
rownames(results) = c("Lower Estimate", "Higher Estimate")
return (results)
}
ci_percent_custom = custom_ci_percentile(data$soil, b = 5000, alpha = 0.05)
#ci_percent_custom
### built-in R function
######
# reference section 3.2.3 of notes
## create stat function that finds E[X] from a singular bootstrap sample of our data
find_ex = function(data, indices){
n = length(data)
sample_data = data[indices]
mu_hat = sum(log(sample_data))/n
theta_squared_hat = sum((log(data) - mu_hat)^2)/n
ex_estimate = exp(mu_hat +
(theta_squared_hat/2))
}
# now that this function is made, plug it into the boot function
boot_result = boot(data$soil, find_ex, R = 5000)
ci_percent_r_stats = boot.ci(boot_result, type = "perc")
# Note: boot.ci function defaults to 95% confidence level, can change this using the conf = argument
#ci_percent_r_stats
#ci_percent_r_stats$percent
#ci_percent_r_stats$percent[4] # = lower interval end
#ci_percent_r_stats$percent[5] # = higher interval end
ci_percent_r = rbind(ci_percent_r_stats$percent[4],
ci_percent_r_stats$percent[5])
rownames(ci_percent_r) = c("Lower Estimate", "Higher Estimate")
colnames(ci_percent_r) = "Percentile"
#ci_percent_r
To construct the percentile confidence interval for the mean soil
concentration amongst the broader population of urban sites, I resorted
to both custom function creation as well as R’s boot() function. Per these results, we can
say with approximately 95% confidence that the population mean is either
between 3.154 and 5.565 mg/kg or 3.456 and 5.413 mg/kg.
c.) Bootstrap BCa CI
After creating the percentile intervals, I then moved forward with
bootstrap BCa (bias-corrected and accelerated) intervals. BCa intervals
are a more sophisticated option to their standard percentile
counterparts. They are especially valued when dealing with skewed
distributions/data or biased estimators, something that the percentile
option does not account for nearly as much.
### custom function
# reference section 3.3.2
# START FUNCTION
custom_ci_bca = function(data, b, alpha, original_estimate){
n = length(data)
bootstrap_ex_estimates = numeric(b)
# bias correction "measures median bias by comparing bootstrap estimates to the original estimate."
prop_less = 0 # initialize counting variable at = 0
for (i in 1:b){ # START BOOTSTRAP LOOP
boot_sample = sample(data, size = n, replace= TRUE)
mu_hat[i] = sum(log(boot_sample))/n
theta_squared_hat[i] = sum((log(boot_sample) - mu_hat[i])^2)/n
bootstrap_ex_estimates[i] = exp(mu_hat[i] +
(theta_squared_hat[i]/2))
# bias correction factor below
## can use normal if statement syntax, just incorporate the [i] to indicate that the statement is evaluating element by element
if (bootstrap_ex_estimates[i] < original_estimate){
prop_less = prop_less + 1
}
} # END BOOTSTRAP LOOP
#### START CORRECTION CALCULATION
prop_less = prop_less/b
z0 = qnorm(prop_less)
# now have bias correction
#### END BIAS CORRECTION CALCULATION
#### START ACCELERATION CALCULATION
# good practice to use different "counting variable than was earlier used in function, I'll use j instead of i
jack_vals = numeric(n)
for (j in 1:n){ # START JACK LOOP
jack_sample = data[-j]
mu_jack = sum(log(jack_sample)) / (n-1)
# the jackknife estimate is computed by leaving OUT the ith observation
theta_squared_jack = sum((log(jack_sample)-mu_jack)^2) / (n-1)
jack_vals[j] = exp(mu_jack + (theta_squared_jack/2))
} # END JACK LOOP
theta_jack_mean = mean(jack_vals)
# we want the difference between the total average and each jackknife estimate that left one out
numerator = sum((theta_jack_mean - jack_vals)^3)
denominator = sum((theta_jack_mean - jack_vals)^2)
a_hat = numerator/ (6 * denominator^(3/2))
#### END ACCELERATION CALCULATION
### FINAL OUTPUT/INTERVAL
z_score1 = qnorm(alpha/2)
z_score2 = qnorm(1-alpha/2)
alpha1 = pnorm(z0 + (z0 + z_score1)/(1-a_hat*(z0 + z_score1)))
alpha2 = pnorm(z0 + (z0 + z_score2)/(1-a_hat*(z0 + z_score2)))
lower = quantile(bootstrap_ex_estimates, alpha1)
upper = quantile(bootstrap_ex_estimates, alpha2)
results = rbind(lower,upper)
rownames(results) = c("Lower Estimate", "Higher Estimate")
colnames(results) = "BCA"
return(results)
} # END FUNCTION
#test
ci_bca_custom = custom_ci_bca(data = data$soil, b= 5000, alpha = 0.05, original_estimate = Ex_hat)
#ci_bca_custom
### built-in R function
# can use boot_result object from section b
# once again using boot.ci function, however argument changes to "bca"
ci_bca_r_stats = boot.ci(boot_result, type = "bca")
#ci_bca_r_stats
# interval between 3.515 and 5.515
#ci_bca_r_stats$bca
#ci_bca_r_stats$bca[4] # = lower interval end
#ci_bca_r_stats$bca[5] # = higher interval end
ci_bca_r = rbind(ci_bca_r_stats$bca[4],
ci_bca_r_stats$bca[5])
rownames(ci_bca_r) = c("Lower Estimate", "Higher Estimate")
colnames(ci_bca_r) = "BCA"
#ci_bca_r
Once again utilizing two different coding methods, my BCa results
were the following. With approximately 95% confidence, we can claim that
the population mean of lead concentration in urban sites is somewhere
between 3.244 and 5.85 mg/kg or 3.473 and 5.443 mg/kg.
d.) Asymptotic CI
Lastly, I attempted to estimate the population mean lead
concentration, E[X], via an asymptotic or “normal” approach. Asymptotic
sampling is of course predicated on the idea of the central limit
theorem, meaning that an increase in sample size is correlated with an
increase in normalization.
A fundamental difference in asymptotic and percentile interval
estimation is that the critical value term for asymptotic intervals,
which the standard error is multiplied by, is dependent on the qualities
of the normal distribution. On the other hand, the critical value term
for percentile intervals is dependent on the qualities of the bootstrap
samples’ distribution. A downside of normal bootstrap intervals is the
assumption of normally distributed data, which is not quite met to a
large degree in this instance.
### custom function
# reference section 3.1 from notes
# can use bootstrap_Ex function from part a
custom_ci_asym = function(data, b, alpha) {
n = length(data)
bootstrap_ex_estimates = numeric(b)
# call to previous function
bootstrap_ex_estimates = bootstrap_Ex(data = data, b = b)
# now estimate SE
sum_part = sum((bootstrap_ex_estimates -
mean(bootstrap_ex_estimates))^2)
se = sqrt((1/(b-1))*sum_part)
# now find and output interval
crit_value = abs(qnorm(alpha/2))
lower = mean(bootstrap_ex_estimates) - (crit_value*se)
upper = mean(bootstrap_ex_estimates) + (crit_value*se)
results = rbind(lower,upper)
colnames(results) = "Custom Asym"
rownames(results) = c("Lower Estimate", "Higher Estimate")
return(results)
}
ci_asym_custom = custom_ci_asym(data = data$soil, b = 5000, alpha = 0.05)
### built-in R function
# once again use boot_result object and boot.ci function
ci_asym_r_stats = boot.ci(boot_result, type = "norm")
# using argument "norm"; as sample size increases so does resemblance to normality as per CLT and asymptotic theory
#ci_asym_r_stats
# about 3.162 to 5.148
#ci_asym_r_stats$normal[2] = lower interval
#ci_asym_r_stats$normal[3] = higher interval
ci_asym_r = rbind(ci_asym_r_stats$normal[2],
ci_asym_r_stats$normal[3])
rownames(ci_asym_r) = c("Lower Estimate", "Higher Estimate")
colnames(ci_asym_r) = "Asymptotic"
#ci_asym_r
Per the asymptotic method, we can say with roughly 95% certainty that
the mean lead concentration amongst urban sites is either between 2.974
and 5.493 mg/kg or 3.184 and 5.135 mg/kg
e.) Interval Comparison
Below are two comparison tables displaying the results of each of the
three interval methods that have been discussed. The top table compares
results that were computed via R’s boot() function, while the latter table shows
results calculated via my custom-built functions. The code for each
custom function can be found underneath the respective sections.
## comparing the intervals created via R's boot function
r_intervals = cbind(round(ci_percent_r,3),
round(ci_bca_r,3),
round(ci_asym_r,3))
rownames(r_intervals) = c("Lower Estimate", "Higher Estimate")
kable(r_intervals,align = "c",
caption = "<span style='color:##000000;'>
Intervals via R's Boot Function </span>") %>%
kable_styling(
bootstrap_options = c("striped", "bordered"),
full_width = FALSE,
position = "center")
Intervals via R’s Boot Function
|
|
Percentile
|
BCA
|
Asymptotic
|
|
Lower Estimate
|
3.456
|
3.473
|
3.184
|
|
Higher Estimate
|
5.413
|
5.443
|
5.135
|
## comparing the intervals created via my custom functions
custom_intervals = cbind(round(ci_percent_custom,3),
round(ci_bca_custom,3),
round(ci_asym_custom,3))
rownames(custom_intervals) = c("Lower Estimate", "Higher Estimate")
colnames(custom_intervals) = c("Percentile", "BCA", "Asymptotic")
kable(custom_intervals,align = "c",
caption = "<span style='color:##000000;'>
Intervals via Custom-Built Function </span>") %>%
kable_styling(
bootstrap_options = c("striped", "bordered"),
full_width = FALSE,
position = "center")
Intervals via Custom-Built Function
|
|
Percentile
|
BCA
|
Asymptotic
|
|
Lower Estimate
|
3.154
|
3.244
|
2.974
|
|
Higher Estimate
|
5.565
|
5.850
|
5.493
|
Final Recommendation
Taking everything into consideration, I would suggest moving forward
under the assumption that the BCa interval is the most
accurate.
As I alluded to in a previous section, use of the the asymptotic
interval generally assumes a relatively normal distribution of the
population of interest. In this scenario, we have not assumed normality
for the population of urban sites’ lead concentrations, but rather
log-normality. Beyond that, the BCa interval method is the most robust
in the face of skewness and bias. Its bias correction component utilizes
the median statistic to counterbalance outliers, something that is
certainly relevant to both our sample data and bootstrap distribution of
E[X] estimates.
Below are the histograms for both the sample data, and population
mean bootstrap estimates, this time with the 90th percentile of the
dataset marked. This allows us to see how great of a rightward skew is
applicable to this particular analysis.
hist(data$soil,
main = "Distribution of Concentrations",
xlab = "Concentrations (mg/kg)",
prob = TRUE,
col = "lightblue"
)
# Data point 90th percentile
segments(
x0 = quantile(data$soil,0.9),
y0 = 0,
x1 = quantile(data$soil,0.9),
y1 = 1,
col = "black",
lwd = 4,
lty = 3
)
legend("topright",
legend = "90th Percentile",
col = "black",
lwd = 4,
lty = 3,
box.lwd=3)
box(lwd=3)

hist(Ex_sampling_distribution,
main = "Sampling Distribution of Population Mean Estimates",
xlab = "Concentrations (mg/kg)",
prob = TRUE,
col = "lightblue"
)
# Data point 90th percentile
segments(
x0 = quantile(Ex_sampling_distribution,0.9),
y0 = 0,
x1 = quantile(Ex_sampling_distribution,0.9),
y1 = 1,
col = "black",
lwd = 4,
lty = 3
)
legend("topright",
legend = "90th Percentile",
col = "black",
lwd = 4,
lty = 3,
box.lwd=3)
box(lwd=3)

LS0tCnRpdGxlOiAiQm9vdHN0cmFwIENvbmZpZGVuY2UgSW50ZXJ2YWxzIgphdXRob3I6ICJDaHJpcyBCYWhtIgpkYXRlOiAiTWFyY2ggMjksIDIwMjYiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogdHJ1ZQogICAgICBzbW9vdGhfc2Nyb2xsOiB0cnVlCiAgICB0b2NfZGVwdGg6IDQKICAgIGZpZ193aWR0aDogNgogICAgZmlnX2hlaWdodDogNAogICAgZmlnX2NhcHRpb246IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdGhlbWU6IGx1bWVuCiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDQKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICB3b3JkX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDQKLS0tCgpgYGB7Y3NzLCBlY2hvID0gRkFMU0V9CmRpdiNUT0MgbGkgeyAgICAgLyogdGFibGUgb2YgY29udGVudCAgKi8KICAgIGxpc3Qtc3R5bGU6dXBwZXItcm9tYW47CiAgICBiYWNrZ3JvdW5kLWltYWdlOm5vbmU7CiAgICBiYWNrZ3JvdW5kLXJlcGVhdDpub25lOwogICAgYmFja2dyb3VuZC1wb3NpdGlvbjowOwp9CgpoMS50aXRsZSB7ICAgIC8qIGxldmVsIDEgaGVhZGVyIG9mIHRpdGxlICAqLwogIGZvbnQtc2l6ZTogMjRweDsKICBmb250LXdlaWdodDogYm9sZDsKICBjb2xvcjogRGFya1JlZDsKICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCmg0LmF1dGhvciB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgZm9udC1zaXplOiAxOHB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogIGNvbG9yOiBEYXJrUmVkOwogIHRleHQtYWxpZ246IGNlbnRlcjsKfQoKaDQuZGF0ZSB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgZm9udC1zaXplOiAxOHB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogIGNvbG9yOiBEYXJrQmx1ZTsKICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCmgxIHsgLyogSGVhZGVyIDEgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICAgIGZvbnQtc2l6ZTogMjBweDsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogZGFya3JlZDsKICAgIHRleHQtYWxpZ246IGNlbnRlcjsKfQoKaDIgeyAvKiBIZWFkZXIgMiAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogICAgZm9udC1zaXplOiAxOHB4OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBuYXZ5OwogICAgdGV4dC1hbGlnbjogbGVmdDsKfQoKaDMgeyAvKiBIZWFkZXIgMyAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogICAgZm9udC1zaXplOiAxNnB4OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBuYXZ5OwogICAgdGV4dC1hbGlnbjogbGVmdDsKfQoKaDQgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogICAgZm9udC1zaXplOiAxNHB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogZGFya3JlZDsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KCi8qIEFkZCBkb3RzIGFmdGVyIG51bWJlcmVkIGhlYWRlcnMgKi8KLmhlYWRlci1zZWN0aW9uLW51bWJlcjo6YWZ0ZXIgewogIGNvbnRlbnQ6ICIuIjsKfQpgYGAKCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQojIGNvZGUgY2h1bmsgc3BlY2lmaWVzIHdoZXRoZXIgdGhlIFIgY29kZSwgd2FybmluZ3MsIGFuZCBvdXRwdXQgCiMgd2lsbCBiZSBpbmNsdWRlZCBpbiB0aGUgb3V0cHV0IGZpbGVzLgoKaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7ICAgICAgICAgICAgICAgICAgICAgICMgdXNlIGNvbmRpdGlvbmFsIHN0YXRlbWVudCB0byBkZXRlY3QKICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKSAgICAgICAgICAgICAgICAgICMgd2hldGhlciBhIHBhY2thZ2Ugd2FzIGluc3RhbGxlZCBpbgogICBsaWJyYXJ5KGtuaXRyKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB5b3VyIG1hY2hpbmUuIElmIG5vdCwgaW5zdGFsbCBpdCBhbmQKfSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbG9hZCBpdCB0byB0aGUgd29ya2luZyBkaXJlY3RvcnkuCgppZiAoIXJlcXVpcmUodGlkeXZlcnNlKSkge2xpYnJhcnkodGlkeXZzZXJzZSl9IAoKaWYgKCFyZXF1aXJlKEdHYWxseSkpIHtsaWJyYXJ5KEdHYWxseSl9IAoKaWYgKCFyZXF1aXJlKGthYmxlRXh0cmEpKSB7bGlicmFyeShrYWJsZUV4dHJhKX0gCgppZiAoIXJlcXVpcmUoZ2dwbG90MikpIHtsaWJyYXJ5KGdncGxvdDIpfSAKCmlmICghcmVxdWlyZShjYXIpKSB7bGlicmFyeShjYXIpfSAKCmlmICghcmVxdWlyZShkcGx5cikpIHtsaWJyYXJ5KGRwbHlyKX0gCgppZiAoIXJlcXVpcmUocGFuZGVyKSkge2xpYnJhcnkocGFuZGVyKX0gCgppZiAoIXJlcXVpcmUoZm9yZWNhc3QpKSB7bGlicmFyeShmb3JlY2FzdCl9IAoKaWYgKCFyZXF1aXJlKGx1YnJpZGF0ZSkpIHtsaWJyYXJ5KGx1YnJpZGF0ZSl9IAoKaWYgKCFyZXF1aXJlKCJzY2FsZXMiKSkgewppbnN0YWxsLnBhY2thZ2VzKCJzY2FsZXMiKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKbGlicmFyeSgic2NhbGVzIikgCn0KCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKCWVjaG8gPSBUUlVFLAoJbWVzc2FnZSA9IEZBTFNFLAoJd2FybmluZyA9IEZBTFNFLAoJY29tbWVudCA9IE5BLAoJcmVzdWx0cyA9IFRSVUUsCglmaWcuYWxpZ24gPSAiY2VudGVyIgopCmBgYAoKCiMgRGF0YSBhbmQgU2V0dXAKCmBgYHtyfQpkYXRhID0gcmJpbmQuZGF0YS5mcmFtZSgwLjg1LCAxLjIzLCAwLjkyLCAzLjQ1LCAyLjExLCAxLjU2LCA0Ljg5LCAyLjM0LCAxLjc4LCA2LjcyLCAwLjk1LCAxLjM0LCA4LjkxLCAKMi42NywgMS44OSwgNS40MywgMS4xMiwgMy43OCwgMi40NSwgNy42NSwgMS4wNSwgMS40NSwgMTIuMzQsIDIuODksIDIuMDEsIDQuNTYsIAoxLjIzLCA0LjMyLCAyLjY3LCA5Ljg3LCAwLjk5LCAxLjU2LCAxNS4yMywgMy4xMiwgMi4zNCwgMy44OSwgMS4zNCwgNS42NywgMi44OSwgCjExLjQ1LCAxLjEyLCAxLjY3LCAxOC45MCwgMy40NSwgMi41NiwgMy40NSwgMS40NSwgNi43OCwgMy4xMiwgMTQuNTYsIDEuMjMsIDEuNzgsIAoyMi4zNCwgMy43OCwgMi43OCkKY29sbmFtZXMoZGF0YSkgPSAic29pbCIKYGBgCkZvciB0aGlzIGFuYWx5c2lzLCB3ZSB3aWxsIGJlIGV4YW1pbmluZyBhIGRhdGFzZXQgb2YgYHIgbnJvdyhkYXRhKWAgdXJiYW4gZ2FyZGVuIHNpdGVzJyBzb2lsIGxlYWQgY29uY2VudHJhdGlvbnMuIFRoZXNlIGNvbmNlbnRyYXRpb25zIG9mIHNvaWwgbGVhZCAoY2hlbWljYWwgcHJlZml4ICJQYiIpIGFyZSBtZWFzdXJlZCBpbiBtZy9rZy4gTW92aW5nIGZvcndhcmQgaW4gdGhpcyBhbmFseXNpcywgd2Ugd2lsbCBhc3N1bWUgdGhlIGRhdGEsIGFuZCBicm9hZGVyIHBvcHVsYXRpb24gb2YgbGVhZCBjb25jZW50cmF0aW9ucyBpbiB1cmJhbiBzaXRlcyBmb2xsb3cgYSAqKmxvZy1ub3JtYWwgZGlzdHJpYnV0aW9uKiouIFRoaXMgYXNzdW1wdGlvbiBpcyBwcmVkaWNhdGVkIG9uIHRoZSBmYWN0IHRoYXQgc2FtcGxlcyBzdWNoIGFzIHdoYXQgd2UgYXJlIHdvcmtpbmcgd2l0aCBhcmUgdHlwaWNhbGx5IG5vdGFibHkgcmlnaHQgc2tld2VkIGFuZCBieSBuYXR1cmUgbXVzdCBiZSBub24tbmVnYXRpdmUuCgpTdW1tYXJ5IHN0YXRpc3RpY3MgYW5kIGEgaGlzdG9ncmFtIG9mIHRoZSBkYXRhc2V0IGF0IGhhbmQgYXJlIGJlbG93LgoKYGBge3IsIGZpZy5oZWlnaHQ9NS41LCBmaWcud2lkdGg9Ni41fQpzdW1fc3RhdHNfdGFibGUgPSBmdW5jdGlvbih2YXJpYWJsZSl7CiAgdGFibGUgPSBjYmluZCgKICAgIHJvdW5kKG1pbih2YXJpYWJsZSksMiksCiAgICByb3VuZChxdWFudGlsZSh2YXJpYWJsZSwgMC4yNSksMiksCiAgICByb3VuZChtZWRpYW4odmFyaWFibGUpLDIpLAogICAgcm91bmQobWVhbih2YXJpYWJsZSksMiksCiAgICByb3VuZChxdWFudGlsZSh2YXJpYWJsZSwgMC43NSksMiksCiAgICByb3VuZChtYXgodmFyaWFibGUpLDIpCiAgKQogIGNvbG5hbWVzKHRhYmxlKSA9IGMoIk1pbiIsICJRMSIsICJNZWQiLCAiTWVhbiIsICJRMyIsICJNYXgiKQogIHJvd25hbWVzKHRhYmxlKSA9IE5VTEwKICByZXR1cm4odGFibGUpCn0KClN1bW1hcnlfVGFibGUgPSBzdW1fc3RhdHNfdGFibGUodmFyaWFibGUgPSBkYXRhJHNvaWwpCmthYmxlKFN1bW1hcnlfVGFibGUsYWxpZ24gPSAiYyIsCiAgICAgIGNhcHRpb24gPSAiPHNwYW4gc3R5bGU9J2NvbG9yOiMjMDAwMDAwOyc+CiAgICAgIFN1bW1hcnkgU3RhdHMgb2YgU29pbCBUaW1lcyA8L3NwYW4+IikgJT4lCiAga2FibGVfc3R5bGluZygKICAgIGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJib3JkZXJlZCIpLAogICAgZnVsbF93aWR0aCA9IEZBTFNFLAogICAgcG9zaXRpb24gPSAiY2VudGVyIikKCgpoaXN0KGRhdGEkc29pbCwgCiAgICAgbWFpbiA9ICJEaXN0cmlidXRpb24gb2YgQ29uY2VudHJhdGlvbnMiLAogICAgIHhsYWIgPSAiQ29uY2VudHJhdGlvbnMgKG1nL2tnKSIsCiAgICAgcHJvYiA9IFRSVUUsCiAgICAgY29sID0gImxpZ2h0Ymx1ZSIKKQpib3gobHdkPTMpCgpgYGAKClVzaW5nIG91ciBhdmFpbGFibGUgc2FtcGxlIGRhdGEsIGFuZCBvdXIgcHJlc3VtcHRpb24gb2YgbG9nLW5vcm1hbGl0eSwgdGhlIGZvbGxvd2luZyBzZWN0aW9ucyB3aWxsIGNvbnNpc3Qgb2YgYXR0ZW1wdHMgdG8gZXN0aW1hdGUgdGhlICoqYXZlcmFnZSBsZWFkIGNvbmNlbnRyYXRpb25zKiogKG1nL2tnKSBhY3Jvc3MgdGhlICoqYnJvYWQgcG9wdWxhdGlvbioqIG9mIHVyYmFuIHNpdGVzIHNpbWlsYXIgdG8gdGhvc2UgdGhhdCB3ZXJlIG9ic2VydmVkIGZvciBvdXIgc2FtcGxlLiBGb3IgbWF0aGVtYXRpY2FsIG5vdGF0aW9uIHB1cnBvc2VzLCB0aGlzIG1lYW4gbGVhZCBjb25jZW50cmF0aW9uIHdpbGwgYmUgZGVub3RlZCBhcyAqKkVbWF0qKi4gSSB3aWxsIHBlcmZvcm0gYm90aCBwb2ludCBlc3RpbWF0aW9uIGFuZCBpbnRlcnZhbCBlc3RpbWF0aW9uLgoKVG8gZmluZCBhbiBpbml0aWFsIHBvaW50IGVzdGltYXRlIGZvciBFW1hdLCBJIHV0aWxpemVkIHRoZSBNTEUgZXN0aW1hdGlvbiBmb3JtdWxhcyBmb3IgdGhlIGxvZyBub3JtYWwgZGlzdHJpYnV0aW9uIGFzIHdlbGwgYXMgc3RhbmRhcmQgYWxnZWJyYWljIHN1YnN0aXR1dGlvbi4gVGhlIHJlbGV2YW50IGZvcm11bGFzIGFyZSB2aXNpYmxlIGJlbG93LgoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCIvVXNlcnMvY2hyaXNiYWhtL0xpYnJhcnkvTW9iaWxlIERvY3VtZW50cy9jb21+YXBwbGV+Q2xvdWREb2NzL1dlc3QgQ2hlc3Rlci9TcHJpbmcgMjAyNi9TVEEgNTA2IC0gR3JhZCBNYXRoIFN0YXQgMiAvU1RBIDUwNiBSIEZvbGRlci9XZWVrIDkgLSBCb290c3RyYXAgQ29uZmlkZW5jZSBJbnRlcnZhbHMvTUxFLnBuZyIpCgprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiL1VzZXJzL2NocmlzYmFobS9MaWJyYXJ5L01vYmlsZSBEb2N1bWVudHMvY29tfmFwcGxlfkNsb3VkRG9jcy9XZXN0IENoZXN0ZXIvU3ByaW5nIDIwMjYvU1RBIDUwNiAtIEdyYWQgTWF0aCBTdGF0IDIgL1NUQSA1MDYgUiBGb2xkZXIvV2VlayA5IC0gQm9vdHN0cmFwIENvbmZpZGVuY2UgSW50ZXJ2YWxzL0VYLnBuZyIpCmBgYAoKCmBgYHtyfQpzYW1wbGVfbWVhbiA9IG1lYW4oZGF0YSRzb2lsKQoKICAjIGJhc2VkIG9uIEdJVkVOIGZvcm11bGEgaW4gYXNzaWdubWVudCBpbnN0cnVjdGlvbnMgZm9yIE1MRSBlc3RpbWF0b3Igb2YgbXUKbXVfaGF0ID0gc3VtKGxvZyhkYXRhJHNvaWwpKS9ucm93KGRhdGEpCgogIyBiYXNlZCBvbiBHSVZFTiBmb3JtdWxhIGluIGFzc2lnbm1lbnQgaW5zdHJ1Y3Rpb25zIGZvciBNTEUgZXN0aW1hdG9yIG9mIHRoZXRhIHNxdWFyZWQKdGhldGFfc3F1YXJlZF9oYXQgPSBzdW0oKGxvZyhkYXRhJHNvaWwpIC0gbXVfaGF0KV4yKS9ucm93KGRhdGEpCgpFeF9oYXQgPSBleHAobXVfaGF0ICsgKHRoZXRhX3NxdWFyZWRfaGF0LzIpKQoKIyBFW3hdID0gbG9nbm9ybWFsIHBvcHVsYXRpb24gbWVhbgpgYGAKClBlciB0aGlzIG1hdGhlbWF0aWNhbCBzZXR1cCwgb3VyIHN0YXJ0aW5nIGVzdGltYXRlIG9mIHBvcHVsYXRpb24gYXZlcmFnZSBsZWFkIGNvbmNlbnRyYXRpb24gaXMgYXBwcm94aW1hdGVseSBgciByb3VuZChFeF9oYXQsMylgLiAKCgojIGEuKSBCb290c3RyYXAgU2FtcGxpbmcgRGlzdHJpYnV0aW9uCk5leHQsIEkgdXNlZCBib290c3RyYXBwaW5nIHRvIGFjcXVpcmUgYSBicm9hZGVyIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbiBvZiB0aGUgYXZlcmFnZSBsZWFkIGNvbmNlbnRyYXRpb24gcG9pbnQgZXN0aW1hdGUuIEFmdGVyIHBlcmZvcm1pbmcgNSwwMDAgaXRlcmF0aW9ucyBvZiBib290c3RyYXAgc2FtcGxpbmcsIGFuZCBjYWxjdWxhdGluZyBFW1hdIGZvciBlYWNoIHNhbXBsZSwgdGhlIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbiBvZiBwb3B1bGF0aW9uIG1lYW4gZXN0aW1hdGVzIGlzIHZpc2libGUgYmVsb3cuCgpgYGB7ciwgZmlnLmhlaWdodD01LjUsIGZpZy53aWR0aD02LjV9CmxpYnJhcnkoYm9vdCkKc2V0LnNlZWQoMTAwKSAjIHNldHRpbmcgc2VlZCBub3cgZm9yIGVudGlyZSBwcm9ncmFtCgpib290c3RyYXBfRXggPSBmdW5jdGlvbihkYXRhLCBiKSB7CiAgbiA9IGxlbmd0aChkYXRhKQogIGJvb3RzdHJhcF9leF9lc3RpbWF0ZXMgPSBudW1lcmljKGIpCiAgCiAgICAjIFNUQVJUIEZPUiBMT09QCiAgIGZvciAoaSBpbiAxOmIpewogICAgIGJvb3Rfc2FtcGxlID0gc2FtcGxlKGRhdGEsIHNpemUgPSBuLCByZXBsYWNlPSBUUlVFKQogICAgIG11X2hhdFtpXSA9IHN1bShsb2coYm9vdF9zYW1wbGUpKS9uCiAgICAgICAgIyBtYWtlIHN1cmUgdG8gdXNlIGJvb3Rfc2FtcGxlIGluIHRoaXMgbGluZSwgcHJldmlvdXNseSBJIHdhcyB1c2luZyBkYXRhIGluc2lkZSB0aGUgbG9nIGZ1bmN0aW9uIGFuZCBteSBvdXRwdXQgd2FzIHRoZSBzYW1lIHZhbHVlIGZvciBldmVyeSBlbGVtZW50IG9mIHRoZSB2ZWN0b3IKICAgICAKICAgICB0aGV0YV9zcXVhcmVkX2hhdFtpXSA9IHN1bSgobG9nKGJvb3Rfc2FtcGxlKSAtIG11X2hhdFtpXSleMikvbgogICAgIAogICAgIGJvb3RzdHJhcF9leF9lc3RpbWF0ZXNbaV0gPSBleHAobXVfaGF0W2ldICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHRoZXRhX3NxdWFyZWRfaGF0W2ldLzIpKQogICB9CiAgICAjIEVORCBGT1IgTE9PUAogIAogIHJldHVybihib290c3RyYXBfZXhfZXN0aW1hdGVzKSAjIGZpbmFsIG91dHB1dAp9CgogICMgYWx3YXlzIHJlbWVtYmVyIHRvIHNldCB0aGUgc2VlZCBmb3IgY29uc2lzdGVudCByZXBldGl0aW9uCkV4X3NhbXBsaW5nX2Rpc3RyaWJ1dGlvbiA9IGJvb3RzdHJhcF9FeChkYXRhID0gZGF0YSRzb2lsLCBiID0gNTAwMCkKCmhpc3QoRXhfc2FtcGxpbmdfZGlzdHJpYnV0aW9uLCAKICAgICBtYWluID0gIlNhbXBsaW5nIERpc3RyaWJ1dGlvbiBvZiBQb3B1bGF0aW9uIE1lYW4gRXN0aW1hdGVzIiwKICAgICB4bGFiID0gIkNvbmNlbnRyYXRpb25zIChtZy9rZykiLAogICAgIHByb2IgPSBUUlVFLAogICAgIGNvbCA9ICJsaWdodGJsdWUiCikKCmJveChsd2Q9MykKYGBgCgpBcyB3ZSBjYW4gc2VlIGZyb20gb3VyIGhpc3RvZ3JhbSwgdGhlIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbiBvZiBFW1hdIGVzdGltYXRlcyBpcyByb3VnaGx5IGxvZy1ub3JtYWwgZGlzdHJpYnV0ZWQsIHdpdGggYSByaWdodHdhcmQgc2tldy4gVGhlIG1lYW4gb2Ygb3VyIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbiBpcyByb3VnaGx5IGByIHJvdW5kKG1lYW4oRXhfc2FtcGxpbmdfZGlzdHJpYnV0aW9uKSwzKWAsIHdoaWNoIGlzIGV4dHJhb3JkaW5hcmlseSBjbG9zZSB0byB0aGUgcG9wdWxhdGlvbiBtZWFuIGVzdGltYXRlIGFjcXVpcmVkIHN0cmljdGx5IGZyb20gb3VyIGF2YWlsYWJsZSBzYW1wbGUgZGF0YSBvZiBgciByb3VuZChFeF9oYXQsMylgLgoKCiMgYi4pIEJvb3RzdHJhcCBQZXJjZW50aWxlIENJCkFmdGVyIGZpbmRpbmcgYSBzYW1wbGUgZGlzdHJpYnV0aW9uLCBJIG9uY2UgYWdhaW4gZW1wbG95IGJvb3RzdHJhcHBpbmcsIHRoaXMgdGltZSB0byBjb25zdHJ1Y3QgYSBwZXJjZW50aWxlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgZm9yIEVbWF0uIFBlcmNlbnRpbGUgaW50ZXJ2YWxzIGFyZSBhIHNvbGlkIGZvdW5kYXRpb24gZm9yIHBhcmFtZXRlciBlc3RpbWF0aW9uLiBUaGV5IGFyZSB0aGUgbGVhc3QgbWF0aGVtYXRpY2FsbHkgY29tcGxleCBvZiBhbGwgY29uZmlkZW5jZSBpbnRlcnZhbHMsIHJlbHlpbmcgb24gdGhlIGxlZnQgYW5kIHJpZ2h0IHF1YW50aWxlIGN1dG9mZnMgb2Ygb3VyIGRpc3RyaWJ1dGlvbiwgYXMgcGVyIHRoZSBjaG9zZW4gbGV2ZWwgb2YgJFxhbHBoYSQuIFNpbmNlIHRoZSBjb25maWRlbmNlIGxldmVsIGZvciB0aGlzIGludGVydmFsIHdpbGwgYmUgOTUlLCAkXGFscGhhJCA9IDAuMDUgaW4gdGhpcyBpbnN0YW5jZS4KCmBgYHtyfQpjdXN0b21fY2lfcGVyY2VudGlsZSA9IGZ1bmN0aW9uKGRhdGEsIGIsIGFscGhhKXsKICBuID0gbGVuZ3RoKGRhdGEpCiAgYm9vdHN0cmFwX2V4X2VzdGltYXRlcyA9IG51bWVyaWMoYikKICBtdV9oYXQgPSBudW1lcmljKGIpCiAgdGhldGFfc3F1YXJlZF9oYXQgPSBudW1lcmljKGIpCiAgCiAgIyBmb3IgdGhpcyBmdW5jdGlvbiBjYW4gdXNlIHRoZSBzYW1lIGJvb3RzdHJhcHBpbmcgcHJvY2VkdXJlIGZyb20gYWJvdmUgdG8gb2J0YWluIHRoZSBib290c3RyYXBfZXggZXN0aW1hdGVzIHZlY3RvcgogICAgIyBTVEFSVCBGT1IgTE9PUAogICAgZm9yKGkgaW4gMTpiKXsKICAgICBib290X3NhbXBsZSA9IHNhbXBsZShkYXRhLCBzaXplID0gbiwgcmVwbGFjZT0gVFJVRSkKICAgICBtdV9oYXRbaV0gPSBzdW0obG9nKGJvb3Rfc2FtcGxlKSkvbgogICAgIHRoZXRhX3NxdWFyZWRfaGF0W2ldID0gc3VtKChsb2coYm9vdF9zYW1wbGUpIC0gbXVfaGF0W2ldKV4yKS9uCiAgICAgYm9vdHN0cmFwX2V4X2VzdGltYXRlc1tpXSA9IGV4cChtdV9oYXRbaV0gKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAodGhldGFfc3F1YXJlZF9oYXRbaV0vMikpCiAgICB9ICMgRU5EIEZPUiBMT09QCiAgCiAgCiAgc29ydF9ib290c3RyYXBfZXhfZXN0aW1hdGVzID0gc29ydChib290c3RyYXBfZXhfZXN0aW1hdGVzKQogIGxvd2VyX3F1YW50ID0gKGFscGhhLzIpCiAgaGlnaGVyX3F1YW50ID0gKDEtKGFscGhhLzIpKQogIGxvd2VyX2VzdGltYXRlID0gcXVhbnRpbGUoc29ydF9ib290c3RyYXBfZXhfZXN0aW1hdGVzLCBsb3dlcl9xdWFudCkKICBoaWdoZXJfZXN0aW1hdGUgPSBxdWFudGlsZShzb3J0X2Jvb3RzdHJhcF9leF9lc3RpbWF0ZXMsIGhpZ2hlcl9xdWFudCkKICByZXN1bHRzID0gcmJpbmQobG93ZXJfZXN0aW1hdGUsCiAgICAgICAgICAgICAgICAgIGhpZ2hlcl9lc3RpbWF0ZSkKICBjb2xuYW1lcyhyZXN1bHRzKSA9ICJDdXN0b20gUGVyY2VudCIKICByb3duYW1lcyhyZXN1bHRzKSA9IGMoIkxvd2VyIEVzdGltYXRlIiwgIkhpZ2hlciBFc3RpbWF0ZSIpCiAKICByZXR1cm4gKHJlc3VsdHMpCn0KCmNpX3BlcmNlbnRfY3VzdG9tID0gY3VzdG9tX2NpX3BlcmNlbnRpbGUoZGF0YSRzb2lsLCBiID0gNTAwMCwgYWxwaGEgPSAwLjA1KQoKI2NpX3BlcmNlbnRfY3VzdG9tCmBgYAoKYGBge3J9CiMjIyBidWlsdC1pbiBSIGZ1bmN0aW9uCgojIyMjIyMKIyByZWZlcmVuY2Ugc2VjdGlvbiAzLjIuMyBvZiBub3RlcwoKIyMgY3JlYXRlIHN0YXQgZnVuY3Rpb24gdGhhdCBmaW5kcyBFW1hdIGZyb20gYSBzaW5ndWxhciBib290c3RyYXAgc2FtcGxlIG9mIG91ciBkYXRhCgpmaW5kX2V4ID0gZnVuY3Rpb24oZGF0YSwgaW5kaWNlcyl7CiAgbiA9IGxlbmd0aChkYXRhKQogIHNhbXBsZV9kYXRhID0gZGF0YVtpbmRpY2VzXQogIAogIG11X2hhdCA9IHN1bShsb2coc2FtcGxlX2RhdGEpKS9uCiAgdGhldGFfc3F1YXJlZF9oYXQgPSBzdW0oKGxvZyhkYXRhKSAtIG11X2hhdCleMikvbgogIAogIGV4X2VzdGltYXRlID0gZXhwKG11X2hhdCArIAogICAgICAgICAgICAgICAgICAgICAgKHRoZXRhX3NxdWFyZWRfaGF0LzIpKQp9CiAgIyBub3cgdGhhdCB0aGlzIGZ1bmN0aW9uIGlzIG1hZGUsIHBsdWcgaXQgaW50byB0aGUgYm9vdCBmdW5jdGlvbgoKYm9vdF9yZXN1bHQgPSBib290KGRhdGEkc29pbCwgZmluZF9leCwgUiA9IDUwMDApCgpjaV9wZXJjZW50X3Jfc3RhdHMgPSBib290LmNpKGJvb3RfcmVzdWx0LCB0eXBlID0gInBlcmMiKQogICMgTm90ZTogYm9vdC5jaSBmdW5jdGlvbiBkZWZhdWx0cyB0byA5NSUgY29uZmlkZW5jZSBsZXZlbCwgY2FuIGNoYW5nZSB0aGlzIHVzaW5nIHRoZSBjb25mID0gYXJndW1lbnQKCiNjaV9wZXJjZW50X3Jfc3RhdHMKCiNjaV9wZXJjZW50X3Jfc3RhdHMkcGVyY2VudAoKI2NpX3BlcmNlbnRfcl9zdGF0cyRwZXJjZW50WzRdICMgPSBsb3dlciBpbnRlcnZhbCBlbmQKI2NpX3BlcmNlbnRfcl9zdGF0cyRwZXJjZW50WzVdICMgPSBoaWdoZXIgaW50ZXJ2YWwgZW5kCgpjaV9wZXJjZW50X3IgPSByYmluZChjaV9wZXJjZW50X3Jfc3RhdHMkcGVyY2VudFs0XSwKICAgICAgICAgICAgICAgICAgICAgY2lfcGVyY2VudF9yX3N0YXRzJHBlcmNlbnRbNV0pCgpyb3duYW1lcyhjaV9wZXJjZW50X3IpID0gYygiTG93ZXIgRXN0aW1hdGUiLCAiSGlnaGVyIEVzdGltYXRlIikKY29sbmFtZXMoY2lfcGVyY2VudF9yKSA9ICJQZXJjZW50aWxlIgoKI2NpX3BlcmNlbnRfcgpgYGAKClRvIGNvbnN0cnVjdCB0aGUgcGVyY2VudGlsZSBjb25maWRlbmNlIGludGVydmFsIGZvciB0aGUgbWVhbiBzb2lsIGNvbmNlbnRyYXRpb24gYW1vbmdzdCB0aGUgYnJvYWRlciBwb3B1bGF0aW9uIG9mIHVyYmFuIHNpdGVzLCBJIHJlc29ydGVkIHRvIGJvdGggY3VzdG9tIGZ1bmN0aW9uIGNyZWF0aW9uIGFzIHdlbGwgYXMgUidzIDxzcGFuIHN0eWxlPSJjb2xvcjpibHVlOyI+Ym9vdCgpPC9zcGFuPiBmdW5jdGlvbi4gUGVyIHRoZXNlIHJlc3VsdHMsIHdlIGNhbiBzYXkgd2l0aCBhcHByb3hpbWF0ZWx5IDk1JSBjb25maWRlbmNlIHRoYXQgdGhlIHBvcHVsYXRpb24gbWVhbiBpcyBlaXRoZXIgYmV0d2VlbiBgciByb3VuZChjaV9wZXJjZW50X2N1c3RvbVsxXSwzKWAgYW5kIGByIHJvdW5kKGNpX3BlcmNlbnRfY3VzdG9tWzJdLDMpYCBtZy9rZyAqb3IqIGByIHJvdW5kKGNpX3BlcmNlbnRfclsxXSwzKWAgYW5kIGByIHJvdW5kKGNpX3BlcmNlbnRfclsyXSwzKWAgbWcva2cuCgojIGMuKSBCb290c3RyYXAgQkNhIENJIApBZnRlciBjcmVhdGluZyB0aGUgcGVyY2VudGlsZSBpbnRlcnZhbHMsIEkgdGhlbiBtb3ZlZCBmb3J3YXJkIHdpdGggYm9vdHN0cmFwIEJDYSAoYmlhcy1jb3JyZWN0ZWQgYW5kIGFjY2VsZXJhdGVkKSBpbnRlcnZhbHMuIEJDYSBpbnRlcnZhbHMgYXJlIGEgbW9yZSBzb3BoaXN0aWNhdGVkIG9wdGlvbiB0byB0aGVpciBzdGFuZGFyZCBwZXJjZW50aWxlIGNvdW50ZXJwYXJ0cy4gVGhleSBhcmUgZXNwZWNpYWxseSB2YWx1ZWQgd2hlbiBkZWFsaW5nIHdpdGggc2tld2VkIGRpc3RyaWJ1dGlvbnMvZGF0YSBvciBiaWFzZWQgZXN0aW1hdG9ycywgc29tZXRoaW5nIHRoYXQgdGhlIHBlcmNlbnRpbGUgb3B0aW9uIGRvZXMgKm5vdCogYWNjb3VudCBmb3IgbmVhcmx5IGFzIG11Y2guCgpgYGB7cn0KIyMjIGN1c3RvbSBmdW5jdGlvbgojIHJlZmVyZW5jZSBzZWN0aW9uIDMuMy4yCgojIFNUQVJUIEZVTkNUSU9OCmN1c3RvbV9jaV9iY2EgPSBmdW5jdGlvbihkYXRhLCBiLCBhbHBoYSwgb3JpZ2luYWxfZXN0aW1hdGUpeyAKICBuID0gbGVuZ3RoKGRhdGEpCiAgYm9vdHN0cmFwX2V4X2VzdGltYXRlcyA9IG51bWVyaWMoYikKICAKIyBiaWFzIGNvcnJlY3Rpb24gIm1lYXN1cmVzIG1lZGlhbiBiaWFzIGJ5IGNvbXBhcmluZyBib290c3RyYXAgZXN0aW1hdGVzIHRvIHRoZSBvcmlnaW5hbCBlc3RpbWF0ZS4iCiAgCiAgcHJvcF9sZXNzID0gMCAjIGluaXRpYWxpemUgY291bnRpbmcgdmFyaWFibGUgYXQgPSAwCiAgCiAgZm9yIChpIGluIDE6Yil7ICMgU1RBUlQgQk9PVFNUUkFQIExPT1AKICAgICBib290X3NhbXBsZSA9IHNhbXBsZShkYXRhLCBzaXplID0gbiwgcmVwbGFjZT0gVFJVRSkKICAgICBtdV9oYXRbaV0gPSBzdW0obG9nKGJvb3Rfc2FtcGxlKSkvbgogICAgIHRoZXRhX3NxdWFyZWRfaGF0W2ldID0gc3VtKChsb2coYm9vdF9zYW1wbGUpIC0gbXVfaGF0W2ldKV4yKS9uCiAgICAgYm9vdHN0cmFwX2V4X2VzdGltYXRlc1tpXSA9IGV4cChtdV9oYXRbaV0gKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAodGhldGFfc3F1YXJlZF9oYXRbaV0vMikpCiAgICAgCiAgICAgIyBiaWFzIGNvcnJlY3Rpb24gZmFjdG9yIGJlbG93CiAgICAgIyMgY2FuIHVzZSBub3JtYWwgaWYgc3RhdGVtZW50IHN5bnRheCwganVzdCBpbmNvcnBvcmF0ZSB0aGUgW2ldIHRvIGluZGljYXRlIHRoYXQgdGhlIHN0YXRlbWVudCBpcyBldmFsdWF0aW5nIGVsZW1lbnQgYnkgZWxlbWVudAogICAgICAgICBpZiAoYm9vdHN0cmFwX2V4X2VzdGltYXRlc1tpXSA8IG9yaWdpbmFsX2VzdGltYXRlKXsKICAgICAgICAgIHByb3BfbGVzcyA9IHByb3BfbGVzcyArIDEKICAgICAgICAgfQogICAgIH0gIyBFTkQgQk9PVFNUUkFQIExPT1AKICAgICAKICAgICAgIyMjIyBTVEFSVCBDT1JSRUNUSU9OIENBTENVTEFUSU9OICAKICAgICAgICBwcm9wX2xlc3MgPSBwcm9wX2xlc3MvYgogICAgICAgIHowID0gcW5vcm0ocHJvcF9sZXNzKQogICAgICAgICMgbm93IGhhdmUgYmlhcyBjb3JyZWN0aW9uCiAgICAgICMjIyMgRU5EIEJJQVMgQ09SUkVDVElPTiBDQUxDVUxBVElPTgogIAogICAgICAgIAogICAgICAjIyMjIFNUQVJUIEFDQ0VMRVJBVElPTiBDQUxDVUxBVElPTgogICAgICAgICAgIyBnb29kIHByYWN0aWNlIHRvIHVzZSBkaWZmZXJlbnQgImNvdW50aW5nIHZhcmlhYmxlIHRoYW4gd2FzIGVhcmxpZXIgdXNlZCBpbiBmdW5jdGlvbiwgSSdsbCB1c2UgaiBpbnN0ZWFkIG9mIGkKICAgICBqYWNrX3ZhbHMgPSBudW1lcmljKG4pCiAgICAgCiAgICAgZm9yIChqIGluIDE6bil7ICMgU1RBUlQgSkFDSyBMT09QCiAgICAgICBqYWNrX3NhbXBsZSA9IGRhdGFbLWpdCiAgICAgICAKICAgICAgIG11X2phY2sgPSBzdW0obG9nKGphY2tfc2FtcGxlKSkgLyAobi0xKQogICAgICAgICMgdGhlIGphY2trbmlmZSBlc3RpbWF0ZSBpcyBjb21wdXRlZCBieSBsZWF2aW5nIE9VVCB0aGUgaXRoIG9ic2VydmF0aW9uCiAgICAgICB0aGV0YV9zcXVhcmVkX2phY2sgPSBzdW0oKGxvZyhqYWNrX3NhbXBsZSktbXVfamFjayleMikgLyAobi0xKQogICAgICAgamFja192YWxzW2pdID0gZXhwKG11X2phY2sgKyAodGhldGFfc3F1YXJlZF9qYWNrLzIpKQogICAgIH0gIyBFTkQgSkFDSyBMT09QCiAgICAgCiAgICAgICB0aGV0YV9qYWNrX21lYW4gPSBtZWFuKGphY2tfdmFscykKICAgICAgICAgICAgICMgd2Ugd2FudCB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSB0b3RhbCBhdmVyYWdlIGFuZCBlYWNoIGphY2trbmlmZSBlc3RpbWF0ZSB0aGF0IGxlZnQgb25lIG91dAogICAgICAgbnVtZXJhdG9yID0gc3VtKCh0aGV0YV9qYWNrX21lYW4gLSBqYWNrX3ZhbHMpXjMpCiAgICAgICBkZW5vbWluYXRvciA9IHN1bSgodGhldGFfamFja19tZWFuIC0gamFja192YWxzKV4yKQogICAgICAgCiAgICAgICBhX2hhdCA9IG51bWVyYXRvci8gKDYgKiBkZW5vbWluYXRvcl4oMy8yKSkKICAgICAjIyMjIEVORCBBQ0NFTEVSQVRJT04gQ0FMQ1VMQVRJT04KICAgICAgIAogICAgICAgCiAgICAjIyMgRklOQUwgT1VUUFVUL0lOVEVSVkFMCiAgICAgICB6X3Njb3JlMSA9IHFub3JtKGFscGhhLzIpCiAgICAgICB6X3Njb3JlMiA9IHFub3JtKDEtYWxwaGEvMikKICAgICAgIGFscGhhMSA9IHBub3JtKHowICsgKHowICsgel9zY29yZTEpLygxLWFfaGF0Kih6MCArIHpfc2NvcmUxKSkpCiAgICAgICBhbHBoYTIgPSBwbm9ybSh6MCArICh6MCArIHpfc2NvcmUyKS8oMS1hX2hhdCooejAgKyB6X3Njb3JlMikpKQogICAgICAgCiAgICAgICBsb3dlciA9IHF1YW50aWxlKGJvb3RzdHJhcF9leF9lc3RpbWF0ZXMsIGFscGhhMSkKICAgICAgIHVwcGVyID0gcXVhbnRpbGUoYm9vdHN0cmFwX2V4X2VzdGltYXRlcywgYWxwaGEyKQogICAgICAgcmVzdWx0cyA9IHJiaW5kKGxvd2VyLHVwcGVyKQogICAgICAgcm93bmFtZXMocmVzdWx0cykgPSBjKCJMb3dlciBFc3RpbWF0ZSIsICJIaWdoZXIgRXN0aW1hdGUiKQogICAgICAgY29sbmFtZXMocmVzdWx0cykgPSAiQkNBIgogICAgICAgCiAgICAgICByZXR1cm4ocmVzdWx0cykKICAgICAgICAgICAgCn0gIyBFTkQgRlVOQ1RJT04KCgojdGVzdApjaV9iY2FfY3VzdG9tID0gY3VzdG9tX2NpX2JjYShkYXRhID0gZGF0YSRzb2lsLCBiPSA1MDAwLCBhbHBoYSA9IDAuMDUsIG9yaWdpbmFsX2VzdGltYXRlID0gRXhfaGF0KQoKI2NpX2JjYV9jdXN0b20KYGBgCgpgYGB7cn0KIyMjIGJ1aWx0LWluIFIgZnVuY3Rpb24KCiMgY2FuIHVzZSBib290X3Jlc3VsdCBvYmplY3QgZnJvbSBzZWN0aW9uIGIKIyBvbmNlIGFnYWluIHVzaW5nIGJvb3QuY2kgZnVuY3Rpb24sIGhvd2V2ZXIgYXJndW1lbnQgY2hhbmdlcyB0byAiYmNhIgpjaV9iY2Ffcl9zdGF0cyA9IGJvb3QuY2koYm9vdF9yZXN1bHQsIHR5cGUgPSAiYmNhIikKCiNjaV9iY2Ffcl9zdGF0cwogICMgaW50ZXJ2YWwgYmV0d2VlbiAzLjUxNSBhbmQgNS41MTUKCiNjaV9iY2Ffcl9zdGF0cyRiY2EKCiNjaV9iY2Ffcl9zdGF0cyRiY2FbNF0gIyA9IGxvd2VyIGludGVydmFsIGVuZAojY2lfYmNhX3Jfc3RhdHMkYmNhWzVdICMgPSBoaWdoZXIgaW50ZXJ2YWwgZW5kCgpjaV9iY2FfciA9IHJiaW5kKGNpX2JjYV9yX3N0YXRzJGJjYVs0XSwKICAgICAgICAgICAgICAgICAgICAgY2lfYmNhX3Jfc3RhdHMkYmNhWzVdKQoKcm93bmFtZXMoY2lfYmNhX3IpID0gYygiTG93ZXIgRXN0aW1hdGUiLCAiSGlnaGVyIEVzdGltYXRlIikKY29sbmFtZXMoY2lfYmNhX3IpID0gIkJDQSIKCiNjaV9iY2FfcgpgYGAKCk9uY2UgYWdhaW4gdXRpbGl6aW5nIHR3byBkaWZmZXJlbnQgY29kaW5nIG1ldGhvZHMsIG15IEJDYSByZXN1bHRzIHdlcmUgdGhlIGZvbGxvd2luZy4gV2l0aCBhcHByb3hpbWF0ZWx5IDk1JSBjb25maWRlbmNlLCB3ZSBjYW4gY2xhaW0gdGhhdCB0aGUgcG9wdWxhdGlvbiBtZWFuIG9mIGxlYWQgY29uY2VudHJhdGlvbiBpbiB1cmJhbiBzaXRlcyBpcyBzb21ld2hlcmUgYmV0d2VlbiBgciByb3VuZChjaV9iY2FfY3VzdG9tWzFdLDMpYCBhbmQgYHIgcm91bmQoY2lfYmNhX2N1c3RvbVsyXSwzKWAgbWcva2cgKm9yKiBgciByb3VuZChjaV9iY2FfclsxXSwzKWAgYW5kIGByIHJvdW5kKGNpX2JjYV9yWzJdLDMpYCBtZy9rZy4KCgojIGQuKSBBc3ltcHRvdGljIENJIApMYXN0bHksIEkgYXR0ZW1wdGVkIHRvIGVzdGltYXRlIHRoZSBwb3B1bGF0aW9uIG1lYW4gbGVhZCBjb25jZW50cmF0aW9uLCBFW1hdLCB2aWEgYW4gYXN5bXB0b3RpYyBvciAibm9ybWFsIiBhcHByb2FjaC4gQXN5bXB0b3RpYyBzYW1wbGluZyBpcyBvZiBjb3Vyc2UgcHJlZGljYXRlZCBvbiB0aGUgaWRlYSBvZiB0aGUgY2VudHJhbCBsaW1pdCB0aGVvcmVtLCBtZWFuaW5nIHRoYXQgYW4gaW5jcmVhc2UgaW4gc2FtcGxlIHNpemUgaXMgY29ycmVsYXRlZCB3aXRoIGFuIGluY3JlYXNlIGluIG5vcm1hbGl6YXRpb24uIAoKQSBmdW5kYW1lbnRhbCBkaWZmZXJlbmNlIGluIGFzeW1wdG90aWMgYW5kIHBlcmNlbnRpbGUgaW50ZXJ2YWwgZXN0aW1hdGlvbiBpcyB0aGF0IHRoZSBjcml0aWNhbCB2YWx1ZSB0ZXJtIGZvciBhc3ltcHRvdGljIGludGVydmFscywgd2hpY2ggdGhlIHN0YW5kYXJkIGVycm9yIGlzIG11bHRpcGxpZWQgYnksIGlzIGRlcGVuZGVudCBvbiB0aGUgcXVhbGl0aWVzIG9mIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uLiBPbiB0aGUgb3RoZXIgaGFuZCwgdGhlIGNyaXRpY2FsIHZhbHVlIHRlcm0gZm9yIHBlcmNlbnRpbGUgaW50ZXJ2YWxzIGlzIGRlcGVuZGVudCBvbiB0aGUgcXVhbGl0aWVzIG9mIHRoZSBib290c3RyYXAgc2FtcGxlcycgZGlzdHJpYnV0aW9uLiBBIGRvd25zaWRlIG9mIG5vcm1hbCBib290c3RyYXAgaW50ZXJ2YWxzIGlzIHRoZSBhc3N1bXB0aW9uIG9mIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIGRhdGEsIHdoaWNoIGlzIG5vdCBxdWl0ZSBtZXQgdG8gYSBsYXJnZSBkZWdyZWUgaW4gdGhpcyBpbnN0YW5jZS4KCgpgYGB7ciwgaW5jbHVkZT1GQUxTRX0KIyMjIHRlc3RpbmcgY2h1bmsKICAjIGVuZGluZyB1cCBub3QgZ29pbmcgdGhpcyByb3V0ZQoKIyMgYmVsb3cgaXMgImZvcm11bGEiIGZvciBjcmVhdGluZyBsYXJnZXIgcG9wdWxhdGlvbiBvZiBsb2cgbm9ybSBkaXN0cmlidXRlZCBkYXRhIHNpbWlsYXIgdG8gb3VyIHNhbXBsZSBkYXRhCmxhcmdlX3BvcCA9IHJsbm9ybSg1MCwgbWVhbiA9IGxvZyhFeF9oYXQpLCBzZCA9IHRoZXRhX3NxdWFyZWRfaGF0KQpsYXJnZV9wb3AgPSBzb3J0KGxhcmdlX3BvcCkKc29ydCA9IHNvcnQoZGF0YSRzb2lsKQoKbGFyZ2VfcG9wCnNvcnQKbWVhbihsYXJnZV9wb3ApCm1lYW4oZGF0YSRzb2lsKQoKIyMgbWFrZSBsYXJnZSBwb3B1bGF0aW9uIHdpdGggY2hhcmFjdGVyaXN0aWNzIG9mIG91ciBzYW1wbGUgLyBwb3B1bGF0aW9uIGRpc3RyaWJ1dGlvbgpsYXJnZV9wb3AgPSBybG5vcm0oMTAwMDAsIG1lYW4gPSBsb2coRXhfaGF0KSwgc2QgPSB0aGV0YV9zcXVhcmVkX2hhdCkKCiNtZWFuKGxhcmdlX3BvcCkKI21lYW4oZGF0YSRzb2lsKQogICMgbWVhbnMgYXJlIG9mIHNpbWlsYXIgdmFsdWUKCiMjIG5vdyB0YWtlIGJvb3RzdHJhcCBzYW1wbGVzIG9mIHRoYXQgbGFyZ2UgcG9wdWxhdGlvbgoKI2NpX2FzeW1fY3VzdG9tID0gY3VzdG9tX2NpX2FzeW0oZGF0YSA9IGxhcmdlX3BvcCwgYiA9IDUwMDAsIGFscGhhID0gMC4wNSkKCgpgYGAKCmBgYHtyfQojIyMgY3VzdG9tIGZ1bmN0aW9uCiAgIyByZWZlcmVuY2Ugc2VjdGlvbiAzLjEgZnJvbSBub3RlcwogICMgY2FuIHVzZSBib290c3RyYXBfRXggZnVuY3Rpb24gZnJvbSBwYXJ0IGEKCmN1c3RvbV9jaV9hc3ltID0gZnVuY3Rpb24oZGF0YSwgYiwgYWxwaGEpIHsKICBuID0gbGVuZ3RoKGRhdGEpCiAgYm9vdHN0cmFwX2V4X2VzdGltYXRlcyA9IG51bWVyaWMoYikKICAKICAjIGNhbGwgdG8gcHJldmlvdXMgZnVuY3Rpb24KICBib290c3RyYXBfZXhfZXN0aW1hdGVzID0gYm9vdHN0cmFwX0V4KGRhdGEgPSBkYXRhLCBiID0gYikKICAKICAjIG5vdyBlc3RpbWF0ZSBTRQogIHN1bV9wYXJ0ID0gc3VtKChib290c3RyYXBfZXhfZXN0aW1hdGVzIC0gCiAgICAgICAgICAgICAgICAgICAgbWVhbihib290c3RyYXBfZXhfZXN0aW1hdGVzKSleMikKICBzZSA9IHNxcnQoKDEvKGItMSkpKnN1bV9wYXJ0KQogIAogICMgbm93IGZpbmQgYW5kIG91dHB1dCBpbnRlcnZhbAogIGNyaXRfdmFsdWUgPSBhYnMocW5vcm0oYWxwaGEvMikpCiAgbG93ZXIgPSBtZWFuKGJvb3RzdHJhcF9leF9lc3RpbWF0ZXMpIC0gKGNyaXRfdmFsdWUqc2UpCiAgdXBwZXIgPSBtZWFuKGJvb3RzdHJhcF9leF9lc3RpbWF0ZXMpICsgKGNyaXRfdmFsdWUqc2UpCiAgcmVzdWx0cyA9IHJiaW5kKGxvd2VyLHVwcGVyKQogIGNvbG5hbWVzKHJlc3VsdHMpID0gIkN1c3RvbSBBc3ltIgogIHJvd25hbWVzKHJlc3VsdHMpID0gYygiTG93ZXIgRXN0aW1hdGUiLCAiSGlnaGVyIEVzdGltYXRlIikKICAKICByZXR1cm4ocmVzdWx0cykKfQoKY2lfYXN5bV9jdXN0b20gPSBjdXN0b21fY2lfYXN5bShkYXRhID0gZGF0YSRzb2lsLCBiID0gNTAwMCwgYWxwaGEgPSAwLjA1KQoKYGBgCgpgYGB7cn0KIyMjIGJ1aWx0LWluIFIgZnVuY3Rpb24KCiMgb25jZSBhZ2FpbiB1c2UgYm9vdF9yZXN1bHQgb2JqZWN0IGFuZCBib290LmNpIGZ1bmN0aW9uCgpjaV9hc3ltX3Jfc3RhdHMgPSBib290LmNpKGJvb3RfcmVzdWx0LCB0eXBlID0gIm5vcm0iKQogICMgdXNpbmcgYXJndW1lbnQgIm5vcm0iOyBhcyBzYW1wbGUgc2l6ZSBpbmNyZWFzZXMgc28gZG9lcyByZXNlbWJsYW5jZSB0byBub3JtYWxpdHkgYXMgcGVyIENMVCBhbmQgYXN5bXB0b3RpYyB0aGVvcnkKCiNjaV9hc3ltX3Jfc3RhdHMKICAjIGFib3V0IDMuMTYyIHRvIDUuMTQ4CgojY2lfYXN5bV9yX3N0YXRzJG5vcm1hbFsyXSA9IGxvd2VyIGludGVydmFsCiNjaV9hc3ltX3Jfc3RhdHMkbm9ybWFsWzNdID0gaGlnaGVyIGludGVydmFsCgpjaV9hc3ltX3IgPSByYmluZChjaV9hc3ltX3Jfc3RhdHMkbm9ybWFsWzJdLAogICAgICAgICAgICAgICAgICBjaV9hc3ltX3Jfc3RhdHMkbm9ybWFsWzNdKQoKcm93bmFtZXMoY2lfYXN5bV9yKSA9IGMoIkxvd2VyIEVzdGltYXRlIiwgIkhpZ2hlciBFc3RpbWF0ZSIpCmNvbG5hbWVzKGNpX2FzeW1fcikgPSAiQXN5bXB0b3RpYyIKCiNjaV9hc3ltX3IKYGBgCgpQZXIgdGhlIGFzeW1wdG90aWMgbWV0aG9kLCB3ZSBjYW4gc2F5IHdpdGggcm91Z2hseSA5NSUgY2VydGFpbnR5IHRoYXQgdGhlIG1lYW4gbGVhZCBjb25jZW50cmF0aW9uIGFtb25nc3QgdXJiYW4gc2l0ZXMgaXMgZWl0aGVyIGJldHdlZW4gYHIgcm91bmQoY2lfYXN5bV9jdXN0b21bMV0sIDMpYCBhbmQgYHIgcm91bmQoY2lfYXN5bV9jdXN0b21bMl0sIDMpYCBtZy9rZyAqb3IqIGByIHJvdW5kKGNpX2FzeW1fclsxXSwgMylgIGFuZCBgciByb3VuZChjaV9hc3ltX3JbMl0sIDMpYCBtZy9rZwoKIyBlLikgSW50ZXJ2YWwgQ29tcGFyaXNvbgpCZWxvdyBhcmUgdHdvIGNvbXBhcmlzb24gdGFibGVzIGRpc3BsYXlpbmcgdGhlIHJlc3VsdHMgb2YgZWFjaCBvZiB0aGUgdGhyZWUgaW50ZXJ2YWwgbWV0aG9kcyB0aGF0IGhhdmUgYmVlbiBkaXNjdXNzZWQuIFRoZSB0b3AgdGFibGUgY29tcGFyZXMgcmVzdWx0cyB0aGF0IHdlcmUgY29tcHV0ZWQgdmlhIFIncyA8c3BhbiBzdHlsZT0iY29sb3I6Ymx1ZTsiPmJvb3QoKTwvc3Bhbj4gZnVuY3Rpb24sIHdoaWxlIHRoZSBsYXR0ZXIgdGFibGUgc2hvd3MgcmVzdWx0cyBjYWxjdWxhdGVkIHZpYSBteSBjdXN0b20tYnVpbHQgZnVuY3Rpb25zLiBUaGUgY29kZSBmb3IgZWFjaCBjdXN0b20gZnVuY3Rpb24gY2FuIGJlIGZvdW5kIHVuZGVybmVhdGggdGhlIHJlc3BlY3RpdmUgc2VjdGlvbnMuCgpgYGB7cn0KIyMgY29tcGFyaW5nIHRoZSBpbnRlcnZhbHMgY3JlYXRlZCB2aWEgUidzIGJvb3QgZnVuY3Rpb24Kcl9pbnRlcnZhbHMgPSBjYmluZChyb3VuZChjaV9wZXJjZW50X3IsMyksCiAgICAgICAgICAgICAgICAgICAgcm91bmQoY2lfYmNhX3IsMyksCiAgICAgICAgICAgICAgICAgICAgcm91bmQoY2lfYXN5bV9yLDMpKQpyb3duYW1lcyhyX2ludGVydmFscykgPSBjKCJMb3dlciBFc3RpbWF0ZSIsICJIaWdoZXIgRXN0aW1hdGUiKQoKa2FibGUocl9pbnRlcnZhbHMsYWxpZ24gPSAiYyIsCiAgICAgIGNhcHRpb24gPSAiPHNwYW4gc3R5bGU9J2NvbG9yOiMjMDAwMDAwOyc+CiAgICAgIEludGVydmFscyB2aWEgUidzIEJvb3QgRnVuY3Rpb24gPC9zcGFuPiIpICU+JQogIGthYmxlX3N0eWxpbmcoCiAgICBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiYm9yZGVyZWQiKSwKICAgIGZ1bGxfd2lkdGggPSBGQUxTRSwKICAgIHBvc2l0aW9uID0gImNlbnRlciIpCgojIyBjb21wYXJpbmcgdGhlIGludGVydmFscyBjcmVhdGVkIHZpYSBteSBjdXN0b20gZnVuY3Rpb25zCmN1c3RvbV9pbnRlcnZhbHMgPSBjYmluZChyb3VuZChjaV9wZXJjZW50X2N1c3RvbSwzKSwKICAgICAgICAgICAgICAgICAgICByb3VuZChjaV9iY2FfY3VzdG9tLDMpLAogICAgICAgICAgICAgICAgICAgIHJvdW5kKGNpX2FzeW1fY3VzdG9tLDMpKQpyb3duYW1lcyhjdXN0b21faW50ZXJ2YWxzKSA9IGMoIkxvd2VyIEVzdGltYXRlIiwgIkhpZ2hlciBFc3RpbWF0ZSIpCmNvbG5hbWVzKGN1c3RvbV9pbnRlcnZhbHMpID0gYygiUGVyY2VudGlsZSIsICJCQ0EiLCAiQXN5bXB0b3RpYyIpCgprYWJsZShjdXN0b21faW50ZXJ2YWxzLGFsaWduID0gImMiLAogICAgICBjYXB0aW9uID0gIjxzcGFuIHN0eWxlPSdjb2xvcjojIzAwMDAwMDsnPgogICAgICBJbnRlcnZhbHMgdmlhIEN1c3RvbS1CdWlsdCBGdW5jdGlvbiA8L3NwYW4+IikgJT4lCiAga2FibGVfc3R5bGluZygKICAgIGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJib3JkZXJlZCIpLAogICAgZnVsbF93aWR0aCA9IEZBTFNFLAogICAgcG9zaXRpb24gPSAiY2VudGVyIikKCmBgYAoKIyMgRmluYWwgUmVjb21tZW5kYXRpb24KVGFraW5nIGV2ZXJ5dGhpbmcgaW50byBjb25zaWRlcmF0aW9uLCBJIHdvdWxkIHN1Z2dlc3QgbW92aW5nIGZvcndhcmQgdW5kZXIgdGhlIGFzc3VtcHRpb24gdGhhdCB0aGUgKipCQ2EgaW50ZXJ2YWwqKiBpcyB0aGUgbW9zdCBhY2N1cmF0ZS4gCgpBcyBJIGFsbHVkZWQgdG8gaW4gYSBwcmV2aW91cyBzZWN0aW9uLCB1c2Ugb2YgdGhlIHRoZSBhc3ltcHRvdGljIGludGVydmFsIGdlbmVyYWxseSBhc3N1bWVzIGEgcmVsYXRpdmVseSBub3JtYWwgZGlzdHJpYnV0aW9uIG9mIHRoZSBwb3B1bGF0aW9uIG9mIGludGVyZXN0LiBJbiB0aGlzIHNjZW5hcmlvLCB3ZSBoYXZlIG5vdCBhc3N1bWVkIG5vcm1hbGl0eSBmb3IgdGhlIHBvcHVsYXRpb24gb2YgdXJiYW4gc2l0ZXMnIGxlYWQgY29uY2VudHJhdGlvbnMsIGJ1dCByYXRoZXIgbG9nLW5vcm1hbGl0eS4gQmV5b25kIHRoYXQsIHRoZSBCQ2EgaW50ZXJ2YWwgbWV0aG9kIGlzIHRoZSBtb3N0IHJvYnVzdCBpbiB0aGUgZmFjZSBvZiBza2V3bmVzcyBhbmQgYmlhcy4gSXRzIGJpYXMgY29ycmVjdGlvbiBjb21wb25lbnQgdXRpbGl6ZXMgdGhlIG1lZGlhbiBzdGF0aXN0aWMgdG8gY291bnRlcmJhbGFuY2Ugb3V0bGllcnMsIHNvbWV0aGluZyB0aGF0IGlzIGNlcnRhaW5seSByZWxldmFudCB0byBib3RoIG91ciBzYW1wbGUgZGF0YSBhbmQgYm9vdHN0cmFwIGRpc3RyaWJ1dGlvbiBvZiBFW1hdIGVzdGltYXRlcy4gCgpCZWxvdyBhcmUgdGhlIGhpc3RvZ3JhbXMgZm9yIGJvdGggdGhlIHNhbXBsZSBkYXRhLCBhbmQgcG9wdWxhdGlvbiBtZWFuIGJvb3RzdHJhcCBlc3RpbWF0ZXMsIHRoaXMgdGltZSB3aXRoIHRoZSA5MHRoIHBlcmNlbnRpbGUgb2YgdGhlIGRhdGFzZXQgbWFya2VkLiBUaGlzIGFsbG93cyB1cyB0byBzZWUgaG93IGdyZWF0IG9mIGEgcmlnaHR3YXJkIHNrZXcgaXMgYXBwbGljYWJsZSB0byB0aGlzIHBhcnRpY3VsYXIgYW5hbHlzaXMuCgpgYGB7ciwgZmlnLmhlaWdodD01LjUsIGZpZy53aWR0aD02LjV9Cmhpc3QoZGF0YSRzb2lsLCAKICAgICBtYWluID0gIkRpc3RyaWJ1dGlvbiBvZiBDb25jZW50cmF0aW9ucyIsCiAgICAgeGxhYiA9ICJDb25jZW50cmF0aW9ucyAobWcva2cpIiwKICAgICBwcm9iID0gVFJVRSwKICAgICBjb2wgPSAibGlnaHRibHVlIgopCgogIyBEYXRhIHBvaW50IDkwdGggcGVyY2VudGlsZQogICAgc2VnbWVudHMoCiAgICAgIHgwID0gcXVhbnRpbGUoZGF0YSRzb2lsLDAuOSksCiAgICAgIHkwID0gMCwKICAgICAgeDEgPSBxdWFudGlsZShkYXRhJHNvaWwsMC45KSwKICAgICAgeTEgPSAxLAogICAgICBjb2wgPSAiYmxhY2siLAogICAgICBsd2QgPSA0LAogICAgICBsdHkgPSAzCiAgICApCgpsZWdlbmQoInRvcHJpZ2h0IiwKICAgICAgIGxlZ2VuZCA9ICI5MHRoIFBlcmNlbnRpbGUiLAogICAgICAgY29sID0gImJsYWNrIiwKICAgICAgIGx3ZCA9IDQsCiAgICAgICBsdHkgPSAzLAogICAgICAgYm94Lmx3ZD0zKQoKYm94KGx3ZD0zKQpgYGAKCgpgYGB7ciwgZmlnLmhlaWdodD01LjUsIGZpZy53aWR0aD02LjV9Cmhpc3QoRXhfc2FtcGxpbmdfZGlzdHJpYnV0aW9uLCAKICAgICBtYWluID0gIlNhbXBsaW5nIERpc3RyaWJ1dGlvbiBvZiBQb3B1bGF0aW9uIE1lYW4gRXN0aW1hdGVzIiwKICAgICB4bGFiID0gIkNvbmNlbnRyYXRpb25zIChtZy9rZykiLAogICAgIHByb2IgPSBUUlVFLAogICAgIGNvbCA9ICJsaWdodGJsdWUiCikKCiAjIERhdGEgcG9pbnQgOTB0aCBwZXJjZW50aWxlCiAgICBzZWdtZW50cygKICAgICAgeDAgPSBxdWFudGlsZShFeF9zYW1wbGluZ19kaXN0cmlidXRpb24sMC45KSwKICAgICAgeTAgPSAwLAogICAgICB4MSA9IHF1YW50aWxlKEV4X3NhbXBsaW5nX2Rpc3RyaWJ1dGlvbiwwLjkpLAogICAgICB5MSA9IDEsCiAgICAgIGNvbCA9ICJibGFjayIsCiAgICAgIGx3ZCA9IDQsCiAgICAgIGx0eSA9IDMKICAgICkKCmxlZ2VuZCgidG9wcmlnaHQiLAogICAgICAgbGVnZW5kID0gIjkwdGggUGVyY2VudGlsZSIsCiAgICAgICBjb2wgPSAiYmxhY2siLAogICAgICAgbHdkID0gNCwKICAgICAgIGx0eSA9IDMsCiAgICAgICBib3gubHdkPTMpICAgIAogIApib3gobHdkPTMpCmBgYAo=