This notebook decomposes the variance of ASER state and district averages (and round to round changes in those averages) into a persistent component and a transitory component. We then further decompose the transitory component into sampling error and a non-sampling component.
We are unable to definitely say whether the non-sampling transitory component is due to non-sampling survey error or one-off shocks to learning outcomes, but there are several reasons to believe that survey error is more likely. In particular:
- Few policies last for only one year
- There are unlikely to be large changes in cohort ability or a big shift from rural to urban
Scroll to the end to see all the results
Decomposing variance into persistent and transitory components
Kaine and Staiger (2002) develop two methods for decomposing variance in the changes in scores into persistent and transitory components. The intuition behind these methods is that if a change in scores from one year to the next is reversed in the following year we would likely suspect that the changes in scores were not due to an actual underlying improvement in learning outcomes. Instead, we would expect that the observed temporary increase was due to measurement error or some other transitory effect (e.g. perhaps there was a heat wave which lowered scores one year).
For the first method they first assume that average test scores for a school in time t, \(y_t\), consist of a fixed component \(\alpha\), a persistent component \(v_t\) which follows a random walk, and a transitory component \(\varepsilon _t\)
\[y_t=\alpha+v_t+\varepsilon_t; v_t=v_{t-1}+u_t\]
Then \(Var(y_t-y_{t-1})= \sigma_u^2+2\sigma_{\varepsilon}^2\) and the proportion of the overall variance of the changes in y arising due to the transitory shock, the \(2\sigma_{\varepsilon}^2\) component, can be estimated as…
\[ -2*corr(\Delta y_t , \Delta y_{t-1} ) = \frac{2\sigma_{\varepsilon}^2}{(\sigma_u^2+2\sigma_{\varepsilon}^2)} \]
Similarly, we can also estimate the proportion of variance in levels (as opposed to changes) which are due to the transitory shock using the fact that…
\[ \sigma^2_{\varepsilon}=-corr(\Delta y_t , \Delta y_{t-1} )*Var(\Delta y_t ) \]
A potential downside to this method is that it relies on the assumption that the terms \(u_t\) are not serially correlated. This might be the case if, for example, a state or district implemented a program which led to sustained improvements in learning outcomes. We can test for this by looking at \(corr(\Delta y_t , \Delta y_{t-2} )\). If the \(u_t\) terms are not serially correlated, the correlation in current changes and twice lagged changes should be 0.
We find that this holds for district changes (the correlation between changes and twice lagged changes is -0.0739763) but not for the state changes (the correlation is -0.2202468). Thus, for states we use Kane and Staiger’s second method which is slightly more complicated. (We also apply the first method as a robustness check.)
The second method relies on the fact that if there is both a persistent component and a transitory component to scores, we would expect the correlation between current scores and the first lagged score to reflect both persistent and transitory shocks while the correlation between current scores and further lags would mainly reflect the transitory component. Thus, if looking at a graph of the correlation by lag number, the correlation should fall quite a bit from 1 with the first lag and then exhibit relatively steady decay after that. We do in fact see this with state scores.
Using this method, we the variance of the persistent component using the following formula:
\[ \sigma^2_{pers}=1-\sigma^2_{\varepsilon}=\frac{\sigma^2_y*\rho_1}{\rho_{pers}}\]
Where \[\rho_{pers}=1/K \sum \frac{\rho_{k+1}}{\rho_k} \]
Decomposing non-persistent variance into sampling and other sources
If we have an estimate of the sampling error for scores, we may further decompose the variance arising from transitory shocks into a component due to sampling error and a component due to other unexplained sources. That is, we assume that \(\varepsilon_t = \varepsilon_{ts} + \varepsilon_{to}\) where the first component is due to sampling and the second is due to other unexplained sources (and the two components are independent) and combine our estimates of \(\sigma^2_s\) and with estimates of \(\sigma_{\varepsilon}^2\) from above.
ASER doesn’t publish standard errors and we don’t have access to the microdata so we are unable to directly estimate the standard errors. There are two ways in which we can indirectly estimate the standard errors. First, this paper by Ramaswami and Wadhwa gives standard errors for a few states and districts. Standard errors for the proportion of class 3-5 students who can read a std 1 text by state, reported in table 1, are all roughly .01. The states for which standard errors are reported are all fairly large states and thus we should not use this value for all states, but it serves as a useful robustness check. Standard errors for districts are around .04. (To arrive at this figure, I used the margin of errors reported for std35_lang in table 2 which are roughly .12. From table 1, I assumed that the prevalence of std35_lang is around .65 and used the formula from the paper for margin of error to back out the standard errors.). So, using this approach, our estimate of \(\sigma_{s}^2\) for state averages is \(.0001=.01^2\) and for district averages is \(.0016=.04^2\). Note that since there are around 16-25 districts per state (for the states which the paper calculates standard errors) we would expect the district variance to be about 1/16th to 1/25th the state variance which is what we see.
Alternatively, we may calculate standard errors for district averages analtically using knowledge of the sampling design and an estimate of the ICC at the village level from IHDS. Using IHDS, we know that the ICC of ASER scores at the village level is around .067. (See the IHDS analysis notebook for this calculation.) Within each district, ASER samples 30 villages and interviews 20 households (or is it kids?) per village. For a variable with prevalence p = .65, the variance of the district estimates from sampling would be…
\[ DEFF = 1+(m-1)\rho \approx 1+(20-1)*.067=2.273\]
\[ \sigma_s^2=\frac{DEFF*p*(1-p)}{600}\approx 9.4708333\times 10^{-4}\] The close similarity between estimates of \(\sigma_{s}^2\) derived analytically and estimates backed out from the Ramaswami and Wadhwa paper gives us confidence.
We take as our final value of \(\sigma_{s}^2\) for districts is .0013. For states, we calculate \(\sigma_{s}^2=.0013/(N_s)\) where \(N_s\) is the number of districts in state s and then take the average across states. We note that the proportion of variance in state levels and changes due to sampling is very small and thus estimating state level sampling variance accurately is less important than for districts.
District Data
We use ASER data from the ASER district pages from years 2006 to 2014. These are the only years for which ASER has publicly released district level data (to my knowledge). There are four learning outcomes variables which all of these district pages include:
- Share class 1 and 2 students who can at least read letters
- Share class 1 and 2 students who can at least recognize numbers
- Share class 3, 4, and 5 students who can at least read level 1 text
- Share class 3, 4, and 5 students who can at least do subtraction
Note that these figures averages across all children, regardless of what type of school they attend.
We use the last two learning outcomes – those for children in class 3, 4, and 5. These learning outcomes should be, in theory, more stable. In addition, they are similar to the learning outcome used in the ASER vs. NAS analysis.
State Data
State level data has been scraped from the individual state “ASER Trends over time” reports. I first used tabula to scrape the pdf and then used an R script (“import ASER trends over time”) to clean up the tabula output. Note that I had to manually change the tabula output in several cases because it didn’t work super well.
There are a lot of different values, but I just used…
- share of class 3 kids who can read a std 1 text
- Share of class 3 kids who can do at least subtraction
These are the only variables available for class 3 kids (though they are also broken up by school type as well) in the trends over time report.
Setup
library(tidyverse)
dist_path <- "C:/Users/dougj/Documents/Data/Education/ASER District Data/Clean"
output <- "C:/Users/dougj/Dropbox/Education in India/Original research/Learning outcomes data/figures"
dists <- read_csv(file.path(dist_path, "aser_district_partial.csv"))
state_path <- "C:/Users/dougj/Documents/Data/Education/ASER trends over time"
states <- read_csv(file.path(state_path, "aser_trends.csv")) %>% select(year, State, std3_reading, std3_math)
##### IMPORTANT: TO DO ALL THE ANALYZE FOR MATH, SET THE SUBJECT BELOW TO "MATH" ###
subject <- "math"
if (subject == "math") {
dists$std35_std1_and_up <- dists$std35_subtraction_and_up
states$std3_reading <- states$std3_math
}
### IMPORTANT -- THIS IS WHERE I SPECIFY DISTRICT SAMPLING VARIANCE ###
var_dist_sampling <- .0013
District analysis
Estimate \(corr(\Delta y_t , \Delta y_{t-1} )\) by using the autocorrelation of district deltas.
# Create variable for deltas and first and second lag of the delta
dist_deltas <- dists %>%
group_by(State, District) %>%
mutate(delta_reading = std35_std1_and_up - lag(std35_std1_and_up, order_by = year), delta_math = std35_subtraction_and_up - lag(std35_subtraction_and_up)) %>%
mutate(delta_reading_lagged = lag(delta_reading, order_by = year), delta_reading_dbl_lag = lag(delta_reading, n= 2, order_by = year)) %>%
arrange(State, District, year)
# Calculate autocorrelation of delta_reading by district and then average over all districts
# Note that since the data is already grouped by State and district, we are calculating
# autocorrelation for each district and then averaging across all districts
corr_dist_deltas <- dist_deltas %>%
filter(year >= 2008) %>%
summarise(auto = cor(delta_reading, delta_reading_lagged)) %>%
ungroup() %>%
summarise(mean_auto=mean(auto)) %>% .$mean_auto
# Calculate the autocorrelation in one go for all pairs of delta and delta_lagged.
# Note that we are not doing any averaging here.
# This should spit out a very similar value and it does.
check_corr_dist_deltas <- dist_deltas %>%
ungroup() %>%
filter(year >= 2008) %>%
summarise(auto = cor(delta_reading, delta_reading_lagged))
# Calculate the overall variance of the deltas
# Note that we have to divide by 100 here to get the actual number.
# We didn't need to do this above because we just calculated correlation and thus scale didn't matter
var_dist_deltas <- var(dist_deltas$delta_reading/100, na.rm = TRUE)
# Calculate overall variance of the district values.
# Note that we don't want to first calculate variance of dist reading scores by state and then average
# That would really underestimate the variance of the district scores.
# (To understand intuition, note districts are considered iid in the model above.)
var_dist_levels <- var(dists$std35_std1_and_up/100, na.rm = TRUE)
# Calculate variance of the transitory component
var_dist_epsilon <- -corr_dist_deltas*var_dist_deltas
Check that \(corr(\Delta y_t , \Delta y_{t-2} )=0\) and that letters and numbers are correlated.
#
corr_dist_dbl_lag <- dist_deltas %>% filter(year >= 2009) %>%
ungroup() %>%
summarize(auto =cor(delta_reading,delta_reading_dbl_lag, use = "pairwise.complete.obs")) %>%
.$auto
# Check that changes in letters and numbers is correlated -- they are
dist_deltas %>% filter(year != 2006) %>% ungroup() %>%
summarize(cor(delta_reading,delta_math))
NA
Consolidated district level results
Based on the code above, the final values for the key parameters for the district level are…
- \(corr(\Delta y_t , \Delta y_{t-1} ) = -0.3803595\)
- \(Var(\Delta y_t )= 0.0205213\)
- \(\sigma^2_{\varepsilon} = -corr(\Delta y_t , \Delta y_{t-1} )* Var(\Delta y_t ) = 0.0078055\)
- \(\sigma^2_y = 0.0327374\)
From these figures, we can calculate:
- Share of variance in levels due to transitory shocks = 0.2384259
- Share of variance in changes due to transitory shocks = 0.7607191
- Share of the transitory variance due to sampling (for both changes and levels) = 0.1665502
State analysis - method 1
Estimate \(corr(\Delta y_t , \Delta y_{t-1} )\) at state level by average autocorrelation of state deltas.
# Create variable for year on year change for each district
state_deltas <- states %>%
group_by(State) %>%
mutate(delta_reading = std3_reading - lag(std3_reading, order_by = year), delta_math = std3_math - lag(std3_math, order_by = year)) %>%
mutate(delta_reading_lagged = lag(delta_reading, order_by = year), delta_reading_dbl_lag = lag(delta_reading,n=2, order_by = year)) %>%
arrange(State, year)
# Calculate average autocorrelation of delta_reading
corr_state_deltas <- state_deltas %>%
filter(year >= 2008) %>%
summarise(auto = cor(delta_reading, delta_reading_lagged, use = "pairwise.complete.obs")) %>%
ungroup() %>%
summarise(mean_auto=mean(auto)) %>% .$mean_auto
# Calculate correlation betwen delta letters and delta letters lagged for entire dataset (without first calculating for each state and then averaging).
# this should be about the same as when we first calculate for each state and then average --> which it is.
check_corr_state_deltas <- state_deltas %>% filter(year >= 2008) %>%
ungroup() %>%
summarize(auto =cor(delta_reading,delta_reading_lagged, use = "pairwise.complete.obs")) %>%
.$auto
# calculate the variance of the deltas
var_state_deltas <- var(state_deltas$delta_reading/100, na.rm = TRUE)
# calculate the variance of the levels
var_state_levels <- var(state_deltas$std3_reading/100, na.rm = TRUE)
# calculate variance of transitory component
var_state_epsilon <- -corr_state_deltas*var_state_deltas
Calculate average sampling variance. Note that since we are just calculating the overall average, I don’t have to merge on state names.
var_state_sampling <- dists %>% filter(year ==2008) %>%
count(State) %>%
mutate(sampling_var = var_dist_sampling/n) %>%
summarize(mean_sampling = mean(sampling_var)) %>% .$mean_sampling
check that there is no correlation with double lags
# Check that changes in letters and numbers is correlated -- they are highly correlated
state_deltas %>% filter(year >= 2008) %>% ungroup() %>%
summarize(cor(delta_reading,delta_math, use = "pairwise.complete.obs"))
corr_state_dbl_lag <- state_deltas %>% filter(year >= 2009) %>%
ungroup() %>%
summarize(auto =cor(delta_reading,delta_reading_dbl_lag, use = "pairwise.complete.obs")) %>%
.$auto
temp <- state_deltas %>% filter(year >= 2009) %>%
group_by(State) %>%
summarize(auto =cor(delta_reading,delta_reading_dbl_lag, use = "pairwise.complete.obs"))
Consolidated state level results - method 1
Since the correlation of current levels and twice lags is not 0, we don’t use these values, but consolidating them here for reference:
- \(corr(\Delta y_t , \Delta y_{t-1} ) = -0.20926\)
- \(Var(\Delta y_t )= 0.0073836\)
- \(\sigma^2_{\varepsilon} = -corr(\Delta y_t , \Delta y_{t-1} )* Var(\Delta y_t ) = 0.0015451\)
- \(\sigma^2_y = 0.0261895\)
- \(\sigma^2_{sampling} = 1.7844227\times 10^{-4}\)
State analysis - method 2
Calculate the share of variance due to persistent effects by look at how correlation in levels decays over time.
state_lags <- states %>%
group_by(State) %>%
mutate(read_lag1 = lag(std3_reading, order_by = year),
read_lag2 = lag(std3_reading, n= 2, order_by = year),
read_lag3 = lag(std3_reading, n =3, order_by = year),
read_lag4 = lag(std3_reading, n =4, order_by = year),
read_lag5 = lag(std3_reading, n =5, order_by = year)) %>%
ungroup()
rho = c()
# for each of the lags, calculate the correlation between current and the lag and store in vector rho
for (lag in seq(1,5)) {
rho <- c(rho, cor(state_lags$std3_reading, state_lags[[paste("read_lag",as.character(lag),sep="")]], use = "pairwise.complete.obs"))
}
# Calculate variance of the transitory component by comparing rho_1 with the decay of rho after that
var_state_levels_persistent2 <- rho[1]/mean(rho/lag(rho), na.rm = TRUE)*var_state_levels
# Calculate the share of variance coming from other transitory sources.
# We will need this to calculate the variance breakup for changes
var_state_levels_other2 <- var_state_levels - var_state_levels_persistent2 - var_state_sampling
# Save a graph showing the decay of the correlation
quick_df <- tibble(lag = seq(0,5), correlation = c(1,rho))
ggplot(quick_df, aes(x= lag, y = correlation)) +
geom_line() +
geom_point() +
ylim(0,1)
ggsave(paste(subject, "- correlation_decay.png"), width = 5, height = 6 , path = output)

