How to use this document. Run the code along with me. Comments start with #. Each section mirrors the live lab; code chunks show the command and its output together.

Today’s plan

  1. Clean environment + setup
  2. Explore the CollegeDistance dataset
  3. Proportion test: prop.test
  4. Simple linear regression
  5. Multiple regression
  6. Quick practice

1 Clean Environment + Setup

rm(list = ls())   # clean environment

# Install and load packages
# install.packages("AER")
library(AER)
library(dplyr)
library(ggplot2)

2 Explore the CollegeDistance Data

The dataset includes information on high school graduates’ test scores, family background, and distance to college. It ships with the AER package, so no external file is needed.

Key variables

  • gender — student gender (Factor: “male”, “female”)
  • ethnicity — student ethnicity (Factor: “other”, “afam”, “hispanic”)
  • score — student test score (Numeric)
  • fcollege — father attended college (Factor: “no”, “yes”)
  • mcollege — mother attended college (Factor: “no”, “yes”)
  • home — student lives at home (Factor: “no”, “yes”)
  • urban — lives in an urban area (Factor: “no”, “yes”)
  • unemp — county unemployment rate (%) (Numeric)
  • wage — average wage in county (Numeric)
  • distance — distance (in miles) to nearest 4-year college (Numeric)
  • tuition — relative tuition cost at 4-year colleges (Numeric)
  • education — years of schooling completed (Numeric)
  • income — family income level (Factor: “low”, “high”)
  • region — region of the U.S. (Factor: “other”, “west”)
# Load the dataset from the AER package
data("CollegeDistance")
college <- CollegeDistance
remove(CollegeDistance)  # remove duplicate
# View data structure
str(college)
#> 'data.frame':    4739 obs. of  14 variables:
#>  $ gender   : Factor w/ 2 levels "male","female": 1 2 1 1 2 1 2 2 1 2 ...
#>  $ ethnicity: Factor w/ 3 levels "other","afam",..: 1 1 1 2 1 1 1 1 1 1 ...
#>  $ score    : num  39.2 48.9 48.7 40.4 40.5 ...
#>  $ fcollege : Factor w/ 2 levels "no","yes": 2 1 1 1 1 1 1 1 2 1 ...
#>  $ mcollege : Factor w/ 2 levels "no","yes": 1 1 1 1 1 1 1 1 1 1 ...
#>  $ home     : Factor w/ 2 levels "no","yes": 2 2 2 2 1 2 2 2 2 2 ...
#>  $ urban    : Factor w/ 2 levels "no","yes": 2 2 2 2 2 2 1 1 2 2 ...
#>  $ unemp    : num  6.2 6.2 6.2 6.2 5.6 ...
#>  $ wage     : num  8.09 8.09 8.09 8.09 8.09 ...
#>  $ distance : num  0.2 0.2 0.2 0.2 0.4 ...
#>  $ tuition  : num  0.889 0.889 0.889 0.889 0.889 ...
#>  $ education: num  12 12 12 12 13 12 13 15 13 15 ...
#>  $ income   : Factor w/ 2 levels "low","high": 2 1 1 1 1 1 1 1 1 1 ...
#>  $ region   : Factor w/ 2 levels "other","west": 1 1 1 1 1 1 1 1 1 1 ...
#>  - attr(*, "datalabel")= chr ""
#>  - attr(*, "time.stamp")= chr "25 Oct 2002 16:44"
#>  - attr(*, "formats")= chr [1:14] "%9.0g" "%9.0g" "%9.0g" "%9.0g" ...
#>  - attr(*, "types")= int [1:14] 102 102 102 102 102 102 102 102 102 102 ...
#>  - attr(*, "val.labels")= chr [1:14] "" "" "" "" ...
#>  - attr(*, "var.labels")= chr [1:14] "" "" "" "" ...
#>  - attr(*, "version")= int 6
#>  - attr(*, "label.table")=List of 14
#>   ..$ : NULL
#>   ..$ : NULL
#>   ..$ : NULL
#>   ..$ : NULL
#>   ..$ : NULL
#>   ..$ : NULL
#>   ..$ : NULL
#>   ..$ : NULL
#>   ..$ : NULL
#>   ..$ : NULL
#>   ..$ : NULL
#>   ..$ : NULL
#>   ..$ : NULL
#>   ..$ : NULL
# In RStudio you would run View(college); here we preview the first rows.
knitr::kable(head(college), caption = "First rows of the CollegeDistance data")
First rows of the CollegeDistance data
gender ethnicity score fcollege mcollege home urban unemp wage distance tuition education income region
male other 39.15 yes no yes yes 6.2 8.09 0.2 0.88915 12 high other
female other 48.87 no no yes yes 6.2 8.09 0.2 0.88915 12 low other
male other 48.74 no no yes yes 6.2 8.09 0.2 0.88915 12 low other
male afam 40.40 no no yes yes 6.2 8.09 0.2 0.88915 12 low other
female other 40.48 no no no yes 5.6 8.09 0.4 0.88915 13 low other
male other 54.71 no no yes yes 5.6 8.09 0.4 0.88915 12 low other

