knitr::opts_chunk$set(cache = TRUE, dev = c("png", "pdf"))
library(here)
source(here("src", "model_linear_grampians.R"))
library(forcats)
library(ggplot2)
Coefficient Plot
covariate_nms <- c(
mlq = "Mean Moisture\nIndex Lowest\nQuarter",
twi = "Topographic\nWetness\nIndex",
r1k = "Relief 1000m\nRadius",
tn = "Total Nitrogen"
)
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",
mlq = "Mean\nMoisture\nIndex Lowest\nQuarter",
twi = "Topographic\nWetness\nIndex",
r1k = "Relief 1000m\nRadius",
tn = "Total Nitrogen"
)
)
) +
scale_x_discrete(name = "") +
ylab("Standardised coefficients") +
theme_bw() +
theme(axis.text.y = element_text(face = "italic"))

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 = covariate_nms,
ylim = c(-3, 3),
plot.log = c("", "", "x")
)

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)
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)
data.frame(
x = x,
y = y,
x_raw = x_raw,
y_raw = y_raw,
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)[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 = 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)
}




















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 = c(-.02, 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, .99, -.04), 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
)

IycgLS0tCiMnIHRpdGxlOiAiUGxvdHMgZm9yIG1vZGVsIG9mIEdyYW1waWFucyBPY2N1cGFuY3kgYW5kIFRyYWl0IERhdGEgd2l0aCBsaW5lYXIgcmVsYXRpb25zaGlwcyIKIycgYXV0aG9yOiAiV2lsbGlhbSBLLiBNb3JyaXMiCiMnIGRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKIycgb3V0cHV0OgojJyAgIHJtYXJrZG93bjo6aHRtbF9ub3RlYm9vazoKIycgICAgIGNvZGVfZm9sZGluZzogaGlkZQojJyAtLS0KCiMrIHNldHVwLCBtZXNzYWdlPUZBTFNFCmtuaXRyOjpvcHRzX2NodW5rJHNldChjYWNoZSA9IFRSVUUsIGRldiA9IGMoInBuZyIsICJwZGYiKSkKbGlicmFyeShoZXJlKQpzb3VyY2UoaGVyZSgic3JjIiwgIm1vZGVsX2xpbmVhcl9ncmFtcGlhbnMuUiIpKQpsaWJyYXJ5KGZvcmNhdHMpCmxpYnJhcnkoZ2dwbG90MikKCiMnICMjIENvZWZmaWNpZW50IFBsb3QKIysgY29lZi1wbG90LCBmaWcud2lkdGg9Ny41CmNvdmFyaWF0ZV9ubXMgPC0gYygKICBtbHEgPSAiTWVhbiBNb2lzdHVyZVxuSW5kZXggTG93ZXN0XG5RdWFydGVyIiwKICB0d2kgPSAiVG9wb2dyYXBoaWNcbldldG5lc3NcbkluZGV4IiwKICByMWsgPSAiUmVsaWVmIDEwMDBtXG5SYWRpdXMiLAogIHRuICA9ICJUb3RhbCBOaXRyb2dlbiIKKQoKY29lZl9ncmFtcGlhbnMgPC0gYXMuZGF0YS5mcmFtZS50YWJsZShjb2VmX3NpbXMobW9kZWxfZ3JhbXBpYW5zKSkKCmNvZWZfZ3JhbXBpYW5zJFZhcjEgPC0gZmN0X3JlY29kZSgKICBjb2VmX2dyYW1waWFucyRWYXIxLAogIGBFdWNhbHlwdHVzIGdvbmlvY2FseXhgID0gIkV1Y2FseXB0dXMgKGdvbmlvY2FseXh8bm9ydG9uaWkpIiwKICBgRXVjYWx5cHR1cyB2aW1pbmFsaXMgc3Vic3AuIHZpbWluYWxpc2AgPQogICAgIkV1Y2FseXB0dXMgdmltaW5hbGlzIHN1YnNwLiAocHJ5b3JpYW5hfHZpbWluYWxpcykiCikKCmNvZWZfZ3JhbXBpYW5zJFZhcjEgPC0gYXMuY2hhcmFjdGVyKGNvZWZfZ3JhbXBpYW5zJFZhcjEpCmNvZWZfZ3JhbXBpYW5zJFZhcjEgPC0gZ3N1YigiRXVjYWx5cHR1cyIsICJFLiIsIGNvZWZfZ3JhbXBpYW5zJFZhcjEpCmNvZWZfZ3JhbXBpYW5zJFZhcjEgPC0gZ3N1Yigic3Vic3AuIiwgInNzcC4iLCBjb2VmX2dyYW1waWFucyRWYXIxKQoKZ2dwbG90KGNvZWZfZ3JhbXBpYW5zKSArCmFlcyhmYWN0b3IoVmFyMSwgbGV2ZWxzID0gcmV2KGxldmVscyhmYWN0b3IoVmFyMSkpKSksIEZyZXEpICsKZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwpnZW9tX3Zpb2xpbihmaWxsID0gImdyZXkzNSIsIHNjYWxlID0gIndpZHRoIiwgd2lkdGggPSAuNSwgdHJpbSA9IFRSVUUpICsKY29vcmRfZmxpcCgpICsKZmFjZXRfZ3JpZCgKICB+VmFyMiwKICBsYWJlbGxlciA9IGFzX2xhYmVsbGVyKAogICAgYygKICAgICAgYChJbnRlcmNlcHQpYCA9ICJJbnRlcmNlcHQiLAogICAgICBtbHEgID0gIk1lYW5cbk1vaXN0dXJlXG5JbmRleCBMb3dlc3RcblF1YXJ0ZXIiLAogICAgICB0d2kgID0gIlRvcG9ncmFwaGljXG5XZXRuZXNzXG5JbmRleCIsCiAgICAgIHIxayAgPSAiUmVsaWVmIDEwMDBtXG5SYWRpdXMiLAogICAgICB0biAgPSAiVG90YWwgTml0cm9nZW4iCiAgICApCiAgKQopICsKc2NhbGVfeF9kaXNjcmV0ZShuYW1lID0gIiIpICsKeWxhYigiU3RhbmRhcmRpc2VkIGNvZWZmaWNpZW50cyIpICsKdGhlbWVfYncoKSArCnRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiaXRhbGljIikpCgojJyAjIyBUcmFpdC1FbnZpcm9ubWVudGFsIFJlc3BvbnNlIFJlbGF0aW9uc2hpcHMKIysgdHJhaXQtZW52LXBsb3QsIGZpZy53aWR0aD03LjUsIGZpZy5oZWlnaHQ9Ny41CnRyYWl0X2Vudl9wbG90KAogIG1vZGVsX2dyYW1waWFucywKICBtb2RlbGRhdGFfZ3JhbXBpYW5zLAogIGd2YXJzID0gYygKICAgIHNsYSA9ICJzbGFfbW0yX3Blcl9tZyIsIHNtID0gInNlZWRfbWFzc19tZyIsIG1oID0gIm1heF9oZWlnaHRfbSIKICApLAogIHhsYWJzID0gbGlzdCgKICAgIGV4cHJlc3Npb24oU0xBfihtbV4yfm1nXi0xKSksICJTZWVkIE1hc3MgKG1nKSIsICJNYXhpbXVtIEhlaWdodCAobSkiCiAgKSwKICB5bGFicyA9IGNvdmFyaWF0ZV9ubXMsCiAgeWxpbSA9IGMoLTMsIDMpLAogIHBsb3QubG9nID0gYygiIiwgIiIsICJ4IikKKQoKIycgIyMgVHJhaXRzLUVudmlyb25tZW50YWwgUmVzcG9uc2UgMkQgU3VyZmFjZXMKIysgdHJhaXQtZW52LXN1cmZhY2UsIGZpZy53aWR0aD03LjUKcGFuZWxfZGF0YSA8LSBtYXBwbHkoCiAgZnVuY3Rpb24oc2xhX3Jhdywgc21fcmF3KSB7CiAgICBzbGEgICAgPC0gbG9nKG1kZyRzbGFfbW0yX3Blcl9tZykKICAgIHNsYV9tICA8LSBtZWFuKHNsYSkKICAgIHNsYV9zZCA8LSBzZChzbGEpCiAgICBzbSAgICAgPC0gbG9nKG1kZyRzZWVkX21hc3NfbWcpCiAgICBzbV9tICAgPC0gbWVhbihzbSkKICAgIHNtX3NkICA8LSBzZChzbSkKICAgIHggPC0gcmVwKHNlcV9ybmcobWRnJG1scSwgbmEucm0gPSBUUlVFLCBsZW5ndGgub3V0ID0gNTApLCB0aW1lcyA9IDUwKQogICAgeSA8LSByZXAoc2VxX3JuZyhtZGckdHdpLCBuYS5ybSA9IFRSVUUsIGxlbmd0aC5vdXQgPSA1MCksIGVhY2ggPSA1MCkKICAgIHhfcmF3IDwtIHJlcChzZXFfcm5nKG1kZyRtZWFuX21vaXN0dXJlX2luZGV4X29mX2xvd19xdHIsIG5hLnJtID0gVFJVRSwgbGVuZ3RoLm91dCA9IDUwKSwgdGltZXMgPSA1MCkKICAgIHlfcmF3IDwtIHJlcChzZXFfcm5nKG1kZyR0b3BvZ3JhcGhpY193ZXRuZXNzX2luZGV4XzNzZWMsIG5hLnJtID0gVFJVRSwgbGVuZ3RoLm91dCA9IDUwKSwgZWFjaCA9IDUwKQogICAgZGF0YS5mcmFtZSgKICAgICAgeCA9IHgsCiAgICAgIHkgPSB5LAogICAgICB4X3JhdyA9IHhfcmF3LAogICAgICB5X3JhdyA9IHlfcmF3LAogICAgICB6ID0gcHJlZGljdF9wcm9iX25ld190YXhvbigKICAgICAgICBtb2RlbF9ncmFtcGlhbnMsCiAgICAgICAgZGF0YS5mcmFtZSgKICAgICAgICAgIG1scSA9IHgsCiAgICAgICAgICB0d2kgPSB5LAogICAgICAgICAgcjFrID0gMCwKICAgICAgICAgIHRuID0gMCwKICAgICAgICAgIHNsYSA9IChsb2coc2xhX3JhdykgLSBzbGFfbSkgLyBzbGFfc2QsCiAgICAgICAgICBzbSAgPSAobG9nKHNtX3JhdykgLSBzbV9tKSAvIHNtX3NkLAogICAgICAgICAgbWggPSAwCiAgICAgICAgKQogICAgICApLAogICAgICBzbGEgPSBzbGFfcmF3LAogICAgICBzbSAgPSBzbV9yYXcKICAgICkKICB9LAogIHNsYV9yYXcgPSBjKDMsIDUsIDMsIDUpLAogIHNtX3JhdyA9IGMoLjUsIC41LCAxLjUsIDEuNSksCiAgU0lNUExJRlkgPSBGQUxTRQopCgpwYW5lbF9kYXRhIDwtIGRvLmNhbGwocmJpbmQsIHBhbmVsX2RhdGEpCmNvbG5hbWVzKHBhbmVsX2RhdGEpWzY6N10gPC0gYygiU0xBIiwgIlNlZWQgTWFzcyIpCgpnZ3Bsb3QocGFuZWxfZGF0YSkgKwphZXMoeF9yYXcsIHlfcmF3LCB6ID0geiwgZmlsbCA9IHopICsKZ2VvbV9yYXN0ZXIoYWxwaGEgPSAuNykgKwpnZW9tX2NvbnRvdXIoY29sID0gImdyZXkiKSArCnNjYWxlX2ZpbGxfZ3JhZGllbnRuKAogIG5hbWUgPSAiUHIoWT0xKSIsIGNvbG91cnMgPSBncmV5LmNvbG9ycyg1MCwgMSwgLjEsIGdhbW1hID0gLjMpCikgKwp4bGFiKCJNZWFuIE1vaXN0dXJlIEluZGV4IExvd2VzdCBRdWFydGVyIikgKwp5bGFiKCJUb3BvZ3JhcGhpYyBXZXRuZXNzIEluZGV4IikgKwpmYWNldF9ncmlkKGBTZWVkIE1hc3NgIH4gU0xBLCBsYWJlbGxlciA9IGxhYmVsX2JvdGgpICsKdGhlbWVfYncoKQoKIycgIyMgM0QgUmVzcG9uc2UgU3VyZmFjZQojKyByZXNwb25zZS1zdXJmYWNlLTNkLCBmaWcud2lkdGg9MTAKcGVyc3AoCiAgbGlzdCgKICAgIHggPSBzZXFfcm5nKG1kZyRtbHEsIG5hLnJtID0gVFJVRSwgbGVuZ3RoLm91dCA9IDUwKSwKICAgIHkgPSBzZXFfcm5nKG1kZyR0d2ksIG5hLnJtID0gVFJVRSwgbGVuZ3RoLm91dCA9IDUwKQogICksCiAgeiA9IG1hdHJpeCgKICAgIHByZWRpY3RfcHJvYl90YXhvbigKICAgICAgbW9kZWxfZ3JhbXBpYW5zLAogICAgICAiRXVjYWx5cHR1cyByYWRpYXRhIiwKICAgICAgZGF0YS5mcmFtZSgKICAgICAgICBtbHEgPSByZXAoc2VxX3JuZyhtZGckbWxxLCBuYS5ybSA9IFRSVUUsIGxlbmd0aC5vdXQgPSA1MCksIHRpbWVzID0gNTApLAogICAgICAgIHR3aSA9IHJlcChzZXFfcm5nKG1kZyR0d2ksIG5hLnJtID0gVFJVRSwgbGVuZ3RoLm91dCA9IDUwKSwgZWFjaCA9IDUwKSwKICAgICAgICByMWsgPSAwLAogICAgICAgIHRuID0gMAogICAgICApCiAgICApLAogICAgNTAKICApLAogIG1haW4gPSAiRXVjYWx5cHR1cyByYWRpYXRhIiwKICB6bGFiID0gIlxuUHIoWT0xKSIsCiAgeGxhYiA9ICJcbk1lYW4gTW9pc3R1cmUgSW5kZXggTG93ZXN0IFF1YXJ0ZXIiLAogIHlsYWIgPSAiXG5Ub3BvZ3JhcGhpYyBXZXRuZXNzIEluZGV4IiwKICBjb2wgPSAiY29ybmZsb3dlcmJsdWUiLCBib3JkZXIgPSAic2FsbW9uIiwKICB0aGV0YSA9IDI1LCBwaGkgPSA0NSwKICBmb250Lm1haW4gPSAzCikKCiMnICMjIDJEIFN1cmZhY2UgUHJlZGljdGlvbnMKIysgc3VyZmFjZS0yZC1wbG90LCBmaWcud2lkdGg9MTAKZm9yIChpIGluIGxldmVscyhtb2RlbF9ncmFtcGlhbnNAZmxpc3QkdGF4b24pKSB7CiAgcGFuZWxfZGF0YSA8LSBkYXRhLmZyYW1lKAogICAgeCA9IHJlcChzZXFfcm5nKG1kZyRtbHEsIG5hLnJtID0gVFJVRSwgbGVuZ3RoLm91dCA9IDUwKSwgdGltZXMgPSA1MCksCiAgICB5ID0gcmVwKHNlcV9ybmcobWRnJHR3aSwgbmEucm0gPSBUUlVFLCBsZW5ndGgub3V0ID0gNTApLCBlYWNoID0gNTApLAogICAgeiA9IHByZWRpY3RfcHJvYl90YXhvbigKICAgICAgbW9kZWxfZ3JhbXBpYW5zLCBpLAogICAgICBjYmluZCgKICAgICAgICBtbHEgPSByZXAoc2VxX3JuZyhtZGckbWxxLCBuYS5ybSA9IFRSVUUsIGxlbmd0aC5vdXQgPSA1MCksIHRpbWVzID0gNTApLAogICAgICAgIHR3aSA9IHJlcChzZXFfcm5nKG1kZyR0d2ksIG5hLnJtID0gVFJVRSwgbGVuZ3RoLm91dCA9IDUwKSwgZWFjaCA9IDUwKSwKICAgICAgICByMWsgPSAwLAogICAgICAgIHRuID0gMAogICAgICApCiAgICApCiAgKQoKICBydWdfZGF0YSA8LSBsYXBwbHkoCiAgICBjKGFic2VudCA9IEZBTFNFLCBwcmVzZW50ID0gVFJVRSksCiAgICBmdW5jdGlvbih4KSB7CiAgICAgIGFucyA8LSBzdWJzZXQoCiAgICAgICAgbWRnLAogICAgICAgIHRheG9uID09IGkgJiBvY2N1cGFuY3kgPT0geCwKICAgICAgICBjKCJtbHEiLCAidHdpIikKICAgICAgKQogICAgICBuYW1lcyhhbnMpIDwtIGMoIngiLCAieSIpCiAgICAgIGFucwogICAgfQogICkKCiAgZGVuc2l0eXBsb3QgPC0KICAgIGdncGxvdChwYW5lbF9kYXRhKSArCiAgICBhZXMoeCwgeSwgeiA9IHosIGZpbGwgPSB6KSArCiAgICBnZW9tX3Jhc3RlcihhbHBoYSA9IC43KSArCiAgICBnZW9tX3J1ZygKICAgICAgZGF0YSA9IHJ1Z19kYXRhJGFic2VudCwgYWVzKHgsIHkpLCBpbmhlcml0LmFlcyA9IEZBTFNFLCBjb2wgPSAiZ3JleSIKICAgICkgKwogICAgZ2VvbV9ydWcoCiAgICAgIGRhdGEgPSBydWdfZGF0YSRwcmVzZW50LCBhZXMoeCwgeSksIGluaGVyaXQuYWVzID0gRkFMU0UsIGNvbCA9ICJibGFjayIKICAgICkgKwogICAgc2NhbGVfZmlsbF9ncmFkaWVudG4obmFtZSA9ICJQcihZPTEpIiwgY29sb3VycyA9IGdyZXkuY29sb3JzKDUwLCAxLCAwKSkgKwogICAgeGxhYigiTWVhbiBNb2lzdHVyZSBJbmRleCBMb3dlc3QgUXVhcnRlciIpICsKICAgIHlsYWIoIlRvcG9ncmFwaGljIFdldG5lc3MgSW5kZXgiKSArCiAgICBnZ3RpdGxlKGkpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiaXRhbGljIikpCgogIHByaW50KGRlbnNpdHlwbG90KQp9CgojJyAjIyBQYXJ0aWFsIERlcGVuZGVuY2UgUGxvdHMKIysgcGFydGlhbC1kZXBlbmRlbmNlLXBsb3RzLCBmaWcud2lkdGg9MTAKeCA8LSBsaXN0KAogIG1lYW5fbW9pc3R1cmVfaW5kZXhfb2ZfbG93X3F0ciA9CiAgICBzZXFfcm5nKG1kZyRtZWFuX21vaXN0dXJlX2luZGV4X29mX2xvd19xdHIsIG5hLnJtID0gVFJVRSksCiAgdG9wb2dyYXBoaWNfd2V0bmVzc19pbmRleF8zc2VjID0KICAgIHNlcV9ybmcobWRnJHRvcG9ncmFwaGljX3dldG5lc3NfaW5kZXhfM3NlYywgbmEucm0gPSBUUlVFKSwKICByZWxpZWZfMTAwMG1fcmFkaXVzID0KICAgIHNlcV9ybmcobWRnJHJlbGllZl8xMDAwbV9yYWRpdXMsIG5hLnJtID0gVFJVRSksCiAgdG90YWxfbml0cm9nZW4gPQogICAgc2VxX3JuZyhtZGckdG90YWxfbml0cm9nZW4sIG5hLnJtID0gVFJVRSkKKQpucCA8LSBsaXN0KAogICJNZWFuIE1vaXN0dXJlIEluZGV4IExvd2VzdCBRdWFydGVyIiA9IGRhdGEuZnJhbWUoCiAgICBtbHEgPSBzZXFfcm5nKG1kZyRtbHEsIG5hLnJtID0gVFJVRSksIHR3aSA9IDAsIHIxayA9IDAsIHRuID0gMAogICksCiAgIlRvcG9ncmFwaGljIFdldG5lc3MgSW5kZXgiID0gZGF0YS5mcmFtZSgKICAgIHR3aSA9IHNlcV9ybmcobWRnJG1scSwgbmEucm0gPSBUUlVFKSwgbWxxID0gMCwgcjFrID0gMCwgdG4gPSAwCiAgKSwKICAiUmVsaWVmIDEwMDBtIFJhZGl1cyIgPWRhdGEuZnJhbWUoCiAgICByMWsgPSBzZXFfcm5nKG1kZyRtbHEsIG5hLnJtID0gVFJVRSksIHR3aSA9IDAsIG1scSA9IDAsIHRuID0gMAogICksCiAgIlRvdGFsIE5pdHJvZ2VuIiA9IGRhdGEuZnJhbWUoCiAgICB0biA9IHNlcV9ybmcobWRnJG1scSwgbmEucm0gPSBUUlVFKSwgdHdpID0gMCwgcjFrID0gMCwgbWxxID0gMAogICkKKQoKcGFyKG1mcm93ID0gYygxLCA0KSwgb21hID0gYygwLCA0LCA0LCAwKSwgZm9udC5tYWluID0gMywgbGFzID0gMSkKZm9yKGkgaW4gbGV2ZWxzKG1vZGVsX2dyYW1waWFuc0BmbGlzdCR0YXhvbikpIHsKICBmb3IgKGogaW4gc2VxX2Fsb25nKG5wKSkgewogICAgcGFyKG1hciA9IGMoNSwgMCwgMCwgMSkpCiAgICBwbG90KHhbW2pdXSwgcHJlZGljdF9wcm9iX3RheG9uKG1vZGVsX2dyYW1waWFucywgaSwgbnBbW2pdXSksCiAgICAgIHlsaW0gPSAwOjEsIHR5cGUgPSAibCIsIGx3ZCA9IDMsCiAgICAgIHlsYWIgPSBpZmVsc2UoaiA9PSAxLCAiUHIoWT0xKSIsICIiKSwKICAgICAgeGxhYiA9IG5hbWVzKG5wKVtqXSwgeWF4dCA9IGlmZWxzZShqID09IDEsICJzIiwgIm4iKSwKICAgICAgcGFuZWwuZmlyc3QgPSBncmlkKCksIHhwZCA9IE5BCiAgICApCiAgICB3aXRoKAogICAgICBzdWJzZXQobWRnLCB0YXhvbiA9PSBpKSwKICAgICAgcG9pbnRzKAogICAgICAgIGdldChuYW1lcyh4W2pdKSksIGlmZWxzZShvY2N1cGFuY3ksIDEuMDIsIC0uMDIpLCBwY2ggPSAxNSwKICAgICAgICBjb2wgPSByZ2IoLjEsIC4xLCAuMSwgLjEpCiAgICAgICkKICAgICkKICB9CiAgdGl0bGUoaSwgb3V0ZXIgPSBUUlVFKQp9CgojKyB0d28tdGF4YS1wYXJ0aWFsLWRlcGVuZGVuY2UtcGxvdCwgZmlnLndpZHRoPTcuNSwgZmlnLmhlaWdodD0yLjUKcGFyKG1mcm93ID0gYygxLCA0KSwgb21hID0gYygwLCA0LCAxLCAwKSwgbGFzID0gMSkKZm9yIChqIGluIHNlcV9hbG9uZyhucCkpIHsKICBwYXIobWFyID0gYyg1LCAwLCAwLCAxKSkKICBwbG90KAogICAgeFtbal1dLAogICAgcHJlZGljdF9wcm9iX3RheG9uKG1vZGVsX2dyYW1waWFucywgIkV1Y2FseXB0dXMgbWVsbGlvZG9yYSIsIG5wW1tqXV0pLAogICAgeWxpbSA9IGMoLS4wMiwgMSksIHR5cGUgPSAibCIsIGx3ZCA9IDMsIGNvbCA9ICJibGFjayIsCiAgICB5bGFiID0gaWZlbHNlKGogPT0gMSwgIlByKFk9MSkiLCAiIiksCiAgICB4bGFiID0gbmFtZXMobnApW2pdLCB5YXh0ID0gaWZlbHNlKGogPT0gMSwgInMiLCAibiIpLAogICAgcGFuZWwuZmlyc3QgPSBncmlkKCksIHhwZCA9IE5BCiAgKQogIHdpdGgoCiAgICBzdWJzZXQobWRnLCB0YXhvbiA9PSAiRXVjYWx5cHR1cyBtZWxsaW9kb3JhIiksCiAgICBwb2ludHMoCiAgICAgIGdldChuYW1lcyh4W2pdKSksIGlmZWxzZShvY2N1cGFuY3ksIDEuMDI1LCAtLjAxKSwgcGNoID0gMTUsCiAgICAgIGNvbCA9IHJnYiguMiwgLjIsIC4yLCAuMSkKICAgICkKICApCiAgcG9pbnRzKAogICAgeFtbal1dLAogICAgcHJlZGljdF9wcm9iX3RheG9uKG1vZGVsX2dyYW1waWFucywgIkV1Y2FseXB0dXMgb2JsaXF1YSIsIG5wW1tqXV0pLAogICAgdHlwZSA9ICJsIiwgbHdkID0gMywgY29sID0gImdyZXkiCiAgKQogIHdpdGgoCiAgICBzdWJzZXQobWRnLCB0YXhvbiA9PSAiRXVjYWx5cHR1cyBvYmxpcXVhIiksCiAgICBwb2ludHMoCiAgICAgIGdldChuYW1lcyh4W2pdKSksIGlmZWxzZShvY2N1cGFuY3ksIC45OSwgLS4wNCksIHBjaCA9IDE1LAogICAgICBjb2wgPSByZ2IoLjgsIC44LCAuOCwgLjEpCiAgICApCiAgKQp9CmxlZ2VuZCgKICAidG9wcmlnaHQiLAogIGxlZ2VuZCA9IGMoIkV1Y2FseXB0dXMgbWVsbGlvZG9yYSIsICJFdWNhbHlwdHVzIG9ibGlxdWEiKSwKICBmaWxsID0gYygiYmxhY2siLCAiZ3JleSIpLCBuY29sID0gMSwgYnR5ID0gIm4iLCB0ZXh0LmZvbnQgPSAzLAogIGJvcmRlciA9IE5BLCB5LmludGVyc3AgPSAyLCBpbnNldCA9IC4wNQopCgo=