Predicting the yields of mesquite bushes. See Chapter 12 in Regression and Other Stories.


Load packages

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

Set random seed for reproducability

SEED <- 4587

Load data

mesquite <- read.table(root("Mesquite/data","mesquite.dat"), header=TRUE)
head(mesquite)
  obs group diam1 diam2 total_height canopy_height density weight
1   1   MCD   1.8  1.15         1.30          1.00       1  401.3
2   2   MCD   1.7  1.35         1.35          1.33       1  513.7
3   3   MCD   2.8  2.55         2.16          0.60       1 1179.2
4   4   MCD   1.3  0.85         1.80          1.20       1  308.0
5   5   MCD   3.3  1.90         1.55          1.05       1  855.2
6   6   MCD   1.4  1.40         1.20          1.00       1  268.7

Predict weight given all the predictors

fit_1 <- stan_glm(weight ~ diam1 + diam2 + canopy_height + total_height +
                    density + group, data=mesquite, seed=SEED, refresh=0)
print(fit_1)
stan_glm
 family:       gaussian [identity]
 formula:      weight ~ diam1 + diam2 + canopy_height + total_height + density + 
       group
 observations: 46
 predictors:   7
------
              Median  MAD_SD 
(Intercept)   -1087.1   177.1
diam1           186.9   114.4
diam2           370.4   124.6
canopy_height   349.3   211.1
total_height    -99.9   188.7
density         131.4    34.7
groupMCD        363.5    99.6

Auxiliary parameter(s):
      Median MAD_SD
sigma 273.9   30.8 

------
* For help interpreting the printed output see ?print.stanreg
* For info on the priors used see ?prior_summary.stanreg
(loo_1 <- loo(fit_1))

Computed from 4000 by 46 log-likelihood matrix

         Estimate   SE
elpd_loo   -334.1 12.9
p_loo        15.9  8.8
looic       668.3 25.8
------
Monte Carlo SE of elpd_loo is NA.

Pareto k diagnostic values:
                         Count Pct.    Min. n_eff
(-Inf, 0.5]   (good)     43    93.5%   698       
 (0.5, 0.7]   (ok)        1     2.2%   102       
   (0.7, 1]   (bad)       1     2.2%   113       
   (1, Inf)   (very bad)  1     2.2%   2         
See help('pareto-k-diagnostic') for details.

We get warnings about high Pareto k values, which indicates that the importance sampling approximation used in loo is in this case unreliable. We thus use more robust K-fold-CV.

kfold_1 <- kfold(fit_1, K=10)
kfold_1

Based on 10-fold cross-validation

           Estimate   SE
elpd_kfold   -347.4 26.9
p_kfold          NA   NA
kfoldic       694.8 53.9

Predict log(weight) given log transformed predictors

fit_2 <- stan_glm(log(weight) ~ log(diam1) + log(diam2) + log(canopy_height) +
                      log(total_height) + log(density) + group,
                  data=mesquite, seed=SEED, refresh=0)
(loo_2 <- loo(fit_2))

Computed from 4000 by 46 log-likelihood matrix

         Estimate   SE
elpd_loo    -19.2  5.3
p_loo         7.5  1.5
looic        38.5 10.7
------
Monte Carlo SE of elpd_loo is NA.

Pareto k diagnostic values:
                         Count Pct.    Min. n_eff
(-Inf, 0.5]   (good)     44    95.7%   945       
 (0.5, 0.7]   (ok)        1     2.2%   374       
   (0.7, 1]   (bad)       1     2.2%   555       
   (1, Inf)   (very bad)  0     0.0%   <NA>      
See help('pareto-k-diagnostic') for details.

Jacobian correction to make the models comparable

Jacobian correction is needed as model 1 is modeling y and model 2 is modeling log(y).

loo_2_with_jacobian <- loo_2
loo_2_with_jacobian$pointwise[,1] <- loo_2_with_jacobian$pointwise[,1]-
                                     log(mesquite$weight)
(elpd_loo_2_with_jacobian <- sum(loo_2_with_jacobian$pointwise[,1]))
[1] -291.5386

