Building a logistic regression model: wells in Bangladesh. See Chapter 13 in Regression and Other Stories.


Load packages

library("rprojroot")
root<-has_file(".ROS-Examples-root")$make_fix_file()
library("rstanarm")
library("loo")
invlogit <- plogis

Load data

wells <- read.csv(root("Arsenic/data","wells.csv"))
head(wells)
  switch arsenic   dist dist100 assoc educ educ4
1      1    2.36 16.826 0.16826     0    0  0.00
2      1    0.71 47.322 0.47322     0    0  0.00
3      0    2.07 20.967 0.20967     0   10  2.50
4      1    1.15 21.486 0.21486     0   12  3.00
5      1    1.10 40.874 0.40874     1   14  3.50
6      1    3.90 69.518 0.69518     1    9  2.25
n <- nrow(wells)

Null model

Log-score for coin flipping

prob <- 0.5
round(log(prob)*sum(wells$switch) + log(1-prob)*sum(1-wells$switch),1)
[1] -2093.3

Log-score for intercept model

round(prob <- mean(wells$switch),2)
[1] 0.58
round(log(prob)*sum(wells$switch) + log(1-prob)*sum(1-wells$switch),1)
[1] -2059

A single predictor

Fit a model using distance to the nearest safe well

fit_1 <- stan_glm(switch ~ dist, family = binomial(link = "logit"), data=wells)
print(fit_1, digits=3)
stan_glm
 family:       binomial [logit]
 formula:      switch ~ dist
 observations: 3020
 predictors:   2
------
            Median MAD_SD
(Intercept)  0.605  0.058
dist        -0.006  0.001

------
* For help interpreting the printed output see ?print.stanreg
* For info on the priors used see ?prior_summary.stanreg

LOO log score

(loo1 <- loo(fit_1))

Computed from 4000 by 3020 log-likelihood matrix

         Estimate   SE
elpd_loo  -2040.1 10.4
p_loo         1.9  0.0
looic      4080.1 20.8
------
Monte Carlo SE of elpd_loo is 0.0.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.

Histogram of distances

hist(wells$dist, breaks=seq(0,10+max(wells$dist),10), freq=TRUE,
     xlab="Distance (in meters) to nearest safe well", ylab="", main="", mgp=c(2,.5,0))

Scale distance in meters to distance in 100 meters

wells$dist100 <- wells$dist/100

Fit a model using scaled distance to the nearest safe well

fit_2 <- stan_glm(switch ~ dist100, family = binomial(link = "logit"), data=wells)
print(fit_2, digits=2)
stan_glm
 family:       binomial [logit]
 formula:      switch ~ dist100
 observations: 3020
 predictors:   2
------
            Median MAD_SD
(Intercept)  0.61   0.06 
dist100     -0.62   0.09 

------
* For help interpreting the printed output see ?print.stanreg
* For info on the priors used see ?prior_summary.stanreg

LOO log score

(loo2 <- loo(fit_2, save_psis = TRUE))

Computed from 4000 by 3020 log-likelihood matrix

         Estimate   SE
elpd_loo  -2040.1 10.4
p_loo         2.0  0.0
looic      4080.3 20.9
------
Monte Carlo SE of elpd_loo is 0.0.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.

Plot model fit

jitter_binary <- function(a, jitt=.05){
  a + (1-2*a)*runif(length(a),0,jitt)
}
plot(c(0,max(wells$dist, na.rm=TRUE)*1.02), c(0,1),
     xlab="Distance (in meters) to nearest safe well", ylab="Pr (switching)",
     type="n", xaxs="i", yaxs="i", mgp=c(2,.5,0))
curve(invlogit(coef(fit_1)[1]+coef(fit_1)[2]*x), lwd=1, add=TRUE)
points(wells$dist, jitter_binary(wells$switch), pch=20, cex=.1)

Plot uncertainty in the estimated coefficients

sims <- as.matrix(fit_2)
par(pty="s")
plot(sims[1:500,1], sims[1:500,2], xlim=c(.4,.8), ylim=c(-1,0),
     xlab=expression(beta[0]), ylab=expression(beta[1]), mgp=c(1.5,.5,0),
     pch=20, cex=.5, xaxt="n", yaxt="n")
axis(1, seq(.4,.8,.2), mgp=c(1.5,.5,0))
axis(2, seq(-1,0,.5), mgp=c(1.5,.5,0))

Plot uncertainty in the estimated predictions

plot(c(0,max(wells$dist, na.rm=T)*1.02), c(0,1),
     xlab="Distance (in meters) to nearest safe well", ylab="Pr (switching)",
     type="n", xaxs="i", yaxs="i", mgp=c(2,.5,0))
for (j in 1:20) {
    curve (invlogit(sims[j,1]+sims[j,2]*x/100), lwd=.5,
           col="darkgray", add=TRUE)
}
curve(invlogit(coef(fit_2)[1]+coef(fit_2)[2]*x/100), lwd=1, add=T)
points(wells$dist, jitter_binary(wells$switch), pch=20, cex=.1)

Two predictors

Histogram of arsenic levels

hist(wells$arsenic, breaks=seq(0,.25+max(wells$arsenic),.25), freq=TRUE,
     xlab="Arsenic concentration in well water", ylab="", main="", mgp=c(2,.5,0))

Fit a model using scaled distance and arsenic level

fit_3 <- stan_glm(switch ~ dist100 + arsenic, family = binomial(link = "logit"),
                  data=wells)
print(fit_3, digits=2)
stan_glm
 family:       binomial [logit]
 formula:      switch ~ dist100 + arsenic
 observations: 3020
 predictors:   3
------
            Median MAD_SD
(Intercept)  0.01   0.08 
dist100     -0.90   0.11 
arsenic      0.46   0.04 

------
* For help interpreting the printed output see ?print.stanreg
* For info on the priors used see ?prior_summary.stanreg

LOO log score

(loo3 <- loo(fit_3, save_psis = TRUE))

Computed from 4000 by 3020 log-likelihood matrix

         Estimate   SE
elpd_loo  -1968.5 15.7
p_loo         3.3  0.1
looic      3937.0 31.3
------
Monte Carlo SE of elpd_loo is 0.0.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.

Compare models

loo_compare(loo2, loo3)
      elpd_diff se_diff
fit_3   0.0       0.0  
fit_2 -71.6      12.1  

Average improvement in LOO predictive probabilities

from dist100 to dist100 + arsenic

pred2 <- loo_predict(fit_2, psis_object = loo2$psis_object)$value
pred3 <- loo_predict(fit_3, psis_object = loo3$psis_object)$value
round(mean(c(pred3[wells$switch==1]-pred2[wells$switch==1],pred2[wells$switch==0]-pred3[wells$switch==0])),3)
[1] 0.022

Plot model fits

