Here I take some of the code from ElectionsEconomy/hibbs.R The original goal was just to explore using stan_glm() for fitting simple linear regression models.

A couple of sidebars arose from this example.

Load packages

library("here")
root<-here
library("rstanarm")
library("arm")
library("ggplot2")
library("bayesplot")
theme_set(bayesplot::theme_default(base_family = "sans"))

Load data

This data was used to formulate a Bread & Peace model of voting in presidential elections in relation to the economy.

The variables are a bit peculiar:

hibbs <- read.table(root("ElectionsEconomy/data","hibbs.dat"), header=TRUE)
head(hibbs)
  year growth  vote inc_party_candidate other_candidate
1 1952   2.40 44.60           Stevenson      Eisenhower
2 1956   2.89 57.76          Eisenhower       Stevenson
3 1960   0.85 49.91               Nixon         Kennedy
4 1964   4.21 61.34             Johnson       Goldwater
5 1968   3.02 49.60            Humphrey           Nixon
6 1972   3.62 61.79               Nixon        McGovern

Add some info on party. Just do this to identify the party of the incumbant candidate

Dems <- c("Stevenson", "Johnson", "Humphrey", "Carter", "Clinton", "Gore", "Obama" )

incParty <- 
  ifelse(hibbs$inc_party_candidate %in% Dems, "Dem", "Rep")