3 Proportion Test: prop.test

Research question. Is the proportion of high-income students different from 0.5?

# Count number of 'high' income students
x_high <- sum(college$income == "high")

# Total number of students
n_total <- nrow(college)

Two-sided test (\(H_0\): true proportion of high-income students \(= 0.5\); \(H_1\): true proportion \(\neq 0.5\)). The test statistic (\(X^2\)) and p-value tell us whether the observed proportion is significantly different from 0.5.

prop_test_result <- prop.test(x = x_high, n = n_total, p = 0.5)
prop_test_result
#> 
#>  1-sample proportions test with continuity correction
#> 
#> data:  x_high out of n_total, null probability 0.5
#> X-squared = 850.83, df = 1, p-value < 2.2e-16
#> alternative hypothesis: true p is not equal to 0.5
#> 95 percent confidence interval:
#>  0.2752141 0.3012030
#> sample estimates:
#>         p 
#> 0.2880355

Check the 95% confidence interval.

prop_test_result$conf.int
#> [1] 0.2752141 0.3012030
#> attr(,"conf.level")
#> [1] 0.95

One-sided test — test whether the proportion of high-income students \(> 0.5\) (\(H_0\): \(p \leq 0.5\); \(H_1\): \(p > 0.5\)). If the p-value \(< 0.05\), we reject \(H_0\) and conclude the proportion is significantly greater than 0.5. The one-sided test is used when we have a directional hypothesis.

prop_test_one_sided <- prop.test(x = x_high, n = n_total, p = 0.5, alternative = "greater")
prop_test_one_sided
#> 
#>  1-sample proportions test with continuity correction
#> 
#> data:  x_high out of n_total, null probability 0.5
#> X-squared = 850.83, df = 1, p-value = 1
#> alternative hypothesis: true p is greater than 0.5
#> 95 percent confidence interval:
#>  0.2772343 1.0000000
#> sample estimates:
#>         p 
#> 0.2880355

4 Simple Linear Regression

Research question. Does distance to college affect test scores?

# Fit a simple regression model
model_1 <- lm(score ~ distance, data = college)
summary(model_1)
#> 
#> Call:
#> lm(formula = score ~ distance, data = college)
#> 
#> Residuals:
#>     Min      1Q  Median      3Q     Max 
#> -22.352  -6.924   0.203   6.813  22.101 
#> 
#> Coefficients:
#>             Estimate Std. Error t value Pr(>|t|)    
#> (Intercept) 51.35330    0.16034  320.27  < 2e-16 ***
#> distance    -0.25752    0.05491   -4.69 2.81e-06 ***
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> 
#> Residual standard error: 8.683 on 4737 degrees of freedom
#> Multiple R-squared:  0.004621,   Adjusted R-squared:  0.004411 
#> F-statistic: 21.99 on 1 and 4737 DF,  p-value: 2.815e-06

Confidence interval for the coefficients.

confint(model_1)
#>                  2.5 %     97.5 %
#> (Intercept) 51.0389556 51.6676422
#> distance    -0.3651712 -0.1498628

Interpretation.

  • Intercept: predicted test score when distance = 0.
  • Slope (distance): expected change in score for each additional mile.
  • Check the p-value to test \(H_0\): \(\beta_{\text{distance}} = 0\).

