Background

This dataset was posted by Jered Ataky on week 5 discussion board in DATA 607. The entire document about it can be found in this link: https://www.kaggle.com/spscientist/students-performance-in-exams

The proposed analyses were:

  • Correlation between students performance and parental level of education.

-if scores can be predicted based on the other variables such as test preparation, parental level of education, and lunch cost. We can see if these variables affect the scores and build a model.

-We can also see if some scores are correlated with each other, such as reading and writing.

Libraries

library(tidyverse)
## -- Attaching packages --------------------------------------------------------------------------------------- tidyverse 1.3.0 --
## v ggplot2 3.3.2     v purrr   0.3.4
## v tibble  3.0.3     v dplyr   1.0.2
## v tidyr   1.1.2     v stringr 1.4.0
## v readr   1.3.1     v forcats 0.5.0
## -- Conflicts ------------------------------------------------------------------------------------------ tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()
library(kableExtra)
## 
## Attaching package: 'kableExtra'
## The following object is masked from 'package:dplyr':
## 
##     group_rows

Data Transformation

Data insights and cleansing

# Get the data

data <- read.csv("https://raw.githubusercontent.com/jnataky/DATA-607/master/A2_Various_dataset_transformation/students_performance.csv")
# make a copy of the data frame 

data_copy <- data

dim(data_copy)
## [1] 1000    8
head(data_copy)
##   gender race.ethnicity parental.level.of.education        lunch
## 1 female        group B           bachelor's degree     standard
## 2 female        group C                some college     standard
## 3 female        group B             master's degree     standard
## 4   male        group A          associate's degree free/reduced
## 5   male        group C                some college     standard
## 6 female        group B          associate's degree     standard
##   test.preparation.course math.score reading.score writing.score
## 1                    none         72            72            74
## 2               completed         69            90            88
## 3                    none         90            95            93
## 4                    none         47            57            44
## 5                    none         76            78            75
## 6                    none         71            83            78
# Retrieve columns names

colnames(data_copy)
## [1] "gender"                      "race.ethnicity"             
## [3] "parental.level.of.education" "lunch"                      
## [5] "test.preparation.course"     "math.score"                 
## [7] "reading.score"               "writing.score"
# Check for missing values

sum(is.na(data_copy))
## [1] 0
# Rename columns

data_copy <- data_copy %>%
  rename(parent_level = parental.level.of.education, lunch = lunch, prep_test = test.preparation.course, math =  math.score, reading = reading.score, writing = writing.score)

head(data_copy)
##   gender race.ethnicity       parent_level        lunch prep_test math reading
## 1 female        group B  bachelor's degree     standard      none   72      72
## 2 female        group C       some college     standard completed   69      90
## 3 female        group B    master's degree     standard      none   90      95
## 4   male        group A associate's degree free/reduced      none   47      57
## 5   male        group C       some college     standard      none   76      78
## 6 female        group B associate's degree     standard      none   71      83
##   writing
## 1      74
## 2      88
## 3      93
## 4      44
## 5      75
## 6      78

Tidying the data frame

Subset data frame in 3 for further analysis

# another copy

data_copy1 <- data_copy
# Subset for parent_level and tests score

data_1 <- data_copy1[c(3,6:8)]
head(data_1)
##         parent_level math reading writing
## 1  bachelor's degree   72      72      74
## 2       some college   69      90      88
## 3    master's degree   90      95      93
## 4 associate's degree   47      57      44
## 5       some college   76      78      75
## 6 associate's degree   71      83      78
# Check different parent_level

unique(data_1$parent_level)
## [1] "bachelor's degree"  "some college"       "master's degree"   
## [4] "associate's degree" "high school"        "some high school"
# Gather columns

data_1 <- data_1 %>%
  gather("test", "score", 2:4)
# Wider the data frame

data_1 <- data_1 %>%
  group_by(parent_level, test) %>%
  summarise(average_score = round(mean(score), 0))
## `summarise()` regrouping output by 'parent_level' (override with `.groups` argument)
# Kable for tidy table

data_1 %>%
  kbl(caption = "Test score mean with parent level of education", align = 'c') %>%
  kable_material(c("striped", "hover")) %>%
  row_spec(0, color = "indigo")
