Learning Objectives


Upon completing today’s lab activity, students should be able to do the following using R and RStudio:

  1. Computing quantiles/percentiles given some data.

  2. Using bootstrapping to compute Confidence Intervals (CIs).


library(tidyverse)
library(openintro)
library(infer)
library(ggplot2)
library(gghighlight)


Computing Quantiles given Some Data


We can compute the quantiles or percentiles of a given data using the base R function called quantile.

# given some data (unordered)
x <- c(4,5,5,6,7,7,2,3,4,5,5,5)

# the 50th percentile (also known as the median)
print(quantile(x,0.50))
## 50% 
##   5
# the 2.5th percentile
print(quantile(x,0.025))
##  2.5% 
## 2.275
# the 97.5th percentile
print(quantile(x,0.975))
## 97.5% 
##     7


Case Study - Medical Consultant (Proportion)


One consultant tried to attract patients by noting the average complication rate for liver donor surgeries in the US is about 10%, but her clients have had only 3 complications in the 62 liver donor surgeries she has facilitated.

She claims this is strong evidence that her work meaningfully contributes to reducing complications.

Let \(p\) represent the true complication rate for liver donors working with this consultant. We estimate \(p\) using the data, and label the estimate \(\hat{p}\).

\[\hat{p} = \frac{3}{62} = 0.048 \longrightarrow \text{Observed Statistic}\]

\[p_0 = 0.10 \longrightarrow \text{The Null Statistic - the average complication rate in the US}\] The claim is that there is a causal connection, but the data are observational, so we must be on the lookout for confounding variables. We can’t conclude a causal connection for observational studies.

Objective: Estimate the unknown population proportion by using the sample to approximate the proportion of complications for a client of the medical consultant. Make a 95% confidence interval to give a plausible range of values for the population proportion.

# Even though we don't have the actual data, we have the sample proportion and we can work on that for performing bootstrapping.
set.seed(334422)
bsprop_med <- tibble(
  bsprop = rbinom(10000, size=62, prob=(3/62))/62 # this function simulates the binomial ("success" (complication) or "failure" (no complication))
)

bsprop_med_summary <- bsprop_med %>%
  summarise(
    bsprop_025 = quantile(bsprop, 0.025),
    bsprop_975 = quantile(bsprop, 0.975),
  )
ggplot(bsprop_med, aes(x = bsprop)) +
  geom_histogram(binwidth = 0.0075, fill = "gray") +
  annotate("segment", 
           x = bsprop_med_summary$bsprop_025, y = 0, 
           xend = bsprop_med_summary$bsprop_025, yend = 1000,
           linetype = "dashed", color="blue") +
  annotate("segment", 
           x = bsprop_med_summary$bsprop_975, y = 0, 
           xend = bsprop_med_summary$bsprop_975, yend = 1000,
           linetype = "dashed", color="blue") +
  annotate("text", x = bsprop_med_summary$bsprop_025, y = 1200, label = "2.5th\npercentile") +
  annotate("text", x = bsprop_med_summary$bsprop_975, y = 1200, label = "97.5th\npercentile") +
  labs(
    x = "Bootstrapped proportion of surgical complications",
    y = "Count",
    title = "10,000 bootstrapped proportions (with 95% CI)"
  )
The original medical consultant data is bootstrapped 10,000 times. Each simulation creates a sample from the original data where the proportion of a complication is 3/62. The bootstrap 2.5 percentile proportion is 0 and the 97.5 percentile is 0.113. The result is: we are confident that, in the population, the true probability of a complication is between 0% and 11.3%.

The original medical consultant data is bootstrapped 10,000 times. Each simulation creates a sample from the original data where the proportion of a complication is 3/62. The bootstrap 2.5 percentile proportion is 0 and the 97.5 percentile is 0.113. The result is: we are confident that, in the population, the true probability of a complication is between 0% and 11.3%.

The 95% Confidence Interval (CI): Using bootstrapping the true proportion of a complication is between 0 and 0.1129032. The interval overlaps the null statistic 0.10. There is a possibility that the consultant’s work is associated with a higher risk (\(p > 0.10\)), higher than the US average.


Case Study - Housing prices in Ames, Iowa (Mean)


In this section, we are using the ames data set which is available in the openintro package.

Data set contains information from the Ames Assessor’s Office used in computing assessed values for individual residential properties sold in Ames, IA from 2006 to 2010. Here, we are focusing on the sale price in USD.

prices <- ames %>% select(price)
mean_price <- mean(ames$price)
paste("Mean price = ",mean_price)
## [1] "Mean price =  180796.060068259"

The mean house sale price is

\[\bar{x} = 180796.06 \longrightarrow \text{Observed Statistic.}\]

Let \(\mu\) be the true mean price. We estimate \(\mu\) using the data, and label the estimate \(\bar{x}\).

Objective: Estimate the unknown population proportion by using the sample to approximate the mean house sale price.

set.seed(334422)

k <- 10000 # number of trials
n <- 100 # sample size

bs_prices <- rep_sample_n(prices,n,replace=TRUE,reps=k)

bs_prices_means <- bs_prices %>%
  group_by(replicate) %>% 
  summarize(stat = mean(price))


  • Make a 95% confidence interval to give a plausible range of values for the population proportion.
probs_95 <- c(0.025,0.975)

ci_95 <- bs_prices_means %>%
  pull(stat) %>%
  quantile(probs_95)
  
ci_95
##     2.5%    97.5% 
## 165654.6 196754.8

The 95% confidence interval is (165777.5,197069.0). We are 95% confident that the true mean house sale price is in between $165777.5 and $197069.0.

ggplot(bs_prices_means, aes(x = stat)) +
  geom_histogram(bins = 50, fill = "gray") +
  annotate("segment", 
           x = ci_95[1], y = 0, 
           xend = ci_95[1], yend = 400,
           linetype = "dashed", color = "blue") +
  annotate("segment", 
           x = ci_95[2], y = 0, 
           xend = ci_95[2], yend = 400,
           linetype = "dashed", color = "blue") +
  annotate("text", x = ci_95[1], y = 402, label = "2.5th\npercentile") +
  annotate("text", x = ci_95[2], y = 402, label = "97.5th\npercentile") +
  labs(
    x = "Bootstrapped proportion of sale prices",
    y = "Count",
    title = "10,000 bootstrapped means  (with 95% CI)"
  )


  • Make a 90% confidence interval to give a plausible range of values for the population proportion.
probs_90 <- c(0.05,0.95)

ci_90 <- bs_prices_means %>%
  pull(stat) %>%
  quantile(probs_90)
  
ci_90
##       5%      95% 
## 167904.5 194218.3

The 90% confidence interval is (168063.4,194202.3 ). We are 90% confident that the true mean house sale sprice is in between $168063.4 and $194202.3.

