Predict respondents' yearly earnings using survey data from 1990. See Chapters 6, 9 and 12 in Regression and Other Stories.


Load packages

library("rprojroot")
root<-has_file(".ROS-Examples-root")$make_fix_file()
library("rstanarm")
library("ggplot2")
library("bayesplot")
theme_set(bayesplot::theme_default(base_family = "sans"))

Set random seed for reproducibility

SEED <- 7783

Load data

earnings <- read.csv(root("Earnings/data","earnings.csv"))
head(earnings)
  height weight male  earn earnk ethnicity education mother_education
1     74    210    1 50000    50     White        16               16
2     66    125    0 60000    60     White        16               16
3     64    126    0 30000    30     White        16               16
4     65    200    0 25000    25     White        17               17
5     63    110    0 50000    50     Other        16               16
6     68    165    0 62000    62     Black        18               18
  father_education walk exercise smokenow tense angry age
1               16    3        3        2     0     0  45
2               16    6        5        1     0     0  58
3               16    8        1        2     1     1  29
4               NA    8        1        2     0     0  57
5               16    5        6        2     0     0  91
6               18    1        1        2     2     2  54
n <- nrow(earnings)
height_jitter_add <- runif(n, -.2, .2)

Normal linear regression

Predict earnings in dollars

fit_0 <- stan_glm(earn ~ height, data=earnings,
                  seed = SEED, refresh = 0)
print(fit_0)
stan_glm
 family:       gaussian [identity]
 formula:      earn ~ height
 observations: 1816
 predictors:   2
------
            Median   MAD_SD  
(Intercept) -85061.4   8786.9
height        1594.5    131.0

Auxiliary parameter(s):
      Median  MAD_SD 
sigma 21696.8   369.2

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

Plot linear model draws

sims_0 <- as.matrix(fit_0)
n_sims <- nrow(sims_0)
keep <- earnings$earn <= 2e5
par(mar=c(3,3,2,0), mgp=c(1.7,.5,0), tck=-.01)
plot((earnings$height + height_jitter_add)[keep], earnings$earn[keep], xlab="height", ylab="earnings", pch=20, yaxt="n", col="gray10", bty="l", cex=.4)
mtext("Fitted linear model", 3, 1)
axis(2, seq(0, 2e5, 1e5), c("0", "100000", "200000"))
for (i in sample(n_sims, 10)){
 curve(sims_0[i,1] + sims_0[i,2]*x, lwd=0.5, col="gray30", add=TRUE)
}
curve(coef(fit_0)[1] + coef(fit_0)[2]*x, add=TRUE)

Plot linear model draws with x-axis extended to 0

keep <- earnings$earn <= 2e5
par(mar=c(3,3,2,0), mgp=c(1.7,.5,0), tck=-.01)
plot((earnings$height + height_jitter_add)[keep], earnings$earn[keep], xlab="height", ylab="earnings", pch=20, yaxt="n", col="gray10", bty="l", cex=.4, xlim=c(0, max(earnings$height)), ylim=c(-1e5, 2.2e5))
mtext("x-axis extended to 0", 3, 1)
axis(2, seq(-1e5, 2e5, 1e5), c("-100000", "0", "100000", "200000"))
for (i in sample(n_sims, 10)){
 curve(sims_0[i,1] + sims_0[i,2]*x, lwd=0.5, col="gray30", add=TRUE)
}
curve(coef(fit_0)[1] + coef(fit_0)[2]*x, add=TRUE)

Predict earnings in thousands dollars

By scaling the earnings, the model coefficients are scaled, but the results don't change otherwise.

earnings$earnk <- earnings$earn/1000
# (earnk is actually already included in the data frame `earnings` for
# convenience for running examples in different arts of the book)
fit_1 <- stan_glm(earnk ~ height, data = earnings,
                  seed = SEED, refresh = 0)
print(fit_1)
stan_glm
 family:       gaussian [identity]
 formula:      earnk ~ height
 observations: 1816
 predictors:   2
------
            Median MAD_SD
(Intercept) -85.1    8.9 
height        1.6    0.1 

Auxiliary parameter(s):
      Median MAD_SD
sigma 21.7    0.4  

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

for plotting scale back to dollar scale

coef1 <- coef(fit_1)*1000

Plot linear model, ggplot version

gg_earnings <- ggplot(subset(earnings, subset=earn<2e5), aes(x = jitter(height, amount=0.2), y = earn)) +
  geom_point(alpha = 0.75) +
  geom_hline(yintercept = 0, color = "darkgray") +
  geom_abline(intercept = coef1[1], slope = coef1[2], size = 1) +
  labs(x = "height", y = "earnings",
       title = "Fitted linear model")
gg_earnings

Plot extrapolation, ggplot version

modifying the gg_earnings object we already created

gg_earnings +
  ylim(-70000, 200000) +
  xlim(0, 80) +
  labs(title = "Extrapolation")

Include male/female

fit_2 <- stan_glm(earnk ~ height + male, data = earnings,
                  seed = SEED, refresh = 0)
print(fit_2)
stan_glm
 family:       gaussian [identity]
 formula:      earnk ~ height + male
 observations: 1816
 predictors:   3
------
            Median MAD_SD
(Intercept) -25.7   12.0 
height        0.6    0.2 
male         10.7    1.5 

Auxiliary parameter(s):
      Median MAD_SD
sigma 21.4    0.4  

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

for plotting scale back to dollar scale

coef2 <- coef(fit_2)*1000

Include male/female, ggplot version

ggplot(earnings, aes(height, earn)) +
  geom_blank() +
  geom_abline(
    intercept = c(coef2[1], coef2[1] + coef2[3]),
    slope = coef2[2],
    color = c("red", "blue")
  ) +
  coord_cartesian(
    ylim = range(predict(fit_2)*1000),
    xlim = range(earnings$height)
  ) +
  annotate(
    "text",
    x = c(68, 68),
    y = c(coef2[1] + coef2[2] * 65, coef2[1] + coef2[3] + coef2[2] * 65),
    label = c("women:\ny = -11 000 + 450x", "men:\ny = -2 000 + 450x"),
    color = c("red", "blue"),
    size = 5, hjust = 0
  ) +
  labs(
    x = "height",
    y = "predicted earnings",
    title = "Fitted regression, displayed as\nseparate lines for men and women"
  )

