Loading the packages:

# Loading the tidyverse package
library(tidyverse)

Reading in the NFL drives data from github

# Read in the nfl drive data
drives <- read.csv("https://raw.githubusercontent.com/Shammalamala/STA4504/refs/heads/main/data/ch1/nfl%20drives.csv")

# Looking at the different ways drives can end
unique(drives$drive_end)
## [1] "Field Goal" "Turnover"   "Touchdown"  "Punt"

We will be focusing on the variable drive_end

There are 4 ways in the data that a touchdown can end: Touchdown, Field Goal, Punt, Turnover

Summary Statistics

Let’s start by getting the needed statistics from the sample: \(y\), \(n\), and \(\hat{\pi}\)

# total touchdowns
td_total <- sum(drives$drive_end == "Touchdown")

# sample size
n <- nrow(drives)

# Sample proportion
td_prop <- mean(drives$drive_end == "Touchdown")

c('y' = td_total, 'n' = n, 'pi_hat' = td_prop)
##       y       n  pi_hat 
##  300.00 1250.00    0.24

Confidence Intervals for a proportion

If we reject our null hypothesis, we often followup with a confidence interval to narrow down what \(\pi\) could be.

We’ll look at 3 different intervals:

  1. Wald interval - the most common interval

  2. Score interval - Equivalent to the score test

  3. Agresti-Coull interval - Tends to work better than the previous two for smaller samples when the sample proportion is close to 0 or 1

We’ll be using a 95% confidence level for our examples, but these work for any chosen level!

Wald Interval

\[\hat{\pi} \pm z_{\alpha/2} \sqrt{\frac{\hat{\pi}(1-\hat{\pi})}{n}}\]

# Start by finding the critical value of a 95% CI:
z95 <- qnorm(1 - 0.05/2)

wald_se <- sqrt(td_prop*(1-td_prop)/n)

# Next the confidence interval!
wald_ci_td <- 
  c(
    lower = td_prop - z95*wald_se,
    upper = td_prop + z95*wald_se
  )

wald_ci_td |> signif(digits = 3)
## lower upper 
## 0.216 0.264

Using a Wald confidence interval, we can be 95% confident that between 21.6% to 26.4% of all NFL drives end in touchdowns.

Score CI

How do we calculate a Score confidence interval?

We find the values of \(\pi_0\) that would cause us to not reject the null hypothesis. The easiest way to find that is find the values of \(\pi_0\) that give a test stat less than or equal to our critical value we found earlier!

score_df <- 
  tibble(
    pi0 = seq(0, 1, by = 0.001),    # Create a range of pi_0 values to test
    se0 = sqrt(pi0*(1-pi0)/n), # Calculating the standard errors for the different pi0
    z = (td_prop - pi0)/se0    # Finding the Score test stat for the various pi0
  )        

score_df
## # A tibble: 1,001 × 3
##      pi0      se0     z
##    <dbl>    <dbl> <dbl>
##  1 0     0        Inf  
##  2 0.001 0.000894 267. 
##  3 0.002 0.00126  188. 
##  4 0.003 0.00155  153. 
##  5 0.004 0.00179  132. 
##  6 0.005 0.00199  118. 
##  7 0.006 0.00218  107. 
##  8 0.007 0.00236   98.8
##  9 0.008 0.00252   92.1
## 10 0.009 0.00267   86.5
## # ℹ 991 more rows
# Next we want to find the values of pi0 that have a test stat below z95
score_df |> 
  filter(abs(z) <= z95) |> 
  summarize(
    lower = min(pi0),
    upper = max(pi0)
  )
## # A tibble: 1 × 2
##   lower upper
##   <dbl> <dbl>
## 1 0.218 0.264

When rounding to 3 decimal places, we get a very similar confidence interval to the Wald interval earlier!

There is also a formula we can use in place of conducting a grid search:

\[\frac{y +\left(z^*\right)^2/2}{n + \left(z^*\right)^2} \pm \frac{z^*}{n + \left(z^*\right)^2} \sqrt{\frac{y(n - y)}{n} + \frac{\left(z^*\right)^2}{4}}\]

where \(y\) is the count, not proportion

# First, find the "statistic"
score_stat <- (td_total + z95^2/2)/(n + z95^2)


# Next find the standard error
score_se <- sqrt(td_total *(n - td_total)/n + z95^2/4)


# Then margin of error
me_formula <- z95/(n + z95^2) * score_se


