library(tidyverse)     # for plotting and summarizing
library(ggridges)      # for ridge plots
library(ggmosaic)      # for mosaic plots
library(moderndive)    # for nice model output
library(broom)         # for nice model output 
library(infer)         # for making inferences about models
theme_set(theme_minimal()) # changes the theme of ggplots to theme_minimal, my personal favorite

GOAL:

By the end of these notes and activities, you should be able to perform the following tasks.

  • Construct a confidence interval of a model coefficient from a bootstrap distribution.
  • Construct a confidence interval of a model coefficient “using statistical theory” (ie. from the R output).
  • Explain how a confidence interval can be useful and understand why we construct them.
  • Be aware of a couple common misinterpretations of confidence intervals and explain why they are incorrect.

During the past week, we have been learning about sampling and bootstrap distributions which help us understand how statistics vary from sample to sample. Today, we will learn how those can be used to help us construct confidence intervals.

Normal Distribution tangent

We’ve all seen normally distributed data. It turns out “the” normal distribution is actually a family of distributions that depends on the mean and standard deviation of the data. The visual below is a “standard” normal distribution, which means it has mean 0 and standard deviation of 1. Here is a plot of a standard normal distribution.

Facts about Normal Distributions:

  • They are symmetric around the mean of the distribution.
  • ~68% of the data is within 1 standard deviation of the mean (purple shaded area), ~ 95% of the data is within 2 standard deviations of the mean (purple plus blue shaded area), and ~99.7% of the data is within 3 standard deviations of the mean (purple, blue, and green shaded area).
  • MANY sampling distributions are normal or VERY close to normal (the t-distribution is a close cousin of the normal distribution).
  • Sampling distributions are often Normal, centered on the population parameter (eg. mean, actual slope, etc.). Sampling distributions of coefficients are very close to normal, close enough that we’ll just use the normal distribution as a good approximation.

We’ll use some of this information as we talk about confidence intervals and inference.

Confidence intervals

Recall the sampling distribution of the slope, \(\hat{\beta}_1\), from last time:

kc_house_data <-
  house_prices %>% 
  filter(bedrooms<=5, bedrooms>0) %>% 
  mutate(grade_CAT = fct_relevel(ifelse(grade %in% "1":"7", "Low",
                                        ifelse(grade == "8", "Medium","High")),
                                     "Low", "Medium", "High"),
         age=2015-yr_built)
set.seed(1113)

slopes_200_times <- 
  rep_sample_n(kc_house_data, 
               size = 500, 
               reps = 200, 
               replace = FALSE) %>% 
  group_by(replicate) %>%     
  summarize(lm(log(price) ~ log(sqft_living)) %>% tidy()) %>% 
  ungroup() %>% 
  filter(term == "log(sqft_living)") 
## `summarise()` has grouped output by 'replicate'. You can override using the `.groups` argument.
slopes_200_times %>% 
  ggplot(aes(x = estimate)) +
  geom_histogram(bins = 20) +
  geom_vline(xintercept = 0.836771, color = "darkred")

YOUR TURN!

  • Look at the sampling distribution of \(\hat{\beta}_1\). Approximately how many of the estimated coefficients, \(\hat{\beta}_1\), are within 2 standard errors (SE’s) of the population coefficient?
  • If we calculated an interval like the one below, what proportion of intervals would contain the true population parameter?

\[ (\hat{\beta}_1 - 2SE, \hat{\beta}_1 + 2SE) \]

Illustrating the confidence intervals

Let’s actually illustrate what I asked you to do in the second question above.

You will NOT have to write code like this on your own, but I will explain it for those who are interested.

First, I find and store the SE of the estimated slopes.

SE <- sd(slopes_200_times %>% pull(estimate))
SE
## [1] 0.04802503

Next, find the ends of the intervals. And, create a variable that checks to see if the interval contains the population slope, 0.836771, or not. Scroll through the output. Do any intervals not contain the true slope?

conf_int_200_times <-
  slopes_200_times %>% 
  select(replicate, estimate) %>% 
  mutate(lower = estimate - 2*SE, 
         upper = estimate + 2*SE,
         pop_slope = 0.836771,
         pop_slope_in = pop_slope < upper & pop_slope > lower)

conf_int_200_times

Now, let’s visualize this in a plot.

conf_int_200_times %>% 
  ggplot() +
  geom_linerange(aes(x=replicate, 
                     ymin=lower, ymax=upper, 
                     color=pop_slope_in),
                size=.3) + 
  geom_point(aes(x=replicate, y=estimate, 
                 color=pop_slope_in), size=.3) +
  geom_hline(yintercept = 0.836771, alpha=.5) +
  coord_flip() 

So, what proportion of intervals contain the true slope?













This illustrates the meaning of a the 95% confidence interval! A 95% confidence interval is an interval in which 95% of the intervals constructed this way (in repeated sampling of the population) contain the true parameter. So, the 95% “confidence” has to do with confidence in the method.

I think the tweet below is a great illustration for how to think of confidence intervals.

Unfortunately, we don’t know if we have one that does or does not contain the true parameter. So, we really use these intervals to give a sense of the precision of our estimate. If the interval is really wide, it’s not very precise. If it’s narrow, it’s more precise.

Think of the confidence interval as an interval estimate of our slope. So, rather than having just one number as our estimate, we now have a range of plausible values.

