Gaussian Distribution

Gaussian distribution (named after Johann Carl Friedrich Gauss, 1777-1855, aka the normal distribution) is a special distribution that is the basis of Classical Parametric Statistics, why? Well because its really easy to work with (not a joke). It is defined by and it is defined by 2 parameters (\(\mu\) & \(\sigma\)) when the other two parameters (Skewness & Kurtosis) equal 0. I will come back to those below under Moments.

Gaussian distribution (aka the normal distribution) will serve as our population distribution. R will let us simulate a population with \(\mu = 100; \sigma = 15; N = 1e10^6\). Note: the seed allows all have to identical random results.

We will use the rnorm function which will allow us to pass the parameters we want to use to create our population distribution. As R is an object-oriented language, the results of this function will be an object (a bucket, which we filled with random, but normally distributed numbers). We can examine what is in this object, but first we must name out this object, and we call it anything we want as long as we don’t have spaces in our name (for example, The.Bucket.of.Many.Random.Numbers, however that is a silly name), so we will call it Normal.Sample.1.

set.seed(666)
n=1e6 #1 million people
Mu=100 # Set pop mean
S = 15 # set pop SD
Normal.Sample.1<-rnorm(n, mean = Mu, sd = S)

We can add a histogram (hist), where we could define a bin size (but R will do it automatically if we do not pass one) and add labels, as all graphs should be well labeled.

hist(Normal.Sample.1,
  main="Raw Score Histogram", 
  xlab="Population Distribution", ylab="Frequency")
abline(v=100, col="black")

As we can see in Figure above, we have what seems a nice normal distribution with 1 million random scores. Next, we need to examine the shape of the distribution by looking at the 4 moments.

Moments

There are 4 moments that can capture important aspects of the distribution (1. center, 2. spread, 3.symmetry, and 4. peakiness).

Moment 1: Central Tendency

Captures the center of the distribution and be defined three classical ways (Mean, Median, Mode). Mean/Median/Mode are used to identify a single score (point-estimation) that is representative for an entire distribution or set of data.

Mean (the average):

  • is the standard measure of central tendency in statistics.
  • is not necessarily equal to any score in the data set
  • is the most stable measure from sample to sample.
  • is very influenced by outliers (the mean will be strongly influenced by the presence of extreme scores).
  • is based on all scores from the sample but the mode and the median are not.

Median (the middle number):

  • is not sensitive to outliers!
  • is the best measure of central tendency if the distribution is skewed.

Mode (most common number):

  • is the least stable measure from sample to sample.

Mean

In R there many ways to do things. There are often packages which people have created to make your life easier but let’s start by replicating the formula in code. You will notice below that code that we can write it multiple steps, or we could have done it all at once. But first sum the object and divide it by the length of the object (note that length is the way we tabulate how long our object is. In this case out object is a vector: which is a simply a 1-dim string of numbers).

\[M = \frac{\Sigma X}{N}\]

Note: In R you can use “=” or “<-” to create the object. To help make the code more readable I use “=” to set argument or parameters that I pass into function and “<-” for objects. R coders in general use “<-”.

SumX <- sum(Normal.Sample.1) # Sum of X
N <- length(Normal.Sample.1) # length of vector 
M <- SumX/N # calc mean
M # Calls objects for us to see
## [1] 99.99483
# OR all at once
M <-sum(Normal.Sample.1)/length(Normal.Sample.1)

The mean was 99.99 and close to expected \(\mu\) of 100. However, we should use the built-in function, mean(Normal.Sample.1)

Median

Here I can call median and not create an object. This will cause R to show me the answer, but not save it.

median(Normal.Sample.1)
## [1] 99.98384

Mode

There is no built-in mode function in R that gives the mode. Note: The function mode yields information about the type of data (numeric, factor, etc.) of the object. So you have to go to google and either 1) find a package or 2) find someone who wrote a function.

  • Why is the mode a problem? Because it might be multi-modal or non-modal.

  • Online people suggest the modeest package. However, this package has not been updated to work in the latest version R (3.6.1 as of 8-2019).

  • When packages fail, we turn to stackoverflow. You can follow this link and see all the people talking about this problem and trying to write their own function of mode: https://stackoverflow.com/questions/2547402/is-there-a-built-in-function-for-finding-the-mode. I have copied over one of those empirical mode functions (based on converting the distribution into PDF and find the peak; written by Rasmus Baath). So remember R is open-source and when you start using random function you find online, you need to vet them carefully. This one will only work when there is only one peak.

Note: This is how you generate your own function in R. We will return to this concept next week.

estimate_mode <- function(x) {
  d <- density(x)
  d$x[which.max(d$y)]
}

estimate_mode(Normal.Sample.1)
## [1] 99.60596

Moment 2: Spread

Variance captures the spread of the distribution and can be defined in many classical ways (variance, standard deviation, median absolute difference, interquartile range, entropy). A good measure of variability will a) describe the spread of the distribution, b) describe how well an individual score represents the entire distribution. The most common in psychology is the variance and standard deviation. The causes of variability are a) Individual differences in participants (genetics, physiology, experience, moods, etc.), b) Researcher & Environment factors (factors in the research environment that influence how people behave). and c) Measurement effects (how subjects react to a particular method of testing).

Our estimates of moments can be biased (have error in them). Biased sample statistic is if the average value of the sample statistic, obtained over many different samples, constantly under or overestimates the population parameter. Unbiased sample statistic is if the average value of the sample statistic, obtained over many different samples, is equal to the population parameter. Basically, we always try to make sure that we are as close and unbiased as possible when trying to use sample to explain a population. To that we use (\(N-1\)) when we do are sample calculations. Note that for a sample to be an unbiased estimate of a population it must be randomly selected. Similarly, if scores from a sample are to serve as unbiased estimates of population scores they must be free to vary randomly.

In our future analyses, we will often use the unbiased variance statistics, but when we describe distribution we use the standard deviation (which is the square-root of the variance). In practice, one often assumes that the data are from an approximately normally distributed population. If that assumption is justified, then about 68% of the values are within 1 standard deviation of the mean, about 95% of the values are within two standard deviations and about 99.7% lie within 3 standard deviations. This is known as the “68-95-99.7 rule”, or “the empirical rule”. First to let’s calculate the variance than standard deviation.

Variance/SD (Biased and Unbiased)

