library(tidyverse)
library(openintro)
library(scales)
library(corrplot)
library(ggthemes)
source("../scripts/prune_race_variables.R")
theme_set(theme_clean())

Import Data

assess <- read_csv("../data/assess.csv")
## Rows: 13328 Columns: 4
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## dbl (4): leaid, read_score, math_score, total_score
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
hh <- read_csv("../data/hh.csv") %>%
  select(-contains("MOE"))
## Rows: 13313 Columns: 18
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr  (3): state, dist, region
## dbl (15): leaid, children, pct_pov, pct_SP, SP_MOE, pct_HHVJ, HHVJ_MOE, pct_...
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
race <- read_csv("../data/race.csv") %>% 
    prune_and_predom() %>%
    mutate(leaid = as.integer(leaid), 
           predom_race = as.character(predom_race))
## Rows: 11910 Columns: 66
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr  (3): geo_id, dist, year
## dbl (63): leaid, total_pop_est, total_pop_moe, total_hisp_latino, total_hisp...
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
grad <- read_csv("../data/grad.csv")
## Rows: 12663 Columns: 2
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## dbl (2): leaid, grad_rate_midpt
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
data <- hh %>%
  left_join(assess, by = "leaid")%>%
  left_join(race, by = "leaid") %>%
  left_join(grad, by = "leaid")

data <- data %>%
    select(leaid, 
           dist, children, 
           grad_rate_midpt, 
           starts_with("pct"), 
           -pct_PI) %>% 
    mutate(
        across(.cols = pct_pov:pct_CLI, 
               .fns = function(x) {round(x*100, 3)})
    )
names(data)
##  [1] "leaid"           "dist"            "children"        "grad_rate_midpt"
##  [5] "pct_pov"         "pct_SP"          "pct_HHVJ"        "pct_CC"         
##  [9] "pct_NCI"         "pct_CD"          "pct_CLI"         "pct_hisp_latino"
## [13] "pct_white"       "pct_black"       "pct_native"      "pct_asian"

Variable Distributions

Let’s look at the distributions of all the different variables.

data %>%
    pivot_longer(cols = contains("pct"), 
                 names_to = "type", 
                 values_to = "vals") %>%
    ggplot(aes(x = vals)) + 
    geom_histogram() + 
    facet_wrap(vars(type))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## Warning: Removed 7020 rows containing non-finite values (stat_bin).

data %>%
    select(pct_native) %>% 
    filter(pct_native > 0) %>%
    na.omit() %>%
    ggplot(aes(x = pct_native)) + 
    geom_histogram()
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Most Predominant Race

Because of the heavy right skew of the distribution of Native American proportions across school districts, we will replace this column with an indicator. To account for all the difference races, we can make this indicator column correspond to which race is the predominant race, indicated by a given race having the maximum proportion in the partition of races within a given school district.

data <- data %>%
    select(12:16) %>%
    mutate(
        predom_race = names(.)[max.col(.)],
        predom_race = predom_race %>% 
            str_replace_all("pct_", ""), 
        predom_race = predom_race %>% 
            factor(levels = c("hisp_latino", "white", 
                              "black", "native", "asian"), 
                   labels = c("Hispanic/Latino", "White", 
                              "Black", "Native American", "Asian")
            )
    ) %>%
    select(predom_race) %>% 
    bind_cols(data) %>%
    relocate(predom_race, .after = children) 

data %>%
    count(predom_race)
## # A tibble: 6 × 2
##   predom_race         n
##   <fct>           <int>
## 1 Hispanic/Latino  1213
## 2 White            9917
## 3 Black             530
## 4 Native American   198
## 5 Asian              51
## 6 <NA>             1404

Grad Rates by Most Predominant Race

Now that we’ve added an indicator for the predominant race, let’s visualize some of the graduation rates as broken up by that most predominant race.

data %>% 
    filter(!is.na(predom_race)) %>%
    ggplot(aes(
        x = grad_rate_midpt, 
        y = after_stat(density)
    )) + 
    geom_freqpoly(aes(color = predom_race)) + 
    scale_x_continuous(labels = scales::percent_format(scale = 1)) + 
    labs(x = "Graduation Rate", 
         y = "", 
         title = "Graduation Rate Distribution per Race", 
         fill = "Predominant Race", 
         color = "Predominant Race")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## Warning: Removed 1708 rows containing non-finite values (stat_bin).

