A workflow for deciding how many digits to report when summarizing the posterior distribution, and how to check how many independent Monte Carlo (MC) draws or dependent Markov chain Monte Carlo (MCMC) draws are needed.

Introduction

When running any iterative algorithm we need to decide when to stop or how many iterations and how many sequences to run. In the context of posterior inference, the answer can be divided in two parts: (1) how many chains and iterations do we need to assess that the algorithm is sampling from something close to the target distribution, and (2) how many draws do we need so that the reported posterior summaries would not change in important ways if the inference would be repeated? This notebook discusses the second part.

Before we can answer how many chains and iterations we need to run, we need to know how many significant digits we want to report. Too often, we see tables filled with numbers like \(1.7705\). It’s very unlikely that all these digits are accurately estimated, and also very unlikely that the accuracy in magnitude of one in ten thousand would be needed for any practical purpose. Reporting too many digits makes it more difficult to read summary tables. Thus, before considering how many iterations we need it’s useful to consider how many digits it is sensible to report.

Without any additional information, we may assume that relative errors smaller than 1% are typically negligible and thus most of the time reporting at most 2 significant digits would be sufficient. Accuracy to just one significant digit can be sufficient in the early stages of analysis and can be sensible and convenient even in final reporting, as discussed in the example below.

MCMC and other Monte Carlo methods are stochastic and if the inference would be repeated with a different random seed (random number generators in computers are usually producing deterministic pseudo-random sequences), the estimates would vary. The amount of variation reduces when more iterations are used. For example, if the posterior would be close to normal with standard deviation 1, \(\mathrm{normal}(\mu, 1)\), then 2000 independent draws from the posterior would provide enough accuracy that the second significant digit of posterior mean would only sometimes vary to one smaller or larger value. On the other hand, for 1 significant digit accuracy, 100 independent draws would be often sufficient, but reliable convergence diagnostics may need more iterations than 100 (see, e.g., Vehtari et al. (2021)). The above thumb-rules are useful for the necessary number of independent draws for a posterior mean of a distribution which is relatively close to normal and in other cases and, for exmaple, for posterior quantiles more draws may be needed.

MCMC in general doesn’t produce independent draws and the effect of dependency affects how many draws are needed to estimate different expectations. As in general, we don’t know beforhand how MCMC will perform for a new posterior, and we don’t know what is the scale of that posterior beforehand, we need to start with some initial guess of number of iterations to run.

Summary

Summary of workflow for how many digits to report

  1. Run inference with some default number of iterations
  2. Check convergence diagnostics for all parameters
  3. Check that ESS is big enough for reliable convergence diagnostics for all quantities of interest
  4. Look at the posterior for quantities of interest and decide how many significant digits is reasonable taking into account the posterior uncertainty (using SD, MAD, or tail quantiles)
  5. Check that MCSE is small enough for the desired accuracy of reporting the posterior summaries for the quantities of interest.
  • If the accuracy is not sufficient, report less digits or run more iterations.
  • Halving MCSE requires quadrupling the number of iterations (if CLT holds).
  • Different quantities of interest have different MCSE and may require different number of iterations for the desired accuracy.
  • Some quantities of interest may have posterior distribution with infinite variance, and then the ESS and MCSE are not defined for the expectation. In such cases use, for example, median instead of mean and mean absolute deviation (MAD) instead of standard deviation. ESS and MCSE for (non-extreme) quantiles can be derived from the (non-extreme) cumulative probabilities that always have finite mean and variance.

Example

As an example, we analyse the trend in summer months average temperature 1952–2013 at Kilpisjärvi in northwestern Finnish Lapland. Summer months are June, July, and August, and we analyse the average temperature over these months in each year.

Load packages

library("rprojroot")
root<-has_file(".Workflow-Examples-root")$make_fix_file()
library(tidyr) 
library(dplyr) 
library(cmdstanr)
library(posterior)
options(pillar.negative = FALSE)
library(lemon)
library(ggplot2)
library(bayesplot)
theme_set(bayesplot::theme_default(base_family = "sans"))
SEED <- 48927 # set random seed for reproducibility

Kilpisjärvi data and model

Data

Load Kilpisjärvi summer month average temperatures 1952-2013:

data_kilpis <- read.delim(root("Digits/data","kilpisjarvi-summer-temp.csv"), sep = ";")
data_lin <-list(N = nrow(data_kilpis),
             x = data_kilpis$year,
             xpred = 2016,
             y = data_kilpis[,5])

Plot the data

ggplot() +
  geom_point(aes(x, y), data = data.frame(data_lin), size = 1) +
  labs(y = 'Summer temperature\n at Kilpisjärvi', x= "Year")

Gaussian linear model

We use a simple linear model with normal observation model, weakly informative normal prior, and the predictor (time) centered to have 0 mean. We assume a priori that increase or decrease in temperature is equally likely, and that it is unlikely that temperature would change more 10 degrees in 100 years. We also assume that yearly variation in summer temperatures is likely to be less than 3 degrees.

The following Stan code centers the covariate to reduce posterior dependency of slope and coefficient parameters. It also makes it easier to define the prior on average temperature in the center of the time range (instead defining prior for temperature at year 0).

code_lin <- root("Digits", "linear.stan")
writeLines(readLines(code_lin))
// Gaussian linear model with adjustable priors
data {
  int<lower=0> N; // number of data points
  vector[N] x;    // covariate / predictor
  vector[N] y;    // target
  real pmualpha_c;// prior mean for alpha_c
  real psalpha;   // prior std for alpha
  real pmubeta;   // prior mean for beta
  real psbeta;    // prior std for beta
  real pssigma;   // prior std for half-normal prior for sigma
}
transformed data {
  // centering the predictor makes the posterior easier to sample
  real xmean = mean(x);
  vector[N] x_c = x - xmean;
}
parameters {
  real alpha_c;        // intercept for centered x
  real beta;           // slope
  real<lower=0> sigma; // standard deviation is constrained to be positive
}
model {
  alpha_c ~ normal(pmualpha_c, psalpha);   // prior
  beta ~ normal(pmubeta, psbeta);          // prior
  sigma ~ normal(0, pssigma);              // as sigma is constrained to be positive,
                                           // this is same as half-normal prior
  y ~ normal(alpha_c + beta*x_c, sigma); // observation model / likelihood
}

Prior parameter values for weakly informative priors

data_lin_priors <- c(list(
    pmualpha_c = 10,     # prior mean for average temperature
    psalpha = 10,        # weakly informative
    pmubeta = 0,         # a priori incr. and decr. as likely
    psbeta = 0.1/3,   # avg temp prob does does not incr. more than a degree per 10 years:  setting this to +/-3 sd's
    pssigma = 1),        # setting sd of total variation in summer average temperatures to 1 degree implies that +/- 3 sd's is +/-3 degrees: 
  data_lin)

Run inference for some number of iterations

We run MCMC with Stan’s current default settings. All convergence diagnostics pass and all effective sample size are big enough that we can assume that the convergence diagnostics are reliable.

mod_lin <- cmdstan_model(stan_file = code_lin)
fit_lin <- mod_lin$sample(data = data_lin_priors, seed = SEED, refresh = 0)

Run convergence diagnostics

There were no convergence issues reported by sampling. We can also explicitly call CmdStan inference diagnostics:

fit_lin$cmdstan_diagnose()
Processing csv files: /tmp/RtmpHmb0aX/linear-202310221755-1-667708.csv, /tmp/RtmpHmb0aX/linear-202310221755-2-667708.csv, /tmp/RtmpHmb0aX/linear-202310221755-3-667708.csv, /tmp/RtmpHmb0aX/linear-202310221755-4-667708.csv

Checking sampler transitions treedepth.
Treedepth satisfactory for all transitions.

Checking sampler transitions for divergences.
No divergent transitions found.

Checking E-BFMI - sampler transitions HMC potential energy.
E-BFMI satisfactory.

Effective sample size satisfactory.

Split R-hat values satisfactory all parameters.

Processing complete, no problems detected.

We check \(\widehat{R}\) end ESS values, which in this case all look good.

draws <- as_draws_rvars(fit_lin$draws())
summarize_draws(draws)
variable mean median sd mad q5 q95 rhat ess_bulk ess_tail
lp__ -38.56 -38.20 1.30 1.02 -41.09 -37.21 1 1880 2642
alpha_c 9.32 9.32 0.14 0.14 9.09 9.55 1 3364 2436
beta 0.02 0.02 0.01 0.01 0.01 0.03 1 3864 2525
sigma 1.12 1.11 0.10 0.10 0.97 1.29 1 3014 2776

Compute posterior draws for the linear fit

draws$mu <- draws$alpha_c+draws$beta*(data_lin$x-mean(data_lin$x))

Plot the linear fit with 90% posterior interval

data.frame(x = data_lin$x,
           y = data_lin$y,
           Emu = mean(draws$mu),
           q05 = as.vector(quantile(draws$mu, 0.05)),
           q95 = as.vector(quantile(draws$mu, 0.95))) %>% 
  ggplot() +
  geom_ribbon(aes(x=x, ymin=q05, ymax=q95), fill='grey90') +
  geom_line(aes(x=x, y=Emu, )) +
  geom_point(aes(x, y), size = 1) +
  labs(y = 'Summer temperature\n at Kilpisjärvi (°C)', x= "Year")+
  guides(linetype = "none")

At this point it is sufficient that diagnostics are OK (cmdstan_diagnose says “no problems detected”) and effective sample sizes are large enough (>400) that we can assume the diagnostics to be reliable.

We could also do posterior predictive checking and residual plots, but now we focus on checking how many MCMC iterations are needed and how many digits to report in posterior summary results.

How many digits to report based on posterior uncertainty

We want to report posterior summaries for the slope, that is the increase in average summer temperature, and for the probability that the slope is positive. We first consider what is the reasonable reporting accuracy if the posterior inference would be exact (ie ignoring first the Monet Carlo variability).

We start looking at the mean and 90% interval for the slope parameter beta

draws %>%
  subset_draws("beta") %>%
  summarize_draws(mean, ~quantile(.x, probs = c(0.05, 0.95))) 
variable mean 5% 95%
beta 0.02 0.007 0.032

These values correspond to the temperature increase per year, but to improve readability we switch looking at the temperature increase per 100 years.

draws <- draws %>%
  mutate_variables(beta100 = 100*beta)

Let’s look at the mean and 90% interval for the expected temperature increase per 100 years.

draws %>%
  subset_draws("beta100") %>%
  summarize_draws(mean, ~quantile(.x, probs = c(0.05, 0.95)))
variable mean 5% 95%
beta100 1.966 0.673 3.242

The number of digits shown in R varies depending on the print method and options for the specific object and above we see 3 decimal digits. Depending on the print method, We may also see more digits, for example:

mean(draws$beta)
[1] 0.01965928
quantile(draws$beta, probs=c(0.05,0.95))
[1] 0.006732486 0.032416130