Test score mean with parent level of education
parent_level test average_score
associate’s degree math 68
associate’s degree reading 71
associate’s degree writing 70
bachelor’s degree math 69
bachelor’s degree reading 73
bachelor’s degree writing 73
high school math 62
high school reading 65
high school writing 62
master’s degree math 70
master’s degree reading 75
master’s degree writing 76
some college math 67
some college reading 69
some college writing 69
some high school math 63
some high school reading 67
some high school writing 65
# Subset for lunch and tests score

data_2 <- data_copy1[c(4,6:8)]
# Check different type of lunch

unique(data_2$lunch)
## [1] "standard"     "free/reduced"
# Gather columns

data_2 <- data_2 %>%
  gather("test", "score", 2:4)
# Wider the data frame

data_2 <- data_2 %>%
  group_by(lunch, test) %>%
  summarise(average_score = round(mean(score), 0))
## `summarise()` regrouping output by 'lunch' (override with `.groups` argument)
# Kable for tidy table

data_2 %>%
  kbl(caption = "Test score mean with type of lunch offered to students", align = 'c') %>%
  kable_material(c("striped", "hover")) %>%
  row_spec(0, color = "indigo")
Test score mean with type of lunch offered to students
lunch test average_score
free/reduced math 59
free/reduced reading 65
free/reduced writing 63
standard math 70
standard reading 72
standard writing 71
# Subset for test_prep and tests score

data_3 <- data_copy1[c(5:8)]
# Gather columns

data_3 <- data_3 %>%
  gather("test", "score", 2:4)
# Wider the data frame

data_3 <- data_3 %>%
  group_by(prep_test, test) %>%
  summarise(average_score = round(mean(score), 0))
## `summarise()` regrouping output by 'prep_test' (override with `.groups` argument)
# Kable for tidy table

data_3 %>%
  kbl(caption = "Test score mean with type of lunch offered to students", align = 'c') %>%
  kable_material(c("striped", "hover")) %>%
  row_spec(0, color = "indigo")
Test score mean with type of lunch offered to students
prep_test test average_score
completed math 70
completed reading 74
completed writing 74
none math 64
none reading 67
none writing 65

Data Analysis

Correlation between parental level of education and tests score

ggplot(data = data_1) +
  geom_bar( mapping = aes(x = reorder(parent_level, average_score), y = average_score, fill = test), position = "dodge", stat = "identity") +
  facet_wrap(~ test, nrow = 3)

There is a positive correlation between parent level of education and students performance.

Correlation between lunch and tests score

ggplot(data = data_2) +
  geom_bar( mapping = aes(x = reorder(lunch, average_score), y = average_score, fill = test), position = "dodge", stat = "identity", width = 0.5) +
  facet_wrap(~ test, nrow = 3)

Students with standard lunch perform better than students with free/reduced lunch

Correlation between test preparation and tests score

ggplot(data = data_3) +
  geom_bar( mapping = aes(x = reorder(prep_test, average_score), y = average_score, fill = test), position = "dodge", stat = "identity", width = 0.5) +
  facet_wrap(~ test, nrow = 3)

There is a positive correlation between completing test preparation and not completing for all the 3 tests.

Findings

As we can see from analyses above, students performance are correlated to each of these three factors: parent level of education, lunch, and test preparation.

For parent level of education, the more the parents have a higher education the more students performed on all of the tests. This is maybe certain students tend to challenge themselves to their parents. Also something interesting is that the average performance for students whose parents level is “some high school” perform better than students whose parents completed high school.

In regards to lunch, seems like parent income affect students performance in tests.

For test preparation, this is sort of expected that students preparing for tests perform better although we can find some particular cases out there.

