library(ggplot2)
library(patchwork)
library(mvtnorm)
set.seed(431)
One Metropolis–Hastings update step
MHstep <- function(theta_current, sig) {
theta_star <- rnorm(1, mean = theta_current, sd = sig) # propose candidate θ*
accprob <- targetdist(theta_star) / targetdist(theta_current) # acceptance probability
accprob <- min(1, accprob)
# accept or reject
u <- runif(1)
if (u <= accprob) {
theta_next <- theta_star
a <- 1
} else {
theta_next <- theta_current
a <- 0
}
return(list(theta1 = theta_next, a = a))
}
Metropolis–Hastings Sampler
MH_sampler <- function(nsamp, sig, burnin, lag, theta_current) {
theta_samples <- numeric(nsamp)
acc <- c(accepted = 0, proposed = 0)
theta <- theta_current # starting value
# Burn-in
for (i in 1:burnin) {
step <- MHstep(theta, sig)
theta <- step$theta1
acc <- acc + c(step$a, 1)
}
# Main sampling
for (i in 1:nsamp) {
for (j in 1:lag) {
step <- MHstep(theta, sig)
theta <- step$theta1
acc <- acc + c(step$a, 1)
}
theta_samples[i] <- theta
}
return(list(samples = theta_samples, acc = acc))
}
Visualization function
plot_MH <- function(sig, nsamp = NULL, theta_initial = NULL) {
# Pull global defaults if user does not override
if (is.null(nsamp)) nsamp <- get("nsamp", envir = .GlobalEnv)
if (is.null(theta_initial)) theta_initial <- get("theta_initial", envir = .GlobalEnv)
# Run MH sampler
result <- MH_sampler(
nsamp = nsamp,
sig = sig,
burnin = burnin,
lag = lag,
theta_current = theta_initial # pass renamed argument to MH sampler
)
theta_vals <- result$samples
# True normalized density
thetas <- seq(-3, 3, length.out = 500)
dens <- targetdist(thetas)
dens <- dens / sum(dens) / (thetas[2] - thetas[1])
df_samples <- data.frame(theta = theta_vals)
df_true <- data.frame(theta = thetas, y = dens)
# Histogram + True Density
p1 <- ggplot() +
geom_histogram(data = df_samples,
aes(theta, y = ..density.., fill = "Samples"),
bins = 30, color = "black") +
geom_line(data = df_true,
aes(theta, y, color = "True Density"),
size = 1.1) +
scale_color_manual(values = c("True Density" = "red")) +
scale_fill_manual(values = c("Samples" = "gray80")) +
labs(
title = paste0("Metropolis–Hastings Sampling (σ = ", sig, ")"),
subtitle = paste0(
"burn-in = ", burnin,
", nsamp = ", nsamp,
", initial θ = ", theta_initial
),
x = expression(theta), y = "density",
color = "", fill = ""
) +
theme_bw(base_size = 14)
# ---------------- Trace Plot ----------------
df_trace <- data.frame(iter = 1:length(theta_vals), value = theta_vals)
p2 <- ggplot(df_trace, aes(iter, value)) +
geom_line(color = "black") +
labs(
title = "Trace Plot",
subtitle = paste0(
"burn-in = ", burnin,
", kept samples = ", nsamp,
", initial θ = ", theta_initial
),
y = expression(theta~value),
x = "iteration"
) +
theme_bw(base_size = 14)
# Return stacked plots
p1 / p2
}
Example
set.seed(431)
# Target distribution (unnormalized)
targetdist <- function(theta) {
exp(-theta^4/6 + theta^2/2) * cos(theta^3/4)
}
burnin <- 8000
lag <- 1
nsamp <- 50000
theta_initial <- 0
# global default
#plot_MH(sig = 0.1)
#plot_MH(sig = 1)
#plot_MH(sig = 10)
# 1. Well-tuned, centered start
plot_MH(sig = 1, nsamp = 3000, theta_initial = 0)

# 2. Same σ, bad initial value
plot_MH(sig = 1, nsamp = 3000, theta_initial = 6)

# 3. Smaller step size, slower mixing
plot_MH(sig = 0.01, nsamp = 3000, theta_initial = 0)

Gibbs Sampler for Normal Model with Semi-Conjugate Priors
# Data summary
n <- 24
ybar <- 7.8730 # sample mean
s <- 0.05353 # sample sd
### Prior parameters
mu0 <- 7.9876 # prior mean for mu
sigma0.2 <- 0.000625 # prior variance of mu
alpha <- 2.5 # IG(alpha, beta)
beta <- 0.0043
# Run Gibbs sampler
Nsim <- 100000 # total draws
mus <- numeric(Nsim) # store mu draws
sigma2 <- numeric(Nsim) # store sigma^2 draws
## Initial values
mus[1] <- 8
SSE1 <- (n-1)*s^2 + n*(ybar - mus[1])^2
sigma2[1] <- 1 / rgamma(1, n/2 + alpha, SSE1/2 + beta)
## Gibbs updates
for (k in 2:Nsim) {
### 1. Sample mu | sigma^2, y
var_mu <- 1 / (n / sigma2[k-1] + 1 / sigma0.2)
mean_mu <- var_mu * (n*ybar / sigma2[k-1] + mu0 / sigma0.2)
mus[k] <- rnorm(1, mean_mu, sqrt(var_mu))
### 2. Sample sigma^2 | mu, y
SSE <- (n-1)*s^2 + n*(ybar - mus[k])^2
sigma2[k] <- 1 / rgamma(1, n/2 + alpha, SSE/2 + beta)
}
# Posterior summaries
cat("Posterior mean(mu):", mean(mus), "\n")
Posterior mean(mu): 7.893102
cat("Posterior sd(mu):", sd(mus), "\n")
Posterior sd(mu): 0.01170627
cat("95% CI for mu:\n"); print(quantile(mus, c(0.025, 0.975)))
95% CI for mu:
2.5% 97.5%
7.871854 7.917967
cat("\nPosterior mean(sigma^2):", mean(sigma2), "\n")
Posterior mean(sigma^2): 0.003244212
cat("95% CI for sigma^2:\n"); print(quantile(sigma2, c(0.025, 0.975)))
95% CI for sigma^2:
2.5% 97.5%
0.001803182 0.005834502
# Visualize first few Gibbs steps
maxit <- 20
plot(mus[1:maxit], sigma2[1:maxit], type = "n",
xlab = expression(mu), ylab = expression(sigma^2),
main = "First 20 Gibbs Iterations")
arrows(mus[1:(maxit-1)], sigma2[1:(maxit-1)],
mus[2:maxit], sigma2[2:maxit],
length = 0.1, angle = 30, col = rainbow(maxit-1))
points(mus[1:maxit], sigma2[1:maxit], pch = 20)