data %>% 
    filter(!is.na(predom_race)) %>%
    ggplot(aes(
        x = grad_rate_midpt, 
        y = after_stat(density)
    )) + 
    geom_histogram(aes(color = predom_race, 
                       fill = predom_race)) + 
    geom_freqpoly(aes(color = predom_race)) + 
    scale_x_continuous(labels = scales::percent_format(scale = 1)) + 
    labs(x = "Graduation Rate", 
         y = "", 
         title = "Graduation Rate Distribution per Race", 
         fill = "Predominant Race", 
         color = "Predominant Race")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## Warning: Removed 1708 rows containing non-finite values (stat_bin).
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## Warning: Removed 1708 rows containing non-finite values (stat_bin).

data %>% 
    filter(!is.na(predom_race)) %>%
    ggplot(aes(
        x = grad_rate_midpt, 
        y = after_stat(density)
    )) + 
    geom_histogram() + 
    geom_density() + 
    facet_grid(rows = vars(predom_race)) + 
    scale_x_continuous(labels = scales::percent_format(scale = 1)) + 
    labs(x = "Graduation Rate", 
         y = "", 
         title = "Graduation Rate Distribution per Race")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## Warning: Removed 1708 rows containing non-finite values (stat_bin).
## Warning: Removed 1708 rows containing non-finite values (stat_density).

Predictor Distributions by Most Prevalent Race

Now that we’ve split up our school districts by the most prevalent race in that district, we can now look at the distributions of our household conditions by race to see what we can see.

data %>%
    select(!(pct_hisp_latino:last_col())) %>%
    pivot_longer(cols = contains("pct"), 
                 names_to = "type", 
                 values_to = "vals") %>%
    ggplot(aes(x = vals, y = after_stat(density))) + 
    geom_histogram() + 
    facet_grid(rows = vars(type), 
               cols = vars(predom_race))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Variable Correlations per Predominant Racial Group

Hispanic/Latino

hh_conds <- data %>% 
    select(predom_race, pct_pov:pct_CLI) %>%
    filter(!is.na(predom_race))

races <- hh_conds %>% 
    count(predom_race) %>% 
    pull(predom_race) %>% 
    as.character()


hh_conds %>%
    filter(
        predom_race == races[1]
    ) %>% 
    select(!predom_race) %>%
    cor() %>%
    corrplot(method = "number")

For school districts which are primarily Hispanic/Latino, we can see that the following variables are moderately correlated with each other (\(|r| > 0.4\)): - Percent Poverty and Percent Single Parent - Percent Poverty and Percent No Computer/Internet Access - Percent Crowded Conditions and Percent of Linguistically Isolated Children

White

hh_conds %>%
    filter(
        predom_race == races[2]
    ) %>% 
    select(!predom_race) %>%
    cor() %>%
    corrplot(method = "number")

For school districts which are primarily White, we can see that the following variables are moderately correlated with each other (\(|r| > 0.4\)): - Percent Poverty and Percent Single Parent - Percent Poverty and Percent No Computer/Internet Access

Black

hh_conds %>%
    filter(
        predom_race == races[3]
    ) %>% 
    select(!predom_race) %>%
    cor() %>%
    corrplot(method = "number")

For school districts which are primarily Black, we can see that the following variables are moderately correlated with each other (\(|r| > 0.4\)): - Percent Poverty and Percent Single Parent - Percent Poverty and Percent No Computer/Internet Access

Native American

hh_conds %>%
    filter(
        predom_race == races[4]
    ) %>% 
    select(!predom_race) %>%
    cor() %>%
    corrplot(method = "number")

For school districts which are primarily White, we can see that the following variables are moderately correlated with each other (\(|r| > 0.4\)): - Percent Poverty and Percent Crowded Conditions - Percent Poverty and Percent No Computer/Internet Access

Asian

hh_conds %>%
    filter(
        predom_race == races[5]
    ) %>% 
    select(!predom_race) %>%
    cor() %>%
    corrplot(method = "number")

For school districts which are primarily Asian, we can see that almost all of the variables are strongly correlated with one another. This will require some thought for our regression analysis, though it is important to note that there are only 51 school districts recorded which are predominantly Asian.

