Introduction
We have discussed the sampling distribution of sample statistics
based on theory. In this module, we are interested in sampling
distribution using simulation approaches.
In statistics, Monte Carlo simulation refers to using
computer-generated random numbers from population \(F(x:\theta)\) to approximate statistical
quantities that are difficult or impossible to
compute analytically. It’s essentially computational
experimentation that lets you study statistical behavior through
simulation rather than mathematical derivation.
A special Monte Carlo simulation we are going to introduce in this
model is called Bootstrap Simulation (or Bootstrap resampling). The
bootstrap sampling method is unequivocally a Monte Carlo simulation
technique that generate random numbers from \(F_n(x)\). It is perhaps the most
influential and widely used Monte Carlo method in applied statistics
over the last 40 years, precisely because it replaces difficult
mathematical derivations with computationally intensive random sampling
from the empirical data distribution.
This module focuses on non-parametric distribution and sampling from
the non-parametric (empirical) distribution. The goal is to use samples
taken from empirical distribution to approximate the sampling
distributions of estimated parameters such as sample means, standard
deviations, correlation coefficients, etc. Later, we will introduce
Bootstrap confidence interval and Bootstrap hypothesis testing.
Bootstrap methods and ideas are widely used in practice.
Parametric vs. Nonparametric Approaches and their
applications will be detailed in this module:
- Parametric: Assume data follows specific
distribution with known probability distribution function (e.g., normal,
exponential)
- Nonparametric: Make minimal assumptions about
underlying distribution
We will explain how to estimate an unknown cumulative
(probability) distribution function (CDF) based on random
sample taken from that population and how to repeated taken random
sample of the estimated cumulative (probability) distribution
function (ECDF). The later is commonly called empirical
cumulative distribution function (ECDF).
Empirical Distribution
Function (EDF) Revisited
Mathematical Definition
For a sample \(X_1, X_2, \ldots,
X_n\), the EDF \(\hat{F}_n(x)\)
is:
\[
\hat{F}_n(x) = \widehat{P}(X < x) = \frac{1}{n} \sum_{i=1}^n I(X_i
\leq x) = \frac{ \# [ \text{ (data values}) < x]}{n}
\]
where \(I(\cdot)\) is the indicator
function.
Example Consider the distribution of customer
waiting time at a restaurant. We randomly selected customers and
recorded their waiting times (in minute) $ ={2, 5, 10, 12, 15, 20, 35
}$.
We plot relative frequency histogram and cumulative relative
frequency histogram in the following.
XX = c(2, 5, 10, 12, 15, 20, 35 )
par(mfrow = c(1,2))
# Method 1: Using hist() with cumulative = TRUE
h0 <- hist(XX, breaks = 8, freq = FALSE, plot = FALSE)
h0$counts <- h0$counts/sum(h0$counts) # relative frequency
##
plot(h0,
col = "skyblue",
ylim=c(0,1),
main = "Relative Freq Histogram",
xlab = "Waiting Time",
ylab = "Relative Frequency")
##
h <- hist(XX, breaks = 8, freq = FALSE, plot = FALSE)
h$counts <- cumsum(h$counts)/sum(h$counts) # cumulative relative frequency
plot(h,
col = "skyblue",
ylim=c(0,1),
main = "Cumulative Relative Freq. Histogram",
xlab = "Waiting Time",
ylab = "Relative Cumulative Frequency")

The histogram approximates the shape of the probability density
function, while the cumulative histogram approximates the true
cumulative distribution function (CDF).
Properties
- Step function with jumps of size \(1/n\) at each observation
- Consistent estimator: \(\hat{F}_n(x) \to
F(x)\) as \(n \to \infty\)
(Glivenko-Cantelli theorem)
- Nonparametric maximum likelihood estimator
Algorithm for Constructing EDF
- Sort observations: \(x_{(1)} \leq x_{(2)} \leq \ldots \leq
x_{(n)}\)
- Initialize \(\hat{F}_n(x)
= 0\) for \(x <
x_{(1)}\)
- For each \(i = 1, \ldots,
n-1\):
- \(\hat{F}_n(x) = i/n\) for \(x_{(i)} \leq x < x_{(i+1)}\)
- Set \(\hat{F}_n(x) =
1\) for \(x \geq x_{(n)}\)
Pseudo-code
function empirical_cdf(data, x_values):
# Input: data (array of n observations), x_values (points to evaluate)
# Output: Fn values at x_values
sorted_data = sort(data)
n = length(data)
Fn = empty_array(length(x_values))
for j in 1:length(x_values):
x = x_values[j]
count = 0
for i in 1:n:
if sorted_data[i] <= x:
count = count + 1
Fn[j] = count / n
return Fn
Sampling
Populations
Sampling is the process of selecting a subset of individuals from a
larger population to estimate characteristics of the whole population.
The core purposes are:
Practicality and Cost-Effectiveness: It is often
impossible, too expensive, and too time-consuming to study an entire
population (a census). Sampling makes research feasible.
Speed: Data can be collected and analyzed much
faster from a sample than from an entire population.
Accuracy and Manageability: With limited
resources, you can ensure higher data quality (e.g., better-trained
interviewers, more precise measurements) on a smaller sample. A small,
well-managed study can be more accurate than a large, messy
census.
Inference: The fundamental goal is to make
statistical inferences—to use sample statistics (e.g., mean, proportion)
to estimate population parameters and draw conclusions about the
population.
We have previously discussed that most established statistical
methods are built on the assumption of independent and identically
distributed (iid) sampling. To achieve iid samples, it is essential to
distinguish between finite and infinite populations.
A finite population consists of a fixed, countable number of
elements—such as registered voters in an election or items in a
warehouse inventory. When sampling from such a population, the ratio of
sample size to population size (n/N) is important. If this
ratio is large, a finite population correction (FPC) should be applied
to adjust standard errors. This adjustment accounts for the reduced
variability that occurs when sampling without replacement from a limited
pool. Typically, a complete sampling frame exists for finite
populations, enabling approaches such as simple random sampling or
stratified sampling.
In contrast, an infinite population is theoretical or effectively
unbounded—such as all potential outputs of a continuous manufacturing
process. In this case, sampling one unit does not affect the probability
of selecting another, so no FPC is necessary, and standard formulas
assuming independence apply directly. In practice, very large
populations—for example, all global smartphone users—are often treated
as infinite due to their immense scale and the absence of a complete
sampling frame.
Sampling True
Population \(F(x:\theta)\)
The entire logic of statistical inference from a single sample to
conclusions about a population rests on understanding the properties of
this unobserved but fundamental true sampling
distribution. As was discussed earlier,
the true sampling distribution (i.e., exact
sampling distribution) is used for exact inference.
When the sampling distribution of a statistic is too complex to
derive analytically, and thus no simple pivotal quantity exists for
exact inference, the Monte Carlo method that takes
samples from the true
population provides a powerful simulation-based
alternative. The general algorithm is outlined in the following
- Choose estimator \(\hat{\theta}\)
for parameter \(\theta\).
- For a grid of possible \(\theta\) values
- Simulate \(B\) datasets from the
true population \(F(\cdot; \theta)\).
- Compute \(\hat{\theta}^*_1, \dots,
\hat{\theta}^*_B\) from each sample.
- Use the empirical distribution of \(\hat{\theta}^*\) to estimate the
sampling distribution under this \(\theta\).
- Using the above Monte Carlo sampling distribution to make
inference.
Remarks:
An estimator of population parameter
\(\theta\), denoted by \(\hat{\theta}\), is a function of data
values.
Key Use Cases of Monte Carlo for Sampling Distributions
2.1 When analytical derivation of the sampling distribution is
intractable: eg., median and quantiles, etc.
2.2 Ratio estimators such BMI (\(w/h^2\)) with very complex sampling
distribution.
2.3 Nonlinear functions of statistics
2.4 Small sample inference
The above algorithm is outlined graphicall in the following.

Example Assume that the particular numeric
characteristics of the WCU student population are the heights of all
students.
We don’t know the distribution of the heights.
We also don’t know whether a specific sample size is large enough to
use the central limit theorem. This means we don’t know whether it is
appropriate to use the central limit theorem to characterize the
sampling distribution of the mean height.
Due to the above constraints, we cannot find the sampling
distribution of the sample means using only the knowledge of elementary
statistics. However, if sampling is not expensive, we take repeated
samples with the same sample size. The resulting sample means can be
used to approximate the sampling distribution of the sample mean.
wcu.height <- read.table("https://pengdsci.github.io/STA506/w04/w02-wcuheights.txt", header = TRUE)
##
sample.mean.vec = NULL # define an empty vector to hold sample means of
# repeated samples.
for(i in 1:1000){ # starting for-loop to take repeated random samples
# with n = 81
ith.sample = sample( x = wcu.height$Height, # population of all WCU students heights
size = 81, # sample size = 81 values in the sample
replace = FALSE # sample without replacement
) # this is the i-th random sample
sample.mean.vec[i] = mean(ith.sample) # calculate the mean of i-th sample and save it in
# the empty vector: sample.mean.vec
}
## histogram
hist(sample.mean.vec, # data used for histogram
probability = TRUE, # relative frequency
breaks = 14, # specify number of vertical bars
xlab = "sample means of repeated samples", # change the label of x-axis
# add a title to the histogram
main="Approximated Sampling Distribution \n of Sample Means",
cex.main = 0.9,
col.main = "navy")
lines(density(sample.mean.vec), col = "skyblue", lwd = 2)

The above Monte Carlo sampling distribution of sample mean (with n =
91) is approximately symmetric.
Bootstrap Sampling
Distribution
Standard bootstrap sampling involves repeatedly drawing samples, with
replacement, from the empirical distribution of the observed data. This
method treats the original sample as a proxy for the true population. It
is formally justified by the Glivenko-Cantelli theorem, which ensures
the empirical distribution converges uniformly to the true distribution
as the sample size grows. Consequently, for large samples, resampling
from this empirical approximation effectively replicates the process of
drawing new samples from the underlying population, enabling robust
non-parametric inference.
The Bootstrap Principle
- Idea: Use the EDF \(\hat{F}_n\) as an approximation to the true
\(F\)
- Bootstrap world: Sampling from \(\hat{F}_n\) \(\approx\) sampling from \(F\) in real world
- Key insight: Resample from the observed data with
replacement
Mathematical Algorithm
Given data \(X = (X_1, \ldots,
X_n)\) and statistic \(T(X)\):
- Compute the estimated parameter, denoted by \(t_{\text{obs}} = T(X)\), from original
sample
- For \(b = 1\) to
\(B\) (\(B
=\) number of bootstrap samples):
- Draw \(X^*_1, \ldots, X^*_n \sim
\hat{F}_n\) (i.i.d.). More specifically, we use
sampling with replacement
from the original sample data set.
- Compute \(t^*_b = T(X^*)\)
- Bootstrap distribution: \(\{t^*_1, \ldots, t^*_B\}\)
- Estimate standard error, confidence intervals,
bias, etc.
Pseudo-code for Bootstrap
function bootstrap(data, statistic, B):
# Input: data (array), statistic (function), B (number of bootstrap samples)
# Output: bootstrap distribution
n = length(data)
t_obs = statistic(data)
bootstrap_dist = empty_array(B)
for b in 1:B:
# Resample with replacement
indices = sample(1:n, n, replace=TRUE)
bootstrap_sample = data[indices]
bootstrap_dist[b] = statistic(bootstrap_sample)
return list(observed=t_obs, distribution=bootstrap_dist)
The above standard Bootstrap algorithm is described in the following
figure

Example We still use the same simulated data of WCU
students’ height.
### read the delimited data from URL
url = "https://pengdsci.github.io/STA506/w04/w02-wcuheights.txt"
wcu.height = read.table(url, header = TRUE)
# taking the original random sample from the population
original.sample = sample( wcu.height$Height, # population of all WCU students heights
81, # sample size = 81 values in the sample
replace = FALSE # sample without replacement
)
### Bootstrap sampling begins
bt.sample.mean.vec = NULL # define an empty vector to hold sample means of repeated samples.
for(i in 1:1000){ # starting for-loop to take bootstrap samples with n = 81
ith.bt.sample = sample(x = original.sample, # Original sample with 81 WCU students' heights
size = 81, # sample size = 81 MUST be equal to the sample size!!
replace = TRUE # MUST use WITH REPLACEMENT!!
) # this is the i-th Bootstrap sample
bt.sample.mean.vec[i] = mean(ith.bt.sample) # calculate the mean of i-th bootstrap sample and
# save it in the empty vector: sample.bt.mean.vec
}
###
hist(bt.sample.mean.vec, # data used for histogram
breaks = 14, # specify number of vertical bars
probability = TRUE,
xlab = "Bootstrap sample means", # change the label of x-axis
# add a title to the histogram
main="Bootstrap Sampling Distribution \n of Sample Means",
cex.main = 0.9,
col.main = "navy")
lines(density(bt.sample.mean.vec), col = "skyblue", lwd = 2)

Remarks
Mimicking the Original Sampling Process: The
bootstrap aims to simulate what would happen if you repeated the
original data-collection experiment. If the original study collected
\(n\) observations, then each simulated
experiment should also collect \(n\)
observations to preserve the inherent variability (standard error) of
the estimator, which typically scales with \(1/\sqrt{n}\).
Consistency and Theoretical Foundation: The
bootstrap’s validity relies on the empirical distribution converging to
the true distribution (per Glivenko-Cantelli). Drawing a smaller sample
(\(m < n\)) would unnecessarily
increase the Monte Carlo error and is less efficient. Drawing a larger
sample (\(m > n\)) would incorrectly
suggest you have more information than you actually do, artificially
shrinking estimated standard errors and confidence intervals, leading to
anti-conservative (overly confident) inference.
Preserving the Data Structure: Many statistical
properties (e.g., bias) are functions of sample size. Using \(m \ne n\) would estimate the sampling
distribution for a different hypothetical study size, not the one you
actually conducted.
Jackknife
(Leave-one-out) Resampling
The Jackknife (leave-one-out) is a deterministic resampling method
for bias reduction and variance estimation. Unlike the bootstrap’s
random sampling, it systematically creates n new datasets, each
formed by omitting a single observation from the original
n-sized sample. This process measures the sensitivity of a
statistic to each data point, providing a direct, nonparametric
assessment of the estimator’s stability. The Jackknife is
computationally efficient and particularly effective for smooth
statistics (e.g., means, ratios), though it can fail for non-smooth
estimators like the median. Its core outputs are closed-form estimates
for bias and standard error, forming a foundation for more complex
resampling techniques.
The above simple idea is depicted in the following figure.

The pseudo code is based on the following algorith
Algorithm
Initialization: Start with the observed sample
\(X = (x_1, x_2, \dots, x_n)\). Compute
the original estimate \(\hat{\theta} =
s(X)\) for the statistic of interest.
Generate Pseudo-Values: For each \(i = 1, \dots, n\):
- Construct the i-th Jackknife sample \(X_{(-i)}\) by removing observation \(x_i\).
- Compute the corresponding statistic \(\hat{\theta}_{(-i)} = s(X_{(-i)})\).
Calculate the Mean Replicate: Compute the
average of the Jackknife replicates:
\(\bar{\theta}_{(\cdot)} = \frac{1}{n}
\sum_{i=1}^{n} \hat{\theta}_{(-i)}\).
Estimate Bias & Variance:
- Bias: \(\widehat{\text{bias}}_{\text{jack}} =
(n-1)(\bar{\theta}_{(\cdot)} - \hat{\theta})\).
- Variance: \(\widehat{\text{var}}_{\text{jack}} = \frac{n-1}{n}
\sum_{i=1}^{n} (\hat{\theta}_{(-i)} -
\bar{\theta}_{(\cdot)})^2\).
Produce Corrected Estimate (Optional):
A bias-corrected estimate is \(\hat{\theta}_{\text{jack}} = \hat{\theta} -
\widehat{\text{bias}}_{\text{jack}} = n\hat{\theta} -
(n-1)\bar{\theta}_{(\cdot)}\).
Example The same simulated data will used in this
Kackknife sampling distribution
### read the delimited data from URL
url = "https://pengdsci.github.io/STA506/w04/w02-wcuheights.txt"
wcu.height = read.table(url, header = TRUE)
## Take an original random sample from the population
original.sample = sample( wcu.height$Height, # population of all WCU students heights
81, # sample size = 81 values in the sample
replace = FALSE # sample without replacement
)
## Define a vector to store Jackknife sample means
jack.vec.avg <- NULL # unspecified empty vector
## calculate jackknife sample means
for (i in 1:81){
jack.vec <- original.sample[-i] # leave one out
jack.vec.avg[i] <- mean(jack.vec)
}
###
hist(jack.vec.avg, # data used for histogram
breaks = 14, # specify number of vertical bars
probability = TRUE,
xlab = "Jackknife sample means", # change the label of x-axis
# add a title to the histogram
main="Jackknife Sampling Distribution \n of Sample Means",
cex.main = 0.9,
col.main = "navy")
lines(density(jack.vec.avg), col = "skyblue", lwd = 2)

Comparisons Among
The
The Monte Carlo, bootstrap, and jackknife are foundational resampling
methods with distinct approaches.
Monte Carlo simulation draws repeated samples
from a known theoretical distribution, offering precise inference under
correct model specification but becoming unreliable if the model is
wrong.
In contrast, the bootstrap resamples with
replacement from the observed data itself, providing flexible,
nonparametric inference without strong distributional assumptions,
making it a modern default despite its computational demands.
The jackknife, a deterministic and efficient
alternative, systematically leaves out one observation at a time,
yielding simple closed-form estimates of bias and variance for smooth
statistics but lacking the bootstrap’s generality for complex
estimators.
Choosing among them involves balancing assumptions, computation, and
robustness. Monte Carlo excels when the underlying model is trusted; the
bootstrap delivers versatile, data-driven inference for most applied
problems; and the jackknife serves well for quick diagnostics and
variance estimation. Together, they enable rigorous, computationally
informed statistical analysis across diverse settings.
The following figure shows the steps of Monte Carlo and Bootstrap
sampling distribution of a sample statistic

An Example: Correlation
Coefficient
In this example, we study explore the sampling distribution of
sample correlation coefficient. Since this application
involves two variables, we need to set up the problem.
- Definition and Setup:
- Parameter of Interest: The population correlation
coefficient, \(\rho\), estimated by the
sample Pearson correlation \(r\)
computed from \(n\) paired observations
\((X_i, Y_i)\).
- Goal: Estimate the sampling distribution of \(r\) using the bootstrap, i.e., approximate
the variability and shape of \(r\)
across hypothetical repeated samples from the population.
- Original Sample:
- Data: \(\mathbf{D} = \{(x_1, y_1), (x_2,
y_2), \dots, (x_n, y_n)\}\)
- Compute original statistic: \[
r_{\text{orig}} = \frac{\sum (x_i - \bar{x})(y_i - \bar{y})}{\sqrt{\sum
(x_i - \bar{x})^2 \sum (y_i - \bar{y})^2}}
\]
- Resampling:
- Draw \(B\) bootstrap samples (\(B\) large, e.g., 10,000) by sampling \(n\) pairs with replacement
from \(\mathbf{D}\).
- Each bootstrap sample \(\mathbf{D}^*_b\) has the same size \(n\), but some pairs appear multiple times,
others not at all.
- Compute Bootstrap Replicates:
- For each \(\mathbf{D}^*_b\),
compute the correlation coefficient \(r^*_b\).
- Empirical Distribution: The collection \(\{r^*_1, r^*_2, \dots, r^*_B\}\) forms the
bootstrap approximation of the sampling distribution of \(r\).
Example: When bootstrapping correlation, it is
critical to resample the entire ordered
pair \((X_i, Y_i)\) for each
observation, rather than resampling the \(X\) and \(Y\) variables independently. This approach
preserves the inherent joint structure of the original dataset, ensuring
the bootstrap samples accurately reflect the true bivariate
relationship.
# Generate correlated data
set.seed(789)
n <- 40
true_rho <- 0.7 # true correlation coefficient in the simulation
x <- rnorm(n)
y <- true_rho * x + sqrt(1 - true_rho^2) * rnorm(n)
data_corr <- data.frame(x, y)
# R Function for Bootstrap correlation coefficient
bootstrap_correlation <- function(data, B = 10000) {
n <- nrow(data)
original_cor <- cor(data$x, data$y) # sample correlation coefficient
bootstrap_cors <- numeric(B) # B-dimensional zero vector
for (i in 1:B) {
# Resample pairs (rows) to preserve correlation structure
indices <- sample(1:n, n, replace = TRUE)
bootstrap_sample <- data[indices, ]
bootstrap_cors[i] <- cor(bootstrap_sample$x, bootstrap_sample$y)
}
bootstrap_cors
}
# Run bootstrap
cor_results <- bootstrap_correlation(data_corr, B = 5000)
# Visualization
par(mfrow = c(1, 2))
plot(x, y, main = "Original Data", pch = 19, col = "blue",
xlab = "X", ylab = "Y")
abline(lm(y ~ x), col = "red", lwd = 2)
hist(cor_results, breaks = 30,
main = "Bootstrap Distribution\nof Correlation",
xlab = "Correlation Coefficient", col = "steelblue",
probability = TRUE, xlim = c(0, 1))

Example: Using boot Package to perform Bootstrap
sampling and estimation.
# Using the boot package for more sophisticated analyses
library(boot)
# Define statistic function -
mean_stat <- function(data, indices) {
d <- data[indices] # Allows boot to select resamples
return(mean(d))
}
# Run bootstrap using boot()
set.seed(123)
sample_data <- rgamma(25, shape = 2, rate = 1)
boot_results <- boot(sample_data, statistic = mean_stat, R = 5000)
# Basic bootstrap
plot(boot_results)

Practical
Considerations
When to Use Bootstrap
- Small to moderate sample sizes
- Complex statistics without known sampling distribution
- Assessment of estimator variability
- Bias estimation and correction
Limitations and Caveats
- Sample representativeness: Bootstrap assumes sample
represents population
- Small samples: May perform poorly with \(n < 20\)
- Heavy-tailed distributions: May require more
bootstrap replications
- Dependence structure: Requires modification for
time series/spatial data
- Boundary issues: Problems with statistics near
boundaries
Choosing Number of Bootstrap Samples (\(B\))
- Standard errors: \(B \geq
200\) often sufficient
- Confidence intervals: \(B
\geq 1000\) recommended
- BCa intervals: \(B \geq
5000\) for stable results
- Percentile methods: Larger \(B\) for accurate tail estimation
LS0tDQp0aXRsZTogIk5vbnBhcmVtdHJpYyBEaXN0cmlidXRpb24gYW5kIEJvb3RzdHJhcCBTYW1wbGluZyINCmF1dGhvcjogIkNoZW5nIFBlbmciDQpkYXRlOiAiV2VzdCBDaGVzdGVyIFVuaXZlcnNpdHkiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRvY19jb2xsYXBzZWQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHNtb290aF9zY3JvbGw6IHllcw0KICAgIHRoZW1lOiBsdW1lbg0KICBwZGZfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgZmlnX3dpZHRoOiAzDQogICAgZmlnX2hlaWdodDogMw0KICB3b3JkX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBrZWVwX21kOiB5ZXMNCmVkaXRvcl9vcHRpb25zOiANCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KLS0tDQoNCmBgYHtjc3MsIGVjaG8gPSBGQUxTRX0NCiNUT0M6OmJlZm9yZSB7DQogIGNvbnRlbnQ6ICJUYWJsZSBvZiBDb250ZW50cyI7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LXNpemU6IDEuMmVtOw0KICBkaXNwbGF5OiBibG9jazsNCiAgY29sb3I6IG5hdnk7DQogIG1hcmdpbi1ib3R0b206IDEwcHg7DQp9DQoNCg0KZGl2I1RPQyBsaSB7ICAgICAvKiB0YWJsZSBvZiBjb250ZW50ICAqLw0KICAgIGxpc3Qtc3R5bGU6dXBwZXItcm9tYW47DQogICAgYmFja2dyb3VuZC1pbWFnZTpub25lOw0KICAgIGJhY2tncm91bmQtcmVwZWF0Om5vbmU7DQogICAgYmFja2dyb3VuZC1wb3NpdGlvbjowOw0KfQ0KDQpoMS50aXRsZSB7ICAgIC8qIGxldmVsIDEgaGVhZGVyIG9mIHRpdGxlICAqLw0KICBmb250LXNpemU6IDIycHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBjb2xvcjogRGFya1JlZDsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KICBmb250LWZhbWlseTogIkdpbGwgU2FucyIsIHNhbnMtc2VyaWY7DQp9DQoNCmg0LmF1dGhvciB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogIGZvbnQtc2l6ZTogMTVweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7DQogIGNvbG9yOiBuYXZ5Ow0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCmg0LmRhdGUgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICBmb250LXNpemU6IDE4cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LWZhbWlseTogIkdpbGwgU2FucyIsIHNhbnMtc2VyaWY7DQogIGNvbG9yOiBEYXJrQmx1ZTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KDQpoMSB7IC8qIEhlYWRlciAxIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAyMHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCg0KaDIgeyAvKiBIZWFkZXIgMiAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoMyB7IC8qIEhlYWRlciAzIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxNnB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmg0IHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE0cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCi8qIEFkZCBkb3RzIGFmdGVyIG51bWJlcmVkIGhlYWRlcnMgKi8NCi5oZWFkZXItc2VjdGlvbi1udW1iZXI6OmFmdGVyIHsNCiAgY29udGVudDogIi4iOw0KDQpib2R5IHsgYmFja2dyb3VuZC1jb2xvcjp3aGl0ZTsgfQ0KDQouaGlnaGxpZ2h0bWUgeyBiYWNrZ3JvdW5kLWNvbG9yOnllbGxvdzsgfQ0KDQpwIHsgYmFja2dyb3VuZC1jb2xvcjp3aGl0ZTsgfQ0KDQp9DQpgYGANCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQojIGNvZGUgY2h1bmsgc3BlY2lmaWVzIHdoZXRoZXIgdGhlIFIgY29kZSwgd2FybmluZ3MsIGFuZCBvdXRwdXQgDQojIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG91dHB1dCBmaWxlcy4NCmlmICghcmVxdWlyZSgia25pdHIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KICAgbGlicmFyeShrbml0cikNCn0NCmlmICghcmVxdWlyZSgicGFuZGVyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInBhbmRlciIpDQogICBsaWJyYXJ5KHBhbmRlcikNCn0NCmlmICghcmVxdWlyZSgiZ2dwbG90MiIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQ0KICBsaWJyYXJ5KGdncGxvdDIpDQp9DQppZiAoIXJlcXVpcmUoInRpZHl2ZXJzZSIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQogIGxpYnJhcnkodGlkeXZlcnNlKQ0KfQ0KDQppZiAoIXJlcXVpcmUoImJvb3QiKSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJib290IikNCiAgbGlicmFyeShib290KQ0KfQ0KaWYgKCFyZXF1aXJlKCJmaXRkaXN0cnBsdXMiKSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJmaXRkaXN0cnBsdXMiKQ0KICBsaWJyYXJ5KGZpdGRpc3RycGx1cykNCn0NCiMjIGxpYnJhcnkoZml0ZGlzdHJwbHVzKQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAgICAgICAjIGluY2x1ZGUgY29kZSBjaHVuayBpbiB0aGUgb3V0cHV0IGZpbGUNCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsICAgIyBzb21ldGltZXMsIHlvdSBjb2RlIG1heSBwcm9kdWNlIHdhcm5pbmcgbWVzc2FnZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgeW91IGNhbiBjaG9vc2UgdG8gaW5jbHVkZSB0aGUgd2FybmluZyBtZXNzYWdlcyBpbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHRoZSBvdXRwdXQgZmlsZS4gDQogICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cyA9IFRSVUUsICAgICMgeW91IGNhbiBhbHNvIGRlY2lkZSB3aGV0aGVyIHRvIGluY2x1ZGUgdGhlIG91dHB1dA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGluIHRoZSBvdXRwdXQgZmlsZS4NCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgY29tbWVudCA9IE5BDQogICAgICAgICAgICAgICAgICAgICAgKSAgDQpgYGANCg0KXA0KDQojIEludHJvZHVjdGlvbg0KDQpXZSBoYXZlIGRpc2N1c3NlZCB0aGUgc2FtcGxpbmcgZGlzdHJpYnV0aW9uIG9mIHNhbXBsZSBzdGF0aXN0aWNzIGJhc2VkIG9uIHRoZW9yeS4gSW4gdGhpcyBtb2R1bGUsIHdlIGFyZSBpbnRlcmVzdGVkIGluIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbiB1c2luZyBzaW11bGF0aW9uIGFwcHJvYWNoZXMuDQoNCkluIHN0YXRpc3RpY3MsIE1vbnRlIENhcmxvIHNpbXVsYXRpb24gcmVmZXJzIHRvIHVzaW5nIGNvbXB1dGVyLWdlbmVyYXRlZCByYW5kb20gbnVtYmVycyBmcm9tIHBvcHVsYXRpb24gJEYoeDpcdGhldGEpJCB0byBhcHByb3hpbWF0ZSBzdGF0aXN0aWNhbCBxdWFudGl0aWVzIHRoYXQgYXJlICoqZGlmZmljdWx0Kiogb3IgKippbXBvc3NpYmxlIHRvIGNvbXB1dGUgYW5hbHl0aWNhbGx5KiouIEl0J3MgZXNzZW50aWFsbHkgY29tcHV0YXRpb25hbCBleHBlcmltZW50YXRpb24gdGhhdCBsZXRzIHlvdSBzdHVkeSBzdGF0aXN0aWNhbCBiZWhhdmlvciB0aHJvdWdoIHNpbXVsYXRpb24gcmF0aGVyIHRoYW4gbWF0aGVtYXRpY2FsIGRlcml2YXRpb24uDQoNCkEgc3BlY2lhbCBNb250ZSBDYXJsbyBzaW11bGF0aW9uIHdlIGFyZSBnb2luZyB0byBpbnRyb2R1Y2UgaW4gdGhpcyBtb2RlbCBpcyBjYWxsZWQgQm9vdHN0cmFwIFNpbXVsYXRpb24gKG9yIEJvb3RzdHJhcCByZXNhbXBsaW5nKS4gVGhlIGJvb3RzdHJhcCBzYW1wbGluZyBtZXRob2QgaXMgdW5lcXVpdm9jYWxseSBhIE1vbnRlIENhcmxvIHNpbXVsYXRpb24gdGVjaG5pcXVlIHRoYXQgZ2VuZXJhdGUgcmFuZG9tIG51bWJlcnMgZnJvbSAkRl9uKHgpJC4gSXQgaXMgcGVyaGFwcyB0aGUgbW9zdCBpbmZsdWVudGlhbCBhbmQgd2lkZWx5IHVzZWQgTW9udGUgQ2FybG8gbWV0aG9kIGluIGFwcGxpZWQgc3RhdGlzdGljcyBvdmVyIHRoZSBsYXN0IDQwIHllYXJzLCBwcmVjaXNlbHkgYmVjYXVzZSBpdCByZXBsYWNlcyBkaWZmaWN1bHQgbWF0aGVtYXRpY2FsIGRlcml2YXRpb25zIHdpdGggY29tcHV0YXRpb25hbGx5IGludGVuc2l2ZSByYW5kb20gc2FtcGxpbmcgZnJvbSB0aGUgZW1waXJpY2FsIGRhdGEgZGlzdHJpYnV0aW9uLg0KDQpUaGlzIG1vZHVsZSBmb2N1c2VzIG9uIG5vbi1wYXJhbWV0cmljIGRpc3RyaWJ1dGlvbiBhbmQgc2FtcGxpbmcgZnJvbSB0aGUgbm9uLXBhcmFtZXRyaWMgKGVtcGlyaWNhbCkgZGlzdHJpYnV0aW9uLiBUaGUgZ29hbCBpcyB0byB1c2Ugc2FtcGxlcyB0YWtlbiBmcm9tIGVtcGlyaWNhbCBkaXN0cmlidXRpb24gdG8gYXBwcm94aW1hdGUgdGhlIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbnMgb2YgZXN0aW1hdGVkIHBhcmFtZXRlcnMgc3VjaCBhcyBzYW1wbGUgbWVhbnMsIHN0YW5kYXJkIGRldmlhdGlvbnMsIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50cywgZXRjLiBMYXRlciwgd2Ugd2lsbCBpbnRyb2R1Y2UgQm9vdHN0cmFwIGNvbmZpZGVuY2UgaW50ZXJ2YWwgYW5kIEJvb3RzdHJhcCBoeXBvdGhlc2lzIHRlc3RpbmcuIEJvb3RzdHJhcCBtZXRob2RzIGFuZCBpZGVhcyBhcmUgd2lkZWx5IHVzZWQgaW4gcHJhY3RpY2UuDQoNCg0KKipQYXJhbWV0cmljIHZzLiBOb25wYXJhbWV0cmljIEFwcHJvYWNoZXMqKiBhbmQgdGhlaXIgYXBwbGljYXRpb25zIHdpbGwgYmUgZGV0YWlsZWQgaW4gdGhpcyBtb2R1bGU6DQoNCi0gICAqKlBhcmFtZXRyaWMqKjogQXNzdW1lIGRhdGEgZm9sbG93cyBzcGVjaWZpYyBkaXN0cmlidXRpb24gd2l0aCBrbm93biBwcm9iYWJpbGl0eSBkaXN0cmlidXRpb24gZnVuY3Rpb24gKGUuZy4sIG5vcm1hbCwgZXhwb25lbnRpYWwpDQotICAgKipOb25wYXJhbWV0cmljKio6IE1ha2UgbWluaW1hbCBhc3N1bXB0aW9ucyBhYm91dCB1bmRlcmx5aW5nIGRpc3RyaWJ1dGlvbg0KDQoNCldlIHdpbGwgZXhwbGFpbiBob3cgdG8gZXN0aW1hdGUgYW4gdW5rbm93biAqKmN1bXVsYXRpdmUgKHByb2JhYmlsaXR5KSBkaXN0cmlidXRpb24gZnVuY3Rpb24gKENERikqKiBiYXNlZCBvbiByYW5kb20gc2FtcGxlIHRha2VuIGZyb20gdGhhdCBwb3B1bGF0aW9uIGFuZCBob3cgdG8gcmVwZWF0ZWQgdGFrZW4gcmFuZG9tIHNhbXBsZSBvZiB0aGUgKiplc3RpbWF0ZWQgY3VtdWxhdGl2ZSAocHJvYmFiaWxpdHkpIGRpc3RyaWJ1dGlvbiBmdW5jdGlvbiAoRUNERikqKi4gVGhlIGxhdGVyIGlzIGNvbW1vbmx5IGNhbGxlZCBlbXBpcmljYWwgY3VtdWxhdGl2ZSBkaXN0cmlidXRpb24gZnVuY3Rpb24gKEVDREYpLg0KDQoNCg0KIyBFbXBpcmljYWwgRGlzdHJpYnV0aW9uIEZ1bmN0aW9uIChFREYpIFJldmlzaXRlZA0KDQoqKk1hdGhlbWF0aWNhbCBEZWZpbml0aW9uKioNCg0KRm9yIGEgc2FtcGxlICRYXzEsIFhfMiwgXGxkb3RzLCBYX24kLCB0aGUgRURGICRcaGF0e0Z9X24oeCkkIGlzOg0KDQokJA0KXGhhdHtGfV9uKHgpID0gXHdpZGVoYXR7UH0oWCA8IHgpID0gXGZyYWN7MX17bn0gXHN1bV97aT0xfV5uIEkoWF9pIFxsZXEgeCkgPSBcZnJhY3sgXCMgWyBcdGV4dHsgKGRhdGEgdmFsdWVzfSkgPCB4XX17bn0NCiQkDQoNCndoZXJlICRJKFxjZG90KSQgaXMgdGhlIGluZGljYXRvciBmdW5jdGlvbi4NCg0KKipFeGFtcGxlKiogQ29uc2lkZXIgdGhlIGRpc3RyaWJ1dGlvbiBvZiBjdXN0b21lciB3YWl0aW5nIHRpbWUgYXQgYSByZXN0YXVyYW50LiBXZSByYW5kb21seSBzZWxlY3RlZCBjdXN0b21lcnMgYW5kIHJlY29yZGVkIHRoZWlyIHdhaXRpbmcgdGltZXMgKGluIG1pbnV0ZSkgXCQgXG1hdGhiZntYfSA9ezIsIDUsIDEwLCAxMiwgMTUsIDIwLCAzNSB9XCQuDQoNCldlIHBsb3QgcmVsYXRpdmUgZnJlcXVlbmN5IGhpc3RvZ3JhbSBhbmQgY3VtdWxhdGl2ZSByZWxhdGl2ZSBmcmVxdWVuY3kgaGlzdG9ncmFtIGluIHRoZSBmb2xsb3dpbmcuDQoNCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9OH0NClhYID0gYygyLCA1LCAxMCwgMTIsIDE1LCAyMCwgMzUgKQ0KcGFyKG1mcm93ID0gYygxLDIpKQ0KIyBNZXRob2QgMTogVXNpbmcgaGlzdCgpIHdpdGggY3VtdWxhdGl2ZSA9IFRSVUUNCmgwIDwtIGhpc3QoWFgsIGJyZWFrcyA9IDgsIGZyZXEgPSBGQUxTRSwgcGxvdCA9IEZBTFNFKQ0KaDAkY291bnRzIDwtIGgwJGNvdW50cy9zdW0oaDAkY291bnRzKSAgICMgcmVsYXRpdmUgZnJlcXVlbmN5DQojIw0KcGxvdChoMCwgDQogICAgIGNvbCA9ICJza3libHVlIiwNCiAgICAgeWxpbT1jKDAsMSksDQogICAgIG1haW4gPSAiUmVsYXRpdmUgRnJlcSBIaXN0b2dyYW0iLA0KICAgICB4bGFiID0gIldhaXRpbmcgVGltZSIsDQogICAgIHlsYWIgPSAiUmVsYXRpdmUgRnJlcXVlbmN5IikNCg0KIyMNCmggPC0gaGlzdChYWCwgYnJlYWtzID0gOCwgZnJlcSA9IEZBTFNFLCBwbG90ID0gRkFMU0UpDQpoJGNvdW50cyA8LSBjdW1zdW0oaCRjb3VudHMpL3N1bShoJGNvdW50cykgICMgY3VtdWxhdGl2ZSByZWxhdGl2ZSBmcmVxdWVuY3kNCnBsb3QoaCwgDQogICAgIGNvbCA9ICJza3libHVlIiwNCiAgICAgeWxpbT1jKDAsMSksDQogICAgIG1haW4gPSAiQ3VtdWxhdGl2ZSBSZWxhdGl2ZSBGcmVxLiBIaXN0b2dyYW0iLA0KICAgICB4bGFiID0gIldhaXRpbmcgVGltZSIsDQogICAgIHlsYWIgPSAiUmVsYXRpdmUgQ3VtdWxhdGl2ZSBGcmVxdWVuY3kiKQ0KYGBgDQoNClRoZSBoaXN0b2dyYW0gYXBwcm94aW1hdGVzIHRoZSBzaGFwZSBvZiB0aGUgcHJvYmFiaWxpdHkgZGVuc2l0eSBmdW5jdGlvbiwgd2hpbGUgdGhlIGN1bXVsYXRpdmUgaGlzdG9ncmFtIGFwcHJveGltYXRlcyB0aGUgdHJ1ZSBjdW11bGF0aXZlIGRpc3RyaWJ1dGlvbiBmdW5jdGlvbiAoQ0RGKS4NCg0KDQoqKlByb3BlcnRpZXMqKg0KDQotICAgU3RlcCBmdW5jdGlvbiB3aXRoIGp1bXBzIG9mIHNpemUgJDEvbiQgYXQgZWFjaCBvYnNlcnZhdGlvbg0KLSAgIENvbnNpc3RlbnQgZXN0aW1hdG9yOiAkXGhhdHtGfV9uKHgpIFx0byBGKHgpJCBhcyAkbiBcdG8gXGluZnR5JCAoR2xpdmVua28tQ2FudGVsbGkgdGhlb3JlbSkNCi0gICBOb25wYXJhbWV0cmljIG1heGltdW0gbGlrZWxpaG9vZCBlc3RpbWF0b3INCg0KKipBbGdvcml0aG0gZm9yIENvbnN0cnVjdGluZyBFREYqKg0KDQotICAgKipTb3J0Kiogb2JzZXJ2YXRpb25zOiAkeF97KDEpfSBcbGVxIHhfeygyKX0gXGxlcSBcbGRvdHMgXGxlcSB4X3sobil9JA0KLSAgICoqSW5pdGlhbGl6ZSoqICRcaGF0e0Z9X24oeCkgPSAwJCBmb3IgJHggPCB4X3soMSl9JA0KLSAgICoqRm9yKiogZWFjaCAkaSA9IDEsIFxsZG90cywgbi0xJDoNCiAgICAtICAgJFxoYXR7Rn1fbih4KSA9IGkvbiQgZm9yICR4X3soaSl9IFxsZXEgeCA8IHhfeyhpKzEpfSQNCi0gICAqKlNldCoqICRcaGF0e0Z9X24oeCkgPSAxJCBmb3IgJHggXGdlcSB4X3sobil9JA0KDQoqKlBzZXVkby1jb2RlKioNCg0KYGBgICAgICAgICAgDQpmdW5jdGlvbiBlbXBpcmljYWxfY2RmKGRhdGEsIHhfdmFsdWVzKToNCiAgICAjIElucHV0OiBkYXRhIChhcnJheSBvZiBuIG9ic2VydmF0aW9ucyksIHhfdmFsdWVzIChwb2ludHMgdG8gZXZhbHVhdGUpDQogICAgIyBPdXRwdXQ6IEZuIHZhbHVlcyBhdCB4X3ZhbHVlcw0KICAgIA0KICAgIHNvcnRlZF9kYXRhID0gc29ydChkYXRhKQ0KICAgIG4gPSBsZW5ndGgoZGF0YSkNCiAgICBGbiA9IGVtcHR5X2FycmF5KGxlbmd0aCh4X3ZhbHVlcykpDQogICAgDQogICAgZm9yIGogaW4gMTpsZW5ndGgoeF92YWx1ZXMpOg0KICAgICAgICB4ID0geF92YWx1ZXNbal0NCiAgICAgICAgY291bnQgPSAwDQogICAgICAgIGZvciBpIGluIDE6bjoNCiAgICAgICAgICAgIGlmIHNvcnRlZF9kYXRhW2ldIDw9IHg6DQogICAgICAgICAgICAgICAgY291bnQgPSBjb3VudCArIDENCiAgICAgICAgRm5bal0gPSBjb3VudCAvIG4NCiAgICANCiAgICByZXR1cm4gRm4NCmBgYA0KDQojIFNhbXBsaW5nIFBvcHVsYXRpb25zDQoNClNhbXBsaW5nIGlzIHRoZSBwcm9jZXNzIG9mIHNlbGVjdGluZyBhIHN1YnNldCBvZiBpbmRpdmlkdWFscyBmcm9tIGEgbGFyZ2VyIHBvcHVsYXRpb24gdG8gZXN0aW1hdGUgY2hhcmFjdGVyaXN0aWNzIG9mIHRoZSB3aG9sZSBwb3B1bGF0aW9uLiBUaGUgY29yZSBwdXJwb3NlcyBhcmU6DQoNCiogKipQcmFjdGljYWxpdHkgYW5kIENvc3QtRWZmZWN0aXZlbmVzcyoqOiBJdCBpcyBvZnRlbiBpbXBvc3NpYmxlLCB0b28gZXhwZW5zaXZlLCBhbmQgdG9vIHRpbWUtY29uc3VtaW5nIHRvIHN0dWR5IGFuIGVudGlyZSBwb3B1bGF0aW9uIChhIGNlbnN1cykuIFNhbXBsaW5nIG1ha2VzIHJlc2VhcmNoIGZlYXNpYmxlLg0KDQoqICoqU3BlZWQqKjogRGF0YSBjYW4gYmUgY29sbGVjdGVkIGFuZCBhbmFseXplZCBtdWNoIGZhc3RlciBmcm9tIGEgc2FtcGxlIHRoYW4gZnJvbSBhbiBlbnRpcmUgcG9wdWxhdGlvbi4NCg0KKiAqKkFjY3VyYWN5IGFuZCBNYW5hZ2VhYmlsaXR5Kio6IFdpdGggbGltaXRlZCByZXNvdXJjZXMsIHlvdSBjYW4gZW5zdXJlIGhpZ2hlciBkYXRhIHF1YWxpdHkgKGUuZy4sIGJldHRlci10cmFpbmVkIGludGVydmlld2VycywgbW9yZSBwcmVjaXNlIG1lYXN1cmVtZW50cykgb24gYSBzbWFsbGVyIHNhbXBsZS4gQSBzbWFsbCwgd2VsbC1tYW5hZ2VkIHN0dWR5IGNhbiBiZSBtb3JlIGFjY3VyYXRlIHRoYW4gYSBsYXJnZSwgbWVzc3kgY2Vuc3VzLg0KDQoqICoqSW5mZXJlbmNlKio6IFRoZSBmdW5kYW1lbnRhbCBnb2FsIGlzIHRvIG1ha2Ugc3RhdGlzdGljYWwgaW5mZXJlbmNlc+KAlHRvIHVzZSBzYW1wbGUgc3RhdGlzdGljcyAoZS5nLiwgbWVhbiwgcHJvcG9ydGlvbikgdG8gZXN0aW1hdGUgcG9wdWxhdGlvbiBwYXJhbWV0ZXJzIGFuZCBkcmF3IGNvbmNsdXNpb25zIGFib3V0IHRoZSBwb3B1bGF0aW9uLg0KDQpXZSBoYXZlIHByZXZpb3VzbHkgZGlzY3Vzc2VkIHRoYXQgbW9zdCBlc3RhYmxpc2hlZCBzdGF0aXN0aWNhbCBtZXRob2RzIGFyZSBidWlsdCBvbiB0aGUgYXNzdW1wdGlvbiBvZiBpbmRlcGVuZGVudCBhbmQgaWRlbnRpY2FsbHkgZGlzdHJpYnV0ZWQgKGlpZCkgc2FtcGxpbmcuIFRvIGFjaGlldmUgaWlkIHNhbXBsZXMsIGl0IGlzIGVzc2VudGlhbCB0byBkaXN0aW5ndWlzaCBiZXR3ZWVuIGZpbml0ZSBhbmQgaW5maW5pdGUgcG9wdWxhdGlvbnMuDQoNCkEgZmluaXRlIHBvcHVsYXRpb24gY29uc2lzdHMgb2YgYSBmaXhlZCwgY291bnRhYmxlIG51bWJlciBvZiBlbGVtZW50c+KAlHN1Y2ggYXMgcmVnaXN0ZXJlZCB2b3RlcnMgaW4gYW4gZWxlY3Rpb24gb3IgaXRlbXMgaW4gYSB3YXJlaG91c2UgaW52ZW50b3J5LiBXaGVuIHNhbXBsaW5nIGZyb20gc3VjaCBhIHBvcHVsYXRpb24sIHRoZSByYXRpbyBvZiBzYW1wbGUgc2l6ZSB0byBwb3B1bGF0aW9uIHNpemUgKCpuL04qKSBpcyBpbXBvcnRhbnQuIElmIHRoaXMgcmF0aW8gaXMgbGFyZ2UsIGEgZmluaXRlIHBvcHVsYXRpb24gY29ycmVjdGlvbiAoRlBDKSBzaG91bGQgYmUgYXBwbGllZCB0byBhZGp1c3Qgc3RhbmRhcmQgZXJyb3JzLiBUaGlzIGFkanVzdG1lbnQgYWNjb3VudHMgZm9yIHRoZSByZWR1Y2VkIHZhcmlhYmlsaXR5IHRoYXQgb2NjdXJzIHdoZW4gc2FtcGxpbmcgd2l0aG91dCByZXBsYWNlbWVudCBmcm9tIGEgbGltaXRlZCBwb29sLiBUeXBpY2FsbHksIGEgY29tcGxldGUgc2FtcGxpbmcgZnJhbWUgZXhpc3RzIGZvciBmaW5pdGUgcG9wdWxhdGlvbnMsIGVuYWJsaW5nIGFwcHJvYWNoZXMgc3VjaCBhcyBzaW1wbGUgcmFuZG9tIHNhbXBsaW5nIG9yIHN0cmF0aWZpZWQgc2FtcGxpbmcuDQoNCkluIGNvbnRyYXN0LCBhbiBpbmZpbml0ZSBwb3B1bGF0aW9uIGlzIHRoZW9yZXRpY2FsIG9yIGVmZmVjdGl2ZWx5IHVuYm91bmRlZOKAlHN1Y2ggYXMgYWxsIHBvdGVudGlhbCBvdXRwdXRzIG9mIGEgY29udGludW91cyBtYW51ZmFjdHVyaW5nIHByb2Nlc3MuIEluIHRoaXMgY2FzZSwgc2FtcGxpbmcgb25lIHVuaXQgZG9lcyBub3QgYWZmZWN0IHRoZSBwcm9iYWJpbGl0eSBvZiBzZWxlY3RpbmcgYW5vdGhlciwgc28gbm8gRlBDIGlzIG5lY2Vzc2FyeSwgYW5kIHN0YW5kYXJkIGZvcm11bGFzIGFzc3VtaW5nIGluZGVwZW5kZW5jZSBhcHBseSBkaXJlY3RseS4gSW4gcHJhY3RpY2UsIHZlcnkgbGFyZ2UgcG9wdWxhdGlvbnPigJRmb3IgZXhhbXBsZSwgYWxsIGdsb2JhbCBzbWFydHBob25lIHVzZXJz4oCUYXJlIG9mdGVuIHRyZWF0ZWQgYXMgaW5maW5pdGUgZHVlIHRvIHRoZWlyIGltbWVuc2Ugc2NhbGUgYW5kIHRoZSBhYnNlbmNlIG9mIGEgY29tcGxldGUgc2FtcGxpbmcgZnJhbWUuDQoNCg0KDQojIyBTYW1wbGluZyBUcnVlIFBvcHVsYXRpb24gJEYoeDpcdGhldGEpJA0KDQpUaGUgZW50aXJlIGxvZ2ljIG9mIHN0YXRpc3RpY2FsIGluZmVyZW5jZSBmcm9tIGEgc2luZ2xlIHNhbXBsZSB0byBjb25jbHVzaW9ucyBhYm91dCBhIHBvcHVsYXRpb24gcmVzdHMgb24gdW5kZXJzdGFuZGluZyB0aGUgcHJvcGVydGllcyBvZiB0aGlzIHVub2JzZXJ2ZWQgYnV0IGZ1bmRhbWVudGFsICoqdHJ1ZSBzYW1wbGluZyBkaXN0cmlidXRpb24qKi4gQXMgd2FzIGRpc2N1c3NlZCBlYXJsaWVyLCA8Zm9udCBjb2xvciA9ICJyZWQiPioqdGhlIHRydWUgc2FtcGxpbmcgZGlzdHJpYnV0aW9uIChpLmUuLCBleGFjdCBzYW1wbGluZyBkaXN0cmlidXRpb24pIGlzIHVzZWQgZm9yIGV4YWN0IGluZmVyZW5jZS4qKjwvZm9udD4gDQoNCldoZW4gdGhlIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbiBvZiBhIHN0YXRpc3RpYyBpcyB0b28gY29tcGxleCB0byBkZXJpdmUgYW5hbHl0aWNhbGx5LCBhbmQgdGh1cyBubyBzaW1wbGUgcGl2b3RhbCBxdWFudGl0eSBleGlzdHMgZm9yIGV4YWN0IGluZmVyZW5jZSwgdGhlICoqTW9udGUgQ2FybG8gbWV0aG9kKiogdGhhdCB0YWtlcyBzYW1wbGVzIGZyb20gdGhlIDxmb250IGNvbG9yID0gInJlZCI+Kip0cnVlIHBvcHVsYXRpb24qKjwvZm9udD4gcHJvdmlkZXMgYSBwb3dlcmZ1bCBzaW11bGF0aW9uLWJhc2VkIGFsdGVybmF0aXZlLiBUaGUgZ2VuZXJhbCBhbGdvcml0aG0gaXMgb3V0bGluZWQgaW4gdGhlIGZvbGxvd2luZw0KDQoqICBDaG9vc2UgZXN0aW1hdG9yICRcaGF0e1x0aGV0YX0kIGZvciBwYXJhbWV0ZXIgJFx0aGV0YSQuDQoqICoqRm9yIGEgZ3JpZCBvZiBwb3NzaWJsZSAkXHRoZXRhJCB2YWx1ZXMqKg0KICArIFNpbXVsYXRlICRCJCBkYXRhc2V0cyBmcm9tIHRoZSA8Zm9udCBjb2xvciA9ICJyZWQiPioqdHJ1ZSBwb3B1bGF0aW9uICRGKFxjZG90OyBcdGhldGEpJCoqPC9mb250Pi4NCiAgKyBDb21wdXRlICRcaGF0e1x0aGV0YX1eKl8xLCBcZG90cywgXGhhdHtcdGhldGF9XipfQiQgZnJvbSBlYWNoIHNhbXBsZS4NCiAgKyBVc2UgdGhlIGVtcGlyaWNhbCBkaXN0cmlidXRpb24gb2YgJFxoYXR7XHRoZXRhfV4qJCB0byBlc3RpbWF0ZSB0aGUgKipzYW1wbGluZyBkaXN0cmlidXRpb24gdW5kZXIgdGhpcyAkXHRoZXRhJCoqLg0KKiBVc2luZyB0aGUgYWJvdmUgTW9udGUgQ2FybG8gc2FtcGxpbmcgZGlzdHJpYnV0aW9uIHRvIG1ha2UgaW5mZXJlbmNlLg0KDQoqKlJlbWFya3MqKjogDQoNCjEuIDxmb250IGNvbG9yID0gInJlZCI+KipBbiBlc3RpbWF0b3Igb2YgcG9wdWxhdGlvbiBwYXJhbWV0ZXIgJFx0aGV0YSQsIGRlbm90ZWQgYnkgJFxoYXR7XHRoZXRhfSQsIGlzIGEgZnVuY3Rpb24gb2YgZGF0YSB2YWx1ZXMqKi48L2ZvbnQ+DQoNCjIuIEtleSBVc2UgQ2FzZXMgb2YgTW9udGUgQ2FybG8gZm9yIFNhbXBsaW5nIERpc3RyaWJ1dGlvbnMNCg0KICAgMi4xIFdoZW4gYW5hbHl0aWNhbCBkZXJpdmF0aW9uIG9mIHRoZSBzYW1wbGluZyBkaXN0cmlidXRpb24gaXMgaW50cmFjdGFibGU6IGVnLiwgbWVkaWFuIGFuZCBxdWFudGlsZXMsIGV0Yy4NCiAgDQogICAyLjIgUmF0aW8gZXN0aW1hdG9ycyBzdWNoIEJNSSAoJHcvaF4yJCkgd2l0aCB2ZXJ5IGNvbXBsZXggc2FtcGxpbmcgZGlzdHJpYnV0aW9uLg0KICANCiAgIDIuMyBOb25saW5lYXIgZnVuY3Rpb25zIG9mIHN0YXRpc3RpY3MNCiAgDQogICAyLjQgU21hbGwgc2FtcGxlIGluZmVyZW5jZQ0KDQpcDQoNClRoZSBhYm92ZSBhbGdvcml0aG0gaXMgb3V0bGluZWQgZ3JhcGhpY2FsbCBpbiB0aGUgZm9sbG93aW5nLg0KDQpgYGB7ciBlY2hvID0gRkFMU0UsIGZpZy5hbGlnbj0nY2VudGVyJywgb3V0LndpZHRoPSI5NSUifQ0KaW5jbHVkZV9ncmFwaGljcygiTW9udGVDYXJsby5wbmciKQ0KYGBgDQoNClwNCg0KKipFeGFtcGxlKiogQXNzdW1lIHRoYXQgdGhlIHBhcnRpY3VsYXIgbnVtZXJpYyBjaGFyYWN0ZXJpc3RpY3Mgb2YgdGhlIFdDVSBzdHVkZW50IHBvcHVsYXRpb24gYXJlIHRoZSBoZWlnaHRzIG9mIGFsbCBzdHVkZW50cy4NCg0KV2UgZG9u4oCZdCBrbm93IHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIGhlaWdodHMuDQoNCldlIGFsc28gZG9u4oCZdCBrbm93IHdoZXRoZXIgYSBzcGVjaWZpYyBzYW1wbGUgc2l6ZSBpcyBsYXJnZSBlbm91Z2ggdG8gdXNlIHRoZSBjZW50cmFsIGxpbWl0IHRoZW9yZW0uIFRoaXMgbWVhbnMgd2UgZG9u4oCZdCBrbm93IHdoZXRoZXIgaXQgaXMgYXBwcm9wcmlhdGUgdG8gdXNlIHRoZSBjZW50cmFsIGxpbWl0IHRoZW9yZW0gdG8gY2hhcmFjdGVyaXplIHRoZSBzYW1wbGluZyBkaXN0cmlidXRpb24gb2YgdGhlIG1lYW4gaGVpZ2h0Lg0KDQpEdWUgdG8gdGhlIGFib3ZlIGNvbnN0cmFpbnRzLCB3ZSBjYW5ub3QgZmluZCB0aGUgc2FtcGxpbmcgZGlzdHJpYnV0aW9uIG9mIHRoZSBzYW1wbGUgbWVhbnMgdXNpbmcgb25seSB0aGUga25vd2xlZGdlIG9mIGVsZW1lbnRhcnkgc3RhdGlzdGljcy4gSG93ZXZlciwgaWYgc2FtcGxpbmcgaXMgbm90IGV4cGVuc2l2ZSwgd2UgdGFrZSByZXBlYXRlZCBzYW1wbGVzIHdpdGggdGhlIHNhbWUgc2FtcGxlIHNpemUuIFRoZSByZXN1bHRpbmcgc2FtcGxlIG1lYW5zIGNhbiBiZSB1c2VkIHRvIGFwcHJveGltYXRlIHRoZSBzYW1wbGluZyBkaXN0cmlidXRpb24gb2YgdGhlIHNhbXBsZSBtZWFuLg0KDQoNCg0KDQpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD00LCBmaWcuaGVpZ2h0PTR9DQp3Y3UuaGVpZ2h0IDwtIHJlYWQudGFibGUoImh0dHBzOi8vcGVuZ2RzY2kuZ2l0aHViLmlvL1NUQTUwNi93MDQvdzAyLXdjdWhlaWdodHMudHh0IiwgaGVhZGVyID0gVFJVRSkNCiMjDQpzYW1wbGUubWVhbi52ZWMgPSBOVUxMICAgICAgIyBkZWZpbmUgYW4gZW1wdHkgdmVjdG9yIHRvIGhvbGQgc2FtcGxlIG1lYW5zIG9mIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgcmVwZWF0ZWQgc2FtcGxlcy4NCmZvcihpIGluIDE6MTAwMCl7ICAgICAgICAgICAjIHN0YXJ0aW5nIGZvci1sb29wIHRvIHRha2UgcmVwZWF0ZWQgcmFuZG9tIHNhbXBsZXMgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB3aXRoIG4gPSA4MQ0KICBpdGguc2FtcGxlID0gc2FtcGxlKCB4ID0gd2N1LmhlaWdodCRIZWlnaHQsICMgcG9wdWxhdGlvbiBvZiBhbGwgV0NVIHN0dWRlbnRzIGhlaWdodHMNCiAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDgxLCAgICAgICAgICAgICAgICAjIHNhbXBsZSBzaXplID0gODEgdmFsdWVzIGluIHRoZSBzYW1wbGUNCiAgICAgICAgICAgICAgICAgICAgICAgcmVwbGFjZSA9IEZBTFNFICAgICMgc2FtcGxlIHdpdGhvdXQgcmVwbGFjZW1lbnQNCiAgICAgICAgICAgICAgICAgICAgICkgICAgICAgICAgICAgICAgICAgICMgdGhpcyBpcyB0aGUgaS10aCByYW5kb20gc2FtcGxlDQogICBzYW1wbGUubWVhbi52ZWNbaV0gPSBtZWFuKGl0aC5zYW1wbGUpICAjIGNhbGN1bGF0ZSB0aGUgbWVhbiBvZiBpLXRoIHNhbXBsZSBhbmQgc2F2ZSBpdCBpbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGUgZW1wdHkgdmVjdG9yOiBzYW1wbGUubWVhbi52ZWMgDQp9DQojIyBoaXN0b2dyYW0NCmhpc3Qoc2FtcGxlLm1lYW4udmVjLCAgICAgICAgICAgICAgICAgICAgICAgICAgICMgZGF0YSB1c2VkIGZvciBoaXN0b2dyYW0NCiAgICAgcHJvYmFiaWxpdHkgPSBUUlVFLCAgICAgICAgICAgICAgICAgICAgICAgIyByZWxhdGl2ZSBmcmVxdWVuY3kNCiAgICAgYnJlYWtzID0gMTQsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgc3BlY2lmeSBudW1iZXIgb2YgdmVydGljYWwgYmFycw0KICAgICB4bGFiID0gInNhbXBsZSBtZWFucyBvZiByZXBlYXRlZCBzYW1wbGVzIiwgIyBjaGFuZ2UgdGhlIGxhYmVsIG9mIHgtYXhpcw0KICAgICAjIGFkZCBhIHRpdGxlIHRvIHRoZSBoaXN0b2dyYW0NCiAgICAgbWFpbj0iQXBwcm94aW1hdGVkIFNhbXBsaW5nIERpc3RyaWJ1dGlvbiAgXG4gIG9mIFNhbXBsZSBNZWFucyIsDQogICAgIGNleC5tYWluID0gMC45LA0KICAgICBjb2wubWFpbiA9ICJuYXZ5IikgICANCmxpbmVzKGRlbnNpdHkoc2FtcGxlLm1lYW4udmVjKSwgY29sID0gInNreWJsdWUiLCBsd2QgPSAyKQ0KYGBgDQoNClRoZSBhYm92ZSBNb250ZSBDYXJsbyBzYW1wbGluZyBkaXN0cmlidXRpb24gb2Ygc2FtcGxlIG1lYW4gKHdpdGggbiA9IDkxKSBpcyBhcHByb3hpbWF0ZWx5IHN5bW1ldHJpYy4NCg0KDQoNCiMjIEJvb3RzdHJhcCBTYW1wbGluZyBEaXN0cmlidXRpb24NCg0KU3RhbmRhcmQgYm9vdHN0cmFwIHNhbXBsaW5nIGludm9sdmVzIHJlcGVhdGVkbHkgZHJhd2luZyBzYW1wbGVzLCB3aXRoIHJlcGxhY2VtZW50LCBmcm9tIHRoZSBlbXBpcmljYWwgZGlzdHJpYnV0aW9uIG9mIHRoZSBvYnNlcnZlZCBkYXRhLiBUaGlzIG1ldGhvZCB0cmVhdHMgdGhlIG9yaWdpbmFsIHNhbXBsZSBhcyBhIHByb3h5IGZvciB0aGUgdHJ1ZSBwb3B1bGF0aW9uLiBJdCBpcyBmb3JtYWxseSBqdXN0aWZpZWQgYnkgdGhlIEdsaXZlbmtvLUNhbnRlbGxpIHRoZW9yZW0sIHdoaWNoIGVuc3VyZXMgdGhlIGVtcGlyaWNhbCBkaXN0cmlidXRpb24gY29udmVyZ2VzIHVuaWZvcm1seSB0byB0aGUgdHJ1ZSBkaXN0cmlidXRpb24gYXMgdGhlIHNhbXBsZSBzaXplIGdyb3dzLiBDb25zZXF1ZW50bHksIGZvciBsYXJnZSBzYW1wbGVzLCByZXNhbXBsaW5nIGZyb20gdGhpcyBlbXBpcmljYWwgYXBwcm94aW1hdGlvbiBlZmZlY3RpdmVseSByZXBsaWNhdGVzIHRoZSBwcm9jZXNzIG9mIGRyYXdpbmcgbmV3IHNhbXBsZXMgZnJvbSB0aGUgdW5kZXJseWluZyBwb3B1bGF0aW9uLCBlbmFibGluZyByb2J1c3Qgbm9uLXBhcmFtZXRyaWMgaW5mZXJlbmNlLg0KDQoNCioqVGhlIEJvb3RzdHJhcCBQcmluY2lwbGUqKg0KDQoqICAqKklkZWEqKjogVXNlIHRoZSBFREYgJFxoYXR7Rn1fbiQgYXMgYW4gYXBwcm94aW1hdGlvbiB0byB0aGUgdHJ1ZSAkRiQNCiogICoqQm9vdHN0cmFwIHdvcmxkKio6IFNhbXBsaW5nIGZyb20gJFxoYXR7Rn1fbiQgJFxhcHByb3gkIHNhbXBsaW5nIGZyb20gJEYkIGluIHJlYWwgd29ybGQNCiogICoqS2V5IGluc2lnaHQqKjogUmVzYW1wbGUgZnJvbSB0aGUgb2JzZXJ2ZWQgZGF0YSB3aXRoIHJlcGxhY2VtZW50DQoNCg0KKipNYXRoZW1hdGljYWwgQWxnb3JpdGhtKioNCg0KR2l2ZW4gZGF0YSAkWCA9IChYXzEsIFxsZG90cywgWF9uKSQgYW5kIHN0YXRpc3RpYyAkVChYKSQ6DQoNCiogKipDb21wdXRlKiogdGhlIGVzdGltYXRlZCBwYXJhbWV0ZXIsIGRlbm90ZWQgYnkgJHRfe1x0ZXh0e29ic319ID0gVChYKSQsIGZyb20gb3JpZ2luYWwgc2FtcGxlDQoqICAqKkZvcioqICRiID0gMSQgdG8gJEIkICgkQiA9JCBudW1iZXIgb2YgYm9vdHN0cmFwIHNhbXBsZXMpOg0KICAgKyBEcmF3ICRYXipfMSwgXGxkb3RzLCBYXipfbiBcc2ltIFxoYXR7Rn1fbiQgKGkuaS5kLikuIE1vcmUgc3BlY2lmaWNhbGx5LCB3ZSB1c2UgPGZvbnQgY29sb3IgPSAicmVkIj4qKnNhbXBsaW5nIHdpdGggcmVwbGFjZW1lbnQqKjwvZm9udD4gZnJvbSB0aGUgb3JpZ2luYWwgc2FtcGxlIGRhdGEgc2V0Lg0KICAgKyBDb21wdXRlICR0XipfYiA9IFQoWF4qKSQNCiogICoqQm9vdHN0cmFwIGRpc3RyaWJ1dGlvbioqOiAkXHt0XipfMSwgXGxkb3RzLCB0XipfQlx9JA0KKiAgKipFc3RpbWF0ZSoqIHN0YW5kYXJkIGVycm9yLCBjb25maWRlbmNlIGludGVydmFscywgYmlhcywgZXRjLg0KDQoNCioqUHNldWRvLWNvZGUgZm9yIEJvb3RzdHJhcCoqDQoNCmBgYCAgICAgICAgIA0KZnVuY3Rpb24gYm9vdHN0cmFwKGRhdGEsIHN0YXRpc3RpYywgQik6DQogICAgIyBJbnB1dDogZGF0YSAoYXJyYXkpLCBzdGF0aXN0aWMgKGZ1bmN0aW9uKSwgQiAobnVtYmVyIG9mIGJvb3RzdHJhcCBzYW1wbGVzKQ0KICAgICMgT3V0cHV0OiBib290c3RyYXAgZGlzdHJpYnV0aW9uDQogICAgDQogICAgbiA9IGxlbmd0aChkYXRhKQ0KICAgIHRfb2JzID0gc3RhdGlzdGljKGRhdGEpDQogICAgYm9vdHN0cmFwX2Rpc3QgPSBlbXB0eV9hcnJheShCKQ0KICAgIA0KICAgIGZvciBiIGluIDE6QjoNCiAgICAgICAgIyBSZXNhbXBsZSB3aXRoIHJlcGxhY2VtZW50DQogICAgICAgIGluZGljZXMgPSBzYW1wbGUoMTpuLCBuLCByZXBsYWNlPVRSVUUpDQogICAgICAgIGJvb3RzdHJhcF9zYW1wbGUgPSBkYXRhW2luZGljZXNdDQogICAgICAgIGJvb3RzdHJhcF9kaXN0W2JdID0gc3RhdGlzdGljKGJvb3RzdHJhcF9zYW1wbGUpDQogICAgDQogICAgcmV0dXJuIGxpc3Qob2JzZXJ2ZWQ9dF9vYnMsIGRpc3RyaWJ1dGlvbj1ib290c3RyYXBfZGlzdCkNCmBgYA0KDQpUaGUgYWJvdmUgc3RhbmRhcmQgQm9vdHN0cmFwIGFsZ29yaXRobSBpcyBkZXNjcmliZWQgaW4gdGhlIGZvbGxvd2luZyBmaWd1cmUNCg0KDQpgYGB7ciBlY2hvID0gRkFMU0UsIGZpZy5hbGlnbj0nY2VudGVyJywgb3V0LndpZHRoPSI5NSUifQ0KaW5jbHVkZV9ncmFwaGljcygidzAyLUJvb3RTYW1wbGluZ0Rpc3QuanBnIikNCmBgYA0KDQoNCioqRXhhbXBsZSoqIFdlIHN0aWxsIHVzZSB0aGUgc2FtZSBzaW11bGF0ZWQgZGF0YSBvZiBXQ1Ugc3R1ZGVudHMnIGhlaWdodC4NCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD00fQ0KIyMjIHJlYWQgdGhlIGRlbGltaXRlZCBkYXRhIGZyb20gVVJMDQp1cmwgPSAiaHR0cHM6Ly9wZW5nZHNjaS5naXRodWIuaW8vU1RBNTA2L3cwNC93MDItd2N1aGVpZ2h0cy50eHQiDQp3Y3UuaGVpZ2h0ID0gcmVhZC50YWJsZSh1cmwsIGhlYWRlciA9IFRSVUUpDQojIHRha2luZyB0aGUgb3JpZ2luYWwgcmFuZG9tIHNhbXBsZSBmcm9tIHRoZSBwb3B1bGF0aW9uDQpvcmlnaW5hbC5zYW1wbGUgPSBzYW1wbGUoIHdjdS5oZWlnaHQkSGVpZ2h0LCAgICAjIHBvcHVsYXRpb24gb2YgYWxsIFdDVSBzdHVkZW50cyBoZWlnaHRzDQogICAgICAgICAgICAgICAgICAgICAgIDgxLCAgICAgICAgICAgICAgICAgICAgICAjIHNhbXBsZSBzaXplID0gODEgdmFsdWVzIGluIHRoZSBzYW1wbGUNCiAgICAgICAgICAgICAgICAgICAgICAgcmVwbGFjZSA9IEZBTFNFICAgICAgICAgICMgc2FtcGxlIHdpdGhvdXQgcmVwbGFjZW1lbnQNCiAgICAgICAgICAgICAgICAgKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KIyMjIEJvb3RzdHJhcCBzYW1wbGluZyBiZWdpbnMgDQpidC5zYW1wbGUubWVhbi52ZWMgPSBOVUxMICAgICAgIyBkZWZpbmUgYW4gZW1wdHkgdmVjdG9yIHRvIGhvbGQgc2FtcGxlIG1lYW5zIG9mIHJlcGVhdGVkIHNhbXBsZXMuDQpmb3IoaSBpbiAxOjEwMDApeyAgICAgICAgICAgICAgIyBzdGFydGluZyBmb3ItbG9vcCB0byB0YWtlIGJvb3RzdHJhcCBzYW1wbGVzIHdpdGggbiA9IDgxDQogIGl0aC5idC5zYW1wbGUgPSBzYW1wbGUoeCA9IG9yaWdpbmFsLnNhbXBsZSwgIyBPcmlnaW5hbCBzYW1wbGUgd2l0aCA4MSBXQ1Ugc3R1ZGVudHMnIGhlaWdodHMNCiAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDgxLCAgICAgICAgICAgICAjIHNhbXBsZSBzaXplID0gODEgTVVTVCBiZSBlcXVhbCB0byB0aGUgc2FtcGxlIHNpemUhIQ0KICAgICAgICAgICAgICAgICAgICByZXBsYWNlID0gVFJVRSAgICAgICAgICAgICMgTVVTVCB1c2UgV0lUSCBSRVBMQUNFTUVOVCEhDQogICAgICAgICAgICAgICAgICAgICAgICkgICAgICAgICAgICAgICAgICAgICAgIyB0aGlzIGlzIHRoZSBpLXRoIEJvb3RzdHJhcCBzYW1wbGUNCiAgYnQuc2FtcGxlLm1lYW4udmVjW2ldID0gbWVhbihpdGguYnQuc2FtcGxlKSAjIGNhbGN1bGF0ZSB0aGUgbWVhbiBvZiBpLXRoIGJvb3RzdHJhcCBzYW1wbGUgYW5kIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgc2F2ZSBpdCBpbiB0aGUgZW1wdHkgdmVjdG9yOiBzYW1wbGUuYnQubWVhbi52ZWMgDQp9DQojIyMNCmhpc3QoYnQuc2FtcGxlLm1lYW4udmVjLCAgICAgICAgICAgICAgICAgICAgICMgZGF0YSB1c2VkIGZvciBoaXN0b2dyYW0NCiAgICAgYnJlYWtzID0gMTQsICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgc3BlY2lmeSBudW1iZXIgb2YgdmVydGljYWwgYmFycw0KICAgICBwcm9iYWJpbGl0eSA9IFRSVUUsDQogICAgICAgeGxhYiA9ICJCb290c3RyYXAgc2FtcGxlIG1lYW5zIiwgICAgICAjIGNoYW5nZSB0aGUgbGFiZWwgb2YgeC1heGlzDQogICAgICAjIGFkZCBhIHRpdGxlIHRvIHRoZSBoaXN0b2dyYW0NCiAgICAgICAgbWFpbj0iQm9vdHN0cmFwIFNhbXBsaW5nIERpc3RyaWJ1dGlvbiBcbiBvZiBTYW1wbGUgTWVhbnMiLA0KICAgICAgICAgIGNleC5tYWluID0gMC45LA0KICAgICAgIGNvbC5tYWluID0gIm5hdnkiKSAgIA0KbGluZXMoZGVuc2l0eShidC5zYW1wbGUubWVhbi52ZWMpLCBjb2wgPSAic2t5Ymx1ZSIsIGx3ZCA9IDIpDQoNCmBgYA0KDQoNCg0KKipSZW1hcmtzKioNCg0KKiAqKk1pbWlja2luZyB0aGUgT3JpZ2luYWwgU2FtcGxpbmcgUHJvY2VzcyoqOiBUaGUgYm9vdHN0cmFwIGFpbXMgdG8gc2ltdWxhdGUgd2hhdCB3b3VsZCBoYXBwZW4gaWYgeW91IHJlcGVhdGVkIHRoZSBvcmlnaW5hbCBkYXRhLWNvbGxlY3Rpb24gZXhwZXJpbWVudC4gSWYgdGhlIG9yaWdpbmFsIHN0dWR5IGNvbGxlY3RlZCAkbiQgb2JzZXJ2YXRpb25zLCB0aGVuIGVhY2ggc2ltdWxhdGVkIGV4cGVyaW1lbnQgc2hvdWxkIGFsc28gY29sbGVjdCAkbiQgb2JzZXJ2YXRpb25zIHRvIHByZXNlcnZlIHRoZSBpbmhlcmVudCB2YXJpYWJpbGl0eSAoc3RhbmRhcmQgZXJyb3IpIG9mIHRoZSBlc3RpbWF0b3IsIHdoaWNoIHR5cGljYWxseSBzY2FsZXMgd2l0aCAkMS9cc3FydHtufSQuDQoNCiogKipDb25zaXN0ZW5jeSBhbmQgVGhlb3JldGljYWwgRm91bmRhdGlvbioqOiBUaGUgYm9vdHN0cmFwJ3MgdmFsaWRpdHkgcmVsaWVzIG9uIHRoZSBlbXBpcmljYWwgZGlzdHJpYnV0aW9uIGNvbnZlcmdpbmcgdG8gdGhlIHRydWUgZGlzdHJpYnV0aW9uIChwZXIgR2xpdmVua28tQ2FudGVsbGkpLiBEcmF3aW5nIGEgc21hbGxlciBzYW1wbGUgKCRtIDwgbiQpIHdvdWxkIHVubmVjZXNzYXJpbHkgaW5jcmVhc2UgdGhlIE1vbnRlIENhcmxvIGVycm9yIGFuZCBpcyBsZXNzIGVmZmljaWVudC4gRHJhd2luZyBhIGxhcmdlciBzYW1wbGUgKCRtID4gbiQpIHdvdWxkIGluY29ycmVjdGx5IHN1Z2dlc3QgeW91IGhhdmUgbW9yZSBpbmZvcm1hdGlvbiB0aGFuIHlvdSBhY3R1YWxseSBkbywgYXJ0aWZpY2lhbGx5IHNocmlua2luZyBlc3RpbWF0ZWQgc3RhbmRhcmQgZXJyb3JzIGFuZCBjb25maWRlbmNlIGludGVydmFscywgbGVhZGluZyB0byBhbnRpLWNvbnNlcnZhdGl2ZSAob3Zlcmx5IGNvbmZpZGVudCkgaW5mZXJlbmNlLg0KDQoqICoqUHJlc2VydmluZyB0aGUgRGF0YSBTdHJ1Y3R1cmUqKjogTWFueSBzdGF0aXN0aWNhbCBwcm9wZXJ0aWVzIChlLmcuLCBiaWFzKSBhcmUgZnVuY3Rpb25zIG9mIHNhbXBsZSBzaXplLiBVc2luZyAkbSBcbmUgbiQgd291bGQgZXN0aW1hdGUgdGhlIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbiBmb3IgYSBkaWZmZXJlbnQgaHlwb3RoZXRpY2FsIHN0dWR5IHNpemUsIG5vdCB0aGUgb25lIHlvdSBhY3R1YWxseSBjb25kdWN0ZWQuDQoNCg0KDQoNCg0KDQojIyBKYWNra25pZmUgKExlYXZlLW9uZS1vdXQpIFJlc2FtcGxpbmcNCg0KDQpUaGUgSmFja2tuaWZlIChsZWF2ZS1vbmUtb3V0KSBpcyBhIGRldGVybWluaXN0aWMgcmVzYW1wbGluZyBtZXRob2QgZm9yIGJpYXMgcmVkdWN0aW9uIGFuZCB2YXJpYW5jZSBlc3RpbWF0aW9uLiBVbmxpa2UgdGhlIGJvb3RzdHJhcCdzIHJhbmRvbSBzYW1wbGluZywgaXQgc3lzdGVtYXRpY2FsbHkgY3JlYXRlcyAqbiogbmV3IGRhdGFzZXRzLCBlYWNoIGZvcm1lZCBieSBvbWl0dGluZyBhIHNpbmdsZSBvYnNlcnZhdGlvbiBmcm9tIHRoZSBvcmlnaW5hbCAqbiotc2l6ZWQgc2FtcGxlLiBUaGlzIHByb2Nlc3MgbWVhc3VyZXMgdGhlIHNlbnNpdGl2aXR5IG9mIGEgc3RhdGlzdGljIHRvIGVhY2ggZGF0YSBwb2ludCwgcHJvdmlkaW5nIGEgZGlyZWN0LCBub25wYXJhbWV0cmljIGFzc2Vzc21lbnQgb2YgdGhlIGVzdGltYXRvcidzIHN0YWJpbGl0eS4gVGhlIEphY2trbmlmZSBpcyBjb21wdXRhdGlvbmFsbHkgZWZmaWNpZW50IGFuZCBwYXJ0aWN1bGFybHkgZWZmZWN0aXZlIGZvciBzbW9vdGggc3RhdGlzdGljcyAoZS5nLiwgbWVhbnMsIHJhdGlvcyksIHRob3VnaCBpdCBjYW4gZmFpbCBmb3Igbm9uLXNtb290aCBlc3RpbWF0b3JzIGxpa2UgdGhlIG1lZGlhbi4gSXRzIGNvcmUgb3V0cHV0cyBhcmUgY2xvc2VkLWZvcm0gZXN0aW1hdGVzIGZvciBiaWFzIGFuZCBzdGFuZGFyZCBlcnJvciwgZm9ybWluZyBhIGZvdW5kYXRpb24gZm9yIG1vcmUgY29tcGxleCByZXNhbXBsaW5nIHRlY2huaXF1ZXMuDQoNClRoZSBhYm92ZSBzaW1wbGUgaWRlYSBpcyBkZXBpY3RlZCBpbiB0aGUgZm9sbG93aW5nIGZpZ3VyZS4NCg0KYGBge3IgZWNobyA9IEZBTFNFLCBmaWcuYWxpZ249J2NlbnRlcicsIG91dC53aWR0aD0iNzUlIn0NCmluY2x1ZGVfZ3JhcGhpY3MoIkphY2trbmlmZS5wbmciKQ0KYGBgDQoNClRoZSBwc2V1ZG8gY29kZSBpcyBiYXNlZCBvbiB0aGUgZm9sbG93aW5nIGFsZ29yaXRoDQoNCioqQWxnb3JpdGhtKioNCg0KMS4gICoqSW5pdGlhbGl6YXRpb246KiogU3RhcnQgd2l0aCB0aGUgb2JzZXJ2ZWQgc2FtcGxlICRYID0gKHhfMSwgeF8yLCBcZG90cywgeF9uKSQuIENvbXB1dGUgdGhlIG9yaWdpbmFsIGVzdGltYXRlICRcaGF0e1x0aGV0YX0gPSBzKFgpJCBmb3IgdGhlIHN0YXRpc3RpYyBvZiBpbnRlcmVzdC4NCg0KMi4gICoqR2VuZXJhdGUgUHNldWRvLVZhbHVlczoqKiBGb3IgZWFjaCAkaSA9IDEsIFxkb3RzLCBuJDoNCiAgICBhLiBDb25zdHJ1Y3QgdGhlICppKi10aCBKYWNra25pZmUgc2FtcGxlICRYX3soLWkpfSQgYnkgcmVtb3Zpbmcgb2JzZXJ2YXRpb24gJHhfaSQuDQogICAgYi4gQ29tcHV0ZSB0aGUgY29ycmVzcG9uZGluZyBzdGF0aXN0aWMgJFxoYXR7XHRoZXRhfV97KC1pKX0gPSBzKFhfeygtaSl9KSQuDQoNCjMuICAqKkNhbGN1bGF0ZSB0aGUgTWVhbiBSZXBsaWNhdGU6KiogQ29tcHV0ZSB0aGUgYXZlcmFnZSBvZiB0aGUgSmFja2tuaWZlIHJlcGxpY2F0ZXM6ICANCiAgICAkXGJhcntcdGhldGF9X3soXGNkb3QpfSA9IFxmcmFjezF9e259IFxzdW1fe2k9MX1ee259IFxoYXR7XHRoZXRhfV97KC1pKX0kLg0KDQo0LiAgKipFc3RpbWF0ZSBCaWFzICYgVmFyaWFuY2U6KiogIA0KICAgIC0gKipCaWFzOioqICRcd2lkZWhhdHtcdGV4dHtiaWFzfX1fe1x0ZXh0e2phY2t9fSA9IChuLTEpKFxiYXJ7XHRoZXRhfV97KFxjZG90KX0gLSBcaGF0e1x0aGV0YX0pJC4gIA0KICAgIC0gKipWYXJpYW5jZToqKiAkXHdpZGVoYXR7XHRleHR7dmFyfX1fe1x0ZXh0e2phY2t9fSA9IFxmcmFje24tMX17bn0gXHN1bV97aT0xfV57bn0gKFxoYXR7XHRoZXRhfV97KC1pKX0gLSBcYmFye1x0aGV0YX1feyhcY2RvdCl9KV4yJC4NCg0KNS4gICoqUHJvZHVjZSBDb3JyZWN0ZWQgRXN0aW1hdGUgKE9wdGlvbmFsKToqKiAgDQogICAgQSBiaWFzLWNvcnJlY3RlZCBlc3RpbWF0ZSBpcyAkXGhhdHtcdGhldGF9X3tcdGV4dHtqYWNrfX0gPSBcaGF0e1x0aGV0YX0gLSBcd2lkZWhhdHtcdGV4dHtiaWFzfX1fe1x0ZXh0e2phY2t9fSA9IG5caGF0e1x0aGV0YX0gLSAobi0xKVxiYXJ7XHRoZXRhfV97KFxjZG90KX0kLg0KDQoNCioqRXhhbXBsZSoqIFRoZSBzYW1lIHNpbXVsYXRlZCBkYXRhIHdpbGwgdXNlZCBpbiB0aGlzIEthY2trbmlmZSBzYW1wbGluZyBkaXN0cmlidXRpb24NCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD00fQ0KIyMjIHJlYWQgdGhlIGRlbGltaXRlZCBkYXRhIGZyb20gVVJMDQp1cmwgPSAiaHR0cHM6Ly9wZW5nZHNjaS5naXRodWIuaW8vU1RBNTA2L3cwNC93MDItd2N1aGVpZ2h0cy50eHQiDQp3Y3UuaGVpZ2h0ID0gcmVhZC50YWJsZSh1cmwsIGhlYWRlciA9IFRSVUUpDQoNCiMjIFRha2UgYW4gb3JpZ2luYWwgcmFuZG9tIHNhbXBsZSBmcm9tIHRoZSBwb3B1bGF0aW9uDQpvcmlnaW5hbC5zYW1wbGUgPSBzYW1wbGUoIHdjdS5oZWlnaHQkSGVpZ2h0LCAgICAjIHBvcHVsYXRpb24gb2YgYWxsIFdDVSBzdHVkZW50cyBoZWlnaHRzDQogICAgICAgICAgICAgICAgICAgICAgIDgxLCAgICAgICAgICAgICAgICAgICAgICAjIHNhbXBsZSBzaXplID0gODEgdmFsdWVzIGluIHRoZSBzYW1wbGUNCiAgICAgICAgICAgICAgICAgICAgICAgcmVwbGFjZSA9IEZBTFNFICAgICAgICAgICMgc2FtcGxlIHdpdGhvdXQgcmVwbGFjZW1lbnQNCiAgICAgICAgICAgICAgICAgKSAgIA0KDQojIyBEZWZpbmUgYSB2ZWN0b3IgdG8gc3RvcmUgSmFja2tuaWZlIHNhbXBsZSBtZWFucw0KamFjay52ZWMuYXZnIDwtIE5VTEwgICAgICAjIHVuc3BlY2lmaWVkIGVtcHR5IHZlY3Rvcg0KDQojIyBjYWxjdWxhdGUgamFja2tuaWZlIHNhbXBsZSBtZWFucw0KDQpmb3IgKGkgaW4gMTo4MSl7DQogIGphY2sudmVjIDwtIG9yaWdpbmFsLnNhbXBsZVstaV0gICMgbGVhdmUgb25lIG91dA0KICBqYWNrLnZlYy5hdmdbaV0gPC0gbWVhbihqYWNrLnZlYykNCn0NCg0KIyMjDQpoaXN0KGphY2sudmVjLmF2ZywgICAgICAgICAgICAgICAgICAgICAjIGRhdGEgdXNlZCBmb3IgaGlzdG9ncmFtDQogICAgIGJyZWFrcyA9IDE0LCAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHNwZWNpZnkgbnVtYmVyIG9mIHZlcnRpY2FsIGJhcnMNCiAgICAgcHJvYmFiaWxpdHkgPSBUUlVFLA0KICAgICAgIHhsYWIgPSAiSmFja2tuaWZlIHNhbXBsZSBtZWFucyIsICAgICAgIyBjaGFuZ2UgdGhlIGxhYmVsIG9mIHgtYXhpcw0KICAgICAgIyBhZGQgYSB0aXRsZSB0byB0aGUgaGlzdG9ncmFtDQogICAgICAgIG1haW49IkphY2trbmlmZSBTYW1wbGluZyBEaXN0cmlidXRpb24gXG4gb2YgU2FtcGxlIE1lYW5zIiwNCiAgICAgICAgICBjZXgubWFpbiA9IDAuOSwNCiAgICAgICBjb2wubWFpbiA9ICJuYXZ5IikgICANCmxpbmVzKGRlbnNpdHkoamFjay52ZWMuYXZnKSwgY29sID0gInNreWJsdWUiLCBsd2QgPSAyKQ0KYGBgDQoNCg0KDQojIyBDb21wYXJpc29ucyBBbW9uZyBUaGUgIA0KDQpUaGUgTW9udGUgQ2FybG8sIGJvb3RzdHJhcCwgYW5kIGphY2trbmlmZSBhcmUgZm91bmRhdGlvbmFsIHJlc2FtcGxpbmcgbWV0aG9kcyB3aXRoIGRpc3RpbmN0IGFwcHJvYWNoZXMuIA0KDQoqICoqTW9udGUgQ2FybG8gc2ltdWxhdGlvbioqIGRyYXdzIHJlcGVhdGVkIHNhbXBsZXMgZnJvbSBhIGtub3duIHRoZW9yZXRpY2FsIGRpc3RyaWJ1dGlvbiwgb2ZmZXJpbmcgcHJlY2lzZSBpbmZlcmVuY2UgdW5kZXIgY29ycmVjdCBtb2RlbCBzcGVjaWZpY2F0aW9uIGJ1dCBiZWNvbWluZyB1bnJlbGlhYmxlIGlmIHRoZSBtb2RlbCBpcyB3cm9uZy4gDQoNCiogSW4gY29udHJhc3QsICoqdGhlIGJvb3RzdHJhcCByZXNhbXBsZXMqKiB3aXRoIHJlcGxhY2VtZW50IGZyb20gdGhlIG9ic2VydmVkIGRhdGEgaXRzZWxmLCBwcm92aWRpbmcgZmxleGlibGUsIG5vbnBhcmFtZXRyaWMgaW5mZXJlbmNlIHdpdGhvdXQgc3Ryb25nIGRpc3RyaWJ1dGlvbmFsIGFzc3VtcHRpb25zLCBtYWtpbmcgaXQgYSBtb2Rlcm4gZGVmYXVsdCBkZXNwaXRlIGl0cyBjb21wdXRhdGlvbmFsIGRlbWFuZHMuIA0KDQoqICoqVGhlIGphY2trbmlmZSoqLCBhIGRldGVybWluaXN0aWMgYW5kIGVmZmljaWVudCBhbHRlcm5hdGl2ZSwgc3lzdGVtYXRpY2FsbHkgbGVhdmVzIG91dCBvbmUgb2JzZXJ2YXRpb24gYXQgYSB0aW1lLCB5aWVsZGluZyBzaW1wbGUgY2xvc2VkLWZvcm0gZXN0aW1hdGVzIG9mIGJpYXMgYW5kIHZhcmlhbmNlIGZvciBzbW9vdGggc3RhdGlzdGljcyBidXQgbGFja2luZyB0aGUgYm9vdHN0cmFw4oCZcyBnZW5lcmFsaXR5IGZvciBjb21wbGV4IGVzdGltYXRvcnMuDQoNCg0KQ2hvb3NpbmcgYW1vbmcgdGhlbSBpbnZvbHZlcyBiYWxhbmNpbmcgYXNzdW1wdGlvbnMsIGNvbXB1dGF0aW9uLCBhbmQgcm9idXN0bmVzcy4gTW9udGUgQ2FybG8gZXhjZWxzIHdoZW4gdGhlIHVuZGVybHlpbmcgbW9kZWwgaXMgdHJ1c3RlZDsgdGhlIGJvb3RzdHJhcCBkZWxpdmVycyB2ZXJzYXRpbGUsIGRhdGEtZHJpdmVuIGluZmVyZW5jZSBmb3IgbW9zdCBhcHBsaWVkIHByb2JsZW1zOyBhbmQgdGhlIGphY2trbmlmZSBzZXJ2ZXMgd2VsbCBmb3IgcXVpY2sgZGlhZ25vc3RpY3MgYW5kIHZhcmlhbmNlIGVzdGltYXRpb24uIFRvZ2V0aGVyLCB0aGV5IGVuYWJsZSByaWdvcm91cywgY29tcHV0YXRpb25hbGx5IGluZm9ybWVkIHN0YXRpc3RpY2FsIGFuYWx5c2lzIGFjcm9zcyBkaXZlcnNlIHNldHRpbmdzLg0KDQpUaGUgZm9sbG93aW5nIGZpZ3VyZSBzaG93cyB0aGUgc3RlcHMgb2YgTW9udGUgQ2FybG8gYW5kIEJvb3RzdHJhcCBzYW1wbGluZyBkaXN0cmlidXRpb24gb2YgYSBzYW1wbGUgc3RhdGlzdGljDQoNCg0KDQpgYGB7ciBlY2hvID0gRkFMU0UsIGZpZy5hbGlnbj0nY2VudGVyJywgb3V0LndpZHRoPSI4NSUifQ0KaW5jbHVkZV9ncmFwaGljcygiU2FtcGxpbmdSZXNhbXBsaW5nLnBuZyIpDQpgYGANCg0KDQoNCg0KDQoNCg0KIyBBbiBFeGFtcGxlOiBDb3JyZWxhdGlvbiBDb2VmZmljaWVudA0KDQpJbiB0aGlzIGV4YW1wbGUsIHdlIHN0dWR5IGV4cGxvcmUgdGhlIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbiBvZiAqKnNhbXBsZSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCoqLiBTaW5jZSB0aGlzIGFwcGxpY2F0aW9uIGludm9sdmVzIHR3byB2YXJpYWJsZXMsIHdlIG5lZWQgdG8gc2V0IHVwIHRoZSBwcm9ibGVtLg0KDQoqICoqRGVmaW5pdGlvbiBhbmQgU2V0dXA6KioNCiAgKyAqKlBhcmFtZXRlciBvZiBJbnRlcmVzdCoqOiBUaGUgcG9wdWxhdGlvbiBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCwgJFxyaG8kLCBlc3RpbWF0ZWQgYnkgdGhlIHNhbXBsZSBQZWFyc29uIGNvcnJlbGF0aW9uICRyJCBjb21wdXRlZCBmcm9tICRuJCBwYWlyZWQgb2JzZXJ2YXRpb25zICQoWF9pLCBZX2kpJC4NCiAgKyAqKkdvYWwqKjogRXN0aW1hdGUgdGhlIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbiBvZiAkciQgdXNpbmcgdGhlIGJvb3RzdHJhcCwgaS5lLiwgYXBwcm94aW1hdGUgdGhlIHZhcmlhYmlsaXR5IGFuZCBzaGFwZSBvZiAkciQgYWNyb3NzIGh5cG90aGV0aWNhbCByZXBlYXRlZCBzYW1wbGVzIGZyb20gdGhlIHBvcHVsYXRpb24uDQoNCiogKipPcmlnaW5hbCBTYW1wbGU6KioNCiAgKyBEYXRhOiAkXG1hdGhiZntEfSA9IFx7KHhfMSwgeV8xKSwgKHhfMiwgeV8yKSwgXGRvdHMsICh4X24sIHlfbilcfSQNCiAgKyBDb21wdXRlIG9yaWdpbmFsIHN0YXRpc3RpYzoNCiQkDQpyX3tcdGV4dHtvcmlnfX0gPSBcZnJhY3tcc3VtICh4X2kgLSBcYmFye3h9KSh5X2kgLSBcYmFye3l9KX17XHNxcnR7XHN1bSAoeF9pIC0gXGJhcnt4fSleMiBcc3VtICh5X2kgLSBcYmFye3l9KV4yfX0NCiQkDQoNCiogKipSZXNhbXBsaW5nOioqDQogICsgRHJhdyAkQiQgYm9vdHN0cmFwIHNhbXBsZXMgKCRCJCBsYXJnZSwgZS5nLiwgMTAsMDAwKSBieSBzYW1wbGluZyAkbiQgcGFpcnMgKip3aXRoIHJlcGxhY2VtZW50KiogZnJvbSAkXG1hdGhiZntEfSQuDQogICsgRWFjaCBib290c3RyYXAgc2FtcGxlICRcbWF0aGJme0R9XipfYiQgaGFzIHRoZSBzYW1lIHNpemUgJG4kLCBidXQgc29tZSBwYWlycyBhcHBlYXIgbXVsdGlwbGUgdGltZXMsIG90aGVycyBub3QgYXQgYWxsLg0KDQoqICoqQ29tcHV0ZSBCb290c3RyYXAgUmVwbGljYXRlczoqKg0KICArIEZvciBlYWNoICRcbWF0aGJme0R9XipfYiQsIGNvbXB1dGUgdGhlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50ICRyXipfYiQuDQogICANCiogKipFbXBpcmljYWwgRGlzdHJpYnV0aW9uOioqIFRoZSBjb2xsZWN0aW9uICRce3JeKl8xLCByXipfMiwgXGRvdHMsIHJeKl9CXH0kIGZvcm1zIHRoZSBib290c3RyYXAgYXBwcm94aW1hdGlvbiBvZiB0aGUgc2FtcGxpbmcgZGlzdHJpYnV0aW9uIG9mICRyJC4NCg0KXA0KDQoqKkV4YW1wbGUqKjogV2hlbiBib290c3RyYXBwaW5nIGNvcnJlbGF0aW9uLCBpdCBpcyAqKmNyaXRpY2FsKiogdG8gcmVzYW1wbGUgdGhlICoqZW50aXJlIG9yZGVyZWQgcGFpcioqICQoWF9pLCBZX2kpJCBmb3IgZWFjaCBvYnNlcnZhdGlvbiwgcmF0aGVyIHRoYW4gcmVzYW1wbGluZyB0aGUgJFgkIGFuZCAkWSQgdmFyaWFibGVzIGluZGVwZW5kZW50bHkuIFRoaXMgYXBwcm9hY2ggcHJlc2VydmVzIHRoZSBpbmhlcmVudCBqb2ludCBzdHJ1Y3R1cmUgb2YgdGhlIG9yaWdpbmFsIGRhdGFzZXQsIGVuc3VyaW5nIHRoZSBib290c3RyYXAgc2FtcGxlcyBhY2N1cmF0ZWx5IHJlZmxlY3QgdGhlIHRydWUgYml2YXJpYXRlIHJlbGF0aW9uc2hpcC4NCg0KDQpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTR9DQojIEdlbmVyYXRlIGNvcnJlbGF0ZWQgZGF0YQ0Kc2V0LnNlZWQoNzg5KQ0KbiA8LSA0MA0KdHJ1ZV9yaG8gPC0gMC43ICAgICAgIyB0cnVlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50IGluIHRoZSBzaW11bGF0aW9uDQp4IDwtIHJub3JtKG4pDQp5IDwtIHRydWVfcmhvICogeCArIHNxcnQoMSAtIHRydWVfcmhvXjIpICogcm5vcm0obikNCmRhdGFfY29yciA8LSBkYXRhLmZyYW1lKHgsIHkpDQoNCiMgUiBGdW5jdGlvbiBmb3IgQm9vdHN0cmFwIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50DQpib290c3RyYXBfY29ycmVsYXRpb24gPC0gZnVuY3Rpb24oZGF0YSwgQiA9IDEwMDAwKSB7DQogIG4gPC0gbnJvdyhkYXRhKQ0KICBvcmlnaW5hbF9jb3IgPC0gY29yKGRhdGEkeCwgZGF0YSR5KSAgICAgIyBzYW1wbGUgY29ycmVsYXRpb24gY29lZmZpY2llbnQNCiAgYm9vdHN0cmFwX2NvcnMgPC0gbnVtZXJpYyhCKSAgICAgICAgICAgICMgQi1kaW1lbnNpb25hbCB6ZXJvIHZlY3Rvcg0KICANCiAgZm9yIChpIGluIDE6Qikgew0KICAgICMgUmVzYW1wbGUgcGFpcnMgKHJvd3MpIHRvIHByZXNlcnZlIGNvcnJlbGF0aW9uIHN0cnVjdHVyZQ0KICAgIGluZGljZXMgPC0gc2FtcGxlKDE6biwgbiwgcmVwbGFjZSA9IFRSVUUpDQogICAgYm9vdHN0cmFwX3NhbXBsZSA8LSBkYXRhW2luZGljZXMsIF0NCiAgICBib290c3RyYXBfY29yc1tpXSA8LSBjb3IoYm9vdHN0cmFwX3NhbXBsZSR4LCBib290c3RyYXBfc2FtcGxlJHkpDQogIH0NCiBib290c3RyYXBfY29ycw0KfQ0KDQojIFJ1biBib290c3RyYXANCmNvcl9yZXN1bHRzIDwtIGJvb3RzdHJhcF9jb3JyZWxhdGlvbihkYXRhX2NvcnIsIEIgPSA1MDAwKQ0KDQojIFZpc3VhbGl6YXRpb24NCnBhcihtZnJvdyA9IGMoMSwgMikpDQpwbG90KHgsIHksIG1haW4gPSAiT3JpZ2luYWwgRGF0YSIsIHBjaCA9IDE5LCBjb2wgPSAiYmx1ZSIsDQogICAgIHhsYWIgPSAiWCIsIHlsYWIgPSAiWSIpDQphYmxpbmUobG0oeSB+IHgpLCBjb2wgPSAicmVkIiwgbHdkID0gMikNCg0KaGlzdChjb3JfcmVzdWx0cywgYnJlYWtzID0gMzAsIA0KICAgICBtYWluID0gIkJvb3RzdHJhcCBEaXN0cmlidXRpb25cbm9mIENvcnJlbGF0aW9uIiwNCiAgICAgeGxhYiA9ICJDb3JyZWxhdGlvbiBDb2VmZmljaWVudCIsIGNvbCA9ICJzdGVlbGJsdWUiLA0KICAgICBwcm9iYWJpbGl0eSA9IFRSVUUsIHhsaW0gPSBjKDAsIDEpKQ0KYGBgDQoNCg0KDQoNCioqRXhhbXBsZSoqOiBVc2luZyBib290IFBhY2thZ2UgdG8gcGVyZm9ybSBCb290c3RyYXAgc2FtcGxpbmcgYW5kIGVzdGltYXRpb24uDQoNCmBgYHtyfQ0KIyBVc2luZyB0aGUgYm9vdCBwYWNrYWdlIGZvciBtb3JlIHNvcGhpc3RpY2F0ZWQgYW5hbHlzZXMNCmxpYnJhcnkoYm9vdCkNCg0KIyBEZWZpbmUgc3RhdGlzdGljIGZ1bmN0aW9uIC0gDQptZWFuX3N0YXQgPC0gZnVuY3Rpb24oZGF0YSwgaW5kaWNlcykgew0KICBkIDwtIGRhdGFbaW5kaWNlc10gICMgQWxsb3dzIGJvb3QgdG8gc2VsZWN0IHJlc2FtcGxlcw0KICByZXR1cm4obWVhbihkKSkNCn0NCg0KIyBSdW4gYm9vdHN0cmFwIHVzaW5nIGJvb3QoKQ0Kc2V0LnNlZWQoMTIzKQ0Kc2FtcGxlX2RhdGEgPC0gcmdhbW1hKDI1LCBzaGFwZSA9IDIsIHJhdGUgPSAxKQ0KYm9vdF9yZXN1bHRzIDwtIGJvb3Qoc2FtcGxlX2RhdGEsIHN0YXRpc3RpYyA9IG1lYW5fc3RhdCwgUiA9IDUwMDApDQoNCiMgQmFzaWMgYm9vdHN0cmFwDQpwbG90KGJvb3RfcmVzdWx0cykNCmBgYA0KDQoNCg0KIyBQcmFjdGljYWwgQ29uc2lkZXJhdGlvbnMNCg0KKipXaGVuIHRvIFVzZSBCb290c3RyYXAqKg0KDQotICAgU21hbGwgdG8gbW9kZXJhdGUgc2FtcGxlIHNpemVzDQotICAgQ29tcGxleCBzdGF0aXN0aWNzIHdpdGhvdXQga25vd24gc2FtcGxpbmcgZGlzdHJpYnV0aW9uDQotICAgQXNzZXNzbWVudCBvZiBlc3RpbWF0b3IgdmFyaWFiaWxpdHkNCi0gICBCaWFzIGVzdGltYXRpb24gYW5kIGNvcnJlY3Rpb24NCg0KKipMaW1pdGF0aW9ucyBhbmQgQ2F2ZWF0cyoqDQoNCi0gICAqKlNhbXBsZSByZXByZXNlbnRhdGl2ZW5lc3MqKjogQm9vdHN0cmFwIGFzc3VtZXMgc2FtcGxlIHJlcHJlc2VudHMgcG9wdWxhdGlvbg0KLSAgICoqU21hbGwgc2FtcGxlcyoqOiBNYXkgcGVyZm9ybSBwb29ybHkgd2l0aCAkbiA8IDIwJA0KLSAgICoqSGVhdnktdGFpbGVkIGRpc3RyaWJ1dGlvbnMqKjogTWF5IHJlcXVpcmUgbW9yZSBib290c3RyYXAgcmVwbGljYXRpb25zDQotICAgKipEZXBlbmRlbmNlIHN0cnVjdHVyZSoqOiBSZXF1aXJlcyBtb2RpZmljYXRpb24gZm9yIHRpbWUgc2VyaWVzL3NwYXRpYWwgZGF0YQ0KLSAgICoqQm91bmRhcnkgaXNzdWVzKio6IFByb2JsZW1zIHdpdGggc3RhdGlzdGljcyBuZWFyIGJvdW5kYXJpZXMNCg0KKipDaG9vc2luZyBOdW1iZXIgb2YgQm9vdHN0cmFwIFNhbXBsZXMgKCoqJEIkKQ0KDQotICAgKipTdGFuZGFyZCBlcnJvcnMqKjogJEIgXGdlcSAyMDAkIG9mdGVuIHN1ZmZpY2llbnQNCi0gICAqKkNvbmZpZGVuY2UgaW50ZXJ2YWxzKio6ICRCIFxnZXEgMTAwMCQgcmVjb21tZW5kZWQNCi0gICAqKkJDYSBpbnRlcnZhbHMqKjogJEIgXGdlcSA1MDAwJCBmb3Igc3RhYmxlIHJlc3VsdHMNCi0gICAqKlBlcmNlbnRpbGUgbWV0aG9kcyoqOiBMYXJnZXIgJEIkIGZvciBhY2N1cmF0ZSB0YWlsIGVzdGltYXRpb24NCg0KDQoNCg==