I. Confidence Intervals
When conducting exploratory data analysis, we often wish to estimate parameters like the mean and standard deviation for numeric data, or a proportion for category data. Statisticians prefer interval estimates to point estimates. Though the confidence interval gives less apparent precision, the range of values can be constructed so that there is high likelihood the actual parameter is within that range.
Traditional confidence intervals use a theoretical distribution like the normal distribution or \(t\)-distribution. For a 95% confidence interval, two cutoff values are calculated, one left and one right, that will capture exactly 95% of the theoretical distribution between them.
Initializing RStudio
The data set we will use primarily is Data3350 which was produced in 2015 during an undergraduate research project about personality and humor. The VarsData3350 PDF file has descriptions of each variable in the Data3350 file. Both are available for download in D2L. Be sure to put the Data3350 in your R folder in Documents, and make sure your working directory is set the same way (Session menu). The code block below uses the library function to ensure that the Mosaic package is loaded and will import the data frame used in this module: Data3350.
library(mosaic)
library(readxl)
Data3350 = read_excel("Data3350.xlsx")
Example: IQ Scores
Question. Human IQ’s have the \(N(100,15)\) distribution. Find a symmetric interval about the mean that captures exactly 95% of the IQ distribution.
The mosaic function cdist finds the "center of the distribution. We can specify the normal distribution and the level of confidence.
cdist("norm", 0.95)
[1] -1.959964 1.959964

We know that the two cutoff values will lie exactly 1.96 standard deviations above or below the mean. We can the cdist function do the arithmetic for us by multiplying the cutoff values by the standard deviation and adding the population mean.
cdist("norm", 0.95 , plot = FALSE)*15+100
[1] 70.60054 129.39946
We know that 95% of human IQ’s will fall between 70.6 and 129.4.
Example 2: Sample of Student IQ’s
In a sample of 25 college students, the average IQ was 111. Find a 95% confidence interval for the mean IQ.
Solution. We can solve the \(z\)-statistic formula for \(z^*\), the cutoff values.
\[z = \frac{\overline x - \mu}{\sigma / \sqrt{n}}\] \[\overline x - \mu = z\cdot\frac{\sigma}{\sqrt n} \] We need to calculate the two \(z^*\) cutoff values will be identical distances from the mean, so we add the \(\pm\) and simplify.
\[\mu = \overline x \pm z^*\cdot\frac{\sigma}{\sqrt n} \] Here, \(z^* = \pm 1.96\), so we can substitute
\[\mu = 111 \pm 1.96\cdot\frac{15}{\sqrt {25}} \] and find the two cutoff values.
\[\mu = 111 \pm (3) 1.96 =111 \pm 5.88 \] Thus, the 95% confidence interval for the mean of these 25 college students is \[(105.12,116.88)\]
We can accomplish the same thing by correcting the standard deviation by the square root of the sample size and using cdist like before.
cdist("norm", 0.95, plot = FALSE)*3 +111
[1] 105.1201 116.8799
II. A Randomization Approach
We can also simply generate random values from the normal distribution and find the 2.5th and 97.5th percentiles. Try re-running the code block below several times and observe how closely the estimated cutoff values are to \(\pm 1.96\).
qdata(rnorm(500), p=c(0.025, 0.975))
2.5% 97.5%
-1.873852 1.885386
We can create a randomized 95% confidence interval for 25 students. Again, execute the code block several times to see how closely it mirrors the theoretical distribution.
qdata(rnorm(500)*3+111, p=c(0.025, 0.975))
2.5% 97.5%
104.9984 116.1012
III. Why \(t\)-intervals and not \(z\)-intervals
Recall the assumptions for hypothesis tests for the mean of a distribution.
- Normality
- Equal Variances
- Independence of the Observations
The \(z\)-test and \(z\)-interval are often used to show simple examples of a hypothesis testing or creating confidence intervals. Procedures based on the \(z\)-statistic are rarely used in practice because it is quite brittle. In the 1920’s, William Sealy Gossett created the \(t\)-test which provides a more robust statistic, so much so that \(t\)-intervals are almost always used in modern research reports for applications involving normal distributions.
Example 3: \(t\)-interval
Returning to the hypothetical sample of 25 college students with average IQ of 111, let’s assume the sample standard deviation was 9. Find a 95% confidence \(t\)-interval for the mean IQ.
Solution. We can solve for the cutoff values similar to what we did for \(z\), but here \(\sigma\) will be replaced by \(s\). Using the estimate \(s\) rather than the parameter \(\sigma\) makes sense because the population parameters are rarely known in practice.
Degrees of Freedom
The \(t\)-distribution is a series of approximately bell-shaped curves that converge to the normal distribution, so the chosen degrees of freedom selects a particular curve in the series appropriate to our sample size. For this example, \(df = n -1 =24\). Typically, the degrees of freedom for \(t\)-tests is one less than the sample size.
The calculations are very similar.
\[t = \frac{\overline x - \mu}{s / \sqrt{n}}\]
\[\overline x - \mu = t\cdot\frac{\sigma}{\sqrt n} \] We need to calculate the two \(t^*\) cutoff values will be identical distances from the mean, so we add the \(\pm\) and simplify.
\[\mu = \overline x \pm t^*\cdot\frac{\sigma}{\sqrt n} \]
With 24 degrees of freedom, we can use the cdist function to show the situation for the \(t\)-statistic.
cdist("t", df = 24, 0.95)
[1] -2.063899 2.063899

With substitution, we find \[\mu = \overline x \pm 2.06 \cdot \frac{9}{\sqrt{25}} \] which simplifies to \[\mu =111 \pm 2.06 \cdot 1.8 \]
and thus the 95% confidence interval for the mean IQ is \[(107.29,114.71)\]
We can tweak the results of the cdist function like before which confirms our by-hand calculations.
cdist("t", 0.95, df = 24, plot = FALSE)*1.8 + 111
[1] 107.285 114.715
Example 4: Confidence Intervals for the Mean from a Data Frame
Let’s find an estimate for the mean of the Sleep variable in the Data3350 data frame. The assumptions for using \(z\)- and \(t\)-procedures include the normality assumption, so we should first check a histogram.
histogram(~Sleep, data = Data3350)

We have an approximately normal shape but slight skew to the left. Fortunately, the \(t\)-distribution is robust with respect to violations of the normality assumption when the sample size is larger than 40.
favstats(~Sleep, data = Data3350)
Our sample is 146, so the \(t\)-interval estimate should be reasonably accurate.
The Mosaic function confint extracts confidence intervals from hypothesis tests which explains why we’re wrapping it around a \(t\)-test. The particulars of the alternative hypothesis and value for \(\mu_0\) don’t affect the confidence interval estimate, so we leave them off.
confint(t.test(~ Sleep, data = Data3350))
We find that the 95% confidence interval for average Sleep was \((6.03,6.67)\) hours over the previous 48 hours (including naps). College students in this sample are not getting the recommended dosage!
Mosaic’s Randomization Options
- Shuffle. Permutes the values in the sample data.
- Sample. Draws a sub-sample from the sample datawithout replacement.
- Resample. Draws a sub-sample from the sample datawith replacement.
For examples of permutation tests and bootstrapping, see the Randomization Tutorial.
IV. Bootstrapping Approach
Bootstrapping is a randomization technique that allows us to create confidence intervals without assuming we know anything about the distribution. We take random draws from the data set itself using a process called resampling. For details on Bootstrapping see Chapter 3 in Sonderegger & Buscaglia (2020).
Let’s try to understand resampling using the Sleep variable from the Data3350 data frame. We’ll first draw a sample from the observations in Sleep. Note that the draws are with replacement.
temp = resample(Data3350$Sleep, size = 10)
temp
[1] 3.0 9.0 5.5 6.0 6.5 3.0 3.5 10.0 4.0 9.0
We can then then take the mean.
mean(temp)
[1] 5.95
Our plan is to do this hundreds of times while allowing the resample function to choose it’s own sample size. Below, we create a new frame called bootstrap which will keep the means from 500 resamplings.
bootstrap = do(500) * mean(resample(Data3350$Sleep))
bootstrap
Let’s check a density plot to see how our bootstrapping distribution turned out. Remember to re-execute the code blocks directly above and below several times to see what is happening with the bootstrap sampling distribution.
densityplot(~mean, data=bootstrap)

