Data Science Module

Topic 5B: Simulations in R


Welcome to the fifth Data Science computer lab.

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

In this computer lab we will cover how 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 (e.g. a selection of STM1001 students, from the entire STM1001 cohort).

Because it is typically unfeasible to collect data on the entire population, 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 use 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\), which follows the standard normal distribution - in other words, \(X \sim N(0, 1)\).

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 don’t need to specify these.

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

As expected, the 100 sample observations appear to fit the standard normal distribution probability density curve well.

Our main interest here is not the variability of the sample values however, but rather the sample mean.

If we check the sample mean of 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, 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 one sample, we will now simulate a number of random samples from \(X\), in order to obtain a more accurate estimate of the sample mean \(\bar{X}\).

2.4

To begin, suppose we sample 5 observations of \(X\), and then compute the sample mean of these 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) # 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

Since our underlying data is generated from a 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 10000 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 loop. Specifically, we will use what is known as 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, and store it 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 10000 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, and store it 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?

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?

3 CLT Simulation - Exponential Distribution

To demonstrate the magic of the Central Limit Theorem, let’s carry out some simulations involving data generated from distributions other than the normal distribution.

For example, let’s now consider the Exponential distribution. The Exponential distribution is known to be highly skewed (i.e. asymmetric). 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 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.1

Recall that the Exponential distribution is defined by one parameter, known as the rate parameter (in contrast for example to the Normal distribution, which is defined by two parameters, namely the mean and the variance).