Include interaction

fit_3 <- stan_glm(earnk ~ height + male + height:male, data = earnings,
                  seed = SEED, refresh = 0)
print(fit_3)
stan_glm
 family:       gaussian [identity]
 formula:      earnk ~ height + male + height:male
 observations: 1816
 predictors:   4
------
            Median MAD_SD
(Intercept)  -9.3   15.2 
height        0.4    0.2 
male        -29.3   24.3 
height:male   0.6    0.4 

Auxiliary parameter(s):
      Median MAD_SD
sigma 21.4    0.3  

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

for plotting scale back to dollar scale

coef3 <- coef(fit_3)*1000

Include interaction, ggplot version

ggplot(subset(earnings, subset=earn>0), aes(height, earn)) +
  geom_blank() +
  geom_abline(
    intercept = c(coef3[1], coef3[1] + coef3[3]),
    slope = c(coef3[2], coef3[2] + coef3[4]),
    color = c("red", "blue")
  ) +
  coord_cartesian(
    ylim = range(predict(fit_3)*1000),
    xlim = range(earnings$height)
  ) +
  annotate(
    "text",
    x = c(62, 68),
    y = c(coef3[1] + coef3[2] * 80, coef3[1]+coef3[3] + (coef3[2]+coef3[4])*66),
    label = c("women:\ny = -7 000 + 180x", "men:\ny = -22 000 + 740x"),
    color = c("red", "blue"),
    size = 5, hjust = 0
  ) +
  labs(
    x = "height",
    y = "predicted earnings",
    title = "Fitted regression with interactions,\nseparate lines for men and women"
  )

Linear regression on log scale

Models on log scale

logmodel_1 <- stan_glm(log(earn) ~ height, data = earnings,
                       subset = earn>0,
                       seed = SEED, refresh = 0)
print(logmodel_1, digits=2)
stan_glm
 family:       gaussian [identity]
 formula:      log(earn) ~ height
 observations: 1629
 predictors:   2
------
            Median MAD_SD
(Intercept) 5.90   0.37  
height      0.06   0.01  

Auxiliary parameter(s):
      Median MAD_SD
sigma 0.88   0.01  

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

Model on log10 scale

log10model_1 <- stan_glm(log10(earn) ~ height, data = earnings,
                         subset = earn>0,
                         seed = SEED, refresh = 0)
print(log10model_1, digits=3)
stan_glm
 family:       gaussian [identity]
 formula:      log10(earn) ~ height
 observations: 1629
 predictors:   2
------
            Median MAD_SD
(Intercept) 2.571  0.165 
height      0.025  0.002 

Auxiliary parameter(s):
      Median MAD_SD
sigma 0.381  0.007 

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

Model on log scale with two predictors

logmodel_2 <- stan_glm(log(earn) ~ height + male, data = earnings,
                       subset = earn>0,
                       seed = SEED, refresh = 0)
print(logmodel_2, digits=2)
stan_glm
 family:       gaussian [identity]
 formula:      log(earn) ~ height + male
 observations: 1629
 predictors:   3
------
            Median MAD_SD
(Intercept) 7.97   0.49  
height      0.02   0.01  
male        0.37   0.06  

Auxiliary parameter(s):
      Median MAD_SD
sigma 0.87   0.01  

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

Model on log scale for the target and one predictor

loglogmodel_2 <- stan_glm(log(earn) ~ log(height) + male, data = earnings,
                          subset = earn>0,
                          seed = SEED, refresh = 0)
print(loglogmodel_2, digits=2)
stan_glm
 family:       gaussian [identity]
 formula:      log(earn) ~ log(height) + male
 observations: 1629
 predictors:   3
------
            Median MAD_SD
(Intercept) 2.83   2.20  
log(height) 1.60   0.53  
male        0.37   0.06  

Auxiliary parameter(s):
      Median MAD_SD
sigma 0.87   0.02  

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

Model on log scale with two predictors and interaction

logmodel_3 <- stan_glm(log(earn) ~ height + male + height:male, data = earnings,
                       subset = earn>0,
                       seed = SEED, refresh = 0)
print(logmodel_3, digits=2)
stan_glm
 family:       gaussian [identity]
 formula:      log(earn) ~ height + male + height:male
 observations: 1629
 predictors:   4
------
            Median MAD_SD
(Intercept)  8.53   0.65 
height       0.02   0.01 
male        -0.87   0.99 
height:male  0.02   0.01 

Auxiliary parameter(s):
      Median MAD_SD
sigma 0.87   0.02  

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

Model on log scale with standardized interaction

earnings$z_height <- with(earnings, (height - mean(height))/sd(height))
logmodel_3a <- stan_glm(log(earn) ~ z_height + male + z_height:male,
                        data = earnings, subset = earn>0,
                        seed = SEED, refresh = 0)
print(logmodel_3a, digits=2)
stan_glm
 family:       gaussian [identity]
 formula:      log(earn) ~ z_height + male + z_height:male
 observations: 1629
 predictors:   4
------
              Median MAD_SD
(Intercept)   9.54   0.04  
z_height      0.06   0.04  
male          0.35   0.06  
z_height:male 0.08   0.06  

Auxiliary parameter(s):
      Median MAD_SD
sigma 0.87   0.02  

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

PLot log models

get posterior draws

sims <- as.matrix(logmodel_1)
n_sims <- nrow(sims)

Plot log model on log scale

keep <- earnings$earn > 0
par(mar=c(3,3,2,0), mgp=c(1.7,.5,0), tck=-.01)
plot((earnings$height + height_jitter_add)[keep], log(earnings$earn)[keep], xlab="height", ylab="log (earnings)", pch=20, yaxt="n", col="gray10", bty="l", cex=.4)
mtext("Log regression plotted on log scale", 3, 1)
axis(2, seq(6,12,2))
for (i in sample(n_sims, 10)){
 curve(sims[i,1] + sims[i,2]*x, lwd=0.5, col="gray30", add=TRUE)
}
curve(coef(logmodel_1)[1] + coef(logmodel_1)[2]*x, add=TRUE)

Plot posterior draws of linear model on log scale, ggplot version