Add this as another column in `hibbs``

hibbs <- cbind(hibbs, incParty)
head(hibbs,4)
  year growth  vote inc_party_candidate other_candidate incParty
1 1952   2.40 44.60           Stevenson      Eisenhower      Dem
2 1956   2.89 57.76          Eisenhower       Stevenson      Rep
3 1960   0.85 49.91               Nixon         Kennedy      Rep
4 1964   4.21 61.34             Johnson       Goldwater      Dem

Plots, similar to fig 7.2

Start with a basic plot, then add (+) other layers

This is a bit of prep work to see if a linear model is reasonable

p1 <- 
ggplot(aes(x=growth, y=vote, label=year), data=hibbs) +
  labs(
    x = "Avg recent growth in personal income",
    y ="Incumbent party's vote share"
  )

Just points & year labels

p1 + geom_point() + geom_text()

Different regimes? Different potential explanations?

Color the points by incumbent party. Something interesting here. Is there something difference when the incumbent is a Democrat? (Should probably reverse the colors for Dem & Rep.)

p1 + geom_point() + geom_text(aes(color=incParty))

Join points in order of x? This makes no sense.

p1 + geom_text() + geom_line()

Try a linear smooth

p1 + geom_text() + 
  geom_smooth(method="lm", formula = y ~ x)

Try a loess smooth. How much evidence for non-linearity?

p1 + geom_text() + 
  geom_smooth(method="loess")

Fit Separate lines by party

p1 + geom_text(aes(color=incParty)) +
  geom_smooth(aes(color=incParty, fill=incParty), 
              method="lm", formula = y ~ x)

Linear regression, using stan_glm()

The option refresh = 0 supresses the default Stan sampling progress output. This is useful for small data with fast computation. For more complex models and bigger data, it can be useful to see the progress.

M1 <- stan_glm(vote ~ growth, data = hibbs, refresh = 0)

Print default summary of the fitted model

print(M1)
stan_glm
 family:       gaussian [identity]
 formula:      vote ~ growth
 observations: 16
 predictors:   2
------
            Median MAD_SD
(Intercept) 46.3    1.7  
growth       3.1    0.7  

Auxiliary parameter(s):
      Median MAD_SD
sigma 3.9    0.7   

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

Print summary of the priors used. This is handy, because it might not be clear what stan_glm is doing.

prior_summary(M1)
Priors for model 'M1' 
------
Intercept (after predictors centered)
  Specified prior:
    ~ normal(location = 52, scale = 2.5)
  Adjusted prior:
    ~ normal(location = 52, scale = 14)

Coefficients
  Specified prior:
    ~ normal(location = 0, scale = 2.5)
  Adjusted prior:
    ~ normal(location = 0, scale = 10)

Auxiliary (sigma)
  Specified prior:
    ~ exponential(rate = 1)
  Adjusted prior:
    ~ exponential(rate = 0.18)
------
See help('prior_summary.stanreg') for more details

Posterior interval

For reporting, use bayesian poster intervals rather than normal theory CIs

round(posterior_interval(M1),1)
              5%  95%
(Intercept) 43.3 49.2
growth       1.8  4.3
sigma        2.9  5.6

What’s in this stan_glm object?

Hmm, looks sort of like a lm object, but with a lot more stuff.

names(M1)
 [1] "coefficients"      "ses"               "fitted.values"    
 [4] "linear.predictors" "residuals"         "df.residual"      
 [7] "covmat"            "y"                 "model"            
[10] "data"              "family"            "offset"           
[13] "weights"           "prior.weights"     "contrasts"        
[16] "na.action"         "formula"           "terms"            
[19] "prior.info"        "algorithm"         "stan_summary"     
[22] "stanfit"           "rstan_version"     "call"             
[25] "stan_function"     "compute_mean_PPD"  "xlevels"          

Compare with lm

m1 <- lm(vote ~ growth, data = hibbs)
m1

Call:
lm(formula = vote ~ growth, data = hibbs)

Coefficients:
(Intercept)       growth  
     46.248        3.061  
cbind(stan=coef(M1), lm=coef(m1))
                 stan        lm
(Intercept) 46.270779 46.247648
growth       3.057011  3.060528

Illustrate computations

Extract the simulations

This seems like magic. as.matrix() returns the coefficients and residual standard deviation from all 4000 simulations of the posterior distribution.

sims <- as.matrix(M1)
a <- sims[,1]
b <- sims[,2]
sigma <- sims[,3]
n_sims <- nrow(sims)

Median and mean absolute deviation (MAD_SD)

Median <- apply(sims, 2, median)
MAD_SD <- apply(sims, 2, mad)
print(cbind(Median, MAD_SD))
               Median    MAD_SD
(Intercept) 46.270779 1.7060718
growth       3.057011 0.7237720
sigma        3.891913 0.7489519

Plot coefficients

Add data 68 and 95% ellipses. Hmm, there seem to be much more than 5% outside the larger ellipse.

ggplot(data.frame(a = sims[, 1], b = sims[, 2]), aes(a, b)) +
  geom_point(size = 1) +
  stat_ellipse(color="blue", size=1.5, level=0.95) +
  stat_ellipse(color="blue", size=2,   level=0.68) +
  geom_vline(xintercept = mean(sims[, 1]), color="blue") +
  geom_hline(yintercept = mean(sims[, 2]), color="blue") +
  labs(title = "Posterior draws of the regression coefficients a, b")

Plot regression lines

Cute graphics tricks:

  • geom_abline() used to plot both individual lines and their average.
  • Plot the points twice, with a white background forgreater visibility
ggplot(hibbs, aes(x = growth, y = vote)) +
  geom_abline(                # individual lines
    intercept = sims[1:100, 1],
    slope = sims[1:100, 2],
    size = 0.1
  ) +
  geom_abline(                 # overall line
    intercept = mean(sims[, 1]),
    slope = mean(sims[, 2]),
    color="blue",
    size = 2
  ) +
  geom_point(color = "white", size = 3) +
  geom_point(color = "blue", size = 2) +
  labs(
    x = "Avg recent growth in personal income",
    y ="Incumbent party's vote share",
    title = "Data and 100 posterior draws of the line, y = a + bx"
  ) +
  scale_x_continuous(
    limits = c(-.7, 4.5),
    breaks = 0:4,
    labels = paste(0:4, "%", sep = "")
  ) +
  scale_y_continuous(
    limits = c(43, 63),
    breaks = seq(45, 60, 5),
    labels = paste(seq(45, 60, 5), "%", sep = "")
  )

IycgLS0tDQojJyB0aXRsZTogIkxpbmVhciBSZWdyZXNzaW9uIEV4YW1wbGU6IEVsZWN0aW9ucyBFY29ub215Ig0KIycgYXV0aG9yOiAiTWljaGFlbCBGcmllbmRseSINCiMnIGRhdGU6ICJgciBmb3JtYXQoU3lzLkRhdGUoKSlgIg0KIycgb3V0cHV0Og0KIycgICBodG1sX2RvY3VtZW50Og0KIycgICAgIHRoZW1lOiByZWFkYWJsZQ0KIycgICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiMnIC0tLQ0KDQojJyBIZXJlIEkgdGFrZSBzb21lIG9mIHRoZSBjb2RlIGZyb20gYEVsZWN0aW9uc0Vjb25vbXkvaGliYnMuUmANCiMnIFRoZSBvcmlnaW5hbCBnb2FsIHdhcyBqdXN0IHRvIGV4cGxvcmUgdXNpbmcgYHN0YW5fZ2xtKClgIGZvciBmaXR0aW5nIHNpbXBsZQ0KIycgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWxzLg0KIycgDQojJyBBIGNvdXBsZSBvZiBzaWRlYmFycyBhcm9zZSBmcm9tIHRoaXMgZXhhbXBsZS4NCiMnIA0KIycgDQoNCiMrIHNldHVwLCBpbmNsdWRlPUZBTFNFDQprbml0cjo6b3B0c19jaHVuayRzZXQobWVzc2FnZT1GQUxTRSwgZXJyb3I9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGNvbW1lbnQ9TkEpDQoNCiMnICMjIyMgTG9hZCBwYWNrYWdlcw0KbGlicmFyeSgiaGVyZSIpDQpyb290PC1oZXJlDQpsaWJyYXJ5KCJyc3RhbmFybSIpDQpsaWJyYXJ5KCJhcm0iKQ0KbGlicmFyeSgiZ2dwbG90MiIpDQpsaWJyYXJ5KCJiYXllc3Bsb3QiKQ0KdGhlbWVfc2V0KGJheWVzcGxvdDo6dGhlbWVfZGVmYXVsdChiYXNlX2ZhbWlseSA9ICJzYW5zIikpDQoNCiMnICMjIyMgTG9hZCBkYXRhDQojJyANCiMnIFRoaXMgZGF0YSB3YXMgdXNlZCB0byBmb3JtdWxhdGUgYSAqQnJlYWQgJiBQZWFjZSogbW9kZWwgb2Ygdm90aW5nDQojJyBpbiBwcmVzaWRlbnRpYWwgZWxlY3Rpb25zIGluIHJlbGF0aW9uIHRvIHRoZSBlY29ub215Lg0KIycgDQojJyBUaGUgdmFyaWFibGVzIGFyZSBhIGJpdCBwZWN1bGlhcjogDQojJyANCiMnICogYHZvdGVgOiB0aGUgcGVyY2VudCB2b3RlIGZvciB0aGUgaW5jdW1iZW50IHBhcnR5DQojJyAqIGBncm93dGhgOiBhdmVyYWdlIHJlY2VudCBncm93dGggaW4gcGVyc29uYWwgaW5jb21lIHNpbmNlIHRoZSBsYXN0IGVsZWN0aW9uDQojJyANCmhpYmJzIDwtIHJlYWQudGFibGUocm9vdCgiRWxlY3Rpb25zRWNvbm9teS9kYXRhIiwiaGliYnMuZGF0IiksIGhlYWRlcj1UUlVFKQ0KaGVhZChoaWJicykNCg0KIycgQWRkIHNvbWUgaW5mbyBvbiBwYXJ0eS4gSnVzdCBkbyB0aGlzIHRvIGlkZW50aWZ5IHRoZSBwYXJ0eSBvZiB0aGUgaW5jdW1iYW50DQojJyBjYW5kaWRhdGUNCiMnIA0KRGVtcyA8LSBjKCJTdGV2ZW5zb24iLCAiSm9obnNvbiIsICJIdW1waHJleSIsICJDYXJ0ZXIiLCAiQ2xpbnRvbiIsICJHb3JlIiwgIk9iYW1hIiApDQoNCmluY1BhcnR5IDwtIA0KICBpZmVsc2UoaGliYnMkaW5jX3BhcnR5X2NhbmRpZGF0ZSAlaW4lIERlbXMsICJEZW0iLCAiUmVwIikNCg0KIycgQWRkIHRoaXMgYXMgYW5vdGhlciBjb2x1bW4gaW4gYGhpYmJzYGANCmhpYmJzIDwtIGNiaW5kKGhpYmJzLCBpbmNQYXJ0eSkNCmhlYWQoaGliYnMsNCkNCg0KDQojJyAjIyBQbG90cywgc2ltaWxhciB0byBmaWcgNy4yDQojJyANCg0KIycgIyMjIyBTdGFydCB3aXRoIGEgYmFzaWMgcGxvdCwgdGhlbiBhZGQgKGArYCkgb3RoZXIgbGF5ZXJzDQojJyBUaGlzIGlzIGEgYml0IG9mIHByZXAgd29yayB0byBzZWUgaWYgYSBsaW5lYXIgbW9kZWwgaXMgcmVhc29uYWJsZSAgDQpwMSA8LSANCmdncGxvdChhZXMoeD1ncm93dGgsIHk9dm90ZSwgbGFiZWw9eWVhciksIGRhdGE9aGliYnMpICsNCiAgbGFicygNCiAgICB4ID0gIkF2ZyByZWNlbnQgZ3Jvd3RoIGluIHBlcnNvbmFsIGluY29tZSIsDQogICAgeSA9IkluY3VtYmVudCBwYXJ0eSdzIHZvdGUgc2hhcmUiDQogICkNCg0KIycgSnVzdCBwb2ludHMgJiB5ZWFyIGxhYmVscw0KcDEgKyBnZW9tX3BvaW50KCkgKyBnZW9tX3RleHQoKQ0KDQojJyBEaWZmZXJlbnQgcmVnaW1lcz8gRGlmZmVyZW50IHBvdGVudGlhbCBleHBsYW5hdGlvbnM/DQojJyANCiMnIENvbG9yIHRoZSBwb2ludHMgYnkgaW5jdW1iZW50IHBhcnR5LiBTb21ldGhpbmcgaW50ZXJlc3RpbmcgaGVyZS4NCiMnIElzIHRoZXJlIHNvbWV0aGluZyBkaWZmZXJlbmNlIHdoZW4gdGhlIGluY3VtYmVudCBpcyBhIERlbW9jcmF0Pw0KIycgKFNob3VsZCBwcm9iYWJseSByZXZlcnNlIHRoZSBjb2xvcnMgZm9yIERlbSAmIFJlcC4pDQpwMSArIGdlb21fcG9pbnQoKSArIGdlb21fdGV4dChhZXMoY29sb3I9aW5jUGFydHkpKQ0KDQojJyBKb2luIHBvaW50cyBpbiBvcmRlciBvZiB4PyAgVGhpcyBtYWtlcyBubyBzZW5zZS4NCnAxICsgZ2VvbV90ZXh0KCkgKyBnZW9tX2xpbmUoKQ0KDQojJyBUcnkgYSBsaW5lYXIgc21vb3RoDQpwMSArIGdlb21fdGV4dCgpICsgDQogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iLCBmb3JtdWxhID0geSB+IHgpDQogDQojJyBUcnkgYSBsb2VzcyBzbW9vdGguICBIb3cgbXVjaCBldmlkZW5jZSBmb3Igbm9uLWxpbmVhcml0eT8NCnAxICsgZ2VvbV90ZXh0KCkgKyANCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsb2VzcyIpDQoNCiMnIEZpdCBTZXBhcmF0ZSBsaW5lcyBieSBwYXJ0eQ0KcDEgKyBnZW9tX3RleHQoYWVzKGNvbG9yPWluY1BhcnR5KSkgKw0KICBnZW9tX3Ntb290aChhZXMoY29sb3I9aW5jUGFydHksIGZpbGw9aW5jUGFydHkpLCANCiAgICAgICAgICAgICAgbWV0aG9kPSJsbSIsIGZvcm11bGEgPSB5IH4geCkNCg0KDQojJyAjIyBMaW5lYXIgcmVncmVzc2lvbiwgdXNpbmcgYHN0YW5fZ2xtKClgDQojJyANCiMnIFRoZSBvcHRpb24gYHJlZnJlc2ggPSAwYCBzdXByZXNzZXMgdGhlIGRlZmF1bHQgU3RhbiBzYW1wbGluZw0KIycgcHJvZ3Jlc3Mgb3V0cHV0LiBUaGlzIGlzIHVzZWZ1bCBmb3Igc21hbGwgZGF0YSB3aXRoIGZhc3QNCiMnIGNvbXB1dGF0aW9uLiBGb3IgbW9yZSBjb21wbGV4IG1vZGVscyBhbmQgYmlnZ2VyIGRhdGEsIGl0IGNhbiBiZQ0KIycgdXNlZnVsIHRvIHNlZSB0aGUgcHJvZ3Jlc3MuDQojJyANCk0xIDwtIHN0YW5fZ2xtKHZvdGUgfiBncm93dGgsIGRhdGEgPSBoaWJicywgcmVmcmVzaCA9IDApDQoNCiMnIFByaW50IGRlZmF1bHQgc3VtbWFyeSBvZiB0aGUgZml0dGVkIG1vZGVsDQpwcmludChNMSkNCiMnIFByaW50IHN1bW1hcnkgb2YgdGhlIHByaW9ycyB1c2VkLiBUaGlzIGlzIGhhbmR5LCBiZWNhdXNlIGl0IG1pZ2h0DQojJyBub3QgYmUgY2xlYXIgd2hhdCBgc3Rhbl9nbG1gIGlzIGRvaW5nLg0KcHJpb3Jfc3VtbWFyeShNMSkNCg0KIycgIyMjIyBQb3N0ZXJpb3IgaW50ZXJ2YWwNCiMnIEZvciByZXBvcnRpbmcsIHVzZSBiYXllc2lhbiBwb3N0ZXIgaW50ZXJ2YWxzIHJhdGhlciB0aGFuIG5vcm1hbCB0aGVvcnkgQ0lzDQpyb3VuZChwb3N0ZXJpb3JfaW50ZXJ2YWwoTTEpLDEpDQoNCg0KIycgIyMjIyBXaGF0J3MgaW4gdGhpcyBgc3Rhbl9nbG1gIG9iamVjdD8NCiMnIEhtbSwgbG9va3Mgc29ydCBvZiBsaWtlIGEgYGxtYCBvYmplY3QsIGJ1dCB3aXRoIGEgbG90IG1vcmUgc3R1ZmYuDQoNCm5hbWVzKE0xKQ0KDQojJyAjIyBDb21wYXJlIHdpdGggbG0NCg0KbTEgPC0gbG0odm90ZSB+IGdyb3d0aCwgZGF0YSA9IGhpYmJzKQ0KbTENCg0KY2JpbmQoc3Rhbj1jb2VmKE0xKSwgbG09Y29lZihtMSkpDQoNCiMnICMjIElsbHVzdHJhdGUgY29tcHV0YXRpb25zDQoNCiMnICMjIyMgRXh0cmFjdCB0aGUgc2ltdWxhdGlvbnMNCiMnIFRoaXMgc2VlbXMgbGlrZSBtYWdpYy4gIGBhcy5tYXRyaXgoKWAgcmV0dXJucyB0aGUgY29lZmZpY2llbnRzIGFuZA0KIycgcmVzaWR1YWwgc3RhbmRhcmQgZGV2aWF0aW9uIGZyb20gYWxsIDQwMDAgc2ltdWxhdGlvbnMgb2YgdGhlDQojJyBwb3N0ZXJpb3IgZGlzdHJpYnV0aW9uLg0KIycgDQpzaW1zIDwtIGFzLm1hdHJpeChNMSkNCmEgPC0gc2ltc1ssMV0NCmIgPC0gc2ltc1ssMl0NCnNpZ21hIDwtIHNpbXNbLDNdDQpuX3NpbXMgPC0gbnJvdyhzaW1zKQ0KDQojJyAjIyMjIE1lZGlhbiBhbmQgbWVhbiBhYnNvbHV0ZSBkZXZpYXRpb24gKE1BRF9TRCkNCk1lZGlhbiA8LSBhcHBseShzaW1zLCAyLCBtZWRpYW4pDQpNQURfU0QgPC0gYXBwbHkoc2ltcywgMiwgbWFkKQ0KcHJpbnQoY2JpbmQoTWVkaWFuLCBNQURfU0QpKQ0KDQojJyAjIyMjIFBsb3QgY29lZmZpY2llbnRzDQojJyBBZGQgZGF0YSA2OCBhbmQgOTUlIGVsbGlwc2VzLg0KIycgSG1tLCB0aGVyZSBzZWVtIHRvIGJlIG11Y2ggbW9yZSB0aGFuIDUlIG91dHNpZGUgdGhlIGxhcmdlciBlbGxpcHNlLg0KDQpnZ3Bsb3QoZGF0YS5mcmFtZShhID0gc2ltc1ssIDFdLCBiID0gc2ltc1ssIDJdKSwgYWVzKGEsIGIpKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDEpICsNCiAgc3RhdF9lbGxpcHNlKGNvbG9yPSJibHVlIiwgc2l6ZT0xLjUsIGxldmVsPTAuOTUpICsNCiAgc3RhdF9lbGxpcHNlKGNvbG9yPSJibHVlIiwgc2l6ZT0yLCAgIGxldmVsPTAuNjgpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbWVhbihzaW1zWywgMV0pLCBjb2xvcj0iYmx1ZSIpICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gbWVhbihzaW1zWywgMl0pLCBjb2xvcj0iYmx1ZSIpICsNCiAgbGFicyh0aXRsZSA9ICJQb3N0ZXJpb3IgZHJhd3Mgb2YgdGhlIHJlZ3Jlc3Npb24gY29lZmZpY2llbnRzIGEsIGIiKQ0KDQojJyAjIyMjIFBsb3QgcmVncmVzc2lvbiBsaW5lcw0KIycgQ3V0ZSBncmFwaGljcyB0cmlja3M6DQojJyANCiMnICAqIGBnZW9tX2FibGluZSgpYCB1c2VkIHRvIHBsb3QgYm90aCBpbmRpdmlkdWFsIGxpbmVzIGFuZCB0aGVpciBhdmVyYWdlLiANCiMnICAqIFBsb3QgdGhlIHBvaW50cyB0d2ljZSwgd2l0aCBhIHdoaXRlIGJhY2tncm91bmQgZm9yZ3JlYXRlciB2aXNpYmlsaXR5DQoNCmdncGxvdChoaWJicywgYWVzKHggPSBncm93dGgsIHkgPSB2b3RlKSkgKw0KICBnZW9tX2FibGluZSggICAgICAgICAgICAgICAgIyBpbmRpdmlkdWFsIGxpbmVzDQogICAgaW50ZXJjZXB0ID0gc2ltc1sxOjEwMCwgMV0sDQogICAgc2xvcGUgPSBzaW1zWzE6MTAwLCAyXSwNCiAgICBzaXplID0gMC4xDQogICkgKw0KICBnZW9tX2FibGluZSggICAgICAgICAgICAgICAgICMgb3ZlcmFsbCBsaW5lDQogICAgaW50ZXJjZXB0ID0gbWVhbihzaW1zWywgMV0pLA0KICAgIHNsb3BlID0gbWVhbihzaW1zWywgMl0pLA0KICAgIGNvbG9yPSJibHVlIiwNCiAgICBzaXplID0gMg0KICApICsNCiAgZ2VvbV9wb2ludChjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSAzKSArDQogIGdlb21fcG9pbnQoY29sb3IgPSAiYmx1ZSIsIHNpemUgPSAyKSArDQogIGxhYnMoDQogICAgeCA9ICJBdmcgcmVjZW50IGdyb3d0aCBpbiBwZXJzb25hbCBpbmNvbWUiLA0KICAgIHkgPSJJbmN1bWJlbnQgcGFydHkncyB2b3RlIHNoYXJlIiwNCiAgICB0aXRsZSA9ICJEYXRhIGFuZCAxMDAgcG9zdGVyaW9yIGRyYXdzIG9mIHRoZSBsaW5lLCB5ID0gYSArIGJ4Ig0KICApICsNCiAgc2NhbGVfeF9jb250aW51b3VzKA0KICAgIGxpbWl0cyA9IGMoLS43LCA0LjUpLA0KICAgIGJyZWFrcyA9IDA6NCwNCiAgICBsYWJlbHMgPSBwYXN0ZSgwOjQsICIlIiwgc2VwID0gIiIpDQogICkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoDQogICAgbGltaXRzID0gYyg0MywgNjMpLA0KICAgIGJyZWFrcyA9IHNlcSg0NSwgNjAsIDUpLA0KICAgIGxhYmVscyA9IHBhc3RlKHNlcSg0NSwgNjAsIDUpLCAiJSIsIHNlcCA9ICIiKQ0KICApDQoNCg0K