knitr::opts_chunk$set(cache = TRUE, dev = c("png", "pdf"))
library(here)
source(here("src", "model_quadratic_grampians.R"))
library(forcats)
library(ggplot2)

Coefficient Plot

covariate_nms <- c(
  mlq  = "Mean\nMoisture\nIndex\nLowest\nQuarter",
  mlq2 = "Mean\nMoisture\nIndex\nLowest\nQuarter\u00b2",
  twi  = "Topographic\nWetness\nIndex",
  twi2 = "Topographic\nWetness\nIndex\u00b2",
  r1k  = "Relief\n1000m\nRadius",
  r1k2 = "Relief\n1000m\nRadius\u00b2",
  tn   = "Total\nNitrogen",
  tn2  = "Total\nNitrogen\u00b2"
)

coef_grampians <- as.data.frame.table(coef_sims(model_grampians))

coef_grampians$Var1 <- fct_recode(
  coef_grampians$Var1,
  `Eucalyptus goniocalyx` = "Eucalyptus (goniocalyx|nortonii)",
  `Eucalyptus viminalis subsp. viminalis` =
    "Eucalyptus viminalis subsp. (pryoriana|viminalis)"
)

coef_grampians$Var1 <- as.character(coef_grampians$Var1)
coef_grampians$Var1 <- gsub("Eucalyptus", "E.", coef_grampians$Var1)
coef_grampians$Var1 <- gsub("subsp.", "ssp.", coef_grampians$Var1)

ggplot(coef_grampians) +
aes(factor(Var1, levels = rev(levels(factor(Var1)))), Freq) +
geom_hline(yintercept = 0) +
geom_violin(fill = "grey35", scale = "width", width = .5, trim = TRUE) +
coord_flip() +
facet_grid(
  ~Var2,
  labeller = as_labeller(c(`(Intercept)` = "Intercept", covariate_nms))
) +
scale_x_discrete(name = "") +
ylab("Standardised coefficients") +
theme_bw() +
theme(
  axis.text.y = element_text(face = "italic"),
  strip.text.x = element_text(size = 6)
)

Trait-Environmental Response Relationships

trait_env_plot(
  model_grampians,
  mdg,
  gvars = c(
    sla = "sla_mm2_per_mg", sm = "seed_mass_mg", mh = "max_height_m"
  ),
  xlabs = list(
    expression(SLA~(mm^2~mg^-1)), "Seed Mass (mg)", "Maximum Height (m)"
  ),
  ylabs = covariate_nms,
  plot.log = c("", "", "x")
)

Traits-Environmental Response 2D Surfaces

unscaled_covariates <- mdg[
  c(
    "mean_moisture_index_of_low_qtr", "topographic_wetness_index_3sec",
    "relief_1000m_radius", "total_nitrogen"
  )
]

covariate_polys <- new_poly(unscaled_covariates, 1:2, length.out = 50)
covariate_polys_expd <- covariate_polys[rep(seq(50), times = 50), ]
covariate_polys_expd[, 3:4] <- covariate_polys[rep(seq(50), each = 50), 3:4]
colnames(covariate_polys_expd) <- colnames(covariate_polys) <-
  names(covariate_nms)

panel_data <- mapply(
  function(sla_raw, sm_raw) {
    sla    <- log(mdg$sla_mm2_per_mg)
    sla_m  <- mean(sla)
    sla_sd <- sd(sla)
    sm     <- log(mdg$seed_mass_mg)
    sm_m   <- mean(sm)
    sm_sd  <- sd(sm)
    data.frame(
      x = covariate_polys_expd[, "mlq"],
      y = covariate_polys_expd[, "twi"],
      x_raw = rep(seq_rng(mdg$mean_moisture_index_of_low_qtr, na.rm = TRUE, length.out = 50), times = 50),
      y_raw = rep(seq_rng(mdg$topographic_wetness_index_3sec, na.rm = TRUE, length.out = 50), each = 50),
      z = predict_prob_new_taxon(
        model_grampians,
        data.frame(
          covariate_polys_expd,
          sla = (log(sla_raw) - sla_m) / sla_sd,
          sm  = (log(sm_raw) - sm_m) / sm_sd,
          mh = 0
        )
      ),
      sla = sla_raw,
      sm  = sm_raw
    )
  },
  sla_raw = c(3, 5, 3, 5),
  sm_raw = c(.5, .5, 1.5, 1.5),
  SIMPLIFY = FALSE
)

