“Effect or Treatment Heterogeneity? Policy Evaluation with Aggregated and Disaggregated Treatments”

Phillip Heiler and Michael C. Knaus

Scenario 2: Job Corps

This Notebook replicates the results of Section 8.2 using the publicly available data that can be downloaded here. The notebook should help to …

  • show the underlying code for researchers interested in replicating the analysis or in adapting it to new datasets

  • show that we get similar results if we only use random forests instead of the ensemble method

The explanations throughout the notebook are kept short. Please see the paper for more details regarding the decomposition parameters and their estimation.

Click on the “Code” button on the top right of this notebook to “Hide All Code” and see only the results or “Download Rmd” to extract the underlying code.

Running the analyses in this notebook took roughly two hours on a SWITCHengine with eight cores and 32 GB RAM. Running it with the full emsemble took three days. To replicate the ensemble uncomment the lines 172 to 175 in the .RmD file.



Data preparation

Download the impact.sas7bdat, baseline.sas7bdat, key_vars.sas7bdat, and mileston.sas7bdat files from OPENICPSR and save them in the same folder as the notebook.

# Load required libraries
library(causalDML)
library(sas7bdat)
library(tidyverse)

# Set seed
seed = 1234
set.seed(seed)

Now prepare outcome, effective treatment, and confounders as well as the heterogeneity variable gender:

# Download dataset from https://www.openicpsr.org/openicpsr/project/113269/version/V1/view
# into working directory and load the raw data (takes some time)
impact_raw = read.sas7bdat("impact.sas7bdat")
baseline_raw = read.sas7bdat("baseline.sas7bdat")
key_vars_raw = read.sas7bdat("key_vars.sas7bdat")
mileston_raw = read.sas7bdat("mileston.sas7bdat")

# Extract the relevant variables
impact = select(impact_raw,MPRID,EARNY4,EVERJCH)
impact_temp = select(impact_raw,MPRID,JCVCLERC,JCVHLTH,JCVAUTO,JCVWELD,JCVELTRC,JCVCSTRC,JCVFOOD,JCVETRNC,JCVOTH)
baseline = select(baseline_raw,MPRID,RACE_ETH,HS_D,GED_D,VOC_D,ANY_ED1,HGC,NTV_LANG,WKEARNR,
                  HASCHLD,MARRIAGE,R_HEAD,HHMEMB,HEALTH,PY_CIG,PY_ALCHL,
                  PY_POT,HADWORRY,HEAR_JC,KNEWCNTR,E_MATH,E_READ,E_ALONG,
                  E_CONTRL,E_ESTEEM,E_SPCJOB,E_FRIEND,KNEW_JC,EARN_YR)
key_vars = select(key_vars_raw,MPRID,TREATMNT,FEMALE,AGE_CAT,EDUC_GR,NONRES)
mileston = select(mileston_raw,MPRID,LIVESPOU,EVERWORK,YR_WORK,CURRJOB,
                   JOB0_3, JOB3_9, JOB9_12, MOSTWELF,GOT_AFDC,GOT_FS,ED0_6,ED6_12,
                   PUBLICH,BADHLTH,HARDUSE,POTUSE,EVARRST,PMSA,MSA,PRARRI)

# Code the versions
versions = rep("Nothing",nrow(impact))
versions[impact_temp[,2] == 1] = "Clerical"
versions[impact_temp[,3] == 1] = "Health"
versions[impact_temp[,4] == 1] = "Auto"
versions[impact_temp[,5] == 1] = "Welding"
versions[impact_temp[,6] == 1 | impact_temp[,9] == 1] = "Electrical"
versions[impact_temp[,7] == 1] = "Construction"
versions[impact_temp[,8] == 1] = "Food"
versions[impact_temp[,10] == 1] = "Other"
versions[rowSums(impact_temp[,2:10],na.rm=T) > 1] = "Multiple"
impact = cbind(impact,versions)

# Merge the data
inner_join(impact,baseline,by="MPRID") %>% inner_join(key_vars,by="MPRID")  %>% inner_join(mileston,by="MPRID") %>%
  mutate(RACE_W = as.numeric(RACE_ETH == 1)) %>%  mutate(RACE_B = as.numeric(RACE_ETH == 2)) %>%
  mutate(RACE_H = as.numeric(RACE_ETH == 3)) %>%  mutate(RACE_O = as.numeric(RACE_ETH == 4)) %>% 
  mutate(WKEARNR = replace(WKEARNR,is.na(WKEARNR),0)) %>%
  mutate(EARN_YR = replace(EARN_YR,is.na(EARN_YR),0)) -> db

# Remove observations with missing values
db %>% na.omit() -> db

# Create main variables
Y = as.matrix(select(db,EARNY4))
D = as.matrix(select(db,TREATMNT))
# Heterogeneity variable
female = select(db,FEMALE)
fem_mat = cbind(1-female,female)
label_fem = c("Male","Female")
colnames(fem_mat) = label_fem

# Create versions
JC = db$EVERJCH
T = rep(NA,length(Y))
T[D == 0] = "Control"
T[D == 1 & JC == 0] = "No JC"
T[D == 1 & JC == 1 & db$versions == "Clerical"] = "Clerical"
T[D == 1 & JC == 1 & db$versions == "Health"] = "Health"
T[D == 1 & JC == 1 & db$versions == "Auto"] = "Auto"
T[D == 1 & JC == 1 & db$versions == "Welding"] = "Welding"
T[D == 1 & JC == 1 & db$versions == "Electrical"] = "Electrical"
T[D == 1 & JC == 1 & db$versions == "Construction"] = "Construction"
T[D == 1 & JC == 1 & db$versions == "Food"] = "Food"
T[D == 1 & JC == 1 & db$versions == "Other"] = "Other"
T[D == 1 & JC == 1 & db$versions == "Multiple"] = "Multiple"
T[is.na(T)] = "JC without voc"
label_T = c("Control","No JC","JC without voc","Clerical","Health","Auto","Welding","Electrical",
            "Construction","Food","Other","Multiple")
T = factor(T,levels=label_T)