sims_display <- sample(n_sims, 10)
ggplot(subset(earnings, subset=earn>0), aes(height, log(earn))) +
  geom_jitter(height = 0, width = 0.25) +
  geom_abline(
    intercept = sims[sims_display, 1],
    slope = sims[sims_display, 2],
    color = "darkgray"
  ) +
  geom_abline(
    intercept = coef(logmodel_1)[1],
    slope = coef(logmodel_1)[2]
  ) +
  labs(
    x = "height",
    y = "log(earnings)",
    title = "Log regression, plotted on log scale"
  )

Plot log model on linear scale

keep <- earnings$earn > 0 & earnings$earn <= 2e5
par(mar=c(3,3,2,0), mgp=c(1.7,.5,0), tck=-.01)
plot((earnings$height + height_jitter_add)[keep], earnings$earn[keep], xlab="height", ylab="earnings", pch=20, yaxt="n", col="gray10", bty="l", cex=.4)
mtext("Log regression plotted on original scale", 3, 1)
axis(2, seq(0, 2e5, 1e5), c("0", "100000", "200000"))
for (i in sample(n_sims, 10)){
 curve(exp(sims[i,1] + sims[i,2]*x), lwd=0.5, col="gray30", add=TRUE)
}
curve(exp(coef(logmodel_1)[1] + coef(logmodel_1)[2]*x), add=TRUE)

Posterior predictive checking

Posterior predictive checking for model in linear scale

for fair comparison refit the linear scale model only for non.zero earnings

yrep_0 <- posterior_predict(fit_0)
n_sims <- nrow(yrep_0)
sims_display <- sample(n_sims, 100)
ppc_0 <- ppc_dens_overlay(earnings$earn, yrep_0[sims_display,]) +
  theme(axis.line.y = element_blank())

Posterior predictive checking for model in log scale

yrep_log_1 <- posterior_predict(logmodel_1)
n_sims <- nrow(yrep_log_1)
sims_display <- sample(n_sims, 100)
ppc_log_1 <- ppc_dens_overlay(log(earnings$earn[earnings$earn>0]), yrep_log_1[sims_display,]) +
    theme(axis.line.y = element_blank())
bpg <- bayesplot_grid(
  ppc_0, ppc_log_1,
  grid_args = list(ncol = 2),
  titles = c("earn", "log(earn)"))
bpg

Posterior predictive checking for model in linear scale

fit_2b <- stan_glm(earn ~ height + male, data = earnings, subset=earn>0,
                   seed = SEED, refresh = 0)
yrep_2 <- posterior_predict(fit_2b)
n_sims <- nrow(yrep_2)
sims_display <- sample(n_sims, 100)
ppc_dens_overlay(earnings$earn[earnings$earn>0], yrep_2[sims_display,])

Posterior predictive checking for model in log scale

yrep_log_2 <- posterior_predict(logmodel_2)
n_sims <- nrow(yrep_log_2)
sims_display <- sample(n_sims, 100)
ppc_dens_overlay(log(earnings$earn[earnings$earn>0]), yrep_log_2[sims_display,])

Posterior predictive checking for model in log-log scale

yrep_loglog_2 <- posterior_predict(loglogmodel_2)
n_sims <- nrow(yrep_loglog_2)
sims_display <- sample(n_sims, 100)
ppc_dens_overlay(log(earnings$earn[earnings$earn>0]), yrep_loglog_2[sims_display,])