plot(c(0,max(wells$dist,na.rm=T)*1.02), c(0,1),
     xlab="Distance (in meters) to nearest safe well", ylab="Pr (switching)",
     type="n", xaxs="i", yaxs="i", mgp=c(2,.5,0))
points(wells$dist, jitter_binary(wells$switch), pch=20, cex=.1)
curve(invlogit(coef(fit_3)[1]+coef(fit_3)[2]*x/100+coef(fit_3)[3]*.50), lwd=.5, add=T)
curve(invlogit(coef(fit_3)[1]+coef(fit_3)[2]*x/100+coef(fit_3)[3]*1.00), lwd=.5, add=T)
text(50, .27, "if As = 0.5", adj=0, cex=.8)
text(75, .50, "if As = 1.0", adj=0, cex=.8)

plot(c(0,max(wells$arsenic,na.rm=T)*1.02), c(0,1),
     xlab="Arsenic concentration in well water", ylab="Pr (switching)",
     type="n", xaxs="i", yaxs="i", mgp=c(2,.5,0))
points(wells$arsenic, jitter_binary(wells$switch), pch=20, cex=.1)
curve(invlogit(coef(fit_3)[1]+coef(fit_3)[2]*0+coef(fit_3)[3]*x), from=0.5, lwd=.5, add=T)
curve(invlogit(coef(fit_3)[1]+coef(fit_3)[2]*0.5+coef(fit_3)[3]*x), from=0.5, lwd=.5, add=T)
text(.5, .78, "if dist = 0", adj=0, cex=.8)
text(2, .6, "if dist = 50", adj=0, cex=.8)

Interaction

Fit a model using scaled distance, arsenic level, and an interaction

fit_4 <- stan_glm(switch ~ dist100 + arsenic + dist100:arsenic,
                  family = binomial(link="logit"), data = wells)
print(fit_4, digits=2)
stan_glm
 family:       binomial [logit]
 formula:      switch ~ dist100 + arsenic + dist100:arsenic
 observations: 3020
 predictors:   4
------
                Median MAD_SD
(Intercept)     -0.15   0.11 
dist100         -0.58   0.20 
arsenic          0.55   0.07 
dist100:arsenic -0.18   0.10 

------
* For help interpreting the printed output see ?print.stanreg
* For info on the priors used see ?prior_summary.stanreg

LOO log score

(loo4 <- loo(fit_4))

Computed from 4000 by 3020 log-likelihood matrix

         Estimate   SE
elpd_loo  -1968.0 15.9
p_loo         4.3  0.3
looic      3935.9 31.7
------
Monte Carlo SE of elpd_loo is 0.0.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.

Compare models

loo_compare(loo3, loo4)
      elpd_diff se_diff
fit_4  0.0       0.0   
fit_3 -0.5       1.9   

Centering the input variables

wells$c_dist100 <- wells$dist100 - mean(wells$dist100)
wells$c_arsenic <- wells$arsenic - mean(wells$arsenic)
fit_5 <- stan_glm(switch ~ c_dist100 + c_arsenic + c_dist100:c_arsenic,
                  family = binomial(link="logit"), data = wells)
print(fit_5, digits=2)
stan_glm
 family:       binomial [logit]
 formula:      switch ~ c_dist100 + c_arsenic + c_dist100:c_arsenic
 observations: 3020
 predictors:   4
------
                    Median MAD_SD
(Intercept)          0.35   0.04 
c_dist100           -0.88   0.10 
c_arsenic            0.47   0.04 
c_dist100:c_arsenic -0.18   0.10 

------
* For help interpreting the printed output see ?print.stanreg
* For info on the priors used see ?prior_summary.stanreg

Plot model fits

plot(c(0,max(wells$dist,na.rm=T)*1.02), c(0,1),
     xlab="Distance (in meters) to nearest safe well", ylab="Pr (switching)",
     type="n", xaxs="i", yaxs="i", mgp=c(2,.5,0))
points(wells$dist, jitter_binary(wells$switch), pch=20, cex=.1)
curve(invlogit(coef(fit_4)[1]+coef(fit_4)[2]*x/100+coef(fit_4)[3]*.50+coef(fit_4)[4]*x/100*.50), lwd=.5, add=T)
curve(invlogit(coef(fit_4)[1]+coef(fit_4)[2]*x/100+coef(fit_4)[3]*1.00+coef(fit_4)[4]*x/100*1.00), lwd=.5, add=T)
text (50, .29, "if As = 0.5", adj=0, cex=.8)
text (75, .50, "if As = 1.0", adj=0, cex=.8)

plot(c(0,max(wells$arsenic,na.rm=T)*1.02), c(0,1),
     xlab="Arsenic concentration in well water", ylab="Pr (switching)",
     type="n", xaxs="i", yaxs="i", mgp=c(2,.5,0))
points(wells$arsenic, jitter_binary(wells$switch), pch=20, cex=.1)
curve(invlogit(coef(fit_4)[1]+coef(fit_4)[2]*0+coef(fit_4)[3]*x+coef(fit_4)[4]*0*x), from=0.5, lwd=.5, add=T)
curve(invlogit(coef(fit_4)[1]+coef(fit_4)[2]*0.5+coef(fit_4)[3]*x+coef(fit_4)[4]*0.5*x), from=0.5, lwd=.5, add=T)
text (.5, .78, "if dist = 0", adj=0, cex=.8)
text (2, .6, "if dist = 50", adj=0, cex=.8)

More predictors

Adding social predictors

fit_6 <- stan_glm(switch ~ dist100 + arsenic + educ4 + assoc,
                  family = binomial(link="logit"), data = wells)
print(fit_6, digits=2)
stan_glm
 family:       binomial [logit]
 formula:      switch ~ dist100 + arsenic + educ4 + assoc
 observations: 3020
 predictors:   5
------
            Median MAD_SD
(Intercept) -0.16   0.10 
dist100     -0.90   0.10 
arsenic      0.47   0.04 
educ4        0.17   0.04 
assoc       -0.12   0.08 

------
* For help interpreting the printed output see ?print.stanreg
* For info on the priors used see ?prior_summary.stanreg

LOO log score

(loo6 <- loo(fit_6))

Computed from 4000 by 3020 log-likelihood matrix

         Estimate   SE
elpd_loo  -1959.0 16.1
p_loo         5.2  0.1
looic      3918.0 32.2
------
Monte Carlo SE of elpd_loo is 0.0.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.

Compare models

loo_compare(loo4, loo6)
      elpd_diff se_diff
fit_6  0.0       0.0   
fit_4 -9.0       5.1   

Remove assoc

fit_7 <- stan_glm(switch ~ dist100 + arsenic + educ4,
                  family = binomial(link="logit"), data = wells)
print(fit_7, digits=2)
stan_glm
 family:       binomial [logit]
 formula:      switch ~ dist100 + arsenic + educ4
 observations: 3020
 predictors:   4
------
            Median MAD_SD
(Intercept) -0.22   0.09 
dist100     -0.90   0.10 
arsenic      0.47   0.04 
educ4        0.17   0.04 

