Regular counts
Let’s consider a regular Poisson regression model for catches of spot
prawns \(y_i\) as a function of bait
type \(C_i\) and water temperature
\(T_i\), such that
\[
\begin{aligned}
\text{data distribution:} & ~~ y_i \sim \text{Poisson}(\lambda_i) \\
\\
\text{link function:} & ~~ \text{log}(\lambda_i) = \mu_i \\ \\
\text{linear predictor:} & ~~ \mu_i = \alpha + \beta_1 C_i + \beta_2
T_i
\end{aligned}
\]
Catches of spot prawns
The first step is to simulate the catch data. We’ll assume that
catches of spot prawns increase with water temperature, and that catches
are generally greater when using fish as bait compared to chicken.
set.seed(514)
## sample size
nn <- 113
## average catch
b0 = 3.5
## effect of chicken as bait
b_bait <- 0.1
## effect of temperature
b_temp <- 0.03
## bait type
fish <- sample(c(0, 1), nn, replace = TRUE)
## water temp
temp <- runif(nn, 7, 13)
## linear predictor
eta <- exp(b0 + b_bait * fish + b_temp * temp)
## catches
catch <- rep(NA, length(eta))
for(i in 1:nn) {
catch[i] <- rpois(1, eta[i])
}
## combine data
prawns <- data.frame(cbind(catch, fish, temp))
Here are plots of catch versus water temperature and bait type.
## set plot area
par(mfrow = c(1, 2),
mai = c(0.9, 0.4, 0.6, 0.1),
omi = c(0, 0.7, 0, 0), bg = NA,
cex.main = 1.2, cex.lab = 1.2)
## plot temp vs catch
plot(temp, catch, las = 1, pch = 16, xpd = NA,
xlab = "Temperature (C)", ylab = "Catch")
## plot bait vs catch
plot(fish + 1, catch, las = 1, pch = 16,
xlim = c(0.5, 2.5), xlab = "Bait type", xaxt = "n",
yaxt = "n", ylab = "")
axis(1, at = c(1, 2), labels = c("Chicken", "Fish"))

Model fitting
Fitting Poisson regression models proceeds as with other GLMs using
glm(). Recall that we must specify both the
family of the distribution and the link type.
By default glm() assumes the canonical link once a family
is specified, but it’s good “defensive programming” to explicitly
include it anyway. Here is our model for catch as a function of
temperature and bait type.
## Poisson regression
cmod <- glm(catch ~ temp + fish, data = prawns,
family = poisson(link = "log"))
faraway::sumary(cmod)
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 3.5717603 0.0856999 41.6775 < 2.2e-16
## temp 0.0258438 0.0080182 3.2231 0.001268
## fish 0.0803358 0.0275039 2.9209 0.003490
##
## n = 113 p = 3
## Deviance = 152.84428 Null Deviance = 171.01822 (Difference = 18.17393)
All three model coefficients are “significant” at the \(\alpha\) = 0.05 level. Recall that the true
values are (Intercept) = 3.5, temp = 0.03, and
fish = 0.1, so our estimates are reasonably close to the
true values. Also recall that because bait type is a categorical
predictor with 2 levels, the effect of fish represents the
case where the bait type is fish. If the bait type is chicken, then the
effect is zero.
We also get an estimate of the model deviance
(Deviance), which is ~152.84. To extract the deviance from
a fitted model, you can use deviance(cmod) or
summary(cmod)$deviance.
Inference
Once we’ve fit out model, it’s natural to wonder about parameter
(un)certainty, goodness of fit, and whether model diagnostics reveal any
possible problems with our model.
Confidence intervals for \(\beta_i\)
We can easily estimate the CI’s on the model parameters with
confint(). Here are the upper and lower 95% CI’s on our
model parameters with the MLEs.
## CI's for prawn model
ci_prawns <- confint(cmod)
ci_tbl <- cbind(ci_prawns[,1], coef(cmod), ci_prawns[,2])
colnames(ci_tbl) <- c("Lower", "MLE", "Upper")
signif(ci_tbl, 3)
## Lower MLE Upper
## (Intercept) 3.4000 3.5700 3.7400
## temp 0.0101 0.0258 0.0416
## fish 0.0265 0.0803 0.1340
We saw in lecture that we can have possible biases in \(\text{SE}(\beta)\), which means we may want
to compute CI’s based on the profile likelihood. To calculate
the profile likelihoods, we simply evaluate the likelihood at each point
along a sequence of possible parameter values. Here are the profile
likelihoods for the effects of temperature and bait type.
## number of points to profile
nb <- 200
## possible beta's
beta_bait <- seq(0, 0.2, length = nb)
beta_temp <- seq(-0.01, 0.07, length = nb)
## calculate neg-LL of possible beta_temp
## fix beta_bait at its MLE
plt <- rep(NA, nb)
for(i in 1:nb) {
mm <- glm(catch ~ 1 + offset(beta_temp[i] * temp + offset(coef(cmod)[3] * fish)),
data = prawns,
family = poisson(link = "log"))
plt[i] <- -logLik(mm)
}
## calculate neg-LL of possible beta_bait
## fix beta_temp at its MLE
plb <- rep(NA, nb)
for(i in 1:nb) {
mm <- glm(catch ~ 1 + offset(coef(cmod)[2] * temp + offset(beta_bait[i] * fish)),
data = prawns,
family = poisson(link = "log"))
plb[i] <- -logLik(mm)
}
Here are plots of the profile likelihoods and the threshold value
based upon the 95\(^{th}\) percentile
for a \(\chi^2_{1}\) on one degree of
freedom (i.e., the difference in the number of parameters between the
model and a model without the parameter). The blue points are the
estimated lower and upper 95% CI.
## set plot area
par(mfrow = c(1, 2),
mai = c(0.9, 0.9, 0.6, 0.1),
omi = c(0, 0, 0, 0),
cex.lab = 1.5)
## threshold value for CI
crit <- -(logLik(cmod) - qchisq(0.95, 1) / 2)
## likelihood profile for temp
plot(beta_temp, plt, type = "l", las = 1,
ylab = "Negative log-likelihood", xlab = expression(beta[temp]))
abline(h = crit, lty = "dashed")
points(confint(cmod)[2,], c(crit, crit), pch = 16, col = "blue")
## likelihood profile for bait
plot(beta_bait, plb, type = "l", las = 1,
ylab = "", xlab = expression(beta[bait]))
abline(h = crit, lty = "dashed")
points(confint(cmod)[3,], c(crit, crit), pch = 16, col = "blue")

Goodness of fit
It’s natural to ask how well a model fits the data. As with logistic
regression models based upon a binomial distribution, we can check the
deviance \(D\) against a \(\chi^2\) distribution. Recall that the
deviance for any model is
\[
D_i = \text{-}2 \left[ \log \mathcal{L}(M_i) - \log \mathcal{L}(M_0)
\right]
\]
where \(M_i\) is the model of
interest and \(M_0\) is an
intercept-only model. The log-likelihood for a Poisson is given by
\[
\log \mathcal{L}(y; \lambda) = \sum_{i=1}^{n} \left[ y_{i} \log
(\lambda)- \lambda - \log \left( y_{i}! \right) \right]
\]
and hence the deviance for a Poisson is
\[
\log \mathcal{L}(y; \lambda) = \sum_{i=1}^{n} \left[ y_{i} \log (y_i /
\hat{\lambda}) - (y_i - \hat{\lambda}) \right]
\]
The null hypothesis for our \(chi^2\) test is that our model is correctly
specified and it adequately fits the data. Here is the code for our
test.
## deviance of prawn model
D_full <- summary(cmod)$deviance
## LRT with df = n - k
(p_value <- pchisq(D_full, nn - length(coef(cmod)),
lower.tail = FALSE))
## [1] 0.004338247
This \(p\)-value is rather small so
we reject the \(H_0\), and conclude
that the model does not provide an adequate fit to the data. But wait–we
simulated the data according to a Poisson distribution, so why did this
test conclude a lack of fit? In this case the reason is because the use
of a \(\chi^2\) distribution for the
likelihood ratio test relies on asymptotic properties of the
distribution, in that a Poisson distribution approximates a normal
distribution as the mean gets larger. Therefore, there are no
guarantees, even when the sample size is large, that the test will be
valid.
Recall from lecture that the assumption of \(D \sim \chi^2_{n - k}\) can be violated
with Poisson models unless \(\lambda\)
is large. Another option is to use the same Pearson’s \(X^2\) statistic we saw for binomial models,
where
\[
X^2 = \sum_{i = 1}^n \frac{(O_i - E_i)^2}{E_i} \sim \chi^2_{(n - k)} \\
\]
So for our Poisson model
\[
X^2 = \sum_{i=1}^{n} \frac{(y_i - \hat{\lambda}_i)^2}{\hat{\lambda}_i}
\sim \chi^2_{n - k}
\]
Again our null hypothesis is that our model is correctly specified.
Here is the code to conduct the test.
## numerator
nm <- (prawns$catch - fitted(cmod))^2
## denominator
dm <- fitted(cmod)
## Pearson's
X2 <- sum(nm / dm)
## test
(p_value <- pchisq(X2, nn - length(coef(cmod)), lower.tail = FALSE))
## [1] 0.002860662
We again the \(p\)-value is rather
small so we reject the \(H_0\), and
conclude that the model does not provide an adequate fit to the data
(with the same caveat as above).
Fitted values & CI’s
We can obtain the fitted values and confidence intervals around the
fits in a manner analogous to that for logistic regression models. The
important thing here is to remember that we want to estimate the
uncertainty in log-space and then back-transform the intervals into
count space. For ease in interpretation, we also want to calculate the
CI’s for the fits with both bait types as a function of temperature.
## sorted temp
tmp <- prawns[order(prawns[,3]),]
## split data into bait types
fdat <- tmp[tmp$fish == 1,]
cdat <- tmp[tmp$fish == 0,]
## fitted values
fish <- predict(cmod, fdat, se.fit = TRUE, type = "link")
chkn <- predict(cmod, cdat, se.fit = TRUE, type = "link")
## t value
t_crit <- qt(0.975, nn - length(coef(cmod)))
## CI's for fish
fish_fit <- exp(fish$fit)
fish_lo <- exp(fish$fit - t_crit * fish$se.fit)
fish_hi <- exp(fish$fit + t_crit * fish$se.fit)
## CI's for chicken
chkn_fit <- exp(chkn$fit)
chkn_lo <- exp(chkn$fit - t_crit * chkn$se.fit)
chkn_hi <- exp(chkn$fit + t_crit * chkn$se.fit)
Here is a plot of the catches versus temperature with overlays of the
model fits for both bait types.
## set plot area
par(mai = c(0.9, 0.9, 0.6, 0.1),
omi = c(0, 0, 0, 0),
cex.lab = 1.5)
## temp vs catch
plot(temp, catch, pch = 16, las = 1,
ylab = "Catch", xlab ="Temperature (C)")
## with fish bait
lines(fdat$temp, fish_fit, lwd = 2, col = "blue")
lines(fdat$temp, fish_lo, lwd = 1, col = "blue")
lines(fdat$temp, fish_hi, lwd = 1, col = "blue")
text(7, 52, "Fish", pos = 4, col = "blue")
## with chicken bait
lines(cdat$temp, chkn_fit, lwd = 2, col = "darkred")
lines(cdat$temp, chkn_lo, lwd = 1, col = "darkred")
lines(cdat$temp, chkn_hi, lwd = 1, col = "darkred")
text(7, 34, "Chicken", pos = 4, col = "darkred")

Model diagnostics
As with other models, it’s important to examine diagnostic checks for
our fitted models. The first thing we can do is examine a plot of the
model residuals.
Residuals
## set plot area
par(mai = c(0.9, 0.9, 0.6, 0.1),
omi = c(0, 0, 0, 0),
cex.lab = 1.5)
## resids vs fitted
ee <- prawns$catch - fitted(cmod)
plot(fitted(cmod), ee, pch = 16, las = 1,
ylab = "Residuals", xlab ="Fitted values")

These residuals look good in that there is no obvious pattern
(linear, nonlinear), nor is there any evidence of
heteroscedasticity.
Leverage
We can calculate the leverages \(h\)
to look for unusual observation in predictor space. Recall that
we are potentially concerned about \(h > 2
\frac{k}{n}\). We can use hatvalues() to compute the
leverages.
## leverages
hat_values <- hatvalues(cmod)
## threshold value
h_crit <- 2 * length(coef(cmod)) / nn
## check if any h_i > b_crit
any(hat_values > h_crit)
## [1] FALSE
None of these points has a leverage greater than our threshold value.
We can also use faraway::halfnorm() to plot them.
## set plot area
par(mai = c(0.9, 0.9, 0.6, 0.1),
omi = c(0, 0, 0, 0),
cex.lab = 1.5)
## halfnormal plot
faraway::halfnorm(hat_values, nlab = 0, labs = "", las = 1)
text(0, 0.92*par("usr")[4],
substitute(italic(h[crit]) == h_crit, list(h_crit = round(h_crit, 3))),
pos = 4)

Cook’s Distance
Recall that we can use Cook’s \(D\)
to identify potentially influential points, where
\[
D_{i}=e_{i}^{2} \frac{1}{k}\left(\frac{h_{i}}{1-h_{i}}\right)
\]
In general we should be potentially concerned about \(D_i > F^{(0.5)}_{n, n - k} \approx
1\).
## Cook's D
CD <- cooks.distance(cmod)
## Threshold value
CD_crit <- qf(0.5, nn, nn - length(coef(cmod)))
## check if any CD_i > CD_crit
any(CD > CD_crit)
## [1] FALSE
It looks like none of the Cook’s \(D\) values exceed our threshold value.
Let’s plot them with faraway::halfnorm().
## set plot area
par(mai = c(0.9, 0.9, 0.1, 0.1),
omi = c(0, 0, 0, 0),
cex.lab = 1.5)
## halfnormal plot
faraway::halfnorm(CD, nlab = 0, labs = "", las = 1)

Model selection
We can use a likelihood ratio test to compare our model to an
intercept-only model
## deviance of full model
D_full <- summary(cmod)$deviance
## deviance of null model
D_null <- summary(cmod)$null.deviance
## test statistic
lambda <- D_null - D_full
## LRT with df = 2
(p_value <- pchisq(lambda, 2, lower.tail = FALSE))
## [1] 0.0001131307
This \(p\)-value is very small so we
reject \(H_0\) (that the data come from
the null model).
Overdispersed counts
We saw that logistic regression models based upon the binomial
distribution can exhibit overdispersion if the deviance is larger than
expected. Poisson regression models are also prone to overdispersion
because there is only one parameter specifying both the mean and the
variance.
\[
y_i \sim \text{Poisson}(\lambda)
\]
Bycatch of green sea turtles
In lecture we used some example data indicative of bycatch of sea
turtles in trawl fisheries. Here are the simulated data wherein ~50% of
the fleet was outfitted with turtle excluder devices (TEDS) and the
number of turtles caught per 1000 trawl hours was recorded along with
water temperature.
## number of obs
nn <- 197
## presence/absence of TED
TED <- sample(c(0,1), nn, replace = TRUE)
## temperature
temp <- runif(nn, 15, 25)
## mean bycatch
beta_0 <- -1.5
## effect of TED
beta_1 <- -1.1
## effect of temp
beta_2 <- 0.085
## variance inflation
mu <- 1
vif <- 3
## expectation
mean <- exp(beta_0 + beta_1 * TED + beta_2 * temp)
## bycatch
bycatch <- rnbinom(nn, mu = mean, size = mu^2 / (vif - mu))
## data frame
turtles <- data.frame(bycatch, TED, temp)
## set plot area
par(mai = c(0.9, 0.9, 0.6, 0.1),
omi = c(0, 0, 0, 0),
cex.lab = 1.5)
## histogram of catches
hist(turtles$bycatch, las = 1, breaks = seq(0, max(bycatch)),
col = "seagreen", border = "gray",
xlab = "Bycatch", main = "")

Poisson model for bycatch
Let’s begin by fitting a Poisson regression model to bycatch of
turtles \(y_i\) as a function of TED
presence/absence \(T_i\) and water
temperature \(W_i\). Here is the
specification of our GLM:
\[
\begin{aligned}
\text{data distribution:} & ~~ y_i \sim \text{Poisson}(\lambda_i) \\
\\
\text{link function:} & ~~ \text{log}(\lambda_i) = \eta_i \\ \\
\text{linear predictor:} & ~~ \eta_i = \alpha + \beta_1 T_i +
\beta_2 W_i
\end{aligned}
\]
Here is our model fit to the data.
## Poisson regression
ted_mod <- glm(bycatch ~ TED + temp, data = turtles,
family = poisson(link = "log"))
## model summary
faraway::sumary(ted_mod)
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.449170 0.630344 -2.2990 0.02150
## TED -0.960144 0.189518 -5.0662 4.057e-07
## temp 0.072820 0.030293 2.4039 0.01622
##
## n = 197 p = 3
## Deviance = 352.47008 Null Deviance = 386.40774 (Difference = 33.93766)
Two of these parameters appear to be non-significant at \(\alpha\) = 0.05. That said, the estimated
values are reasonably close the true values above.
Goodness of fit
As we did above for the prawn model, we can use Pearson’s \(\chi^2\) statistic as a goodness-of-fit
measure for our turtle model. Here again the null hypothesis is that our
model is correctly specified.
## Pearson's X^2 statistic
X2 <- sum((bycatch - fitted(ted_mod))^2 / fitted(ted_mod))
## likelihood ratio test
pchisq(X2, df = nn - length(coef(ted_mod)),
lower.tail = FALSE)
## [1] 5.972817e-28
The \(p\)-value is quite small so we
reject \(H_0\) and conclude that the
Poisson model is not a good fit to the data.
Overdispersion
We can consider the possibility that the variance scales linearly
with the mean, such that
\[
\text{Var}(y) = c \lambda
\]
If \(c\) = 1 then \(y \sim \text{Poisson}(\lambda)\), and if
\(c\) > 1 the data are
overdispersed. We can estimate the overdispersion \(\hat{c}\) as
\[
\hat{c} = \frac{X^2}{n - k}
\]
and
## function to calculate dispersion parameter
c_hat <- function(obs, model) {
X2 <- sum((obs - fitted(model))^2 / fitted(model))
return(X2 / (length(obs) - length(coef(model))))
}
## dispersion parameter
(c_hat_ted <- c_hat(bycatch, ted_mod))
## [1] 2.541267
This estimate of dispersion is well above 1 so we should be concerned
about its effect on the estimated uncertainty of our model parameters.
Therefore, we can tell R that we want to account for
the overdispersion when estimating the SE for the model parameters by
including the dispersion argument in
summary(). Let’s compare the SE’s for both cases.
## regular Poisson
signif(summary(ted_mod)$coefficients, 3)
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.4500 0.6300 -2.30 2.15e-02
## TED -0.9600 0.1900 -5.07 4.06e-07
## temp 0.0728 0.0303 2.40 1.62e-02
## overdispersed Poisson
signif(summary(ted_mod, dispersion = c_hat_ted)$coefficients, 3)
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.4500 1.0000 -1.44 0.14900
## TED -0.9600 0.3020 -3.18 0.00148
## temp 0.0728 0.0483 1.51 0.13200
The SE’s for the overdispersed model are clearly larger. We can see
the effect this has on the estimated confidence intervals by overlaying
them on plots of the data and zooming in on the lower range of the
data.
Effect of overdispersion
## fitted values
tmp <- turtles[order(turtles[,3]),]
fdat <- tmp[tmp$TED == 1,]
cdat <- tmp[tmp$TED == 0,]
TED <- predict(ted_mod, fdat, se.fit = TRUE, type = "link")
no_TED <- predict(ted_mod, cdat, se.fit = TRUE, type = "link")
## VIF fitted values
tmp2 <- turtles[order(turtles[,3]),]
fdat2 <- tmp2[tmp2$TED == 1,]
cdat2 <- tmp2[tmp2$TED == 0,]
TED2 <- predict(ted_mod, fdat2, se.fit = TRUE, type = "link", dispersion = c_hat_ted)
no_TED2 <- predict(ted_mod, cdat2, se.fit = TRUE, type = "link", dispersion = c_hat_ted)
## t value
t_crit <- qt(0.975, nn - length(coef(ted_mod)))
## set plot area
par(mfrow = c(1,2),
mai = c(0.9, 0.9, 0.6, 0.1),
omi = c(0, 0, 0, 0),
cex.lab = 1.4)
## temp vs bycatch
plot(temp, bycatch, pch = 16, las = 1, ylim = c(0, 3.5),
ylab = "Bycatch", xlab ="Temperature (C)", main = "Without VIF")
## with TED
lines(fdat$temp, exp(TED$fit), lwd = 2, col = "blue")
lines(fdat$temp, exp(TED$fit + t_crit * TED$se.fit), lwd = 1, col = "blue")
lines(fdat$temp, exp(TED$fit - t_crit * TED$se.fit), lwd = 1, col = "blue")
text(7, 65, "with TED", pos = 4, col = "blue")
## without TED
lines(cdat$temp, exp(no_TED$fit), lwd = 2, col = "darkred")
lines(cdat$temp, exp(no_TED$fit + t_crit * no_TED$se.fit), lwd = 1, col = "darkred")
lines(cdat$temp, exp(no_TED$fit - t_crit * no_TED$se.fit), lwd = 1, col = "darkred")
text(7, 30, "w/o TED", pos = 4, col = "darkred")
## temp vs bycatch
plot(temp, bycatch, pch = 16, las = 1, ylim = c(0, 3.5),
ylab = "", xlab ="Temperature (C)", main = "With VIF")
## with TED
lines(fdat2$temp, exp(TED2$fit), lwd = 2, col = "blue")
lines(fdat2$temp, exp(TED2$fit + t_crit * TED2$se.fit), lwd = 1, col = "blue")
lines(fdat2$temp, exp(TED2$fit - t_crit * TED2$se.fit), lwd = 1, col = "blue")
text(7, 65, "with TED", pos = 4, col = "blue")
## without TED
lines(cdat$temp, exp(no_TED2$fit), lwd = 2, col = "darkred")
lines(cdat$temp, exp(no_TED2$fit + t_crit * no_TED2$se.fit), lwd = 1, col = "darkred")
lines(cdat$temp, exp(no_TED2$fit - t_crit * no_TED2$se.fit), lwd = 1, col = "darkred")
text(7, 30, "w/o TED", pos = 4, col = "darkred")

