Mean and variance from a sample

Assume that our data set is \(n=100\) real numbers which have been sampled from a normal distribution with zero mean and unit variance.

Assume that given data we want to estimate the mean and variance (standard deviation) of the distribution that generated the data. The correct answer would be mean = 0 and sd = 1, but we never get exactly correct answer from a sample. Instead, we need to somehow estimate these values from our empirical sample.

Lets sample 1000 datasets of \(n=100\) numbers and compute mean and variance for each of them. Lets look at the distribution of means and variances.

Mean

set.seed(42)

## Make a matrix where columns are datasets of 100 real numbers
x <- replicate(1000,rnorm(100))

means <- apply(x,2,mean) # means for data sets
sds0 <- apply(x,2,function(y) sqrt(sum((y-mean(y))^2)/length(y))) # "biased" standard deviations
sds1 <- apply(x,2,function(y) sqrt(sum((y-mean(y))^2)/(length(y)-1))) # "unbiased" standard deviations

mv <- function(x) sprintf(" = %.4f ± %.4f",mean(x),sd(x))

hist(means,
     xlab=expression(hat(mu)),,
     main=bquote(paste(hat(mu),.(mv(means)))))

From the theory we know that given \(n\) real numbers \(x_i\), \(i\in\{1,\ldots,n\}\), the unbiased estimate of the mean is given by \[\hat\mu=\sum\nolimits_{i=1}^n{x_i}/n,\] which is confirmed by the histogram above.

We also know that the error in this estimate has a variance (standard deviation) of the mean estimate is \[ \sigma_{\hat\mu}=\sigma/\sqrt{n},\] where \(\sigma=1\) in our case. We notice that the theoretical values agree well with the ones that we see from the same histogram.

plot(means,sds1,
     xlab=expression(hat(mu)),
     ylab=expression(hat(sigma)[1]),
     main="estimated means and variances")
abline(v=0,col="red")
abline(h=1,col="red")
legend("topleft",
       legend=c("true values","estimates for datasets"),
       lty=c("solid",NA),
       pch=c(NA,1),
       col=c("red","black"),
       cex=0.5)

Variance (standard deviation)

Lets then look at the estimator of variance (standard deviation). If an estimate is “biased” it means that (for finite data) the expected value of the estimate differes from the true value. The most known instance of biased estimate is the naive estimator for the standard deviation.

hist(sds0,
     xlab=expression(hat(sigma)[0]),
     main=bquote(paste(hat(sigma)[0],.(mv(sds0)))))

hist(sds1,
     xlab=expression(hat(sigma)[1]),
     main=bquote(paste(hat(sigma)[1],.(mv(sds1)))))

Naive “biased” estimate of variance (standard deviation) is given by \[\hat\sigma_0=\left(\sum\nolimits_{i=1}^n{\left(x_i-\hat\mu\right)^2}/n\right)^{1/2}.\] “Unbiased” estimate of variance (standard deviation) is given by \[\hat\sigma_1=\left(\sum\nolimits_{i=1}^n{\left(x_i-\hat\mu\right)^2}/(n-1)\right)^{1/2}.\] We indeed notice that the unbiased estimate gives on average a result that is very close to the true value of \(\sigma=1\), while the biased estimate underestimates the variance.

Estimated regression coefficients

Assume that we have again \(n=100\) data points \((x_i,y_i)\in{\mathbb{R^2}}\), where \(i=\{1,\ldots,n\}\), \(y_i=2+3x_i+\epsilon_i\) and \(\epsilon_i\in{\mathbb{R}}\) is a noise term. Assume that \(x_i\) and \(\epsilon_i\) are sampled independently from a normal distribution with zero mean and unit variance.

y <- 2+3*x+rnorm(length(x))
plot(x[,1],y[,1],xlab="x",ylab="y")

Consider OLS linear regression where a regression function \[ f(x)=\beta_0+\beta_1 x\] is fitted to the data. Obviously, the “true” values for the parameters \(\beta_0\) and \(\beta_1\) read \(\beta_0=2\) and \(\beta_1=3\), but from a finite sample we never get exactly the correct result, instead, the fits vary slightly.

bb <- sapply(1:ncol(x),
             function(i) lm(y~x,data.frame(x=x[,i],y=y[,i]))$coefficients)

plot(x[,1],y[,1],xlab="x",ylab="y",main="OLS fits for different data sets")
abline(a=2,b=3)
for(i in 1:10) {
  abline(a=bb[1,i],b=bb[2,i],lty="dotted")
}
legend("topleft",legend=c("true model","fitted models"),
       lty=c("solid","dotted"))

We next study the distribution of regression coefficients \(\hat\beta_0\) and \(\hat\beta_1\) in various fits.

plot(t(bb),
     xlab=expression(hat(beta)[0]),ylab=expression(hat(beta)[1]),
     main="estimated regression coefficients")
abline(v=2,col="red")
abline(h=3,col="red")
legend("topleft",
       legend=c("true coefficients","estimates for datasets"),
       lty=c("solid",NA),
       pch=c(NA,1),
       col=c("red","black"),
       cex=0.5)


hist(bb[1,],
     xlab=expression(hat(beta)[0]),
     main=bquote(paste(hat(beta)[0],.(mv(bb[1,])))))

hist(bb[2,],
     xlab=expression(hat(beta)[1]),
     main=bquote(paste(hat(beta)[1],.(mv(bb[2,])))))

Not surprisingly, the “error” in the estimates of both \(\hat\beta_0\) and \(\hat\beta_1\) obey the \(\sigma/\sqrt{n}=0.1\) rule here. We however leave the derivation of this as an exercise for you. On average, we get rather accurately the “correct” result \(\hat\beta_0=2\) and \(\hat\beta_1=3\), but for individual data sets there is some variance of the order of \(0.1^2\).

