1 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).

2 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

3 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.

3.1 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:

  1. An estimator of population parameter \(\theta\), denoted by \(\hat{\theta}\), is a function of data values.

  2. 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.

3.2 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.

3.3 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

  1. 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.

  2. Generate Pseudo-Values: For each \(i = 1, \dots, n\):

    1. Construct the i-th Jackknife sample \(X_{(-i)}\) by removing observation \(x_i\).
    2. Compute the corresponding statistic \(\hat{\theta}_{(-i)} = s(X_{(-i)})\).
  3. Calculate the Mean Replicate: Compute the average of the Jackknife replicates:
    \(\bar{\theta}_{(\cdot)} = \frac{1}{n} \sum_{i=1}^{n} \hat{\theta}_{(-i)}\).

  4. 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\).
  5. 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)

3.4 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

4 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)

5 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==