This project is part of my dataquest course. The aim of the project is to interrogate the data from the American gameshow ‘Jeopardy’. The dataset includes every question, the question value, the answer, the date, round and show number. There are two aims: to see if some categories are statistically more likely to appear more often than others ; to see if certain terms in questions are statistically more likely to appear in high value questions. The chi-squared test will be used to answer these questions.

#load libraries

library (readr)
library(stringr)
library(ggplot2)
Registered S3 method overwritten by 'dplyr':
  method           from
  print.rowwise_df     
Want to understand how all the pieces fit together? Read R for Data Science:
https://r4ds.had.co.nz/
library(dplyr)

Attaching package: 㤼㸱dplyr㤼㸲

The following objects are masked from 㤼㸱package:stats㤼㸲:

    filter, lag

The following objects are masked from 㤼㸱package:base㤼㸲:

    intersect, setdiff, setequal, union
library(purrr)
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
-- Attaching packages --------------------------------------- tidyverse 1.3.0 --
v tibble  3.0.1     v forcats 0.5.0
v tidyr   1.0.3     
-- Conflicts ------------------------------------------ tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
#load data and clean column names

setwd("C:/Users/Ana/Desktop/Data Analytics/CSV Files")
data <- read_csv("jeopardy_2.csv")
Parsed with column specification:
cols(
  `Show Number` = col_double(),
  `Air Date` = col_character(),
  Round = col_character(),
  Category = col_character(),
  Value = col_character(),
  Question = col_character(),
  Answer = col_character()
)
colnames(data)
[1] "Show Number" "Air Date"    "Round"       "Category"    "Value"       "Question"    "Answer"     
colnames(data) <- tolower(colnames(data))
colnames(data)[1:2] <- c("show_number", "air_date")

#print first 5 rows of data
head(data, 5)
#print number of rows in dataframe
nrow(data)
[1] 19999
#print the number of unique categories
length(unique(data$category))
[1] 3580
#clean value column and make numeric

data_2 <- data %>%
  mutate(value = str_replace(value, "\\$", "")) %>%
  mutate(value = str_replace(value, "[Nn]one", "")) %>%
  mutate(value = as.numeric(value)) %>%
  drop_na(value)
NAs introduced by coercion
head(data_2,100)
#normalise the question, answer and category columns

normalise <- function(vector) {
  vector <- str_replace_all(vector, "[:punct:]", "")
  vector <- tolower(vector)
}

data_3 <- data_2 %>%
  mutate(category = normalise(category)) %>%
  mutate(question = normalise(question)) %>%
  mutate(answer = normalise(answer))

head(data_3)
#split the air_date column into three columns; day, month, year

data_4 <- data_3 %>%
  separate(air_date, c("day", "month", "year"), sep = "/") %>%
  mutate(day = as.numeric(day)) %>%
  mutate(month = as.numeric(month)) %>%
  mutate(year = as.numeric(year))

head(data_4, 100)
NA
science_cat <- data_4 %>%
  filter(category == "science")

sci_observed <- nrow(science_cat)

history_cat <- data_4 %>%
  filter(category == "history")

hist_observed <- nrow(history_cat)

shakespeare_cat <- data_4 %>%
  filter(category == "shakespeare")

ss_observed <- nrow(shakespeare_cat)

sci_observed
[1] 33
hist_observed
[1] 38
ss_observed
[1] 19
n_questions <- nrow(data_4)
p_category_expected <-   1/3369 
p_not_category_expected <- 3368/3369 
p_expected <- c(p_category_expected, p_not_category_expected)

science_obs <- c(sci_observed, n_questions - sci_observed)

chisq.test(science_obs, p = p_expected)

    Chi-squared test for given probabilities

data:  science_obs
X-squared = 133.76, df = 1, p-value < 2.2e-16

The p-value is < 0.05. I.e. it is extremely unlikely that this result would occur. Therefore we should reject the null hypothesis that there is no bias towards science questions.

history_obs <- c(hist_observed, n_questions - hist_observed)

chisq.test(history_obs, p = p_expected)

    Chi-squared test for given probabilities

data:  history_obs
X-squared = 187.05, df = 1, p-value < 2.2e-16

The p-value is < 0.05. I.e. it is extremely unlikely that this result would occur. Therefore we should reject the null hypothesis that there is no bias towards history questions.

shakespeare_obs <- c(ss_observed, n_questions - ss_observed)

chisq.test(shakespeare_obs, p = p_expected)

    Chi-squared test for given probabilities

data:  shakespeare_obs
X-squared = 31.966, df = 1, p-value = 1.569e-08

The p-value is < 0.05. I.e. it is extremely unlikely that this result would occur. Therefore we should reject the null hypothesis that there is no bias towards shakespeare questions.

#order data set by air date

data_5 <- data_4 %>%
  arrange(year, month, day)
longwords <- function(vector) {
  indv_words <- unlist(str_split(vector, "\\s+"))
  logic <- str_detect(indv_words, "\\w\\w\\w\\w\\w\\w+")
  long_words <- indv_words[logic]
  long_words
}
test_sentence <- "hellothere my name is Ana and I'm learning to code elephant swimming monsoon hurricane government predjudice fakenews"
#vector <- test_sentence
#indv_words <- unlist(str_split(vector, "\\s+"))
#logic <- str_detect(indv_words, "\\w\\w\\w\\w\\w\\w+")
#long_words <- indv_words[logic]
#long_words