# Create control matrix
x_main = as.matrix(select(db,FEMALE,AGE_CAT,RACE_W,RACE_B,RACE_H,RACE_O,EDUC_GR,
                     LIVESPOU,EVERWORK,YR_WORK,CURRJOB,JOB0_3, JOB3_9, JOB9_12,
                     MOSTWELF,GOT_AFDC,GOT_FS,ED0_6,ED6_12,PUBLICH,BADHLTH,HARDUSE,POTUSE,EVARRST,PMSA,MSA,
                     HS_D,GED_D,VOC_D,ANY_ED1,HGC,NTV_LANG,WKEARNR,
                     HASCHLD,MARRIAGE,R_HEAD,HHMEMB,HEALTH,PY_CIG,PY_ALCHL,
                     PY_POT,HADWORRY,HEAR_JC,KNEWCNTR,E_MATH,E_READ,E_ALONG,
                     E_CONTRL,E_ESTEEM,E_SPCJOB,E_FRIEND,KNEW_JC,NONRES,PRARRI,EARN_YR))
X = design_matrix(x_main,int=colnames(x_main),int_d=2)
X = data_screen(X,print=F) 

# Boolean to extract main effects
main_effects = !grepl(":",colnames(X))



Decomposition

Double ML for the effective treatment

The implementation is based on the causalDML package that estimates the average potential outcomes and average treatment effects for the multivalued effective treatment. The nuisance parameters are estimated using an ensemble of methods, which first needs to be initialized.

## Initialize components to be used in the ensemble learner
# General component
mean = create_method("mean",name="Mean")
forest =  create_method("forest_grf",x_select = main_effects,name="Forest",
                        args=list(honesty = F,tune.parameters = "all",seed=seed))

# Pscore specific components
ridge_bin_low = create_method("ridge",x_select = main_effects,name="Ridge low",
                              args=list(family = "binomial",lambda.min.ratio=0.001))
lasso_bin_low = create_method("lasso",x_select = main_effects,name="Lasso low",
                              args=list(family = "binomial",lambda.min.ratio=0.01))
ridge_bin_high = create_method("ridge",name="Ridge high",
                               args=list(family = "binomial",lambda.min.ratio=0.01))
lasso_bin_high = create_method("lasso",name="Lasso high",
                               args=list(family = "binomial",lambda.min.ratio=0.05))

# Outcome specific components
ridge_ls_low = create_method("ridge",x_select = main_effects,name="Ridge low",
                              args=list(lambda.min.ratio=0.0001))
lasso_ls_low = create_method("lasso",x_select = main_effects,name="Lasso low",
                              args=list(lambda.min.ratio=0.001))
ridge_ls_high = create_method("ridge",name="Ridge high",
                               args=list(lambda.min.ratio=0.05))
lasso_ls_high = create_method("lasso",name="Lasso high",
                               args=list(lambda.min.ratio=0.05))

# Run multiple treatment model to get scores
ate = causalDML(Y,T,X,
                 ml_w=list(forest),
                 ml_y=list(forest),quiet=F)
# Uncomment this to replicate the results with ensemble of methods
# ate = causalDML(Y,T,X,
#                  ml_w=list(mean,forest,ridge_bin_low,lasso_bin_low,
#                            ridge_bin_high,lasso_bin_high),
#                  ml_y=list(mean,forest,ridge_ls_low,lasso_ls_low,
#                            ridge_ls_high,lasso_ls_high))
# Show results for each effective treatment
plot(ate$APO)

summary(ate$APO)
                   APO        SE
Control       195.5294  2.935893
No JC         199.1164  5.213854
JC ithout voc 189.3148  6.003815
Clerical      232.9166 14.655847
Health        202.2124 12.753642
Auto          259.0107 22.461835
Welding       239.0742 17.897670
Electrical    241.7421 24.288266
Construction  236.5801 11.709246
Food          200.3551 11.762820
Other         216.3865  7.908796
Multiple      234.2120  8.767559



Decomposition

The decomposition reuses the nuisance parameters and doubly robust scores that are stored in the object created by the causalDML function.

Now we replicate the results of Figure 5 of the paper

## Decomposition for each subgroup
# Regression without constant
cat("Without constant:\n")
Without constant:
decomp_female_woc = HK_decomposition(ate$APO,fem_mat,intercept=FALSE)
summary(decomp_female_woc)
nATE:
t test of coefficients:

        Estimate Std. Error t value  Pr(>|t|)    
zMale    18.2468     5.3624  3.4028 0.0006698 ***
zFemale  10.6330     5.2989  2.0066 0.0448161 *  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

rATE:
t test of coefficients:

        Estimate Std. Error t value Pr(>|t|)   
zMale    18.9297     5.9604  3.1759 0.001498 **
zFemale  16.0903     5.6883  2.8287 0.004684 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Delta:
t test of coefficients:

        Estimate Std. Error t value Pr(>|t|)  
zMale   -0.68284    2.61117 -0.2615  0.79371  
zFemale -5.45726    2.17331 -2.5110  0.01205 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
# Regression with constant
cat("\n\nWith constant:\n")


With constant:
decomp_female_wc = HK_decomposition(ate$APO,female,intercept=TRUE)
summary(decomp_female_wc)
nATE:
t test of coefficients:

            Estimate Std. Error t value  Pr(>|t|)    
(Intercept)  18.2468     5.3624  3.4028 0.0006698 ***
z            -7.6138     7.5388 -1.0100 0.3125420    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

rATE:
t test of coefficients:

            Estimate Std. Error t value Pr(>|t|)   
(Intercept)  18.9297     5.9604  3.1759 0.001498 **
z            -2.8394     8.2391 -0.3446 0.730381   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Delta:
t test of coefficients:

            Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.68284    2.61117 -0.2615   0.7937
z           -4.77442    3.39728 -1.4054   0.1599

and the Figure itself:

# The following is probably the most complicated way to create the graph, but it works
# Extract coefficients
coef_fem = c(decomp_female_woc$nATE$results[1,1],
             decomp_female_woc$Delta$results[1,1],
             decomp_female_woc$rATE$results[1,1],
             decomp_female_woc$nATE$results[2,1],
             decomp_female_woc$Delta$results[2,1],
             decomp_female_woc$rATE$results[2,1],
             decomp_female_wc$nATE$results[2,1],
             decomp_female_wc$Delta$results[2,1],
             decomp_female_wc$rATE$results[2,1])

