Learning Objectives


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

  1. Perform the Chi-Squared Test for Independence using simulation and theoretical methods.


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


Lizard Habitats


The exercise problems shown below was taken and slightly modified from your textbook OpenIntro: Introduction to Modern Statistics Section 18.4.

Consider the following problem statement.

In order to assess whether habitat conditions are related to the sunlight choices a lizard makes for resting, Western fence lizard (Sceloporus occidentalis) were observed across three different microhabitats. Adolph1990 Asbury2007

The lizard_habitat data used in this exercise can be found in the openintro R package.

  • The null and alternative Hypothesis \[H_0: \text{Sunlight and site are independent. Sunlight choices do not vary by site.}\] \[H_A: \text{Sunlight and site are dependent. Sunlight choices vary by site}\]

The data. Here, it counts the number of items in each category.

lizard_habitat %>% 
  count(site, sunlight)
## # A tibble: 9 × 3
##   site     sunlight     n
##   <fct>    <fct>    <int>
## 1 desert   sun         16
## 2 desert   partial     32
## 3 desert   shade       71
## 4 mountain sun         56
## 5 mountain partial     36
## 6 mountain shade       15
## 7 valley   sun         42
## 8 valley   partial     40
## 9 valley   shade       24

Here is the data printed as table.

lizard_habitat %>%
  count(site, sunlight) %>%
  pivot_wider(names_from = sunlight, values_from = n) %>%
  adorn_totals(where = c("row", "col")) %>%
  kbl(align = "lrrrr", booktabs = TRUE) %>%
  kable_styling(bootstrap_options = c("striped", "condensed"), 
                latex_options = "HOLD_position",
                full_width = FALSE) %>%
  add_header_above(c(" "=1, "sunlight" = 3, " " = 1)) %>%
  column_spec(1:5, width = "5em")
sunlight
site sun partial shade Total
desert 16 32 71 119
mountain 56 36 15 107
valley 42 40 24 106
Total 114 108 110 332

Throughout this demonstration, we will be using the infer package.

Calculating the observed \(\chi^2\) statistic.

Calculating the observed statistic,

Chisq_hat <- lizard_habitat %>%
  specify(formula = site ~ sunlight) %>% 
  hypothesize(null = "independence") %>%
  calculate(stat = "Chisq")

Chisq_hat
## Response: site (factor)
## Explanatory: sunlight (factor)
## Null Hypothesis: independence
## # A tibble: 1 × 1
##    stat
##   <dbl>
## 1  68.8

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

Chisq_hat <- lizard_habitat %>%
  observe(formula = site ~ sunlight, stat = "Chisq")

Chisq_hat
## Response: site (factor)
## Explanatory: sunlight (factor)
## # A tibble: 1 × 1
##    stat
##   <dbl>
## 1  68.8

Randomization/Permutation Method

Then, generating the null distribution using randomizations,

null_dist <- lizard_habitat %>%
  specify(site ~ sunlight) %>%
  hypothesize(null = "independence") %>% 
  generate(reps = 1000, type = "permute") %>% 
  calculate(stat = "Chisq")

Visualizing the observed statistic alongside the null distribution,

visualize(null_dist) +
  shade_p_value(obs_stat = Chisq_hat, direction = "greater")

Theoretical Method

Before using the theoretical method for the Chi-Squared test for independence, you need to check if the conditions are met.

Conditions: * Independent observations * Large samples: 5 expected counts in each cell

Finding the null distribution using theoretical methods using the assume() verb,

null_dist_theory <- lizard_habitat %>%
  specify(site ~ sunlight) %>%
  assume(distribution = "Chisq")

Visualizing the observed statistic using the theory-based null distribution,

visualize(null_dist_theory) +
  shade_p_value(obs_stat = Chisq_hat, direction = "greater")

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

visualize(null_dist, method = "both") +
  shade_p_value(obs_stat = Chisq_hat, direction = "greater")
## 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

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

null_dist %>%
  get_p_value(obs_stat = Chisq_hat, direction = "greater")
## 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 wrapper to carry out the test,

lizard_habitat %>%
  chisq_test(formula = site ~ sunlight)
## # A tibble: 1 × 3
##   statistic chisq_df  p_value
##       <dbl>    <int>    <dbl>
## 1      68.8        4 4.12e-14