longwords <- function(vector) {
  indv_words <- unlist(str_split(vector, "\\s+"))
  logic <- str_detect(indv_words, "\\w\\w\\w\\w\\w\\w+")
  long_words <- indv_words[logic]
  long_words
}

#longwords(test_sentence)
#count how many unique 6+letter words there are in the questions

length(terms_used)
[1] 23584
# filter the dataframe to and include a new column which categorises a question as high or low value

data_6 <- data_5 %>%
  select(value, question) %>%
  mutate(high_low = if_else(value < 800, "low", "high"))

head(data_6, 1000)

#check the proportion of high value and low value questions

data_6 %>% group_by(high_low) %>% summarise(Freq = n(), percent = n()/nrow(data_6)*100) 
NA
#create a function which takes a word and outputs the number of times it appears in a value question

wordcount <- 0

data_6_hv <- data_6 %>% filter(high_low == "high")
data_6_lv <- data_6 %>% filter(high_low == "low")

question_split_and_count <- function(question, word) {
  
  q_long_words <- longwords(question) #vector of long words in each question
  present <- if_else(word %in% q_long_words, 1, 0) # check if word appears in vector
  wordcount <- wordcount + present
}

#run this funtion for high value questions. Test it on the word "british"

sum(unlist(map2(data_6_hv$question, "british", question_split_and_count)))
[1] 69
#run this funtion for low value questions. Test it on the word "british"

sum(unlist(map2(data_6_lv$question, "british", question_split_and_count)))
[1] 83
#iterate through the words of the terms_used vector for the high value questions
#As the term_used vector has 20,000+ words, I don't want to interate through it all, so need to find a way to reduce the number of terms.
#Firstly, when looking at hypothesis testing, you need a minimum of 5 occurances. Lots of these words will likely only occur once or twice throughout the whole dataset so it would be good to get rid of those words
all_words <- paste(data_6$question, collapse = " ")
#create a function which counts the number of times a word appears in all_words

occurances <- function(word){
  searchword <- paste(" ", word, " ", sep="")
  str_count(all_words, searchword)
}

words_appear <- unlist(map(terms_used, occurances))
#We now have vector which contains the number of occurances per word of the terms_used vector. bind this vectors to create a dataframe. 

unique_terms <- as.data.frame(cbind(terms_used, words_appear))

#We only want to include words that have enough appearances, otherwise the chi-squared function won't be reliable. We know that if there are less than 5 instances, then the chi-quared test won't be reliable. Therefore, filter to only keep words with over 5 appearances.

unique_terms_2 <- unique_terms %>%
  mutate(words_appear = as.numeric(words_appear)) %>%
  filter(words_appear > 5) %>%
  arrange(desc(words_appear))

head(unique_terms_2, 100)

#print number of unique terms
nrow(unique_terms_2)
[1] 2616
#now for the analysis, take the top 20 most used terms in questions

popular_terms_used <- unique_terms_2$terms_used[1:20]

#print populat_terms_used vector
popular_terms_used
 [1] "called"               "country"              "played"               "became"              
 [5] "before"               "american"             "capital"              "target=blank>here<a>"
 [9] "french"               "famous"               "president"            "island"              
[13] "little"               "national"             "largest"              "people"              
[17] "author"               "around"               "british"              "meaning"             

#now iterate through the words of the popular_terms_used vector for the high value questions

#test_terms <- c("britain", "america", "canada")

hv_freq <- c()

for(word in popular_terms_used) {
  hv_freq <- c(hv_freq, sum(unlist(map2(data_6_hv$question, word, question_split_and_count))))
}

hv_freq

#iterate through the words of the terms_used vector for the low value questions

lv_freq <- c()

for(word in popular_terms_used) {
  lv_freq <- c(lv_freq, sum(unlist(map2(data_6_lv$question, word, question_split_and_count))))
}

lv_freq
#bind the popular_terms_used vector to the frequencies for high and low value questions

pop_word_freq <- as.data.frame(cbind(popular_terms_used, hv_freq, lv_freq))

#as we know that there are 3 low value questions for every 2 high value questions, calculate the expected probability

p_hv_expected <- 0.4 
p_lv_expected <- 0.6 
p_expected <- c(p_hv_expected, p_lv_expected)

#manipulate the dataframe to include rows for the proportion of each word appearring in high and low value questions. also calculate the p-value for each word.

pop_word_freq_2 <- pop_word_freq %>%
  mutate(hv_freq = as.numeric(hv_freq),
         lv_freq = as.numeric(lv_freq),
         total = (hv_freq + lv_freq),
         prop_hv = hv_freq/total,
         prop_lv = lv_freq/total,
         n = (prop_hv - p_hv_expected)^2/p_hv_expected + (prop_lv - p_lv_expected)^2/p_lv_expected,
         pvalue = 1 - pchisq(n, df = 1)) %>%
  filter(total > 10)

pop_word_freq_2

As none of the p-values were less than 0.05 we cannot reject the null hypothesis. i.e. there is nothing to support any of these terms showing up more in high or low value questions. Disappointing!