# Trace plots
trace_mu <- ggplot(data.frame(iter = 1:Nsim, mu = mus),
aes(iter, mu)) +
geom_line(color = "steelblue") +
labs(title = "Trace Plot for μ",
x = "Iteration", y = expression(mu)) +
theme_bw(14)
trace_sigma2 <- ggplot(data.frame(iter = 1:Nsim, sigma2 = sigma2),
aes(iter, sigma2)) +
geom_line(color = "firebrick") +
labs(title = expression("Trace Plot for " * sigma^2),
x = "Iteration", y = expression(sigma^2)) +
theme_bw(14)
# Posterior density plots
dens_mu <- ggplot(data.frame(mu = mus), aes(mu)) +
geom_density(fill = "steelblue", alpha = 0.4) +
geom_vline(xintercept = mean(mus), color = "blue", linetype = 2) +
labs(title = "Posterior Density of μ",
x = expression(mu), y = "Density") +
theme_bw(14)
dens_sigma2 <- ggplot(data.frame(sigma2 = sigma2), aes(sigma2)) +
geom_density(fill = "firebrick", alpha = 0.4) +
geom_vline(xintercept = mean(sigma2), color = "red", linetype = 2) +
labs(title = "Posterior Density of σ²",
x = expression(sigma^2), y = "Density") +
theme_bw(14)
# Joint posterior (μ, σ²)
df_post <- data.frame(mu = mus, sigma2 = sigma2)
joint_contour <- ggplot(df_post, aes(mu, sigma2)) +
stat_density_2d(aes(fill = ..level..), geom = "polygon", alpha = 0.6) +
scale_fill_viridis_c() +
labs(title = "Posterior Joint Density of (μ, σ²)",
x = expression(mu), y = expression(sigma^2)) +
theme_bw(14)
joint_heatmap <- ggplot(df_post, aes(mu, sigma2)) +
stat_density_2d_filled(contour_var = "density") +
labs(title = "Posterior Joint Density Heatmap",
x = expression(mu), y = expression(sigma^2)) +
theme_bw(14)
# Plot combined panels
( trace_mu | trace_sigma2 ) / ( dens_mu | dens_sigma2 )

joint_contour

joint_heatmap

MH Sampler
set.seed(431)
## Log-posterior for (mu, log_sigma2)
log_post <- function(mu, log_sigma2) {
sigma2 <- exp(log_sigma2)
# SSE(mu) using sufficient stats
SSE <- (n - 1)*s^2 + n*(ybar - mu)^2
# log-likelihood: N(mu, sigma2) for n observations
lp_y <- -(n/2) * log(2*pi*sigma2) - SSE/(2*sigma2)
# prior for mu ~ N(mu0, sigma0^2)
lp_mu <- dnorm(mu, mean = mu0, sd = sqrt(sigma0.2), log = TRUE)
# prior for sigma2 ~ IG(alpha, beta), up to constants:
# p(sigma2) ∝ (sigma2)^-(alpha+1) exp(-beta/sigma2)
lp_s2 <- -(alpha + 1)*log(sigma2) - beta/sigma2
# Jacobian for transform sigma2 = exp(log_sigma2)
lp_jac <- log_sigma2
return(lp_y + lp_mu + lp_s2 + lp_jac)
}
mh_sampler <- function(Nsim, start_mu, start_log_s2,
prop_sd_mu, prop_sd_log_s2) {
mu <- numeric(Nsim)
log_s2 <- numeric(Nsim)
mu[1] <- start_mu
log_s2[1] <- start_log_s2
acc <- 0
for (k in 2:Nsim) {
# Propose new (mu, log_sigma2) with Gaussian random walk
mu_prop <- rnorm(1, mean = mu[k-1], sd = prop_sd_mu)
log_s2_prop <- rnorm(1, mean = log_s2[k-1], sd = prop_sd_log_s2)
# Log acceptance ratio (symmetric proposal ⇒ q cancels)
log_alpha <- log_post(mu_prop, log_s2_prop) -
log_post(mu[k-1], log_s2[k-1])
if (log(runif(1)) < log_alpha) {
# accept
mu[k] <- mu_prop
log_s2[k] <- log_s2_prop
acc <- acc + 1
} else {
# reject (stay at previous)
mu[k] <- mu[k-1]
log_s2[k] <- log_s2[k-1]
}
}
list(mu = mu,
sigma2 = exp(log_s2),
acc_rate = acc / (Nsim - 1))
}
# Use Gibbs initial sigma2[1] as starting point for MH
mh_out <- mh_sampler(
Nsim = Nsim,
start_mu = mus[1],
start_log_s2 = log(sigma2[1]),
prop_sd_mu = 0.005, # tune these
prop_sd_log_s2 = 0.05
)
mh_out$acc_rate # check acceptance rate; aim ~ 0.2–0.5
[1] 0.8239982
Comparsion Plots
library(ggplot2)
library(patchwork)
df_comp <- data.frame(
iter = 1:Nsim,
gibbs_mu = mus,
mh_mu = mh_out$mu,
gibbs_sigma2 = sigma2,
mh_sigma2 = mh_out$sigma2
)
# Trace Plot
trace_mu_both <- ggplot(df_comp) +
geom_line(aes(iter, gibbs_mu, colour = "Gibbs")) +
geom_line(aes(iter, mh_mu, colour = "MH"), alpha = 0.7) +
scale_colour_manual(values = c("Gibbs" = "steelblue",
"MH" = "orange")) +
labs(title = "Trace Plot for μ: Gibbs vs MH",
x = "Iteration", y = expression(mu), colour = "") +
theme_bw(14)
trace_s2_both <- ggplot(df_comp) +
geom_line(aes(iter, gibbs_sigma2, colour = "Gibbs")) +
geom_line(aes(iter, mh_sigma2, colour = "MH"), alpha = 0.7) +
scale_colour_manual(values = c("Gibbs" = "firebrick",
"MH" = "darkgreen")) +
labs(title = expression("Trace Plot for " * sigma^2 * ": Gibbs vs MH"),
x = "Iteration", y = expression(sigma^2), colour = "") +
theme_bw(14)
trace_mu_both / trace_s2_both

# Density comparison
dens_mu_both <- ggplot(df_comp) +
geom_density(aes(gibbs_mu, colour = "Gibbs"), adjust = 1.2) +
geom_density(aes(mh_mu, colour = "MH"), adjust = 1.2, linetype = 2) +
scale_colour_manual(values = c("Gibbs" = "steelblue",
"MH" = "orange")) +
labs(title = "Posterior of μ: Gibbs vs MH",
x = expression(mu), y = "Density", colour = "") +
theme_bw(14)
dens_s2_both <- ggplot(df_comp) +
geom_density(aes(gibbs_sigma2, colour = "Gibbs"), adjust = 1.2) +
geom_density(aes(mh_sigma2, colour = "MH"), adjust = 1.2, linetype = 2) +
scale_colour_manual(values = c("Gibbs" = "firebrick",
"MH" = "darkgreen")) +
labs(title = expression("Posterior of " * sigma^2 * ": Gibbs vs MH"),
x = expression(sigma^2), y = "Density", colour = "") +
theme_bw(14)
dens_mu_both | dens_s2_both

# --- Gibbs heatmap
mh_mu_q <- quantile(df_comp$mh_mu, probs = c(0.005, 0.995))
mh_s2_q <- quantile(df_comp$mh_sigma2, probs = c(0.005, 0.995))
zoom_x <- c(mh_mu_q[1], mh_mu_q[2])
zoom_y <- c(mh_s2_q[1], mh_s2_q[2])
heat_gibbs_zoom <- ggplot(df_comp, aes(gibbs_mu, gibbs_sigma2)) +
stat_density_2d_filled(contour_var = "density", alpha = 0.9) +
stat_density_2d(color = "white", linewidth = 0.4) +
scale_fill_viridis_d(option = "C") +
coord_cartesian(xlim = zoom_x, ylim = zoom_y, expand = FALSE) +
labs(
title = "Joint Posterior Heatmap (Gibbs)",
x = expression(mu),
y = expression(sigma^2),
fill = "Density Level"
) +
theme_bw(base_size = 16) +
theme(
plot.title = element_text(size = 20, face = "bold", hjust = 0.5),
axis.title = element_text(size = 18),
axis.text = element_text(size = 14),
legend.title = element_text(size = 14),
legend.text = element_text(size = 12),
panel.border = element_rect(linewidth = 0.8, color = "black"),
panel.grid = element_blank()
)
heat_gibbs_zoom