panel_data <- do.call(rbind, panel_data)
colnames(panel_data)[6:7] <- c("SLA", "Seed Mass")

ggplot(panel_data) +
aes(x_raw, y_raw, z = z, fill = z) +
geom_raster(alpha = .7) +
geom_contour(col = "grey") +
scale_fill_gradientn(
  name = "Pr(Y=1)", colours = grey.colors(50, 1, .1, gamma = .3)
) +
xlab("Mean Moisture Index Lowest Quarter") +
ylab("Topographic Wetness Index") +
facet_grid(`Seed Mass` ~ SLA, labeller = label_both) +
theme_bw()

3D Response Surface

persp(
  list(
    x = covariate_polys[, "mlq"],
    y = covariate_polys[, "twi"]
  ),
  z = matrix(
    predict_prob_taxon(
      model_grampians,
      "Eucalyptus radiata",
      covariate_polys_expd
    ),
    50
  ),
  main = "Eucalyptus radiata",
  zlab = "\nPr(Y=1)",
  xlab = "\nMean Moisture Index Lowest Quarter",
  ylab = "\nTopographic Wetness Index",
  col = "cornflowerblue", border = "salmon",
  theta = 25, phi = 45,
  font.main = 3
)

2D Surface Predictions

for (i in levels(model_grampians@flist$taxon)) {
  panel_data <- data.frame(
    x = covariate_polys_expd[, "mlq"],
    y = covariate_polys_expd[, "twi"],
    z = predict_prob_taxon(model_grampians, i, covariate_polys_expd)
  )

  rug_data <- lapply(
    c(absent = FALSE, present = TRUE),
    function(x) {
      ans <- subset(
        mdg,
        taxon == i & occupancy == x,
        c("mlq", "twi")
      )
      names(ans) <- c("x", "y")
      ans
    }
  )

  densityplot <-
    ggplot(panel_data) +
    aes(x, y, z = z, fill = z) +
    geom_raster(alpha = .7) +
    geom_rug(
      data = rug_data$absent, aes(x, y), inherit.aes = FALSE, col = "grey"
    ) +
    geom_rug(
      data = rug_data$present, aes(x, y), inherit.aes = FALSE, col = "black"
    ) +
    scale_fill_gradientn(name = "Pr(Y=1)", colours = grey.colors(50, 1, 0)) +
    xlab("Mean Moisture Index Lowest Quarter") +
    ylab("Topographic Wetness Index") +
    ggtitle(i) +
    theme_minimal() +
    theme(plot.title = element_text(face = "italic"))

  print(densityplot)
}

Partial Dependence Plots

x <- list(
  mean_moisture_index_of_low_qtr =
    seq_rng(mdg$mean_moisture_index_of_low_qtr, na.rm = TRUE),
  topographic_wetness_index_3sec =
    seq_rng(mdg$topographic_wetness_index_3sec, na.rm = TRUE),
  relief_1000m_radius =
    seq_rng(mdg$relief_1000m_radius, na.rm = TRUE),
  total_nitrogen =
    seq_rng(mdg$total_nitrogen, na.rm = TRUE)
)
np <- list(
  "Mean Moisture Index Lowest Quarter" =
    new_poly(unscaled_covariates, 1, colnames = names(covariate_nms)
  ),
  "Topographic Wetness Index" =
    new_poly(unscaled_covariates, 2, colnames = names(covariate_nms)
  ),
  "Relief 1000m Radius" =
    new_poly(unscaled_covariates, 3, colnames = names(covariate_nms)
  ),
  "Total Nitrogen" =
    new_poly(unscaled_covariates, 4, colnames = names(covariate_nms)
  )
)

par(mfrow = c(1, 4), oma = c(0, 4, 4, 0), font.main = 3, las = 1)
for(i in levels(model_grampians@flist$taxon)) {
  for (j in seq_along(np)) {
    par(mar = c(5, 0, 0, 1))
    plot(x[[j]], predict_prob_taxon(model_grampians, i, np[[j]]),
      ylim = 0:1, type = "l", lwd = 3,
      ylab = ifelse(j == 1, "Pr(Y=1)", ""),
      xlab = names(np)[j], yaxt = ifelse(j == 1, "s", "n"),
      panel.first = grid(), xpd = NA
    )
    with(
      subset(mdg, taxon == i),
      points(
        get(names(x[j])), ifelse(occupancy, 1.02, -.02), pch = 15,
        col = rgb(.1, .1, .1, .1)
      )
    )
  }
  title(i, outer = TRUE)
}