LS0tDQp0aXRsZTogIlBvcHVsYXIgQ2F0ZWdvcmllcyBhbmQgS2V5IFdvcmRzIGluIHRoZSBBbWVyaWNhbiBnYW1lc2hvdyAnSmVvcGFyZHknIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KVGhpcyBwcm9qZWN0IGlzIHBhcnQgb2YgbXkgZGF0YXF1ZXN0IGNvdXJzZS4gVGhlIGFpbSBvZiB0aGUgcHJvamVjdCBpcyB0byBpbnRlcnJvZ2F0ZSB0aGUgZGF0YSBmcm9tIHRoZSBBbWVyaWNhbiBnYW1lc2hvdyAnSmVvcGFyZHknLiBUaGUgZGF0YXNldCBpbmNsdWRlcyBldmVyeSBxdWVzdGlvbiwgdGhlIHF1ZXN0aW9uIHZhbHVlLCB0aGUgYW5zd2VyLCB0aGUgZGF0ZSwgcm91bmQgYW5kIHNob3cgbnVtYmVyLiBUaGVyZSBhcmUgdHdvIGFpbXM6IHRvIHNlZSBpZiBzb21lIGNhdGVnb3JpZXMgYXJlIHN0YXRpc3RpY2FsbHkgbW9yZSBsaWtlbHkgdG8gYXBwZWFyIG1vcmUgb2Z0ZW4gdGhhbiBvdGhlcnMgOyB0byBzZWUgaWYgY2VydGFpbiB0ZXJtcyBpbiBxdWVzdGlvbnMgYXJlIHN0YXRpc3RpY2FsbHkgbW9yZSBsaWtlbHkgdG8gYXBwZWFyIGluIGhpZ2ggdmFsdWUgcXVlc3Rpb25zLiBUaGUgY2hpLXNxdWFyZWQgdGVzdCB3aWxsIGJlIHVzZWQgdG8gYW5zd2VyIHRoZXNlIHF1ZXN0aW9ucy4gDQoNCmBgYHtyfQ0KI2xvYWQgbGlicmFyaWVzDQoNCmxpYnJhcnkgKHJlYWRyKQ0KbGlicmFyeShzdHJpbmdyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkocHVycnIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmBgYA0KDQpgYGB7cn0NCiNsb2FkIGRhdGEgYW5kIGNsZWFuIGNvbHVtbiBuYW1lcw0KDQpzZXR3ZCgiQzovVXNlcnMvQW5hL0Rlc2t0b3AvRGF0YSBBbmFseXRpY3MvQ1NWIEZpbGVzIikNCmRhdGEgPC0gcmVhZF9jc3YoImplb3BhcmR5XzIuY3N2IikNCmNvbG5hbWVzKGRhdGEpDQpjb2xuYW1lcyhkYXRhKSA8LSB0b2xvd2VyKGNvbG5hbWVzKGRhdGEpKQ0KY29sbmFtZXMoZGF0YSlbMToyXSA8LSBjKCJzaG93X251bWJlciIsICJhaXJfZGF0ZSIpDQoNCiNwcmludCBmaXJzdCA1IHJvd3Mgb2YgZGF0YQ0KaGVhZChkYXRhLCA1KQ0KI3ByaW50IG51bWJlciBvZiByb3dzIGluIGRhdGFmcmFtZQ0KbnJvdyhkYXRhKQ0KI3ByaW50IHRoZSBudW1iZXIgb2YgdW5pcXVlIGNhdGVnb3JpZXMNCmxlbmd0aCh1bmlxdWUoZGF0YSRjYXRlZ29yeSkpDQpgYGANCmBgYHtyfQ0KI2NsZWFuIHZhbHVlIGNvbHVtbiBhbmQgbWFrZSBudW1lcmljDQoNCmRhdGFfMiA8LSBkYXRhICU+JQ0KICBtdXRhdGUodmFsdWUgPSBzdHJfcmVwbGFjZSh2YWx1ZSwgIlxcJCIsICIiKSkgJT4lDQogIG11dGF0ZSh2YWx1ZSA9IHN0cl9yZXBsYWNlKHZhbHVlLCAiW05uXW9uZSIsICIiKSkgJT4lDQogIG11dGF0ZSh2YWx1ZSA9IGFzLm51bWVyaWModmFsdWUpKSAlPiUNCiAgZHJvcF9uYSh2YWx1ZSkNCg0KaGVhZChkYXRhXzIsMTAwKQ0KYGBgDQoNCmBgYHtyfQ0KI25vcm1hbGlzZSB0aGUgcXVlc3Rpb24sIGFuc3dlciBhbmQgY2F0ZWdvcnkgY29sdW1ucw0KDQpub3JtYWxpc2UgPC0gZnVuY3Rpb24odmVjdG9yKSB7DQogIHZlY3RvciA8LSBzdHJfcmVwbGFjZV9hbGwodmVjdG9yLCAiWzpwdW5jdDpdIiwgIiIpDQogIHZlY3RvciA8LSB0b2xvd2VyKHZlY3RvcikNCn0NCg0KZGF0YV8zIDwtIGRhdGFfMiAlPiUNCiAgbXV0YXRlKGNhdGVnb3J5ID0gbm9ybWFsaXNlKGNhdGVnb3J5KSkgJT4lDQogIG11dGF0ZShxdWVzdGlvbiA9IG5vcm1hbGlzZShxdWVzdGlvbikpICU+JQ0KICBtdXRhdGUoYW5zd2VyID0gbm9ybWFsaXNlKGFuc3dlcikpDQoNCmhlYWQoZGF0YV8zKQ0KYGBgDQoNCmBgYHtyfQ0KI3NwbGl0IHRoZSBhaXJfZGF0ZSBjb2x1bW4gaW50byB0aHJlZSBjb2x1bW5zOyBkYXksIG1vbnRoLCB5ZWFyDQoNCmRhdGFfNCA8LSBkYXRhXzMgJT4lDQogIHNlcGFyYXRlKGFpcl9kYXRlLCBjKCJkYXkiLCAibW9udGgiLCAieWVhciIpLCBzZXAgPSAiLyIpICU+JQ0KICBtdXRhdGUoZGF5ID0gYXMubnVtZXJpYyhkYXkpKSAlPiUNCiAgbXV0YXRlKG1vbnRoID0gYXMubnVtZXJpYyhtb250aCkpICU+JQ0KICBtdXRhdGUoeWVhciA9IGFzLm51bWVyaWMoeWVhcikpDQoNCmhlYWQoZGF0YV80LCAxMDApDQoNCmBgYA0KDQoNCmBgYHtyfQ0KI2NvdW50IGhvdyBvZnRlbiB0aGUgY2F0ZWdvcmllcyAnc2NpZW5jZScsICdoaXN0b3J5JyBhbmQgJ3NoYWtlc3BlYXJlJyBvY2N1ci4gV2Ugd2FudCB0byBzZWUgaWYgdGhlc2UgY2F0ZWdvcmllcyBhcmUgbW9yZSBsaWtlbHkgdG8gb2NjdXIgdGhhbiBvdGhlciBjYXRlZ29yaWVzLiANCiNOdWxsIGh5cG90aGVzaXM6IHNjaWVuY2UvaGlzdG9yeS9zaGFrZXNwZWFyZSBjYXRlZ29yaWVzIGFyZSBlcXVhbGx5IGxpa2VseSB0byBvY2N1ciBhcyBhbnkgb3RoZXIgY2F0ZWdvcnkNCg0Kc2NpZW5jZV9jYXQgPC0gZGF0YV80ICU+JQ0KICBmaWx0ZXIoY2F0ZWdvcnkgPT0gInNjaWVuY2UiKQ0KDQpzY2lfb2JzZXJ2ZWQgPC0gbnJvdyhzY2llbmNlX2NhdCkNCg0KaGlzdG9yeV9jYXQgPC0gZGF0YV80ICU+JQ0KICBmaWx0ZXIoY2F0ZWdvcnkgPT0gImhpc3RvcnkiKQ0KDQpoaXN0X29ic2VydmVkIDwtIG5yb3coaGlzdG9yeV9jYXQpDQoNCnNoYWtlc3BlYXJlX2NhdCA8LSBkYXRhXzQgJT4lDQogIGZpbHRlcihjYXRlZ29yeSA9PSAic2hha2VzcGVhcmUiKQ0KDQpzc19vYnNlcnZlZCA8LSBucm93KHNoYWtlc3BlYXJlX2NhdCkNCg0Kc2NpX29ic2VydmVkDQpoaXN0X29ic2VydmVkDQpzc19vYnNlcnZlZA0KDQpgYGANCg0KYGBge3J9DQojYXMgdGhlcmUgYXJlIDMzNjkgdW5xaXVlIGNhdGVnb3JpZXMsIGNhbGN1bGF0ZSB0aGUgZXhwZWN0ZWQgcHJvYmFiaWxpdHkgZm9yIGEgcGFydGljdWxhciBjYXRlZ29yeSB0byBhcHBlYXINCg0Kbl9xdWVzdGlvbnMgPC0gbnJvdyhkYXRhXzQpDQpwX2NhdGVnb3J5X2V4cGVjdGVkIDwtICAgMS8zMzY5IA0KcF9ub3RfY2F0ZWdvcnlfZXhwZWN0ZWQgPC0gMzM2OC8zMzY5IA0KcF9leHBlY3RlZCA8LSBjKHBfY2F0ZWdvcnlfZXhwZWN0ZWQsIHBfbm90X2NhdGVnb3J5X2V4cGVjdGVkKQ0KDQojZm9yICdzY2llbmNlJywgcnVuIGEgY2hpLXNxdWFyZWQgdGVzdCB0byBzZWUgaWYgd2UgY2FuIHJlamVjdCBvciBhY2NlcHQgdGhlIG51bGwgaHlwb3RoZXNpcy4gDQoNCnNjaWVuY2Vfb2JzIDwtIGMoc2NpX29ic2VydmVkLCBuX3F1ZXN0aW9ucyAtIHNjaV9vYnNlcnZlZCkNCg0KY2hpc3EudGVzdChzY2llbmNlX29icywgcCA9IHBfZXhwZWN0ZWQpDQpgYGANClRoZSBwLXZhbHVlIGlzIDwgMC4wNS4gSS5lLiBpdCBpcyBleHRyZW1lbHkgdW5saWtlbHkgdGhhdCB0aGlzIHJlc3VsdCB3b3VsZCBvY2N1ci4gVGhlcmVmb3JlIHdlIHNob3VsZCByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyB0aGF0IHRoZXJlIGlzIG5vIGJpYXMgdG93YXJkcyBzY2llbmNlIHF1ZXN0aW9ucy4NCmBgYHtyfQ0KaGlzdG9yeV9vYnMgPC0gYyhoaXN0X29ic2VydmVkLCBuX3F1ZXN0aW9ucyAtIGhpc3Rfb2JzZXJ2ZWQpDQoNCmNoaXNxLnRlc3QoaGlzdG9yeV9vYnMsIHAgPSBwX2V4cGVjdGVkKQ0KYGBgDQpUaGUgcC12YWx1ZSBpcyA8IDAuMDUuIEkuZS4gaXQgaXMgZXh0cmVtZWx5IHVubGlrZWx5IHRoYXQgdGhpcyByZXN1bHQgd291bGQgb2NjdXIuIFRoZXJlZm9yZSB3ZSBzaG91bGQgcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgdGhhdCB0aGVyZSBpcyBubyBiaWFzIHRvd2FyZHMgaGlzdG9yeSBxdWVzdGlvbnMuDQpgYGB7cn0NCnNoYWtlc3BlYXJlX29icyA8LSBjKHNzX29ic2VydmVkLCBuX3F1ZXN0aW9ucyAtIHNzX29ic2VydmVkKQ0KDQpjaGlzcS50ZXN0KHNoYWtlc3BlYXJlX29icywgcCA9IHBfZXhwZWN0ZWQpDQpgYGANClRoZSBwLXZhbHVlIGlzIDwgMC4wNS4gSS5lLiBpdCBpcyBleHRyZW1lbHkgdW5saWtlbHkgdGhhdCB0aGlzIHJlc3VsdCB3b3VsZCBvY2N1ci4gVGhlcmVmb3JlIHdlIHNob3VsZCByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyB0aGF0IHRoZXJlIGlzIG5vIGJpYXMgdG93YXJkcyBzaGFrZXNwZWFyZSBxdWVzdGlvbnMuDQpgYGB7cn0NCiNvcmRlciBkYXRhIHNldCBieSBhaXIgZGF0ZQ0KDQpkYXRhXzUgPC0gZGF0YV80ICU+JQ0KICBhcnJhbmdlKHllYXIsIG1vbnRoLCBkYXkpDQoNCmBgYA0KDQpgYGB7cn0NCiNjcmVhdGUgYSBmdW5jdGlvbiB0aGF0IHRha2VzIGFuIGlucHV0IHN0cmluZyBhbmQgb3V0cHV0cyBhIHZlY3RvciBvZiBhbGwgdGhlIDYrIGxldHRlciB3b3JkcyB0aGF0IGFwcGVhciBpbiB0aGUgaW5wdXQgc3RyaW5nLg0KDQpsb25nd29yZHMgPC0gZnVuY3Rpb24odmVjdG9yKSB7DQogIGluZHZfd29yZHMgPC0gdW5saXN0KHN0cl9zcGxpdCh2ZWN0b3IsICJcXHMrIikpDQogIGxvZ2ljIDwtIHN0cl9kZXRlY3QoaW5kdl93b3JkcywgIlxcd1xcd1xcd1xcd1xcd1xcdysiKQ0KICBsb25nX3dvcmRzIDwtIGluZHZfd29yZHNbbG9naWNdDQogIGxvbmdfd29yZHMNCn0NCg0KYGBgDQoNCmBgYHtyfQ0KI21hcCB0aGUgbG9uZ3dvcmRzIGZ1bmN0aW9uIHRvIHRoZSBxdWVzdGlvbiBjb2x1bW4gdG8gY3JlYXRlIGEgdmVjdG9yIG9mIGFsbCB1bmlxdWUgbG9uZyAoNiBsZXR0ZXJzICspIHdvcmRzIHByZXNlbnQgaW4gdGhlIHF1ZXN0aW9ucw0KDQp0ZXJtc191c2VkIDwtIHVuaXF1ZSh1bmxpc3QobWFwKGRhdGFfNSRxdWVzdGlvbiwgbG9uZ3dvcmRzKSkpDQoNCmhlYWQodGVybXNfdXNlZCwgMTApDQoNCg0KYGBgDQpgYGB7cn0NCiNjb3VudCBob3cgbWFueSB1bmlxdWUgNitsZXR0ZXIgd29yZHMgdGhlcmUgYXJlIGluIHRoZSBxdWVzdGlvbnMNCg0KbGVuZ3RoKHRlcm1zX3VzZWQpDQpgYGANCg0KYGBge3J9DQojIGZpbHRlciB0aGUgZGF0YWZyYW1lIHRvIGFuZCBpbmNsdWRlIGEgbmV3IGNvbHVtbiB3aGljaCBjYXRlZ29yaXNlcyBhIHF1ZXN0aW9uIGFzIGhpZ2ggb3IgbG93IHZhbHVlDQoNCmRhdGFfNiA8LSBkYXRhXzUgJT4lDQogIHNlbGVjdCh2YWx1ZSwgcXVlc3Rpb24pICU+JQ0KICBtdXRhdGUoaGlnaF9sb3cgPSBpZl9lbHNlKHZhbHVlIDwgODAwLCAibG93IiwgImhpZ2giKSkNCg0KaGVhZChkYXRhXzYsIDEwMDApDQoNCiNjaGVjayB0aGUgcHJvcG9ydGlvbiBvZiBoaWdoIHZhbHVlIGFuZCBsb3cgdmFsdWUgcXVlc3Rpb25zDQoNCmRhdGFfNiAlPiUgZ3JvdXBfYnkoaGlnaF9sb3cpICU+JSBzdW1tYXJpc2UoRnJlcSA9IG4oKSwgcGVyY2VudCA9IG4oKS9ucm93KGRhdGFfNikqMTAwKSANCg0KYGBgDQoNCg0KYGBge3J9DQoNCiNzcGxpdCB0aGUgZGF0YWZyYW1lIGludG8gMiAtIDEgZm9yIGhpZ2ggdmFsdWUgcXVlc3Rpb25zLCB0aGUgb3RoZXIgZm9yIGxvdyB2YWx1ZSBxdWVzdGlvbnMNCg0KZGF0YV82X2h2IDwtIGRhdGFfNiAlPiUgZmlsdGVyKGhpZ2hfbG93ID09ICJoaWdoIikNCmRhdGFfNl9sdiA8LSBkYXRhXzYgJT4lIGZpbHRlcihoaWdoX2xvdyA9PSAibG93IikNCg0KI2NyZWF0ZSBhIGZ1bmN0aW9uIHdoaWNoIHRha2VzIGEgd29yZCBhbmQgb3V0cHV0cyB0aGUgbnVtYmVyIG9mIHRpbWVzIGl0IGFwcGVhcnMgaW4gYSBoaWdoIGFuZCBsb3cgdmFsdWUgcXVlc3Rpb24NCg0Kd29yZGNvdW50IDwtIDANCg0KcXVlc3Rpb25fc3BsaXRfYW5kX2NvdW50IDwtIGZ1bmN0aW9uKHF1ZXN0aW9uLCB3b3JkKSB7DQogIA0KICBxX2xvbmdfd29yZHMgPC0gbG9uZ3dvcmRzKHF1ZXN0aW9uKSAjdmVjdG9yIG9mIGxvbmcgd29yZHMgaW4gZWFjaCBxdWVzdGlvbg0KICBwcmVzZW50IDwtIGlmX2Vsc2Uod29yZCAlaW4lIHFfbG9uZ193b3JkcywgMSwgMCkgIyBjaGVjayBpZiB3b3JkIGFwcGVhcnMgaW4gdmVjdG9yDQogIHdvcmRjb3VudCA8LSB3b3JkY291bnQgKyBwcmVzZW50DQp9DQoNCiNydW4gdGhpcyBmdW50aW9uIGZvciBoaWdoIHZhbHVlIHF1ZXN0aW9ucy4gVGVzdCBpdCBvbiB0aGUgd29yZCAiYnJpdGlzaCINCg0Kc3VtKHVubGlzdChtYXAyKGRhdGFfNl9odiRxdWVzdGlvbiwgImJyaXRpc2giLCBxdWVzdGlvbl9zcGxpdF9hbmRfY291bnQpKSkNCg0KI3J1biB0aGlzIGZ1bnRpb24gZm9yIGxvdyB2YWx1ZSBxdWVzdGlvbnMuIFRlc3QgaXQgb24gdGhlIHdvcmQgImJyaXRpc2giDQoNCnN1bSh1bmxpc3QobWFwMihkYXRhXzZfbHYkcXVlc3Rpb24sICJicml0aXNoIiwgcXVlc3Rpb25fc3BsaXRfYW5kX2NvdW50KSkpDQpgYGANCg0KDQpgYGB7cn0NCiNpdGVyYXRlIHRocm91Z2ggdGhlIHdvcmRzIG9mIHRoZSB0ZXJtc191c2VkIHZlY3RvciBmb3IgdGhlIGhpZ2ggdmFsdWUgcXVlc3Rpb25zDQojQXMgdGhlIHRlcm1fdXNlZCB2ZWN0b3IgaGFzIDIwLDAwMCsgd29yZHMsIEkgZG9uJ3Qgd2FudCB0byBpbnRlcmF0ZSB0aHJvdWdoIGl0IGFsbCwgc28gbmVlZCB0byBmaW5kIGEgd2F5IHRvIHJlZHVjZSB0aGUgbnVtYmVyIG9mIHRlcm1zLg0KI0ZpcnN0bHksIHdoZW4gbG9va2luZyBhdCBoeXBvdGhlc2lzIHRlc3RpbmcsIHlvdSBuZWVkIGEgbWluaW11bSBvZiA1IG9jY3VyYW5jZXMuIExvdHMgb2YgdGhlc2Ugd29yZHMgd2lsbCBsaWtlbHkgb25seSBvY2N1ciBvbmNlIG9yIHR3aWNlIHRocm91Z2hvdXQgdGhlIHdob2xlIGRhdGFzZXQgc28gaXQgd291bGQgYmUgZ29vZCB0byBnZXQgcmlkIG9mIHRob3NlIHdvcmRzDQoNCmBgYA0KDQoNCmBgYHtyfQ0KI2ZpcnN0LCB0YWtlIHRoZSB0ZXJtc191c2VkIHZlY3RvciBhbmQgdXNlIHBhc3RlIHRvIGNyZWF0ZSBvbmUgbG9uZyBzdHJpbmcgY29udGFpbmluZyBldmVyeSB3b3JkLiBjYWxsIHRoaXMgYWxsX3dvcmRzLiANCg0KYWxsX3dvcmRzIDwtIHBhc3RlKGRhdGFfNiRxdWVzdGlvbiwgY29sbGFwc2UgPSAiICIpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KI2NyZWF0ZSBhIGZ1bmN0aW9uIHdoaWNoIGNvdW50cyB0aGUgbnVtYmVyIG9mIHRpbWVzIGEgd29yZCBhcHBlYXJzIGluIGFsbF93b3Jkcw0KDQpvY2N1cmFuY2VzIDwtIGZ1bmN0aW9uKHdvcmQpew0KICBzZWFyY2h3b3JkIDwtIHBhc3RlKCIgIiwgd29yZCwgIiAiLCBzZXA9IiIpDQogIHN0cl9jb3VudChhbGxfd29yZHMsIHNlYXJjaHdvcmQpDQp9DQoNCndvcmRzX2FwcGVhciA8LSB1bmxpc3QobWFwKHRlcm1zX3VzZWQsIG9jY3VyYW5jZXMpKQ0KDQpgYGANCg0KDQpgYGB7cn0NCiNXZSBub3cgaGF2ZSB2ZWN0b3Igd2hpY2ggY29udGFpbnMgdGhlIG51bWJlciBvZiBvY2N1cmFuY2VzIHBlciB3b3JkIG9mIHRoZSB0ZXJtc191c2VkIHZlY3Rvci4gYmluZCB0aGlzIHZlY3RvcnMgdG8gY3JlYXRlIGEgZGF0YWZyYW1lLiANCg0KdW5pcXVlX3Rlcm1zIDwtIGFzLmRhdGEuZnJhbWUoY2JpbmQodGVybXNfdXNlZCwgd29yZHNfYXBwZWFyKSkNCg0KI1dlIG9ubHkgd2FudCB0byBpbmNsdWRlIHdvcmRzIHRoYXQgaGF2ZSBlbm91Z2ggYXBwZWFyYW5jZXMsIG90aGVyd2lzZSB0aGUgY2hpLXNxdWFyZWQgZnVuY3Rpb24gd29uJ3QgYmUgcmVsaWFibGUuIFdlIGtub3cgdGhhdCBpZiB0aGVyZSBhcmUgbGVzcyB0aGFuIDUgaW5zdGFuY2VzLCB0aGVuIHRoZSBjaGktcXVhcmVkIHRlc3Qgd29uJ3QgYmUgcmVsaWFibGUuIFRoZXJlZm9yZSwgZmlsdGVyIHRvIG9ubHkga2VlcCB3b3JkcyB3aXRoIG92ZXIgNSBhcHBlYXJhbmNlcy4NCg0KdW5pcXVlX3Rlcm1zXzIgPC0gdW5pcXVlX3Rlcm1zICU+JQ0KICBtdXRhdGUod29yZHNfYXBwZWFyID0gYXMubnVtZXJpYyh3b3Jkc19hcHBlYXIpKSAlPiUNCiAgZmlsdGVyKHdvcmRzX2FwcGVhciA+IDUpICU+JQ0KICBhcnJhbmdlKGRlc2Mod29yZHNfYXBwZWFyKSkNCg0KaGVhZCh1bmlxdWVfdGVybXNfMiwgMTAwKQ0KDQojcHJpbnQgbnVtYmVyIG9mIHVuaXF1ZSB0ZXJtcw0KbnJvdyh1bmlxdWVfdGVybXNfMikNCg0KI25vdyBmb3IgdGhlIGFuYWx5c2lzLCB0YWtlIHRoZSB0b3AgMjAgbW9zdCB1c2VkIHRlcm1zIGluIHF1ZXN0aW9ucw0KDQpwb3B1bGFyX3Rlcm1zX3VzZWQgPC0gdW5pcXVlX3Rlcm1zXzIkdGVybXNfdXNlZFsxOjIwXQ0KDQojcHJpbnQgcG9wdWxhdF90ZXJtc191c2VkIHZlY3Rvcg0KcG9wdWxhcl90ZXJtc191c2VkDQoNCmBgYA0KDQpgYGB7cn0NCg0KI25vdyBpdGVyYXRlIHRocm91Z2ggdGhlIHdvcmRzIG9mIHRoZSBwb3B1bGFyX3Rlcm1zX3VzZWQgdmVjdG9yIGZvciB0aGUgaGlnaCB2YWx1ZSBxdWVzdGlvbnMNCg0KI3Rlc3RfdGVybXMgPC0gYygiYnJpdGFpbiIsICJhbWVyaWNhIiwgImNhbmFkYSIpDQoNCmh2X2ZyZXEgPC0gYygpDQoNCmZvcih3b3JkIGluIHBvcHVsYXJfdGVybXNfdXNlZCkgew0KICBodl9mcmVxIDwtIGMoaHZfZnJlcSwgc3VtKHVubGlzdChtYXAyKGRhdGFfNl9odiRxdWVzdGlvbiwgd29yZCwgcXVlc3Rpb25fc3BsaXRfYW5kX2NvdW50KSkpKQ0KfQ0KDQpodl9mcmVxDQoNCmBgYA0KDQpgYGB7cn0NCg0KI2l0ZXJhdGUgdGhyb3VnaCB0aGUgd29yZHMgb2YgdGhlIHRlcm1zX3VzZWQgdmVjdG9yIGZvciB0aGUgbG93IHZhbHVlIHF1ZXN0aW9ucw0KDQpsdl9mcmVxIDwtIGMoKQ0KDQpmb3Iod29yZCBpbiBwb3B1bGFyX3Rlcm1zX3VzZWQpIHsNCiAgbHZfZnJlcSA8LSBjKGx2X2ZyZXEsIHN1bSh1bmxpc3QobWFwMihkYXRhXzZfbHYkcXVlc3Rpb24sIHdvcmQsIHF1ZXN0aW9uX3NwbGl0X2FuZF9jb3VudCkpKSkNCn0NCg0KbHZfZnJlcQ0KYGBgDQpgYGB7cn0NCiNiaW5kIHRoZSBwb3B1bGFyX3Rlcm1zX3VzZWQgdmVjdG9yIHRvIHRoZSBmcmVxdWVuY2llcyBmb3IgaGlnaCBhbmQgbG93IHZhbHVlIHF1ZXN0aW9ucw0KDQpwb3Bfd29yZF9mcmVxIDwtIGFzLmRhdGEuZnJhbWUoY2JpbmQocG9wdWxhcl90ZXJtc191c2VkLCBodl9mcmVxLCBsdl9mcmVxKSkNCg0KI2FzIHdlIGtub3cgdGhhdCB0aGVyZSBhcmUgMyBsb3cgdmFsdWUgcXVlc3Rpb25zIGZvciBldmVyeSAyIGhpZ2ggdmFsdWUgcXVlc3Rpb25zLCBjYWxjdWxhdGUgdGhlIGV4cGVjdGVkIHByb2JhYmlsaXR5DQoNCnBfaHZfZXhwZWN0ZWQgPC0gMC40IA0KcF9sdl9leHBlY3RlZCA8LSAwLjYgDQpwX2V4cGVjdGVkIDwtIGMocF9odl9leHBlY3RlZCwgcF9sdl9leHBlY3RlZCkNCg0KI21hbmlwdWxhdGUgdGhlIGRhdGFmcmFtZSB0byBpbmNsdWRlIHJvd3MgZm9yIHRoZSBwcm9wb3J0aW9uIG9mIGVhY2ggd29yZCBhcHBlYXJyaW5nIGluIGhpZ2ggYW5kIGxvdyB2YWx1ZSBxdWVzdGlvbnMuIGFsc28gY2FsY3VsYXRlIHRoZSBwLXZhbHVlIGZvciBlYWNoIHdvcmQuDQoNCnBvcF93b3JkX2ZyZXFfMiA8LSBwb3Bfd29yZF9mcmVxICU+JQ0KICBtdXRhdGUoaHZfZnJlcSA9IGFzLm51bWVyaWMoaHZfZnJlcSksDQogICAgICAgICBsdl9mcmVxID0gYXMubnVtZXJpYyhsdl9mcmVxKSwNCiAgICAgICAgIHRvdGFsID0gKGh2X2ZyZXEgKyBsdl9mcmVxKSwNCiAgICAgICAgIHByb3BfaHYgPSBodl9mcmVxL3RvdGFsLA0KICAgICAgICAgcHJvcF9sdiA9IGx2X2ZyZXEvdG90YWwsDQogICAgICAgICBuID0gKHByb3BfaHYgLSBwX2h2X2V4cGVjdGVkKV4yL3BfaHZfZXhwZWN0ZWQgKyAocHJvcF9sdiAtIHBfbHZfZXhwZWN0ZWQpXjIvcF9sdl9leHBlY3RlZCwNCiAgICAgICAgIHB2YWx1ZSA9IDEgLSBwY2hpc3EobiwgZGYgPSAxKSkgJT4lDQogIGZpbHRlcih0b3RhbCA+IDEwKQ0KDQpwb3Bfd29yZF9mcmVxXzINCg0KYGBgDQpBcyBub25lIG9mIHRoZSBwLXZhbHVlcyB3ZXJlIGxlc3MgdGhhbiAwLjA1IHdlIGNhbm5vdCByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcy4gaS5lLiB0aGVyZSBpcyBub3RoaW5nIHRvIHN1cHBvcnQgYW55IG9mIHRoZXNlIHRlcm1zIHNob3dpbmcgdXAgbW9yZSBpbiBoaWdoIG9yIGxvdyB2YWx1ZSBxdWVzdGlvbnMuIERpc2FwcG9pbnRpbmchDQoNCg0K