Bootstrap

We were able to do the above exercise because we knew the distribution that generated the data. What if we do not know the distribution? Then we can use the bootstrap sampling, see the textbook, Sec. 5.2, for discussion.

First, we choose the first sampled dataset of size \(n=100\) and assume that we have no access to the 999 other datasets.

For this specific dataset we have the following estimates \(\hat\mu=\) 0.0325148, \(\hat\sigma_0=\) 1.0361371, \(\hat\sigma_1=\) 1.041357, \(\hat\beta_0=\) 2.0127722, and \(\hat\beta_1=\) 2.807633.

Lets generate 1000 bootstrap replicates out of this chosen dataset only.

## Resample each of the columns (datasets) with replacement
idx <- c(replicate(1000,sample.int(100,replace=TRUE)))

## Bootstrap samples of x[,1] and y[,1]
xb <- matrix(x[idx,1],nrow=nrow(x),ncol=ncol(x))
yb <- matrix(y[idx,1],nrow=nrow(y),ncol=ncol(y))

Do all of the same stuff with the bootstrap samples that we did with the samples from the “true” distribution.

meansb <- apply(xb,2,mean) # means for data sets
sds0b <- apply(xb,2,function(y) sqrt(sum((y-mean(y))^2)/length(y))) # "biased" standard deviations
sds1b <- apply(xb,2,function(y) sqrt(sum((y-mean(y))^2)/(length(y)-1))) # "unbiased" standard deviations

The bootstrap estimates of \(\hat\mu\) and \(\hat\sigma_1\) and their variances look very similar to the corresponding values from the true distribution.

hist(meansb,
     xlab=expression(hat(mu)),,
     main=bquote(paste(hat(mu),.(mv(means)))))

hist(sds0b,
     xlab=expression(hat(sigma)[0]),
     main=bquote(paste(hat(sigma)[0],.(mv(sds0)))))

hist(sds1b,
     xlab=expression(hat(sigma)[1]),
     main=bquote(paste(hat(sigma)[1],.(mv(sds1)))))

We next take a look at regression. More specifically, we do the OLS regression for bootstrap replicates of the dataset. Remember that for the original dataset the estimates of the regression coefficients are \(\hat\beta_0=\) 2.0127722 and \(\hat\beta_1=\) 2.807633.

bbb <- sapply(1:ncol(x),
             function(i) lm(y~x,data.frame(x=xb[,i],y=yb[,i]))$coefficients)

plot(x[,1],y[,1],xlab="x",ylab="y")
abline(a=2,b=3)
for(i in 1:10) {
  abline(a=bbb[1,i],b=bbb[2,i],lty="dotted")
}

The bootstrap distribution of the regression coefficients is a bit more interesting.

plot(t(bbb),
     xlab=expression(hat(beta)[0]),ylab=expression(hat(beta)[1]),
     main="estimated regression coefficients")
abline(v=2,col="red")
abline(h=3,col="red")
abline(v=bb[1,1],col="red",lty="dashed")
abline(h=bb[2,1],col="red",lty="dashed")
legend("topleft",
       legend=c("true coefficients","original estimates","bootstrap estimates"),
       lty=c("solid","dashed",NA),
       pch=c(NA,NA,1),
       col=c("red","red","black"),
       cex=0.5)


hist(bbb[1,],
     xlab=expression(hat(beta)[0]),
     main=bquote(paste(hat(beta)[0],.(mv(bbb[1,])))))

hist(bbb[2,],
     xlab=expression(hat(beta)[1]),
     main=bquote(paste(hat(beta)[1],.(mv(bbb[2,])))))

Miracle happened! It seems that we do not need to be able to sample from the true distribution at all. “Simulating” the true distribution with bootstrap samples seem to work just fine. Notice that there are of course some subtle assumptions that we need to make in order for this to be consistent, but they are outside the scope of this course.

Notice that the bootstrap estimates are centered around the empirical means of the chosen dataset, not the true means. For example, for the \(\hat\beta_1=\) 2.807633 for our dataset and this is where bootstrap distribution for \(\hat\beta_1\) is centered. This is logical, as the bootstrap cannot magically find out that it should be centered around 3. However, the estimate of variance is at least approximately correct. Therefore, with the bootstrap you cannot magically find the “true” mean (only the mean of the empirical sample), but you can find a good estimate of the variance of an estimator. When you know the variance you can find the confidence intervals for the estimator. For example \(\pm 1.96\hat\sigma_1\) confidence intervals for the parameter \(\hat\beta_1=\) 2.807633 would be given by \([\) 2.5966345 \(,\) 3.0186315 \(]\). The “true” value \(\beta_1=3\) is indeed inside this interval.

About confidence intervals and statistical testing

Why \(\pm 1.96\hat\sigma_1\)? If a random variable \(X\) is normally distributed with mean \(\mu\) and variance \(\sigma\), then its value is with 95% probability in the interval \([\mu-1.96\sigma,\mu+1.96\sigma]\). We call this interval 95% confidence interval.

Often, an interesting question is if the null hypothesis that a linear coefficient \(\beta_1\) vanishes can be rejected. We can reject the null hypothesis, i.e., claim that \(\beta_1\) really is non-zero, if zero is not included in the confidence interval. R reports directly standard errors for (i.e., \(1\sigma\) errors) for linear regression coefficients as well as p-values for the null hypothesis that the coefficient vanishes:

print(summary(lm(y~x,data.frame(x=x[,1],y=y[,1]))))