Biased Variance with known \(\mu\) \[ \sigma^2 = \frac{\Sigma (X-\mu)^2}{N}\] This is a theoretical formula, but in practice we use the Unbiased Variance when \(\mu\) is unknown. \[ S^2 = \frac{\Sigma (X-M)^2}{N-1}\] R vectorizes the data so \(\Sigma(X-M)^2\) will follow the PEMDAS, but watch the (). More is better, less can screw you up [e.g., this will fail sum(Normal.Sample.1-M)^2/N-1 because it R reads is as \(S^2 = \Sigma (X-M)^{\frac{2}{N-1}}\).

Varience.mu<-sum((Normal.Sample.1-M)^2)/(N-1)

The \(S^2\) was 224.84 which again is close to \(\sigma^2\) of 225

The R function uses \(M\) and \(N-1\) not \(\mu\) and \(N\)

Varience.M<-var(Normal.Sample.1)

Unbiased var = 224.84

Unbiased SD

\[ S = \sqrt{S^2}\] use the R function and note its called sd. Never name your object just sd (it is case sensitive)

SD.calc <- sd(Normal.Sample.1)

Unbiased sd = 14.99

MAD

When you have lots of outliers in your data, you might want to instead calculate the Median Absolute Difference (MAD). Its is robust, meaning it is not as influenced by outliers.

\[MAD = b*median|[x_i - median(x)]|\] where, \(b = 1.4826\)

MAD_Normal<-mad(Normal.Sample.1)

MAD (corrected) = 14.98

You will notice this is very similar to sd value.

Note: You can force R to give you the uncorrected by changing the arguments

?mad
MAD_noCorrect<-mad(Normal.Sample.1, constant = 1)

MAD (uncorrected) = 10.1

Alternative MAD scores

Mean absolute deviation

\[MAD = b*median|[x_i - mean(x)]|\]

MAD_mean<-mad(Normal.Sample.1, center = mean(Normal.Sample.1))

MAD (based on mean center) = 14.98

You will notice it is the same as our median centered mad as the median = mean in this sample (as it is normal with a huge N)

Relationship between \(M\) and \(S\)

Because \(S\) is calculated using the first moment of \(M\), \(S\) will always increase as function magnitude of \(M\). What if you want to compare the \(S\) between two distributions with very different \(M\) values? You can normalize \(S\) by taking the coefficient of variation (CV)

\[CV = \frac{S}{M}\]

CV<- SD.calc/M

We see the \(CV\) was 0.15.

Moment 3: Skewness

There are many different formulas for skewness, but here is the basic concept \[Skewness = \frac{\Sigma(X-M)^3 /N}{S^{3}} \]

To calculate a can install a package to do the work for you: install.packages("moments")

# install.packages("moments") # remove hashtag and run it ONCE. Not each time you need it
library(moments)
SK.Calc<-skewness(Normal.Sample.1)

Skewness = 0

Moment 4: Kurtosis

There are many different formulas for kurtosis, but here is the basic concept

\[Kurtosis = \frac{\Sigma(X-M)^4 /N}{S^{4}} - 3 \]

The kurtosis function is in the moments package. Note: How did I know that? I first googled for “kurtosis in R”, found the package, installed it, read the documentation, found the function, realized it did not subtract 3 automatically and used it.

K.Calc<-kurtosis(Normal.Sample.1)-3

Kurtosis = 0

Distributions and Probability

Probability Density Function (PDF)

  • You can calculate the PDF using this function (but best to have zscored first). Thus the formula works when \(M = 0\), \(S = 1\). This will allow users to calculate the probability related to getting specific scores.

\[f(x) = \frac{1}{\sqrt{2\pi\sigma^2}} e^{-\frac{(x - \mu)^2}{2 \sigma^2}}\]

Zscore formulas

zscore formula when \(\mu\) and \(\sigma\) is known

\[Z = \frac{X-\mu}{\sigma}\] zscore formula when \(\mu\) and \(\sigma\) is unknown (R default assumption)

\[Z = \frac{X-M}{S}\]

We can use the scale function: scale(x, center = TRUE, scale = TRUE). We can leave the defaults of center = TRUE (which center the data, do \(X-M\) instead of just \(X\) in the numerator) and scale = TRUE (divide by \(S\)). To use defaults, just write nothing. If you want to center and not standardize do, scale(Normal.Sample.1, scale=FALSE)

?scale # To see arguments for R function
Normal.Sample.Z<-scale(Normal.Sample.1)

Normal.Sample.Z is now a vector with a length of N

This does not change the shape of the distribution but makes it so you can compare between distributions using the same scale, Now, \(M = 0\) and \(S = 1\)

hist(Normal.Sample.Z,
  main="Z Score Histogram", 
  xlab="Z-score", ylab="Frequency")

plot(density(Normal.Sample.Z),
  main="Probability Density Function", 
  xlab="z-score", ylab="Probability", 
  xlim=c(-3.25, 3.25))

  • Look a the PDF in your book and you will this matches. Lets put all into practice!

Why You Need to Standardize

Imagine you are teaching 3 classes: Statistics, Cognition, & Neuro. You have a student in all three classes, and she wants to how to compare her exam scores between all three classes (with N = 50 in each; but this does not need to be the case).

Student scores:

  • Stats: \(X = 40\)
  • Cog: \(X = 83\)
  • Neuro: \(X = 60\)

Black line = Student score relative to the class

set.seed(123)
N=50
Stats.class<-rnorm(N, mean=60,sd=8)
hist(Stats.class,
  main="Raw Score Histogram", 
  xlab="Stats Exam", ylab="Frequency")
abline(v=40, col="red")

Stats.Mean<-mean(Stats.class)
Stats.sd<-sd(Stats.class)
set.seed(123)
N=50
Cognition<-rnorm(N, mean=75,sd=4)
hist(Cognition,
  main="Raw Score Histogram", 
  xlab="Cognitive Exam", ylab="Frequency")
abline(v=83, col="black")

Cog.Mean<-mean(Cognition)
Cog.sd<-sd(Cognition)
set.seed(123)
N=50
Neuro<-rnorm(N, mean=40,sd=15)
hist(Neuro,
  main="Raw Score Histogram", 
  xlab="Neuro Exam", ylab="Frequency")
abline(v=60, col="black")

Neuro.Mean<-mean(Neuro)
Neuro.sd<-sd(Neuro)

Course Descriptive

  • Stats: M = 60.275, sd = 7.407
  • Cog: M = 75.138, sd = 3.703
  • Neuro: M = 40.516, sd = 13.888

The student looks at the histograms and the class mean/sd and says so what? [Now you know why they failed your stats exam]

Find Percentile

  • We need the z-score for the individual score, so we will use the sample zscore formula to calculate their individual zscore by hand

\[Z = \frac{X - M}{s}\]

Z-Scores per Exam

Stats.Z<-(40 - mean(Stats.class))/sd(Stats.class)
Cog.Z<-(83 - mean(Cognition))/sd(Cognition)
Neuro.Z<-(60 - mean(Neuro))/sd(Neuro)
  • Stats: Z = -2.737
  • Cog: Z = 2.123
  • Neuro: Z = 1.403

Student says so what does all this mean?

Let’s assume the normal distribution and give them their percentile

Relative the normal distribution here is how the three tests are

plot(density(Normal.Sample.Z),
  main="Probability Density Function", 
  xlab="z-score", ylab="Probability", 
  xlim=c(-3.25, 3.25))
abline(v=Stats.Z, col="red")
abline(v=Cog.Z, col="blue")
abline(v=Neuro.Z, col="green")

The percentile can be easier seen in the CDF of these positions. We can do that via the ecdf function (which is slow). The area under the curve behind the line percentile score can be calculated manually in R, but that is a slow process. R can look up those values for you with the function pnorm.

plot(ecdf(Normal.Sample.Z),
  main="Cumulative Density Function", 
  xlab="z-score", ylab="Probability", 
  xlim=c(-3.25, 3.25))
abline(v=Stats.Z, col="red")
abline(v=Cog.Z, col="blue")
abline(v=Neuro.Z, col="green")

But wait? Do we assume the true population distribution of our sample is normal, or should we calculate the percentile for this data based on this distribution (empirically)? Mostly we assume the normal distribution and we use the tables in our book. Also, doing it empirically opens up a lot questions we will hold off for now.

Stats.Perc<-round(pnorm(Stats.Z)*100,1)
Cog.Perc<-round(pnorm(Cog.Z)*100,1)
Neuro.Perc<-round(pnorm(Neuro.Z)*100,1)
  • Stats: Percentile = 0.3
  • Cog: Percentile = 98.3
  • Neuro: Percentile = 92

Check this numbers in your tables!

You tell the student they need to start doing their stats homework!

Sampling Error

We rarely, if ever, get to work with population data. Instead, we sample our population and hope we can estimate the parameters of the population distribution via sample statistics. In R, we can simulate this process very quickly.

Sample

To extract a sample in R from a population, we can do it a few ways. However, we will do it the more verbose way for now (but it is slower to run).

Step 1: Generate/View population

We did this way before using our the rnorm function. Here is the histogram again:

hist(Normal.Sample.1,
  main="Raw Score Histogram", 
  xlab="Population Distribution", ylab="Frequency")
abline(v=100, col="black")

Step 2: Randomly sample from the distribution

We can use the sample function. The function works as follows: sample(distro, sample size you want, with/without replacement). If you ?sample, you will notice the default is to sample without replacement, so we need to override that argument. Note: We again need to set a seed to get the same answer

set.seed(42)
SampleSize = 10
sample.1<-sample(Normal.Sample.1, SampleSize, replace = TRUE)
hist(sample.1,
  main="Raw Score Histogram", 
  xlab="Sample Distribution", ylab="Frequency")

Step 3: Calculate moments of sample

M.1<-mean(sample.1)
SD.1<-sd(sample.1)
SK.1<-skewness(sample.1)
K.1<-kurtosis(sample.1)-3
Moments M S Skewness Kurtosis
Pop Params 100 15 0 0
Sim moments 99.99 14.99 0 -0.15
Sample moments 100.18 12.06 0.59 -0.15

You can see how our moments of the sample are different from our population (sampling error)

Step 4: Simulate 1000 samples!

The replicate function allows us to sample over and over again (creating a matrix of 10 values per sample X 1000 samples). The apply function allows us to apply a function across rows or columns (we want to apply over columns as each column is a sample).

NumberofSamples=1000
SampleSize=10
Sample.Results<-replicate(NumberofSamples,sample(Normal.Sample.1, size = SampleSize, replace=TRUE))
Sample.Means<-apply(Sample.Results,2,mean)
Sample.SD<-apply(Sample.Results,2,sd)
Sample.SK<-apply(Sample.Results,2,skewness)
Sample.K<-apply(Sample.Results,2,kurtosis)-3
hist(Sample.Means,
  main="Means of Samples Histogram", 
  xlab="Means Distribution", ylab="Frequency")

You will notice the distribution of means is normal and centered around 100, and it was precisely: Mean of means = 99.79 [very close to population!]

hist(Sample.SD,
  main="SD of Samples Histogram", 
  xlab="SD Distribution", ylab="Frequency")

You will notice the distribution of SD is skewed a bit positive centered below around 15. Mean of SD = 14.55 [below our population as our sample size is small, so its biased estimate).

hist(Sample.SK,
  main="Skewness of Samples Histogram", 
  xlab="Skewness Distribution", ylab="Frequency")

You will notice the distribution of skewness is skewed a bit as well centered around 0. Mean of skewness = -0.03

hist(Sample.K,
  main="Kurtosis of Samples Histogram", 
  xlab="Kurtosis Distribution", ylab="Frequency")

You will notice the distribution of kurtosis is very negatively skewed and not centered at zero. Mean of kurtosis = -0.56. Estimating the kurtosis is very difficult in small samples, and you will often have to assume you are working from a normal sample. If your sample size per study was larger, this would work much better.

Step 4: Moments of the Distribution of Means

Classical methods often use sample means to compare differences, as in the like the t-test and ANOVA (and not sd). We can thus extract our sampling error by examining the second moment of the distribution of means:

\[SE = \sqrt{\frac{\Sigma (M-M_{Grand})^2}{N-1}}\]

M.S<-mean(Sample.Means)
SD.S<-sd(Sample.Means)

The grand mean \(M_G\) = 99.79

Sampling error (spread of that mean) = 4.67

Standard Error

We cannot run thousands of samples, so we can approximate this value

\[SE = \frac{S}{\sqrt{N}}\]

So our first sample sd = 12.06 and it would estimate our standard error of the mean to be SE = 3.81, which is smaller but not too far from our simulated value. This value will be more accurate as our N increase, and our SD estimate gets more precise and accurate.

In fact, I can show how unstable the SE guess would actually be from our N = 10 simulation done 1000 times

SEM<-Sample.SD/SampleSize^.5

hist(SEM,
  main="SEM of Samples Histogram", 
  xlab="SEM Distribution", ylab="Frequency")

SEM.Estimate<-mean(SEM)

So our mean of the SE calculated values, mean SEM = 4.6 from our simulation is extremely close (but still smaller) than estimate our standard error of the SE from our simulation = 4.67. You will notice the distribution of possible SEM we could get from our studies is very large, and that is because our sample was very small. As you increase the sample size this distribution will narrow.

The main point is that samples are guesses of the population, and your guess will depend on the spread of the original distribution. The wider that distribution that larger the sample needs to be to estimate it. You cannot know if you are right, so we hope those numbers will replicate. If you reran the study and found the first two moments are jumping around, you probably need a much large sample size.

LS0tDQp0aXRsZTogJ01vbWVudHMsIFotc2NvcmVzLCBQcm9iYWJpbGl0eSwgJiBTYW1wbGluZyBFcnJvcicNCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBmb250c2l6ZTogOHB0DQogICAgaGlnaGxpZ2h0OiB0ZXh0bWF0ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogbm8NCiAgICB0aGVtZTogZmxhdGx5DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IG5vDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQojIFRoaXMgc3R1ZmYgYXBwbGllcyBhY3Jvc3MgUiB3aW5kb3dzDQprbml0cjo6b3B0c19jaHVuayRzZXQoY2FjaGU9VFJVRSkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChtZXNzYWdlID0gRkFMU0UpDQprbml0cjo6b3B0c19jaHVuayRzZXQod2FybmluZyA9ICBGQUxTRSkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcud2lkdGg9NS4wKQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGZpZy5oZWlnaHQ9My41KQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGZpZy5hbGlnbj0nY2VudGVyJykgDQpgYGANCg0KDQojIEdhdXNzaWFuIERpc3RyaWJ1dGlvbg0KR2F1c3NpYW4gZGlzdHJpYnV0aW9uIChuYW1lZCBhZnRlciBKb2hhbm4gQ2FybCBGcmllZHJpY2ggR2F1c3MsIDE3NzctMTg1NSwgYWthIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uKSBpcyBhIHNwZWNpYWwgZGlzdHJpYnV0aW9uIHRoYXQgaXMgdGhlIGJhc2lzIG9mIENsYXNzaWNhbCAqKlBhcmFtZXRyaWMqKiBTdGF0aXN0aWNzLCB3aHk/IFdlbGwgYmVjYXVzZSBpdHMgcmVhbGx5IGVhc3kgdG8gd29yayB3aXRoIChub3QgYSBqb2tlKS4gIEl0IGlzIGRlZmluZWQgYnkgYW5kIGl0IGlzIGRlZmluZWQgYnkgMiBwYXJhbWV0ZXJzICgkXG11JCAmICRcc2lnbWEkKSB3aGVuIHRoZSBvdGhlciB0d28gcGFyYW1ldGVycyAoU2tld25lc3MgJiBLdXJ0b3NpcykgZXF1YWwgMC4gSSB3aWxsIGNvbWUgYmFjayB0byB0aG9zZSBiZWxvdyB1bmRlciAqKk1vbWVudHMqKi4gICAgIA0KDQpHYXVzc2lhbiBkaXN0cmlidXRpb24gKGFrYSB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbikgd2lsbCBzZXJ2ZSBhcyBvdXIgcG9wdWxhdGlvbiBkaXN0cmlidXRpb24uIFIgd2lsbCBsZXQgdXMgc2ltdWxhdGUgYSBwb3B1bGF0aW9uIHdpdGggJFxtdSA9IDEwMDsgIFxzaWdtYSA9IDE1OyBOID0gMWUxMF42JC4gKk5vdGU6IHRoZSBzZWVkIGFsbG93cyBhbGwgaGF2ZSB0byBpZGVudGljYWwgcmFuZG9tIHJlc3VsdHMuKg0KDQpXZSB3aWxsIHVzZSB0aGUgYHJub3JtYCBmdW5jdGlvbiB3aGljaCB3aWxsIGFsbG93IHVzIHRvICpwYXNzKiB0aGUgcGFyYW1ldGVycyB3ZSB3YW50IHRvIHVzZSB0byBjcmVhdGUgb3VyIHBvcHVsYXRpb24gZGlzdHJpYnV0aW9uLiBBcyBSIGlzIGFuIG9iamVjdC1vcmllbnRlZCBsYW5ndWFnZSwgdGhlIHJlc3VsdHMgb2YgdGhpcyBmdW5jdGlvbiB3aWxsIGJlIGFuICpvYmplY3QqIChhIGJ1Y2tldCwgd2hpY2ggd2UgZmlsbGVkIHdpdGggcmFuZG9tLCBidXQgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgbnVtYmVycykuIFdlIGNhbiBleGFtaW5lIHdoYXQgaXMgaW4gdGhpcyAqb2JqZWN0KiwgYnV0IGZpcnN0IHdlIG11c3QgbmFtZSBvdXQgdGhpcyBvYmplY3QsIGFuZCB3ZSBjYWxsIGl0IGFueXRoaW5nIHdlIHdhbnQgYXMgbG9uZyBhcyB3ZSBkb24ndCBoYXZlIHNwYWNlcyBpbiBvdXIgbmFtZSAoZm9yIGV4YW1wbGUsIFRoZS5CdWNrZXQub2YuTWFueS5SYW5kb20uTnVtYmVycywgaG93ZXZlciB0aGF0IGlzIGEgc2lsbHkgbmFtZSksIHNvIHdlIHdpbGwgY2FsbCBpdCAqKk5vcm1hbC5TYW1wbGUuMSoqLg0KDQpgYGB7cn0NCnNldC5zZWVkKDY2NikNCm49MWU2ICMxIG1pbGxpb24gcGVvcGxlDQpNdT0xMDAgIyBTZXQgcG9wIG1lYW4NClMgPSAxNSAjIHNldCBwb3AgU0QNCk5vcm1hbC5TYW1wbGUuMTwtcm5vcm0obiwgbWVhbiA9IE11LCBzZCA9IFMpDQpgYGANCg0KV2UgY2FuIGFkZCBhIGhpc3RvZ3JhbSAoYGhpc3RgKSwgd2hlcmUgd2UgY291bGQgZGVmaW5lIGEgYmluIHNpemUgKGJ1dCBSIHdpbGwgZG8gaXQgYXV0b21hdGljYWxseSBpZiB3ZSBkbyBub3QgKnBhc3MqIG9uZSkgYW5kIGFkZCBsYWJlbHMsIGFzIGFsbCBncmFwaHMgc2hvdWxkIGJlIHdlbGwgbGFiZWxlZC4gICANCg0KYGBge3J9DQpoaXN0KE5vcm1hbC5TYW1wbGUuMSwNCiAgbWFpbj0iUmF3IFNjb3JlIEhpc3RvZ3JhbSIsIA0KICB4bGFiPSJQb3B1bGF0aW9uIERpc3RyaWJ1dGlvbiIsIHlsYWI9IkZyZXF1ZW5jeSIpDQphYmxpbmUodj0xMDAsIGNvbD0iYmxhY2siKQ0KYGBgDQoNCkFzIHdlIGNhbiBzZWUgaW4gRmlndXJlIGFib3ZlLCB3ZSBoYXZlIHdoYXQgc2VlbXMgYSBuaWNlIG5vcm1hbCBkaXN0cmlidXRpb24gd2l0aCAxIG1pbGxpb24gcmFuZG9tIHNjb3Jlcy4gTmV4dCwgd2UgbmVlZCB0byBleGFtaW5lIHRoZSBzaGFwZSBvZiB0aGUgZGlzdHJpYnV0aW9uIGJ5IGxvb2tpbmcgYXQgdGhlIDQgbW9tZW50cy4gDQoNCiMjIE1vbWVudHMgDQpUaGVyZSBhcmUgNCBtb21lbnRzIHRoYXQgY2FuIGNhcHR1cmUgaW1wb3J0YW50IGFzcGVjdHMgb2YgdGhlIGRpc3RyaWJ1dGlvbiAoMS4gY2VudGVyLCAyLiBzcHJlYWQsIDMuc3ltbWV0cnksIGFuZCA0LiBwZWFraW5lc3MpLiANCg0KIyMjIE1vbWVudCAxOiAgQ2VudHJhbCBUZW5kZW5jeSANCkNhcHR1cmVzIHRoZSBjZW50ZXIgb2YgdGhlIGRpc3RyaWJ1dGlvbiBhbmQgYmUgZGVmaW5lZCB0aHJlZSBjbGFzc2ljYWwgd2F5cyAoTWVhbiwgTWVkaWFuLCBNb2RlKS4gTWVhbi9NZWRpYW4vTW9kZSBhcmUgdXNlZCB0byBpZGVudGlmeSBhIHNpbmdsZSBzY29yZSAocG9pbnQtZXN0aW1hdGlvbikgdGhhdCBpcyByZXByZXNlbnRhdGl2ZSBmb3IgYW4gZW50aXJlIGRpc3RyaWJ1dGlvbiBvciBzZXQgb2YgZGF0YS4gDQoNCk1lYW4gKHRoZSBhdmVyYWdlKToNCg0KLSBpcyB0aGUgc3RhbmRhcmQgbWVhc3VyZSBvZiBjZW50cmFsIHRlbmRlbmN5IGluIHN0YXRpc3RpY3MuIA0KLSBpcyBub3QgbmVjZXNzYXJpbHkgZXF1YWwgdG8gYW55IHNjb3JlIGluIHRoZSBkYXRhIHNldCANCi0gaXMgdGhlIG1vc3Qgc3RhYmxlIG1lYXN1cmUgZnJvbSBzYW1wbGUgdG8gc2FtcGxlLiANCi0gaXMgdmVyeSBpbmZsdWVuY2VkIGJ5IG91dGxpZXJzICh0aGUgbWVhbiB3aWxsIGJlIHN0cm9uZ2x5IGluZmx1ZW5jZWQgYnkgdGhlIHByZXNlbmNlIG9mIGV4dHJlbWUgc2NvcmVzKS4gDQotIGlzIGJhc2VkIG9uIGFsbCBzY29yZXMgZnJvbSB0aGUgc2FtcGxlIGJ1dCB0aGUgbW9kZSBhbmQgdGhlIG1lZGlhbiBhcmUgbm90LiANCg0KTWVkaWFuICh0aGUgbWlkZGxlIG51bWJlcik6DQoNCi0gaXMgbm90IHNlbnNpdGl2ZSB0byBvdXRsaWVycyEgDQotIGlzIHRoZSBiZXN0IG1lYXN1cmUgb2YgY2VudHJhbCB0ZW5kZW5jeSBpZiB0aGUgZGlzdHJpYnV0aW9uIGlzIHNrZXdlZC4gDQoNCk1vZGUgKG1vc3QgY29tbW9uIG51bWJlcik6DQoNCi0gaXMgdGhlIGxlYXN0IHN0YWJsZSBtZWFzdXJlIGZyb20gc2FtcGxlIHRvIHNhbXBsZS4gDQoNCg0KIyMjIyBNZWFuDQpJbiBSIHRoZXJlIG1hbnkgd2F5cyB0byBkbyB0aGluZ3MuIFRoZXJlIGFyZSBvZnRlbiBwYWNrYWdlcyB3aGljaCBwZW9wbGUgaGF2ZSBjcmVhdGVkIHRvIG1ha2UgeW91ciBsaWZlIGVhc2llciBidXQgbGV04oCZcyBzdGFydCBieSByZXBsaWNhdGluZyB0aGUgZm9ybXVsYSBpbiBjb2RlLiBZb3Ugd2lsbCBub3RpY2UgYmVsb3cgdGhhdCBjb2RlIHRoYXQgd2UgY2FuIHdyaXRlIGl0IG11bHRpcGxlIHN0ZXBzLCBvciB3ZSBjb3VsZCBoYXZlIGRvbmUgaXQgYWxsIGF0IG9uY2UuIEJ1dCBmaXJzdCBgc3VtYCB0aGUgb2JqZWN0IGFuZCBkaXZpZGUgaXQgYnkgdGhlIGBsZW5ndGhgIG9mIHRoZSBvYmplY3QgKG5vdGUgdGhhdCBsZW5ndGggaXMgdGhlIHdheSB3ZSB0YWJ1bGF0ZSBob3cgbG9uZyBvdXIgb2JqZWN0IGlzLiBJbiB0aGlzIGNhc2Ugb3V0IG9iamVjdCBpcyBhICp2ZWN0b3IqOiB3aGljaCBpcyBhIHNpbXBseSBhIDEtZGltIHN0cmluZyBvZiBudW1iZXJzKS4NCg0KJCRNID0gXGZyYWN7XFNpZ21hIFh9e059JCQNCg0KKipOb3RlOioqIEluIFIgeW91IGNhbiB1c2UgIj0iIG9yICI8LSIgdG8gY3JlYXRlIHRoZSBvYmplY3QuIFRvIGhlbHAgbWFrZSB0aGUgY29kZSBtb3JlIHJlYWRhYmxlIEkgdXNlICI9IiB0byBzZXQgKmFyZ3VtZW50KiBvciAqcGFyYW1ldGVycyogdGhhdCBJIHBhc3MgaW50byBmdW5jdGlvbiBhbmQgIjwtIiBmb3Igb2JqZWN0cy4gUiBjb2RlcnMgaW4gZ2VuZXJhbCB1c2UgIjwtIi4NCg0KYGBge3J9DQpTdW1YIDwtIHN1bShOb3JtYWwuU2FtcGxlLjEpICMgU3VtIG9mIFgNCk4gPC0gbGVuZ3RoKE5vcm1hbC5TYW1wbGUuMSkgIyBsZW5ndGggb2YgdmVjdG9yIA0KTSA8LSBTdW1YL04gIyBjYWxjIG1lYW4NCk0gIyBDYWxscyBvYmplY3RzIGZvciB1cyB0byBzZWUNCg0KIyBPUiBhbGwgYXQgb25jZQ0KTSA8LXN1bShOb3JtYWwuU2FtcGxlLjEpL2xlbmd0aChOb3JtYWwuU2FtcGxlLjEpDQpgYGANCg0KVGhlIG1lYW4gd2FzIGByIHJvdW5kKE0sMilgIGFuZCBjbG9zZSB0byBleHBlY3RlZCAkXG11JCBvZiAxMDAuIEhvd2V2ZXIsIHdlIHNob3VsZCB1c2UgdGhlIGJ1aWx0LWluIGZ1bmN0aW9uLCBgbWVhbihOb3JtYWwuU2FtcGxlLjEpYA0KDQoNCiMjIyMgTWVkaWFuDQpIZXJlIEkgY2FuIGNhbGwgbWVkaWFuIGFuZCBub3QgY3JlYXRlIGFuIG9iamVjdC4gIFRoaXMgd2lsbCBjYXVzZSBSIHRvIHNob3cgbWUgdGhlIGFuc3dlciwgYnV0IG5vdCBzYXZlIGl0Lg0KDQpgYGB7cn0NCm1lZGlhbihOb3JtYWwuU2FtcGxlLjEpDQpgYGANCg0KIyMjIyBNb2RlDQpUaGVyZSBpcyBubyBidWlsdC1pbiBtb2RlIGZ1bmN0aW9uIGluIFIgdGhhdCBnaXZlcyB0aGUgbW9kZS4gTm90ZTogVGhlIGZ1bmN0aW9uIGBtb2RlYCB5aWVsZHMgaW5mb3JtYXRpb24gYWJvdXQgdGhlIHR5cGUgb2YgZGF0YSAobnVtZXJpYywgZmFjdG9yLCBldGMuKSBvZiB0aGUgb2JqZWN0LiBTbyB5b3UgaGF2ZSB0byBnbyB0byBnb29nbGUgYW5kIGVpdGhlciAxKSBmaW5kIGEgcGFja2FnZSBvciAyKSBmaW5kIHNvbWVvbmUgd2hvIHdyb3RlIGEgZnVuY3Rpb24uIA0KDQotIFdoeSBpcyB0aGUgbW9kZSBhIHByb2JsZW0/IEJlY2F1c2UgaXQgbWlnaHQgYmUgbXVsdGktbW9kYWwgb3Igbm9uLW1vZGFsLiAgDQoNCi0gT25saW5lIHBlb3BsZSBzdWdnZXN0IHRoZSBgbW9kZWVzdGAgcGFja2FnZS4gSG93ZXZlciwgdGhpcyBwYWNrYWdlIGhhcyBub3QgYmVlbiB1cGRhdGVkIHRvIHdvcmsgaW4gdGhlIGxhdGVzdCB2ZXJzaW9uIFIgKDMuNi4xIGFzIG9mIDgtMjAxOSkuIA0KLSBXaGVuIHBhY2thZ2VzIGZhaWwsIHdlIHR1cm4gdG8gKipzdGFja292ZXJmbG93KiouIFlvdSBjYW4gZm9sbG93IHRoaXMgbGluayBhbmQgc2VlIGFsbCB0aGUgcGVvcGxlIHRhbGtpbmcgYWJvdXQgdGhpcyBwcm9ibGVtIGFuZCB0cnlpbmcgdG8gd3JpdGUgdGhlaXIgb3duIGZ1bmN0aW9uIG9mIG1vZGU6IGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzI1NDc0MDIvaXMtdGhlcmUtYS1idWlsdC1pbi1mdW5jdGlvbi1mb3ItZmluZGluZy10aGUtbW9kZS4gSSBoYXZlIGNvcGllZCBvdmVyIG9uZSBvZiB0aG9zZSBlbXBpcmljYWwgbW9kZSBmdW5jdGlvbnMgKGJhc2VkIG9uIGNvbnZlcnRpbmcgdGhlIGRpc3RyaWJ1dGlvbiBpbnRvIFBERiBhbmQgZmluZCB0aGUgcGVhazsgd3JpdHRlbiBieSBSYXNtdXMgQmFhdGgpLiAgU28gcmVtZW1iZXIgUiBpcyBvcGVuLXNvdXJjZSBhbmQgd2hlbiB5b3Ugc3RhcnQgdXNpbmcgcmFuZG9tIGZ1bmN0aW9uIHlvdSBmaW5kIG9ubGluZSwgeW91IG5lZWQgdG8gdmV0IHRoZW0gY2FyZWZ1bGx5LiBUaGlzIG9uZSB3aWxsIG9ubHkgd29yayB3aGVuIHRoZXJlIGlzIG9ubHkgb25lIHBlYWsuDQoNCipOb3RlKjogVGhpcyBpcyBob3cgeW91IGdlbmVyYXRlIHlvdXIgb3duIGZ1bmN0aW9uIGluIFIuICpXZSB3aWxsIHJldHVybiB0byB0aGlzIGNvbmNlcHQgbmV4dCB3ZWVrLiogIA0KDQpgYGB7cn0NCmVzdGltYXRlX21vZGUgPC0gZnVuY3Rpb24oeCkgew0KICBkIDwtIGRlbnNpdHkoeCkNCiAgZCR4W3doaWNoLm1heChkJHkpXQ0KfQ0KDQplc3RpbWF0ZV9tb2RlKE5vcm1hbC5TYW1wbGUuMSkNCg0KYGBgDQoNCg0KIyMjIE1vbWVudCAyOiBTcHJlYWQNClZhcmlhbmNlIGNhcHR1cmVzIHRoZSBzcHJlYWQgb2YgdGhlIGRpc3RyaWJ1dGlvbiBhbmQgY2FuIGJlIGRlZmluZWQgaW4gbWFueSBjbGFzc2ljYWwgd2F5cyAodmFyaWFuY2UsIHN0YW5kYXJkIGRldmlhdGlvbiwgbWVkaWFuIGFic29sdXRlIGRpZmZlcmVuY2UsIGludGVycXVhcnRpbGUgcmFuZ2UsIGVudHJvcHkpLiBBIGdvb2QgbWVhc3VyZSBvZiB2YXJpYWJpbGl0eSB3aWxsIGEpIGRlc2NyaWJlIHRoZSBzcHJlYWQgb2YgdGhlIGRpc3RyaWJ1dGlvbiwgYikgZGVzY3JpYmUgaG93IHdlbGwgYW4gaW5kaXZpZHVhbCBzY29yZSByZXByZXNlbnRzIHRoZSBlbnRpcmUgZGlzdHJpYnV0aW9uLiAgVGhlIG1vc3QgY29tbW9uIGluIHBzeWNob2xvZ3kgaXMgdGhlIHZhcmlhbmNlIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24uIFRoZSBjYXVzZXMgb2YgdmFyaWFiaWxpdHkgYXJlIGEpIEluZGl2aWR1YWwgZGlmZmVyZW5jZXMgaW4gcGFydGljaXBhbnRzIChnZW5ldGljcywgcGh5c2lvbG9neSwgZXhwZXJpZW5jZSwgbW9vZHMsIGV0Yy4pLCBiKSBSZXNlYXJjaGVyICYgRW52aXJvbm1lbnQgZmFjdG9ycyAoZmFjdG9ycyBpbiB0aGUgcmVzZWFyY2ggZW52aXJvbm1lbnQgdGhhdCBpbmZsdWVuY2UgaG93IHBlb3BsZSBiZWhhdmUpLiBhbmQgYykgTWVhc3VyZW1lbnQgZWZmZWN0cyAoaG93IHN1YmplY3RzIHJlYWN0IHRvIGEgcGFydGljdWxhciBtZXRob2Qgb2YgdGVzdGluZykuIA0KDQpPdXIgZXN0aW1hdGVzIG9mIG1vbWVudHMgY2FuIGJlIGJpYXNlZCAoaGF2ZSBlcnJvciBpbiB0aGVtKS4gQmlhc2VkIHNhbXBsZSBzdGF0aXN0aWMgaXMgaWYgdGhlIGF2ZXJhZ2UgdmFsdWUgb2YgdGhlIHNhbXBsZSBzdGF0aXN0aWMsIG9idGFpbmVkIG92ZXIgbWFueSBkaWZmZXJlbnQgc2FtcGxlcywgY29uc3RhbnRseSB1bmRlciBvciBvdmVyZXN0aW1hdGVzIHRoZSBwb3B1bGF0aW9uIHBhcmFtZXRlci4gVW5iaWFzZWQgc2FtcGxlIHN0YXRpc3RpYyBpcyBpZiB0aGUgYXZlcmFnZSB2YWx1ZSBvZiB0aGUgc2FtcGxlIHN0YXRpc3RpYywgb2J0YWluZWQgb3ZlciBtYW55IGRpZmZlcmVudCBzYW1wbGVzLCBpcyBlcXVhbCB0byB0aGUgcG9wdWxhdGlvbiBwYXJhbWV0ZXIuIEJhc2ljYWxseSwgd2UgYWx3YXlzIHRyeSB0byBtYWtlIHN1cmUgdGhhdCB3ZSBhcmUgYXMgY2xvc2UgYW5kIHVuYmlhc2VkIGFzIHBvc3NpYmxlIHdoZW4gdHJ5aW5nIHRvIHVzZSBzYW1wbGUgdG8gZXhwbGFpbiBhIHBvcHVsYXRpb24uICBUbyB0aGF0IHdlIHVzZSAoJE4tMSQpIHdoZW4gd2UgZG8gYXJlIHNhbXBsZSBjYWxjdWxhdGlvbnMuICpOb3RlKiB0aGF0IGZvciBhIHNhbXBsZSB0byBiZSBhbiB1bmJpYXNlZCBlc3RpbWF0ZSBvZiBhIHBvcHVsYXRpb24gaXQgbXVzdCBiZSByYW5kb21seSBzZWxlY3RlZC4gU2ltaWxhcmx5LCBpZiBzY29yZXMgZnJvbSBhIHNhbXBsZSBhcmUgdG8gc2VydmUgYXMgdW5iaWFzZWQgZXN0aW1hdGVzIG9mIHBvcHVsYXRpb24gc2NvcmVzIHRoZXkgbXVzdCBiZSBmcmVlIHRvIHZhcnkgcmFuZG9tbHkuIA0KDQpJbiBvdXIgZnV0dXJlIGFuYWx5c2VzLCB3ZSB3aWxsIG9mdGVuIHVzZSB0aGUgdW5iaWFzZWQgdmFyaWFuY2Ugc3RhdGlzdGljcywgYnV0IHdoZW4gd2UgZGVzY3JpYmUgZGlzdHJpYnV0aW9uIHdlIHVzZSB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uICh3aGljaCBpcyB0aGUgc3F1YXJlLXJvb3Qgb2YgdGhlIHZhcmlhbmNlKS4gSW4gcHJhY3RpY2UsIG9uZSBvZnRlbiBhc3N1bWVzIHRoYXQgdGhlIGRhdGEgYXJlIGZyb20gYW4gYXBwcm94aW1hdGVseSBub3JtYWxseSBkaXN0cmlidXRlZCBwb3B1bGF0aW9uLiBJZiB0aGF0IGFzc3VtcHRpb24gaXMganVzdGlmaWVkLCB0aGVuIGFib3V0IDY4JSBvZiB0aGUgdmFsdWVzIGFyZSB3aXRoaW4gMSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIG1lYW4sIGFib3V0IDk1JSBvZiB0aGUgdmFsdWVzIGFyZSB3aXRoaW4gdHdvIHN0YW5kYXJkIGRldmlhdGlvbnMgYW5kIGFib3V0IDk5LjclIGxpZSB3aXRoaW4gMyBzdGFuZGFyZCBkZXZpYXRpb25zLiBUaGlzIGlzIGtub3duIGFzIHRoZSAiNjgtOTUtOTkuNyBydWxlIiwgb3IgInRoZSBlbXBpcmljYWwgcnVsZSIuICBGaXJzdCB0byBsZXQncyBjYWxjdWxhdGUgdGhlIHZhcmlhbmNlIHRoYW4gc3RhbmRhcmQgZGV2aWF0aW9uLiANCg0KDQojIyMjIFZhcmlhbmNlL1NEIChCaWFzZWQgYW5kIFVuYmlhc2VkKQ0KQmlhc2VkIFZhcmlhbmNlIHdpdGgga25vd24gJFxtdSQNCiQkIFxzaWdtYV4yID0gXGZyYWN7XFNpZ21hIChYLVxtdSleMn17Tn0kJA0KVGhpcyBpcyBhIHRoZW9yZXRpY2FsIGZvcm11bGEsIGJ1dCBpbiBwcmFjdGljZSB3ZSB1c2UgdGhlICoqVW5iaWFzZWQgVmFyaWFuY2UqKiB3aGVuICRcbXUkIGlzIHVua25vd24uDQokJCBTXjIgPSBcZnJhY3tcU2lnbWEgKFgtTSleMn17Ti0xfSQkDQpSIHZlY3Rvcml6ZXMgdGhlIGRhdGEgc28gJFxTaWdtYShYLU0pXjIkIHdpbGwgZm9sbG93IHRoZSBQRU1EQVMsIGJ1dCB3YXRjaCB0aGUgKCkuIE1vcmUgaXMgYmV0dGVyLCBsZXNzIGNhbiBzY3JldyB5b3UgdXAgW2UuZy4sIHRoaXMgd2lsbCBmYWlsIGBzdW0oTm9ybWFsLlNhbXBsZS4xLU0pXjIvTi0xYCBiZWNhdXNlIGl0IFIgcmVhZHMgaXMgYXMgJFNeMiA9IFxTaWdtYSAoWC1NKV57XGZyYWN7Mn17Ti0xfX0kLg0KDQpgYGB7cn0NClZhcmllbmNlLm11PC1zdW0oKE5vcm1hbC5TYW1wbGUuMS1NKV4yKS8oTi0xKQ0KYGBgDQoNClRoZSAkU14yJCB3YXMgYHIgcm91bmQoVmFyaWVuY2UubXUsMilgIHdoaWNoIGFnYWluIGlzIGNsb3NlIHRvICRcc2lnbWFeMiQgb2YgYHIgMTVeMmANCg0KVGhlIFIgZnVuY3Rpb24gdXNlcyAkTSQgYW5kICROLTEkIG5vdCAkXG11JCBhbmQgJE4kDQoNCmBgYHtyfQ0KVmFyaWVuY2UuTTwtdmFyKE5vcm1hbC5TYW1wbGUuMSkNCmBgYA0KDQpVbmJpYXNlZCB2YXIgPSBgciByb3VuZChWYXJpZW5jZS5NLDIpYA0KDQojIyMjIFVuYmlhc2VkIFNEDQoNCiQkIFMgPSBcc3FydHtTXjJ9JCQNCnVzZSB0aGUgUiBmdW5jdGlvbiBhbmQgbm90ZSBpdHMgY2FsbGVkIGBzZGAuIE5ldmVyIG5hbWUgeW91ciBvYmplY3QganVzdCBgc2RgICgqKml0IGlzIGNhc2Ugc2Vuc2l0aXZlKiopDQpgYGB7cn0NClNELmNhbGMgPC0gc2QoTm9ybWFsLlNhbXBsZS4xKQ0KYGBgDQoNClVuYmlhc2VkIHNkID0gYHIgcm91bmQoU0QuY2FsYywyKWANCg0KIyMjIyBNQUQNCg0KV2hlbiB5b3UgaGF2ZSBsb3RzIG9mIG91dGxpZXJzIGluIHlvdXIgZGF0YSwgeW91IG1pZ2h0IHdhbnQgdG8gaW5zdGVhZCBjYWxjdWxhdGUgdGhlIE1lZGlhbiBBYnNvbHV0ZSBEaWZmZXJlbmNlIChNQUQpLiAgSXRzIGlzICoqcm9idXN0KiosIG1lYW5pbmcgaXQgaXMgbm90IGFzIGluZmx1ZW5jZWQgYnkgb3V0bGllcnMuDQoNCiQkTUFEID0gYiptZWRpYW58W3hfaSAtIG1lZGlhbih4KV18JCQNCndoZXJlLCAkYiA9IDEuNDgyNiQNCg0KYGBge3J9DQpNQURfTm9ybWFsPC1tYWQoTm9ybWFsLlNhbXBsZS4xKQ0KYGBgDQoNCk1BRCAoY29ycmVjdGVkKSA9IGByIHJvdW5kKE1BRF9Ob3JtYWwsMilgDQoNCllvdSB3aWxsIG5vdGljZSB0aGlzIGlzIHZlcnkgc2ltaWxhciB0byBzZCB2YWx1ZS4gDQoNCk5vdGU6IFlvdSBjYW4gZm9yY2UgUiB0byBnaXZlIHlvdSB0aGUgdW5jb3JyZWN0ZWQgYnkgY2hhbmdpbmcgdGhlIGFyZ3VtZW50cw0KYGBge3J9DQo/bWFkDQpNQURfbm9Db3JyZWN0PC1tYWQoTm9ybWFsLlNhbXBsZS4xLCBjb25zdGFudCA9IDEpDQpgYGANCg0KTUFEICh1bmNvcnJlY3RlZCkgPSBgciByb3VuZChNQURfbm9Db3JyZWN0LDIpYA0KDQojIyMjIEFsdGVybmF0aXZlIE1BRCBzY29yZXMNCg0KTWVhbiBhYnNvbHV0ZSBkZXZpYXRpb24gDQoNCiQkTUFEID0gYiptZWRpYW58W3hfaSAtIG1lYW4oeCldfCQkDQoNCmBgYHtyfQ0KTUFEX21lYW48LW1hZChOb3JtYWwuU2FtcGxlLjEsIGNlbnRlciA9IG1lYW4oTm9ybWFsLlNhbXBsZS4xKSkNCmBgYA0KDQpNQUQgKGJhc2VkIG9uIG1lYW4gY2VudGVyKSA9IGByIHJvdW5kKE1BRF9tZWFuLDIpYA0KDQpZb3Ugd2lsbCBub3RpY2UgaXQgaXMgdGhlIHNhbWUgYXMgb3VyIG1lZGlhbiBjZW50ZXJlZCBtYWQgYXMgdGhlIG1lZGlhbiA9IG1lYW4gaW4gdGhpcyBzYW1wbGUgKGFzIGl0IGlzIG5vcm1hbCB3aXRoIGEgaHVnZSBOKQ0KDQojIyMjIFJlbGF0aW9uc2hpcCBiZXR3ZWVuICRNJCBhbmQgJFMkDQpCZWNhdXNlICRTJCBpcyBjYWxjdWxhdGVkIHVzaW5nIHRoZSBmaXJzdCBtb21lbnQgb2YgJE0kLCAkUyQgd2lsbCBhbHdheXMgaW5jcmVhc2UgYXMgZnVuY3Rpb24gbWFnbml0dWRlIG9mICRNJC4gIFdoYXQgaWYgeW91IHdhbnQgdG8gY29tcGFyZSB0aGUgJFMkIGJldHdlZW4gdHdvIGRpc3RyaWJ1dGlvbnMgd2l0aCB2ZXJ5IGRpZmZlcmVudCAkTSQgdmFsdWVzPyBZb3UgY2FuIG5vcm1hbGl6ZSAkUyQgYnkgdGFraW5nIHRoZSBjb2VmZmljaWVudCBvZiB2YXJpYXRpb24gKENWKQ0KDQokJENWID0gXGZyYWN7U317TX0kJA0KDQpgYGB7cn0NCkNWPC0gU0QuY2FsYy9NDQpgYGANCg0KV2Ugc2VlIHRoZSAkQ1YkIHdhcyBgciByb3VuZChDViwgMilgLiANCg0KIyMjIE1vbWVudCAzOiBTa2V3bmVzcw0KVGhlcmUgYXJlIG1hbnkgZGlmZmVyZW50IGZvcm11bGFzIGZvciBza2V3bmVzcywgYnV0IGhlcmUgaXMgdGhlIGJhc2ljIGNvbmNlcHQgDQokJFNrZXduZXNzID0gXGZyYWN7XFNpZ21hKFgtTSleMyAvTn17U157M319ICAkJA0KDQpUbyBjYWxjdWxhdGUgYSBjYW4gaW5zdGFsbCBhIHBhY2thZ2UgdG8gZG8gdGhlIHdvcmsgZm9yIHlvdTogYGluc3RhbGwucGFja2FnZXMoIm1vbWVudHMiKWANCg0KYGBge3J9DQojIGluc3RhbGwucGFja2FnZXMoIm1vbWVudHMiKSAjIHJlbW92ZSBoYXNodGFnIGFuZCBydW4gaXQgT05DRS4gTm90IGVhY2ggdGltZSB5b3UgbmVlZCBpdA0KbGlicmFyeShtb21lbnRzKQ0KU0suQ2FsYzwtc2tld25lc3MoTm9ybWFsLlNhbXBsZS4xKQ0KYGBgDQoNClNrZXduZXNzID0gYHIgcm91bmQoU0suQ2FsYywyKWANCg0KIyMjIE1vbWVudCA0OiBLdXJ0b3Npcw0KDQpUaGVyZSBhcmUgbWFueSBkaWZmZXJlbnQgZm9ybXVsYXMgZm9yIGt1cnRvc2lzLCBidXQgaGVyZSBpcyB0aGUgYmFzaWMgY29uY2VwdCANCg0KJCRLdXJ0b3NpcyA9IFxmcmFje1xTaWdtYShYLU0pXjQgL059e1NeezR9fSAtIDMgICQkDQoNClRoZSBrdXJ0b3NpcyBmdW5jdGlvbiBpcyBpbiB0aGUgYG1vbWVudHNgIHBhY2thZ2UuICpOb3RlOiBIb3cgZGlkIEkga25vdyB0aGF0PyBJIGZpcnN0IGdvb2dsZWQgZm9yICJrdXJ0b3NpcyBpbiBSIiwgZm91bmQgdGhlIHBhY2thZ2UsIGluc3RhbGxlZCBpdCwgcmVhZCB0aGUgZG9jdW1lbnRhdGlvbiwgZm91bmQgdGhlIGZ1bmN0aW9uLCByZWFsaXplZCBpdCBkaWQgbm90IHN1YnRyYWN0IDMgYXV0b21hdGljYWxseSBhbmQgdXNlZCBpdC4qICANCg0KYGBge3J9DQpLLkNhbGM8LWt1cnRvc2lzKE5vcm1hbC5TYW1wbGUuMSktMw0KYGBgDQoNCkt1cnRvc2lzID0gYHIgcm91bmQoSy5DYWxjLDIpYA0KDQojIERpc3RyaWJ1dGlvbnMgYW5kIFByb2JhYmlsaXR5DQoNCiMjIFByb2JhYmlsaXR5IERlbnNpdHkgRnVuY3Rpb24gKFBERikNCi0gWW91IGNhbiBjYWxjdWxhdGUgdGhlIFBERiB1c2luZyB0aGlzIGZ1bmN0aW9uIChidXQgYmVzdCB0byBoYXZlIHpzY29yZWQgZmlyc3QpLiBUaHVzIHRoZSBmb3JtdWxhIHdvcmtzIHdoZW4gJE0gPSAwJCwgJFMgPSAxJC4gVGhpcyB3aWxsIGFsbG93IHVzZXJzIHRvIGNhbGN1bGF0ZSB0aGUgKnByb2JhYmlsaXR5KiByZWxhdGVkIHRvIGdldHRpbmcgc3BlY2lmaWMgc2NvcmVzLg0KDQokJGYoeCkgPSBcZnJhY3sxfXtcc3FydHsyXHBpXHNpZ21hXjJ9fSBlXnstXGZyYWN7KHggLSBcbXUpXjJ9ezIgXHNpZ21hXjJ9fSQkDQoNCiMjIFpzY29yZSBmb3JtdWxhcw0KenNjb3JlIGZvcm11bGEgd2hlbiAkXG11JCBhbmQgJFxzaWdtYSQgaXMga25vd24gDQoNCiQkWiA9IFxmcmFje1gtXG11fXtcc2lnbWF9JCQNCnpzY29yZSBmb3JtdWxhIHdoZW4gJFxtdSQgYW5kICRcc2lnbWEkIGlzIHVua25vd24gKFIgZGVmYXVsdCBhc3N1bXB0aW9uKQ0KDQokJFogPSBcZnJhY3tYLU19e1N9JCQNCg0KV2UgY2FuIHVzZSB0aGUgYHNjYWxlYCBmdW5jdGlvbjogc2NhbGUoeCwgY2VudGVyID0gVFJVRSwgc2NhbGUgPSBUUlVFKS4gV2UgY2FuIGxlYXZlIHRoZSBkZWZhdWx0cyBvZiBjZW50ZXIgPSBUUlVFICh3aGljaCBjZW50ZXIgdGhlIGRhdGEsIGRvICRYLU0kIGluc3RlYWQgb2YganVzdCAkWCQgaW4gdGhlIG51bWVyYXRvcikgYW5kIHNjYWxlID0gVFJVRSAoZGl2aWRlIGJ5ICRTJCkuIFRvIHVzZSBkZWZhdWx0cywganVzdCB3cml0ZSBub3RoaW5nLiBJZiB5b3Ugd2FudCB0byBjZW50ZXIgYW5kIG5vdCBzdGFuZGFyZGl6ZSBkbywgYHNjYWxlKE5vcm1hbC5TYW1wbGUuMSwgc2NhbGU9RkFMU0UpYA0KDQpgYGB7cn0NCj9zY2FsZSAjIFRvIHNlZSBhcmd1bWVudHMgZm9yIFIgZnVuY3Rpb24NCk5vcm1hbC5TYW1wbGUuWjwtc2NhbGUoTm9ybWFsLlNhbXBsZS4xKQ0KYGBgDQoNCk5vcm1hbC5TYW1wbGUuWiBpcyBub3cgYSB2ZWN0b3Igd2l0aCBhIGxlbmd0aCBvZiBOIA0KDQpUaGlzIGRvZXMgbm90IGNoYW5nZSB0aGUgc2hhcGUgb2YgdGhlIGRpc3RyaWJ1dGlvbiBidXQgbWFrZXMgaXQgc28geW91IGNhbiBjb21wYXJlIGJldHdlZW4gZGlzdHJpYnV0aW9ucyB1c2luZyB0aGUgc2FtZSBzY2FsZSwgTm93LCAkTSA9IDAkIGFuZCAkUyA9IDEkDQoNCmBgYHtyfQ0KaGlzdChOb3JtYWwuU2FtcGxlLlosDQogIG1haW49IlogU2NvcmUgSGlzdG9ncmFtIiwgDQogIHhsYWI9Ilotc2NvcmUiLCB5bGFiPSJGcmVxdWVuY3kiKQ0KYGBgDQoNCmBgYHtyfQ0KcGxvdChkZW5zaXR5KE5vcm1hbC5TYW1wbGUuWiksDQogIG1haW49IlByb2JhYmlsaXR5IERlbnNpdHkgRnVuY3Rpb24iLCANCiAgeGxhYj0iei1zY29yZSIsIHlsYWI9IlByb2JhYmlsaXR5IiwgDQogIHhsaW09YygtMy4yNSwgMy4yNSkpDQpgYGANCg0KLSBMb29rIGEgdGhlIFBERiBpbiB5b3VyIGJvb2sgYW5kIHlvdSB3aWxsIHRoaXMgbWF0Y2hlcy4gTGV0cyBwdXQgYWxsIGludG8gcHJhY3RpY2UhIA0KDQojIyBXaHkgWW91IE5lZWQgdG8gU3RhbmRhcmRpemUNCj4gSW1hZ2luZSB5b3UgYXJlIHRlYWNoaW5nIDMgY2xhc3NlczogU3RhdGlzdGljcywgQ29nbml0aW9uLCAmIE5ldXJvLiBZb3UgaGF2ZSBhIHN0dWRlbnQgaW4gYWxsIHRocmVlIGNsYXNzZXMsIGFuZCBzaGUgd2FudHMgdG8gaG93IHRvIGNvbXBhcmUgaGVyIGV4YW0gc2NvcmVzIGJldHdlZW4gYWxsIHRocmVlIGNsYXNzZXMgKHdpdGggTiA9IDUwIGluIGVhY2g7IGJ1dCB0aGlzIGRvZXMgbm90IG5lZWQgdG8gYmUgdGhlIGNhc2UpLiANCg0KU3R1ZGVudCBzY29yZXM6IA0KDQotIFN0YXRzOiAkWCA9IDQwJA0KLSBDb2c6ICRYID0gODMkDQotIE5ldXJvOiAkWCA9IDYwJA0KDQpCbGFjayBsaW5lID0gU3R1ZGVudCBzY29yZSByZWxhdGl2ZSB0byB0aGUgY2xhc3MNCg0KYGBge3J9DQpzZXQuc2VlZCgxMjMpDQpOPTUwDQpTdGF0cy5jbGFzczwtcm5vcm0oTiwgbWVhbj02MCxzZD04KQ0KaGlzdChTdGF0cy5jbGFzcywNCiAgbWFpbj0iUmF3IFNjb3JlIEhpc3RvZ3JhbSIsIA0KICB4bGFiPSJTdGF0cyBFeGFtIiwgeWxhYj0iRnJlcXVlbmN5IikNCmFibGluZSh2PTQwLCBjb2w9InJlZCIpDQpTdGF0cy5NZWFuPC1tZWFuKFN0YXRzLmNsYXNzKQ0KU3RhdHMuc2Q8LXNkKFN0YXRzLmNsYXNzKQ0KYGBgDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMTIzKQ0KTj01MA0KQ29nbml0aW9uPC1ybm9ybShOLCBtZWFuPTc1LHNkPTQpDQpoaXN0KENvZ25pdGlvbiwNCiAgbWFpbj0iUmF3IFNjb3JlIEhpc3RvZ3JhbSIsIA0KICB4bGFiPSJDb2duaXRpdmUgRXhhbSIsIHlsYWI9IkZyZXF1ZW5jeSIpDQphYmxpbmUodj04MywgY29sPSJibGFjayIpDQpDb2cuTWVhbjwtbWVhbihDb2duaXRpb24pDQpDb2cuc2Q8LXNkKENvZ25pdGlvbikNCmBgYA0KDQpgYGB7cn0NCnNldC5zZWVkKDEyMykNCk49NTANCk5ldXJvPC1ybm9ybShOLCBtZWFuPTQwLHNkPTE1KQ0KaGlzdChOZXVybywNCiAgbWFpbj0iUmF3IFNjb3JlIEhpc3RvZ3JhbSIsIA0KICB4bGFiPSJOZXVybyBFeGFtIiwgeWxhYj0iRnJlcXVlbmN5IikNCmFibGluZSh2PTYwLCBjb2w9ImJsYWNrIikNCk5ldXJvLk1lYW48LW1lYW4oTmV1cm8pDQpOZXVyby5zZDwtc2QoTmV1cm8pDQpgYGANCg0KQ291cnNlIERlc2NyaXB0aXZlIA0KDQotIFN0YXRzOiBNID0gYHIgcm91bmQoU3RhdHMuTWVhbiwzKWAsIHNkID0gYHIgcm91bmQoU3RhdHMuc2QsMylgDQotIENvZzogTSA9IGByIHJvdW5kKENvZy5NZWFuLDMpYCwgc2QgPSBgciByb3VuZChDb2cuc2QsMylgDQotIE5ldXJvOiBNID0gYHIgcm91bmQoTmV1cm8uTWVhbiwzKWAsIHNkID0gYHIgcm91bmQoTmV1cm8uc2QsMylgDQoNCj4gVGhlIHN0dWRlbnQgbG9va3MgYXQgdGhlIGhpc3RvZ3JhbXMgYW5kIHRoZSBjbGFzcyBtZWFuL3NkIGFuZCBzYXlzIHNvIHdoYXQ/ICBbTm93IHlvdSBrbm93IHdoeSB0aGV5IGZhaWxlZCB5b3VyIHN0YXRzIGV4YW1dDQoNCiMjIEZpbmQgUGVyY2VudGlsZQ0KLSBXZSBuZWVkIHRoZSB6LXNjb3JlIGZvciB0aGUgaW5kaXZpZHVhbCBzY29yZSwgc28gd2Ugd2lsbCB1c2UgdGhlIHNhbXBsZSB6c2NvcmUgZm9ybXVsYSB0byBjYWxjdWxhdGUgdGhlaXIgaW5kaXZpZHVhbCB6c2NvcmUgYnkgaGFuZA0KDQokJFogPSBcZnJhY3tYIC0gTX17c30kJA0KDQoqKlotU2NvcmVzIHBlciBFeGFtKioNCg0KYGBge3J9DQpTdGF0cy5aPC0oNDAgLSBtZWFuKFN0YXRzLmNsYXNzKSkvc2QoU3RhdHMuY2xhc3MpDQpDb2cuWjwtKDgzIC0gbWVhbihDb2duaXRpb24pKS9zZChDb2duaXRpb24pDQpOZXVyby5aPC0oNjAgLSBtZWFuKE5ldXJvKSkvc2QoTmV1cm8pDQpgYGANCg0KLSBTdGF0czogWiA9IGByIHJvdW5kKFN0YXRzLlosMylgDQotIENvZzogWiA9IGByIHJvdW5kKENvZy5aLDMpYA0KLSBOZXVybzogWiA9IGByIHJvdW5kKE5ldXJvLlosMylgDQoNCj4gU3R1ZGVudCBzYXlzIHNvIHdoYXQgZG9lcyBhbGwgdGhpcyBtZWFuPw0KDQoqKkxldCdzIGFzc3VtZSB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbiBhbmQgZ2l2ZSB0aGVtIHRoZWlyIHBlcmNlbnRpbGUqKg0KDQoNClJlbGF0aXZlIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uIGhlcmUgaXMgaG93IHRoZSB0aHJlZSB0ZXN0cyBhcmUNCg0KYGBge3J9DQpwbG90KGRlbnNpdHkoTm9ybWFsLlNhbXBsZS5aKSwNCiAgbWFpbj0iUHJvYmFiaWxpdHkgRGVuc2l0eSBGdW5jdGlvbiIsIA0KICB4bGFiPSJ6LXNjb3JlIiwgeWxhYj0iUHJvYmFiaWxpdHkiLCANCiAgeGxpbT1jKC0zLjI1LCAzLjI1KSkNCmFibGluZSh2PVN0YXRzLlosIGNvbD0icmVkIikNCmFibGluZSh2PUNvZy5aLCBjb2w9ImJsdWUiKQ0KYWJsaW5lKHY9TmV1cm8uWiwgY29sPSJncmVlbiIpDQpgYGANCg0KVGhlIHBlcmNlbnRpbGUgY2FuIGJlIGVhc2llciBzZWVuIGluIHRoZSBDREYgb2YgdGhlc2UgcG9zaXRpb25zLiBXZSBjYW4gZG8gdGhhdCB2aWEgdGhlIGBlY2RmYCBmdW5jdGlvbiAod2hpY2ggaXMgc2xvdykuIFRoZSBhcmVhIHVuZGVyIHRoZSBjdXJ2ZSBiZWhpbmQgdGhlIGxpbmUgcGVyY2VudGlsZSBzY29yZSBjYW4gYmUgY2FsY3VsYXRlZCBtYW51YWxseSBpbiBSLCBidXQgdGhhdCBpcyBhIHNsb3cgcHJvY2Vzcy4gIFIgY2FuIGxvb2sgdXAgdGhvc2UgdmFsdWVzIGZvciB5b3Ugd2l0aCB0aGUgZnVuY3Rpb24gYHBub3JtYC4gDQoNCg0KYGBge3J9DQpwbG90KGVjZGYoTm9ybWFsLlNhbXBsZS5aKSwNCiAgbWFpbj0iQ3VtdWxhdGl2ZSBEZW5zaXR5IEZ1bmN0aW9uIiwgDQogIHhsYWI9Inotc2NvcmUiLCB5bGFiPSJQcm9iYWJpbGl0eSIsIA0KICB4bGltPWMoLTMuMjUsIDMuMjUpKQ0KYWJsaW5lKHY9U3RhdHMuWiwgY29sPSJyZWQiKQ0KYWJsaW5lKHY9Q29nLlosIGNvbD0iYmx1ZSIpDQphYmxpbmUodj1OZXVyby5aLCBjb2w9ImdyZWVuIikNCmBgYA0KDQpCdXQgd2FpdD8gRG8gd2UgYXNzdW1lIHRoZSB0cnVlIHBvcHVsYXRpb24gZGlzdHJpYnV0aW9uIG9mIG91ciBzYW1wbGUgaXMgbm9ybWFsLCBvciBzaG91bGQgd2UgY2FsY3VsYXRlIHRoZSBwZXJjZW50aWxlIGZvciB0aGlzIGRhdGEgYmFzZWQgb24gdGhpcyBkaXN0cmlidXRpb24gKGVtcGlyaWNhbGx5KT8gTW9zdGx5IHdlIGFzc3VtZSB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbiBhbmQgd2UgdXNlIHRoZSB0YWJsZXMgaW4gb3VyIGJvb2suIEFsc28sIGRvaW5nIGl0IGVtcGlyaWNhbGx5IG9wZW5zIHVwIGEgbG90IHF1ZXN0aW9ucyB3ZSB3aWxsIGhvbGQgb2ZmIGZvciBub3cuIA0KDQpgYGB7cn0NClN0YXRzLlBlcmM8LXJvdW5kKHBub3JtKFN0YXRzLlopKjEwMCwxKQ0KQ29nLlBlcmM8LXJvdW5kKHBub3JtKENvZy5aKSoxMDAsMSkNCk5ldXJvLlBlcmM8LXJvdW5kKHBub3JtKE5ldXJvLlopKjEwMCwxKQ0KYGBgDQoNCi0gU3RhdHM6IFBlcmNlbnRpbGUgPSBgciBTdGF0cy5QZXJjYA0KLSBDb2c6IFBlcmNlbnRpbGUgPSBgciBDb2cuUGVyY2ANCi0gTmV1cm86IFBlcmNlbnRpbGUgPSBgciBOZXVyby5QZXJjYA0KDQpDaGVjayB0aGlzIG51bWJlcnMgaW4geW91ciB0YWJsZXMhIA0KDQo+IFlvdSB0ZWxsIHRoZSBzdHVkZW50IHRoZXkgbmVlZCB0byBzdGFydCBkb2luZyB0aGVpciBzdGF0cyBob21ld29yayEgDQoNCiMgU2FtcGxpbmcgRXJyb3INCg0KV2UgcmFyZWx5LCBpZiBldmVyLCBnZXQgdG8gd29yayB3aXRoIHBvcHVsYXRpb24gZGF0YS4gIEluc3RlYWQsIHdlIHNhbXBsZSBvdXIgcG9wdWxhdGlvbiBhbmQgaG9wZSB3ZSBjYW4gZXN0aW1hdGUgdGhlIHBhcmFtZXRlcnMgb2YgdGhlIHBvcHVsYXRpb24gZGlzdHJpYnV0aW9uIHZpYSBzYW1wbGUgc3RhdGlzdGljcy4gIEluIFIsIHdlIGNhbiBzaW11bGF0ZSB0aGlzIHByb2Nlc3MgdmVyeSBxdWlja2x5LiAgDQoNCiMjIFNhbXBsZQ0KVG8gZXh0cmFjdCBhIHNhbXBsZSBpbiBSIGZyb20gYSBwb3B1bGF0aW9uLCB3ZSBjYW4gZG8gaXQgYSBmZXcgd2F5cy4gIEhvd2V2ZXIsIHdlIHdpbGwgZG8gaXQgdGhlIG1vcmUgdmVyYm9zZSB3YXkgZm9yIG5vdyAoYnV0IGl0IGlzIHNsb3dlciB0byBydW4pLg0KDQojIyMgU3RlcCAxOiBHZW5lcmF0ZS9WaWV3IHBvcHVsYXRpb24NCldlIGRpZCB0aGlzIHdheSBiZWZvcmUgdXNpbmcgb3VyIHRoZSBybm9ybSBmdW5jdGlvbi4gSGVyZSBpcyB0aGUgaGlzdG9ncmFtIGFnYWluOg0KDQpgYGB7cn0NCmhpc3QoTm9ybWFsLlNhbXBsZS4xLA0KICBtYWluPSJSYXcgU2NvcmUgSGlzdG9ncmFtIiwgDQogIHhsYWI9IlBvcHVsYXRpb24gRGlzdHJpYnV0aW9uIiwgeWxhYj0iRnJlcXVlbmN5IikNCmFibGluZSh2PTEwMCwgY29sPSJibGFjayIpDQpgYGANCg0KIyMjIFN0ZXAgMjogUmFuZG9tbHkgc2FtcGxlIGZyb20gdGhlIGRpc3RyaWJ1dGlvbg0KV2UgY2FuIHVzZSB0aGUgYHNhbXBsZWAgZnVuY3Rpb24uIFRoZSBmdW5jdGlvbiB3b3JrcyBhcyBmb2xsb3dzOiBzYW1wbGUoZGlzdHJvLCBzYW1wbGUgc2l6ZSB5b3Ugd2FudCwgd2l0aC93aXRob3V0IHJlcGxhY2VtZW50KS4gSWYgeW91ID9zYW1wbGUsIHlvdSB3aWxsIG5vdGljZSB0aGUgZGVmYXVsdCBpcyB0byBzYW1wbGUgd2l0aG91dCByZXBsYWNlbWVudCwgc28gd2UgbmVlZCB0byBvdmVycmlkZSB0aGF0IGFyZ3VtZW50LiAqTm90ZTogV2UgYWdhaW4gbmVlZCB0byBzZXQgYSBzZWVkIHRvIGdldCB0aGUgc2FtZSBhbnN3ZXIqDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoNDIpDQpTYW1wbGVTaXplID0gMTANCnNhbXBsZS4xPC1zYW1wbGUoTm9ybWFsLlNhbXBsZS4xLCBTYW1wbGVTaXplLCByZXBsYWNlID0gVFJVRSkNCmBgYA0KDQpgYGB7cn0NCmhpc3Qoc2FtcGxlLjEsDQogIG1haW49IlJhdyBTY29yZSBIaXN0b2dyYW0iLCANCiAgeGxhYj0iU2FtcGxlIERpc3RyaWJ1dGlvbiIsIHlsYWI9IkZyZXF1ZW5jeSIpDQpgYGANCg0KIyMjIFN0ZXAgMzogQ2FsY3VsYXRlIG1vbWVudHMgb2Ygc2FtcGxlDQoNCmBgYHtyfQ0KTS4xPC1tZWFuKHNhbXBsZS4xKQ0KU0QuMTwtc2Qoc2FtcGxlLjEpDQpTSy4xPC1za2V3bmVzcyhzYW1wbGUuMSkNCksuMTwta3VydG9zaXMoc2FtcGxlLjEpLTMNCmBgYA0KDQoNCk1vbWVudHMgICAgfCBNICAgICAgfCBTICAgICB8IFNrZXduZXNzIHwgS3VydG9zaXN8DQotLS0tLS0tLS0tLXwtLS0tLS0tLXwtLS0tLS0tfC0tLS0tLS0tLS18LS0tLS0tLS0tfCANClBvcCBQYXJhbXMgfCAxMDAgICAgfCAxNSAgICB8IDAgICAgICAgIHwgMCAgICAgICB8DQpTaW0gbW9tZW50cyB8IGByIHJvdW5kKE0sMilgIHwgYHIgcm91bmQoU0QuY2FsYywyKWB8IGByIHJvdW5kKFNLLkNhbGMsMilgIHwgYHIgcm91bmQoSy4xLDIpYHwNClNhbXBsZSBtb21lbnRzIHwgYHIgcm91bmQoTS4xLDIpYCB8IGByIHJvdW5kKFNELjEsMilgfCBgciByb3VuZChTSy4xLDIpYCB8IGByIHJvdW5kKEsuMSwyKWB8DQoNCg0KWW91IGNhbiBzZWUgaG93IG91ciBtb21lbnRzIG9mIHRoZSBzYW1wbGUgYXJlIGRpZmZlcmVudCBmcm9tIG91ciBwb3B1bGF0aW9uIChzYW1wbGluZyBlcnJvcikNCg0KIyMjIFN0ZXAgNDogU2ltdWxhdGUgMTAwMCBzYW1wbGVzIQ0KVGhlIGByZXBsaWNhdGVgIGZ1bmN0aW9uIGFsbG93cyB1cyB0byBzYW1wbGUgb3ZlciBhbmQgb3ZlciBhZ2FpbiAoY3JlYXRpbmcgYSBtYXRyaXggb2YgMTAgdmFsdWVzIHBlciBzYW1wbGUgWCAxMDAwIHNhbXBsZXMpLiBUaGUgYGFwcGx5YCBmdW5jdGlvbiBhbGxvd3MgdXMgdG8gYXBwbHkgYSBmdW5jdGlvbiBhY3Jvc3Mgcm93cyBvciBjb2x1bW5zICh3ZSB3YW50IHRvIGFwcGx5IG92ZXIgY29sdW1ucyBhcyBlYWNoIGNvbHVtbiBpcyBhIHNhbXBsZSkuIA0KDQpgYGB7cn0NCk51bWJlcm9mU2FtcGxlcz0xMDAwDQpTYW1wbGVTaXplPTEwDQpTYW1wbGUuUmVzdWx0czwtcmVwbGljYXRlKE51bWJlcm9mU2FtcGxlcyxzYW1wbGUoTm9ybWFsLlNhbXBsZS4xLCBzaXplID0gU2FtcGxlU2l6ZSwgcmVwbGFjZT1UUlVFKSkNClNhbXBsZS5NZWFuczwtYXBwbHkoU2FtcGxlLlJlc3VsdHMsMixtZWFuKQ0KU2FtcGxlLlNEPC1hcHBseShTYW1wbGUuUmVzdWx0cywyLHNkKQ0KU2FtcGxlLlNLPC1hcHBseShTYW1wbGUuUmVzdWx0cywyLHNrZXduZXNzKQ0KU2FtcGxlLks8LWFwcGx5KFNhbXBsZS5SZXN1bHRzLDIsa3VydG9zaXMpLTMNCmBgYA0KDQoNCmBgYHtyfQ0KaGlzdChTYW1wbGUuTWVhbnMsDQogIG1haW49Ik1lYW5zIG9mIFNhbXBsZXMgSGlzdG9ncmFtIiwgDQogIHhsYWI9Ik1lYW5zIERpc3RyaWJ1dGlvbiIsIHlsYWI9IkZyZXF1ZW5jeSIpDQpgYGANCg0KWW91IHdpbGwgbm90aWNlIHRoZSBkaXN0cmlidXRpb24gb2YgbWVhbnMgaXMgbm9ybWFsIGFuZCBjZW50ZXJlZCBhcm91bmQgMTAwLCBhbmQgaXQgd2FzIHByZWNpc2VseTogTWVhbiBvZiBtZWFucyA9IGByIHJvdW5kKG1lYW4oU2FtcGxlLk1lYW5zKSwyKWAgW3ZlcnkgY2xvc2UgdG8gcG9wdWxhdGlvbiFdDQoNCmBgYHtyfQ0KaGlzdChTYW1wbGUuU0QsDQogIG1haW49IlNEIG9mIFNhbXBsZXMgSGlzdG9ncmFtIiwgDQogIHhsYWI9IlNEIERpc3RyaWJ1dGlvbiIsIHlsYWI9IkZyZXF1ZW5jeSIpDQpgYGANCg0KWW91IHdpbGwgbm90aWNlIHRoZSBkaXN0cmlidXRpb24gb2YgU0QgaXMgc2tld2VkIGEgYml0IHBvc2l0aXZlIGNlbnRlcmVkIGJlbG93IGFyb3VuZCAxNS4gTWVhbiBvZiBTRCA9IGByIHJvdW5kKG1lYW4oU2FtcGxlLlNEKSwyKWAgW2JlbG93IG91ciBwb3B1bGF0aW9uIGFzIG91ciBzYW1wbGUgc2l6ZSBpcyBzbWFsbCwgc28gaXRzIGJpYXNlZCBlc3RpbWF0ZSkuIA0KDQoNCmBgYHtyfQ0KaGlzdChTYW1wbGUuU0ssDQogIG1haW49IlNrZXduZXNzIG9mIFNhbXBsZXMgSGlzdG9ncmFtIiwgDQogIHhsYWI9IlNrZXduZXNzIERpc3RyaWJ1dGlvbiIsIHlsYWI9IkZyZXF1ZW5jeSIpDQpgYGANCg0KWW91IHdpbGwgbm90aWNlIHRoZSBkaXN0cmlidXRpb24gb2Ygc2tld25lc3MgaXMgc2tld2VkIGEgYml0IGFzIHdlbGwgY2VudGVyZWQgYXJvdW5kIDAuIE1lYW4gb2Ygc2tld25lc3MgPSBgciByb3VuZChtZWFuKFNhbXBsZS5TSyksMilgIA0KDQoNCmBgYHtyfQ0KaGlzdChTYW1wbGUuSywNCiAgbWFpbj0iS3VydG9zaXMgb2YgU2FtcGxlcyBIaXN0b2dyYW0iLCANCiAgeGxhYj0iS3VydG9zaXMgRGlzdHJpYnV0aW9uIiwgeWxhYj0iRnJlcXVlbmN5IikNCmBgYA0KDQpZb3Ugd2lsbCBub3RpY2UgdGhlIGRpc3RyaWJ1dGlvbiBvZiBrdXJ0b3NpcyBpcyB2ZXJ5IG5lZ2F0aXZlbHkgc2tld2VkIGFuZCBub3QgY2VudGVyZWQgYXQgemVyby4gTWVhbiBvZiBrdXJ0b3NpcyA9IGByIHJvdW5kKG1lYW4oU2FtcGxlLkspLDIpYC4gRXN0aW1hdGluZyB0aGUga3VydG9zaXMgaXMgdmVyeSBkaWZmaWN1bHQgaW4gc21hbGwgc2FtcGxlcywgYW5kIHlvdSB3aWxsIG9mdGVuIGhhdmUgdG8gYXNzdW1lIHlvdSBhcmUgd29ya2luZyBmcm9tIGEgbm9ybWFsIHNhbXBsZS4gSWYgeW91ciBzYW1wbGUgc2l6ZSBwZXIgc3R1ZHkgd2FzIGxhcmdlciwgdGhpcyB3b3VsZCB3b3JrIG11Y2ggYmV0dGVyLiANCg0KIyMjIFN0ZXAgNDogTW9tZW50cyBvZiB0aGUgRGlzdHJpYnV0aW9uIG9mIE1lYW5zDQpDbGFzc2ljYWwgbWV0aG9kcyBvZnRlbiB1c2Ugc2FtcGxlIG1lYW5zIHRvIGNvbXBhcmUgZGlmZmVyZW5jZXMsIGFzIGluIHRoZSBsaWtlIHRoZSB0LXRlc3QgYW5kIEFOT1ZBIChhbmQgbm90IHNkKS4gV2UgY2FuIHRodXMgZXh0cmFjdCBvdXIgc2FtcGxpbmcgZXJyb3IgYnkgZXhhbWluaW5nIHRoZSBzZWNvbmQgbW9tZW50IG9mIHRoZSBkaXN0cmlidXRpb24gb2YgbWVhbnM6IA0KDQokJFNFID0gXHNxcnR7XGZyYWN7XFNpZ21hIChNLU1fe0dyYW5kfSleMn17Ti0xfX0kJA0KDQoNCmBgYHtyfQ0KTS5TPC1tZWFuKFNhbXBsZS5NZWFucykNClNELlM8LXNkKFNhbXBsZS5NZWFucykNCg0KYGBgDQoNClRoZSBncmFuZCBtZWFuICRNX0ckID0gYHIgcm91bmQoTS5TLDIpYA0KDQpTYW1wbGluZyBlcnJvciAoc3ByZWFkIG9mIHRoYXQgbWVhbikgPSBgciByb3VuZChTRC5TLDIpYA0KDQojIyBTdGFuZGFyZCBFcnJvcg0KV2UgY2Fubm90IHJ1biB0aG91c2FuZHMgb2Ygc2FtcGxlcywgc28gd2UgY2FuIGFwcHJveGltYXRlIHRoaXMgdmFsdWUNCg0KJCRTRSA9IFxmcmFje1N9e1xzcXJ0e059fSQkDQoNClNvIG91ciBmaXJzdCBzYW1wbGUgc2QgPSBgciByb3VuZChTRC4xLDIpYCBhbmQgaXQgd291bGQgZXN0aW1hdGUgb3VyIHN0YW5kYXJkIGVycm9yIG9mIHRoZSBtZWFuIHRvIGJlIFNFID0gYHIgcm91bmQoU0QuMS8oMTBeLjUpLDIpYCwgd2hpY2ggaXMgc21hbGxlciBidXQgbm90IHRvbyBmYXIgZnJvbSBvdXIgc2ltdWxhdGVkIHZhbHVlLiBUaGlzIHZhbHVlIHdpbGwgYmUgbW9yZSBhY2N1cmF0ZSBhcyBvdXIgTiBpbmNyZWFzZSwgYW5kIG91ciBTRCBlc3RpbWF0ZSBnZXRzIG1vcmUgcHJlY2lzZSBhbmQgYWNjdXJhdGUuIA0KDQpJbiBmYWN0LCBJIGNhbiBzaG93IGhvdyB1bnN0YWJsZSB0aGUgU0UgZ3Vlc3Mgd291bGQgYWN0dWFsbHkgYmUgZnJvbSBvdXIgTiA9IDEwIHNpbXVsYXRpb24gZG9uZSAxMDAwIHRpbWVzDQoNCg0KYGBge3J9DQpTRU08LVNhbXBsZS5TRC9TYW1wbGVTaXplXi41DQoNCmhpc3QoU0VNLA0KICBtYWluPSJTRU0gb2YgU2FtcGxlcyBIaXN0b2dyYW0iLCANCiAgeGxhYj0iU0VNIERpc3RyaWJ1dGlvbiIsIHlsYWI9IkZyZXF1ZW5jeSIpDQpgYGANCg0KYGBge3J9DQpTRU0uRXN0aW1hdGU8LW1lYW4oU0VNKQ0KYGBgDQoNClNvIG91ciBtZWFuIG9mIHRoZSBTRSBjYWxjdWxhdGVkIHZhbHVlcywgbWVhbiBTRU0gPSBgciByb3VuZChTRU0uRXN0aW1hdGUsIDIpYCBmcm9tIG91ciBzaW11bGF0aW9uIGlzIGV4dHJlbWVseSBjbG9zZSAoYnV0IHN0aWxsIHNtYWxsZXIpIHRoYW4gZXN0aW1hdGUgb3VyIHN0YW5kYXJkIGVycm9yIG9mIHRoZSBTRSBmcm9tIG91ciBzaW11bGF0aW9uID0gYHIgcm91bmQoU0QuUywyKWAuIFlvdSB3aWxsIG5vdGljZSB0aGUgZGlzdHJpYnV0aW9uIG9mIHBvc3NpYmxlIFNFTSB3ZSBjb3VsZCBnZXQgZnJvbSBvdXIgc3R1ZGllcyBpcyB2ZXJ5IGxhcmdlLCBhbmQgdGhhdCBpcyBiZWNhdXNlIG91ciBzYW1wbGUgd2FzIHZlcnkgc21hbGwuICBBcyB5b3UgaW5jcmVhc2UgdGhlIHNhbXBsZSBzaXplIHRoaXMgZGlzdHJpYnV0aW9uIHdpbGwgbmFycm93LiAgDQoNClRoZSBtYWluIHBvaW50IGlzIHRoYXQgc2FtcGxlcyBhcmUgZ3Vlc3NlcyBvZiB0aGUgcG9wdWxhdGlvbiwgYW5kIHlvdXIgZ3Vlc3Mgd2lsbCBkZXBlbmQgb24gdGhlIHNwcmVhZCBvZiB0aGUgb3JpZ2luYWwgZGlzdHJpYnV0aW9uLiAgVGhlIHdpZGVyIHRoYXQgZGlzdHJpYnV0aW9uIHRoYXQgbGFyZ2VyIHRoZSBzYW1wbGUgbmVlZHMgdG8gYmUgdG8gZXN0aW1hdGUgaXQuIFlvdSBjYW5ub3Qga25vdyBpZiB5b3UgYXJlIHJpZ2h0LCBzbyB3ZSBob3BlIHRob3NlIG51bWJlcnMgd2lsbCByZXBsaWNhdGUuIElmIHlvdSByZXJhbiB0aGUgc3R1ZHkgYW5kIGZvdW5kIHRoZSBmaXJzdCB0d28gbW9tZW50cyBhcmUganVtcGluZyBhcm91bmQsIHlvdSBwcm9iYWJseSBuZWVkIGEgbXVjaCBsYXJnZSBzYW1wbGUgc2l6ZS4NCg0KDQo8c2NyaXB0Pg0KICAoZnVuY3Rpb24oaSxzLG8sZyxyLGEsbSl7aVsnR29vZ2xlQW5hbHl0aWNzT2JqZWN0J109cjtpW3JdPWlbcl18fGZ1bmN0aW9uKCl7DQogIChpW3JdLnE9aVtyXS5xfHxbXSkucHVzaChhcmd1bWVudHMpfSxpW3JdLmw9MSpuZXcgRGF0ZSgpO2E9cy5jcmVhdGVFbGVtZW50KG8pLA0KICBtPXMuZ2V0RWxlbWVudHNCeVRhZ05hbWUobylbMF07YS5hc3luYz0xO2Euc3JjPWc7bS5wYXJlbnROb2RlLmluc2VydEJlZm9yZShhLG0pDQogIH0pKHdpbmRvdyxkb2N1bWVudCwnc2NyaXB0JywnaHR0cHM6Ly93d3cuZ29vZ2xlLWFuYWx5dGljcy5jb20vYW5hbHl0aWNzLmpzJywnZ2EnKTsNCg0KICBnYSgnY3JlYXRlJywgJ1VBLTkwNDE1MTYwLTEnLCAnYXV0bycpOw0KICBnYSgnc2VuZCcsICdwYWdldmlldycpOw0KDQo8L3NjcmlwdD4=