Simulations in R
set.seed(1)
n <- 100
x <- rnorm(n)
hist(x, freq = FALSE, col = "chartreuse3", xlim = c(-3, 3),
main = paste("Histogram of random sample \n from standard Normal distribution, n = ", n))
# Overlay standard normal curve
curve(dnorm(x), add = TRUE, col = "blue", lwd = 2)
# Add line denoting sample mean
abline(v = round(mean(x), 3), col = "red", lwd = 2, lty = 2)

set.seed(1)
n <- 5 # Specify sample size
x <- rnorm(n) # Randomly generate ns samples from the normal distribution
norm_mean <- mean(x) # Compute the mean of the samples, and store it in a new object
#Specify sample size
ns <- 5
# Specify number of times to conduct process
trials <- 10000
# create object in which to store sample means once they are generated
norm.means <- rep(0, trials) # Note length is equal to the number of trials
# Run for loop
for(i in 1:trials){
# Randomly generate ns samples from the normal distribution
x <- rnorm(ns)
# Compute mean of samples, and store it in the norm.means object, in ith position
norm.means[i] <- mean(x)
}
hist(norm.means, freq = FALSE, breaks = 20, col = "red",
xlim = c(-3, 3),
xlab = expression(bar(x)),
main = paste("Histogram of means, n = ", ns))
curve(dnorm(x,
mean = 0, sd = 1/sqrt(ns)),
add = TRUE, col = "blue", lwd = 2)

The simulated sample means are centred on the population mean of 0, but do display some variance.
#Specify sample size
ns <- 30
# Specify number of times to conduct process
trials <- 10000
# create object in which to store sample means once they are generated
norm.means <- rep(0, trials) # Note length is equal to the number of trials
# Run for loop
for(i in 1:trials){
# Randomly generate ns samples from the normal distribution
x <- rnorm(ns)
# Compute mean of samples, and store it in the norm.means object, in ith position
norm.means[i] <- mean(x)
}
hist(norm.means, freq = FALSE, breaks = 20, col = "red",
xlim = c(-3, 3),
xlab = expression(bar(x)),
main = paste("Histogram of means, n = ", ns))
curve(dnorm(x,
mean = 0, sd = 1/sqrt(ns)),
add = TRUE, col = "blue", lwd = 2)

As we increase the sample size, the variance of the sample means decreases.
#Specify sample size
ns <- 60
# Specify number of times to conduct process
trials <- 10000
# create object in which to store sample means once they are generated
norm.means <- rep(0, trials) # Note length is equal to the number of trials
# Run for loop
for(i in 1:trials){
# Randomly generate ns samples from the normal distribution
x <- rnorm(ns)
# Compute mean of samples, and store it in the norm.means object, in ith position
norm.means[i] <- mean(x)
}
hist(norm.means, freq = FALSE, breaks = 20, col = "red",
xlim = c(-3, 3),
xlab = expression(bar(x)),
main = paste("Histogram of means, n = ", ns))
curve(dnorm(x,
mean = 0, sd = 1/sqrt(ns)),
add = TRUE, col = "blue", lwd = 2)

For a sample size of 60, the variance of the sample means is very low, providing us with an accurate estimate of the population mean.
CLT Simulation - Exponential Distribution
set.seed(1)
n <- 100
rate = 10
x <- rexp(n, rate = rate)
hist(x, freq = FALSE, col = "chartreuse3", xlim = c(0, 0.5),
main = paste("Histogram of random sample \n from Exponential distribution, n = ", n))
curve(dnorm(x, 1/rate, 1/rate), add = TRUE, col = "blue", lwd = 2)

#Specify sample size
ns <- 5
# Specify rate
rate = 10
# Specify number of times to conduct process
trials <- 10000
# create object in which to store sample means once they are generated
norm.means <- rep(0, trials) # Note length is equal to the number of trials
# Run for loop
for(i in 1:trials){
# Randomly generate ns samples from the exponential distribution
x <- rexp(ns, rate = rate)
# Compute mean of samples, and store it in the norm.means object, in ith position
norm.means[i] <- mean(x)
}
hist(norm.means, freq = FALSE, breaks = 20, col = "red",
xlim = c(0, 0.4),
xlab = expression(bar(x)),
main = paste("Histogram of means, n = ", ns))
curve(dnorm(x, mean = 1/rate, sd = 1/rate/sqrt(ns)), add = TRUE,
col = "blue", lwd = 2)

Here we use an x-axis range of 0 to 0.4.
The resulting data set is not as skewed as the underlying distribution, but there is still a noticeable skew (this is because of the low sample size).
#Specify sample size
ns <- 30
# Specify rate
rate = 10
# Specify number of times to conduct process
trials <- 10000
# create object in which to store sample means once they are generated
norm.means <- rep(0, trials) # Note length is equal to the number of trials
# Run for loop
for(i in 1:trials){
# Randomly generate ns samples from the exponential distribution
x <- rexp(ns, rate = rate)
# Compute mean of samples, and store it in the norm.means object, in ith position
norm.means[i] <- mean(x)
}
hist(norm.means, freq = FALSE, breaks = 20, col = "red",
xlim = c(0, 0.2),
xlab = expression(bar(x)),
main = paste("Histogram of means, n = ", ns))
curve(dnorm(x, mean = 1/rate, sd = 1/rate/sqrt(ns)), add = TRUE,
col = "blue", lwd = 2)

Here, we change the x axis range to be from 0 to 0.2. The sample means now display very little variance, and provide a much more accurate estimate of the population mean of 0.1. Note that the Normal density curve also fits the data well. These results are due to the sample size being bigger (30 instead of 5).
#Specify sample size
ns <- 60
# Specify rate
rate = 10
# Specify number of times to conduct process
trials <- 10000
# create object in which to store sample means once they are generated
norm.means <- rep(0, trials) # Note length is equal to the number of trials
# Run for loop
for(i in 1:trials){
# Randomly generate ns samples from the exponential distribution
x <- rexp(ns, rate = rate)
# Compute mean of samples, and store it in the norm.means object, in ith position
norm.means[i] <- mean(x)
}
hist(norm.means, freq = FALSE, breaks = 20, col = "red",
xlim = c(0, 0.2),
xlab = expression(bar(x)),
main = paste("Histogram of means, n = ", ns))
curve(dnorm(x, mean = 1/rate, sd = 1/rate/sqrt(ns)), add = TRUE,
col = "blue", lwd = 2)

For a sample size of 60, the resultant sample means are more accurate, and the corresponding normal density curve fits these distribution of these sample means extremely well (as expected via the CLT).
CLT Simulation - Bernoulli Distribution
set.seed(1)
n <- 100
p = 0.3
x <- rbinom(n, 1, p)
hist(x, freq = FALSE, col = "chartreuse3", xlim = c(0, 1),
main = paste("Histogram of random sample \n from Bernoulli distribution, n = ", n))
curve(dnorm(x, p, sd = sqrt(p*(1 - p))), add = TRUE, col = "blue", lwd = 2)

