Background
These lab exercises focus on fitting and evaluating linear mixed
models. We will be working with some hypothetical survey data on the
abundance of seabirds and waterfowl in Puget Sound with the intention of
estimating trends among locations over time. The data consist of an
aggregate index of abundance for 50+ species, which is based upon counts
of birds per unit effort at each of 9 sites (ie, 3 surveys each in the
north, central, and south basins). The surveys were conducted from
2000-2018.
Data ingest
The data are contained in the accompanying file
seabirds.csv, which consists of a column for year plus 9
more columns with the abundance index at each site. Thus, we will need
to reshape the data from its “wide” format into a “long” format where
each row of the data frame consists of a single record for year, site,
and index.
## get raw data
raw_data <- read.csv("seabirds.csv")
## seq of years of data
years <- raw_data$year
## number of years of data
n_yrs <- length(years)
## number of sites
n_sites <- ncol(raw_data) - 1
## take a peek
head(raw_data)
## year N_1 N_2 N_3 C_1 C_2 C_3 S_1 S_2 S_3
## 1 2000 26.3 20.0 14.9 26.2 20.0 15.9 14.9 14.5 18.0
## 2 2001 16.4 23.2 22.7 24.3 20.8 19.9 28.7 18.2 21.0
## 3 2002 23.7 18.8 18.5 27.4 21.2 21.5 27.2 17.7 21.8
## 4 2003 23.5 14.8 20.7 25.2 20.0 21.1 17.8 26.5 20.9
## 5 2004 25.6 19.8 19.9 32.2 22.4 17.1 21.9 18.2 23.3
## 6 2005 25.2 21.1 17.9 34.0 21.9 20.1 21.1 13.8 18.7
Let’s plot the index for each of the sites over time.
## set color Palette
clr <- viridis::plasma(n_sites, begin = 0.2, end = 0.8)
## plot the raw data
par(mai = c(0.9, 0.9, 0.6, 0.1),
omi = c(0, 0, 0, 0))
matplot(raw_data[,1], raw_data[,-1], pch = 16, las = 1, col = clr,
ylab = "Seabird abundance index", xlab = "Year")
Fitting models with lmer()
As we saw briefly in lecture, we cannot fit mixed models with our
standard lm() function. Instead, we will use the
lmer() function in the lme4
package by Bates
et al. (2015).
As with other statistical models, lmer() uses a standard
formula notation with the response and expression separated
by ~.
response ~ expression
The expression includes any fixed effects (FE) and random effects
(RE) separated by +. However, each RE term is of the form
(RE_expr | factor), where the vertical bar |
indicates that the random effects given by RE_expr should
be nested within factor.
Random effects for group means
Consider a simple one-way ANOVA model for an observation \(i\) from group \(j\) \((y_{ij})\) that includes a global mean
\(\mu\) plus the group-level means
\(\alpha_j\), such that
\[
y_{ij} = \mu + \alpha_j + \epsilon_{ij} \\
\alpha_{j} \sim \text{N}(0, \sigma_\alpha^2) \\
\epsilon_{ij} \sim \text{N}(0, \sigma_\epsilon^2)
\]
Assuming the data y and group ID group are
contained in data_frame, we would fit this model using
lmer(y ~ 1 + (1 | group), data = data_frame)
where the first 1 represents \(\mu\) and (1 | group)
represents the \(\alpha_j\) (ie, a
random effect for each group). Just as with lm(), we can
drop the leading 1 + to make the global mean implicit, such
that
lmer(y ~ (1 | group), data = data_frame)
Random intercepts & fixed slope
Now consider an ANCOVA model for an observation \(i\) from group \(j\) \((y_{ij})\) that includes a fixed effect
(slope) \(\beta_1\) of a predictor
\(x\) plus group-level offsets \(\alpha_j\) to the overall intercept \(\beta_0\), such that
\[
y_{ij} = (\beta_0 + \alpha_j) + \beta_1 x_{ij} + \epsilon_{ij} \\
\alpha_{j} \sim \text{N}(0, \sigma_\alpha^2) \\
\epsilon_{ij} \sim \text{N}(0, \sigma_\epsilon^2)
\]
That is, each group has a common slope \(\beta_1\) plus a y-intercept equal to \(\beta_0 + \alpha_j\). To see the
relationship between this model and its implementation in
lmer(), let’s separate the fixed effects and the random
effect for group, such that
\[
y_{ij} = \beta_0 + \beta_1 x_{ij} + \alpha_j + \epsilon_{ij} \\
\]
Assuming the data y, predictor x and group
ID group are contained in data_frame, we would
fit this model using
lmer(y ~ 1 + x + (1 | group), data = data_frame)
where the leading 1 + x represents the fixed intercept
and slope \((\beta_0, \beta_1)\) and
(1 | group) represents the group-level offset \(\alpha_j\). Just as with lm(),
we can drop the leading 1 + to make the global intercept
implicit, such that
lmer(y ~ x + (1 | group), data = data_frame)
Random intercepts & slopes
Now consider a model for an observation \(i\) from group \(j\) \((y_{ij})\) that includes random effects for
both the effect (slope) of \(x\) \((\beta_1 + \delta_j)\) and the group-level
intercepts \((\beta_0 + \alpha_j)\),
such that
\[
y_{ij} = (\beta_0 + \alpha_j) + (\beta_1 + \delta_j) x_{ij} +
\epsilon_{ij} \\
\alpha_{j} \sim \text{N}(0, \sigma_\alpha^2) \\
\delta_{j} \sim \text{N}(0, \sigma_\delta^2) \\
\epsilon_{ij} \sim \text{N}(0, \sigma_\epsilon^2)
\]
Here again, rewriting this model by separating the fixed and random
terms makes it easier to see how it aligns with the lmer()
notation.
\[
\begin{aligned}
y_{ij} &= (\beta_0 + \alpha_j) + (\beta_1 + \delta_j) x_{ij} +
\epsilon_{ij} \\
&= \beta_0 + \alpha_j + \beta_1 x_{ij} + \delta_j x_{ij} +
\epsilon_{ij} \\
&= \beta_0 + \beta_1 x_{ij} + (\alpha_j + \delta_j x_{ij}) +
\epsilon_{ij} \\
\end{aligned}
\]
Assuming the data y, predictor x and group
ID group are contained in data_frame, we would
fit this model using
lmer(y ~ 1 + x + (1 + x || group), data = data_frame)
where the 1 + x represents the fixed intercept and slope
and (1 + x || group) represents the \(\alpha_j\) and \(\delta_j\) (ie, random intercepts and
slopes for each group). Here we use the double pipe || in
the random effect because we don’t want the intercept and slope to be
correlated with one another. Just as with lm(), we can drop
the 1 + for both the FE and RE terms, such that
lmer(y ~ x + (x || group), data = data_frame)
Model fitting & evaluation
Before we fit any models, let’s begin by thinking about the data. In
this case we have surveys from different locations around Puget Sound,
and those locations are but a few of the possible sites that might have
been surveyed (ie, they do not represent the entirety of available
habitat). Thus, it sounds like we should treat site as a
random effect.
These data were also collected over time, which suggests that perhaps
a model with an explicit accounting for time would be good. One option
would be to treat year as a random effect, as we’re not
particularly interested in the specific effect of any one year.
Random effect of site
Let’s first fit a model with a random effect for site only \(s\) and ignore the temporal aspect of the
data. This is akin to the ANOVA model above, such that
\[
y_{s,t} = \mu + \alpha_s + \epsilon_{s,t} \\
\alpha_{s} \sim \text{N}(0, \sigma_\alpha^2) \\
\epsilon_{s,t} \sim \text{N}(0, \sigma_\epsilon^2)
\]
and \(\alpha_j\) is the random
effect of site.
## load lme4 package
library(lme4)
## fit model with RE for site
mod_site <- lmer(index ~ 1 + (1 | site), data = df)
## model summary
summary(mod_site)
## Linear mixed model fit by REML ['lmerMod']
## Formula: index ~ 1 + (1 | site)
## Data: df
##
## REML criterion at convergence: 987.2
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -2.59392 -0.70832 -0.06334 0.65978 2.72398
##
## Random effects:
## Groups Name Variance Std.Dev.
## site (Intercept) 4.166 2.041
## Residual 17.437 4.176
## Number of obs: 171, groups: site, 9
##
## Fixed effects:
## Estimate Std. Error t value
## (Intercept) 24.0351 0.7516 31.98
Notice that this model summary info is somewhat different that what
we’ve been seeing from lm(). In particular, there are 2
different blocks of results: one for the random effect of
site and the residual errors, and another for the fixed
effect of a global mean (Intercept).
Also notice that there are no \(p\)-values in this output. As we discussed
in lecture, this is because any assumptions about the distributional
form of our null hypothesis tests are likely to be violated when
including random effects in the model.
Estimates of random effects
Normally we would use coef() to extract the estimated
coefficients, but it will return the sum of \(\mu + \alpha_j\). If we just want the \(\alpha_j\), we can instead use
ranef().
## mu + alpha
coef(mod_site)$site
## (Intercept)
## C_1 28.06491
## C_2 24.13141
## C_3 22.72536
## N_1 24.39020
## N_2 22.98414
## N_3 22.56146
## S_1 25.73155
## S_2 22.46226
## S_3 23.26449
## alpha only
ranef(mod_site)$site
## (Intercept)
## C_1 4.02982111
## C_2 0.09632466
## C_3 -1.30972780
## N_1 0.35510732
## N_2 -1.05094514
## N_3 -1.47362349
## S_1 1.69646411
## S_2 -1.57282351
## S_3 -0.77059726
Correlation among random effects
As we learned in lecture, we can estimate the correlation among the
random effects as
\[
\rho = \frac{\sigma_\alpha^2}{\sigma_\alpha^2 + \sigma_\epsilon^2}
\]
which we can compute from the estimates in the above table. The
function VarCorr() will return the results, but they are a
bit hard to access directly, so we can embed that call inside of
as.data.frame().
## get var(RE)
(var_re_site <- as.data.frame(VarCorr(mod_site)))
## grp var1 var2 vcov sdcor
## 1 site (Intercept) <NA> 4.166043 2.041089
## 2 Residual <NA> <NA> 17.436888 4.175750
## variance of random effects
sigma2_alpha <- var_re_site$vcov[1]
## variance of residuals
sigma2_epsilon <- var_re_site$vcov[2]
## calculate the correlation among RE's
rho <- sigma2_alpha / (sigma2_alpha + sigma2_epsilon)
round(rho, 2)
## [1] 0.19
It looks like there is not a lot of correlation among the random
effects. We should also note that \(\rho\) provides us with an estimate of the
proportion of the variance explained by the random effects (similar to
\(R^2\) for the fixed effects).
Random effect of year
Now let’s fit another model that only includes the random effect of
year \(t\), where
\[
y_{s,t} = \mu + \alpha_t + \epsilon_{s,t} \\
\alpha_{t} \sim \text{N}(0, \sigma_\alpha^2) \\
\epsilon_{s,t} \sim \text{N}(0, \sigma_\epsilon^2)
\]
and \(\alpha_t\) is now the random
effect of year.
## fit model with RE for year
mod_year <- lmer(index ~ 1 + (1 | year), data = df)
## model summary
summary(mod_year)
## Linear mixed model fit by REML ['lmerMod']
## Formula: index ~ 1 + (1 | year)
## Data: df
##
## REML criterion at convergence: 989.8
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -2.0624 -0.6200 -0.1094 0.5171 2.8591
##
## Random effects:
## Groups Name Variance Std.Dev.
## year (Intercept) 4.528 2.128
## Residual 16.847 4.104
## Number of obs: 171, groups: year, 19
##
## Fixed effects:
## Estimate Std. Error t value
## (Intercept) 24.0351 0.5804 41.41
Estimates of random effects
Here are the estimates of the \(\alpha_t\).
## alpha only
ranef(mod_year)$year
## (Intercept)
## 1 -3.586079548
## 2 -1.660015132
## 3 -1.455616459
## 4 -2.029505040
## 5 -1.251217786
## 6 -1.770075956
## 7 0.077373587
## 8 0.879245303
## 9 -1.266940761
## 10 -0.009102775
## 11 0.266049285
## 12 0.674846630
## 13 -0.873866390
## 14 1.083643976
## 15 3.269137476
## 16 2.435819811
## 17 1.154397362
## 18 1.846208255
## 19 2.215698163
Do you notice anything about these random effects for year? The
appear to be increasing over time, such that the estimate for 2000 is
-3.59 and the estimate for 2018 is 2.22.
Correlation among random effects
Here is the correlation among the random effects for year.
## get var(RE)
(var_re_year <- as.data.frame(VarCorr(mod_year)))
## grp var1 var2 vcov sdcor
## 1 year (Intercept) <NA> 4.528355 2.127993
## 2 Residual <NA> <NA> 16.846564 4.104457
## variance of random effects
sigma2_alpha <- var_re_year$vcov[1]
## variance of residuals
sigma2_epsilon <- var_re_year$vcov[2]
## calculate the correlation among RE's
rho <- sigma2_alpha / (sigma2_alpha + sigma2_epsilon)
round(rho, 2)
## [1] 0.21
Here, too, there is not a lot of correlation among the random
effects.
Random effects for site & year
Now let’s fit a model that includes random effects for both
site and year, where
\[
y_{s,t} = \mu + \alpha_s + \alpha_t + \epsilon_{s,t} \\
\alpha_{s} \sim \text{N}(0, \sigma_{\alpha_s}^2) \\
\alpha_{t} \sim \text{N}(0, \sigma_{\alpha_t}^2) \\
\epsilon_{s,t} \sim \text{N}(0, \sigma_\epsilon^2)
\]
and \(\alpha_t\) is now the random
effect of year.
## model with RE's for both site and year
mod_site_year <- lmer(index ~ 1 + (1 | site) + (1 | year), df)
## model summary
summary(mod_site_year)
## Linear mixed model fit by REML ['lmerMod']
## Formula: index ~ 1 + (1 | site) + (1 | year)
## Data: df
##
## REML criterion at convergence: 959.8
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -1.97613 -0.70823 -0.08333 0.58907 2.70628
##
## Random effects:
## Groups Name Variance Std.Dev.
## year (Intercept) 5.021 2.241
## site (Intercept) 4.430 2.105
## Residual 12.416 3.524
## Number of obs: 171, groups: year, 19; site, 9
##
## Fixed effects:
## Estimate Std. Error t value
## (Intercept) 24.0351 0.9106 26.4
Here we can see that the residual variance \(\sigma^2\) has decreased quite a bit
compared to our other models. We can check how much of the total
variance is explained by the combination of the two random effects as
follows:
## get var(RE)
var_re_site_year <- as.data.frame(VarCorr(mod_site_year))
## variance of site random effects
sigma2_alpha_s <- var_re_site_year$vcov[1]
## variance of year random effects
sigma2_alpha_t <- var_re_site_year$vcov[2]
## variance of residuals
sigma2_epsilon <- var_re_site_year$vcov[3]
## calculate the correlation among RE's
rho <- (sigma2_alpha_s + sigma2_alpha_t) /
(sigma2_alpha_s + sigma2_alpha_t + sigma2_epsilon)
round(rho, 2)
## [1] 0.43
Estimates of random effects
Here are the estimates of the \(\alpha_s\) and \(\alpha_t\).
## alpha only
ranef(mod_site_year)
## $year
## (Intercept)
## 1 -3.97590273
## 2 -1.84046634
## 3 -1.61384860
## 4 -2.25012148
## 5 -1.38723086
## 6 -1.96249128
## 7 0.08578445
## 8 0.97482327
## 9 -1.40466299
## 10 -0.01009229
## 11 0.29497005
## 12 0.74820553
## 13 -0.96885965
## 14 1.20144101
## 15 3.62450761
## 16 2.70060452
## 17 1.27988561
## 18 2.04689950
## 19 2.45655465
##
## $site
## (Intercept)
## C_1 4.2854225
## C_2 0.1024343
## C_3 -1.3928005
## N_1 0.3776309
## N_2 -1.1176039
## N_3 -1.5670917
## S_1 1.8040666
## S_2 -1.6725837
## S_3 -0.8194743
##
## with conditional variances for "year" "site"
Likelihood ratio tests
We can use likelihood ratio tests to determine whether there is
support for any given random effect in a model. These tests require a
simulation-based approach that involves a search over a large gridded
space of ratios of \(\sigma_\alpha^2 /
\sigma_\epsilon^2\). For more information, see Crainiceanu
& Ruppert (2004).
To conduct these tests, we’ll use the exactRLRT()
function from the RLRsim
package.
Single random effect
The first option compares a model with a single random
effect to an identical model that lacks the random effect. The null
hypothesis for this test is \(H_0 :
\text{Var}(\alpha) = \sigma_\alpha^2 = 0\). The test statistic is
given by
\[
\lambda = 2 \log \mathcal{L}(\sigma_\alpha^2 \neq 0) - 2 \log
\mathcal{L}(\sigma_\alpha^2 = 0)
\]
Let’s go ahead and test our 2 models with random effects for
site and year. To compare our models with a
single random effect, we will compare them against a full model with
both random effects. To do so, we need 3 different models:
model with single RE of interest to be tested
(model_A)
full model with 2+ RE’s (model_AB)
full model minus the RE in model (1)
(model_B)
To conduct the test we use
extractRLRT(model_A, model_AB, model_B).
## load RLRsim package
library(RLRsim)
## test `site` model
exactRLRT(mod_site, mod_site_year, mod_year)
##
## simulated finite sample distribution of RLRT.
##
## (p-value based on 10000 simulated values)
##
## data:
## RLRT = 29.969, p-value < 2.2e-16
We can clearly reject \(H_0 :
\sigma_{\alpha_s}^2 = 0\) and conclude that there is support for
inclusion of the site random effect.
Now let’s go ahead and test the model with a single random effect for
year.
## test `year` model
exactRLRT(mod_year, mod_site_year, mod_site)
##
## simulated finite sample distribution of RLRT.
##
## (p-value based on 10000 simulated values)
##
## data:
## RLRT = 27.39, p-value < 2.2e-16
We can clearly reject \(H_0 :
\sigma_{\alpha_t}^2 = 0\) and conclude that there is support for
inclusion of the year random effect.
Multiple random effects
We can use a bootstrapping approach to test for evidence against
including multiple random effects in the same model. Our approach
follows this pseudo-code:
fit null model with no random effects
calculate likelihood ratio statistic
simulate data from the null model in (1)
fit simple & full model to data from (3)
calculate likelihood ratio (difference in
log-likelihood)
repeats steps 3-5 many times
see where statistic from (2) falls within estimated distribution
from (3-6)
Importantly, too, we need to specify that the random effects model be
fit using maximum likelihood (ML) instead of the default
restricted maximum likelihood (REML).
## set random seed to make it reproducible
set.seed(514)
## Step 1: fit null model with no RE's using `lm()`
null_model <- lm(index ~ 1, data = df)
## Step 2: calculate likelihood ratio (ie, difference in log-likelihood)
lambda <- 2 * (logLik(mod_site_year) - logLik(null_model))
## number of bootstrapped samples
nb <- 1000
## empty vector for storing LRT statistics
LRT_boot <- rep(NA, nb)
## do bootstrapping
for(i in 1:nb) {
## Step 3: simulate data from null model
sim_data <- unlist(simulate(null_model))
## Step 4: fit null and RE models to sim data
m_null <- lm(sim_data ~ 1)
m_alt <- lmer(sim_data ~ 1 + (1 | site) + (1 | year), data = df, REML = FALSE)
## Step 5: calculate likelihood ratio
LRT_boot[i] <- as.numeric(2*(logLik(m_alt) - logLik(m_null)))
## Step 6: repeat this `nb` times
}
## Step 7: calculate approximate p-value
mean(LRT_boot > lambda)
## [1] 0
Here it appears as though none of the 1000 bootstrapped samples had a
test statistic larger than the original value of 46.4.
Model diagnostics
We would be remiss if we did not do some diagnostic checks on our
model. One of our assumptions is that the residuals \(\epsilon\) and random effects \(\alpha\) are normally distributed, which we
can check with Q-Q plots. Let’s do some diagnostic checks for the model
with random effects for both site and
year.
Q-Q plots
## set plot area
par(mai = c(0.9, 0.9, 0.6, 0.1),
omi = c(0, 0, 0, 0),
mfrow = c(1,2), cex.lab = 1.2)
## qq resids
qqnorm(residuals(mod_site_year), main = "QQ plot (residuals)", las = 1, pch = 16)
qqline(residuals(mod_site_year))
## qq RE's
qqnorm(unlist(ranef(mod_site_year)), main = "QQ plot (RE's)", las = 1, pch = 16)
qqline(unlist(ranef(mod_site_year)))