there will be a warning that the target data is not the same same, this is ok because we have the jacobian correction

loo_compare(kfold_1, loo_2_with_jacobian)
      elpd_diff se_diff
fit_2   0.0       0.0  
fit_1 -55.9      24.6  

Posterior predictive checking for model in original scale

yrep_1 <- posterior_predict(fit_1)
n_sims <- nrow(yrep_1)
sims_display <- sample(n_sims, 100)
ppc_1 <- ppc_dens_overlay(mesquite$weight, yrep_1[sims_display,]) +
    theme(axis.line.y = element_blank())

Posterior predictive checking for model in log scale

yrep_2 <- posterior_predict(fit_2)
ppc_2 <- ppc_dens_overlay(log(mesquite$weight), yrep_2[sims_display,]) +
  theme(axis.line.y = element_blank())
bpg <- bayesplot_grid(
  ppc_1, ppc_2,
  grid_args = list(ncol = 2),
  titles = c("Model for weight", "Model for log(weight)")
)

Display posterior predictive checking plots

bpg

Plot marginal posteriors

mcmc_areas(as.matrix(fit_2), regex_pars = "^log|^gro")

**Plot joint marginal posterior for log(canopy_height) and log(total_height)

mcmc_scatter(as.matrix(fit_2), pars = c("log(canopy_height)","log(total_height)"), size = 1) +
    geom_vline(xintercept=0) +
    geom_hline(yintercept=0) +
    labs(x="coef of log(canopy_height)", y="coef of log(total_height)")

Additional transformed variables

mesquite$canopy_volume <- mesquite$diam1 * mesquite$diam2 * mesquite$canopy_height
mesquite$canopy_area <- mesquite$diam1 * mesquite$diam2
mesquite$canopy_shape <- mesquite$diam1 / mesquite$diam2

A model with a canopy volume variable

fit_3 <- stan_glm(log(weight) ~ log(canopy_volume), data=mesquite,
                  seed=SEED, refresh=0)
print(fit_3)
stan_glm
 family:       gaussian [identity]
 formula:      log(weight) ~ log(canopy_volume)
 observations: 46
 predictors:   2
------
                   Median MAD_SD
(Intercept)        5.2    0.1   
log(canopy_volume) 0.7    0.1   

Auxiliary parameter(s):
      Median MAD_SD
sigma 0.4    0.0   

------
* For help interpreting the printed output see ?print.stanreg
* For info on the priors used see ?prior_summary.stanreg
loo_3 <- loo(fit_3)

Both models are modeling log(y) and can be compared directly.

loo_compare(loo_2, loo_3)
      elpd_diff se_diff
fit_2  0.0       0.0   
fit_3 -7.4       5.0   

Compare also LOO-R^2

round(median(loo_R2(fit_2)),2)
[1] 0.85
round(median(loo_R2(fit_3)),2)
[1] 0.79

Compare Bayesian R^2

round(median(bayes_R2(fit_2)),2)
[1] 0.87
round(median(bayes_R2(fit_3)),2)
[1] 0.79

Add canopy area and canopy shape

fit_4 <- stan_glm(log(weight) ~ log(canopy_volume) +
                      log(canopy_area) + log(canopy_shape) +
                      log(total_height) + log(density) + group,
                  data=mesquite, seed=SEED, refresh=0)
print(fit_4)
stan_glm
 family:       gaussian [identity]
 formula:      log(weight) ~ log(canopy_volume) + log(canopy_area) + log(canopy_shape) + 
       log(total_height) + log(density) + group
 observations: 46
 predictors:   7
------
                   Median MAD_SD
(Intercept)         4.8    0.2  
log(canopy_volume)  0.4    0.3  
log(canopy_area)    0.4    0.3  
log(canopy_shape)  -0.4    0.2  
log(total_height)   0.4    0.3  
log(density)        0.1    0.1  
groupMCD            0.6    0.1  

Auxiliary parameter(s):
      Median MAD_SD
sigma 0.3    0.0   

------
* For help interpreting the printed output see ?print.stanreg
* For info on the priors used see ?prior_summary.stanreg
(loo_4 <- loo(fit_4))

