Data Science Stream

Topic 5B: Simulations in R


Example R code solutions for the Data Science Computer Lab 5, which uses the R packages dplyr (Wickham et al. 2021) and ggplot2 (Wickham et al. 2022), 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

No answer required.

2.5 for loops

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, store 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, store 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, store 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 The Rate Parameter and Population Mean

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

No answer required.

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 more symmetric and closer to that of a normal distribution. This results adheres with the Central Limit Theorem. Further increases in the sample size would result in a sample mean distribution that even more closely matched that of a normal distribution.


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., W. Chang, L. Henry, T. L. Pedersen, K. Takahashi, C. Wilke, K. Woo, H. Yutani, D. Dunnington, and RStudio. 2022. ggplot2: Create Elegant Data Visualisations Using the Grammar of Graphics. https://cran.r-project.org/web/packages/ggplot2/index.html.
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+DQoNCiMjIyBEYXRhIFNjaWVuY2UgU3RyZWFtIHstfQ0KDQojIyMgVG9waWMgNUI6IFNpbXVsYXRpb25zIGluIFIgey19DQoNCjxicj4NCg0KRXhhbXBsZSBSIGNvZGUgc29sdXRpb25zIGZvciB0aGUgW0RhdGEgU2NpZW5jZSBDb21wdXRlciBMYWIgNV0oaHR0cHM6Ly9ycHVicy5jb20vTFRVX1NUTTEwMDEvRFNNQ0w1KSwgd2hpY2ggdXNlcyB0aGUgUiBwYWNrYWdlcyBgZHBseXJgIFtAZHBseXJdIGFuZCBgZ2dwbG90MmAgW0BnZ3Bsb3QyXSwgYW5kIHBlbmd1aW4gZGF0YSBmcm9tIHRoZSBgcGFsbWVycGVuZ3VpbnNgIFIgcGFja2FnZSBbQHBlbmd1aW5zXSwgYXJlIHByZXNlbnRlZCBiZWxvdy4NCg0KIyBTYW1wbGluZyBEaXN0cmlidXRpb25zDQojIyBTYW1wbGluZw0KDQpObyBhbnN3ZXIgcmVxdWlyZWQuDQoNCiMjIFRoZSBDZW50cmFsIExpbWl0IFRoZW9yZW0geyNDTFR9DQoNCk5vIGFuc3dlciByZXF1aXJlZC4NCg0KIyBTaW11bGF0aW9ucyBpbiBSDQoNCiMjIHsjYmFzZX0NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVH0NCnNldC5zZWVkKDEpDQpuIDwtIDEwMA0KeCA8LSBybm9ybShuKQ0KYGBgDQoNCiMjDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFR9DQpoaXN0KHgsIGZyZXEgPSBGQUxTRSwgY29sID0gImNoYXJ0cmV1c2UzIiwgeGxpbSA9IGMoLTMsIDMpLA0KICAgICBtYWluID0gcGFzdGUoIkhpc3RvZ3JhbSBvZiByYW5kb20gc2FtcGxlIFxuIGZyb20gc3RhbmRhcmQgTm9ybWFsIGRpc3RyaWJ1dGlvbiwgbiA9ICIsIG4pKSANCiMgT3ZlcmxheSBzdGFuZGFyZCBub3JtYWwgY3VydmUNCmN1cnZlKGRub3JtKHgpLCBhZGQgPSBUUlVFLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpDQojIEFkZCBsaW5lIGRlbm90aW5nIHNhbXBsZSBtZWFuDQphYmxpbmUodiA9IHJvdW5kKG1lYW4oeCksIDMpLCBjb2wgPSAicmVkIiwgbHdkID0gMiwgbHR5ID0gMikNCmBgYA0KDQojIw0KDQpObyBhbnN3ZXIgcmVxdWlyZWQuDQoNCiMjIHsjc3RhcnR9DQoNCk5vIGFuc3dlciByZXF1aXJlZC4NCg0KIyMgYGZvciBsb29wc2AgeyNzaW1zdGFydH0NCg0KTm8gYW5zd2VyIHJlcXVpcmVkLg0KDQojIyB7I3NpbX0NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgY2FjaGUgPSBUfQ0KI1NwZWNpZnkgc2FtcGxlIHNpemUNCm5zIDwtIDUNCg0KIyBTcGVjaWZ5IG51bWJlciBvZiB0aW1lcyB0byBjb25kdWN0IHByb2Nlc3MgIA0KdHJpYWxzIDwtIDEwMDAwDQoNCiMgY3JlYXRlIG9iamVjdCBpbiB3aGljaCB0byBzdG9yZSBzYW1wbGUgbWVhbnMgb25jZSB0aGV5IGFyZSBnZW5lcmF0ZWQNCm5vcm0ubWVhbnMgPC0gcmVwKDAsIHRyaWFscykgIyBOb3RlIGxlbmd0aCBpcyBlcXVhbCB0byB0aGUgbnVtYmVyIG9mIHRyaWFscw0KDQojIFJ1biBmb3IgbG9vcCAgDQpmb3IoaSBpbiAxOnRyaWFscyl7DQogICAgIyBSYW5kb21seSBnZW5lcmF0ZSBucyBzYW1wbGVzIGZyb20gdGhlIG5vcm1hbCBkaXN0cmlidXRpb24NCiAgICB4IDwtIHJub3JtKG5zKSANCiAgICAjIENvbXB1dGUgbWVhbiBvZiBzYW1wbGVzLCBzdG9yZSBpbiB0aGUgbm9ybS5tZWFucyBvYmplY3QsIGluIGl0aCBwb3NpdGlvbg0KICAgIG5vcm0ubWVhbnNbaV0gPC0gbWVhbih4KX0NCmBgYA0KDQojIyB7I3Zpen0NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgY2FjaGUgPSBUfQ0KaGlzdChub3JtLm1lYW5zLCBmcmVxID0gRkFMU0UsIGJyZWFrcyA9IDIwLCBjb2wgPSAicmVkIiwgDQogICAgIHhsaW0gPSBjKC0zLCAzKSwNCiAgICAgeGxhYiA9IGV4cHJlc3Npb24oYmFyKHgpKSwNCiAgICAgbWFpbiA9IHBhc3RlKCJIaXN0b2dyYW0gb2YgbWVhbnMsIG4gPSAiLCBucykpIA0KDQpjdXJ2ZShkbm9ybSh4LCANCiAgICAgIG1lYW4gPSAwLCBzZCA9IDEvc3FydChucykpLCANCiAgICAgIGFkZCA9IFRSVUUsIGNvbCA9ICJibHVlIiwgbHdkID0gMikgDQpgYGANCg0KVGhlIHNpbXVsYXRlZCBzYW1wbGUgbWVhbnMgYXJlIGNlbnRyZWQgb24gdGhlIHBvcHVsYXRpb24gbWVhbiBvZiAwLCBidXQgZG8gZGlzcGxheSBzb21lIHZhcmlhbmNlLg0KDQojIw0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCBjYWNoZSA9IFR9DQojU3BlY2lmeSBzYW1wbGUgc2l6ZQ0KbnMgPC0gMzANCiAgDQojIFNwZWNpZnkgbnVtYmVyIG9mIHRpbWVzIHRvIGNvbmR1Y3QgcHJvY2VzcyAgDQp0cmlhbHMgPC0gMTAwMDANCg0KIyBjcmVhdGUgb2JqZWN0IGluIHdoaWNoIHRvIHN0b3JlIHNhbXBsZSBtZWFucyBvbmNlIHRoZXkgYXJlIGdlbmVyYXRlZA0Kbm9ybS5tZWFucyA8LSByZXAoMCwgdHJpYWxzKSAjIE5vdGUgbGVuZ3RoIGlzIGVxdWFsIHRvIHRoZSBudW1iZXIgb2YgdHJpYWxzDQoNCiMgUnVuIGZvciBsb29wICANCmZvcihpIGluIDE6dHJpYWxzKXsNCiAgICAjIFJhbmRvbWx5IGdlbmVyYXRlIG5zIHNhbXBsZXMgZnJvbSB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbg0KICAgIHggPC0gcm5vcm0obnMpIA0KICAgICMgQ29tcHV0ZSBtZWFuIG9mIHNhbXBsZXMsIHN0b3JlIGluIHRoZSBub3JtLm1lYW5zIG9iamVjdCwgaW4gaXRoIHBvc2l0aW9uDQogICAgbm9ybS5tZWFuc1tpXSA8LSBtZWFuKHgpfQ0KYGBgDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIGNhY2hlID0gVH0NCmhpc3Qobm9ybS5tZWFucywgZnJlcSA9IEZBTFNFLCBicmVha3MgPSAyMCwgY29sID0gInJlZCIsIA0KICAgICB4bGltID0gYygtMywgMyksDQogICAgIHhsYWIgPSBleHByZXNzaW9uKGJhcih4KSksDQogICAgIG1haW4gPSBwYXN0ZSgiSGlzdG9ncmFtIG9mIG1lYW5zLCBuID0gIiwgbnMpKSANCmN1cnZlKGRub3JtKHgsIA0KICAgICAgbWVhbiA9IDAsIHNkID0gMS9zcXJ0KG5zKSksIA0KICAgICAgYWRkID0gVFJVRSwgY29sID0gImJsdWUiLCBsd2QgPSAyKSANCmBgYA0KDQpBcyB3ZSBpbmNyZWFzZSB0aGUgc2FtcGxlIHNpemUsIHRoZSB2YXJpYW5jZSBvZiB0aGUgc2FtcGxlIG1lYW5zIGRlY3JlYXNlcy4NCg0KIyMNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgY2FjaGUgPSBUfQ0KI1NwZWNpZnkgc2FtcGxlIHNpemUNCm5zIDwtIDYwDQogIA0KIyBTcGVjaWZ5IG51bWJlciBvZiB0aW1lcyB0byBjb25kdWN0IHByb2Nlc3MgIA0KdHJpYWxzIDwtIDEwMDAwDQoNCiMgY3JlYXRlIG9iamVjdCBpbiB3aGljaCB0byBzdG9yZSBzYW1wbGUgbWVhbnMgb25jZSB0aGV5IGFyZSBnZW5lcmF0ZWQNCm5vcm0ubWVhbnMgPC0gcmVwKDAsIHRyaWFscykgIyBOb3RlIGxlbmd0aCBpcyBlcXVhbCB0byB0aGUgbnVtYmVyIG9mIHRyaWFscw0KDQojIFJ1biBmb3IgbG9vcCAgDQpmb3IoaSBpbiAxOnRyaWFscyl7DQogICAgIyBSYW5kb21seSBnZW5lcmF0ZSBucyBzYW1wbGVzIGZyb20gdGhlIG5vcm1hbCBkaXN0cmlidXRpb24NCiAgICB4IDwtIHJub3JtKG5zKSANCiAgICAjIENvbXB1dGUgbWVhbiBvZiBzYW1wbGVzLCBzdG9yZSBpbiB0aGUgbm9ybS5tZWFucyBvYmplY3QsIGluIGl0aCBwb3NpdGlvbiANCiAgICBub3JtLm1lYW5zW2ldIDwtIG1lYW4oeCl9DQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVH0NCmhpc3Qobm9ybS5tZWFucywgZnJlcSA9IEZBTFNFLCBicmVha3MgPSAyMCwgY29sID0gInJlZCIsIA0KICAgICB4bGltID0gYygtMywgMyksDQogICAgIHhsYWIgPSBleHByZXNzaW9uKGJhcih4KSksDQogICAgIG1haW4gPSBwYXN0ZSgiSGlzdG9ncmFtIG9mIG1lYW5zLCBuID0gIiwgbnMpKSANCmN1cnZlKGRub3JtKHgsIA0KICAgICAgbWVhbiA9IDAsIHNkID0gMS9zcXJ0KG5zKSksIA0KICAgICAgYWRkID0gVFJVRSwgY29sID0gImJsdWUiLCBsd2QgPSAyKSANCmBgYA0KDQpGb3IgYSBzYW1wbGUgc2l6ZSBvZiA2MCwgdGhlIHZhcmlhbmNlIG9mIHRoZSBzYW1wbGUgbWVhbnMgaXMgdmVyeSBsb3csIHByb3ZpZGluZyB1cyB3aXRoIGFuIGFjY3VyYXRlIGVzdGltYXRlIG9mIHRoZSBwb3B1bGF0aW9uIG1lYW4uDQoNCiMgQ0xUIFNpbXVsYXRpb24gLSBFeHBvbmVudGlhbCBEaXN0cmlidXRpb24NCg0KIyMNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVH0NCnNldC5zZWVkKDEpDQpuIDwtIDEwMA0KcmF0ZSA9IDEwDQp4IDwtIHJleHAobiwgcmF0ZSA9IHJhdGUpDQpgYGANCg0KIyMNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVH0NCmhpc3QoeCwgZnJlcSA9IEZBTFNFLCBjb2wgPSAiY2hhcnRyZXVzZTMiLCB4bGltID0gYygwLCAwLjUpLA0KICAgICBtYWluID0gcGFzdGUoIkhpc3RvZ3JhbSBvZiByYW5kb20gc2FtcGxlIFxuIGZyb20gRXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uLCBuID0gIiwgbikpDQoNCmN1cnZlKGRub3JtKHgsIDEvcmF0ZSwgMS9yYXRlKSwgYWRkID0gVFJVRSwgY29sID0gImJsdWUiLCBsd2QgPSAyKQ0KYGBgDQoNCiMjIFRoZSBSYXRlIFBhcmFtZXRlciBhbmQgUG9wdWxhdGlvbiBNZWFuDQoNCk5vIGFuc3dlciByZXF1aXJlZC4NCg0KIyMgeyNleHBzaW19DQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIGNhY2hlID0gVH0NCiNTcGVjaWZ5IHNhbXBsZSBzaXplDQpucyA8LSA1DQogIA0KIyBTcGVjaWZ5IHJhdGUNCnJhdGUgPSAxMA0KDQojIFNwZWNpZnkgbnVtYmVyIG9mIHRpbWVzIHRvIGNvbmR1Y3QgcHJvY2VzcyAgDQp0cmlhbHMgPC0gMTAwMDANCg0KIyBjcmVhdGUgb2JqZWN0IGluIHdoaWNoIHRvIHN0b3JlIHNhbXBsZSBtZWFucyBvbmNlIHRoZXkgYXJlIGdlbmVyYXRlZA0Kbm9ybS5tZWFucyA8LSByZXAoMCwgdHJpYWxzKSAjIE5vdGUgbGVuZ3RoIGlzIGVxdWFsIHRvIHRoZSBudW1iZXIgb2YgdHJpYWxzDQoNCiMgUnVuIGZvciBsb29wICANCmZvcihpIGluIDE6dHJpYWxzKXsNCiAgICAjIFJhbmRvbWx5IGdlbmVyYXRlIG5zIHNhbXBsZXMgZnJvbSB0aGUgZXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uDQogICAgeCA8LSByZXhwKG5zLCByYXRlID0gcmF0ZSkNCiAgICAjIENvbXB1dGUgbWVhbiBvZiBzYW1wbGVzLCBhbmQgc3RvcmUgaXQgaW4gdGhlIG5vcm0ubWVhbnMgb2JqZWN0LCBpbiBpdGggcG9zaXRpb24gDQogICAgbm9ybS5tZWFuc1tpXSA8LSBtZWFuKHgpIA0KICAgIH0NCmBgYA0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCBjYWNoZSA9IFR9DQpoaXN0KG5vcm0ubWVhbnMsIGZyZXEgPSBGQUxTRSwgYnJlYWtzID0gMjAsIGNvbCA9ICJyZWQiLCANCiAgICAgeGxpbSA9IGMoMCwgMC40KSwNCiAgICAgeGxhYiA9IGV4cHJlc3Npb24oYmFyKHgpKSwNCiAgICAgbWFpbiA9IHBhc3RlKCJIaXN0b2dyYW0gb2YgbWVhbnMsIG4gPSAiLCBucykpIA0KDQpjdXJ2ZShkbm9ybSh4LCBtZWFuID0gMS9yYXRlLCBzZCA9IDEvcmF0ZS9zcXJ0KG5zKSksIGFkZCA9IFRSVUUsDQogICAgICAgIGNvbCA9ICJibHVlIiwgbHdkID0gMikNCmBgYA0KDQpIZXJlIHdlIHVzZSBhbiB4LWF4aXMgcmFuZ2Ugb2YgMCB0byAwLjQuDQoNCiMjDQoNClRoZSByZXN1bHRpbmcgZGF0YSBzZXQgaXMgbm90IGFzIHNrZXdlZCBhcyB0aGUgdW5kZXJseWluZyBkaXN0cmlidXRpb24sIGJ1dCB0aGVyZSBpcyBzdGlsbCBhIG5vdGljZWFibGUgc2tldyAodGhpcyBpcyBiZWNhdXNlIG9mIHRoZSBsb3cgc2FtcGxlIHNpemUpLg0KDQojIw0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCBjYWNoZSA9IFR9DQojU3BlY2lmeSBzYW1wbGUgc2l6ZQ0KbnMgPC0gMzANCiAgDQojIFNwZWNpZnkgcmF0ZQ0KcmF0ZSA9IDEwDQoNCiMgU3BlY2lmeSBudW1iZXIgb2YgdGltZXMgdG8gY29uZHVjdCBwcm9jZXNzICANCnRyaWFscyA8LSAxMDAwMA0KDQojIGNyZWF0ZSBvYmplY3QgaW4gd2hpY2ggdG8gc3RvcmUgc2FtcGxlIG1lYW5zIG9uY2UgdGhleSBhcmUgZ2VuZXJhdGVkDQpub3JtLm1lYW5zIDwtIHJlcCgwLCB0cmlhbHMpICMgTm90ZSBsZW5ndGggaXMgZXF1YWwgdG8gdGhlIG51bWJlciBvZiB0cmlhbHMNCg0KIyBSdW4gZm9yIGxvb3AgIA0KZm9yKGkgaW4gMTp0cmlhbHMpew0KICAgICMgUmFuZG9tbHkgZ2VuZXJhdGUgbnMgc2FtcGxlcyBmcm9tIHRoZSBleHBvbmVudGlhbCBkaXN0cmlidXRpb24NCiAgICB4IDwtIHJleHAobnMsIHJhdGUgPSByYXRlKQ0KICAgICMgQ29tcHV0ZSBtZWFuIG9mIHNhbXBsZXMsIGFuZCBzdG9yZSBpdCBpbiB0aGUgbm9ybS5tZWFucyBvYmplY3QsIGluIGl0aCBwb3NpdGlvbiANCiAgICBub3JtLm1lYW5zW2ldIDwtIG1lYW4oeCkgDQogICAgfQ0KYGBgDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIGNhY2hlID0gVH0NCmhpc3Qobm9ybS5tZWFucywgZnJlcSA9IEZBTFNFLCBicmVha3MgPSAyMCwgY29sID0gInJlZCIsIA0KICAgICB4bGltID0gYygwLCAwLjIpLA0KICAgICB4bGFiID0gZXhwcmVzc2lvbihiYXIoeCkpLA0KICAgICBtYWluID0gcGFzdGUoIkhpc3RvZ3JhbSBvZiBtZWFucywgbiA9ICIsIG5zKSkgDQoNCmN1cnZlKGRub3JtKHgsIG1lYW4gPSAxL3JhdGUsIHNkID0gMS9yYXRlL3NxcnQobnMpKSwgYWRkID0gVFJVRSwNCiAgICAgICAgY29sID0gImJsdWUiLCBsd2QgPSAyKQ0KYGBgDQoNCkhlcmUsIHdlIGNoYW5nZSB0aGUgeCBheGlzIHJhbmdlIHRvIGJlIGZyb20gMCB0byAwLjIuIFRoZSBzYW1wbGUgbWVhbnMgbm93IGRpc3BsYXkgdmVyeSBsaXR0bGUgdmFyaWFuY2UsIGFuZCBwcm92aWRlIGEgbXVjaCBtb3JlIGFjY3VyYXRlIGVzdGltYXRlIG9mIHRoZSBwb3B1bGF0aW9uIG1lYW4gb2YgMC4xLiBOb3RlIHRoYXQgdGhlIE5vcm1hbCBkZW5zaXR5IGN1cnZlIGFsc28gZml0cyB0aGUgZGF0YSB3ZWxsLiBUaGVzZSByZXN1bHRzIGFyZSBkdWUgdG8gdGhlIHNhbXBsZSBzaXplIGJlaW5nIGJpZ2dlciAoMzAgaW5zdGVhZCBvZiA1KS4NCg0KIyMNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgY2FjaGUgPSBUfQ0KI1NwZWNpZnkgc2FtcGxlIHNpemUNCm5zIDwtIDYwDQogIA0KIyBTcGVjaWZ5IHJhdGUNCnJhdGUgPSAxMA0KDQojIFNwZWNpZnkgbnVtYmVyIG9mIHRpbWVzIHRvIGNvbmR1Y3QgcHJvY2VzcyAgDQp0cmlhbHMgPC0gMTAwMDANCg0KIyBjcmVhdGUgb2JqZWN0IGluIHdoaWNoIHRvIHN0b3JlIHNhbXBsZSBtZWFucyBvbmNlIHRoZXkgYXJlIGdlbmVyYXRlZA0Kbm9ybS5tZWFucyA8LSByZXAoMCwgdHJpYWxzKSAjIE5vdGUgbGVuZ3RoIGlzIGVxdWFsIHRvIHRoZSBudW1iZXIgb2YgdHJpYWxzDQoNCiMgUnVuIGZvciBsb29wICANCmZvcihpIGluIDE6dHJpYWxzKXsNCiAgICAjIFJhbmRvbWx5IGdlbmVyYXRlIG5zIHNhbXBsZXMgZnJvbSB0aGUgZXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uDQogICAgeCA8LSByZXhwKG5zLCByYXRlID0gcmF0ZSkNCiAgICAjIENvbXB1dGUgbWVhbiBvZiBzYW1wbGVzLCBhbmQgc3RvcmUgaXQgaW4gdGhlIG5vcm0ubWVhbnMgb2JqZWN0LCBpbiBpdGggcG9zaXRpb24gDQogICAgbm9ybS5tZWFuc1tpXSA8LSBtZWFuKHgpIA0KICAgIH0NCmBgYA0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCBjYWNoZSA9IFR9DQpoaXN0KG5vcm0ubWVhbnMsIGZyZXEgPSBGQUxTRSwgYnJlYWtzID0gMjAsIGNvbCA9ICJyZWQiLCANCiAgICAgeGxpbSA9IGMoMCwgMC4yKSwNCiAgICAgeGxhYiA9IGV4cHJlc3Npb24oYmFyKHgpKSwNCiAgICAgbWFpbiA9IHBhc3RlKCJIaXN0b2dyYW0gb2YgbWVhbnMsIG4gPSAiLCBucykpIA0KDQpjdXJ2ZShkbm9ybSh4LCBtZWFuID0gMS9yYXRlLCBzZCA9IDEvcmF0ZS9zcXJ0KG5zKSksIGFkZCA9IFRSVUUsDQogICAgICAgIGNvbCA9ICJibHVlIiwgbHdkID0gMikNCmBgYA0KDQpGb3IgYSBzYW1wbGUgc2l6ZSBvZiA2MCwgdGhlIHJlc3VsdGFudCBzYW1wbGUgbWVhbnMgYXJlIG1vcmUgYWNjdXJhdGUsIGFuZCB0aGUgY29ycmVzcG9uZGluZyBub3JtYWwgZGVuc2l0eSBjdXJ2ZSBmaXRzIHRoZXNlIGRpc3RyaWJ1dGlvbiBvZiB0aGVzZSBzYW1wbGUgbWVhbnMgZXh0cmVtZWx5IHdlbGwgKGFzIGV4cGVjdGVkIHZpYSB0aGUgQ0xUKS4NCg0KIyBDTFQgU2ltdWxhdGlvbiAtIEJlcm5vdWxsaSBEaXN0cmlidXRpb24NCg0KIyMNCg0KTm8gYW5zd2VyIHJlcXVpcmVkLg0KDQojIw0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCBjYWNoZSA9IFR9DQojU3BlY2lmeSBzYW1wbGUgc2l6ZQ0KbnMgPC0gNQ0KDQojIFNwZWNpZnkgc3VjY2VzcyByYXRlDQpwID0gMC4zDQoNCiMgU3BlY2lmeSBudW1iZXIgb2YgdGltZXMgdG8gY29uZHVjdCBwcm9jZXNzICANCnRyaWFscyA8LSAxMDAwMA0KDQojIGNyZWF0ZSBvYmplY3QgaW4gd2hpY2ggdG8gc3RvcmUgc2FtcGxlIG1lYW5zIG9uY2UgdGhleSBhcmUgZ2VuZXJhdGVkDQpub3JtLm1lYW5zIDwtIHJlcCgwLCB0cmlhbHMpICMgTm90ZSBsZW5ndGggaXMgZXF1YWwgdG8gdGhlIG51bWJlciBvZiB0cmlhbHMNCg0KIyBSdW4gZm9yIGxvb3AgIA0KZm9yKGkgaW4gMTp0cmlhbHMpew0KICAgICMgUmFuZG9tbHkgZ2VuZXJhdGUgbnMgc2FtcGxlcyBmcm9tIHRoZSBCZXJub3VsbGkgZGlzdHJpYnV0aW9uDQogICAgeCA8LSByYmlub20obnMsIDEsIHApDQogICAgIyBDb21wdXRlIG1lYW4gb2Ygc2FtcGxlcywgYW5kIHN0b3JlIGl0IGluIHRoZSBub3JtLm1lYW5zIG9iamVjdCwgaW4gaXRoIHBvc2l0aW9uIA0KICAgIG5vcm0ubWVhbnNbaV0gPC0gbWVhbih4KSANCiAgICB9DQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgY2FjaGUgPSBUfQ0KaGlzdChub3JtLm1lYW5zLCBmcmVxID0gRkFMU0UsIGJyZWFrcyA9IDIwLCBjb2wgPSAicmVkIiwgDQogICAgIHhsaW0gPSBjKDAsIDEpLA0KICAgICB4bGFiID0gZXhwcmVzc2lvbihiYXIoeCkpLA0KICAgICBtYWluID0gcGFzdGUoIkhpc3RvZ3JhbSBvZiBtZWFucywgbiA9ICIsIG5zKSkgDQoNCiMgU2V0IG11IGFuZCBzaWdtYSBmb3IgdGhlIGFwcHJveGltYXRpbmcgbm9ybWFsIGRpc3RyaWJ1dGlvbg0KbXUgPC0gcA0Kc2lnbWEgPC0gc3FydChwKigxIC0gcCkpDQogIA0KIyBPdmVybGF5IHRoZSBub3JtYWwgZGVuc2l0eQ0KY3VydmUoZG5vcm0oeCwgbXUsIHNpZ21hL3NxcnQobnMpKSwgYWRkID0gVFJVRSwgY29sID0gImJsdWUiLCBsd2QgPSAyKQ0KYGBgDQoNCiMjDQoNClRoZSBwbG90IG9mIHRoZSBzYW1wbGUgbWVhbnMgaXMgY2xlYXJseSBub3Qgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuDQoNCiMjDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIGNhY2hlID0gVH0NCiNTcGVjaWZ5IHNhbXBsZSBzaXplDQpucyA8LSAzMA0KICANCiMgU3BlY2lmeSBzdWNjZXNzIHJhdGUNCnAgPSAwLjMNCg0KIyBTcGVjaWZ5IG51bWJlciBvZiB0aW1lcyB0byBjb25kdWN0IHByb2Nlc3MgIA0KdHJpYWxzIDwtIDEwMDAwDQoNCiMgY3JlYXRlIG9iamVjdCBpbiB3aGljaCB0byBzdG9yZSBzYW1wbGUgbWVhbnMgb25jZSB0aGV5IGFyZSBnZW5lcmF0ZWQNCm5vcm0ubWVhbnMgPC0gcmVwKDAsIHRyaWFscykgIyBOb3RlIGxlbmd0aCBpcyBlcXVhbCB0byB0aGUgbnVtYmVyIG9mIHRyaWFscw0KDQojIFJ1biBmb3IgbG9vcCAgDQpmb3IoaSBpbiAxOnRyaWFscyl7DQogICAgIyBSYW5kb21seSBnZW5lcmF0ZSBucyBzYW1wbGVzIGZyb20gdGhlIEJlcm5vdWxsaSBkaXN0cmlidXRpb24NCiAgICB4IDwtIHJiaW5vbShucywgMSwgcCkNCiAgICAjIENvbXB1dGUgbWVhbiBvZiBzYW1wbGVzLCBhbmQgc3RvcmUgaXQgaW4gdGhlIG5vcm0ubWVhbnMgb2JqZWN0LCBpbiBpdGggcG9zaXRpb24gDQogICAgbm9ybS5tZWFuc1tpXSA8LSBtZWFuKHgpIA0KICAgIH0NCmBgYA0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCBjYWNoZSA9IFR9DQpoaXN0KG5vcm0ubWVhbnMsIGZyZXEgPSBGQUxTRSwgYnJlYWtzID0gMjAsIGNvbCA9ICJyZWQiLCANCiAgICAgeGxpbSA9IGMoMCwgMSksDQogICAgIHhsYWIgPSBleHByZXNzaW9uKGJhcih4KSksDQogICAgIG1haW4gPSBwYXN0ZSgiSGlzdG9ncmFtIG9mIG1lYW5zLCBuID0gIiwgbnMpKSANCg0KIyBTZXQgbXUgYW5kIHNpZ21hIGZvciB0aGUgYXBwcm94aW1hdGluZyBub3JtYWwgZGlzdHJpYnV0aW9uDQptdSA8LSBwDQpzaWdtYSA8LSBzcXJ0KHAqKDEgLSBwKSkNCiAgDQojIE92ZXJsYXkgdGhlIG5vcm1hbCBkZW5zaXR5DQpjdXJ2ZShkbm9ybSh4LCBtdSwgc2lnbWEvc3FydChucykpLCBhZGQgPSBUUlVFLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpDQpgYGANCg0KQWxsIG9mIGEgc3VkZGVuLCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBzYW1wbGUgbWVhbnMgYmVnaW5zIHRvIGxvb2sgbXVjaCBtb3JlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLg0KDQojIw0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCBjYWNoZSA9IFR9DQojU3BlY2lmeSBzYW1wbGUgc2l6ZQ0KbnMgPC0gNjANCiAgDQojIFNwZWNpZnkgc3VjY2VzcyByYXRlDQpwID0gMC4zDQoNCiMgU3BlY2lmeSBudW1iZXIgb2YgdGltZXMgdG8gY29uZHVjdCBwcm9jZXNzICANCnRyaWFscyA8LSAxMDAwMA0KDQojIGNyZWF0ZSBvYmplY3QgaW4gd2hpY2ggdG8gc3RvcmUgc2FtcGxlIG1lYW5zIG9uY2UgdGhleSBhcmUgZ2VuZXJhdGVkDQpub3JtLm1lYW5zIDwtIHJlcCgwLCB0cmlhbHMpICMgTm90ZSBsZW5ndGggaXMgZXF1YWwgdG8gdGhlIG51bWJlciBvZiB0cmlhbHMNCg0KIyBSdW4gZm9yIGxvb3AgIA0KZm9yKGkgaW4gMTp0cmlhbHMpew0KICAgICMgUmFuZG9tbHkgZ2VuZXJhdGUgbnMgc2FtcGxlcyBmcm9tIHRoZSBCZXJub3VsbGkgZGlzdHJpYnV0aW9uDQogICAgeCA8LSByYmlub20obnMsIDEsIHApDQogICAgIyBDb21wdXRlIG1lYW4gb2Ygc2FtcGxlcywgYW5kIHN0b3JlIGl0IGluIHRoZSBub3JtLm1lYW5zIG9iamVjdCwgaW4gaXRoIHBvc2l0aW9uIA0KICAgIG5vcm0ubWVhbnNbaV0gPC0gbWVhbih4KSANCiAgICB9DQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgY2FjaGUgPSBUfQ0KaGlzdChub3JtLm1lYW5zLCBmcmVxID0gRkFMU0UsIGJyZWFrcyA9IDIwLCBjb2wgPSAicmVkIiwgDQogICAgIHhsaW0gPSBjKDAsIDEpLA0KICAgICB4bGFiID0gZXhwcmVzc2lvbihiYXIoeCkpLA0KICAgICBtYWluID0gcGFzdGUoIkhpc3RvZ3JhbSBvZiBtZWFucywgbiA9ICIsIG5zKSkgDQoNCiMgU2V0IG11IGFuZCBzaWdtYSBmb3IgdGhlIGFwcHJveGltYXRpbmcgbm9ybWFsIGRpc3RyaWJ1dGlvbg0KbXUgPC0gcA0Kc2lnbWEgPC0gc3FydChwKigxIC0gcCkpDQogIA0KIyBPdmVybGF5IHRoZSBub3JtYWwgZGVuc2l0eQ0KY3VydmUoZG5vcm0oeCwgbXUsIHNpZ21hL3NxcnQobnMpKSwgYWRkID0gVFJVRSwgY29sID0gImJsdWUiLCBsd2QgPSAyKQ0KYGBgDQoNCkZvciBhIHNhbXBsZSBzaXplIG9mIDYwLCB0aGUgc2FtcGxlIG1lYW5zIGFyZSBub3cgbG9va2luZyBhcyBpZiB0aGV5IGFsbW9zdCBjb3VsZCBoYXZlIGJlZW4gZ2VuZXJhdGVkIGZyb20gYSBub3JtYWwgZGlzdHJpYnV0aW9uLCB3aGljaCBpcyBhbWF6aW5nIGdpdmVuIHRoZXkgYXJlIG9idGFpbmVkIGZyb20gZGF0YSBnZW5lcmF0ZWQgZnJvbSBhIGRpc2NyZXRlIGRpc3RyaWJ1dGlvbi4NCg0KDQojIEV4dGVuc2lvbiAtIEF2ZXJhZ2UgRGlhbW9uZCBQcmljZXMNCg0KVGhlIFIgY29kZSBiZWxvdyBzaG91bGQgaGF2ZSBiZWVuIHJ1bjoNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCmluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KYGBgDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUiLCBldmFsID0gVCwgaW5jbHVkZSA9IEZ9DQpsaWJyYXJ5KGdncGxvdDIpDQpgYGANCg0KIyMNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVH0NCmhpc3QoZGlhbW9uZHMkcHJpY2UsIGNvbCA9ICJza3libHVlIiwgeGxhYiA9ICJEaWFtb25kIFByaWNlICgkKSIsDQogICAgIG1haW4gPSAiSGlzdG9ncmFtIG9mIERpYW1vbmQgUHJpY2VzICgkKSIsIGZyZXEgPSBGKQ0KYGBgDQoNCiMjIHsjZGlhbW9uZHNpbX0NCg0KRXhhbXBsZSBSIGNvZGUgaXMgcHJvdmlkZWQgYmVsb3c6DQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIGNhY2hlID0gVH0NCiNTcGVjaWZ5IHNhbXBsZSBzaXplDQpucyA8LSA1DQogIA0KIyBTcGVjaWZ5IG51bWJlciBvZiB0aW1lcyB0byBjb25kdWN0IHByb2Nlc3MgIA0KdHJpYWxzIDwtIDEwMA0KDQojIGNyZWF0ZSBvYmplY3QgaW4gd2hpY2ggdG8gc3RvcmUgc2FtcGxlIG1lYW5zIG9uY2UgdGhleSBhcmUgZ2VuZXJhdGVkDQpub3JtLm1lYW5zIDwtIHJlcCgwLCB0cmlhbHMpICMgTm90ZSBsZW5ndGggaXMgZXF1YWwgdG8gdGhlIG51bWJlciBvZiB0cmlhbHMNCg0KIyBSdW4gZm9yIGxvb3AgIA0KZm9yKGkgaW4gMTp0cmlhbHMpew0KICAgICMgUmFuZG9tbHkgc2FtcGxlIG5zIHZhbHVlcyBmcm9tIHRoZSBkaWFtb25kcyBkYXRhIHNldA0KICAgIHggPC0gc2FtcGxlKGRpYW1vbmRzJHByaWNlLCBucykNCiAgICAjIENvbXB1dGUgbWVhbiBvZiBzYW1wbGVzLCBhbmQgc3RvcmUgaXQgaW4gdGhlIG5vcm0ubWVhbnMgb2JqZWN0LCBpbiBpdGggcG9zaXRpb24gDQogICAgbm9ybS5tZWFuc1tpXSA8LSBtZWFuKHgpIA0KICAgIH0NCmBgYA0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCBjYWNoZSA9IFR9DQpoaXN0KG5vcm0ubWVhbnMsIGZyZXEgPSBGQUxTRSwgY29sID0gInNreWJsdWUiLA0KICAgICB4bGFiID0gZXhwcmVzc2lvbihiYXIoeCkpLA0KICAgICBtYWluID0gcGFzdGUoIkhpc3RvZ3JhbSBvZiBtZWFucywgbiA9ICIsIG5zKSkgDQpgYGANCg0KV2Ugbm90ZSB0aGF0IHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHNhbXBsZSBtZWFucyBpcyBxdWl0ZSBza2V3ZWQuDQoNCiMjIHsjZGlhbW9uZHNpbWxhcmdlfQ0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCBjYWNoZSA9IFR9DQojU3BlY2lmeSBzYW1wbGUgc2l6ZQ0KbnMgPC0gMzANCiAgDQojIFNwZWNpZnkgbnVtYmVyIG9mIHRpbWVzIHRvIGNvbmR1Y3QgcHJvY2VzcyAgDQp0cmlhbHMgPC0gMTAwDQoNCiMgY3JlYXRlIG9iamVjdCBpbiB3aGljaCB0byBzdG9yZSBzYW1wbGUgbWVhbnMgb25jZSB0aGV5IGFyZSBnZW5lcmF0ZWQNCm5vcm0ubWVhbnMyIDwtIHJlcCgwLCB0cmlhbHMpICMgTm90ZSBsZW5ndGggaXMgZXF1YWwgdG8gdGhlIG51bWJlciBvZiB0cmlhbHMNCg0KIyBSdW4gZm9yIGxvb3AgIA0KZm9yKGkgaW4gMTp0cmlhbHMpew0KICAgICMgUmFuZG9tbHkgc2FtcGxlIG5zIHZhbHVlcyBmcm9tIHRoZSBkaWFtb25kcyBkYXRhIHNldA0KICAgIHggPC0gc2FtcGxlKGRpYW1vbmRzJHByaWNlLCBucykNCiAgICAjIENvbXB1dGUgbWVhbiBvZiBzYW1wbGVzLCBhbmQgc3RvcmUgaXQgaW4gdGhlIG5vcm0ubWVhbnMgb2JqZWN0LCBpbiBpdGggcG9zaXRpb24gDQogICAgbm9ybS5tZWFuczJbaV0gPC0gbWVhbih4KSANCiAgICB9DQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgY2FjaGUgPSBUfQ0KaGlzdChub3JtLm1lYW5zMiwgZnJlcSA9IEZBTFNFLCBjb2wgPSAic2t5Ymx1ZSIsDQogICAgIHhsYWIgPSBleHByZXNzaW9uKGJhcih4KSksDQogICAgIG1haW4gPSBwYXN0ZSgiSGlzdG9ncmFtIG9mIG1lYW5zLCBuID0gIiwgbnMpKSANCmBgYA0KDQpCeSBpbmNyZWFzaW5nIG91ciBzYW1wbGUgc2l6ZSB0byAzMCwgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgc2FtcGxlIG1lYW5zIG5vdyBhcHBlYXJzIG1vcmUgc3ltbWV0cmljIGFuZCBjbG9zZXIgdG8gdGhhdCBvZiBhIG5vcm1hbCBkaXN0cmlidXRpb24uIFRoaXMgcmVzdWx0cyBhZGhlcmVzIHdpdGggdGhlIENlbnRyYWwgTGltaXQgVGhlb3JlbS4gRnVydGhlciBpbmNyZWFzZXMgaW4gdGhlIHNhbXBsZSBzaXplIHdvdWxkIHJlc3VsdCBpbiBhIHNhbXBsZSBtZWFuIGRpc3RyaWJ1dGlvbiB0aGF0IGV2ZW4gbW9yZSBjbG9zZWx5IG1hdGNoZWQgdGhhdCBvZiBhIG5vcm1hbCBkaXN0cmlidXRpb24uDQoNCjxicj4NCg0KIyMjIyBHcmVhdCBqb2IsIHRoYXQncyBldmVyeXRoaW5nIGZvciB0b2RheSEgIyMjIyB7LX0NCg0KSG9wZWZ1bGx5LCB0aGlzIGNvbXB1dGVyIGxhYiBoYXMgaGVscGVkIGNlbWVudCB5b3VyIHVuZGVyc3RhbmRpbmcgb2YgdGhlIENlbnRyYWwgTGltaXQgVGhlb3JlbS4NCg0KPGJyPg0KDQojIFJlZmVyZW5jZXMgey0gI1JlZn0NCjxkaXYgaWQ9InJlZnMiPjwvZGl2Pg0KDQo8YnI+DQoNCjxmb250IGNvbG9yID0gImdyZXkiPg0KVGhlc2Ugbm90ZXMgaGF2ZSBiZWVuIHByZXBhcmVkIGJ5IFJ1cGVydCBLdXZla2UgYW5kIEFtYW5kYSBTaGFrZXIuIFRoZSBjb3B5cmlnaHQgZm9yIHRoZSBtYXRlcmlhbCBpbiB0aGVzZSBub3RlcyByZXNpZGVzIHdpdGggdGhlIGF1dGhvcnMgbmFtZWQgYWJvdmUsIHdpdGggdGhlIERlcGFydG1lbnQgb2YgTWF0aGVtYXRpY2FsIGFuZCBQaHlzaWNhbCBTY2llbmNlcyBhbmQgd2l0aCBMYSBUcm9iZSBVbml2ZXJzaXR5LiBDb3B5cmlnaHQgaW4gdGhpcyB3b3JrIGlzIHZlc3RlZCBpbiBMYSBUcm9iZSBVbml2ZXJzaXR5IGluY2x1ZGluZyBhbGwgTGEgVHJvYmUgVW5pdmVyc2l0eSBicmFuZGluZyBhbmQgbmFtaW5nLiBVbmxlc3Mgb3RoZXJ3aXNlIHN0YXRlZCwgbWF0ZXJpYWwgd2l0aGluIHRoaXMgd29yayBpcyBsaWNlbnNlZCB1bmRlciBhIENyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24tTm9uIENvbW1lcmNpYWwtTm9uIERlcml2YXRpdmVzIExpY2Vuc2UgDQo8YSBocmVmID0gImh0dHBzOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1uYy1uZC80LjAvQ0MiIHRhcmdldD0iX2JsYW5rIj4gQlktTkMtTkQuIDwvYT4NCjwvZm9udD4=