Loading Data

Loading libraries

library(tidyverse)
library(magrittr)
#library(scales)
library(modelr)

Reading raw score data for last year’s tests

tracker <- read_csv("raw_tracker.csv") #### Read from LMS 
 #### Folder GoH Testing > Cohort17-21 > AY17-18 Class 9 BL-ML-EL
glimpse(tracker)
Observations: 5,260
Variables: 9
$ `Centre Name` <chr> "AMSSS Agroha, Hisar", "AMSSS Agroha, Hisar", "AMSSS Agroha, Hisar",...
$ `Student ID`  <chr> "HI10100001", "HI10100003", "HI10100005", "HI10100007", "HI10100009"...
$ ENG_BL        <int> 12, 8, 13, 13, 13, 11, NA, 12, 11, NA, NA, 8, NA, 10, NA, 8, 5, 3, 1...
$ MTH_BL        <int> 9, 12, 10, 20, 10, 13, 9, 14, 10, 14, 18, 18, 15, 15, 22, 12, 12, 9,...
$ MTH_EL        <int> 29, NA, 23, NA, NA, NA, NA, 35, 19, NA, NA, 38, NA, NA, 23, 12, NA, ...
$ MTH_ML        <int> 15, 8, 12, 16, 11, 11, 11, 22, NA, 13, NA, 22, NA, 17, 13, 8, 9, 7, ...
$ SCI_BL        <int> 9, 19, 15, 17, 26, 20, 9, 15, 16, 20, 17, 19, 15, 19, 23, 13, 8, 14,...
$ SCI_EL        <int> 13, NA, 9, NA, NA, NA, NA, 16, 8, NA, NA, 23, NA, NA, 8, 12, NA, NA,...
$ SCI_ML        <int> 12, 14, 15, 15, 11, 10, 8, 15, NA, 11, NA, 19, NA, 12, 11, 12, 12, 1...

Reading scores for Baseline 2 along with subject and grade level scores

df10 <- read_csv("df10_raw.csv") #### Evaluated from OMR data
#### Folder GoH Testing > AY18-19 > Baseline Eng Medium 59 Schools [Oct]
 
glimpse(df10)
Observations: 3,361
Variables: 13
$ X1           <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20...
$ Student.ID   <chr> "HI10100051", "HI10100023", "HI10100119", "HI10100131", "HI10100049",...
$ Sheet.ID     <chr> "100673", "100643", "100644", "100645", "100646", "100648", "100649",...
$ Set          <chr> "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A",...
$ School.Name  <chr> "AMSSS Agroha 10th.xlsx", "AMSSS Agroha 10th.xlsx", "AMSSS Agroha 10t...
$ Grade        <int> 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 1...
$ Total        <int> 57, 62, 47, 44, 57, 70, 66, 52, 53, 54, 66, 42, 56, 60, 33, 58, 46, 5...
$ MTH_BL2      <int> 34, 35, 24, 18, 35, 38, 36, 24, 27, 28, 37, 28, 32, 30, 18, 29, 25, 3...
$ SCI_BL2      <int> 23, 27, 23, 26, 22, 32, 30, 28, 26, 26, 29, 14, 24, 30, 15, 29, 21, 2...
$ MTH_BL2_AT9  <int> 15, 13, 9, 8, 14, 16, 15, 9, 10, 10, 16, 9, 11, 10, 6, 11, 8, 12, 6, ...
$ SCI_BL2_AT9  <int> 8, 13, 9, 11, 11, 15, 12, 11, 9, 9, 12, 4, 10, 12, 7, 11, 6, 12, 7, 3...
$ MTH_BL2_BEL9 <int> 19, 22, 15, 10, 21, 22, 21, 15, 17, 18, 21, 19, 21, 20, 12, 18, 17, 1...
$ SCI_BL2_BEL9 <int> 15, 14, 14, 15, 11, 17, 18, 17, 17, 17, 17, 10, 14, 18, 8, 18, 15, 17...

Data Cleaning

Joining both tables

tracker %<>%
  inner_join(df10, by = c(`Student ID` = "Student.ID")) #### Notice " " for common variables
 (tracker)

Removing unnecessary columns

tracker %<>%
  select(-MTH_ML, -SCI_ML, -MTH_EL, -SCI_EL, -ENG_BL, -X1, -Sheet.ID, -Set, -School.Name, -Grade, -Total)
 (tracker)

Keeping only students who gave both tests