Since the p-value is close to zero, we can reject the null and conclude that there is an association between sunlight choice and the site on which the lizards prefer to live their best lives.

Ngrams and Collocations

Sorry, I thought I have time for this but I am just busy busy lemon squishy. If you are interested in learning about statistical natural language processing using text data or data analysis in general, I recommend taking the Data Science class in Spring of 2022. The prerequisites for Data Science is Introduction to Probability and Statistics. If you are doing well in the Introduction to Probability and Statistics, then you should be okay in Data Science.


Mini Activities


Disaggregating Asian American tobacco use, data.

Understanding cultural differences in tobacco use across different demographic groups can lead to improved health care education and treatment. A recent study disaggregated tobacco use across Asian American ethnic groups including Asian-Indian (n = 4,373), Chinese (n = 4,736), and Filipino (n = 4,912), in comparison to non-Hispanic Whites (n = 275,025). The number of current smokers in each group was reported as Asian-Indian (n = 223), Chinese (n = 279), Filipino (n = 609), and non-Hispanic Whites (n = 50,880). Rao2021

Here is the data code.

asian_smoke <- tibble(
  ethnicity = c(
    rep("Asian-Indian", 4373),
    rep("Chinese", 4736),
    rep("Filipino", 4912)
  ),
  outcome = c(
    rep("smoke", 223), rep("don't smoke", 4150),
    rep("smoke", 279), rep("don't smoke", 4457),
    rep("smoke", 609), rep("don't smoke", 4303)
  )
)

Here is the data printed as table.

asian_smoke %>%
  count(ethnicity, outcome) %>%
  pivot_wider(names_from = outcome, values_from = n) %>%
  adorn_totals(where = c("row", "col")) %>%
  kbl(align = "lrrrr", booktabs = TRUE, format.args = list(big.mark = ",")) %>%
  kable_styling(bootstrap_options = c("striped", "condensed"), 
                latex_options = "HOLD_position",
                full_width = FALSE) %>%
  add_header_above(c(" " = 1, "Smoking" = 2, " " = 1)) %>%
  column_spec(1, width = "7em") %>%
  column_spec(2:4, width = "5em")
Smoking
ethnicity don’t smoke smoke Total
Asian-Indian 4,150 223 4,373
Chinese 4,457 279 4,736
Filipino 4,303 609 4,912
Total 12,910 1,111 14,021
  • In order to assess whether there is a difference in current smoking rates across three Asian American ethnic groups, the observed data is compared to the data that would be expected if there were no association between the variables.
  1. What is the null and alternative hypothesis?

  2. Carry out the randomization procedure and theoretical method for the Chi-Squared test for independence. Plot the resulting distributions.

  3. Compute the p-value using the randomization and theory.

  4. What is the conclusion?