Warning:common misinterpretations of these intervals (all are incorrect!)

  1. “There is a 95% chance (or 95% probability) that this confidence interval contains the true slope.”

  2. If I take another sample and fit a model, “There is a 95% chance the slope will be in this confidence interval.”

YOUR TURN!

Assume you have a sample of data. You fit a model to the data and construct a 95% confidence interval for the slope. Think of it as one of the lines from the picture above. Explain why the statements above are incorrect.

Constructing confidence intervals with our one sample of data

In the simulation above I computed the SE of the estimated coefficient using the sampling distribution. But we know that we will only have one sample, so we will have to estimate the standard error from our one sample.

How can we do this?

  1. Simulation using the bootstrap distribution.
  2. Use theory and formulas.

1. Bootstrap CI’s

Let’s look at a model from one of our samples of data, samp1.

set.seed(327)

samp1 <- kc_house_data %>% 
  sample_n(size=500) 

lm.samp1 <- lm(log(price) ~ log(sqft_living), 
               data=samp1)

tidy(lm.samp1) %>% 
  select(term, estimate)

Let’s construct the bootstrap distribution of the estimated coefficient of log(sqft_living).

set.seed(1113)
boot_model_200_times <-
  rep_sample_n(samp1, 
               size = 500, 
               reps = 200, 
               replace = TRUE) %>% 
  group_by(replicate) %>%     
  summarize(lm(log(price) ~ log(sqft_living)) %>% tidy()) %>% 
  ungroup() %>% 
  filter(term == "log(sqft_living)") 
## `summarise()` has grouped output by 'replicate'. You can override using the `.groups` argument.
boot_model_200_times %>% 
  ggplot(aes(x = estimate)) +
  geom_histogram(bins = 20)

YOUR TURN!

  1. Find the SE of the coefficient estimates from the bootstrapped estimates. (Remove eval=FALSE when finished)
# HINT: open the boot_model_200_times file to see what's in it, first
boot_model_200_times %>% 
  summarize(SE = ___)
  1. How does this SE compare to the SE you found from the sampling distribution?

  2. Construct a 95% confidence interval using the SE you found from the bootstrap distribution. (Remove eval=FALSE when finished)

boot_model_200_times %>% 
  summarize(SE = ___,
            lowerCI = ___ - ___*___,
            upperCI = ___ + ___*___)
  1. How do you interpret this confidence interval?

  2. We can also find the confidence interval as the middle 95% of the bootstrap distribution. Try computing it this way. How does it compare to the method using the standard error? (Remove eval=FALSE when finished)

boot_model_200_times %>% 
  summarize(lowerCI = quantile(estimate, probs = ___),
            upperCI = quantile(estimate, probs = ___))

2. Using theory and formulas to construct CIs from a sample of data

Let’s look at the full regression table from the model we built using samp1. We can add a confidence interval by including conf.int = TRUE. I also added it “by hand”. These are slightly different partially because we are rounding when we use the multiplier of 2. Mulitplying by 1.96 would be closer.

tidy(lm.samp1, conf.int = TRUE) %>% 
  mutate(lowerCI = estimate - 2*std.error,
         upperCI = estimate + 2*std.error)

Notice that there is a variable in this output called … std.error! How does that standard error compare to the standard error you computed from the bootstrap distribution?

This standard error is computed using some statistical theory (for reference, see STAT 155 Notes). That is used in constructing the confidence interval.

Confidence in Predictions

YOUR TURN! (Extra challenge)

I would like to construct a confidence interval for the average price of homes with 2000 sqft of living. Describe in words how you could use the bootstrap technique to help answer that question. Then, code it!