tracker %<>%
  filter(!is.na(MTH_BL)) %>%
  filter(!is.na(MTH_BL2))
dim(tracker)
[1] 2701   10

Combining Math and Science Scores to get Baseline 1 and Baseline 2 (Grade 8 and below only) scores

gain <- tracker %>%
  mutate(BL1 = (MTH_BL + SCI_BL)) %>%
  mutate(BL2_BEL9 = (MTH_BL2_BEL9 + SCI_BL2_BEL9)) %>%
  select(`Centre Name`, `Student ID`, BL1, BL2_BEL9)
 (gain)

Absolute Improvement on Normalized Scores

Min Max Scaling of Raw Scores to a range of [0,100]

normalize <- function(x) {
    return (round(100*(x - min(x)) / (max(x) - min(x))))
  }
gain %<>%
  bind_cols(as.data.frame(lapply(gain["BL1"], normalize))) %>%
  bind_cols(as.data.frame(lapply(gain["BL2_BEL9"], normalize))) %>%
  rename(norm_BL1 = BL11) %>%
  rename(norm_BL2_BEL9 = BL2_BEL91)
 (gain)

Average score per school and improvement

school_gain <- gain %>%
  group_by(`Centre Name`) %>%
  summarise(count = n(),
            Avg_Norm_BL1 = round(mean(norm_BL1)),
            Avg_Norm_BL2_BEL9 = round(mean(norm_BL2_BEL9)),
            Delta_Avg = Avg_Norm_BL2_BEL9 - Avg_Norm_BL1
            ) %>%
  arrange(Delta_Avg)
school_gain

Plotting normalized scores by student

gain %>%
  ggplot(aes(x = norm_BL1, y = norm_BL2_BEL9 )) +     #### No quotes needed in aes x and y arguement
  geom_point(aes(colour = `Centre Name`)) + 
  geom_smooth(method = "lm", se=FALSE) +      #### Removes the 95% confidence interval
  theme(legend.position="none") +
  xlim(0,100) +
  ylim(0,100)

Plotting school-wise average scores

school_gain %>%
  ggplot(aes(x = Avg_Norm_BL1, y = Avg_Norm_BL2_BEL9, label = `Centre Name` )) +     #### No quotes needed in aes x and y arguement
  geom_point() + 
  #geom_smooth(method = "lm", se=FALSE) +     #### Removes the 95% confidence interval
  #xlim(0,100) +
  #ylim(0,100)
  geom_text(check_overlap = TRUE, size = 2) +
  theme(legend.position="none")

Relative gain within school-groups based on performance

Let’s classify these schools into 3 categories based on their Avg Score in BL1

school_gain %<>%
  mutate(Performance = if_else(Avg_Norm_BL1 < 35, "Low", 
                               if_else(Avg_Norm_BL1 < 45, "Mid", "High")
                               )
         )
school_gain %>%
  ggplot(aes(x = Avg_Norm_BL1, y = Avg_Norm_BL2_BEL9, label = `Centre Name` )) +     #### No quotes needed in aes x and y arguement
  geom_point(aes(colour = factor(Performance), fill = factor(Performance))) + 
  #geom_smooth(method = "lm", se=FALSE) +     #### Removes the 95% confidence interval
  #xlim(0,100) +
  #ylim(0,100)
  geom_text(check_overlap = TRUE, size = 2) +
  theme(legend.position="none") +
  scale_colour_manual(values = c("Low" = "red", "Mid" = "blue", "High" = "green"))

Mapping school performance to student data

gain %<>%
  left_join(school_gain, by = "Centre Name") %>%
  select(-count, -Avg_Norm_BL1, -Avg_Norm_BL2_BEL9, -Delta_Avg)
(gain)

Checking student gain at Low performing schools first

low_performing <- gain %>%
  filter(Performance == "Low")
#### Getting linear regression fit
low_mod <- lm(norm_BL2_BEL9 ~ norm_BL1, data = low_performing)
low_performing %<>% 
  add_predictions(low_mod) %>%
  add_residuals(low_mod)
low_performing %<>%
  mutate(delta = round(100*resid / norm_BL1) )
low_performing %<>%
  mutate(movement = if_else(delta > 20, "UP", (if_else(delta > -20, "SAME", "DOWN"))))
