1 Brief Introduction

Please watching this video, to get some ideas about Confidence Intervals (CI)

2 CI in Business

This video guide you, how can you apply Confidence Intervals in Business.

3 Your Exercise

In this section, your expected to get familiar with confidential intervals exercise:

3.1 Exercise 1

Find a point estimate of average university student Age with the sample data from survey!

library(MASS)
age.survey = survey$Age
mean(age.survey,na.rm=TRUE)
## [1] 20.37451
p.est<-t.test(age.survey, conf.level = 0.95)
p.est$conf.int 
## [1] 19.54600 21.20303
## attr(,"conf.level")
## [1] 0.95

As we can see, confidence intervals for the average university student height with the sample data from survey is 19.54-21.20. Therefore, we can say with 95% confidence that this interval estimate includes the true population-mean is equal to 20.37.

3.2 Exercise 2

Assume the population standard deviation \(\sigma\) of the student Age in data survey is 7. Find the margin of error and interval estimate at 95% confidence level.

library(MASS)                                         
age.response = na.omit(survey$Age)              
n = length(age.response)                            
sigma = 7                                           
sem = sigma/sqrt(n)                                    #
E = qnorm(.975)*sem ;E
## [1] 0.8911934
xbar = mean(age.response); xbar
## [1] 20.37451
xbar + c(-E, E)
## [1] 19.48332 21.26571

Assuming the population standard deviation being 7, the margin of error for the student height survey at 95% confidence level is 0.89 year. The confidence interval is between 19.48332 to 21.26571 years.

3.3 Exercise 3

Without assuming the population standard deviation \(\sigma\) of the student Age in survey, find the margin of error and interval estimate at 95% confidence level.

library(MASS)                                          
age.response = na.omit(survey$Age)               
n = length(age.response)                            
s = 7                                               
SE = s/sqrt(n)                                         
E = qt(.975, df=n-1)*SE; E 
## [1] 0.8957872
xbar = mean(age.response); xbar
## [1] 20.37451
xbar + c(-E, E) 
## [1] 19.47873 21.27030

Without assumption on the population standard deviation, the margin of error for the student age survey at 95% confidence level is 0.9 year. The confidence interval is between 19.47873 to 21.27030 years.

3.4 Exercise 4

Improve the quality of a sample survey by increasing the sample size with unknown standard deviation \(\sigma\)!.

zstar = qnorm(0.975)
sigma = 7
E = 1.2
zstar^2*sigma^2/E^2
## [1] 130.7163

The sample size need to be 230.71 to achieve the margin error

3.5 Exercise 5

Assume you don’t have planned proportion estimate, find the sample size needed to achieve 5% margin of error for the male student survey at 95% confidence level!

gender.response = na.omit(survey$Sex)
n = length(gender.response)
male = sum(gender.response == "Male"); male
## [1] 118
pbar  = male/n;pbar
## [1] 0.5
zstar = qnorm(0.975)
p=0.5

E = 0.05
zstar^2*p*(1-p)/E^2
## [1] 384.1459

the sample size needed to achieve 5% margin of error for the male student survey at 95% confidence level is 118

3.6 Exercise 6

Perform confidence intervals analysis on this data set from 2004 that includes data on average hourly earnings, marital status, gender, and age for thousands of people.

cps04 <- read.csv("cps04.csv", header = T, sep = ",")

# Average Hourly Earnings
ahe.resp = na.omit(cps04$ahe)        
n = length(ahe.resp)                  
sigma = sd(ahe.resp)                  
sem = sigma/sqrt(n)                   

xbar <- mean(ahe.resp); xbar
## [1] 16.7712
xbar + c(-E, E)
## [1] 16.7212 16.8212
# Marital Status
mar.response = na.omit(cps04$bachelor)
n = length(mar.response)
m = sum(mar.response == "1"); m
## [1] 3640
sigma = sd(mar.response)
SE=sigma/sqrt(n)
E= qnorm(0.975)*SE; E
## [1] 0.01092388
xbar <- mean(mar.response); xbar
## [1] 0.4557976
xbar+c(-E,E)
## [1] 0.4448738 0.4667215
# Female
female.response = na.omit(cps04$female)
n = length(female.response)
f = sum(female.response == "1"); f
## [1] 3313
sigma = sd(female.response)
SE=sigma/sqrt(n)
E= qnorm(0.975)*SE; E
## [1] 0.01080662
xbar <- mean(female.response); xbar
## [1] 0.414851
xbar+c(-E,E)
## [1] 0.4040444 0.4256576
# Age
age.resp = na.omit(cps04$age)         
n = length(age.resp)                  
sigma = sd(age.resp)                  
sem = sigma/sqrt(n)                   
E = qnorm(.975)*sem ;E
## [1] 0.06340892
xbar <- mean(age.resp); xbar
## [1] 29.75445
xbar + c(-E, E)
## [1] 29.69104 29.81785

The average of average hour earnings is 16.7712, with the length between 16.7078 to 16.834.

The average of marital status is 0.4557976, with the length between 0.3923887 to 0.5192066.

The average of female is 0.414851, with the length between 0.3514421 to 0.4782599.

The average of age is 29.75445, with the length between 29.69104 to 29.81785.

4 Case Study

Assume you have access to data on an entire population, say the size of every house in all residential home sales in Ames, Iowa between 2006 and 2010 it’s straight forward to answer questions like,

  • How big is the typical house in Ames?
  • How much variation is there in sizes of houses?.
  • How much is the average price of house in Ames?
  • How much is the confidence interval price of house in Ames?

But, If you have access to only a sample of the population, as is often the case, the task becomes more complicated. What is your best guess for the typical size if you only know the sizes of several dozen houses? This sort of situation requires that you use your sample to make inference on what your population looks like.

4.1 Collect Data

To access the data in R, type the following code:

download.file("http://www.openintro.org/stat/data/ames.RData", destfile = "ames.RData")
load("ames.RData")

In this case study we’ll start with a simple random sample of size 60 from the population. Specifically, this is a simple random sample of size 60. Note that the data set has information on many housing variables, but for the first portion of the lab we’ll focus on the size of the house, represented by the variable Gr.Liv.Area.

#randomly set seed to fix outputs in this assignment
set.seed(0)
population <- ames$Gr.Liv.Area
samp <- sample(population, 60)
samp
##  [1] 2200 2093 1040 2233 1523 1660 1555 1102  848 1136 2061 1122  960 1092 2610
## [16] 2217 1959 2334 1660 1576  848 2004  988 1500  874 1340 1800 1069 1456  784
## [31]  985 1928  882 1124 1639 1214 1434 1150 1544 1812 1511 1949 1077 1248 1480
## [46] 1320 1717 1367  928 2552 1953  693 2690 2276 1173 1258 2582 1558  672 1488

4.2 Visualization

As usual, before you begin to analyze more about your data. It’s important to visualize the data in advance. Here, we use a random sample of size 60 from the population.

# Histogram
library(moments)
hist(samp, breaks = 20, col = 'pink')

# Make a histogram of your sample
hist(samp, main ="Distribution fo Samp", 
     col = "deeppink3", 
     xlim = c(200, 3500), 
     freq = F,
     xlab = "Samp")
# ...and add a density curve
curve(dnorm(x, 
            mean=mean(samp), 
            sd=sd(samp)), add=T, 
            col="blue", lwd=2)

