library(tidyverse); library(gt); library(epitools)
# Reading in the nfl drives data
drives <- read.csv("https://raw.githubusercontent.com/Shammalamala/STA4504/refs/heads/main/data/ch2/nfl%20drives.csv")
Looking at the way drives can begin and end:
unique(drives$drive_start)
## [1] "Fumble" "Interception" "Kickoff" "Punt"
unique(drives$drive_end)
## [1] "Field Goal" "Punt" "Touchdown" "Turnover"
Motivating Question: Is a team more likely to score
a touchdown after a turnover compared to a punt or kickoff?
Relative risk is often used for two binary variables, so let’s
convert our data into two binary variables:
drive_start: turnover - Interception/Fumble vs kick -
Kickoff/Punt
drive_end: TD - Touchdown vs noTD - Field
Goal/Turnover/Punt
drives2 <-
drives |>
mutate(
drive_start = if_else(drive_start %in% c("Interception", "Fumble"),
true = "turnover",
false = "kick") |>
factor(),
drive_end = if_else(drive_end == "Touchdown",
true = "TD",
false = "noTD") |>
factor()
)
Next, let’s display the results in a two-way table using
xtabs()
# Displaying a two-way table using xtabs()
drive_freq <-
xtabs(formula = ~ drive_start + drive_end, data = drives2)
# The addmargins() function will add the margins to the table
drive_freq |>
addmargins()
## drive_end
## drive_start noTD TD Sum
## kick 4055 1200 5255
## turnover 571 239 810
## Sum 4626 1439 6065
And converting the table from counts to conditional proportions using
prop.table(margin = "drive_start")
drive_freq |>
prop.table(margin = "drive_start") |>
round(digits = 3)
## drive_end
## drive_start noTD TD
## kick 0.772 0.228
## turnover 0.705 0.295
Let’s create a bar chart to compare the probability of a touchdown
between the two groups:
drive_freq |>
# Calculate the conditional proportions
prop.table(margin = "drive_start") |>
# Convert the table to a data frame to be used by ggplot()
data.frame() |>
# Rename Freq to prop
rename(prop = Freq) |>
ggplot(
mapping = aes(
x = drive_start,
fill = drive_end,
y = prop
)
) +
geom_col(width = 0.5) +
labs(
y = "Proportion",
x = "How Drive Began",
fill = "Drive \nResult"
) +
theme_test() +
scale_y_continuous(expand = c(0, 0, 0, 0.05)) +
scale_fill_manual(
labels = c("No Touchdown", "Touchdown"),
values = c("darkorange", "steelblue")
)

