Learning Objectives


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

  1. Perform inferences in means using simulation and theoretical methods.


library(tidyverse)
library(openintro)
library(dplyr)
library(infer)
library(kableExtra)
library(janitor)


US Births

Every year, the US releases to the public a large data set containing information on births recorded in the country. This data set has been of interest to medical researchers who are studying the relation between habits and practices of expectant mothers and the birth of their children. We will work with a random sample of 1,000 cases from the data set released in 2014.

The births14 data can be found in the openintro R package.

births14 <- births14 %>% na.omit()
glimpse(births14)
## Rows: 794
## Columns: 13
## $ fage           <int> 34, 36, 37, 32, 32, 37, 29, 30, 29, 30, 34, 28, 32, 24,…
## $ mage           <dbl> 34, 31, 36, 31, 26, 36, 24, 32, 26, 34, 27, 22, 25, 20,…
## $ mature         <chr> "younger mom", "younger mom", "mature mom", "younger mo…
## $ weeks          <dbl> 37, 41, 37, 36, 39, 36, 40, 39, 39, 42, 40, 40, 34, 37,…
## $ premie         <chr> "full term", "full term", "full term", "premie", "full …
## $ visits         <dbl> 14, 12, 10, 12, 14, 10, 13, 15, 11, 14, 16, 20, 20, 10,…
## $ gained         <dbl> 28, 41, 28, 48, 45, 20, 65, 25, 22, 40, 30, 31, 25, 70,…
## $ weight         <dbl> 6.96, 8.86, 7.51, 6.75, 6.69, 6.13, 6.74, 8.94, 9.12, 8…
## $ lowbirthweight <chr> "not low", "not low", "not low", "not low", "not low", …
## $ sex            <chr> "male", "female", "female", "female", "female", "female…
## $ habit          <chr> "nonsmoker", "nonsmoker", "nonsmoker", "nonsmoker", "no…
## $ marital        <chr> "married", "married", "married", "married", "married", …
## $ whitemom       <chr> "white", "white", "not white", "white", "white", "white…

Summary Statistics for Smoker and NonSmoker Groups

births14_sample_stats <- births14 %>%
  group_by(habit) %>%
  summarise(
    n = n(),
    Mean = mean(weight),
    SD = sd(weight)
  )
births14_sample_stats %>%
  kbl(linesep = "", booktabs = TRUE, caption = "Summary statistics for the `births14` dataset.",
      col.names = c("Habit", "n", "Mean", "SD"),
      align = "lccc", digits = 2) %>%
  kable_styling(bootstrap_options = c("striped", "condensed"), 
                latex_options = c("striped", "hold_position"), full_width = FALSE) %>%
  column_spec(1:4, width = "7em")
Summary statistics for the births14 dataset.
Habit n Mean SD
nonsmoker 732 7.31 1.21
smoker 62 6.55 1.61

Hypothesis Statements for One-Sample Mean

  • Question - Is the data (smoking group) a convincing evidence to support the claim of the average weight to be less than \(7.5\) lbs?

  • \(H_0\): The average weight of the smoking group is \(7.5\) lbs. \[\mu = 7.5\]

  • \(H_A\): The average weight of the smoking group is not \(7.5\) lbs. \[\mu \ne 7.5\]

  • The null value is \(\mu_0 = 7.5\). The point-estimate is \(\bar{x} = 6.68\) and the sample standard deviation is \(s = 1.60\).

Hypothesis Statements for Two-Sample Means

  • Is there a difference in weight means between the smoking group and nonsmoking group?

  • \(H_0\): There is no difference in means between the smoking and nonsmoking groups. \[\mu_{smoking} = \mu_{nonsmoking}\]

  • \(H_A\): There is a significant difference in means between the smoking and nonsmoking groups. In particular the smoking group weights is less than the nonsmoking group weights. \[\mu_{smoking} < \mu_{nonsmoking}\]

  • The null value is \(\mu_0 = 0\). The point-estimate is \(\bar{x}_{nonsmoking} - \bar{x}_{smoking} = 0.59\) and the sample standard deviations are \(s_{smoking} = 1.60\) and \(s_{nonsmoking} = 1.23\).


One Sample t-test


births14_smoke <- births14 %>% filter(habit == "smoker")

Calculating the observed statistic,

T <- births14_smoke %>%
  specify(response = weight) %>%
  hypothesize(null = "point", mu = 7.5) %>%
  calculate(stat = "t")

T
## Response: weight (numeric)
## Null Hypothesis: point
## # A tibble: 1 × 1
##    stat
##   <dbl>
## 1 -4.63

Alternatively, using the observe() wrapper to calculate the observed statistic,

T <- births14_smoke %>%
  observe(response = weight, null = "point", mu = 7.5, stat = "t")

T
## Response: weight (numeric)
## Null Hypothesis: point
## # A tibble: 1 × 1
##    stat
##   <dbl>
## 1 -4.63

Then, generating the null distribution,

null_dist <- births14_smoke %>%
  specify(response = weight) %>%
  hypothesize(null = "point", mu = 7.5) %>%
  generate(reps = 3000, type = "bootstrap") %>%
  calculate(stat = "t")

Alternatively, finding the null distribution using theoretical methods using the assume() verb,

null_dist_theory <- births14_smoke %>%
  specify(response = weight)  %>%
  assume("t")

Visualizing the observed statistic alongside the null distribution,

visualize(null_dist, method = "both") +
  shade_p_value(obs_stat = T, direction = "two-sided")
## Warning: Check to make sure the conditions have been met for the theoretical
## method. {infer} currently does not check these for you.

Compute p-value.

null_dist %>%
  get_p_value(obs_stat = T, direction = "two-sided")
## Warning: Please be cautious in reporting a p-value of 0. This result is an
## approximation based on the number of `reps` chosen in the `generate()` step. See
## `?get_p_value()` for more information.
## # A tibble: 1 × 1
##   p_value
##     <dbl>
## 1       0

Alternatively, using the t_test wrapper:

births14_smoke %>%
  t_test(response = weight, mu = 7.5)
## # A tibble: 1 × 7
##   statistic  t_df   p_value alternative estimate lower_ci upper_ci
##       <dbl> <dbl>     <dbl> <chr>          <dbl>    <dbl>    <dbl>
## 1     -4.63    61 0.0000195 two.sided       6.55     6.15     6.96

infer does not support testing on one numerical variable via the z distribution.


One Sample t-interval


Finding the observed statistic,

x_bar <- births14_smoke %>% 
  specify(response = weight) %>%
  calculate(stat = "mean")

Alternatively, using the observe() wrapper to calculate the observed statistic,

x_bar <- births14_smoke %>% 
  observe(response = weight, stat = "mean")

Then, generating a bootstrap distribution,

boot_dist <- births14_smoke %>%
   specify(response = weight) %>%
   generate(reps = 1000, type = "bootstrap") %>%
   calculate(stat = "mean")

Use the bootstrap distribution to find a confidence interval,

percentile_ci <- get_ci(boot_dist)

Visualizing the observed statistic alongside the distribution,

visualize(boot_dist) +
  shade_confidence_interval(endpoints = percentile_ci)

Alternatively, use the bootstrap distribution to find a confidence interval using the standard error,