LS0tDQp0aXRsZTogIlByb2JsZW0gMTogU3R1ZGVudCBQZXJmb3JtYW5jZSINCmF1dGhvcjogIkplcmVkIEF0YWt5Ig0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0OiANCiAgb3BlbmludHJvOjpsYWJfcmVwb3J0OiBkZWZhdWx0DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCi0tLQ0KDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNCiMjIEJhY2tncm91bmQNCg0KDQo8c3R5bGU+DQpkaXYuYXF1YW1hcmluZSB7IGJhY2tncm91bmQtY29sb3I6IzdmZmZkNDsgYm9yZGVyLXJhZGl1czogMTBweDsgcGFkZGluZzogNXB4O30NCjwvc3R5bGU+DQo8ZGl2IGNsYXNzID0gImFxdWFtYXJpbmUiPg0KDQpUaGlzIGRhdGFzZXQgd2FzIHBvc3RlZCBieSBKZXJlZCBBdGFreSBvbiB3ZWVrIDUgZGlzY3Vzc2lvbiBib2FyZCBpbiBEQVRBIDYwNy4NClRoZSBlbnRpcmUgZG9jdW1lbnQgYWJvdXQgaXQgY2FuIGJlIGZvdW5kIGluIHRoaXMgbGluazoNCmh0dHBzOi8vd3d3LmthZ2dsZS5jb20vc3BzY2llbnRpc3Qvc3R1ZGVudHMtcGVyZm9ybWFuY2UtaW4tZXhhbXMNCg0KVGhlIHByb3Bvc2VkIGFuYWx5c2VzIHdlcmU6DQoNCi0gQ29ycmVsYXRpb24gYmV0d2VlbiBzdHVkZW50cyBwZXJmb3JtYW5jZSBhbmQgcGFyZW50YWwgbGV2ZWwgb2YgZWR1Y2F0aW9uLg0KDQotaWYgc2NvcmVzIGNhbiBiZSBwcmVkaWN0ZWQgYmFzZWQgb24gdGhlIG90aGVyIHZhcmlhYmxlcyBzdWNoIGFzIHRlc3QgcHJlcGFyYXRpb24sIA0KcGFyZW50YWwgbGV2ZWwgb2YgZWR1Y2F0aW9uLCBhbmQgbHVuY2ggY29zdC4gV2UgY2FuIHNlZSBpZiB0aGVzZSB2YXJpYWJsZXMgYWZmZWN0IHRoZSBzY29yZXMgYW5kIGJ1aWxkIGEgbW9kZWwuICANCg0KLVdlIGNhbiBhbHNvIHNlZSBpZiBzb21lIHNjb3JlcyBhcmUgY29ycmVsYXRlZCB3aXRoIGVhY2ggb3RoZXIsIHN1Y2ggYXMgcmVhZGluZyBhbmQgd3JpdGluZy4gDQoNCg0KPC9kaXY+IFxoZmlsbFxicmVhaw0KDQoNCiMjIExpYnJhcmllcw0KDQpgYGB7cn0NCg0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGthYmxlRXh0cmEpDQpgYGANCg0KIyMgRGF0YSBUcmFuc2Zvcm1hdGlvbg0KDQojIyMgRGF0YSBpbnNpZ2h0cyBhbmQgY2xlYW5zaW5nIA0KDQpgYGB7cn0NCiMgR2V0IHRoZSBkYXRhDQoNCmRhdGEgPC0gcmVhZC5jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9qbmF0YWt5L0RBVEEtNjA3L21hc3Rlci9BMl9WYXJpb3VzX2RhdGFzZXRfdHJhbnNmb3JtYXRpb24vc3R1ZGVudHNfcGVyZm9ybWFuY2UuY3N2IikNCg0KYGBgDQoNCmBgYHtyfQ0KIyBtYWtlIGEgY29weSBvZiB0aGUgZGF0YSBmcmFtZSANCg0KZGF0YV9jb3B5IDwtIGRhdGENCg0KZGltKGRhdGFfY29weSkNCg0KYGBgDQoNCmBgYHtyfQ0KaGVhZChkYXRhX2NvcHkpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KIyBSZXRyaWV2ZSBjb2x1bW5zIG5hbWVzDQoNCmNvbG5hbWVzKGRhdGFfY29weSkNCg0KYGBgDQoNCg0KYGBge3J9DQojIENoZWNrIGZvciBtaXNzaW5nIHZhbHVlcw0KDQpzdW0oaXMubmEoZGF0YV9jb3B5KSkNCg0KYGBgDQpgYGB7cn0NCiMgUmVuYW1lIGNvbHVtbnMNCg0KZGF0YV9jb3B5IDwtIGRhdGFfY29weSAlPiUNCiAgcmVuYW1lKHBhcmVudF9sZXZlbCA9IHBhcmVudGFsLmxldmVsLm9mLmVkdWNhdGlvbiwgbHVuY2ggPSBsdW5jaCwgcHJlcF90ZXN0ID0gdGVzdC5wcmVwYXJhdGlvbi5jb3Vyc2UsIG1hdGggPSAgbWF0aC5zY29yZSwgcmVhZGluZyA9IHJlYWRpbmcuc2NvcmUsIHdyaXRpbmcgPSB3cml0aW5nLnNjb3JlKQ0KDQpoZWFkKGRhdGFfY29weSkNCg0KDQpgYGANCg0KIyMjIFRpZHlpbmcgdGhlIGRhdGEgZnJhbWUNCg0KIyMjIyBTdWJzZXQgZGF0YSBmcmFtZSBpbiAzIGZvciBmdXJ0aGVyIGFuYWx5c2lzDQoNCmBgYHtyfQ0KIyBhbm90aGVyIGNvcHkNCg0KZGF0YV9jb3B5MSA8LSBkYXRhX2NvcHkNCg0KYGBgDQoNCg0KYGBge3J9DQoNCiMgU3Vic2V0IGZvciBwYXJlbnRfbGV2ZWwgYW5kIHRlc3RzIHNjb3JlDQoNCmRhdGFfMSA8LSBkYXRhX2NvcHkxW2MoMyw2OjgpXQ0KaGVhZChkYXRhXzEpDQpgYGANCg0KYGBge3J9DQojIENoZWNrIGRpZmZlcmVudCBwYXJlbnRfbGV2ZWwNCg0KdW5pcXVlKGRhdGFfMSRwYXJlbnRfbGV2ZWwpDQoNCmBgYA0KDQpgYGB7cn0NCiMgR2F0aGVyIGNvbHVtbnMNCg0KZGF0YV8xIDwtIGRhdGFfMSAlPiUNCiAgZ2F0aGVyKCJ0ZXN0IiwgInNjb3JlIiwgMjo0KQ0KDQpgYGANCg0KYGBge3J9DQojIFdpZGVyIHRoZSBkYXRhIGZyYW1lDQoNCmRhdGFfMSA8LSBkYXRhXzEgJT4lDQogIGdyb3VwX2J5KHBhcmVudF9sZXZlbCwgdGVzdCkgJT4lDQogIHN1bW1hcmlzZShhdmVyYWdlX3Njb3JlID0gcm91bmQobWVhbihzY29yZSksIDApKQ0KDQoNCmBgYA0KDQpgYGB7cn0NCg0KIyBLYWJsZSBmb3IgdGlkeSB0YWJsZQ0KDQpkYXRhXzEgJT4lDQogIGtibChjYXB0aW9uID0gIlRlc3Qgc2NvcmUgbWVhbiB3aXRoIHBhcmVudCBsZXZlbCBvZiBlZHVjYXRpb24iLCBhbGlnbiA9ICdjJykgJT4lDQogIGthYmxlX21hdGVyaWFsKGMoInN0cmlwZWQiLCAiaG92ZXIiKSkgJT4lDQogIHJvd19zcGVjKDAsIGNvbG9yID0gImluZGlnbyIpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KDQojIFN1YnNldCBmb3IgbHVuY2ggYW5kIHRlc3RzIHNjb3JlDQoNCmRhdGFfMiA8LSBkYXRhX2NvcHkxW2MoNCw2OjgpXQ0KYGBgDQoNCmBgYHtyfQ0KIyBDaGVjayBkaWZmZXJlbnQgdHlwZSBvZiBsdW5jaA0KDQp1bmlxdWUoZGF0YV8yJGx1bmNoKQ0KDQpgYGANCg0KYGBge3J9DQojIEdhdGhlciBjb2x1bW5zDQoNCmRhdGFfMiA8LSBkYXRhXzIgJT4lDQogIGdhdGhlcigidGVzdCIsICJzY29yZSIsIDI6NCkNCg0KYGBgDQoNCmBgYHtyfQ0KIyBXaWRlciB0aGUgZGF0YSBmcmFtZQ0KDQpkYXRhXzIgPC0gZGF0YV8yICU+JQ0KICBncm91cF9ieShsdW5jaCwgdGVzdCkgJT4lDQogIHN1bW1hcmlzZShhdmVyYWdlX3Njb3JlID0gcm91bmQobWVhbihzY29yZSksIDApKQ0KDQpgYGANCg0KYGBge3J9DQoNCiMgS2FibGUgZm9yIHRpZHkgdGFibGUNCg0KZGF0YV8yICU+JQ0KICBrYmwoY2FwdGlvbiA9ICJUZXN0IHNjb3JlIG1lYW4gd2l0aCB0eXBlIG9mIGx1bmNoIG9mZmVyZWQgdG8gc3R1ZGVudHMiLCBhbGlnbiA9ICdjJykgJT4lDQogIGthYmxlX21hdGVyaWFsKGMoInN0cmlwZWQiLCAiaG92ZXIiKSkgJT4lDQogIHJvd19zcGVjKDAsIGNvbG9yID0gImluZGlnbyIpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KDQojIFN1YnNldCBmb3IgdGVzdF9wcmVwIGFuZCB0ZXN0cyBzY29yZQ0KDQpkYXRhXzMgPC0gZGF0YV9jb3B5MVtjKDU6OCldDQpgYGANCg0KDQpgYGB7cn0NCiMgR2F0aGVyIGNvbHVtbnMNCg0KZGF0YV8zIDwtIGRhdGFfMyAlPiUNCiAgZ2F0aGVyKCJ0ZXN0IiwgInNjb3JlIiwgMjo0KQ0KDQpgYGANCg0KDQpgYGB7cn0NCiMgV2lkZXIgdGhlIGRhdGEgZnJhbWUNCg0KZGF0YV8zIDwtIGRhdGFfMyAlPiUNCiAgZ3JvdXBfYnkocHJlcF90ZXN0LCB0ZXN0KSAlPiUNCiAgc3VtbWFyaXNlKGF2ZXJhZ2Vfc2NvcmUgPSByb3VuZChtZWFuKHNjb3JlKSwgMCkpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KDQojIEthYmxlIGZvciB0aWR5IHRhYmxlDQoNCmRhdGFfMyAlPiUNCiAga2JsKGNhcHRpb24gPSAiVGVzdCBzY29yZSBtZWFuIHdpdGggdHlwZSBvZiBsdW5jaCBvZmZlcmVkIHRvIHN0dWRlbnRzIiwgYWxpZ24gPSAnYycpICU+JQ0KICBrYWJsZV9tYXRlcmlhbChjKCJzdHJpcGVkIiwgImhvdmVyIikpICU+JQ0KICByb3dfc3BlYygwLCBjb2xvciA9ICJpbmRpZ28iKQ0KDQpgYGANCg0KDQojIyBEYXRhIEFuYWx5c2lzDQoNCiMjIyBDb3JyZWxhdGlvbiBiZXR3ZWVuIHBhcmVudGFsIGxldmVsIG9mIGVkdWNhdGlvbiBhbmQgdGVzdHMgc2NvcmUNCg0KYGBge3J9DQoNCmdncGxvdChkYXRhID0gZGF0YV8xKSArDQogIGdlb21fYmFyKCBtYXBwaW5nID0gYWVzKHggPSByZW9yZGVyKHBhcmVudF9sZXZlbCwgYXZlcmFnZV9zY29yZSksIHkgPSBhdmVyYWdlX3Njb3JlLCBmaWxsID0gdGVzdCksIHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgZmFjZXRfd3JhcCh+IHRlc3QsIG5yb3cgPSAzKQ0KDQpgYGANCg0KVGhlcmUgaXMgYSBwb3NpdGl2ZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHBhcmVudCBsZXZlbCBvZiBlZHVjYXRpb24gDQphbmQgc3R1ZGVudHMgcGVyZm9ybWFuY2UuDQoNCg0KIyMjIENvcnJlbGF0aW9uIGJldHdlZW4gbHVuY2ggYW5kIHRlc3RzIHNjb3JlDQoNCg0KYGBge3J9DQoNCmdncGxvdChkYXRhID0gZGF0YV8yKSArDQogIGdlb21fYmFyKCBtYXBwaW5nID0gYWVzKHggPSByZW9yZGVyKGx1bmNoLCBhdmVyYWdlX3Njb3JlKSwgeSA9IGF2ZXJhZ2Vfc2NvcmUsIGZpbGwgPSB0ZXN0KSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAwLjUpICsNCiAgZmFjZXRfd3JhcCh+IHRlc3QsIG5yb3cgPSAzKQ0KDQpgYGANClN0dWRlbnRzIHdpdGggc3RhbmRhcmQgbHVuY2ggcGVyZm9ybSBiZXR0ZXIgdGhhbiBzdHVkZW50cyB3aXRoIGZyZWUvcmVkdWNlZCBsdW5jaCANCg0KDQojIyMgQ29ycmVsYXRpb24gYmV0d2VlbiB0ZXN0IHByZXBhcmF0aW9uIGFuZCB0ZXN0cyBzY29yZQ0KDQpgYGB7cn0NCg0KZ2dwbG90KGRhdGEgPSBkYXRhXzMpICsNCiAgZ2VvbV9iYXIoIG1hcHBpbmcgPSBhZXMoeCA9IHJlb3JkZXIocHJlcF90ZXN0LCBhdmVyYWdlX3Njb3JlKSwgeSA9IGF2ZXJhZ2Vfc2NvcmUsIGZpbGwgPSB0ZXN0KSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAwLjUpICsNCiAgZmFjZXRfd3JhcCh+IHRlc3QsIG5yb3cgPSAzKQ0KDQpgYGANClRoZXJlIGlzIGEgcG9zaXRpdmUgY29ycmVsYXRpb24gYmV0d2VlbiBjb21wbGV0aW5nIHRlc3QgcHJlcGFyYXRpb24gYW5kIG5vdCBjb21wbGV0aW5nDQpmb3IgYWxsIHRoZSAzIHRlc3RzLg0KDQoNCiMjIEZpbmRpbmdzDQoNCg0KPHN0eWxlPg0KZGl2LmFxdWFtYXJpbmUgeyBiYWNrZ3JvdW5kLWNvbG9yOiM3ZmZmZDQ7IGJvcmRlci1yYWRpdXM6IDEwcHg7IHBhZGRpbmc6IDVweDt9DQo8L3N0eWxlPg0KPGRpdiBjbGFzcyA9ICJhcXVhbWFyaW5lIj4NCg0KDQpBcyB3ZSBjYW4gc2VlIGZyb20gYW5hbHlzZXMgYWJvdmUsIHN0dWRlbnRzIHBlcmZvcm1hbmNlIGFyZSBjb3JyZWxhdGVkIHRvIGVhY2ggb2YgdGhlc2UgdGhyZWUgDQpmYWN0b3JzOiBwYXJlbnQgbGV2ZWwgb2YgZWR1Y2F0aW9uLCBsdW5jaCwgYW5kIHRlc3QgcHJlcGFyYXRpb24uDQoNCkZvciBwYXJlbnQgbGV2ZWwgb2YgZWR1Y2F0aW9uLCB0aGUgbW9yZSB0aGUgcGFyZW50cyBoYXZlIGEgaGlnaGVyIGVkdWNhdGlvbiANCnRoZSBtb3JlIHN0dWRlbnRzIHBlcmZvcm1lZCBvbiBhbGwgb2YgdGhlIHRlc3RzLiBUaGlzIGlzIG1heWJlIGNlcnRhaW4gc3R1ZGVudHMgdGVuZCB0byANCmNoYWxsZW5nZSB0aGVtc2VsdmVzIHRvIHRoZWlyIHBhcmVudHMuIEFsc28gc29tZXRoaW5nIGludGVyZXN0aW5nIGlzIHRoYXQgDQp0aGUgYXZlcmFnZSBwZXJmb3JtYW5jZSBmb3Igc3R1ZGVudHMgd2hvc2UgcGFyZW50cyBsZXZlbCBpcyAic29tZSBoaWdoIHNjaG9vbCIgcGVyZm9ybQ0KYmV0dGVyIHRoYW4gc3R1ZGVudHMgd2hvc2UgcGFyZW50cyBjb21wbGV0ZWQgaGlnaCBzY2hvb2wuDQoNCkluIHJlZ2FyZHMgdG8gbHVuY2gsIHNlZW1zIGxpa2UgcGFyZW50IGluY29tZSBhZmZlY3Qgc3R1ZGVudHMgcGVyZm9ybWFuY2UgaW4gdGVzdHMuDQoNCkZvciB0ZXN0IHByZXBhcmF0aW9uLCB0aGlzIGlzIHNvcnQgb2YgZXhwZWN0ZWQgdGhhdCBzdHVkZW50cyBwcmVwYXJpbmcgZm9yIHRlc3RzIA0KcGVyZm9ybSBiZXR0ZXIgYWx0aG91Z2ggd2UgY2FuIGZpbmQgc29tZSBwYXJ0aWN1bGFyIGNhc2VzIG91dCB0aGVyZS4NCg0KDQoNCjwvZGl2PiBcaGZpbGxcYnJlYWsNCg==