Suppose now that our random variable \(X\) follows an exponential distribution with rate parameter \(\lambda = 10\). In other words, \(X \sim 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 is highly skewed, and clearly different to data generated from the symmetric normal distribution. If we try (somewhat optimistically) to overlay a normal distribution probability density curve (similar to in 2.2), with appropriate mean and variance values, (shown in blue), our result is unhelpful.

3.3

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. If we check the sample mean of x, we find that this is equal to 0.1030676. In theory, we know that the population mean \(\mu = 1/\lambda = 0.1\), so this sample mean is quite a good estimate.

3.4

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

Using the code in 2.6 as a guide, simulate 10000 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?

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?

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, \(X \sim 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, as we will soon see, 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!

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 the appropriate normal distribution probability density curve:

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

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?

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:

# Note that you will have to change this code to the relevant package
install.packages("palmerpenguins")
library(palmerpenguins)

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, simulate taking 100 samples of 5 random round cut diamond sale prices, and plot a histogram of the resultant sample means. What do you observe?

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.

LS0tDQp0aXRsZTogIlNUTTEwMDE6IENvbXB1dGVyIExhYiA1QiINCm91dHB1dDoNCiAgYm9va2Rvd246Omh0bWxfZG9jdW1lbnQyOiANCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgdGhlbWU6IHJlYWRhYmxlDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQpiaWJsaW9ncmFwaHk6IFNUTTEwMDFfRFNfQ0xfcmVmZXJlbmNlcy5iaWIgDQpsaW5rLWNpdGF0aW9uczogeWVzDQotLS0NCg0KPHN0eWxlPg0KI1RPQyB7DQogIGJhY2tncm91bmQ6IHVybCgiaHR0cHM6Ly93d3cubGF0cm9iZS5lZHUuYXUvX21lZGlhL2xhLXRyb2JlLWFwaS92NS9pbWcvbG9nby5zdmciKTsNCiAgYmFja2dyb3VuZC1zaXplOiBjb250YWluOw0KICBwYWRkaW5nLXRvcDogODBweCAhaW1wb3J0YW50Ow0KICBiYWNrZ3JvdW5kLXJlcGVhdDogbm8tcmVwZWF0Ow0KfQ0KPC9zdHlsZT4NCg0KIyMjIERhdGEgU2NpZW5jZSBNb2R1bGUgey19DQoNCiMjIyBUb3BpYyA1QjogU2ltdWxhdGlvbnMgaW4gUiB7LX0NCg0KPGJyPg0KDQpXZWxjb21lIHRvIHRoZSBmaWZ0aCBEYXRhIFNjaWVuY2UgY29tcHV0ZXIgbGFiLg0KDQpJbiBbVG9waWMgNF0oaHR0cHM6Ly9ib29rZG93bi5vcmcvY29udGVudC84OGVmOWI3Yy01ODMzLTRhNzAtODRmMi05MzQ3MDk1N2QxZjkvKSwgd2UgaW50cm9kdWNlZCBzYW1wbGluZyBkaXN0cmlidXRpb25zIGFuZCB0aGUgY29uY2VwdCBvZiB0aGUgKkNlbnRyYWwgTGltaXQgVGhlb3JlbSouIA0KDQpJbiB0aGlzIGNvbXB1dGVyIGxhYiB3ZSB3aWxsIGNvdmVyIGhvdyB0byBjb25kdWN0IHRoZSBzaW11bGF0aW9ucyBkaXNjdXNzZWQgaW4gW0NoYXB0ZXIgMyBvZiBUb3BpYyA0XShodHRwczovL2Jvb2tkb3duLm9yZy9jb250ZW50Lzg4ZWY5YjdjLTU4MzMtNGE3MC04NGYyLTkzNDcwOTU3ZDFmOS8zLXRoZS1jZW50cmFsLWxpbWl0LXRoZW9yZW0uaHRtbCkuIA0KKipJdCBtaWdodCBiZSBoZWxwZnVsIHRvIGtlZXAgdGhpcyBjb250ZW50IG9wZW4gaW4gYSBzZXBhcmF0ZSB0YWIgd2hpbGUgeW91IHdvcmsgdGhyb3VnaCB0aGUgbGFiIG1hdGVyaWFsLCBpbiBjYXNlIHlvdSB3b3VsZCBsaWtlIHRvIHF1aWNrbHkgZG91YmxlLWNoZWNrIHlvdXIgdW5kZXJzdGFuZGluZyBvZiBhbnkgY29uY2VwdHMuKioNCg0KQnkgdGhlIGVuZCBvZiB0aGlzIGxhYiwgeW91IHNob3VsZCBiZSBhYmxlIHRvIGNvbmR1Y3Qgc2ltcGxlIHNpbXVsYXRpb25zIGluIFIuIExldCdzIGdldCBzdGFydGVkIQ0KDQojIFNhbXBsaW5nIERpc3RyaWJ1dGlvbnMNCg0KIyMgU2FtcGxpbmcNCg0KUmVjYWxsIHRoYXQgYSAqKnNhbXBsZSoqIGlzIGEgcmFuZG9tIHNlbGVjdGlvbiBvZiB1bml0cyBmcm9tIGEgY2hvc2VuIHBvcHVsYXRpb24gKGUuZy4gYSBzZWxlY3Rpb24gb2YgU1RNMTAwMSBzdHVkZW50cywgZnJvbSB0aGUgZW50aXJlIFNUTTEwMDEgY29ob3J0KS4NCg0KQmVjYXVzZSBpdCBpcyB0eXBpY2FsbHkgdW5mZWFzaWJsZSB0byBjb2xsZWN0IGRhdGEgb24gdGhlIGVudGlyZSBwb3B1bGF0aW9uLCB3ZSBpbnN0ZWFkIGNvbmR1Y3QgYW5hbHlzZXMgdXNpbmcgYSBzYW1wbGUuIFdlIGhvcGUgdGhhdCB0aGUgaW5mZXJlbmNlcyB3ZSBtYWtlIHVzaW5nIHRoZSBzYW1wbGUgZGF0YSBjYW4gYmUgZXh0cmFwb2xhdGVkIHRvIHByb3ZpZGUgaW5mb3JtYXRpb24gYWJvdXQgdGhlIHBvcHVsYXRpb24sIGFuZCB3ZSBjYW4gdXNlIHN0YXRpc3RpY2FsIHRlY2huaXF1ZXMgdG8gYXNjZXJ0YWluIHRoZSBhY2N1cmFjeSBvZiB0aGVzZSBpbmZlcmVuY2VzLiANCg0KT25lIHN1Y2ggc3RhdGlzdGljYWwgdGVjaG5pcXVlIHdlIGNhbiB1c2UgaXMgdGhlIENlbnRyYWwgTGltaXQgVGhlb3JlbS4NCg0KIyMgVGhlIENlbnRyYWwgTGltaXQgVGhlb3JlbSB7I0NMVH0NCg0KUmVjYWxsIHRoZSBkZWZpbml0aW9uIG9mIHRoZSBDZW50cmFsIExpbWl0IFRoZW9yZW0gKENMVCk6DQoNCjxjZW50ZXI+DQpMZXQgJFhfMSwgXGxkb3RzLCBYX24kIGJlIGEgcmFuZG9tIHNhbXBsZSBmcm9tIGEgZGlzdHJpYnV0aW9uIHdpdGggZmluaXRlIG1lYW4gJFxtdSQgYW5kIGZpbml0ZSB2YXJpYW5jZSAkXHNpZ21hXjIkLiANCg0KRm9yICRcb3ZlcmxpbmV7WH0kIGRlbm90aW5nIHRoZSBzYW1wbGUgbWVhbiwgaWYgJG4kIGlzIHN1ZmZpY2llbnRseSBsYXJnZSB0aGVuDQokJFxvdmVybGluZXtYfVxzdGFja3JlbHtcdGlueSBcdGV4dHthcHByb3gufX1cc2ltIE5cbGVmdChcbXUsXGZyYWN7XHNpZ21hXjJ9e259XHJpZ2h0KSAsICQkDQp3aGVyZSAkXHN0YWNrcmVse1x0aW55IFx0ZXh0e2FwcHJveC59fVxzaW0kIGRlbm90ZXMgJ2FwcHJveGltYXRlbHkgZGlzdHJpYnV0ZWQgYXMnLg0KPC9jZW50ZXI+DQo8YnI+DQoNCkJ5IHRoZSBDTFQsIGl0IGZvbGxvd3MgdGhhdCBhcyB3ZSBpbmNyZWFzZSBvdXIgc2FtcGxlIHNpemUsIHRoZSBzYW1wbGUgbWVhbiAkXG92ZXJsaW5le1h9JCB3aWxsIGdldCBpbmNyZWFzaW5nbHkgY2xvc2VyIChpLmUuIGNvbnZlcmdlKSB0byB0aGUgcG9wdWxhdGlvbiBtZWFuICRcbXUkLiBBcyAkbiQgaW5jcmVhc2VzLCB0aGUgdmFyaWFuY2Ugb2YgdGhlIHNhbXBsZSBtZWFuICRcb3ZlcmxpbmV7WH0kIHdpbGwgYWxzbyBkZWNyZWFzZS4NCg0KSW4gb3RoZXIgd29yZHMsIHdoaWxlIHNhbXBsZXMgb2YgaW5kaXZpZHVhbHMgY2FuIGV4aGliaXQgc2lnbmlmaWNhbnQgdmFyaWF0aW9uLCBzYW1wbGVzIG9mIG1lYW5zIHRlbmQgdG8gaGF2ZSBsZXNzIHZhcmlhYmlsaXR5IChhcyBlYWNoIG1lYW4gaXMgY2FsY3VsYXRlZCBmcm9tIGEgc2FtcGxlIG9mIGluZGl2aWR1YWxzLCByZWR1Y2luZyB0aGUgaW1wYWN0IG9mIG91dGxpZXJzKS4NCg0KTGV0J3MgdmlzdWFsaXNlIHRoaXMgcHJvY2VzcyBpbiBSIHVzaW5nIHNvbWUgc2ltdWxhdGlvbnMuDQoNCiMgU2ltdWxhdGlvbnMgaW4gUg0KDQpDYXJyeWluZyBvdXQgc2ltdWxhdGlvbnMgaW4gUiBpcyBhY3R1YWxseSBxdWl0ZSBzdHJhaWdodGZvcndhcmQuIA0KDQpXZSB3aWxsIHdhbGsgdGhyb3VnaCB0aGUgc3RlcHMgaW52b2x2ZWQgb25lIGF0IGEgdGltZS4NCg0KIyMgeyNiYXNlfQ0KDQpTdXBwb3NlIHRoYXQgd2UgYXJlIGludGVyZXN0ZWQgaW4gdGhlIHJhbmRvbSB2YXJpYWJsZSAkWCQsIHdoaWNoIGZvbGxvd3MgdGhlIHN0YW5kYXJkIG5vcm1hbCBkaXN0cmlidXRpb24gLSBpbiBvdGhlciB3b3JkcywgJFggXHNpbSBOKDAsIDEpJC4NCg0KV2UgY2FuIGdlbmVyYXRlIGEgc2FtcGxlIG9mIDEwMCBvYnNlcnZhdGlvbnMgZnJvbSB0aGlzIGRpc3RyaWJ1dGlvbiB1c2luZyB0aGUgZm9sbG93aW5nIFIgY29kZToNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVH0NCnNldC5zZWVkKDEpDQpuIDwtIDEwMA0KDQp4IDwtIHJub3JtKG4pDQpgYGANCg0KUnVuIHRoaXMgY29kZSBub3cuDQoNCipOb3RlOiBUaGUgZGVmYXVsdCBtZWFuIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24gdmFsdWVzIHVzZWQgYnkgYHJub3JtYCBhcmUgMCBhbmQgMSByZXNwZWN0aXZlbHksIHNvIHdlIGRvbid0IG5lZWQgdG8gc3BlY2lmeSB0aGVzZS4qDQoNCiMjIHsjYmFzZWhpc3R9DQoNCldlIGNhbiBwbG90IG91ciBnZW5lcmF0ZWQgZGF0YSB1c2luZyB0aGUgYGhpc3RgIGZ1bmN0aW9uLCBhcyBzaG93biBiZWxvdy4NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVH0NCmhpc3QoeCwgZnJlcSA9IEZBTFNFLCBjb2wgPSAiY2hhcnRyZXVzZTMiLCB4bGltID0gYygtMywgMyksDQogICAgIG1haW4gPSBwYXN0ZSgiSGlzdG9ncmFtIG9mIHJhbmRvbSBzYW1wbGUgXG4gZnJvbSBzdGFuZGFyZCBOb3JtYWwgZGlzdHJpYnV0aW9uLCBuID0gIiwgbikpIA0KIyBPdmVybGF5IHN0YW5kYXJkIG5vcm1hbCBjdXJ2ZQ0KY3VydmUoZG5vcm0oeCksIGFkZCA9IFRSVUUsIGNvbCA9ICJibHVlIiwgbHdkID0gMikNCiMgQWRkIGxpbmUgZGVub3Rpbmcgc2FtcGxlIG1lYW4NCmFibGluZSh2ID0gcm91bmQobWVhbih4KSwgMyksIGNvbCA9ICJyZWQiLCBsd2QgPSAyLCBsdHkgPSAyKQ0KYGBgDQoNCipOb3RlIHRoYXQgd2UgaGF2ZSBhbHNvIHVzZWQgdGhlIGBjdXJ2ZWAgYW5kIGBkbm9ybWAgZnVuY3Rpb25zIGhlcmUgdG8gb3ZlcmxheSB0aGUgc3RhbmRhcmQgbm9ybWFsIGRpc3RyaWJ1dGlvbiBwcm9iYWJpbGl0eSBkZW5zaXR5IGN1cnZlLioNCg0KIyMNCg0KQXMgZXhwZWN0ZWQsIHRoZSAxMDAgc2FtcGxlIG9ic2VydmF0aW9ucyBhcHBlYXIgdG8gZml0IHRoZSBzdGFuZGFyZCBub3JtYWwgZGlzdHJpYnV0aW9uIHByb2JhYmlsaXR5IGRlbnNpdHkgY3VydmUgd2VsbC4gDQoNCk91ciBtYWluIGludGVyZXN0IGhlcmUgaXMgbm90IHRoZSB2YXJpYWJpbGl0eSBvZiB0aGUgc2FtcGxlIHZhbHVlcyBob3dldmVyLCBidXQgcmF0aGVyIHRoZSAqc2FtcGxlIG1lYW4qLiANCg0KSWYgd2UgY2hlY2sgdGhlIHNhbXBsZSBtZWFuIG9mIGB4YCwgd2UgZmluZCB0aGF0IHRoaXMgaXMgZXF1YWwgdG8gYXBwcm94aW1hdGVseSBgciByb3VuZChtZWFuKHgpLCAzKWAgKHNob3duIGJ5IHRoZSByZWQgZGFzaGVkIGxpbmUgaW4gdGhlIHBsb3QgYWJvdmUpLiBTaW5jZSB0aGlzIGlzIHRoZSBzYW1wbGUgbWVhbiBmb3IganVzdCBvbmUgc2FtcGxlLCB3ZSBjYW4ndCBiZSB0b28gY29uZmlkZW50IGluIHVzaW5nIHRoaXMgZXN0aW1hdGUgYXMgYW4gYWNjdXJhdGUgZXN0aW1hdGUgb2YgdGhlIHBvcHVsYXRpb24gbWVhbiAod2hpY2ggd2Uga25vdyB3YXMgc3BlY2lmaWVkIHRvIGJlIGAwYCkuDQoNClJhdGhlciB0aGFuIHJlbHlpbmcgb24ganVzdCBvbmUgc2FtcGxlLCB3ZSB3aWxsIG5vdyBzaW11bGF0ZSBhIG51bWJlciBvZiByYW5kb20gc2FtcGxlcyBmcm9tICRYJCwgaW4gb3JkZXIgdG8gb2J0YWluIGEgbW9yZSBhY2N1cmF0ZSBlc3RpbWF0ZSBvZiB0aGUgc2FtcGxlIG1lYW4gJFxiYXJ7WH0kLiANCg0KIyMgeyNzdGFydH0NCg0KVG8gYmVnaW4sIHN1cHBvc2Ugd2Ugc2FtcGxlIDUgb2JzZXJ2YXRpb25zIG9mICRYJCwgYW5kIHRoZW4gY29tcHV0ZSB0aGUgc2FtcGxlIG1lYW4gb2YgdGhlc2Ugb2JzZXJ2YXRpb25zLg0KDQpVc2luZyB0aGUgY29kZSBpbiBcQHJlZihiYXNlKSwgaXQgZm9sbG93cyB0aGF0IHRoaXMgcHJvY2VzcyBpcyBxdWl0ZSBzdHJhaWdodGZvcndhcmQ6DQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRiwgZWNobyA9IFR9DQpzZXQuc2VlZCgxKQ0KbiA8LSA1ICMgU3BlY2lmeSBzYW1wbGUgc2l6ZQ0KeCA8LSBybm9ybShuKSAjIFJhbmRvbWx5IGdlbmVyYXRlIG5zIHNhbXBsZXMgZnJvbSB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbg0Kbm9ybV9tZWFuIDwtIG1lYW4oeCkgIyBDb21wdXRlIHRoZSBtZWFuIG9mIHRoZSBzYW1wbGVzLCBhbmQgc3RvcmUgaXQgaW4gYSBuZXcgb2JqZWN0DQpgYGANCg0KIyMgeyNzaW1zdGFydH0NCg0KU2luY2Ugb3VyIHVuZGVybHlpbmcgZGF0YSBpcyBnZW5lcmF0ZWQgZnJvbSBhIG5vcm1hbCBkaXN0cmlidXRpb24sIGl0IGZvbGxvd3MgdGhhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBzYW1wbGUgbWVhbiB3aWxsIGFsc28gYmUgbm9ybWFsICh3ZSBjYW4gdGhpbmsgb2YgdGhpcyByZXN1bHQgYXMgYSBwcmVjdXJzb3IgdG8gdGhlIENlbnRyYWwgTGltaXQgVGhlb3JlbSkuIA0KDQpUbyBhY2N1cmF0ZWx5IHZpc3VhbGlzZSB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBzYW1wbGUgbWVhbiwgd2Ugd2lsbCBuZWVkIHRvIHJlcGVhdCB0aGUgcHJvY2VzcyBvdXRsaW5lZCBpbiBcQHJlZihzdGFydCkgKiptYW55IHRpbWVzKiouIFRoaXMgaXMgd2hlcmUgb3VyIHNpbXVsYXRpb25zIGNhbiByZWFsbHkgc2hpbmUuDQoNClN1cHBvc2UsIHJhdGhlciB0aGFuIGNvbmR1Y3RpbmcgdGhlIHByb2Nlc3Mgb3V0bGluZWQgaW4gXEByZWYoc3RhcnQpIG9uY2UsIHdlIGluc3RlYWQgY29uZHVjdCBpdCAxMDAwMCB0aW1lcy4gDQpJdCB3b3VsZCB0YWtlIGEgd2hpbGUgdG8gd3JpdGUgdGhpcyBjb2RlIG91dCBsaW5lIGJ5IGxpbmUgaW4gUiAob3ZlciA5MDAwIGxpbmVzIHBvdGVudGlhbGx5ISkuDQoNCkluc3RlYWQsIHRvIHNhdmUgdGltZSwgd2Ugd2lsbCB1c2UgYSBgbG9vcGAuDQpTcGVjaWZpY2FsbHksIHdlIHdpbGwgdXNlIHdoYXQgaXMga25vd24gYXMgYSBgZm9yIGxvb3BgLiBBIGBmb3IgbG9vcGAgaXMgYSBmdW5jdGlvbiB0aGF0IHdpbGwgcmVwZWF0IGEgc3BlY2lmaWVkIHNldCBvZiBvcGVyYXRpb25zIGEgc3BlY2lmaWVkIG51bWJlciBvZiB0aW1lcy4NCg0KVGhlIGBDb2RlYCBjaHVuayBiZWxvdyBwcm92aWRlcyBhIHNpbXBsZSBleGFtcGxlIG9mIHRoZSBSIHN5bnRheCBmb3IgYSBgZm9yIGxvb3BgLg0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IEYsIGVjaG8gPSBUfQ0KZm9yKGkgaW4gMToxMCl7DQogIHggPC0gcm5vcm0oaSkNCiAgbWVhbih4KQ0KfQ0KYGBgDQoNCkhvdyBkbyB3ZSBpbnRlcnByZXQgdGhpcyBjb2RlPw0KV2VsbCx3ZSBoYXZlIHNwZWNpZmllZCB0aGF0IGZvciBzb21lIGlucHV0IGBpYCwgd2hlcmUgYGlgIGNhbiB0YWtlIHRoZSBpbnRlZ2VyIHZhbHVlcyAxIHVwIHRvIDEwLCB0aGUgYGZvciBsb29wYCB3aWxsIHNpbXVsYXRlIGBpYCByYW5kb20gdmFsdWVzIGZyb20gdGhlIHN0YW5kYXJkIE5vcm1hbCBkaXN0cmlidXRpb24sIHN0b3JlIHRoZW0gaW4gdGhlIG9iamVjdCBgeGAsIGFuZCB0aGVuIGNvbXB1dGUgdGhlIG1lYW4gb2YgYHhgLiANCg0KVGh1cywgb3VyIGBmb3IgbG9vcGAgcnVucyBsaWtlIHRoaXM6DQoNCiogVGhlIGBmb3IgbG9vcGAgc3RhcnRzIHdpdGggdGhlIGZpcnN0IHNwZWNpZmllZCB2YWx1ZSwgMSwgYW5kIHNpbXVsYXRlcyAxIHJhbmRvbSB2YWx1ZSBmcm9tIHRoZSBzdGFuZGFyZCBOb3JtYWwgZGlzdHJpYnV0aW9uLiANCiogVGhlIG1lYW4gb2YgYHhgIGlzIG5vdyBjb21wdXRlZC4gVGhpcyBpcyB0aGUgbGFzdCBvcGVyYXRpb24gaW4gdGhlIGBmb3IgbG9vcGAuDQoqIFNpbmNlIHRoZSBzcGVjaWZpZWQgb3BlcmF0aW9ucyBpbnNpZGUgdGhlIGxvb3AgaGF2ZSBiZWVuIGZpbmlzaGVkIGZvciB0aGF0IHZhbHVlIG9mIGBpYCwgdGhlIGxvb3Agc3RhcnRzIGFnYWluLCB3aXRoIGBpPTJgIG5vdy4gDQoqIFRoaXMgcHJvY2VzcyBjb250aW51ZXMsIHVudGlsIHRoZSBmaW5hbCBzcGVjaWZpZWQgdmFsdWUgb2YgYGlgLCBuYW1lbHkgYGk9MTBgLCBoYXMgYmVlbiB1c2VkLiANCiogQXQgdGhpcyBwb2ludCwgdGhlIGBmb3IgbG9vcGAgaXMgY29tcGxldGUuDQoNCipOb3RlOiBXZSBkbyBub3QgaGF2ZSB0byB1c2UgdGhlIGxldHRlciBgaWAgaGVyZSwgaXQgaXMgc2ltcGx5IGNvbnZlbnRpb24uIFlvdSBjYW4gdXNlIGEgZGlmZmVyZW50IGxldHRlciwgYnV0IHJlbWVtYmVyLCBtYWtlIHN1cmUgeW91IGhhdmUgbm90IHVzZWQgeW91ciBjaG9zZW4gbGV0dGVyIGFzIGEgbmFtZSBmb3IgYSBwcmV2aW91cyBvYmplY3QgaW4gd2hpY2ggeW91IGhhdmUgc3RvcmVkIGRhdGEuKg0KDQoNCiMjICB7I3NpbX0NCg0KVGhlIGBDb2RlYCBjaHVuayBiZWxvdyBleHBhbmRzIHVwb24gdGhlIGBmb3IgbG9vcGAgZXhhbXBsZSBkaXNjdXNzZWQgYWJvdmUgaW4gXEByZWYoc2ltc3RhcnQpLiBUYWtlIGEgbG9vayBhdCB0aGlzIGNvZGUsIHJlYWQgdGhlIGNvbW1lbnRzIGNhcmVmdWxseSwgYW5kIG1ha2Ugc3VyZSB5b3UgdW5kZXJzdGFuZCB3aGF0IHRoZSBjb2RlIGRvZXMgKG5vdGUgc29tZSB2YWx1ZXMgYXJlIG1pc3NpbmcsIGFzIGRlbm90ZWQgYnkgdGhlIGAuLi5gKS4NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCiNTcGVjaWZ5IHNhbXBsZSBzaXplDQpucyA8LSAuLi4NCiAgDQojIFNwZWNpZnkgbnVtYmVyIG9mIHRpbWVzIHRvIGNvbmR1Y3QgcHJvY2VzcyAgDQp0cmlhbHMgPC0gLi4uDQoNCiMgY3JlYXRlIG9iamVjdCBpbiB3aGljaCB0byBzdG9yZSBzYW1wbGUgbWVhbnMgb25jZSB0aGV5IGFyZSBnZW5lcmF0ZWQNCm5vcm0ubWVhbnMgPC0gcmVwKDAsIHRyaWFscykgIyBOb3RlIGxlbmd0aCBpcyBlcXVhbCB0byB0aGUgbnVtYmVyIG9mIHRyaWFscw0KDQojIFJ1biBmb3IgbG9vcCAgDQpmb3IoaSBpbiAxOnRyaWFscyl7DQogICAgIyBSYW5kb21seSBnZW5lcmF0ZSBucyBzYW1wbGVzIGZyb20gdGhlIG5vcm1hbCBkaXN0cmlidXRpb24NCiAgICB4IDwtIHJub3JtKG5zKSANCiAgICAjIENvbXB1dGUgbWVhbiBvZiBzYW1wbGVzLCBhbmQgc3RvcmUgaXQgaW4gdGhlIG5vcm0ubWVhbnMgb2JqZWN0LCBpbiBpdGggcG9zaXRpb24gDQogICAgbm9ybS5tZWFuc1tpXSA8LSBtZWFuKHgpIA0KICAgIH0NCg0KYGBgDQoNCk9uY2UgeW91IGZlZWwgY29uZmlkZW50IGluIHlvdXIgdW5kZXJzdGFuZGluZyBvZiB0aGlzIGNvZGUsIHJlcGxhY2UgdGhlIGAuLi5gIG1pc3NpbmcgZGV0YWlscyBmb3IgYG5zYCBhbmQgYHRyaWFsc2AsIHVzaW5nIHRoZSBmb2xsb3dpbmcgZGV0YWlsczoNCg0KKiBZb3Ugd2FudCB0byB0YWtlIDEwMDAwIHNhbXBsZXMgb2YgcmFuZG9tbHkgZ2VuZXJhdGVkIHZhbHVlcyBmcm9tIHRoZSBzdGFuZGFyZCBOb3JtYWwgZGlzdHJpYnV0aW9uLg0KKiBFYWNoIHNhbXBsZSBzaG91bGQgaGF2ZSBhIHNhbXBsZSBzaXplIG9mIDUuDQoNCk9uY2UgeW91IGhhdmUgZmlsbGVkIGluIHRoZSBkZXRhaWxzLCBydW4geW91ciBjb2RlLg0KDQoqSGludDogSWYgeW91IGhhdmUgZ2l2ZW4gdGhpcyBhIGRlY2VudCBzaG90LCBidXQgYXJlIHN0dWNrLCB5b3UgY2FuIGNoZWNrIHRoZSBgQ29kZWAgY2h1bmsgYmVsb3c6Kg0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIiwgZXZhbCA9IFQsIGVjaG8gPSBUfQ0KI1NwZWNpZnkgc2FtcGxlIHNpemUNCm5zIDwtIDUNCiAgDQojIFNwZWNpZnkgbnVtYmVyIG9mIHRpbWVzIHRvIGNvbmR1Y3QgcHJvY2VzcyAgDQp0cmlhbHMgPC0gMTAwMDANCg0KIyBjcmVhdGUgb2JqZWN0IGluIHdoaWNoIHRvIHN0b3JlIHNhbXBsZSBtZWFucyBvbmNlIHRoZXkgYXJlIGdlbmVyYXRlZA0Kbm9ybS5tZWFucyA8LSByZXAoMCwgdHJpYWxzKSAjIE5vdGUgbGVuZ3RoIGlzIGVxdWFsIHRvIHRoZSBudW1iZXIgb2YgdHJpYWxzDQoNCiMgUnVuIGZvciBsb29wICANCmZvcihpIGluIDE6dHJpYWxzKXsNCiAgICAjIFJhbmRvbWx5IGdlbmVyYXRlIG5zIHNhbXBsZXMgZnJvbSB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbg0KICAgIHggPC0gcm5vcm0obnMpIA0KICAgICMgQ29tcHV0ZSBtZWFuIG9mIHNhbXBsZXMsIGFuZCBzdG9yZSBpdCBpbiB0aGUgbm9ybS5tZWFucyBvYmplY3QsIGluIGl0aCBwb3NpdGlvbiANCiAgICBub3JtLm1lYW5zW2ldIDwtIG1lYW4oeCkgDQogICAgfQ0KYGBgDQoNCiMjIHsjdml6fQ0KDQpUbyB2aXN1YWxpc2Ugb3VyIHJlc3VsdHMsIHdlIGNhbiB1c2UgdGhlIGZvbGxvd2luZyBjb2RlOg0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IEYsIGVjaG8gPSBUfQ0KaGlzdChub3JtLm1lYW5zLCBmcmVxID0gRkFMU0UsIGJyZWFrcyA9IDIwLCBjb2wgPSAicmVkIiwgDQogICAgIHhsaW0gPSBjKC0zLCAzKSwNCiAgICAgeGxhYiA9IGV4cHJlc3Npb24oYmFyKHgpKSwNCiAgICAgbWFpbiA9IHBhc3RlKCJIaXN0b2dyYW0gb2YgbWVhbnMsIG4gPSAiLCBucykpIA0KYGBgDQoNCldlIGNhbiBhbHNvIG92ZXJsYXkgYSBub3JtYWwgZGVuc2l0eSBjdXJ2ZSwgdGhhdCwgc2luY2Ugb3VyIHVuZGVybHlpbmcgZGF0YSBpcyBub3JtYWwsDQp3aWxsIHJlZmxlY3QgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgc2FtcGxlIG1lYW4uIA0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IEYsIGVjaG8gPSBUfSAgDQpjdXJ2ZShkbm9ybSh4LCANCiAgICAgIG1lYW4gPSAwLCBzZCA9IDEvc3FydChucykpLCANCiAgICAgIGFkZCA9IFRSVUUsIGNvbCA9ICJibHVlIiwgbHdkID0gMikgDQpgYGANCg0KUnVuIHRoZXNlIGNvZGUgY2h1bmtzIG5vdywgYW5kIGNoZWNrIHlvdXIgcmVzdWx0cy4gQXJlIG91ciBzaW11bGF0ZWQgc2FtcGxlIG1lYW5zIGNsb3NlIHRvIHRoZSBwb3B1bGF0aW9uIG1lYW4gb2YgMD8NCg0KIyMNCg0KUmVwZWF0IHN0ZXBzIFxAcmVmKHNpbSkgYW5kIFxAcmVmKHZpeiksIHVzaW5nIGEgc2FtcGxlIG9mIDMwIGluc3RlYWQgb2YgNS4gV2hhdCBkbyB5b3Ugbm90aWNlIGFib3V0IHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHNpbXVsYXRlZCBzYW1wbGUgbWVhbnM/DQoNCiMjDQoNCkZpbmFsbHksIHJlcGVhdCBzdGVwcyBcQHJlZihzaW0pIGFuZCBcQHJlZih2aXopLCB1c2luZyBhIHNhbXBsZSBvZiA2MC4gV2hhdCBkbyB5b3Ugbm90aWNlIGFib3V0IHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHNpbXVsYXRlZCBzYW1wbGUgbWVhbnMgbm93Pw0KDQojIENMVCBTaW11bGF0aW9uIC0gRXhwb25lbnRpYWwgRGlzdHJpYnV0aW9uDQoNClRvIGRlbW9uc3RyYXRlIHRoZSBtYWdpYyBvZiB0aGUgQ2VudHJhbCBMaW1pdCBUaGVvcmVtLCBsZXQncyBjYXJyeSBvdXQgc29tZSBzaW11bGF0aW9ucyBpbnZvbHZpbmcgZGF0YSBnZW5lcmF0ZWQgZnJvbSBkaXN0cmlidXRpb25zIG90aGVyIHRoYW4gdGhlIG5vcm1hbCBkaXN0cmlidXRpb24uIA0KDQpGb3IgZXhhbXBsZSwgbGV0J3Mgbm93IGNvbnNpZGVyIHRoZSAqKkV4cG9uZW50aWFsIGRpc3RyaWJ1dGlvbioqLiANClRoZSBFeHBvbmVudGlhbCBkaXN0cmlidXRpb24gaXMga25vd24gdG8gYmUgaGlnaGx5IHNrZXdlZCAoaS5lLiBhc3ltbWV0cmljKS4gQ2xlYXJseSwgd2UgY2Fubm90IGZpdCBhIG5vcm1hbCBjdXJ2ZSB3ZWxsIHRvIGRhdGEgZ2VuZXJhdGVkIGZyb20gYW4gRXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uLiBIb3dldmVyLCBhcyB3ZSB3b3JrIHRocm91Z2ggdGhpcyBxdWVzdGlvbiwgd2Ugd2lsbCBmaW5kIHRoYXQgd2hlbiB3ZSBtb2RlbCB0aGUgZGlzdHJpYnV0aW9uIG9mIHNhbXBsZSBtZWFucyBvZiBkYXRhIGdlbmVyYXRlZCBmcm9tIGFuIEV4cG9uZW50aWFsIGRpc3RyaWJ1dGlvbiwgdGhpcyBkaXN0cmlidXRpb24gb2Ygc2FtcGxlIG1lYW5zICoqY2FuKiogYmUgZml0dGVkIHdlbGwgYnkgYSBub3JtYWwgY3VydmUsIGVzcGVjaWFsbHkgYXMgb3VyIHNhbXBsZSBzaXplIGluY3JlYXNlcy4gVGhpcyAoc29tZXdoYXQgdW5pbnR1aXRpdmUpIHJlc3VsdCBpcyBkdWUgdG8gdGhlIENlbnRyYWwgTGltaXQgVGhlb3JlbSENCg0KIyMNCg0KUmVjYWxsIHRoYXQgdGhlIEV4cG9uZW50aWFsIGRpc3RyaWJ1dGlvbiBpcyBkZWZpbmVkIGJ5IG9uZSBwYXJhbWV0ZXIsIGtub3duIGFzIHRoZSAqcmF0ZSBwYXJhbWV0ZXIqIChpbiBjb250cmFzdCBmb3IgZXhhbXBsZSB0byB0aGUgTm9ybWFsIGRpc3RyaWJ1dGlvbiwgd2hpY2ggaXMgZGVmaW5lZCBieSB0d28gcGFyYW1ldGVycywgbmFtZWx5IHRoZSBtZWFuIGFuZCB0aGUgdmFyaWFuY2UpLiANCg0KU3VwcG9zZSBub3cgdGhhdCBvdXIgcmFuZG9tIHZhcmlhYmxlICRYJCBmb2xsb3dzIGFuIGV4cG9uZW50aWFsIGRpc3RyaWJ1dGlvbiB3aXRoIHJhdGUgcGFyYW1ldGVyICRcbGFtYmRhID0gMTAkLiBJbiBvdGhlciB3b3JkcywgJFggXHNpbSBFeHAoMTApJC4NCg0KV2UgY2FuIGdlbmVyYXRlIGEgc2FtcGxlIG9mIDEwMCBvYnNlcnZhdGlvbnMgZnJvbSB0aGlzIGRpc3RyaWJ1dGlvbiB1c2luZyB0aGUgZm9sbG93aW5nIFIgY29kZToNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVH0NCnNldC5zZWVkKDEpDQpuIDwtIDEwMA0KcmF0ZSA9IDEwDQp4IDwtIHJleHAobiwgcmF0ZSA9IHJhdGUpDQpgYGANCg0KKk5vdGUgdGhhdCB3ZSB1c2UgYHJleHBgIHRvIHJhbmRvbWx5IGdlbmVyYXRlIHZhbHVlcyBmcm9tIHRoZSBleHBvbmVudGlhbCBkaXN0cmlidXRpb24sIGluc3RlYWQgb2YgdXNpbmcgYHJub3JtYCAod2hpY2ggaXMgZm9yIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uKS4qDQoNClJ1biB0aGlzIGNvZGUgbm93Lg0KDQojIw0KDQpPdXIgZ2VuZXJhdGVkIGRhdGEgaXMgaGlnaGx5IHNrZXdlZCwgYW5kIGNsZWFybHkgZGlmZmVyZW50IHRvIGRhdGEgZ2VuZXJhdGVkIGZyb20gdGhlIHN5bW1ldHJpYyBub3JtYWwgZGlzdHJpYnV0aW9uLiBJZiB3ZSB0cnkgKHNvbWV3aGF0IG9wdGltaXN0aWNhbGx5KSB0byBvdmVybGF5IGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiBwcm9iYWJpbGl0eSBkZW5zaXR5IGN1cnZlIChzaW1pbGFyIHRvIGluIFxAcmVmKGJhc2VoaXN0KSksICB3aXRoIGFwcHJvcHJpYXRlIG1lYW4gYW5kIHZhcmlhbmNlIHZhbHVlcywgKHNob3duIGluIGJsdWUpLCBvdXIgcmVzdWx0IGlzIHVuaGVscGZ1bC4NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gRiwgZmlnLmRpbSA9IGMoNiw2KX0NCmhpc3QoeCwgZnJlcSA9IEZBTFNFLCBjb2wgPSAiY2hhcnRyZXVzZTMiLCB4bGltID0gYygwLCAwLjUpLA0KICAgICBtYWluID0gcGFzdGUoIkhpc3RvZ3JhbSBvZiByYW5kb20gc2FtcGxlIFxuIGZyb20gRXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uLCBuID0gIiwgbikpDQpjdXJ2ZShkbm9ybSh4LCAxL3JhdGUsIDEvcmF0ZSksIGFkZCA9IFRSVUUsIGNvbCA9ICJibHVlIiwgbHdkID0gMikNCmBgYA0KDQojIw0KDQpJbnN0ZWFkIG9mIGNvbnNpZGVyaW5nIHRoZSBpbmRpdmlkdWFsIGRhdGEgcG9pbnRzIGdlbmVyYXRlZCBmcm9tIHRoZSBFeHBvbmVudGlhbCBkaXN0cmlidXRpb24sIGxldCdzIHNoaWZ0IG91ciBmb2N1cyB0byB0aGUgc2FtcGxlIG1lYW4gb2YgdGhlc2UgZGF0YSBwb2ludHMuDQpJZiB3ZSBjaGVjayB0aGUgc2FtcGxlIG1lYW4gb2YgYHhgLCB3ZSBmaW5kIHRoYXQgdGhpcyBpcyBlcXVhbCB0byBgciBtZWFuKHgpYC4gSW4gdGhlb3J5LCB3ZSBrbm93IHRoYXQgdGhlIHBvcHVsYXRpb24gbWVhbiAkXG11ID0gMS9cbGFtYmRhID0gMC4xJCwgc28gdGhpcyBzYW1wbGUgbWVhbiBpcyBxdWl0ZSBhIGdvb2QgZXN0aW1hdGUuDQoNCiMjIHsjZXhwc2ltfQ0KDQpMZXQgdXMgbm93IGNvbmR1Y3QgdGhlIHNpbXVsYXRpb24gcHJvY2VzcyB1c2VkIGluIFxAcmVmKHNpbSksIGZvciBvdXIgZXhwb25lbnRpYWxseSBkaXN0cmlidXRlZCBkYXRhLg0KDQpVc2luZyB0aGUgY29kZSBpbiBcQHJlZihzaW0pIGFzIGEgZ3VpZGUsIHNpbXVsYXRlIDEwMDAwIHNhbXBsZSBtZWFucyBvZiAkWCQsIHVzaW5nIHNhbXBsZXMgb2Ygc2l6ZSA1Lg0KDQpQbG90IHlvdXIgcmVzdWx0cywgdXNpbmcgdGhlIGNvZGUgaW4gXEByZWYodml6KSBhcyBhIGd1aWRlLg0KDQoqTm90ZTogWW91IHdpbGwgaGF2ZSB0byBjaGFuZ2UgdGhlIHgtYXhpcyByYW5nZSBmb3IgdGhlIGhpc3RvZ3JhbSAodmlhIHRoZSBgeGxpbWAgYXJndW1lbnQpLiBUcnkgdXNpbmcgYSByYW5nZSBvZiAwIHRvIDAuNC4qDQoNCipOb3RlIDI6IFVzZSB0aGUgY29kZSBpbiB0aGUgYENvZGVgIGNodW5rIGJlbG93IHRvIG92ZXJsYXkgdGhlIGFwcHJvcHJpYXRlIE5vcm1hbCBkaXN0cmlidXRpb24gcHJvYmFiaWxpdHkgZGVuc2l0eSBjdXJ2ZToqDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRiwgZWNobyA9IFR9DQpjdXJ2ZShkbm9ybSh4LCBtZWFuID0gMS9yYXRlLCBzZCA9IDEvcmF0ZS9zcXJ0KG5zKSksIGFkZCA9IFRSVUUsDQogICAgICAgIGNvbCA9ICJibHVlIiwgbHdkID0gMikNCmBgYA0KDQojIw0KDQpXaGF0IGRvIHlvdSBub3RpY2UgYWJvdXQgeW91ciByZXN1bHRhbnQgcGxvdD8NCg0KIyMNCg0KUmVwZWF0cyBcQHJlZihleHBzaW0pIGZvciAkWCBcc2ltIEV4cCgxMCkkLCB1c2luZyBhIHNhbXBsZSBvZiAzMCBpbnN0ZWFkIG9mIDUuIFdoYXQgZG8geW91IG5vdGljZSBhYm91dCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBzaW11bGF0ZWQgc2FtcGxlIG1lYW5zPw0KDQojIw0KDQpGaW5hbGx5LCByZXBlYXQgXEByZWYoZXhwc2ltKSBmb3IgJFggXHNpbSBFeHAoMTApJCwgdXNpbmcgYSBzYW1wbGUgb2YgNjAuIFdoYXQgZG8geW91IG5vdGljZSBhYm91dCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBzaW11bGF0ZWQgc2FtcGxlIG1lYW5zIG5vdz8NCg0KIyBDTFQgU2ltdWxhdGlvbiAtIEJlcm5vdWxsaSBEaXN0cmlidXRpb24NCg0KQXMgZGlzY3Vzc2VkIGluIFtTZWN0aW9uIDMuMyBvZiBUb3BpYyA0XShodHRwczovL2Jvb2tkb3duLm9yZy9jb250ZW50Lzg4ZWY5YjdjLTU4MzMtNGE3MC04NGYyLTkzNDcwOTU3ZDFmOS8zLTMtY2x0LXNpbXVsYXRlZC1leGFtcGxlLXdpdGgtYmVybm91bGxpLWRpc3RyaWJ1dGVkLXBvcHVsYXRpb24uaHRtbCksIHRoZSBDZW50cmFsIExpbWl0IFRoZW9yZW0gZXZlbiBhcHBsaWVzIHRvIGRpc2NyZXRlIHJhbmRvbSB2YXJpYWJsZXMuDQoNClN1cHBvc2UgdGhhdCBvdXIgcmFuZG9tIHZhcmlhYmxlICRYJCBub3cgZm9sbG93cyBhIEJlcm5vdWxsaSBkaXN0cmlidXRpb24gd2l0aCBzdWNjZXNzIHBhcmFtZXRlciAkcCA9IDAuMyQuIEluIG90aGVyIHdvcmRzLCAkWCBcc2ltIEJFUk4oMC4zKSQuDQoNCiMjDQoNCklmIHdlIGdlbmVyYXRlIGEgc2FtcGxlIG9mIDEwMCBvYnNlcnZhdGlvbnMgZnJvbSB0aGlzIGRpc3RyaWJ1dGlvbiAoc2VlIHRoZSBSIGNvZGUgYmVsb3cpIGFuZCB0aGVuIHZpc3VhbGlzZSBvdXIgZ2VuZXJhdGVkIGRhdGEsIHdlIHNlZSBhIHJvdWdobHkgNzAvMzAgc3BsaXQgb2Ygb2JzZXJ2YXRpb25zIGJldHdlZW4gJHg9MCQgYW5kICR4PTEkLiBDbGVhcmx5LCAoanVzdCBhcyBpbiB0aGUgRXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uIGNhc2UpLCB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbiBwcm9iYWJpbGl0eSBkZW5zaXR5IGN1cnZlLCB3aXRoIGFwcHJvcHJpYXRlIHBhcmFtZXRlciBzcGVjaWZpY2F0aW9ucywgKHNob3duIGluIGJsdWUpLCBpcyBhbiBleHRyZW1lbHkgcG9vciBmaXQgZm9yIHRoaXMgZGF0YS4NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVH0NCnNldC5zZWVkKDEpDQpuIDwtIDEwMA0KcCA9IDAuMw0KeCA8LSByYmlub20obiwgMSwgcCkNCmBgYA0KDQoqTm90ZSB0aGF0IHdlIHVzZSBgcmJpbm9tYCB0byByYW5kb21seSBnZW5lcmF0ZSB2YWx1ZXMgZnJvbSB0aGUgQmVybm91bGxpIGRpc3RyaWJ1dGlvbiwgaW5zdGVhZCBvZiB1c2luZyBgcm5vcm1gICh3aGljaCBpcyBmb3IgdGhlIG5vcm1hbCBkaXN0cmlidXRpb24pLioNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gRn0NCmhpc3QoeCwgZnJlcSA9IEZBTFNFLCBjb2wgPSAiY2hhcnRyZXVzZTMiLCB4bGltID0gYygwLCAxKSwNCiAgICAgbWFpbiA9IHBhc3RlKCJIaXN0b2dyYW0gb2YgcmFuZG9tIHNhbXBsZSBcbiBmcm9tIEJlcm5vdWxsaSBkaXN0cmlidXRpb24sIG4gPSAiLCBuKSkgDQpjdXJ2ZShkbm9ybSh4LCBwLCBzZCA9IHNxcnQocCooMSAtIHApKSksIGFkZCA9IFRSVUUsIGNvbCA9ICJibHVlIiwgbHdkID0gMikNCmBgYA0KDQojIw0KDQpIb3dldmVyLCBhcyB3ZSB3aWxsIHNvb24gc2VlLCBkZXNwaXRlIG91ciBkYXRhIGJlaW5nIGdlbmVyYXRlZCBmcm9tIGEgZGlzY3JldGUgZGlzdHJpYnV0aW9uLCB3ZSBjYW4gc3RpbGwgdXNlIHRoZSBDZW50cmFsIExpbWl0IFRoZW9yZW0gdG8gb2J0YWluIGFuIGFjY3VyYXRlIGVzdGltYXRlIG9mIHRoZSBwb3B1bGF0aW9uIG1lYW4hDQoNCkxldCB1cyBub3cgY29uZHVjdCB0aGUgc2ltdWxhdGlvbiBwcm9jZXNzIHVzZWQgaW4gXEByZWYoc2ltKSwgZm9yIG91ciBCZXJub3VsbGkgZGlzdHJpYnV0ZWQgZGF0YS4NCg0KVXNpbmcgdGhlIGNvZGUgaW4gXEByZWYoc2ltKSBhcyBhIGd1aWRlLCBzaW11bGF0ZSAxMDAwMCBzYW1wbGUgbWVhbnMgb2YgJFgkLCB1c2luZyBzYW1wbGVzIG9mIHNpemUgNS4NClRoZW4sIHBsb3QgeW91ciByZXN1bHRzLCB1c2luZyB0aGUgY29kZSBpbiBcQHJlZih2aXopIGFzIGEgZ3VpZGUuDQoNCipOb3RlOiBZb3Ugd2lsbCBoYXZlIHRvIGNoYW5nZSB0aGUgeC1heGlzIHJhbmdlIGZvciB0aGUgaGlzdG9ncmFtICh2aWEgdGhlIGB4bGltYCBhcmd1bWVudCkuKg0KDQoqTm90ZSAyOiBVc2UgdGhlIGNvZGUgaW4gdGhlIGBDb2RlYCBjaHVuayBiZWxvdyB0byBvdmVybGF5IHRoZSBhcHByb3ByaWF0ZSBub3JtYWwgZGlzdHJpYnV0aW9uIHByb2JhYmlsaXR5IGRlbnNpdHkgY3VydmU6Kg0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IEYsIGVjaG8gPSBUfQ0KIyBTZXQgbXUgYW5kIHNpZ21hIGZvciB0aGUgYXBwcm94aW1hdGluZyBub3JtYWwgZGlzdHJpYnV0aW9uDQptdSA8LSBwDQpzaWdtYSA8LSBzcXJ0KHAqKDEgLSBwKSkNCiAgDQojIE92ZXJsYXkgdGhlIG5vcm1hbCBkZW5zaXR5DQpjdXJ2ZShkbm9ybSh4LCBtdSwgc2lnbWEvc3FydChucykpLCBhZGQgPSBUUlVFLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpDQpgYGANCg0KIyMNCg0KV2hhdCBkbyB5b3Ugbm90aWNlIGFib3V0IHlvdXIgcmVzdWx0YW50IHBsb3Q/DQoNCiMjDQoNClJlcGVhdCBcQHJlZihleHBzaW0pIGZvciAkWCBcc2ltIEJFUk4oMC4zKSQsIHVzaW5nIGEgc2FtcGxlIG9mIDMwIGluc3RlYWQgb2YgNS4gV2hhdCBkbyB5b3Ugbm90aWNlIGFib3V0IHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHNpbXVsYXRlZCBzYW1wbGUgbWVhbnM/DQoNCiMjDQoNCkZpbmFsbHksIHJlcGVhdCBcQHJlZihleHBzaW0pIGZvciAkWCBcc2ltIEJFUk4oMC4zKSQsIHVzaW5nIGEgc2FtcGxlIG9mIDYwLiBXaGF0IGRvIHlvdSBub3RpY2UgYWJvdXQgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgc2ltdWxhdGVkIHNhbXBsZSBtZWFucyBub3c/DQoNCiMgRXh0ZW5zaW9uIC0gQXZlcmFnZSBEaWFtb25kIFByaWNlcw0KDQpMZXQncyBjb25zaWRlciBob3cgd2UgY2FuIGFwcGx5IHRoZSBDZW50cmFsIExpbWl0IFRoZW9yZW0gdG8gcmVhbCBkYXRhLg0KDQpGb3IgdGhpcyBxdWVzdGlvbiwgd2Ugd2lsbCBjb25zaWRlciBkYXRhIG9uIGFwcHJveGltYXRlbHkgNTQsMDAwIHJvdW5kIGN1dCBkaWFtb25kcy4gVGhpcyBkYXRhIGlzIHN0b3JlZCBpbiB0aGUgYGRpYW1vbmRzYCBkYXRhIHNldCBpbiB0aGUgYGdncGxvdDJgIFIgcGFja2FnZS4gV2Ugd2lsbCB0cmVhdCB0aGlzIGRhdGEgYXMgdGhlIHBvcHVsYXRpb24gZGF0YS4NCg0KSW5zdGFsbCBhbmQgbG9hZCB0aGUgYGdncGxvdDJgIFIgcGFja2FnZSBub3cuDQoNCipIaW50OiBJZiB5b3UgbmVlZCBhIHJlZnJlc2hlciBvbiBpbnN0YWxsaW5nIGFuZCBsb2FkaW5nIHBhY2thZ2VzIGluIFIsIGNoZWNrIHRoZSBgQ29kZWAgY2h1bmsgYmVsb3c6Kg0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIiwgZXZhbCA9IEYsIGVjaG8gPSBUfQ0KIyBOb3RlIHRoYXQgeW91IHdpbGwgaGF2ZSB0byBjaGFuZ2UgdGhpcyBjb2RlIHRvIHRoZSByZWxldmFudCBwYWNrYWdlDQppbnN0YWxsLnBhY2thZ2VzKCJwYWxtZXJwZW5ndWlucyIpDQpsaWJyYXJ5KHBhbG1lcnBlbmd1aW5zKQ0KYGBgDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUiLCBldmFsID0gVCwgaW5jbHVkZSA9IEZ9DQpsaWJyYXJ5KGdncGxvdDIpDQpgYGANCg0KIyMNCg0KSWYgd2UgcGxvdCB0aGUgcHJpY2Ugb2Ygcm91bmQgY3V0IGRpYW1vbmRzIHVzaW5nIGEgaGlzdG9ncmFtLCB3ZSBjYW4gc2VlIHRoYXQgdGhlIGRhdGEgaXMgY2xlYXJseSBub3Qgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuDQoNCipNYWtlIHN1cmUgdG8gcnVuIHRoaXMgY29kZSBiZWZvcmUgY29udGludWluZy4qDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFR9DQpoaXN0KGRpYW1vbmRzJHByaWNlLCBjb2wgPSAic2t5Ymx1ZSIsIHhsYWIgPSAiRGlhbW9uZCBQcmljZSAoJCkiLA0KICAgICBtYWluID0gIkhpc3RvZ3JhbSBvZiBEaWFtb25kIFByaWNlcyAoJCkiLCBmcmVxID0gRikNCmBgYA0KDQojIyB7I2RpYW1vbmRzaW19DQoNClN1cHBvc2UgdGhhdCB5b3UgYXJlIGludGVyZXN0ZWQgaW4gZXN0aW1hdGluZyB0aGUgcG9wdWxhdGlvbiBtZWFuIHByaWNlIGZvciByb3VuZCBjdXQgZGlhbW9uZHMsIGJ1dCBkbyBub3QgaGF2ZSBhY2Nlc3MgdG8gdGhlIGZ1bGwgYGRpYW1vbmRzYCBkYXRhIHNldC4NCg0KSW5zdGVhZCwgeW91IGNhbiBvbmx5IHNhbXBsZSBwcmljZXMgZm9yIDUgcm91bmQgY3V0IGRpYW1vbmRzIGF0IGEgdGltZSwgcmVwcmVzZW50ZWQgYnkgdGhlIGNvZGUgYmVsb3c6DQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFR9DQp4IDwtIHNhbXBsZShkaWFtb25kcyRwcmljZSwgNSkNCmBgYA0KDQpVc2luZyB0aGlzIGNvZGUgYW5kIHRoZSBjb2RlIGluIFxAcmVmKHNpbSkgYXMgYSBndWlkZSwgc2ltdWxhdGUgdGFraW5nIDEwMCBzYW1wbGVzIG9mIDUgcmFuZG9tIHJvdW5kIGN1dCBkaWFtb25kIHNhbGUgcHJpY2VzLCBhbmQgcGxvdCBhIGhpc3RvZ3JhbSBvZiB0aGUgcmVzdWx0YW50IHNhbXBsZSBtZWFucy4gV2hhdCBkbyB5b3Ugb2JzZXJ2ZT8NCg0KIyMgeyNkaWFtb25kc2ltbGFyZ2V9DQoNClJlcGVhdCBcQHJlZihkaWFtb25kc2ltKSwgYnV0IHRoaXMgdGltZSBzdXBwb3NlIHRoYXQgeW91IGFyZSBhYmxlIHRvIHRha2Ugc2FtcGxlcyBvZiAzMCBkaWFtb25kcyBhdCBhIHRpbWUsIGluc3RlYWQgb2YgNS4gV2hhdCBjaGFuZ2VzIGRvIHlvdSBvYnNlcnZlPyANCg0KPGJyPg0KDQojIyMjIEdyZWF0IGpvYiwgdGhhdCdzIGV2ZXJ5dGhpbmcgZm9yIHRvZGF5ISAjIyMjIHstfQ0KDQpIb3BlZnVsbHksIHRoaXMgY29tcHV0ZXIgbGFiIGhhcyBoZWxwZWQgY2VtZW50IHlvdXIgdW5kZXJzdGFuZGluZyBvZiB0aGUgQ2VudHJhbCBMaW1pdCBUaGVvcmVtLg0KDQo8YnI+DQoNCiMgUmVmZXJlbmNlcyB7LSAjUmVmfQ0KPGRpdiBpZD0icmVmcyI+PC9kaXY+DQoNCjxicj4NCg0KPGZvbnQgY29sb3IgPSAiZ3JleSI+DQpUaGVzZSBub3RlcyBoYXZlIGJlZW4gcHJlcGFyZWQgYnkgUnVwZXJ0IEt1dmVrZSBhbmQgQW1hbmRhIFNoYWtlci4gVGhlIGNvcHlyaWdodCBmb3IgdGhlIG1hdGVyaWFsIGluIHRoZXNlIG5vdGVzIHJlc2lkZXMgd2l0aCB0aGUgYXV0aG9ycyBuYW1lZCBhYm92ZSwgd2l0aCB0aGUgRGVwYXJ0bWVudCBvZiBNYXRoZW1hdGljYWwgYW5kIFBoeXNpY2FsIFNjaWVuY2VzIGFuZCB3aXRoIExhIFRyb2JlIFVuaXZlcnNpdHkuIENvcHlyaWdodCBpbiB0aGlzIHdvcmsgaXMgdmVzdGVkIGluIExhIFRyb2JlIFVuaXZlcnNpdHkgaW5jbHVkaW5nIGFsbCBMYSBUcm9iZSBVbml2ZXJzaXR5IGJyYW5kaW5nIGFuZCBuYW1pbmcuIFVubGVzcyBvdGhlcndpc2Ugc3RhdGVkLCBtYXRlcmlhbCB3aXRoaW4gdGhpcyB3b3JrIGlzIGxpY2Vuc2VkIHVuZGVyIGEgQ3JlYXRpdmUgQ29tbW9ucyBBdHRyaWJ1dGlvbi1Ob24gQ29tbWVyY2lhbC1Ob24gRGVyaXZhdGl2ZXMgTGljZW5zZSANCjxhIGhyZWYgPSAiaHR0cHM6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LW5jLW5kLzQuMC9DQyIgdGFyZ2V0PSJfYmxhbmsiPiBCWS1OQy1ORC4gPC9hPg0KPC9mb250Pg==