# MH heatmap
heat_mh_zoom <- ggplot(df_comp, aes(mh_mu, mh_sigma2)) +
stat_density_2d_filled(contour_var = "density", alpha = 0.9) +
stat_density_2d(color = "white", linewidth = 0.4) +
scale_fill_viridis_d(option = "C") +
coord_cartesian(xlim = zoom_x, ylim = zoom_y, expand = FALSE) +
labs(
title = "Joint Posterior Heatmap (MH)",
x = expression(mu),
y = expression(sigma^2),
fill = "Density Level"
) +
theme_bw(base_size = 16) +
theme(
plot.title = element_text(size = 20, face = "bold", hjust = 0.5),
axis.title = element_text(size = 18),
axis.text = element_text(size = 14),
legend.title = element_text(size = 14),
legend.text = element_text(size = 12),
panel.border = element_rect(linewidth = 0.8, color = "black"),
panel.grid = element_blank()
)
heat_mh_zoom

# Set layout: 1 row, 2 columns
par(mfrow = c(1, 2), mar = c(5, 5, 4, 2))
# ------------------------------
# Panel 1: Posterior of μ
# ------------------------------
dens_gibbs_mu <- density(df_comp$gibbs_mu)
dens_mh_mu <- density(df_comp$mh_mu)
plot(dens_gibbs_mu,
main = "Posterior of μ: Gibbs vs MH",
xlab = expression(mu),
ylab = "Density",
col = "steelblue",
lwd = 2,
lty = 1, # solid
cex.lab = 1.3,
cex.main = 1.4)
lines(dens_mh_mu,
col = "orange",
lwd = 2,
lty = 2) # dashed
legend("topright",
legend = c("Gibbs (solid)", "MH (dashed)"),
col = c("steelblue", "orange"),
lwd = 2,
lty = c(1, 2),
bty = "n",
cex = 1.1)
# ------------------------------
# Panel 2: Posterior of σ²
# ------------------------------
dens_gibbs_s2 <- density(df_comp$gibbs_sigma2)
dens_mh_s2 <- density(df_comp$mh_sigma2)
plot(dens_gibbs_s2,
main = expression("Posterior of " * sigma^2 * ": Gibbs vs MH"),
xlab = expression(sigma^2),
ylab = "Density",
col = "firebrick",
lwd = 2,
lty = 1, # solid
cex.lab = 1.3,
cex.main = 1.4)
lines(dens_mh_s2,
col = "darkgreen",
lwd = 2,
lty = 2) # dashed
legend("topright",
legend = c("Gibbs (solid)", "MH (dashed)"),
col = c("firebrick", "darkgreen"),
lwd = 2,
lty = c(1, 2),
bty = "n",
cex = 1.1)
# Restore default layout
par(mfrow = c(1, 1))

