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

Coefficient Plot

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

ggplot(coef_grampians) +
aes(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",
      mlq  = "Mean Moisture\nIndex Lowest\nQuarter",
      twi  = "Topographic\nWetness\nIndex",
      r1k  = "Relief 1000m\nRadius",
      tn  = "Total Nitrogen"
    )
  )
) +
scale_x_discrete(name = "", limits = rev(levels(coef_grampians$Var1))) +
ylab("Standardised coefficients") +
theme_bw()

Trait-Environmental Response Relationships

trait_env_plot(
  model_grampians,
  modeldata_grampians,
  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 = c(
    "Mean Moisture Index\nLowest Quarter", "Topographic\nWetness Index",
    "Relief 1000m Radius", "Total Nitrogen"
  )
)

Traits-Environmental Response 2D Surfaces

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)
    x <- rep(seq_rng(mdg$mlq, na.rm = TRUE, length.out = 50), times = 50)
    y <- rep(seq_rng(mdg$twi, na.rm = TRUE, length.out = 50), each = 50)
    data.frame(
      x = x,
      y = y,
      z = predict_prob_new_taxon(
        model_grampians,
        data.frame(
          mlq = x,
          twi = y,
          r1k = 0,
          tn = 0,
          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)[4:5] <- c("SLA", "Seed Mass")

ggplot(panel_data) +
aes(x, y, 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 = seq_rng(mdg$mlq, na.rm = TRUE, length.out = 50),
    y = seq_rng(mdg$twi, na.rm = TRUE, length.out = 50)
  ),
  z = matrix(
    predict_prob_taxon(
      model_grampians,
      "Eucalyptus radiata",
      data.frame(
        mlq = rep(seq_rng(mdg$mlq, na.rm = TRUE, length.out = 50), times = 50),
        twi = rep(seq_rng(mdg$twi, na.rm = TRUE, length.out = 50), each = 50),
        r1k = 0,
        tn = 0
      )
    ),
    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 = rep(seq_rng(mdg$mlq, na.rm = TRUE, length.out = 50), times = 50),
    y = rep(seq_rng(mdg$twi, na.rm = TRUE, length.out = 50), each = 50),
    z = predict_prob_taxon(
      model_grampians, i,
      cbind(
        mlq = rep(seq_rng(mdg$mlq, na.rm = TRUE, length.out = 50), times = 50),
        twi = rep(seq_rng(mdg$twi, na.rm = TRUE, length.out = 50), each = 50),
        r1k = 0,
        tn = 0
      )
    )
  )

  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" = data.frame(
    mlq = seq_rng(mdg$mlq, na.rm = TRUE), twi = 0, r1k = 0, tn = 0
  ),
  "Topographic Wetness Index" = data.frame(
    twi = seq_rng(mdg$mlq, na.rm = TRUE), mlq = 0, r1k = 0, tn = 0
  ),
  "Relief 1000m Radius" =data.frame(
    r1k = seq_rng(mdg$mlq, na.rm = TRUE), twi = 0, mlq = 0, tn = 0
  ),
  "Total Nitrogen" = data.frame(
    tn = seq_rng(mdg$mlq, na.rm = TRUE), twi = 0, r1k = 0, mlq = 0
  )
)

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)
}