5 Multiple Regression

Research question. Does distance still matter after controlling for family background, income, and region?

model_2 <- lm(score ~ distance + fcollege + mcollege +
                home + urban + unemp + wage + tuition +
                education + income + region,
              data = college)
summary(model_2)
#> 
#> Call:
#> lm(formula = score ~ distance + fcollege + mcollege + home + 
#>     urban + unemp + wage + tuition + education + income + region, 
#>     data = college)
#> 
#> Residuals:
#>      Min       1Q   Median       3Q      Max 
#> -21.5003  -5.6451   0.0033   5.4572  22.7546 
#> 
#> Coefficients:
#>             Estimate Std. Error t value Pr(>|t|)    
#> (Intercept) 15.49630    1.19365  12.982  < 2e-16 ***
#> distance    -0.05115    0.05291  -0.967 0.333764    
#> fcollegeyes  1.92447    0.31524   6.105 1.11e-09 ***
#> mcollegeyes  0.94899    0.35420   2.679 0.007404 ** 
#> homeyes      1.43657    0.28806   4.987 6.35e-07 ***
#> urbanyes    -1.33062    0.27229  -4.887 1.06e-06 ***
#> unemp       -0.14297    0.04373  -3.269 0.001086 ** 
#> wage         0.47496    0.08860   5.361 8.68e-08 ***
#> tuition      3.16110    0.42604   7.420 1.38e-13 ***
#> education    2.01015    0.06457  31.133  < 2e-16 ***
#> incomehigh   0.31580    0.26308   1.200 0.230042    
#> regionwest   1.19619    0.33984   3.520 0.000436 ***
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> 
#> Residual standard error: 7.477 on 4727 degrees of freedom
#> Multiple R-squared:  0.2635, Adjusted R-squared:  0.2618 
#> F-statistic: 153.8 on 11 and 4727 DF,  p-value: < 2.2e-16

Interpretation.

  • Each coefficient shows the expected change in score for a one-unit change in that variable, holding the others constant.
  • Compare \(\beta_{\text{distance}}\) in model_1 vs. model_2: does the effect get smaller (suggesting confounding)?

6 Quick Practice

Q1) Proportion test. Is the proportion of high-income students different from 0.5? (\(H_0\): \(p = 0.5\); \(H_1\): \(p \neq 0.5\).) If p-value \(< 0.05\), conclude the proportion of high-income students is significantly different from 0.5.

x_high <- sum(college$income == "high")   # number of high-income students
n_total <- nrow(college)                  # total number of students

prop_test_q1 <- prop.test(x = x_high, n = n_total, p = 0.5)
prop_test_q1
#> 
#>  1-sample proportions test with continuity correction
#> 
#> data:  x_high out of n_total, null probability 0.5
#> X-squared = 850.83, df = 1, p-value < 2.2e-16
#> alternative hypothesis: true p is not equal to 0.5
#> 95 percent confidence interval:
#>  0.2752141 0.3012030
#> sample estimates:
#>         p 
#> 0.2880355

Q2) Proportion test. Is the proportion of students living at home greater than 70%? (\(H_0\): \(p \leq 0.7\); \(H_1\): \(p > 0.7\).) If p-value \(< 0.05\), conclude more than 70% of students live at home.

x_home <- sum(college$home == "yes")   # number of students living at home

prop_test_q2 <- prop.test(x = x_home, n = n_total, p = 0.7, alternative = "greater")
prop_test_q2
#> 
#>  1-sample proportions test with continuity correction
#> 
#> data:  x_home out of n_total, null probability 0.7
#> X-squared = 325.55, df = 1, p-value < 2.2e-16
#> alternative hypothesis: true p is greater than 0.7
#> 95 percent confidence interval:
#>  0.8107504 1.0000000
#> sample estimates:
#>         p 
#> 0.8202152

Q3) Multiple regression. Does family income predict students’ test scores after controlling for parents’ education, distance, home, and region? Which variables are statistically significant (\(p < 0.05\))? Are the effects of income and distance positive or negative?

