This case study demonstrates using simple examples the most common failure modes in Markov chain Monte Carlo based Bayesian inference, how to recognize these using the diagnostics, and how to fix the problems.

Load packages

library("rprojroot")
root<-has_file(".casestudies-root")$make_fix_file()
library(cmdstanr) 
library(posterior)
options(pillar.neg = FALSE, pillar.subtle=FALSE, pillar.sigfig=2)
library(lemon)
library(tidyr) 
library(dplyr) 
library(ggplot2)
library(bayesplot)
theme_set(bayesplot::theme_default(base_family = "sans", base_size=16))
set1 <- RColorBrewer::brewer.pal(7, "Set1")
SEED <- 48927 # set random seed for reproducibility

Improper posterior

An unbounded likelihood without a proper prior can lead to an improper posterior. We recommend to always use proper priors (integral over a proper distribution is finite) to guarantee proper posteriors.

A commonly used model that can have unbounded likelihood is logistic regression with complete separation in data.

Data

Univariate continous predictor \(x\), binary target \(y\), and the two classes are completely separable, which leads to unbounded likelihood.

set.seed(SEED+4)
M=1;
N=10;
x=matrix(sort(rnorm(N)),ncol=M)
y=rep(c(0,1), each=N/2)
data_logit <-list(M = M, N = N, x = x, y = y)
data.frame(data_logit) |>
  ggplot(aes(x, y)) +
  geom_point(size = 3, shape=1, alpha=0.6) +
  scale_y_continuous(breaks=c(0,1))

ggsave(file='separable_data.pdf', width=4, height=4)

Model

We use the following Stan logistic regression model, where we have `forgot'' to include prior for the coefficientbeta`.

code_logit <- root("Problems", "logit_glm.stan")
writeLines(readLines(code_logit))
// logistic regression
data {
  int<lower=0> N;
  int<lower=0> M;
  array[N] int<lower=0,upper=1> y;
  matrix[N,M] x;
}
parameters {
  real alpha;
  vector[M] beta;
}
model {
  y ~ bernoulli_logit_glm(x, alpha, beta);
}

Sample

mod_logit <- cmdstan_model(stan_file = code_logit)
fit_logit <- mod_logit$sample(data = data_logit, seed = SEED, refresh = 0)
Running MCMC with 4 sequential chains...

Chain 1 finished in 0.9 seconds.
Chain 2 finished in 1.0 seconds.
Chain 3 finished in 1.1 seconds.
Chain 4 finished in 1.0 seconds.

All 4 chains finished successfully.
Mean chain execution time: 1.0 seconds.
Total execution time: 4.3 seconds.
Warning: 1580 of 4000 (40.0%) transitions ended with a divergence.
See https://mc-stan.org/misc/warnings for details.
Warning: 2420 of 4000 (60.0%) transitions hit the maximum treedepth limit of 10.
See https://mc-stan.org/misc/warnings for details.

Convergence diagnostics

When running Stan, we get warnings. We can also explicitly check the inference diagnostics:

fit_logit$diagnostic_summary()
$num_divergent
[1] 434 419 362 365

$num_max_treedepth
[1] 566 581 638 635

$ebfmi
[1] 1.957384 1.975748 2.023517 1.920562

We can also check \(\widehat{R}\) end effective sample size (ESS) diagnostics

draws <- as_draws_rvars(fit_logit$draws())
summarize_draws(draws)
variable mean median sd mad q5 q95 rhat ess_bulk ess_tail
lp__ 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 NA NA NA
alpha 1.892074e+34 3.417172e+29 3.847278e+34 5.066299e+29 1.206648e+24 1.052236e+35 3.44 4 11
beta 4.517489e+34 8.496816e+29 9.178637e+34 1.259738e+30 2.718532e+24 2.707925e+35 3.45 4 12

We see that \(\widehat{R}\) for both and are about 3 and Bulk-ESS is about 4, which indicate that the chains are not mixing at all.