Consolidated state level results - method 2
With method 2, we have the same values for * \(Var(\Delta y_t )\),\(\sigma^2_y\), and \(\sigma^2_{sampling}\).
Instead of calculating \(\sigma^2_{\varepsilon}\), we calculate…
- \(\sigma^2_{pers} = 0.0252023\)
And then use these values to calculate…
- Share of variance in levels due to transitory shocks = 0.0376981
- Share of variance in changes due to transitory shocks = 0.2674285
- Share of the transitory variance due to sampling (for both changes and levels) = 0.1807383
Create bar plot of results
We now have all the inputs we need to replicate figure 4 from Kane and Staiger
# Create empty tibble to store results
# I
df_bar <- tibble(state_or_dist = rep(c("State","District"),each =6),
changes_or_levels =rep(rep(c("Changes","Levels"), each =3), times= 2),
bar_part = factor(rep(c("Persistent","Transitory sampling", "Transitory other"),4), levels = c("Transitory other","Transitory sampling", "Persistent")),
value = rep(.001,12)
)
# Update the values for the district changes bar
df_bar$value[(df_bar$state_or_dist == "District") & (df_bar$changes_or_levels == "Changes") & (df_bar$bar_part == "Persistent")] <- var_dist_deltas - 2*var_dist_epsilon
df_bar$value[(df_bar$state_or_dist == "District") & (df_bar$changes_or_levels == "Changes") & (df_bar$bar_part == "Transitory sampling")] <- 2*var_dist_sampling
df_bar$value[(df_bar$state_or_dist == "District") & (df_bar$changes_or_levels == "Changes") & (df_bar$bar_part == "Transitory other")] <- 2*var_dist_epsilon - 2*var_dist_sampling
# Update the values for the district levels bar
df_bar$value[(df_bar$state_or_dist == "District") & (df_bar$changes_or_levels == "Levels") & (df_bar$bar_part == "Persistent")] <- var_dist_levels - var_dist_epsilon
df_bar$value[(df_bar$state_or_dist == "District") & (df_bar$changes_or_levels == "Levels") & (df_bar$bar_part == "Transitory sampling")] <- var_dist_sampling
df_bar$value[(df_bar$state_or_dist == "District") & (df_bar$changes_or_levels == "Levels") & (df_bar$bar_part == "Transitory other")] <- var_dist_epsilon - var_dist_sampling
##### STATE DATA #####
# CHANGES
df_bar$value[(df_bar$state_or_dist == "State") & (df_bar$changes_or_levels == "Changes") & (df_bar$bar_part == "Persistent")] <- var_state_deltas-2*(var_state_sampling+var_state_levels_other2)
df_bar$value[(df_bar$state_or_dist == "State") & (df_bar$changes_or_levels == "Changes") & (df_bar$bar_part == "Transitory sampling")] <- 2*var_state_sampling
df_bar$value[(df_bar$state_or_dist == "State") & (df_bar$changes_or_levels == "Changes") & (df_bar$bar_part == "Transitory other")] <- 2*var_state_levels_other2
# LEVELS
df_bar$value[(df_bar$state_or_dist == "State") & (df_bar$changes_or_levels == "Levels") & (df_bar$bar_part == "Persistent")] <- var_state_levels_persistent2
df_bar$value[(df_bar$state_or_dist == "State") & (df_bar$changes_or_levels == "Levels") & (df_bar$bar_part == "Transitory sampling")] <- var_state_sampling
df_bar$value[(df_bar$state_or_dist == "State") & (df_bar$changes_or_levels == "Levels") & (df_bar$bar_part == "Transitory other")] <- var_state_levels_other2
# I have created this graph so that you can see it in the notebook
# The final version which combines both subjects, is created in a separate notebook
ggplot(df_bar, aes(fill = bar_part, y=value, x= changes_or_levels)) +
geom_bar(position="stack", stat ="identity") +
facet_grid(~ state_or_dist) +
scale_fill_manual(values = c("red", "orange", "blue"))+
labs(fill = "Variance component", x = "")
ggsave(paste(subject," - variance_decomposition.png"), width = 5, height = 6 , path = output)