Your Challenge:

  • Describe the distribution of your sample. What would you say is the “typical” size within your sample? Also state precisely what you interpreted “typical” to mean.
n <- 60
population <- ames$Gr.Liv.Area
samp <- sample(population, 60)

summary(samp)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##     778    1122    1448    1536    1728    3608
hist(samp, breaks = 10)

mean(population)
## [1] 1499.69
  • Would you expect another student’s distribution to be identical to yours? Would you expect it to be similar? Why or why not?

No, this is a random sample of 35 randomly selected observations. The question here will be how similar is similar? or how near is near?, then if the values are near then yes, it could happen.

4.3 Confidence Intervals

One of the most common ways to describe the typical or central value of a distribution is to use the mean. In this case we can calculate the mean of the sample using,

sample_mean <- mean(samp)
sample_mean
## [1] 1536.317

Return for a moment to the question that first motivated this lab: based on this sample, what can we infer about the population? Based only on this single sample, the best estimate of the average living area of houses sold in Ames would be the sample mean, usually denoted as \(\bar{x}\) (here we’re calling it sample_mean). That serves as a good point estimate but it would be useful to also communicate how uncertain we are of that estimate. This can be captured by using a confidence interval.

We can calculate a 95% confidence interval for a sample mean by adding and subtracting 1.96 standard errors to the point estimate (I assume that you have been familiar with this formula).

se <- sd(samp) / sqrt(60)
lower <- sample_mean - 1.96 * se
upper <- sample_mean + 1.96 * se
c(lower, upper)
## [1] 1395.866 1676.767

This is an important inference that we’ve just made: even though we don’t know what the full population looks like, we’re 95% confident that the true average size of houses in Ames lies between the values lower and upper. There are a few conditions that must be met for this interval to be valid.

Your Challenge:

  • For the confidence interval to be valid, the sample mean must be normally distributed and have standard error $ s/$. What conditions must be met for this to be true? No, this is a random sample of 60 randomly selected observations. The question here will be how similar is similar? or how near is near?, then if the values are near then yes, it could happen
  • What does “95% confidence” mean? Is the confidence interval level for the normal model with standard error SE. The confidence interval for the population parameter is pointestimate±z⋅SE where z corresponds to the confidence level selected.
  • Does your confidence interval capture the true average size of houses in Ames? If you are working on this case study, does your classmate’s interval capture this value? Yes, the above confidence interval capture the true average size of houses in Ames. I would expect my classmate to capture the mean value on their lab as well.

4.4 Simulation

let’s simulate a scenario of confidence interval in classroom to capture the true average size of houses in Ames. Suppose we have 100 students in the classroom.

count = 0
for (i in 1:100) {
  samp <- sample(population,60)
  samp_mean<- mean(samp)
  se <- sd(samp)/sqrt(60)
  lower <- samp_mean-1.96*se
  upper <- samp_mean+1.96*se
  if ((lower <= 1499.69) & (upper >= 1499.69)) {
    count = count+1
  }  
}
count
## [1] 97

Using R, we’re going to recreate many samples to learn more about how sample means and confidence intervals vary from one sample to another. Loops come in handy here (If you are unfamiliar with loops, review the Sampling Distribution Lab).

Here is the rough outline:

  • Obtain a random sample.
  • Calculate and store the sample’s mean and standard deviation.
  • Repeat steps (1) and (2) 50 times.
  • Use these stored statistics to calculate many confidence intervals.

But before we do all of this, we need to first create empty vectors where we can save the means and standard deviations that will be calculated from each sample. And while we’re at it, let’s also store the desired sample size as \(n\).

samp_mean <- rep(NA, 50)
samp_sd <- rep(NA, 50)
n <- 60
n
## [1] 60

Now we’re ready for the loop where we calculate the means and standard deviations of 50 random samples.

for(i in 1:50){
  samp <- sample(population, n) # obtain a sample of size n = 60 from the population
  samp_mean[i] <- mean(samp)    # save sample mean in ith element of samp_mean
  samp_sd[i] <- sd(samp)        # save sample sd in ith element of samp_sd
}
samp
##  [1]  825 1889 1047 2715 1636 1347 1659  996 1242 1256 1142 1501 1566 2172 1414
## [16] 1489 1788 1358 1488 1229  882 4476 1356 1657 1287 1107 1389 1044 1188 1367
## [31] 1125 1102 2237 1392 1495 1068 1218 1138 1137 1780 1105 1322 1074 1484  874
## [46] 1720 1682 1337 1240 1116  980  876 2136 1104 1299  864 1404 1665 2019 1432

Lastly, we construct the confidence intervals.

lower_vector <- samp_mean - 1.96 * samp_sd / sqrt(n) 
upper_vector <- samp_mean + 1.96 * samp_sd / sqrt(n)

Lower bounds of these 50 confidence intervals are stored in lower_vector, and the upper bounds are in upper_vector. Let’s view the first interval.

c(lower_vector[1], upper_vector[1])
## [1] 1331.196 1577.604
# confidential interval visualization
plot_ci(lower_vector, upper_vector, mean(population))

# For a 95% confidence interval, the critical value is -1.959964 and 1.959964.
qnorm((1-0.95)/2)
## [1] -1.959964
qnorm((1+0.95)/2)
## [1] 1.959964

Your Challenge:

  • What proportion of your confidence intervals include the true population mean? Is this proportion exactly equal to the confidence level? If not, explain why.
plot_ci(lower_vector, upper_vector, mean(population))

Vector <- data.frame(lower_vector, upper_vector)
meanp <- mean(population)

left <- sum(Vector$upper_vector < meanp)
right <- sum(Vector$lower_vector > meanp)

noMeanIncluded <- left + right
noMeanIncluded
## [1] 2
proportion <- round(noMeanIncluded/n ,2)
proportion
## [1] 0.03

In this case only 95% include the population mean. This proportion is not necesarily the same as our confidence level but very near approximation of it.

  • Pick a confidence level of your choosing, provided it is 99%. What is the appropriate critical value?
lower_vector <- samp_mean - 0.84 * samp_sd / sqrt(n) 
upper_vector <- samp_mean + 0.84 * samp_sd / sqrt(n)
plot_ci(lower_vector, upper_vector, mean(population))

Vector <- data.frame(lower_vector, upper_vector)
meanp <- mean(population)

left <- sum(Vector$upper_vector < meanp)
right <- sum(Vector$lower_vector > meanp)

noMeanIncluded <- left + right
noMeanIncluded
## [1] 19
proportion <- round(noMeanIncluded/n ,2)
proportion
## [1] 0.32

In this case only 73% include the population mean. This proportion is not necesarily the same as our confidence level but very near approximation of it.

