1. What is Zero Inflation?
In a wide variety of applications, we find data that has an excess of
zeros. For example, consider the example from McElreath where monks
working in a monastary to copy pages either 1) get drunk and don’t do
anything, so they produce 0s or 2) work, and either produces 0, 1, 2, 3,
or more manuscripts In such a dataset, you would expect an excess of
zeros due to a structural property of the data generating
process - namely that some zeroes are due to a probability of no pages
being written, in this case. Let’s see how he simulates this.
library(rethinking)
# define parameters
prob_drink <- 0.2 # 20% of days
rate_work <- 1 # average 1 manuscript per day
# sample one year of production
N <- 365
# simulate days monks drink
set.seed(365)
drink <- rbinom( N , 1 , prob_drink )
# simulate manuscripts completed
y <- (1-drink)*rpois( N , rate_work )
Notice in the last piece that we FIRST get a random binomial of work
or no work, THEN use a poisson to get the number of pages generated.
Let’s plot this and see the different sources of zeroes.
monks <- data.frame(drink = drink, manuscripts = y)
ggplot(monks, aes(x = manuscripts, fill = factor(drink))) +
geom_bar()
So, there are more zeroes than we’d expect from a poisson with a
lambda of 1, AND we see that this is again a mixture distribution - a
compounding of a binomial and a poisson.
There are many types of zero inflated - or zero augmented -
distributions out there. Think of any distribution, but then assume some
process is adding more zeroes! We’ll talk about a few, but you can dream
up just about anything you’d like. Commonly you’ll hear about ZIPs,
ZIBs, ZINBs, or even ZINs. We also run into Zero Augmented - or Hurdle -
models like ZAGs, ZALNs (zero augmented log-normal distributions), and
more.
1.1 Why are we accounting for zero inflation?
Quite simply, not accounting for an excess of zeros will inevitably
downward bias your parameter estimates. I leave this to the reader to
contemplate why.
1.2 Zero Inflation versus Hurdle Models
Zero Inflation and Zero Augmentation, or Hurdle, distributions mean
two different things. The difference comes from two types of
zeroes.
Structural Zeros come from some probabilistic process
that prevents an outcome. The monks got drunk, so they produced no
manuscripts! Or, you didn’t see that hippo because it was underwater
when you were doing your surveys! Or, the cost of fish was too low, so
fishermen just didn’t go to see to catch anything, and so had zero
catch! There are a lot of possible causes of structural zeroes - and
they can be modeled.
Sampling Zeros come from the data generating process
that is generating your observations. So, a monk just didn’t finish any
manuscripts that day. Or habitat was of poor quality, so you didn’t
count any hippos. Or waves were too high, and fishermen didn’t catch
anything.
Consider the example in the figure below of going to observe rhinos
in the wild. If you count 0 because, perhaps they are there but you fail
to detect them, that is a structural zero. You have the
probability, p, of a structural zero. If your observation would have
detected rhinos if they were there, but there just happen to be none,
that’s a sampling zero.
Zero Inflated models comprise of a mix of structural and sampling
issues. Hurdle models are ones where you only have structural
zeros. We often find these cropping up with distributions which
cannot have zeros in them, for example.
Let’s look at how we fit a few different zero augmented models to get
a feel for them
2. The Zero Inflated Poisson
As we have the monk data at hand already, we can use it as a handy
starting point for ZIP models.
2.1 ZIP with Likelihood
We can fit a ZIP model using a variety of packages in R. For
example,
library(pscl)
monk_pscl <- zeroinfl(manuscripts ~ 1, data = monks)
summary(monk_pscl)
##
## Call:
## zeroinfl(formula = manuscripts ~ 1, data = monks)
##
## Pearson residuals:
## Min 1Q Median 3Q Max
## -0.7923 -0.7923 -0.7923 0.2332 3.3096
##
## Count model coefficients (poisson with log link):
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 0.00346 0.09197 0.038 0.97
##
## Zero-inflation model coefficients (binomial with logit link):
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.2079 0.3291 -3.671 0.000242 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Number of iterations in BFGS optimization: 10
## Log-likelihood: -435.6 on 2 Df
Here you can explicitly see that we’re estimating a binomial model
with a logit link for the zero inflatino part. And as it’s a logit
coefficient, we can see that the probability of no work is 0.2300728 By
putting a |
after the intercept, we could model the zero
inflation process itself with another equation.
See also how the answer differs from glm
coef(glm(manuscripts ~ 1, data = monks, family = poisson))
## (Intercept)
## -0.2579903
Other packages also implement zero inflation. I inclde
pscl
as it wsa the most common one for some time. More
recently, glmmTMB
has implemented a pretty robust and
flexible zero inflation and hurdle schema which I rather like.
library(glmmTMB)
monk_tmb <- glmmTMB(manuscripts ~ 1,
ziformula = ~ 1,
family = poisson,
data = monks)
summary(monk_tmb)
## Family: poisson ( log )
## Formula: manuscripts ~ 1
## Zero inflation: ~1
## Data: monks
##
## AIC BIC logLik deviance df.resid
## 875.3 883.1 -435.6 871.3 363
##
##
## Conditional model:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 0.00346 0.09197 0.038 0.97
##
## Zero-inflation model:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.2079 0.3291 -3.671 0.000242 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
fixef(monk_tmb)[2]$zi |> inv_logit()
## (Intercept)
## 0.2300658
The results are the same, but, you can include whatever family you’d
like - just include some zero inflation!
2.2 ZIP and Bayes
Rethinking provides some comfort here. It provides a
dzipois
density which takes a probability of a zero and a
lambda.The trickier part is that we now have two relationships - one for
the logit link of the drink/no drink and a second log link for
manuscripts.
zip_mod <- alist(
#likelihood
manuscripts ~ dzipois(p, lambda),
#data generating process
logit(p) ~ a,
log(lambda) ~ b,
#priors
a ~ dnorm(-1,2),
b ~ dnorm(0,5)
)
zip_fit <- quap(zip_mod, data = monks)
This model produces very similar output with differences only due to
priors
precis(zip_fit)
## mean sd 5.5% 94.5%
## a -1.202498558 0.32260061 -1.7180766 -0.6869205
## b 0.004533354 0.09118098 -0.1411915 0.1502582
Feel free to look at postcheck or other diagnostics here to see if
we’re ok. And, note, when the two parts of this relationship become
trickier, you will need to resort to ulam()
.
3. ZIB
Yes. It’s true. A binomial process can be due to structural and
sampling zeros. It’s two coupled binomial models.
Let’s look at the fishing in state parks dataset from rethinking.
We’ll apply two quick transformations with the idea of, we want to see
if you’re more likely to catch a fish if you’re hanging out with more
people or if having kid’s with you just throws the whole day to
hell.
data(Fish)
Fish <- Fish %>%
mutate(caught_anything = as.numeric(fish_caught>0),
with_kids = as.factor(child>0))
FishPlot <- ggplot(Fish,
aes(x = persons, y = caught_anything, color = with_kids)) +
geom_jitter(position = position_jitter(width = 0.3, height = 0.1))
FishPlot
We can see a lot of zeros when people come with kids!
3.1 ZIBs and Likelihood
zib_tmb <- glmmTMB(caught_anything ~ persons,
ziformula = ~ with_kids+0,
family = binomial,
data = Fish)
What’s the chance you won’t catch fish if you bring kids?
inv_logit(fixef(zib_tmb)$zi[2])
## with_kidsTRUE
## 0.6712779
Whoah. That’s big.
3.1 ZIBs and Bayes
We can take the model above and easily recode it into rethinking
using flat priors using the dzibinom
density, which will
take two different logistics.
mod_zib <- alist(
#Likelihood
caught_anything ~ dzibinom(p_zero, size, prob_caught),
#DGP
logit(prob_caught) <- a + b*persons,
logit(p_zero) <- b_kids[with_kids],
#priors
a ~ dnorm(0,10),
b ~ dnorm(0,10),
b_kids[with_kids] ~ dnorm(0,5)
)
fit_zib <- quap(mod_zib,
data = Fish |>
mutate(size = 1,
with_kids = as.numeric(with_kids)))
Which produces broadly similar results.
precis(fit_zib, depth = 2)
## mean sd 5.5% 94.5%
## a -1.8484417 0.4677124 -2.5959364 -1.1009470
## b 1.1989977 0.2637843 0.7774195 1.6205760
## b_kids[1] -4.1876389 2.1661546 -7.6495724 -0.7257055
## b_kids[2] 0.7256153 0.2354231 0.3493636 1.1018669
The only real difference is the probability of getting a 0 without
kids. But if you inv_logit
it, you can see it’s very small
- as is the results from the glmmTMB
fit above. And the
zero inflation of having kids - 0.6738423 - is about the same. Ah,
Kids.
3.1.1 ZIBs and Bayes
Given that the probability of catching a fish is the compounded
probability of having kids and number of people, we can look at the
resulting probabilities via simulation. I’m bumping the size up to 100
so we can get a more smooth estimate of probability at each data point
from sim
.
#input data frame
pred_df <- crossing(persons = seq(1,4,length.out=100),
with_kids = c(1,2),
size = 100)
#get predictions with error
pred_zib <- predicted_draws(fit_zib, pred_df)|>
mutate(caught_anything = .prediction/100,
with_kids = c(FALSE, TRUE)[with_kids])
#visualize
FishPlot +
facet_wrap(~with_kids) +
stat_lineribbon(data = pred_zib,
color = "black",
alpha = 0.2) +
scale_fill_brewer(palette = "Blues")
## Warning: Combining variables of class <factor> and <logical> was deprecated in ggplot2
## 3.4.0.
## ℹ Please ensure your variables are compatible before plotting (location:
## `combine_vars()`)
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: Combining variables of class <logical> and <factor> was deprecated in ggplot2
## 3.4.0.
## ℹ Please ensure your variables are compatible before plotting (location:
## `combine_vars()`)
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
4. ZINB
Knowing that kids make things difficult (am I working out some issues
here? Maybe I am!), we can notice that the dataset actually looks at the
NUMBER of fish caught. Now, normally we’d look at this as a poisson (or
a ZIP!) but, let’s look at the distribution of catch by number of
people.
library(ggridges)
##
## Attaching package: 'ggridges'
## The following objects are masked from 'package:tidybayes':
##
## scale_point_color_continuous, scale_point_color_discrete,
## scale_point_colour_continuous, scale_point_colour_discrete,
## scale_point_fill_continuous, scale_point_fill_discrete,
## scale_point_size_continuous
ggplot(data = Fish,
mapping = aes(x = fish_caught, y = as.factor(persons), fill = as.factor(with_kids))) +
geom_density_ridges(alpha = 0.7)
## Picking joint bandwidth of 2.2
Looking at this, we can see that the data is not only clearly 0
inflated, but, wow, that’s a long tail. A poisson is going to be a bad
choice. Instead, a negative binomial is going to be the way to go.
The ZINB model is a fairly common one for this type of situation.
Rather than belabor the point, here’s a glmmTMB
example
with a ZINB. Note that I’m using nbinom1 here. This is a great way to
model overdispersion, as instead of the variance expanding with the
square of the mean, it expands linearly with the mean. Again, a modeling
choice!
zinb_tmb <- glmmTMB(fish_caught ~ persons,
ziformula = ~ with_kids+0,
family = nbinom1,
data = Fish)
And you can then work from there. What do you see here?
summary(zinb_tmb)
## Family: nbinom1 ( log )
## Formula: fish_caught ~ persons
## Zero inflation: ~with_kids + 0
## Data: Fish
##
## AIC BIC logLik deviance df.resid
## 877.5 895.1 -433.7 867.5 245
##
##
## Dispersion parameter for nbinom1 family (): 10.8
##
## Conditional model:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -0.07753 0.28516 -0.272 0.786
## persons 0.61363 0.08719 7.037 1.96e-12 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Zero-inflation model:
## Estimate Std. Error z value Pr(>|z|)
## with_kidsFALSE -20.1677 4277.7629 -0.005 0.9962
## with_kidsTRUE 0.5694 0.2430 2.343 0.0191 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
5. Gone Fishing - Gama Hurdles
We can also use continuous data. This is most common with Gamma
distributed data, as you cannot have a waiting time of 0. Let’s use a
simulated data set looking at duration of offshore fishing trips in days
given average wave height.
fishing <- read.csv("https://biol609.github.io/lectures/data/20/fishing_duration.csv")
#what's there
head(fishing)
## days_at_sea seas_m non_zero
## 1 2.04671364 3.1117604 1
## 2 1.07712028 2.8300817 1
## 3 0.14453844 1.7110089 1
## 4 0.00000000 2.3203441 0
## 5 0.05439326 2.5521608 1
## 6 0.00000000 0.9862452 0
#visualize the data
plot(days_at_sea ~ seas_m, data=fishing)
5.1. Exploratory Analysis Decisions
OK, let’s assume you have no a priori knowledge about this data save
the variables in it. You are interested in just a bivariate
relationship. Period.
Now, in building a model for this, you have to decide on three
things.
1. What is the data generating process?
2. What is the error generating process - the distribution of the
variation around predicted values?
3. As we’re using Bayes, do we have information that can allow us to
provide weakly informative priors?
5.2 The data generating process
On the data generating process, we can look at the data and see, hey,
we have a negative relationship, and its one that cannot be less than 0.
This suggests a power or exponential relationship. An exponential (log
link function) seems pretty reasonable.
5.3 The error generating process
This one is harder. We have made some decisions that are useful. We
have no non-negative values. We have continuous data. So, no normal
distribution. And no Poisson or other count distribution. But what are
we left with. Log-normal? Gamma? Erlang? Weibull? Others (oh, and there
are others).
We have a few options - we can plot histograms, plot densities at
each predictor value (or bin of predictor), we can fit a gaussian model,
know that it’s wrong but look at its residual distribution, we can stare
at our scatterplot and ponder.
What we’re pondering is histomancy - the mystic ability to
divine distributions from a histogram or density plot.
It is a terrible idea.
Instead, let’s actually use science and some thought. In this case,
we’re looking at a distribution of durations (days at sea). There’s some
underlying thing that determines the duration that someone stays at sea.
This fits naturally to a Gamma distribution. Others could work here,
too, but, a Gamma is also maximum entropy distribution for data from 0
to infinity where the variance increases with the mean. And a member of
the exponential family, so fairly easy to work with. So, yes, you could
choose others, but for biological plausibility, and ease of use, it’s an
excellent first choice.
5.3.1 The Gamma
As a quick reminder of what the gamma is, it’s a distribution that
can be defined with either a shape parameter and a rate of events
happening (1/time to event - in this case, the decision to port) or the
same shape parameter and a scale parameter which is 1/rate (so, time for
1 event to happen). This can lead to a little bit of confusion, as
you’ll see it presented either way. Personally, I like rate, but either
will work
So, below, as we increase the rate, we have more and more short wait
times for 1 event.
library(tidyr)
library(dplyr)
library(ggplot2)
gamma_frame <- crossing(rate = seq(0.1, 2, length.out=5),
shape=1,
x=seq(0.01, 5, length.out=200)) %>%
mutate(d = dgamma(x, shape = shape, rate = rate))
ggplot(gamma_frame, aes(x=x, y=d, color=factor(rate))) +
geom_line()
To make things a bit easier, the mean of a gamma is mu = shape *
scale. This leads to a few relationships/transformations which can
become useful.
shape = mu/scale
rate = shape/mu
scale = mu/shape
It’s a bit of a pain, as depending on how you put things together,
you can get slightly different results from models. But it should not
matter to qualitative outcomes.
5.4 Priors
In this case, we don’t really have any prior information! So we want
flat priors. We can use regularization - say, b ~ dnorm(0,3), but how
much depends on you. We’re also going to want priors for scale or rate
parameters. These can be normal, but often cauchy (for scale) or
exponential (for rate) priors work well. YMMV.
5.5. Fitting with a Gamma
5.5.1 The model
So, let’s start with dgamma
. By default,
dgamma
takes first a shape and then a rate argument. This
presents a small challenge, as above we have shape = rate/mu. This means
we would need to work with our mean value a bit. Rather than a straight
log(mu)
statement, we’re going to need to use the
calculated value. Let’s put together a model.
library(rethinking)
fishing_gamma_mod <- alist(
#likelihood
#noting that rate = shape/exp(log_mu)
days_at_sea ~ dgamma(shape, shape/exp(log_mu)),
#data generating process
log_mu <- a + b*seas_m,
#priors
a ~ dnorm(0,100),
b ~ dnorm(0,100),
shape ~ dexp(2)
)
McElreath has also put together a shortcut, dgamma2
, but
it tends to produce slightly different results, as it calculates shape
as a function of the predictors. So I’m not a yuge fan.
fishing_gamma_mod2 <- alist(
#likelihood
days_at_sea ~ dgamma2(mu, scale),
#data generating process
log(mu) <- a + b*seas_m,
#priors
a ~ dnorm(0,100),
b ~ dnorm(0,100),
scale ~ dcauchy(0,2)
)
5.5.2 The fit
OK, let’s fit this thing using the first model!
fishing_gamma_fit <- map(fishing_gamma_mod, data=fishing)
## Error in map(fishing_gamma_mod, data = fishing): initial value in 'vmmin' is not finite
## The start values for the parameters were invalid. This could be caused by missing values (NA) in the data or by start values outside the parameter constraints. If there are no NA values in the data, try using explicit start values.
Uh oh! What’s wrong?
and now, we encounter mistake #1. Remember that we’re using a log
link? Well, log(0) is not a number, so, of course our model fails! So we
need to drop those 0s. They mean that a fisherman didn’t leave port at
all, and are likely best conisdered as a separate process. Regardless,
even if we want to fold them back in (see below), we would be greatly
helped by building a model that does not require handling those
details.
fishing_clean <- fishing %>% filter(days_at_sea != 0)
set.seed(609)
fishing_gamma_fit <- map(fishing_gamma_mod, data=fishing_clean)
## Error in map(fishing_gamma_mod, data = fishing_clean): non-finite finite-difference value [3]
## Start values for parameters may be too far from MAP.
## Try better priors or use explicit start values.
## If you sampled random start values, just trying again may work.
## Start values used in this attempt:
## a = -180.807609298684
## b = 29.0262239923922
## shape = 0.110016871757038
Oops! That didn’t work either! Well that’s not good. So, what does
the error say? That start values were invalid. OK.
Welp, eyeballing the graph of the data, we see a positive intercept
and negative slope. So, even with the same seed (other seed values allow
for convergence), let’s re-try!
set.seed(609)
fishing_gamma_fit <- map(fishing_gamma_mod, data=fishing_clean,
start = list(a=1, b=-1))
Fit!
5.5.3 Model evaluation
Let’s check out our posterior!
pairs(fishing_gamma_fit)
## Warning in par(usr): argument 1 does not name a graphical parameter
## Warning in par(usr): argument 1 does not name a graphical parameter
## Warning in par(usr): argument 1 does not name a graphical parameter
Hey! Not bad. Indeed, I wouldn’t even go to STAN with a fit like
this.
par(mfrow=c(2,3))
postcheck(fishing_gamma_fit)
par(mfrow=c(1,1), ask=F)
Looking pretty good! there are one or two points outside of the
predictive CI, but, eh, that’s not bad considering the large number of
data points we have. Worth investigating, but not losing too much sleep
over.
5.5.4 What do the results say?
We can first look at the general results
precis(fishing_gamma_fit)
## mean sd 5.5% 94.5%
## a 2.2107901 0.30827198 1.7181119 2.7034682
## b -0.6341226 0.11152433 -0.8123600 -0.4558852
## shape 0.4629509 0.05212386 0.3796469 0.5462549
So, a decline of -0.63, or, for every 1m wave, fishermen would spend
53% less time at sea (exp(-0.63)
). We can’t say absolute
days here, as this is a nonlinear function - what happens in absolute
units going from 2 to 3 is different from 3 to 4. But we can judge it on
a percentage scale. Try calculating it out if you don’t believe it.
We can also visualize the results
#start with a fresh data frame of predicted values
pred_df <- data.frame(seas_m = seq(0,5,length.out=200))
#OK, now get some sim and link output
sim_fishing <- sim(fishing_gamma_fit, data=pred_df)
#note, for link, we need to exponentiate
link_fishing <- exp(link(fishing_gamma_fit, data=pred_df))
#smoosh it all together
pred_df <- pred_df %>%
mutate(days_at_sea = apply(link_fishing, 2, median),
lwr_fit = apply(link_fishing, 2, HPDI)[1,],
upr_fit = apply(link_fishing, 2, HPDI)[2,],
lwr = apply(sim_fishing, 2, HPDI)[1,],
upr = apply(sim_fishing, 2, HPDI)[2,]
)
#a nice ggplot
ggplot(data=pred_df,
mapping=aes(x=seas_m, y=days_at_sea)) +
geom_ribbon(mapping=aes(ymin=lwr, ymax=upr), alpha=0.4) +
geom_ribbon(mapping=aes(ymin=lwr_fit, ymax=upr_fit), fill="blue", alpha=0.4) +
geom_line(lwd=1, color="red") +
geom_point(data=fishing_clean) +
theme_bw(base_size=17)
Not bad. We can see the results of a Gamma distribution - the mean
variance scaling relationship. We can see we have some outliers to
inspect, but, overall, pretty darned good.
6. About those Zeroes - Zero Augmented Gamma
6.1 Zero Inflation, augmentation, hurdles, and more
Excessive zeroes are not something to be scared of. Of which to be
scared? Whatever, you guys know this on a deep level. Because a zero
inflated or zero augmented distribution is nothing more than the
lovechild of a binomial logistic regression and a GLM of your own
choosing.
Let’s start by thinking about a Hurdle or Zero Augmented model. In
these models, you cannot have any zeroes for reasons related to
constrains of your data generating process or error generating process.
Instead, Zeroes are generated by one data generating process, then
another process determines the relationship with your response variable.
So, you first split your model into one where you have either 0 or non-0
outcomes, and perform a logistic regression. With whatever predictors
you want. Then, with all of the non-zero outcomes, you perform whatever
GLM you want.
A Zero Inflated or Zero Augmented model is slightly different. Here,
zeroes are generated either by some process that is binary - a thing
happened or it didn’t - OR they are generated by whatever data
generating process you are modeling.
Zero Inflated models come in many forms - Zero Inflated Poisson (uses
dzipois(lambda, p)
in rethinking), Zero Inflated Binomial
(uses dzibinom(p_zero, size, p)
), Zero Augmented Gamma
(dzagamma2(prob, mu, scale)
) and more which can be pulled
from other libraries in R.
6.2 How do I know if it is zero inflated
There are two straightforward ways to see if something is zero
inflated. First, what’s the distribution look like? Do you see a lot of
zeros?
plot(density(fishing$days_at_sea))
OK - lots of zeroes - which, given that this is a Gamma, is super
suspect. But, for this or other distributions, they might be OK.
Sometimes you’ll even see two humps - one around zero, one somewhere
else. Zero Inflation!
You can also look at a scatterplot and see if there are a suspicious
number of zeroes across all of the values of a predictor variable. Sure,
you might ahve a non-normal distribution, but that kind of pattern is a
bit odd.
plot(days_at_sea ~ seas_m, data=fishing)
6.3 Using the ZAG
To work with our original data - zeroes and all - we can use a Zero
Augmented Gamma Distribution. I’m still not a huge fan of
dzagamma2
so let’s make our own using the rate formulation.
To do this, I literally just entered dzamma2
in R, then
rewrote the function a bit to use the rate formulation.
dzagamma <- function (x, prob, shape, rate, log = FALSE)
{
K <- as.data.frame(cbind(x = x, prob = prob, shape = shape, rate = rate))
llg <- dgamma(x, shape = shape, rate = rate, log = TRUE)
ll <- ifelse(K$x == 0, log(K$prob), log(1 - K$prob) + llg)
if (log == FALSE)
ll <- exp(ll)
ll
}
Let this be a less - you can put in whatever density function you
want - if R doesn’t have it, write your own! Heck, this format is a
really straightforward way to turn any distribution - normal, whatever -
into a zero inflated distribution.
In this distribution, we’ll have a lot of extra 0s. What’s great is
that we can appropriate our earlier model for use here.
fishing_zagamma_mod <- alist(
#likelihood
#noting that rate = shape/exp(log_mu)
days_at_sea ~ dzagamma2(prob, mu, scale),
#data generating process
log(mu) <- a + b*seas_m,
#priors
a ~ dnorm(0,100),
b ~ dnorm(0,100),
scale ~ dexp(2),
prob ~ dunif(0,1)
)
We have no info on the probability, so, we’re just putting in a flat
uniform prior between 0 and 1. We could use a beta if we wanted, but,
meh. We can then fit this, using our lessons about start values from
before.
fishing_zagamma_fit <- quap(fishing_zagamma_mod, data=fishing,
start = list(a=1, b=-1))
6.4 Evaluation
Let’s look at those posteriors!
pairs(fishing_zagamma_fit)
## Warning in par(usr): argument 1 does not name a graphical parameter
## Warning in par(usr): argument 1 does not name a graphical parameter
## Warning in par(usr): argument 1 does not name a graphical parameter
## Warning in par(usr): argument 1 does not name a graphical parameter
The pairs plot looks nice and well behaved. Other checks and
sim
are a bit more difficult, as they require a random
number generator which we currently… don’t have. So, let’s make one.
rzagamma2 <- function(n, prob, scale, rate){
is_zero <- rbinom(n, 1, prob=1-prob)
is_zero * rgamma(n, scale = scale, rate)
}
With this, we can use postcheck
par(mfrow=c(3,3))
postcheck(fishing_zagamma_fit)
par(mfrow=c(1,1), ask=F)
Hey - it’s all of the data! And it looks - good!
6.5 What do the results say?
We can first look at the general results
precis(fishing_zagamma_fit)
## mean sd 5.5% 94.5%
## a 1.1152591 0.19096871 0.8100543 1.42046401
## b -0.1448523 0.06373614 -0.2467149 -0.04298964
## scale 4.7410432 0.67868115 3.6563796 5.82570675
## prob 0.2933332 0.03717393 0.2339221 0.35274431
No surprise, our coefficients are exactly the same as before! Wahoo!
Except now we also know there’s a 30% chance on any given day that a
fisherman will just say ‘meh’ and not go do sea.
We can also visualize the results. First, we will plot the prediction
for JUST the non-zero results using the fitted model. Then we will
contrast it to putting in the full 0’s prediction, which comes from the
ZAG distribtion.
# a prediction frame
pred_zag <- predicted_draws(fishing_zagamma_fit,
data.frame(
seas_m = seq(0, 5,
length.out = 100)),
value = "days_at_sea")
# a linpred frame
fit_zag <- linpred_draws(fishing_zagamma_fit,
data.frame(
seas_m = seq(0, 5,
length.out = 100)),
value = "days_at_sea")
# fit interval of link - not with ZAG
ggplot(fit_zag,
aes(x = seas_m, y = days_at_sea)) +
stat_lineribbon() +
scale_fill_brewer(palette = "Greens") +
geom_point(data = fishing)
# prediction interval
ggplot(pred_zag,
aes(x = seas_m, y = days_at_sea)) +
stat_lineribbon() +
scale_fill_brewer(palette = "Oranges") +
geom_point(data = fishing)
Note the difference in CI width and downweighting of the line with
just fit. There is a lot more going on here, and the full prediction
interval gives us what we need to see.
LS0tCnRpdGxlOiAiWmVybyBJbmZsYXRpb24iCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShyZXRoaW5raW5nKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2xtbVRNQikKbGlicmFyeShwc2NsKQpsaWJyYXJ5KG1nY3YpCmxpYnJhcnkodGlkeWJheWVzKQpsaWJyYXJ5KHRpZHliYXllcy5yZXRoaW5raW5nKQp0aGVtZV9zZXQodGhlbWVfYncoYmFzZV9zaXplPTEyKSkKa25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCiMjIDEuIFdoYXQgaXMgWmVybyBJbmZsYXRpb24/CgpJbiBhIHdpZGUgdmFyaWV0eSBvZiBhcHBsaWNhdGlvbnMsIHdlIGZpbmQgZGF0YSB0aGF0IGhhcyBhbiBleGNlc3Mgb2YgemVyb3MuIEZvciBleGFtcGxlLCBjb25zaWRlciB0aGUgZXhhbXBsZSBmcm9tIE1jRWxyZWF0aCB3aGVyZSBtb25rcyB3b3JraW5nIGluIGEgbW9uYXN0YXJ5IHRvIGNvcHkgcGFnZXMgZWl0aGVyIDEpIGdldCBkcnVuayBhbmQgZG9uJ3QgZG8gYW55dGhpbmcsIHNvIHRoZXkgcHJvZHVjZSAwcyBvciAyKSB3b3JrLCBhbmQgZWl0aGVyIHByb2R1Y2VzIDAsIDEsIDIsIDMsIG9yIG1vcmUgbWFudXNjcmlwdHMgSW4gc3VjaCBhIGRhdGFzZXQsIHlvdSB3b3VsZCBleHBlY3QgYW4gZXhjZXNzIG9mIHplcm9zIGR1ZSB0byBhICpzdHJ1Y3R1cmFsKiBwcm9wZXJ0eSBvZiB0aGUgZGF0YSBnZW5lcmF0aW5nIHByb2Nlc3MgLSBuYW1lbHkgdGhhdCBzb21lIHplcm9lcyBhcmUgZHVlIHRvIGEgcHJvYmFiaWxpdHkgb2Ygbm8gcGFnZXMgYmVpbmcgd3JpdHRlbiwgaW4gdGhpcyBjYXNlLiBMZXQncyBzZWUgaG93IGhlIHNpbXVsYXRlcyB0aGlzLgoKYGBge3J9CmxpYnJhcnkocmV0aGlua2luZykKCiMgZGVmaW5lIHBhcmFtZXRlcnMKcHJvYl9kcmluayA8LSAwLjIgIyAyMCUgb2YgZGF5cwpyYXRlX3dvcmsgPC0gMSAgICAjIGF2ZXJhZ2UgMSBtYW51c2NyaXB0IHBlciBkYXkKIyBzYW1wbGUgb25lIHllYXIgb2YgcHJvZHVjdGlvbgpOIDwtIDM2NQoKIyBzaW11bGF0ZSBkYXlzIG1vbmtzIGRyaW5rCnNldC5zZWVkKDM2NSkKZHJpbmsgPC0gcmJpbm9tKCBOICwgMSAsIHByb2JfZHJpbmsgKQoKIyBzaW11bGF0ZSBtYW51c2NyaXB0cyBjb21wbGV0ZWQKeSA8LSAoMS1kcmluaykqcnBvaXMoIE4gLCByYXRlX3dvcmsgKQpgYGAKCgpOb3RpY2UgaW4gdGhlIGxhc3QgcGllY2UgdGhhdCB3ZSBGSVJTVCBnZXQgYSByYW5kb20gYmlub21pYWwgb2Ygd29yayBvciBubyB3b3JrLCBUSEVOIHVzZSBhIHBvaXNzb24gdG8gZ2V0IHRoZSBudW1iZXIgb2YgcGFnZXMgZ2VuZXJhdGVkLiBMZXQncyBwbG90IHRoaXMgYW5kIHNlZSB0aGUgZGlmZmVyZW50IHNvdXJjZXMgb2YgemVyb2VzLgoKYGBge3J9Cm1vbmtzIDwtIGRhdGEuZnJhbWUoZHJpbmsgPSBkcmluaywgbWFudXNjcmlwdHMgPSB5KQoKZ2dwbG90KG1vbmtzLCBhZXMoeCA9IG1hbnVzY3JpcHRzLCBmaWxsID0gZmFjdG9yKGRyaW5rKSkpICsKICBnZW9tX2JhcigpCmBgYAoKU28sIHRoZXJlIGFyZSBtb3JlIHplcm9lcyB0aGFuIHdlJ2QgZXhwZWN0IGZyb20gYSBwb2lzc29uIHdpdGggYSBsYW1iZGEgb2YgMSwgQU5EIHdlIHNlZSB0aGF0IHRoaXMgaXMgYWdhaW4gYSBtaXh0dXJlIGRpc3RyaWJ1dGlvbiAtIGEgY29tcG91bmRpbmcgb2YgYSBiaW5vbWlhbCBhbmQgYSBwb2lzc29uLgoKVGhlcmUgYXJlIG1hbnkgdHlwZXMgb2YgemVybyBpbmZsYXRlZCAtIG9yIHplcm8gYXVnbWVudGVkIC0gZGlzdHJpYnV0aW9ucyBvdXQgdGhlcmUuIFRoaW5rIG9mIGFueSBkaXN0cmlidXRpb24sIGJ1dCB0aGVuIGFzc3VtZSBzb21lIHByb2Nlc3MgaXMgYWRkaW5nIG1vcmUgemVyb2VzISBXZSdsbCB0YWxrIGFib3V0IGEgZmV3LCBidXQgeW91IGNhbiBkcmVhbSB1cCBqdXN0IGFib3V0IGFueXRoaW5nIHlvdSdkIGxpa2UuIENvbW1vbmx5IHlvdSdsbCBoZWFyIGFib3V0IFpJUHMsIFpJQnMsIFpJTkJzLCBvciBldmVuIFpJTnMuIFdlIGFsc28gcnVuIGludG8gWmVybyBBdWdtZW50ZWQgLSBvciBIdXJkbGUgLSBtb2RlbHMgbGlrZSBaQUdzLCBaQUxOcyAoemVybyBhdWdtZW50ZWQgbG9nLW5vcm1hbCBkaXN0cmlidXRpb25zKSwgYW5kIG1vcmUuCgoKCiMjIyAxLjEgV2h5IGFyZSB3ZSBhY2NvdW50aW5nIGZvciB6ZXJvIGluZmxhdGlvbj8KClF1aXRlIHNpbXBseSwgbm90IGFjY291bnRpbmcgZm9yIGFuIGV4Y2VzcyBvZiB6ZXJvcyB3aWxsIGluZXZpdGFibHkgZG93bndhcmQgYmlhcyB5b3VyIHBhcmFtZXRlciBlc3RpbWF0ZXMuIEkgbGVhdmUgdGhpcyB0byB0aGUgcmVhZGVyIHRvIGNvbnRlbXBsYXRlIHdoeS4gCgojIyMgMS4yIFplcm8gSW5mbGF0aW9uIHZlcnN1cyBIdXJkbGUgTW9kZWxzCgpaZXJvIEluZmxhdGlvbiBhbmQgWmVybyBBdWdtZW50YXRpb24sIG9yIEh1cmRsZSwgZGlzdHJpYnV0aW9ucyBtZWFuIHR3byBkaWZmZXJlbnQgdGhpbmdzLiBUaGUgZGlmZmVyZW5jZSBjb21lcyBmcm9tIHR3byB0eXBlcyBvZiB6ZXJvZXMuICAKXAoqKlN0cnVjdHVyYWwgWmVyb3MqKiBjb21lIGZyb20gc29tZSBwcm9iYWJpbGlzdGljIHByb2Nlc3MgdGhhdCBwcmV2ZW50cyBhbiBvdXRjb21lLiBUaGUgbW9ua3MgZ290IGRydW5rLCBzbyB0aGV5IHByb2R1Y2VkIG5vIG1hbnVzY3JpcHRzISBPciwgeW91IGRpZG4ndCBzZWUgdGhhdCBoaXBwbyBiZWNhdXNlIGl0IHdhcyB1bmRlcndhdGVyIHdoZW4geW91IHdlcmUgZG9pbmcgeW91ciBzdXJ2ZXlzISBPciwgdGhlIGNvc3Qgb2YgZmlzaCB3YXMgdG9vIGxvdywgc28gZmlzaGVybWVuIGp1c3QgZGlkbid0IGdvIHRvIHNlZSB0byBjYXRjaCBhbnl0aGluZywgYW5kIHNvIGhhZCB6ZXJvIGNhdGNoISBUaGVyZSBhcmUgYSBsb3Qgb2YgcG9zc2libGUgY2F1c2VzIG9mIHN0cnVjdHVyYWwgemVyb2VzIC0gYW5kIHRoZXkgY2FuIGJlIG1vZGVsZWQuICAKXAoqKlNhbXBsaW5nIFplcm9zKiogY29tZSBmcm9tIHRoZSBkYXRhIGdlbmVyYXRpbmcgcHJvY2VzcyB0aGF0IGlzIGdlbmVyYXRpbmcgeW91ciBvYnNlcnZhdGlvbnMuIFNvLCBhIG1vbmsganVzdCBkaWRuJ3QgZmluaXNoIGFueSBtYW51c2NyaXB0cyB0aGF0IGRheS4gT3IgaGFiaXRhdCB3YXMgb2YgcG9vciBxdWFsaXR5LCBzbyB5b3UgZGlkbid0IGNvdW50IGFueSBoaXBwb3MuIE9yIHdhdmVzIHdlcmUgdG9vIGhpZ2gsIGFuZCBmaXNoZXJtZW4gZGlkbid0IGNhdGNoIGFueXRoaW5nLiAgClwKCkNvbnNpZGVyIHRoZSBleGFtcGxlIGluIHRoZSBmaWd1cmUgYmVsb3cgb2YgZ29pbmcgdG8gb2JzZXJ2ZSByaGlub3MgaW4gdGhlIHdpbGQuIElmIHlvdSBjb3VudCAwIGJlY2F1c2UsIHBlcmhhcHMgdGhleSBhcmUgdGhlcmUgYnV0IHlvdSBmYWlsIHRvIGRldGVjdCB0aGVtLCB0aGF0IGlzIGEgKnN0cnVjdHVyYWwgemVybyouIFlvdSBoYXZlIHRoZSBwcm9iYWJpbGl0eSwgcCwgb2YgYSBzdHJ1Y3R1cmFsIHplcm8uIElmIHlvdXIgb2JzZXJ2YXRpb24gd291bGQgaGF2ZSBkZXRlY3RlZCByaGlub3MgaWYgdGhleSB3ZXJlIHRoZXJlLCBidXQgdGhlcmUganVzdCBoYXBwZW4gdG8gYmUgbm9uZSwgdGhhdCdzIGEgKipzYW1wbGluZyB6ZXJvKiouCgohW10oLi9pbWFnZXMvemluZmwvc3RydWN0dXJhbF9zYW1wbGluZ196ZXJvcy5qcGcpCgpaZXJvIEluZmxhdGVkIG1vZGVscyBjb21wcmlzZSBvZiBhIG1peCBvZiBzdHJ1Y3R1cmFsIGFuZCBzYW1wbGluZyBpc3N1ZXMuIEh1cmRsZSBtb2RlbHMgYXJlIG9uZXMgd2hlcmUgeW91ICpvbmx5IGhhdmUgc3RydWN0dXJhbCB6ZXJvcyouIFdlIG9mdGVuIGZpbmQgdGhlc2UgY3JvcHBpbmcgdXAgd2l0aCBkaXN0cmlidXRpb25zIHdoaWNoIGNhbm5vdCBoYXZlIHplcm9zIGluIHRoZW0sIGZvciBleGFtcGxlLgoKTGV0J3MgbG9vayBhdCBob3cgd2UgZml0IGEgZmV3IGRpZmZlcmVudCB6ZXJvIGF1Z21lbnRlZCBtb2RlbHMgdG8gZ2V0IGEgZmVlbCBmb3IgdGhlbQoKCiMjIDIuIFRoZSBaZXJvIEluZmxhdGVkIFBvaXNzb24KCkFzIHdlIGhhdmUgdGhlIG1vbmsgZGF0YSBhdCBoYW5kIGFscmVhZHksIHdlIGNhbiB1c2UgaXQgYXMgYSBoYW5keSBzdGFydGluZyBwb2ludCBmb3IgWklQIG1vZGVscy4KCiMjIyAyLjEgWklQIHdpdGggTGlrZWxpaG9vZAoKV2UgY2FuIGZpdCBhIFpJUCBtb2RlbCB1c2luZyBhIHZhcmlldHkgb2YgcGFja2FnZXMgaW4gUi4gRm9yIGV4YW1wbGUsCgpgYGB7ciB6aXAxfQpsaWJyYXJ5KHBzY2wpCgptb25rX3BzY2wgPC0gemVyb2luZmwobWFudXNjcmlwdHMgfiAxLCBkYXRhID0gbW9ua3MpCgpzdW1tYXJ5KG1vbmtfcHNjbCkKYGBgCgpIZXJlIHlvdSBjYW4gZXhwbGljaXRseSBzZWUgdGhhdCB3ZSdyZSBlc3RpbWF0aW5nIGEgYmlub21pYWwgbW9kZWwgd2l0aCBhIGxvZ2l0IGxpbmsgZm9yIHRoZSB6ZXJvIGluZmxhdGlubyBwYXJ0LiBBbmQgYXMgaXQncyBhIGxvZ2l0IGNvZWZmaWNpZW50LCB3ZSBjYW4gc2VlIHRoYXQgdGhlIHByb2JhYmlsaXR5IG9mIG5vIHdvcmsgaXMgYHIgaW52X2xvZ2l0KC0xLjIwNzkpYCBCeSBwdXR0aW5nIGEgYHxgIGFmdGVyIHRoZSBpbnRlcmNlcHQsIHdlIGNvdWxkIG1vZGVsIHRoZSB6ZXJvIGluZmxhdGlvbiBwcm9jZXNzIGl0c2VsZiB3aXRoIGFub3RoZXIgZXF1YXRpb24uCgpTZWUgYWxzbyBob3cgdGhlIGFuc3dlciBkaWZmZXJzIGZyb20gYGdsbWAKCmBgYHtyfQpjb2VmKGdsbShtYW51c2NyaXB0cyB+IDEsIGRhdGEgPSBtb25rcywgZmFtaWx5ID0gcG9pc3NvbikpCmBgYAoKT3RoZXIgcGFja2FnZXMgYWxzbyBpbXBsZW1lbnQgemVybyBpbmZsYXRpb24uIEkgaW5jbGRlIGBwc2NsYCBhcyBpdCB3c2EgdGhlIG1vc3QgY29tbW9uIG9uZSBmb3Igc29tZSB0aW1lLiBNb3JlIHJlY2VudGx5LCBgZ2xtbVRNQmAgaGFzIGltcGxlbWVudGVkIGEgcHJldHR5IHJvYnVzdCBhbmQgZmxleGlibGUgemVybyBpbmZsYXRpb24gYW5kIGh1cmRsZSBzY2hlbWEgd2hpY2ggSSByYXRoZXIgbGlrZS4KCmBgYHtyfQpsaWJyYXJ5KGdsbW1UTUIpCgptb25rX3RtYiA8LSBnbG1tVE1CKG1hbnVzY3JpcHRzIH4gMSwKICAgICAgICAgICAgICAgICAgICB6aWZvcm11bGEgPSB+IDEsCiAgICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gcG9pc3NvbiwKICAgICAgICAgICAgICAgICAgICBkYXRhID0gbW9ua3MpCgpzdW1tYXJ5KG1vbmtfdG1iKQoKZml4ZWYobW9ua190bWIpWzJdJHppIHw+IGludl9sb2dpdCgpCmBgYAoKVGhlIHJlc3VsdHMgYXJlIHRoZSBzYW1lLCBidXQsIHlvdSBjYW4gaW5jbHVkZSB3aGF0ZXZlciBmYW1pbHkgeW91J2QgbGlrZSAtIGp1c3QgaW5jbHVkZSBzb21lIHplcm8gaW5mbGF0aW9uISAKCiMjIyAyLjIgWklQIGFuZCBCYXllcwoKUmV0aGlua2luZyBwcm92aWRlcyBzb21lIGNvbWZvcnQgaGVyZS4gSXQgcHJvdmlkZXMgYSBgZHppcG9pc2AgZGVuc2l0eSB3aGljaCB0YWtlcyBhIHByb2JhYmlsaXR5IG9mIGEgemVybyBhbmQgYSBsYW1iZGEuVGhlIHRyaWNraWVyIHBhcnQgaXMgdGhhdCB3ZSBub3cgaGF2ZSB0d28gcmVsYXRpb25zaGlwcyAtIG9uZSBmb3IgdGhlIGxvZ2l0IGxpbmsgb2YgdGhlIGRyaW5rL25vIGRyaW5rIGFuZCBhIHNlY29uZCBsb2cgbGluayBmb3IgbWFudXNjcmlwdHMuCgoKYGBge3J9CnppcF9tb2QgPC0gYWxpc3QoCiAgCiAgI2xpa2VsaWhvb2QKICBtYW51c2NyaXB0cyB+IGR6aXBvaXMocCwgbGFtYmRhKSwKICAKICAjZGF0YSBnZW5lcmF0aW5nIHByb2Nlc3MKICBsb2dpdChwKSB+IGEsCiAgbG9nKGxhbWJkYSkgfiBiLAogIAogICNwcmlvcnMKICBhIH4gZG5vcm0oLTEsMiksCiAgYiB+IGRub3JtKDAsNSkKKQoKemlwX2ZpdCA8LSBxdWFwKHppcF9tb2QsIGRhdGEgPSBtb25rcykKYGBgCgpUaGlzIG1vZGVsIHByb2R1Y2VzIHZlcnkgc2ltaWxhciBvdXRwdXQgd2l0aCBkaWZmZXJlbmNlcyBvbmx5IGR1ZSB0byBwcmlvcnMKCmBgYHtyfQpwcmVjaXMoemlwX2ZpdCkKYGBgCgpGZWVsIGZyZWUgdG8gbG9vayBhdCBwb3N0Y2hlY2sgb3Igb3RoZXIgZGlhZ25vc3RpY3MgaGVyZSB0byBzZWUgaWYgd2UncmUgb2suIEFuZCwgbm90ZSwgd2hlbiB0aGUgdHdvIHBhcnRzIG9mIHRoaXMgcmVsYXRpb25zaGlwIGJlY29tZSB0cmlja2llciwgeW91IHdpbGwgbmVlZCB0byByZXNvcnQgdG8gYHVsYW0oKWAuCgojIyAzLiBaSUIKClllcy4gSXQncyB0cnVlLiBBIGJpbm9taWFsIHByb2Nlc3MgY2FuIGJlIGR1ZSB0byBzdHJ1Y3R1cmFsIGFuZCBzYW1wbGluZyB6ZXJvcy4gSXQncyB0d28gY291cGxlZCBiaW5vbWlhbCBtb2RlbHMuCgohW10oLi9pbWFnZXMvemluZmwveW9fZGF3Z196aWIuanBnKQoKTGV0J3MgbG9vayBhdCB0aGUgZmlzaGluZyBpbiBzdGF0ZSBwYXJrcyBkYXRhc2V0IGZyb20gcmV0aGlua2luZy4gV2UnbGwgYXBwbHkgdHdvIHF1aWNrIHRyYW5zZm9ybWF0aW9ucyB3aXRoIHRoZSBpZGVhIG9mLCB3ZSB3YW50IHRvIHNlZSBpZiB5b3UncmUgbW9yZSBsaWtlbHkgdG8gY2F0Y2ggYSBmaXNoIGlmIHlvdSdyZSBoYW5naW5nIG91dCB3aXRoIG1vcmUgcGVvcGxlIG9yIGlmIGhhdmluZyBraWQncyB3aXRoIHlvdSBqdXN0IHRocm93cyB0aGUgd2hvbGUgZGF5IHRvIGhlbGwuCgoKYGBge3J9CmRhdGEoRmlzaCkKCkZpc2ggPC0gRmlzaCAlPiUKICBtdXRhdGUoY2F1Z2h0X2FueXRoaW5nID0gYXMubnVtZXJpYyhmaXNoX2NhdWdodD4wKSwKICAgICAgICAgd2l0aF9raWRzID0gYXMuZmFjdG9yKGNoaWxkPjApKQoKRmlzaFBsb3QgPC0gZ2dwbG90KEZpc2gsCiAgICAgICBhZXMoeCA9IHBlcnNvbnMsIHkgPSBjYXVnaHRfYW55dGhpbmcsIGNvbG9yID0gd2l0aF9raWRzKSkgKwogIGdlb21faml0dGVyKHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyKHdpZHRoID0gMC4zLCBoZWlnaHQgPSAwLjEpKQoKRmlzaFBsb3QKYGBgCgpXZSBjYW4gc2VlIGEgbG90IG9mIHplcm9zIHdoZW4gcGVvcGxlIGNvbWUgd2l0aCBraWRzISAKCiMjIDMuMSBaSUJzIGFuZCBMaWtlbGlob29kCgpgYGB7ciBnbG1tVE1CfQp6aWJfdG1iIDwtIGdsbW1UTUIoY2F1Z2h0X2FueXRoaW5nIH4gcGVyc29ucywKICAgICAgICAgICAgICAgICAgIHppZm9ybXVsYSA9IH4gd2l0aF9raWRzKzAsCiAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSBiaW5vbWlhbCwKICAgICAgICAgICAgICAgICAgIGRhdGEgPSBGaXNoKQpgYGAKCldoYXQncyB0aGUgY2hhbmNlIHlvdSB3b24ndCBjYXRjaCBmaXNoIGlmIHlvdSBicmluZyBraWRzPwoKYGBge3J9Cmludl9sb2dpdChmaXhlZih6aWJfdG1iKSR6aVsyXSkKYGBgCgpXaG9haC4gVGhhdCdzIGJpZy4KCiMjIDMuMSBaSUJzIGFuZCBCYXllcwoKV2UgY2FuIHRha2UgdGhlIG1vZGVsIGFib3ZlIGFuZCBlYXNpbHkgcmVjb2RlIGl0IGludG8gcmV0aGlua2luZyB1c2luZyBmbGF0IHByaW9ycyB1c2luZyB0aGUgYGR6aWJpbm9tYCBkZW5zaXR5LCB3aGljaCB3aWxsIHRha2UgdHdvIGRpZmZlcmVudCBsb2dpc3RpY3MuCgpgYGB7cn0KbW9kX3ppYiA8LSBhbGlzdCgKICAjTGlrZWxpaG9vZAogIGNhdWdodF9hbnl0aGluZyB+IGR6aWJpbm9tKHBfemVybywgc2l6ZSwgcHJvYl9jYXVnaHQpLAogIAogICNER1AKICBsb2dpdChwcm9iX2NhdWdodCkgPC0gYSArIGIqcGVyc29ucywKIGxvZ2l0KHBfemVybykgPC0gYl9raWRzW3dpdGhfa2lkc10sCiAgCiAgI3ByaW9ycwogIGEgfiBkbm9ybSgwLDEwKSwKCiAgYiB+IGRub3JtKDAsMTApLAogIGJfa2lkc1t3aXRoX2tpZHNdIH4gZG5vcm0oMCw1KQopCgpmaXRfemliIDwtIHF1YXAobW9kX3ppYiwgCiAgICAgICAgICAgICAgIGRhdGEgPSBGaXNoIHw+IAogICAgICAgICAgICAgICAgIG11dGF0ZShzaXplID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgIHdpdGhfa2lkcyA9IGFzLm51bWVyaWMod2l0aF9raWRzKSkpCmBgYAoKV2hpY2ggcHJvZHVjZXMgYnJvYWRseSBzaW1pbGFyIHJlc3VsdHMuCmBgYHtyfQpwcmVjaXMoZml0X3ppYiwgZGVwdGggPSAyKQpgYGAKClRoZSBvbmx5IHJlYWwgZGlmZmVyZW5jZSBpcyB0aGUgcHJvYmFiaWxpdHkgb2YgZ2V0dGluZyBhIDAgd2l0aG91dCBraWRzLiBCdXQgaWYgeW91IGBpbnZfbG9naXRgIGl0LCB5b3UgY2FuIHNlZSBpdCdzIHZlcnkgc21hbGwgLSBhcyBpcyB0aGUgcmVzdWx0cyBmcm9tIHRoZSBgZ2xtbVRNQmAgZml0IGFib3ZlLiBBbmQgdGhlIHplcm8gaW5mbGF0aW9uIG9mIGhhdmluZyBraWRzIC0gYHIgaW52X2xvZ2l0KGNvZWYoZml0X3ppYilbNF0pYCAtIGlzIGFib3V0IHRoZSBzYW1lLiBBaCwgS2lkcy4KCiMjIDMuMS4xIFpJQnMgYW5kIEJheWVzCgpHaXZlbiB0aGF0IHRoZSBwcm9iYWJpbGl0eSBvZiBjYXRjaGluZyBhIGZpc2ggaXMgdGhlIGNvbXBvdW5kZWQgcHJvYmFiaWxpdHkgb2YgaGF2aW5nIGtpZHMgYW5kIG51bWJlciBvZiBwZW9wbGUsIHdlIGNhbiBsb29rIGF0IHRoZSByZXN1bHRpbmcgcHJvYmFiaWxpdGllcyB2aWEgc2ltdWxhdGlvbi4gSSdtIGJ1bXBpbmcgdGhlIHNpemUgdXAgdG8gMTAwIHNvIHdlIGNhbiBnZXQgYSBtb3JlIHNtb290aCBlc3RpbWF0ZSBvZiBwcm9iYWJpbGl0eSBhdCBlYWNoIGRhdGEgcG9pbnQgZnJvbSBgc2ltYC4KCmBgYHtyIHppYl9iYXllc30KI2lucHV0IGRhdGEgZnJhbWUKcHJlZF9kZiA8LSBjcm9zc2luZyhwZXJzb25zID0gc2VxKDEsNCxsZW5ndGgub3V0PTEwMCksIAogICAgICAgICAgICAgICAgICAgIHdpdGhfa2lkcyA9IGMoMSwyKSwgCiAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEwMCkKCiNnZXQgcHJlZGljdGlvbnMgd2l0aCBlcnJvcgpwcmVkX3ppYiA8LSBwcmVkaWN0ZWRfZHJhd3MoZml0X3ppYiwgcHJlZF9kZil8PgogIG11dGF0ZShjYXVnaHRfYW55dGhpbmcgPSAucHJlZGljdGlvbi8xMDAsCiAgICAgICAgIHdpdGhfa2lkcyA9IGMoRkFMU0UsIFRSVUUpW3dpdGhfa2lkc10pCgojdmlzdWFsaXplCkZpc2hQbG90ICsKICAgZmFjZXRfd3JhcCh+d2l0aF9raWRzKSArCiAgc3RhdF9saW5lcmliYm9uKGRhdGEgPSBwcmVkX3ppYiwgCiAgICAgICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgCiAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4yKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJCbHVlcyIpCiAKCgpgYGAKCiMjIDQuIFpJTkIKS25vd2luZyB0aGF0IGtpZHMgbWFrZSB0aGluZ3MgZGlmZmljdWx0IChhbSBJIHdvcmtpbmcgb3V0IHNvbWUgaXNzdWVzIGhlcmU/IE1heWJlIEkgYW0hKSwgd2UgY2FuIG5vdGljZSB0aGF0IHRoZSBkYXRhc2V0IGFjdHVhbGx5IGxvb2tzIGF0IHRoZSBOVU1CRVIgb2YgZmlzaCBjYXVnaHQuIE5vdywgbm9ybWFsbHkgd2UnZCBsb29rIGF0IHRoaXMgYXMgYSBwb2lzc29uIChvciBhIFpJUCEpIGJ1dCwgbGV0J3MgbG9vayBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIGNhdGNoIGJ5IG51bWJlciBvZiBwZW9wbGUuCgpgYGB7cn0KbGlicmFyeShnZ3JpZGdlcykKZ2dwbG90KGRhdGEgPSBGaXNoLCAKICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IGZpc2hfY2F1Z2h0LCB5ID0gYXMuZmFjdG9yKHBlcnNvbnMpLCBmaWxsID0gYXMuZmFjdG9yKHdpdGhfa2lkcykpKSArCiAgZ2VvbV9kZW5zaXR5X3JpZGdlcyhhbHBoYSA9IDAuNykKCmBgYAoKTG9va2luZyBhdCB0aGlzLCB3ZSBjYW4gc2VlIHRoYXQgdGhlIGRhdGEgaXMgbm90IG9ubHkgY2xlYXJseSAwIGluZmxhdGVkLCBidXQsIHdvdywgdGhhdCdzIGEgbG9uZyB0YWlsLiBBIHBvaXNzb24gaXMgZ29pbmcgdG8gYmUgYSBiYWQgY2hvaWNlLiBJbnN0ZWFkLCBhIG5lZ2F0aXZlIGJpbm9taWFsIGlzIGdvaW5nIHRvIGJlIHRoZSB3YXkgdG8gZ28uCgpUaGUgWklOQiBtb2RlbCBpcyBhIGZhaXJseSBjb21tb24gb25lIGZvciB0aGlzIHR5cGUgb2Ygc2l0dWF0aW9uLiAgUmF0aGVyIHRoYW4gYmVsYWJvciB0aGUgcG9pbnQsIGhlcmUncyBhIGBnbG1tVE1CYCBleGFtcGxlIHdpdGggYSBaSU5CLiBOb3RlIHRoYXQgSSdtIHVzaW5nIG5iaW5vbTEgaGVyZS4gVGhpcyBpcyBhIGdyZWF0IHdheSB0byBtb2RlbCBvdmVyZGlzcGVyc2lvbiwgYXMgaW5zdGVhZCBvZiB0aGUgdmFyaWFuY2UgZXhwYW5kaW5nIHdpdGggdGhlIHNxdWFyZSBvZiB0aGUgbWVhbiwgaXQgZXhwYW5kcyBsaW5lYXJseSB3aXRoIHRoZSBtZWFuLiBBZ2FpbiwgYSBtb2RlbGluZyBjaG9pY2UhCgpgYGB7ciB6aW5ifQp6aW5iX3RtYiA8LSBnbG1tVE1CKGZpc2hfY2F1Z2h0IH4gcGVyc29ucywKICAgICAgICAgICAgICAgICAgIHppZm9ybXVsYSA9IH4gd2l0aF9raWRzKzAsCiAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSBuYmlub20xLAogICAgICAgICAgICAgICAgICAgZGF0YSA9IEZpc2gpCmBgYAoKQW5kIHlvdSBjYW4gdGhlbiB3b3JrIGZyb20gdGhlcmUuIFdoYXQgZG8geW91IHNlZSBoZXJlPwoKYGBge3IgemluYl9zdW19CnN1bW1hcnkoemluYl90bWIpCmBgYAoKPCEtLQpTaW1pbGFybHksIHdlIGNhbiBkbyB0aGlzIGluIGEgQmF5ZXNpYW4gZnJhbWV3b3JrLgoKYGBge3IsIGV2YWwgPSBGQUxTRX0KbW9kX3ppbmIgPC0gYWxpc3QoCiAgI0xpa2VsaWhvb2QKICBmaXNoX2NhdWdodCB+IGR6aWJpbm9tKHBfemVybywgc2l6ZSwgcHJvYiksCiAgCiAgI3RyYW5zZm9ybWF0aW9uIGZvciBuYmlub20KICAjcHJvYiA9IHNpemUvKHNpemUrbXUpLAogIHByb2IgPC0gc2l6ZS8oc2l6ZStlc3RfZmlzaF9jYXVnaHQpLAogIAogICNER1AKIGxvZyhlc3RfZmlzaF9jYXVnaHQpIDwtIGEgKyBiKnBlcnNvbnMsCiBsb2dpdChwX3plcm8pIDwtIGJfa2lkc1t3aXRoX2tpZHNdLAogIAogICNwcmlvcnMKICBhIH4gZG5vcm0oMywyKSwKICBzaXplIH4gZGV4cCgyKSwKCiAgYiB+IGRub3JtKDAsNSksCiAgYl9raWRzW3dpdGhfa2lkc10gfiBkbm9ybSgwLDUpCikKCmZpdF96aW5iIDwtIHF1YXAobW9kX3ppbmIsIAogICAgICAgICAgICAgICAgZGF0YSA9IEZpc2ggJT4lIG11dGF0ZShzaXplID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpdGhfa2lkcyA9IGFzLm51bWVyaWMod2l0aF9raWRzKSkpCgpgYGAKCi0tPgojIyA1LiBHb25lIEZpc2hpbmcgLSBHYW1hIEh1cmRsZXMKCldlIGNhbiBhbHNvIHVzZSBjb250aW51b3VzIGRhdGEuIFRoaXMgaXMgbW9zdCBjb21tb24gd2l0aCBHYW1tYSBkaXN0cmlidXRlZCBkYXRhLCBhcyB5b3UgY2Fubm90IGhhdmUgYSB3YWl0aW5nIHRpbWUgb2YgMC4gTGV0J3MgdXNlIGEgc2ltdWxhdGVkIGRhdGEgc2V0IGxvb2tpbmcgYXQgZHVyYXRpb24gb2Ygb2Zmc2hvcmUgZmlzaGluZyB0cmlwcyBpbiBkYXlzIGdpdmVuIGF2ZXJhZ2Ugd2F2ZSBoZWlnaHQuCgpgYGB7ciBsb2FkX2RhdGF9CmZpc2hpbmcgPC0gcmVhZC5jc3YoImh0dHBzOi8vYmlvbDYwOS5naXRodWIuaW8vbGVjdHVyZXMvZGF0YS8yMC9maXNoaW5nX2R1cmF0aW9uLmNzdiIpCgojd2hhdCdzIHRoZXJlCmhlYWQoZmlzaGluZykKCiN2aXN1YWxpemUgdGhlIGRhdGEKcGxvdChkYXlzX2F0X3NlYSB+IHNlYXNfbSwgZGF0YT1maXNoaW5nKQpgYGAKCiMjIyA1LjEuIEV4cGxvcmF0b3J5IEFuYWx5c2lzIERlY2lzaW9ucwoKT0ssIGxldCdzIGFzc3VtZSB5b3UgaGF2ZSBubyBhIHByaW9yaSBrbm93bGVkZ2UgYWJvdXQgdGhpcyBkYXRhIHNhdmUgdGhlIHZhcmlhYmxlcyBpbiBpdC4gWW91IGFyZSBpbnRlcmVzdGVkIGluIGp1c3QgYSBiaXZhcmlhdGUgcmVsYXRpb25zaGlwLiBQZXJpb2QuICAKXApOb3csIGluIGJ1aWxkaW5nIGEgbW9kZWwgZm9yIHRoaXMsIHlvdSBoYXZlIHRvIGRlY2lkZSBvbiB0aHJlZSB0aGluZ3MuICAKXAoxLiBXaGF0IGlzIHRoZSBkYXRhIGdlbmVyYXRpbmcgcHJvY2Vzcz8gIAoyLiBXaGF0IGlzIHRoZSBlcnJvciBnZW5lcmF0aW5nIHByb2Nlc3MgLSB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSB2YXJpYXRpb24gYXJvdW5kIHByZWRpY3RlZCB2YWx1ZXM/ICAKMy4gQXMgd2UncmUgdXNpbmcgQmF5ZXMsIGRvIHdlIGhhdmUgaW5mb3JtYXRpb24gdGhhdCBjYW4gYWxsb3cgdXMgdG8gcHJvdmlkZSB3ZWFrbHkgaW5mb3JtYXRpdmUgcHJpb3JzPyAgCgojIyMgNS4yIFRoZSBkYXRhIGdlbmVyYXRpbmcgcHJvY2VzcwoKT24gdGhlIGRhdGEgZ2VuZXJhdGluZyBwcm9jZXNzLCB3ZSBjYW4gbG9vayBhdCB0aGUgZGF0YSBhbmQgc2VlLCBoZXksIHdlIGhhdmUgYSBuZWdhdGl2ZSByZWxhdGlvbnNoaXAsIGFuZCBpdHMgb25lIHRoYXQgY2Fubm90IGJlIGxlc3MgdGhhbiAwLiBUaGlzIHN1Z2dlc3RzIGEgcG93ZXIgb3IgZXhwb25lbnRpYWwgcmVsYXRpb25zaGlwLiBBbiBleHBvbmVudGlhbCAobG9nIGxpbmsgZnVuY3Rpb24pIHNlZW1zIHByZXR0eSByZWFzb25hYmxlLgoKIyMjIDUuMyBUaGUgZXJyb3IgZ2VuZXJhdGluZyBwcm9jZXNzCgpUaGlzIG9uZSBpcyBoYXJkZXIuIFdlIGhhdmUgbWFkZSBzb21lIGRlY2lzaW9ucyB0aGF0IGFyZSB1c2VmdWwuIFdlIGhhdmUgbm8gbm9uLW5lZ2F0aXZlIHZhbHVlcy4gV2UgaGF2ZSBjb250aW51b3VzIGRhdGEuIFNvLCBubyBub3JtYWwgZGlzdHJpYnV0aW9uLiBBbmQgbm8gUG9pc3NvbiBvciBvdGhlciBjb3VudCBkaXN0cmlidXRpb24uIEJ1dCB3aGF0IGFyZSB3ZSBsZWZ0IHdpdGguIExvZy1ub3JtYWw/IEdhbW1hPyBFcmxhbmc/IFdlaWJ1bGw/IE90aGVycyAob2gsIGFuZCB0aGVyZSBhcmUgb3RoZXJzKS4gIAoKV2UgaGF2ZSBhIGZldyBvcHRpb25zIC0gd2UgY2FuIHBsb3QgaGlzdG9ncmFtcywgcGxvdCBkZW5zaXRpZXMgYXQgZWFjaCBwcmVkaWN0b3IgdmFsdWUgKG9yIGJpbiBvZiBwcmVkaWN0b3IpLCB3ZSBjYW4gZml0IGEgZ2F1c3NpYW4gbW9kZWwsIGtub3cgdGhhdCBpdCdzIHdyb25nIGJ1dCBsb29rIGF0IGl0cyByZXNpZHVhbCBkaXN0cmlidXRpb24sIHdlIGNhbiBzdGFyZSBhdCBvdXIgc2NhdHRlcnBsb3QgYW5kIHBvbmRlci4gIAoKV2hhdCB3ZSdyZSBwb25kZXJpbmcgaXMgKmhpc3RvbWFuY3kqIC0gdGhlIG15c3RpYyBhYmlsaXR5IHRvIGRpdmluZSBkaXN0cmlidXRpb25zIGZyb20gYSBoaXN0b2dyYW0gb3IgZGVuc2l0eSBwbG90LiAgCgpJdCBpcyBhIHRlcnJpYmxlIGlkZWEuICAKCkluc3RlYWQsIGxldCdzIGFjdHVhbGx5IHVzZSBzY2llbmNlIGFuZCBzb21lIHRob3VnaHQuIEluIHRoaXMgY2FzZSwgd2UncmUgbG9va2luZyBhdCBhIGRpc3RyaWJ1dGlvbiBvZiBkdXJhdGlvbnMgKGRheXMgYXQgc2VhKS4gVGhlcmUncyBzb21lIHVuZGVybHlpbmcgdGhpbmcgdGhhdCBkZXRlcm1pbmVzIHRoZSBkdXJhdGlvbiB0aGF0IHNvbWVvbmUgc3RheXMgYXQgc2VhLiBUaGlzIGZpdHMgbmF0dXJhbGx5IHRvIGEgR2FtbWEgZGlzdHJpYnV0aW9uLiBPdGhlcnMgY291bGQgd29yayBoZXJlLCB0b28sIGJ1dCwgYSBHYW1tYSBpcyBhbHNvIG1heGltdW0gZW50cm9weSBkaXN0cmlidXRpb24gZm9yIGRhdGEgZnJvbSAwIHRvIGluZmluaXR5IHdoZXJlIHRoZSB2YXJpYW5jZSBpbmNyZWFzZXMgd2l0aCB0aGUgbWVhbi4gQW5kIGEgbWVtYmVyIG9mIHRoZSBleHBvbmVudGlhbCBmYW1pbHksIHNvIGZhaXJseSBlYXN5IHRvIHdvcmsgd2l0aC4gU28sIHllcywgeW91IGNvdWxkIGNob29zZSBvdGhlcnMsIGJ1dCBmb3IgYmlvbG9naWNhbCBwbGF1c2liaWxpdHksIGFuZCBlYXNlIG9mIHVzZSwgaXQncyBhbiBleGNlbGxlbnQgZmlyc3QgY2hvaWNlLgoKIyMjIyA1LjMuMSBUaGUgR2FtbWEKCiFbXSguL2ltYWdlcy8yMC9hbmNpZW50LWFsaWVucy1ndXkxMS13aHktdXNlLWdhbW1hLWdsbS1hbGllbnMuanBnKQoKQXMgYSBxdWljayByZW1pbmRlciBvZiB3aGF0IHRoZSBnYW1tYSBpcywgaXQncyBhIGRpc3RyaWJ1dGlvbiB0aGF0IGNhbiBiZSBkZWZpbmVkIHdpdGggZWl0aGVyIGEgc2hhcGUgcGFyYW1ldGVyIGFuZCBhIHJhdGUgb2YgZXZlbnRzIGhhcHBlbmluZyAoMS90aW1lIHRvIGV2ZW50IC0gaW4gdGhpcyBjYXNlLCB0aGUgZGVjaXNpb24gdG8gcG9ydCkgb3IgdGhlIHNhbWUgc2hhcGUgcGFyYW1ldGVyIGFuZCBhIHNjYWxlIHBhcmFtZXRlciB3aGljaCBpcyAxL3JhdGUgKHNvLCB0aW1lIGZvciAxIGV2ZW50IHRvIGhhcHBlbikuIFRoaXMgY2FuIGxlYWQgdG8gYSBsaXR0bGUgYml0IG9mIGNvbmZ1c2lvbiwgYXMgeW91J2xsIHNlZSBpdCBwcmVzZW50ZWQgZWl0aGVyIHdheS4gUGVyc29uYWxseSwgSSBsaWtlIHJhdGUsIGJ1dCBlaXRoZXIgd2lsbCB3b3JrCgpTbywgYmVsb3csIGFzIHdlIGluY3JlYXNlIHRoZSByYXRlLCB3ZSBoYXZlIG1vcmUgYW5kIG1vcmUgc2hvcnQgd2FpdCB0aW1lcyBmb3IgMSBldmVudC4KCmBgYHtyIGdhbW1hLCBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGdncGxvdDIpCgpnYW1tYV9mcmFtZSA8LSBjcm9zc2luZyhyYXRlID0gc2VxKDAuMSwgMiwgbGVuZ3RoLm91dD01KSwgCiAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlPTEsIAogICAgICAgICAgICAgICAgICAgICAgICB4PXNlcSgwLjAxLCA1LCBsZW5ndGgub3V0PTIwMCkpICU+JQogIG11dGF0ZShkID0gZGdhbW1hKHgsIHNoYXBlID0gc2hhcGUsIHJhdGUgPSByYXRlKSkKCmdncGxvdChnYW1tYV9mcmFtZSwgYWVzKHg9eCwgeT1kLCBjb2xvcj1mYWN0b3IocmF0ZSkpKSArCiAgZ2VvbV9saW5lKCkKCmBgYAoKVG8gbWFrZSB0aGluZ3MgYSBiaXQgZWFzaWVyLCB0aGUgbWVhbiBvZiBhIGdhbW1hIGlzIG11ID0gc2hhcGUgKiBzY2FsZS4gVGhpcyBsZWFkcyB0byBhIGZldyByZWxhdGlvbnNoaXBzL3RyYW5zZm9ybWF0aW9ucyB3aGljaCBjYW4gYmVjb21lIHVzZWZ1bC4gIAoKc2hhcGUgPSBtdS9zY2FsZSAgCnJhdGUgPSBzaGFwZS9tdSAgCnNjYWxlID0gbXUvc2hhcGUgIAoKSXQncyBhIGJpdCBvZiBhIHBhaW4sIGFzIGRlcGVuZGluZyBvbiBob3cgeW91IHB1dCB0aGluZ3MgdG9nZXRoZXIsIHlvdSBjYW4gZ2V0IHNsaWdodGx5IGRpZmZlcmVudCByZXN1bHRzIGZyb20gbW9kZWxzLiBCdXQgaXQgc2hvdWxkIG5vdCBtYXR0ZXIgdG8gcXVhbGl0YXRpdmUgb3V0Y29tZXMuCgojIyMgNS40IFByaW9ycwoKSW4gdGhpcyBjYXNlLCB3ZSBkb24ndCByZWFsbHkgaGF2ZSBhbnkgcHJpb3IgaW5mb3JtYXRpb24hIFNvIHdlIHdhbnQgZmxhdCBwcmlvcnMuIFdlIGNhbiB1c2UgcmVndWxhcml6YXRpb24gLSBzYXksIGIgfiBkbm9ybSgwLDMpLCBidXQgaG93IG11Y2ggZGVwZW5kcyBvbiB5b3UuIFdlJ3JlIGFsc28gZ29pbmcgdG8gd2FudCBwcmlvcnMgZm9yIHNjYWxlIG9yIHJhdGUgcGFyYW1ldGVycy4gVGhlc2UgY2FuIGJlIG5vcm1hbCwgYnV0IG9mdGVuIGNhdWNoeSAoZm9yIHNjYWxlKSBvciBleHBvbmVudGlhbCAoZm9yIHJhdGUpIHByaW9ycyB3b3JrIHdlbGwuIFlNTVYuCgojIyMgNS41LiBGaXR0aW5nIHdpdGggYSBHYW1tYQoKCiMjIyMgNS41LjEgVGhlIG1vZGVsClNvLCBsZXQncyBzdGFydCB3aXRoIGBkZ2FtbWFgLiBCeSBkZWZhdWx0LCBgZGdhbW1hYCB0YWtlcyBmaXJzdCBhIHNoYXBlIGFuZCB0aGVuIGEgcmF0ZSBhcmd1bWVudC4gVGhpcyBwcmVzZW50cyBhIHNtYWxsIGNoYWxsZW5nZSwgYXMgYWJvdmUgd2UgaGF2ZSBzaGFwZSA9IHJhdGUvbXUuIFRoaXMgbWVhbnMgd2Ugd291bGQgbmVlZCB0byB3b3JrIHdpdGggb3VyIG1lYW4gdmFsdWUgYSBiaXQuIFJhdGhlciB0aGFuIGEgc3RyYWlnaHQgYGxvZyhtdSlgIHN0YXRlbWVudCwgd2UncmUgZ29pbmcgdG8gbmVlZCB0byB1c2UgdGhlIGNhbGN1bGF0ZWQgdmFsdWUuICBMZXQncyBwdXQgdG9nZXRoZXIgYSBtb2RlbC4KCgpgYGB7ciBnYW1tYV9tb2QsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkocmV0aGlua2luZykKCmZpc2hpbmdfZ2FtbWFfbW9kIDwtIGFsaXN0KAogICNsaWtlbGlob29kCiAgI25vdGluZyB0aGF0IHJhdGUgPSBzaGFwZS9leHAobG9nX211KQogIGRheXNfYXRfc2VhIH4gZGdhbW1hKHNoYXBlLCBzaGFwZS9leHAobG9nX211KSksCiAgCiAgI2RhdGEgZ2VuZXJhdGluZyBwcm9jZXNzCiAgbG9nX211IDwtIGEgKyBiKnNlYXNfbSwKICAKICAjcHJpb3JzCiAgYSB+IGRub3JtKDAsMTAwKSwKICBiIH4gZG5vcm0oMCwxMDApLAogIHNoYXBlIH4gZGV4cCgyKQopCmBgYAoKCk1jRWxyZWF0aCBoYXMgYWxzbyBwdXQgdG9nZXRoZXIgYSBzaG9ydGN1dCwgYGRnYW1tYTJgLCBidXQgaXQgdGVuZHMgdG8gcHJvZHVjZSBzbGlnaHRseSBkaWZmZXJlbnQgcmVzdWx0cywgYXMgaXQgY2FsY3VsYXRlcyBzaGFwZSBhcyBhIGZ1bmN0aW9uIG9mIHRoZSBwcmVkaWN0b3JzLiBTbyBJJ20gbm90IGEgeXVnZSBmYW4uCgpgYGB7ciBnYW1tYV9tb2RfMn0KZmlzaGluZ19nYW1tYV9tb2QyIDwtIGFsaXN0KAogICNsaWtlbGlob29kCiAgZGF5c19hdF9zZWEgfiBkZ2FtbWEyKG11LCBzY2FsZSksCiAgCiAgI2RhdGEgZ2VuZXJhdGluZyBwcm9jZXNzCiAgbG9nKG11KSA8LSBhICsgYipzZWFzX20sCgogICNwcmlvcnMKICBhIH4gZG5vcm0oMCwxMDApLAogIGIgfiBkbm9ybSgwLDEwMCksCiAgc2NhbGUgfiBkY2F1Y2h5KDAsMikKKQpgYGAKCiMjIyMgNS41LjIgVGhlIGZpdAoKT0ssIGxldCdzIGZpdCB0aGlzIHRoaW5nIHVzaW5nIHRoZSBmaXJzdCBtb2RlbCEgIAoKYGBge3IgZml0X2dhbW1hLCBlcnJvcj1UUlVFfQpmaXNoaW5nX2dhbW1hX2ZpdCA8LSBtYXAoZmlzaGluZ19nYW1tYV9tb2QsIGRhdGE9ZmlzaGluZykKYGBgCgpVaCBvaCEgV2hhdCdzIHdyb25nPyAgCgphbmQgbm93LCB3ZSBlbmNvdW50ZXIgbWlzdGFrZSAjMS4gUmVtZW1iZXIgdGhhdCB3ZSdyZSB1c2luZyBhIGxvZyBsaW5rPyBXZWxsLCBsb2coMCkgaXMgbm90IGEgbnVtYmVyLCBzbywgb2YgY291cnNlIG91ciBtb2RlbCBmYWlscyEgU28gd2UgbmVlZCB0byBkcm9wIHRob3NlIDBzLiBUaGV5IG1lYW4gdGhhdCBhIGZpc2hlcm1hbiBkaWRuJ3QgbGVhdmUgcG9ydCBhdCBhbGwsIGFuZCBhcmUgbGlrZWx5IGJlc3QgY29uaXNkZXJlZCBhcyBhIHNlcGFyYXRlIHByb2Nlc3MuIFJlZ2FyZGxlc3MsIGV2ZW4gaWYgd2Ugd2FudCB0byBmb2xkIHRoZW0gYmFjayBpbiAoc2VlIGJlbG93KSwgd2Ugd291bGQgYmUgZ3JlYXRseSBoZWxwZWQgYnkgYnVpbGRpbmcgYSBtb2RlbCB0aGF0IGRvZXMgbm90IHJlcXVpcmUgaGFuZGxpbmcgdGhvc2UgZGV0YWlscy4KCmBgYHtyIGZpdF9nYW1tYV9nb29kLCBlcnJvcj1UUlVFfQpmaXNoaW5nX2NsZWFuIDwtIGZpc2hpbmcgJT4lIGZpbHRlcihkYXlzX2F0X3NlYSAhPSAwKQoKc2V0LnNlZWQoNjA5KQpmaXNoaW5nX2dhbW1hX2ZpdCA8LSBtYXAoZmlzaGluZ19nYW1tYV9tb2QsIGRhdGE9ZmlzaGluZ19jbGVhbikKYGBgCgpPb3BzISBUaGF0IGRpZG4ndCB3b3JrIGVpdGhlciEgV2VsbCB0aGF0J3Mgbm90IGdvb2QuIFNvLCB3aGF0IGRvZXMgdGhlIGVycm9yIHNheT8gVGhhdCBzdGFydCB2YWx1ZXMgd2VyZSBpbnZhbGlkLiAgT0suCgpXZWxwLCBleWViYWxsaW5nIHRoZSBncmFwaCBvZiB0aGUgZGF0YSwgd2Ugc2VlIGEgcG9zaXRpdmUgaW50ZXJjZXB0IGFuZCBuZWdhdGl2ZSBzbG9wZS4gU28sIGV2ZW4gd2l0aCB0aGUgc2FtZSBzZWVkIChvdGhlciBzZWVkIHZhbHVlcyBhbGxvdyBmb3IgY29udmVyZ2VuY2UpLCBsZXQncyByZS10cnkhCgpgYGB7ciBmaXRfZ2FtbWFfcmVhbGx5X2dvb2R9CnNldC5zZWVkKDYwOSkKZmlzaGluZ19nYW1tYV9maXQgPC0gbWFwKGZpc2hpbmdfZ2FtbWFfbW9kLCBkYXRhPWZpc2hpbmdfY2xlYW4sCiAgICAgICAgICAgICAgICAgICAgICAgICBzdGFydCA9IGxpc3QoYT0xLCBiPS0xKSkKYGBgCgpGaXQhCgojIyMjIDUuNS4zIE1vZGVsIGV2YWx1YXRpb24KCkxldCdzIGNoZWNrIG91dCBvdXIgcG9zdGVyaW9yIQoKYGBge3IgcG9zdF9ub3JtYWx9CnBhaXJzKGZpc2hpbmdfZ2FtbWFfZml0KQpgYGAKCkhleSEgTm90IGJhZC4gSW5kZWVkLCBJIHdvdWxkbid0IGV2ZW4gZ28gdG8gU1RBTiB3aXRoIGEgZml0IGxpa2UgdGhpcy4KCmBgYHtyIHBvc3RjaGVjaywgZXJyb3I9VFJVRSwgcmVzdWx0cz0iaGlkZSIsIG1lc3NhZ2U9RkFMU0V9CnBhcihtZnJvdz1jKDIsMykpCnBvc3RjaGVjayhmaXNoaW5nX2dhbW1hX2ZpdCkKcGFyKG1mcm93PWMoMSwxKSwgYXNrPUYpCmBgYAoKTG9va2luZyBwcmV0dHkgZ29vZCEgdGhlcmUgYXJlIG9uZSBvciB0d28gcG9pbnRzIG91dHNpZGUgb2YgdGhlIHByZWRpY3RpdmUgQ0ksIGJ1dCwgZWgsIHRoYXQncyBub3QgYmFkIGNvbnNpZGVyaW5nIHRoZSBsYXJnZSBudW1iZXIgb2YgZGF0YSBwb2ludHMgd2UgaGF2ZS4gV29ydGggaW52ZXN0aWdhdGluZywgYnV0IG5vdCBsb3NpbmcgdG9vIG11Y2ggc2xlZXAgb3Zlci4KCiMjIyMgNS41LjQgV2hhdCBkbyB0aGUgcmVzdWx0cyBzYXk/CgpXZSBjYW4gZmlyc3QgbG9vayBhdCB0aGUgZ2VuZXJhbCByZXN1bHRzCgpgYGB7ciBwcmVjaXNfZ2FtbWF9CnByZWNpcyhmaXNoaW5nX2dhbW1hX2ZpdCkKYGBgCgpTbywgYSBkZWNsaW5lIG9mIC0wLjYzLCBvciwgZm9yIGV2ZXJ5IDFtIHdhdmUsIGZpc2hlcm1lbiB3b3VsZCBzcGVuZCA1MyUgbGVzcyB0aW1lIGF0IHNlYSAoYGV4cCgtMC42MylgKS4gV2UgY2FuJ3Qgc2F5IGFic29sdXRlIGRheXMgaGVyZSwgYXMgdGhpcyBpcyBhIG5vbmxpbmVhciBmdW5jdGlvbiAtIHdoYXQgaGFwcGVucyBpbiBhYnNvbHV0ZSB1bml0cyBnb2luZyBmcm9tIDIgdG8gMyBpcyBkaWZmZXJlbnQgZnJvbSAzIHRvIDQuIEJ1dCB3ZSBjYW4ganVkZ2UgaXQgb24gYSBwZXJjZW50YWdlIHNjYWxlLiBUcnkgY2FsY3VsYXRpbmcgaXQgb3V0IGlmIHlvdSBkb24ndCBiZWxpZXZlIGl0LiAgCgpXZSBjYW4gYWxzbyB2aXN1YWxpemUgdGhlIHJlc3VsdHMKCmBgYHtyIGZpdF9wbG90LCByZXN1bHRzPSJoaWRlIn0KI3N0YXJ0IHdpdGggYSBmcmVzaCBkYXRhIGZyYW1lIG9mIHByZWRpY3RlZCB2YWx1ZXMKcHJlZF9kZiA8LSBkYXRhLmZyYW1lKHNlYXNfbSA9IHNlcSgwLDUsbGVuZ3RoLm91dD0yMDApKQoKI09LLCBub3cgZ2V0IHNvbWUgc2ltIGFuZCBsaW5rIG91dHB1dApzaW1fZmlzaGluZyA8LSBzaW0oZmlzaGluZ19nYW1tYV9maXQsIGRhdGE9cHJlZF9kZikKCiNub3RlLCBmb3IgbGluaywgd2UgbmVlZCB0byBleHBvbmVudGlhdGUKbGlua19maXNoaW5nIDwtIGV4cChsaW5rKGZpc2hpbmdfZ2FtbWFfZml0LCBkYXRhPXByZWRfZGYpKQoKI3Ntb29zaCBpdCBhbGwgdG9nZXRoZXIKcHJlZF9kZiA8LSBwcmVkX2RmICU+JQogIG11dGF0ZShkYXlzX2F0X3NlYSA9IGFwcGx5KGxpbmtfZmlzaGluZywgMiwgbWVkaWFuKSwKICAgICAgICAgbHdyX2ZpdCA9IGFwcGx5KGxpbmtfZmlzaGluZywgMiwgSFBESSlbMSxdLAogICAgICAgICB1cHJfZml0ID0gYXBwbHkobGlua19maXNoaW5nLCAyLCBIUERJKVsyLF0sCiAgICAgICAgIGx3ciA9IGFwcGx5KHNpbV9maXNoaW5nLCAyLCBIUERJKVsxLF0sCiAgICAgICAgIHVwciA9IGFwcGx5KHNpbV9maXNoaW5nLCAyLCBIUERJKVsyLF0KICAgICAgICAgKQoKI2EgbmljZSBnZ3Bsb3QKZ2dwbG90KGRhdGE9cHJlZF9kZiwKICAgICAgIG1hcHBpbmc9YWVzKHg9c2Vhc19tLCB5PWRheXNfYXRfc2VhKSkgKwogIGdlb21fcmliYm9uKG1hcHBpbmc9YWVzKHltaW49bHdyLCB5bWF4PXVwciksIGFscGhhPTAuNCkgKwogIGdlb21fcmliYm9uKG1hcHBpbmc9YWVzKHltaW49bHdyX2ZpdCwgeW1heD11cHJfZml0KSwgZmlsbD0iYmx1ZSIsIGFscGhhPTAuNCkgKwogIGdlb21fbGluZShsd2Q9MSwgY29sb3I9InJlZCIpICsKICBnZW9tX3BvaW50KGRhdGE9ZmlzaGluZ19jbGVhbikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZT0xNykKYGBgCgpOb3QgYmFkLiBXZSBjYW4gc2VlIHRoZSByZXN1bHRzIG9mIGEgR2FtbWEgZGlzdHJpYnV0aW9uIC0gdGhlIG1lYW4gdmFyaWFuY2Ugc2NhbGluZyByZWxhdGlvbnNoaXAuIFdlIGNhbiBzZWUgd2UgaGF2ZSBzb21lIG91dGxpZXJzIHRvIGluc3BlY3QsIGJ1dCwgb3ZlcmFsbCwgcHJldHR5IGRhcm5lZCBnb29kLgoKIyMgNi4gQWJvdXQgdGhvc2UgWmVyb2VzIC0gWmVybyBBdWdtZW50ZWQgR2FtbWEKIVtdKC4vaW1hZ2VzLzIwL3doYXQtaWYtaS10b2xkLXlvdS13aGF0LWlmLWktdG9sZC15b3UteW91LWFscmVhZHkta25vdy16ZXJvLWluZmxhdGlvbi5qcGcpCgojIyMgNi4xIFplcm8gSW5mbGF0aW9uLCBhdWdtZW50YXRpb24sIGh1cmRsZXMsIGFuZCBtb3JlCgpFeGNlc3NpdmUgemVyb2VzIGFyZSBub3Qgc29tZXRoaW5nIHRvIGJlIHNjYXJlZCBvZi4gT2Ygd2hpY2ggdG8gYmUgc2NhcmVkPyBXaGF0ZXZlciwgeW91IGd1eXMga25vdyB0aGlzIG9uIGEgZGVlcCBsZXZlbC4gQmVjYXVzZSBhIHplcm8gaW5mbGF0ZWQgb3IgemVybyBhdWdtZW50ZWQgZGlzdHJpYnV0aW9uIGlzIG5vdGhpbmcgbW9yZSB0aGFuIHRoZSBsb3ZlY2hpbGQgb2YgYSBiaW5vbWlhbCBsb2dpc3RpYyByZWdyZXNzaW9uIGFuZCBhIEdMTSBvZiB5b3VyIG93biBjaG9vc2luZy4KCkxldCdzIHN0YXJ0IGJ5IHRoaW5raW5nIGFib3V0IGEgSHVyZGxlIG9yIFplcm8gQXVnbWVudGVkIG1vZGVsLiBJbiB0aGVzZSBtb2RlbHMsIHlvdSBjYW5ub3QgaGF2ZSBhbnkgemVyb2VzIGZvciByZWFzb25zIHJlbGF0ZWQgdG8gY29uc3RyYWlucyBvZiB5b3VyIGRhdGEgZ2VuZXJhdGluZyBwcm9jZXNzIG9yIGVycm9yIGdlbmVyYXRpbmcgcHJvY2Vzcy4gSW5zdGVhZCwgWmVyb2VzIGFyZSBnZW5lcmF0ZWQgYnkgb25lIGRhdGEgZ2VuZXJhdGluZyBwcm9jZXNzLCB0aGVuIGFub3RoZXIgcHJvY2VzcyBkZXRlcm1pbmVzIHRoZSByZWxhdGlvbnNoaXAgd2l0aCB5b3VyIHJlc3BvbnNlIHZhcmlhYmxlLiBTbywgeW91IGZpcnN0IHNwbGl0IHlvdXIgbW9kZWwgaW50byBvbmUgd2hlcmUgeW91IGhhdmUgZWl0aGVyIDAgb3Igbm9uLTAgb3V0Y29tZXMsIGFuZCBwZXJmb3JtIGEgbG9naXN0aWMgcmVncmVzc2lvbi4gV2l0aCB3aGF0ZXZlciBwcmVkaWN0b3JzIHlvdSB3YW50LiBUaGVuLCB3aXRoIGFsbCBvZiB0aGUgbm9uLXplcm8gb3V0Y29tZXMsIHlvdSBwZXJmb3JtIHdoYXRldmVyIEdMTSB5b3Ugd2FudC4KCkEgWmVybyBJbmZsYXRlZCBvciBaZXJvIEF1Z21lbnRlZCBtb2RlbCBpcyBzbGlnaHRseSBkaWZmZXJlbnQuIEhlcmUsIHplcm9lcyBhcmUgZ2VuZXJhdGVkIGVpdGhlciBieSBzb21lIHByb2Nlc3MgdGhhdCBpcyBiaW5hcnkgLSBhIHRoaW5nIGhhcHBlbmVkIG9yIGl0IGRpZG4ndCAtIE9SIHRoZXkgYXJlIGdlbmVyYXRlZCBieSB3aGF0ZXZlciAgZGF0YSBnZW5lcmF0aW5nIHByb2Nlc3MgeW91IGFyZSBtb2RlbGluZy4KCiFbXSguL2ltYWdlcy8yMC96aWdfemFnLmpwZykKClplcm8gSW5mbGF0ZWQgbW9kZWxzIGNvbWUgaW4gbWFueSBmb3JtcyAtIFplcm8gSW5mbGF0ZWQgUG9pc3NvbiAodXNlcyBgZHppcG9pcyhsYW1iZGEsIHApYCBpbiByZXRoaW5raW5nKSwgWmVybyBJbmZsYXRlZCBCaW5vbWlhbCAodXNlcyBgZHppYmlub20ocF96ZXJvLCBzaXplLCBwKWApLCBaZXJvIEF1Z21lbnRlZCBHYW1tYSAoYGR6YWdhbW1hMihwcm9iLCBtdSwgc2NhbGUpYCkgYW5kIG1vcmUgd2hpY2ggY2FuIGJlIHB1bGxlZCBmcm9tIG90aGVyIGxpYnJhcmllcyBpbiBSLgoKIyMjIDYuMiBIb3cgZG8gSSBrbm93IGlmIGl0IGlzIHplcm8gaW5mbGF0ZWQgCgpUaGVyZSBhcmUgdHdvIHN0cmFpZ2h0Zm9yd2FyZCB3YXlzIHRvIHNlZSBpZiBzb21ldGhpbmcgaXMgemVybyBpbmZsYXRlZC4gRmlyc3QsIHdoYXQncyB0aGUgZGlzdHJpYnV0aW9uIGxvb2sgbGlrZT8gRG8geW91IHNlZSBhIGxvdCBvZiB6ZXJvcz8KCmBgYHtyIHpkZW5zfQpwbG90KGRlbnNpdHkoZmlzaGluZyRkYXlzX2F0X3NlYSkpCmBgYAoKT0sgLSBsb3RzIG9mIHplcm9lcyAtIHdoaWNoLCBnaXZlbiB0aGF0IHRoaXMgaXMgYSBHYW1tYSwgaXMgc3VwZXIgc3VzcGVjdC4gQnV0LCBmb3IgdGhpcyBvciBvdGhlciBkaXN0cmlidXRpb25zLCB0aGV5IG1pZ2h0IGJlIE9LLiBTb21ldGltZXMgeW91J2xsIGV2ZW4gc2VlIHR3byBodW1wcyAtIG9uZSBhcm91bmQgemVybywgb25lIHNvbWV3aGVyZSBlbHNlLiBaZXJvIEluZmxhdGlvbiEKCllvdSBjYW4gYWxzbyBsb29rIGF0IGEgc2NhdHRlcnBsb3QgYW5kIHNlZSBpZiB0aGVyZSBhcmUgYSBzdXNwaWNpb3VzIG51bWJlciBvZiB6ZXJvZXMgYWNyb3NzIGFsbCBvZiB0aGUgdmFsdWVzIG9mIGEgcHJlZGljdG9yIHZhcmlhYmxlLiBTdXJlLCB5b3UgbWlnaHQgYWh2ZSBhIG5vbi1ub3JtYWwgZGlzdHJpYnV0aW9uLCBidXQgdGhhdCBraW5kIG9mIHBhdHRlcm4gaXMgYSBiaXQgb2RkLgoKYGBge3IgZnVsbF9zY2F0dGVyfQpwbG90KGRheXNfYXRfc2VhIH4gc2Vhc19tLCBkYXRhPWZpc2hpbmcpCmBgYAoKIyMjIDYuMyBVc2luZyB0aGUgWkFHCgpUbyB3b3JrIHdpdGggb3VyIG9yaWdpbmFsIGRhdGEgLSB6ZXJvZXMgYW5kIGFsbCAtIHdlIGNhbiB1c2UgYSBaZXJvIEF1Z21lbnRlZCBHYW1tYSBEaXN0cmlidXRpb24uIEknbSBzdGlsbCBub3QgYSBodWdlIGZhbiBvZiBgZHphZ2FtbWEyYCBzbyBsZXQncyBtYWtlIG91ciBvd24gdXNpbmcgdGhlIHJhdGUgZm9ybXVsYXRpb24uIFRvIGRvIHRoaXMsIEkgbGl0ZXJhbGx5IGp1c3QgZW50ZXJlZCBgZHphbW1hMmAgaW4gUiwgdGhlbiByZXdyb3RlIHRoZSBmdW5jdGlvbiBhIGJpdCB0byB1c2UgdGhlIHJhdGUgZm9ybXVsYXRpb24uCgpgYGB7ciBkemFnYW19CgpkemFnYW1tYSA8LSBmdW5jdGlvbiAoeCwgcHJvYiwgc2hhcGUsIHJhdGUsIGxvZyA9IEZBTFNFKSAKewogIEsgPC0gYXMuZGF0YS5mcmFtZShjYmluZCh4ID0geCwgcHJvYiA9IHByb2IsIHNoYXBlID0gc2hhcGUsIHJhdGUgPSByYXRlKSkKICBsbGcgPC0gZGdhbW1hKHgsIHNoYXBlID0gc2hhcGUsIHJhdGUgPSByYXRlLCBsb2cgPSBUUlVFKQogIGxsIDwtIGlmZWxzZShLJHggPT0gMCwgbG9nKEskcHJvYiksIGxvZygxIC0gSyRwcm9iKSArIGxsZykKICBpZiAobG9nID09IEZBTFNFKSAKICAgIGxsIDwtIGV4cChsbCkKICBsbAp9CmBgYAoKTGV0IHRoaXMgYmUgYSBsZXNzIC0geW91IGNhbiBwdXQgaW4gd2hhdGV2ZXIgZGVuc2l0eSBmdW5jdGlvbiB5b3Ugd2FudCAtIGlmIFIgZG9lc24ndCBoYXZlIGl0LCB3cml0ZSB5b3VyIG93biEgSGVjaywgdGhpcyBmb3JtYXQgaXMgYSByZWFsbHkgc3RyYWlnaHRmb3J3YXJkIHdheSB0byB0dXJuIGFueSBkaXN0cmlidXRpb24gLSBub3JtYWwsIHdoYXRldmVyIC0gaW50byBhIHplcm8gaW5mbGF0ZWQgZGlzdHJpYnV0aW9uLgoKSW4gdGhpcyBkaXN0cmlidXRpb24sIHdlJ2xsIGhhdmUgYSBsb3Qgb2YgZXh0cmEgMHMuIFdoYXQncyBncmVhdCBpcyB0aGF0IHdlIGNhbiBhcHByb3ByaWF0ZSBvdXIgZWFybGllciBtb2RlbCBmb3IgdXNlIGhlcmUuCgpgYGB7ciB6YWdfbW9kfQpmaXNoaW5nX3phZ2FtbWFfbW9kIDwtIGFsaXN0KAogICNsaWtlbGlob29kCiAgI25vdGluZyB0aGF0IHJhdGUgPSBzaGFwZS9leHAobG9nX211KQogIGRheXNfYXRfc2VhIH4gZHphZ2FtbWEyKHByb2IsIG11LCBzY2FsZSksCiAgCiAgI2RhdGEgZ2VuZXJhdGluZyBwcm9jZXNzCiAgbG9nKG11KSA8LSBhICsgYipzZWFzX20sCiAgCiAgI3ByaW9ycwogIGEgfiBkbm9ybSgwLDEwMCksCiAgYiB+IGRub3JtKDAsMTAwKSwKICBzY2FsZSB+IGRleHAoMiksCiAgcHJvYiB+IGR1bmlmKDAsMSkKKQpgYGAKCldlIGhhdmUgbm8gaW5mbyBvbiB0aGUgcHJvYmFiaWxpdHksIHNvLCB3ZSdyZSBqdXN0IHB1dHRpbmcgaW4gYSBmbGF0IHVuaWZvcm0gcHJpb3IgYmV0d2VlbiAwIGFuZCAxLiBXZSBjb3VsZCB1c2UgYSBiZXRhIGlmIHdlIHdhbnRlZCwgYnV0LCBtZWguIFdlIGNhbiB0aGVuIGZpdCB0aGlzLCB1c2luZyBvdXIgbGVzc29ucyBhYm91dCBzdGFydCB2YWx1ZXMgZnJvbSBiZWZvcmUuCgpgYGB7ciB6YWdfZml0fQpmaXNoaW5nX3phZ2FtbWFfZml0IDwtIHF1YXAoZmlzaGluZ196YWdhbW1hX21vZCwgZGF0YT1maXNoaW5nLAogICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQgPSBsaXN0KGE9MSwgYj0tMSkpCmBgYAoKIyMjIDYuNCBFdmFsdWF0aW9uCgpMZXQncyBsb29rIGF0IHRob3NlIHBvc3RlcmlvcnMhCgpgYGB7ciBwYWlyc196YWd9CnBhaXJzKGZpc2hpbmdfemFnYW1tYV9maXQpCmBgYAoKVGhlIHBhaXJzIHBsb3QgbG9va3MgbmljZSBhbmQgd2VsbCBiZWhhdmVkLiBPdGhlciBjaGVja3MgYW5kIGBzaW1gIGFyZSBhIGJpdCBtb3JlIGRpZmZpY3VsdCwgYXMgdGhleSByZXF1aXJlIGEgcmFuZG9tIG51bWJlciBnZW5lcmF0b3Igd2hpY2ggd2UgY3VycmVudGx5Li4uIGRvbid0IGhhdmUuIFNvLCBsZXQncyBtYWtlIG9uZS4KCmBgYHtyIHJ6YWd9CnJ6YWdhbW1hMiA8LSBmdW5jdGlvbihuLCBwcm9iLCBzY2FsZSwgcmF0ZSl7CiAgaXNfemVybyA8LSByYmlub20obiwgMSwgcHJvYj0xLXByb2IpCiAgaXNfemVybyAqIHJnYW1tYShuLCBzY2FsZSA9IHNjYWxlLCByYXRlKQp9CmBgYAoKV2l0aCB0aGlzLCB3ZSBjYW4gdXNlIHBvc3RjaGVjawoKYGBge3IgcG9zdGNoZWNrX3phZ30KcGFyKG1mcm93PWMoMywzKSkKcG9zdGNoZWNrKGZpc2hpbmdfemFnYW1tYV9maXQpCnBhcihtZnJvdz1jKDEsMSksIGFzaz1GKQpgYGAKCkhleSAtIGl0J3MgYWxsIG9mIHRoZSBkYXRhISBBbmQgaXQgbG9va3MgLSBnb29kISAKCgojIyMjIDYuNSBXaGF0IGRvIHRoZSByZXN1bHRzIHNheT8KCldlIGNhbiBmaXJzdCBsb29rIGF0IHRoZSBnZW5lcmFsIHJlc3VsdHMKCmBgYHtyIHByZWNpc196Z2FtbWF9CnByZWNpcyhmaXNoaW5nX3phZ2FtbWFfZml0KQpgYGAKCk5vIHN1cnByaXNlLCBvdXIgY29lZmZpY2llbnRzIGFyZSBleGFjdGx5IHRoZSBzYW1lIGFzIGJlZm9yZSEgV2Fob28hIEV4Y2VwdCBub3cgd2UgYWxzbyBrbm93IHRoZXJlJ3MgYSAzMCUgY2hhbmNlIG9uIGFueSBnaXZlbiBkYXkgdGhhdCBhIGZpc2hlcm1hbiB3aWxsIGp1c3Qgc2F5ICdtZWgnIGFuZCBub3QgZ28gZG8gc2VhLgoKV2UgY2FuIGFsc28gdmlzdWFsaXplIHRoZSByZXN1bHRzLiBGaXJzdCwgd2Ugd2lsbCBwbG90IHRoZSBwcmVkaWN0aW9uIGZvciBKVVNUIHRoZSBub24temVybyByZXN1bHRzIHVzaW5nIHRoZSBmaXR0ZWQgbW9kZWwuIFRoZW4gd2Ugd2lsbCBjb250cmFzdCBpdCB0byBwdXR0aW5nIGluIHRoZSBmdWxsIDAncyBwcmVkaWN0aW9uLCB3aGljaCBjb21lcyBmcm9tIHRoZSBaQUcgZGlzdHJpYnRpb24uCgpgYGB7cn0KIyBhIHByZWRpY3Rpb24gZnJhbWUKcHJlZF96YWcgPC0gcHJlZGljdGVkX2RyYXdzKGZpc2hpbmdfemFnYW1tYV9maXQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhLmZyYW1lKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWFzX20gPSBzZXEoMCwgNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aC5vdXQgPSAxMDApKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gImRheXNfYXRfc2VhIikKCgojIGEgbGlucHJlZCBmcmFtZQpmaXRfemFnIDwtIGxpbnByZWRfZHJhd3MoZmlzaGluZ196YWdhbW1hX2ZpdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEuZnJhbWUoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlYXNfbSA9IHNlcSgwLCA1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoLm91dCA9IDEwMCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSAiZGF5c19hdF9zZWEiKQoKIyBmaXQgaW50ZXJ2YWwgb2YgbGluayAtIG5vdCB3aXRoIFpBRwpnZ3Bsb3QoZml0X3phZywKICAgICAgIGFlcyh4ID0gc2Vhc19tLCB5ID0gZGF5c19hdF9zZWEpKSArCiAgc3RhdF9saW5lcmliYm9uKCkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiR3JlZW5zIikgKwogIGdlb21fcG9pbnQoZGF0YSA9IGZpc2hpbmcpCgojIHByZWRpY3Rpb24gaW50ZXJ2YWwKZ2dwbG90KHByZWRfemFnLAogICAgICAgYWVzKHggPSBzZWFzX20sIHkgPSBkYXlzX2F0X3NlYSkpICsKICBzdGF0X2xpbmVyaWJib24oKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJPcmFuZ2VzIikgKwogIGdlb21fcG9pbnQoZGF0YSA9IGZpc2hpbmcpCmBgYAoKTm90ZSB0aGUgZGlmZmVyZW5jZSBpbiBDSSB3aWR0aCBhbmQgZG93bndlaWdodGluZyBvZiB0aGUgbGluZSB3aXRoIGp1c3QgZml0LiBUaGVyZSBpcyBhIGxvdCBtb3JlIGdvaW5nIG9uIGhlcmUsIGFuZCB0aGUgZnVsbCBwcmVkaWN0aW9uIGludGVydmFsIGdpdmVzIHVzIHdoYXQgd2UgbmVlZCB0byBzZWUuCgo8IS0tCgpgYGB7ciBmaXQsIHJlc3VsdHM9ImhpZGUifQojc3RhcnQgd2l0aCBhIGZyZXNoIGRhdGEgZnJhbWUgb2YgcHJlZGljdGVkIHZhbHVlcwpwcmVkX2RmX3ogPC0gZGF0YS5mcmFtZShzZWFzX20gPSBzZXEoMCw1LGxlbmd0aC5vdXQ9MjAwKSkKCiNPSywgbm93IGdldCBzb21lIHNpbSBhbmQgbGluayBvdXRwdXQKc2ltX2Zpc2hpbmdfeiA8LSBzaW0oZmlzaGluZ196YWdhbW1hX2ZpdCwgZGF0YT1wcmVkX2RmX3opCgojbm90ZSwgZm9yIGxpbmssIHdlIG5lZWQgdG8gZXhwb25lbnRpYXRlCmxpbmtfZmlzaGluZ196IDwtIGV4cChsaW5rKGZpc2hpbmdfemFnYW1tYV9maXQsIGRhdGE9cHJlZF9kZl96KSkKCiNzbW9vc2ggaXQgYWxsIHRvZ2V0aGVyCnByZWRfZGZfeiA8LSBwcmVkX2RmX3ogJT4lCiAgbXV0YXRlKGRheXNfYXRfc2VhID0gYXBwbHkobGlua19maXNoaW5nX3osIDIsIG1lZGlhbiksCiAgICAgICAgIGx3cl9maXQgPSBhcHBseShsaW5rX2Zpc2hpbmdfeiwgMiwgSFBESSlbMSxdLAogICAgICAgICB1cHJfZml0ID0gYXBwbHkobGlua19maXNoaW5nX3osIDIsIEhQREkpWzIsXSwKICAgICAgICAgbHdyID0gYXBwbHkoc2ltX2Zpc2hpbmdfeiwgMiwgSFBESSlbMSxdLAogICAgICAgICB1cHIgPSBhcHBseShzaW1fZmlzaGluZ196LCAyLCBIUERJKVsyLF0KICAgICAgICAgKQoKI2EgbmljZSBnZ3Bsb3QKZ2dwbG90KGRhdGE9cHJlZF9kZl96LAogICAgICAgbWFwcGluZz1hZXMoeD1zZWFzX20sIHk9ZGF5c19hdF9zZWEpKSArCiAgZ2VvbV9yaWJib24obWFwcGluZz1hZXMoeW1pbj1sd3IsIHltYXg9dXByKSwgYWxwaGE9MC40KSArCiAgZ2VvbV9yaWJib24obWFwcGluZz1hZXMoeW1pbj1sd3JfZml0LCB5bWF4PXVwcl9maXQpLCBmaWxsPSJibHVlIiwgYWxwaGE9MC40KSArCiAgZ2VvbV9saW5lKGx3ZD0xLCBjb2xvcj0icmVkIikgKwogIGdlb21fcG9pbnQoZGF0YT1maXNoaW5nKSArCiAgdGhlbWVfYncoYmFzZV9zaXplPTE3KQpgYGAKCkl0J3MgaGFyZCB0byBzZWUgdGhlIGRpZmZlcmVuY2UgcmVsYXRpdmUgdG8gdGhlIHByZXZpb3VzIHBsb3QsIGJ1dCwgaWYgeW91IHRha2UgYSBnYW5kZXIsIHRoZSBzY2FsZSBvZiB0aGUgcHJlZGljdGl2ZSBpbnRlcnZhbCBoYXMgc2hydW5rIGEgYml0LiBPciwgZ2V0cyBwdWxsZWQgdG93YXJkcyB6ZXJvLCBhcyBpdCB3ZXJlLCBhcyB3ZSBoYXZlIGEgbG90IG9mIHplcm9lcy4gTWFrZXMgc2Vuc2UhCi0tPg==