Previously we talked about how a sample proportion varies from sample to sample and were introduced to the bootstrap technique. Now, we would like to apply that to linear models to learn about how coefficient estimates vary from sample to sample.
Sampling Distributions
We will examine a really simple model that uses log(sqft_living)
to explain log(price)
. We are going to think of this as the “population model”.
kc_house_data %>%
ggplot(aes(x=log(sqft_living), y = log(price))) +
geom_point(alpha=.5, size = .2)
lm_simple <- lm(log(price) ~ log(sqft_living),
data=kc_house_data)
tidy(lm_simple)
The “population model” is:
extract_eq(lm_simple,
ital_vars = TRUE,
wrap = TRUE,
use_coefs = TRUE)
\[
\begin{aligned}
\widehat{log(price)} &= 6.74 + 0.84(log(sqft\_living))
\end{aligned}
\]
Let’s plot that line on the scatterplot of the data.
augment(lm_simple, data=kc_house_data) %>%
ggplot(aes(x=log(sqft_living), y = log(price))) +
geom_point(alpha = .5, size = .2) +
geom_line(aes(y=.fitted), color="darkred")
Now let’s say that I was going to collect this data myself and I didn’t have time (or the technical skills) to get all 21,613 observations. So, instead, I collect a sample of 500 observations.
I will mimic this by sampling from the entire dataset using the sample_n()
function. Reminder: The set.seed()
function at the beginning allows you to replicate the random sampling process so that you get the same random sample every time the code runs (including when you knit the document). This also means that if someone else uses that same seed, they will get the same result, as long as they started with the same data. It is very important to use set.seed()
anytime we conduct a random process so that we can replicate it. It does not matter what number we put in there.
Then, fit the model that uses log(sqft_living)
to explain log(price)
. How does this model compare to the model that used all the data?
set.seed(327)
samp1 <- kc_house_data %>%
sample_n(size=500)
lm_samp1 <- lm(log(price) ~ log(sqft_living),
data=samp1)
tidy(lm_samp1)
extract_eq(lm_samp1,
ital_vars = TRUE,
wrap = TRUE,
use_coefs = TRUE)
\[
\begin{aligned}
\widehat{log(price)} &= 6.59 + 0.86(log(sqft\_living))
\end{aligned}
\]
Let’s plot the lines. I am going to use the geom_smooth
function to do this because it will come in handy later.
augment(lm_simple, data=kc_house_data) %>%
ggplot(aes(x=log(sqft_living), y = log(price))) +
geom_point(alpha=.2, size = .2) +
geom_point(data = samp1, color="lightblue", alpha = .2, size = .2) +
geom_line(aes(y=.fitted), color="darkred") +
geom_smooth(data = samp1, method = "lm", se = FALSE,
color="lightblue", size=.5)
Let’s take another sample of size 500 and fit another line. Use a different seed from the first sample so they are different random samples.
set.seed(300)
samp2 <- kc_house_data %>%
sample_n(size=500)
lm_samp2 <- lm(log(price) ~ log(sqft_living),
data=samp2)
tidy(lm_samp2)
extract_eq(lm_samp2,
ital_vars = TRUE,
wrap = TRUE,
use_coefs = TRUE)
\[
\begin{aligned}
\widehat{log(price)} &= 6.72 + 0.84(log(sqft\_living))
\end{aligned}
\]
And plot this line …
augment(lm_simple, data=kc_house_data) %>%
ggplot(aes(x=log(sqft_living), y = log(price))) +
geom_point(alpha=.2, size = .2) +
geom_line(aes(y=.fitted), color="darkred") +
geom_smooth(data = samp1, method = "lm", se = FALSE,
color="lightblue", size = .5) +
geom_smooth(data = samp2, method = "lm", se = FALSE,
color="lightblue", size = .5)
## `geom_smooth()` using formula 'y ~ x'
## `geom_smooth()` using formula 'y ~ x'
Now, in order to understand sampling variability we need to be able to this many times. Rather than having us run different models one by one to learn about the variability of the coefficients, we can use simulation to do that for us.
Like in the Reese’s Pieces activity, we will use the rep_sample_n()
function to take multiple repeated samples. Below we take 200 samples of size 500 from the “population”, kc_house_data
. We are taking samples without replacement this time because we are pretending that we are sampling from the population, like when we sampled Reese’s Pieces using the applets. How many observations are in samples_200
?
set.seed(1113)
samples_200 <- rep_sample_n(kc_house_data, #data we're sampling from
size = 500, #size of each sample
reps = 200, #how many samples to take
replace = FALSE #with or without
#replacement?
)
GOAL: For each sample, we would like to fit a model that uses log(sqft_living)
to predict log(price)
. We would like to understand how the intercept and slope vary from sample to sample.
First, let’s do this graphically. What do you observe?
#This first section plots the "population" points:
augment(lm_simple, data=kc_house_data) %>%
ggplot(aes(x=log(sqft_living), y = log(price))) +
geom_point(alpha=.2, color="darkgray", size = .2) +
#This code plots each of the lines
geom_smooth(data = samples_200, #Use the samples_200 data
aes(group = replicate), #"For each replicate"
method = "lm", se = FALSE, #Use lm() to fit a model
#where log(sqft_living)
#explains log(price)
color="lightblue", size = .5) + #color the lines lightblue
geom_line(aes(y=.fitted), color="darkred") #add the "population" line
## `geom_smooth()` using formula 'y ~ x'
Now, let’s actually fit the model 200 times. Look carefully at the output. What is the code doing on the line with “???”?
model_200_times <-
samples_200 %>% #start with the 200 samples of size 500
group_by(replicate) %>% #for each replicate
summarize(lm(log(price) ~ log(sqft_living)) %>% tidy()) %>% #???
ungroup() #ungroup the data - good to do this when finished with
## `summarise()` has grouped output by 'replicate'. You can override using the `.groups` argument.
#grouped calculations
model_200_times
We can now look at the sampling distributions of the estimated slope and intercept. These show us how we expect those statistics to vary from sample to sample. I also put vertical lines where the actual intercept and slope (from the “population model”) are located.
#slope
model_200_times %>% #200 models
filter(term == "log(sqft_living)") %>% #filter to the term we're interested in
ggplot(aes(x = estimate)) +
geom_histogram(bins = 20) + #create a histogram of the coefficients
geom_vline(xintercept = 0.8351142, color = "darkred") +
labs(title = bquote("Distribution of" ~ hat(beta)[1]))
#intercept
model_200_times %>%
filter(term == "(Intercept)") %>% # LOOK CAREFULLY!!
ggplot(aes(x = estimate)) +
geom_histogram(bins = 20) +
geom_vline(xintercept = 6.7431084, color = "darkred") +
labs(title = bquote("Distribution of" ~ hat(beta)[0]))
YOUR TURN!
What is an observation in the histograms above?
How would you describe these distributions in terms of shape?
Compute the mean and standard deviation of the slope and intercept estimates. The standard deviation here has a special name, a standard error, or SE for short. A standard error is the standard deviation of a statistic. I’ve started the code for you below. Remove the eval=FALSE
.
model_200_times %>%
group_by(___) %>% # We want to compute the mean and standard deviation for each what?
summarize(mean_est = ___, # The mean of the estimate
se_est = ___) # The standard deviation of the estimate
- What would happen to the sampling distribution of the slope if, instead of taking samples of size 500, we took samples of size 100? Redo the simulation taking samples of size 100 rather than 500. I have started the code for you below. Fill in the “???”’s and also compute the mean and standard error. Remove the
eval=FALSE
.
#Sample from the "population"
set.seed(327)
size100_200 <- rep_sample_n(kc_house_data, #data we're sampling from
size = ???, #size of each sample
reps = ???, #how many samples to take
replace = ??? #with or without
#replacement?
)
#Fit the model 200 times
model_size100_200_times <-
size100_200 %>% #start with the 200 samples of size 500
group_by(???) %>% #for each replicate
summarize(lm(??? ~ ???) %>% tidy()) %>% #???
ungroup() #ungroup the data - good to do this when finished with
#grouped calculations
model_size100_200_times
#Create the histogram of the slopes
model_size100_200_times %>% #200 models
filter(term == "???") %>% #filter to the term we're interested in
ggplot(aes(x = estimate)) +
geom_histogram(bins = 20) + #create a histogram of the coefficients
geom_vline(xintercept = 0.8351142, color = "darkred") +
labs(title = bquote("Distribution of" ~ hat(beta)[1]))
- Now try doing what you did in #3 with samples of size 1000. How does that change the distribution?
LS0tCnRpdGxlOiAiU2FtcGxpbmcgdmFyaWF0aW9uIGluIExpbmVhciBNb2RlbHMiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGRmX3ByaW50OiBwYWdlZAogICAgY29kZV9kb3dubG9hZDogdHJ1ZQotLS0KCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpICAgICMgZm9yIHBsb3R0aW5nIGFuZCBzdW1tYXJpemluZwpsaWJyYXJ5KGVxdWF0aW9tYXRpYykgIyBmb3IgbW9kZWwgZXF1YXRpb25zCmxpYnJhcnkoZ2dyaWRnZXMpICAgICAjIGZvciByaWRnZSBwbG90cwpsaWJyYXJ5KGdnbW9zYWljKSAgICAgIyBmb3IgbW9zYWljIHBsb3RzCmxpYnJhcnkobW9kZXJuZGl2ZSkgICAjIGZvciBuaWNlIG1vZGVsIG91dHB1dApsaWJyYXJ5KGJyb29tKSAgICAgICAgIyBmb3IgbmljZSBtb2RlbCBvdXRwdXQgCmxpYnJhcnkoaW5mZXIpICAgICAgICAjIGZvciBtYWtpbmcgaW5mZXJlbmNlcyBhYm91dCBtb2RlbHMKdGhlbWVfc2V0KHRoZW1lX21pbmltYWwoKSkgI2NoYW5nZXMgdGhlIHRoZW1lIG9mIGdncGxvdHMgdG8gdGhlbWVfbWluaW1hbCwgbXkgcGVyc29uYWwgZmF2b3JpdGUKYGBgCgoKPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtc3VjY2VzcyI+CiAgPHN0cm9uZz5HT0FMOjwvc3Ryb25nPgoKQnkgdGhlIGVuZCBvZiB0aGVzZSBub3RlcyBhbmQgYWN0aXZpdGllcywgeW91IHNob3VsZCBiZSBhYmxlIHRvIHBlcmZvcm0gdGhlIGZvbGxvd2luZyB0YXNrcy4KCiogVXNlIGEgYm9vdHN0cmFwIGRpc3RyaWJ1dGlvbiB0byB1bmRlcnN0YW5kIGhvdyBtb2RlbCBjb2VmZmljaWVudHMgdmFyeSBmcm9tIHNhbXBsZSB0byBzYW1wbGUuICAKKiBBcHBseSBib290c3RyYXAgY29kZSBJIGhhdmUgd3JpdHRlbiB0byBhIG5ldyBtb2RlbC4gIAoqIENyZWF0ZSBhIGhpc3RvZ3JhbSB0byByZXByZXNlbnQgdGhlIGJvb3RzdHJhcCBkaXN0cmlidXRpb24gZm9yIGEgbW9kZWwgY29lZmZpY2llbnQuICAKCjwvZGl2PgoKClByZXZpb3VzbHkgd2UgdGFsa2VkIGFib3V0IGhvdyBhIHNhbXBsZSBwcm9wb3J0aW9uIHZhcmllcyBmcm9tIHNhbXBsZSB0byBzYW1wbGUgYW5kIHdlcmUgaW50cm9kdWNlZCB0byB0aGUgYm9vdHN0cmFwIHRlY2huaXF1ZS4gTm93LCB3ZSB3b3VsZCBsaWtlIHRvIGFwcGx5IHRoYXQgdG8gbGluZWFyIG1vZGVscyB0byBsZWFybiBhYm91dCBob3cgY29lZmZpY2llbnQgZXN0aW1hdGVzIHZhcnkgZnJvbSBzYW1wbGUgdG8gc2FtcGxlLiAKCgpMZXQncyBvbmNlIGFnYWluIHVzZSB0aGUgYGtjX2hvdXNlX2RhdGFgLCBhIG1vZGlmaWVkIHZlcnNpb24gb2YgdGhlIGBob3VzZV9kYXRhYCBmcm9tIHRoZSBgbW9kZXJuZGl2ZWAgbGlicmFyeS4gV2UgYXJlIGdvaW5nIHRvIHByZXRlbmQgdGhhdCB0aGlzIGlzIHRoZSBlbnRpcmUgKipwb3B1bGF0aW9uKiogb2YgaG91c2VzLgoKYGBge3IsIGVycm9yPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQprY19ob3VzZV9kYXRhIDwtCiAgaG91c2VfcHJpY2VzICU+JSAKICBmaWx0ZXIoYmVkcm9vbXM8PTUsIGJlZHJvb21zPjApICU+JSAKICBtdXRhdGUoZ3JhZGVfQ0FUID0gZmN0X3JlbGV2ZWwoaWZlbHNlKGdyYWRlICVpbiUgIjEiOiI3IiwgIkxvdyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ3JhZGUgPT0gIjgiLCAiTWVkaXVtIiwiSGlnaCIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJMb3ciLCAiTWVkaXVtIiwgIkhpZ2giKSwKICAgICAgICAgYWdlPTIwMTUteXJfYnVpbHQpCgpgYGAKCgojIyBTYW1wbGluZyBEaXN0cmlidXRpb25zCgpXZSB3aWxsIGV4YW1pbmUgYSByZWFsbHkgc2ltcGxlIG1vZGVsIHRoYXQgdXNlcyBgbG9nKHNxZnRfbGl2aW5nKWAgdG8gZXhwbGFpbiBgbG9nKHByaWNlKWAuIFdlIGFyZSBnb2luZyB0byB0aGluayBvZiB0aGlzIGFzIHRoZSAicG9wdWxhdGlvbiBtb2RlbCIuIAoKYGBge3J9CmtjX2hvdXNlX2RhdGEgJT4lIAogIGdncGxvdChhZXMoeD1sb2coc3FmdF9saXZpbmcpLCB5ID0gbG9nKHByaWNlKSkpICsKICBnZW9tX3BvaW50KGFscGhhPS41LCBzaXplID0gLjIpCmBgYAoKCmBgYHtyfQpsbV9zaW1wbGUgPC0gbG0obG9nKHByaWNlKSB+IGxvZyhzcWZ0X2xpdmluZyksCiAgICAgICAgICAgICAgICBkYXRhPWtjX2hvdXNlX2RhdGEpCnRpZHkobG1fc2ltcGxlKQpgYGAKClRoZSAicG9wdWxhdGlvbiBtb2RlbCIgaXM6CgpgYGB7cn0KZXh0cmFjdF9lcShsbV9zaW1wbGUsIAogICAgICAgICAgIGl0YWxfdmFycyA9IFRSVUUsIAogICAgICAgICAgIHdyYXAgPSBUUlVFLCAKICAgICAgICAgICB1c2VfY29lZnMgPSBUUlVFKQpgYGAKCgpMZXQncyBwbG90IHRoYXQgbGluZSBvbiB0aGUgc2NhdHRlcnBsb3Qgb2YgdGhlIGRhdGEuCgpgYGB7cn0KYXVnbWVudChsbV9zaW1wbGUsIGRhdGE9a2NfaG91c2VfZGF0YSkgJT4lIAogIGdncGxvdChhZXMoeD1sb2coc3FmdF9saXZpbmcpLCB5ID0gbG9nKHByaWNlKSkpICsKICBnZW9tX3BvaW50KGFscGhhID0gLjUsIHNpemUgPSAuMikgKwogIGdlb21fbGluZShhZXMoeT0uZml0dGVkKSwgY29sb3I9ImRhcmtyZWQiKQpgYGAKCgoKTm93IGxldCdzIHNheSB0aGF0IEkgd2FzIGdvaW5nIHRvIGNvbGxlY3QgdGhpcyBkYXRhIG15c2VsZiBhbmQgSSBkaWRuJ3QgaGF2ZSB0aW1lIChvciB0aGUgdGVjaG5pY2FsIHNraWxscykgdG8gZ2V0IGFsbCAyMSw2MTMgb2JzZXJ2YXRpb25zLiBTbywgaW5zdGVhZCwgSSBjb2xsZWN0IGEgc2FtcGxlIG9mIDUwMCBvYnNlcnZhdGlvbnMuIAoKSSB3aWxsIG1pbWljIHRoaXMgYnkgc2FtcGxpbmcgZnJvbSB0aGUgZW50aXJlIGRhdGFzZXQgdXNpbmcgdGhlIGBzYW1wbGVfbigpYCBmdW5jdGlvbi4gKlJlbWluZGVyKjogIFRoZSBgc2V0LnNlZWQoKWAgZnVuY3Rpb24gYXQgdGhlIGJlZ2lubmluZyBhbGxvd3MgeW91IHRvIHJlcGxpY2F0ZSB0aGUgcmFuZG9tIHNhbXBsaW5nIHByb2Nlc3Mgc28gdGhhdCB5b3UgZ2V0IHRoZSBzYW1lIHJhbmRvbSBzYW1wbGUgZXZlcnkgdGltZSB0aGUgY29kZSBydW5zIChpbmNsdWRpbmcgd2hlbiB5b3Uga25pdCB0aGUgZG9jdW1lbnQpLiBUaGlzIGFsc28gbWVhbnMgdGhhdCBpZiBzb21lb25lIGVsc2UgdXNlcyB0aGF0IHNhbWUgc2VlZCwgdGhleSB3aWxsIGdldCB0aGUgc2FtZSByZXN1bHQsIGFzIGxvbmcgYXMgdGhleSBzdGFydGVkIHdpdGggdGhlIHNhbWUgZGF0YS4gSXQgaXMgdmVyeSBpbXBvcnRhbnQgdG8gdXNlIGBzZXQuc2VlZCgpYCBhbnl0aW1lIHdlIGNvbmR1Y3QgYSByYW5kb20gcHJvY2VzcyBzbyB0aGF0IHdlIGNhbiByZXBsaWNhdGUgaXQuIEl0IGRvZXMgbm90IG1hdHRlciB3aGF0IG51bWJlciB3ZSBwdXQgaW4gdGhlcmUuCgpUaGVuLCBmaXQgdGhlIG1vZGVsIHRoYXQgdXNlcyBgbG9nKHNxZnRfbGl2aW5nKWAgdG8gZXhwbGFpbiBgbG9nKHByaWNlKWAuICoqSG93IGRvZXMgdGhpcyBtb2RlbCBjb21wYXJlIHRvIHRoZSBtb2RlbCB0aGF0IHVzZWQgYWxsIHRoZSBkYXRhPyoqCgpgYGB7cn0Kc2V0LnNlZWQoMzI3KQoKc2FtcDEgPC0ga2NfaG91c2VfZGF0YSAlPiUgCiAgc2FtcGxlX24oc2l6ZT01MDApIAoKbG1fc2FtcDEgPC0gbG0obG9nKHByaWNlKSB+IGxvZyhzcWZ0X2xpdmluZyksIAogICAgICAgICAgICAgICBkYXRhPXNhbXAxKQoKdGlkeShsbV9zYW1wMSkKYGBgCgpgYGB7cn0KZXh0cmFjdF9lcShsbV9zYW1wMSwgCiAgICAgICAgICAgaXRhbF92YXJzID0gVFJVRSwgCiAgICAgICAgICAgd3JhcCA9IFRSVUUsIAogICAgICAgICAgIHVzZV9jb2VmcyA9IFRSVUUpCmBgYAoKCkxldCdzIHBsb3QgdGhlIGxpbmVzLiBJIGFtIGdvaW5nIHRvIHVzZSB0aGUgYGdlb21fc21vb3RoYCBmdW5jdGlvbiB0byBkbyB0aGlzIGJlY2F1c2UgaXQgd2lsbCBjb21lIGluIGhhbmR5IGxhdGVyLgoKYGBge3IsIG1lc3NhZ2U9RkFMU0V9CmF1Z21lbnQobG1fc2ltcGxlLCBkYXRhPWtjX2hvdXNlX2RhdGEpICU+JSAKICBnZ3Bsb3QoYWVzKHg9bG9nKHNxZnRfbGl2aW5nKSwgeSA9IGxvZyhwcmljZSkpKSArCiAgZ2VvbV9wb2ludChhbHBoYT0uMiwgc2l6ZSA9IC4yKSArCiAgZ2VvbV9wb2ludChkYXRhID0gc2FtcDEsIGNvbG9yPSJsaWdodGJsdWUiLCBhbHBoYSA9IC4yLCBzaXplID0gLjIpICsKICBnZW9tX2xpbmUoYWVzKHk9LmZpdHRlZCksIGNvbG9yPSJkYXJrcmVkIikgKwogIGdlb21fc21vb3RoKGRhdGEgPSBzYW1wMSwgbWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgCiAgICAgICAgICAgICAgY29sb3I9ImxpZ2h0Ymx1ZSIsIHNpemU9LjUpCmBgYAoKTGV0J3MgdGFrZSBhbm90aGVyIHNhbXBsZSBvZiBzaXplIDUwMCBhbmQgZml0IGFub3RoZXIgbGluZS4gVXNlIGEgZGlmZmVyZW50IHNlZWQgZnJvbSB0aGUgZmlyc3Qgc2FtcGxlIHNvIHRoZXkgYXJlIGRpZmZlcmVudCByYW5kb20gc2FtcGxlcy4KCmBgYHtyfQpzZXQuc2VlZCgzMDApCgpzYW1wMiA8LSBrY19ob3VzZV9kYXRhICU+JSAKICBzYW1wbGVfbihzaXplPTUwMCkgCgpsbV9zYW1wMiA8LSBsbShsb2cocHJpY2UpIH4gbG9nKHNxZnRfbGl2aW5nKSwgCiAgICAgICAgICAgICAgIGRhdGE9c2FtcDIpCgp0aWR5KGxtX3NhbXAyKQpgYGAKCmBgYHtyfQpleHRyYWN0X2VxKGxtX3NhbXAyLCAKICAgICAgICAgICBpdGFsX3ZhcnMgPSBUUlVFLCAKICAgICAgICAgICB3cmFwID0gVFJVRSwgCiAgICAgICAgICAgdXNlX2NvZWZzID0gVFJVRSkKYGBgCgpBbmQgcGxvdCB0aGlzIGxpbmUgLi4uCgpgYGB7cn0KYXVnbWVudChsbV9zaW1wbGUsIGRhdGE9a2NfaG91c2VfZGF0YSkgJT4lIAogIGdncGxvdChhZXMoeD1sb2coc3FmdF9saXZpbmcpLCB5ID0gbG9nKHByaWNlKSkpICsKICBnZW9tX3BvaW50KGFscGhhPS4yLCBzaXplID0gLjIpICsKICBnZW9tX2xpbmUoYWVzKHk9LmZpdHRlZCksIGNvbG9yPSJkYXJrcmVkIikgKwogIGdlb21fc21vb3RoKGRhdGEgPSBzYW1wMSwgbWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgCiAgICAgICAgICAgICAgY29sb3I9ImxpZ2h0Ymx1ZSIsIHNpemUgPSAuNSkgKwogIGdlb21fc21vb3RoKGRhdGEgPSBzYW1wMiwgbWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgCiAgICAgICAgICAgICAgY29sb3I9ImxpZ2h0Ymx1ZSIsIHNpemUgPSAuNSkgCmBgYAoKTm93LCBpbiBvcmRlciB0byB1bmRlcnN0YW5kIHNhbXBsaW5nIHZhcmlhYmlsaXR5IHdlIG5lZWQgdG8gYmUgYWJsZSB0byB0aGlzIG1hbnkgdGltZXMuIFJhdGhlciB0aGFuIGhhdmluZyB1cyBydW4gZGlmZmVyZW50IG1vZGVscyBvbmUgYnkgb25lIHRvIGxlYXJuIGFib3V0IHRoZSB2YXJpYWJpbGl0eSBvZiB0aGUgY29lZmZpY2llbnRzLCB3ZSBjYW4gdXNlIHNpbXVsYXRpb24gdG8gZG8gdGhhdCBmb3IgdXMuIAoKTGlrZSBpbiB0aGUgUmVlc2UncyBQaWVjZXMgYWN0aXZpdHksIHdlIHdpbGwgdXNlIHRoZSBgcmVwX3NhbXBsZV9uKClgIGZ1bmN0aW9uIHRvIHRha2UgbXVsdGlwbGUgcmVwZWF0ZWQgc2FtcGxlcy4gQmVsb3cgd2UgdGFrZSAyMDAgc2FtcGxlcyBvZiBzaXplIDUwMCBmcm9tIHRoZSAicG9wdWxhdGlvbiIsIGBrY19ob3VzZV9kYXRhYC4gV2UgYXJlIHRha2luZyBzYW1wbGVzICp3aXRob3V0KiByZXBsYWNlbWVudCB0aGlzIHRpbWUgYmVjYXVzZSB3ZSBhcmUgcHJldGVuZGluZyB0aGF0IHdlIGFyZSBzYW1wbGluZyBmcm9tIHRoZSBwb3B1bGF0aW9uLCBsaWtlIHdoZW4gd2Ugc2FtcGxlZCBSZWVzZSdzIFBpZWNlcyB1c2luZyB0aGUgYXBwbGV0cy4gKipIb3cgbWFueSBvYnNlcnZhdGlvbnMgYXJlIGluIGBzYW1wbGVzXzIwMGA/KiogCgpgYGB7cn0Kc2V0LnNlZWQoMTExMykKc2FtcGxlc18yMDAgPC0gcmVwX3NhbXBsZV9uKGtjX2hvdXNlX2RhdGEsICNkYXRhIHdlJ3JlIHNhbXBsaW5nIGZyb20KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSA1MDAsICNzaXplIG9mIGVhY2ggc2FtcGxlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXBzID0gMjAwLCAjaG93IG1hbnkgc2FtcGxlcyB0byB0YWtlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXBsYWNlID0gRkFMU0UgI3dpdGggb3Igd2l0aG91dAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNyZXBsYWNlbWVudD8KICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKYGBgCgoqR09BTCo6IEZvciBlYWNoIHNhbXBsZSwgd2Ugd291bGQgbGlrZSB0byBmaXQgYSBtb2RlbCB0aGF0IHVzZXMgYGxvZyhzcWZ0X2xpdmluZylgIHRvIHByZWRpY3QgYGxvZyhwcmljZSlgLiBXZSB3b3VsZCBsaWtlIHRvIHVuZGVyc3RhbmQgaG93IHRoZSBpbnRlcmNlcHQgYW5kIHNsb3BlIHZhcnkgZnJvbSBzYW1wbGUgdG8gc2FtcGxlLgoKRmlyc3QsIGxldCdzIGRvIHRoaXMgZ3JhcGhpY2FsbHkuICoqV2hhdCBkbyB5b3Ugb2JzZXJ2ZT8qKgoKYGBge3J9CiNUaGlzIGZpcnN0IHNlY3Rpb24gcGxvdHMgdGhlICJwb3B1bGF0aW9uIiBwb2ludHM6CmF1Z21lbnQobG1fc2ltcGxlLCBkYXRhPWtjX2hvdXNlX2RhdGEpICU+JSAKICBnZ3Bsb3QoYWVzKHg9bG9nKHNxZnRfbGl2aW5nKSwgeSA9IGxvZyhwcmljZSkpKSArIAogIGdlb21fcG9pbnQoYWxwaGE9LjIsIGNvbG9yPSJkYXJrZ3JheSIsIHNpemUgPSAuMikgKyAKI1RoaXMgY29kZSBwbG90cyBlYWNoIG9mIHRoZSBsaW5lcyAgCiAgZ2VvbV9zbW9vdGgoZGF0YSA9IHNhbXBsZXNfMjAwLCAjVXNlIHRoZSBzYW1wbGVzXzIwMCBkYXRhCiAgICAgICAgICAgICAgYWVzKGdyb3VwID0gcmVwbGljYXRlKSwgIyJGb3IgZWFjaCByZXBsaWNhdGUiCiAgICAgICAgICAgICAgbWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgI1VzZSBsbSgpIHRvIGZpdCBhIG1vZGVsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI3doZXJlIGxvZyhzcWZ0X2xpdmluZykKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjZXhwbGFpbnMgbG9nKHByaWNlKQogICAgICAgICAgICAgIGNvbG9yPSJsaWdodGJsdWUiLCBzaXplID0gLjUpICsgI2NvbG9yIHRoZSBsaW5lcyBsaWdodGJsdWUKICBnZW9tX2xpbmUoYWVzKHk9LmZpdHRlZCksIGNvbG9yPSJkYXJrcmVkIikgICNhZGQgdGhlICJwb3B1bGF0aW9uIiBsaW5lCmBgYAoKCk5vdywgbGV0J3MgYWN0dWFsbHkgZml0IHRoZSBtb2RlbCAyMDAgdGltZXMuIExvb2sgY2FyZWZ1bGx5IGF0IHRoZSBvdXRwdXQuICoqV2hhdCBpcyB0aGUgY29kZSBkb2luZyBvbiB0aGUgbGluZSB3aXRoICI/Pz8iPyoqCgpgYGB7cn0KbW9kZWxfMjAwX3RpbWVzIDwtCiAgc2FtcGxlc18yMDAgJT4lICNzdGFydCB3aXRoIHRoZSAyMDAgc2FtcGxlcyBvZiBzaXplIDUwMAogIGdyb3VwX2J5KHJlcGxpY2F0ZSkgJT4lICNmb3IgZWFjaCByZXBsaWNhdGUgCiAgc3VtbWFyaXplKGxtKGxvZyhwcmljZSkgfiBsb2coc3FmdF9saXZpbmcpKSAlPiUgdGlkeSgpKSAlPiUgIz8/PwogIHVuZ3JvdXAoKSAjdW5ncm91cCB0aGUgZGF0YSAtIGdvb2QgdG8gZG8gdGhpcyB3aGVuIGZpbmlzaGVkIHdpdGgKICAgICAgICAgICAgI2dyb3VwZWQgY2FsY3VsYXRpb25zCgptb2RlbF8yMDBfdGltZXMKYGBgCgoKV2UgY2FuIG5vdyBsb29rIGF0IHRoZSAqc2FtcGxpbmcgZGlzdHJpYnV0aW9ucyogb2YgdGhlIGVzdGltYXRlZCBzbG9wZSBhbmQgaW50ZXJjZXB0LiBUaGVzZSBzaG93IHVzIGhvdyB3ZSBleHBlY3QgdGhvc2Ugc3RhdGlzdGljcyB0byB2YXJ5IGZyb20gc2FtcGxlIHRvIHNhbXBsZS4gSSBhbHNvIHB1dCB2ZXJ0aWNhbCBsaW5lcyB3aGVyZSB0aGUgYWN0dWFsIGludGVyY2VwdCBhbmQgc2xvcGUgKGZyb20gdGhlICJwb3B1bGF0aW9uIG1vZGVsIikgYXJlIGxvY2F0ZWQuIAoKYGBge3J9CiNzbG9wZQptb2RlbF8yMDBfdGltZXMgJT4lICMyMDAgbW9kZWxzCiAgZmlsdGVyKHRlcm0gPT0gImxvZyhzcWZ0X2xpdmluZykiKSAlPiUgI2ZpbHRlciB0byB0aGUgdGVybSB3ZSdyZSBpbnRlcmVzdGVkIGluCiAgZ2dwbG90KGFlcyh4ID0gZXN0aW1hdGUpKSArIAogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAyMCkgKyAjY3JlYXRlIGEgaGlzdG9ncmFtIG9mIHRoZSBjb2VmZmljaWVudHMKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLjgzNTExNDIsIGNvbG9yID0gImRhcmtyZWQiKSArCiAgbGFicyh0aXRsZSA9IGJxdW90ZSgiRGlzdHJpYnV0aW9uIG9mIiB+IGhhdChiZXRhKVsxXSkpCmBgYAoKYGBge3J9CiNpbnRlcmNlcHQKbW9kZWxfMjAwX3RpbWVzICU+JSAKICBmaWx0ZXIodGVybSA9PSAiKEludGVyY2VwdCkiKSAlPiUgIyBMT09LIENBUkVGVUxMWSEhCiAgZ2dwbG90KGFlcyh4ID0gZXN0aW1hdGUpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDIwKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gNi43NDMxMDg0LCBjb2xvciA9ICJkYXJrcmVkIikgKwogIGxhYnModGl0bGUgPSBicXVvdGUoIkRpc3RyaWJ1dGlvbiBvZiIgfiBoYXQoYmV0YSlbMF0pKQpgYGAKCgo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1pbmZvIj4KICA8c3Ryb25nPllPVVIgVFVSTiE8L3N0cm9uZz4KICAKMS4gV2hhdCBpcyBhbiBvYnNlcnZhdGlvbiBpbiB0aGUgaGlzdG9ncmFtcyBhYm92ZT8KCjIuIEhvdyB3b3VsZCB5b3UgZGVzY3JpYmUgdGhlc2UgZGlzdHJpYnV0aW9ucyBpbiB0ZXJtcyBvZiBzaGFwZT8KCjMuIENvbXB1dGUgdGhlIG1lYW4gYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgc2xvcGUgYW5kIGludGVyY2VwdCBlc3RpbWF0ZXMuIFRoZSBzdGFuZGFyZCBkZXZpYXRpb24gaGVyZSBoYXMgYSBzcGVjaWFsIG5hbWUsIGEgKnN0YW5kYXJkIGVycm9yKiwgb3IgU0UgZm9yIHNob3J0LiBBIHN0YW5kYXJkIGVycm9yIGlzIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgYSBzdGF0aXN0aWMuIEkndmUgc3RhcnRlZCB0aGUgY29kZSBmb3IgeW91IGJlbG93LiBSZW1vdmUgdGhlIGBldmFsPUZBTFNFYC4KCmBgYHtyLCBldmFsPUZBTFNFfQptb2RlbF8yMDBfdGltZXMgJT4lIAogIGdyb3VwX2J5KF9fXykgJT4lICMgV2Ugd2FudCB0byBjb21wdXRlIHRoZSBtZWFuIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24gZm9yIGVhY2ggd2hhdD8KICBzdW1tYXJpemUobWVhbl9lc3QgPSBfX18sICMgVGhlIG1lYW4gb2YgdGhlIGVzdGltYXRlCiAgICAgICAgICAgIHNlX2VzdCA9IF9fXykgICAjIFRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIGVzdGltYXRlIApgYGAKCjMuIFdoYXQgd291bGQgaGFwcGVuIHRvIHRoZSBzYW1wbGluZyBkaXN0cmlidXRpb24gb2YgdGhlIHNsb3BlIGlmLCBpbnN0ZWFkIG9mIHRha2luZyBzYW1wbGVzIG9mIHNpemUgNTAwLCB3ZSB0b29rIHNhbXBsZXMgb2Ygc2l6ZSAxMDA/IFJlZG8gdGhlIHNpbXVsYXRpb24gdGFraW5nIHNhbXBsZXMgb2Ygc2l6ZSAxMDAgcmF0aGVyIHRoYW4gNTAwLiBJIGhhdmUgc3RhcnRlZCB0aGUgY29kZSBmb3IgeW91IGJlbG93LiBGaWxsIGluIHRoZSAiPz8/IidzIGFuZCBhbHNvIGNvbXB1dGUgdGhlIG1lYW4gYW5kIHN0YW5kYXJkIGVycm9yLiBSZW1vdmUgdGhlIGBldmFsPUZBTFNFYC4KCmBgYHtyLCBldmFsPUZBTFNFfQojU2FtcGxlIGZyb20gdGhlICJwb3B1bGF0aW9uIgpzZXQuc2VlZCgzMjcpCnNpemUxMDBfMjAwIDwtIHJlcF9zYW1wbGVfbihrY19ob3VzZV9kYXRhLCAjZGF0YSB3ZSdyZSBzYW1wbGluZyBmcm9tCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gPz8/LCAjc2l6ZSBvZiBlYWNoIHNhbXBsZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwcyA9ID8/PywgI2hvdyBtYW55IHNhbXBsZXMgdG8gdGFrZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwbGFjZSA9ID8/PyAjd2l0aCBvciB3aXRob3V0CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI3JlcGxhY2VtZW50PwogICAgICAgICAgICAgICAgICAgICAgICAgICAgKQoKI0ZpdCB0aGUgbW9kZWwgMjAwIHRpbWVzCm1vZGVsX3NpemUxMDBfMjAwX3RpbWVzIDwtCiAgc2l6ZTEwMF8yMDAgJT4lICNzdGFydCB3aXRoIHRoZSAyMDAgc2FtcGxlcyBvZiBzaXplIDUwMAogIGdyb3VwX2J5KD8/PykgJT4lICNmb3IgZWFjaCByZXBsaWNhdGUgCiAgc3VtbWFyaXplKGxtKD8/PyB+ID8/PykgJT4lIHRpZHkoKSkgJT4lICM/Pz8KICB1bmdyb3VwKCkgI3VuZ3JvdXAgdGhlIGRhdGEgLSBnb29kIHRvIGRvIHRoaXMgd2hlbiBmaW5pc2hlZCB3aXRoCiAgICAgICAgICAgICNncm91cGVkIGNhbGN1bGF0aW9ucwoKbW9kZWxfc2l6ZTEwMF8yMDBfdGltZXMKCiNDcmVhdGUgdGhlIGhpc3RvZ3JhbSBvZiB0aGUgc2xvcGVzCm1vZGVsX3NpemUxMDBfMjAwX3RpbWVzICU+JSAjMjAwIG1vZGVscwogIGZpbHRlcih0ZXJtID09ICI/Pz8iKSAlPiUgI2ZpbHRlciB0byB0aGUgdGVybSB3ZSdyZSBpbnRlcmVzdGVkIGluCiAgZ2dwbG90KGFlcyh4ID0gZXN0aW1hdGUpKSArIAogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAyMCkgKyAjY3JlYXRlIGEgaGlzdG9ncmFtIG9mIHRoZSBjb2VmZmljaWVudHMKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLjgzNTExNDIsIGNvbG9yID0gImRhcmtyZWQiKSArCiAgbGFicyh0aXRsZSA9IGJxdW90ZSgiRGlzdHJpYnV0aW9uIG9mIiB+IGhhdChiZXRhKVsxXSkpCmBgYAoKNC4gTm93IHRyeSBkb2luZyB3aGF0IHlvdSBkaWQgaW4gIzMgd2l0aCBzYW1wbGVzIG9mIHNpemUgMTAwMC4gSG93IGRvZXMgdGhhdCBjaGFuZ2UgdGhlIGRpc3RyaWJ1dGlvbj8KCjwvZGl2PgoKCiMjIEJvb3RzdHJhcCBEaXN0cmlidXRpb25zCgpSZW1lbWJlciBpbml0aWFsbHkgSSBzYWlkIHRvIHByZXRlbmQgdGhhdCBJIGNvdWxkbid0IGNvbGxlY3QgdGhlIGVudGlyZSBwb3B1bGF0aW9uIG9mIGRhdGEuIEkgY291bGQgb25seSBjb2xsZWN0IDUwMCBvYnNlcnZhdGlvbnMuIEJ1dCwgaWYgSSBjb3VsZG4ndCBjb2xsZWN0IHRoZSBlbnRpcmUgc2FtcGxlIG9mIGRhdGEgdG8gYmVnaW4gd2l0aCwgd2h5IHdvdWxkIEkgYmUgYWJsZSB0byBjb2xsZWN0IDIwMCBkaWZmZXJlbnQgc2FtcGxlcyBvZiBzaXplIDUwMD8gSSBjb3VsZG4ndCEgCgpUaGlzIGlzIHdoZXJlICoqYm9vdHN0cmFwcGluZyoqIGNvbWVzIGluIHRvIHNhdmUgdGhlIGRheSEgV2UgY2FuIHVzZSBib290c3RyYXBwaW5nIHRvIGVzdGltYXRlIHRoZSBzYW1wbGluZyBkaXN0cmlidXRpb24gb2YgdGhlIHNsb3BlICh3ZSBjb3VsZCBhbHNvIGRvIHRoaXMgZm9yIHRoZSBpbnRlcmNlcHQsIGluIGEgc2ltaWxhciB3YXkpIHVzaW5nIG9ubHkgdGhlIG9yaWdpbmFsIHNhbXBsZSB3ZSB0b29rLgoKUmVjYWxsLCB0aGUgZ2VuZXJhbCBib290c3RyYXBwaW5nIGFsZ29yaXRobToKCiogQ29sbGVjdCBhIHJhbmRvbSBzYW1wbGUuIChUaGUgb3JpZ2luYWwgc2FtcGxlLCB3aGljaCBpbiB0aGlzIGNsYXNzIHdpbGwgYWx3YXlzIGJlIGdpdmVuIHRvIHlvdS4pIAoqIFRha2UgYSBzYW1wbGUsIFdJVEggUkVQTEFDRU1FTlQsIG9mIHRoZSBvcmlnaW5hbCBzYW1wbGUgdGhhdCBpcyB0aGUgc2FtZSBzaXplIGFzIHRoZSBvcmlnaW5hbCBzYW1wbGUuIFRoaXMgaXMgY2FsbGVkIHRoZSByZXNhbXBsZSBvciB0aGUgYm9vdHN0cmFwIHNhbXBsZS4gIAoqIENvbXB1dGUgdGhlIHN0YXRpc3RpYyB5b3UgYXJlIGludGVyZXN0ZWQgaW4gb24gdGhlIGJvb3RzdHJhcCBzYW1wbGUuICoqV2hhdCBzaG91bGQgdGhhdCBiZSBpbiB0aGlzIGV4YW1wbGU/KiogICAgCiogUmVwZWF0IHRoZSBwcmV2aW91cyB0d28gc3RlcHMgYSByZWFzb25hYmxlIG51bWJlciBvZiB0aW1lcywgc2F5IGF0IGxlYXN0IDEwMCBidXQgbW9yZSBpZiB5b3UgY2FuLiBUaGlzIGlzIHRoZSBudW1iZXIgb2Ygc2FtcGxlcyBvciByZXBsaWNhdGVzLgoKCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWluZm8iPgogIDxzdHJvbmc+WU9VUiBUVVJOITwvc3Ryb25nPgoKQXNzdW1lIHRoYXQgd2Ugb25seSBoYXZlIHRoZSBpbml0aWFsIHNhbXBsZSB3ZSB0b29rLCAqc2FtcDEqLiBhbmQgY29uc3RydWN0IHRoZSBib290c3RyYXAgZGlzdHJpYnV0aW9uIG9mIHRoZSBzbG9wZS4gSG93IGRvZXMgaXQgY29tcGFyZSB0byB0aGUgYWN0dWFsIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbiBvZiB0aGUgc2xvcGUgYWJvdmU/IEZpbmQgdGhlIG1lYW4gYW5kIHN0YW5kYXJkIGVycm9yIG9mIHRoZSBzbG9wZXMsIGluIGFkZGl0aW9uIHRvIHBsb3R0aW5nIHRoZSBkaXN0cmlidXRpb24uCgpJIGhhdmUgc3RhcnRlZCB0aGUgY29kZSBmb3IgeW91IGJlbG93LiBSZW1vdmUgdGhlIGBldmFsPUZBTFNFYCB3aGVuIGZpbmlzaGVkLgoKYGBge3IsIGV2YWw9RkFMU0V9CnNldC5zZWVkKDExMTMpCnJlc2FtcGxlc18yMDAgPC0gcmVwX3NhbXBsZV9uKF9fX19fLCAgICAgICAgIyB3aGVyZSBkbyB3ZSBzYW1wbGUgZnJvbT8KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSBfX19fXywgICAjIHdoYXQgaXMgdGhlIHNpemUgb2YgZWFjaCBzYW1wbGU/CiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXBzID0gX19fX18sICAgIyBob3cgbWFueSB0aW1lZCBkbyB3ZSByZXBlYXQgdGhlIHdob2xlIHNhbXBsaW5nIHByb2Nlc3M/CiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXBsYWNlID0gX19fX18pICMgZG8gd2Ugc2FtcGxlIHdpdGggb3Igd2l0aG91dCByZXBsYWNlbWVudD8KCmJvb3RfbW9kZWxfMjAwX3RpbWVzIDwtCiAgcmVzYW1wbGVzXzIwMCAlPiUgCiAgZ3JvdXBfYnkoX19fX18pICU+JSAgICAgCiAgc3VtbWFyaXplKGxtKF9fX19fIH4gX19fX18pICU+JSB0aWR5KCkpCgpib290X21vZGVsXzIwMF90aW1lcyAlPiUgCiAgZmlsdGVyKHRlcm0gPT0gIl9fX19fIikgJT4lIAogIGdncGxvdChhZXMoeCA9IF9fX19fKSkgKwogIGdlb21faGlzdG9ncmFtKCkKYGBgCgo8L2Rpdj4KCgoKCgoKCgoKCgoKCgoKCg==