#### Count of UP / DOWN and SAME per school for Low performing schools
low_performing %>%
  group_by(`Centre Name`, movement) %>%
  summarise(countCommonStudents = n() ) %>%
  spread(movement, countCommonStudents) %>%
  replace(., is.na(.), 0) %>%               #### Replace missing values from spread with 0
  mutate(NET_perc_UP = round(100*(UP-DOWN) / (UP+DOWN+SAME))) %>%
  arrange(NET_perc_UP)

Checking student gain of Middle Performing Schools

mid_performing <- gain %>%
  filter(Performance == "Mid")
#### Getting linear regression fit
mid_mod <- lm(norm_BL2_BEL9 ~ norm_BL1, data = mid_performing)
mid_performing %<>% 
  add_predictions(mid_mod) %>%
  add_residuals(mid_mod)
mid_performing %<>%
  mutate(delta = round(100*resid / norm_BL1) ) %>%
  mutate(movement = if_else(delta > 20, "UP", (if_else(delta > -20, "SAME", "DOWN"))))
#### Count of UP / DOWN and SAME per school for Low performing schools
mid_performing %>%
  group_by(`Centre Name`, movement) %>%
  summarise(countCommonStudents = n() ) %>%
  spread(movement, countCommonStudents) %>%
  replace(., is.na(.), 0) %>%
  mutate(NET_perc_UP = round(100*(UP-DOWN) / (UP+DOWN+SAME))) %>%
  arrange(NET_perc_UP)

Checking student gain of High Performing Schools

high_performing <- gain %>%
  filter(Performance == "High")
#### Getting linear regression fit
high_mod <- lm(norm_BL2_BEL9 ~ norm_BL1, data = high_performing)
high_performing %<>% 
  add_predictions(high_mod) %>%
  add_residuals(high_mod)
high_performing %<>%
  mutate(delta = round(100*resid / norm_BL1) ) %>%
  mutate(movement = if_else(delta > 20, "UP", (if_else(delta > -20, "SAME", "DOWN"))))
#### Count of UP / DOWN and SAME per school for Low performing schools
high_performing %>%
  group_by(`Centre Name`, movement) %>%
  summarise(countCommonStudents = n() ) %>%
  spread(movement, countCommonStudents) %>%
  replace(., is.na(.), 0) %>%
  mutate(NET_perc_UP = round(100*(UP-DOWN) / (UP+DOWN+SAME))) %>%
  arrange(NET_perc_UP)
