Go back to R doodles

My personal web page

My official USM web page

1 Researchers frequently report results as relative effects

For example,

“Male flies from selected lines had 50% larger upwind flight ability than male flies from control lines (Control mean: 117.5 cm/s; Selected mean 176.5 cm/s).”

where a relative effect is

\[\begin{equation} 100 \frac{\bar{y}_B - \bar{y}_A}{\bar{y}_A} \end{equation}\]

If we are to follow best practices, we should present this effect with a measure of uncertainty, such as a confidence interval. The absolute effect is 59.0 cm/s and the 95% CI of this effect is (48.7, 69.3 cm/s). But if we present the result as a relative effect, or percent difference from some reference value, how do we compute a “relative CI”?

2 Four methods to compute the standard error and CI of a relative effect

2.1 Naive relative confidence intervals

\[\begin{equation} relative\_CI = 100\frac{absolute\_CI}{\bar{y}_A} \end{equation}\]

For the fly example, the 95% naive relative CI is bounded by \(100\frac{48.7}{117.5} = 41.4\%\) and \(100\frac{69.3}{117.5} = 59.0\%\). These are easy to compute but wrong because the error in estimating a relative difference is a function of the error in estimating both the numerator (the absolute difference) and the denominator (the reference mean). The consequence is that naive relative confidence intervals are too narrow (or too optimistic, or suggest too much precision).

2.2 Back-transformed intervals from log-transformed data.

This post is motivated by the post The percent difference fallacy and a solution: the ratio t-test from Anthony Darrouzet-Nardi at Anthony’s Science blog. Anthony suggests a clever solution for a simple, linear model with a single factor with two levels (or a “t-test” design): the relative CIs are the backtransformed CIs of the effect of the log-transformed data.

  1. log transform the response variable
  2. run the linear model \(log(y) = b_0 + b_1 Treatment\)
  3. compute the CI of \(b_1\)
  4. backtransform using \(100(\mathrm{exp}(CI) - 1)\)

Let’s think about this.

  1. The coefficient \(b_1\) of the linear model of log transformed \(y\) is \(\overline{\mathrm{log}(y_B)} - \overline{\mathrm{log}(y_A)}\)
  2. This is the difference in the logs of the geometric means of group B and group A, where a geometric mean is
  3. \(GM=(\Pi y)^\frac{1}{n}\) and the log of a geometric mean is
  4. \(\mathrm{log}(GM) = \mathrm{log}((\Pi y)^\frac{1}{n}) = \frac{1}{n}\sum{\mathrm{log}(y)}\) (note that the typical way to compute a geometric mean is using a log transformation since this is unlikely to blow up to really big values)
  5. And because the difference of two logs is the log of their ratio, \(b_1 = \overline{\mathrm{log}(y_B)} - \overline{\mathrm{log}(y_A)} = \mathrm{log}(\frac{GM_B}{GM_A})\), and
  6. \(\mathrm{exp}(b_1) = \frac{GM_B}{GM_A}\)
  7. Backtransforming \(b_1\) gives us the multiplier. To get the percent difference as a fraction, we need to subtract 1, therefore
  8. \(\mathrm{exp}(b_1) - 1 = \frac{GM_B}{GM_A} - 1\), which is equal to
  9. \(\mathrm{exp}(b_1) - 1 = \frac{GM_B}{GM_A} - \frac{GM_A}{GM_A}\), which is equal to
  10. \(\mathrm{exp}(b_1) - 1 = \frac{GM_B - GM_A}{GM_A}\), so, the relative difference of log-transformed \(y\) backtransformed and converted to a percent is
\[\begin{equation} 100(\mathrm{exp}(b_1) - 1) = 100(\frac{GM_B - GM_A}{GM_A}) \end{equation}\]

In other words, the CI using the backtransformed CI of the log-transformed \(y\) is of the relative difference of the geometric means, not the arithmetic means. To think about this estimate of the CI of the relative effect, it helps to remember that the geometric mean is always smaller (closer to zero) than the arithmetic mean, so the numerator is a difference of slightly smaller values, and the denominator is a sligtly smaller values. I’ll return to this. A potential problem with this method is, how to generalize it for more complex models, such as single factor models with more than two levels, or factorial models, or models with continuous covariates.

2.3 The Delta method

The relative effect \(100\frac{\bar{y}_B - \bar{y}_A}{\bar{y}_A}\) is a non-linear transformation of the absolute effect. The standard error of a non-linear transformation \(G(X)\) of random variable can be approximated using a Taylor series approximation, using

\[\begin{equation} \mathrm{VAR}(G(X)) \approx \nabla G(X)^\top \mathrm{COV}(X) \nabla G(X) \end{equation}\]

where \(\nabla G(X)\) is the gradient of the function \(G(X)\), which is a vector of partial derivatives – think of this as the vector specifying the direction of the steepest ascent at some point on the surface of \(G(X)\).

The Delta method is easily applied to any linear model, including a hierarchical models and generalized linear models. And it is even easier in R thanks to the deltamethod function from the msm package.

2.4 Bootstrap standard errors and CI

The bootstrap standard error of a relative effect is simply the standard deviation of the vector of \(k\) relative effects, with each relative effect computed from a random re-sample, with replacement, of the original data. There are several methods for computing a bootstrap CI, the simplest is to simply use percentiles (e.g. 0.025 and 0.975) of the vector of re-sampled relative effects.

3 Comparing CIs computed using the naive, log, and Delta methods

I use a simple Monte-Carlo simulation to compute the frequency of CIs that contain the true relative effect. Sorry, no comparison with a bootstrap because this is a quick report! The simulated data use parameters estimated from a full-factorial analysis of the effect of a selection treatment (levels “CN” and “AA”) and sex (levels “F” and “M”) on upwind flight ability in Drosophila melanogaster. Upwind flight ability was measured as the highest wind tunnel speed at which the fly could fly. For more about the selection experiment, see Weber, K.E. (1996). Large genetic change at small fitness cost in large populations of Drosophila melanogaster selected for wind tunnel flight: rethinking fitness surfaces. Genetics 144, 205–213.

The Harrell plots above show the (A) absolute and (B) relative effects (upper part) and the distribution of the raw data (bottom part) for the fly data. More about Harrell plots is at https://www.biorxiv.org/content/early/2018/11/10/458182

3.1 Single factor with two levels (“t-test”)

set.seed(1)
n <- 27 # average n over the four groups of flies
b0 <- 117.5 # control males
b1 <- 176.5 - b0 # effect of selection in males
# parameters gathered into vector
b <- c(b0, b1)
# error standard deviation
sigma <- 19.2 # residual standard error of fly data
# expected effects on percent scale
b1.p <- b1/b0*100
# make model matrix
selection_levels <- c("CN", "AA") #AA is selected
x <- data.table(Treatment=factor(rep(selection_levels, each=n), selection_levels))
X <- model.matrix(formula(~Treatment), x)
# make data
niter <- 10^4
res1 <- matrix(NA, nrow=niter, ncol=2) # naive
colnames(res1) <- c("ci.low", "ci.high")
res2 <- matrix(NA, nrow=niter, ncol=2) # log ratio
colnames(res2) <- c("ci.low", "ci.high")
res3 <- matrix(NA, nrow=niter, ncol=2) # delta
colnames(res3) <- c("ci.low", "ci.high")
for(iter in 1:niter){
  y <- (X%*%b + rnorm(n*2, sd=sigma))[,1]
  fd <- data.table(Y=y, x)
  fit1 <- lm(Y~Treatment, data=fd)
  bhat <- coef(fit1)
  
  # naive method
  ci <- confint(fit1)["TreatmentAA", ]
  res1[iter, ] <- ci/bhat[1]*100
  
  # log method
  fit1.log <- lm(log(Y)~Treatment, data=fd)
  ci <- exp(confint(fit1.log)["TreatmentAA", ])-1
  res2[iter, ] <- ci*100
  # delta method
  df <- fit1$df.residual
  tcrit <- qt(.975, df)
  sd <- summary(fit1)$sigma
  se <- deltamethod(~x2/x1, mean=coef(fit1), cov=vcov(fit1))
  res3[iter, "ci.low"] <- 100*(bhat[2]/bhat[1] - tcrit*se)
  res3[iter, "ci.high"] <- 100*(bhat[2]/bhat[1] + tcrit*se)
  
  # fun math
  # G(X) = b1/b0 or y/x or x2/x1
  # del(y/x) = (y/x^2, 1/x)
  # del(b1/b0) = (b1/b0^2, 1/b0)
  # del <- c(bhat[2]/bhat[1]^2, 1/bhat[1])
  # se.fun <- sqrt(t(del)%*%vcov(fit1)%*%del)
}
naive <- length(which(res1[,"ci.low"] < b1.p & res1[,"ci.high"] > b1.p))/niter*100
logratio <- length(which(res2[,"ci.low"] < b1.p & res2[,"ci.high"] > b1.p))/niter*100
delta <- length(which(res3[,"ci.low"] < b1.p & res3[,"ci.high"] > b1.p))/niter*100
res_table <- data.table(Method=c("naive", "log", "delta"),
                        Coverage=round(c(naive, logratio, delta),1))
knitr::kable(res_table)
Method Coverage
naive 87.6
log 94.5
delta 95.0

The table above shows the long run (\(10^4\) runs) frequency of CIs that include the true relative difference for each of the three methods. The simulation confirms that a naive CI is too narrow, which is why far fewer than 95% of the CIs covered the true value. The narrow interval implies a standard error that is too small, and a \(t\)-value that is too large, and a \(p\)-value that is too “optimistic”.

Both the log transform and espeically Delta methods have close to the nominal coverage. Nevertheless, there are interesting differences between the log and Delta methods.

p1 <- qplot(res2[,1], res3[,1]) +
  xlab("Lower CI (log method)") +
  ylab("Lower CI (Delta method)") +
  geom_abline(intercept=0, slope=1, color="red") +
  NULL
p2 <- qplot(res2[,2], res3[,2]) +
  xlab("Upper CI (log method)") +
  ylab("Upper CI (Delta method)") +
  geom_abline(intercept=0, slope=1, color="red") +
  NULL
plot_grid(p1, p2, ncol=2, labels="AUTO")

The plots above show that the CIs estimated using the log transformation is “right” shifted (i.e. to larger values) compared to the CIs estimated using the Delta method. This right shift is because the mean in the denominator of the relative effect is a geometric mean using the log method, but an arithemetic mean using the Delta method. Because a geometric mean is always smaller than the arithmetic mean, the relative effect using the log method will be bigger than the relative effect computed using the Delta method. More curiously, how can both methods have seemingly good coverage if the CI computed using the log method is right-shifted relative to the CI computed using the Delta method?

logratio.lo <- length(which(res2[,"ci.low"] > b1.p))/niter*100
delta.lo <- length(which(res3[,"ci.low"] > b1.p))/niter*100
logratio.hi <- length(which(res2[,"ci.high"] < b1.p))/niter*100
delta.hi <- length(which(res3[,"ci.high"] < b1.p))/niter*100
res_table <- data.table(Method=c("log", "delta"),
                        Lower=round(c(logratio.lo, delta.lo),1),
                        Upper=round(c(logratio.hi, delta.hi),1)
                        )
knitr::kable(res_table)
Method Lower Upper
log 3.6 1.8
delta 2.0 3.1

The table above gives the long run frequency of true relative effects that are less than the lower CI or greater than the upper CI for the log and Delta methods. The log method shows a higher than expected frequency at the lower CI and lower than expected frequency at the upper CI, indicated that the CIs computed using the log transformation are slightly right-shifted. The Delta method shows the opposite pattern, indicating that the CIs computed using the Delta method are slightly left-shifted. I assume these shifts are real (although they may be conditional on the parameterization) and not just sample artifacts. Regardless, despite these shifts, the coverage over the range is close to (or equal to for the Delta method) the expected coverage.

3.2 Single factor with four levels (“post-hoc”)

The Delta method is easily applied to more complex designs but its not clear how to implement the log method in more complex designs. For example, if there are four levels in a factor and we want the contrast and CIs for all six pairwise effects, do we just log transform the response and backtransform the CIs of the contrasts (the “whole model” log method) or do we do the log method on all six contrasts independently (the “pairwise” log method)?

Here, I evaluate the two log methods, as well as the naive and Delta methods, by comparing the relative difference of three non-reference levels of the fly data (selected females, control males, selected males) from the reference level (control females or “CN-F”).

