US Democrat presidents dataset

Here’s a dataset of US presidential elections. Each row represents a presidential election at the county level. The variables in the dataset are the US state, the county within that state, and the percentage of votes that went to the Democrat candidate in 2008, 2012, and in 2016.

# Load libraries
library(tidyr)
library(dplyr)
library(ggplot2)
library(fst)
library(tibble)
library(readr)
dem_votes_potus_08_16 <- read_fst(uselect_path)
dem_votes_potus_08_16
colnames(dem_votes_potus_08_16)
[1] "state"             "county"            "FIPS"              "dem_cand_votes_08" "dem_percent_08"    "dem_cand_votes_12" "dem_percent_12"   
[8] "dem_cand_votes_16" "dem_percent_16"   

Hypotheses

One question is whether the percentage of votes given to the Republican candidate was lower in 2008 compared to 2012. To test this, we form the hypotheses. As before, the null hypothesis is that our hunch is wrong, and that the population parameters are the same in each year group. The alternative hypothesis is that the parameter in 2008 was lower than in 2012. I’m setting a significance level of 0.05.

One feature of this dataset is that the 2008 votes and the 2012 votes are paired, since they both refer to the same county. That is, the 2008 and 2012 values aren’t independent from each other. Some voting patterns may occur due to county-level demographics and local politics. We want to capture this pairing in our model.

\[ H_{0}: \mu_{2008} \ - \mu_{2012} = 0 \\ H_{A}: \mu_{2008} \ - \mu_{2012} < 0 \]

\[ Set\ \alpha = 0.05: \ Significance \ level \]

From two samples to one

For paired analyses, rather than considering the two variables separately, we consider a single variable of the difference. In this histogram of the difference most values are between minus ten and ten, with a few outliers.

sample_data <- dem_votes_potus_08_16 %>%
  mutate(diff = dem_percent_08 - dem_percent_12)
ggplot(sample_data, aes(x = diff)) +
  geom_histogram(binwidth = 1)

NA
head(sample_data$diff, 30)
 [1] -2.23387788  1.20418692 -0.86343547  1.94779306 -1.56068097  2.19284462  0.46573839 -1.95303233 -0.15685772  1.09746821 -1.23219534 -0.65191061  1.07898478
[14]  2.90689306 -1.40145860  5.98220437  2.10897226  1.89697848  3.26170252  0.98114752 -0.35486217  3.46370218  3.06243598  1.50691738  4.39727218  2.72474816
[27] -0.09605252  2.30883794  2.32793299  3.61597762

Calculate sample statistics of the difference

The sample mean, x-bar, is calculated on this difference. It is \(3.059\)

xbar_diff <- sample_data %>%
  summarise(xbar_diff = mean(diff)) %>%
  pull(xbar_diff)

xbar_diff
[1] 3.059585

Revised hypotheses

We can restate the hypotheses in terms of the single population mean, \(\mu_{diff}\) , being equal to or less than zero. The test statistic, \(t\), has a slightly simpler equation compared to the two sample case. We have one statistic, so the number of degrees of freedom is the number of rows in the sample minus one.

Old hypotheses

\[ H_{0}: \mu_{2008} \ - \mu_{2012} = 0 \\ H_{A}: \mu_{2008} \ - \mu_{2012} < 0 \]

New hypothesis

\[ H_{0}: \mu_{diff} = 0 \\ H_{A}: \mu_{diff} < 0 \]

Calculating the p-value

To calculate the test statistic, we need the number of rows in the dataset, 500. And we need the standard deviation of the differences. We already know \(\bar{x}\) , the mean of the differences. Assuming the null hypothesis is true means \(\mu_{diff}\) is zero.

\[ \ t = \frac{x_{diff} \ - \mu_{diff}}{\sqrt{\frac{s^2_{diff}}{n_{diff}}}} \]

n_diff <- nrow(sample_data)
n_diff
[1] 500
s_diff <- sample_data %>%
  summarise(sd_diff = sd(diff)) %>%
  pull(sd_diff)

s_diff
[1] 3.388767
t_stat <- (xbar_diff - 0) / sqrt(s_diff ^ 2 / n_diff)
t_stat
[1] 20.18859
degrees_of_freedom <- n_diff - 1

p_value <- pt(t_stat, df = degrees_of_freedom)
p_value
[1] 1

We now have everything we need to plug into the equation to calculate \(t\). It’s \(20.18\). The degrees of freedom are one less than \(n_{diff}\) at \(499\). Finally, we transform t with the t-distribution CDF. The p-value is \(1\). That means we accept the null hypothesis and reject the alternative hypothesis that the Democrat candidate got a smaller percentage of the vote in 2008 compared to 2012.

