Data Science Module

Topic 5B: Simulations in R


Example R code solutions for the Data Science Computer Lab 5, which uses the R package dplyr (Wickham et al. 2021) and penguin data from the palmerpenguins R package (Horst, Hill, and Gorman 2020), are presented below.

1 Sampling Distributions

1.1 Sampling

No answer required.

1.2 The Central Limit Theorem

No answer required.

2 Simulations in R

2.1

set.seed(1)
n <- 100

x <- rnorm(n)

2.2

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)

2.3

No answer required.

2.4

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

2.5

No answer required.

2.6

#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) 
    }

2.7

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.

2.8

#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.

2.9

#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.

3 CLT Simulation - Exponential Distribution

3.1

set.seed(1)
n <- 100
rate = 10
x <- rexp(n, rate = rate)

3.2

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)

3.3

No answer required.

3.4

#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.

3.5

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).

3.6

#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).

3.7

#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).

4 CLT Simulation - Bernoulli Distribution

4.1

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)

4.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)

4.3

The plot of the sample means is clearly not normally distributed.

4.4

#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.

4.5

#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.

5 Extension - Average Diamond Prices

The R code below should have been run:

install.packages("ggplot2")
library(ggplot2)

5.1

hist(diamonds$price, col = "skyblue", xlab = "Diamond Price ($)",
     main = "Histogram of Diamond Prices ($)", freq = F)

5.2

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.

5.3

#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.


References

Horst, Allison Marie, Alison Presmanes Hill, and Kristen B Gorman. 2020. Palmerpenguins: Palmer Archipelago (Antarctica) Penguin Data. https://doi.org/10.5281/zenodo.3960218.
Wickham, H., R. Francois, L. Henry, K. Muller, and RStudio. 2021. dplyr: A Grammar of Data Manipulation. https://dplyr.tidyverse.org, https://github.com/tidyverse/dplyr.


These notes have been prepared by Rupert Kuveke and Amanda Shaker. The copyright for the material in these notes resides with the authors named above, with the Department of Mathematical and Physical Sciences and with La Trobe University. Copyright in this work is vested in La Trobe University including all La Trobe University branding and naming. Unless otherwise stated, material within this work is licensed under a Creative Commons Attribution-Non Commercial-Non Derivatives License BY-NC-ND.