# use the four fly levels but pretend it is not factorial
set.seed(1)
n <- 27 # average n over the four groups of flies
# means
mu <- c(131.6, 181.0, 117.5, 176.5) #CN-F, AA-F, CN-M, AA-M
b0 <- 131.6 # control females
b1 <- 181.0 - b0 # effect of selection in females
b2 <- 117.5 - b0 # effect of male in control
b3 <- 176.5 - b0 # effect of selection and male -- not an interaction effect!
# parameters gathered into vector
b <- c(b0, b1, b2, b3)
# error standard deviation
sigma <- 19.2 # residual standard error of fly data
# expected effects on response and percent scale
# call the expected
b1.p <- b1/b0*100
b2.p <- b2/b0*100
b3.p <- b3/b0*100
# make model matrix
A_levels <- c("CN-F", "AA-F", "CN-M", "AA-M")
x <- data.table(Treatment=factor(rep(A_levels, each=n), factor(A_levels)))
X <- model.matrix(formula(~Treatment), x)
n_cells <- length(levels(x$Treatment))
# make data
niter <- 10^4
res1.lo <- matrix(NA, nrow=niter, ncol=3) # naive
res1.up <- matrix(NA, nrow=niter, ncol=3) # naive
res2.lo <- matrix(NA, nrow=niter, ncol=3) # log
res2.up <- matrix(NA, nrow=niter, ncol=3) # log
res3.lo <- matrix(NA, nrow=niter, ncol=3) # delta
res3.up <- matrix(NA, nrow=niter, ncol=3) # delta
res4.lo <- matrix(NA, nrow=niter, ncol=3) # log-pairwise
res4.up <- matrix(NA, nrow=niter, ncol=3) # log-pairwise
for(iter in 1:niter){
  y <- (X%*%b + rnorm(n*n_cells, sd=sigma))[,1]
  fd <- data.table(Y=y, x)
  fit1 <- lm(Y~Treatment, data=fd)
  bhat <- coef(fit1)
  # contrast(emmeans(fit1, specs="Treatment"), adjust="none", method="revpairwise")
  
  # naive method
  ci.lo <- confint(fit1)[2:4, "2.5 %"]
  ci.up <- confint(fit1)[2:4, "97.5 %"]
  res1.lo[iter, ] <- ci.lo/bhat[1]*100
  res1.up[iter, ] <- ci.up/bhat[1]*100
  
  # log method 1 - run everything at once
  fit2 <- lm(log(Y)~Treatment, data=fd)
  ci.lo <- exp(confint(fit2)[2:4, "2.5 %"]) - 1
  ci.up <- exp(confint(fit2)[2:4, "97.5 %"]) - 1
  res2.lo[iter, ] <- ci.lo*100
  res2.up[iter, ] <- ci.up*100
  
  # log method 2 -- pairwise
  fit2 <- lm(log(Y)~Treatment, data=fd[Treatment=="CN-F" | Treatment=="AA-F"])
  ci.lo <- exp(confint(fit2)[2, "2.5 %"]) - 1
  ci.up <- exp(confint(fit2)[2, "97.5 %"]) - 1
  res4.lo[iter, 1] <- ci.lo*100
  res4.up[iter, 1] <- ci.up*100
  fit2 <- lm(log(Y)~Treatment, data=fd[Treatment=="CN-F" | Treatment=="CN-M"])
  ci.lo <- exp(confint(fit2)[2, "2.5 %"]) - 1
  ci.up <- exp(confint(fit2)[2, "97.5 %"]) - 1
  res4.lo[iter, 2] <- ci.lo*100
  res4.up[iter, 2] <- ci.up*100
  fit2 <- lm(log(Y)~Treatment, data=fd[Treatment=="CN-F" | Treatment=="AA-M"])
  ci.lo <- exp(confint(fit2)[2, "2.5 %"]) - 1
  ci.up <- exp(confint(fit2)[2, "97.5 %"]) - 1
  res4.lo[iter, 3] <- ci.lo*100
  res4.up[iter, 3] <- ci.up*100
  # delta method
  df <- fit1$df.residual
  tcrit <- qt(.975, df)
  sd <- summary(fit1)$sigma
  se <- c(
    deltamethod(~x2/x1, mean=coef(fit1), cov=vcov(fit1)),
    deltamethod(~x3/x1, mean=coef(fit1), cov=vcov(fit1)),
    deltamethod(~x4/x1, mean=coef(fit1), cov=vcov(fit1))
  )
  res3.lo[iter, ] <- 100*(bhat[2:4]/bhat[1] - tcrit*se)
  res3.up[iter, ] <- 100*(bhat[2:4]/bhat[1] + tcrit*se)
}
naive <- c(length(which(res1.lo[,1] < b1.p & res1.up[,1] > b1.p))/niter*100,
           length(which(res1.lo[,2] < b2.p & res1.up[,2] > b2.p))/niter*100,
           length(which(res1.lo[,3] < b3.p & res1.up[,3] > b3.p))/niter*100
)
logratio1 <- c(length(which(res2.lo[,1] < b1.p & res2.up[,1] > b1.p))/niter*100,
              length(which(res2.lo[,2] < b2.p & res2.up[,2] > b2.p))/niter*100,
              length(which(res2.lo[,3] < b3.p & res2.up[,3] > b3.p))/niter*100
)
logratio2 <- c(length(which(res4.lo[,1] < b1.p & res4.up[,1] > b1.p))/niter*100,
              length(which(res4.lo[,2] < b2.p & res4.up[,2] > b2.p))/niter*100,
              length(which(res4.lo[,3] < b3.p & res4.up[,3] > b3.p))/niter*100
)
delta <- c(length(which(res3.lo[,1] < b1.p & res3.up[,1] > b1.p))/niter*100,
           length(which(res3.lo[,2] < b2.p & res3.up[,2] > b2.p))/niter*100,
           length(which(res3.lo[,3] < b3.p & res3.up[,3] > b3.p))/niter*100
)
res.table <- data.table(rbind(naive, logratio1, logratio2, delta))
colnames(res.table) <- c("AAF-CNF", "CNM-CNF", "AAM-CNF")
res.table <- cbind(Method=c("naive", "log", "log-pw", "Delta"), res.table)
knitr::kable(res.table, digits=c(0,1,1,1))
Method AAF-CNF CNM-CNF AAM-CNF
naive 90.1 96.1 90.7
log 96.0 90.7 95.9
log-pw 95.1 95.2 95.0
Delta 95.3 95.2 95.3

The table above shows the long run (\(10^4\) runs) frequency of CIs that include the true relative difference for each of the three contrasts (differences from CN-F) for each of the four methods, including both the whole-model and pairwise log methods. The whole-model log method can have intervals that are two narrow, as indicated by the lower-than-nominal frequency for the CN-F relative difference. The frequencies of the run-pairwise log method and Deta method look pretty good, but this is only one parameterization.

3.3 Factorial (2 X 2)

# use the four fly levels but pretend it is not factorial
set.seed(1)
n <- 27 # average n over the four groups of flies
# means
mu <- c(131.6, 181.0, 117.5, 176.5) #CN-F, AA-F, CN-M, AA-M
b0 <- 131.6 # control females
b1 <- 181.0 - b0 # effect of selection in females
b2 <- 117.5 - b0 # effect of male in control
b3 <- 176.5 - (b0 + b1 + b2) # interaction effect!
# parameters gathered into vector
b <- c(b0, b1, b2, b3)
# error standard deviation
sigma <- 19.2 # residual standard error of fly data
# expected effects on response and percent scale
# there are 2 x 2 = four pairwise effects (of one treatment within each level of the other treatment)
# call these A0 and A1, B0 and B1
# call the expected
A0 <- b1
A1 <- ((b0+b1+b2+b3)-(b0+b2))
A0.p <- 100*A0/b0
A1.p <- 100*A1/(b0+b2)
# make model matrix
A_levels <- factor(rep(c("CN", "AA"), each=n), c("CN", "AA"))
B_levels <- factor(c("F", "M"))
x <- expand.grid(Treatment=A_levels,Sex=B_levels)
X <- model.matrix(formula(~Treatment*Sex), x)
set.seed(1)
niter <- 10^4
methods <- c("naive", "log", "log-pw", "Delta")
n.methods <- length(methods)
res <- data.frame(method=rep(methods, niter),
                  A0.lo=NA,
                  A0.up=NA,
                  A1.lo=NA,
                  A1.up=NA)
row.e <- 0 # end row for saving 
for(iter in 1:niter){
  # make data
  y <- (X%*%b + rnorm(n*4, sd=sigma))[,1]
  fd <- data.table(Y=y, x)
  
  # fit
  fit <- lm(Y~Treatment*Sex, data=fd)
  fit.emm <- emmeans(fit, specs=c("Treatment", "Sex"))
  fit.eff <- summary(contrast(fit.emm, adjust="none", method="revpairwise"), infer=c(TRUE, TRUE))
  
  # cell means
  ybar11 <- summary(fit.emm)[1, "emmean"] # CN-F
  ybar21 <- summary(fit.emm)[2, "emmean"] # AA-F
  ybar12 <- summary(fit.emm)[3, "emmean"] # CN-M
  ybar22 <- summary(fit.emm)[4, "emmean"] # AA-M
  
  # naive convert CI to percent
  naive <- 100*c(
    fit.eff[1, "lower.CL"]/ybar11,
    fit.eff[1, "upper.CL"]/ybar11,
    fit.eff[6, "lower.CL"]/ybar12,
    fit.eff[6, "upper.CL"]/ybar12
  )
  # log method 1 -- run everything at once
  fit2 <- lm(log(Y)~Treatment*Sex, data=fd)
  fit2.emm <- emmeans(fit2, specs=c("Treatment", "Sex"))
  fit2.eff <- summary(contrast(fit2.emm, adjust="none", method="revpairwise"), infer=c(TRUE, TRUE))
  logratio1 <- 100*c(
    exp(fit2.eff[1, "lower.CL"])-1,
    exp(fit2.eff[1, "upper.CL"])-1,
    exp(fit2.eff[6, "lower.CL"])-1,
    exp(fit2.eff[6, "upper.CL"])-1
  )
  
  # log method 2 -- pairwise
  combos <- c("CN-F", "AA-F", "CN-M", "AA-M")
  fd[, combo:=factor(paste(Treatment, Sex, sep="-"), combos)]
  fit2 <- lm(log(Y)~combo, data=fd[combo=="CN-F" | combo=="AA-F"])
  ci.lo1 <- exp(confint(fit2)[2, "2.5 %"]) - 1
  ci.up1 <- exp(confint(fit2)[2, "97.5 %"]) - 1
  fit2 <- lm(log(Y)~combo, data=fd[combo=="CN-M" | combo=="AA-M"])
  ci.lo2 <- exp(confint(fit2)[2, "2.5 %"]) - 1
  ci.up2 <- exp(confint(fit2)[2, "97.5 %"]) - 1
  
  logratio2 <- 100*c(ci.lo1, ci.up1, ci.lo2, ci.up2)
  # delta
  A0hat.p <- fit.eff[1, "estimate"]/ybar11
  A1hat.p <- fit.eff[6, "estimate"]/ybar12
  se <- c(
    deltamethod(~x2/x1, mean=coef(fit), cov=vcov(fit)),
    deltamethod(~(x2+x4)/(x1+x3), mean=coef(fit), cov=vcov(fit))
  )
  delta <- 100*c(
    A0hat.p-tcrit*se[1],
    A0hat.p+tcrit*se[1],
    A1hat.p-tcrit*se[2],
    A1hat.p+tcrit*se[2]
  )
  row.s <- row.e + 1
  row.e <- row.s + n.methods - 1
  res[row.s:row.e, 2:(n.methods+1)] <-rbind(naive, logratio1, logratio2, delta)
}
res <- data.table(res)
method_k <- "naive"
naive <- c(
  length(which(res[method==method_k,A0.lo] < A0.p & res[method==method_k,A0.up] > A0.p))/niter*100,
  length(which(res[method==method_k,A1.lo] < A1.p & res[method==method_k,A1.up] > A1.p))/niter*100
)
method_k <- "log"
logratio1 <- c(
  length(which(res[method==method_k,A0.lo] < A0.p & res[method==method_k,A0.up] > A0.p))/niter*100,
  length(which(res[method==method_k,A1.lo] < A1.p & res[method==method_k,A1.up] > A1.p))/niter*100
)
method_k <- "log-pw"
logratio2 <- c(
  length(which(res[method==method_k,A0.lo] < A0.p & res[method==method_k,A0.up] > A0.p))/niter*100,
  length(which(res[method==method_k,A1.lo] < A1.p & res[method==method_k,A1.up] > A1.p))/niter*100
)
method_k <- "Delta"
delta <- c(
  length(which(res[method==method_k,A0.lo] < A0.p & res[method==method_k,A0.up] > A0.p))/niter*100,
  length(which(res[method==method_k,A1.lo] < A1.p & res[method==method_k,A1.up] > A1.p))/niter*100
)
res.table <- data.table(rbind(naive, logratio1, logratio2, delta))
colnames(res.table) <- c("AAF-CNF", "AAM-CNM")
res.table <- cbind(Method=c("naive", "log", "log-pw", "Delta"), res.table)
knitr::kable(res.table, digits=c(0,1,1))
Method AAF-CNF AAM-CNM
naive 90.1 87.2
log 96.0 93.0
log-pw 95.1 94.3
Delta 95.6 95.1

The table above shows the long run (\(10^4\) runs) frequency of CIs that include the true relative difference for the two simple effects of the selection factor for each of the four methods, including both the whole-model and pairwise log methods. Again, the pairwise log method and Delta method have pretty good coverage. The whole-model log method is less good and the naive method is even less good!

4 (probably not) Final thoughts