LS0tCnRpdGxlOiAiTUggQWxnbyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwYXRjaHdvcmspICAKbGlicmFyeShtdnRub3JtKSAgCnNldC5zZWVkKDQzMSkKYGBgCgojIyMgICBPbmUgTWV0cm9wb2xpc+KAk0hhc3RpbmdzIHVwZGF0ZSBzdGVwCmBgYHtyfQpNSHN0ZXAgPC0gZnVuY3Rpb24odGhldGFfY3VycmVudCwgc2lnKSB7CiAgdGhldGFfc3RhciA8LSBybm9ybSgxLCBtZWFuID0gdGhldGFfY3VycmVudCwgc2QgPSBzaWcpICAjIHByb3Bvc2UgY2FuZGlkYXRlIM64KgogIGFjY3Byb2IgPC0gdGFyZ2V0ZGlzdCh0aGV0YV9zdGFyKSAvIHRhcmdldGRpc3QodGhldGFfY3VycmVudCkgICMgYWNjZXB0YW5jZSBwcm9iYWJpbGl0eQogIGFjY3Byb2IgPC0gbWluKDEsIGFjY3Byb2IpCiAgIyBhY2NlcHQgb3IgcmVqZWN0CiAgdSA8LSBydW5pZigxKQogIGlmICh1IDw9IGFjY3Byb2IpIHsKICAgIHRoZXRhX25leHQgPC0gdGhldGFfc3RhcgogICAgYSA8LSAxCiAgfSBlbHNlIHsKICAgIHRoZXRhX25leHQgPC0gdGhldGFfY3VycmVudAogICAgYSA8LSAwCiAgfQogIHJldHVybihsaXN0KHRoZXRhMSA9IHRoZXRhX25leHQsIGEgPSBhKSkKfQpgYGAKCgojIyMgIE1ldHJvcG9saXPigJNIYXN0aW5ncyBTYW1wbGVyCmBgYHtyfQpNSF9zYW1wbGVyIDwtIGZ1bmN0aW9uKG5zYW1wLCBzaWcsIGJ1cm5pbiwgbGFnLCB0aGV0YV9jdXJyZW50KSB7CiAgdGhldGFfc2FtcGxlcyA8LSBudW1lcmljKG5zYW1wKQogIGFjYyA8LSBjKGFjY2VwdGVkID0gMCwgcHJvcG9zZWQgPSAwKQogIHRoZXRhIDwtIHRoZXRhX2N1cnJlbnQgICAjIHN0YXJ0aW5nIHZhbHVlCiAgIyBCdXJuLWluCiAgZm9yIChpIGluIDE6YnVybmluKSB7CiAgICBzdGVwIDwtIE1Ic3RlcCh0aGV0YSwgc2lnKQogICAgdGhldGEgPC0gc3RlcCR0aGV0YTEKICAgIGFjYyA8LSBhY2MgKyBjKHN0ZXAkYSwgMSkKICB9CiAgIyBNYWluIHNhbXBsaW5nCiAgZm9yIChpIGluIDE6bnNhbXApIHsKICAgIGZvciAoaiBpbiAxOmxhZykgewogICAgICBzdGVwIDwtIE1Ic3RlcCh0aGV0YSwgc2lnKQogICAgICB0aGV0YSA8LSBzdGVwJHRoZXRhMQogICAgICBhY2MgPC0gYWNjICsgYyhzdGVwJGEsIDEpCiAgICB9CiAgICB0aGV0YV9zYW1wbGVzW2ldIDwtIHRoZXRhCiAgfQogIHJldHVybihsaXN0KHNhbXBsZXMgPSB0aGV0YV9zYW1wbGVzLCBhY2MgPSBhY2MpKQp9CmBgYAoKCiMjIyAgVmlzdWFsaXphdGlvbiBmdW5jdGlvbgoKCmBgYHtyfQpwbG90X01IIDwtIGZ1bmN0aW9uKHNpZywgbnNhbXAgPSBOVUxMLCB0aGV0YV9pbml0aWFsID0gTlVMTCkgewogIAogICMgUHVsbCBnbG9iYWwgZGVmYXVsdHMgaWYgdXNlciBkb2VzIG5vdCBvdmVycmlkZQogIGlmIChpcy5udWxsKG5zYW1wKSkgbnNhbXAgPC0gZ2V0KCJuc2FtcCIsIGVudmlyID0gLkdsb2JhbEVudikKICBpZiAoaXMubnVsbCh0aGV0YV9pbml0aWFsKSkgdGhldGFfaW5pdGlhbCA8LSBnZXQoInRoZXRhX2luaXRpYWwiLCBlbnZpciA9IC5HbG9iYWxFbnYpCiAgCiAgIyBSdW4gTUggc2FtcGxlcgogIHJlc3VsdCA8LSBNSF9zYW1wbGVyKAogICAgbnNhbXAgPSBuc2FtcCwKICAgIHNpZyA9IHNpZywKICAgIGJ1cm5pbiA9IGJ1cm5pbiwKICAgIGxhZyA9IGxhZywKICAgIHRoZXRhX2N1cnJlbnQgPSB0aGV0YV9pbml0aWFsICAgIyBwYXNzIHJlbmFtZWQgYXJndW1lbnQgdG8gTUggc2FtcGxlcgogICkKICAKICB0aGV0YV92YWxzIDwtIHJlc3VsdCRzYW1wbGVzCiAgCiAgIyBUcnVlIG5vcm1hbGl6ZWQgZGVuc2l0eQogIHRoZXRhcyA8LSBzZXEoLTMsIDMsIGxlbmd0aC5vdXQgPSA1MDApCiAgZGVucyA8LSB0YXJnZXRkaXN0KHRoZXRhcykKICBkZW5zIDwtIGRlbnMgLyBzdW0oZGVucykgLyAodGhldGFzWzJdIC0gdGhldGFzWzFdKQogIAogIGRmX3NhbXBsZXMgPC0gZGF0YS5mcmFtZSh0aGV0YSA9IHRoZXRhX3ZhbHMpCiAgZGZfdHJ1ZSAgICA8LSBkYXRhLmZyYW1lKHRoZXRhID0gdGhldGFzLCB5ID0gZGVucykKICAKICAjIEhpc3RvZ3JhbSArIFRydWUgRGVuc2l0eSAKIHAxIDwtIGdncGxvdCgpICsKICBnZW9tX2hpc3RvZ3JhbShkYXRhID0gZGZfc2FtcGxlcywKICAgICAgICAgICAgICAgICBhZXModGhldGEsIHkgPSAuLmRlbnNpdHkuLiwgZmlsbCA9ICJTYW1wbGVzIiksCiAgICAgICAgICAgICAgICAgYmlucyA9IDMwLCBjb2xvciA9ICJibGFjayIpICsKICBnZW9tX2xpbmUoZGF0YSA9IGRmX3RydWUsCiAgICAgICAgICAgIGFlcyh0aGV0YSwgeSwgY29sb3IgPSAiVHJ1ZSBEZW5zaXR5IiksCiAgICAgICAgICAgIHNpemUgPSAxLjEpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiVHJ1ZSBEZW5zaXR5IiA9ICJyZWQiKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIlNhbXBsZXMiID0gImdyYXk4MCIpKSArCiAgbGFicygKICAgIHRpdGxlID0gcGFzdGUwKCJNZXRyb3BvbGlz4oCTSGFzdGluZ3MgU2FtcGxpbmcgKM+DID0gIiwgc2lnLCAiKSIpLAogICAgc3VidGl0bGUgPSBwYXN0ZTAoCiAgICAgICJidXJuLWluID0gIiwgYnVybmluLAogICAgICAiLCAgbnNhbXAgPSAiLCBuc2FtcCwKICAgICAgIiwgIGluaXRpYWwgzrggPSAiLCB0aGV0YV9pbml0aWFsCiAgICApLAogICAgeCA9IGV4cHJlc3Npb24odGhldGEpLCB5ID0gImRlbnNpdHkiLAogICAgY29sb3IgPSAiIiwgZmlsbCA9ICIiCiAgKSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTQpCgogIAogICMgLS0tLS0tLS0tLS0tLS0tLSBUcmFjZSBQbG90IC0tLS0tLS0tLS0tLS0tLS0KICBkZl90cmFjZSA8LSBkYXRhLmZyYW1lKGl0ZXIgPSAxOmxlbmd0aCh0aGV0YV92YWxzKSwgdmFsdWUgPSB0aGV0YV92YWxzKQogIAogIHAyIDwtIGdncGxvdChkZl90cmFjZSwgYWVzKGl0ZXIsIHZhbHVlKSkgKwogICAgZ2VvbV9saW5lKGNvbG9yID0gImJsYWNrIikgKwogICAgbGFicygKICAgICAgdGl0bGUgPSAiVHJhY2UgUGxvdCIsCiAgICAgIHN1YnRpdGxlID0gcGFzdGUwKAogICAgICAgICJidXJuLWluID0gIiwgYnVybmluLAogICAgICAgICIsICBrZXB0IHNhbXBsZXMgPSAiLCBuc2FtcCwKICAgICAgICAiLCAgaW5pdGlhbCDOuCA9ICIsIHRoZXRhX2luaXRpYWwKICAgICAgKSwKICAgICAgeSA9IGV4cHJlc3Npb24odGhldGF+dmFsdWUpLAogICAgICB4ID0gIml0ZXJhdGlvbiIKICAgICkgKwogICAgdGhlbWVfYncoYmFzZV9zaXplID0gMTQpCiAgCiAgIyBSZXR1cm4gc3RhY2tlZCBwbG90cwogIHAxIC8gcDIKfQpgYGAKCiMjIEV4YW1wbGUKYGBge3J9CnNldC5zZWVkKDQzMSkKIyAgIFRhcmdldCBkaXN0cmlidXRpb24gKHVubm9ybWFsaXplZCkKdGFyZ2V0ZGlzdCA8LSBmdW5jdGlvbih0aGV0YSkgewogIGV4cCgtdGhldGFeNC82ICsgdGhldGFeMi8yKSAqIGNvcyh0aGV0YV4zLzQpCn0KYnVybmluIDwtIDgwMDAKbGFnIDwtIDEKbnNhbXAgPC0gNTAwMDAKdGhldGFfaW5pdGlhbCA8LSAwICAgCgojIGdsb2JhbCBkZWZhdWx0CiNwbG90X01IKHNpZyA9IDAuMSkKI3Bsb3RfTUgoc2lnID0gMSkKI3Bsb3RfTUgoc2lnID0gMTApCmBgYAoKCmBgYHtyfQojIDEuIFdlbGwtdHVuZWQsIGNlbnRlcmVkIHN0YXJ0CnBsb3RfTUgoc2lnID0gMSwgbnNhbXAgPSAzMDAwLCB0aGV0YV9pbml0aWFsID0gMCkKIyAyLiBTYW1lIM+DLCBiYWQgaW5pdGlhbCB2YWx1ZSAKcGxvdF9NSChzaWcgPSAxLCBuc2FtcCA9IDMwMDAsIHRoZXRhX2luaXRpYWwgPSA2KQojIDMuIFNtYWxsZXIgc3RlcCBzaXplLCBzbG93ZXIgbWl4aW5nCnBsb3RfTUgoc2lnID0gMC4wMSwgbnNhbXAgPSAzMDAwLCB0aGV0YV9pbml0aWFsID0gMCkKYGBgCgojICBHaWJicyBTYW1wbGVyIGZvciBOb3JtYWwgTW9kZWwgd2l0aCBTZW1pLUNvbmp1Z2F0ZSBQcmlvcnMKYGBge3J9CiMgRGF0YSBzdW1tYXJ5Cm4gICAgPC0gMjQKeWJhciA8LSA3Ljg3MzAgICAgICAgICAgICMgc2FtcGxlIG1lYW4KcyAgICAgPC0gMC4wNTM1MyAgICAgICAgICMgc2FtcGxlIHNkCgojIyMgUHJpb3IgcGFyYW1ldGVycwptdTAgICAgICAgPC0gNy45ODc2ICAgICAgIyBwcmlvciBtZWFuIGZvciBtdQpzaWdtYTAuMiAgPC0gMC4wMDA2MjUgICAgIyBwcmlvciB2YXJpYW5jZSBvZiBtdQphbHBoYSAgICAgPC0gMi41ICAgICAgICAgIyBJRyhhbHBoYSwgYmV0YSkKYmV0YSAgICAgIDwtIDAuMDA0MwoKIyAgUnVuIEdpYmJzIHNhbXBsZXIKTnNpbSA8LSAxMDAwMDAgICAgICAgICAgICAgICAjIHRvdGFsIGRyYXdzCm11cyA8LSBudW1lcmljKE5zaW0pICAgICAgICAgIyBzdG9yZSBtdSBkcmF3cwpzaWdtYTIgPC0gbnVtZXJpYyhOc2ltKSAgICAgICMgc3RvcmUgc2lnbWFeMiBkcmF3cwoKIyMgSW5pdGlhbCB2YWx1ZXMKbXVzWzFdIDwtIDgKU1NFMSAgIDwtIChuLTEpKnNeMiArIG4qKHliYXIgLSBtdXNbMV0pXjIKc2lnbWEyWzFdIDwtIDEgLyByZ2FtbWEoMSwgbi8yICsgYWxwaGEsIFNTRTEvMiArIGJldGEpCgojIyBHaWJicyB1cGRhdGVzCmZvciAoayBpbiAyOk5zaW0pIHsKICAKICAjIyMgMS4gU2FtcGxlIG11IHwgc2lnbWFeMiwgeQogIHZhcl9tdSAgPC0gMSAvIChuIC8gc2lnbWEyW2stMV0gKyAxIC8gc2lnbWEwLjIpCiAgbWVhbl9tdSA8LSB2YXJfbXUgKiAobip5YmFyIC8gc2lnbWEyW2stMV0gKyBtdTAgLyBzaWdtYTAuMikKICBtdXNba10gPC0gcm5vcm0oMSwgbWVhbl9tdSwgc3FydCh2YXJfbXUpKQogIAogICMjIyAyLiBTYW1wbGUgc2lnbWFeMiB8IG11LCB5CiAgU1NFIDwtIChuLTEpKnNeMiArIG4qKHliYXIgLSBtdXNba10pXjIKICBzaWdtYTJba10gPC0gMSAvIHJnYW1tYSgxLCBuLzIgKyBhbHBoYSwgU1NFLzIgKyBiZXRhKQp9CgoKIyAgUG9zdGVyaW9yIHN1bW1hcmllcwpjYXQoIlBvc3RlcmlvciBtZWFuKG11KToiLCBtZWFuKG11cyksICJcbiIpCmNhdCgiUG9zdGVyaW9yIHNkKG11KToiLCAgIHNkKG11cyksICJcbiIpCmNhdCgiOTUlIENJIGZvciBtdTpcbiIpOyBwcmludChxdWFudGlsZShtdXMsIGMoMC4wMjUsIDAuOTc1KSkpCmNhdCgiXG5Qb3N0ZXJpb3IgbWVhbihzaWdtYV4yKToiLCBtZWFuKHNpZ21hMiksICJcbiIpCmNhdCgiOTUlIENJIGZvciBzaWdtYV4yOlxuIik7IHByaW50KHF1YW50aWxlKHNpZ21hMiwgYygwLjAyNSwgMC45NzUpKSkKCgojICBWaXN1YWxpemUgZmlyc3QgZmV3IEdpYmJzIHN0ZXBzCm1heGl0IDwtIDIwCnBsb3QobXVzWzE6bWF4aXRdLCBzaWdtYTJbMTptYXhpdF0sIHR5cGUgPSAibiIsCiAgICAgeGxhYiA9IGV4cHJlc3Npb24obXUpLCB5bGFiID0gZXhwcmVzc2lvbihzaWdtYV4yKSwKICAgICBtYWluID0gIkZpcnN0IDIwIEdpYmJzIEl0ZXJhdGlvbnMiKQphcnJvd3MobXVzWzE6KG1heGl0LTEpXSwgc2lnbWEyWzE6KG1heGl0LTEpXSwKICAgICAgIG11c1syOm1heGl0XSwgc2lnbWEyWzI6bWF4aXRdLAogICAgICAgbGVuZ3RoID0gMC4xLCBhbmdsZSA9IDMwLCBjb2wgPSByYWluYm93KG1heGl0LTEpKQpwb2ludHMobXVzWzE6bWF4aXRdLCBzaWdtYTJbMTptYXhpdF0sIHBjaCA9IDIwKQoKIyAgVHJhY2UgcGxvdHMKdHJhY2VfbXUgPC0gZ2dwbG90KGRhdGEuZnJhbWUoaXRlciA9IDE6TnNpbSwgbXUgPSBtdXMpLAogICAgICAgICAgICAgICAgICAgYWVzKGl0ZXIsIG11KSkgKwogIGdlb21fbGluZShjb2xvciA9ICJzdGVlbGJsdWUiKSArCiAgbGFicyh0aXRsZSA9ICJUcmFjZSBQbG90IGZvciDOvCIsCiAgICAgICB4ID0gIkl0ZXJhdGlvbiIsIHkgPSBleHByZXNzaW9uKG11KSkgKwogIHRoZW1lX2J3KDE0KQp0cmFjZV9zaWdtYTIgPC0gZ2dwbG90KGRhdGEuZnJhbWUoaXRlciA9IDE6TnNpbSwgc2lnbWEyID0gc2lnbWEyKSwKICAgICAgICAgICAgICAgICAgICAgICBhZXMoaXRlciwgc2lnbWEyKSkgKwogIGdlb21fbGluZShjb2xvciA9ICJmaXJlYnJpY2siKSArCiAgbGFicyh0aXRsZSA9IGV4cHJlc3Npb24oIlRyYWNlIFBsb3QgZm9yICIgKiBzaWdtYV4yKSwKICAgICAgIHggPSAiSXRlcmF0aW9uIiwgeSA9IGV4cHJlc3Npb24oc2lnbWFeMikpICsKICB0aGVtZV9idygxNCkKCiMgIFBvc3RlcmlvciBkZW5zaXR5IHBsb3RzCmRlbnNfbXUgPC0gZ2dwbG90KGRhdGEuZnJhbWUobXUgPSBtdXMpLCBhZXMobXUpKSArCiAgZ2VvbV9kZW5zaXR5KGZpbGwgPSAic3RlZWxibHVlIiwgYWxwaGEgPSAwLjQpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBtZWFuKG11cyksIGNvbG9yID0gImJsdWUiLCBsaW5ldHlwZSA9IDIpICsKICBsYWJzKHRpdGxlID0gIlBvc3RlcmlvciBEZW5zaXR5IG9mIM68IiwKICAgICAgIHggPSBleHByZXNzaW9uKG11KSwgeSA9ICJEZW5zaXR5IikgKwogIHRoZW1lX2J3KDE0KQpkZW5zX3NpZ21hMiA8LSBnZ3Bsb3QoZGF0YS5mcmFtZShzaWdtYTIgPSBzaWdtYTIpLCBhZXMoc2lnbWEyKSkgKwogIGdlb21fZGVuc2l0eShmaWxsID0gImZpcmVicmljayIsIGFscGhhID0gMC40KSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbWVhbihzaWdtYTIpLCBjb2xvciA9ICJyZWQiLCBsaW5ldHlwZSA9IDIpICsKICBsYWJzKHRpdGxlID0gIlBvc3RlcmlvciBEZW5zaXR5IG9mIM+DwrIiLAogICAgICAgeCA9IGV4cHJlc3Npb24oc2lnbWFeMiksIHkgPSAiRGVuc2l0eSIpICsKICB0aGVtZV9idygxNCkKCiMgIEpvaW50IHBvc3RlcmlvciAozrwsIM+DwrIpCmRmX3Bvc3QgPC0gZGF0YS5mcmFtZShtdSA9IG11cywgc2lnbWEyID0gc2lnbWEyKQpqb2ludF9jb250b3VyIDwtIGdncGxvdChkZl9wb3N0LCBhZXMobXUsIHNpZ21hMikpICsKICBzdGF0X2RlbnNpdHlfMmQoYWVzKGZpbGwgPSAuLmxldmVsLi4pLCBnZW9tID0gInBvbHlnb24iLCBhbHBoYSA9IDAuNikgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKCkgKwogIGxhYnModGl0bGUgPSAiUG9zdGVyaW9yIEpvaW50IERlbnNpdHkgb2YgKM68LCDPg8KyKSIsCiAgICAgICB4ID0gZXhwcmVzc2lvbihtdSksIHkgPSBleHByZXNzaW9uKHNpZ21hXjIpKSArCiAgdGhlbWVfYncoMTQpCmpvaW50X2hlYXRtYXAgPC0gZ2dwbG90KGRmX3Bvc3QsIGFlcyhtdSwgc2lnbWEyKSkgKwogIHN0YXRfZGVuc2l0eV8yZF9maWxsZWQoY29udG91cl92YXIgPSAiZGVuc2l0eSIpICsKICBsYWJzKHRpdGxlID0gIlBvc3RlcmlvciBKb2ludCBEZW5zaXR5IEhlYXRtYXAiLAogICAgICAgeCA9IGV4cHJlc3Npb24obXUpLCB5ID0gZXhwcmVzc2lvbihzaWdtYV4yKSkgKwogIHRoZW1lX2J3KDE0KQoKCiMgIFBsb3QgY29tYmluZWQgcGFuZWxzCiggdHJhY2VfbXUgfCB0cmFjZV9zaWdtYTIgKSAvICggZGVuc19tdSB8IGRlbnNfc2lnbWEyICkKam9pbnRfY29udG91cgpqb2ludF9oZWF0bWFwCmBgYAoKCgojICBNSCBTYW1wbGVyIApgYGB7cn0Kc2V0LnNlZWQoNDMxKQojIyBMb2ctcG9zdGVyaW9yIGZvciAobXUsIGxvZ19zaWdtYTIpCmxvZ19wb3N0IDwtIGZ1bmN0aW9uKG11LCBsb2dfc2lnbWEyKSB7CiAgc2lnbWEyIDwtIGV4cChsb2dfc2lnbWEyKQogIAogICMgU1NFKG11KSB1c2luZyBzdWZmaWNpZW50IHN0YXRzCiAgU1NFIDwtIChuIC0gMSkqc14yICsgbiooeWJhciAtIG11KV4yCiAgCiAgIyBsb2ctbGlrZWxpaG9vZDogTihtdSwgc2lnbWEyKSBmb3IgbiBvYnNlcnZhdGlvbnMKICBscF95IDwtIC0obi8yKSAqIGxvZygyKnBpKnNpZ21hMikgLSBTU0UvKDIqc2lnbWEyKQogIAogICMgcHJpb3IgZm9yIG11IH4gTihtdTAsIHNpZ21hMF4yKQogIGxwX211IDwtIGRub3JtKG11LCBtZWFuID0gbXUwLCBzZCA9IHNxcnQoc2lnbWEwLjIpLCBsb2cgPSBUUlVFKQogIAogICMgcHJpb3IgZm9yIHNpZ21hMiB+IElHKGFscGhhLCBiZXRhKSwgdXAgdG8gY29uc3RhbnRzOgogICMgcChzaWdtYTIpIOKInSAoc2lnbWEyKV4tKGFscGhhKzEpIGV4cCgtYmV0YS9zaWdtYTIpCiAgbHBfczIgPC0gLShhbHBoYSArIDEpKmxvZyhzaWdtYTIpIC0gYmV0YS9zaWdtYTIKICAKICAjIEphY29iaWFuIGZvciB0cmFuc2Zvcm0gc2lnbWEyID0gZXhwKGxvZ19zaWdtYTIpCiAgbHBfamFjIDwtIGxvZ19zaWdtYTIKICByZXR1cm4obHBfeSArIGxwX211ICsgbHBfczIgKyBscF9qYWMpCn0gCiAgCiAgCm1oX3NhbXBsZXIgPC0gZnVuY3Rpb24oTnNpbSwgc3RhcnRfbXUsIHN0YXJ0X2xvZ19zMiwKICAgICAgICAgICAgICAgICAgICAgICBwcm9wX3NkX211LCBwcm9wX3NkX2xvZ19zMikgewogIG11ICAgICA8LSBudW1lcmljKE5zaW0pCiAgbG9nX3MyIDwtIG51bWVyaWMoTnNpbSkKICBtdVsxXSAgICAgPC0gc3RhcnRfbXUKICBsb2dfczJbMV0gPC0gc3RhcnRfbG9nX3MyCiAgYWNjIDwtIDAKICAKICBmb3IgKGsgaW4gMjpOc2ltKSB7CiAgICAjIFByb3Bvc2UgbmV3IChtdSwgbG9nX3NpZ21hMikgd2l0aCBHYXVzc2lhbiByYW5kb20gd2FsawogICAgbXVfcHJvcCAgICAgPC0gcm5vcm0oMSwgbWVhbiA9IG11W2stMV0sICAgICBzZCA9IHByb3Bfc2RfbXUpCiAgICBsb2dfczJfcHJvcCA8LSBybm9ybSgxLCBtZWFuID0gbG9nX3MyW2stMV0sIHNkID0gcHJvcF9zZF9sb2dfczIpCiAgICAKICAgICMgTG9nIGFjY2VwdGFuY2UgcmF0aW8gKHN5bW1ldHJpYyBwcm9wb3NhbCDih5IgcSBjYW5jZWxzKQogICAgbG9nX2FscGhhIDwtIGxvZ19wb3N0KG11X3Byb3AsIGxvZ19zMl9wcm9wKSAtCiAgICAgICAgICAgICAgICAgbG9nX3Bvc3QobXVbay0xXSwgbG9nX3MyW2stMV0pCiAgICAKICAgIGlmIChsb2cocnVuaWYoMSkpIDwgbG9nX2FscGhhKSB7CiAgICAgICMgYWNjZXB0CiAgICAgIG11W2tdICAgICA8LSBtdV9wcm9wCiAgICAgIGxvZ19zMltrXSA8LSBsb2dfczJfcHJvcAogICAgICBhY2MgPC0gYWNjICsgMQogICAgfSBlbHNlIHsKICAgICAgIyByZWplY3QgKHN0YXkgYXQgcHJldmlvdXMpCiAgICAgIG11W2tdICAgICA8LSBtdVtrLTFdCiAgICAgIGxvZ19zMltrXSA8LSBsb2dfczJbay0xXQogICAgfQogIH0KICAKICBsaXN0KG11ID0gbXUsCiAgICAgICBzaWdtYTIgPSBleHAobG9nX3MyKSwKICAgICAgIGFjY19yYXRlID0gYWNjIC8gKE5zaW0gLSAxKSkKfQoKIyBVc2UgR2liYnMgaW5pdGlhbCBzaWdtYTJbMV0gYXMgc3RhcnRpbmcgcG9pbnQgZm9yIE1ICm1oX291dCA8LSBtaF9zYW1wbGVyKAogIE5zaW0gICAgICAgICAgPSBOc2ltLAogIHN0YXJ0X211ICAgICAgPSBtdXNbMV0sCiAgc3RhcnRfbG9nX3MyICA9IGxvZyhzaWdtYTJbMV0pLAogIHByb3Bfc2RfbXUgICAgPSAwLjAwNSwgICAjIHR1bmUgdGhlc2UKICBwcm9wX3NkX2xvZ19zMiA9IDAuMDUKKQoKbWhfb3V0JGFjY19yYXRlICAgIyBjaGVjayBhY2NlcHRhbmNlIHJhdGU7IGFpbSB+IDAuMuKAkzAuNQpgYGAKCgoKIyBDb21wYXJzaW9uIFBsb3RzCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocGF0Y2h3b3JrKQoKZGZfY29tcCA8LSBkYXRhLmZyYW1lKAogIGl0ZXIgICAgICAgICAgPSAxOk5zaW0sCiAgZ2liYnNfbXUgICAgICA9IG11cywKICBtaF9tdSAgICAgICAgID0gbWhfb3V0JG11LAogIGdpYmJzX3NpZ21hMiAgPSBzaWdtYTIsCiAgbWhfc2lnbWEyICAgICA9IG1oX291dCRzaWdtYTIKKQoKIyBUcmFjZSBQbG90CnRyYWNlX211X2JvdGggPC0gZ2dwbG90KGRmX2NvbXApICsKICBnZW9tX2xpbmUoYWVzKGl0ZXIsIGdpYmJzX211LCBjb2xvdXIgPSAiR2liYnMiKSkgKwogIGdlb21fbGluZShhZXMoaXRlciwgbWhfbXUsICAgIGNvbG91ciA9ICJNSCIpLCBhbHBoYSA9IDAuNykgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiR2liYnMiID0gInN0ZWVsYmx1ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNSCIgICAgPSAib3JhbmdlIikpICsKICBsYWJzKHRpdGxlID0gIlRyYWNlIFBsb3QgZm9yIM68OiBHaWJicyB2cyBNSCIsCiAgICAgICB4ID0gIkl0ZXJhdGlvbiIsIHkgPSBleHByZXNzaW9uKG11KSwgY29sb3VyID0gIiIpICsKICB0aGVtZV9idygxNCkKdHJhY2VfczJfYm90aCA8LSBnZ3Bsb3QoZGZfY29tcCkgKwogIGdlb21fbGluZShhZXMoaXRlciwgZ2liYnNfc2lnbWEyLCBjb2xvdXIgPSAiR2liYnMiKSkgKwogIGdlb21fbGluZShhZXMoaXRlciwgbWhfc2lnbWEyLCAgICBjb2xvdXIgPSAiTUgiKSwgYWxwaGEgPSAwLjcpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIkdpYmJzIiA9ICJmaXJlYnJpY2siLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTUgiICAgID0gImRhcmtncmVlbiIpKSArCiAgbGFicyh0aXRsZSA9IGV4cHJlc3Npb24oIlRyYWNlIFBsb3QgZm9yICIgKiBzaWdtYV4yICogIjogR2liYnMgdnMgTUgiKSwKICAgICAgIHggPSAiSXRlcmF0aW9uIiwgeSA9IGV4cHJlc3Npb24oc2lnbWFeMiksIGNvbG91ciA9ICIiKSArCiAgdGhlbWVfYncoMTQpCnRyYWNlX211X2JvdGggLyB0cmFjZV9zMl9ib3RoCgoKIyBEZW5zaXR5IGNvbXBhcmlzb24KZGVuc19tdV9ib3RoIDwtIGdncGxvdChkZl9jb21wKSArCiAgZ2VvbV9kZW5zaXR5KGFlcyhnaWJic19tdSwgY29sb3VyID0gIkdpYmJzIiksIGFkanVzdCA9IDEuMikgKwogIGdlb21fZGVuc2l0eShhZXMobWhfbXUsICAgIGNvbG91ciA9ICJNSCIpLCAgICBhZGp1c3QgPSAxLjIsIGxpbmV0eXBlID0gMikgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiR2liYnMiID0gInN0ZWVsYmx1ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNSCIgICAgPSAib3JhbmdlIikpICsKICBsYWJzKHRpdGxlID0gIlBvc3RlcmlvciBvZiDOvDogR2liYnMgdnMgTUgiLAogICAgICAgeCA9IGV4cHJlc3Npb24obXUpLCB5ID0gIkRlbnNpdHkiLCBjb2xvdXIgPSAiIikgKwogIHRoZW1lX2J3KDE0KQpkZW5zX3MyX2JvdGggPC0gZ2dwbG90KGRmX2NvbXApICsKICBnZW9tX2RlbnNpdHkoYWVzKGdpYmJzX3NpZ21hMiwgY29sb3VyID0gIkdpYmJzIiksIGFkanVzdCA9IDEuMikgKwogIGdlb21fZGVuc2l0eShhZXMobWhfc2lnbWEyLCAgICBjb2xvdXIgPSAiTUgiKSwgICAgYWRqdXN0ID0gMS4yLCBsaW5ldHlwZSA9IDIpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIkdpYmJzIiA9ICJmaXJlYnJpY2siLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTUgiICAgID0gImRhcmtncmVlbiIpKSArCiAgbGFicyh0aXRsZSA9IGV4cHJlc3Npb24oIlBvc3RlcmlvciBvZiAiICogc2lnbWFeMiAqICI6IEdpYmJzIHZzIE1IIiksCiAgICAgICB4ID0gZXhwcmVzc2lvbihzaWdtYV4yKSwgeSA9ICJEZW5zaXR5IiwgY29sb3VyID0gIiIpICsKICB0aGVtZV9idygxNCkKZGVuc19tdV9ib3RoIHwgZGVuc19zMl9ib3RoCgoKCiMgLS0tIEdpYmJzIGhlYXRtYXAgCm1oX211X3EgIDwtIHF1YW50aWxlKGRmX2NvbXAkbWhfbXUsICAgICBwcm9icyA9IGMoMC4wMDUsIDAuOTk1KSkKbWhfczJfcSAgPC0gcXVhbnRpbGUoZGZfY29tcCRtaF9zaWdtYTIsIHByb2JzID0gYygwLjAwNSwgMC45OTUpKQp6b29tX3ggPC0gYyhtaF9tdV9xWzFdLCBtaF9tdV9xWzJdKQp6b29tX3kgPC0gYyhtaF9zMl9xWzFdLCBtaF9zMl9xWzJdKQpoZWF0X2dpYmJzX3pvb20gPC0gZ2dwbG90KGRmX2NvbXAsIGFlcyhnaWJic19tdSwgZ2liYnNfc2lnbWEyKSkgKwogIHN0YXRfZGVuc2l0eV8yZF9maWxsZWQoY29udG91cl92YXIgPSAiZGVuc2l0eSIsIGFscGhhID0gMC45KSArCiAgc3RhdF9kZW5zaXR5XzJkKGNvbG9yID0gIndoaXRlIiwgbGluZXdpZHRoID0gMC40KSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2Qob3B0aW9uID0gIkMiKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSB6b29tX3gsIHlsaW0gPSB6b29tX3ksIGV4cGFuZCA9IEZBTFNFKSArCiAgbGFicygKICAgIHRpdGxlID0gIkpvaW50IFBvc3RlcmlvciBIZWF0bWFwIChHaWJicykiLAogICAgeCA9IGV4cHJlc3Npb24obXUpLAogICAgeSA9IGV4cHJlc3Npb24oc2lnbWFeMiksCiAgICBmaWxsID0gIkRlbnNpdHkgTGV2ZWwiCiAgKSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTYpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiLCBoanVzdCA9IDAuNSksCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCksCiAgICBheGlzLnRleHQgID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwKICAgIGxlZ2VuZC50ZXh0ICA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGxpbmV3aWR0aCA9IDAuOCwgY29sb3IgPSAiYmxhY2siKSwKICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkKICApCmhlYXRfZ2liYnNfem9vbQoKCiMgTUggaGVhdG1hcCAKCmhlYXRfbWhfem9vbSA8LSBnZ3Bsb3QoZGZfY29tcCwgYWVzKG1oX211LCBtaF9zaWdtYTIpKSArCiAgc3RhdF9kZW5zaXR5XzJkX2ZpbGxlZChjb250b3VyX3ZhciA9ICJkZW5zaXR5IiwgYWxwaGEgPSAwLjkpICsKICBzdGF0X2RlbnNpdHlfMmQoY29sb3IgPSAid2hpdGUiLCBsaW5ld2lkdGggPSAwLjQpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfZChvcHRpb24gPSAiQyIpICsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IHpvb21feCwgeWxpbSA9IHpvb21feSwgZXhwYW5kID0gRkFMU0UpICsKICBsYWJzKAogICAgdGl0bGUgPSAiSm9pbnQgUG9zdGVyaW9yIEhlYXRtYXAgKE1IKSIsCiAgICB4ID0gZXhwcmVzc2lvbihtdSksCiAgICB5ID0gZXhwcmVzc2lvbihzaWdtYV4yKSwKICAgIGZpbGwgPSAiRGVuc2l0eSBMZXZlbCIKICApICsKICB0aGVtZV9idyhiYXNlX3NpemUgPSAxNikgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIsIGhqdXN0ID0gMC41KSwKICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSwKICAgIGF4aXMudGV4dCAgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLAogICAgbGVnZW5kLnRleHQgID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QobGluZXdpZHRoID0gMC44LCBjb2xvciA9ICJibGFjayIpLAogICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKQogICkKaGVhdF9taF96b29tCgpgYGAKYGBge3J9CiMgU2V0IGxheW91dDogMSByb3csIDIgY29sdW1ucwpwYXIobWZyb3cgPSBjKDEsIDIpLCBtYXIgPSBjKDUsIDUsIDQsIDIpKQoKIyBQYW5lbCAxOiBQb3N0ZXJpb3Igb2YgzrwKZGVuc19naWJic19tdSA8LSBkZW5zaXR5KGRmX2NvbXAkZ2liYnNfbXUpCmRlbnNfbWhfbXUgICAgPC0gZGVuc2l0eShkZl9jb21wJG1oX211KQoKcGxvdChkZW5zX2dpYmJzX211LAogICAgIG1haW4gPSAiUG9zdGVyaW9yIG9mIM68OiBHaWJicyB2cyBNSCIsCiAgICAgeGxhYiA9IGV4cHJlc3Npb24obXUpLAogICAgIHlsYWIgPSAiRGVuc2l0eSIsCiAgICAgY29sICA9ICJzdGVlbGJsdWUiLAogICAgIGx3ZCAgPSAyLAogICAgIGx0eSAgPSAxLCAgICAgICAgICAjIHNvbGlkCiAgICAgY2V4LmxhYiA9IDEuMywKICAgICBjZXgubWFpbiA9IDEuNCkKCmxpbmVzKGRlbnNfbWhfbXUsCiAgICAgIGNvbCA9ICJvcmFuZ2UiLAogICAgICBsd2QgPSAyLAogICAgICBsdHkgPSAyKSAgICAgICAgICAjIGRhc2hlZAoKbGVnZW5kKCJ0b3ByaWdodCIsCiAgICAgICBsZWdlbmQgPSBjKCJHaWJicyAoc29saWQpIiwgIk1IIChkYXNoZWQpIiksCiAgICAgICBjb2wgPSBjKCJzdGVlbGJsdWUiLCAib3JhbmdlIiksCiAgICAgICBsd2QgPSAyLAogICAgICAgbHR5ID0gYygxLCAyKSwKICAgICAgIGJ0eSA9ICJuIiwKICAgICAgIGNleCA9IDEuMSkKCiMgUGFuZWwgMjogUG9zdGVyaW9yIG9mIM+DwrIKZGVuc19naWJic19zMiA8LSBkZW5zaXR5KGRmX2NvbXAkZ2liYnNfc2lnbWEyKQpkZW5zX21oX3MyICAgIDwtIGRlbnNpdHkoZGZfY29tcCRtaF9zaWdtYTIpCgpwbG90KGRlbnNfZ2liYnNfczIsCiAgICAgbWFpbiA9IGV4cHJlc3Npb24oIlBvc3RlcmlvciBvZiAiICogc2lnbWFeMiAqICI6IEdpYmJzIHZzIE1IIiksCiAgICAgeGxhYiA9IGV4cHJlc3Npb24oc2lnbWFeMiksCiAgICAgeWxhYiA9ICJEZW5zaXR5IiwKICAgICBjb2wgID0gImZpcmVicmljayIsCiAgICAgbHdkICA9IDIsCiAgICAgbHR5ICA9IDEsICAgICAgICAgICMgc29saWQKICAgICBjZXgubGFiID0gMS4zLAogICAgIGNleC5tYWluID0gMS40KQoKbGluZXMoZGVuc19taF9zMiwKICAgICAgY29sID0gImRhcmtncmVlbiIsCiAgICAgIGx3ZCA9IDIsCiAgICAgIGx0eSA9IDIpICAgICAgICAgICMgZGFzaGVkCgpsZWdlbmQoInRvcHJpZ2h0IiwKICAgICAgIGxlZ2VuZCA9IGMoIkdpYmJzIChzb2xpZCkiLCAiTUggKGRhc2hlZCkiKSwKICAgICAgIGNvbCA9IGMoImZpcmVicmljayIsICJkYXJrZ3JlZW4iKSwKICAgICAgIGx3ZCA9IDIsCiAgICAgICBsdHkgPSBjKDEsIDIpLAogICAgICAgYnR5ID0gIm4iLAogICAgICAgY2V4ID0gMS4xKQoKIyBSZXN0b3JlIGRlZmF1bHQgbGF5b3V0CnBhcihtZnJvdyA9IGMoMSwgMSkpCgpgYGAKCgoKCgoKCg==