Finally, we use the Mosaic qdata function to find the percentiles of the bootstrapping distribution (or any other distribution we have available). The argument “p=c(0.025, 0.975)” asks for the 2.5th and 97.5th percentiles, so we will have the middle 95% of the distribution.
qdata(~mean, p=c(0.025, 0.975), data=bootstrap)
2.5% 97.5%
6.049924 6.663788
The bootstrapping confidence interval we created using 500 resamples closely approximates what we calculated using the theoretical distribution and can be useful in many situations where we can trust the \(t\)-interval. In practice, we use \(t\)-intervals to estimate means whenever the assumptions are met.
The only assumption required for bootstrapping confidence intervals to work is that the bootstrapping distribution be symmetric. For data which do not meet the requires of \(z\)- and \(t\)- procedures due to small size or lack of normality, we can bootstrap a confidence interval.
Example 5: Confidence Intervals for Proportions.
Consider the variable SitClass from the Data3350 data frame. We see that the options relate to students who prefer sitting in the Front, Middle or Back of class.
tally(~SitClass, data = Data3350)
SitClass
B F M
35 58 72
We can create a 95% confidence interval for, say, those who prefer seats in the front of class. Note that we specify which proportion to estimate by defining “success.” We can use \(z\)-proportion procedures because we have at least 10 successes and 10 failures in our sample (and would for any of these proportions). However, the prop.test function uses \(\chi^2\) for all proportion testing which is even more robust than \(z\). In sum, these data are quite appropriate for this procedure.
confint(prop.test(~SitClass, success = "F", data = Data3350))
We are 95% confident the actual proportion of students who prefer sitting in front is \((28.0\%, 43.0\%)\).
V. Boostrapping for Proportions
We will resample the SitClass observations and place them in temporary storage in the variable seat to show the commands we will use. Notice that the prop function can count a specific level of the category variable.
seat = resample(Data3350$SitClass)
seat
[1] "F" "F" "B" "B" "F" "M" "B" "B" "B" "M" "F" "B" "M" "M" "M" "B" "M"
[18] "B" "M" "F" "F" "M" "M" "B" "M" "F" "F" "B" "M" "M" "B" "M" "F" "M"
[35] "F" "M" "M" "B" "B" "M" "B" "M" "F" "F" "M" "M" "M" "M" "M" "F" "M"
[52] "M" "M" "F" "B" "M" "F" "M" "F" "M" "M" "B" "M" "F" "B" "F" "M" "M"
[69] "B" "M" "M" "B" "M" "M" "M" "F" "F" "M" "F" "M" "M" "M" "M" "F" "M"
[86] "M" "B" "B" "M" "M" "M" "F" "F" "F" "B" "F" "F" "F" "M" "M" "M" "M"
[103] "M" "B" "F" "B" "M" "B" "M" "M" "F" "F" "M" "M" "M" "F" "B" "B" "F"
[120] "M" "F" "M" "F" "B" "B" "M" "F" "F" "M" "M" "F" "M" "F" "F" "F" "M"
[137] "F" "B" "F" "M" "M" "F" "F" "M" "M" "B" "M" "F" "F" "M" "B" "M" "F"
[154] "M" "M" "M" "M" "M" "F" "M" "M" "M" "F" "M" "M"
prop(seat , success = "F")
prop_F
0.3030303
The code block below generates the resamples and immediately checks the proportion that are “F”. The results are stored in a data frame boots with the variable name “prop_F”. The boots distribution is a sample of proportions (or percentages). Execute the code block below several times to visualize what is happening.
boots = do(500) * prop(resample(Data3350$SitClass),success = "F")
histogram(~prop_F, data = boots)

