Summary

This notebook compares ASER 2018 data, NAS 2017 data, and IHDS 2012 data. ASER and NAS differ in both sampling and the assessment tool used. I provide a brief recap of ASER and NAS and then discuss what data is used for this comparison. The ASER Centre has put together a comparison of the two surveys here

ASER

  1. Frequency
    1. Basic survey conducted every other year
  2. Sampling
    1. Only rural areas covered
    2. In each rural district, 30 villages are selected using PPS. In each village, 20 households are selected using the right-hand rule
    3. Survey is conducted at home rather than in school. Thus, results not affected by enrollment / attendance.
    4. All children 5-16 years old, regardless of school enrollment, are administered the assessment. (In addition, data on enrollment is collected for 3 and 4 year olds
  3. Data collected
    1. Assessment tests basic reading and math.
      1. Read levels are not even letters, letters, word, std 1 text, std 2 text
      2. Math levels are not even 1-9, 1-9 numbers, 10-99 numbers, substract, and divide
    2. Basic household details and school attendance (e.g. whether public or private) also collected
  4. Other
    1. ASER is carried out through local partners who rely on volunteers
    2. There are some internal and third party checks, but these seem to be pretty minimal
    3. The assessment is administered one-on-one by the enumerators who read out the questions to the child being assessed.
    4. ASER uses weights when calculating state and national figures

NAS

NCERT has been conducting NAS since 2001 but in previous years they only collected data for a single grade at a time. (For example, they collected data for class 5 in academic year 2001-02, for class 8 in academic year 2002-03, and for class 3 in academic year 2003-04. See here page 6 for more info.) In addition, the sample sizes in previous years were smaller (they were only intended to be representative at the state level) and the assessment tool used was different. More details of NAS 2017 can be found here. In particular, the following documents are partiularly useful:

  1. Frequency
    1. Previous versions of the NAS were carried out every year. There has only been one instance in which NAS has been carried out in its current form (in 2017)
  2. Sampling
    1. Schools are selected from UDISE using PPS (according to the ASER note on the NAS)
    2. Includes both government and government aided (See here)
    3. Grades 3, 5, and 8 covered
    4. If there is more than one section for grades 3, 5, or 8 then one section was randomly selected. (See bottom of page 7 of FAQ)
    5. If a section has more than 30 students, then roughly 30 students randomly selected. The method for randomly selecting students appears to be well thought and clearly documented in field investigator module.
  3. Data collected
    1. Test language, math, and environmental science
    2. Seems like they also collect basic data about the school
  4. Implementation
    1. NCERT is responsible for designing the survey tools and quality assurance. (See roles and functions of different stakeholders in FAQ)
    2. States are responsible for translating the test into regional languages
    3. The test is a paper and pencil test. Students fill out a paper questionnaire and then the field investigators tallies responses on an OMR sheet.
    4. Government school teachers cannot be field investigators. Ideally, DIET students should be field investigators but B.Ed or M.Ed students can only serve as FIs. (See FAQ and FI module)
    5. Field investigators visit schools on a prep day to meet the teachers and fill the school and teacher questionnaires. The assessment is done on a second day (which was November 17th for all districts across the country).
    6. The test is paper and pencil. Field investigators read questions aloud (but do not read the passage in the reading comprehension book).
    7. According to the field investigator module, the field investigatores “after administration of tests, fill up the PQ by interview mode for each student one by one”
    8. It seems like only class 8 students directly fill OMR sheets and that class 3 and 5 students instead mark in the test booklet. (page 14 and 15 of field investigator module)
  5. Other
    1. Estimates are not weighted (actual enrollment varied quite a bit from figures in USIDE so ideally should have used weights)

Comparing ASER and NAS

Andres copied NAS data from here. I copied the ASER data from table 5 in the 2018 ASER report. To make the data as comparable as possible…

  • ASER data is for class 3 students able to read a standard 2 text. Only government school students are included.
  • NAS data is only for rural areas for class 3 students. (The website above breaks down results for rural / urban). The NAS language assessment for class 3 tests competencies L312 and L304. L304 is “Reads small texts with comprehension i.e., identifies main ideas, details, sequence and draws conclusion”. L312 is “Reads printed scripts on the classroom walls: poems, posters, charts etc”. Unclear how the two data points are combined.

Note that even with these corrections, there are still a lot of ways in which ASER and NAS differ. The biggest difference is that ASER is representative of all children enrolled in govt schools while NAS is representative only of children who showed up on the day of the assessment. In addition, the assessment itself varies quite a bit. (And the ASER exam suggests that the pen and paper exam )

library(tidyverse)
library(haven)
library(survey)
path <- "C:/Users/dougj/Documents/Data/Education"
figures <- "C:/Users/dougj/Dropbox/Education in India/Original research/Learning outcomes data/figures"

library(ggrepel)

### Rank comparison
main_data <- read_csv(file.path(path, "ASER 2018 and NAS 2017 govt school grade 3 reading_corrected.csv"))
Parsed with column specification:
cols(
  State = col_character(),
  ASER_2012 = col_double(),
  ASER_2014 = col_double(),
  ASER_2016 = col_double(),
  ASER_2018 = col_double(),
  NAS = col_double(),
  aser_rank = col_double(),
  nas_rank = col_double()
)
ggplot(data = main_data,aes(x=aser_rank,y=nas_rank,label= State)) + geom_abline(intercept = 0, slope = 1, color="orange")  +
  geom_abline(intercept = -6, slope = 1, color="gray", lwd=1, lty=2) +
  geom_abline(intercept = 6, slope = 1, color="gray", lwd=1, lty=2) +
  geom_point(color="darkblue")  +
  theme_bw() + labs(title="State Rankings Based on Language Results for Std III Students (Rural)", 
                    x = "Rank in ASER (2018)", y = "Rank in NAS (2017)") + 
   scale_y_continuous(breaks=c(1:28)) + scale_x_continuous(breaks=c(1:28))  + theme(panel.grid.minor =   element_blank(),
   panel.grid.major =   element_line(colour = "gray",size=0.1)) + geom_label_repel() 

# ggsave("aser_nas_lang_ranking.png", width = 9, height = 6 , path = figures)
ggsave("aser_nas_lang_ranking.png", width = 9, height = 6)

ASER and NAS vs GDP

Given the huge variation in state GDP per capita, one would expect that there would be some correlation in GPD per capita and learning outcomes. Surprisingly, this is not the case.

setwd("C:/Users/dougj/Documents/Data/Education")
The working directory was changed to C:/Users/dougj/Documents/Data/Education inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
gdp <- read_csv("state GDP per capita.csv")
Parsed with column specification:
cols(
  State = col_character(),
  `NSDP per capita` = col_double(),
  `Data year` = col_character()
)
df <- main_data %>% left_join(gdp, by = "State")
print(paste("Number of unmatched states", sum(is.na(df$`NSDP per capita`))))
[1] "Number of unmatched states 0"
df$gdp_rank <- NA
df$gdp_rank[order(df$`NSDP per capita`, decreasing = TRUE)] <- 1:nrow(df)

temp <- df %>% select(ASER_2018, 'NSDP per capita', NAS)
cor(temp, method = "pearson", use = "pairwise.complete.obs")
                ASER_2018 NSDP per capita       NAS
ASER_2018       1.0000000       0.4154964 0.1872901
NSDP per capita 0.4154964       1.0000000 0.0515147
NAS             0.1872901       0.0515147 1.0000000
cor(temp, method = "spearman", use = "pairwise.complete.obs")
                ASER_2018 NSDP per capita       NAS
ASER_2018       1.0000000       0.3758205 0.1267176
NSDP per capita 0.3758205       1.0000000 0.1382236
NAS             0.1267176       0.1382236 1.0000000
# formal test for correlation
cor.test(temp$ASER_2018,temp$`NSDP per capita`, use = "pairwise.complete.obs", method = "pearson")

    Pearson's product-moment correlation

data:  temp$ASER_2018 and temp$`NSDP per capita`
t = 2.284, df = 25, p-value = 0.03113
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.04213542 0.68703188
sample estimates:
      cor 
0.4154964 
cor.test(temp$ASER_2018,temp$`NSDP per capita`, use = "pairwise.complete.obs", method = "spearman")
Cannot compute exact p-value with ties

    Spearman's rank correlation rho

data:  temp$ASER_2018 and temp$`NSDP per capita`
S = 2044.8, p-value = 0.05337
alternative hypothesis: true rho is not equal to 0
sample estimates:
      rho 
0.3758205 
cor.test(temp$NAS,temp$`NSDP per capita`, use = "pairwise.complete.obs", method = "pearson")

    Pearson's product-moment correlation

data:  temp$NAS and temp$`NSDP per capita`
t = 0.26302, df = 26, p-value = 0.7946
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.3278634  0.4165853
sample estimates:
      cor 
0.0515147 
cor.test(temp$NAS,temp$`NSDP per capita`, use = "pairwise.complete.obs", method = "spearman")
Cannot compute exact p-value with ties

    Spearman's rank correlation rho

data:  temp$NAS and temp$`NSDP per capita`
S = 3148.9, p-value = 0.483
alternative hypothesis: true rho is not equal to 0
sample estimates:
      rho 
0.1382236 
ggplot(data = df,aes(x= gdp_rank,y=nas_rank,label= State)) + geom_abline(intercept = 0, slope = 1, color="orange")  +
  geom_point(color="darkblue")  +
  theme_bw() + labs(title="NAS vs GDP", 
                    x = "GDP rank", y = "Rank in NAS (2017)") + 
   scale_y_continuous(breaks=c(1:28)) + scale_x_continuous(breaks=c(1:28))  + theme(panel.grid.minor =   element_blank(),
   panel.grid.major =   element_line(colour = "gray",size=0.1)) + geom_label_repel() 
ggplot(data = df,aes(x= gdp_rank,y=aser_rank,label= State)) + geom_abline(intercept = 0, slope = 1, color="orange")  +
  geom_point(color="darkblue")  +
  theme_bw() + labs(title="ASER vs GDP", 
                    x = "GDP rank", y = "Rank in ASER (2018)") + 
   scale_y_continuous(breaks=c(1:28)) + scale_x_continuous(breaks=c(1:28))  + theme(panel.grid.minor =   element_blank(),
   panel.grid.major =   element_line(colour = "gray",size=0.1)) + geom_label_repel() 

Compare ASER, NAS, and IHDS

While ASER and NAS use different assessments, based on their descriptions it seems like the reading components of each assessment seeks to measure about the same thing. Therefore, it is useful to compare the average scores (as opposed to ranks) of each assessment for each state.

Calculate IHDS scores by state.

Calculate percentage of students with ASER == 4 (i.e. can read std 2 level text) for rural (URBAN2011 == 0) govt school (CS4 ==2) or private aided (CS4 == 3) students in grades 2 to 5 (there are too few students if we restrict only to grade 3) by state. warning: this code takes a long time

ihds_ind_dir <- "C:/Users/dougj/Documents/Data/IHDS/IHDS 2012/DS0001"
ind_file <- file.path(ihds_ind_dir, "36151-0001-Data.dta")
# read in just those variables that i need
# this is much faster than reading in everything and then selecting
ihds <- read_dta(ind_file, col_select = c(STATEID, DISTID, PSUID, HHID, HHSPLITID, PERSONID, IDPSU, WT, RO3, RO7, RO5, URBAN2011, starts_with("CS"), starts_with("TA"), starts_with("ED")))
ihds <- ihds %>% mutate(psu_expanded = paste(STATEID, DISTID, PSUID, sep ="-"), hh_expanded = paste(STATEID, DISTID, PSUID, HHID, HHSPLITID, sep ="-"))

# confirm that TA4 (class) is not NA if TA8B is not NA --> there are only 38 instances when TA8B is not NA but TA4 is NA
ihds %>% filter(!is.na(TA8B)) %>% count(TA4)

# drop the one row with missing values for weights
ihds <- ihds %>% filter(!is.na(WT))

# create variable for ASER at level 4
ihds <- ihds %>% mutate(ASER4 = (TA8B ==4)) %>% mutate(State = as_factor(STATEID))

# use the survey package to set the survey design.  I will use the ihds_svy object to calculate CIs
ihds_svy <- svydesign(id =~ psu_expanded + hh_expanded, weights =~ WT, data = ihds)

# use statsby to get the % of selected kids who achieve level 4 on ASER reading by state
# note that I am not sure if subsetting within statsby is kosher, but the standard errors should be ok 
# more or less ok regardless
ihds_scores <- svyby(~ASER4, ~State, subset(ihds_svy, !is.na(TA8B) & (CS4 == 2 | CS4 == 3) & (TA4 >= 2 & TA4 <= 5) & (URBAN2011 == 0)), svymean, na.rm=TRUE)

# convert to a tibble
ihds_scores <- as.tibble(ihds_scores) %>% select(State, ASER4TRUE, se.ASER4TRUE) %>% rename(ihds = ASER4TRUE, ihds_se = se.ASER4TRUE)

# Unsure, but I think this gets rid of the space and number at the end of the state name
ihds_scores$State <- sub("...$", "", ihds_scores$State)

# replace the standard errors with NA is SE == 0
ihds_scores$ihds[ihds_scores$ihds_se == 0] <- NA

# replace Orissa with Odisha in state 
ihds_scores$State[ihds_scores$State == "Orissa"] <- "Odisha"
ihds_scores$ihds <- round(ihds_scores$ihds, 3)*100

Calculate correlations

aser_nas <- main_data %>% select(State, ASER_2018, NAS)
scores <- aser_nas %>% full_join(ihds_scores, by = "State")

# drop if IHDS_ASER is NA
# scores <- scores %>% filter(!is.na(IHDS_ASER)) %>% arrange(ASER) %>% select(State, ASER, IHDS_ASER, NAS, obs)

# calculate correlation matrix --> while there are a few outliers, overall the ASER data and IHDS data match Ok
# note that 
temp <- scores %>% select(ASER_2018, ihds, NAS)
cor(temp, method = "pearson", use = "pairwise.complete.obs")
          ASER_2018        ihds         NAS
ASER_2018 1.0000000 0.617984954 0.187290066
ihds      0.6179850 1.000000000 0.003204316
NAS       0.1872901 0.003204316 1.000000000
cor(temp, method = "spearman", use = "pairwise.complete.obs")
          ASER_2018        ihds         NAS
ASER_2018 1.0000000  0.60152502  0.12671756
ihds      0.6015250  1.00000000 -0.03106467
NAS       0.1267176 -0.03106467  1.00000000
# conduct formal correlation test
cor.test(temp$NAS,temp$ihds, use = "pairwise.complete.obs", method = "pearson")

    Pearson's product-moment correlation

data:  temp$NAS and temp$ihds
t = 0.01433, df = 20, p-value = 0.9887
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.4189701  0.4242396
sample estimates:
        cor 
0.003204316 
cor.test(temp$ASER_2018,temp$ihds, use = "pairwise.complete.obs", method = "pearson")

    Pearson's product-moment correlation

data:  temp$ASER_2018 and temp$ihds
t = 3.5153, df = 20, p-value = 0.002176
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.2655702 0.8247157
sample estimates:
     cor 
0.617985 
cor.test(temp$NAS,temp$ASER_2018, use = "pairwise.complete.obs", method = "pearson")

    Pearson's product-moment correlation

data:  temp$NAS and temp$ASER_2018
t = 0.95332, df = 25, p-value = 0.3496
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.2074917  0.5296102
sample estimates:
      cor 
0.1872901 
cor.test(temp$NAS,temp$ihds, use = "pairwise.complete.obs", method = "spearman")
Cannot compute exact p-value with ties

    Spearman's rank correlation rho

data:  temp$NAS and temp$ihds
S = 1826, p-value = 0.8908
alternative hypothesis: true rho is not equal to 0
sample estimates:
        rho 
-0.03106467 
cor.test(temp$ASER_2018,temp$ihds, use = "pairwise.complete.obs", method = "spearman")
Cannot compute exact p-value with ties

    Spearman's rank correlation rho

data:  temp$ASER_2018 and temp$ihds
S = 705.7, p-value = 0.003063
alternative hypothesis: true rho is not equal to 0
sample estimates:
     rho 
0.601525 
cor.test(temp$NAS,temp$ASER_2018, use = "pairwise.complete.obs", method = "spearman")
Cannot compute exact p-value with ties

    Spearman's rank correlation rho

data:  temp$NAS and temp$ASER_2018
S = 2860.9, p-value = 0.5288
alternative hypothesis: true rho is not equal to 0
sample estimates:
      rho 
0.1267176 

Create graph showing IHDS, ASER, and NAS all on same scale.


scores.long <- scores %>% select(State, ASER_2018, NAS, ihds) %>%
  rename(IHDS = ihds) %>%
  filter(!is.na(ASER_2018) & !is.na(NAS)) %>%
  gather(Assessment, avg_score, -State) 

ggplot(data = scores.long, aes(x= reorder(State, avg_score),y=avg_score, fill= Assessment)) + 
  geom_bar(stat = "identity", position = position_dodge(width=.8)) + 
  theme(axis.text.x = element_text(angle=90)) + 
  scale_fill_manual(values = c("lightblue", "blue", "darkblue"))+
  labs(y = "Average score", x = "")

Attempt to create the same bar but with standard errors for IHDS.

# treat the SE as just another score
scores.long2 <- scores  %>%
  filter(!is.na(ASER_2018) & !is.na(NAS)) %>% 
  mutate(IHDS = paste(ihds,ihds_se, sep ="-")) %>% 
  select(State, ASER_2018, NAS, IHDS) %>% 
  gather(Assessment, avg_score, -State) %>%
  separate(avg_score, sep = "-", into = c("avg_score","se"))
Expected 2 pieces. Missing pieces filled with `NA` in 54 rows [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...].
# convert avg_score and se back to numeric 
scores.long2 <- scores.long2  %>%
  mutate(avg_score = as.numeric(avg_score), se = as.numeric(se))
NAs introduced by coercionNAs introduced by coercion
# multiply se 
scores.long2 <- scores.long2  %>%
  mutate(se = 100*se)


# create y_min and y_max
m <- qnorm(1-.05/2)
scores.long2 <- scores.long2  %>%
  mutate(ymin = avg_score-m*se, ymax = avg_score+m*se) %>%
  mutate(ymin = ifelse(ymin <0, 0, ymin))


ggplot(data = scores.long2, aes(x= reorder(State, avg_score),y=avg_score, fill= Assessment)) + 
  geom_bar(stat = "identity", position = position_dodge(width=.8)) + 
  geom_errorbar(aes(ymin = ymin, ymax = ymax), width = .1) + 
  theme(axis.text.x = element_text(angle=90)) + 
  scale_fill_manual(values = c("lightblue", "blue", "darkblue"))+
  labs(y = "Average score", x = "")
ggsave("aser_nas_ihds_values.png", width = 9, height = 6 , path = figures)

Show line graphs of ASER class 3 reading scores for govt school students over time.

# reshape the main data
scores.long3 <- main_data %>% 
  select(State, starts_with("ASER")) %>% 
  select(-aser_rank) %>%
  gather(key ="Temp", value= "Reading", -State) %>%
  separate(Temp, sep = "_", into = c("dummy","Year"))

ggplot(data = scores.long3, aes(x=Year, y=Reading, color=State)) +
  geom_line(aes(group=State))

ggsave("aser_over_time.png", path = figures)
Saving 7.29 x 4.5 in image

LS0tDQp0aXRsZTogIkNvbXBhcmUgQVNFUiwgTkFTLCBhbmQgSUhEUyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCiMgU3VtbWFyeQ0KVGhpcyBub3RlYm9vayBjb21wYXJlcyBBU0VSIDIwMTggZGF0YSwgTkFTIDIwMTcgZGF0YSwgYW5kIElIRFMgMjAxMiBkYXRhLiAgQVNFUiBhbmQgTkFTIGRpZmZlciBpbiBib3RoIHNhbXBsaW5nIGFuZCB0aGUgYXNzZXNzbWVudCB0b29sIHVzZWQuIEkgcHJvdmlkZSBhIGJyaWVmIHJlY2FwIG9mIEFTRVIgYW5kIE5BUyBhbmQgdGhlbiBkaXNjdXNzIHdoYXQgZGF0YSBpcyB1c2VkIGZvciB0aGlzIGNvbXBhcmlzb24uIFRoZSBBU0VSIENlbnRyZSBoYXMgcHV0IHRvZ2V0aGVyIGEgY29tcGFyaXNvbiBvZiB0aGUgdHdvIHN1cnZleXMgW2hlcmVdKGh0dHBzOi8vaW1nLmFzZXJjZW50cmUub3JnL2RvY3MvQm90dG9tJTIwUGFuZWwvS2V5JTIwRG9jcy9uYXNfc3RkdnZzX2FzZXIucGRmKQ0KDQojIyBBU0VSDQoxLiBGcmVxdWVuY3kNCiAgICAxLiBCYXNpYyBzdXJ2ZXkgY29uZHVjdGVkIGV2ZXJ5IG90aGVyIHllYXINCjIuIFNhbXBsaW5nDQogICAgMS4gT25seSBydXJhbCBhcmVhcyBjb3ZlcmVkDQogICAgMi4gSW4gZWFjaCBydXJhbCBkaXN0cmljdCwgMzAgdmlsbGFnZXMgYXJlIHNlbGVjdGVkIHVzaW5nIFBQUy4gIEluIGVhY2ggdmlsbGFnZSwgMjAgaG91c2Vob2xkcyBhcmUgc2VsZWN0ZWQgdXNpbmcgdGhlIHJpZ2h0LWhhbmQgcnVsZQ0KICAgIDMuIFN1cnZleSBpcyBjb25kdWN0ZWQgYXQgaG9tZSByYXRoZXIgdGhhbiBpbiBzY2hvb2wuIFRodXMsIHJlc3VsdHMgbm90IGFmZmVjdGVkIGJ5IGVucm9sbG1lbnQgLyBhdHRlbmRhbmNlLg0KICAgIDQuIEFsbCBjaGlsZHJlbiA1LTE2IHllYXJzIG9sZCwgcmVnYXJkbGVzcyBvZiBzY2hvb2wgZW5yb2xsbWVudCwgYXJlIGFkbWluaXN0ZXJlZCB0aGUgYXNzZXNzbWVudC4gKEluIGFkZGl0aW9uLCBkYXRhIG9uIGVucm9sbG1lbnQgaXMgY29sbGVjdGVkIGZvciAzIGFuZCA0IHllYXIgb2xkcw0KMy4gRGF0YSBjb2xsZWN0ZWQNCiAgICAxLiBBc3Nlc3NtZW50IHRlc3RzIGJhc2ljIHJlYWRpbmcgYW5kIG1hdGguICANCiAgICAgICAgYS4gUmVhZCBsZXZlbHMgYXJlIG5vdCBldmVuIGxldHRlcnMsIGxldHRlcnMsIHdvcmQsIHN0ZCAxIHRleHQsIHN0ZCAyIHRleHQNCiAgICAgICAgYi4gTWF0aCBsZXZlbHMgYXJlIG5vdCBldmVuIDEtOSwgMS05IG51bWJlcnMsIDEwLTk5IG51bWJlcnMsIHN1YnN0cmFjdCwgYW5kIGRpdmlkZQ0KICAgIDIuIEJhc2ljIGhvdXNlaG9sZCBkZXRhaWxzIGFuZCBzY2hvb2wgYXR0ZW5kYW5jZSAoZS5nLiB3aGV0aGVyIHB1YmxpYyBvciBwcml2YXRlKSBhbHNvIGNvbGxlY3RlZA0KNC4gT3RoZXINCiAgICAxLiBBU0VSIGlzIGNhcnJpZWQgb3V0IHRocm91Z2ggbG9jYWwgcGFydG5lcnMgd2hvIHJlbHkgb24gdm9sdW50ZWVycw0KICAgIDIuIFRoZXJlIGFyZSBzb21lIGludGVybmFsIGFuZCB0aGlyZCBwYXJ0eSBjaGVja3MsIGJ1dCB0aGVzZSBzZWVtIHRvIGJlIHByZXR0eSBtaW5pbWFsDQogICAgMy4gVGhlIGFzc2Vzc21lbnQgaXMgYWRtaW5pc3RlcmVkIG9uZS1vbi1vbmUgYnkgdGhlIGVudW1lcmF0b3JzIHdobyByZWFkIG91dCB0aGUgcXVlc3Rpb25zIHRvIHRoZSBjaGlsZCBiZWluZyBhc3Nlc3NlZC4NCiAgICA0LiBBU0VSIHVzZXMgd2VpZ2h0cyB3aGVuIGNhbGN1bGF0aW5nIHN0YXRlIGFuZCBuYXRpb25hbCBmaWd1cmVzDQoNCg0KIyMgTkFTDQpOQ0VSVCBoYXMgYmVlbiBjb25kdWN0aW5nIE5BUyBzaW5jZSAyMDAxIGJ1dCBpbiBwcmV2aW91cyB5ZWFycyB0aGV5IG9ubHkgY29sbGVjdGVkIGRhdGEgZm9yIGEgc2luZ2xlIGdyYWRlIGF0IGEgdGltZS4gKEZvciBleGFtcGxlLCB0aGV5IGNvbGxlY3RlZCBkYXRhIGZvciBjbGFzcyA1IGluIGFjYWRlbWljIHllYXIgMjAwMS0wMiwgZm9yIGNsYXNzIDggaW4gYWNhZGVtaWMgeWVhciAyMDAyLTAzLCBhbmQgZm9yIGNsYXNzIDMgaW4gYWNhZGVtaWMgeWVhciAyMDAzLTA0LiAgU2VlIFtoZXJlXShodHRwOi8vd3d3Lm5jZXJ0Lm5pYy5pbi9wcm9ncmFtbWVzL05BUy9wZGYvRFJDX3JlcG9ydC5wZGYpIHBhZ2UgNiBmb3IgbW9yZSBpbmZvLikgSW4gYWRkaXRpb24sIHRoZSBzYW1wbGUgc2l6ZXMgaW4gcHJldmlvdXMgeWVhcnMgd2VyZSBzbWFsbGVyICh0aGV5IHdlcmUgb25seSBpbnRlbmRlZCB0byBiZSByZXByZXNlbnRhdGl2ZSBhdCB0aGUgc3RhdGUgbGV2ZWwpIGFuZCB0aGUgYXNzZXNzbWVudCB0b29sIHVzZWQgd2FzIGRpZmZlcmVudC4gTW9yZSBkZXRhaWxzIG9mIE5BUyAyMDE3IGNhbiBiZSBmb3VuZCBbaGVyZV0oaHR0cDovL3d3dy5uY2VydC5uaWMuaW4vcHJvZ3JhbW1lcy9OQVMvVHJhaW5pbmcuaHRtbCkuIEluIHBhcnRpY3VsYXIsIHRoZSBmb2xsb3dpbmcgZG9jdW1lbnRzIGFyZSBwYXJ0aXVsYXJseSB1c2VmdWw6DQoNCiogW0ZBUV0oaHR0cDovL3d3dy5uY2VydC5uaWMuaW4vcHJvZ3JhbW1lcy9OQVMvcGRmL05BU19GcmVxdWVudGx5QXNrZWRfUXVlc3Rpb25zLnBkZikNCiogW0ZpZWxkIGludmVzdGlnYXRvciBtb2R1bGUgZm9yIHRlc3QgYWRtaW5pc3RyYXRpb25dKGh0dHA6Ly93d3cubmNlcnQubmljLmluL3Byb2dyYW1tZXMvTkFTL3BkZi9Nb2R1bGVfQWRtaW5pc3RyYXRpb25fRmllbGRfSW52ZXN0aWdhdG9ycy5wZGYpIA0KKiBbRGlzdHJpY3QgdHJhaW5pbmcgbW9kdWxlXShodHRwOi8vd3d3Lm5jZXJ0Lm5pYy5pbi9wcm9ncmFtbWVzL05BUy9wZGYvTkFTX0Rpc3RyaWN0X1dvcmtzaG9wX01vZHVsZS5wZGYpDQoqIFtPcGVyYXRpb25hbCBndWlkZWxpbmVzIGN1bSB0cmFpbmluZyBtYW51YWxdKGh0dHA6Ly93d3cubmNlcnQubmljLmluL3Byb2dyYW1tZXMvTkFTL3BkZi9PcGVyYXRpb25hbF9HdWlkZWxpbmVzX1RyYWluaW5nX01hbnVhbC5wZGYpDQoNCg0KMS4gRnJlcXVlbmN5DQogICAgMS4gUHJldmlvdXMgdmVyc2lvbnMgb2YgdGhlIE5BUyB3ZXJlIGNhcnJpZWQgb3V0IGV2ZXJ5IHllYXIuICBUaGVyZSBoYXMgb25seSBiZWVuIG9uZSBpbnN0YW5jZSBpbiB3aGljaCBOQVMgaGFzIGJlZW4gY2FycmllZCBvdXQgaW4gaXRzIGN1cnJlbnQgZm9ybSAoaW4gMjAxNykNCjIuIFNhbXBsaW5nDQogICAgMS4gU2Nob29scyBhcmUgc2VsZWN0ZWQgZnJvbSBVRElTRSB1c2luZyBQUFMgKGFjY29yZGluZyB0byB0aGUgQVNFUiBub3RlIG9uIHRoZSBOQVMpDQogICAgMi4gSW5jbHVkZXMgYm90aCBnb3Zlcm5tZW50IGFuZCBnb3Zlcm5tZW50IGFpZGVkIChTZWUgW2hlcmVdKGh0dHA6Ly93d3cubmNlcnQubmljLmluL3Byb2dyYW1tZXMvTkFTL0RSQy5odG1sKSkNCiAgICAyLiBHcmFkZXMgMywgNSwgYW5kIDggY292ZXJlZA0KICAgIDMuIElmIHRoZXJlIGlzIG1vcmUgdGhhbiBvbmUgc2VjdGlvbiBmb3IgZ3JhZGVzIDMsIDUsIG9yIDggdGhlbiBvbmUgc2VjdGlvbiB3YXMgcmFuZG9tbHkgc2VsZWN0ZWQuIChTZWUgYm90dG9tIG9mIHBhZ2UgNyBvZiBGQVEpDQogICAgNC4gSWYgYSBzZWN0aW9uIGhhcyBtb3JlIHRoYW4gMzAgc3R1ZGVudHMsIHRoZW4gcm91Z2hseSAzMCBzdHVkZW50cyByYW5kb21seSBzZWxlY3RlZC4gVGhlIG1ldGhvZCBmb3IgcmFuZG9tbHkgc2VsZWN0aW5nIHN0dWRlbnRzIGFwcGVhcnMgdG8gYmUgd2VsbCB0aG91Z2h0IGFuZCBjbGVhcmx5IGRvY3VtZW50ZWQgaW4gZmllbGQgaW52ZXN0aWdhdG9yIG1vZHVsZS4NCjMuIERhdGEgY29sbGVjdGVkDQogICAgMS4gVGVzdCBsYW5ndWFnZSwgbWF0aCwgYW5kIGVudmlyb25tZW50YWwgc2NpZW5jZQ0KICAgIDIuIFNlZW1zIGxpa2UgdGhleSBhbHNvIGNvbGxlY3QgYmFzaWMgZGF0YSBhYm91dCB0aGUgc2Nob29sDQo0LiBJbXBsZW1lbnRhdGlvbg0KICAgIDEuIE5DRVJUIGlzIHJlc3BvbnNpYmxlIGZvciBkZXNpZ25pbmcgdGhlIHN1cnZleSB0b29scyBhbmQgcXVhbGl0eSBhc3N1cmFuY2UuIChTZWUgcm9sZXMgYW5kIGZ1bmN0aW9ucyBvZiBkaWZmZXJlbnQgc3Rha2Vob2xkZXJzIGluIEZBUSkgDQogICAgMi4gU3RhdGVzIGFyZSByZXNwb25zaWJsZSBmb3IgdHJhbnNsYXRpbmcgdGhlIHRlc3QgaW50byByZWdpb25hbCBsYW5ndWFnZXMNCiAgICAzLiBUaGUgdGVzdCBpcyBhIHBhcGVyIGFuZCBwZW5jaWwgdGVzdC4gU3R1ZGVudHMgZmlsbCBvdXQgYSBwYXBlciBxdWVzdGlvbm5haXJlIGFuZCB0aGVuIHRoZSBmaWVsZCBpbnZlc3RpZ2F0b3JzIHRhbGxpZXMgcmVzcG9uc2VzIG9uIGFuIE9NUiBzaGVldC4gIA0KICAgIDQuIEdvdmVybm1lbnQgc2Nob29sIHRlYWNoZXJzIGNhbm5vdCBiZSBmaWVsZCBpbnZlc3RpZ2F0b3JzLiBJZGVhbGx5LCBESUVUIHN0dWRlbnRzIHNob3VsZCBiZSBmaWVsZCBpbnZlc3RpZ2F0b3JzIGJ1dCBCLkVkIG9yIE0uRWQgc3R1ZGVudHMgY2FuIG9ubHkgc2VydmUgYXMgRklzLiAoU2VlIEZBUSBhbmQgRkkgbW9kdWxlKQ0KICAgIDUuIEZpZWxkIGludmVzdGlnYXRvcnMgdmlzaXQgc2Nob29scyBvbiBhIHByZXAgZGF5IHRvIG1lZXQgdGhlIHRlYWNoZXJzIGFuZCBmaWxsIHRoZSBzY2hvb2wgYW5kIHRlYWNoZXIgcXVlc3Rpb25uYWlyZXMuIFRoZSBhc3Nlc3NtZW50IGlzIGRvbmUgb24gYSBzZWNvbmQgZGF5ICh3aGljaCB3YXMgTm92ZW1iZXIgMTd0aCBmb3IgYWxsIGRpc3RyaWN0cyBhY3Jvc3MgdGhlIGNvdW50cnkpLg0KICAgIDYuIFRoZSB0ZXN0IGlzIHBhcGVyIGFuZCBwZW5jaWwuIEZpZWxkIGludmVzdGlnYXRvcnMgcmVhZCBxdWVzdGlvbnMgYWxvdWQgKGJ1dCBkbyBub3QgcmVhZCB0aGUgcGFzc2FnZSBpbiB0aGUgcmVhZGluZyBjb21wcmVoZW5zaW9uIGJvb2spLiANCiAgICA3LiBBY2NvcmRpbmcgdG8gdGhlIGZpZWxkIGludmVzdGlnYXRvciBtb2R1bGUsIHRoZSBmaWVsZCBpbnZlc3RpZ2F0b3JlcyAiYWZ0ZXIgYWRtaW5pc3RyYXRpb24gb2YgdGVzdHMsIGZpbGwgdXAgdGhlIFBRIGJ5DQppbnRlcnZpZXcgbW9kZSBmb3IgZWFjaCBzdHVkZW50IG9uZSBieSBvbmUiDQogICAgOC4gSXQgc2VlbXMgbGlrZSBvbmx5IGNsYXNzIDggc3R1ZGVudHMgZGlyZWN0bHkgZmlsbCBPTVIgc2hlZXRzIGFuZCB0aGF0IGNsYXNzIDMgYW5kIDUgc3R1ZGVudHMgaW5zdGVhZCBtYXJrIGluIHRoZSB0ZXN0IGJvb2tsZXQuIChwYWdlIDE0IGFuZCAxNSBvZiBmaWVsZCBpbnZlc3RpZ2F0b3IgbW9kdWxlKQ0KNC4gT3RoZXINCiAgICAxLiBFc3RpbWF0ZXMgYXJlIG5vdCB3ZWlnaHRlZCAoYWN0dWFsIGVucm9sbG1lbnQgdmFyaWVkIHF1aXRlIGEgYml0IGZyb20gZmlndXJlcyBpbiBVU0lERSBzbyBpZGVhbGx5IHNob3VsZCBoYXZlIHVzZWQgd2VpZ2h0cykNCiAgICANCiMjIENvbXBhcmluZyBBU0VSIGFuZCBOQVMNCkFuZHJlcyBjb3BpZWQgTkFTIGRhdGEgZnJvbSBbaGVyZV0oaHR0cDovL25hcy5zY2hvb2xlZHVpbmZvLmluL2Rhc2hib2FyZC9uYXNfbmNlcnQjLykuICBJIGNvcGllZCB0aGUgQVNFUiBkYXRhIGZyb20gdGFibGUgNSBpbiB0aGUgMjAxOCBBU0VSIHJlcG9ydC4gVG8gbWFrZSB0aGUgZGF0YSBhcyBjb21wYXJhYmxlIGFzIHBvc3NpYmxlLi4uDQoNCiogQVNFUiBkYXRhIGlzIGZvciBjbGFzcyAzIHN0dWRlbnRzIGFibGUgdG8gcmVhZCBhIHN0YW5kYXJkIDIgdGV4dC4gT25seSBnb3Zlcm5tZW50IHNjaG9vbCBzdHVkZW50cyBhcmUgaW5jbHVkZWQuDQoqIE5BUyBkYXRhIGlzIG9ubHkgZm9yIHJ1cmFsIGFyZWFzIGZvciBjbGFzcyAzIHN0dWRlbnRzLiAoVGhlIHdlYnNpdGUgYWJvdmUgYnJlYWtzIGRvd24gcmVzdWx0cyBmb3IgcnVyYWwgLyB1cmJhbikuIFRoZSBOQVMgbGFuZ3VhZ2UgYXNzZXNzbWVudCBmb3IgY2xhc3MgMyB0ZXN0cyBjb21wZXRlbmNpZXMgTDMxMiBhbmQgTDMwNC4gTDMwNCBpcyAiUmVhZHMgc21hbGwgdGV4dHMgd2l0aCBjb21wcmVoZW5zaW9uIGkuZS4sIGlkZW50aWZpZXMgbWFpbiBpZGVhcywgZGV0YWlscywgc2VxdWVuY2UgYW5kIGRyYXdzIGNvbmNsdXNpb24iLiBMMzEyIGlzICJSZWFkcyBwcmludGVkIHNjcmlwdHMgb24gdGhlIGNsYXNzcm9vbSB3YWxsczogcG9lbXMsIHBvc3RlcnMsIGNoYXJ0cyBldGMiLiBVbmNsZWFyIGhvdyB0aGUgdHdvIGRhdGEgcG9pbnRzIGFyZSBjb21iaW5lZC4NCg0KTm90ZSB0aGF0IGV2ZW4gd2l0aCB0aGVzZSBjb3JyZWN0aW9ucywgdGhlcmUgYXJlIHN0aWxsIGEgbG90IG9mIHdheXMgaW4gd2hpY2ggQVNFUiBhbmQgTkFTIGRpZmZlci4gVGhlIGJpZ2dlc3QgZGlmZmVyZW5jZSBpcyB0aGF0IEFTRVIgaXMgcmVwcmVzZW50YXRpdmUgb2YgYWxsIGNoaWxkcmVuIGVucm9sbGVkIGluIGdvdnQgc2Nob29scyB3aGlsZSBOQVMgaXMgcmVwcmVzZW50YXRpdmUgb25seSBvZiBjaGlsZHJlbiB3aG8gc2hvd2VkIHVwIG9uIHRoZSBkYXkgb2YgdGhlIGFzc2Vzc21lbnQuICBJbiBhZGRpdGlvbiwgdGhlIGFzc2Vzc21lbnQgaXRzZWxmIHZhcmllcyBxdWl0ZSBhIGJpdC4gKEFuZCB0aGUgQVNFUiBleGFtIHN1Z2dlc3RzIHRoYXQgdGhlIHBlbiBhbmQgcGFwZXIgZXhhbSApDQoNCmBgYHtyIHNldHVwfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGhhdmVuKQ0KbGlicmFyeShzdXJ2ZXkpDQpwYXRoIDwtICJDOi9Vc2Vycy9kb3Vnai9Eb2N1bWVudHMvRGF0YS9FZHVjYXRpb24iDQpmaWd1cmVzIDwtICJDOi9Vc2Vycy9kb3Vnai9Ecm9wYm94L0VkdWNhdGlvbiBpbiBJbmRpYS9PcmlnaW5hbCByZXNlYXJjaC9MZWFybmluZyBvdXRjb21lcyBkYXRhL2ZpZ3VyZXMiDQpgYGANCg0KDQoNCmBgYHtyfQ0KDQpsaWJyYXJ5KGdncmVwZWwpDQoNCiMjIyBSYW5rIGNvbXBhcmlzb24NCm1haW5fZGF0YSA8LSByZWFkX2NzdihmaWxlLnBhdGgocGF0aCwgIkFTRVIgMjAxOCBhbmQgTkFTIDIwMTcgZ292dCBzY2hvb2wgZ3JhZGUgMyByZWFkaW5nX2NvcnJlY3RlZC5jc3YiKSkNCmdncGxvdChkYXRhID0gbWFpbl9kYXRhLGFlcyh4PWFzZXJfcmFuayx5PW5hc19yYW5rLGxhYmVsPSBTdGF0ZSkpICsgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMCwgc2xvcGUgPSAxLCBjb2xvcj0ib3JhbmdlIikgICsNCiAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gLTYsIHNsb3BlID0gMSwgY29sb3I9ImdyYXkiLCBsd2Q9MSwgbHR5PTIpICsNCiAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gNiwgc2xvcGUgPSAxLCBjb2xvcj0iZ3JheSIsIGx3ZD0xLCBsdHk9MikgKw0KICBnZW9tX3BvaW50KGNvbG9yPSJkYXJrYmx1ZSIpICArDQogIHRoZW1lX2J3KCkgKyBsYWJzKHRpdGxlPSJTdGF0ZSBSYW5raW5ncyBCYXNlZCBvbiBMYW5ndWFnZSBSZXN1bHRzIGZvciBTdGQgSUlJIFN0dWRlbnRzIChSdXJhbCkiLCANCiAgICAgICAgICAgICAgICAgICAgeCA9ICJSYW5rIGluIEFTRVIgKDIwMTgpIiwgeSA9ICJSYW5rIGluIE5BUyAoMjAxNykiKSArIA0KICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1jKDE6MjgpKSArIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygxOjI4KSkgICsgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9ICAgZWxlbWVudF9ibGFuaygpLA0KICAgcGFuZWwuZ3JpZC5tYWpvciA9ICAgZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmF5IixzaXplPTAuMSkpICsgZ2VvbV9sYWJlbF9yZXBlbCgpIA0KDQojIGdnc2F2ZSgiYXNlcl9uYXNfbGFuZ19yYW5raW5nLnBuZyIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gNiAsIHBhdGggPSBmaWd1cmVzKQ0KZ2dzYXZlKCJhc2VyX25hc19sYW5nX3JhbmtpbmcucG5nIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA2KQ0KDQpgYGANCg0KIyMgQVNFUiBhbmQgTkFTIHZzIEdEUA0KR2l2ZW4gdGhlIGh1Z2UgdmFyaWF0aW9uIGluIHN0YXRlIEdEUCBwZXIgY2FwaXRhLCBvbmUgd291bGQgZXhwZWN0IHRoYXQgdGhlcmUgd291bGQgYmUgc29tZSBjb3JyZWxhdGlvbiBpbiBHUEQgcGVyIGNhcGl0YSBhbmQgbGVhcm5pbmcgb3V0Y29tZXMuIFN1cnByaXNpbmdseSwgdGhpcyBpcyBub3QgdGhlIGNhc2UuDQoNCmBgYHtyfQ0Kc2V0d2QoIkM6L1VzZXJzL2RvdWdqL0RvY3VtZW50cy9EYXRhL0VkdWNhdGlvbiIpDQpnZHAgPC0gcmVhZF9jc3YoInN0YXRlIEdEUCBwZXIgY2FwaXRhLmNzdiIpDQpkZiA8LSBtYWluX2RhdGEgJT4lIGxlZnRfam9pbihnZHAsIGJ5ID0gIlN0YXRlIikNCnByaW50KHBhc3RlKCJOdW1iZXIgb2YgdW5tYXRjaGVkIHN0YXRlcyIsIHN1bShpcy5uYShkZiRgTlNEUCBwZXIgY2FwaXRhYCkpKSkNCmRmJGdkcF9yYW5rIDwtIE5BDQpkZiRnZHBfcmFua1tvcmRlcihkZiRgTlNEUCBwZXIgY2FwaXRhYCwgZGVjcmVhc2luZyA9IFRSVUUpXSA8LSAxOm5yb3coZGYpDQoNCnRlbXAgPC0gZGYgJT4lIHNlbGVjdChBU0VSXzIwMTgsICdOU0RQIHBlciBjYXBpdGEnLCBOQVMpDQpjb3IodGVtcCwgbWV0aG9kID0gInBlYXJzb24iLCB1c2UgPSAicGFpcndpc2UuY29tcGxldGUub2JzIikNCmNvcih0ZW1wLCBtZXRob2QgPSAic3BlYXJtYW4iLCB1c2UgPSAicGFpcndpc2UuY29tcGxldGUub2JzIikNCg0KIyBmb3JtYWwgdGVzdCBmb3IgY29ycmVsYXRpb24NCmNvci50ZXN0KHRlbXAkQVNFUl8yMDE4LHRlbXAkYE5TRFAgcGVyIGNhcGl0YWAsIHVzZSA9ICJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiLCBtZXRob2QgPSAicGVhcnNvbiIpDQpjb3IudGVzdCh0ZW1wJEFTRVJfMjAxOCx0ZW1wJGBOU0RQIHBlciBjYXBpdGFgLCB1c2UgPSAicGFpcndpc2UuY29tcGxldGUub2JzIiwgbWV0aG9kID0gInNwZWFybWFuIikNCmNvci50ZXN0KHRlbXAkTkFTLHRlbXAkYE5TRFAgcGVyIGNhcGl0YWAsIHVzZSA9ICJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiLCBtZXRob2QgPSAicGVhcnNvbiIpDQpjb3IudGVzdCh0ZW1wJE5BUyx0ZW1wJGBOU0RQIHBlciBjYXBpdGFgLCB1c2UgPSAicGFpcndpc2UuY29tcGxldGUub2JzIiwgbWV0aG9kID0gInNwZWFybWFuIikNCg0KZ2dwbG90KGRhdGEgPSBkZixhZXMoeD0gZ2RwX3JhbmsseT1uYXNfcmFuayxsYWJlbD0gU3RhdGUpKSArIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDAsIHNsb3BlID0gMSwgY29sb3I9Im9yYW5nZSIpICArDQogIGdlb21fcG9pbnQoY29sb3I9ImRhcmtibHVlIikgICsNCiAgdGhlbWVfYncoKSArIGxhYnModGl0bGU9Ik5BUyB2cyBHRFAiLCANCiAgICAgICAgICAgICAgICAgICAgeCA9ICJHRFAgcmFuayIsIHkgPSAiUmFuayBpbiBOQVMgKDIwMTcpIikgKyANCiAgIHNjYWxlX3lfY29udGludW91cyhicmVha3M9YygxOjI4KSkgKyBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoMToyOCkpICArIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSAgIGVsZW1lbnRfYmxhbmsoKSwNCiAgIHBhbmVsLmdyaWQubWFqb3IgPSAgIGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JheSIsc2l6ZT0wLjEpKSArIGdlb21fbGFiZWxfcmVwZWwoKSANCg0KDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IGRmLGFlcyh4PSBnZHBfcmFuayx5PWFzZXJfcmFuayxsYWJlbD0gU3RhdGUpKSArIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDAsIHNsb3BlID0gMSwgY29sb3I9Im9yYW5nZSIpICArDQogIGdlb21fcG9pbnQoY29sb3I9ImRhcmtibHVlIikgICsNCiAgdGhlbWVfYncoKSArIGxhYnModGl0bGU9IkFTRVIgdnMgR0RQIiwgDQogICAgICAgICAgICAgICAgICAgIHggPSAiR0RQIHJhbmsiLCB5ID0gIlJhbmsgaW4gQVNFUiAoMjAxOCkiKSArIA0KICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1jKDE6MjgpKSArIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygxOjI4KSkgICsgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9ICAgZWxlbWVudF9ibGFuaygpLA0KICAgcGFuZWwuZ3JpZC5tYWpvciA9ICAgZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmF5IixzaXplPTAuMSkpICsgZ2VvbV9sYWJlbF9yZXBlbCgpIA0KDQpgYGANCg0KIyMgQ29tcGFyZSBBU0VSLCBOQVMsIGFuZCBJSERTDQpXaGlsZSBBU0VSIGFuZCBOQVMgdXNlIGRpZmZlcmVudCBhc3Nlc3NtZW50cywgYmFzZWQgb24gdGhlaXIgZGVzY3JpcHRpb25zIGl0IHNlZW1zIGxpa2UgdGhlIHJlYWRpbmcgY29tcG9uZW50cyBvZiBlYWNoIGFzc2Vzc21lbnQgc2Vla3MgdG8gbWVhc3VyZSBhYm91dCB0aGUgc2FtZSB0aGluZy4gVGhlcmVmb3JlLCBpdCBpcyB1c2VmdWwgdG8gY29tcGFyZSB0aGUgYXZlcmFnZSBzY29yZXMgKGFzIG9wcG9zZWQgdG8gcmFua3MpIG9mIGVhY2ggYXNzZXNzbWVudCBmb3IgZWFjaCBzdGF0ZS4NCg0KIyMjIENhbGN1bGF0ZSBJSERTIHNjb3JlcyBieSBzdGF0ZS4gDQpDYWxjdWxhdGUgcGVyY2VudGFnZSBvZiBzdHVkZW50cyB3aXRoIEFTRVIgPT0gNCAoaS5lLiBjYW4gcmVhZCBzdGQgMiBsZXZlbCB0ZXh0KSBmb3IgcnVyYWwgKFVSQkFOMjAxMSA9PSAwKSBnb3Z0IHNjaG9vbCAoQ1M0ID09Mikgb3IgcHJpdmF0ZSBhaWRlZCAoQ1M0ID09IDMpIHN0dWRlbnRzIGluIGdyYWRlcyAyIHRvIDUgKHRoZXJlIGFyZSB0b28gZmV3IHN0dWRlbnRzIGlmIHdlIHJlc3RyaWN0IG9ubHkgdG8gZ3JhZGUgMykgYnkgc3RhdGUuICp3YXJuaW5nOiB0aGlzIGNvZGUgdGFrZXMgYSBsb25nIHRpbWUqIA0KDQpgYGB7cn0NCmloZHNfaW5kX2RpciA8LSAiQzovVXNlcnMvZG91Z2ovRG9jdW1lbnRzL0RhdGEvSUhEUy9JSERTIDIwMTIvRFMwMDAxIg0KaW5kX2ZpbGUgPC0gZmlsZS5wYXRoKGloZHNfaW5kX2RpciwgIjM2MTUxLTAwMDEtRGF0YS5kdGEiKQ0KIyByZWFkIGluIGp1c3QgdGhvc2UgdmFyaWFibGVzIHRoYXQgaSBuZWVkDQojIHRoaXMgaXMgbXVjaCBmYXN0ZXIgdGhhbiByZWFkaW5nIGluIGV2ZXJ5dGhpbmcgYW5kIHRoZW4gc2VsZWN0aW5nDQppaGRzIDwtIHJlYWRfZHRhKGluZF9maWxlLCBjb2xfc2VsZWN0ID0gYyhTVEFURUlELCBESVNUSUQsIFBTVUlELCBISElELCBISFNQTElUSUQsIFBFUlNPTklELCBJRFBTVSwgV1QsIFJPMywgUk83LCBSTzUsIFVSQkFOMjAxMSwgc3RhcnRzX3dpdGgoIkNTIiksIHN0YXJ0c193aXRoKCJUQSIpLCBzdGFydHNfd2l0aCgiRUQiKSkpDQppaGRzIDwtIGloZHMgJT4lIG11dGF0ZShwc3VfZXhwYW5kZWQgPSBwYXN0ZShTVEFURUlELCBESVNUSUQsIFBTVUlELCBzZXAgPSItIiksIGhoX2V4cGFuZGVkID0gcGFzdGUoU1RBVEVJRCwgRElTVElELCBQU1VJRCwgSEhJRCwgSEhTUExJVElELCBzZXAgPSItIikpDQoNCiMgY29uZmlybSB0aGF0IFRBNCAoY2xhc3MpIGlzIG5vdCBOQSBpZiBUQThCIGlzIG5vdCBOQSAtLT4gdGhlcmUgYXJlIG9ubHkgMzggaW5zdGFuY2VzIHdoZW4gVEE4QiBpcyBub3QgTkEgYnV0IFRBNCBpcyBOQQ0KaWhkcyAlPiUgZmlsdGVyKCFpcy5uYShUQThCKSkgJT4lIGNvdW50KFRBNCkNCg0KIyBkcm9wIHRoZSBvbmUgcm93IHdpdGggbWlzc2luZyB2YWx1ZXMgZm9yIHdlaWdodHMNCmloZHMgPC0gaWhkcyAlPiUgZmlsdGVyKCFpcy5uYShXVCkpDQoNCiMgY3JlYXRlIHZhcmlhYmxlIGZvciBBU0VSIGF0IGxldmVsIDQNCmloZHMgPC0gaWhkcyAlPiUgbXV0YXRlKEFTRVI0ID0gKFRBOEIgPT00KSkgJT4lIG11dGF0ZShTdGF0ZSA9IGFzX2ZhY3RvcihTVEFURUlEKSkNCg0KIyB1c2UgdGhlIHN1cnZleSBwYWNrYWdlIHRvIHNldCB0aGUgc3VydmV5IGRlc2lnbi4gIEkgd2lsbCB1c2UgdGhlIGloZHNfc3Z5IG9iamVjdCB0byBjYWxjdWxhdGUgQ0lzDQppaGRzX3N2eSA8LSBzdnlkZXNpZ24oaWQgPX4gcHN1X2V4cGFuZGVkICsgaGhfZXhwYW5kZWQsIHdlaWdodHMgPX4gV1QsIGRhdGEgPSBpaGRzKQ0KDQojIHVzZSBzdGF0c2J5IHRvIGdldCB0aGUgJSBvZiBzZWxlY3RlZCBraWRzIHdobyBhY2hpZXZlIGxldmVsIDQgb24gQVNFUiByZWFkaW5nIGJ5IHN0YXRlDQojIG5vdGUgdGhhdCBJIGFtIG5vdCBzdXJlIGlmIHN1YnNldHRpbmcgd2l0aGluIHN0YXRzYnkgaXMga29zaGVyLCBidXQgdGhlIHN0YW5kYXJkIGVycm9ycyBzaG91bGQgYmUgb2sgDQojIG1vcmUgb3IgbGVzcyBvayByZWdhcmRsZXNzDQppaGRzX3Njb3JlcyA8LSBzdnlieSh+QVNFUjQsIH5TdGF0ZSwgc3Vic2V0KGloZHNfc3Z5LCAhaXMubmEoVEE4QikgJiAoQ1M0ID09IDIgfCBDUzQgPT0gMykgJiAoVEE0ID49IDIgJiBUQTQgPD0gNSkgJiAoVVJCQU4yMDExID09IDApKSwgc3Z5bWVhbiwgbmEucm09VFJVRSkNCg0KIyBjb252ZXJ0IHRvIGEgdGliYmxlDQppaGRzX3Njb3JlcyA8LSBhcy50aWJibGUoaWhkc19zY29yZXMpICU+JSBzZWxlY3QoU3RhdGUsIEFTRVI0VFJVRSwgc2UuQVNFUjRUUlVFKSAlPiUgcmVuYW1lKGloZHMgPSBBU0VSNFRSVUUsIGloZHNfc2UgPSBzZS5BU0VSNFRSVUUpDQoNCiMgVW5zdXJlLCBidXQgSSB0aGluayB0aGlzIGdldHMgcmlkIG9mIHRoZSBzcGFjZSBhbmQgbnVtYmVyIGF0IHRoZSBlbmQgb2YgdGhlIHN0YXRlIG5hbWUNCmloZHNfc2NvcmVzJFN0YXRlIDwtIHN1YigiLi4uJCIsICIiLCBpaGRzX3Njb3JlcyRTdGF0ZSkNCg0KIyByZXBsYWNlIHRoZSBzdGFuZGFyZCBlcnJvcnMgd2l0aCBOQSBpcyBTRSA9PSAwDQppaGRzX3Njb3JlcyRpaGRzW2loZHNfc2NvcmVzJGloZHNfc2UgPT0gMF0gPC0gTkENCg0KIyByZXBsYWNlIE9yaXNzYSB3aXRoIE9kaXNoYSBpbiBzdGF0ZSANCmloZHNfc2NvcmVzJFN0YXRlW2loZHNfc2NvcmVzJFN0YXRlID09ICJPcmlzc2EiXSA8LSAiT2Rpc2hhIg0KaWhkc19zY29yZXMkaWhkcyA8LSByb3VuZChpaGRzX3Njb3JlcyRpaGRzLCAzKSoxMDANCg0KYGBgDQoNCiMjIENhbGN1bGF0ZSBjb3JyZWxhdGlvbnMgDQoNCmBgYHtyfQ0KYXNlcl9uYXMgPC0gbWFpbl9kYXRhICU+JSBzZWxlY3QoU3RhdGUsIEFTRVJfMjAxOCwgTkFTKQ0Kc2NvcmVzIDwtIGFzZXJfbmFzICU+JSBmdWxsX2pvaW4oaWhkc19zY29yZXMsIGJ5ID0gIlN0YXRlIikNCg0KIyBkcm9wIGlmIElIRFNfQVNFUiBpcyBOQQ0KIyBzY29yZXMgPC0gc2NvcmVzICU+JSBmaWx0ZXIoIWlzLm5hKElIRFNfQVNFUikpICU+JSBhcnJhbmdlKEFTRVIpICU+JSBzZWxlY3QoU3RhdGUsIEFTRVIsIElIRFNfQVNFUiwgTkFTLCBvYnMpDQoNCiMgY2FsY3VsYXRlIGNvcnJlbGF0aW9uIG1hdHJpeCAtLT4gd2hpbGUgdGhlcmUgYXJlIGEgZmV3IG91dGxpZXJzLCBvdmVyYWxsIHRoZSBBU0VSIGRhdGEgYW5kIElIRFMgZGF0YSBtYXRjaCBPaw0KIyBub3RlIHRoYXQgDQp0ZW1wIDwtIHNjb3JlcyAlPiUgc2VsZWN0KEFTRVJfMjAxOCwgaWhkcywgTkFTKQ0KY29yKHRlbXAsIG1ldGhvZCA9ICJwZWFyc29uIiwgdXNlID0gInBhaXJ3aXNlLmNvbXBsZXRlLm9icyIpDQpjb3IodGVtcCwgbWV0aG9kID0gInNwZWFybWFuIiwgdXNlID0gInBhaXJ3aXNlLmNvbXBsZXRlLm9icyIpDQoNCiMgY29uZHVjdCBmb3JtYWwgY29ycmVsYXRpb24gdGVzdA0KY29yLnRlc3QodGVtcCROQVMsdGVtcCRpaGRzLCB1c2UgPSAicGFpcndpc2UuY29tcGxldGUub2JzIiwgbWV0aG9kID0gInBlYXJzb24iKQ0KY29yLnRlc3QodGVtcCRBU0VSXzIwMTgsdGVtcCRpaGRzLCB1c2UgPSAicGFpcndpc2UuY29tcGxldGUub2JzIiwgbWV0aG9kID0gInBlYXJzb24iKQ0KY29yLnRlc3QodGVtcCROQVMsdGVtcCRBU0VSXzIwMTgsIHVzZSA9ICJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiLCBtZXRob2QgPSAicGVhcnNvbiIpDQoNCmNvci50ZXN0KHRlbXAkTkFTLHRlbXAkaWhkcywgdXNlID0gInBhaXJ3aXNlLmNvbXBsZXRlLm9icyIsIG1ldGhvZCA9ICJzcGVhcm1hbiIpDQpjb3IudGVzdCh0ZW1wJEFTRVJfMjAxOCx0ZW1wJGloZHMsIHVzZSA9ICJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiLCBtZXRob2QgPSAic3BlYXJtYW4iKQ0KY29yLnRlc3QodGVtcCROQVMsdGVtcCRBU0VSXzIwMTgsIHVzZSA9ICJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiLCBtZXRob2QgPSAic3BlYXJtYW4iKQ0KDQpgYGANCg0KQ3JlYXRlIGdyYXBoIHNob3dpbmcgSUhEUywgQVNFUiwgYW5kIE5BUyBhbGwgb24gc2FtZSBzY2FsZS4NCg0KYGBge3J9DQoNCnNjb3Jlcy5sb25nIDwtIHNjb3JlcyAlPiUgc2VsZWN0KFN0YXRlLCBBU0VSXzIwMTgsIE5BUywgaWhkcykgJT4lDQogIHJlbmFtZShJSERTID0gaWhkcykgJT4lDQogIGZpbHRlcighaXMubmEoQVNFUl8yMDE4KSAmICFpcy5uYShOQVMpKSAlPiUNCiAgZ2F0aGVyKEFzc2Vzc21lbnQsIGF2Z19zY29yZSwgLVN0YXRlKSANCg0KZ2dwbG90KGRhdGEgPSBzY29yZXMubG9uZywgYWVzKHg9IHJlb3JkZXIoU3RhdGUsIGF2Z19zY29yZSkseT1hdmdfc2NvcmUsIGZpbGw9IEFzc2Vzc21lbnQpKSArIA0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aD0uOCkpICsgDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTkwKSkgKyANCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygibGlnaHRibHVlIiwgImJsdWUiLCAiZGFya2JsdWUiKSkrDQogIGxhYnMoeSA9ICJBdmVyYWdlIHNjb3JlIiwgeCA9ICIiKQ0KDQpgYGANCg0KQXR0ZW1wdCB0byBjcmVhdGUgdGhlIHNhbWUgYmFyIGJ1dCB3aXRoIHN0YW5kYXJkIGVycm9ycyBmb3IgSUhEUy4gDQoNCg0KYGBge3J9DQojIHRyZWF0IHRoZSBTRSBhcyBqdXN0IGFub3RoZXIgc2NvcmUNCnNjb3Jlcy5sb25nMiA8LSBzY29yZXMgICU+JQ0KICBmaWx0ZXIoIWlzLm5hKEFTRVJfMjAxOCkgJiAhaXMubmEoTkFTKSkgJT4lIA0KICBtdXRhdGUoSUhEUyA9IHBhc3RlKGloZHMsaWhkc19zZSwgc2VwID0iLSIpKSAlPiUgDQogIHNlbGVjdChTdGF0ZSwgQVNFUl8yMDE4LCBOQVMsIElIRFMpICU+JSANCiAgZ2F0aGVyKEFzc2Vzc21lbnQsIGF2Z19zY29yZSwgLVN0YXRlKSAlPiUNCiAgc2VwYXJhdGUoYXZnX3Njb3JlLCBzZXAgPSAiLSIsIGludG8gPSBjKCJhdmdfc2NvcmUiLCJzZSIpKQ0KDQojIGNvbnZlcnQgYXZnX3Njb3JlIGFuZCBzZSBiYWNrIHRvIG51bWVyaWMgDQpzY29yZXMubG9uZzIgPC0gc2NvcmVzLmxvbmcyICAlPiUNCiAgbXV0YXRlKGF2Z19zY29yZSA9IGFzLm51bWVyaWMoYXZnX3Njb3JlKSwgc2UgPSBhcy5udW1lcmljKHNlKSkNCg0KIyBtdWx0aXBseSBzZSANCnNjb3Jlcy5sb25nMiA8LSBzY29yZXMubG9uZzIgICU+JQ0KICBtdXRhdGUoc2UgPSAxMDAqc2UpDQoNCg0KIyBjcmVhdGUgeV9taW4gYW5kIHlfbWF4DQptIDwtIHFub3JtKDEtLjA1LzIpDQpzY29yZXMubG9uZzIgPC0gc2NvcmVzLmxvbmcyICAlPiUNCiAgbXV0YXRlKHltaW4gPSBhdmdfc2NvcmUtbSpzZSwgeW1heCA9IGF2Z19zY29yZSttKnNlKSAlPiUNCiAgbXV0YXRlKHltaW4gPSBpZmVsc2UoeW1pbiA8MCwgMCwgeW1pbikpDQoNCg0KZ2dwbG90KGRhdGEgPSBzY29yZXMubG9uZzIsIGFlcyh4PSByZW9yZGVyKFN0YXRlLCBhdmdfc2NvcmUpLHk9YXZnX3Njb3JlLCBmaWxsPSBBc3Nlc3NtZW50KSkgKyANCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGg9LjgpKSArIA0KICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0geW1pbiwgeW1heCA9IHltYXgpLCB3aWR0aCA9IC4xKSArIA0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT05MCkpICsgDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImxpZ2h0Ymx1ZSIsICJibHVlIiwgImRhcmtibHVlIikpKw0KICBsYWJzKHkgPSAiQXZlcmFnZSBzY29yZSIsIHggPSAiIikNCmdnc2F2ZSgiYXNlcl9uYXNfaWhkc192YWx1ZXMucG5nIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA2ICwgcGF0aCA9IGZpZ3VyZXMpDQpgYGANCg0KDQpTaG93IGxpbmUgZ3JhcGhzIG9mIEFTRVIgY2xhc3MgMyByZWFkaW5nIHNjb3JlcyBmb3IgZ292dCBzY2hvb2wgc3R1ZGVudHMgb3ZlciB0aW1lLg0KDQpgYGB7cn0NCiMgcmVzaGFwZSB0aGUgbWFpbiBkYXRhDQpzY29yZXMubG9uZzMgPC0gbWFpbl9kYXRhICU+JSANCiAgc2VsZWN0KFN0YXRlLCBzdGFydHNfd2l0aCgiQVNFUiIpKSAlPiUgDQogIHNlbGVjdCgtYXNlcl9yYW5rKSAlPiUNCiAgZ2F0aGVyKGtleSA9IlRlbXAiLCB2YWx1ZT0gIlJlYWRpbmciLCAtU3RhdGUpICU+JQ0KICBzZXBhcmF0ZShUZW1wLCBzZXAgPSAiXyIsIGludG8gPSBjKCJkdW1teSIsIlllYXIiKSkNCg0KZ2dwbG90KGRhdGEgPSBzY29yZXMubG9uZzMsIGFlcyh4PVllYXIsIHk9UmVhZGluZywgY29sb3I9U3RhdGUpKSArDQogIGdlb21fbGluZShhZXMoZ3JvdXA9U3RhdGUpKQ0KDQpnZ3NhdmUoImFzZXJfb3Zlcl90aW1lLnBuZyIsIHBhdGggPSBmaWd1cmVzKQ0KDQpgYGANCg0K