The more digits are shown, the more of them are likely to be unnecessary clutter distracting the reader from the important message. Considering the width of the 90% interval, practically meaningful accuracy would be here to report posterior mean as 2.0 and the posterior interval as [0.7 , 3.2]. Depending on the context, it might be even better to round more, and report that the increase is estimated to be 1 to 3 degrees per century (81% probability, or rounded to 80% probability), or 0 to 4 degrees per century (99% probability). There is no need to stick to reporting 90% or 95% interval.

The number of significant digits needed for reporting can be often determined also with rough posterior approximations that indicate the order of magnitude of the posterior mean and scale, and then more iterations may be needed to get more accurate estimate for those digits.

How many digits to report based on Monte Carlo standard error

Now that we have an estimate for the posterior uncertainty of the slope parameter, we can check whether we have enough many iterations for the desired reporting accuracy. Markov chain Monte Carlo method used by Stan to make the posterior estimates is stochastic. If we repeat the computation with different random number generator seed, we get slightly different estimates.

estimates <- t(sapply(1:10, function(i) {
  mod_lin$sample(data = data_lin_priors, seed = SEED+i, refresh = 0,
                 show_messages = FALSE)$draws() %>%
    mutate_variables(beta100 = 100*beta) %>%
    subset_draws("beta100") %>%
      summarize_draws(mean, ~quantile(.x, probs = c(0.05, 0.95))) %>%
      select(-variable)})) %>% unlist() %>% matrix(nrow=10)
colnames(estimates) <- c("mean" ,"5%","95%")
as_tibble(estimates)
mean 5% 95%
1.939 0.662 3.202
1.918 0.580 3.196
1.963 0.665 3.310
1.931 0.583 3.249
1.937 0.647 3.196
1.926 0.660 3.166
1.939 0.651 3.268
1.928 0.651 3.204
1.933 0.677 3.212
1.918 0.649 3.190

We see that for mean the third digit is varying and the rounded value is between 1.9 and 2.0. For the 5% quantile even the first significant digit is sometimes varying and the rounded value would vary between 0.6 and 0.7. For the 95% quantile the second digit is varying and the rounded values would vary between 3.2 and 3.3. Based on this, it would be OK to report the mean as 1.9 or 2 and 90% interval as [0.7, 3.2] as based on the first Monte Carlo estimate. Considering the scale, the minor variation in the last digit is not affecting the interpretation of the results. Alternatively the courser ranges [1, 3] or [0, 4] could be reported as discussed above.

Instead of repeating the estimation many times we can estimate the accuracy of the original sampling by computing Monte Carlo standard error (MCSE) that takes into account the quantity of interest, and the effective sample size of MCMC draws (see, e.g., Vehtari et al. (2021)).

draws %>%
  subset_draws("beta100") %>%
  summarize_draws(mcse_mean, ~mcse_quantile(.x, probs = c(0.05, 0.95)))
variable mcse_mean mcse_q5 mcse_q95
beta100 0.013 0.036 0.033

We show also the ESS values for mean and quantiles, to illustrate that the ESS values can be different for different quantities, but also that the same ESS doesn’t lead to the same MCSE, and similar ESS doesn’t lead to similar MCSE as MCSE depends also on the quantity. Here, for example, although ESSs are similar for all quantities, 5% and 95% quantiles have clearly higher MCSE than the mean.

draws %>%
  subset_draws("beta100") %>%
  summarize_draws(ess_mean, ~ess_quantile(.x, probs = c(0.05, 0.95)))
variable ess_mean ess_q5 ess_q95
beta100 3816 2525 3153

The MCSE for the mean estimate is about 0.01 and for 5% and 95% quantiles about 0.03. If we multiply these by 2, the likely range of variation due to Monte Carlo is \(\pm 0.02\) for mean and \(\pm 0.07\) for 5% and 95% quantiles. From this we can interpret that it’s unlikely there would be variation in the reported estimate for the mean, if it is reported as 2.0. For 5% and 95% quantiles there can be variation in the first decimal digit, but that difference would not be meaningful in most cases. We could run more iterations to get the MCSE for quantiles down to something like 0.01, which would require about 10 times more iterations. Assuming the posterior has finite variance and MCMC is mixing well, we expect that running four times more iterations would halve the MCSEs.

As discussed before, it might be anyway better to report the posterior uncertainty interval with less digits, and if we reported either 80% interval \([1, 3]\) or 99% interval \([0, 4]\), we would already have sufficient accuracy for the number of shown digits. These MCSE estimates illustrate also the fact that usually tail quantiles have lower accuracy than the posterior mean.

We can also report the probability that the temperature change is positive.

draws %>%
  mutate_variables(beta0p = beta100>0) %>%
  subset_draws("beta0p") %>%
  summarize_draws("mean", mcse = mcse_mean)
variable mean mcse
beta0p 0.993 0.001

The probability is simply estimated as a posterior mean of an indicator function and the usual MCSE for mean estimate is used. The MCSE indicates that we have enough MCMC iterations for practically meaningful reporting that the probability that the temperature is increasing is larger than 99%. There is not much practical difference to reporting that the probability is 99.3% and to estimate that third digit accurately would require 64 times more iterations. For this simple problem, sampling that many iterations would not be time consuming, but we might also instead consider to obtain more data to verify that the summer temperature in northern Finland has been increasing since 1952.

We additionaly compute probabilities that the temperature increase is more than 1, 2, 3 or 4 degrees, and corresponding MCSEs and ESSs.

draws %>%
  subset_draws("beta100") %>%
  mutate_variables(beta1p = beta100>1,
                   beta2p = beta100>2,
                   beta3p = beta100>3,
                   beta4p = beta100>4) %>%
  subset_draws("beta[1-4]p", regex=TRUE) %>%
  summarize_draws("mean", mcse = mcse_mean, ESS = ess_mean)
variable mean mcse ESS
beta1p 0.896 0.006 3020
beta2p 0.487 0.008 4311
beta3p 0.088 0.005 3188
beta4p 0.006 0.001 3265

Taking into account MCSEs given the current posterior sample, we can summarise these as p(beta100>1) = 88%–91%, p(beta100>2) = 46%–51%, p(beta100>3) = 7%–10%, p(beta100>4) = 0.2%–1%. To get these probabilities estimated with 2 digit accuracy would again require more iterations (16-300 times more iterations depending on the quantity), but the added iterations would not change the conclusion radically.

MCSE computation details

The details of how MCSE is estimated for posterior expectations and quantiles are provided by Vehtari et al. (2021), and implementations are available, for example in the posterior R package used in this notebook and in ArviZ Python package.

Rough estimates for how many iterations to run initially

Before running any MCMC, we may obtain some rough estimates of how many iterations we would need for certain relative accuracy for the posterior mean (if MCMC runs well).

If we assume that the posterior of parameter \(\theta\) has finite mean and variance, and we have many independent Monte Carlo draws \(S\), we can use central limit theorem to justify that the uncertainty related to the estimated expectation can be approximated with normal distribution, \(\mathrm{normal}(\hat{\theta}, \hat{\sigma}_\theta / \sqrt{S})\), where \(\hat{\theta}\) is the estimate and \(\hat{\sigma}_\theta\) is the estimated posterior standard deviation of \(\theta\).

We can see that given any \(\hat{\theta}\) and \(\hat{\sigma}_\theta\), if \(S=100\), the uncertainty is 10% of the posterior scale which would often be sufficient for initial experiments, and if \(S=10000\), the uncertainty is 1% of the posterior scale which would often be sufficient for two significant digit accuracy.

10% relative accuracy means that despite the magnitude of \(\hat{\sigma}_\theta\) we get accuracy approximately a worth at least one digit. Let’s first assume \(\hat{\theta} = 1.234\). We can simplify the analysis by noting that if examine the behavior given different \(\hat{\sigma}_\theta\) values as, e.g., \(10^{-1}\), \(10^{0}\), \(10^{1}\), and correspondingly present the \(\hat{\theta}\) as \(12.34 \times 10^{-1}\), \(1.234 \times 10^{0}\), \(0.1234 \times 10^{1}\). We get equivalent, but simpler analysis if we set \(\hat{\sigma}_\theta=1\) and analyse the cases with different values \(\hat{\theta}\) (ie we change the coordinates to have unit scale with respect to the posterior standard deviation).

  • If \(S=100\) (independent draws) and \(\hat{\sigma}_\theta=1\), MCSE is \(0.1\) and with 99% probability that variation in E[\(\theta\)] is \(\pm 0.3\). Thus, if the estimation would be repeated the first significant digit would stay the same or have minor variability to one smaller or one lager digit. Thus we have approximately one significant digit accuracy.
  • If \(S=2000\) (independent draws) and \(\hat{\sigma}_\theta=1\), MCSE is \(0.02\) and with 99% probability that variation in E[\(\theta\)] is \(\pm 0.07\). Thus, if the estimation would be repeated the first significant digit would stay the same, and the second significant digit would have have minor variability to one smaller or one lager digit. Thus we have approximately two significant digit accuracy. With a larger \(S\), there is less variability in the second significant digit.

Dynamic Hamiltonian Monte Carlo in Stan is often so efficient that ESS>S/2. Thus running with the default options 4 chains with 1000 iterations after warmup is likely to give near two significant digit accuracy for the posterior mean. The accuracy for 5% and 95% quantiles would be between one and two significant digits.

The above analysis shows the benefit of interpreting ESS as a scale free diagnostic whether we are likely to have enough iterations. A scale free here means we don’t need to compare ESS values to posterior standard deviations or to domain knowledge of the quantity of interest, making it faster to check that we have high enough ESS for many quantities of interest. However, high ESS is not sufficient to guarantee certain accuracy, as MCSE depends also on the quantity of interest and thus in the end it is useful to check MCSEs for the values to be reported. For example, above, the estimate for whether the temperature increase is larger than 4 degrees per century has high ESS, but the indicator variable contains less information (than continuous values) and thus much higher ESS would be needed for two significant digit accuracy.


References

Vehtari, A., Gelman, A., Simpson, D., Carpenter, B. and Bürkner, P.-C. (2021) ‘Rank-normalization, folding, and localization: An improved \(\widehat{R}\) for assessing convergence of MCMC’, Bayesian Analysis, 16(2), pp. 667–718.