Computed from 4000 by 46 log-likelihood matrix

         Estimate   SE
elpd_loo    -19.3  5.3
p_loo         7.5  1.5
looic        38.6 10.7
------
Monte Carlo SE of elpd_loo is 0.1.

Pareto k diagnostic values:
                         Count Pct.    Min. n_eff
(-Inf, 0.5]   (good)     44    95.7%   925       
 (0.5, 0.7]   (ok)        2     4.3%   268       
   (0.7, 1]   (bad)       0     0.0%   <NA>      
   (1, Inf)   (very bad)  0     0.0%   <NA>      

All Pareto k estimates are ok (k < 0.7).
See help('pareto-k-diagnostic') for details.
loo_compare(loo_2, loo_4)
      elpd_diff se_diff
fit_2  0.0       0.0   
fit_4 -0.1       0.1   
round(median(loo_R2(fit_4)),2)
[1] 0.85
round(median(bayes_R2(fit_4)),2)
[1] 0.87

Plot Bayesian R^2

mcmc_hist(data.frame(bayes_R2(fit_4)), binwidth=0.005)+
  xlab('Bayesian R^2') + scale_y_continuous(breaks=NULL)

Plot marginals

mcmc_areas(as.matrix(fit_4))

Plot pairwise joint marginals

Strong collinearity between canopy volume and canopy area is obvious

mcmc_pairs(as.matrix(fit_4), pars=c("log(canopy_volume)","log(canopy_area)",
                                    "log(canopy_shape)","log(total_height)",
                                    "log(density)"))

A model with just canopy volume and canopy shape

fit_5 <- stan_glm(log(weight) ~ log(canopy_volume) + log(canopy_shape) +
    group, data=mesquite, seed=SEED, refresh=0)
(loo_5 <- loo(fit_5))

Computed from 4000 by 46 log-likelihood matrix

         Estimate   SE
elpd_loo    -18.0  5.4
p_loo         5.4  1.3
looic        36.0 10.9
------
Monte Carlo SE of elpd_loo is 0.1.

Pareto k diagnostic values:
                         Count Pct.    Min. n_eff
(-Inf, 0.5]   (good)     44    95.7%   1195      
 (0.5, 0.7]   (ok)        2     4.3%   530       
   (0.7, 1]   (bad)       0     0.0%   <NA>      
   (1, Inf)   (very bad)  0     0.0%   <NA>      

All Pareto k estimates are ok (k < 0.7).
See help('pareto-k-diagnostic') for details.
loo_compare(loo_4, loo_5)
      elpd_diff se_diff