#Specify sample size
ns <- 5
# Specify success rate
p = 0.3
# Specify number of times to conduct process
trials <- 10000
# create object in which to store sample means once they are generated
norm.means <- rep(0, trials) # Note length is equal to the number of trials
# Run for loop
for(i in 1:trials){
# Randomly generate ns samples from the Bernoulli distribution
x <- rbinom(ns, 1, p)
# Compute mean of samples, and store it in the norm.means object, in ith position
norm.means[i] <- mean(x)
}
hist(norm.means, freq = FALSE, breaks = 20, col = "red",
xlim = c(0, 1),
xlab = expression(bar(x)),
main = paste("Histogram of means, n = ", ns))
# Set mu and sigma for the approximating normal distribution
mu <- p
sigma <- sqrt(p*(1 - p))
# Overlay the normal density
curve(dnorm(x, mu, sigma/sqrt(ns)), add = TRUE, col = "blue", lwd = 2)

The plot of the sample means is clearly not normally distributed.
#Specify sample size
ns <- 30
# Specify success rate
p = 0.3
# Specify number of times to conduct process
trials <- 10000
# create object in which to store sample means once they are generated
norm.means <- rep(0, trials) # Note length is equal to the number of trials
# Run for loop
for(i in 1:trials){
# Randomly generate ns samples from the Bernoulli distribution
x <- rbinom(ns, 1, p)
# Compute mean of samples, and store it in the norm.means object, in ith position
norm.means[i] <- mean(x)
}
hist(norm.means, freq = FALSE, breaks = 20, col = "red",
xlim = c(0, 1),
xlab = expression(bar(x)),
main = paste("Histogram of means, n = ", ns))
# Set mu and sigma for the approximating normal distribution
mu <- p
sigma <- sqrt(p*(1 - p))
# Overlay the normal density
curve(dnorm(x, mu, sigma/sqrt(ns)), add = TRUE, col = "blue", lwd = 2)

All of a sudden, the distribution of the sample means begins to look much more normally distributed.
#Specify sample size
ns <- 60
# Specify success rate
p = 0.3
# Specify number of times to conduct process
trials <- 10000
# create object in which to store sample means once they are generated
norm.means <- rep(0, trials) # Note length is equal to the number of trials
# Run for loop
for(i in 1:trials){
# Randomly generate ns samples from the Bernoulli distribution
x <- rbinom(ns, 1, p)
# Compute mean of samples, and store it in the norm.means object, in ith position
norm.means[i] <- mean(x)
}
hist(norm.means, freq = FALSE, breaks = 20, col = "red",
xlim = c(0, 1),
xlab = expression(bar(x)),
main = paste("Histogram of means, n = ", ns))
# Set mu and sigma for the approximating normal distribution
mu <- p
sigma <- sqrt(p*(1 - p))
# Overlay the normal density
curve(dnorm(x, mu, sigma/sqrt(ns)), add = TRUE, col = "blue", lwd = 2)

For a sample size of 60, the sample means are now looking as if they almost could have been generated from a normal distribution, which is amazing given they are obtained from data generated from a discrete distribution.
Extension - Average Diamond Prices
The R code below should have been run:
install.packages("ggplot2")
library(ggplot2)
hist(diamonds$price, col = "skyblue", xlab = "Diamond Price ($)",
main = "Histogram of Diamond Prices ($)", freq = F)

Example R code is provided below:
#Specify sample size
ns <- 5
# Specify number of times to conduct process
trials <- 100
# create object in which to store sample means once they are generated
norm.means <- rep(0, trials) # Note length is equal to the number of trials
# Run for loop
for(i in 1:trials){
# Randomly sample ns values from the diamonds data set
x <- sample(diamonds$price, ns)
# Compute mean of samples, and store it in the norm.means object, in ith position
norm.means[i] <- mean(x)
}
hist(norm.means, freq = FALSE, col = "skyblue",
xlab = expression(bar(x)),
main = paste("Histogram of means, n = ", ns))

We note that the distribution of the sample means is quite skewed.
#Specify sample size
ns <- 30
# Specify number of times to conduct process
trials <- 100
# create object in which to store sample means once they are generated
norm.means2 <- rep(0, trials) # Note length is equal to the number of trials
# Run for loop
for(i in 1:trials){
# Randomly sample ns values from the diamonds data set
x <- sample(diamonds$price, ns)
# Compute mean of samples, and store it in the norm.means object, in ith position
norm.means2[i] <- mean(x)
}
hist(norm.means2, freq = FALSE, col = "skyblue",
xlab = expression(bar(x)),
main = paste("Histogram of means, n = ", ns))