Testing differences between two means using t.test()

That was a lot of calculating. Fortunately, there’s an easier way using t.test(). It works with vectors, so the first argument is the vector of differences. The type of alternative hypothesis can be two-sided, less or greater. Finally, you specify the value of \(\mu_{diff}\) from the null hypothesis. Zero is the default, so strictly-speaking we didn’t need to specify it. Here’s the output. You should recognize the value of the test statistic and the degrees of freedom, as well as \(\bar{x}\) on the last line. The p-value is written as “less 1”. p-values smaller than this are less reliable due to computational accuracy constraints, but it’s the same number we calculated before.

t.test(
  # Vector of differences
  sample_data$diff,
  # Choose between "two sided", "less", "greater"
  alternative = "less",
  # Null hypothesis population parameter
  mu = 0
  )

    One Sample t-test

data:  sample_data$diff
t = 20.189, df = 499, p-value = 1
alternative hypothesis: true mean is less than 0
95 percent confidence interval:
     -Inf 3.309327
sample estimates:
mean of x 
 3.059585 

t-test() with paired = TRUE

There’s a variation of t.test() for paired data that requires even less work. Rather than calculating the difference between the two paired variables, you can just pass them both directly to t.test() and set paired to TRUE. Notice that all the numbers are the same.

t.test(sample_data$dem_percent_08, sample_data$dem_percent_12, 
       alternative = "less", mu = 0, paired = TRUE)

    Paired t-test

data:  sample_data$dem_percent_08 and sample_data$dem_percent_12
t = 20.189, df = 499, p-value = 1
alternative hypothesis: true mean difference is less than 0
95 percent confidence interval:
     -Inf 3.309327
sample estimates:
mean difference 
       3.059585 

Unpaired t.test()

If we don’t set paired = TRUE and instead performed an unpaired t-test, then the numbers change. The test statistic is closer to one, there are more degrees of freedom, and the p-value is much larger. Performing an unpaired t-test increases the chance of a false negative error.

t.test(x = sample_data$dem_percent_08, y = sample_data$dem_percent_12,
       alternative = "less", mu = 0)

    Welch Two Sample t-test

data:  sample_data$dem_percent_08 and sample_data$dem_percent_12
t = 3.3584, df = 994.6, p-value = 0.9996
alternative hypothesis: true difference in means is less than 0
95 percent confidence interval:
     -Inf 4.559485
sample estimates:
mean of x mean of y 
 41.84253  38.78294 

Visualizing the difference

Before you start running hypothesis tests, it’s a great idea to perform some exploratory data analysis. That is, calculating summary statistics and visualizing distributions.

Here, we’ll look at the proportion of county-level votes for the Democratic candidate in 2012 and 2016, dem_votes_potus_12_16. Since the counties are the same in both years, these samples are paired. The columns containing the samples are dem_percent_12 and dem_percent_16.

# Calculate the differences from 2012 to 2016
sample_dem_data <- dem_votes_potus_08_16 %>%
  select(state, county, dem_percent_12, dem_percent_16) %>%
  mutate(diff = dem_percent_12 - dem_percent_16)

sample_dem_data
# Find mean & standard deviations of differences
diff_stats <- sample_dem_data %>%
  summarise(xbar_diff = mean(diff), s_diff = sd(diff))

# See the results
diff_stats
# Using sample_dem_data, plot diff as a histogram
  ggplot(sample_dem_data, aes(diff)) + 
    geom_histogram(binwidth = 1)

Using t.test()

Manually calculating test statistics and transforming them with a CDF to get a p-value is a lot of effort to do every time we need to compare two sample means. The comparison of two sample means is called a t-test, and R has a t.test() function to accomplish it. This function provides some flexibility in how you perform the test.

Now, we’ll explore the difference between the proportion of county-level votes for the Democratic candidate in 2012 and 2016.

# Conduct a t-test on diff
test_results <- t.test(sample_dem_data$diff, alternative = "greater", mu = 0)

# See the results
test_results

    One Sample t-test

data:  sample_dem_data$diff
t = 30.298, df = 499, p-value < 2.2e-16
alternative hypothesis: true mean is greater than 0
95 percent confidence interval:
 6.45787     Inf
sample estimates:
mean of x 
 6.829313 
# Conduct a paired t-test on dem_percent_12 and dem_percent_16
test_results <- t.test(sample_dem_data$dem_percent_12, sample_dem_data$dem_percent_16, alternative = "greater", mu = 0, paired = TRUE)

# See the results
test_results

    Paired t-test

data:  sample_dem_data$dem_percent_12 and sample_dem_data$dem_percent_16
t = 30.298, df = 499, p-value < 2.2e-16
alternative hypothesis: true mean difference is greater than 0
95 percent confidence interval:
 6.45787     Inf