par(mfrow = c(1, 4), oma = c(0, 4, 1, 0), las = 1)
for (j in seq_along(np)) {
  par(mar = c(5, 0, 0, 1))
  plot(
    x[[j]],
    predict_prob_taxon(model_grampians, "Eucalyptus melliodora", np[[j]]),
    ylim = 0:1, type = "l", lwd = 3, col = "black",
    ylab = ifelse(j == 1, "Pr(Y=1)", ""),
    xlab = names(np)[j], yaxt = ifelse(j == 1, "s", "n"),
    panel.first = grid(), xpd = NA
  )
  with(
    subset(mdg, taxon == "Eucalyptus melliodora"),
    points(
      get(names(x[j])), ifelse(occupancy, 1.025, -.01), pch = 15,
      col = rgb(.2, .2, .2, .1)
    )
  )
  points(
    x[[j]],
    predict_prob_taxon(model_grampians, "Eucalyptus obliqua", np[[j]]),
    type = "l", lwd = 3, col = "grey"
  )
  with(
    subset(mdg, taxon == "Eucalyptus obliqua"),
    points(
      get(names(x[j])), ifelse(occupancy, 1.01, -.025), pch = 15,
      col =  rgb(.8, .8, .8, .1)
    )
  )
}
legend(
  "topright",
  legend = c("Eucalyptus melliodora", "Eucalyptus obliqua"),
  fill = c("black", "grey"), ncol = 1, bty = "n", text.font = 3,
  border = NA, y.intersp = 2, inset = .05
)