Quasi-Poisson models
We saw with the case of overdispersed binomial models that we could
use a quasi-likelihood to estimate the parameters. To fit these
models, we use family = quasipoisson(link = "log") in our
call to glm(). Here are the quasi-likelihood fits compared
to the overdispersed Poisson.
## Poisson regression
ted_mod_q <- glm(bycatch ~ TED + temp, data = turtles,
family = quasipoisson(link = "log"))
## quasi-Poisson
signif(summary(ted_mod_q)$coefficients, 3)
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -1.4500 1.0000 -1.44 0.15100
## TED -0.9600 0.3020 -3.18 0.00173
## temp 0.0728 0.0483 1.51 0.13300
## overdispersed Poisson
signif(summary(ted_mod, dispersion = c_hat_ted)$coefficients, 3)
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.4500 1.0000 -1.44 0.14900
## TED -0.9600 0.3020 -3.18 0.00148
## temp 0.0728 0.0483 1.51 0.13200
These estimates indeed very close to one another.
Quasi-AIC
Just as we did for binomial models, we can use a quasi-AIC
to compare models, where
\[
QAIC = 2 k - 2 \frac{\log \mathcal{L}}{\hat{c}}
\]
Here’s a comparison of several possible models for turtle
bycatch.
## fit reduced models
ted_ted <- glm(bycatch ~ TED, data = turtles,
family = poisson(link = "log"))
ted_temp <- glm(bycatch ~ temp, data = turtles,
family = poisson(link = "log"))
## fit null model
ted_null <- glm(bycatch ~ 1, data = turtles,
family = poisson(link = "log"))
## get c_hat's
c_hats <- c(c_hat(bycatch, ted_mod),
c_hat(bycatch, ted_ted),
c_hat(bycatch, ted_temp),
c_hat(bycatch, ted_null))
## model selection results
## neg log-likelihoods
tbl_mods <- -c(logLik(ted_mod), logLik(ted_ted),
logLik(ted_temp), logLik(ted_null))
## k & AIC
tbl_mods <- cbind(tbl_mods, AIC(ted_mod, ted_ted, ted_temp, ted_null))
## delta-AIC
tbl_mods <- cbind(tbl_mods, tbl_mods[,3] - min(tbl_mods[,3]))
## QAIC
tbl_mods <- cbind(tbl_mods, 2 * tbl_mods[,1] + 2 * tbl_mods[,2] / c_hats)
## delta-QAIC
tbl_mods <- cbind(tbl_mods, tbl_mods[,5] - min(tbl_mods[,5]))
## label table
rownames(tbl_mods) <- c("B0 + TED + temp ", "B0 + TED ",
"B0 + temp ", "B0 only ")
colnames(tbl_mods) <- c("neg-LL", "k", "AIC", "deltaAIC", "QAIC", "deltaQAIC")
round(tbl_mods, 1)
## neg-LL k AIC deltaAIC QAIC deltaQAIC
## B0 + TED + temp 257.9 3 521.8 0.0 518.2 0.0
## B0 + TED 260.8 2 525.7 3.9 523.3 5.1
## B0 + temp 272.4 2 548.8 26.9 546.2 28.0
## B0 only 274.9 1 551.8 29.9 550.5 32.3
Negative binomial distribution
We have seen several examples in lecture where we can use the
negative binomial distribution to model overdispersed data because it
has an additional parameter for the spread. Here is the description of a
GLM for bycatch of turtles \(y_i\) as a
function of TED presence/absence \(T_i\) and water temperature \(W_i\)
\[
\begin{aligned}
\text{data distribution:} & ~~ y_i \sim \text{negBin}(r, \mu_i) \\
\\
\text{link function:} & ~~ \text{log}(\mu_i) = \eta_i \\ \\
\text{linear predictor:} & ~~ \eta_i = \alpha + \beta_1 T_i +
\beta_2 W_i
\end{aligned}
\]
We can model our bycatch data with a negative binomial using
glm.nb() from the MASS package.
## load MASS
library(MASS)
## negative binomial regression
ted_mod_nb <- glm.nb(bycatch ~ TED + temp, data = turtles,
link = "log")
Let’s compare these estimates to those for the overdispersed and
quasi-likelihood models.
## overdispersed Poisson
signif(summary(ted_mod, dispersion = c_hat_ted)$coefficients, 3)
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.4500 1.0000 -1.44 0.14900
## TED -0.9600 0.3020 -3.18 0.00148
## temp 0.0728 0.0483 1.51 0.13200
## quasi-Poisson
signif(summary(ted_mod_q)$coefficients, 3)
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -1.4500 1.0000 -1.44 0.15100
## TED -0.9600 0.3020 -3.18 0.00173
## temp 0.0728 0.0483 1.51 0.13300
## negative binomial
signif(summary(ted_mod_nb)$coefficients, 3)
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.2900 0.9970 -1.29 0.19600
## TED -0.9330 0.2840 -3.28 0.00103
## temp 0.0645 0.0486 1.33 0.18400
The model estimates from the negative binomial model are rather
similar to those from the other methods.
Zero-truncated counts
Although somewhat rare in ecological studies, we saw some examples in
lecture of so-called “zero-truncated data” (e.g., the time a whale is at
the surface before diving, herd size in elk, number of fin rays on a
fish). We also saw that the data themselves are not a problem, but
rather an underlying assumption of a Poisson or negative binomial
distribution may be the problem.
Poisson for zero-truncated data
The probability that \(y_i = 0\)
is
\[
f(y_i; \lambda_i) = \frac{\exp (\text{-} \lambda_i)
\lambda_{i}^{y_i}}{y_i!} \\
\Downarrow \\
\begin{align}
f(y_i = 0; \lambda_i) &= \frac{\exp (\text{-} \lambda_i)
\lambda_{i}^0}{0!} \\
&= \exp (\text{-} \lambda_i)
\end{align}
\]
and therefore the probability that \(y_i
\neq 0\) is
\[
f(y_i \neq 0; \lambda_i) = 1 - \exp (\text{-} \lambda_i)
\]
We can now exclude the probability that \(y_i = 0\) by dividing the pmf by the
probability that \(y_i \neq 0\)
\[
f(y_i; \lambda_i) = \frac{\exp (\text{-} \lambda_i)
\lambda_{i}^{y_i}}{y_i!} \\
\Downarrow \\
f^+(y_i; \lambda_i | y_i > 0) = \frac{\exp (\text{-} \lambda_i)
\lambda_{i}^{y_i}}{y_i!} \cdot \frac{1}{1 - \exp (\text{-} \lambda_i)}
\\
\Downarrow \\
\log \mathcal{L} = \left( y_i \log \lambda_i - \lambda_i \right) -
\left( 1 - \exp (\text{-} \lambda_i) \right)
\]
Road-killed snakes
Let’s revisit the data presented in Zuur et al. (2009) on the number
of days that carcasses from road-killed snakes stay on roads. The
predictors are the total rainfall (mm) and an indicator of whether the
snake was killed in the driving lane or the shoulder (or “verve” as it
is sometimes called). Let’s begin by loading and plotting the data.
## read data
snakes <- read.csv("snakes.csv", stringsAsFactors = FALSE)
## set plot area
par(mai = c(0.9, 0.9, 0.6, 0.1),
omi = c(0, 0, 0, 0), bg = NA,
cex.lab = 1.3)
## histogram
hh <- hist(snakes$n_days, breaks = seq(0, max(snakes$n_days)), plot = FALSE)
barplot(hh$counts, names.arg = seq(max(snakes$n_days)), las = 1,
ylab = "Count", xlab = "Number of days",
col = "dodgerblue", border = "gray")

Poisson model
Let’s first consider a regular Poisson regression model, which has a
non-zero likelihood of producing zeros.
## Poisson regression
smod_pois <- glm(n_days ~ location + rain, data = snakes,
family = poisson(link = "log"))
## model summary
summary(smod_pois)
##
## Call:
## glm(formula = n_days ~ location + rain, family = poisson(link = "log"),
## data = snakes)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 0.439195 0.088539 4.960 7.03e-07 ***
## locationV 0.462663 0.119060 3.886 0.000102 ***
## rain 0.021707 0.003092 7.021 2.21e-12 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for poisson family taken to be 1)
##
## Null deviance: 226.38 on 129 degrees of freedom
## Residual deviance: 175.80 on 127 degrees of freedom
## AIC: 497.63
##
## Number of Fisher Scoring iterations: 5
Zero-truncated Poisson
Now let’s fit a zero-truncated Poisson regression model with
vglm() from VGAM and compare the results
to our regular Poisson model above. To do so, we need to specify
family = pospoisson to indicate we want a zero-truncated
Poisson distribution.
library(VGAM)
## zero-truncated Poisson regression
smod_ztpois <- vglm(n_days ~ location + rain, data = snakes,
family = pospoisson)
## parameter MLEs and SEs for Poisson
beta_hat_p <- cbind(coef(smod_pois), sqrt(diag(vcov(smod_pois))))
## parameter MLEs and SEs for Poisson+
beta_hat_ztp <- cbind(coef(smod_ztpois), sqrt(diag(vcov(smod_ztpois))))
## table of results
tbl_pois <- round(cbind(beta_hat_p, beta_hat_ztp), 3)
colnames(tbl_pois) <- c(" Poisson", " Poisson SE", " +Poisson", " +Poisson SE")
tbl_pois
## Poisson Poisson SE +Poisson +Poisson SE
## (Intercept) 0.439 0.089 0.041 0.125
## locationV 0.463 0.119 0.711 0.149
## rain 0.022 0.003 0.027 0.003
Here we can see that MLE’s from the regular Poisson model are biased
high and low for the intercept and location effect, respectively. The
SE’s for the Poisson model are also biased low.
Zero-truncated negative binomial
Looking back at the results from the regular Poisson model, we can
also see that the model deviance seems rather high given the degrees of
freedom (\(D\) = 226.4 with \(df\) = 129). This suggests that we should
consider a model that allows for additional variance beyond that for a
Poisson. The negative binomial is an obvious choice.
Recall that for \(y_i \sim
\text{negBinom}(r, \mu)\), its probability mass function is
\[
f(y; \mu, r) = \frac{(y+r-1) !}{(r-1) ! y !} \left( \frac{r}{\mu + r}
\right)^{r}\left( \frac{\mu}{\mu + r} \right)^{y}
\]
The probability that \(y_i = 0\)
is
\[
f(y; r, \mu) = \frac{(y+r-1) !}{(r-1) ! y !} \left( \frac{r}{\mu + r}
\right)^{r}\left( \frac{\mu}{\mu + r} \right)^{y} \\
\Downarrow \\
\begin{align}
f(y_i = 0; r, \mu) &= \frac{(0+r-1) !}{(r-1) ! 0 !} \left(
\frac{r}{\mu + r} \right)^{r} \left( \frac{\mu}{\mu + r} \right)^{0} \\
&= \left( \frac{r}{\mu + r} \right)^{r}
\end{align}
\]
and the probability that \(y_i \neq
0\) is therefore
\[
f(y_i \neq 0; r, \mu_i) = 1 - \left( \frac{r}{\mu + r} \right)^{r}
\]
Just as we did for the Poisson distribution, we can now exclude the
probability that \(y_i = 0\) by
dividing the pmf by the probability that \(y_i
\neq 0\)
\[
f(y; r, \mu) = \frac{(y+r-1) !}{(r-1) ! y !} \left( \frac{r}{\mu + r}
\right)^{r} \left( \frac{\mu}{\mu + r} \right)^{y} \\
\Downarrow \\
f^+(y_i; \lambda_i | y_i > 0) = \frac{ \frac{(y+r-1) !}{(r-1) ! y !}
\left( \frac{r}{\mu + r} \right)^{r} \left( \frac{\mu}{\mu + r}
\right)^{y} }{ 1 - \left( \frac{r}{\mu + r} \right)^{r} } \\
\Downarrow \\
\log \mathcal{L} = \log \mathcal{L}(\text{NB}) - \log \left( 1 - \left(
\frac{r}{\mu + r} \right)^{r} \right)
\]
Road-killed snakes
Let’s first consider a regular negative binomial regression model to
which we can compare a zero-truncated version.
## load MASS pkg
library(MASS)
## negative binomial regression
smod_nb <- glm.nb(n_days ~ location + rain, data = snakes,
link = "log")
## model summary
summary(smod_nb)
##
## Call:
## glm.nb(formula = n_days ~ location + rain, data = snakes, link = "log",
## init.theta = 4.153875871)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 0.418101 0.106859 3.913 9.13e-05 ***
## locationV 0.453524 0.151708 2.989 0.00279 **
## rain 0.025127 0.004529 5.548 2.88e-08 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for Negative Binomial(4.1539) family taken to be 1)
##
## Null deviance: 128.298 on 129 degrees of freedom
## Residual deviance: 94.918 on 127 degrees of freedom
## AIC: 469.28
##
## Number of Fisher Scoring iterations: 1
##
##
## Theta: 4.15
## Std. Err.: 1.17
##
## 2 x log-likelihood: -461.279
Right away we can see that the deviance for this model is much more
in line with our expectation. Now let’s fit a zero-truncated negative
binomial regression model with vglm() from
VGAM and compare it to the regular negative binomial
model. Here we need to specify family = posnegbinomial to
specify a zero-truncated negative binomial.
library(VGAM)
## zero-truncated negative binomial regression
smod_ztnb <- vglm(n_days ~ location + rain, data = snakes,
family = posnegbinomial)
## MLEs and SEs for regular NB
beta_hat_nb <- cbind(coef(smod_nb), sqrt(diag(vcov(smod_nb))))
## MLEs and SEs for regular NB+
beta_hat_ztnb <- cbind(coef(smod_ztnb)[-2], sqrt(diag(vcov(smod_ztnb))[-2]))
## table of results
tbl_nb <- round(cbind(beta_hat_nb, beta_hat_ztnb), 3)
colnames(tbl_nb) <- c(" NB", " NB SE", " +NB", " +NB SE")
tbl_nb
## NB NB SE +NB +NB SE
## (Intercept) 0.418 0.107 -17.972 1.948
## locationV 0.454 0.152 0.965 2.933
## rain 0.025 0.005 0.065 0.103
This is a particularly impressive example of the biases in MLE’s and
the associated SE’s that one would get by fitting the wrong model.
Zero-inflated counts
Count data that have an excess of zeros tend to be more common in
ecological studies. These zero-inflated data contain more zeros
than would be expected under a Poisson or negative binomial
distribution. In general, there are 4 different types of errors that
cause zeros
Structural (an animal is absent because the habitat is
unsuitable)
Design (sampling is limited temporally or spatially)
Observer error (inexperience or difficult circumstances)
Process error (habitat is suitable but unused)
Approaches to zero-inflated data
There are 2 general approaches for dealing with zero-inflated data,
which differ in their assumption about the underlying sources of the
excess zeros:
Zero-altered (“hurdle”) models
Zero-inflated (“mixture”) models
Zero-altered (ZA) models do not discriminate among the 4 types of
zeros and treat all of the count data as belonging to one of two
distinct groups: zeros and non-zeros. Zero-inflated (ZI) models also
treat the zeros as coming from two sources, but they arise either via
observation errors (missed detections) or ecological reasons (the plant
or animal was absent because of the environment). The primary difference
is that ZA models treat the non-zeros as zero-truncated data whereas ZI
models treat the non-zeros and some of the zeros as coming from
a regular Poisson or negative binomial distribution. Here is a graphical
depiction of the two cases.
## extra zeros + Poisson(3)
set.seed(514)
all <- c(rep(0, 50), rpois(300, 3))
## ZAP
idx_zap <- ifelse(all > 0, 0, 1)
all_zap <- table(all, idx_zap)
## ZIP
idx_zip <- c(rep(1, 50), rep(0, 300))
all_zip <- table(all, idx_zip)
## set plot area
par(mfrow = c(1, 2),
mai = c(0.9, 0.9, 0.6, 0.1),
omi = c(0, 0, 0, 0), bg = NA,
cex.main = 1.2, cex.lab = 1.2)
## bar charts of the data
barplot(t(all_zap), las = 1, col=c("dodgerblue","indianred"), border ="gray",
xlab = "Count", main = "Zero altered (hurdle)")
barplot(t(all_zip), las = 1, col=c("dodgerblue","indianred"), border ="gray",
xlab = "Count", main = "Zero inflated (mixture)")