These plots both look pretty good. Perhaps there is some deviation
from normality for the random effects, but there are not many values
from which to ascertain whether or not the assumption of normality has
been violated.
Residuals versus fitted
We can also plot the model residuals against the fitted values to
look for evidence of heteroscedasticity or non-linearity in the
residuals.
## resids vs fitted
plot(fitted(mod_site_year), residuals(mod_site_year), las = 1, pch = 16,
xlab = "Fitted", ylab = "Residuals",
main = "Residuals vs fitted")
abline(h=0, lty = "dashed")

This residual plot looks promising in that there are no obvious
patterns to the residuals.
Autocorrelation
Because these data were collected over time, we should be aware of
possible autocorrelation among the residuals. It would be a bit messy to
create plots for all 9 of the time series, so we’ll just get a table of
the results from acf() and see whether any of them exceed
the critical value given by
\[
0 \pm \frac{z_{\alpha/2}}{\sqrt{n}}
\]
where \(z_{\alpha/2}\) is the \(1-\alpha/2\) quantile of the standard
normal distribution. For example, if \(\alpha\) = 0.05, then \(z_{\alpha/2}\) = 1.96. Here we’ll only
examine correlations out to a lag of 5 years because it’s unlikely that
counts in this year would be related to counts 6 or more years in the
past (and hopefully not at any years in the past).
## Type-I error
alpha_crit <- 0.05
## threshold value for rho (correlation)
(rho_crit <- qnorm(1 - alpha_crit/2) / sqrt(n_yrs))
## [1] 0.4496466
## rearrange residuals into matrix
rr <- matrix(residuals(mod_site_year), n_yrs, n_sites)
## get ACF
ACF <- apply(rr, 2, acf, lag.max = 5, plot = FALSE)
ACF <- lapply(ACF, function(x) x$acf)
## convert list to matrix; don't need row 1 b/c rho_0 = 1
ACF <- do.call(cbind, ACF)[-1,]
## check if any |values| > rho_crit
any(abs(ACF) > rho_crit)
## [1] FALSE
It looks like the random effect for year \(\alpha_t\) must have done an adequate job
of accounting for any autocorrelation in the data.
Mixed model with a trend
Both our plot of the raw data and the random effects for year showed
evidence of an increasing trend in the index of abundance. Let’s now fit
a model that includes a fixed effect for year to account for
this apparent trend, plus random effects for both site and year. At
first glance, it might seem problematic to include both a fixed and
random effect for year, but we have multiple sites sampled per year, so
the fixed effect will give us the overall linear trend across all sites,
and the random effect will allow for additional variation among years
(ie, all sites in a given year may be greater or less than the long-term
average). Specifically, the model we want to fit is
\[
y_{s,t} = \beta_0 + \beta_1 t + \alpha_s + \alpha_t + \epsilon_{s,t} \\
\alpha_{s} \sim \text{N}(0, \sigma_{\alpha_s}^2) \\
\alpha_{t} \sim \text{N}(0, \sigma_{\alpha_t}^2) \\
\epsilon_{s,t} \sim \text{N}(0, \sigma_\epsilon^2)
\]
Let’s fit this model and compare it to the comparable model we fit
earlier without a fixed effect of year.
## model with RE's for both site and year
mod_site_year_f <- lmer(index ~ 1 + year + (1 | site) + (1 | year), df)
## model summary
summary(mod_site_year_f)
## Linear mixed model fit by REML ['lmerMod']
## Formula: index ~ 1 + year + (1 | site) + (1 | year)
## Data: df
##
## REML criterion at convergence: 938.5
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -2.03292 -0.76397 -0.07034 0.58757 2.60509
##
## Random effects:
## Groups Name Variance Std.Dev.
## year (Intercept) 0.2758 0.5252
## site (Intercept) 4.4303 2.1048
## Residual 12.4163 3.5237
## Number of obs: 171, groups: year, 19; site, 9
##
## Fixed effects:
## Estimate Std. Error t value
## (Intercept) 20.12690 0.93264 21.581
## year 0.39082 0.05389 7.252
##
## Correlation of Fixed Effects:
## (Intr)
## year -0.578
You can see from the summary info above that the fixed effect of
year is ~0.39, which means the index of abundance is
increasing by ~4 units per decade.
Model comparison
In this case we can use AIC to directly compare these models because
they only differ with respect to the fixed effect for year.
However, before doing so, we need to refit both of the models using ML
rather than REML.
## refit site & year model
mod_sy_ml <- lmer(index ~ 1 + (1 | site) + (1 | year), df, REML = FALSE)
## refit
mod_syf_ml <- lmer(index ~ 1 + year + (1 | site) + (1 | year), df, REML = FALSE)
## get AIC for both models
AIC(mod_sy_ml)
AIC(mod_syf_ml)
## [1] 969.4638
## [1] 945.701
The AIC for the model with a fixed effect of year is ~24 units lower
than the more simple model, which is indeed strong evidence for the
inclusion of year as a fixed effect. Another option for
comparing nested models with the same random effects structure is a
\(\chi^2\) test via
anova(), which has the added advantage of also providing
AIC and BIC values as well. To do so, we use
anova(reduced model, full model).
## LRT for fixed effect of `year`
anova(mod_sy_ml, mod_syf_ml)
## Data: df
## Models:
## mod_sy_ml: index ~ 1 + (1 | site) + (1 | year)
## mod_syf_ml: index ~ 1 + year + (1 | site) + (1 | year)
## npar AIC BIC logLik -2*log(L) Chisq Df Pr(>Chisq)
## mod_sy_ml 4 969.46 982.03 -480.73 961.46
## mod_syf_ml 5 945.70 961.41 -467.85 935.70 25.763 1 3.861e-07 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
General considerations
Here are some general guidelines to follow when fitting and
evaluating mixed effects models.
Fixed effects
You should use maximum likelihood (ML) when comparing models with
different fixed effects, as ML doesn’t rely on the coefficients of the
fixed effects, whereas REML assumes that the fixed effects are all set
and correct. That said, you should ultimately use the parameter
estimates from your final “best” model as obtained via REML because ML
estimates of the variances of the random effects tend to be biased
low.
Random effects
You can use model selection to help you decide which random effects
to retain, but in general, random effects should be based upon
your knowledge of the system. For example, is there
pseudoreplication? Are the data part of a time series or spatial
sampling design? As we saw above, we use REML estimators to compare
models with different random effects.
Entire model selection
The most important thing is to not vary both random
and fixed effects at the same time. You should address one of the
components and then the other, often in a back-and-forth-manner. Here is
the model selection process recommended by Zuur et
al. (2009):
fit the most complex model you can envision based on your
possible covariates and random effects
sort out the random effects structure using REML-based inference
via AIC or likelihood ratio tests
sort out the fixed effects structure while keeping your
random effects constant using REML and \(F\)- or \(t\)-tests, or compare nested ML models via
AIC
present the results of your final model using REML
estimation
LS0tCnRpdGxlOiAiRml0dGluZyBsaW5lYXIgbWl4ZWQgbW9kZWxzIgphdXRob3I6ICI8YnI+TWFyayBTY2hldWVyZWxsIgpkYXRlOiAiOCBNYXkgMjAyNiIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0aGVtZTogCiAgICAgIGJvb3Rzd2F0Y2g6IGpvdXJuYWwKICAgICAgcHJpbWFyeTogIiMzMjAwNmUiCiAgICBoaWdobGlnaHQ6IHRleHRtYXRlCiAgICBjc3M6IC4uL2xlY3R1cmVfaW5zdC5jc3MKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRvY19kZXB0aDogNAotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIG1lc3NhZ2UgPSBGQUxTRSkKYGBgCgojIEJhY2tncm91bmQKClRoZXNlIGxhYiBleGVyY2lzZXMgZm9jdXMgb24gZml0dGluZyBhbmQgZXZhbHVhdGluZyBsaW5lYXIgbWl4ZWQgbW9kZWxzLiBXZSB3aWxsIGJlIHdvcmtpbmcgd2l0aCBzb21lIGh5cG90aGV0aWNhbCBzdXJ2ZXkgZGF0YSBvbiB0aGUgYWJ1bmRhbmNlIG9mIHNlYWJpcmRzIGFuZCB3YXRlcmZvd2wgaW4gUHVnZXQgU291bmQgd2l0aCB0aGUgaW50ZW50aW9uIG9mIGVzdGltYXRpbmcgdHJlbmRzIGFtb25nIGxvY2F0aW9ucyBvdmVyIHRpbWUuIFRoZSBkYXRhIGNvbnNpc3Qgb2YgYW4gYWdncmVnYXRlIGluZGV4IG9mIGFidW5kYW5jZSBmb3IgNTArIHNwZWNpZXMsIHdoaWNoIGlzIGJhc2VkIHVwb24gY291bnRzIG9mIGJpcmRzIHBlciB1bml0IGVmZm9ydCBhdCBlYWNoIG9mIDkgc2l0ZXMgKGllLCAzIHN1cnZleXMgZWFjaCBpbiB0aGUgbm9ydGgsIGNlbnRyYWwsIGFuZCBzb3V0aCBiYXNpbnMpLiBUaGUgc3VydmV5cyB3ZXJlIGNvbmR1Y3RlZCBmcm9tIDIwMDAtMjAxOC4KCiMjIERhdGEgaW5nZXN0CgpUaGUgZGF0YSBhcmUgY29udGFpbmVkIGluIHRoZSBhY2NvbXBhbnlpbmcgZmlsZSBgc2VhYmlyZHMuY3N2YCwgd2hpY2ggY29uc2lzdHMgb2YgYSBjb2x1bW4gZm9yIHllYXIgcGx1cyA5IG1vcmUgY29sdW1ucyB3aXRoIHRoZSBhYnVuZGFuY2UgaW5kZXggYXQgZWFjaCBzaXRlLiBUaHVzLCB3ZSB3aWxsIG5lZWQgdG8gcmVzaGFwZSB0aGUgZGF0YSBmcm9tIGl0cyAid2lkZSIgZm9ybWF0IGludG8gYSAibG9uZyIgZm9ybWF0IHdoZXJlIGVhY2ggcm93IG9mIHRoZSBkYXRhIGZyYW1lIGNvbnNpc3RzIG9mIGEgc2luZ2xlIHJlY29yZCBmb3IgeWVhciwgc2l0ZSwgYW5kIGluZGV4LgoKYGBge3IgZGF0YV9pbXBvcnR9CiMjIGdldCByYXcgZGF0YQpyYXdfZGF0YSA8LSByZWFkLmNzdigic2VhYmlyZHMuY3N2IikKCiMjIHNlcSBvZiB5ZWFycyBvZiBkYXRhCnllYXJzIDwtIHJhd19kYXRhJHllYXIKCiMjIG51bWJlciBvZiB5ZWFycyBvZiBkYXRhCm5feXJzIDwtIGxlbmd0aCh5ZWFycykKCiMjIG51bWJlciBvZiBzaXRlcwpuX3NpdGVzIDwtIG5jb2wocmF3X2RhdGEpIC0gMQoKIyMgdGFrZSBhIHBlZWsKaGVhZChyYXdfZGF0YSkKYGBgCgpMZXQncyBwbG90IHRoZSBpbmRleCBmb3IgZWFjaCBvZiB0aGUgc2l0ZXMgb3ZlciB0aW1lLgoKYGBge3IgcGxvdF9yYXdfZGF0YSwgZmlnLmhlaWdodD00LjUsIGZpZy53aWR0aD02LCBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy5jYXA9IkZpZ3VyZSAxLiBUaW1lIHNlcmllcyBvZiBhYnVuZGFuY2Ugb2YgUHVnZXQgU291bmQgc2VhYmlyZHMgYXQgOSBkaWZmZXJlbnQgc2l0ZXMuIn0KIyMgc2V0IGNvbG9yIFBhbGV0dGUKY2xyIDwtIHZpcmlkaXM6OnBsYXNtYShuX3NpdGVzLCBiZWdpbiA9IDAuMiwgZW5kID0gMC44KQoKIyMgcGxvdCB0aGUgcmF3IGRhdGEKcGFyKG1haSA9IGMoMC45LCAwLjksIDAuNiwgMC4xKSwKICAgIG9taSA9IGMoMCwgMCwgMCwgMCkpCm1hdHBsb3QocmF3X2RhdGFbLDFdLCByYXdfZGF0YVssLTFdLCBwY2ggPSAxNiwgbGFzID0gMSwgY29sID0gY2xyLAogICAgICAgIHlsYWIgPSAiU2VhYmlyZCBhYnVuZGFuY2UgaW5kZXgiLCB4bGFiID0gIlllYXIiKQpgYGAKCiMjIERhdGEgZm9ybWF0dGluZwoKVG8gcmVzaGFwZSB0aGUgZGF0YSwgd2UnbGwgdXNlIGBwaXZvdF9sb25nZXIoKWAgZnJvbSB0aGUgWyoqdGlkeXIqKl0oaHR0cHM6Ly90aWR5ci50aWR5dmVyc2Uub3JnLykgcGFja2FnZSAoc2VlIGA/dGlkeXI6OnBpdm90X2xvbmdlcmAgZm9yIG1vcmUgaW5mbykuIEJlZm9yZSBkb2luZyBzbywgaG93ZXZlciwgd2UnbGwgcmVwbGFjZSB0aGUgYWN0dWFsIHllYXJzIHdpdGggYSBzaW1wbGUgdGltZSBpbmRleCB0aGF0IHJ1bnMgZnJvbSAxIHRvIGByIG5feXJzYCwgd2hpY2ggd2lsbCBhZGp1c3Qgb3VyIG1vZGVsIGludGVyY2VwdCB0ZXJtIHRvIGJlIHJlbGF0aXZlIHRvIHRoZSB5ZWFyIGByIHllYXJzWzFdYCBpbnN0ZWFkIG9mIHRoZSB5ZWFyIDAgQUQuCgpgYGB7ciB0aWR5X2RhdGF9CiMjIHRpZHkgdGhlIGRhdGEKIyMgcmVwbGFjZSB5ZWFycyB3aXRoIHRpbWUgaW5kZXggZnJvbSAxOm5feXJzCnJhd19kYXRhWywieWVhciJdIDwtIHNlcShuX3lycykKCiMjIGNvbnZlcnQgZnJvbSB3aWRlIHRvIGxvbmcKZGYgPC0gdGlkeXI6OnBpdm90X2xvbmdlcihhcy5kYXRhLmZyYW1lKHJhd19kYXRhKSwgLXllYXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAic2l0ZSIsIHZhbHVlc190byA9ICJpbmRleCIpCgojIyBjb252ZXJ0IHRoZSB0aWJibGUgdG8gYSBkYXRhIGZyYW1lCmRmIDwtIGFzLmRhdGEuZnJhbWUoZGYpCgojIyBpbnNwZWN0IG91ciB0aWR5IGRhdGEKaGVhZChkZiwgMTApCmBgYAoKIyBGaXR0aW5nIG1vZGVscyB3aXRoIGBsbWVyKClgCgpBcyB3ZSBzYXcgYnJpZWZseSBpbiBsZWN0dXJlLCB3ZSBjYW5ub3QgZml0IG1peGVkIG1vZGVscyB3aXRoIG91ciBzdGFuZGFyZCBgbG0oKWAgZnVuY3Rpb24uIEluc3RlYWQsIHdlIHdpbGwgdXNlIHRoZSBgbG1lcigpYCBmdW5jdGlvbiBpbiB0aGUgWyoqbG1lNCoqXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvbG1lNC8pIHBhY2thZ2UgYnkgW0JhdGVzIGV0IGFsLiAoMjAxNSldKCJyZWZlcmVuY2VzL0JhdGVzXzIwMTVfbG1lNF9wYWNrYWdlLnBkZiIpLgoKQXMgd2l0aCBvdGhlciBzdGF0aXN0aWNhbCBtb2RlbHMsIGBsbWVyKClgIHVzZXMgYSBzdGFuZGFyZCBgZm9ybXVsYWAgbm90YXRpb24gd2l0aCB0aGUgcmVzcG9uc2UgYW5kIGV4cHJlc3Npb24gc2VwYXJhdGVkIGJ5IGB+YC4KCmBgYApyZXNwb25zZSB+IGV4cHJlc3Npb24KYGBgCgpUaGUgZXhwcmVzc2lvbiBpbmNsdWRlcyBhbnkgZml4ZWQgZWZmZWN0cyAoRkUpIGFuZCByYW5kb20gZWZmZWN0cyAoUkUpIHNlcGFyYXRlZCBieSBgK2AuIEhvd2V2ZXIsIGVhY2ggUkUgdGVybSBpcyBvZiB0aGUgZm9ybSBgKFJFX2V4cHIgfCBmYWN0b3IpYCwgd2hlcmUgdGhlIHZlcnRpY2FsIGJhciBgfGAgaW5kaWNhdGVzIHRoYXQgdGhlIHJhbmRvbSBlZmZlY3RzIGdpdmVuIGJ5IGBSRV9leHByYCBzaG91bGQgYmUgbmVzdGVkIHdpdGhpbiBgZmFjdG9yYC4KCiMjIFJhbmRvbSBlZmZlY3RzIGZvciBncm91cCBtZWFucwoKQ29uc2lkZXIgYSBzaW1wbGUgb25lLXdheSBBTk9WQSBtb2RlbCBmb3IgYW4gb2JzZXJ2YXRpb24gJGkkIGZyb20gZ3JvdXAgJGokICQoeV97aWp9KSQgdGhhdCBpbmNsdWRlcyBhIGdsb2JhbCBtZWFuICRcbXUkIHBsdXMgdGhlIGdyb3VwLWxldmVsIG1lYW5zICRcYWxwaGFfaiQsIHN1Y2ggdGhhdAoKJCQKeV97aWp9ID0gXG11ICsgXGFscGhhX2ogKyBcZXBzaWxvbl97aWp9IFxcClxhbHBoYV97an0gXHNpbSBcdGV4dHtOfSgwLCBcc2lnbWFfXGFscGhhXjIpIFxcClxlcHNpbG9uX3tpan0gXHNpbSBcdGV4dHtOfSgwLCBcc2lnbWFfXGVwc2lsb25eMikKJCQKCkFzc3VtaW5nIHRoZSBkYXRhIGB5YCBhbmQgZ3JvdXAgSUQgYGdyb3VwYCBhcmUgY29udGFpbmVkIGluIGBkYXRhX2ZyYW1lYCwgd2Ugd291bGQgZml0IHRoaXMgbW9kZWwgdXNpbmcKCmBgYApsbWVyKHkgfiAxICsgKDEgfCBncm91cCksIGRhdGEgPSBkYXRhX2ZyYW1lKQpgYGAKCndoZXJlIHRoZSBmaXJzdCBgMWAgcmVwcmVzZW50cyAkXG11JCBhbmQgYCgxIHwgZ3JvdXApYCByZXByZXNlbnRzIHRoZSAkXGFscGhhX2okIChpZSwgYSByYW5kb20gZWZmZWN0IGZvciBlYWNoIGdyb3VwKS4gSnVzdCBhcyB3aXRoIGBsbSgpYCwgd2UgY2FuIGRyb3AgdGhlIGxlYWRpbmcgYDEgK2AgdG8gbWFrZSB0aGUgZ2xvYmFsIG1lYW4gaW1wbGljaXQsIHN1Y2ggdGhhdAoKYGBgCmxtZXIoeSB+ICgxIHwgZ3JvdXApLCBkYXRhID0gZGF0YV9mcmFtZSkKYGBgCgojIyBSYW5kb20gaW50ZXJjZXB0cyAmIGZpeGVkIHNsb3BlCgpOb3cgY29uc2lkZXIgYW4gQU5DT1ZBIG1vZGVsIGZvciBhbiBvYnNlcnZhdGlvbiAkaSQgZnJvbSBncm91cCAkaiQgJCh5X3tpan0pJCB0aGF0IGluY2x1ZGVzIGEgZml4ZWQgZWZmZWN0IChzbG9wZSkgJFxiZXRhXzEkIG9mIGEgcHJlZGljdG9yICR4JCBwbHVzIGdyb3VwLWxldmVsIG9mZnNldHMgJFxhbHBoYV9qJCB0byB0aGUgb3ZlcmFsbCBpbnRlcmNlcHQgJFxiZXRhXzAkLCBzdWNoIHRoYXQKCiQkCnlfe2lqfSA9IChcYmV0YV8wICsgXGFscGhhX2opICsgXGJldGFfMSB4X3tpan0gKyBcZXBzaWxvbl97aWp9IFxcClxhbHBoYV97an0gXHNpbSBcdGV4dHtOfSgwLCBcc2lnbWFfXGFscGhhXjIpIFxcClxlcHNpbG9uX3tpan0gXHNpbSBcdGV4dHtOfSgwLCBcc2lnbWFfXGVwc2lsb25eMikKJCQKClRoYXQgaXMsIGVhY2ggZ3JvdXAgaGFzIGEgY29tbW9uIHNsb3BlICRcYmV0YV8xJCBwbHVzIGEgeS1pbnRlcmNlcHQgZXF1YWwgdG8gJFxiZXRhXzAgKyBcYWxwaGFfaiQuIFRvIHNlZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhpcyBtb2RlbCBhbmQgaXRzIGltcGxlbWVudGF0aW9uIGluIGBsbWVyKClgLCBsZXQncyBzZXBhcmF0ZSB0aGUgZml4ZWQgZWZmZWN0cyBhbmQgdGhlIHJhbmRvbSBlZmZlY3QgZm9yIGdyb3VwLCBzdWNoIHRoYXQKCiQkCnlfe2lqfSA9IFxiZXRhXzAgKyBcYmV0YV8xIHhfe2lqfSArIFxhbHBoYV9qICsgXGVwc2lsb25fe2lqfSBcXAokJAoKQXNzdW1pbmcgdGhlIGRhdGEgYHlgLCBwcmVkaWN0b3IgYHhgIGFuZCBncm91cCBJRCBgZ3JvdXBgIGFyZSBjb250YWluZWQgaW4gYGRhdGFfZnJhbWVgLCB3ZSB3b3VsZCBmaXQgdGhpcyBtb2RlbCB1c2luZwoKYGBgCmxtZXIoeSB+IDEgKyB4ICsgKDEgfCBncm91cCksIGRhdGEgPSBkYXRhX2ZyYW1lKQpgYGAKCndoZXJlIHRoZSBsZWFkaW5nIGAxICsgeGAgcmVwcmVzZW50cyB0aGUgZml4ZWQgaW50ZXJjZXB0IGFuZCBzbG9wZSAkKFxiZXRhXzAsIFxiZXRhXzEpJCBhbmQgYCgxIHwgZ3JvdXApYCByZXByZXNlbnRzIHRoZSBncm91cC1sZXZlbCBvZmZzZXQgJFxhbHBoYV9qJC4gSnVzdCBhcyB3aXRoIGBsbSgpYCwgd2UgY2FuIGRyb3AgdGhlIGxlYWRpbmcgYDEgK2AgdG8gbWFrZSB0aGUgZ2xvYmFsIGludGVyY2VwdCBpbXBsaWNpdCwgc3VjaCB0aGF0CgpgYGAKbG1lcih5IH4geCArICgxIHwgZ3JvdXApLCBkYXRhID0gZGF0YV9mcmFtZSkKYGBgCgojIyBSYW5kb20gaW50ZXJjZXB0cyAmIHNsb3BlcwoKTm93IGNvbnNpZGVyIGEgbW9kZWwgZm9yIGFuIG9ic2VydmF0aW9uICRpJCBmcm9tIGdyb3VwICRqJCAkKHlfe2lqfSkkIHRoYXQgaW5jbHVkZXMgcmFuZG9tIGVmZmVjdHMgZm9yIGJvdGggdGhlIGVmZmVjdCAoc2xvcGUpIG9mICR4JCAkKFxiZXRhXzEgKyBcZGVsdGFfaikkIGFuZCB0aGUgZ3JvdXAtbGV2ZWwgaW50ZXJjZXB0cyAkKFxiZXRhXzAgKyBcYWxwaGFfaikkLCBzdWNoIHRoYXQKCiQkCnlfe2lqfSA9IChcYmV0YV8wICsgXGFscGhhX2opICsgKFxiZXRhXzEgKyBcZGVsdGFfaikgeF97aWp9ICsgXGVwc2lsb25fe2lqfSBcXApcYWxwaGFfe2p9IFxzaW0gXHRleHR7Tn0oMCwgXHNpZ21hX1xhbHBoYV4yKSBcXApcZGVsdGFfe2p9IFxzaW0gXHRleHR7Tn0oMCwgXHNpZ21hX1xkZWx0YV4yKSBcXApcZXBzaWxvbl97aWp9IFxzaW0gXHRleHR7Tn0oMCwgXHNpZ21hX1xlcHNpbG9uXjIpCiQkCgpIZXJlIGFnYWluLCByZXdyaXRpbmcgdGhpcyBtb2RlbCBieSBzZXBhcmF0aW5nIHRoZSBmaXhlZCBhbmQgcmFuZG9tIHRlcm1zIG1ha2VzIGl0IGVhc2llciB0byBzZWUgaG93IGl0IGFsaWducyB3aXRoIHRoZSBgbG1lcigpYCBub3RhdGlvbi4KCiQkClxiZWdpbnthbGlnbmVkfQp5X3tpan0gJj0gKFxiZXRhXzAgKyBcYWxwaGFfaikgKyAoXGJldGFfMSArIFxkZWx0YV9qKSB4X3tpan0gKyBcZXBzaWxvbl97aWp9IFxcCiAgICAgICAmPSBcYmV0YV8wICsgXGFscGhhX2ogKyBcYmV0YV8xIHhfe2lqfSArIFxkZWx0YV9qIHhfe2lqfSArIFxlcHNpbG9uX3tpan0gXFwKICAgICAgICY9IFxiZXRhXzAgKyBcYmV0YV8xIHhfe2lqfSArIChcYWxwaGFfaiArIFxkZWx0YV9qIHhfe2lqfSkgKyBcZXBzaWxvbl97aWp9IFxcClxlbmR7YWxpZ25lZH0KJCQKCkFzc3VtaW5nIHRoZSBkYXRhIGB5YCwgcHJlZGljdG9yIGB4YCBhbmQgZ3JvdXAgSUQgYGdyb3VwYCBhcmUgY29udGFpbmVkIGluIGBkYXRhX2ZyYW1lYCwgd2Ugd291bGQgZml0IHRoaXMgbW9kZWwgdXNpbmcKCmBgYApsbWVyKHkgfiAxICsgeCArICgxICsgeCB8fCBncm91cCksIGRhdGEgPSBkYXRhX2ZyYW1lKQpgYGAKCndoZXJlIHRoZSBgMSArIHhgIHJlcHJlc2VudHMgdGhlIGZpeGVkIGludGVyY2VwdCBhbmQgc2xvcGUgYW5kIGAoMSArIHggfHwgZ3JvdXApYCByZXByZXNlbnRzIHRoZSAkXGFscGhhX2okIGFuZCAkXGRlbHRhX2okIChpZSwgcmFuZG9tIGludGVyY2VwdHMgYW5kIHNsb3BlcyBmb3IgZWFjaCBncm91cCkuIEhlcmUgd2UgdXNlIHRoZSBkb3VibGUgcGlwZSBgfHxgIGluIHRoZSByYW5kb20gZWZmZWN0IGJlY2F1c2Ugd2UgZG9uJ3Qgd2FudCB0aGUgaW50ZXJjZXB0IGFuZCBzbG9wZSB0byBiZSBjb3JyZWxhdGVkIHdpdGggb25lIGFub3RoZXIuIEp1c3QgYXMgd2l0aCBgbG0oKWAsIHdlIGNhbiBkcm9wIHRoZSBgMSArYCBmb3IgYm90aCB0aGUgRkUgYW5kIFJFIHRlcm1zLCBzdWNoIHRoYXQKCmBgYApsbWVyKHkgfiB4ICsgKHggfHwgZ3JvdXApLCBkYXRhID0gZGF0YV9mcmFtZSkKYGBgCgojIE1vZGVsIGZpdHRpbmcgJiBldmFsdWF0aW9uCgpCZWZvcmUgd2UgZml0IGFueSBtb2RlbHMsIGxldCdzIGJlZ2luIGJ5IHRoaW5raW5nIGFib3V0IHRoZSBkYXRhLiBJbiB0aGlzIGNhc2Ugd2UgaGF2ZSBzdXJ2ZXlzIGZyb20gZGlmZmVyZW50IGxvY2F0aW9ucyBhcm91bmQgUHVnZXQgU291bmQsIGFuZCB0aG9zZSBsb2NhdGlvbnMgYXJlIGJ1dCBhIGZldyBvZiB0aGUgcG9zc2libGUgc2l0ZXMgdGhhdCBtaWdodCBoYXZlIGJlZW4gc3VydmV5ZWQgKGllLCB0aGV5IGRvIG5vdCByZXByZXNlbnQgdGhlIGVudGlyZXR5IG9mIGF2YWlsYWJsZSBoYWJpdGF0KS4gVGh1cywgaXQgc291bmRzIGxpa2Ugd2Ugc2hvdWxkIHRyZWF0IGBzaXRlYCBhcyBhIHJhbmRvbSBlZmZlY3QuCgpUaGVzZSBkYXRhIHdlcmUgYWxzbyBjb2xsZWN0ZWQgb3ZlciB0aW1lLCB3aGljaCBzdWdnZXN0cyB0aGF0IHBlcmhhcHMgYSBtb2RlbCB3aXRoIGFuIGV4cGxpY2l0IGFjY291bnRpbmcgZm9yIHRpbWUgd291bGQgYmUgZ29vZC4gT25lIG9wdGlvbiB3b3VsZCBiZSB0byB0cmVhdCBgeWVhcmAgYXMgYSByYW5kb20gZWZmZWN0LCBhcyB3ZSdyZSBub3QgcGFydGljdWxhcmx5IGludGVyZXN0ZWQgaW4gdGhlIHNwZWNpZmljIGVmZmVjdCBvZiBhbnkgb25lIHllYXIuIAoKIyMgUmFuZG9tIGVmZmVjdCBvZiBzaXRlCgpMZXQncyBmaXJzdCBmaXQgYSBtb2RlbCB3aXRoIGEgcmFuZG9tIGVmZmVjdCBmb3Igc2l0ZSBvbmx5ICRzJCBhbmQgaWdub3JlIHRoZSB0ZW1wb3JhbCBhc3BlY3Qgb2YgdGhlIGRhdGEuIFRoaXMgaXMgYWtpbiB0byB0aGUgQU5PVkEgbW9kZWwgYWJvdmUsIHN1Y2ggdGhhdAoKJCQKeV97cyx0fSA9IFxtdSArIFxhbHBoYV9zICsgXGVwc2lsb25fe3MsdH0gXFwKXGFscGhhX3tzfSBcc2ltIFx0ZXh0e059KDAsIFxzaWdtYV9cYWxwaGFeMikgXFwKXGVwc2lsb25fe3MsdH0gXHNpbSBcdGV4dHtOfSgwLCBcc2lnbWFfXGVwc2lsb25eMikKJCQKCmFuZCAkXGFscGhhX2okIGlzIHRoZSByYW5kb20gZWZmZWN0IG9mIGBzaXRlYC4KCmBgYHtyIGZpdF9yZV9zaXRlfQojIyBsb2FkIGxtZTQgcGFja2FnZQpsaWJyYXJ5KGxtZTQpCgojIyBmaXQgbW9kZWwgd2l0aCBSRSBmb3Igc2l0ZQptb2Rfc2l0ZSA8LSBsbWVyKGluZGV4IH4gMSArICgxIHwgc2l0ZSksIGRhdGEgPSBkZikKCiMjIG1vZGVsIHN1bW1hcnkKc3VtbWFyeShtb2Rfc2l0ZSkKYGBgCgpOb3RpY2UgdGhhdCB0aGlzIG1vZGVsIHN1bW1hcnkgaW5mbyBpcyBzb21ld2hhdCBkaWZmZXJlbnQgdGhhdCB3aGF0IHdlJ3ZlIGJlZW4gc2VlaW5nIGZyb20gYGxtKClgLiBJbiBwYXJ0aWN1bGFyLCB0aGVyZSBhcmUgMiBkaWZmZXJlbnQgYmxvY2tzIG9mIHJlc3VsdHM6IG9uZSBmb3IgdGhlIHJhbmRvbSBlZmZlY3Qgb2YgYHNpdGVgIGFuZCB0aGUgcmVzaWR1YWwgZXJyb3JzLCBhbmQgYW5vdGhlciBmb3IgdGhlIGZpeGVkIGVmZmVjdCBvZiBhIGdsb2JhbCBtZWFuIGAoSW50ZXJjZXB0KWAuCgpBbHNvIG5vdGljZSB0aGF0IHRoZXJlIGFyZSBubyAkcCQtdmFsdWVzIGluIHRoaXMgb3V0cHV0LiBBcyB3ZSBkaXNjdXNzZWQgaW4gbGVjdHVyZSwgdGhpcyBpcyBiZWNhdXNlIGFueSBhc3N1bXB0aW9ucyBhYm91dCB0aGUgZGlzdHJpYnV0aW9uYWwgZm9ybSBvZiBvdXIgbnVsbCBoeXBvdGhlc2lzIHRlc3RzIGFyZSBsaWtlbHkgdG8gYmUgdmlvbGF0ZWQgd2hlbiBpbmNsdWRpbmcgcmFuZG9tIGVmZmVjdHMgaW4gdGhlIG1vZGVsLgoKIyMjIEVzdGltYXRlcyBvZiByYW5kb20gZWZmZWN0cwoKTm9ybWFsbHkgd2Ugd291bGQgdXNlIGBjb2VmKClgIHRvIGV4dHJhY3QgdGhlIGVzdGltYXRlZCBjb2VmZmljaWVudHMsIGJ1dCBpdCB3aWxsIHJldHVybiB0aGUgc3VtIG9mICRcbXUgKyBcYWxwaGFfaiQuIElmIHdlIGp1c3Qgd2FudCB0aGUgJFxhbHBoYV9qJCwgd2UgY2FuIGluc3RlYWQgdXNlIGByYW5lZigpYC4KCmBgYHtyIG1vZF9zaXRlX2NvZWZ9CiMjIG11ICsgYWxwaGEKY29lZihtb2Rfc2l0ZSkkc2l0ZQojIyBhbHBoYSBvbmx5CnJhbmVmKG1vZF9zaXRlKSRzaXRlCmBgYAoKIyMjIENvcnJlbGF0aW9uIGFtb25nIHJhbmRvbSBlZmZlY3RzCgpBcyB3ZSBsZWFybmVkIGluIGxlY3R1cmUsIHdlIGNhbiBlc3RpbWF0ZSB0aGUgY29ycmVsYXRpb24gYW1vbmcgdGhlIHJhbmRvbSBlZmZlY3RzIGFzCgokJApccmhvID0gXGZyYWN7XHNpZ21hX1xhbHBoYV4yfXtcc2lnbWFfXGFscGhhXjIgKyBcc2lnbWFfXGVwc2lsb25eMn0KJCQKCndoaWNoIHdlIGNhbiBjb21wdXRlIGZyb20gdGhlIGVzdGltYXRlcyBpbiB0aGUgYWJvdmUgdGFibGUuIFRoZSBmdW5jdGlvbiBgVmFyQ29ycigpYCB3aWxsIHJldHVybiB0aGUgcmVzdWx0cywgYnV0IHRoZXkgYXJlIGEgYml0IGhhcmQgdG8gYWNjZXNzIGRpcmVjdGx5LCBzbyB3ZSBjYW4gZW1iZWQgdGhhdCBjYWxsIGluc2lkZSBvZiBgYXMuZGF0YS5mcmFtZSgpYC4KCmBgYHtyIGZpdF9yZV9zaXRlX2Nvcn0KIyMgZ2V0IHZhcihSRSkKKHZhcl9yZV9zaXRlIDwtIGFzLmRhdGEuZnJhbWUoVmFyQ29ycihtb2Rfc2l0ZSkpKQojIyB2YXJpYW5jZSBvZiByYW5kb20gZWZmZWN0cwpzaWdtYTJfYWxwaGEgPC0gdmFyX3JlX3NpdGUkdmNvdlsxXQojIyB2YXJpYW5jZSBvZiByZXNpZHVhbHMKc2lnbWEyX2Vwc2lsb24gPC0gdmFyX3JlX3NpdGUkdmNvdlsyXQojIyBjYWxjdWxhdGUgdGhlIGNvcnJlbGF0aW9uIGFtb25nIFJFJ3MKcmhvIDwtIHNpZ21hMl9hbHBoYSAvIChzaWdtYTJfYWxwaGEgKyBzaWdtYTJfZXBzaWxvbikKcm91bmQocmhvLCAyKQpgYGAKCkl0IGxvb2tzIGxpa2UgdGhlcmUgaXMgbm90IGEgbG90IG9mIGNvcnJlbGF0aW9uIGFtb25nIHRoZSByYW5kb20gZWZmZWN0cy4gV2Ugc2hvdWxkIGFsc28gbm90ZSB0aGF0ICRccmhvJCBwcm92aWRlcyB1cyB3aXRoIGFuIGVzdGltYXRlIG9mIHRoZSBwcm9wb3J0aW9uIG9mIHRoZSB2YXJpYW5jZSBleHBsYWluZWQgYnkgdGhlIHJhbmRvbSBlZmZlY3RzIChzaW1pbGFyIHRvICRSXjIkIGZvciB0aGUgZml4ZWQgZWZmZWN0cykuCgojIyBSYW5kb20gZWZmZWN0IG9mIHllYXIKCk5vdyBsZXQncyBmaXQgYW5vdGhlciBtb2RlbCB0aGF0IG9ubHkgaW5jbHVkZXMgdGhlIHJhbmRvbSBlZmZlY3Qgb2YgYHllYXJgICR0JCwgd2hlcmUKCiQkCnlfe3MsdH0gPSBcbXUgKyBcYWxwaGFfdCArIFxlcHNpbG9uX3tzLHR9IFxcClxhbHBoYV97dH0gXHNpbSBcdGV4dHtOfSgwLCBcc2lnbWFfXGFscGhhXjIpIFxcClxlcHNpbG9uX3tzLHR9IFxzaW0gXHRleHR7Tn0oMCwgXHNpZ21hX1xlcHNpbG9uXjIpCiQkCgphbmQgJFxhbHBoYV90JCBpcyBub3cgdGhlIHJhbmRvbSBlZmZlY3Qgb2YgYHllYXJgLgoKYGBge3IgZml0X3JlX3llYXJ9CiMjIGZpdCBtb2RlbCB3aXRoIFJFIGZvciB5ZWFyCm1vZF95ZWFyIDwtIGxtZXIoaW5kZXggfiAxICsgKDEgfCB5ZWFyKSwgZGF0YSA9IGRmKQoKIyMgbW9kZWwgc3VtbWFyeQpzdW1tYXJ5KG1vZF95ZWFyKQpgYGAKCiMjIyBFc3RpbWF0ZXMgb2YgcmFuZG9tIGVmZmVjdHMKCkhlcmUgYXJlIHRoZSBlc3RpbWF0ZXMgb2YgdGhlICRcYWxwaGFfdCQuCgpgYGB7ciBtb2RfeWVhcl9jb2VmfQojIyBhbHBoYSBvbmx5CnJhbmVmKG1vZF95ZWFyKSR5ZWFyCmBgYAoKRG8geW91IG5vdGljZSBhbnl0aGluZyBhYm91dCB0aGVzZSByYW5kb20gZWZmZWN0cyBmb3IgeWVhcj8gVGhlIGFwcGVhciB0byBiZSBpbmNyZWFzaW5nIG92ZXIgdGltZSwgc3VjaCB0aGF0IHRoZSBlc3RpbWF0ZSBmb3IgMjAwMCBpcyBgciByb3VuZChyYW5lZihtb2RfeWVhcikkeWVhclsxLDFdLCAyKWAgYW5kIHRoZSBlc3RpbWF0ZSBmb3IgMjAxOCBpcyBgciByb3VuZChyYW5lZihtb2RfeWVhcikkeWVhcltuX3lycywxXSwgMilgLgoKIyMjIENvcnJlbGF0aW9uIGFtb25nIHJhbmRvbSBlZmZlY3RzCgpIZXJlIGlzIHRoZSBjb3JyZWxhdGlvbiBhbW9uZyB0aGUgcmFuZG9tIGVmZmVjdHMgZm9yIHllYXIuCgpgYGB7ciBmaXRfcmVfeWVhcl9jb3J9CiMjIGdldCB2YXIoUkUpCih2YXJfcmVfeWVhciA8LSBhcy5kYXRhLmZyYW1lKFZhckNvcnIobW9kX3llYXIpKSkKIyMgdmFyaWFuY2Ugb2YgcmFuZG9tIGVmZmVjdHMKc2lnbWEyX2FscGhhIDwtIHZhcl9yZV95ZWFyJHZjb3ZbMV0KIyMgdmFyaWFuY2Ugb2YgcmVzaWR1YWxzCnNpZ21hMl9lcHNpbG9uIDwtIHZhcl9yZV95ZWFyJHZjb3ZbMl0KIyMgY2FsY3VsYXRlIHRoZSBjb3JyZWxhdGlvbiBhbW9uZyBSRSdzCnJobyA8LSBzaWdtYTJfYWxwaGEgLyAoc2lnbWEyX2FscGhhICsgc2lnbWEyX2Vwc2lsb24pCnJvdW5kKHJobywgMikKYGBgCgpIZXJlLCB0b28sIHRoZXJlIGlzIG5vdCBhIGxvdCBvZiBjb3JyZWxhdGlvbiBhbW9uZyB0aGUgcmFuZG9tIGVmZmVjdHMuCgoKIyMgUmFuZG9tIGVmZmVjdHMgZm9yIHNpdGUgJiB5ZWFyCgpOb3cgbGV0J3MgZml0IGEgbW9kZWwgdGhhdCBpbmNsdWRlcyByYW5kb20gZWZmZWN0cyBmb3IgYm90aCBgc2l0ZWAgYW5kIGB5ZWFyYCwgd2hlcmUKCiQkCnlfe3MsdH0gPSBcbXUgKyBcYWxwaGFfcyArIFxhbHBoYV90ICsgXGVwc2lsb25fe3MsdH0gXFwKXGFscGhhX3tzfSBcc2ltIFx0ZXh0e059KDAsIFxzaWdtYV97XGFscGhhX3N9XjIpIFxcClxhbHBoYV97dH0gXHNpbSBcdGV4dHtOfSgwLCBcc2lnbWFfe1xhbHBoYV90fV4yKSBcXApcZXBzaWxvbl97cyx0fSBcc2ltIFx0ZXh0e059KDAsIFxzaWdtYV9cZXBzaWxvbl4yKQokJAoKYW5kICRcYWxwaGFfdCQgaXMgbm93IHRoZSByYW5kb20gZWZmZWN0IG9mIGB5ZWFyYC4KCmBgYHtyIGZpdF9zaXRlX3llYXJ9CiMjIG1vZGVsIHdpdGggUkUncyBmb3IgYm90aCBzaXRlIGFuZCB5ZWFyCm1vZF9zaXRlX3llYXIgPC0gbG1lcihpbmRleCB+IDEgKyAoMSB8IHNpdGUpICsgKDEgfCB5ZWFyKSwgZGYpCgojIyBtb2RlbCBzdW1tYXJ5CnN1bW1hcnkobW9kX3NpdGVfeWVhcikKYGBgCgpIZXJlIHdlIGNhbiBzZWUgdGhhdCB0aGUgcmVzaWR1YWwgdmFyaWFuY2UgJFxzaWdtYV4yJCBoYXMgZGVjcmVhc2VkIHF1aXRlIGEgYml0IGNvbXBhcmVkIHRvIG91ciBvdGhlciBtb2RlbHMuIFdlIGNhbiBjaGVjayBob3cgbXVjaCBvZiB0aGUgdG90YWwgdmFyaWFuY2UgaXMgZXhwbGFpbmVkIGJ5IHRoZSBjb21iaW5hdGlvbiBvZiB0aGUgdHdvIHJhbmRvbSBlZmZlY3RzIGFzIGZvbGxvd3M6CgpgYGB7ciBmaXRfcmVfc2l0ZV95ZWFyX2Nvcn0KIyMgZ2V0IHZhcihSRSkKdmFyX3JlX3NpdGVfeWVhciA8LSBhcy5kYXRhLmZyYW1lKFZhckNvcnIobW9kX3NpdGVfeWVhcikpCiMjIHZhcmlhbmNlIG9mIHNpdGUgcmFuZG9tIGVmZmVjdHMKc2lnbWEyX2FscGhhX3MgPC0gdmFyX3JlX3NpdGVfeWVhciR2Y292WzFdCiMjIHZhcmlhbmNlIG9mIHllYXIgcmFuZG9tIGVmZmVjdHMKc2lnbWEyX2FscGhhX3QgPC0gdmFyX3JlX3NpdGVfeWVhciR2Y292WzJdCiMjIHZhcmlhbmNlIG9mIHJlc2lkdWFscwpzaWdtYTJfZXBzaWxvbiA8LSB2YXJfcmVfc2l0ZV95ZWFyJHZjb3ZbM10KIyMgY2FsY3VsYXRlIHRoZSBjb3JyZWxhdGlvbiBhbW9uZyBSRSdzCnJobyA8LSAoc2lnbWEyX2FscGhhX3MgKyBzaWdtYTJfYWxwaGFfdCkgLyAKICAgICAgIChzaWdtYTJfYWxwaGFfcyArIHNpZ21hMl9hbHBoYV90ICsgc2lnbWEyX2Vwc2lsb24pCnJvdW5kKHJobywgMikKYGBgCgojIyMgRXN0aW1hdGVzIG9mIHJhbmRvbSBlZmZlY3RzCgpIZXJlIGFyZSB0aGUgZXN0aW1hdGVzIG9mIHRoZSAkXGFscGhhX3MkIGFuZCAkXGFscGhhX3QkLgoKYGBge3IgbW9kX3NpdGVfeWVhcl9jb2VmfQojIyBhbHBoYSBvbmx5CnJhbmVmKG1vZF9zaXRlX3llYXIpCmBgYAoKIyBMaWtlbGlob29kIHJhdGlvIHRlc3RzCgpXZSBjYW4gdXNlIGxpa2VsaWhvb2QgcmF0aW8gdGVzdHMgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgdGhlcmUgaXMgc3VwcG9ydCBmb3IgYW55IGdpdmVuIHJhbmRvbSBlZmZlY3QgaW4gYSBtb2RlbC4gVGhlc2UgdGVzdHMgcmVxdWlyZSBhIHNpbXVsYXRpb24tYmFzZWQgYXBwcm9hY2ggdGhhdCBpbnZvbHZlcyBhIHNlYXJjaCBvdmVyIGEgbGFyZ2UgZ3JpZGRlZCBzcGFjZSBvZiByYXRpb3Mgb2YgJFxzaWdtYV9cYWxwaGFeMiAvIFxzaWdtYV9cZXBzaWxvbl4yJC4gRm9yIG1vcmUgaW5mb3JtYXRpb24sIHNlZSBbQ3JhaW5pY2VhbnUgJiBSdXBwZXJ0ICgyMDA0KV0oaHR0cHM6Ly9kb2kub3JnLzEwLjExMTEvai4xNDY3LTk4NjguMjAwNC4wMDQzOC54KS4KClRvIGNvbmR1Y3QgdGhlc2UgdGVzdHMsIHdlJ2xsIHVzZSB0aGUgYGV4YWN0UkxSVCgpYCBmdW5jdGlvbiBmcm9tIHRoZSBbKipSTFJzaW0qKl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL1JMUnNpbS9pbmRleC5odG1sKSBwYWNrYWdlLgoKIyMgU2luZ2xlIHJhbmRvbSBlZmZlY3QKClRoZSBmaXJzdCBvcHRpb24gY29tcGFyZXMgYSBtb2RlbCB3aXRoIGEgKnNpbmdsZSogcmFuZG9tIGVmZmVjdCB0byBhbiBpZGVudGljYWwgbW9kZWwgdGhhdCBsYWNrcyB0aGUgcmFuZG9tIGVmZmVjdC4gVGhlIG51bGwgaHlwb3RoZXNpcyBmb3IgdGhpcyB0ZXN0IGlzICRIXzAgOiBcdGV4dHtWYXJ9KFxhbHBoYSkgPSBcc2lnbWFfXGFscGhhXjIgPSAwJC4gVGhlIHRlc3Qgc3RhdGlzdGljIGlzIGdpdmVuIGJ5CgokJApcbGFtYmRhID0gMiBcbG9nIFxtYXRoY2Fse0x9KFxzaWdtYV9cYWxwaGFeMiBcbmVxIDApIC0gMiBcbG9nIFxtYXRoY2Fse0x9KFxzaWdtYV9cYWxwaGFeMiA9IDApCiQkCgpMZXQncyBnbyBhaGVhZCBhbmQgdGVzdCBvdXIgMiBtb2RlbHMgd2l0aCByYW5kb20gZWZmZWN0cyBmb3IgYHNpdGVgIGFuZCBgeWVhcmAuIFRvIGNvbXBhcmUgb3VyIG1vZGVscyB3aXRoIGEgc2luZ2xlIHJhbmRvbSBlZmZlY3QsIHdlIHdpbGwgY29tcGFyZSB0aGVtIGFnYWluc3QgYSBmdWxsIG1vZGVsIHdpdGggYm90aCByYW5kb20gZWZmZWN0cy4gVG8gZG8gc28sIHdlIG5lZWQgMyBkaWZmZXJlbnQgbW9kZWxzOgoKMSkgbW9kZWwgd2l0aCBzaW5nbGUgUkUgb2YgaW50ZXJlc3QgdG8gYmUgdGVzdGVkIChgbW9kZWxfQWApCgoyKSBmdWxsIG1vZGVsIHdpdGggMisgUkUncyAoYG1vZGVsX0FCYCkKCjMpIGZ1bGwgbW9kZWwgbWludXMgdGhlIFJFIGluIG1vZGVsICgxKSAoYG1vZGVsX0JgKQoKVG8gY29uZHVjdCB0aGUgdGVzdCB3ZSB1c2UgYGV4dHJhY3RSTFJUKG1vZGVsX0EsIG1vZGVsX0FCLCBtb2RlbF9CKWAuCgpgYGB7ciBMUlRfc2l0ZSwgd2FybmluZz1GQUxTRX0KIyMgbG9hZCBSTFJzaW0gcGFja2FnZQpsaWJyYXJ5KFJMUnNpbSkKCiMjIHRlc3QgYHNpdGVgIG1vZGVsCmV4YWN0UkxSVChtb2Rfc2l0ZSwgbW9kX3NpdGVfeWVhciwgbW9kX3llYXIpCmBgYAoKV2UgY2FuIGNsZWFybHkgcmVqZWN0ICRIXzAgOiBcc2lnbWFfe1xhbHBoYV9zfV4yID0gMCQgYW5kIGNvbmNsdWRlIHRoYXQgdGhlcmUgaXMgc3VwcG9ydCBmb3IgaW5jbHVzaW9uIG9mIHRoZSBgc2l0ZWAgcmFuZG9tIGVmZmVjdC4KCk5vdyBsZXQncyBnbyBhaGVhZCBhbmQgdGVzdCB0aGUgbW9kZWwgd2l0aCBhIHNpbmdsZSByYW5kb20gZWZmZWN0IGZvciBgeWVhcmAuCgpgYGB7ciBMUlRfeWVhciwgd2FybmluZz1GQUxTRX0KIyMgdGVzdCBgeWVhcmAgbW9kZWwKZXhhY3RSTFJUKG1vZF95ZWFyLCBtb2Rfc2l0ZV95ZWFyLCBtb2Rfc2l0ZSkKYGBgCgpXZSBjYW4gY2xlYXJseSByZWplY3QgJEhfMCA6IFxzaWdtYV97XGFscGhhX3R9XjIgPSAwJCBhbmQgY29uY2x1ZGUgdGhhdCB0aGVyZSBpcyBzdXBwb3J0IGZvciBpbmNsdXNpb24gb2YgdGhlIGB5ZWFyYCByYW5kb20gZWZmZWN0LgoKIyMgTXVsdGlwbGUgcmFuZG9tIGVmZmVjdHMKCldlIGNhbiB1c2UgYSBib290c3RyYXBwaW5nIGFwcHJvYWNoIHRvIHRlc3QgZm9yIGV2aWRlbmNlIGFnYWluc3QgaW5jbHVkaW5nIG11bHRpcGxlIHJhbmRvbSBlZmZlY3RzIGluIHRoZSBzYW1lIG1vZGVsLiBPdXIgYXBwcm9hY2ggZm9sbG93cyB0aGlzIHBzZXVkby1jb2RlOgoKMS4gZml0IG51bGwgbW9kZWwgd2l0aCBubyByYW5kb20gZWZmZWN0cwoKMi4gY2FsY3VsYXRlIGxpa2VsaWhvb2QgcmF0aW8gc3RhdGlzdGljCgozLiBzaW11bGF0ZSBkYXRhIGZyb20gdGhlIG51bGwgbW9kZWwgaW4gKDEpCgo0LiBmaXQgc2ltcGxlICYgZnVsbCBtb2RlbCB0byBkYXRhIGZyb20gKDMpCgo1LiBjYWxjdWxhdGUgbGlrZWxpaG9vZCByYXRpbyAoZGlmZmVyZW5jZSBpbiBsb2ctbGlrZWxpaG9vZCkKCjYuIHJlcGVhdHMgc3RlcHMgMy01ICptYW55KiB0aW1lcwoKNy4gc2VlIHdoZXJlIHN0YXRpc3RpYyBmcm9tICgyKSBmYWxscyB3aXRoaW4gZXN0aW1hdGVkIGRpc3RyaWJ1dGlvbiBmcm9tICgzLTYpCgoKSW1wb3J0YW50bHksIHRvbywgd2UgbmVlZCB0byBzcGVjaWZ5IHRoYXQgdGhlIHJhbmRvbSBlZmZlY3RzIG1vZGVsIGJlIGZpdCB1c2luZyBtYXhpbXVtIGxpa2VsaWhvb2QgKE1MKSBpbnN0ZWFkIG9mIHRoZSBkZWZhdWx0ICpyZXN0cmljdGVkKiBtYXhpbXVtIGxpa2VsaWhvb2QgKFJFTUwpLgoKYGBge3IgYm9vdHN0cmFwcGluZywgd2FybmluZyA9IEZBTFNFfQojIyBzZXQgcmFuZG9tIHNlZWQgdG8gbWFrZSBpdCByZXByb2R1Y2libGUKc2V0LnNlZWQoNTE0KQoKIyMgU3RlcCAxOiBmaXQgbnVsbCBtb2RlbCB3aXRoIG5vIFJFJ3MgdXNpbmcgYGxtKClgCm51bGxfbW9kZWwgPC0gbG0oaW5kZXggfiAxLCBkYXRhID0gZGYpCgojIyBTdGVwIDI6IGNhbGN1bGF0ZSBsaWtlbGlob29kIHJhdGlvIChpZSwgZGlmZmVyZW5jZSBpbiBsb2ctbGlrZWxpaG9vZCkKbGFtYmRhIDwtIDIgKiAobG9nTGlrKG1vZF9zaXRlX3llYXIpIC0gbG9nTGlrKG51bGxfbW9kZWwpKQoKIyMgbnVtYmVyIG9mIGJvb3RzdHJhcHBlZCBzYW1wbGVzCm5iIDwtIDEwMDAKIyMgZW1wdHkgdmVjdG9yIGZvciBzdG9yaW5nIExSVCBzdGF0aXN0aWNzCkxSVF9ib290IDwtIHJlcChOQSwgbmIpCiMjIGRvIGJvb3RzdHJhcHBpbmcKZm9yKGkgaW4gMTpuYikgewogICMjIFN0ZXAgMzogc2ltdWxhdGUgZGF0YSBmcm9tIG51bGwgbW9kZWwKICBzaW1fZGF0YSA8LSB1bmxpc3Qoc2ltdWxhdGUobnVsbF9tb2RlbCkpCiAgIyMgU3RlcCA0OiBmaXQgbnVsbCBhbmQgUkUgbW9kZWxzIHRvIHNpbSBkYXRhCiAgbV9udWxsIDwtIGxtKHNpbV9kYXRhIH4gMSkKICBtX2FsdCA8LSBsbWVyKHNpbV9kYXRhIH4gMSArICgxIHwgc2l0ZSkgKyAoMSB8IHllYXIpLCBkYXRhID0gZGYsIFJFTUwgPSBGQUxTRSkKICAjIyBTdGVwIDU6IGNhbGN1bGF0ZSBsaWtlbGlob29kIHJhdGlvCiAgTFJUX2Jvb3RbaV0gPC0gYXMubnVtZXJpYygyKihsb2dMaWsobV9hbHQpIC0gbG9nTGlrKG1fbnVsbCkpKQogICMjIFN0ZXAgNjogcmVwZWF0IHRoaXMgYG5iYCB0aW1lcwp9CiMjIFN0ZXAgNzogY2FsY3VsYXRlIGFwcHJveGltYXRlIHAtdmFsdWUKbWVhbihMUlRfYm9vdCA+IGxhbWJkYSkKYGBgCgpIZXJlIGl0IGFwcGVhcnMgYXMgdGhvdWdoIG5vbmUgb2YgdGhlIGByIG5iYCBib290c3RyYXBwZWQgc2FtcGxlcyBoYWQgYSB0ZXN0IHN0YXRpc3RpYyBsYXJnZXIgdGhhbiB0aGUgb3JpZ2luYWwgdmFsdWUgb2YgYHIgcm91bmQobGFtYmRhLDEpYC4KCiMgTW9kZWwgZGlhZ25vc3RpY3MKCldlIHdvdWxkIGJlIHJlbWlzcyBpZiB3ZSBkaWQgbm90IGRvIHNvbWUgZGlhZ25vc3RpYyBjaGVja3Mgb24gb3VyIG1vZGVsLiBPbmUgb2Ygb3VyIGFzc3VtcHRpb25zIGlzIHRoYXQgdGhlIHJlc2lkdWFscyAkXGVwc2lsb24kIGFuZCByYW5kb20gZWZmZWN0cyAkXGFscGhhJCBhcmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQsIHdoaWNoIHdlIGNhbiBjaGVjayB3aXRoIFEtUSBwbG90cy4gTGV0J3MgZG8gc29tZSBkaWFnbm9zdGljIGNoZWNrcyBmb3IgdGhlIG1vZGVsIHdpdGggcmFuZG9tIGVmZmVjdHMgZm9yIGJvdGggYHNpdGVgIGFuZCBgeWVhcmAuCgojIyBRLVEgcGxvdHMKCmBgYHtyIHJlX2RpYWdub3N0aWNzLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD00LCBmaWcuYWxpZ249J2NlbnRlcid9CiMjIHNldCBwbG90IGFyZWEKcGFyKG1haSA9IGMoMC45LCAwLjksIDAuNiwgMC4xKSwKICAgIG9taSA9IGMoMCwgMCwgMCwgMCksCiAgICBtZnJvdyA9IGMoMSwyKSwgY2V4LmxhYiA9IDEuMikKCiMjIHFxIHJlc2lkcwpxcW5vcm0ocmVzaWR1YWxzKG1vZF9zaXRlX3llYXIpLCBtYWluID0gIlFRIHBsb3QgKHJlc2lkdWFscykiLCBsYXMgPSAxLCBwY2ggPSAxNikKcXFsaW5lKHJlc2lkdWFscyhtb2Rfc2l0ZV95ZWFyKSkKCiMjIHFxIFJFJ3MKcXFub3JtKHVubGlzdChyYW5lZihtb2Rfc2l0ZV95ZWFyKSksIG1haW4gPSAiUVEgcGxvdCAoUkUncykiLCBsYXMgPSAxLCBwY2ggPSAxNikKcXFsaW5lKHVubGlzdChyYW5lZihtb2Rfc2l0ZV95ZWFyKSkpCmBgYAoKVGhlc2UgcGxvdHMgYm90aCBsb29rIHByZXR0eSBnb29kLiBQZXJoYXBzIHRoZXJlIGlzIHNvbWUgZGV2aWF0aW9uIGZyb20gbm9ybWFsaXR5IGZvciB0aGUgcmFuZG9tIGVmZmVjdHMsIGJ1dCB0aGVyZSBhcmUgbm90IG1hbnkgdmFsdWVzIGZyb20gd2hpY2ggdG8gYXNjZXJ0YWluIHdoZXRoZXIgb3Igbm90IHRoZSBhc3N1bXB0aW9uIG9mIG5vcm1hbGl0eSBoYXMgYmVlbiB2aW9sYXRlZC4KCiMjIFJlc2lkdWFscyB2ZXJzdXMgZml0dGVkCgpXZSBjYW4gYWxzbyBwbG90IHRoZSBtb2RlbCByZXNpZHVhbHMgYWdhaW5zdCB0aGUgZml0dGVkIHZhbHVlcyB0byBsb29rIGZvciBldmlkZW5jZSBvZiBoZXRlcm9zY2VkYXN0aWNpdHkgb3Igbm9uLWxpbmVhcml0eSBpbiB0aGUgcmVzaWR1YWxzLgoKYGBge3IgcmVfZGlhZ25vc3RpY3NfMiwgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9NC41LCBmaWcuYWxpZ249J2NlbnRlcid9CiMjIHJlc2lkcyB2cyBmaXR0ZWQKcGxvdChmaXR0ZWQobW9kX3NpdGVfeWVhciksIHJlc2lkdWFscyhtb2Rfc2l0ZV95ZWFyKSwgbGFzID0gMSwgcGNoID0gMTYsCiAgICAgeGxhYiA9ICJGaXR0ZWQiLCB5bGFiID0gIlJlc2lkdWFscyIsCiAgICAgbWFpbiA9ICJSZXNpZHVhbHMgdnMgZml0dGVkIikKYWJsaW5lKGg9MCwgbHR5ID0gImRhc2hlZCIpCmBgYAoKVGhpcyByZXNpZHVhbCBwbG90IGxvb2tzIHByb21pc2luZyBpbiB0aGF0IHRoZXJlIGFyZSBubyBvYnZpb3VzIHBhdHRlcm5zIHRvIHRoZSByZXNpZHVhbHMuCgojIyBBdXRvY29ycmVsYXRpb24KCkJlY2F1c2UgdGhlc2UgZGF0YSB3ZXJlIGNvbGxlY3RlZCBvdmVyIHRpbWUsIHdlIHNob3VsZCBiZSBhd2FyZSBvZiBwb3NzaWJsZSBhdXRvY29ycmVsYXRpb24gYW1vbmcgdGhlIHJlc2lkdWFscy4gSXQgd291bGQgYmUgYSBiaXQgbWVzc3kgdG8gY3JlYXRlIHBsb3RzIGZvciBhbGwgOSBvZiB0aGUgdGltZSBzZXJpZXMsIHNvIHdlJ2xsIGp1c3QgZ2V0IGEgdGFibGUgb2YgdGhlIHJlc3VsdHMgZnJvbSBgYWNmKClgIGFuZCBzZWUgd2hldGhlciBhbnkgb2YgdGhlbSBleGNlZWQgdGhlIGNyaXRpY2FsIHZhbHVlIGdpdmVuIGJ5CgokJAowIFxwbSBcZnJhY3t6X3tcYWxwaGEvMn19e1xzcXJ0e259fQokJAoKd2hlcmUgJHpfe1xhbHBoYS8yfSQgaXMgdGhlICQxLVxhbHBoYS8yJCBxdWFudGlsZSBvZiB0aGUgc3RhbmRhcmQgbm9ybWFsIGRpc3RyaWJ1dGlvbi4gRm9yIGV4YW1wbGUsIGlmICRcYWxwaGEkID0gMC4wNSwgdGhlbiAkel97XGFscGhhLzJ9JCA9IDEuOTYuIEhlcmUgd2UnbGwgb25seSBleGFtaW5lIGNvcnJlbGF0aW9ucyBvdXQgdG8gYSBsYWcgb2YgNSB5ZWFycyBiZWNhdXNlIGl0J3MgdW5saWtlbHkgdGhhdCBjb3VudHMgaW4gdGhpcyB5ZWFyIHdvdWxkIGJlIHJlbGF0ZWQgdG8gY291bnRzIDYgb3IgbW9yZSB5ZWFycyBpbiB0aGUgcGFzdCAoYW5kIGhvcGVmdWxseSBub3QgYXQgYW55IHllYXJzIGluIHRoZSBwYXN0KS4KCmBgYHtyIGFjZn0KIyMgVHlwZS1JIGVycm9yCmFscGhhX2NyaXQgPC0gMC4wNQoKIyMgdGhyZXNob2xkIHZhbHVlIGZvciByaG8gKGNvcnJlbGF0aW9uKQoocmhvX2NyaXQgPC0gcW5vcm0oMSAtIGFscGhhX2NyaXQvMikgLyBzcXJ0KG5feXJzKSkKCiMjIHJlYXJyYW5nZSByZXNpZHVhbHMgaW50byBtYXRyaXgKcnIgPC0gbWF0cml4KHJlc2lkdWFscyhtb2Rfc2l0ZV95ZWFyKSwgbl95cnMsIG5fc2l0ZXMpCgojIyBnZXQgQUNGCkFDRiA8LSBhcHBseShyciwgMiwgYWNmLCBsYWcubWF4ID0gNSwgcGxvdCA9IEZBTFNFKQpBQ0YgPC0gbGFwcGx5KEFDRiwgZnVuY3Rpb24oeCkgeCRhY2YpCiMjIGNvbnZlcnQgbGlzdCB0byBtYXRyaXg7IGRvbid0IG5lZWQgcm93IDEgYi9jIHJob18wID0gMQpBQ0YgPC0gZG8uY2FsbChjYmluZCwgQUNGKVstMSxdCgojIyBjaGVjayBpZiBhbnkgfHZhbHVlc3wgPiByaG9fY3JpdAphbnkoYWJzKEFDRikgPiByaG9fY3JpdCkKYGBgCgpJdCBsb29rcyBsaWtlIHRoZSByYW5kb20gZWZmZWN0IGZvciB5ZWFyICRcYWxwaGFfdCQgbXVzdCBoYXZlIGRvbmUgYW4gYWRlcXVhdGUgam9iIG9mIGFjY291bnRpbmcgZm9yIGFueSBhdXRvY29ycmVsYXRpb24gaW4gdGhlIGRhdGEuCgojIE1peGVkIG1vZGVsIHdpdGggYSB0cmVuZAoKQm90aCBvdXIgcGxvdCBvZiB0aGUgcmF3IGRhdGEgYW5kIHRoZSByYW5kb20gZWZmZWN0cyBmb3IgeWVhciBzaG93ZWQgZXZpZGVuY2Ugb2YgYW4gaW5jcmVhc2luZyB0cmVuZCBpbiB0aGUgaW5kZXggb2YgYWJ1bmRhbmNlLiBMZXQncyBub3cgZml0IGEgbW9kZWwgdGhhdCBpbmNsdWRlcyBhICpmaXhlZCogZWZmZWN0IGZvciB5ZWFyIHRvIGFjY291bnQgZm9yIHRoaXMgYXBwYXJlbnQgdHJlbmQsIHBsdXMgcmFuZG9tIGVmZmVjdHMgZm9yIGJvdGggc2l0ZSBhbmQgeWVhci4gQXQgZmlyc3QgZ2xhbmNlLCBpdCBtaWdodCBzZWVtIHByb2JsZW1hdGljIHRvIGluY2x1ZGUgYm90aCBhIGZpeGVkIGFuZCByYW5kb20gZWZmZWN0IGZvciB5ZWFyLCBidXQgd2UgaGF2ZSBtdWx0aXBsZSBzaXRlcyBzYW1wbGVkIHBlciB5ZWFyLCBzbyB0aGUgZml4ZWQgZWZmZWN0IHdpbGwgZ2l2ZSB1cyB0aGUgb3ZlcmFsbCBsaW5lYXIgdHJlbmQgYWNyb3NzIGFsbCBzaXRlcywgYW5kIHRoZSByYW5kb20gZWZmZWN0IHdpbGwgYWxsb3cgZm9yIGFkZGl0aW9uYWwgdmFyaWF0aW9uIGFtb25nIHllYXJzIChpZSwgYWxsIHNpdGVzIGluIGEgZ2l2ZW4geWVhciBtYXkgYmUgZ3JlYXRlciBvciBsZXNzIHRoYW4gdGhlIGxvbmctdGVybSBhdmVyYWdlKS4gU3BlY2lmaWNhbGx5LCB0aGUgbW9kZWwgd2Ugd2FudCB0byBmaXQgaXMKCiQkCnlfe3MsdH0gPSBcYmV0YV8wICsgXGJldGFfMSB0ICsgXGFscGhhX3MgKyBcYWxwaGFfdCArIFxlcHNpbG9uX3tzLHR9IFxcClxhbHBoYV97c30gXHNpbSBcdGV4dHtOfSgwLCBcc2lnbWFfe1xhbHBoYV9zfV4yKSBcXApcYWxwaGFfe3R9IFxzaW0gXHRleHR7Tn0oMCwgXHNpZ21hX3tcYWxwaGFfdH1eMikgXFwKXGVwc2lsb25fe3MsdH0gXHNpbSBcdGV4dHtOfSgwLCBcc2lnbWFfXGVwc2lsb25eMikKJCQKCkxldCdzIGZpdCB0aGlzIG1vZGVsIGFuZCBjb21wYXJlIGl0IHRvIHRoZSBjb21wYXJhYmxlIG1vZGVsIHdlIGZpdCBlYXJsaWVyIHdpdGhvdXQgYSBmaXhlZCBlZmZlY3Qgb2YgYHllYXJgLgoKYGBge3IgZml0X3NpdGVfeWVhcl9mfQojIyBtb2RlbCB3aXRoIFJFJ3MgZm9yIGJvdGggc2l0ZSBhbmQgeWVhcgptb2Rfc2l0ZV95ZWFyX2YgPC0gbG1lcihpbmRleCB+IDEgKyB5ZWFyICsgKDEgfCBzaXRlKSArICgxIHwgeWVhciksIGRmKQoKIyMgbW9kZWwgc3VtbWFyeQpzdW1tYXJ5KG1vZF9zaXRlX3llYXJfZikKYGBgCgpZb3UgY2FuIHNlZSBmcm9tIHRoZSBzdW1tYXJ5IGluZm8gYWJvdmUgdGhhdCB0aGUgZml4ZWQgZWZmZWN0IG9mIGB5ZWFyYCBpcyB+MC4zOSwgd2hpY2ggbWVhbnMgdGhlIGluZGV4IG9mIGFidW5kYW5jZSBpcyBpbmNyZWFzaW5nIGJ5IH40IHVuaXRzIHBlciBkZWNhZGUuCgojIyBNb2RlbCBjb21wYXJpc29uCgpJbiB0aGlzIGNhc2Ugd2UgY2FuIHVzZSBBSUMgdG8gZGlyZWN0bHkgY29tcGFyZSB0aGVzZSBtb2RlbHMgYmVjYXVzZSB0aGV5IG9ubHkgZGlmZmVyIHdpdGggcmVzcGVjdCB0byB0aGUgZml4ZWQgZWZmZWN0IGZvciBgeWVhcmAuIEhvd2V2ZXIsIGJlZm9yZSBkb2luZyBzbywgd2UgbmVlZCB0byByZWZpdCBib3RoIG9mIHRoZSBtb2RlbHMgdXNpbmcgTUwgcmF0aGVyIHRoYW4gUkVNTC4gCgpgYGB7ciBjb21wYXJlX2Z1bGxfbW9kZWxzLCByZXN1bHRzID0gJ2hvbGQnfQojIyByZWZpdCBzaXRlICYgeWVhciBtb2RlbAptb2Rfc3lfbWwgPC0gbG1lcihpbmRleCB+IDEgKyAoMSB8IHNpdGUpICsgKDEgfCB5ZWFyKSwgZGYsIFJFTUwgPSBGQUxTRSkKIyMgcmVmaXQgCm1vZF9zeWZfbWwgPC0gbG1lcihpbmRleCB+IDEgKyB5ZWFyICsgKDEgfCBzaXRlKSArICgxIHwgeWVhciksIGRmLCBSRU1MID0gRkFMU0UpCiMjIGdldCBBSUMgZm9yIGJvdGggbW9kZWxzCkFJQyhtb2Rfc3lfbWwpCkFJQyhtb2Rfc3lmX21sKQpgYGAKClRoZSBBSUMgZm9yIHRoZSBtb2RlbCB3aXRoIGEgZml4ZWQgZWZmZWN0IG9mIHllYXIgaXMgfjI0IHVuaXRzIGxvd2VyIHRoYW4gdGhlIG1vcmUgc2ltcGxlIG1vZGVsLCB3aGljaCBpcyBpbmRlZWQgc3Ryb25nIGV2aWRlbmNlIGZvciB0aGUgaW5jbHVzaW9uIG9mIGB5ZWFyYCBhcyBhIGZpeGVkIGVmZmVjdC4gQW5vdGhlciBvcHRpb24gZm9yIGNvbXBhcmluZyBuZXN0ZWQgbW9kZWxzIHdpdGggdGhlIHNhbWUgcmFuZG9tIGVmZmVjdHMgc3RydWN0dXJlIGlzIGEgJFxjaGleMiQgdGVzdCB2aWEgYGFub3ZhKClgLCB3aGljaCBoYXMgdGhlIGFkZGVkIGFkdmFudGFnZSBvZiBhbHNvIHByb3ZpZGluZyBBSUMgYW5kIEJJQyB2YWx1ZXMgYXMgd2VsbC4gVG8gZG8gc28sIHdlIHVzZSBgYW5vdmEocmVkdWNlZCBtb2RlbCwgZnVsbCBtb2RlbClgLgoKYGBge3IgdGVzdF92aWFfYW5vdmF9CiMjIExSVCBmb3IgZml4ZWQgZWZmZWN0IG9mIGB5ZWFyYAphbm92YShtb2Rfc3lfbWwsIG1vZF9zeWZfbWwpCmBgYAoKIyBHZW5lcmFsIGNvbnNpZGVyYXRpb25zCgpIZXJlIGFyZSBzb21lIGdlbmVyYWwgZ3VpZGVsaW5lcyB0byBmb2xsb3cgd2hlbiBmaXR0aW5nIGFuZCBldmFsdWF0aW5nIG1peGVkIGVmZmVjdHMgbW9kZWxzLgoKIyMgRml4ZWQgZWZmZWN0cwoKWW91IHNob3VsZCB1c2UgbWF4aW11bSBsaWtlbGlob29kIChNTCkgd2hlbiBjb21wYXJpbmcgbW9kZWxzIHdpdGggZGlmZmVyZW50IGZpeGVkIGVmZmVjdHMsIGFzIE1MIGRvZXNu4oCZdCByZWx5IG9uIHRoZSBjb2VmZmljaWVudHMgb2YgdGhlIGZpeGVkIGVmZmVjdHMsIHdoZXJlYXMgUkVNTCBhc3N1bWVzIHRoYXQgdGhlIGZpeGVkIGVmZmVjdHMgYXJlIGFsbCBzZXQgYW5kIGNvcnJlY3QuIFRoYXQgc2FpZCwgeW91IHNob3VsZCB1bHRpbWF0ZWx5IHVzZSB0aGUgcGFyYW1ldGVyIGVzdGltYXRlcyBmcm9tIHlvdXIgZmluYWwgImJlc3QiIG1vZGVsIGFzIG9idGFpbmVkIHZpYSBSRU1MIGJlY2F1c2UgTUwgZXN0aW1hdGVzIG9mIHRoZSB2YXJpYW5jZXMgb2YgdGhlIHJhbmRvbSBlZmZlY3RzIHRlbmQgdG8gYmUgYmlhc2VkIGxvdy4KCiMjIFJhbmRvbSBlZmZlY3RzCgpZb3UgY2FuIHVzZSBtb2RlbCBzZWxlY3Rpb24gdG8gaGVscCB5b3UgZGVjaWRlIHdoaWNoIHJhbmRvbSBlZmZlY3RzIHRvIHJldGFpbiwgYnV0IGluIGdlbmVyYWwsICoqcmFuZG9tIGVmZmVjdHMgc2hvdWxkIGJlIGJhc2VkIHVwb24geW91ciBrbm93bGVkZ2Ugb2YgdGhlIHN5c3RlbSoqLiBGb3IgZXhhbXBsZSwgaXMgdGhlcmUgcHNldWRvcmVwbGljYXRpb24/IEFyZSB0aGUgZGF0YSBwYXJ0IG9mIGEgdGltZSBzZXJpZXMgb3Igc3BhdGlhbCBzYW1wbGluZyBkZXNpZ24/IEFzIHdlIHNhdyBhYm92ZSwgd2UgdXNlIFJFTUwgZXN0aW1hdG9ycyB0byBjb21wYXJlIG1vZGVscyB3aXRoIGRpZmZlcmVudCByYW5kb20gZWZmZWN0cy4KCiMjIEVudGlyZSBtb2RlbCBzZWxlY3Rpb24KClRoZSBtb3N0IGltcG9ydGFudCB0aGluZyBpcyB0byAqKm5vdCoqIHZhcnkgYm90aCByYW5kb20gYW5kIGZpeGVkIGVmZmVjdHMgYXQgdGhlIHNhbWUgdGltZS4gWW91IHNob3VsZCBhZGRyZXNzIG9uZSBvZiB0aGUgY29tcG9uZW50cyBhbmQgdGhlbiB0aGUgb3RoZXIsIG9mdGVuIGluIGEgYmFjay1hbmQtZm9ydGgtbWFubmVyLiBIZXJlIGlzIHRoZSBtb2RlbCBzZWxlY3Rpb24gcHJvY2VzcyByZWNvbW1lbmRlZCBieSBbWnV1ciBldCBhbC4gKDIwMDkpXShyZWZlcmVuY2VzL1p1dXJfMjAwOV9taXhlZF9lZmZlY3RzX21vZGVsc19pbl9SLnBkZik6CgoqIGZpdCB0aGUgbW9zdCBjb21wbGV4IG1vZGVsIHlvdSBjYW4gZW52aXNpb24gYmFzZWQgb24geW91ciBwb3NzaWJsZSBjb3ZhcmlhdGVzIGFuZCByYW5kb20gZWZmZWN0cwoKKiBzb3J0IG91dCB0aGUgcmFuZG9tIGVmZmVjdHMgc3RydWN0dXJlIHVzaW5nIFJFTUwtYmFzZWQgaW5mZXJlbmNlIHZpYSBBSUMgb3IgbGlrZWxpaG9vZCByYXRpbyB0ZXN0cwoKKiBzb3J0IG91dCB0aGUgZml4ZWQgZWZmZWN0cyBzdHJ1Y3R1cmUgKndoaWxlIGtlZXBpbmcgeW91ciByYW5kb20gZWZmZWN0cyBjb25zdGFudCogdXNpbmcgUkVNTCBhbmQgJEYkLSBvciAkdCQtdGVzdHMsIG9yIGNvbXBhcmUgbmVzdGVkIE1MIG1vZGVscyB2aWEgQUlDCgoqIHByZXNlbnQgdGhlIHJlc3VsdHMgb2YgeW91ciBmaW5hbCBtb2RlbCB1c2luZyBSRU1MIGVzdGltYXRpb24KCgo=