LS0tDQp0aXRsZTogIlNUTTEwMDE6IENvbXB1dGVyIExhYiA1QiBTb2x1dGlvbnMiDQpvdXRwdXQ6DQogIGJvb2tkb3duOjpodG1sX2RvY3VtZW50MjogDQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIHRoZW1lOiByZWFkYWJsZQ0KICAgIGNvZGVfZm9sZGluZzogc2hvdw0KYmlibGlvZ3JhcGh5OiBTVE0xMDAxX0RTX0NMX3JlZmVyZW5jZXMuYmliIA0KbGluay1jaXRhdGlvbnM6IHllcw0KLS0tDQoNCjxzdHlsZT4NCiNUT0Mgew0KICBiYWNrZ3JvdW5kOiB1cmwoImh0dHBzOi8vd3d3LmxhdHJvYmUuZWR1LmF1L19tZWRpYS9sYS10cm9iZS1hcGkvdjUvaW1nL2xvZ28uc3ZnIik7DQogIGJhY2tncm91bmQtc2l6ZTogY29udGFpbjsNCiAgcGFkZGluZy10b3A6IDgwcHggIWltcG9ydGFudDsNCiAgYmFja2dyb3VuZC1yZXBlYXQ6IG5vLXJlcGVhdDsNCn0NCjwvc3R5bGU+DQoNCiMjIyBEYXRhIFNjaWVuY2UgTW9kdWxlIHstfQ0KDQojIyMgVG9waWMgNUI6IFNpbXVsYXRpb25zIGluIFIgey19DQoNCjxicj4NCg0KRXhhbXBsZSBSIGNvZGUgc29sdXRpb25zIGZvciB0aGUgW0RhdGEgU2NpZW5jZSBDb21wdXRlciBMYWIgNV0oaHR0cHM6Ly9ycHVicy5jb20vTFRVX1NUTTEwMDEvRFNNQ0w1X1MpLCB3aGljaCB1c2VzIHRoZSBSIHBhY2thZ2UgYGRwbHlyYCBbQGRwbHlyXSBhbmQgcGVuZ3VpbiBkYXRhIGZyb20gdGhlIGBwYWxtZXJwZW5ndWluc2AgUiBwYWNrYWdlIFtAcGVuZ3VpbnNdLCBhcmUgcHJlc2VudGVkIGJlbG93Lg0KDQojIFNhbXBsaW5nIERpc3RyaWJ1dGlvbnMNCg0KIyMgU2FtcGxpbmcNCg0KTm8gYW5zd2VyIHJlcXVpcmVkLg0KDQojIyBUaGUgQ2VudHJhbCBMaW1pdCBUaGVvcmVtIHsjQ0xUfQ0KDQpObyBhbnN3ZXIgcmVxdWlyZWQuDQoNCiMgU2ltdWxhdGlvbnMgaW4gUg0KDQojIyB7I2Jhc2V9DQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFR9DQpzZXQuc2VlZCgxKQ0KbiA8LSAxMDANCg0KeCA8LSBybm9ybShuKQ0KYGBgDQoNCiMjDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFR9DQpoaXN0KHgsIGZyZXEgPSBGQUxTRSwgY29sID0gImNoYXJ0cmV1c2UzIiwgeGxpbSA9IGMoLTMsIDMpLA0KICAgICBtYWluID0gcGFzdGUoIkhpc3RvZ3JhbSBvZiByYW5kb20gc2FtcGxlIFxuIGZyb20gc3RhbmRhcmQgTm9ybWFsIGRpc3RyaWJ1dGlvbiwgbiA9ICIsIG4pKSANCiMgT3ZlcmxheSBzdGFuZGFyZCBub3JtYWwgY3VydmUNCmN1cnZlKGRub3JtKHgpLCBhZGQgPSBUUlVFLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpDQojIEFkZCBsaW5lIGRlbm90aW5nIHNhbXBsZSBtZWFuDQphYmxpbmUodiA9IHJvdW5kKG1lYW4oeCksIDMpLCBjb2wgPSAicmVkIiwgbHdkID0gMiwgbHR5ID0gMikNCmBgYA0KDQojIw0KDQpObyBhbnN3ZXIgcmVxdWlyZWQuDQoNCiMjIHsjc3RhcnR9DQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFR9DQpzZXQuc2VlZCgxKQ0KbiA8LSA1ICMgU3BlY2lmeSBzYW1wbGUgc2l6ZQ0KeCA8LSBybm9ybShuKSAjIFJhbmRvbWx5IGdlbmVyYXRlIG5zIHNhbXBsZXMgZnJvbSB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbg0Kbm9ybV9tZWFuIDwtIG1lYW4oeCkgIyBDb21wdXRlIHRoZSBtZWFuIG9mIHRoZSBzYW1wbGVzLCBhbmQgc3RvcmUgaXQgaW4gYSBuZXcgb2JqZWN0DQpgYGANCg0KIyMgeyNzaW1zdGFydH0NCg0KTm8gYW5zd2VyIHJlcXVpcmVkLg0KDQojIyB7I3NpbX0NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgY2FjaGUgPSBUfQ0KI1NwZWNpZnkgc2FtcGxlIHNpemUNCm5zIDwtIDUNCiAgDQojIFNwZWNpZnkgbnVtYmVyIG9mIHRpbWVzIHRvIGNvbmR1Y3QgcHJvY2VzcyAgDQp0cmlhbHMgPC0gMTAwMDANCg0KIyBjcmVhdGUgb2JqZWN0IGluIHdoaWNoIHRvIHN0b3JlIHNhbXBsZSBtZWFucyBvbmNlIHRoZXkgYXJlIGdlbmVyYXRlZA0Kbm9ybS5tZWFucyA8LSByZXAoMCwgdHJpYWxzKSAjIE5vdGUgbGVuZ3RoIGlzIGVxdWFsIHRvIHRoZSBudW1iZXIgb2YgdHJpYWxzDQoNCiMgUnVuIGZvciBsb29wICANCmZvcihpIGluIDE6dHJpYWxzKXsNCiAgICAjIFJhbmRvbWx5IGdlbmVyYXRlIG5zIHNhbXBsZXMgZnJvbSB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbg0KICAgIHggPC0gcm5vcm0obnMpIA0KICAgICMgQ29tcHV0ZSBtZWFuIG9mIHNhbXBsZXMsIGFuZCBzdG9yZSBpdCBpbiB0aGUgbm9ybS5tZWFucyBvYmplY3QsIGluIGl0aCBwb3NpdGlvbiANCiAgICBub3JtLm1lYW5zW2ldIDwtIG1lYW4oeCkgDQogICAgfQ0KYGBgDQoNCiMjIHsjdml6fQ0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCBjYWNoZSA9IFR9DQpoaXN0KG5vcm0ubWVhbnMsIGZyZXEgPSBGQUxTRSwgYnJlYWtzID0gMjAsIGNvbCA9ICJyZWQiLCANCiAgICAgeGxpbSA9IGMoLTMsIDMpLA0KICAgICB4bGFiID0gZXhwcmVzc2lvbihiYXIoeCkpLA0KICAgICBtYWluID0gcGFzdGUoIkhpc3RvZ3JhbSBvZiBtZWFucywgbiA9ICIsIG5zKSkgDQoNCmN1cnZlKGRub3JtKHgsIA0KICAgICAgbWVhbiA9IDAsIHNkID0gMS9zcXJ0KG5zKSksIA0KICAgICAgYWRkID0gVFJVRSwgY29sID0gImJsdWUiLCBsd2QgPSAyKSANCmBgYA0KDQpUaGUgc2ltdWxhdGVkIHNhbXBsZSBtZWFucyBhcmUgY2VudHJlZCBvbiB0aGUgcG9wdWxhdGlvbiBtZWFuIG9mIDAsIGJ1dCBkbyBkaXNwbGF5IHNvbWUgdmFyaWFuY2UuDQoNCiMjDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIGNhY2hlID0gVH0NCiNTcGVjaWZ5IHNhbXBsZSBzaXplDQpucyA8LSAzMA0KICANCiMgU3BlY2lmeSBudW1iZXIgb2YgdGltZXMgdG8gY29uZHVjdCBwcm9jZXNzICANCnRyaWFscyA8LSAxMDAwMA0KDQojIGNyZWF0ZSBvYmplY3QgaW4gd2hpY2ggdG8gc3RvcmUgc2FtcGxlIG1lYW5zIG9uY2UgdGhleSBhcmUgZ2VuZXJhdGVkDQpub3JtLm1lYW5zIDwtIHJlcCgwLCB0cmlhbHMpICMgTm90ZSBsZW5ndGggaXMgZXF1YWwgdG8gdGhlIG51bWJlciBvZiB0cmlhbHMNCg0KIyBSdW4gZm9yIGxvb3AgIA0KZm9yKGkgaW4gMTp0cmlhbHMpew0KICAgICMgUmFuZG9tbHkgZ2VuZXJhdGUgbnMgc2FtcGxlcyBmcm9tIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uDQogICAgeCA8LSBybm9ybShucykgDQogICAgIyBDb21wdXRlIG1lYW4gb2Ygc2FtcGxlcywgYW5kIHN0b3JlIGl0IGluIHRoZSBub3JtLm1lYW5zIG9iamVjdCwgaW4gaXRoIHBvc2l0aW9uIA0KICAgIG5vcm0ubWVhbnNbaV0gPC0gbWVhbih4KSANCiAgICB9DQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgY2FjaGUgPSBUfQ0KaGlzdChub3JtLm1lYW5zLCBmcmVxID0gRkFMU0UsIGJyZWFrcyA9IDIwLCBjb2wgPSAicmVkIiwgDQogICAgIHhsaW0gPSBjKC0zLCAzKSwNCiAgICAgeGxhYiA9IGV4cHJlc3Npb24oYmFyKHgpKSwNCiAgICAgbWFpbiA9IHBhc3RlKCJIaXN0b2dyYW0gb2YgbWVhbnMsIG4gPSAiLCBucykpIA0KDQpjdXJ2ZShkbm9ybSh4LCANCiAgICAgIG1lYW4gPSAwLCBzZCA9IDEvc3FydChucykpLCANCiAgICAgIGFkZCA9IFRSVUUsIGNvbCA9ICJibHVlIiwgbHdkID0gMikgDQpgYGANCg0KQXMgd2UgaW5jcmVhc2UgdGhlIHNhbXBsZSBzaXplLCB0aGUgdmFyaWFuY2Ugb2YgdGhlIHNhbXBsZSBtZWFucyBkZWNyZWFzZXMuDQoNCiMjDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIGNhY2hlID0gVH0NCiNTcGVjaWZ5IHNhbXBsZSBzaXplDQpucyA8LSA2MA0KICANCiMgU3BlY2lmeSBudW1iZXIgb2YgdGltZXMgdG8gY29uZHVjdCBwcm9jZXNzICANCnRyaWFscyA8LSAxMDAwMA0KDQojIGNyZWF0ZSBvYmplY3QgaW4gd2hpY2ggdG8gc3RvcmUgc2FtcGxlIG1lYW5zIG9uY2UgdGhleSBhcmUgZ2VuZXJhdGVkDQpub3JtLm1lYW5zIDwtIHJlcCgwLCB0cmlhbHMpICMgTm90ZSBsZW5ndGggaXMgZXF1YWwgdG8gdGhlIG51bWJlciBvZiB0cmlhbHMNCg0KIyBSdW4gZm9yIGxvb3AgIA0KZm9yKGkgaW4gMTp0cmlhbHMpew0KICAgICMgUmFuZG9tbHkgZ2VuZXJhdGUgbnMgc2FtcGxlcyBmcm9tIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uDQogICAgeCA8LSBybm9ybShucykgDQogICAgIyBDb21wdXRlIG1lYW4gb2Ygc2FtcGxlcywgYW5kIHN0b3JlIGl0IGluIHRoZSBub3JtLm1lYW5zIG9iamVjdCwgaW4gaXRoIHBvc2l0aW9uIA0KICAgIG5vcm0ubWVhbnNbaV0gPC0gbWVhbih4KSANCiAgICB9DQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVH0NCmhpc3Qobm9ybS5tZWFucywgZnJlcSA9IEZBTFNFLCBicmVha3MgPSAyMCwgY29sID0gInJlZCIsIA0KICAgICB4bGltID0gYygtMywgMyksDQogICAgIHhsYWIgPSBleHByZXNzaW9uKGJhcih4KSksDQogICAgIG1haW4gPSBwYXN0ZSgiSGlzdG9ncmFtIG9mIG1lYW5zLCBuID0gIiwgbnMpKSANCg0KY3VydmUoZG5vcm0oeCwgDQogICAgICBtZWFuID0gMCwgc2QgPSAxL3NxcnQobnMpKSwgDQogICAgICBhZGQgPSBUUlVFLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpIA0KYGBgDQoNCkZvciBhIHNhbXBsZSBzaXplIG9mIDYwLCB0aGUgdmFyaWFuY2Ugb2YgdGhlIHNhbXBsZSBtZWFucyBpcyB2ZXJ5IGxvdywgcHJvdmlkaW5nIHVzIHdpdGggYW4gYWNjdXJhdGUgZXN0aW1hdGUgb2YgdGhlIHBvcHVsYXRpb24gbWVhbi4NCg0KIyBDTFQgU2ltdWxhdGlvbiAtIEV4cG9uZW50aWFsIERpc3RyaWJ1dGlvbg0KDQojIw0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBUfQ0Kc2V0LnNlZWQoMSkNCm4gPC0gMTAwDQpyYXRlID0gMTANCnggPC0gcmV4cChuLCByYXRlID0gcmF0ZSkNCmBgYA0KDQojIw0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBUfQ0KaGlzdCh4LCBmcmVxID0gRkFMU0UsIGNvbCA9ICJjaGFydHJldXNlMyIsIHhsaW0gPSBjKDAsIDAuNSksDQogICAgIG1haW4gPSBwYXN0ZSgiSGlzdG9ncmFtIG9mIHJhbmRvbSBzYW1wbGUgXG4gZnJvbSBFeHBvbmVudGlhbCBkaXN0cmlidXRpb24sIG4gPSAiLCBuKSkNCg0KY3VydmUoZG5vcm0oeCwgMS9yYXRlLCAxL3JhdGUpLCBhZGQgPSBUUlVFLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpDQpgYGANCg0KIyMNCg0KTm8gYW5zd2VyIHJlcXVpcmVkLg0KDQojIyB7I2V4cHNpbX0NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgY2FjaGUgPSBUfQ0KI1NwZWNpZnkgc2FtcGxlIHNpemUNCm5zIDwtIDUNCiAgDQojIFNwZWNpZnkgcmF0ZQ0KcmF0ZSA9IDEwDQoNCiMgU3BlY2lmeSBudW1iZXIgb2YgdGltZXMgdG8gY29uZHVjdCBwcm9jZXNzICANCnRyaWFscyA8LSAxMDAwMA0KDQojIGNyZWF0ZSBvYmplY3QgaW4gd2hpY2ggdG8gc3RvcmUgc2FtcGxlIG1lYW5zIG9uY2UgdGhleSBhcmUgZ2VuZXJhdGVkDQpub3JtLm1lYW5zIDwtIHJlcCgwLCB0cmlhbHMpICMgTm90ZSBsZW5ndGggaXMgZXF1YWwgdG8gdGhlIG51bWJlciBvZiB0cmlhbHMNCg0KIyBSdW4gZm9yIGxvb3AgIA0KZm9yKGkgaW4gMTp0cmlhbHMpew0KICAgICMgUmFuZG9tbHkgZ2VuZXJhdGUgbnMgc2FtcGxlcyBmcm9tIHRoZSBleHBvbmVudGlhbCBkaXN0cmlidXRpb24NCiAgICB4IDwtIHJleHAobnMsIHJhdGUgPSByYXRlKQ0KICAgICMgQ29tcHV0ZSBtZWFuIG9mIHNhbXBsZXMsIGFuZCBzdG9yZSBpdCBpbiB0aGUgbm9ybS5tZWFucyBvYmplY3QsIGluIGl0aCBwb3NpdGlvbiANCiAgICBub3JtLm1lYW5zW2ldIDwtIG1lYW4oeCkgDQogICAgfQ0KYGBgDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIGNhY2hlID0gVH0NCmhpc3Qobm9ybS5tZWFucywgZnJlcSA9IEZBTFNFLCBicmVha3MgPSAyMCwgY29sID0gInJlZCIsIA0KICAgICB4bGltID0gYygwLCAwLjQpLA0KICAgICB4bGFiID0gZXhwcmVzc2lvbihiYXIoeCkpLA0KICAgICBtYWluID0gcGFzdGUoIkhpc3RvZ3JhbSBvZiBtZWFucywgbiA9ICIsIG5zKSkgDQoNCmN1cnZlKGRub3JtKHgsIG1lYW4gPSAxL3JhdGUsIHNkID0gMS9yYXRlL3NxcnQobnMpKSwgYWRkID0gVFJVRSwNCiAgICAgICAgY29sID0gImJsdWUiLCBsd2QgPSAyKQ0KYGBgDQoNCkhlcmUgd2UgdXNlIGFuIHgtYXhpcyByYW5nZSBvZiAwIHRvIDAuNC4NCg0KIyMNCg0KVGhlIHJlc3VsdGluZyBkYXRhIHNldCBpcyBub3QgYXMgc2tld2VkIGFzIHRoZSB1bmRlcmx5aW5nIGRpc3RyaWJ1dGlvbiwgYnV0IHRoZXJlIGlzIHN0aWxsIGEgbm90aWNlYWJsZSBza2V3ICh0aGlzIGlzIGJlY2F1c2Ugb2YgdGhlIGxvdyBzYW1wbGUgc2l6ZSkuDQoNCiMjDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIGNhY2hlID0gVH0NCiNTcGVjaWZ5IHNhbXBsZSBzaXplDQpucyA8LSAzMA0KICANCiMgU3BlY2lmeSByYXRlDQpyYXRlID0gMTANCg0KIyBTcGVjaWZ5IG51bWJlciBvZiB0aW1lcyB0byBjb25kdWN0IHByb2Nlc3MgIA0KdHJpYWxzIDwtIDEwMDAwDQoNCiMgY3JlYXRlIG9iamVjdCBpbiB3aGljaCB0byBzdG9yZSBzYW1wbGUgbWVhbnMgb25jZSB0aGV5IGFyZSBnZW5lcmF0ZWQNCm5vcm0ubWVhbnMgPC0gcmVwKDAsIHRyaWFscykgIyBOb3RlIGxlbmd0aCBpcyBlcXVhbCB0byB0aGUgbnVtYmVyIG9mIHRyaWFscw0KDQojIFJ1biBmb3IgbG9vcCAgDQpmb3IoaSBpbiAxOnRyaWFscyl7DQogICAgIyBSYW5kb21seSBnZW5lcmF0ZSBucyBzYW1wbGVzIGZyb20gdGhlIGV4cG9uZW50aWFsIGRpc3RyaWJ1dGlvbg0KICAgIHggPC0gcmV4cChucywgcmF0ZSA9IHJhdGUpDQogICAgIyBDb21wdXRlIG1lYW4gb2Ygc2FtcGxlcywgYW5kIHN0b3JlIGl0IGluIHRoZSBub3JtLm1lYW5zIG9iamVjdCwgaW4gaXRoIHBvc2l0aW9uIA0KICAgIG5vcm0ubWVhbnNbaV0gPC0gbWVhbih4KSANCiAgICB9DQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgY2FjaGUgPSBUfQ0KaGlzdChub3JtLm1lYW5zLCBmcmVxID0gRkFMU0UsIGJyZWFrcyA9IDIwLCBjb2wgPSAicmVkIiwgDQogICAgIHhsaW0gPSBjKDAsIDAuMiksDQogICAgIHhsYWIgPSBleHByZXNzaW9uKGJhcih4KSksDQogICAgIG1haW4gPSBwYXN0ZSgiSGlzdG9ncmFtIG9mIG1lYW5zLCBuID0gIiwgbnMpKSANCg0KY3VydmUoZG5vcm0oeCwgbWVhbiA9IDEvcmF0ZSwgc2QgPSAxL3JhdGUvc3FydChucykpLCBhZGQgPSBUUlVFLA0KICAgICAgICBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpDQpgYGANCg0KSGVyZSwgd2UgY2hhbmdlIHRoZSB4IGF4aXMgcmFuZ2UgdG8gYmUgZnJvbSAwIHRvIDAuMi4gVGhlIHNhbXBsZSBtZWFucyBub3cgZGlzcGxheSB2ZXJ5IGxpdHRsZSB2YXJpYW5jZSwgYW5kIHByb3ZpZGUgYSBtdWNoIG1vcmUgYWNjdXJhdGUgZXN0aW1hdGUgb2YgdGhlIHBvcHVsYXRpb24gbWVhbiBvZiAwLjEuIE5vdGUgdGhhdCB0aGUgTm9ybWFsIGRlbnNpdHkgY3VydmUgYWxzbyBmaXRzIHRoZSBkYXRhIHdlbGwuIFRoZXNlIHJlc3VsdHMgYXJlIGR1ZSB0byB0aGUgc2FtcGxlIHNpemUgYmVpbmcgYmlnZ2VyICgzMCBpbnN0ZWFkIG9mIDUpLg0KDQojIw0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCBjYWNoZSA9IFR9DQojU3BlY2lmeSBzYW1wbGUgc2l6ZQ0KbnMgPC0gNjANCiAgDQojIFNwZWNpZnkgcmF0ZQ0KcmF0ZSA9IDEwDQoNCiMgU3BlY2lmeSBudW1iZXIgb2YgdGltZXMgdG8gY29uZHVjdCBwcm9jZXNzICANCnRyaWFscyA8LSAxMDAwMA0KDQojIGNyZWF0ZSBvYmplY3QgaW4gd2hpY2ggdG8gc3RvcmUgc2FtcGxlIG1lYW5zIG9uY2UgdGhleSBhcmUgZ2VuZXJhdGVkDQpub3JtLm1lYW5zIDwtIHJlcCgwLCB0cmlhbHMpICMgTm90ZSBsZW5ndGggaXMgZXF1YWwgdG8gdGhlIG51bWJlciBvZiB0cmlhbHMNCg0KIyBSdW4gZm9yIGxvb3AgIA0KZm9yKGkgaW4gMTp0cmlhbHMpew0KICAgICMgUmFuZG9tbHkgZ2VuZXJhdGUgbnMgc2FtcGxlcyBmcm9tIHRoZSBleHBvbmVudGlhbCBkaXN0cmlidXRpb24NCiAgICB4IDwtIHJleHAobnMsIHJhdGUgPSByYXRlKQ0KICAgICMgQ29tcHV0ZSBtZWFuIG9mIHNhbXBsZXMsIGFuZCBzdG9yZSBpdCBpbiB0aGUgbm9ybS5tZWFucyBvYmplY3QsIGluIGl0aCBwb3NpdGlvbiANCiAgICBub3JtLm1lYW5zW2ldIDwtIG1lYW4oeCkgDQogICAgfQ0KYGBgDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIGNhY2hlID0gVH0NCmhpc3Qobm9ybS5tZWFucywgZnJlcSA9IEZBTFNFLCBicmVha3MgPSAyMCwgY29sID0gInJlZCIsIA0KICAgICB4bGltID0gYygwLCAwLjIpLA0KICAgICB4bGFiID0gZXhwcmVzc2lvbihiYXIoeCkpLA0KICAgICBtYWluID0gcGFzdGUoIkhpc3RvZ3JhbSBvZiBtZWFucywgbiA9ICIsIG5zKSkgDQoNCmN1cnZlKGRub3JtKHgsIG1lYW4gPSAxL3JhdGUsIHNkID0gMS9yYXRlL3NxcnQobnMpKSwgYWRkID0gVFJVRSwNCiAgICAgICAgY29sID0gImJsdWUiLCBsd2QgPSAyKQ0KYGBgDQoNCkZvciBhIHNhbXBsZSBzaXplIG9mIDYwLCB0aGUgcmVzdWx0YW50IHNhbXBsZSBtZWFucyBhcmUgbW9yZSBhY2N1cmF0ZSwgYW5kIHRoZSBjb3JyZXNwb25kaW5nIG5vcm1hbCBkZW5zaXR5IGN1cnZlIGZpdHMgdGhlc2UgZGlzdHJpYnV0aW9uIG9mIHRoZXNlIHNhbXBsZSBtZWFucyBleHRyZW1lbHkgd2VsbCAoYXMgZXhwZWN0ZWQgdmlhIHRoZSBDTFQpLg0KDQojIENMVCBTaW11bGF0aW9uIC0gQmVybm91bGxpIERpc3RyaWJ1dGlvbg0KDQojIw0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBUfQ0Kc2V0LnNlZWQoMSkNCm4gPC0gMTAwDQpwID0gMC4zDQp4IDwtIHJiaW5vbShuLCAxLCBwKQ0KDQpoaXN0KHgsIGZyZXEgPSBGQUxTRSwgY29sID0gImNoYXJ0cmV1c2UzIiwgeGxpbSA9IGMoMCwgMSksDQogICAgIG1haW4gPSBwYXN0ZSgiSGlzdG9ncmFtIG9mIHJhbmRvbSBzYW1wbGUgXG4gZnJvbSBCZXJub3VsbGkgZGlzdHJpYnV0aW9uLCBuID0gIiwgbikpIA0KY3VydmUoZG5vcm0oeCwgcCwgc2QgPSBzcXJ0KHAqKDEgLSBwKSkpLCBhZGQgPSBUUlVFLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpDQpgYGANCg0KIyMNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgY2FjaGUgPSBUfQ0KI1NwZWNpZnkgc2FtcGxlIHNpemUNCm5zIDwtIDUNCiAgDQojIFNwZWNpZnkgc3VjY2VzcyByYXRlDQpwID0gMC4zDQoNCiMgU3BlY2lmeSBudW1iZXIgb2YgdGltZXMgdG8gY29uZHVjdCBwcm9jZXNzICANCnRyaWFscyA8LSAxMDAwMA0KDQojIGNyZWF0ZSBvYmplY3QgaW4gd2hpY2ggdG8gc3RvcmUgc2FtcGxlIG1lYW5zIG9uY2UgdGhleSBhcmUgZ2VuZXJhdGVkDQpub3JtLm1lYW5zIDwtIHJlcCgwLCB0cmlhbHMpICMgTm90ZSBsZW5ndGggaXMgZXF1YWwgdG8gdGhlIG51bWJlciBvZiB0cmlhbHMNCg0KIyBSdW4gZm9yIGxvb3AgIA0KZm9yKGkgaW4gMTp0cmlhbHMpew0KICAgICMgUmFuZG9tbHkgZ2VuZXJhdGUgbnMgc2FtcGxlcyBmcm9tIHRoZSBCZXJub3VsbGkgZGlzdHJpYnV0aW9uDQogICAgeCA8LSByYmlub20obnMsIDEsIHApDQogICAgIyBDb21wdXRlIG1lYW4gb2Ygc2FtcGxlcywgYW5kIHN0b3JlIGl0IGluIHRoZSBub3JtLm1lYW5zIG9iamVjdCwgaW4gaXRoIHBvc2l0aW9uIA0KICAgIG5vcm0ubWVhbnNbaV0gPC0gbWVhbih4KSANCiAgICB9DQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgY2FjaGUgPSBUfQ0KaGlzdChub3JtLm1lYW5zLCBmcmVxID0gRkFMU0UsIGJyZWFrcyA9IDIwLCBjb2wgPSAicmVkIiwgDQogICAgIHhsaW0gPSBjKDAsIDEpLA0KICAgICB4bGFiID0gZXhwcmVzc2lvbihiYXIoeCkpLA0KICAgICBtYWluID0gcGFzdGUoIkhpc3RvZ3JhbSBvZiBtZWFucywgbiA9ICIsIG5zKSkgDQoNCiMgU2V0IG11IGFuZCBzaWdtYSBmb3IgdGhlIGFwcHJveGltYXRpbmcgbm9ybWFsIGRpc3RyaWJ1dGlvbg0KbXUgPC0gcA0Kc2lnbWEgPC0gc3FydChwKigxIC0gcCkpDQogIA0KIyBPdmVybGF5IHRoZSBub3JtYWwgZGVuc2l0eQ0KY3VydmUoZG5vcm0oeCwgbXUsIHNpZ21hL3NxcnQobnMpKSwgYWRkID0gVFJVRSwgY29sID0gImJsdWUiLCBsd2QgPSAyKQ0KYGBgDQoNCiMjDQoNClRoZSBwbG90IG9mIHRoZSBzYW1wbGUgbWVhbnMgaXMgY2xlYXJseSBub3Qgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuDQoNCiMjDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIGNhY2hlID0gVH0NCiNTcGVjaWZ5IHNhbXBsZSBzaXplDQpucyA8LSAzMA0KICANCiMgU3BlY2lmeSBzdWNjZXNzIHJhdGUNCnAgPSAwLjMNCg0KIyBTcGVjaWZ5IG51bWJlciBvZiB0aW1lcyB0byBjb25kdWN0IHByb2Nlc3MgIA0KdHJpYWxzIDwtIDEwMDAwDQoNCiMgY3JlYXRlIG9iamVjdCBpbiB3aGljaCB0byBzdG9yZSBzYW1wbGUgbWVhbnMgb25jZSB0aGV5IGFyZSBnZW5lcmF0ZWQNCm5vcm0ubWVhbnMgPC0gcmVwKDAsIHRyaWFscykgIyBOb3RlIGxlbmd0aCBpcyBlcXVhbCB0byB0aGUgbnVtYmVyIG9mIHRyaWFscw0KDQojIFJ1biBmb3IgbG9vcCAgDQpmb3IoaSBpbiAxOnRyaWFscyl7DQogICAgIyBSYW5kb21seSBnZW5lcmF0ZSBucyBzYW1wbGVzIGZyb20gdGhlIEJlcm5vdWxsaSBkaXN0cmlidXRpb24NCiAgICB4IDwtIHJiaW5vbShucywgMSwgcCkNCiAgICAjIENvbXB1dGUgbWVhbiBvZiBzYW1wbGVzLCBhbmQgc3RvcmUgaXQgaW4gdGhlIG5vcm0ubWVhbnMgb2JqZWN0LCBpbiBpdGggcG9zaXRpb24gDQogICAgbm9ybS5tZWFuc1tpXSA8LSBtZWFuKHgpIA0KICAgIH0NCmBgYA0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCBjYWNoZSA9IFR9DQpoaXN0KG5vcm0ubWVhbnMsIGZyZXEgPSBGQUxTRSwgYnJlYWtzID0gMjAsIGNvbCA9ICJyZWQiLCANCiAgICAgeGxpbSA9IGMoMCwgMSksDQogICAgIHhsYWIgPSBleHByZXNzaW9uKGJhcih4KSksDQogICAgIG1haW4gPSBwYXN0ZSgiSGlzdG9ncmFtIG9mIG1lYW5zLCBuID0gIiwgbnMpKSANCg0KIyBTZXQgbXUgYW5kIHNpZ21hIGZvciB0aGUgYXBwcm94aW1hdGluZyBub3JtYWwgZGlzdHJpYnV0aW9uDQptdSA8LSBwDQpzaWdtYSA8LSBzcXJ0KHAqKDEgLSBwKSkNCiAgDQojIE92ZXJsYXkgdGhlIG5vcm1hbCBkZW5zaXR5DQpjdXJ2ZShkbm9ybSh4LCBtdSwgc2lnbWEvc3FydChucykpLCBhZGQgPSBUUlVFLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpDQpgYGANCg0KQWxsIG9mIGEgc3VkZGVuLCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBzYW1wbGUgbWVhbnMgYmVnaW5zIHRvIGxvb2sgbXVjaCBtb3JlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLg0KDQojIw0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCBjYWNoZSA9IFR9DQojU3BlY2lmeSBzYW1wbGUgc2l6ZQ0KbnMgPC0gNjANCiAgDQojIFNwZWNpZnkgc3VjY2VzcyByYXRlDQpwID0gMC4zDQoNCiMgU3BlY2lmeSBudW1iZXIgb2YgdGltZXMgdG8gY29uZHVjdCBwcm9jZXNzICANCnRyaWFscyA8LSAxMDAwMA0KDQojIGNyZWF0ZSBvYmplY3QgaW4gd2hpY2ggdG8gc3RvcmUgc2FtcGxlIG1lYW5zIG9uY2UgdGhleSBhcmUgZ2VuZXJhdGVkDQpub3JtLm1lYW5zIDwtIHJlcCgwLCB0cmlhbHMpICMgTm90ZSBsZW5ndGggaXMgZXF1YWwgdG8gdGhlIG51bWJlciBvZiB0cmlhbHMNCg0KIyBSdW4gZm9yIGxvb3AgIA0KZm9yKGkgaW4gMTp0cmlhbHMpew0KICAgICMgUmFuZG9tbHkgZ2VuZXJhdGUgbnMgc2FtcGxlcyBmcm9tIHRoZSBCZXJub3VsbGkgZGlzdHJpYnV0aW9uDQogICAgeCA8LSByYmlub20obnMsIDEsIHApDQogICAgIyBDb21wdXRlIG1lYW4gb2Ygc2FtcGxlcywgYW5kIHN0b3JlIGl0IGluIHRoZSBub3JtLm1lYW5zIG9iamVjdCwgaW4gaXRoIHBvc2l0aW9uIA0KICAgIG5vcm0ubWVhbnNbaV0gPC0gbWVhbih4KSANCiAgICB9DQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgY2FjaGUgPSBUfQ0KaGlzdChub3JtLm1lYW5zLCBmcmVxID0gRkFMU0UsIGJyZWFrcyA9IDIwLCBjb2wgPSAicmVkIiwgDQogICAgIHhsaW0gPSBjKDAsIDEpLA0KICAgICB4bGFiID0gZXhwcmVzc2lvbihiYXIoeCkpLA0KICAgICBtYWluID0gcGFzdGUoIkhpc3RvZ3JhbSBvZiBtZWFucywgbiA9ICIsIG5zKSkgDQoNCiMgU2V0IG11IGFuZCBzaWdtYSBmb3IgdGhlIGFwcHJveGltYXRpbmcgbm9ybWFsIGRpc3RyaWJ1dGlvbg0KbXUgPC0gcA0Kc2lnbWEgPC0gc3FydChwKigxIC0gcCkpDQogIA0KIyBPdmVybGF5IHRoZSBub3JtYWwgZGVuc2l0eQ0KY3VydmUoZG5vcm0oeCwgbXUsIHNpZ21hL3NxcnQobnMpKSwgYWRkID0gVFJVRSwgY29sID0gImJsdWUiLCBsd2QgPSAyKQ0KYGBgDQoNCkZvciBhIHNhbXBsZSBzaXplIG9mIDYwLCB0aGUgc2FtcGxlIG1lYW5zIGFyZSBub3cgbG9va2luZyBhcyBpZiB0aGV5IGFsbW9zdCBjb3VsZCBoYXZlIGJlZW4gZ2VuZXJhdGVkIGZyb20gYSBub3JtYWwgZGlzdHJpYnV0aW9uLCB3aGljaCBpcyBhbWF6aW5nIGdpdmVuIHRoZXkgYXJlIG9idGFpbmVkIGZyb20gZGF0YSBnZW5lcmF0ZWQgZnJvbSBhIGRpc2NyZXRlIGRpc3RyaWJ1dGlvbi4NCg0KDQojIEV4dGVuc2lvbiAtIEF2ZXJhZ2UgRGlhbW9uZCBQcmljZXMNCg0KVGhlIFIgY29kZSBiZWxvdyBzaG91bGQgaGF2ZSBiZWVuIHJ1bjoNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCmluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KYGBgDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUiLCBldmFsID0gVCwgaW5jbHVkZSA9IEZ9DQpsaWJyYXJ5KGdncGxvdDIpDQpgYGANCg0KIyMNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVH0NCmhpc3QoZGlhbW9uZHMkcHJpY2UsIGNvbCA9ICJza3libHVlIiwgeGxhYiA9ICJEaWFtb25kIFByaWNlICgkKSIsDQogICAgIG1haW4gPSAiSGlzdG9ncmFtIG9mIERpYW1vbmQgUHJpY2VzICgkKSIsIGZyZXEgPSBGKQ0KYGBgDQoNCiMjIHsjZGlhbW9uZHNpbX0NCg0KRXhhbXBsZSBSIGNvZGUgaXMgcHJvdmlkZWQgYmVsb3c6DQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIGNhY2hlID0gVH0NCiNTcGVjaWZ5IHNhbXBsZSBzaXplDQpucyA8LSA1DQogIA0KIyBTcGVjaWZ5IG51bWJlciBvZiB0aW1lcyB0byBjb25kdWN0IHByb2Nlc3MgIA0KdHJpYWxzIDwtIDEwMA0KDQojIGNyZWF0ZSBvYmplY3QgaW4gd2hpY2ggdG8gc3RvcmUgc2FtcGxlIG1lYW5zIG9uY2UgdGhleSBhcmUgZ2VuZXJhdGVkDQpub3JtLm1lYW5zIDwtIHJlcCgwLCB0cmlhbHMpICMgTm90ZSBsZW5ndGggaXMgZXF1YWwgdG8gdGhlIG51bWJlciBvZiB0cmlhbHMNCg0KIyBSdW4gZm9yIGxvb3AgIA0KZm9yKGkgaW4gMTp0cmlhbHMpew0KICAgICMgUmFuZG9tbHkgc2FtcGxlIG5zIHZhbHVlcyBmcm9tIHRoZSBkaWFtb25kcyBkYXRhIHNldA0KICAgIHggPC0gc2FtcGxlKGRpYW1vbmRzJHByaWNlLCBucykNCiAgICAjIENvbXB1dGUgbWVhbiBvZiBzYW1wbGVzLCBhbmQgc3RvcmUgaXQgaW4gdGhlIG5vcm0ubWVhbnMgb2JqZWN0LCBpbiBpdGggcG9zaXRpb24gDQogICAgbm9ybS5tZWFuc1tpXSA8LSBtZWFuKHgpIA0KICAgIH0NCmBgYA0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCBjYWNoZSA9IFR9DQpoaXN0KG5vcm0ubWVhbnMsIGZyZXEgPSBGQUxTRSwgY29sID0gInNreWJsdWUiLA0KICAgICB4bGFiID0gZXhwcmVzc2lvbihiYXIoeCkpLA0KICAgICBtYWluID0gcGFzdGUoIkhpc3RvZ3JhbSBvZiBtZWFucywgbiA9ICIsIG5zKSkgDQpgYGANCg0KV2Ugbm90ZSB0aGF0IHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHNhbXBsZSBtZWFucyBpcyBxdWl0ZSBza2V3ZWQuDQoNCiMjIHsjZGlhbW9uZHNpbWxhcmdlfQ0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCBjYWNoZSA9IFR9DQojU3BlY2lmeSBzYW1wbGUgc2l6ZQ0KbnMgPC0gMzANCiAgDQojIFNwZWNpZnkgbnVtYmVyIG9mIHRpbWVzIHRvIGNvbmR1Y3QgcHJvY2VzcyAgDQp0cmlhbHMgPC0gMTAwDQoNCiMgY3JlYXRlIG9iamVjdCBpbiB3aGljaCB0byBzdG9yZSBzYW1wbGUgbWVhbnMgb25jZSB0aGV5IGFyZSBnZW5lcmF0ZWQNCm5vcm0ubWVhbnMyIDwtIHJlcCgwLCB0cmlhbHMpICMgTm90ZSBsZW5ndGggaXMgZXF1YWwgdG8gdGhlIG51bWJlciBvZiB0cmlhbHMNCg0KIyBSdW4gZm9yIGxvb3AgIA0KZm9yKGkgaW4gMTp0cmlhbHMpew0KICAgICMgUmFuZG9tbHkgc2FtcGxlIG5zIHZhbHVlcyBmcm9tIHRoZSBkaWFtb25kcyBkYXRhIHNldA0KICAgIHggPC0gc2FtcGxlKGRpYW1vbmRzJHByaWNlLCBucykNCiAgICAjIENvbXB1dGUgbWVhbiBvZiBzYW1wbGVzLCBhbmQgc3RvcmUgaXQgaW4gdGhlIG5vcm0ubWVhbnMgb2JqZWN0LCBpbiBpdGggcG9zaXRpb24gDQogICAgbm9ybS5tZWFuczJbaV0gPC0gbWVhbih4KSANCiAgICB9DQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgY2FjaGUgPSBUfQ0KaGlzdChub3JtLm1lYW5zMiwgZnJlcSA9IEZBTFNFLCBjb2wgPSAic2t5Ymx1ZSIsDQogICAgIHhsYWIgPSBleHByZXNzaW9uKGJhcih4KSksDQogICAgIG1haW4gPSBwYXN0ZSgiSGlzdG9ncmFtIG9mIG1lYW5zLCBuID0gIiwgbnMpKSANCmBgYA0KDQpCeSBpbmNyZWFzaW5nIG91ciBzYW1wbGUgc2l6ZSB0byAzMCwgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgc2FtcGxlIG1lYW5zIG5vdyBhcHBlYXJzIGFwcHJveGltYXRlbHkgbm9ybWFsIChpLmUuIHN5bW1ldHJpYykuIFRoaXMgcmVzdWx0cyBhZGhlcmVzIHdpdGggdGhlIENlbnRyYWwgTGltaXQgVGhlb3JlbS4NCg0KPGJyPg0KDQojIyMjIEdyZWF0IGpvYiwgdGhhdCdzIGV2ZXJ5dGhpbmcgZm9yIHRvZGF5ISAjIyMjIHstfQ0KDQpIb3BlZnVsbHksIHRoaXMgY29tcHV0ZXIgbGFiIGhhcyBoZWxwZWQgY2VtZW50IHlvdXIgdW5kZXJzdGFuZGluZyBvZiB0aGUgQ2VudHJhbCBMaW1pdCBUaGVvcmVtLg0KDQo8YnI+DQoNCiMgUmVmZXJlbmNlcyB7LSAjUmVmfQ0KPGRpdiBpZD0icmVmcyI+PC9kaXY+DQoNCjxicj4NCg0KPGZvbnQgY29sb3IgPSAiZ3JleSI+DQpUaGVzZSBub3RlcyBoYXZlIGJlZW4gcHJlcGFyZWQgYnkgUnVwZXJ0IEt1dmVrZSBhbmQgQW1hbmRhIFNoYWtlci4gVGhlIGNvcHlyaWdodCBmb3IgdGhlIG1hdGVyaWFsIGluIHRoZXNlIG5vdGVzIHJlc2lkZXMgd2l0aCB0aGUgYXV0aG9ycyBuYW1lZCBhYm92ZSwgd2l0aCB0aGUgRGVwYXJ0bWVudCBvZiBNYXRoZW1hdGljYWwgYW5kIFBoeXNpY2FsIFNjaWVuY2VzIGFuZCB3aXRoIExhIFRyb2JlIFVuaXZlcnNpdHkuIENvcHlyaWdodCBpbiB0aGlzIHdvcmsgaXMgdmVzdGVkIGluIExhIFRyb2JlIFVuaXZlcnNpdHkgaW5jbHVkaW5nIGFsbCBMYSBUcm9iZSBVbml2ZXJzaXR5IGJyYW5kaW5nIGFuZCBuYW1pbmcuIFVubGVzcyBvdGhlcndpc2Ugc3RhdGVkLCBtYXRlcmlhbCB3aXRoaW4gdGhpcyB3b3JrIGlzIGxpY2Vuc2VkIHVuZGVyIGEgQ3JlYXRpdmUgQ29tbW9ucyBBdHRyaWJ1dGlvbi1Ob24gQ29tbWVyY2lhbC1Ob24gRGVyaXZhdGl2ZXMgTGljZW5zZSANCjxhIGhyZWYgPSAiaHR0cHM6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LW5jLW5kLzQuMC9DQyIgdGFyZ2V0PSJfYmxhbmsiPiBCWS1OQy1ORC4gPC9hPg0KPC9mb250Pg==