There are some differences, but it isn’t a very noticeable
difference.
Odds: \(\frac{\pi}{1-\pi}\)
The odds are another way of measuring how frequently events occur,
but instead they compare the probability of the event happening vs the
event not happening using a ratio:
\[\textrm{odds} =
\frac{\pi}{1-\pi}\]
If we ignore how the drive began, the odds a drive ends in a
touchdown is:
\[\textrm{odds of a touchdown} =
\frac{p}{1-p} = \frac{1439}{4626} = 0.31\]
which means that for every 1 drive that ends in a touchdown, about 3
drives do not
One benefit of calculating the odds is if we want to estimate it for
a binary variable, we place the sample count of success on the top and
the sample count of failures on the bottom of the fraction.
Like we did with the probabilities (or “risks”), we can use the odds
to test if two binary variables are associated using the odds
ratio
Odds Ratio
The odds ratio is similar to the risk ratio, in that it is a ratio of
the odds of success for two groups of a binary variable (group 1 vs
group 2):
\[\theta_{XY} =
\frac{\textrm{odds}_1}{\textrm{odds}_2}\]
The odds a drive ends on a touchdown if the drive starts from a
turnover is:
\[\textrm{odds}_1 = \frac{239}{571} =
0.419\]
The odds a drive ends on a touchdown if the drive starts from a
kickoff or punt is:
\[\textrm{odds}_2 = \frac{1200}{4055} =
0.296\]
Then our estimated odds ratio is:
\[\hat{\theta}_{Y|X} =
\frac{\textrm{odds}_1}{\textrm{odds}_2} = \frac{0.419}{0.296} =
1.414\]
We can interpret the results as
“The odds a drive ends with a touchdown is 1.414
times higher if the drive started from a turnover than from a kickoff or
punt”
While both odds are below 1, the odds a drive ends in a touchdown if
it starts from a turnover is about 40% higher than if it started after a
kick.
Odds ratio: Direct Estimation
We can estimate the odds ratio a little more directly using our
sample counts. If the counts are in a 2x2 table:
| |
Y = 1 |
Y = 2 |
| X = 1 |
n11 |
n12 |
| X = 2 |
n21 |
n22 |
Then our estimated odds ratio is
\[\hat{\theta}_{Y|X} = \frac{p_{1}
(1-p_{2})}{p_{2} (1-p_{1})} = \frac{n_{11} \times n_{22}}{n_{12} \times
n_{21}}\]
The odds ratio for our example is:
\[\hat{\theta}_{Y|X} = \frac{239 \times
4055}{571 * 1200} = 1.414\]
Inference with the Odds Ratio:
Similar to the risk ratio (or relative risk), we work with the log
odds ratio \(\ln \hat{\theta}_{Y|X}\)
instead of the odds ratio directly.
If all of the observed counts are at least 10:
\[\ln \hat{\theta}_{Y|X} \sim N(\ln
\theta_{Y|X}, SE)\]
and the standard error is:
\[SE(\ln \hat{\theta}_{Y|X}) =
\sqrt{\frac{1}{n_{11}} + \frac{1}{n_{12}} + \frac{1}{n_{21}} +
\frac{1}{n_{22}}}\]
Hypothesis Test
Our null hypothesis is:
\[H_0: \theta_{Y|X} = 1 \rightarrow H_0:
\ln \theta_{Y|X} = 0\]
and our test statistic is:
\[z = \frac{\ln
\hat{\theta}_{Y|X}}{\sqrt{\frac{1}{n_{11}} + \frac{1}{n_{12}} +
\frac{1}{n_{21}} + \frac{1}{n_{22}}}}\]
We can conduct a hypothesis test for the odds ratio using
oddsratio() in the epitools package.
It wants a 2x2 table with:
- column 1 = failure and column 2 = success
- row 1 = reference group and row 2 = comparison group
- reference = kick
- comparison = turnover
which is the exact order of our table!
The arguments for oddsratio() are:
x = the 2x2 table described above
method = "wald" to use the Normal model to find the
p-value and critical value
conf.level = 0.95 the confidence level of a desired
hypothesis test
rev = "neither" will reverse the order of the “rows”,
“columns”, or “both” of the table from x =
td_OR <-
oddsratio(x = drive_freq, method = "wald")
# The table with margins:
td_OR$data
## drive_end
## drive_start noTD TD Total
## kick 4055 1200 5255
## turnover 571 239 810
## Total 4626 1439 6065
# The estimated odds ratio and confidence interval
data.frame(td_OR$measure)
## estimate lower upper
## kick 1.000000 NA NA
## turnover 1.414397 1.200264 1.666733
# And the p-value (chi.squared)
data.frame(td_OR$p.value)
## midp.exact fisher.exact chi.square
## kick NA NA NA
## turnover 4.724261e-05 5.233613e-05 3.264256e-05
Order of Conditioning
A big advantage of using the odds ratio over the relative risk is the
order of the condition (\(Y|X\) vs
\(X|Y\)) won’t change the result
\[\theta_{Y|X} = \theta_{X|Y} =
\theta_{XY}\]
For instance, if we swap the order of the rows and columns with
t() (for transpose), the results for the odds ratio won’t
change, but the relative risk will!
# Calculate the OR swapping the rows and columns (swapping X and Y roles)
oddsratio(x = drive_freq |> t(),
method = "wald") |>
pluck('measure') |>
data.frame() |>
round(3)
## estimate lower upper
## noTD 1.000 NA NA
## TD 1.414 1.2 1.667
Note that our estimate and confidence interval remain exactly the
same!
The same won’t be true for the relative risk:
# Calculating the relative risk for Y|X
riskratio(x = drive_freq,
method = "wald") |>
pluck('measure') |>
data.frame() |>
round(3)
## estimate lower upper
## kick 1.000 NA NA
## turnover 1.292 1.149 1.453
# Calculating the relative risk for X|Y
riskratio(x = drive_freq |> t(),
method = "wald") |>
pluck('measure') |>
data.frame() |>
round(3)
## estimate lower upper
## noTD 1.000 NA NA
## TD 1.346 1.171 1.546
Who cares if the odds ratio is symmetric (can reverse X and Y and get
the same result) while the relative risk is not?
Based on how the data are collected, we can’t always estimate the
conditional proportions needed for the relative risk.
For retrospective studies, we can’t estimate \(P(Y=j|X = i) = \pi_{i|j}\) since the number
of cases in each group of \(Y\) is not
random.
However, the counts for \(X\) within
each group of \(Y\) is random in
retrospective studies, which means we can estimate \(P(X = i|Y = j) = \pi_{i|j}\). And as long
as we can estimate one conditional proportion, we can use the odds ratio
to check if \(X\) and \(Y\) are independent and calculate
confidence intervals for \(\theta_{Y|X}\) even if we can estimate
\(\pi_{j|i}\) directly!
LS0tDQp0aXRsZTogIlR3byBCaW5hcnkgVmFyaWFibGVzIC0gT2RkcyBSYXRpbyINCmF1dGhvcjogIkNoYXB0ZXIgMiINCmRhdGU6ICJTVEEgNDUwNCINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBmaWdfd2lkdGg6IDEwDQogICAgZmlnX2hlaWdodDogNg0KICAgIGZpZ19jYXB0aW9uOiB0cnVlDQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgbnVtYmVyX3NlY3Rpb25zOiBmYWxzZQ0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICBzbW9vdGhfc2Nyb2xsOiB0cnVlDQogICAgdGhlbWU6IGx1bWVuDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgZmlnLmFsaWduID0gImNlbnRlciIpDQpgYGANCg0KDQpgYGB7ciBwYWNrYWdlc19kYXRhLCBtZXNzYWdlID0gRiwgd2FybmluZyA9IEZ9DQpsaWJyYXJ5KHRpZHl2ZXJzZSk7IGxpYnJhcnkoZ3QpOyBsaWJyYXJ5KGVwaXRvb2xzKQ0KDQojIFJlYWRpbmcgaW4gdGhlIG5mbCBkcml2ZXMgZGF0YQ0KZHJpdmVzIDwtIHJlYWQuY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vU2hhbW1hbGFtYWxhL1NUQTQ1MDQvcmVmcy9oZWFkcy9tYWluL2RhdGEvY2gyL25mbCUyMGRyaXZlcy5jc3YiKSANCmBgYA0KDQoNCkxvb2tpbmcgYXQgdGhlIHdheSBkcml2ZXMgY2FuIGJlZ2luIGFuZCBlbmQ6DQoNCg0KYGBge3IgZHJpdmVfc3RhcnRfZW5kfQ0KdW5pcXVlKGRyaXZlcyRkcml2ZV9zdGFydCkNCnVuaXF1ZShkcml2ZXMkZHJpdmVfZW5kKQ0KDQpgYGANCg0KKipNb3RpdmF0aW5nIFF1ZXN0aW9uOioqIElzIGEgdGVhbSBtb3JlIGxpa2VseSB0byBzY29yZSBhIHRvdWNoZG93biBhZnRlciBhIHR1cm5vdmVyIGNvbXBhcmVkIHRvIGEgcHVudCBvciBraWNrb2ZmPw0KDQpSZWxhdGl2ZSByaXNrIGlzIG9mdGVuIHVzZWQgZm9yIHR3byBiaW5hcnkgdmFyaWFibGVzLCBzbyBsZXQncyBjb252ZXJ0IG91ciBkYXRhIGludG8gdHdvIGJpbmFyeSB2YXJpYWJsZXM6DQoNCi0gYGRyaXZlX3N0YXJ0YDogdHVybm92ZXIgLSBJbnRlcmNlcHRpb24vRnVtYmxlIHZzIGtpY2sgLSBLaWNrb2ZmL1B1bnQNCi0gYGRyaXZlX2VuZGA6IFREIC0gVG91Y2hkb3duIHZzIG5vVEQgLSBGaWVsZCBHb2FsL1R1cm5vdmVyL1B1bnQgDQoNCmBgYHtyIGRyaXZlczJ9DQpkcml2ZXMyIDwtIA0KICBkcml2ZXMgfD4gDQogIG11dGF0ZSgNCiAgICBkcml2ZV9zdGFydCA9IGlmX2Vsc2UoZHJpdmVfc3RhcnQgJWluJSBjKCJJbnRlcmNlcHRpb24iLCAiRnVtYmxlIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgIHRydWUgPSAidHVybm92ZXIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBmYWxzZSA9ICJraWNrIikgfD4gDQogICAgICAgICAgICAgICAgICBmYWN0b3IoKSwNCiAgICAgICAgIA0KICAgIGRyaXZlX2VuZCA9IGlmX2Vsc2UoZHJpdmVfZW5kID09ICJUb3VjaGRvd24iLA0KICAgICAgICAgICAgICAgICAgICAgICAgdHJ1ZSA9ICJURCIsDQogICAgICAgICAgICAgICAgICAgICAgICBmYWxzZSA9ICJub1REIikgfD4gDQogICAgICAgICAgICAgICAgZmFjdG9yKCkNCiAgKQ0KYGBgDQoNCk5leHQsIGxldCdzIGRpc3BsYXkgdGhlIHJlc3VsdHMgaW4gYSB0d28td2F5IHRhYmxlIHVzaW5nIGB4dGFicygpYCANCg0KYGBge3IgZHJpdmVfZnJlcX0NCiMgRGlzcGxheWluZyBhIHR3by13YXkgdGFibGUgdXNpbmcgeHRhYnMoKQ0KZHJpdmVfZnJlcSA8LSANCiAgeHRhYnMoZm9ybXVsYSA9IH4gZHJpdmVfc3RhcnQgKyBkcml2ZV9lbmQsIGRhdGEgPSBkcml2ZXMyKQ0KDQojIFRoZSBhZGRtYXJnaW5zKCkgZnVuY3Rpb24gd2lsbCBhZGQgdGhlIG1hcmdpbnMgdG8gdGhlIHRhYmxlDQpkcml2ZV9mcmVxIHw+IA0KICBhZGRtYXJnaW5zKCkgDQpgYGANCg0KDQpBbmQgY29udmVydGluZyB0aGUgdGFibGUgZnJvbSBjb3VudHMgdG8gY29uZGl0aW9uYWwgcHJvcG9ydGlvbnMgdXNpbmcgYHByb3AudGFibGUobWFyZ2luID0gImRyaXZlX3N0YXJ0IilgDQoNCmBgYHtyIGRyaXZlX3Byb3B9DQpkcml2ZV9mcmVxIHw+IA0KICBwcm9wLnRhYmxlKG1hcmdpbiA9ICJkcml2ZV9zdGFydCIpIHw+IA0KICANCiAgcm91bmQoZGlnaXRzID0gMykNCg0KYGBgDQoNCkxldCdzIGNyZWF0ZSBhIGJhciBjaGFydCB0byBjb21wYXJlIHRoZSBwcm9iYWJpbGl0eSBvZiBhIHRvdWNoZG93biBiZXR3ZWVuIHRoZSB0d28gZ3JvdXBzOg0KDQpgYGB7ciBiYXJfY2hhcnR9DQpkcml2ZV9mcmVxIHw+IA0KICAjIENhbGN1bGF0ZSB0aGUgY29uZGl0aW9uYWwgcHJvcG9ydGlvbnMNCiAgcHJvcC50YWJsZShtYXJnaW4gPSAiZHJpdmVfc3RhcnQiKSB8PiANCiAgIyBDb252ZXJ0IHRoZSB0YWJsZSB0byBhIGRhdGEgZnJhbWUgdG8gYmUgdXNlZCBieSBnZ3Bsb3QoKQ0KICBkYXRhLmZyYW1lKCkgfD4gDQogICMgUmVuYW1lIEZyZXEgdG8gcHJvcA0KICByZW5hbWUocHJvcCA9IEZyZXEpIHw+IA0KICANCiAgZ2dwbG90KA0KICAgIG1hcHBpbmcgPSBhZXMoDQogICAgICB4ID0gZHJpdmVfc3RhcnQsDQogICAgICBmaWxsID0gZHJpdmVfZW5kLA0KICAgICAgeSA9IHByb3ANCiAgICApDQogICkgKyANCiAgDQogIGdlb21fY29sKHdpZHRoID0gMC41KSArIA0KICANCiAgbGFicygNCiAgICB5ID0gIlByb3BvcnRpb24iLA0KICAgIHggPSAiSG93IERyaXZlIEJlZ2FuIiwNCiAgICBmaWxsID0gIkRyaXZlIFxuUmVzdWx0Ig0KICApICsgDQogIA0KICB0aGVtZV90ZXN0KCkgKyANCiAgDQogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsIDAsIDAsIDAuMDUpKSArIA0KICANCiAgc2NhbGVfZmlsbF9tYW51YWwoDQogICAgbGFiZWxzID0gYygiTm8gVG91Y2hkb3duIiwgIlRvdWNoZG93biIpLA0KICAgIHZhbHVlcyA9IGMoImRhcmtvcmFuZ2UiLCAic3RlZWxibHVlIikNCiAgKQ0KDQoNCmBgYA0KDQpUaGVyZSBhcmUgc29tZSBkaWZmZXJlbmNlcywgYnV0IGl0IGlzbid0IGEgdmVyeSBub3RpY2VhYmxlIGRpZmZlcmVuY2UuIA0KDQoNCg0KDQojIyBPZGRzOiAkXGZyYWN7XHBpfXsxLVxwaX0kDQoNClRoZSBvZGRzIGFyZSBhbm90aGVyIHdheSBvZiBtZWFzdXJpbmcgaG93IGZyZXF1ZW50bHkgZXZlbnRzIG9jY3VyLCBidXQgaW5zdGVhZCB0aGV5IGNvbXBhcmUgdGhlIHByb2JhYmlsaXR5IG9mIHRoZSBldmVudCBoYXBwZW5pbmcgdnMgdGhlIGV2ZW50IG5vdCBoYXBwZW5pbmcgdXNpbmcgYSByYXRpbzoNCg0KJCRcdGV4dHJte29kZHN9ID0gXGZyYWN7XHBpfXsxLVxwaX0kJA0KDQpJZiB3ZSBpZ25vcmUgaG93IHRoZSBkcml2ZSBiZWdhbiwgdGhlIG9kZHMgYSBkcml2ZSBlbmRzIGluIGEgdG91Y2hkb3duIGlzOg0KDQokJFx0ZXh0cm17b2RkcyBvZiBhIHRvdWNoZG93bn0gPSBcZnJhY3twfXsxLXB9ID0gXGZyYWN7MTQzOX17NDYyNn0gPSAwLjMxJCQNCg0Kd2hpY2ggbWVhbnMgdGhhdCBmb3IgZXZlcnkgMSBkcml2ZSB0aGF0IGVuZHMgaW4gYSB0b3VjaGRvd24sIGFib3V0IDMgZHJpdmVzIGRvIG5vdA0KDQpPbmUgYmVuZWZpdCBvZiBjYWxjdWxhdGluZyB0aGUgb2RkcyBpcyBpZiB3ZSB3YW50IHRvIGVzdGltYXRlIGl0IGZvciBhIGJpbmFyeSB2YXJpYWJsZSwgd2UgcGxhY2UgdGhlIHNhbXBsZSBjb3VudCBvZiBzdWNjZXNzIG9uIHRoZSB0b3AgYW5kIHRoZSBzYW1wbGUgY291bnQgb2YgZmFpbHVyZXMgb24gdGhlIGJvdHRvbSBvZiB0aGUgZnJhY3Rpb24uDQoNCg0KTGlrZSB3ZSBkaWQgd2l0aCB0aGUgcHJvYmFiaWxpdGllcyAob3IgInJpc2tzIiksIHdlIGNhbiB1c2UgdGhlIG9kZHMgdG8gdGVzdCBpZiB0d28gYmluYXJ5IHZhcmlhYmxlcyBhcmUgYXNzb2NpYXRlZCB1c2luZyB0aGUgKipvZGRzIHJhdGlvKioNCg0KDQoNCg0KIyMgT2RkcyBSYXRpbw0KDQpUaGUgb2RkcyByYXRpbyBpcyBzaW1pbGFyIHRvIHRoZSByaXNrIHJhdGlvLCBpbiB0aGF0IGl0IGlzIGEgcmF0aW8gb2YgdGhlIG9kZHMgb2Ygc3VjY2VzcyBmb3IgdHdvIGdyb3VwcyBvZiBhIGJpbmFyeSB2YXJpYWJsZSAoZ3JvdXAgMSB2cyBncm91cCAyKToNCg0KJCRcdGhldGFfe1hZfSA9IFxmcmFje1x0ZXh0cm17b2Rkc31fMX17XHRleHRybXtvZGRzfV8yfSQkDQoNClRoZSBvZGRzIGEgZHJpdmUgZW5kcyBvbiBhIHRvdWNoZG93biBpZiB0aGUgZHJpdmUgc3RhcnRzIGZyb20gYSB0dXJub3ZlciBpczoNCg0KJCRcdGV4dHJte29kZHN9XzEgPSBcZnJhY3syMzl9ezU3MX0gPSAwLjQxOSQkDQoNClRoZSBvZGRzIGEgZHJpdmUgZW5kcyBvbiBhIHRvdWNoZG93biBpZiB0aGUgZHJpdmUgc3RhcnRzIGZyb20gYSBraWNrb2ZmIG9yIHB1bnQgaXM6DQoNCiQkXHRleHRybXtvZGRzfV8yID0gXGZyYWN7MTIwMH17NDA1NX0gPSAwLjI5NiQkDQoNClRoZW4gb3VyIGVzdGltYXRlZCBvZGRzIHJhdGlvIGlzOg0KDQokJFxoYXR7XHRoZXRhfV97WXxYfSA9IFxmcmFje1x0ZXh0cm17b2Rkc31fMX17XHRleHRybXtvZGRzfV8yfSA9IFxmcmFjezAuNDE5fXswLjI5Nn0gPSAxLjQxNCQkDQoNCldlIGNhbiBpbnRlcnByZXQgdGhlIHJlc3VsdHMgYXMgDQoNCiJUaGUgKipvZGRzKiogYSBkcml2ZSBlbmRzIHdpdGggYSB0b3VjaGRvd24gaXMgMS40MTQgdGltZXMgaGlnaGVyIGlmIHRoZSBkcml2ZSBzdGFydGVkIGZyb20gYSB0dXJub3ZlciB0aGFuIGZyb20gYSBraWNrb2ZmIG9yIHB1bnQiDQoNCg0KV2hpbGUgYm90aCBvZGRzIGFyZSBiZWxvdyAxLCB0aGUgb2RkcyBhIGRyaXZlIGVuZHMgaW4gYSB0b3VjaGRvd24gaWYgaXQgc3RhcnRzIGZyb20gYSB0dXJub3ZlciBpcyBhYm91dCA0MCUgaGlnaGVyIHRoYW4gaWYgaXQgc3RhcnRlZCBhZnRlciBhIGtpY2suDQoNCg0KIyMjIE9kZHMgcmF0aW86IERpcmVjdCBFc3RpbWF0aW9uDQoNCldlIGNhbiBlc3RpbWF0ZSB0aGUgb2RkcyByYXRpbyBhIGxpdHRsZSBtb3JlIGRpcmVjdGx5IHVzaW5nIG91ciBzYW1wbGUgY291bnRzLiBJZiB0aGUgY291bnRzIGFyZSBpbiBhIDJ4MiB0YWJsZToNCg0KYGBge3IsIGVjaG8gPSBGfQ0KdHJpYmJsZSgNCiAgfiBgIGAsIH4gYFkgPSAxYCwgfiAnWSA9IDInLA0KICAiWCA9IDEiLCAibjExIiwgIm4xMiIsDQogICJYID0gMiIsICJuMjEiLCAibjIyIg0KKSB8PiANCiAgZ3QoKSB8PiANCiAgY29sc19hbGlnbihhbGlnbiA9ICJjZW50ZXIiKQ0KYGBgDQoNCg0KDQoNCg0KDQpUaGVuIG91ciBlc3RpbWF0ZWQgb2RkcyByYXRpbyBpcyANCg0KJCRcaGF0e1x0aGV0YX1fe1l8WH0gPSBcZnJhY3twX3sxfSAoMS1wX3syfSl9e3BfezJ9ICgxLXBfezF9KX0gPSBcZnJhY3tuX3sxMX0gXHRpbWVzIG5fezIyfX17bl97MTJ9IFx0aW1lcyBuX3syMX19JCQNCg0KDQoNClRoZSBvZGRzIHJhdGlvIGZvciBvdXIgZXhhbXBsZSBpczoNCg0KJCRcaGF0e1x0aGV0YX1fe1l8WH0gPSBcZnJhY3syMzkgXHRpbWVzIDQwNTV9ezU3MSAqIDEyMDB9ID0gMS40MTQkJA0KDQoNCg0KDQojIyBJbmZlcmVuY2Ugd2l0aCB0aGUgT2RkcyBSYXRpbzoNCg0KU2ltaWxhciB0byB0aGUgcmlzayByYXRpbyAob3IgcmVsYXRpdmUgcmlzayksIHdlIHdvcmsgd2l0aCB0aGUgbG9nIG9kZHMgcmF0aW8gJFxsbiBcaGF0e1x0aGV0YX1fe1l8WH0kIGluc3RlYWQgb2YgdGhlIG9kZHMgcmF0aW8gZGlyZWN0bHkuDQoNCklmIGFsbCBvZiB0aGUgb2JzZXJ2ZWQgY291bnRzIGFyZSBhdCBsZWFzdCAxMDoNCg0KJCRcbG4gXGhhdHtcdGhldGF9X3tZfFh9IFxzaW0gTihcbG4gXHRoZXRhX3tZfFh9LCBTRSkkJA0KDQphbmQgdGhlIHN0YW5kYXJkIGVycm9yIGlzOg0KDQokJFNFKFxsbiBcaGF0e1x0aGV0YX1fe1l8WH0pID0gXHNxcnR7XGZyYWN7MX17bl97MTF9fSArIFxmcmFjezF9e25fezEyfX0gKyBcZnJhY3sxfXtuX3syMX19ICsgXGZyYWN7MX17bl97MjJ9fX0kJA0KDQoNCiMjIyBIeXBvdGhlc2lzIFRlc3QNCg0KT3VyIG51bGwgaHlwb3RoZXNpcyBpczoNCg0KJCRIXzA6IFx0aGV0YV97WXxYfSA9IDEgIFxyaWdodGFycm93IEhfMDogXGxuIFx0aGV0YV97WXxYfSA9IDAkJA0KDQphbmQgb3VyIHRlc3Qgc3RhdGlzdGljIGlzOg0KDQokJHogPSBcZnJhY3tcbG4gXGhhdHtcdGhldGF9X3tZfFh9fXtcc3FydHtcZnJhY3sxfXtuX3sxMX19ICsgXGZyYWN7MX17bl97MTJ9fSArIFxmcmFjezF9e25fezIxfX0gKyBcZnJhY3sxfXtuX3syMn19fX0kJA0KDQoNCldlIGNhbiBjb25kdWN0IGEgaHlwb3RoZXNpcyB0ZXN0IGZvciB0aGUgb2RkcyByYXRpbyB1c2luZyBgb2Rkc3JhdGlvKClgIGluIHRoZSBgZXBpdG9vbHNgIHBhY2thZ2UuIA0KDQpJdCB3YW50cyBhIDJ4MiB0YWJsZSB3aXRoOiANCg0KLSBjb2x1bW4gMSA9IGZhaWx1cmUgYW5kIGNvbHVtbiAyID0gc3VjY2VzcyAgDQogIC0gZmFpbCA9IG5vVEQgDQogIC0gc3VjY2VzcyA9IFREDQoNCi0gcm93IDEgPSByZWZlcmVuY2UgZ3JvdXAgYW5kIHJvdyAyID0gY29tcGFyaXNvbiBncm91cCANCiAgLSByZWZlcmVuY2UgPSBraWNrIA0KICAtIGNvbXBhcmlzb24gPSB0dXJub3Zlcg0KDQp3aGljaCBpcyB0aGUgZXhhY3Qgb3JkZXIgb2Ygb3VyIHRhYmxlIQ0KDQoNClRoZSBhcmd1bWVudHMgZm9yIGBvZGRzcmF0aW8oKWAgYXJlOg0KDQotIGB4ID0gYCB0aGUgMngyIHRhYmxlIGRlc2NyaWJlZCBhYm92ZQ0KLSBgbWV0aG9kID0gIndhbGQiYCB0byB1c2UgdGhlIE5vcm1hbCBtb2RlbCB0byBmaW5kIHRoZSBwLXZhbHVlIGFuZCBjcml0aWNhbCB2YWx1ZQ0KLSBgY29uZi5sZXZlbCA9IDAuOTVgIHRoZSBjb25maWRlbmNlIGxldmVsIG9mIGEgZGVzaXJlZCBoeXBvdGhlc2lzIHRlc3QNCi0gYHJldiA9ICJuZWl0aGVyImAgd2lsbCByZXZlcnNlIHRoZSBvcmRlciBvZiB0aGUgInJvd3MiLCAiY29sdW1ucyIsIG9yICJib3RoIiBvZiB0aGUgdGFibGUgZnJvbSBgeCA9IGANCg0KYGBge3Igb2Rkc3JhdGlvfQ0KdGRfT1IgPC0gDQogIG9kZHNyYXRpbyh4ID0gZHJpdmVfZnJlcSwgbWV0aG9kID0gIndhbGQiKQ0KDQojIFRoZSB0YWJsZSB3aXRoIG1hcmdpbnM6DQp0ZF9PUiRkYXRhDQoNCiMgVGhlIGVzdGltYXRlZCBvZGRzIHJhdGlvIGFuZCBjb25maWRlbmNlIGludGVydmFsDQpkYXRhLmZyYW1lKHRkX09SJG1lYXN1cmUpDQoNCiMgQW5kIHRoZSBwLXZhbHVlIChjaGkuc3F1YXJlZCkNCmRhdGEuZnJhbWUodGRfT1IkcC52YWx1ZSkNCg0KYGBgDQoNCg0KIyMjIE9yZGVyIG9mIENvbmRpdGlvbmluZw0KDQpBIGJpZyBhZHZhbnRhZ2Ugb2YgdXNpbmcgdGhlIG9kZHMgcmF0aW8gb3ZlciB0aGUgcmVsYXRpdmUgcmlzayBpcyB0aGUgb3JkZXIgb2YgdGhlIGNvbmRpdGlvbiAoJFl8WCQgdnMgJFh8WSQpIHdvbid0IGNoYW5nZSB0aGUgcmVzdWx0DQoNCiQkXHRoZXRhX3tZfFh9ID0gXHRoZXRhX3tYfFl9ID0gXHRoZXRhX3tYWX0kJA0KDQoNCkZvciBpbnN0YW5jZSwgaWYgd2Ugc3dhcCB0aGUgb3JkZXIgb2YgdGhlIHJvd3MgYW5kIGNvbHVtbnMgd2l0aCBgdCgpYCAoZm9yIHRyYW5zcG9zZSksIHRoZSByZXN1bHRzIGZvciB0aGUgb2RkcyByYXRpbyB3b24ndCBjaGFuZ2UsIGJ1dCB0aGUgcmVsYXRpdmUgcmlzayB3aWxsIQ0KDQpgYGB7ciBPUl9YWX0NCiMgQ2FsY3VsYXRlIHRoZSBPUiBzd2FwcGluZyB0aGUgcm93cyBhbmQgY29sdW1ucyAoc3dhcHBpbmcgWCBhbmQgWSByb2xlcykNCm9kZHNyYXRpbyh4ID0gZHJpdmVfZnJlcSB8PiB0KCksIA0KICAgICAgICAgIG1ldGhvZCA9ICJ3YWxkIikgfD4gDQogIHBsdWNrKCdtZWFzdXJlJykgfD4gDQogIGRhdGEuZnJhbWUoKSB8PiANCiAgcm91bmQoMykNCg0KYGBgDQoNCk5vdGUgdGhhdCBvdXIgZXN0aW1hdGUgYW5kIGNvbmZpZGVuY2UgaW50ZXJ2YWwgcmVtYWluIGV4YWN0bHkgdGhlIHNhbWUhDQoNCg0KVGhlIHNhbWUgd29uJ3QgYmUgdHJ1ZSBmb3IgdGhlIHJlbGF0aXZlIHJpc2s6DQoNCmBgYHtyIFJSX1hZfQ0KIyBDYWxjdWxhdGluZyB0aGUgcmVsYXRpdmUgcmlzayBmb3IgWXxYDQpyaXNrcmF0aW8oeCA9IGRyaXZlX2ZyZXEsIA0KICAgICAgICAgIG1ldGhvZCA9ICJ3YWxkIikgfD4gDQogIHBsdWNrKCdtZWFzdXJlJykgfD4gDQogIGRhdGEuZnJhbWUoKSB8PiANCiAgcm91bmQoMykNCg0KIyBDYWxjdWxhdGluZyB0aGUgcmVsYXRpdmUgcmlzayBmb3IgWHxZDQpyaXNrcmF0aW8oeCA9IGRyaXZlX2ZyZXEgfD4gdCgpLCANCiAgICAgICAgICBtZXRob2QgPSAid2FsZCIpIHw+IA0KICBwbHVjaygnbWVhc3VyZScpIHw+IA0KICBkYXRhLmZyYW1lKCkgfD4gDQogIHJvdW5kKDMpDQoNCmBgYA0KDQpXaG8gY2FyZXMgaWYgdGhlIG9kZHMgcmF0aW8gaXMgc3ltbWV0cmljIChjYW4gcmV2ZXJzZSBYIGFuZCBZIGFuZCBnZXQgdGhlIHNhbWUgcmVzdWx0KSB3aGlsZSB0aGUgcmVsYXRpdmUgcmlzayBpcyBub3Q/DQoNCkJhc2VkIG9uIGhvdyB0aGUgZGF0YSBhcmUgY29sbGVjdGVkLCB3ZSBjYW4ndCBhbHdheXMgZXN0aW1hdGUgdGhlIGNvbmRpdGlvbmFsIHByb3BvcnRpb25zIG5lZWRlZCBmb3IgdGhlIHJlbGF0aXZlIHJpc2suIA0KDQpGb3IgcmV0cm9zcGVjdGl2ZSBzdHVkaWVzLCB3ZSBjYW4ndCBlc3RpbWF0ZSAkUChZPWp8WCA9IGkpID0gXHBpX3tpfGp9JCBzaW5jZSB0aGUgbnVtYmVyIG9mIGNhc2VzIGluIGVhY2ggZ3JvdXAgb2YgJFkkIGlzIG5vdCByYW5kb20uDQoNCkhvd2V2ZXIsIHRoZSBjb3VudHMgZm9yICRYJCB3aXRoaW4gZWFjaCBncm91cCBvZiAkWSQgaXMgcmFuZG9tIGluIHJldHJvc3BlY3RpdmUgc3R1ZGllcywgd2hpY2ggbWVhbnMgd2UgY2FuIGVzdGltYXRlICRQKFggPSBpfFkgPSBqKSA9IFxwaV97aXxqfSQuIEFuZCBhcyBsb25nIGFzIHdlIGNhbiBlc3RpbWF0ZSBvbmUgY29uZGl0aW9uYWwgcHJvcG9ydGlvbiwgd2UgY2FuIHVzZSB0aGUgb2RkcyByYXRpbyB0byBjaGVjayBpZiAkWCQgYW5kICRZJCBhcmUgaW5kZXBlbmRlbnQgYW5kIGNhbGN1bGF0ZSBjb25maWRlbmNlIGludGVydmFscyBmb3IgJFx0aGV0YV97WXxYfSQgZXZlbiBpZiB3ZSBjYW4gZXN0aW1hdGUgJFxwaV97anxpfSQgZGlyZWN0bHkhDQoNCg0KDQoNCg==