Do not report naive CIs of relative effects! And, if you are emphasizing some aspect of inference using a relative effect, such as a \(p\)-value, make sure the \(p\)-value is computed from a statistically correct standard error, which isn’t a naive SE (the absolute SE divided by the reference mean times 100).

If the model is anything more complex than a simple \(t\)-test, do not use the log method on the whole model but instead use the log method on specific contrasts. This “pairwise” log method has pretty good results and the CIs are pretty easy to compute, although I explored this with only a single parameterization of only a few, simple linear models.

The Delta method is somewhat more satisfying than the pairwise log method since it uses the whole model. And it also has pretty good results, with the caveat that I explored this with only a single parameterization of only a few, simple linear models.

While relative effects give us some since of the bigness of an effect, a general problem with reporting results as relative effects is that it discourages us from doing the hard work of working out the biological (including physiological, ecological, evolutionary) consequences of absolute effects. Consider this when presenting results as relative effects.

LS0tCnRpdGxlOiAiUmVwb3J0aW5nIGVmZmVjdHMgYXMgcmVsYXRpdmUgZGlmZmVyZW5jZXMuLi53aXRoIGEgY29uZmlkZW5jZSBpbnRlcnZhbCIKYXV0aG9yOiAiSmVmZnJleSBBLiBXYWxrZXIiCmRhdGU6ICIxMS8xNC8yMDE4IgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdGhlbWU6IHVuaXRlZAogICAgdG9jOiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKLS0tCgpbR28gYmFjayB0byBSIGRvb2RsZXNdKGh0dHBzOi8vcmRvb2RsZXMucmJpbmQuaW8pCgpbTXkgcGVyc29uYWwgd2ViIHBhZ2VdKGh0dHBzOi8vd3d3Lm1pZGRsZXByb2Zlc3Nvci5jb20pCgpbTXkgb2ZmaWNpYWwgVVNNIHdlYiBwYWdlXShodHRwczovL3VzbS5tYWluZS5lZHUvYmlvL2plZmZyZXktd2Fsa2VyKQoKYGBge3Igc2V0dXAsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGNvbW1lbnQ9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShlbW1lYW5zKQpsaWJyYXJ5KGRhdGEudGFibGUpCmxpYnJhcnkobXNtKSAjZGVsdGFtZXRob2QKbGlicmFyeShoYXJyZWxscGxvdCkKbGlicmFyeShjb3dwbG90KQpkYXRhX3BhdGggPC0gIi4uL2RhdGEiCmBgYAoKYGBge3IgZmx5cGxvdCwgZWNobz1GQUxTRX0KIyBwYXRoIDwtICdtYW51c2NyaXB0L2RhdGEvJyAjIGZvciBjb25zb2xlCmZpbGVuYW1lIDwtICdmbHlfYnVyc3QudHh0JwpmaWxlX3BhdGggPC0gcGFzdGUoZGF0YV9wYXRoLCBmaWxlbmFtZSwgc2VwPScvJykgIyBmb3Iga25pdApmbHkgPC0gZnJlYWQoZmlsZV9wYXRoLCBzdHJpbmdzQXNGYWN0b3JzID0gVFJVRSkKZmx5WywgVHJlYXRtZW50Oj1mYWN0b3IoVHJlYXRtZW50LCBjKCdDTicsICdBQScpKV0KCmZpdCA8LSBsbShWYnVyc3QgfiBUcmVhdG1lbnQqU2V4LCBkYXRhPWZseSkKZml0LmVtbSA8LSBlbW1lYW5zKGZpdCwgc3BlY3M9YygiVHJlYXRtZW50IiwgIlNleCIpKQpmaXQuZWZmIDwtIHN1bW1hcnkoY29udHJhc3QoZml0LmVtbSwgYWRqdXN0PSJub25lIiwgbWV0aG9kPSJyZXZwYWlyd2lzZSIpLCAgaW5mZXI9YyhUUlVFLCBUUlVFKSkKCmhwMSA8LSBoYXJyZWxscGxvdCh4PSdUcmVhdG1lbnQnLCB5PSdWYnVyc3QnLCBnPSdTZXgnLCBkYXRhPWZseSwgYWRkX2ludGVyYWN0aW9uID0gVFJVRSwgaW50ZXJhY3Rpb24uZ3JvdXAgPSBUUlVFLCBjb250cmFzdHMubWV0aG9kID0gJ3JldnBhaXJ3aXNlJywgeV9sYWJlbCA9ICgnQnVyc3QgU3BlZWQgKGNtL3MpJykpCmhwMiA8LSBoYXJyZWxscGxvdCh4PSdUcmVhdG1lbnQnLCB5PSdWYnVyc3QnLCBnPSdTZXgnLCBkYXRhPWZseSwgYWRkX2ludGVyYWN0aW9uID0gVFJVRSwgaW50ZXJhY3Rpb24uZ3JvdXAgPSBUUlVFLCBjb250cmFzdHMubWV0aG9kID0gJ3JldnBhaXJ3aXNlJywgIGNvbnRyYXN0cy5zY2FsaW5nID0gInBlcmNlbnQiLCB5X2xhYmVsID0gKCdCdXJzdCBTcGVlZCAoY20vcyknKSkKYGBgCgojIFJlc2VhcmNoZXJzIGZyZXF1ZW50bHkgcmVwb3J0IHJlc3VsdHMgYXMgcmVsYXRpdmUgZWZmZWN0cwoKRm9yIGV4YW1wbGUsCgoiTWFsZSBmbGllcyBmcm9tIHNlbGVjdGVkIGxpbmVzIGhhZCA1MCUgbGFyZ2VyIHVwd2luZCBmbGlnaHQgYWJpbGl0eSB0aGFuIG1hbGUgZmxpZXMgZnJvbSBjb250cm9sIGxpbmVzIChDb250cm9sIG1lYW46IDExNy41IGNtL3M7IFNlbGVjdGVkIG1lYW4gMTc2LjUgY20vcykuIgoKd2hlcmUgYSByZWxhdGl2ZSBlZmZlY3QgaXMKClxiZWdpbntlcXVhdGlvbn0KMTAwIFxmcmFje1xiYXJ7eX1fQiAtIFxiYXJ7eX1fQX17XGJhcnt5fV9BfQpcZW5ke2VxdWF0aW9ufQoKSWYgd2UgYXJlIHRvIGZvbGxvdyBiZXN0IHByYWN0aWNlcywgd2Ugc2hvdWxkIHByZXNlbnQgdGhpcyBlZmZlY3Qgd2l0aCBhIG1lYXN1cmUgb2YgdW5jZXJ0YWludHksIHN1Y2ggYXMgYSBjb25maWRlbmNlIGludGVydmFsLiBUaGUgYWJzb2x1dGUgZWZmZWN0IGlzIDU5LjAgY20vcyBhbmQgdGhlIDk1JSBDSSBvZiB0aGlzIGVmZmVjdCBpcyAoNDguNywgNjkuMyBjbS9zKS4gQnV0IGlmIHdlIHByZXNlbnQgdGhlIHJlc3VsdCBhcyBhIHJlbGF0aXZlIGVmZmVjdCwgb3IgcGVyY2VudCBkaWZmZXJlbmNlIGZyb20gc29tZSByZWZlcmVuY2UgdmFsdWUsIGhvdyBkbyB3ZSBjb21wdXRlIGEgInJlbGF0aXZlIENJIj8KCiMgRm91ciBtZXRob2RzIHRvIGNvbXB1dGUgdGhlIHN0YW5kYXJkIGVycm9yIGFuZCBDSSBvZiBhIHJlbGF0aXZlIGVmZmVjdAojIyBOYWl2ZSByZWxhdGl2ZSBjb25maWRlbmNlIGludGVydmFscwoKXGJlZ2lue2VxdWF0aW9ufQpyZWxhdGl2ZVxfQ0kgPSAxMDBcZnJhY3thYnNvbHV0ZVxfQ0l9e1xiYXJ7eX1fQX0KXGVuZHtlcXVhdGlvbn0KCkZvciB0aGUgZmx5IGV4YW1wbGUsIHRoZSA5NSUgbmFpdmUgcmVsYXRpdmUgQ0kgaXMgYm91bmRlZCBieSAkMTAwXGZyYWN7NDguN317MTE3LjV9ID0gNDEuNFwlJCBhbmQgJDEwMFxmcmFjezY5LjN9ezExNy41fSA9IDU5LjBcJSQuIFRoZXNlIGFyZSBlYXN5IHRvIGNvbXB1dGUgYnV0IHdyb25nIGJlY2F1c2UgdGhlIGVycm9yIGluIGVzdGltYXRpbmcgYSByZWxhdGl2ZSBkaWZmZXJlbmNlIGlzIGEgZnVuY3Rpb24gb2YgdGhlIGVycm9yIGluIGVzdGltYXRpbmcgYm90aCB0aGUgbnVtZXJhdG9yICh0aGUgYWJzb2x1dGUgZGlmZmVyZW5jZSkgYW5kIHRoZSBkZW5vbWluYXRvciAodGhlIHJlZmVyZW5jZSBtZWFuKS4gVGhlIGNvbnNlcXVlbmNlIGlzIHRoYXQgbmFpdmUgcmVsYXRpdmUgY29uZmlkZW5jZSBpbnRlcnZhbHMgYXJlIHRvbyBuYXJyb3cgKG9yIHRvbyBvcHRpbWlzdGljLCBvciBzdWdnZXN0IHRvbyBtdWNoIHByZWNpc2lvbikuCgojIyBCYWNrLXRyYW5zZm9ybWVkIGludGVydmFscyBmcm9tIGxvZy10cmFuc2Zvcm1lZCBkYXRhLgoKVGhpcyBwb3N0IGlzIG1vdGl2YXRlZCBieSB0aGUgcG9zdCBbVGhlIHBlcmNlbnQgZGlmZmVyZW5jZSBmYWxsYWN5IGFuZCBhIHNvbHV0aW9uOiB0aGUgcmF0aW8gdC10ZXN0XShodHRwOi8vc2NpZW5jZWJsb2cuZGFycm91emV0LW5hcmRpLm5ldC8/cD0yMDY2KSBmcm9tIEFudGhvbnkgRGFycm91emV0LU5hcmRpIGF0IFtBbnRob255J3MgU2NpZW5jZSBibG9nXShodHRwOi8vc2NpZW5jZWJsb2cuZGFycm91emV0LW5hcmRpLm5ldCkuIEFudGhvbnkgc3VnZ2VzdHMgYSBjbGV2ZXIgc29sdXRpb24gZm9yIGEgc2ltcGxlLCBsaW5lYXIgbW9kZWwgd2l0aCBhIHNpbmdsZSBmYWN0b3Igd2l0aCB0d28gbGV2ZWxzIChvciBhICJ0LXRlc3QiIGRlc2lnbik6IHRoZSByZWxhdGl2ZSBDSXMgYXJlIHRoZSBiYWNrdHJhbnNmb3JtZWQgQ0lzIG9mIHRoZSBlZmZlY3Qgb2YgdGhlIGxvZy10cmFuc2Zvcm1lZCBkYXRhLgoKMS4gbG9nIHRyYW5zZm9ybSB0aGUgcmVzcG9uc2UgdmFyaWFibGUKMi4gcnVuIHRoZSBsaW5lYXIgbW9kZWwgJGxvZyh5KSA9IGJfMCArIGJfMSBUcmVhdG1lbnQkCjMuIGNvbXB1dGUgdGhlIENJIG9mICRiXzEkCjQuIGJhY2t0cmFuc2Zvcm0gdXNpbmcgJDEwMChcbWF0aHJte2V4cH0oQ0kpIC0gMSkkCgpMZXQncyB0aGluayBhYm91dCB0aGlzLgoKMS4gVGhlIGNvZWZmaWNpZW50ICRiXzEkIG9mIHRoZSBsaW5lYXIgbW9kZWwgb2YgbG9nIHRyYW5zZm9ybWVkICR5JCBpcyAkXG92ZXJsaW5le1xtYXRocm17bG9nfSh5X0IpfSAtIFxvdmVybGluZXtcbWF0aHJte2xvZ30oeV9BKX0kCjIuIFRoaXMgaXMgdGhlIGRpZmZlcmVuY2UgaW4gdGhlIGxvZ3Mgb2YgdGhlIGdlb21ldHJpYyBtZWFucyBvZiBncm91cCBCIGFuZCBncm91cCBBLCB3aGVyZSBhIGdlb21ldHJpYyBtZWFuIGlzCjMuICRHTT0oXFBpIHkpXlxmcmFjezF9e259JCBhbmQgdGhlIGxvZyBvZiBhIGdlb21ldHJpYyBtZWFuIGlzCjQuICRcbWF0aHJte2xvZ30oR00pID0gXG1hdGhybXtsb2d9KChcUGkgeSleXGZyYWN7MX17bn0pID0gXGZyYWN7MX17bn1cc3Vte1xtYXRocm17bG9nfSh5KX0kIChub3RlIHRoYXQgdGhlIHR5cGljYWwgd2F5IHRvIGNvbXB1dGUgYSBnZW9tZXRyaWMgbWVhbiBpcyB1c2luZyBhIGxvZyB0cmFuc2Zvcm1hdGlvbiBzaW5jZSB0aGlzIGlzIHVubGlrZWx5IHRvIGJsb3cgdXAgdG8gcmVhbGx5IGJpZyB2YWx1ZXMpCjUuIEFuZCBiZWNhdXNlIHRoZSBkaWZmZXJlbmNlIG9mIHR3byBsb2dzIGlzIHRoZSBsb2cgb2YgdGhlaXIgcmF0aW8sICRiXzEgPSBcb3ZlcmxpbmV7XG1hdGhybXtsb2d9KHlfQil9IC0gXG92ZXJsaW5le1xtYXRocm17bG9nfSh5X0EpfSA9IFxtYXRocm17bG9nfShcZnJhY3tHTV9CfXtHTV9BfSkkLCBhbmQKNi4gJFxtYXRocm17ZXhwfShiXzEpID0gXGZyYWN7R01fQn17R01fQX0kCjcuIEJhY2t0cmFuc2Zvcm1pbmcgJGJfMSQgZ2l2ZXMgdXMgdGhlIG11bHRpcGxpZXIuIFRvIGdldCB0aGUgcGVyY2VudCBkaWZmZXJlbmNlIGFzIGEgZnJhY3Rpb24sIHdlIG5lZWQgdG8gc3VidHJhY3QgMSwgdGhlcmVmb3JlCjguICRcbWF0aHJte2V4cH0oYl8xKSAtIDEgPSBcZnJhY3tHTV9CfXtHTV9BfSAtIDEkLCB3aGljaCBpcyBlcXVhbCB0bwo5LiAkXG1hdGhybXtleHB9KGJfMSkgLSAxID0gXGZyYWN7R01fQn17R01fQX0gLSBcZnJhY3tHTV9BfXtHTV9BfSQsIHdoaWNoIGlzIGVxdWFsIHRvCjEwLiAkXG1hdGhybXtleHB9KGJfMSkgLSAxID0gXGZyYWN7R01fQiAtIEdNX0F9e0dNX0F9JCwgc28sIHRoZSByZWxhdGl2ZSBkaWZmZXJlbmNlIG9mIGxvZy10cmFuc2Zvcm1lZCAkeSQgYmFja3RyYW5zZm9ybWVkIGFuZCBjb252ZXJ0ZWQgdG8gYSBwZXJjZW50IGlzCgpcYmVnaW57ZXF1YXRpb259CjEwMChcbWF0aHJte2V4cH0oYl8xKSAtIDEpID0gMTAwKFxmcmFje0dNX0IgLSBHTV9BfXtHTV9BfSkKXGVuZHtlcXVhdGlvbn0KCkluIG90aGVyIHdvcmRzLCB0aGUgQ0kgdXNpbmcgdGhlIGJhY2t0cmFuc2Zvcm1lZCBDSSBvZiB0aGUgbG9nLXRyYW5zZm9ybWVkICR5JCBpcyBvZiB0aGUgcmVsYXRpdmUgZGlmZmVyZW5jZSBvZiB0aGUgKipnZW9tZXRyaWMgbWVhbnMqKiwgbm90IHRoZSBhcml0aG1ldGljIG1lYW5zLiBUbyB0aGluayBhYm91dCB0aGlzIGVzdGltYXRlIG9mIHRoZSBDSSBvZiB0aGUgcmVsYXRpdmUgZWZmZWN0LCBpdCBoZWxwcyB0byByZW1lbWJlciB0aGF0IHRoZSBnZW9tZXRyaWMgbWVhbiBpcyBhbHdheXMgc21hbGxlciAoY2xvc2VyIHRvIHplcm8pIHRoYW4gdGhlIGFyaXRobWV0aWMgbWVhbiwgc28gdGhlIG51bWVyYXRvciBpcyBhIGRpZmZlcmVuY2Ugb2Ygc2xpZ2h0bHkgc21hbGxlciB2YWx1ZXMsIGFuZCB0aGUgZGVub21pbmF0b3IgaXMgYSBzbGlndGx5IHNtYWxsZXIgdmFsdWVzLiBJJ2xsIHJldHVybiB0byB0aGlzLiBBIHBvdGVudGlhbCBwcm9ibGVtIHdpdGggdGhpcyBtZXRob2QgaXMsIGhvdyB0byBnZW5lcmFsaXplIGl0IGZvciBtb3JlIGNvbXBsZXggbW9kZWxzLCBzdWNoIGFzIHNpbmdsZSBmYWN0b3IgbW9kZWxzIHdpdGggbW9yZSB0aGFuIHR3byBsZXZlbHMsIG9yIGZhY3RvcmlhbCBtb2RlbHMsIG9yIG1vZGVscyB3aXRoIGNvbnRpbnVvdXMgY292YXJpYXRlcy4KCiMjIFRoZSBEZWx0YSBtZXRob2QKClRoZSByZWxhdGl2ZSBlZmZlY3QgJDEwMFxmcmFje1xiYXJ7eX1fQiAtIFxiYXJ7eX1fQX17XGJhcnt5fV9BfSQgaXMgYSBub24tbGluZWFyIHRyYW5zZm9ybWF0aW9uIG9mIHRoZSBhYnNvbHV0ZSBlZmZlY3QuIFRoZSBzdGFuZGFyZCBlcnJvciBvZiBhIG5vbi1saW5lYXIgdHJhbnNmb3JtYXRpb24gJEcoWCkkIG9mIHJhbmRvbSB2YXJpYWJsZSBjYW4gYmUgYXBwcm94aW1hdGVkIHVzaW5nIGEgVGF5bG9yIHNlcmllcyBhcHByb3hpbWF0aW9uLCB1c2luZwoKXGJlZ2lue2VxdWF0aW9ufQpcbWF0aHJte1ZBUn0oRyhYKSkgXGFwcHJveCBcbmFibGEgRyhYKV5cdG9wIFxtYXRocm17Q09WfShYKSBcbmFibGEgRyhYKQpcZW5ke2VxdWF0aW9ufQoKd2hlcmUgJFxuYWJsYSBHKFgpJCBpcyB0aGUgZ3JhZGllbnQgb2YgdGhlIGZ1bmN0aW9uICRHKFgpJCwgd2hpY2ggaXMgYSB2ZWN0b3Igb2YgcGFydGlhbCBkZXJpdmF0aXZlcyAtLSB0aGluayBvZiB0aGlzIGFzIHRoZSB2ZWN0b3Igc3BlY2lmeWluZyB0aGUgZGlyZWN0aW9uIG9mIHRoZSBzdGVlcGVzdCBhc2NlbnQgYXQgc29tZSBwb2ludCBvbiB0aGUgc3VyZmFjZSBvZiAkRyhYKSQuCgpUaGUgRGVsdGEgbWV0aG9kIGlzIGVhc2lseSBhcHBsaWVkIHRvIGFueSBsaW5lYXIgbW9kZWwsIGluY2x1ZGluZyBhIGhpZXJhcmNoaWNhbCBtb2RlbHMgYW5kIGdlbmVyYWxpemVkIGxpbmVhciBtb2RlbHMuIEFuZCBpdCBpcyBldmVuIGVhc2llciBpbiBSIHRoYW5rcyB0byB0aGUgYGRlbHRhbWV0aG9kYCBmdW5jdGlvbiBmcm9tIHRoZSBtc20gcGFja2FnZS4KCiMjIEJvb3RzdHJhcCBzdGFuZGFyZCBlcnJvcnMgYW5kIENJCgpUaGUgYm9vdHN0cmFwIHN0YW5kYXJkIGVycm9yIG9mIGEgcmVsYXRpdmUgZWZmZWN0IGlzIHNpbXBseSB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIHRoZSB2ZWN0b3Igb2YgJGskIHJlbGF0aXZlIGVmZmVjdHMsIHdpdGggZWFjaCByZWxhdGl2ZSBlZmZlY3QgY29tcHV0ZWQgZnJvbSBhIHJhbmRvbSByZS1zYW1wbGUsIHdpdGggcmVwbGFjZW1lbnQsIG9mIHRoZSBvcmlnaW5hbCBkYXRhLiBUaGVyZSBhcmUgc2V2ZXJhbCBtZXRob2RzIGZvciBjb21wdXRpbmcgYSBib290c3RyYXAgQ0ksIHRoZSBzaW1wbGVzdCBpcyB0byBzaW1wbHkgdXNlIHBlcmNlbnRpbGVzIChlLmcuIDAuMDI1IGFuZCAwLjk3NSkgb2YgdGhlIHZlY3RvciBvZiByZS1zYW1wbGVkIHJlbGF0aXZlIGVmZmVjdHMuCgojIENvbXBhcmluZyBDSXMgY29tcHV0ZWQgdXNpbmcgdGhlIG5haXZlLCBsb2csIGFuZCBEZWx0YSBtZXRob2RzCgpJIHVzZSBhIHNpbXBsZSBNb250ZS1DYXJsbyBzaW11bGF0aW9uIHRvIGNvbXB1dGUgdGhlIGZyZXF1ZW5jeSBvZiBDSXMgdGhhdCBjb250YWluIHRoZSB0cnVlIHJlbGF0aXZlIGVmZmVjdC4gU29ycnksIG5vIGNvbXBhcmlzb24gd2l0aCBhIGJvb3RzdHJhcCBiZWNhdXNlIHRoaXMgaXMgYSBxdWljayByZXBvcnQhIFRoZSBzaW11bGF0ZWQgZGF0YSB1c2UgcGFyYW1ldGVycyBlc3RpbWF0ZWQgZnJvbSBhIGZ1bGwtZmFjdG9yaWFsIGFuYWx5c2lzIG9mIHRoZSBlZmZlY3Qgb2YgYSBzZWxlY3Rpb24gdHJlYXRtZW50IChsZXZlbHMgIkNOIiBhbmQgIkFBIikgYW5kIHNleCAobGV2ZWxzICJGIiBhbmQgIk0iKSBvbiB1cHdpbmQgZmxpZ2h0IGFiaWxpdHkgaW4gKkRyb3NvcGhpbGEgbWVsYW5vZ2FzdGVyKi4gVXB3aW5kIGZsaWdodCBhYmlsaXR5IHdhcyBtZWFzdXJlZCBhcyB0aGUgaGlnaGVzdCB3aW5kIHR1bm5lbCBzcGVlZCBhdCB3aGljaCB0aGUgZmx5IGNvdWxkIGZseS4gRm9yIG1vcmUgYWJvdXQgdGhlIHNlbGVjdGlvbiBleHBlcmltZW50LCBzZWUgV2ViZXIsIEsuRS4gKDE5OTYpLiBMYXJnZSBnZW5ldGljIGNoYW5nZSBhdCBzbWFsbCBmaXRuZXNzIGNvc3QgaW4gbGFyZ2UgcG9wdWxhdGlvbnMgb2YgRHJvc29waGlsYSBtZWxhbm9nYXN0ZXIgc2VsZWN0ZWQgZm9yIHdpbmQgdHVubmVsIGZsaWdodDogcmV0aGlua2luZyBmaXRuZXNzIHN1cmZhY2VzLiBHZW5ldGljcyAxNDQsIDIwNeKAkzIxMy4KCmBgYHtyIGZseS1oYXJyZWwtcGxvdCwgZWNobz1GQUxTRX0KcGxvdF9ncmlkKGhwMSRnZywgaHAyJGdnLCBuY29sPTIsIGxhYmVscz0iQVVUTyIpCmBgYAoKVGhlIEhhcnJlbGwgcGxvdHMgYWJvdmUgc2hvdyB0aGUgKEEpIGFic29sdXRlIGFuZCAoQikgcmVsYXRpdmUgZWZmZWN0cyAodXBwZXIgcGFydCkgYW5kIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHJhdyBkYXRhIChib3R0b20gcGFydCkgZm9yIHRoZSBmbHkgZGF0YS4gTW9yZSBhYm91dCBIYXJyZWxsIHBsb3RzIGlzIGF0IGh0dHBzOi8vd3d3LmJpb3J4aXYub3JnL2NvbnRlbnQvZWFybHkvMjAxOC8xMS8xMC80NTgxODIKCiMjIFNpbmdsZSBmYWN0b3Igd2l0aCB0d28gbGV2ZWxzICgidC10ZXN0IikKCmBgYHtyIHR3by1sZXZlbCwgZXZhbD1UUlVFfQpzZXQuc2VlZCgxKQoKbiA8LSAyNyAjIGF2ZXJhZ2UgbiBvdmVyIHRoZSBmb3VyIGdyb3VwcyBvZiBmbGllcwpiMCA8LSAxMTcuNSAjIGNvbnRyb2wgbWFsZXMKYjEgPC0gMTc2LjUgLSBiMCAjIGVmZmVjdCBvZiBzZWxlY3Rpb24gaW4gbWFsZXMKCiMgcGFyYW1ldGVycyBnYXRoZXJlZCBpbnRvIHZlY3RvcgpiIDwtIGMoYjAsIGIxKQoKIyBlcnJvciBzdGFuZGFyZCBkZXZpYXRpb24Kc2lnbWEgPC0gMTkuMiAjIHJlc2lkdWFsIHN0YW5kYXJkIGVycm9yIG9mIGZseSBkYXRhCgojIGV4cGVjdGVkIGVmZmVjdHMgb24gcGVyY2VudCBzY2FsZQpiMS5wIDwtIGIxL2IwKjEwMAoKIyBtYWtlIG1vZGVsIG1hdHJpeApzZWxlY3Rpb25fbGV2ZWxzIDwtIGMoIkNOIiwgIkFBIikgI0FBIGlzIHNlbGVjdGVkCnggPC0gZGF0YS50YWJsZShUcmVhdG1lbnQ9ZmFjdG9yKHJlcChzZWxlY3Rpb25fbGV2ZWxzLCBlYWNoPW4pLCBzZWxlY3Rpb25fbGV2ZWxzKSkKWCA8LSBtb2RlbC5tYXRyaXgoZm9ybXVsYSh+VHJlYXRtZW50KSwgeCkKCiMgbWFrZSBkYXRhCm5pdGVyIDwtIDEwXjQKcmVzMSA8LSBtYXRyaXgoTkEsIG5yb3c9bml0ZXIsIG5jb2w9MikgIyBuYWl2ZQpjb2xuYW1lcyhyZXMxKSA8LSBjKCJjaS5sb3ciLCAiY2kuaGlnaCIpCnJlczIgPC0gbWF0cml4KE5BLCBucm93PW5pdGVyLCBuY29sPTIpICMgbG9nIHJhdGlvCmNvbG5hbWVzKHJlczIpIDwtIGMoImNpLmxvdyIsICJjaS5oaWdoIikKcmVzMyA8LSBtYXRyaXgoTkEsIG5yb3c9bml0ZXIsIG5jb2w9MikgIyBkZWx0YQpjb2xuYW1lcyhyZXMzKSA8LSBjKCJjaS5sb3ciLCAiY2kuaGlnaCIpCmZvcihpdGVyIGluIDE6bml0ZXIpewogIHkgPC0gKFglKiViICsgcm5vcm0obioyLCBzZD1zaWdtYSkpWywxXQogIGZkIDwtIGRhdGEudGFibGUoWT15LCB4KQogIGZpdDEgPC0gbG0oWX5UcmVhdG1lbnQsIGRhdGE9ZmQpCiAgYmhhdCA8LSBjb2VmKGZpdDEpCiAgCiAgIyBuYWl2ZSBtZXRob2QKICBjaSA8LSBjb25maW50KGZpdDEpWyJUcmVhdG1lbnRBQSIsIF0KICByZXMxW2l0ZXIsIF0gPC0gY2kvYmhhdFsxXSoxMDAKICAKICAjIGxvZyBtZXRob2QKICBmaXQxLmxvZyA8LSBsbShsb2coWSl+VHJlYXRtZW50LCBkYXRhPWZkKQogIGNpIDwtIGV4cChjb25maW50KGZpdDEubG9nKVsiVHJlYXRtZW50QUEiLCBdKS0xCiAgcmVzMltpdGVyLCBdIDwtIGNpKjEwMAoKICAjIGRlbHRhIG1ldGhvZAogIGRmIDwtIGZpdDEkZGYucmVzaWR1YWwKICB0Y3JpdCA8LSBxdCguOTc1LCBkZikKICBzZCA8LSBzdW1tYXJ5KGZpdDEpJHNpZ21hCiAgc2UgPC0gZGVsdGFtZXRob2QofngyL3gxLCBtZWFuPWNvZWYoZml0MSksIGNvdj12Y292KGZpdDEpKQogIHJlczNbaXRlciwgImNpLmxvdyJdIDwtIDEwMCooYmhhdFsyXS9iaGF0WzFdIC0gdGNyaXQqc2UpCiAgcmVzM1tpdGVyLCAiY2kuaGlnaCJdIDwtIDEwMCooYmhhdFsyXS9iaGF0WzFdICsgdGNyaXQqc2UpCiAgCiAgIyBmdW4gbWF0aAogICMgRyhYKSA9IGIxL2IwIG9yIHkveCBvciB4Mi94MQogICMgZGVsKHkveCkgPSAoeS94XjIsIDEveCkKICAjIGRlbChiMS9iMCkgPSAoYjEvYjBeMiwgMS9iMCkKICAjIGRlbCA8LSBjKGJoYXRbMl0vYmhhdFsxXV4yLCAxL2JoYXRbMV0pCiAgIyBzZS5mdW4gPC0gc3FydCh0KGRlbCklKiV2Y292KGZpdDEpJSolZGVsKQp9CgpuYWl2ZSA8LSBsZW5ndGgod2hpY2gocmVzMVssImNpLmxvdyJdIDwgYjEucCAmIHJlczFbLCJjaS5oaWdoIl0gPiBiMS5wKSkvbml0ZXIqMTAwCmxvZ3JhdGlvIDwtIGxlbmd0aCh3aGljaChyZXMyWywiY2kubG93Il0gPCBiMS5wICYgcmVzMlssImNpLmhpZ2giXSA+IGIxLnApKS9uaXRlcioxMDAKZGVsdGEgPC0gbGVuZ3RoKHdoaWNoKHJlczNbLCJjaS5sb3ciXSA8IGIxLnAgJiByZXMzWywiY2kuaGlnaCJdID4gYjEucCkpL25pdGVyKjEwMAoKcmVzX3RhYmxlIDwtIGRhdGEudGFibGUoTWV0aG9kPWMoIm5haXZlIiwgImxvZyIsICJkZWx0YSIpLAogICAgICAgICAgICAgICAgICAgICAgICBDb3ZlcmFnZT1yb3VuZChjKG5haXZlLCBsb2dyYXRpbywgZGVsdGEpLDEpKQprbml0cjo6a2FibGUocmVzX3RhYmxlKQpgYGAKClRoZSB0YWJsZSBhYm92ZSBzaG93cyB0aGUgbG9uZyBydW4gKCQxMF40JCBydW5zKSBmcmVxdWVuY3kgb2YgQ0lzIHRoYXQgaW5jbHVkZSB0aGUgdHJ1ZSByZWxhdGl2ZSBkaWZmZXJlbmNlIGZvciBlYWNoIG9mIHRoZSB0aHJlZSBtZXRob2RzLiBUaGUgc2ltdWxhdGlvbiBjb25maXJtcyB0aGF0IGEgbmFpdmUgQ0kgaXMgdG9vIG5hcnJvdywgd2hpY2ggaXMgd2h5IGZhciBmZXdlciB0aGFuIDk1JSBvZiB0aGUgQ0lzIGNvdmVyZWQgdGhlIHRydWUgdmFsdWUuIFRoZSBuYXJyb3cgaW50ZXJ2YWwgaW1wbGllcyBhIHN0YW5kYXJkIGVycm9yIHRoYXQgaXMgdG9vIHNtYWxsLCBhbmQgYSAkdCQtdmFsdWUgdGhhdCBpcyB0b28gbGFyZ2UsIGFuZCBhICRwJC12YWx1ZSB0aGF0IGlzIHRvbyAib3B0aW1pc3RpYyIuCgpCb3RoIHRoZSBsb2cgdHJhbnNmb3JtIGFuZCBlc3BlaWNhbGx5IERlbHRhIG1ldGhvZHMgaGF2ZSBjbG9zZSB0byB0aGUgbm9taW5hbCBjb3ZlcmFnZS4gTmV2ZXJ0aGVsZXNzLCB0aGVyZSBhcmUgaW50ZXJlc3RpbmcgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgbG9nIGFuZCBEZWx0YSBtZXRob2RzLgoKYGBge3IgdHdvLWxldmVsLXBsb3R9CnAxIDwtIHFwbG90KHJlczJbLDFdLCByZXMzWywxXSkgKwogIHhsYWIoIkxvd2VyIENJIChsb2cgbWV0aG9kKSIpICsKICB5bGFiKCJMb3dlciBDSSAoRGVsdGEgbWV0aG9kKSIpICsKICBnZW9tX2FibGluZShpbnRlcmNlcHQ9MCwgc2xvcGU9MSwgY29sb3I9InJlZCIpICsKICBOVUxMCnAyIDwtIHFwbG90KHJlczJbLDJdLCByZXMzWywyXSkgKwogIHhsYWIoIlVwcGVyIENJIChsb2cgbWV0aG9kKSIpICsKICB5bGFiKCJVcHBlciBDSSAoRGVsdGEgbWV0aG9kKSIpICsKICBnZW9tX2FibGluZShpbnRlcmNlcHQ9MCwgc2xvcGU9MSwgY29sb3I9InJlZCIpICsKICBOVUxMCnBsb3RfZ3JpZChwMSwgcDIsIG5jb2w9MiwgbGFiZWxzPSJBVVRPIikKYGBgCgpUaGUgcGxvdHMgYWJvdmUgc2hvdyB0aGF0IHRoZSBDSXMgZXN0aW1hdGVkIHVzaW5nIHRoZSBsb2cgdHJhbnNmb3JtYXRpb24gaXMgInJpZ2h0IiBzaGlmdGVkIChpLmUuIHRvIGxhcmdlciB2YWx1ZXMpIGNvbXBhcmVkIHRvIHRoZSBDSXMgZXN0aW1hdGVkIHVzaW5nIHRoZSBEZWx0YSBtZXRob2QuIFRoaXMgcmlnaHQgc2hpZnQgaXMgYmVjYXVzZSB0aGUgbWVhbiBpbiB0aGUgZGVub21pbmF0b3Igb2YgdGhlIHJlbGF0aXZlIGVmZmVjdCBpcyBhIGdlb21ldHJpYyBtZWFuIHVzaW5nIHRoZSBsb2cgbWV0aG9kLCBidXQgYW4gYXJpdGhlbWV0aWMgbWVhbiB1c2luZyB0aGUgRGVsdGEgbWV0aG9kLiBCZWNhdXNlIGEgZ2VvbWV0cmljIG1lYW4gaXMgYWx3YXlzIHNtYWxsZXIgdGhhbiB0aGUgYXJpdGhtZXRpYyBtZWFuLCB0aGUgcmVsYXRpdmUgZWZmZWN0IHVzaW5nIHRoZSBsb2cgbWV0aG9kIHdpbGwgYmUgYmlnZ2VyIHRoYW4gdGhlIHJlbGF0aXZlIGVmZmVjdCBjb21wdXRlZCB1c2luZyB0aGUgRGVsdGEgbWV0aG9kLiBNb3JlIGN1cmlvdXNseSwgaG93IGNhbiBib3RoIG1ldGhvZHMgaGF2ZSBzZWVtaW5nbHkgZ29vZCBjb3ZlcmFnZSBpZiB0aGUgQ0kgY29tcHV0ZWQgdXNpbmcgdGhlIGxvZyBtZXRob2QgaXMgcmlnaHQtc2hpZnRlZCByZWxhdGl2ZSB0byB0aGUgQ0kgY29tcHV0ZWQgdXNpbmcgdGhlIERlbHRhIG1ldGhvZD8KCmBgYHtyIHR3by1sZXZlbC1zaGlmdH0KbG9ncmF0aW8ubG8gPC0gbGVuZ3RoKHdoaWNoKHJlczJbLCJjaS5sb3ciXSA+IGIxLnApKS9uaXRlcioxMDAKZGVsdGEubG8gPC0gbGVuZ3RoKHdoaWNoKHJlczNbLCJjaS5sb3ciXSA+IGIxLnApKS9uaXRlcioxMDAKbG9ncmF0aW8uaGkgPC0gbGVuZ3RoKHdoaWNoKHJlczJbLCJjaS5oaWdoIl0gPCBiMS5wKSkvbml0ZXIqMTAwCmRlbHRhLmhpIDwtIGxlbmd0aCh3aGljaChyZXMzWywiY2kuaGlnaCJdIDwgYjEucCkpL25pdGVyKjEwMAoKcmVzX3RhYmxlIDwtIGRhdGEudGFibGUoTWV0aG9kPWMoImxvZyIsICJkZWx0YSIpLAogICAgICAgICAgICAgICAgICAgICAgICBMb3dlcj1yb3VuZChjKGxvZ3JhdGlvLmxvLCBkZWx0YS5sbyksMSksCiAgICAgICAgICAgICAgICAgICAgICAgIFVwcGVyPXJvdW5kKGMobG9ncmF0aW8uaGksIGRlbHRhLmhpKSwxKQogICAgICAgICAgICAgICAgICAgICAgICApCmtuaXRyOjprYWJsZShyZXNfdGFibGUpCmBgYAoKVGhlIHRhYmxlIGFib3ZlIGdpdmVzIHRoZSBsb25nIHJ1biBmcmVxdWVuY3kgb2YgdHJ1ZSByZWxhdGl2ZSBlZmZlY3RzIHRoYXQgYXJlIGxlc3MgdGhhbiB0aGUgbG93ZXIgQ0kgb3IgZ3JlYXRlciB0aGFuIHRoZSB1cHBlciBDSSBmb3IgdGhlIGxvZyBhbmQgRGVsdGEgbWV0aG9kcy4gVGhlIGxvZyBtZXRob2Qgc2hvd3MgYSBoaWdoZXIgdGhhbiBleHBlY3RlZCBmcmVxdWVuY3kgYXQgdGhlIGxvd2VyIENJIGFuZCBsb3dlciB0aGFuIGV4cGVjdGVkIGZyZXF1ZW5jeSBhdCB0aGUgdXBwZXIgQ0ksIGluZGljYXRlZCB0aGF0IHRoZSBDSXMgY29tcHV0ZWQgdXNpbmcgdGhlIGxvZyB0cmFuc2Zvcm1hdGlvbiBhcmUgc2xpZ2h0bHkgcmlnaHQtc2hpZnRlZC4gVGhlIERlbHRhIG1ldGhvZCBzaG93cyB0aGUgb3Bwb3NpdGUgcGF0dGVybiwgaW5kaWNhdGluZyB0aGF0IHRoZSBDSXMgY29tcHV0ZWQgdXNpbmcgdGhlIERlbHRhIG1ldGhvZCBhcmUgc2xpZ2h0bHkgbGVmdC1zaGlmdGVkLiBJIGFzc3VtZSB0aGVzZSBzaGlmdHMgYXJlIHJlYWwgKGFsdGhvdWdoIHRoZXkgbWF5IGJlIGNvbmRpdGlvbmFsIG9uIHRoZSBwYXJhbWV0ZXJpemF0aW9uKSBhbmQgbm90IGp1c3Qgc2FtcGxlIGFydGlmYWN0cy4gUmVnYXJkbGVzcywgZGVzcGl0ZSB0aGVzZSBzaGlmdHMsIHRoZSBjb3ZlcmFnZSBvdmVyIHRoZSByYW5nZSBpcyBjbG9zZSB0byAob3IgZXF1YWwgdG8gZm9yIHRoZSBEZWx0YSBtZXRob2QpIHRoZSBleHBlY3RlZCBjb3ZlcmFnZS4KCiMjIFNpbmdsZSBmYWN0b3Igd2l0aCBmb3VyIGxldmVscyAoInBvc3QtaG9jIikKClRoZSBEZWx0YSBtZXRob2QgaXMgZWFzaWx5IGFwcGxpZWQgdG8gbW9yZSBjb21wbGV4IGRlc2lnbnMgYnV0IGl0cyBub3QgY2xlYXIgaG93IHRvIGltcGxlbWVudCB0aGUgbG9nIG1ldGhvZCBpbiBtb3JlIGNvbXBsZXggZGVzaWducy4gRm9yIGV4YW1wbGUsIGlmIHRoZXJlIGFyZSBmb3VyIGxldmVscyBpbiBhIGZhY3RvciBhbmQgd2Ugd2FudCB0aGUgY29udHJhc3QgYW5kIENJcyBmb3IgYWxsIHNpeCBwYWlyd2lzZSBlZmZlY3RzLCBkbyB3ZSBqdXN0IGxvZyB0cmFuc2Zvcm0gdGhlIHJlc3BvbnNlIGFuZCBiYWNrdHJhbnNmb3JtIHRoZSBDSXMgb2YgdGhlIGNvbnRyYXN0cyAodGhlICJ3aG9sZSBtb2RlbCIgbG9nIG1ldGhvZCkgb3IgZG8gd2UgZG8gdGhlIGxvZyBtZXRob2Qgb24gYWxsIHNpeCBjb250cmFzdHMgaW5kZXBlbmRlbnRseSAodGhlICJwYWlyd2lzZSIgbG9nIG1ldGhvZCk/CgpIZXJlLCBJIGV2YWx1YXRlIHRoZSB0d28gbG9nIG1ldGhvZHMsIGFzIHdlbGwgYXMgdGhlIG5haXZlIGFuZCBEZWx0YSBtZXRob2RzLCBieSBjb21wYXJpbmcgdGhlIHJlbGF0aXZlIGRpZmZlcmVuY2Ugb2YgdGhyZWUgbm9uLXJlZmVyZW5jZSBsZXZlbHMgb2YgdGhlIGZseSBkYXRhIChzZWxlY3RlZCBmZW1hbGVzLCBjb250cm9sIG1hbGVzLCBzZWxlY3RlZCBtYWxlcykgZnJvbSB0aGUgcmVmZXJlbmNlIGxldmVsIChjb250cm9sIGZlbWFsZXMgb3IgIkNOLUYiKS4KCmBgYHtyIGZvdXItbGV2ZWxzLCBldmFsPVRSVUV9CiMgdXNlIHRoZSBmb3VyIGZseSBsZXZlbHMgYnV0IHByZXRlbmQgaXQgaXMgbm90IGZhY3RvcmlhbApzZXQuc2VlZCgxKQpuIDwtIDI3ICMgYXZlcmFnZSBuIG92ZXIgdGhlIGZvdXIgZ3JvdXBzIG9mIGZsaWVzCiMgbWVhbnMKbXUgPC0gYygxMzEuNiwgMTgxLjAsIDExNy41LCAxNzYuNSkgI0NOLUYsIEFBLUYsIENOLU0sIEFBLU0KYjAgPC0gMTMxLjYgIyBjb250cm9sIGZlbWFsZXMKYjEgPC0gMTgxLjAgLSBiMCAjIGVmZmVjdCBvZiBzZWxlY3Rpb24gaW4gZmVtYWxlcwpiMiA8LSAxMTcuNSAtIGIwICMgZWZmZWN0IG9mIG1hbGUgaW4gY29udHJvbApiMyA8LSAxNzYuNSAtIGIwICMgZWZmZWN0IG9mIHNlbGVjdGlvbiBhbmQgbWFsZSAtLSBub3QgYW4gaW50ZXJhY3Rpb24gZWZmZWN0IQoKIyBwYXJhbWV0ZXJzIGdhdGhlcmVkIGludG8gdmVjdG9yCmIgPC0gYyhiMCwgYjEsIGIyLCBiMykKCiMgZXJyb3Igc3RhbmRhcmQgZGV2aWF0aW9uCnNpZ21hIDwtIDE5LjIgIyByZXNpZHVhbCBzdGFuZGFyZCBlcnJvciBvZiBmbHkgZGF0YQoKIyBleHBlY3RlZCBlZmZlY3RzIG9uIHJlc3BvbnNlIGFuZCBwZXJjZW50IHNjYWxlCiMgY2FsbCB0aGUgZXhwZWN0ZWQKYjEucCA8LSBiMS9iMCoxMDAKYjIucCA8LSBiMi9iMCoxMDAKYjMucCA8LSBiMy9iMCoxMDAKCiMgbWFrZSBtb2RlbCBtYXRyaXgKQV9sZXZlbHMgPC0gYygiQ04tRiIsICJBQS1GIiwgIkNOLU0iLCAiQUEtTSIpCnggPC0gZGF0YS50YWJsZShUcmVhdG1lbnQ9ZmFjdG9yKHJlcChBX2xldmVscywgZWFjaD1uKSwgZmFjdG9yKEFfbGV2ZWxzKSkpClggPC0gbW9kZWwubWF0cml4KGZvcm11bGEoflRyZWF0bWVudCksIHgpCm5fY2VsbHMgPC0gbGVuZ3RoKGxldmVscyh4JFRyZWF0bWVudCkpCgojIG1ha2UgZGF0YQpuaXRlciA8LSAxMF40CnJlczEubG8gPC0gbWF0cml4KE5BLCBucm93PW5pdGVyLCBuY29sPTMpICMgbmFpdmUKcmVzMS51cCA8LSBtYXRyaXgoTkEsIG5yb3c9bml0ZXIsIG5jb2w9MykgIyBuYWl2ZQpyZXMyLmxvIDwtIG1hdHJpeChOQSwgbnJvdz1uaXRlciwgbmNvbD0zKSAjIGxvZwpyZXMyLnVwIDwtIG1hdHJpeChOQSwgbnJvdz1uaXRlciwgbmNvbD0zKSAjIGxvZwpyZXMzLmxvIDwtIG1hdHJpeChOQSwgbnJvdz1uaXRlciwgbmNvbD0zKSAjIGRlbHRhCnJlczMudXAgPC0gbWF0cml4KE5BLCBucm93PW5pdGVyLCBuY29sPTMpICMgZGVsdGEKcmVzNC5sbyA8LSBtYXRyaXgoTkEsIG5yb3c9bml0ZXIsIG5jb2w9MykgIyBsb2ctcGFpcndpc2UKcmVzNC51cCA8LSBtYXRyaXgoTkEsIG5yb3c9bml0ZXIsIG5jb2w9MykgIyBsb2ctcGFpcndpc2UKZm9yKGl0ZXIgaW4gMTpuaXRlcil7CiAgeSA8LSAoWCUqJWIgKyBybm9ybShuKm5fY2VsbHMsIHNkPXNpZ21hKSlbLDFdCiAgZmQgPC0gZGF0YS50YWJsZShZPXksIHgpCiAgZml0MSA8LSBsbShZflRyZWF0bWVudCwgZGF0YT1mZCkKICBiaGF0IDwtIGNvZWYoZml0MSkKICAjIGNvbnRyYXN0KGVtbWVhbnMoZml0MSwgc3BlY3M9IlRyZWF0bWVudCIpLCBhZGp1c3Q9Im5vbmUiLCBtZXRob2Q9InJldnBhaXJ3aXNlIikKICAKICAjIG5haXZlIG1ldGhvZAogIGNpLmxvIDwtIGNvbmZpbnQoZml0MSlbMjo0LCAiMi41ICUiXQogIGNpLnVwIDwtIGNvbmZpbnQoZml0MSlbMjo0LCAiOTcuNSAlIl0KICByZXMxLmxvW2l0ZXIsIF0gPC0gY2kubG8vYmhhdFsxXSoxMDAKICByZXMxLnVwW2l0ZXIsIF0gPC0gY2kudXAvYmhhdFsxXSoxMDAKICAKICAjIGxvZyBtZXRob2QgMSAtIHJ1biBldmVyeXRoaW5nIGF0IG9uY2UKICBmaXQyIDwtIGxtKGxvZyhZKX5UcmVhdG1lbnQsIGRhdGE9ZmQpCiAgY2kubG8gPC0gZXhwKGNvbmZpbnQoZml0MilbMjo0LCAiMi41ICUiXSkgLSAxCiAgY2kudXAgPC0gZXhwKGNvbmZpbnQoZml0MilbMjo0LCAiOTcuNSAlIl0pIC0gMQogIHJlczIubG9baXRlciwgXSA8LSBjaS5sbyoxMDAKICByZXMyLnVwW2l0ZXIsIF0gPC0gY2kudXAqMTAwCiAgCiAgIyBsb2cgbWV0aG9kIDIgLS0gcGFpcndpc2UKICBmaXQyIDwtIGxtKGxvZyhZKX5UcmVhdG1lbnQsIGRhdGE9ZmRbVHJlYXRtZW50PT0iQ04tRiIgfCBUcmVhdG1lbnQ9PSJBQS1GIl0pCiAgY2kubG8gPC0gZXhwKGNvbmZpbnQoZml0MilbMiwgIjIuNSAlIl0pIC0gMQogIGNpLnVwIDwtIGV4cChjb25maW50KGZpdDIpWzIsICI5Ny41ICUiXSkgLSAxCiAgcmVzNC5sb1tpdGVyLCAxXSA8LSBjaS5sbyoxMDAKICByZXM0LnVwW2l0ZXIsIDFdIDwtIGNpLnVwKjEwMAoKICBmaXQyIDwtIGxtKGxvZyhZKX5UcmVhdG1lbnQsIGRhdGE9ZmRbVHJlYXRtZW50PT0iQ04tRiIgfCBUcmVhdG1lbnQ9PSJDTi1NIl0pCiAgY2kubG8gPC0gZXhwKGNvbmZpbnQoZml0MilbMiwgIjIuNSAlIl0pIC0gMQogIGNpLnVwIDwtIGV4cChjb25maW50KGZpdDIpWzIsICI5Ny41ICUiXSkgLSAxCiAgcmVzNC5sb1tpdGVyLCAyXSA8LSBjaS5sbyoxMDAKICByZXM0LnVwW2l0ZXIsIDJdIDwtIGNpLnVwKjEwMAoKICBmaXQyIDwtIGxtKGxvZyhZKX5UcmVhdG1lbnQsIGRhdGE9ZmRbVHJlYXRtZW50PT0iQ04tRiIgfCBUcmVhdG1lbnQ9PSJBQS1NIl0pCiAgY2kubG8gPC0gZXhwKGNvbmZpbnQoZml0MilbMiwgIjIuNSAlIl0pIC0gMQogIGNpLnVwIDwtIGV4cChjb25maW50KGZpdDIpWzIsICI5Ny41ICUiXSkgLSAxCiAgcmVzNC5sb1tpdGVyLCAzXSA8LSBjaS5sbyoxMDAKICByZXM0LnVwW2l0ZXIsIDNdIDwtIGNpLnVwKjEwMAoKICAjIGRlbHRhIG1ldGhvZAogIGRmIDwtIGZpdDEkZGYucmVzaWR1YWwKICB0Y3JpdCA8LSBxdCguOTc1LCBkZikKICBzZCA8LSBzdW1tYXJ5KGZpdDEpJHNpZ21hCiAgc2UgPC0gYygKICAgIGRlbHRhbWV0aG9kKH54Mi94MSwgbWVhbj1jb2VmKGZpdDEpLCBjb3Y9dmNvdihmaXQxKSksCiAgICBkZWx0YW1ldGhvZCh+eDMveDEsIG1lYW49Y29lZihmaXQxKSwgY292PXZjb3YoZml0MSkpLAogICAgZGVsdGFtZXRob2Qofng0L3gxLCBtZWFuPWNvZWYoZml0MSksIGNvdj12Y292KGZpdDEpKQogICkKICByZXMzLmxvW2l0ZXIsIF0gPC0gMTAwKihiaGF0WzI6NF0vYmhhdFsxXSAtIHRjcml0KnNlKQogIHJlczMudXBbaXRlciwgXSA8LSAxMDAqKGJoYXRbMjo0XS9iaGF0WzFdICsgdGNyaXQqc2UpCn0KCm5haXZlIDwtIGMobGVuZ3RoKHdoaWNoKHJlczEubG9bLDFdIDwgYjEucCAmIHJlczEudXBbLDFdID4gYjEucCkpL25pdGVyKjEwMCwKICAgICAgICAgICBsZW5ndGgod2hpY2gocmVzMS5sb1ssMl0gPCBiMi5wICYgcmVzMS51cFssMl0gPiBiMi5wKSkvbml0ZXIqMTAwLAogICAgICAgICAgIGxlbmd0aCh3aGljaChyZXMxLmxvWywzXSA8IGIzLnAgJiByZXMxLnVwWywzXSA+IGIzLnApKS9uaXRlcioxMDAKKQpsb2dyYXRpbzEgPC0gYyhsZW5ndGgod2hpY2gocmVzMi5sb1ssMV0gPCBiMS5wICYgcmVzMi51cFssMV0gPiBiMS5wKSkvbml0ZXIqMTAwLAogICAgICAgICAgICAgIGxlbmd0aCh3aGljaChyZXMyLmxvWywyXSA8IGIyLnAgJiByZXMyLnVwWywyXSA+IGIyLnApKS9uaXRlcioxMDAsCiAgICAgICAgICAgICAgbGVuZ3RoKHdoaWNoKHJlczIubG9bLDNdIDwgYjMucCAmIHJlczIudXBbLDNdID4gYjMucCkpL25pdGVyKjEwMAopCmxvZ3JhdGlvMiA8LSBjKGxlbmd0aCh3aGljaChyZXM0LmxvWywxXSA8IGIxLnAgJiByZXM0LnVwWywxXSA+IGIxLnApKS9uaXRlcioxMDAsCiAgICAgICAgICAgICAgbGVuZ3RoKHdoaWNoKHJlczQubG9bLDJdIDwgYjIucCAmIHJlczQudXBbLDJdID4gYjIucCkpL25pdGVyKjEwMCwKICAgICAgICAgICAgICBsZW5ndGgod2hpY2gocmVzNC5sb1ssM10gPCBiMy5wICYgcmVzNC51cFssM10gPiBiMy5wKSkvbml0ZXIqMTAwCikKZGVsdGEgPC0gYyhsZW5ndGgod2hpY2gocmVzMy5sb1ssMV0gPCBiMS5wICYgcmVzMy51cFssMV0gPiBiMS5wKSkvbml0ZXIqMTAwLAogICAgICAgICAgIGxlbmd0aCh3aGljaChyZXMzLmxvWywyXSA8IGIyLnAgJiByZXMzLnVwWywyXSA+IGIyLnApKS9uaXRlcioxMDAsCiAgICAgICAgICAgbGVuZ3RoKHdoaWNoKHJlczMubG9bLDNdIDwgYjMucCAmIHJlczMudXBbLDNdID4gYjMucCkpL25pdGVyKjEwMAopCnJlcy50YWJsZSA8LSBkYXRhLnRhYmxlKHJiaW5kKG5haXZlLCBsb2dyYXRpbzEsIGxvZ3JhdGlvMiwgZGVsdGEpKQpjb2xuYW1lcyhyZXMudGFibGUpIDwtIGMoIkFBRi1DTkYiLCAiQ05NLUNORiIsICJBQU0tQ05GIikKcmVzLnRhYmxlIDwtIGNiaW5kKE1ldGhvZD1jKCJuYWl2ZSIsICJsb2ciLCAibG9nLXB3IiwgIkRlbHRhIiksIHJlcy50YWJsZSkKa25pdHI6OmthYmxlKHJlcy50YWJsZSwgZGlnaXRzPWMoMCwxLDEsMSkpCmBgYAoKVGhlIHRhYmxlIGFib3ZlIHNob3dzIHRoZSBsb25nIHJ1biAoJDEwXjQkIHJ1bnMpIGZyZXF1ZW5jeSBvZiBDSXMgdGhhdCBpbmNsdWRlIHRoZSB0cnVlIHJlbGF0aXZlIGRpZmZlcmVuY2UgZm9yIGVhY2ggb2YgdGhlIHRocmVlIGNvbnRyYXN0cyAoZGlmZmVyZW5jZXMgZnJvbSBDTi1GKSBmb3IgZWFjaCBvZiB0aGUgZm91ciBtZXRob2RzLCBpbmNsdWRpbmcgYm90aCB0aGUgd2hvbGUtbW9kZWwgYW5kIHBhaXJ3aXNlIGxvZyBtZXRob2RzLiBUaGUgd2hvbGUtbW9kZWwgbG9nIG1ldGhvZCBjYW4gaGF2ZSBpbnRlcnZhbHMgdGhhdCBhcmUgdHdvIG5hcnJvdywgYXMgaW5kaWNhdGVkIGJ5IHRoZSBsb3dlci10aGFuLW5vbWluYWwgZnJlcXVlbmN5IGZvciB0aGUgQ04tRiByZWxhdGl2ZSBkaWZmZXJlbmNlLiBUaGUgZnJlcXVlbmNpZXMgb2YgdGhlIHJ1bi1wYWlyd2lzZSBsb2cgbWV0aG9kIGFuZCBEZXRhIG1ldGhvZCBsb29rIHByZXR0eSBnb29kLCBidXQgdGhpcyBpcyBvbmx5IG9uZSBwYXJhbWV0ZXJpemF0aW9uLgoKIyMgRmFjdG9yaWFsICgyIFggMikKYGBge3IgZmFjdG9yaWFsLCBldmFsPVRSVUV9CiMgdXNlIHRoZSBmb3VyIGZseSBsZXZlbHMgaW4gYSBmdWxseSBmYWN0b3JpYWwgZGVzaWduCnNldC5zZWVkKDEpCm4gPC0gMjcgIyBhdmVyYWdlIG4gb3ZlciB0aGUgZm91ciBncm91cHMgb2YgZmxpZXMKIyBtZWFucwptdSA8LSBjKDEzMS42LCAxODEuMCwgMTE3LjUsIDE3Ni41KSAjQ04tRiwgQUEtRiwgQ04tTSwgQUEtTQpiMCA8LSAxMzEuNiAjIGNvbnRyb2wgZmVtYWxlcwpiMSA8LSAxODEuMCAtIGIwICMgZWZmZWN0IG9mIHNlbGVjdGlvbiBpbiBmZW1hbGVzCmIyIDwtIDExNy41IC0gYjAgIyBlZmZlY3Qgb2YgbWFsZSBpbiBjb250cm9sCmIzIDwtIDE3Ni41IC0gKGIwICsgYjEgKyBiMikgIyBpbnRlcmFjdGlvbiBlZmZlY3QhCgojIHBhcmFtZXRlcnMgZ2F0aGVyZWQgaW50byB2ZWN0b3IKYiA8LSBjKGIwLCBiMSwgYjIsIGIzKQoKIyBlcnJvciBzdGFuZGFyZCBkZXZpYXRpb24Kc2lnbWEgPC0gMTkuMiAjIHJlc2lkdWFsIHN0YW5kYXJkIGVycm9yIG9mIGZseSBkYXRhCgojIGV4cGVjdGVkIGVmZmVjdHMgb24gcmVzcG9uc2UgYW5kIHBlcmNlbnQgc2NhbGUKIyB0aGVyZSBhcmUgMiB4IDIgPSBmb3VyIHBhaXJ3aXNlIGVmZmVjdHMgKG9mIG9uZSB0cmVhdG1lbnQgd2l0aGluIGVhY2ggbGV2ZWwgb2YgdGhlIG90aGVyIHRyZWF0bWVudCkKIyBjYWxsIHRoZXNlIEEwIGFuZCBBMSwgQjAgYW5kIEIxCiMgY2FsbCB0aGUgZXhwZWN0ZWQKQTAgPC0gYjEKQTEgPC0gKChiMCtiMStiMitiMyktKGIwK2IyKSkKQTAucCA8LSAxMDAqQTAvYjAKQTEucCA8LSAxMDAqQTEvKGIwK2IyKQoKIyBtYWtlIG1vZGVsIG1hdHJpeApBX2xldmVscyA8LSBmYWN0b3IocmVwKGMoIkNOIiwgIkFBIiksIGVhY2g9biksIGMoIkNOIiwgIkFBIikpCkJfbGV2ZWxzIDwtIGZhY3RvcihjKCJGIiwgIk0iKSkKeCA8LSBleHBhbmQuZ3JpZChUcmVhdG1lbnQ9QV9sZXZlbHMsU2V4PUJfbGV2ZWxzKQpYIDwtIG1vZGVsLm1hdHJpeChmb3JtdWxhKH5UcmVhdG1lbnQqU2V4KSwgeCkKCgpzZXQuc2VlZCgxKQpuaXRlciA8LSAxMF40Cm1ldGhvZHMgPC0gYygibmFpdmUiLCAibG9nIiwgImxvZy1wdyIsICJEZWx0YSIpCm4ubWV0aG9kcyA8LSBsZW5ndGgobWV0aG9kcykKcmVzIDwtIGRhdGEuZnJhbWUobWV0aG9kPXJlcChtZXRob2RzLCBuaXRlciksCiAgICAgICAgICAgICAgICAgIEEwLmxvPU5BLAogICAgICAgICAgICAgICAgICBBMC51cD1OQSwKICAgICAgICAgICAgICAgICAgQTEubG89TkEsCiAgICAgICAgICAgICAgICAgIEExLnVwPU5BKQpyb3cuZSA8LSAwICMgZW5kIHJvdyBmb3Igc2F2aW5nIApmb3IoaXRlciBpbiAxOm5pdGVyKXsKICAjIG1ha2UgZGF0YQogIHkgPC0gKFglKiViICsgcm5vcm0obio0LCBzZD1zaWdtYSkpWywxXQogIGZkIDwtIGRhdGEudGFibGUoWT15LCB4KQogIAogICMgZml0CiAgZml0IDwtIGxtKFl+VHJlYXRtZW50KlNleCwgZGF0YT1mZCkKICBmaXQuZW1tIDwtIGVtbWVhbnMoZml0LCBzcGVjcz1jKCJUcmVhdG1lbnQiLCAiU2V4IikpCiAgZml0LmVmZiA8LSBzdW1tYXJ5KGNvbnRyYXN0KGZpdC5lbW0sIGFkanVzdD0ibm9uZSIsIG1ldGhvZD0icmV2cGFpcndpc2UiKSwgaW5mZXI9YyhUUlVFLCBUUlVFKSkKICAKICAjIGNlbGwgbWVhbnMKICB5YmFyMTEgPC0gc3VtbWFyeShmaXQuZW1tKVsxLCAiZW1tZWFuIl0gIyBDTi1GCiAgeWJhcjIxIDwtIHN1bW1hcnkoZml0LmVtbSlbMiwgImVtbWVhbiJdICMgQUEtRgogIHliYXIxMiA8LSBzdW1tYXJ5KGZpdC5lbW0pWzMsICJlbW1lYW4iXSAjIENOLU0KICB5YmFyMjIgPC0gc3VtbWFyeShmaXQuZW1tKVs0LCAiZW1tZWFuIl0gIyBBQS1NCiAgCiAgIyBuYWl2ZSBjb252ZXJ0IENJIHRvIHBlcmNlbnQKICBuYWl2ZSA8LSAxMDAqYygKICAgIGZpdC5lZmZbMSwgImxvd2VyLkNMIl0veWJhcjExLAogICAgZml0LmVmZlsxLCAidXBwZXIuQ0wiXS95YmFyMTEsCiAgICBmaXQuZWZmWzYsICJsb3dlci5DTCJdL3liYXIxMiwKICAgIGZpdC5lZmZbNiwgInVwcGVyLkNMIl0veWJhcjEyCiAgKQoKICAjIGxvZyBtZXRob2QgMSAtLSBydW4gZXZlcnl0aGluZyBhdCBvbmNlCiAgZml0MiA8LSBsbShsb2coWSl+VHJlYXRtZW50KlNleCwgZGF0YT1mZCkKICBmaXQyLmVtbSA8LSBlbW1lYW5zKGZpdDIsIHNwZWNzPWMoIlRyZWF0bWVudCIsICJTZXgiKSkKICBmaXQyLmVmZiA8LSBzdW1tYXJ5KGNvbnRyYXN0KGZpdDIuZW1tLCBhZGp1c3Q9Im5vbmUiLCBtZXRob2Q9InJldnBhaXJ3aXNlIiksIGluZmVyPWMoVFJVRSwgVFJVRSkpCiAgbG9ncmF0aW8xIDwtIDEwMCpjKAogICAgZXhwKGZpdDIuZWZmWzEsICJsb3dlci5DTCJdKS0xLAogICAgZXhwKGZpdDIuZWZmWzEsICJ1cHBlci5DTCJdKS0xLAogICAgZXhwKGZpdDIuZWZmWzYsICJsb3dlci5DTCJdKS0xLAogICAgZXhwKGZpdDIuZWZmWzYsICJ1cHBlci5DTCJdKS0xCiAgKQogIAogICMgbG9nIG1ldGhvZCAyIC0tIHBhaXJ3aXNlCiAgY29tYm9zIDwtIGMoIkNOLUYiLCAiQUEtRiIsICJDTi1NIiwgIkFBLU0iKQogIGZkWywgY29tYm86PWZhY3RvcihwYXN0ZShUcmVhdG1lbnQsIFNleCwgc2VwPSItIiksIGNvbWJvcyldCiAgZml0MiA8LSBsbShsb2coWSl+Y29tYm8sIGRhdGE9ZmRbY29tYm89PSJDTi1GIiB8IGNvbWJvPT0iQUEtRiJdKQogIGNpLmxvMSA8LSBleHAoY29uZmludChmaXQyKVsyLCAiMi41ICUiXSkgLSAxCiAgY2kudXAxIDwtIGV4cChjb25maW50KGZpdDIpWzIsICI5Ny41ICUiXSkgLSAxCgogIGZpdDIgPC0gbG0obG9nKFkpfmNvbWJvLCBkYXRhPWZkW2NvbWJvPT0iQ04tTSIgfCBjb21ibz09IkFBLU0iXSkKICBjaS5sbzIgPC0gZXhwKGNvbmZpbnQoZml0MilbMiwgIjIuNSAlIl0pIC0gMQogIGNpLnVwMiA8LSBleHAoY29uZmludChmaXQyKVsyLCAiOTcuNSAlIl0pIC0gMQogIAogIGxvZ3JhdGlvMiA8LSAxMDAqYyhjaS5sbzEsIGNpLnVwMSwgY2kubG8yLCBjaS51cDIpCgogICMgZGVsdGEKICBBMGhhdC5wIDwtIGZpdC5lZmZbMSwgImVzdGltYXRlIl0veWJhcjExCiAgQTFoYXQucCA8LSBmaXQuZWZmWzYsICJlc3RpbWF0ZSJdL3liYXIxMgogIHNlIDwtIGMoCiAgICBkZWx0YW1ldGhvZCh+eDIveDEsIG1lYW49Y29lZihmaXQpLCBjb3Y9dmNvdihmaXQpKSwKICAgIGRlbHRhbWV0aG9kKH4oeDIreDQpLyh4MSt4MyksIG1lYW49Y29lZihmaXQpLCBjb3Y9dmNvdihmaXQpKQogICkKICBkZWx0YSA8LSAxMDAqYygKICAgIEEwaGF0LnAtdGNyaXQqc2VbMV0sCiAgICBBMGhhdC5wK3Rjcml0KnNlWzFdLAogICAgQTFoYXQucC10Y3JpdCpzZVsyXSwKICAgIEExaGF0LnArdGNyaXQqc2VbMl0KICApCiAgcm93LnMgPC0gcm93LmUgKyAxCiAgcm93LmUgPC0gcm93LnMgKyBuLm1ldGhvZHMgLSAxCiAgcmVzW3Jvdy5zOnJvdy5lLCAyOihuLm1ldGhvZHMrMSldIDwtcmJpbmQobmFpdmUsIGxvZ3JhdGlvMSwgbG9ncmF0aW8yLCBkZWx0YSkKfQpyZXMgPC0gZGF0YS50YWJsZShyZXMpCgptZXRob2RfayA8LSAibmFpdmUiCm5haXZlIDwtIGMoCiAgbGVuZ3RoKHdoaWNoKHJlc1ttZXRob2Q9PW1ldGhvZF9rLEEwLmxvXSA8IEEwLnAgJiByZXNbbWV0aG9kPT1tZXRob2RfayxBMC51cF0gPiBBMC5wKSkvbml0ZXIqMTAwLAogIGxlbmd0aCh3aGljaChyZXNbbWV0aG9kPT1tZXRob2RfayxBMS5sb10gPCBBMS5wICYgcmVzW21ldGhvZD09bWV0aG9kX2ssQTEudXBdID4gQTEucCkpL25pdGVyKjEwMAopCgptZXRob2RfayA8LSAibG9nIgpsb2dyYXRpbzEgPC0gYygKICBsZW5ndGgod2hpY2gocmVzW21ldGhvZD09bWV0aG9kX2ssQTAubG9dIDwgQTAucCAmIHJlc1ttZXRob2Q9PW1ldGhvZF9rLEEwLnVwXSA+IEEwLnApKS9uaXRlcioxMDAsCiAgbGVuZ3RoKHdoaWNoKHJlc1ttZXRob2Q9PW1ldGhvZF9rLEExLmxvXSA8IEExLnAgJiByZXNbbWV0aG9kPT1tZXRob2RfayxBMS51cF0gPiBBMS5wKSkvbml0ZXIqMTAwCikKCm1ldGhvZF9rIDwtICJsb2ctcHciCmxvZ3JhdGlvMiA8LSBjKAogIGxlbmd0aCh3aGljaChyZXNbbWV0aG9kPT1tZXRob2RfayxBMC5sb10gPCBBMC5wICYgcmVzW21ldGhvZD09bWV0aG9kX2ssQTAudXBdID4gQTAucCkpL25pdGVyKjEwMCwKICBsZW5ndGgod2hpY2gocmVzW21ldGhvZD09bWV0aG9kX2ssQTEubG9dIDwgQTEucCAmIHJlc1ttZXRob2Q9PW1ldGhvZF9rLEExLnVwXSA+IEExLnApKS9uaXRlcioxMDAKKQoKbWV0aG9kX2sgPC0gIkRlbHRhIgpkZWx0YSA8LSBjKAogIGxlbmd0aCh3aGljaChyZXNbbWV0aG9kPT1tZXRob2RfayxBMC5sb10gPCBBMC5wICYgcmVzW21ldGhvZD09bWV0aG9kX2ssQTAudXBdID4gQTAucCkpL25pdGVyKjEwMCwKICBsZW5ndGgod2hpY2gocmVzW21ldGhvZD09bWV0aG9kX2ssQTEubG9dIDwgQTEucCAmIHJlc1ttZXRob2Q9PW1ldGhvZF9rLEExLnVwXSA+IEExLnApKS9uaXRlcioxMDAKKQoKcmVzLnRhYmxlIDwtIGRhdGEudGFibGUocmJpbmQobmFpdmUsIGxvZ3JhdGlvMSwgbG9ncmF0aW8yLCBkZWx0YSkpCmNvbG5hbWVzKHJlcy50YWJsZSkgPC0gYygiQUFGLUNORiIsICJBQU0tQ05NIikKcmVzLnRhYmxlIDwtIGNiaW5kKE1ldGhvZD1jKCJuYWl2ZSIsICJsb2ciLCAibG9nLXB3IiwgIkRlbHRhIiksIHJlcy50YWJsZSkKa25pdHI6OmthYmxlKHJlcy50YWJsZSwgZGlnaXRzPWMoMCwxLDEpKQoKYGBgCgpUaGUgdGFibGUgYWJvdmUgc2hvd3MgdGhlIGxvbmcgcnVuICgkMTBeNCQgcnVucykgZnJlcXVlbmN5IG9mIENJcyB0aGF0IGluY2x1ZGUgdGhlIHRydWUgcmVsYXRpdmUgZGlmZmVyZW5jZSBmb3IgdGhlIHR3byBzaW1wbGUgZWZmZWN0cyBvZiB0aGUgc2VsZWN0aW9uIGZhY3RvciBmb3IgZWFjaCBvZiB0aGUgZm91ciBtZXRob2RzLCBpbmNsdWRpbmcgYm90aCB0aGUgd2hvbGUtbW9kZWwgYW5kIHBhaXJ3aXNlIGxvZyBtZXRob2RzLiBBZ2FpbiwgdGhlIHBhaXJ3aXNlIGxvZyBtZXRob2QgYW5kIERlbHRhIG1ldGhvZCBoYXZlIHByZXR0eSBnb29kIGNvdmVyYWdlLiBUaGUgd2hvbGUtbW9kZWwgbG9nIG1ldGhvZCBpcyBsZXNzIGdvb2QgYW5kIHRoZSBuYWl2ZSBtZXRob2QgaXMgZXZlbiBsZXNzIGdvb2QhCgojIChwcm9iYWJseSBub3QpIEZpbmFsIHRob3VnaHRzCgpEbyBub3QgcmVwb3J0IG5haXZlIENJcyBvZiByZWxhdGl2ZSBlZmZlY3RzISBBbmQsIGlmIHlvdSBhcmUgZW1waGFzaXppbmcgc29tZSBhc3BlY3Qgb2YgaW5mZXJlbmNlIHVzaW5nIGEgcmVsYXRpdmUgZWZmZWN0LCBzdWNoIGFzIGEgJHAkLXZhbHVlLCBtYWtlIHN1cmUgdGhlICRwJC12YWx1ZSBpcyBjb21wdXRlZCBmcm9tIGEgc3RhdGlzdGljYWxseSBjb3JyZWN0IHN0YW5kYXJkIGVycm9yLCB3aGljaCBpc24ndCBhIG5haXZlIFNFICh0aGUgYWJzb2x1dGUgU0UgZGl2aWRlZCBieSB0aGUgcmVmZXJlbmNlIG1lYW4gdGltZXMgMTAwKS4KCklmIHRoZSBtb2RlbCBpcyBhbnl0aGluZyBtb3JlIGNvbXBsZXggdGhhbiBhIHNpbXBsZSAkdCQtdGVzdCwgZG8gbm90IHVzZSB0aGUgbG9nIG1ldGhvZCBvbiB0aGUgd2hvbGUgbW9kZWwgYnV0IGluc3RlYWQgdXNlIHRoZSBsb2cgbWV0aG9kIG9uIHNwZWNpZmljIGNvbnRyYXN0cy4gVGhpcyAicGFpcndpc2UiIGxvZyBtZXRob2QgaGFzIHByZXR0eSBnb29kIHJlc3VsdHMgYW5kIHRoZSBDSXMgYXJlIHByZXR0eSBlYXN5IHRvIGNvbXB1dGUsIGFsdGhvdWdoIEkgZXhwbG9yZWQgdGhpcyB3aXRoIG9ubHkgYSBzaW5nbGUgcGFyYW1ldGVyaXphdGlvbiBvZiBvbmx5IGEgZmV3LCBzaW1wbGUgbGluZWFyIG1vZGVscy4KClRoZSBEZWx0YSBtZXRob2QgaXMgc29tZXdoYXQgbW9yZSBzYXRpc2Z5aW5nIHRoYW4gdGhlIHBhaXJ3aXNlIGxvZyBtZXRob2Qgc2luY2UgaXQgdXNlcyB0aGUgd2hvbGUgbW9kZWwuIEFuZCBpdCBhbHNvIGhhcyBwcmV0dHkgZ29vZCByZXN1bHRzLCB3aXRoIHRoZSBjYXZlYXQgdGhhdCBJIGV4cGxvcmVkIHRoaXMgd2l0aCBvbmx5IGEgc2luZ2xlIHBhcmFtZXRlcml6YXRpb24gb2Ygb25seSBhIGZldywgc2ltcGxlIGxpbmVhciBtb2RlbHMuCgpXaGlsZSByZWxhdGl2ZSBlZmZlY3RzIGdpdmUgdXMgc29tZSBzaW5jZSBvZiB0aGUgYmlnbmVzcyBvZiBhbiBlZmZlY3QsIGEgZ2VuZXJhbCBwcm9ibGVtIHdpdGggcmVwb3J0aW5nIHJlc3VsdHMgYXMgcmVsYXRpdmUgZWZmZWN0cyBpcyB0aGF0IGl0IGRpc2NvdXJhZ2VzIHVzIGZyb20gZG9pbmcgdGhlIGhhcmQgd29yayBvZiB3b3JraW5nIG91dCB0aGUgYmlvbG9naWNhbCAoaW5jbHVkaW5nIHBoeXNpb2xvZ2ljYWwsIGVjb2xvZ2ljYWwsIGV2b2x1dGlvbmFyeSkgY29uc2VxdWVuY2VzIG9mIGFic29sdXRlIGVmZmVjdHMuIENvbnNpZGVyIHRoaXMgd2hlbiBwcmVzZW50aW5nIHJlc3VsdHMgYXMgcmVsYXRpdmUgZWZmZWN0cy4=