standard_error_ci <- get_ci(boot_dist, type = "se", point_estimate = x_bar)

visualize(boot_dist) +
  shade_confidence_interval(endpoints = standard_error_ci)

Instead of a simulation-based bootstrap distribution, we can also define a theory-based sampling distribution,

sampling_dist <- births14_smoke %>%
   specify(response = weight) %>%
   assume(distribution = "t")

Visualization and calculation of confidence intervals interfaces in the same way as with the simulation-based distribution,

theor_ci <- get_ci(sampling_dist, point_estimate = x_bar)

theor_ci
## # A tibble: 1 × 2
##   lower_ci upper_ci
##      <dbl>    <dbl>
## 1     6.15     6.96
visualize(sampling_dist) +
  shade_confidence_interval(endpoints = theor_ci)

Note that the t distribution is recentered and rescaled to lie on the scale of the observed data. infer does not support confidence intervals on means via the z distribution.


Two Sample t-test


Finding the standardized observed statistic,

t_hat <- births14 %>% 
  specify(weight ~ habit) %>% 
  hypothesize(null = "independence") %>%
  calculate(stat = "t", order = c("smoker", "nonsmoker"))

t_hat
## Response: weight (numeric)
## Explanatory: habit (factor)
## Null Hypothesis: independence
## # A tibble: 1 × 1
##    stat
##   <dbl>
## 1 -3.60

Alternatively, using the observe() wrapper to calculate the observed statistic

t_hat <- births14 %>% 
  observe(weight ~ habit,
          stat = "t", order = c("smoker", "nonsmoker"))

Then, generating the null distribution,

null_dist <- births14 %>%
  specify(weight ~ habit) %>%
  hypothesize(null = "independence") %>%
  generate(reps = 1000, type = "permute") %>%
  calculate(stat = "t", order = c("smoker", "nonsmoker"))

Alternatively, finding the null distribution using theoretical methods using the assume() verb,

null_dist_theory <- births14 %>%
  specify(weight ~ habit) %>%
  assume("t")

Visualizing the observed statistic alongside the null distribution,

visualize(null_dist) +
  shade_p_value(obs_stat = t_hat, direction = "less")

Alternatively, visualizing the observed statistic using the theory-based null distribution,

visualize(null_dist_theory) +
  shade_p_value(obs_stat = t_hat, direction = "less")

Alternatively, visualizing the observed statistic using both of the null distributions,

visualize(null_dist, method = "both") +
  shade_p_value(obs_stat = t_hat, direction = "less")
## Warning: Check to make sure the conditions have been met for the theoretical
## method. {infer} currently does not check these for you.

Note that the above code makes use of the randomization-based null distribution.

Calculating the p-value from the null distribution and observed statistic,

null_dist %>%
  get_p_value(obs_stat = t_hat, direction = "less")
## # A tibble: 1 × 1
##   p_value
##     <dbl>
## 1   0.001

Note the similarities in this plot and the previous one.


Two Sample t-interval


Finding the standardized point estimate,

t_hat <- births14 %>%
  specify(weight ~ habit) %>%
  calculate(stat = "t", order = c("smoker", "nonsmoker"))

Alternatively, using the observe() wrapper to calculate the observed statistic,

t_hat <- births14 %>%
  observe(weight ~ habit,
          stat = "t", order = c("smoker", "nonsmoker"))

Then, generating a bootstrap distribution,

boot_dist <- births14 %>%
   specify(weight ~ habit) %>%
   generate(reps = 1000, type = "bootstrap") %>%
   calculate(stat = "t", order = c("smoker", "nonsmoker"))

Use the bootstrap distribution to find a confidence interval,

percentile_ci <- get_ci(boot_dist)

Visualizing the observed statistic alongside the distribution,

visualize(boot_dist) +
  shade_confidence_interval(endpoints = percentile_ci)

Alternatively, use the bootstrap distribution to find a confidence interval using the standard error,

standard_error_ci <- boot_dist %>%
  get_ci(type = "se", point_estimate = t_hat)

visualize(boot_dist) +
  shade_confidence_interval(endpoints = standard_error_ci)

See the above subsection (diff in means) for a theory-based approach. infer does not support confidence intervals on means via the z distribution.


Paired Means

The ucla_textbooks_f18 data can be found in the openintro R package.

glimpse(ucla_textbooks_f18)
## Rows: 201
## Columns: 20
## $ year             <dbl> 2018, 2018, 2018, 2018, 2018, 2018, 2018, 2018, 2018,…
## $ term             <fct> Fall, Fall, Fall, Fall, Fall, Fall, Fall, Fall, Fall,…
## $ subject          <fct> "American Indian Studies", "Anthropology", "Art", "Ar…
## $ subject_abbr     <fct> AM IND, ANTHRO, NA, ART&ARC, NA, ASTR, BMD RES, CHEM,…
## $ course           <fct> "Introduction to American Indian Studies", "Archaeolo…
## $ course_num       <fct> M10, 2, 11D, 10, M60W, 4, 5HA, 14A, 14B, M5A, 10, 1E,…
## $ course_numeric   <int> 10, 2, 11, 10, 60, 4, 5, 14, 14, 5, 10, 1, 2, 9, 10, …
## $ seminar          <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALS…
## $ ind_study        <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALS…
## $ apprenticeship   <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALS…
## $ internship       <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALS…
## $ honors_contracts <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALS…
## $ laboratory       <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALS…
## $ special_topic    <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALS…
## $ textbook_isbn    <chr> "9781138477858", "9780307741806", NA, "9780979757549"…
## $ bookstore_new    <dbl> 47.97, 14.26, NA, 13.50, 49.26, 119.97, NA, 188.10, 2…
## $ bookstore_used   <dbl> 44.97, 10.96, NA, 11.00, 43.26, 67.00, NA, 149.00, 16…
## $ amazon_new       <dbl> 47.45, 13.55, NA, 12.53, 54.95, 124.80, NA, NA, NA, N…
## $ amazon_used      <dbl> 51.20, 7.10, NA, NA, 24.83, 47.75, NA, NA, 90.00, NA,…
## $ notes            <fct> "", "", NA, "", NA, NA, NA, "", "New version only fro…

Select the prices for new books from the bookstore and amazon.

new_books <- ucla_textbooks_f18 %>% select(bookstore_new,amazon_new) %>% na.omit()
new_books
## # A tibble: 68 × 2
##    bookstore_new amazon_new
##            <dbl>      <dbl>
##  1         48.0       47.4 
##  2         14.3       13.6 
##  3         13.5       12.5 
##  4         49.3       55.0 
##  5        120.       125.  
##  6         17.0       11.8 
##  7         12.0       10.9 
##  8         26.8       38.9 
##  9          9.96       8.99
## 10         40.0       35   
## # … with 58 more rows

Next, we take the difference of the pairs.

new_books_diff <- new_books %>% mutate(diff = bookstore_new - amazon_new)
new_books_diff
## # A tibble: 68 × 3
##    bookstore_new amazon_new    diff
##            <dbl>      <dbl>   <dbl>
##  1         48.0       47.4    0.520
##  2         14.3       13.6    0.710
##  3         13.5       12.5    0.97 
##  4         49.3       55.0   -5.69 
##  5        120.       125.    -4.83 
##  6         17.0       11.8    5.18 
##  7         12.0       10.9    1.09 
##  8         26.8       38.9  -12.2  
##  9          9.96       8.99   0.97 
## 10         40.0       35      4.97 
## # … with 58 more rows