# Extract p-values
pv_fem = c(decomp_female_woc$nATE$results[1,4],
           decomp_female_woc$Delta$results[1,4],
           decomp_female_woc$rATE$results[1,4],
           decomp_female_woc$nATE$results[2,4],
           decomp_female_woc$Delta$results[2,4],
           decomp_female_woc$rATE$results[2,4],
           decomp_female_wc$nATE$results[2,4],
           decomp_female_wc$Delta$results[2,4],
           decomp_female_wc$rATE$results[2,4])

# Start and end points for waterfall graph
start0 = c(0,coef_fem[1],coef_fem[3])
end0 = c(coef_fem[1],coef_fem[3],0)
start1 = c(0,coef_fem[4],coef_fem[6])
end1 = c(coef_fem[4],coef_fem[6],0)
start2 = c(0,coef_fem[7],coef_fem[9])
end2 = c(coef_fem[7],coef_fem[9],0)

# Format results
coef_fem = format(coef_fem,digits=2)
pv_fem = paste0("(",format(pv_fem,digits=0,nsmall=3,scientific=F),")")

data.frame(id=c(1:3,1:3,1:3),
                   Estimand=factor(c("nATE","Delta","rATE","nATE","Delta","rATE","nATE","Delta","rATE"),levels = c("nATE","Delta","rATE")),
                   Gender = factor(c(rep("Male",3),rep("Female",3),rep("Difference Female - Male",3)),
                                   levels = c("Female","Male","Difference Female - Male")),
                   start= c(start0,start1,start2),
                   end=c(end0,end1,end2),
                   coef = coef_fem,
                   pvalue = pv_fem) %>%
  ggplot(aes(id, fill = Estimand,group=Gender)) +
    geom_rect(aes(xmin = id - 0.5, xmax = id + 0.5, ymin = end,ymax = start)) +
    scale_fill_brewer(palette="Dark2") + ylab("Effect") +
    scale_x_continuous(breaks=c(1,2,3),labels=c("nATE", expression(Delta),"rATE")) + 
    theme_bw() + geom_hline(yintercept = 0) +
    xlab("Estimand") + theme(legend.position="none") + 
    geom_text(aes(x = id, y = (start+end+1.25)/2, label = coef),size = 2.75) +
    geom_text(aes(x = id, y = (start+end-1.25)/2, label = pvalue),size = 2.75) +
    facet_wrap(~Gender)