write_csv(df_bar, file.path(output, paste(subject, "- bar data.csv")))
Create dataframe with results
Take the output that was used to create the bar graph, reshape it, and save it as a csv
df_final <- df_bar %>%
pivot_wider(names_from = "bar_part", values_from= "value") %>%
mutate(total_var = `Persistent`+`Transitory sampling`+`Transitory other`) %>%
mutate(share_pers = `Persistent`/total_var, share_samp = `Transitory sampling`/total_var, share_other = `Transitory other`/total_var)
write_csv(df_final, file.path(output, paste(subject, "- var deco.csv")))
LS0tDQp0aXRsZTogIkFTRVIgdmFyaWFuY2Ugb3ZlciB0aW1lIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KVGhpcyBub3RlYm9vayBkZWNvbXBvc2VzIHRoZSB2YXJpYW5jZSBvZiBBU0VSIHN0YXRlIGFuZCBkaXN0cmljdCBhdmVyYWdlcyAoYW5kIHJvdW5kIHRvIHJvdW5kIGNoYW5nZXMgaW4gdGhvc2UgYXZlcmFnZXMpIGludG8gYSBwZXJzaXN0ZW50IGNvbXBvbmVudCBhbmQgYSB0cmFuc2l0b3J5IGNvbXBvbmVudC4gV2UgdGhlbiBmdXJ0aGVyIGRlY29tcG9zZSB0aGUgdHJhbnNpdG9yeSBjb21wb25lbnQgaW50byBzYW1wbGluZyBlcnJvciBhbmQgYSBub24tc2FtcGxpbmcgY29tcG9uZW50Lg0KDQpXZSBhcmUgdW5hYmxlIHRvIGRlZmluaXRlbHkgc2F5IHdoZXRoZXIgdGhlIG5vbi1zYW1wbGluZyB0cmFuc2l0b3J5IGNvbXBvbmVudCBpcyBkdWUgdG8gbm9uLXNhbXBsaW5nIHN1cnZleSBlcnJvciBvciBvbmUtb2ZmIHNob2NrcyB0byBsZWFybmluZyBvdXRjb21lcywgYnV0IHRoZXJlIGFyZSBzZXZlcmFsIHJlYXNvbnMgdG8gYmVsaWV2ZSB0aGF0IHN1cnZleSBlcnJvciBpcyBtb3JlIGxpa2VseS4gSW4gcGFydGljdWxhcjoNCg0KKiBGZXcgcG9saWNpZXMgbGFzdCBmb3Igb25seSBvbmUgeWVhcg0KKiBUaGVyZSBhcmUgdW5saWtlbHkgdG8gYmUgbGFyZ2UgY2hhbmdlcyBpbiBjb2hvcnQgYWJpbGl0eSBvciBhIGJpZyBzaGlmdCBmcm9tIHJ1cmFsIHRvIHVyYmFuDQoNCioqU2Nyb2xsIHRvIHRoZSBlbmQgdG8gc2VlIGFsbCB0aGUgcmVzdWx0cyoqDQoNCiMjIERlY29tcG9zaW5nIHZhcmlhbmNlIGludG8gcGVyc2lzdGVudCBhbmQgdHJhbnNpdG9yeSBjb21wb25lbnRzDQpbS2FpbmUgYW5kIFN0YWlnZXIgKDIwMDIpXShodHRwczovL3B1YnMuYWVhd2ViLm9yZy9kb2kvcGRmcGx1cy8xMC4xMjU3LzA4OTUzMzAwMjMyMDk1MDk5MykgZGV2ZWxvcCB0d28gbWV0aG9kcyBmb3IgZGVjb21wb3NpbmcgdmFyaWFuY2UgaW4gdGhlIGNoYW5nZXMgaW4gc2NvcmVzIGludG8gcGVyc2lzdGVudCBhbmQgdHJhbnNpdG9yeSBjb21wb25lbnRzLiBUaGUgaW50dWl0aW9uIGJlaGluZCB0aGVzZSBtZXRob2RzIGlzIHRoYXQgaWYgYSBjaGFuZ2UgaW4gc2NvcmVzIGZyb20gb25lIHllYXIgdG8gdGhlIG5leHQgaXMgcmV2ZXJzZWQgaW4gdGhlIGZvbGxvd2luZyB5ZWFyIHdlIHdvdWxkIGxpa2VseSBzdXNwZWN0IHRoYXQgdGhlIGNoYW5nZXMgaW4gc2NvcmVzIHdlcmUgbm90IGR1ZSB0byBhbiBhY3R1YWwgdW5kZXJseWluZyBpbXByb3ZlbWVudCBpbiBsZWFybmluZyBvdXRjb21lcy4gSW5zdGVhZCwgd2Ugd291bGQgZXhwZWN0IHRoYXQgdGhlIG9ic2VydmVkIHRlbXBvcmFyeSBpbmNyZWFzZSB3YXMgZHVlIHRvIG1lYXN1cmVtZW50IGVycm9yIG9yIHNvbWUgb3RoZXIgdHJhbnNpdG9yeSBlZmZlY3QgKGUuZy4gcGVyaGFwcyB0aGVyZSB3YXMgYSBoZWF0IHdhdmUgd2hpY2ggbG93ZXJlZCBzY29yZXMgb25lIHllYXIpLg0KDQpGb3IgdGhlIGZpcnN0IG1ldGhvZCB0aGV5IGZpcnN0IGFzc3VtZSB0aGF0IGF2ZXJhZ2UgdGVzdCBzY29yZXMgZm9yIGEgc2Nob29sIGluIHRpbWUgdCwgJHlfdCQsIGNvbnNpc3Qgb2YgYSBmaXhlZCBjb21wb25lbnQgJFxhbHBoYSQsIGEgcGVyc2lzdGVudCBjb21wb25lbnQgJHZfdCQgd2hpY2ggZm9sbG93cyBhIHJhbmRvbSB3YWxrLCBhbmQgYSB0cmFuc2l0b3J5IGNvbXBvbmVudCAkXHZhcmVwc2lsb24gX3QkDQoNCiQkeV90PVxhbHBoYSt2X3QrXHZhcmVwc2lsb25fdDsgdl90PXZfe3QtMX0rdV90JCQNCg0KVGhlbiAkVmFyKHlfdC15X3t0LTF9KT0gXHNpZ21hX3VeMisyXHNpZ21hX3tcdmFyZXBzaWxvbn1eMiQgYW5kIHRoZSBwcm9wb3J0aW9uIG9mIHRoZSBvdmVyYWxsIHZhcmlhbmNlIG9mIHRoZSBjaGFuZ2VzIGluIHkgYXJpc2luZyBkdWUgdG8gdGhlIHRyYW5zaXRvcnkgc2hvY2ssIHRoZSAkMlxzaWdtYV97XHZhcmVwc2lsb259XjIkIGNvbXBvbmVudCwgY2FuIGJlIGVzdGltYXRlZCBhcy4uLg0KDQokJCAtMipjb3JyKFxEZWx0YSB5X3QgLCBcRGVsdGEgeV97dC0xfSApID0gIFxmcmFjezJcc2lnbWFfe1x2YXJlcHNpbG9ufV4yfXsoXHNpZ21hX3VeMisyXHNpZ21hX3tcdmFyZXBzaWxvbn1eMil9ICQkDQoNClNpbWlsYXJseSwgd2UgY2FuIGFsc28gZXN0aW1hdGUgdGhlIHByb3BvcnRpb24gb2YgdmFyaWFuY2UgaW4gKmxldmVscyogKGFzIG9wcG9zZWQgdG8gY2hhbmdlcykgd2hpY2ggYXJlIGR1ZSB0byB0aGUgdHJhbnNpdG9yeSBzaG9jayB1c2luZyB0aGUgZmFjdCB0aGF0Li4uDQoNCiQkIFxzaWdtYV4yX3tcdmFyZXBzaWxvbn09LWNvcnIoXERlbHRhIHlfdCAsIFxEZWx0YSB5X3t0LTF9ICkqVmFyKFxEZWx0YSB5X3QgKSAkJA0KDQpBIHBvdGVudGlhbCBkb3duc2lkZSB0byB0aGlzIG1ldGhvZCBpcyB0aGF0IGl0IHJlbGllcyBvbiB0aGUgYXNzdW1wdGlvbiB0aGF0IHRoZSB0ZXJtcyAkdV90JCBhcmUgbm90IHNlcmlhbGx5IGNvcnJlbGF0ZWQuIFRoaXMgbWlnaHQgYmUgdGhlIGNhc2UgaWYsIGZvciBleGFtcGxlLCBhIHN0YXRlIG9yIGRpc3RyaWN0IGltcGxlbWVudGVkIGEgcHJvZ3JhbSB3aGljaCBsZWQgdG8gc3VzdGFpbmVkIGltcHJvdmVtZW50cyBpbiBsZWFybmluZyBvdXRjb21lcy4gIFdlIGNhbiB0ZXN0IGZvciB0aGlzIGJ5IGxvb2tpbmcgYXQgJGNvcnIoXERlbHRhIHlfdCAsIFxEZWx0YSB5X3t0LTJ9ICkkLiBJZiB0aGUgJHVfdCQgdGVybXMgYXJlIG5vdCBzZXJpYWxseSBjb3JyZWxhdGVkLCB0aGUgY29ycmVsYXRpb24gaW4gY3VycmVudCBjaGFuZ2VzIGFuZCB0d2ljZSBsYWdnZWQgY2hhbmdlcyBzaG91bGQgYmUgMC4NCg0KV2UgZmluZCB0aGF0IHRoaXMgaG9sZHMgZm9yIGRpc3RyaWN0IGNoYW5nZXMgKHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIGNoYW5nZXMgYW5kIHR3aWNlIGxhZ2dlZCBjaGFuZ2VzIGlzIGByIGNvcnJfZGlzdF9kYmxfbGFnYCkgYnV0IG5vdCBmb3IgdGhlIHN0YXRlIGNoYW5nZXMgKHRoZSBjb3JyZWxhdGlvbiBpcyBgciBjb3JyX3N0YXRlX2RibF9sYWdgKS4gVGh1cywgZm9yIHN0YXRlcyB3ZSB1c2UgS2FuZSBhbmQgU3RhaWdlcidzIHNlY29uZCBtZXRob2Qgd2hpY2ggaXMgc2xpZ2h0bHkgbW9yZSBjb21wbGljYXRlZC4gKFdlIGFsc28gYXBwbHkgdGhlIGZpcnN0IG1ldGhvZCBhcyBhIHJvYnVzdG5lc3MgY2hlY2suKQ0KDQpUaGUgc2Vjb25kIG1ldGhvZCByZWxpZXMgb24gdGhlIGZhY3QgdGhhdCBpZiB0aGVyZSBpcyBib3RoIGEgcGVyc2lzdGVudCBjb21wb25lbnQgYW5kIGEgdHJhbnNpdG9yeSBjb21wb25lbnQgdG8gc2NvcmVzLCB3ZSB3b3VsZCBleHBlY3QgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gY3VycmVudCBzY29yZXMgYW5kIHRoZSBmaXJzdCBsYWdnZWQgc2NvcmUgdG8gcmVmbGVjdCBib3RoIHBlcnNpc3RlbnQgYW5kIHRyYW5zaXRvcnkgc2hvY2tzIHdoaWxlIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIGN1cnJlbnQgc2NvcmVzIGFuZCBmdXJ0aGVyIGxhZ3Mgd291bGQgbWFpbmx5IHJlZmxlY3QgdGhlIHRyYW5zaXRvcnkgY29tcG9uZW50LiBUaHVzLCBpZiBsb29raW5nIGF0IGEgZ3JhcGggb2YgdGhlIGNvcnJlbGF0aW9uIGJ5IGxhZyBudW1iZXIsIHRoZSBjb3JyZWxhdGlvbiBzaG91bGQgZmFsbCBxdWl0ZSBhIGJpdCBmcm9tIDEgd2l0aCB0aGUgZmlyc3QgbGFnIGFuZCB0aGVuIGV4aGliaXQgcmVsYXRpdmVseSBzdGVhZHkgZGVjYXkgYWZ0ZXIgdGhhdC4gIFdlIGRvIGluIGZhY3Qgc2VlIHRoaXMgd2l0aCBzdGF0ZSBzY29yZXMuDQoNClVzaW5nIHRoaXMgbWV0aG9kLCB3ZSB0aGUgdmFyaWFuY2Ugb2YgdGhlIHBlcnNpc3RlbnQgY29tcG9uZW50IHVzaW5nIHRoZSBmb2xsb3dpbmcgZm9ybXVsYToNCg0KJCQgXHNpZ21hXjJfe3BlcnN9PTEtXHNpZ21hXjJfe1x2YXJlcHNpbG9ufT1cZnJhY3tcc2lnbWFeMl95KlxyaG9fMX17XHJob197cGVyc319JCQNCg0KV2hlcmUgJCRccmhvX3twZXJzfT0xL0sgXHN1bSBcZnJhY3tccmhvX3trKzF9fXtccmhvX2t9ICQkDQoNCg0KDQojIyBEZWNvbXBvc2luZyBub24tcGVyc2lzdGVudCB2YXJpYW5jZSBpbnRvIHNhbXBsaW5nIGFuZCBvdGhlciBzb3VyY2VzDQpJZiB3ZSBoYXZlIGFuIGVzdGltYXRlIG9mIHRoZSBzYW1wbGluZyBlcnJvciBmb3Igc2NvcmVzLCB3ZSBtYXkgZnVydGhlciBkZWNvbXBvc2UgdGhlIHZhcmlhbmNlIGFyaXNpbmcgZnJvbSB0cmFuc2l0b3J5IHNob2NrcyBpbnRvIGEgY29tcG9uZW50IGR1ZSB0byBzYW1wbGluZyBlcnJvciBhbmQgYSBjb21wb25lbnQgZHVlIHRvIG90aGVyIHVuZXhwbGFpbmVkIHNvdXJjZXMuICBUaGF0IGlzLCB3ZSBhc3N1bWUgdGhhdCAkXHZhcmVwc2lsb25fdCA9IFx2YXJlcHNpbG9uX3t0c30gKyBcdmFyZXBzaWxvbl97dG99JCB3aGVyZSB0aGUgZmlyc3QgY29tcG9uZW50IGlzIGR1ZSB0byBzYW1wbGluZyBhbmQgdGhlIHNlY29uZCBpcyBkdWUgdG8gb3RoZXIgdW5leHBsYWluZWQgc291cmNlcyAoYW5kIHRoZSB0d28gY29tcG9uZW50cyBhcmUgaW5kZXBlbmRlbnQpIGFuZCBjb21iaW5lIG91ciBlc3RpbWF0ZXMgb2YgJFxzaWdtYV4yX3MkIGFuZCB3aXRoIGVzdGltYXRlcyBvZiAkXHNpZ21hX3tcdmFyZXBzaWxvbn1eMiQgZnJvbSBhYm92ZS4NCg0KDQpBU0VSIGRvZXNuJ3QgcHVibGlzaCBzdGFuZGFyZCBlcnJvcnMgYW5kIHdlIGRvbid0IGhhdmUgYWNjZXNzIHRvIHRoZSBtaWNyb2RhdGEgc28gd2UgYXJlIHVuYWJsZSB0byBkaXJlY3RseSBlc3RpbWF0ZSB0aGUgc3RhbmRhcmQgZXJyb3JzLiAgVGhlcmUgYXJlIHR3byB3YXlzIGluIHdoaWNoIHdlIGNhbiBpbmRpcmVjdGx5IGVzdGltYXRlIHRoZSBzdGFuZGFyZCBlcnJvcnMuICBGaXJzdCwgdGhpcyBbcGFwZXJdKGh0dHA6Ly9pbWcuYXNlcmNlbnRyZS5vcmcvZG9jcy9Bc2VyJTIwc3VydmV5L1RlY2huaWNhbCUyMFBhcGVycy9wcmVjaXNpb25vZmFzZXJlc3RpbWF0ZXNfcmFtYXN3YW1pX3dhZGh3YS5wZGYpIGJ5IFJhbWFzd2FtaSBhbmQgV2FkaHdhIGdpdmVzIHN0YW5kYXJkIGVycm9ycyBmb3IgYSBmZXcgc3RhdGVzIGFuZCBkaXN0cmljdHMuIFN0YW5kYXJkIGVycm9ycyBmb3IgdGhlIHByb3BvcnRpb24gb2YgY2xhc3MgMy01IHN0dWRlbnRzIHdobyBjYW4gcmVhZCBhIHN0ZCAxIHRleHQgYnkgc3RhdGUsIHJlcG9ydGVkIGluIHRhYmxlIDEsIGFyZSBhbGwgcm91Z2hseSAuMDEuICBUaGUgc3RhdGVzIGZvciB3aGljaCBzdGFuZGFyZCBlcnJvcnMgYXJlIHJlcG9ydGVkIGFyZSBhbGwgZmFpcmx5IGxhcmdlIHN0YXRlcyBhbmQgdGh1cyB3ZSBzaG91bGQgbm90IHVzZSB0aGlzIHZhbHVlIGZvciBhbGwgc3RhdGVzLCBidXQgaXQgc2VydmVzIGFzIGEgdXNlZnVsIHJvYnVzdG5lc3MgY2hlY2suIFN0YW5kYXJkIGVycm9ycyBmb3IgZGlzdHJpY3RzIGFyZSBhcm91bmQgLjA0LiAoVG8gYXJyaXZlIGF0IHRoaXMgZmlndXJlLCBJIHVzZWQgdGhlIG1hcmdpbiBvZiBlcnJvcnMgcmVwb3J0ZWQgZm9yIHN0ZDM1X2xhbmcgaW4gdGFibGUgMiB3aGljaCBhcmUgcm91Z2hseSAuMTIuICBGcm9tIHRhYmxlIDEsIEkgYXNzdW1lZCB0aGF0IHRoZSBwcmV2YWxlbmNlIG9mIHN0ZDM1X2xhbmcgaXMgYXJvdW5kIC42NSBhbmQgdXNlZCB0aGUgZm9ybXVsYSBmcm9tIHRoZSBwYXBlciBmb3IgbWFyZ2luIG9mIGVycm9yIHRvIGJhY2sgb3V0IHRoZSBzdGFuZGFyZCBlcnJvcnMuKS4gU28sIHVzaW5nIHRoaXMgYXBwcm9hY2gsIG91ciBlc3RpbWF0ZSBvZiAkXHNpZ21hX3tzfV4yJCBmb3Igc3RhdGUgYXZlcmFnZXMgaXMgJC4wMDAxPS4wMV4yJCBhbmQgZm9yIGRpc3RyaWN0IGF2ZXJhZ2VzIGlzICQuMDAxNj0uMDReMiQuIE5vdGUgdGhhdCBzaW5jZSB0aGVyZSBhcmUgYXJvdW5kIDE2LTI1IGRpc3RyaWN0cyBwZXIgc3RhdGUgKGZvciB0aGUgc3RhdGVzIHdoaWNoIHRoZSBwYXBlciBjYWxjdWxhdGVzIHN0YW5kYXJkIGVycm9ycykgd2Ugd291bGQgZXhwZWN0IHRoZSBkaXN0cmljdCB2YXJpYW5jZSB0byBiZSBhYm91dCAxLzE2dGggdG8gMS8yNXRoIHRoZSBzdGF0ZSB2YXJpYW5jZSB3aGljaCBpcyB3aGF0IHdlIHNlZS4NCg0KQWx0ZXJuYXRpdmVseSwgd2UgbWF5IGNhbGN1bGF0ZSBzdGFuZGFyZCBlcnJvcnMgZm9yIGRpc3RyaWN0IGF2ZXJhZ2VzIGFuYWx0aWNhbGx5IHVzaW5nIGtub3dsZWRnZSBvZiB0aGUgc2FtcGxpbmcgZGVzaWduIGFuZCBhbiBlc3RpbWF0ZSBvZiB0aGUgSUNDIGF0IHRoZSB2aWxsYWdlIGxldmVsIGZyb20gSUhEUy4gVXNpbmcgSUhEUywgd2Uga25vdyB0aGF0IHRoZSBJQ0Mgb2YgQVNFUiBzY29yZXMgYXQgdGhlIHZpbGxhZ2UgbGV2ZWwgaXMgYXJvdW5kIC4wNjcuIChTZWUgdGhlIElIRFMgYW5hbHlzaXMgbm90ZWJvb2sgZm9yIHRoaXMgY2FsY3VsYXRpb24uKSBXaXRoaW4gZWFjaCBkaXN0cmljdCwgQVNFUiBzYW1wbGVzIDMwIHZpbGxhZ2VzIGFuZCBpbnRlcnZpZXdzIDIwIGhvdXNlaG9sZHMgKG9yIGlzIGl0IGtpZHM/KSBwZXIgdmlsbGFnZS4gRm9yIGEgdmFyaWFibGUgd2l0aCBwcmV2YWxlbmNlIHAgPSAuNjUsIHRoZSB2YXJpYW5jZSBvZiB0aGUgZGlzdHJpY3QgZXN0aW1hdGVzIGZyb20gc2FtcGxpbmcgd291bGQgYmUuLi4NCg0KJCQgREVGRiA9IDErKG0tMSlccmhvIFxhcHByb3ggMSsoMjAtMSkqLjA2Nz1gciAuMDY3KjE5KzFgJCQNCg0KJCQgXHNpZ21hX3NeMj1cZnJhY3tERUZGKnAqKDEtcCl9ezYwMH1cYXBwcm94IGByICguMDY3KjE5KzEpKi41KigxLS41KS82MDBgJCQgDQpUaGUgY2xvc2Ugc2ltaWxhcml0eSBiZXR3ZWVuIGVzdGltYXRlcyBvZiAkXHNpZ21hX3tzfV4yJCBkZXJpdmVkIGFuYWx5dGljYWxseSBhbmQgZXN0aW1hdGVzIGJhY2tlZCBvdXQgZnJvbSB0aGUgUmFtYXN3YW1pIGFuZCBXYWRod2EgcGFwZXIgZ2l2ZXMgdXMgY29uZmlkZW5jZS4NCg0KV2UgdGFrZSBhcyBvdXIgZmluYWwgdmFsdWUgb2YgJFxzaWdtYV97c31eMiQgZm9yIGRpc3RyaWN0cyBpcyAuMDAxMy4gIEZvciBzdGF0ZXMsIHdlIGNhbGN1bGF0ZSAkXHNpZ21hX3tzfV4yPS4wMDEzLyhOX3MpJCB3aGVyZSAkTl9zJCBpcyB0aGUgbnVtYmVyIG9mIGRpc3RyaWN0cyBpbiBzdGF0ZSBzIGFuZCB0aGVuIHRha2UgdGhlIGF2ZXJhZ2UgYWNyb3NzIHN0YXRlcy4gV2Ugbm90ZSB0aGF0IHRoZSBwcm9wb3J0aW9uIG9mIHZhcmlhbmNlIGluIHN0YXRlIGxldmVscyBhbmQgY2hhbmdlcyBkdWUgdG8gc2FtcGxpbmcgaXMgdmVyeSBzbWFsbCBhbmQgdGh1cyBlc3RpbWF0aW5nIHN0YXRlIGxldmVsIHNhbXBsaW5nIHZhcmlhbmNlIGFjY3VyYXRlbHkgaXMgbGVzcyBpbXBvcnRhbnQgdGhhbiBmb3IgZGlzdHJpY3RzLg0KDQojIyBEaXN0cmljdCBEYXRhDQpXZSB1c2UgQVNFUiBkYXRhIGZyb20gdGhlIEFTRVIgZGlzdHJpY3QgcGFnZXMgZnJvbSB5ZWFycyAyMDA2IHRvIDIwMTQuICBUaGVzZSBhcmUgdGhlIG9ubHkgeWVhcnMgZm9yIHdoaWNoIEFTRVIgaGFzIHB1YmxpY2x5IHJlbGVhc2VkIGRpc3RyaWN0IGxldmVsIGRhdGEgKHRvIG15IGtub3dsZWRnZSkuICBUaGVyZSBhcmUgZm91ciBsZWFybmluZyBvdXRjb21lcyB2YXJpYWJsZXMgd2hpY2ggYWxsIG9mIHRoZXNlIGRpc3RyaWN0IHBhZ2VzIGluY2x1ZGU6DQoNCiogU2hhcmUgY2xhc3MgMSBhbmQgMiBzdHVkZW50cyB3aG8gY2FuIGF0IGxlYXN0IHJlYWQgbGV0dGVycw0KKiBTaGFyZSBjbGFzcyAxIGFuZCAyIHN0dWRlbnRzIHdobyBjYW4gYXQgbGVhc3QgcmVjb2duaXplIG51bWJlcnMNCiogU2hhcmUgY2xhc3MgMywgNCwgYW5kIDUgc3R1ZGVudHMgd2hvIGNhbiBhdCBsZWFzdCByZWFkIGxldmVsIDEgdGV4dA0KKiBTaGFyZSBjbGFzcyAzLCA0LCBhbmQgNSBzdHVkZW50cyB3aG8gY2FuIGF0IGxlYXN0IGRvIHN1YnRyYWN0aW9uDQoNCk5vdGUgdGhhdCB0aGVzZSBmaWd1cmVzIGF2ZXJhZ2VzIGFjcm9zcyBhbGwgY2hpbGRyZW4sIHJlZ2FyZGxlc3Mgb2Ygd2hhdCB0eXBlIG9mIHNjaG9vbCB0aGV5IGF0dGVuZC4gDQoNCldlIHVzZSB0aGUgbGFzdCB0d28gbGVhcm5pbmcgb3V0Y29tZXMgLS0gdGhvc2UgZm9yIGNoaWxkcmVuIGluIGNsYXNzIDMsIDQsIGFuZCA1LiBUaGVzZSBsZWFybmluZyBvdXRjb21lcyBzaG91bGQgYmUsIGluIHRoZW9yeSwgbW9yZSBzdGFibGUuIEluIGFkZGl0aW9uLCB0aGV5IGFyZSBzaW1pbGFyIHRvIHRoZSBsZWFybmluZyBvdXRjb21lIHVzZWQgaW4gdGhlIEFTRVIgdnMuIE5BUyBhbmFseXNpcy4NCg0KIyMgU3RhdGUgRGF0YQ0KU3RhdGUgbGV2ZWwgZGF0YSBoYXMgYmVlbiBzY3JhcGVkIGZyb20gdGhlIGluZGl2aWR1YWwgc3RhdGUgIkFTRVIgVHJlbmRzIG92ZXIgdGltZSIgcmVwb3J0cy4gSSBmaXJzdCB1c2VkIHRhYnVsYSB0byBzY3JhcGUgdGhlIHBkZiBhbmQgdGhlbiB1c2VkIGFuIFIgc2NyaXB0ICgiaW1wb3J0IEFTRVIgdHJlbmRzIG92ZXIgdGltZSIpIHRvIGNsZWFuIHVwIHRoZSB0YWJ1bGEgb3V0cHV0LiAgTm90ZSB0aGF0IEkgaGFkIHRvIG1hbnVhbGx5IGNoYW5nZSB0aGUgdGFidWxhIG91dHB1dCBpbiBzZXZlcmFsIGNhc2VzIGJlY2F1c2UgaXQgZGlkbid0IHdvcmsgc3VwZXIgd2VsbC4NCg0KVGhlcmUgYXJlIGEgbG90IG9mIGRpZmZlcmVudCB2YWx1ZXMsIGJ1dCBJIGp1c3QgdXNlZC4uLg0KDQoqIHNoYXJlIG9mIGNsYXNzIDMga2lkcyB3aG8gY2FuIHJlYWQgYSBzdGQgMSB0ZXh0DQoqIFNoYXJlIG9mIGNsYXNzIDMga2lkcyB3aG8gY2FuIGRvIGF0IGxlYXN0IHN1YnRyYWN0aW9uDQoNClRoZXNlIGFyZSB0aGUgb25seSB2YXJpYWJsZXMgYXZhaWxhYmxlIGZvciBjbGFzcyAzIGtpZHMgKHRob3VnaCB0aGV5IGFyZSBhbHNvIGJyb2tlbiB1cCBieSBzY2hvb2wgdHlwZSBhcyB3ZWxsKSBpbiB0aGUgdHJlbmRzIG92ZXIgdGltZSByZXBvcnQuDQoNCiMjIyBTZXR1cA0KYGBge3IsIHJlc3VsdHM9J2hpZGUnfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpkaXN0X3BhdGggPC0gIkM6L1VzZXJzL2RvdWdqL0RvY3VtZW50cy9EYXRhL0VkdWNhdGlvbi9BU0VSIERpc3RyaWN0IERhdGEvQ2xlYW4iDQpvdXRwdXQgPC0gIkM6L1VzZXJzL2RvdWdqL0Ryb3Bib3gvRWR1Y2F0aW9uIGluIEluZGlhL09yaWdpbmFsIHJlc2VhcmNoL0xlYXJuaW5nIG91dGNvbWVzIGRhdGEvZmlndXJlcyINCmRpc3RzIDwtIHJlYWRfY3N2KGZpbGUucGF0aChkaXN0X3BhdGgsICJhc2VyX2Rpc3RyaWN0X3BhcnRpYWwuY3N2IikpDQoNCnN0YXRlX3BhdGggPC0gIkM6L1VzZXJzL2RvdWdqL0RvY3VtZW50cy9EYXRhL0VkdWNhdGlvbi9BU0VSIHRyZW5kcyBvdmVyIHRpbWUiDQpzdGF0ZXMgPC0gcmVhZF9jc3YoZmlsZS5wYXRoKHN0YXRlX3BhdGgsICJhc2VyX3RyZW5kcy5jc3YiKSkgJT4lIHNlbGVjdCh5ZWFyLCBTdGF0ZSwgc3RkM19yZWFkaW5nLCBzdGQzX21hdGgpDQoNCiMjIyMjIElNUE9SVEFOVDogVE8gRE8gQUxMIFRIRSBBTkFMWVpFIEZPUiBNQVRILCBTRVQgVEhFIFNVQkpFQ1QgQkVMT1cgVE8gIk1BVEgiICMjIyANCnN1YmplY3QgPC0gIm1hdGgiDQppZiAoc3ViamVjdCA9PSAibWF0aCIpIHsNCiAgZGlzdHMkc3RkMzVfc3RkMV9hbmRfdXAgPC0gZGlzdHMkc3RkMzVfc3VidHJhY3Rpb25fYW5kX3VwDQogIHN0YXRlcyRzdGQzX3JlYWRpbmcgPC0gc3RhdGVzJHN0ZDNfbWF0aA0KfQ0KDQoNCiMjIyBJTVBPUlRBTlQgLS0gVEhJUyBJUyBXSEVSRSBJIFNQRUNJRlkgRElTVFJJQ1QgU0FNUExJTkcgVkFSSUFOQ0UgIyMjDQp2YXJfZGlzdF9zYW1wbGluZyA8LSAuMDAxMw0KDQpgYGANCg0KDQojIyBEaXN0cmljdCBhbmFseXNpcw0KRXN0aW1hdGUgJGNvcnIoXERlbHRhIHlfdCAsIFxEZWx0YSB5X3t0LTF9ICkkIGJ5IHVzaW5nIHRoZSBhdXRvY29ycmVsYXRpb24gb2YgZGlzdHJpY3QgZGVsdGFzLiANCg0KYGBge3J9DQojIENyZWF0ZSB2YXJpYWJsZSBmb3IgZGVsdGFzIGFuZCBmaXJzdCBhbmQgc2Vjb25kIGxhZyBvZiB0aGUgZGVsdGENCmRpc3RfZGVsdGFzIDwtIGRpc3RzICU+JSANCiAgZ3JvdXBfYnkoU3RhdGUsIERpc3RyaWN0KSAlPiUgDQogIG11dGF0ZShkZWx0YV9yZWFkaW5nID0gc3RkMzVfc3RkMV9hbmRfdXAgLSBsYWcoc3RkMzVfc3RkMV9hbmRfdXAsIG9yZGVyX2J5ID0geWVhciksIGRlbHRhX21hdGggPSBzdGQzNV9zdWJ0cmFjdGlvbl9hbmRfdXAgLSBsYWcoc3RkMzVfc3VidHJhY3Rpb25fYW5kX3VwKSkgJT4lDQogIG11dGF0ZShkZWx0YV9yZWFkaW5nX2xhZ2dlZCA9IGxhZyhkZWx0YV9yZWFkaW5nLCBvcmRlcl9ieSA9IHllYXIpLCBkZWx0YV9yZWFkaW5nX2RibF9sYWcgPSBsYWcoZGVsdGFfcmVhZGluZywgbj0gMiwgb3JkZXJfYnkgPSB5ZWFyKSkgJT4lDQogIGFycmFuZ2UoU3RhdGUsIERpc3RyaWN0LCB5ZWFyKQ0KDQoNCiMgQ2FsY3VsYXRlIGF1dG9jb3JyZWxhdGlvbiBvZiBkZWx0YV9yZWFkaW5nIGJ5IGRpc3RyaWN0IGFuZCB0aGVuIGF2ZXJhZ2Ugb3ZlciBhbGwgZGlzdHJpY3RzDQojIE5vdGUgdGhhdCBzaW5jZSB0aGUgZGF0YSBpcyBhbHJlYWR5IGdyb3VwZWQgYnkgU3RhdGUgYW5kIGRpc3RyaWN0LCB3ZSBhcmUgY2FsY3VsYXRpbmcgDQojIGF1dG9jb3JyZWxhdGlvbiBmb3IgZWFjaCBkaXN0cmljdCBhbmQgdGhlbiBhdmVyYWdpbmcgYWNyb3NzIGFsbCBkaXN0cmljdHMNCmNvcnJfZGlzdF9kZWx0YXMgPC0gZGlzdF9kZWx0YXMgJT4lIA0KICBmaWx0ZXIoeWVhciA+PSAyMDA4KSAlPiUgDQogIHN1bW1hcmlzZShhdXRvID0gY29yKGRlbHRhX3JlYWRpbmcsIGRlbHRhX3JlYWRpbmdfbGFnZ2VkKSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgc3VtbWFyaXNlKG1lYW5fYXV0bz1tZWFuKGF1dG8pKSAlPiUgLiRtZWFuX2F1dG8NCg0KDQojIENhbGN1bGF0ZSB0aGUgYXV0b2NvcnJlbGF0aW9uIGluIG9uZSBnbyBmb3IgYWxsIHBhaXJzIG9mIGRlbHRhIGFuZCBkZWx0YV9sYWdnZWQuDQojIE5vdGUgdGhhdCB3ZSBhcmUgbm90IGRvaW5nIGFueSBhdmVyYWdpbmcgaGVyZS4NCiMgVGhpcyBzaG91bGQgc3BpdCBvdXQgYSB2ZXJ5IHNpbWlsYXIgdmFsdWUgYW5kIGl0IGRvZXMuDQpjaGVja19jb3JyX2Rpc3RfZGVsdGFzIDwtIGRpc3RfZGVsdGFzICU+JSANCiAgdW5ncm91cCgpICU+JQ0KICBmaWx0ZXIoeWVhciA+PSAyMDA4KSAlPiUgDQogIHN1bW1hcmlzZShhdXRvID0gY29yKGRlbHRhX3JlYWRpbmcsIGRlbHRhX3JlYWRpbmdfbGFnZ2VkKSkNCg0KDQojIENhbGN1bGF0ZSB0aGUgb3ZlcmFsbCB2YXJpYW5jZSBvZiB0aGUgZGVsdGFzDQojIE5vdGUgdGhhdCB3ZSBoYXZlIHRvIGRpdmlkZSBieSAxMDAgaGVyZSB0byBnZXQgdGhlIGFjdHVhbCBudW1iZXIuDQojIFdlIGRpZG4ndCBuZWVkIHRvIGRvIHRoaXMgYWJvdmUgYmVjYXVzZSB3ZSBqdXN0IGNhbGN1bGF0ZWQgY29ycmVsYXRpb24gYW5kIHRodXMgc2NhbGUgZGlkbid0IG1hdHRlcg0KdmFyX2Rpc3RfZGVsdGFzIDwtIHZhcihkaXN0X2RlbHRhcyRkZWx0YV9yZWFkaW5nLzEwMCwgbmEucm0gPSBUUlVFKQ0KDQojIENhbGN1bGF0ZSBvdmVyYWxsIHZhcmlhbmNlIG9mIHRoZSBkaXN0cmljdCB2YWx1ZXMuDQojIE5vdGUgdGhhdCB3ZSBkb24ndCB3YW50IHRvIGZpcnN0IGNhbGN1bGF0ZSB2YXJpYW5jZSBvZiBkaXN0IHJlYWRpbmcgc2NvcmVzIGJ5IHN0YXRlIGFuZCB0aGVuIGF2ZXJhZ2UNCiMgVGhhdCB3b3VsZCByZWFsbHkgdW5kZXJlc3RpbWF0ZSB0aGUgdmFyaWFuY2Ugb2YgdGhlIGRpc3RyaWN0IHNjb3Jlcy4NCiMgKFRvIHVuZGVyc3RhbmQgaW50dWl0aW9uLCBub3RlIGRpc3RyaWN0cyBhcmUgY29uc2lkZXJlZCBpaWQgaW4gdGhlIG1vZGVsIGFib3ZlLikNCnZhcl9kaXN0X2xldmVscyA8LSB2YXIoZGlzdHMkc3RkMzVfc3RkMV9hbmRfdXAvMTAwLCBuYS5ybSA9IFRSVUUpDQoNCiMgQ2FsY3VsYXRlIHZhcmlhbmNlIG9mIHRoZSB0cmFuc2l0b3J5IGNvbXBvbmVudA0KdmFyX2Rpc3RfZXBzaWxvbiA8LSAtY29ycl9kaXN0X2RlbHRhcyp2YXJfZGlzdF9kZWx0YXMNCg0KYGBgDQoNCg0KQ2hlY2sgdGhhdCAkY29ycihcRGVsdGEgeV90ICwgXERlbHRhIHlfe3QtMn0gKT0wJCBhbmQgdGhhdCBsZXR0ZXJzIGFuZCBudW1iZXJzIGFyZSBjb3JyZWxhdGVkLg0KYGBge3J9DQojIA0KY29ycl9kaXN0X2RibF9sYWcgPC0gZGlzdF9kZWx0YXMgJT4lIGZpbHRlcih5ZWFyID49IDIwMDkpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIHN1bW1hcml6ZShhdXRvID1jb3IoZGVsdGFfcmVhZGluZyxkZWx0YV9yZWFkaW5nX2RibF9sYWcsIHVzZSA9ICJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiKSkgJT4lDQogIC4kYXV0bw0KDQoNCiMgQ2hlY2sgdGhhdCBjaGFuZ2VzIGluIGxldHRlcnMgYW5kIG51bWJlcnMgaXMgY29ycmVsYXRlZCAtLSB0aGV5IGFyZQ0KZGlzdF9kZWx0YXMgJT4lIGZpbHRlcih5ZWFyICE9IDIwMDYpICU+JSB1bmdyb3VwKCkgJT4lDQogIHN1bW1hcml6ZShjb3IoZGVsdGFfcmVhZGluZyxkZWx0YV9tYXRoKSkNCg0KYGBgDQoNCg0KDQojIyMgQ29uc29saWRhdGVkIGRpc3RyaWN0IGxldmVsIHJlc3VsdHMNCkJhc2VkIG9uIHRoZSBjb2RlIGFib3ZlLCB0aGUgZmluYWwgdmFsdWVzIGZvciB0aGUga2V5IHBhcmFtZXRlcnMgZm9yIHRoZSBkaXN0cmljdCBsZXZlbCBhcmUuLi4NCg0KKiAkY29ycihcRGVsdGEgeV90ICwgXERlbHRhIHlfe3QtMX0gKSA9IGByIGNvcnJfZGlzdF9kZWx0YXNgJA0KKiAkVmFyKFxEZWx0YSB5X3QgKT0gYHIgdmFyX2Rpc3RfZGVsdGFzYCQNCiogJFxzaWdtYV4yX3tcdmFyZXBzaWxvbn0gPSAtY29ycihcRGVsdGEgeV90ICwgXERlbHRhIHlfe3QtMX0gKSogVmFyKFxEZWx0YSB5X3QgKSA9IGByIHZhcl9kaXN0X2Vwc2lsb25gJA0KKiAkXHNpZ21hXjJfeSA9IGByIHZhcl9kaXN0X2xldmVsc2AkIA0KDQpGcm9tIHRoZXNlIGZpZ3VyZXMsIHdlIGNhbiBjYWxjdWxhdGU6DQoNCiogU2hhcmUgb2YgdmFyaWFuY2UgaW4gKipsZXZlbHMqKiBkdWUgdG8gdHJhbnNpdG9yeSBzaG9ja3MgPSBgciB2YXJfZGlzdF9lcHNpbG9uL3Zhcl9kaXN0X2xldmVsc2ANCiogU2hhcmUgb2YgdmFyaWFuY2UgaW4gKipjaGFuZ2VzKiogZHVlIHRvIHRyYW5zaXRvcnkgc2hvY2tzID0gYHIgLTIqY29ycl9kaXN0X2RlbHRhc2ANCiogU2hhcmUgb2YgdGhlIHRyYW5zaXRvcnkgdmFyaWFuY2UgZHVlIHRvIHNhbXBsaW5nIChmb3IgYm90aCBjaGFuZ2VzIGFuZCBsZXZlbHMpID0gYHIgdmFyX2Rpc3Rfc2FtcGxpbmcvdmFyX2Rpc3RfZXBzaWxvbmANCg0KIyMgU3RhdGUgYW5hbHlzaXMgLSBtZXRob2QgMQ0KRXN0aW1hdGUgJGNvcnIoXERlbHRhIHlfdCAsIFxEZWx0YSB5X3t0LTF9ICkkIGF0IHN0YXRlIGxldmVsIGJ5IGF2ZXJhZ2UgYXV0b2NvcnJlbGF0aW9uIG9mIHN0YXRlIGRlbHRhcy4NCg0KYGBge3J9DQojIENyZWF0ZSB2YXJpYWJsZSBmb3IgeWVhciBvbiB5ZWFyIGNoYW5nZSBmb3IgZWFjaCBkaXN0cmljdA0Kc3RhdGVfZGVsdGFzIDwtIHN0YXRlcyAlPiUgDQogIGdyb3VwX2J5KFN0YXRlKSAlPiUgDQogIG11dGF0ZShkZWx0YV9yZWFkaW5nID0gc3RkM19yZWFkaW5nIC0gbGFnKHN0ZDNfcmVhZGluZywgb3JkZXJfYnkgPSB5ZWFyKSwgZGVsdGFfbWF0aCA9IHN0ZDNfbWF0aCAtIGxhZyhzdGQzX21hdGgsIG9yZGVyX2J5ID0geWVhcikpICU+JQ0KICBtdXRhdGUoZGVsdGFfcmVhZGluZ19sYWdnZWQgPSBsYWcoZGVsdGFfcmVhZGluZywgb3JkZXJfYnkgPSB5ZWFyKSwgZGVsdGFfcmVhZGluZ19kYmxfbGFnID0gbGFnKGRlbHRhX3JlYWRpbmcsbj0yLCBvcmRlcl9ieSA9IHllYXIpKSAlPiUNCiAgYXJyYW5nZShTdGF0ZSwgeWVhcikNCg0KDQojIENhbGN1bGF0ZSBhdmVyYWdlIGF1dG9jb3JyZWxhdGlvbiBvZiBkZWx0YV9yZWFkaW5nDQpjb3JyX3N0YXRlX2RlbHRhcyA8LSBzdGF0ZV9kZWx0YXMgJT4lIA0KICBmaWx0ZXIoeWVhciA+PSAyMDA4KSAlPiUgDQogIHN1bW1hcmlzZShhdXRvID0gY29yKGRlbHRhX3JlYWRpbmcsIGRlbHRhX3JlYWRpbmdfbGFnZ2VkLCB1c2UgPSAicGFpcndpc2UuY29tcGxldGUub2JzIikpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIHN1bW1hcmlzZShtZWFuX2F1dG89bWVhbihhdXRvKSkgJT4lIC4kbWVhbl9hdXRvDQoNCiMgQ2FsY3VsYXRlIGNvcnJlbGF0aW9uIGJldHdlbiBkZWx0YSBsZXR0ZXJzIGFuZCBkZWx0YSBsZXR0ZXJzIGxhZ2dlZCBmb3IgZW50aXJlIGRhdGFzZXQgKHdpdGhvdXQgZmlyc3QgY2FsY3VsYXRpbmcgZm9yIGVhY2ggc3RhdGUgYW5kIHRoZW4gYXZlcmFnaW5nKS4NCiMgdGhpcyBzaG91bGQgYmUgYWJvdXQgdGhlIHNhbWUgYXMgd2hlbiB3ZSBmaXJzdCBjYWxjdWxhdGUgZm9yIGVhY2ggc3RhdGUgYW5kIHRoZW4gYXZlcmFnZSAtLT4gd2hpY2ggaXQgaXMuDQpjaGVja19jb3JyX3N0YXRlX2RlbHRhcyA8LSBzdGF0ZV9kZWx0YXMgJT4lIGZpbHRlcih5ZWFyID49IDIwMDgpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIHN1bW1hcml6ZShhdXRvID1jb3IoZGVsdGFfcmVhZGluZyxkZWx0YV9yZWFkaW5nX2xhZ2dlZCwgdXNlID0gInBhaXJ3aXNlLmNvbXBsZXRlLm9icyIpKSAlPiUNCiAgLiRhdXRvDQoNCg0KIyBjYWxjdWxhdGUgdGhlIHZhcmlhbmNlIG9mIHRoZSBkZWx0YXMNCnZhcl9zdGF0ZV9kZWx0YXMgPC0gdmFyKHN0YXRlX2RlbHRhcyRkZWx0YV9yZWFkaW5nLzEwMCwgbmEucm0gPSBUUlVFKQ0KDQojIGNhbGN1bGF0ZSB0aGUgdmFyaWFuY2Ugb2YgdGhlIGxldmVscw0KdmFyX3N0YXRlX2xldmVscyA8LSB2YXIoc3RhdGVfZGVsdGFzJHN0ZDNfcmVhZGluZy8xMDAsIG5hLnJtID0gVFJVRSkNCg0KIyBjYWxjdWxhdGUgdmFyaWFuY2Ugb2YgdHJhbnNpdG9yeSBjb21wb25lbnQNCnZhcl9zdGF0ZV9lcHNpbG9uIDwtIC1jb3JyX3N0YXRlX2RlbHRhcyp2YXJfc3RhdGVfZGVsdGFzDQoNCmBgYA0KDQpDYWxjdWxhdGUgYXZlcmFnZSBzYW1wbGluZyB2YXJpYW5jZS4gTm90ZSB0aGF0IHNpbmNlIHdlIGFyZSBqdXN0IGNhbGN1bGF0aW5nIHRoZSBvdmVyYWxsIGF2ZXJhZ2UsIEkgZG9uJ3QgaGF2ZSB0byBtZXJnZSBvbiBzdGF0ZSBuYW1lcy4NCmBgYHtyfQ0KdmFyX3N0YXRlX3NhbXBsaW5nIDwtIGRpc3RzICU+JSBmaWx0ZXIoeWVhciA9PTIwMDgpICU+JQ0KICBjb3VudChTdGF0ZSkgJT4lDQogIG11dGF0ZShzYW1wbGluZ192YXIgPSB2YXJfZGlzdF9zYW1wbGluZy9uKSAlPiUNCiAgc3VtbWFyaXplKG1lYW5fc2FtcGxpbmcgPSBtZWFuKHNhbXBsaW5nX3ZhcikpICU+JSAuJG1lYW5fc2FtcGxpbmcNCg0KICANCmBgYA0KDQpjaGVjayB0aGF0IHRoZXJlIGlzIG5vIGNvcnJlbGF0aW9uIHdpdGggZG91YmxlIGxhZ3MNCmBgYHtyfQ0KIyBDaGVjayB0aGF0IGNoYW5nZXMgaW4gbGV0dGVycyBhbmQgbnVtYmVycyBpcyBjb3JyZWxhdGVkIC0tIHRoZXkgYXJlIGhpZ2hseSBjb3JyZWxhdGVkDQpzdGF0ZV9kZWx0YXMgJT4lIGZpbHRlcih5ZWFyID49IDIwMDgpICU+JSB1bmdyb3VwKCkgJT4lDQogIHN1bW1hcml6ZShjb3IoZGVsdGFfcmVhZGluZyxkZWx0YV9tYXRoLCB1c2UgPSAicGFpcndpc2UuY29tcGxldGUub2JzIikpDQoNCg0KY29ycl9zdGF0ZV9kYmxfbGFnIDwtIHN0YXRlX2RlbHRhcyAlPiUgZmlsdGVyKHllYXIgPj0gMjAwOSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgc3VtbWFyaXplKGF1dG8gPWNvcihkZWx0YV9yZWFkaW5nLGRlbHRhX3JlYWRpbmdfZGJsX2xhZywgdXNlID0gInBhaXJ3aXNlLmNvbXBsZXRlLm9icyIpKSAlPiUNCiAgLiRhdXRvDQoNCg0KdGVtcCA8LSBzdGF0ZV9kZWx0YXMgJT4lIGZpbHRlcih5ZWFyID49IDIwMDkpICU+JQ0KICBncm91cF9ieShTdGF0ZSkgJT4lDQogIHN1bW1hcml6ZShhdXRvID1jb3IoZGVsdGFfcmVhZGluZyxkZWx0YV9yZWFkaW5nX2RibF9sYWcsIHVzZSA9ICJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiKSkNCg0KDQpgYGANCg0KIyMjIENvbnNvbGlkYXRlZCBzdGF0ZSBsZXZlbCByZXN1bHRzIC0gbWV0aG9kIDENClNpbmNlIHRoZSBjb3JyZWxhdGlvbiBvZiBjdXJyZW50IGxldmVscyBhbmQgdHdpY2UgbGFncyBpcyBub3QgMCwgd2UgZG9uJ3QgdXNlIHRoZXNlIHZhbHVlcywgYnV0IGNvbnNvbGlkYXRpbmcgdGhlbSBoZXJlIGZvciByZWZlcmVuY2U6DQoNCiogJGNvcnIoXERlbHRhIHlfdCAsIFxEZWx0YSB5X3t0LTF9ICkgPSBgciBjb3JyX3N0YXRlX2RlbHRhc2AkDQoqICRWYXIoXERlbHRhIHlfdCApPSBgciB2YXJfc3RhdGVfZGVsdGFzYCQNCiogJFxzaWdtYV4yX3tcdmFyZXBzaWxvbn0gPSAtY29ycihcRGVsdGEgeV90ICwgXERlbHRhIHlfe3QtMX0gKSogVmFyKFxEZWx0YSB5X3QgKSA9IGByIHZhcl9zdGF0ZV9lcHNpbG9uYCQNCiogJFxzaWdtYV4yX3kgPSBgciB2YXJfc3RhdGVfbGV2ZWxzYCQgDQoqICRcc2lnbWFeMl97c2FtcGxpbmd9ID0gYHIgdmFyX3N0YXRlX3NhbXBsaW5nYCQNCg0KIyMgU3RhdGUgYW5hbHlzaXMgLSBtZXRob2QgMg0KDQpDYWxjdWxhdGUgdGhlIHNoYXJlIG9mIHZhcmlhbmNlIGR1ZSB0byBwZXJzaXN0ZW50IGVmZmVjdHMgYnkgbG9vayBhdCBob3cgY29ycmVsYXRpb24gaW4gbGV2ZWxzIGRlY2F5cyBvdmVyIHRpbWUuDQoNCmBgYHtyfQ0Kc3RhdGVfbGFncyA8LSBzdGF0ZXMgJT4lDQogIGdyb3VwX2J5KFN0YXRlKSAlPiUNCiAgbXV0YXRlKHJlYWRfbGFnMSA9IGxhZyhzdGQzX3JlYWRpbmcsIG9yZGVyX2J5ID0geWVhciksDQogICAgICAgICByZWFkX2xhZzIgPSBsYWcoc3RkM19yZWFkaW5nLCBuPSAyLCBvcmRlcl9ieSA9IHllYXIpLA0KICAgICAgICAgcmVhZF9sYWczID0gbGFnKHN0ZDNfcmVhZGluZywgbiA9Mywgb3JkZXJfYnkgPSB5ZWFyKSwNCiAgICAgICAgIHJlYWRfbGFnNCA9IGxhZyhzdGQzX3JlYWRpbmcsIG4gPTQsIG9yZGVyX2J5ID0geWVhciksDQogICAgICAgICByZWFkX2xhZzUgPSBsYWcoc3RkM19yZWFkaW5nLCBuID01LCBvcmRlcl9ieSA9IHllYXIpKSAlPiUNCiAgdW5ncm91cCgpDQoNCnJobyA9IGMoKQ0KIyBmb3IgZWFjaCBvZiB0aGUgbGFncywgY2FsY3VsYXRlIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIGN1cnJlbnQgYW5kIHRoZSBsYWcgYW5kIHN0b3JlIGluIHZlY3RvciByaG8NCmZvciAobGFnIGluIHNlcSgxLDUpKSB7DQogIHJobyA8LSBjKHJobywgY29yKHN0YXRlX2xhZ3Mkc3RkM19yZWFkaW5nLCBzdGF0ZV9sYWdzW1twYXN0ZSgicmVhZF9sYWciLGFzLmNoYXJhY3RlcihsYWcpLHNlcD0iIildXSwgdXNlID0gInBhaXJ3aXNlLmNvbXBsZXRlLm9icyIpKQ0KfQ0KIyBDYWxjdWxhdGUgdmFyaWFuY2Ugb2YgdGhlIHRyYW5zaXRvcnkgY29tcG9uZW50IGJ5IGNvbXBhcmluZyByaG9fMSB3aXRoIHRoZSBkZWNheSBvZiByaG8gYWZ0ZXIgdGhhdA0KdmFyX3N0YXRlX2xldmVsc19wZXJzaXN0ZW50MiA8LSByaG9bMV0vbWVhbihyaG8vbGFnKHJobyksIG5hLnJtID0gVFJVRSkqdmFyX3N0YXRlX2xldmVscw0KDQojIENhbGN1bGF0ZSB0aGUgc2hhcmUgb2YgdmFyaWFuY2UgY29taW5nIGZyb20gb3RoZXIgdHJhbnNpdG9yeSBzb3VyY2VzLg0KIyBXZSB3aWxsIG5lZWQgdGhpcyB0byBjYWxjdWxhdGUgdGhlIHZhcmlhbmNlIGJyZWFrdXAgZm9yIGNoYW5nZXMNCnZhcl9zdGF0ZV9sZXZlbHNfb3RoZXIyIDwtIHZhcl9zdGF0ZV9sZXZlbHMgLSB2YXJfc3RhdGVfbGV2ZWxzX3BlcnNpc3RlbnQyIC0gdmFyX3N0YXRlX3NhbXBsaW5nDQoNCiMgU2F2ZSBhIGdyYXBoIHNob3dpbmcgdGhlIGRlY2F5IG9mIHRoZSBjb3JyZWxhdGlvbg0KcXVpY2tfZGYgPC0gdGliYmxlKGxhZyA9IHNlcSgwLDUpLCBjb3JyZWxhdGlvbiA9IGMoMSxyaG8pKQ0KZ2dwbG90KHF1aWNrX2RmLCBhZXMoeD0gbGFnLCB5ID0gY29ycmVsYXRpb24pKSArIA0KICBnZW9tX2xpbmUoKSArDQogIGdlb21fcG9pbnQoKSArDQogIHlsaW0oMCwxKQ0KDQpnZ3NhdmUocGFzdGUoc3ViamVjdCwgIi0gY29ycmVsYXRpb25fZGVjYXkucG5nIiksIHdpZHRoID0gNSwgaGVpZ2h0ID0gNiAsIHBhdGggPSBvdXRwdXQpDQpgYGANCg0KIyMjIENvbnNvbGlkYXRlZCBzdGF0ZSBsZXZlbCByZXN1bHRzIC0gbWV0aG9kIDINCldpdGggbWV0aG9kIDIsIHdlIGhhdmUgdGhlIHNhbWUgdmFsdWVzIGZvciAqICRWYXIoXERlbHRhIHlfdCApJCwkXHNpZ21hXjJfeSQsIGFuZCAkXHNpZ21hXjJfe3NhbXBsaW5nfSQuDQoNCkluc3RlYWQgb2YgY2FsY3VsYXRpbmcgJFxzaWdtYV4yX3tcdmFyZXBzaWxvbn0kLCB3ZSBjYWxjdWxhdGUuLi4NCg0KKiAkXHNpZ21hXjJfe3BlcnN9ID0gYHIgdmFyX3N0YXRlX2xldmVsc19wZXJzaXN0ZW50MmAkDQoNCkFuZCB0aGVuIHVzZSB0aGVzZSB2YWx1ZXMgdG8gY2FsY3VsYXRlLi4uDQoNCiogU2hhcmUgb2YgdmFyaWFuY2UgaW4gKipsZXZlbHMqKiBkdWUgdG8gdHJhbnNpdG9yeSBzaG9ja3MgPSBgciAxLSh2YXJfc3RhdGVfbGV2ZWxzX3BlcnNpc3RlbnQyKS92YXJfc3RhdGVfbGV2ZWxzYA0KKiBTaGFyZSBvZiB2YXJpYW5jZSBpbiAqKmNoYW5nZXMqKiBkdWUgdG8gdHJhbnNpdG9yeSBzaG9ja3MgPSBgciAyKih2YXJfc3RhdGVfc2FtcGxpbmcrdmFyX3N0YXRlX2xldmVsc19vdGhlcjIpL3Zhcl9zdGF0ZV9kZWx0YXNgDQoqIFNoYXJlIG9mIHRoZSB0cmFuc2l0b3J5IHZhcmlhbmNlIGR1ZSB0byBzYW1wbGluZyAoZm9yIGJvdGggY2hhbmdlcyBhbmQgbGV2ZWxzKSA9IGByIHZhcl9zdGF0ZV9zYW1wbGluZy8odmFyX3N0YXRlX2xldmVscy12YXJfc3RhdGVfbGV2ZWxzX3BlcnNpc3RlbnQyKWANCg0KDQojIyMgQ3JlYXRlIGJhciBwbG90IG9mIHJlc3VsdHMNCldlIG5vdyBoYXZlIGFsbCB0aGUgaW5wdXRzIHdlIG5lZWQgdG8gcmVwbGljYXRlIGZpZ3VyZSA0IGZyb20gS2FuZSBhbmQgU3RhaWdlcg0KYGBge3J9DQojIENyZWF0ZSBlbXB0eSB0aWJibGUgdG8gc3RvcmUgcmVzdWx0cw0KIyBJIA0KZGZfYmFyIDwtIHRpYmJsZShzdGF0ZV9vcl9kaXN0ID0gcmVwKGMoIlN0YXRlIiwiRGlzdHJpY3QiKSxlYWNoID02KSwgDQogICAgICAgICAgICAgICAgIGNoYW5nZXNfb3JfbGV2ZWxzID1yZXAocmVwKGMoIkNoYW5nZXMiLCJMZXZlbHMiKSwgZWFjaCA9MyksIHRpbWVzPSAyKSwNCiAgICAgICAgICAgICAgICAgYmFyX3BhcnQgPSBmYWN0b3IocmVwKGMoIlBlcnNpc3RlbnQiLCJUcmFuc2l0b3J5IHNhbXBsaW5nIiwgIlRyYW5zaXRvcnkgb3RoZXIiKSw0KSwgbGV2ZWxzID0gYygiVHJhbnNpdG9yeSBvdGhlciIsIlRyYW5zaXRvcnkgc2FtcGxpbmciLCAiUGVyc2lzdGVudCIpKSwNCiAgICAgICAgICAgICAgICAgdmFsdWUgPSByZXAoLjAwMSwxMikNCiAgICAgICAgICAgICAgICAgKQ0KIyBVcGRhdGUgdGhlIHZhbHVlcyBmb3IgdGhlIGRpc3RyaWN0IGNoYW5nZXMgYmFyDQpkZl9iYXIkdmFsdWVbKGRmX2JhciRzdGF0ZV9vcl9kaXN0ID09ICJEaXN0cmljdCIpICYgKGRmX2JhciRjaGFuZ2VzX29yX2xldmVscyA9PSAiQ2hhbmdlcyIpICYgKGRmX2JhciRiYXJfcGFydCA9PSAiUGVyc2lzdGVudCIpXSA8LSB2YXJfZGlzdF9kZWx0YXMgLSAyKnZhcl9kaXN0X2Vwc2lsb24NCg0KZGZfYmFyJHZhbHVlWyhkZl9iYXIkc3RhdGVfb3JfZGlzdCA9PSAiRGlzdHJpY3QiKSAmIChkZl9iYXIkY2hhbmdlc19vcl9sZXZlbHMgPT0gIkNoYW5nZXMiKSAmIChkZl9iYXIkYmFyX3BhcnQgPT0gIlRyYW5zaXRvcnkgc2FtcGxpbmciKV0gPC0gMip2YXJfZGlzdF9zYW1wbGluZw0KDQpkZl9iYXIkdmFsdWVbKGRmX2JhciRzdGF0ZV9vcl9kaXN0ID09ICJEaXN0cmljdCIpICYgKGRmX2JhciRjaGFuZ2VzX29yX2xldmVscyA9PSAiQ2hhbmdlcyIpICYgKGRmX2JhciRiYXJfcGFydCA9PSAiVHJhbnNpdG9yeSBvdGhlciIpXSA8LSAyKnZhcl9kaXN0X2Vwc2lsb24gLSAyKnZhcl9kaXN0X3NhbXBsaW5nDQoNCg0KIyBVcGRhdGUgdGhlIHZhbHVlcyBmb3IgdGhlIGRpc3RyaWN0IGxldmVscyBiYXINCmRmX2JhciR2YWx1ZVsoZGZfYmFyJHN0YXRlX29yX2Rpc3QgPT0gIkRpc3RyaWN0IikgJiAoZGZfYmFyJGNoYW5nZXNfb3JfbGV2ZWxzID09ICJMZXZlbHMiKSAmIChkZl9iYXIkYmFyX3BhcnQgPT0gIlBlcnNpc3RlbnQiKV0gPC0gdmFyX2Rpc3RfbGV2ZWxzIC0gdmFyX2Rpc3RfZXBzaWxvbg0KDQpkZl9iYXIkdmFsdWVbKGRmX2JhciRzdGF0ZV9vcl9kaXN0ID09ICJEaXN0cmljdCIpICYgKGRmX2JhciRjaGFuZ2VzX29yX2xldmVscyA9PSAiTGV2ZWxzIikgJiAoZGZfYmFyJGJhcl9wYXJ0ID09ICJUcmFuc2l0b3J5IHNhbXBsaW5nIildIDwtIHZhcl9kaXN0X3NhbXBsaW5nDQoNCmRmX2JhciR2YWx1ZVsoZGZfYmFyJHN0YXRlX29yX2Rpc3QgPT0gIkRpc3RyaWN0IikgJiAoZGZfYmFyJGNoYW5nZXNfb3JfbGV2ZWxzID09ICJMZXZlbHMiKSAmIChkZl9iYXIkYmFyX3BhcnQgPT0gIlRyYW5zaXRvcnkgb3RoZXIiKV0gPC0gdmFyX2Rpc3RfZXBzaWxvbiAtIHZhcl9kaXN0X3NhbXBsaW5nDQoNCiMjIyMjIFNUQVRFIERBVEEgIyMjIyMNCg0KIyBDSEFOR0VTDQpkZl9iYXIkdmFsdWVbKGRmX2JhciRzdGF0ZV9vcl9kaXN0ID09ICJTdGF0ZSIpICYgKGRmX2JhciRjaGFuZ2VzX29yX2xldmVscyA9PSAiQ2hhbmdlcyIpICYgKGRmX2JhciRiYXJfcGFydCA9PSAiUGVyc2lzdGVudCIpXSA8LSB2YXJfc3RhdGVfZGVsdGFzLTIqKHZhcl9zdGF0ZV9zYW1wbGluZyt2YXJfc3RhdGVfbGV2ZWxzX290aGVyMikNCg0KZGZfYmFyJHZhbHVlWyhkZl9iYXIkc3RhdGVfb3JfZGlzdCA9PSAiU3RhdGUiKSAmIChkZl9iYXIkY2hhbmdlc19vcl9sZXZlbHMgPT0gIkNoYW5nZXMiKSAmIChkZl9iYXIkYmFyX3BhcnQgPT0gIlRyYW5zaXRvcnkgc2FtcGxpbmciKV0gPC0gMip2YXJfc3RhdGVfc2FtcGxpbmcNCg0KZGZfYmFyJHZhbHVlWyhkZl9iYXIkc3RhdGVfb3JfZGlzdCA9PSAiU3RhdGUiKSAmIChkZl9iYXIkY2hhbmdlc19vcl9sZXZlbHMgPT0gIkNoYW5nZXMiKSAmIChkZl9iYXIkYmFyX3BhcnQgPT0gIlRyYW5zaXRvcnkgb3RoZXIiKV0gPC0gMip2YXJfc3RhdGVfbGV2ZWxzX290aGVyMg0KDQoNCiMgTEVWRUxTDQpkZl9iYXIkdmFsdWVbKGRmX2JhciRzdGF0ZV9vcl9kaXN0ID09ICJTdGF0ZSIpICYgKGRmX2JhciRjaGFuZ2VzX29yX2xldmVscyA9PSAiTGV2ZWxzIikgJiAoZGZfYmFyJGJhcl9wYXJ0ID09ICJQZXJzaXN0ZW50IildIDwtIHZhcl9zdGF0ZV9sZXZlbHNfcGVyc2lzdGVudDINCg0KZGZfYmFyJHZhbHVlWyhkZl9iYXIkc3RhdGVfb3JfZGlzdCA9PSAiU3RhdGUiKSAmIChkZl9iYXIkY2hhbmdlc19vcl9sZXZlbHMgPT0gIkxldmVscyIpICYgKGRmX2JhciRiYXJfcGFydCA9PSAiVHJhbnNpdG9yeSBzYW1wbGluZyIpXSA8LSB2YXJfc3RhdGVfc2FtcGxpbmcNCg0KZGZfYmFyJHZhbHVlWyhkZl9iYXIkc3RhdGVfb3JfZGlzdCA9PSAiU3RhdGUiKSAmIChkZl9iYXIkY2hhbmdlc19vcl9sZXZlbHMgPT0gIkxldmVscyIpICYgKGRmX2JhciRiYXJfcGFydCA9PSAiVHJhbnNpdG9yeSBvdGhlciIpXSA8LSB2YXJfc3RhdGVfbGV2ZWxzX290aGVyMg0KDQoNCiMgSSBoYXZlIGNyZWF0ZWQgdGhpcyBncmFwaCBzbyB0aGF0IHlvdSBjYW4gc2VlIGl0IGluIHRoZSBub3RlYm9vaw0KIyBUaGUgZmluYWwgdmVyc2lvbiB3aGljaCBjb21iaW5lcyBib3RoIHN1YmplY3RzLCBpcyBjcmVhdGVkIGluIGEgc2VwYXJhdGUgbm90ZWJvb2sNCmdncGxvdChkZl9iYXIsIGFlcyhmaWxsID0gYmFyX3BhcnQsIHk9dmFsdWUsIHg9IGNoYW5nZXNfb3JfbGV2ZWxzKSkgKw0KICBnZW9tX2Jhcihwb3NpdGlvbj0ic3RhY2siLCBzdGF0ID0iaWRlbnRpdHkiKSArDQogIGZhY2V0X2dyaWQofiBzdGF0ZV9vcl9kaXN0KSArIA0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJyZWQiLCAib3JhbmdlIiwgImJsdWUiKSkrDQogIGxhYnMoZmlsbCA9ICJWYXJpYW5jZSBjb21wb25lbnQiLCB4ID0gIiIpDQoNCmdnc2F2ZShwYXN0ZShzdWJqZWN0LCIgLSB2YXJpYW5jZV9kZWNvbXBvc2l0aW9uLnBuZyIpLCB3aWR0aCA9IDUsIGhlaWdodCA9IDYgLCBwYXRoID0gb3V0cHV0KQ0KDQp3cml0ZV9jc3YoZGZfYmFyLCBmaWxlLnBhdGgob3V0cHV0LCBwYXN0ZShzdWJqZWN0LCAiLSBiYXIgZGF0YS5jc3YiKSkpDQpgYGANCg0KIyMjIENyZWF0ZSBkYXRhZnJhbWUgd2l0aCByZXN1bHRzDQpUYWtlIHRoZSBvdXRwdXQgdGhhdCB3YXMgdXNlZCB0byBjcmVhdGUgdGhlIGJhciBncmFwaCwgcmVzaGFwZSBpdCwgYW5kIHNhdmUgaXQgYXMgYSBjc3YNCg0KYGBge3J9DQpkZl9maW5hbCA8LSBkZl9iYXIgJT4lDQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSAiYmFyX3BhcnQiLCB2YWx1ZXNfZnJvbT0gInZhbHVlIikgJT4lDQogIG11dGF0ZSh0b3RhbF92YXIgPSBgUGVyc2lzdGVudGArYFRyYW5zaXRvcnkgc2FtcGxpbmdgK2BUcmFuc2l0b3J5IG90aGVyYCkgJT4lDQogIG11dGF0ZShzaGFyZV9wZXJzID0gYFBlcnNpc3RlbnRgL3RvdGFsX3Zhciwgc2hhcmVfc2FtcCA9IGBUcmFuc2l0b3J5IHNhbXBsaW5nYC90b3RhbF92YXIsIHNoYXJlX290aGVyID0gYFRyYW5zaXRvcnkgb3RoZXJgL3RvdGFsX3ZhcikNCg0Kd3JpdGVfY3N2KGRmX2ZpbmFsLCBmaWxlLnBhdGgob3V0cHV0LCBwYXN0ZShzdWJqZWN0LCAiLSB2YXIgZGVjby5jc3YiKSkpDQpgYGANCg0KDQoNCg0KDQoNCg0KDQoNCg==