sample estimates:
mean difference 
       6.829313 

What is the correct decision from the t-test assuming \(\alpha \ = 0.001\) ?

Reject the null hypothesis

Compare the paired t-test to an (inappropriate) unpaired test on the same data.

How does the p-value change?

# Conduct a t-test on diff
test_results <- t.test(x=sample_dem_data$dem_percent_12, y=sample_dem_data$dem_percent_16, alternative = "greater", mu = 0)
test_results

    Welch Two Sample t-test

data:  sample_dem_data$dem_percent_12 and sample_dem_data$dem_percent_16
t = 7.1816, df = 997.19, p-value = 6.732e-13
alternative hypothesis: true difference in means is greater than 0
95 percent confidence interval:
 5.263684      Inf
sample estimates:
mean of x mean of y 
 38.78294  31.95363 

The p-value from de unpaired test is greater than the p-value from the paired test

END

LS0tDQp0aXRsZTogIlBhaXJlZCB0LXRlc3RzIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQpkYXRlOiAyMDI0LTAzLTE4DQphdXRob3I6IEp1YW4gRmVybmFuZG8gTW9zcXVlcmEgQXJhdWpvDQotLS0NCg0KIyMjICoqVVMgRGVtb2NyYXQgcHJlc2lkZW50cyBkYXRhc2V0KioNCg0KSGVyZSdzIGEgZGF0YXNldCBvZiBVUyBwcmVzaWRlbnRpYWwgZWxlY3Rpb25zLiBFYWNoIHJvdyByZXByZXNlbnRzIGEgcHJlc2lkZW50aWFsIGVsZWN0aW9uIGF0IHRoZSBjb3VudHkgbGV2ZWwuIFRoZSB2YXJpYWJsZXMgaW4gdGhlIGRhdGFzZXQgYXJlIHRoZSBVUyBzdGF0ZSwgdGhlIGNvdW50eSB3aXRoaW4gdGhhdCBzdGF0ZSwgYW5kIHRoZSBwZXJjZW50YWdlIG9mIHZvdGVzIHRoYXQgd2VudCB0byB0aGUgRGVtb2NyYXQgY2FuZGlkYXRlIGluIDIwMDgsIDIwMTIsIGFuZCBpbiAyMDE2Lg0KDQpgYGB7cn0NCiMgTG9hZCBsaWJyYXJpZXMNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShmc3QpDQpsaWJyYXJ5KHRpYmJsZSkNCmxpYnJhcnkocmVhZHIpDQpgYGANCg0KYGBge3IgZWNobz1GQUxTRX0NCnVzZWxlY3RfcGF0aCA8LSAiQzovVXNlcnMvSnVhbkZlciBNb3NxdWVyYS9Eb2N1bWVudHMvZGF0YXNldHMvZGVtX2NvdW50eV9wcmVzX2pvaW5lZC5mc3QiDQpgYGANCg0KYGBge3J9DQpkZW1fdm90ZXNfcG90dXNfMDhfMTYgPC0gcmVhZF9mc3QodXNlbGVjdF9wYXRoKQ0KZGVtX3ZvdGVzX3BvdHVzXzA4XzE2DQpjb2xuYW1lcyhkZW1fdm90ZXNfcG90dXNfMDhfMTYpDQpgYGANCg0KIyMjICoqSHlwb3RoZXNlcyoqDQoNCk9uZSBxdWVzdGlvbiBpcyB3aGV0aGVyIHRoZSBwZXJjZW50YWdlIG9mIHZvdGVzIGdpdmVuIHRvIHRoZSBSZXB1YmxpY2FuIGNhbmRpZGF0ZSAqKndhcyBsb3dlciBpbiAyMDA4IGNvbXBhcmVkIHRvIDIwMTIqKi4gVG8gdGVzdCB0aGlzLCB3ZSBmb3JtIHRoZSBoeXBvdGhlc2VzLiBBcyBiZWZvcmUsICoqdGhlIG51bGwgaHlwb3RoZXNpcyBpcyB0aGF0IG91ciBodW5jaCBpcyB3cm9uZyoqLCBhbmQgdGhhdCB0aGUgcG9wdWxhdGlvbiBwYXJhbWV0ZXJzIGFyZSB0aGUgc2FtZSBpbiBlYWNoIHllYXIgZ3JvdXAuIFQqKmhlIGFsdGVybmF0aXZlIGh5cG90aGVzaXMgaXMgdGhhdCB0aGUgcGFyYW1ldGVyIGluIDIwMDggd2FzIGxvd2VyIHRoYW4gaW4gMjAxMioqLiBJJ20gc2V0dGluZyBhIHNpZ25pZmljYW5jZSBsZXZlbCBvZiAqKjAuMDUqKi4NCg0KT25lIGZlYXR1cmUgb2YgdGhpcyBkYXRhc2V0IGlzIHRoYXQgKip0aGUgMjAwOCB2b3RlcyBhbmQgdGhlIDIwMTIgdm90ZXMgYXJlIHBhaXJlZCoqLCBzaW5jZSB0aGV5IGJvdGggcmVmZXIgdG8gdGhlIHNhbWUgY291bnR5LiBUaGF0IGlzLCB0aGUgMjAwOCBhbmQgMjAxMiB2YWx1ZXMgYXJlbid0IGluZGVwZW5kZW50IGZyb20gZWFjaCBvdGhlci4gU29tZSB2b3RpbmcgcGF0dGVybnMgbWF5IG9jY3VyIGR1ZSB0byBjb3VudHktbGV2ZWwgZGVtb2dyYXBoaWNzIGFuZCBsb2NhbCBwb2xpdGljcy4gV2Ugd2FudCB0byBjYXB0dXJlIHRoaXMgcGFpcmluZyBpbiBvdXIgbW9kZWwuDQoNCiQkDQpIX3swfTogXG11X3syMDA4fSBcIC0gXG11X3syMDEyfSA9IDANClxcIEhfe0F9OiBcbXVfezIwMDh9IFwgLSBcbXVfezIwMTJ9IDwgMA0KJCQNCg0KJCQNClNldFwgXGFscGhhID0gMC4wNTogXCBTaWduaWZpY2FuY2UgXCBsZXZlbA0KJCQNCg0KIyMjICoqRnJvbSB0d28gc2FtcGxlcyB0byBvbmUqKg0KDQpGb3IgcGFpcmVkIGFuYWx5c2VzLCByYXRoZXIgdGhhbiBjb25zaWRlcmluZyB0aGUgdHdvIHZhcmlhYmxlcyBzZXBhcmF0ZWx5LCB3ZSBjb25zaWRlciBhIHNpbmdsZSB2YXJpYWJsZSBvZiB0aGUgZGlmZmVyZW5jZS4gSW4gdGhpcyBoaXN0b2dyYW0gb2YgdGhlIGRpZmZlcmVuY2UgbW9zdCB2YWx1ZXMgYXJlIGJldHdlZW4gbWludXMgdGVuIGFuZCB0ZW4sIHdpdGggYSBmZXcgb3V0bGllcnMuDQoNCmBgYHtyfQ0Kc2FtcGxlX2RhdGEgPC0gZGVtX3ZvdGVzX3BvdHVzXzA4XzE2ICU+JQ0KICBtdXRhdGUoZGlmZiA9IGRlbV9wZXJjZW50XzA4IC0gZGVtX3BlcmNlbnRfMTIpDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3Qoc2FtcGxlX2RhdGEsIGFlcyh4ID0gZGlmZikpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxKQ0KICANCmBgYA0KDQpgYGB7cn0NCmhlYWQoc2FtcGxlX2RhdGEkZGlmZiwgMzApDQpgYGANCg0KIyMjICoqQ2FsY3VsYXRlIHNhbXBsZSBzdGF0aXN0aWNzIG9mIHRoZSBkaWZmZXJlbmNlKioNCg0KVGhlIHNhbXBsZSBtZWFuLCBgeC1iYXJgLCBpcyBjYWxjdWxhdGVkIG9uIHRoaXMgZGlmZmVyZW5jZS4gSXQgaXMgJDMuMDU5JA0KDQpgYGB7cn0NCnhiYXJfZGlmZiA8LSBzYW1wbGVfZGF0YSAlPiUNCiAgc3VtbWFyaXNlKHhiYXJfZGlmZiA9IG1lYW4oZGlmZikpICU+JQ0KICBwdWxsKHhiYXJfZGlmZikNCg0KeGJhcl9kaWZmDQpgYGANCg0KIyMjICoqUmV2aXNlZCBoeXBvdGhlc2VzKioNCg0KV2UgY2FuIHJlc3RhdGUgdGhlIGh5cG90aGVzZXMgaW4gdGVybXMgb2YgdGhlIHNpbmdsZSBwb3B1bGF0aW9uIG1lYW4sICRcbXVfe2RpZmZ9JCAsIGJlaW5nICoqZXF1YWwgdG8gb3IgbGVzcyB0aGFuIHplcm8qKi4gVGhlIHRlc3Qgc3RhdGlzdGljLCAkdCQsIGhhcyBhIHNsaWdodGx5IHNpbXBsZXIgZXF1YXRpb24gY29tcGFyZWQgdG8gdGhlIHR3byBzYW1wbGUgY2FzZS4gV2UgaGF2ZSBvbmUgc3RhdGlzdGljLCBzbyB0aGUgbnVtYmVyIG9mIGRlZ3JlZXMgb2YgZnJlZWRvbSBpcyB0aGUgbnVtYmVyIG9mIHJvd3MgaW4gdGhlIHNhbXBsZSBtaW51cyBvbmUuDQoNCiMjIyMgKipPbGQgaHlwb3RoZXNlcyoqDQoNCiQkDQpIX3swfTogXG11X3syMDA4fSBcIC0gXG11X3syMDEyfSA9IDANClxcIEhfe0F9OiBcbXVfezIwMDh9IFwgLSBcbXVfezIwMTJ9IDwgMA0KJCQNCg0KIyMjIyAqKk5ldyBoeXBvdGhlc2lzKioNCg0KJCQNCkhfezB9OiBcbXVfe2RpZmZ9ID0gMCBcXA0KSF97QX06IFxtdV97ZGlmZn0gPCAwDQokJA0KDQojIyMgKipDYWxjdWxhdGluZyB0aGUgcC12YWx1ZSoqDQoNClRvIGNhbGN1bGF0ZSB0aGUgdGVzdCBzdGF0aXN0aWMsIHdlIG5lZWQgdGhlIG51bWJlciBvZiByb3dzIGluIHRoZSBkYXRhc2V0LCA1MDAuIEFuZCB3ZSBuZWVkIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIGRpZmZlcmVuY2VzLiBXZSBhbHJlYWR5IGtub3cgJFxiYXJ7eH0kICwgdGhlIG1lYW4gb2YgdGhlIGRpZmZlcmVuY2VzLiBBc3N1bWluZyB0aGUgbnVsbCBoeXBvdGhlc2lzIGlzIHRydWUgbWVhbnMgJFxtdV97ZGlmZn0kIGlzIHplcm8uDQoNCiQkDQpcIHQgPSBcZnJhY3t4X3tkaWZmfSBcIC0gXG11X3tkaWZmfX17XHNxcnR7XGZyYWN7c14yX3tkaWZmfX17bl97ZGlmZn19fX0NCiQkDQoNCmBgYHtyfQ0Kbl9kaWZmIDwtIG5yb3coc2FtcGxlX2RhdGEpDQpuX2RpZmYNCmBgYA0KDQpgYGB7cn0NCnNfZGlmZiA8LSBzYW1wbGVfZGF0YSAlPiUNCiAgc3VtbWFyaXNlKHNkX2RpZmYgPSBzZChkaWZmKSkgJT4lDQogIHB1bGwoc2RfZGlmZikNCg0Kc19kaWZmDQpgYGANCg0KYGBge3J9DQp0X3N0YXQgPC0gKHhiYXJfZGlmZiAtIDApIC8gc3FydChzX2RpZmYgXiAyIC8gbl9kaWZmKQ0KdF9zdGF0DQpgYGANCg0KYGBge3J9DQpkZWdyZWVzX29mX2ZyZWVkb20gPC0gbl9kaWZmIC0gMQ0KDQpwX3ZhbHVlIDwtIHB0KHRfc3RhdCwgZGYgPSBkZWdyZWVzX29mX2ZyZWVkb20pDQpwX3ZhbHVlDQpgYGANCg0KV2Ugbm93IGhhdmUgZXZlcnl0aGluZyB3ZSBuZWVkIHRvIHBsdWcgaW50byB0aGUgZXF1YXRpb24gdG8gY2FsY3VsYXRlICR0JC4gSXQncyAkMjAuMTgkLiBUaGUgZGVncmVlcyBvZiBmcmVlZG9tIGFyZSBvbmUgbGVzcyB0aGFuICRuX3tkaWZmfSQgYXQgJDQ5OSQuIEZpbmFsbHksIHdlIHRyYW5zZm9ybSB0IHdpdGggdGhlIHQtZGlzdHJpYnV0aW9uIENERi4gVGhlIHAtdmFsdWUgaXMgJDEkLiBUaGF0IG1lYW5zIHdlIGFjY2VwdCB0aGUgbnVsbCBoeXBvdGhlc2lzIGFuZCByZWplY3QgdGhlIGFsdGVybmF0aXZlIGh5cG90aGVzaXMgdGhhdCB0aGUgRGVtb2NyYXQgY2FuZGlkYXRlIGdvdCBhIHNtYWxsZXIgcGVyY2VudGFnZSBvZiB0aGUgdm90ZSBpbiAyMDA4IGNvbXBhcmVkIHRvIDIwMTIuDQoNCiMjIyAqKlRlc3RpbmcgZGlmZmVyZW5jZXMgYmV0d2VlbiB0d28gbWVhbnMgdXNpbmcgdC50ZXN0KCkqKg0KDQpUaGF0IHdhcyBhIGxvdCBvZiBjYWxjdWxhdGluZy4gRm9ydHVuYXRlbHksIHRoZXJlJ3MgYW4gZWFzaWVyIHdheSB1c2luZyBgdC50ZXN0KClgLiBJdCB3b3JrcyB3aXRoIHZlY3RvcnMsIHNvIHRoZSBmaXJzdCBhcmd1bWVudCBpcyB0aGUgdmVjdG9yIG9mIGRpZmZlcmVuY2VzLiBUaGUgKip0eXBlIG9mIGFsdGVybmF0aXZlIGh5cG90aGVzaXMgY2FuIGJlIHR3by1zaWRlZCwgbGVzcyBvciBncmVhdGVyKiouIEZpbmFsbHksIHlvdSBzcGVjaWZ5IHRoZSB2YWx1ZSBvZiAkXG11X3tkaWZmfSQgZnJvbSB0aGUgbnVsbCBoeXBvdGhlc2lzLiBaZXJvIGlzIHRoZSBkZWZhdWx0LCBzbyBzdHJpY3RseS1zcGVha2luZyB3ZSBkaWRuJ3QgbmVlZCB0byBzcGVjaWZ5IGl0LiBIZXJlJ3MgdGhlIG91dHB1dC4gWW91IHNob3VsZCByZWNvZ25pemUgdGhlIHZhbHVlIG9mIHRoZSB0ZXN0IHN0YXRpc3RpYyBhbmQgdGhlIGRlZ3JlZXMgb2YgZnJlZWRvbSwgYXMgd2VsbCBhcyAkXGJhcnt4fSQgb24gdGhlIGxhc3QgbGluZS4gVGhlICoqcC12YWx1ZSoqIGlzIHdyaXR0ZW4gYXMgIioqKmxlc3MgMSoqKiIuICoqcC12YWx1ZXMqKiBzbWFsbGVyIHRoYW4gdGhpcyBhcmUgbGVzcyByZWxpYWJsZSBkdWUgdG8gY29tcHV0YXRpb25hbCBhY2N1cmFjeSBjb25zdHJhaW50cywgYnV0IGl0J3MgdGhlIHNhbWUgbnVtYmVyIHdlIGNhbGN1bGF0ZWQgYmVmb3JlLg0KDQpgYGB7cn0NCnQudGVzdCgNCiAgIyBWZWN0b3Igb2YgZGlmZmVyZW5jZXMNCiAgc2FtcGxlX2RhdGEkZGlmZiwNCiAgIyBDaG9vc2UgYmV0d2VlbiAidHdvIHNpZGVkIiwgImxlc3MiLCAiZ3JlYXRlciINCiAgYWx0ZXJuYXRpdmUgPSAibGVzcyIsDQogICMgTnVsbCBoeXBvdGhlc2lzIHBvcHVsYXRpb24gcGFyYW1ldGVyDQogIG11ID0gMA0KICApDQpgYGANCg0KIyMjICoqYHQtdGVzdCgpYCB3aXRoIHBhaXJlZCA9IFRSVUUqKg0KDQpUaGVyZSdzIGEgdmFyaWF0aW9uIG9mIGB0LnRlc3QoKWAgZm9yIHBhaXJlZCBkYXRhIHRoYXQgcmVxdWlyZXMgZXZlbiBsZXNzIHdvcmsuIFJhdGhlciB0aGFuIGNhbGN1bGF0aW5nIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHR3byBwYWlyZWQgdmFyaWFibGVzLCB5b3UgY2FuIGp1c3QgcGFzcyB0aGVtIGJvdGggZGlyZWN0bHkgdG8gYHQudGVzdCgpYCBhbmQgc2V0IHBhaXJlZCB0byBUUlVFLiBOb3RpY2UgdGhhdCBhbGwgdGhlIG51bWJlcnMgYXJlIHRoZSBzYW1lLg0KDQpgYGB7cn0NCnQudGVzdChzYW1wbGVfZGF0YSRkZW1fcGVyY2VudF8wOCwgc2FtcGxlX2RhdGEkZGVtX3BlcmNlbnRfMTIsIA0KICAgICAgIGFsdGVybmF0aXZlID0gImxlc3MiLCBtdSA9IDAsIHBhaXJlZCA9IFRSVUUpDQpgYGANCg0KIyMjICoqVW5wYWlyZWQgYHQudGVzdCgpYCoqDQoNCklmIHdlIGRvbid0IHNldCBgcGFpcmVkID0gVFJVRWAgYW5kIGluc3RlYWQgcGVyZm9ybWVkIGFuIHVucGFpcmVkIHQtdGVzdCwgdGhlbiB0aGUgbnVtYmVycyBjaGFuZ2UuIFRoZSB0ZXN0IHN0YXRpc3RpYyBpcyBjbG9zZXIgdG8gb25lLCB0aGVyZSBhcmUgbW9yZSBkZWdyZWVzIG9mIGZyZWVkb20sIGFuZCB0aGUgcC12YWx1ZSBpcyBtdWNoIGxhcmdlci4gKipQZXJmb3JtaW5nIGFuIHVucGFpcmVkIHQtdGVzdCBpbmNyZWFzZXMgdGhlIGNoYW5jZSBvZiBhIGZhbHNlIG5lZ2F0aXZlIGVycm9yKiouDQoNCmBgYHtyfQ0KdC50ZXN0KHggPSBzYW1wbGVfZGF0YSRkZW1fcGVyY2VudF8wOCwgeSA9IHNhbXBsZV9kYXRhJGRlbV9wZXJjZW50XzEyLA0KICAgICAgIGFsdGVybmF0aXZlID0gImxlc3MiLCBtdSA9IDApDQpgYGANCg0KIyMjICoqVmlzdWFsaXppbmcgdGhlIGRpZmZlcmVuY2UqKg0KDQpCZWZvcmUgeW91IHN0YXJ0IHJ1bm5pbmcgaHlwb3RoZXNpcyB0ZXN0cywgaXQncyBhIGdyZWF0IGlkZWEgdG8gcGVyZm9ybSBzb21lIGV4cGxvcmF0b3J5IGRhdGEgYW5hbHlzaXMuIFRoYXQgaXMsIGNhbGN1bGF0aW5nIHN1bW1hcnkgc3RhdGlzdGljcyBhbmQgdmlzdWFsaXppbmcgZGlzdHJpYnV0aW9ucy4NCg0KSGVyZSwgd2UnbGwgbG9vayBhdCB0aGUgcHJvcG9ydGlvbiBvZiBjb3VudHktbGV2ZWwgdm90ZXMgZm9yIHRoZSBEZW1vY3JhdGljIGNhbmRpZGF0ZSBpbiAyMDEyIGFuZCAyMDE2LCBgZGVtX3ZvdGVzX3BvdHVzXzEyXzE2YC4gU2luY2UgdGhlIGNvdW50aWVzIGFyZSB0aGUgc2FtZSBpbiBib3RoIHllYXJzLCB0aGVzZSBzYW1wbGVzIGFyZSBwYWlyZWQuIFRoZSBjb2x1bW5zIGNvbnRhaW5pbmcgdGhlIHNhbXBsZXMgYXJlIGBkZW1fcGVyY2VudF8xMmAgYW5kIGBkZW1fcGVyY2VudF8xNmAuDQoNCmBgYHtyfQ0KIyBDYWxjdWxhdGUgdGhlIGRpZmZlcmVuY2VzIGZyb20gMjAxMiB0byAyMDE2DQpzYW1wbGVfZGVtX2RhdGEgPC0gZGVtX3ZvdGVzX3BvdHVzXzA4XzE2ICU+JQ0KICBzZWxlY3Qoc3RhdGUsIGNvdW50eSwgZGVtX3BlcmNlbnRfMTIsIGRlbV9wZXJjZW50XzE2KSAlPiUNCiAgbXV0YXRlKGRpZmYgPSBkZW1fcGVyY2VudF8xMiAtIGRlbV9wZXJjZW50XzE2KQ0KDQpzYW1wbGVfZGVtX2RhdGENCmBgYA0KDQpgYGB7cn0NCiMgRmluZCBtZWFuICYgc3RhbmRhcmQgZGV2aWF0aW9ucyBvZiBkaWZmZXJlbmNlcw0KZGlmZl9zdGF0cyA8LSBzYW1wbGVfZGVtX2RhdGEgJT4lDQogIHN1bW1hcmlzZSh4YmFyX2RpZmYgPSBtZWFuKGRpZmYpLCBzX2RpZmYgPSBzZChkaWZmKSkNCg0KIyBTZWUgdGhlIHJlc3VsdHMNCmRpZmZfc3RhdHMNCmBgYA0KDQpgYGB7cn0NCiMgVXNpbmcgc2FtcGxlX2RlbV9kYXRhLCBwbG90IGRpZmYgYXMgYSBoaXN0b2dyYW0NCiAgZ2dwbG90KHNhbXBsZV9kZW1fZGF0YSwgYWVzKGRpZmYpKSArIA0KICAgIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSkNCmBgYA0KDQojIyMgKipVc2luZyB0LnRlc3QoKSoqDQoNCk1hbnVhbGx5IGNhbGN1bGF0aW5nIHRlc3Qgc3RhdGlzdGljcyBhbmQgdHJhbnNmb3JtaW5nIHRoZW0gd2l0aCBhIENERiB0byBnZXQgYSAqKnAtdmFsdWUqKiBpcyBhIGxvdCBvZiBlZmZvcnQgdG8gZG8gZXZlcnkgdGltZSB3ZSBuZWVkIHRvIGNvbXBhcmUgdHdvIHNhbXBsZSBtZWFucy4gVGhlIGNvbXBhcmlzb24gb2YgdHdvIHNhbXBsZSBtZWFucyBpcyBjYWxsZWQgYSB0LXRlc3QsIGFuZCBSIGhhcyBhIGB0LnRlc3QoKWAgZnVuY3Rpb24gdG8gYWNjb21wbGlzaCBpdC4gVGhpcyBmdW5jdGlvbiBwcm92aWRlcyBzb21lIGZsZXhpYmlsaXR5IGluIGhvdyB5b3UgcGVyZm9ybSB0aGUgdGVzdC4NCg0KTm93LCB3ZSdsbCBleHBsb3JlIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHByb3BvcnRpb24gb2YgY291bnR5LWxldmVsIHZvdGVzIGZvciB0aGUgRGVtb2NyYXRpYyBjYW5kaWRhdGUgaW4gMjAxMiBhbmQgMjAxNi4NCg0KYGBge3J9DQojIENvbmR1Y3QgYSB0LXRlc3Qgb24gZGlmZg0KdGVzdF9yZXN1bHRzIDwtIHQudGVzdChzYW1wbGVfZGVtX2RhdGEkZGlmZiwgYWx0ZXJuYXRpdmUgPSAiZ3JlYXRlciIsIG11ID0gMCkNCg0KIyBTZWUgdGhlIHJlc3VsdHMNCnRlc3RfcmVzdWx0cw0KYGBgDQoNCmBgYHtyfQ0KIyBDb25kdWN0IGEgcGFpcmVkIHQtdGVzdCBvbiBkZW1fcGVyY2VudF8xMiBhbmQgZGVtX3BlcmNlbnRfMTYNCnRlc3RfcmVzdWx0cyA8LSB0LnRlc3Qoc2FtcGxlX2RlbV9kYXRhJGRlbV9wZXJjZW50XzEyLCBzYW1wbGVfZGVtX2RhdGEkZGVtX3BlcmNlbnRfMTYsIGFsdGVybmF0aXZlID0gImdyZWF0ZXIiLCBtdSA9IDAsIHBhaXJlZCA9IFRSVUUpDQoNCiMgU2VlIHRoZSByZXN1bHRzDQp0ZXN0X3Jlc3VsdHMNCmBgYA0KDQojIyMgKipXaGF0IGlzIHRoZSBjb3JyZWN0IGRlY2lzaW9uIGZyb20gdGhlIHQtdGVzdCBhc3N1bWluZyoqICRcYWxwaGEgXCA9IDAuMDAxJCA/DQoNCioqUmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMqKg0KDQojIyMgQ29tcGFyZSB0aGUgcGFpcmVkIHQtdGVzdCB0byBhbiAoaW5hcHByb3ByaWF0ZSkgdW5wYWlyZWQgdGVzdCBvbiB0aGUgc2FtZSBkYXRhLg0KDQoqKkhvdyBkb2VzIHRoZSBwLXZhbHVlIGNoYW5nZT8qKg0KDQpgYGB7cn0NCiMgQ29uZHVjdCBhIHQtdGVzdCBvbiBkaWZmDQp0ZXN0X3Jlc3VsdHMgPC0gdC50ZXN0KHg9c2FtcGxlX2RlbV9kYXRhJGRlbV9wZXJjZW50XzEyLCB5PXNhbXBsZV9kZW1fZGF0YSRkZW1fcGVyY2VudF8xNiwgYWx0ZXJuYXRpdmUgPSAiZ3JlYXRlciIsIG11ID0gMCkNCnRlc3RfcmVzdWx0cw0KYGBgDQoNCioqVGhlIHAtdmFsdWUgZnJvbSBkZSB1bnBhaXJlZCB0ZXN0IGlzIGdyZWF0ZXIgdGhhbiB0aGUgcC12YWx1ZSBmcm9tIHRoZSBwYWlyZWQgdGVzdCoqDQoNCiMjIyBFTkQNCg==