LS0tCnRpdGxlOiAiQmFzZWxpbmUgU2NvcmVzIENvbXBhcmlzb24gLSAyMDE3IHYgMjAxOCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMgTG9hZGluZyBEYXRhCiMjIyMgTG9hZGluZyBsaWJyYXJpZXMKYGBge3IgZWNobz1UUlVFLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShtYWdyaXR0cikKI2xpYnJhcnkoc2NhbGVzKQpsaWJyYXJ5KG1vZGVscikKYGBgCgojIyMjIFJlYWRpbmcgcmF3IHNjb3JlIGRhdGEgZm9yIGxhc3QgeWVhcidzIHRlc3RzCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRX0KdHJhY2tlciA8LSByZWFkX2NzdigicmF3X3RyYWNrZXIuY3N2IikgIyMjIyBSZWFkIGZyb20gTE1TIAogIyMjIyBGb2xkZXIgR29IIFRlc3RpbmcgPiBDb2hvcnQxNy0yMSA+IEFZMTctMTggQ2xhc3MgOSBCTC1NTC1FTAoKZ2xpbXBzZSh0cmFja2VyKQpgYGAKCiMjIyMgUmVhZGluZyBzY29yZXMgZm9yIEJhc2VsaW5lIDIgYWxvbmcgd2l0aCBzdWJqZWN0IGFuZCBncmFkZSBsZXZlbCBzY29yZXMKYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpkZjEwIDwtIHJlYWRfY3N2KCJkZjEwX3Jhdy5jc3YiKSAjIyMjIEV2YWx1YXRlZCBmcm9tIE9NUiBkYXRhCiMjIyMgRm9sZGVyIEdvSCBUZXN0aW5nID4gQVkxOC0xOSA+IEJhc2VsaW5lIEVuZyBNZWRpdW0gNTkgU2Nob29scyBbT2N0XQogCmdsaW1wc2UoZGYxMCkKYGBgCgojIyBEYXRhIENsZWFuaW5nCiMjIyMgSm9pbmluZyBib3RoIHRhYmxlcwpgYGB7ciBlY2hvPVRSVUV9CnRyYWNrZXIgJTw+JQogIGlubmVyX2pvaW4oZGYxMCwgYnkgPSBjKGBTdHVkZW50IElEYCA9ICJTdHVkZW50LklEIikpICMjIyMgTm90aWNlICIgIiBmb3IgY29tbW9uIHZhcmlhYmxlcwoKICh0cmFja2VyKQpgYGAKCiMjIyMgUmVtb3ZpbmcgdW5uZWNlc3NhcnkgY29sdW1ucwpgYGB7ciBlY2hvPVRSVUV9CnRyYWNrZXIgJTw+JQogIHNlbGVjdCgtTVRIX01MLCAtU0NJX01MLCAtTVRIX0VMLCAtU0NJX0VMLCAtRU5HX0JMLCAtWDEsIC1TaGVldC5JRCwgLVNldCwgLVNjaG9vbC5OYW1lLCAtR3JhZGUsIC1Ub3RhbCkKCiAodHJhY2tlcikKYGBgCgojIyMjIEtlZXBpbmcgb25seSBzdHVkZW50cyB3aG8gZ2F2ZSBib3RoIHRlc3RzCmBgYHtyIGVjaG89VFJVRX0KdHJhY2tlciAlPD4lCiAgZmlsdGVyKCFpcy5uYShNVEhfQkwpKSAlPiUKICBmaWx0ZXIoIWlzLm5hKE1USF9CTDIpKQoKZGltKHRyYWNrZXIpCmBgYAoKIyMjIyBDb21iaW5pbmcgTWF0aCBhbmQgU2NpZW5jZSBTY29yZXMgdG8gZ2V0IEJhc2VsaW5lIDEgYW5kIEJhc2VsaW5lIDIgKEdyYWRlIDggYW5kIGJlbG93IG9ubHkpIHNjb3JlcwpgYGB7ciBlY2hvPVRSVUV9CmdhaW4gPC0gdHJhY2tlciAlPiUKICBtdXRhdGUoQkwxID0gKE1USF9CTCArIFNDSV9CTCkpICU+JQogIG11dGF0ZShCTDJfQkVMOSA9IChNVEhfQkwyX0JFTDkgKyBTQ0lfQkwyX0JFTDkpKSAlPiUKICBzZWxlY3QoYENlbnRyZSBOYW1lYCwgYFN0dWRlbnQgSURgLCBCTDEsIEJMMl9CRUw5KQoKIChnYWluKQpgYGAKCiMjIEFic29sdXRlIEltcHJvdmVtZW50IG9uIE5vcm1hbGl6ZWQgU2NvcmVzCiMjIyMgTWluIE1heCBTY2FsaW5nIG9mIFJhdyBTY29yZXMgdG8gYSByYW5nZSBvZiBbMCwxMDBdCmBgYHtyIGVjaG89VFJVRX0Kbm9ybWFsaXplIDwtIGZ1bmN0aW9uKHgpIHsKICAgIHJldHVybiAocm91bmQoMTAwKih4IC0gbWluKHgpKSAvIChtYXgoeCkgLSBtaW4oeCkpKSkKICB9CgpnYWluICU8PiUKICBiaW5kX2NvbHMoYXMuZGF0YS5mcmFtZShsYXBwbHkoZ2FpblsiQkwxIl0sIG5vcm1hbGl6ZSkpKSAlPiUKICBiaW5kX2NvbHMoYXMuZGF0YS5mcmFtZShsYXBwbHkoZ2FpblsiQkwyX0JFTDkiXSwgbm9ybWFsaXplKSkpICU+JQogIHJlbmFtZShub3JtX0JMMSA9IEJMMTEpICU+JQogIHJlbmFtZShub3JtX0JMMl9CRUw5ID0gQkwyX0JFTDkxKQoKIChnYWluKQpgYGAKCiMjIyMgQXZlcmFnZSBzY29yZSBwZXIgc2Nob29sIGFuZCBpbXByb3ZlbWVudApgYGB7ciBlY2hvPVRSVUV9CnNjaG9vbF9nYWluIDwtIGdhaW4gJT4lCiAgZ3JvdXBfYnkoYENlbnRyZSBOYW1lYCkgJT4lCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpLAogICAgICAgICAgICBBdmdfTm9ybV9CTDEgPSByb3VuZChtZWFuKG5vcm1fQkwxKSksCiAgICAgICAgICAgIEF2Z19Ob3JtX0JMMl9CRUw5ID0gcm91bmQobWVhbihub3JtX0JMMl9CRUw5KSksCiAgICAgICAgICAgIERlbHRhX0F2ZyA9IEF2Z19Ob3JtX0JMMl9CRUw5IC0gQXZnX05vcm1fQkwxCiAgICAgICAgICAgICkgJT4lCiAgYXJyYW5nZShEZWx0YV9BdmcpCgpzY2hvb2xfZ2FpbgpgYGAKCgojIyMjIFBsb3R0aW5nIG5vcm1hbGl6ZWQgc2NvcmVzIGJ5IHN0dWRlbnQKYGBge3IgZWNobz1UUlVFfQpnYWluICU+JQogIGdncGxvdChhZXMoeCA9IG5vcm1fQkwxLCB5ID0gbm9ybV9CTDJfQkVMOSApKSArICAgICAjIyMjIE5vIHF1b3RlcyBuZWVkZWQgaW4gYWVzIHggYW5kIHkgYXJndWVtZW50CiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gYENlbnRyZSBOYW1lYCkpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2U9RkFMU0UpICsgICAgICAjIyMjIFJlbW92ZXMgdGhlIDk1JSBjb25maWRlbmNlIGludGVydmFsCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKwogIHhsaW0oMCwxMDApICsKICB5bGltKDAsMTAwKQpgYGAKCiMjIyMgUGxvdHRpbmcgc2Nob29sLXdpc2UgYXZlcmFnZSBzY29yZXMKYGBge3IgZWNobz1UUlVFfQpzY2hvb2xfZ2FpbiAlPiUKICBnZ3Bsb3QoYWVzKHggPSBBdmdfTm9ybV9CTDEsIHkgPSBBdmdfTm9ybV9CTDJfQkVMOSwgbGFiZWwgPSBgQ2VudHJlIE5hbWVgICkpICsgICAgICMjIyMgTm8gcXVvdGVzIG5lZWRlZCBpbiBhZXMgeCBhbmQgeSBhcmd1ZW1lbnQKICBnZW9tX3BvaW50KCkgKyAKICAjZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2U9RkFMU0UpICsgICAgICMjIyMgUmVtb3ZlcyB0aGUgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwKICAjeGxpbSgwLDEwMCkgKwogICN5bGltKDAsMTAwKQogIGdlb21fdGV4dChjaGVja19vdmVybGFwID0gVFJVRSwgc2l6ZSA9IDIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKQpgYGAKCiMjIFJlbGF0aXZlIGdhaW4gd2l0aGluIHNjaG9vbC1ncm91cHMgYmFzZWQgb24gcGVyZm9ybWFuY2UgCiMjIyMgTGV0J3MgY2xhc3NpZnkgdGhlc2Ugc2Nob29scyBpbnRvIDMgY2F0ZWdvcmllcyBiYXNlZCBvbiB0aGVpciBBdmcgU2NvcmUgaW4gQkwxCmBgYHtyIGVjaG89VFJVRX0Kc2Nob29sX2dhaW4gJTw+JQogIG11dGF0ZShQZXJmb3JtYW5jZSA9IGlmX2Vsc2UoQXZnX05vcm1fQkwxIDwgMzUsICJMb3ciLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmX2Vsc2UoQXZnX05vcm1fQkwxIDwgNDUsICJNaWQiLCAiSGlnaCIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICkKCnNjaG9vbF9nYWluICU+JQogIGdncGxvdChhZXMoeCA9IEF2Z19Ob3JtX0JMMSwgeSA9IEF2Z19Ob3JtX0JMMl9CRUw5LCBsYWJlbCA9IGBDZW50cmUgTmFtZWAgKSkgKyAgICAgIyMjIyBObyBxdW90ZXMgbmVlZGVkIGluIGFlcyB4IGFuZCB5IGFyZ3VlbWVudAogIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IGZhY3RvcihQZXJmb3JtYW5jZSksIGZpbGwgPSBmYWN0b3IoUGVyZm9ybWFuY2UpKSkgKyAKICAjZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2U9RkFMU0UpICsgICAgICMjIyMgUmVtb3ZlcyB0aGUgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwKICAjeGxpbSgwLDEwMCkgKwogICN5bGltKDAsMTAwKQogIGdlb21fdGV4dChjaGVja19vdmVybGFwID0gVFJVRSwgc2l6ZSA9IDIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJMb3ciID0gInJlZCIsICJNaWQiID0gImJsdWUiLCAiSGlnaCIgPSAiZ3JlZW4iKSkKYGBgCgojIyMjIE1hcHBpbmcgc2Nob29sIHBlcmZvcm1hbmNlIHRvIHN0dWRlbnQgZGF0YQpgYGB7ciBlY2hvPVRSVUV9CmdhaW4gJTw+JQogIGxlZnRfam9pbihzY2hvb2xfZ2FpbiwgYnkgPSAiQ2VudHJlIE5hbWUiKSAlPiUKICBzZWxlY3QoLWNvdW50LCAtQXZnX05vcm1fQkwxLCAtQXZnX05vcm1fQkwyX0JFTDksIC1EZWx0YV9BdmcpCgooZ2FpbikKYGBgCgoKIyMjIyBDaGVja2luZyBzdHVkZW50IGdhaW4gYXQgTG93IHBlcmZvcm1pbmcgc2Nob29scyBmaXJzdApgYGB7ciBlY2hvPVRSVUV9Cmxvd19wZXJmb3JtaW5nIDwtIGdhaW4gJT4lCiAgZmlsdGVyKFBlcmZvcm1hbmNlID09ICJMb3ciKQojIyMjIEdldHRpbmcgbGluZWFyIHJlZ3Jlc3Npb24gZml0Cmxvd19tb2QgPC0gbG0obm9ybV9CTDJfQkVMOSB+IG5vcm1fQkwxLCBkYXRhID0gbG93X3BlcmZvcm1pbmcpCgpsb3dfcGVyZm9ybWluZyAlPD4lIAogIGFkZF9wcmVkaWN0aW9ucyhsb3dfbW9kKSAlPiUKICBhZGRfcmVzaWR1YWxzKGxvd19tb2QpCgpsb3dfcGVyZm9ybWluZyAlPD4lCiAgbXV0YXRlKGRlbHRhID0gcm91bmQoMTAwKnJlc2lkIC8gbm9ybV9CTDEpICkKCmxvd19wZXJmb3JtaW5nICU8PiUKICBtdXRhdGUobW92ZW1lbnQgPSBpZl9lbHNlKGRlbHRhID4gMjAsICJVUCIsIChpZl9lbHNlKGRlbHRhID4gLTIwLCAiU0FNRSIsICJET1dOIikpKSkKCiMjIyMgQ291bnQgb2YgVVAgLyBET1dOIGFuZCBTQU1FIHBlciBzY2hvb2wgZm9yIExvdyBwZXJmb3JtaW5nIHNjaG9vbHMKbG93X3BlcmZvcm1pbmcgJT4lCiAgZ3JvdXBfYnkoYENlbnRyZSBOYW1lYCwgbW92ZW1lbnQpICU+JQogIHN1bW1hcmlzZShjb3VudENvbW1vblN0dWRlbnRzID0gbigpICkgJT4lCiAgc3ByZWFkKG1vdmVtZW50LCBjb3VudENvbW1vblN0dWRlbnRzKSAlPiUKICByZXBsYWNlKC4sIGlzLm5hKC4pLCAwKSAlPiUgICAgICAgICAgICAgICAjIyMjIFJlcGxhY2UgbWlzc2luZyB2YWx1ZXMgZnJvbSBzcHJlYWQgd2l0aCAwCiAgbXV0YXRlKE5FVF9wZXJjX1VQID0gcm91bmQoMTAwKihVUC1ET1dOKSAvIChVUCtET1dOK1NBTUUpKSkgJT4lCiAgYXJyYW5nZShORVRfcGVyY19VUCkKYGBgCgojIyMjIENoZWNraW5nIHN0dWRlbnQgZ2FpbiBvZiBNaWRkbGUgUGVyZm9ybWluZyBTY2hvb2xzCmBgYHtyIGVjaG89VFJVRX0KbWlkX3BlcmZvcm1pbmcgPC0gZ2FpbiAlPiUKICBmaWx0ZXIoUGVyZm9ybWFuY2UgPT0gIk1pZCIpCiMjIyMgR2V0dGluZyBsaW5lYXIgcmVncmVzc2lvbiBmaXQKbWlkX21vZCA8LSBsbShub3JtX0JMMl9CRUw5IH4gbm9ybV9CTDEsIGRhdGEgPSBtaWRfcGVyZm9ybWluZykKCm1pZF9wZXJmb3JtaW5nICU8PiUgCiAgYWRkX3ByZWRpY3Rpb25zKG1pZF9tb2QpICU+JQogIGFkZF9yZXNpZHVhbHMobWlkX21vZCkKCm1pZF9wZXJmb3JtaW5nICU8PiUKICBtdXRhdGUoZGVsdGEgPSByb3VuZCgxMDAqcmVzaWQgLyBub3JtX0JMMSkgKSAlPiUKICBtdXRhdGUobW92ZW1lbnQgPSBpZl9lbHNlKGRlbHRhID4gMjAsICJVUCIsIChpZl9lbHNlKGRlbHRhID4gLTIwLCAiU0FNRSIsICJET1dOIikpKSkKCiMjIyMgQ291bnQgb2YgVVAgLyBET1dOIGFuZCBTQU1FIHBlciBzY2hvb2wgZm9yIExvdyBwZXJmb3JtaW5nIHNjaG9vbHMKbWlkX3BlcmZvcm1pbmcgJT4lCiAgZ3JvdXBfYnkoYENlbnRyZSBOYW1lYCwgbW92ZW1lbnQpICU+JQogIHN1bW1hcmlzZShjb3VudENvbW1vblN0dWRlbnRzID0gbigpICkgJT4lCiAgc3ByZWFkKG1vdmVtZW50LCBjb3VudENvbW1vblN0dWRlbnRzKSAlPiUKICByZXBsYWNlKC4sIGlzLm5hKC4pLCAwKSAlPiUKICBtdXRhdGUoTkVUX3BlcmNfVVAgPSByb3VuZCgxMDAqKFVQLURPV04pIC8gKFVQK0RPV04rU0FNRSkpKSAlPiUKICBhcnJhbmdlKE5FVF9wZXJjX1VQKQpgYGAKCiMjIyMgQ2hlY2tpbmcgc3R1ZGVudCBnYWluIG9mIEhpZ2ggUGVyZm9ybWluZyBTY2hvb2xzCmBgYHtyIGVjaG89VFJVRX0KaGlnaF9wZXJmb3JtaW5nIDwtIGdhaW4gJT4lCiAgZmlsdGVyKFBlcmZvcm1hbmNlID09ICJIaWdoIikKIyMjIyBHZXR0aW5nIGxpbmVhciByZWdyZXNzaW9uIGZpdApoaWdoX21vZCA8LSBsbShub3JtX0JMMl9CRUw5IH4gbm9ybV9CTDEsIGRhdGEgPSBoaWdoX3BlcmZvcm1pbmcpCgpoaWdoX3BlcmZvcm1pbmcgJTw+JSAKICBhZGRfcHJlZGljdGlvbnMoaGlnaF9tb2QpICU+JQogIGFkZF9yZXNpZHVhbHMoaGlnaF9tb2QpCgpoaWdoX3BlcmZvcm1pbmcgJTw+JQogIG11dGF0ZShkZWx0YSA9IHJvdW5kKDEwMCpyZXNpZCAvIG5vcm1fQkwxKSApICU+JQogIG11dGF0ZShtb3ZlbWVudCA9IGlmX2Vsc2UoZGVsdGEgPiAyMCwgIlVQIiwgKGlmX2Vsc2UoZGVsdGEgPiAtMjAsICJTQU1FIiwgIkRPV04iKSkpKQoKIyMjIyBDb3VudCBvZiBVUCAvIERPV04gYW5kIFNBTUUgcGVyIHNjaG9vbCBmb3IgTG93IHBlcmZvcm1pbmcgc2Nob29scwpoaWdoX3BlcmZvcm1pbmcgJT4lCiAgZ3JvdXBfYnkoYENlbnRyZSBOYW1lYCwgbW92ZW1lbnQpICU+JQogIHN1bW1hcmlzZShjb3VudENvbW1vblN0dWRlbnRzID0gbigpICkgJT4lCiAgc3ByZWFkKG1vdmVtZW50LCBjb3VudENvbW1vblN0dWRlbnRzKSAlPiUKICByZXBsYWNlKC4sIGlzLm5hKC4pLCAwKSAlPiUKICBtdXRhdGUoTkVUX3BlcmNfVVAgPSByb3VuZCgxMDAqKFVQLURPV04pIC8gKFVQK0RPV04rU0FNRSkpKSAlPiUKICBhcnJhbmdlKE5FVF9wZXJjX1VQKQpgYGAK