------
* For help interpreting the printed output see ?print.stanreg
* For info on the priors used see ?prior_summary.stanreg

LOO log score

(loo7 <- loo(fit_7))

Computed from 4000 by 3020 log-likelihood matrix

         Estimate   SE
elpd_loo  -1959.4 16.1
p_loo         4.3  0.1
looic      3918.9 32.1
------
Monte Carlo SE of elpd_loo is 0.0.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.

Compare models

loo_compare(loo4, loo7)
      elpd_diff se_diff
fit_7  0.0       0.0   
fit_4 -8.5       4.8   
loo_compare(loo6, loo7)
      elpd_diff se_diff
fit_6  0.0       0.0   
fit_7 -0.5       1.6   

Add interactions with education

wells$c_educ4 <- wells$educ4 - mean(wells$educ4)
fit_8 <- stan_glm(switch ~ c_dist100 + c_arsenic + c_educ4 +
                      c_dist100:c_educ4 + c_arsenic:c_educ4,
                  family = binomial(link="logit"), data = wells)
print(fit_8, digits=2)
stan_glm
 family:       binomial [logit]
 formula:      switch ~ c_dist100 + c_arsenic + c_educ4 + c_dist100:c_educ4 + 
       c_arsenic:c_educ4
 observations: 3020
 predictors:   6
------
                  Median MAD_SD
(Intercept)        0.35   0.04 
c_dist100         -0.92   0.10 
c_arsenic          0.49   0.04 
c_educ4            0.19   0.04 
c_dist100:c_educ4  0.33   0.10 
c_arsenic:c_educ4  0.08   0.04 

------
* For help interpreting the printed output see ?print.stanreg
* For info on the priors used see ?prior_summary.stanreg

LOO log score

(loo8 <- loo(fit_8, save_psis=TRUE))

Computed from 4000 by 3020 log-likelihood matrix

         Estimate   SE
elpd_loo  -1952.9 16.5
p_loo         6.6  0.3
looic      3905.8 33.0
------
Monte Carlo SE of elpd_loo is 0.0.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.

Compare models

loo_compare(loo3, loo8)
      elpd_diff se_diff
fit_8   0.0       0.0  
fit_3 -15.6       6.3  
loo_compare(loo7, loo8)
      elpd_diff se_diff
fit_8  0.0       0.0   
fit_7 -6.6       4.3   

Average improvement in LOO predictive probabilities

from dist100 + arsenic to dist100 + arsenic + educ4 + dist100:educ4 + arsenic:educ4

pred8 <- loo_predict(fit_8, psis_object = loo8$psis_object)$value
round(mean(c(pred8[wells$switch==1]-pred3[wells$switch==1],pred3[wells$switch==0]-pred8[wells$switch==0])),3)
[1] 0.005

Transformation of variable

Fit a model using scaled distance and log arsenic level

wells$log_arsenic <- log(wells$arsenic)
fit_3a <- stan_glm(switch ~ dist100 + log_arsenic, family = binomial(link = "logit"),
                   data = wells)
print(fit_3a, digits=2)
stan_glm
 family:       binomial [logit]
 formula:      switch ~ dist100 + log_arsenic
 observations: 3020
 predictors:   3
------
            Median MAD_SD
(Intercept)  0.52   0.06 
dist100     -0.98   0.10 
log_arsenic  0.88   0.07 

------
* For help interpreting the printed output see ?print.stanreg
* For info on the priors used see ?prior_summary.stanreg

LOO log score

(loo3a <- loo(fit_3a))

Computed from 4000 by 3020 log-likelihood matrix

         Estimate   SE
elpd_loo  -1952.2 16.3
p_loo         3.0  0.1
looic      3904.4 32.6
------
Monte Carlo SE of elpd_loo is 0.0.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.

Compare models

loo_compare(loo3, loo3a)
       elpd_diff se_diff
fit_3a   0.0       0.0  
fit_3  -16.3       4.4  

Fit a model using scaled distance, log arsenic level, and an interaction

fit_4a <- stan_glm(switch ~ dist100 + log_arsenic + dist100:log_arsenic,
                  family = binomial(link = "logit"), data = wells)
print(fit_4a, digits=2)
stan_glm
 family:       binomial [logit]
 formula:      switch ~ dist100 + log_arsenic + dist100:log_arsenic
 observations: 3020
 predictors:   4
------
                    Median MAD_SD
(Intercept)          0.49   0.07 
dist100             -0.88   0.14 
log_arsenic          0.99   0.11 
dist100:log_arsenic -0.23   0.18 

------
* For help interpreting the printed output see ?print.stanreg
* For info on the priors used see ?prior_summary.stanreg

LOO log score

(loo4a <- loo(fit_4a))

Computed from 4000 by 3020 log-likelihood matrix

         Estimate   SE
elpd_loo  -1952.4 16.4
p_loo         4.1  0.1
looic      3904.9 32.8
------
Monte Carlo SE of elpd_loo is 0.0.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.

Compare models

loo_compare(loo3a, loo4a)
       elpd_diff se_diff
fit_3a  0.0       0.0   
fit_4a -0.2       1.3   

Add interactions with education

wells$c_log_arsenic <- wells$log_arsenic - mean(wells$log_arsenic)
fit_8a <- stan_glm(switch ~ c_dist100 + c_log_arsenic + c_educ4 +
                      c_dist100:c_educ4 + c_log_arsenic:c_educ4,
                  family = binomial(link="logit"), data = wells)
print(fit_8a, digits=2)
stan_glm
 family:       binomial [logit]
 formula:      switch ~ c_dist100 + c_log_arsenic + c_educ4 + c_dist100:c_educ4 + 
       c_log_arsenic:c_educ4
 observations: 3020
 predictors:   6
------
                      Median MAD_SD
(Intercept)            0.34   0.04 
c_dist100             -1.00   0.11 
c_log_arsenic          0.91   0.07 
c_educ4                0.18   0.04 
c_dist100:c_educ4      0.35   0.11 
c_log_arsenic:c_educ4  0.06   0.07 

------
* For help interpreting the printed output see ?print.stanreg
* For info on the priors used see ?prior_summary.stanreg

LOO log score

(loo8a <- loo(fit_8a, save_psis=TRUE))

Computed from 4000 by 3020 log-likelihood matrix

         Estimate   SE
elpd_loo  -1938.0 17.1
p_loo         6.1  0.2
looic      3875.9 34.3
------
Monte Carlo SE of elpd_loo is 0.0.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.

Compare models

loo_compare(loo8, loo8a)
       elpd_diff se_diff