ggplot(bs_prices_means, aes(x = stat)) +
  geom_histogram(bins = 50, fill = "gray") +
  annotate("segment", 
           x = ci_90[1], y = 0, 
           xend = ci_90[1], yend = 400,
           linetype = "dashed", color = "blue") +
  annotate("segment", 
           x = ci_90[2], y = 0, 
           xend = ci_90[2], yend = 400,
           linetype = "dashed", color = "blue") +
  annotate("text", x = ci_90[1], y = 402, label = "5th\npercentile") +
  annotate("text", x = ci_90[2], y = 402, label = "95th\npercentile") +
  labs(
    x = "Bootstrapped proportion of sale prices",
    y = "Count",
    title = "10,000 bootstrapped means  (with 90% CI)"
  )


Case Study - Climate Change (Proportion)

This section is from the textbook OpenIntro: Section 15.4

A 2019 Pew Research report states the following:

To keep our computation simple, we will assume a total population size of 100,000 (even though that’s smaller than the population size of all US adults).

Roughly six-in-ten U.S. adults (62%) say climate change is currently affecting their local community either a great deal or some, according to a new Pew Research Center survey.

Source: Most Americans say climate change impacts their community, but effects vary by region

In this exercise, you will assume this 62% is a true population proportion and learn about how sample proportions can vary from sample to sample by taking smaller samples from the population. We will first create our population assuming a population size of 100,000. This means 62,000 (62%) of the adult population think climate change impacts their community, and the remaining 38,000 does not think so.

NOTE: Population parameters are unknown. This exercise pretends we know the popoulation proportion for demonstration puposes.

us_adults <- tibble(
  climate_change_affects = c(rep("Yes", 62000), rep("No", 38000))
)
ggplot(us_adults, aes(x = climate_change_affects)) +
  geom_bar() +
  labs(
    x = "", y = "",
    title = "Do you think climate change is affecting your local community?"
  ) +
  coord_flip() 

us_adults %>%
  count(climate_change_affects) %>%
  mutate(p = n /sum(n))
## # A tibble: 2 × 3
##   climate_change_affects     n     p
##   <chr>                  <int> <dbl>
## 1 No                     38000  0.38
## 2 Yes                    62000  0.62

In this section, you’ll start with a simple random sample of size 60 from the population.

n <- 60
samp <- us_adults %>%
  sample_n(size = n)

In essence, bootstrapping assumes that there are more of observations in the populations like the ones in the observed sample. So we “reconstruct” the population by resampling from our sample, with replacement. The bootstrapping scheme is as follows:

  • Step 1. Take a bootstrap sample - a random sample taken with replacement from the original sample.

  • Step 2. Calculate the bootstrap statistic (e.g. proportion, mean, etc.) computed on the bootstrap samples.

  • Step 3. Repeat steps (1) and (2) many times to create a bootstrap distribution - a distribution of bootstrap statistics.

  • Step 4. Calculate the bounds of the XX% confidence interval as the middle XX% of the bootstrap distribution.

The two methods to compute the confidence interval is using the percentile method or using the standard error method.

Instead of coding up each of these steps, we will construct confidence intervals using the infer package.

This code will find the 95 percent confidence interval for proportion of US adults who think climate change affects their local community.

samp %>%
  specify(response = climate_change_affects, success = "Yes") %>%
  generate(reps = 1000, type = "bootstrap") %>%
  calculate(stat = "prop") %>%
  get_ci(level = 0.95, type = "percentile")
## # A tibble: 1 × 2
##   lower_ci upper_ci
##      <dbl>    <dbl>
## 1    0.516     0.75
  • In specify we specify the response variable and the level of that variable we are calling a success.

  • In generate we provide the number of resamples we want from the population in the reps argument (this should be a reasonably large number) as well as the type of resampling we want to do, which is “bootstrap” in the case of constructing a confidence interval.

  • Then, we calculate the sample statistic of interest for each of these resamples, which is proportion.

  • To compute the confidence interval, we use the get_ci function and use 0.95 as the confidence level. Here, wer are using the percentile method.

Feel free to test out the rest of the arguments for these functions, since these commands will be used together to calculate confidence intervals and solve inference problems for the rest of the semester.

To recap: even though we don’t know what the full population looks like, we’re 95% confident that the true proportion of US adults who think climate change affects their local community is between the two bounds reported as result of this pipeline.

Earlier in this section, we assumed that 62% is a true population proportion. In our 95% interval, the 62% is within this interval, which means that we captured the true population proportion. Again, population parameters are unknown, this example is for demonstration purposes. In reality, There is still a 5% chance that the interval is wrong.


Lab Exercises


Note: You must include your code and results to answer the exercise problems.


I. Climate Change

From the Case Study - Climate Change (Proportion) section, use similar codes to answer the following questions. These problems requre a combination of what we have learned in lab since the first week (e.g. for loops, while loops, conditional statements etc).

For convenience, below is the R code used in this section.

# "the population" or "the data"
us_adults <- tibble(
  climate_change_affects = c(rep("Yes", 62000), rep("No", 38000))
)


  1. Obtain a random sample of 60 from the us_adults data. Calculate the sample proportion, and use these to calculate and store the lower and upper bounds of the 95% confidence interval (use 1000 trials or resamples). Repeat these steps 100 times.

  2. From problem 1, you should have 100 95% confidence intervals. Compute the number of intervals that contain the true population proportion. Remember that we assumed that the true population proportion is 0.62 (62%).

  3. A 95% confidence interval gives us a region where, had we redone the same data, then 95% of the time, the true value \(p\) will be contained in the interval. What proportion of your confidence intervals include the true population proportion? Is this proportion exactly equal or close to the confidence level? Explain your reasoning.

  4. Choose a different confidence level than 95%. Would you expect a confidence interval at this level to be wider or narrower than the confidence interval you calculated at the 95% confidence level? Explain your reasoning.

  5. Find a confidence interval for the proportion of US Adults who think climate change is affecting their local community with a confidence level of your choosing (other than 95%) and interpret it.


