Inference for a population mean

Standard error, LLN, and CLT

  • The standard error of the mean (SEM) is the standard deviation of the sample-mean’s estimate of a population mean.
  • law of large numbers (LLN)
  • In probability theory, the central limit theorem (CLT) states that, given certain conditions, the mean of a sufficiently large number of independent random variables, each with finite mean and variance, will be approximately normally distributed
#### Illustration of Central Limit Theorem, Uniform distribution
# demo.clt.unif(N, n)
# draws N samples of size n from Uniform(0,1)
# and plots the N means with a normal distribution overlay
demo.clt.unif <- function(N, n) {
  # draw sample in a matrix with N columns and n rows
  sam <- matrix(runif(N*n, 0, 1), ncol=N);
  # calculate the mean of each column
  sam.mean <- colMeans(sam)
  # the sd of the mean is the SEM
  sam.se <- sd(sam.mean)
  # calculate the true SEM given the sample size n
  true.se <- sqrt((1/12)/n)
  # draw a histogram of the means
  hist(sam.mean, freq = FALSE, breaks = 25
      , main = paste("True SEM =", round(true.se, 4)
      , ", Est SEM = ", round( sam.se, 4))
      , xlab = paste("n =", n))
  # overlay a density curve for the sample means
  points(density(sam.mean), type = "l")
  # overlay a normal distribution, bold and red
  x <- seq(0, 1, length = 1000)
  points(x, dnorm(x, mean = 0.5, sd = true.se), type = "l", lwd = 2, col = "red")
  # place a rug of points under the plot
  rug(sam.mean)
}
Warning message:
In scan(file = file, what = what, sep = sep, quote = quote, dec = dec,  :
  EOF within quoted string
par(mfrow=c(2,2));
demo.clt.unif(10000, 1)
demo.clt.unif(10000, 2)
demo.clt.unif(10000, 6)
demo.clt.unif(10000, 12)

#### Illustration of Central Limit Theorem, Exponential distribution
# demo.clt.exp(N, n) draws N samples of size n from Exponential(1)
# and plots the N means with a normal distribution overlay
demo.clt.exp <- function(N, n) {
  # draw sample in a matrix with N columns and n rows
  sam <- matrix(rexp(N*n, 1), ncol=N);
  # calculate the mean of each column
  sam.mean <- colMeans(sam)
  # the sd of the mean is the SEM
  sam.se <- sd(sam.mean)
  # calculate the true SEM given the sample size n
  true.se <- sqrt(1/n)
  # draw a histogram of the means
  hist(sam.mean, freq = FALSE, breaks = 25
  , main = paste("True SEM =", round(true.se, 4), ", Est SEM = ", round(sam.se, 4))
  , xlab = paste("n =", n))
  # overlay a density curve for the sample means
  points(density(sam.mean), type = "l")
  # overlay a normal distribution, bold and red
  x <- seq(0, 5, length = 1000)
  points(x, dnorm(x, mean = 1, sd = true.se), type = "l", lwd = 2, col = "red")
  # place a rug of points under the plot
  rug(sam.mean)
}
par(mfrow=c(2,2));
demo.clt.exp(10000, 1)
demo.clt.exp(10000, 6)
demo.clt.exp(10000, 30)
demo.clt.exp(10000, 100)

z-score

# sample from normal distribution
df <- data.frame(x = rnorm(100, mean = 100, sd = 15))
df$z <- scale(df$x) # by default, this performs a z-score transformation
summary(df)
       x                  z.V1        
 Min.   : 72.31   Min.   :-1.8105739  
 1st Qu.: 89.45   1st Qu.:-0.6054972  
 Median : 96.72   Median :-0.0945894  
 Mean   : 98.06   Mean   : 0.0000000  
 3rd Qu.:107.72   3rd Qu.: 0.6790059  
 Max.   :138.00   Max.   : 2.8084950  
## x z.V1
## Min. : 39.64 Min. :-3.446123
## 1st Qu.: 90.99 1st Qu.:-0.485300
## Median :100.00 Median : 0.033925
## Mean : 99.41 Mean : 0.000000
## 3rd Qu.:110.72 3rd Qu.: 0.652006
## Max. :132.70 Max. : 1.919736
## ggplot
library(ggplot2)
p1 <- ggplot(df, aes(x = x))
# Histogram with density instead of count on y-axis
p1 <- p1 + geom_histogram(aes(y=..density..))
p1 <- p1 + geom_density(alpha=0.1, fill="white")
p1 <- p1 + geom_rug()
p1 <- p1 + labs(title = "X ~ Normal(100, 15)")
p2 <- ggplot(df, aes(x = z))
# Histogram with density instead of count on y-axis
p2 <- p2 + geom_histogram(aes(y=..density..))
p2 <- p2 + geom_density(alpha=0.1, fill="white")
p2 <- p2 + geom_rug()
p2 <- p2 + labs(title = "Z ~ Normal(0, 1)")
library(gridExtra)
grid.arrange(p1, p2, ncol=1)

t-distribution

The Student’s t-distribution is a family of continuous probability distributions that arises when estimating the mean of a normally distributed population in situations where the sample size is small and population standard deviation is unknown.

#### Normal vs t-distributions with a range of degrees-of-freedom
x <- seq(-8, 8, length = 1000)
par(mfrow=c(1,1))
plot(x, dnorm(x), type = "l", lwd = 2, col = "red"
, main = "Normal (red) vs t-dist with df=1, 2, 6, 12, 30, 100")
points(x, dt(x, 1), type = "l")
points(x, dt(x, 2), type = "l")
points(x, dt(x, 6), type = "l")
points(x, dt(x, 12), type = "l")
points(x, dt(x, 30), type = "l")
points(x, dt(x,100), type = "l")

CI for µ

The assumption

The procedure is based on the assumptions that the data are a random sample from the population of interest, and that the population frequency curve is normal. In fact, the assumptions are slightly looser than this, the population frequency curve can be anything provided the sample size is large enough that it’s reasonable to assume that the sampling distribution of the mean is normal. #### Assessing assumptions using the bootstrap

#### Visual comparison of whether sampling distribution is close to Normal via Bootstrap
# a function to compare the bootstrap sampling distribution with
# a normal distribution with mean and SEM estimated from the data
bs.one.samp.dist <- function(dat, N = 1e4) {
  n <- length(dat);
  # resample from data
  sam <- matrix(sample(dat, size = N * n, replace = TRUE), ncol=N);
  # draw a histogram of the means
  sam.mean <- colMeans(sam);
  # save par() settings
  old.par <- par(no.readonly = TRUE)
  # make smaller margins
  par(mfrow=c(2,1), mar=c(3,2,2,1), oma=c(1,1,1,1))
  # Histogram overlaid with kernel density curve
  hist(dat, freq = FALSE, breaks = 6
       , main = "Plot of data with smoothed density curve")
  points(density(dat), type = "l")
  rug(dat)
  hist(sam.mean, freq = FALSE, breaks = 25
       , main = "Bootstrap sampling distribution of the mean"
       , xlab = paste("Data: n =", n
       , ", mean =", signif(mean(dat), digits = 5)
       , ", se =", signif(sd(dat)/sqrt(n)), digits = 5))
       # overlay a density curve for the sample means
       points(density(sam.mean), type = "l")
  # overlay a normal distribution, bold and red
  x <- seq(min(sam.mean), max(sam.mean), length = 1000)
  points(x, dnorm(x, mean = mean(dat), sd = sd(dat)/sqrt(n))
         , type = "l", lwd = 2, col = "red")
  # place a rug of points under the plot
  rug(sam.mean)
  # restore par() settings
  par(old.par)
}
# example data, skewed --- try others datasets to develop your intuition
x <- rgamma(10, shape = .5, scale = 20)
bs.one.samp.dist(x)

Hypothesis Testing for µ

Example: Age at First Transplant

We are interested in testing H[0]: µ = 50 against H[A]: µ != 50,

#### Example: Age at First Transplant
# enter data as a vector
age <- c(54, 42, 51, 54, 49, 56, 33, 58, 54, 64, 49)
par(mfrow=c(2,1))
# Histogram overlaid with kernel density curve
hist(age, freq = FALSE, breaks = 6)
points(density(age), type = "l")
rug(age)
# violin plot
library(vioplot)
vioplot(age, horizontal=TRUE, col="gray")

# stem-and-leaf plot
# stem(age, scale=2)
# t.crit
qt(1 - 0.05/2, df = length(age) - 1)
[1] 2.228139
# defaults include: alternative = "two.sided", conf.level = 0.95
t.summary <- t.test(age, mu = 50)
t.summary

    One Sample t-test

data:  age
t = 0.51107, df = 10, p-value = 0.6204
alternative hypothesis: true mean is not equal to 50
95 percent confidence interval:
 45.72397 56.82149
sample estimates:
mean of x 
 51.27273 
names(t.summary)
[1] "statistic"   "parameter"   "p.value"     "conf.int"    "estimate"    "null.value" 
[7] "alternative" "method"      "data.name"  
# the assumption of normality of the sampling distribution appears reasonablly close
bs.one.samp.dist(age)

# Function ot plot t-distribution with shaded p-value
t.dist.pval <- function(t.summary) {
  par(mfrow=c(1,1))
  lim.extreme <- max(4, abs(t.summary$statistic) + 0.5)
  lim.lower <- -lim.extreme;
  lim.upper <-  lim.extreme;
  x.curve <- seq(lim.lower, lim.upper, length=200)
  y.curve <- dt(x.curve, df = t.summary$parameter)
  plot(x.curve, y.curve, type = "n"
      , ylab = paste("t-dist( df =", signif(t.summary$parameter, 3), ")")
      , xlab = paste("t-stat =", signif(t.summary$statistic, 5)
                   , ", Shaded area is p-value =", signif(t.summary$p.value, 5)))
  if ((t.summary$alternative == "less")
      | (t.summary$alternative == "two.sided")) {
    x.pval.l <- seq(lim.lower, -abs(t.summary$statistic), length=200)
    y.pval.l <- dt(x.pval.l, df = t.summary$parameter)
    polygon(c(lim.lower, x.pval.l, -abs(t.summary$statistic))
          , c(0, y.pval.l, 0), col="gray")
  }
  if ((t.summary$alternative == "greater")
      | (t.summary$alternative == "two.sided")) {
    x.pval.u <- seq(abs(t.summary$statistic), lim.upper, length=200)
    y.pval.u <- dt(x.pval.u, df = t.summary$parameter)
    polygon(c(abs(t.summary$statistic), x.pval.u, lim.upper)
          , c(0, y.pval.u, 0), col="gray")
  }
  points(x.curve, y.curve, type = "l", lwd = 2, col = "black")
}
# for the age example
t.dist.pval(t.summary)

Design issues and power

The power of a test is the probability of correctly rejecting H0 when it is false. Equivalently, power = 1 − Prob( failing to reject H[0] when it is false ) = 1 − Prob( Type-II error ).

#### Power calculations (that you can do on your own)
toco <- c(5.6, 2.7, 6.2, 2.9, 1.5, 4.0, 4.3, 3.0, 3.6, 2.4, 6.7, 3.8)
library(pwr)
power.t.test(n = NULL, delta = 1.00 - 0.54, sd = sd(toco)
             , sig.level = 0.05, power = 0.50
             , type = "one.sample", alternative = "two.sided")

     One-sample t test power calculation 

              n = 47.4122
          delta = 0.46
             sd = 1.582552
      sig.level = 0.05
          power = 0.5
    alternative = two.sided
power.t.test(n = NULL, delta = 0.75 - 0.54, sd = sd(toco)
             , sig.level = 0.05, power = 0.50
             , type = "one.sample", alternative = "two.sided")

     One-sample t test power calculation 

              n = 220.0851
          delta = 0.21
             sd = 1.582552
      sig.level = 0.05
          power = 0.5
    alternative = two.sided
LS0tCnRpdGxlOiAiRXN0aW1hdGlvbiBpbiBPbmUtU2FtcGxlIFByb2JsZW1zIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6IAogICAgdG9jOiB5ZXMKLS0tCgojIyMgSW5mZXJlbmNlIGZvciBhIHBvcHVsYXRpb24gbWVhbgojIyMjIFN0YW5kYXJkIGVycm9yLCBMTE4sIGFuZCBDTFQKKiBUaGUgc3RhbmRhcmQgZXJyb3Igb2YgdGhlIG1lYW4gKFNFTSkgaXMgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgc2FtcGxlLW1lYW7igJlzIGVzdGltYXRlIG9mIGEgcG9wdWxhdGlvbiBtZWFuLgoqIGxhdyBvZiBsYXJnZSBudW1iZXJzIChMTE4pCiogSW4gcHJvYmFiaWxpdHkgdGhlb3J5LCB0aGUgY2VudHJhbCBsaW1pdCB0aGVvcmVtIChDTFQpIHN0YXRlcyB0aGF0LCBnaXZlbiBjZXJ0YWluIGNvbmRpdGlvbnMsIHRoZSBtZWFuIG9mIGEgc3VmZmljaWVudGx5IGxhcmdlIG51bWJlciBvZiBpbmRlcGVuZGVudCByYW5kb20gdmFyaWFibGVzLCBlYWNoIHdpdGggZmluaXRlIG1lYW4gYW5kIHZhcmlhbmNlLCB3aWxsIGJlIGFwcHJveGltYXRlbHkgbm9ybWFsbHkgZGlzdHJpYnV0ZWQKYGBge3J9CiMjIyMgSWxsdXN0cmF0aW9uIG9mIENlbnRyYWwgTGltaXQgVGhlb3JlbSwgVW5pZm9ybSBkaXN0cmlidXRpb24KIyBkZW1vLmNsdC51bmlmKE4sIG4pCiMgZHJhd3MgTiBzYW1wbGVzIG9mIHNpemUgbiBmcm9tIFVuaWZvcm0oMCwxKQojIGFuZCBwbG90cyB0aGUgTiBtZWFucyB3aXRoIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiBvdmVybGF5CmRlbW8uY2x0LnVuaWYgPC0gZnVuY3Rpb24oTiwgbikgewogICMgZHJhdyBzYW1wbGUgaW4gYSBtYXRyaXggd2l0aCBOIGNvbHVtbnMgYW5kIG4gcm93cwogIHNhbSA8LSBtYXRyaXgocnVuaWYoTipuLCAwLCAxKSwgbmNvbD1OKTsKICAjIGNhbGN1bGF0ZSB0aGUgbWVhbiBvZiBlYWNoIGNvbHVtbgogIHNhbS5tZWFuIDwtIGNvbE1lYW5zKHNhbSkKICAjIHRoZSBzZCBvZiB0aGUgbWVhbiBpcyB0aGUgU0VNCiAgc2FtLnNlIDwtIHNkKHNhbS5tZWFuKQogICMgY2FsY3VsYXRlIHRoZSB0cnVlIFNFTSBnaXZlbiB0aGUgc2FtcGxlIHNpemUgbgogIHRydWUuc2UgPC0gc3FydCgoMS8xMikvbikKICAjIGRyYXcgYSBoaXN0b2dyYW0gb2YgdGhlIG1lYW5zCiAgaGlzdChzYW0ubWVhbiwgZnJlcSA9IEZBTFNFLCBicmVha3MgPSAyNQogICAgICAsIG1haW4gPSBwYXN0ZSgiVHJ1ZSBTRU0gPSIsIHJvdW5kKHRydWUuc2UsIDQpCiAgICAgICwgIiwgRXN0IFNFTSA9ICIsIHJvdW5kKCBzYW0uc2UsIDQpKQogICAgICAsIHhsYWIgPSBwYXN0ZSgibiA9IiwgbikpCiAgIyBvdmVybGF5IGEgZGVuc2l0eSBjdXJ2ZSBmb3IgdGhlIHNhbXBsZSBtZWFucwogIHBvaW50cyhkZW5zaXR5KHNhbS5tZWFuKSwgdHlwZSA9ICJsIikKICAjIG92ZXJsYXkgYSBub3JtYWwgZGlzdHJpYnV0aW9uLCBib2xkIGFuZCByZWQKICB4IDwtIHNlcSgwLCAxLCBsZW5ndGggPSAxMDAwKQogIHBvaW50cyh4LCBkbm9ybSh4LCBtZWFuID0gMC41LCBzZCA9IHRydWUuc2UpLCB0eXBlID0gImwiLCBsd2QgPSAyLCBjb2wgPSAicmVkIikKICAjIHBsYWNlIGEgcnVnIG9mIHBvaW50cyB1bmRlciB0aGUgcGxvdAogIHJ1ZyhzYW0ubWVhbikKfQpwYXIobWZyb3c9YygyLDIpKTsKZGVtby5jbHQudW5pZigxMDAwMCwgMSkKZGVtby5jbHQudW5pZigxMDAwMCwgMikKZGVtby5jbHQudW5pZigxMDAwMCwgNikKZGVtby5jbHQudW5pZigxMDAwMCwgMTIpCmBgYAoKYGBge3J9CiMjIyMgSWxsdXN0cmF0aW9uIG9mIENlbnRyYWwgTGltaXQgVGhlb3JlbSwgRXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uCiMgZGVtby5jbHQuZXhwKE4sIG4pIGRyYXdzIE4gc2FtcGxlcyBvZiBzaXplIG4gZnJvbSBFeHBvbmVudGlhbCgxKQojIGFuZCBwbG90cyB0aGUgTiBtZWFucyB3aXRoIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiBvdmVybGF5CmRlbW8uY2x0LmV4cCA8LSBmdW5jdGlvbihOLCBuKSB7CiAgIyBkcmF3IHNhbXBsZSBpbiBhIG1hdHJpeCB3aXRoIE4gY29sdW1ucyBhbmQgbiByb3dzCiAgc2FtIDwtIG1hdHJpeChyZXhwKE4qbiwgMSksIG5jb2w9Tik7CiAgIyBjYWxjdWxhdGUgdGhlIG1lYW4gb2YgZWFjaCBjb2x1bW4KICBzYW0ubWVhbiA8LSBjb2xNZWFucyhzYW0pCiAgIyB0aGUgc2Qgb2YgdGhlIG1lYW4gaXMgdGhlIFNFTQogIHNhbS5zZSA8LSBzZChzYW0ubWVhbikKICAjIGNhbGN1bGF0ZSB0aGUgdHJ1ZSBTRU0gZ2l2ZW4gdGhlIHNhbXBsZSBzaXplIG4KICB0cnVlLnNlIDwtIHNxcnQoMS9uKQogICMgZHJhdyBhIGhpc3RvZ3JhbSBvZiB0aGUgbWVhbnMKICBoaXN0KHNhbS5tZWFuLCBmcmVxID0gRkFMU0UsIGJyZWFrcyA9IDI1CiAgLCBtYWluID0gcGFzdGUoIlRydWUgU0VNID0iLCByb3VuZCh0cnVlLnNlLCA0KSwgIiwgRXN0IFNFTSA9ICIsIHJvdW5kKHNhbS5zZSwgNCkpCiAgLCB4bGFiID0gcGFzdGUoIm4gPSIsIG4pKQogICMgb3ZlcmxheSBhIGRlbnNpdHkgY3VydmUgZm9yIHRoZSBzYW1wbGUgbWVhbnMKICBwb2ludHMoZGVuc2l0eShzYW0ubWVhbiksIHR5cGUgPSAibCIpCiAgIyBvdmVybGF5IGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiwgYm9sZCBhbmQgcmVkCiAgeCA8LSBzZXEoMCwgNSwgbGVuZ3RoID0gMTAwMCkKICBwb2ludHMoeCwgZG5vcm0oeCwgbWVhbiA9IDEsIHNkID0gdHJ1ZS5zZSksIHR5cGUgPSAibCIsIGx3ZCA9IDIsIGNvbCA9ICJyZWQiKQogICMgcGxhY2UgYSBydWcgb2YgcG9pbnRzIHVuZGVyIHRoZSBwbG90CiAgcnVnKHNhbS5tZWFuKQp9CnBhcihtZnJvdz1jKDIsMikpOwpkZW1vLmNsdC5leHAoMTAwMDAsIDEpCmRlbW8uY2x0LmV4cCgxMDAwMCwgNikKZGVtby5jbHQuZXhwKDEwMDAwLCAzMCkKZGVtby5jbHQuZXhwKDEwMDAwLCAxMDApCmBgYAoKIyMjIHotc2NvcmUKYGBge3J9CiMgc2FtcGxlIGZyb20gbm9ybWFsIGRpc3RyaWJ1dGlvbgpkZiA8LSBkYXRhLmZyYW1lKHggPSBybm9ybSgxMDAsIG1lYW4gPSAxMDAsIHNkID0gMTUpKQpkZiR6IDwtIHNjYWxlKGRmJHgpICMgYnkgZGVmYXVsdCwgdGhpcyBwZXJmb3JtcyBhIHotc2NvcmUgdHJhbnNmb3JtYXRpb24Kc3VtbWFyeShkZikKIyMgeCB6LlYxCiMjIE1pbi4gOiAzOS42NCBNaW4uIDotMy40NDYxMjMKIyMgMXN0IFF1LjogOTAuOTkgMXN0IFF1LjotMC40ODUzMDAKIyMgTWVkaWFuIDoxMDAuMDAgTWVkaWFuIDogMC4wMzM5MjUKIyMgTWVhbiA6IDk5LjQxIE1lYW4gOiAwLjAwMDAwMAojIyAzcmQgUXUuOjExMC43MiAzcmQgUXUuOiAwLjY1MjAwNgojIyBNYXguIDoxMzIuNzAgTWF4LiA6IDEuOTE5NzM2CiMjIGdncGxvdApsaWJyYXJ5KGdncGxvdDIpCnAxIDwtIGdncGxvdChkZiwgYWVzKHggPSB4KSkKIyBIaXN0b2dyYW0gd2l0aCBkZW5zaXR5IGluc3RlYWQgb2YgY291bnQgb24geS1heGlzCnAxIDwtIHAxICsgZ2VvbV9oaXN0b2dyYW0oYWVzKHk9Li5kZW5zaXR5Li4pKQpwMSA8LSBwMSArIGdlb21fZGVuc2l0eShhbHBoYT0wLjEsIGZpbGw9IndoaXRlIikKcDEgPC0gcDEgKyBnZW9tX3J1ZygpCnAxIDwtIHAxICsgbGFicyh0aXRsZSA9ICJYIH4gTm9ybWFsKDEwMCwgMTUpIikKcDIgPC0gZ2dwbG90KGRmLCBhZXMoeCA9IHopKQojIEhpc3RvZ3JhbSB3aXRoIGRlbnNpdHkgaW5zdGVhZCBvZiBjb3VudCBvbiB5LWF4aXMKcDIgPC0gcDIgKyBnZW9tX2hpc3RvZ3JhbShhZXMoeT0uLmRlbnNpdHkuLikpCnAyIDwtIHAyICsgZ2VvbV9kZW5zaXR5KGFscGhhPTAuMSwgZmlsbD0id2hpdGUiKQpwMiA8LSBwMiArIGdlb21fcnVnKCkKcDIgPC0gcDIgKyBsYWJzKHRpdGxlID0gIlogfiBOb3JtYWwoMCwgMSkiKQpsaWJyYXJ5KGdyaWRFeHRyYSkKZ3JpZC5hcnJhbmdlKHAxLCBwMiwgbmNvbD0xKQpgYGAKCiMjIyB0LWRpc3RyaWJ1dGlvbgpUaGUgU3R1ZGVudOKAmXMgdC1kaXN0cmlidXRpb24gaXMgYSBmYW1pbHkgb2YgY29udGludW91cyBwcm9iYWJpbGl0eSBkaXN0cmlidXRpb25zIHRoYXQgYXJpc2VzIHdoZW4gZXN0aW1hdGluZyB0aGUgbWVhbiBvZiBhIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIHBvcHVsYXRpb24gaW4gc2l0dWF0aW9ucyB3aGVyZSB0aGUgc2FtcGxlIHNpemUgaXMgc21hbGwgYW5kIHBvcHVsYXRpb24gc3RhbmRhcmQgZGV2aWF0aW9uIGlzIHVua25vd24uIApgYGB7cn0KIyMjIyBOb3JtYWwgdnMgdC1kaXN0cmlidXRpb25zIHdpdGggYSByYW5nZSBvZiBkZWdyZWVzLW9mLWZyZWVkb20KeCA8LSBzZXEoLTgsIDgsIGxlbmd0aCA9IDEwMDApCnBhcihtZnJvdz1jKDEsMSkpCnBsb3QoeCwgZG5vcm0oeCksIHR5cGUgPSAibCIsIGx3ZCA9IDIsIGNvbCA9ICJyZWQiCiwgbWFpbiA9ICJOb3JtYWwgKHJlZCkgdnMgdC1kaXN0IHdpdGggZGY9MSwgMiwgNiwgMTIsIDMwLCAxMDAiKQpwb2ludHMoeCwgZHQoeCwgMSksIHR5cGUgPSAibCIpCnBvaW50cyh4LCBkdCh4LCAyKSwgdHlwZSA9ICJsIikKcG9pbnRzKHgsIGR0KHgsIDYpLCB0eXBlID0gImwiKQpwb2ludHMoeCwgZHQoeCwgMTIpLCB0eXBlID0gImwiKQpwb2ludHMoeCwgZHQoeCwgMzApLCB0eXBlID0gImwiKQpwb2ludHMoeCwgZHQoeCwxMDApLCB0eXBlID0gImwiKQpgYGAKCiMjIyBDSSBmb3IgwrUKIyMjIyBUaGUgYXNzdW1wdGlvbgpUaGUgcHJvY2VkdXJlIGlzIGJhc2VkIG9uIHRoZSBhc3N1bXB0aW9ucyB0aGF0IHRoZSBkYXRhIGFyZSBhIHJhbmRvbSBzYW1wbGUgZnJvbSB0aGUgcG9wdWxhdGlvbiBvZiBpbnRlcmVzdCwgYW5kIHRoYXQgdGhlIHBvcHVsYXRpb24gZnJlcXVlbmN5IGN1cnZlIGlzIG5vcm1hbC4KSW4gZmFjdCwgdGhlIGFzc3VtcHRpb25zIGFyZSBzbGlnaHRseSBsb29zZXIgdGhhbiB0aGlzLCB0aGUgcG9wdWxhdGlvbiBmcmVxdWVuY3kgY3VydmUgY2FuIGJlIGFueXRoaW5nIHByb3ZpZGVkIHRoZSBzYW1wbGUgc2l6ZSBpcyBsYXJnZSBlbm91Z2ggdGhhdCBpdOKAmXMgcmVhc29uYWJsZSB0byBhc3N1bWUgdGhhdCB0aGUgc2FtcGxpbmcgZGlzdHJpYnV0aW9uIG9mIHRoZSBtZWFuIGlzIG5vcm1hbC4KIyMjIyBBc3Nlc3NpbmcgYXNzdW1wdGlvbnMgdXNpbmcgdGhlIGJvb3RzdHJhcApgYGB7cn0KIyMjIyBWaXN1YWwgY29tcGFyaXNvbiBvZiB3aGV0aGVyIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbiBpcyBjbG9zZSB0byBOb3JtYWwgdmlhIEJvb3RzdHJhcAojIGEgZnVuY3Rpb24gdG8gY29tcGFyZSB0aGUgYm9vdHN0cmFwIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbiB3aXRoCiMgYSBub3JtYWwgZGlzdHJpYnV0aW9uIHdpdGggbWVhbiBhbmQgU0VNIGVzdGltYXRlZCBmcm9tIHRoZSBkYXRhCmJzLm9uZS5zYW1wLmRpc3QgPC0gZnVuY3Rpb24oZGF0LCBOID0gMWU0KSB7CiAgbiA8LSBsZW5ndGgoZGF0KTsKICAjIHJlc2FtcGxlIGZyb20gZGF0YQogIHNhbSA8LSBtYXRyaXgoc2FtcGxlKGRhdCwgc2l6ZSA9IE4gKiBuLCByZXBsYWNlID0gVFJVRSksIG5jb2w9Tik7CiAgIyBkcmF3IGEgaGlzdG9ncmFtIG9mIHRoZSBtZWFucwogIHNhbS5tZWFuIDwtIGNvbE1lYW5zKHNhbSk7CiAgIyBzYXZlIHBhcigpIHNldHRpbmdzCiAgb2xkLnBhciA8LSBwYXIobm8ucmVhZG9ubHkgPSBUUlVFKQogICMgbWFrZSBzbWFsbGVyIG1hcmdpbnMKICBwYXIobWZyb3c9YygyLDEpLCBtYXI9YygzLDIsMiwxKSwgb21hPWMoMSwxLDEsMSkpCiAgIyBIaXN0b2dyYW0gb3ZlcmxhaWQgd2l0aCBrZXJuZWwgZGVuc2l0eSBjdXJ2ZQogIGhpc3QoZGF0LCBmcmVxID0gRkFMU0UsIGJyZWFrcyA9IDYKICAgICAgICwgbWFpbiA9ICJQbG90IG9mIGRhdGEgd2l0aCBzbW9vdGhlZCBkZW5zaXR5IGN1cnZlIikKICBwb2ludHMoZGVuc2l0eShkYXQpLCB0eXBlID0gImwiKQogIHJ1ZyhkYXQpCiAgaGlzdChzYW0ubWVhbiwgZnJlcSA9IEZBTFNFLCBicmVha3MgPSAyNQogICAgICAgLCBtYWluID0gIkJvb3RzdHJhcCBzYW1wbGluZyBkaXN0cmlidXRpb24gb2YgdGhlIG1lYW4iCiAgICAgICAsIHhsYWIgPSBwYXN0ZSgiRGF0YTogbiA9IiwgbgogICAgICAgLCAiLCBtZWFuID0iLCBzaWduaWYobWVhbihkYXQpLCBkaWdpdHMgPSA1KQogICAgICAgLCAiLCBzZSA9Iiwgc2lnbmlmKHNkKGRhdCkvc3FydChuKSksIGRpZ2l0cyA9IDUpKQogICAgICAgIyBvdmVybGF5IGEgZGVuc2l0eSBjdXJ2ZSBmb3IgdGhlIHNhbXBsZSBtZWFucwogICAgICAgcG9pbnRzKGRlbnNpdHkoc2FtLm1lYW4pLCB0eXBlID0gImwiKQogICMgb3ZlcmxheSBhIG5vcm1hbCBkaXN0cmlidXRpb24sIGJvbGQgYW5kIHJlZAogIHggPC0gc2VxKG1pbihzYW0ubWVhbiksIG1heChzYW0ubWVhbiksIGxlbmd0aCA9IDEwMDApCiAgcG9pbnRzKHgsIGRub3JtKHgsIG1lYW4gPSBtZWFuKGRhdCksIHNkID0gc2QoZGF0KS9zcXJ0KG4pKQogICAgICAgICAsIHR5cGUgPSAibCIsIGx3ZCA9IDIsIGNvbCA9ICJyZWQiKQogICMgcGxhY2UgYSBydWcgb2YgcG9pbnRzIHVuZGVyIHRoZSBwbG90CiAgcnVnKHNhbS5tZWFuKQogICMgcmVzdG9yZSBwYXIoKSBzZXR0aW5ncwogIHBhcihvbGQucGFyKQp9CiMgZXhhbXBsZSBkYXRhLCBza2V3ZWQgLS0tIHRyeSBvdGhlcnMgZGF0YXNldHMgdG8gZGV2ZWxvcCB5b3VyIGludHVpdGlvbgp4IDwtIHJnYW1tYSgxMCwgc2hhcGUgPSAuNSwgc2NhbGUgPSAyMCkKYnMub25lLnNhbXAuZGlzdCh4KQpgYGAKCiMjIyBIeXBvdGhlc2lzIFRlc3RpbmcgZm9yIMK1CiMjIyMgRXhhbXBsZTogQWdlIGF0IEZpcnN0IFRyYW5zcGxhbnQgCldlIGFyZSBpbnRlcmVzdGVkIGluIHRlc3RpbmcgSFswXTogwrUgPSA1MCBhZ2FpbnN0IEhbQV06IMK1ICE9IDUwLApgYGB7cn0KIyMjIyBFeGFtcGxlOiBBZ2UgYXQgRmlyc3QgVHJhbnNwbGFudAojIGVudGVyIGRhdGEgYXMgYSB2ZWN0b3IKYWdlIDwtIGMoNTQsIDQyLCA1MSwgNTQsIDQ5LCA1NiwgMzMsIDU4LCA1NCwgNjQsIDQ5KQpwYXIobWZyb3c9YygyLDEpKQojIEhpc3RvZ3JhbSBvdmVybGFpZCB3aXRoIGtlcm5lbCBkZW5zaXR5IGN1cnZlCmhpc3QoYWdlLCBmcmVxID0gRkFMU0UsIGJyZWFrcyA9IDYpCnBvaW50cyhkZW5zaXR5KGFnZSksIHR5cGUgPSAibCIpCnJ1ZyhhZ2UpCiMgdmlvbGluIHBsb3QKbGlicmFyeSh2aW9wbG90KQp2aW9wbG90KGFnZSwgaG9yaXpvbnRhbD1UUlVFLCBjb2w9ImdyYXkiKQpgYGAKCmBgYHtyfQojIHN0ZW0tYW5kLWxlYWYgcGxvdAojIHN0ZW0oYWdlLCBzY2FsZT0yKQojIHQuY3JpdApxdCgxIC0gMC4wNS8yLCBkZiA9IGxlbmd0aChhZ2UpIC0gMSkKIyBkZWZhdWx0cyBpbmNsdWRlOiBhbHRlcm5hdGl2ZSA9ICJ0d28uc2lkZWQiLCBjb25mLmxldmVsID0gMC45NQp0LnN1bW1hcnkgPC0gdC50ZXN0KGFnZSwgbXUgPSA1MCkKdC5zdW1tYXJ5Cm5hbWVzKHQuc3VtbWFyeSkKIyB0aGUgYXNzdW1wdGlvbiBvZiBub3JtYWxpdHkgb2YgdGhlIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbiBhcHBlYXJzIHJlYXNvbmFibGx5IGNsb3NlCmJzLm9uZS5zYW1wLmRpc3QoYWdlKQpgYGAKCmBgYHtyfQojIEZ1bmN0aW9uIG90IHBsb3QgdC1kaXN0cmlidXRpb24gd2l0aCBzaGFkZWQgcC12YWx1ZQp0LmRpc3QucHZhbCA8LSBmdW5jdGlvbih0LnN1bW1hcnkpIHsKICBwYXIobWZyb3c9YygxLDEpKQogIGxpbS5leHRyZW1lIDwtIG1heCg0LCBhYnModC5zdW1tYXJ5JHN0YXRpc3RpYykgKyAwLjUpCiAgbGltLmxvd2VyIDwtIC1saW0uZXh0cmVtZTsKICBsaW0udXBwZXIgPC0gIGxpbS5leHRyZW1lOwogIHguY3VydmUgPC0gc2VxKGxpbS5sb3dlciwgbGltLnVwcGVyLCBsZW5ndGg9MjAwKQogIHkuY3VydmUgPC0gZHQoeC5jdXJ2ZSwgZGYgPSB0LnN1bW1hcnkkcGFyYW1ldGVyKQogIHBsb3QoeC5jdXJ2ZSwgeS5jdXJ2ZSwgdHlwZSA9ICJuIgogICAgICAsIHlsYWIgPSBwYXN0ZSgidC1kaXN0KCBkZiA9Iiwgc2lnbmlmKHQuc3VtbWFyeSRwYXJhbWV0ZXIsIDMpLCAiKSIpCiAgICAgICwgeGxhYiA9IHBhc3RlKCJ0LXN0YXQgPSIsIHNpZ25pZih0LnN1bW1hcnkkc3RhdGlzdGljLCA1KQogICAgICAgICAgICAgICAgICAgLCAiLCBTaGFkZWQgYXJlYSBpcyBwLXZhbHVlID0iLCBzaWduaWYodC5zdW1tYXJ5JHAudmFsdWUsIDUpKSkKICBpZiAoKHQuc3VtbWFyeSRhbHRlcm5hdGl2ZSA9PSAibGVzcyIpCiAgICAgIHwgKHQuc3VtbWFyeSRhbHRlcm5hdGl2ZSA9PSAidHdvLnNpZGVkIikpIHsKICAgIHgucHZhbC5sIDwtIHNlcShsaW0ubG93ZXIsIC1hYnModC5zdW1tYXJ5JHN0YXRpc3RpYyksIGxlbmd0aD0yMDApCiAgICB5LnB2YWwubCA8LSBkdCh4LnB2YWwubCwgZGYgPSB0LnN1bW1hcnkkcGFyYW1ldGVyKQogICAgcG9seWdvbihjKGxpbS5sb3dlciwgeC5wdmFsLmwsIC1hYnModC5zdW1tYXJ5JHN0YXRpc3RpYykpCiAgICAgICAgICAsIGMoMCwgeS5wdmFsLmwsIDApLCBjb2w9ImdyYXkiKQogIH0KICBpZiAoKHQuc3VtbWFyeSRhbHRlcm5hdGl2ZSA9PSAiZ3JlYXRlciIpCiAgICAgIHwgKHQuc3VtbWFyeSRhbHRlcm5hdGl2ZSA9PSAidHdvLnNpZGVkIikpIHsKICAgIHgucHZhbC51IDwtIHNlcShhYnModC5zdW1tYXJ5JHN0YXRpc3RpYyksIGxpbS51cHBlciwgbGVuZ3RoPTIwMCkKICAgIHkucHZhbC51IDwtIGR0KHgucHZhbC51LCBkZiA9IHQuc3VtbWFyeSRwYXJhbWV0ZXIpCiAgICBwb2x5Z29uKGMoYWJzKHQuc3VtbWFyeSRzdGF0aXN0aWMpLCB4LnB2YWwudSwgbGltLnVwcGVyKQogICAgICAgICAgLCBjKDAsIHkucHZhbC51LCAwKSwgY29sPSJncmF5IikKICB9CiAgcG9pbnRzKHguY3VydmUsIHkuY3VydmUsIHR5cGUgPSAibCIsIGx3ZCA9IDIsIGNvbCA9ICJibGFjayIpCn0KCiMgZm9yIHRoZSBhZ2UgZXhhbXBsZQp0LmRpc3QucHZhbCh0LnN1bW1hcnkpCmBgYAoKIyMjIERlc2lnbiBpc3N1ZXMgYW5kIHBvd2VyClRoZSBwb3dlciBvZiBhIHRlc3QgaXMgdGhlIHByb2JhYmlsaXR5IG9mIGNvcnJlY3RseSByZWplY3RpbmcgSDAgd2hlbiBpdCBpcyBmYWxzZS4gRXF1aXZhbGVudGx5LApwb3dlciA9IDEg4oiSIFByb2IoIGZhaWxpbmcgdG8gcmVqZWN0IEhbMF0gd2hlbiBpdCBpcyBmYWxzZSApID0gMSDiiJIgUHJvYiggVHlwZS1JSSBlcnJvciApLgpgYGB7cn0KIyMjIyBQb3dlciBjYWxjdWxhdGlvbnMgKHRoYXQgeW91IGNhbiBkbyBvbiB5b3VyIG93bikKdG9jbyA8LSBjKDUuNiwgMi43LCA2LjIsIDIuOSwgMS41LCA0LjAsIDQuMywgMy4wLCAzLjYsIDIuNCwgNi43LCAzLjgpCmxpYnJhcnkocHdyKQpwb3dlci50LnRlc3QobiA9IE5VTEwsIGRlbHRhID0gMS4wMCAtIDAuNTQsIHNkID0gc2QodG9jbykKICAgICAgICAgICAgICwgc2lnLmxldmVsID0gMC4wNSwgcG93ZXIgPSAwLjUwCiAgICAgICAgICAgICAsIHR5cGUgPSAib25lLnNhbXBsZSIsIGFsdGVybmF0aXZlID0gInR3by5zaWRlZCIpCnBvd2VyLnQudGVzdChuID0gTlVMTCwgZGVsdGEgPSAwLjc1IC0gMC41NCwgc2QgPSBzZCh0b2NvKQogICAgICAgICAgICAgLCBzaWcubGV2ZWwgPSAwLjA1LCBwb3dlciA9IDAuNTAKICAgICAgICAgICAgICwgdHlwZSA9ICJvbmUuc2FtcGxlIiwgYWx0ZXJuYXRpdmUgPSAidHdvLnNpZGVkIikKYGBgCgo=