model_q3 <- lm(score ~ income + fcollege + mcollege + distance + home + region, data = college)
summary(model_q3)
#> 
#> Call:
#> lm(formula = score ~ income + fcollege + mcollege + distance + 
#>     home + region, data = college)
#> 
#> Residuals:
#>      Min       1Q   Median       3Q      Max 
#> -22.6793  -6.4663   0.0954   6.3711  21.4955 
#> 
#> Coefficients:
#>             Estimate Std. Error t value Pr(>|t|)    
#> (Intercept) 47.94593    0.30943 154.950  < 2e-16 ***
#> incomehigh   1.52070    0.28892   5.263 1.48e-07 ***
#> fcollegeyes  3.77278    0.34438  10.955  < 2e-16 ***
#> mcollegeyes  2.14938    0.39110   5.496 4.10e-08 ***
#> distance    -0.13655    0.05309  -2.572   0.0101 *  
#> homeyes      2.19001    0.31774   6.893 6.20e-12 ***
#> regionwest  -0.62941    0.30327  -2.075   0.0380 *  
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> 
#> Residual standard error: 8.307 on 4732 degrees of freedom
#> Multiple R-squared:  0.08978,    Adjusted R-squared:  0.08862 
#> F-statistic: 77.79 on 6 and 4732 DF,  p-value: < 2.2e-16

7 Wrap-up

Key takeaways

  • Regression helps quantify relationships between variables.
  • Multiple regression controls for confounders.
  • Interaction terms test whether effects vary by group.
  • Always interpret coefficients in context!