LS0tCnRpdGxlOiAiSG93IG1hbnkgaXRlcmF0aW9ucyB0byBydW4gYW5kIGhvdyBtYW55IGRpZ2l0cyB0byByZXBvcnQiCmF1dGhvcjogIkFraSBWZWh0YXJpIgpkYXRlOiAiRmlyc3QgdmVyc2lvbiAyMDIwLTEyLTA1LiBMYXN0IG1vZGlmaWVkIGByIGZvcm1hdChTeXMuRGF0ZSgpKWAuIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiByZWFkYWJsZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDIKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQpiaWJsaW9ncmFwaHk6IGRpZ2l0cy5iaWIKY3NsOiBoYXJ2YXJkLWNpdGUtdGhlbS1yaWdodC5jc2wKbGluay1jaXRhdGlvbnM6IHllcwotLS0KCkEgd29ya2Zsb3cgZm9yIGRlY2lkaW5nIGhvdyBtYW55IGRpZ2l0cyB0byByZXBvcnQgd2hlbiBzdW1tYXJpemluZwp0aGUgcG9zdGVyaW9yIGRpc3RyaWJ1dGlvbiwgYW5kIGhvdyB0byBjaGVjayBob3cgbWFueSBpbmRlcGVuZGVudApNb250ZSBDYXJsbyAoTUMpIGRyYXdzIG9yIGRlcGVuZGVudCBNYXJrb3YgY2hhaW4gTW9udGUgQ2FybG8gKE1DTUMpCmRyYXdzIGFyZSBuZWVkZWQuCgojIEludHJvZHVjdGlvbgoKV2hlbiBydW5uaW5nIGFueSBpdGVyYXRpdmUgYWxnb3JpdGhtIHdlIG5lZWQgdG8gZGVjaWRlIHdoZW4gdG8gc3RvcCBvciBob3cgbWFueSBpdGVyYXRpb25zIGFuZCBob3cgbWFueSBzZXF1ZW5jZXMgdG8gcnVuLiBJbiB0aGUgY29udGV4dCBvZiBwb3N0ZXJpb3IgaW5mZXJlbmNlLCB0aGUgYW5zd2VyIGNhbiBiZSBkaXZpZGVkIGluIHR3byBwYXJ0czogKDEpIGhvdyBtYW55IGNoYWlucyBhbmQgaXRlcmF0aW9ucyBkbyB3ZSBuZWVkIHRvIGFzc2VzcyB0aGF0IHRoZSBhbGdvcml0aG0gaXMgc2FtcGxpbmcgZnJvbSBzb21ldGhpbmcgY2xvc2UgdG8gdGhlIHRhcmdldCBkaXN0cmlidXRpb24sIGFuZCAoMikgaG93IG1hbnkgZHJhd3MgZG8gd2UgbmVlZCBzbyB0aGF0IHRoZSByZXBvcnRlZCBwb3N0ZXJpb3Igc3VtbWFyaWVzIHdvdWxkIG5vdCBjaGFuZ2UgaW4gaW1wb3J0YW50IHdheXMgaWYgdGhlIGluZmVyZW5jZSB3b3VsZCBiZSByZXBlYXRlZD8gVGhpcyBub3RlYm9vayBkaXNjdXNzZXMgdGhlIHNlY29uZCBwYXJ0LgoKQmVmb3JlIHdlIGNhbiBhbnN3ZXIgaG93IG1hbnkgY2hhaW5zIGFuZCBpdGVyYXRpb25zIHdlIG5lZWQgdG8gcnVuLCB3ZSBuZWVkIHRvIGtub3cgaG93IG1hbnkgc2lnbmlmaWNhbnQgZGlnaXRzIHdlIHdhbnQgdG8gcmVwb3J0LiBUb28gb2Z0ZW4sIHdlIHNlZSB0YWJsZXMgZmlsbGVkIHdpdGggbnVtYmVycyBsaWtlICQxLjc3MDUkLiBJdCdzIHZlcnkgdW5saWtlbHkgdGhhdCBhbGwgdGhlc2UgZGlnaXRzIGFyZSBhY2N1cmF0ZWx5IGVzdGltYXRlZCwgYW5kIGFsc28gdmVyeSB1bmxpa2VseSB0aGF0IHRoZSBhY2N1cmFjeSBpbiBtYWduaXR1ZGUgb2Ygb25lIGluIHRlbiB0aG91c2FuZCB3b3VsZCBiZSBuZWVkZWQgZm9yIGFueSBwcmFjdGljYWwgcHVycG9zZS4gUmVwb3J0aW5nIHRvbyBtYW55IGRpZ2l0cyBtYWtlcyBpdCBtb3JlIGRpZmZpY3VsdCB0byByZWFkIHN1bW1hcnkgdGFibGVzLiBUaHVzLCBiZWZvcmUgY29uc2lkZXJpbmcgaG93IG1hbnkgaXRlcmF0aW9ucyB3ZSBuZWVkIGl0J3MgdXNlZnVsIHRvIGNvbnNpZGVyIGhvdyBtYW55IGRpZ2l0cyBpdCBpcyBzZW5zaWJsZSB0byByZXBvcnQuCgpXaXRob3V0IGFueSBhZGRpdGlvbmFsIGluZm9ybWF0aW9uLCB3ZSBtYXkgYXNzdW1lIHRoYXQgcmVsYXRpdmUgZXJyb3JzIHNtYWxsZXIgdGhhbiAxXCUgYXJlIHR5cGljYWxseSBuZWdsaWdpYmxlIGFuZCB0aHVzIG1vc3Qgb2YgdGhlIHRpbWUgcmVwb3J0aW5nIGF0IG1vc3QgMiBzaWduaWZpY2FudCBkaWdpdHMgd291bGQgYmUgc3VmZmljaWVudC4gQWNjdXJhY3kgdG8ganVzdCBvbmUgc2lnbmlmaWNhbnQgZGlnaXQgY2FuIGJlIHN1ZmZpY2llbnQgaW4gdGhlIGVhcmx5IHN0YWdlcyBvZiBhbmFseXNpcyBhbmQgY2FuIGJlIHNlbnNpYmxlIGFuZCBjb252ZW5pZW50IGV2ZW4gaW4gZmluYWwgcmVwb3J0aW5nLCBhcyBkaXNjdXNzZWQgaW4gdGhlIGV4YW1wbGUgYmVsb3cuCgpNQ01DIGFuZCBvdGhlciBNb250ZSBDYXJsbyBtZXRob2RzIGFyZSBzdG9jaGFzdGljIGFuZCBpZiB0aGUgaW5mZXJlbmNlIHdvdWxkIGJlIHJlcGVhdGVkIHdpdGggYSBkaWZmZXJlbnQgcmFuZG9tIHNlZWQgKHJhbmRvbSBudW1iZXIgZ2VuZXJhdG9ycyBpbiBjb21wdXRlcnMgYXJlIHVzdWFsbHkgcHJvZHVjaW5nIGRldGVybWluaXN0aWMgcHNldWRvLXJhbmRvbSBzZXF1ZW5jZXMpLCB0aGUgZXN0aW1hdGVzIHdvdWxkIHZhcnkuIFRoZSBhbW91bnQgb2YgdmFyaWF0aW9uIHJlZHVjZXMgd2hlbiBtb3JlIGl0ZXJhdGlvbnMgYXJlIHVzZWQuIEZvciBleGFtcGxlLCBpZiB0aGUgcG9zdGVyaW9yIHdvdWxkIGJlIGNsb3NlIHRvIG5vcm1hbCB3aXRoIHN0YW5kYXJkIGRldmlhdGlvbiAxLCAkXG1hdGhybXtub3JtYWx9KFxtdSwgMSkkLCB0aGVuIDIwMDAgaW5kZXBlbmRlbnQgZHJhd3MgZnJvbSB0aGUgcG9zdGVyaW9yIHdvdWxkIHByb3ZpZGUgZW5vdWdoIGFjY3VyYWN5IHRoYXQgdGhlIHNlY29uZCBzaWduaWZpY2FudCBkaWdpdCBvZiBwb3N0ZXJpb3IgbWVhbiB3b3VsZCBvbmx5IHNvbWV0aW1lcyB2YXJ5IHRvIG9uZSBzbWFsbGVyIG9yIGxhcmdlciB2YWx1ZS4gT24gdGhlIG90aGVyIGhhbmQsIGZvciAxIHNpZ25pZmljYW50IGRpZ2l0IGFjY3VyYWN5LCAxMDAgaW5kZXBlbmRlbnQgZHJhd3Mgd291bGQgYmUgb2Z0ZW4gc3VmZmljaWVudCwgYnV0IHJlbGlhYmxlIGNvbnZlcmdlbmNlIGRpYWdub3N0aWNzIG1heSBuZWVkIG1vcmUgaXRlcmF0aW9ucyB0aGFuIDEwMCAoc2VlLCBlLmcuLCBAVmVodGFyaStldGFsOjIwMjE6UmhhdCkuIFRoZSBhYm92ZSB0aHVtYi1ydWxlcyBhcmUgdXNlZnVsIGZvciB0aGUgbmVjZXNzYXJ5IG51bWJlciBvZiBpbmRlcGVuZGVudCBkcmF3cyBmb3IgYSBwb3N0ZXJpb3IgbWVhbiBvZiBhIGRpc3RyaWJ1dGlvbiB3aGljaCBpcyByZWxhdGl2ZWx5IGNsb3NlIHRvIG5vcm1hbCBhbmQgaW4gb3RoZXIgY2FzZXMgYW5kLCBmb3IgZXhtYXBsZSwgZm9yIHBvc3RlcmlvciBxdWFudGlsZXMgbW9yZSBkcmF3cyBtYXkgYmUgbmVlZGVkLgoKTUNNQyBpbiBnZW5lcmFsIGRvZXNuJ3QgcHJvZHVjZSBpbmRlcGVuZGVudCBkcmF3cyBhbmQgdGhlIGVmZmVjdCBvZiBkZXBlbmRlbmN5IGFmZmVjdHMgaG93IG1hbnkgZHJhd3MgYXJlIG5lZWRlZCB0byBlc3RpbWF0ZSBkaWZmZXJlbnQgZXhwZWN0YXRpb25zLiBBcyBpbiBnZW5lcmFsLCB3ZSBkb24ndCBrbm93IGJlZm9yaGFuZCBob3cgTUNNQyB3aWxsIHBlcmZvcm0gZm9yIGEgbmV3IHBvc3RlcmlvciwgYW5kIHdlIGRvbid0IGtub3cgd2hhdCBpcyB0aGUgc2NhbGUgb2YgdGhhdCBwb3N0ZXJpb3IgYmVmb3JlaGFuZCwgd2UgbmVlZCB0byBzdGFydCB3aXRoIHNvbWUgaW5pdGlhbCBndWVzcyBvZiBudW1iZXIgb2YgaXRlcmF0aW9ucyB0byBydW4uCgojIFN1bW1hcnkKClN1bW1hcnkgb2Ygd29ya2Zsb3cgZm9yIGhvdyBtYW55IGRpZ2l0cyB0byByZXBvcnQKCjEuIFJ1biBpbmZlcmVuY2Ugd2l0aCBzb21lIGRlZmF1bHQgbnVtYmVyIG9mIGl0ZXJhdGlvbnMKMi4gQ2hlY2sgY29udmVyZ2VuY2UgZGlhZ25vc3RpY3MgZm9yIGFsbCBwYXJhbWV0ZXJzCjMuIENoZWNrIHRoYXQgRVNTIGlzIGJpZyBlbm91Z2ggZm9yIHJlbGlhYmxlIGNvbnZlcmdlbmNlCiAgIGRpYWdub3N0aWNzIGZvciBhbGwgcXVhbnRpdGllcyBvZiBpbnRlcmVzdAo0LiBMb29rIGF0IHRoZSBwb3N0ZXJpb3IgZm9yIHF1YW50aXRpZXMgb2YgaW50ZXJlc3QgYW5kIGRlY2lkZSBob3cKICAgbWFueSBzaWduaWZpY2FudCBkaWdpdHMgaXMgcmVhc29uYWJsZSB0YWtpbmcgaW50byBhY2NvdW50IHRoZQogICBwb3N0ZXJpb3IgdW5jZXJ0YWludHkgKHVzaW5nIFNELCBNQUQsIG9yIHRhaWwgcXVhbnRpbGVzKQo1LiBDaGVjayB0aGF0IE1DU0UgaXMgc21hbGwgZW5vdWdoIGZvciB0aGUgZGVzaXJlZCBhY2N1cmFjeSBvZgogICByZXBvcnRpbmcgdGhlIHBvc3RlcmlvciBzdW1tYXJpZXMgZm9yIHRoZSBxdWFudGl0aWVzIG9mCiAgIGludGVyZXN0LgoKIC0gSWYgdGhlIGFjY3VyYWN5IGlzIG5vdCBzdWZmaWNpZW50LCByZXBvcnQgbGVzcyBkaWdpdHMgb3IgcnVuCiAgIG1vcmUgaXRlcmF0aW9ucy4KIC0gSGFsdmluZyBNQ1NFIHJlcXVpcmVzIHF1YWRydXBsaW5nIHRoZSBudW1iZXIgb2YgaXRlcmF0aW9ucwogICAoaWYgQ0xUIGhvbGRzKS4KIC0gRGlmZmVyZW50IHF1YW50aXRpZXMgb2YgaW50ZXJlc3QgaGF2ZSBkaWZmZXJlbnQgTUNTRSBhbmQgbWF5CiAgIHJlcXVpcmUgZGlmZmVyZW50IG51bWJlciBvZiBpdGVyYXRpb25zIGZvciB0aGUgZGVzaXJlZCBhY2N1cmFjeS4KIC0gU29tZSBxdWFudGl0aWVzIG9mIGludGVyZXN0IG1heSBoYXZlIHBvc3RlcmlvciBkaXN0cmlidXRpb24gd2l0aAogICBpbmZpbml0ZSB2YXJpYW5jZSwgYW5kIHRoZW4gdGhlIEVTUyBhbmQgTUNTRSBhcmUgbm90IGRlZmluZWQgZm9yCiAgIHRoZSBleHBlY3RhdGlvbi4gSW4gc3VjaCBjYXNlcyB1c2UsIGZvciBleGFtcGxlLCBtZWRpYW4gaW5zdGVhZAogICBvZiBtZWFuIGFuZCBtZWFuIGFic29sdXRlIGRldmlhdGlvbiAoTUFEKSBpbnN0ZWFkIG9mIHN0YW5kYXJkCiAgIGRldmlhdGlvbi4gRVNTIGFuZCBNQ1NFIGZvciAobm9uLWV4dHJlbWUpIHF1YW50aWxlcyBjYW4gYmUKICAgZGVyaXZlZCBmcm9tIHRoZSAobm9uLWV4dHJlbWUpIGN1bXVsYXRpdmUgcHJvYmFiaWxpdGllcyB0aGF0CiAgIGFsd2F5cyBoYXZlIGZpbml0ZSBtZWFuIGFuZCB2YXJpYW5jZS4KCi0tLS0tLS0tLS0tLS0KCiMgRXhhbXBsZQoKQXMgYW4gZXhhbXBsZSwgd2UgYW5hbHlzZSB0aGUgdHJlbmQgaW4gc3VtbWVyIG1vbnRocyBhdmVyYWdlIHRlbXBlcmF0dXJlIDE5NTItLTIwMTMgYXQgS2lscGlzasOkcnZpIGluIG5vcnRod2VzdGVybiBGaW5uaXNoIExhcGxhbmQuIFN1bW1lciBtb250aHMgYXJlIEp1bmUsIEp1bHksIGFuZCBBdWd1c3QsIGFuZCB3ZSBhbmFseXNlIHRoZSBhdmVyYWdlIHRlbXBlcmF0dXJlIG92ZXIgdGhlc2UgbW9udGhzIGluIGVhY2ggeWVhci4KCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBjb21tZW50PU5BKQojIHN3aXRjaCB0aGlzIHRvIFRSVUUgdG8gc2F2ZSBmaWd1cmVzIGluIHNlcGFyYXRlIGZpbGVzCnNhdmVmaWdzIDwtIEZBTFNFCmBgYAoKIyMjIExvYWQgcGFja2FnZXMKCmBgYHtyIH0KbGlicmFyeSgicnByb2pyb290IikKcm9vdDwtaGFzX2ZpbGUoIi5Xb3JrZmxvdy1FeGFtcGxlcy1yb290IikkbWFrZV9maXhfZmlsZSgpCmxpYnJhcnkodGlkeXIpIApsaWJyYXJ5KGRwbHlyKSAKbGlicmFyeShjbWRzdGFucikKbGlicmFyeShwb3N0ZXJpb3IpCm9wdGlvbnMocGlsbGFyLm5lZ2F0aXZlID0gRkFMU0UpCmxpYnJhcnkobGVtb24pCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShiYXllc3Bsb3QpCnRoZW1lX3NldChiYXllc3Bsb3Q6OnRoZW1lX2RlZmF1bHQoYmFzZV9mYW1pbHkgPSAic2FucyIpKQpTRUVEIDwtIDQ4OTI3ICMgc2V0IHJhbmRvbSBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkKYGBgCgotLS0tLS0tLS0tLS0tCgojIyBLaWxwaXNqw6RydmkgZGF0YSBhbmQgbW9kZWwKCiMjIyBEYXRhCgpMb2FkIEtpbHBpc2rDpHJ2aSBzdW1tZXIgbW9udGggYXZlcmFnZSB0ZW1wZXJhdHVyZXMgMTk1Mi0yMDEzOgoKYGBge3IgfQpkYXRhX2tpbHBpcyA8LSByZWFkLmRlbGltKHJvb3QoIkRpZ2l0cy9kYXRhIiwia2lscGlzamFydmktc3VtbWVyLXRlbXAuY3N2IiksIHNlcCA9ICI7IikKZGF0YV9saW4gPC1saXN0KE4gPSBucm93KGRhdGFfa2lscGlzKSwKICAgICAgICAgICAgIHggPSBkYXRhX2tpbHBpcyR5ZWFyLAogICAgICAgICAgICAgeHByZWQgPSAyMDE2LAogICAgICAgICAgICAgeSA9IGRhdGFfa2lscGlzWyw1XSkKYGBgCgoKUGxvdCB0aGUgZGF0YQoKYGBge3IgfQpnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChhZXMoeCwgeSksIGRhdGEgPSBkYXRhLmZyYW1lKGRhdGFfbGluKSwgc2l6ZSA9IDEpICsKICBsYWJzKHkgPSAnU3VtbWVyIHRlbXBlcmF0dXJlXG4gYXQgS2lscGlzasOkcnZpJywgeD0gIlllYXIiKQpgYGAKCiMjIyBHYXVzc2lhbiBsaW5lYXIgbW9kZWwKCldlIHVzZSBhIHNpbXBsZSBsaW5lYXIgbW9kZWwgd2l0aCBub3JtYWwgb2JzZXJ2YXRpb24gbW9kZWwsIHdlYWtseQppbmZvcm1hdGl2ZSBub3JtYWwgcHJpb3IsIGFuZCB0aGUgcHJlZGljdG9yICh0aW1lKSBjZW50ZXJlZCB0byBoYXZlCjAgbWVhbi4gV2UgYXNzdW1lIGEgcHJpb3JpIHRoYXQgaW5jcmVhc2Ugb3IgZGVjcmVhc2UgaW4gdGVtcGVyYXR1cmUKaXMgZXF1YWxseSBsaWtlbHksIGFuZCB0aGF0IGl0IGlzIHVubGlrZWx5IHRoYXQgdGVtcGVyYXR1cmUgd291bGQKY2hhbmdlIG1vcmUgMTAgZGVncmVlcyBpbiAxMDAgeWVhcnMuIFdlIGFsc28gYXNzdW1lIHRoYXQgeWVhcmx5CnZhcmlhdGlvbiBpbiBzdW1tZXIgdGVtcGVyYXR1cmVzIGlzIGxpa2VseSB0byBiZSBsZXNzIHRoYW4gMwpkZWdyZWVzLgoKVGhlIGZvbGxvd2luZyBTdGFuIGNvZGUgY2VudGVycyB0aGUgY292YXJpYXRlIHRvIHJlZHVjZSBwb3N0ZXJpb3IKZGVwZW5kZW5jeSBvZiBzbG9wZSBhbmQgY29lZmZpY2llbnQgcGFyYW1ldGVycy4gSXQgYWxzbyBtYWtlcyBpdAplYXNpZXIgdG8gZGVmaW5lIHRoZSBwcmlvciBvbiBhdmVyYWdlIHRlbXBlcmF0dXJlIGluIHRoZSBjZW50ZXIgb2YKdGhlIHRpbWUgcmFuZ2UgKGluc3RlYWQgZGVmaW5pbmcgcHJpb3IgZm9yIHRlbXBlcmF0dXJlIGF0IHllYXIgMCkuCgpgYGB7ciB9CmNvZGVfbGluIDwtIHJvb3QoIkRpZ2l0cyIsICJsaW5lYXIuc3RhbiIpCndyaXRlTGluZXMocmVhZExpbmVzKGNvZGVfbGluKSkKYGBgCgojIyMgUHJpb3IgcGFyYW1ldGVyIHZhbHVlcyBmb3Igd2Vha2x5IGluZm9ybWF0aXZlIHByaW9ycwoKYGBge3IgfQpkYXRhX2xpbl9wcmlvcnMgPC0gYyhsaXN0KAogICAgcG11YWxwaGFfYyA9IDEwLCAgICAgIyBwcmlvciBtZWFuIGZvciBhdmVyYWdlIHRlbXBlcmF0dXJlCiAgICBwc2FscGhhID0gMTAsICAgICAgICAjIHdlYWtseSBpbmZvcm1hdGl2ZQogICAgcG11YmV0YSA9IDAsICAgICAgICAgIyBhIHByaW9yaSBpbmNyLiBhbmQgZGVjci4gYXMgbGlrZWx5CiAgICBwc2JldGEgPSAwLjEvMywgICAjIGF2ZyB0ZW1wIHByb2IgZG9lcyBkb2VzIG5vdCBpbmNyLiBtb3JlIHRoYW4gYSBkZWdyZWUgcGVyIDEwIHllYXJzOiAgc2V0dGluZyB0aGlzIHRvICsvLTMgc2QncwogICAgcHNzaWdtYSA9IDEpLCAgICAgICAgIyBzZXR0aW5nIHNkIG9mIHRvdGFsIHZhcmlhdGlvbiBpbiBzdW1tZXIgYXZlcmFnZSB0ZW1wZXJhdHVyZXMgdG8gMSBkZWdyZWUgaW1wbGllcyB0aGF0ICsvLSAzIHNkJ3MgaXMgKy8tMyBkZWdyZWVzOiAKICBkYXRhX2xpbikKYGBgCgojIyBSdW4gaW5mZXJlbmNlIGZvciBzb21lIG51bWJlciBvZiBpdGVyYXRpb25zCgpXZSBydW4gTUNNQyB3aXRoIFN0YW4ncyBjdXJyZW50IGRlZmF1bHQgc2V0dGluZ3MuIEFsbCBjb252ZXJnZW5jZQpkaWFnbm9zdGljcyBwYXNzIGFuZCBhbGwgZWZmZWN0aXZlIHNhbXBsZSBzaXplIGFyZSBiaWcgZW5vdWdoIHRoYXQKd2UgY2FuIGFzc3VtZSB0aGF0IHRoZSBjb252ZXJnZW5jZSBkaWFnbm9zdGljcyBhcmUgcmVsaWFibGUuCgoKYGBge3IgcmVzdWx0cz0naGlkZSd9Cm1vZF9saW4gPC0gY21kc3Rhbl9tb2RlbChzdGFuX2ZpbGUgPSBjb2RlX2xpbikKZml0X2xpbiA8LSBtb2RfbGluJHNhbXBsZShkYXRhID0gZGF0YV9saW5fcHJpb3JzLCBzZWVkID0gU0VFRCwgcmVmcmVzaCA9IDApCmBgYAoKIyMgUnVuIGNvbnZlcmdlbmNlIGRpYWdub3N0aWNzCgpUaGVyZSB3ZXJlIG5vIGNvbnZlcmdlbmNlIGlzc3VlcyByZXBvcnRlZCBieSBzYW1wbGluZy4gV2UgY2FuIGFsc28KZXhwbGljaXRseSBjYWxsIENtZFN0YW4gaW5mZXJlbmNlIGRpYWdub3N0aWNzOgoKYGBge3IgfQpmaXRfbGluJGNtZHN0YW5fZGlhZ25vc2UoKQpgYGAKCldlIGNoZWNrICRcd2lkZWhhdHtSfSQgZW5kIEVTUyB2YWx1ZXMsIHdoaWNoIGluIHRoaXMgY2FzZSBhbGwgbG9vayBnb29kLgoKYGBge3IgcmVuZGVyPWxlbW9uX3ByaW50LCBkaWdpdHM9YygwLDIsMiwyLDIsMiwyLDIsMCwwKX0KZHJhd3MgPC0gYXNfZHJhd3NfcnZhcnMoZml0X2xpbiRkcmF3cygpKQpzdW1tYXJpemVfZHJhd3MoZHJhd3MpCmBgYAoKQ29tcHV0ZSBwb3N0ZXJpb3IgZHJhd3MgZm9yIHRoZSBsaW5lYXIgZml0CgpgYGB7ciB9CmRyYXdzJG11IDwtIGRyYXdzJGFscGhhX2MrZHJhd3MkYmV0YSooZGF0YV9saW4keC1tZWFuKGRhdGFfbGluJHgpKQpgYGAKClBsb3QgdGhlIGxpbmVhciBmaXQgd2l0aCA5MCUgcG9zdGVyaW9yIGludGVydmFsCgpgYGB7ciB9CmRhdGEuZnJhbWUoeCA9IGRhdGFfbGluJHgsCiAgICAgICAgICAgeSA9IGRhdGFfbGluJHksCiAgICAgICAgICAgRW11ID0gbWVhbihkcmF3cyRtdSksCiAgICAgICAgICAgcTA1ID0gYXMudmVjdG9yKHF1YW50aWxlKGRyYXdzJG11LCAwLjA1KSksCiAgICAgICAgICAgcTk1ID0gYXMudmVjdG9yKHF1YW50aWxlKGRyYXdzJG11LCAwLjk1KSkpICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2VvbV9yaWJib24oYWVzKHg9eCwgeW1pbj1xMDUsIHltYXg9cTk1KSwgZmlsbD0nZ3JleTkwJykgKwogIGdlb21fbGluZShhZXMoeD14LCB5PUVtdSwgKSkgKwogIGdlb21fcG9pbnQoYWVzKHgsIHkpLCBzaXplID0gMSkgKwogIGxhYnMoeSA9ICdTdW1tZXIgdGVtcGVyYXR1cmVcbiBhdCBLaWxwaXNqw6RydmkgKMKwQyknLCB4PSAiWWVhciIpKwogIGd1aWRlcyhsaW5ldHlwZSA9ICJub25lIikKYGBgCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmlmIChzYXZlZmlncykgZ2dzYXZlKHJvb3QoIktpbHBpc2phcnZpIiwia2lscGlzamFydmlfZml0LnBkZiIpLAogICAgICAgICAgICAgICAgICAgICB3aWR0aD02LCBoZWlnaHQ9MykKYGBgCgpBdCB0aGlzIHBvaW50IGl0IGlzIHN1ZmZpY2llbnQgdGhhdCBkaWFnbm9zdGljcyBhcmUgT0sKKGNtZHN0YW5fZGlhZ25vc2Ugc2F5cyAibm8gcHJvYmxlbXMgZGV0ZWN0ZWQiKSBhbmQgZWZmZWN0aXZlIHNhbXBsZQpzaXplcyBhcmUgbGFyZ2UgZW5vdWdoICg+NDAwKSB0aGF0IHdlIGNhbiBhc3N1bWUgdGhlIGRpYWdub3N0aWNzIHRvCmJlIHJlbGlhYmxlLgoKV2UgY291bGQgYWxzbyBkbyBwb3N0ZXJpb3IgcHJlZGljdGl2ZSBjaGVja2luZyBhbmQgcmVzaWR1YWwgcGxvdHMsCmJ1dCBub3cgd2UgZm9jdXMgb24gY2hlY2tpbmcgaG93IG1hbnkgTUNNQyBpdGVyYXRpb25zIGFyZSBuZWVkZWQKYW5kIGhvdyBtYW55IGRpZ2l0cyB0byByZXBvcnQgaW4gcG9zdGVyaW9yIHN1bW1hcnkgcmVzdWx0cy4KCiMjIEhvdyBtYW55IGRpZ2l0cyB0byByZXBvcnQgYmFzZWQgb24gcG9zdGVyaW9yIHVuY2VydGFpbnR5CgpXZSB3YW50IHRvIHJlcG9ydCBwb3N0ZXJpb3Igc3VtbWFyaWVzIGZvciB0aGUgc2xvcGUsIHRoYXQgaXMgdGhlCmluY3JlYXNlIGluIGF2ZXJhZ2Ugc3VtbWVyIHRlbXBlcmF0dXJlLCBhbmQgZm9yIHRoZSBwcm9iYWJpbGl0eQp0aGF0IHRoZSBzbG9wZSBpcyBwb3NpdGl2ZS4gV2UgZmlyc3QgY29uc2lkZXIgd2hhdCBpcyB0aGUKcmVhc29uYWJsZSByZXBvcnRpbmcgYWNjdXJhY3kgaWYgdGhlIHBvc3RlcmlvciBpbmZlcmVuY2Ugd291bGQgYmUKZXhhY3QgKGllIGlnbm9yaW5nIGZpcnN0IHRoZSBNb25ldCBDYXJsbyB2YXJpYWJpbGl0eSkuCgpXZSBzdGFydCBsb29raW5nIGF0IHRoZSBtZWFuIGFuZCA5MCUgaW50ZXJ2YWwgZm9yIHRoZSBzbG9wZSBwYXJhbWV0ZXIgYmV0YQoKYGBge3IgcmVuZGVyPWxlbW9uX3ByaW50LCBkaWdpdHM9M30KZHJhd3MgJT4lCiAgc3Vic2V0X2RyYXdzKCJiZXRhIikgJT4lCiAgc3VtbWFyaXplX2RyYXdzKG1lYW4sIH5xdWFudGlsZSgueCwgcHJvYnMgPSBjKDAuMDUsIDAuOTUpKSkgCmBgYAoKVGhlc2UgdmFsdWVzIGNvcnJlc3BvbmQgdG8gdGhlIHRlbXBlcmF0dXJlIGluY3JlYXNlIHBlciB5ZWFyLCBidXQKdG8gaW1wcm92ZSByZWFkYWJpbGl0eSB3ZSBzd2l0Y2ggbG9va2luZyBhdCB0aGUgdGVtcGVyYXR1cmUKaW5jcmVhc2UgcGVyIDEwMCB5ZWFycy4gCgpgYGB7ciB9CmRyYXdzIDwtIGRyYXdzICU+JQogIG11dGF0ZV92YXJpYWJsZXMoYmV0YTEwMCA9IDEwMCpiZXRhKQpgYGAKCkxldCdzIGxvb2sgYXQgdGhlIG1lYW4gYW5kIDkwJSBpbnRlcnZhbCBmb3IgdGhlIGV4cGVjdGVkIHRlbXBlcmF0dXJlCmluY3JlYXNlIHBlciAxMDAgeWVhcnMuCgpgYGB7ciByZW5kZXI9bGVtb25fcHJpbnQsIGRpZ2l0cz0zfQpkcmF3cyAlPiUKICBzdWJzZXRfZHJhd3MoImJldGExMDAiKSAlPiUKICBzdW1tYXJpemVfZHJhd3MobWVhbiwgfnF1YW50aWxlKC54LCBwcm9icyA9IGMoMC4wNSwgMC45NSkpKQpgYGAKClRoZSBudW1iZXIgb2YgZGlnaXRzIHNob3duIGluIFIgdmFyaWVzIGRlcGVuZGluZyBvbiB0aGUgcHJpbnQKbWV0aG9kIGFuZCBvcHRpb25zIGZvciB0aGUgc3BlY2lmaWMgb2JqZWN0IGFuZCBhYm92ZSB3ZSBzZWUgMwpkZWNpbWFsIGRpZ2l0cy4gRGVwZW5kaW5nIG9uIHRoZSBwcmludCBtZXRob2QsIFdlIG1heSBhbHNvIHNlZQptb3JlIGRpZ2l0cywgZm9yIGV4YW1wbGU6CgpgYGB7ciB9Cm1lYW4oZHJhd3MkYmV0YSkKcXVhbnRpbGUoZHJhd3MkYmV0YSwgcHJvYnM9YygwLjA1LDAuOTUpKQpgYGAKClRoZSBtb3JlIGRpZ2l0cyBhcmUgc2hvd24sIHRoZSBtb3JlIG9mIHRoZW0gYXJlIGxpa2VseSB0byBiZQp1bm5lY2Vzc2FyeSBjbHV0dGVyIGRpc3RyYWN0aW5nIHRoZSByZWFkZXIgZnJvbSB0aGUgaW1wb3J0YW50Cm1lc3NhZ2UuICBDb25zaWRlcmluZyB0aGUgd2lkdGggb2YgdGhlIDkwJSBpbnRlcnZhbCwgcHJhY3RpY2FsbHkKbWVhbmluZ2Z1bCBhY2N1cmFjeSB3b3VsZCBiZSBoZXJlIHRvIHJlcG9ydCBwb3N0ZXJpb3IgbWVhbiBhcyAyLjAKYW5kIHRoZSBwb3N0ZXJpb3IgaW50ZXJ2YWwgYXMgWzAuNyAsIDMuMl0uIERlcGVuZGluZyBvbiB0aGUKY29udGV4dCwgaXQgbWlnaHQgYmUgZXZlbiBiZXR0ZXIgdG8gcm91bmQgbW9yZSwgYW5kIHJlcG9ydCB0aGF0IHRoZQppbmNyZWFzZSBpcyBlc3RpbWF0ZWQgdG8gYmUgMSB0byAzIGRlZ3JlZXMgcGVyIGNlbnR1cnkgKDgxJQpwcm9iYWJpbGl0eSwgb3Igcm91bmRlZCB0byA4MCUgcHJvYmFiaWxpdHkpLCBvciAwIHRvIDQgZGVncmVlcyBwZXIKY2VudHVyeSAoOTklIHByb2JhYmlsaXR5KS4gVGhlcmUgaXMgbm8gbmVlZCB0byBzdGljayB0byByZXBvcnRpbmcKOTAlIG9yIDk1JSBpbnRlcnZhbC4KClRoZSBudW1iZXIgb2Ygc2lnbmlmaWNhbnQgZGlnaXRzIG5lZWRlZCBmb3IgcmVwb3J0aW5nIGNhbiBiZSBvZnRlbgpkZXRlcm1pbmVkIGFsc28gd2l0aCByb3VnaCBwb3N0ZXJpb3IgYXBwcm94aW1hdGlvbnMgdGhhdCBpbmRpY2F0ZQp0aGUgb3JkZXIgb2YgbWFnbml0dWRlIG9mIHRoZSBwb3N0ZXJpb3IgbWVhbiBhbmQgc2NhbGUsIGFuZCB0aGVuCm1vcmUgaXRlcmF0aW9ucyBtYXkgYmUgbmVlZGVkIHRvIGdldCBtb3JlIGFjY3VyYXRlIGVzdGltYXRlIGZvcgp0aG9zZSBkaWdpdHMuCgojIyBIb3cgbWFueSBkaWdpdHMgdG8gcmVwb3J0IGJhc2VkIG9uIE1vbnRlIENhcmxvIHN0YW5kYXJkIGVycm9yCgpOb3cgdGhhdCB3ZSBoYXZlIGFuIGVzdGltYXRlIGZvciB0aGUgcG9zdGVyaW9yIHVuY2VydGFpbnR5IG9mIHRoZQpzbG9wZSBwYXJhbWV0ZXIsIHdlIGNhbiBjaGVjayB3aGV0aGVyIHdlIGhhdmUgZW5vdWdoIG1hbnkKaXRlcmF0aW9ucyBmb3IgdGhlIGRlc2lyZWQgcmVwb3J0aW5nIGFjY3VyYWN5LiBNYXJrb3YgY2hhaW4gTW9udGUKQ2FybG8gbWV0aG9kIHVzZWQgYnkgU3RhbiB0byBtYWtlIHRoZSBwb3N0ZXJpb3IgZXN0aW1hdGVzIGlzCnN0b2NoYXN0aWMuIElmIHdlIHJlcGVhdCB0aGUgY29tcHV0YXRpb24gd2l0aCBkaWZmZXJlbnQgcmFuZG9tCm51bWJlciBnZW5lcmF0b3Igc2VlZCwgd2UgZ2V0IHNsaWdodGx5IGRpZmZlcmVudCBlc3RpbWF0ZXMuCgpgYGB7ciByZXN1bHRzPSdoaWRlJ30KZXN0aW1hdGVzIDwtIHQoc2FwcGx5KDE6MTAsIGZ1bmN0aW9uKGkpIHsKICBtb2RfbGluJHNhbXBsZShkYXRhID0gZGF0YV9saW5fcHJpb3JzLCBzZWVkID0gU0VFRCtpLCByZWZyZXNoID0gMCwKICAgICAgICAgICAgICAgICBzaG93X21lc3NhZ2VzID0gRkFMU0UpJGRyYXdzKCkgJT4lCiAgICBtdXRhdGVfdmFyaWFibGVzKGJldGExMDAgPSAxMDAqYmV0YSkgJT4lCiAgICBzdWJzZXRfZHJhd3MoImJldGExMDAiKSAlPiUKICAgICAgc3VtbWFyaXplX2RyYXdzKG1lYW4sIH5xdWFudGlsZSgueCwgcHJvYnMgPSBjKDAuMDUsIDAuOTUpKSkgJT4lCiAgICAgIHNlbGVjdCgtdmFyaWFibGUpfSkpICU+JSB1bmxpc3QoKSAlPiUgbWF0cml4KG5yb3c9MTApCmNvbG5hbWVzKGVzdGltYXRlcykgPC0gYygibWVhbiIgLCI1JSIsIjk1JSIpCmBgYApgYGB7ciByZW5kZXI9bGVtb25fcHJpbnQsIGRpZ2l0cz0zfQphc190aWJibGUoZXN0aW1hdGVzKQpgYGAKCldlIHNlZSB0aGF0IGZvciBtZWFuIHRoZSB0aGlyZCBkaWdpdCBpcyB2YXJ5aW5nIGFuZCB0aGUgcm91bmRlZAp2YWx1ZSBpcyBiZXR3ZWVuIDEuOSBhbmQgMi4wLiBGb3IgdGhlIDUlIHF1YW50aWxlIGV2ZW4gdGhlIGZpcnN0CnNpZ25pZmljYW50IGRpZ2l0IGlzIHNvbWV0aW1lcyB2YXJ5aW5nIGFuZCB0aGUgcm91bmRlZCB2YWx1ZSB3b3VsZAp2YXJ5IGJldHdlZW4gMC42IGFuZCAwLjcuICBGb3IgdGhlIDk1JSBxdWFudGlsZSB0aGUgc2Vjb25kIGRpZ2l0IGlzCnZhcnlpbmcgYW5kIHRoZSByb3VuZGVkIHZhbHVlcyB3b3VsZCB2YXJ5IGJldHdlZW4gMy4yIGFuZAozLjMuIEJhc2VkIG9uIHRoaXMsIGl0IHdvdWxkIGJlIE9LIHRvIHJlcG9ydCB0aGUgbWVhbiBhcyAxLjkgb3IgMgphbmQgOTAlIGludGVydmFsIGFzIFswLjcsIDMuMl0gYXMgYmFzZWQgb24gdGhlIGZpcnN0IE1vbnRlIENhcmxvCmVzdGltYXRlLiBDb25zaWRlcmluZyB0aGUgc2NhbGUsIHRoZSBtaW5vciB2YXJpYXRpb24gaW4gdGhlIGxhc3QKZGlnaXQgaXMgbm90IGFmZmVjdGluZyB0aGUgaW50ZXJwcmV0YXRpb24gb2YgdGhlCnJlc3VsdHMuIEFsdGVybmF0aXZlbHkgdGhlIGNvdXJzZXIgcmFuZ2VzIFsxLCAzXSBvciBbMCwgNF0gY291bGQgYmUKcmVwb3J0ZWQgYXMgZGlzY3Vzc2VkIGFib3ZlLgoKSW5zdGVhZCBvZiByZXBlYXRpbmcgdGhlIGVzdGltYXRpb24gbWFueSB0aW1lcyB3ZSBjYW4gZXN0aW1hdGUgdGhlCmFjY3VyYWN5IG9mIHRoZSBvcmlnaW5hbCBzYW1wbGluZyBieSBjb21wdXRpbmcgTW9udGUgQ2FybG8gc3RhbmRhcmQKZXJyb3IgKE1DU0UpIHRoYXQgdGFrZXMgaW50byBhY2NvdW50IHRoZSBxdWFudGl0eSBvZiBpbnRlcmVzdCwgYW5kIHRoZQplZmZlY3RpdmUgc2FtcGxlIHNpemUgb2YgTUNNQyBkcmF3cyAoc2VlLCBlLmcuLCBAVmVodGFyaStldGFsOjIwMjE6UmhhdCkuCgoKYGBge3IgcmVuZGVyPWxlbW9uX3ByaW50LCBkaWdpdHM9M30KZHJhd3MgJT4lCiAgc3Vic2V0X2RyYXdzKCJiZXRhMTAwIikgJT4lCiAgc3VtbWFyaXplX2RyYXdzKG1jc2VfbWVhbiwgfm1jc2VfcXVhbnRpbGUoLngsIHByb2JzID0gYygwLjA1LCAwLjk1KSkpCmBgYAoKV2Ugc2hvdyBhbHNvIHRoZSBFU1MgdmFsdWVzIGZvciBtZWFuIGFuZCBxdWFudGlsZXMsIHRvIGlsbHVzdHJhdGUKdGhhdCB0aGUgRVNTIHZhbHVlcyBjYW4gYmUgZGlmZmVyZW50IGZvciBkaWZmZXJlbnQgcXVhbnRpdGllcywgYnV0CmFsc28gdGhhdCB0aGUgc2FtZSBFU1MgZG9lc24ndCBsZWFkIHRvIHRoZSBzYW1lIE1DU0UsIGFuZCBzaW1pbGFyCkVTUyBkb2Vzbid0IGxlYWQgdG8gc2ltaWxhciBNQ1NFIGFzIE1DU0UgZGVwZW5kcyBhbHNvIG9uIHRoZQpxdWFudGl0eS4gSGVyZSwgZm9yIGV4YW1wbGUsIGFsdGhvdWdoIEVTU3MgYXJlIHNpbWlsYXIgZm9yIGFsbApxdWFudGl0aWVzLCA1XCUgYW5kIDk1XCUgcXVhbnRpbGVzIGhhdmUgY2xlYXJseSBoaWdoZXIgTUNTRSB0aGFuCnRoZSBtZWFuLgoKCmBgYHtyIHJlbmRlcj1sZW1vbl9wcmludCwgZGlnaXRzPTB9CmRyYXdzICU+JQogIHN1YnNldF9kcmF3cygiYmV0YTEwMCIpICU+JQogIHN1bW1hcml6ZV9kcmF3cyhlc3NfbWVhbiwgfmVzc19xdWFudGlsZSgueCwgcHJvYnMgPSBjKDAuMDUsIDAuOTUpKSkKYGBgCgpUaGUgTUNTRSBmb3IgdGhlIG1lYW4gZXN0aW1hdGUgaXMgYWJvdXQgMC4wMSBhbmQgZm9yIDUlIGFuZCA5NSUKcXVhbnRpbGVzIGFib3V0IDAuMDMuIElmIHdlIG11bHRpcGx5IHRoZXNlIGJ5IDIsIHRoZSBsaWtlbHkgcmFuZ2UKb2YgdmFyaWF0aW9uIGR1ZSB0byBNb250ZSBDYXJsbyBpcyAkXHBtIDAuMDIkIGZvciBtZWFuIGFuZCAkXHBtCjAuMDckIGZvciA1JSBhbmQgOTUlIHF1YW50aWxlcy4gRnJvbSB0aGlzIHdlIGNhbiBpbnRlcnByZXQgdGhhdAppdCdzIHVubGlrZWx5IHRoZXJlIHdvdWxkIGJlIHZhcmlhdGlvbiBpbiB0aGUgcmVwb3J0ZWQgZXN0aW1hdGUgZm9yCnRoZSBtZWFuLCBpZiBpdCBpcyByZXBvcnRlZCBhcyAyLjAuIEZvciA1JSBhbmQgOTUlIHF1YW50aWxlcwp0aGVyZSBjYW4gYmUgdmFyaWF0aW9uIGluIHRoZSBmaXJzdCBkZWNpbWFsIGRpZ2l0LCBidXQgdGhhdApkaWZmZXJlbmNlIHdvdWxkIG5vdCBiZSBtZWFuaW5nZnVsIGluIG1vc3QgY2FzZXMuIFdlIGNvdWxkIHJ1biBtb3JlCml0ZXJhdGlvbnMgdG8gZ2V0IHRoZSBNQ1NFIGZvciBxdWFudGlsZXMgZG93biB0byBzb21ldGhpbmcgbGlrZQowLjAxLCB3aGljaCB3b3VsZCByZXF1aXJlIGFib3V0IDEwIHRpbWVzIG1vcmUgaXRlcmF0aW9ucy4gQXNzdW1pbmcKdGhlIHBvc3RlcmlvciBoYXMgZmluaXRlIHZhcmlhbmNlIGFuZCBNQ01DIGlzIG1peGluZyB3ZWxsLCB3ZQpleHBlY3QgdGhhdCBydW5uaW5nIGZvdXIgdGltZXMgbW9yZSBpdGVyYXRpb25zIHdvdWxkIGhhbHZlIHRoZQpNQ1NFcy4KCkFzIGRpc2N1c3NlZCBiZWZvcmUsIGl0IG1pZ2h0IGJlIGFueXdheSBiZXR0ZXIgdG8gcmVwb3J0IHRoZQpwb3N0ZXJpb3IgdW5jZXJ0YWludHkgaW50ZXJ2YWwgd2l0aCBsZXNzIGRpZ2l0cywgYW5kIGlmIHdlIHJlcG9ydGVkCmVpdGhlciA4MCUgaW50ZXJ2YWwgJFsxLCAzXSQgb3IgOTklIGludGVydmFsICRbMCwgNF0kLCB3ZSB3b3VsZAphbHJlYWR5IGhhdmUgc3VmZmljaWVudCBhY2N1cmFjeSBmb3IgdGhlIG51bWJlciBvZiBzaG93bgpkaWdpdHMuIFRoZXNlIE1DU0UgZXN0aW1hdGVzIGlsbHVzdHJhdGUgYWxzbyB0aGUgZmFjdCB0aGF0IHVzdWFsbHkKdGFpbCBxdWFudGlsZXMgaGF2ZSBsb3dlciBhY2N1cmFjeSB0aGFuIHRoZSBwb3N0ZXJpb3IgbWVhbi4KCldlIGNhbiBhbHNvIHJlcG9ydCB0aGUgcHJvYmFiaWxpdHkgdGhhdCB0aGUgdGVtcGVyYXR1cmUgY2hhbmdlIGlzCnBvc2l0aXZlLgoKYGBge3IgcmVuZGVyPWxlbW9uX3ByaW50LCBkaWdpdHM9M30KZHJhd3MgJT4lCiAgbXV0YXRlX3ZhcmlhYmxlcyhiZXRhMHAgPSBiZXRhMTAwPjApICU+JQogIHN1YnNldF9kcmF3cygiYmV0YTBwIikgJT4lCiAgc3VtbWFyaXplX2RyYXdzKCJtZWFuIiwgbWNzZSA9IG1jc2VfbWVhbikKYGBgCgpUaGUgcHJvYmFiaWxpdHkgaXMgc2ltcGx5IGVzdGltYXRlZCBhcyBhIHBvc3RlcmlvciBtZWFuIG9mIGFuCmluZGljYXRvciBmdW5jdGlvbiBhbmQgdGhlIHVzdWFsIE1DU0UgZm9yIG1lYW4gZXN0aW1hdGUgaXMgdXNlZC4KVGhlIE1DU0UgaW5kaWNhdGVzIHRoYXQgd2UgaGF2ZSBlbm91Z2ggTUNNQyBpdGVyYXRpb25zIGZvcgpwcmFjdGljYWxseSBtZWFuaW5nZnVsIHJlcG9ydGluZyB0aGF0IHRoZSBwcm9iYWJpbGl0eSB0aGF0IHRoZQp0ZW1wZXJhdHVyZSBpcyBpbmNyZWFzaW5nIGlzIGxhcmdlciB0aGFuIDk5JS4gVGhlcmUgaXMgbm90IG11Y2gKcHJhY3RpY2FsIGRpZmZlcmVuY2UgdG8gcmVwb3J0aW5nIHRoYXQgdGhlIHByb2JhYmlsaXR5IGlzIDk5LjMlCmFuZCB0byBlc3RpbWF0ZSB0aGF0IHRoaXJkIGRpZ2l0IGFjY3VyYXRlbHkgd291bGQgcmVxdWlyZSA2NCB0aW1lcwptb3JlIGl0ZXJhdGlvbnMuIEZvciB0aGlzIHNpbXBsZSBwcm9ibGVtLCBzYW1wbGluZyB0aGF0IG1hbnkKaXRlcmF0aW9ucyB3b3VsZCBub3QgYmUgdGltZSBjb25zdW1pbmcsIGJ1dCB3ZSBtaWdodCBhbHNvIGluc3RlYWQKY29uc2lkZXIgdG8gb2J0YWluIG1vcmUgZGF0YSB0byB2ZXJpZnkgdGhhdCB0aGUgc3VtbWVyIHRlbXBlcmF0dXJlCmluIG5vcnRoZXJuIEZpbmxhbmQgaGFzIGJlZW4gaW5jcmVhc2luZyBzaW5jZSAxOTUyLgoKV2UgYWRkaXRpb25hbHkgY29tcHV0ZSBwcm9iYWJpbGl0aWVzIHRoYXQgdGhlIHRlbXBlcmF0dXJlIGluY3JlYXNlCmlzIG1vcmUgdGhhbiAxLCAyLCAzIG9yIDQgZGVncmVlcywgYW5kIGNvcnJlc3BvbmRpbmcgTUNTRXMgYW5kIEVTU3MuCgpgYGB7ciByZW5kZXI9bGVtb25fcHJpbnQsIGRpZ2l0cz1jKDAsIDMsIDMsIDApfQpkcmF3cyAlPiUKICBzdWJzZXRfZHJhd3MoImJldGExMDAiKSAlPiUKICBtdXRhdGVfdmFyaWFibGVzKGJldGExcCA9IGJldGExMDA+MSwKICAgICAgICAgICAgICAgICAgIGJldGEycCA9IGJldGExMDA+MiwKICAgICAgICAgICAgICAgICAgIGJldGEzcCA9IGJldGExMDA+MywKICAgICAgICAgICAgICAgICAgIGJldGE0cCA9IGJldGExMDA+NCkgJT4lCiAgc3Vic2V0X2RyYXdzKCJiZXRhWzEtNF1wIiwgcmVnZXg9VFJVRSkgJT4lCiAgc3VtbWFyaXplX2RyYXdzKCJtZWFuIiwgbWNzZSA9IG1jc2VfbWVhbiwgRVNTID0gZXNzX21lYW4pCmBgYAoKVGFraW5nIGludG8gYWNjb3VudCBNQ1NFcyBnaXZlbiB0aGUgY3VycmVudCBwb3N0ZXJpb3Igc2FtcGxlLCB3ZQpjYW4gc3VtbWFyaXNlIHRoZXNlIGFzIHAoYmV0YTEwMD4xKSA9IDg4JS0tOTElLCBwKGJldGExMDA+MikgPQo0NiUtLTUxJSwgcChiZXRhMTAwPjMpID0gNyUtLTEwJSwgcChiZXRhMTAwPjQpID0gMC4yJS0tMSUuIFRvIGdldAp0aGVzZSBwcm9iYWJpbGl0aWVzIGVzdGltYXRlZCB3aXRoIDIgZGlnaXQgYWNjdXJhY3kgd291bGQgYWdhaW4KcmVxdWlyZSBtb3JlIGl0ZXJhdGlvbnMgKDE2LTMwMCB0aW1lcyBtb3JlIGl0ZXJhdGlvbnMgZGVwZW5kaW5nIG9uCnRoZSBxdWFudGl0eSksIGJ1dCB0aGUgYWRkZWQgaXRlcmF0aW9ucyB3b3VsZCBub3QgY2hhbmdlIHRoZQpjb25jbHVzaW9uIHJhZGljYWxseS4KCiMjIE1DU0UgY29tcHV0YXRpb24gZGV0YWlscwoKVGhlIGRldGFpbHMgb2YgaG93IE1DU0UgaXMgZXN0aW1hdGVkIGZvciBwb3N0ZXJpb3IgZXhwZWN0YXRpb25zIGFuZApxdWFudGlsZXMgYXJlIHByb3ZpZGVkIGJ5IEBWZWh0YXJpK2V0YWw6MjAyMTpSaGF0LCBhbmQKaW1wbGVtZW50YXRpb25zIGFyZSBhdmFpbGFibGUsIGZvciBleGFtcGxlIGluIHRoZSBgcG9zdGVyaW9yYCBSCnBhY2thZ2UgdXNlZCBpbiB0aGlzIG5vdGVib29rIGFuZCBpbiBgQXJ2aVpgIFB5dGhvbiBwYWNrYWdlLgoKIyMgUm91Z2ggZXN0aW1hdGVzIGZvciBob3cgbWFueSBpdGVyYXRpb25zIHRvIHJ1biBpbml0aWFsbHkKCkJlZm9yZSBydW5uaW5nIGFueSBNQ01DLCB3ZSBtYXkgb2J0YWluIHNvbWUgcm91Z2ggZXN0aW1hdGVzIG9mIGhvdwptYW55IGl0ZXJhdGlvbnMgd2Ugd291bGQgbmVlZCBmb3IgY2VydGFpbiByZWxhdGl2ZSBhY2N1cmFjeSBmb3IKdGhlIHBvc3RlcmlvciBtZWFuIChpZiBNQ01DIHJ1bnMgd2VsbCkuCgpJZiB3ZSBhc3N1bWUgdGhhdCB0aGUgcG9zdGVyaW9yIG9mIHBhcmFtZXRlciAkXHRoZXRhJCBoYXMgZmluaXRlCm1lYW4gYW5kIHZhcmlhbmNlLCBhbmQgd2UgaGF2ZSBtYW55IGluZGVwZW5kZW50IE1vbnRlIENhcmxvIGRyYXdzCiRTJCwgd2UgY2FuIHVzZSBjZW50cmFsIGxpbWl0IHRoZW9yZW0gdG8ganVzdGlmeSB0aGF0IHRoZSB1bmNlcnRhaW50eQpyZWxhdGVkIHRvIHRoZSBlc3RpbWF0ZWQgZXhwZWN0YXRpb24gY2FuIGJlIGFwcHJveGltYXRlZCB3aXRoCm5vcm1hbCBkaXN0cmlidXRpb24sICRcbWF0aHJte25vcm1hbH0oXGhhdHtcdGhldGF9LCBcaGF0e1xzaWdtYX1fXHRoZXRhIC8KXHNxcnR7U30pJCwgd2hlcmUgJFxoYXR7XHRoZXRhfSQgaXMgdGhlIGVzdGltYXRlIGFuZAokXGhhdHtcc2lnbWF9X1x0aGV0YSQgaXMgdGhlIGVzdGltYXRlZCBwb3N0ZXJpb3Igc3RhbmRhcmQgZGV2aWF0aW9uCm9mICRcdGhldGEkLgoKV2UgY2FuIHNlZSB0aGF0IGdpdmVuIGFueSAkXGhhdHtcdGhldGF9JCBhbmQgJFxoYXR7XHNpZ21hfV9cdGhldGEkLAppZiAkUz0xMDAkLCB0aGUgdW5jZXJ0YWludHkgaXMgMTBcJSBvZiB0aGUgcG9zdGVyaW9yIHNjYWxlIHdoaWNoCndvdWxkIG9mdGVuIGJlIHN1ZmZpY2llbnQgZm9yIGluaXRpYWwgZXhwZXJpbWVudHMsIGFuZCBpZiAkUz0xMDAwMCQsCnRoZSB1bmNlcnRhaW50eSBpcyAxXCUgb2YgdGhlIHBvc3RlcmlvciBzY2FsZSB3aGljaCB3b3VsZCBvZnRlbiBiZQpzdWZmaWNpZW50IGZvciB0d28gc2lnbmlmaWNhbnQgZGlnaXQgYWNjdXJhY3kuCgoxMFwlIHJlbGF0aXZlIGFjY3VyYWN5IG1lYW5zIHRoYXQgZGVzcGl0ZSB0aGUgbWFnbml0dWRlIG9mCiRcaGF0e1xzaWdtYX1fXHRoZXRhJCB3ZSBnZXQgYWNjdXJhY3kgYXBwcm94aW1hdGVseSBhIHdvcnRoIGF0CmxlYXN0IG9uZSBkaWdpdC4gTGV0J3MgZmlyc3QgYXNzdW1lICRcaGF0e1x0aGV0YX0gPSAxLjIzNCQuIFdlIGNhbgpzaW1wbGlmeSB0aGUgYW5hbHlzaXMgYnkgbm90aW5nIHRoYXQgaWYgZXhhbWluZSB0aGUgYmVoYXZpb3IgZ2l2ZW4KZGlmZmVyZW50ICRcaGF0e1xzaWdtYX1fXHRoZXRhJCB2YWx1ZXMgYXMsIGUuZy4sICQxMF57LTF9JCwKJDEwXnswfSQsICQxMF57MX0kLCBhbmQgY29ycmVzcG9uZGluZ2x5IHByZXNlbnQgdGhlICRcaGF0e1x0aGV0YX0kCmFzICQxMi4zNCBcdGltZXMgMTBeey0xfSQsICQxLjIzNCBcdGltZXMgMTBeezB9JCwgJDAuMTIzNCBcdGltZXMKMTBeezF9JC4gV2UgZ2V0IGVxdWl2YWxlbnQsIGJ1dCBzaW1wbGVyIGFuYWx5c2lzIGlmIHdlIHNldAokXGhhdHtcc2lnbWF9X1x0aGV0YT0xJCBhbmQgYW5hbHlzZSB0aGUgY2FzZXMgd2l0aCBkaWZmZXJlbnQgdmFsdWVzCiRcaGF0e1x0aGV0YX0kIChpZSB3ZSBjaGFuZ2UgdGhlIGNvb3JkaW5hdGVzIHRvIGhhdmUgdW5pdCBzY2FsZQp3aXRoIHJlc3BlY3QgdG8gdGhlIHBvc3RlcmlvciBzdGFuZGFyZCBkZXZpYXRpb24pLgoKICAtIElmICRTPTEwMCQgKGluZGVwZW5kZW50IGRyYXdzKSBhbmQgJFxoYXR7XHNpZ21hfV9cdGhldGE9MSQsCiAgICBNQ1NFIGlzICQwLjEkIGFuZCB3aXRoIDk5XCUgcHJvYmFiaWxpdHkgdGhhdCB2YXJpYXRpb24gaW4KICAgIEVbJFx0aGV0YSRdIGlzICRccG0gMC4zJC4gVGh1cywgaWYgdGhlIGVzdGltYXRpb24gd291bGQgYmUKICAgIHJlcGVhdGVkIHRoZSBmaXJzdCBzaWduaWZpY2FudCBkaWdpdCB3b3VsZCBzdGF5IHRoZSBzYW1lIG9yCiAgICBoYXZlIG1pbm9yIHZhcmlhYmlsaXR5IHRvIG9uZSBzbWFsbGVyIG9yIG9uZSBsYWdlciBkaWdpdC4gVGh1cwogICAgd2UgaGF2ZSBhcHByb3hpbWF0ZWx5IG9uZSBzaWduaWZpY2FudCBkaWdpdCBhY2N1cmFjeS4KICAtIElmICRTPTIwMDAkIChpbmRlcGVuZGVudCBkcmF3cykgYW5kICRcaGF0e1xzaWdtYX1fXHRoZXRhPTEkLAogICAgTUNTRSBpcyAkMC4wMiQgYW5kIHdpdGggOTlcJSBwcm9iYWJpbGl0eSB0aGF0IHZhcmlhdGlvbiBpbgogICAgRVskXHRoZXRhJF0gaXMgJFxwbSAwLjA3JC4gVGh1cywgaWYgdGhlIGVzdGltYXRpb24gd291bGQgYmUKICAgIHJlcGVhdGVkIHRoZSBmaXJzdCBzaWduaWZpY2FudCBkaWdpdCB3b3VsZCBzdGF5IHRoZSBzYW1lLCBhbmQKICAgIHRoZSBzZWNvbmQgc2lnbmlmaWNhbnQgZGlnaXQgd291bGQgaGF2ZSBoYXZlIG1pbm9yIHZhcmlhYmlsaXR5CiAgICB0byBvbmUgc21hbGxlciBvciBvbmUgbGFnZXIgZGlnaXQuIFRodXMgd2UgaGF2ZSBhcHByb3hpbWF0ZWx5CiAgICB0d28gc2lnbmlmaWNhbnQgZGlnaXQgYWNjdXJhY3kuIFdpdGggYSBsYXJnZXIgJFMkLCB0aGVyZSBpcwogICAgbGVzcyB2YXJpYWJpbGl0eSBpbiB0aGUgc2Vjb25kIHNpZ25pZmljYW50IGRpZ2l0LgoKRHluYW1pYyBIYW1pbHRvbmlhbiBNb250ZSBDYXJsbyBpbiBTdGFuIGlzIG9mdGVuIHNvIGVmZmljaWVudCB0aGF0CkVTUz5TLzIuIFRodXMgcnVubmluZyB3aXRoIHRoZSBkZWZhdWx0IG9wdGlvbnMgNCBjaGFpbnMgd2l0aCAxMDAwCml0ZXJhdGlvbnMgYWZ0ZXIgd2FybXVwIGlzIGxpa2VseSB0byBnaXZlIG5lYXIgdHdvIHNpZ25pZmljYW50CmRpZ2l0IGFjY3VyYWN5IGZvciB0aGUgcG9zdGVyaW9yIG1lYW4uIFRoZSBhY2N1cmFjeSBmb3IgNVwlIGFuZAo5NVwlIHF1YW50aWxlcyB3b3VsZCBiZSBiZXR3ZWVuIG9uZSBhbmQgdHdvIHNpZ25pZmljYW50IGRpZ2l0cy4KClRoZSBhYm92ZSBhbmFseXNpcyBzaG93cyB0aGUgYmVuZWZpdCBvZiBpbnRlcnByZXRpbmcgRVNTIGFzIGEgc2NhbGUKZnJlZSBkaWFnbm9zdGljIHdoZXRoZXIgd2UgYXJlIGxpa2VseSB0byBoYXZlIGVub3VnaCBpdGVyYXRpb25zLiBBCnNjYWxlIGZyZWUgaGVyZSBtZWFucyB3ZSBkb24ndCBuZWVkIHRvIGNvbXBhcmUgRVNTIHZhbHVlcyB0bwpwb3N0ZXJpb3Igc3RhbmRhcmQgZGV2aWF0aW9ucyBvciB0byBkb21haW4ga25vd2xlZGdlIG9mIHRoZQpxdWFudGl0eSBvZiBpbnRlcmVzdCwgbWFraW5nIGl0IGZhc3RlciB0byBjaGVjayB0aGF0IHdlIGhhdmUgaGlnaAplbm91Z2ggRVNTIGZvciBtYW55IHF1YW50aXRpZXMgb2YgaW50ZXJlc3QuIEhvd2V2ZXIsIGhpZ2ggRVNTIGlzCm5vdCBzdWZmaWNpZW50IHRvIGd1YXJhbnRlZSBjZXJ0YWluIGFjY3VyYWN5LCBhcyBNQ1NFIGRlcGVuZHMgYWxzbwpvbiB0aGUgcXVhbnRpdHkgb2YgaW50ZXJlc3QgYW5kIHRodXMgaW4gdGhlIGVuZCBpdCBpcyB1c2VmdWwgdG8KY2hlY2sgTUNTRXMgZm9yIHRoZSB2YWx1ZXMgdG8gYmUgcmVwb3J0ZWQuIEZvciBleGFtcGxlLCBhYm92ZSwgdGhlCmVzdGltYXRlIGZvciB3aGV0aGVyIHRoZSB0ZW1wZXJhdHVyZSBpbmNyZWFzZSBpcyBsYXJnZXIgdGhhbiA0CmRlZ3JlZXMgcGVyIGNlbnR1cnkgaGFzIGhpZ2ggRVNTLCBidXQgdGhlIGluZGljYXRvciB2YXJpYWJsZQpjb250YWlucyBsZXNzIGluZm9ybWF0aW9uICh0aGFuIGNvbnRpbnVvdXMgdmFsdWVzKSBhbmQgdGh1cyBtdWNoCmhpZ2hlciBFU1Mgd291bGQgYmUgbmVlZGVkIGZvciB0d28gc2lnbmlmaWNhbnQgZGlnaXQgYWNjdXJhY3kuCgo8YnIgLz4KCiMgUmVmZXJlbmNlcyB7LnVubnVtYmVyZWR9Cgo8ZGl2IGlkPSJyZWZzIj48L2Rpdj4KCg==