LS0tDQp0aXRsZTogIlJlcGxpY2F0aW9uIE5vdGVib29rIg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOiBkZWZhdWx0DQotLS0NCg0KIyAiRWZmZWN0IG9yIFRyZWF0bWVudCBIZXRlcm9nZW5laXR5PyBQb2xpY3kgRXZhbHVhdGlvbiB3aXRoIEFnZ3JlZ2F0ZWQgYW5kIERpc2FnZ3JlZ2F0ZWQgVHJlYXRtZW50cyINCiMjIFBoaWxsaXAgSGVpbGVyIGFuZCBNaWNoYWVsIEMuIEtuYXVzDQoNCiMjIFNjZW5hcmlvIDI6IEpvYiBDb3Jwcw0KDQpUaGlzIE5vdGVib29rIHJlcGxpY2F0ZXMgdGhlIHJlc3VsdHMgb2YgU2VjdGlvbiA4LjIgdXNpbmcgdGhlIHB1YmxpY2x5IGF2YWlsYWJsZSBkYXRhIHRoYXQgY2FuIGJlIGRvd25sb2FkZWQgW2hlcmVdKGh0dHBzOi8vd3d3Lm9wZW5pY3Bzci5vcmcvb3BlbmljcHNyL3Byb2plY3QvMTEzMjY5L3ZlcnNpb24vVjEvdmlldykuIFRoZSBub3RlYm9vayBzaG91bGQgaGVscCB0byAuLi4NCg0KLSBzaG93IHRoZSB1bmRlcmx5aW5nIGNvZGUgZm9yIHJlc2VhcmNoZXJzIGludGVyZXN0ZWQgaW4gcmVwbGljYXRpbmcgdGhlIGFuYWx5c2lzIG9yIGluIGFkYXB0aW5nIGl0IHRvIG5ldyBkYXRhc2V0cw0KDQotIHNob3cgdGhhdCB3ZSBnZXQgc2ltaWxhciByZXN1bHRzIGlmIHdlIG9ubHkgdXNlIHJhbmRvbSBmb3Jlc3RzIGluc3RlYWQgb2YgdGhlIGVuc2VtYmxlIG1ldGhvZA0KDQpUaGUgZXhwbGFuYXRpb25zIHRocm91Z2hvdXQgdGhlIG5vdGVib29rIGFyZSBrZXB0IHNob3J0LiBQbGVhc2Ugc2VlIHRoZSBwYXBlciBmb3IgbW9yZSBkZXRhaWxzIHJlZ2FyZGluZyB0aGUgZGVjb21wb3NpdGlvbiBwYXJhbWV0ZXJzIGFuZCB0aGVpciBlc3RpbWF0aW9uLg0KDQpDbGljayBvbiB0aGUgIkNvZGUiIGJ1dHRvbiBvbiB0aGUgdG9wIHJpZ2h0IG9mIHRoaXMgbm90ZWJvb2sgdG8gIkhpZGUgQWxsIENvZGUiIGFuZCBzZWUgb25seSB0aGUgcmVzdWx0cyBvciAiRG93bmxvYWQgUm1kIiB0byBleHRyYWN0IHRoZSB1bmRlcmx5aW5nIGNvZGUuDQoNClJ1bm5pbmcgdGhlIGFuYWx5c2VzIGluIHRoaXMgbm90ZWJvb2sgdG9vayByb3VnaGx5IHR3byBob3VycyBvbiBhIFtTV0lUQ0hlbmdpbmVdKGh0dHBzOi8vd3d3LnN3aXRjaC5jaC9lbmdpbmVzLykgd2l0aCBlaWdodCBjb3JlcyBhbmQgMzIgR0IgUkFNLiBSdW5uaW5nIGl0IHdpdGggdGhlIGZ1bGwgZW1zZW1ibGUgdG9vayB0aHJlZSBkYXlzLiBUbyByZXBsaWNhdGUgdGhlIGVuc2VtYmxlIHVuY29tbWVudCB0aGUgbGluZXMgMTcyIHRvIDE3NSBpbiB0aGUgLlJtRCBmaWxlLg0KDQoNCjxicj4NCjxicj4NCg0KIyMgRGF0YSBwcmVwYXJhdGlvbg0KDQpEb3dubG9hZCB0aGUgKmltcGFjdC5zYXM3YmRhdCwgYmFzZWxpbmUuc2FzN2JkYXQsIGtleV92YXJzLnNhczdiZGF0LCBhbmQgbWlsZXN0b24uc2FzN2JkYXQqIGZpbGVzIGZyb20gW09QRU5JQ1BTUl0oaHR0cHM6Ly93d3cub3BlbmljcHNyLm9yZy9vcGVuaWNwc3IvcHJvamVjdC8xMTMyNjkvdmVyc2lvbi9WMS92aWV3KSBhbmQgc2F2ZSB0aGVtIGluIHRoZSBzYW1lIGZvbGRlciBhcyB0aGUgbm90ZWJvb2suDQoNCmBgYHtyfQ0KIyBMb2FkIHJlcXVpcmVkIGxpYnJhcmllcw0KbGlicmFyeShjYXVzYWxETUwpDQpsaWJyYXJ5KHNhczdiZGF0KQ0KbGlicmFyeSh0aWR5dmVyc2UpDQoNCiMgU2V0IHNlZWQNCnNlZWQgPSAxMjM0DQpzZXQuc2VlZChzZWVkKQ0KYGBgDQoNCk5vdyBwcmVwYXJlIG91dGNvbWUsIGVmZmVjdGl2ZSB0cmVhdG1lbnQsIGFuZCBjb25mb3VuZGVycyBhcyB3ZWxsIGFzIHRoZSBoZXRlcm9nZW5laXR5IHZhcmlhYmxlIGdlbmRlcjoNCg0KYGBge3J9DQojIERvd25sb2FkIGRhdGFzZXQgZnJvbSBodHRwczovL3d3dy5vcGVuaWNwc3Iub3JnL29wZW5pY3Bzci9wcm9qZWN0LzExMzI2OS92ZXJzaW9uL1YxL3ZpZXcNCiMgaW50byB3b3JraW5nIGRpcmVjdG9yeSBhbmQgbG9hZCB0aGUgcmF3IGRhdGEgKHRha2VzIHNvbWUgdGltZSkNCmltcGFjdF9yYXcgPSByZWFkLnNhczdiZGF0KCJpbXBhY3Quc2FzN2JkYXQiKQ0KYmFzZWxpbmVfcmF3ID0gcmVhZC5zYXM3YmRhdCgiYmFzZWxpbmUuc2FzN2JkYXQiKQ0Ka2V5X3ZhcnNfcmF3ID0gcmVhZC5zYXM3YmRhdCgia2V5X3ZhcnMuc2FzN2JkYXQiKQ0KbWlsZXN0b25fcmF3ID0gcmVhZC5zYXM3YmRhdCgibWlsZXN0b24uc2FzN2JkYXQiKQ0KDQojIEV4dHJhY3QgdGhlIHJlbGV2YW50IHZhcmlhYmxlcw0KaW1wYWN0ID0gc2VsZWN0KGltcGFjdF9yYXcsTVBSSUQsRUFSTlk0LEVWRVJKQ0gpDQppbXBhY3RfdGVtcCA9IHNlbGVjdChpbXBhY3RfcmF3LE1QUklELEpDVkNMRVJDLEpDVkhMVEgsSkNWQVVUTyxKQ1ZXRUxELEpDVkVMVFJDLEpDVkNTVFJDLEpDVkZPT0QsSkNWRVRSTkMsSkNWT1RIKQ0KYmFzZWxpbmUgPSBzZWxlY3QoYmFzZWxpbmVfcmF3LE1QUklELFJBQ0VfRVRILEhTX0QsR0VEX0QsVk9DX0QsQU5ZX0VEMSxIR0MsTlRWX0xBTkcsV0tFQVJOUiwNCiAgICAgICAgICAgICAgICAgIEhBU0NITEQsTUFSUklBR0UsUl9IRUFELEhITUVNQixIRUFMVEgsUFlfQ0lHLFBZX0FMQ0hMLA0KICAgICAgICAgICAgICAgICAgUFlfUE9ULEhBRFdPUlJZLEhFQVJfSkMsS05FV0NOVFIsRV9NQVRILEVfUkVBRCxFX0FMT05HLA0KICAgICAgICAgICAgICAgICAgRV9DT05UUkwsRV9FU1RFRU0sRV9TUENKT0IsRV9GUklFTkQsS05FV19KQyxFQVJOX1lSKQ0Ka2V5X3ZhcnMgPSBzZWxlY3Qoa2V5X3ZhcnNfcmF3LE1QUklELFRSRUFUTU5ULEZFTUFMRSxBR0VfQ0FULEVEVUNfR1IsTk9OUkVTKQ0KbWlsZXN0b24gPSBzZWxlY3QobWlsZXN0b25fcmF3LE1QUklELExJVkVTUE9VLEVWRVJXT1JLLFlSX1dPUkssQ1VSUkpPQiwNCiAgICAgICAgICAgICAgICAgICBKT0IwXzMsIEpPQjNfOSwgSk9COV8xMiwgTU9TVFdFTEYsR09UX0FGREMsR09UX0ZTLEVEMF82LEVENl8xMiwNCiAgICAgICAgICAgICAgICAgICBQVUJMSUNILEJBREhMVEgsSEFSRFVTRSxQT1RVU0UsRVZBUlJTVCxQTVNBLE1TQSxQUkFSUkkpDQoNCiMgQ29kZSB0aGUgdmVyc2lvbnMNCnZlcnNpb25zID0gcmVwKCJOb3RoaW5nIixucm93KGltcGFjdCkpDQp2ZXJzaW9uc1tpbXBhY3RfdGVtcFssMl0gPT0gMV0gPSAiQ2xlcmljYWwiDQp2ZXJzaW9uc1tpbXBhY3RfdGVtcFssM10gPT0gMV0gPSAiSGVhbHRoIg0KdmVyc2lvbnNbaW1wYWN0X3RlbXBbLDRdID09IDFdID0gIkF1dG8iDQp2ZXJzaW9uc1tpbXBhY3RfdGVtcFssNV0gPT0gMV0gPSAiV2VsZGluZyINCnZlcnNpb25zW2ltcGFjdF90ZW1wWyw2XSA9PSAxIHwgaW1wYWN0X3RlbXBbLDldID09IDFdID0gIkVsZWN0cmljYWwiDQp2ZXJzaW9uc1tpbXBhY3RfdGVtcFssN10gPT0gMV0gPSAiQ29uc3RydWN0aW9uIg0KdmVyc2lvbnNbaW1wYWN0X3RlbXBbLDhdID09IDFdID0gIkZvb2QiDQp2ZXJzaW9uc1tpbXBhY3RfdGVtcFssMTBdID09IDFdID0gIk90aGVyIg0KdmVyc2lvbnNbcm93U3VtcyhpbXBhY3RfdGVtcFssMjoxMF0sbmEucm09VCkgPiAxXSA9ICJNdWx0aXBsZSINCmltcGFjdCA9IGNiaW5kKGltcGFjdCx2ZXJzaW9ucykNCg0KIyBNZXJnZSB0aGUgZGF0YQ0KaW5uZXJfam9pbihpbXBhY3QsYmFzZWxpbmUsYnk9Ik1QUklEIikgJT4lIGlubmVyX2pvaW4oa2V5X3ZhcnMsYnk9Ik1QUklEIikgICU+JSBpbm5lcl9qb2luKG1pbGVzdG9uLGJ5PSJNUFJJRCIpICU+JQ0KICBtdXRhdGUoUkFDRV9XID0gYXMubnVtZXJpYyhSQUNFX0VUSCA9PSAxKSkgJT4lICBtdXRhdGUoUkFDRV9CID0gYXMubnVtZXJpYyhSQUNFX0VUSCA9PSAyKSkgJT4lDQogIG11dGF0ZShSQUNFX0ggPSBhcy5udW1lcmljKFJBQ0VfRVRIID09IDMpKSAlPiUgIG11dGF0ZShSQUNFX08gPSBhcy5udW1lcmljKFJBQ0VfRVRIID09IDQpKSAlPiUgDQogIG11dGF0ZShXS0VBUk5SID0gcmVwbGFjZShXS0VBUk5SLGlzLm5hKFdLRUFSTlIpLDApKSAlPiUNCiAgbXV0YXRlKEVBUk5fWVIgPSByZXBsYWNlKEVBUk5fWVIsaXMubmEoRUFSTl9ZUiksMCkpIC0+IGRiDQoNCiMgUmVtb3ZlIG9ic2VydmF0aW9ucyB3aXRoIG1pc3NpbmcgdmFsdWVzDQpkYiAlPiUgbmEub21pdCgpIC0+IGRiDQoNCiMgQ3JlYXRlIG1haW4gdmFyaWFibGVzDQpZID0gYXMubWF0cml4KHNlbGVjdChkYixFQVJOWTQpKQ0KRCA9IGFzLm1hdHJpeChzZWxlY3QoZGIsVFJFQVRNTlQpKQ0KIyBIZXRlcm9nZW5laXR5IHZhcmlhYmxlDQpmZW1hbGUgPSBzZWxlY3QoZGIsRkVNQUxFKQ0KZmVtX21hdCA9IGNiaW5kKDEtZmVtYWxlLGZlbWFsZSkNCmxhYmVsX2ZlbSA9IGMoIk1hbGUiLCJGZW1hbGUiKQ0KY29sbmFtZXMoZmVtX21hdCkgPSBsYWJlbF9mZW0NCg0KIyBDcmVhdGUgdmVyc2lvbnMNCkpDID0gZGIkRVZFUkpDSA0KVCA9IHJlcChOQSxsZW5ndGgoWSkpDQpUW0QgPT0gMF0gPSAiQ29udHJvbCINClRbRCA9PSAxICYgSkMgPT0gMF0gPSAiTm8gSkMiDQpUW0QgPT0gMSAmIEpDID09IDEgJiBkYiR2ZXJzaW9ucyA9PSAiQ2xlcmljYWwiXSA9ICJDbGVyaWNhbCINClRbRCA9PSAxICYgSkMgPT0gMSAmIGRiJHZlcnNpb25zID09ICJIZWFsdGgiXSA9ICJIZWFsdGgiDQpUW0QgPT0gMSAmIEpDID09IDEgJiBkYiR2ZXJzaW9ucyA9PSAiQXV0byJdID0gIkF1dG8iDQpUW0QgPT0gMSAmIEpDID09IDEgJiBkYiR2ZXJzaW9ucyA9PSAiV2VsZGluZyJdID0gIldlbGRpbmciDQpUW0QgPT0gMSAmIEpDID09IDEgJiBkYiR2ZXJzaW9ucyA9PSAiRWxlY3RyaWNhbCJdID0gIkVsZWN0cmljYWwiDQpUW0QgPT0gMSAmIEpDID09IDEgJiBkYiR2ZXJzaW9ucyA9PSAiQ29uc3RydWN0aW9uIl0gPSAiQ29uc3RydWN0aW9uIg0KVFtEID09IDEgJiBKQyA9PSAxICYgZGIkdmVyc2lvbnMgPT0gIkZvb2QiXSA9ICJGb29kIg0KVFtEID09IDEgJiBKQyA9PSAxICYgZGIkdmVyc2lvbnMgPT0gIk90aGVyIl0gPSAiT3RoZXIiDQpUW0QgPT0gMSAmIEpDID09IDEgJiBkYiR2ZXJzaW9ucyA9PSAiTXVsdGlwbGUiXSA9ICJNdWx0aXBsZSINClRbaXMubmEoVCldID0gIkpDIHdpdGhvdXQgdm9jIg0KbGFiZWxfVCA9IGMoIkNvbnRyb2wiLCJObyBKQyIsIkpDIHdpdGhvdXQgdm9jIiwiQ2xlcmljYWwiLCJIZWFsdGgiLCJBdXRvIiwiV2VsZGluZyIsIkVsZWN0cmljYWwiLA0KICAgICAgICAgICAgIkNvbnN0cnVjdGlvbiIsIkZvb2QiLCJPdGhlciIsIk11bHRpcGxlIikNClQgPSBmYWN0b3IoVCxsZXZlbHM9bGFiZWxfVCkNCg0KIyBDcmVhdGUgY29udHJvbCBtYXRyaXgNCnhfbWFpbiA9IGFzLm1hdHJpeChzZWxlY3QoZGIsRkVNQUxFLEFHRV9DQVQsUkFDRV9XLFJBQ0VfQixSQUNFX0gsUkFDRV9PLEVEVUNfR1IsDQogICAgICAgICAgICAgICAgICAgICBMSVZFU1BPVSxFVkVSV09SSyxZUl9XT1JLLENVUlJKT0IsSk9CMF8zLCBKT0IzXzksIEpPQjlfMTIsDQogICAgICAgICAgICAgICAgICAgICBNT1NUV0VMRixHT1RfQUZEQyxHT1RfRlMsRUQwXzYsRUQ2XzEyLFBVQkxJQ0gsQkFESExUSCxIQVJEVVNFLFBPVFVTRSxFVkFSUlNULFBNU0EsTVNBLA0KICAgICAgICAgICAgICAgICAgICAgSFNfRCxHRURfRCxWT0NfRCxBTllfRUQxLEhHQyxOVFZfTEFORyxXS0VBUk5SLA0KICAgICAgICAgICAgICAgICAgICAgSEFTQ0hMRCxNQVJSSUFHRSxSX0hFQUQsSEhNRU1CLEhFQUxUSCxQWV9DSUcsUFlfQUxDSEwsDQogICAgICAgICAgICAgICAgICAgICBQWV9QT1QsSEFEV09SUlksSEVBUl9KQyxLTkVXQ05UUixFX01BVEgsRV9SRUFELEVfQUxPTkcsDQogICAgICAgICAgICAgICAgICAgICBFX0NPTlRSTCxFX0VTVEVFTSxFX1NQQ0pPQixFX0ZSSUVORCxLTkVXX0pDLE5PTlJFUyxQUkFSUkksRUFSTl9ZUikpDQpYID0gZGVzaWduX21hdHJpeCh4X21haW4saW50PWNvbG5hbWVzKHhfbWFpbiksaW50X2Q9MikNClggPSBkYXRhX3NjcmVlbihYLHByaW50PUYpIA0KDQojIEJvb2xlYW4gdG8gZXh0cmFjdCBtYWluIGVmZmVjdHMNCm1haW5fZWZmZWN0cyA9ICFncmVwbCgiOiIsY29sbmFtZXMoWCkpDQpgYGANCg0KPGJyPg0KPGJyPg0KDQojIERlY29tcG9zaXRpb24NCg0KIyMgRG91YmxlIE1MIGZvciB0aGUgZWZmZWN0aXZlIHRyZWF0bWVudA0KDQpUaGUgaW1wbGVtZW50YXRpb24gaXMgYmFzZWQgb24gdGhlICpbY2F1c2FsRE1MXShodHRwczovL2dpdGh1Yi5jb20vTUNLbmF1cy9jYXVzYWxETUwpKiBwYWNrYWdlIHRoYXQgZXN0aW1hdGVzIHRoZSBhdmVyYWdlIHBvdGVudGlhbCBvdXRjb21lcyBhbmQgYXZlcmFnZSB0cmVhdG1lbnQgZWZmZWN0cyBmb3IgdGhlIG11bHRpdmFsdWVkIGVmZmVjdGl2ZSB0cmVhdG1lbnQuIFRoZSBudWlzYW5jZSBwYXJhbWV0ZXJzIGFyZSBlc3RpbWF0ZWQgdXNpbmcgYW4gZW5zZW1ibGUgb2YgbWV0aG9kcywgd2hpY2ggZmlyc3QgbmVlZHMgdG8gYmUgaW5pdGlhbGl6ZWQuDQoNCmBgYHtyfQ0KIyMgSW5pdGlhbGl6ZSBjb21wb25lbnRzIHRvIGJlIHVzZWQgaW4gdGhlIGVuc2VtYmxlIGxlYXJuZXINCiMgR2VuZXJhbCBjb21wb25lbnQNCm1lYW4gPSBjcmVhdGVfbWV0aG9kKCJtZWFuIixuYW1lPSJNZWFuIikNCmZvcmVzdCA9ICBjcmVhdGVfbWV0aG9kKCJmb3Jlc3RfZ3JmIix4X3NlbGVjdCA9IG1haW5fZWZmZWN0cyxuYW1lPSJGb3Jlc3QiLA0KICAgICAgICAgICAgICAgICAgICAgICAgYXJncz1saXN0KGhvbmVzdHkgPSBGLHR1bmUucGFyYW1ldGVycyA9ICJhbGwiLHNlZWQ9c2VlZCkpDQoNCiMgUHNjb3JlIHNwZWNpZmljIGNvbXBvbmVudHMNCnJpZGdlX2Jpbl9sb3cgPSBjcmVhdGVfbWV0aG9kKCJyaWRnZSIseF9zZWxlY3QgPSBtYWluX2VmZmVjdHMsbmFtZT0iUmlkZ2UgbG93IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFyZ3M9bGlzdChmYW1pbHkgPSAiYmlub21pYWwiLGxhbWJkYS5taW4ucmF0aW89MC4wMDEpKQ0KbGFzc29fYmluX2xvdyA9IGNyZWF0ZV9tZXRob2QoImxhc3NvIix4X3NlbGVjdCA9IG1haW5fZWZmZWN0cyxuYW1lPSJMYXNzbyBsb3ciLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXJncz1saXN0KGZhbWlseSA9ICJiaW5vbWlhbCIsbGFtYmRhLm1pbi5yYXRpbz0wLjAxKSkNCnJpZGdlX2Jpbl9oaWdoID0gY3JlYXRlX21ldGhvZCgicmlkZ2UiLG5hbWU9IlJpZGdlIGhpZ2giLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFyZ3M9bGlzdChmYW1pbHkgPSAiYmlub21pYWwiLGxhbWJkYS5taW4ucmF0aW89MC4wMSkpDQpsYXNzb19iaW5faGlnaCA9IGNyZWF0ZV9tZXRob2QoImxhc3NvIixuYW1lPSJMYXNzbyBoaWdoIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcmdzPWxpc3QoZmFtaWx5ID0gImJpbm9taWFsIixsYW1iZGEubWluLnJhdGlvPTAuMDUpKQ0KDQojIE91dGNvbWUgc3BlY2lmaWMgY29tcG9uZW50cw0KcmlkZ2VfbHNfbG93ID0gY3JlYXRlX21ldGhvZCgicmlkZ2UiLHhfc2VsZWN0ID0gbWFpbl9lZmZlY3RzLG5hbWU9IlJpZGdlIGxvdyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcmdzPWxpc3QobGFtYmRhLm1pbi5yYXRpbz0wLjAwMDEpKQ0KbGFzc29fbHNfbG93ID0gY3JlYXRlX21ldGhvZCgibGFzc28iLHhfc2VsZWN0ID0gbWFpbl9lZmZlY3RzLG5hbWU9Ikxhc3NvIGxvdyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcmdzPWxpc3QobGFtYmRhLm1pbi5yYXRpbz0wLjAwMSkpDQpyaWRnZV9sc19oaWdoID0gY3JlYXRlX21ldGhvZCgicmlkZ2UiLG5hbWU9IlJpZGdlIGhpZ2giLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFyZ3M9bGlzdChsYW1iZGEubWluLnJhdGlvPTAuMDUpKQ0KbGFzc29fbHNfaGlnaCA9IGNyZWF0ZV9tZXRob2QoImxhc3NvIixuYW1lPSJMYXNzbyBoaWdoIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcmdzPWxpc3QobGFtYmRhLm1pbi5yYXRpbz0wLjA1KSkNCg0KIyBSdW4gbXVsdGlwbGUgdHJlYXRtZW50IG1vZGVsIHRvIGdldCBzY29yZXMNCmF0ZSA9IGNhdXNhbERNTChZLFQsWCwNCiAgICAgICAgICAgICAgICAgbWxfdz1saXN0KGZvcmVzdCksDQogICAgICAgICAgICAgICAgIG1sX3k9bGlzdChmb3Jlc3QpLHF1aWV0PUYpDQojIFVuY29tbWVudCB0aGlzIHRvIHJlcGxpY2F0ZSB0aGUgcmVzdWx0cyB3aXRoIGVuc2VtYmxlIG9mIG1ldGhvZHMNCiMgYXRlID0gY2F1c2FsRE1MKFksVCxYLA0KIyAgICAgICAgICAgICAgICAgIG1sX3c9bGlzdChtZWFuLGZvcmVzdCxyaWRnZV9iaW5fbG93LGxhc3NvX2Jpbl9sb3csDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJpZGdlX2Jpbl9oaWdoLGxhc3NvX2Jpbl9oaWdoKSwNCiMgICAgICAgICAgICAgICAgICBtbF95PWxpc3QobWVhbixmb3Jlc3QscmlkZ2VfbHNfbG93LGxhc3NvX2xzX2xvdywNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmlkZ2VfbHNfaGlnaCxsYXNzb19sc19oaWdoKSkNCmBgYA0KDQpgYGB7cn0NCiMgU2hvdyByZXN1bHRzIGZvciBlYWNoIGVmZmVjdGl2ZSB0cmVhdG1lbnQNCnBsb3QoYXRlJEFQTykNCnN1bW1hcnkoYXRlJEFQTykNCmBgYA0KDQo8YnI+DQo8YnI+DQoNCiMjIERlY29tcG9zaXRpb24NCg0KVGhlIGRlY29tcG9zaXRpb24gcmV1c2VzIHRoZSBudWlzYW5jZSBwYXJhbWV0ZXJzIGFuZCBkb3VibHkgcm9idXN0IHNjb3JlcyB0aGF0IGFyZSBzdG9yZWQgaW4gdGhlIG9iamVjdCBjcmVhdGVkIGJ5IHRoZSAqY2F1c2FsRE1MKiBmdW5jdGlvbi4NCg0KTm93IHdlIHJlcGxpY2F0ZSB0aGUgcmVzdWx0cyBvZiBGaWd1cmUgNSBvZiB0aGUgcGFwZXINCg0KYGBge3J9DQojIyBEZWNvbXBvc2l0aW9uIGZvciBlYWNoIHN1Ymdyb3VwDQojIFJlZ3Jlc3Npb24gd2l0aG91dCBjb25zdGFudA0KY2F0KCJXaXRob3V0IGNvbnN0YW50OlxuIikNCmRlY29tcF9mZW1hbGVfd29jID0gSEtfZGVjb21wb3NpdGlvbihhdGUkQVBPLGZlbV9tYXQsaW50ZXJjZXB0PUZBTFNFKQ0Kc3VtbWFyeShkZWNvbXBfZmVtYWxlX3dvYykNCg0KIyBSZWdyZXNzaW9uIHdpdGggY29uc3RhbnQNCmNhdCgiXG5cbldpdGggY29uc3RhbnQ6XG4iKQ0KZGVjb21wX2ZlbWFsZV93YyA9IEhLX2RlY29tcG9zaXRpb24oYXRlJEFQTyxmZW1hbGUsaW50ZXJjZXB0PVRSVUUpDQpzdW1tYXJ5KGRlY29tcF9mZW1hbGVfd2MpDQpgYGANCg0KYW5kIHRoZSBGaWd1cmUgaXRzZWxmOg0KDQpgYGB7cn0NCiMgVGhlIGZvbGxvd2luZyBpcyBwcm9iYWJseSB0aGUgbW9zdCBjb21wbGljYXRlZCB3YXkgdG8gY3JlYXRlIHRoZSBncmFwaCwgYnV0IGl0IHdvcmtzDQojIEV4dHJhY3QgY29lZmZpY2llbnRzDQpjb2VmX2ZlbSA9IGMoZGVjb21wX2ZlbWFsZV93b2MkbkFURSRyZXN1bHRzWzEsMV0sDQogICAgICAgICAgICAgZGVjb21wX2ZlbWFsZV93b2MkRGVsdGEkcmVzdWx0c1sxLDFdLA0KICAgICAgICAgICAgIGRlY29tcF9mZW1hbGVfd29jJHJBVEUkcmVzdWx0c1sxLDFdLA0KICAgICAgICAgICAgIGRlY29tcF9mZW1hbGVfd29jJG5BVEUkcmVzdWx0c1syLDFdLA0KICAgICAgICAgICAgIGRlY29tcF9mZW1hbGVfd29jJERlbHRhJHJlc3VsdHNbMiwxXSwNCiAgICAgICAgICAgICBkZWNvbXBfZmVtYWxlX3dvYyRyQVRFJHJlc3VsdHNbMiwxXSwNCiAgICAgICAgICAgICBkZWNvbXBfZmVtYWxlX3djJG5BVEUkcmVzdWx0c1syLDFdLA0KICAgICAgICAgICAgIGRlY29tcF9mZW1hbGVfd2MkRGVsdGEkcmVzdWx0c1syLDFdLA0KICAgICAgICAgICAgIGRlY29tcF9mZW1hbGVfd2MkckFURSRyZXN1bHRzWzIsMV0pDQoNCiMgRXh0cmFjdCBwLXZhbHVlcw0KcHZfZmVtID0gYyhkZWNvbXBfZmVtYWxlX3dvYyRuQVRFJHJlc3VsdHNbMSw0XSwNCiAgICAgICAgICAgZGVjb21wX2ZlbWFsZV93b2MkRGVsdGEkcmVzdWx0c1sxLDRdLA0KICAgICAgICAgICBkZWNvbXBfZmVtYWxlX3dvYyRyQVRFJHJlc3VsdHNbMSw0XSwNCiAgICAgICAgICAgZGVjb21wX2ZlbWFsZV93b2MkbkFURSRyZXN1bHRzWzIsNF0sDQogICAgICAgICAgIGRlY29tcF9mZW1hbGVfd29jJERlbHRhJHJlc3VsdHNbMiw0XSwNCiAgICAgICAgICAgZGVjb21wX2ZlbWFsZV93b2MkckFURSRyZXN1bHRzWzIsNF0sDQogICAgICAgICAgIGRlY29tcF9mZW1hbGVfd2MkbkFURSRyZXN1bHRzWzIsNF0sDQogICAgICAgICAgIGRlY29tcF9mZW1hbGVfd2MkRGVsdGEkcmVzdWx0c1syLDRdLA0KICAgICAgICAgICBkZWNvbXBfZmVtYWxlX3djJHJBVEUkcmVzdWx0c1syLDRdKQ0KDQojIFN0YXJ0IGFuZCBlbmQgcG9pbnRzIGZvciB3YXRlcmZhbGwgZ3JhcGgNCnN0YXJ0MCA9IGMoMCxjb2VmX2ZlbVsxXSxjb2VmX2ZlbVszXSkNCmVuZDAgPSBjKGNvZWZfZmVtWzFdLGNvZWZfZmVtWzNdLDApDQpzdGFydDEgPSBjKDAsY29lZl9mZW1bNF0sY29lZl9mZW1bNl0pDQplbmQxID0gYyhjb2VmX2ZlbVs0XSxjb2VmX2ZlbVs2XSwwKQ0Kc3RhcnQyID0gYygwLGNvZWZfZmVtWzddLGNvZWZfZmVtWzldKQ0KZW5kMiA9IGMoY29lZl9mZW1bN10sY29lZl9mZW1bOV0sMCkNCg0KIyBGb3JtYXQgcmVzdWx0cw0KY29lZl9mZW0gPSBmb3JtYXQoY29lZl9mZW0sZGlnaXRzPTIpDQpwdl9mZW0gPSBwYXN0ZTAoIigiLGZvcm1hdChwdl9mZW0sZGlnaXRzPTAsbnNtYWxsPTMsc2NpZW50aWZpYz1GKSwiKSIpDQoNCmRhdGEuZnJhbWUoaWQ9YygxOjMsMTozLDE6MyksDQogICAgICAgICAgICAgICAgICAgRXN0aW1hbmQ9ZmFjdG9yKGMoIm5BVEUiLCJEZWx0YSIsInJBVEUiLCJuQVRFIiwiRGVsdGEiLCJyQVRFIiwibkFURSIsIkRlbHRhIiwickFURSIpLGxldmVscyA9IGMoIm5BVEUiLCJEZWx0YSIsInJBVEUiKSksDQogICAgICAgICAgICAgICAgICAgR2VuZGVyID0gZmFjdG9yKGMocmVwKCJNYWxlIiwzKSxyZXAoIkZlbWFsZSIsMykscmVwKCJEaWZmZXJlbmNlIEZlbWFsZSAtIE1hbGUiLDMpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiRmVtYWxlIiwiTWFsZSIsIkRpZmZlcmVuY2UgRmVtYWxlIC0gTWFsZSIpKSwNCiAgICAgICAgICAgICAgICAgICBzdGFydD0gYyhzdGFydDAsc3RhcnQxLHN0YXJ0MiksDQogICAgICAgICAgICAgICAgICAgZW5kPWMoZW5kMCxlbmQxLGVuZDIpLA0KICAgICAgICAgICAgICAgICAgIGNvZWYgPSBjb2VmX2ZlbSwNCiAgICAgICAgICAgICAgICAgICBwdmFsdWUgPSBwdl9mZW0pICU+JQ0KICBnZ3Bsb3QoYWVzKGlkLCBmaWxsID0gRXN0aW1hbmQsZ3JvdXA9R2VuZGVyKSkgKw0KICAgIGdlb21fcmVjdChhZXMoeG1pbiA9IGlkIC0gMC41LCB4bWF4ID0gaWQgKyAwLjUsIHltaW4gPSBlbmQseW1heCA9IHN0YXJ0KSkgKw0KICAgIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGU9IkRhcmsyIikgKyB5bGFiKCJFZmZlY3QiKSArDQogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDEsMiwzKSxsYWJlbHM9YygibkFURSIsIGV4cHJlc3Npb24oRGVsdGEpLCJyQVRFIikpICsgDQogICAgdGhlbWVfYncoKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsNCiAgICB4bGFiKCJFc3RpbWFuZCIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKyANCiAgICBnZW9tX3RleHQoYWVzKHggPSBpZCwgeSA9IChzdGFydCtlbmQrMS4yNSkvMiwgbGFiZWwgPSBjb2VmKSxzaXplID0gMi43NSkgKw0KICAgIGdlb21fdGV4dChhZXMoeCA9IGlkLCB5ID0gKHN0YXJ0K2VuZC0xLjI1KS8yLCBsYWJlbCA9IHB2YWx1ZSksc2l6ZSA9IDIuNzUpICsNCiAgICBmYWNldF93cmFwKH5HZW5kZXIpDQpgYGANCg0K