fit_5  0.0       0.0   
fit_4 -1.3       1.5   
round(median(loo_R2(fit_5)),2)
[1] 0.85
round(median(bayes_R2(fit_5)),2)
[1] 0.87
LS0tCnRpdGxlOiAiUmVncmVzc2lvbiBhbmQgT3RoZXIgU3RvcmllczogTWVzcXVpdGUiCmF1dGhvcjogIkFuZHJldyBHZWxtYW4sIEplbm5pZmVyIEhpbGwsIEFraSBWZWh0YXJpIgpkYXRlOiAiYHIgZm9ybWF0KFN5cy5EYXRlKCkpYCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0aGVtZTogcmVhZGFibGUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAyCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKLS0tClByZWRpY3RpbmcgdGhlIHlpZWxkcyBvZiBtZXNxdWl0ZSBidXNoZXMuIFNlZSBDaGFwdGVyIDEyIGluClJlZ3Jlc3Npb24gYW5kIE90aGVyIFN0b3JpZXMuCgotLS0tLS0tLS0tLS0tCgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChtZXNzYWdlPUZBTFNFLCBlcnJvcj1GQUxTRSwgd2FybmluZz1GQUxTRSwgY29tbWVudD1OQSkKIyBzd2l0Y2ggdGhpcyB0byBUUlVFIHRvIHNhdmUgZmlndXJlcyBpbiBzZXBhcmF0ZSBmaWxlcwpzYXZlZmlncyA8LSBGQUxTRQpgYGAKCiMjIyMgTG9hZCBwYWNrYWdlcwoKYGBge3IgfQpsaWJyYXJ5KCJycHJvanJvb3QiKQpyb290PC1oYXNfZmlsZSgiLlJPUy1FeGFtcGxlcy1yb290IikkbWFrZV9maXhfZmlsZSgpCmxpYnJhcnkoImZvcmVpZ24iKQpsaWJyYXJ5KCJyc3RhbmFybSIpCmxpYnJhcnkoImxvbyIpCmxpYnJhcnkoImdncGxvdDIiKQpsaWJyYXJ5KCJiYXllc3Bsb3QiKQp0aGVtZV9zZXQoYmF5ZXNwbG90Ojp0aGVtZV9kZWZhdWx0KGJhc2VfZmFtaWx5ID0gInNhbnMiKSkKYGBgCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CiMgZ3JheXNjYWxlIGZpZ3VyZXMgZm9yIHRoZSBib29rCmlmIChzYXZlZmlncykgY29sb3Jfc2NoZW1lX3NldChzY2hlbWUgPSAiZ3JheSIpCmBgYAoKU2V0IHJhbmRvbSBzZWVkIGZvciByZXByb2R1Y2FiaWxpdHkKCmBgYHtyIH0KU0VFRCA8LSA0NTg3CmBgYAoKIyMjIyBMb2FkIGRhdGEKCmBgYHtyIH0KbWVzcXVpdGUgPC0gcmVhZC50YWJsZShyb290KCJNZXNxdWl0ZS9kYXRhIiwibWVzcXVpdGUuZGF0IiksIGhlYWRlcj1UUlVFKQpoZWFkKG1lc3F1aXRlKQpgYGAKCiMjIFByZWRpY3Qgd2VpZ2h0IGdpdmVuIGFsbCB0aGUgcHJlZGljdG9ycwoKYGBge3IgfQpmaXRfMSA8LSBzdGFuX2dsbSh3ZWlnaHQgfiBkaWFtMSArIGRpYW0yICsgY2Fub3B5X2hlaWdodCArIHRvdGFsX2hlaWdodCArCiAgICAgICAgICAgICAgICAgICAgZGVuc2l0eSArIGdyb3VwLCBkYXRhPW1lc3F1aXRlLCBzZWVkPVNFRUQsIHJlZnJlc2g9MCkKcHJpbnQoZml0XzEpCihsb29fMSA8LSBsb28oZml0XzEpKQpgYGAKCldlIGdldCB3YXJuaW5ncyBhYm91dCBoaWdoIFBhcmV0byBrIHZhbHVlcywgd2hpY2ggaW5kaWNhdGVzIHRoYXQKdGhlIGltcG9ydGFuY2Ugc2FtcGxpbmcgYXBwcm94aW1hdGlvbiB1c2VkIGluIGxvbyBpcyBpbiB0aGlzIGNhc2UKdW5yZWxpYWJsZS4gV2UgdGh1cyB1c2UgbW9yZSByb2J1c3QgSy1mb2xkLUNWLgoKYGBge3IgfQprZm9sZF8xIDwtIGtmb2xkKGZpdF8xLCBLPTEwKQprZm9sZF8xCmBgYAoKIyMgUHJlZGljdCBsb2cod2VpZ2h0KSBnaXZlbiBsb2cgdHJhbnNmb3JtZWQgcHJlZGljdG9ycwoKYGBge3IgfQpmaXRfMiA8LSBzdGFuX2dsbShsb2cod2VpZ2h0KSB+IGxvZyhkaWFtMSkgKyBsb2coZGlhbTIpICsgbG9nKGNhbm9weV9oZWlnaHQpICsKICAgICAgICAgICAgICAgICAgICAgIGxvZyh0b3RhbF9oZWlnaHQpICsgbG9nKGRlbnNpdHkpICsgZ3JvdXAsCiAgICAgICAgICAgICAgICAgIGRhdGE9bWVzcXVpdGUsIHNlZWQ9U0VFRCwgcmVmcmVzaD0wKQoobG9vXzIgPC0gbG9vKGZpdF8yKSkKYGBgCgojIyMjIEphY29iaWFuIGNvcnJlY3Rpb24gdG8gbWFrZSB0aGUgbW9kZWxzIGNvbXBhcmFibGU8YnI+CkphY29iaWFuIGNvcnJlY3Rpb24gaXMgbmVlZGVkIGFzIG1vZGVsIDEgaXMgbW9kZWxpbmcgeSBhbmQgbW9kZWwgMgppcyBtb2RlbGluZyBsb2coeSkuCgpgYGB7ciB9Cmxvb18yX3dpdGhfamFjb2JpYW4gPC0gbG9vXzIKbG9vXzJfd2l0aF9qYWNvYmlhbiRwb2ludHdpc2VbLDFdIDwtIGxvb18yX3dpdGhfamFjb2JpYW4kcG9pbnR3aXNlWywxXS0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZyhtZXNxdWl0ZSR3ZWlnaHQpCihlbHBkX2xvb18yX3dpdGhfamFjb2JpYW4gPC0gc3VtKGxvb18yX3dpdGhfamFjb2JpYW4kcG9pbnR3aXNlWywxXSkpCmBgYAoKdGhlcmUgd2lsbCBiZSBhIHdhcm5pbmcgdGhhdCB0aGUgdGFyZ2V0IGRhdGEgaXMgbm90IHRoZSBzYW1lIHNhbWUsIAp0aGlzIGlzIG9rIGJlY2F1c2Ugd2UgaGF2ZSB0aGUgamFjb2JpYW4gY29ycmVjdGlvbgoKYGBge3IgfQpsb29fY29tcGFyZShrZm9sZF8xLCBsb29fMl93aXRoX2phY29iaWFuKQpgYGAKCiMjIyMgUG9zdGVyaW9yIHByZWRpY3RpdmUgY2hlY2tpbmcgZm9yIG1vZGVsIGluIG9yaWdpbmFsIHNjYWxlCgpgYGB7ciB9CnlyZXBfMSA8LSBwb3N0ZXJpb3JfcHJlZGljdChmaXRfMSkKbl9zaW1zIDwtIG5yb3coeXJlcF8xKQpzaW1zX2Rpc3BsYXkgPC0gc2FtcGxlKG5fc2ltcywgMTAwKQpwcGNfMSA8LSBwcGNfZGVuc19vdmVybGF5KG1lc3F1aXRlJHdlaWdodCwgeXJlcF8xW3NpbXNfZGlzcGxheSxdKSArCiAgICB0aGVtZShheGlzLmxpbmUueSA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgojIyMjIFBvc3RlcmlvciBwcmVkaWN0aXZlIGNoZWNraW5nIGZvciBtb2RlbCBpbiBsb2cgc2NhbGUKCmBgYHtyIH0KeXJlcF8yIDwtIHBvc3Rlcmlvcl9wcmVkaWN0KGZpdF8yKQpwcGNfMiA8LSBwcGNfZGVuc19vdmVybGF5KGxvZyhtZXNxdWl0ZSR3ZWlnaHQpLCB5cmVwXzJbc2ltc19kaXNwbGF5LF0pICsKICB0aGVtZShheGlzLmxpbmUueSA9IGVsZW1lbnRfYmxhbmsoKSkKYnBnIDwtIGJheWVzcGxvdF9ncmlkKAogIHBwY18xLCBwcGNfMiwKICBncmlkX2FyZ3MgPSBsaXN0KG5jb2wgPSAyKSwKICB0aXRsZXMgPSBjKCJNb2RlbCBmb3Igd2VpZ2h0IiwgIk1vZGVsIGZvciBsb2cod2VpZ2h0KSIpCikKYGBgCgojIyMjIERpc3BsYXkgcG9zdGVyaW9yIHByZWRpY3RpdmUgY2hlY2tpbmcgcGxvdHMKCmBgYHtyIH0KYnBnCmBgYApgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQppZiAoc2F2ZWZpZ3MpCiAgZ2dzYXZlKHJvb3QoIk1lc3F1aXRlL2ZpZ3MiLCJtZXNxdWl0ZV9wcGMucGRmIiksIGJwZywgaGVpZ2h0PTMsIHdpZHRoPTksIGNvbG9ybW9kZWw9ImdyYXkiKQpgYGAKCiMjIyMgUGxvdCBtYXJnaW5hbCBwb3N0ZXJpb3JzCgpgYGB7ciBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD02fQptY21jX2FyZWFzKGFzLm1hdHJpeChmaXRfMiksIHJlZ2V4X3BhcnMgPSAiXmxvZ3xeZ3JvIikKYGBgCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmlmIChzYXZlZmlncykKICAgIGdnc2F2ZShyb290KCJNZXNxdWl0ZS9maWdzIiwibWVzcXVpdGVfYXJlYXMucGRmIiksIGhlaWdodD0zLjUsIHdpZHRoPTUsIGNvbG9ybW9kZWw9ImdyYXkiKQpgYGAKCioqUGxvdCBqb2ludCBtYXJnaW5hbCBwb3N0ZXJpb3IgZm9yIGxvZyhjYW5vcHlfaGVpZ2h0KSBhbmQgbG9nKHRvdGFsX2hlaWdodCkKCmBgYHtyIH0KbWNtY19zY2F0dGVyKGFzLm1hdHJpeChmaXRfMiksIHBhcnMgPSBjKCJsb2coY2Fub3B5X2hlaWdodCkiLCJsb2codG90YWxfaGVpZ2h0KSIpLCBzaXplID0gMSkgKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PTApICsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdD0wKSArCiAgICBsYWJzKHg9ImNvZWYgb2YgbG9nKGNhbm9weV9oZWlnaHQpIiwgeT0iY29lZiBvZiBsb2codG90YWxfaGVpZ2h0KSIpCmBgYApgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQppZiAoc2F2ZWZpZ3MpCiAgICBnZ3NhdmUocm9vdCgiTWVzcXVpdGUvZmlncyIsIm1lc3F1aXRlX3NjYXR0ZXIucGRmIiksIGhlaWdodD0zLjUsIHdpZHRoPTUsIGNvbG9ybW9kZWw9ImdyYXkiKQpgYGAKCiMjIEFkZGl0aW9uYWwgdHJhbnNmb3JtZWQgdmFyaWFibGVzCgpgYGB7ciB9Cm1lc3F1aXRlJGNhbm9weV92b2x1bWUgPC0gbWVzcXVpdGUkZGlhbTEgKiBtZXNxdWl0ZSRkaWFtMiAqIG1lc3F1aXRlJGNhbm9weV9oZWlnaHQKbWVzcXVpdGUkY2Fub3B5X2FyZWEgPC0gbWVzcXVpdGUkZGlhbTEgKiBtZXNxdWl0ZSRkaWFtMgptZXNxdWl0ZSRjYW5vcHlfc2hhcGUgPC0gbWVzcXVpdGUkZGlhbTEgLyBtZXNxdWl0ZSRkaWFtMgpgYGAKCiMjIEEgbW9kZWwgd2l0aCBhIGNhbm9weSB2b2x1bWUgdmFyaWFibGUKCmBgYHtyIH0KZml0XzMgPC0gc3Rhbl9nbG0obG9nKHdlaWdodCkgfiBsb2coY2Fub3B5X3ZvbHVtZSksIGRhdGE9bWVzcXVpdGUsCiAgICAgICAgICAgICAgICAgIHNlZWQ9U0VFRCwgcmVmcmVzaD0wKQpwcmludChmaXRfMykKbG9vXzMgPC0gbG9vKGZpdF8zKQpgYGAKCkJvdGggbW9kZWxzIGFyZSBtb2RlbGluZyBsb2coeSkgYW5kIGNhbiBiZSBjb21wYXJlZCBkaXJlY3RseS4KCmBgYHtyIH0KbG9vX2NvbXBhcmUobG9vXzIsIGxvb18zKQpgYGAKCiMjIyMgQ29tcGFyZSBhbHNvIExPTy1SXjIKCmBgYHtyIH0Kcm91bmQobWVkaWFuKGxvb19SMihmaXRfMikpLDIpCnJvdW5kKG1lZGlhbihsb29fUjIoZml0XzMpKSwyKQpgYGAKCiMjIyMgQ29tcGFyZSBCYXllc2lhbiBSXjIKCmBgYHtyIH0Kcm91bmQobWVkaWFuKGJheWVzX1IyKGZpdF8yKSksMikKcm91bmQobWVkaWFuKGJheWVzX1IyKGZpdF8zKSksMikKYGBgCgojIyBBZGQgY2Fub3B5IGFyZWEgYW5kIGNhbm9weSBzaGFwZQoKYGBge3IgfQpmaXRfNCA8LSBzdGFuX2dsbShsb2cod2VpZ2h0KSB+IGxvZyhjYW5vcHlfdm9sdW1lKSArCiAgICAgICAgICAgICAgICAgICAgICBsb2coY2Fub3B5X2FyZWEpICsgbG9nKGNhbm9weV9zaGFwZSkgKwogICAgICAgICAgICAgICAgICAgICAgbG9nKHRvdGFsX2hlaWdodCkgKyBsb2coZGVuc2l0eSkgKyBncm91cCwKICAgICAgICAgICAgICAgICAgZGF0YT1tZXNxdWl0ZSwgc2VlZD1TRUVELCByZWZyZXNoPTApCnByaW50KGZpdF80KQoobG9vXzQgPC0gbG9vKGZpdF80KSkKbG9vX2NvbXBhcmUobG9vXzIsIGxvb180KQpyb3VuZChtZWRpYW4obG9vX1IyKGZpdF80KSksMikKcm91bmQobWVkaWFuKGJheWVzX1IyKGZpdF80KSksMikKYGBgCgojIyMjIFBsb3QgQmF5ZXNpYW4gUl4yCgpgYGB7ciByZXN1bHRzPSdoaWRlJywgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9Nn0KbWNtY19oaXN0KGRhdGEuZnJhbWUoYmF5ZXNfUjIoZml0XzQpKSwgYmlud2lkdGg9MC4wMDUpKwogIHhsYWIoJ0JheWVzaWFuIFJeMicpICsgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1OVUxMKQpgYGAKCiMjIyMgUGxvdCBtYXJnaW5hbHMKCmBgYHtyIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTZ9Cm1jbWNfYXJlYXMoYXMubWF0cml4KGZpdF80KSkKYGBgCgojIyMjIFBsb3QgcGFpcndpc2Ugam9pbnQgbWFyZ2luYWxzPGJyPgpTdHJvbmcgY29sbGluZWFyaXR5IGJldHdlZW4gY2Fub3B5IHZvbHVtZSBhbmQgY2Fub3B5IGFyZWEgaXMgb2J2aW91cwoKYGBge3IgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9OH0KbWNtY19wYWlycyhhcy5tYXRyaXgoZml0XzQpLCBwYXJzPWMoImxvZyhjYW5vcHlfdm9sdW1lKSIsImxvZyhjYW5vcHlfYXJlYSkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibG9nKGNhbm9weV9zaGFwZSkiLCJsb2codG90YWxfaGVpZ2h0KSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJsb2coZGVuc2l0eSkiKSkKYGBgCgojIyBBIG1vZGVsIHdpdGgganVzdCBjYW5vcHkgdm9sdW1lIGFuZCBjYW5vcHkgc2hhcGUKCmBgYHtyIH0KZml0XzUgPC0gc3Rhbl9nbG0obG9nKHdlaWdodCkgfiBsb2coY2Fub3B5X3ZvbHVtZSkgKyBsb2coY2Fub3B5X3NoYXBlKSArCiAgICBncm91cCwgZGF0YT1tZXNxdWl0ZSwgc2VlZD1TRUVELCByZWZyZXNoPTApCihsb29fNSA8LSBsb28oZml0XzUpKQpsb29fY29tcGFyZShsb29fNCwgbG9vXzUpCnJvdW5kKG1lZGlhbihsb29fUjIoZml0XzUpKSwyKQpyb3VuZChtZWRpYW4oYmF5ZXNfUjIoZml0XzUpKSwyKQpgYGAKCg==