LS0tCnRpdGxlOiAiUmVncmVzc2lvbiBhbmQgT3RoZXIgU3RvcmllczogRWFybmluZ3MiCmF1dGhvcjogIkFuZHJldyBHZWxtYW4sIEplbm5pZmVyIEhpbGwsIEFraSBWZWh0YXJpIgpkYXRlOiAiYHIgZm9ybWF0KFN5cy5EYXRlKCkpYCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0aGVtZTogcmVhZGFibGUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAyCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKLS0tClByZWRpY3QgcmVzcG9uZGVudHMnIHllYXJseSBlYXJuaW5ncyB1c2luZyBzdXJ2ZXkgZGF0YSBmcm9tCjE5OTAuIFNlZSBDaGFwdGVycyA2LCA5IGFuZCAxMiBpbiBSZWdyZXNzaW9uIGFuZCBPdGhlciBTdG9yaWVzLgoKLS0tLS0tLS0tLS0tLQoKCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQobWVzc2FnZT1GQUxTRSwgZXJyb3I9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGNvbW1lbnQ9TkEpCiMgc3dpdGNoIHRoaXMgdG8gVFJVRSB0byBzYXZlIGZpZ3VyZXMgaW4gc2VwYXJhdGUgZmlsZXMKc2F2ZWZpZ3MgPC0gRkFMU0UKYGBgCgojIyMjIExvYWQgcGFja2FnZXMKCmBgYHtyIH0KbGlicmFyeSgicnByb2pyb290IikKcm9vdDwtaGFzX2ZpbGUoIi5ST1MtRXhhbXBsZXMtcm9vdCIpJG1ha2VfZml4X2ZpbGUoKQpsaWJyYXJ5KCJyc3RhbmFybSIpCmxpYnJhcnkoImdncGxvdDIiKQpsaWJyYXJ5KCJiYXllc3Bsb3QiKQp0aGVtZV9zZXQoYmF5ZXNwbG90Ojp0aGVtZV9kZWZhdWx0KGJhc2VfZmFtaWx5ID0gInNhbnMiKSkKYGBgCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CiMgZ3JheXNjYWxlIGZpZ3VyZXMgZm9yIHRoZSBib29rCmlmIChzYXZlZmlncykgY29sb3Jfc2NoZW1lX3NldChzY2hlbWUgPSAiZ3JheSIpCmBgYAoKU2V0IHJhbmRvbSBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkKCmBgYHtyIH0KU0VFRCA8LSA3NzgzCmBgYAoKIyMjIyBMb2FkIGRhdGEKCmBgYHtyIH0KZWFybmluZ3MgPC0gcmVhZC5jc3Yocm9vdCgiRWFybmluZ3MvZGF0YSIsImVhcm5pbmdzLmNzdiIpKQpoZWFkKGVhcm5pbmdzKQpuIDwtIG5yb3coZWFybmluZ3MpCmhlaWdodF9qaXR0ZXJfYWRkIDwtIHJ1bmlmKG4sIC0uMiwgLjIpCmBgYAoKIyMgTm9ybWFsIGxpbmVhciByZWdyZXNzaW9uCgojIyMjIFByZWRpY3QgZWFybmluZ3MgaW4gZG9sbGFycwoKYGBge3IgfQpmaXRfMCA8LSBzdGFuX2dsbShlYXJuIH4gaGVpZ2h0LCBkYXRhPWVhcm5pbmdzLAogICAgICAgICAgICAgICAgICBzZWVkID0gU0VFRCwgcmVmcmVzaCA9IDApCnByaW50KGZpdF8wKQpgYGAKCiMjIyMgUGxvdCBsaW5lYXIgbW9kZWwgZHJhd3MKCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmlmIChzYXZlZmlncykgcGRmKHJvb3QoIkVhcm5pbmdzL2ZpZ3MiLCJoZWlnaHRzLnNpbXBsZTBhLnBkZiIpLCBoZWlnaHQ9Mywgd2lkdGg9NC4yLCBjb2xvcm1vZGVsPSJncmF5IikKYGBgCmBgYHtyIH0Kc2ltc18wIDwtIGFzLm1hdHJpeChmaXRfMCkKbl9zaW1zIDwtIG5yb3coc2ltc18wKQprZWVwIDwtIGVhcm5pbmdzJGVhcm4gPD0gMmU1CnBhcihtYXI9YygzLDMsMiwwKSwgbWdwPWMoMS43LC41LDApLCB0Y2s9LS4wMSkKcGxvdCgoZWFybmluZ3MkaGVpZ2h0ICsgaGVpZ2h0X2ppdHRlcl9hZGQpW2tlZXBdLCBlYXJuaW5ncyRlYXJuW2tlZXBdLCB4bGFiPSJoZWlnaHQiLCB5bGFiPSJlYXJuaW5ncyIsIHBjaD0yMCwgeWF4dD0ibiIsIGNvbD0iZ3JheTEwIiwgYnR5PSJsIiwgY2V4PS40KQptdGV4dCgiRml0dGVkIGxpbmVhciBtb2RlbCIsIDMsIDEpCmF4aXMoMiwgc2VxKDAsIDJlNSwgMWU1KSwgYygiMCIsICIxMDAwMDAiLCAiMjAwMDAwIikpCmZvciAoaSBpbiBzYW1wbGUobl9zaW1zLCAxMCkpewogY3VydmUoc2ltc18wW2ksMV0gKyBzaW1zXzBbaSwyXSp4LCBsd2Q9MC41LCBjb2w9ImdyYXkzMCIsIGFkZD1UUlVFKQp9CmN1cnZlKGNvZWYoZml0XzApWzFdICsgY29lZihmaXRfMClbMl0qeCwgYWRkPVRSVUUpCmBgYApgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpkZXYub2ZmKCkKYGBgCgojIyMjIFBsb3QgbGluZWFyIG1vZGVsIGRyYXdzIHdpdGggeC1heGlzIGV4dGVuZGVkIHRvIDAKCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmlmIChzYXZlZmlncykgcGRmKHJvb3QoIkVhcm5pbmdzL2ZpZ3MiLCJoZWlnaHRzLmludGVyY2VwdC5wZGYiKSwgaGVpZ2h0PTMsIHdpZHRoPTQuMiwgY29sb3Jtb2RlbD0iZ3JheSIpCmBgYApgYGB7ciB9CmtlZXAgPC0gZWFybmluZ3MkZWFybiA8PSAyZTUKcGFyKG1hcj1jKDMsMywyLDApLCBtZ3A9YygxLjcsLjUsMCksIHRjaz0tLjAxKQpwbG90KChlYXJuaW5ncyRoZWlnaHQgKyBoZWlnaHRfaml0dGVyX2FkZClba2VlcF0sIGVhcm5pbmdzJGVhcm5ba2VlcF0sIHhsYWI9ImhlaWdodCIsIHlsYWI9ImVhcm5pbmdzIiwgcGNoPTIwLCB5YXh0PSJuIiwgY29sPSJncmF5MTAiLCBidHk9ImwiLCBjZXg9LjQsIHhsaW09YygwLCBtYXgoZWFybmluZ3MkaGVpZ2h0KSksIHlsaW09YygtMWU1LCAyLjJlNSkpCm10ZXh0KCJ4LWF4aXMgZXh0ZW5kZWQgdG8gMCIsIDMsIDEpCmF4aXMoMiwgc2VxKC0xZTUsIDJlNSwgMWU1KSwgYygiLTEwMDAwMCIsICIwIiwgIjEwMDAwMCIsICIyMDAwMDAiKSkKZm9yIChpIGluIHNhbXBsZShuX3NpbXMsIDEwKSl7CiBjdXJ2ZShzaW1zXzBbaSwxXSArIHNpbXNfMFtpLDJdKngsIGx3ZD0wLjUsIGNvbD0iZ3JheTMwIiwgYWRkPVRSVUUpCn0KY3VydmUoY29lZihmaXRfMClbMV0gKyBjb2VmKGZpdF8wKVsyXSp4LCBhZGQ9VFJVRSkKYGBgCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmlmIChzYXZlZmlncykgZGV2Lm9mZigpCmBgYAoKIyMjIyBQcmVkaWN0IGVhcm5pbmdzIGluIHRob3VzYW5kcyBkb2xsYXJzCgpCeSBzY2FsaW5nIHRoZSBlYXJuaW5ncywgdGhlIG1vZGVsIGNvZWZmaWNpZW50cyBhcmUgc2NhbGVkLCBidXQgdGhlCnJlc3VsdHMgZG9uJ3QgY2hhbmdlIG90aGVyd2lzZS4KCmBgYHtyIH0KZWFybmluZ3MkZWFybmsgPC0gZWFybmluZ3MkZWFybi8xMDAwCiMgKGVhcm5rIGlzIGFjdHVhbGx5IGFscmVhZHkgaW5jbHVkZWQgaW4gdGhlIGRhdGEgZnJhbWUgYGVhcm5pbmdzYCBmb3IKIyBjb252ZW5pZW5jZSBmb3IgcnVubmluZyBleGFtcGxlcyBpbiBkaWZmZXJlbnQgYXJ0cyBvZiB0aGUgYm9vaykKZml0XzEgPC0gc3Rhbl9nbG0oZWFybmsgfiBoZWlnaHQsIGRhdGEgPSBlYXJuaW5ncywKICAgICAgICAgICAgICAgICAgc2VlZCA9IFNFRUQsIHJlZnJlc2ggPSAwKQpwcmludChmaXRfMSkKYGBgCgpmb3IgcGxvdHRpbmcgc2NhbGUgYmFjayB0byBkb2xsYXIgc2NhbGUKCmBgYHtyIH0KY29lZjEgPC0gY29lZihmaXRfMSkqMTAwMApgYGAKCiMjIyMgUGxvdCBsaW5lYXIgbW9kZWwsIGdncGxvdCB2ZXJzaW9uCgpgYGB7ciB9CmdnX2Vhcm5pbmdzIDwtIGdncGxvdChzdWJzZXQoZWFybmluZ3MsIHN1YnNldD1lYXJuPDJlNSksIGFlcyh4ID0gaml0dGVyKGhlaWdodCwgYW1vdW50PTAuMiksIHkgPSBlYXJuKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjc1KSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3IgPSAiZGFya2dyYXkiKSArCiAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gY29lZjFbMV0sIHNsb3BlID0gY29lZjFbMl0sIHNpemUgPSAxKSArCiAgbGFicyh4ID0gImhlaWdodCIsIHkgPSAiZWFybmluZ3MiLAogICAgICAgdGl0bGUgPSAiRml0dGVkIGxpbmVhciBtb2RlbCIpCmdnX2Vhcm5pbmdzCmBgYAoKIyMjIyBQbG90IGV4dHJhcG9sYXRpb24sIGdncGxvdCB2ZXJzaW9uCm1vZGlmeWluZyB0aGUgZ2dfZWFybmluZ3Mgb2JqZWN0IHdlIGFscmVhZHkgY3JlYXRlZAoKYGBge3IgfQpnZ19lYXJuaW5ncyArCiAgeWxpbSgtNzAwMDAsIDIwMDAwMCkgKwogIHhsaW0oMCwgODApICsKICBsYWJzKHRpdGxlID0gIkV4dHJhcG9sYXRpb24iKQpgYGAKCiMjIyMgSW5jbHVkZSBtYWxlL2ZlbWFsZQoKYGBge3IgfQpmaXRfMiA8LSBzdGFuX2dsbShlYXJuayB+IGhlaWdodCArIG1hbGUsIGRhdGEgPSBlYXJuaW5ncywKICAgICAgICAgICAgICAgICAgc2VlZCA9IFNFRUQsIHJlZnJlc2ggPSAwKQpwcmludChmaXRfMikKYGBgCgpmb3IgcGxvdHRpbmcgc2NhbGUgYmFjayB0byBkb2xsYXIgc2NhbGUKCmBgYHtyIH0KY29lZjIgPC0gY29lZihmaXRfMikqMTAwMApgYGAKCiMjIyMgSW5jbHVkZSBtYWxlL2ZlbWFsZSwgZ2dwbG90IHZlcnNpb24KCmBgYHtyIH0KZ2dwbG90KGVhcm5pbmdzLCBhZXMoaGVpZ2h0LCBlYXJuKSkgKwogIGdlb21fYmxhbmsoKSArCiAgZ2VvbV9hYmxpbmUoCiAgICBpbnRlcmNlcHQgPSBjKGNvZWYyWzFdLCBjb2VmMlsxXSArIGNvZWYyWzNdKSwKICAgIHNsb3BlID0gY29lZjJbMl0sCiAgICBjb2xvciA9IGMoInJlZCIsICJibHVlIikKICApICsKICBjb29yZF9jYXJ0ZXNpYW4oCiAgICB5bGltID0gcmFuZ2UocHJlZGljdChmaXRfMikqMTAwMCksCiAgICB4bGltID0gcmFuZ2UoZWFybmluZ3MkaGVpZ2h0KQogICkgKwogIGFubm90YXRlKAogICAgInRleHQiLAogICAgeCA9IGMoNjgsIDY4KSwKICAgIHkgPSBjKGNvZWYyWzFdICsgY29lZjJbMl0gKiA2NSwgY29lZjJbMV0gKyBjb2VmMlszXSArIGNvZWYyWzJdICogNjUpLAogICAgbGFiZWwgPSBjKCJ3b21lbjpcbnkgPSAtMTEgMDAwICsgNDUweCIsICJtZW46XG55ID0gLTIgMDAwICsgNDUweCIpLAogICAgY29sb3IgPSBjKCJyZWQiLCAiYmx1ZSIpLAogICAgc2l6ZSA9IDUsIGhqdXN0ID0gMAogICkgKwogIGxhYnMoCiAgICB4ID0gImhlaWdodCIsCiAgICB5ID0gInByZWRpY3RlZCBlYXJuaW5ncyIsCiAgICB0aXRsZSA9ICJGaXR0ZWQgcmVncmVzc2lvbiwgZGlzcGxheWVkIGFzXG5zZXBhcmF0ZSBsaW5lcyBmb3IgbWVuIGFuZCB3b21lbiIKICApCmBgYAoKIyMjIyBJbmNsdWRlIGludGVyYWN0aW9uCgpgYGB7ciB9CmZpdF8zIDwtIHN0YW5fZ2xtKGVhcm5rIH4gaGVpZ2h0ICsgbWFsZSArIGhlaWdodDptYWxlLCBkYXRhID0gZWFybmluZ3MsCiAgICAgICAgICAgICAgICAgIHNlZWQgPSBTRUVELCByZWZyZXNoID0gMCkKcHJpbnQoZml0XzMpCmBgYAoKZm9yIHBsb3R0aW5nIHNjYWxlIGJhY2sgdG8gZG9sbGFyIHNjYWxlCgpgYGB7ciB9CmNvZWYzIDwtIGNvZWYoZml0XzMpKjEwMDAKYGBgCgojIyMjIEluY2x1ZGUgaW50ZXJhY3Rpb24sIGdncGxvdCB2ZXJzaW9uCgpgYGB7ciB9CmdncGxvdChzdWJzZXQoZWFybmluZ3MsIHN1YnNldD1lYXJuPjApLCBhZXMoaGVpZ2h0LCBlYXJuKSkgKwogIGdlb21fYmxhbmsoKSArCiAgZ2VvbV9hYmxpbmUoCiAgICBpbnRlcmNlcHQgPSBjKGNvZWYzWzFdLCBjb2VmM1sxXSArIGNvZWYzWzNdKSwKICAgIHNsb3BlID0gYyhjb2VmM1syXSwgY29lZjNbMl0gKyBjb2VmM1s0XSksCiAgICBjb2xvciA9IGMoInJlZCIsICJibHVlIikKICApICsKICBjb29yZF9jYXJ0ZXNpYW4oCiAgICB5bGltID0gcmFuZ2UocHJlZGljdChmaXRfMykqMTAwMCksCiAgICB4bGltID0gcmFuZ2UoZWFybmluZ3MkaGVpZ2h0KQogICkgKwogIGFubm90YXRlKAogICAgInRleHQiLAogICAgeCA9IGMoNjIsIDY4KSwKICAgIHkgPSBjKGNvZWYzWzFdICsgY29lZjNbMl0gKiA4MCwgY29lZjNbMV0rY29lZjNbM10gKyAoY29lZjNbMl0rY29lZjNbNF0pKjY2KSwKICAgIGxhYmVsID0gYygid29tZW46XG55ID0gLTcgMDAwICsgMTgweCIsICJtZW46XG55ID0gLTIyIDAwMCArIDc0MHgiKSwKICAgIGNvbG9yID0gYygicmVkIiwgImJsdWUiKSwKICAgIHNpemUgPSA1LCBoanVzdCA9IDAKICApICsKICBsYWJzKAogICAgeCA9ICJoZWlnaHQiLAogICAgeSA9ICJwcmVkaWN0ZWQgZWFybmluZ3MiLAogICAgdGl0bGUgPSAiRml0dGVkIHJlZ3Jlc3Npb24gd2l0aCBpbnRlcmFjdGlvbnMsXG5zZXBhcmF0ZSBsaW5lcyBmb3IgbWVuIGFuZCB3b21lbiIKICApCmBgYAoKIyMgTGluZWFyIHJlZ3Jlc3Npb24gb24gbG9nIHNjYWxlCiMjIyMgTW9kZWxzIG9uIGxvZyBzY2FsZQoKYGBge3IgfQpsb2dtb2RlbF8xIDwtIHN0YW5fZ2xtKGxvZyhlYXJuKSB+IGhlaWdodCwgZGF0YSA9IGVhcm5pbmdzLAogICAgICAgICAgICAgICAgICAgICAgIHN1YnNldCA9IGVhcm4+MCwKICAgICAgICAgICAgICAgICAgICAgICBzZWVkID0gU0VFRCwgcmVmcmVzaCA9IDApCnByaW50KGxvZ21vZGVsXzEsIGRpZ2l0cz0yKQpgYGAKCiMjIyMgTW9kZWwgb24gbG9nMTAgc2NhbGUKCmBgYHtyIH0KbG9nMTBtb2RlbF8xIDwtIHN0YW5fZ2xtKGxvZzEwKGVhcm4pIH4gaGVpZ2h0LCBkYXRhID0gZWFybmluZ3MsCiAgICAgICAgICAgICAgICAgICAgICAgICBzdWJzZXQgPSBlYXJuPjAsCiAgICAgICAgICAgICAgICAgICAgICAgICBzZWVkID0gU0VFRCwgcmVmcmVzaCA9IDApCnByaW50KGxvZzEwbW9kZWxfMSwgZGlnaXRzPTMpCmBgYAoKIyMjIyBNb2RlbCBvbiBsb2cgc2NhbGUgd2l0aCB0d28gcHJlZGljdG9ycwoKYGBge3IgfQpsb2dtb2RlbF8yIDwtIHN0YW5fZ2xtKGxvZyhlYXJuKSB+IGhlaWdodCArIG1hbGUsIGRhdGEgPSBlYXJuaW5ncywKICAgICAgICAgICAgICAgICAgICAgICBzdWJzZXQgPSBlYXJuPjAsCiAgICAgICAgICAgICAgICAgICAgICAgc2VlZCA9IFNFRUQsIHJlZnJlc2ggPSAwKQpwcmludChsb2dtb2RlbF8yLCBkaWdpdHM9MikKYGBgCgojIyMjIE1vZGVsIG9uIGxvZyBzY2FsZSBmb3IgdGhlIHRhcmdldCBhbmQgb25lIHByZWRpY3RvcgoKYGBge3IgfQpsb2dsb2dtb2RlbF8yIDwtIHN0YW5fZ2xtKGxvZyhlYXJuKSB+IGxvZyhoZWlnaHQpICsgbWFsZSwgZGF0YSA9IGVhcm5pbmdzLAogICAgICAgICAgICAgICAgICAgICAgICAgIHN1YnNldCA9IGVhcm4+MCwKICAgICAgICAgICAgICAgICAgICAgICAgICBzZWVkID0gU0VFRCwgcmVmcmVzaCA9IDApCnByaW50KGxvZ2xvZ21vZGVsXzIsIGRpZ2l0cz0yKQpgYGAKCiMjIyMgTW9kZWwgb24gbG9nIHNjYWxlIHdpdGggdHdvIHByZWRpY3RvcnMgYW5kIGludGVyYWN0aW9uCgpgYGB7ciB9CmxvZ21vZGVsXzMgPC0gc3Rhbl9nbG0obG9nKGVhcm4pIH4gaGVpZ2h0ICsgbWFsZSArIGhlaWdodDptYWxlLCBkYXRhID0gZWFybmluZ3MsCiAgICAgICAgICAgICAgICAgICAgICAgc3Vic2V0ID0gZWFybj4wLAogICAgICAgICAgICAgICAgICAgICAgIHNlZWQgPSBTRUVELCByZWZyZXNoID0gMCkKcHJpbnQobG9nbW9kZWxfMywgZGlnaXRzPTIpCmBgYAoKIyMjIyBNb2RlbCBvbiBsb2cgc2NhbGUgd2l0aCBzdGFuZGFyZGl6ZWQgaW50ZXJhY3Rpb24KCmBgYHtyIH0KZWFybmluZ3Mkel9oZWlnaHQgPC0gd2l0aChlYXJuaW5ncywgKGhlaWdodCAtIG1lYW4oaGVpZ2h0KSkvc2QoaGVpZ2h0KSkKbG9nbW9kZWxfM2EgPC0gc3Rhbl9nbG0obG9nKGVhcm4pIH4gel9oZWlnaHQgKyBtYWxlICsgel9oZWlnaHQ6bWFsZSwKICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGVhcm5pbmdzLCBzdWJzZXQgPSBlYXJuPjAsCiAgICAgICAgICAgICAgICAgICAgICAgIHNlZWQgPSBTRUVELCByZWZyZXNoID0gMCkKcHJpbnQobG9nbW9kZWxfM2EsIGRpZ2l0cz0yKQpgYGAKCiMjIyMgUExvdCBsb2cgbW9kZWxzCmdldCBwb3N0ZXJpb3IgZHJhd3MKCmBgYHtyIH0Kc2ltcyA8LSBhcy5tYXRyaXgobG9nbW9kZWxfMSkKbl9zaW1zIDwtIG5yb3coc2ltcykKYGBgCgojIyMjIFBsb3QgbG9nIG1vZGVsIG9uIGxvZyBzY2FsZQoKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KaWYgKHNhdmVmaWdzKSBwZGYocm9vdCgiRWFybmluZ3MvZmlncyIsImhlaWdodHMubG9nMWEucGRmIiksIGhlaWdodD0zLCB3aWR0aD00LjIsIGNvbG9ybW9kZWw9ImdyYXkiKQpgYGAKYGBge3IgfQprZWVwIDwtIGVhcm5pbmdzJGVhcm4gPiAwCnBhcihtYXI9YygzLDMsMiwwKSwgbWdwPWMoMS43LC41LDApLCB0Y2s9LS4wMSkKcGxvdCgoZWFybmluZ3MkaGVpZ2h0ICsgaGVpZ2h0X2ppdHRlcl9hZGQpW2tlZXBdLCBsb2coZWFybmluZ3MkZWFybilba2VlcF0sIHhsYWI9ImhlaWdodCIsIHlsYWI9ImxvZyAoZWFybmluZ3MpIiwgcGNoPTIwLCB5YXh0PSJuIiwgY29sPSJncmF5MTAiLCBidHk9ImwiLCBjZXg9LjQpCm10ZXh0KCJMb2cgcmVncmVzc2lvbiBwbG90dGVkIG9uIGxvZyBzY2FsZSIsIDMsIDEpCmF4aXMoMiwgc2VxKDYsMTIsMikpCmZvciAoaSBpbiBzYW1wbGUobl9zaW1zLCAxMCkpewogY3VydmUoc2ltc1tpLDFdICsgc2ltc1tpLDJdKngsIGx3ZD0wLjUsIGNvbD0iZ3JheTMwIiwgYWRkPVRSVUUpCn0KY3VydmUoY29lZihsb2dtb2RlbF8xKVsxXSArIGNvZWYobG9nbW9kZWxfMSlbMl0qeCwgYWRkPVRSVUUpCmBgYApgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQppZiAoc2F2ZWZpZ3MpIGRldi5vZmYoKQpgYGAKCiMjIyMgUGxvdCBwb3N0ZXJpb3IgZHJhd3Mgb2YgbGluZWFyIG1vZGVsIG9uIGxvZyBzY2FsZSwgZ2dwbG90IHZlcnNpb24KCmBgYHtyIH0Kc2ltc19kaXNwbGF5IDwtIHNhbXBsZShuX3NpbXMsIDEwKQpnZ3Bsb3Qoc3Vic2V0KGVhcm5pbmdzLCBzdWJzZXQ9ZWFybj4wKSwgYWVzKGhlaWdodCwgbG9nKGVhcm4pKSkgKwogIGdlb21faml0dGVyKGhlaWdodCA9IDAsIHdpZHRoID0gMC4yNSkgKwogIGdlb21fYWJsaW5lKAogICAgaW50ZXJjZXB0ID0gc2ltc1tzaW1zX2Rpc3BsYXksIDFdLAogICAgc2xvcGUgPSBzaW1zW3NpbXNfZGlzcGxheSwgMl0sCiAgICBjb2xvciA9ICJkYXJrZ3JheSIKICApICsKICBnZW9tX2FibGluZSgKICAgIGludGVyY2VwdCA9IGNvZWYobG9nbW9kZWxfMSlbMV0sCiAgICBzbG9wZSA9IGNvZWYobG9nbW9kZWxfMSlbMl0KICApICsKICBsYWJzKAogICAgeCA9ICJoZWlnaHQiLAogICAgeSA9ICJsb2coZWFybmluZ3MpIiwKICAgIHRpdGxlID0gIkxvZyByZWdyZXNzaW9uLCBwbG90dGVkIG9uIGxvZyBzY2FsZSIKICApCmBgYAoKIyMjIyBQbG90IGxvZyBtb2RlbCBvbiBsaW5lYXIgc2NhbGUKCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmlmIChzYXZlZmlncykgcGRmKHJvb3QoIkVhcm5pbmdzL2ZpZ3MiLCJoZWlnaHRzLmxvZzFiLnBkZiIpLCBoZWlnaHQ9Mywgd2lkdGg9NC4yLCBjb2xvcm1vZGVsPSJncmF5IikKYGBgCmBgYHtyIH0Ka2VlcCA8LSBlYXJuaW5ncyRlYXJuID4gMCAmIGVhcm5pbmdzJGVhcm4gPD0gMmU1CnBhcihtYXI9YygzLDMsMiwwKSwgbWdwPWMoMS43LC41LDApLCB0Y2s9LS4wMSkKcGxvdCgoZWFybmluZ3MkaGVpZ2h0ICsgaGVpZ2h0X2ppdHRlcl9hZGQpW2tlZXBdLCBlYXJuaW5ncyRlYXJuW2tlZXBdLCB4bGFiPSJoZWlnaHQiLCB5bGFiPSJlYXJuaW5ncyIsIHBjaD0yMCwgeWF4dD0ibiIsIGNvbD0iZ3JheTEwIiwgYnR5PSJsIiwgY2V4PS40KQptdGV4dCgiTG9nIHJlZ3Jlc3Npb24gcGxvdHRlZCBvbiBvcmlnaW5hbCBzY2FsZSIsIDMsIDEpCmF4aXMoMiwgc2VxKDAsIDJlNSwgMWU1KSwgYygiMCIsICIxMDAwMDAiLCAiMjAwMDAwIikpCmZvciAoaSBpbiBzYW1wbGUobl9zaW1zLCAxMCkpewogY3VydmUoZXhwKHNpbXNbaSwxXSArIHNpbXNbaSwyXSp4KSwgbHdkPTAuNSwgY29sPSJncmF5MzAiLCBhZGQ9VFJVRSkKfQpjdXJ2ZShleHAoY29lZihsb2dtb2RlbF8xKVsxXSArIGNvZWYobG9nbW9kZWxfMSlbMl0qeCksIGFkZD1UUlVFKQpgYGAKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KaWYgKHNhdmVmaWdzKSBkZXYub2ZmKCkKYGBgCgojIyBQb3N0ZXJpb3IgcHJlZGljdGl2ZSBjaGVja2luZwojIyMjIFBvc3RlcmlvciBwcmVkaWN0aXZlIGNoZWNraW5nIGZvciBtb2RlbCBpbiBsaW5lYXIgc2NhbGU8YnI+CmZvciBmYWlyIGNvbXBhcmlzb24gcmVmaXQgdGhlIGxpbmVhciBzY2FsZSBtb2RlbCBvbmx5IGZvciBub24uemVybyBlYXJuaW5ncwoKYGBge3IgfQp5cmVwXzAgPC0gcG9zdGVyaW9yX3ByZWRpY3QoZml0XzApCm5fc2ltcyA8LSBucm93KHlyZXBfMCkKc2ltc19kaXNwbGF5IDwtIHNhbXBsZShuX3NpbXMsIDEwMCkKcHBjXzAgPC0gcHBjX2RlbnNfb3ZlcmxheShlYXJuaW5ncyRlYXJuLCB5cmVwXzBbc2ltc19kaXNwbGF5LF0pICsKICB0aGVtZShheGlzLmxpbmUueSA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgojIyMjIFBvc3RlcmlvciBwcmVkaWN0aXZlIGNoZWNraW5nIGZvciBtb2RlbCBpbiBsb2cgc2NhbGUKCmBgYHtyIH0KeXJlcF9sb2dfMSA8LSBwb3N0ZXJpb3JfcHJlZGljdChsb2dtb2RlbF8xKQpuX3NpbXMgPC0gbnJvdyh5cmVwX2xvZ18xKQpzaW1zX2Rpc3BsYXkgPC0gc2FtcGxlKG5fc2ltcywgMTAwKQpwcGNfbG9nXzEgPC0gcHBjX2RlbnNfb3ZlcmxheShsb2coZWFybmluZ3MkZWFybltlYXJuaW5ncyRlYXJuPjBdKSwgeXJlcF9sb2dfMVtzaW1zX2Rpc3BsYXksXSkgKwogICAgdGhlbWUoYXhpcy5saW5lLnkgPSBlbGVtZW50X2JsYW5rKCkpCmJwZyA8LSBiYXllc3Bsb3RfZ3JpZCgKICBwcGNfMCwgcHBjX2xvZ18xLAogIGdyaWRfYXJncyA9IGxpc3QobmNvbCA9IDIpLAogIHRpdGxlcyA9IGMoImVhcm4iLCAibG9nKGVhcm4pIikpCmJwZwpgYGAKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KZ2dzYXZlKHJvb3QoIkVhcm5pbmdzL2ZpZ3MiLCJlYXJuaW5nc19wcGMucGRmIiksIGJwZywgaGVpZ2h0PTMsIHdpZHRoPTksIGNvbG9ybW9kZWw9ImdyYXkiKQpgYGAKCiMjIyMgUG9zdGVyaW9yIHByZWRpY3RpdmUgY2hlY2tpbmcgZm9yIG1vZGVsIGluIGxpbmVhciBzY2FsZQoKYGBge3IgfQpmaXRfMmIgPC0gc3Rhbl9nbG0oZWFybiB+IGhlaWdodCArIG1hbGUsIGRhdGEgPSBlYXJuaW5ncywgc3Vic2V0PWVhcm4+MCwKICAgICAgICAgICAgICAgICAgIHNlZWQgPSBTRUVELCByZWZyZXNoID0gMCkKeXJlcF8yIDwtIHBvc3Rlcmlvcl9wcmVkaWN0KGZpdF8yYikKbl9zaW1zIDwtIG5yb3coeXJlcF8yKQpzaW1zX2Rpc3BsYXkgPC0gc2FtcGxlKG5fc2ltcywgMTAwKQpwcGNfZGVuc19vdmVybGF5KGVhcm5pbmdzJGVhcm5bZWFybmluZ3MkZWFybj4wXSwgeXJlcF8yW3NpbXNfZGlzcGxheSxdKQpgYGAKCiMjIyMgUG9zdGVyaW9yIHByZWRpY3RpdmUgY2hlY2tpbmcgZm9yIG1vZGVsIGluIGxvZyBzY2FsZQoKYGBge3IgfQp5cmVwX2xvZ18yIDwtIHBvc3Rlcmlvcl9wcmVkaWN0KGxvZ21vZGVsXzIpCm5fc2ltcyA8LSBucm93KHlyZXBfbG9nXzIpCnNpbXNfZGlzcGxheSA8LSBzYW1wbGUobl9zaW1zLCAxMDApCnBwY19kZW5zX292ZXJsYXkobG9nKGVhcm5pbmdzJGVhcm5bZWFybmluZ3MkZWFybj4wXSksIHlyZXBfbG9nXzJbc2ltc19kaXNwbGF5LF0pCmBgYAoKIyMjIyBQb3N0ZXJpb3IgcHJlZGljdGl2ZSBjaGVja2luZyBmb3IgbW9kZWwgaW4gbG9nLWxvZyBzY2FsZQoKYGBge3IgfQp5cmVwX2xvZ2xvZ18yIDwtIHBvc3Rlcmlvcl9wcmVkaWN0KGxvZ2xvZ21vZGVsXzIpCm5fc2ltcyA8LSBucm93KHlyZXBfbG9nbG9nXzIpCnNpbXNfZGlzcGxheSA8LSBzYW1wbGUobl9zaW1zLCAxMDApCnBwY19kZW5zX292ZXJsYXkobG9nKGVhcm5pbmdzJGVhcm5bZWFybmluZ3MkZWFybj4wXSksIHlyZXBfbG9nbG9nXzJbc2ltc19kaXNwbGF5LF0pCmBgYAoK