Data Science Stream

Topic 5B: Simulations in R


Welcome to the fifth computer lab for the Data Science stream of STM1001.

In Topic 4, we introduced sampling distributions and the concept of the Central Limit Theorem.

In this computer lab we will use R to conduct the simulations discussed in Chapter 3 of Topic 4.

  • It might be helpful to keep this content open in a separate tab while you work through the lab material, in case you would like to quickly double-check your understanding of any concepts.

By the end of this lab, you should be able to conduct simple simulations in R. Let’s get started!

1 Sampling Distributions

1.1 Sampling

🏑 Recall that a sample is a random selection of units from a chosen population.

  • For example, if the STM1001 cohort was our chosen population, then a random selection of STM1001 students would be a sample from this population.

Because it is typically unfeasible to collect data on an entire population of interest, we instead conduct analyses using a sample. We hope that the inferences we make using the sample data can be extrapolated to provide information about the population, and we can use statistical techniques to ascertain the accuracy of these inferences.

One such statistical technique we can utilise is the Central Limit Theorem.

1.2 The Central Limit Theorem

🏑 Recall the definition of the Central Limit Theorem (CLT):

Let \(X_1, \ldots, X_n\) be a random sample from a distribution with finite mean \(\mu\) and finite variance \(\sigma^2\).

For \(\overline{X}\) denoting the sample mean, if \(n\) is sufficiently large then \[\overline{X}\stackrel{\tiny \text{approx.}}\sim N\left(\mu,\frac{\sigma^2}{n}\right) , \] where \(\stackrel{\tiny \text{approx.}}\sim\) denotes β€˜approximately distributed as’.


By the CLT, it follows that as we increase our sample size, the sample mean \(\overline{X}\) will get increasingly closer (i.e.Β converge) to the population mean \(\mu\). As \(n\) increases, the variance of the sample mean \(\overline{X}\) will also decrease.

In other words, while samples of individuals can exhibit significant variation, samples of means tend to have less variability (as each mean is calculated from a sample of individuals, reducing the impact of outliers).

Let’s visualise this process in R using some simulations.

2 Simulations in R

Carrying out simulations in R is actually quite straightforward. We will walk through the steps involved one at a time.

2.1

πŸ’» Suppose that we are interested in the random variable \(X \sim N(0, 1)\) - in other words, here \(X\) follows the standard normal distribution.

We can generate a sample of 100 observations from this distribution using the following R code:

set.seed(1)
n <- 100
x <- rnorm(n)

Run this code now.

Note: The default mean and standard deviation values used by rnorm are 0 and 1 respectively, so we do not need to specify them in this instance.

2.2

πŸ’» We can plot our generated data using the hist function, as shown below.

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)

Note that we have also used the curve and dnorm functions here to overlay the standard normal distribution probability density curve.

2.3

πŸ’» Our main interest here is the sample mean, not the variability of the sample values.

If we check the sample mean of our data set x, we find that this is equal to approximately 0.109 (shown by the red dashed line in the plot above). Since this is the sample mean for just one sample of 100 observations, we can’t be too confident in using this estimate as an accurate estimate of the population mean (which we know was specified to be 0).

Rather than relying on just the one sample of 100 observations, we will now simulate a number of random samples from \(X\), in order to obtain multiple sample mean estimates, which we can use in turn to obtain more accurate estimate of the population mean.

2.4

πŸ’» To begin, suppose we sample just 5 observations of \(X\), rather than 100, and then compute the sample mean of these 5 observations.

Using the code in 2.1, it follows that this process is quite straightforward:

set.seed(1)
n <- 5 # Specify sample size
x <- rnorm(n) # Generate n samples from the standard normal distribution
norm_mean <- mean(x) # Store the mean of the samples in a new object


🎧 Online students πŸ’¬ Run your object norm_mean and post your result in the chat.


2.5 for loops

πŸ’» Since our underlying data is generated from a standard normal distribution, it follows that the distribution of the sample mean will also be normal (we can think of this result as a precursor to the Central Limit Theorem).

To accurately visualise the distribution of the sample mean, we will need to repeat the process outlined in 2.4 many times. This is where our simulations can really shine.

Suppose, rather than conducting the process outlined in 2.4 once, we instead conduct it 10,000 times. It would take a while to write this code out line by line in R (over 9000 lines potentially!).

Instead, to save time, we will use a for loop. A for loop is a function that will repeat a specified set of operations a specified number of times.

The Code chunk below provides a simple example of the R syntax for a for loop.

for(i in 1:10){
  x <- rnorm(i)
  mean(x)}

How do we interpret this code? Well,we have specified that for some input i, where i can take the integer values 1 up to 10, the for loop will simulate i random values from the standard Normal distribution, store them in the object x, and then compute the mean of x.

Thus, our for loop runs like this:

  • The for loop starts with the first specified value, 1, and simulates 1 random value from the standard Normal distribution.
  • The mean of x is now computed. This is the last operation in the for loop.
  • Since the specified operations inside the loop have been finished for that value of i, the loop starts again, with i=2 now.
  • This process continues, until the final specified value of i, namely i=10, has been used.
  • At this point, the for loop is complete.

Note: We do not have to use the letter i here, it is simply convention. You can use a different letter, but remember, make sure you have not used your chosen letter as a name for a previous object in which you have stored data.

2.6

πŸ’» The Code chunk below expands upon the for loop example discussed above in 2.5. Take a look at this code, read the comments carefully, and make sure you understand what the code does (note some values are missing, as denoted by the ...).

#Specify sample size
ns <- ...
# Specify number of times to conduct process  
trials <- ...
# 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)}

Once you feel confident in your understanding of this code, replace the ... missing details for ns and trials, using the following details:

  • You want to take 10,000 samples of randomly generated values from the standard Normal distribution.
  • Each sample should have a sample size of 5.

Once you have filled in the details, run your code.

Hint: If you have given this a decent shot, but are stuck, you can check the Code chunk below:

#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

πŸ’» To visualise our results, we can use the following code:

hist(norm.means, freq = FALSE, breaks = 20, col = "red", 
     xlim = c(-3, 3),
     xlab = expression(bar(x)),
     main = paste("Histogram of means, n = ", ns)) 

We can also overlay a normal density curve, that, since our underlying data is normal, will reflect the distribution of the sample mean.

curve(dnorm(x, 
      mean = 0, sd = 1/sqrt(ns)), 
      add = TRUE, col = "blue", lwd = 2) 

Run these code chunks now, and check your results. Are our simulated sample means close to the population mean of 0?

2.8

πŸ’»Repeat steps 2.6 and 2.7, using a sample of 30 instead of 5. What do you notice about the distribution of the simulated sample means?


🎧 Online students πŸ’¬ Leave a comment in the chat about the changes you observe in the distribution, changing from \(n=5\) to \(n=30\).


2.9

πŸ’» Finally, repeat steps 2.6 and 2.7, using a sample of 60. What do you notice about the distribution of the simulated sample means now?


🎧 Online students πŸ’¬ Leave a comment in the chat about the changes you observe in the distribution, changing from \(n=30\) to \(n=60\).


3 CLT Simulation - Exponential Distribution

πŸ’» To demonstrate the versatility of the Central Limit Theorem, let’s carry out some simulations involving data generated from the Exponential distribution, which (unlike the Normal distribution) is highly skewed (i.e.Β asymmetric).

3.1

πŸ’» Recall from Topic 3 that the Exponential distribution is defined by one parameter, known as the rate parameter. The rate parameter is denoted by the Greek letter \(\lambda\).

If a random variable \(X\) follows an Exponential distribution with rate parameter \(\lambda\), we write \(X\sim Exp(\lambda)\).

Suppose now that our random variable \(X\) follows an exponential distribution with rate parameter \(\lambda = 10\). In other words, suppose \(X \sim \text{Exp}(10)\).

We can generate a sample of 100 observations from this distribution using the following R code:

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

Note that we use rexp to randomly generate values from the exponential distribution, instead of using rnorm (which is for the normal distribution).

Run this code now.

3.2

πŸ’» Our generated data from 3.1 is highly skewed, and clearly different to data generated from the symmetric normal distribution. This disparity can be seen in Figure 3.1 below, which shows a histogram of the data, with a normal distribution probability density curve overlaid in blue (similar to in 2.2), based on appropriate mean and variance values.

Data generated from an Exponential distribution, with a normal curve overlaid.

Figure 3.1: Data generated from an Exponential distribution, with a normal curve overlaid.

Clearly, we cannot fit a normal curve well to data generated from an Exponential distribution. However, as we work through this question, we will find that when we model the distribution of the sample means of data generated from an Exponential distribution, this distribution of sample means can be fitted well by a normal curve, especially as our sample size increases. This (somewhat unintuitive) result is due to the Central Limit Theorem!

3.3 The Rate Parameter and Population Mean

πŸ’» Instead of considering the individual data points generated from the Exponential distribution, let’s shift our focus to the sample mean of these data points.

For data generated from an Exponential distribution, the population mean \(\mu\) is in theory equal to 1 divided by the rate parameter \(\lambda\). I.e., for \(X\sim Exp(\lambda)\), the population mean of \(X\) equals \(\frac{1}{\lambda}\).

If we check the sample mean of x, we find that this is equal to 0.1030676 - this sample mean is quite a good estimate of the population mean (\(\mu = 1/10 = 0.1\)), given the theory.

3.4

πŸ’» Let us now conduct the simulation process used in 2.6, for our data sampled from \(X \sim \text{Exp}(10)\).

Using the code in 2.6 as a guide, simulate 10,000 sample means of \(X\), using samples of size 5.

Plot your results, using the code in 2.7 as a guide.

Note: You will have to change the x-axis range for the histogram (via the xlim argument). Try using a range of 0 to 0.4.

Note 2: Use the code in the Code chunk below to overlay the appropriate Normal distribution probability density curve:

curve(dnorm(x, mean = 1/rate, sd = 1/rate/sqrt(ns)), add = TRUE,
        col = "blue", lwd = 2)

3.5

πŸ’» What do you notice about your resultant plot?

3.6

