Importing and Cleaning Data
district_data <- read_excel("../raw/NHGIS_District_data.xlsx")
Fortunately, there isn’t much initial restructuring required of this data.
## [1] "School ID"
## [2] "State"
## [3] "Geographic School District"
## [4] "Children 5-17 (SAIPE Estimate)"
## [5] "% Poverty (SAIPE Estimate)"
## [6] "% Single Parent Estimate"
## [7] "Single Parent Margin of Error"
## [8] "% HHs With Vulnerable Job Estimate"
## [9] "Vulnerable Job Margin of Error"
## [10] "% Crowded Conditions Estimate"
## [11] "HH With Crowded Conditions Margin of Error"
## [12] "% No Computer or Internet Estimate"
## [13] "No Computer or Internet Margin of Error"
## [14] "% Children with Disability"
## [15] "Children with Disability Margin of Error"
## [16] "% Linguistically Isolated Children"
## [17] "Linguistically Isolated Children Margin of Error"
Let’s work on renaming our variables to more R
-friendly names.
names_list <- c(
"school_ID",
"state",
"dist", # Geographic School District
"children", # Children 5-17 (SAIPE Estimate)
"pct_pov", # % Poverty (SAIPE Estimate)
"pct_SP", # % Single Parent Estimate
"SP_MOE", # Single Parent Margin of Error
"pct_HHVJ", # % HHs With Vulnerable Job Estimate
"HHVJ_MOE", # Vulnerable Job Margin of Error
"pct_CC", # % Crowded Conditions Estimate
"CC_MOE", # HH With Crowded Conditions Margin of Error
"pct_NCI", # % No Computer or Internet Estimate
"nci_MOE", # No Computer or Internet Margin of Error
"pct_CD", # % Children with Disability
"CD_MOE", # Children with Disability Margin of Error
"pct_CLI", # % Linguistically Isolated Children
"CLI_MOE" # Linguistically Isolated Children Margin of Error
)
names(district_data) <- names_list
district_pcts <- district_data %>%
select(-ends_with("MOE"))
We make a new dataset, district_pcts
, which contains all the values without any of the margins of error.
We can now do some preliminary analysis on this data. Let’s first see if there’s any NA/missing data:
district_data %>%
is.na() %>%
colSums()
## school_ID state dist children pct_pov pct_SP SP_MOE pct_HHVJ
## 0 0 0 0 0 0 0 0
## HHVJ_MOE pct_CC CC_MOE pct_NCI nci_MOE pct_CD CD_MOE pct_CLI
## 0 0 0 0 0 0 0 0
## CLI_MOE
## 0
Fortunately, there don’t appear to be any NA values in any of the percentage columns.
Analysis
Variable Correlations
Let’s check out some variable correlations:
district_pcts[,4:ncol(district_pcts)] %>%
cor() %>%
corrplot(method = "number")
Based on the correlations, it might make sense to plot some variables against each other to see some initial trends. We will choose a cutoff correlation value of 0.3 to distinguish variables which may be of interest. This is completely arbitrary, but limits the amount of plots we need to make such that the analysis is not entirely cumbersome.
Additionally, we will only consider school districts which have more than 100 students. This eliminates outlying values which appear for low numbers of students, such as measures equal to 100%. As an example, we can look at the variable pct_pov
; there are a few data points at the 100% mark, so let’s look at these values:
district_data %>%
filter(pct_pov == 1) %>%
arrange(pct_pov) %>%
select(state, dist, children, pct_pov)
## # A tibble: 2 × 4
## state dist children pct_pov
## <chr> <chr> <dbl> <dbl>
## 1 Maine Seboeis Plantation 17 1
## 2 New Mexico Wagon Mound Public Schools 59 1
Because of this low number of children affecting the values of the variables so much, we’ll set 100 to be that cutoff value and continue with analysis. Additionally, since we have over 10,000 rows in our dataset, we randomly sample 1000 of these values for each of the following plots.
Correlated Variable Plots
district_filtered <- district_data %>%
filter(children > 100)
nrow(district_data) - nrow(district_filtered)
## [1] 790
ggplot(district_filtered[sample(1000),],
aes(x = pct_pov,
y = pct_SP
)) +
geom_point(alpha = 0.1) +
geom_smooth()
## `geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")'
<<<<<<< HEAD
=======
>>>>>>> 6056c29c711690a9ae14a8e4ec179ee3356985e0
ggplot(district_filtered[sample(1000),],
aes(x = pct_pov,
y = pct_CC
)) +
geom_point(alpha = 0.1) +
geom_smooth()
## `geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")'
<<<<<<< HEAD
=======
>>>>>>> 6056c29c711690a9ae14a8e4ec179ee3356985e0
ggplot(district_filtered[sample(1000),],
aes(x = pct_pov,
y = pct_NCI
)) +
geom_point(alpha = 0.1) +
geom_smooth()
## `geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")'
<<<<<<< HEAD
=======
>>>>>>> 6056c29c711690a9ae14a8e4ec179ee3356985e0
ggplot(district_filtered[sample(1000),],
aes(x = pct_SP,
y = pct_NCI
)) +
geom_point(alpha = 0.1) +
geom_smooth()
## `geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")'
<<<<<<< HEAD
=======
>>>>>>> 6056c29c711690a9ae14a8e4ec179ee3356985e0
ggplot(district_filtered[sample(1000),],
aes(x = pct_CC,
y = pct_NCI
)) +
geom_point(alpha = 0.1) +
geom_smooth()
## `geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")'
<<<<<<< HEAD
=======
>>>>>>> 6056c29c711690a9ae14a8e4ec179ee3356985e0
ggplot(district_filtered[sample(1000),],
aes(x = pct_CC,
y = pct_CLI
)) +
geom_point(alpha = 0.1) +
geom_smooth()
## `geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")'
<<<<<<< HEAD
=======
>>>>>>> 6056c29c711690a9ae14a8e4ec179ee3356985e0
Immediately from all of these plots, we can notice that the vast majority of values for any given predictor are below 50%. We can notice that, similar to what our correlation matrix would have us believe, there appears to be a positive correlation between all of these variables.
Distribution of Number of Students
To get a better idea at what sorts of numbers we’re looking at in terms of the number of children in each shcool district, let’s look at a summary of the distribution. We’ll look at all school districts rather than just those with more than 100 students:
summary(district_data$children)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0 445 1264 4353 3458 1213005
The mean of this distribution is well above the third quartile, implying that this data is heavily right-skewed. This makes sense, given the fact that there are so many small school districts and likely a few very large ones.
Because of the right-skewed nature of this data, let’s look at a log-transformed boxplot
district_data %>%
filter(children > 0) %>%
ggplot(aes(x = children)) +
geom_boxplot() +
geom_jitter(aes(y = 0), alpha = 0.01, height = 0.05) +
scale_x_log10() +
geom_density()
<<<<<<< HEAD
=======
>>>>>>> 6056c29c711690a9ae14a8e4ec179ee3356985e0
Interestingly, when the number of children in each district is log-transformed, the density plot seems to be relatively symmetric about the median. Perhaps there’s some sort of log-normal distribution underlying the distribution of children in school districts in the U.S.?
Additionally, let’s see which school district has over a million estimated children aged 5 to 17.
district_data %>%
select(state, dist, children) %>%
arrange(desc(children)) %>%
head(5)
## # A tibble: 5 × 3
## state dist children
## <chr> <chr> <dbl>
## 1 New York New York City Department Of Education 1213005
## 2 California Los Angeles Unified School District 724446
## 3 Puerto Rico Puerto Rico 529844
## 4 Illinois Chicago Public School District 299 399883
## 5 Florida Dade County School District 396516
Makes sense. Is this actually a school district, or is it a conglomerate of school districts? We’ll assume that the data is good, and that the New York City Department of Education is, in fact, classified as a school district.
LS0tCnRpdGxlOiAiUHJlbGltaW5hcnkgQW5hbHlzaXMiCmF1dGhvcjogIkpvbiBHZWlnZXIsIE5vZWwgR29vZHdpbiwgQWJpZ2FpbCBKb3BwYSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6IG9wZW5pbnRybzo6bGFiX3JlcG9ydAotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmBgYAoKIyBJbXBvcnRpbmcgUGFja2FnZXMKCmBgYHtyLCBtZXNzYWdlPUZ9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShjb3JycGxvdCkKYGBgCgojIEltcG9ydGluZyBhbmQgQ2xlYW5pbmcgRGF0YQoKYGBge3J9CmRpc3RyaWN0X2RhdGEgPC0gcmVhZF9leGNlbCgiLi4vcmF3L05IR0lTX0Rpc3RyaWN0X2RhdGEueGxzeCIpCmBgYAoKRm9ydHVuYXRlbHksIHRoZXJlIGlzbid0IG11Y2ggaW5pdGlhbCByZXN0cnVjdHVyaW5nIHJlcXVpcmVkIG9mIHRoaXMgZGF0YS4gCgpgYGB7cn0KbmFtZXMoZGlzdHJpY3RfZGF0YSkKYGBgCgpMZXQncyB3b3JrIG9uIHJlbmFtaW5nIG91ciB2YXJpYWJsZXMgdG8gbW9yZSBgUmAtZnJpZW5kbHkgbmFtZXMuIAoKYGBge3J9Cm5hbWVzX2xpc3QgPC0gYygKICAgICJzY2hvb2xfSUQiLCAKICAgICJzdGF0ZSIsIAogICAgImRpc3QiLCAgIyBHZW9ncmFwaGljIFNjaG9vbCBEaXN0cmljdCAKICAgICJjaGlsZHJlbiIsICMgQ2hpbGRyZW4gNS0xNyAoU0FJUEUgRXN0aW1hdGUpCiAgICAicGN0X3BvdiIsICMgJSBQb3ZlcnR5IChTQUlQRSBFc3RpbWF0ZSkKICAgICJwY3RfU1AiLCAjICUgU2luZ2xlIFBhcmVudCBFc3RpbWF0ZQogICAgIlNQX01PRSIsICMgU2luZ2xlIFBhcmVudCBNYXJnaW4gb2YgRXJyb3IKICAgICJwY3RfSEhWSiIsICMgJSBISHMgV2l0aCBWdWxuZXJhYmxlIEpvYiBFc3RpbWF0ZQogICAgIkhIVkpfTU9FIiwgIyBWdWxuZXJhYmxlIEpvYiBNYXJnaW4gb2YgRXJyb3IKICAgICJwY3RfQ0MiLCAjICUgQ3Jvd2RlZCBDb25kaXRpb25zIEVzdGltYXRlCiAgICAiQ0NfTU9FIiwgIyBISCBXaXRoIENyb3dkZWQgQ29uZGl0aW9ucyBNYXJnaW4gb2YgRXJyb3IKICAgICJwY3RfTkNJIiwgIyAlIE5vIENvbXB1dGVyIG9yIEludGVybmV0IEVzdGltYXRlCiAgICAibmNpX01PRSIsICMgTm8gQ29tcHV0ZXIgb3IgSW50ZXJuZXQgTWFyZ2luIG9mIEVycm9yCiAgICAicGN0X0NEIiwgIyAlIENoaWxkcmVuIHdpdGggRGlzYWJpbGl0eQogICAgIkNEX01PRSIsICMgQ2hpbGRyZW4gd2l0aCBEaXNhYmlsaXR5IE1hcmdpbiBvZiBFcnJvcgogICAgInBjdF9DTEkiLCAjICUgTGluZ3Vpc3RpY2FsbHkgSXNvbGF0ZWQgQ2hpbGRyZW4KICAgICJDTElfTU9FIiAjIExpbmd1aXN0aWNhbGx5IElzb2xhdGVkIENoaWxkcmVuIE1hcmdpbiBvZiBFcnJvcgopCm5hbWVzKGRpc3RyaWN0X2RhdGEpIDwtIG5hbWVzX2xpc3QKZGlzdHJpY3RfcGN0cyA8LSBkaXN0cmljdF9kYXRhICU+JQogICAgc2VsZWN0KC1lbmRzX3dpdGgoIk1PRSIpKSAKYGBgCgpXZSBtYWtlIGEgbmV3IGRhdGFzZXQsIGBkaXN0cmljdF9wY3RzYCwgd2hpY2ggY29udGFpbnMgYWxsIHRoZSB2YWx1ZXMgd2l0aG91dCBhbnkgb2YgdGhlIG1hcmdpbnMgb2YgZXJyb3IuIAoKV2UgY2FuIG5vdyBkbyBzb21lIHByZWxpbWluYXJ5IGFuYWx5c2lzIG9uIHRoaXMgZGF0YS4gTGV0J3MgZmlyc3Qgc2VlIGlmIHRoZXJlJ3MgYW55IE5BL21pc3NpbmcgZGF0YToKCmBgYHtyfQpkaXN0cmljdF9kYXRhICU+JSAKICAgIGlzLm5hKCkgJT4lIAogICAgY29sU3VtcygpCmBgYAoKRm9ydHVuYXRlbHksIHRoZXJlIGRvbid0IGFwcGVhciB0byBiZSBhbnkgTkEgdmFsdWVzIGluIGFueSBvZiB0aGUgcGVyY2VudGFnZSBjb2x1bW5zLiAKCiMgQW5hbHlzaXMKCiMjIFZhcmlhYmxlIENvcnJlbGF0aW9ucwoKTGV0J3MgY2hlY2sgb3V0IHNvbWUgdmFyaWFibGUgY29ycmVsYXRpb25zOiAKCmBgYHtyfQpkaXN0cmljdF9wY3RzWyw0Om5jb2woZGlzdHJpY3RfcGN0cyldICU+JSAKICAgIGNvcigpICU+JQogICAgY29ycnBsb3QobWV0aG9kID0gIm51bWJlciIpCmBgYApCYXNlZCBvbiB0aGUgY29ycmVsYXRpb25zLCBpdCBtaWdodCBtYWtlIHNlbnNlIHRvIHBsb3Qgc29tZSB2YXJpYWJsZXMgYWdhaW5zdCBlYWNoIG90aGVyIHRvIHNlZSBzb21lIGluaXRpYWwgdHJlbmRzLiBXZSB3aWxsIGNob29zZSBhIGN1dG9mZiBjb3JyZWxhdGlvbiB2YWx1ZSBvZiAwLjMgdG8gZGlzdGluZ3Vpc2ggdmFyaWFibGVzIHdoaWNoIG1heSBiZSBvZiBpbnRlcmVzdC4gVGhpcyBpcyBjb21wbGV0ZWx5IGFyYml0cmFyeSwgYnV0IGxpbWl0cyB0aGUgYW1vdW50IG9mIHBsb3RzIHdlIG5lZWQgdG8gbWFrZSBzdWNoIHRoYXQgdGhlIGFuYWx5c2lzIGlzIG5vdCBlbnRpcmVseSBjdW1iZXJzb21lLiAKCkFkZGl0aW9uYWxseSwgd2Ugd2lsbCBvbmx5IGNvbnNpZGVyIHNjaG9vbCBkaXN0cmljdHMgd2hpY2ggaGF2ZSBtb3JlIHRoYW4gMTAwIHN0dWRlbnRzLiBUaGlzIGVsaW1pbmF0ZXMgb3V0bHlpbmcgdmFsdWVzIHdoaWNoIGFwcGVhciBmb3IgbG93IG51bWJlcnMgb2Ygc3R1ZGVudHMsIHN1Y2ggYXMgbWVhc3VyZXMgZXF1YWwgdG8gMTAwJS4gQXMgYW4gZXhhbXBsZSwgd2UgY2FuIGxvb2sgYXQgdGhlIHZhcmlhYmxlIGBwY3RfcG92YDsgdGhlcmUgYXJlIGEgZmV3IGRhdGEgcG9pbnRzIGF0IHRoZSAxMDAlIG1hcmssIHNvIGxldCdzIGxvb2sgYXQgdGhlc2UgdmFsdWVzOiAKYGBge3J9CmRpc3RyaWN0X2RhdGEgJT4lIAogICAgZmlsdGVyKHBjdF9wb3YgPT0gMSkgJT4lIAogICAgYXJyYW5nZShwY3RfcG92KSAlPiUKICAgIHNlbGVjdChzdGF0ZSwgZGlzdCwgY2hpbGRyZW4sIHBjdF9wb3YpCmBgYAoKQmVjYXVzZSBvZiB0aGlzIGxvdyBudW1iZXIgb2YgY2hpbGRyZW4gYWZmZWN0aW5nIHRoZSB2YWx1ZXMgb2YgdGhlIHZhcmlhYmxlcyBzbyBtdWNoLCB3ZSdsbCBzZXQgMTAwIHRvIGJlIHRoYXQgY3V0b2ZmIHZhbHVlIGFuZCBjb250aW51ZSB3aXRoIGFuYWx5c2lzLiBBZGRpdGlvbmFsbHksIHNpbmNlIHdlIGhhdmUgb3ZlciAxMCwwMDAgcm93cyBpbiBvdXIgZGF0YXNldCwgd2UgcmFuZG9tbHkgc2FtcGxlIDEwMDAgb2YgdGhlc2UgdmFsdWVzIGZvciBlYWNoIG9mIHRoZSBmb2xsb3dpbmcgcGxvdHMuCgojIyBDb3JyZWxhdGVkIFZhcmlhYmxlIFBsb3RzCgpgYGB7cn0KZGlzdHJpY3RfZmlsdGVyZWQgPC0gZGlzdHJpY3RfZGF0YSAlPiUKICAgIGZpbHRlcihjaGlsZHJlbiA+IDEwMCkKbnJvdyhkaXN0cmljdF9kYXRhKSAtIG5yb3coZGlzdHJpY3RfZmlsdGVyZWQpCgpnZ3Bsb3QoZGlzdHJpY3RfZmlsdGVyZWRbc2FtcGxlKDEwMDApLF0sCiAgICAgICBhZXMoeCA9IHBjdF9wb3YsIAogICAgICAgICAgIHkgPSBwY3RfU1AKICAgICAgICkpICsgCiAgICBnZW9tX3BvaW50KGFscGhhID0gMC4xKSArIAogICAgZ2VvbV9zbW9vdGgoKQoKZ2dwbG90KGRpc3RyaWN0X2ZpbHRlcmVkW3NhbXBsZSgxMDAwKSxdLAogICAgICAgYWVzKHggPSBwY3RfcG92LCAKICAgICAgICAgICB5ID0gcGN0X0NDCiAgICAgICApKSArIAogICAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMSkgKyAKICAgIGdlb21fc21vb3RoKCkKCmdncGxvdChkaXN0cmljdF9maWx0ZXJlZFtzYW1wbGUoMTAwMCksXSwKICAgICAgIGFlcyh4ID0gcGN0X3BvdiwgCiAgICAgICAgICAgeSA9IHBjdF9OQ0kKICAgICAgICkpICsgCiAgICBnZW9tX3BvaW50KGFscGhhID0gMC4xKSArIAogICAgZ2VvbV9zbW9vdGgoKQoKZ2dwbG90KGRpc3RyaWN0X2ZpbHRlcmVkW3NhbXBsZSgxMDAwKSxdLAogICAgICAgYWVzKHggPSBwY3RfU1AsIAogICAgICAgICAgIHkgPSBwY3RfTkNJCiAgICAgICApKSArIAogICAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMSkgKyAKICAgIGdlb21fc21vb3RoKCkKCmdncGxvdChkaXN0cmljdF9maWx0ZXJlZFtzYW1wbGUoMTAwMCksXSwKICAgICAgIGFlcyh4ID0gcGN0X0NDLCAKICAgICAgICAgICB5ID0gcGN0X05DSQogICAgICAgKSkgKyAKICAgIGdlb21fcG9pbnQoYWxwaGEgPSAwLjEpICsgCiAgICBnZW9tX3Ntb290aCgpCgpnZ3Bsb3QoZGlzdHJpY3RfZmlsdGVyZWRbc2FtcGxlKDEwMDApLF0sCiAgICAgICBhZXMoeCA9IHBjdF9DQywgCiAgICAgICAgICAgeSA9IHBjdF9DTEkKICAgICAgICkpICsgCiAgICBnZW9tX3BvaW50KGFscGhhID0gMC4xKSArIAogICAgZ2VvbV9zbW9vdGgoKQpgYGAKCkltbWVkaWF0ZWx5IGZyb20gYWxsIG9mIHRoZXNlIHBsb3RzLCB3ZSBjYW4gbm90aWNlIHRoYXQgdGhlIHZhc3QgbWFqb3JpdHkgb2YgdmFsdWVzIGZvciBhbnkgZ2l2ZW4gcHJlZGljdG9yIGFyZSBiZWxvdyA1MCUuIFdlIGNhbiBub3RpY2UgdGhhdCwgc2ltaWxhciB0byB3aGF0IG91ciBjb3JyZWxhdGlvbiBtYXRyaXggd291bGQgaGF2ZSB1cyBiZWxpZXZlLCB0aGVyZSBhcHBlYXJzIHRvIGJlIGEgcG9zaXRpdmUgY29ycmVsYXRpb24gYmV0d2VlbiBhbGwgb2YgdGhlc2UgdmFyaWFibGVzLgoKIyMgRGlzdHJpYnV0aW9uIG9mIE51bWJlciBvZiBTdHVkZW50cwoKVG8gZ2V0IGEgYmV0dGVyIGlkZWEgYXQgd2hhdCBzb3J0cyBvZiBudW1iZXJzIHdlJ3JlIGxvb2tpbmcgYXQgaW4gdGVybXMgb2YgdGhlIG51bWJlciBvZiBjaGlsZHJlbiBpbiBlYWNoIHNoY29vbCBkaXN0cmljdCwgbGV0J3MgbG9vayBhdCBhIHN1bW1hcnkgb2YgdGhlIGRpc3RyaWJ1dGlvbi4gV2UnbGwgbG9vayBhdCBhbGwgc2Nob29sIGRpc3RyaWN0cyByYXRoZXIgdGhhbiBqdXN0IHRob3NlIHdpdGggbW9yZSB0aGFuIDEwMCBzdHVkZW50czogCmBgYHtyfQpzdW1tYXJ5KGRpc3RyaWN0X2RhdGEkY2hpbGRyZW4pCmBgYApUaGUgbWVhbiBvZiB0aGlzIGRpc3RyaWJ1dGlvbiBpcyB3ZWxsIGFib3ZlIHRoZSB0aGlyZCBxdWFydGlsZSwgaW1wbHlpbmcgdGhhdCB0aGlzIGRhdGEgaXMgaGVhdmlseSByaWdodC1za2V3ZWQuIFRoaXMgbWFrZXMgc2Vuc2UsIGdpdmVuIHRoZSBmYWN0IHRoYXQgdGhlcmUgYXJlIHNvIG1hbnkgc21hbGwgc2Nob29sIGRpc3RyaWN0cyBhbmQgbGlrZWx5IGEgZmV3IHZlcnkgbGFyZ2Ugb25lcy4gCgpCZWNhdXNlIG9mIHRoZSByaWdodC1za2V3ZWQgbmF0dXJlIG9mIHRoaXMgZGF0YSwgbGV0J3MgbG9vayBhdCBhIGxvZy10cmFuc2Zvcm1lZCBib3hwbG90CgpgYGB7cn0KZGlzdHJpY3RfZGF0YSAlPiUgCiAgICBmaWx0ZXIoY2hpbGRyZW4gPiAwKSAlPiUKICAgIGdncGxvdChhZXMoeCA9IGNoaWxkcmVuKSkgKyAKICAgIGdlb21fYm94cGxvdCgpICsgCiAgICBnZW9tX2ppdHRlcihhZXMoeSA9IDApLCBhbHBoYSA9IDAuMDEsIGhlaWdodCA9IDAuMDUpICsgCiAgICBzY2FsZV94X2xvZzEwKCkgKyAKICAgIGdlb21fZGVuc2l0eSgpCmBgYAoKSW50ZXJlc3RpbmdseSwgd2hlbiB0aGUgbnVtYmVyIG9mIGNoaWxkcmVuIGluIGVhY2ggZGlzdHJpY3QgaXMgbG9nLXRyYW5zZm9ybWVkLCB0aGUgZGVuc2l0eSBwbG90IHNlZW1zIHRvIGJlIHJlbGF0aXZlbHkgc3ltbWV0cmljIGFib3V0IHRoZSBtZWRpYW4uIFBlcmhhcHMgdGhlcmUncyBzb21lIHNvcnQgb2YgbG9nLW5vcm1hbCBkaXN0cmlidXRpb24gdW5kZXJseWluZyB0aGUgZGlzdHJpYnV0aW9uIG9mIGNoaWxkcmVuIGluIHNjaG9vbCBkaXN0cmljdHMgaW4gdGhlIFUuUy4/CgpBZGRpdGlvbmFsbHksIGxldCdzIHNlZSB3aGljaCBzY2hvb2wgZGlzdHJpY3QgaGFzIG92ZXIgYSBtaWxsaW9uIGVzdGltYXRlZCBjaGlsZHJlbiBhZ2VkIDUgdG8gMTcuIApgYGB7cn0KZGlzdHJpY3RfZGF0YSAlPiUgCiAgICBzZWxlY3Qoc3RhdGUsIGRpc3QsIGNoaWxkcmVuKSAlPiUKICAgIGFycmFuZ2UoZGVzYyhjaGlsZHJlbikpICU+JQogICAgaGVhZCg1KQpgYGAKTWFrZXMgc2Vuc2UuIElzIHRoaXMgYWN0dWFsbHkgYSBzY2hvb2wgZGlzdHJpY3QsIG9yIGlzIGl0IGEgY29uZ2xvbWVyYXRlIG9mIHNjaG9vbCBkaXN0cmljdHM/IFdlJ2xsIGFzc3VtZSB0aGF0IHRoZSBkYXRhIGlzIGdvb2QsIGFuZCB0aGF0IHRoZSBOZXcgWW9yayBDaXR5IERlcGFydG1lbnQgb2YgRWR1Y2F0aW9uIGlzLCBpbiBmYWN0LCBjbGFzc2lmaWVkIGFzIGEgc2Nob29sIGRpc3RyaWN0LiAKCg==
LS0tCnRpdGxlOiAiUHJlbGltaW5hcnkgQW5hbHlzaXMiCmF1dGhvcjogIkpvbiBHZWlnZXIsIE5vZWwgR29vZHdpbiwgQWJpZ2FpbCBKb3BwYSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6IG9wZW5pbnRybzo6bGFiX3JlcG9ydAotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmBgYAoKIyBJbXBvcnRpbmcgUGFja2FnZXMKCmBgYHtyLCBtZXNzYWdlPUZ9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShjb3JycGxvdCkKbGlicmFyeShnZ3RoZW1lcykKdGhlbWVfc2V0KHRoZW1lX2NsZWFuKCkpCmBgYAoKIyBJbXBvcnRpbmcgYW5kIENsZWFuaW5nIERhdGEKCmBgYHtyfQpkaXN0cmljdF9kYXRhIDwtIHJlYWRfZXhjZWwoIi4uL3Jhdy9OSEdJU19EaXN0cmljdF9kYXRhLnhsc3giKQpgYGAKCkZvcnR1bmF0ZWx5LCB0aGVyZSBpc24ndCBtdWNoIGluaXRpYWwgcmVzdHJ1Y3R1cmluZyByZXF1aXJlZCBvZiB0aGlzIGRhdGEuIAoKYGBge3J9Cm5hbWVzKGRpc3RyaWN0X2RhdGEpCmBgYAoKTGV0J3Mgd29yayBvbiByZW5hbWluZyBvdXIgdmFyaWFibGVzIHRvIG1vcmUgYFJgLWZyaWVuZGx5IG5hbWVzLiAKCmBgYHtyfQpuYW1lc19saXN0IDwtIGMoCiAgICAic2Nob29sX0lEIiwgCiAgICAic3RhdGUiLCAKICAgICJkaXN0IiwgICMgR2VvZ3JhcGhpYyBTY2hvb2wgRGlzdHJpY3QgCiAgICAiY2hpbGRyZW4iLCAjIENoaWxkcmVuIDUtMTcgKFNBSVBFIEVzdGltYXRlKQogICAgInBjdF9wb3YiLCAjICUgUG92ZXJ0eSAoU0FJUEUgRXN0aW1hdGUpCiAgICAicGN0X1NQIiwgIyAlIFNpbmdsZSBQYXJlbnQgRXN0aW1hdGUKICAgICJTUF9NT0UiLCAjIFNpbmdsZSBQYXJlbnQgTWFyZ2luIG9mIEVycm9yCiAgICAicGN0X0hIVkoiLCAjICUgSEhzIFdpdGggVnVsbmVyYWJsZSBKb2IgRXN0aW1hdGUKICAgICJISFZKX01PRSIsICMgVnVsbmVyYWJsZSBKb2IgTWFyZ2luIG9mIEVycm9yCiAgICAicGN0X0NDIiwgIyAlIENyb3dkZWQgQ29uZGl0aW9ucyBFc3RpbWF0ZQogICAgIkNDX01PRSIsICMgSEggV2l0aCBDcm93ZGVkIENvbmRpdGlvbnMgTWFyZ2luIG9mIEVycm9yCiAgICAicGN0X05DSSIsICMgJSBObyBDb21wdXRlciBvciBJbnRlcm5ldCBFc3RpbWF0ZQogICAgIm5jaV9NT0UiLCAjIE5vIENvbXB1dGVyIG9yIEludGVybmV0IE1hcmdpbiBvZiBFcnJvcgogICAgInBjdF9DRCIsICMgJSBDaGlsZHJlbiB3aXRoIERpc2FiaWxpdHkKICAgICJDRF9NT0UiLCAjIENoaWxkcmVuIHdpdGggRGlzYWJpbGl0eSBNYXJnaW4gb2YgRXJyb3IKICAgICJwY3RfQ0xJIiwgIyAlIExpbmd1aXN0aWNhbGx5IElzb2xhdGVkIENoaWxkcmVuCiAgICAiQ0xJX01PRSIgIyBMaW5ndWlzdGljYWxseSBJc29sYXRlZCBDaGlsZHJlbiBNYXJnaW4gb2YgRXJyb3IKKQpuYW1lcyhkaXN0cmljdF9kYXRhKSA8LSBuYW1lc19saXN0CmRpc3RyaWN0X3BjdHMgPC0gZGlzdHJpY3RfZGF0YSAlPiUKICAgIHNlbGVjdCgtZW5kc193aXRoKCJNT0UiKSkgCmBgYAoKV2UgbWFrZSBhIG5ldyBkYXRhc2V0LCBgZGlzdHJpY3RfcGN0c2AsIHdoaWNoIGNvbnRhaW5zIGFsbCB0aGUgdmFsdWVzIHdpdGhvdXQgYW55IG9mIHRoZSBtYXJnaW5zIG9mIGVycm9yLiAKCldlIGNhbiBub3cgZG8gc29tZSBwcmVsaW1pbmFyeSBhbmFseXNpcyBvbiB0aGlzIGRhdGEuIExldCdzIGZpcnN0IHNlZSBpZiB0aGVyZSdzIGFueSBOQS9taXNzaW5nIGRhdGE6CgpgYGB7cn0KZGlzdHJpY3RfZGF0YSAlPiUgCiAgICBpcy5uYSgpICU+JSAKICAgIGNvbFN1bXMoKQpgYGAKCkZvcnR1bmF0ZWx5LCB0aGVyZSBkb24ndCBhcHBlYXIgdG8gYmUgYW55IE5BIHZhbHVlcyBpbiBhbnkgb2YgdGhlIHBlcmNlbnRhZ2UgY29sdW1ucy4gCgojIEFuYWx5c2lzCgojIyBWYXJpYWJsZSBDb3JyZWxhdGlvbnMKCkxldCdzIGNoZWNrIG91dCBzb21lIHZhcmlhYmxlIGNvcnJlbGF0aW9uczogCgpgYGB7cn0KZGlzdHJpY3RfcGN0c1ssNDpuY29sKGRpc3RyaWN0X3BjdHMpXSAlPiUgCiAgICBjb3IoKSAlPiUKICAgIGNvcnJwbG90KG1ldGhvZCA9ICJudW1iZXIiKQpgYGAKQmFzZWQgb24gdGhlIGNvcnJlbGF0aW9ucywgaXQgbWlnaHQgbWFrZSBzZW5zZSB0byBwbG90IHNvbWUgdmFyaWFibGVzIGFnYWluc3QgZWFjaCBvdGhlciB0byBzZWUgc29tZSBpbml0aWFsIHRyZW5kcy4gV2Ugd2lsbCBjaG9vc2UgYSBjdXRvZmYgY29ycmVsYXRpb24gdmFsdWUgb2YgMC4zIHRvIGRpc3Rpbmd1aXNoIHZhcmlhYmxlcyB3aGljaCBtYXkgYmUgb2YgaW50ZXJlc3QuIFRoaXMgaXMgY29tcGxldGVseSBhcmJpdHJhcnksIGJ1dCBsaW1pdHMgdGhlIGFtb3VudCBvZiBwbG90cyB3ZSBuZWVkIHRvIG1ha2Ugc3VjaCB0aGF0IHRoZSBhbmFseXNpcyBpcyBub3QgZW50aXJlbHkgY3VtYmVyc29tZS4gCgpBZGRpdGlvbmFsbHksIHdlIHdpbGwgb25seSBjb25zaWRlciBzY2hvb2wgZGlzdHJpY3RzIHdoaWNoIGhhdmUgbW9yZSB0aGFuIDEwMCBzdHVkZW50cy4gVGhpcyBlbGltaW5hdGVzIG91dGx5aW5nIHZhbHVlcyB3aGljaCBhcHBlYXIgZm9yIGxvdyBudW1iZXJzIG9mIHN0dWRlbnRzLCBzdWNoIGFzIG1lYXN1cmVzIGVxdWFsIHRvIDEwMCUuIEFzIGFuIGV4YW1wbGUsIHdlIGNhbiBsb29rIGF0IHRoZSB2YXJpYWJsZSBgcGN0X3BvdmA7IHRoZXJlIGFyZSBhIGZldyBkYXRhIHBvaW50cyBhdCB0aGUgMTAwJSBtYXJrLCBzbyBsZXQncyBsb29rIGF0IHRoZXNlIHZhbHVlczogCmBgYHtyfQpkaXN0cmljdF9kYXRhICU+JSAKICAgIGZpbHRlcihwY3RfcG92ID09IDEpICU+JSAKICAgIGFycmFuZ2UocGN0X3BvdikgJT4lCiAgICBzZWxlY3Qoc3RhdGUsIGRpc3QsIGNoaWxkcmVuLCBwY3RfcG92KQpgYGAKCkJlY2F1c2Ugb2YgdGhpcyBsb3cgbnVtYmVyIG9mIGNoaWxkcmVuIGFmZmVjdGluZyB0aGUgdmFsdWVzIG9mIHRoZSB2YXJpYWJsZXMgc28gbXVjaCwgd2UnbGwgc2V0IDEwMCB0byBiZSB0aGF0IGN1dG9mZiB2YWx1ZSBhbmQgY29udGludWUgd2l0aCBhbmFseXNpcy4gQWRkaXRpb25hbGx5LCBzaW5jZSB3ZSBoYXZlIG92ZXIgMTAsMDAwIHJvd3MgaW4gb3VyIGRhdGFzZXQsIHdlIHJhbmRvbWx5IHNhbXBsZSAxMDAwIG9mIHRoZXNlIHZhbHVlcyBmb3IgZWFjaCBvZiB0aGUgZm9sbG93aW5nIHBsb3RzLgoKIyMgQ29ycmVsYXRlZCBWYXJpYWJsZSBQbG90cwoKYGBge3J9CmRpc3RyaWN0X2ZpbHRlcmVkIDwtIGRpc3RyaWN0X2RhdGEgJT4lCiAgICBmaWx0ZXIoY2hpbGRyZW4gPiAxMDApCm5yb3coZGlzdHJpY3RfZGF0YSkgLSBucm93KGRpc3RyaWN0X2ZpbHRlcmVkKQoKZ2dwbG90KGRpc3RyaWN0X2ZpbHRlcmVkW3NhbXBsZSgxMDAwKSxdLAogICAgICAgYWVzKHggPSBwY3RfcG92LCAKICAgICAgICAgICB5ID0gcGN0X1NQCiAgICAgICApKSArIAogICAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMSkgKyAKICAgIGdlb21fc21vb3RoKCkKCmdncGxvdChkaXN0cmljdF9maWx0ZXJlZFtzYW1wbGUoMTAwMCksXSwKICAgICAgIGFlcyh4ID0gcGN0X3BvdiwgCiAgICAgICAgICAgeSA9IHBjdF9DQwogICAgICAgKSkgKyAKICAgIGdlb21fcG9pbnQoYWxwaGEgPSAwLjEpICsgCiAgICBnZW9tX3Ntb290aCgpCgpnZ3Bsb3QoZGlzdHJpY3RfZmlsdGVyZWRbc2FtcGxlKDEwMDApLF0sCiAgICAgICBhZXMoeCA9IHBjdF9wb3YsIAogICAgICAgICAgIHkgPSBwY3RfTkNJCiAgICAgICApKSArIAogICAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMSkgKyAKICAgIGdlb21fc21vb3RoKCkKCmdncGxvdChkaXN0cmljdF9maWx0ZXJlZFtzYW1wbGUoMTAwMCksXSwKICAgICAgIGFlcyh4ID0gcGN0X1NQLCAKICAgICAgICAgICB5ID0gcGN0X05DSQogICAgICAgKSkgKyAKICAgIGdlb21fcG9pbnQoYWxwaGEgPSAwLjEpICsgCiAgICBnZW9tX3Ntb290aCgpCgpnZ3Bsb3QoZGlzdHJpY3RfZmlsdGVyZWRbc2FtcGxlKDEwMDApLF0sCiAgICAgICBhZXMoeCA9IHBjdF9DQywgCiAgICAgICAgICAgeSA9IHBjdF9OQ0kKICAgICAgICkpICsgCiAgICBnZW9tX3BvaW50KGFscGhhID0gMC4xKSArIAogICAgZ2VvbV9zbW9vdGgoKQoKZ2dwbG90KGRpc3RyaWN0X2ZpbHRlcmVkW3NhbXBsZSgxMDAwKSxdLAogICAgICAgYWVzKHggPSBwY3RfQ0MsIAogICAgICAgICAgIHkgPSBwY3RfQ0xJCiAgICAgICApKSArIAogICAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMSkgKyAKICAgIGdlb21fc21vb3RoKCkKYGBgCgpJbW1lZGlhdGVseSBmcm9tIGFsbCBvZiB0aGVzZSBwbG90cywgd2UgY2FuIG5vdGljZSB0aGF0IHRoZSB2YXN0IG1ham9yaXR5IG9mIHZhbHVlcyBmb3IgYW55IGdpdmVuIHByZWRpY3RvciBhcmUgYmVsb3cgNTAlLiBXZSBjYW4gbm90aWNlIHRoYXQsIHNpbWlsYXIgdG8gd2hhdCBvdXIgY29ycmVsYXRpb24gbWF0cml4IHdvdWxkIGhhdmUgdXMgYmVsaWV2ZSwgdGhlcmUgYXBwZWFycyB0byBiZSBhIHBvc2l0aXZlIGNvcnJlbGF0aW9uIGJldHdlZW4gYWxsIG9mIHRoZXNlIHZhcmlhYmxlcy4KCiMjIERpc3RyaWJ1dGlvbiBvZiBOdW1iZXIgb2YgU3R1ZGVudHMKClRvIGdldCBhIGJldHRlciBpZGVhIGF0IHdoYXQgc29ydHMgb2YgbnVtYmVycyB3ZSdyZSBsb29raW5nIGF0IGluIHRlcm1zIG9mIHRoZSBudW1iZXIgb2YgY2hpbGRyZW4gaW4gZWFjaCBzaGNvb2wgZGlzdHJpY3QsIGxldCdzIGxvb2sgYXQgYSBzdW1tYXJ5IG9mIHRoZSBkaXN0cmlidXRpb24uIFdlJ2xsIGxvb2sgYXQgYWxsIHNjaG9vbCBkaXN0cmljdHMgcmF0aGVyIHRoYW4ganVzdCB0aG9zZSB3aXRoIG1vcmUgdGhhbiAxMDAgc3R1ZGVudHM6IApgYGB7cn0Kc3VtbWFyeShkaXN0cmljdF9kYXRhJGNoaWxkcmVuKQpgYGAKVGhlIG1lYW4gb2YgdGhpcyBkaXN0cmlidXRpb24gaXMgd2VsbCBhYm92ZSB0aGUgdGhpcmQgcXVhcnRpbGUsIGltcGx5aW5nIHRoYXQgdGhpcyBkYXRhIGlzIGhlYXZpbHkgcmlnaHQtc2tld2VkLiBUaGlzIG1ha2VzIHNlbnNlLCBnaXZlbiB0aGUgZmFjdCB0aGF0IHRoZXJlIGFyZSBzbyBtYW55IHNtYWxsIHNjaG9vbCBkaXN0cmljdHMgYW5kIGxpa2VseSBhIGZldyB2ZXJ5IGxhcmdlIG9uZXMuIAoKQmVjYXVzZSBvZiB0aGUgcmlnaHQtc2tld2VkIG5hdHVyZSBvZiB0aGlzIGRhdGEsIGxldCdzIGxvb2sgYXQgYSBsb2ctdHJhbnNmb3JtZWQgYm94cGxvdAoKYGBge3J9CmRpc3RyaWN0X2RhdGEgJT4lIAogICAgZmlsdGVyKGNoaWxkcmVuID4gMCkgJT4lCiAgICBnZ3Bsb3QoYWVzKHggPSBjaGlsZHJlbikpICsgCiAgICBnZW9tX2JveHBsb3QoKSArIAogICAgZ2VvbV9qaXR0ZXIoYWVzKHkgPSAwKSwgYWxwaGEgPSAwLjAxLCBoZWlnaHQgPSAwLjA1KSArIAogICAgc2NhbGVfeF9sb2cxMCgpICsgCiAgICBnZW9tX2RlbnNpdHkoKQpgYGAKCkludGVyZXN0aW5nbHksIHdoZW4gdGhlIG51bWJlciBvZiBjaGlsZHJlbiBpbiBlYWNoIGRpc3RyaWN0IGlzIGxvZy10cmFuc2Zvcm1lZCwgdGhlIGRlbnNpdHkgcGxvdCBzZWVtcyB0byBiZSByZWxhdGl2ZWx5IHN5bW1ldHJpYyBhYm91dCB0aGUgbWVkaWFuLiBQZXJoYXBzIHRoZXJlJ3Mgc29tZSBzb3J0IG9mIGxvZy1ub3JtYWwgZGlzdHJpYnV0aW9uIHVuZGVybHlpbmcgdGhlIGRpc3RyaWJ1dGlvbiBvZiBjaGlsZHJlbiBpbiBzY2hvb2wgZGlzdHJpY3RzIGluIHRoZSBVLlMuPwoKQWRkaXRpb25hbGx5LCBsZXQncyBzZWUgd2hpY2ggc2Nob29sIGRpc3RyaWN0IGhhcyBvdmVyIGEgbWlsbGlvbiBlc3RpbWF0ZWQgY2hpbGRyZW4gYWdlZCA1IHRvIDE3LiAKYGBge3J9CmRpc3RyaWN0X2RhdGEgJT4lIAogICAgc2VsZWN0KHN0YXRlLCBkaXN0LCBjaGlsZHJlbikgJT4lCiAgICBhcnJhbmdlKGRlc2MoY2hpbGRyZW4pKSAlPiUKICAgIGhlYWQoNSkKYGBgCk1ha2VzIHNlbnNlLiBJcyB0aGlzIGFjdHVhbGx5IGEgc2Nob29sIGRpc3RyaWN0LCBvciBpcyBpdCBhIGNvbmdsb21lcmF0ZSBvZiBzY2hvb2wgZGlzdHJpY3RzPyBXZSdsbCBhc3N1bWUgdGhhdCB0aGUgZGF0YSBpcyBnb29kLCBhbmQgdGhhdCB0aGUgTmV3IFlvcmsgQ2l0eSBEZXBhcnRtZW50IG9mIEVkdWNhdGlvbiBpcywgaW4gZmFjdCwgY2xhc3NpZmllZCBhcyBhIHNjaG9vbCBkaXN0cmljdC4gCgo=