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.
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
}
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)
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)))
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)))
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)
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)))
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)))
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)
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)
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.
LS0tCnRpdGxlOiAiSG93IG1hbnkgaXRlcmF0aW9ucyB0byBydW4gYW5kIGhvdyBtYW55IGRpZ2l0cyB0byByZXBvcnQiCmF1dGhvcjogIkFraSBWZWh0YXJpIgpkYXRlOiAiRmlyc3QgdmVyc2lvbiAyMDIwLTEyLTA1LiBMYXN0IG1vZGlmaWVkIGByIGZvcm1hdChTeXMuRGF0ZSgpKWAuIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiByZWFkYWJsZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDIKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQpiaWJsaW9ncmFwaHk6IGRpZ2l0cy5iaWIKY3NsOiBoYXJ2YXJkLWNpdGUtdGhlbS1yaWdodC5jc2wKbGluay1jaXRhdGlvbnM6IHllcwotLS0KCkEgd29ya2Zsb3cgZm9yIGRlY2lkaW5nIGhvdyBtYW55IGRpZ2l0cyB0byByZXBvcnQgd2hlbiBzdW1tYXJpemluZwp0aGUgcG9zdGVyaW9yIGRpc3RyaWJ1dGlvbiwgYW5kIGhvdyB0byBjaGVjayBob3cgbWFueSBpbmRlcGVuZGVudApNb250ZSBDYXJsbyAoTUMpIGRyYXdzIG9yIGRlcGVuZGVudCBNYXJrb3YgY2hhaW4gTW9udGUgQ2FybG8gKE1DTUMpCmRyYXdzIGFyZSBuZWVkZWQuCgojIEludHJvZHVjdGlvbgoKV2hlbiBydW5uaW5nIGFueSBpdGVyYXRpdmUgYWxnb3JpdGhtIHdlIG5lZWQgdG8gZGVjaWRlIHdoZW4gdG8gc3RvcCBvciBob3cgbWFueSBpdGVyYXRpb25zIGFuZCBob3cgbWFueSBzZXF1ZW5jZXMgdG8gcnVuLiBJbiB0aGUgY29udGV4dCBvZiBwb3N0ZXJpb3IgaW5mZXJlbmNlLCB0aGUgYW5zd2VyIGNhbiBiZSBkaXZpZGVkIGluIHR3byBwYXJ0czogKDEpIGhvdyBtYW55IGNoYWlucyBhbmQgaXRlcmF0aW9ucyBkbyB3ZSBuZWVkIHRvIGFzc2VzcyB0aGF0IHRoZSBhbGdvcml0aG0gaXMgc2FtcGxpbmcgZnJvbSBzb21ldGhpbmcgY2xvc2UgdG8gdGhlIHRhcmdldCBkaXN0cmlidXRpb24sIGFuZCAoMikgaG93IG1hbnkgZHJhd3MgZG8gd2UgbmVlZCBzbyB0aGF0IHRoZSByZXBvcnRlZCBwb3N0ZXJpb3Igc3VtbWFyaWVzIHdvdWxkIG5vdCBjaGFuZ2UgaW4gaW1wb3J0YW50IHdheXMgaWYgdGhlIGluZmVyZW5jZSB3b3VsZCBiZSByZXBlYXRlZD8gVGhpcyBub3RlYm9vayBkaXNjdXNzZXMgdGhlIHNlY29uZCBwYXJ0LgoKQmVmb3JlIHdlIGNhbiBhbnN3ZXIgaG93IG1hbnkgY2hhaW5zIGFuZCBpdGVyYXRpb25zIHdlIG5lZWQgdG8gcnVuLCB3ZSBuZWVkIHRvIGtub3cgaG93IG1hbnkgc2lnbmlmaWNhbnQgZGlnaXRzIHdlIHdhbnQgdG8gcmVwb3J0LiBUb28gb2Z0ZW4sIHdlIHNlZSB0YWJsZXMgZmlsbGVkIHdpdGggbnVtYmVycyBsaWtlICQxLjc3MDUkLiBJdCdzIHZlcnkgdW5saWtlbHkgdGhhdCBhbGwgdGhlc2UgZGlnaXRzIGFyZSBhY2N1cmF0ZWx5IGVzdGltYXRlZCwgYW5kIGFsc28gdmVyeSB1bmxpa2VseSB0aGF0IHRoZSBhY2N1cmFjeSBpbiBtYWduaXR1ZGUgb2Ygb25lIGluIHRlbiB0aG91c2FuZCB3b3VsZCBiZSBuZWVkZWQgZm9yIGFueSBwcmFjdGljYWwgcHVycG9zZS4gUmVwb3J0aW5nIHRvbyBtYW55IGRpZ2l0cyBtYWtlcyBpdCBtb3JlIGRpZmZpY3VsdCB0byByZWFkIHN1bW1hcnkgdGFibGVzLiBUaHVzLCBiZWZvcmUgY29uc2lkZXJpbmcgaG93IG1hbnkgaXRlcmF0aW9ucyB3ZSBuZWVkIGl0J3MgdXNlZnVsIHRvIGNvbnNpZGVyIGhvdyBtYW55IGRpZ2l0cyBpdCBpcyBzZW5zaWJsZSB0byByZXBvcnQuCgpXaXRob3V0IGFueSBhZGRpdGlvbmFsIGluZm9ybWF0aW9uLCB3ZSBtYXkgYXNzdW1lIHRoYXQgcmVsYXRpdmUgZXJyb3JzIHNtYWxsZXIgdGhhbiAxXCUgYXJlIHR5cGljYWxseSBuZWdsaWdpYmxlIGFuZCB0aHVzIG1vc3Qgb2YgdGhlIHRpbWUgcmVwb3J0aW5nIGF0IG1vc3QgMiBzaWduaWZpY2FudCBkaWdpdHMgd291bGQgYmUgc3VmZmljaWVudC4gQWNjdXJhY3kgdG8ganVzdCBvbmUgc2lnbmlmaWNhbnQgZGlnaXQgY2FuIGJlIHN1ZmZpY2llbnQgaW4gdGhlIGVhcmx5IHN0YWdlcyBvZiBhbmFseXNpcyBhbmQgY2FuIGJlIHNlbnNpYmxlIGFuZCBjb252ZW5pZW50IGV2ZW4gaW4gZmluYWwgcmVwb3J0aW5nLCBhcyBkaXNjdXNzZWQgaW4gdGhlIGV4YW1wbGUgYmVsb3cuCgpNQ01DIGFuZCBvdGhlciBNb250ZSBDYXJsbyBtZXRob2RzIGFyZSBzdG9jaGFzdGljIGFuZCBpZiB0aGUgaW5mZXJlbmNlIHdvdWxkIGJlIHJlcGVhdGVkIHdpdGggYSBkaWZmZXJlbnQgcmFuZG9tIHNlZWQgKHJhbmRvbSBudW1iZXIgZ2VuZXJhdG9ycyBpbiBjb21wdXRlcnMgYXJlIHVzdWFsbHkgcHJvZHVjaW5nIGRldGVybWluaXN0aWMgcHNldWRvLXJhbmRvbSBzZXF1ZW5jZXMpLCB0aGUgZXN0aW1hdGVzIHdvdWxkIHZhcnkuIFRoZSBhbW91bnQgb2YgdmFyaWF0aW9uIHJlZHVjZXMgd2hlbiBtb3JlIGl0ZXJhdGlvbnMgYXJlIHVzZWQuIEZvciBleGFtcGxlLCBpZiB0aGUgcG9zdGVyaW9yIHdvdWxkIGJlIGNsb3NlIHRvIG5vcm1hbCB3aXRoIHN0YW5kYXJkIGRldmlhdGlvbiAxLCAkXG1hdGhybXtub3JtYWx9KFxtdSwgMSkkLCB0aGVuIDIwMDAgaW5kZXBlbmRlbnQgZHJhd3MgZnJvbSB0aGUgcG9zdGVyaW9yIHdvdWxkIHByb3ZpZGUgZW5vdWdoIGFjY3VyYWN5IHRoYXQgdGhlIHNlY29uZCBzaWduaWZpY2FudCBkaWdpdCBvZiBwb3N0ZXJpb3IgbWVhbiB3b3VsZCBvbmx5IHNvbWV0aW1lcyB2YXJ5IHRvIG9uZSBzbWFsbGVyIG9yIGxhcmdlciB2YWx1ZS4gT24gdGhlIG90aGVyIGhhbmQsIGZvciAxIHNpZ25pZmljYW50IGRpZ2l0IGFjY3VyYWN5LCAxMDAgaW5kZXBlbmRlbnQgZHJhd3Mgd291bGQgYmUgb2Z0ZW4gc3VmZmljaWVudCwgYnV0IHJlbGlhYmxlIGNvbnZlcmdlbmNlIGRpYWdub3N0aWNzIG1heSBuZWVkIG1vcmUgaXRlcmF0aW9ucyB0aGFuIDEwMCAoc2VlLCBlLmcuLCBAVmVodGFyaStldGFsOjIwMjE6UmhhdCkuIFRoZSBhYm92ZSB0aHVtYi1ydWxlcyBhcmUgdXNlZnVsIGZvciB0aGUgbmVjZXNzYXJ5IG51bWJlciBvZiBpbmRlcGVuZGVudCBkcmF3cyBmb3IgYSBwb3N0ZXJpb3IgbWVhbiBvZiBhIGRpc3RyaWJ1dGlvbiB3aGljaCBpcyByZWxhdGl2ZWx5IGNsb3NlIHRvIG5vcm1hbCBhbmQgaW4gb3RoZXIgY2FzZXMgYW5kLCBmb3IgZXhtYXBsZSwgZm9yIHBvc3RlcmlvciBxdWFudGlsZXMgbW9yZSBkcmF3cyBtYXkgYmUgbmVlZGVkLgoKTUNNQyBpbiBnZW5lcmFsIGRvZXNuJ3QgcHJvZHVjZSBpbmRlcGVuZGVudCBkcmF3cyBhbmQgdGhlIGVmZmVjdCBvZiBkZXBlbmRlbmN5IGFmZmVjdHMgaG93IG1hbnkgZHJhd3MgYXJlIG5lZWRlZCB0byBlc3RpbWF0ZSBkaWZmZXJlbnQgZXhwZWN0YXRpb25zLiBBcyBpbiBnZW5lcmFsLCB3ZSBkb24ndCBrbm93IGJlZm9yaGFuZCBob3cgTUNNQyB3aWxsIHBlcmZvcm0gZm9yIGEgbmV3IHBvc3RlcmlvciwgYW5kIHdlIGRvbid0IGtub3cgd2hhdCBpcyB0aGUgc2NhbGUgb2YgdGhhdCBwb3N0ZXJpb3IgYmVmb3JlaGFuZCwgd2UgbmVlZCB0byBzdGFydCB3aXRoIHNvbWUgaW5pdGlhbCBndWVzcyBvZiBudW1iZXIgb2YgaXRlcmF0aW9ucyB0byBydW4uCgojIFN1bW1hcnkKClN1bW1hcnkgb2Ygd29ya2Zsb3cgZm9yIGhvdyBtYW55IGRpZ2l0cyB0byByZXBvcnQKCjEuIFJ1biBpbmZlcmVuY2Ugd2l0aCBzb21lIGRlZmF1bHQgbnVtYmVyIG9mIGl0ZXJhdGlvbnMKMi4gQ2hlY2sgY29udmVyZ2VuY2UgZGlhZ25vc3RpY3MgZm9yIGFsbCBwYXJhbWV0ZXJzCjMuIENoZWNrIHRoYXQgRVNTIGlzIGJpZyBlbm91Z2ggZm9yIHJlbGlhYmxlIGNvbnZlcmdlbmNlCiAgIGRpYWdub3N0aWNzIGZvciBhbGwgcXVhbnRpdGllcyBvZiBpbnRlcmVzdAo0LiBMb29rIGF0IHRoZSBwb3N0ZXJpb3IgZm9yIHF1YW50aXRpZXMgb2YgaW50ZXJlc3QgYW5kIGRlY2lkZSBob3cKICAgbWFueSBzaWduaWZpY2FudCBkaWdpdHMgaXMgcmVhc29uYWJsZSB0YWtpbmcgaW50byBhY2NvdW50IHRoZQogICBwb3N0ZXJpb3IgdW5jZXJ0YWludHkgKHVzaW5nIFNELCBNQUQsIG9yIHRhaWwgcXVhbnRpbGVzKQo1LiBDaGVjayB0aGF0IE1DU0UgaXMgc21hbGwgZW5vdWdoIGZvciB0aGUgZGVzaXJlZCBhY2N1cmFjeSBvZgogICByZXBvcnRpbmcgdGhlIHBvc3RlcmlvciBzdW1tYXJpZXMgZm9yIHRoZSBxdWFudGl0aWVzIG9mCiAgIGludGVyZXN0LgoKIC0gSWYgdGhlIGFjY3VyYWN5IGlzIG5vdCBzdWZmaWNpZW50LCByZXBvcnQgbGVzcyBkaWdpdHMgb3IgcnVuCiAgIG1vcmUgaXRlcmF0aW9ucy4KIC0gSGFsdmluZyBNQ1NFIHJlcXVpcmVzIHF1YWRydXBsaW5nIHRoZSBudW1iZXIgb2YgaXRlcmF0aW9ucwogICAoaWYgQ0xUIGhvbGRzKS4KIC0gRGlmZmVyZW50IHF1YW50aXRpZXMgb2YgaW50ZXJlc3QgaGF2ZSBkaWZmZXJlbnQgTUNTRSBhbmQgbWF5CiAgIHJlcXVpcmUgZGlmZmVyZW50IG51bWJlciBvZiBpdGVyYXRpb25zIGZvciB0aGUgZGVzaXJlZCBhY2N1cmFjeS4KIC0gU29tZSBxdWFudGl0aWVzIG9mIGludGVyZXN0IG1heSBoYXZlIHBvc3RlcmlvciBkaXN0cmlidXRpb24gd2l0aAogICBpbmZpbml0ZSB2YXJpYW5jZSwgYW5kIHRoZW4gdGhlIEVTUyBhbmQgTUNTRSBhcmUgbm90IGRlZmluZWQgZm9yCiAgIHRoZSBleHBlY3RhdGlvbi4gSW4gc3VjaCBjYXNlcyB1c2UsIGZvciBleGFtcGxlLCBtZWRpYW4gaW5zdGVhZAogICBvZiBtZWFuIGFuZCBtZWFuIGFic29sdXRlIGRldmlhdGlvbiAoTUFEKSBpbnN0ZWFkIG9mIHN0YW5kYXJkCiAgIGRldmlhdGlvbi4gRVNTIGFuZCBNQ1NFIGZvciAobm9uLWV4dHJlbWUpIHF1YW50aWxlcyBjYW4gYmUKICAgZGVyaXZlZCBmcm9tIHRoZSAobm9uLWV4dHJlbWUpIGN1bXVsYXRpdmUgcHJvYmFiaWxpdGllcyB0aGF0CiAgIGFsd2F5cyBoYXZlIGZpbml0ZSBtZWFuIGFuZCB2YXJpYW5jZS4KCi0tLS0tLS0tLS0tLS0KCiMgRXhhbXBsZQoKQXMgYW4gZXhhbXBsZSwgd2UgYW5hbHlzZSB0aGUgdHJlbmQgaW4gc3VtbWVyIG1vbnRocyBhdmVyYWdlIHRlbXBlcmF0dXJlIDE5NTItLTIwMTMgYXQgS2lscGlzasOkcnZpIGluIG5vcnRod2VzdGVybiBGaW5uaXNoIExhcGxhbmQuIFN1bW1lciBtb250aHMgYXJlIEp1bmUsIEp1bHksIGFuZCBBdWd1c3QsIGFuZCB3ZSBhbmFseXNlIHRoZSBhdmVyYWdlIHRlbXBlcmF0dXJlIG92ZXIgdGhlc2UgbW9udGhzIGluIGVhY2ggeWVhci4KCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBjb21tZW50PU5BKQojIHN3aXRjaCB0aGlzIHRvIFRSVUUgdG8gc2F2ZSBmaWd1cmVzIGluIHNlcGFyYXRlIGZpbGVzCnNhdmVmaWdzIDwtIEZBTFNFCmBgYAoKIyMjIExvYWQgcGFja2FnZXMKCmBgYHtyIH0KbGlicmFyeSgicnByb2pyb290IikKcm9vdDwtaGFzX2ZpbGUoIi5Xb3JrZmxvdy1FeGFtcGxlcy1yb290IikkbWFrZV9maXhfZmlsZSgpCmxpYnJhcnkodGlkeXIpIApsaWJyYXJ5KGRwbHlyKSAKbGlicmFyeShjbWRzdGFucikKbGlicmFyeShwb3N0ZXJpb3IpCm9wdGlvbnMocGlsbGFyLm5lZ2F0aXZlID0gRkFMU0UpCmxpYnJhcnkobGVtb24pCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShiYXllc3Bsb3QpCnRoZW1lX3NldChiYXllc3Bsb3Q6OnRoZW1lX2RlZmF1bHQoYmFzZV9mYW1pbHkgPSAic2FucyIpKQpTRUVEIDwtIDQ4OTI3ICMgc2V0IHJhbmRvbSBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkKYGBgCgotLS0tLS0tLS0tLS0tCgojIyBLaWxwaXNqw6RydmkgZGF0YSBhbmQgbW9kZWwKCiMjIyBEYXRhCgpMb2FkIEtpbHBpc2rDpHJ2aSBzdW1tZXIgbW9udGggYXZlcmFnZSB0ZW1wZXJhdHVyZXMgMTk1Mi0yMDEzOgoKYGBge3IgfQpkYXRhX2tpbHBpcyA8LSByZWFkLmRlbGltKHJvb3QoIkRpZ2l0cy9kYXRhIiwia2lscGlzamFydmktc3VtbWVyLXRlbXAuY3N2IiksIHNlcCA9ICI7IikKZGF0YV9saW4gPC1saXN0KE4gPSBucm93KGRhdGFfa2lscGlzKSwKICAgICAgICAgICAgIHggPSBkYXRhX2tpbHBpcyR5ZWFyLAogICAgICAgICAgICAgeHByZWQgPSAyMDE2LAogICAgICAgICAgICAgeSA9IGRhdGFfa2lscGlzWyw1XSkKYGBgCgoKUGxvdCB0aGUgZGF0YQoKYGBge3IgfQpnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChhZXMoeCwgeSksIGRhdGEgPSBkYXRhLmZyYW1lKGRhdGFfbGluKSwgc2l6ZSA9IDEpICsKICBsYWJzKHkgPSAnU3VtbWVyIHRlbXBlcmF0dXJlXG4gYXQgS2lscGlzasOkcnZpJywgeD0gIlllYXIiKQpgYGAKCiMjIyBHYXVzc2lhbiBsaW5lYXIgbW9kZWwKCldlIHVzZSBhIHNpbXBsZSBsaW5lYXIgbW9kZWwgd2l0aCBub3JtYWwgb2JzZXJ2YXRpb24gbW9kZWwsIHdlYWtseQppbmZvcm1hdGl2ZSBub3JtYWwgcHJpb3IsIGFuZCB0aGUgcHJlZGljdG9yICh0aW1lKSBjZW50ZXJlZCB0byBoYXZlCjAgbWVhbi4gV2UgYXNzdW1lIGEgcHJpb3JpIHRoYXQgaW5jcmVhc2Ugb3IgZGVjcmVhc2UgaW4gdGVtcGVyYXR1cmUKaXMgZXF1YWxseSBsaWtlbHksIGFuZCB0aGF0IGl0IGlzIHVubGlrZWx5IHRoYXQgdGVtcGVyYXR1cmUgd291bGQKY2hhbmdlIG1vcmUgMTAgZGVncmVlcyBpbiAxMDAgeWVhcnMuIFdlIGFsc28gYXNzdW1lIHRoYXQgeWVhcmx5CnZhcmlhdGlvbiBpbiBzdW1tZXIgdGVtcGVyYXR1cmVzIGlzIGxpa2VseSB0byBiZSBsZXNzIHRoYW4gMwpkZWdyZWVzLgoKVGhlIGZvbGxvd2luZyBTdGFuIGNvZGUgY2VudGVycyB0aGUgY292YXJpYXRlIHRvIHJlZHVjZSBwb3N0ZXJpb3IKZGVwZW5kZW5jeSBvZiBzbG9wZSBhbmQgY29lZmZpY2llbnQgcGFyYW1ldGVycy4gSXQgYWxzbyBtYWtlcyBpdAplYXNpZXIgdG8gZGVmaW5lIHRoZSBwcmlvciBvbiBhdmVyYWdlIHRlbXBlcmF0dXJlIGluIHRoZSBjZW50ZXIgb2YKdGhlIHRpbWUgcmFuZ2UgKGluc3RlYWQgZGVmaW5pbmcgcHJpb3IgZm9yIHRlbXBlcmF0dXJlIGF0IHllYXIgMCkuCgpgYGB7ciB9CmNvZGVfbGluIDwtIHJvb3QoIkRpZ2l0cyIsICJsaW5lYXIuc3RhbiIpCndyaXRlTGluZXMocmVhZExpbmVzKGNvZGVfbGluKSkKYGBgCgojIyMgUHJpb3IgcGFyYW1ldGVyIHZhbHVlcyBmb3Igd2Vha2x5IGluZm9ybWF0aXZlIHByaW9ycwoKYGBge3IgfQpkYXRhX2xpbl9wcmlvcnMgPC0gYyhsaXN0KAogICAgcG11YWxwaGFfYyA9IDEwLCAgICAgIyBwcmlvciBtZWFuIGZvciBhdmVyYWdlIHRlbXBlcmF0dXJlCiAgICBwc2FscGhhID0gMTAsICAgICAgICAjIHdlYWtseSBpbmZvcm1hdGl2ZQogICAgcG11YmV0YSA9IDAsICAgICAgICAgIyBhIHByaW9yaSBpbmNyLiBhbmQgZGVjci4gYXMgbGlrZWx5CiAgICBwc2JldGEgPSAwLjEvMywgICAjIGF2ZyB0ZW1wIHByb2IgZG9lcyBkb2VzIG5vdCBpbmNyLiBtb3JlIHRoYW4gYSBkZWdyZWUgcGVyIDEwIHllYXJzOiAgc2V0dGluZyB0aGlzIHRvICsvLTMgc2QncwogICAgcHNzaWdtYSA9IDEpLCAgICAgICAgIyBzZXR0aW5nIHNkIG9mIHRvdGFsIHZhcmlhdGlvbiBpbiBzdW1tZXIgYXZlcmFnZSB0ZW1wZXJhdHVyZXMgdG8gMSBkZWdyZWUgaW1wbGllcyB0aGF0ICsvLSAzIHNkJ3MgaXMgKy8tMyBkZWdyZWVzOiAKICBkYXRhX2xpbikKYGBgCgojIyBSdW4gaW5mZXJlbmNlIGZvciBzb21lIG51bWJlciBvZiBpdGVyYXRpb25zCgpXZSBydW4gTUNNQyB3aXRoIFN0YW4ncyBjdXJyZW50IGRlZmF1bHQgc2V0dGluZ3MuIEFsbCBjb252ZXJnZW5jZQpkaWFnbm9zdGljcyBwYXNzIGFuZCBhbGwgZWZmZWN0aXZlIHNhbXBsZSBzaXplIGFyZSBiaWcgZW5vdWdoIHRoYXQKd2UgY2FuIGFzc3VtZSB0aGF0IHRoZSBjb252ZXJnZW5jZSBkaWFnbm9zdGljcyBhcmUgcmVsaWFibGUuCgoKYGBge3IgcmVzdWx0cz0naGlkZSd9Cm1vZF9saW4gPC0gY21kc3Rhbl9tb2RlbChzdGFuX2ZpbGUgPSBjb2RlX2xpbikKZml0X2xpbiA8LSBtb2RfbGluJHNhbXBsZShkYXRhID0gZGF0YV9saW5fcHJpb3JzLCBzZWVkID0gU0VFRCwgcmVmcmVzaCA9IDApCmBgYAoKIyMgUnVuIGNvbnZlcmdlbmNlIGRpYWdub3N0aWNzCgpUaGVyZSB3ZXJlIG5vIGNvbnZlcmdlbmNlIGlzc3VlcyByZXBvcnRlZCBieSBzYW1wbGluZy4gV2UgY2FuIGFsc28KZXhwbGljaXRseSBjYWxsIENtZFN0YW4gaW5mZXJlbmNlIGRpYWdub3N0aWNzOgoKYGBge3IgfQpmaXRfbGluJGNtZHN0YW5fZGlhZ25vc2UoKQpgYGAKCldlIGNoZWNrICRcd2lkZWhhdHtSfSQgZW5kIEVTUyB2YWx1ZXMsIHdoaWNoIGluIHRoaXMgY2FzZSBhbGwgbG9vayBnb29kLgoKYGBge3IgcmVuZGVyPWxlbW9uX3ByaW50LCBkaWdpdHM9YygwLDIsMiwyLDIsMiwyLDIsMCwwKX0KZHJhd3MgPC0gYXNfZHJhd3NfcnZhcnMoZml0X2xpbiRkcmF3cygpKQpzdW1tYXJpemVfZHJhd3MoZHJhd3MpCmBgYAoKQ29tcHV0ZSBwb3N0ZXJpb3IgZHJhd3MgZm9yIHRoZSBsaW5lYXIgZml0CgpgYGB7ciB9CmRyYXdzJG11IDwtIGRyYXdzJGFscGhhX2MrZHJhd3MkYmV0YSooZGF0YV9saW4keC1tZWFuKGRhdGFfbGluJHgpKQpgYGAKClBsb3QgdGhlIGxpbmVhciBmaXQgd2l0aCA5MCUgcG9zdGVyaW9yIGludGVydmFsCgpgYGB7ciB9CmRhdGEuZnJhbWUoeCA9IGRhdGFfbGluJHgsCiAgICAgICAgICAgeSA9IGRhdGFfbGluJHksCiAgICAgICAgICAgRW11ID0gbWVhbihkcmF3cyRtdSksCiAgICAgICAgICAgcTA1ID0gYXMudmVjdG9yKHF1YW50aWxlKGRyYXdzJG11LCAwLjA1KSksCiAgICAgICAgICAgcTk1ID0gYXMudmVjdG9yKHF1YW50aWxlKGRyYXdzJG11LCAwLjk1KSkpICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2VvbV9yaWJib24oYWVzKHg9eCwgeW1pbj1xMDUsIHltYXg9cTk1KSwgZmlsbD0nZ3JleTkwJykgKwogIGdlb21fbGluZShhZXMoeD14LCB5PUVtdSwgKSkgKwogIGdlb21fcG9pbnQoYWVzKHgsIHkpLCBzaXplID0gMSkgKwogIGxhYnMoeSA9ICdTdW1tZXIgdGVtcGVyYXR1cmVcbiBhdCBLaWxwaXNqw6RydmkgKMKwQyknLCB4PSAiWWVhciIpKwogIGd1aWRlcyhsaW5ldHlwZSA9ICJub25lIikKYGBgCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmlmIChzYXZlZmlncykgZ2dzYXZlKHJvb3QoIktpbHBpc2phcnZpIiwia2lscGlzamFydmlfZml0LnBkZiIpLAogICAgICAgICAgICAgICAgICAgICB3aWR0aD02LCBoZWlnaHQ9MykKYGBgCgpBdCB0aGlzIHBvaW50IGl0IGlzIHN1ZmZpY2llbnQgdGhhdCBkaWFnbm9zdGljcyBhcmUgT0sKKGNtZHN0YW5fZGlhZ25vc2Ugc2F5cyAibm8gcHJvYmxlbXMgZGV0ZWN0ZWQiKSBhbmQgZWZmZWN0aXZlIHNhbXBsZQpzaXplcyBhcmUgbGFyZ2UgZW5vdWdoICg+NDAwKSB0aGF0IHdlIGNhbiBhc3N1bWUgdGhlIGRpYWdub3N0aWNzIHRvCmJlIHJlbGlhYmxlLgoKV2UgY291bGQgYWxzbyBkbyBwb3N0ZXJpb3IgcHJlZGljdGl2ZSBjaGVja2luZyBhbmQgcmVzaWR1YWwgcGxvdHMsCmJ1dCBub3cgd2UgZm9jdXMgb24gY2hlY2tpbmcgaG93IG1hbnkgTUNNQyBpdGVyYXRpb25zIGFyZSBuZWVkZWQKYW5kIGhvdyBtYW55IGRpZ2l0cyB0byByZXBvcnQgaW4gcG9zdGVyaW9yIHN1bW1hcnkgcmVzdWx0cy4KCiMjIEhvdyBtYW55IGRpZ2l0cyB0byByZXBvcnQgYmFzZWQgb24gcG9zdGVyaW9yIHVuY2VydGFpbnR5CgpXZSB3YW50IHRvIHJlcG9ydCBwb3N0ZXJpb3Igc3VtbWFyaWVzIGZvciB0aGUgc2xvcGUsIHRoYXQgaXMgdGhlCmluY3JlYXNlIGluIGF2ZXJhZ2Ugc3VtbWVyIHRlbXBlcmF0dXJlLCBhbmQgZm9yIHRoZSBwcm9iYWJpbGl0eQp0aGF0IHRoZSBzbG9wZSBpcyBwb3NpdGl2ZS4gV2UgZmlyc3QgY29uc2lkZXIgd2hhdCBpcyB0aGUKcmVhc29uYWJsZSByZXBvcnRpbmcgYWNjdXJhY3kgaWYgdGhlIHBvc3RlcmlvciBpbmZlcmVuY2Ugd291bGQgYmUKZXhhY3QgKGllIGlnbm9yaW5nIGZpcnN0IHRoZSBNb25ldCBDYXJsbyB2YXJpYWJpbGl0eSkuCgpXZSBzdGFydCBsb29raW5nIGF0IHRoZSBtZWFuIGFuZCA5MCUgaW50ZXJ2YWwgZm9yIHRoZSBzbG9wZSBwYXJhbWV0ZXIgYmV0YQoKYGBge3IgcmVuZGVyPWxlbW9uX3ByaW50LCBkaWdpdHM9M30KZHJhd3MgJT4lCiAgc3Vic2V0X2RyYXdzKCJiZXRhIikgJT4lCiAgc3VtbWFyaXplX2RyYXdzKG1lYW4sIH5xdWFudGlsZSgueCwgcHJvYnMgPSBjKDAuMDUsIDAuOTUpKSkgCmBgYAoKVGhlc2UgdmFsdWVzIGNvcnJlc3BvbmQgdG8gdGhlIHRlbXBlcmF0dXJlIGluY3JlYXNlIHBlciB5ZWFyLCBidXQKdG8gaW1wcm92ZSByZWFkYWJpbGl0eSB3ZSBzd2l0Y2ggbG9va2luZyBhdCB0aGUgdGVtcGVyYXR1cmUKaW5jcmVhc2UgcGVyIDEwMCB5ZWFycy4gCgpgYGB7ciB9CmRyYXdzIDwtIGRyYXdzICU+JQogIG11dGF0ZV92YXJpYWJsZXMoYmV0YTEwMCA9IDEwMCpiZXRhKQpgYGAKCkxldCdzIGxvb2sgYXQgdGhlIG1lYW4gYW5kIDkwJSBpbnRlcnZhbCBmb3IgdGhlIGV4cGVjdGVkIHRlbXBlcmF0dXJlCmluY3JlYXNlIHBlciAxMDAgeWVhcnMuCgpgYGB7ciByZW5kZXI9bGVtb25fcHJpbnQsIGRpZ2l0cz0zfQpkcmF3cyAlPiUKICBzdWJzZXRfZHJhd3MoImJldGExMDAiKSAlPiUKICBzdW1tYXJpemVfZHJhd3MobWVhbiwgfnF1YW50aWxlKC54LCBwcm9icyA9IGMoMC4wNSwgMC45NSkpKQpgYGAKClRoZSBudW1iZXIgb2YgZGlnaXRzIHNob3duIGluIFIgdmFyaWVzIGRlcGVuZGluZyBvbiB0aGUgcHJpbnQKbWV0aG9kIGFuZCBvcHRpb25zIGZvciB0aGUgc3BlY2lmaWMgb2JqZWN0IGFuZCBhYm92ZSB3ZSBzZWUgMwpkZWNpbWFsIGRpZ2l0cy4gRGVwZW5kaW5nIG9uIHRoZSBwcmludCBtZXRob2QsIFdlIG1heSBhbHNvIHNlZQptb3JlIGRpZ2l0cywgZm9yIGV4YW1wbGU6CgpgYGB7ciB9Cm1lYW4oZHJhd3MkYmV0YSkKcXVhbnRpbGUoZHJhd3MkYmV0YSwgcHJvYnM9YygwLjA1LDAuOTUpKQpgYGAKClRoZSBtb3JlIGRpZ2l0cyBhcmUgc2hvd24sIHRoZSBtb3JlIG9mIHRoZW0gYXJlIGxpa2VseSB0byBiZQp1bm5lY2Vzc2FyeSBjbHV0dGVyIGRpc3RyYWN0aW5nIHRoZSByZWFkZXIgZnJvbSB0aGUgaW1wb3J0YW50Cm1lc3NhZ2UuICBDb25zaWRlcmluZyB0aGUgd2lkdGggb2YgdGhlIDkwJSBpbnRlcnZhbCwgcHJhY3RpY2FsbHkKbWVhbmluZ2Z1bCBhY2N1cmFjeSB3b3VsZCBiZSBoZXJlIHRvIHJlcG9ydCBwb3N0ZXJpb3IgbWVhbiBhcyAyLjAKYW5kIHRoZSBwb3N0ZXJpb3IgaW50ZXJ2YWwgYXMgWzAuNyAsIDMuMl0uIERlcGVuZGluZyBvbiB0aGUKY29udGV4dCwgaXQgbWlnaHQgYmUgZXZlbiBiZXR0ZXIgdG8gcm91bmQgbW9yZSwgYW5kIHJlcG9ydCB0aGF0IHRoZQppbmNyZWFzZSBpcyBlc3RpbWF0ZWQgdG8gYmUgMSB0byAzIGRlZ3JlZXMgcGVyIGNlbnR1cnkgKDgxJQpwcm9iYWJpbGl0eSwgb3Igcm91bmRlZCB0byA4MCUgcHJvYmFiaWxpdHkpLCBvciAwIHRvIDQgZGVncmVlcyBwZXIKY2VudHVyeSAoOTklIHByb2JhYmlsaXR5KS4gVGhlcmUgaXMgbm8gbmVlZCB0byBzdGljayB0byByZXBvcnRpbmcKOTAlIG9yIDk1JSBpbnRlcnZhbC4KClRoZSBudW1iZXIgb2Ygc2lnbmlmaWNhbnQgZGlnaXRzIG5lZWRlZCBmb3IgcmVwb3J0aW5nIGNhbiBiZSBvZnRlbgpkZXRlcm1pbmVkIGFsc28gd2l0aCByb3VnaCBwb3N0ZXJpb3IgYXBwcm94aW1hdGlvbnMgdGhhdCBpbmRpY2F0ZQp0aGUgb3JkZXIgb2YgbWFnbml0dWRlIG9mIHRoZSBwb3N0ZXJpb3IgbWVhbiBhbmQgc2NhbGUsIGFuZCB0aGVuCm1vcmUgaXRlcmF0aW9ucyBtYXkgYmUgbmVlZGVkIHRvIGdldCBtb3JlIGFjY3VyYXRlIGVzdGltYXRlIGZvcgp0aG9zZSBkaWdpdHMuCgojIyBIb3cgbWFueSBkaWdpdHMgdG8gcmVwb3J0IGJhc2VkIG9uIE1vbnRlIENhcmxvIHN0YW5kYXJkIGVycm9yCgpOb3cgdGhhdCB3ZSBoYXZlIGFuIGVzdGltYXRlIGZvciB0aGUgcG9zdGVyaW9yIHVuY2VydGFpbnR5IG9mIHRoZQpzbG9wZSBwYXJhbWV0ZXIsIHdlIGNhbiBjaGVjayB3aGV0aGVyIHdlIGhhdmUgZW5vdWdoIG1hbnkKaXRlcmF0aW9ucyBmb3IgdGhlIGRlc2lyZWQgcmVwb3J0aW5nIGFjY3VyYWN5LiBNYXJrb3YgY2hhaW4gTW9udGUKQ2FybG8gbWV0aG9kIHVzZWQgYnkgU3RhbiB0byBtYWtlIHRoZSBwb3N0ZXJpb3IgZXN0aW1hdGVzIGlzCnN0b2NoYXN0aWMuIElmIHdlIHJlcGVhdCB0aGUgY29tcHV0YXRpb24gd2l0aCBkaWZmZXJlbnQgcmFuZG9tCm51bWJlciBnZW5lcmF0b3Igc2VlZCwgd2UgZ2V0IHNsaWdodGx5IGRpZmZlcmVudCBlc3RpbWF0ZXMuCgpgYGB7ciByZXN1bHRzPSdoaWRlJ30KZXN0aW1hdGVzIDwtIHQoc2FwcGx5KDE6MTAsIGZ1bmN0aW9uKGkpIHsKICBtb2RfbGluJHNhbXBsZShkYXRhID0gZGF0YV9saW5fcHJpb3JzLCBzZWVkID0gU0VFRCtpLCByZWZyZXNoID0gMCwKICAgICAgICAgICAgICAgICBzaG93X21lc3NhZ2VzID0gRkFMU0UpJGRyYXdzKCkgJT4lCiAgICBtdXRhdGVfdmFyaWFibGVzKGJldGExMDAgPSAxMDAqYmV0YSkgJT4lCiAgICBzdWJzZXRfZHJhd3MoImJldGExMDAiKSAlPiUKICAgICAgc3VtbWFyaXplX2RyYXdzKG1lYW4sIH5xdWFudGlsZSgueCwgcHJvYnMgPSBjKDAuMDUsIDAuOTUpKSkgJT4lCiAgICAgIHNlbGVjdCgtdmFyaWFibGUpfSkpICU+JSB1bmxpc3QoKSAlPiUgbWF0cml4KG5yb3c9MTApCmNvbG5hbWVzKGVzdGltYXRlcykgPC0gYygibWVhbiIgLCI1JSIsIjk1JSIpCmBgYApgYGB7ciByZW5kZXI9bGVtb25fcHJpbnQsIGRpZ2l0cz0zfQphc190aWJibGUoZXN0aW1hdGVzKQpgYGAKCldlIHNlZSB0aGF0IGZvciBtZWFuIHRoZSB0aGlyZCBkaWdpdCBpcyB2YXJ5aW5nIGFuZCB0aGUgcm91bmRlZAp2YWx1ZSBpcyBiZXR3ZWVuIDEuOSBhbmQgMi4wLiBGb3IgdGhlIDUlIHF1YW50aWxlIGV2ZW4gdGhlIGZpcnN0CnNpZ25pZmljYW50IGRpZ2l0IGlzIHNvbWV0aW1lcyB2YXJ5aW5nIGFuZCB0aGUgcm91bmRlZCB2YWx1ZSB3b3VsZAp2YXJ5IGJldHdlZW4gMC42IGFuZCAwLjcuICBGb3IgdGhlIDk1JSBxdWFudGlsZSB0aGUgc2Vjb25kIGRpZ2l0IGlzCnZhcnlpbmcgYW5kIHRoZSByb3VuZGVkIHZhbHVlcyB3b3VsZCB2YXJ5IGJldHdlZW4gMy4yIGFuZAozLjMuIEJhc2VkIG9uIHRoaXMsIGl0IHdvdWxkIGJlIE9LIHRvIHJlcG9ydCB0aGUgbWVhbiBhcyAxLjkgb3IgMgphbmQgOTAlIGludGVydmFsIGFzIFswLjcsIDMuMl0gYXMgYmFzZWQgb24gdGhlIGZpcnN0IE1vbnRlIENhcmxvCmVzdGltYXRlLiBDb25zaWRlcmluZyB0aGUgc2NhbGUsIHRoZSBtaW5vciB2YXJpYXRpb24gaW4gdGhlIGxhc3QKZGlnaXQgaXMgbm90IGFmZmVjdGluZyB0aGUgaW50ZXJwcmV0YXRpb24gb2YgdGhlCnJlc3VsdHMuIEFsdGVybmF0aXZlbHkgdGhlIGNvdXJzZXIgcmFuZ2VzIFsxLCAzXSBvciBbMCwgNF0gY291bGQgYmUKcmVwb3J0ZWQgYXMgZGlzY3Vzc2VkIGFib3ZlLgoKSW5zdGVhZCBvZiByZXBlYXRpbmcgdGhlIGVzdGltYXRpb24gbWFueSB0aW1lcyB3ZSBjYW4gZXN0aW1hdGUgdGhlCmFjY3VyYWN5IG9mIHRoZSBvcmlnaW5hbCBzYW1wbGluZyBieSBjb21wdXRpbmcgTW9udGUgQ2FybG8gc3RhbmRhcmQKZXJyb3IgKE1DU0UpIHRoYXQgdGFrZXMgaW50byBhY2NvdW50IHRoZSBxdWFudGl0eSBvZiBpbnRlcmVzdCwgYW5kIHRoZQplZmZlY3RpdmUgc2FtcGxlIHNpemUgb2YgTUNNQyBkcmF3cyAoc2VlLCBlLmcuLCBAVmVodGFyaStldGFsOjIwMjE6UmhhdCkuCgoKYGBge3IgcmVuZGVyPWxlbW9uX3ByaW50LCBkaWdpdHM9M30KZHJhd3MgJT4lCiAgc3Vic2V0X2RyYXdzKCJiZXRhMTAwIikgJT4lCiAgc3VtbWFyaXplX2RyYXdzKG1jc2VfbWVhbiwgfm1jc2VfcXVhbnRpbGUoLngsIHByb2JzID0gYygwLjA1LCAwLjk1KSkpCmBgYAoKV2Ugc2hvdyBhbHNvIHRoZSBFU1MgdmFsdWVzIGZvciBtZWFuIGFuZCBxdWFudGlsZXMsIHRvIGlsbHVzdHJhdGUKdGhhdCB0aGUgRVNTIHZhbHVlcyBjYW4gYmUgZGlmZmVyZW50IGZvciBkaWZmZXJlbnQgcXVhbnRpdGllcywgYnV0CmFsc28gdGhhdCB0aGUgc2FtZSBFU1MgZG9lc24ndCBsZWFkIHRvIHRoZSBzYW1lIE1DU0UsIGFuZCBzaW1pbGFyCkVTUyBkb2Vzbid0IGxlYWQgdG8gc2ltaWxhciBNQ1NFIGFzIE1DU0UgZGVwZW5kcyBhbHNvIG9uIHRoZQpxdWFudGl0eS4gSGVyZSwgZm9yIGV4YW1wbGUsIGFsdGhvdWdoIEVTU3MgYXJlIHNpbWlsYXIgZm9yIGFsbApxdWFudGl0aWVzLCA1XCUgYW5kIDk1XCUgcXVhbnRpbGVzIGhhdmUgY2xlYXJseSBoaWdoZXIgTUNTRSB0aGFuCnRoZSBtZWFuLgoKCmBgYHtyIHJlbmRlcj1sZW1vbl9wcmludCwgZGlnaXRzPTB9CmRyYXdzICU+JQogIHN1YnNldF9kcmF3cygiYmV0YTEwMCIpICU+JQogIHN1bW1hcml6ZV9kcmF3cyhlc3NfbWVhbiwgfmVzc19xdWFudGlsZSgueCwgcHJvYnMgPSBjKDAuMDUsIDAuOTUpKSkKYGBgCgpUaGUgTUNTRSBmb3IgdGhlIG1lYW4gZXN0aW1hdGUgaXMgYWJvdXQgMC4wMSBhbmQgZm9yIDUlIGFuZCA5NSUKcXVhbnRpbGVzIGFib3V0IDAuMDMuIElmIHdlIG11bHRpcGx5IHRoZXNlIGJ5IDIsIHRoZSBsaWtlbHkgcmFuZ2UKb2YgdmFyaWF0aW9uIGR1ZSB0byBNb250ZSBDYXJsbyBpcyAkXHBtIDAuMDIkIGZvciBtZWFuIGFuZCAkXHBtCjAuMDckIGZvciA1JSBhbmQgOTUlIHF1YW50aWxlcy4gRnJvbSB0aGlzIHdlIGNhbiBpbnRlcnByZXQgdGhhdAppdCdzIHVubGlrZWx5IHRoZXJlIHdvdWxkIGJlIHZhcmlhdGlvbiBpbiB0aGUgcmVwb3J0ZWQgZXN0aW1hdGUgZm9yCnRoZSBtZWFuLCBpZiBpdCBpcyByZXBvcnRlZCBhcyAyLjAuIEZvciA1JSBhbmQgOTUlIHF1YW50aWxlcwp0aGVyZSBjYW4gYmUgdmFyaWF0aW9uIGluIHRoZSBmaXJzdCBkZWNpbWFsIGRpZ2l0LCBidXQgdGhhdApkaWZmZXJlbmNlIHdvdWxkIG5vdCBiZSBtZWFuaW5nZnVsIGluIG1vc3QgY2FzZXMuIFdlIGNvdWxkIHJ1biBtb3JlCml0ZXJhdGlvbnMgdG8gZ2V0IHRoZSBNQ1NFIGZvciBxdWFudGlsZXMgZG93biB0byBzb21ldGhpbmcgbGlrZQowLjAxLCB3aGljaCB3b3VsZCByZXF1aXJlIGFib3V0IDEwIHRpbWVzIG1vcmUgaXRlcmF0aW9ucy4gQXNzdW1pbmcKdGhlIHBvc3RlcmlvciBoYXMgZmluaXRlIHZhcmlhbmNlIGFuZCBNQ01DIGlzIG1peGluZyB3ZWxsLCB3ZQpleHBlY3QgdGhhdCBydW5uaW5nIGZvdXIgdGltZXMgbW9yZSBpdGVyYXRpb25zIHdvdWxkIGhhbHZlIHRoZQpNQ1NFcy4KCkFzIGRpc2N1c3NlZCBiZWZvcmUsIGl0IG1pZ2h0IGJlIGFueXdheSBiZXR0ZXIgdG8gcmVwb3J0IHRoZQpwb3N0ZXJpb3IgdW5jZXJ0YWludHkgaW50ZXJ2YWwgd2l0aCBsZXNzIGRpZ2l0cywgYW5kIGlmIHdlIHJlcG9ydGVkCmVpdGhlciA4MCUgaW50ZXJ2YWwgJFsxLCAzXSQgb3IgOTklIGludGVydmFsICRbMCwgNF0kLCB3ZSB3b3VsZAphbHJlYWR5IGhhdmUgc3VmZmljaWVudCBhY2N1cmFjeSBmb3IgdGhlIG51bWJlciBvZiBzaG93bgpkaWdpdHMuIFRoZXNlIE1DU0UgZXN0aW1hdGVzIGlsbHVzdHJhdGUgYWxzbyB0aGUgZmFjdCB0aGF0IHVzdWFsbHkKdGFpbCBxdWFudGlsZXMgaGF2ZSBsb3dlciBhY2N1cmFjeSB0aGFuIHRoZSBwb3N0ZXJpb3IgbWVhbi4KCldlIGNhbiBhbHNvIHJlcG9ydCB0aGUgcHJvYmFiaWxpdHkgdGhhdCB0aGUgdGVtcGVyYXR1cmUgY2hhbmdlIGlzCnBvc2l0aXZlLgoKYGBge3IgcmVuZGVyPWxlbW9uX3ByaW50LCBkaWdpdHM9M30KZHJhd3MgJT4lCiAgbXV0YXRlX3ZhcmlhYmxlcyhiZXRhMHAgPSBiZXRhMTAwPjApICU+JQogIHN1YnNldF9kcmF3cygiYmV0YTBwIikgJT4lCiAgc3VtbWFyaXplX2RyYXdzKCJtZWFuIiwgbWNzZSA9IG1jc2VfbWVhbikKYGBgCgpUaGUgcHJvYmFiaWxpdHkgaXMgc2ltcGx5IGVzdGltYXRlZCBhcyBhIHBvc3RlcmlvciBtZWFuIG9mIGFuCmluZGljYXRvciBmdW5jdGlvbiBhbmQgdGhlIHVzdWFsIE1DU0UgZm9yIG1lYW4gZXN0aW1hdGUgaXMgdXNlZC4KVGhlIE1DU0UgaW5kaWNhdGVzIHRoYXQgd2UgaGF2ZSBlbm91Z2ggTUNNQyBpdGVyYXRpb25zIGZvcgpwcmFjdGljYWxseSBtZWFuaW5nZnVsIHJlcG9ydGluZyB0aGF0IHRoZSBwcm9iYWJpbGl0eSB0aGF0IHRoZQp0ZW1wZXJhdHVyZSBpcyBpbmNyZWFzaW5nIGlzIGxhcmdlciB0aGFuIDk5JS4gVGhlcmUgaXMgbm90IG11Y2gKcHJhY3RpY2FsIGRpZmZlcmVuY2UgdG8gcmVwb3J0aW5nIHRoYXQgdGhlIHByb2JhYmlsaXR5IGlzIDk5LjMlCmFuZCB0byBlc3RpbWF0ZSB0aGF0IHRoaXJkIGRpZ2l0IGFjY3VyYXRlbHkgd291bGQgcmVxdWlyZSA2NCB0aW1lcwptb3JlIGl0ZXJhdGlvbnMuIEZvciB0aGlzIHNpbXBsZSBwcm9ibGVtLCBzYW1wbGluZyB0aGF0IG1hbnkKaXRlcmF0aW9ucyB3b3VsZCBub3QgYmUgdGltZSBjb25zdW1pbmcsIGJ1dCB3ZSBtaWdodCBhbHNvIGluc3RlYWQKY29uc2lkZXIgdG8gb2J0YWluIG1vcmUgZGF0YSB0byB2ZXJpZnkgdGhhdCB0aGUgc3VtbWVyIHRlbXBlcmF0dXJlCmluIG5vcnRoZXJuIEZpbmxhbmQgaGFzIGJlZW4gaW5jcmVhc2luZyBzaW5jZSAxOTUyLgoKV2UgYWRkaXRpb25hbHkgY29tcHV0ZSBwcm9iYWJpbGl0aWVzIHRoYXQgdGhlIHRlbXBlcmF0dXJlIGluY3JlYXNlCmlzIG1vcmUgdGhhbiAxLCAyLCAzIG9yIDQgZGVncmVlcywgYW5kIGNvcnJlc3BvbmRpbmcgTUNTRXMgYW5kIEVTU3MuCgpgYGB7ciByZW5kZXI9bGVtb25fcHJpbnQsIGRpZ2l0cz1jKDAsIDMsIDMsIDApfQpkcmF3cyAlPiUKICBzdWJzZXRfZHJhd3MoImJldGExMDAiKSAlPiUKICBtdXRhdGVfdmFyaWFibGVzKGJldGExcCA9IGJldGExMDA+MSwKICAgICAgICAgICAgICAgICAgIGJldGEycCA9IGJldGExMDA+MiwKICAgICAgICAgICAgICAgICAgIGJldGEzcCA9IGJldGExMDA+MywKICAgICAgICAgICAgICAgICAgIGJldGE0cCA9IGJldGExMDA+NCkgJT4lCiAgc3Vic2V0X2RyYXdzKCJiZXRhWzEtNF1wIiwgcmVnZXg9VFJVRSkgJT4lCiAgc3VtbWFyaXplX2RyYXdzKCJtZWFuIiwgbWNzZSA9IG1jc2VfbWVhbiwgRVNTID0gZXNzX21lYW4pCmBgYAoKVGFraW5nIGludG8gYWNjb3VudCBNQ1NFcyBnaXZlbiB0aGUgY3VycmVudCBwb3N0ZXJpb3Igc2FtcGxlLCB3ZQpjYW4gc3VtbWFyaXNlIHRoZXNlIGFzIHAoYmV0YTEwMD4xKSA9IDg4JS0tOTElLCBwKGJldGExMDA+MikgPQo0NiUtLTUxJSwgcChiZXRhMTAwPjMpID0gNyUtLTEwJSwgcChiZXRhMTAwPjQpID0gMC4yJS0tMSUuIFRvIGdldAp0aGVzZSBwcm9iYWJpbGl0aWVzIGVzdGltYXRlZCB3aXRoIDIgZGlnaXQgYWNjdXJhY3kgd291bGQgYWdhaW4KcmVxdWlyZSBtb3JlIGl0ZXJhdGlvbnMgKDE2LTMwMCB0aW1lcyBtb3JlIGl0ZXJhdGlvbnMgZGVwZW5kaW5nIG9uCnRoZSBxdWFudGl0eSksIGJ1dCB0aGUgYWRkZWQgaXRlcmF0aW9ucyB3b3VsZCBub3QgY2hhbmdlIHRoZQpjb25jbHVzaW9uIHJhZGljYWxseS4KCiMjIE1DU0UgY29tcHV0YXRpb24gZGV0YWlscwoKVGhlIGRldGFpbHMgb2YgaG93IE1DU0UgaXMgZXN0aW1hdGVkIGZvciBwb3N0ZXJpb3IgZXhwZWN0YXRpb25zIGFuZApxdWFudGlsZXMgYXJlIHByb3ZpZGVkIGJ5IEBWZWh0YXJpK2V0YWw6MjAyMTpSaGF0LCBhbmQKaW1wbGVtZW50YXRpb25zIGFyZSBhdmFpbGFibGUsIGZvciBleGFtcGxlIGluIHRoZSBgcG9zdGVyaW9yYCBSCnBhY2thZ2UgdXNlZCBpbiB0aGlzIG5vdGVib29rIGFuZCBpbiBgQXJ2aVpgIFB5dGhvbiBwYWNrYWdlLgoKIyMgUm91Z2ggZXN0aW1hdGVzIGZvciBob3cgbWFueSBpdGVyYXRpb25zIHRvIHJ1biBpbml0aWFsbHkKCkJlZm9yZSBydW5uaW5nIGFueSBNQ01DLCB3ZSBtYXkgb2J0YWluIHNvbWUgcm91Z2ggZXN0aW1hdGVzIG9mIGhvdwptYW55IGl0ZXJhdGlvbnMgd2Ugd291bGQgbmVlZCBmb3IgY2VydGFpbiByZWxhdGl2ZSBhY2N1cmFjeSBmb3IKdGhlIHBvc3RlcmlvciBtZWFuIChpZiBNQ01DIHJ1bnMgd2VsbCkuCgpJZiB3ZSBhc3N1bWUgdGhhdCB0aGUgcG9zdGVyaW9yIG9mIHBhcmFtZXRlciAkXHRoZXRhJCBoYXMgZmluaXRlCm1lYW4gYW5kIHZhcmlhbmNlLCBhbmQgd2UgaGF2ZSBtYW55IGluZGVwZW5kZW50IE1vbnRlIENhcmxvIGRyYXdzCiRTJCwgd2UgY2FuIHVzZSBjZW50cmFsIGxpbWl0IHRoZW9yZW0gdG8ganVzdGlmeSB0aGF0IHRoZSB1bmNlcnRhaW50eQpyZWxhdGVkIHRvIHRoZSBlc3RpbWF0ZWQgZXhwZWN0YXRpb24gY2FuIGJlIGFwcHJveGltYXRlZCB3aXRoCm5vcm1hbCBkaXN0cmlidXRpb24sICRcbWF0aHJte25vcm1hbH0oXGhhdHtcdGhldGF9LCBcaGF0e1xzaWdtYX1fXHRoZXRhIC8KXHNxcnR7U30pJCwgd2hlcmUgJFxoYXR7XHRoZXRhfSQgaXMgdGhlIGVzdGltYXRlIGFuZAokXGhhdHtcc2lnbWF9X1x0aGV0YSQgaXMgdGhlIGVzdGltYXRlZCBwb3N0ZXJpb3Igc3RhbmRhcmQgZGV2aWF0aW9uCm9mICRcdGhldGEkLgoKV2UgY2FuIHNlZSB0aGF0IGdpdmVuIGFueSAkXGhhdHtcdGhldGF9JCBhbmQgJFxoYXR7XHNpZ21hfV9cdGhldGEkLAppZiAkUz0xMDAkLCB0aGUgdW5jZXJ0YWludHkgaXMgMTBcJSBvZiB0aGUgcG9zdGVyaW9yIHNjYWxlIHdoaWNoCndvdWxkIG9mdGVuIGJlIHN1ZmZpY2llbnQgZm9yIGluaXRpYWwgZXhwZXJpbWVudHMsIGFuZCBpZiAkUz0xMDAwMCQsCnRoZSB1bmNlcnRhaW50eSBpcyAxXCUgb2YgdGhlIHBvc3RlcmlvciBzY2FsZSB3aGljaCB3b3VsZCBvZnRlbiBiZQpzdWZmaWNpZW50IGZvciB0d28gc2lnbmlmaWNhbnQgZGlnaXQgYWNjdXJhY3kuCgoxMFwlIHJlbGF0aXZlIGFjY3VyYWN5IG1lYW5zIHRoYXQgZGVzcGl0ZSB0aGUgbWFnbml0dWRlIG9mCiRcaGF0e1xzaWdtYX1fXHRoZXRhJCB3ZSBnZXQgYWNjdXJhY3kgYXBwcm94aW1hdGVseSBhIHdvcnRoIGF0CmxlYXN0IG9uZSBkaWdpdC4gTGV0J3MgZmlyc3QgYXNzdW1lICRcaGF0e1x0aGV0YX0gPSAxLjIzNCQuIFdlIGNhbgpzaW1wbGlmeSB0aGUgYW5hbHlzaXMgYnkgbm90aW5nIHRoYXQgaWYgZXhhbWluZSB0aGUgYmVoYXZpb3IgZ2l2ZW4KZGlmZmVyZW50ICRcaGF0e1xzaWdtYX1fXHRoZXRhJCB2YWx1ZXMgYXMsIGUuZy4sICQxMF57LTF9JCwKJDEwXnswfSQsICQxMF57MX0kLCBhbmQgY29ycmVzcG9uZGluZ2x5IHByZXNlbnQgdGhlICRcaGF0e1x0aGV0YX0kCmFzICQxMi4zNCBcdGltZXMgMTBeey0xfSQsICQxLjIzNCBcdGltZXMgMTBeezB9JCwgJDAuMTIzNCBcdGltZXMKMTBeezF9JC4gV2UgZ2V0IGVxdWl2YWxlbnQsIGJ1dCBzaW1wbGVyIGFuYWx5c2lzIGlmIHdlIHNldAokXGhhdHtcc2lnbWF9X1x0aGV0YT0xJCBhbmQgYW5hbHlzZSB0aGUgY2FzZXMgd2l0aCBkaWZmZXJlbnQgdmFsdWVzCiRcaGF0e1x0aGV0YX0kIChpZSB3ZSBjaGFuZ2UgdGhlIGNvb3JkaW5hdGVzIHRvIGhhdmUgdW5pdCBzY2FsZQp3aXRoIHJlc3BlY3QgdG8gdGhlIHBvc3RlcmlvciBzdGFuZGFyZCBkZXZpYXRpb24pLgoKICAtIElmICRTPTEwMCQgKGluZGVwZW5kZW50IGRyYXdzKSBhbmQgJFxoYXR7XHNpZ21hfV9cdGhldGE9MSQsCiAgICBNQ1NFIGlzICQwLjEkIGFuZCB3aXRoIDk5XCUgcHJvYmFiaWxpdHkgdGhhdCB2YXJpYXRpb24gaW4KICAgIEVbJFx0aGV0YSRdIGlzICRccG0gMC4zJC4gVGh1cywgaWYgdGhlIGVzdGltYXRpb24gd291bGQgYmUKICAgIHJlcGVhdGVkIHRoZSBmaXJzdCBzaWduaWZpY2FudCBkaWdpdCB3b3VsZCBzdGF5IHRoZSBzYW1lIG9yCiAgICBoYXZlIG1pbm9yIHZhcmlhYmlsaXR5IHRvIG9uZSBzbWFsbGVyIG9yIG9uZSBsYWdlciBkaWdpdC4gVGh1cwogICAgd2UgaGF2ZSBhcHByb3hpbWF0ZWx5IG9uZSBzaWduaWZpY2FudCBkaWdpdCBhY2N1cmFjeS4KICAtIElmICRTPTIwMDAkIChpbmRlcGVuZGVudCBkcmF3cykgYW5kICRcaGF0e1xzaWdtYX1fXHRoZXRhPTEkLAogICAgTUNTRSBpcyAkMC4wMiQgYW5kIHdpdGggOTlcJSBwcm9iYWJpbGl0eSB0aGF0IHZhcmlhdGlvbiBpbgogICAgRVskXHRoZXRhJF0gaXMgJFxwbSAwLjA3JC4gVGh1cywgaWYgdGhlIGVzdGltYXRpb24gd291bGQgYmUKICAgIHJlcGVhdGVkIHRoZSBmaXJzdCBzaWduaWZpY2FudCBkaWdpdCB3b3VsZCBzdGF5IHRoZSBzYW1lLCBhbmQKICAgIHRoZSBzZWNvbmQgc2lnbmlmaWNhbnQgZGlnaXQgd291bGQgaGF2ZSBoYXZlIG1pbm9yIHZhcmlhYmlsaXR5CiAgICB0byBvbmUgc21hbGxlciBvciBvbmUgbGFnZXIgZGlnaXQuIFRodXMgd2UgaGF2ZSBhcHByb3hpbWF0ZWx5CiAgICB0d28gc2lnbmlmaWNhbnQgZGlnaXQgYWNjdXJhY3kuIFdpdGggYSBsYXJnZXIgJFMkLCB0aGVyZSBpcwogICAgbGVzcyB2YXJpYWJpbGl0eSBpbiB0aGUgc2Vjb25kIHNpZ25pZmljYW50IGRpZ2l0LgoKRHluYW1pYyBIYW1pbHRvbmlhbiBNb250ZSBDYXJsbyBpbiBTdGFuIGlzIG9mdGVuIHNvIGVmZmljaWVudCB0aGF0CkVTUz5TLzIuIFRodXMgcnVubmluZyB3aXRoIHRoZSBkZWZhdWx0IG9wdGlvbnMgNCBjaGFpbnMgd2l0aCAxMDAwCml0ZXJhdGlvbnMgYWZ0ZXIgd2FybXVwIGlzIGxpa2VseSB0byBnaXZlIG5lYXIgdHdvIHNpZ25pZmljYW50CmRpZ2l0IGFjY3VyYWN5IGZvciB0aGUgcG9zdGVyaW9yIG1lYW4uIFRoZSBhY2N1cmFjeSBmb3IgNVwlIGFuZAo5NVwlIHF1YW50aWxlcyB3b3VsZCBiZSBiZXR3ZWVuIG9uZSBhbmQgdHdvIHNpZ25pZmljYW50IGRpZ2l0cy4KClRoZSBhYm92ZSBhbmFseXNpcyBzaG93cyB0aGUgYmVuZWZpdCBvZiBpbnRlcnByZXRpbmcgRVNTIGFzIGEgc2NhbGUKZnJlZSBkaWFnbm9zdGljIHdoZXRoZXIgd2UgYXJlIGxpa2VseSB0byBoYXZlIGVub3VnaCBpdGVyYXRpb25zLiBBCnNjYWxlIGZyZWUgaGVyZSBtZWFucyB3ZSBkb24ndCBuZWVkIHRvIGNvbXBhcmUgRVNTIHZhbHVlcyB0bwpwb3N0ZXJpb3Igc3RhbmRhcmQgZGV2aWF0aW9ucyBvciB0byBkb21haW4ga25vd2xlZGdlIG9mIHRoZQpxdWFudGl0eSBvZiBpbnRlcmVzdCwgbWFraW5nIGl0IGZhc3RlciB0byBjaGVjayB0aGF0IHdlIGhhdmUgaGlnaAplbm91Z2ggRVNTIGZvciBtYW55IHF1YW50aXRpZXMgb2YgaW50ZXJlc3QuIEhvd2V2ZXIsIGhpZ2ggRVNTIGlzCm5vdCBzdWZmaWNpZW50IHRvIGd1YXJhbnRlZSBjZXJ0YWluIGFjY3VyYWN5LCBhcyBNQ1NFIGRlcGVuZHMgYWxzbwpvbiB0aGUgcXVhbnRpdHkgb2YgaW50ZXJlc3QgYW5kIHRodXMgaW4gdGhlIGVuZCBpdCBpcyB1c2VmdWwgdG8KY2hlY2sgTUNTRXMgZm9yIHRoZSB2YWx1ZXMgdG8gYmUgcmVwb3J0ZWQuIEZvciBleGFtcGxlLCBhYm92ZSwgdGhlCmVzdGltYXRlIGZvciB3aGV0aGVyIHRoZSB0ZW1wZXJhdHVyZSBpbmNyZWFzZSBpcyBsYXJnZXIgdGhhbiA0CmRlZ3JlZXMgcGVyIGNlbnR1cnkgaGFzIGhpZ2ggRVNTLCBidXQgdGhlIGluZGljYXRvciB2YXJpYWJsZQpjb250YWlucyBsZXNzIGluZm9ybWF0aW9uICh0aGFuIGNvbnRpbnVvdXMgdmFsdWVzKSBhbmQgdGh1cyBtdWNoCmhpZ2hlciBFU1Mgd291bGQgYmUgbmVlZGVkIGZvciB0d28gc2lnbmlmaWNhbnQgZGlnaXQgYWNjdXJhY3kuCgo8YnIgLz4KCiMgUmVmZXJlbmNlcyB7LnVubnVtYmVyZWR9Cgo8ZGl2IGlkPSJyZWZzIj48L2Rpdj4KCg==