Call:
lm(formula = y ~ x, data = data.frame(x = x[, 1], y = y[, 1]))

Residuals:
    Min      1Q  Median      3Q     Max 
-2.9289 -0.5077 -0.0846  0.5860  3.5658 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  2.01277    0.09838   20.46   <2e-16 ***
x            2.80763    0.09491   29.58   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.9834 on 98 degrees of freedom
Multiple R-squared:  0.8993,    Adjusted R-squared:  0.8983 
F-statistic: 875.2 on 1 and 98 DF,  p-value: < 2.2e-16

Please read Sec. 3.1.2 of the text book for more information.

LS0tCnRpdGxlOiAiQWJvdXQgYm9vdHN0cmFwIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKYXV0aG9yOiBLYWkgUHVvbGFtw6RraQpkYXRlOiAxMyBEZWNlbWJlciAyMDE5Ci0tLQoKIyMgTWVhbiBhbmQgdmFyaWFuY2UgZnJvbSBhIHNhbXBsZQoKQXNzdW1lIHRoYXQgb3VyIGRhdGEgc2V0IGlzICRuPTEwMCQgcmVhbCBudW1iZXJzIHdoaWNoIGhhdmUgYmVlbiBzYW1wbGVkIGZyb20gYSBub3JtYWwgZGlzdHJpYnV0aW9uIHdpdGggemVybyBtZWFuIGFuZCB1bml0IHZhcmlhbmNlLiAKCkFzc3VtZSB0aGF0IGdpdmVuIGRhdGEgd2Ugd2FudCB0byBlc3RpbWF0ZSB0aGUgbWVhbiBhbmQgdmFyaWFuY2UgKHN0YW5kYXJkIGRldmlhdGlvbikgb2YgdGhlIGRpc3RyaWJ1dGlvbiB0aGF0IGdlbmVyYXRlZCB0aGUgZGF0YS4gVGhlIGNvcnJlY3QgYW5zd2VyIHdvdWxkIGJlIG1lYW4gPSAwIGFuZCBzZCA9IDEsIGJ1dCB3ZSBuZXZlciBnZXQgZXhhY3RseSBjb3JyZWN0IGFuc3dlciBmcm9tIGEgc2FtcGxlLiBJbnN0ZWFkLCB3ZSBuZWVkIHRvIHNvbWVob3cgZXN0aW1hdGUgdGhlc2UgdmFsdWVzIGZyb20gb3VyIGVtcGlyaWNhbCBzYW1wbGUuCgpMZXRzIHNhbXBsZSAxMDAwIGRhdGFzZXRzIG9mICRuPTEwMCQgbnVtYmVycyBhbmQgY29tcHV0ZSBtZWFuIGFuZCB2YXJpYW5jZSBmb3IgZWFjaCBvZiB0aGVtLiBMZXRzIGxvb2sgYXQgdGhlIGRpc3RyaWJ1dGlvbiBvZiBtZWFucyBhbmQgdmFyaWFuY2VzLgoKIyMjIE1lYW4KCmBgYHtyfQpzZXQuc2VlZCg0MikKCiMjIE1ha2UgYSBtYXRyaXggd2hlcmUgY29sdW1ucyBhcmUgZGF0YXNldHMgb2YgMTAwIHJlYWwgbnVtYmVycwp4IDwtIHJlcGxpY2F0ZSgxMDAwLHJub3JtKDEwMCkpCgptZWFucyA8LSBhcHBseSh4LDIsbWVhbikgIyBtZWFucyBmb3IgZGF0YSBzZXRzCnNkczAgPC0gYXBwbHkoeCwyLGZ1bmN0aW9uKHkpIHNxcnQoc3VtKCh5LW1lYW4oeSkpXjIpL2xlbmd0aCh5KSkpICMgImJpYXNlZCIgc3RhbmRhcmQgZGV2aWF0aW9ucwpzZHMxIDwtIGFwcGx5KHgsMixmdW5jdGlvbih5KSBzcXJ0KHN1bSgoeS1tZWFuKHkpKV4yKS8obGVuZ3RoKHkpLTEpKSkgIyAidW5iaWFzZWQiIHN0YW5kYXJkIGRldmlhdGlvbnMKCm12IDwtIGZ1bmN0aW9uKHgpIHNwcmludGYoIiA9ICUuNGYgwrEgJS40ZiIsbWVhbih4KSxzZCh4KSkKCmhpc3QobWVhbnMsCiAgICAgeGxhYj1leHByZXNzaW9uKGhhdChtdSkpLCwKICAgICBtYWluPWJxdW90ZShwYXN0ZShoYXQobXUpLC4obXYobWVhbnMpKSkpKQpgYGAKCkZyb20gdGhlIHRoZW9yeSB3ZSBrbm93IHRoYXQgZ2l2ZW4gJG4kIHJlYWwgbnVtYmVycyAkeF9pJCwgJGlcaW5cezEsXGxkb3RzLG5cfSQsIHRoZSB1bmJpYXNlZCBlc3RpbWF0ZSBvZiB0aGUgbWVhbiBpcyBnaXZlbiBieQokJFxoYXRcbXU9XHN1bVxub2xpbWl0c197aT0xfV5ue3hfaX0vbiwkJAp3aGljaCBpcyBjb25maXJtZWQgYnkgdGhlIGhpc3RvZ3JhbSBhYm92ZS4KCldlIGFsc28ga25vdyB0aGF0IHRoZSBlcnJvciBpbiB0aGlzIGVzdGltYXRlIGhhcyBhIHZhcmlhbmNlIChzdGFuZGFyZCBkZXZpYXRpb24pIG9mIHRoZSBtZWFuIGVzdGltYXRlIGlzCiQkIFxzaWdtYV97XGhhdFxtdX09XHNpZ21hL1xzcXJ0e259LCQkCndoZXJlICRcc2lnbWE9MSQgaW4gb3VyIGNhc2UuIFdlIG5vdGljZSB0aGF0IHRoZSB0aGVvcmV0aWNhbCB2YWx1ZXMgYWdyZWUgd2VsbCB3aXRoIHRoZSBvbmVzIHRoYXQgd2Ugc2VlIGZyb20gdGhlIHNhbWUgaGlzdG9ncmFtLgoKYGBge3J9CnBsb3QobWVhbnMsc2RzMSwKICAgICB4bGFiPWV4cHJlc3Npb24oaGF0KG11KSksCiAgICAgeWxhYj1leHByZXNzaW9uKGhhdChzaWdtYSlbMV0pLAogICAgIG1haW49ImVzdGltYXRlZCBtZWFucyBhbmQgdmFyaWFuY2VzIikKYWJsaW5lKHY9MCxjb2w9InJlZCIpCmFibGluZShoPTEsY29sPSJyZWQiKQpsZWdlbmQoInRvcGxlZnQiLAogICAgICAgbGVnZW5kPWMoInRydWUgdmFsdWVzIiwiZXN0aW1hdGVzIGZvciBkYXRhc2V0cyIpLAogICAgICAgbHR5PWMoInNvbGlkIixOQSksCiAgICAgICBwY2g9YyhOQSwxKSwKICAgICAgIGNvbD1jKCJyZWQiLCJibGFjayIpLAogICAgICAgY2V4PTAuNSkKYGBgCgojIyMgVmFyaWFuY2UgKHN0YW5kYXJkIGRldmlhdGlvbikKCkxldHMgdGhlbiBsb29rIGF0IHRoZSBlc3RpbWF0b3Igb2YgdmFyaWFuY2UgKHN0YW5kYXJkIGRldmlhdGlvbikuIElmIGFuIGVzdGltYXRlIGlzICJiaWFzZWQiIGl0IG1lYW5zIHRoYXQgKGZvciBmaW5pdGUgZGF0YSkgdGhlIGV4cGVjdGVkIHZhbHVlIG9mIHRoZSBlc3RpbWF0ZSBkaWZmZXJlcyBmcm9tIHRoZSB0cnVlIHZhbHVlLiBUaGUgbW9zdCBrbm93biBpbnN0YW5jZSBvZiBiaWFzZWQgZXN0aW1hdGUgaXMgdGhlIG5haXZlIGVzdGltYXRvciBmb3IgdGhlIHN0YW5kYXJkIGRldmlhdGlvbi4KCmBgYHtyfQpoaXN0KHNkczAsCiAgICAgeGxhYj1leHByZXNzaW9uKGhhdChzaWdtYSlbMF0pLAogICAgIG1haW49YnF1b3RlKHBhc3RlKGhhdChzaWdtYSlbMF0sLihtdihzZHMwKSkpKSkKaGlzdChzZHMxLAogICAgIHhsYWI9ZXhwcmVzc2lvbihoYXQoc2lnbWEpWzFdKSwKICAgICBtYWluPWJxdW90ZShwYXN0ZShoYXQoc2lnbWEpWzFdLC4obXYoc2RzMSkpKSkpCmBgYAoKTmFpdmUgImJpYXNlZCIgZXN0aW1hdGUgb2YgdmFyaWFuY2UgKHN0YW5kYXJkIGRldmlhdGlvbikgaXMgZ2l2ZW4gYnkKJCRcaGF0XHNpZ21hXzA9XGxlZnQoXHN1bVxub2xpbWl0c197aT0xfV5ue1xsZWZ0KHhfaS1caGF0XG11XHJpZ2h0KV4yfS9uXHJpZ2h0KV57MS8yfS4kJAoiVW5iaWFzZWQiIGVzdGltYXRlIG9mIHZhcmlhbmNlIChzdGFuZGFyZCBkZXZpYXRpb24pIGlzIGdpdmVuIGJ5CiQkXGhhdFxzaWdtYV8xPVxsZWZ0KFxzdW1cbm9saW1pdHNfe2k9MX1ebntcbGVmdCh4X2ktXGhhdFxtdVxyaWdodCleMn0vKG4tMSlccmlnaHQpXnsxLzJ9LiQkCldlIGluZGVlZCBub3RpY2UgdGhhdCB0aGUgdW5iaWFzZWQgZXN0aW1hdGUgZ2l2ZXMgb24gYXZlcmFnZSBhIHJlc3VsdCB0aGF0IGlzIHZlcnkgY2xvc2UgdG8gdGhlIHRydWUgdmFsdWUgb2YgJFxzaWdtYT0xJCwgd2hpbGUgdGhlIGJpYXNlZCBlc3RpbWF0ZSB1bmRlcmVzdGltYXRlcyB0aGUgdmFyaWFuY2UuCgojIyBFc3RpbWF0ZWQgcmVncmVzc2lvbiBjb2VmZmljaWVudHMKCkFzc3VtZSB0aGF0IHdlIGhhdmUgYWdhaW4gJG49MTAwJCBkYXRhIHBvaW50cyAkKHhfaSx5X2kpXGlue1xtYXRoYmJ7Ul4yfX0kLCB3aGVyZSAkaT1cezEsXGxkb3RzLG5cfSQsICR5X2k9MiszeF9pK1xlcHNpbG9uX2kkIGFuZCAkXGVwc2lsb25faVxpbntcbWF0aGJie1J9fSQgaXMgYSBub2lzZSB0ZXJtLiBBc3N1bWUgdGhhdCAkeF9pJCBhbmQgJFxlcHNpbG9uX2kkIGFyZSBzYW1wbGVkIGluZGVwZW5kZW50bHkgZnJvbSBhIG5vcm1hbCBkaXN0cmlidXRpb24gd2l0aCB6ZXJvIG1lYW4gYW5kIHVuaXQgdmFyaWFuY2UuIAoKYGBge3J9CnkgPC0gMiszKngrcm5vcm0obGVuZ3RoKHgpKQpwbG90KHhbLDFdLHlbLDFdLHhsYWI9IngiLHlsYWI9InkiKQpgYGAKCkNvbnNpZGVyIE9MUyBsaW5lYXIgcmVncmVzc2lvbiB3aGVyZSBhIHJlZ3Jlc3Npb24gZnVuY3Rpb24gJCQKZih4KT1cYmV0YV8wK1xiZXRhXzEgeCQkCmlzIGZpdHRlZCB0byB0aGUgZGF0YS4gT2J2aW91c2x5LCB0aGUgInRydWUiIHZhbHVlcyBmb3IgdGhlIHBhcmFtZXRlcnMgJFxiZXRhXzAkIGFuZCAkXGJldGFfMSQgcmVhZCAkXGJldGFfMD0yJCBhbmQgJFxiZXRhXzE9MyQsIGJ1dCBmcm9tIGEgZmluaXRlIHNhbXBsZSB3ZSBuZXZlciBnZXQgZXhhY3RseSB0aGUgY29ycmVjdCByZXN1bHQsIGluc3RlYWQsIHRoZSBmaXRzIHZhcnkgc2xpZ2h0bHkuCgpgYGB7cn0KYmIgPC0gc2FwcGx5KDE6bmNvbCh4KSwKICAgICAgICAgICAgIGZ1bmN0aW9uKGkpIGxtKHl+eCxkYXRhLmZyYW1lKHg9eFssaV0seT15WyxpXSkpJGNvZWZmaWNpZW50cykKCnBsb3QoeFssMV0seVssMV0seGxhYj0ieCIseWxhYj0ieSIsbWFpbj0iT0xTIGZpdHMgZm9yIGRpZmZlcmVudCBkYXRhIHNldHMiKQphYmxpbmUoYT0yLGI9MykKZm9yKGkgaW4gMToxMCkgewogIGFibGluZShhPWJiWzEsaV0sYj1iYlsyLGldLGx0eT0iZG90dGVkIikKfQpsZWdlbmQoInRvcGxlZnQiLGxlZ2VuZD1jKCJ0cnVlIG1vZGVsIiwiZml0dGVkIG1vZGVscyIpLAogICAgICAgbHR5PWMoInNvbGlkIiwiZG90dGVkIikpCmBgYAoKV2UgbmV4dCBzdHVkeSB0aGUgZGlzdHJpYnV0aW9uIG9mIHJlZ3Jlc3Npb24gY29lZmZpY2llbnRzICRcaGF0XGJldGFfMCQgYW5kICRcaGF0XGJldGFfMSQgaW4gdmFyaW91cyBmaXRzLgoKYGBge3J9CnBsb3QodChiYiksCiAgICAgeGxhYj1leHByZXNzaW9uKGhhdChiZXRhKVswXSkseWxhYj1leHByZXNzaW9uKGhhdChiZXRhKVsxXSksCiAgICAgbWFpbj0iZXN0aW1hdGVkIHJlZ3Jlc3Npb24gY29lZmZpY2llbnRzIikKYWJsaW5lKHY9Mixjb2w9InJlZCIpCmFibGluZShoPTMsY29sPSJyZWQiKQpsZWdlbmQoInRvcGxlZnQiLAogICAgICAgbGVnZW5kPWMoInRydWUgY29lZmZpY2llbnRzIiwiZXN0aW1hdGVzIGZvciBkYXRhc2V0cyIpLAogICAgICAgbHR5PWMoInNvbGlkIixOQSksCiAgICAgICBwY2g9YyhOQSwxKSwKICAgICAgIGNvbD1jKCJyZWQiLCJibGFjayIpLAogICAgICAgY2V4PTAuNSkKCmhpc3QoYmJbMSxdLAogICAgIHhsYWI9ZXhwcmVzc2lvbihoYXQoYmV0YSlbMF0pLAogICAgIG1haW49YnF1b3RlKHBhc3RlKGhhdChiZXRhKVswXSwuKG12KGJiWzEsXSkpKSkpCmhpc3QoYmJbMixdLAogICAgIHhsYWI9ZXhwcmVzc2lvbihoYXQoYmV0YSlbMV0pLAogICAgIG1haW49YnF1b3RlKHBhc3RlKGhhdChiZXRhKVsxXSwuKG12KGJiWzIsXSkpKSkpCmBgYAoKTm90IHN1cnByaXNpbmdseSwgdGhlICJlcnJvciIgaW4gdGhlIGVzdGltYXRlcyBvZiBib3RoICRcaGF0XGJldGFfMCQgYW5kICRcaGF0XGJldGFfMSQgb2JleSB0aGUgJFxzaWdtYS9cc3FydHtufT0wLjEkIHJ1bGUgaGVyZS4gV2UgaG93ZXZlciBsZWF2ZSB0aGUgZGVyaXZhdGlvbiBvZiB0aGlzIGFzIGFuIGV4ZXJjaXNlIGZvciB5b3UuIE9uIGF2ZXJhZ2UsIHdlIGdldCByYXRoZXIgYWNjdXJhdGVseSB0aGUgImNvcnJlY3QiIHJlc3VsdCAkXGhhdFxiZXRhXzA9MiQgYW5kICRcaGF0XGJldGFfMT0zJCwgYnV0IGZvciBpbmRpdmlkdWFsIGRhdGEgc2V0cyB0aGVyZSBpcyBzb21lIHZhcmlhbmNlIG9mIHRoZSBvcmRlciBvZiAkMC4xXjIkLgoKIyMgQm9vdHN0cmFwCgpXZSB3ZXJlIGFibGUgdG8gZG8gdGhlIGFib3ZlIGV4ZXJjaXNlIGJlY2F1c2Ugd2Uga25ldyB0aGUgZGlzdHJpYnV0aW9uIHRoYXQgZ2VuZXJhdGVkIHRoZSBkYXRhLiBXaGF0IGlmIHdlIGRvIG5vdCBrbm93IHRoZSBkaXN0cmlidXRpb24/IFRoZW4gd2UgY2FuIHVzZSB0aGUgKipib290c3RyYXAqKiBzYW1wbGluZywgc2VlIHRoZSB0ZXh0Ym9vaywgU2VjLiA1LjIsIGZvciBkaXNjdXNzaW9uLgoKRmlyc3QsIHdlIGNob29zZSB0aGUgZmlyc3Qgc2FtcGxlZCBkYXRhc2V0IG9mIHNpemUgJG49MTAwJCBhbmQgYXNzdW1lIHRoYXQgd2UgaGF2ZSBubyBhY2Nlc3MgdG8gdGhlIDk5OSBvdGhlciBkYXRhc2V0cy4KCkZvciB0aGlzIHNwZWNpZmljIGRhdGFzZXQgd2UgaGF2ZSB0aGUgZm9sbG93aW5nIGVzdGltYXRlcyAkXGhhdFxtdT0kIGByIG1lYW4oeFssMV0pYCwgJFxoYXRcc2lnbWFfMD0kIGByIHNkKHhbLDFdKSpzcXJ0KDk5LzEwMClgLCAkXGhhdFxzaWdtYV8xPSQgYHIgc2QoeFssMV0pYCwgJFxoYXRcYmV0YV8wPSQgYHIgYmJbMSwxXWAsIGFuZCAkXGhhdFxiZXRhXzE9JCBgciBiYlsyLDFdYC4KCkxldHMgZ2VuZXJhdGUgMTAwMCBib290c3RyYXAgcmVwbGljYXRlcyBvdXQgb2YgdGhpcyBjaG9zZW4gZGF0YXNldCBvbmx5LgoKYGBge3J9CiMjIFJlc2FtcGxlIGVhY2ggb2YgdGhlIGNvbHVtbnMgKGRhdGFzZXRzKSB3aXRoIHJlcGxhY2VtZW50CmlkeCA8LSBjKHJlcGxpY2F0ZSgxMDAwLHNhbXBsZS5pbnQoMTAwLHJlcGxhY2U9VFJVRSkpKQoKIyMgQm9vdHN0cmFwIHNhbXBsZXMgb2YgeFssMV0gYW5kIHlbLDFdCnhiIDwtIG1hdHJpeCh4W2lkeCwxXSxucm93PW5yb3coeCksbmNvbD1uY29sKHgpKQp5YiA8LSBtYXRyaXgoeVtpZHgsMV0sbnJvdz1ucm93KHkpLG5jb2w9bmNvbCh5KSkKYGBgCgpEbyBhbGwgb2YgdGhlIHNhbWUgc3R1ZmYgd2l0aCB0aGUgYm9vdHN0cmFwIHNhbXBsZXMgdGhhdCB3ZSBkaWQgd2l0aCB0aGUgc2FtcGxlcyBmcm9tIHRoZSAidHJ1ZSIgZGlzdHJpYnV0aW9uLgoKYGBge3J9Cm1lYW5zYiA8LSBhcHBseSh4YiwyLG1lYW4pICMgbWVhbnMgZm9yIGRhdGEgc2V0cwpzZHMwYiA8LSBhcHBseSh4YiwyLGZ1bmN0aW9uKHkpIHNxcnQoc3VtKCh5LW1lYW4oeSkpXjIpL2xlbmd0aCh5KSkpICMgImJpYXNlZCIgc3RhbmRhcmQgZGV2aWF0aW9ucwpzZHMxYiA8LSBhcHBseSh4YiwyLGZ1bmN0aW9uKHkpIHNxcnQoc3VtKCh5LW1lYW4oeSkpXjIpLyhsZW5ndGgoeSktMSkpKSAjICJ1bmJpYXNlZCIgc3RhbmRhcmQgZGV2aWF0aW9ucwpgYGAKClRoZSBib290c3RyYXAgZXN0aW1hdGVzIG9mICRcaGF0XG11JCBhbmQgJFxoYXRcc2lnbWFfMSQgYW5kIHRoZWlyIHZhcmlhbmNlcyBsb29rIHZlcnkgc2ltaWxhciB0byB0aGUgY29ycmVzcG9uZGluZyB2YWx1ZXMgZnJvbSB0aGUgdHJ1ZSBkaXN0cmlidXRpb24uCgpgYGB7cn0KaGlzdChtZWFuc2IsCiAgICAgeGxhYj1leHByZXNzaW9uKGhhdChtdSkpLCwKICAgICBtYWluPWJxdW90ZShwYXN0ZShoYXQobXUpLC4obXYobWVhbnMpKSkpKQpoaXN0KHNkczBiLAogICAgIHhsYWI9ZXhwcmVzc2lvbihoYXQoc2lnbWEpWzBdKSwKICAgICBtYWluPWJxdW90ZShwYXN0ZShoYXQoc2lnbWEpWzBdLC4obXYoc2RzMCkpKSkpCmhpc3Qoc2RzMWIsCiAgICAgeGxhYj1leHByZXNzaW9uKGhhdChzaWdtYSlbMV0pLAogICAgIG1haW49YnF1b3RlKHBhc3RlKGhhdChzaWdtYSlbMV0sLihtdihzZHMxKSkpKSkKYGBgCgpXZSBuZXh0IHRha2UgYSBsb29rIGF0IHJlZ3Jlc3Npb24uIE1vcmUgc3BlY2lmaWNhbGx5LCB3ZSBkbyB0aGUgT0xTIHJlZ3Jlc3Npb24gZm9yIGJvb3RzdHJhcCByZXBsaWNhdGVzIG9mIHRoZSBkYXRhc2V0LiBSZW1lbWJlciB0aGF0IGZvciB0aGUgb3JpZ2luYWwgZGF0YXNldCB0aGUgZXN0aW1hdGVzIG9mIHRoZSByZWdyZXNzaW9uIGNvZWZmaWNpZW50cyBhcmUgJFxoYXRcYmV0YV8wPSQgYHIgYmJbMSwxXWAgYW5kICRcaGF0XGJldGFfMT0kIGByIGJiWzIsMV1gLgoKYGBge3J9CmJiYiA8LSBzYXBwbHkoMTpuY29sKHgpLAogICAgICAgICAgICAgZnVuY3Rpb24oaSkgbG0oeX54LGRhdGEuZnJhbWUoeD14YlssaV0seT15YlssaV0pKSRjb2VmZmljaWVudHMpCgpwbG90KHhbLDFdLHlbLDFdLHhsYWI9IngiLHlsYWI9InkiKQphYmxpbmUoYT0yLGI9MykKZm9yKGkgaW4gMToxMCkgewogIGFibGluZShhPWJiYlsxLGldLGI9YmJiWzIsaV0sbHR5PSJkb3R0ZWQiKQp9CmBgYAoKVGhlIGJvb3RzdHJhcCBkaXN0cmlidXRpb24gb2YgdGhlIHJlZ3Jlc3Npb24gY29lZmZpY2llbnRzIGlzIGEgYml0IG1vcmUgaW50ZXJlc3RpbmcuCgpgYGB7cn0KcGxvdCh0KGJiYiksCiAgICAgeGxhYj1leHByZXNzaW9uKGhhdChiZXRhKVswXSkseWxhYj1leHByZXNzaW9uKGhhdChiZXRhKVsxXSksCiAgICAgbWFpbj0iZXN0aW1hdGVkIHJlZ3Jlc3Npb24gY29lZmZpY2llbnRzIikKYWJsaW5lKHY9Mixjb2w9InJlZCIpCmFibGluZShoPTMsY29sPSJyZWQiKQphYmxpbmUodj1iYlsxLDFdLGNvbD0icmVkIixsdHk9ImRhc2hlZCIpCmFibGluZShoPWJiWzIsMV0sY29sPSJyZWQiLGx0eT0iZGFzaGVkIikKbGVnZW5kKCJ0b3BsZWZ0IiwKICAgICAgIGxlZ2VuZD1jKCJ0cnVlIGNvZWZmaWNpZW50cyIsIm9yaWdpbmFsIGVzdGltYXRlcyIsImJvb3RzdHJhcCBlc3RpbWF0ZXMiKSwKICAgICAgIGx0eT1jKCJzb2xpZCIsImRhc2hlZCIsTkEpLAogICAgICAgcGNoPWMoTkEsTkEsMSksCiAgICAgICBjb2w9YygicmVkIiwicmVkIiwiYmxhY2siKSwKICAgICAgIGNleD0wLjUpCgpoaXN0KGJiYlsxLF0sCiAgICAgeGxhYj1leHByZXNzaW9uKGhhdChiZXRhKVswXSksCiAgICAgbWFpbj1icXVvdGUocGFzdGUoaGF0KGJldGEpWzBdLC4obXYoYmJiWzEsXSkpKSkpCmhpc3QoYmJiWzIsXSwKICAgICB4bGFiPWV4cHJlc3Npb24oaGF0KGJldGEpWzFdKSwKICAgICBtYWluPWJxdW90ZShwYXN0ZShoYXQoYmV0YSlbMV0sLihtdihiYmJbMixdKSkpKSkKYGBgCgpNaXJhY2xlIGhhcHBlbmVkISBJdCBzZWVtcyB0aGF0IHdlIGRvIG5vdCBuZWVkIHRvIGJlIGFibGUgdG8gc2FtcGxlIGZyb20gdGhlIHRydWUgZGlzdHJpYnV0aW9uIGF0IGFsbC4gIlNpbXVsYXRpbmciIHRoZSB0cnVlIGRpc3RyaWJ1dGlvbiB3aXRoIGJvb3RzdHJhcCBzYW1wbGVzIHNlZW0gdG8gd29yayBqdXN0IGZpbmUuIE5vdGljZSB0aGF0IHRoZXJlIGFyZSBvZiBjb3Vyc2Ugc29tZSBzdWJ0bGUgYXNzdW1wdGlvbnMgdGhhdCB3ZSBuZWVkIHRvIG1ha2UgaW4gb3JkZXIgZm9yIHRoaXMgdG8gYmUgY29uc2lzdGVudCwgYnV0IHRoZXkgYXJlIG91dHNpZGUgdGhlIHNjb3BlIG9mIHRoaXMgY291cnNlLgoKTm90aWNlIHRoYXQgdGhlIGJvb3RzdHJhcCBlc3RpbWF0ZXMgYXJlIGNlbnRlcmVkIGFyb3VuZCB0aGUgZW1waXJpY2FsIG1lYW5zIG9mIHRoZSBjaG9zZW4gZGF0YXNldCwgbm90IHRoZSB0cnVlIG1lYW5zLiBGb3IgZXhhbXBsZSwgZm9yIHRoZSAkXGhhdFxiZXRhXzE9JCBgciBiYlsyLDFdYCBmb3Igb3VyIGRhdGFzZXQgYW5kIHRoaXMgaXMgd2hlcmUgYm9vdHN0cmFwIGRpc3RyaWJ1dGlvbiBmb3IgJFxoYXRcYmV0YV8xJCBpcyBjZW50ZXJlZC4gVGhpcyBpcyBsb2dpY2FsLCBhcyB0aGUgYm9vdHN0cmFwIGNhbm5vdCBtYWdpY2FsbHkgZmluZCBvdXQgdGhhdCBpdCBzaG91bGQgYmUgY2VudGVyZWQgYXJvdW5kIDMuIEhvd2V2ZXIsIHRoZSBlc3RpbWF0ZSBvZiB2YXJpYW5jZSBpcyBhdCBsZWFzdCBhcHByb3hpbWF0ZWx5IGNvcnJlY3QuIFRoZXJlZm9yZSwgd2l0aCB0aGUgYm9vdHN0cmFwIHlvdSBjYW5ub3QgbWFnaWNhbGx5IGZpbmQgdGhlICJ0cnVlIiBtZWFuIChvbmx5IHRoZSBtZWFuIG9mIHRoZSBlbXBpcmljYWwgc2FtcGxlKSwgYnV0IHlvdSBjYW4gZmluZCBhIGdvb2QgZXN0aW1hdGUgb2YgdGhlIHZhcmlhbmNlIG9mIGFuIGVzdGltYXRvci4gV2hlbiB5b3Uga25vdyB0aGUgdmFyaWFuY2UgeW91IGNhbiBmaW5kIHRoZSBjb25maWRlbmNlIGludGVydmFscyBmb3IgdGhlIGVzdGltYXRvci4gRm9yIGV4YW1wbGUgJFxwbSAxLjk2XGhhdFxzaWdtYV8xJCBjb25maWRlbmNlIGludGVydmFscyBmb3IgdGhlIHBhcmFtZXRlciAkXGhhdFxiZXRhXzE9JCBgciBiYlsyLDFdYCB3b3VsZCBiZSBnaXZlbiBieSAkWyQgYHIgYmJbMiwxXS0xLjk2KnNkKGJiYlsyLF0pYCAkLCQgYHIgYmJbMiwxXSsxLjk2KnNkKGJiYlsyLF0pYCAkXSQuIFRoZSAidHJ1ZSIgdmFsdWUgJFxiZXRhXzE9MyQgaXMgaW5kZWVkIGluc2lkZSB0aGlzIGludGVydmFsLgoKIyMgQWJvdXQgY29uZmlkZW5jZSBpbnRlcnZhbHMgYW5kIHN0YXRpc3RpY2FsIHRlc3RpbmcKCldoeSAkXHBtIDEuOTZcaGF0XHNpZ21hXzEkPyBJZiBhIHJhbmRvbSB2YXJpYWJsZSAkWCQgaXMgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgd2l0aCBtZWFuICRcbXUkIGFuZCB2YXJpYW5jZSAkXHNpZ21hJCwgdGhlbiBpdHMgdmFsdWUgaXMgd2l0aCA5NSUgcHJvYmFiaWxpdHkgaW4gdGhlIGludGVydmFsICRbXG11LTEuOTZcc2lnbWEsXG11KzEuOTZcc2lnbWFdJC4gV2UgY2FsbCB0aGlzIGludGVydmFsICo5NSUgY29uZmlkZW5jZSBpbnRlcnZhbCouCgpPZnRlbiwgYW4gaW50ZXJlc3RpbmcgcXVlc3Rpb24gaXMgaWYgdGhlIG51bGwgaHlwb3RoZXNpcyB0aGF0IGEgbGluZWFyIGNvZWZmaWNpZW50ICRcYmV0YV8xJCB2YW5pc2hlcyBjYW4gYmUgcmVqZWN0ZWQuIFdlIGNhbiByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcywgaS5lLiwgY2xhaW0gdGhhdCAkXGJldGFfMSQgcmVhbGx5IGlzIG5vbi16ZXJvLCBpZiB6ZXJvIGlzIG5vdCBpbmNsdWRlZCBpbiB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbC4gUiByZXBvcnRzIGRpcmVjdGx5IHN0YW5kYXJkIGVycm9ycyBmb3IgKGkuZS4sICQxXHNpZ21hJCBlcnJvcnMpIGZvciBsaW5lYXIgcmVncmVzc2lvbiBjb2VmZmljaWVudHMgYXMgd2VsbCBhcyBwLXZhbHVlcyBmb3IgdGhlIG51bGwgaHlwb3RoZXNpcyB0aGF0IHRoZSBjb2VmZmljaWVudCB2YW5pc2hlczoKCmBgYHtyfQpwcmludChzdW1tYXJ5KGxtKHl+eCxkYXRhLmZyYW1lKHg9eFssMV0seT15WywxXSkpKSkKYGBgCgpQbGVhc2UgcmVhZCBTZWMuIDMuMS4yIG9mIHRoZSB0ZXh0IGJvb2sgZm9yIG1vcmUgaW5mb3JtYXRpb24u