fit_8a   0.0       0.0  
fit_8  -14.9       4.3  
LS0tCnRpdGxlOiAiUmVncmVzc2lvbiBhbmQgT3RoZXIgU3RvcmllczogQXJzZW5pYyIKYXV0aG9yOiAiQW5kcmV3IEdlbG1hbiwgSmVubmlmZXIgSGlsbCwgQWtpIFZlaHRhcmkiCmRhdGU6ICJgciBmb3JtYXQoU3lzLkRhdGUoKSlgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiByZWFkYWJsZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDIKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQotLS0KQnVpbGRpbmcgYSBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsOiB3ZWxscyBpbiBCYW5nbGFkZXNoLiBTZWUKQ2hhcHRlciAxMyBpbiBSZWdyZXNzaW9uIGFuZCBPdGhlciBTdG9yaWVzLgoKLS0tLS0tLS0tLS0tLQoKCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQobWVzc2FnZT1GQUxTRSwgZXJyb3I9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGNvbW1lbnQ9TkEpCiMgc3dpdGNoIHRoaXMgdG8gVFJVRSB0byBzYXZlIGZpZ3VyZXMgaW4gc2VwYXJhdGUgZmlsZXMKc2F2ZWZpZ3MgPC0gRkFMU0UKYGBgCgojIyMjIExvYWQgcGFja2FnZXMKCmBgYHtyIH0KbGlicmFyeSgicnByb2pyb290IikKcm9vdDwtaGFzX2ZpbGUoIi5ST1MtRXhhbXBsZXMtcm9vdCIpJG1ha2VfZml4X2ZpbGUoKQpsaWJyYXJ5KCJyc3RhbmFybSIpCmxpYnJhcnkoImxvbyIpCmludmxvZ2l0IDwtIHBsb2dpcwpgYGAKCiMjIyMgTG9hZCBkYXRhCgpgYGB7ciB9CndlbGxzIDwtIHJlYWQuY3N2KHJvb3QoIkFyc2VuaWMvZGF0YSIsIndlbGxzLmNzdiIpKQpoZWFkKHdlbGxzKQpuIDwtIG5yb3cod2VsbHMpCmBgYAoKIyMgTnVsbCBtb2RlbAoKIyMjIyBMb2ctc2NvcmUgZm9yIGNvaW4gZmxpcHBpbmcKCmBgYHtyIH0KcHJvYiA8LSAwLjUKcm91bmQobG9nKHByb2IpKnN1bSh3ZWxscyRzd2l0Y2gpICsgbG9nKDEtcHJvYikqc3VtKDEtd2VsbHMkc3dpdGNoKSwxKQpgYGAKCiMjIyMgTG9nLXNjb3JlIGZvciBpbnRlcmNlcHQgbW9kZWwKCmBgYHtyIH0Kcm91bmQocHJvYiA8LSBtZWFuKHdlbGxzJHN3aXRjaCksMikKcm91bmQobG9nKHByb2IpKnN1bSh3ZWxscyRzd2l0Y2gpICsgbG9nKDEtcHJvYikqc3VtKDEtd2VsbHMkc3dpdGNoKSwxKQpgYGAKCiMjIEEgc2luZ2xlIHByZWRpY3RvcgoKIyMjIyBGaXQgYSBtb2RlbCB1c2luZyBkaXN0YW5jZSB0byB0aGUgbmVhcmVzdCBzYWZlIHdlbGwKCmBgYHtyIHJlc3VsdHM9J2hpZGUnfQpmaXRfMSA8LSBzdGFuX2dsbShzd2l0Y2ggfiBkaXN0LCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksIGRhdGE9d2VsbHMpCmBgYAoKCgpgYGB7ciB9CnByaW50KGZpdF8xLCBkaWdpdHM9MykKYGBgCgojIyMjIExPTyBsb2cgc2NvcmUKCmBgYHtyIH0KKGxvbzEgPC0gbG9vKGZpdF8xKSkKYGBgCgojIyMjIEhpc3RvZ3JhbSBvZiBkaXN0YW5jZXMKCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmlmIChzYXZlZmlncykgcG9zdHNjcmlwdChyb290KCJBcnNlbmljL2ZpZ3MiLCJhcnNlbmljLmRpc3RhbmNlcy5ibmV3LnBzIiksCiAgICAgICAgICAgICAgICAgICAgICAgICBoZWlnaHQ9Mywgd2lkdGg9NCwgaG9yaXpvbnRhbD1UUlVFKQpgYGAKYGBge3IgfQpoaXN0KHdlbGxzJGRpc3QsIGJyZWFrcz1zZXEoMCwxMCttYXgod2VsbHMkZGlzdCksMTApLCBmcmVxPVRSVUUsCiAgICAgeGxhYj0iRGlzdGFuY2UgKGluIG1ldGVycykgdG8gbmVhcmVzdCBzYWZlIHdlbGwiLCB5bGFiPSIiLCBtYWluPSIiLCBtZ3A9YygyLC41LDApKQpgYGAKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KaWYgKHNhdmVmaWdzKSBkZXYub2ZmKCkKYGBgCgojIyMjIFNjYWxlIGRpc3RhbmNlIGluIG1ldGVycyB0byBkaXN0YW5jZSBpbiAxMDAgbWV0ZXJzCgpgYGB7ciB9CndlbGxzJGRpc3QxMDAgPC0gd2VsbHMkZGlzdC8xMDAKYGBgCgojIyMjIEZpdCBhIG1vZGVsIHVzaW5nIHNjYWxlZCBkaXN0YW5jZSB0byB0aGUgbmVhcmVzdCBzYWZlIHdlbGwKCmBgYHtyIHJlc3VsdHM9J2hpZGUnfQpmaXRfMiA8LSBzdGFuX2dsbShzd2l0Y2ggfiBkaXN0MTAwLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksIGRhdGE9d2VsbHMpCmBgYAoKCgpgYGB7ciB9CnByaW50KGZpdF8yLCBkaWdpdHM9MikKYGBgCgojIyMjIExPTyBsb2cgc2NvcmUKCmBgYHtyIH0KKGxvbzIgPC0gbG9vKGZpdF8yLCBzYXZlX3BzaXMgPSBUUlVFKSkKYGBgCgojIyMjIFBsb3QgbW9kZWwgZml0CgpgYGB7ciB9CmppdHRlcl9iaW5hcnkgPC0gZnVuY3Rpb24oYSwgaml0dD0uMDUpewogIGEgKyAoMS0yKmEpKnJ1bmlmKGxlbmd0aChhKSwwLGppdHQpCn0KYGBgCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmlmIChzYXZlZmlncykgcG9zdHNjcmlwdChyb290KCJBcnNlbmljL2ZpZ3MiLCJhcnNlbmljLmxvZ2l0Zml0LjFuZXcuYS5wcyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0PTMuNSwgd2lkdGg9NCwgaG9yaXpvbnRhbD1UUlVFKQpgYGAKYGBge3IgfQpwbG90KGMoMCxtYXgod2VsbHMkZGlzdCwgbmEucm09VFJVRSkqMS4wMiksIGMoMCwxKSwKICAgICB4bGFiPSJEaXN0YW5jZSAoaW4gbWV0ZXJzKSB0byBuZWFyZXN0IHNhZmUgd2VsbCIsIHlsYWI9IlByIChzd2l0Y2hpbmcpIiwKICAgICB0eXBlPSJuIiwgeGF4cz0iaSIsIHlheHM9ImkiLCBtZ3A9YygyLC41LDApKQpjdXJ2ZShpbnZsb2dpdChjb2VmKGZpdF8xKVsxXStjb2VmKGZpdF8xKVsyXSp4KSwgbHdkPTEsIGFkZD1UUlVFKQpwb2ludHMod2VsbHMkZGlzdCwgaml0dGVyX2JpbmFyeSh3ZWxscyRzd2l0Y2gpLCBwY2g9MjAsIGNleD0uMSkKYGBgCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmlmIChzYXZlZmlncykgZGV2Lm9mZigpCmBgYAoKIyMjIyBQbG90IHVuY2VydGFpbnR5IGluIHRoZSBlc3RpbWF0ZWQgY29lZmZpY2llbnRzCgpgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQppZiAoc2F2ZWZpZ3MpIHBvc3RzY3JpcHQocm9vdCgiQXJzZW5pYy9maWdzIiwiYXJzZW5pYy5sb2dpdGZpdC5zY2F0dGVycGxvdC5wcyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0PTMuNSwgd2lkdGg9My41LCBob3Jpem9udGFsPVRSVUUpCmBgYApgYGB7ciB9CnNpbXMgPC0gYXMubWF0cml4KGZpdF8yKQpwYXIocHR5PSJzIikKcGxvdChzaW1zWzE6NTAwLDFdLCBzaW1zWzE6NTAwLDJdLCB4bGltPWMoLjQsLjgpLCB5bGltPWMoLTEsMCksCiAgICAgeGxhYj1leHByZXNzaW9uKGJldGFbMF0pLCB5bGFiPWV4cHJlc3Npb24oYmV0YVsxXSksIG1ncD1jKDEuNSwuNSwwKSwKICAgICBwY2g9MjAsIGNleD0uNSwgeGF4dD0ibiIsIHlheHQ9Im4iKQpheGlzKDEsIHNlcSguNCwuOCwuMiksIG1ncD1jKDEuNSwuNSwwKSkKYXhpcygyLCBzZXEoLTEsMCwuNSksIG1ncD1jKDEuNSwuNSwwKSkKYGBgCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmlmIChzYXZlZmlncykgZGV2Lm9mZigpCmBgYAoKIyMjIyBQbG90IHVuY2VydGFpbnR5IGluIHRoZSBlc3RpbWF0ZWQgcHJlZGljdGlvbnMKCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmlmIChzYXZlZmlncykgcG9zdHNjcmlwdChyb290KCJBcnNlbmljL2ZpZ3MiLCJhcnNlbmljLmxvZ2l0Zml0LjFuZXcuYi5wcyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0PTMuNSwgd2lkdGg9NCwgaG9yaXpvbnRhbD1UUlVFKQpgYGAKYGBge3IgfQpwbG90KGMoMCxtYXgod2VsbHMkZGlzdCwgbmEucm09VCkqMS4wMiksIGMoMCwxKSwKICAgICB4bGFiPSJEaXN0YW5jZSAoaW4gbWV0ZXJzKSB0byBuZWFyZXN0IHNhZmUgd2VsbCIsIHlsYWI9IlByIChzd2l0Y2hpbmcpIiwKICAgICB0eXBlPSJuIiwgeGF4cz0iaSIsIHlheHM9ImkiLCBtZ3A9YygyLC41LDApKQpmb3IgKGogaW4gMToyMCkgewogICAgY3VydmUgKGludmxvZ2l0KHNpbXNbaiwxXStzaW1zW2osMl0qeC8xMDApLCBsd2Q9LjUsCiAgICAgICAgICAgY29sPSJkYXJrZ3JheSIsIGFkZD1UUlVFKQp9CmN1cnZlKGludmxvZ2l0KGNvZWYoZml0XzIpWzFdK2NvZWYoZml0XzIpWzJdKngvMTAwKSwgbHdkPTEsIGFkZD1UKQpwb2ludHMod2VsbHMkZGlzdCwgaml0dGVyX2JpbmFyeSh3ZWxscyRzd2l0Y2gpLCBwY2g9MjAsIGNleD0uMSkKYGBgCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmlmIChzYXZlZmlncykgZGV2Lm9mZigpCmBgYAoKIyMgVHdvIHByZWRpY3RvcnMKCiMjIyMgSGlzdG9ncmFtIG9mIGFyc2VuaWMgbGV2ZWxzCgpgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQppZiAoc2F2ZWZpZ3MpIHBvc3RzY3JpcHQocm9vdCgiQXJzZW5pYy9maWdzIiwiYXJzZW5pYy5sZXZlbHMuYS5wcyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0PTMsIHdpZHRoPTQsIGhvcml6b250YWw9VFJVRSkKYGBgCmBgYHtyIH0KaGlzdCh3ZWxscyRhcnNlbmljLCBicmVha3M9c2VxKDAsLjI1K21heCh3ZWxscyRhcnNlbmljKSwuMjUpLCBmcmVxPVRSVUUsCiAgICAgeGxhYj0iQXJzZW5pYyBjb25jZW50cmF0aW9uIGluIHdlbGwgd2F0ZXIiLCB5bGFiPSIiLCBtYWluPSIiLCBtZ3A9YygyLC41LDApKQpgYGAKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KaWYgKHNhdmVmaWdzKSBkZXYub2ZmKCkKYGBgCgojIyMjIEZpdCBhIG1vZGVsIHVzaW5nIHNjYWxlZCBkaXN0YW5jZSBhbmQgYXJzZW5pYyBsZXZlbAoKYGBge3IgcmVzdWx0cz0naGlkZSd9CmZpdF8zIDwtIHN0YW5fZ2xtKHN3aXRjaCB+IGRpc3QxMDAgKyBhcnNlbmljLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksCiAgICAgICAgICAgICAgICAgIGRhdGE9d2VsbHMpCmBgYAoKCgpgYGB7ciB9CnByaW50KGZpdF8zLCBkaWdpdHM9MikKYGBgCgojIyMjIExPTyBsb2cgc2NvcmUKCmBgYHtyIH0KKGxvbzMgPC0gbG9vKGZpdF8zLCBzYXZlX3BzaXMgPSBUUlVFKSkKYGBgCgojIyMjIENvbXBhcmUgbW9kZWxzCgpgYGB7ciB9Cmxvb19jb21wYXJlKGxvbzIsIGxvbzMpCmBgYAoKIyMjIyBBdmVyYWdlIGltcHJvdmVtZW50IGluIExPTyBwcmVkaWN0aXZlIHByb2JhYmlsaXRpZXM8YnI+CmZyb20gZGlzdDEwMCB0byBkaXN0MTAwICsgYXJzZW5pYwoKYGBge3IgfQpwcmVkMiA8LSBsb29fcHJlZGljdChmaXRfMiwgcHNpc19vYmplY3QgPSBsb28yJHBzaXNfb2JqZWN0KSR2YWx1ZQpwcmVkMyA8LSBsb29fcHJlZGljdChmaXRfMywgcHNpc19vYmplY3QgPSBsb28zJHBzaXNfb2JqZWN0KSR2YWx1ZQpyb3VuZChtZWFuKGMocHJlZDNbd2VsbHMkc3dpdGNoPT0xXS1wcmVkMlt3ZWxscyRzd2l0Y2g9PTFdLHByZWQyW3dlbGxzJHN3aXRjaD09MF0tcHJlZDNbd2VsbHMkc3dpdGNoPT0wXSkpLDMpCmBgYAoKIyMjIyBQbG90IG1vZGVsIGZpdHMKCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmlmIChzYXZlZmlncykgcG9zdHNjcmlwdChyb290KCJBcnNlbmljL2ZpZ3MiLCJhcnNlbmljLjJ2YXJpYWJsZXMuYS5wcyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0PTMuNSwgd2lkdGg9NCwgaG9yaXpvbnRhbD1UUlVFKQpgYGAKYGBge3IgfQpwbG90KGMoMCxtYXgod2VsbHMkZGlzdCxuYS5ybT1UKSoxLjAyKSwgYygwLDEpLAogICAgIHhsYWI9IkRpc3RhbmNlIChpbiBtZXRlcnMpIHRvIG5lYXJlc3Qgc2FmZSB3ZWxsIiwgeWxhYj0iUHIgKHN3aXRjaGluZykiLAogICAgIHR5cGU9Im4iLCB4YXhzPSJpIiwgeWF4cz0iaSIsIG1ncD1jKDIsLjUsMCkpCnBvaW50cyh3ZWxscyRkaXN0LCBqaXR0ZXJfYmluYXJ5KHdlbGxzJHN3aXRjaCksIHBjaD0yMCwgY2V4PS4xKQpjdXJ2ZShpbnZsb2dpdChjb2VmKGZpdF8zKVsxXStjb2VmKGZpdF8zKVsyXSp4LzEwMCtjb2VmKGZpdF8zKVszXSouNTApLCBsd2Q9LjUsIGFkZD1UKQpjdXJ2ZShpbnZsb2dpdChjb2VmKGZpdF8zKVsxXStjb2VmKGZpdF8zKVsyXSp4LzEwMCtjb2VmKGZpdF8zKVszXSoxLjAwKSwgbHdkPS41LCBhZGQ9VCkKdGV4dCg1MCwgLjI3LCAiaWYgQXMgPSAwLjUiLCBhZGo9MCwgY2V4PS44KQp0ZXh0KDc1LCAuNTAsICJpZiBBcyA9IDEuMCIsIGFkaj0wLCBjZXg9LjgpCmBgYApgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQppZiAoc2F2ZWZpZ3MpIGRldi5vZmYoKQpgYGAKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KaWYgKHNhdmVmaWdzKSBwb3N0c2NyaXB0KHJvb3QoIkFyc2VuaWMvZmlncyIsImFyc2VuaWMuMnZhcmlhYmxlcy5iLnBzIiksCiAgICAgICAgICAgICAgICAgICAgICAgICBoZWlnaHQ9My41LCB3aWR0aD00LCBob3Jpem9udGFsPVRSVUUpCmBgYApgYGB7ciB9CnBsb3QoYygwLG1heCh3ZWxscyRhcnNlbmljLG5hLnJtPVQpKjEuMDIpLCBjKDAsMSksCiAgICAgeGxhYj0iQXJzZW5pYyBjb25jZW50cmF0aW9uIGluIHdlbGwgd2F0ZXIiLCB5bGFiPSJQciAoc3dpdGNoaW5nKSIsCiAgICAgdHlwZT0ibiIsIHhheHM9ImkiLCB5YXhzPSJpIiwgbWdwPWMoMiwuNSwwKSkKcG9pbnRzKHdlbGxzJGFyc2VuaWMsIGppdHRlcl9iaW5hcnkod2VsbHMkc3dpdGNoKSwgcGNoPTIwLCBjZXg9LjEpCmN1cnZlKGludmxvZ2l0KGNvZWYoZml0XzMpWzFdK2NvZWYoZml0XzMpWzJdKjArY29lZihmaXRfMylbM10qeCksIGZyb209MC41LCBsd2Q9LjUsIGFkZD1UKQpjdXJ2ZShpbnZsb2dpdChjb2VmKGZpdF8zKVsxXStjb2VmKGZpdF8zKVsyXSowLjUrY29lZihmaXRfMylbM10qeCksIGZyb209MC41LCBsd2Q9LjUsIGFkZD1UKQp0ZXh0KC41LCAuNzgsICJpZiBkaXN0ID0gMCIsIGFkaj0wLCBjZXg9LjgpCnRleHQoMiwgLjYsICJpZiBkaXN0ID0gNTAiLCBhZGo9MCwgY2V4PS44KQpgYGAKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KaWYgKHNhdmVmaWdzKSBkZXYub2ZmKCkKYGBgCgojIyBJbnRlcmFjdGlvbgoKIyMjIyBGaXQgYSBtb2RlbCB1c2luZyBzY2FsZWQgZGlzdGFuY2UsIGFyc2VuaWMgbGV2ZWwsIGFuZCBhbiBpbnRlcmFjdGlvbgoKYGBge3IgcmVzdWx0cz0naGlkZSd9CmZpdF80IDwtIHN0YW5fZ2xtKHN3aXRjaCB+IGRpc3QxMDAgKyBhcnNlbmljICsgZGlzdDEwMDphcnNlbmljLAogICAgICAgICAgICAgICAgICBmYW1pbHkgPSBiaW5vbWlhbChsaW5rPSJsb2dpdCIpLCBkYXRhID0gd2VsbHMpCmBgYAoKCgpgYGB7ciB9CnByaW50KGZpdF80LCBkaWdpdHM9MikKYGBgCgojIyMjIExPTyBsb2cgc2NvcmUKCmBgYHtyIH0KKGxvbzQgPC0gbG9vKGZpdF80KSkKYGBgCgojIyMjIENvbXBhcmUgbW9kZWxzCgpgYGB7ciB9Cmxvb19jb21wYXJlKGxvbzMsIGxvbzQpCmBgYAoKIyMjIyBDZW50ZXJpbmcgdGhlIGlucHV0IHZhcmlhYmxlcwoKYGBge3IgfQp3ZWxscyRjX2Rpc3QxMDAgPC0gd2VsbHMkZGlzdDEwMCAtIG1lYW4od2VsbHMkZGlzdDEwMCkKd2VsbHMkY19hcnNlbmljIDwtIHdlbGxzJGFyc2VuaWMgLSBtZWFuKHdlbGxzJGFyc2VuaWMpCmBgYApgYGB7ciByZXN1bHRzPSdoaWRlJ30KZml0XzUgPC0gc3Rhbl9nbG0oc3dpdGNoIH4gY19kaXN0MTAwICsgY19hcnNlbmljICsgY19kaXN0MTAwOmNfYXJzZW5pYywKICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gYmlub21pYWwobGluaz0ibG9naXQiKSwgZGF0YSA9IHdlbGxzKQpgYGAKCgoKYGBge3IgfQpwcmludChmaXRfNSwgZGlnaXRzPTIpCmBgYAoKIyMjIyBQbG90IG1vZGVsIGZpdHMKCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmlmIChzYXZlZmlncykgcG9zdHNjcmlwdChyb290KCJBcnNlbmljL2ZpZ3MiLCJhcnNlbmljLmludGVyYWN0LmEucHMiKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGhlaWdodD0zLjUsIHdpZHRoPTQsIGhvcml6b250YWw9VFJVRSkKYGBgCmBgYHtyIH0KcGxvdChjKDAsbWF4KHdlbGxzJGRpc3QsbmEucm09VCkqMS4wMiksIGMoMCwxKSwKICAgICB4bGFiPSJEaXN0YW5jZSAoaW4gbWV0ZXJzKSB0byBuZWFyZXN0IHNhZmUgd2VsbCIsIHlsYWI9IlByIChzd2l0Y2hpbmcpIiwKICAgICB0eXBlPSJuIiwgeGF4cz0iaSIsIHlheHM9ImkiLCBtZ3A9YygyLC41LDApKQpwb2ludHMod2VsbHMkZGlzdCwgaml0dGVyX2JpbmFyeSh3ZWxscyRzd2l0Y2gpLCBwY2g9MjAsIGNleD0uMSkKY3VydmUoaW52bG9naXQoY29lZihmaXRfNClbMV0rY29lZihmaXRfNClbMl0qeC8xMDArY29lZihmaXRfNClbM10qLjUwK2NvZWYoZml0XzQpWzRdKngvMTAwKi41MCksIGx3ZD0uNSwgYWRkPVQpCmN1cnZlKGludmxvZ2l0KGNvZWYoZml0XzQpWzFdK2NvZWYoZml0XzQpWzJdKngvMTAwK2NvZWYoZml0XzQpWzNdKjEuMDArY29lZihmaXRfNClbNF0qeC8xMDAqMS4wMCksIGx3ZD0uNSwgYWRkPVQpCnRleHQgKDUwLCAuMjksICJpZiBBcyA9IDAuNSIsIGFkaj0wLCBjZXg9LjgpCnRleHQgKDc1LCAuNTAsICJpZiBBcyA9IDEuMCIsIGFkaj0wLCBjZXg9LjgpCmBgYApgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQppZiAoc2F2ZWZpZ3MpIGRldi5vZmYoKQpgYGAKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KaWYgKHNhdmVmaWdzKSBwb3N0c2NyaXB0KHJvb3QoIkFyc2VuaWMvZmlncyIsImFyc2VuaWMuaW50ZXJhY3QuYi5wcyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0PTMuNSwgd2lkdGg9NCwgaG9yaXpvbnRhbD1UUlVFKQpgYGAKYGBge3IgfQpwbG90KGMoMCxtYXgod2VsbHMkYXJzZW5pYyxuYS5ybT1UKSoxLjAyKSwgYygwLDEpLAogICAgIHhsYWI9IkFyc2VuaWMgY29uY2VudHJhdGlvbiBpbiB3ZWxsIHdhdGVyIiwgeWxhYj0iUHIgKHN3aXRjaGluZykiLAogICAgIHR5cGU9Im4iLCB4YXhzPSJpIiwgeWF4cz0iaSIsIG1ncD1jKDIsLjUsMCkpCnBvaW50cyh3ZWxscyRhcnNlbmljLCBqaXR0ZXJfYmluYXJ5KHdlbGxzJHN3aXRjaCksIHBjaD0yMCwgY2V4PS4xKQpjdXJ2ZShpbnZsb2dpdChjb2VmKGZpdF80KVsxXStjb2VmKGZpdF80KVsyXSowK2NvZWYoZml0XzQpWzNdKngrY29lZihmaXRfNClbNF0qMCp4KSwgZnJvbT0wLjUsIGx3ZD0uNSwgYWRkPVQpCmN1cnZlKGludmxvZ2l0KGNvZWYoZml0XzQpWzFdK2NvZWYoZml0XzQpWzJdKjAuNStjb2VmKGZpdF80KVszXSp4K2NvZWYoZml0XzQpWzRdKjAuNSp4KSwgZnJvbT0wLjUsIGx3ZD0uNSwgYWRkPVQpCnRleHQgKC41LCAuNzgsICJpZiBkaXN0ID0gMCIsIGFkaj0wLCBjZXg9LjgpCnRleHQgKDIsIC42LCAiaWYgZGlzdCA9IDUwIiwgYWRqPTAsIGNleD0uOCkKYGBgCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmlmIChzYXZlZmlncykgZGV2Lm9mZigpCmBgYAoKIyMgTW9yZSBwcmVkaWN0b3JzCgojIyMjIEFkZGluZyBzb2NpYWwgcHJlZGljdG9ycwoKYGBge3IgcmVzdWx0cz0naGlkZSd9CmZpdF82IDwtIHN0YW5fZ2xtKHN3aXRjaCB+IGRpc3QxMDAgKyBhcnNlbmljICsgZWR1YzQgKyBhc3NvYywKICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gYmlub21pYWwobGluaz0ibG9naXQiKSwgZGF0YSA9IHdlbGxzKQpgYGAKCgoKYGBge3IgfQpwcmludChmaXRfNiwgZGlnaXRzPTIpCmBgYAoKIyMjIyBMT08gbG9nIHNjb3JlCgpgYGB7ciB9Cihsb282IDwtIGxvbyhmaXRfNikpCmBgYAoKIyMjIyBDb21wYXJlIG1vZGVscwoKYGBge3IgfQpsb29fY29tcGFyZShsb280LCBsb282KQpgYGAKCiMjIyMgUmVtb3ZlIGFzc29jCgpgYGB7ciByZXN1bHRzPSdoaWRlJ30KZml0XzcgPC0gc3Rhbl9nbG0oc3dpdGNoIH4gZGlzdDEwMCArIGFyc2VuaWMgKyBlZHVjNCwKICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gYmlub21pYWwobGluaz0ibG9naXQiKSwgZGF0YSA9IHdlbGxzKQpgYGAKCgoKYGBge3IgfQpwcmludChmaXRfNywgZGlnaXRzPTIpCmBgYAoKIyMjIyBMT08gbG9nIHNjb3JlCgpgYGB7ciB9Cihsb283IDwtIGxvbyhmaXRfNykpCmBgYAoKIyMjIyBDb21wYXJlIG1vZGVscwoKYGBge3IgfQpsb29fY29tcGFyZShsb280LCBsb283KQpsb29fY29tcGFyZShsb282LCBsb283KQpgYGAKCiMjIyMgQWRkIGludGVyYWN0aW9ucyB3aXRoIGVkdWNhdGlvbgoKYGBge3IgfQp3ZWxscyRjX2VkdWM0IDwtIHdlbGxzJGVkdWM0IC0gbWVhbih3ZWxscyRlZHVjNCkKYGBgCmBgYHtyIHJlc3VsdHM9J2hpZGUnfQpmaXRfOCA8LSBzdGFuX2dsbShzd2l0Y2ggfiBjX2Rpc3QxMDAgKyBjX2Fyc2VuaWMgKyBjX2VkdWM0ICsKICAgICAgICAgICAgICAgICAgICAgIGNfZGlzdDEwMDpjX2VkdWM0ICsgY19hcnNlbmljOmNfZWR1YzQsCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IGJpbm9taWFsKGxpbms9ImxvZ2l0IiksIGRhdGEgPSB3ZWxscykKYGBgCgoKCmBgYHtyIH0KcHJpbnQoZml0XzgsIGRpZ2l0cz0yKQpgYGAKCiMjIyMgTE9PIGxvZyBzY29yZQoKYGBge3IgfQoobG9vOCA8LSBsb28oZml0XzgsIHNhdmVfcHNpcz1UUlVFKSkKYGBgCgojIyMjIENvbXBhcmUgbW9kZWxzCgpgYGB7ciB9Cmxvb19jb21wYXJlKGxvbzMsIGxvbzgpCmxvb19jb21wYXJlKGxvbzcsIGxvbzgpCmBgYAoKIyMjIyBBdmVyYWdlIGltcHJvdmVtZW50IGluIExPTyBwcmVkaWN0aXZlIHByb2JhYmlsaXRpZXM8YnI+CmZyb20gZGlzdDEwMCArIGFyc2VuaWMgdG8gZGlzdDEwMCArIGFyc2VuaWMgKyBlZHVjNCArIGRpc3QxMDA6ZWR1YzQgKyBhcnNlbmljOmVkdWM0CgpgYGB7ciB9CnByZWQ4IDwtIGxvb19wcmVkaWN0KGZpdF84LCBwc2lzX29iamVjdCA9IGxvbzgkcHNpc19vYmplY3QpJHZhbHVlCnJvdW5kKG1lYW4oYyhwcmVkOFt3ZWxscyRzd2l0Y2g9PTFdLXByZWQzW3dlbGxzJHN3aXRjaD09MV0scHJlZDNbd2VsbHMkc3dpdGNoPT0wXS1wcmVkOFt3ZWxscyRzd2l0Y2g9PTBdKSksMykKYGBgCgojIyBUcmFuc2Zvcm1hdGlvbiBvZiB2YXJpYWJsZQoKIyMjIyBGaXQgYSBtb2RlbCB1c2luZyBzY2FsZWQgZGlzdGFuY2UgYW5kIGxvZyBhcnNlbmljIGxldmVsCgpgYGB7ciB9CndlbGxzJGxvZ19hcnNlbmljIDwtIGxvZyh3ZWxscyRhcnNlbmljKQpgYGAKYGBge3IgcmVzdWx0cz0naGlkZSd9CmZpdF8zYSA8LSBzdGFuX2dsbShzd2l0Y2ggfiBkaXN0MTAwICsgbG9nX2Fyc2VuaWMsIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSwKICAgICAgICAgICAgICAgICAgIGRhdGEgPSB3ZWxscykKYGBgCgoKCmBgYHtyIH0KcHJpbnQoZml0XzNhLCBkaWdpdHM9MikKYGBgCgojIyMjIExPTyBsb2cgc2NvcmUKCmBgYHtyIH0KKGxvbzNhIDwtIGxvbyhmaXRfM2EpKQpgYGAKCiMjIyMgQ29tcGFyZSBtb2RlbHMKCmBgYHtyIH0KbG9vX2NvbXBhcmUobG9vMywgbG9vM2EpCmBgYAoKIyMjIyBGaXQgYSBtb2RlbCB1c2luZyBzY2FsZWQgZGlzdGFuY2UsIGxvZyBhcnNlbmljIGxldmVsLCBhbmQgYW4gaW50ZXJhY3Rpb248YnI+CgpgYGB7ciByZXN1bHRzPSdoaWRlJ30KZml0XzRhIDwtIHN0YW5fZ2xtKHN3aXRjaCB+IGRpc3QxMDAgKyBsb2dfYXJzZW5pYyArIGRpc3QxMDA6bG9nX2Fyc2VuaWMsCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSwgZGF0YSA9IHdlbGxzKQpgYGAKCgoKYGBge3IgfQpwcmludChmaXRfNGEsIGRpZ2l0cz0yKQpgYGAKCiMjIyMgTE9PIGxvZyBzY29yZQoKYGBge3IgfQoobG9vNGEgPC0gbG9vKGZpdF80YSkpCmBgYAoKIyMjIyBDb21wYXJlIG1vZGVscwoKYGBge3IgfQpsb29fY29tcGFyZShsb28zYSwgbG9vNGEpCmBgYAoKIyMjIyBBZGQgaW50ZXJhY3Rpb25zIHdpdGggZWR1Y2F0aW9uCgpgYGB7ciB9CndlbGxzJGNfbG9nX2Fyc2VuaWMgPC0gd2VsbHMkbG9nX2Fyc2VuaWMgLSBtZWFuKHdlbGxzJGxvZ19hcnNlbmljKQpgYGAKYGBge3IgcmVzdWx0cz0naGlkZSd9CmZpdF84YSA8LSBzdGFuX2dsbShzd2l0Y2ggfiBjX2Rpc3QxMDAgKyBjX2xvZ19hcnNlbmljICsgY19lZHVjNCArCiAgICAgICAgICAgICAgICAgICAgICBjX2Rpc3QxMDA6Y19lZHVjNCArIGNfbG9nX2Fyc2VuaWM6Y19lZHVjNCwKICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gYmlub21pYWwobGluaz0ibG9naXQiKSwgZGF0YSA9IHdlbGxzKQpgYGAKCgoKYGBge3IgfQpwcmludChmaXRfOGEsIGRpZ2l0cz0yKQpgYGAKCiMjIyMgTE9PIGxvZyBzY29yZQoKYGBge3IgfQoobG9vOGEgPC0gbG9vKGZpdF84YSwgc2F2ZV9wc2lzPVRSVUUpKQpgYGAKCiMjIyMgQ29tcGFyZSBtb2RlbHMKCmBgYHtyIH0KbG9vX2NvbXBhcmUobG9vOCwgbG9vOGEpCmBgYAoK