LS0tDQp0aXRsZTogIkNvbmZpZGVuY2UgSW50ZXJ2YWxzIg0KYXV0aG9yOiAiWW9uYXRoYW4gQW5nZ3JhaXdhbiINCmRhdGU6ICJgciBmb3JtYXQoU3lzLkRhdGUoKSwgJyVCICVkLCAlWScpYCINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzDQogICAgdGhlbWU6IHNwYWNlbGFiDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQotLS0NCg0KYGBge3IgTG9nbyxlY2hvPUZBTFNFLGZpZy5hbGlnbj0nY2VudGVyJywgb3V0LndpZHRoID0gJzQwJSd9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiQzovVXNlcnMvWW9uYXRoYW4vRG93bmxvYWRzL2xvZ29tYXRhbmEuanBnIikNCmBgYA0KDQojIEJyaWVmIEludHJvZHVjdGlvbiANCg0KUGxlYXNlIHdhdGNoaW5nIHRoaXMgdmlkZW8sIHRvIGdldCBzb21lIGlkZWFzIGFib3V0IENvbmZpZGVuY2UgSW50ZXJ2YWxzIChDSSkNCg0KPGNlbnRlcj4NCjxpZnJhbWUgd2lkdGg9IjgwMCIgaGVpZ2h0PSI0NTAiIHNyYz0iaHR0cHM6Ly93d3cueW91dHViZS5jb20vZW1iZWQvTWJYVGhiVFNyVkkiIGZyYW1lYm9yZGVyPSIwIiBhbGxvdz0iYWNjZWxlcm9tZXRlcjsgYXV0b3BsYXk7IGVuY3J5cHRlZC1tZWRpYTsgZ3lyb3Njb3BlOyBwaWN0dXJlLWluLXBpY3R1cmUiIGFsbG93ZnVsbHNjcmVlbj48L2lmcmFtZT4NCjwvY2VudGVyPg0KDQoNCiMgQ0kgaW4gQnVzaW5lc3MgDQoNClRoaXMgdmlkZW8gZ3VpZGUgeW91LCBob3cgY2FuIHlvdSBhcHBseSBDb25maWRlbmNlIEludGVydmFscyBpbiBCdXNpbmVzcy4NCg0KPGNlbnRlcj4NCjxpZnJhbWUgd2lkdGg9IjgwMCIgaGVpZ2h0PSI0NTAiIHNyYz0iaHR0cHM6Ly93d3cueW91dHViZS5jb20vZW1iZWQvX0pHQUxldE1jam8iIGZyYW1lYm9yZGVyPSIwIiBhbGxvdz0iYWNjZWxlcm9tZXRlcjsgYXV0b3BsYXk7IGVuY3J5cHRlZC1tZWRpYTsgZ3lyb3Njb3BlOyBwaWN0dXJlLWluLXBpY3R1cmUiIGFsbG93ZnVsbHNjcmVlbj48L2lmcmFtZT4NCjwvY2VudGVyPg0KDQoNCiMgWW91ciBFeGVyY2lzZSANCg0KSW4gdGhpcyBzZWN0aW9uLCB5b3VyIGV4cGVjdGVkIHRvIGdldCBmYW1pbGlhciB3aXRoIGNvbmZpZGVudGlhbCBpbnRlcnZhbHMgZXhlcmNpc2U6IA0KDQojIyBFeGVyY2lzZSAxDQoNCkZpbmQgYSBwb2ludCBlc3RpbWF0ZSBvZiBhdmVyYWdlIHVuaXZlcnNpdHkgc3R1ZGVudCBgQWdlYCB3aXRoIHRoZSBzYW1wbGUgZGF0YSBmcm9tIGBzdXJ2ZXlgIQ0KDQpgYGB7cn0NCmxpYnJhcnkoTUFTUykNCmFnZS5zdXJ2ZXkgPSBzdXJ2ZXkkQWdlDQptZWFuKGFnZS5zdXJ2ZXksbmEucm09VFJVRSkNCmBgYA0KDQpgYGB7cn0NCnAuZXN0PC10LnRlc3QoYWdlLnN1cnZleSwgY29uZi5sZXZlbCA9IDAuOTUpDQpwLmVzdCRjb25mLmludCANCmBgYA0KDQpBcyB3ZSBjYW4gc2VlLCBjb25maWRlbmNlIGludGVydmFscyBmb3IgdGhlIGF2ZXJhZ2UgdW5pdmVyc2l0eSBzdHVkZW50IGhlaWdodCB3aXRoIHRoZSBzYW1wbGUgZGF0YSBmcm9tIHN1cnZleSBpcyAxOS41NC0yMS4yMC4gVGhlcmVmb3JlLCB3ZSBjYW4gc2F5IHdpdGggOTUlIGNvbmZpZGVuY2UgdGhhdCB0aGlzIGludGVydmFsIGVzdGltYXRlIGluY2x1ZGVzIHRoZSB0cnVlIHBvcHVsYXRpb24tbWVhbiBpcyBlcXVhbCB0byAyMC4zNy4NCg0KIyMgRXhlcmNpc2UgMg0KDQpBc3N1bWUgdGhlIHBvcHVsYXRpb24gc3RhbmRhcmQgZGV2aWF0aW9uICRcc2lnbWEkIG9mIHRoZSBzdHVkZW50IGBBZ2VgIGluIGRhdGEgYHN1cnZleWAgaXMgNy4gRmluZCB0aGUgbWFyZ2luIG9mIGVycm9yIGFuZCBpbnRlcnZhbCBlc3RpbWF0ZSBhdCA5NSUgY29uZmlkZW5jZSBsZXZlbC4NCg0KYGBge3J9DQpsaWJyYXJ5KE1BU1MpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCmFnZS5yZXNwb25zZSA9IG5hLm9taXQoc3VydmV5JEFnZSkgICAgICAgICAgICAgIA0KbiA9IGxlbmd0aChhZ2UucmVzcG9uc2UpICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0Kc2lnbWEgPSA3ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0Kc2VtID0gc2lnbWEvc3FydChuKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCkUgPSBxbm9ybSguOTc1KSpzZW0gO0UNCnhiYXIgPSBtZWFuKGFnZS5yZXNwb25zZSk7IHhiYXINCnhiYXIgKyBjKC1FLCBFKQ0KYGBgDQoNCkFzc3VtaW5nIHRoZSBwb3B1bGF0aW9uIHN0YW5kYXJkIGRldmlhdGlvbiBiZWluZyA3LCB0aGUgbWFyZ2luIG9mIGVycm9yIGZvciB0aGUgc3R1ZGVudCBoZWlnaHQgc3VydmV5IGF0IDk1JSBjb25maWRlbmNlIGxldmVsIGlzIDAuODkgeWVhci4gVGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgaXMgYmV0d2VlbiAxOS40ODMzMiB0byAyMS4yNjU3MSB5ZWFycy4NCg0KIyMgRXhlcmNpc2UgMw0KDQpXaXRob3V0IGFzc3VtaW5nIHRoZSBwb3B1bGF0aW9uIHN0YW5kYXJkIGRldmlhdGlvbiAkXHNpZ21hJCBvZiB0aGUgc3R1ZGVudCBgQWdlYCBpbiBzdXJ2ZXksIGZpbmQgdGhlIG1hcmdpbiBvZiBlcnJvciBhbmQgaW50ZXJ2YWwgZXN0aW1hdGUgYXQgOTUlIGNvbmZpZGVuY2UgbGV2ZWwuDQoNCmBgYHtyfQ0KbGlicmFyeShNQVNTKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KYWdlLnJlc3BvbnNlID0gbmEub21pdChzdXJ2ZXkkQWdlKSAgICAgICAgICAgICAgIA0KbiA9IGxlbmd0aChhZ2UucmVzcG9uc2UpICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KcyA9IDcgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KU0UgPSBzL3NxcnQobikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KRSA9IHF0KC45NzUsIGRmPW4tMSkqU0U7IEUgDQp4YmFyID0gbWVhbihhZ2UucmVzcG9uc2UpOyB4YmFyDQp4YmFyICsgYygtRSwgRSkgDQpgYGANCldpdGhvdXQgYXNzdW1wdGlvbiBvbiB0aGUgcG9wdWxhdGlvbiBzdGFuZGFyZCBkZXZpYXRpb24sIHRoZSBtYXJnaW4gb2YgZXJyb3IgZm9yIHRoZSBzdHVkZW50IGFnZSBzdXJ2ZXkgYXQgOTUlIGNvbmZpZGVuY2UgbGV2ZWwgaXMgMC45IHllYXIuIFRoZSBjb25maWRlbmNlIGludGVydmFsIGlzIGJldHdlZW4gMTkuNDc4NzMgdG8gMjEuMjcwMzAgeWVhcnMuDQoNCg0KDQojIyBFeGVyY2lzZSA0DQoNCkltcHJvdmUgdGhlIHF1YWxpdHkgb2YgYSBzYW1wbGUgYHN1cnZleWAgYnkgaW5jcmVhc2luZyB0aGUgc2FtcGxlIHNpemUgd2l0aCB1bmtub3duIHN0YW5kYXJkIGRldmlhdGlvbiAkXHNpZ21hJCEuDQoNCmBgYHtyfQ0KenN0YXIgPSBxbm9ybSgwLjk3NSkNCnNpZ21hID0gNw0KRSA9IDEuMg0KenN0YXJeMipzaWdtYV4yL0VeMg0KYGBgDQoNClRoZSBzYW1wbGUgc2l6ZSBuZWVkIHRvIGJlIDIzMC43MSB0byBhY2hpZXZlIHRoZSBtYXJnaW4gZXJyb3INCg0KIyMgRXhlcmNpc2UgNQ0KDQpBc3N1bWUgeW91IGRvbuKAmXQgaGF2ZSBwbGFubmVkIHByb3BvcnRpb24gZXN0aW1hdGUsIGZpbmQgdGhlIHNhbXBsZSBzaXplIG5lZWRlZCB0byBhY2hpZXZlIDUlIG1hcmdpbiBvZiBlcnJvciBmb3IgdGhlIG1hbGUgc3R1ZGVudCBgc3VydmV5YCBhdCA5NSUgY29uZmlkZW5jZSBsZXZlbCENCg0KYGBge3J9DQpnZW5kZXIucmVzcG9uc2UgPSBuYS5vbWl0KHN1cnZleSRTZXgpDQpuID0gbGVuZ3RoKGdlbmRlci5yZXNwb25zZSkNCm1hbGUgPSBzdW0oZ2VuZGVyLnJlc3BvbnNlID09ICJNYWxlIik7IG1hbGUNCnBiYXIgID0gbWFsZS9uO3BiYXINCg0KenN0YXIgPSBxbm9ybSgwLjk3NSkNCnA9MC41DQoNCkUgPSAwLjA1DQp6c3Rhcl4yKnAqKDEtcCkvRV4yDQpgYGANCnRoZSBzYW1wbGUgc2l6ZSBuZWVkZWQgdG8gYWNoaWV2ZSA1JSBtYXJnaW4gb2YgZXJyb3IgZm9yIHRoZSBtYWxlIHN0dWRlbnQgYHN1cnZleWAgYXQgOTUlIGNvbmZpZGVuY2UgbGV2ZWwgaXMgMTE4DQoNCiMjIEV4ZXJjaXNlIDYNCg0KUGVyZm9ybSBjb25maWRlbmNlIGludGVydmFscyBhbmFseXNpcyBvbiB0aGlzIFtkYXRhIHNldF0oaHR0cDovL211cnJheWxheC5vcmcvZGF0YXNldHMvY3BzMDQuY3N2KSBmcm9tIDIwMDQgdGhhdCBpbmNsdWRlcyBkYXRhIG9uIGF2ZXJhZ2UgaG91cmx5IGVhcm5pbmdzLCBtYXJpdGFsIHN0YXR1cywgZ2VuZGVyLCBhbmQgYWdlIGZvciB0aG91c2FuZHMgb2YgcGVvcGxlLg0KDQpgYGB7cn0NCmNwczA0IDwtIHJlYWQuY3N2KCJjcHMwNC5jc3YiLCBoZWFkZXIgPSBULCBzZXAgPSAiLCIpDQoNCiMgQXZlcmFnZSBIb3VybHkgRWFybmluZ3MNCmFoZS5yZXNwID0gbmEub21pdChjcHMwNCRhaGUpICAgICAgICANCm4gPSBsZW5ndGgoYWhlLnJlc3ApICAgICAgICAgICAgICAgICAgDQpzaWdtYSA9IHNkKGFoZS5yZXNwKSAgICAgICAgICAgICAgICAgIA0Kc2VtID0gc2lnbWEvc3FydChuKSAgICAgICAgICAgICAgICAgICANCg0KeGJhciA8LSBtZWFuKGFoZS5yZXNwKTsgeGJhcg0KeGJhciArIGMoLUUsIEUpDQoNCiMgTWFyaXRhbCBTdGF0dXMNCm1hci5yZXNwb25zZSA9IG5hLm9taXQoY3BzMDQkYmFjaGVsb3IpDQpuID0gbGVuZ3RoKG1hci5yZXNwb25zZSkNCm0gPSBzdW0obWFyLnJlc3BvbnNlID09ICIxIik7IG0NCnNpZ21hID0gc2QobWFyLnJlc3BvbnNlKQ0KU0U9c2lnbWEvc3FydChuKQ0KRT0gcW5vcm0oMC45NzUpKlNFOyBFDQoNCnhiYXIgPC0gbWVhbihtYXIucmVzcG9uc2UpOyB4YmFyDQp4YmFyK2MoLUUsRSkNCg0KIyBGZW1hbGUNCmZlbWFsZS5yZXNwb25zZSA9IG5hLm9taXQoY3BzMDQkZmVtYWxlKQ0KbiA9IGxlbmd0aChmZW1hbGUucmVzcG9uc2UpDQpmID0gc3VtKGZlbWFsZS5yZXNwb25zZSA9PSAiMSIpOyBmDQpzaWdtYSA9IHNkKGZlbWFsZS5yZXNwb25zZSkNClNFPXNpZ21hL3NxcnQobikNCkU9IHFub3JtKDAuOTc1KSpTRTsgRQ0KDQp4YmFyIDwtIG1lYW4oZmVtYWxlLnJlc3BvbnNlKTsgeGJhcg0KeGJhcitjKC1FLEUpDQoNCiMgQWdlDQphZ2UucmVzcCA9IG5hLm9taXQoY3BzMDQkYWdlKSAgICAgICAgIA0KbiA9IGxlbmd0aChhZ2UucmVzcCkgICAgICAgICAgICAgICAgICANCnNpZ21hID0gc2QoYWdlLnJlc3ApICAgICAgICAgICAgICAgICAgDQpzZW0gPSBzaWdtYS9zcXJ0KG4pICAgICAgICAgICAgICAgICAgIA0KRSA9IHFub3JtKC45NzUpKnNlbSA7RQ0KDQp4YmFyIDwtIG1lYW4oYWdlLnJlc3ApOyB4YmFyDQp4YmFyICsgYygtRSwgRSkNCmBgYA0KVGhlIGF2ZXJhZ2Ugb2YgYXZlcmFnZSBob3VyIGVhcm5pbmdzIGlzIDE2Ljc3MTIsIHdpdGggdGhlIGxlbmd0aCBiZXR3ZWVuIDE2LjcwNzggdG8gMTYuODM0Lg0KDQpUaGUgYXZlcmFnZSBvZiBtYXJpdGFsIHN0YXR1cyBpcyAwLjQ1NTc5NzYsIHdpdGggdGhlIGxlbmd0aCBiZXR3ZWVuICAwLjM5MjM4ODcgdG8gMC41MTkyMDY2Lg0KDQpUaGUgYXZlcmFnZSBvZiBmZW1hbGUgaXMgMC40MTQ4NTEsIHdpdGggdGhlIGxlbmd0aCBiZXR3ZWVuICAgMC4zNTE0NDIxIHRvIDAuNDc4MjU5OS4NCg0KVGhlIGF2ZXJhZ2Ugb2YgYWdlIGlzIDI5Ljc1NDQ1LCB3aXRoIHRoZSBsZW5ndGggYmV0d2VlbiAgIDI5LjY5MTA0IHRvIDI5LjgxNzg1Lg0KDQojIENhc2UgU3R1ZHkgDQoNCkFzc3VtZSB5b3UgaGF2ZSBhY2Nlc3MgdG8gZGF0YSBvbiBhbiBlbnRpcmUgcG9wdWxhdGlvbiwgc2F5IHRoZSBzaXplIG9mIGV2ZXJ5IGhvdXNlIGluIFthbGwgcmVzaWRlbnRpYWwgaG9tZSBzYWxlcyBpbiBBbWVzLCBJb3dhIGJldHdlZW4gMjAwNiBhbmQgMjAxMF0oaHR0cHM6Ly93d3cub3BlbmludHJvLm9yZy9ib29rL3N0YXRkYXRhLz9kYXRhPWFtZXMpIGl04oCZcyBzdHJhaWdodCBmb3J3YXJkIHRvIGFuc3dlciBxdWVzdGlvbnMgbGlrZSwgDQoNCiogSG93IGJpZyBpcyB0aGUgdHlwaWNhbCBob3VzZSBpbiBBbWVzPyANCiogSG93IG11Y2ggdmFyaWF0aW9uIGlzIHRoZXJlIGluIHNpemVzIG9mIGhvdXNlcz8uIA0KKiBIb3cgbXVjaCBpcyB0aGUgYXZlcmFnZSBwcmljZSBvZiBob3VzZSBpbiBBbWVzPw0KKiBIb3cgbXVjaCBpcyB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbCBwcmljZSBvZiBob3VzZSBpbiBBbWVzPw0KDQpCdXQsIElmIHlvdSBoYXZlIGFjY2VzcyB0byBvbmx5IGEgc2FtcGxlIG9mIHRoZSBwb3B1bGF0aW9uLCBhcyBpcyBvZnRlbiB0aGUgY2FzZSwgdGhlIHRhc2sgYmVjb21lcyBtb3JlIGNvbXBsaWNhdGVkLiBXaGF0IGlzIHlvdXIgYmVzdCBndWVzcyBmb3IgdGhlIHR5cGljYWwgc2l6ZSBpZiB5b3Ugb25seSBrbm93IHRoZSBzaXplcyBvZiBzZXZlcmFsIGRvemVuIGhvdXNlcz8gVGhpcyBzb3J0IG9mIHNpdHVhdGlvbiByZXF1aXJlcyB0aGF0IHlvdSB1c2UgeW91ciBzYW1wbGUgdG8gbWFrZSBpbmZlcmVuY2Ugb24gd2hhdCB5b3VyIHBvcHVsYXRpb24gbG9va3MgbGlrZS4NCg0KDQojIyBDb2xsZWN0IERhdGENCg0KVG8gYWNjZXNzIHRoZSBkYXRhIGluIFIsIHR5cGUgdGhlIGZvbGxvd2luZyBjb2RlOg0KDQpgYGB7cn0NCmRvd25sb2FkLmZpbGUoImh0dHA6Ly93d3cub3BlbmludHJvLm9yZy9zdGF0L2RhdGEvYW1lcy5SRGF0YSIsIGRlc3RmaWxlID0gImFtZXMuUkRhdGEiKQ0KbG9hZCgiYW1lcy5SRGF0YSIpDQpgYGANCg0KSW4gdGhpcyBjYXNlIHN0dWR5IHdl4oCZbGwgc3RhcnQgd2l0aCBhIHNpbXBsZSByYW5kb20gc2FtcGxlIG9mIHNpemUgNjAgZnJvbSB0aGUgcG9wdWxhdGlvbi4gU3BlY2lmaWNhbGx5LCB0aGlzIGlzIGEgc2ltcGxlIHJhbmRvbSBzYW1wbGUgb2Ygc2l6ZSA2MC4gTm90ZSB0aGF0IHRoZSBkYXRhIHNldCBoYXMgaW5mb3JtYXRpb24gb24gbWFueSBob3VzaW5nIHZhcmlhYmxlcywgYnV0IGZvciB0aGUgZmlyc3QgcG9ydGlvbiBvZiB0aGUgbGFiIHdl4oCZbGwgZm9jdXMgb24gdGhlIHNpemUgb2YgdGhlIGhvdXNlLCByZXByZXNlbnRlZCBieSB0aGUgdmFyaWFibGUgYEdyLkxpdi5BcmVhYC4NCg0KYGBge3J9DQojcmFuZG9tbHkgc2V0IHNlZWQgdG8gZml4IG91dHB1dHMgaW4gdGhpcyBhc3NpZ25tZW50DQpzZXQuc2VlZCgwKQ0KcG9wdWxhdGlvbiA8LSBhbWVzJEdyLkxpdi5BcmVhDQpzYW1wIDwtIHNhbXBsZShwb3B1bGF0aW9uLCA2MCkNCnNhbXANCmBgYA0KDQoNCiMjIFZpc3VhbGl6YXRpb24NCg0KQXMgdXN1YWwsIGJlZm9yZSB5b3UgYmVnaW4gdG8gYW5hbHl6ZSBtb3JlIGFib3V0IHlvdXIgZGF0YS4gSXQncyBpbXBvcnRhbnQgdG8gdmlzdWFsaXplIHRoZSBkYXRhIGluIGFkdmFuY2UuIEhlcmUsIHdlIHVzZSBhIHJhbmRvbSBzYW1wbGUgb2Ygc2l6ZSA2MCBmcm9tIHRoZSBwb3B1bGF0aW9uLg0KDQpgYGB7cn0NCiMgSGlzdG9ncmFtDQpsaWJyYXJ5KG1vbWVudHMpDQpoaXN0KHNhbXAsIGJyZWFrcyA9IDIwLCBjb2wgPSAncGluaycpDQpgYGANCg0KYGBge3J9DQojIE1ha2UgYSBoaXN0b2dyYW0gb2YgeW91ciBzYW1wbGUNCmhpc3Qoc2FtcCwgbWFpbiA9IkRpc3RyaWJ1dGlvbiBmbyBTYW1wIiwgDQogICAgIGNvbCA9ICJkZWVwcGluazMiLCANCiAgICAgeGxpbSA9IGMoMjAwLCAzNTAwKSwgDQogICAgIGZyZXEgPSBGLA0KICAgICB4bGFiID0gIlNhbXAiKQ0KIyAuLi5hbmQgYWRkIGEgZGVuc2l0eSBjdXJ2ZQ0KY3VydmUoZG5vcm0oeCwgDQogICAgICAgICAgICBtZWFuPW1lYW4oc2FtcCksIA0KICAgICAgICAgICAgc2Q9c2Qoc2FtcCkpLCBhZGQ9VCwgDQogICAgICAgICAgICBjb2w9ImJsdWUiLCBsd2Q9MikNCmBgYA0KDQoqKllvdXIgQ2hhbGxlbmdlOioqIA0KDQoqIERlc2NyaWJlIHRoZSBkaXN0cmlidXRpb24gb2YgeW91ciBzYW1wbGUuIFdoYXQgd291bGQgeW91IHNheSBpcyB0aGUg4oCcdHlwaWNhbOKAnSBzaXplIHdpdGhpbiB5b3VyIHNhbXBsZT8gQWxzbyBzdGF0ZSBwcmVjaXNlbHkgd2hhdCB5b3UgaW50ZXJwcmV0ZWQg4oCcdHlwaWNhbOKAnSB0byBtZWFuLiANCmBgYHtyfQ0KbiA8LSA2MA0KcG9wdWxhdGlvbiA8LSBhbWVzJEdyLkxpdi5BcmVhDQpzYW1wIDwtIHNhbXBsZShwb3B1bGF0aW9uLCA2MCkNCg0Kc3VtbWFyeShzYW1wKQ0KYGBgDQpgYGB7cn0NCmhpc3Qoc2FtcCwgYnJlYWtzID0gMTApDQpgYGANCg0KYGBge3J9DQptZWFuKHBvcHVsYXRpb24pDQpgYGANCg0KDQoqIFdvdWxkIHlvdSBleHBlY3QgYW5vdGhlciBzdHVkZW504oCZcyBkaXN0cmlidXRpb24gdG8gYmUgaWRlbnRpY2FsIHRvIHlvdXJzPyBXb3VsZCB5b3UgZXhwZWN0IGl0IHRvIGJlIHNpbWlsYXI/IFdoeSBvciB3aHkgbm90Pw0KDQpObywgdGhpcyBpcyBhIHJhbmRvbSBzYW1wbGUgb2YgMzUgcmFuZG9tbHkgc2VsZWN0ZWQgb2JzZXJ2YXRpb25zLiBUaGUgcXVlc3Rpb24gaGVyZSB3aWxsIGJlIGhvdyBzaW1pbGFyIGlzIHNpbWlsYXI/IG9yIGhvdyBuZWFyIGlzIG5lYXI/LCB0aGVuIGlmIHRoZSB2YWx1ZXMgYXJlIG5lYXIgdGhlbiB5ZXMsIGl0IGNvdWxkIGhhcHBlbi4NCg0KIyMgQ29uZmlkZW5jZSBJbnRlcnZhbHMNCg0KT25lIG9mIHRoZSBtb3N0IGNvbW1vbiB3YXlzIHRvIGRlc2NyaWJlIHRoZSB0eXBpY2FsIG9yIGNlbnRyYWwgdmFsdWUgb2YgYSBkaXN0cmlidXRpb24gaXMgdG8gdXNlIHRoZSBtZWFuLiBJbiB0aGlzIGNhc2Ugd2UgY2FuIGNhbGN1bGF0ZSB0aGUgbWVhbiBvZiB0aGUgc2FtcGxlIHVzaW5nLA0KDQpgYGB7cn0NCnNhbXBsZV9tZWFuIDwtIG1lYW4oc2FtcCkNCnNhbXBsZV9tZWFuDQpgYGANClJldHVybiBmb3IgYSBtb21lbnQgdG8gdGhlIHF1ZXN0aW9uIHRoYXQgZmlyc3QgbW90aXZhdGVkIHRoaXMgbGFiOiBiYXNlZCBvbiB0aGlzIHNhbXBsZSwgd2hhdCBjYW4gd2UgaW5mZXIgYWJvdXQgdGhlIHBvcHVsYXRpb24/IEJhc2VkIG9ubHkgb24gdGhpcyBzaW5nbGUgc2FtcGxlLCB0aGUgYmVzdCBlc3RpbWF0ZSBvZiB0aGUgYXZlcmFnZSBsaXZpbmcgYXJlYSBvZiBob3VzZXMgc29sZCBpbiBBbWVzIHdvdWxkIGJlIHRoZSBzYW1wbGUgbWVhbiwgdXN1YWxseSBkZW5vdGVkIGFzICRcYmFye3h9JCAoaGVyZSB3ZeKAmXJlIGNhbGxpbmcgaXQgYHNhbXBsZV9tZWFuYCkuIFRoYXQgc2VydmVzIGFzIGEgZ29vZCBwb2ludCBlc3RpbWF0ZSBidXQgaXQgd291bGQgYmUgdXNlZnVsIHRvIGFsc28gY29tbXVuaWNhdGUgaG93IHVuY2VydGFpbiB3ZSBhcmUgb2YgdGhhdCBlc3RpbWF0ZS4gVGhpcyBjYW4gYmUgY2FwdHVyZWQgYnkgdXNpbmcgYSBjb25maWRlbmNlIGludGVydmFsLg0KDQpXZSBjYW4gY2FsY3VsYXRlIGEgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgZm9yIGEgc2FtcGxlIG1lYW4gYnkgYWRkaW5nIGFuZCBzdWJ0cmFjdGluZyAxLjk2IHN0YW5kYXJkIGVycm9ycyB0byB0aGUgcG9pbnQgZXN0aW1hdGUgKEkgYXNzdW1lIHRoYXQgeW91IGhhdmUgYmVlbiBmYW1pbGlhciB3aXRoIHRoaXMgZm9ybXVsYSkuDQoNCmBgYHtyfQ0Kc2UgPC0gc2Qoc2FtcCkgLyBzcXJ0KDYwKQ0KbG93ZXIgPC0gc2FtcGxlX21lYW4gLSAxLjk2ICogc2UNCnVwcGVyIDwtIHNhbXBsZV9tZWFuICsgMS45NiAqIHNlDQpjKGxvd2VyLCB1cHBlcikNCmBgYA0KVGhpcyBpcyBhbiBpbXBvcnRhbnQgaW5mZXJlbmNlIHRoYXQgd2XigJl2ZSBqdXN0IG1hZGU6IGV2ZW4gdGhvdWdoIHdlIGRvbuKAmXQga25vdyB3aGF0IHRoZSBmdWxsIHBvcHVsYXRpb24gbG9va3MgbGlrZSwgd2XigJlyZSA5NSUgY29uZmlkZW50IHRoYXQgdGhlIHRydWUgYXZlcmFnZSBzaXplIG9mIGhvdXNlcyBpbiBgQW1lc2AgbGllcyBiZXR3ZWVuIHRoZSB2YWx1ZXMgbG93ZXIgYW5kIHVwcGVyLiBUaGVyZSBhcmUgYSBmZXcgY29uZGl0aW9ucyB0aGF0IG11c3QgYmUgbWV0IGZvciB0aGlzIGludGVydmFsIHRvIGJlIHZhbGlkLg0KDQoqKllvdXIgQ2hhbGxlbmdlOioqIA0KDQoqIEZvciB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbCB0byBiZSB2YWxpZCwgdGhlIHNhbXBsZSBtZWFuIG11c3QgYmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgYW5kIGhhdmUgc3RhbmRhcmQgZXJyb3IgJCBzL1xzcXJ0e259JC4gV2hhdCBjb25kaXRpb25zIG11c3QgYmUgbWV0IGZvciB0aGlzIHRvIGJlIHRydWU/DQpObywgdGhpcyBpcyBhIHJhbmRvbSBzYW1wbGUgb2YgNjAgcmFuZG9tbHkgc2VsZWN0ZWQgb2JzZXJ2YXRpb25zLiBUaGUgcXVlc3Rpb24gaGVyZSB3aWxsIGJlIGhvdyBzaW1pbGFyIGlzIHNpbWlsYXI/IG9yIGhvdyBuZWFyIGlzIG5lYXI/LCB0aGVuIGlmIHRoZSB2YWx1ZXMgYXJlIG5lYXIgdGhlbiB5ZXMsIGl0IGNvdWxkIGhhcHBlbg0KKiBXaGF0IGRvZXMg4oCcOTUlIGNvbmZpZGVuY2XigJ0gbWVhbj8NCklzIHRoZSBjb25maWRlbmNlIGludGVydmFsIGxldmVsIGZvciB0aGUgbm9ybWFsIG1vZGVsIHdpdGggc3RhbmRhcmQgZXJyb3IgU0UuIFRoZSBjb25maWRlbmNlIGludGVydmFsIGZvciB0aGUgcG9wdWxhdGlvbiBwYXJhbWV0ZXIgaXMgDQpwb2ludGVzdGltYXRlwrF64ouFU0Ugd2hlcmUgeiBjb3JyZXNwb25kcyB0byB0aGUgY29uZmlkZW5jZSBsZXZlbCBzZWxlY3RlZC4NCiogRG9lcyB5b3VyIGNvbmZpZGVuY2UgaW50ZXJ2YWwgY2FwdHVyZSB0aGUgdHJ1ZSBhdmVyYWdlIHNpemUgb2YgaG91c2VzIGluIGBBbWVzYD8gSWYgeW91IGFyZSB3b3JraW5nIG9uIHRoaXMgY2FzZSBzdHVkeSwgZG9lcyB5b3VyIGNsYXNzbWF0ZeKAmXMgaW50ZXJ2YWwgY2FwdHVyZSB0aGlzIHZhbHVlPw0KWWVzLCB0aGUgYWJvdmUgY29uZmlkZW5jZSBpbnRlcnZhbCBjYXB0dXJlIHRoZSB0cnVlIGF2ZXJhZ2Ugc2l6ZSBvZiBob3VzZXMgaW4gQW1lcy4gSSB3b3VsZCBleHBlY3QgbXkgY2xhc3NtYXRlIHRvIGNhcHR1cmUgdGhlIG1lYW4gdmFsdWUgb24gdGhlaXIgbGFiIGFzIHdlbGwuDQoNCg0KIyMgU2ltdWxhdGlvbiANCg0KbGV04oCZcyBzaW11bGF0ZSBhIHNjZW5hcmlvIG9mIGNvbmZpZGVuY2UgaW50ZXJ2YWwgaW4gY2xhc3Nyb29tIHRvIGNhcHR1cmUgdGhlIHRydWUgYXZlcmFnZSBzaXplIG9mIGhvdXNlcyBpbiBgQW1lc2AuIFN1cHBvc2Ugd2UgaGF2ZSAxMDAgc3R1ZGVudHMgaW4gdGhlIGNsYXNzcm9vbS4gDQoNCmBgYHtyfQ0KY291bnQgPSAwDQpmb3IgKGkgaW4gMToxMDApIHsNCiAgc2FtcCA8LSBzYW1wbGUocG9wdWxhdGlvbiw2MCkNCiAgc2FtcF9tZWFuPC0gbWVhbihzYW1wKQ0KICBzZSA8LSBzZChzYW1wKS9zcXJ0KDYwKQ0KICBsb3dlciA8LSBzYW1wX21lYW4tMS45NipzZQ0KICB1cHBlciA8LSBzYW1wX21lYW4rMS45NipzZQ0KICBpZiAoKGxvd2VyIDw9IDE0OTkuNjkpICYgKHVwcGVyID49IDE0OTkuNjkpKSB7DQogICAgY291bnQgPSBjb3VudCsxDQogIH0gIA0KfQ0KY291bnQNCmBgYA0KVXNpbmcgUiwgd2XigJlyZSBnb2luZyB0byByZWNyZWF0ZSBtYW55IHNhbXBsZXMgdG8gbGVhcm4gbW9yZSBhYm91dCBob3cgc2FtcGxlIG1lYW5zIGFuZCBjb25maWRlbmNlIGludGVydmFscyB2YXJ5IGZyb20gb25lIHNhbXBsZSB0byBhbm90aGVyLiBMb29wcyBjb21lIGluIGhhbmR5IGhlcmUgKElmIHlvdSBhcmUgdW5mYW1pbGlhciB3aXRoIGxvb3BzLCByZXZpZXcgdGhlIFNhbXBsaW5nIERpc3RyaWJ1dGlvbiBMYWIpLg0KDQpIZXJlIGlzIHRoZSByb3VnaCBvdXRsaW5lOg0KDQoqIE9idGFpbiBhIHJhbmRvbSBzYW1wbGUuDQoqIENhbGN1bGF0ZSBhbmQgc3RvcmUgdGhlIHNhbXBsZeKAmXMgbWVhbiBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uLg0KKiBSZXBlYXQgc3RlcHMgKDEpIGFuZCAoMikgNTAgdGltZXMuDQoqIFVzZSB0aGVzZSBzdG9yZWQgc3RhdGlzdGljcyB0byBjYWxjdWxhdGUgbWFueSBjb25maWRlbmNlIGludGVydmFscy4NCg0KQnV0IGJlZm9yZSB3ZSBkbyBhbGwgb2YgdGhpcywgd2UgbmVlZCB0byBmaXJzdCBjcmVhdGUgZW1wdHkgdmVjdG9ycyB3aGVyZSB3ZSBjYW4gc2F2ZSB0aGUgbWVhbnMgYW5kIHN0YW5kYXJkIGRldmlhdGlvbnMgdGhhdCB3aWxsIGJlIGNhbGN1bGF0ZWQgZnJvbSBlYWNoIHNhbXBsZS4gQW5kIHdoaWxlIHdl4oCZcmUgYXQgaXQsIGxldOKAmXMgYWxzbyBzdG9yZSB0aGUgZGVzaXJlZCBzYW1wbGUgc2l6ZSBhcyAkbiQuDQoNCg0KYGBge3J9DQpzYW1wX21lYW4gPC0gcmVwKE5BLCA1MCkNCnNhbXBfc2QgPC0gcmVwKE5BLCA1MCkNCm4gPC0gNjANCm4NCmBgYA0KDQpOb3cgd2XigJlyZSByZWFkeSBmb3IgdGhlIGxvb3Agd2hlcmUgd2UgY2FsY3VsYXRlIHRoZSBtZWFucyBhbmQgc3RhbmRhcmQgZGV2aWF0aW9ucyBvZiA1MCByYW5kb20gc2FtcGxlcy4NCg0KYGBge3J9DQpmb3IoaSBpbiAxOjUwKXsNCiAgc2FtcCA8LSBzYW1wbGUocG9wdWxhdGlvbiwgbikgIyBvYnRhaW4gYSBzYW1wbGUgb2Ygc2l6ZSBuID0gNjAgZnJvbSB0aGUgcG9wdWxhdGlvbg0KICBzYW1wX21lYW5baV0gPC0gbWVhbihzYW1wKSAgICAjIHNhdmUgc2FtcGxlIG1lYW4gaW4gaXRoIGVsZW1lbnQgb2Ygc2FtcF9tZWFuDQogIHNhbXBfc2RbaV0gPC0gc2Qoc2FtcCkgICAgICAgICMgc2F2ZSBzYW1wbGUgc2QgaW4gaXRoIGVsZW1lbnQgb2Ygc2FtcF9zZA0KfQ0Kc2FtcA0KYGBgDQoNCkxhc3RseSwgd2UgY29uc3RydWN0IHRoZSBjb25maWRlbmNlIGludGVydmFscy4NCg0KYGBge3J9DQpsb3dlcl92ZWN0b3IgPC0gc2FtcF9tZWFuIC0gMS45NiAqIHNhbXBfc2QgLyBzcXJ0KG4pIA0KdXBwZXJfdmVjdG9yIDwtIHNhbXBfbWVhbiArIDEuOTYgKiBzYW1wX3NkIC8gc3FydChuKQ0KYGBgDQoNCg0KTG93ZXIgYm91bmRzIG9mIHRoZXNlIDUwIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGFyZSBzdG9yZWQgaW4gYGxvd2VyX3ZlY3RvcmAsIGFuZCB0aGUgdXBwZXIgYm91bmRzIGFyZSBpbiBgdXBwZXJfdmVjdG9yYC4gTGV04oCZcyB2aWV3IHRoZSBmaXJzdCBpbnRlcnZhbC4NCg0KYGBge3J9DQpjKGxvd2VyX3ZlY3RvclsxXSwgdXBwZXJfdmVjdG9yWzFdKQ0KYGBgDQpgYGB7cn0NCiMgY29uZmlkZW50aWFsIGludGVydmFsIHZpc3VhbGl6YXRpb24NCnBsb3RfY2kobG93ZXJfdmVjdG9yLCB1cHBlcl92ZWN0b3IsIG1lYW4ocG9wdWxhdGlvbikpDQojIEZvciBhIDk1JSBjb25maWRlbmNlIGludGVydmFsLCB0aGUgY3JpdGljYWwgdmFsdWUgaXMgLTEuOTU5OTY0IGFuZCAxLjk1OTk2NC4NCnFub3JtKCgxLTAuOTUpLzIpDQpxbm9ybSgoMSswLjk1KS8yKQ0KYGBgDQoNCioqWW91ciBDaGFsbGVuZ2U6KiogDQoNCiogV2hhdCBwcm9wb3J0aW9uIG9mIHlvdXIgY29uZmlkZW5jZSBpbnRlcnZhbHMgaW5jbHVkZSB0aGUgdHJ1ZSBwb3B1bGF0aW9uIG1lYW4/IElzIHRoaXMgcHJvcG9ydGlvbiBleGFjdGx5IGVxdWFsIHRvIHRoZSBjb25maWRlbmNlIGxldmVsPyBJZiBub3QsIGV4cGxhaW4gd2h5Lg0KYGBge3J9DQpwbG90X2NpKGxvd2VyX3ZlY3RvciwgdXBwZXJfdmVjdG9yLCBtZWFuKHBvcHVsYXRpb24pKQ0KVmVjdG9yIDwtIGRhdGEuZnJhbWUobG93ZXJfdmVjdG9yLCB1cHBlcl92ZWN0b3IpDQptZWFucCA8LSBtZWFuKHBvcHVsYXRpb24pDQoNCmxlZnQgPC0gc3VtKFZlY3RvciR1cHBlcl92ZWN0b3IgPCBtZWFucCkNCnJpZ2h0IDwtIHN1bShWZWN0b3IkbG93ZXJfdmVjdG9yID4gbWVhbnApDQoNCm5vTWVhbkluY2x1ZGVkIDwtIGxlZnQgKyByaWdodA0Kbm9NZWFuSW5jbHVkZWQNCmBgYA0KDQpgYGB7cn0NCnByb3BvcnRpb24gPC0gcm91bmQobm9NZWFuSW5jbHVkZWQvbiAsMikNCnByb3BvcnRpb24NCmBgYA0KSW4gdGhpcyBjYXNlIG9ubHkgOTUlIGluY2x1ZGUgdGhlIHBvcHVsYXRpb24gbWVhbi4gVGhpcyBwcm9wb3J0aW9uIGlzIG5vdCBuZWNlc2FyaWx5IHRoZSBzYW1lIGFzIG91ciBjb25maWRlbmNlIGxldmVsIGJ1dCB2ZXJ5IG5lYXIgYXBwcm94aW1hdGlvbiBvZiBpdC4NCg0KKiBQaWNrIGEgY29uZmlkZW5jZSBsZXZlbCBvZiB5b3VyIGNob29zaW5nLCBwcm92aWRlZCBpdCBpcyA5OSUuIFdoYXQgaXMgdGhlIGFwcHJvcHJpYXRlIGNyaXRpY2FsIHZhbHVlPw0KYGBge3J9DQpsb3dlcl92ZWN0b3IgPC0gc2FtcF9tZWFuIC0gMC44NCAqIHNhbXBfc2QgLyBzcXJ0KG4pIA0KdXBwZXJfdmVjdG9yIDwtIHNhbXBfbWVhbiArIDAuODQgKiBzYW1wX3NkIC8gc3FydChuKQ0KcGxvdF9jaShsb3dlcl92ZWN0b3IsIHVwcGVyX3ZlY3RvciwgbWVhbihwb3B1bGF0aW9uKSkNCmBgYA0KDQpgYGB7cn0NClZlY3RvciA8LSBkYXRhLmZyYW1lKGxvd2VyX3ZlY3RvciwgdXBwZXJfdmVjdG9yKQ0KbWVhbnAgPC0gbWVhbihwb3B1bGF0aW9uKQ0KDQpsZWZ0IDwtIHN1bShWZWN0b3IkdXBwZXJfdmVjdG9yIDwgbWVhbnApDQpyaWdodCA8LSBzdW0oVmVjdG9yJGxvd2VyX3ZlY3RvciA+IG1lYW5wKQ0KDQpub01lYW5JbmNsdWRlZCA8LSBsZWZ0ICsgcmlnaHQNCm5vTWVhbkluY2x1ZGVkDQpgYGANCg0KYGBge3J9DQpwcm9wb3J0aW9uIDwtIHJvdW5kKG5vTWVhbkluY2x1ZGVkL24gLDIpDQpwcm9wb3J0aW9uDQpgYGANCkluIHRoaXMgY2FzZSBvbmx5IDczJSBpbmNsdWRlIHRoZSBwb3B1bGF0aW9uIG1lYW4uIFRoaXMgcHJvcG9ydGlvbiBpcyBub3QgbmVjZXNhcmlseSB0aGUgc2FtZSBhcyBvdXIgY29uZmlkZW5jZSBsZXZlbCBidXQgdmVyeSBuZWFyIGFwcHJveGltYXRpb24gb2YgaXQuDQoNCg0KDQoNCg0KDQoNCg0K