LS0tCnRpdGxlOiAiNyAtIEluZmVyZW5jZSBmb3IgVHdvLVdheSBUYWJsZXMiCmF1dGhvcjogIkFsZXggSm9obiBRdWlqYW5vIgpkYXRlOiAiMTEvMTYvMjAyMSIKb3V0cHV0OiBvcGVuaW50cm86OmxhYl9yZXBvcnQKLS0tCgojIyAqKkxlYXJuaW5nIE9iamVjdGl2ZXMqKgoKPGJyPgoKVXBvbiBjb21wbGV0aW5nIHRvZGF5J3MgbGFiIGFjdGl2aXR5LCBzdHVkZW50cyBzaG91bGQgYmUgYWJsZSB0byBkbyB0aGUgZm9sbG93aW5nIHVzaW5nIFIgYW5kIFJTdHVkaW86CiAgCiAgMS4gUGVyZm9ybSB0aGUgQ2hpLVNxdWFyZWQgVGVzdCBmb3IgSW5kZXBlbmRlbmNlIHVzaW5nIHNpbXVsYXRpb24gYW5kIHRoZW9yZXRpY2FsIG1ldGhvZHMuCiAgCjxicj4KCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkob3BlbmludHJvKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGluZmVyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCmxpYnJhcnkoamFuaXRvcikKYGBgCgo8YnI+CgojIyAqKkxpemFyZCBIYWJpdGF0cyoqCgo8YnI+CgpUaGUgZXhlcmNpc2UgcHJvYmxlbXMgc2hvd24gYmVsb3cgd2FzIHRha2VuIGFuZCBzbGlnaHRseSBtb2RpZmllZCBmcm9tIHlvdXIgdGV4dGJvb2sgW09wZW5JbnRybzogSW50cm9kdWN0aW9uIHRvIE1vZGVybiBTdGF0aXN0aWNzIFNlY3Rpb24gMTguNF0oaHR0cHM6Ly9vcGVuaW50cm8taW1zLm5ldGxpZnkuYXBwL2luZmVyZW5jZS10YWJsZXMuaHRtbCNjaHAxOC1leGVyY2lzZXMpe3RhcmdldD0iX2JsYW5rIn0uCgpDb25zaWRlciB0aGUgZm9sbG93aW5nIHByb2JsZW0gc3RhdGVtZW50LgoKPiBJbiBvcmRlciB0byBhc3Nlc3Mgd2hldGhlciBoYWJpdGF0IGNvbmRpdGlvbnMgYXJlIHJlbGF0ZWQgdG8gdGhlIHN1bmxpZ2h0IGNob2ljZXMgYSBsaXphcmQgbWFrZXMgZm9yIHJlc3RpbmcsIFdlc3Rlcm4gZmVuY2UgbGl6YXJkICgqU2NlbG9wb3J1cyBvY2NpZGVudGFsaXMqKSB3ZXJlIG9ic2VydmVkIGFjcm9zcyB0aHJlZSBkaWZmZXJlbnQgbWljcm9oYWJpdGF0cy4gW0Fkb2xwaDE5OTBdKGh0dHBzOi8vZXNham91cm5hbHMub25saW5lbGlicmFyeS53aWxleS5jb20vZG9pL2Ficy8xMC4yMzA3LzE5NDAyNzE/Y2FzYV90b2tlbj1XT25tVDNvc2MtTUFBQUFBOkphOTgxWXVTRnJSbllYMWlhSk1EN1RUMnQ0V0ZFVTVzbTVORS1nbkpUSVNNUVRqUmRBNFhsWUpjWDQ1dUFFR2o0LWhmaldCWjVyTUMyYTApe3RhcmdldD0iX2JsYW5rIn0gW0FzYnVyeTIwMDddKGh0dHBzOi8vc2Nob2xhcnNoaXAuY2xhcmVtb250LmVkdS9jZ2kvdmlld2NvbnRlbnQuY2dpP3JlZmVyZXI9aHR0cHM6Ly9zY2hvbGFyLmdvb2dsZS5jb20vJmh0dHBzcmVkaXI9MSZhcnRpY2xlPTEyNzcmY29udGV4dD1obWNfZmFjX3B1Yil7dGFyZ2V0PSJfYmxhbmsifQoKVGhlIFtgbGl6YXJkX2hhYml0YXRgXShodHRwOi8vb3BlbmludHJvc3RhdC5naXRodWIuaW8vb3BlbmludHJvL3JlZmVyZW5jZS9saXphcmRfaGFiaXRhdC5odG1sKSBkYXRhIHVzZWQgaW4gdGhpcyBleGVyY2lzZSBjYW4gYmUgZm91bmQgaW4gdGhlIFsqKm9wZW5pbnRybyoqXShodHRwOi8vb3BlbmludHJvc3RhdC5naXRodWIuaW8vb3BlbmludHJvKSBSIHBhY2thZ2UuCgoqIFRoZSBudWxsIGFuZCBhbHRlcm5hdGl2ZSBIeXBvdGhlc2lzCiAgJCRIXzA6IFx0ZXh0e1N1bmxpZ2h0IGFuZCBzaXRlIGFyZSBpbmRlcGVuZGVudC4gU3VubGlnaHQgY2hvaWNlcyBkbyBub3QgdmFyeSBieSBzaXRlLn0kJAogICQkSF9BOiBcdGV4dHtTdW5saWdodCBhbmQgc2l0ZSBhcmUgZGVwZW5kZW50LiBTdW5saWdodCBjaG9pY2VzIHZhcnkgYnkgc2l0ZX0kJAoKVGhlIGRhdGEuIEhlcmUsIGl0IGNvdW50cyB0aGUgbnVtYmVyIG9mIGl0ZW1zIGluIGVhY2ggY2F0ZWdvcnkuCgpgYGB7cn0KbGl6YXJkX2hhYml0YXQgJT4lIAogIGNvdW50KHNpdGUsIHN1bmxpZ2h0KQpgYGAKCkhlcmUgaXMgdGhlIGRhdGEgcHJpbnRlZCBhcyB0YWJsZS4KCmBgYHtyIGVjaG89VFJVRX0KbGl6YXJkX2hhYml0YXQgJT4lCiAgY291bnQoc2l0ZSwgc3VubGlnaHQpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBzdW5saWdodCwgdmFsdWVzX2Zyb20gPSBuKSAlPiUKICBhZG9ybl90b3RhbHMod2hlcmUgPSBjKCJyb3ciLCAiY29sIikpICU+JQogIGtibChhbGlnbiA9ICJscnJyciIsIGJvb2t0YWJzID0gVFJVRSkgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiY29uZGVuc2VkIiksIAogICAgICAgICAgICAgICAgbGF0ZXhfb3B0aW9ucyA9ICJIT0xEX3Bvc2l0aW9uIiwKICAgICAgICAgICAgICAgIGZ1bGxfd2lkdGggPSBGQUxTRSkgJT4lCiAgYWRkX2hlYWRlcl9hYm92ZShjKCIgIj0xLCAic3VubGlnaHQiID0gMywgIiAiID0gMSkpICU+JQogIGNvbHVtbl9zcGVjKDE6NSwgd2lkdGggPSAiNWVtIikKYGBgCgpUaHJvdWdob3V0IHRoaXMgZGVtb25zdHJhdGlvbiwgd2Ugd2lsbCBiZSB1c2luZyB0aGUgYGluZmVyYCBwYWNrYWdlLgoKIyMjIENhbGN1bGF0aW5nIHRoZSBvYnNlcnZlZCAkXGNoaV4yJCBzdGF0aXN0aWMuCgpDYWxjdWxhdGluZyB0aGUgb2JzZXJ2ZWQgc3RhdGlzdGljLAoKYGBge3J9CkNoaXNxX2hhdCA8LSBsaXphcmRfaGFiaXRhdCAlPiUKICBzcGVjaWZ5KGZvcm11bGEgPSBzaXRlIH4gc3VubGlnaHQpICU+JSAKICBoeXBvdGhlc2l6ZShudWxsID0gImluZGVwZW5kZW5jZSIpICU+JQogIGNhbGN1bGF0ZShzdGF0ID0gIkNoaXNxIikKCkNoaXNxX2hhdApgYGAKCkFsdGVybmF0aXZlbHksIHVzaW5nIHRoZSBvYnNlcnZlKCkgd3JhcHBlciB0byBjYWxjdWxhdGUgdGhlIG9ic2VydmVkIHN0YXRpc3RpYywKCmBgYHtyfQpDaGlzcV9oYXQgPC0gbGl6YXJkX2hhYml0YXQgJT4lCiAgb2JzZXJ2ZShmb3JtdWxhID0gc2l0ZSB+IHN1bmxpZ2h0LCBzdGF0ID0gIkNoaXNxIikKCkNoaXNxX2hhdApgYGAKCiMjIyBSYW5kb21pemF0aW9uL1Blcm11dGF0aW9uIE1ldGhvZAoKVGhlbiwgZ2VuZXJhdGluZyB0aGUgbnVsbCBkaXN0cmlidXRpb24gdXNpbmcgcmFuZG9taXphdGlvbnMsCgpgYGB7cn0KbnVsbF9kaXN0IDwtIGxpemFyZF9oYWJpdGF0ICU+JQogIHNwZWNpZnkoc2l0ZSB+IHN1bmxpZ2h0KSAlPiUKICBoeXBvdGhlc2l6ZShudWxsID0gImluZGVwZW5kZW5jZSIpICU+JSAKICBnZW5lcmF0ZShyZXBzID0gMTAwMCwgdHlwZSA9ICJwZXJtdXRlIikgJT4lIAogIGNhbGN1bGF0ZShzdGF0ID0gIkNoaXNxIikKYGBgCgpWaXN1YWxpemluZyB0aGUgb2JzZXJ2ZWQgc3RhdGlzdGljIGFsb25nc2lkZSB0aGUgbnVsbCBkaXN0cmlidXRpb24sCgpgYGB7cn0KdmlzdWFsaXplKG51bGxfZGlzdCkgKwogIHNoYWRlX3BfdmFsdWUob2JzX3N0YXQgPSBDaGlzcV9oYXQsIGRpcmVjdGlvbiA9ICJncmVhdGVyIikKYGBgCgojIyMgVGhlb3JldGljYWwgTWV0aG9kCgpCZWZvcmUgdXNpbmcgdGhlIHRoZW9yZXRpY2FsIG1ldGhvZCBmb3IgdGhlIENoaS1TcXVhcmVkIHRlc3QgZm9yIGluZGVwZW5kZW5jZSwgeW91IG5lZWQgdG8gY2hlY2sgaWYgdGhlIGNvbmRpdGlvbnMgYXJlIG1ldC4KCkNvbmRpdGlvbnM6CiAgKiBJbmRlcGVuZGVudCBvYnNlcnZhdGlvbnMKICAqIExhcmdlIHNhbXBsZXM6IDUgZXhwZWN0ZWQgY291bnRzIGluIGVhY2ggY2VsbAoKRmluZGluZyB0aGUgbnVsbCBkaXN0cmlidXRpb24gdXNpbmcgdGhlb3JldGljYWwgbWV0aG9kcyB1c2luZyB0aGUgYGFzc3VtZSgpYCB2ZXJiLAoKYGBge3J9Cm51bGxfZGlzdF90aGVvcnkgPC0gbGl6YXJkX2hhYml0YXQgJT4lCiAgc3BlY2lmeShzaXRlIH4gc3VubGlnaHQpICU+JQogIGFzc3VtZShkaXN0cmlidXRpb24gPSAiQ2hpc3EiKQpgYGAKClZpc3VhbGl6aW5nIHRoZSBvYnNlcnZlZCBzdGF0aXN0aWMgdXNpbmcgdGhlIHRoZW9yeS1iYXNlZCBudWxsIGRpc3RyaWJ1dGlvbiwKCmBgYHtyfQp2aXN1YWxpemUobnVsbF9kaXN0X3RoZW9yeSkgKwogIHNoYWRlX3BfdmFsdWUob2JzX3N0YXQgPSBDaGlzcV9oYXQsIGRpcmVjdGlvbiA9ICJncmVhdGVyIikKYGBgCgpBbHRlcm5hdGl2ZWx5LCB2aXN1YWxpemluZyB0aGUgb2JzZXJ2ZWQgc3RhdGlzdGljIHVzaW5nIGJvdGggb2YgdGhlIG51bGwgZGlzdHJpYnV0aW9ucywKCmBgYHtyfQp2aXN1YWxpemUobnVsbF9kaXN0LCBtZXRob2QgPSAiYm90aCIpICsKICBzaGFkZV9wX3ZhbHVlKG9ic19zdGF0ID0gQ2hpc3FfaGF0LCBkaXJlY3Rpb24gPSAiZ3JlYXRlciIpCmBgYAoKTm90ZSB0aGF0IHRoZSBhYm92ZSBjb2RlIG1ha2VzIHVzZSBvZiB0aGUgcmFuZG9taXphdGlvbi1iYXNlZCBudWxsIGRpc3RyaWJ1dGlvbi4KCiMjIyBDYWxjdWxhdGluZyB0aGUgcC12YWx1ZQoKQ2FsY3VsYXRpbmcgdGhlIHAtdmFsdWUgZnJvbSB0aGUgbnVsbCBkaXN0cmlidXRpb24gYW5kIG9ic2VydmVkIHN0YXRpc3RpYywKCmBgYHtyfQpudWxsX2Rpc3QgJT4lCiAgZ2V0X3BfdmFsdWUob2JzX3N0YXQgPSBDaGlzcV9oYXQsIGRpcmVjdGlvbiA9ICJncmVhdGVyIikKYGBgCgpBbHRlcm5hdGl2ZWx5LCB1c2luZyB0aGUgd3JhcHBlciB0byBjYXJyeSBvdXQgdGhlIHRlc3QsCgpgYGB7cn0KbGl6YXJkX2hhYml0YXQgJT4lCiAgY2hpc3FfdGVzdChmb3JtdWxhID0gc2l0ZSB+IHN1bmxpZ2h0KQpgYGAKClNpbmNlIHRoZSBwLXZhbHVlIGlzIGNsb3NlIHRvIHplcm8sIHdlIGNhbiByZWplY3QgdGhlIG51bGwgYW5kIGNvbmNsdWRlIHRoYXQgdGhlcmUgaXMgYW4gYXNzb2NpYXRpb24gYmV0d2VlbiBzdW5saWdodCBjaG9pY2UgYW5kIHRoZSBzaXRlIG9uIHdoaWNoIHRoZSBsaXphcmRzIHByZWZlciB0byBsaXZlIHRoZWlyIGJlc3QgbGl2ZXMuCgojIyMgTmdyYW1zIGFuZCBDb2xsb2NhdGlvbnMKCipTb3JyeSwgSSB0aG91Z2h0IEkgaGF2ZSB0aW1lIGZvciB0aGlzIGJ1dCBJIGFtIGp1c3QgYnVzeSBidXN5IGxlbW9uIHNxdWlzaHkuIElmIHlvdSBhcmUgaW50ZXJlc3RlZCBpbiBsZWFybmluZyBhYm91dCBzdGF0aXN0aWNhbCBuYXR1cmFsIGxhbmd1YWdlIHByb2Nlc3NpbmcgdXNpbmcgdGV4dCBkYXRhIG9yIGRhdGEgYW5hbHlzaXMgaW4gZ2VuZXJhbCwgKipJIHJlY29tbWVuZCB0YWtpbmcgdGhlIERhdGEgU2NpZW5jZSBjbGFzcyBpbiBTcHJpbmcgb2YgMjAyMioqLiBUaGUgcHJlcmVxdWlzaXRlcyBmb3IgRGF0YSBTY2llbmNlIGlzIEludHJvZHVjdGlvbiB0byBQcm9iYWJpbGl0eSBhbmQgU3RhdGlzdGljcy4gSWYgeW91IGFyZSBkb2luZyB3ZWxsIGluIHRoZSBJbnRyb2R1Y3Rpb24gdG8gUHJvYmFiaWxpdHkgYW5kIFN0YXRpc3RpY3MsIHRoZW4geW91IHNob3VsZCBiZSBva2F5IGluIERhdGEgU2NpZW5jZS4qCgo8YnI+CgojIyAqKk1pbmkgQWN0aXZpdGllcyoqCgo8YnI+CgoqKkRpc2FnZ3JlZ2F0aW5nIEFzaWFuIEFtZXJpY2FuIHRvYmFjY28gdXNlLCBkYXRhLioqCgo+IFVuZGVyc3RhbmRpbmcgY3VsdHVyYWwgZGlmZmVyZW5jZXMgaW4gdG9iYWNjbyB1c2UgYWNyb3NzIGRpZmZlcmVudCBkZW1vZ3JhcGhpYyBncm91cHMgY2FuIGxlYWQgdG8gaW1wcm92ZWQgaGVhbHRoIGNhcmUgZWR1Y2F0aW9uIGFuZCB0cmVhdG1lbnQuIEEgcmVjZW50IHN0dWR5IGRpc2FnZ3JlZ2F0ZWQgdG9iYWNjbyB1c2UgYWNyb3NzIEFzaWFuIEFtZXJpY2FuIGV0aG5pYyBncm91cHMgaW5jbHVkaW5nIEFzaWFuLUluZGlhbiAobiA9IDQsMzczKSwgQ2hpbmVzZSAobiA9IDQsNzM2KSwgYW5kIEZpbGlwaW5vIChuID0gNCw5MTIpLCBpbiBjb21wYXJpc29uIHRvIG5vbi1IaXNwYW5pYyBXaGl0ZXMgKG4gPSAyNzUsMDI1KS4gIFRoZSBudW1iZXIgb2YgY3VycmVudCBzbW9rZXJzIGluIGVhY2ggZ3JvdXAgd2FzIHJlcG9ydGVkIGFzIEFzaWFuLUluZGlhbiAobiA9IDIyMyksIENoaW5lc2UgKG4gPSAyNzkpLCBGaWxpcGlubyAobiA9IDYwOSksIGFuZCBub24tSGlzcGFuaWMgV2hpdGVzIChuID0gNTAsODgwKS4gW1JhbzIwMjFdKGh0dHBzOi8vbGluay5zcHJpbmdlci5jb20vYXJ0aWNsZS8xMC4xMDA3JTJGczQwNjE1LTAyMS0wMTAyNC01KXt0YXJnZXQ9Il9ibGFuayJ9CiAgCkhlcmUgaXMgdGhlIGRhdGEgY29kZS4KCmBgYHtyfQphc2lhbl9zbW9rZSA8LSB0aWJibGUoCiAgZXRobmljaXR5ID0gYygKICAgIHJlcCgiQXNpYW4tSW5kaWFuIiwgNDM3MyksCiAgICByZXAoIkNoaW5lc2UiLCA0NzM2KSwKICAgIHJlcCgiRmlsaXBpbm8iLCA0OTEyKQogICksCiAgb3V0Y29tZSA9IGMoCiAgICByZXAoInNtb2tlIiwgMjIzKSwgcmVwKCJkb24ndCBzbW9rZSIsIDQxNTApLAogICAgcmVwKCJzbW9rZSIsIDI3OSksIHJlcCgiZG9uJ3Qgc21va2UiLCA0NDU3KSwKICAgIHJlcCgic21va2UiLCA2MDkpLCByZXAoImRvbid0IHNtb2tlIiwgNDMwMykKICApCikKYGBgCgpIZXJlIGlzIHRoZSBkYXRhIHByaW50ZWQgYXMgdGFibGUuCgpgYGB7ciBlY2hvPVRSVUV9CmFzaWFuX3Ntb2tlICU+JQogIGNvdW50KGV0aG5pY2l0eSwgb3V0Y29tZSkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IG91dGNvbWUsIHZhbHVlc19mcm9tID0gbikgJT4lCiAgYWRvcm5fdG90YWxzKHdoZXJlID0gYygicm93IiwgImNvbCIpKSAlPiUKICBrYmwoYWxpZ24gPSAibHJycnIiLCBib29rdGFicyA9IFRSVUUsIGZvcm1hdC5hcmdzID0gbGlzdChiaWcubWFyayA9ICIsIikpICU+JQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImNvbmRlbnNlZCIpLCAKICAgICAgICAgICAgICAgIGxhdGV4X29wdGlvbnMgPSAiSE9MRF9wb3NpdGlvbiIsCiAgICAgICAgICAgICAgICBmdWxsX3dpZHRoID0gRkFMU0UpICU+JQogIGFkZF9oZWFkZXJfYWJvdmUoYygiICIgPSAxLCAiU21va2luZyIgPSAyLCAiICIgPSAxKSkgJT4lCiAgY29sdW1uX3NwZWMoMSwgd2lkdGggPSAiN2VtIikgJT4lCiAgY29sdW1uX3NwZWMoMjo0LCB3aWR0aCA9ICI1ZW0iKQpgYGAKCiAgKiBJbiBvcmRlciB0byBhc3Nlc3Mgd2hldGhlciB0aGVyZSBpcyBhIGRpZmZlcmVuY2UgaW4gY3VycmVudCBzbW9raW5nIHJhdGVzIGFjcm9zcyB0aHJlZSBBc2lhbiBBbWVyaWNhbiBldGhuaWMgZ3JvdXBzLCB0aGUgb2JzZXJ2ZWQgZGF0YSBpcyBjb21wYXJlZCB0byB0aGUgZGF0YSB0aGF0IHdvdWxkIGJlIGV4cGVjdGVkIGlmIHRoZXJlIHdlcmUgbm8gYXNzb2NpYXRpb24gYmV0d2VlbiB0aGUgdmFyaWFibGVzLgogIAogIDEuIFdoYXQgaXMgdGhlIG51bGwgYW5kIGFsdGVybmF0aXZlIGh5cG90aGVzaXM/CiAgCiAgMi4gQ2Fycnkgb3V0IHRoZSByYW5kb21pemF0aW9uIHByb2NlZHVyZSBhbmQgdGhlb3JldGljYWwgbWV0aG9kIGZvciB0aGUgQ2hpLVNxdWFyZWQgdGVzdCBmb3IgaW5kZXBlbmRlbmNlLiBQbG90IHRoZSByZXN1bHRpbmcgZGlzdHJpYnV0aW9ucy4KICAKICAzLiBDb21wdXRlIHRoZSBwLXZhbHVlIHVzaW5nIHRoZSByYW5kb21pemF0aW9uIGFuZCB0aGVvcnkuCiAgCiAgNC4gV2hhdCBpcyB0aGUgY29uY2x1c2lvbj8KCjxicj4K