LS0tCnRpdGxlOiAiUHJlZGljdG9yIERpc3RyaWJ1dGlvbnMiCmF1dGhvcjogIkpvbiBHZWlnZXIsIE5vZWwgR29vZHdpbiwgQWJpZ2FpbCBKb3BwYSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6IG9wZW5pbnRybzo6bGFiX3JlcG9ydAotLS0KCmBgYHtyIGxvYWQtcGFja2FnZXMsIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KG9wZW5pbnRybykKbGlicmFyeShzY2FsZXMpCmxpYnJhcnkoY29ycnBsb3QpCmxpYnJhcnkoZ2d0aGVtZXMpCnNvdXJjZSgiLi4vc2NyaXB0cy9wcnVuZV9yYWNlX3ZhcmlhYmxlcy5SIikKdGhlbWVfc2V0KHRoZW1lX2NsZWFuKCkpCmBgYAoKIyBJbXBvcnQgRGF0YQoKYGBge3J9Cgphc3Nlc3MgPC0gcmVhZF9jc3YoIi4uL2RhdGEvYXNzZXNzLmNzdiIpCmhoIDwtIHJlYWRfY3N2KCIuLi9kYXRhL2hoLmNzdiIpICU+JQogIHNlbGVjdCgtY29udGFpbnMoIk1PRSIpKQpyYWNlIDwtIHJlYWRfY3N2KCIuLi9kYXRhL3JhY2UuY3N2IikgJT4lIAogICAgcHJ1bmVfYW5kX3ByZWRvbSgpICU+JQogICAgbXV0YXRlKGxlYWlkID0gYXMuaW50ZWdlcihsZWFpZCksIAogICAgICAgICAgIHByZWRvbV9yYWNlID0gYXMuY2hhcmFjdGVyKHByZWRvbV9yYWNlKSkKZ3JhZCA8LSByZWFkX2NzdigiLi4vZGF0YS9ncmFkLmNzdiIpCgpkYXRhIDwtIGhoICU+JQogIGxlZnRfam9pbihhc3Nlc3MsIGJ5ID0gImxlYWlkIiklPiUKICBsZWZ0X2pvaW4ocmFjZSwgYnkgPSAibGVhaWQiKSAlPiUKICBsZWZ0X2pvaW4oZ3JhZCwgYnkgPSAibGVhaWQiKQoKZGF0YSA8LSBkYXRhICU+JQogICAgc2VsZWN0KGxlYWlkLCAKICAgICAgICAgICBkaXN0LCBjaGlsZHJlbiwgCiAgICAgICAgICAgZ3JhZF9yYXRlX21pZHB0LCAKICAgICAgICAgICBzdGFydHNfd2l0aCgicGN0IiksIAogICAgICAgICAgIC1wY3RfUEkpICU+JSAKICAgIG11dGF0ZSgKICAgICAgICBhY3Jvc3MoLmNvbHMgPSBwY3RfcG92OnBjdF9DTEksIAogICAgICAgICAgICAgICAuZm5zID0gZnVuY3Rpb24oeCkge3JvdW5kKHgqMTAwLCAzKX0pCiAgICApCm5hbWVzKGRhdGEpCmBgYAoKIyBWYXJpYWJsZSBEaXN0cmlidXRpb25zCgpMZXQncyBsb29rIGF0IHRoZSBkaXN0cmlidXRpb25zIG9mIGFsbCB0aGUgZGlmZmVyZW50IHZhcmlhYmxlcy4KCmBgYHtyfQpkYXRhICU+JQogICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjb250YWlucygicGN0IiksIAogICAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInR5cGUiLCAKICAgICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAidmFscyIpICU+JQogICAgZ2dwbG90KGFlcyh4ID0gdmFscykpICsgCiAgICBnZW9tX2hpc3RvZ3JhbSgpICsgCiAgICBmYWNldF93cmFwKHZhcnModHlwZSkpCmBgYAoKYGBge3J9CmRhdGEgJT4lCiAgICBzZWxlY3QocGN0X25hdGl2ZSkgJT4lIAogICAgZmlsdGVyKHBjdF9uYXRpdmUgPiAwKSAlPiUKICAgIG5hLm9taXQoKSAlPiUKICAgIGdncGxvdChhZXMoeCA9IHBjdF9uYXRpdmUpKSArIAogICAgZ2VvbV9oaXN0b2dyYW0oKQpgYGAKCiMgTW9zdCBQcmVkb21pbmFudCBSYWNlCgpCZWNhdXNlIG9mIHRoZSBoZWF2eSByaWdodCBza2V3IG9mIHRoZSBkaXN0cmlidXRpb24gb2YgTmF0aXZlIEFtZXJpY2FuIHByb3BvcnRpb25zIGFjcm9zcyBzY2hvb2wgZGlzdHJpY3RzLCB3ZSB3aWxsIHJlcGxhY2UgdGhpcyBjb2x1bW4gd2l0aCBhbiBpbmRpY2F0b3IuIFRvIGFjY291bnQgZm9yIGFsbCB0aGUgZGlmZmVyZW5jZSByYWNlcywgd2UgY2FuIG1ha2UgdGhpcyBpbmRpY2F0b3IgY29sdW1uIGNvcnJlc3BvbmQgdG8gd2hpY2ggcmFjZSBpcyB0aGUgcHJlZG9taW5hbnQgcmFjZSwgaW5kaWNhdGVkIGJ5IGEgZ2l2ZW4gcmFjZSBoYXZpbmcgdGhlIG1heGltdW0gcHJvcG9ydGlvbiBpbiB0aGUgcGFydGl0aW9uIG9mIHJhY2VzIHdpdGhpbiBhIGdpdmVuIHNjaG9vbCBkaXN0cmljdC4gCgpgYGB7cn0KZGF0YSA8LSBkYXRhICU+JQogICAgc2VsZWN0KDEyOjE2KSAlPiUKICAgIG11dGF0ZSgKICAgICAgICBwcmVkb21fcmFjZSA9IG5hbWVzKC4pW21heC5jb2woLildLAogICAgICAgIHByZWRvbV9yYWNlID0gcHJlZG9tX3JhY2UgJT4lIAogICAgICAgICAgICBzdHJfcmVwbGFjZV9hbGwoInBjdF8iLCAiIiksIAogICAgICAgIHByZWRvbV9yYWNlID0gcHJlZG9tX3JhY2UgJT4lIAogICAgICAgICAgICBmYWN0b3IobGV2ZWxzID0gYygiaGlzcF9sYXRpbm8iLCAid2hpdGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJsYWNrIiwgIm5hdGl2ZSIsICJhc2lhbiIpLCAKICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkhpc3BhbmljL0xhdGlubyIsICJXaGl0ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQmxhY2siLCAiTmF0aXZlIEFtZXJpY2FuIiwgIkFzaWFuIikKICAgICAgICAgICAgKQogICAgKSAlPiUKICAgIHNlbGVjdChwcmVkb21fcmFjZSkgJT4lIAogICAgYmluZF9jb2xzKGRhdGEpICU+JQogICAgcmVsb2NhdGUocHJlZG9tX3JhY2UsIC5hZnRlciA9IGNoaWxkcmVuKSAKCmRhdGEgJT4lCiAgICBjb3VudChwcmVkb21fcmFjZSkKYGBgCgojIEdyYWQgUmF0ZXMgYnkgTW9zdCBQcmVkb21pbmFudCBSYWNlCgpOb3cgdGhhdCB3ZSd2ZSBhZGRlZCBhbiBpbmRpY2F0b3IgZm9yIHRoZSBwcmVkb21pbmFudCByYWNlLCBsZXQncyB2aXN1YWxpemUgc29tZSBvZiB0aGUgZ3JhZHVhdGlvbiByYXRlcyBhcyBicm9rZW4gdXAgYnkgdGhhdCBtb3N0IHByZWRvbWluYW50IHJhY2UuIAoKYGBge3J9CmRhdGEgJT4lIAogICAgZmlsdGVyKCFpcy5uYShwcmVkb21fcmFjZSkpICU+JQogICAgZ2dwbG90KGFlcygKICAgICAgICB4ID0gZ3JhZF9yYXRlX21pZHB0LCAKICAgICAgICB5ID0gYWZ0ZXJfc3RhdChkZW5zaXR5KQogICAgKSkgKyAKICAgIGdlb21fZnJlcXBvbHkoYWVzKGNvbG9yID0gcHJlZG9tX3JhY2UpKSArIAogICAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoc2NhbGUgPSAxKSkgKyAKICAgIGxhYnMoeCA9ICJHcmFkdWF0aW9uIFJhdGUiLCAKICAgICAgICAgeSA9ICIiLCAKICAgICAgICAgdGl0bGUgPSAiR3JhZHVhdGlvbiBSYXRlIERpc3RyaWJ1dGlvbiBwZXIgUmFjZSIsIAogICAgICAgICBmaWxsID0gIlByZWRvbWluYW50IFJhY2UiLCAKICAgICAgICAgY29sb3IgPSAiUHJlZG9taW5hbnQgUmFjZSIpCgpkYXRhICU+JSAKICAgIGZpbHRlcighaXMubmEocHJlZG9tX3JhY2UpKSAlPiUKICAgIGdncGxvdChhZXMoCiAgICAgICAgeCA9IGdyYWRfcmF0ZV9taWRwdCwgCiAgICAgICAgeSA9IGFmdGVyX3N0YXQoZGVuc2l0eSkKICAgICkpICsgCiAgICBnZW9tX2hpc3RvZ3JhbShhZXMoY29sb3IgPSBwcmVkb21fcmFjZSwgCiAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IHByZWRvbV9yYWNlKSkgKyAKICAgIGdlb21fZnJlcXBvbHkoYWVzKGNvbG9yID0gcHJlZG9tX3JhY2UpKSArIAogICAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoc2NhbGUgPSAxKSkgKyAKICAgIGxhYnMoeCA9ICJHcmFkdWF0aW9uIFJhdGUiLCAKICAgICAgICAgeSA9ICIiLCAKICAgICAgICAgdGl0bGUgPSAiR3JhZHVhdGlvbiBSYXRlIERpc3RyaWJ1dGlvbiBwZXIgUmFjZSIsIAogICAgICAgICBmaWxsID0gIlByZWRvbWluYW50IFJhY2UiLCAKICAgICAgICAgY29sb3IgPSAiUHJlZG9taW5hbnQgUmFjZSIpCgpkYXRhICU+JSAKICAgIGZpbHRlcighaXMubmEocHJlZG9tX3JhY2UpKSAlPiUKICAgIGdncGxvdChhZXMoCiAgICAgICAgeCA9IGdyYWRfcmF0ZV9taWRwdCwgCiAgICAgICAgeSA9IGFmdGVyX3N0YXQoZGVuc2l0eSkKICAgICkpICsgCiAgICBnZW9tX2hpc3RvZ3JhbSgpICsgCiAgICBnZW9tX2RlbnNpdHkoKSArIAogICAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhwcmVkb21fcmFjZSkpICsgCiAgICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChzY2FsZSA9IDEpKSArIAogICAgbGFicyh4ID0gIkdyYWR1YXRpb24gUmF0ZSIsIAogICAgICAgICB5ID0gIiIsIAogICAgICAgICB0aXRsZSA9ICJHcmFkdWF0aW9uIFJhdGUgRGlzdHJpYnV0aW9uIHBlciBSYWNlIikKYGBgCgojIFByZWRpY3RvciBEaXN0cmlidXRpb25zIGJ5IE1vc3QgUHJldmFsZW50IFJhY2UKCk5vdyB0aGF0IHdlJ3ZlIHNwbGl0IHVwIG91ciBzY2hvb2wgZGlzdHJpY3RzIGJ5IHRoZSBtb3N0IHByZXZhbGVudCByYWNlIGluIHRoYXQgZGlzdHJpY3QsIHdlIGNhbiBub3cgbG9vayBhdCB0aGUgZGlzdHJpYnV0aW9ucyBvZiBvdXIgaG91c2Vob2xkIGNvbmRpdGlvbnMgYnkgcmFjZSB0byBzZWUgd2hhdCB3ZSBjYW4gc2VlLiAKCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD04fQpkYXRhICU+JQogICAgc2VsZWN0KCEocGN0X2hpc3BfbGF0aW5vOmxhc3RfY29sKCkpKSAlPiUKICAgIHBpdm90X2xvbmdlcihjb2xzID0gY29udGFpbnMoInBjdCIpLCAKICAgICAgICAgICAgICAgICBuYW1lc190byA9ICJ0eXBlIiwgCiAgICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gInZhbHMiKSAlPiUKICAgIGdncGxvdChhZXMoeCA9IHZhbHMsIHkgPSBhZnRlcl9zdGF0KGRlbnNpdHkpKSkgKyAKICAgIGdlb21faGlzdG9ncmFtKCkgKyAKICAgIGZhY2V0X2dyaWQocm93cyA9IHZhcnModHlwZSksIAogICAgICAgICAgICAgICBjb2xzID0gdmFycyhwcmVkb21fcmFjZSkpCmBgYAoKCgojIFZhcmlhYmxlIENvcnJlbGF0aW9ucyBwZXIgUHJlZG9taW5hbnQgUmFjaWFsIEdyb3VwCgojIyBIaXNwYW5pYy9MYXRpbm8KCmBgYHtyfQpoaF9jb25kcyA8LSBkYXRhICU+JSAKICAgIHNlbGVjdChwcmVkb21fcmFjZSwgcGN0X3BvdjpwY3RfQ0xJKSAlPiUKICAgIGZpbHRlcighaXMubmEocHJlZG9tX3JhY2UpKQoKcmFjZXMgPC0gaGhfY29uZHMgJT4lIAogICAgY291bnQocHJlZG9tX3JhY2UpICU+JSAKICAgIHB1bGwocHJlZG9tX3JhY2UpICU+JSAKICAgIGFzLmNoYXJhY3RlcigpCgoKaGhfY29uZHMgJT4lCiAgICBmaWx0ZXIoCiAgICAgICAgcHJlZG9tX3JhY2UgPT0gcmFjZXNbMV0KICAgICkgJT4lIAogICAgc2VsZWN0KCFwcmVkb21fcmFjZSkgJT4lCiAgICBjb3IoKSAlPiUKICAgIGNvcnJwbG90KG1ldGhvZCA9ICJudW1iZXIiKQpgYGAKCkZvciBzY2hvb2wgZGlzdHJpY3RzIHdoaWNoIGFyZSBwcmltYXJpbHkgSGlzcGFuaWMvTGF0aW5vLCB3ZSBjYW4gc2VlIHRoYXQgdGhlIGZvbGxvd2luZyB2YXJpYWJsZXMgYXJlIG1vZGVyYXRlbHkgY29ycmVsYXRlZCB3aXRoIGVhY2ggb3RoZXIgKCR8cnwgPiAwLjQkKTogCi0gUGVyY2VudCBQb3ZlcnR5IGFuZCBQZXJjZW50IFNpbmdsZSBQYXJlbnQKLSBQZXJjZW50IFBvdmVydHkgYW5kIFBlcmNlbnQgTm8gQ29tcHV0ZXIvSW50ZXJuZXQgQWNjZXNzCi0gUGVyY2VudCBDcm93ZGVkIENvbmRpdGlvbnMgYW5kIFBlcmNlbnQgb2YgTGluZ3Vpc3RpY2FsbHkgSXNvbGF0ZWQgQ2hpbGRyZW4KCiMjIFdoaXRlCgpgYGB7cn0KaGhfY29uZHMgJT4lCiAgICBmaWx0ZXIoCiAgICAgICAgcHJlZG9tX3JhY2UgPT0gcmFjZXNbMl0KICAgICkgJT4lIAogICAgc2VsZWN0KCFwcmVkb21fcmFjZSkgJT4lCiAgICBjb3IoKSAlPiUKICAgIGNvcnJwbG90KG1ldGhvZCA9ICJudW1iZXIiKQpgYGAKCkZvciBzY2hvb2wgZGlzdHJpY3RzIHdoaWNoIGFyZSBwcmltYXJpbHkgV2hpdGUsIHdlIGNhbiBzZWUgdGhhdCB0aGUgZm9sbG93aW5nIHZhcmlhYmxlcyBhcmUgbW9kZXJhdGVseSBjb3JyZWxhdGVkIHdpdGggZWFjaCBvdGhlciAoJHxyfCA+IDAuNCQpOiAKLSBQZXJjZW50IFBvdmVydHkgYW5kIFBlcmNlbnQgU2luZ2xlIFBhcmVudAotIFBlcmNlbnQgUG92ZXJ0eSBhbmQgUGVyY2VudCBObyBDb21wdXRlci9JbnRlcm5ldCBBY2Nlc3MKCiMjIEJsYWNrCgpgYGB7cn0KaGhfY29uZHMgJT4lCiAgICBmaWx0ZXIoCiAgICAgICAgcHJlZG9tX3JhY2UgPT0gcmFjZXNbM10KICAgICkgJT4lIAogICAgc2VsZWN0KCFwcmVkb21fcmFjZSkgJT4lCiAgICBjb3IoKSAlPiUKICAgIGNvcnJwbG90KG1ldGhvZCA9ICJudW1iZXIiKQpgYGAKCkZvciBzY2hvb2wgZGlzdHJpY3RzIHdoaWNoIGFyZSBwcmltYXJpbHkgQmxhY2ssIHdlIGNhbiBzZWUgdGhhdCB0aGUgZm9sbG93aW5nIHZhcmlhYmxlcyBhcmUgbW9kZXJhdGVseSBjb3JyZWxhdGVkIHdpdGggZWFjaCBvdGhlciAoJHxyfCA+IDAuNCQpOiAKLSBQZXJjZW50IFBvdmVydHkgYW5kIFBlcmNlbnQgU2luZ2xlIFBhcmVudAotIFBlcmNlbnQgUG92ZXJ0eSBhbmQgUGVyY2VudCBObyBDb21wdXRlci9JbnRlcm5ldCBBY2Nlc3MKCiMjIE5hdGl2ZSBBbWVyaWNhbgoKYGBge3J9CmhoX2NvbmRzICU+JQogICAgZmlsdGVyKAogICAgICAgIHByZWRvbV9yYWNlID09IHJhY2VzWzRdCiAgICApICU+JSAKICAgIHNlbGVjdCghcHJlZG9tX3JhY2UpICU+JQogICAgY29yKCkgJT4lCiAgICBjb3JycGxvdChtZXRob2QgPSAibnVtYmVyIikKYGBgCgpGb3Igc2Nob29sIGRpc3RyaWN0cyB3aGljaCBhcmUgcHJpbWFyaWx5IFdoaXRlLCB3ZSBjYW4gc2VlIHRoYXQgdGhlIGZvbGxvd2luZyB2YXJpYWJsZXMgYXJlIG1vZGVyYXRlbHkgY29ycmVsYXRlZCB3aXRoIGVhY2ggb3RoZXIgKCR8cnwgPiAwLjQkKTogCi0gUGVyY2VudCBQb3ZlcnR5IGFuZCBQZXJjZW50IENyb3dkZWQgQ29uZGl0aW9ucwotIFBlcmNlbnQgUG92ZXJ0eSBhbmQgUGVyY2VudCBObyBDb21wdXRlci9JbnRlcm5ldCBBY2Nlc3MKCiMjIEFzaWFuCgpgYGB7cn0KaGhfY29uZHMgJT4lCiAgICBmaWx0ZXIoCiAgICAgICAgcHJlZG9tX3JhY2UgPT0gcmFjZXNbNV0KICAgICkgJT4lIAogICAgc2VsZWN0KCFwcmVkb21fcmFjZSkgJT4lCiAgICBjb3IoKSAlPiUKICAgIGNvcnJwbG90KG1ldGhvZCA9ICJudW1iZXIiKQpgYGAKCkZvciBzY2hvb2wgZGlzdHJpY3RzIHdoaWNoIGFyZSBwcmltYXJpbHkgQXNpYW4sIHdlIGNhbiBzZWUgdGhhdCBhbG1vc3QgYWxsIG9mIHRoZSB2YXJpYWJsZXMgYXJlIHN0cm9uZ2x5IGNvcnJlbGF0ZWQgd2l0aCBvbmUgYW5vdGhlci4gVGhpcyB3aWxsIHJlcXVpcmUgc29tZSB0aG91Z2h0IGZvciBvdXIgcmVncmVzc2lvbiBhbmFseXNpcywgdGhvdWdoIGl0IGlzIGltcG9ydGFudCB0byBub3RlIHRoYXQgdGhlcmUgYXJlIG9ubHkgNTEgc2Nob29sIGRpc3RyaWN0cyByZWNvcmRlZCB3aGljaCBhcmUgcHJlZG9taW5hbnRseSBBc2lhbi4KCg==