LS0tCnRpdGxlOiAiTGFiIDEwIOKAlCBQcm9wb3J0aW9uIFRlc3RzICYgSW5mZXJlbmNlIGZvciBSZWdyZXNzaW9uIgpzdWJ0aXRsZTogIlF1YW50aXRhdGl2ZSBSZWFzb25pbmcgwrcgTEFCIDQxMyIKYXV0aG9yOiAiSW5zdHJ1Y3RvcjogU3ViaW4gTmEiCmRhdGU6ICJOb3ZlbWJlciAxMiwgMjAyNSIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0aGVtZTogZmxhdGx5CiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdG9jX2RlcHRoOiAyCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIGRmX3ByaW50OiBwYWdlZAogICAgY29kZV9kb3dubG9hZDogdHJ1ZQotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgZWNobyA9IFRSVUUsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLAogIGZpZy5hbGlnbiA9ICJjZW50ZXIiLCBmaWcud2lkdGggPSA3LCBmaWcuaGVpZ2h0ID0gNC4yLAogIGNvbW1lbnQgPSAiIz4iCikKYGBgCgo+ICoqSG93IHRvIHVzZSB0aGlzIGRvY3VtZW50LioqIFJ1biB0aGUgY29kZSBhbG9uZyB3aXRoIG1lLiBDb21tZW50cyBzdGFydCB3aXRoIGAjYC4KPiBFYWNoIHNlY3Rpb24gbWlycm9ycyB0aGUgbGl2ZSBsYWI7IGNvZGUgY2h1bmtzIHNob3cgdGhlIGNvbW1hbmQgYW5kIGl0cyBvdXRwdXQgdG9nZXRoZXIuCgoqKlRvZGF5J3MgcGxhbioqCgoxLiBDbGVhbiBlbnZpcm9ubWVudCArIHNldHVwCjIuIEV4cGxvcmUgdGhlIENvbGxlZ2VEaXN0YW5jZSBkYXRhc2V0CjMuIFByb3BvcnRpb24gdGVzdDogYHByb3AudGVzdGAKNC4gU2ltcGxlIGxpbmVhciByZWdyZXNzaW9uCjUuIE11bHRpcGxlIHJlZ3Jlc3Npb24KNi4gUXVpY2sgcHJhY3RpY2UKCi0tLQoKIyBDbGVhbiBFbnZpcm9ubWVudCArIFNldHVwCgpgYGB7ciBjbGVhbi1zZXR1cH0Kcm0obGlzdCA9IGxzKCkpICAgIyBjbGVhbiBlbnZpcm9ubWVudAoKIyBJbnN0YWxsIGFuZCBsb2FkIHBhY2thZ2VzCiMgaW5zdGFsbC5wYWNrYWdlcygiQUVSIikKbGlicmFyeShBRVIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKYGBgCgojIEV4cGxvcmUgdGhlIENvbGxlZ2VEaXN0YW5jZSBEYXRhCgpUaGUgZGF0YXNldCBpbmNsdWRlcyBpbmZvcm1hdGlvbiBvbiBoaWdoIHNjaG9vbCBncmFkdWF0ZXMnIHRlc3Qgc2NvcmVzLCBmYW1pbHkKYmFja2dyb3VuZCwgYW5kIGRpc3RhbmNlIHRvIGNvbGxlZ2UuIEl0IHNoaXBzIHdpdGggdGhlICoqQUVSKiogcGFja2FnZSwgc28gbm8KZXh0ZXJuYWwgZmlsZSBpcyBuZWVkZWQuCgoqKktleSB2YXJpYWJsZXMqKgoKLSBgZ2VuZGVyYCDigJQgc3R1ZGVudCBnZW5kZXIgKEZhY3RvcjogIm1hbGUiLCAiZmVtYWxlIikKLSBgZXRobmljaXR5YCDigJQgc3R1ZGVudCBldGhuaWNpdHkgKEZhY3RvcjogIm90aGVyIiwgImFmYW0iLCAiaGlzcGFuaWMiKQotIGBzY29yZWAg4oCUIHN0dWRlbnQgdGVzdCBzY29yZSAoTnVtZXJpYykKLSBgZmNvbGxlZ2VgIOKAlCBmYXRoZXIgYXR0ZW5kZWQgY29sbGVnZSAoRmFjdG9yOiAibm8iLCAieWVzIikKLSBgbWNvbGxlZ2VgIOKAlCBtb3RoZXIgYXR0ZW5kZWQgY29sbGVnZSAoRmFjdG9yOiAibm8iLCAieWVzIikKLSBgaG9tZWAg4oCUIHN0dWRlbnQgbGl2ZXMgYXQgaG9tZSAoRmFjdG9yOiAibm8iLCAieWVzIikKLSBgdXJiYW5gIOKAlCBsaXZlcyBpbiBhbiB1cmJhbiBhcmVhIChGYWN0b3I6ICJubyIsICJ5ZXMiKQotIGB1bmVtcGAg4oCUIGNvdW50eSB1bmVtcGxveW1lbnQgcmF0ZSAoJSkgKE51bWVyaWMpCi0gYHdhZ2VgIOKAlCBhdmVyYWdlIHdhZ2UgaW4gY291bnR5IChOdW1lcmljKQotIGBkaXN0YW5jZWAg4oCUIGRpc3RhbmNlIChpbiBtaWxlcykgdG8gbmVhcmVzdCA0LXllYXIgY29sbGVnZSAoTnVtZXJpYykKLSBgdHVpdGlvbmAg4oCUIHJlbGF0aXZlIHR1aXRpb24gY29zdCBhdCA0LXllYXIgY29sbGVnZXMgKE51bWVyaWMpCi0gYGVkdWNhdGlvbmAg4oCUIHllYXJzIG9mIHNjaG9vbGluZyBjb21wbGV0ZWQgKE51bWVyaWMpCi0gYGluY29tZWAg4oCUIGZhbWlseSBpbmNvbWUgbGV2ZWwgKEZhY3RvcjogImxvdyIsICJoaWdoIikKLSBgcmVnaW9uYCDigJQgcmVnaW9uIG9mIHRoZSBVLlMuIChGYWN0b3I6ICJvdGhlciIsICJ3ZXN0IikKCmBgYHtyIGxvYWQtZGF0YX0KIyBMb2FkIHRoZSBkYXRhc2V0IGZyb20gdGhlIEFFUiBwYWNrYWdlCmRhdGEoIkNvbGxlZ2VEaXN0YW5jZSIpCmNvbGxlZ2UgPC0gQ29sbGVnZURpc3RhbmNlCnJlbW92ZShDb2xsZWdlRGlzdGFuY2UpICAjIHJlbW92ZSBkdXBsaWNhdGUKYGBgCgpgYGB7ciBleHBsb3JlfQojIFZpZXcgZGF0YSBzdHJ1Y3R1cmUKc3RyKGNvbGxlZ2UpCgojIEluIFJTdHVkaW8geW91IHdvdWxkIHJ1biBWaWV3KGNvbGxlZ2UpOyBoZXJlIHdlIHByZXZpZXcgdGhlIGZpcnN0IHJvd3MuCmtuaXRyOjprYWJsZShoZWFkKGNvbGxlZ2UpLCBjYXB0aW9uID0gIkZpcnN0IHJvd3Mgb2YgdGhlIENvbGxlZ2VEaXN0YW5jZSBkYXRhIikKYGBgCgojIFByb3BvcnRpb24gVGVzdDogYHByb3AudGVzdGAKCioqUmVzZWFyY2ggcXVlc3Rpb24uKiogSXMgdGhlIHByb3BvcnRpb24gb2YgaGlnaC1pbmNvbWUgc3R1ZGVudHMgZGlmZmVyZW50IGZyb20gMC41PwoKYGBge3IgcHJvcC1zZXR1cH0KIyBDb3VudCBudW1iZXIgb2YgJ2hpZ2gnIGluY29tZSBzdHVkZW50cwp4X2hpZ2ggPC0gc3VtKGNvbGxlZ2UkaW5jb21lID09ICJoaWdoIikKCiMgVG90YWwgbnVtYmVyIG9mIHN0dWRlbnRzCm5fdG90YWwgPC0gbnJvdyhjb2xsZWdlKQpgYGAKCioqVHdvLXNpZGVkIHRlc3QqKiAoJEhfMCQ6IHRydWUgcHJvcG9ydGlvbiBvZiBoaWdoLWluY29tZSBzdHVkZW50cyAkPSAwLjUkOwokSF8xJDogdHJ1ZSBwcm9wb3J0aW9uICRcbmVxIDAuNSQpLiBUaGUgdGVzdCBzdGF0aXN0aWMgKCRYXjIkKSBhbmQgKnAqLXZhbHVlIHRlbGwKdXMgd2hldGhlciB0aGUgb2JzZXJ2ZWQgcHJvcG9ydGlvbiBpcyBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBmcm9tIDAuNS4KCmBgYHtyIHByb3AtdHdvLXNpZGVkfQpwcm9wX3Rlc3RfcmVzdWx0IDwtIHByb3AudGVzdCh4ID0geF9oaWdoLCBuID0gbl90b3RhbCwgcCA9IDAuNSkKcHJvcF90ZXN0X3Jlc3VsdApgYGAKCioqQ2hlY2sgdGhlIDk1JSBjb25maWRlbmNlIGludGVydmFsLioqCgpgYGB7ciBwcm9wLWNpfQpwcm9wX3Rlc3RfcmVzdWx0JGNvbmYuaW50CmBgYAoKKipPbmUtc2lkZWQgdGVzdCoqIOKAlCB0ZXN0IHdoZXRoZXIgdGhlIHByb3BvcnRpb24gb2YgaGlnaC1pbmNvbWUgc3R1ZGVudHMgJD4gMC41JAooJEhfMCQ6ICRwIFxsZXEgMC41JDsgJEhfMSQ6ICRwID4gMC41JCkuIElmIHRoZSAqcCotdmFsdWUgJDwgMC4wNSQsIHdlIHJlamVjdCAkSF8wJAphbmQgY29uY2x1ZGUgdGhlIHByb3BvcnRpb24gaXMgc2lnbmlmaWNhbnRseSBncmVhdGVyIHRoYW4gMC41LiBUaGUgb25lLXNpZGVkIHRlc3QKaXMgdXNlZCB3aGVuIHdlIGhhdmUgYSBkaXJlY3Rpb25hbCBoeXBvdGhlc2lzLgoKYGBge3IgcHJvcC1vbmUtc2lkZWR9CnByb3BfdGVzdF9vbmVfc2lkZWQgPC0gcHJvcC50ZXN0KHggPSB4X2hpZ2gsIG4gPSBuX3RvdGFsLCBwID0gMC41LCBhbHRlcm5hdGl2ZSA9ICJncmVhdGVyIikKcHJvcF90ZXN0X29uZV9zaWRlZApgYGAKCiMgU2ltcGxlIExpbmVhciBSZWdyZXNzaW9uCgoqKlJlc2VhcmNoIHF1ZXN0aW9uLioqIERvZXMgZGlzdGFuY2UgdG8gY29sbGVnZSBhZmZlY3QgdGVzdCBzY29yZXM/CgpgYGB7ciBtb2RlbC0xfQojIEZpdCBhIHNpbXBsZSByZWdyZXNzaW9uIG1vZGVsCm1vZGVsXzEgPC0gbG0oc2NvcmUgfiBkaXN0YW5jZSwgZGF0YSA9IGNvbGxlZ2UpCnN1bW1hcnkobW9kZWxfMSkKYGBgCgoqKkNvbmZpZGVuY2UgaW50ZXJ2YWwgZm9yIHRoZSBjb2VmZmljaWVudHMuKioKCmBgYHtyIG1vZGVsLTEtY2l9CmNvbmZpbnQobW9kZWxfMSkKYGBgCgoqKkludGVycHJldGF0aW9uLioqCgotIEludGVyY2VwdDogcHJlZGljdGVkIHRlc3Qgc2NvcmUgd2hlbiBgZGlzdGFuY2VgID0gMC4KLSBTbG9wZSAoYGRpc3RhbmNlYCk6IGV4cGVjdGVkIGNoYW5nZSBpbiBgc2NvcmVgIGZvciBlYWNoIGFkZGl0aW9uYWwgbWlsZS4KLSBDaGVjayB0aGUgKnAqLXZhbHVlIHRvIHRlc3QgJEhfMCQ6ICRcYmV0YV97XHRleHR7ZGlzdGFuY2V9fSA9IDAkLgoKIyBNdWx0aXBsZSBSZWdyZXNzaW9uCgoqKlJlc2VhcmNoIHF1ZXN0aW9uLioqIERvZXMgZGlzdGFuY2Ugc3RpbGwgbWF0dGVyIGFmdGVyIGNvbnRyb2xsaW5nIGZvciBmYW1pbHkKYmFja2dyb3VuZCwgaW5jb21lLCBhbmQgcmVnaW9uPwoKYGBge3IgbW9kZWwtMn0KbW9kZWxfMiA8LSBsbShzY29yZSB+IGRpc3RhbmNlICsgZmNvbGxlZ2UgKyBtY29sbGVnZSArCiAgICAgICAgICAgICAgICBob21lICsgdXJiYW4gKyB1bmVtcCArIHdhZ2UgKyB0dWl0aW9uICsKICAgICAgICAgICAgICAgIGVkdWNhdGlvbiArIGluY29tZSArIHJlZ2lvbiwKICAgICAgICAgICAgICBkYXRhID0gY29sbGVnZSkKc3VtbWFyeShtb2RlbF8yKQpgYGAKCioqSW50ZXJwcmV0YXRpb24uKioKCi0gRWFjaCBjb2VmZmljaWVudCBzaG93cyB0aGUgZXhwZWN0ZWQgY2hhbmdlIGluIGBzY29yZWAgZm9yIGEgb25lLXVuaXQgY2hhbmdlIGluCiAgdGhhdCB2YXJpYWJsZSwgaG9sZGluZyB0aGUgb3RoZXJzIGNvbnN0YW50LgotIENvbXBhcmUgJFxiZXRhX3tcdGV4dHtkaXN0YW5jZX19JCBpbiBgbW9kZWxfMWAgdnMuIGBtb2RlbF8yYDogZG9lcyB0aGUgZWZmZWN0CiAgZ2V0IHNtYWxsZXIgKHN1Z2dlc3RpbmcgY29uZm91bmRpbmcpPwoKIyBRdWljayBQcmFjdGljZQoKKipRMSkgUHJvcG9ydGlvbiB0ZXN0LioqIElzIHRoZSBwcm9wb3J0aW9uIG9mIGhpZ2gtaW5jb21lIHN0dWRlbnRzIGRpZmZlcmVudCBmcm9tIDAuNT8KKCRIXzAkOiAkcCA9IDAuNSQ7ICRIXzEkOiAkcCBcbmVxIDAuNSQuKSBJZiAqcCotdmFsdWUgJDwgMC4wNSQsIGNvbmNsdWRlIHRoZQpwcm9wb3J0aW9uIG9mIGhpZ2gtaW5jb21lIHN0dWRlbnRzIGlzIHNpZ25pZmljYW50bHkgZGlmZmVyZW50IGZyb20gMC41LgoKYGBge3IgcTF9CnhfaGlnaCA8LSBzdW0oY29sbGVnZSRpbmNvbWUgPT0gImhpZ2giKSAgICMgbnVtYmVyIG9mIGhpZ2gtaW5jb21lIHN0dWRlbnRzCm5fdG90YWwgPC0gbnJvdyhjb2xsZWdlKSAgICAgICAgICAgICAgICAgICMgdG90YWwgbnVtYmVyIG9mIHN0dWRlbnRzCgpwcm9wX3Rlc3RfcTEgPC0gcHJvcC50ZXN0KHggPSB4X2hpZ2gsIG4gPSBuX3RvdGFsLCBwID0gMC41KQpwcm9wX3Rlc3RfcTEKYGBgCgoqKlEyKSBQcm9wb3J0aW9uIHRlc3QuKiogSXMgdGhlIHByb3BvcnRpb24gb2Ygc3R1ZGVudHMgbGl2aW5nIGF0IGhvbWUgZ3JlYXRlciB0aGFuIDcwJT8KKCRIXzAkOiAkcCBcbGVxIDAuNyQ7ICRIXzEkOiAkcCA+IDAuNyQuKSBJZiAqcCotdmFsdWUgJDwgMC4wNSQsIGNvbmNsdWRlIG1vcmUgdGhhbgo3MCUgb2Ygc3R1ZGVudHMgbGl2ZSBhdCBob21lLgoKYGBge3IgcTJ9CnhfaG9tZSA8LSBzdW0oY29sbGVnZSRob21lID09ICJ5ZXMiKSAgICMgbnVtYmVyIG9mIHN0dWRlbnRzIGxpdmluZyBhdCBob21lCgpwcm9wX3Rlc3RfcTIgPC0gcHJvcC50ZXN0KHggPSB4X2hvbWUsIG4gPSBuX3RvdGFsLCBwID0gMC43LCBhbHRlcm5hdGl2ZSA9ICJncmVhdGVyIikKcHJvcF90ZXN0X3EyCmBgYAoKKipRMykgTXVsdGlwbGUgcmVncmVzc2lvbi4qKiBEb2VzIGZhbWlseSBpbmNvbWUgcHJlZGljdCBzdHVkZW50cycgdGVzdCBzY29yZXMgYWZ0ZXIKY29udHJvbGxpbmcgZm9yIHBhcmVudHMnIGVkdWNhdGlvbiwgZGlzdGFuY2UsIGhvbWUsIGFuZCByZWdpb24/IFdoaWNoIHZhcmlhYmxlcyBhcmUKc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCAoJHAgPCAwLjA1JCk/IEFyZSB0aGUgZWZmZWN0cyBvZiBpbmNvbWUgYW5kIGRpc3RhbmNlCnBvc2l0aXZlIG9yIG5lZ2F0aXZlPwoKYGBge3IgcTN9Cm1vZGVsX3EzIDwtIGxtKHNjb3JlIH4gaW5jb21lICsgZmNvbGxlZ2UgKyBtY29sbGVnZSArIGRpc3RhbmNlICsgaG9tZSArIHJlZ2lvbiwgZGF0YSA9IGNvbGxlZ2UpCnN1bW1hcnkobW9kZWxfcTMpCmBgYAoKIyBXcmFwLXVwCgoqKktleSB0YWtlYXdheXMqKgoKLSBSZWdyZXNzaW9uIGhlbHBzIHF1YW50aWZ5IHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB2YXJpYWJsZXMuCi0gTXVsdGlwbGUgcmVncmVzc2lvbiBjb250cm9scyBmb3IgY29uZm91bmRlcnMuCi0gSW50ZXJhY3Rpb24gdGVybXMgdGVzdCB3aGV0aGVyIGVmZmVjdHMgdmFyeSBieSBncm91cC4KLSBBbHdheXMgaW50ZXJwcmV0IGNvZWZmaWNpZW50cyBpbiBjb250ZXh0IQo=