# Then interval:
tribble(
      ~'result',                ~'value',
            'y',                td_total,
            'n',                       n,
   'score stat',              score_stat,
     'Score SE',                score_se,
     'Score ME',              me_formula,
  'lower bound', score_stat - me_formula,
  'upper bound', score_stat + me_formula
) |> 
  mutate(
    value = round(value, 3)
  )
## # A tibble: 7 × 2
##   result         value
##   <chr>          <dbl>
## 1 y            300    
## 2 n           1250    
## 3 score stat     0.241
## 4 Score SE      15.1  
## 5 Score ME       0.024
## 6 lower bound    0.217
## 7 upper bound    0.264

Our two answers are slight different due to rounding and only searching to the nearest 0.001. If we used enough digits in our “search”, the answer will be identical!

Agresti-Coull

The Agresti-Coull (AC) interval ‘mixes’ the score and Wald intervals together.

How? It keeps the same general form of the Wald interval:

\[\hat{\pi} \pm z_{\alpha/2} \sqrt{\frac{\hat{\pi}(1-\hat{\pi})}{n}}\]

but it updates \(y\) and \(n\):

\[\tilde{y} = y + (z^*)^2/2 \\ \tilde{n} = n + (z^*)^2 \\ \tilde{\pi} = \tilde{y} / \tilde{n}\]

# Calculating the 'new' point estimate
y_tilde <- td_total + (z95^2)/2
n_tilde <-  n + z95^2
pi_tilde <- y_tilde / n_tilde

# The standard error
AG_se <- sqrt(pi_tilde * (1-pi_tilde) / n)

# Lower and upper bounds
AG_ci <- 
  c('lower' = pi_tilde - z95 * AG_se,
    'upper' = pi_tilde + z95 * AG_se
    )

AG_ci
##     lower     upper 
## 0.2170939 0.2644992

Just like the score and Wald interval, it’s very, very similar!

Built-in Functions

If you want one function to rule them all, we can use the binom.confint() function in the binom package.

It works similarly to prop.test(), in that we need to specify x and n. However, we can also specify methods as a way to tell it which method to build the confidence interval:

library(binom)
binom.confint(
  x = td_total,
  n = n,
  conf.level = 0.95,
  methods = 'asymptotic'
)
##       method   x    n mean     lower     upper
## 1 asymptotic 300 1250 0.24 0.2163242 0.2636758
binom.confint(
  x = td_total,
  n = n,
  conf.level = 0.95,
  methods = 'wilson'
)
##   method   x    n mean     lower     upper
## 1 wilson 300 1250 0.24 0.2171436 0.2644495
binom.confint(
  x = td_total,
  n = n,
  conf.level = 0.95,
  methods = 'ac'
)
##          method   x    n mean     lower     upper
## 1 agresti-coull 300 1250 0.24 0.2171302 0.2644629

You can also give it all three methods in one function by giving methods a vector:

binom.confint(
  x = td_total,
  n = n,
  conf.level = 0.95,
  methods = c('asymptotic', 'wilson', 'ac')
)
##          method   x    n mean     lower     upper
## 1 agresti-coull 300 1250 0.24 0.2171302 0.2644629
## 2    asymptotic 300 1250 0.24 0.2163242 0.2636758
## 3        wilson 300 1250 0.24 0.2171436 0.2644495
LS0tDQp0aXRsZTogIkNvbmZpZGVuY2UgSW50ZXJ2YWxzIGZvciBhIFNpbmdsZSBQcm9wb3J0aW9uIg0KYXV0aG9yOiAiQ2hhcHRlciAxIg0KZGF0ZTogIlNUQSA0NTA0Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGZpZ193aWR0aDogNg0KICAgIGZpZ19oZWlnaHQ6IDYNCiAgICBmaWdfY2FwdGlvbjogdHJ1ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgc21vb3RoX3Njcm9sbDogdHJ1ZQ0KICAgIHRoZW1lOiBsdW1lbg0KICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICBmaWcuYWxpZ24gPSAiY2VudGVyIikNCmBgYA0KDQpMb2FkaW5nIHRoZSBwYWNrYWdlczoNCg0KYGBge3IgcGFja2FnZXMsIG1lc3NhZ2UgPSBGLCB3YXJuaW5nID0gRn0NCiMgTG9hZGluZyB0aGUgdGlkeXZlcnNlIHBhY2thZ2UNCmxpYnJhcnkodGlkeXZlcnNlKQ0KYGBgDQoNClJlYWRpbmcgaW4gdGhlIE5GTCBkcml2ZXMgZGF0YSBmcm9tIGdpdGh1Yg0KDQpgYGB7ciBkYXRhfQ0KIyBSZWFkIGluIHRoZSBuZmwgZHJpdmUgZGF0YQ0KZHJpdmVzIDwtIHJlYWQuY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vU2hhbW1hbGFtYWxhL1NUQTQ1MDQvcmVmcy9oZWFkcy9tYWluL2RhdGEvY2gxL25mbCUyMGRyaXZlcy5jc3YiKQ0KDQojIExvb2tpbmcgYXQgdGhlIGRpZmZlcmVudCB3YXlzIGRyaXZlcyBjYW4gZW5kDQp1bmlxdWUoZHJpdmVzJGRyaXZlX2VuZCkNCg0KYGBgDQoNCldlIHdpbGwgYmUgZm9jdXNpbmcgb24gdGhlIHZhcmlhYmxlIGBkcml2ZV9lbmRgDQoNClRoZXJlIGFyZSA0IHdheXMgaW4gdGhlIGRhdGEgdGhhdCBhIHRvdWNoZG93biBjYW4gZW5kOiBUb3VjaGRvd24sIEZpZWxkIEdvYWwsIFB1bnQsIFR1cm5vdmVyDQoNCg0KIyMgU3VtbWFyeSBTdGF0aXN0aWNzDQoNCkxldCdzIHN0YXJ0IGJ5IGdldHRpbmcgdGhlIG5lZWRlZCBzdGF0aXN0aWNzIGZyb20gdGhlIHNhbXBsZTogJHkkLCAkbiQsIGFuZCAkXGhhdHtccGl9JA0KDQpgYGB7ciB0ZF9wcm9wfQ0KIyB0b3RhbCB0b3VjaGRvd25zDQp0ZF90b3RhbCA8LSBzdW0oZHJpdmVzJGRyaXZlX2VuZCA9PSAiVG91Y2hkb3duIikNCg0KIyBzYW1wbGUgc2l6ZQ0KbiA8LSBucm93KGRyaXZlcykNCg0KIyBTYW1wbGUgcHJvcG9ydGlvbg0KdGRfcHJvcCA8LSBtZWFuKGRyaXZlcyRkcml2ZV9lbmQgPT0gIlRvdWNoZG93biIpDQoNCmMoJ3knID0gdGRfdG90YWwsICduJyA9IG4sICdwaV9oYXQnID0gdGRfcHJvcCkNCmBgYA0KDQoNCiMjIENvbmZpZGVuY2UgSW50ZXJ2YWxzIGZvciBhIHByb3BvcnRpb24NCg0KSWYgd2UgcmVqZWN0IG91ciBudWxsIGh5cG90aGVzaXMsIHdlIG9mdGVuIGZvbGxvd3VwIHdpdGggYSBjb25maWRlbmNlIGludGVydmFsIHRvIG5hcnJvdyBkb3duIHdoYXQgJFxwaSQgY291bGQgYmUuDQoNCldlJ2xsIGxvb2sgYXQgMyBkaWZmZXJlbnQgaW50ZXJ2YWxzOg0KDQoxKSBXYWxkIGludGVydmFsIC0gdGhlIG1vc3QgY29tbW9uIGludGVydmFsDQoNCjIpIFNjb3JlIGludGVydmFsIC0gRXF1aXZhbGVudCB0byB0aGUgc2NvcmUgdGVzdA0KDQozKSBBZ3Jlc3RpLUNvdWxsIGludGVydmFsIC0gVGVuZHMgdG8gd29yayBiZXR0ZXIgdGhhbiB0aGUgcHJldmlvdXMgdHdvIGZvciBzbWFsbGVyIHNhbXBsZXMgd2hlbiB0aGUgc2FtcGxlIHByb3BvcnRpb24gaXMgY2xvc2UgdG8gMCBvciAxDQoNCg0KV2UnbGwgYmUgdXNpbmcgYSA5NSUgY29uZmlkZW5jZSBsZXZlbCBmb3Igb3VyIGV4YW1wbGVzLCBidXQgdGhlc2Ugd29yayBmb3IgYW55IGNob3NlbiBsZXZlbCENCg0KDQoNCg0KIyMjIFdhbGQgSW50ZXJ2YWwNCg0KJCRcaGF0e1xwaX0gXHBtIHpfe1xhbHBoYS8yfSBcc3FydHtcZnJhY3tcaGF0e1xwaX0oMS1caGF0e1xwaX0pfXtufX0kJA0KDQoNCg0KYGBge3Igd2FsZF9DSX0NCiMgU3RhcnQgYnkgZmluZGluZyB0aGUgY3JpdGljYWwgdmFsdWUgb2YgYSA5NSUgQ0k6DQp6OTUgPC0gcW5vcm0oMSAtIDAuMDUvMikNCg0Kd2FsZF9zZSA8LSBzcXJ0KHRkX3Byb3AqKDEtdGRfcHJvcCkvbikNCg0KIyBOZXh0IHRoZSBjb25maWRlbmNlIGludGVydmFsIQ0Kd2FsZF9jaV90ZCA8LSANCiAgYygNCiAgICBsb3dlciA9IHRkX3Byb3AgLSB6OTUqd2FsZF9zZSwNCiAgICB1cHBlciA9IHRkX3Byb3AgKyB6OTUqd2FsZF9zZQ0KICApDQoNCndhbGRfY2lfdGQgfD4gc2lnbmlmKGRpZ2l0cyA9IDMpDQpgYGANCg0KVXNpbmcgYSBXYWxkIGNvbmZpZGVuY2UgaW50ZXJ2YWwsIHdlIGNhbiBiZSA5NSUgY29uZmlkZW50IHRoYXQgYmV0d2VlbiAyMS42JSB0byAyNi40JSBvZiBhbGwgTkZMIGRyaXZlcyBlbmQgaW4gdG91Y2hkb3ducy4NCg0KIyMjIFNjb3JlIENJDQoNCkhvdyBkbyB3ZSBjYWxjdWxhdGUgYSBTY29yZSBjb25maWRlbmNlIGludGVydmFsPw0KDQpXZSBmaW5kIHRoZSB2YWx1ZXMgb2YgJFxwaV8wJCB0aGF0IHdvdWxkIGNhdXNlIHVzIHRvICoqbm90KiogcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMuIFRoZSBlYXNpZXN0IHdheSB0byBmaW5kIHRoYXQgaXMgZmluZCB0aGUgdmFsdWVzIG9mICRccGlfMCQgdGhhdCBnaXZlIGEgdGVzdCBzdGF0IGxlc3MgdGhhbiBvciBlcXVhbCB0byBvdXIgY3JpdGljYWwgdmFsdWUgd2UgZm91bmQgZWFybGllciENCg0KYGBge3Igc2NvcmVfY2l9DQpzY29yZV9kZiA8LSANCiAgdGliYmxlKA0KICAgIHBpMCA9IHNlcSgwLCAxLCBieSA9IDAuMDAxKSwgICAgIyBDcmVhdGUgYSByYW5nZSBvZiBwaV8wIHZhbHVlcyB0byB0ZXN0DQogICAgc2UwID0gc3FydChwaTAqKDEtcGkwKS9uKSwgIyBDYWxjdWxhdGluZyB0aGUgc3RhbmRhcmQgZXJyb3JzIGZvciB0aGUgZGlmZmVyZW50IHBpMA0KICAgIHogPSAodGRfcHJvcCAtIHBpMCkvc2UwICAgICMgRmluZGluZyB0aGUgU2NvcmUgdGVzdCBzdGF0IGZvciB0aGUgdmFyaW91cyBwaTANCiAgKSAgICAgICAgDQoNCnNjb3JlX2RmDQoNCiMgTmV4dCB3ZSB3YW50IHRvIGZpbmQgdGhlIHZhbHVlcyBvZiBwaTAgdGhhdCBoYXZlIGEgdGVzdCBzdGF0IGJlbG93IHo5NQ0Kc2NvcmVfZGYgfD4gDQogIGZpbHRlcihhYnMoeikgPD0gejk1KSB8PiANCiAgc3VtbWFyaXplKA0KICAgIGxvd2VyID0gbWluKHBpMCksDQogICAgdXBwZXIgPSBtYXgocGkwKQ0KICApDQpgYGANCg0KV2hlbiByb3VuZGluZyB0byAzIGRlY2ltYWwgcGxhY2VzLCB3ZSBnZXQgYSB2ZXJ5IHNpbWlsYXIgY29uZmlkZW5jZSBpbnRlcnZhbCB0byB0aGUgV2FsZCBpbnRlcnZhbCBlYXJsaWVyIQ0KDQoNCg0KVGhlcmUgaXMgYWxzbyBhIGZvcm11bGEgd2UgY2FuIHVzZSBpbiBwbGFjZSBvZiBjb25kdWN0aW5nIGEgZ3JpZCBzZWFyY2g6DQoNCiQkXGZyYWN7eSArXGxlZnQoel4qXHJpZ2h0KV4yLzJ9e24gKyBcbGVmdCh6XipccmlnaHQpXjJ9IFxwbSBcZnJhY3t6Xip9e24gKyBcbGVmdCh6XipccmlnaHQpXjJ9IFxzcXJ0e1xmcmFje3kobiAtIHkpfXtufSArIFxmcmFje1xsZWZ0KHpeKlxyaWdodCleMn17NH19JCQNCg0Kd2hlcmUgJHkkIGlzIHRoZSBjb3VudCwgbm90IHByb3BvcnRpb24NCg0KYGBge3Igc2NvcmVfZm9ybXVsYX0NCiMgRmlyc3QsIGZpbmQgdGhlICJzdGF0aXN0aWMiDQpzY29yZV9zdGF0IDwtICh0ZF90b3RhbCArIHo5NV4yLzIpLyhuICsgejk1XjIpDQoNCg0KIyBOZXh0IGZpbmQgdGhlIHN0YW5kYXJkIGVycm9yDQpzY29yZV9zZSA8LSBzcXJ0KHRkX3RvdGFsICoobiAtIHRkX3RvdGFsKS9uICsgejk1XjIvNCkNCg0KDQojIFRoZW4gbWFyZ2luIG9mIGVycm9yDQptZV9mb3JtdWxhIDwtIHo5NS8obiArIHo5NV4yKSAqIHNjb3JlX3NlDQoNCg0KIyBUaGVuIGludGVydmFsOg0KdHJpYmJsZSgNCiAgICAgIH4ncmVzdWx0JywgICAgICAgICAgICAgICAgfid2YWx1ZScsDQogICAgICAgICAgICAneScsICAgICAgICAgICAgICAgIHRkX3RvdGFsLA0KICAgICAgICAgICAgJ24nLCAgICAgICAgICAgICAgICAgICAgICAgbiwNCiAgICdzY29yZSBzdGF0JywgICAgICAgICAgICAgIHNjb3JlX3N0YXQsDQogICAgICdTY29yZSBTRScsICAgICAgICAgICAgICAgIHNjb3JlX3NlLA0KICAgICAnU2NvcmUgTUUnLCAgICAgICAgICAgICAgbWVfZm9ybXVsYSwNCiAgJ2xvd2VyIGJvdW5kJywgc2NvcmVfc3RhdCAtIG1lX2Zvcm11bGEsDQogICd1cHBlciBib3VuZCcsIHNjb3JlX3N0YXQgKyBtZV9mb3JtdWxhDQopIHw+IA0KICBtdXRhdGUoDQogICAgdmFsdWUgPSByb3VuZCh2YWx1ZSwgMykNCiAgKQ0KDQpgYGANCg0KT3VyIHR3byBhbnN3ZXJzIGFyZSBzbGlnaHQgZGlmZmVyZW50IGR1ZSB0byByb3VuZGluZyBhbmQgb25seSBzZWFyY2hpbmcgdG8gdGhlIG5lYXJlc3QgMC4wMDEuIElmIHdlIHVzZWQgZW5vdWdoIGRpZ2l0cyBpbiBvdXIgInNlYXJjaCIsIHRoZSBhbnN3ZXIgd2lsbCBiZSBpZGVudGljYWwhDQoNCg0KIyMjIEFncmVzdGktQ291bGwNCg0KVGhlIEFncmVzdGktQ291bGwgKEFDKSBpbnRlcnZhbCAnbWl4ZXMnIHRoZSBzY29yZSBhbmQgV2FsZCBpbnRlcnZhbHMgdG9nZXRoZXIuDQoNCkhvdz8gSXQga2VlcHMgdGhlIHNhbWUgZ2VuZXJhbCBmb3JtIG9mIHRoZSBXYWxkIGludGVydmFsOg0KDQokJFxoYXR7XHBpfSBccG0gel97XGFscGhhLzJ9IFxzcXJ0e1xmcmFje1xoYXR7XHBpfSgxLVxoYXR7XHBpfSl9e259fSQkDQoNCmJ1dCBpdCB1cGRhdGVzICR5JCBhbmQgJG4kOg0KDQokJFx0aWxkZXt5fSA9IHkgKyAoel4qKV4yLzIgXFwgXHRpbGRle259ID0gbiArICh6XiopXjIgXFwgXHRpbGRle1xwaX0gPSBcdGlsZGV7eX0gLyBcdGlsZGV7bn0kJA0KDQpgYGB7ciBBQ19pbnRlcnZhbH0NCiMgQ2FsY3VsYXRpbmcgdGhlICduZXcnIHBvaW50IGVzdGltYXRlDQp5X3RpbGRlIDwtIHRkX3RvdGFsICsgKHo5NV4yKS8yDQpuX3RpbGRlIDwtICBuICsgejk1XjINCnBpX3RpbGRlIDwtIHlfdGlsZGUgLyBuX3RpbGRlDQoNCiMgVGhlIHN0YW5kYXJkIGVycm9yDQpBR19zZSA8LSBzcXJ0KHBpX3RpbGRlICogKDEtcGlfdGlsZGUpIC8gbikNCg0KIyBMb3dlciBhbmQgdXBwZXIgYm91bmRzDQpBR19jaSA8LSANCiAgYygnbG93ZXInID0gcGlfdGlsZGUgLSB6OTUgKiBBR19zZSwNCiAgICAndXBwZXInID0gcGlfdGlsZGUgKyB6OTUgKiBBR19zZQ0KICAgICkNCg0KQUdfY2kNCg0KYGBgDQoNCkp1c3QgbGlrZSB0aGUgc2NvcmUgYW5kIFdhbGQgaW50ZXJ2YWwsIGl0J3MgdmVyeSwgdmVyeSBzaW1pbGFyIQ0KDQojIyBCdWlsdC1pbiBGdW5jdGlvbnMNCg0KSWYgeW91IHdhbnQgKm9uZSBmdW5jdGlvbiB0byBydWxlIHRoZW0gYWxsKiwgd2UgY2FuIHVzZSB0aGUgYGJpbm9tLmNvbmZpbnQoKWAgZnVuY3Rpb24gaW4gdGhlIGBiaW5vbWAgcGFja2FnZS4NCg0KSXQgd29ya3Mgc2ltaWxhcmx5IHRvIGBwcm9wLnRlc3QoKWAsIGluIHRoYXQgd2UgbmVlZCB0byBzcGVjaWZ5IGB4YCBhbmQgYG5gLiBIb3dldmVyLCB3ZSBjYW4gYWxzbyBzcGVjaWZ5IGBtZXRob2RzYCBhcyBhIHdheSB0byB0ZWxsIGl0IHdoaWNoIG1ldGhvZCB0byBidWlsZCB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbDoNCg0KLSAnYXN5bXB0b3RpYycgPSBXYWxkDQotICd3aWxzb24nID0gc2NvcmUNCi0gJ2FjJyA9IEFncmVzdGktQ291bGwNCg0KDQpgYGB7ciBidWlsdGluX3dhbGR9DQpsaWJyYXJ5KGJpbm9tKQ0KYmlub20uY29uZmludCgNCiAgeCA9IHRkX3RvdGFsLA0KICBuID0gbiwNCiAgY29uZi5sZXZlbCA9IDAuOTUsDQogIG1ldGhvZHMgPSAnYXN5bXB0b3RpYycNCikNCmBgYA0KDQoNCg0KYGBge3IgYnVpbHRpbl9zY29yZX0NCmJpbm9tLmNvbmZpbnQoDQogIHggPSB0ZF90b3RhbCwNCiAgbiA9IG4sDQogIGNvbmYubGV2ZWwgPSAwLjk1LA0KICBtZXRob2RzID0gJ3dpbHNvbicNCikNCmBgYA0KDQpgYGB7ciBidWlsdGluX2FjfQ0KYmlub20uY29uZmludCgNCiAgeCA9IHRkX3RvdGFsLA0KICBuID0gbiwNCiAgY29uZi5sZXZlbCA9IDAuOTUsDQogIG1ldGhvZHMgPSAnYWMnDQopDQpgYGANCg0KDQpZb3UgY2FuIGFsc28gZ2l2ZSBpdCBhbGwgdGhyZWUgbWV0aG9kcyBpbiBvbmUgZnVuY3Rpb24gYnkgZ2l2aW5nIGBtZXRob2RzYCBhIHZlY3RvcjoNCg0KYGBge3IgYnVpbHRpbl9hbGwzfQ0KYmlub20uY29uZmludCgNCiAgeCA9IHRkX3RvdGFsLA0KICBuID0gbiwNCiAgY29uZi5sZXZlbCA9IDAuOTUsDQogIG1ldGhvZHMgPSBjKCdhc3ltcHRvdGljJywgJ3dpbHNvbicsICdhYycpDQopDQpgYGANCg0KDQoNCg0KDQoNCg==