IycgLS0tCiMnIHRpdGxlOiAiUGxvdHMgZm9yIG1vZGVsIG9mIEdyYW1waWFucyBPY2N1cGFuY3kgYW5kIFRyYWl0IERhdGEgd2l0aCBsaW5lYXIgcmVsYXRpb25zaGlwcyBhbmQgbG9jYXRpb24gcmFuZG9tIGVmZmVjdCIKIycgYXV0aG9yOiAiV2lsbGlhbSBLLiBNb3JyaXMiCiMnIGRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKIycgb3V0cHV0OgojJyAgIHJtYXJrZG93bjo6aHRtbF9ub3RlYm9vazoKIycgICAgIGNvZGVfZm9sZGluZzogaGlkZQojJyAtLS0KCiMrIHNldHVwLCBtZXNzYWdlPUZBTFNFCmtuaXRyOjpvcHRzX2NodW5rJHNldChjYWNoZSA9IFRSVUUsIGRldiA9IGMoInBuZyIsICJwZGYiKSkKbGlicmFyeShoZXJlKQpzb3VyY2UoaGVyZSgic3JjIiwgIm1vZGVsX2xpbmVhcl9sb2NhbGl0eV9ncmFtcGlhbnMuUiIpKQpsaWJyYXJ5KGdncGxvdDIpCgojJyAjIyBDb2VmZmljaWVudCBQbG90CiMrIGNvZWYtcGxvdCwgZmlnLndpZHRoPTEwCmNvZWZfZ3JhbXBpYW5zIDwtIGFzLmRhdGEuZnJhbWUudGFibGUoY29lZl9zaW1zKG1vZGVsX2dyYW1waWFucykpCgpnZ3Bsb3QoY29lZl9ncmFtcGlhbnMpICsKYWVzKFZhcjEsIEZyZXEpICsKZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwpnZW9tX3Zpb2xpbihmaWxsID0gImdyZXkzNSIsIHNjYWxlID0gIndpZHRoIiwgd2lkdGggPSAuNSwgdHJpbSA9IFRSVUUpICsKY29vcmRfZmxpcCgpICsKZmFjZXRfZ3JpZCgKICB+VmFyMiwKICBsYWJlbGxlciA9IGFzX2xhYmVsbGVyKAogICAgYygKICAgICAgYChJbnRlcmNlcHQpYCA9ICJJbnRlcmNlcHQiLAogICAgICBtbHEgID0gIk1lYW4gTW9pc3R1cmVcbkluZGV4IExvd2VzdFxuUXVhcnRlciIsCiAgICAgIHR3aSAgPSAiVG9wb2dyYXBoaWNcbldldG5lc3NcbkluZGV4IiwKICAgICAgcjFrICA9ICJSZWxpZWYgMTAwMG1cblJhZGl1cyIsCiAgICAgIHRuICA9ICJUb3RhbCBOaXRyb2dlbiIKICAgICkKICApCikgKwpzY2FsZV94X2Rpc2NyZXRlKG5hbWUgPSAiIiwgbGltaXRzID0gcmV2KGxldmVscyhjb2VmX2dyYW1waWFucyRWYXIxKSkpICsKeWxhYigiU3RhbmRhcmRpc2VkIGNvZWZmaWNpZW50cyIpICsKdGhlbWVfYncoKQoKIycgIyMgVHJhaXQtRW52aXJvbm1lbnRhbCBSZXNwb25zZSBSZWxhdGlvbnNoaXBzCiMrIHRyYWl0LWVudi1wbG90LCBmaWcud2lkdGg9MTAKdHJhaXRfZW52X3Bsb3QoCiAgbW9kZWxfZ3JhbXBpYW5zLAogIG1vZGVsZGF0YV9ncmFtcGlhbnMsCiAgZ3ZhcnMgPSBjKAogICAgc2xhID0gInNsYV9tbTJfcGVyX21nIiwgc20gPSAic2VlZF9tYXNzX21nIiwgbWggPSAibWF4X2hlaWdodF9tIgogICksCiAgeGxhYnMgPSBsaXN0KAogICAgZXhwcmVzc2lvbihTTEF+KG1tXjJ+bWdeLTEpKSwgIlNlZWQgTWFzcyAobWcpIiwgIk1heGltdW0gSGVpZ2h0IChtKSIKICApLAogIHlsYWJzID0gYygKICAgICJNZWFuIE1vaXN0dXJlIEluZGV4XG5Mb3dlc3QgUXVhcnRlciIsICJUb3BvZ3JhcGhpY1xuV2V0bmVzcyBJbmRleCIsCiAgICAiUmVsaWVmIDEwMDBtIFJhZGl1cyIsICJUb3RhbCBOaXRyb2dlbiIKICApCikKCiMnICMjIFRyYWl0cy1FbnZpcm9ubWVudGFsIFJlc3BvbnNlIDJEIFN1cmZhY2VzCiMrIHRyYWl0LWVudi1zdXJmYWNlLCBmaWcud2lkdGg9MTAKcGFuZWxfZGF0YSA8LSBtYXBwbHkoCiAgZnVuY3Rpb24oc2xhX3Jhdywgc21fcmF3KSB7CiAgICBzbGEgICAgPC0gbG9nKG1kZyRzbGFfbW0yX3Blcl9tZykKICAgIHNsYV9tICA8LSBtZWFuKHNsYSkKICAgIHNsYV9zZCA8LSBzZChzbGEpCiAgICBzbSAgICAgPC0gbG9nKG1kZyRzZWVkX21hc3NfbWcpCiAgICBzbV9tICAgPC0gbWVhbihzbSkKICAgIHNtX3NkICA8LSBzZChzbSkKICAgIHggPC0gcmVwKHNlcV9ybmcobWRnJG1scSwgbmEucm0gPSBUUlVFLCBsZW5ndGgub3V0ID0gNTApLCB0aW1lcyA9IDUwKQogICAgeSA8LSByZXAoc2VxX3JuZyhtZGckdHdpLCBuYS5ybSA9IFRSVUUsIGxlbmd0aC5vdXQgPSA1MCksIGVhY2ggPSA1MCkKICAgIGRhdGEuZnJhbWUoCiAgICAgIHggPSB4LAogICAgICB5ID0geSwKICAgICAgeiA9IHByZWRpY3RfcHJvYl9uZXdfdGF4b24oCiAgICAgICAgbW9kZWxfZ3JhbXBpYW5zLAogICAgICAgIGRhdGEuZnJhbWUoCiAgICAgICAgICBtbHEgPSB4LAogICAgICAgICAgdHdpID0geSwKICAgICAgICAgIHIxayA9IDAsCiAgICAgICAgICB0biA9IDAsCiAgICAgICAgICBzbGEgPSAobG9nKHNsYV9yYXcpIC0gc2xhX20pIC8gc2xhX3NkLAogICAgICAgICAgc20gID0gKGxvZyhzbV9yYXcpIC0gc21fbSkgLyBzbV9zZCwKICAgICAgICAgIG1oID0gMAogICAgICAgICkKICAgICAgKSwKICAgICAgc2xhID0gc2xhX3JhdywKICAgICAgc20gID0gc21fcmF3CiAgICApCiAgfSwKICBzbGFfcmF3ID0gYygzLCA1LCAzLCA1KSwKICBzbV9yYXcgPSBjKC41LCAuNSwgMS41LCAxLjUpLAogIFNJTVBMSUZZID0gRkFMU0UKKQoKcGFuZWxfZGF0YSA8LSBkby5jYWxsKHJiaW5kLCBwYW5lbF9kYXRhKQpjb2xuYW1lcyhwYW5lbF9kYXRhKVs0OjVdIDwtIGMoIlNMQSIsICJTZWVkIE1hc3MiKQoKZ2dwbG90KHBhbmVsX2RhdGEpICsKYWVzKHgsIHksIHogPSB6LCBmaWxsID0geikgKwpnZW9tX3Jhc3RlcihhbHBoYSA9IC43KSArCmdlb21fY29udG91cihjb2wgPSAiZ3JleSIpICsKc2NhbGVfZmlsbF9ncmFkaWVudG4oCiAgbmFtZSA9ICJQcihZPTEpIiwgY29sb3VycyA9IGdyZXkuY29sb3JzKDUwLCAxLCAuMSwgZ2FtbWEgPSAuMykKKSArCnhsYWIoIk1lYW4gTW9pc3R1cmUgSW5kZXggTG93ZXN0IFF1YXJ0ZXIiKSArCnlsYWIoIlRvcG9ncmFwaGljIFdldG5lc3MgSW5kZXgiKSArCmZhY2V0X2dyaWQoYFNlZWQgTWFzc2AgfiBTTEEsIGxhYmVsbGVyID0gbGFiZWxfYm90aCkgKwp0aGVtZV9idygpCgojJyAjIyAzRCBSZXNwb25zZSBTdXJmYWNlCiMrIHJlc3BvbnNlLXN1cmZhY2UtM2QsIGZpZy53aWR0aD0xMApwZXJzcCgKICBsaXN0KAogICAgeCA9IHNlcV9ybmcobWRnJG1scSwgbmEucm0gPSBUUlVFLCBsZW5ndGgub3V0ID0gNTApLAogICAgeSA9IHNlcV9ybmcobWRnJHR3aSwgbmEucm0gPSBUUlVFLCBsZW5ndGgub3V0ID0gNTApCiAgKSwKICB6ID0gbWF0cml4KAogICAgcHJlZGljdF9wcm9iX3RheG9uKAogICAgICBtb2RlbF9ncmFtcGlhbnMsCiAgICAgICJFdWNhbHlwdHVzIHJhZGlhdGEiLAogICAgICBkYXRhLmZyYW1lKAogICAgICAgIG1scSA9IHJlcChzZXFfcm5nKG1kZyRtbHEsIG5hLnJtID0gVFJVRSwgbGVuZ3RoLm91dCA9IDUwKSwgdGltZXMgPSA1MCksCiAgICAgICAgdHdpID0gcmVwKHNlcV9ybmcobWRnJHR3aSwgbmEucm0gPSBUUlVFLCBsZW5ndGgub3V0ID0gNTApLCBlYWNoID0gNTApLAogICAgICAgIHIxayA9IDAsCiAgICAgICAgdG4gPSAwCiAgICAgICkKICAgICksCiAgICA1MAogICksCiAgbWFpbiA9ICJFdWNhbHlwdHVzIHJhZGlhdGEiLAogIHpsYWIgPSAiXG5QcihZPTEpIiwKICB4bGFiID0gIlxuTWVhbiBNb2lzdHVyZSBJbmRleCBMb3dlc3QgUXVhcnRlciIsCiAgeWxhYiA9ICJcblRvcG9ncmFwaGljIFdldG5lc3MgSW5kZXgiLAogIGNvbCA9ICJjb3JuZmxvd2VyYmx1ZSIsIGJvcmRlciA9ICJzYWxtb24iLAogIHRoZXRhID0gMjUsIHBoaSA9IDQ1LAogIGZvbnQubWFpbiA9IDMKKQoKIycgIyMgMkQgU3VyZmFjZSBQcmVkaWN0aW9ucwojKyBzdXJmYWNlLTJkLXBsb3QsIGZpZy53aWR0aD0xMApmb3IgKGkgaW4gbGV2ZWxzKG1vZGVsX2dyYW1waWFuc0BmbGlzdCR0YXhvbikpIHsKICBwYW5lbF9kYXRhIDwtIGRhdGEuZnJhbWUoCiAgICB4ID0gcmVwKHNlcV9ybmcobWRnJG1scSwgbmEucm0gPSBUUlVFLCBsZW5ndGgub3V0ID0gNTApLCB0aW1lcyA9IDUwKSwKICAgIHkgPSByZXAoc2VxX3JuZyhtZGckdHdpLCBuYS5ybSA9IFRSVUUsIGxlbmd0aC5vdXQgPSA1MCksIGVhY2ggPSA1MCksCiAgICB6ID0gcHJlZGljdF9wcm9iX3RheG9uKAogICAgICBtb2RlbF9ncmFtcGlhbnMsIGksCiAgICAgIGNiaW5kKAogICAgICAgIG1scSA9IHJlcChzZXFfcm5nKG1kZyRtbHEsIG5hLnJtID0gVFJVRSwgbGVuZ3RoLm91dCA9IDUwKSwgdGltZXMgPSA1MCksCiAgICAgICAgdHdpID0gcmVwKHNlcV9ybmcobWRnJHR3aSwgbmEucm0gPSBUUlVFLCBsZW5ndGgub3V0ID0gNTApLCBlYWNoID0gNTApLAogICAgICAgIHIxayA9IDAsCiAgICAgICAgdG4gPSAwCiAgICAgICkKICAgICkKICApCgogIHJ1Z19kYXRhIDwtIGxhcHBseSgKICAgIGMoYWJzZW50ID0gRkFMU0UsIHByZXNlbnQgPSBUUlVFKSwKICAgIGZ1bmN0aW9uKHgpIHsKICAgICAgYW5zIDwtIHN1YnNldCgKICAgICAgICBtZGcsCiAgICAgICAgdGF4b24gPT0gaSAmIG9jY3VwYW5jeSA9PSB4LAogICAgICAgIGMoIm1scSIsICJ0d2kiKQogICAgICApCiAgICAgIG5hbWVzKGFucykgPC0gYygieCIsICJ5IikKICAgICAgYW5zCiAgICB9CiAgKQoKICBkZW5zaXR5cGxvdCA8LQogICAgZ2dwbG90KHBhbmVsX2RhdGEpICsKICAgIGFlcyh4LCB5LCB6ID0geiwgZmlsbCA9IHopICsKICAgIGdlb21fcmFzdGVyKGFscGhhID0gLjcpICsKICAgIGdlb21fcnVnKAogICAgICBkYXRhID0gcnVnX2RhdGEkYWJzZW50LCBhZXMoeCwgeSksIGluaGVyaXQuYWVzID0gRkFMU0UsIGNvbCA9ICJncmV5IgogICAgKSArCiAgICBnZW9tX3J1ZygKICAgICAgZGF0YSA9IHJ1Z19kYXRhJHByZXNlbnQsIGFlcyh4LCB5KSwgaW5oZXJpdC5hZXMgPSBGQUxTRSwgY29sID0gImJsYWNrIgogICAgKSArCiAgICBzY2FsZV9maWxsX2dyYWRpZW50bihuYW1lID0gIlByKFk9MSkiLCBjb2xvdXJzID0gZ3JleS5jb2xvcnMoNTAsIDEsIDApKSArCiAgICB4bGFiKCJNZWFuIE1vaXN0dXJlIEluZGV4IExvd2VzdCBRdWFydGVyIikgKwogICAgeWxhYigiVG9wb2dyYXBoaWMgV2V0bmVzcyBJbmRleCIpICsKICAgIGdndGl0bGUoaSkgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJpdGFsaWMiKSkKCiAgcHJpbnQoZGVuc2l0eXBsb3QpCn0KCiMnICMjIFBhcnRpYWwgRGVwZW5kZW5jZSBQbG90cwojKyBwYXJ0aWFsLWRlcGVuZGVuY2UtcGxvdHMsIGZpZy53aWR0aD0xMAp4IDwtIGxpc3QoCiAgbWVhbl9tb2lzdHVyZV9pbmRleF9vZl9sb3dfcXRyID0KICAgIHNlcV9ybmcobWRnJG1lYW5fbW9pc3R1cmVfaW5kZXhfb2ZfbG93X3F0ciwgbmEucm0gPSBUUlVFKSwKICB0b3BvZ3JhcGhpY193ZXRuZXNzX2luZGV4XzNzZWMgPQogICAgc2VxX3JuZyhtZGckdG9wb2dyYXBoaWNfd2V0bmVzc19pbmRleF8zc2VjLCBuYS5ybSA9IFRSVUUpLAogIHJlbGllZl8xMDAwbV9yYWRpdXMgPQogICAgc2VxX3JuZyhtZGckcmVsaWVmXzEwMDBtX3JhZGl1cywgbmEucm0gPSBUUlVFKSwKICB0b3RhbF9uaXRyb2dlbiA9CiAgICBzZXFfcm5nKG1kZyR0b3RhbF9uaXRyb2dlbiwgbmEucm0gPSBUUlVFKQopCm5wIDwtIGxpc3QoCiAgIk1lYW4gTW9pc3R1cmUgSW5kZXggTG93ZXN0IFF1YXJ0ZXIiID0gZGF0YS5mcmFtZSgKICAgIG1scSA9IHNlcV9ybmcobWRnJG1scSwgbmEucm0gPSBUUlVFKSwgdHdpID0gMCwgcjFrID0gMCwgdG4gPSAwCiAgKSwKICAiVG9wb2dyYXBoaWMgV2V0bmVzcyBJbmRleCIgPSBkYXRhLmZyYW1lKAogICAgdHdpID0gc2VxX3JuZyhtZGckbWxxLCBuYS5ybSA9IFRSVUUpLCBtbHEgPSAwLCByMWsgPSAwLCB0biA9IDAKICApLAogICJSZWxpZWYgMTAwMG0gUmFkaXVzIiA9ZGF0YS5mcmFtZSgKICAgIHIxayA9IHNlcV9ybmcobWRnJG1scSwgbmEucm0gPSBUUlVFKSwgdHdpID0gMCwgbWxxID0gMCwgdG4gPSAwCiAgKSwKICAiVG90YWwgTml0cm9nZW4iID0gZGF0YS5mcmFtZSgKICAgIHRuID0gc2VxX3JuZyhtZGckbWxxLCBuYS5ybSA9IFRSVUUpLCB0d2kgPSAwLCByMWsgPSAwLCBtbHEgPSAwCiAgKQopCgpwYXIobWZyb3cgPSBjKDEsIDQpLCBvbWEgPSBjKDAsIDQsIDQsIDApLCBmb250Lm1haW4gPSAzLCBsYXMgPSAxKQpmb3IoaSBpbiBsZXZlbHMobW9kZWxfZ3JhbXBpYW5zQGZsaXN0JHRheG9uKSkgewogIGZvciAoaiBpbiBzZXFfYWxvbmcobnApKSB7CiAgICBwYXIobWFyID0gYyg1LCAwLCAwLCAxKSkKICAgIHBsb3QoeFtbal1dLCBwcmVkaWN0X3Byb2JfdGF4b24obW9kZWxfZ3JhbXBpYW5zLCBpLCBucFtbal1dKSwKICAgICAgeWxpbSA9IDA6MSwgdHlwZSA9ICJsIiwgbHdkID0gMywKICAgICAgeWxhYiA9IGlmZWxzZShqID09IDEsICJQcihZPTEpIiwgIiIpLAogICAgICB4bGFiID0gbmFtZXMobnApW2pdLCB5YXh0ID0gaWZlbHNlKGogPT0gMSwgInMiLCAibiIpLAogICAgICBwYW5lbC5maXJzdCA9IGdyaWQoKSwgeHBkID0gTkEKICAgICkKICAgIHdpdGgoCiAgICAgIHN1YnNldChtZGcsIHRheG9uID09IGkpLAogICAgICBwb2ludHMoCiAgICAgICAgZ2V0KG5hbWVzKHhbal0pKSwgaWZlbHNlKG9jY3VwYW5jeSwgMS4wMiwgLS4wMiksIHBjaCA9IDE1LAogICAgICAgIGNvbCA9IHJnYiguMSwgLjEsIC4xLCAuMSkKICAgICAgKQogICAgKQogIH0KICB0aXRsZShpLCBvdXRlciA9IFRSVUUpCn0K