This is an R-code companion to Session 4, and the contents encompass just about all the material in the session. During the lecture associated with the lesson, we showed some OpenGL-based animations of the MCMC sampler for the inbreeding model, but the code for that is implemented in C, and is not super accessible. So, the goal here is to implement, in R, the model and MCMC for the model using the several different types of samplers discussed in the session.
Let’s load Hadley’s tidyverse and other packages we need before we get going. The following will also install them if you don’t have them.
packs <- c("tidyverse", "plotly", "viridis", "broom")
# install any that are not here
install_em <- setdiff(packs, rownames(installed.packages()))
if (length(install_em) > 0) install.packages(pkgs = install_em)
# load em up
dump <- lapply(packs, function(x) library(x, character.only = TRUE))
Loading tidyverse: ggplot2
Loading tidyverse: tibble
Loading tidyverse: tidyr
Loading tidyverse: readr
Loading tidyverse: purrr
Loading tidyverse: dplyr
Conflicts with tidy packages --------------------------------------------------------------------------------------
filter(): dplyr, stats
lag(): dplyr, stats
Attaching package: ‘plotly’
The following object is masked from ‘package:ggplot2’:
last_plot
The following object is masked from ‘package:stats’:
filter
The following object is masked from ‘package:graphics’:
layout
Loading required package: viridisLite
Review of the model
We are dealing with a very simple model for inbreeding. It is one type of model that might be used to account for an excess of homozygotes in a sample from a population. We assume that we have taken a sample of \(n\) diploid individuals from the population, and we will be considering just a single locus at a time. This locus has two alleles \(A\) and \(a\), and our sample can be summarized by (what turns out to be the sufficient statistic, in this case) the numbers of the three possible genotypes: \(n_{AA}\), the number of \(AA\) homozygotes; \(n_{Aa}\), the number of heterozygotes; and \(n_{aa}\), the number of \(aa\) homozygotes. Of course, \(n_{AA} + n_{Aa} + n_{aa} = n\).
In a population with no inbreeding, the expected fraction of genotypes follows the Hardy-Weinberg equilibrium proportions. Letting \(p\) denote the frequency of the \(A\) allele in the population, under Hardy-Weinberg equilibrium the, expected fractions of the different genotypes are: \[
\begin{aligned}
P_\mathrm{HW}(AA) & = p^2 \\
P_\mathrm{HW}(Aa) & = 2p(1-p)\\
P_\mathrm{HW}(aa) & = (1-p)^2
\end{aligned}
\]
Basic probabilities
Inbreeding in a population violates one of the many assumptions required for Hardy-Weinberg equilibrium to hold. We model inbreeding here as a property of the pair of gene copies that occur in an individual in the population, and we measure it with the population inbreeding coefficient, \(f\), which can be interpreted as the probability that the pair of gene copies in an individual randomly sampled from the population are identical by descent, or IBD for short. For our purposes in this session, we will take “identical by descent” to mean that they are both copies of the same, recent ancestral gene copy. More important than the exact definition of “identical by descent” adopted here are the consequences for two gene copies of being IBD. And in this case, that is very simple: we will assume that if two gene copies are IBD, then they must also be the same allelic type. In other words, if two gene copies are IBD, and the first of them is allele \(A\), then the second must also be allele \(A\).
So, given the inbreeding coefficient \(f\), we can compute the probability that a randomly sampled individual has the genotype \(AA\), \(Aa\), or \(aa\). First, let us consider \(P(AA)\): with probability \(f\) the two gene copies at a locus in the individual are IBD, in which case only the first gene copy must by \(A\), since the second one will be too. On the other hand, with probability \((1-f)\) the two gene copies at the locus in the individual are not IBD, and so the probability of being \(AA\) is just the standard Hardy-Weinberg probability, \(P_\mathrm{HW}(AA) = p^2\). Hence, under the inbreeding model: \[
\begin{aligned}
P(AA) &= fp + (1-f)p^2 \\
P(Aa) &= f\times 0 + (1-f)2p(1-p) \\
P(aa) &= f(1-p) + (1-f)(1-p)^2
\end{aligned}
\]
The likelihood
Now recall that our data are \((n_{AA}, n_{Aa}, n_{aa})\)—the numbers of the different genotypes observed in the sample. To move forward in inference, we need to be able to compute the likelihood, which is the probability of our data given the values of the parameters: \(P(n_{AA}, n_{Aa}, n_{aa}|p,f)\). Note here that the two parameters in our model are \(p\), the frequency of the \(A\) allele in the population, and \(f\), the population inbreeding coefficient. We assume that each individual is sampled independently from the population, so the likelihood is a multinomial: \[
P(n_{AA}, n_{Aa}, n_{aa}) = \frac{n!}{n_{AA}! + n_{Aa}! + n_{aa}!}~
[fp + (1-f)p^2]^{n_{AA}}~
[(1-f)2p(1-p)]^{n_{Aa}}~
[f(1-p) + (1-f)(1-p)^2]^{n_{aa}}
\] The multinomial coefficient is a constant with respect to \(p\) and \(f\) so it will drop out.
The priors
We need priors of \(p\) and \(f\). These are proportions, so a natural choice is the beta distribution.
Let’s define \(f \sim \mathrm{Beta}(\alpha_f, \beta_f)\) and \(p \sim \mathrm{Beta}(\alpha_p, \beta_p)\), and we will set up our model that way, though the default values we will use are \(\alpha_f = \beta_f = \alpha_p = \beta_p = 1\) which will give us uniform priors for \(f\) and \(p\).
The joint probability
This is just the product of the priors and the likelihoods. In its full glory, it looks like: \[
\begin{aligned}
P(n_{AA}, n_{Aa}, n_{aa}, f, p | \alpha_f, \beta_f, \alpha_p, \beta_p) & =
\frac{\Gamma(\alpha_f + \beta_f)}{\Gamma(\alpha_f)\Gamma(\beta_f)}f^{\alpha_f - 1}(1-f)^{\beta_f - 1}
\frac{\Gamma(\alpha_p + \beta_p)}{\Gamma(\alpha_p)\Gamma(\beta_p)}p^{\alpha_p - 1}(1-p)^{\beta_p - 1} \times \\
& \frac{n!}{n_{AA}! + n_{Aa}! + n_{aa}!}~
[fp + (1-f)p^2]^{n_{AA}}~
[(1-f)2p(1-p)]^{n_{Aa}}~
[f(1-p) + (1-f)(1-p)^2]^{n_{aa}}
\end{aligned}
\] We will be using this in MCMC in which the the hyperpriors \((\alpha_f, \beta_f, \alpha_p, \beta_p)\) and the data are fixed. Thus the terms (factors) that involve only the data and the hyperpriors are constants that will drop out of the Hastings ratio, so they can be safely ignored. So, our joint probability can be computed as something that looks like: \[
\begin{aligned}
P(n_{AA}, n_{Aa}, n_{aa}, f, p | \alpha_f, \beta_f, \alpha_p, \beta_p) & \propto
f^{\alpha_f - 1}(1-f)^{\beta_f - 1}
p^{\alpha_p - 1}(1-p)^{\beta_p - 1} \times \\
& ~~~~[fp + (1-f)p^2]^{n_{AA}}~
[(1-f)2p(1-p)]^{n_{Aa}}~
[f(1-p) + (1-f)(1-p)^2]^{n_{aa}}
\end{aligned}
\] We will implement this in a function that returns the log of the above quantity so that we won’t run into underflow issues with very large samples:
#' the log of the joint probability of all the data and paramaters given the priors
#'
#' This is computed having dropped all the constant factors in the probability.
#' @param n a vector of three elements: (nAA, nAa, naa), the number of AA's, the
#' number of Aa's, and the number of aa's
#' @param f the inbreeding coeffient
#' @param p the frequency of the A allele
#' @param pri a vector of four components: (alpha_f, beta_f, alpha_p, beta_p) which are the
#' beta parameters for the priors on f and p. By default they are all 1.
log_joint_prob <- function(n, f, p, pri = c(1, 1, 1, 1)) {
# not going to do much error checking here
# compute the raw values, anything outside of the unit interval we will send
# back as NaN
ifelse(f <= 0 | f >= 1 | p <= 0 | p >= 1, NaN,
log(f) * (pri[1] - 1) +
log(1 - f) * (pri[2] - 1) +
log(p) * (pri[3] - 1) +
log(1 - p) * (pri[4] - 1) +
log(f * p + (1 - f) * p ^ 2) * n[1] +
log((1 - f) * 2 * p * (1 - p)) * n[2] +
log(f * (1 - p) + (1 - f) * (1 - p) ^ 2) * n[3])
}
Note that this function is vectorized over \(f\) and \(p\), but not \(n\) or the priors.
A 3-D plot
We can compute the joint probability of all the variables easily, and, because this is a toy problem in two dimensions, we can visualize roughly what the posterior surface will look like by computing values on a grid and normalizing those values so they sum to one. Let’s do that, since it is a good chance to introduce the plotly package to anyone that might not yet know it.
So, let’s take the example from the lecture and set our data to be \(n_{AA} = 30\), \(n_{Aa} = 10\), and \(n_{aa} = 10\). Those are the expected values if \(f = 0.5\) and \(p = 0.7\),
ndata <- c(30, 10, 10)
and then compute the log prob, exponentiate it, and normalize it over a grid of value for \(f\) and \(p\):
f_vals <- seq(0, 1, by = 0.03)
p_vals <- seq(0, 1, by = 0.03)
# make a tidy tibble of values
grid_vals <- expand.grid(f = f_vals, p = p_vals) %>%
as_tibble() %>%
mutate(joint = exp(log_joint_prob(ndata, f, p))) %>%
mutate(norm_joint = joint / sum(joint, na.rm = TRUE)) %>%
select(-joint)
# then put those values into a matrix, with rows corresponding to f and cols to p
probs <- matrix(grid_vals$norm_joint, nrow = length(f_vals), ncol = length(p_vals))
Now we can plot it with plotly:
plot_ly(x = ~p_vals, y = ~f_vals, z = ~probs) %>%
add_surface()
Try interacting with that plot, especially if you are not familiar with plotly. You can zoom, pan, and revolve it, and you can also look at individual values by mousing over within the plot.
“2-D” Metroplois-Hastings Sampler
We now start our forays into different MCMC samplers, roughly following the lecture notes from the session. The first is a sampler in which we propose changes to both \(f\) and \(p\) and then we accept or reject both of those proposaled changes, together, in one fell swoop, according to the Hastings Ratio.
For our proposals in this case we will use two independent, symmmetrical normal distributions centered on the current values. We will wrap up the whole process in a single function called mcmc_2d_mh()
.
#' function to do MCMC using a "2-D" Metropolis-Hastings sampler
#' @param ndata a three-vector (nAA, nAa, naa) of the observed data
#' @param pri a vector of four components: (alpha_f, beta_f, alpha_p, beta_p)
#' @param init a two vector of starting values (f, p). Each should be within the
#' unit interval.
#' @param sweeps the number of sweeps (i.e proposed changes) to do in the MCMC chain.
#' @param f_sd the standard deviation of the normal distribution for proposing new values to f
#' @param p_sd the standard deviation of the normal distribution for proposing new values to p
#' @return returns a tibble of proposals made, values visited, values of MH ratio, etc
mcmc_2d_mh <- function(ndata,
pri = c(1, 1, 1, 1),
init = c(.2, .5),
sweeps = 500,
f_sd = 0.07,
p_sd = 0.07) {
# create vectors in which to store output. Note that we will be storing
# the proposed values and the MH-ratio each sweep, too, for later analysis.
f <- p <- fprop <- pprop <- mh_ratio <- rep(NA_real_, sweeps + 1)
accepted_f <- accepted_p <- rep(NA, sweeps + 1)
# put initial values in
f[1] <- init[1]
p[1] <- init[2]
# then cycle over sweeps
for (i in 1:sweeps) {
# propose new values
fprop[i] <- rnorm(1, f[i], f_sd)
pprop[i] <- rnorm(1, p[i], p_sd)
# compute the hastings ratio
# the log M-H ratio is the difference of the log joint probs.
# since the proposal distributions are symmetrical they drop out of the ratio.
mh_ratio[i] <- exp(log_joint_prob(ndata, fprop[i], pprop[i], pri) -
log_joint_prob(ndata, f[i], p[i], pri))
# now, if mh_ratio[i] is NaN it means that f or p was proposed outside of the unit interval
# and it should be rejected immediately. If not, then we simulate a uniform R.V. on (0, 1)
# and reject the proposal if that number is greater than the MH-ratio.
if (is.nan(mh_ratio[i]) || runif(1) > mh_ratio[i]) {# reject!
accepted_f[i] <- FALSE
accepted_p[i] <- FALSE
f[i + 1] <- f[i]
p[i + 1] <- p[i]
} else {# accept!
accepted_f[i] <- TRUE
accepted_p[i] <- TRUE
f[i + 1] <- fprop[i]
p[i + 1] <- pprop[i]
}
}
# in the end, make a tibble and return
tibble(sweep = 1:(sweeps + 1),
f = f,
p = p,
proposed_f = fprop,
proposed_p = pprop,
mh_ratio = mh_ratio,
accepted_f = accepted_f,
accepted_p = accepted_p
)
}
A brief note: In the above function (and the one following) we are being careful to record not just the current state of the chain, but also every proposed value. Typically this is not done in MCMC. Rather, it is more usual to simply record the state of the chain at each sweep (or at some “thinned” interval of sweeps). However we wanted to keep a full record of the progression of all the variables so that they would be available for students to peruse or analyze.
Component-wise Metropolis-Hastings Sampler
Rather than proposing changes to both \(f\) and \(p\) before accepting or rejecting them, we can propose just a change to \(f\) (say) and accept or reject the proposal, and then propose just a change to \(p\), and then accept or reject that. This is called component-wise Metropolis-Hastings sampling. Underlying it is a central theme in MCMC, which is that just one or a few dimensions can be changed with each proposal, but as long as the acceptance or rejection of each proposal is done in a way that satisfies detailed balance, and as long as all the different types of proposals, when used together create an irreducible chain around the space, then you get a valid MCMC sampler.
We make a function that looks much like mcmc_2d_mh()
, but in which the proposal and acceptance steps for \(f\) and \(p\) are done separately within each sweep. This is going to look a little bit weird because we do each update within the sweep but set the new value of \(f\) in the “next” sweep. (You’ll see below…)
#' function to do MCMC using a component-wise Metropolis-Hastings sampler
#' @param ndata a three-vector (nAA, nAa, naa) of the observed data
#' @param pri a vector of four components: (alpha_f, beta_f, alpha_p, beta_p)
#' @param init a two vector of starting values (f, p). Each should be within the
#' unit interval.
#' @param sweeps the number of sweeps (i.e proposed changes) to do in the MCMC chain.
#' @param f_sd the standard deviation of the normal distribution for proposing new values to f
#' @param p_sd the standard deviation of the normal distribution for proposing new values to p
#' @return returns a tibble of proposals made, values visited, values of MH ratio, etc
mcmc_cw_mh <- function(ndata,
pri = c(1, 1, 1, 1),
init = c(.2, .5),
sweeps = 500,
f_sd = 0.07,
p_sd = 0.07) {
# create vectors in which to store output. Note that we will be storing
# the proposed values and the MH-ratio each sweep, too, for later analysis.
f <- p <- fprop <- pprop <- mh_ratio_f <- mh_ratio_p <- rep(NA_real_, sweeps + 1)
accepted_f <- accepted_p <- rep(NA, sweeps + 1)
# put initial values in
f[1] <- init[1]
p[1] <- init[2]
# then cycle over sweeps
for (i in 1:sweeps) {
# propose new value for f
fprop[i] <- rnorm(1, f[i], f_sd)
# compute the hastings ratio with only a change to f proposed
mh_ratio_f[i] <- exp(log_joint_prob(ndata, fprop[i], p[i], pri) -
log_joint_prob(ndata, f[i], p[i], pri))
# then accept or reject it
U <- runif(1)
if (is.nan(mh_ratio_f[i]) | runif(1) > mh_ratio_f[i]) {# reject!
accepted_f[i] <- FALSE
f[i + 1] <- f[i]
} else {# if accepted, then update the value of f
accepted_f[i] <- TRUE
f[i + 1] <- fprop[i] # set the value. This is a little weird because we are still in sweep i.
}
# now, the current value of f is stored in f[i + 1], and we propose a new value for p
pprop[i] <- rnorm(1, p[i], p_sd)
# compute the hastings ratio using the new f and the proposed value of p
mh_ratio_p[i] <- exp(log_joint_prob(ndata, f[i + 1], pprop[i], pri) -
log_joint_prob(ndata, f[i + 1], p[i], pri))
# and reject or accept the proposal
if (is.nan(mh_ratio_p[i]) | runif(1) > mh_ratio_p[i]) {# reject!
accepted_p[i] <- FALSE
p[i + 1] <- p[i]
} else {# if not accepted then make p the same as the current p
accepted_p[i] <- TRUE
p[i + 1] <- pprop[i]
}
}
# in the end, make a tibble and return
tibble(sweep = 1:(sweeps + 1),
f = f,
p = p,
proposed_f = fprop,
proposed_p = pprop,
mh_ratio_f = mh_ratio_f,
mh_ratio_p = mh_ratio_p,
accepted_f = accepted_f,
accepted_p = accepted_p
)
}
The Gibbs sampler
Implementing a Gibbs sampler is made easy by attaching to each of the 50 observed genotypes, a latent variable which indicates whether the two gene copies at the locus in that individual are IBD or not. In order to do this, we must now treat each individual as an observation, rather than just summarizing the number of AA’s, Aa’s, and aa’s. However, we can still pass the data into our function as, for example, ndata = c(30, 10, 10)
, and then expand that into a list of individual IDs within the function.
Using the Gibbs sampler a sweep of our algorithm will involve three steps:
- simulate new values for the latent variables (\(U\) in the lecture notes) from their full conditionals.
- simulate a new value of \(f\) from its full conditional.
- simulate a new value of \(p\) from its full conditional.
The lecture notes from session 4 don’t go into much detail about the exact form of the full conditionals. For \(f\) and \(p\) it is pretty easily understood from the session that they will be beta distributions. Here, however, it will behoove us to explicitly derive the full conditional for the latent variables. Let’s refresh our memory by looking at the DAG for the model with the latent variables:
Aha! Knowing what we do about how DAGs tell us about the factorization of joint probability distributions, this shows us that \(U_i\), the latent indicator of IBD status for individual \(i\), will appear in terms in the joint probability that looks like: \[
P(U_i|f)P(Y_i|U_i, p)
\] Let’s say that \(U_i = 1\) means the individual is inbred (i.e. carries two gene copies that are IBD) at the locus, and \(U_i=0\) means the individual’s gene copies are not IBD at the locus.
The first term is hence a simple Bernoulli proportion, i.e. \(P(U_i = 1 |f) = f\).
The second term is the probabilty of the individual having a genotype given the two gene copies are IBD or not. These can be simply enumerated: \[
\begin{aligned}
P(Y_i = AA | U_i = 0, p) &= p^2 & P(Y_i = AA | U_i = 1, p) &= p \\
P(Y_i = Aa | U_i = 0, p) &= 2p(1-p) & P(Y_i = Aa | U_i = 1, p) &= 0 \\
P(Y_i = aa | U_i = 0, p) &= (1-p)^2 & P(Y_i = aa | U_i = 1, p) &= (1-p)
\end{aligned}
\] These follow simply from the fact that if \(U_i=0\) the two gene copies are assumed to be drawn independently from the population allele frequency, and if \(U_i=1\) then the first gene copy is drawn from the population allele frequency, and the allelic type of the second is simply always that of the first.
To compute the full conditional for \(U_i\) we need to compute \(P(U_i|f)P(Y_i|U_i, p)\) for the individuals fixed genotypes \(Y_i\) and for the current values of \(f\) and \(p\), for both \(U_i=0\) and \(U_i=1\), and then normalize the probability so that it sums to 1 over the two possible values of \(U_i\). For example: \[
\begin{aligned}
P(U_i = 1 | Y_i = AA, p, f) &= \frac{P(U_i=1|f)P(Y_i=AA|U_i=0, p)}
{P(U_i=0|f)P(Y_i=AA|U_i=0, p) + {P(U_i=1|f)P(Y_i=AA|U_i=0, p)}} \\
&= \frac{fp}
{(1-f)p^2 + fp}
\end{aligned}
\]
Of course, if the individual is heterozygous, we know that its two gene copies cannot be IBD, so \(P(U_i = 1|Y_i = Aa, p, f) = 0\).
Now, let’s write that function!
#' function to do MCMC using a Gibbs sampler
#'
#' Note that we no longer need the f_sd and p_sd parameters. The Gibbs sampler
#' will be making proposals from the full conditional distribution!
#' @param ndata a three-vector (nAA, nAa, naa) of the observed data
#' @param pri a vector of four components: (alpha_f, beta_f, alpha_p, beta_p)
#' @param init a two vector of starting values (f, p). Each should be within the
#' unit interval.
#' @param sweeps the number of sweeps (i.e proposed changes) to do in the MCMC chain.
#' @return returns a tibble of proposals made, values visited, values of MH ratio, etc
mcmc_gibbs <- function(ndata,
pri = c(1, 1, 1, 1),
init = c(.2, .5),
sweeps = 500) {
# first arrange the data into individual observations, AA's first, then Aa's, then aa's
# We will make the genotypes factors, so AA = 1, Aa = 2, and aa = 3, so that we can count
# them up easily and have them ordered consistently.
obs_data <- rep(c("AA", "Aa", "aa"), times = ndata) %>%
factor(levels = c("AA", "Aa", "aa"))
latent_ibd <- logical(length(obs_data)) # vector of latent flags that tell us whether each
# individual carries gene copies that are IBD or not
latent_probs <- numeric(length(obs_data)) # a vector for holding the full conditional probabilities
# of the latent_ibd variables
# initialize f and p
f <- p <- rep(NA_real_, sweeps)
f[1] <- init[1]
p[1] <- init[2]
# then given initial values for f and p, initialize the latent_ibd vars (the vector of U_i's)
# first compute the full conditionals
latent_probs <- ifelse(obs_data == "AA", f[1] * p[1] / (f[1] * p[1] + (1 - f[1]) * p[1] ^ 2),
ifelse(obs_data == "Aa", 0,
ifelse(obs_data == "aa", f[1] * (1 - p[1]) / (f[1] * (1 - p[1]) + (1 - f[1]) * (1 - p[1]) ^ 2), NA)))
# then simulate from them. TRUE = inbred, FALSE = not inbred
latent_ibd <- runif(n = length(latent_probs)) < latent_probs
# now do the sweeps. In each one the steps are:
# 1. simulate a new value of f from its full conditional.
# 2. simulate a new value of p from its full conditional.
# 3. simulate new values for latent_ibd from their full conditionals.
# Every proposal will be accepted, so we will not bother recording the value of the
# proposed values like we did above
for (i in 2:sweeps) {
# 1. simulate a new value of f from its full conditional.
# recall that alpha_f is in pri[1] and beta_f is in pri[2]
ibd_counts <- table(latent_ibd) # returns vector of number of FALSEs and number of TRUEs
f[i] <- rbeta(n = 1, shape1 = ibd_counts[2] + pri[1], shape2 = ibd_counts[1] + pri[2])
# 2. simulate a new value of p from its full conditional.
# recall that alpha_p is in pri[3] and beta_p is in pri[4]
# we have to count up gene copies: two for each non-inbred individual and only
# one for each inbred individual. We want to get the number of A's and a's this way
# count the number of different genotypes that are non-IBD
nibd_genos <- table(obs_data[latent_ibd == FALSE])
# then add up the number of As and as
nibd_A = 2 * nibd_genos["AA"] + nibd_genos["Aa"]
nibd_a = 2 * nibd_genos["aa"] + nibd_genos["Aa"]
# then do something similar for the genotypes that are IBD
ibd_genos <- table(obs_data[latent_ibd == TRUE])
ibd_A = ibd_genos["AA"]
ibd_a = ibd_genos["aa"]
# then simulate p
p[i] <- rbeta(n = 1, shape1 = pri[3] + nibd_A + ibd_A, shape2 = pri[4] + nibd_a + ibd_a)
# 3. simulate new values for latent_ibd from their full conditionals
latent_probs <- ifelse(obs_data == "AA", f[i] * p[i] / (f[i] * p[i] + (1 - f[i]) * p[i] ^ 2),
ifelse(obs_data == "Aa", 0,
ifelse(obs_data == "aa", f[i] * (1 - p[i]) / (f[i] * (1 - p[i]) + (1 - f[i]) * (1 - p[i]) ^ 2), NA)))
# then simulate from them. TRUE = inbred, FALSE = not inbred
latent_ibd <- runif(n = length(latent_probs)) < latent_probs
}
# at the end return a tibble
tibble(sweep = 1:sweeps,
f = f,
p = p
)
}
Collect Samples
Now, we can collect samples from all three samplers. Let’s go ahead and put them all together into a tidy data frame. Let’s do 5,000 sweeps…
set.seed(10)
the_sample <- list(two_d = mcmc_2d_mh(ndata, sweeps = 5000),
comp_wise = mcmc_cw_mh(ndata, sweeps = 5000),
gibbs = mcmc_gibbs(ndata, sweeps = 5000)) %>%
bind_rows(.id = "sampler")
Posterior means for \(f\) and \(p\)
Compute posterior means:
the_sample %>%
filter(sweep > 200) %>%
group_by(sampler) %>%
summarise(mean_f = mean(f),
mean_p = mean(p))
Plot the results
Then plot the results, tossing the first 200 as burn in:
ggplot(the_sample %>% filter(sweep > 200), aes(x = f, y = p)) +
geom_point(size = 0.3, alpha = 0.3, colour = "gray") +
# stat_density_2d(aes(fill = ..level..), geom = "polygon") +
geom_density_2d(colour = "black") +
facet_wrap(~ sampler) +
# scale_fill_viridis() +
xlim(0, 1) +
ylim(0, 1) +
theme_bw()
That looks like everything is working. From the sample of points (in gray) visited by each chain we can make an estimate of the 2-D posterior surface.
If we wanted to look at that surface with some colors denoting actual values we could do this:
ggplot(the_sample %>% filter(sweep > 200), aes(x = f, y = p)) +
stat_density_2d(aes(fill = ..level..), geom = "polygon") +
facet_wrap(~ sampler) +
scale_fill_viridis() +
xlim(0, 1) +
ylim(0, 1)
Cool.
Which sampler mixes better?
This is an interesting question that students might want to explore a little. One way to do that is to investigate the auto-correlation between different states visited by the chain. That is, the correlation between the state at sweep \(t\) and at sweep \(t - \ell\) where \(\ell\) is the “lag”, and is usually investigated for a set of values from \(\ell = 0,\ldots,\mathrm{max~lag}\). This can be computed with the acf
function in \(R\). To keep it tidy, we will use dplyr::do
and broom::tidy
, after tidyr::gather()
ing the \(f\) and \(p\) values…
auto_corrs <- the_sample %>%
filter(sweep > 200) %>% # once again, toss the first 200 as burn-in
select(sampler, sweep, f, p) %>%
gather(key = "variable", value = "value", f, p) %>%
group_by(sampler, variable) %>%
do(tidy(acf(.$value, plot = FALSE)))
auto_corrs
And now we can plot those:
ggplot(auto_corrs, aes(x = lag, y = acf, colour = variable)) +
geom_segment(aes(xend = lag, yend = 0)) +
facet_grid(sampler ~ variable)
OK! Check that out. It is quite clear that the Gibbs sampler is mixing better, especially for \(p\)—there is much less correlation between successive values in the MCMC chain.
On the other hand, the astute student might notice that the Gibbs sampler takes a bit longer to run. This is especially true in R (not so much difference in compiled code). Nonetheless, this shows a fundamental tradeoff that often happens in MCMC: you can often get better mixing per-sweep by making more intelligent proposals. But, if those proposals take a lot of extra time to compute (or if they are a shrieking horror to code up) it might not be worth it. It is in making decisions like these where some of the fun “art” of implementing MCMC comes in.
LS0tCnRpdGxlOiAiTUNNQyBTYW1wbGluZyBmb3IgYSBTaW1wbGUgSW5icmVlZGluZyBNb2RlbCIKZGVzY3JpcHRpb246IFdlIHJldmlldyBvdXIgc2ltcGxlIG1vZGVsIGZvciBpbmJyZWVkaW5nIGF0IGEgbG9jdXMgYW5kIGRldmVsb3AgdGhlIGNvZGUgdG8gcGVyZm9ybSBzZXZlcmFsIGRpZmZlcmVudCB0eXBlcyBvZiBNZXRyb3BvbGlzLUhhc3RpbmdzIHVwZGF0ZXMsIHRoZW4gYXVnbWVudCB0aGUgbW9kZWwgdG8gaW5jbHVkZSBsYXRlbnQgdmFyaWFibGVzIHRoYXQgbGV0IHVzIGVhc2lseSB0byBHaWJicy1zYW1wbGluZyB1cGRhdGVzLgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQotLS0KClx1c2VwYWNrYWdle2Jsa2FycmF5fQpcdXNlcGFja2FnZXthbXNtYXRofQpcbmV3Y29tbWFuZHtcYm19e1xib2xkc3ltYm9sfQpcbmV3Y29tbWFuZHtcRXhwfXtcbWF0aGJiYntFfX0KClRoaXMgaXMgYW4gUi1jb2RlIGNvbXBhbmlvbiB0byBTZXNzaW9uIDQsIGFuZCB0aGUgY29udGVudHMgZW5jb21wYXNzIGp1c3QgYWJvdXQgCmFsbCB0aGUgbWF0ZXJpYWwgaW4gdGhlIHNlc3Npb24uICBEdXJpbmcgdGhlIGxlY3R1cmUgYXNzb2NpYXRlZCB3aXRoIHRoZSBsZXNzb24sCndlIHNob3dlZCBzb21lIE9wZW5HTC1iYXNlZCBhbmltYXRpb25zIG9mIHRoZSBNQ01DIHNhbXBsZXIgZm9yIHRoZSBpbmJyZWVkaW5nIG1vZGVsLApidXQgdGhlIGNvZGUgZm9yIHRoYXQgaXMgaW1wbGVtZW50ZWQgaW4gQywgYW5kIGlzIG5vdCBzdXBlciBhY2Nlc3NpYmxlLiAgU28sIHRoZSBnb2FsCmhlcmUgaXMgdG8gaW1wbGVtZW50LCBpbiBSLCB0aGUgbW9kZWwgYW5kIE1DTUMgZm9yIHRoZSBtb2RlbCB1c2luZyB0aGUgc2V2ZXJhbCBkaWZmZXJlbnQKdHlwZXMgb2Ygc2FtcGxlcnMgZGlzY3Vzc2VkIGluIHRoZSBzZXNzaW9uLiAgCgpMZXQncyBsb2FkIEhhZGxleSdzIHRpZHl2ZXJzZSBhbmQgb3RoZXIgcGFja2FnZXMgd2UgbmVlZCBiZWZvcmUgd2UgZ2V0IGdvaW5nLiAgVGhlIGZvbGxvd2luZwp3aWxsIGFsc28gaW5zdGFsbCB0aGVtIGlmIHlvdSBkb24ndCBoYXZlIHRoZW0uIApgYGB7cn0KcGFja3MgPC0gYygidGlkeXZlcnNlIiwgInBsb3RseSIsICJ2aXJpZGlzIiwgImJyb29tIikKCiMgaW5zdGFsbCBhbnkgdGhhdCBhcmUgbm90IGhlcmUKaW5zdGFsbF9lbSA8LSBzZXRkaWZmKHBhY2tzLCByb3duYW1lcyhpbnN0YWxsZWQucGFja2FnZXMoKSkpCmlmIChsZW5ndGgoaW5zdGFsbF9lbSkgPiAwKSBpbnN0YWxsLnBhY2thZ2VzKHBrZ3MgPSBpbnN0YWxsX2VtKQoKIyBsb2FkIGVtIHVwCmR1bXAgPC0gbGFwcGx5KHBhY2tzLCBmdW5jdGlvbih4KSBsaWJyYXJ5KHgsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkpCmBgYAoKIyMgUmV2aWV3IG9mIHRoZSBtb2RlbAoKV2UgYXJlIGRlYWxpbmcgd2l0aCBhIHZlcnkgc2ltcGxlIG1vZGVsIGZvciBpbmJyZWVkaW5nLiAgSXQgaXMgb25lIHR5cGUgb2YKbW9kZWwgdGhhdCBtaWdodCBiZSB1c2VkIHRvIGFjY291bnQgZm9yIGFuIGV4Y2VzcyBvZiBob21venlnb3RlcyBpbiBhIHNhbXBsZSAKZnJvbSBhIHBvcHVsYXRpb24uICBXZSBhc3N1bWUgdGhhdCB3ZSBoYXZlIHRha2VuIGEgc2FtcGxlIG9mICRuJCBkaXBsb2lkCmluZGl2aWR1YWxzIGZyb20gdGhlIHBvcHVsYXRpb24sIGFuZCB3ZSB3aWxsIGJlIGNvbnNpZGVyaW5nIGp1c3QgYSBzaW5nbGUKbG9jdXMgYXQgYSB0aW1lLiAgIFRoaXMgbG9jdXMgaGFzIHR3byBhbGxlbGVzICRBJCBhbmQgJGEkLCBhbmQgb3VyIHNhbXBsZSAKY2FuIGJlIHN1bW1hcml6ZWQgYnkgKHdoYXQgdHVybnMgb3V0IHRvIGJlIHRoZSBzdWZmaWNpZW50IHN0YXRpc3RpYywgaW4gdGhpcwpjYXNlKSB0aGUgbnVtYmVycyBvZiB0aGUgdGhyZWUgcG9zc2libGUgZ2Vub3R5cGVzOiAkbl97QUF9JCwgdGhlIG51bWJlciBvZgokQUEkIGhvbW96eWdvdGVzOyAkbl97QWF9JCwgdGhlIG51bWJlciBvZiBoZXRlcm96eWdvdGVzOyBhbmQgJG5fe2FhfSQsIHRoZQpudW1iZXIgb2YgJGFhJCBob21venlnb3Rlcy4gIE9mIGNvdXJzZSwgJG5fe0FBfSArIG5fe0FhfSArIG5fe2FhfSA9IG4kLgoKSW4gYSBwb3B1bGF0aW9uIHdpdGggbm8gaW5icmVlZGluZywgdGhlIGV4cGVjdGVkIGZyYWN0aW9uIG9mIGdlbm90eXBlcyBmb2xsb3dzCnRoZSBIYXJkeS1XZWluYmVyZyBlcXVpbGlicml1bSBwcm9wb3J0aW9ucy4gIExldHRpbmcgJHAkIGRlbm90ZSB0aGUgZnJlcXVlbmN5IG9mIHRoZQokQSQgYWxsZWxlIGluIHRoZSBwb3B1bGF0aW9uLCB1bmRlciBIYXJkeS1XZWluYmVyZyBlcXVpbGlicml1bSB0aGUsIGV4cGVjdGVkIGZyYWN0aW9ucwpvZiB0aGUgZGlmZmVyZW50IGdlbm90eXBlcyBhcmU6CiQkClxiZWdpbnthbGlnbmVkfQpQX1xtYXRocm17SFd9KEFBKSAmID0gcF4yIFxcClBfXG1hdGhybXtIV30oQWEpICYgPSAycCgxLXApXFwKUF9cbWF0aHJte0hXfShhYSkgJiA9ICgxLXApXjIKXGVuZHthbGlnbmVkfQokJAoKIyMjIEJhc2ljIHByb2JhYmlsaXRpZXMKCkluYnJlZWRpbmcgaW4gYSBwb3B1bGF0aW9uIHZpb2xhdGVzIG9uZSBvZiB0aGUgbWFueSBhc3N1bXB0aW9ucyByZXF1aXJlZCBmb3IgSGFyZHktV2VpbmJlcmcKZXF1aWxpYnJpdW0gdG8gaG9sZC4gIFdlIG1vZGVsIGluYnJlZWRpbmcgaGVyZSBhcyBhIHByb3BlcnR5IG9mIHRoZSBwYWlyIG9mIGdlbmUgY29waWVzCnRoYXQgb2NjdXIgaW4gYW4gaW5kaXZpZHVhbCBpbiB0aGUgcG9wdWxhdGlvbiwgYW5kIHdlIG1lYXN1cmUgaXQgd2l0aCB0aGUgcG9wdWxhdGlvbgppbmJyZWVkaW5nIGNvZWZmaWNpZW50LCAkZiQsIHdoaWNoIGNhbiBiZSBpbnRlcnByZXRlZCBhcyB0aGUgcHJvYmFiaWxpdHkKdGhhdCB0aGUgcGFpciBvZiBnZW5lIGNvcGllcyBpbiBhbiBpbmRpdmlkdWFsIHJhbmRvbWx5IHNhbXBsZWQgZnJvbSB0aGUgcG9wdWxhdGlvbiBhcmUgX2lkZW50aWNhbApieSBkZXNjZW50Xywgb3IgSUJEIGZvciBzaG9ydC4gIEZvciBvdXIgcHVycG9zZXMgaW4gdGhpcyBzZXNzaW9uLCB3ZSB3aWxsIHRha2UgImlkZW50aWNhbCBieSBkZXNjZW50IiB0byBtZWFuIHRoYXQKdGhleSBhcmUgYm90aCBjb3BpZXMgb2YgdGhlIHNhbWUsIHJlY2VudCBhbmNlc3RyYWwgZ2VuZSBjb3B5LiAgTW9yZSBpbXBvcnRhbnQgdGhhbiB0aGUgZXhhY3QKZGVmaW5pdGlvbiBvZiAiaWRlbnRpY2FsIGJ5IGRlc2NlbnQiIGFkb3B0ZWQgaGVyZSBhcmUgdGhlIGNvbnNlcXVlbmNlcyBmb3IgdHdvIGdlbmUgY29waWVzIG9mCmJlaW5nIElCRC4gIEFuZCBpbiB0aGlzIGNhc2UsIHRoYXQgaXMgdmVyeSBzaW1wbGU6IHdlIHdpbGwgYXNzdW1lIHRoYXQgaWYgCnR3byBnZW5lIGNvcGllcyBhcmUgSUJELCB0aGVuIHRoZXkgbXVzdCBhbHNvIGJlIHRoZSBzYW1lIGFsbGVsaWMgdHlwZS4gIEluIG90aGVyCndvcmRzLCBpZiB0d28gZ2VuZSBjb3BpZXMgYXJlIElCRCwgYW5kIHRoZSBmaXJzdCBvZiB0aGVtIGlzIGFsbGVsZSAkQSQsIHRoZW4gdGhlIHNlY29uZCBtdXN0CmFsc28gYmUgYWxsZWxlICRBJC4gIAoKU28sIGdpdmVuIHRoZSBpbmJyZWVkaW5nIGNvZWZmaWNpZW50ICRmJCwgd2UgY2FuIGNvbXB1dGUgdGhlIHByb2JhYmlsaXR5IHRoYXQKYSByYW5kb21seSBzYW1wbGVkIGluZGl2aWR1YWwgaGFzIHRoZSBnZW5vdHlwZSAkQUEkLCAkQWEkLCBvciAkYWEkLiAgRmlyc3QsIGxldCB1cyBjb25zaWRlcgokUChBQSkkOiB3aXRoIHByb2JhYmlsaXR5ICRmJCB0aGUgdHdvIGdlbmUgY29waWVzIGF0IGEgbG9jdXMgaW4gdGhlIGluZGl2aWR1YWwgYXJlIElCRCwgCmluIHdoaWNoIGNhc2Ugb25seSB0aGUgZmlyc3QgZ2VuZSBjb3B5IG11c3QgYnkgJEEkLCBzaW5jZSB0aGUgc2Vjb25kIG9uZSB3aWxsIGJlIHRvby4gIE9uIHRoZSBvdGhlciBoYW5kLCB3aXRoIHByb2JhYmlsaXR5ICQoMS1mKSQgdGhlIHR3byBnZW5lIGNvcGllcyBhdCB0aGUgbG9jdXMgaW4gdGhlCmluZGl2aWR1YWwgYXJlIG5vdCBJQkQsIGFuZCBzbyB0aGUgcHJvYmFiaWxpdHkgb2YgYmVpbmcgJEFBJCBpcyBqdXN0IHRoZSBzdGFuZGFyZCBIYXJkeS1XZWluYmVyZyAKcHJvYmFiaWxpdHksICRQX1xtYXRocm17SFd9KEFBKSA9IHBeMiQuICBIZW5jZSwgdW5kZXIgdGhlIGluYnJlZWRpbmcgbW9kZWw6CiQkClxiZWdpbnthbGlnbmVkfQpQKEFBKSAmPSBmcCArICgxLWYpcF4yIFxcClAoQWEpICY9IGZcdGltZXMgMCArICgxLWYpMnAoMS1wKSBcXApQKGFhKSAmPSBmKDEtcCkgKyAoMS1mKSgxLXApXjIKXGVuZHthbGlnbmVkfQokJAoKIyMjIFRoZSBsaWtlbGlob29kCk5vdyByZWNhbGwgdGhhdCBvdXIgZGF0YSBhcmUgJChuX3tBQX0sIG5fe0FhfSwgbl97YWF9KSQtLS10aGUgbnVtYmVycyBvZiB0aGUgZGlmZmVyZW50IGdlbm90eXBlcwpvYnNlcnZlZCBpbiB0aGUgc2FtcGxlLiAgVG8gbW92ZSBmb3J3YXJkIGluIGluZmVyZW5jZSwgd2UgbmVlZCB0byBiZSBhYmxlIHRvIGNvbXB1dGUgdGhlIApsaWtlbGlob29kLCB3aGljaCBpcyB0aGUgcHJvYmFiaWxpdHkgb2Ygb3VyIGRhdGEgZ2l2ZW4gdGhlIHZhbHVlcyBvZiB0aGUgcGFyYW1ldGVyczogJFAobl97QUF9LCBuX3tBYX0sIG5fe2FhfXxwLGYpJC4KTm90ZSBoZXJlIHRoYXQgdGhlIHR3byBwYXJhbWV0ZXJzIGluIG91ciBtb2RlbCBhcmUgJHAkLCB0aGUgZnJlcXVlbmN5IG9mIHRoZSAkQSQgYWxsZWxlIGluIHRoZSBwb3B1bGF0aW9uLAphbmQgJGYkLCB0aGUgcG9wdWxhdGlvbiBpbmJyZWVkaW5nIGNvZWZmaWNpZW50LiAgV2UgYXNzdW1lIHRoYXQgZWFjaCBpbmRpdmlkdWFsIGlzIHNhbXBsZWQgaW5kZXBlbmRlbnRseQpmcm9tIHRoZSBwb3B1bGF0aW9uLCBzbyB0aGUgbGlrZWxpaG9vZCBpcyBhIG11bHRpbm9taWFsOgokJApQKG5fe0FBfSwgbl97QWF9LCBuX3thYX0pID0gXGZyYWN7biF9e25fe0FBfSEgKyBuX3tBYX0hICsgbl97YWF9IX1+CltmcCArICgxLWYpcF4yXV57bl97QUF9fX4KWygxLWYpMnAoMS1wKV1ee25fe0FhfX1+CltmKDEtcCkgKyAoMS1mKSgxLXApXjJdXntuX3thYX19CiQkClRoZSBtdWx0aW5vbWlhbCBjb2VmZmljaWVudCBpcyBhIGNvbnN0YW50IHdpdGggcmVzcGVjdCB0byAkcCQgYW5kICRmJCBzbyBpdCB3aWxsIGRyb3Agb3V0LiAgCgojIyMgVGhlIHByaW9ycwoKV2UgbmVlZCBwcmlvcnMgb2YgJHAkIGFuZCAkZiQuICBUaGVzZSBhcmUgcHJvcG9ydGlvbnMsIHNvIGEgbmF0dXJhbCBjaG9pY2UgaXMgdGhlIGJldGEgZGlzdHJpYnV0aW9uLiAgCkxldCdzIGRlZmluZSAkZiBcc2ltIFxtYXRocm17QmV0YX0oXGFscGhhX2YsIFxiZXRhX2YpJCBhbmQgJHAgXHNpbSBcbWF0aHJte0JldGF9KFxhbHBoYV9wLCBcYmV0YV9wKSQsCmFuZCB3ZSB3aWxsIHNldCB1cCBvdXIgbW9kZWwgdGhhdCB3YXksIHRob3VnaCB0aGUgZGVmYXVsdCB2YWx1ZXMgd2Ugd2lsbCB1c2UgYXJlCiRcYWxwaGFfZiA9IFxiZXRhX2YgPSBcYWxwaGFfcCA9IFxiZXRhX3AgPSAxJCB3aGljaCB3aWxsIGdpdmUgdXMgdW5pZm9ybSBwcmlvcnMgZm9yICRmJCBhbmQgJHAkLiAgCgojIyMgVGhlIGpvaW50IHByb2JhYmlsaXR5CgpUaGlzIGlzIGp1c3QgdGhlIHByb2R1Y3Qgb2YgdGhlIHByaW9ycyBhbmQgdGhlIGxpa2VsaWhvb2RzLiAgSW4gaXRzIGZ1bGwgZ2xvcnksIGl0IGxvb2tzIGxpa2U6CiQkClxiZWdpbnthbGlnbmVkfQpQKG5fe0FBfSwgbl97QWF9LCBuX3thYX0sIGYsIHAgfCBcYWxwaGFfZiwgXGJldGFfZiwgXGFscGhhX3AsIFxiZXRhX3ApICYgPSAKXGZyYWN7XEdhbW1hKFxhbHBoYV9mICsgXGJldGFfZil9e1xHYW1tYShcYWxwaGFfZilcR2FtbWEoXGJldGFfZil9Zl57XGFscGhhX2YgLSAxfSgxLWYpXntcYmV0YV9mIC0gMX0KXGZyYWN7XEdhbW1hKFxhbHBoYV9wICsgXGJldGFfcCl9e1xHYW1tYShcYWxwaGFfcClcR2FtbWEoXGJldGFfcCl9cF57XGFscGhhX3AgLSAxfSgxLXApXntcYmV0YV9wIC0gMX0gXHRpbWVzIFxcCiYgXGZyYWN7biF9e25fe0FBfSEgKyBuX3tBYX0hICsgbl97YWF9IX1+CltmcCArICgxLWYpcF4yXV57bl97QUF9fX4KWygxLWYpMnAoMS1wKV1ee25fe0FhfX1+CltmKDEtcCkgKyAoMS1mKSgxLXApXjJdXntuX3thYX19ClxlbmR7YWxpZ25lZH0KJCQKV2Ugd2lsbCBiZSB1c2luZyB0aGlzIGluIApNQ01DIGluIHdoaWNoIHRoZSB0aGUgaHlwZXJwcmlvcnMgJChcYWxwaGFfZiwgXGJldGFfZiwgXGFscGhhX3AsIFxiZXRhX3ApJCBhbmQgdGhlIGRhdGEgYXJlIGZpeGVkLgpUaHVzIHRoZSB0ZXJtcyAoZmFjdG9ycykgdGhhdCBpbnZvbHZlIF9vbmx5XyB0aGUgZGF0YSBhbmQgdGhlIGh5cGVycHJpb3JzIGFyZSBjb25zdGFudHMgdGhhdCB3aWxsIGRyb3AKb3V0IG9mIHRoZSBIYXN0aW5ncyByYXRpbywgc28gdGhleSBjYW4gYmUgc2FmZWx5IGlnbm9yZWQuICBTbywgb3VyIGpvaW50IHByb2JhYmlsaXR5IGNhbiBiZSBjb21wdXRlZAphcyBzb21ldGhpbmcgdGhhdCBsb29rcyBsaWtlOgokJApcYmVnaW57YWxpZ25lZH0KUChuX3tBQX0sIG5fe0FhfSwgbl97YWF9LCBmLCBwIHwgXGFscGhhX2YsIFxiZXRhX2YsIFxhbHBoYV9wLCBcYmV0YV9wKSAmIFxwcm9wdG8gCmZee1xhbHBoYV9mIC0gMX0oMS1mKV57XGJldGFfZiAtIDF9CnBee1xhbHBoYV9wIC0gMX0oMS1wKV57XGJldGFfcCAtIDF9IFx0aW1lcyBcXAomIH5+fn5bZnAgKyAoMS1mKXBeMl1ee25fe0FBfX1+ClsoMS1mKTJwKDEtcCldXntuX3tBYX19fgpbZigxLXApICsgKDEtZikoMS1wKV4yXV57bl97YWF9fQpcZW5ke2FsaWduZWR9CiQkCldlIHdpbGwgaW1wbGVtZW50IHRoaXMgaW4gYSBmdW5jdGlvbiB0aGF0IHJldHVybnMgdGhlIF9sb2dfIG9mIHRoZSBhYm92ZSBxdWFudGl0eQpzbyB0aGF0IHdlIHdvbid0IHJ1biBpbnRvIHVuZGVyZmxvdyBpc3N1ZXMgd2l0aCB2ZXJ5IGxhcmdlIHNhbXBsZXM6CmBgYHtyIGpvaW50fQojJyB0aGUgbG9nIG9mIHRoZSBqb2ludCBwcm9iYWJpbGl0eSBvZiBhbGwgdGhlIGRhdGEgYW5kIHBhcmFtYXRlcnMgZ2l2ZW4gdGhlIHByaW9ycwojJwojJyBUaGlzIGlzIGNvbXB1dGVkIGhhdmluZyBkcm9wcGVkIGFsbCB0aGUgY29uc3RhbnQgZmFjdG9ycyBpbiB0aGUgcHJvYmFiaWxpdHkuCiMnIEBwYXJhbSBuIGEgdmVjdG9yIG9mIHRocmVlIGVsZW1lbnRzOiAobkFBLCBuQWEsIG5hYSksIHRoZSBudW1iZXIgb2YgQUEncywgdGhlCiMnIG51bWJlciBvZiBBYSdzLCBhbmQgdGhlIG51bWJlciBvZiBhYSdzCiMnIEBwYXJhbSBmIHRoZSBpbmJyZWVkaW5nIGNvZWZmaWVudAojJyBAcGFyYW0gcCB0aGUgZnJlcXVlbmN5IG9mIHRoZSBBIGFsbGVsZQojJyBAcGFyYW0gcHJpIGEgdmVjdG9yIG9mIGZvdXIgY29tcG9uZW50czogKGFscGhhX2YsIGJldGFfZiwgYWxwaGFfcCwgYmV0YV9wKSB3aGljaCBhcmUgdGhlIAojJyBiZXRhIHBhcmFtZXRlcnMgZm9yIHRoZSBwcmlvcnMgb24gZiBhbmQgcC4gIEJ5IGRlZmF1bHQgdGhleSBhcmUgYWxsIDEuCmxvZ19qb2ludF9wcm9iIDwtIGZ1bmN0aW9uKG4sIGYsIHAsIHByaSA9IGMoMSwgMSwgMSwgMSkpIHsKICAjIG5vdCBnb2luZyB0byBkbyBtdWNoIGVycm9yIGNoZWNraW5nIGhlcmUKICAKICAjIGNvbXB1dGUgdGhlIHJhdyB2YWx1ZXMsIGFueXRoaW5nIG91dHNpZGUgb2YgdGhlIHVuaXQgaW50ZXJ2YWwgd2Ugd2lsbCBzZW5kCiAgIyBiYWNrIGFzIE5hTgogIGlmZWxzZShmIDw9IDAgfCBmID49IDEgfCBwIDw9IDAgfCBwID49IDEsIE5hTiwKICAgICAgICAgbG9nKGYpICogKHByaVsxXSAtIDEpICsgCiAgICAgICAgICAgbG9nKDEgLSBmKSAqIChwcmlbMl0gLSAxKSArCiAgICAgICAgICAgbG9nKHApICogKHByaVszXSAtIDEpICsKICAgICAgICAgICBsb2coMSAtIHApICogKHByaVs0XSAtIDEpICsKICAgICAgICAgICBsb2coZiAqIHAgKyAoMSAtIGYpICogcCBeIDIpICogblsxXSArCiAgICAgICAgICAgbG9nKCgxIC0gZikgKiAyICogcCAqICgxIC0gcCkpICogblsyXSArIAogICAgICAgICAgIGxvZyhmICogKDEgLSBwKSArICgxIC0gZikgKiAoMSAtIHApIF4gMikgKiBuWzNdKQogIAogIAoKfQpgYGAKTm90ZSB0aGF0IHRoaXMgZnVuY3Rpb24gaXMgdmVjdG9yaXplZCBvdmVyICRmJCBhbmQgJHAkLCBidXQgbm90ICRuJCBvciB0aGUgcHJpb3JzLgoKCiMjIyBBIDMtRCBwbG90CgpXZSBjYW4gY29tcHV0ZSB0aGUgam9pbnQgcHJvYmFiaWxpdHkgb2YgYWxsIHRoZSB2YXJpYWJsZXMgZWFzaWx5LCBhbmQsIGJlY2F1c2UgdGhpcyBpcyBhIHRveSBwcm9ibGVtIAppbiB0d28gZGltZW5zaW9ucywgd2UgY2FuIHZpc3VhbGl6ZSByb3VnaGx5IHdoYXQgdGhlIHBvc3RlcmlvciBzdXJmYWNlIHdpbGwgbG9vayBsaWtlIGJ5IApjb21wdXRpbmcgdmFsdWVzIG9uIGEgZ3JpZCBhbmQgbm9ybWFsaXppbmcgdGhvc2UgdmFsdWVzIHNvIHRoZXkgc3VtIHRvIG9uZS4gIExldCdzIGRvIHRoYXQsIHNpbmNlCml0IGlzIGEgZ29vZCBjaGFuY2UgdG8gaW50cm9kdWNlIHRoZSBbcGxvdGx5XShodHRwczovL3Bsb3QubHkvci8pIHBhY2thZ2UgdG8gYW55b25lIHRoYXQgbWlnaHQgbm90IHlldCBrbm93IGl0LgoKU28sIGxldCdzIHRha2UgdGhlIGV4YW1wbGUgZnJvbSB0aGUgbGVjdHVyZSBhbmQgc2V0IG91ciBkYXRhIHRvIGJlICRuX3tBQX0gPSAzMCQsICRuX3tBYX0gPSAxMCQsIGFuZCAKJG5fe2FhfSA9IDEwJC4gIFRob3NlIGFyZSB0aGUgZXhwZWN0ZWQgdmFsdWVzIGlmICRmID0gMC41JCBhbmQgJHAgPSAwLjckLApgYGB7cn0KbmRhdGEgPC0gYygzMCwgMTAsIDEwKQpgYGAKYW5kIHRoZW4gY29tcHV0ZSB0aGUgbG9nIHByb2IsIGV4cG9uZW50aWF0ZSBpdCwgYW5kIG5vcm1hbGl6ZSBpdCBvdmVyIGEgZ3JpZCBvZiB2YWx1ZSBmb3IKJGYkIGFuZCAkcCQ6CmBgYHtyfQpmX3ZhbHMgPC0gc2VxKDAsIDEsIGJ5ID0gMC4wMykKcF92YWxzIDwtIHNlcSgwLCAxLCBieSA9IDAuMDMpCgojIG1ha2UgYSB0aWR5IHRpYmJsZSBvZiB2YWx1ZXMgCmdyaWRfdmFscyA8LSBleHBhbmQuZ3JpZChmID0gZl92YWxzLCBwID0gcF92YWxzKSAlPiUKICBhc190aWJibGUoKSAlPiUKICBtdXRhdGUoam9pbnQgPSBleHAobG9nX2pvaW50X3Byb2IobmRhdGEsIGYsIHApKSkgJT4lCiAgbXV0YXRlKG5vcm1fam9pbnQgPSBqb2ludCAvIHN1bShqb2ludCwgbmEucm0gPSBUUlVFKSkgJT4lCiAgc2VsZWN0KC1qb2ludCkKCiMgdGhlbiBwdXQgdGhvc2UgdmFsdWVzIGludG8gYSBtYXRyaXgsIHdpdGggcm93cyBjb3JyZXNwb25kaW5nIHRvIGYgYW5kIGNvbHMgdG8gcApwcm9icyA8LSBtYXRyaXgoZ3JpZF92YWxzJG5vcm1fam9pbnQsIG5yb3cgPSBsZW5ndGgoZl92YWxzKSwgbmNvbCA9IGxlbmd0aChwX3ZhbHMpKQoKYGBgCk5vdyB3ZSBjYW4gcGxvdCBpdCB3aXRoIHBsb3RseToKYGBge3IsIGZpZy53aWR0aD04fQpwbG90X2x5KHggPSB+cF92YWxzLCB5ID0gfmZfdmFscywgeiA9IH5wcm9icykgJT4lCiAgYWRkX3N1cmZhY2UoKQpgYGAKClRyeSBpbnRlcmFjdGluZyB3aXRoIHRoYXQgcGxvdCwgZXNwZWNpYWxseSBpZiB5b3UgYXJlIG5vdCBmYW1pbGlhciB3aXRoIHBsb3RseS4gIFlvdSBjYW4gem9vbSwgcGFuLCBhbmQKcmV2b2x2ZSBpdCwgYW5kIHlvdSBjYW4gYWxzbyBsb29rIGF0IGluZGl2aWR1YWwgdmFsdWVzIGJ5IG1vdXNpbmcgb3ZlciB3aXRoaW4gdGhlIHBsb3QuCgojIyAiMi1EIiBNZXRyb3Bsb2lzLUhhc3RpbmdzIFNhbXBsZXIKCldlIG5vdyBzdGFydCBvdXIgZm9yYXlzIGludG8gZGlmZmVyZW50IE1DTUMgc2FtcGxlcnMsIHJvdWdobHkgZm9sbG93aW5nIHRoZSBsZWN0dXJlIG5vdGVzIGZyb20gdGhlIHNlc3Npb24uIApUaGUgZmlyc3QgaXMgYSBzYW1wbGVyIGluIHdoaWNoIHdlIHByb3Bvc2UgY2hhbmdlcyB0byBib3RoICRmJCBhbmQgJHAkIGFuZCB0aGVuIHdlIGFjY2VwdCBvciByZWplY3QgYm90aCBvZiB0aG9zZQpwcm9wb3NhbGVkIGNoYW5nZXMsIHRvZ2V0aGVyLCBpbiBvbmUgZmVsbCBzd29vcCwgYWNjb3JkaW5nIHRvIHRoZSBIYXN0aW5ncyBSYXRpby4KCkZvciBvdXIgcHJvcG9zYWxzIGluIHRoaXMgY2FzZSB3ZSB3aWxsIHVzZSB0d28gaW5kZXBlbmRlbnQsIHN5bW1tZXRyaWNhbCBub3JtYWwgZGlzdHJpYnV0aW9ucyBjZW50ZXJlZApvbiB0aGUgY3VycmVudCB2YWx1ZXMuICBXZSB3aWxsIHdyYXAgdXAgdGhlIHdob2xlIHByb2Nlc3MgaW4gYSBzaW5nbGUgZnVuY3Rpb24KY2FsbGVkIGBtY21jXzJkX21oKClgLgpgYGB7cn0KIycgZnVuY3Rpb24gdG8gZG8gTUNNQyB1c2luZyBhICIyLUQiIE1ldHJvcG9saXMtSGFzdGluZ3Mgc2FtcGxlcgojJyBAcGFyYW0gbmRhdGEgYSB0aHJlZS12ZWN0b3IgKG5BQSwgbkFhLCBuYWEpIG9mIHRoZSBvYnNlcnZlZCBkYXRhCiMnIEBwYXJhbSBwcmkgYSB2ZWN0b3Igb2YgZm91ciBjb21wb25lbnRzOiAoYWxwaGFfZiwgYmV0YV9mLCBhbHBoYV9wLCBiZXRhX3ApCiMnIEBwYXJhbSBpbml0IGEgdHdvIHZlY3RvciBvZiBzdGFydGluZyB2YWx1ZXMgKGYsIHApLiAgRWFjaCBzaG91bGQgYmUgd2l0aGluIHRoZQojJyB1bml0IGludGVydmFsLgojJyBAcGFyYW0gc3dlZXBzIHRoZSBudW1iZXIgb2Ygc3dlZXBzIChpLmUgcHJvcG9zZWQgY2hhbmdlcykgdG8gZG8gaW4gdGhlIE1DTUMgY2hhaW4uCiMnIEBwYXJhbSBmX3NkIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIG5vcm1hbCBkaXN0cmlidXRpb24gZm9yIHByb3Bvc2luZyBuZXcgdmFsdWVzIHRvIGYKIycgQHBhcmFtIHBfc2QgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbiBmb3IgcHJvcG9zaW5nIG5ldyB2YWx1ZXMgdG8gcAojJyBAcmV0dXJuIHJldHVybnMgYSB0aWJibGUgb2YgcHJvcG9zYWxzIG1hZGUsIHZhbHVlcyB2aXNpdGVkLCB2YWx1ZXMgb2YgTUggcmF0aW8sIGV0YwptY21jXzJkX21oIDwtIGZ1bmN0aW9uKG5kYXRhLCAKICAgICAgICAgICAgICAgICAgICAgICBwcmkgPSBjKDEsIDEsIDEsIDEpLCAKICAgICAgICAgICAgICAgICAgICAgICBpbml0ID0gYyguMiwgLjUpLCAKICAgICAgICAgICAgICAgICAgICAgICBzd2VlcHMgPSA1MDAsCiAgICAgICAgICAgICAgICAgICAgICAgZl9zZCA9IDAuMDcsCiAgICAgICAgICAgICAgICAgICAgICAgcF9zZCA9IDAuMDcpIHsKCiAgIyBjcmVhdGUgdmVjdG9ycyBpbiB3aGljaCB0byBzdG9yZSBvdXRwdXQuIE5vdGUgdGhhdCB3ZSB3aWxsIGJlIHN0b3JpbmcgCiAgIyB0aGUgcHJvcG9zZWQgdmFsdWVzIGFuZCB0aGUgTUgtcmF0aW8gZWFjaCBzd2VlcCwgdG9vLCBmb3IgbGF0ZXIgYW5hbHlzaXMuCiAgZiA8LSBwIDwtIGZwcm9wIDwtIHBwcm9wIDwtIG1oX3JhdGlvIDwtIHJlcChOQV9yZWFsXywgc3dlZXBzICsgMSkKICBhY2NlcHRlZF9mIDwtIGFjY2VwdGVkX3AgPC0gcmVwKE5BLCBzd2VlcHMgKyAxKQogIAogICMgcHV0IGluaXRpYWwgdmFsdWVzIGluCiAgZlsxXSA8LSBpbml0WzFdCiAgcFsxXSA8LSBpbml0WzJdCiAgCiAgIyB0aGVuIGN5Y2xlIG92ZXIgc3dlZXBzCiAgZm9yIChpIGluIDE6c3dlZXBzKSB7CiAgICAKICAgICMgcHJvcG9zZSBuZXcgdmFsdWVzCiAgICBmcHJvcFtpXSA8LSBybm9ybSgxLCBmW2ldLCBmX3NkKQogICAgcHByb3BbaV0gPC0gcm5vcm0oMSwgcFtpXSwgcF9zZCkKICAgIAogICAgIyBjb21wdXRlIHRoZSBoYXN0aW5ncyByYXRpbwogICAgIyB0aGUgbG9nIE0tSCByYXRpbyBpcyB0aGUgZGlmZmVyZW5jZSBvZiB0aGUgbG9nIGpvaW50IHByb2JzLgogICAgIyBzaW5jZSB0aGUgcHJvcG9zYWwgZGlzdHJpYnV0aW9ucyBhcmUgc3ltbWV0cmljYWwgdGhleSBkcm9wIG91dCBvZiB0aGUgcmF0aW8uCiAgICBtaF9yYXRpb1tpXSA8LSBleHAobG9nX2pvaW50X3Byb2IobmRhdGEsIGZwcm9wW2ldLCBwcHJvcFtpXSwgcHJpKSAtCiAgICAgIGxvZ19qb2ludF9wcm9iKG5kYXRhLCBmW2ldLCBwW2ldLCBwcmkpKQogICAgCiAgICAjIG5vdywgaWYgbWhfcmF0aW9baV0gaXMgTmFOIGl0IG1lYW5zIHRoYXQgZiBvciBwIHdhcyBwcm9wb3NlZCBvdXRzaWRlIG9mIHRoZSB1bml0IGludGVydmFsCiAgICAjIGFuZCBpdCBzaG91bGQgYmUgcmVqZWN0ZWQgaW1tZWRpYXRlbHkuICBJZiBub3QsIHRoZW4gd2Ugc2ltdWxhdGUgYSB1bmlmb3JtIFIuVi4gb24gKDAsIDEpCiAgICAjIGFuZCByZWplY3QgdGhlIHByb3Bvc2FsIGlmIHRoYXQgbnVtYmVyIGlzIGdyZWF0ZXIgdGhhbiB0aGUgTUgtcmF0aW8uCiAgICBpZiAoaXMubmFuKG1oX3JhdGlvW2ldKSB8fCBydW5pZigxKSA+IG1oX3JhdGlvW2ldKSB7IyByZWplY3QhCiAgICAgIGFjY2VwdGVkX2ZbaV0gPC0gRkFMU0UKICAgICAgYWNjZXB0ZWRfcFtpXSA8LSBGQUxTRQogICAgICBmW2kgKyAxXSA8LSBmW2ldCiAgICAgIHBbaSArIDFdIDwtIHBbaV0KICAgIH0gZWxzZSB7IyBhY2NlcHQhCiAgICAgIGFjY2VwdGVkX2ZbaV0gPC0gVFJVRQogICAgICBhY2NlcHRlZF9wW2ldIDwtIFRSVUUKICAgICAgZltpICsgMV0gPC0gZnByb3BbaV0KICAgICAgcFtpICsgMV0gPC0gcHByb3BbaV0KICAgIH0KICAgIAogIH0KICAKICAjIGluIHRoZSBlbmQsIG1ha2UgYSB0aWJibGUgYW5kIHJldHVybgogIHRpYmJsZShzd2VlcCA9IDE6KHN3ZWVwcyArIDEpLAogICAgICAgICBmID0gZiwKICAgICAgICAgcCA9IHAsIAogICAgICAgICBwcm9wb3NlZF9mID0gZnByb3AsCiAgICAgICAgIHByb3Bvc2VkX3AgPSBwcHJvcCwKICAgICAgICAgbWhfcmF0aW8gPSBtaF9yYXRpbywKICAgICAgICAgYWNjZXB0ZWRfZiA9IGFjY2VwdGVkX2YsCiAgICAgICAgIGFjY2VwdGVkX3AgPSBhY2NlcHRlZF9wCiAgICAgICAgICkKfQpgYGAKCioqQSBicmllZiBub3RlOioqIEluIHRoZSBhYm92ZSBmdW5jdGlvbiAoYW5kIHRoZSBvbmUgZm9sbG93aW5nKSB3ZSBhcmUgYmVpbmcgY2FyZWZ1bCB0byByZWNvcmQKbm90IGp1c3QgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIGNoYWluLCBidXQgYWxzbwpldmVyeSBfcHJvcG9zZWRfIHZhbHVlLiAgVHlwaWNhbGx5IHRoaXMgaXMgbm90IGRvbmUgaW4gTUNNQy4gIFJhdGhlciwgaXQgaXMgbW9yZSB1c3VhbCB0byBzaW1wbHkKcmVjb3JkIHRoZSBzdGF0ZSBvZiB0aGUgY2hhaW4gYXQgZWFjaCBzd2VlcCAob3IgYXQgc29tZSAidGhpbm5lZCIgaW50ZXJ2YWwgb2Ygc3dlZXBzKS4gSG93ZXZlcgp3ZSB3YW50ZWQgdG8ga2VlcCBhIGZ1bGwgcmVjb3JkIG9mIHRoZSBwcm9ncmVzc2lvbiBvZiBhbGwgdGhlIHZhcmlhYmxlcyBzbyB0aGF0IHRoZXkgd291bGQgYmUKYXZhaWxhYmxlIGZvciAgc3R1ZGVudHMgdG8gcGVydXNlIG9yIGFuYWx5emUuIAoKCiMjIENvbXBvbmVudC13aXNlIE1ldHJvcG9saXMtSGFzdGluZ3MgU2FtcGxlcgoKUmF0aGVyIHRoYW4gcHJvcG9zaW5nIGNoYW5nZXMgdG8gYm90aCAkZiQgYW5kICRwJCBiZWZvcmUgYWNjZXB0aW5nIG9yIHJlamVjdGluZyB0aGVtLAp3ZSBjYW4gcHJvcG9zZSBqdXN0IGEgY2hhbmdlIHRvICRmJCAoc2F5KSBhbmQgYWNjZXB0IG9yIHJlamVjdCB0aGUgcHJvcG9zYWwsIGFuZCB0aGVuIHByb3Bvc2UganVzdCBhIGNoYW5nZQp0byAkcCQsIGFuZCB0aGVuIGFjY2VwdCBvciByZWplY3QgdGhhdC4gIFRoaXMgaXMgY2FsbGVkIGNvbXBvbmVudC13aXNlIE1ldHJvcG9saXMtSGFzdGluZ3Mgc2FtcGxpbmcuIApVbmRlcmx5aW5nIGl0IGlzIGEgY2VudHJhbCB0aGVtZSBpbiBNQ01DLCB3aGljaCBpcyB0aGF0IGp1c3Qgb25lIG9yIGEgZmV3IGRpbWVuc2lvbnMgY2FuIGJlIGNoYW5nZWQKd2l0aCBlYWNoIHByb3Bvc2FsLCBidXQgYXMgbG9uZyBhcyB0aGUgYWNjZXB0YW5jZSBvciByZWplY3Rpb24gb2YgZWFjaCBwcm9wb3NhbCBpcyBkb25lIGluCmEgd2F5IHRoYXQgc2F0aXNmaWVzIGRldGFpbGVkIGJhbGFuY2UsIF9hbmRfIGFzIGxvbmcgYXMgYWxsIHRoZSBkaWZmZXJlbnQgdHlwZXMgb2YgcHJvcG9zYWxzLAp3aGVuIHVzZWQgdG9nZXRoZXIgY3JlYXRlIGFuIGlycmVkdWNpYmxlIGNoYWluIGFyb3VuZCB0aGUgc3BhY2UsIHRoZW4geW91IGdldCBhIHZhbGlkIE1DTUMgc2FtcGxlci4KCldlIG1ha2UgYSBmdW5jdGlvbiB0aGF0IGxvb2tzIG11Y2ggbGlrZSBgbWNtY18yZF9taCgpYCwgYnV0IGluIHdoaWNoIHRoZSBwcm9wb3NhbCBhbmQgYWNjZXB0YW5jZSBzdGVwcwpmb3IgJGYkIGFuZCAkcCQgYXJlIGRvbmUgc2VwYXJhdGVseSB3aXRoaW4gZWFjaCBzd2VlcC4gVGhpcyBpcyBnb2luZyB0byBsb29rIGEgbGl0dGxlIGJpdCB3ZWlyZApiZWNhdXNlIHdlIGRvIGVhY2ggdXBkYXRlIHdpdGhpbiB0aGUgc3dlZXAgYnV0IHNldCB0aGUgbmV3IHZhbHVlIG9mICRmJCBpbiB0aGUgIm5leHQiIHN3ZWVwLgooWW91J2xsIHNlZSBiZWxvdy4uLikKYGBge3J9CiMnIGZ1bmN0aW9uIHRvIGRvIE1DTUMgdXNpbmcgYSBjb21wb25lbnQtd2lzZSBNZXRyb3BvbGlzLUhhc3RpbmdzIHNhbXBsZXIKIycgQHBhcmFtIG5kYXRhIGEgdGhyZWUtdmVjdG9yIChuQUEsIG5BYSwgbmFhKSBvZiB0aGUgb2JzZXJ2ZWQgZGF0YQojJyBAcGFyYW0gcHJpIGEgdmVjdG9yIG9mIGZvdXIgY29tcG9uZW50czogKGFscGhhX2YsIGJldGFfZiwgYWxwaGFfcCwgYmV0YV9wKQojJyBAcGFyYW0gaW5pdCBhIHR3byB2ZWN0b3Igb2Ygc3RhcnRpbmcgdmFsdWVzIChmLCBwKS4gIEVhY2ggc2hvdWxkIGJlIHdpdGhpbiB0aGUKIycgdW5pdCBpbnRlcnZhbC4KIycgQHBhcmFtIHN3ZWVwcyB0aGUgbnVtYmVyIG9mIHN3ZWVwcyAoaS5lIHByb3Bvc2VkIGNoYW5nZXMpIHRvIGRvIGluIHRoZSBNQ01DIGNoYWluLgojJyBAcGFyYW0gZl9zZCB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uIGZvciBwcm9wb3NpbmcgbmV3IHZhbHVlcyB0byBmCiMnIEBwYXJhbSBwX3NkIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIG5vcm1hbCBkaXN0cmlidXRpb24gZm9yIHByb3Bvc2luZyBuZXcgdmFsdWVzIHRvIHAKIycgQHJldHVybiByZXR1cm5zIGEgdGliYmxlIG9mIHByb3Bvc2FscyBtYWRlLCB2YWx1ZXMgdmlzaXRlZCwgdmFsdWVzIG9mIE1IIHJhdGlvLCBldGMKbWNtY19jd19taCA8LSBmdW5jdGlvbihuZGF0YSwgCiAgICAgICAgICAgICAgICAgICAgICAgcHJpID0gYygxLCAxLCAxLCAxKSwgCiAgICAgICAgICAgICAgICAgICAgICAgaW5pdCA9IGMoLjIsIC41KSwgCiAgICAgICAgICAgICAgICAgICAgICAgc3dlZXBzID0gNTAwLAogICAgICAgICAgICAgICAgICAgICAgIGZfc2QgPSAwLjA3LAogICAgICAgICAgICAgICAgICAgICAgIHBfc2QgPSAwLjA3KSB7CgogICMgY3JlYXRlIHZlY3RvcnMgaW4gd2hpY2ggdG8gc3RvcmUgb3V0cHV0LiBOb3RlIHRoYXQgd2Ugd2lsbCBiZSBzdG9yaW5nIAogICMgdGhlIHByb3Bvc2VkIHZhbHVlcyBhbmQgdGhlIE1ILXJhdGlvIGVhY2ggc3dlZXAsIHRvbywgZm9yIGxhdGVyIGFuYWx5c2lzLgogIGYgPC0gcCA8LSBmcHJvcCA8LSBwcHJvcCA8LSBtaF9yYXRpb19mIDwtIG1oX3JhdGlvX3AgPC0gcmVwKE5BX3JlYWxfLCBzd2VlcHMgKyAxKQogIGFjY2VwdGVkX2YgPC0gYWNjZXB0ZWRfcCA8LSByZXAoTkEsIHN3ZWVwcyArIDEpCiAgCiAgIyBwdXQgaW5pdGlhbCB2YWx1ZXMgaW4KICBmWzFdIDwtIGluaXRbMV0KICBwWzFdIDwtIGluaXRbMl0KICAKICAjIHRoZW4gY3ljbGUgb3ZlciBzd2VlcHMKICBmb3IgKGkgaW4gMTpzd2VlcHMpIHsKICAgIAogICAgIyBwcm9wb3NlIG5ldyB2YWx1ZSBmb3IgZgogICAgZnByb3BbaV0gPC0gcm5vcm0oMSwgZltpXSwgZl9zZCkKICAgIAogICAgIyBjb21wdXRlIHRoZSBoYXN0aW5ncyByYXRpbyB3aXRoIG9ubHkgYSBjaGFuZ2UgdG8gZiBwcm9wb3NlZAogICAgbWhfcmF0aW9fZltpXSA8LSBleHAobG9nX2pvaW50X3Byb2IobmRhdGEsIGZwcm9wW2ldLCBwW2ldLCBwcmkpIC0KICAgICAgbG9nX2pvaW50X3Byb2IobmRhdGEsIGZbaV0sIHBbaV0sIHByaSkpCiAgICAKICAgICMgdGhlbiBhY2NlcHQgb3IgcmVqZWN0IGl0CiAgICBVIDwtIHJ1bmlmKDEpCiAgICBpZiAoaXMubmFuKG1oX3JhdGlvX2ZbaV0pIHwgcnVuaWYoMSkgPiBtaF9yYXRpb19mW2ldKSB7IyByZWplY3QhCiAgICAgIGFjY2VwdGVkX2ZbaV0gPC0gRkFMU0UKICAgICAgZltpICsgMV0gPC0gZltpXQogICAgfSBlbHNlIHsjIGlmIGFjY2VwdGVkLCB0aGVuIHVwZGF0ZSB0aGUgdmFsdWUgb2YgZgogICAgICBhY2NlcHRlZF9mW2ldIDwtIFRSVUUKICAgICAgZltpICsgMV0gPC0gZnByb3BbaV0gIyBzZXQgdGhlIHZhbHVlLiAgVGhpcyBpcyBhIGxpdHRsZSB3ZWlyZCBiZWNhdXNlIHdlIGFyZSBzdGlsbCBpbiBzd2VlcCBpLgogICAgfQogICAgCiAgICAjIG5vdywgdGhlIGN1cnJlbnQgdmFsdWUgb2YgZiBpcyBzdG9yZWQgaW4gZltpICsgMV0sIGFuZCB3ZSBwcm9wb3NlIGEgbmV3IHZhbHVlIGZvciBwCiAgICBwcHJvcFtpXSA8LSBybm9ybSgxLCBwW2ldLCBwX3NkKQogICAgCiAgICAgIyBjb21wdXRlIHRoZSBoYXN0aW5ncyByYXRpbyB1c2luZyB0aGUgbmV3IGYgYW5kIHRoZSBwcm9wb3NlZCB2YWx1ZSBvZiBwCiAgICBtaF9yYXRpb19wW2ldIDwtIGV4cChsb2dfam9pbnRfcHJvYihuZGF0YSwgZltpICsgMV0sIHBwcm9wW2ldLCBwcmkpIC0KICAgICAgbG9nX2pvaW50X3Byb2IobmRhdGEsIGZbaSArIDFdLCBwW2ldLCBwcmkpKQogICAgCiAgICAKICAgICMgYW5kIHJlamVjdCBvciBhY2NlcHQgdGhlIHByb3Bvc2FsCiAgICBpZiAoaXMubmFuKG1oX3JhdGlvX3BbaV0pIHwgcnVuaWYoMSkgPiBtaF9yYXRpb19wW2ldKSB7IyByZWplY3QhCiAgICAgIGFjY2VwdGVkX3BbaV0gPC0gRkFMU0UKICAgICAgcFtpICsgMV0gPC0gcFtpXQogICAgfSBlbHNlIHsjIGlmIG5vdCBhY2NlcHRlZCB0aGVuIG1ha2UgcCB0aGUgc2FtZSBhcyB0aGUgY3VycmVudCBwCiAgICAgIGFjY2VwdGVkX3BbaV0gPC0gVFJVRQogICAgICBwW2kgKyAxXSA8LSBwcHJvcFtpXQogICAgfQogICAgCiAgfQogIAogICMgaW4gdGhlIGVuZCwgbWFrZSBhIHRpYmJsZSBhbmQgcmV0dXJuCiAgdGliYmxlKHN3ZWVwID0gMTooc3dlZXBzICsgMSksCiAgICAgICAgIGYgPSBmLAogICAgICAgICBwID0gcCwgCiAgICAgICAgIHByb3Bvc2VkX2YgPSBmcHJvcCwKICAgICAgICAgcHJvcG9zZWRfcCA9IHBwcm9wLAogICAgICAgICBtaF9yYXRpb19mID0gbWhfcmF0aW9fZiwKICAgICAgICAgbWhfcmF0aW9fcCA9IG1oX3JhdGlvX3AsCiAgICAgICAgIGFjY2VwdGVkX2YgPSBhY2NlcHRlZF9mLAogICAgICAgICBhY2NlcHRlZF9wID0gYWNjZXB0ZWRfcAogICAgICAgICApCn0KYGBgCgoKCiMjIFRoZSBHaWJicyBzYW1wbGVyCgpJbXBsZW1lbnRpbmcgYSBHaWJicyBzYW1wbGVyIGlzIG1hZGUgZWFzeSBieSBhdHRhY2hpbmcgdG8gZWFjaCBvZiB0aGUgNTAgb2JzZXJ2ZWQgZ2Vub3R5cGVzLCBhCl9sYXRlbnQgdmFyaWFibGVfIHdoaWNoIGluZGljYXRlcyB3aGV0aGVyIHRoZSB0d28gZ2VuZSBjb3BpZXMgYXQgdGhlIGxvY3VzIGluIHRoYXQgaW5kaXZpZHVhbAphcmUgSUJEIG9yIG5vdC4gIEluIG9yZGVyIHRvIGRvIHRoaXMsIHdlIG11c3Qgbm93IHRyZWF0IGVhY2ggaW5kaXZpZHVhbCBhcyBhbiBvYnNlcnZhdGlvbiwgcmF0aGVyCnRoYW4ganVzdCBzdW1tYXJpemluZyB0aGUgbnVtYmVyIG9mIEFBJ3MsIEFhJ3MsIGFuZCBhYSdzLiAgSG93ZXZlciwgd2UgY2FuIHN0aWxsIHBhc3MgdGhlIGRhdGEKaW50byBvdXIgZnVuY3Rpb24gYXMsIGZvciBleGFtcGxlLCBgbmRhdGEgPSBjKDMwLCAxMCwgMTApYCwgYW5kIHRoZW4gZXhwYW5kIHRoYXQgaW50byBhIGxpc3Qgb2YgCmluZGl2aWR1YWwgSURzIHdpdGhpbiB0aGUgZnVuY3Rpb24uCgpVc2luZyB0aGUgR2liYnMgc2FtcGxlciBhIHN3ZWVwIG9mIG91ciBhbGdvcml0aG0gd2lsbCBpbnZvbHZlIHRocmVlIHN0ZXBzOgoKMS4gc2ltdWxhdGUgbmV3IHZhbHVlcyBmb3IgdGhlIGxhdGVudCB2YXJpYWJsZXMgKCRVJCBpbiB0aGUgbGVjdHVyZSBub3RlcykgZnJvbSB0aGVpciBmdWxsIGNvbmRpdGlvbmFscy4KMi4gc2ltdWxhdGUgYSBuZXcgdmFsdWUgb2YgJGYkIGZyb20gaXRzIGZ1bGwgY29uZGl0aW9uYWwuCjMuIHNpbXVsYXRlIGEgbmV3IHZhbHVlIG9mICRwJCBmcm9tIGl0cyBmdWxsIGNvbmRpdGlvbmFsLgoKVGhlIGxlY3R1cmUgbm90ZXMgZnJvbSBzZXNzaW9uIDQgZG9uJ3QgZ28gaW50byBtdWNoIGRldGFpbCBhYm91dCB0aGUgZXhhY3QKZm9ybSBvZiB0aGUgZnVsbCBjb25kaXRpb25hbHMuICBGb3IgJGYkIGFuZCAkcCQgaXQgaXMgcHJldHR5IGVhc2lseSB1bmRlcnN0b29kCmZyb20gdGhlIHNlc3Npb24gdGhhdCB0aGV5IHdpbGwgYmUgYmV0YSBkaXN0cmlidXRpb25zLiAgSGVyZSwgaG93ZXZlciwgaXQgd2lsbApiZWhvb3ZlIHVzIHRvIGV4cGxpY2l0bHkgZGVyaXZlIHRoZSBmdWxsIGNvbmRpdGlvbmFsIGZvcgp0aGUgbGF0ZW50IHZhcmlhYmxlcy4gIExldCdzIHJlZnJlc2ggb3VyIG1lbW9yeSBieSBsb29raW5nIGF0IHRoZSBEQUcgZm9yIHRoZSBtb2RlbAp3aXRoIHRoZSBsYXRlbnQgdmFyaWFibGVzOgpgYGB7ciBlY2hvPUZBTFNFfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaW5wdXRzL2luYnJlZWRpbmdfZGFnLnBuZyIpCmBgYAoKQWhhISBLbm93aW5nIHdoYXQgd2UgZG8gYWJvdXQgaG93IERBR3MgdGVsbCB1cyBhYm91dCB0aGUgZmFjdG9yaXphdGlvbiBvZgpqb2ludCBwcm9iYWJpbGl0eSBkaXN0cmlidXRpb25zLCB0aGlzIHNob3dzIHVzIHRoYXQgJFVfaSQsIHRoZSBsYXRlbnQgaW5kaWNhdG9yCm9mIElCRCBzdGF0dXMgZm9yIGluZGl2aWR1YWwgJGkkLCB3aWxsIGFwcGVhciBpbiB0ZXJtcyBpbiB0aGUgam9pbnQgcHJvYmFiaWxpdHkKdGhhdCBsb29rcyBsaWtlOgokJApQKFVfaXxmKVAoWV9pfFVfaSwgcCkKJCQKTGV0J3Mgc2F5IHRoYXQgJFVfaSA9IDEkIG1lYW5zIHRoZSBpbmRpdmlkdWFsIGlzIGluYnJlZCAoaS5lLiBjYXJyaWVzCnR3byBnZW5lIGNvcGllcyB0aGF0IGFyZSBJQkQpIGF0IHRoZSBsb2N1cywgYW5kICRVX2k9MCQgbWVhbnMgdGhlIGluZGl2aWR1YWwncwpnZW5lIGNvcGllcyBhcmUgbm90IElCRCBhdCB0aGUgbG9jdXMuICAKVGhlIGZpcnN0IHRlcm0gaXMgaGVuY2UgYSBzaW1wbGUgQmVybm91bGxpIHByb3BvcnRpb24sIGkuZS4gJFAoVV9pID0gMSB8ZikgPSBmJC4KClRoZSBzZWNvbmQgdGVybSBpcyB0aGUgcHJvYmFiaWx0eSBvZiB0aGUgaW5kaXZpZHVhbCBoYXZpbmcgYSBnZW5vdHlwZSBnaXZlbiB0aGUgdHdvCmdlbmUgY29waWVzIGFyZSBJQkQgb3Igbm90LiAgVGhlc2UgY2FuIGJlIHNpbXBseSBlbnVtZXJhdGVkOgokJApcYmVnaW57YWxpZ25lZH0KUChZX2kgPSBBQSB8IFVfaSA9IDAsIHApICY9IHBeMiAgJiBQKFlfaSA9IEFBIHwgVV9pID0gMSwgcCkgJj0gcCBcXApQKFlfaSA9IEFhIHwgVV9pID0gMCwgcCkgJj0gMnAoMS1wKSAgJiBQKFlfaSA9IEFhIHwgVV9pID0gMSwgcCkgJj0gMCBcXApQKFlfaSA9IGFhIHwgVV9pID0gMCwgcCkgJj0gKDEtcCleMiAgJiBQKFlfaSA9IGFhIHwgVV9pID0gMSwgcCkgJj0gKDEtcCkKXGVuZHthbGlnbmVkfQokJApUaGVzZSBmb2xsb3cgc2ltcGx5IGZyb20gdGhlIGZhY3QgdGhhdCBpZiAkVV9pPTAkIHRoZSB0d28gZ2VuZSBjb3BpZXMgYXJlIGFzc3VtZWQgdG8gYmUgZHJhd24gCmluZGVwZW5kZW50bHkgZnJvbSB0aGUgcG9wdWxhdGlvbiBhbGxlbGUgZnJlcXVlbmN5LCBhbmQgaWYgJFVfaT0xJCB0aGVuIHRoZSBmaXJzdCBnZW5lIGNvcHkgaXMKZHJhd24gZnJvbSB0aGUgcG9wdWxhdGlvbiBhbGxlbGUgZnJlcXVlbmN5LCBhbmQgdGhlIGFsbGVsaWMgdHlwZSBvZiB0aGUgc2Vjb25kIGlzIHNpbXBseSAKYWx3YXlzIHRoYXQgb2YgdGhlIGZpcnN0LgoKVG8gY29tcHV0ZSB0aGUgZnVsbCBjb25kaXRpb25hbCBmb3IgJFVfaSQgd2UgbmVlZCB0byBjb21wdXRlICRQKFVfaXxmKVAoWV9pfFVfaSwgcCkkIGZvciB0aGUgaW5kaXZpZHVhbHMKZml4ZWQgZ2Vub3R5cGVzICRZX2kkIGFuZCBmb3IgdGhlIGN1cnJlbnQgdmFsdWVzIG9mICRmJCBhbmQgJHAkLCBmb3IgYm90aCAkVV9pPTAkIGFuZCAkVV9pPTEkLCBhbmQgdGhlbgpub3JtYWxpemUgdGhlIHByb2JhYmlsaXR5IHNvIHRoYXQgaXQgc3VtcyB0byAxIG92ZXIgdGhlIHR3byBwb3NzaWJsZSB2YWx1ZXMgb2YgJFVfaSQuICBGb3IgZXhhbXBsZToKJCQKXGJlZ2lue2FsaWduZWR9ClAoVV9pID0gMSB8IFlfaSA9IEFBLCBwLCBmKSAmPSBcZnJhY3tQKFVfaT0xfGYpUChZX2k9QUF8VV9pPTAsIHApfQp7UChVX2k9MHxmKVAoWV9pPUFBfFVfaT0wLCBwKSArIHtQKFVfaT0xfGYpUChZX2k9QUF8VV9pPTAsIHApfX0gXFwKJj0gXGZyYWN7ZnB9CnsoMS1mKXBeMiArIGZwfQpcZW5ke2FsaWduZWR9CiQkCgpPZiBjb3Vyc2UsIGlmIHRoZSBpbmRpdmlkdWFsIGlzIGhldGVyb3p5Z291cywgd2Uga25vdyB0aGF0IGl0cyB0d28gZ2VuZSBjb3BpZXMgY2Fubm90IGJlIElCRCwgc28KJFAoVV9pID0gMXxZX2kgPSBBYSwgcCwgZikgPSAwJC4KCgpOb3csIGxldCdzIHdyaXRlIHRoYXQgZnVuY3Rpb24hCmBgYHtyfQojJyBmdW5jdGlvbiB0byBkbyBNQ01DIHVzaW5nIGEgR2liYnMgc2FtcGxlcgojJwojJyBOb3RlIHRoYXQgd2Ugbm8gbG9uZ2VyIG5lZWQgdGhlIGZfc2QgYW5kIHBfc2QgcGFyYW1ldGVycy4gVGhlIEdpYmJzIHNhbXBsZXIKIycgd2lsbCBiZSBtYWtpbmcgcHJvcG9zYWxzIGZyb20gdGhlIGZ1bGwgY29uZGl0aW9uYWwgZGlzdHJpYnV0aW9uIQojJyBAcGFyYW0gbmRhdGEgYSB0aHJlZS12ZWN0b3IgKG5BQSwgbkFhLCBuYWEpIG9mIHRoZSBvYnNlcnZlZCBkYXRhCiMnIEBwYXJhbSBwcmkgYSB2ZWN0b3Igb2YgZm91ciBjb21wb25lbnRzOiAoYWxwaGFfZiwgYmV0YV9mLCBhbHBoYV9wLCBiZXRhX3ApCiMnIEBwYXJhbSBpbml0IGEgdHdvIHZlY3RvciBvZiBzdGFydGluZyB2YWx1ZXMgKGYsIHApLiAgRWFjaCBzaG91bGQgYmUgd2l0aGluIHRoZQojJyB1bml0IGludGVydmFsLgojJyBAcGFyYW0gc3dlZXBzIHRoZSBudW1iZXIgb2Ygc3dlZXBzIChpLmUgcHJvcG9zZWQgY2hhbmdlcykgdG8gZG8gaW4gdGhlIE1DTUMgY2hhaW4uCiMnIEByZXR1cm4gcmV0dXJucyBhIHRpYmJsZSBvZiBwcm9wb3NhbHMgbWFkZSwgdmFsdWVzIHZpc2l0ZWQsIHZhbHVlcyBvZiBNSCByYXRpbywgZXRjCm1jbWNfZ2liYnMgPC0gZnVuY3Rpb24obmRhdGEsIAogICAgICAgICAgICAgICAgICAgICAgIHByaSA9IGMoMSwgMSwgMSwgMSksIAogICAgICAgICAgICAgICAgICAgICAgIGluaXQgPSBjKC4yLCAuNSksIAogICAgICAgICAgICAgICAgICAgICAgIHN3ZWVwcyA9IDUwMCkgewogIAogICMgZmlyc3QgYXJyYW5nZSB0aGUgZGF0YSBpbnRvIGluZGl2aWR1YWwgb2JzZXJ2YXRpb25zLCBBQSdzIGZpcnN0LCB0aGVuIEFhJ3MsIHRoZW4gYWEncwogICMgV2Ugd2lsbCBtYWtlIHRoZSBnZW5vdHlwZXMgZmFjdG9ycywgc28gQUEgPSAxLCBBYSA9IDIsIGFuZCBhYSA9IDMsIHNvIHRoYXQgd2UgY2FuIGNvdW50CiAgIyB0aGVtIHVwIGVhc2lseSBhbmQgaGF2ZSB0aGVtIG9yZGVyZWQgY29uc2lzdGVudGx5LgogIG9ic19kYXRhIDwtIHJlcChjKCJBQSIsICJBYSIsICJhYSIpLCB0aW1lcyA9IG5kYXRhKSAlPiUKICAgIGZhY3RvcihsZXZlbHMgPSBjKCJBQSIsICJBYSIsICJhYSIpKQogIAogIGxhdGVudF9pYmQgPC0gbG9naWNhbChsZW5ndGgob2JzX2RhdGEpKSAjIHZlY3RvciBvZiBsYXRlbnQgZmxhZ3MgdGhhdCB0ZWxsIHVzIHdoZXRoZXIgZWFjaCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBpbmRpdmlkdWFsIGNhcnJpZXMgZ2VuZSBjb3BpZXMgdGhhdCBhcmUgSUJEIG9yIG5vdAogIAogIGxhdGVudF9wcm9icyA8LSBudW1lcmljKGxlbmd0aChvYnNfZGF0YSkpICMgYSB2ZWN0b3IgZm9yIGhvbGRpbmcgdGhlIGZ1bGwgY29uZGl0aW9uYWwgcHJvYmFiaWxpdGllcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgb2YgdGhlIGxhdGVudF9pYmQgdmFyaWFibGVzCiAgCiAgIyBpbml0aWFsaXplIGYgYW5kIHAKICBmIDwtIHAgPC0gcmVwKE5BX3JlYWxfLCBzd2VlcHMpCiAgZlsxXSA8LSBpbml0WzFdCiAgcFsxXSA8LSBpbml0WzJdCiAgCiAgIyB0aGVuIGdpdmVuIGluaXRpYWwgdmFsdWVzIGZvciBmIGFuZCBwLCBpbml0aWFsaXplIHRoZSBsYXRlbnRfaWJkIHZhcnMgKHRoZSB2ZWN0b3Igb2YgVV9pJ3MpCiAgIyBmaXJzdCBjb21wdXRlIHRoZSBmdWxsIGNvbmRpdGlvbmFscwogIGxhdGVudF9wcm9icyA8LSBpZmVsc2Uob2JzX2RhdGEgPT0gIkFBIiwgZlsxXSAqIHBbMV0gLyAoZlsxXSAqIHBbMV0gKyAoMSAtIGZbMV0pICogcFsxXSBeIDIpLAogICAgICAgICAgICAgICAgICBpZmVsc2Uob2JzX2RhdGEgPT0gIkFhIiwgMCwKICAgICAgICAgICAgICAgICAgaWZlbHNlKG9ic19kYXRhID09ICJhYSIsIGZbMV0gKiAoMSAtIHBbMV0pIC8gKGZbMV0gKiAoMSAtIHBbMV0pICsgKDEgLSBmWzFdKSAqICgxIC0gcFsxXSkgXiAyKSwgTkEpKSkgCiAgCiAgIyB0aGVuIHNpbXVsYXRlIGZyb20gdGhlbS4gVFJVRSA9IGluYnJlZCwgRkFMU0UgPSBub3QgaW5icmVkCiAgbGF0ZW50X2liZCA8LSBydW5pZihuID0gbGVuZ3RoKGxhdGVudF9wcm9icykpIDwgbGF0ZW50X3Byb2JzCgogIAogICMgbm93IGRvIHRoZSBzd2VlcHMuICBJbiBlYWNoIG9uZSB0aGUgc3RlcHMgYXJlOgogICMgICAxLiBzaW11bGF0ZSBhIG5ldyB2YWx1ZSBvZiBmIGZyb20gaXRzIGZ1bGwgY29uZGl0aW9uYWwuCiAgIyAgIDIuIHNpbXVsYXRlIGEgbmV3IHZhbHVlIG9mIHAgZnJvbSBpdHMgZnVsbCBjb25kaXRpb25hbC4KICAjICAgMy4gc2ltdWxhdGUgbmV3IHZhbHVlcyBmb3IgbGF0ZW50X2liZCBmcm9tIHRoZWlyIGZ1bGwgY29uZGl0aW9uYWxzLgogICMgRXZlcnkgcHJvcG9zYWwgd2lsbCBiZSBhY2NlcHRlZCwgc28gd2Ugd2lsbCBub3QgYm90aGVyIHJlY29yZGluZyB0aGUgdmFsdWUgb2YgdGhlCiAgIyBwcm9wb3NlZCB2YWx1ZXMgbGlrZSB3ZSBkaWQgYWJvdmUgCiAgZm9yIChpIGluIDI6c3dlZXBzKSB7CiAgICAjIDEuICBzaW11bGF0ZSBhIG5ldyB2YWx1ZSBvZiBmIGZyb20gaXRzIGZ1bGwgY29uZGl0aW9uYWwuCiAgICAjIHJlY2FsbCB0aGF0IGFscGhhX2YgaXMgaW4gcHJpWzFdIGFuZCBiZXRhX2YgaXMgaW4gcHJpWzJdCiAgICBpYmRfY291bnRzIDwtIHRhYmxlKGxhdGVudF9pYmQpICAjIHJldHVybnMgdmVjdG9yIG9mIG51bWJlciBvZiBGQUxTRXMgYW5kIG51bWJlciBvZiBUUlVFcwogICAgZltpXSA8LSByYmV0YShuID0gMSwgc2hhcGUxID0gaWJkX2NvdW50c1syXSArIHByaVsxXSwgc2hhcGUyID0gaWJkX2NvdW50c1sxXSArIHByaVsyXSkKICAgIAogICAgIyAyLiBzaW11bGF0ZSBhIG5ldyB2YWx1ZSBvZiBwIGZyb20gaXRzIGZ1bGwgY29uZGl0aW9uYWwuCiAgICAjIHJlY2FsbCB0aGF0IGFscGhhX3AgaXMgaW4gcHJpWzNdIGFuZCBiZXRhX3AgaXMgaW4gcHJpWzRdCiAgICAjIHdlIGhhdmUgdG8gY291bnQgdXAgZ2VuZSBjb3BpZXM6IHR3byBmb3IgZWFjaCBub24taW5icmVkIGluZGl2aWR1YWwgYW5kIG9ubHkKICAgICMgb25lIGZvciBlYWNoIGluYnJlZCBpbmRpdmlkdWFsLiAgV2Ugd2FudCB0byBnZXQgdGhlIG51bWJlciBvZiBBJ3MgYW5kIGEncyB0aGlzIHdheQogICAgCiAgICAjIGNvdW50IHRoZSBudW1iZXIgb2YgZGlmZmVyZW50IGdlbm90eXBlcyB0aGF0IGFyZSBub24tSUJECiAgICBuaWJkX2dlbm9zIDwtIHRhYmxlKG9ic19kYXRhW2xhdGVudF9pYmQgPT0gRkFMU0VdKQogICAgIyB0aGVuIGFkZCB1cCB0aGUgbnVtYmVyIG9mIEFzIGFuZCBhcwogICAgbmliZF9BID0gMiAqIG5pYmRfZ2Vub3NbIkFBIl0gKyBuaWJkX2dlbm9zWyJBYSJdIAogICAgbmliZF9hID0gMiAqIG5pYmRfZ2Vub3NbImFhIl0gKyBuaWJkX2dlbm9zWyJBYSJdIAogICAgCiAgICAjIHRoZW4gZG8gc29tZXRoaW5nIHNpbWlsYXIgZm9yIHRoZSBnZW5vdHlwZXMgdGhhdCBhcmUgSUJECiAgICBpYmRfZ2Vub3MgPC0gdGFibGUob2JzX2RhdGFbbGF0ZW50X2liZCA9PSBUUlVFXSkKICAgIGliZF9BID0gaWJkX2dlbm9zWyJBQSJdCiAgICBpYmRfYSA9IGliZF9nZW5vc1siYWEiXQogICAgCiAgICAjIHRoZW4gc2ltdWxhdGUgcAogICAgcFtpXSA8LSByYmV0YShuID0gMSwgc2hhcGUxID0gcHJpWzNdICsgbmliZF9BICsgaWJkX0EsIHNoYXBlMiA9IHByaVs0XSArIG5pYmRfYSArIGliZF9hKQogICAgCiAgICAjIDMuIHNpbXVsYXRlIG5ldyB2YWx1ZXMgZm9yIGxhdGVudF9pYmQgZnJvbSB0aGVpciBmdWxsIGNvbmRpdGlvbmFscwogICAgbGF0ZW50X3Byb2JzIDwtIGlmZWxzZShvYnNfZGF0YSA9PSAiQUEiLCBmW2ldICogcFtpXSAvIChmW2ldICogcFtpXSArICgxIC0gZltpXSkgKiBwW2ldIF4gMiksCiAgICAgICAgICAgICAgICAgIGlmZWxzZShvYnNfZGF0YSA9PSAiQWEiLCAwLAogICAgICAgICAgICAgICAgICBpZmVsc2Uob2JzX2RhdGEgPT0gImFhIiwgZltpXSAqICgxIC0gcFtpXSkgLyAoZltpXSAqICgxIC0gcFtpXSkgKyAoMSAtIGZbaV0pICogKDEgLSBwW2ldKSBeIDIpLCBOQSkpKSAKICAKICAjIHRoZW4gc2ltdWxhdGUgZnJvbSB0aGVtLiBUUlVFID0gaW5icmVkLCBGQUxTRSA9IG5vdCBpbmJyZWQKICBsYXRlbnRfaWJkIDwtIHJ1bmlmKG4gPSBsZW5ndGgobGF0ZW50X3Byb2JzKSkgPCBsYXRlbnRfcHJvYnMKICB9CiAgCiAgIyBhdCB0aGUgZW5kIHJldHVybiBhIHRpYmJsZQogIHRpYmJsZShzd2VlcCA9IDE6c3dlZXBzLAogICAgICAgICBmID0gZiwKICAgICAgICAgcCA9IHAKICAgICAgICAgKQogIAp9CgpgYGAKCgojIyBDb2xsZWN0IFNhbXBsZXMKCk5vdywgd2UgY2FuIGNvbGxlY3Qgc2FtcGxlcyBmcm9tIGFsbCB0aHJlZSBzYW1wbGVycy4gIExldCdzIGdvIGFoZWFkIGFuZCBwdXQgdGhlbSBhbGwKdG9nZXRoZXIgaW50byBhIHRpZHkgZGF0YSBmcmFtZS4gTGV0J3MgZG8gNSwwMDAgc3dlZXBzLi4uCmBgYHtyfQpzZXQuc2VlZCgxMCkKdGhlX3NhbXBsZSA8LSBsaXN0KHR3b19kID0gbWNtY18yZF9taChuZGF0YSwgc3dlZXBzID0gNTAwMCksCiAgICAgICAgICAgICAgICAgICBjb21wX3dpc2UgPSBtY21jX2N3X21oKG5kYXRhLCBzd2VlcHMgPSA1MDAwKSwKICAgICAgICAgICAgICAgICAgIGdpYmJzID0gbWNtY19naWJicyhuZGF0YSwgc3dlZXBzID0gNTAwMCkpICU+JQogIGJpbmRfcm93cyguaWQgPSAic2FtcGxlciIpCmBgYAoKIyMjIFBvc3RlcmlvciBtZWFucyBmb3IgJGYkIGFuZCAkcCQKQ29tcHV0ZSBwb3N0ZXJpb3IgbWVhbnM6CmBgYHtyfQp0aGVfc2FtcGxlICU+JSAKICBmaWx0ZXIoc3dlZXAgPiAyMDApICU+JQogIGdyb3VwX2J5KHNhbXBsZXIpICU+JQogIHN1bW1hcmlzZShtZWFuX2YgPSBtZWFuKGYpLAogICAgICAgICAgICBtZWFuX3AgPSBtZWFuKHApKQpgYGAKCiMjIyBQbG90IHRoZSByZXN1bHRzCgpUaGVuIHBsb3QgdGhlIHJlc3VsdHMsIHRvc3NpbmcgdGhlIGZpcnN0IDIwMCBhcyBidXJuIGluOgpgYGB7cn0KZ2dwbG90KHRoZV9zYW1wbGUgJT4lIGZpbHRlcihzd2VlcCA+IDIwMCksIGFlcyh4ID0gZiwgeSA9IHApKSArCiAgZ2VvbV9wb2ludChzaXplID0gMC4zLCBhbHBoYSA9IDAuMywgY29sb3VyID0gImdyYXkiKSArCiMgIHN0YXRfZGVuc2l0eV8yZChhZXMoZmlsbCA9IC4ubGV2ZWwuLiksIGdlb20gPSAicG9seWdvbiIpICsKICBnZW9tX2RlbnNpdHlfMmQoY29sb3VyID0gImJsYWNrIikgKwogIGZhY2V0X3dyYXAofiBzYW1wbGVyKSArCiMgIHNjYWxlX2ZpbGxfdmlyaWRpcygpICsKICB4bGltKDAsIDEpICsKICB5bGltKDAsIDEpICsKICB0aGVtZV9idygpCmBgYAoKVGhhdCBsb29rcyBsaWtlIGV2ZXJ5dGhpbmcgaXMgd29ya2luZy4gIEZyb20gdGhlIHNhbXBsZSBvZiBwb2ludHMgCihpbiBncmF5KSB2aXNpdGVkIGJ5IGVhY2ggY2hhaW4gd2UgY2FuIG1ha2UgYW4gZXN0aW1hdGUgb2YgdGhlCjItRCBwb3N0ZXJpb3Igc3VyZmFjZS4KCklmIHdlIHdhbnRlZCB0byBsb29rIGF0IHRoYXQgc3VyZmFjZSB3aXRoIHNvbWUgY29sb3JzIGRlbm90aW5nIGFjdHVhbCB2YWx1ZXMgCndlIGNvdWxkIGRvIHRoaXM6CmBgYHtyfQpnZ3Bsb3QodGhlX3NhbXBsZSAlPiUgZmlsdGVyKHN3ZWVwID4gMjAwKSwgYWVzKHggPSBmLCB5ID0gcCkpICsKICBzdGF0X2RlbnNpdHlfMmQoYWVzKGZpbGwgPSAuLmxldmVsLi4pLCBnZW9tID0gInBvbHlnb24iKSArCiAgZmFjZXRfd3JhcCh+IHNhbXBsZXIpICsKICBzY2FsZV9maWxsX3ZpcmlkaXMoKSArCiAgeGxpbSgwLCAxKSArCiAgeWxpbSgwLCAxKQpgYGAKCkNvb2wuCgojIyMgV2hpY2ggc2FtcGxlciBtaXhlcyBiZXR0ZXI/CgpUaGlzIGlzIGFuIGludGVyZXN0aW5nIHF1ZXN0aW9uIHRoYXQgc3R1ZGVudHMgbWlnaHQgd2FudCB0byBleHBsb3JlIGEgbGl0dGxlLiBPbmUgd2F5IAp0byBkbyB0aGF0IGlzIHRvIGludmVzdGlnYXRlIHRoZSBhdXRvLWNvcnJlbGF0aW9uIGJldHdlZW4gZGlmZmVyZW50IHN0YXRlcyB2aXNpdGVkIApieSB0aGUgY2hhaW4uICBUaGF0IGlzLCB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgc3RhdGUgYXQgc3dlZXAgJHQkIGFuZCBhdCBzd2VlcAokdCAtIFxlbGwkIHdoZXJlICRcZWxsJCBpcyB0aGUgImxhZyIsIGFuZCBpcyB1c3VhbGx5IGludmVzdGlnYXRlZCBmb3IgYSBzZXQgb2YgdmFsdWVzIGZyb20gCiRcZWxsID0gMCxcbGRvdHMsXG1hdGhybXttYXh+bGFnfSQuICAgIFRoaXMgY2FuIGJlIGNvbXB1dGVkIHdpdGggdGhlIGBhY2ZgIGZ1bmN0aW9uIAppbiAkUiQuICBUbyBrZWVwIGl0IHRpZHksIHdlIHdpbGwgdXNlIGBkcGx5cjo6ZG9gIGFuZCBgYnJvb206OnRpZHlgLCBhZnRlciBgdGlkeXI6OmdhdGhlcigpYGluZwp0aGUgJGYkIGFuZCAkcCQgdmFsdWVzLi4uCmBgYHtyfQphdXRvX2NvcnJzIDwtIHRoZV9zYW1wbGUgJT4lIAogIGZpbHRlcihzd2VlcCA+IDIwMCkgICU+JSAgIyBvbmNlIGFnYWluLCB0b3NzIHRoZSBmaXJzdCAyMDAgYXMgYnVybi1pbgogIHNlbGVjdChzYW1wbGVyLCBzd2VlcCwgZiwgcCkgJT4lCiAgZ2F0aGVyKGtleSA9ICJ2YXJpYWJsZSIsIHZhbHVlID0gInZhbHVlIiwgZiwgcCkgJT4lCiAgZ3JvdXBfYnkoc2FtcGxlciwgdmFyaWFibGUpICU+JQogIGRvKHRpZHkoYWNmKC4kdmFsdWUsIHBsb3QgPSBGQUxTRSkpKQoKYXV0b19jb3JycwpgYGAKCkFuZCBub3cgd2UgY2FuIHBsb3QgdGhvc2U6CmBgYHtyfQpnZ3Bsb3QoYXV0b19jb3JycywgYWVzKHggPSBsYWcsIHkgPSBhY2YsIGNvbG91ciA9IHZhcmlhYmxlKSkgKwogIGdlb21fc2VnbWVudChhZXMoeGVuZCA9IGxhZywgeWVuZCA9IDApKSArCiAgZmFjZXRfZ3JpZChzYW1wbGVyIH4gdmFyaWFibGUpCmBgYAoKT0shIENoZWNrIHRoYXQgb3V0LiAgSXQgaXMgcXVpdGUgY2xlYXIgdGhhdCB0aGUgR2liYnMgc2FtcGxlciBpcyBtaXhpbmcgYmV0dGVyLAplc3BlY2lhbGx5IGZvciAkcCQtLS10aGVyZSBpcyBtdWNoIGxlc3MgY29ycmVsYXRpb24gYmV0d2VlbiBzdWNjZXNzaXZlIHZhbHVlcyBpbiB0aGUKTUNNQyBjaGFpbi4KCk9uIHRoZSBvdGhlciBoYW5kLCB0aGUgYXN0dXRlIHN0dWRlbnQgbWlnaHQgbm90aWNlIHRoYXQgdGhlIEdpYmJzIHNhbXBsZXIgdGFrZXMgYSBiaXQgbG9uZ2VyCnRvIHJ1bi4gIFRoaXMgaXMgZXNwZWNpYWxseSB0cnVlIGluIFIgKG5vdCBzbyBtdWNoIGRpZmZlcmVuY2UgaW4gY29tcGlsZWQgY29kZSkuICBOb25ldGhlbGVzcywKdGhpcyBzaG93cyBhIGZ1bmRhbWVudGFsIHRyYWRlb2ZmIHRoYXQgb2Z0ZW4gaGFwcGVucyBpbiBNQ01DOiB5b3UgY2FuIG9mdGVuIGdldCBiZXR0ZXIgbWl4aW5nCnBlci1zd2VlcCBieSBtYWtpbmcgbW9yZSBpbnRlbGxpZ2VudCBwcm9wb3NhbHMuICBCdXQsIGlmIHRob3NlIHByb3Bvc2FscyB0YWtlIGEgbG90IG9mIGV4dHJhIHRpbWUKdG8gY29tcHV0ZSAob3IgaWYgdGhleSBhcmUgYSBzaHJpZWtpbmcgaG9ycm9yIHRvIGNvZGUgdXApIGl0IG1pZ2h0IG5vdCBiZSB3b3J0aCBpdC4gIEl0IGlzIGluCm1ha2luZyBkZWNpc2lvbnMgbGlrZSB0aGVzZSB3aGVyZSBzb21lIG9mIHRoZSBmdW4gImFydCIgb2YgaW1wbGVtZW50aW5nIE1DTUMgY29tZXMgaW4uCgojIyBTZXNzaW9uIEluZm9ybWF0aW9uCmBgYHtyfQpzZXNzaW9uSW5mbygpCmBgYAoK