By increasing our sample size to 30, the distribution of the sample means now appears approximately normal (i.e. symmetric). This results adheres with the Central Limit Theorem.
Great job, that’s everything for today!
Hopefully, this computer lab has helped cement your understanding of the Central Limit Theorem.
LS0tDQp0aXRsZTogIlNUTTEwMDE6IENvbXB1dGVyIExhYiA1QiBTb2x1dGlvbnMiDQpvdXRwdXQ6DQogIGJvb2tkb3duOjpodG1sX2RvY3VtZW50MjogDQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIHRoZW1lOiByZWFkYWJsZQ0KICAgIGNvZGVfZm9sZGluZzogc2hvdw0KYmlibGlvZ3JhcGh5OiBTVE0xMDAxX0RTX0NMX3JlZmVyZW5jZXMuYmliIA0KbGluay1jaXRhdGlvbnM6IHllcw0KLS0tDQoNCjxzdHlsZT4NCiNUT0Mgew0KICBiYWNrZ3JvdW5kOiB1cmwoImh0dHBzOi8vd3d3LmxhdHJvYmUuZWR1LmF1L19tZWRpYS9sYS10cm9iZS1hcGkvdjUvaW1nL2xvZ28uc3ZnIik7DQogIGJhY2tncm91bmQtc2l6ZTogY29udGFpbjsNCiAgcGFkZGluZy10b3A6IDgwcHggIWltcG9ydGFudDsNCiAgYmFja2dyb3VuZC1yZXBlYXQ6IG5vLXJlcGVhdDsNCn0NCjwvc3R5bGU+DQoNCiMjIyBEYXRhIFNjaWVuY2UgTW9kdWxlIHstfQ0KDQojIyMgVG9waWMgNUI6IFNpbXVsYXRpb25zIGluIFIgey19DQoNCjxicj4NCg0KRXhhbXBsZSBSIGNvZGUgc29sdXRpb25zIGZvciB0aGUgW0RhdGEgU2NpZW5jZSBDb21wdXRlciBMYWIgNV0oaHR0cHM6Ly9ycHVicy5jb20vTFRVX1NUTTEwMDEvRFNNQ0w1X1MpLCB3aGljaCB1c2VzIHRoZSBSIHBhY2thZ2UgYGRwbHlyYCBbQGRwbHlyXSBhbmQgcGVuZ3VpbiBkYXRhIGZyb20gdGhlIGBwYWxtZXJwZW5ndWluc2AgUiBwYWNrYWdlIFtAcGVuZ3VpbnNdLCBhcmUgcHJlc2VudGVkIGJlbG93Lg0KDQojIFNhbXBsaW5nIERpc3RyaWJ1dGlvbnMNCg0KIyMgU2FtcGxpbmcNCg0KTm8gYW5zd2VyIHJlcXVpcmVkLg0KDQojIyBUaGUgQ2VudHJhbCBMaW1pdCBUaGVvcmVtIHsjQ0xUfQ0KDQpObyBhbnN3ZXIgcmVxdWlyZWQuDQoNCiMgU2ltdWxhdGlvbnMgaW4gUg0KDQojIyB7I2Jhc2V9DQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFR9DQpzZXQuc2VlZCgxKQ0KbiA8LSAxMDANCg0KeCA8LSBybm9ybShuKQ0KYGBgDQoNCiMjDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFR9DQpoaXN0KHgsIGZyZXEgPSBGQUxTRSwgY29sID0gImNoYXJ0cmV1c2UzIiwgeGxpbSA9IGMoLTMsIDMpLA0KICAgICBtYWluID0gcGFzdGUoIkhpc3RvZ3JhbSBvZiByYW5kb20gc2FtcGxlIFxuIGZyb20gc3RhbmRhcmQgTm9ybWFsIGRpc3RyaWJ1dGlvbiwgbiA9ICIsIG4pKSANCiMgT3ZlcmxheSBzdGFuZGFyZCBub3JtYWwgY3VydmUNCmN1cnZlKGRub3JtKHgpLCBhZGQgPSBUUlVFLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpDQojIEFkZCBsaW5lIGRlbm90aW5nIHNhbXBsZSBtZWFuDQphYmxpbmUodiA9IHJvdW5kKG1lYW4oeCksIDMpLCBjb2wgPSAicmVkIiwgbHdkID0gMiwgbHR5ID0gMikNCmBgYA0KDQojIw0KDQpObyBhbnN3ZXIgcmVxdWlyZWQuDQoNCiMjIHsjc3RhcnR9DQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFR9DQpzZXQuc2VlZCgxKQ0KbiA8LSA1ICMgU3BlY2lmeSBzYW1wbGUgc2l6ZQ0KeCA8LSBybm9ybShuKSAjIFJhbmRvbWx5IGdlbmVyYXRlIG5zIHNhbXBsZXMgZnJvbSB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbg0Kbm9ybV9tZWFuIDwtIG1lYW4oeCkgIyBDb21wdXRlIHRoZSBtZWFuIG9mIHRoZSBzYW1wbGVzLCBhbmQgc3RvcmUgaXQgaW4gYSBuZXcgb2JqZWN0DQpgYGANCg0KIyMgeyNzaW1zdGFydH0NCg0KTm8gYW5zd2VyIHJlcXVpcmVkLg0KDQojIyB7I3NpbX0NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgY2FjaGUgPSBUfQ0KI1NwZWNpZnkgc2FtcGxlIHNpemUNCm5zIDwtIDUNCiAgDQojIFNwZWNpZnkgbnVtYmVyIG9mIHRpbWVzIHRvIGNvbmR1Y3QgcHJvY2VzcyAgDQp0cmlhbHMgPC0gMTAwMDANCg0KIyBjcmVhdGUgb2JqZWN0IGluIHdoaWNoIHRvIHN0b3JlIHNhbXBsZSBtZWFucyBvbmNlIHRoZXkgYXJlIGdlbmVyYXRlZA0Kbm9ybS5tZWFucyA8LSByZXAoMCwgdHJpYWxzKSAjIE5vdGUgbGVuZ3RoIGlzIGVxdWFsIHRvIHRoZSBudW1iZXIgb2YgdHJpYWxzDQoNCiMgUnVuIGZvciBsb29wICANCmZvcihpIGluIDE6dHJpYWxzKXsNCiAgICAjIFJhbmRvbWx5IGdlbmVyYXRlIG5zIHNhbXBsZXMgZnJvbSB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbg0KICAgIHggPC0gcm5vcm0obnMpIA0KICAgICMgQ29tcHV0ZSBtZWFuIG9mIHNhbXBsZXMsIGFuZCBzdG9yZSBpdCBpbiB0aGUgbm9ybS5tZWFucyBvYmplY3QsIGluIGl0aCBwb3NpdGlvbiANCiAgICBub3JtLm1lYW5zW2ldIDwtIG1lYW4oeCkgDQogICAgfQ0KYGBgDQoNCiMjIHsjdml6fQ0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCBjYWNoZSA9IFR9DQpoaXN0KG5vcm0ubWVhbnMsIGZyZXEgPSBGQUxTRSwgYnJlYWtzID0gMjAsIGNvbCA9ICJyZWQiLCANCiAgICAgeGxpbSA9IGMoLTMsIDMpLA0KICAgICB4bGFiID0gZXhwcmVzc2lvbihiYXIoeCkpLA0KICAgICBtYWluID0gcGFzdGUoIkhpc3RvZ3JhbSBvZiBtZWFucywgbiA9ICIsIG5zKSkgDQoNCmN1cnZlKGRub3JtKHgsIA0KICAgICAgbWVhbiA9IDAsIHNkID0gMS9zcXJ0KG5zKSksIA0KICAgICAgYWRkID0gVFJVRSwgY29sID0gImJsdWUiLCBsd2QgPSAyKSANCmBgYA0KDQpUaGUgc2ltdWxhdGVkIHNhbXBsZSBtZWFucyBhcmUgY2VudHJlZCBvbiB0aGUgcG9wdWxhdGlvbiBtZWFuIG9mIDAsIGJ1dCBkbyBkaXNwbGF5IHNvbWUgdmFyaWFuY2UuDQoNCiMjDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIGNhY2hlID0gVH0NCiNTcGVjaWZ5IHNhbXBsZSBzaXplDQpucyA8LSAzMA0KICANCiMgU3BlY2lmeSBudW1iZXIgb2YgdGltZXMgdG8gY29uZHVjdCBwcm9jZXNzICANCnRyaWFscyA8LSAxMDAwMA0KDQojIGNyZWF0ZSBvYmplY3QgaW4gd2hpY2ggdG8gc3RvcmUgc2FtcGxlIG1lYW5zIG9uY2UgdGhleSBhcmUgZ2VuZXJhdGVkDQpub3JtLm1lYW5zIDwtIHJlcCgwLCB0cmlhbHMpICMgTm90ZSBsZW5ndGggaXMgZXF1YWwgdG8gdGhlIG51bWJlciBvZiB0cmlhbHMNCg0KIyBSdW4gZm9yIGxvb3AgIA0KZm9yKGkgaW4gMTp0cmlhbHMpew0KICAgICMgUmFuZG9tbHkgZ2VuZXJhdGUgbnMgc2FtcGxlcyBmcm9tIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uDQogICAgeCA8LSBybm9ybShucykgDQogICAgIyBDb21wdXRlIG1lYW4gb2Ygc2FtcGxlcywgYW5kIHN0b3JlIGl0IGluIHRoZSBub3JtLm1lYW5zIG9iamVjdCwgaW4gaXRoIHBvc2l0aW9uIA0KICAgIG5vcm0ubWVhbnNbaV0gPC0gbWVhbih4KSANCiAgICB9DQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgY2FjaGUgPSBUfQ0KaGlzdChub3JtLm1lYW5zLCBmcmVxID0gRkFMU0UsIGJyZWFrcyA9IDIwLCBjb2wgPSAicmVkIiwgDQogICAgIHhsaW0gPSBjKC0zLCAzKSwNCiAgICAgeGxhYiA9IGV4cHJlc3Npb24oYmFyKHgpKSwNCiAgICAgbWFpbiA9IHBhc3RlKCJIaXN0b2dyYW0gb2YgbWVhbnMsIG4gPSAiLCBucykpIA0KDQpjdXJ2ZShkbm9ybSh4LCANCiAgICAgIG1lYW4gPSAwLCBzZCA9IDEvc3FydChucykpLCANCiAgICAgIGFkZCA9IFRSVUUsIGNvbCA9ICJibHVlIiwgbHdkID0gMikgDQpgYGANCg0KQXMgd2UgaW5jcmVhc2UgdGhlIHNhbXBsZSBzaXplLCB0aGUgdmFyaWFuY2Ugb2YgdGhlIHNhbXBsZSBtZWFucyBkZWNyZWFzZXMuDQoNCiMjDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIGNhY2hlID0gVH0NCiNTcGVjaWZ5IHNhbXBsZSBzaXplDQpucyA8LSA2MA0KICANCiMgU3BlY2lmeSBudW1iZXIgb2YgdGltZXMgdG8gY29uZHVjdCBwcm9jZXNzICANCnRyaWFscyA8LSAxMDAwMA0KDQojIGNyZWF0ZSBvYmplY3QgaW4gd2hpY2ggdG8gc3RvcmUgc2FtcGxlIG1lYW5zIG9uY2UgdGhleSBhcmUgZ2VuZXJhdGVkDQpub3JtLm1lYW5zIDwtIHJlcCgwLCB0cmlhbHMpICMgTm90ZSBsZW5ndGggaXMgZXF1YWwgdG8gdGhlIG51bWJlciBvZiB0cmlhbHMNCg0KIyBSdW4gZm9yIGxvb3AgIA0KZm9yKGkgaW4gMTp0cmlhbHMpew0KICAgICMgUmFuZG9tbHkgZ2VuZXJhdGUgbnMgc2FtcGxlcyBmcm9tIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uDQogICAgeCA8LSBybm9ybShucykgDQogICAgIyBDb21wdXRlIG1lYW4gb2Ygc2FtcGxlcywgYW5kIHN0b3JlIGl0IGluIHRoZSBub3JtLm1lYW5zIG9iamVjdCwgaW4gaXRoIHBvc2l0aW9uIA0KICAgIG5vcm0ubWVhbnNbaV0gPC0gbWVhbih4KSANCiAgICB9DQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVH0NCmhpc3Qobm9ybS5tZWFucywgZnJlcSA9IEZBTFNFLCBicmVha3MgPSAyMCwgY29sID0gInJlZCIsIA0KICAgICB4bGltID0gYygtMywgMyksDQogICAgIHhsYWIgPSBleHByZXNzaW9uKGJhcih4KSksDQogICAgIG1haW4gPSBwYXN0ZSgiSGlzdG9ncmFtIG9mIG1lYW5zLCBuID0gIiwgbnMpKSANCg0KY3VydmUoZG5vcm0oeCwgDQogICAgICBtZWFuID0gMCwgc2QgPSAxL3NxcnQobnMpKSwgDQogICAgICBhZGQgPSBUUlVFLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpIA0KYGBgDQoNCkZvciBhIHNhbXBsZSBzaXplIG9mIDYwLCB0aGUgdmFyaWFuY2Ugb2YgdGhlIHNhbXBsZSBtZWFucyBpcyB2ZXJ5IGxvdywgcHJvdmlkaW5nIHVzIHdpdGggYW4gYWNjdXJhdGUgZXN0aW1hdGUgb2YgdGhlIHBvcHVsYXRpb24gbWVhbi4NCg0KIyBDTFQgU2ltdWxhdGlvbiAtIEV4cG9uZW50aWFsIERpc3RyaWJ1dGlvbg0KDQojIw0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBUfQ0Kc2V0LnNlZWQoMSkNCm4gPC0gMTAwDQpyYXRlID0gMTANCnggPC0gcmV4cChuLCByYXRlID0gcmF0ZSkNCmBgYA0KDQojIw0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBUfQ0KaGlzdCh4LCBmcmVxID0gRkFMU0UsIGNvbCA9ICJjaGFydHJldXNlMyIsIHhsaW0gPSBjKDAsIDAuNSksDQogICAgIG1haW4gPSBwYXN0ZSgiSGlzdG9ncmFtIG9mIHJhbmRvbSBzYW1wbGUgXG4gZnJvbSBFeHBvbmVudGlhbCBkaXN0cmlidXRpb24sIG4gPSAiLCBuKSkNCg0KY3VydmUoZG5vcm0oeCwgMS9yYXRlLCAxL3JhdGUpLCBhZGQgPSBUUlVFLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpDQpgYGANCg0KIyMNCg0KTm8gYW5zd2VyIHJlcXVpcmVkLg0KDQojIyB7I2V4cHNpbX0NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgY2FjaGUgPSBUfQ0KI1NwZWNpZnkgc2FtcGxlIHNpemUNCm5zIDwtIDUNCiAgDQojIFNwZWNpZnkgcmF0ZQ0KcmF0ZSA9IDEwDQoNCiMgU3BlY2lmeSBudW1iZXIgb2YgdGltZXMgdG8gY29uZHVjdCBwcm9jZXNzICANCnRyaWFscyA8LSAxMDAwMA0KDQojIGNyZWF0ZSBvYmplY3QgaW4gd2hpY2ggdG8gc3RvcmUgc2FtcGxlIG1lYW5zIG9uY2UgdGhleSBhcmUgZ2VuZXJhdGVkDQpub3JtLm1lYW5zIDwtIHJlcCgwLCB0cmlhbHMpICMgTm90ZSBsZW5ndGggaXMgZXF1YWwgdG8gdGhlIG51bWJlciBvZiB0cmlhbHMNCg0KIyBSdW4gZm9yIGxvb3AgIA0KZm9yKGkgaW4gMTp0cmlhbHMpew0KICAgICMgUmFuZG9tbHkgZ2VuZXJhdGUgbnMgc2FtcGxlcyBmcm9tIHRoZSBleHBvbmVudGlhbCBkaXN0cmlidXRpb24NCiAgICB4IDwtIHJleHAobnMsIHJhdGUgPSByYXRlKQ0KICAgICMgQ29tcHV0ZSBtZWFuIG9mIHNhbXBsZXMsIGFuZCBzdG9yZSBpdCBpbiB0aGUgbm9ybS5tZWFucyBvYmplY3QsIGluIGl0aCBwb3NpdGlvbiANCiAgICBub3JtLm1lYW5zW2ldIDwtIG1lYW4oeCkgDQogICAgfQ0KYGBgDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIGNhY2hlID0gVH0NCmhpc3Qobm9ybS5tZWFucywgZnJlcSA9IEZBTFNFLCBicmVha3MgPSAyMCwgY29sID0gInJlZCIsIA0KICAgICB4bGltID0gYygwLCAwLjQpLA0KICAgICB4bGFiID0gZXhwcmVzc2lvbihiYXIoeCkpLA0KICAgICBtYWluID0gcGFzdGUoIkhpc3RvZ3JhbSBvZiBtZWFucywgbiA9ICIsIG5zKSkgDQoNCmN1cnZlKGRub3JtKHgsIG1lYW4gPSAxL3JhdGUsIHNkID0gMS9yYXRlL3NxcnQobnMpKSwgYWRkID0gVFJVRSwNCiAgICAgICAgY29sID0gImJsdWUiLCBsd2QgPSAyKQ0KYGBgDQoNCkhlcmUgd2UgdXNlIGFuIHgtYXhpcyByYW5nZSBvZiAwIHRvIDAuNC4NCg0KIyMNCg0KVGhlIHJlc3VsdGluZyBkYXRhIHNldCBpcyBub3QgYXMgc2tld2VkIGFzIHRoZSB1bmRlcmx5aW5nIGRpc3RyaWJ1dGlvbiwgYnV0IHRoZXJlIGlzIHN0aWxsIGEgbm90aWNlYWJsZSBza2V3ICh0aGlzIGlzIGJlY2F1c2Ugb2YgdGhlIGxvdyBzYW1wbGUgc2l6ZSkuDQoNCiMjDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIGNhY2hlID0gVH0NCiNTcGVjaWZ5IHNhbXBsZSBzaXplDQpucyA8LSAzMA0KICANCiMgU3BlY2lmeSByYXRlDQpyYXRlID0gMTANCg0KIyBTcGVjaWZ5IG51bWJlciBvZiB0aW1lcyB0byBjb25kdWN0IHByb2Nlc3MgIA0KdHJpYWxzIDwtIDEwMDAwDQoNCiMgY3JlYXRlIG9iamVjdCBpbiB3aGljaCB0byBzdG9yZSBzYW1wbGUgbWVhbnMgb25jZSB0aGV5IGFyZSBnZW5lcmF0ZWQNCm5vcm0ubWVhbnMgPC0gcmVwKDAsIHRyaWFscykgIyBOb3RlIGxlbmd0aCBpcyBlcXVhbCB0byB0aGUgbnVtYmVyIG9mIHRyaWFscw0KDQojIFJ1biBmb3IgbG9vcCAgDQpmb3IoaSBpbiAxOnRyaWFscyl7DQogICAgIyBSYW5kb21seSBnZW5lcmF0ZSBucyBzYW1wbGVzIGZyb20gdGhlIGV4cG9uZW50aWFsIGRpc3RyaWJ1dGlvbg0KICAgIHggPC0gcmV4cChucywgcmF0ZSA9IHJhdGUpDQogICAgIyBDb21wdXRlIG1lYW4gb2Ygc2FtcGxlcywgYW5kIHN0b3JlIGl0IGluIHRoZSBub3JtLm1lYW5zIG9iamVjdCwgaW4gaXRoIHBvc2l0aW9uIA0KICAgIG5vcm0ubWVhbnNbaV0gPC0gbWVhbih4KSANCiAgICB9DQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgY2FjaGUgPSBUfQ0KaGlzdChub3JtLm1lYW5zLCBmcmVxID0gRkFMU0UsIGJyZWFrcyA9IDIwLCBjb2wgPSAicmVkIiwgDQogICAgIHhsaW0gPSBjKDAsIDAuMiksDQogICAgIHhsYWIgPSBleHByZXNzaW9uKGJhcih4KSksDQogICAgIG1haW4gPSBwYXN0ZSgiSGlzdG9ncmFtIG9mIG1lYW5zLCBuID0gIiwgbnMpKSANCg0KY3VydmUoZG5vcm0oeCwgbWVhbiA9IDEvcmF0ZSwgc2QgPSAxL3JhdGUvc3FydChucykpLCBhZGQgPSBUUlVFLA0KICAgICAgICBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpDQpgYGANCg0KSGVyZSwgd2UgY2hhbmdlIHRoZSB4IGF4aXMgcmFuZ2UgdG8gYmUgZnJvbSAwIHRvIDAuMi4gVGhlIHNhbXBsZSBtZWFucyBub3cgZGlzcGxheSB2ZXJ5IGxpdHRsZSB2YXJpYW5jZSwgYW5kIHByb3ZpZGUgYSBtdWNoIG1vcmUgYWNjdXJhdGUgZXN0aW1hdGUgb2YgdGhlIHBvcHVsYXRpb24gbWVhbiBvZiAwLjEuIE5vdGUgdGhhdCB0aGUgTm9ybWFsIGRlbnNpdHkgY3VydmUgYWxzbyBmaXRzIHRoZSBkYXRhIHdlbGwuIFRoZXNlIHJlc3VsdHMgYXJlIGR1ZSB0byB0aGUgc2FtcGxlIHNpemUgYmVpbmcgYmlnZ2VyICgzMCBpbnN0ZWFkIG9mIDUpLg0KDQojIw0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCBjYWNoZSA9IFR9DQojU3BlY2lmeSBzYW1wbGUgc2l6ZQ0KbnMgPC0gNjANCiAgDQojIFNwZWNpZnkgcmF0ZQ0KcmF0ZSA9IDEwDQoNCiMgU3BlY2lmeSBudW1iZXIgb2YgdGltZXMgdG8gY29uZHVjdCBwcm9jZXNzICANCnRyaWFscyA8LSAxMDAwMA0KDQojIGNyZWF0ZSBvYmplY3QgaW4gd2hpY2ggdG8gc3RvcmUgc2FtcGxlIG1lYW5zIG9uY2UgdGhleSBhcmUgZ2VuZXJhdGVkDQpub3JtLm1lYW5zIDwtIHJlcCgwLCB0cmlhbHMpICMgTm90ZSBsZW5ndGggaXMgZXF1YWwgdG8gdGhlIG51bWJlciBvZiB0cmlhbHMNCg0KIyBSdW4gZm9yIGxvb3AgIA0KZm9yKGkgaW4gMTp0cmlhbHMpew0KICAgICMgUmFuZG9tbHkgZ2VuZXJhdGUgbnMgc2FtcGxlcyBmcm9tIHRoZSBleHBvbmVudGlhbCBkaXN0cmlidXRpb24NCiAgICB4IDwtIHJleHAobnMsIHJhdGUgPSByYXRlKQ0KICAgICMgQ29tcHV0ZSBtZWFuIG9mIHNhbXBsZXMsIGFuZCBzdG9yZSBpdCBpbiB0aGUgbm9ybS5tZWFucyBvYmplY3QsIGluIGl0aCBwb3NpdGlvbiANCiAgICBub3JtLm1lYW5zW2ldIDwtIG1lYW4oeCkgDQogICAgfQ0KYGBgDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIGNhY2hlID0gVH0NCmhpc3Qobm9ybS5tZWFucywgZnJlcSA9IEZBTFNFLCBicmVha3MgPSAyMCwgY29sID0gInJlZCIsIA0KICAgICB4bGltID0gYygwLCAwLjIpLA0KICAgICB4bGFiID0gZXhwcmVzc2lvbihiYXIoeCkpLA0KICAgICBtYWluID0gcGFzdGUoIkhpc3RvZ3JhbSBvZiBtZWFucywgbiA9ICIsIG5zKSkgDQoNCmN1cnZlKGRub3JtKHgsIG1lYW4gPSAxL3JhdGUsIHNkID0gMS9yYXRlL3NxcnQobnMpKSwgYWRkID0gVFJVRSwNCiAgICAgICAgY29sID0gImJsdWUiLCBsd2QgPSAyKQ0KYGBgDQoNCkZvciBhIHNhbXBsZSBzaXplIG9mIDYwLCB0aGUgcmVzdWx0YW50IHNhbXBsZSBtZWFucyBhcmUgbW9yZSBhY2N1cmF0ZSwgYW5kIHRoZSBjb3JyZXNwb25kaW5nIG5vcm1hbCBkZW5zaXR5IGN1cnZlIGZpdHMgdGhlc2UgZGlzdHJpYnV0aW9uIG9mIHRoZXNlIHNhbXBsZSBtZWFucyBleHRyZW1lbHkgd2VsbCAoYXMgZXhwZWN0ZWQgdmlhIHRoZSBDTFQpLg0KDQojIENMVCBTaW11bGF0aW9uIC0gQmVybm91bGxpIERpc3RyaWJ1dGlvbg0KDQojIw0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBUfQ0Kc2V0LnNlZWQoMSkNCm4gPC0gMTAwDQpwID0gMC4zDQp4IDwtIHJiaW5vbShuLCAxLCBwKQ0KDQpoaXN0KHgsIGZyZXEgPSBGQUxTRSwgY29sID0gImNoYXJ0cmV1c2UzIiwgeGxpbSA9IGMoMCwgMSksDQogICAgIG1haW4gPSBwYXN0ZSgiSGlzdG9ncmFtIG9mIHJhbmRvbSBzYW1wbGUgXG4gZnJvbSBCZXJub3VsbGkgZGlzdHJpYnV0aW9uLCBuID0gIiwgbikpIA0KY3VydmUoZG5vcm0oeCwgcCwgc2QgPSBzcXJ0KHAqKDEgLSBwKSkpLCBhZGQgPSBUUlVFLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpDQpgYGANCg0KIyMNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgY2FjaGUgPSBUfQ0KI1NwZWNpZnkgc2FtcGxlIHNpemUNCm5zIDwtIDUNCiAgDQojIFNwZWNpZnkgc3VjY2VzcyByYXRlDQpwID0gMC4zDQoNCiMgU3BlY2lmeSBudW1iZXIgb2YgdGltZXMgdG8gY29uZHVjdCBwcm9jZXNzICANCnRyaWFscyA8LSAxMDAwMA0KDQojIGNyZWF0ZSBvYmplY3QgaW4gd2hpY2ggdG8gc3RvcmUgc2FtcGxlIG1lYW5zIG9uY2UgdGhleSBhcmUgZ2VuZXJhdGVkDQpub3JtLm1lYW5zIDwtIHJlcCgwLCB0cmlhbHMpICMgTm90ZSBsZW5ndGggaXMgZXF1YWwgdG8gdGhlIG51bWJlciBvZiB0cmlhbHMNCg0KIyBSdW4gZm9yIGxvb3AgIA0KZm9yKGkgaW4gMTp0cmlhbHMpew0KICAgICMgUmFuZG9tbHkgZ2VuZXJhdGUgbnMgc2FtcGxlcyBmcm9tIHRoZSBCZXJub3VsbGkgZGlzdHJpYnV0aW9uDQogICAgeCA8LSByYmlub20obnMsIDEsIHApDQogICAgIyBDb21wdXRlIG1lYW4gb2Ygc2FtcGxlcywgYW5kIHN0b3JlIGl0IGluIHRoZSBub3JtLm1lYW5zIG9iamVjdCwgaW4gaXRoIHBvc2l0aW9uIA0KICAgIG5vcm0ubWVhbnNbaV0gPC0gbWVhbih4KSANCiAgICB9DQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgY2FjaGUgPSBUfQ0KaGlzdChub3JtLm1lYW5zLCBmcmVxID0gRkFMU0UsIGJyZWFrcyA9IDIwLCBjb2wgPSAicmVkIiwgDQogICAgIHhsaW0gPSBjKDAsIDEpLA0KICAgICB4bGFiID0gZXhwcmVzc2lvbihiYXIoeCkpLA0KICAgICBtYWluID0gcGFzdGUoIkhpc3RvZ3JhbSBvZiBtZWFucywgbiA9ICIsIG5zKSkgDQoNCiMgU2V0IG11IGFuZCBzaWdtYSBmb3IgdGhlIGFwcHJveGltYXRpbmcgbm9ybWFsIGRpc3RyaWJ1dGlvbg0KbXUgPC0gcA0Kc2lnbWEgPC0gc3FydChwKigxIC0gcCkpDQogIA0KIyBPdmVybGF5IHRoZSBub3JtYWwgZGVuc2l0eQ0KY3VydmUoZG5vcm0oeCwgbXUsIHNpZ21hL3NxcnQobnMpKSwgYWRkID0gVFJVRSwgY29sID0gImJsdWUiLCBsd2QgPSAyKQ0KYGBgDQoNCiMjDQoNClRoZSBwbG90IG9mIHRoZSBzYW1wbGUgbWVhbnMgaXMgY2xlYXJseSBub3Qgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuDQoNCiMjDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIGNhY2hlID0gVH0NCiNTcGVjaWZ5IHNhbXBsZSBzaXplDQpucyA8LSAzMA0KICANCiMgU3BlY2lmeSBzdWNjZXNzIHJhdGUNCnAgPSAwLjMNCg0KIyBTcGVjaWZ5IG51bWJlciBvZiB0aW1lcyB0byBjb25kdWN0IHByb2Nlc3MgIA0KdHJpYWxzIDwtIDEwMDAwDQoNCiMgY3JlYXRlIG9iamVjdCBpbiB3aGljaCB0byBzdG9yZSBzYW1wbGUgbWVhbnMgb25jZSB0aGV5IGFyZSBnZW5lcmF0ZWQNCm5vcm0ubWVhbnMgPC0gcmVwKDAsIHRyaWFscykgIyBOb3RlIGxlbmd0aCBpcyBlcXVhbCB0byB0aGUgbnVtYmVyIG9mIHRyaWFscw0KDQojIFJ1biBmb3IgbG9vcCAgDQpmb3IoaSBpbiAxOnRyaWFscyl7DQogICAgIyBSYW5kb21seSBnZW5lcmF0ZSBucyBzYW1wbGVzIGZyb20gdGhlIEJlcm5vdWxsaSBkaXN0cmlidXRpb24NCiAgICB4IDwtIHJiaW5vbShucywgMSwgcCkNCiAgICAjIENvbXB1dGUgbWVhbiBvZiBzYW1wbGVzLCBhbmQgc3RvcmUgaXQgaW4gdGhlIG5vcm0ubWVhbnMgb2JqZWN0LCBpbiBpdGggcG9zaXRpb24gDQogICAgbm9ybS5tZWFuc1tpXSA8LSBtZWFuKHgpIA0KICAgIH0NCmBgYA0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCBjYWNoZSA9IFR9DQpoaXN0KG5vcm0ubWVhbnMsIGZyZXEgPSBGQUxTRSwgYnJlYWtzID0gMjAsIGNvbCA9ICJyZWQiLCANCiAgICAgeGxpbSA9IGMoMCwgMSksDQogICAgIHhsYWIgPSBleHByZXNzaW9uKGJhcih4KSksDQogICAgIG1haW4gPSBwYXN0ZSgiSGlzdG9ncmFtIG9mIG1lYW5zLCBuID0gIiwgbnMpKSANCg0KIyBTZXQgbXUgYW5kIHNpZ21hIGZvciB0aGUgYXBwcm94aW1hdGluZyBub3JtYWwgZGlzdHJpYnV0aW9uDQptdSA8LSBwDQpzaWdtYSA8LSBzcXJ0KHAqKDEgLSBwKSkNCiAgDQojIE92ZXJsYXkgdGhlIG5vcm1hbCBkZW5zaXR5DQpjdXJ2ZShkbm9ybSh4LCBtdSwgc2lnbWEvc3FydChucykpLCBhZGQgPSBUUlVFLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpDQpgYGANCg0KQWxsIG9mIGEgc3VkZGVuLCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBzYW1wbGUgbWVhbnMgYmVnaW5zIHRvIGxvb2sgbXVjaCBtb3JlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLg0KDQojIw0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCBjYWNoZSA9IFR9DQojU3BlY2lmeSBzYW1wbGUgc2l6ZQ0KbnMgPC0gNjANCiAgDQojIFNwZWNpZnkgc3VjY2VzcyByYXRlDQpwID0gMC4zDQoNCiMgU3BlY2lmeSBudW1iZXIgb2YgdGltZXMgdG8gY29uZHVjdCBwcm9jZXNzICANCnRyaWFscyA8LSAxMDAwMA0KDQojIGNyZWF0ZSBvYmplY3QgaW4gd2hpY2ggdG8gc3RvcmUgc2FtcGxlIG1lYW5zIG9uY2UgdGhleSBhcmUgZ2VuZXJhdGVkDQpub3JtLm1lYW5zIDwtIHJlcCgwLCB0cmlhbHMpICMgTm90ZSBsZW5ndGggaXMgZXF1YWwgdG8gdGhlIG51bWJlciBvZiB0cmlhbHMNCg0KIyBSdW4gZm9yIGxvb3AgIA0KZm9yKGkgaW4gMTp0cmlhbHMpew0KICAgICMgUmFuZG9tbHkgZ2VuZXJhdGUgbnMgc2FtcGxlcyBmcm9tIHRoZSBCZXJub3VsbGkgZGlzdHJpYnV0aW9uDQogICAgeCA8LSByYmlub20obnMsIDEsIHApDQogICAgIyBDb21wdXRlIG1lYW4gb2Ygc2FtcGxlcywgYW5kIHN0b3JlIGl0IGluIHRoZSBub3JtLm1lYW5zIG9iamVjdCwgaW4gaXRoIHBvc2l0aW9uIA0KICAgIG5vcm0ubWVhbnNbaV0gPC0gbWVhbih4KSANCiAgICB9DQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgY2FjaGUgPSBUfQ0KaGlzdChub3JtLm1lYW5zLCBmcmVxID0gRkFMU0UsIGJyZWFrcyA9IDIwLCBjb2wgPSAicmVkIiwgDQogICAgIHhsaW0gPSBjKDAsIDEpLA0KICAgICB4bGFiID0gZXhwcmVzc2lvbihiYXIoeCkpLA0KICAgICBtYWluID0gcGFzdGUoIkhpc3RvZ3JhbSBvZiBtZWFucywgbiA9ICIsIG5zKSkgDQoNCiMgU2V0IG11IGFuZCBzaWdtYSBmb3IgdGhlIGFwcHJveGltYXRpbmcgbm9ybWFsIGRpc3RyaWJ1dGlvbg0KbXUgPC0gcA0Kc2lnbWEgPC0gc3FydChwKigxIC0gcCkpDQogIA0KIyBPdmVybGF5IHRoZSBub3JtYWwgZGVuc2l0eQ0KY3VydmUoZG5vcm0oeCwgbXUsIHNpZ21hL3NxcnQobnMpKSwgYWRkID0gVFJVRSwgY29sID0gImJsdWUiLCBsd2QgPSAyKQ0KYGBgDQoNCkZvciBhIHNhbXBsZSBzaXplIG9mIDYwLCB0aGUgc2FtcGxlIG1lYW5zIGFyZSBub3cgbG9va2luZyBhcyBpZiB0aGV5IGFsbW9zdCBjb3VsZCBoYXZlIGJlZW4gZ2VuZXJhdGVkIGZyb20gYSBub3JtYWwgZGlzdHJpYnV0aW9uLCB3aGljaCBpcyBhbWF6aW5nIGdpdmVuIHRoZXkgYXJlIG9idGFpbmVkIGZyb20gZGF0YSBnZW5lcmF0ZWQgZnJvbSBhIGRpc2NyZXRlIGRpc3RyaWJ1dGlvbi4NCg0KDQojIEV4dGVuc2lvbiAtIEF2ZXJhZ2UgRGlhbW9uZCBQcmljZXMNCg0KVGhlIFIgY29kZSBiZWxvdyBzaG91bGQgaGF2ZSBiZWVuIHJ1bjoNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCmluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KYGBgDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUiLCBldmFsID0gVCwgaW5jbHVkZSA9IEZ9DQpsaWJyYXJ5KGdncGxvdDIpDQpgYGANCg0KIyMNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVH0NCmhpc3QoZGlhbW9uZHMkcHJpY2UsIGNvbCA9ICJza3libHVlIiwgeGxhYiA9ICJEaWFtb25kIFByaWNlICgkKSIsDQogICAgIG1haW4gPSAiSGlzdG9ncmFtIG9mIERpYW1vbmQgUHJpY2VzICgkKSIsIGZyZXEgPSBGKQ0KYGBgDQoNCiMjIHsjZGlhbW9uZHNpbX0NCg0KRXhhbXBsZSBSIGNvZGUgaXMgcHJvdmlkZWQgYmVsb3c6DQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIGNhY2hlID0gVH0NCiNTcGVjaWZ5IHNhbXBsZSBzaXplDQpucyA8LSA1DQogIA0KIyBTcGVjaWZ5IG51bWJlciBvZiB0aW1lcyB0byBjb25kdWN0IHByb2Nlc3MgIA0KdHJpYWxzIDwtIDEwMA0KDQojIGNyZWF0ZSBvYmplY3QgaW4gd2hpY2ggdG8gc3RvcmUgc2FtcGxlIG1lYW5zIG9uY2UgdGhleSBhcmUgZ2VuZXJhdGVkDQpub3JtLm1lYW5zIDwtIHJlcCgwLCB0cmlhbHMpICMgTm90ZSBsZW5ndGggaXMgZXF1YWwgdG8gdGhlIG51bWJlciBvZiB0cmlhbHMNCg0KIyBSdW4gZm9yIGxvb3AgIA0KZm9yKGkgaW4gMTp0cmlhbHMpew0KICAgICMgUmFuZG9tbHkgc2FtcGxlIG5zIHZhbHVlcyBmcm9tIHRoZSBkaWFtb25kcyBkYXRhIHNldA0KICAgIHggPC0gc2FtcGxlKGRpYW1vbmRzJHByaWNlLCBucykNCiAgICAjIENvbXB1dGUgbWVhbiBvZiBzYW1wbGVzLCBhbmQgc3RvcmUgaXQgaW4gdGhlIG5vcm0ubWVhbnMgb2JqZWN0LCBpbiBpdGggcG9zaXRpb24gDQogICAgbm9ybS5tZWFuc1tpXSA8LSBtZWFuKHgpIA0KICAgIH0NCmBgYA0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCBjYWNoZSA9IFR9DQpoaXN0KG5vcm0ubWVhbnMsIGZyZXEgPSBGQUxTRSwgY29sID0gInNreWJsdWUiLA0KICAgICB4bGFiID0gZXhwcmVzc2lvbihiYXIoeCkpLA0KICAgICBtYWluID0gcGFzdGUoIkhpc3RvZ3JhbSBvZiBtZWFucywgbiA9ICIsIG5zKSkgDQpgYGANCg0KV2Ugbm90ZSB0aGF0IHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHNhbXBsZSBtZWFucyBpcyBxdWl0ZSBza2V3ZWQuDQoNCiMjIHsjZGlhbW9uZHNpbWxhcmdlfQ0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCBjYWNoZSA9IFR9DQojU3BlY2lmeSBzYW1wbGUgc2l6ZQ0KbnMgPC0gMzANCiAgDQojIFNwZWNpZnkgbnVtYmVyIG9mIHRpbWVzIHRvIGNvbmR1Y3QgcHJvY2VzcyAgDQp0cmlhbHMgPC0gMTAwDQoNCiMgY3JlYXRlIG9iamVjdCBpbiB3aGljaCB0byBzdG9yZSBzYW1wbGUgbWVhbnMgb25jZSB0aGV5IGFyZSBnZW5lcmF0ZWQNCm5vcm0ubWVhbnMyIDwtIHJlcCgwLCB0cmlhbHMpICMgTm90ZSBsZW5ndGggaXMgZXF1YWwgdG8gdGhlIG51bWJlciBvZiB0cmlhbHMNCg0KIyBSdW4gZm9yIGxvb3AgIA0KZm9yKGkgaW4gMTp0cmlhbHMpew0KICAgICMgUmFuZG9tbHkgc2FtcGxlIG5zIHZhbHVlcyBmcm9tIHRoZSBkaWFtb25kcyBkYXRhIHNldA0KICAgIHggPC0gc2FtcGxlKGRpYW1vbmRzJHByaWNlLCBucykNCiAgICAjIENvbXB1dGUgbWVhbiBvZiBzYW1wbGVzLCBhbmQgc3RvcmUgaXQgaW4gdGhlIG5vcm0ubWVhbnMgb2JqZWN0LCBpbiBpdGggcG9zaXRpb24gDQogICAgbm9ybS5tZWFuczJbaV0gPC0gbWVhbih4KSANCiAgICB9DQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgY2FjaGUgPSBUfQ0KaGlzdChub3JtLm1lYW5zMiwgZnJlcSA9IEZBTFNFLCBjb2wgPSAic2t5Ymx1ZSIsDQogICAgIHhsYWIgPSBleHByZXNzaW9uKGJhcih4KSksDQogICAgIG1haW4gPSBwYXN0ZSgiSGlzdG9ncmFtIG9mIG1lYW5zLCBuID0gIiwgbnMpKSANCmBgYA0KDQpCeSBpbmNyZWFzaW5nIG91ciBzYW1wbGUgc2l6ZSB0byAzMCwgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgc2FtcGxlIG1lYW5zIG5vdyBhcHBlYXJzIGFwcHJveGltYXRlbHkgbm9ybWFsIChpLmUuIHN5bW1ldHJpYykuIFRoaXMgcmVzdWx0cyBhZGhlcmVzIHdpdGggdGhlIENlbnRyYWwgTGltaXQgVGhlb3JlbS4NCg0KPGJyPg0KDQojIyMjIEdyZWF0IGpvYiwgdGhhdCdzIGV2ZXJ5dGhpbmcgZm9yIHRvZGF5ISAjIyMjIHstfQ0KDQpIb3BlZnVsbHksIHRoaXMgY29tcHV0ZXIgbGFiIGhhcyBoZWxwZWQgY2VtZW50IHlvdXIgdW5kZXJzdGFuZGluZyBvZiB0aGUgQ2VudHJhbCBMaW1pdCBUaGVvcmVtLg0KDQo8YnI+DQoNCiMgUmVmZXJlbmNlcyB7LSAjUmVmfQ0KPGRpdiBpZD0icmVmcyI+PC9kaXY+DQoNCjxicj4NCg0KPGZvbnQgY29sb3IgPSAiZ3JleSI+DQpUaGVzZSBub3RlcyBoYXZlIGJlZW4gcHJlcGFyZWQgYnkgUnVwZXJ0IEt1dmVrZSBhbmQgQW1hbmRhIFNoYWtlci4gVGhlIGNvcHlyaWdodCBmb3IgdGhlIG1hdGVyaWFsIGluIHRoZXNlIG5vdGVzIHJlc2lkZXMgd2l0aCB0aGUgYXV0aG9ycyBuYW1lZCBhYm92ZSwgd2l0aCB0aGUgRGVwYXJ0bWVudCBvZiBNYXRoZW1hdGljYWwgYW5kIFBoeXNpY2FsIFNjaWVuY2VzIGFuZCB3aXRoIExhIFRyb2JlIFVuaXZlcnNpdHkuIENvcHlyaWdodCBpbiB0aGlzIHdvcmsgaXMgdmVzdGVkIGluIExhIFRyb2JlIFVuaXZlcnNpdHkgaW5jbHVkaW5nIGFsbCBMYSBUcm9iZSBVbml2ZXJzaXR5IGJyYW5kaW5nIGFuZCBuYW1pbmcuIFVubGVzcyBvdGhlcndpc2Ugc3RhdGVkLCBtYXRlcmlhbCB3aXRoaW4gdGhpcyB3b3JrIGlzIGxpY2Vuc2VkIHVuZGVyIGEgQ3JlYXRpdmUgQ29tbW9ucyBBdHRyaWJ1dGlvbi1Ob24gQ29tbWVyY2lhbC1Ob24gRGVyaXZhdGl2ZXMgTGljZW5zZSANCjxhIGhyZWYgPSAiaHR0cHM6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LW5jLW5kLzQuMC9DQyIgdGFyZ2V0PSJfYmxhbmsiPiBCWS1OQy1ORC4gPC9hPg0KPC9mb250Pg==