Now, I can use my differences to perform hypothesis test, which is equivalent to a one-sample t-test.

T <- new_books_diff %>%
  specify(response = diff) %>%
  hypothesize(null = "point", mu = 0) %>%
  calculate(stat = "t")

T
## Response: diff (numeric)
## Null Hypothesis: point
## # A tibble: 1 × 1
##    stat
##   <dbl>
## 1  2.20
null_dist_theory <- new_books_diff %>%
  specify(response = diff)  %>%
  assume("t")
visualize(null_dist_theory) +
  shade_p_value(obs_stat = T, direction = "two-sided")

null_dist_theory %>%
  get_p_value(obs_stat = T, direction = "two-sided")
## # A tibble: 1 × 1
##   p_value
##     <dbl>
## 1  0.0312

Next, we can do confidence intervals, which is equivalent to a two-sample t-interval.

x_bar_diff <- new_books_diff %>% 
  specify(response = diff) %>%
  calculate(stat = "mean")

x_bar_diff
## Response: diff (numeric)
## # A tibble: 1 × 1
##    stat
##   <dbl>
## 1  3.58

Simulation Method

boot_dist <- new_books_diff %>%
   specify(response = diff) %>%
   generate(reps = 1000, type = "bootstrap") %>%
   calculate(stat = "mean")
standard_error_ci <- get_ci(boot_dist, type = "se", point_estimate = x_bar_diff)

standard_error_ci
## # A tibble: 1 × 2
##   lower_ci upper_ci
##      <dbl>    <dbl>
## 1    0.489     6.68
visualize(boot_dist) +
  shade_confidence_interval(endpoints = standard_error_ci)

Theoretical Method

sampling_dist <- new_books_diff %>%
   specify(response = diff) %>%
   assume(distribution = "t")
theor_ci <- get_ci(sampling_dist, point_estimate = x_bar_diff)

theor_ci
## # A tibble: 1 × 2
##   lower_ci upper_ci
##      <dbl>    <dbl>
## 1    0.334     6.83
visualize(sampling_dist) +
  shade_confidence_interval(endpoints = theor_ci)

Comparing Multiple Means

Go through the tutorial in Chapter 23.4 in the Textbook.

Tutorial 5 - Lesson 8

Mini Activities


  1. Use the births14 data set to perform a hypothesis test and confidence interval using the weight and whitemom variables.

    1. Print out the summarized statistics of the variables weight and whitemom. Note that the weight variable is a continuous numerical variable while the whitemom variable is a nominal categorical variable with two levels.

    2. Perform a hypothesis test and confidence interval for the not white level in the whitemom variable. Suppose that the average birth weight is \(7.5\) lb. Does the data show a convincing evidence that non white individuals have less average birth weights?

    3. Perform inference (hypothesis testing and confidence interval) for the difference in birth weight means for the two levels in the whitemom variable. Is there a significant difference and by how much?

  2. Use the ucla_textbooks_f18 data set to perform a hypothesis test and confidence interval for comparing the new and used books.

    1. Compute the paired difference between the UCLA bookstore and Amazon used books. Perform a hypothesis test and compute the 95% confidence interval. What is your null and alternative hypothesis? What are your conclusions?

    2. Suppose that you are comparing new and used books regardless of store. Compute the paired difference between new and used books (take the average price for each book between stores and then compute the difference). Compute the 95% confidence interval.


