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