LS0tCnRpdGxlOiAiQ29uZmlkZW5jZSBJbnRlcnZhbHMiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGRmX3ByaW50OiBwYWdlZAogICAgY29kZV9kb3dubG9hZDogdHJ1ZQotLS0KCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkgICAgICMgZm9yIHBsb3R0aW5nIGFuZCBzdW1tYXJpemluZwpsaWJyYXJ5KGdncmlkZ2VzKSAgICAgICMgZm9yIHJpZGdlIHBsb3RzCmxpYnJhcnkoZ2dtb3NhaWMpICAgICAgIyBmb3IgbW9zYWljIHBsb3RzCmxpYnJhcnkobW9kZXJuZGl2ZSkgICAgIyBmb3IgbmljZSBtb2RlbCBvdXRwdXQKbGlicmFyeShicm9vbSkgICAgICAgICAjIGZvciBuaWNlIG1vZGVsIG91dHB1dCAKbGlicmFyeShpbmZlcikgICAgICAgICAjIGZvciBtYWtpbmcgaW5mZXJlbmNlcyBhYm91dCBtb2RlbHMKdGhlbWVfc2V0KHRoZW1lX21pbmltYWwoKSkgIyBjaGFuZ2VzIHRoZSB0aGVtZSBvZiBnZ3Bsb3RzIHRvIHRoZW1lX21pbmltYWwsIG15IHBlcnNvbmFsIGZhdm9yaXRlCmBgYAoKPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtc3VjY2VzcyI+CiAgPHN0cm9uZz5HT0FMOjwvc3Ryb25nPgoKQnkgdGhlIGVuZCBvZiB0aGVzZSBub3RlcyBhbmQgYWN0aXZpdGllcywgeW91IHNob3VsZCBiZSBhYmxlIHRvIHBlcmZvcm0gdGhlIGZvbGxvd2luZyB0YXNrcy4KCiogQ29uc3RydWN0IGEgY29uZmlkZW5jZSBpbnRlcnZhbCBvZiBhIG1vZGVsIGNvZWZmaWNpZW50IGZyb20gYSBib290c3RyYXAgZGlzdHJpYnV0aW9uLiAgCiogQ29uc3RydWN0IGEgY29uZmlkZW5jZSBpbnRlcnZhbCBvZiBhIG1vZGVsIGNvZWZmaWNpZW50ICJ1c2luZyBzdGF0aXN0aWNhbCB0aGVvcnkiIChpZS4gZnJvbSB0aGUgUiBvdXRwdXQpLiAgCiogRXhwbGFpbiBob3cgYSBjb25maWRlbmNlIGludGVydmFsIGNhbiBiZSB1c2VmdWwgYW5kIHVuZGVyc3RhbmQgd2h5IHdlIGNvbnN0cnVjdCB0aGVtLiAgCiogQmUgYXdhcmUgb2YgYSBjb3VwbGUgY29tbW9uIG1pc2ludGVycHJldGF0aW9ucyBvZiBjb25maWRlbmNlIGludGVydmFscyBhbmQgZXhwbGFpbiB3aHkgdGhleSBhcmUgaW5jb3JyZWN0LgoKPC9kaXY+CgpEdXJpbmcgdGhlIHBhc3Qgd2Vlaywgd2UgaGF2ZSBiZWVuIGxlYXJuaW5nIGFib3V0IHNhbXBsaW5nIGFuZCBib290c3RyYXAgZGlzdHJpYnV0aW9ucyB3aGljaCBoZWxwIHVzIHVuZGVyc3RhbmQgaG93IHN0YXRpc3RpY3MgdmFyeSBmcm9tIHNhbXBsZSB0byBzYW1wbGUuIFRvZGF5LCB3ZSB3aWxsIGxlYXJuIGhvdyB0aG9zZSBjYW4gYmUgdXNlZCB0byBoZWxwIHVzIGNvbnN0cnVjdCBjb25maWRlbmNlIGludGVydmFscy4gCgojIE5vcm1hbCBEaXN0cmlidXRpb24gdGFuZ2VudAoKV2UndmUgYWxsIHNlZW4gbm9ybWFsbHkgZGlzdHJpYnV0ZWQgZGF0YS4gSXQgdHVybnMgb3V0ICJ0aGUiIG5vcm1hbCBkaXN0cmlidXRpb24gaXMgYWN0dWFsbHkgYSBmYW1pbHkgb2YgZGlzdHJpYnV0aW9ucyB0aGF0IGRlcGVuZHMgb24gdGhlIG1lYW4gYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgZGF0YS4gVGhlIHZpc3VhbCBiZWxvdyBpcyBhICJzdGFuZGFyZCIgbm9ybWFsIGRpc3RyaWJ1dGlvbiwgd2hpY2ggbWVhbnMgaXQgaGFzIG1lYW4gMCBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIDEuIEhlcmUgaXMgYSBwbG90IG9mIGEgc3RhbmRhcmQgbm9ybWFsIGRpc3RyaWJ1dGlvbi4KCmBgYHtyLCBlY2hvPUZBTFNFfQpzZXQuc2VlZCg4NDkzKQp0aWJibGUoeCA9IHJub3JtKDEwMDAwMCkpICU+JSAKICBtdXRhdGUoY2xyID0gY2FzZV93aGVuKAogICAgYmV0d2Vlbih4LCAtMSwgMSkgfiAiMSBzZCIsCiAgICBiZXR3ZWVuKHgsIC0yLCAyKSB+ICIyIHNkIiwKICAgIGJldHdlZW4oeCwgLTMsIDMpIH4gIjMgc2QiLAogICAgVFJVRSB+ICIzKyBzZCIpKSAlPiUgCiAgZ2dwbG90KCkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh4ID0geCwgZmlsbCA9IGNsciksIGJpbnM9MzAwKSArIAogIHNjYWxlX2ZpbGxfdmlyaWRpc19kKCkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSAtMzozKSArCiAgZ3VpZGVzKGZpbGwgPSAibm9uZSIpCmBgYAoKRmFjdHMgYWJvdXQgTm9ybWFsIERpc3RyaWJ1dGlvbnM6CgoqIFRoZXkgYXJlIHN5bW1ldHJpYyBhcm91bmQgdGhlIG1lYW4gb2YgdGhlIGRpc3RyaWJ1dGlvbi4gIAoqIH42OFwlIG9mIHRoZSBkYXRhIGlzIHdpdGhpbiAxIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgbWVhbiAocHVycGxlIHNoYWRlZCBhcmVhKSwgfiA5NVwlIG9mIHRoZSBkYXRhIGlzIHdpdGhpbiAyIHN0YW5kYXJkIGRldmlhdGlvbnMgb2YgdGhlIG1lYW4gKHB1cnBsZSBwbHVzIGJsdWUgc2hhZGVkIGFyZWEpLCBhbmQgfjk5LjclIG9mIHRoZSBkYXRhIGlzIHdpdGhpbiAzIHN0YW5kYXJkIGRldmlhdGlvbnMgb2YgdGhlIG1lYW4gKHB1cnBsZSwgYmx1ZSwgYW5kIGdyZWVuIHNoYWRlZCBhcmVhKS4gIAoqIE1BTlkgc2FtcGxpbmcgZGlzdHJpYnV0aW9ucyBhcmUgbm9ybWFsIG9yIFZFUlkgY2xvc2UgdG8gbm9ybWFsICh0aGUgdC1kaXN0cmlidXRpb24gaXMgYSBjbG9zZSBjb3VzaW4gb2YgdGhlIG5vcm1hbCBkaXN0cmlidXRpb24pLiAgCiogU2FtcGxpbmcgZGlzdHJpYnV0aW9ucyBhcmUgb2Z0ZW4gTm9ybWFsLCBjZW50ZXJlZCBvbiB0aGUgcG9wdWxhdGlvbiBwYXJhbWV0ZXIgKGVnLiBtZWFuLCBhY3R1YWwgc2xvcGUsIGV0Yy4pLiBTYW1wbGluZyBkaXN0cmlidXRpb25zIG9mIGNvZWZmaWNpZW50cyBhcmUgdmVyeSBjbG9zZSB0byBub3JtYWwsIGNsb3NlIGVub3VnaCB0aGF0IHdlJ2xsIGp1c3QgdXNlIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uIGFzIGEgZ29vZCBhcHByb3hpbWF0aW9uLiAKCgpXZSdsbCB1c2Ugc29tZSBvZiB0aGlzIGluZm9ybWF0aW9uIGFzIHdlIHRhbGsgYWJvdXQgY29uZmlkZW5jZSBpbnRlcnZhbHMgYW5kIGluZmVyZW5jZS4KCiMgQ29uZmlkZW5jZSBpbnRlcnZhbHMKClJlY2FsbCB0aGUgc2FtcGxpbmcgZGlzdHJpYnV0aW9uIG9mIHRoZSBzbG9wZSwgJFxoYXR7XGJldGF9XzEkLCBmcm9tIGxhc3QgdGltZToKCmBgYHtyLCBlcnJvcj1GQUxTRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0Ka2NfaG91c2VfZGF0YSA8LQogIGhvdXNlX3ByaWNlcyAlPiUgCiAgZmlsdGVyKGJlZHJvb21zPD01LCBiZWRyb29tcz4wKSAlPiUgCiAgbXV0YXRlKGdyYWRlX0NBVCA9IGZjdF9yZWxldmVsKGlmZWxzZShncmFkZSAlaW4lICIxIjoiNyIsICJMb3ciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdyYWRlID09ICI4IiwgIk1lZGl1bSIsIkhpZ2giKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTG93IiwgIk1lZGl1bSIsICJIaWdoIiksCiAgICAgICAgIGFnZT0yMDE1LXlyX2J1aWx0KQoKYGBgCgoKYGBge3J9CnNldC5zZWVkKDExMTMpCgpzbG9wZXNfMjAwX3RpbWVzIDwtIAogIHJlcF9zYW1wbGVfbihrY19ob3VzZV9kYXRhLCAKICAgICAgICAgICAgICAgc2l6ZSA9IDUwMCwgCiAgICAgICAgICAgICAgIHJlcHMgPSAyMDAsIAogICAgICAgICAgICAgICByZXBsYWNlID0gRkFMU0UpICU+JSAKICBncm91cF9ieShyZXBsaWNhdGUpICU+JSAgICAgCiAgc3VtbWFyaXplKGxtKGxvZyhwcmljZSkgfiBsb2coc3FmdF9saXZpbmcpKSAlPiUgdGlkeSgpKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBmaWx0ZXIodGVybSA9PSAibG9nKHNxZnRfbGl2aW5nKSIpIAoKc2xvcGVzXzIwMF90aW1lcyAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gZXN0aW1hdGUpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDIwKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMC44MzY3NzEsIGNvbG9yID0gImRhcmtyZWQiKQpgYGAKCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWluZm8iPgogIDxzdHJvbmc+WU9VUiBUVVJOITwvc3Ryb25nPgoKKiBMb29rIGF0IHRoZSBzYW1wbGluZyBkaXN0cmlidXRpb24gb2YgJFxoYXR7XGJldGF9XzEkLiBBcHByb3hpbWF0ZWx5IGhvdyBtYW55IG9mIHRoZSBlc3RpbWF0ZWQgY29lZmZpY2llbnRzLCAkXGhhdHtcYmV0YX1fMSQsIGFyZSB3aXRoaW4gMiBzdGFuZGFyZCBlcnJvcnMgKFNFJ3MpIG9mIHRoZSBwb3B1bGF0aW9uIGNvZWZmaWNpZW50PyAgCiogSWYgd2UgY2FsY3VsYXRlZCBhbiBpbnRlcnZhbCBsaWtlIHRoZSBvbmUgYmVsb3csIHdoYXQgcHJvcG9ydGlvbiBvZiBpbnRlcnZhbHMgd291bGQgY29udGFpbiB0aGUgdHJ1ZSBwb3B1bGF0aW9uIHBhcmFtZXRlcj8KCiQkCihcaGF0e1xiZXRhfV8xIC0gMlNFLCBcaGF0e1xiZXRhfV8xICsgMlNFKQokJAo8L2Rpdj4KCiMjIElsbHVzdHJhdGluZyB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbHMKCkxldCdzIGFjdHVhbGx5IGlsbHVzdHJhdGUgd2hhdCBJIGFza2VkIHlvdSB0byBkbyBpbiB0aGUgc2Vjb25kIHF1ZXN0aW9uIGFib3ZlLgoKWW91IHdpbGwgTk9UIGhhdmUgdG8gd3JpdGUgY29kZSBsaWtlIHRoaXMgb24geW91ciBvd24sIGJ1dCBJIHdpbGwgZXhwbGFpbiBpdCBmb3IgdGhvc2Ugd2hvIGFyZSBpbnRlcmVzdGVkLgoKRmlyc3QsIEkgZmluZCBhbmQgc3RvcmUgdGhlIFNFIG9mIHRoZSBlc3RpbWF0ZWQgc2xvcGVzLgoKYGBge3J9ClNFIDwtIHNkKHNsb3Blc18yMDBfdGltZXMgJT4lIHB1bGwoZXN0aW1hdGUpKQpTRQpgYGAKCk5leHQsIGZpbmQgdGhlIGVuZHMgb2YgdGhlIGludGVydmFscy4gQW5kLCBjcmVhdGUgYSB2YXJpYWJsZSB0aGF0IGNoZWNrcyB0byBzZWUgaWYgdGhlIGludGVydmFsIGNvbnRhaW5zIHRoZSBwb3B1bGF0aW9uIHNsb3BlLCAwLjgzNjc3MSwgb3Igbm90LiBTY3JvbGwgdGhyb3VnaCB0aGUgb3V0cHV0LiAqKkRvIGFueSBpbnRlcnZhbHMgbm90IGNvbnRhaW4gdGhlIHRydWUgc2xvcGU/KioKCmBgYHtyfQpjb25mX2ludF8yMDBfdGltZXMgPC0KICBzbG9wZXNfMjAwX3RpbWVzICU+JSAKICBzZWxlY3QocmVwbGljYXRlLCBlc3RpbWF0ZSkgJT4lIAogIG11dGF0ZShsb3dlciA9IGVzdGltYXRlIC0gMipTRSwgCiAgICAgICAgIHVwcGVyID0gZXN0aW1hdGUgKyAyKlNFLAogICAgICAgICBwb3Bfc2xvcGUgPSAwLjgzNjc3MSwKICAgICAgICAgcG9wX3Nsb3BlX2luID0gcG9wX3Nsb3BlIDwgdXBwZXIgJiBwb3Bfc2xvcGUgPiBsb3dlcikKCmNvbmZfaW50XzIwMF90aW1lcwpgYGAKCk5vdywgbGV0J3MgdmlzdWFsaXplIHRoaXMgaW4gYSBwbG90LgoKYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTR9CmNvbmZfaW50XzIwMF90aW1lcyAlPiUgCiAgZ2dwbG90KCkgKwogIGdlb21fbGluZXJhbmdlKGFlcyh4PXJlcGxpY2F0ZSwgCiAgICAgICAgICAgICAgICAgICAgIHltaW49bG93ZXIsIHltYXg9dXBwZXIsIAogICAgICAgICAgICAgICAgICAgICBjb2xvcj1wb3Bfc2xvcGVfaW4pLAogICAgICAgICAgICAgICAgc2l6ZT0uMykgKyAKICBnZW9tX3BvaW50KGFlcyh4PXJlcGxpY2F0ZSwgeT1lc3RpbWF0ZSwgCiAgICAgICAgICAgICAgICAgY29sb3I9cG9wX3Nsb3BlX2luKSwgc2l6ZT0uMykgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuODM2NzcxLCBhbHBoYT0uNSkgKwogIGNvb3JkX2ZsaXAoKSAKYGBgCgoqKlNvLCB3aGF0IHByb3BvcnRpb24gb2YgaW50ZXJ2YWxzIGNvbnRhaW4gdGhlIHRydWUgc2xvcGU/KioKClwKXApcClwKXApcClwKXApcClwKXApcCgoKVGhpcyBpbGx1c3RyYXRlcyB0aGUgbWVhbmluZyBvZiBhIHRoZSA5NVwlIGNvbmZpZGVuY2UgaW50ZXJ2YWwhIEEgOTVcJSBjb25maWRlbmNlIGludGVydmFsIGlzIGFuIGludGVydmFsIGluIHdoaWNoIDk1XCUgb2YgdGhlIGludGVydmFscyBjb25zdHJ1Y3RlZCB0aGlzIHdheSAoaW4gcmVwZWF0ZWQgc2FtcGxpbmcgb2YgdGhlIHBvcHVsYXRpb24pIGNvbnRhaW4gdGhlIHRydWUgcGFyYW1ldGVyLiBTbywgdGhlIDk1XCUgImNvbmZpZGVuY2UiIGhhcyB0byBkbyB3aXRoIGNvbmZpZGVuY2UgaW4gdGhlIG1ldGhvZC4KCkkgdGhpbmsgdGhlIHR3ZWV0IGJlbG93IGlzIGEgZ3JlYXQgaWxsdXN0cmF0aW9uIGZvciBob3cgdG8gdGhpbmsgb2YgY29uZmlkZW5jZSBpbnRlcnZhbHMuCgo8YmxvY2txdW90ZSBjbGFzcz0idHdpdHRlci10d2VldCI+PHAgbGFuZz0iZW4iIGRpcj0ibHRyIj5CdXQsIHRoZSDigJx0cnVl4oCdIHZhbHVlIGlzIHRoZSBwYXJ0IHRoZXkgc2hvdWxkIHZpZXcgYXMgZml4ZWQuIDxicj48YnI+SW5zdGVhZCwgSSBwcm9wb3NlIGV4cGxhaW5pbmcgcHJlY2lzaW9uLCBhY2N1cmFjeSwgYW5kIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIHdpdGggcmluZyB0b3NzLiA8YnI+PGJyPlRoZSDigJx0cnV0aOKAnSBpcyBpbiBhIGZpeGVkIHBsYWNlLCBhbmQgaXTigJlzIHRoZSBjb25maWRlbmNlIGludGVydmFsIHJpbmcgdGhhdCBtYXkgb3IgbWF5IG5vdCBsYW5kIHdoZXJlIHlvdSB3YW50IGl0IHRvLiAzLzQgPGEgaHJlZj0iaHR0cHM6Ly90LmNvL1ljYTVVWG9yYzQiPnBpYy50d2l0dGVyLmNvbS9ZY2E1VVhvcmM0PC9hPjwvcD4mbWRhc2g7IEVsbGllIE11cnJheSAoQEVwaUVsbGllKSA8YSBocmVmPSJodHRwczovL3R3aXR0ZXIuY29tL0VwaUVsbGllL3N0YXR1cy8xMDczMzg1NDI3MzE3NDY1MDg5P3JlZl9zcmM9dHdzcmMlNUV0ZnciPkRlY2VtYmVyIDE0LCAyMDE4PC9hPjwvYmxvY2txdW90ZT4gPHNjcmlwdCBhc3luYyBzcmM9Imh0dHBzOi8vcGxhdGZvcm0udHdpdHRlci5jb20vd2lkZ2V0cy5qcyIgY2hhcnNldD0idXRmLTgiPjwvc2NyaXB0PgoKKipVbmZvcnR1bmF0ZWx5KiosIHdlIGRvbid0IGtub3cgaWYgd2UgaGF2ZSBvbmUgdGhhdCBkb2VzIG9yIGRvZXMgbm90IGNvbnRhaW4gdGhlIHRydWUgcGFyYW1ldGVyLiBTbywgd2UgcmVhbGx5IHVzZSB0aGVzZSBpbnRlcnZhbHMgdG8gZ2l2ZSBhIHNlbnNlIG9mIHRoZSBwcmVjaXNpb24gb2Ygb3VyIGVzdGltYXRlLiBJZiB0aGUgaW50ZXJ2YWwgaXMgcmVhbGx5IHdpZGUsIGl0J3Mgbm90IHZlcnkgcHJlY2lzZS4gSWYgaXQncyBuYXJyb3csIGl0J3MgbW9yZSBwcmVjaXNlLiAKClRoaW5rIG9mIHRoZSBjb25maWRlbmNlIGludGVydmFsIGFzIGFuIGludGVydmFsIGVzdGltYXRlIG9mIG91ciBzbG9wZS4gU28sIHJhdGhlciB0aGFuIGhhdmluZyBqdXN0IG9uZSBudW1iZXIgYXMgb3VyIGVzdGltYXRlLCB3ZSBub3cgaGF2ZSBhIHJhbmdlIG9mIHBsYXVzaWJsZSB2YWx1ZXMuCgojIyBXYXJuaW5nOmNvbW1vbiBtaXNpbnRlcnByZXRhdGlvbnMgb2YgdGhlc2UgaW50ZXJ2YWxzIChhbGwgYXJlIGluY29ycmVjdCEpCgoxLiAiVGhlcmUgaXMgYSA5NSUgY2hhbmNlIChvciA5NSUgcHJvYmFiaWxpdHkpIHRoYXQgdGhpcyBjb25maWRlbmNlIGludGVydmFsIGNvbnRhaW5zIHRoZSB0cnVlIHNsb3BlLiIKCjIuIElmIEkgdGFrZSBhbm90aGVyIHNhbXBsZSBhbmQgZml0IGEgbW9kZWwsICJUaGVyZSBpcyBhIDk1JSBjaGFuY2UgdGhlIHNsb3BlIHdpbGwgYmUgaW4gdGhpcyBjb25maWRlbmNlIGludGVydmFsLiIKCgo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1pbmZvIj4KICA8c3Ryb25nPllPVVIgVFVSTiE8L3N0cm9uZz4KCkFzc3VtZSB5b3UgaGF2ZSBhIHNhbXBsZSBvZiBkYXRhLiBZb3UgZml0IGEgbW9kZWwgdG8gdGhlIGRhdGEgYW5kIGNvbnN0cnVjdCBhIDk1XCUgY29uZmlkZW5jZSBpbnRlcnZhbCBmb3IgdGhlIHNsb3BlLiBUaGluayBvZiBpdCBhcyBvbmUgb2YgdGhlIGxpbmVzIGZyb20gdGhlIHBpY3R1cmUgYWJvdmUuIEV4cGxhaW4gd2h5IHRoZSBzdGF0ZW1lbnRzIGFib3ZlIGFyZSBpbmNvcnJlY3QuIAoKPC9kaXY+CgojIENvbnN0cnVjdGluZyBjb25maWRlbmNlIGludGVydmFscyB3aXRoIG91ciBvbmUgc2FtcGxlIG9mIGRhdGEKCkluIHRoZSBzaW11bGF0aW9uIGFib3ZlIEkgY29tcHV0ZWQgdGhlIFNFIG9mIHRoZSBlc3RpbWF0ZWQgY29lZmZpY2llbnQgdXNpbmcgdGhlIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbi4gQnV0IHdlIGtub3cgdGhhdCB3ZSB3aWxsIG9ubHkgaGF2ZSBvbmUgc2FtcGxlLCBzbyB3ZSB3aWxsIGhhdmUgdG8gZXN0aW1hdGUgdGhlIHN0YW5kYXJkIGVycm9yIGZyb20gb3VyIG9uZSBzYW1wbGUuCgpIb3cgY2FuIHdlIGRvIHRoaXM/CgoxLiBTaW11bGF0aW9uIHVzaW5nIHRoZSBib290c3RyYXAgZGlzdHJpYnV0aW9uLiAgCjIuIFVzZSB0aGVvcnkgYW5kIGZvcm11bGFzLgoKCiMjIDEuIEJvb3RzdHJhcCBDSSdzCgpMZXQncyBsb29rIGF0IGEgbW9kZWwgZnJvbSBvbmUgb2Ygb3VyIHNhbXBsZXMgb2YgZGF0YSwgYHNhbXAxYC4KCmBgYHtyfQpzZXQuc2VlZCgzMjcpCgpzYW1wMSA8LSBrY19ob3VzZV9kYXRhICU+JSAKICBzYW1wbGVfbihzaXplPTUwMCkgCgpsbS5zYW1wMSA8LSBsbShsb2cocHJpY2UpIH4gbG9nKHNxZnRfbGl2aW5nKSwgCiAgICAgICAgICAgICAgIGRhdGE9c2FtcDEpCgp0aWR5KGxtLnNhbXAxKSAlPiUgCiAgc2VsZWN0KHRlcm0sIGVzdGltYXRlKQpgYGAKCkxldCdzIGNvbnN0cnVjdCB0aGUgYm9vdHN0cmFwIGRpc3RyaWJ1dGlvbiBvZiB0aGUgZXN0aW1hdGVkIGNvZWZmaWNpZW50IG9mIGBsb2coc3FmdF9saXZpbmcpYC4gCgpgYGB7cn0Kc2V0LnNlZWQoMTExMykKYm9vdF9tb2RlbF8yMDBfdGltZXMgPC0KICByZXBfc2FtcGxlX24oc2FtcDEsIAogICAgICAgICAgICAgICBzaXplID0gNTAwLCAKICAgICAgICAgICAgICAgcmVwcyA9IDIwMCwgCiAgICAgICAgICAgICAgIHJlcGxhY2UgPSBUUlVFKSAlPiUgCiAgZ3JvdXBfYnkocmVwbGljYXRlKSAlPiUgICAgIAogIHN1bW1hcml6ZShsbShsb2cocHJpY2UpIH4gbG9nKHNxZnRfbGl2aW5nKSkgJT4lIHRpZHkoKSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgZmlsdGVyKHRlcm0gPT0gImxvZyhzcWZ0X2xpdmluZykiKSAKCmJvb3RfbW9kZWxfMjAwX3RpbWVzICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBlc3RpbWF0ZSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMjApCmBgYAoKPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtaW5mbyI+CiAgPHN0cm9uZz5ZT1VSIFRVUk4hPC9zdHJvbmc+CgoxLiBGaW5kIHRoZSBTRSBvZiB0aGUgY29lZmZpY2llbnQgZXN0aW1hdGVzIGZyb20gdGhlIGJvb3RzdHJhcHBlZCBlc3RpbWF0ZXMuIChSZW1vdmUgYGV2YWw9RkFMU0VgIHdoZW4gZmluaXNoZWQpCgpgYGB7ciwgZXZhbD1GQUxTRX0KIyBISU5UOiBvcGVuIHRoZSBib290X21vZGVsXzIwMF90aW1lcyBmaWxlIHRvIHNlZSB3aGF0J3MgaW4gaXQsIGZpcnN0CmJvb3RfbW9kZWxfMjAwX3RpbWVzICU+JSAKICBzdW1tYXJpemUoU0UgPSBfX18pCmBgYAoKMi4gSG93IGRvZXMgdGhpcyBTRSBjb21wYXJlIHRvIHRoZSBTRSB5b3UgZm91bmQgZnJvbSB0aGUgc2FtcGxpbmcgZGlzdHJpYnV0aW9uPyAgCgoKMy4gQ29uc3RydWN0IGEgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgdXNpbmcgdGhlIFNFIHlvdSBmb3VuZCBmcm9tIHRoZSBib290c3RyYXAgZGlzdHJpYnV0aW9uLiAoUmVtb3ZlIGBldmFsPUZBTFNFYCB3aGVuIGZpbmlzaGVkKQoKYGBge3IsIGV2YWw9RkFMU0V9CmJvb3RfbW9kZWxfMjAwX3RpbWVzICU+JSAKICBzdW1tYXJpemUoU0UgPSBfX18sCiAgICAgICAgICAgIGxvd2VyQ0kgPSBfX18gLSBfX18qX19fLAogICAgICAgICAgICB1cHBlckNJID0gX19fICsgX19fKl9fXykKYGBgCgoKNC4gSG93IGRvIHlvdSBpbnRlcnByZXQgdGhpcyBjb25maWRlbmNlIGludGVydmFsPwoKNS4gV2UgY2FuIGFsc28gZmluZCB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbCBhcyB0aGUgbWlkZGxlIDk1XCUgb2YgdGhlIGJvb3RzdHJhcCBkaXN0cmlidXRpb24uIFRyeSBjb21wdXRpbmcgaXQgdGhpcyB3YXkuIEhvdyBkb2VzIGl0IGNvbXBhcmUgdG8gdGhlIG1ldGhvZCB1c2luZyB0aGUgc3RhbmRhcmQgZXJyb3I/IChSZW1vdmUgYGV2YWw9RkFMU0VgIHdoZW4gZmluaXNoZWQpCgpgYGB7ciwgZXZhbD1GQUxTRX0KYm9vdF9tb2RlbF8yMDBfdGltZXMgJT4lIAogIHN1bW1hcml6ZShsb3dlckNJID0gcXVhbnRpbGUoZXN0aW1hdGUsIHByb2JzID0gX19fKSwKICAgICAgICAgICAgdXBwZXJDSSA9IHF1YW50aWxlKGVzdGltYXRlLCBwcm9icyA9IF9fXykpCmBgYAoKCjwvZGl2PgoKIyMgMi4gVXNpbmcgdGhlb3J5IGFuZCBmb3JtdWxhcyB0byBjb25zdHJ1Y3QgQ0lzIGZyb20gYSBzYW1wbGUgb2YgZGF0YQoKTGV0J3MgbG9vayBhdCB0aGUgZnVsbCByZWdyZXNzaW9uIHRhYmxlIGZyb20gdGhlIG1vZGVsIHdlIGJ1aWx0IHVzaW5nIGBzYW1wMWAuIFdlIGNhbiBhZGQgYSBjb25maWRlbmNlIGludGVydmFsIGJ5IGluY2x1ZGluZyBgY29uZi5pbnQgPSBUUlVFYC4gSSBhbHNvIGFkZGVkIGl0ICJieSBoYW5kIi4gVGhlc2UgYXJlIHNsaWdodGx5IGRpZmZlcmVudCBwYXJ0aWFsbHkgYmVjYXVzZSB3ZSBhcmUgcm91bmRpbmcgd2hlbiB3ZSB1c2UgdGhlIG11bHRpcGxpZXIgb2YgMi4gTXVsaXRwbHlpbmcgYnkgMS45NiB3b3VsZCBiZSBjbG9zZXIuIAoKYGBge3J9CnRpZHkobG0uc2FtcDEsIGNvbmYuaW50ID0gVFJVRSkgJT4lIAogIG11dGF0ZShsb3dlckNJID0gZXN0aW1hdGUgLSAyKnN0ZC5lcnJvciwKICAgICAgICAgdXBwZXJDSSA9IGVzdGltYXRlICsgMipzdGQuZXJyb3IpCmBgYAoKCk5vdGljZSB0aGF0IHRoZXJlIGlzIGEgdmFyaWFibGUgaW4gdGhpcyBvdXRwdXQgY2FsbGVkIC4uLiBgc3RkLmVycm9yYCEgKipIb3cgZG9lcyB0aGF0IHN0YW5kYXJkIGVycm9yIGNvbXBhcmUgdG8gdGhlIHN0YW5kYXJkIGVycm9yIHlvdSBjb21wdXRlZCBmcm9tIHRoZSBib290c3RyYXAgZGlzdHJpYnV0aW9uPyAqKgoKVGhpcyBzdGFuZGFyZCBlcnJvciBpcyBjb21wdXRlZCB1c2luZyBzb21lIHN0YXRpc3RpY2FsIHRoZW9yeSAoZm9yIHJlZmVyZW5jZSwgc2VlIFtTVEFUIDE1NSBOb3Rlc10oaHR0cHM6Ly9iY2hlZ2dlc2V0aC5naXRodWIuaW8vU3RhdDE1NU5vdGVzL2NvbmZpZGVuY2UtaW50ZXJ2YWxzLmh0bWwpKS4gVGhhdCBpcyB1c2VkIGluIGNvbnN0cnVjdGluZyB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbC4gCgojIENvbmZpZGVuY2UgaW4gUHJlZGljdGlvbnMKCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWluZm8iPgogIDxzdHJvbmc+WU9VUiBUVVJOISAoRXh0cmEgY2hhbGxlbmdlKSA8L3N0cm9uZz4KCkkgd291bGQgbGlrZSB0byBjb25zdHJ1Y3QgYSBjb25maWRlbmNlIGludGVydmFsIGZvciB0aGUgYXZlcmFnZSBwcmljZSBvZiBob21lcyB3aXRoIDIwMDAgc3FmdCBvZiBsaXZpbmcuIERlc2NyaWJlIGluIHdvcmRzIGhvdyB5b3UgY291bGQgdXNlIHRoZSBib290c3RyYXAgdGVjaG5pcXVlIHRvIGhlbHAgYW5zd2VyIHRoYXQgcXVlc3Rpb24uIFRoZW4sIGNvZGUgaXQhCgo8L2Rpdj4K