πŸ’» Repeats 3.4 for \(X \sim Exp(10)\), using a sample of 30 instead of 5. What do you notice about the distribution of the simulated sample means?


🎧 Online students πŸ’¬ Leave a comment in the chat about the changes you observe in the distribution, changing from \(n=5\) to \(n=30\).


3.7

πŸ’» Finally, repeat 3.4 for \(X \sim Exp(10)\), using a sample of 60. What do you notice about the distribution of the simulated sample means now?


🎧 Online students πŸ’¬ Leave a comment in the chat about the changes you observe in the distribution, changing from \(n=30\) to \(n=60\).


4 CLT Simulation - Bernoulli Distribution

πŸ’» As discussed in Section 3.3 of Topic 4, the Central Limit Theorem even applies to discrete random variables.

Suppose that our random variable \(X\) now follows a Bernoulli distribution with success parameter \(p = 0.3\). In other words, suppose \(X \sim \text{BERN}(0.3)\).

4.1

πŸ’» If we generate a sample of 100 observations from this distribution (see the R code below) and then visualise our generated data, we see a roughly 70/30 split of observations between \(x=0\) and \(x=1\). Clearly, (just as in the Exponential distribution case), the normal distribution probability density curve, with appropriate parameter specifications, (shown in blue), is an extremely poor fit for this data.

set.seed(1)
n <- 100
p = 0.3
x <- rbinom(n, 1, p)

Note that we use rbinom to randomly generate values from the Bernoulli distribution, instead of using rnorm (which is for the normal distribution).

4.2

πŸ’» However, despite our data being generated from a discrete distribution, we can still use the Central Limit Theorem to obtain an accurate estimate of the population mean by considering the distribution of \(\bar{X}\)!

Let us now conduct the simulation process used in 2.6, for our Bernoulli-distributed data.

Using the code in 2.6 as a guide, simulate 10000 sample means of \(X\), using samples of size 5. Then, plot your results, using the code in 2.7 as a guide.

Note: You will have to change the x-axis range for the histogram (via the xlim argument).

Note 2: Use the code in the Code chunk below to overlay a normal distribution probability density curve with the appropriate parameter specifications:

# 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

πŸ’» What do you notice about your resultant plot?

4.4

πŸ’» Repeat 3.4 for \(X \sim BERN(0.3)\), using a sample of 30 instead of 5. What do you notice about the distribution of the simulated sample means?


🎧 Online students πŸ’¬ Leave a comment in the chat about the changes you observe in the distribution, changing from \(n=5\) to \(n=30\).


4.5

πŸ’» Finally, repeat 3.4 for \(X \sim BERN(0.3)\), using a sample of 60. What do you notice about the distribution of the simulated sample means now?


🎧 Online students πŸ’¬ Leave a comment in the chat about the changes you observe in the distribution, changing from \(n=30\) to \(n=60\).


5 Extension: Average Diamond Prices

πŸ’» Let’s consider how we can apply the Central Limit Theorem to real data.

For this question, we will consider data on approximately 54,000 round cut diamonds. This data is stored in the diamonds data set in the ggplot2 R package. We will treat this data as the population data.

Install and load the ggplot2 R package now.

Hint: If you need a refresher on installing and loading packages in R, check the Code chunk below:

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

5.1

πŸ’» If we plot the price of round cut diamonds using a histogram, we can see that the data is clearly not normally distributed.

Make sure to run this code before continuing.

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

5.2

πŸ’» Suppose that you are interested in estimating the population mean price for round cut diamonds, but do not have access to the full diamonds data set.

Instead, you can only sample prices for 5 round cut diamonds at a time, represented by the code below:

x <- sample(diamonds$price, 5)

Using this code and the code in 2.6 as a guide, obtain 100 sample means from 100 simulated samples of 5 random round cut diamond sale prices. Plot a histogram of these sample means. What do you observe?


🎧 Online students πŸ’¬ Volunteer to share your screen to show your histogram and discuss your results, if you got to this stage before the end of the lab.


5.3

πŸ’» Repeat 5.2, but this time suppose that you are able to take samples of 30 diamonds at a time, instead of 5. What changes do you observe?


Great job, that’s everything for today!

Hopefully, this computer lab has helped cement your understanding of the Central Limit Theorem.


References


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.