LS0tCnRpdGxlOiAiOCAtIEluZmVyZW5jZSBmb3IgTWVhbnMiCmF1dGhvcjogIkFsZXggSm9obiBRdWlqYW5vIgpkYXRlOiAiMTEvMjMvMjAyMSIKb3V0cHV0OiBvcGVuaW50cm86OmxhYl9yZXBvcnQKLS0tCgojIyAqKkxlYXJuaW5nIE9iamVjdGl2ZXMqKgoKPGJyPgoKVXBvbiBjb21wbGV0aW5nIHRvZGF5J3MgbGFiIGFjdGl2aXR5LCBzdHVkZW50cyBzaG91bGQgYmUgYWJsZSB0byBkbyB0aGUgZm9sbG93aW5nIHVzaW5nIFIgYW5kIFJTdHVkaW86CiAgCiAgMS4gUGVyZm9ybSBpbmZlcmVuY2VzIGluIG1lYW5zIHVzaW5nIHNpbXVsYXRpb24gYW5kIHRoZW9yZXRpY2FsIG1ldGhvZHMuCiAgCjxicj4KCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkob3BlbmludHJvKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGluZmVyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCmxpYnJhcnkoamFuaXRvcikKYGBgCgo8YnI+CgojIyAqKlVTIEJpcnRocyoqCgpFdmVyeSB5ZWFyLCB0aGUgVVMgcmVsZWFzZXMgdG8gdGhlIHB1YmxpYyBhIGxhcmdlIGRhdGEgc2V0IGNvbnRhaW5pbmcgaW5mb3JtYXRpb24gb24gYmlydGhzIHJlY29yZGVkIGluIHRoZSBjb3VudHJ5LiBUaGlzIGRhdGEgc2V0IGhhcyBiZWVuIG9mIGludGVyZXN0IHRvIG1lZGljYWwgcmVzZWFyY2hlcnMgd2hvIGFyZSBzdHVkeWluZyB0aGUgcmVsYXRpb24gYmV0d2VlbiBoYWJpdHMgYW5kIHByYWN0aWNlcyBvZiBleHBlY3RhbnQgbW90aGVycyBhbmQgdGhlIGJpcnRoIG9mIHRoZWlyIGNoaWxkcmVuLiBXZSB3aWxsIHdvcmsgd2l0aCBhIHJhbmRvbSBzYW1wbGUgb2YgMSwwMDAgY2FzZXMgZnJvbSB0aGUgZGF0YSBzZXQgcmVsZWFzZWQgaW4gMjAxNC4KClRoZSBbYGJpcnRoczE0YF0oaHR0cDovL29wZW5pbnRyb3N0YXQuZ2l0aHViLmlvL29wZW5pbnRyby9yZWZlcmVuY2UvYmlydGhzMTQuaHRtbCkgZGF0YSBjYW4gYmUgZm91bmQgaW4gdGhlIFsqKm9wZW5pbnRybyoqXShodHRwOi8vb3BlbmludHJvc3RhdC5naXRodWIuaW8vb3BlbmludHJvKSBSIHBhY2thZ2UuCgpgYGB7cn0KYmlydGhzMTQgPC0gYmlydGhzMTQgJT4lIG5hLm9taXQoKQpnbGltcHNlKGJpcnRoczE0KQpgYGAKCiMjIyBTdW1tYXJ5IFN0YXRpc3RpY3MgZm9yIFNtb2tlciBhbmQgTm9uU21va2VyIEdyb3VwcwoKYGBge3J9CmJpcnRoczE0X3NhbXBsZV9zdGF0cyA8LSBiaXJ0aHMxNCAlPiUKICBncm91cF9ieShoYWJpdCkgJT4lCiAgc3VtbWFyaXNlKAogICAgbiA9IG4oKSwKICAgIE1lYW4gPSBtZWFuKHdlaWdodCksCiAgICBTRCA9IHNkKHdlaWdodCkKICApCmBgYAoKYGBge3J9CmJpcnRoczE0X3NhbXBsZV9zdGF0cyAlPiUKICBrYmwobGluZXNlcCA9ICIiLCBib29rdGFicyA9IFRSVUUsIGNhcHRpb24gPSAiU3VtbWFyeSBzdGF0aXN0aWNzIGZvciB0aGUgYGJpcnRoczE0YCBkYXRhc2V0LiIsCiAgICAgIGNvbC5uYW1lcyA9IGMoIkhhYml0IiwgIm4iLCAiTWVhbiIsICJTRCIpLAogICAgICBhbGlnbiA9ICJsY2NjIiwgZGlnaXRzID0gMikgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiY29uZGVuc2VkIiksIAogICAgICAgICAgICAgICAgbGF0ZXhfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG9sZF9wb3NpdGlvbiIpLCBmdWxsX3dpZHRoID0gRkFMU0UpICU+JQogIGNvbHVtbl9zcGVjKDE6NCwgd2lkdGggPSAiN2VtIikKYGBgCgojIyMgSHlwb3RoZXNpcyBTdGF0ZW1lbnRzIGZvciBPbmUtU2FtcGxlIE1lYW4KCiAgKiBRdWVzdGlvbiAtIElzIHRoZSBkYXRhIChzbW9raW5nIGdyb3VwKSBhIGNvbnZpbmNpbmcgZXZpZGVuY2UgdG8gc3VwcG9ydCB0aGUgY2xhaW0gb2YgdGhlIGF2ZXJhZ2Ugd2VpZ2h0IHRvIGJlIGxlc3MgdGhhbiAkNy41JCBsYnM/CgogICogJEhfMCQ6IFRoZSBhdmVyYWdlIHdlaWdodCBvZiB0aGUgc21va2luZyBncm91cCBpcyAkNy41JCBsYnMuCiAgICAkJFxtdSA9IDcuNSQkCiAgICAKICAqICRIX0EkOiBUaGUgYXZlcmFnZSB3ZWlnaHQgb2YgdGhlIHNtb2tpbmcgZ3JvdXAgaXMgbm90ICQ3LjUkIGxicy4KICAgICQkXG11IFxuZSA3LjUkJAogICAgCiAgKiBUaGUgbnVsbCB2YWx1ZSBpcyAkXG11XzAgPSA3LjUkLiBUaGUgcG9pbnQtZXN0aW1hdGUgaXMgJFxiYXJ7eH0gPSA2LjY4JCBhbmQgdGhlIHNhbXBsZSBzdGFuZGFyZCBkZXZpYXRpb24gaXMgJHMgPSAxLjYwJC4KICAKIyMjIEh5cG90aGVzaXMgU3RhdGVtZW50cyBmb3IgVHdvLVNhbXBsZSBNZWFucwoKICAqIElzIHRoZXJlIGEgZGlmZmVyZW5jZSBpbiB3ZWlnaHQgbWVhbnMgYmV0d2VlbiB0aGUgc21va2luZyBncm91cCBhbmQgbm9uc21va2luZyBncm91cD8KCiAgKiAkSF8wJDogVGhlcmUgaXMgbm8gZGlmZmVyZW5jZSBpbiBtZWFucyBiZXR3ZWVuIHRoZSBzbW9raW5nIGFuZCBub25zbW9raW5nIGdyb3Vwcy4KICAgICQkXG11X3tzbW9raW5nfSA9IFxtdV97bm9uc21va2luZ30kJAogICAgCiAgKiAkSF9BJDogVGhlcmUgaXMgYSBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGluIG1lYW5zIGJldHdlZW4gdGhlIHNtb2tpbmcgYW5kIG5vbnNtb2tpbmcgZ3JvdXBzLiBJbiBwYXJ0aWN1bGFyIHRoZSBzbW9raW5nIGdyb3VwIHdlaWdodHMgaXMgbGVzcyB0aGFuIHRoZSBub25zbW9raW5nIGdyb3VwIHdlaWdodHMuCiAgICAkJFxtdV97c21va2luZ30gPCBcbXVfe25vbnNtb2tpbmd9JCQKICAgIAogICogVGhlIG51bGwgdmFsdWUgaXMgJFxtdV8wID0gMCQuIFRoZSBwb2ludC1lc3RpbWF0ZSBpcyAkXGJhcnt4fV97bm9uc21va2luZ30gLSBcYmFye3h9X3tzbW9raW5nfSA9IDAuNTkkIGFuZCB0aGUgc2FtcGxlIHN0YW5kYXJkIGRldmlhdGlvbnMgYXJlICRzX3tzbW9raW5nfSA9IDEuNjAkIGFuZCAkc197bm9uc21va2luZ30gPSAxLjIzJC4KCjxicj4KCiMjICoqT25lIFNhbXBsZSB0LXRlc3QqKgoKPGJyPgoKYGBge3J9CmJpcnRoczE0X3Ntb2tlIDwtIGJpcnRoczE0ICU+JSBmaWx0ZXIoaGFiaXQgPT0gInNtb2tlciIpCmBgYAoKQ2FsY3VsYXRpbmcgdGhlIG9ic2VydmVkIHN0YXRpc3RpYywKCmBgYHtyfQpUIDwtIGJpcnRoczE0X3Ntb2tlICU+JQogIHNwZWNpZnkocmVzcG9uc2UgPSB3ZWlnaHQpICU+JQogIGh5cG90aGVzaXplKG51bGwgPSAicG9pbnQiLCBtdSA9IDcuNSkgJT4lCiAgY2FsY3VsYXRlKHN0YXQgPSAidCIpCgpUCmBgYAoKQWx0ZXJuYXRpdmVseSwgdXNpbmcgdGhlIGBvYnNlcnZlKClgIHdyYXBwZXIgdG8gY2FsY3VsYXRlIHRoZSBvYnNlcnZlZCBzdGF0aXN0aWMsCgpgYGB7cn0KVCA8LSBiaXJ0aHMxNF9zbW9rZSAlPiUKICBvYnNlcnZlKHJlc3BvbnNlID0gd2VpZ2h0LCBudWxsID0gInBvaW50IiwgbXUgPSA3LjUsIHN0YXQgPSAidCIpCgpUCmBgYCAgCiAgClRoZW4sIGdlbmVyYXRpbmcgdGhlIG51bGwgZGlzdHJpYnV0aW9uLAoKYGBge3J9Cm51bGxfZGlzdCA8LSBiaXJ0aHMxNF9zbW9rZSAlPiUKICBzcGVjaWZ5KHJlc3BvbnNlID0gd2VpZ2h0KSAlPiUKICBoeXBvdGhlc2l6ZShudWxsID0gInBvaW50IiwgbXUgPSA3LjUpICU+JQogIGdlbmVyYXRlKHJlcHMgPSAzMDAwLCB0eXBlID0gImJvb3RzdHJhcCIpICU+JQogIGNhbGN1bGF0ZShzdGF0ID0gInQiKQpgYGAKCkFsdGVybmF0aXZlbHksIGZpbmRpbmcgdGhlIG51bGwgZGlzdHJpYnV0aW9uIHVzaW5nIHRoZW9yZXRpY2FsIG1ldGhvZHMgdXNpbmcgdGhlIGBhc3N1bWUoKWAgdmVyYiwKCmBgYHtyfQpudWxsX2Rpc3RfdGhlb3J5IDwtIGJpcnRoczE0X3Ntb2tlICU+JQogIHNwZWNpZnkocmVzcG9uc2UgPSB3ZWlnaHQpICAlPiUKICBhc3N1bWUoInQiKQpgYGAKClZpc3VhbGl6aW5nIHRoZSBvYnNlcnZlZCBzdGF0aXN0aWMgYWxvbmdzaWRlIHRoZSBudWxsIGRpc3RyaWJ1dGlvbiwKCmBgYHtyfQp2aXN1YWxpemUobnVsbF9kaXN0LCBtZXRob2QgPSAiYm90aCIpICsKICBzaGFkZV9wX3ZhbHVlKG9ic19zdGF0ID0gVCwgZGlyZWN0aW9uID0gInR3by1zaWRlZCIpCmBgYAoKQ29tcHV0ZSBwLXZhbHVlLgoKYGBge3J9Cm51bGxfZGlzdCAlPiUKICBnZXRfcF92YWx1ZShvYnNfc3RhdCA9IFQsIGRpcmVjdGlvbiA9ICJ0d28tc2lkZWQiKQpgYGAKCkFsdGVybmF0aXZlbHksIHVzaW5nIHRoZSB0X3Rlc3Qgd3JhcHBlcjoKCmBgYHtyfQpiaXJ0aHMxNF9zbW9rZSAlPiUKICB0X3Rlc3QocmVzcG9uc2UgPSB3ZWlnaHQsIG11ID0gNy41KQpgYGAKCmBpbmZlcmAgZG9lcyBub3Qgc3VwcG9ydCB0ZXN0aW5nIG9uIG9uZSBudW1lcmljYWwgdmFyaWFibGUgdmlhIHRoZSB6IGRpc3RyaWJ1dGlvbi4KCjxicj4KCiMjICoqT25lIFNhbXBsZSB0LWludGVydmFsKioKCjxicj4KCkZpbmRpbmcgdGhlIG9ic2VydmVkIHN0YXRpc3RpYywKCmBgYHtyfQp4X2JhciA8LSBiaXJ0aHMxNF9zbW9rZSAlPiUgCiAgc3BlY2lmeShyZXNwb25zZSA9IHdlaWdodCkgJT4lCiAgY2FsY3VsYXRlKHN0YXQgPSAibWVhbiIpCmBgYAoKQWx0ZXJuYXRpdmVseSwgdXNpbmcgdGhlIG9ic2VydmUoKSB3cmFwcGVyIHRvIGNhbGN1bGF0ZSB0aGUgb2JzZXJ2ZWQgc3RhdGlzdGljLAoKYGBge3J9CnhfYmFyIDwtIGJpcnRoczE0X3Ntb2tlICU+JSAKICBvYnNlcnZlKHJlc3BvbnNlID0gd2VpZ2h0LCBzdGF0ID0gIm1lYW4iKQpgYGAKClRoZW4sIGdlbmVyYXRpbmcgYSBib290c3RyYXAgZGlzdHJpYnV0aW9uLAoKYGBge3J9CmJvb3RfZGlzdCA8LSBiaXJ0aHMxNF9zbW9rZSAlPiUKICAgc3BlY2lmeShyZXNwb25zZSA9IHdlaWdodCkgJT4lCiAgIGdlbmVyYXRlKHJlcHMgPSAxMDAwLCB0eXBlID0gImJvb3RzdHJhcCIpICU+JQogICBjYWxjdWxhdGUoc3RhdCA9ICJtZWFuIikKYGBgCgpVc2UgdGhlIGJvb3RzdHJhcCBkaXN0cmlidXRpb24gdG8gZmluZCBhIGNvbmZpZGVuY2UgaW50ZXJ2YWwsCgpgYGB7cn0KcGVyY2VudGlsZV9jaSA8LSBnZXRfY2koYm9vdF9kaXN0KQpgYGAKClZpc3VhbGl6aW5nIHRoZSBvYnNlcnZlZCBzdGF0aXN0aWMgYWxvbmdzaWRlIHRoZSBkaXN0cmlidXRpb24sCgpgYGB7cn0KdmlzdWFsaXplKGJvb3RfZGlzdCkgKwogIHNoYWRlX2NvbmZpZGVuY2VfaW50ZXJ2YWwoZW5kcG9pbnRzID0gcGVyY2VudGlsZV9jaSkKYGBgCgpBbHRlcm5hdGl2ZWx5LCB1c2UgdGhlIGJvb3RzdHJhcCBkaXN0cmlidXRpb24gdG8gZmluZCBhIGNvbmZpZGVuY2UgaW50ZXJ2YWwgdXNpbmcgdGhlIHN0YW5kYXJkIGVycm9yLAoKYGBge3J9CnN0YW5kYXJkX2Vycm9yX2NpIDwtIGdldF9jaShib290X2Rpc3QsIHR5cGUgPSAic2UiLCBwb2ludF9lc3RpbWF0ZSA9IHhfYmFyKQoKdmlzdWFsaXplKGJvb3RfZGlzdCkgKwogIHNoYWRlX2NvbmZpZGVuY2VfaW50ZXJ2YWwoZW5kcG9pbnRzID0gc3RhbmRhcmRfZXJyb3JfY2kpCmBgYAoKSW5zdGVhZCBvZiBhIHNpbXVsYXRpb24tYmFzZWQgYm9vdHN0cmFwIGRpc3RyaWJ1dGlvbiwgd2UgY2FuIGFsc28gZGVmaW5lIGEgdGhlb3J5LWJhc2VkIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbiwKCmBgYHtyfQpzYW1wbGluZ19kaXN0IDwtIGJpcnRoczE0X3Ntb2tlICU+JQogICBzcGVjaWZ5KHJlc3BvbnNlID0gd2VpZ2h0KSAlPiUKICAgYXNzdW1lKGRpc3RyaWJ1dGlvbiA9ICJ0IikKYGBgCgpWaXN1YWxpemF0aW9uIGFuZCBjYWxjdWxhdGlvbiBvZiBjb25maWRlbmNlIGludGVydmFscyBpbnRlcmZhY2VzIGluIHRoZSBzYW1lIHdheSBhcyB3aXRoIHRoZSBzaW11bGF0aW9uLWJhc2VkIGRpc3RyaWJ1dGlvbiwKCmBgYHtyfQp0aGVvcl9jaSA8LSBnZXRfY2koc2FtcGxpbmdfZGlzdCwgcG9pbnRfZXN0aW1hdGUgPSB4X2JhcikKCnRoZW9yX2NpCmBgYAoKYGBge3J9CnZpc3VhbGl6ZShzYW1wbGluZ19kaXN0KSArCiAgc2hhZGVfY29uZmlkZW5jZV9pbnRlcnZhbChlbmRwb2ludHMgPSB0aGVvcl9jaSkKYGBgCgpOb3RlIHRoYXQgdGhlIHQgZGlzdHJpYnV0aW9uIGlzIHJlY2VudGVyZWQgYW5kIHJlc2NhbGVkIHRvIGxpZSBvbiB0aGUgc2NhbGUgb2YgdGhlIG9ic2VydmVkIGRhdGEuIGluZmVyIGRvZXMgbm90IHN1cHBvcnQgY29uZmlkZW5jZSBpbnRlcnZhbHMgb24gbWVhbnMgdmlhIHRoZSB6IGRpc3RyaWJ1dGlvbi4KCjxicj4KCiMjICoqVHdvIFNhbXBsZSB0LXRlc3QqKgoKPGJyPgoKRmluZGluZyB0aGUgc3RhbmRhcmRpemVkIG9ic2VydmVkIHN0YXRpc3RpYywKCmBgYHtyfQp0X2hhdCA8LSBiaXJ0aHMxNCAlPiUgCiAgc3BlY2lmeSh3ZWlnaHQgfiBoYWJpdCkgJT4lIAogIGh5cG90aGVzaXplKG51bGwgPSAiaW5kZXBlbmRlbmNlIikgJT4lCiAgY2FsY3VsYXRlKHN0YXQgPSAidCIsIG9yZGVyID0gYygic21va2VyIiwgIm5vbnNtb2tlciIpKQoKdF9oYXQKYGBgCgpBbHRlcm5hdGl2ZWx5LCB1c2luZyB0aGUgYG9ic2VydmUoKWAgd3JhcHBlciB0byBjYWxjdWxhdGUgdGhlIG9ic2VydmVkIHN0YXRpc3RpYwoKYGBge3J9CnRfaGF0IDwtIGJpcnRoczE0ICU+JSAKICBvYnNlcnZlKHdlaWdodCB+IGhhYml0LAogICAgICAgICAgc3RhdCA9ICJ0Iiwgb3JkZXIgPSBjKCJzbW9rZXIiLCAibm9uc21va2VyIikpCmBgYAoKVGhlbiwgZ2VuZXJhdGluZyB0aGUgbnVsbCBkaXN0cmlidXRpb24sCgpgYGB7cn0KbnVsbF9kaXN0IDwtIGJpcnRoczE0ICU+JQogIHNwZWNpZnkod2VpZ2h0IH4gaGFiaXQpICU+JQogIGh5cG90aGVzaXplKG51bGwgPSAiaW5kZXBlbmRlbmNlIikgJT4lCiAgZ2VuZXJhdGUocmVwcyA9IDEwMDAsIHR5cGUgPSAicGVybXV0ZSIpICU+JQogIGNhbGN1bGF0ZShzdGF0ID0gInQiLCBvcmRlciA9IGMoInNtb2tlciIsICJub25zbW9rZXIiKSkKYGBgCgpBbHRlcm5hdGl2ZWx5LCBmaW5kaW5nIHRoZSBudWxsIGRpc3RyaWJ1dGlvbiB1c2luZyB0aGVvcmV0aWNhbCBtZXRob2RzIHVzaW5nIHRoZSBgYXNzdW1lKClgIHZlcmIsCgpgYGB7cn0KbnVsbF9kaXN0X3RoZW9yeSA8LSBiaXJ0aHMxNCAlPiUKICBzcGVjaWZ5KHdlaWdodCB+IGhhYml0KSAlPiUKICBhc3N1bWUoInQiKQpgYGAKClZpc3VhbGl6aW5nIHRoZSBvYnNlcnZlZCBzdGF0aXN0aWMgYWxvbmdzaWRlIHRoZSBudWxsIGRpc3RyaWJ1dGlvbiwKCmBgYHtyfQp2aXN1YWxpemUobnVsbF9kaXN0KSArCiAgc2hhZGVfcF92YWx1ZShvYnNfc3RhdCA9IHRfaGF0LCBkaXJlY3Rpb24gPSAibGVzcyIpCmBgYAoKQWx0ZXJuYXRpdmVseSwgdmlzdWFsaXppbmcgdGhlIG9ic2VydmVkIHN0YXRpc3RpYyB1c2luZyB0aGUgdGhlb3J5LWJhc2VkIG51bGwgZGlzdHJpYnV0aW9uLAoKYGBge3J9CnZpc3VhbGl6ZShudWxsX2Rpc3RfdGhlb3J5KSArCiAgc2hhZGVfcF92YWx1ZShvYnNfc3RhdCA9IHRfaGF0LCBkaXJlY3Rpb24gPSAibGVzcyIpCmBgYAoKQWx0ZXJuYXRpdmVseSwgdmlzdWFsaXppbmcgdGhlIG9ic2VydmVkIHN0YXRpc3RpYyB1c2luZyBib3RoIG9mIHRoZSBudWxsIGRpc3RyaWJ1dGlvbnMsCgpgYGB7cn0KdmlzdWFsaXplKG51bGxfZGlzdCwgbWV0aG9kID0gImJvdGgiKSArCiAgc2hhZGVfcF92YWx1ZShvYnNfc3RhdCA9IHRfaGF0LCBkaXJlY3Rpb24gPSAibGVzcyIpCmBgYAoKTm90ZSB0aGF0IHRoZSBhYm92ZSBjb2RlIG1ha2VzIHVzZSBvZiB0aGUgcmFuZG9taXphdGlvbi1iYXNlZCBudWxsIGRpc3RyaWJ1dGlvbi4KCkNhbGN1bGF0aW5nIHRoZSBwLXZhbHVlIGZyb20gdGhlIG51bGwgZGlzdHJpYnV0aW9uIGFuZCBvYnNlcnZlZCBzdGF0aXN0aWMsCgpgYGB7cn0KbnVsbF9kaXN0ICU+JQogIGdldF9wX3ZhbHVlKG9ic19zdGF0ID0gdF9oYXQsIGRpcmVjdGlvbiA9ICJsZXNzIikKYGBgCgpOb3RlIHRoZSBzaW1pbGFyaXRpZXMgaW4gdGhpcyBwbG90IGFuZCB0aGUgcHJldmlvdXMgb25lLgoKPGJyPgoKIyMgKipUd28gU2FtcGxlIHQtaW50ZXJ2YWwqKgoKPGJyPgoKRmluZGluZyB0aGUgc3RhbmRhcmRpemVkIHBvaW50IGVzdGltYXRlLAoKYGBge3J9CnRfaGF0IDwtIGJpcnRoczE0ICU+JQogIHNwZWNpZnkod2VpZ2h0IH4gaGFiaXQpICU+JQogIGNhbGN1bGF0ZShzdGF0ID0gInQiLCBvcmRlciA9IGMoInNtb2tlciIsICJub25zbW9rZXIiKSkKYGBgCgpBbHRlcm5hdGl2ZWx5LCB1c2luZyB0aGUgYG9ic2VydmUoKWAgd3JhcHBlciB0byBjYWxjdWxhdGUgdGhlIG9ic2VydmVkIHN0YXRpc3RpYywKCmBgYHtyfQp0X2hhdCA8LSBiaXJ0aHMxNCAlPiUKICBvYnNlcnZlKHdlaWdodCB+IGhhYml0LAogICAgICAgICAgc3RhdCA9ICJ0Iiwgb3JkZXIgPSBjKCJzbW9rZXIiLCAibm9uc21va2VyIikpCmBgYAoKVGhlbiwgZ2VuZXJhdGluZyBhIGJvb3RzdHJhcCBkaXN0cmlidXRpb24sCgpgYGB7cn0KYm9vdF9kaXN0IDwtIGJpcnRoczE0ICU+JQogICBzcGVjaWZ5KHdlaWdodCB+IGhhYml0KSAlPiUKICAgZ2VuZXJhdGUocmVwcyA9IDEwMDAsIHR5cGUgPSAiYm9vdHN0cmFwIikgJT4lCiAgIGNhbGN1bGF0ZShzdGF0ID0gInQiLCBvcmRlciA9IGMoInNtb2tlciIsICJub25zbW9rZXIiKSkKYGBgCgpVc2UgdGhlIGJvb3RzdHJhcCBkaXN0cmlidXRpb24gdG8gZmluZCBhIGNvbmZpZGVuY2UgaW50ZXJ2YWwsCgpgYGB7cn0KcGVyY2VudGlsZV9jaSA8LSBnZXRfY2koYm9vdF9kaXN0KQpgYGAKClZpc3VhbGl6aW5nIHRoZSBvYnNlcnZlZCBzdGF0aXN0aWMgYWxvbmdzaWRlIHRoZSBkaXN0cmlidXRpb24sCgpgYGB7cn0KdmlzdWFsaXplKGJvb3RfZGlzdCkgKwogIHNoYWRlX2NvbmZpZGVuY2VfaW50ZXJ2YWwoZW5kcG9pbnRzID0gcGVyY2VudGlsZV9jaSkKYGBgCgpBbHRlcm5hdGl2ZWx5LCB1c2UgdGhlIGJvb3RzdHJhcCBkaXN0cmlidXRpb24gdG8gZmluZCBhIGNvbmZpZGVuY2UgaW50ZXJ2YWwgdXNpbmcgdGhlIHN0YW5kYXJkIGVycm9yLAoKYGBge3J9CnN0YW5kYXJkX2Vycm9yX2NpIDwtIGJvb3RfZGlzdCAlPiUKICBnZXRfY2kodHlwZSA9ICJzZSIsIHBvaW50X2VzdGltYXRlID0gdF9oYXQpCgp2aXN1YWxpemUoYm9vdF9kaXN0KSArCiAgc2hhZGVfY29uZmlkZW5jZV9pbnRlcnZhbChlbmRwb2ludHMgPSBzdGFuZGFyZF9lcnJvcl9jaSkKYGBgCgpTZWUgdGhlIGFib3ZlIHN1YnNlY3Rpb24gKGRpZmYgaW4gbWVhbnMpIGZvciBhIHRoZW9yeS1iYXNlZCBhcHByb2FjaC4gaW5mZXIgZG9lcyBub3Qgc3VwcG9ydCBjb25maWRlbmNlIGludGVydmFscyBvbiBtZWFucyB2aWEgdGhlIHogZGlzdHJpYnV0aW9uLgoKPGJyPgoKIyMgKipQYWlyZWQgTWVhbnMqKgoKVGhlIFtgdWNsYV90ZXh0Ym9va3NfZjE4YF0oaHR0cDovL29wZW5pbnRyb3N0YXQuZ2l0aHViLmlvL29wZW5pbnRyby9yZWZlcmVuY2UvdWNsYV90ZXh0Ym9va3NfZjE4Lmh0bWwpIGRhdGEgY2FuIGJlIGZvdW5kIGluIHRoZSBbKipvcGVuaW50cm8qKl0oaHR0cDovL29wZW5pbnRyb3N0YXQuZ2l0aHViLmlvL29wZW5pbnRybykgUiBwYWNrYWdlLgoKYGBge3J9CmdsaW1wc2UodWNsYV90ZXh0Ym9va3NfZjE4KQpgYGAKClNlbGVjdCB0aGUgcHJpY2VzIGZvciBuZXcgYm9va3MgZnJvbSB0aGUgYm9va3N0b3JlIGFuZCBhbWF6b24uCgpgYGB7cn0KbmV3X2Jvb2tzIDwtIHVjbGFfdGV4dGJvb2tzX2YxOCAlPiUgc2VsZWN0KGJvb2tzdG9yZV9uZXcsYW1hem9uX25ldykgJT4lIG5hLm9taXQoKQpuZXdfYm9va3MKYGBgCgpOZXh0LCB3ZSB0YWtlIHRoZSBkaWZmZXJlbmNlIG9mIHRoZSBwYWlycy4KCmBgYHtyfQpuZXdfYm9va3NfZGlmZiA8LSBuZXdfYm9va3MgJT4lIG11dGF0ZShkaWZmID0gYm9va3N0b3JlX25ldyAtIGFtYXpvbl9uZXcpCm5ld19ib29rc19kaWZmCmBgYAoKTm93LCBJIGNhbiB1c2UgbXkgZGlmZmVyZW5jZXMgdG8gcGVyZm9ybSAqKmh5cG90aGVzaXMgdGVzdCoqLCB3aGljaCBpcyBlcXVpdmFsZW50IHRvIGEgb25lLXNhbXBsZSB0LXRlc3QuCgpgYGB7cn0KVCA8LSBuZXdfYm9va3NfZGlmZiAlPiUKICBzcGVjaWZ5KHJlc3BvbnNlID0gZGlmZikgJT4lCiAgaHlwb3RoZXNpemUobnVsbCA9ICJwb2ludCIsIG11ID0gMCkgJT4lCiAgY2FsY3VsYXRlKHN0YXQgPSAidCIpCgpUCmBgYAoKYGBge3J9Cm51bGxfZGlzdF90aGVvcnkgPC0gbmV3X2Jvb2tzX2RpZmYgJT4lCiAgc3BlY2lmeShyZXNwb25zZSA9IGRpZmYpICAlPiUKICBhc3N1bWUoInQiKQpgYGAKCmBgYHtyfQp2aXN1YWxpemUobnVsbF9kaXN0X3RoZW9yeSkgKwogIHNoYWRlX3BfdmFsdWUob2JzX3N0YXQgPSBULCBkaXJlY3Rpb24gPSAidHdvLXNpZGVkIikKYGBgCgpgYGB7cn0KbnVsbF9kaXN0X3RoZW9yeSAlPiUKICBnZXRfcF92YWx1ZShvYnNfc3RhdCA9IFQsIGRpcmVjdGlvbiA9ICJ0d28tc2lkZWQiKQpgYGAKCk5leHQsIHdlIGNhbiBkbyAqKmNvbmZpZGVuY2UgaW50ZXJ2YWxzKiosIHdoaWNoIGlzIGVxdWl2YWxlbnQgdG8gYSB0d28tc2FtcGxlIHQtaW50ZXJ2YWwuCgpgYGB7cn0KeF9iYXJfZGlmZiA8LSBuZXdfYm9va3NfZGlmZiAlPiUgCiAgc3BlY2lmeShyZXNwb25zZSA9IGRpZmYpICU+JQogIGNhbGN1bGF0ZShzdGF0ID0gIm1lYW4iKQoKeF9iYXJfZGlmZgpgYGAKClNpbXVsYXRpb24gTWV0aG9kCgpgYGB7cn0KYm9vdF9kaXN0IDwtIG5ld19ib29rc19kaWZmICU+JQogICBzcGVjaWZ5KHJlc3BvbnNlID0gZGlmZikgJT4lCiAgIGdlbmVyYXRlKHJlcHMgPSAxMDAwLCB0eXBlID0gImJvb3RzdHJhcCIpICU+JQogICBjYWxjdWxhdGUoc3RhdCA9ICJtZWFuIikKYGBgCgpgYGB7cn0Kc3RhbmRhcmRfZXJyb3JfY2kgPC0gZ2V0X2NpKGJvb3RfZGlzdCwgdHlwZSA9ICJzZSIsIHBvaW50X2VzdGltYXRlID0geF9iYXJfZGlmZikKCnN0YW5kYXJkX2Vycm9yX2NpCmBgYAoKYGBge3J9CnZpc3VhbGl6ZShib290X2Rpc3QpICsKICBzaGFkZV9jb25maWRlbmNlX2ludGVydmFsKGVuZHBvaW50cyA9IHN0YW5kYXJkX2Vycm9yX2NpKQpgYGAKClRoZW9yZXRpY2FsIE1ldGhvZAoKYGBge3J9CnNhbXBsaW5nX2Rpc3QgPC0gbmV3X2Jvb2tzX2RpZmYgJT4lCiAgIHNwZWNpZnkocmVzcG9uc2UgPSBkaWZmKSAlPiUKICAgYXNzdW1lKGRpc3RyaWJ1dGlvbiA9ICJ0IikKYGBgCgpgYGB7cn0KdGhlb3JfY2kgPC0gZ2V0X2NpKHNhbXBsaW5nX2Rpc3QsIHBvaW50X2VzdGltYXRlID0geF9iYXJfZGlmZikKCnRoZW9yX2NpCmBgYAoKYGBge3J9CnZpc3VhbGl6ZShzYW1wbGluZ19kaXN0KSArCiAgc2hhZGVfY29uZmlkZW5jZV9pbnRlcnZhbChlbmRwb2ludHMgPSB0aGVvcl9jaSkKYGBgCgojIyAqKkNvbXBhcmluZyBNdWx0aXBsZSBNZWFucyoqCgpHbyB0aHJvdWdoIHRoZSB0dXRvcmlhbCBpbiBDaGFwdGVyIDIzLjQgaW4gdGhlIFRleHRib29rLgoKW1R1dG9yaWFsIDUgLSBMZXNzb24gOF0oaHR0cHM6Ly9vcGVuaW50cm8uc2hpbnlhcHBzLmlvL2ltcy0wNS1pbmZlci0wOC8pe3RhcmdldD0iX2JsYW5rIn0KCiMjICoqTWluaSBBY3Rpdml0aWVzKioKCjxicj4KCjEuIFVzZSB0aGUgYGJpcnRoczE0YCBkYXRhIHNldCB0byBwZXJmb3JtIGEgaHlwb3RoZXNpcyB0ZXN0IGFuZCBjb25maWRlbmNlIGludGVydmFsIHVzaW5nIHRoZSBgd2VpZ2h0YCBhbmQgYHdoaXRlbW9tYCB2YXJpYWJsZXMuCgogICAgYS4gUHJpbnQgb3V0IHRoZSBzdW1tYXJpemVkIHN0YXRpc3RpY3Mgb2YgdGhlIHZhcmlhYmxlcyBgd2VpZ2h0YCBhbmQgYHdoaXRlbW9tYC4gTm90ZSB0aGF0IHRoZSBgd2VpZ2h0YCB2YXJpYWJsZSBpcyBhIGNvbnRpbnVvdXMgbnVtZXJpY2FsIHZhcmlhYmxlIHdoaWxlIHRoZSBgd2hpdGVtb21gIHZhcmlhYmxlIGlzIGEgbm9taW5hbCBjYXRlZ29yaWNhbCB2YXJpYWJsZSB3aXRoIHR3byBsZXZlbHMuCgogICAgYi4gUGVyZm9ybSBhIGh5cG90aGVzaXMgdGVzdCBhbmQgY29uZmlkZW5jZSBpbnRlcnZhbCBmb3IgdGhlIGBub3Qgd2hpdGVgIGxldmVsIGluIHRoZSBgd2hpdGVtb21gIHZhcmlhYmxlLiBTdXBwb3NlIHRoYXQgdGhlIGF2ZXJhZ2UgYmlydGggd2VpZ2h0IGlzICQ3LjUkIGxiLiBEb2VzIHRoZSBkYXRhIHNob3cgYSBjb252aW5jaW5nIGV2aWRlbmNlIHRoYXQgbm9uIHdoaXRlIGluZGl2aWR1YWxzIGhhdmUgbGVzcyBhdmVyYWdlIGJpcnRoIHdlaWdodHM/CgogICAgYy4gUGVyZm9ybSBpbmZlcmVuY2UgKGh5cG90aGVzaXMgdGVzdGluZyBhbmQgY29uZmlkZW5jZSBpbnRlcnZhbCkgZm9yIHRoZSBkaWZmZXJlbmNlIGluIGJpcnRoIHdlaWdodCBtZWFucyBmb3IgdGhlIHR3byBsZXZlbHMgaW4gdGhlIGB3aGl0ZW1vbWAgdmFyaWFibGUuIElzIHRoZXJlIGEgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBhbmQgYnkgaG93IG11Y2g/CgoyLiBVc2UgdGhlIGB1Y2xhX3RleHRib29rc19mMThgIGRhdGEgc2V0IHRvIHBlcmZvcm0gYSBoeXBvdGhlc2lzIHRlc3QgYW5kIGNvbmZpZGVuY2UgaW50ZXJ2YWwgZm9yIGNvbXBhcmluZyB0aGUgbmV3IGFuZCB1c2VkIGJvb2tzLgoKICAgIGEuIENvbXB1dGUgdGhlIHBhaXJlZCBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIFVDTEEgYm9va3N0b3JlIGFuZCBBbWF6b24gdXNlZCBib29rcy4gUGVyZm9ybSBhIGh5cG90aGVzaXMgdGVzdCBhbmQgY29tcHV0ZSB0aGUgOTVcJSBjb25maWRlbmNlIGludGVydmFsLiBXaGF0IGlzIHlvdXIgbnVsbCBhbmQgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcz8gV2hhdCBhcmUgeW91ciBjb25jbHVzaW9ucz8KICAKICAgIGIuIFN1cHBvc2UgdGhhdCB5b3UgYXJlIGNvbXBhcmluZyBuZXcgYW5kIHVzZWQgYm9va3MgcmVnYXJkbGVzcyBvZiBzdG9yZS4gQ29tcHV0ZSB0aGUgcGFpcmVkIGRpZmZlcmVuY2UgYmV0d2VlbiBuZXcgYW5kIHVzZWQgYm9va3MgKHRha2UgdGhlIGF2ZXJhZ2UgcHJpY2UgZm9yIGVhY2ggYm9vayBiZXR3ZWVuIHN0b3JlcyBhbmQgdGhlbiBjb21wdXRlIHRoZSBkaWZmZXJlbmNlKS4gQ29tcHV0ZSB0aGUgOTVcJSBjb25maWRlbmNlIGludGVydmFsLgoKPGJyPgo=