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
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)
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)
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.
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))
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.
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))
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!
LS0tCnRpdGxlOiAiUmVwb3J0aW5nIGVmZmVjdHMgYXMgcmVsYXRpdmUgZGlmZmVyZW5jZXMuLi53aXRoIGEgY29uZmlkZW5jZSBpbnRlcnZhbCIKYXV0aG9yOiAiSmVmZnJleSBBLiBXYWxrZXIiCmRhdGU6ICIxMS8xNC8yMDE4IgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdGhlbWU6IHVuaXRlZAogICAgdG9jOiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKLS0tCgpbR28gYmFjayB0byBSIGRvb2RsZXNdKGh0dHBzOi8vcmRvb2RsZXMucmJpbmQuaW8pCgpbTXkgcGVyc29uYWwgd2ViIHBhZ2VdKGh0dHBzOi8vd3d3Lm1pZGRsZXByb2Zlc3Nvci5jb20pCgpbTXkgb2ZmaWNpYWwgVVNNIHdlYiBwYWdlXShodHRwczovL3VzbS5tYWluZS5lZHUvYmlvL2plZmZyZXktd2Fsa2VyKQoKYGBge3Igc2V0dXAsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGNvbW1lbnQ9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShlbW1lYW5zKQpsaWJyYXJ5KGRhdGEudGFibGUpCmxpYnJhcnkobXNtKSAjZGVsdGFtZXRob2QKbGlicmFyeShoYXJyZWxscGxvdCkKbGlicmFyeShjb3dwbG90KQpkYXRhX3BhdGggPC0gIi4uL2RhdGEiCmBgYAoKYGBge3IgZmx5cGxvdCwgZWNobz1GQUxTRX0KIyBwYXRoIDwtICdtYW51c2NyaXB0L2RhdGEvJyAjIGZvciBjb25zb2xlCmZpbGVuYW1lIDwtICdmbHlfYnVyc3QudHh0JwpmaWxlX3BhdGggPC0gcGFzdGUoZGF0YV9wYXRoLCBmaWxlbmFtZSwgc2VwPScvJykgIyBmb3Iga25pdApmbHkgPC0gZnJlYWQoZmlsZV9wYXRoLCBzdHJpbmdzQXNGYWN0b3JzID0gVFJVRSkKZmx5WywgVHJlYXRtZW50Oj1mYWN0b3IoVHJlYXRtZW50LCBjKCdDTicsICdBQScpKV0KCmZpdCA8LSBsbShWYnVyc3QgfiBUcmVhdG1lbnQqU2V4LCBkYXRhPWZseSkKZml0LmVtbSA8LSBlbW1lYW5zKGZpdCwgc3BlY3M9YygiVHJlYXRtZW50IiwgIlNleCIpKQpmaXQuZWZmIDwtIHN1bW1hcnkoY29udHJhc3QoZml0LmVtbSwgYWRqdXN0PSJub25lIiwgbWV0aG9kPSJyZXZwYWlyd2lzZSIpLCAgaW5mZXI9YyhUUlVFLCBUUlVFKSkKCmhwMSA8LSBoYXJyZWxscGxvdCh4PSdUcmVhdG1lbnQnLCB5PSdWYnVyc3QnLCBnPSdTZXgnLCBkYXRhPWZseSwgYWRkX2ludGVyYWN0aW9uID0gVFJVRSwgaW50ZXJhY3Rpb24uZ3JvdXAgPSBUUlVFLCBjb250cmFzdHMubWV0aG9kID0gJ3JldnBhaXJ3aXNlJywgeV9sYWJlbCA9ICgnQnVyc3QgU3BlZWQgKGNtL3MpJykpCmhwMiA8LSBoYXJyZWxscGxvdCh4PSdUcmVhdG1lbnQnLCB5PSdWYnVyc3QnLCBnPSdTZXgnLCBkYXRhPWZseSwgYWRkX2ludGVyYWN0aW9uID0gVFJVRSwgaW50ZXJhY3Rpb24uZ3JvdXAgPSBUUlVFLCBjb250cmFzdHMubWV0aG9kID0gJ3JldnBhaXJ3aXNlJywgIGNvbnRyYXN0cy5zY2FsaW5nID0gInBlcmNlbnQiLCB5X2xhYmVsID0gKCdCdXJzdCBTcGVlZCAoY20vcyknKSkKYGBgCgojIFJlc2VhcmNoZXJzIGZyZXF1ZW50bHkgcmVwb3J0IHJlc3VsdHMgYXMgcmVsYXRpdmUgZWZmZWN0cwoKRm9yIGV4YW1wbGUsCgoiTWFsZSBmbGllcyBmcm9tIHNlbGVjdGVkIGxpbmVzIGhhZCA1MCUgbGFyZ2VyIHVwd2luZCBmbGlnaHQgYWJpbGl0eSB0aGFuIG1hbGUgZmxpZXMgZnJvbSBjb250cm9sIGxpbmVzIChDb250cm9sIG1lYW46IDExNy41IGNtL3M7IFNlbGVjdGVkIG1lYW4gMTc2LjUgY20vcykuIgoKd2hlcmUgYSByZWxhdGl2ZSBlZmZlY3QgaXMKClxiZWdpbntlcXVhdGlvbn0KMTAwIFxmcmFje1xiYXJ7eX1fQiAtIFxiYXJ7eX1fQX17XGJhcnt5fV9BfQpcZW5ke2VxdWF0aW9ufQoKSWYgd2UgYXJlIHRvIGZvbGxvdyBiZXN0IHByYWN0aWNlcywgd2Ugc2hvdWxkIHByZXNlbnQgdGhpcyBlZmZlY3Qgd2l0aCBhIG1lYXN1cmUgb2YgdW5jZXJ0YWludHksIHN1Y2ggYXMgYSBjb25maWRlbmNlIGludGVydmFsLiBUaGUgYWJzb2x1dGUgZWZmZWN0IGlzIDU5LjAgY20vcyBhbmQgdGhlIDk1JSBDSSBvZiB0aGlzIGVmZmVjdCBpcyAoNDguNywgNjkuMyBjbS9zKS4gQnV0IGlmIHdlIHByZXNlbnQgdGhlIHJlc3VsdCBhcyBhIHJlbGF0aXZlIGVmZmVjdCwgb3IgcGVyY2VudCBkaWZmZXJlbmNlIGZyb20gc29tZSByZWZlcmVuY2UgdmFsdWUsIGhvdyBkbyB3ZSBjb21wdXRlIGEgInJlbGF0aXZlIENJIj8KCiMgRm91ciBtZXRob2RzIHRvIGNvbXB1dGUgdGhlIHN0YW5kYXJkIGVycm9yIGFuZCBDSSBvZiBhIHJlbGF0aXZlIGVmZmVjdAojIyBOYWl2ZSByZWxhdGl2ZSBjb25maWRlbmNlIGludGVydmFscwoKXGJlZ2lue2VxdWF0aW9ufQpyZWxhdGl2ZVxfQ0kgPSAxMDBcZnJhY3thYnNvbHV0ZVxfQ0l9e1xiYXJ7eX1fQX0KXGVuZHtlcXVhdGlvbn0KCkZvciB0aGUgZmx5IGV4YW1wbGUsIHRoZSA5NSUgbmFpdmUgcmVsYXRpdmUgQ0kgaXMgYm91bmRlZCBieSAkMTAwXGZyYWN7NDguN317MTE3LjV9ID0gNDEuNFwlJCBhbmQgJDEwMFxmcmFjezY5LjN9ezExNy41fSA9IDU5LjBcJSQuIFRoZXNlIGFyZSBlYXN5IHRvIGNvbXB1dGUgYnV0IHdyb25nIGJlY2F1c2UgdGhlIGVycm9yIGluIGVzdGltYXRpbmcgYSByZWxhdGl2ZSBkaWZmZXJlbmNlIGlzIGEgZnVuY3Rpb24gb2YgdGhlIGVycm9yIGluIGVzdGltYXRpbmcgYm90aCB0aGUgbnVtZXJhdG9yICh0aGUgYWJzb2x1dGUgZGlmZmVyZW5jZSkgYW5kIHRoZSBkZW5vbWluYXRvciAodGhlIHJlZmVyZW5jZSBtZWFuKS4gVGhlIGNvbnNlcXVlbmNlIGlzIHRoYXQgbmFpdmUgcmVsYXRpdmUgY29uZmlkZW5jZSBpbnRlcnZhbHMgYXJlIHRvbyBuYXJyb3cgKG9yIHRvbyBvcHRpbWlzdGljLCBvciBzdWdnZXN0IHRvbyBtdWNoIHByZWNpc2lvbikuCgojIyBCYWNrLXRyYW5zZm9ybWVkIGludGVydmFscyBmcm9tIGxvZy10cmFuc2Zvcm1lZCBkYXRhLgoKVGhpcyBwb3N0IGlzIG1vdGl2YXRlZCBieSB0aGUgcG9zdCBbVGhlIHBlcmNlbnQgZGlmZmVyZW5jZSBmYWxsYWN5IGFuZCBhIHNvbHV0aW9uOiB0aGUgcmF0aW8gdC10ZXN0XShodHRwOi8vc2NpZW5jZWJsb2cuZGFycm91emV0LW5hcmRpLm5ldC8/cD0yMDY2KSBmcm9tIEFudGhvbnkgRGFycm91emV0LU5hcmRpIGF0IFtBbnRob255J3MgU2NpZW5jZSBibG9nXShodHRwOi8vc2NpZW5jZWJsb2cuZGFycm91emV0LW5hcmRpLm5ldCkuIEFudGhvbnkgc3VnZ2VzdHMgYSBjbGV2ZXIgc29sdXRpb24gZm9yIGEgc2ltcGxlLCBsaW5lYXIgbW9kZWwgd2l0aCBhIHNpbmdsZSBmYWN0b3Igd2l0aCB0d28gbGV2ZWxzIChvciBhICJ0LXRlc3QiIGRlc2lnbik6IHRoZSByZWxhdGl2ZSBDSXMgYXJlIHRoZSBiYWNrdHJhbnNmb3JtZWQgQ0lzIG9mIHRoZSBlZmZlY3Qgb2YgdGhlIGxvZy10cmFuc2Zvcm1lZCBkYXRhLgoKMS4gbG9nIHRyYW5zZm9ybSB0aGUgcmVzcG9uc2UgdmFyaWFibGUKMi4gcnVuIHRoZSBsaW5lYXIgbW9kZWwgJGxvZyh5KSA9IGJfMCArIGJfMSBUcmVhdG1lbnQkCjMuIGNvbXB1dGUgdGhlIENJIG9mICRiXzEkCjQuIGJhY2t0cmFuc2Zvcm0gdXNpbmcgJDEwMChcbWF0aHJte2V4cH0oQ0kpIC0gMSkkCgpMZXQncyB0aGluayBhYm91dCB0aGlzLgoKMS4gVGhlIGNvZWZmaWNpZW50ICRiXzEkIG9mIHRoZSBsaW5lYXIgbW9kZWwgb2YgbG9nIHRyYW5zZm9ybWVkICR5JCBpcyAkXG92ZXJsaW5le1xtYXRocm17bG9nfSh5X0IpfSAtIFxvdmVybGluZXtcbWF0aHJte2xvZ30oeV9BKX0kCjIuIFRoaXMgaXMgdGhlIGRpZmZlcmVuY2UgaW4gdGhlIGxvZ3Mgb2YgdGhlIGdlb21ldHJpYyBtZWFucyBvZiBncm91cCBCIGFuZCBncm91cCBBLCB3aGVyZSBhIGdlb21ldHJpYyBtZWFuIGlzCjMuICRHTT0oXFBpIHkpXlxmcmFjezF9e259JCBhbmQgdGhlIGxvZyBvZiBhIGdlb21ldHJpYyBtZWFuIGlzCjQuICRcbWF0aHJte2xvZ30oR00pID0gXG1hdGhybXtsb2d9KChcUGkgeSleXGZyYWN7MX17bn0pID0gXGZyYWN7MX17bn1cc3Vte1xtYXRocm17bG9nfSh5KX0kIChub3RlIHRoYXQgdGhlIHR5cGljYWwgd2F5IHRvIGNvbXB1dGUgYSBnZW9tZXRyaWMgbWVhbiBpcyB1c2luZyBhIGxvZyB0cmFuc2Zvcm1hdGlvbiBzaW5jZSB0aGlzIGlzIHVubGlrZWx5IHRvIGJsb3cgdXAgdG8gcmVhbGx5IGJpZyB2YWx1ZXMpCjUuIEFuZCBiZWNhdXNlIHRoZSBkaWZmZXJlbmNlIG9mIHR3byBsb2dzIGlzIHRoZSBsb2cgb2YgdGhlaXIgcmF0aW8sICRiXzEgPSBcb3ZlcmxpbmV7XG1hdGhybXtsb2d9KHlfQil9IC0gXG92ZXJsaW5le1xtYXRocm17bG9nfSh5X0EpfSA9IFxtYXRocm17bG9nfShcZnJhY3tHTV9CfXtHTV9BfSkkLCBhbmQKNi4gJFxtYXRocm17ZXhwfShiXzEpID0gXGZyYWN7R01fQn17R01fQX0kCjcuIEJhY2t0cmFuc2Zvcm1pbmcgJGJfMSQgZ2l2ZXMgdXMgdGhlIG11bHRpcGxpZXIuIFRvIGdldCB0aGUgcGVyY2VudCBkaWZmZXJlbmNlIGFzIGEgZnJhY3Rpb24sIHdlIG5lZWQgdG8gc3VidHJhY3QgMSwgdGhlcmVmb3JlCjguICRcbWF0aHJte2V4cH0oYl8xKSAtIDEgPSBcZnJhY3tHTV9CfXtHTV9BfSAtIDEkLCB3aGljaCBpcyBlcXVhbCB0bwo5LiAkXG1hdGhybXtleHB9KGJfMSkgLSAxID0gXGZyYWN7R01fQn17R01fQX0gLSBcZnJhY3tHTV9BfXtHTV9BfSQsIHdoaWNoIGlzIGVxdWFsIHRvCjEwLiAkXG1hdGhybXtleHB9KGJfMSkgLSAxID0gXGZyYWN7R01fQiAtIEdNX0F9e0dNX0F9JCwgc28sIHRoZSByZWxhdGl2ZSBkaWZmZXJlbmNlIG9mIGxvZy10cmFuc2Zvcm1lZCAkeSQgYmFja3RyYW5zZm9ybWVkIGFuZCBjb252ZXJ0ZWQgdG8gYSBwZXJjZW50IGlzCgpcYmVnaW57ZXF1YXRpb259CjEwMChcbWF0aHJte2V4cH0oYl8xKSAtIDEpID0gMTAwKFxmcmFje0dNX0IgLSBHTV9BfXtHTV9BfSkKXGVuZHtlcXVhdGlvbn0KCkluIG90aGVyIHdvcmRzLCB0aGUgQ0kgdXNpbmcgdGhlIGJhY2t0cmFuc2Zvcm1lZCBDSSBvZiB0aGUgbG9nLXRyYW5zZm9ybWVkICR5JCBpcyBvZiB0aGUgcmVsYXRpdmUgZGlmZmVyZW5jZSBvZiB0aGUgKipnZW9tZXRyaWMgbWVhbnMqKiwgbm90IHRoZSBhcml0aG1ldGljIG1lYW5zLiBUbyB0aGluayBhYm91dCB0aGlzIGVzdGltYXRlIG9mIHRoZSBDSSBvZiB0aGUgcmVsYXRpdmUgZWZmZWN0LCBpdCBoZWxwcyB0byByZW1lbWJlciB0aGF0IHRoZSBnZW9tZXRyaWMgbWVhbiBpcyBhbHdheXMgc21hbGxlciAoY2xvc2VyIHRvIHplcm8pIHRoYW4gdGhlIGFyaXRobWV0aWMgbWVhbiwgc28gdGhlIG51bWVyYXRvciBpcyBhIGRpZmZlcmVuY2Ugb2Ygc2xpZ2h0bHkgc21hbGxlciB2YWx1ZXMsIGFuZCB0aGUgZGVub21pbmF0b3IgaXMgYSBzbGlndGx5IHNtYWxsZXIgdmFsdWVzLiBJJ2xsIHJldHVybiB0byB0aGlzLiBBIHBvdGVudGlhbCBwcm9ibGVtIHdpdGggdGhpcyBtZXRob2QgaXMsIGhvdyB0byBnZW5lcmFsaXplIGl0IGZvciBtb3JlIGNvbXBsZXggbW9kZWxzLCBzdWNoIGFzIHNpbmdsZSBmYWN0b3IgbW9kZWxzIHdpdGggbW9yZSB0aGFuIHR3byBsZXZlbHMsIG9yIGZhY3RvcmlhbCBtb2RlbHMsIG9yIG1vZGVscyB3aXRoIGNvbnRpbnVvdXMgY292YXJpYXRlcy4KCiMjIFRoZSBEZWx0YSBtZXRob2QKClRoZSByZWxhdGl2ZSBlZmZlY3QgJDEwMFxmcmFje1xiYXJ7eX1fQiAtIFxiYXJ7eX1fQX17XGJhcnt5fV9BfSQgaXMgYSBub24tbGluZWFyIHRyYW5zZm9ybWF0aW9uIG9mIHRoZSBhYnNvbHV0ZSBlZmZlY3QuIFRoZSBzdGFuZGFyZCBlcnJvciBvZiBhIG5vbi1saW5lYXIgdHJhbnNmb3JtYXRpb24gJEcoWCkkIG9mIHJhbmRvbSB2YXJpYWJsZSBjYW4gYmUgYXBwcm94aW1hdGVkIHVzaW5nIGEgVGF5bG9yIHNlcmllcyBhcHByb3hpbWF0aW9uLCB1c2luZwoKXGJlZ2lue2VxdWF0aW9ufQpcbWF0aHJte1ZBUn0oRyhYKSkgXGFwcHJveCBcbmFibGEgRyhYKV5cdG9wIFxtYXRocm17Q09WfShYKSBcbmFibGEgRyhYKQpcZW5ke2VxdWF0aW9ufQoKd2hlcmUgJFxuYWJsYSBHKFgpJCBpcyB0aGUgZ3JhZGllbnQgb2YgdGhlIGZ1bmN0aW9uICRHKFgpJCwgd2hpY2ggaXMgYSB2ZWN0b3Igb2YgcGFydGlhbCBkZXJpdmF0aXZlcyAtLSB0aGluayBvZiB0aGlzIGFzIHRoZSB2ZWN0b3Igc3BlY2lmeWluZyB0aGUgZGlyZWN0aW9uIG9mIHRoZSBzdGVlcGVzdCBhc2NlbnQgYXQgc29tZSBwb2ludCBvbiB0aGUgc3VyZmFjZSBvZiAkRyhYKSQuCgpUaGUgRGVsdGEgbWV0aG9kIGlzIGVhc2lseSBhcHBsaWVkIHRvIGFueSBsaW5lYXIgbW9kZWwsIGluY2x1ZGluZyBhIGhpZXJhcmNoaWNhbCBtb2RlbHMgYW5kIGdlbmVyYWxpemVkIGxpbmVhciBtb2RlbHMuIEFuZCBpdCBpcyBldmVuIGVhc2llciBpbiBSIHRoYW5rcyB0byB0aGUgYGRlbHRhbWV0aG9kYCBmdW5jdGlvbiBmcm9tIHRoZSBtc20gcGFja2FnZS4KCiMjIEJvb3RzdHJhcCBzdGFuZGFyZCBlcnJvcnMgYW5kIENJCgpUaGUgYm9vdHN0cmFwIHN0YW5kYXJkIGVycm9yIG9mIGEgcmVsYXRpdmUgZWZmZWN0IGlzIHNpbXBseSB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIHRoZSB2ZWN0b3Igb2YgJGskIHJlbGF0aXZlIGVmZmVjdHMsIHdpdGggZWFjaCByZWxhdGl2ZSBlZmZlY3QgY29tcHV0ZWQgZnJvbSBhIHJhbmRvbSByZS1zYW1wbGUsIHdpdGggcmVwbGFjZW1lbnQsIG9mIHRoZSBvcmlnaW5hbCBkYXRhLiBUaGVyZSBhcmUgc2V2ZXJhbCBtZXRob2RzIGZvciBjb21wdXRpbmcgYSBib290c3RyYXAgQ0ksIHRoZSBzaW1wbGVzdCBpcyB0byBzaW1wbHkgdXNlIHBlcmNlbnRpbGVzIChlLmcuIDAuMDI1IGFuZCAwLjk3NSkgb2YgdGhlIHZlY3RvciBvZiByZS1zYW1wbGVkIHJlbGF0aXZlIGVmZmVjdHMuCgojIENvbXBhcmluZyBDSXMgY29tcHV0ZWQgdXNpbmcgdGhlIG5haXZlLCBsb2csIGFuZCBEZWx0YSBtZXRob2RzCgpJIHVzZSBhIHNpbXBsZSBNb250ZS1DYXJsbyBzaW11bGF0aW9uIHRvIGNvbXB1dGUgdGhlIGZyZXF1ZW5jeSBvZiBDSXMgdGhhdCBjb250YWluIHRoZSB0cnVlIHJlbGF0aXZlIGVmZmVjdC4gU29ycnksIG5vIGNvbXBhcmlzb24gd2l0aCBhIGJvb3RzdHJhcCBiZWNhdXNlIHRoaXMgaXMgYSBxdWljayByZXBvcnQhIFRoZSBzaW11bGF0ZWQgZGF0YSB1c2UgcGFyYW1ldGVycyBlc3RpbWF0ZWQgZnJvbSBhIGZ1bGwtZmFjdG9yaWFsIGFuYWx5c2lzIG9mIHRoZSBlZmZlY3Qgb2YgYSBzZWxlY3Rpb24gdHJlYXRtZW50IChsZXZlbHMgIkNOIiBhbmQgIkFBIikgYW5kIHNleCAobGV2ZWxzICJGIiBhbmQgIk0iKSBvbiB1cHdpbmQgZmxpZ2h0IGFiaWxpdHkgaW4gKkRyb3NvcGhpbGEgbWVsYW5vZ2FzdGVyKi4gVXB3aW5kIGZsaWdodCBhYmlsaXR5IHdhcyBtZWFzdXJlZCBhcyB0aGUgaGlnaGVzdCB3aW5kIHR1bm5lbCBzcGVlZCBhdCB3aGljaCB0aGUgZmx5IGNvdWxkIGZseS4gRm9yIG1vcmUgYWJvdXQgdGhlIHNlbGVjdGlvbiBleHBlcmltZW50LCBzZWUgV2ViZXIsIEsuRS4gKDE5OTYpLiBMYXJnZSBnZW5ldGljIGNoYW5nZSBhdCBzbWFsbCBmaXRuZXNzIGNvc3QgaW4gbGFyZ2UgcG9wdWxhdGlvbnMgb2YgRHJvc29waGlsYSBtZWxhbm9nYXN0ZXIgc2VsZWN0ZWQgZm9yIHdpbmQgdHVubmVsIGZsaWdodDogcmV0aGlua2luZyBmaXRuZXNzIHN1cmZhY2VzLiBHZW5ldGljcyAxNDQsIDIwNeKAkzIxMy4KCmBgYHtyIGZseS1oYXJyZWwtcGxvdCwgZWNobz1GQUxTRX0KcGxvdF9ncmlkKGhwMSRnZywgaHAyJGdnLCBuY29sPTIsIGxhYmVscz0iQVVUTyIpCmBgYAoKVGhlIEhhcnJlbGwgcGxvdHMgYWJvdmUgc2hvdyB0aGUgKEEpIGFic29sdXRlIGFuZCAoQikgcmVsYXRpdmUgZWZmZWN0cyAodXBwZXIgcGFydCkgYW5kIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHJhdyBkYXRhIChib3R0b20gcGFydCkgZm9yIHRoZSBmbHkgZGF0YS4gTW9yZSBhYm91dCBIYXJyZWxsIHBsb3RzIGlzIGF0IGh0dHBzOi8vd3d3LmJpb3J4aXYub3JnL2NvbnRlbnQvZWFybHkvMjAxOC8xMS8xMC80NTgxODIKCiMjIFNpbmdsZSBmYWN0b3Igd2l0aCB0d28gbGV2ZWxzICgidC10ZXN0IikKCmBgYHtyIHR3by1sZXZlbCwgZXZhbD1UUlVFfQpzZXQuc2VlZCgxKQoKbiA8LSAyNyAjIGF2ZXJhZ2UgbiBvdmVyIHRoZSBmb3VyIGdyb3VwcyBvZiBmbGllcwpiMCA8LSAxMTcuNSAjIGNvbnRyb2wgbWFsZXMKYjEgPC0gMTc2LjUgLSBiMCAjIGVmZmVjdCBvZiBzZWxlY3Rpb24gaW4gbWFsZXMKCiMgcGFyYW1ldGVycyBnYXRoZXJlZCBpbnRvIHZlY3RvcgpiIDwtIGMoYjAsIGIxKQoKIyBlcnJvciBzdGFuZGFyZCBkZXZpYXRpb24Kc2lnbWEgPC0gMTkuMiAjIHJlc2lkdWFsIHN0YW5kYXJkIGVycm9yIG9mIGZseSBkYXRhCgojIGV4cGVjdGVkIGVmZmVjdHMgb24gcGVyY2VudCBzY2FsZQpiMS5wIDwtIGIxL2IwKjEwMAoKIyBtYWtlIG1vZGVsIG1hdHJpeApzZWxlY3Rpb25fbGV2ZWxzIDwtIGMoIkNOIiwgIkFBIikgI0FBIGlzIHNlbGVjdGVkCnggPC0gZGF0YS50YWJsZShUcmVhdG1lbnQ9ZmFjdG9yKHJlcChzZWxlY3Rpb25fbGV2ZWxzLCBlYWNoPW4pLCBzZWxlY3Rpb25fbGV2ZWxzKSkKWCA8LSBtb2RlbC5tYXRyaXgoZm9ybXVsYSh+VHJlYXRtZW50KSwgeCkKCiMgbWFrZSBkYXRhCm5pdGVyIDwtIDEwXjQKcmVzMSA8LSBtYXRyaXgoTkEsIG5yb3c9bml0ZXIsIG5jb2w9MikgIyBuYWl2ZQpjb2xuYW1lcyhyZXMxKSA8LSBjKCJjaS5sb3ciLCAiY2kuaGlnaCIpCnJlczIgPC0gbWF0cml4KE5BLCBucm93PW5pdGVyLCBuY29sPTIpICMgbG9nIHJhdGlvCmNvbG5hbWVzKHJlczIpIDwtIGMoImNpLmxvdyIsICJjaS5oaWdoIikKcmVzMyA8LSBtYXRyaXgoTkEsIG5yb3c9bml0ZXIsIG5jb2w9MikgIyBkZWx0YQpjb2xuYW1lcyhyZXMzKSA8LSBjKCJjaS5sb3ciLCAiY2kuaGlnaCIpCmZvcihpdGVyIGluIDE6bml0ZXIpewogIHkgPC0gKFglKiViICsgcm5vcm0obioyLCBzZD1zaWdtYSkpWywxXQogIGZkIDwtIGRhdGEudGFibGUoWT15LCB4KQogIGZpdDEgPC0gbG0oWX5UcmVhdG1lbnQsIGRhdGE9ZmQpCiAgYmhhdCA8LSBjb2VmKGZpdDEpCiAgCiAgIyBuYWl2ZSBtZXRob2QKICBjaSA8LSBjb25maW50KGZpdDEpWyJUcmVhdG1lbnRBQSIsIF0KICByZXMxW2l0ZXIsIF0gPC0gY2kvYmhhdFsxXSoxMDAKICAKICAjIGxvZyBtZXRob2QKICBmaXQxLmxvZyA8LSBsbShsb2coWSl+VHJlYXRtZW50LCBkYXRhPWZkKQogIGNpIDwtIGV4cChjb25maW50KGZpdDEubG9nKVsiVHJlYXRtZW50QUEiLCBdKS0xCiAgcmVzMltpdGVyLCBdIDwtIGNpKjEwMAoKICAjIGRlbHRhIG1ldGhvZAogIGRmIDwtIGZpdDEkZGYucmVzaWR1YWwKICB0Y3JpdCA8LSBxdCguOTc1LCBkZikKICBzZCA8LSBzdW1tYXJ5KGZpdDEpJHNpZ21hCiAgc2UgPC0gZGVsdGFtZXRob2QofngyL3gxLCBtZWFuPWNvZWYoZml0MSksIGNvdj12Y292KGZpdDEpKQogIHJlczNbaXRlciwgImNpLmxvdyJdIDwtIDEwMCooYmhhdFsyXS9iaGF0WzFdIC0gdGNyaXQqc2UpCiAgcmVzM1tpdGVyLCAiY2kuaGlnaCJdIDwtIDEwMCooYmhhdFsyXS9iaGF0WzFdICsgdGNyaXQqc2UpCiAgCiAgIyBmdW4gbWF0aAogICMgRyhYKSA9IGIxL2IwIG9yIHkveCBvciB4Mi94MQogICMgZGVsKHkveCkgPSAoeS94XjIsIDEveCkKICAjIGRlbChiMS9iMCkgPSAoYjEvYjBeMiwgMS9iMCkKICAjIGRlbCA8LSBjKGJoYXRbMl0vYmhhdFsxXV4yLCAxL2JoYXRbMV0pCiAgIyBzZS5mdW4gPC0gc3FydCh0KGRlbCklKiV2Y292KGZpdDEpJSolZGVsKQp9CgpuYWl2ZSA8LSBsZW5ndGgod2hpY2gocmVzMVssImNpLmxvdyJdIDwgYjEucCAmIHJlczFbLCJjaS5oaWdoIl0gPiBiMS5wKSkvbml0ZXIqMTAwCmxvZ3JhdGlvIDwtIGxlbmd0aCh3aGljaChyZXMyWywiY2kubG93Il0gPCBiMS5wICYgcmVzMlssImNpLmhpZ2giXSA+IGIxLnApKS9uaXRlcioxMDAKZGVsdGEgPC0gbGVuZ3RoKHdoaWNoKHJlczNbLCJjaS5sb3ciXSA8IGIxLnAgJiByZXMzWywiY2kuaGlnaCJdID4gYjEucCkpL25pdGVyKjEwMAoKcmVzX3RhYmxlIDwtIGRhdGEudGFibGUoTWV0aG9kPWMoIm5haXZlIiwgImxvZyIsICJkZWx0YSIpLAogICAgICAgICAgICAgICAgICAgICAgICBDb3ZlcmFnZT1yb3VuZChjKG5haXZlLCBsb2dyYXRpbywgZGVsdGEpLDEpKQprbml0cjo6a2FibGUocmVzX3RhYmxlKQpgYGAKClRoZSB0YWJsZSBhYm92ZSBzaG93cyB0aGUgbG9uZyBydW4gKCQxMF40JCBydW5zKSBmcmVxdWVuY3kgb2YgQ0lzIHRoYXQgaW5jbHVkZSB0aGUgdHJ1ZSByZWxhdGl2ZSBkaWZmZXJlbmNlIGZvciBlYWNoIG9mIHRoZSB0aHJlZSBtZXRob2RzLiBUaGUgc2ltdWxhdGlvbiBjb25maXJtcyB0aGF0IGEgbmFpdmUgQ0kgaXMgdG9vIG5hcnJvdywgd2hpY2ggaXMgd2h5IGZhciBmZXdlciB0aGFuIDk1JSBvZiB0aGUgQ0lzIGNvdmVyZWQgdGhlIHRydWUgdmFsdWUuIFRoZSBuYXJyb3cgaW50ZXJ2YWwgaW1wbGllcyBhIHN0YW5kYXJkIGVycm9yIHRoYXQgaXMgdG9vIHNtYWxsLCBhbmQgYSAkdCQtdmFsdWUgdGhhdCBpcyB0b28gbGFyZ2UsIGFuZCBhICRwJC12YWx1ZSB0aGF0IGlzIHRvbyAib3B0aW1pc3RpYyIuCgpCb3RoIHRoZSBsb2cgdHJhbnNmb3JtIGFuZCBlc3BlaWNhbGx5IERlbHRhIG1ldGhvZHMgaGF2ZSBjbG9zZSB0byB0aGUgbm9taW5hbCBjb3ZlcmFnZS4gTmV2ZXJ0aGVsZXNzLCB0aGVyZSBhcmUgaW50ZXJlc3RpbmcgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgbG9nIGFuZCBEZWx0YSBtZXRob2RzLgoKYGBge3IgdHdvLWxldmVsLXBsb3R9CnAxIDwtIHFwbG90KHJlczJbLDFdLCByZXMzWywxXSkgKwogIHhsYWIoIkxvd2VyIENJIChsb2cgbWV0aG9kKSIpICsKICB5bGFiKCJMb3dlciBDSSAoRGVsdGEgbWV0aG9kKSIpICsKICBnZW9tX2FibGluZShpbnRlcmNlcHQ9MCwgc2xvcGU9MSwgY29sb3I9InJlZCIpICsKICBOVUxMCnAyIDwtIHFwbG90KHJlczJbLDJdLCByZXMzWywyXSkgKwogIHhsYWIoIlVwcGVyIENJIChsb2cgbWV0aG9kKSIpICsKICB5bGFiKCJVcHBlciBDSSAoRGVsdGEgbWV0aG9kKSIpICsKICBnZW9tX2FibGluZShpbnRlcmNlcHQ9MCwgc2xvcGU9MSwgY29sb3I9InJlZCIpICsKICBOVUxMCnBsb3RfZ3JpZChwMSwgcDIsIG5jb2w9MiwgbGFiZWxzPSJBVVRPIikKYGBgCgpUaGUgcGxvdHMgYWJvdmUgc2hvdyB0aGF0IHRoZSBDSXMgZXN0aW1hdGVkIHVzaW5nIHRoZSBsb2cgdHJhbnNmb3JtYXRpb24gaXMgInJpZ2h0IiBzaGlmdGVkIChpLmUuIHRvIGxhcmdlciB2YWx1ZXMpIGNvbXBhcmVkIHRvIHRoZSBDSXMgZXN0aW1hdGVkIHVzaW5nIHRoZSBEZWx0YSBtZXRob2QuIFRoaXMgcmlnaHQgc2hpZnQgaXMgYmVjYXVzZSB0aGUgbWVhbiBpbiB0aGUgZGVub21pbmF0b3Igb2YgdGhlIHJlbGF0aXZlIGVmZmVjdCBpcyBhIGdlb21ldHJpYyBtZWFuIHVzaW5nIHRoZSBsb2cgbWV0aG9kLCBidXQgYW4gYXJpdGhlbWV0aWMgbWVhbiB1c2luZyB0aGUgRGVsdGEgbWV0aG9kLiBCZWNhdXNlIGEgZ2VvbWV0cmljIG1lYW4gaXMgYWx3YXlzIHNtYWxsZXIgdGhhbiB0aGUgYXJpdGhtZXRpYyBtZWFuLCB0aGUgcmVsYXRpdmUgZWZmZWN0IHVzaW5nIHRoZSBsb2cgbWV0aG9kIHdpbGwgYmUgYmlnZ2VyIHRoYW4gdGhlIHJlbGF0aXZlIGVmZmVjdCBjb21wdXRlZCB1c2luZyB0aGUgRGVsdGEgbWV0aG9kLiBNb3JlIGN1cmlvdXNseSwgaG93IGNhbiBib3RoIG1ldGhvZHMgaGF2ZSBzZWVtaW5nbHkgZ29vZCBjb3ZlcmFnZSBpZiB0aGUgQ0kgY29tcHV0ZWQgdXNpbmcgdGhlIGxvZyBtZXRob2QgaXMgcmlnaHQtc2hpZnRlZCByZWxhdGl2ZSB0byB0aGUgQ0kgY29tcHV0ZWQgdXNpbmcgdGhlIERlbHRhIG1ldGhvZD8KCmBgYHtyIHR3by1sZXZlbC1zaGlmdH0KbG9ncmF0aW8ubG8gPC0gbGVuZ3RoKHdoaWNoKHJlczJbLCJjaS5sb3ciXSA+IGIxLnApKS9uaXRlcioxMDAKZGVsdGEubG8gPC0gbGVuZ3RoKHdoaWNoKHJlczNbLCJjaS5sb3ciXSA+IGIxLnApKS9uaXRlcioxMDAKbG9ncmF0aW8uaGkgPC0gbGVuZ3RoKHdoaWNoKHJlczJbLCJjaS5oaWdoIl0gPCBiMS5wKSkvbml0ZXIqMTAwCmRlbHRhLmhpIDwtIGxlbmd0aCh3aGljaChyZXMzWywiY2kuaGlnaCJdIDwgYjEucCkpL25pdGVyKjEwMAoKcmVzX3RhYmxlIDwtIGRhdGEudGFibGUoTWV0aG9kPWMoImxvZyIsICJkZWx0YSIpLAogICAgICAgICAgICAgICAgICAgICAgICBMb3dlcj1yb3VuZChjKGxvZ3JhdGlvLmxvLCBkZWx0YS5sbyksMSksCiAgICAgICAgICAgICAgICAgICAgICAgIFVwcGVyPXJvdW5kKGMobG9ncmF0aW8uaGksIGRlbHRhLmhpKSwxKQogICAgICAgICAgICAgICAgICAgICAgICApCmtuaXRyOjprYWJsZShyZXNfdGFibGUpCmBgYAoKVGhlIHRhYmxlIGFib3ZlIGdpdmVzIHRoZSBsb25nIHJ1biBmcmVxdWVuY3kgb2YgdHJ1ZSByZWxhdGl2ZSBlZmZlY3RzIHRoYXQgYXJlIGxlc3MgdGhhbiB0aGUgbG93ZXIgQ0kgb3IgZ3JlYXRlciB0aGFuIHRoZSB1cHBlciBDSSBmb3IgdGhlIGxvZyBhbmQgRGVsdGEgbWV0aG9kcy4gVGhlIGxvZyBtZXRob2Qgc2hvd3MgYSBoaWdoZXIgdGhhbiBleHBlY3RlZCBmcmVxdWVuY3kgYXQgdGhlIGxvd2VyIENJIGFuZCBsb3dlciB0aGFuIGV4cGVjdGVkIGZyZXF1ZW5jeSBhdCB0aGUgdXBwZXIgQ0ksIGluZGljYXRlZCB0aGF0IHRoZSBDSXMgY29tcHV0ZWQgdXNpbmcgdGhlIGxvZyB0cmFuc2Zvcm1hdGlvbiBhcmUgc2xpZ2h0bHkgcmlnaHQtc2hpZnRlZC4gVGhlIERlbHRhIG1ldGhvZCBzaG93cyB0aGUgb3Bwb3NpdGUgcGF0dGVybiwgaW5kaWNhdGluZyB0aGF0IHRoZSBDSXMgY29tcHV0ZWQgdXNpbmcgdGhlIERlbHRhIG1ldGhvZCBhcmUgc2xpZ2h0bHkgbGVmdC1zaGlmdGVkLiBJIGFzc3VtZSB0aGVzZSBzaGlmdHMgYXJlIHJlYWwgKGFsdGhvdWdoIHRoZXkgbWF5IGJlIGNvbmRpdGlvbmFsIG9uIHRoZSBwYXJhbWV0ZXJpemF0aW9uKSBhbmQgbm90IGp1c3Qgc2FtcGxlIGFydGlmYWN0cy4gUmVnYXJkbGVzcywgZGVzcGl0ZSB0aGVzZSBzaGlmdHMsIHRoZSBjb3ZlcmFnZSBvdmVyIHRoZSByYW5nZSBpcyBjbG9zZSB0byAob3IgZXF1YWwgdG8gZm9yIHRoZSBEZWx0YSBtZXRob2QpIHRoZSBleHBlY3RlZCBjb3ZlcmFnZS4KCiMjIFNpbmdsZSBmYWN0b3Igd2l0aCBmb3VyIGxldmVscyAoInBvc3QtaG9jIikKClRoZSBEZWx0YSBtZXRob2QgaXMgZWFzaWx5IGFwcGxpZWQgdG8gbW9yZSBjb21wbGV4IGRlc2lnbnMgYnV0IGl0cyBub3QgY2xlYXIgaG93IHRvIGltcGxlbWVudCB0aGUgbG9nIG1ldGhvZCBpbiBtb3JlIGNvbXBsZXggZGVzaWducy4gRm9yIGV4YW1wbGUsIGlmIHRoZXJlIGFyZSBmb3VyIGxldmVscyBpbiBhIGZhY3RvciBhbmQgd2Ugd2FudCB0aGUgY29udHJhc3QgYW5kIENJcyBmb3IgYWxsIHNpeCBwYWlyd2lzZSBlZmZlY3RzLCBkbyB3ZSBqdXN0IGxvZyB0cmFuc2Zvcm0gdGhlIHJlc3BvbnNlIGFuZCBiYWNrdHJhbnNmb3JtIHRoZSBDSXMgb2YgdGhlIGNvbnRyYXN0cyAodGhlICJ3aG9sZSBtb2RlbCIgbG9nIG1ldGhvZCkgb3IgZG8gd2UgZG8gdGhlIGxvZyBtZXRob2Qgb24gYWxsIHNpeCBjb250cmFzdHMgaW5kZXBlbmRlbnRseSAodGhlICJwYWlyd2lzZSIgbG9nIG1ldGhvZCk/CgpIZXJlLCBJIGV2YWx1YXRlIHRoZSB0d28gbG9nIG1ldGhvZHMsIGFzIHdlbGwgYXMgdGhlIG5haXZlIGFuZCBEZWx0YSBtZXRob2RzLCBieSBjb21wYXJpbmcgdGhlIHJlbGF0aXZlIGRpZmZlcmVuY2Ugb2YgdGhyZWUgbm9uLXJlZmVyZW5jZSBsZXZlbHMgb2YgdGhlIGZseSBkYXRhIChzZWxlY3RlZCBmZW1hbGVzLCBjb250cm9sIG1hbGVzLCBzZWxlY3RlZCBtYWxlcykgZnJvbSB0aGUgcmVmZXJlbmNlIGxldmVsIChjb250cm9sIGZlbWFsZXMgb3IgIkNOLUYiKS4KCmBgYHtyIGZvdXItbGV2ZWxzLCBldmFsPVRSVUV9CiMgdXNlIHRoZSBmb3VyIGZseSBsZXZlbHMgYnV0IHByZXRlbmQgaXQgaXMgbm90IGZhY3RvcmlhbApzZXQuc2VlZCgxKQpuIDwtIDI3ICMgYXZlcmFnZSBuIG92ZXIgdGhlIGZvdXIgZ3JvdXBzIG9mIGZsaWVzCiMgbWVhbnMKbXUgPC0gYygxMzEuNiwgMTgxLjAsIDExNy41LCAxNzYuNSkgI0NOLUYsIEFBLUYsIENOLU0sIEFBLU0KYjAgPC0gMTMxLjYgIyBjb250cm9sIGZlbWFsZXMKYjEgPC0gMTgxLjAgLSBiMCAjIGVmZmVjdCBvZiBzZWxlY3Rpb24gaW4gZmVtYWxlcwpiMiA8LSAxMTcuNSAtIGIwICMgZWZmZWN0IG9mIG1hbGUgaW4gY29udHJvbApiMyA8LSAxNzYuNSAtIGIwICMgZWZmZWN0IG9mIHNlbGVjdGlvbiBhbmQgbWFsZSAtLSBub3QgYW4gaW50ZXJhY3Rpb24gZWZmZWN0IQoKIyBwYXJhbWV0ZXJzIGdhdGhlcmVkIGludG8gdmVjdG9yCmIgPC0gYyhiMCwgYjEsIGIyLCBiMykKCiMgZXJyb3Igc3RhbmRhcmQgZGV2aWF0aW9uCnNpZ21hIDwtIDE5LjIgIyByZXNpZHVhbCBzdGFuZGFyZCBlcnJvciBvZiBmbHkgZGF0YQoKIyBleHBlY3RlZCBlZmZlY3RzIG9uIHJlc3BvbnNlIGFuZCBwZXJjZW50IHNjYWxlCiMgY2FsbCB0aGUgZXhwZWN0ZWQKYjEucCA8LSBiMS9iMCoxMDAKYjIucCA8LSBiMi9iMCoxMDAKYjMucCA8LSBiMy9iMCoxMDAKCiMgbWFrZSBtb2RlbCBtYXRyaXgKQV9sZXZlbHMgPC0gYygiQ04tRiIsICJBQS1GIiwgIkNOLU0iLCAiQUEtTSIpCnggPC0gZGF0YS50YWJsZShUcmVhdG1lbnQ9ZmFjdG9yKHJlcChBX2xldmVscywgZWFjaD1uKSwgZmFjdG9yKEFfbGV2ZWxzKSkpClggPC0gbW9kZWwubWF0cml4KGZvcm11bGEoflRyZWF0bWVudCksIHgpCm5fY2VsbHMgPC0gbGVuZ3RoKGxldmVscyh4JFRyZWF0bWVudCkpCgojIG1ha2UgZGF0YQpuaXRlciA8LSAxMF40CnJlczEubG8gPC0gbWF0cml4KE5BLCBucm93PW5pdGVyLCBuY29sPTMpICMgbmFpdmUKcmVzMS51cCA8LSBtYXRyaXgoTkEsIG5yb3c9bml0ZXIsIG5jb2w9MykgIyBuYWl2ZQpyZXMyLmxvIDwtIG1hdHJpeChOQSwgbnJvdz1uaXRlciwgbmNvbD0zKSAjIGxvZwpyZXMyLnVwIDwtIG1hdHJpeChOQSwgbnJvdz1uaXRlciwgbmNvbD0zKSAjIGxvZwpyZXMzLmxvIDwtIG1hdHJpeChOQSwgbnJvdz1uaXRlciwgbmNvbD0zKSAjIGRlbHRhCnJlczMudXAgPC0gbWF0cml4KE5BLCBucm93PW5pdGVyLCBuY29sPTMpICMgZGVsdGEKcmVzNC5sbyA8LSBtYXRyaXgoTkEsIG5yb3c9bml0ZXIsIG5jb2w9MykgIyBsb2ctcGFpcndpc2UKcmVzNC51cCA8LSBtYXRyaXgoTkEsIG5yb3c9bml0ZXIsIG5jb2w9MykgIyBsb2ctcGFpcndpc2UKZm9yKGl0ZXIgaW4gMTpuaXRlcil7CiAgeSA8LSAoWCUqJWIgKyBybm9ybShuKm5fY2VsbHMsIHNkPXNpZ21hKSlbLDFdCiAgZmQgPC0gZGF0YS50YWJsZShZPXksIHgpCiAgZml0MSA8LSBsbShZflRyZWF0bWVudCwgZGF0YT1mZCkKICBiaGF0IDwtIGNvZWYoZml0MSkKICAjIGNvbnRyYXN0KGVtbWVhbnMoZml0MSwgc3BlY3M9IlRyZWF0bWVudCIpLCBhZGp1c3Q9Im5vbmUiLCBtZXRob2Q9InJldnBhaXJ3aXNlIikKICAKICAjIG5haXZlIG1ldGhvZAogIGNpLmxvIDwtIGNvbmZpbnQoZml0MSlbMjo0LCAiMi41ICUiXQogIGNpLnVwIDwtIGNvbmZpbnQoZml0MSlbMjo0LCAiOTcuNSAlIl0KICByZXMxLmxvW2l0ZXIsIF0gPC0gY2kubG8vYmhhdFsxXSoxMDAKICByZXMxLnVwW2l0ZXIsIF0gPC0gY2kudXAvYmhhdFsxXSoxMDAKICAKICAjIGxvZyBtZXRob2QgMSAtIHJ1biBldmVyeXRoaW5nIGF0IG9uY2UKICBmaXQyIDwtIGxtKGxvZyhZKX5UcmVhdG1lbnQsIGRhdGE9ZmQpCiAgY2kubG8gPC0gZXhwKGNvbmZpbnQoZml0MilbMjo0LCAiMi41ICUiXSkgLSAxCiAgY2kudXAgPC0gZXhwKGNvbmZpbnQoZml0MilbMjo0LCAiOTcuNSAlIl0pIC0gMQogIHJlczIubG9baXRlciwgXSA8LSBjaS5sbyoxMDAKICByZXMyLnVwW2l0ZXIsIF0gPC0gY2kudXAqMTAwCiAgCiAgIyBsb2cgbWV0aG9kIDIgLS0gcGFpcndpc2UKICBmaXQyIDwtIGxtKGxvZyhZKX5UcmVhdG1lbnQsIGRhdGE9ZmRbVHJlYXRtZW50PT0iQ04tRiIgfCBUcmVhdG1lbnQ9PSJBQS1GIl0pCiAgY2kubG8gPC0gZXhwKGNvbmZpbnQoZml0MilbMiwgIjIuNSAlIl0pIC0gMQogIGNpLnVwIDwtIGV4cChjb25maW50KGZpdDIpWzIsICI5Ny41ICUiXSkgLSAxCiAgcmVzNC5sb1tpdGVyLCAxXSA8LSBjaS5sbyoxMDAKICByZXM0LnVwW2l0ZXIsIDFdIDwtIGNpLnVwKjEwMAoKICBmaXQyIDwtIGxtKGxvZyhZKX5UcmVhdG1lbnQsIGRhdGE9ZmRbVHJlYXRtZW50PT0iQ04tRiIgfCBUcmVhdG1lbnQ9PSJDTi1NIl0pCiAgY2kubG8gPC0gZXhwKGNvbmZpbnQoZml0MilbMiwgIjIuNSAlIl0pIC0gMQogIGNpLnVwIDwtIGV4cChjb25maW50KGZpdDIpWzIsICI5Ny41ICUiXSkgLSAxCiAgcmVzNC5sb1tpdGVyLCAyXSA8LSBjaS5sbyoxMDAKICByZXM0LnVwW2l0ZXIsIDJdIDwtIGNpLnVwKjEwMAoKICBmaXQyIDwtIGxtKGxvZyhZKX5UcmVhdG1lbnQsIGRhdGE9ZmRbVHJlYXRtZW50PT0iQ04tRiIgfCBUcmVhdG1lbnQ9PSJBQS1NIl0pCiAgY2kubG8gPC0gZXhwKGNvbmZpbnQoZml0MilbMiwgIjIuNSAlIl0pIC0gMQogIGNpLnVwIDwtIGV4cChjb25maW50KGZpdDIpWzIsICI5Ny41ICUiXSkgLSAxCiAgcmVzNC5sb1tpdGVyLCAzXSA8LSBjaS5sbyoxMDAKICByZXM0LnVwW2l0ZXIsIDNdIDwtIGNpLnVwKjEwMAoKICAjIGRlbHRhIG1ldGhvZAogIGRmIDwtIGZpdDEkZGYucmVzaWR1YWwKICB0Y3JpdCA8LSBxdCguOTc1LCBkZikKICBzZCA8LSBzdW1tYXJ5KGZpdDEpJHNpZ21hCiAgc2UgPC0gYygKICAgIGRlbHRhbWV0aG9kKH54Mi94MSwgbWVhbj1jb2VmKGZpdDEpLCBjb3Y9dmNvdihmaXQxKSksCiAgICBkZWx0YW1ldGhvZCh+eDMveDEsIG1lYW49Y29lZihmaXQxKSwgY292PXZjb3YoZml0MSkpLAogICAgZGVsdGFtZXRob2Qofng0L3gxLCBtZWFuPWNvZWYoZml0MSksIGNvdj12Y292KGZpdDEpKQogICkKICByZXMzLmxvW2l0ZXIsIF0gPC0gMTAwKihiaGF0WzI6NF0vYmhhdFsxXSAtIHRjcml0KnNlKQogIHJlczMudXBbaXRlciwgXSA8LSAxMDAqKGJoYXRbMjo0XS9iaGF0WzFdICsgdGNyaXQqc2UpCn0KCm5haXZlIDwtIGMobGVuZ3RoKHdoaWNoKHJlczEubG9bLDFdIDwgYjEucCAmIHJlczEudXBbLDFdID4gYjEucCkpL25pdGVyKjEwMCwKICAgICAgICAgICBsZW5ndGgod2hpY2gocmVzMS5sb1ssMl0gPCBiMi5wICYgcmVzMS51cFssMl0gPiBiMi5wKSkvbml0ZXIqMTAwLAogICAgICAgICAgIGxlbmd0aCh3aGljaChyZXMxLmxvWywzXSA8IGIzLnAgJiByZXMxLnVwWywzXSA+IGIzLnApKS9uaXRlcioxMDAKKQpsb2dyYXRpbzEgPC0gYyhsZW5ndGgod2hpY2gocmVzMi5sb1ssMV0gPCBiMS5wICYgcmVzMi51cFssMV0gPiBiMS5wKSkvbml0ZXIqMTAwLAogICAgICAgICAgICAgIGxlbmd0aCh3aGljaChyZXMyLmxvWywyXSA8IGIyLnAgJiByZXMyLnVwWywyXSA+IGIyLnApKS9uaXRlcioxMDAsCiAgICAgICAgICAgICAgbGVuZ3RoKHdoaWNoKHJlczIubG9bLDNdIDwgYjMucCAmIHJlczIudXBbLDNdID4gYjMucCkpL25pdGVyKjEwMAopCmxvZ3JhdGlvMiA8LSBjKGxlbmd0aCh3aGljaChyZXM0LmxvWywxXSA8IGIxLnAgJiByZXM0LnVwWywxXSA+IGIxLnApKS9uaXRlcioxMDAsCiAgICAgICAgICAgICAgbGVuZ3RoKHdoaWNoKHJlczQubG9bLDJdIDwgYjIucCAmIHJlczQudXBbLDJdID4gYjIucCkpL25pdGVyKjEwMCwKICAgICAgICAgICAgICBsZW5ndGgod2hpY2gocmVzNC5sb1ssM10gPCBiMy5wICYgcmVzNC51cFssM10gPiBiMy5wKSkvbml0ZXIqMTAwCikKZGVsdGEgPC0gYyhsZW5ndGgod2hpY2gocmVzMy5sb1ssMV0gPCBiMS5wICYgcmVzMy51cFssMV0gPiBiMS5wKSkvbml0ZXIqMTAwLAogICAgICAgICAgIGxlbmd0aCh3aGljaChyZXMzLmxvWywyXSA8IGIyLnAgJiByZXMzLnVwWywyXSA+IGIyLnApKS9uaXRlcioxMDAsCiAgICAgICAgICAgbGVuZ3RoKHdoaWNoKHJlczMubG9bLDNdIDwgYjMucCAmIHJlczMudXBbLDNdID4gYjMucCkpL25pdGVyKjEwMAopCnJlcy50YWJsZSA8LSBkYXRhLnRhYmxlKHJiaW5kKG5haXZlLCBsb2dyYXRpbzEsIGxvZ3JhdGlvMiwgZGVsdGEpKQpjb2xuYW1lcyhyZXMudGFibGUpIDwtIGMoIkFBRi1DTkYiLCAiQ05NLUNORiIsICJBQU0tQ05GIikKcmVzLnRhYmxlIDwtIGNiaW5kKE1ldGhvZD1jKCJuYWl2ZSIsICJsb2ciLCAibG9nLXB3IiwgIkRlbHRhIiksIHJlcy50YWJsZSkKa25pdHI6OmthYmxlKHJlcy50YWJsZSwgZGlnaXRzPWMoMCwxLDEsMSkpCmBgYAoKVGhlIHRhYmxlIGFib3ZlIHNob3dzIHRoZSBsb25nIHJ1biAoJDEwXjQkIHJ1bnMpIGZyZXF1ZW5jeSBvZiBDSXMgdGhhdCBpbmNsdWRlIHRoZSB0cnVlIHJlbGF0aXZlIGRpZmZlcmVuY2UgZm9yIGVhY2ggb2YgdGhlIHRocmVlIGNvbnRyYXN0cyAoZGlmZmVyZW5jZXMgZnJvbSBDTi1GKSBmb3IgZWFjaCBvZiB0aGUgZm91ciBtZXRob2RzLCBpbmNsdWRpbmcgYm90aCB0aGUgd2hvbGUtbW9kZWwgYW5kIHBhaXJ3aXNlIGxvZyBtZXRob2RzLiBUaGUgd2hvbGUtbW9kZWwgbG9nIG1ldGhvZCBjYW4gaGF2ZSBpbnRlcnZhbHMgdGhhdCBhcmUgdHdvIG5hcnJvdywgYXMgaW5kaWNhdGVkIGJ5IHRoZSBsb3dlci10aGFuLW5vbWluYWwgZnJlcXVlbmN5IGZvciB0aGUgQ04tRiByZWxhdGl2ZSBkaWZmZXJlbmNlLiBUaGUgZnJlcXVlbmNpZXMgb2YgdGhlIHJ1bi1wYWlyd2lzZSBsb2cgbWV0aG9kIGFuZCBEZXRhIG1ldGhvZCBsb29rIHByZXR0eSBnb29kLCBidXQgdGhpcyBpcyBvbmx5IG9uZSBwYXJhbWV0ZXJpemF0aW9uLgoKIyMgRmFjdG9yaWFsICgyIFggMikKYGBge3IgZmFjdG9yaWFsLCBldmFsPVRSVUV9CiMgdXNlIHRoZSBmb3VyIGZseSBsZXZlbHMgaW4gYSBmdWxseSBmYWN0b3JpYWwgZGVzaWduCnNldC5zZWVkKDEpCm4gPC0gMjcgIyBhdmVyYWdlIG4gb3ZlciB0aGUgZm91ciBncm91cHMgb2YgZmxpZXMKIyBtZWFucwptdSA8LSBjKDEzMS42LCAxODEuMCwgMTE3LjUsIDE3Ni41KSAjQ04tRiwgQUEtRiwgQ04tTSwgQUEtTQpiMCA8LSAxMzEuNiAjIGNvbnRyb2wgZmVtYWxlcwpiMSA8LSAxODEuMCAtIGIwICMgZWZmZWN0IG9mIHNlbGVjdGlvbiBpbiBmZW1hbGVzCmIyIDwtIDExNy41IC0gYjAgIyBlZmZlY3Qgb2YgbWFsZSBpbiBjb250cm9sCmIzIDwtIDE3Ni41IC0gKGIwICsgYjEgKyBiMikgIyBpbnRlcmFjdGlvbiBlZmZlY3QhCgojIHBhcmFtZXRlcnMgZ2F0aGVyZWQgaW50byB2ZWN0b3IKYiA8LSBjKGIwLCBiMSwgYjIsIGIzKQoKIyBlcnJvciBzdGFuZGFyZCBkZXZpYXRpb24Kc2lnbWEgPC0gMTkuMiAjIHJlc2lkdWFsIHN0YW5kYXJkIGVycm9yIG9mIGZseSBkYXRhCgojIGV4cGVjdGVkIGVmZmVjdHMgb24gcmVzcG9uc2UgYW5kIHBlcmNlbnQgc2NhbGUKIyB0aGVyZSBhcmUgMiB4IDIgPSBmb3VyIHBhaXJ3aXNlIGVmZmVjdHMgKG9mIG9uZSB0cmVhdG1lbnQgd2l0aGluIGVhY2ggbGV2ZWwgb2YgdGhlIG90aGVyIHRyZWF0bWVudCkKIyBjYWxsIHRoZXNlIEEwIGFuZCBBMSwgQjAgYW5kIEIxCiMgY2FsbCB0aGUgZXhwZWN0ZWQKQTAgPC0gYjEKQTEgPC0gKChiMCtiMStiMitiMyktKGIwK2IyKSkKQTAucCA8LSAxMDAqQTAvYjAKQTEucCA8LSAxMDAqQTEvKGIwK2IyKQoKIyBtYWtlIG1vZGVsIG1hdHJpeApBX2xldmVscyA8LSBmYWN0b3IocmVwKGMoIkNOIiwgIkFBIiksIGVhY2g9biksIGMoIkNOIiwgIkFBIikpCkJfbGV2ZWxzIDwtIGZhY3RvcihjKCJGIiwgIk0iKSkKeCA8LSBleHBhbmQuZ3JpZChUcmVhdG1lbnQ9QV9sZXZlbHMsU2V4PUJfbGV2ZWxzKQpYIDwtIG1vZGVsLm1hdHJpeChmb3JtdWxhKH5UcmVhdG1lbnQqU2V4KSwgeCkKCgpzZXQuc2VlZCgxKQpuaXRlciA8LSAxMF40Cm1ldGhvZHMgPC0gYygibmFpdmUiLCAibG9nIiwgImxvZy1wdyIsICJEZWx0YSIpCm4ubWV0aG9kcyA8LSBsZW5ndGgobWV0aG9kcykKcmVzIDwtIGRhdGEuZnJhbWUobWV0aG9kPXJlcChtZXRob2RzLCBuaXRlciksCiAgICAgICAgICAgICAgICAgIEEwLmxvPU5BLAogICAgICAgICAgICAgICAgICBBMC51cD1OQSwKICAgICAgICAgICAgICAgICAgQTEubG89TkEsCiAgICAgICAgICAgICAgICAgIEExLnVwPU5BKQpyb3cuZSA8LSAwICMgZW5kIHJvdyBmb3Igc2F2aW5nIApmb3IoaXRlciBpbiAxOm5pdGVyKXsKICAjIG1ha2UgZGF0YQogIHkgPC0gKFglKiViICsgcm5vcm0obio0LCBzZD1zaWdtYSkpWywxXQogIGZkIDwtIGRhdGEudGFibGUoWT15LCB4KQogIAogICMgZml0CiAgZml0IDwtIGxtKFl+VHJlYXRtZW50KlNleCwgZGF0YT1mZCkKICBmaXQuZW1tIDwtIGVtbWVhbnMoZml0LCBzcGVjcz1jKCJUcmVhdG1lbnQiLCAiU2V4IikpCiAgZml0LmVmZiA8LSBzdW1tYXJ5KGNvbnRyYXN0KGZpdC5lbW0sIGFkanVzdD0ibm9uZSIsIG1ldGhvZD0icmV2cGFpcndpc2UiKSwgaW5mZXI9YyhUUlVFLCBUUlVFKSkKICAKICAjIGNlbGwgbWVhbnMKICB5YmFyMTEgPC0gc3VtbWFyeShmaXQuZW1tKVsxLCAiZW1tZWFuIl0gIyBDTi1GCiAgeWJhcjIxIDwtIHN1bW1hcnkoZml0LmVtbSlbMiwgImVtbWVhbiJdICMgQUEtRgogIHliYXIxMiA8LSBzdW1tYXJ5KGZpdC5lbW0pWzMsICJlbW1lYW4iXSAjIENOLU0KICB5YmFyMjIgPC0gc3VtbWFyeShmaXQuZW1tKVs0LCAiZW1tZWFuIl0gIyBBQS1NCiAgCiAgIyBuYWl2ZSBjb252ZXJ0IENJIHRvIHBlcmNlbnQKICBuYWl2ZSA8LSAxMDAqYygKICAgIGZpdC5lZmZbMSwgImxvd2VyLkNMIl0veWJhcjExLAogICAgZml0LmVmZlsxLCAidXBwZXIuQ0wiXS95YmFyMTEsCiAgICBmaXQuZWZmWzYsICJsb3dlci5DTCJdL3liYXIxMiwKICAgIGZpdC5lZmZbNiwgInVwcGVyLkNMIl0veWJhcjEyCiAgKQoKICAjIGxvZyBtZXRob2QgMSAtLSBydW4gZXZlcnl0aGluZyBhdCBvbmNlCiAgZml0MiA8LSBsbShsb2coWSl+VHJlYXRtZW50KlNleCwgZGF0YT1mZCkKICBmaXQyLmVtbSA8LSBlbW1lYW5zKGZpdDIsIHNwZWNzPWMoIlRyZWF0bWVudCIsICJTZXgiKSkKICBmaXQyLmVmZiA8LSBzdW1tYXJ5KGNvbnRyYXN0KGZpdDIuZW1tLCBhZGp1c3Q9Im5vbmUiLCBtZXRob2Q9InJldnBhaXJ3aXNlIiksIGluZmVyPWMoVFJVRSwgVFJVRSkpCiAgbG9ncmF0aW8xIDwtIDEwMCpjKAogICAgZXhwKGZpdDIuZWZmWzEsICJsb3dlci5DTCJdKS0xLAogICAgZXhwKGZpdDIuZWZmWzEsICJ1cHBlci5DTCJdKS0xLAogICAgZXhwKGZpdDIuZWZmWzYsICJsb3dlci5DTCJdKS0xLAogICAgZXhwKGZpdDIuZWZmWzYsICJ1cHBlci5DTCJdKS0xCiAgKQogIAogICMgbG9nIG1ldGhvZCAyIC0tIHBhaXJ3aXNlCiAgY29tYm9zIDwtIGMoIkNOLUYiLCAiQUEtRiIsICJDTi1NIiwgIkFBLU0iKQogIGZkWywgY29tYm86PWZhY3RvcihwYXN0ZShUcmVhdG1lbnQsIFNleCwgc2VwPSItIiksIGNvbWJvcyldCiAgZml0MiA8LSBsbShsb2coWSl+Y29tYm8sIGRhdGE9ZmRbY29tYm89PSJDTi1GIiB8IGNvbWJvPT0iQUEtRiJdKQogIGNpLmxvMSA8LSBleHAoY29uZmludChmaXQyKVsyLCAiMi41ICUiXSkgLSAxCiAgY2kudXAxIDwtIGV4cChjb25maW50KGZpdDIpWzIsICI5Ny41ICUiXSkgLSAxCgogIGZpdDIgPC0gbG0obG9nKFkpfmNvbWJvLCBkYXRhPWZkW2NvbWJvPT0iQ04tTSIgfCBjb21ibz09IkFBLU0iXSkKICBjaS5sbzIgPC0gZXhwKGNvbmZpbnQoZml0MilbMiwgIjIuNSAlIl0pIC0gMQogIGNpLnVwMiA8LSBleHAoY29uZmludChmaXQyKVsyLCAiOTcuNSAlIl0pIC0gMQogIAogIGxvZ3JhdGlvMiA8LSAxMDAqYyhjaS5sbzEsIGNpLnVwMSwgY2kubG8yLCBjaS51cDIpCgogICMgZGVsdGEKICBBMGhhdC5wIDwtIGZpdC5lZmZbMSwgImVzdGltYXRlIl0veWJhcjExCiAgQTFoYXQucCA8LSBmaXQuZWZmWzYsICJlc3RpbWF0ZSJdL3liYXIxMgogIHNlIDwtIGMoCiAgICBkZWx0YW1ldGhvZCh+eDIveDEsIG1lYW49Y29lZihmaXQpLCBjb3Y9dmNvdihmaXQpKSwKICAgIGRlbHRhbWV0aG9kKH4oeDIreDQpLyh4MSt4MyksIG1lYW49Y29lZihmaXQpLCBjb3Y9dmNvdihmaXQpKQogICkKICBkZWx0YSA8LSAxMDAqYygKICAgIEEwaGF0LnAtdGNyaXQqc2VbMV0sCiAgICBBMGhhdC5wK3Rjcml0KnNlWzFdLAogICAgQTFoYXQucC10Y3JpdCpzZVsyXSwKICAgIEExaGF0LnArdGNyaXQqc2VbMl0KICApCiAgcm93LnMgPC0gcm93LmUgKyAxCiAgcm93LmUgPC0gcm93LnMgKyBuLm1ldGhvZHMgLSAxCiAgcmVzW3Jvdy5zOnJvdy5lLCAyOihuLm1ldGhvZHMrMSldIDwtcmJpbmQobmFpdmUsIGxvZ3JhdGlvMSwgbG9ncmF0aW8yLCBkZWx0YSkKfQpyZXMgPC0gZGF0YS50YWJsZShyZXMpCgptZXRob2RfayA8LSAibmFpdmUiCm5haXZlIDwtIGMoCiAgbGVuZ3RoKHdoaWNoKHJlc1ttZXRob2Q9PW1ldGhvZF9rLEEwLmxvXSA8IEEwLnAgJiByZXNbbWV0aG9kPT1tZXRob2RfayxBMC51cF0gPiBBMC5wKSkvbml0ZXIqMTAwLAogIGxlbmd0aCh3aGljaChyZXNbbWV0aG9kPT1tZXRob2RfayxBMS5sb10gPCBBMS5wICYgcmVzW21ldGhvZD09bWV0aG9kX2ssQTEudXBdID4gQTEucCkpL25pdGVyKjEwMAopCgptZXRob2RfayA8LSAibG9nIgpsb2dyYXRpbzEgPC0gYygKICBsZW5ndGgod2hpY2gocmVzW21ldGhvZD09bWV0aG9kX2ssQTAubG9dIDwgQTAucCAmIHJlc1ttZXRob2Q9PW1ldGhvZF9rLEEwLnVwXSA+IEEwLnApKS9uaXRlcioxMDAsCiAgbGVuZ3RoKHdoaWNoKHJlc1ttZXRob2Q9PW1ldGhvZF9rLEExLmxvXSA8IEExLnAgJiByZXNbbWV0aG9kPT1tZXRob2RfayxBMS51cF0gPiBBMS5wKSkvbml0ZXIqMTAwCikKCm1ldGhvZF9rIDwtICJsb2ctcHciCmxvZ3JhdGlvMiA8LSBjKAogIGxlbmd0aCh3aGljaChyZXNbbWV0aG9kPT1tZXRob2RfayxBMC5sb10gPCBBMC5wICYgcmVzW21ldGhvZD09bWV0aG9kX2ssQTAudXBdID4gQTAucCkpL25pdGVyKjEwMCwKICBsZW5ndGgod2hpY2gocmVzW21ldGhvZD09bWV0aG9kX2ssQTEubG9dIDwgQTEucCAmIHJlc1ttZXRob2Q9PW1ldGhvZF9rLEExLnVwXSA+IEExLnApKS9uaXRlcioxMDAKKQoKbWV0aG9kX2sgPC0gIkRlbHRhIgpkZWx0YSA8LSBjKAogIGxlbmd0aCh3aGljaChyZXNbbWV0aG9kPT1tZXRob2RfayxBMC5sb10gPCBBMC5wICYgcmVzW21ldGhvZD09bWV0aG9kX2ssQTAudXBdID4gQTAucCkpL25pdGVyKjEwMCwKICBsZW5ndGgod2hpY2gocmVzW21ldGhvZD09bWV0aG9kX2ssQTEubG9dIDwgQTEucCAmIHJlc1ttZXRob2Q9PW1ldGhvZF9rLEExLnVwXSA+IEExLnApKS9uaXRlcioxMDAKKQoKcmVzLnRhYmxlIDwtIGRhdGEudGFibGUocmJpbmQobmFpdmUsIGxvZ3JhdGlvMSwgbG9ncmF0aW8yLCBkZWx0YSkpCmNvbG5hbWVzKHJlcy50YWJsZSkgPC0gYygiQUFGLUNORiIsICJBQU0tQ05NIikKcmVzLnRhYmxlIDwtIGNiaW5kKE1ldGhvZD1jKCJuYWl2ZSIsICJsb2ciLCAibG9nLXB3IiwgIkRlbHRhIiksIHJlcy50YWJsZSkKa25pdHI6OmthYmxlKHJlcy50YWJsZSwgZGlnaXRzPWMoMCwxLDEpKQoKYGBgCgpUaGUgdGFibGUgYWJvdmUgc2hvd3MgdGhlIGxvbmcgcnVuICgkMTBeNCQgcnVucykgZnJlcXVlbmN5IG9mIENJcyB0aGF0IGluY2x1ZGUgdGhlIHRydWUgcmVsYXRpdmUgZGlmZmVyZW5jZSBmb3IgdGhlIHR3byBzaW1wbGUgZWZmZWN0cyBvZiB0aGUgc2VsZWN0aW9uIGZhY3RvciBmb3IgZWFjaCBvZiB0aGUgZm91ciBtZXRob2RzLCBpbmNsdWRpbmcgYm90aCB0aGUgd2hvbGUtbW9kZWwgYW5kIHBhaXJ3aXNlIGxvZyBtZXRob2RzLiBBZ2FpbiwgdGhlIHBhaXJ3aXNlIGxvZyBtZXRob2QgYW5kIERlbHRhIG1ldGhvZCBoYXZlIHByZXR0eSBnb29kIGNvdmVyYWdlLiBUaGUgd2hvbGUtbW9kZWwgbG9nIG1ldGhvZCBpcyBsZXNzIGdvb2QgYW5kIHRoZSBuYWl2ZSBtZXRob2QgaXMgZXZlbiBsZXNzIGdvb2QhCgojIChwcm9iYWJseSBub3QpIEZpbmFsIHRob3VnaHRzCgpEbyBub3QgcmVwb3J0IG5haXZlIENJcyBvZiByZWxhdGl2ZSBlZmZlY3RzISBBbmQsIGlmIHlvdSBhcmUgZW1waGFzaXppbmcgc29tZSBhc3BlY3Qgb2YgaW5mZXJlbmNlIHVzaW5nIGEgcmVsYXRpdmUgZWZmZWN0LCBzdWNoIGFzIGEgJHAkLXZhbHVlLCBtYWtlIHN1cmUgdGhlICRwJC12YWx1ZSBpcyBjb21wdXRlZCBmcm9tIGEgc3RhdGlzdGljYWxseSBjb3JyZWN0IHN0YW5kYXJkIGVycm9yLCB3aGljaCBpc24ndCBhIG5haXZlIFNFICh0aGUgYWJzb2x1dGUgU0UgZGl2aWRlZCBieSB0aGUgcmVmZXJlbmNlIG1lYW4gdGltZXMgMTAwKS4KCklmIHRoZSBtb2RlbCBpcyBhbnl0aGluZyBtb3JlIGNvbXBsZXggdGhhbiBhIHNpbXBsZSAkdCQtdGVzdCwgZG8gbm90IHVzZSB0aGUgbG9nIG1ldGhvZCBvbiB0aGUgd2hvbGUgbW9kZWwgYnV0IGluc3RlYWQgdXNlIHRoZSBsb2cgbWV0aG9kIG9uIHNwZWNpZmljIGNvbnRyYXN0cy4gVGhpcyAicGFpcndpc2UiIGxvZyBtZXRob2QgaGFzIHByZXR0eSBnb29kIHJlc3VsdHMgYW5kIHRoZSBDSXMgYXJlIHByZXR0eSBlYXN5IHRvIGNvbXB1dGUsIGFsdGhvdWdoIEkgZXhwbG9yZWQgdGhpcyB3aXRoIG9ubHkgYSBzaW5nbGUgcGFyYW1ldGVyaXphdGlvbiBvZiBvbmx5IGEgZmV3LCBzaW1wbGUgbGluZWFyIG1vZGVscy4KClRoZSBEZWx0YSBtZXRob2QgaXMgc29tZXdoYXQgbW9yZSBzYXRpc2Z5aW5nIHRoYW4gdGhlIHBhaXJ3aXNlIGxvZyBtZXRob2Qgc2luY2UgaXQgdXNlcyB0aGUgd2hvbGUgbW9kZWwuIEFuZCBpdCBhbHNvIGhhcyBwcmV0dHkgZ29vZCByZXN1bHRzLCB3aXRoIHRoZSBjYXZlYXQgdGhhdCBJIGV4cGxvcmVkIHRoaXMgd2l0aCBvbmx5IGEgc2luZ2xlIHBhcmFtZXRlcml6YXRpb24gb2Ygb25seSBhIGZldywgc2ltcGxlIGxpbmVhciBtb2RlbHMuCgpXaGlsZSByZWxhdGl2ZSBlZmZlY3RzIGdpdmUgdXMgc29tZSBzaW5jZSBvZiB0aGUgYmlnbmVzcyBvZiBhbiBlZmZlY3QsIGEgZ2VuZXJhbCBwcm9ibGVtIHdpdGggcmVwb3J0aW5nIHJlc3VsdHMgYXMgcmVsYXRpdmUgZWZmZWN0cyBpcyB0aGF0IGl0IGRpc2NvdXJhZ2VzIHVzIGZyb20gZG9pbmcgdGhlIGhhcmQgd29yayBvZiB3b3JraW5nIG91dCB0aGUgYmlvbG9naWNhbCAoaW5jbHVkaW5nIHBoeXNpb2xvZ2ljYWwsIGVjb2xvZ2ljYWwsIGV2b2x1dGlvbmFyeSkgY29uc2VxdWVuY2VzIG9mIGFic29sdXRlIGVmZmVjdHMuIENvbnNpZGVyIHRoaXMgd2hlbiBwcmVzZW50aW5nIHJlc3VsdHMgYXMgcmVsYXRpdmUgZWZmZWN0cy4=