IycgLS0tCiMnIHRpdGxlOiAiUGxvdHMgZm9yIG1vZGVsIG9mIEdyYW1waWFucyBPY2N1cGFuY3kgYW5kIFRyYWl0IERhdGEgd2l0aCBxdWFkcmF0aWMgcmVsYXRpb25zaGlwcyIKIycgYXV0aG9yOiAiV2lsbGlhbSBLLiBNb3JyaXMiCiMnIGRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKIycgb3V0cHV0OgojJyAgIHJtYXJrZG93bjo6aHRtbF9ub3RlYm9vazoKIycgICAgIGNvZGVfZm9sZGluZzogaGlkZQojJyAtLS0KCiMrIHNldHVwLCBtZXNzYWdlPUZBTFNFCmtuaXRyOjpvcHRzX2NodW5rJHNldChjYWNoZSA9IFRSVUUsIGRldiA9IGMoInBuZyIsICJwZGYiKSkKbGlicmFyeShoZXJlKQpzb3VyY2UoaGVyZSgic3JjIiwgIm1vZGVsX3F1YWRyYXRpY19ncmFtcGlhbnMuUiIpKQpsaWJyYXJ5KGZvcmNhdHMpCmxpYnJhcnkoZ2dwbG90MikKCiMnICMjIENvZWZmaWNpZW50IFBsb3QKIysgY29lZi1wbG90LCBmaWcud2lkdGg9Ny41CmNvdmFyaWF0ZV9ubXMgPC0gYygKICBtbHEgID0gIk1lYW5cbk1vaXN0dXJlXG5JbmRleFxuTG93ZXN0XG5RdWFydGVyIiwKICBtbHEyID0gIk1lYW5cbk1vaXN0dXJlXG5JbmRleFxuTG93ZXN0XG5RdWFydGVyXHUwMGIyIiwKICB0d2kgID0gIlRvcG9ncmFwaGljXG5XZXRuZXNzXG5JbmRleCIsCiAgdHdpMiA9ICJUb3BvZ3JhcGhpY1xuV2V0bmVzc1xuSW5kZXhcdTAwYjIiLAogIHIxayAgPSAiUmVsaWVmXG4xMDAwbVxuUmFkaXVzIiwKICByMWsyID0gIlJlbGllZlxuMTAwMG1cblJhZGl1c1x1MDBiMiIsCiAgdG4gICA9ICJUb3RhbFxuTml0cm9nZW4iLAogIHRuMiAgPSAiVG90YWxcbk5pdHJvZ2VuXHUwMGIyIgopCgpjb2VmX2dyYW1waWFucyA8LSBhcy5kYXRhLmZyYW1lLnRhYmxlKGNvZWZfc2ltcyhtb2RlbF9ncmFtcGlhbnMpKQoKY29lZl9ncmFtcGlhbnMkVmFyMSA8LSBmY3RfcmVjb2RlKAogIGNvZWZfZ3JhbXBpYW5zJFZhcjEsCiAgYEV1Y2FseXB0dXMgZ29uaW9jYWx5eGAgPSAiRXVjYWx5cHR1cyAoZ29uaW9jYWx5eHxub3J0b25paSkiLAogIGBFdWNhbHlwdHVzIHZpbWluYWxpcyBzdWJzcC4gdmltaW5hbGlzYCA9CiAgICAiRXVjYWx5cHR1cyB2aW1pbmFsaXMgc3Vic3AuIChwcnlvcmlhbmF8dmltaW5hbGlzKSIKKQoKY29lZl9ncmFtcGlhbnMkVmFyMSA8LSBhcy5jaGFyYWN0ZXIoY29lZl9ncmFtcGlhbnMkVmFyMSkKY29lZl9ncmFtcGlhbnMkVmFyMSA8LSBnc3ViKCJFdWNhbHlwdHVzIiwgIkUuIiwgY29lZl9ncmFtcGlhbnMkVmFyMSkKY29lZl9ncmFtcGlhbnMkVmFyMSA8LSBnc3ViKCJzdWJzcC4iLCAic3NwLiIsIGNvZWZfZ3JhbXBpYW5zJFZhcjEpCgpnZ3Bsb3QoY29lZl9ncmFtcGlhbnMpICsKYWVzKGZhY3RvcihWYXIxLCBsZXZlbHMgPSByZXYobGV2ZWxzKGZhY3RvcihWYXIxKSkpKSwgRnJlcSkgKwpnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCmdlb21fdmlvbGluKGZpbGwgPSAiZ3JleTM1Iiwgc2NhbGUgPSAid2lkdGgiLCB3aWR0aCA9IC41LCB0cmltID0gVFJVRSkgKwpjb29yZF9mbGlwKCkgKwpmYWNldF9ncmlkKAogIH5WYXIyLAogIGxhYmVsbGVyID0gYXNfbGFiZWxsZXIoYyhgKEludGVyY2VwdClgID0gIkludGVyY2VwdCIsIGNvdmFyaWF0ZV9ubXMpKQopICsKc2NhbGVfeF9kaXNjcmV0ZShuYW1lID0gIiIpICsKeWxhYigiU3RhbmRhcmRpc2VkIGNvZWZmaWNpZW50cyIpICsKdGhlbWVfYncoKSArCnRoZW1lKAogIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiaXRhbGljIiksCiAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KQopCgojJyAjIyBUcmFpdC1FbnZpcm9ubWVudGFsIFJlc3BvbnNlIFJlbGF0aW9uc2hpcHMKIysgdHJhaXQtZW52LXBsb3QsIGZpZy53aWR0aD03LjUsIGZpZy5oZWlnaHQ9Ny41CnRyYWl0X2Vudl9wbG90KAogIG1vZGVsX2dyYW1waWFucywKICBtZGcsCiAgZ3ZhcnMgPSBjKAogICAgc2xhID0gInNsYV9tbTJfcGVyX21nIiwgc20gPSAic2VlZF9tYXNzX21nIiwgbWggPSAibWF4X2hlaWdodF9tIgogICksCiAgeGxhYnMgPSBsaXN0KAogICAgZXhwcmVzc2lvbihTTEF+KG1tXjJ+bWdeLTEpKSwgIlNlZWQgTWFzcyAobWcpIiwgIk1heGltdW0gSGVpZ2h0IChtKSIKICApLAogIHlsYWJzID0gY292YXJpYXRlX25tcywKICBwbG90LmxvZyA9IGMoIiIsICIiLCAieCIpCikKCiMnICMjIFRyYWl0cy1FbnZpcm9ubWVudGFsIFJlc3BvbnNlIDJEIFN1cmZhY2VzCiMrIHRyYWl0LWVudi1zdXJmYWNlLCBmaWcud2lkdGg9Ny41CnVuc2NhbGVkX2NvdmFyaWF0ZXMgPC0gbWRnWwogIGMoCiAgICAibWVhbl9tb2lzdHVyZV9pbmRleF9vZl9sb3dfcXRyIiwgInRvcG9ncmFwaGljX3dldG5lc3NfaW5kZXhfM3NlYyIsCiAgICAicmVsaWVmXzEwMDBtX3JhZGl1cyIsICJ0b3RhbF9uaXRyb2dlbiIKICApCl0KCmNvdmFyaWF0ZV9wb2x5cyA8LSBuZXdfcG9seSh1bnNjYWxlZF9jb3ZhcmlhdGVzLCAxOjIsIGxlbmd0aC5vdXQgPSA1MCkKY292YXJpYXRlX3BvbHlzX2V4cGQgPC0gY292YXJpYXRlX3BvbHlzW3JlcChzZXEoNTApLCB0aW1lcyA9IDUwKSwgXQpjb3ZhcmlhdGVfcG9seXNfZXhwZFssIDM6NF0gPC0gY292YXJpYXRlX3BvbHlzW3JlcChzZXEoNTApLCBlYWNoID0gNTApLCAzOjRdCmNvbG5hbWVzKGNvdmFyaWF0ZV9wb2x5c19leHBkKSA8LSBjb2xuYW1lcyhjb3ZhcmlhdGVfcG9seXMpIDwtCiAgbmFtZXMoY292YXJpYXRlX25tcykKCnBhbmVsX2RhdGEgPC0gbWFwcGx5KAogIGZ1bmN0aW9uKHNsYV9yYXcsIHNtX3JhdykgewogICAgc2xhICAgIDwtIGxvZyhtZGckc2xhX21tMl9wZXJfbWcpCiAgICBzbGFfbSAgPC0gbWVhbihzbGEpCiAgICBzbGFfc2QgPC0gc2Qoc2xhKQogICAgc20gICAgIDwtIGxvZyhtZGckc2VlZF9tYXNzX21nKQogICAgc21fbSAgIDwtIG1lYW4oc20pCiAgICBzbV9zZCAgPC0gc2Qoc20pCiAgICBkYXRhLmZyYW1lKAogICAgICB4ID0gY292YXJpYXRlX3BvbHlzX2V4cGRbLCAibWxxIl0sCiAgICAgIHkgPSBjb3ZhcmlhdGVfcG9seXNfZXhwZFssICJ0d2kiXSwKICAgICAgeF9yYXcgPSByZXAoc2VxX3JuZyhtZGckbWVhbl9tb2lzdHVyZV9pbmRleF9vZl9sb3dfcXRyLCBuYS5ybSA9IFRSVUUsIGxlbmd0aC5vdXQgPSA1MCksIHRpbWVzID0gNTApLAogICAgICB5X3JhdyA9IHJlcChzZXFfcm5nKG1kZyR0b3BvZ3JhcGhpY193ZXRuZXNzX2luZGV4XzNzZWMsIG5hLnJtID0gVFJVRSwgbGVuZ3RoLm91dCA9IDUwKSwgZWFjaCA9IDUwKSwKICAgICAgeiA9IHByZWRpY3RfcHJvYl9uZXdfdGF4b24oCiAgICAgICAgbW9kZWxfZ3JhbXBpYW5zLAogICAgICAgIGRhdGEuZnJhbWUoCiAgICAgICAgICBjb3ZhcmlhdGVfcG9seXNfZXhwZCwKICAgICAgICAgIHNsYSA9IChsb2coc2xhX3JhdykgLSBzbGFfbSkgLyBzbGFfc2QsCiAgICAgICAgICBzbSAgPSAobG9nKHNtX3JhdykgLSBzbV9tKSAvIHNtX3NkLAogICAgICAgICAgbWggPSAwCiAgICAgICAgKQogICAgICApLAogICAgICBzbGEgPSBzbGFfcmF3LAogICAgICBzbSAgPSBzbV9yYXcKICAgICkKICB9LAogIHNsYV9yYXcgPSBjKDMsIDUsIDMsIDUpLAogIHNtX3JhdyA9IGMoLjUsIC41LCAxLjUsIDEuNSksCiAgU0lNUExJRlkgPSBGQUxTRQopCgpwYW5lbF9kYXRhIDwtIGRvLmNhbGwocmJpbmQsIHBhbmVsX2RhdGEpCmNvbG5hbWVzKHBhbmVsX2RhdGEpWzY6N10gPC0gYygiU0xBIiwgIlNlZWQgTWFzcyIpCgpnZ3Bsb3QocGFuZWxfZGF0YSkgKwphZXMoeF9yYXcsIHlfcmF3LCB6ID0geiwgZmlsbCA9IHopICsKZ2VvbV9yYXN0ZXIoYWxwaGEgPSAuNykgKwpnZW9tX2NvbnRvdXIoY29sID0gImdyZXkiKSArCnNjYWxlX2ZpbGxfZ3JhZGllbnRuKAogIG5hbWUgPSAiUHIoWT0xKSIsIGNvbG91cnMgPSBncmV5LmNvbG9ycyg1MCwgMSwgLjEsIGdhbW1hID0gLjMpCikgKwp4bGFiKCJNZWFuIE1vaXN0dXJlIEluZGV4IExvd2VzdCBRdWFydGVyIikgKwp5bGFiKCJUb3BvZ3JhcGhpYyBXZXRuZXNzIEluZGV4IikgKwpmYWNldF9ncmlkKGBTZWVkIE1hc3NgIH4gU0xBLCBsYWJlbGxlciA9IGxhYmVsX2JvdGgpICsKdGhlbWVfYncoKQoKIycgIyMgM0QgUmVzcG9uc2UgU3VyZmFjZQojKyByZXNwb25zZS1zdXJmYWNlLTNkLCBmaWcud2lkdGg9MTAKcGVyc3AoCiAgbGlzdCgKICAgIHggPSBjb3ZhcmlhdGVfcG9seXNbLCAibWxxIl0sCiAgICB5ID0gY292YXJpYXRlX3BvbHlzWywgInR3aSJdCiAgKSwKICB6ID0gbWF0cml4KAogICAgcHJlZGljdF9wcm9iX3RheG9uKAogICAgICBtb2RlbF9ncmFtcGlhbnMsCiAgICAgICJFdWNhbHlwdHVzIHJhZGlhdGEiLAogICAgICBjb3ZhcmlhdGVfcG9seXNfZXhwZAogICAgKSwKICAgIDUwCiAgKSwKICBtYWluID0gIkV1Y2FseXB0dXMgcmFkaWF0YSIsCiAgemxhYiA9ICJcblByKFk9MSkiLAogIHhsYWIgPSAiXG5NZWFuIE1vaXN0dXJlIEluZGV4IExvd2VzdCBRdWFydGVyIiwKICB5bGFiID0gIlxuVG9wb2dyYXBoaWMgV2V0bmVzcyBJbmRleCIsCiAgY29sID0gImNvcm5mbG93ZXJibHVlIiwgYm9yZGVyID0gInNhbG1vbiIsCiAgdGhldGEgPSAyNSwgcGhpID0gNDUsCiAgZm9udC5tYWluID0gMwopCgojJyAjIyAyRCBTdXJmYWNlIFByZWRpY3Rpb25zCiMrIHN1cmZhY2UtMmQtcGxvdCwgZmlnLndpZHRoPTEwCmZvciAoaSBpbiBsZXZlbHMobW9kZWxfZ3JhbXBpYW5zQGZsaXN0JHRheG9uKSkgewogIHBhbmVsX2RhdGEgPC0gZGF0YS5mcmFtZSgKICAgIHggPSBjb3ZhcmlhdGVfcG9seXNfZXhwZFssICJtbHEiXSwKICAgIHkgPSBjb3ZhcmlhdGVfcG9seXNfZXhwZFssICJ0d2kiXSwKICAgIHogPSBwcmVkaWN0X3Byb2JfdGF4b24obW9kZWxfZ3JhbXBpYW5zLCBpLCBjb3ZhcmlhdGVfcG9seXNfZXhwZCkKICApCgogIHJ1Z19kYXRhIDwtIGxhcHBseSgKICAgIGMoYWJzZW50ID0gRkFMU0UsIHByZXNlbnQgPSBUUlVFKSwKICAgIGZ1bmN0aW9uKHgpIHsKICAgICAgYW5zIDwtIHN1YnNldCgKICAgICAgICBtZGcsCiAgICAgICAgdGF4b24gPT0gaSAmIG9jY3VwYW5jeSA9PSB4LAogICAgICAgIGMoIm1scSIsICJ0d2kiKQogICAgICApCiAgICAgIG5hbWVzKGFucykgPC0gYygieCIsICJ5IikKICAgICAgYW5zCiAgICB9CiAgKQoKICBkZW5zaXR5cGxvdCA8LQogICAgZ2dwbG90KHBhbmVsX2RhdGEpICsKICAgIGFlcyh4LCB5LCB6ID0geiwgZmlsbCA9IHopICsKICAgIGdlb21fcmFzdGVyKGFscGhhID0gLjcpICsKICAgIGdlb21fcnVnKAogICAgICBkYXRhID0gcnVnX2RhdGEkYWJzZW50LCBhZXMoeCwgeSksIGluaGVyaXQuYWVzID0gRkFMU0UsIGNvbCA9ICJncmV5IgogICAgKSArCiAgICBnZW9tX3J1ZygKICAgICAgZGF0YSA9IHJ1Z19kYXRhJHByZXNlbnQsIGFlcyh4LCB5KSwgaW5oZXJpdC5hZXMgPSBGQUxTRSwgY29sID0gImJsYWNrIgogICAgKSArCiAgICBzY2FsZV9maWxsX2dyYWRpZW50bihuYW1lID0gIlByKFk9MSkiLCBjb2xvdXJzID0gZ3JleS5jb2xvcnMoNTAsIDEsIDApKSArCiAgICB4bGFiKCJNZWFuIE1vaXN0dXJlIEluZGV4IExvd2VzdCBRdWFydGVyIikgKwogICAgeWxhYigiVG9wb2dyYXBoaWMgV2V0bmVzcyBJbmRleCIpICsKICAgIGdndGl0bGUoaSkgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJpdGFsaWMiKSkKCiAgcHJpbnQoZGVuc2l0eXBsb3QpCn0KCiMnICMjIFBhcnRpYWwgRGVwZW5kZW5jZSBQbG90cwojKyBwYXJ0aWFsLWRlcGVuZGVuY2UtcGxvdHMsIGZpZy53aWR0aD0xMAp4IDwtIGxpc3QoCiAgbWVhbl9tb2lzdHVyZV9pbmRleF9vZl9sb3dfcXRyID0KICAgIHNlcV9ybmcobWRnJG1lYW5fbW9pc3R1cmVfaW5kZXhfb2ZfbG93X3F0ciwgbmEucm0gPSBUUlVFKSwKICB0b3BvZ3JhcGhpY193ZXRuZXNzX2luZGV4XzNzZWMgPQogICAgc2VxX3JuZyhtZGckdG9wb2dyYXBoaWNfd2V0bmVzc19pbmRleF8zc2VjLCBuYS5ybSA9IFRSVUUpLAogIHJlbGllZl8xMDAwbV9yYWRpdXMgPQogICAgc2VxX3JuZyhtZGckcmVsaWVmXzEwMDBtX3JhZGl1cywgbmEucm0gPSBUUlVFKSwKICB0b3RhbF9uaXRyb2dlbiA9CiAgICBzZXFfcm5nKG1kZyR0b3RhbF9uaXRyb2dlbiwgbmEucm0gPSBUUlVFKQopCm5wIDwtIGxpc3QoCiAgIk1lYW4gTW9pc3R1cmUgSW5kZXggTG93ZXN0IFF1YXJ0ZXIiID0KICAgIG5ld19wb2x5KHVuc2NhbGVkX2NvdmFyaWF0ZXMsIDEsIGNvbG5hbWVzID0gbmFtZXMoY292YXJpYXRlX25tcykKICApLAogICJUb3BvZ3JhcGhpYyBXZXRuZXNzIEluZGV4IiA9CiAgICBuZXdfcG9seSh1bnNjYWxlZF9jb3ZhcmlhdGVzLCAyLCBjb2xuYW1lcyA9IG5hbWVzKGNvdmFyaWF0ZV9ubXMpCiAgKSwKICAiUmVsaWVmIDEwMDBtIFJhZGl1cyIgPQogICAgbmV3X3BvbHkodW5zY2FsZWRfY292YXJpYXRlcywgMywgY29sbmFtZXMgPSBuYW1lcyhjb3ZhcmlhdGVfbm1zKQogICksCiAgIlRvdGFsIE5pdHJvZ2VuIiA9CiAgICBuZXdfcG9seSh1bnNjYWxlZF9jb3ZhcmlhdGVzLCA0LCBjb2xuYW1lcyA9IG5hbWVzKGNvdmFyaWF0ZV9ubXMpCiAgKQopCgpwYXIobWZyb3cgPSBjKDEsIDQpLCBvbWEgPSBjKDAsIDQsIDQsIDApLCBmb250Lm1haW4gPSAzLCBsYXMgPSAxKQpmb3IoaSBpbiBsZXZlbHMobW9kZWxfZ3JhbXBpYW5zQGZsaXN0JHRheG9uKSkgewogIGZvciAoaiBpbiBzZXFfYWxvbmcobnApKSB7CiAgICBwYXIobWFyID0gYyg1LCAwLCAwLCAxKSkKICAgIHBsb3QoeFtbal1dLCBwcmVkaWN0X3Byb2JfdGF4b24obW9kZWxfZ3JhbXBpYW5zLCBpLCBucFtbal1dKSwKICAgICAgeWxpbSA9IDA6MSwgdHlwZSA9ICJsIiwgbHdkID0gMywKICAgICAgeWxhYiA9IGlmZWxzZShqID09IDEsICJQcihZPTEpIiwgIiIpLAogICAgICB4bGFiID0gbmFtZXMobnApW2pdLCB5YXh0ID0gaWZlbHNlKGogPT0gMSwgInMiLCAibiIpLAogICAgICBwYW5lbC5maXJzdCA9IGdyaWQoKSwgeHBkID0gTkEKICAgICkKICAgIHdpdGgoCiAgICAgIHN1YnNldChtZGcsIHRheG9uID09IGkpLAogICAgICBwb2ludHMoCiAgICAgICAgZ2V0KG5hbWVzKHhbal0pKSwgaWZlbHNlKG9jY3VwYW5jeSwgMS4wMiwgLS4wMiksIHBjaCA9IDE1LAogICAgICAgIGNvbCA9IHJnYiguMSwgLjEsIC4xLCAuMSkKICAgICAgKQogICAgKQogIH0KICB0aXRsZShpLCBvdXRlciA9IFRSVUUpCn0KCgojKyB0d28tdGF4YS1wYXJ0aWFsLWRlcGVuZGVuY2UtcGxvdCwgZmlnLndpZHRoPTcuNSwgZmlnLmhlaWdodD0yLjUKcGFyKG1mcm93ID0gYygxLCA0KSwgb21hID0gYygwLCA0LCAxLCAwKSwgbGFzID0gMSkKZm9yIChqIGluIHNlcV9hbG9uZyhucCkpIHsKICBwYXIobWFyID0gYyg1LCAwLCAwLCAxKSkKICBwbG90KAogICAgeFtbal1dLAogICAgcHJlZGljdF9wcm9iX3RheG9uKG1vZGVsX2dyYW1waWFucywgIkV1Y2FseXB0dXMgbWVsbGlvZG9yYSIsIG5wW1tqXV0pLAogICAgeWxpbSA9IDA6MSwgdHlwZSA9ICJsIiwgbHdkID0gMywgY29sID0gImJsYWNrIiwKICAgIHlsYWIgPSBpZmVsc2UoaiA9PSAxLCAiUHIoWT0xKSIsICIiKSwKICAgIHhsYWIgPSBuYW1lcyhucClbal0sIHlheHQgPSBpZmVsc2UoaiA9PSAxLCAicyIsICJuIiksCiAgICBwYW5lbC5maXJzdCA9IGdyaWQoKSwgeHBkID0gTkEKICApCiAgd2l0aCgKICAgIHN1YnNldChtZGcsIHRheG9uID09ICJFdWNhbHlwdHVzIG1lbGxpb2RvcmEiKSwKICAgIHBvaW50cygKICAgICAgZ2V0KG5hbWVzKHhbal0pKSwgaWZlbHNlKG9jY3VwYW5jeSwgMS4wMjUsIC0uMDEpLCBwY2ggPSAxNSwKICAgICAgY29sID0gcmdiKC4yLCAuMiwgLjIsIC4xKQogICAgKQogICkKICBwb2ludHMoCiAgICB4W1tqXV0sCiAgICBwcmVkaWN0X3Byb2JfdGF4b24obW9kZWxfZ3JhbXBpYW5zLCAiRXVjYWx5cHR1cyBvYmxpcXVhIiwgbnBbW2pdXSksCiAgICB0eXBlID0gImwiLCBsd2QgPSAzLCBjb2wgPSAiZ3JleSIKICApCiAgd2l0aCgKICAgIHN1YnNldChtZGcsIHRheG9uID09ICJFdWNhbHlwdHVzIG9ibGlxdWEiKSwKICAgIHBvaW50cygKICAgICAgZ2V0KG5hbWVzKHhbal0pKSwgaWZlbHNlKG9jY3VwYW5jeSwgMS4wMSwgLS4wMjUpLCBwY2ggPSAxNSwKICAgICAgY29sID0gIHJnYiguOCwgLjgsIC44LCAuMSkKICAgICkKICApCn0KbGVnZW5kKAogICJ0b3ByaWdodCIsCiAgbGVnZW5kID0gYygiRXVjYWx5cHR1cyBtZWxsaW9kb3JhIiwgIkV1Y2FseXB0dXMgb2JsaXF1YSIpLAogIGZpbGwgPSBjKCJibGFjayIsICJncmV5IiksIG5jb2wgPSAxLCBidHkgPSAibiIsIHRleHQuZm9udCA9IDMsCiAgYm9yZGVyID0gTkEsIHkuaW50ZXJzcCA9IDIsIGluc2V0ID0gLjA1CikKCgo=