Zero-altered Poisson
Zero-altered models consist of 2 parts:
a binomial model to determine the probability of a zero
a truncated Poisson or negative binomial to model the positive
counts
Here we’ll consider a zero-altered Poisson (ZAP) model, which is
given by
\[
f_{\text{ZAP}}(y; \pi, \lambda) =
\left\{
\begin{array}{lc}
f_{\text{binomial}}(y = 0; \pi) \\
\left[1 - f_{\text{binomial}}(y = 0; \pi) \right] \times \left(
\frac{f_{\text{Poisson}}(y = 0; \lambda)}{1 - f_{\text{Poisson}}(y = 0;
\lambda)} \right)
\end{array}
\right.
\]
where \(\pi\) is the probability of
finding any individuals, and \(\lambda\) is the mean (and variance) of the
positive counts.
We can model both parameters as functions of covariates, such that
the logit-transformed probability of detection is given by
\[
\text{logit}(\pi) = \mathbf{X}_d \boldsymbol{\beta}_d
\]
and the log-transformed mean and variance of the positive counts is
given by
\[
\log(\lambda) = \mathbf{X}_c \boldsymbol{\beta}_c
\]
Counts of hippos
Let’s apply a ZAP model to our fictitious survey data for hippos,
where we assume the following the probability of finding hippos
increases with water availability and the number of hippos increases
with tree density. We’ll model detection as a function of water
availability \(W\), such that
\[
z_i \sim \text{Bernoulli}(\pi_i) \\
\text{logit}(\pi) = \gamma_0 + \gamma_1 W_i
\]
and the positive counts as a function of tree density \(T\), such that
\[
c_i \sim \text{Poisson}^+(\lambda_i) \\
\log(\lambda) = \beta_0 + \beta_1 T_i
\]
Total counts are then a function of the non-zero detections and the
positive counts
\[
y_i = z_i c_i
\]
Here’s how we simulate the zero-inflated data.
## function to generate positive Poisson values
rtpois <- function(n, l) {
qpois(runif(n, dpois(0, l), 1), l)
}
set.seed(514)
## sample size
nn <- 200
## parameters for detection model
gamma_0 <- -2
gamma_tree <- 3
## parameters for count model
beta_0 <- 2
beta_tree <- 0.8
## covariates
water <- runif(nn, 0, 1)
trees <- runif(nn, 0, 1)
## expectation for Pr(detect)
mu <- 1/(1+exp(-(gamma_0 + gamma_tree * water)))
## detections (0/1)
z <- rbinom(nn, 1, mu)
## expectation for pos counts
lambda <- exp(beta_0 + beta_tree * trees)
## pos counts
pos_count <- rtpois(nn, lambda)
## observations
y <- z * pos_count
Here is a plot of the simulated hippo counts.
## set plot area
par(mai = c(0.9, 0.9, 0.1, 0.1),
omi = c(0, 0, 0, 0), bg = NA,
cex.main = 1.2, cex.lab = 1.2)
## histogram of counts
hist(y, breaks = seq(0, max(y)), las = 1, col = "dodgerblue", border = "gray",
main = "", xlab = "Number of hippos", ylab = "Frequency", )

ZAP model for hippos
We can fit ZAP models in R with hurdle() from the
pscl package. Note that the formula for ZAP models is
specified as
y ~ predictors_of_counts | predictors_for_detection.
## load pscl
library(pscl)
## fit hurdle model
hippo_zap <- hurdle(y ~ trees | water)
## model summary
summary(hippo_zap)
##
## Call:
## hurdle(formula = y ~ trees | water)
##
## Pearson residuals:
## Min 1Q Median 3Q Max
## -1.2165 -0.7104 -0.4803 0.9193 2.6988
##
## Count model coefficients (truncated poisson with log link):
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 2.05104 0.06955 29.492 < 2e-16 ***
## trees 0.74967 0.10843 6.914 4.71e-12 ***
## Zero hurdle model coefficients (binomial with logit link):
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.7326 0.3519 -4.924 8.48e-07 ***
## water 2.3422 0.5676 4.126 3.69e-05 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Number of iterations in BFGS optimization: 11
## Log-likelihood: -326.1 on 4 Df
The model summary gives us the parameter estimates for both the
detection model and the count model. The parameter estimates are pretty
close to the true values above, but the slope for the effect of water
availability is a bit low.
We can plot the relationships between water availability and the
probability of detection, and the estimated count as a function of our
index of tree density.
## fitted for detection prob (pi)
water <- sort(water)
gamma_hat_0 <- coef(hippo_zap)[3]
gamma_hat_1 <- coef(hippo_zap)[4]
pi_hat <- 1/(1+exp(-(gamma_hat_0 + gamma_hat_1*water)))
## matrix of derivatives for SE's
derivs <- matrix(NA,nrow=nn,ncol=4)
derivs[,1] <- derivs[,2] <- 0
derivs[,3] <- (exp(gamma_hat_0 + gamma_hat_1*water)) / ((exp(gamma_hat_0 + gamma_hat_1*water)+1)^2)
derivs[,4] <- (water * exp(gamma_hat_0 + gamma_hat_1*water)) / ((exp(gamma_hat_0 + gamma_hat_1*water)+1)^2)
se <- sqrt( diag ( derivs %*% vcov(hippo_zap) %*% t(derivs) ))
lower <- pi_hat - se * qt(0.025, nn-2, lower.tail = FALSE)
upper <- pi_hat + se * qt(0.025, nn-2, lower.tail = FALSE)
## fitted for mean & var (lambda)
trees <- sort(trees)
beta_hat_0 <- coef(hippo_zap)[1]
beta_hat_1 <- coef(hippo_zap)[2]
lambda_hat <- exp(beta_hat_0 + beta_hat_1*trees)
## matrix of derivatives for SE's
derivs_2 <- matrix(NA,nrow=nn,ncol=4)
derivs_2[,1] <- exp(beta_hat_0+beta_hat_1*trees)
derivs_2[,2] <- trees*exp(beta_hat_0+beta_hat_1*trees)
derivs_2[,3] <- derivs_2[,4] <- 0
se_2 <- sqrt( diag ( derivs_2 %*% vcov(hippo_zap) %*% t(derivs_2) ))
lower_2 <- lambda_hat - se_2 * qt(0.025, nn-2, lower.tail = FALSE)
upper_2 <- lambda_hat + se_2 * qt(0.025, nn-2, lower.tail = FALSE)
## set plot area
par(mfrow = c(1, 2),
mai = c(0.9, 0.9, 0.6, 0.1),
omi = c(0, 0, 0, 0), bg = NA,
cex.main = 1.2, cex.lab = 1.2)
## detections
plot(water, pi_hat, type = "l", las = 1, ylim = c(0, 1), lwd = 2, col = "dodgerblue",
xlab = "Water availability", ylab = expression(pi), main = "Detection")
lines(water, lower, lty = 2, col = "dodgerblue", lwd = 2)
lines(water, upper, lty = 2, col = "dodgerblue", lwd = 2)
## counts
plot(trees, lambda_hat, type = "l", las = 1, ylim = c(0, 20), lwd = 2, col = "darkgreen",
xlab = "Tree density", ylab = expression(lambda), main = "Counts")
lines(trees, lower_2, lty = 2, col = "darkgreen", lwd = 2)
lines(trees, upper_2, lty = 2, col = "darkgreen", lwd = 2)

Zero-inflated Poisson
Zero-inflated Poisson (ZIP) models consist of 2 parts
a binomial model to determine the probability of a zero
a Poisson model for counts, which can include zeros
Recall that the probability of a zero count comes from 2 sources:
false zeros (missed detections)
true zeros (ecological reasons)
which means
Pr(zero) = Pr(false zero) + Pr(true zero) \(\times\) Pr(count = 0)
Thus, a zero-inflated Poisson (ZIP) model is given by
\[
\begin{align}
f_{\text{ZIP}}(y = 0) &= f_{\text{Binomial}}(\pi) + [1 -
f_{\text{Binomial}}(\pi)] f_{\text{Poisson}}(y = 0; \lambda) \\
~ \\
f_{\text{ZIP}}(y | y > 0) &= [1 - f_{\text{Binomial}}(\pi)]
f_{\text{Poisson}}(y; \lambda) \\
\end{align}
\]
where \(\pi\) is the probability of
false zeros (missed detections) and \(\lambda\) is the mean (and variance) of
all counts (including zeros)
Counts of deer
Let’s apply a ZIP model to a simulated survey for white tailed deer
where we’ll assume that the probability of not detecting deer
increases with tree density \(T\), such
that
\[
z_i \sim \text{Bernoulli}(\pi_i) \\
\text{logit}(\pi) = \gamma_0 + \gamma_1 T_i
\]
and the counts of deer also increase with tree density \(T\), such that
\[
c_i \sim \text{Poisson}(\lambda_i) \\
\log(\lambda) = \beta_0 + \beta_1 T_i
\]
Total counts as a function of non-detections and positive counts
\[
y_i = (1 - z_i) c_i
\]
Here are the simulated data.
set.seed(514)
## sample size
nn <- 200
## parameters for detection model
gamma_0 <- 0.01
gamma_tree <- 3
## parameters for count model
beta_0 <- 1.5
beta_tree <- 1.2
## covariate
trees <- runif(nn, 0, 1)
## expectation for Pr(detect)
mu <- 1 / (1 + exp(-(gamma_0 + gamma_tree * trees)))
## missed detections (0/1)
z <- rbinom(nn, 1, mu)
## expectation for pos counts
lambda <- exp(beta_0 + beta_tree * trees)
## pos counts
pos_count <- rpois(nn, lambda)
## observations
y <- (1 - z) * pos_count
Here is a histogram of the deer counts
## set plot area
par(mai = c(0.9, 0.9, 0.1, 0.1),
omi = c(0, 0, 0, 0), bg = NA,
cex.main = 1.2, cex.lab = 1.2)
## histogram of counts
hist(y, breaks = seq(0, max(y)), las = 1, col = "brown", border = "gray",
main = "", xlab = "Number of deer", ylab = "Frequency", )

ZIP model for deer
We can fit ZIP models in R with zeroinfl() from the
pscl package, where again we specify the formula as
y ~ predictors_of_counts | predictors_for_detection.
## fit hurdle model
deer_zip <- zeroinfl(y ~ trees | trees)
## model summary
summary(deer_zip)
##
## Call:
## zeroinfl(formula = y ~ trees | trees)
##
## Pearson residuals:
## Min 1Q Median 3Q Max
## -0.7312 -0.5103 -0.3674 -0.2611 4.1697
##
## Count model coefficients (poisson with log link):
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 1.5190 0.1183 12.841 < 2e-16 ***
## trees 1.0660 0.2272 4.693 2.69e-06 ***
##
## Zero-inflation model coefficients (binomial with logit link):
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 0.2625 0.3438 0.764 0.445104
## trees 2.4158 0.7048 3.428 0.000609 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Number of iterations in BFGS optimization: 12
## Log-likelihood: -185.8 on 4 Df
Here, too, the estimated parameters for both the detection and count
models generally agree with the true values, although the
estimated intercept appears to be non-significant.
As we did for the ZAP model for hippos, we can plot the estimated
probability of non-detection and expected count as a function of tree
density.
## fitted for detection prob (pi)
trees <- sort(trees)
gamma_hat_0 <- coef(deer_zip)[3]
gamma_hat_1 <- coef(deer_zip)[4]
pi_hat <- 1/(1+exp(-(gamma_hat_0 + gamma_hat_1 * trees)))
## matrix of derivatives
derivs <- matrix(NA, nrow = nn, ncol = 4)
derivs[,1] <- derivs[,2] <- 0
derivs[,3] <- (exp(gamma_hat_0 + gamma_hat_1*trees))/((exp(gamma_hat_0 + gamma_hat_1*trees)+1)^2)
derivs[,4] <- (trees*exp(gamma_hat_0 + gamma_hat_1*trees))/((exp(gamma_hat_0 + gamma_hat_1*trees)+1)^2)
se <- sqrt( diag ( derivs %*% vcov(deer_zip) %*% t(derivs) ))
lower <- pi_hat - se * qt(0.025, nn-2, lower.tail = FALSE)
upper <- pi_hat + se * qt(0.025, nn-2, lower.tail = FALSE)
## fitted for mean & var (lambda)
beta_hat_0 <- coef(deer_zip)[1]
beta_hat_1 <- coef(deer_zip)[2]
lambda_hat <- exp(beta_hat_0 + beta_hat_1*trees)
## matrix of derivatives
derivs_2 <- matrix(NA, nrow = nn, ncol = 4)
derivs_2[,1] <- exp(beta_hat_0+beta_hat_1*trees)
derivs_2[,2] <- trees*exp(beta_hat_0+beta_hat_1*trees)
derivs_2[,3] <- derivs_2[,4] <- 0
se_2 <- sqrt( diag ( derivs_2 %*% vcov(deer_zip) %*% t(derivs_2) ))
lower_2 <- lambda_hat - se_2 * qt(0.025, nn-2, lower.tail = FALSE)
upper_2 <- lambda_hat + se_2 * qt(0.025, nn-2, lower.tail = FALSE)
## set plot area
par(mfrow = c(1, 2),
mai = c(0.9, 0.9, 0.6, 0.1),
omi = c(0, 0, 0, 0), bg = NA,
cex.main = 1.2, cex.lab = 1.2)
## detections
plot(trees, pi_hat, type = "l", las = 1, ylim = c(0, 1), lwd = 2, col = "darkgreen",
xlab = "Tree density", ylab = expression(pi), main = "Missed detection")
lines(trees, lower, lty = 2, col = "darkgreen", lwd = 2)
lines(trees, upper, lty = 2, col = "darkgreen", lwd = 2)
## counts
plot(trees, lambda_hat, type = "l", las = 1, ylim = c(0, 20), lwd = 2, col = "darkgreen",
xlab = "Tree density", ylab = expression(lambda), main = "Counts")
lines(trees, lower_2, lty = 2, col = "darkgreen", lwd = 2)
lines(trees, upper_2, lty = 2, col = "darkgreen", lwd = 2)

LS0tCnRpdGxlOiAiRml0dGluZyBtb2RlbHMgdG8gY291bnQgZGF0YSIKYXV0aG9yOiAiTWFyayBTY2hldWVyZWxsIgpkYXRlOiAiMjIgTWF5IDIwMjYiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdGhlbWU6IAogICAgICBib290c3dhdGNoOiBqb3VybmFsCiAgICAgIHByaW1hcnk6ICIjMzIwMDZlIgogICAgaGlnaGxpZ2h0OiB0ZXh0bWF0ZQogICAgY3NzOiAuLi9sZWN0dXJlX2luc3QuY3NzCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfZGVwdGg6IDQKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSkKYGBgCgojIEJhY2tncm91bmQKClRoZXNlIGxhYiBleGVyY2lzZXMgZm9jdXMgb24gZml0dGluZyBhbmQgZXZhbHVhdGluZyBtb2RlbHMgZm9yIGNvdW50IGRhdGEuIFRoZXNlIGluY2x1ZGUgcmVndWxhciBQb2lzc29uIGFuZCBuZWdhdGl2ZSBiaW5vbWlhbCByZWdyZXNzaW9uIG1vZGVscywgYW5kIHplcm8tdHJ1bmNhdGVkLCB6ZXJvLWFsdGVyZWQsIGFuZCB6ZXJvLWluZmxhdGVkIG1vZGVscy4gV2UnbGwgdXNlIHRoZSBleGFtcGxlcyB3ZSBzYXcgaW4gbGVjdHVyZSB0byBkZW1vbnN0cmF0ZSB0aGUgdmFyaW91cyBvcHRpb25zIGluICoqUioqIGZvciBmaXR0aW5nIG1vZGVscywgZXZhbHVhdGluZyB0aGVpciBnb29kbmVzcy1vZi1maXQsIGFuZCBleGFtaW5pbmcgbW9kZWwgZGlhZ25vc3RpY3MuCgpFYXJsaWVyIGluIHRoZSBjb3Vyc2Ugd2UgbW9kZWxlZCBjb3VudHMgYXMgKHBvc3NpYmx5IGxvZyB0cmFuc2Zvcm1lZCkgZGVuc2l0eSwgd2hlcmUKCiQkClx0ZXh0e0RlbnNpdHl9X2kgPSBmIChcdGV4dHtDb3VudH1faSwgXHRleHR7QXJlYX1faSkgXFwKXERvd25hcnJvdyBcXApcdGV4dHtEZW5zaXR5fV9pID0gXGZyYWN7XHRleHR7Q291bnR9X2l9e1x0ZXh0e0FyZWF9X2l9IFxcCiQkCgpXaXRoIEdMTXMgZm9yIGNvdW50IGRhdGEsIHdlIGluc3RlYWQgc2hpZnQgb3VyIGZvY3VzIHRvCgokJApcdGV4dHtDb3VudH1faSA9IGYgKFx0ZXh0e0FyZWF9X2ksIFxkb3RzKQokJAoKIyMgQ29tcG9uZW50cyBvZiBhIEdMTQoKQXMgd2UndmUgc2VlbiBmb3Igb3RoZXIgR0xNcywgdGhlcmUgYXJlIDMgaW1wb3J0YW50IGNvbXBvbmVudHMgdG8gYSByZWdyZXNzaW9uIG1vZGVsIGZvciBjb3VudCBkYXRhOgoKMS4gRGlzdHJpYnV0aW9uIG9mIHRoZSBkYXRhOiAkeSBcc2ltIGZfe1x0aGV0YX0oeSkkCgoyLiBMaW5rIGZ1bmN0aW9uOiAkZyhcZXRhKSQKCjMuIExpbmVhciBwcmVkaWN0b3I6ICRcZXRhID0gXG1hdGhiZntYfSBcYm9sZHN5bWJvbHtcYmV0YX0kCgpXZSBhcmUgaW50ZXJlc3RlZCBpbiB0aGUgc28tY2FsbGVkICpjYW5vbmljYWwgbGlua3MqIGZvciBHTE1zLiBIZXJlIGlzIGEgc3VtbWFyeSB0YWJsZSBvZiB0aGUgY2Fub25pY2FsIGxpbmtzLCBhbmQgdGhlaXIgbWVhbiBmdW5jdGlvbnMsIGZvciB0aHJlZSBjb21tb24gZGlzdHJpYnV0aW9ucy4gRm9yIFBvaXNzb24gYW5kIG5lZ2F0aXZlIGJpbm9taWFsIG1vZGVscyBmb3IgY291bnRzLCB3ZSB1c2UgYSAqbG9nIGxpbmsqIGdpdmVuIGJ5IAoKJCQKXGxvZyAoXG11KSA9IFxtYXRoYmZ7WH0gXGJvbGRzeW1ib2x7XGJldGF9CiQkCgphbmQgaXRzIGludmVyc2UgbWVhbiBmdW5jdGlvbiBnaXZlbiBieQoKJCQKXG11ID0gXGV4cCAoXG1hdGhiZntYfSBcYm9sZHN5bWJvbHtcYmV0YX0pCiQkCgoqKioKCiMgUmVndWxhciBjb3VudHMKCkxldCdzIGNvbnNpZGVyIGEgcmVndWxhciBQb2lzc29uIHJlZ3Jlc3Npb24gbW9kZWwgZm9yIGNhdGNoZXMgb2Ygc3BvdCBwcmF3bnMgJHlfaSQgYXMgYSBmdW5jdGlvbiBvZiBiYWl0IHR5cGUgJENfaSQgYW5kIHdhdGVyIHRlbXBlcmF0dXJlICRUX2kkLCBzdWNoIHRoYXQKCiQkClxiZWdpbnthbGlnbmVkfQpcdGV4dHtkYXRhIGRpc3RyaWJ1dGlvbjp9ICYgfn4geV9pIFxzaW0gXHRleHR7UG9pc3Nvbn0oXGxhbWJkYV9pKSBcXCBcXApcdGV4dHtsaW5rIGZ1bmN0aW9uOn0gJiB+fiBcdGV4dHtsb2d9KFxsYW1iZGFfaSkgPSBcbXVfaSBcXCBcXApcdGV4dHtsaW5lYXIgcHJlZGljdG9yOn0gJiB+fiBcbXVfaSA9IFxhbHBoYSArIFxiZXRhXzEgQ19pICsgXGJldGFfMiBUX2kKXGVuZHthbGlnbmVkfQokJAoKIyMgQ2F0Y2hlcyBvZiBzcG90IHByYXducwoKVGhlIGZpcnN0IHN0ZXAgaXMgdG8gc2ltdWxhdGUgdGhlIGNhdGNoIGRhdGEuIFdlJ2xsIGFzc3VtZSB0aGF0IGNhdGNoZXMgb2Ygc3BvdCBwcmF3bnMgaW5jcmVhc2Ugd2l0aCB3YXRlciB0ZW1wZXJhdHVyZSwgYW5kIHRoYXQgY2F0Y2hlcyBhcmUgZ2VuZXJhbGx5IGdyZWF0ZXIgd2hlbiB1c2luZyBmaXNoIGFzIGJhaXQgY29tcGFyZWQgdG8gY2hpY2tlbi4KCmBgYHtyIHByYXduc19kYXRhfQpzZXQuc2VlZCg1MTQpCiMjIHNhbXBsZSBzaXplCm5uIDwtIDExMwojIyBhdmVyYWdlIGNhdGNoCmIwID0gMy41CiMjIGVmZmVjdCBvZiBjaGlja2VuIGFzIGJhaXQKYl9iYWl0IDwtIDAuMQojIyBlZmZlY3Qgb2YgdGVtcGVyYXR1cmUKYl90ZW1wIDwtIDAuMDMKIyMgYmFpdCB0eXBlCmZpc2ggPC0gc2FtcGxlKGMoMCwgMSksIG5uLCByZXBsYWNlID0gVFJVRSkKIyMgd2F0ZXIgdGVtcAp0ZW1wIDwtIHJ1bmlmKG5uLCA3LCAxMykKIyMgbGluZWFyIHByZWRpY3RvcgpldGEgPC0gZXhwKGIwICsgYl9iYWl0ICogZmlzaCArIGJfdGVtcCAqIHRlbXApCiMjIGNhdGNoZXMKY2F0Y2ggPC0gcmVwKE5BLCBsZW5ndGgoZXRhKSkgCmZvcihpIGluIDE6bm4pIHsKICBjYXRjaFtpXSA8LSBycG9pcygxLCBldGFbaV0pCn0KIyMgY29tYmluZSBkYXRhCnByYXducyA8LSBkYXRhLmZyYW1lKGNiaW5kKGNhdGNoLCBmaXNoLCB0ZW1wKSkKYGBgCgpIZXJlIGFyZSBwbG90cyBvZiBjYXRjaCB2ZXJzdXMgd2F0ZXIgdGVtcGVyYXR1cmUgYW5kIGJhaXQgdHlwZS4KCmBgYHtyIHByYXduc19wbG90cywgZmlnLmhlaWdodCA9IDQuNSwgZmlnLndpZHRoID0gOCwgZmlnLmFsaWduID0gJ2NlbnRlcid9CiMjIHNldCBwbG90IGFyZWEKcGFyKG1mcm93ID0gYygxLCAyKSwKICAgIG1haSA9IGMoMC45LCAwLjQsIDAuNiwgMC4xKSwKICAgIG9taSA9IGMoMCwgMC43LCAwLCAwKSwgYmcgPSBOQSwKICAgIGNleC5tYWluID0gMS4yLCBjZXgubGFiID0gMS4yKQojIyBwbG90IHRlbXAgdnMgY2F0Y2gKcGxvdCh0ZW1wLCBjYXRjaCwgbGFzID0gMSwgcGNoID0gMTYsIHhwZCA9IE5BLAogICAgIHhsYWIgPSAiVGVtcGVyYXR1cmUgKEMpIiwgeWxhYiA9ICJDYXRjaCIpCiMjIHBsb3QgYmFpdCB2cyBjYXRjaApwbG90KGZpc2ggKyAxLCBjYXRjaCwgbGFzID0gMSwgcGNoID0gMTYsCiAgICAgeGxpbSA9IGMoMC41LCAyLjUpLCB4bGFiID0gIkJhaXQgdHlwZSIsIHhheHQgPSAibiIsCiAgICAgeWF4dCA9ICJuIiwgeWxhYiA9ICIiKQpheGlzKDEsIGF0ID0gYygxLCAyKSwgbGFiZWxzID0gYygiQ2hpY2tlbiIsICJGaXNoIikpCmBgYAoKPGJyPgoKIyMgTW9kZWwgZml0dGluZwoKRml0dGluZyBQb2lzc29uIHJlZ3Jlc3Npb24gbW9kZWxzIHByb2NlZWRzIGFzIHdpdGggb3RoZXIgR0xNcyB1c2luZyBgZ2xtKClgLiBSZWNhbGwgdGhhdCB3ZSBtdXN0IHNwZWNpZnkgYm90aCB0aGUgYGZhbWlseWAgb2YgdGhlIGRpc3RyaWJ1dGlvbiBhbmQgdGhlIGBsaW5rYCB0eXBlLiBCeSBkZWZhdWx0IGBnbG0oKWAgYXNzdW1lcyB0aGUgY2Fub25pY2FsIGxpbmsgb25jZSBhIGZhbWlseSBpcyBzcGVjaWZpZWQsIGJ1dCBpdCdzIGdvb2QgImRlZmVuc2l2ZSBwcm9ncmFtbWluZyIgdG8gZXhwbGljaXRseSBpbmNsdWRlIGl0IGFueXdheS4gSGVyZSBpcyBvdXIgbW9kZWwgZm9yIGNhdGNoIGFzIGEgZnVuY3Rpb24gb2YgdGVtcGVyYXR1cmUgYW5kIGJhaXQgdHlwZS4KCmBgYHtyIHByYXduX21vZGVsfQojIyBQb2lzc29uIHJlZ3Jlc3Npb24KY21vZCA8LSBnbG0oY2F0Y2ggfiB0ZW1wICsgZmlzaCwgZGF0YSA9IHByYXducywKICAgICAgICAgICAgZmFtaWx5ID0gcG9pc3NvbihsaW5rID0gImxvZyIpKQpmYXJhd2F5OjpzdW1hcnkoY21vZCkKYGBgCgpBbGwgdGhyZWUgbW9kZWwgY29lZmZpY2llbnRzIGFyZSAic2lnbmlmaWNhbnQiIGF0IHRoZSAkXGFscGhhJCA9IDAuMDUgbGV2ZWwuIFJlY2FsbCB0aGF0IHRoZSB0cnVlIHZhbHVlcyBhcmUgYChJbnRlcmNlcHQpYCA9IGByIGIwYCwgYHRlbXBgID0gYHIgYl90ZW1wYCwgYW5kIGBmaXNoYCA9IGByIGJfYmFpdGAsIHNvIG91ciBlc3RpbWF0ZXMgYXJlIHJlYXNvbmFibHkgY2xvc2UgdG8gdGhlIHRydWUgdmFsdWVzLiBBbHNvIHJlY2FsbCB0aGF0IGJlY2F1c2UgYmFpdCB0eXBlIGlzIGEgY2F0ZWdvcmljYWwgcHJlZGljdG9yIHdpdGggMiBsZXZlbHMsIHRoZSBlZmZlY3Qgb2YgYGZpc2hgIHJlcHJlc2VudHMgdGhlIGNhc2Ugd2hlcmUgdGhlIGJhaXQgdHlwZSBpcyBmaXNoLiBJZiB0aGUgYmFpdCB0eXBlIGlzIGNoaWNrZW4sIHRoZW4gdGhlIGVmZmVjdCBpcyB6ZXJvLgoKV2UgYWxzbyBnZXQgYW4gZXN0aW1hdGUgb2YgdGhlIG1vZGVsIGRldmlhbmNlIChgRGV2aWFuY2VgKSwgd2hpY2ggaXMgfmByIHJvdW5kKGRldmlhbmNlKGNtb2QpLCAyKWAuIFRvIGV4dHJhY3QgdGhlIGRldmlhbmNlIGZyb20gYSBmaXR0ZWQgbW9kZWwsIHlvdSBjYW4gdXNlIGBkZXZpYW5jZShjbW9kKWAgb3IgYHN1bW1hcnkoY21vZCkkZGV2aWFuY2VgLgoKIyMgSW5mZXJlbmNlCgpPbmNlIHdlJ3ZlIGZpdCBvdXQgbW9kZWwsIGl0J3MgbmF0dXJhbCB0byB3b25kZXIgYWJvdXQgcGFyYW1ldGVyICh1biljZXJ0YWludHksIGdvb2RuZXNzIG9mIGZpdCwgYW5kIHdoZXRoZXIgbW9kZWwgZGlhZ25vc3RpY3MgcmV2ZWFsIGFueSBwb3NzaWJsZSBwcm9ibGVtcyB3aXRoIG91ciBtb2RlbC4KCiMjIyBDb25maWRlbmNlIGludGVydmFscyBmb3IgJFxiZXRhX2kkCgpXZSBjYW4gZWFzaWx5IGVzdGltYXRlIHRoZSBDSSdzIG9uIHRoZSBtb2RlbCBwYXJhbWV0ZXJzIHdpdGggYGNvbmZpbnQoKWAuIEhlcmUgYXJlIHRoZSB1cHBlciBhbmQgbG93ZXIgOTUlIENJJ3Mgb24gb3VyIG1vZGVsIHBhcmFtZXRlcnMgd2l0aCB0aGUgTUxFcy4KCmBgYHtyIGNpX3ByYXducywgbWVzc2FnZSA9IEZBTFNFfQojIyBDSSdzIGZvciBwcmF3biBtb2RlbApjaV9wcmF3bnMgPC0gY29uZmludChjbW9kKQpjaV90YmwgPC0gY2JpbmQoY2lfcHJhd25zWywxXSwgY29lZihjbW9kKSwgY2lfcHJhd25zWywyXSkKY29sbmFtZXMoY2lfdGJsKSA8LSBjKCJMb3dlciIsICJNTEUiLCAiVXBwZXIiKQpzaWduaWYoY2lfdGJsLCAzKQpgYGAKCldlIHNhdyBpbiBsZWN0dXJlIHRoYXQgd2UgY2FuIGhhdmUgcG9zc2libGUgYmlhc2VzIGluICRcdGV4dHtTRX0oXGJldGEpJCwgd2hpY2ggbWVhbnMgd2UgbWF5IHdhbnQgdG8gY29tcHV0ZSBDSSdzIGJhc2VkIG9uIHRoZSAqcHJvZmlsZSBsaWtlbGlob29kKi4gVG8gY2FsY3VsYXRlIHRoZSBwcm9maWxlIGxpa2VsaWhvb2RzLCB3ZSBzaW1wbHkgZXZhbHVhdGUgdGhlIGxpa2VsaWhvb2QgYXQgZWFjaCBwb2ludCBhbG9uZyBhIHNlcXVlbmNlIG9mIHBvc3NpYmxlIHBhcmFtZXRlciB2YWx1ZXMuIEhlcmUgYXJlIHRoZSBwcm9maWxlIGxpa2VsaWhvb2RzIGZvciB0aGUgZWZmZWN0cyBvZiB0ZW1wZXJhdHVyZSBhbmQgYmFpdCB0eXBlLgoKYGBge3IgcHJvZmlsZV9MTH0KIyMgbnVtYmVyIG9mIHBvaW50cyB0byBwcm9maWxlCm5iIDwtIDIwMAoKIyMgcG9zc2libGUgYmV0YSdzCmJldGFfYmFpdCA8LSBzZXEoMCwgMC4yLCBsZW5ndGggPSBuYikKYmV0YV90ZW1wIDwtIHNlcSgtMC4wMSwgMC4wNywgbGVuZ3RoID0gbmIpCgojIyBjYWxjdWxhdGUgbmVnLUxMIG9mIHBvc3NpYmxlIGJldGFfdGVtcAojIyBmaXggYmV0YV9iYWl0IGF0IGl0cyBNTEUKcGx0IDwtIHJlcChOQSwgbmIpCmZvcihpIGluIDE6bmIpIHsKICBtbSA8LSBnbG0oY2F0Y2ggfiAxICsgb2Zmc2V0KGJldGFfdGVtcFtpXSAqIHRlbXAgKyBvZmZzZXQoY29lZihjbW9kKVszXSAqIGZpc2gpKSwKICAgICAgICAgICAgZGF0YSA9IHByYXducywKICAgICAgICAgICAgZmFtaWx5ID0gcG9pc3NvbihsaW5rID0gImxvZyIpKQogIHBsdFtpXSA8LSAtbG9nTGlrKG1tKQp9CgojIyBjYWxjdWxhdGUgbmVnLUxMIG9mIHBvc3NpYmxlIGJldGFfYmFpdAojIyBmaXggYmV0YV90ZW1wIGF0IGl0cyBNTEUKcGxiIDwtIHJlcChOQSwgbmIpCmZvcihpIGluIDE6bmIpIHsKICBtbSA8LSBnbG0oY2F0Y2ggfiAxICsgb2Zmc2V0KGNvZWYoY21vZClbMl0gKiB0ZW1wICsgb2Zmc2V0KGJldGFfYmFpdFtpXSAqIGZpc2gpKSwKICAgICAgICAgICAgZGF0YSA9IHByYXducywKICAgICAgICAgICAgZmFtaWx5ID0gcG9pc3NvbihsaW5rID0gImxvZyIpKQogIHBsYltpXSA8LSAtbG9nTGlrKG1tKQp9CmBgYAoKSGVyZSBhcmUgcGxvdHMgb2YgdGhlIHByb2ZpbGUgbGlrZWxpaG9vZHMgYW5kIHRoZSB0aHJlc2hvbGQgdmFsdWUgYmFzZWQgdXBvbiB0aGUgOTUkXnt0aH0kIHBlcmNlbnRpbGUgZm9yIGEgJFxjaGleMl97MX0kIG9uIG9uZSBkZWdyZWUgb2YgZnJlZWRvbSAoaS5lLiwgdGhlIGRpZmZlcmVuY2UgaW4gdGhlIG51bWJlciBvZiBwYXJhbWV0ZXJzIGJldHdlZW4gdGhlIG1vZGVsIGFuZCBhIG1vZGVsIHdpdGhvdXQgdGhlIHBhcmFtZXRlcikuIFRoZSBibHVlIHBvaW50cyBhcmUgdGhlIGVzdGltYXRlZCBsb3dlciBhbmQgdXBwZXIgOTUlIENJLgoKYGBge3IgcGxvdF9wcm9maWxlLCBmaWcuaGVpZ2h0PTQuNSwgZmlnLndpZHRoPTgsIGZpZy5hbGlnbj0nY2VudGVyJywgbWVzc2FnZSA9IEZBTFNFfQojIyBzZXQgcGxvdCBhcmVhCnBhcihtZnJvdyA9IGMoMSwgMiksCiAgICBtYWkgPSBjKDAuOSwgMC45LCAwLjYsIDAuMSksCiAgICBvbWkgPSBjKDAsIDAsIDAsIDApLAogICAgY2V4LmxhYiA9IDEuNSkKCiMjIHRocmVzaG9sZCB2YWx1ZSBmb3IgQ0kKY3JpdCA8LSAtKGxvZ0xpayhjbW9kKSAtIHFjaGlzcSgwLjk1LCAxKSAvIDIpCgojIyBsaWtlbGlob29kIHByb2ZpbGUgZm9yIHRlbXAKcGxvdChiZXRhX3RlbXAsIHBsdCwgdHlwZSA9ICJsIiwgbGFzID0gMSwKICAgICB5bGFiID0gIk5lZ2F0aXZlIGxvZy1saWtlbGlob29kIiwgeGxhYiA9IGV4cHJlc3Npb24oYmV0YVt0ZW1wXSkpCmFibGluZShoID0gY3JpdCwgbHR5ID0gImRhc2hlZCIpCnBvaW50cyhjb25maW50KGNtb2QpWzIsXSwgYyhjcml0LCBjcml0KSwgcGNoID0gMTYsIGNvbCA9ICJibHVlIikKCiMjIGxpa2VsaWhvb2QgcHJvZmlsZSBmb3IgYmFpdApwbG90KGJldGFfYmFpdCwgcGxiLCB0eXBlID0gImwiLCBsYXMgPSAxLAogICAgIHlsYWIgPSAiIiwgeGxhYiA9IGV4cHJlc3Npb24oYmV0YVtiYWl0XSkpCmFibGluZShoID0gY3JpdCwgbHR5ID0gImRhc2hlZCIpCnBvaW50cyhjb25maW50KGNtb2QpWzMsXSwgYyhjcml0LCBjcml0KSwgcGNoID0gMTYsIGNvbCA9ICJibHVlIikKYGBgCgo8YnI+CgojIyMgR29vZG5lc3Mgb2YgZml0CgpJdCdzIG5hdHVyYWwgdG8gYXNrIGhvdyB3ZWxsIGEgbW9kZWwgZml0cyB0aGUgZGF0YS4gQXMgd2l0aCBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVscyBiYXNlZCB1cG9uIGEgYmlub21pYWwgZGlzdHJpYnV0aW9uLCB3ZSBjYW4gY2hlY2sgdGhlIGRldmlhbmNlICREJCBhZ2FpbnN0IGEgJFxjaGleMiQgZGlzdHJpYnV0aW9uLiBSZWNhbGwgdGhhdCB0aGUgZGV2aWFuY2UgZm9yIGFueSBtb2RlbCBpcwoKJCQKRF9pID0gXHRleHR7LX0yIFxsZWZ0WyBcbG9nIFxtYXRoY2Fse0x9KE1faSkgLSBcbG9nIFxtYXRoY2Fse0x9KE1fMCkgXHJpZ2h0XQokJAoKd2hlcmUgJE1faSQgaXMgdGhlIG1vZGVsIG9mIGludGVyZXN0IGFuZCAkTV8wJCBpcyBhbiBpbnRlcmNlcHQtb25seSBtb2RlbC4gVGhlIGxvZy1saWtlbGlob29kIGZvciBhIFBvaXNzb24gaXMgZ2l2ZW4gYnkKCiQkClxsb2cgXG1hdGhjYWx7TH0oeTsgXGxhbWJkYSkgPSBcc3VtX3tpPTF9XntufSBcbGVmdFsgeV97aX0gXGxvZyAoXGxhbWJkYSktIFxsYW1iZGEgLSBcbG9nIFxsZWZ0KCB5X3tpfSEgXHJpZ2h0KSAgXHJpZ2h0XQokJAoKYW5kIGhlbmNlIHRoZSBkZXZpYW5jZSBmb3IgYSBQb2lzc29uIGlzCgokJApcbG9nIFxtYXRoY2Fse0x9KHk7IFxsYW1iZGEpID0gXHN1bV97aT0xfV57bn0gXGxlZnRbIHlfe2l9IFxsb2cgKHlfaSAvIFxoYXR7XGxhbWJkYX0pIC0gKHlfaSAtIFxoYXR7XGxhbWJkYX0pICBccmlnaHRdCiQkCgpUaGUgbnVsbCBoeXBvdGhlc2lzIGZvciBvdXIgJGNoaV4yJCB0ZXN0IGlzIHRoYXQgb3VyIG1vZGVsIGlzIGNvcnJlY3RseSBzcGVjaWZpZWQgYW5kIGl0IGFkZXF1YXRlbHkgZml0cyB0aGUgZGF0YS4gSGVyZSBpcyB0aGUgY29kZSBmb3Igb3VyIHRlc3QuCgpgYGB7ciBtb2RlbF9kZXZ9CiMjIGRldmlhbmNlIG9mIHByYXduIG1vZGVsCkRfZnVsbCA8LSBzdW1tYXJ5KGNtb2QpJGRldmlhbmNlCiMjIExSVCB3aXRoIGRmID0gbiAtIGsKKHBfdmFsdWUgPC0gcGNoaXNxKERfZnVsbCwgbm4gLSBsZW5ndGgoY29lZihjbW9kKSksCiAgICAgICAgICAgICAgICAgICBsb3dlci50YWlsID0gRkFMU0UpKQpgYGAKClRoaXMgJHAkLXZhbHVlIGlzIHJhdGhlciBzbWFsbCBzbyB3ZSByZWplY3QgdGhlICRIXzAkLCBhbmQgY29uY2x1ZGUgdGhhdCB0aGUgbW9kZWwgZG9lcyBub3QgcHJvdmlkZSBhbiBhZGVxdWF0ZSBmaXQgdG8gdGhlIGRhdGEuIEJ1dCB3YWl0LS13ZSBzaW11bGF0ZWQgdGhlIGRhdGEgYWNjb3JkaW5nIHRvIGEgUG9pc3NvbiBkaXN0cmlidXRpb24sIHNvIHdoeSBkaWQgdGhpcyB0ZXN0IGNvbmNsdWRlIGEgbGFjayBvZiBmaXQ/IEluIHRoaXMgY2FzZSB0aGUgcmVhc29uIGlzIGJlY2F1c2UgdGhlIHVzZSBvZiBhICRcY2hpXjIkIGRpc3RyaWJ1dGlvbiBmb3IgdGhlIGxpa2VsaWhvb2QgcmF0aW8gdGVzdCByZWxpZXMgb24gYXN5bXB0b3RpYyBwcm9wZXJ0aWVzIG9mIHRoZSBkaXN0cmlidXRpb24sIGluIHRoYXQgYSBQb2lzc29uIGRpc3RyaWJ1dGlvbiBhcHByb3hpbWF0ZXMgYSBub3JtYWwgZGlzdHJpYnV0aW9uIGFzIHRoZSBtZWFuIGdldHMgbGFyZ2VyLiBUaGVyZWZvcmUsIHRoZXJlIGFyZSBubyBndWFyYW50ZWVzLCBldmVuIHdoZW4gdGhlIHNhbXBsZSBzaXplIGlzIGxhcmdlLCB0aGF0IHRoZSB0ZXN0IHdpbGwgYmUgdmFsaWQuCgpSZWNhbGwgZnJvbSBsZWN0dXJlIHRoYXQgdGhlIGFzc3VtcHRpb24gb2YgJEQgXHNpbSBcY2hpXjJfe24gLSBrfSQgY2FuIGJlIHZpb2xhdGVkIHdpdGggUG9pc3NvbiBtb2RlbHMgdW5sZXNzICRcbGFtYmRhJCBpcyBsYXJnZS4gQW5vdGhlciBvcHRpb24gaXMgdG8gdXNlIHRoZSBzYW1lIFBlYXJzb24ncyAkWF4yJCBzdGF0aXN0aWMgd2Ugc2F3IGZvciBiaW5vbWlhbCBtb2RlbHMsIHdoZXJlCgokJApYXjIgPSBcc3VtX3tpID0gMX1ebiBcZnJhY3soT19pIC0gRV9pKV4yfXtFX2l9IFxzaW0gXGNoaV4yX3sobiAtIGspfSBcXAokJAoKU28gZm9yIG91ciBQb2lzc29uIG1vZGVsCgokJApYXjIgPSBcc3VtX3tpPTF9XntufSBcZnJhY3soeV9pIC0gXGhhdHtcbGFtYmRhfV9pKV4yfXtcaGF0e1xsYW1iZGF9X2l9IFxzaW0gXGNoaV4yX3tuIC0ga30KJCQKCkFnYWluIG91ciBudWxsIGh5cG90aGVzaXMgaXMgdGhhdCBvdXIgbW9kZWwgaXMgY29ycmVjdGx5IHNwZWNpZmllZC4gSGVyZSBpcyB0aGUgY29kZSB0byBjb25kdWN0IHRoZSB0ZXN0LgoKYGBge3IgcGVhcnNvbl9nb2Z9CiMjIG51bWVyYXRvcgpubSA8LSAocHJhd25zJGNhdGNoIC0gZml0dGVkKGNtb2QpKV4yCiMjIGRlbm9taW5hdG9yCmRtIDwtIGZpdHRlZChjbW9kKQojIyBQZWFyc29uJ3MKWDIgPC0gc3VtKG5tIC8gZG0pCiMjIHRlc3QKKHBfdmFsdWUgPC0gcGNoaXNxKFgyLCBubiAtIGxlbmd0aChjb2VmKGNtb2QpKSwgbG93ZXIudGFpbCA9IEZBTFNFKSkKYGBgCgpXZSBhZ2FpbiB0aGUgJHAkLXZhbHVlIGlzIHJhdGhlciBzbWFsbCBzbyB3ZSByZWplY3QgdGhlICRIXzAkLCBhbmQgY29uY2x1ZGUgdGhhdCB0aGUgbW9kZWwgZG9lcyBub3QgcHJvdmlkZSBhbiBhZGVxdWF0ZSBmaXQgdG8gdGhlIGRhdGEgKHdpdGggdGhlIHNhbWUgY2F2ZWF0IGFzIGFib3ZlKS4KCgojIyMgRml0dGVkIHZhbHVlcyAmIENJJ3MKCldlIGNhbiBvYnRhaW4gdGhlIGZpdHRlZCB2YWx1ZXMgYW5kIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGFyb3VuZCB0aGUgZml0cyBpbiBhIG1hbm5lciBhbmFsb2dvdXMgdG8gdGhhdCBmb3IgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbHMuIFRoZSBpbXBvcnRhbnQgdGhpbmcgaGVyZSBpcyB0byByZW1lbWJlciB0aGF0IHdlIHdhbnQgdG8gZXN0aW1hdGUgdGhlIHVuY2VydGFpbnR5IGluIGxvZy1zcGFjZSBhbmQgdGhlbiBiYWNrLXRyYW5zZm9ybSB0aGUgaW50ZXJ2YWxzIGludG8gY291bnQgc3BhY2UuIEZvciBlYXNlIGluIGludGVycHJldGF0aW9uLCB3ZSBhbHNvIHdhbnQgdG8gY2FsY3VsYXRlIHRoZSBDSSdzIGZvciB0aGUgZml0cyB3aXRoIGJvdGggYmFpdCB0eXBlcyBhcyBhIGZ1bmN0aW9uIG9mIHRlbXBlcmF0dXJlLgoKYGBge3IgZml0dGVkX2NpfQojIyBzb3J0ZWQgdGVtcCAKdG1wIDwtIHByYXduc1tvcmRlcihwcmF3bnNbLDNdKSxdCiMjIHNwbGl0IGRhdGEgaW50byBiYWl0IHR5cGVzCmZkYXQgPC0gdG1wW3RtcCRmaXNoID09IDEsXQpjZGF0IDwtIHRtcFt0bXAkZmlzaCA9PSAwLF0KCiMjIGZpdHRlZCB2YWx1ZXMKZmlzaCA8LSBwcmVkaWN0KGNtb2QsIGZkYXQsIHNlLmZpdCA9IFRSVUUsIHR5cGUgPSAibGluayIpCmNoa24gPC0gcHJlZGljdChjbW9kLCBjZGF0LCBzZS5maXQgPSBUUlVFLCB0eXBlID0gImxpbmsiKQoKIyMgdCB2YWx1ZQp0X2NyaXQgPC0gcXQoMC45NzUsIG5uIC0gbGVuZ3RoKGNvZWYoY21vZCkpKQoKIyMgQ0kncyBmb3IgZmlzaApmaXNoX2ZpdCA8LSBleHAoZmlzaCRmaXQpCmZpc2hfbG8gPC0gZXhwKGZpc2gkZml0IC0gdF9jcml0ICogZmlzaCRzZS5maXQpCmZpc2hfaGkgPC0gZXhwKGZpc2gkZml0ICsgdF9jcml0ICogZmlzaCRzZS5maXQpCgojIyBDSSdzIGZvciBjaGlja2VuCmNoa25fZml0IDwtIGV4cChjaGtuJGZpdCkKY2hrbl9sbyA8LSBleHAoY2hrbiRmaXQgLSB0X2NyaXQgKiBjaGtuJHNlLmZpdCkKY2hrbl9oaSA8LSBleHAoY2hrbiRmaXQgKyB0X2NyaXQgKiBjaGtuJHNlLmZpdCkKYGBgCgpIZXJlIGlzIGEgcGxvdCBvZiB0aGUgY2F0Y2hlcyB2ZXJzdXMgdGVtcGVyYXR1cmUgd2l0aCBvdmVybGF5cyBvZiB0aGUgbW9kZWwgZml0cyBmb3IgYm90aCBiYWl0IHR5cGVzLgoKYGBge3IgcGxvdF9maXR0ZWRfY2ksIGZpZy5oZWlnaHQ9NC41LCBmaWcud2lkdGg9NC41LCBmaWcuYWxpZ249J2NlbnRlcid9CiMjIHNldCBwbG90IGFyZWEKcGFyKG1haSA9IGMoMC45LCAwLjksIDAuNiwgMC4xKSwKICAgIG9taSA9IGMoMCwgMCwgMCwgMCksCiAgICBjZXgubGFiID0gMS41KQoKIyMgdGVtcCB2cyBjYXRjaApwbG90KHRlbXAsIGNhdGNoLCBwY2ggPSAxNiwgbGFzID0gMSwKICAgICB5bGFiID0gIkNhdGNoIiwgeGxhYiA9IlRlbXBlcmF0dXJlIChDKSIpCiMjIHdpdGggZmlzaCBiYWl0CmxpbmVzKGZkYXQkdGVtcCwgZmlzaF9maXQsIGx3ZCA9IDIsIGNvbCA9ICJibHVlIikKbGluZXMoZmRhdCR0ZW1wLCBmaXNoX2xvLCBsd2QgPSAxLCBjb2wgPSAiYmx1ZSIpCmxpbmVzKGZkYXQkdGVtcCwgZmlzaF9oaSwgbHdkID0gMSwgY29sID0gImJsdWUiKQp0ZXh0KDcsIDUyLCAiRmlzaCIsIHBvcyA9IDQsIGNvbCA9ICJibHVlIikKIyMgd2l0aCBjaGlja2VuIGJhaXQKbGluZXMoY2RhdCR0ZW1wLCBjaGtuX2ZpdCwgbHdkID0gMiwgY29sID0gImRhcmtyZWQiKQpsaW5lcyhjZGF0JHRlbXAsIGNoa25fbG8sIGx3ZCA9IDEsIGNvbCA9ICJkYXJrcmVkIikKbGluZXMoY2RhdCR0ZW1wLCBjaGtuX2hpLCBsd2QgPSAxLCBjb2wgPSAiZGFya3JlZCIpCnRleHQoNywgMzQsICJDaGlja2VuIiwgcG9zID0gNCwgY29sID0gImRhcmtyZWQiKQpgYGAKCjxicj4KCiMjIE1vZGVsIGRpYWdub3N0aWNzCgpBcyB3aXRoIG90aGVyIG1vZGVscywgaXQncyBpbXBvcnRhbnQgdG8gZXhhbWluZSBkaWFnbm9zdGljIGNoZWNrcyBmb3Igb3VyIGZpdHRlZCBtb2RlbHMuIFRoZSBmaXJzdCB0aGluZyB3ZSBjYW4gZG8gaXMgZXhhbWluZSBhIHBsb3Qgb2YgdGhlIG1vZGVsIHJlc2lkdWFscy4KCiMjIyBSZXNpZHVhbHMKCmBgYHtyIHJlc2lkcywgZmlnLmhlaWdodD00LjUsIGZpZy53aWR0aD00LjUsIGZpZy5hbGlnbj0nY2VudGVyJ30KIyMgc2V0IHBsb3QgYXJlYQpwYXIobWFpID0gYygwLjksIDAuOSwgMC42LCAwLjEpLAogICAgb21pID0gYygwLCAwLCAwLCAwKSwKICAgIGNleC5sYWIgPSAxLjUpCgojIyByZXNpZHMgdnMgZml0dGVkCmVlIDwtIHByYXducyRjYXRjaCAtIGZpdHRlZChjbW9kKQpwbG90KGZpdHRlZChjbW9kKSwgZWUsIHBjaCA9IDE2LCBsYXMgPSAxLAogICAgIHlsYWIgPSAiUmVzaWR1YWxzIiwgeGxhYiA9IkZpdHRlZCB2YWx1ZXMiKQpgYGAKCjxicj4KClRoZXNlIHJlc2lkdWFscyBsb29rIGdvb2QgaW4gdGhhdCB0aGVyZSBpcyBubyBvYnZpb3VzIHBhdHRlcm4gKGxpbmVhciwgbm9ubGluZWFyKSwgbm9yIGlzIHRoZXJlIGFueSBldmlkZW5jZSBvZiBoZXRlcm9zY2VkYXN0aWNpdHkuCgojIyMgTGV2ZXJhZ2UKCldlIGNhbiBjYWxjdWxhdGUgdGhlIGxldmVyYWdlcyAkaCQgdG8gbG9vayBmb3IgdW51c3VhbCBvYnNlcnZhdGlvbiBpbiAqcHJlZGljdG9yIHNwYWNlKi4gUmVjYWxsIHRoYXQgd2UgYXJlIHBvdGVudGlhbGx5IGNvbmNlcm5lZCBhYm91dCAkaCA+IDIgXGZyYWN7a317bn0kLiBXZSBjYW4gdXNlIGBoYXR2YWx1ZXMoKWAgdG8gY29tcHV0ZSB0aGUgbGV2ZXJhZ2VzLgoKYGBge3IgbGV2ZXJhZ2V9CiMjIGxldmVyYWdlcwpoYXRfdmFsdWVzIDwtIGhhdHZhbHVlcyhjbW9kKQojIyB0aHJlc2hvbGQgdmFsdWUKaF9jcml0IDwtIDIgKiBsZW5ndGgoY29lZihjbW9kKSkgLyBubgojIyBjaGVjayBpZiBhbnkgaF9pID4gYl9jcml0CmFueShoYXRfdmFsdWVzID4gaF9jcml0KQpgYGAKCk5vbmUgb2YgdGhlc2UgcG9pbnRzIGhhcyBhIGxldmVyYWdlIGdyZWF0ZXIgdGhhbiBvdXIgdGhyZXNob2xkIHZhbHVlLiBXZSBjYW4gYWxzbyB1c2UgYGZhcmF3YXk6OmhhbGZub3JtKClgIHRvIHBsb3QgdGhlbS4KCmBgYHtyIHBsb3RfbGV2ZXJhZ2UsIGZpZy5oZWlnaHQ9NC41LCBmaWcud2lkdGg9NC41LCBmaWcuYWxpZ249J2NlbnRlcid9CiMjIHNldCBwbG90IGFyZWEKcGFyKG1haSA9IGMoMC45LCAwLjksIDAuNiwgMC4xKSwKICAgIG9taSA9IGMoMCwgMCwgMCwgMCksCiAgICBjZXgubGFiID0gMS41KQoKIyMgaGFsZm5vcm1hbCBwbG90CmZhcmF3YXk6OmhhbGZub3JtKGhhdF92YWx1ZXMsIG5sYWIgPSAwLCBsYWJzID0gIiIsIGxhcyA9IDEpCnRleHQoMCwgMC45MipwYXIoInVzciIpWzRdLAogICAgIHN1YnN0aXR1dGUoaXRhbGljKGhbY3JpdF0pID09IGhfY3JpdCwgbGlzdChoX2NyaXQgPSByb3VuZChoX2NyaXQsIDMpKSksCiAgICAgcG9zID0gNCkKYGBgCgo8YnI+CgojIyMgQ29vaydzIERpc3RhbmNlCgpSZWNhbGwgdGhhdCB3ZSBjYW4gdXNlIENvb2sncyAkRCQgdG8gaWRlbnRpZnkgcG90ZW50aWFsbHkgaW5mbHVlbnRpYWwgcG9pbnRzLCB3aGVyZQoKJCQKRF97aX09ZV97aX1eezJ9IFxmcmFjezF9e2t9XGxlZnQoXGZyYWN7aF97aX19ezEtaF97aX19XHJpZ2h0KQokJAoKSW4gZ2VuZXJhbCB3ZSBzaG91bGQgYmUgcG90ZW50aWFsbHkgY29uY2VybmVkIGFib3V0ICREX2kgPiBGXnsoMC41KX1fe24sIG4gLSBrfSBcYXBwcm94IDEkLgoKYGBge3IgY29va3N9CiMjIENvb2sncyBECkNEIDwtIGNvb2tzLmRpc3RhbmNlKGNtb2QpCiMjIFRocmVzaG9sZCB2YWx1ZQpDRF9jcml0IDwtIHFmKDAuNSwgbm4sIG5uIC0gbGVuZ3RoKGNvZWYoY21vZCkpKQojIyBjaGVjayBpZiBhbnkgQ0RfaSA+IENEX2NyaXQKYW55KENEID4gQ0RfY3JpdCkKYGBgCgpJdCBsb29rcyBsaWtlIG5vbmUgb2YgdGhlIENvb2sncyAkRCQgdmFsdWVzIGV4Y2VlZCBvdXIgdGhyZXNob2xkIHZhbHVlLiBMZXQncyBwbG90IHRoZW0gd2l0aCBgZmFyYXdheTo6aGFsZm5vcm0oKWAuCgpgYGB7ciBwbG90X2Nvb2tzLCBmaWcuaGVpZ2h0PTQuNSwgZmlnLndpZHRoPTQuNSwgZmlnLmFsaWduPSdjZW50ZXInfQojIyBzZXQgcGxvdCBhcmVhCnBhcihtYWkgPSBjKDAuOSwgMC45LCAwLjEsIDAuMSksCiAgICBvbWkgPSBjKDAsIDAsIDAsIDApLAogICAgY2V4LmxhYiA9IDEuNSkKCiMjIGhhbGZub3JtYWwgcGxvdApmYXJhd2F5OjpoYWxmbm9ybShDRCwgbmxhYiA9IDAsIGxhYnMgPSAiIiwgbGFzID0gMSkKYGBgCgo8YnI+CgojIyBNb2RlbCBzZWxlY3Rpb24KCldlIGNhbiB1c2UgYSBsaWtlbGlob29kIHJhdGlvIHRlc3QgdG8gY29tcGFyZSBvdXIgbW9kZWwgdG8gYW4gaW50ZXJjZXB0LW9ubHkgbW9kZWwKCmBgYHtyIExSVF9kZXZ9CiMjIGRldmlhbmNlIG9mIGZ1bGwgbW9kZWwKRF9mdWxsIDwtIHN1bW1hcnkoY21vZCkkZGV2aWFuY2UKIyMgZGV2aWFuY2Ugb2YgbnVsbCBtb2RlbApEX251bGwgPC0gc3VtbWFyeShjbW9kKSRudWxsLmRldmlhbmNlCiMjIHRlc3Qgc3RhdGlzdGljCmxhbWJkYSA8LSBEX251bGwgLSBEX2Z1bGwKIyMgTFJUIHdpdGggZGYgPSAyCihwX3ZhbHVlIDwtIHBjaGlzcShsYW1iZGEsIDIsIGxvd2VyLnRhaWwgPSBGQUxTRSkpCmBgYAoKVGhpcyAkcCQtdmFsdWUgaXMgdmVyeSBzbWFsbCBzbyB3ZSByZWplY3QgJEhfMCQgKHRoYXQgdGhlIGRhdGEgY29tZSBmcm9tIHRoZSBudWxsIG1vZGVsKS4KCioqKgoKIyBPdmVyZGlzcGVyc2VkIGNvdW50cwoKV2Ugc2F3IHRoYXQgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbHMgYmFzZWQgdXBvbiB0aGUgYmlub21pYWwgZGlzdHJpYnV0aW9uIGNhbiBleGhpYml0IG92ZXJkaXNwZXJzaW9uIGlmIHRoZSBkZXZpYW5jZSBpcyBsYXJnZXIgdGhhbiBleHBlY3RlZC4gUG9pc3NvbiByZWdyZXNzaW9uIG1vZGVscyBhcmUgYWxzbyBwcm9uZSB0byBvdmVyZGlzcGVyc2lvbiBiZWNhdXNlIHRoZXJlIGlzIG9ubHkgb25lIHBhcmFtZXRlciBzcGVjaWZ5aW5nIGJvdGggdGhlIG1lYW4gYW5kIHRoZSB2YXJpYW5jZS4KCiQkCnlfaSBcc2ltIFx0ZXh0e1BvaXNzb259KFxsYW1iZGEpCiQkCgojIyBCeWNhdGNoIG9mIGdyZWVuIHNlYSB0dXJ0bGVzCgpJbiBsZWN0dXJlIHdlIHVzZWQgc29tZSBleGFtcGxlIGRhdGEgaW5kaWNhdGl2ZSBvZiBieWNhdGNoIG9mIHNlYSB0dXJ0bGVzIGluIHRyYXdsIGZpc2hlcmllcy4gSGVyZSBhcmUgdGhlIHNpbXVsYXRlZCBkYXRhIHdoZXJlaW4gfjUwJSBvZiB0aGUgZmxlZXQgd2FzIG91dGZpdHRlZCB3aXRoIHR1cnRsZSBleGNsdWRlciBkZXZpY2VzIChURURTKSBhbmQgdGhlIG51bWJlciBvZiB0dXJ0bGVzIGNhdWdodCBwZXIgMTAwMCB0cmF3bCBob3VycyB3YXMgcmVjb3JkZWQgYWxvbmcgd2l0aCB3YXRlciB0ZW1wZXJhdHVyZS4KCmBgYHtyIHR1cnRsZXN9CiMjIG51bWJlciBvZiBvYnMKbm4gPC0gMTk3CiMjIHByZXNlbmNlL2Fic2VuY2Ugb2YgVEVEClRFRCA8LSBzYW1wbGUoYygwLDEpLCBubiwgcmVwbGFjZSA9IFRSVUUpCiMjIHRlbXBlcmF0dXJlCnRlbXAgPC0gcnVuaWYobm4sIDE1LCAyNSkKCiMjIG1lYW4gYnljYXRjaApiZXRhXzAgPC0gLTEuNQojIyBlZmZlY3Qgb2YgVEVECmJldGFfMSA8LSAtMS4xCiMjIGVmZmVjdCBvZiB0ZW1wCmJldGFfMiA8LSAwLjA4NQoKIyMgdmFyaWFuY2UgaW5mbGF0aW9uCm11IDwtIDEKdmlmIDwtIDMKCiMjIGV4cGVjdGF0aW9uCm1lYW4gPC0gZXhwKGJldGFfMCArIGJldGFfMSAqIFRFRCArIGJldGFfMiAqIHRlbXApCgojIyBieWNhdGNoCmJ5Y2F0Y2ggPC0gcm5iaW5vbShubiwgbXUgPSBtZWFuLCBzaXplID0gbXVeMiAvICh2aWYgLSBtdSkpCgojIyBkYXRhIGZyYW1lCnR1cnRsZXMgPC0gZGF0YS5mcmFtZShieWNhdGNoLCBURUQsIHRlbXApCmBgYAoKCmBgYHtyIHBsb3RfdHVydGxlcywgZmlnLmhlaWdodD00LjUsIGZpZy53aWR0aD00LjUsIGZpZy5hbGlnbj0nY2VudGVyJ30KIyMgc2V0IHBsb3QgYXJlYQpwYXIobWFpID0gYygwLjksIDAuOSwgMC42LCAwLjEpLAogICAgb21pID0gYygwLCAwLCAwLCAwKSwKICAgIGNleC5sYWIgPSAxLjUpCgojIyBoaXN0b2dyYW0gb2YgY2F0Y2hlcwpoaXN0KHR1cnRsZXMkYnljYXRjaCwgbGFzID0gMSwgYnJlYWtzID0gc2VxKDAsIG1heChieWNhdGNoKSksCiAgICAgY29sID0gInNlYWdyZWVuIiwgYm9yZGVyID0gImdyYXkiLAogICAgIHhsYWIgPSAiQnljYXRjaCIsIG1haW4gPSAiIikKYGBgCgo8YnI+CgojIyBQb2lzc29uIG1vZGVsIGZvciBieWNhdGNoCgpMZXQncyBiZWdpbiBieSBmaXR0aW5nIGEgUG9pc3NvbiByZWdyZXNzaW9uIG1vZGVsIHRvIGJ5Y2F0Y2ggb2YgdHVydGxlcyAkeV9pJCBhcyBhIGZ1bmN0aW9uIG9mIFRFRCBwcmVzZW5jZS9hYnNlbmNlICRUX2kkIGFuZCB3YXRlciB0ZW1wZXJhdHVyZSAkV19pJC4gSGVyZSBpcyB0aGUgc3BlY2lmaWNhdGlvbiBvZiBvdXIgR0xNOgoKJCQKXGJlZ2lue2FsaWduZWR9Clx0ZXh0e2RhdGEgZGlzdHJpYnV0aW9uOn0gJiB+fiB5X2kgXHNpbSBcdGV4dHtQb2lzc29ufShcbGFtYmRhX2kpIFxcIFxcClx0ZXh0e2xpbmsgZnVuY3Rpb246fSAmIH5+IFx0ZXh0e2xvZ30oXGxhbWJkYV9pKSA9IFxldGFfaSBcXCBcXApcdGV4dHtsaW5lYXIgcHJlZGljdG9yOn0gJiB+fiBcZXRhX2kgPSBcYWxwaGEgKyBcYmV0YV8xIFRfaSArIFxiZXRhXzIgV19pClxlbmR7YWxpZ25lZH0KJCQKCkhlcmUgaXMgb3VyIG1vZGVsIGZpdCB0byB0aGUgZGF0YS4KCmBgYHtyIHRlZF9tb2RlbH0KIyMgUG9pc3NvbiByZWdyZXNzaW9uCnRlZF9tb2QgPC0gZ2xtKGJ5Y2F0Y2ggfiBURUQgKyB0ZW1wLCBkYXRhID0gdHVydGxlcywKICAgICAgICAgICAgICAgZmFtaWx5ID0gcG9pc3NvbihsaW5rID0gImxvZyIpKQojIyBtb2RlbCBzdW1tYXJ5CmZhcmF3YXk6OnN1bWFyeSh0ZWRfbW9kKQpgYGAKClR3byBvZiB0aGVzZSBwYXJhbWV0ZXJzIGFwcGVhciB0byBiZSBub24tc2lnbmlmaWNhbnQgYXQgJFxhbHBoYSQgPSAwLjA1LiBUaGF0IHNhaWQsIHRoZSBlc3RpbWF0ZWQgdmFsdWVzIGFyZSByZWFzb25hYmx5IGNsb3NlIHRoZSB0cnVlIHZhbHVlcyBhYm92ZS4KCiMjIEdvb2RuZXNzIG9mIGZpdAoKQXMgd2UgZGlkIGFib3ZlIGZvciB0aGUgcHJhd24gbW9kZWwsIHdlIGNhbiB1c2UgUGVhcnNvbidzICRcY2hpXjIkIHN0YXRpc3RpYyBhcyBhIGdvb2RuZXNzLW9mLWZpdCBtZWFzdXJlIGZvciBvdXIgdHVydGxlIG1vZGVsLiBIZXJlIGFnYWluIHRoZSBudWxsIGh5cG90aGVzaXMgaXMgdGhhdCBvdXIgbW9kZWwgaXMgY29ycmVjdGx5IHNwZWNpZmllZC4KCmBgYHtyIHRlZF9nb2Z9CiMjIFBlYXJzb24ncyBYXjIgc3RhdGlzdGljClgyIDwtIHN1bSgoYnljYXRjaCAtIGZpdHRlZCh0ZWRfbW9kKSleMiAvIGZpdHRlZCh0ZWRfbW9kKSkKIyMgbGlrZWxpaG9vZCByYXRpbyB0ZXN0CnBjaGlzcShYMiwgZGYgPSBubiAtIGxlbmd0aChjb2VmKHRlZF9tb2QpKSwKICAgICAgIGxvd2VyLnRhaWwgPSBGQUxTRSkKYGBgCgpUaGUgJHAkLXZhbHVlIGlzIHF1aXRlIHNtYWxsIHNvIHdlIHJlamVjdCAkSF8wJCBhbmQgY29uY2x1ZGUgdGhhdCB0aGUgUG9pc3NvbiBtb2RlbCBpcyBub3QgYSBnb29kIGZpdCB0byB0aGUgZGF0YS4KCiMjIyBPdmVyZGlzcGVyc2lvbgoKV2UgY2FuIGNvbnNpZGVyIHRoZSBwb3NzaWJpbGl0eSB0aGF0IHRoZSB2YXJpYW5jZSBzY2FsZXMgbGluZWFybHkgd2l0aCB0aGUgbWVhbiwgc3VjaCB0aGF0CgokJApcdGV4dHtWYXJ9KHkpID0gYyBcbGFtYmRhCiQkCgpJZiAkYyQgPSAxIHRoZW4gJHkgXHNpbSBcdGV4dHtQb2lzc29ufShcbGFtYmRhKSQsIGFuZCBpZiAkYyQgPiAxIHRoZSBkYXRhIGFyZSAqb3ZlcmRpc3BlcnNlZCouIFdlIGNhbiBlc3RpbWF0ZSB0aGUgb3ZlcmRpc3BlcnNpb24gJFxoYXR7Y30kIGFzCgokJApcaGF0e2N9ID0gXGZyYWN7WF4yfXtuIC0ga30KJCQKCmFuZAoKYGBge3IgdGVkX292ZXJ9CiMjIGZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSBkaXNwZXJzaW9uIHBhcmFtZXRlcgpjX2hhdCA8LSBmdW5jdGlvbihvYnMsIG1vZGVsKSB7CiAgWDIgPC0gc3VtKChvYnMgLSBmaXR0ZWQobW9kZWwpKV4yIC8gZml0dGVkKG1vZGVsKSkKICByZXR1cm4oWDIgLyAobGVuZ3RoKG9icykgLSBsZW5ndGgoY29lZihtb2RlbCkpKSkKfQojIyBkaXNwZXJzaW9uIHBhcmFtZXRlcgooY19oYXRfdGVkIDwtIGNfaGF0KGJ5Y2F0Y2gsIHRlZF9tb2QpKQpgYGAKClRoaXMgZXN0aW1hdGUgb2YgZGlzcGVyc2lvbiBpcyB3ZWxsIGFib3ZlIDEgc28gd2Ugc2hvdWxkIGJlIGNvbmNlcm5lZCBhYm91dCBpdHMgZWZmZWN0IG9uIHRoZSBlc3RpbWF0ZWQgdW5jZXJ0YWludHkgb2Ygb3VyIG1vZGVsIHBhcmFtZXRlcnMuIFRoZXJlZm9yZSwgd2UgY2FuIHRlbGwgKipSKiogdGhhdCB3ZSB3YW50IHRvIGFjY291bnQgZm9yIHRoZSBvdmVyZGlzcGVyc2lvbiB3aGVuIGVzdGltYXRpbmcgdGhlIFNFIGZvciB0aGUgbW9kZWwgcGFyYW1ldGVycyBieSBpbmNsdWRpbmcgdGhlIGBkaXNwZXJzaW9uYCBhcmd1bWVudCBpbiBgc3VtbWFyeSgpYC4gTGV0J3MgY29tcGFyZSB0aGUgU0UncyBmb3IgYm90aCBjYXNlcy4KCmBgYHtyIHRlZF9ib3RofQojIyByZWd1bGFyIFBvaXNzb24Kc2lnbmlmKHN1bW1hcnkodGVkX21vZCkkY29lZmZpY2llbnRzLCAzKQojIyBvdmVyZGlzcGVyc2VkIFBvaXNzb24Kc2lnbmlmKHN1bW1hcnkodGVkX21vZCwgZGlzcGVyc2lvbiA9IGNfaGF0X3RlZCkkY29lZmZpY2llbnRzLCAzKQpgYGAKClRoZSBTRSdzIGZvciB0aGUgb3ZlcmRpc3BlcnNlZCBtb2RlbCBhcmUgY2xlYXJseSBsYXJnZXIuIFdlIGNhbiBzZWUgdGhlIGVmZmVjdCB0aGlzIGhhcyBvbiB0aGUgZXN0aW1hdGVkIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGJ5IG92ZXJsYXlpbmcgdGhlbSBvbiBwbG90cyBvZiB0aGUgZGF0YSBhbmQgem9vbWluZyBpbiBvbiB0aGUgbG93ZXIgcmFuZ2Ugb2YgdGhlIGRhdGEuCgojIyBFZmZlY3Qgb2Ygb3ZlcmRpc3BlcnNpb24KCmBgYHtyIGZpdHRlZF9jaV8yLCBmaWcuaGVpZ2h0PTQuNSwgZmlnLndpZHRoPTcuNSwgZmlnLmFsaWduPSdjZW50ZXInfQojIyBmaXR0ZWQgdmFsdWVzCnRtcCA8LSB0dXJ0bGVzW29yZGVyKHR1cnRsZXNbLDNdKSxdCmZkYXQgPC0gdG1wW3RtcCRURUQgPT0gMSxdCmNkYXQgPC0gdG1wW3RtcCRURUQgPT0gMCxdClRFRCA8LSBwcmVkaWN0KHRlZF9tb2QsIGZkYXQsIHNlLmZpdCA9IFRSVUUsIHR5cGUgPSAibGluayIpCm5vX1RFRCA8LSBwcmVkaWN0KHRlZF9tb2QsIGNkYXQsIHNlLmZpdCA9IFRSVUUsIHR5cGUgPSAibGluayIpCgojIyBWSUYgZml0dGVkIHZhbHVlcwp0bXAyIDwtIHR1cnRsZXNbb3JkZXIodHVydGxlc1ssM10pLF0KZmRhdDIgPC0gdG1wMlt0bXAyJFRFRCA9PSAxLF0KY2RhdDIgPC0gdG1wMlt0bXAyJFRFRCA9PSAwLF0KVEVEMiA8LSBwcmVkaWN0KHRlZF9tb2QsIGZkYXQyLCBzZS5maXQgPSBUUlVFLCB0eXBlID0gImxpbmsiLCBkaXNwZXJzaW9uID0gY19oYXRfdGVkKQpub19URUQyIDwtIHByZWRpY3QodGVkX21vZCwgY2RhdDIsIHNlLmZpdCA9IFRSVUUsIHR5cGUgPSAibGluayIsIGRpc3BlcnNpb24gPSBjX2hhdF90ZWQpCgojIyB0IHZhbHVlCnRfY3JpdCA8LSBxdCgwLjk3NSwgbm4gLSBsZW5ndGgoY29lZih0ZWRfbW9kKSkpCgojIyBzZXQgcGxvdCBhcmVhCnBhcihtZnJvdyA9IGMoMSwyKSwKICAgIG1haSA9IGMoMC45LCAwLjksIDAuNiwgMC4xKSwKICAgIG9taSA9IGMoMCwgMCwgMCwgMCksCiAgICBjZXgubGFiID0gMS40KQoKIyMgdGVtcCB2cyBieWNhdGNoCnBsb3QodGVtcCwgYnljYXRjaCwgcGNoID0gMTYsIGxhcyA9IDEsIHlsaW0gPSBjKDAsIDMuNSksCiAgICAgeWxhYiA9ICJCeWNhdGNoIiwgeGxhYiA9IlRlbXBlcmF0dXJlIChDKSIsIG1haW4gPSAiV2l0aG91dCBWSUYiKQojIyB3aXRoIFRFRApsaW5lcyhmZGF0JHRlbXAsIGV4cChURUQkZml0KSwgbHdkID0gMiwgY29sID0gImJsdWUiKQpsaW5lcyhmZGF0JHRlbXAsIGV4cChURUQkZml0ICsgdF9jcml0ICogVEVEJHNlLmZpdCksIGx3ZCA9IDEsIGNvbCA9ICJibHVlIikKbGluZXMoZmRhdCR0ZW1wLCBleHAoVEVEJGZpdCAtIHRfY3JpdCAqIFRFRCRzZS5maXQpLCBsd2QgPSAxLCBjb2wgPSAiYmx1ZSIpCnRleHQoNywgNjUsICJ3aXRoIFRFRCIsIHBvcyA9IDQsIGNvbCA9ICJibHVlIikKIyMgd2l0aG91dCBURUQKbGluZXMoY2RhdCR0ZW1wLCBleHAobm9fVEVEJGZpdCksIGx3ZCA9IDIsIGNvbCA9ICJkYXJrcmVkIikKbGluZXMoY2RhdCR0ZW1wLCBleHAobm9fVEVEJGZpdCArIHRfY3JpdCAqIG5vX1RFRCRzZS5maXQpLCBsd2QgPSAxLCBjb2wgPSAiZGFya3JlZCIpCmxpbmVzKGNkYXQkdGVtcCwgZXhwKG5vX1RFRCRmaXQgLSB0X2NyaXQgKiBub19URUQkc2UuZml0KSwgbHdkID0gMSwgY29sID0gImRhcmtyZWQiKQp0ZXh0KDcsIDMwLCAidy9vIFRFRCIsIHBvcyA9IDQsIGNvbCA9ICJkYXJrcmVkIikKCiMjIHRlbXAgdnMgYnljYXRjaApwbG90KHRlbXAsIGJ5Y2F0Y2gsIHBjaCA9IDE2LCBsYXMgPSAxLCB5bGltID0gYygwLCAzLjUpLAogICAgIHlsYWIgPSAiIiwgeGxhYiA9IlRlbXBlcmF0dXJlIChDKSIsIG1haW4gPSAiV2l0aCBWSUYiKQojIyB3aXRoIFRFRApsaW5lcyhmZGF0MiR0ZW1wLCBleHAoVEVEMiRmaXQpLCBsd2QgPSAyLCBjb2wgPSAiYmx1ZSIpCmxpbmVzKGZkYXQyJHRlbXAsIGV4cChURUQyJGZpdCArIHRfY3JpdCAqIFRFRDIkc2UuZml0KSwgbHdkID0gMSwgY29sID0gImJsdWUiKQpsaW5lcyhmZGF0MiR0ZW1wLCBleHAoVEVEMiRmaXQgLSB0X2NyaXQgKiBURUQyJHNlLmZpdCksIGx3ZCA9IDEsIGNvbCA9ICJibHVlIikKdGV4dCg3LCA2NSwgIndpdGggVEVEIiwgcG9zID0gNCwgY29sID0gImJsdWUiKQojIyB3aXRob3V0IFRFRApsaW5lcyhjZGF0JHRlbXAsIGV4cChub19URUQyJGZpdCksIGx3ZCA9IDIsIGNvbCA9ICJkYXJrcmVkIikKbGluZXMoY2RhdCR0ZW1wLCBleHAobm9fVEVEMiRmaXQgKyB0X2NyaXQgKiBub19URUQyJHNlLmZpdCksIGx3ZCA9IDEsIGNvbCA9ICJkYXJrcmVkIikKbGluZXMoY2RhdCR0ZW1wLCBleHAobm9fVEVEMiRmaXQgLSB0X2NyaXQgKiBub19URUQyJHNlLmZpdCksIGx3ZCA9IDEsIGNvbCA9ICJkYXJrcmVkIikKdGV4dCg3LCAzMCwgIncvbyBURUQiLCBwb3MgPSA0LCBjb2wgPSAiZGFya3JlZCIpCmBgYAoKCiMjIFF1YXNpLVBvaXNzb24gbW9kZWxzCgpXZSBzYXcgd2l0aCB0aGUgY2FzZSBvZiBvdmVyZGlzcGVyc2VkIGJpbm9taWFsIG1vZGVscyB0aGF0IHdlIGNvdWxkIHVzZSBhICAqcXVhc2ktbGlrZWxpaG9vZCogdG8gZXN0aW1hdGUgdGhlIHBhcmFtZXRlcnMuIFRvIGZpdCB0aGVzZSBtb2RlbHMsIHdlIHVzZSBgZmFtaWx5ID0gcXVhc2lwb2lzc29uKGxpbmsgPSAibG9nIilgIGluIG91ciBjYWxsIHRvIGBnbG0oKWAuIEhlcmUgYXJlIHRoZSBxdWFzaS1saWtlbGlob29kIGZpdHMgY29tcGFyZWQgdG8gdGhlIG92ZXJkaXNwZXJzZWQgUG9pc3Nvbi4KCmBgYHtyIHRlZF9tb2RlbF9xdWFzaX0KIyMgUG9pc3NvbiByZWdyZXNzaW9uCnRlZF9tb2RfcSA8LSBnbG0oYnljYXRjaCB+IFRFRCArIHRlbXAsIGRhdGEgPSB0dXJ0bGVzLAogICAgICAgICAgICAgICAgIGZhbWlseSA9IHF1YXNpcG9pc3NvbihsaW5rID0gImxvZyIpKQojIyBxdWFzaS1Qb2lzc29uCnNpZ25pZihzdW1tYXJ5KHRlZF9tb2RfcSkkY29lZmZpY2llbnRzLCAzKQojIyBvdmVyZGlzcGVyc2VkIFBvaXNzb24Kc2lnbmlmKHN1bW1hcnkodGVkX21vZCwgZGlzcGVyc2lvbiA9IGNfaGF0X3RlZCkkY29lZmZpY2llbnRzLCAzKQpgYGAKClRoZXNlIGVzdGltYXRlcyBpbmRlZWQgdmVyeSBjbG9zZSB0byBvbmUgYW5vdGhlci4KCiMjIyBRdWFzaS1BSUMKCkp1c3QgYXMgd2UgZGlkIGZvciBiaW5vbWlhbCBtb2RlbHMsIHdlIGNhbiB1c2UgYSAqcXVhc2kqLUFJQyB0byBjb21wYXJlIG1vZGVscywgd2hlcmUKCiQkClFBSUMgPSAyIGsgLSAyIFxmcmFje1xsb2cgXG1hdGhjYWx7TH19e1xoYXR7Y319CiQkCgpIZXJlJ3MgYSBjb21wYXJpc29uIG9mIHNldmVyYWwgcG9zc2libGUgbW9kZWxzIGZvciB0dXJ0bGUgYnljYXRjaC4KCmBgYHtyIHFhaWN9CiMjIGZpdCByZWR1Y2VkIG1vZGVscwp0ZWRfdGVkIDwtIGdsbShieWNhdGNoIH4gVEVELCBkYXRhID0gdHVydGxlcywKICAgICAgICAgICAgICAgZmFtaWx5ID0gcG9pc3NvbihsaW5rID0gImxvZyIpKQp0ZWRfdGVtcCA8LSBnbG0oYnljYXRjaCB+IHRlbXAsIGRhdGEgPSB0dXJ0bGVzLAogICAgICAgICAgICAgICAgZmFtaWx5ID0gcG9pc3NvbihsaW5rID0gImxvZyIpKQojIyBmaXQgbnVsbCBtb2RlbAp0ZWRfbnVsbCA8LSBnbG0oYnljYXRjaCB+IDEsIGRhdGEgPSB0dXJ0bGVzLAogICAgICAgICAgICAgICAgZmFtaWx5ID0gcG9pc3NvbihsaW5rID0gImxvZyIpKQojIyBnZXQgY19oYXQncwpjX2hhdHMgPC0gYyhjX2hhdChieWNhdGNoLCB0ZWRfbW9kKSwKICAgICAgICAgICAgY19oYXQoYnljYXRjaCwgdGVkX3RlZCksCiAgICAgICAgICAgIGNfaGF0KGJ5Y2F0Y2gsIHRlZF90ZW1wKSwKICAgICAgICAgICAgY19oYXQoYnljYXRjaCwgdGVkX251bGwpKQoKIyMgbW9kZWwgc2VsZWN0aW9uIHJlc3VsdHMKIyMgbmVnIGxvZy1saWtlbGlob29kcwp0YmxfbW9kcyA8LSAtYyhsb2dMaWsodGVkX21vZCksIGxvZ0xpayh0ZWRfdGVkKSwKICAgICAgICAgICAgICAgbG9nTGlrKHRlZF90ZW1wKSwgbG9nTGlrKHRlZF9udWxsKSkKIyMgayAmIEFJQwp0YmxfbW9kcyA8LSBjYmluZCh0YmxfbW9kcywgQUlDKHRlZF9tb2QsIHRlZF90ZWQsIHRlZF90ZW1wLCB0ZWRfbnVsbCkpCiMjIGRlbHRhLUFJQwp0YmxfbW9kcyA8LSBjYmluZCh0YmxfbW9kcywgdGJsX21vZHNbLDNdIC0gbWluKHRibF9tb2RzWywzXSkpCiMjIFFBSUMKdGJsX21vZHMgPC0gY2JpbmQodGJsX21vZHMsIDIgKiB0YmxfbW9kc1ssMV0gKyAyICogdGJsX21vZHNbLDJdIC8gY19oYXRzKQojIyBkZWx0YS1RQUlDCnRibF9tb2RzIDwtIGNiaW5kKHRibF9tb2RzLCB0YmxfbW9kc1ssNV0gLSBtaW4odGJsX21vZHNbLDVdKSkKIyMgbGFiZWwgdGFibGUKcm93bmFtZXModGJsX21vZHMpIDwtIGMoIkIwICsgVEVEICsgdGVtcCAgIiwgIkIwICsgVEVEICAiLAogICAgICAgICAgICAgICAgICAgICAgICAiQjAgKyB0ZW1wICAiLCAiQjAgb25seSAgIikKY29sbmFtZXModGJsX21vZHMpIDwtIGMoIm5lZy1MTCIsICJrIiwgIkFJQyIsICJkZWx0YUFJQyIsICJRQUlDIiwgImRlbHRhUUFJQyIpCnJvdW5kKHRibF9tb2RzLCAxKQpgYGAKCgojIyBOZWdhdGl2ZSBiaW5vbWlhbCBkaXN0cmlidXRpb24KCldlIGhhdmUgc2VlbiBzZXZlcmFsIGV4YW1wbGVzIGluIGxlY3R1cmUgd2hlcmUgd2UgY2FuIHVzZSB0aGUgbmVnYXRpdmUgYmlub21pYWwgZGlzdHJpYnV0aW9uIHRvIG1vZGVsIG92ZXJkaXNwZXJzZWQgZGF0YSBiZWNhdXNlIGl0IGhhcyBhbiBhZGRpdGlvbmFsIHBhcmFtZXRlciBmb3IgdGhlIHNwcmVhZC4gSGVyZSBpcyB0aGUgZGVzY3JpcHRpb24gb2YgYSBHTE0gZm9yIGJ5Y2F0Y2ggb2YgdHVydGxlcyAkeV9pJCBhcyBhIGZ1bmN0aW9uIG9mIFRFRCBwcmVzZW5jZS9hYnNlbmNlICRUX2kkIGFuZCB3YXRlciB0ZW1wZXJhdHVyZSAkV19pJAoKJCQKXGJlZ2lue2FsaWduZWR9Clx0ZXh0e2RhdGEgZGlzdHJpYnV0aW9uOn0gJiB+fiB5X2kgXHNpbSBcdGV4dHtuZWdCaW59KHIsIFxtdV9pKSBcXCBcXApcdGV4dHtsaW5rIGZ1bmN0aW9uOn0gJiB+fiBcdGV4dHtsb2d9KFxtdV9pKSA9IFxldGFfaSBcXCBcXApcdGV4dHtsaW5lYXIgcHJlZGljdG9yOn0gJiB+fiBcZXRhX2kgPSBcYWxwaGEgKyBcYmV0YV8xIFRfaSArIFxiZXRhXzIgV19pClxlbmR7YWxpZ25lZH0KJCQKCjxicj4KCldlIGNhbiBtb2RlbCBvdXIgYnljYXRjaCBkYXRhIHdpdGggYSBuZWdhdGl2ZSBiaW5vbWlhbCB1c2luZyBgZ2xtLm5iKClgIGZyb20gdGhlICoqTUFTUyoqIHBhY2thZ2UuCgpgYGB7ciB0ZWRfbW9kZWxfbmJ9CiMjIGxvYWQgTUFTUwpsaWJyYXJ5KE1BU1MpCiMjIG5lZ2F0aXZlIGJpbm9taWFsIHJlZ3Jlc3Npb24KdGVkX21vZF9uYiA8LSBnbG0ubmIoYnljYXRjaCB+IFRFRCArIHRlbXAsIGRhdGEgPSB0dXJ0bGVzLAogICAgICAgICAgICAgICAgICAgICBsaW5rID0gImxvZyIpCmBgYAoKTGV0J3MgY29tcGFyZSB0aGVzZSBlc3RpbWF0ZXMgdG8gdGhvc2UgZm9yIHRoZSBvdmVyZGlzcGVyc2VkIGFuZCBxdWFzaS1saWtlbGlob29kIG1vZGVscy4KCmBgYHtyIHRlZF9tb2RlbF9uYl9jb21wYXJlfQojIyBvdmVyZGlzcGVyc2VkIFBvaXNzb24Kc2lnbmlmKHN1bW1hcnkodGVkX21vZCwgZGlzcGVyc2lvbiA9IGNfaGF0X3RlZCkkY29lZmZpY2llbnRzLCAzKQojIyBxdWFzaS1Qb2lzc29uCnNpZ25pZihzdW1tYXJ5KHRlZF9tb2RfcSkkY29lZmZpY2llbnRzLCAzKQojIyBuZWdhdGl2ZSBiaW5vbWlhbApzaWduaWYoc3VtbWFyeSh0ZWRfbW9kX25iKSRjb2VmZmljaWVudHMsIDMpCmBgYAoKVGhlIG1vZGVsIGVzdGltYXRlcyBmcm9tIHRoZSBuZWdhdGl2ZSBiaW5vbWlhbCBtb2RlbCBhcmUgcmF0aGVyIHNpbWlsYXIgdG8gdGhvc2UgZnJvbSB0aGUgb3RoZXIgbWV0aG9kcy4KCioqKgoKIyBaZXJvLXRydW5jYXRlZCBjb3VudHMKCkFsdGhvdWdoIHNvbWV3aGF0IHJhcmUgaW4gZWNvbG9naWNhbCBzdHVkaWVzLCB3ZSBzYXcgc29tZSBleGFtcGxlcyBpbiBsZWN0dXJlIG9mIHNvLWNhbGxlZCAiemVyby10cnVuY2F0ZWQgZGF0YSIgKGUuZy4sIHRoZSB0aW1lIGEgd2hhbGUgaXMgYXQgdGhlIHN1cmZhY2UgYmVmb3JlIGRpdmluZywgaGVyZCBzaXplIGluIGVsaywgbnVtYmVyIG9mIGZpbiByYXlzIG9uIGEgZmlzaCkuIFdlIGFsc28gc2F3IHRoYXQgdGhlIGRhdGEgdGhlbXNlbHZlcyBhcmUgbm90IGEgcHJvYmxlbSwgYnV0IHJhdGhlciBhbiB1bmRlcmx5aW5nIGFzc3VtcHRpb24gb2YgYSBQb2lzc29uIG9yIG5lZ2F0aXZlIGJpbm9taWFsIGRpc3RyaWJ1dGlvbiBtYXkgYmUgdGhlIHByb2JsZW0uCgojIyBQb2lzc29uIGZvciB6ZXJvLXRydW5jYXRlZCBkYXRhCgpUaGUgcHJvYmFiaWxpdHkgdGhhdCAkeV9pID0gMCQgaXMKCiQkCmYoeV9pOyBcbGFtYmRhX2kpID0gXGZyYWN7XGV4cCAoXHRleHR7LX0gXGxhbWJkYV9pKSBcbGFtYmRhX3tpfV57eV9pfX17eV9pIX0gXFwKXERvd25hcnJvdyBcXApcYmVnaW57YWxpZ259CmYoeV9pID0gMDsgXGxhbWJkYV9pKSAmPSBcZnJhY3tcZXhwIChcdGV4dHstfSBcbGFtYmRhX2kpIFxsYW1iZGFfe2l9XjB9ezAhfSBcXAogICY9IFxleHAgKFx0ZXh0ey19IFxsYW1iZGFfaSkKXGVuZHthbGlnbn0KJCQKCmFuZCB0aGVyZWZvcmUgdGhlIHByb2JhYmlsaXR5IHRoYXQgJHlfaSBcbmVxIDAkIGlzCgokJApmKHlfaSBcbmVxIDA7IFxsYW1iZGFfaSkgPSAxIC0gXGV4cCAoXHRleHR7LX0gXGxhbWJkYV9pKQokJAoKV2UgY2FuIG5vdyBleGNsdWRlIHRoZSBwcm9iYWJpbGl0eSB0aGF0ICR5X2kgPSAwJCBieSBkaXZpZGluZyB0aGUgcG1mIGJ5IHRoZSBwcm9iYWJpbGl0eSB0aGF0ICR5X2kgXG5lcSAwJAoKJCQKZih5X2k7IFxsYW1iZGFfaSkgPSBcZnJhY3tcZXhwIChcdGV4dHstfSBcbGFtYmRhX2kpIFxsYW1iZGFfe2l9Xnt5X2l9fXt5X2khfSBcXApcRG93bmFycm93IFxcCmZeKyh5X2k7IFxsYW1iZGFfaSB8IHlfaSA+IDApID0gXGZyYWN7XGV4cCAoXHRleHR7LX0gXGxhbWJkYV9pKSBcbGFtYmRhX3tpfV57eV9pfX17eV9pIX0gXGNkb3QgXGZyYWN7MX17MSAtIFxleHAgKFx0ZXh0ey19IFxsYW1iZGFfaSl9IFxcClxEb3duYXJyb3cgXFwKXGxvZyBcbWF0aGNhbHtMfSA9IFxsZWZ0KCB5X2kgXGxvZyBcbGFtYmRhX2kgLSBcbGFtYmRhX2kgXHJpZ2h0KSAtIFxsZWZ0KCAxIC0gXGV4cCAoXHRleHR7LX0gXGxhbWJkYV9pKSBccmlnaHQpCiQkCgoKIyMgUm9hZC1raWxsZWQgc25ha2VzCgpMZXQncyByZXZpc2l0IHRoZSBkYXRhIHByZXNlbnRlZCBpbiBadXVyIGV0IGFsLiAoMjAwOSkgb24gdGhlIG51bWJlciBvZiBkYXlzIHRoYXQgY2FyY2Fzc2VzIGZyb20gcm9hZC1raWxsZWQgc25ha2VzIHN0YXkgb24gcm9hZHMuIFRoZSBwcmVkaWN0b3JzIGFyZSB0aGUgdG90YWwgcmFpbmZhbGwgKG1tKSBhbmQgYW4gaW5kaWNhdG9yIG9mIHdoZXRoZXIgdGhlIHNuYWtlIHdhcyBraWxsZWQgaW4gdGhlIGRyaXZpbmcgbGFuZSBvciB0aGUgc2hvdWxkZXIgKG9yICJ2ZXJ2ZSIgYXMgaXQgaXMgc29tZXRpbWVzIGNhbGxlZCkuIExldCdzIGJlZ2luIGJ5IGxvYWRpbmcgYW5kIHBsb3R0aW5nIHRoZSBkYXRhLgoKYGBge3Igc25ha2VfZGF0YSwgZmlnLmhlaWdodD00LjUsIGZpZy53aWR0aD02LCBmaWcuYWxpZ249J2NlbnRlcid9CiMjIHJlYWQgZGF0YQpzbmFrZXMgPC0gcmVhZC5jc3YoInNuYWtlcy5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCgojIyBzZXQgcGxvdCBhcmVhCnBhcihtYWkgPSBjKDAuOSwgMC45LCAwLjYsIDAuMSksCiAgICBvbWkgPSBjKDAsIDAsIDAsIDApLCBiZyA9IE5BLAogICAgY2V4LmxhYiA9IDEuMykKIyMgaGlzdG9ncmFtCmhoIDwtIGhpc3Qoc25ha2VzJG5fZGF5cywgYnJlYWtzID0gc2VxKDAsIG1heChzbmFrZXMkbl9kYXlzKSksIHBsb3QgPSBGQUxTRSkKYmFycGxvdChoaCRjb3VudHMsIG5hbWVzLmFyZyA9IHNlcShtYXgoc25ha2VzJG5fZGF5cykpLCBsYXMgPSAxLAogICAgICAgIHlsYWIgPSAiQ291bnQiLCB4bGFiID0gIk51bWJlciBvZiBkYXlzIiwKICAgICAgICBjb2wgPSAiZG9kZ2VyYmx1ZSIsIGJvcmRlciA9ICJncmF5IikKYGBgCgo8YnI+CgojIyBQb2lzc29uIG1vZGVsCgpMZXQncyBmaXJzdCBjb25zaWRlciBhIHJlZ3VsYXIgUG9pc3NvbiByZWdyZXNzaW9uIG1vZGVsLCB3aGljaCBoYXMgYSBub24temVybyBsaWtlbGlob29kIG9mIHByb2R1Y2luZyB6ZXJvcy4KCmBgYHtyIHNuYWtlX3BvaXN9CiMjIFBvaXNzb24gcmVncmVzc2lvbgpzbW9kX3BvaXMgPC0gZ2xtKG5fZGF5cyB+IGxvY2F0aW9uICsgcmFpbiwgZGF0YSA9IHNuYWtlcywKICAgICAgICAgICAgICAgICBmYW1pbHkgPSBwb2lzc29uKGxpbmsgPSAibG9nIikpCiMjIG1vZGVsIHN1bW1hcnkKc3VtbWFyeShzbW9kX3BvaXMpCmBgYAoKCiMjIFplcm8tdHJ1bmNhdGVkIFBvaXNzb24KCk5vdyBsZXQncyBmaXQgYSB6ZXJvLXRydW5jYXRlZCBQb2lzc29uIHJlZ3Jlc3Npb24gbW9kZWwgd2l0aCBgdmdsbSgpYCBmcm9tICoqVkdBTSoqIGFuZCBjb21wYXJlIHRoZSByZXN1bHRzIHRvIG91ciByZWd1bGFyIFBvaXNzb24gbW9kZWwgYWJvdmUuIFRvIGRvIHNvLCB3ZSBuZWVkIHRvIHNwZWNpZnkgYGZhbWlseSA9IHBvc3BvaXNzb25gIHRvIGluZGljYXRlIHdlIHdhbnQgYSB6ZXJvLXRydW5jYXRlZCBQb2lzc29uIGRpc3RyaWJ1dGlvbi4KCmBgYHtyIHNuYWtlX3BvaXNfcG9zfQpsaWJyYXJ5KFZHQU0pCiMjIHplcm8tdHJ1bmNhdGVkIFBvaXNzb24gcmVncmVzc2lvbgpzbW9kX3p0cG9pcyA8LSB2Z2xtKG5fZGF5cyB+IGxvY2F0aW9uICsgcmFpbiwgZGF0YSA9IHNuYWtlcywKICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSBwb3Nwb2lzc29uKQoKIyMgcGFyYW1ldGVyIE1MRXMgYW5kIFNFcyBmb3IgUG9pc3NvbgpiZXRhX2hhdF9wIDwtIGNiaW5kKGNvZWYoc21vZF9wb2lzKSwgc3FydChkaWFnKHZjb3Yoc21vZF9wb2lzKSkpKQojIyBwYXJhbWV0ZXIgTUxFcyBhbmQgU0VzIGZvciBQb2lzc29uKwpiZXRhX2hhdF96dHAgPC0gY2JpbmQoY29lZihzbW9kX3p0cG9pcyksIHNxcnQoZGlhZyh2Y292KHNtb2RfenRwb2lzKSkpKQoKIyMgdGFibGUgb2YgcmVzdWx0cwp0YmxfcG9pcyA8LSByb3VuZChjYmluZChiZXRhX2hhdF9wLCBiZXRhX2hhdF96dHApLCAzKQpjb2xuYW1lcyh0YmxfcG9pcykgPC0gYygiICBQb2lzc29uIiwgIiAgUG9pc3NvbiBTRSIsICIgICtQb2lzc29uIiwgIiAgK1BvaXNzb24gU0UiKQp0YmxfcG9pcwpgYGAKCkhlcmUgd2UgY2FuIHNlZSB0aGF0IE1MRSdzIGZyb20gdGhlIHJlZ3VsYXIgUG9pc3NvbiBtb2RlbCBhcmUgYmlhc2VkIGhpZ2ggYW5kIGxvdyBmb3IgdGhlIGludGVyY2VwdCBhbmQgbG9jYXRpb24gZWZmZWN0LCByZXNwZWN0aXZlbHkuIFRoZSBTRSdzIGZvciB0aGUgUG9pc3NvbiBtb2RlbCBhcmUgYWxzbyBiaWFzZWQgbG93LgoKIyMgWmVyby10cnVuY2F0ZWQgbmVnYXRpdmUgYmlub21pYWwKCkxvb2tpbmcgYmFjayBhdCB0aGUgcmVzdWx0cyBmcm9tIHRoZSByZWd1bGFyIFBvaXNzb24gbW9kZWwsIHdlIGNhbiBhbHNvIHNlZSB0aGF0IHRoZSBtb2RlbCBkZXZpYW5jZSBzZWVtcyByYXRoZXIgaGlnaCBnaXZlbiB0aGUgZGVncmVlcyBvZiBmcmVlZG9tICgkRCQgPSBgciByb3VuZChzbW9kX3BvaXMkbnVsbC5kZXZpYW5jZSwgMSlgIHdpdGggJGRmJCA9IGByIHNtb2RfcG9pcyRkZi5udWxsYCkuIFRoaXMgc3VnZ2VzdHMgdGhhdCB3ZSBzaG91bGQgY29uc2lkZXIgYSBtb2RlbCB0aGF0IGFsbG93cyBmb3IgYWRkaXRpb25hbCB2YXJpYW5jZSBiZXlvbmQgdGhhdCBmb3IgYSBQb2lzc29uLiBUaGUgbmVnYXRpdmUgYmlub21pYWwgaXMgYW4gb2J2aW91cyBjaG9pY2UuCgpSZWNhbGwgdGhhdCBmb3IgJHlfaSBcc2ltIFx0ZXh0e25lZ0Jpbm9tfShyLCBcbXUpJCwgaXRzIHByb2JhYmlsaXR5IG1hc3MgZnVuY3Rpb24gaXMKCiQkCmYoeTsgXG11LCByKSA9IFxmcmFjeyh5K3ItMSkgIX17KHItMSkgISB5ICF9IFxsZWZ0KCBcZnJhY3tyfXtcbXUgKyByfSBccmlnaHQpXntyfVxsZWZ0KCBcZnJhY3tcbXV9e1xtdSArIHJ9IFxyaWdodClee3l9CiQkCgpUaGUgcHJvYmFiaWxpdHkgdGhhdCAkeV9pID0gMCQgaXMKCiQkCmYoeTsgciwgXG11KSA9IFxmcmFjeyh5K3ItMSkgIX17KHItMSkgISB5ICF9IFxsZWZ0KCBcZnJhY3tyfXtcbXUgKyByfSBccmlnaHQpXntyfVxsZWZ0KCBcZnJhY3tcbXV9e1xtdSArIHJ9IFxyaWdodClee3l9IFxcClxEb3duYXJyb3cgXFwKXGJlZ2lue2FsaWdufQpmKHlfaSA9IDA7IHIsIFxtdSkgJj0gXGZyYWN7KDArci0xKSAhfXsoci0xKSAhIDAgIX0gXGxlZnQoIFxmcmFje3J9e1xtdSArIHJ9IFxyaWdodClee3J9IFxsZWZ0KCBcZnJhY3tcbXV9e1xtdSArIHJ9IFxyaWdodCleezB9IFxcCiAgJj0gXGxlZnQoIFxmcmFje3J9e1xtdSArIHJ9IFxyaWdodClee3J9ClxlbmR7YWxpZ259CiQkCgphbmQgdGhlIHByb2JhYmlsaXR5IHRoYXQgJHlfaSBcbmVxIDAkIGlzIHRoZXJlZm9yZQoKJCQKZih5X2kgXG5lcSAwOyByLCBcbXVfaSkgPSAxIC0gXGxlZnQoIFxmcmFje3J9e1xtdSArIHJ9IFxyaWdodClee3J9CiQkCgpKdXN0IGFzIHdlIGRpZCBmb3IgdGhlIFBvaXNzb24gZGlzdHJpYnV0aW9uLCB3ZSBjYW4gbm93IGV4Y2x1ZGUgdGhlIHByb2JhYmlsaXR5IHRoYXQgJHlfaSA9IDAkIGJ5IGRpdmlkaW5nIHRoZSBwbWYgYnkgdGhlIHByb2JhYmlsaXR5IHRoYXQgJHlfaSBcbmVxIDAkCgokJApmKHk7IHIsIFxtdSkgPSBcZnJhY3soeStyLTEpICF9eyhyLTEpICEgeSAhfSBcbGVmdCggXGZyYWN7cn17XG11ICsgcn0gXHJpZ2h0KV57cn0gXGxlZnQoIFxmcmFje1xtdX17XG11ICsgcn0gXHJpZ2h0KV57eX0gXFwKXERvd25hcnJvdyBcXApmXisoeV9pOyBcbGFtYmRhX2kgfCB5X2kgPiAwKSA9IFxmcmFjeyBcZnJhY3soeStyLTEpICF9eyhyLTEpICEgeSAhfSBcbGVmdCggXGZyYWN7cn17XG11ICsgcn0gXHJpZ2h0KV57cn0gXGxlZnQoIFxmcmFje1xtdX17XG11ICsgcn0gXHJpZ2h0KV57eX0gfXsgMSAtIFxsZWZ0KCBcZnJhY3tyfXtcbXUgKyByfSBccmlnaHQpXntyfSB9IFxcClxEb3duYXJyb3cgXFwKXGxvZyBcbWF0aGNhbHtMfSA9IFxsb2cgXG1hdGhjYWx7TH0oXHRleHR7TkJ9KSAtIFxsb2cgXGxlZnQoIDEgLSBcbGVmdCggXGZyYWN7cn17XG11ICsgcn0gXHJpZ2h0KV57cn0gXHJpZ2h0KQokJAoKIyMgUm9hZC1raWxsZWQgc25ha2VzCgpMZXQncyBmaXJzdCBjb25zaWRlciBhIHJlZ3VsYXIgbmVnYXRpdmUgYmlub21pYWwgcmVncmVzc2lvbiBtb2RlbCB0byB3aGljaCB3ZSBjYW4gY29tcGFyZSBhIHplcm8tdHJ1bmNhdGVkIHZlcnNpb24uCgpgYGB7ciBzbmFrZV9uYn0KIyMgbG9hZCBNQVNTIHBrZwpsaWJyYXJ5KE1BU1MpCiMjIG5lZ2F0aXZlIGJpbm9taWFsIHJlZ3Jlc3Npb24Kc21vZF9uYiA8LSBnbG0ubmIobl9kYXlzIH4gbG9jYXRpb24gKyByYWluLCBkYXRhID0gc25ha2VzLAogICAgICAgICAgICAgICAgICBsaW5rID0gImxvZyIpCiMjIG1vZGVsIHN1bW1hcnkKc3VtbWFyeShzbW9kX25iKQpgYGAKClJpZ2h0IGF3YXkgd2UgY2FuIHNlZSB0aGF0IHRoZSBkZXZpYW5jZSBmb3IgdGhpcyBtb2RlbCBpcyBtdWNoIG1vcmUgaW4gbGluZSB3aXRoIG91ciBleHBlY3RhdGlvbi4gTm93IGxldCdzIGZpdCBhIHplcm8tdHJ1bmNhdGVkIG5lZ2F0aXZlIGJpbm9taWFsIHJlZ3Jlc3Npb24gbW9kZWwgd2l0aCBgdmdsbSgpYCBmcm9tICoqVkdBTSoqIGFuZCBjb21wYXJlIGl0IHRvIHRoZSByZWd1bGFyIG5lZ2F0aXZlIGJpbm9taWFsIG1vZGVsLiBIZXJlIHdlIG5lZWQgdG8gc3BlY2lmeSBgZmFtaWx5ID0gcG9zbmVnYmlub21pYWxgIHRvIHNwZWNpZnkgYSB6ZXJvLXRydW5jYXRlZCBuZWdhdGl2ZSBiaW5vbWlhbC4KCmBgYHtyIHNuYWtlX25iX3Bvc30KbGlicmFyeShWR0FNKQojIyB6ZXJvLXRydW5jYXRlZCBuZWdhdGl2ZSBiaW5vbWlhbCByZWdyZXNzaW9uCnNtb2RfenRuYiA8LSB2Z2xtKG5fZGF5cyB+IGxvY2F0aW9uICsgcmFpbiwgZGF0YSA9IHNuYWtlcywKICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gcG9zbmVnYmlub21pYWwpCgojIyBNTEVzIGFuZCBTRXMgZm9yIHJlZ3VsYXIgTkIKYmV0YV9oYXRfbmIgPC0gY2JpbmQoY29lZihzbW9kX25iKSwgc3FydChkaWFnKHZjb3Yoc21vZF9uYikpKSkKIyMgTUxFcyBhbmQgU0VzIGZvciByZWd1bGFyIE5CKwpiZXRhX2hhdF96dG5iIDwtIGNiaW5kKGNvZWYoc21vZF96dG5iKVstMl0sIHNxcnQoZGlhZyh2Y292KHNtb2RfenRuYikpWy0yXSkpCgojIyB0YWJsZSBvZiByZXN1bHRzCnRibF9uYiA8LSByb3VuZChjYmluZChiZXRhX2hhdF9uYiwgYmV0YV9oYXRfenRuYiksIDMpCmNvbG5hbWVzKHRibF9uYikgPC0gYygiICBOQiIsICIgIE5CIFNFIiwgIiAgICAgICtOQiIsICIgK05CIFNFIikKdGJsX25iCmBgYAoKVGhpcyBpcyBhIHBhcnRpY3VsYXJseSBpbXByZXNzaXZlIGV4YW1wbGUgb2YgdGhlIGJpYXNlcyBpbiBNTEUncyBhbmQgdGhlIGFzc29jaWF0ZWQgU0UncyB0aGF0IG9uZSB3b3VsZCBnZXQgYnkgZml0dGluZyB0aGUgd3JvbmcgbW9kZWwuCgoqKioKCiMgWmVyby1pbmZsYXRlZCBjb3VudHMKCkNvdW50IGRhdGEgdGhhdCBoYXZlIGFuIGV4Y2VzcyBvZiB6ZXJvcyB0ZW5kIHRvIGJlIG1vcmUgY29tbW9uIGluIGVjb2xvZ2ljYWwgc3R1ZGllcy4gVGhlc2UgKnplcm8taW5mbGF0ZWQqIGRhdGEgY29udGFpbiBtb3JlIHplcm9zIHRoYW4gd291bGQgYmUgZXhwZWN0ZWQgdW5kZXIgYSBQb2lzc29uIG9yIG5lZ2F0aXZlIGJpbm9taWFsIGRpc3RyaWJ1dGlvbi4gSW4gZ2VuZXJhbCwgdGhlcmUgYXJlIDQgZGlmZmVyZW50IHR5cGVzIG9mIGVycm9ycyB0aGF0IGNhdXNlIHplcm9zCgoxKSBTdHJ1Y3R1cmFsIChhbiBhbmltYWwgaXMgYWJzZW50IGJlY2F1c2UgdGhlIGhhYml0YXQgaXMgdW5zdWl0YWJsZSkKCjIpIERlc2lnbiAoc2FtcGxpbmcgaXMgbGltaXRlZCB0ZW1wb3JhbGx5IG9yIHNwYXRpYWxseSkKCjMpIE9ic2VydmVyIGVycm9yIChpbmV4cGVyaWVuY2Ugb3IgZGlmZmljdWx0IGNpcmN1bXN0YW5jZXMpCgo0KSBQcm9jZXNzIGVycm9yIChoYWJpdGF0IGlzIHN1aXRhYmxlIGJ1dCB1bnVzZWQpCgojIyBBcHByb2FjaGVzIHRvIHplcm8taW5mbGF0ZWQgZGF0YQoKVGhlcmUgYXJlIDIgZ2VuZXJhbCBhcHByb2FjaGVzIGZvciBkZWFsaW5nIHdpdGggemVyby1pbmZsYXRlZCBkYXRhLCB3aGljaCBkaWZmZXIgaW4gdGhlaXIgYXNzdW1wdGlvbiBhYm91dCB0aGUgdW5kZXJseWluZyBzb3VyY2VzIG9mIHRoZSBleGNlc3MgemVyb3M6CgoxKSBaZXJvLWFsdGVyZWQgKCJodXJkbGUiKSBtb2RlbHMKCjIpIFplcm8taW5mbGF0ZWQgKCJtaXh0dXJlIikgbW9kZWxzCgpaZXJvLWFsdGVyZWQgKFpBKSBtb2RlbHMgZG8gbm90IGRpc2NyaW1pbmF0ZSBhbW9uZyB0aGUgNCB0eXBlcyBvZiB6ZXJvcyBhbmQgdHJlYXQgYWxsIG9mIHRoZSBjb3VudCBkYXRhIGFzIGJlbG9uZ2luZyB0byBvbmUgb2YgdHdvIGRpc3RpbmN0IGdyb3VwczogemVyb3MgYW5kIG5vbi16ZXJvcy4gWmVyby1pbmZsYXRlZCAoWkkpIG1vZGVscyBhbHNvIHRyZWF0IHRoZSB6ZXJvcyBhcyBjb21pbmcgZnJvbSB0d28gc291cmNlcywgYnV0IHRoZXkgYXJpc2UgZWl0aGVyIHZpYSBvYnNlcnZhdGlvbiBlcnJvcnMgKG1pc3NlZCBkZXRlY3Rpb25zKSBvciBlY29sb2dpY2FsIHJlYXNvbnMgKHRoZSBwbGFudCBvciBhbmltYWwgd2FzIGFic2VudCBiZWNhdXNlIG9mIHRoZSBlbnZpcm9ubWVudCkuIFRoZSBwcmltYXJ5IGRpZmZlcmVuY2UgaXMgdGhhdCBaQSBtb2RlbHMgdHJlYXQgdGhlIG5vbi16ZXJvcyBhcyB6ZXJvLXRydW5jYXRlZCBkYXRhIHdoZXJlYXMgWkkgbW9kZWxzIHRyZWF0IHRoZSBub24temVyb3MgYW5kICpzb21lIG9mIHRoZSB6ZXJvcyogYXMgY29taW5nIGZyb20gYSByZWd1bGFyIFBvaXNzb24gb3IgbmVnYXRpdmUgYmlub21pYWwgZGlzdHJpYnV0aW9uLiBIZXJlIGlzIGEgZ3JhcGhpY2FsIGRlcGljdGlvbiBvZiB0aGUgdHdvIGNhc2VzLgoKYGBge3IgemFfemlfY29tcGFyZSwgZmlnLmhlaWdodD00LjUsIGZpZy53aWR0aD03LjUsIGZpZy5hbGlnbj0nY2VudGVyJ30KIyMgZXh0cmEgemVyb3MgKyBQb2lzc29uKDMpCnNldC5zZWVkKDUxNCkKYWxsIDwtIGMocmVwKDAsIDUwKSwgcnBvaXMoMzAwLCAzKSkKIyMgWkFQCmlkeF96YXAgPC0gaWZlbHNlKGFsbCA+IDAsIDAsIDEpCmFsbF96YXAgPC0gdGFibGUoYWxsLCBpZHhfemFwKQojIyBaSVAKaWR4X3ppcCA8LSBjKHJlcCgxLCA1MCksIHJlcCgwLCAzMDApKQphbGxfemlwIDwtIHRhYmxlKGFsbCwgaWR4X3ppcCkKCiMjIHNldCBwbG90IGFyZWEKcGFyKG1mcm93ID0gYygxLCAyKSwKICAgIG1haSA9IGMoMC45LCAwLjksIDAuNiwgMC4xKSwKICAgIG9taSA9IGMoMCwgMCwgMCwgMCksIGJnID0gTkEsCiAgICBjZXgubWFpbiA9IDEuMiwgY2V4LmxhYiA9IDEuMikKCiMjIGJhciBjaGFydHMgb2YgdGhlIGRhdGEKYmFycGxvdCh0KGFsbF96YXApLCBsYXMgPSAxLCBjb2w9YygiZG9kZ2VyYmx1ZSIsImluZGlhbnJlZCIpLCBib3JkZXIgPSJncmF5IiwKICAgICAgICB4bGFiID0gIkNvdW50IiwgbWFpbiA9ICJaZXJvIGFsdGVyZWQgKGh1cmRsZSkiKQpiYXJwbG90KHQoYWxsX3ppcCksIGxhcyA9IDEsIGNvbD1jKCJkb2RnZXJibHVlIiwiaW5kaWFucmVkIiksIGJvcmRlciA9ImdyYXkiLAogICAgICAgIHhsYWIgPSAiQ291bnQiLCBtYWluID0gIlplcm8gaW5mbGF0ZWQgKG1peHR1cmUpIikKYGBgCgo8YnI+CgojIyBaZXJvLWFsdGVyZWQgUG9pc3NvbgoKWmVyby1hbHRlcmVkIG1vZGVscyBjb25zaXN0IG9mIDIgcGFydHM6CgoxKSBhIGJpbm9taWFsIG1vZGVsIHRvIGRldGVybWluZSB0aGUgcHJvYmFiaWxpdHkgb2YgYSB6ZXJvCgoyKSBhIHRydW5jYXRlZCBQb2lzc29uIG9yIG5lZ2F0aXZlIGJpbm9taWFsIHRvIG1vZGVsIHRoZSBwb3NpdGl2ZSBjb3VudHMKCkhlcmUgd2UnbGwgY29uc2lkZXIgYSB6ZXJvLWFsdGVyZWQgUG9pc3NvbiAoWkFQKSBtb2RlbCwgd2hpY2ggaXMgZ2l2ZW4gYnkKCiQkCmZfe1x0ZXh0e1pBUH19KHk7IFxwaSwgXGxhbWJkYSkgPSAKXGxlZnRcewpcYmVnaW57YXJyYXl9e2xjfQpmX3tcdGV4dHtiaW5vbWlhbH19KHkgPSAwOyBccGkpIFxcClxsZWZ0WzEgLSBmX3tcdGV4dHtiaW5vbWlhbH19KHkgPSAwOyBccGkpIFxyaWdodF0gXHRpbWVzIFxsZWZ0KCBcZnJhY3tmX3tcdGV4dHtQb2lzc29ufX0oeSA9IDA7IFxsYW1iZGEpfXsxIC0gZl97XHRleHR7UG9pc3Nvbn19KHkgPSAwOyBcbGFtYmRhKX0gXHJpZ2h0KSAKXGVuZHthcnJheX0KXHJpZ2h0LgokJAoKd2hlcmUgJFxwaSQgaXMgdGhlIHByb2JhYmlsaXR5IG9mIGZpbmRpbmcgKmFueSogaW5kaXZpZHVhbHMsIGFuZCAkXGxhbWJkYSQgaXMgdGhlIG1lYW4gKGFuZCB2YXJpYW5jZSkgb2YgdGhlICpwb3NpdGl2ZSBjb3VudHMqLgoKV2UgY2FuIG1vZGVsIGJvdGggcGFyYW1ldGVycyBhcyBmdW5jdGlvbnMgb2YgY292YXJpYXRlcywgc3VjaCB0aGF0IHRoZSBsb2dpdC10cmFuc2Zvcm1lZCBwcm9iYWJpbGl0eSBvZiBkZXRlY3Rpb24gaXMgZ2l2ZW4gYnkKCiQkClx0ZXh0e2xvZ2l0fShccGkpID0gXG1hdGhiZntYfV9kIFxib2xkc3ltYm9se1xiZXRhfV9kCiQkCgphbmQgdGhlIGxvZy10cmFuc2Zvcm1lZCBtZWFuIGFuZCB2YXJpYW5jZSBvZiB0aGUgcG9zaXRpdmUgY291bnRzIGlzIGdpdmVuIGJ5CgokJApcbG9nKFxsYW1iZGEpID0gXG1hdGhiZntYfV9jIFxib2xkc3ltYm9se1xiZXRhfV9jCiQkCgojIyBDb3VudHMgb2YgaGlwcG9zCgpMZXQncyBhcHBseSBhIFpBUCBtb2RlbCB0byBvdXIgZmljdGl0aW91cyBzdXJ2ZXkgZGF0YSBmb3IgaGlwcG9zLCB3aGVyZSB3ZSBhc3N1bWUgdGhlIGZvbGxvd2luZyB0aGUgcHJvYmFiaWxpdHkgb2YgZmluZGluZyBoaXBwb3MgaW5jcmVhc2VzIHdpdGggd2F0ZXIgYXZhaWxhYmlsaXR5IGFuZCB0aGUgbnVtYmVyIG9mIGhpcHBvcyBpbmNyZWFzZXMgd2l0aCB0cmVlIGRlbnNpdHkuIFdlJ2xsIG1vZGVsIGRldGVjdGlvbiBhcyBhIGZ1bmN0aW9uIG9mIHdhdGVyIGF2YWlsYWJpbGl0eSAkVyQsIHN1Y2ggdGhhdAoKJCQKel9pIFxzaW0gXHRleHR7QmVybm91bGxpfShccGlfaSkgXFwKXHRleHR7bG9naXR9KFxwaSkgPSBcZ2FtbWFfMCArIFxnYW1tYV8xIFdfaQokJAoKYW5kIHRoZSBwb3NpdGl2ZSBjb3VudHMgYXMgYSBmdW5jdGlvbiBvZiB0cmVlIGRlbnNpdHkgJFQkLCBzdWNoIHRoYXQKCiQkCmNfaSBcc2ltIFx0ZXh0e1BvaXNzb259XisoXGxhbWJkYV9pKSBcXApcbG9nKFxsYW1iZGEpID0gXGJldGFfMCArIFxiZXRhXzEgVF9pCiQkCgpUb3RhbCBjb3VudHMgYXJlIHRoZW4gYSBmdW5jdGlvbiBvZiB0aGUgbm9uLXplcm8gZGV0ZWN0aW9ucyBhbmQgdGhlIHBvc2l0aXZlIGNvdW50cwoKJCQKeV9pID0gel9pIGNfaQokJAoKSGVyZSdzIGhvdyB3ZSBzaW11bGF0ZSB0aGUgemVyby1pbmZsYXRlZCBkYXRhLgoKYGBge3IgaGlwcG9fZGF0YX0KIyMgZnVuY3Rpb24gdG8gZ2VuZXJhdGUgcG9zaXRpdmUgUG9pc3NvbiB2YWx1ZXMKcnRwb2lzIDwtIGZ1bmN0aW9uKG4sIGwpIHsKICBxcG9pcyhydW5pZihuLCBkcG9pcygwLCBsKSwgMSksIGwpIAp9CgpzZXQuc2VlZCg1MTQpCiMjIHNhbXBsZSBzaXplCm5uIDwtIDIwMAojIyBwYXJhbWV0ZXJzIGZvciBkZXRlY3Rpb24gbW9kZWwKZ2FtbWFfMCA8LSAtMgpnYW1tYV90cmVlIDwtIDMKIyMgcGFyYW1ldGVycyBmb3IgY291bnQgbW9kZWwKYmV0YV8wIDwtIDIKYmV0YV90cmVlIDwtIDAuOAojIyBjb3ZhcmlhdGVzCndhdGVyIDwtIHJ1bmlmKG5uLCAwLCAxKQp0cmVlcyA8LSBydW5pZihubiwgMCwgMSkKIyMgZXhwZWN0YXRpb24gZm9yIFByKGRldGVjdCkKbXUgPC0gMS8oMStleHAoLShnYW1tYV8wICsgZ2FtbWFfdHJlZSAqIHdhdGVyKSkpCiMjIGRldGVjdGlvbnMgKDAvMSkKeiA8LSByYmlub20obm4sIDEsIG11KQojIyBleHBlY3RhdGlvbiBmb3IgcG9zIGNvdW50cwpsYW1iZGEgPC0gZXhwKGJldGFfMCArIGJldGFfdHJlZSAqIHRyZWVzKSAKIyMgcG9zIGNvdW50cwpwb3NfY291bnQgPC0gcnRwb2lzKG5uLCBsYW1iZGEpCiMjIG9ic2VydmF0aW9ucwp5IDwtIHogKiBwb3NfY291bnQKYGBgCgpIZXJlIGlzIGEgcGxvdCBvZiB0aGUgc2ltdWxhdGVkIGhpcHBvIGNvdW50cy4KCmBgYHtyIHBsb3RfaGlwcG9fZGF0YSwgZmlnLmhlaWdodD00LjUsIGZpZy53aWR0aD02LCBmaWcuYWxpZ249J2NlbnRlcid9CiMjIHNldCBwbG90IGFyZWEKcGFyKG1haSA9IGMoMC45LCAwLjksIDAuMSwgMC4xKSwKICAgIG9taSA9IGMoMCwgMCwgMCwgMCksIGJnID0gTkEsCiAgICBjZXgubWFpbiA9IDEuMiwgY2V4LmxhYiA9IDEuMikKCiMjIGhpc3RvZ3JhbSBvZiBjb3VudHMKaGlzdCh5LCBicmVha3MgPSBzZXEoMCwgbWF4KHkpKSwgbGFzID0gMSwgY29sID0gImRvZGdlcmJsdWUiLCBib3JkZXIgPSAiZ3JheSIsCiAgICAgbWFpbiA9ICIiLCB4bGFiID0gIk51bWJlciBvZiBoaXBwb3MiLCB5bGFiID0gIkZyZXF1ZW5jeSIsICkKYGBgCgojIyBaQVAgbW9kZWwgZm9yIGhpcHBvcwoKV2UgY2FuIGZpdCBaQVAgbW9kZWxzIGluIFIgd2l0aCBgaHVyZGxlKClgIGZyb20gdGhlICoqcHNjbCoqIHBhY2thZ2UuIE5vdGUgdGhhdCB0aGUgZm9ybXVsYSBmb3IgWkFQIG1vZGVscyBpcyBzcGVjaWZpZWQgYXMgYHkgfiBwcmVkaWN0b3JzX29mX2NvdW50cyB8IHByZWRpY3RvcnNfZm9yX2RldGVjdGlvbmAuCgpgYGB7ciBoaXBwb196YXAsIGVjaG8gPSBUUlVFfQojIyBsb2FkIHBzY2wKbGlicmFyeShwc2NsKQojIyBmaXQgaHVyZGxlIG1vZGVsCmhpcHBvX3phcCA8LSBodXJkbGUoeSB+IHRyZWVzIHwgd2F0ZXIpCiMjIG1vZGVsIHN1bW1hcnkKc3VtbWFyeShoaXBwb196YXApCmBgYAoKVGhlIG1vZGVsIHN1bW1hcnkgZ2l2ZXMgdXMgdGhlIHBhcmFtZXRlciBlc3RpbWF0ZXMgZm9yIGJvdGggdGhlIGRldGVjdGlvbiBtb2RlbCBhbmQgdGhlIGNvdW50IG1vZGVsLiBUaGUgcGFyYW1ldGVyIGVzdGltYXRlcyBhcmUgcHJldHR5IGNsb3NlIHRvIHRoZSB0cnVlIHZhbHVlcyBhYm92ZSwgYnV0IHRoZSBzbG9wZSBmb3IgdGhlIGVmZmVjdCBvZiB3YXRlciBhdmFpbGFiaWxpdHkgaXMgYSBiaXQgbG93LgoKV2UgY2FuIHBsb3QgdGhlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB3YXRlciBhdmFpbGFiaWxpdHkgYW5kIHRoZSBwcm9iYWJpbGl0eSBvZiBkZXRlY3Rpb24sIGFuZCB0aGUgZXN0aW1hdGVkIGNvdW50IGFzIGEgZnVuY3Rpb24gb2Ygb3VyIGluZGV4IG9mIHRyZWUgZGVuc2l0eS4KCmBgYHtyIGhpcHBvX3phcF9maXR0ZWQsIGZpZy5oZWlnaHQ9NC41LCBmaWcud2lkdGg9Ny41LCBmaWcuYWxpZ249J2NlbnRlcid9CiMjIGZpdHRlZCBmb3IgZGV0ZWN0aW9uIHByb2IgKHBpKQp3YXRlciA8LSBzb3J0KHdhdGVyKQpnYW1tYV9oYXRfMCA8LSBjb2VmKGhpcHBvX3phcClbM10KZ2FtbWFfaGF0XzEgPC0gY29lZihoaXBwb196YXApWzRdCnBpX2hhdCA8LSAxLygxK2V4cCgtKGdhbW1hX2hhdF8wICsgZ2FtbWFfaGF0XzEqd2F0ZXIpKSkKCiMjIG1hdHJpeCBvZiBkZXJpdmF0aXZlcyBmb3IgU0UncwpkZXJpdnMgPC0gbWF0cml4KE5BLG5yb3c9bm4sbmNvbD00KQpkZXJpdnNbLDFdIDwtIGRlcml2c1ssMl0gPC0gMApkZXJpdnNbLDNdIDwtIChleHAoZ2FtbWFfaGF0XzAgKyBnYW1tYV9oYXRfMSp3YXRlcikpIC8gKChleHAoZ2FtbWFfaGF0XzAgKyBnYW1tYV9oYXRfMSp3YXRlcikrMSleMikKZGVyaXZzWyw0XSA8LSAod2F0ZXIgKiBleHAoZ2FtbWFfaGF0XzAgKyBnYW1tYV9oYXRfMSp3YXRlcikpIC8gKChleHAoZ2FtbWFfaGF0XzAgKyBnYW1tYV9oYXRfMSp3YXRlcikrMSleMikgCnNlIDwtIHNxcnQoIGRpYWcgKCBkZXJpdnMgJSolIHZjb3YoaGlwcG9femFwKSAlKiUgdChkZXJpdnMpICkpCmxvd2VyIDwtIHBpX2hhdCAtIHNlICogcXQoMC4wMjUsIG5uLTIsIGxvd2VyLnRhaWwgPSBGQUxTRSkKdXBwZXIgPC0gcGlfaGF0ICsgc2UgKiBxdCgwLjAyNSwgbm4tMiwgbG93ZXIudGFpbCA9IEZBTFNFKQoKIyMgZml0dGVkIGZvciBtZWFuICYgdmFyIChsYW1iZGEpCnRyZWVzIDwtIHNvcnQodHJlZXMpCmJldGFfaGF0XzAgPC0gY29lZihoaXBwb196YXApWzFdCmJldGFfaGF0XzEgPC0gY29lZihoaXBwb196YXApWzJdCmxhbWJkYV9oYXQgPC0gZXhwKGJldGFfaGF0XzAgKyBiZXRhX2hhdF8xKnRyZWVzKQoKIyMgbWF0cml4IG9mIGRlcml2YXRpdmVzIGZvciBTRSdzCmRlcml2c18yIDwtIG1hdHJpeChOQSxucm93PW5uLG5jb2w9NCkKZGVyaXZzXzJbLDFdIDwtIGV4cChiZXRhX2hhdF8wK2JldGFfaGF0XzEqdHJlZXMpCmRlcml2c18yWywyXSA8LSB0cmVlcypleHAoYmV0YV9oYXRfMCtiZXRhX2hhdF8xKnRyZWVzKSAKZGVyaXZzXzJbLDNdIDwtIGRlcml2c18yWyw0XSA8LSAwCnNlXzIgPC0gc3FydCggZGlhZyAoIGRlcml2c18yICUqJSB2Y292KGhpcHBvX3phcCkgJSolIHQoZGVyaXZzXzIpICkpCmxvd2VyXzIgPC0gbGFtYmRhX2hhdCAtIHNlXzIgKiBxdCgwLjAyNSwgbm4tMiwgbG93ZXIudGFpbCA9IEZBTFNFKQp1cHBlcl8yIDwtIGxhbWJkYV9oYXQgKyBzZV8yICogcXQoMC4wMjUsIG5uLTIsIGxvd2VyLnRhaWwgPSBGQUxTRSkKCiMjIHNldCBwbG90IGFyZWEKcGFyKG1mcm93ID0gYygxLCAyKSwKICAgIG1haSA9IGMoMC45LCAwLjksIDAuNiwgMC4xKSwKICAgIG9taSA9IGMoMCwgMCwgMCwgMCksIGJnID0gTkEsCiAgICBjZXgubWFpbiA9IDEuMiwgY2V4LmxhYiA9IDEuMikKIyMgZGV0ZWN0aW9ucwpwbG90KHdhdGVyLCBwaV9oYXQsIHR5cGUgPSAibCIsIGxhcyA9IDEsIHlsaW0gPSBjKDAsIDEpLCBsd2QgPSAyLCBjb2wgPSAiZG9kZ2VyYmx1ZSIsCiAgICAgeGxhYiA9ICJXYXRlciBhdmFpbGFiaWxpdHkiLCB5bGFiID0gZXhwcmVzc2lvbihwaSksIG1haW4gPSAiRGV0ZWN0aW9uIikKbGluZXMod2F0ZXIsIGxvd2VyLCBsdHkgPSAyLCAgY29sID0gImRvZGdlcmJsdWUiLCBsd2QgPSAyKQpsaW5lcyh3YXRlciwgdXBwZXIsIGx0eSA9IDIsICBjb2wgPSAiZG9kZ2VyYmx1ZSIsIGx3ZCA9IDIpCiMjIGNvdW50cwpwbG90KHRyZWVzLCBsYW1iZGFfaGF0LCB0eXBlID0gImwiLCBsYXMgPSAxLCB5bGltID0gYygwLCAyMCksIGx3ZCA9IDIsIGNvbCA9ICJkYXJrZ3JlZW4iLAogICAgIHhsYWIgPSAiVHJlZSBkZW5zaXR5IiwgeWxhYiA9IGV4cHJlc3Npb24obGFtYmRhKSwgbWFpbiA9ICJDb3VudHMiKQpsaW5lcyh0cmVlcywgbG93ZXJfMiwgbHR5ID0gMiwgY29sID0gImRhcmtncmVlbiIsIGx3ZCA9IDIpCmxpbmVzKHRyZWVzLCB1cHBlcl8yLCBsdHkgPSAyLCBjb2wgPSAiZGFya2dyZWVuIiwgbHdkID0gMikKCmBgYAoKIyMgWmVyby1pbmZsYXRlZCBQb2lzc29uCgpaZXJvLWluZmxhdGVkIFBvaXNzb24gKFpJUCkgbW9kZWxzIGNvbnNpc3Qgb2YgMiBwYXJ0cwoKMSkgYSBiaW5vbWlhbCBtb2RlbCB0byBkZXRlcm1pbmUgdGhlIHByb2JhYmlsaXR5IG9mIGEgemVybwoKMikgYSBQb2lzc29uIG1vZGVsIGZvciBjb3VudHMsIHdoaWNoIGNhbiBpbmNsdWRlIHplcm9zCgpSZWNhbGwgdGhhdCB0aGUgcHJvYmFiaWxpdHkgb2YgYSB6ZXJvIGNvdW50IGNvbWVzIGZyb20gMiBzb3VyY2VzOgoKMSkgZmFsc2UgemVyb3MgKG1pc3NlZCBkZXRlY3Rpb25zKQoKMikgdHJ1ZSB6ZXJvcyAoZWNvbG9naWNhbCByZWFzb25zKQoKd2hpY2ggbWVhbnMKClByKHplcm8pID0gUHIoZmFsc2UgemVybykgKyBQcih0cnVlIHplcm8pICRcdGltZXMkIFByKGNvdW50ID0gMCkKClRodXMsIGEgemVyby1pbmZsYXRlZCBQb2lzc29uIChaSVApIG1vZGVsIGlzIGdpdmVuIGJ5CgokJApcYmVnaW57YWxpZ259CmZfe1x0ZXh0e1pJUH19KHkgPSAwKSAmPSBmX3tcdGV4dHtCaW5vbWlhbH19KFxwaSkgKyBbMSAtIGZfe1x0ZXh0e0Jpbm9taWFsfX0oXHBpKV0gZl97XHRleHR7UG9pc3Nvbn19KHkgPSAwOyBcbGFtYmRhKSBcXAp+IFxcCmZfe1x0ZXh0e1pJUH19KHkgfCB5ID4gMCkgJj0gWzEgLSBmX3tcdGV4dHtCaW5vbWlhbH19KFxwaSldIGZfe1x0ZXh0e1BvaXNzb259fSh5OyBcbGFtYmRhKSBcXApcZW5ke2FsaWdufQokJAoKd2hlcmUgJFxwaSQgaXMgdGhlIHByb2JhYmlsaXR5IG9mICpmYWxzZSB6ZXJvcyogKG1pc3NlZCBkZXRlY3Rpb25zKSBhbmQgJFxsYW1iZGEkIGlzIHRoZSBtZWFuIChhbmQgdmFyaWFuY2UpIG9mICphbGwgY291bnRzKiAoaW5jbHVkaW5nIHplcm9zKQoKIyMgQ291bnRzIG9mIGRlZXIKCkxldCdzIGFwcGx5IGEgWklQIG1vZGVsIHRvIGEgc2ltdWxhdGVkIHN1cnZleSBmb3Igd2hpdGUgdGFpbGVkIGRlZXIgd2hlcmUgd2UnbGwgYXNzdW1lIHRoYXQgdGhlIHByb2JhYmlsaXR5IG9mICpub3QqIGRldGVjdGluZyBkZWVyIGluY3JlYXNlcyB3aXRoIHRyZWUgZGVuc2l0eSAkVCQsIHN1Y2ggdGhhdAoKJCQKel9pIFxzaW0gXHRleHR7QmVybm91bGxpfShccGlfaSkgXFwKXHRleHR7bG9naXR9KFxwaSkgPSBcZ2FtbWFfMCArIFxnYW1tYV8xIFRfaQokJAoKYW5kIHRoZSBjb3VudHMgb2YgZGVlciBhbHNvIGluY3JlYXNlIHdpdGggdHJlZSBkZW5zaXR5ICRUJCwgc3VjaCB0aGF0CgokJApjX2kgXHNpbSBcdGV4dHtQb2lzc29ufShcbGFtYmRhX2kpIFxcClxsb2coXGxhbWJkYSkgPSBcYmV0YV8wICsgXGJldGFfMSBUX2kKJCQKClRvdGFsIGNvdW50cyBhcyBhIGZ1bmN0aW9uIG9mIG5vbi1kZXRlY3Rpb25zIGFuZCBwb3NpdGl2ZSBjb3VudHMKCiQkCnlfaSA9ICgxIC0gel9pKSBjX2kKJCQKCkhlcmUgYXJlIHRoZSBzaW11bGF0ZWQgZGF0YS4KCmBgYHtyIGRlZXJfZGF0YX0Kc2V0LnNlZWQoNTE0KQojIyBzYW1wbGUgc2l6ZQpubiA8LSAyMDAKIyMgcGFyYW1ldGVycyBmb3IgZGV0ZWN0aW9uIG1vZGVsCmdhbW1hXzAgPC0gMC4wMQpnYW1tYV90cmVlIDwtIDMKIyMgcGFyYW1ldGVycyBmb3IgY291bnQgbW9kZWwKYmV0YV8wIDwtIDEuNQpiZXRhX3RyZWUgPC0gMS4yCiMjIGNvdmFyaWF0ZQp0cmVlcyA8LSBydW5pZihubiwgMCwgMSkKIyMgZXhwZWN0YXRpb24gZm9yIFByKGRldGVjdCkKbXUgPC0gMSAvICgxICsgZXhwKC0oZ2FtbWFfMCArIGdhbW1hX3RyZWUgKiB0cmVlcykpKQojIyBtaXNzZWQgZGV0ZWN0aW9ucyAoMC8xKQp6IDwtIHJiaW5vbShubiwgMSwgbXUpCiMjIGV4cGVjdGF0aW9uIGZvciBwb3MgY291bnRzCmxhbWJkYSA8LSBleHAoYmV0YV8wICsgYmV0YV90cmVlICogdHJlZXMpIAojIyBwb3MgY291bnRzCnBvc19jb3VudCA8LSBycG9pcyhubiwgbGFtYmRhKQojIyBvYnNlcnZhdGlvbnMKeSA8LSAoMSAtIHopICogcG9zX2NvdW50CmBgYAoKSGVyZSBpcyBhIGhpc3RvZ3JhbSBvZiB0aGUgZGVlciBjb3VudHMKCmBgYHtyIHBsb3RfZGVlcl9kYXRhLCBmaWcuaGVpZ2h0PTQuNSwgZmlnLndpZHRoPTYsIGZpZy5hbGlnbj0nY2VudGVyJ30KIyMgc2V0IHBsb3QgYXJlYQpwYXIobWFpID0gYygwLjksIDAuOSwgMC4xLCAwLjEpLAogICAgb21pID0gYygwLCAwLCAwLCAwKSwgYmcgPSBOQSwKICAgIGNleC5tYWluID0gMS4yLCBjZXgubGFiID0gMS4yKQoKIyMgaGlzdG9ncmFtIG9mIGNvdW50cwpoaXN0KHksIGJyZWFrcyA9IHNlcSgwLCBtYXgoeSkpLCBsYXMgPSAxLCBjb2wgPSAiYnJvd24iLCBib3JkZXIgPSAiZ3JheSIsCiAgICAgbWFpbiA9ICIiLCB4bGFiID0gIk51bWJlciBvZiBkZWVyIiwgeWxhYiA9ICJGcmVxdWVuY3kiLCApCmBgYAoKIyMgWklQIG1vZGVsIGZvciBkZWVyCgpXZSBjYW4gZml0IFpJUCBtb2RlbHMgaW4gUiB3aXRoIGB6ZXJvaW5mbCgpYCBmcm9tIHRoZSAqKnBzY2wqKiBwYWNrYWdlLCB3aGVyZSBhZ2FpbiB3ZSBzcGVjaWZ5IHRoZSBmb3JtdWxhIGFzIGB5IH4gcHJlZGljdG9yc19vZl9jb3VudHMgfCBwcmVkaWN0b3JzX2Zvcl9kZXRlY3Rpb25gLgoKYGBge3IgZGVlcl96aXAsIGVjaG8gPSBUUlVFfQojIyBmaXQgaHVyZGxlIG1vZGVsCmRlZXJfemlwIDwtIHplcm9pbmZsKHkgfiB0cmVlcyB8IHRyZWVzKQojIyBtb2RlbCBzdW1tYXJ5CnN1bW1hcnkoZGVlcl96aXApCmBgYAoKSGVyZSwgdG9vLCB0aGUgZXN0aW1hdGVkIHBhcmFtZXRlcnMgZm9yIGJvdGggdGhlIGRldGVjdGlvbiBhbmQgY291bnQgbW9kZWxzICpnZW5lcmFsbHkqIGFncmVlIHdpdGggdGhlIHRydWUgdmFsdWVzLCBhbHRob3VnaCB0aGUgZXN0aW1hdGVkIGludGVyY2VwdCBhcHBlYXJzIHRvIGJlIG5vbi1zaWduaWZpY2FudC4KCkFzIHdlIGRpZCBmb3IgdGhlIFpBUCBtb2RlbCBmb3IgaGlwcG9zLCB3ZSBjYW4gcGxvdCB0aGUgZXN0aW1hdGVkIHByb2JhYmlsaXR5IG9mIG5vbi1kZXRlY3Rpb24gYW5kIGV4cGVjdGVkIGNvdW50IGFzIGEgZnVuY3Rpb24gb2YgdHJlZSBkZW5zaXR5LgoKYGBge3IgZGVlcl96aXBfZml0dGVkLCBmaWcuaGVpZ2h0PTQuNSwgZmlnLndpZHRoPTcuNSwgZmlnLmFsaWduPSdjZW50ZXInfQojIyBmaXR0ZWQgZm9yIGRldGVjdGlvbiBwcm9iIChwaSkKdHJlZXMgPC0gc29ydCh0cmVlcykKZ2FtbWFfaGF0XzAgPC0gY29lZihkZWVyX3ppcClbM10KZ2FtbWFfaGF0XzEgPC0gY29lZihkZWVyX3ppcClbNF0KcGlfaGF0IDwtIDEvKDErZXhwKC0oZ2FtbWFfaGF0XzAgKyBnYW1tYV9oYXRfMSAqIHRyZWVzKSkpCgojIyBtYXRyaXggb2YgZGVyaXZhdGl2ZXMKZGVyaXZzIDwtIG1hdHJpeChOQSwgbnJvdyA9IG5uLCBuY29sID0gNCkKZGVyaXZzWywxXSA8LSBkZXJpdnNbLDJdIDwtIDAKZGVyaXZzWywzXSA8LSAoZXhwKGdhbW1hX2hhdF8wICsgZ2FtbWFfaGF0XzEqdHJlZXMpKS8oKGV4cChnYW1tYV9oYXRfMCArIGdhbW1hX2hhdF8xKnRyZWVzKSsxKV4yKQpkZXJpdnNbLDRdIDwtICh0cmVlcypleHAoZ2FtbWFfaGF0XzAgKyBnYW1tYV9oYXRfMSp0cmVlcykpLygoZXhwKGdhbW1hX2hhdF8wICsgZ2FtbWFfaGF0XzEqdHJlZXMpKzEpXjIpIApzZSA8LSBzcXJ0KCBkaWFnICggZGVyaXZzICUqJSB2Y292KGRlZXJfemlwKSAlKiUgdChkZXJpdnMpICkpCmxvd2VyIDwtIHBpX2hhdCAtIHNlICogcXQoMC4wMjUsIG5uLTIsIGxvd2VyLnRhaWwgPSBGQUxTRSkKdXBwZXIgPC0gcGlfaGF0ICsgc2UgKiBxdCgwLjAyNSwgbm4tMiwgbG93ZXIudGFpbCA9IEZBTFNFKQoKIyMgZml0dGVkIGZvciBtZWFuICYgdmFyIChsYW1iZGEpCmJldGFfaGF0XzAgPC0gY29lZihkZWVyX3ppcClbMV0KYmV0YV9oYXRfMSA8LSBjb2VmKGRlZXJfemlwKVsyXQpsYW1iZGFfaGF0IDwtIGV4cChiZXRhX2hhdF8wICsgYmV0YV9oYXRfMSp0cmVlcykKCiMjIG1hdHJpeCBvZiBkZXJpdmF0aXZlcwpkZXJpdnNfMiA8LSBtYXRyaXgoTkEsIG5yb3cgPSBubiwgbmNvbCA9IDQpCmRlcml2c18yWywxXSA8LSBleHAoYmV0YV9oYXRfMCtiZXRhX2hhdF8xKnRyZWVzKQpkZXJpdnNfMlssMl0gPC0gdHJlZXMqZXhwKGJldGFfaGF0XzArYmV0YV9oYXRfMSp0cmVlcykgCmRlcml2c18yWywzXSA8LSBkZXJpdnNfMlssNF0gPC0gMApzZV8yIDwtIHNxcnQoIGRpYWcgKCBkZXJpdnNfMiAlKiUgdmNvdihkZWVyX3ppcCkgJSolIHQoZGVyaXZzXzIpICkpCmxvd2VyXzIgPC0gbGFtYmRhX2hhdCAtIHNlXzIgKiBxdCgwLjAyNSwgbm4tMiwgbG93ZXIudGFpbCA9IEZBTFNFKQp1cHBlcl8yIDwtIGxhbWJkYV9oYXQgKyBzZV8yICogcXQoMC4wMjUsIG5uLTIsIGxvd2VyLnRhaWwgPSBGQUxTRSkKCiMjIHNldCBwbG90IGFyZWEKcGFyKG1mcm93ID0gYygxLCAyKSwKICAgIG1haSA9IGMoMC45LCAwLjksIDAuNiwgMC4xKSwKICAgIG9taSA9IGMoMCwgMCwgMCwgMCksIGJnID0gTkEsCiAgICBjZXgubWFpbiA9IDEuMiwgY2V4LmxhYiA9IDEuMikKIyMgZGV0ZWN0aW9ucwpwbG90KHRyZWVzLCBwaV9oYXQsIHR5cGUgPSAibCIsIGxhcyA9IDEsIHlsaW0gPSBjKDAsIDEpLCBsd2QgPSAyLCBjb2wgPSAiZGFya2dyZWVuIiwKICAgICB4bGFiID0gIlRyZWUgZGVuc2l0eSIsIHlsYWIgPSBleHByZXNzaW9uKHBpKSwgbWFpbiA9ICJNaXNzZWQgZGV0ZWN0aW9uIikKbGluZXModHJlZXMsIGxvd2VyLCBsdHkgPSAyLCAgY29sID0gImRhcmtncmVlbiIsIGx3ZCA9IDIpCmxpbmVzKHRyZWVzLCB1cHBlciwgbHR5ID0gMiwgIGNvbCA9ICJkYXJrZ3JlZW4iLCBsd2QgPSAyKQojIyBjb3VudHMKcGxvdCh0cmVlcywgbGFtYmRhX2hhdCwgdHlwZSA9ICJsIiwgbGFzID0gMSwgeWxpbSA9IGMoMCwgMjApLCBsd2QgPSAyLCBjb2wgPSAiZGFya2dyZWVuIiwKICAgICB4bGFiID0gIlRyZWUgZGVuc2l0eSIsIHlsYWIgPSBleHByZXNzaW9uKGxhbWJkYSksIG1haW4gPSAiQ291bnRzIikKbGluZXModHJlZXMsIGxvd2VyXzIsIGx0eSA9IDIsIGNvbCA9ICJkYXJrZ3JlZW4iLCBsd2QgPSAyKQpsaW5lcyh0cmVlcywgdXBwZXJfMiwgbHR5ID0gMiwgY29sID0gImRhcmtncmVlbiIsIGx3ZCA9IDIpCmBgYAoKCgoKCgoK