The above diagnostics refer to a documentation (https://mc-stan.org/misc/warnings) that mentions possibility to adjust the sampling algorithm options (e.g., increasing adapt_delta and max_treedepth), but it is better first to investigate the posterior.

The following Figure shows the posterior draws as marginal histograms and joint scatterplots. The range of the values is huge, which is typical for improper posterior, but the values of alpha and beta in any practical application are likely to have much smaller magnitude. In this case, increasing adapt_delta and max_treedepth would not have solved the problem, and would have just caused waste of modeler and computation time.

(p<-mcmc_pairs(as_draws_array(draws), pars=c("alpha","beta")))

ggsave(p, file='separable_pairs.pdf', width=6, height=4)

Stan compiler pedantic check

The above diagnostics are applicable with any probabilistic programming framework. Stan compiler can also recognize some common problems. By default the pedantic mode is not enabled, but we can use option pedantic = TRUE at compilation time, or after compilation with the check_syntax method.

mod_logit$check_syntax(pedantic = TRUE)
Warning: The parameter beta has no priors. This means either no prior is
    provided, or the prior(s) depend on data variables. In the later case,
    this may be a false positive.
Warning: The parameter alpha has no priors. This means either no prior is
    provided, or the prior(s) depend on data variables. In the later case,
    this may be a false positive.
Stan program is syntactically correct

The pedantic check correctly warns that alpha and beta don’t have priors.

A fixed model with proper priors

We add proper weak priors and rerun inference.

code_logit2 <- root("Problems", "logit_glm2.stan")
writeLines(readLines(code_logit2))
// logistic regression
data {
  int<lower=0> N;
  int<lower=0> M;
  array[N] int<lower=0,upper=1> y;
  matrix[N,M] x;
}
parameters {
  real alpha;
  vector[M] beta;
}
model {
  alpha ~ normal(0,10);
  beta ~ normal(0,10);
  y ~ bernoulli_logit_glm(x, alpha, beta);
}

Sample

mod_logit2 <- cmdstan_model(stan_file = code_logit2)
fit_logit2 <- mod_logit2$sample(data = data_logit, seed = SEED, refresh = 0)
Running MCMC with 4 sequential chains...

Chain 1 finished in 0.0 seconds.
Chain 2 finished in 0.0 seconds.
Chain 3 finished in 0.0 seconds.
Chain 4 finished in 0.0 seconds.

All 4 chains finished successfully.
Mean chain execution time: 0.0 seconds.
Total execution time: 0.5 seconds.

Convergence diagnostics

There were no convergence warnings. We can also explicitly check the inference diagnostics:

fit_logit2$diagnostic_summary()
$num_divergent
[1] 0 0 0 0

$num_max_treedepth
[1] 0 0 0 0

$ebfmi
[1] 1.0938307 1.0000890 1.0620493 0.9204544

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

draws <- as_draws_rvars(fit_logit2$draws())
summarize_draws(draws)
variable mean median sd mad q5 q95 rhat ess_bulk ess_tail
lp__ -2.59 -2.29 1.02 0.75 -4.64 -1.60 1 1315 1542
alpha 6.16 5.87 2.80 2.69 2.06 11.21 1 793 1203
beta 14.55 14.10 5.76 5.89 5.92 24.74 1 761 975

The following figure shows the more reasonable marginal histograms and joint scatterplots of the posterior sample.

(p=mcmc_pairs(as_draws_array(draws), pars=c("alpha","beta")))

ggsave(p, file='separable_prior_pairs.pdf', width=6, height=4)

A model with unused parameter

When writing and editing models, a common mistake is to declare a parameter, but not use it in the model. If the parameter is not used at all, it doesn’t have proper prior and the likelihood doesn’t provide information about that parameter, and thus the posterior along that parameter is improper. We use the previous logistic regression model with proper priors on alpha and beta, but include extra parameter declaration real gamma.

Model

code_logit3 <- root("Problems", "logit_glm3.stan")
writeLines(readLines(code_logit3))
// logistic regression
data {
  int<lower=0> N;
  int<lower=0> M;
  array[N] int<lower=0,upper=1> y;
  matrix[N,M] x;
}
parameters {
  real alpha;
  vector[M] beta;
  real gamma;
}
model {
  alpha ~ normal(0,1);
  beta ~ normal(0,1);
  y ~ bernoulli_logit_glm(x, alpha, beta);
}

Sample

mod_logit3 <- cmdstan_model(stan_file = code_logit3)
fit_logit3 <- mod_logit3$sample(data = data_logit, seed = SEED, refresh = 0)
Running MCMC with 4 sequential chains...

Chain 1 finished in 1.4 seconds.
Chain 2 finished in 1.4 seconds.
Chain 3 finished in 1.4 seconds.
Chain 4 finished in 1.3 seconds.

All 4 chains finished successfully.
Mean chain execution time: 1.4 seconds.
Total execution time: 5.7 seconds.
Warning: 1686 of 4000 (42.0%) transitions hit the maximum treedepth limit of 10.
See https://mc-stan.org/misc/warnings for details.

Convergence diagnostics

There is sampler warning. We can also explicitly call inference diagnostics:

fit_logit3$diagnostic_summary()
$num_divergent
[1] 0 0 0 0

$num_max_treedepth
[1] 425 414 442 405

$ebfmi
[1] 1.211723 1.207911 1.343447 1.375802

Instead of increasing max_treedepth, we check the other convergence diagnostics.

draws <- as_draws_rvars(fit_logit3$draws())
summarize_draws(draws)
variable mean median sd mad q5 q95 rhat ess_bulk ess_tail
lp__ -6.610000e+00 -6.31000e+00 1.010000e+00 7.400000e-01 -8.640000e+00 -5.64000e+00 1.00 1641 2467
alpha 3.700000e-01 3.60000e-01 6.100000e-01 5.900000e-01 -6.500000e-01 1.35000e+00 1.00 3382 2727
beta 1.290000e+00 1.27000e+00 7.600000e-01 7.500000e-01 7.000000e-02 2.56000e+00 1.00 3297 2928
gamma -7.271885e+18 -3.75658e+18 5.077307e+19 4.041267e+19 -9.555314e+19 8.54153e+19 3.17 5 12

\(\widehat{R}\), Bulk-ESS, and Tail-ESS look good for alpha and beta, but really bad forgamma, clearly pointing where to look for problems in the model code. The histogram ofgamma` posterior draws show huge magnitude of values (values larger than \(10^{20}\)) indicating improper posterior.

mcmc_pairs(as_draws_array(draws), pars=c("alpha","beta","gamma"))

Non-mixing is well diagnosed by \(\widehat{R}\) and ESS, but the following Figure shows one of the rare cases where trace plots are useful to illustrate the type of non-mixing in case of improper uniform posterior for one the parameters.

mcmc_trace(as_draws_array(draws), pars=c("gamma"))

ggsave(file='unusedparam_trace.pdf', width=6, height=4)

Stan compiler pedantic check

Stan compiler pedantic check also recognizes that parameter gamma was declared but was not used in the density calculation.

mod_logit3$check_syntax(pedantic = TRUE)
Warning: The parameter gamma was declared but was not used in the density
    calculation.
Stan program is syntactically correct

A posterior with two parameters competing

Sometimes the models have two or more parameters that have similar or exactly the same role. We illustrate this by adding an extra column to the previous data matrix. Sometimes the data matrix is augmented with a column of 1’s to present the intercept effect. In this case that is redundant as our model has the explicit intercept term alpha, and this redundancy will lead to problems.

Data

M=2;
N=1000;
x=matrix(c(rep(1,N),sort(rnorm(N))),ncol=M)
y=((x[,1]+rnorm(N)/2)>0)+0
data_logit4 <-list(M = M, N = N, x = x, y = y)

Model

We use the previous logistic regression model with proper priors (and no extra gamma).

code_logit2 <- root("Problems", "logit_glm2.stan")
writeLines(readLines(code_logit2))
// logistic regression
data {
  int<lower=0> N;
  int<lower=0> M;
  array[N] int<lower=0,upper=1> y;
  matrix[N,M] x;
}
parameters {
  real alpha;
  vector[M] beta;
}
model {
  alpha ~ normal(0,10);
  beta ~ normal(0,10);
  y ~ bernoulli_logit_glm(x, alpha, beta);
}

Sample

mod_logit4 <- cmdstan_model(stan_file = code_logit2)
fit_logit4 <- mod_logit4$sample(data = data_logit4, seed = SEED, refresh = 0)
Running MCMC with 4 sequential chains...

Chain 1 finished in 4.0 seconds.
Chain 2 finished in 4.0 seconds.
Chain 3 finished in 3.5 seconds.
Chain 4 finished in 3.7 seconds.

All 4 chains finished successfully.
Mean chain execution time: 3.8 seconds.
Total execution time: 15.5 seconds.

The Stan sampling time per chain with the original data matrix was less than 0.1s per chain. Now the Stan sampling time per chain is several seconds, which is suspicious. There are no automatic convergence diagnostic warnings and checking other diagnostics don’t show anything really bad.

Convergence diagnostics

fit_logit4$diagnostic_summary()
$num_divergent
[1] 0 0 0 0

$num_max_treedepth
[1] 0 0 0 0

$ebfmi
[1] 1.1216053 0.9732017 0.8804549 1.0738646
draws <- as_draws_rvars(fit_logit4$draws())
summarize_draws(draws)
variable mean median sd mad q5 q95 rhat ess_bulk ess_tail
lp__ -116.81 -116.49 1.26 1.03 -119.24 -115.44 1 1135 1954
alpha 1.86 1.89 7.16 6.98 -10.33 13.59 1 1119 1238
beta[1] 1.92 1.87 7.16 6.99 -9.80 14.08 1 1118 1223
beta[2] 0.37 0.37 0.21 0.21 0.04 0.71 1 1360 1530

ESS estimates are above the recommended diagnostic thresholds, but lower than what we would expect in general from Stan for such a lower dimensional problem.

The following figure shows marginal histograms and joint scatterplots, and we can see that alpha and beta[1] are highly correlated.

(p=mcmc_pairs(as_draws_array(draws), pars=c("alpha","beta[1]","beta[2]")))

ggsave(p, file='competing_params_pairs.pdf', width=6, height=4)

We can compute the correlation.

cor(as_draws_matrix(draws)[,c("alpha","beta[1]")])[1,2]
[1] -0.9995226

The numerical value for the correlation is \(-0.999\). The correlation close to 1 can happen also from other reasons (see the next example), but one possibility is that parameters have similar role in the model. Here the reason is the constant column in \(x\), which we put there for the demonstration purposes. We may a have constant column, for example, if the predictor matrix is augmented with the intercept predictor, or if the observed data or subdata used in the specific analysis happens to have only one unique value.

Stan compiler pedantic check

Stan compiler pedantic check examining the code can’t recognize this issue, as the problem depends also on the data.

mod_logit4$check_syntax(pedantic = TRUE)
Stan program is syntactically correct

A posterior with very high correlation

In the previous example the two parameters had the same role in the model, leading to high posterior correlation. High posterior correlations are common also in linear models when the predictor values are far from 0. We illustrate this with a linear regression model for the summer temperature in Kilpisjärvi, Finland, 1952–2013. We use the year as the covariate \(x\) without centering it.

Data

The data are Kilpisjärvi summer month temperatures 1952-2013.

data_kilpis <- read.delim(root("Problems","kilpisjarvi-summer-temp.csv"), sep = ";")
data_lin <-list(M=1,
                N = nrow(data_kilpis),
                x = matrix(data_kilpis$year, ncol=1),
                y = data_kilpis[,5])

data.frame(data_lin) |>
  ggplot(aes(x, y)) +
  geom_point(size = 1) +
  labs(y = 'Summer temp. @Kilpisjärvi', x= "Year") +
  guides(linetype = "none")

ggsave(file='Kilpisjarvi_data.pdf', width=6, height=4)

Model

We use the following Stan linear regression model

code_lin <- root("Problems", "linear_glm_kilpis.stan")
writeLines(readLines(code_lin))
// logistic regression
data {
  int<lower=0> N;
  int<lower=0> M;
  vector[N] y;
  matrix[N,M] x;
}
parameters {
  real alpha;
  vector[M] beta;
  real sigma;
}
model {
  alpha ~ normal(0, 100);
  beta ~ normal(0, 100);
  sigma ~ normal(0, 1);
  y ~ normal_id_glm(x, alpha, beta, sigma);
}
mod_lin <- cmdstan_model(stan_file = code_lin)
fit_lin <- mod_lin$sample(data = data_lin, seed = SEED, refresh = 0)
Running MCMC with 4 sequential chains...
Chain 1 Rejecting initial value:
Chain 1   Error evaluating the log probability at the initial value.
Chain 1 Exception: normal_id_glm_lpdf: Scale vector is -1.5974, but must be positive finite! (in '/tmp/RtmpoIWO9X/model-c49cb463abc8e.stan', line 17, column 2 to column 43)
Chain 1 Exception: normal_id_glm_lpdf: Scale vector is -1.5974, but must be positive finite! (in '/tmp/RtmpoIWO9X/model-c49cb463abc8e.stan', line 17, column 2 to column 43)
Chain 1 Rejecting initial value:
Chain 1   Error evaluating the log probability at the initial value.
Chain 1 Exception: normal_id_glm_lpdf: Scale vector is -0.929594, but must be positive finite! (in '/tmp/RtmpoIWO9X/model-c49cb463abc8e.stan', line 17, column 2 to column 43)
Chain 1 Exception: normal_id_glm_lpdf: Scale vector is -0.929594, but must be positive finite! (in '/tmp/RtmpoIWO9X/model-c49cb463abc8e.stan', line 17, column 2 to column 43)
Chain 1 finished in 1.1 seconds.
Chain 2 finished in 1.0 seconds.
Chain 3 Rejecting initial value:
Chain 3   Error evaluating the log probability at the initial value.
Chain 3 Exception: normal_id_glm_lpdf: Scale vector is -1.50837, but must be positive finite! (in '/tmp/RtmpoIWO9X/model-c49cb463abc8e.stan', line 17, column 2 to column 43)
Chain 3 Exception: normal_id_glm_lpdf: Scale vector is -1.50837, but must be positive finite! (in '/tmp/RtmpoIWO9X/model-c49cb463abc8e.stan', line 17, column 2 to column 43)
Chain 3 finished in 1.0 seconds.
Chain 4 finished in 1.1 seconds.

All 4 chains finished successfully.
Mean chain execution time: 1.0 seconds.
Total execution time: 4.4 seconds.
Warning: 16 of 4000 (0.0%) transitions hit the maximum treedepth limit of 10.
See https://mc-stan.org/misc/warnings for details.

Convergence diagnostics

Stan gives a warning: There were X transitions after warmup that exceeded the maximum treedepth. As in the previous example, there are no other warnings.

fit_lin$diagnostic_summary()
$num_divergent
[1] 0 0 0 0

$num_max_treedepth
[1] 10  4  0  2

$ebfmi
[1] 1.0136207 0.9657334 1.1039565 1.1209683
draws <- as_draws_rvars(fit_lin$draws())
summarize_draws(draws)
variable mean median sd mad q5 q95 rhat ess_bulk ess_tail
lp__ -38.50 -38.18 1.25 1.02 -40.89 -37.15 1 1114 1649
alpha -30.86 -30.79 15.06 14.45 -55.47 -5.57 1 1185 1337
beta 0.02 0.02 0.01 0.01 0.01 0.03 1 1184 1337
sigma 1.12 1.11 0.10 0.10 0.97 1.30 1 1350 1287

ESS estimates are above the diagnostic threshold, but lower than we would expect for such a low dimensional model, unless there are strong posterior correlations. The following Figure shows the marginal histograms and joint scatterplot for alpha and beta[1], which shows they are very highly correlated.

mcmc_pairs(as_draws_array(draws), pars=c("alpha","beta"))

ggsave(p, file='correlating_params_pairs.pdf', width=6, height=4)

Here the reason is that the \(x\) values are in the range 1952–2013, and the intercept alpha denotes the temperature at year 0, which is very far away from the range of observed \(x\). If the intercept alpha changes, the slope beta needs to change too. The high correlation makes the inference slower, and we can make it faster by centering \(x\). Here we simply subtract 1982.5 from the predictor year, so that the mean of \(x\) is 0. We could also include the centering and back transformation to Stan code.

Centered data

data_lin <-list(M=1,
                N = nrow(data_kilpis),
                x = matrix(data_kilpis$year-1982.5, ncol=1),
                y = data_kilpis[,5])
fit_lin <- mod_lin$sample(data = data_lin, seed = SEED, refresh = 0)
Running MCMC with 4 sequential chains...

Chain 1 finished in 0.0 seconds.
Chain 2 finished in 0.0 seconds.
Chain 3 finished in 0.0 seconds.
Chain 4 finished in 0.0 seconds.

All 4 chains finished successfully.
Mean chain execution time: 0.0 seconds.
Total execution time: 0.5 seconds.

Convergence diagnostics

We check the diagnostics

fit_lin$diagnostic_summary()
$num_divergent
[1] 0 0 0 0

$num_max_treedepth
[1] 0 0 0 0

$ebfmi
[1] 1.0579740 0.9583711 1.0273150 1.0810975
draws <- as_draws_rvars(fit_lin$draws())
summarize_draws(draws)
variable mean median sd mad q5 q95 rhat ess_bulk ess_tail
lp__ -38.55 -38.21 1.32 1.06 -41.14 -37.11 1 1915 2466
alpha 9.31 9.31 0.15 0.14 9.07 9.56 1 3681 2701
beta 0.02 0.02 0.01 0.01 0.01 0.03 1 3927 2766
sigma 1.12 1.11 0.11 0.10 0.96 1.31 1 3168 2454

The following figure shows the scatter plot.

mcmc_pairs(as_draws_array(draws), pars=c("alpha","beta"))

With this change, there is no posterior correlation, Bulk-ESS estimates are 3 times bigger, and the mean time per chain goes from 1.3s to less than 0.05s; that is, we get 2 orders of magnitude faster inference. In a bigger problems this could correspond to reduction of computation time from 24 hours to less than 20 minutes.

A bimodal posterior

Bimodal distributions can arise from many reasons as in mixture models or models with non-log-concave likelihoods or priors (that is, with distributions with thick tails). We illustrate the diagnostics revealing the multimodal posterior. We use a simple toy problem with \(t\) model and data that is not from a \(t\) distribution, but from a mixture of two normal distributions

Data

Bimodally distributed data

N=20
y=c(rnorm(N/2, mean=-5, sd=1),rnorm(N/2, mean=5, sd=1));
data_tt <-list(N = N, y = y)

Model

Unimodal Student’s \(t\) model:

code_tt <- root("Problems", "student.stan")
writeLines(readLines(code_tt))
// student-student model
data {
  int<lower=0> N;
  vector[N] y;
}
parameters {
  real mu;
}
model {
  mu ~ student_t(4, 0, 100);
  y ~ student_t(4, mu, 1);
}

Sample

mod_tt <- cmdstan_model(stan_file = code_tt)
fit_tt <- mod_tt$sample(data = data_tt, seed = SEED, refresh = 0)
Running MCMC with 4 sequential chains...

Chain 1 finished in 0.0 seconds.
Chain 2 finished in 0.0 seconds.
Chain 3 finished in 0.0 seconds.
Chain 4 finished in 0.0 seconds.

All 4 chains finished successfully.
Mean chain execution time: 0.0 seconds.
Total execution time: 0.5 seconds.

Convergence diagnostics

We check the diagnostics

fit_tt$diagnostic_summary()
$num_divergent
[1] 0 0 0 0

$num_max_treedepth
[1] 0 0 0 0

$ebfmi
[1] 1.303367 1.037493 1.192409 1.165997
draws <- as_draws_rvars(fit_tt$draws())
summarize_draws(draws)
variable mean median sd mad q5 q95 rhat ess_bulk ess_tail
lp__ -84.57 -84.34 0.74 0.46 -86.03 -83.90 1.13 21 120
mu -0.08 -0.35 4.62 6.81 -5.11 4.99 1.73 6 153

The \(\widehat{R}\) values for mu are large and ESS values for mu are small indicating convergence problems. The following figure shows the histogram and trace plots of the posterior draws, clearly showing the bimodality and that chains are not mixing between the modes.

mcmc_hist(as_draws_array(draws), pars=c("mu"))

ggsave(file='bimodal1_hist.pdf', width=4, height=4)

In this toy example, with random initialization each chains has 50% probability of ending in either mode. We used Stan’s default of 4 chains, and when random initialization is used, there is 6% chance that when running Stan once, we would miss the multimodality. If the attraction areas within the random initialization range are not equal, the probability of missing one mode is even higher. There is a tradeoff between the default computation cost and cost of having higher probability of finding multiple modes. If there is a reason to suspect multimodality, it is useful to run more chains. Running more chains helps to diagnose the multimodality, but the probability of chains ending in different modes can be different from the relative probability mass of each mode, and running more chains doesn’t fix this. Other means are needed to improve mixing between the modes (e.g. Yao et al., 2020) or to approximately weight the chains (e.g. Yao et al., 2022).

Easy bimodal posterior

If the modes in the bimodal distribution are not strongly separated, MCMC can jump from one mode to another and there are no convergence issues.

N=20
y=c(rnorm(N/2, mean=-3, sd=1),rnorm(N/2, mean=3, sd=1));
data_tt <-list(N = N, y = y)
fit_tt <- mod_tt$sample(data = data_tt, seed = SEED, refresh = 0)
Running MCMC with 4 sequential chains...

Chain 1 finished in 0.0 seconds.
Chain 2 finished in 0.0 seconds.
Chain 3 finished in 0.0 seconds.
Chain 4 finished in 0.0 seconds.

All 4 chains finished successfully.
Mean chain execution time: 0.0 seconds.
Total execution time: 0.5 seconds.

Convergence diagnostics

We check the diagnostics

fit_tt$diagnostic_summary()
$num_divergent
[1] 0 0 0 0

$num_max_treedepth
[1] 0 0 0 0

$ebfmi
[1] 0.8670786 0.8435780 0.7262904 0.7804591
draws <- as_draws_rvars(fit_tt$draws())
summarize_draws(draws)
variable mean median sd mad q5 q95 rhat ess_bulk ess_tail
lp__ -54.23 -53.75 1.0 0.57 -56.15 -53.34 1.04 207 1181
mu 0.84 1.34 1.3 0.62 -2.17 2.06 1.06 107 357

Two modes are visible.

mcmc_hist(as_draws_array(draws), pars=c("mu"))

ggsave(file='bimodal2_hist.pdf', width=4, height=4)

Trace plot is not very useful. It shows the chains are jumping between modes, but it’s difficult to see whether the jumps happen often enough and chains are mixing well.

mcmc_trace(as_draws_array(draws), pars=c("mu"))

ggsave(file='bimodal2_trace.pdf', width=4, height=4)

Rank ECDF plot indicates good mixing as all chains have their lines inside the envelope (the envelope assumes no autocorrelation, which is the reason to thin the draws here)

draws |> thin_draws(ndraws(draws)/ess_basic(draws$mu)) |>
  mcmc_rank_ecdf(pars=c("mu"), plot_diff=TRUE)

ggsave(file='bimodal2_rank_ecdf_diff.pdf', width=4, height=4)

Initial value issues

MCMC requires some initial values. By default, Stan generates them randomly from [-2,2] in unconstrained space (constraints on parameters are achieved by transformations). Sometimes these initial values can be bad and cause numerical issues. Computers, (in general) use finite number of bits to present numbers and with very small or large numbers, there can be problems of presenting them or there can be significant loss of accuracy.

The data is generated from a Poisson regression model. The Poisson intensity parameter has to be positive and usually the latent linear predictor is exponentiated to be positive (the exponentiation can also be justified by multiplicative effects on Poisson intensity).

We intentionally generate the data so that there are initialization problems, but the same problem is common with real data when the scale of the predictors is large or small compared to the unit scale. The following figure shows the simulated data.

Data

set.seed(SEED)
M=1;
N=20;
x=1e3*matrix(c(sort(rnorm(N))),ncol=M)
y=rpois(N,exp(1e-3*x[,1]))
data_pois <-list(M = M, N = N, x = x, y = y)
data.frame(data_pois) |>
  ggplot(aes(x, y)) +
  geom_point(size = 3)

ggsave(file='poisson_data.pdf', width=4, height=4)

Model

We use a Poisson regression model with proper priors. The line poisson_log_glm(x, alpha, beta) corresponds to a distribution in which the log intensity of the Poisson distribution is modeled with alpha + beta * x but is implemented with better computational efficiency.

code_pois <- root("Problems", "pois_glm.stan")
writeLines(readLines(code_pois))
// Poisson regression
data {
  int<lower=0> N;
  int<lower=0> M;
  array[N] int<lower=0> y;
  matrix[N,M] x;
}
parameters {
  real alpha;
  vector[M] beta;
}
model {
  alpha ~ normal(0,10);
  beta ~ normal(0,10);
  y ~ poisson_log_glm(x, alpha, beta);
}

Sample

mod_pois <- cmdstan_model(stan_file = code_pois)
fit_pois <- mod_pois$sample(data = data_pois, seed = SEED, refresh = 0)
Running MCMC with 4 sequential chains...
Chain 1 Rejecting initial value:
Chain 1   Log probability evaluates to log(0), i.e. negative infinity.
Chain 1   Stan can't start sampling from this initial value.
Chain 1 Rejecting initial value:
Chain 1   Log probability evaluates to log(0), i.e. negative infinity.
Chain 1   Stan can't start sampling from this initial value.
Chain 1 Rejecting initial value:
Chain 1   Log probability evaluates to log(0), i.e. negative infinity.
Chain 1   Stan can't start sampling from this initial value.
Chain 1 finished in 1.0 seconds.
Chain 2 Rejecting initial value:
Chain 2   Log probability evaluates to log(0), i.e. negative infinity.
Chain 2   Stan can't start sampling from this initial value.
Chain 2 finished in 0.2 seconds.
Chain 3 Rejecting initial value:
Chain 3   Log probability evaluates to log(0), i.e. negative infinity.
Chain 3   Stan can't start sampling from this initial value.
Chain 3 Rejecting initial value:
Chain 3   Log probability evaluates to log(0), i.e. negative infinity.
Chain 3   Stan can't start sampling from this initial value.
Chain 3 Rejecting initial value:
Chain 3   Log probability evaluates to log(0), i.e. negative infinity.
Chain 3   Stan can't start sampling from this initial value.
Chain 3 Rejecting initial value:
Chain 3   Log probability evaluates to log(0), i.e. negative infinity.
Chain 3   Stan can't start sampling from this initial value.
Chain 3 Rejecting initial value:
Chain 3   Log probability evaluates to log(0), i.e. negative infinity.
Chain 3   Stan can't start sampling from this initial value.
Chain 3 Rejecting initial value:
Chain 3   Log probability evaluates to log(0), i.e. negative infinity.
Chain 3   Stan can't start sampling from this initial value.
Chain 3 finished in 0.0 seconds.
Chain 4 Rejecting initial value:
Chain 4   Log probability evaluates to log(0), i.e. negative infinity.
Chain 4   Stan can't start sampling from this initial value.
Chain 4 Rejecting initial value:
Chain 4   Log probability evaluates to log(0), i.e. negative infinity.
Chain 4   Stan can't start sampling from this initial value.
Chain 4 Rejecting initial value:
Chain 4   Log probability evaluates to log(0), i.e. negative infinity.
Chain 4   Stan can't start sampling from this initial value.
Chain 4 Rejecting initial value:
Chain 4   Log probability evaluates to log(0), i.e. negative infinity.
Chain 4   Stan can't start sampling from this initial value.
Chain 4 Rejecting initial value:
Chain 4   Log probability evaluates to log(0), i.e. negative infinity.
Chain 4   Stan can't start sampling from this initial value.
Chain 4 Rejecting initial value:
Chain 4   Log probability evaluates to log(0), i.e. negative infinity.
Chain 4   Stan can't start sampling from this initial value.
Chain 4 Rejecting initial value:
Chain 4   Log probability evaluates to log(0), i.e. negative infinity.
Chain 4   Stan can't start sampling from this initial value.
Chain 4 Rejecting initial value:
Chain 4   Log probability evaluates to log(0), i.e. negative infinity.
Chain 4   Stan can't start sampling from this initial value.
Chain 4 Rejecting initial value:
Chain 4   Log probability evaluates to log(0), i.e. negative infinity.
Chain 4   Stan can't start sampling from this initial value.
Chain 4 Rejecting initial value:
Chain 4   Log probability evaluates to log(0), i.e. negative infinity.
Chain 4   Stan can't start sampling from this initial value.
Chain 4 finished in 0.0 seconds.

All 4 chains finished successfully.
Mean chain execution time: 0.3 seconds.
Total execution time: 1.5 seconds.
Warning: 584 of 4000 (15.0%) transitions hit the maximum treedepth limit of 10.
See https://mc-stan.org/misc/warnings for details.
Warning: 2 of 4 chains had an E-BFMI less than 0.2.
See https://mc-stan.org/misc/warnings for details.

We get a lot of warnings:

Chain 4 Rejecting initial value:
Chain 4   Log probability evaluates to log(0), i.e. negative infinity.
Chain 4   Stan can't start sampling from this initial value.

Convergence diagnostics

We check the diagnostics:

fit_pois$diagnostic_summary()
$num_divergent
[1] 0 0 0 0

$num_max_treedepth
[1] 582   0   1   1

$ebfmi
[1] 1.395338019 1.022888262 0.002205932 0.001748789
draws <- as_draws_rvars(fit_pois$draws())
summarize_draws(draws)
variable mean median sd mad q5 q95 rhat ess_bulk ess_tail
lp__ -9.023224e+80 -1.859e+35 1.986335e+81 2.756153e+35 -5.320882e+81 9.98 5.47 5 11
alpha -7.000000e-02 9.000e-02 6.600000e-01 9.100000e-01 -1.080000e+00 0.70 3.86 4 NA
beta -2.000000e-02 0.000e+00 5.000000e-02 3.000000e-02 -1.100000e-01 0.04 3.20 4 11

\(\widehat{R}\) values are large and ESS values are small, indicating bad mixing. Marginal histograms and joint scatterplots of the posterior draws in the figure below clearly show that two chains have been stuck away from two others.

(p=mcmc_pairs(as_draws_array(draws), pars=c("alpha","beta")))

ggsave(p, file='poisson_pairs.pdf', width=6, height=4)

The reason for the issue is that the initial values for beta are sampled from \((-2, 2)\) and x has some large values. If the initial value for beta is higher than about 0.3 or lower than \(-0.4\), some of the values of exp(alpha + beta * x) will overflow to floating point infinity (Inf).

Scaled data

Sometimes an easy option is to change the initialization range. For example, in this the sampling succeeds if the initial values are drawn from the range \((-0.001, 0.001)\). Alternatively we can scale x to have scale close to unit scale. After this scaling, the computation is fast and all convergence diagnostics look good.

data_pois <-list(M = M, N = N, x = x/1e3, y = y)
data.frame(data_pois) |>
  ggplot(aes(x, y)) +
  geom_point(size = 3)

mod_pois <- cmdstan_model(stan_file = code_pois)
fit_pois <- mod_pois$sample(data = data_pois, seed = SEED, refresh = 0)
Running MCMC with 4 sequential chains...

Chain 1 finished in 0.0 seconds.
Chain 2 finished in 0.0 seconds.
Chain 3 finished in 0.0 seconds.
Chain 4 finished in 0.0 seconds.

All 4 chains finished successfully.
Mean chain execution time: 0.0 seconds.
Total execution time: 0.5 seconds.

Convergence diagnostics

We check the diagnostics:

fit_pois$diagnostic_summary()
$num_divergent
[1] 0 0 0 0

$num_max_treedepth
[1] 0 0 0 0

$ebfmi
[1] 1.105842 1.094182 1.073488 1.112763
draws <- as_draws_rvars(fit_pois$draws())
summarize_draws(draws)
variable mean median sd mad q5 q95 rhat ess_bulk ess_tail
lp__ 9.10 9.40 0.97 0.71 7.13 10.02 1.00 1329 1833
alpha -0.05 -0.04 0.26 0.26 -0.48 0.37 1.00 1239 1364
beta 1.01 1.01 0.18 0.18 0.72 1.31 1.01 1225 1473

If the initial value warning comes only once, it is possible that MCMC was able to escape the bad region and rest of the inference is ok.

Thick tailed posterior

We return to the logistic regression example with separable data. Now we use proper, but thick tailed Cauchy prior.

Model

code_logit4 <- root("Problems", "logit_glm4.stan")
writeLines(readLines(code_logit4))
// logistic regression
data {
  int<lower=0> N;
  int<lower=0> M;
  array[N] int<lower=0,upper=1> y;
  matrix[N,M] x;
}
parameters {
  real alpha;
  vector[M] beta;
}
model {
  alpha ~ cauchy(0, 10);
  beta ~ cauchy(0, 10);
  y ~ bernoulli_logit_glm(x, alpha, beta);
}

Sample

mod_logit4 <- cmdstan_model(stan_file = code_logit4)
fit_logit4 <- mod_logit4$sample(data = data_logit, seed = SEED, refresh = 0)
Running MCMC with 4 sequential chains...

Chain 1 finished in 0.0 seconds.
Chain 2 finished in 0.1 seconds.
Chain 3 finished in 0.0 seconds.
Chain 4 finished in 0.0 seconds.

All 4 chains finished successfully.
Mean chain execution time: 0.0 seconds.
Total execution time: 0.5 seconds.

Convergence diagnostics

We check diagnostics

fit_logit4$diagnostic_summary()
$num_divergent
[1] 0 0 0 0

$num_max_treedepth
[1] 0 0 0 0

$ebfmi
[1] 0.4959455 0.2817680 0.4079288 0.7125728
draws <- as_draws_rvars(fit_logit4$draws())
summarize_draws(draws)
variable mean median sd mad q5 q95 rhat ess_bulk ess_tail
lp__ -3.92 -3.26 2.11 1.52 -8.37 -1.93 1.04 122 95
alpha 16.14 10.09 20.49 7.19 3.19 48.79 1.05 100 95
beta 38.68 24.10 48.50 16.89 8.09 119.59 1.04 100 89

The rounded \(\widehat{R}\) values look good, ESS values are low. Looking at the marginal histograms and joint scatterplots of the posterior draws in the following figure show a thick tail.

(p<-mcmc_pairs(as_draws_array(draws), pars=c("alpha","beta")))

ggsave(p, file='thick_tail_pairs.pdf', width=6, height=4)

The dynamic HMC algorithm used by Stan, along with many other MCMC methods, have problems with such thick tails and mixing is slow.

Rank ECDF plot indicates good mixing as all chains have their lines inside the envelope (the envelope assumes no autocorrelation, which is the reason to thin the draws here)

draws |> thin_draws(ndraws(draws)/ess_bulk(draws$alpha)) |>
  mcmc_rank_ecdf(pars=c("alpha"), plot_diff=TRUE)

ggsave(p, file='thick_tail_rank_ecdf_diff.pdf', width=6, height=4)

More iterations confirm a reasonable mixing.

fit_logit4 <- mod_logit4$sample(data = data_logit, seed = SEED, refresh = 0, iter_sampling=4000)
Running MCMC with 4 sequential chains...

Chain 1 finished in 0.1 seconds.
Chain 2 finished in 0.1 seconds.
Chain 3 finished in 0.1 seconds.
Chain 4 finished in 0.1 seconds.

All 4 chains finished successfully.
Mean chain execution time: 0.1 seconds.
Total execution time: 0.8 seconds.
draws <- as_draws_rvars(fit_logit4$draws())
summarize_draws(draws)
# A tibble: 3 × 10
  variable  mean median    sd   mad    q5   q95  rhat ess_bulk ess_tail
  <chr>    <dbl>  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>    <dbl>    <dbl>
1 lp__      -3.8   -3.2   2.0   1.4  -7.9  -1.9   1.0     712.     624.
2 alpha     15.     9.6  24.    6.7   2.7  45.    1.0     649.     577.
3 beta      36.    23.   54.   16.    7.2 104.    1.0     620.     620.
draws |> thin_draws(ndraws(draws)/ess_bulk(draws$alpha)) |>
  mcmc_rank_ecdf(pars=c("alpha"), plot_diff=TRUE)

Variance parameter that is not constrained to be positive

Demonstration what happens if we forget to constrain a parameter that has to be positive. In Stan the constraint can be added when declaring the parameter as real<lower=0> sigma;

Data

We simulated x and y independently from independently from normal(0,1) and normal(0,0.1) respectively. As \(N=8\) is small, there will be a lot of uncertainty about the parameters including the scale sigma.

M=1;
N=8;
set.seed(SEED)
x=matrix(rnorm(N),ncol=M)
y=rnorm(N)/10
data_lin <-list(M = M, N = N, x = x, y = y)

Model

We use linear regression model with proper priors.

code_lin <- root("Problems", "linear_glm.stan")
writeLines(readLines(code_lin))
// logistic regression
data {
  int<lower=0> N;
  int<lower=0> M;
  vector[N] y;
  matrix[N,M] x;
}
parameters {
  real alpha;
  vector[M] beta;
  real sigma;
}
model {
  alpha ~ normal(0, 1);
  beta ~ normal(0, 1);
  sigma ~ normal(0, 1);
  y ~ normal_id_glm(x, alpha, beta, sigma);
}

Sample

mod_lin <- cmdstan_model(stan_file = code_lin)
fit_lin <- mod_lin$sample(data = data_lin, seed = SEED, refresh = 0)
Running MCMC with 4 sequential chains...

Chain 1 finished in 0.0 seconds.
Chain 2 finished in 0.0 seconds.
Chain 3 finished in 0.0 seconds.
Chain 4 finished in 0.0 seconds.

All 4 chains finished successfully.
Mean chain execution time: 0.0 seconds.
Total execution time: 0.5 seconds.

We get many times the following warnings

Chain 4 Informational Message: The current Metropolis proposal is about to be rejected because of the following issue:
Chain 4 Exception: normal_id_glm_lpdf: Scale vector is -0.747476, but must be positive finite! (in '/tmp/RtmprEP4gg/model-7caa12ce8e405.stan', line 16, column 2 to column 43)
Chain 4 If this warning occurs sporadically, such as for highly constrained variable types like covariance matrices, then the sampler is fine,
Chain 4 but if this warning occurs often then your model may be either severely ill-conditioned or misspecified.

Sometimes these warnings appear in early phase of the sampling, even if the model has been correctly defined. Now we have too many of them, which indicates the samples is trying to jump to infeasible values, which here means the negative scale parameter values. Many rejections may lead to biased estimates.

There are some divergences reported, which is also indication that there might be some problem (as divergence diagnostic has an ad hoc diagnostic threshold, there can also be false positive warnings). Other convergence diagnostics are good, but due to many rejection warnings, it is good to check the model code and numerical accuracy of the computations.

Convergence diagnostics

We check diagnostics

fit_lin$diagnostic_summary()
$num_divergent
[1] 0 0 0 3

$num_max_treedepth
[1] 0 0 0 0

$ebfmi
[1] 0.7768720 0.6476284 0.5988158 0.6908439
draws <- as_draws_rvars(fit_lin$draws())
summarize_draws(draws)
variable mean median sd mad q5 q95 rhat ess_bulk ess_tail
lp__ 18.24 18.71 1.83 1.51 14.66 20.22 1.01 912 843
alpha 0.05 0.05 0.03 0.02 0.01 0.10 1.00 1721 1776
beta 0.04 0.04 0.02 0.02 0.00 0.07 1.00 1988 1389
sigma 0.07 0.06 0.03 0.02 0.04 0.12 1.01 1398 1000

Stan compiler pedantic check

Stan compiler pedantic check can recognize that `A normal_id_glm distribution is given parameter sigma as a scale parameter (argument 4), but sigma was not constrained to be strictly positive. The pedantic check is also warning about the very wide priors.

mod_lin$check_syntax(pedantic = TRUE)
Warning in '/home/ave/proj/public_html/casestudies/Problems/linear_glm.stan', line 17, column 36: A
    normal_id_glm distribution is given parameter sigma as a scale parameter
    (argument 4), but sigma was not constrained to be strictly positive.
Stan program is syntactically correct

After fixing the model with proper parameter constraint, MCMC runs without warnings and the sampling efficiency is better. In this specific case, the bias is negligible when running MCMC with the model code without the constraint, but it is difficult to diagnose without running the fixed model.

Fixed model inlcudes <lower=0> constraint for sigma.

code_lin2 <- root("Problems", "linear_glm2.stan")
writeLines(readLines(code_lin2))
// logistic regression
data {
  int<lower=0> N;
  int<lower=0> M;
  vector[N] y;
  matrix[N,M] x;
}
parameters {
  real alpha;
  vector[M] beta;
  real<lower=0> sigma;
}
model {
  alpha ~ normal(0, 1);
  beta ~ normal(0, 1);
  sigma ~ normal(0, 1);
  y ~ normal_id_glm(x, alpha, beta, sigma);
}

Sample

mod_lin2 <- cmdstan_model(stan_file = code_lin2)
fit_lin2 <- mod_lin2$sample(data = data_lin, seed = SEED, refresh = 0)
Running MCMC with 4 sequential chains...

Chain 1 finished in 0.0 seconds.
Chain 2 finished in 0.0 seconds.
Chain 3 finished in 0.0 seconds.
Chain 4 finished in 0.0 seconds.

All 4 chains finished successfully.
Mean chain execution time: 0.0 seconds.
Total execution time: 0.5 seconds.

We check diagnostics

draws2 <- as_draws_rvars(fit_lin2$draws())
summarize_draws(draws2)
variable mean median sd mad q5 q95 rhat ess_bulk ess_tail
lp__ 15.52 15.95 1.61 1.27 12.25 17.21 1 1141 1322
alpha 0.05 0.05 0.03 0.02 0.01 0.10 1 2024 1724
beta 0.04 0.04 0.02 0.02 0.00 0.07 1 2217 2144
sigma 0.07 0.06 0.03 0.02 0.04 0.13 1 1467 1539

In this specific case, the bias is negligible when running MCMC with the model code without the constraint, but it is difficult to diagnose without running the fixed model.

LS0tCnRpdGxlOiAiSWxsdXN0cmF0aW9uIG9mIHNpbXBsZSBwcm9ibGVtYXRpYyBwb3N0ZXJpb3JzIgphdXRob3I6ICJBa2kgVmVodGFyaSIKZGF0ZTogIkZpcnN0IHZlcnNpb24gMjAyMS0wNi0xMC4gTGFzdCBtb2RpZmllZCBgciBmb3JtYXQoU3lzLkRhdGUoKSlgLiIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0aGVtZTogcmVhZGFibGUKICAgIGZvbnQtc2l6ZS1iYXNlOiAxLjVyZW0KICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAyCiAgICBudW1iZXJfc2VjdGlvbnM6IEZBTFNFCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKYmlibGlvZ3JhcGh5OiAuLi9jYXNlc3R1ZGllcy5iaWIKY3NsOiAuLi9oYXJ2YXJkLWNpdGUtdGhlbS1yaWdodC5jc2wKbGluay1jaXRhdGlvbnM6IHllcwotLS0KCgpUaGlzIGNhc2Ugc3R1ZHkgZGVtb25zdHJhdGVzIHVzaW5nIHNpbXBsZSBleGFtcGxlcyB0aGUgbW9zdCBjb21tb24KZmFpbHVyZSBtb2RlcyBpbiBNYXJrb3YgY2hhaW4gTW9udGUgQ2FybG8gYmFzZWQgQmF5ZXNpYW4gaW5mZXJlbmNlLApob3cgdG8gcmVjb2duaXplIHRoZXNlIHVzaW5nIHRoZSBkaWFnbm9zdGljcywgYW5kIGhvdyB0byBmaXggdGhlCnByb2JsZW1zLgoKCmBgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBjb21tZW50PU5BLCBjYWNoZT1GQUxTRSkKYGBgYAoKIyMjIyBMb2FkIHBhY2thZ2VzCgpgYGBge3J9CmxpYnJhcnkoInJwcm9qcm9vdCIpCnJvb3Q8LWhhc19maWxlKCIuY2FzZXN0dWRpZXMtcm9vdCIpJG1ha2VfZml4X2ZpbGUoKQpsaWJyYXJ5KGNtZHN0YW5yKSAKbGlicmFyeShwb3N0ZXJpb3IpCm9wdGlvbnMocGlsbGFyLm5lZyA9IEZBTFNFLCBwaWxsYXIuc3VidGxlPUZBTFNFLCBwaWxsYXIuc2lnZmlnPTIpCmxpYnJhcnkobGVtb24pCmxpYnJhcnkodGlkeXIpIApsaWJyYXJ5KGRwbHlyKSAKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGJheWVzcGxvdCkKdGhlbWVfc2V0KGJheWVzcGxvdDo6dGhlbWVfZGVmYXVsdChiYXNlX2ZhbWlseSA9ICJzYW5zIiwgYmFzZV9zaXplPTE2KSkKc2V0MSA8LSBSQ29sb3JCcmV3ZXI6OmJyZXdlci5wYWwoNywgIlNldDEiKQpTRUVEIDwtIDQ4OTI3ICMgc2V0IHJhbmRvbSBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkKYGBgYAoKCiMjIEltcHJvcGVyIHBvc3RlcmlvcgoKQW4gdW5ib3VuZGVkIGxpa2VsaWhvb2Qgd2l0aG91dCBhIHByb3BlciBwcmlvciBjYW4gbGVhZCB0byBhbgppbXByb3BlciBwb3N0ZXJpb3IuIFdlIHJlY29tbWVuZCB0byBhbHdheXMgdXNlIHByb3BlciBwcmlvcnMKKGludGVncmFsIG92ZXIgYSBwcm9wZXIgZGlzdHJpYnV0aW9uIGlzIGZpbml0ZSkgdG8gZ3VhcmFudGVlIHByb3Blcgpwb3N0ZXJpb3JzLgoKQSBjb21tb25seSB1c2VkIG1vZGVsIHRoYXQgY2FuIGhhdmUgdW5ib3VuZGVkIGxpa2VsaWhvb2QgaXMKbG9naXN0aWMgcmVncmVzc2lvbiB3aXRoIGNvbXBsZXRlIHNlcGFyYXRpb24gaW4gZGF0YS4KCiMjIyBEYXRhCgpVbml2YXJpYXRlIGNvbnRpbm91cyBwcmVkaWN0b3IgJHgkLCBiaW5hcnkgdGFyZ2V0ICR5JCwgYW5kIHRoZSB0d28KY2xhc3NlcyBhcmUgY29tcGxldGVseSBzZXBhcmFibGUsIHdoaWNoIGxlYWRzIHRvIHVuYm91bmRlZApsaWtlbGlob29kLgoKYGBgYHtyfQpzZXQuc2VlZChTRUVEKzQpCk09MTsKTj0xMDsKeD1tYXRyaXgoc29ydChybm9ybShOKSksbmNvbD1NKQp5PXJlcChjKDAsMSksIGVhY2g9Ti8yKQpkYXRhX2xvZ2l0IDwtbGlzdChNID0gTSwgTiA9IE4sIHggPSB4LCB5ID0geSkKZGF0YS5mcmFtZShkYXRhX2xvZ2l0KSB8PgogIGdncGxvdChhZXMoeCwgeSkpICsKICBnZW9tX3BvaW50KHNpemUgPSAzLCBzaGFwZT0xLCBhbHBoYT0wLjYpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPWMoMCwxKSkKZ2dzYXZlKGZpbGU9J3NlcGFyYWJsZV9kYXRhLnBkZicsIHdpZHRoPTQsIGhlaWdodD00KQpgYGBgCgoKIyMjIE1vZGVsCgpXZSB1c2UgdGhlIGZvbGxvd2luZyBTdGFuIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwsIHdoZXJlIHdlIGhhdmUKYGBmb3Jnb3QnJyB0byBpbmNsdWRlIHByaW9yIGZvciB0aGUgY29lZmZpY2llbnQgYGJldGFgLgoKYGBgYHtyfQpjb2RlX2xvZ2l0IDwtIHJvb3QoIlByb2JsZW1zIiwgImxvZ2l0X2dsbS5zdGFuIikKd3JpdGVMaW5lcyhyZWFkTGluZXMoY29kZV9sb2dpdCkpCmBgYGAKClNhbXBsZQoKYGBgYHtyIG1lc3NhZ2U9VFJVRSwgZXJyb3I9VFJVRSwgd2FybmluZz1UUlVFfQptb2RfbG9naXQgPC0gY21kc3Rhbl9tb2RlbChzdGFuX2ZpbGUgPSBjb2RlX2xvZ2l0KQpmaXRfbG9naXQgPC0gbW9kX2xvZ2l0JHNhbXBsZShkYXRhID0gZGF0YV9sb2dpdCwgc2VlZCA9IFNFRUQsIHJlZnJlc2ggPSAwKQpgYGBgCgoKIyMjIENvbnZlcmdlbmNlIGRpYWdub3N0aWNzCgpXaGVuIHJ1bm5pbmcgU3Rhbiwgd2UgZ2V0IHdhcm5pbmdzLiBXZSBjYW4gYWxzbwpleHBsaWNpdGx5IGNoZWNrIHRoZSBpbmZlcmVuY2UgZGlhZ25vc3RpY3M6CgpgYGBge3J9CmZpdF9sb2dpdCRkaWFnbm9zdGljX3N1bW1hcnkoKQpgYGBgCgpXZSBjYW4gYWxzbyBjaGVjayAkXHdpZGVoYXR7Un0kIGVuZCBlZmZlY3RpdmUgc2FtcGxlIHNpemUgKEVTUykgZGlhZ25vc3RpY3MKCmBgYGB7cn0KZHJhd3MgPC0gYXNfZHJhd3NfcnZhcnMoZml0X2xvZ2l0JGRyYXdzKCkpCmBgYGAKYGBgYHtyIHJlbmRlcj1sZW1vbl9wcmludCwgZGlnaXRzPWMoMCwyLDIsMiwyLDIsMiwyLDAsMCl9CnN1bW1hcml6ZV9kcmF3cyhkcmF3cykKYGBgYAoKV2Ugc2VlIHRoYXQgJFx3aWRlaGF0e1J9JCBmb3IgYm90aCBcdGV4dHR0e2FscGhhfSBhbmQgXHRleHR0dHtiZXRhfQphcmUgYWJvdXQgMyBhbmQgQnVsay1FU1MgaXMgYWJvdXQgNCwgd2hpY2ggaW5kaWNhdGUgdGhhdCB0aGUgY2hhaW5zCmFyZSBub3QgbWl4aW5nIGF0IGFsbC4KClRoZSBhYm92ZSBkaWFnbm9zdGljcyByZWZlciB0byBhIGRvY3VtZW50YXRpb24KKFtodHRwczovL21jLXN0YW4ub3JnL21pc2Mvd2FybmluZ3NdKGh0dHBzOi8vbWMtc3Rhbi5vcmcvbWlzYy93YXJuaW5ncykpCnRoYXQgbWVudGlvbnMgcG9zc2liaWxpdHkgdG8gYWRqdXN0IHRoZSBzYW1wbGluZyBhbGdvcml0aG0gb3B0aW9ucwooZS5nLiwgaW5jcmVhc2luZyBgYWRhcHRfZGVsdGFgIGFuZCBgbWF4X3RyZWVkZXB0aGApLCBidXQgaXQgaXMKYmV0dGVyIGZpcnN0IHRvIGludmVzdGlnYXRlIHRoZSBwb3N0ZXJpb3IuCgpUaGUgZm9sbG93aW5nIEZpZ3VyZSBzaG93cyB0aGUgcG9zdGVyaW9yIGRyYXdzIGFzIG1hcmdpbmFsCmhpc3RvZ3JhbXMgYW5kIGpvaW50IHNjYXR0ZXJwbG90cy4gVGhlIHJhbmdlIG9mIHRoZSB2YWx1ZXMgaXMgaHVnZSwKd2hpY2ggaXMgdHlwaWNhbCBmb3IgaW1wcm9wZXIgcG9zdGVyaW9yLCBidXQgdGhlIHZhbHVlcyBvZiBgYWxwaGFgCmFuZCBgYmV0YWAgaW4gYW55IHByYWN0aWNhbCBhcHBsaWNhdGlvbiBhcmUgbGlrZWx5IHRvIGhhdmUgbXVjaApzbWFsbGVyIG1hZ25pdHVkZS4gSW4gdGhpcyBjYXNlLCBpbmNyZWFzaW5nIGBhZGFwdF9kZWx0YWAgYW5kCmBtYXhfdHJlZWRlcHRoYCB3b3VsZCBub3QgaGF2ZSBzb2x2ZWQgdGhlIHByb2JsZW0sIGFuZCB3b3VsZCBoYXZlCmp1c3QgY2F1c2VkIHdhc3RlIG9mIG1vZGVsZXIgYW5kIGNvbXB1dGF0aW9uIHRpbWUuCgoKYGBgYHtyfQoocDwtbWNtY19wYWlycyhhc19kcmF3c19hcnJheShkcmF3cyksIHBhcnM9YygiYWxwaGEiLCJiZXRhIikpKQpnZ3NhdmUocCwgZmlsZT0nc2VwYXJhYmxlX3BhaXJzLnBkZicsIHdpZHRoPTYsIGhlaWdodD00KQpgYGBgCgoKIyMjIFN0YW4gY29tcGlsZXIgcGVkYW50aWMgY2hlY2sKClRoZSBhYm92ZSBkaWFnbm9zdGljcyBhcmUgYXBwbGljYWJsZSB3aXRoIGFueSBwcm9iYWJpbGlzdGljCnByb2dyYW1taW5nIGZyYW1ld29yay4gIFN0YW4gY29tcGlsZXIgY2FuIGFsc28gcmVjb2duaXplIHNvbWUKY29tbW9uIHByb2JsZW1zLiBCeSBkZWZhdWx0IHRoZSBwZWRhbnRpYyBtb2RlIGlzIG5vdCBlbmFibGVkLCBidXQKd2UgY2FuIHVzZSBvcHRpb24gYHBlZGFudGljID0gVFJVRWAgYXQgY29tcGlsYXRpb24gdGltZSwgb3IgYWZ0ZXIKY29tcGlsYXRpb24gd2l0aCB0aGUgYGNoZWNrX3N5bnRheGAgbWV0aG9kLgoKYGBgYHtyIG1lc3NhZ2U9VFJVRSwgZXJyb3I9VFJVRSwgd2FybmluZz1UUlVFfQptb2RfbG9naXQkY2hlY2tfc3ludGF4KHBlZGFudGljID0gVFJVRSkKYGBgYAoKVGhlIHBlZGFudGljIGNoZWNrIGNvcnJlY3RseSB3YXJucyB0aGF0IGBhbHBoYWAgYW5kIGBiZXRhYCBkb24ndApoYXZlIHByaW9ycy4KCiMjIyBBIGZpeGVkIG1vZGVsIHdpdGggcHJvcGVyIHByaW9ycwoKV2UgYWRkIHByb3BlciB3ZWFrIHByaW9ycyBhbmQgcmVydW4gaW5mZXJlbmNlLgoKYGBgYHtyfQpjb2RlX2xvZ2l0MiA8LSByb290KCJQcm9ibGVtcyIsICJsb2dpdF9nbG0yLnN0YW4iKQp3cml0ZUxpbmVzKHJlYWRMaW5lcyhjb2RlX2xvZ2l0MikpCmBgYGAKClNhbXBsZQoKYGBgYHtyIG1lc3NhZ2U9VFJVRSwgZXJyb3I9VFJVRSwgd2FybmluZz1UUlVFfQptb2RfbG9naXQyIDwtIGNtZHN0YW5fbW9kZWwoc3Rhbl9maWxlID0gY29kZV9sb2dpdDIpCmZpdF9sb2dpdDIgPC0gbW9kX2xvZ2l0MiRzYW1wbGUoZGF0YSA9IGRhdGFfbG9naXQsIHNlZWQgPSBTRUVELCByZWZyZXNoID0gMCkKYGBgYAoKCiMjIyBDb252ZXJnZW5jZSBkaWFnbm9zdGljcwoKVGhlcmUgd2VyZSBubyBjb252ZXJnZW5jZSB3YXJuaW5ncy4gV2UgY2FuIGFsc28KZXhwbGljaXRseSBjaGVjayB0aGUgaW5mZXJlbmNlIGRpYWdub3N0aWNzOgoKYGBgYHtyfQpmaXRfbG9naXQyJGRpYWdub3N0aWNfc3VtbWFyeSgpCmBgYGAKCldlIGNoZWNrICRcd2lkZWhhdHtSfSQgZW5kIEVTUyB2YWx1ZXMsIHdoaWNoIGluIHRoaXMgY2FzZSBhbGwgbG9vayBnb29kLgoKYGBgYHtyfQpkcmF3cyA8LSBhc19kcmF3c19ydmFycyhmaXRfbG9naXQyJGRyYXdzKCkpCmBgYGAKYGBgYHtyIHJlbmRlcj1sZW1vbl9wcmludCwgZGlnaXRzPWMoMCwyLDIsMiwyLDIsMiwyLDAsMCl9CnN1bW1hcml6ZV9kcmF3cyhkcmF3cykKYGBgYAoKVGhlIGZvbGxvd2luZyBmaWd1cmUgc2hvd3MgdGhlIG1vcmUgcmVhc29uYWJsZSBtYXJnaW5hbCBoaXN0b2dyYW1zCmFuZCBqb2ludCBzY2F0dGVycGxvdHMgb2YgdGhlIHBvc3RlcmlvciBzYW1wbGUuCgpgYGBge3J9CihwPW1jbWNfcGFpcnMoYXNfZHJhd3NfYXJyYXkoZHJhd3MpLCBwYXJzPWMoImFscGhhIiwiYmV0YSIpKSkKZ2dzYXZlKHAsIGZpbGU9J3NlcGFyYWJsZV9wcmlvcl9wYWlycy5wZGYnLCB3aWR0aD02LCBoZWlnaHQ9NCkKYGBgYAoKCiMjIEEgbW9kZWwgd2l0aCB1bnVzZWQgcGFyYW1ldGVyCgpXaGVuIHdyaXRpbmcgYW5kIGVkaXRpbmcgbW9kZWxzLCBhIGNvbW1vbiBtaXN0YWtlIGlzIHRvIGRlY2xhcmUgYQpwYXJhbWV0ZXIsIGJ1dCBub3QgdXNlIGl0IGluIHRoZSBtb2RlbC4gSWYgdGhlIHBhcmFtZXRlciBpcyBub3QKdXNlZCBhdCBhbGwsIGl0IGRvZXNuJ3QgaGF2ZSBwcm9wZXIgcHJpb3IgYW5kIHRoZSBsaWtlbGlob29kCmRvZXNuJ3QgcHJvdmlkZSBpbmZvcm1hdGlvbiBhYm91dCB0aGF0IHBhcmFtZXRlciwgYW5kIHRodXMgdGhlCnBvc3RlcmlvciBhbG9uZyB0aGF0IHBhcmFtZXRlciBpcyBpbXByb3Blci4gV2UgdXNlIHRoZSBwcmV2aW91cwpsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsIHdpdGggcHJvcGVyIHByaW9ycyBvbiBgYWxwaGFgIGFuZApgYmV0YWAsIGJ1dCBpbmNsdWRlIGV4dHJhIHBhcmFtZXRlciBkZWNsYXJhdGlvbiBgcmVhbApnYW1tYWAuCgojIyMgTW9kZWwKCmBgYGB7cn0KY29kZV9sb2dpdDMgPC0gcm9vdCgiUHJvYmxlbXMiLCAibG9naXRfZ2xtMy5zdGFuIikKd3JpdGVMaW5lcyhyZWFkTGluZXMoY29kZV9sb2dpdDMpKQpgYGBgCgpTYW1wbGUKCmBgYGB7ciBtZXNzYWdlPVRSVUUsIGVycm9yPVRSVUUsIHdhcm5pbmc9VFJVRX0KbW9kX2xvZ2l0MyA8LSBjbWRzdGFuX21vZGVsKHN0YW5fZmlsZSA9IGNvZGVfbG9naXQzKQpmaXRfbG9naXQzIDwtIG1vZF9sb2dpdDMkc2FtcGxlKGRhdGEgPSBkYXRhX2xvZ2l0LCBzZWVkID0gU0VFRCwgcmVmcmVzaCA9IDApCmBgYGAKCgojIyMgQ29udmVyZ2VuY2UgZGlhZ25vc3RpY3MKClRoZXJlIGlzIHNhbXBsZXIgd2FybmluZy4gV2UgY2FuIGFsc28gZXhwbGljaXRseSBjYWxsIGluZmVyZW5jZQpkaWFnbm9zdGljczoKCmBgYGB7cn0KZml0X2xvZ2l0MyRkaWFnbm9zdGljX3N1bW1hcnkoKQpgYGBgCgpJbnN0ZWFkIG9mIGluY3JlYXNpbmcgYG1heF90cmVlZGVwdGhgLCB3ZSBjaGVjayB0aGUgb3RoZXIgY29udmVyZ2VuY2UgZGlhZ25vc3RpY3MuIAoKYGBgYHtyfQpkcmF3cyA8LSBhc19kcmF3c19ydmFycyhmaXRfbG9naXQzJGRyYXdzKCkpCmBgYGAKYGBgYHtyIHJlbmRlcj1sZW1vbl9wcmludCwgZGlnaXRzPWMoMCwyLDIsMiwyLDIsMiwyLDAsMCl9CnN1bW1hcml6ZV9kcmF3cyhkcmF3cykKYGBgYAoKJFx3aWRlaGF0e1J9JCwgQnVsay1FU1MsIGFuZCBUYWlsLUVTUyBsb29rIGdvb2QgZm9yIGBhbHBoYWAgYW5kCmBiZXRhLCBidXQgcmVhbGx5IGJhZCBmb3IgYGdhbW1hYCwgY2xlYXJseSBwb2ludGluZyB3aGVyZSB0byBsb29rCmZvciBwcm9ibGVtcyBpbiB0aGUgbW9kZWwgY29kZS4gVGhlIGhpc3RvZ3JhbSBvZiBgZ2FtbWFgIHBvc3RlcmlvcgpkcmF3cyBzaG93IGh1Z2UgbWFnbml0dWRlIG9mIHZhbHVlcyAodmFsdWVzIGxhcmdlciB0aGFuICQxMF57MjB9JCkKaW5kaWNhdGluZyBpbXByb3BlciBwb3N0ZXJpb3IuCgpgYGBge3J9Cm1jbWNfcGFpcnMoYXNfZHJhd3NfYXJyYXkoZHJhd3MpLCBwYXJzPWMoImFscGhhIiwiYmV0YSIsImdhbW1hIikpCmBgYGAKCk5vbi1taXhpbmcgaXMgd2VsbCBkaWFnbm9zZWQgYnkgJFx3aWRlaGF0e1J9JCBhbmQgRVNTLCBidXQgdGhlCmZvbGxvd2luZyBGaWd1cmUgc2hvd3Mgb25lIG9mIHRoZSByYXJlIGNhc2VzIHdoZXJlIHRyYWNlIHBsb3RzIGFyZQp1c2VmdWwgdG8gaWxsdXN0cmF0ZSB0aGUgdHlwZSBvZiBub24tbWl4aW5nIGluIGNhc2Ugb2YgaW1wcm9wZXIKdW5pZm9ybSBwb3N0ZXJpb3IgZm9yIG9uZSB0aGUgcGFyYW1ldGVycy4KCmBgYGB7cn0KbWNtY190cmFjZShhc19kcmF3c19hcnJheShkcmF3cyksIHBhcnM9YygiZ2FtbWEiKSkKZ2dzYXZlKGZpbGU9J3VudXNlZHBhcmFtX3RyYWNlLnBkZicsIHdpZHRoPTYsIGhlaWdodD00KQpgYGBgCgojIyMgU3RhbiBjb21waWxlciBwZWRhbnRpYyBjaGVjawoKU3RhbiBjb21waWxlciBwZWRhbnRpYyBjaGVjayBhbHNvIHJlY29nbml6ZXMgdGhhdCBwYXJhbWV0ZXIgYGdhbW1hYCB3YXMKZGVjbGFyZWQgYnV0IHdhcyBub3QgdXNlZCBpbiB0aGUgZGVuc2l0eSBjYWxjdWxhdGlvbi4KCmBgYGB7ciBtZXNzYWdlPVRSVUUsIGVycm9yPVRSVUUsIHdhcm5pbmc9VFJVRX0KbW9kX2xvZ2l0MyRjaGVja19zeW50YXgocGVkYW50aWMgPSBUUlVFKQpgYGBgCgoKIyMgQSBwb3N0ZXJpb3Igd2l0aCB0d28gcGFyYW1ldGVycyBjb21wZXRpbmcKClNvbWV0aW1lcyB0aGUgbW9kZWxzIGhhdmUgdHdvIG9yIG1vcmUgcGFyYW1ldGVycyB0aGF0IGhhdmUgc2ltaWxhcgpvciBleGFjdGx5IHRoZSBzYW1lIHJvbGUuIFdlIGlsbHVzdHJhdGUgdGhpcyBieSBhZGRpbmcgYW4gZXh0cmEKY29sdW1uIHRvIHRoZSBwcmV2aW91cyBkYXRhIG1hdHJpeC4gU29tZXRpbWVzIHRoZSBkYXRhIG1hdHJpeCBpcwphdWdtZW50ZWQgd2l0aCBhIGNvbHVtbiBvZiAx4oCZcyB0byBwcmVzZW50IHRoZSBpbnRlcmNlcHQgZWZmZWN0LiBJbgp0aGlzIGNhc2UgdGhhdCBpcyByZWR1bmRhbnQgYXMgb3VyIG1vZGVsIGhhcyB0aGUgZXhwbGljaXQgaW50ZXJjZXB0CnRlcm0gYGFscGhhYCwgYW5kIHRoaXMgcmVkdW5kYW5jeSB3aWxsIGxlYWQgdG8gcHJvYmxlbXMuCgojIyMgRGF0YQoKYGBgYHtyfQpNPTI7Ck49MTAwMDsKeD1tYXRyaXgoYyhyZXAoMSxOKSxzb3J0KHJub3JtKE4pKSksbmNvbD1NKQp5PSgoeFssMV0rcm5vcm0oTikvMik+MCkrMApkYXRhX2xvZ2l0NCA8LWxpc3QoTSA9IE0sIE4gPSBOLCB4ID0geCwgeSA9IHkpCmBgYGAKCgojIyMgTW9kZWwKCldlIHVzZSB0aGUgcHJldmlvdXMgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbCB3aXRoIHByb3BlciBwcmlvcnMKKGFuZCBubyBleHRyYSBgZ2FtbWFgKS4KCgpgYGBge3J9CmNvZGVfbG9naXQyIDwtIHJvb3QoIlByb2JsZW1zIiwgImxvZ2l0X2dsbTIuc3RhbiIpCndyaXRlTGluZXMocmVhZExpbmVzKGNvZGVfbG9naXQyKSkKYGBgYAoKU2FtcGxlCgpgYGBge3IgbWVzc2FnZT1UUlVFLCBlcnJvcj1UUlVFLCB3YXJuaW5nPVRSVUV9Cm1vZF9sb2dpdDQgPC0gY21kc3Rhbl9tb2RlbChzdGFuX2ZpbGUgPSBjb2RlX2xvZ2l0MikKZml0X2xvZ2l0NCA8LSBtb2RfbG9naXQ0JHNhbXBsZShkYXRhID0gZGF0YV9sb2dpdDQsIHNlZWQgPSBTRUVELCByZWZyZXNoID0gMCkKYGBgYAoKClRoZSBTdGFuIHNhbXBsaW5nIHRpbWUgcGVyIGNoYWluIHdpdGggdGhlIG9yaWdpbmFsIGRhdGEgbWF0cml4IHdhcwpsZXNzIHRoYW4gMC4xcyBwZXIgY2hhaW4uIE5vdyB0aGUgU3RhbiBzYW1wbGluZyB0aW1lIHBlciBjaGFpbiBpcwpzZXZlcmFsIHNlY29uZHMsIHdoaWNoIGlzIHN1c3BpY2lvdXMuIFRoZXJlIGFyZSBubyBhdXRvbWF0aWMKY29udmVyZ2VuY2UgZGlhZ25vc3RpYyB3YXJuaW5ncyBhbmQgY2hlY2tpbmcgb3RoZXIgZGlhZ25vc3RpY3MKZG9uJ3Qgc2hvdyBhbnl0aGluZyByZWFsbHkgYmFkLgoKIyMjIENvbnZlcmdlbmNlIGRpYWdub3N0aWNzCgpgYGBge3J9CmZpdF9sb2dpdDQkZGlhZ25vc3RpY19zdW1tYXJ5KCkKCmRyYXdzIDwtIGFzX2RyYXdzX3J2YXJzKGZpdF9sb2dpdDQkZHJhd3MoKSkKYGBgYApgYGBge3IgcmVuZGVyPWxlbW9uX3ByaW50LCBkaWdpdHM9YygwLDIsMiwyLDIsMiwyLDIsMCwwKX0Kc3VtbWFyaXplX2RyYXdzKGRyYXdzKQpgYGBgCgpFU1MgZXN0aW1hdGVzIGFyZSBhYm92ZSB0aGUgcmVjb21tZW5kZWQgZGlhZ25vc3RpYyB0aHJlc2hvbGRzLCBidXQKbG93ZXIgdGhhbiB3aGF0IHdlIHdvdWxkIGV4cGVjdCBpbiBnZW5lcmFsIGZyb20gU3RhbiBmb3Igc3VjaCBhCmxvd2VyIGRpbWVuc2lvbmFsIHByb2JsZW0uCgpUaGUgZm9sbG93aW5nIGZpZ3VyZSBzaG93cyBtYXJnaW5hbCBoaXN0b2dyYW1zIGFuZCBqb2ludApzY2F0dGVycGxvdHMsIGFuZCB3ZSBjYW4gc2VlIHRoYXQgYGFscGhhYCBhbmQgYGJldGFbMV1gIGFyZSBoaWdobHkKY29ycmVsYXRlZC4gCgpgYGBge3J9CihwPW1jbWNfcGFpcnMoYXNfZHJhd3NfYXJyYXkoZHJhd3MpLCBwYXJzPWMoImFscGhhIiwiYmV0YVsxXSIsImJldGFbMl0iKSkpCmdnc2F2ZShwLCBmaWxlPSdjb21wZXRpbmdfcGFyYW1zX3BhaXJzLnBkZicsIHdpZHRoPTYsIGhlaWdodD00KQpgYGBgCgpXZSBjYW4gY29tcHV0ZSB0aGUgY29ycmVsYXRpb24uCgpgYGBge3J9CmNvcihhc19kcmF3c19tYXRyaXgoZHJhd3MpWyxjKCJhbHBoYSIsImJldGFbMV0iKV0pWzEsMl0KYGBgYAoKVGhlIG51bWVyaWNhbCB2YWx1ZSBmb3IgdGhlIGNvcnJlbGF0aW9uIGlzICQtMC45OTkkLiBUaGUKY29ycmVsYXRpb24gY2xvc2UgdG8gMSBjYW4gaGFwcGVuIGFsc28gZnJvbSBvdGhlciByZWFzb25zIChzZWUgdGhlCm5leHQgZXhhbXBsZSksIGJ1dCBvbmUgcG9zc2liaWxpdHkgaXMgdGhhdCBwYXJhbWV0ZXJzIGhhdmUgc2ltaWxhcgpyb2xlIGluIHRoZSBtb2RlbC4gSGVyZSB0aGUgcmVhc29uIGlzIHRoZSBjb25zdGFudCBjb2x1bW4gaW4gJHgkLAp3aGljaCB3ZSBwdXQgdGhlcmUgZm9yIHRoZSBkZW1vbnN0cmF0aW9uIHB1cnBvc2VzLiBXZSBtYXkgYSBoYXZlCmNvbnN0YW50IGNvbHVtbiwgZm9yIGV4YW1wbGUsIGlmIHRoZSBwcmVkaWN0b3IgbWF0cml4IGlzIGF1Z21lbnRlZAp3aXRoIHRoZSBpbnRlcmNlcHQgcHJlZGljdG9yLCBvciBpZiB0aGUgb2JzZXJ2ZWQgZGF0YSBvciBzdWJkYXRhCnVzZWQgaW4gdGhlIHNwZWNpZmljIGFuYWx5c2lzIGhhcHBlbnMgdG8gaGF2ZSBvbmx5IG9uZSB1bmlxdWUKdmFsdWUuCgojIyMgU3RhbiBjb21waWxlciBwZWRhbnRpYyBjaGVjawoKU3RhbiBjb21waWxlciBwZWRhbnRpYyBjaGVjayBleGFtaW5pbmcgdGhlIGNvZGUgY2Fu4oCZdApyZWNvZ25pemUgdGhpcyBpc3N1ZSwgYXMgdGhlIHByb2JsZW0gZGVwZW5kcyBhbHNvIG9uIHRoZSBkYXRhLgoKYGBgYHtyIG1lc3NhZ2U9VFJVRSwgZXJyb3I9VFJVRSwgd2FybmluZz1UUlVFfQptb2RfbG9naXQ0JGNoZWNrX3N5bnRheChwZWRhbnRpYyA9IFRSVUUpCmBgYGAKCgojIyBBIHBvc3RlcmlvciB3aXRoIHZlcnkgaGlnaCBjb3JyZWxhdGlvbgoKSW4gdGhlIHByZXZpb3VzIGV4YW1wbGUgdGhlIHR3byBwYXJhbWV0ZXJzIGhhZCB0aGUgc2FtZSByb2xlIGluIHRoZQptb2RlbCwgbGVhZGluZyB0byBoaWdoIHBvc3RlcmlvciBjb3JyZWxhdGlvbi4gSGlnaCBwb3N0ZXJpb3IKY29ycmVsYXRpb25zIGFyZSBjb21tb24gYWxzbyBpbiBsaW5lYXIgbW9kZWxzIHdoZW4gdGhlIHByZWRpY3Rvcgp2YWx1ZXMgYXJlIGZhciBmcm9tIDAuIFdlIGlsbHVzdHJhdGUgdGhpcyB3aXRoIGEgbGluZWFyIHJlZ3Jlc3Npb24KbW9kZWwgZm9yIHRoZSBzdW1tZXIgdGVtcGVyYXR1cmUgaW4gS2lscGlzasOkcnZpLCBGaW5sYW5kLAoxOTUyLS0yMDEzLiBXZSB1c2UgdGhlIHllYXIgYXMgdGhlIGNvdmFyaWF0ZSAkeCQgd2l0aG91dCBjZW50ZXJpbmcKaXQuCgojIyMgRGF0YQoKVGhlIGRhdGEgYXJlIEtpbHBpc2rDpHJ2aSBzdW1tZXIgbW9udGggdGVtcGVyYXR1cmVzIDE5NTItMjAxMy4KCmBgYGB7cn0KZGF0YV9raWxwaXMgPC0gcmVhZC5kZWxpbShyb290KCJQcm9ibGVtcyIsImtpbHBpc2phcnZpLXN1bW1lci10ZW1wLmNzdiIpLCBzZXAgPSAiOyIpCmRhdGFfbGluIDwtbGlzdChNPTEsCiAgICAgICAgICAgICAgICBOID0gbnJvdyhkYXRhX2tpbHBpcyksCiAgICAgICAgICAgICAgICB4ID0gbWF0cml4KGRhdGFfa2lscGlzJHllYXIsIG5jb2w9MSksCiAgICAgICAgICAgICAgICB5ID0gZGF0YV9raWxwaXNbLDVdKQoKZGF0YS5mcmFtZShkYXRhX2xpbikgfD4KICBnZ3Bsb3QoYWVzKHgsIHkpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMSkgKwogIGxhYnMoeSA9ICdTdW1tZXIgdGVtcC4gQEtpbHBpc2rDpHJ2aScsIHg9ICJZZWFyIikgKwogIGd1aWRlcyhsaW5ldHlwZSA9ICJub25lIikKZ2dzYXZlKGZpbGU9J0tpbHBpc2phcnZpX2RhdGEucGRmJywgd2lkdGg9NiwgaGVpZ2h0PTQpCmBgYGAKCiMjIyBNb2RlbAoKV2UgdXNlIHRoZSBmb2xsb3dpbmcgU3RhbiBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbAoKYGBgYHtyfQpjb2RlX2xpbiA8LSByb290KCJQcm9ibGVtcyIsICJsaW5lYXJfZ2xtX2tpbHBpcy5zdGFuIikKd3JpdGVMaW5lcyhyZWFkTGluZXMoY29kZV9saW4pKQoKYGBgYApgYGBge3IgbWVzc2FnZT1UUlVFLCBlcnJvcj1UUlVFLCB3YXJuaW5nPVRSVUV9Cm1vZF9saW4gPC0gY21kc3Rhbl9tb2RlbChzdGFuX2ZpbGUgPSBjb2RlX2xpbikKZml0X2xpbiA8LSBtb2RfbGluJHNhbXBsZShkYXRhID0gZGF0YV9saW4sIHNlZWQgPSBTRUVELCByZWZyZXNoID0gMCkKYGBgYAoKIyMjIENvbnZlcmdlbmNlIGRpYWdub3N0aWNzCgpTdGFuIGdpdmVzIGEgd2FybmluZzogVGhlcmUgd2VyZSBYIHRyYW5zaXRpb25zIGFmdGVyIHdhcm11cCB0aGF0CmV4Y2VlZGVkIHRoZSBtYXhpbXVtIHRyZWVkZXB0aC4gQXMgaW4gdGhlIHByZXZpb3VzIGV4YW1wbGUsIHRoZXJlCmFyZSBubyBvdGhlciB3YXJuaW5ncy4KCmBgYGB7cn0KZml0X2xpbiRkaWFnbm9zdGljX3N1bW1hcnkoKQoKZHJhd3MgPC0gYXNfZHJhd3NfcnZhcnMoZml0X2xpbiRkcmF3cygpKQpgYGBgCmBgYGB7ciByZW5kZXI9bGVtb25fcHJpbnQsIGRpZ2l0cz1jKDAsMiwyLDIsMiwyLDIsMiwwLDApfQpzdW1tYXJpemVfZHJhd3MoZHJhd3MpCmBgYGAKCkVTUyBlc3RpbWF0ZXMgYXJlIGFib3ZlIHRoZSBkaWFnbm9zdGljIHRocmVzaG9sZCwgYnV0IGxvd2VyIHRoYW4gd2UKd291bGQgZXhwZWN0IGZvciBzdWNoIGEgbG93IGRpbWVuc2lvbmFsIG1vZGVsLCB1bmxlc3MgdGhlcmUgYXJlCnN0cm9uZyBwb3N0ZXJpb3IgY29ycmVsYXRpb25zLiBUaGUgZm9sbG93aW5nIEZpZ3VyZSBzaG93cyB0aGUKbWFyZ2luYWwgaGlzdG9ncmFtcyBhbmQgam9pbnQgc2NhdHRlcnBsb3QgZm9yIGBhbHBoYWAgYW5kCmBiZXRhWzFdYCwgd2hpY2ggc2hvd3MgdGhleSBhcmUgdmVyeSBoaWdobHkgY29ycmVsYXRlZC4KCmBgYGB7cn0KbWNtY19wYWlycyhhc19kcmF3c19hcnJheShkcmF3cyksIHBhcnM9YygiYWxwaGEiLCJiZXRhIikpCmdnc2F2ZShwLCBmaWxlPSdjb3JyZWxhdGluZ19wYXJhbXNfcGFpcnMucGRmJywgd2lkdGg9NiwgaGVpZ2h0PTQpCmBgYGAKCkhlcmUgdGhlIHJlYXNvbiBpcyB0aGF0IHRoZSAkeCQgdmFsdWVzIGFyZSBpbiB0aGUgcmFuZ2UgMTk1Mi0tMjAxMywKYW5kIHRoZSBpbnRlcmNlcHQgYGFscGhhYCBkZW5vdGVzIHRoZSB0ZW1wZXJhdHVyZSBhdCB5ZWFyIDAsIHdoaWNoCmlzIHZlcnkgZmFyIGF3YXkgZnJvbSB0aGUgcmFuZ2Ugb2Ygb2JzZXJ2ZWQgJHgkLiBJZiB0aGUgaW50ZXJjZXB0CmBhbHBoYWAgY2hhbmdlcywgdGhlIHNsb3BlIGBiZXRhYCBuZWVkcyB0byBjaGFuZ2UgdG9vLiBUaGUgaGlnaApjb3JyZWxhdGlvbiBtYWtlcyB0aGUgaW5mZXJlbmNlIHNsb3dlciwgYW5kIHdlIGNhbiBtYWtlIGl0IGZhc3RlcgpieSBjZW50ZXJpbmcgJHgkLiBIZXJlIHdlIHNpbXBseSBzdWJ0cmFjdCAxOTgyLjUgZnJvbSB0aGUgcHJlZGljdG9yCmB5ZWFyYCwgc28gdGhhdCB0aGUgbWVhbiBvZiAkeCQgaXMgMC4gV2UgY291bGQgYWxzbyBpbmNsdWRlIHRoZQpjZW50ZXJpbmcgYW5kIGJhY2sgdHJhbnNmb3JtYXRpb24gdG8gU3RhbiBjb2RlLgoKIyMjIENlbnRlcmVkIGRhdGEKCgpgYGBge3J9CmRhdGFfbGluIDwtbGlzdChNPTEsCiAgICAgICAgICAgICAgICBOID0gbnJvdyhkYXRhX2tpbHBpcyksCiAgICAgICAgICAgICAgICB4ID0gbWF0cml4KGRhdGFfa2lscGlzJHllYXItMTk4Mi41LCBuY29sPTEpLAogICAgICAgICAgICAgICAgeSA9IGRhdGFfa2lscGlzWyw1XSkKCmBgYGAKYGBgYHtyIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpmaXRfbGluIDwtIG1vZF9saW4kc2FtcGxlKGRhdGEgPSBkYXRhX2xpbiwgc2VlZCA9IFNFRUQsIHJlZnJlc2ggPSAwKQpgYGBgCgojIyMgQ29udmVyZ2VuY2UgZGlhZ25vc3RpY3MKCldlIGNoZWNrIHRoZSBkaWFnbm9zdGljcwoKYGBgYHtyfQpmaXRfbGluJGRpYWdub3N0aWNfc3VtbWFyeSgpCmRyYXdzIDwtIGFzX2RyYXdzX3J2YXJzKGZpdF9saW4kZHJhd3MoKSkKYGBgYApgYGBge3IgcmVuZGVyPWxlbW9uX3ByaW50LCBkaWdpdHM9YygwLDIsMiwyLDIsMiwyLDIsMCwwKX0Kc3VtbWFyaXplX2RyYXdzKGRyYXdzKQpgYGBgCgpUaGUgZm9sbG93aW5nIGZpZ3VyZSBzaG93cyB0aGUgc2NhdHRlciBwbG90LgoKYGBgYHtyfQptY21jX3BhaXJzKGFzX2RyYXdzX2FycmF5KGRyYXdzKSwgcGFycz1jKCJhbHBoYSIsImJldGEiKSkKYGBgYAoKCldpdGggdGhpcyBjaGFuZ2UsIHRoZXJlIGlzIG5vIHBvc3RlcmlvciBjb3JyZWxhdGlvbiwgQnVsay1FU1MKZXN0aW1hdGVzIGFyZSAzIHRpbWVzIGJpZ2dlciwgYW5kIHRoZSBtZWFuIHRpbWUgcGVyIGNoYWluIGdvZXMgZnJvbQoxLjNzIHRvIGxlc3MgdGhhbiAwLjA1czsgdGhhdCBpcywgd2UgZ2V0IDIgb3JkZXJzIG9mIG1hZ25pdHVkZQpmYXN0ZXIgaW5mZXJlbmNlLiBJbiBhIGJpZ2dlciBwcm9ibGVtcyB0aGlzIGNvdWxkIGNvcnJlc3BvbmQgdG8KcmVkdWN0aW9uIG9mIGNvbXB1dGF0aW9uIHRpbWUgZnJvbSAyNCBob3VycyB0byBsZXNzIHRoYW4gMjAKbWludXRlcy4KCgojIyBBIGJpbW9kYWwgcG9zdGVyaW9yCgpCaW1vZGFsIGRpc3RyaWJ1dGlvbnMgY2FuIGFyaXNlIGZyb20gbWFueSByZWFzb25zIGFzIGluIG1peHR1cmUKbW9kZWxzIG9yIG1vZGVscyB3aXRoIG5vbi1sb2ctY29uY2F2ZSBsaWtlbGlob29kcyBvciBwcmlvcnMgKHRoYXQKaXMsIHdpdGggZGlzdHJpYnV0aW9ucyB3aXRoIHRoaWNrIHRhaWxzKS4gV2UgaWxsdXN0cmF0ZSB0aGUKZGlhZ25vc3RpY3MgcmV2ZWFsaW5nIHRoZSBtdWx0aW1vZGFsIHBvc3Rlcmlvci4gV2UgdXNlIGEgc2ltcGxlIHRveQpwcm9ibGVtIHdpdGggJHQkIG1vZGVsIGFuZCBkYXRhIHRoYXQgaXMgbm90IGZyb20gYSAkdCQKZGlzdHJpYnV0aW9uLCBidXQgZnJvbSBhIG1peHR1cmUgb2YgdHdvIG5vcm1hbCBkaXN0cmlidXRpb25zCgojIyMgRGF0YQoKQmltb2RhbGx5IGRpc3RyaWJ1dGVkIGRhdGEKCmBgYGB7cn0KTj0yMAp5PWMocm5vcm0oTi8yLCBtZWFuPS01LCBzZD0xKSxybm9ybShOLzIsIG1lYW49NSwgc2Q9MSkpOwpkYXRhX3R0IDwtbGlzdChOID0gTiwgeSA9IHkpCmBgYGAKCiMjIyBNb2RlbAoKVW5pbW9kYWwgU3R1ZGVudCdzICR0JCBtb2RlbDoKCmBgYGB7cn0KY29kZV90dCA8LSByb290KCJQcm9ibGVtcyIsICJzdHVkZW50LnN0YW4iKQp3cml0ZUxpbmVzKHJlYWRMaW5lcyhjb2RlX3R0KSkKYGBgYAoKU2FtcGxlCgpgYGBge3IgbWVzc2FnZT1UUlVFLCBlcnJvcj1UUlVFLCB3YXJuaW5nPVRSVUV9Cm1vZF90dCA8LSBjbWRzdGFuX21vZGVsKHN0YW5fZmlsZSA9IGNvZGVfdHQpCmZpdF90dCA8LSBtb2RfdHQkc2FtcGxlKGRhdGEgPSBkYXRhX3R0LCBzZWVkID0gU0VFRCwgcmVmcmVzaCA9IDApCmBgYGAKCiMjIyBDb252ZXJnZW5jZSBkaWFnbm9zdGljcwoKV2UgY2hlY2sgdGhlIGRpYWdub3N0aWNzCgpgYGBge3J9CmZpdF90dCRkaWFnbm9zdGljX3N1bW1hcnkoKQpkcmF3cyA8LSBhc19kcmF3c19ydmFycyhmaXRfdHQkZHJhd3MoKSkKYGBgYApgYGBge3IgcmVuZGVyPWxlbW9uX3ByaW50LCBkaWdpdHM9YygwLDIsMiwyLDIsMiwyLDIsMCwwKX0Kc3VtbWFyaXplX2RyYXdzKGRyYXdzKQpgYGBgCgpUaGUgJFx3aWRlaGF0e1J9JCB2YWx1ZXMgZm9yIGBtdWAgYXJlIGxhcmdlIGFuZCBFU1MgdmFsdWVzIGZvciBgbXVgCmFyZSBzbWFsbCBpbmRpY2F0aW5nIGNvbnZlcmdlbmNlIHByb2JsZW1zLiBUaGUgZm9sbG93aW5nIGZpZ3VyZQpzaG93cyB0aGUgaGlzdG9ncmFtIGFuZCB0cmFjZSBwbG90cyBvZiB0aGUgcG9zdGVyaW9yIGRyYXdzLCBjbGVhcmx5CnNob3dpbmcgdGhlIGJpbW9kYWxpdHkgYW5kIHRoYXQgY2hhaW5zIGFyZSBub3QgbWl4aW5nIGJldHdlZW4gdGhlCm1vZGVzLgoKCmBgYGB7cn0KbWNtY19oaXN0KGFzX2RyYXdzX2FycmF5KGRyYXdzKSwgcGFycz1jKCJtdSIpKQpnZ3NhdmUoZmlsZT0nYmltb2RhbDFfaGlzdC5wZGYnLCB3aWR0aD00LCBoZWlnaHQ9NCkKYGBgYAoKSW4gdGhpcyB0b3kgZXhhbXBsZSwgd2l0aCByYW5kb20gaW5pdGlhbGl6YXRpb24gZWFjaCBjaGFpbnMgaGFzCjUwXCUgcHJvYmFiaWxpdHkgb2YgZW5kaW5nIGluIGVpdGhlciBtb2RlLiBXZSB1c2VkIFN0YW4ncyBkZWZhdWx0Cm9mIDQgY2hhaW5zLCBhbmQgd2hlbiByYW5kb20gaW5pdGlhbGl6YXRpb24gaXMgdXNlZCwgdGhlcmUgaXMgNlwlCmNoYW5jZSB0aGF0IHdoZW4gcnVubmluZyBTdGFuIG9uY2UsIHdlIHdvdWxkIG1pc3MgdGhlCm11bHRpbW9kYWxpdHkuIElmIHRoZSBhdHRyYWN0aW9uIGFyZWFzIHdpdGhpbiB0aGUgcmFuZG9tCmluaXRpYWxpemF0aW9uIHJhbmdlIGFyZSBub3QgZXF1YWwsIHRoZSBwcm9iYWJpbGl0eSBvZiBtaXNzaW5nIG9uZQptb2RlIGlzIGV2ZW4gaGlnaGVyLiBUaGVyZSBpcyBhIHRyYWRlb2ZmIGJldHdlZW4gdGhlIGRlZmF1bHQKY29tcHV0YXRpb24gY29zdCBhbmQgY29zdCBvZiBoYXZpbmcgaGlnaGVyIHByb2JhYmlsaXR5IG9mIGZpbmRpbmcKbXVsdGlwbGUgbW9kZXMuIElmIHRoZXJlIGlzIGEgcmVhc29uIHRvIHN1c3BlY3QgbXVsdGltb2RhbGl0eSwgaXQKaXMgdXNlZnVsIHRvIHJ1biBtb3JlIGNoYWlucy4gUnVubmluZyBtb3JlIGNoYWlucyBoZWxwcyB0byBkaWFnbm9zZQp0aGUgbXVsdGltb2RhbGl0eSwgYnV0IHRoZSBwcm9iYWJpbGl0eSBvZiBjaGFpbnMgZW5kaW5nIGluCmRpZmZlcmVudCBtb2RlcyBjYW4gYmUgZGlmZmVyZW50IGZyb20gdGhlIHJlbGF0aXZlIHByb2JhYmlsaXR5IG1hc3MKb2YgZWFjaCBtb2RlLCBhbmQgcnVubmluZyBtb3JlIGNoYWlucyBkb2Vzbid0IGZpeCB0aGlzLiBPdGhlciBtZWFucwphcmUgbmVlZGVkIHRvIGltcHJvdmUgbWl4aW5nIGJldHdlZW4gdGhlIG1vZGVzIChlLmcuIFlhbyBldCBhbC4sCjIwMjApIG9yIHRvIGFwcHJveGltYXRlbHkgd2VpZ2h0IHRoZSBjaGFpbnMgKGUuZy4gWWFvIGV0IGFsLiwKMjAyMikuCgojIyBFYXN5IGJpbW9kYWwgcG9zdGVyaW9yCgpJZiB0aGUgbW9kZXMgaW4gdGhlIGJpbW9kYWwgZGlzdHJpYnV0aW9uIGFyZSBub3Qgc3Ryb25nbHkKc2VwYXJhdGVkLCBNQ01DIGNhbiBqdW1wIGZyb20gb25lIG1vZGUgdG8gYW5vdGhlciBhbmQgdGhlcmUgYXJlIG5vCmNvbnZlcmdlbmNlIGlzc3Vlcy4KCmBgYGB7cn0KTj0yMAp5PWMocm5vcm0oTi8yLCBtZWFuPS0zLCBzZD0xKSxybm9ybShOLzIsIG1lYW49Mywgc2Q9MSkpOwpkYXRhX3R0IDwtbGlzdChOID0gTiwgeSA9IHkpCgpgYGBgCmBgYGB7ciBtZXNzYWdlPVRSVUUsIGVycm9yPVRSVUUsIHdhcm5pbmc9VFJVRX0KZml0X3R0IDwtIG1vZF90dCRzYW1wbGUoZGF0YSA9IGRhdGFfdHQsIHNlZWQgPSBTRUVELCByZWZyZXNoID0gMCkKYGBgYAoKIyMjIENvbnZlcmdlbmNlIGRpYWdub3N0aWNzCgpXZSBjaGVjayB0aGUgZGlhZ25vc3RpY3MKCmBgYGB7cn0KZml0X3R0JGRpYWdub3N0aWNfc3VtbWFyeSgpCmRyYXdzIDwtIGFzX2RyYXdzX3J2YXJzKGZpdF90dCRkcmF3cygpKQpgYGBgCmBgYGB7ciByZW5kZXI9bGVtb25fcHJpbnQsIGRpZ2l0cz1jKDAsMiwyLDIsMiwyLDIsMiwwLDApfQpzdW1tYXJpemVfZHJhd3MoZHJhd3MpCmBgYGAKClR3byBtb2RlcyBhcmUgdmlzaWJsZS4KCmBgYGB7cn0KbWNtY19oaXN0KGFzX2RyYXdzX2FycmF5KGRyYXdzKSwgcGFycz1jKCJtdSIpKQpnZ3NhdmUoZmlsZT0nYmltb2RhbDJfaGlzdC5wZGYnLCB3aWR0aD00LCBoZWlnaHQ9NCkKYGBgYAoKVHJhY2UgcGxvdCBpcyBub3QgdmVyeSB1c2VmdWwuIEl0IHNob3dzIHRoZSBjaGFpbnMgYXJlIGp1bXBpbmcKYmV0d2VlbiBtb2RlcywgYnV0IGl0J3MgZGlmZmljdWx0IHRvIHNlZSB3aGV0aGVyIHRoZSBqdW1wcyBoYXBwZW4Kb2Z0ZW4gZW5vdWdoIGFuZCBjaGFpbnMgYXJlIG1peGluZyB3ZWxsLgoKYGBgYHtyfQptY21jX3RyYWNlKGFzX2RyYXdzX2FycmF5KGRyYXdzKSwgcGFycz1jKCJtdSIpKQpnZ3NhdmUoZmlsZT0nYmltb2RhbDJfdHJhY2UucGRmJywgd2lkdGg9NCwgaGVpZ2h0PTQpCmBgYGAKClJhbmsgRUNERiBwbG90IGluZGljYXRlcyBnb29kIG1peGluZyBhcyBhbGwgY2hhaW5zIGhhdmUgdGhlaXIgbGluZXMKaW5zaWRlIHRoZSBlbnZlbG9wZSAodGhlIGVudmVsb3BlIGFzc3VtZXMgbm8gYXV0b2NvcnJlbGF0aW9uLCB3aGljaAppcyB0aGUgcmVhc29uIHRvIHRoaW4gdGhlIGRyYXdzIGhlcmUpCgpgYGBge3J9CmRyYXdzIHw+IHRoaW5fZHJhd3MobmRyYXdzKGRyYXdzKS9lc3NfYmFzaWMoZHJhd3MkbXUpKSB8PgogIG1jbWNfcmFua19lY2RmKHBhcnM9YygibXUiKSwgcGxvdF9kaWZmPVRSVUUpCmdnc2F2ZShmaWxlPSdiaW1vZGFsMl9yYW5rX2VjZGZfZGlmZi5wZGYnLCB3aWR0aD00LCBoZWlnaHQ9NCkKYGBgYAoKIyMgSW5pdGlhbCB2YWx1ZSBpc3N1ZXMKCk1DTUMgcmVxdWlyZXMgc29tZSBpbml0aWFsIHZhbHVlcy4gQnkgZGVmYXVsdCwgU3RhbiBnZW5lcmF0ZXMgdGhlbQpyYW5kb21seSBmcm9tIFstMiwyXSBpbiB1bmNvbnN0cmFpbmVkIHNwYWNlIChjb25zdHJhaW50cyBvbgpwYXJhbWV0ZXJzIGFyZSBhY2hpZXZlZCBieSB0cmFuc2Zvcm1hdGlvbnMpLiBTb21ldGltZXMgdGhlc2UKaW5pdGlhbCB2YWx1ZXMgY2FuIGJlIGJhZCBhbmQgY2F1c2UgbnVtZXJpY2FsIGlzc3Vlcy4gQ29tcHV0ZXJzLAooaW4gZ2VuZXJhbCkgdXNlIGZpbml0ZSBudW1iZXIgb2YgYml0cyB0byBwcmVzZW50IG51bWJlcnMgYW5kIHdpdGgKdmVyeSBzbWFsbCBvciBsYXJnZSBudW1iZXJzLCB0aGVyZSBjYW4gYmUgcHJvYmxlbXMgb2YgcHJlc2VudGluZwp0aGVtIG9yIHRoZXJlIGNhbiBiZSBzaWduaWZpY2FudCBsb3NzIG9mIGFjY3VyYWN5LgoKVGhlIGRhdGEgaXMgZ2VuZXJhdGVkIGZyb20gYSBQb2lzc29uIHJlZ3Jlc3Npb24gbW9kZWwuIFRoZSBQb2lzc29uCmludGVuc2l0eSBwYXJhbWV0ZXIgaGFzIHRvIGJlIHBvc2l0aXZlIGFuZCB1c3VhbGx5IHRoZSBsYXRlbnQKbGluZWFyIHByZWRpY3RvciBpcyBleHBvbmVudGlhdGVkIHRvIGJlIHBvc2l0aXZlICh0aGUKZXhwb25lbnRpYXRpb24gY2FuIGFsc28gYmUganVzdGlmaWVkIGJ5IG11bHRpcGxpY2F0aXZlIGVmZmVjdHMgb24KUG9pc3NvbiBpbnRlbnNpdHkpLgoKV2UgaW50ZW50aW9uYWxseSBnZW5lcmF0ZSB0aGUgZGF0YSBzbyB0aGF0IHRoZXJlIGFyZSBpbml0aWFsaXphdGlvbgpwcm9ibGVtcywgYnV0IHRoZSBzYW1lIHByb2JsZW0gaXMgY29tbW9uIHdpdGggcmVhbCBkYXRhIHdoZW4gdGhlCnNjYWxlIG9mIHRoZSBwcmVkaWN0b3JzIGlzIGxhcmdlIG9yIHNtYWxsIGNvbXBhcmVkIHRvIHRoZSB1bml0CnNjYWxlLiBUaGUgZm9sbG93aW5nIGZpZ3VyZSBzaG93cyB0aGUgc2ltdWxhdGVkIGRhdGEuCgojIyMgRGF0YQoKYGBgYHtyfQpzZXQuc2VlZChTRUVEKQpNPTE7Ck49MjA7Cng9MWUzKm1hdHJpeChjKHNvcnQocm5vcm0oTikpKSxuY29sPU0pCnk9cnBvaXMoTixleHAoMWUtMyp4WywxXSkpCmRhdGFfcG9pcyA8LWxpc3QoTSA9IE0sIE4gPSBOLCB4ID0geCwgeSA9IHkpCmRhdGEuZnJhbWUoZGF0YV9wb2lzKSB8PgogIGdncGxvdChhZXMoeCwgeSkpICsKICBnZW9tX3BvaW50KHNpemUgPSAzKQpnZ3NhdmUoZmlsZT0ncG9pc3Nvbl9kYXRhLnBkZicsIHdpZHRoPTQsIGhlaWdodD00KQpgYGBgCgoKIyMjIE1vZGVsCgpXZSB1c2UgYSBQb2lzc29uIHJlZ3Jlc3Npb24gbW9kZWwgd2l0aCBwcm9wZXIgcHJpb3JzLiBUaGUgbGluZQpgcG9pc3Nvbl9sb2dfZ2xtKHgsIGFscGhhLCBiZXRhKWAgY29ycmVzcG9uZHMgdG8gYSBkaXN0cmlidXRpb24gaW4Kd2hpY2ggdGhlIGxvZyBpbnRlbnNpdHkgb2YgdGhlIFBvaXNzb24gZGlzdHJpYnV0aW9uIGlzIG1vZGVsZWQgd2l0aApgYWxwaGEgKyBiZXRhICogeGAgYnV0IGlzIGltcGxlbWVudGVkIHdpdGggYmV0dGVyIGNvbXB1dGF0aW9uYWwKZWZmaWNpZW5jeS4KCmBgYGB7cn0KY29kZV9wb2lzIDwtIHJvb3QoIlByb2JsZW1zIiwgInBvaXNfZ2xtLnN0YW4iKQp3cml0ZUxpbmVzKHJlYWRMaW5lcyhjb2RlX3BvaXMpKQpgYGBgCgpTYW1wbGUKCmBgYGB7ciBtZXNzYWdlPVRSVUUsIGVycm9yPVRSVUUsIHdhcm5pbmc9VFJVRX0KbW9kX3BvaXMgPC0gY21kc3Rhbl9tb2RlbChzdGFuX2ZpbGUgPSBjb2RlX3BvaXMpCmZpdF9wb2lzIDwtIG1vZF9wb2lzJHNhbXBsZShkYXRhID0gZGF0YV9wb2lzLCBzZWVkID0gU0VFRCwgcmVmcmVzaCA9IDApCmBgYGAKCldlIGdldCBhIGxvdCBvZiB3YXJuaW5nczoKCmBgYApDaGFpbiA0IFJlamVjdGluZyBpbml0aWFsIHZhbHVlOgpDaGFpbiA0ICAgTG9nIHByb2JhYmlsaXR5IGV2YWx1YXRlcyB0byBsb2coMCksIGkuZS4gbmVnYXRpdmUgaW5maW5pdHkuCkNoYWluIDQgICBTdGFuIGNhbid0IHN0YXJ0IHNhbXBsaW5nIGZyb20gdGhpcyBpbml0aWFsIHZhbHVlLgpgYGAKCiMjIyBDb252ZXJnZW5jZSBkaWFnbm9zdGljcwoKV2UgY2hlY2sgdGhlIGRpYWdub3N0aWNzOgoKYGBgYHtyfQpmaXRfcG9pcyRkaWFnbm9zdGljX3N1bW1hcnkoKQpkcmF3cyA8LSBhc19kcmF3c19ydmFycyhmaXRfcG9pcyRkcmF3cygpKQpgYGBgCmBgYGB7ciByZW5kZXI9bGVtb25fcHJpbnQsIGRpZ2l0cz1jKDAsMiwyLDIsMiwyLDIsMiwwLDApfQpzdW1tYXJpemVfZHJhd3MoZHJhd3MpCmBgYGAKCiRcd2lkZWhhdHtSfSQgdmFsdWVzIGFyZSBsYXJnZSBhbmQgRVNTIHZhbHVlcyBhcmUgc21hbGwsIGluZGljYXRpbmcKYmFkIG1peGluZy4gTWFyZ2luYWwgaGlzdG9ncmFtcyBhbmQgam9pbnQgc2NhdHRlcnBsb3RzIG9mIHRoZQpwb3N0ZXJpb3IgZHJhd3MgaW4gdGhlIGZpZ3VyZSBiZWxvdyBjbGVhcmx5IHNob3cgdGhhdCB0d28KY2hhaW5zIGhhdmUgYmVlbiBzdHVjayBhd2F5IGZyb20gdHdvIG90aGVycy4KCmBgYGB7cn0KKHA9bWNtY19wYWlycyhhc19kcmF3c19hcnJheShkcmF3cyksIHBhcnM9YygiYWxwaGEiLCJiZXRhIikpKQpnZ3NhdmUocCwgZmlsZT0ncG9pc3Nvbl9wYWlycy5wZGYnLCB3aWR0aD02LCBoZWlnaHQ9NCkKYGBgYAoKClRoZSByZWFzb24gZm9yIHRoZSBpc3N1ZSBpcyB0aGF0IHRoZSBpbml0aWFsIHZhbHVlcyBmb3IKYGJldGFgIGFyZSBzYW1wbGVkIGZyb20gJCgtMiwgMikkIGFuZCBgeGAgaGFzIHNvbWUKbGFyZ2UgdmFsdWVzLiBJZiB0aGUgaW5pdGlhbCB2YWx1ZSBmb3IgYGJldGFgIGlzIGhpZ2hlciB0aGFuCmFib3V0IDAuMyBvciBsb3dlciB0aGFuICQtMC40JCwgc29tZSBvZiB0aGUgdmFsdWVzIG9mCmBleHAoYWxwaGEgKyBiZXRhICogeClgIHdpbGwgb3ZlcmZsb3cgdG8gZmxvYXRpbmcgcG9pbnQKaW5maW5pdHkgKGBJbmZgKS4gCgojIyMgU2NhbGVkIGRhdGEKClNvbWV0aW1lcyBhbiBlYXN5IG9wdGlvbiBpcyB0byBjaGFuZ2UgdGhlIGluaXRpYWxpemF0aW9uIHJhbmdlLiBGb3IKZXhhbXBsZSwgaW4gdGhpcyB0aGUgc2FtcGxpbmcgc3VjY2VlZHMgaWYgdGhlIGluaXRpYWwgdmFsdWVzIGFyZQpkcmF3biBmcm9tIHRoZSByYW5nZSAkKC0wLjAwMSwgMC4wMDEpJC4gQWx0ZXJuYXRpdmVseSB3ZSBjYW4gc2NhbGUKYHhgIHRvIGhhdmUgc2NhbGUgY2xvc2UgdG8gdW5pdCBzY2FsZS4gQWZ0ZXIgdGhpcyBzY2FsaW5nLCB0aGUKY29tcHV0YXRpb24gaXMgZmFzdCBhbmQgYWxsIGNvbnZlcmdlbmNlIGRpYWdub3N0aWNzIGxvb2sgZ29vZC4KCmBgYGB7cn0KZGF0YV9wb2lzIDwtbGlzdChNID0gTSwgTiA9IE4sIHggPSB4LzFlMywgeSA9IHkpCmRhdGEuZnJhbWUoZGF0YV9wb2lzKSB8PgogIGdncGxvdChhZXMoeCwgeSkpICsKICBnZW9tX3BvaW50KHNpemUgPSAzKQoKbW9kX3BvaXMgPC0gY21kc3Rhbl9tb2RlbChzdGFuX2ZpbGUgPSBjb2RlX3BvaXMpCmZpdF9wb2lzIDwtIG1vZF9wb2lzJHNhbXBsZShkYXRhID0gZGF0YV9wb2lzLCBzZWVkID0gU0VFRCwgcmVmcmVzaCA9IDApCmBgYGAKCgojIyMgQ29udmVyZ2VuY2UgZGlhZ25vc3RpY3MKCldlIGNoZWNrIHRoZSBkaWFnbm9zdGljczoKCmBgYGB7cn0KZml0X3BvaXMkZGlhZ25vc3RpY19zdW1tYXJ5KCkKZHJhd3MgPC0gYXNfZHJhd3NfcnZhcnMoZml0X3BvaXMkZHJhd3MoKSkKYGBgYApgYGBge3IgcmVuZGVyPWxlbW9uX3ByaW50LCBkaWdpdHM9YygwLDIsMiwyLDIsMiwyLDIsMCwwKX0Kc3VtbWFyaXplX2RyYXdzKGRyYXdzKQpgYGBgCgoKSWYgdGhlIGluaXRpYWwgdmFsdWUgd2FybmluZyBjb21lcyBvbmx5IG9uY2UsIGl0IGlzIHBvc3NpYmxlIHRoYXQKTUNNQyB3YXMgYWJsZSB0byBlc2NhcGUgdGhlIGJhZCByZWdpb24gYW5kIHJlc3Qgb2YgdGhlIGluZmVyZW5jZSBpcwpvay4KCiMjIFRoaWNrIHRhaWxlZCBwb3N0ZXJpb3IKCldlIHJldHVybiB0byB0aGUgbG9naXN0aWMgcmVncmVzc2lvbiBleGFtcGxlIHdpdGggc2VwYXJhYmxlCmRhdGEuIE5vdyB3ZSB1c2UgcHJvcGVyLCBidXQgdGhpY2sgdGFpbGVkIENhdWNoeSBwcmlvci4KCiMjIyBNb2RlbAoKYGBgYHtyfQpjb2RlX2xvZ2l0NCA8LSByb290KCJQcm9ibGVtcyIsICJsb2dpdF9nbG00LnN0YW4iKQp3cml0ZUxpbmVzKHJlYWRMaW5lcyhjb2RlX2xvZ2l0NCkpCmBgYGAKClNhbXBsZQoKYGBgYHtyfQptb2RfbG9naXQ0IDwtIGNtZHN0YW5fbW9kZWwoc3Rhbl9maWxlID0gY29kZV9sb2dpdDQpCmZpdF9sb2dpdDQgPC0gbW9kX2xvZ2l0NCRzYW1wbGUoZGF0YSA9IGRhdGFfbG9naXQsIHNlZWQgPSBTRUVELCByZWZyZXNoID0gMCkKYGBgYAoKCiMjIyBDb252ZXJnZW5jZSBkaWFnbm9zdGljcwoKV2UgY2hlY2sgZGlhZ25vc3RpY3MKCmBgYGB7cn0KZml0X2xvZ2l0NCRkaWFnbm9zdGljX3N1bW1hcnkoKQpkcmF3cyA8LSBhc19kcmF3c19ydmFycyhmaXRfbG9naXQ0JGRyYXdzKCkpCmBgYGAKYGBgYHtyIHJlbmRlcj1sZW1vbl9wcmludCwgZGlnaXRzPWMoMCwyLDIsMiwyLDIsMiwyLDAsMCl9CnN1bW1hcml6ZV9kcmF3cyhkcmF3cykKYGBgYAoKVGhlIHJvdW5kZWQgJFx3aWRlaGF0e1J9JCB2YWx1ZXMgbG9vayBnb29kLCBFU1MgdmFsdWVzIGFyZQpsb3cuIExvb2tpbmcgYXQgdGhlIG1hcmdpbmFsIGhpc3RvZ3JhbXMgYW5kIGpvaW50IHNjYXR0ZXJwbG90cyBvZgp0aGUgcG9zdGVyaW9yIGRyYXdzIGluIHRoZSBmb2xsb3dpbmcgZmlndXJlIHNob3cgYSB0aGljayB0YWlsLgoKYGBgYHtyfQoocDwtbWNtY19wYWlycyhhc19kcmF3c19hcnJheShkcmF3cyksIHBhcnM9YygiYWxwaGEiLCJiZXRhIikpKQpnZ3NhdmUocCwgZmlsZT0ndGhpY2tfdGFpbF9wYWlycy5wZGYnLCB3aWR0aD02LCBoZWlnaHQ9NCkKYGBgYAoKClRoZSBkeW5hbWljIEhNQyBhbGdvcml0aG0gdXNlZCBieSBTdGFuLCBhbG9uZyB3aXRoIG1hbnkgb3RoZXIgTUNNQwptZXRob2RzLCBoYXZlIHByb2JsZW1zIHdpdGggc3VjaCB0aGljayB0YWlscyBhbmQgbWl4aW5nIGlzCnNsb3cuCgpSYW5rIEVDREYgcGxvdCBpbmRpY2F0ZXMgZ29vZCBtaXhpbmcgYXMgYWxsIGNoYWlucyBoYXZlIHRoZWlyIGxpbmVzCmluc2lkZSB0aGUgZW52ZWxvcGUgKHRoZSBlbnZlbG9wZSBhc3N1bWVzIG5vIGF1dG9jb3JyZWxhdGlvbiwgd2hpY2gKaXMgdGhlIHJlYXNvbiB0byB0aGluIHRoZSBkcmF3cyBoZXJlKQoKYGBgYHtyfQpkcmF3cyB8PiB0aGluX2RyYXdzKG5kcmF3cyhkcmF3cykvZXNzX2J1bGsoZHJhd3MkYWxwaGEpKSB8PgogIG1jbWNfcmFua19lY2RmKHBhcnM9YygiYWxwaGEiKSwgcGxvdF9kaWZmPVRSVUUpCmdnc2F2ZShwLCBmaWxlPSd0aGlja190YWlsX3JhbmtfZWNkZl9kaWZmLnBkZicsIHdpZHRoPTYsIGhlaWdodD00KQpgYGBgCgpNb3JlIGl0ZXJhdGlvbnMgY29uZmlybSBhIHJlYXNvbmFibGUgbWl4aW5nLgoKYGBgYHtyfQpmaXRfbG9naXQ0IDwtIG1vZF9sb2dpdDQkc2FtcGxlKGRhdGEgPSBkYXRhX2xvZ2l0LCBzZWVkID0gU0VFRCwgcmVmcmVzaCA9IDAsIGl0ZXJfc2FtcGxpbmc9NDAwMCkKZHJhd3MgPC0gYXNfZHJhd3NfcnZhcnMoZml0X2xvZ2l0NCRkcmF3cygpKQpzdW1tYXJpemVfZHJhd3MoZHJhd3MpCmRyYXdzIHw+IHRoaW5fZHJhd3MobmRyYXdzKGRyYXdzKS9lc3NfYnVsayhkcmF3cyRhbHBoYSkpIHw+CiAgbWNtY19yYW5rX2VjZGYocGFycz1jKCJhbHBoYSIpLCBwbG90X2RpZmY9VFJVRSkKYGBgYAoKCiMjIFZhcmlhbmNlIHBhcmFtZXRlciB0aGF0IGlzIG5vdCBjb25zdHJhaW5lZCB0byBiZSBwb3NpdGl2ZQoKRGVtb25zdHJhdGlvbiB3aGF0IGhhcHBlbnMgaWYgd2UgZm9yZ2V0IHRvIGNvbnN0cmFpbiBhIHBhcmFtZXRlcgp0aGF0IGhhcyB0byBiZSBwb3NpdGl2ZS4gSW4gU3RhbiB0aGUgY29uc3RyYWludCBjYW4gYmUgYWRkZWQgd2hlbgpkZWNsYXJpbmcgdGhlIHBhcmFtZXRlciBhcyBgcmVhbDxsb3dlcj0wPiBzaWdtYTtgCgojIyMgRGF0YQoKV2Ugc2ltdWxhdGVkIHggYW5kIHkgaW5kZXBlbmRlbnRseSBmcm9tIGluZGVwZW5kZW50bHkgZnJvbQpub3JtYWwoMCwxKSBhbmQgbm9ybWFsKDAsMC4xKSByZXNwZWN0aXZlbHkuIEFzICROPTgkIGlzIHNtYWxsLAp0aGVyZSB3aWxsIGJlIGEgbG90IG9mIHVuY2VydGFpbnR5IGFib3V0IHRoZSBwYXJhbWV0ZXJzIGluY2x1ZGluZwp0aGUgc2NhbGUgc2lnbWEuCgpgYGBge3J9Ck09MTsKTj04OwpzZXQuc2VlZChTRUVEKQp4PW1hdHJpeChybm9ybShOKSxuY29sPU0pCnk9cm5vcm0oTikvMTAKZGF0YV9saW4gPC1saXN0KE0gPSBNLCBOID0gTiwgeCA9IHgsIHkgPSB5KQpgYGBgCgojIyMgTW9kZWwKCldlIHVzZSBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCB3aXRoIHByb3BlciBwcmlvcnMuCgpgYGBge3J9CmNvZGVfbGluIDwtIHJvb3QoIlByb2JsZW1zIiwgImxpbmVhcl9nbG0uc3RhbiIpCndyaXRlTGluZXMocmVhZExpbmVzKGNvZGVfbGluKSkKYGBgYAoKU2FtcGxlCgpgYGBge3J9Cm1vZF9saW4gPC0gY21kc3Rhbl9tb2RlbChzdGFuX2ZpbGUgPSBjb2RlX2xpbikKZml0X2xpbiA8LSBtb2RfbGluJHNhbXBsZShkYXRhID0gZGF0YV9saW4sIHNlZWQgPSBTRUVELCByZWZyZXNoID0gMCkKYGBgYAoKV2UgZ2V0IG1hbnkgdGltZXMgdGhlIGZvbGxvd2luZyB3YXJuaW5ncwpgYGAKQ2hhaW4gNCBJbmZvcm1hdGlvbmFsIE1lc3NhZ2U6IFRoZSBjdXJyZW50IE1ldHJvcG9saXMgcHJvcG9zYWwgaXMgYWJvdXQgdG8gYmUgcmVqZWN0ZWQgYmVjYXVzZSBvZiB0aGUgZm9sbG93aW5nIGlzc3VlOgpDaGFpbiA0IEV4Y2VwdGlvbjogbm9ybWFsX2lkX2dsbV9scGRmOiBTY2FsZSB2ZWN0b3IgaXMgLTAuNzQ3NDc2LCBidXQgbXVzdCBiZSBwb3NpdGl2ZSBmaW5pdGUhIChpbiAnL3RtcC9SdG1wckVQNGdnL21vZGVsLTdjYWExMmNlOGU0MDUuc3RhbicsIGxpbmUgMTYsIGNvbHVtbiAyIHRvIGNvbHVtbiA0MykKQ2hhaW4gNCBJZiB0aGlzIHdhcm5pbmcgb2NjdXJzIHNwb3JhZGljYWxseSwgc3VjaCBhcyBmb3IgaGlnaGx5IGNvbnN0cmFpbmVkIHZhcmlhYmxlIHR5cGVzIGxpa2UgY292YXJpYW5jZSBtYXRyaWNlcywgdGhlbiB0aGUgc2FtcGxlciBpcyBmaW5lLApDaGFpbiA0IGJ1dCBpZiB0aGlzIHdhcm5pbmcgb2NjdXJzIG9mdGVuIHRoZW4geW91ciBtb2RlbCBtYXkgYmUgZWl0aGVyIHNldmVyZWx5IGlsbC1jb25kaXRpb25lZCBvciBtaXNzcGVjaWZpZWQuCmBgYAoKU29tZXRpbWVzIHRoZXNlIHdhcm5pbmdzIGFwcGVhciBpbiBlYXJseSBwaGFzZSBvZiB0aGUgc2FtcGxpbmcsCmV2ZW4gaWYgdGhlIG1vZGVsIGhhcyBiZWVuIGNvcnJlY3RseSBkZWZpbmVkLiBOb3cgd2UgaGF2ZSB0b28gbWFueQpvZiB0aGVtLCB3aGljaCBpbmRpY2F0ZXMgdGhlIHNhbXBsZXMgaXMgdHJ5aW5nIHRvIGp1bXAgdG8KaW5mZWFzaWJsZSB2YWx1ZXMsIHdoaWNoIGhlcmUgbWVhbnMgdGhlIG5lZ2F0aXZlIHNjYWxlIHBhcmFtZXRlcgp2YWx1ZXMuIE1hbnkgcmVqZWN0aW9ucyBtYXkgbGVhZCB0byBiaWFzZWQgZXN0aW1hdGVzLgoKVGhlcmUgYXJlIHNvbWUgZGl2ZXJnZW5jZXMgcmVwb3J0ZWQsIHdoaWNoIGlzIGFsc28gaW5kaWNhdGlvbiB0aGF0CnRoZXJlIG1pZ2h0IGJlIHNvbWUgcHJvYmxlbSAoYXMgZGl2ZXJnZW5jZSBkaWFnbm9zdGljIGhhcyBhbiBhZCBob2MKZGlhZ25vc3RpYyB0aHJlc2hvbGQsIHRoZXJlIGNhbiBhbHNvIGJlIGZhbHNlIHBvc2l0aXZlCndhcm5pbmdzKS4gT3RoZXIgY29udmVyZ2VuY2UgZGlhZ25vc3RpY3MgYXJlIGdvb2QsIGJ1dCBkdWUgdG8gbWFueQpyZWplY3Rpb24gd2FybmluZ3MsIGl0IGlzIGdvb2QgdG8gY2hlY2sgdGhlIG1vZGVsIGNvZGUgYW5kCm51bWVyaWNhbCBhY2N1cmFjeSBvZiB0aGUgY29tcHV0YXRpb25zLgoKIyMjIENvbnZlcmdlbmNlIGRpYWdub3N0aWNzCgpXZSBjaGVjayBkaWFnbm9zdGljcwoKYGBgYHtyfQpmaXRfbGluJGRpYWdub3N0aWNfc3VtbWFyeSgpCmRyYXdzIDwtIGFzX2RyYXdzX3J2YXJzKGZpdF9saW4kZHJhd3MoKSkKYGBgYApgYGBge3IgcmVuZGVyPWxlbW9uX3ByaW50LCBkaWdpdHM9YygwLDIsMiwyLDIsMiwyLDIsMCwwKX0Kc3VtbWFyaXplX2RyYXdzKGRyYXdzKQpgYGBgCgojIyMgU3RhbiBjb21waWxlciBwZWRhbnRpYyBjaGVjawoKU3RhbiBjb21waWxlciBwZWRhbnRpYyBjaGVjayBjYW4gcmVjb2duaXplIHRoYXQgYEEgbm9ybWFsX2lkX2dsbQpkaXN0cmlidXRpb24gaXMgZ2l2ZW4gcGFyYW1ldGVyIHNpZ21hIGFzIGEgc2NhbGUgcGFyYW1ldGVyCihhcmd1bWVudCA0KSwgYnV0IHNpZ21hIHdhcyBub3QgY29uc3RyYWluZWQgdG8gYmUgc3RyaWN0bHkKcG9zaXRpdmUuIFRoZSBwZWRhbnRpYyBjaGVjayBpcyBhbHNvIHdhcm5pbmcgYWJvdXQgdGhlIHZlcnkgd2lkZQpwcmlvcnMuCgpgYGBge3IgbWVzc2FnZT1UUlVFLCBlcnJvcj1UUlVFLCB3YXJuaW5nPVRSVUV9Cm1vZF9saW4kY2hlY2tfc3ludGF4KHBlZGFudGljID0gVFJVRSkKYGBgYAoKQWZ0ZXIgZml4aW5nIHRoZSBtb2RlbCB3aXRoIHByb3BlciBwYXJhbWV0ZXIgY29uc3RyYWludCwgTUNNQyBydW5zCndpdGhvdXQgd2FybmluZ3MgYW5kIHRoZSBzYW1wbGluZyBlZmZpY2llbmN5IGlzIGJldHRlci4gSW4gdGhpcwpzcGVjaWZpYyBjYXNlLCB0aGUgYmlhcyBpcyBuZWdsaWdpYmxlIHdoZW4gcnVubmluZyBNQ01DIHdpdGggdGhlCm1vZGVsIGNvZGUgd2l0aG91dCB0aGUgY29uc3RyYWludCwgYnV0IGl0IGlzIGRpZmZpY3VsdCB0byBkaWFnbm9zZQp3aXRob3V0IHJ1bm5pbmcgdGhlIGZpeGVkIG1vZGVsLgoKRml4ZWQgbW9kZWwgaW5sY3VkZXMgPGxvd2VyPTA+IGNvbnN0cmFpbnQgZm9yIHNpZ21hLgoKYGBgYHtyfQpjb2RlX2xpbjIgPC0gcm9vdCgiUHJvYmxlbXMiLCAibGluZWFyX2dsbTIuc3RhbiIpCndyaXRlTGluZXMocmVhZExpbmVzKGNvZGVfbGluMikpCmBgYGAKClNhbXBsZQoKYGBgYHtyfQptb2RfbGluMiA8LSBjbWRzdGFuX21vZGVsKHN0YW5fZmlsZSA9IGNvZGVfbGluMikKZml0X2xpbjIgPC0gbW9kX2xpbjIkc2FtcGxlKGRhdGEgPSBkYXRhX2xpbiwgc2VlZCA9IFNFRUQsIHJlZnJlc2ggPSAwKQpgYGBgCgpXZSBjaGVjayBkaWFnbm9zdGljcwoKYGBgYHtyfQpkcmF3czIgPC0gYXNfZHJhd3NfcnZhcnMoZml0X2xpbjIkZHJhd3MoKSkKYGBgYApgYGBge3IgcmVuZGVyPWxlbW9uX3ByaW50LCBkaWdpdHM9YygwLDIsMiwyLDIsMiwyLDIsMCwwKX0Kc3VtbWFyaXplX2RyYXdzKGRyYXdzMikKYGBgYAoKSW4gdGhpcyBzcGVjaWZpYyBjYXNlLCB0aGUgYmlhcyBpcyBuZWdsaWdpYmxlIHdoZW4gcnVubmluZyBNQ01DCndpdGggdGhlIG1vZGVsIGNvZGUgd2l0aG91dCB0aGUgY29uc3RyYWludCwgYnV0IGl0IGlzIGRpZmZpY3VsdCB0bwpkaWFnbm9zZSB3aXRob3V0IHJ1bm5pbmcgdGhlIGZpeGVkIG1vZGVsLgoK