LS0tDQp0aXRsZTogIlNUTTEwMDE6IENvbXB1dGVyIExhYiA1QiINCm91dHB1dDoNCiAgYm9va2Rvd246Omh0bWxfZG9jdW1lbnQyOiANCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgdGhlbWU6IHJlYWRhYmxlDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQpiaWJsaW9ncmFwaHk6IFNUTTEwMDFfRFNfQ0xfcmVmZXJlbmNlcy5iaWIgDQpsaW5rLWNpdGF0aW9uczogeWVzDQotLS0NCg0KPHN0eWxlPg0KI1RPQyB7DQogIGJhY2tncm91bmQ6IHVybCgiaHR0cHM6Ly93d3cubGF0cm9iZS5lZHUuYXUvX21lZGlhL2xhLXRyb2JlLWFwaS92NS9pbWcvbG9nby5zdmciKTsNCiAgYmFja2dyb3VuZC1zaXplOiBjb250YWluOw0KICBwYWRkaW5nLXRvcDogODBweCAhaW1wb3J0YW50Ow0KICBiYWNrZ3JvdW5kLXJlcGVhdDogbm8tcmVwZWF0Ow0KfQ0KPC9zdHlsZT4NCg0KIyMjIERhdGEgU2NpZW5jZSBTdHJlYW0gey19DQoNCiMjIyBUb3BpYyA1QjogU2ltdWxhdGlvbnMgaW4gUiB7LX0NCg0KPGJyPg0KDQpXZWxjb21lIHRvIHRoZSBmaWZ0aCBjb21wdXRlciBsYWIgZm9yIHRoZSBEYXRhIFNjaWVuY2Ugc3RyZWFtIG9mIFNUTTEwMDEuDQoNCkluIFtUb3BpYyA0XShodHRwczovL2Jvb2tkb3duLm9yZy9jb250ZW50Lzg4ZWY5YjdjLTU4MzMtNGE3MC04NGYyLTkzNDcwOTU3ZDFmOS8pLCB3ZSBpbnRyb2R1Y2VkIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbnMgYW5kIHRoZSBjb25jZXB0IG9mIHRoZSAqQ2VudHJhbCBMaW1pdCBUaGVvcmVtKi4gDQoNCkluIHRoaXMgY29tcHV0ZXIgbGFiIHdlIHdpbGwgdXNlIFIgdG8gY29uZHVjdCB0aGUgc2ltdWxhdGlvbnMgZGlzY3Vzc2VkIGluIFtDaGFwdGVyIDMgb2YgVG9waWMgNF0oaHR0cHM6Ly9ib29rZG93bi5vcmcvY29udGVudC84OGVmOWI3Yy01ODMzLTRhNzAtODRmMi05MzQ3MDk1N2QxZjkvMy10aGUtY2VudHJhbC1saW1pdC10aGVvcmVtLmh0bWwpLiANCg0KICAqICpJdCBtaWdodCBiZSBoZWxwZnVsIHRvIGtlZXAgdGhpcyBjb250ZW50IG9wZW4gaW4gYSBzZXBhcmF0ZSB0YWIgd2hpbGUgeW91IHdvcmsgdGhyb3VnaCB0aGUgbGFiIG1hdGVyaWFsLCBpbiBjYXNlIHlvdSB3b3VsZCBsaWtlIHRvIHF1aWNrbHkgZG91YmxlLWNoZWNrIHlvdXIgdW5kZXJzdGFuZGluZyBvZiBhbnkgY29uY2VwdHMuKg0KDQpCeSB0aGUgZW5kIG9mIHRoaXMgbGFiLCB5b3Ugc2hvdWxkIGJlIGFibGUgdG8gY29uZHVjdCBzaW1wbGUgc2ltdWxhdGlvbnMgaW4gUi4gTGV0J3MgZ2V0IHN0YXJ0ZWQhDQoNCiMgU2FtcGxpbmcgRGlzdHJpYnV0aW9ucw0KDQojIyBTYW1wbGluZw0KDQpgciBlbW86OmppKCJob3VzZV93aXRoX2dhcmRlbiIpYCBSZWNhbGwgdGhhdCBhICoqc2FtcGxlKiogaXMgYSByYW5kb20gc2VsZWN0aW9uIG9mIHVuaXRzIGZyb20gYSBjaG9zZW4gcG9wdWxhdGlvbi4NCg0KICAqIEZvciBleGFtcGxlLCBpZiB0aGUgU1RNMTAwMSBjb2hvcnQgd2FzIG91ciBjaG9zZW4gcG9wdWxhdGlvbiwgdGhlbiBhIHJhbmRvbSBzZWxlY3Rpb24gb2YgU1RNMTAwMSBzdHVkZW50cyB3b3VsZCBiZSBhICoqc2FtcGxlKiogZnJvbSB0aGlzIHBvcHVsYXRpb24uDQoNCkJlY2F1c2UgaXQgaXMgdHlwaWNhbGx5IHVuZmVhc2libGUgdG8gY29sbGVjdCBkYXRhIG9uIGFuIGVudGlyZSBwb3B1bGF0aW9uIG9mIGludGVyZXN0LCB3ZSBpbnN0ZWFkIGNvbmR1Y3QgYW5hbHlzZXMgdXNpbmcgYSBzYW1wbGUuIFdlIGhvcGUgdGhhdCB0aGUgaW5mZXJlbmNlcyB3ZSBtYWtlIHVzaW5nIHRoZSBzYW1wbGUgZGF0YSBjYW4gYmUgZXh0cmFwb2xhdGVkIHRvIHByb3ZpZGUgaW5mb3JtYXRpb24gYWJvdXQgdGhlIHBvcHVsYXRpb24sIGFuZCB3ZSBjYW4gdXNlIHN0YXRpc3RpY2FsIHRlY2huaXF1ZXMgdG8gYXNjZXJ0YWluIHRoZSBhY2N1cmFjeSBvZiB0aGVzZSBpbmZlcmVuY2VzLiANCg0KT25lIHN1Y2ggc3RhdGlzdGljYWwgdGVjaG5pcXVlIHdlIGNhbiB1dGlsaXNlIGlzIHRoZSBDZW50cmFsIExpbWl0IFRoZW9yZW0uDQoNCiMjIFRoZSBDZW50cmFsIExpbWl0IFRoZW9yZW0geyNDTFR9DQoNCmByIGVtbzo6amkoImhvdXNlX3dpdGhfZ2FyZGVuIilgIFJlY2FsbCB0aGUgZGVmaW5pdGlvbiBvZiB0aGUgQ2VudHJhbCBMaW1pdCBUaGVvcmVtIChDTFQpOg0KDQo8Y2VudGVyPg0KTGV0ICRYXzEsIFxsZG90cywgWF9uJCBiZSBhIHJhbmRvbSBzYW1wbGUgZnJvbSBhIGRpc3RyaWJ1dGlvbiB3aXRoIGZpbml0ZSBtZWFuICRcbXUkIGFuZCBmaW5pdGUgdmFyaWFuY2UgJFxzaWdtYV4yJC4gDQoNCkZvciAkXG92ZXJsaW5le1h9JCBkZW5vdGluZyB0aGUgc2FtcGxlIG1lYW4sIGlmICRuJCBpcyBzdWZmaWNpZW50bHkgbGFyZ2UgdGhlbg0KJCRcb3ZlcmxpbmV7WH1cc3RhY2tyZWx7XHRpbnkgXHRleHR7YXBwcm94Ln19XHNpbSBOXGxlZnQoXG11LFxmcmFje1xzaWdtYV4yfXtufVxyaWdodCkgLCAkJA0Kd2hlcmUgJFxzdGFja3JlbHtcdGlueSBcdGV4dHthcHByb3gufX1cc2ltJCBkZW5vdGVzICdhcHByb3hpbWF0ZWx5IGRpc3RyaWJ1dGVkIGFzJy4NCjwvY2VudGVyPg0KPGJyPg0KDQpCeSB0aGUgQ0xULCBpdCBmb2xsb3dzIHRoYXQgYXMgd2UgaW5jcmVhc2Ugb3VyIHNhbXBsZSBzaXplLCB0aGUgc2FtcGxlIG1lYW4gJFxvdmVybGluZXtYfSQgd2lsbCBnZXQgaW5jcmVhc2luZ2x5IGNsb3NlciAoaS5lLiBjb252ZXJnZSkgdG8gdGhlIHBvcHVsYXRpb24gbWVhbiAkXG11JC4gQXMgJG4kIGluY3JlYXNlcywgdGhlIHZhcmlhbmNlIG9mIHRoZSBzYW1wbGUgbWVhbiAkXG92ZXJsaW5le1h9JCB3aWxsIGFsc28gZGVjcmVhc2UuDQoNCkluIG90aGVyIHdvcmRzLCB3aGlsZSBzYW1wbGVzIG9mIGluZGl2aWR1YWxzIGNhbiBleGhpYml0IHNpZ25pZmljYW50IHZhcmlhdGlvbiwgc2FtcGxlcyBvZiBtZWFucyB0ZW5kIHRvIGhhdmUgbGVzcyB2YXJpYWJpbGl0eSAoYXMgZWFjaCBtZWFuIGlzIGNhbGN1bGF0ZWQgZnJvbSBhIHNhbXBsZSBvZiBpbmRpdmlkdWFscywgcmVkdWNpbmcgdGhlIGltcGFjdCBvZiBvdXRsaWVycykuDQoNCkxldCdzIHZpc3VhbGlzZSB0aGlzIHByb2Nlc3MgaW4gUiB1c2luZyBzb21lIHNpbXVsYXRpb25zLg0KDQojIFNpbXVsYXRpb25zIGluIFINCg0KQ2Fycnlpbmcgb3V0IHNpbXVsYXRpb25zIGluIFIgaXMgYWN0dWFsbHkgcXVpdGUgc3RyYWlnaHRmb3J3YXJkLiBXZSB3aWxsIHdhbGsgdGhyb3VnaCB0aGUgc3RlcHMgaW52b2x2ZWQgb25lIGF0IGEgdGltZS4NCg0KIyMgeyNiYXNlfQ0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCBTdXBwb3NlIHRoYXQgd2UgYXJlIGludGVyZXN0ZWQgaW4gdGhlIHJhbmRvbSB2YXJpYWJsZSAkWCBcc2ltIE4oMCwgMSkkIC0gaW4gb3RoZXIgd29yZHMsIGhlcmUgJFgkIGZvbGxvd3MgdGhlIHN0YW5kYXJkIG5vcm1hbCBkaXN0cmlidXRpb24uDQoNCldlIGNhbiBnZW5lcmF0ZSBhIHNhbXBsZSBvZiAxMDAgb2JzZXJ2YXRpb25zIGZyb20gdGhpcyBkaXN0cmlidXRpb24gdXNpbmcgdGhlIGZvbGxvd2luZyBSIGNvZGU6DQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFR9DQpzZXQuc2VlZCgxKQ0KbiA8LSAxMDANCnggPC0gcm5vcm0obikNCmBgYA0KDQpSdW4gdGhpcyBjb2RlIG5vdy4NCg0KKk5vdGU6IFRoZSBkZWZhdWx0IG1lYW4gYW5kIHN0YW5kYXJkIGRldmlhdGlvbiB2YWx1ZXMgdXNlZCBieSBgcm5vcm1gIGFyZSAwIGFuZCAxIHJlc3BlY3RpdmVseSwgc28gd2UgZG8gbm90IG5lZWQgdG8gc3BlY2lmeSB0aGVtIGluIHRoaXMgaW5zdGFuY2UuKg0KDQojIyB7I2Jhc2VoaXN0fQ0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCBXZSBjYW4gcGxvdCBvdXIgZ2VuZXJhdGVkIGRhdGEgdXNpbmcgdGhlIGBoaXN0YCBmdW5jdGlvbiwgYXMgc2hvd24gYmVsb3cuDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFR9DQpoaXN0KHgsIGZyZXEgPSBGQUxTRSwgY29sID0gImNoYXJ0cmV1c2UzIiwgeGxpbSA9IGMoLTMsIDMpLA0KICAgICBtYWluID0gcGFzdGUoIkhpc3RvZ3JhbSBvZiByYW5kb20gc2FtcGxlIFxuIGZyb20gc3RhbmRhcmQgTm9ybWFsIGRpc3RyaWJ1dGlvbiwgbiA9ICIsIG4pKSANCiMgT3ZlcmxheSBzdGFuZGFyZCBub3JtYWwgY3VydmUNCmN1cnZlKGRub3JtKHgpLCBhZGQgPSBUUlVFLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpDQojIEFkZCBsaW5lIGRlbm90aW5nIHNhbXBsZSBtZWFuDQphYmxpbmUodiA9IHJvdW5kKG1lYW4oeCksIDMpLCBjb2wgPSAicmVkIiwgbHdkID0gMiwgbHR5ID0gMikNCmBgYA0KDQoqTm90ZSB0aGF0IHdlIGhhdmUgYWxzbyB1c2VkIHRoZSBgY3VydmVgIGFuZCBgZG5vcm1gIGZ1bmN0aW9ucyBoZXJlIHRvIG92ZXJsYXkgdGhlIHN0YW5kYXJkIG5vcm1hbCBkaXN0cmlidXRpb24gcHJvYmFiaWxpdHkgZGVuc2l0eSBjdXJ2ZS4qDQoNCiMjDQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIE91ciBtYWluIGludGVyZXN0IGhlcmUgaXMgdGhlICoqc2FtcGxlIG1lYW4qKiwgbm90IHRoZSB2YXJpYWJpbGl0eSBvZiB0aGUgc2FtcGxlIHZhbHVlcy4gDQoNCklmIHdlIGNoZWNrIHRoZSBzYW1wbGUgbWVhbiBvZiBvdXIgZGF0YSBzZXQgYHhgLCB3ZSBmaW5kIHRoYXQgdGhpcyBpcyBlcXVhbCB0byBhcHByb3hpbWF0ZWx5IGByIHJvdW5kKG1lYW4oeCksIDMpYCAoc2hvd24gYnkgdGhlIHJlZCBkYXNoZWQgbGluZSBpbiB0aGUgcGxvdCBhYm92ZSkuIFNpbmNlIHRoaXMgaXMgdGhlIHNhbXBsZSBtZWFuIGZvciBqdXN0IG9uZSBzYW1wbGUgb2YgMTAwIG9ic2VydmF0aW9ucywgd2UgY2FuJ3QgYmUgdG9vIGNvbmZpZGVudCBpbiB1c2luZyB0aGlzIGVzdGltYXRlIGFzIGFuIGFjY3VyYXRlIGVzdGltYXRlIG9mIHRoZSBwb3B1bGF0aW9uIG1lYW4gKHdoaWNoIHdlIGtub3cgd2FzIHNwZWNpZmllZCB0byBiZSBgMGApLg0KDQpSYXRoZXIgdGhhbiByZWx5aW5nIG9uIGp1c3QgdGhlIG9uZSBzYW1wbGUgb2YgMTAwIG9ic2VydmF0aW9ucywgd2Ugd2lsbCBub3cgc2ltdWxhdGUgYSBudW1iZXIgb2YgcmFuZG9tIHNhbXBsZXMgZnJvbSAkWCQsIGluIG9yZGVyIHRvIG9idGFpbiBtdWx0aXBsZSBzYW1wbGUgbWVhbiBlc3RpbWF0ZXMsIHdoaWNoIHdlIGNhbiB1c2UgaW4gdHVybiB0byBvYnRhaW4gbW9yZSBhY2N1cmF0ZSBlc3RpbWF0ZSBvZiB0aGUgcG9wdWxhdGlvbiBtZWFuLg0KDQojIyB7I3N0YXJ0fQ0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCBUbyBiZWdpbiwgc3VwcG9zZSB3ZSBzYW1wbGUganVzdCA1IG9ic2VydmF0aW9ucyBvZiAkWCQsIHJhdGhlciB0aGFuIDEwMCwgYW5kIHRoZW4gY29tcHV0ZSB0aGUgc2FtcGxlIG1lYW4gb2YgdGhlc2UgNSBvYnNlcnZhdGlvbnMuDQoNClVzaW5nIHRoZSBjb2RlIGluIFxAcmVmKGJhc2UpLCBpdCBmb2xsb3dzIHRoYXQgdGhpcyBwcm9jZXNzIGlzIHF1aXRlIHN0cmFpZ2h0Zm9yd2FyZDoNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCnNldC5zZWVkKDEpDQpuIDwtIDUgIyBTcGVjaWZ5IHNhbXBsZSBzaXplDQp4IDwtIHJub3JtKG4pICMgR2VuZXJhdGUgbiBzYW1wbGVzIGZyb20gdGhlIHN0YW5kYXJkIG5vcm1hbCBkaXN0cmlidXRpb24NCm5vcm1fbWVhbiA8LSBtZWFuKHgpICMgU3RvcmUgdGhlIG1lYW4gb2YgdGhlIHNhbXBsZXMgaW4gYSBuZXcgb2JqZWN0DQpgYGANCg0KPGJyPg0KDQo8ZGV0YWlscz4NCiAgPHN1bW1hcnk+YHIgZW1vOjpqaSgiaGVhZHBob25lcyIpYCAqKk9ubGluZSBzdHVkZW50cyoqPC9zdW1tYXJ5Pg0KYHIgZW1vOjpqaSgic3BlZWNoX2JhbGxvb24iKWAgIFJ1biB5b3VyIG9iamVjdCBgbm9ybV9tZWFuYCBhbmQgcG9zdCB5b3VyIHJlc3VsdCBpbiB0aGUgY2hhdC4gIA0KPC9kZXRhaWxzPiANCg0KPGJyPg0KDQojIyBgZm9yIGxvb3BzYCB7I3NpbXN0YXJ0fQ0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCBTaW5jZSBvdXIgdW5kZXJseWluZyBkYXRhIGlzIGdlbmVyYXRlZCBmcm9tIGEgc3RhbmRhcmQgbm9ybWFsIGRpc3RyaWJ1dGlvbiwgaXQgZm9sbG93cyB0aGF0IHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHNhbXBsZSBtZWFuIHdpbGwgYWxzbyBiZSBub3JtYWwgKHdlIGNhbiB0aGluayBvZiB0aGlzIHJlc3VsdCBhcyBhIHByZWN1cnNvciB0byB0aGUgQ2VudHJhbCBMaW1pdCBUaGVvcmVtKS4gDQoNClRvIGFjY3VyYXRlbHkgdmlzdWFsaXNlIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHNhbXBsZSBtZWFuLCB3ZSB3aWxsIG5lZWQgdG8gcmVwZWF0IHRoZSBwcm9jZXNzIG91dGxpbmVkIGluIFxAcmVmKHN0YXJ0KSAqKm1hbnkgdGltZXMqKi4gVGhpcyBpcyB3aGVyZSBvdXIgc2ltdWxhdGlvbnMgY2FuIHJlYWxseSBzaGluZS4NCg0KU3VwcG9zZSwgcmF0aGVyIHRoYW4gY29uZHVjdGluZyB0aGUgcHJvY2VzcyBvdXRsaW5lZCBpbiBcQHJlZihzdGFydCkgb25jZSwgd2UgaW5zdGVhZCBjb25kdWN0IGl0IDEwLDAwMCB0aW1lcy4gSXQgd291bGQgdGFrZSBhIHdoaWxlIHRvIHdyaXRlIHRoaXMgY29kZSBvdXQgbGluZSBieSBsaW5lIGluIFIgKG92ZXIgOTAwMCBsaW5lcyBwb3RlbnRpYWxseSEpLg0KDQpJbnN0ZWFkLCB0byBzYXZlIHRpbWUsIHdlIHdpbGwgdXNlIGEgYGZvciBsb29wYC4gQSBgZm9yIGxvb3BgIGlzIGEgZnVuY3Rpb24gdGhhdCB3aWxsIHJlcGVhdCBhIHNwZWNpZmllZCBzZXQgb2Ygb3BlcmF0aW9ucyBhIHNwZWNpZmllZCBudW1iZXIgb2YgdGltZXMuDQoNClRoZSBgQ29kZWAgY2h1bmsgYmVsb3cgcHJvdmlkZXMgYSBzaW1wbGUgZXhhbXBsZSBvZiB0aGUgUiBzeW50YXggZm9yIGEgYGZvciBsb29wYC4NCg0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IEYsIGVjaG8gPSBUfQ0KZm9yKGkgaW4gMToxMCl7DQogIHggPC0gcm5vcm0oaSkNCiAgbWVhbih4KX0NCmBgYA0KDQpIb3cgZG8gd2UgaW50ZXJwcmV0IHRoaXMgY29kZT8NCldlbGwsd2UgaGF2ZSBzcGVjaWZpZWQgdGhhdCBmb3Igc29tZSBpbnB1dCBgaWAsIHdoZXJlIGBpYCBjYW4gdGFrZSB0aGUgaW50ZWdlciB2YWx1ZXMgMSB1cCB0byAxMCwgdGhlIGBmb3IgbG9vcGAgd2lsbCBzaW11bGF0ZSBgaWAgcmFuZG9tIHZhbHVlcyBmcm9tIHRoZSBzdGFuZGFyZCBOb3JtYWwgZGlzdHJpYnV0aW9uLCBzdG9yZSB0aGVtIGluIHRoZSBvYmplY3QgYHhgLCBhbmQgdGhlbiBjb21wdXRlIHRoZSBtZWFuIG9mIGB4YC4gDQoNClRodXMsIG91ciBgZm9yIGxvb3BgIHJ1bnMgbGlrZSB0aGlzOg0KDQoqIFRoZSBgZm9yIGxvb3BgIHN0YXJ0cyB3aXRoIHRoZSBmaXJzdCBzcGVjaWZpZWQgdmFsdWUsIDEsIGFuZCBzaW11bGF0ZXMgMSByYW5kb20gdmFsdWUgZnJvbSB0aGUgc3RhbmRhcmQgTm9ybWFsIGRpc3RyaWJ1dGlvbi4gDQoqIFRoZSBtZWFuIG9mIGB4YCBpcyBub3cgY29tcHV0ZWQuIFRoaXMgaXMgdGhlIGxhc3Qgb3BlcmF0aW9uIGluIHRoZSBgZm9yIGxvb3BgLg0KKiBTaW5jZSB0aGUgc3BlY2lmaWVkIG9wZXJhdGlvbnMgaW5zaWRlIHRoZSBsb29wIGhhdmUgYmVlbiBmaW5pc2hlZCBmb3IgdGhhdCB2YWx1ZSBvZiBgaWAsIHRoZSBsb29wIHN0YXJ0cyBhZ2Fpbiwgd2l0aCBgaT0yYCBub3cuIA0KKiBUaGlzIHByb2Nlc3MgY29udGludWVzLCB1bnRpbCB0aGUgZmluYWwgc3BlY2lmaWVkIHZhbHVlIG9mIGBpYCwgbmFtZWx5IGBpPTEwYCwgaGFzIGJlZW4gdXNlZC4gDQoqIEF0IHRoaXMgcG9pbnQsIHRoZSBgZm9yIGxvb3BgIGlzIGNvbXBsZXRlLg0KDQoqTm90ZTogV2UgZG8gbm90IGhhdmUgdG8gdXNlIHRoZSBsZXR0ZXIgYGlgIGhlcmUsIGl0IGlzIHNpbXBseSBjb252ZW50aW9uLiBZb3UgY2FuIHVzZSBhIGRpZmZlcmVudCBsZXR0ZXIsIGJ1dCByZW1lbWJlciwgbWFrZSBzdXJlIHlvdSBoYXZlIG5vdCB1c2VkIHlvdXIgY2hvc2VuIGxldHRlciBhcyBhIG5hbWUgZm9yIGEgcHJldmlvdXMgb2JqZWN0IGluIHdoaWNoIHlvdSBoYXZlIHN0b3JlZCBkYXRhLioNCg0KIyMgIHsjc2ltfQ0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCBUaGUgYENvZGVgIGNodW5rIGJlbG93IGV4cGFuZHMgdXBvbiB0aGUgYGZvciBsb29wYCBleGFtcGxlIGRpc2N1c3NlZCBhYm92ZSBpbiBcQHJlZihzaW1zdGFydCkuIFRha2UgYSBsb29rIGF0IHRoaXMgY29kZSwgcmVhZCB0aGUgY29tbWVudHMgY2FyZWZ1bGx5LCBhbmQgbWFrZSBzdXJlIHlvdSB1bmRlcnN0YW5kIHdoYXQgdGhlIGNvZGUgZG9lcyAobm90ZSBzb21lIHZhbHVlcyBhcmUgbWlzc2luZywgYXMgZGVub3RlZCBieSB0aGUgYC4uLmApLg0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IEYsIGVjaG8gPSBUfQ0KI1NwZWNpZnkgc2FtcGxlIHNpemUNCm5zIDwtIC4uLg0KIyBTcGVjaWZ5IG51bWJlciBvZiB0aW1lcyB0byBjb25kdWN0IHByb2Nlc3MgIA0KdHJpYWxzIDwtIC4uLg0KIyBjcmVhdGUgb2JqZWN0IGluIHdoaWNoIHRvIHN0b3JlIHNhbXBsZSBtZWFucyBvbmNlIHRoZXkgYXJlIGdlbmVyYXRlZA0Kbm9ybS5tZWFucyA8LSByZXAoMCwgdHJpYWxzKSAjIE5vdGUgbGVuZ3RoIGlzIGVxdWFsIHRvIHRoZSBudW1iZXIgb2YgdHJpYWxzDQojIFJ1biBmb3IgbG9vcCAgDQpmb3IoaSBpbiAxOnRyaWFscyl7DQogICAgIyBSYW5kb21seSBnZW5lcmF0ZSBucyBzYW1wbGVzIGZyb20gdGhlIG5vcm1hbCBkaXN0cmlidXRpb24NCiAgICB4IDwtIHJub3JtKG5zKSANCiAgICAjIENvbXB1dGUgbWVhbiBvZiBzYW1wbGVzLCBzdG9yZSBpbiB0aGUgbm9ybS5tZWFucyBvYmplY3QsIGluIGl0aCBwb3NpdGlvbiANCiAgICBub3JtLm1lYW5zW2ldIDwtIG1lYW4oeCl9DQpgYGANCg0KT25jZSB5b3UgZmVlbCBjb25maWRlbnQgaW4geW91ciB1bmRlcnN0YW5kaW5nIG9mIHRoaXMgY29kZSwgcmVwbGFjZSB0aGUgYC4uLmAgbWlzc2luZyBkZXRhaWxzIGZvciBgbnNgIGFuZCBgdHJpYWxzYCwgdXNpbmcgdGhlIGZvbGxvd2luZyBkZXRhaWxzOg0KDQoqIFlvdSB3YW50IHRvIHRha2UgMTAsMDAwIHNhbXBsZXMgb2YgcmFuZG9tbHkgZ2VuZXJhdGVkIHZhbHVlcyBmcm9tIHRoZSBzdGFuZGFyZCBOb3JtYWwgZGlzdHJpYnV0aW9uLg0KKiBFYWNoIHNhbXBsZSBzaG91bGQgaGF2ZSBhIHNhbXBsZSBzaXplIG9mIDUuDQoNCk9uY2UgeW91IGhhdmUgZmlsbGVkIGluIHRoZSBkZXRhaWxzLCBydW4geW91ciBjb2RlLg0KDQoqSGludDogSWYgeW91IGhhdmUgZ2l2ZW4gdGhpcyBhIGRlY2VudCBzaG90LCBidXQgYXJlIHN0dWNrLCB5b3UgY2FuIGNoZWNrIHRoZSBgQ29kZWAgY2h1bmsgYmVsb3c6Kg0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIiwgZXZhbCA9IFQsIGVjaG8gPSBUfQ0KI1NwZWNpZnkgc2FtcGxlIHNpemUNCm5zIDwtIDUNCiMgU3BlY2lmeSBudW1iZXIgb2YgdGltZXMgdG8gY29uZHVjdCBwcm9jZXNzICANCnRyaWFscyA8LSAxMDAwMA0KIyBjcmVhdGUgb2JqZWN0IGluIHdoaWNoIHRvIHN0b3JlIHNhbXBsZSBtZWFucyBvbmNlIHRoZXkgYXJlIGdlbmVyYXRlZA0Kbm9ybS5tZWFucyA8LSByZXAoMCwgdHJpYWxzKSAjIE5vdGUgbGVuZ3RoIGlzIGVxdWFsIHRvIHRoZSBudW1iZXIgb2YgdHJpYWxzDQojIFJ1biBmb3IgbG9vcCAgDQpmb3IoaSBpbiAxOnRyaWFscyl7DQogICAgIyBSYW5kb21seSBnZW5lcmF0ZSBucyBzYW1wbGVzIGZyb20gdGhlIG5vcm1hbCBkaXN0cmlidXRpb24NCiAgICB4IDwtIHJub3JtKG5zKSANCiAgICAjIENvbXB1dGUgbWVhbiBvZiBzYW1wbGVzLCBzdG9yZSBpbiB0aGUgbm9ybS5tZWFucyBvYmplY3QsIGluIGl0aCBwb3NpdGlvbiANCiAgICBub3JtLm1lYW5zW2ldIDwtIG1lYW4oeCl9DQpgYGANCg0KIyMgeyN2aXp9DQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIFRvIHZpc3VhbGlzZSBvdXIgcmVzdWx0cywgd2UgY2FuIHVzZSB0aGUgZm9sbG93aW5nIGNvZGU6DQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRiwgZWNobyA9IFR9DQpoaXN0KG5vcm0ubWVhbnMsIGZyZXEgPSBGQUxTRSwgYnJlYWtzID0gMjAsIGNvbCA9ICJyZWQiLCANCiAgICAgeGxpbSA9IGMoLTMsIDMpLA0KICAgICB4bGFiID0gZXhwcmVzc2lvbihiYXIoeCkpLA0KICAgICBtYWluID0gcGFzdGUoIkhpc3RvZ3JhbSBvZiBtZWFucywgbiA9ICIsIG5zKSkgDQpgYGANCg0KV2UgY2FuIGFsc28gb3ZlcmxheSBhIG5vcm1hbCBkZW5zaXR5IGN1cnZlLCB0aGF0LCBzaW5jZSBvdXIgdW5kZXJseWluZyBkYXRhIGlzIG5vcm1hbCwNCndpbGwgcmVmbGVjdCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBzYW1wbGUgbWVhbi4gDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRiwgZWNobyA9IFR9ICANCmN1cnZlKGRub3JtKHgsIA0KICAgICAgbWVhbiA9IDAsIHNkID0gMS9zcXJ0KG5zKSksIA0KICAgICAgYWRkID0gVFJVRSwgY29sID0gImJsdWUiLCBsd2QgPSAyKSANCmBgYA0KDQpSdW4gdGhlc2UgY29kZSBjaHVua3Mgbm93LCBhbmQgY2hlY2sgeW91ciByZXN1bHRzLiBBcmUgb3VyIHNpbXVsYXRlZCBzYW1wbGUgbWVhbnMgY2xvc2UgdG8gdGhlIHBvcHVsYXRpb24gbWVhbiBvZiAwPw0KDQojIw0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYFJlcGVhdCBzdGVwcyBcQHJlZihzaW0pIGFuZCBcQHJlZih2aXopLCB1c2luZyBhIHNhbXBsZSBvZiAzMCBpbnN0ZWFkIG9mIDUuIFdoYXQgZG8geW91IG5vdGljZSBhYm91dCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBzaW11bGF0ZWQgc2FtcGxlIG1lYW5zPw0KDQo8YnI+DQoNCjxkZXRhaWxzPg0KICA8c3VtbWFyeT5gciBlbW86OmppKCJoZWFkcGhvbmVzIilgICoqT25saW5lIHN0dWRlbnRzKio8L3N1bW1hcnk+DQpgciBlbW86OmppKCJzcGVlY2hfYmFsbG9vbiIpYCAgTGVhdmUgYSBjb21tZW50IGluIHRoZSBjaGF0IGFib3V0IHRoZSBjaGFuZ2VzIHlvdSBvYnNlcnZlIGluIHRoZSBkaXN0cmlidXRpb24sIGNoYW5naW5nIGZyb20gJG49NSQgdG8gJG49MzAkLg0KPC9kZXRhaWxzPiANCg0KPGJyPg0KDQojIw0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCBGaW5hbGx5LCByZXBlYXQgc3RlcHMgXEByZWYoc2ltKSBhbmQgXEByZWYodml6KSwgdXNpbmcgYSBzYW1wbGUgb2YgNjAuIFdoYXQgZG8geW91IG5vdGljZSBhYm91dCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBzaW11bGF0ZWQgc2FtcGxlIG1lYW5zIG5vdz8NCg0KPGJyPg0KDQo8ZGV0YWlscz4NCiAgPHN1bW1hcnk+YHIgZW1vOjpqaSgiaGVhZHBob25lcyIpYCAqKk9ubGluZSBzdHVkZW50cyoqPC9zdW1tYXJ5Pg0KYHIgZW1vOjpqaSgic3BlZWNoX2JhbGxvb24iKWAgIExlYXZlIGEgY29tbWVudCBpbiB0aGUgY2hhdCBhYm91dCB0aGUgY2hhbmdlcyB5b3Ugb2JzZXJ2ZSBpbiB0aGUgZGlzdHJpYnV0aW9uLCBjaGFuZ2luZyBmcm9tICRuPTMwJCB0byAkbj02MCQuDQo8L2RldGFpbHM+IA0KDQo8YnI+DQoNCiMgQ0xUIFNpbXVsYXRpb24gLSBFeHBvbmVudGlhbCBEaXN0cmlidXRpb24NCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgVG8gZGVtb25zdHJhdGUgdGhlIHZlcnNhdGlsaXR5IG9mIHRoZSBDZW50cmFsIExpbWl0IFRoZW9yZW0sIGxldCdzIGNhcnJ5IG91dCBzb21lIHNpbXVsYXRpb25zIGludm9sdmluZyBkYXRhIGdlbmVyYXRlZCBmcm9tIHRoZSAqKkV4cG9uZW50aWFsIGRpc3RyaWJ1dGlvbioqLCB3aGljaCAodW5saWtlIHRoZSBOb3JtYWwgZGlzdHJpYnV0aW9uKSBpcyBoaWdobHkgc2tld2VkIChpLmUuIGFzeW1tZXRyaWMpLiANCg0KIyMgeyNleHBzaW1zdGFydH0NCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgUmVjYWxsIGZyb20gW1RvcGljIDNdKGh0dHBzOi8vYm9va2Rvd24ub3JnL2Ffc2hha2VyL1NUTTEwMDFfVG9waWNfMy81LW90aGVyLWNvbnRpbnVvdXMtZGlzdHJpYnV0aW9ucy5odG1sKSB0aGF0IHRoZSBFeHBvbmVudGlhbCBkaXN0cmlidXRpb24gaXMgZGVmaW5lZCBieSBvbmUgcGFyYW1ldGVyLCBrbm93biBhcyB0aGUgKnJhdGUgcGFyYW1ldGVyKi4gVGhlIHJhdGUgcGFyYW1ldGVyIGlzIGRlbm90ZWQgYnkgdGhlIEdyZWVrIGxldHRlciAkXGxhbWJkYSQuIA0KDQpJZiBhIHJhbmRvbSB2YXJpYWJsZSAkWCQgZm9sbG93cyBhbiBFeHBvbmVudGlhbCBkaXN0cmlidXRpb24gd2l0aCByYXRlIHBhcmFtZXRlciAkXGxhbWJkYSQsIHdlIHdyaXRlICRYXHNpbSBFeHAoXGxhbWJkYSkkLg0KDQpTdXBwb3NlIG5vdyB0aGF0IG91ciByYW5kb20gdmFyaWFibGUgJFgkIGZvbGxvd3MgYW4gZXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uIHdpdGggcmF0ZSBwYXJhbWV0ZXIgJFxsYW1iZGEgPSAxMCQuIEluIG90aGVyIHdvcmRzLCBzdXBwb3NlICRYIFxzaW0gXHRleHR7RXhwfSgxMCkkLg0KDQpXZSBjYW4gZ2VuZXJhdGUgYSBzYW1wbGUgb2YgMTAwIG9ic2VydmF0aW9ucyBmcm9tIHRoaXMgZGlzdHJpYnV0aW9uIHVzaW5nIHRoZSBmb2xsb3dpbmcgUiBjb2RlOg0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBUfQ0Kc2V0LnNlZWQoMSkNCm4gPC0gMTAwDQpyYXRlID0gMTANCnggPC0gcmV4cChuLCByYXRlID0gcmF0ZSkNCmBgYA0KDQoqTm90ZSB0aGF0IHdlIHVzZSBgcmV4cGAgdG8gcmFuZG9tbHkgZ2VuZXJhdGUgdmFsdWVzIGZyb20gdGhlIGV4cG9uZW50aWFsIGRpc3RyaWJ1dGlvbiwgaW5zdGVhZCBvZiB1c2luZyBgcm5vcm1gICh3aGljaCBpcyBmb3IgdGhlIG5vcm1hbCBkaXN0cmlidXRpb24pLioNCg0KUnVuIHRoaXMgY29kZSBub3cuDQoNCiMjDQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIE91ciBnZW5lcmF0ZWQgZGF0YSBmcm9tIFxAcmVmKGV4cHNpbXN0YXJ0KSBpcyBoaWdobHkgc2tld2VkLCBhbmQgY2xlYXJseSBkaWZmZXJlbnQgdG8gZGF0YSBnZW5lcmF0ZWQgZnJvbSB0aGUgc3ltbWV0cmljIG5vcm1hbCBkaXN0cmlidXRpb24uIFRoaXMgZGlzcGFyaXR5IGNhbiBiZSBzZWVuIGluIEZpZ3VyZSAzLjEgYmVsb3csIHdoaWNoIHNob3dzIGEgaGlzdG9ncmFtIG9mIHRoZSBkYXRhLCB3aXRoIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiBwcm9iYWJpbGl0eSBkZW5zaXR5IGN1cnZlIG92ZXJsYWlkIGluIGJsdWUgKHNpbWlsYXIgdG8gaW4gXEByZWYoYmFzZWhpc3QpKSwgYmFzZWQgb24gYXBwcm9wcmlhdGUgbWVhbiBhbmQgdmFyaWFuY2UgdmFsdWVzLg0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBGLCBmaWcuZGltID0gYyg2LDYpLCBmaWcuY2FwID0gIkRhdGEgZ2VuZXJhdGVkIGZyb20gYW4gRXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uLCB3aXRoIGEgbm9ybWFsIGN1cnZlIG92ZXJsYWlkLiJ9DQpoaXN0KHgsIGZyZXEgPSBGQUxTRSwgY29sID0gImNoYXJ0cmV1c2UzIiwgeGxpbSA9IGMoMCwgMC41KSwNCiAgICAgbWFpbiA9IHBhc3RlKCJIaXN0b2dyYW0gb2YgcmFuZG9tIHNhbXBsZSBcbiBmcm9tIEV4cG9uZW50aWFsIGRpc3RyaWJ1dGlvbiwgbiA9ICIsIG4pKQ0KY3VydmUoZG5vcm0oeCwgMS9yYXRlLCAxL3JhdGUpLCBhZGQgPSBUUlVFLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpDQpgYGANCg0KDQpDbGVhcmx5LCB3ZSBjYW5ub3QgZml0IGEgbm9ybWFsIGN1cnZlIHdlbGwgdG8gZGF0YSBnZW5lcmF0ZWQgZnJvbSBhbiBFeHBvbmVudGlhbCBkaXN0cmlidXRpb24uIEhvd2V2ZXIsIGFzIHdlIHdvcmsgdGhyb3VnaCB0aGlzIHF1ZXN0aW9uLCB3ZSB3aWxsIGZpbmQgdGhhdCB3aGVuIHdlIG1vZGVsIHRoZSAqKmRpc3RyaWJ1dGlvbiBvZiB0aGUgc2FtcGxlIG1lYW5zKiogb2YgZGF0YSBnZW5lcmF0ZWQgZnJvbSBhbiBFeHBvbmVudGlhbCBkaXN0cmlidXRpb24sIHRoaXMgZGlzdHJpYnV0aW9uIG9mIHNhbXBsZSBtZWFucyAqKmNhbioqIGJlIGZpdHRlZCB3ZWxsIGJ5IGEgbm9ybWFsIGN1cnZlLCBlc3BlY2lhbGx5IGFzIG91ciBzYW1wbGUgc2l6ZSBpbmNyZWFzZXMuIFRoaXMgKHNvbWV3aGF0IHVuaW50dWl0aXZlKSByZXN1bHQgaXMgZHVlIHRvIHRoZSBDZW50cmFsIExpbWl0IFRoZW9yZW0hDQoNCiMjIFRoZSBSYXRlIFBhcmFtZXRlciBhbmQgUG9wdWxhdGlvbiBNZWFuDQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIEluc3RlYWQgb2YgY29uc2lkZXJpbmcgdGhlIGluZGl2aWR1YWwgZGF0YSBwb2ludHMgZ2VuZXJhdGVkIGZyb20gdGhlIEV4cG9uZW50aWFsIGRpc3RyaWJ1dGlvbiwgbGV0J3Mgc2hpZnQgb3VyIGZvY3VzIHRvIHRoZSBzYW1wbGUgbWVhbiBvZiB0aGVzZSBkYXRhIHBvaW50cy4NCg0KRm9yIGRhdGEgZ2VuZXJhdGVkIGZyb20gYW4gRXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uLCB0aGUgcG9wdWxhdGlvbiBtZWFuICRcbXUkIGlzIGluIHRoZW9yeSBlcXVhbCB0byAxIGRpdmlkZWQgYnkgdGhlIHJhdGUgcGFyYW1ldGVyICRcbGFtYmRhJC4gSS5lLiwgZm9yICRYXHNpbSBFeHAoXGxhbWJkYSkkLCB0aGUgcG9wdWxhdGlvbiBtZWFuIG9mICRYJCBlcXVhbHMgJFxmcmFjezF9e1xsYW1iZGF9JC4gDQoNCklmIHdlIGNoZWNrIHRoZSBzYW1wbGUgbWVhbiBvZiBgeGAsIHdlIGZpbmQgdGhhdCB0aGlzIGlzIGVxdWFsIHRvIGByIG1lYW4oeClgIC0gdGhpcyBzYW1wbGUgbWVhbiBpcyBxdWl0ZSBhIGdvb2QgZXN0aW1hdGUgb2YgdGhlIHBvcHVsYXRpb24gbWVhbiAoJFxtdSA9IDEvMTAgPSAwLjEkKSwgZ2l2ZW4gdGhlIHRoZW9yeS4NCg0KIyMgeyNleHBzaW19DQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIExldCB1cyBub3cgY29uZHVjdCB0aGUgc2ltdWxhdGlvbiBwcm9jZXNzIHVzZWQgaW4gXEByZWYoc2ltKSwgZm9yIG91ciBkYXRhIHNhbXBsZWQgZnJvbSAkWCBcc2ltIFx0ZXh0e0V4cH0oMTApJC4NCg0KVXNpbmcgdGhlIGNvZGUgaW4gXEByZWYoc2ltKSBhcyBhIGd1aWRlLCBzaW11bGF0ZSAxMCwwMDAgc2FtcGxlIG1lYW5zIG9mICRYJCwgdXNpbmcgc2FtcGxlcyBvZiBzaXplIDUuDQoNClBsb3QgeW91ciByZXN1bHRzLCB1c2luZyB0aGUgY29kZSBpbiBcQHJlZih2aXopIGFzIGEgZ3VpZGUuDQoNCipOb3RlOiBZb3Ugd2lsbCBoYXZlIHRvIGNoYW5nZSB0aGUgeC1heGlzIHJhbmdlIGZvciB0aGUgaGlzdG9ncmFtICh2aWEgdGhlIGB4bGltYCBhcmd1bWVudCkuIFRyeSB1c2luZyBhIHJhbmdlIG9mIDAgdG8gMC40LioNCg0KKk5vdGUgMjogVXNlIHRoZSBjb2RlIGluIHRoZSBgQ29kZWAgY2h1bmsgYmVsb3cgdG8gb3ZlcmxheSB0aGUgYXBwcm9wcmlhdGUgTm9ybWFsIGRpc3RyaWJ1dGlvbiBwcm9iYWJpbGl0eSBkZW5zaXR5IGN1cnZlOioNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCmN1cnZlKGRub3JtKHgsIG1lYW4gPSAxL3JhdGUsIHNkID0gMS9yYXRlL3NxcnQobnMpKSwgYWRkID0gVFJVRSwNCiAgICAgICAgY29sID0gImJsdWUiLCBsd2QgPSAyKQ0KYGBgDQoNCiMjDQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIFdoYXQgZG8geW91IG5vdGljZSBhYm91dCB5b3VyIHJlc3VsdGFudCBwbG90Pw0KDQojIw0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCBSZXBlYXRzIFxAcmVmKGV4cHNpbSkgZm9yICRYIFxzaW0gRXhwKDEwKSQsIHVzaW5nIGEgc2FtcGxlIG9mIDMwIGluc3RlYWQgb2YgNS4gV2hhdCBkbyB5b3Ugbm90aWNlIGFib3V0IHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHNpbXVsYXRlZCBzYW1wbGUgbWVhbnM/DQoNCjxicj4NCg0KPGRldGFpbHM+DQogIDxzdW1tYXJ5PmByIGVtbzo6amkoImhlYWRwaG9uZXMiKWAgKipPbmxpbmUgc3R1ZGVudHMqKjwvc3VtbWFyeT4NCmByIGVtbzo6amkoInNwZWVjaF9iYWxsb29uIilgICBMZWF2ZSBhIGNvbW1lbnQgaW4gdGhlIGNoYXQgYWJvdXQgdGhlIGNoYW5nZXMgeW91IG9ic2VydmUgaW4gdGhlIGRpc3RyaWJ1dGlvbiwgY2hhbmdpbmcgZnJvbSAkbj01JCB0byAkbj0zMCQuDQo8L2RldGFpbHM+IA0KDQo8YnI+DQoNCiMjDQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIEZpbmFsbHksIHJlcGVhdCBcQHJlZihleHBzaW0pIGZvciAkWCBcc2ltIEV4cCgxMCkkLCB1c2luZyBhIHNhbXBsZSBvZiA2MC4gV2hhdCBkbyB5b3Ugbm90aWNlIGFib3V0IHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHNpbXVsYXRlZCBzYW1wbGUgbWVhbnMgbm93Pw0KDQo8YnI+DQoNCjxkZXRhaWxzPg0KICA8c3VtbWFyeT5gciBlbW86OmppKCJoZWFkcGhvbmVzIilgICoqT25saW5lIHN0dWRlbnRzKio8L3N1bW1hcnk+DQpgciBlbW86OmppKCJzcGVlY2hfYmFsbG9vbiIpYCAgTGVhdmUgYSBjb21tZW50IGluIHRoZSBjaGF0IGFib3V0IHRoZSBjaGFuZ2VzIHlvdSBvYnNlcnZlIGluIHRoZSBkaXN0cmlidXRpb24sIGNoYW5naW5nIGZyb20gJG49MzAkIHRvICRuPTYwJC4NCjwvZGV0YWlscz4gDQoNCjxicj4NCg0KIyBDTFQgU2ltdWxhdGlvbiAtIEJlcm5vdWxsaSBEaXN0cmlidXRpb24NCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgQXMgZGlzY3Vzc2VkIGluIFtTZWN0aW9uIDMuMyBvZiBUb3BpYyA0XShodHRwczovL2Jvb2tkb3duLm9yZy9jb250ZW50Lzg4ZWY5YjdjLTU4MzMtNGE3MC04NGYyLTkzNDcwOTU3ZDFmOS8zLTMtY2x0LXNpbXVsYXRlZC1leGFtcGxlLXdpdGgtYmVybm91bGxpLWRpc3RyaWJ1dGVkLXBvcHVsYXRpb24uaHRtbCksIHRoZSBDZW50cmFsIExpbWl0IFRoZW9yZW0gZXZlbiBhcHBsaWVzIHRvIGRpc2NyZXRlIHJhbmRvbSB2YXJpYWJsZXMuDQoNClN1cHBvc2UgdGhhdCBvdXIgcmFuZG9tIHZhcmlhYmxlICRYJCBub3cgZm9sbG93cyBhIEJlcm5vdWxsaSBkaXN0cmlidXRpb24gd2l0aCBzdWNjZXNzIHBhcmFtZXRlciAkcCA9IDAuMyQuIEluIG90aGVyIHdvcmRzLCBzdXBwb3NlICRYIFxzaW0gXHRleHR7QkVSTn0oMC4zKSQuDQoNCiMjDQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIElmIHdlIGdlbmVyYXRlIGEgc2FtcGxlIG9mIDEwMCBvYnNlcnZhdGlvbnMgZnJvbSB0aGlzIGRpc3RyaWJ1dGlvbiAoc2VlIHRoZSBSIGNvZGUgYmVsb3cpIGFuZCB0aGVuIHZpc3VhbGlzZSBvdXIgZ2VuZXJhdGVkIGRhdGEsIHdlIHNlZSBhIHJvdWdobHkgNzAvMzAgc3BsaXQgb2Ygb2JzZXJ2YXRpb25zIGJldHdlZW4gJHg9MCQgYW5kICR4PTEkLiBDbGVhcmx5LCAoanVzdCBhcyBpbiB0aGUgRXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uIGNhc2UpLCB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbiBwcm9iYWJpbGl0eSBkZW5zaXR5IGN1cnZlLCB3aXRoIGFwcHJvcHJpYXRlIHBhcmFtZXRlciBzcGVjaWZpY2F0aW9ucywgKHNob3duIGluIGJsdWUpLCBpcyBhbiBleHRyZW1lbHkgcG9vciBmaXQgZm9yIHRoaXMgZGF0YS4NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVH0NCnNldC5zZWVkKDEpDQpuIDwtIDEwMA0KcCA9IDAuMw0KeCA8LSByYmlub20obiwgMSwgcCkNCmBgYA0KDQoqTm90ZSB0aGF0IHdlIHVzZSBgcmJpbm9tYCB0byByYW5kb21seSBnZW5lcmF0ZSB2YWx1ZXMgZnJvbSB0aGUgQmVybm91bGxpIGRpc3RyaWJ1dGlvbiwgaW5zdGVhZCBvZiB1c2luZyBgcm5vcm1gICh3aGljaCBpcyBmb3IgdGhlIG5vcm1hbCBkaXN0cmlidXRpb24pLioNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gRn0NCmhpc3QoeCwgZnJlcSA9IEZBTFNFLCBjb2wgPSAiY2hhcnRyZXVzZTMiLCB4bGltID0gYygwLCAxKSwNCiAgICAgbWFpbiA9IHBhc3RlKCJIaXN0b2dyYW0gb2YgcmFuZG9tIHNhbXBsZSBcbiBmcm9tIEJlcm5vdWxsaSBkaXN0cmlidXRpb24sIG4gPSAiLCBuKSkgDQpjdXJ2ZShkbm9ybSh4LCBwLCBzZCA9IHNxcnQocCooMSAtIHApKSksIGFkZCA9IFRSVUUsIGNvbCA9ICJibHVlIiwgbHdkID0gMikNCmBgYA0KDQojIw0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCBIb3dldmVyLCBkZXNwaXRlIG91ciBkYXRhIGJlaW5nIGdlbmVyYXRlZCBmcm9tIGEgZGlzY3JldGUgZGlzdHJpYnV0aW9uLCB3ZSBjYW4gc3RpbGwgdXNlIHRoZSBDZW50cmFsIExpbWl0IFRoZW9yZW0gdG8gb2J0YWluIGFuIGFjY3VyYXRlIGVzdGltYXRlIG9mIHRoZSBwb3B1bGF0aW9uIG1lYW4gYnkgY29uc2lkZXJpbmcgdGhlIGRpc3RyaWJ1dGlvbiBvZiAkXGJhcntYfSQhDQoNCkxldCB1cyBub3cgY29uZHVjdCB0aGUgc2ltdWxhdGlvbiBwcm9jZXNzIHVzZWQgaW4gXEByZWYoc2ltKSwgZm9yIG91ciBCZXJub3VsbGktZGlzdHJpYnV0ZWQgZGF0YS4NCg0KVXNpbmcgdGhlIGNvZGUgaW4gXEByZWYoc2ltKSBhcyBhIGd1aWRlLCBzaW11bGF0ZSAxMDAwMCBzYW1wbGUgbWVhbnMgb2YgJFgkLCB1c2luZyBzYW1wbGVzIG9mIHNpemUgNS4NClRoZW4sIHBsb3QgeW91ciByZXN1bHRzLCB1c2luZyB0aGUgY29kZSBpbiBcQHJlZih2aXopIGFzIGEgZ3VpZGUuDQoNCipOb3RlOiBZb3Ugd2lsbCBoYXZlIHRvIGNoYW5nZSB0aGUgeC1heGlzIHJhbmdlIGZvciB0aGUgaGlzdG9ncmFtICh2aWEgdGhlIGB4bGltYCBhcmd1bWVudCkuKg0KDQoqTm90ZSAyOiBVc2UgdGhlIGNvZGUgaW4gdGhlIGBDb2RlYCBjaHVuayBiZWxvdyB0byBvdmVybGF5IGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiBwcm9iYWJpbGl0eSBkZW5zaXR5IGN1cnZlIHdpdGggdGhlIGFwcHJvcHJpYXRlIHBhcmFtZXRlciBzcGVjaWZpY2F0aW9uczoqDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRiwgZWNobyA9IFR9DQojIFNldCBtdSBhbmQgc2lnbWEgZm9yIHRoZSBhcHByb3hpbWF0aW5nIG5vcm1hbCBkaXN0cmlidXRpb24NCm11IDwtIHANCnNpZ21hIDwtIHNxcnQocCooMSAtIHApKQ0KIyBPdmVybGF5IHRoZSBub3JtYWwgZGVuc2l0eQ0KY3VydmUoZG5vcm0oeCwgbXUsIHNpZ21hL3NxcnQobnMpKSwgYWRkID0gVFJVRSwgY29sID0gImJsdWUiLCBsd2QgPSAyKQ0KYGBgDQoNCiMjDQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIFdoYXQgZG8geW91IG5vdGljZSBhYm91dCB5b3VyIHJlc3VsdGFudCBwbG90Pw0KDQojIw0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCBSZXBlYXQgXEByZWYoZXhwc2ltKSBmb3IgJFggXHNpbSBCRVJOKDAuMykkLCB1c2luZyBhIHNhbXBsZSBvZiAzMCBpbnN0ZWFkIG9mIDUuIFdoYXQgZG8geW91IG5vdGljZSBhYm91dCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBzaW11bGF0ZWQgc2FtcGxlIG1lYW5zPw0KDQo8YnI+DQoNCjxkZXRhaWxzPg0KICA8c3VtbWFyeT5gciBlbW86OmppKCJoZWFkcGhvbmVzIilgICoqT25saW5lIHN0dWRlbnRzKio8L3N1bW1hcnk+DQpgciBlbW86OmppKCJzcGVlY2hfYmFsbG9vbiIpYCAgTGVhdmUgYSBjb21tZW50IGluIHRoZSBjaGF0IGFib3V0IHRoZSBjaGFuZ2VzIHlvdSBvYnNlcnZlIGluIHRoZSBkaXN0cmlidXRpb24sIGNoYW5naW5nIGZyb20gJG49NSQgdG8gJG49MzAkLg0KPC9kZXRhaWxzPiANCg0KPGJyPg0KDQojIw0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCBGaW5hbGx5LCByZXBlYXQgXEByZWYoZXhwc2ltKSBmb3IgJFggXHNpbSBCRVJOKDAuMykkLCB1c2luZyBhIHNhbXBsZSBvZiA2MC4gV2hhdCBkbyB5b3Ugbm90aWNlIGFib3V0IHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHNpbXVsYXRlZCBzYW1wbGUgbWVhbnMgbm93Pw0KDQo8YnI+DQoNCjxkZXRhaWxzPg0KICA8c3VtbWFyeT5gciBlbW86OmppKCJoZWFkcGhvbmVzIilgICoqT25saW5lIHN0dWRlbnRzKio8L3N1bW1hcnk+DQpgciBlbW86OmppKCJzcGVlY2hfYmFsbG9vbiIpYCAgTGVhdmUgYSBjb21tZW50IGluIHRoZSBjaGF0IGFib3V0IHRoZSBjaGFuZ2VzIHlvdSBvYnNlcnZlIGluIHRoZSBkaXN0cmlidXRpb24sIGNoYW5naW5nIGZyb20gJG49MzAkIHRvICRuPTYwJC4NCjwvZGV0YWlscz4gDQoNCjxicj4NCg0KIyBFeHRlbnNpb246IEF2ZXJhZ2UgRGlhbW9uZCBQcmljZXMNCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgTGV0J3MgY29uc2lkZXIgaG93IHdlIGNhbiBhcHBseSB0aGUgQ2VudHJhbCBMaW1pdCBUaGVvcmVtIHRvIHJlYWwgZGF0YS4NCg0KRm9yIHRoaXMgcXVlc3Rpb24sIHdlIHdpbGwgY29uc2lkZXIgZGF0YSBvbiBhcHByb3hpbWF0ZWx5IDU0LDAwMCByb3VuZCBjdXQgZGlhbW9uZHMuIFRoaXMgZGF0YSBpcyBzdG9yZWQgaW4gdGhlIGBkaWFtb25kc2AgZGF0YSBzZXQgaW4gdGhlIGBnZ3Bsb3QyYCBSIHBhY2thZ2UuIFdlIHdpbGwgdHJlYXQgdGhpcyBkYXRhIGFzIHRoZSBwb3B1bGF0aW9uIGRhdGEuDQoNCkluc3RhbGwgYW5kIGxvYWQgdGhlIGBnZ3Bsb3QyYCBSIHBhY2thZ2Ugbm93Lg0KDQoqSGludDogSWYgeW91IG5lZWQgYSByZWZyZXNoZXIgb24gaW5zdGFsbGluZyBhbmQgbG9hZGluZyBwYWNrYWdlcyBpbiBSLCBjaGVjayB0aGUgYENvZGVgIGNodW5rIGJlbG93OioNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCmluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KYGBgDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUiLCBldmFsID0gVCwgaW5jbHVkZSA9IEZ9DQpsaWJyYXJ5KGdncGxvdDIpDQpgYGANCg0KIyMNCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgSWYgd2UgcGxvdCB0aGUgcHJpY2Ugb2Ygcm91bmQgY3V0IGRpYW1vbmRzIHVzaW5nIGEgaGlzdG9ncmFtLCB3ZSBjYW4gc2VlIHRoYXQgdGhlIGRhdGEgaXMgY2xlYXJseSBub3Qgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuDQoNCipNYWtlIHN1cmUgdG8gcnVuIHRoaXMgY29kZSBiZWZvcmUgY29udGludWluZy4qDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFR9DQpoaXN0KGRpYW1vbmRzJHByaWNlLCBjb2wgPSAic2t5Ymx1ZSIsIHhsYWIgPSAiRGlhbW9uZCBQcmljZSAoJCkiLA0KICAgICBtYWluID0gIkhpc3RvZ3JhbSBvZiBEaWFtb25kIFByaWNlcyAoJCkiLCBmcmVxID0gRikNCmBgYA0KDQojIyB7I2RpYW1vbmRzaW19DQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIFN1cHBvc2UgdGhhdCB5b3UgYXJlIGludGVyZXN0ZWQgaW4gZXN0aW1hdGluZyB0aGUgcG9wdWxhdGlvbiBtZWFuIHByaWNlIGZvciByb3VuZCBjdXQgZGlhbW9uZHMsIGJ1dCBkbyBub3QgaGF2ZSBhY2Nlc3MgdG8gdGhlIGZ1bGwgYGRpYW1vbmRzYCBkYXRhIHNldC4NCg0KSW5zdGVhZCwgeW91IGNhbiBvbmx5IHNhbXBsZSBwcmljZXMgZm9yIDUgcm91bmQgY3V0IGRpYW1vbmRzIGF0IGEgdGltZSwgcmVwcmVzZW50ZWQgYnkgdGhlIGNvZGUgYmVsb3c6DQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFR9DQp4IDwtIHNhbXBsZShkaWFtb25kcyRwcmljZSwgNSkNCmBgYA0KDQpVc2luZyB0aGlzIGNvZGUgYW5kIHRoZSBjb2RlIGluIFxAcmVmKHNpbSkgYXMgYSBndWlkZSwgb2J0YWluIDEwMCBzYW1wbGUgbWVhbnMgZnJvbSAxMDAgc2ltdWxhdGVkIHNhbXBsZXMgb2YgNSByYW5kb20gcm91bmQgY3V0IGRpYW1vbmQgc2FsZSBwcmljZXMuIFBsb3QgYSBoaXN0b2dyYW0gb2YgdGhlc2Ugc2FtcGxlIG1lYW5zLiBXaGF0IGRvIHlvdSBvYnNlcnZlPw0KDQo8YnI+DQoNCjxkZXRhaWxzPg0KICA8c3VtbWFyeT5gciBlbW86OmppKCJoZWFkcGhvbmVzIilgICoqT25saW5lIHN0dWRlbnRzKio8L3N1bW1hcnk+DQpgciBlbW86OmppKCJzcGVlY2hfYmFsbG9vbiIpYCAgVm9sdW50ZWVyIHRvIHNoYXJlIHlvdXIgc2NyZWVuIHRvIHNob3cgeW91ciBoaXN0b2dyYW0gYW5kIGRpc2N1c3MgeW91ciByZXN1bHRzLCBpZiB5b3UgZ290IHRvIHRoaXMgc3RhZ2UgYmVmb3JlIHRoZSBlbmQgb2YgdGhlIGxhYi4NCjwvZGV0YWlscz4gDQoNCjxicj4NCg0KIyMgeyNkaWFtb25kc2ltbGFyZ2V9DQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIFJlcGVhdCBcQHJlZihkaWFtb25kc2ltKSwgYnV0IHRoaXMgdGltZSBzdXBwb3NlIHRoYXQgeW91IGFyZSBhYmxlIHRvIHRha2Ugc2FtcGxlcyBvZiAzMCBkaWFtb25kcyBhdCBhIHRpbWUsIGluc3RlYWQgb2YgNS4gV2hhdCBjaGFuZ2VzIGRvIHlvdSBvYnNlcnZlPyANCg0KPGJyPg0KDQojIyMjIEdyZWF0IGpvYiwgdGhhdCdzIGV2ZXJ5dGhpbmcgZm9yIHRvZGF5ISAjIyMjIHstfQ0KDQpIb3BlZnVsbHksIHRoaXMgY29tcHV0ZXIgbGFiIGhhcyBoZWxwZWQgY2VtZW50IHlvdXIgdW5kZXJzdGFuZGluZyBvZiB0aGUgQ2VudHJhbCBMaW1pdCBUaGVvcmVtLg0KDQo8YnI+DQoNCiMgUmVmZXJlbmNlcyB7LSAjUmVmfQ0KPGRpdiBpZD0icmVmcyI+PC9kaXY+DQoNCjxicj4NCg0KPGZvbnQgY29sb3IgPSAiZ3JleSI+DQpUaGVzZSBub3RlcyBoYXZlIGJlZW4gcHJlcGFyZWQgYnkgUnVwZXJ0IEt1dmVrZSBhbmQgQW1hbmRhIFNoYWtlci4gVGhlIGNvcHlyaWdodCBmb3IgdGhlIG1hdGVyaWFsIGluIHRoZXNlIG5vdGVzIHJlc2lkZXMgd2l0aCB0aGUgYXV0aG9ycyBuYW1lZCBhYm92ZSwgd2l0aCB0aGUgRGVwYXJ0bWVudCBvZiBNYXRoZW1hdGljYWwgYW5kIFBoeXNpY2FsIFNjaWVuY2VzIGFuZCB3aXRoIExhIFRyb2JlIFVuaXZlcnNpdHkuIENvcHlyaWdodCBpbiB0aGlzIHdvcmsgaXMgdmVzdGVkIGluIExhIFRyb2JlIFVuaXZlcnNpdHkgaW5jbHVkaW5nIGFsbCBMYSBUcm9iZSBVbml2ZXJzaXR5IGJyYW5kaW5nIGFuZCBuYW1pbmcuIFVubGVzcyBvdGhlcndpc2Ugc3RhdGVkLCBtYXRlcmlhbCB3aXRoaW4gdGhpcyB3b3JrIGlzIGxpY2Vuc2VkIHVuZGVyIGEgQ3JlYXRpdmUgQ29tbW9ucyBBdHRyaWJ1dGlvbi1Ob24gQ29tbWVyY2lhbC1Ob24gRGVyaXZhdGl2ZXMgTGljZW5zZSANCjxhIGhyZWYgPSAiaHR0cHM6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LW5jLW5kLzQuMC9DQyIgdGFyZ2V0PSJfYmxhbmsiPiBCWS1OQy1ORC4gPC9hPg0KPC9mb250Pg==