LS0tCnRpdGxlOiAiMyAtIENvbmZpZGVuY2UgSW50ZXJ2YWxzIHdpdGggQm9vdHN0cmFwcGluZyIKYXV0aG9yOiAiQWxleCBKb2huIFF1aWphbm8iCmRhdGU6ICIxMC8wNS8yMDIxIgpvdXRwdXQ6IG9wZW5pbnRybzo6bGFiX3JlcG9ydAotLS0KCiMjICoqTGVhcm5pbmcgT2JqZWN0aXZlcyoqCgo8YnI+CgpVcG9uIGNvbXBsZXRpbmcgdG9kYXkncyBsYWIgYWN0aXZpdHksIHN0dWRlbnRzIHNob3VsZCBiZSBhYmxlIHRvIGRvIHRoZSBmb2xsb3dpbmcgdXNpbmcgUiBhbmQgUlN0dWRpbzoKCiAgMS4gQ29tcHV0aW5nIHF1YW50aWxlcy9wZXJjZW50aWxlcyBnaXZlbiBzb21lIGRhdGEuCiAgCiAgMi4gVXNpbmcgYm9vdHN0cmFwcGluZyB0byBjb21wdXRlIENvbmZpZGVuY2UgSW50ZXJ2YWxzIChDSXMpLgoKPGJyPgoKYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShvcGVuaW50cm8pCmxpYnJhcnkoaW5mZXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ2hpZ2hsaWdodCkKYGBgCgo8YnI+CgojIyAqKkNvbXB1dGluZyBRdWFudGlsZXMgZ2l2ZW4gU29tZSBEYXRhKioKCjxicj4KCldlIGNhbiBjb21wdXRlIHRoZSBxdWFudGlsZXMgb3IgcGVyY2VudGlsZXMgb2YgYSBnaXZlbiBkYXRhIHVzaW5nIHRoZSBiYXNlIFIgZnVuY3Rpb24gY2FsbGVkIGBxdWFudGlsZWAuCgpgYGB7cn0KIyBnaXZlbiBzb21lIGRhdGEgKHVub3JkZXJlZCkKeCA8LSBjKDQsNSw1LDYsNyw3LDIsMyw0LDUsNSw1KQoKIyB0aGUgNTB0aCBwZXJjZW50aWxlIChhbHNvIGtub3duIGFzIHRoZSBtZWRpYW4pCnByaW50KHF1YW50aWxlKHgsMC41MCkpCgojIHRoZSAyLjV0aCBwZXJjZW50aWxlCnByaW50KHF1YW50aWxlKHgsMC4wMjUpKQoKIyB0aGUgOTcuNXRoIHBlcmNlbnRpbGUKcHJpbnQocXVhbnRpbGUoeCwwLjk3NSkpCmBgYAoKPGJyPgoKIyMgKipDYXNlIFN0dWR5IC0gTWVkaWNhbCBDb25zdWx0YW50IChQcm9wb3J0aW9uKSoqCgo8YnI+CgpPbmUgY29uc3VsdGFudCB0cmllZCB0byBhdHRyYWN0IHBhdGllbnRzIGJ5IG5vdGluZyB0aGUgYXZlcmFnZSBjb21wbGljYXRpb24gcmF0ZSBmb3IgbGl2ZXIgZG9ub3Igc3VyZ2VyaWVzIGluIHRoZSBVUyBpcyBhYm91dCAxMCUsIGJ1dCBoZXIgY2xpZW50cyBoYXZlIGhhZCBvbmx5IDMgY29tcGxpY2F0aW9ucyBpbiB0aGUgNjIgbGl2ZXIgZG9ub3Igc3VyZ2VyaWVzIHNoZSBoYXMgZmFjaWxpdGF0ZWQuCgpTaGUgY2xhaW1zIHRoaXMgaXMgc3Ryb25nIGV2aWRlbmNlIHRoYXQgaGVyIHdvcmsgbWVhbmluZ2Z1bGx5IGNvbnRyaWJ1dGVzIHRvIHJlZHVjaW5nIGNvbXBsaWNhdGlvbnMuCgpMZXQgJHAkIHJlcHJlc2VudCB0aGUgdHJ1ZSBjb21wbGljYXRpb24gcmF0ZSBmb3IgbGl2ZXIgZG9ub3JzIHdvcmtpbmcgd2l0aCB0aGlzIGNvbnN1bHRhbnQuIFdlIGVzdGltYXRlICRwJCB1c2luZyB0aGUgZGF0YSwgYW5kIGxhYmVsIHRoZSBlc3RpbWF0ZSAkXGhhdHtwfSQuCiAgICAKJCRcaGF0e3B9ID0gXGZyYWN7M317NjJ9ID0gMC4wNDggXGxvbmdyaWdodGFycm93IFx0ZXh0e09ic2VydmVkIFN0YXRpc3RpY30kJAogIAokJHBfMCA9IDAuMTAgXGxvbmdyaWdodGFycm93IFx0ZXh0e1RoZSBOdWxsIFN0YXRpc3RpYyAtIHRoZSBhdmVyYWdlIGNvbXBsaWNhdGlvbiByYXRlIGluIHRoZSBVU30kJApUaGUgY2xhaW0gaXMgdGhhdCB0aGVyZSBpcyBhIGNhdXNhbCBjb25uZWN0aW9uLCBidXQgdGhlIGRhdGEgYXJlIG9ic2VydmF0aW9uYWwsIHNvIHdlIG11c3QgYmUgb24gdGhlIGxvb2tvdXQgZm9yIGNvbmZvdW5kaW5nIHZhcmlhYmxlcy4gV2UgY2FuJ3QgY29uY2x1ZGUgYSBjYXVzYWwgY29ubmVjdGlvbiBmb3Igb2JzZXJ2YXRpb25hbCBzdHVkaWVzLgogIAoqKk9iamVjdGl2ZToqKiBFc3RpbWF0ZSB0aGUgdW5rbm93biBwb3B1bGF0aW9uIHByb3BvcnRpb24gYnkgdXNpbmcgdGhlIHNhbXBsZSB0byBhcHByb3hpbWF0ZSB0aGUgcHJvcG9ydGlvbiBvZiBjb21wbGljYXRpb25zIGZvciBhIGNsaWVudCBvZiB0aGUgbWVkaWNhbCBjb25zdWx0YW50LiBNYWtlIGEgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgdG8gZ2l2ZSBhIHBsYXVzaWJsZSByYW5nZSBvZiB2YWx1ZXMgZm9yIHRoZSBwb3B1bGF0aW9uIHByb3BvcnRpb24uCiAgCmBgYHtyfQojIEV2ZW4gdGhvdWdoIHdlIGRvbid0IGhhdmUgdGhlIGFjdHVhbCBkYXRhLCB3ZSBoYXZlIHRoZSBzYW1wbGUgcHJvcG9ydGlvbiBhbmQgd2UgY2FuIHdvcmsgb24gdGhhdCBmb3IgcGVyZm9ybWluZyBib290c3RyYXBwaW5nLgpzZXQuc2VlZCgzMzQ0MjIpCmJzcHJvcF9tZWQgPC0gdGliYmxlKAogIGJzcHJvcCA9IHJiaW5vbSgxMDAwMCwgc2l6ZT02MiwgcHJvYj0oMy82MikpLzYyICMgdGhpcyBmdW5jdGlvbiBzaW11bGF0ZXMgdGhlIGJpbm9taWFsICgic3VjY2VzcyIgKGNvbXBsaWNhdGlvbikgb3IgImZhaWx1cmUiIChubyBjb21wbGljYXRpb24pKQopCgpic3Byb3BfbWVkX3N1bW1hcnkgPC0gYnNwcm9wX21lZCAlPiUKICBzdW1tYXJpc2UoCiAgICBic3Byb3BfMDI1ID0gcXVhbnRpbGUoYnNwcm9wLCAwLjAyNSksCiAgICBic3Byb3BfOTc1ID0gcXVhbnRpbGUoYnNwcm9wLCAwLjk3NSksCiAgKQpgYGAKCmBgYHtyIE1lZENvbnNCU1NpbSwgZmlnLmNhcCA9ICJUaGUgb3JpZ2luYWwgbWVkaWNhbCBjb25zdWx0YW50IGRhdGEgaXMgYm9vdHN0cmFwcGVkIDEwLDAwMCB0aW1lcy4gRWFjaCBzaW11bGF0aW9uIGNyZWF0ZXMgYSBzYW1wbGUgZnJvbSB0aGUgb3JpZ2luYWwgZGF0YSB3aGVyZSB0aGUgcHJvcG9ydGlvbiBvZiBhIGNvbXBsaWNhdGlvbiBpcyAzLzYyLiBUaGUgYm9vdHN0cmFwIDIuNSBwZXJjZW50aWxlIHByb3BvcnRpb24gaXMgMCBhbmQgdGhlIDk3LjUgcGVyY2VudGlsZSBpcyAwLjExMy4gVGhlIHJlc3VsdCBpczogd2UgYXJlIGNvbmZpZGVudCB0aGF0LCBpbiB0aGUgcG9wdWxhdGlvbiwgdGhlIHRydWUgcHJvYmFiaWxpdHkgb2YgYSBjb21wbGljYXRpb24gaXMgYmV0d2VlbiAwJSBhbmQgMTEuMyUuIiwgb3V0LndpZHRoPSI1MCUiLCBmaWcuYWxpZ249J2NlbnRlcid9CmdncGxvdChic3Byb3BfbWVkLCBhZXMoeCA9IGJzcHJvcCkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDAuMDA3NSwgZmlsbCA9ICJncmF5IikgKwogIGFubm90YXRlKCJzZWdtZW50IiwgCiAgICAgICAgICAgeCA9IGJzcHJvcF9tZWRfc3VtbWFyeSRic3Byb3BfMDI1LCB5ID0gMCwgCiAgICAgICAgICAgeGVuZCA9IGJzcHJvcF9tZWRfc3VtbWFyeSRic3Byb3BfMDI1LCB5ZW5kID0gMTAwMCwKICAgICAgICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvcj0iYmx1ZSIpICsKICBhbm5vdGF0ZSgic2VnbWVudCIsIAogICAgICAgICAgIHggPSBic3Byb3BfbWVkX3N1bW1hcnkkYnNwcm9wXzk3NSwgeSA9IDAsIAogICAgICAgICAgIHhlbmQgPSBic3Byb3BfbWVkX3N1bW1hcnkkYnNwcm9wXzk3NSwgeWVuZCA9IDEwMDAsCiAgICAgICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3I9ImJsdWUiKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gYnNwcm9wX21lZF9zdW1tYXJ5JGJzcHJvcF8wMjUsIHkgPSAxMjAwLCBsYWJlbCA9ICIyLjV0aFxucGVyY2VudGlsZSIpICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSBic3Byb3BfbWVkX3N1bW1hcnkkYnNwcm9wXzk3NSwgeSA9IDEyMDAsIGxhYmVsID0gIjk3LjV0aFxucGVyY2VudGlsZSIpICsKICBsYWJzKAogICAgeCA9ICJCb290c3RyYXBwZWQgcHJvcG9ydGlvbiBvZiBzdXJnaWNhbCBjb21wbGljYXRpb25zIiwKICAgIHkgPSAiQ291bnQiLAogICAgdGl0bGUgPSAiMTAsMDAwIGJvb3RzdHJhcHBlZCBwcm9wb3J0aW9ucyAod2l0aCA5NSUgQ0kpIgogICkKYGBgCgoqKlRoZSA5NVwlIENvbmZpZGVuY2UgSW50ZXJ2YWwgKENJKToqKiBVc2luZyBib290c3RyYXBwaW5nIHRoZSB0cnVlIHByb3BvcnRpb24gb2YgYSBjb21wbGljYXRpb24gaXMgYmV0d2VlbiBgciBic3Byb3BfbWVkX3N1bW1hcnkkYnNwcm9wXzAyNWAgYW5kIGByIGJzcHJvcF9tZWRfc3VtbWFyeSRic3Byb3BfOTc1YC4gVGhlIGludGVydmFsIG92ZXJsYXBzIHRoZSBudWxsIHN0YXRpc3RpYyAwLjEwLiBUaGVyZSBpcyBhIHBvc3NpYmlsaXR5IHRoYXQgdGhlIGNvbnN1bHRhbnTigJlzIHdvcmsgaXMgYXNzb2NpYXRlZCB3aXRoIGEgaGlnaGVyIHJpc2sgKCRwID4gMC4xMCQpLCBoaWdoZXIgdGhhbiB0aGUgVVMgYXZlcmFnZS4KCjxicj4KCiMjICoqQ2FzZSBTdHVkeSAtIEhvdXNpbmcgcHJpY2VzIGluIEFtZXMsIElvd2EgKE1lYW4pKioKCjxicj4KCkluIHRoaXMgc2VjdGlvbiwgd2UgYXJlIHVzaW5nIHRoZSBgYW1lc2AgZGF0YSBzZXQgd2hpY2ggaXMgYXZhaWxhYmxlIGluIHRoZSBgb3BlbmludHJvYCBwYWNrYWdlLgoKRGF0YSBzZXQgY29udGFpbnMgaW5mb3JtYXRpb24gZnJvbSB0aGUgQW1lcyBBc3Nlc3NvcidzIE9mZmljZSB1c2VkIGluIGNvbXB1dGluZyBhc3Nlc3NlZCB2YWx1ZXMgZm9yIGluZGl2aWR1YWwgcmVzaWRlbnRpYWwgcHJvcGVydGllcyBzb2xkIGluIEFtZXMsIElBIGZyb20gMjAwNiB0byAyMDEwLiBIZXJlLCB3ZSBhcmUgZm9jdXNpbmcgb24gdGhlIHNhbGUgcHJpY2UgaW4gVVNELgoKYGBge3J9CnByaWNlcyA8LSBhbWVzICU+JSBzZWxlY3QocHJpY2UpCm1lYW5fcHJpY2UgPC0gbWVhbihhbWVzJHByaWNlKQpwYXN0ZSgiTWVhbiBwcmljZSA9ICIsbWVhbl9wcmljZSkKYGBgCgpUaGUgbWVhbiBob3VzZSBzYWxlIHByaWNlIGlzIAoKCiQkXGJhcnt4fSA9IDE4MDc5Ni4wNiBcbG9uZ3JpZ2h0YXJyb3cgXHRleHR7T2JzZXJ2ZWQgU3RhdGlzdGljLn0kJAoKTGV0ICRcbXUkIGJlIHRoZSB0cnVlIG1lYW4gcHJpY2UuIFdlIGVzdGltYXRlICRcbXUkIHVzaW5nIHRoZSBkYXRhLCBhbmQgbGFiZWwgdGhlIGVzdGltYXRlICRcYmFye3h9JC4KCioqT2JqZWN0aXZlOioqIEVzdGltYXRlIHRoZSB1bmtub3duIHBvcHVsYXRpb24gcHJvcG9ydGlvbiBieSB1c2luZyB0aGUgc2FtcGxlIHRvIGFwcHJveGltYXRlIHRoZSBtZWFuIGhvdXNlIHNhbGUgcHJpY2UuIAogIApgYGB7cn0Kc2V0LnNlZWQoMzM0NDIyKQoKayA8LSAxMDAwMCAjIG51bWJlciBvZiB0cmlhbHMKbiA8LSAxMDAgIyBzYW1wbGUgc2l6ZQoKYnNfcHJpY2VzIDwtIHJlcF9zYW1wbGVfbihwcmljZXMsbixyZXBsYWNlPVRSVUUscmVwcz1rKQoKYnNfcHJpY2VzX21lYW5zIDwtIGJzX3ByaWNlcyAlPiUKICBncm91cF9ieShyZXBsaWNhdGUpICU+JSAKICBzdW1tYXJpemUoc3RhdCA9IG1lYW4ocHJpY2UpKQpgYGAKCjxicj4KCiAgKiBNYWtlIGEgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgdG8gZ2l2ZSBhIHBsYXVzaWJsZSByYW5nZSBvZiB2YWx1ZXMgZm9yIHRoZSBwb3B1bGF0aW9uIHByb3BvcnRpb24uCgpgYGB7cn0KcHJvYnNfOTUgPC0gYygwLjAyNSwwLjk3NSkKCmNpXzk1IDwtIGJzX3ByaWNlc19tZWFucyAlPiUKICBwdWxsKHN0YXQpICU+JQogIHF1YW50aWxlKHByb2JzXzk1KQogIApjaV85NQpgYGAKClRoZSA5NVwlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgaXMgKDE2NTc3Ny41LDE5NzA2OS4wKS4gV2UgYXJlIDk1XCUgY29uZmlkZW50IHRoYXQgdGhlIHRydWUgbWVhbiBob3VzZSBzYWxlIHByaWNlIGlzIGluIGJldHdlZW4gXCQxNjU3NzcuNSBhbmQgXCQxOTcwNjkuMC4KCmBgYHtyfQpnZ3Bsb3QoYnNfcHJpY2VzX21lYW5zLCBhZXMoeCA9IHN0YXQpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDUwLCBmaWxsID0gImdyYXkiKSArCiAgYW5ub3RhdGUoInNlZ21lbnQiLCAKICAgICAgICAgICB4ID0gY2lfOTVbMV0sIHkgPSAwLCAKICAgICAgICAgICB4ZW5kID0gY2lfOTVbMV0sIHllbmQgPSA0MDAsCiAgICAgICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiYmx1ZSIpICsKICBhbm5vdGF0ZSgic2VnbWVudCIsIAogICAgICAgICAgIHggPSBjaV85NVsyXSwgeSA9IDAsIAogICAgICAgICAgIHhlbmQgPSBjaV85NVsyXSwgeWVuZCA9IDQwMCwKICAgICAgICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJibHVlIikgKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IGNpXzk1WzFdLCB5ID0gNDAyLCBsYWJlbCA9ICIyLjV0aFxucGVyY2VudGlsZSIpICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSBjaV85NVsyXSwgeSA9IDQwMiwgbGFiZWwgPSAiOTcuNXRoXG5wZXJjZW50aWxlIikgKwogIGxhYnMoCiAgICB4ID0gIkJvb3RzdHJhcHBlZCBwcm9wb3J0aW9uIG9mIHNhbGUgcHJpY2VzIiwKICAgIHkgPSAiQ291bnQiLAogICAgdGl0bGUgPSAiMTAsMDAwIGJvb3RzdHJhcHBlZCBtZWFucyAgKHdpdGggOTUlIENJKSIKICApCmBgYAoKPGJyPgoKICAqIE1ha2UgYSA5MCUgY29uZmlkZW5jZSBpbnRlcnZhbCB0byBnaXZlIGEgcGxhdXNpYmxlIHJhbmdlIG9mIHZhbHVlcyBmb3IgdGhlIHBvcHVsYXRpb24gcHJvcG9ydGlvbi4KCmBgYHtyfQpwcm9ic185MCA8LSBjKDAuMDUsMC45NSkKCmNpXzkwIDwtIGJzX3ByaWNlc19tZWFucyAlPiUKICBwdWxsKHN0YXQpICU+JQogIHF1YW50aWxlKHByb2JzXzkwKQogIApjaV85MApgYGAKClRoZSA5MFwlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgaXMgKDE2ODA2My40LDE5NDIwMi4zICkuIFdlIGFyZSA5MFwlIGNvbmZpZGVudCB0aGF0IHRoZSB0cnVlIG1lYW4gaG91c2Ugc2FsZSBzcHJpY2UgaXMgaW4gYmV0d2VlbiBcJDE2ODA2My40IGFuZCBcJDE5NDIwMi4zLgoKYGBge3J9CmdncGxvdChic19wcmljZXNfbWVhbnMsIGFlcyh4ID0gc3RhdCkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNTAsIGZpbGwgPSAiZ3JheSIpICsKICBhbm5vdGF0ZSgic2VnbWVudCIsIAogICAgICAgICAgIHggPSBjaV85MFsxXSwgeSA9IDAsIAogICAgICAgICAgIHhlbmQgPSBjaV85MFsxXSwgeWVuZCA9IDQwMCwKICAgICAgICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJibHVlIikgKwogIGFubm90YXRlKCJzZWdtZW50IiwgCiAgICAgICAgICAgeCA9IGNpXzkwWzJdLCB5ID0gMCwgCiAgICAgICAgICAgeGVuZCA9IGNpXzkwWzJdLCB5ZW5kID0gNDAwLAogICAgICAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gImJsdWUiKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gY2lfOTBbMV0sIHkgPSA0MDIsIGxhYmVsID0gIjV0aFxucGVyY2VudGlsZSIpICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSBjaV85MFsyXSwgeSA9IDQwMiwgbGFiZWwgPSAiOTV0aFxucGVyY2VudGlsZSIpICsKICBsYWJzKAogICAgeCA9ICJCb290c3RyYXBwZWQgcHJvcG9ydGlvbiBvZiBzYWxlIHByaWNlcyIsCiAgICB5ID0gIkNvdW50IiwKICAgIHRpdGxlID0gIjEwLDAwMCBib290c3RyYXBwZWQgbWVhbnMgICh3aXRoIDkwJSBDSSkiCiAgKQpgYGAKCjxicj4KCiMjICoqQ2FzZSBTdHVkeSAtIENsaW1hdGUgQ2hhbmdlIChQcm9wb3J0aW9uKSoqCgpUaGlzIHNlY3Rpb24gaXMgZnJvbSB0aGUgdGV4dGJvb2sgW09wZW5JbnRybzogU2VjdGlvbiAxNS40XShodHRwczovL29wZW5pbnRyby5zaGlueWFwcHMuaW8vY29uZmlkZW5jZV9pbnRlcnZhbHMvI2NvbmZpZGVuY2VfbGV2ZWxzKXt0YXJnZXQ9Il9ibGFuayJ9CgpBIDIwMTkgUGV3IFJlc2VhcmNoIHJlcG9ydCBzdGF0ZXMgdGhlIGZvbGxvd2luZzoKClRvIGtlZXAgb3VyIGNvbXB1dGF0aW9uIHNpbXBsZSwgd2Ugd2lsbCBhc3N1bWUgYSB0b3RhbCBwb3B1bGF0aW9uIHNpemUgb2YgMTAwLDAwMCAoZXZlbiB0aG91Z2ggdGhhdOKAmXMgc21hbGxlciB0aGFuIHRoZSBwb3B1bGF0aW9uIHNpemUgb2YgYWxsIFVTIGFkdWx0cykuCgpSb3VnaGx5IHNpeC1pbi10ZW4gVS5TLiBhZHVsdHMgKDYyJSkgc2F5IGNsaW1hdGUgY2hhbmdlIGlzIGN1cnJlbnRseSBhZmZlY3RpbmcgdGhlaXIgbG9jYWwgY29tbXVuaXR5IGVpdGhlciBhIGdyZWF0IGRlYWwgb3Igc29tZSwgYWNjb3JkaW5nIHRvIGEgbmV3IFBldyBSZXNlYXJjaCBDZW50ZXIgc3VydmV5LgoKU291cmNlOiBbTW9zdCBBbWVyaWNhbnMgc2F5IGNsaW1hdGUgY2hhbmdlIGltcGFjdHMgdGhlaXIgY29tbXVuaXR5LCBidXQgZWZmZWN0cyB2YXJ5IGJ5IHJlZ2lvbl0oaHR0cHM6Ly93d3cucGV3cmVzZWFyY2gub3JnL2ZhY3QtdGFuay8yMDE5LzEyLzAyL21vc3QtYW1lcmljYW5zLXNheS1jbGltYXRlLWNoYW5nZS1pbXBhY3RzLXRoZWlyLWNvbW11bml0eS1idXQtZWZmZWN0cy12YXJ5LWJ5LXJlZ2lvbi8pe3RhcmdldD0iX2JsYW5rIn0KCkluIHRoaXMgZXhlcmNpc2UsIHlvdSB3aWxsIGFzc3VtZSB0aGlzIDYyJSBpcyBhIHRydWUgcG9wdWxhdGlvbiBwcm9wb3J0aW9uIGFuZCBsZWFybiBhYm91dCBob3cgc2FtcGxlIHByb3BvcnRpb25zIGNhbiB2YXJ5IGZyb20gc2FtcGxlIHRvIHNhbXBsZSBieSB0YWtpbmcgc21hbGxlciBzYW1wbGVzIGZyb20gdGhlIHBvcHVsYXRpb24uIFdlIHdpbGwgZmlyc3QgY3JlYXRlIG91ciBwb3B1bGF0aW9uIGFzc3VtaW5nIGEgcG9wdWxhdGlvbiBzaXplIG9mIDEwMCwwMDAuIFRoaXMgbWVhbnMgNjIsMDAwICg2MiUpIG9mIHRoZSBhZHVsdCBwb3B1bGF0aW9uIHRoaW5rIGNsaW1hdGUgY2hhbmdlIGltcGFjdHMgdGhlaXIgY29tbXVuaXR5LCBhbmQgdGhlIHJlbWFpbmluZyAzOCwwMDAgZG9lcyBub3QgdGhpbmsgc28uCgpOT1RFOiBQb3B1bGF0aW9uIHBhcmFtZXRlcnMgYXJlIHVua25vd24uIFRoaXMgZXhlcmNpc2UgcHJldGVuZHMgd2Uga25vdyB0aGUgcG9wb3VsYXRpb24gcHJvcG9ydGlvbiBmb3IgZGVtb25zdHJhdGlvbiBwdXBvc2VzLgoKYGBge3J9CnVzX2FkdWx0cyA8LSB0aWJibGUoCiAgY2xpbWF0ZV9jaGFuZ2VfYWZmZWN0cyA9IGMocmVwKCJZZXMiLCA2MjAwMCksIHJlcCgiTm8iLCAzODAwMCkpCikKYGBgCgpgYGB7cn0KZ2dwbG90KHVzX2FkdWx0cywgYWVzKHggPSBjbGltYXRlX2NoYW5nZV9hZmZlY3RzKSkgKwogIGdlb21fYmFyKCkgKwogIGxhYnMoCiAgICB4ID0gIiIsIHkgPSAiIiwKICAgIHRpdGxlID0gIkRvIHlvdSB0aGluayBjbGltYXRlIGNoYW5nZSBpcyBhZmZlY3RpbmcgeW91ciBsb2NhbCBjb21tdW5pdHk/IgogICkgKwogIGNvb3JkX2ZsaXAoKSAKYGBgCgpgYGB7cn0KdXNfYWR1bHRzICU+JQogIGNvdW50KGNsaW1hdGVfY2hhbmdlX2FmZmVjdHMpICU+JQogIG11dGF0ZShwID0gbiAvc3VtKG4pKQpgYGAKCkluIHRoaXMgc2VjdGlvbiwgeW914oCZbGwgc3RhcnQgd2l0aCBhIHNpbXBsZSByYW5kb20gc2FtcGxlIG9mIHNpemUgNjAgZnJvbSB0aGUgcG9wdWxhdGlvbi4KCmBgYHtyfQpuIDwtIDYwCnNhbXAgPC0gdXNfYWR1bHRzICU+JQogIHNhbXBsZV9uKHNpemUgPSBuKQpgYGAKCkluIGVzc2VuY2UsIGJvb3RzdHJhcHBpbmcgYXNzdW1lcyB0aGF0IHRoZXJlIGFyZSBtb3JlIG9mIG9ic2VydmF0aW9ucyBpbiB0aGUgcG9wdWxhdGlvbnMgbGlrZSB0aGUgb25lcyBpbiB0aGUgb2JzZXJ2ZWQgc2FtcGxlLiBTbyB3ZSDigJxyZWNvbnN0cnVjdOKAnSB0aGUgcG9wdWxhdGlvbiBieSByZXNhbXBsaW5nIGZyb20gb3VyIHNhbXBsZSwgd2l0aCByZXBsYWNlbWVudC4gVGhlIGJvb3RzdHJhcHBpbmcgc2NoZW1lIGlzIGFzIGZvbGxvd3M6CgogICogU3RlcCAxLiBUYWtlIGEgYm9vdHN0cmFwIHNhbXBsZSAtIGEgcmFuZG9tIHNhbXBsZSB0YWtlbiB3aXRoIHJlcGxhY2VtZW50IGZyb20gdGhlIG9yaWdpbmFsIHNhbXBsZS4KCiAgKiBTdGVwIDIuIENhbGN1bGF0ZSB0aGUgYm9vdHN0cmFwIHN0YXRpc3RpYyAoZS5nLiBwcm9wb3J0aW9uLCBtZWFuLCBldGMuKSBjb21wdXRlZCBvbiB0aGUgYm9vdHN0cmFwIHNhbXBsZXMuCgogICogU3RlcCAzLiBSZXBlYXQgc3RlcHMgKDEpIGFuZCAoMikgbWFueSB0aW1lcyB0byBjcmVhdGUgYSBib290c3RyYXAgZGlzdHJpYnV0aW9uIC0gYSBkaXN0cmlidXRpb24gb2YgYm9vdHN0cmFwIHN0YXRpc3RpY3MuCgogICogU3RlcCA0LiBDYWxjdWxhdGUgdGhlIGJvdW5kcyBvZiB0aGUgWFglIGNvbmZpZGVuY2UgaW50ZXJ2YWwgYXMgdGhlIG1pZGRsZSBYWCUgb2YgdGhlIGJvb3RzdHJhcCBkaXN0cmlidXRpb24uCiAgClRoZSB0d28gbWV0aG9kcyB0byBjb21wdXRlIHRoZSBjb25maWRlbmNlIGludGVydmFsIGlzIHVzaW5nIHRoZSBwZXJjZW50aWxlIG1ldGhvZCBvciB1c2luZyB0aGUgc3RhbmRhcmQgZXJyb3IgbWV0aG9kLgoKSW5zdGVhZCBvZiBjb2RpbmcgdXAgZWFjaCBvZiB0aGVzZSBzdGVwcywgd2Ugd2lsbCBjb25zdHJ1Y3QgY29uZmlkZW5jZSBpbnRlcnZhbHMgdXNpbmcgdGhlIGBpbmZlcmAgcGFja2FnZS4KClRoaXMgY29kZSB3aWxsIGZpbmQgdGhlIDk1IHBlcmNlbnQgY29uZmlkZW5jZSBpbnRlcnZhbCBmb3IgcHJvcG9ydGlvbiBvZiBVUyBhZHVsdHMgd2hvIHRoaW5rIGNsaW1hdGUgY2hhbmdlIGFmZmVjdHMgdGhlaXIgbG9jYWwgY29tbXVuaXR5LgoKYGBge3J9CnNhbXAgJT4lCiAgc3BlY2lmeShyZXNwb25zZSA9IGNsaW1hdGVfY2hhbmdlX2FmZmVjdHMsIHN1Y2Nlc3MgPSAiWWVzIikgJT4lCiAgZ2VuZXJhdGUocmVwcyA9IDEwMDAsIHR5cGUgPSAiYm9vdHN0cmFwIikgJT4lCiAgY2FsY3VsYXRlKHN0YXQgPSAicHJvcCIpICU+JQogIGdldF9jaShsZXZlbCA9IDAuOTUsIHR5cGUgPSAicGVyY2VudGlsZSIpCmBgYAoKICAqIEluIGBzcGVjaWZ5YCB3ZSBzcGVjaWZ5IHRoZSByZXNwb25zZSB2YXJpYWJsZSBhbmQgdGhlIGxldmVsIG9mIHRoYXQgdmFyaWFibGUgd2UgYXJlIGNhbGxpbmcgYSBzdWNjZXNzLgoKICAqIEluIGBnZW5lcmF0ZWAgd2UgcHJvdmlkZSB0aGUgbnVtYmVyIG9mIHJlc2FtcGxlcyB3ZSB3YW50IGZyb20gdGhlIHBvcHVsYXRpb24gaW4gdGhlIHJlcHMgYXJndW1lbnQgKHRoaXMgc2hvdWxkIGJlIGEgcmVhc29uYWJseSBsYXJnZSBudW1iZXIpIGFzIHdlbGwgYXMgdGhlIHR5cGUgb2YgcmVzYW1wbGluZyB3ZSB3YW50IHRvIGRvLCB3aGljaCBpcyAiYm9vdHN0cmFwIiBpbiB0aGUgY2FzZSBvZiBjb25zdHJ1Y3RpbmcgYSBjb25maWRlbmNlIGludGVydmFsLgoKICAqIFRoZW4sIHdlIGBjYWxjdWxhdGVgIHRoZSBzYW1wbGUgc3RhdGlzdGljIG9mIGludGVyZXN0IGZvciBlYWNoIG9mIHRoZXNlIHJlc2FtcGxlcywgd2hpY2ggaXMgcHJvcG9ydGlvbi4KICAKICAqIFRvIGNvbXB1dGUgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWwsIHdlIHVzZSB0aGUgYGdldF9jaWAgZnVuY3Rpb24gYW5kIHVzZSAwLjk1IGFzIHRoZSBjb25maWRlbmNlIGxldmVsLiBIZXJlLCB3ZXIgYXJlIHVzaW5nIHRoZSBwZXJjZW50aWxlIG1ldGhvZC4KCkZlZWwgZnJlZSB0byB0ZXN0IG91dCB0aGUgcmVzdCBvZiB0aGUgYXJndW1lbnRzIGZvciB0aGVzZSBmdW5jdGlvbnMsIHNpbmNlIHRoZXNlIGNvbW1hbmRzIHdpbGwgYmUgdXNlZCB0b2dldGhlciB0byBjYWxjdWxhdGUgY29uZmlkZW5jZSBpbnRlcnZhbHMgYW5kIHNvbHZlIGluZmVyZW5jZSBwcm9ibGVtcyBmb3IgdGhlIHJlc3Qgb2YgdGhlIHNlbWVzdGVyLgoKVG8gcmVjYXA6IGV2ZW4gdGhvdWdoIHdlIGRvbuKAmXQga25vdyB3aGF0IHRoZSBmdWxsIHBvcHVsYXRpb24gbG9va3MgbGlrZSwgd2XigJlyZSA5NSUgY29uZmlkZW50IHRoYXQgdGhlIHRydWUgcHJvcG9ydGlvbiBvZiBVUyBhZHVsdHMgd2hvIHRoaW5rIGNsaW1hdGUgY2hhbmdlIGFmZmVjdHMgdGhlaXIgbG9jYWwgY29tbXVuaXR5IGlzIGJldHdlZW4gdGhlIHR3byBib3VuZHMgcmVwb3J0ZWQgYXMgcmVzdWx0IG9mIHRoaXMgcGlwZWxpbmUuCgpFYXJsaWVyIGluIHRoaXMgc2VjdGlvbiwgd2UgYXNzdW1lZCB0aGF0IDYyJSBpcyBhIHRydWUgcG9wdWxhdGlvbiBwcm9wb3J0aW9uLiBJbiBvdXIgOTVcJSBpbnRlcnZhbCwgdGhlIDYyXCUgaXMgd2l0aGluIHRoaXMgaW50ZXJ2YWwsIHdoaWNoIG1lYW5zIHRoYXQgd2UgY2FwdHVyZWQgdGhlIHRydWUgcG9wdWxhdGlvbiBwcm9wb3J0aW9uLiBBZ2FpbiwgcG9wdWxhdGlvbiBwYXJhbWV0ZXJzIGFyZSB1bmtub3duLCB0aGlzIGV4YW1wbGUgaXMgZm9yIGRlbW9uc3RyYXRpb24gcHVycG9zZXMuIEluIHJlYWxpdHksIFRoZXJlIGlzIHN0aWxsIGEgNVwlIGNoYW5jZSB0aGF0IHRoZSBpbnRlcnZhbCBpcyB3cm9uZy4KCjxicj4KCiMjICoqTGFiIEV4ZXJjaXNlcyoqCgo8YnI+CgpOb3RlOiBZb3UgbXVzdCBpbmNsdWRlIHlvdXIgY29kZSBhbmQgcmVzdWx0cyB0byBhbnN3ZXIgdGhlIGV4ZXJjaXNlIHByb2JsZW1zLgoKPGJyPgoKIyMjIEkuIENsaW1hdGUgQ2hhbmdlCgpGcm9tIHRoZSBDYXNlIFN0dWR5IC0gQ2xpbWF0ZSBDaGFuZ2UgKFByb3BvcnRpb24pIHNlY3Rpb24sIHVzZSBzaW1pbGFyIGNvZGVzIHRvIGFuc3dlciB0aGUgZm9sbG93aW5nIHF1ZXN0aW9ucy4gVGhlc2UgcHJvYmxlbXMgcmVxdXJlIGEgY29tYmluYXRpb24gb2Ygd2hhdCB3ZSBoYXZlIGxlYXJuZWQgaW4gbGFiIHNpbmNlIHRoZSBmaXJzdCB3ZWVrIChlLmcuIGZvciBsb29wcywgd2hpbGUgbG9vcHMsIGNvbmRpdGlvbmFsIHN0YXRlbWVudHMgZXRjKS4KCkZvciBjb252ZW5pZW5jZSwgYmVsb3cgaXMgdGhlIFIgY29kZSB1c2VkIGluIHRoaXMgc2VjdGlvbi4KCmBgYHtyfQojICJ0aGUgcG9wdWxhdGlvbiIgb3IgInRoZSBkYXRhIgp1c19hZHVsdHMgPC0gdGliYmxlKAogIGNsaW1hdGVfY2hhbmdlX2FmZmVjdHMgPSBjKHJlcCgiWWVzIiwgNjIwMDApLCByZXAoIk5vIiwgMzgwMDApKQopCmBgYAoKPGJyPgoKICAxLiBPYnRhaW4gYSByYW5kb20gc2FtcGxlIG9mIDYwIGZyb20gdGhlIGB1c19hZHVsdHNgIGRhdGEuIENhbGN1bGF0ZSB0aGUgc2FtcGxlIHByb3BvcnRpb24sIGFuZCB1c2UgdGhlc2UgdG8gY2FsY3VsYXRlIGFuZCBzdG9yZSB0aGUgbG93ZXIgYW5kIHVwcGVyIGJvdW5kcyBvZiB0aGUgOTVcJSBjb25maWRlbmNlIGludGVydmFsICh1c2UgMTAwMCB0cmlhbHMgb3IgcmVzYW1wbGVzKS4gUmVwZWF0IHRoZXNlIHN0ZXBzIDEwMCB0aW1lcy4KICAKICAyLiBGcm9tIHByb2JsZW0gMSwgeW91IHNob3VsZCBoYXZlIDEwMCA5NVwlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzLiBDb21wdXRlIHRoZSBudW1iZXIgb2YgaW50ZXJ2YWxzIHRoYXQgY29udGFpbiB0aGUgdHJ1ZSBwb3B1bGF0aW9uIHByb3BvcnRpb24uIFJlbWVtYmVyIHRoYXQgd2UgYXNzdW1lZCB0aGF0IHRoZSB0cnVlIHBvcHVsYXRpb24gcHJvcG9ydGlvbiBpcyAwLjYyICg2MlwlKS4KICAKICAzLiBBIDk1JSBjb25maWRlbmNlIGludGVydmFsIGdpdmVzIHVzIGEgcmVnaW9uIHdoZXJlLCBoYWQgd2UgcmVkb25lIHRoZSBzYW1lIGRhdGEsIHRoZW4gOTUlIG9mIHRoZSB0aW1lLCB0aGUgdHJ1ZSB2YWx1ZSAkcCQgd2lsbCBiZSBjb250YWluZWQgaW4gdGhlIGludGVydmFsLiBXaGF0IHByb3BvcnRpb24gb2YgeW91ciBjb25maWRlbmNlIGludGVydmFscyBpbmNsdWRlIHRoZSB0cnVlIHBvcHVsYXRpb24gcHJvcG9ydGlvbj8gSXMgdGhpcyBwcm9wb3J0aW9uIGV4YWN0bHkgZXF1YWwgb3IgY2xvc2UgdG8gdGhlIGNvbmZpZGVuY2UgbGV2ZWw/IEV4cGxhaW4geW91ciByZWFzb25pbmcuCiAgCiAgNC4gQ2hvb3NlIGEgZGlmZmVyZW50IGNvbmZpZGVuY2UgbGV2ZWwgdGhhbiA5NSUuIFdvdWxkIHlvdSBleHBlY3QgYSBjb25maWRlbmNlIGludGVydmFsIGF0IHRoaXMgbGV2ZWwgdG8gYmUgd2lkZXIgb3IgbmFycm93ZXIgdGhhbiB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbCB5b3UgY2FsY3VsYXRlZCBhdCB0aGUgOTUlIGNvbmZpZGVuY2UgbGV2ZWw/IEV4cGxhaW4geW91ciByZWFzb25pbmcuCgogIDUuIEZpbmQgYSBjb25maWRlbmNlIGludGVydmFsIGZvciB0aGUgcHJvcG9ydGlvbiBvZiBVUyBBZHVsdHMgd2hvIHRoaW5rIGNsaW1hdGUgY2hhbmdlIGlzIGFmZmVjdGluZyB0aGVpciBsb2NhbCBjb21tdW5pdHkgd2l0aCBhIGNvbmZpZGVuY2UgbGV2ZWwgb2YgeW91ciBjaG9vc2luZyAob3RoZXIgdGhhbiA5NSUpIGFuZCBpbnRlcnByZXQgaXQuCgo8YnI+Cg==