The 95% confidence interval for boots
qdata(~prop_F, p=c(0.025, 0.975), data=boots)
2.5% 97.5%
0.2816667 0.4121212
Once again, the bootstrapping yields a similar confidence interval. For this specific example, the theoretical approach yielded an interval of \((28.0\%, 43.0\%)\).
VI. Hypothesis Testing using Confidence Intervals
Recall the research question from the first example in Module 5: do younger females use less aggressive humor than the overall population? The hypothesis was \[\begin{align*}H_0 &: \mu = 29\\H_a &: \mu < 29\end{align*}\]
Instead of performing a \(t\)-test and generating a \(p\)-value, we can use bootstrapping to estimate the mean of the young female sample and see if \(\mu=29\) is in the interval.
The following two-step subsetting returns the young female sample (\(n = 43\)) in a data frame with only the variable HSAG. These commands are exactly as before except for the na.omit command. There were several empty cells resulting in ages that were unknown in the data frame. The na.omit removes any rows of the data frame where one of the observations is N/A.
fem = subset(Data3350, Sex == "F", c(Age,HSAG))
yF = subset(fem, Age < 20, HSAG)
yFem = na.omit(yF)
yFem
To create a bootstrap distribution, we repeatedly resample the yFem observations, in this case, 500 times.
bootstrap = do(500) * mean (resample(yFem$HSAG))
bootstrap
We need a 90% confidence interval so that the 5th and 95th percentiles of the bootstrap distribution will be the confidence interval endpoints.
qdata(~mean, p=c(0.05, 0.95), data=bootstrap)
5% 95%
24.63026 28.10526
Because \[\mu = 29 \notin (24.2, 28.6)\], we reject the hull hypothesis. We have evidence that young females do indeed use less aggressive humor than the overall population at the \(\alpha = 0.025\) level.
For two-tailed hypothesis tests, we can set \[\alpha = 1 - \text{Confidence Level}\]
For one-tailed hypothesis tests, we must set \[\alpha = 1 - \frac{\text{Confidence Level}}{2}\]
so the areas in the rejection region are identical.
VII. Supplement: How to Change Confidence Level
If we do not specify a confidence level, R defaults to 95%. However, if we specify the parameter conf.level within the \(t\)-test itself, we can change the confidence level. Let’s return to the Sleep variable from the Data3350 data frame. For a baseline, let’s show the 95% confidence interval.
confint(t.test(~ Sleep, data = Data3350))
The 90% confidence interval should be narrower.
confint(t.test(~ Sleep, data = Data3350, conf.level = .9))
We can create a 98% confidence interval. Since our confidence is higher, this interval should be wider than either of the two above.
confint(t.test(~ Sleep, data = Data3350, conf.level = .98))
VIII. Exercises
- How many resamplings should we use when bootstrapping? Try re-running the code blocks from the Sleep example with 50, 100, 500, and 1000 resamplings. How does the accuracy compare to the theoretical confidence interval as number of resamplings increases? Explain why about 500 resamplings is usually good enough.
Code Block: Question 1
bootstrap = do(50) * mean(resample(Data3350$Sleep))
qdata(~mean, p=c(0.025, 0.975), data=bootstrap)
Use the Corps variable in Data3350 where Y / N responses indicate whether the participant’s is in the UNG Corps of Cadets. Assuming the data frame is representative of the UNG Dahlonega campus, create a 90% confidence interval estimate for the percentage of students who are members of the Corps and interpret your findings. Hint: set success = “Y”.
Use the VarsAth variable in Data3350 where Y / N responses indicate whether the participant’s is a varsity UNG athlete. Assuming the data frame is representative of the UNG Dahlonega campus, create a 95% confidence interval estimate for the percentage of students who are varsity athletes and interpret your findings. Hint: set success = “Y”.
Use the TexRel variable in Data3350 where numeric scores represent scores on the Toxic Relationship Beliefs Scale. (Higher scores equate to more toxic beliefs). Assuming the data frame is representative of the UNG Dahlonega campus, create a 99% confidence interval estimate for the mean TxRel score and interpret your findings.
Mosaic’s Randomization Options
- Shuffle. Permutes the values in the sample data.
- Sample. Draws a sub-sample from the sample datawithout replacement.
- Resample. Draws a sub-sample from the sample datawith replacement.
For examples of permutation tests and bootstrapping, see the Randomization Tutorial.
Use the CHS variable in Data3350 where numeric scores represent scores on the Coping Humor Scale. Assuming the data frame is representative of the UNG Dahlonega campus, create a 95% confidence interval estimate for the mean CHS score and interpret your findings.
Use the CHS variable in Data3350 to create a bootstrap confidence interval at the 95% level. Compare and contrast it with the results from the theoretical confidence interval. Use 500 resamplings.
LS0tDQp0aXRsZTogIlN0YXRpc3RpY2FsIEVzdGltYXRpb24iDQpzdWJ0aXRsZTogVU5HIE1BVEggMzM1MCAob25saW5lKQ0KYXV0aG9yOiBSb2JiIFNpbm4NCmRhdGU6IEp1bHkgMjAyMA0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+SS4gQ29uZmlkZW5jZSBJbnRlcnZhbHM8L3NwYW4+DQoNCldoZW4gY29uZHVjdGluZyBleHBsb3JhdG9yeSBkYXRhIGFuYWx5c2lzLCB3ZSBvZnRlbiB3aXNoIHRvIGVzdGltYXRlIHBhcmFtZXRlcnMgbGlrZSB0aGUgbWVhbiBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uIGZvciBudW1lcmljIGRhdGEsIG9yIGEgcHJvcG9ydGlvbiBmb3IgY2F0ZWdvcnkgZGF0YS4gU3RhdGlzdGljaWFucyBwcmVmZXIgaW50ZXJ2YWwgZXN0aW1hdGVzIHRvIHBvaW50IGVzdGltYXRlcy4gVGhvdWdoIHRoZSBjb25maWRlbmNlIGludGVydmFsIGdpdmVzIGxlc3MgYXBwYXJlbnQgcHJlY2lzaW9uLCB0aGUgcmFuZ2Ugb2YgdmFsdWVzIGNhbiBiZSBjb25zdHJ1Y3RlZCBzbyB0aGF0IHRoZXJlIGlzIGhpZ2ggbGlrZWxpaG9vZCB0aGUgYWN0dWFsIHBhcmFtZXRlciBpcyB3aXRoaW4gdGhhdCByYW5nZS4NCg0KVHJhZGl0aW9uYWwgY29uZmlkZW5jZSBpbnRlcnZhbHMgdXNlIGEgdGhlb3JldGljYWwgZGlzdHJpYnV0aW9uIGxpa2UgdGhlIG5vcm1hbCBkaXN0cmlidXRpb24gb3IgJHQkLWRpc3RyaWJ1dGlvbi4gRm9yIGEgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwsIHR3byBjdXRvZmYgdmFsdWVzIGFyZSBjYWxjdWxhdGVkLCBvbmUgbGVmdCBhbmQgb25lIHJpZ2h0LCB0aGF0IHdpbGwgY2FwdHVyZSBleGFjdGx5IDk1JSBvZiB0aGUgdGhlb3JldGljYWwgZGlzdHJpYnV0aW9uIGJldHdlZW4gdGhlbS4NCg0KPGRpdiBzdHlsZT0iZmxvYXQ6cmlnaHQ7IG1hcmdpbjogOHB4OyBib3JkZXI6MnB4IGJsYWNrIHNvbGlkOyBwYWRkaW5nOiAwcHggMTBweCA1cHgiPg0KIyMjIDxzcGFuIHN0eWxlPSJjb2xvcjogcmVkOyI+SW5pdGlhbGl6aW5nIFJTdHVkaW88L3NwYW4+DQpUaGUgZGF0YSBzZXQgd2Ugd2lsbCB1c2UgcHJpbWFyaWx5IGlzICoqRGF0YTMzNTAqKiB3aGljaCB3YXMgcHJvZHVjZWQgaW4gMjAxNSBkdXJpbmcgYW4gdW5kZXJncmFkdWF0ZSByZXNlYXJjaCBwcm9qZWN0IGFib3V0IHBlcnNvbmFsaXR5IGFuZCBodW1vci4gVGhlICoqVmFyc0RhdGEzMzUwKiogUERGIGZpbGUgaGFzIGRlc2NyaXB0aW9ucyBvZiBlYWNoIHZhcmlhYmxlIGluIHRoZSBEYXRhMzM1MCBmaWxlLiBCb3RoIGFyZSBhdmFpbGFibGUgZm9yIGRvd25sb2FkIGluIEQyTC4gQmUgc3VyZSB0byBwdXQgdGhlIERhdGEzMzUwIGluIHlvdXIgUiBmb2xkZXIgaW4gRG9jdW1lbnRzLCBhbmQgbWFrZSBzdXJlIHlvdXIgd29ya2luZyBkaXJlY3RvcnkgaXMgc2V0IHRoZSBzYW1lIHdheSAoU2Vzc2lvbiBtZW51KS4gVGhlIGNvZGUgYmxvY2sgYmVsb3cgdXNlcyB0aGUgKipsaWJyYXJ5KiogZnVuY3Rpb24gdG8gZW5zdXJlIHRoYXQgdGhlICoqTW9zYWljKiogcGFja2FnZSBpcyBsb2FkZWQgYW5kIHdpbGwgaW1wb3J0IHRoZSBkYXRhIGZyYW1lIHVzZWQgaW4gdGhpcyBtb2R1bGU6ICoqRGF0YTMzNTAqKi4NCg0KYGBge3J9DQpsaWJyYXJ5KG1vc2FpYykNCmxpYnJhcnkocmVhZHhsKQ0KRGF0YTMzNTAgPSByZWFkX2V4Y2VsKCJEYXRhMzM1MC54bHN4IikNCmBgYA0KPC9kaXY+DQoNCiMjIEV4YW1wbGU6IElRIFNjb3Jlcw0KDQoqKlF1ZXN0aW9uLioqIEh1bWFuIElRJ3MgaGF2ZSB0aGUgJE4oMTAwLDE1KSQgZGlzdHJpYnV0aW9uLiBGaW5kIGEgc3ltbWV0cmljIGludGVydmFsIGFib3V0IHRoZSBtZWFuIHRoYXQgY2FwdHVyZXMgZXhhY3RseSA5NSUgb2YgdGhlIElRIGRpc3RyaWJ1dGlvbi4NCg0KVGhlICoqbW9zYWljKiogZnVuY3Rpb24gKipjZGlzdCoqIGZpbmRzIHRoZSAiY2VudGVyIG9mIHRoZSBkaXN0cmlidXRpb24uIFdlIGNhbiBzcGVjaWZ5IHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uIGFuZCB0aGUgbGV2ZWwgb2YgY29uZmlkZW5jZS4NCg0KYGBge3J9DQpjZGlzdCgibm9ybSIsIDAuOTUpDQpgYGANCg0KV2Uga25vdyB0aGF0IHRoZSB0d28gY3V0b2ZmIHZhbHVlcyB3aWxsIGxpZSBleGFjdGx5IDEuOTYgc3RhbmRhcmQgZGV2aWF0aW9ucyBhYm92ZSBvciBiZWxvdyB0aGUgbWVhbi4gV2UgY2FuIHRoZSAqKmNkaXN0KiogZnVuY3Rpb24gZG8gdGhlIGFyaXRobWV0aWMgZm9yIHVzIGJ5IG11bHRpcGx5aW5nIHRoZSBjdXRvZmYgdmFsdWVzIGJ5IHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gYW5kIGFkZGluZyB0aGUgcG9wdWxhdGlvbiBtZWFuLg0KDQoNCmBgYHtyfQ0KY2Rpc3QoIm5vcm0iLCAwLjk1ICwgcGxvdCA9IEZBTFNFKSoxNSsxMDANCmBgYA0KDQpXZSBrbm93IHRoYXQgOTUlIG9mIGh1bWFuIElRJ3Mgd2lsbCBmYWxsIGJldHdlZW4gNzAuNiBhbmQgMTI5LjQuDQoNCiMjIEV4YW1wbGUgMjogU2FtcGxlIG9mIFN0dWRlbnQgSVEncw0KDQpJbiBhIHNhbXBsZSBvZiAyNSBjb2xsZWdlIHN0dWRlbnRzLCB0aGUgYXZlcmFnZSBJUSB3YXMgMTExLiBGaW5kIGEgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgZm9yIHRoZSBtZWFuIElRLg0KDQoqKlNvbHV0aW9uLioqIFdlIGNhbiBzb2x2ZSB0aGUgJHokLXN0YXRpc3RpYyBmb3JtdWxhIGZvciAkel4qJCwgdGhlIGN1dG9mZiB2YWx1ZXMuDQoNCiQkeiA9IFxmcmFje1xvdmVybGluZSB4IC0gXG11fXtcc2lnbWEgLyBcc3FydHtufX0kJA0KJCRcb3ZlcmxpbmUgeCAtIFxtdSA9IHpcY2RvdFxmcmFje1xzaWdtYX17XHNxcnQgbn0gJCQNCldlIG5lZWQgdG8gY2FsY3VsYXRlIHRoZSB0d28gJHpeKiQgY3V0b2ZmIHZhbHVlcyB3aWxsIGJlIGlkZW50aWNhbCBkaXN0YW5jZXMgZnJvbSB0aGUgbWVhbiwgc28gd2UgYWRkIHRoZSAkXHBtJCBhbmQgc2ltcGxpZnkuDQoNCiQkXG11ID0gXG92ZXJsaW5lIHggXHBtIHpeKlxjZG90XGZyYWN7XHNpZ21hfXtcc3FydCBufSAkJA0KSGVyZSwgJHpeKiA9IFxwbSAxLjk2JCwgc28gd2UgY2FuIHN1YnN0aXR1dGUNCg0KJCRcbXUgPSAxMTEgXHBtIDEuOTZcY2RvdFxmcmFjezE1fXtcc3FydCB7MjV9fSAkJA0KYW5kIGZpbmQgdGhlIHR3byBjdXRvZmYgdmFsdWVzLg0KDQokJFxtdSA9IDExMSBccG0gKDMpIDEuOTYgPTExMSBccG0gNS44OCAkJA0KVGh1cywgdGhlIDk1JSBjb25maWRlbmNlIGludGVydmFsIGZvciB0aGUgbWVhbiBvZiB0aGVzZSAyNSBjb2xsZWdlIHN0dWRlbnRzIGlzICQkKDEwNS4xMiwxMTYuODgpJCQNCg0KV2UgY2FuIGFjY29tcGxpc2ggdGhlIHNhbWUgdGhpbmcgYnkgY29ycmVjdGluZyB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uIGJ5IHRoZSBzcXVhcmUgcm9vdCBvZiB0aGUgc2FtcGxlIHNpemUgYW5kIHVzaW5nICoqY2Rpc3QqKiBsaWtlIGJlZm9yZS4NCg0KYGBge3J9DQpjZGlzdCgibm9ybSIsIDAuOTUsIHBsb3QgPSBGQUxTRSkqMyArMTExDQpgYGANCg0KDQojIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPklJLiBBIFJhbmRvbWl6YXRpb24gQXBwcm9hY2g8L3NwYW4+DQoNCldlIGNhbiBhbHNvIHNpbXBseSBnZW5lcmF0ZSByYW5kb20gdmFsdWVzIGZyb20gdGhlIG5vcm1hbCBkaXN0cmlidXRpb24gYW5kIGZpbmQgdGhlIDIuNXRoIGFuZCA5Ny41dGggcGVyY2VudGlsZXMuIFRyeSByZS1ydW5uaW5nIHRoZSBjb2RlIGJsb2NrIGJlbG93IHNldmVyYWwgdGltZXMgYW5kIG9ic2VydmUgaG93IGNsb3NlbHkgdGhlIGVzdGltYXRlZCBjdXRvZmYgdmFsdWVzIGFyZSB0byAkXHBtIDEuOTYkLg0KDQpgYGB7cn0NCnFkYXRhKHJub3JtKDUwMCksIHA9YygwLjAyNSwgMC45NzUpKQ0KYGBgDQoNCldlIGNhbiBjcmVhdGUgYSByYW5kb21pemVkIDk1JSBjb25maWRlbmNlIGludGVydmFsIGZvciAyNSBzdHVkZW50cy4gQWdhaW4sIGV4ZWN1dGUgdGhlIGNvZGUgYmxvY2sgc2V2ZXJhbCB0aW1lcyB0byBzZWUgaG93IGNsb3NlbHkgaXQgbWlycm9ycyB0aGUgdGhlb3JldGljYWwgZGlzdHJpYnV0aW9uLg0KDQpgYGB7cn0NCnFkYXRhKHJub3JtKDUwMCkqMysxMTEsIHA9YygwLjAyNSwgMC45NzUpKQ0KYGBgDQoNCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+SUlJLiAgV2h5ICR0JC1pbnRlcnZhbHMgYW5kIG5vdCAkeiQtaW50ZXJ2YWxzPC9zcGFuPg0KDQpSZWNhbGwgdGhlIGFzc3VtcHRpb25zIGZvciBoeXBvdGhlc2lzIHRlc3RzIGZvciB0aGUgbWVhbiBvZiBhIGRpc3RyaWJ1dGlvbi4NCg0KMS4gTm9ybWFsaXR5DQoyLiBFcXVhbCBWYXJpYW5jZXMNCjMuIEluZGVwZW5kZW5jZSBvZiB0aGUgT2JzZXJ2YXRpb25zDQoNClRoZSAkeiQtdGVzdCBhbmQgJHokLWludGVydmFsIGFyZSBvZnRlbiB1c2VkIHRvIHNob3cgc2ltcGxlIGV4YW1wbGVzIG9mIGEgaHlwb3RoZXNpcyB0ZXN0aW5nIG9yIGNyZWF0aW5nIGNvbmZpZGVuY2UgaW50ZXJ2YWxzLiBQcm9jZWR1cmVzIGJhc2VkIG9uIHRoZSAkeiQtc3RhdGlzdGljIGFyZSByYXJlbHkgdXNlZCAgaW4gcHJhY3RpY2UgYmVjYXVzZSBpdCBpcyBxdWl0ZSBicml0dGxlLiBJbiB0aGUgMTkyMCdzLCBXaWxsaWFtIFNlYWx5IEdvc3NldHQgY3JlYXRlZCB0aGUgJHQkLXRlc3Qgd2hpY2ggcHJvdmlkZXMgYSBtb3JlIHJvYnVzdCBzdGF0aXN0aWMsIHNvIG11Y2ggc28gdGhhdCAkdCQtaW50ZXJ2YWxzIGFyZSBhbG1vc3QgYWx3YXlzIHVzZWQgaW4gbW9kZXJuIHJlc2VhcmNoIHJlcG9ydHMgZm9yIGFwcGxpY2F0aW9ucyBpbnZvbHZpbmcgbm9ybWFsIGRpc3RyaWJ1dGlvbnMuDQoNCiMjIEV4YW1wbGUgMzogJHQkLWludGVydmFsDQoNClJldHVybmluZyB0byB0aGUgaHlwb3RoZXRpY2FsIHNhbXBsZSBvZiAyNSBjb2xsZWdlIHN0dWRlbnRzIHdpdGggYXZlcmFnZSBJUSBvZiAxMTEsIGxldCdzIGFzc3VtZSB0aGUgc2FtcGxlIHN0YW5kYXJkIGRldmlhdGlvbiB3YXMgOS4gRmluZCBhIDk1JSBjb25maWRlbmNlICR0JC1pbnRlcnZhbCBmb3IgdGhlIG1lYW4gSVEuDQoNCioqU29sdXRpb24uKiogV2UgY2FuIHNvbHZlIGZvciB0aGUgY3V0b2ZmIHZhbHVlcyBzaW1pbGFyIHRvIHdoYXQgd2UgZGlkIGZvciAkeiQsIGJ1dCBoZXJlICRcc2lnbWEkIHdpbGwgYmUgcmVwbGFjZWQgYnkgJHMkLiBVc2luZyB0aGUgZXN0aW1hdGUgJHMkIHJhdGhlciB0aGFuIHRoZSBwYXJhbWV0ZXIgJFxzaWdtYSQgbWFrZXMgc2Vuc2UgYmVjYXVzZSB0aGUgcG9wdWxhdGlvbiBwYXJhbWV0ZXJzIGFyZSByYXJlbHkga25vd24gaW4gcHJhY3RpY2UuIA0KDQojIyMgRGVncmVlcyBvZiBGcmVlZG9tDQoNClRoZSAkdCQtZGlzdHJpYnV0aW9uIGlzIGEgc2VyaWVzIG9mIGFwcHJveGltYXRlbHkgYmVsbC1zaGFwZWQgY3VydmVzIHRoYXQgY29udmVyZ2UgdG8gdGhlIG5vcm1hbCBkaXN0cmlidXRpb24sIHNvIHRoZSBjaG9zZW4gIGRlZ3JlZXMgb2YgZnJlZWRvbSBzZWxlY3RzIGEgcGFydGljdWxhciBjdXJ2ZSBpbiB0aGUgc2VyaWVzIGFwcHJvcHJpYXRlIHRvIG91ciBzYW1wbGUgc2l6ZS4gRm9yIHRoaXMgZXhhbXBsZSwgJGRmID0gbiAtMSA9MjQkLiBUeXBpY2FsbHksIHRoZSBkZWdyZWVzIG9mIGZyZWVkb20gZm9yICR0JC10ZXN0cyBpcyBvbmUgbGVzcyB0aGFuIHRoZSBzYW1wbGUgc2l6ZS4NCg0KVGhlIGNhbGN1bGF0aW9ucyBhcmUgdmVyeSBzaW1pbGFyLg0KDQokJHQgPSBcZnJhY3tcb3ZlcmxpbmUgeCAtIFxtdX17cyAvIFxzcXJ0e259fSQkDQoNCiQkXG92ZXJsaW5lIHggLSBcbXUgPSB0XGNkb3RcZnJhY3tcc2lnbWF9e1xzcXJ0IG59ICQkDQpXZSBuZWVkIHRvIGNhbGN1bGF0ZSB0aGUgdHdvICR0XiokIGN1dG9mZiB2YWx1ZXMgd2lsbCBiZSBpZGVudGljYWwgZGlzdGFuY2VzIGZyb20gdGhlIG1lYW4sIHNvIHdlIGFkZCB0aGUgJFxwbSQgYW5kIHNpbXBsaWZ5Lg0KDQokJFxtdSA9IFxvdmVybGluZSB4IFxwbSB0XipcY2RvdFxmcmFje1xzaWdtYX17XHNxcnQgbn0gJCQNCg0KV2l0aCAyNCBkZWdyZWVzIG9mIGZyZWVkb20sIHdlIGNhbiB1c2UgdGhlICoqY2Rpc3QqKiBmdW5jdGlvbiB0byBzaG93IHRoZSBzaXR1YXRpb24gZm9yIHRoZSAkdCQtc3RhdGlzdGljLg0KDQpgYGB7cn0NCmNkaXN0KCJ0IiwgZGYgPSAyNCwgMC45NSkNCmBgYA0KDQpXaXRoIHN1YnN0aXR1dGlvbiwgd2UgZmluZA0KJCRcbXUgPSBcb3ZlcmxpbmUgeCBccG0gMi4wNiBcY2RvdCBcZnJhY3s5fXtcc3FydHsyNX19ICQkDQp3aGljaCBzaW1wbGlmaWVzIHRvDQokJFxtdSA9MTExIFxwbSAyLjA2IFxjZG90IDEuOCAkJA0KDQphbmQgdGh1cyB0aGUgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgZm9yIHRoZSBtZWFuIElRIGlzDQokJCgxMDcuMjksMTE0LjcxKSQkDQoNCldlIGNhbiB0d2VhayB0aGUgcmVzdWx0cyBvZiB0aGUgKipjZGlzdCoqIGZ1bmN0aW9uIGxpa2UgYmVmb3JlIHdoaWNoIGNvbmZpcm1zIG91ciBieS1oYW5kIGNhbGN1bGF0aW9ucy4NCg0KYGBge3J9DQpjZGlzdCgidCIsIDAuOTUsIGRmID0gMjQsIHBsb3QgPSBGQUxTRSkqMS44ICsgMTExDQpgYGANCg0KIyMgRXhhbXBsZSA0OiBDb25maWRlbmNlIEludGVydmFscyBmb3IgdGhlIE1lYW4gZnJvbSBhIERhdGEgRnJhbWUNCg0KTGV0J3MgZmluZCBhbiBlc3RpbWF0ZSBmb3IgdGhlIG1lYW4gb2YgdGhlIFNsZWVwIHZhcmlhYmxlIGluIHRoZSBEYXRhMzM1MCBkYXRhIGZyYW1lLiBUaGUgYXNzdW1wdGlvbnMgZm9yIHVzaW5nICR6JC0gYW5kICR0JC1wcm9jZWR1cmVzIGluY2x1ZGUgdGhlIG5vcm1hbGl0eSBhc3N1bXB0aW9uLCBzbyB3ZSBzaG91bGQgZmlyc3QgY2hlY2sgYSBoaXN0b2dyYW0uDQoNCmBgYHtyfQ0KaGlzdG9ncmFtKH5TbGVlcCwgZGF0YSA9IERhdGEzMzUwKQ0KYGBgDQpXZSBoYXZlIGFuIGFwcHJveGltYXRlbHkgbm9ybWFsIHNoYXBlIGJ1dCBzbGlnaHQgc2tldyB0byB0aGUgbGVmdC4gRm9ydHVuYXRlbHksIHRoZSAkdCQtZGlzdHJpYnV0aW9uIGlzIHJvYnVzdCB3aXRoIHJlc3BlY3QgdG8gdmlvbGF0aW9ucyBvZiB0aGUgbm9ybWFsaXR5IGFzc3VtcHRpb24gd2hlbiB0aGUgc2FtcGxlIHNpemUgaXMgbGFyZ2VyIHRoYW4gNDAuDQoNCmBgYHtyfQ0KZmF2c3RhdHMoflNsZWVwLCBkYXRhID0gRGF0YTMzNTApDQpgYGANCk91ciBzYW1wbGUgaXMgMTQ2LCBzbyB0aGUgJHQkLWludGVydmFsIGVzdGltYXRlIHNob3VsZCBiZSByZWFzb25hYmx5IGFjY3VyYXRlLg0KDQpUaGUgTW9zYWljIGZ1bmN0aW9uICoqY29uZmludCoqIGV4dHJhY3RzIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGZyb20gaHlwb3RoZXNpcyB0ZXN0cyB3aGljaCBleHBsYWlucyB3aHkgd2UncmUgd3JhcHBpbmcgaXQgYXJvdW5kIGEgJHQkLXRlc3QuIFRoZSBwYXJ0aWN1bGFycyBvZiB0aGUgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcyBhbmQgdmFsdWUgZm9yICRcbXVfMCQgZG9uJ3QgYWZmZWN0IHRoZSBjb25maWRlbmNlIGludGVydmFsIGVzdGltYXRlLCBzbyB3ZSBsZWF2ZSB0aGVtIG9mZi4NCg0KYGBge3J9DQpjb25maW50KHQudGVzdCh+IFNsZWVwLCBkYXRhID0gRGF0YTMzNTApKQ0KYGBgDQoNCldlIGZpbmQgdGhhdCB0aGUgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgZm9yIGF2ZXJhZ2UgU2xlZXAgd2FzICQoNi4wMyw2LjY3KSQgaG91cnMgb3ZlciB0aGUgcHJldmlvdXMgNDggaG91cnMgKGluY2x1ZGluZyBuYXBzKS4gQ29sbGVnZSBzdHVkZW50cyBpbiB0aGlzIHNhbXBsZSBhcmUgbm90IGdldHRpbmcgdGhlIHJlY29tbWVuZGVkIGRvc2FnZSENCg0KPGRpdiBzdHlsZT0iZmxvYXQ6cmlnaHQ7IG1hcmdpbjogOHB4OyBib3JkZXI6MnB4IGJsYWNrIHNvbGlkOyBwYWRkaW5nOiAxMHB4IDE1cHggMTBweCI+DQojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiByZWQ7Ij5Nb3NhaWMncyBSYW5kb21pemF0aW9uIE9wdGlvbnM8L3NwYW4+DQoxLiAqKlNodWZmbGUuKiogUGVybXV0ZXMgdGhlIHZhbHVlcyBpbiB0aGUgc2FtcGxlIGRhdGEuDQoyLiAqKlNhbXBsZS4qKiBEcmF3cyBhIHN1Yi1zYW1wbGUgZnJvbSB0aGUgc2FtcGxlIGRhdGE8L2JyPip3aXRob3V0IHJlcGxhY2VtZW50Ki4NCjMuICoqUmVzYW1wbGUuKiogRHJhd3MgYSBzdWItc2FtcGxlIGZyb20gdGhlIHNhbXBsZSBkYXRhPC9icj4qd2l0aCByZXBsYWNlbWVudCouPC9icj4NCg0KRm9yIGV4YW1wbGVzIG9mIHBlcm11dGF0aW9uIHRlc3RzIGFuZCBib290c3RyYXBwaW5nLCBzZWU8L2JyPg0KdGhlIDxhIGhyZWYgPSBodHRwczovL3JwdWJzLmNvbS9yb2Jic2lubi9zMTE+UmFuZG9taXphdGlvbiBUdXRvcmlhbDwvYT4uDQo8L2Rpdj4NCg0KIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsdWU7Ij5JVi4gIEJvb3RzdHJhcHBpbmcgQXBwcm9hY2g8L3NwYW4+DQoNCkJvb3RzdHJhcHBpbmcgaXMgYSAqKnJhbmRvbWl6YXRpb24qKiB0ZWNobmlxdWUgdGhhdCBhbGxvd3MgdXMgdG8gY3JlYXRlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIHdpdGhvdXQgYXNzdW1pbmcgd2Uga25vdyBhbnl0aGluZyBhYm91dCB0aGUgZGlzdHJpYnV0aW9uLiBXZSB0YWtlIHJhbmRvbSBkcmF3cyBmcm9tIHRoZSBkYXRhIHNldCBpdHNlbGYgdXNpbmcgYSBwcm9jZXNzIGNhbGxlZCByZXNhbXBsaW5nLiBGb3IgZGV0YWlscyBvbiBCb290c3RyYXBwaW5nIHNlZSBDaGFwdGVyIDMgaW4gPGEgaHJlZiA9IGh0dHBzOi8vZGVyZWtzb25kZXJlZ2dlci5naXRodWIuaW8vNTcwLzMtY29uZmlkZW5jZS1pbnRlcnZhbHMtdmlhLWJvb3RzdHJhcHBpbmcuaHRtbD4gU29uZGVyZWdnZXIgJiBCdXNjYWdsaWEgKDIwMjApPC9hPi4gDQoNCkxldCdzIHRyeSB0byB1bmRlcnN0YW5kIHJlc2FtcGxpbmcgdXNpbmcgdGhlICoqU2xlZXAqKiB2YXJpYWJsZSBmcm9tIHRoZSBEYXRhMzM1MCBkYXRhIGZyYW1lLiBXZSdsbCBmaXJzdCBkcmF3IGEgc2FtcGxlIGZyb20gdGhlIG9ic2VydmF0aW9ucyBpbiAqKlNsZWVwKiouIE5vdGUgdGhhdCB0aGUgZHJhd3MgYXJlIHdpdGggcmVwbGFjZW1lbnQuDQoNCmBgYHtyfQ0KdGVtcCA9IHJlc2FtcGxlKERhdGEzMzUwJFNsZWVwLCBzaXplID0gMTApDQp0ZW1wDQpgYGANCg0KV2UgY2FuIHRoZW4gdGhlbiB0YWtlIHRoZSBtZWFuLg0KDQpgYGB7cn0NCm1lYW4odGVtcCkNCmBgYA0KDQpPdXIgcGxhbiBpcyB0byBkbyB0aGlzIGh1bmRyZWRzIG9mIHRpbWVzIHdoaWxlIGFsbG93aW5nIHRoZSByZXNhbXBsZSBmdW5jdGlvbiB0byBjaG9vc2UgaXQncyBvd24gc2FtcGxlIHNpemUuIEJlbG93LCB3ZSBjcmVhdGUgYSBuZXcgZnJhbWUgY2FsbGVkICoqYm9vdHN0cmFwKiogd2hpY2ggd2lsbCBrZWVwIHRoZSBtZWFucyBmcm9tIDUwMCByZXNhbXBsaW5ncy4NCg0KYGBge3J9DQpib290c3RyYXAgPSBkbyg1MDApICogbWVhbihyZXNhbXBsZShEYXRhMzM1MCRTbGVlcCkpDQpib290c3RyYXANCmBgYA0KDQpMZXQncyBjaGVjayBhIGRlbnNpdHkgcGxvdCB0byBzZWUgaG93IG91ciBib290c3RyYXBwaW5nIGRpc3RyaWJ1dGlvbiB0dXJuZWQgb3V0LiBSZW1lbWJlciB0byByZS1leGVjdXRlIHRoZSBjb2RlIGJsb2NrcyBkaXJlY3RseSBhYm92ZSBhbmQgYmVsb3cgc2V2ZXJhbCB0aW1lcyB0byBzZWUgd2hhdCBpcyBoYXBwZW5pbmcgd2l0aCB0aGUgYm9vdHN0cmFwIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbi4NCg0KYGBge3J9DQpkZW5zaXR5cGxvdCh+bWVhbiwgZGF0YT1ib290c3RyYXApDQpgYGANCg0KRmluYWxseSwgd2UgdXNlIHRoZSBNb3NhaWMgKipxZGF0YSoqIGZ1bmN0aW9uIHRvIGZpbmQgdGhlIHBlcmNlbnRpbGVzIG9mIHRoZSBib290c3RyYXBwaW5nIGRpc3RyaWJ1dGlvbiAob3IgYW55IG90aGVyIGRpc3RyaWJ1dGlvbiB3ZSBoYXZlIGF2YWlsYWJsZSkuIFRoZSBhcmd1bWVudCAicD1jKDAuMDI1LCAwLjk3NSkiIGFza3MgZm9yIHRoZSAyLjV0aCBhbmQgOTcuNXRoIHBlcmNlbnRpbGVzLCBzbyB3ZSB3aWxsIGhhdmUgdGhlIG1pZGRsZSA5NSUgb2YgdGhlIGRpc3RyaWJ1dGlvbi4NCg0KDQpgYGB7cn0NCnFkYXRhKH5tZWFuLCBwPWMoMC4wMjUsIDAuOTc1KSwgZGF0YT1ib290c3RyYXApDQpgYGANCg0KVGhlIGJvb3RzdHJhcHBpbmcgY29uZmlkZW5jZSBpbnRlcnZhbCB3ZSBjcmVhdGVkIHVzaW5nIDUwMCByZXNhbXBsZXMgY2xvc2VseSBhcHByb3hpbWF0ZXMgd2hhdCB3ZSBjYWxjdWxhdGVkIHVzaW5nIHRoZSB0aGVvcmV0aWNhbCBkaXN0cmlidXRpb24gYW5kIGNhbiBiZSB1c2VmdWwgaW4gbWFueSBzaXR1YXRpb25zIHdoZXJlIHdlIGNhbiB0cnVzdCB0aGUgJHQkLWludGVydmFsLiBJbiBwcmFjdGljZSwgd2UgdXNlICR0JC1pbnRlcnZhbHMgdG8gZXN0aW1hdGUgbWVhbnMgd2hlbmV2ZXIgdGhlIGFzc3VtcHRpb25zIGFyZSBtZXQuIA0KDQpUaGUgb25seSBhc3N1bXB0aW9uIHJlcXVpcmVkIGZvciBib290c3RyYXBwaW5nIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIHRvIHdvcmsgaXMgdGhhdCB0aGUgYm9vdHN0cmFwcGluZyBkaXN0cmlidXRpb24gYmUgc3ltbWV0cmljLiBGb3IgZGF0YSB3aGljaCBkbyBub3QgbWVldCB0aGUgcmVxdWlyZXMgb2YgJHokLSBhbmQgJHQkLSBwcm9jZWR1cmVzIGR1ZSB0byBzbWFsbCBzaXplIG9yIGxhY2sgb2Ygbm9ybWFsaXR5LCB3ZSBjYW4gYm9vdHN0cmFwIGEgY29uZmlkZW5jZSBpbnRlcnZhbC4NCg0KDQojIyBFeGFtcGxlIDU6IENvbmZpZGVuY2UgSW50ZXJ2YWxzIGZvciBQcm9wb3J0aW9ucy4NCg0KQ29uc2lkZXIgdGhlIHZhcmlhYmxlICoqU2l0Q2xhc3MqKiBmcm9tIHRoZSBEYXRhMzM1MCBkYXRhIGZyYW1lLiBXZSBzZWUgdGhhdCB0aGUgb3B0aW9ucyByZWxhdGUgdG8gc3R1ZGVudHMgd2hvIHByZWZlciBzaXR0aW5nIGluIHRoZSBGcm9udCwgTWlkZGxlIG9yIEJhY2sgb2YgY2xhc3MuDQoNCmBgYHtyfQ0KdGFsbHkoflNpdENsYXNzLCBkYXRhID0gRGF0YTMzNTApDQpgYGANCg0KV2UgY2FuIGNyZWF0ZSBhIDk1JSBjb25maWRlbmNlIGludGVydmFsIGZvciwgc2F5LCB0aG9zZSB3aG8gcHJlZmVyIHNlYXRzIGluIHRoZSBmcm9udCBvZiBjbGFzcy4gTm90ZSB0aGF0IHdlIHNwZWNpZnkgd2hpY2ggcHJvcG9ydGlvbiB0byBlc3RpbWF0ZSBieSBkZWZpbmluZyAic3VjY2Vzcy4iIFdlIGNhbiB1c2UgJHokLXByb3BvcnRpb24gcHJvY2VkdXJlcyBiZWNhdXNlIHdlIGhhdmUgYXQgbGVhc3QgMTAgc3VjY2Vzc2VzIGFuZCAxMCBmYWlsdXJlcyBpbiBvdXIgc2FtcGxlIChhbmQgd291bGQgZm9yIGFueSBvZiB0aGVzZSBwcm9wb3J0aW9ucykuIEhvd2V2ZXIsIHRoZSAqKnByb3AudGVzdCoqIGZ1bmN0aW9uIHVzZXMgJFxjaGleMiQgZm9yIGFsbCBwcm9wb3J0aW9uIHRlc3Rpbmcgd2hpY2ggaXMgZXZlbiBtb3JlIHJvYnVzdCB0aGFuICR6JC4gSW4gc3VtLCB0aGVzZSBkYXRhIGFyZSBxdWl0ZSBhcHByb3ByaWF0ZSBmb3IgdGhpcyBwcm9jZWR1cmUuDQoNCmBgYHtyfQ0KY29uZmludChwcm9wLnRlc3QoflNpdENsYXNzLCBzdWNjZXNzID0gIkYiLCBkYXRhID0gRGF0YTMzNTApKQ0KYGBgDQoNCldlIGFyZSA5NSUgY29uZmlkZW50IHRoZSBhY3R1YWwgcHJvcG9ydGlvbiBvZiBzdHVkZW50cyB3aG8gcHJlZmVyIHNpdHRpbmcgaW4gZnJvbnQgaXMgJCgyOC4wXCUsIDQzLjBcJSkkLg0KDQojIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPlYuIEJvb3N0cmFwcGluZyBmb3IgUHJvcG9ydGlvbnM8L3NwYW4+DQoNCldlIHdpbGwgcmVzYW1wbGUgdGhlIFNpdENsYXNzIG9ic2VydmF0aW9ucyBhbmQgcGxhY2UgdGhlbSBpbiB0ZW1wb3Jhcnkgc3RvcmFnZSBpbiB0aGUgdmFyaWFibGUgKipzZWF0KiogdG8gc2hvdyB0aGUgY29tbWFuZHMgd2Ugd2lsbCB1c2UuIE5vdGljZSB0aGF0IHRoZSAqKnByb3AqKiBmdW5jdGlvbiBjYW4gY291bnQgYSBzcGVjaWZpYyBsZXZlbCBvZiB0aGUgY2F0ZWdvcnkgdmFyaWFibGUuDQoNCmBgYHtyfQ0Kc2VhdCA9IHJlc2FtcGxlKERhdGEzMzUwJFNpdENsYXNzKQ0Kc2VhdA0KcHJvcChzZWF0ICwgc3VjY2VzcyA9ICJGIikNCmBgYA0KDQpUaGUgY29kZSBibG9jayBiZWxvdyBnZW5lcmF0ZXMgdGhlIHJlc2FtcGxlcyBhbmQgaW1tZWRpYXRlbHkgY2hlY2tzIHRoZSBwcm9wb3J0aW9uIHRoYXQgYXJlICJGIi4gVGhlIHJlc3VsdHMgYXJlIHN0b3JlZCBpbiBhIGRhdGEgZnJhbWUgKipib290cyoqIHdpdGggdGhlIHZhcmlhYmxlIG5hbWUgInByb3BfRiIuIFRoZSAqKmJvb3RzKiogZGlzdHJpYnV0aW9uIGlzIGEgc2FtcGxlIG9mIHByb3BvcnRpb25zIChvciBwZXJjZW50YWdlcykuIEV4ZWN1dGUgdGhlIGNvZGUgYmxvY2sgYmVsb3cgc2V2ZXJhbCB0aW1lcyB0byB2aXN1YWxpemUgd2hhdCBpcyBoYXBwZW5pbmcuDQoNCmBgYHtyfQ0KYm9vdHMgPSBkbyg1MDApICogcHJvcChyZXNhbXBsZShEYXRhMzM1MCRTaXRDbGFzcyksc3VjY2VzcyA9ICJGIikNCmhpc3RvZ3JhbSh+cHJvcF9GLCBkYXRhID0gYm9vdHMpDQpgYGANCg0KVGhlIDk1JSBjb25maWRlbmNlIGludGVydmFsIGZvciAqKmJvb3RzKioNCg0KYGBge3J9DQpxZGF0YSh+cHJvcF9GLCBwPWMoMC4wMjUsIDAuOTc1KSwgZGF0YT1ib290cykNCmBgYA0KDQpPbmNlIGFnYWluLCB0aGUgYm9vdHN0cmFwcGluZyAgeWllbGRzIGEgc2ltaWxhciBjb25maWRlbmNlIGludGVydmFsLiBGb3IgdGhpcyBzcGVjaWZpYyBleGFtcGxlLCB0aGUgdGhlb3JldGljYWwgYXBwcm9hY2ggeWllbGRlZCBhbiBpbnRlcnZhbCBvZiAkKDI4LjBcJSwgNDMuMFwlKSQuIA0KDQojIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPlZJLiBIeXBvdGhlc2lzIFRlc3RpbmcgdXNpbmcgQ29uZmlkZW5jZSBJbnRlcnZhbHM8L3NwYW4+DQoNClJlY2FsbCB0aGUgcmVzZWFyY2ggcXVlc3Rpb24gZnJvbSB0aGUgZmlyc3QgZXhhbXBsZSBpbiBNb2R1bGUgNTogZG8geW91bmdlciBmZW1hbGVzIHVzZSBsZXNzIGFnZ3Jlc3NpdmUgaHVtb3IgdGhhbiB0aGUgb3ZlcmFsbCBwb3B1bGF0aW9uPyBUaGUgaHlwb3RoZXNpcyB3YXMgDQokJFxiZWdpbnthbGlnbip9SF8wICY6IFxtdSA9IDI5XFxIX2EgJjogXG11IDwgMjlcZW5ke2FsaWduKn0kJA0KDQpJbnN0ZWFkIG9mIHBlcmZvcm1pbmcgYSAkdCQtdGVzdCBhbmQgZ2VuZXJhdGluZyBhICRwJC12YWx1ZSwgd2UgY2FuIHVzZSBib290c3RyYXBwaW5nIHRvIGVzdGltYXRlIHRoZSBtZWFuIG9mIHRoZSB5b3VuZyBmZW1hbGUgc2FtcGxlIGFuZCBzZWUgaWYgJFxtdT0yOSQgaXMgaW4gdGhlIGludGVydmFsLg0KDQpUaGUgZm9sbG93aW5nIHR3by1zdGVwIHN1YnNldHRpbmcgcmV0dXJucyB0aGUgeW91bmcgZmVtYWxlIHNhbXBsZSAoJG4gPSA0MyQpIGluIGEgZGF0YSBmcmFtZSB3aXRoIG9ubHkgdGhlIHZhcmlhYmxlICoqSFNBRyoqLiBUaGVzZSBjb21tYW5kcyBhcmUgZXhhY3RseSBhcyBiZWZvcmUgZXhjZXB0IGZvciB0aGUgKipuYS5vbWl0KiogY29tbWFuZC4gVGhlcmUgd2VyZSBzZXZlcmFsIGVtcHR5IGNlbGxzIHJlc3VsdGluZyBpbiBhZ2VzIHRoYXQgd2VyZSB1bmtub3duIGluIHRoZSBkYXRhIGZyYW1lLiBUaGUgKipuYS5vbWl0KiogcmVtb3ZlcyBhbnkgcm93cyBvZiB0aGUgZGF0YSBmcmFtZSB3aGVyZSBvbmUgb2YgdGhlIG9ic2VydmF0aW9ucyBpcyBOL0EuDQoNCmBgYHtyfQ0KZmVtID0gc3Vic2V0KERhdGEzMzUwLCBTZXggPT0gIkYiLCBjKEFnZSxIU0FHKSkNCnlGID0gc3Vic2V0KGZlbSwgQWdlIDwgMjAsIEhTQUcpDQp5RmVtID0gbmEub21pdCh5RikNCnlGZW0NCmBgYA0KDQpUbyBjcmVhdGUgYSBib290c3RyYXAgZGlzdHJpYnV0aW9uLCB3ZSByZXBlYXRlZGx5IHJlc2FtcGxlIHRoZSAqKnlGZW0qKiBvYnNlcnZhdGlvbnMsIGluIHRoaXMgY2FzZSwgNTAwIHRpbWVzLg0KDQpgYGB7cn0NCmJvb3RzdHJhcCA9IGRvKDUwMCkgKiBtZWFuIChyZXNhbXBsZSh5RmVtJEhTQUcpKQ0KYm9vdHN0cmFwDQpgYGANCg0KV2UgbmVlZCBhIDkwJSBjb25maWRlbmNlIGludGVydmFsIHNvIHRoYXQgdGhlIDV0aCBhbmQgOTV0aCBwZXJjZW50aWxlcyBvZiB0aGUgYm9vdHN0cmFwIGRpc3RyaWJ1dGlvbiB3aWxsIGJlIHRoZSBjb25maWRlbmNlIGludGVydmFsIGVuZHBvaW50cy4NCg0KYGBge3J9DQpxZGF0YSh+bWVhbiwgcD1jKDAuMDUsIDAuOTUpLCBkYXRhPWJvb3RzdHJhcCkNCmBgYA0KDQpCZWNhdXNlICQkXG11ID0gMjkgXG5vdGluICgyNC4yLCAyOC42KSQkLCB3ZSByZWplY3QgdGhlIGh1bGwgaHlwb3RoZXNpcy4gV2UgaGF2ZSBldmlkZW5jZSB0aGF0IHlvdW5nIGZlbWFsZXMgZG8gaW5kZWVkIHVzZSBsZXNzIGFnZ3Jlc3NpdmUgaHVtb3IgdGhhbiB0aGUgb3ZlcmFsbCBwb3B1bGF0aW9uIGF0IHRoZSAkXGFscGhhID0gMC4wMjUkIGxldmVsLg0KDQpGb3IgdHdvLXRhaWxlZCBoeXBvdGhlc2lzIHRlc3RzLCB3ZSBjYW4gc2V0ICQkXGFscGhhID0gMSAtIFx0ZXh0e0NvbmZpZGVuY2UgTGV2ZWx9JCQNCg0KRm9yIG9uZS10YWlsZWQgaHlwb3RoZXNpcyB0ZXN0cywgd2UgbXVzdCBzZXQgJCRcYWxwaGEgPSAxIC0gXGZyYWN7XHRleHR7Q29uZmlkZW5jZSBMZXZlbH19ezJ9JCQNCg0Kc28gdGhlIGFyZWFzIGluIHRoZSByZWplY3Rpb24gcmVnaW9uIGFyZSBpZGVudGljYWwuDQoNCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+VklJLiBTdXBwbGVtZW50OiBIb3cgdG8gQ2hhbmdlIENvbmZpZGVuY2UgTGV2ZWw8L3NwYW4+DQoNCklmIHdlIGRvIG5vdCBzcGVjaWZ5IGEgY29uZmlkZW5jZSBsZXZlbCwgUiBkZWZhdWx0cyB0byA5NSUuIEhvd2V2ZXIsIGlmIHdlIHNwZWNpZnkgdGhlIHBhcmFtZXRlciAqKmNvbmYubGV2ZWwqKiB3aXRoaW4gdGhlICR0JC10ZXN0IGl0c2VsZiwgd2UgY2FuIGNoYW5nZSB0aGUgY29uZmlkZW5jZSBsZXZlbC4gTGV0J3MgcmV0dXJuIHRvIHRoZSAqKlNsZWVwKiogdmFyaWFibGUgZnJvbSB0aGUgKipEYXRhMzM1MCoqIGRhdGEgZnJhbWUuIEZvciBhIGJhc2VsaW5lLCBsZXQncyBzaG93IHRoZSA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbC4NCg0KDQpgYGB7cn0NCmNvbmZpbnQodC50ZXN0KH4gU2xlZXAsIGRhdGEgPSBEYXRhMzM1MCkpDQpgYGANCg0KVGhlIDkwJSBjb25maWRlbmNlIGludGVydmFsIHNob3VsZCBiZSBuYXJyb3dlci4NCg0KYGBge3J9DQpjb25maW50KHQudGVzdCh+IFNsZWVwLCBkYXRhID0gRGF0YTMzNTAsIGNvbmYubGV2ZWwgPSAuOSkpDQpgYGANCg0KV2UgY2FuIGNyZWF0ZSBhIDk4JSBjb25maWRlbmNlIGludGVydmFsLiBTaW5jZSBvdXIgY29uZmlkZW5jZSBpcyBoaWdoZXIsIHRoaXMgaW50ZXJ2YWwgc2hvdWxkIGJlIHdpZGVyIHRoYW4gZWl0aGVyIG9mIHRoZSB0d28gYWJvdmUuDQoNCg0KYGBge3J9DQpjb25maW50KHQudGVzdCh+IFNsZWVwLCBkYXRhID0gRGF0YTMzNTAsIGNvbmYubGV2ZWwgPSAuOTgpKQ0KYGBgDQoNCg0KIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsdWU7Ij5WSUlJLiBFeGVyY2lzZXM8L3NwYW4+DQoNCjEuIEhvdyBtYW55IHJlc2FtcGxpbmdzIHNob3VsZCB3ZSB1c2Ugd2hlbiBib290c3RyYXBwaW5nPyBUcnkgcmUtcnVubmluZyB0aGUgY29kZSBibG9ja3MgZnJvbSB0aGUgU2xlZXAgZXhhbXBsZSB3aXRoIDUwLCAxMDAsIDUwMCwgYW5kIDEwMDAgcmVzYW1wbGluZ3MuIEhvdyBkb2VzIHRoZSBhY2N1cmFjeSBjb21wYXJlIHRvIHRoZSB0aGVvcmV0aWNhbCBjb25maWRlbmNlIGludGVydmFsIGFzIG51bWJlciBvZiByZXNhbXBsaW5ncyBpbmNyZWFzZXM/IEV4cGxhaW4gd2h5IGFib3V0IDUwMCByZXNhbXBsaW5ncyBpcyB1c3VhbGx5IGdvb2QgZW5vdWdoLg0KDQo8ZGl2IHN0eWxlPSJmbG9hdDpjZW50ZXI7IG1hcmdpbjogOHB4OyBib3JkZXI6MnB4IGJsYWNrIHNvbGlkOyBwYWRkaW5nOiAxMHB4IDE1cHggMTBweCI+DQojIyMjIENvZGUgQmxvY2s6IFF1ZXN0aW9uIDENCmBgYHtyfQ0KYm9vdHN0cmFwID0gZG8oNTApICogbWVhbihyZXNhbXBsZShEYXRhMzM1MCRTbGVlcCkpDQpxZGF0YSh+bWVhbiwgcD1jKDAuMDI1LCAwLjk3NSksIGRhdGE9Ym9vdHN0cmFwKQ0KYGBgDQo8L2Rpdj4NCg0KDQoyLiBVc2UgdGhlIENvcnBzIHZhcmlhYmxlIGluIERhdGEzMzUwIHdoZXJlIFkgLyBOIHJlc3BvbnNlcyBpbmRpY2F0ZSB3aGV0aGVyIHRoZSBwYXJ0aWNpcGFudCdzIGlzIGluIHRoZSBVTkcgQ29ycHMgb2YgQ2FkZXRzLiBBc3N1bWluZyB0aGUgZGF0YSBmcmFtZSBpcyByZXByZXNlbnRhdGl2ZSBvZiB0aGUgVU5HIERhaGxvbmVnYSBjYW1wdXMsIGNyZWF0ZSBhIDkwJSBjb25maWRlbmNlIGludGVydmFsIGVzdGltYXRlIGZvciB0aGUgcGVyY2VudGFnZSBvZiBzdHVkZW50cyB3aG8gYXJlIG1lbWJlcnMgb2YgdGhlIENvcnBzIGFuZCBpbnRlcnByZXQgeW91ciBmaW5kaW5ncy4gSGludDogc2V0IHN1Y2Nlc3MgPSAiWSIuDQoNCjMuIFVzZSB0aGUgVmFyc0F0aCB2YXJpYWJsZSBpbiBEYXRhMzM1MCB3aGVyZSBZIC8gTiByZXNwb25zZXMgaW5kaWNhdGUgd2hldGhlciB0aGUgcGFydGljaXBhbnQncyBpcyBhIHZhcnNpdHkgVU5HIGF0aGxldGUuIEFzc3VtaW5nIHRoZSBkYXRhIGZyYW1lIGlzIHJlcHJlc2VudGF0aXZlIG9mIHRoZSBVTkcgRGFobG9uZWdhIGNhbXB1cywgY3JlYXRlIGEgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgZXN0aW1hdGUgZm9yIHRoZSBwZXJjZW50YWdlIG9mIHN0dWRlbnRzIHdobyBhcmUgdmFyc2l0eSBhdGhsZXRlcyBhbmQgaW50ZXJwcmV0IHlvdXIgZmluZGluZ3MuIEhpbnQ6IHNldCBzdWNjZXNzID0gIlkiLg0KDQo0LiBVc2UgdGhlIFRleFJlbCB2YXJpYWJsZSBpbiBEYXRhMzM1MCB3aGVyZSBudW1lcmljIHNjb3JlcyByZXByZXNlbnQgc2NvcmVzIG9uIHRoZSA8YSBocmVmID0gaHR0cHM6Ly9wdWJtZWQubmNiaS5ubG0ubmloLmdvdi83NDgwNDk0Lz5Ub3hpYyBSZWxhdGlvbnNoaXAgQmVsaWVmcyBTY2FsZTwvYT4uIChIaWdoZXIgc2NvcmVzIGVxdWF0ZSB0byBtb3JlIHRveGljIGJlbGllZnMpLiBBc3N1bWluZyB0aGUgZGF0YSBmcmFtZSBpcyByZXByZXNlbnRhdGl2ZSBvZiB0aGUgVU5HIERhaGxvbmVnYSBjYW1wdXMsIGNyZWF0ZSBhIDk5JSBjb25maWRlbmNlIGludGVydmFsIGVzdGltYXRlIGZvciB0aGUgbWVhbiBUeFJlbCBzY29yZSBhbmQgaW50ZXJwcmV0IHlvdXIgZmluZGluZ3MuDQoNCjxkaXYgc3R5bGU9ImZsb2F0OnJpZ2h0OyBtYXJnaW46IDhweDsgYm9yZGVyOjJweCBibGFjayBzb2xpZDsgcGFkZGluZzogMTBweCAxNXB4IDEwcHgiPg0KIyMjIDxzcGFuIHN0eWxlPSJjb2xvcjogcmVkOyI+TW9zYWljJ3MgUmFuZG9taXphdGlvbiBPcHRpb25zPC9zcGFuPg0KMS4gKipTaHVmZmxlLioqIFBlcm11dGVzIHRoZSB2YWx1ZXMgaW4gdGhlIHNhbXBsZSBkYXRhLg0KMi4gKipTYW1wbGUuKiogRHJhd3MgYSBzdWItc2FtcGxlIGZyb20gdGhlIHNhbXBsZSBkYXRhPC9icj4qd2l0aG91dCByZXBsYWNlbWVudCouDQozLiAqKlJlc2FtcGxlLioqIERyYXdzIGEgc3ViLXNhbXBsZSBmcm9tIHRoZSBzYW1wbGUgZGF0YTwvYnI+KndpdGggcmVwbGFjZW1lbnQqLjwvYnI+DQoNCkZvciBleGFtcGxlcyBvZiBwZXJtdXRhdGlvbiB0ZXN0cyBhbmQgYm9vdHN0cmFwcGluZywgc2VlPC9icj4NCnRoZSA8YSBocmVmID0gaHR0cHM6Ly9ycHVicy5jb20vcm9iYnNpbm4vczExPlJhbmRvbWl6YXRpb24gVHV0b3JpYWw8L2E+Lg0KPC9kaXY+DQoNCjUuIFVzZSB0aGUgQ0hTIHZhcmlhYmxlIGluIERhdGEzMzUwIHdoZXJlIG51bWVyaWMgc2NvcmVzIHJlcHJlc2VudCBzY29yZXMgb24gdGhlIDxhIGhyZWYgPSBodHRwczovL3d3dy5yZXNlYXJjaGdhdGUubmV0L3Byb2ZpbGUvUm9kX01hcnRpbi9wdWJsaWNhdGlvbi8yNDk5MjkxMDlfVGhlX1NpdHVhdGlvbmFsX0h1bW9yX1Jlc3BvbnNlX1F1ZXN0aW9ubmFpcmVfU0hSUV9hbmRfQ29waW5nX0h1bW9yX1NjYWxlX0NIU19BX2RlY2FkZV9vZl9yZXNlYXJjaF9maW5kaW5ncy9saW5rcy8wMGI0OTUyZGQ4MWJkMjY3ODUwMDAwMDAvVGhlLVNpdHVhdGlvbmFsLUh1bW9yLVJlc3BvbnNlLVF1ZXN0aW9ubmFpcmUtU0hSUS1hbmQtQ29waW5nLUh1bW9yLVNjYWxlLUNIUy1BLWRlY2FkZS1vZi1yZXNlYXJjaC1maW5kaW5ncy5wZGY+Q29waW5nIEh1bW9yIFNjYWxlPC9hPi4gQXNzdW1pbmcgdGhlIGRhdGEgZnJhbWUgaXMgcmVwcmVzZW50YXRpdmUgb2YgdGhlIFVORyBEYWhsb25lZ2EgY2FtcHVzLCBjcmVhdGUgYSA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbCBlc3RpbWF0ZSBmb3IgdGhlIG1lYW4gQ0hTIHNjb3JlIGFuZCBpbnRlcnByZXQgeW91ciBmaW5kaW5ncy4NCg0KNi4gVXNlIHRoZSBDSFMgdmFyaWFibGUgaW4gRGF0YTMzNTAgdG8gY3JlYXRlIGEgYm9vdHN0cmFwIGNvbmZpZGVuY2UgaW50ZXJ2YWwgYXQgdGhlIDk1JSBsZXZlbC4gQ29tcGFyZSBhbmQgY29udHJhc3QgaXQgd2l0aCB0aGUgcmVzdWx0cyBmcm9tIHRoZSB0aGVvcmV0aWNhbCBjb25maWRlbmNlIGludGVydmFsLiBVc2UgNTAwIHJlc2FtcGxpbmdzLg0KDQoNCg==