library(HistogramTools)
library(MASS)
Question 1, Stability
Simulate 10 realisations with 200 observations from the process and plot in the same plot.
lists_ts_ar2ma1 <- vector("list", 10)
set.seed(1)
for (i in seq(10)){
lists_ts_ar2ma1[[i]] <- arima.sim(model = list(order = c(2, 0, 1), ar = c(0.8, 0.1), ma = 0.8), n = 200)
}
par(mfrow = c(10, 1), mar = c(0.5, 0.5, 0.5, 0.5), oma = c(2, 2, 2, 2))
for (i in seq(10)){
plot.ts(lists_ts_ar2ma1[[i]], xaxt = "n", xlab = NULL, ylab = NULL, frame.plot = TRUE)
}
title(main = "10 Realizations from the ARIMA(2,0,1) Process", cex.main = 2, outer = TRUE)
axis(1, at = seq(0, 200, by = 10), las = 0, outer = TRUE)

vec_acf <- c(0.5896, 0.5596, 0.5066, rep(0, 18))
for (i in seq(4, 21)){
vec_acf[i] <- 0.8 * vec_acf[i-1] + 0.1 * vec_acf[i-2]
}
vec_acf <- vec_acf / vec_acf[1]
par(mfrow = c(10, 1), mar = c(0.5, 0.5, 0.5, 0.5), oma = c(2, 2, 2, 2))
for (i in seq(10)){
acf(lists_ts_ar2ma1[[i]], lag.max = 20, xaxt = "n", xlab = NULL, ylab = NULL, frame.plot = TRUE)
lines(seq(0, 20), vec_acf, type = "l", col = "red", lty = 2, lwd = 2)
if (i == 1){
legend("topright", inset = .02, legend = c("Estimated ACF", "5% significance limits", "Calculated ACF"),
col = c("black", "blue", "red", "red", "red"), lty = c(1, 2, 2), lwd = c(1, 1, 2))
}
}
title(main = "ACF of 10 Realizations from the ARIMA(2,0,1) Process", cex.main = 2, outer = TRUE)
axis(1, at = seq(0, 20), las = 0, outer = TRUE)

mat_acf <- matrix(nrow = 10, ncol = 41)
There were 25 warnings (use warnings() to see them)
for (i in seq(10)){
mat_acf[i,] <- acf(lists_ts_ar2ma1[[i]], lag.max = 40, plot = F)$acf[,1,1]
}
# Manual Calculation of AC
vec_acf <- c(0.5896, 0.5596, 0.5066, rep(0, 38))
for (i in seq(4, 41)){
vec_acf[i] <- 0.8 * vec_acf[i-1] + 0.1 * vec_acf[i-2]
}
vec_acf <- vec_acf / vec_acf[1]
# Functional Calculation of AC
vec_acf_2 <- ARMAacf(c(0.8, 0.1), 0.8, lag.max = 40, pacf = FALSE)
# Plot different ACFs
plot(seq(0, 40), vec_acf, ylim = c(min(mat_acf), 1),
type = "l", col = "red", lty = 2, lwd = 3, xlab = "lags", ylab = "autocovariance function",
main = "Estimated ACF from Realizations and Manual Calculated ACF of ARIMA(2,0,1)")
lines(seq(0, 40), rep(0.05, 41), type = "l", col = "blue", lty = 2, lwd = 1)
lines(seq(0, 40), rep(0.05, 41), type = "l", col = "blue", lty = 2, lwd = 1)
lines(seq(0, 40), rep(-0.05, 41), type = "l", col = "blue", lty = 2, lwd = 1)
legend("topright", inset = .02, legend = c("Estimated ACF", "5% significance limits", "Manual Calculated ACF"),
col = c("black", "blue", "red"), lty = c(1, 2, 2), lwd = c(1, 1, 3))
for (i in seq(10)){
lines(seq(0, 40), mat_acf[i,], type = "l", col = "black", lty = 1, lwd = 1)
}

par(mfrow = c(10, 1), mar = c(0.5, 0.5, 0.5, 0.5), oma = c(2, 2, 2, 2))
for (i in seq(10)){
pacf(lists_ts_ar2ma1[[i]], lag.max = 20, xaxt = "n", xlab = NULL, ylab = NULL, frame.plot = TRUE)
}
title(main = "PACF of 10 Realizations from the ARIMA(2,0,1) Process", cex.main = 2, outer = TRUE)
axis(1, at = seq(0, 20), las = 0, outer = TRUE)

mat_pacf <- matrix(nrow = 10, ncol = 20)
for (i in seq(10)){
mat_pacf[i,] <- pacf(lists_ts_ar2ma1[[i]], lag.max = 20, plot = F)$acf[,1,1]
}
# Functional Calculation of PACF
vec_pacf <- ARMAacf(c(0.8, 0.1), 0.8, lag.max = 20, pacf = TRUE)
# Plot different PACFs
plot(seq(1, 20), vec_pacf, ylim = c(min(mat_pacf), 1),
type = "l", col = "red", lty = 2, lwd = 3, xaxt = "n", bty = "n", xlab = "lags", ylab = "autocovariance function",
main = "Estimated PACF from Realizations and Function-Calculated PACF of ARIMA(2,0,1)")
lines(seq(1, 20), rep(0.05, 20), type = "l", col = "blue", lty = 2, lwd = 1)
lines(seq(1, 20), rep(-0.05, 20), type = "l", col = "blue", lty = 2, lwd = 1)
legend("topright", inset = .02, legend = c("Estimated PACF", "5% significance limits", "Fun-Calculated PACF"),
col = c("black", "blue", "red"), lty = c(1, 2, 2), lwd = c(1, 1, 3))
for (i in seq(10)){
lines(seq(1, 20), mat_pacf[i,], type = "l", col = "black", lty = 1, lwd = 1)
}
axis(1, at = seq(1, 20, by = 1), las = 0, outer = FALSE)

Question 2, Predicting the Carbon-Dioxide Level in an Office
list_co2.log.mean <- c(6.153, 6.308, 6.327, 6.344, 6.266, 6.121, 6.096, 6.081,
6.178, 6.411, 6.442, 6.505, 6.195, 6.085, 6.086, 6.079)
list_co2.log <- list_co2.log.mean - 6.24
pred_co2.log_1.hat <- function(t, list_co2.log){
return(0.547 * list_co2.log[t] + 0.86 * list_co2.log[t-7] - 0.47042 * list_co2.log[t-8])
}
pred_co2.log_2.hat <- function(t, list_co2.log){
return(0.299209 * list_co2.log[t] + 0.86 * list_co2.log[t-5] - 0.47042 * list_co2.log[t-6] +
0.47042 * list_co2.log[t-7] - 0.25731974 * list_co2.log[t-8])
}
co2.log_17.hat <- pred_co2.log_1.hat(16, list_co2.log)
co2.log_18.hat <- pred_co2.log_2.hat(16, list_co2.log)
# Prediction Interval
cal_vec_intervalPred <- function(y.hat, var, prob = 0.95){
quantileNormDist <- qnorm(p = 0.95)
boundUp <- y.hat + quantileNormDist * sqrt(var)
boundLow <- y.hat - quantileNormDist * sqrt(var)
return(list(boundUp = drop(boundUp), boundLow = drop(boundLow)))
}
vec_intervalPred_17.hat.mean <- cal_vec_intervalPred(y.hat = co2.log_17.hat + 6.24, var = 4.225e-3)
vec_intervalPred_18.hat.mean <- cal_vec_intervalPred(y.hat = co2.log_18.hat + 6.24, var = 6.536075E-3)
Plot the result
plot(seq(1, 16), list_co2.log.mean,
type = "b", col = "blue", lwd = 1, lty = 1, xaxt = "n", bty = "n", xlim = c(0, 19), ylim = c(6.0, 6.6),
main = paste("Two-Step Prediction of Carbon-Dioxide Level in an Office by ARIMA(1,8,0) Model"),
xlab = "Series", ylab = "Degree")
points(c(17, 18), c(co2.log_17.hat + 6.24, co2.log_18.hat + 6.24),
type = "b", col = "blue", lty = 1, pch = 16) # Predicted values
lines(c(16, 17), c(list_co2.log.mean[16], co2.log_17.hat + 6.24),
type = "c", col = "blue", lty = 1) # Connect observations with one step prediction
legend("topleft", inset = .02, legend = c("Observations", "Prediction", "Pred Interval"),
col = c("blue", "blue", "red"), pch = c(1, 16, 15),
lty = c(1, 1, 3), lwd = c(1, 1, 3))
# Plot the prediction result
points(c(17, 17), vec_intervalPred_17.hat.mean,
type = "b", col = "red", pch = 15, lty = 3, lwd = 2)
points(c(18, 18), vec_intervalPred_18.hat.mean,
type = "b", col = "red", pch = 15, lty = 3, lwd = 2)
axis(1, at = seq(1, 18, by = 1), las = 0, outer = FALSE)

Question 3, Simulating Seasonal Processes
Define the function to plot the residuals for analysis.
# Plot the time series / residuals and its ACF and PACF. No Ljung-Box plot
plotTimeSeriesResidual <- function(dat, num_lag = 50, list_para, ...){
# If the input dat is arima model, just take its residuals are the dat.
if(class(dat) == "Arima")
dat <- dat$residuals
par(mfrow = c(3, 1), mgp = c(2, 0.7, 0), mar = c(1, 1, 1, 1), oma = c(2, 2, 4, 2),
cex.lab = 0.8, cex.axis = 0.8)
plot(dat)
title(main = paste("TS, ACF, PACF when phi_1(", list_para[1], "), phi_2(", list_para[2],
"), phi.cap(", list_para[3], ") theta(", list_para[4], ") and theta.cap(", list_para[5],
")"), cex.main = 1.5, line = 1, outer = TRUE)
acf(dat, lag.max = 20, xaxt = "n")
axis(1, at = seq(0, 20, by = 1), las = 0, outer = FALSE)
pacf(dat, lag.max = 20, xaxt = "n")
axis(1, at = seq(1, 20, by = 1), las = 0, outer = FALSE)
# Ljung-Box Plot
# value_p <- sapply(1:num_lag, function(i) Box.test(dat, i, type = "Ljung-Box")$p.value)
# plot(1L: num_lag, value_p, main = "p Values for Ljung-Box Statistic",
# xlab = "lag", ylab = "p value", ylim = c(0,1))
# abline(h = 0.05, lty = 2, col = "blue")
}
jud_stationary_arima <- function(vec_phi){
# Different definitions of ARMA models have different signs for the AR and/or MA coefficients.
# How to decide the sign of phi is that phi and past observations are in left-hand-side
# Edward J. Xu, 190402
vec_phi <- c(1, vec_phi)
vec.rev_phi <- rev(vec_phi)
vec_root <- polyroot(vec.rev_phi)
vec_root.abs <- abs(vec_root)
vec_root.abs.unit <- abs(vec_root) <= rep(1, length(vec_root))
return(all(vec_root.abs.unit))
}
There were 24 warnings (use warnings() to see them)
list_phi_1 <- c(0.8, 0, -0.7, -0.8, 0.6, 0)
list_phi_2 <- c(0, 0, 0, 0, 0.5, 0)
list_phi.cap_1 <- c(0, - 0.85, 0, 0.7, 0.9, 0)
list_theta_1 <- c(0, 0, 0, 0, 0, - 0.9)
list_theta.cap_1 <- c(0, 0, 0.8, 0, 0, - 0.7)
mat_phi <- matrix(0, nrow = 6, ncol = 14)
mat_theta <- matrix(0, nrow = 6, ncol = 13)
list_stationary <- logical(length = 6)
for (i in seq(6)){
phi_1 <- list_phi_1[i]
phi_2 <- list_phi_2[i]
phi.cap_1 <- list_phi.cap_1[i]
theta_1 <- list_theta_1[i]
theta.cap_1 <- list_theta.cap_1[i]
mat_phi[i,] <- c(phi_1, phi_2, rep(0, 9), phi.cap_1, phi_1 * phi.cap_1, phi_2 * phi.cap_1)
mat_theta[i,] <- c(theta_1, rep(0, 10), theta.cap_1, theta_1 * theta.cap_1)
list_stationary[i] <- jud_stationary_arima(mat_phi[i,])
}
list_ts_ar13ma13 <- vector("list", 6)
set.seed(99)
for(i in seq(6)){
if(list_stationary[i]){
list_para <- rep(0, 5)
list_para[1] <- list_phi_1[i]
list_para[2] <- list_phi_2[i]
list_para[3] <- list_phi.cap_1[i]
list_para[4] <- list_theta_1[i]
list_para[5] <- list_theta.cap_1[i]
list_ts_ar13ma13[[i]] <- arima.sim(model = list(ar = - mat_phi[i,], ma = mat_theta[i,]), n = 200)
plotTimeSeriesResidual(list_ts_ar13ma13[[i]], list_para = list_para)
}
}






Simulate and Estimation
sim_ar1ma1 <- function(phi, theta, sigma, numtime_Sim){
# Different definitions of ARMA models have different signs for the AR and/or MA coefficients.
set.seed(99)
lists_ts_ar1ma1 <- vector("list", 100)
lists_mod_ar1ma1 <- vector("list", 100)
vec_phi.est <- rep(0, 100)
vec_theta.est <- rep(0, 100)
# j <- 1
# vec_series_seed <- rep(0, 100)
for (i in seq(100)){
# print(paste("i: ", i, "j:", j))
# while(any(class(out <- tryCatch(arima(lists_ts_ar1ma1[[i]] <- arima.sim(model = list(ar = - phi_1,
# ma = theta_1), sd = sigma, n = numtime_Sim), order = c(1, 0, 1), include.mean = FALSE),
# error = function(e) e)) == "error")){
# j <- j + 1
# set.seed(j)
# }
lists_ts_ar1ma1[[i]] <- arima.sim(model = list(ar = - phi, ma = theta), sd = sigma, n = numtime_Sim)
lists_mod_ar1ma1[[i]] <- arima(lists_ts_ar1ma1[[i]], order = c(1, 0, 1), method = "ML",
include.mean = FALSE)
vec_phi.est[i] <- lists_mod_ar1ma1[[i]]$coef[1]
vec_theta.est[i] <- lists_mod_ar1ma1[[i]]$coef[2]
# vec_series_seed[i] <- j
}
quan95 <- ApproxQuantile(hist(vec_phi.est, breaks = 50, plot = FALSE), 0.95)
list_result <- list(quan95 = quan95, vec_phi.est = vec_phi.est, vec_theta.est = vec_theta.est)
return(list_result)
}
histPhi_sim_ar1ma1 <- function(vec_phi.est, phi, theta, sigma, numtime_Sim){
den_phi.est <- density(vec_phi.est, adjust = 0.2)
hist_phi.est <- hist(vec_phi.est, breaks = 50, plot = FALSE)
hist(vec_phi.est, breaks = 50, freq = FALSE, ylim = c(0, max(hist_phi.est$density, den_phi.est$y)),
xlab = "phi_1", main = NULL) # cex.lab = 0.8, cex.axis = 0.8
lines(den_phi.est, col = "blue", lwd = 2)
title(main = paste("Hist of phi when times(",numtime_Sim,"), phi(",
phi, "), theta(", theta, ") and sd(", sigma, ")")) # cex.main = 0.8
}
histPhi.2_sim_ar1ma1 <- function(vec_phi.est_1, phi_1, theta_1, sigma_1, numtime_Sim_1,
vec_phi.est_2, phi_2, theta_2, sigma_2, numtime_Sim_2){
par(mfrow = c(1, 2), mar = c(0.5, 1.5, 0.5, 0.5), oma = rep(2, 4),
cex.lab = 0.8, cex.axis = 0.8, cex.main = 0.8)
histPhi_sim_ar1ma1(vec_phi.est_1, phi_1, theta_1, sigma_1, numtime_Sim_1)
histPhi_sim_ar1ma1(vec_phi.est_2, phi_2, theta_2, sigma_2, numtime_Sim_2)
}
histPhi.4_sim_ar1ma1 <- function(mat_phi.est, vec_phi, vec_theta, vec_sigma, vec_numtime_Sim){
par(mfrow = c(2, 2), mar = c(1.5, 1.5, 1.5, 1.5), oma = rep(1, 4),
cex.lab = 0.8, cex.axis = 0.8, cex.main = 0.8)
for (i in seq(1, 4)){
histPhi_sim_ar1ma1(mat_phi.est[i,], vec_phi[i], vec_theta[i], vec_sigma[i], vec_numtime_Sim[i])
}
}
plotContour_sim_ar1ma1 <- function(vec_theta.est, vec_phi.est, phi, theta, sigma, numtime_Sim){
kde_ar1ma1_1 <- kde2d(vec_theta.est, vec_phi.est, n = 20)
contour(kde_ar1ma1_1, xlab = "theta", ylab = "phi", bty = "n", main = NULL)
points(theta, - phi, pch = 4, cex = 2, lwd = 2, col = "red")
title(main = paste("Contour of theta(", theta, ") and phi(", phi, ") when times(", numtime_Sim ,
"), sd(", sigma, ")"))
}
plotContour.2_sim_ar1ma1 <- function(vec_theta.est_1, vec_phi.est_1, phi_1, theta_1, sigma_1, numtime_Sim_1,
vec_theta.est_2, vec_phi.est_2, phi_2, theta_2, sigma_2, numtime_Sim_2){
par(mfrow = c(1, 2), mar = c(0.5, 1.5, 0.5, 0.5), oma = rep(2, 4),
cex.lab = 0.8, cex.axis = 0.8, cex.main = 0.8)
plotContour_sim_ar1ma1(vec_theta.est_1, vec_phi.est_1, phi_1, theta_1, sigma_1, numtime_Sim_1)
plotContour_sim_ar1ma1(vec_theta.est_2, vec_phi.est_2, phi_2, theta_2, sigma_2, numtime_Sim_2)
}
plotContour.4_sim_ar1ma1 <- function(mat_theta.est, mat_phi.est, vec_phi, vec_theta, vec_sigma, vec_numtime_Sim){
par(mfrow = c(2, 2), mar = c(1.5, 1.5, 1.5, 1.5), oma = rep(1, 4),
cex.lab = 0.8, cex.axis = 0.8, cex.main = 0.8)
for (i in seq(1, 4)){
plotContour_sim_ar1ma1(mat_theta.est[i,], mat_phi.est[i,], vec_phi[i],
vec_theta[i], vec_sigma[i], vec_numtime_Sim[i])
}
}
plotQQ_sim_ar1ma1 <- function(vec_phi.est, phi, theta, sigma, numtime_Sim){
qqnorm(vec_phi.est, main = NULL, bty = "n")
qqline(vec_phi.est)
title(main = paste("Norm Q-Q Plot of phi when times(", numtime_Sim ,
"), phi(", phi, "), theta(", theta, ") and sd(", sigma, ")"))
}
plotQQ.2_sim_ar1ma1 <- function(vec_phi.est_1, phi_1, theta_1, sigma_1, numtime_Sim_1,
vec_phi.est_2, phi_2, theta_2, sigma_2, numtime_Sim_2){
par(mfrow = c(1, 2), mar = c(0.5, 1.5, 0.5, 0.5), oma = rep(2, 4),
cex.lab = 0.8, cex.axis = 0.8, cex.main = 0.8)
plotQQ_sim_ar1ma1(vec_phi.est_1, phi_1, theta_1, sigma_1, numtime_Sim_1)
plotQQ_sim_ar1ma1(vec_phi.est_2, phi_2, theta_2, sigma_2, numtime_Sim_2)
}
plotQQ.4_sim_ar1ma1 <- function(mat_phi.est, vec_phi, vec_theta, vec_sigma, vec_numtime_Sim){
par(mfrow = c(2, 2), mar = c(1.5, 1.5, 1.5, 1.5), oma = rep(1, 4),
cex.lab = 0.8, cex.axis = 0.8, cex.main = 0.8)
for (i in seq(1, 4)){
plotQQ.2_sim_ar1ma1(mat_phi.est[i,], vec_phi[i], vec_theta[i], vec_sigma[i], vec_numtime_Sim[i])
}
}
Judge whether the given process are stationary.
jud_stationary_arima(- 0.9)
[1] TRUE
jud_stationary_arima(- 0.995)
[1] TRUE
list_result_1 <- sim_ar1ma1(- 0.9, 0.4, 0.1, 300)
list_result_2 <- sim_ar1ma1(- 0.9, 0.4, 5, 300)
list_result_3 <- sim_ar1ma1(- 0.995, 0.4, 0.1, 300)
list_result_4 <- sim_ar1ma1(- 0.995, 0.4, 5, 300)
mat_phi.est <- matrix(nrow = 4, ncol = 100)
mat_phi.est[1,] <- list_result_1$vec_phi.est
mat_phi.est[2,] <- list_result_2$vec_phi.est
mat_phi.est[3,] <- list_result_3$vec_phi.est
mat_phi.est[4,] <- list_result_4$vec_phi.est
mat_theta.est <- matrix(nrow = 4, ncol = 100)
mat_theta.est[1,] <- list_result_1$vec_theta.est
mat_theta.est[2,] <- list_result_2$vec_theta.est
mat_theta.est[3,] <- list_result_3$vec_theta.est
mat_theta.est[4,] <- list_result_4$vec_theta.est
mat_phi.est <- matrix(nrow = 4, ncol = 100)
mat_phi.est[1,] <- list_result_1$vec_phi.est
mat_phi.est[2,] <- list_result_2$vec_phi.est
mat_phi.est[3,] <- list_result_3$vec_phi.est
mat_phi.est[4,] <- list_result_4$vec_phi.est
histPhi.4_sim_ar1ma1(mat_phi.est, c(- 0.9, - 0.9, - 0.995, - 0.995), rep(0.4, 4), c(0.1, 5, 0.1, 5), rep(300, 4))

plotContour.4_sim_ar1ma1(mat_theta.est, mat_phi.est, c(- 0.9, - 0.9, - 0.995, - 0.995), rep(0.4, 4), c(0.1, 5, 0.1, 5), rep(300, 4))

plotQQ.4_sim_ar1ma1(mat_phi.est, c(- 0.9, - 0.9, - 0.995, - 0.995), rep(0.4, 4), c(0.1, 5, 0.1, 5), rep(300, 4))

| -0.900 |
0.1 |
0.9325 |
| -0.900 |
5.0 |
0.9325 |
| -0.995 |
0.1 |
1.0005 |
| -0.995 |
5.0 |
1.0005 |
The Effect of Number of Simulated Observations
list_result_5 <- sim_ar1ma1(- 0.9, 0.4, 1, 100)
Quantiles computed for histograms with fewer than 100 buckets may be inaccurate. Consider using histograms with more granular buckets.
list_result_6 <- sim_ar1ma1(- 0.9, 0.4, 1, 1000)
Quantiles computed for histograms with fewer than 100 buckets may be inaccurate. Consider using histograms with more granular buckets.
histPhi.2_sim_ar1ma1(list_result_5$vec_phi.est, - 0.9, 0.4, 1, 100,
list_result_6$vec_phi.est, - 0.9, 0.4, 1, 1000)

plotQQ.2_sim_ar1ma1(list_result_5$vec_phi.est, - 0.9, 0.4, 1, 100,
list_result_6$vec_phi.est, - 0.9, 0.4, 1, 1000)

plotContour.2_sim_ar1ma1(list_result_5$vec_theta.est, list_result_5$vec_phi.est, -0.9, 0.4, 1, 300,
list_result_6$vec_theta.est, list_result_6$vec_phi.est, -0.9, 0.4, 1, 1000)

LS0tCnRpdGxlOiAiRFRVMDI0MTcgVFNBOiBBc3NpZ25tZW50IDIsIEFSSU1BIGFuZCBTZWFzb25hbCBNb2RlbCIKb3V0cHV0OiBodG1sX25vdGVib29rCmF1dGhvcjogRWR3YXJkIEouIFh1CmRhdGU6IE1hciAyOXRoLCAyMDE5Ci0tLQoKYGBge3IgZ2xvYmFsX29wdGlvbnMsIHNldCB1cCwgaW5jbHVkZT1GQUxTRX0Kcm0obGlzdD1scygpKSAjVG8gY2xlYXIgbmFtZXNwYWNlCmxpYnJhcnkoa25pdHIpCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gMTIsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFKQpgYGAKCmBgYHtyfQpsaWJyYXJ5KEhpc3RvZ3JhbVRvb2xzKQpsaWJyYXJ5KE1BU1MpCmBgYAoKIyBRdWVzdGlvbiAxLCBTdGFiaWxpdHkKClNpbXVsYXRlIDEwIHJlYWxpc2F0aW9ucyB3aXRoIDIwMCBvYnNlcnZhdGlvbnMgZnJvbSB0aGUgcHJvY2VzcyBhbmQgcGxvdCBpbiB0aGUgc2FtZSBwbG90LgoKYGBge3IsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTJ9Cmxpc3RzX3RzX2FyMm1hMSA8LSB2ZWN0b3IoImxpc3QiLCAxMCkKc2V0LnNlZWQoMSkKZm9yIChpIGluIHNlcSgxMCkpewogICAgbGlzdHNfdHNfYXIybWExW1tpXV0gPC0gYXJpbWEuc2ltKG1vZGVsID0gbGlzdChvcmRlciA9IGMoMiwgMCwgMSksIGFyID0gYygwLjgsIDAuMSksIG1hID0gMC44KSwgbiA9IDIwMCkKfQpwYXIobWZyb3cgPSBjKDEwLCAxKSwgbWFyID0gYygwLjUsIDAuNSwgMC41LCAwLjUpLCBvbWEgPSBjKDIsIDIsIDIsIDIpKQpmb3IgKGkgaW4gc2VxKDEwKSl7CiAgICBwbG90LnRzKGxpc3RzX3RzX2FyMm1hMVtbaV1dLCB4YXh0ID0gIm4iLCB4bGFiID0gTlVMTCwgeWxhYiA9IE5VTEwsIGZyYW1lLnBsb3QgPSBUUlVFKQp9CnRpdGxlKG1haW4gPSAiMTAgUmVhbGl6YXRpb25zIGZyb20gdGhlIEFSSU1BKDIsMCwxKSBQcm9jZXNzIiwgY2V4Lm1haW4gPSAyLCBvdXRlciA9IFRSVUUpCmF4aXMoMSwgYXQgPSBzZXEoMCwgMjAwLCBieSA9IDEwKSwgbGFzID0gMCwgb3V0ZXIgPSBUUlVFKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTIsIGZpZy53aWR0aCA9IDEyfQp2ZWNfYWNmIDwtIGMoMC41ODk2LCAwLjU1OTYsIDAuNTA2NiwgcmVwKDAsIDE4KSkKZm9yIChpIGluIHNlcSg0LCAyMSkpewogICAgdmVjX2FjZltpXSA8LSAwLjggKiB2ZWNfYWNmW2ktMV0gKyAwLjEgKiB2ZWNfYWNmW2ktMl0KfQp2ZWNfYWNmIDwtIHZlY19hY2YgLyB2ZWNfYWNmWzFdCnBhcihtZnJvdyA9IGMoMTAsIDEpLCBtYXIgPSBjKDAuNSwgMC41LCAwLjUsIDAuNSksIG9tYSA9IGMoMiwgMiwgMiwgMikpCmZvciAoaSBpbiBzZXEoMTApKXsKICAgIGFjZihsaXN0c190c19hcjJtYTFbW2ldXSwgbGFnLm1heCA9IDIwLCB4YXh0ID0gIm4iLCB4bGFiID0gTlVMTCwgeWxhYiA9IE5VTEwsIGZyYW1lLnBsb3QgPSBUUlVFKQogICAgbGluZXMoc2VxKDAsIDIwKSwgdmVjX2FjZiwgdHlwZSA9ICJsIiwgY29sID0gInJlZCIsIGx0eSA9IDIsIGx3ZCA9IDIpCiAgICBpZiAoaSA9PSAxKXsKICAgICAgICBsZWdlbmQoInRvcHJpZ2h0IiwgaW5zZXQgPSAuMDIsIGxlZ2VuZCA9IGMoIkVzdGltYXRlZCBBQ0YiLCAiNSUgc2lnbmlmaWNhbmNlIGxpbWl0cyIsICJDYWxjdWxhdGVkIEFDRiIpLCAKICAgICAgICAgICAgY29sID0gYygiYmxhY2siLCAiYmx1ZSIsICJyZWQiLCAicmVkIiwgInJlZCIpLCBsdHkgPSBjKDEsIDIsIDIpLCBsd2QgPSBjKDEsIDEsIDIpKQogICAgfQp9CnRpdGxlKG1haW4gPSAiQUNGIG9mIDEwIFJlYWxpemF0aW9ucyBmcm9tIHRoZSBBUklNQSgyLDAsMSkgUHJvY2VzcyIsIGNleC5tYWluID0gMiwgb3V0ZXIgPSBUUlVFKQpheGlzKDEsIGF0ID0gc2VxKDAsIDIwKSwgbGFzID0gMCwgb3V0ZXIgPSBUUlVFKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gMTF9Cm1hdF9hY2YgPC0gbWF0cml4KG5yb3cgPSAxMCwgbmNvbCA9IDQxKQpmb3IgKGkgaW4gc2VxKDEwKSl7CiAgICBtYXRfYWNmW2ksXSA8LSBhY2YobGlzdHNfdHNfYXIybWExW1tpXV0sIGxhZy5tYXggPSA0MCwgcGxvdCA9IEYpJGFjZlssMSwxXQp9CiMgTWFudWFsIENhbGN1bGF0aW9uIG9mIEFDCnZlY19hY2YgPC0gYygwLjU4OTYsIDAuNTU5NiwgMC41MDY2LCByZXAoMCwgMzgpKQpmb3IgKGkgaW4gc2VxKDQsIDQxKSl7CiAgICB2ZWNfYWNmW2ldIDwtIDAuOCAqIHZlY19hY2ZbaS0xXSArIDAuMSAqIHZlY19hY2ZbaS0yXQp9CnZlY19hY2YgPC0gdmVjX2FjZiAvIHZlY19hY2ZbMV0KIyBGdW5jdGlvbmFsIENhbGN1bGF0aW9uIG9mIEFDCnZlY19hY2ZfMiA8LSBBUk1BYWNmKGMoMC44LCAwLjEpLCAwLjgsIGxhZy5tYXggPSA0MCwgcGFjZiA9IEZBTFNFKQojIFBsb3QgZGlmZmVyZW50IEFDRnMKcGxvdChzZXEoMCwgNDApLCB2ZWNfYWNmLCB5bGltID0gYyhtaW4obWF0X2FjZiksIDEpLAogICAgIHR5cGUgPSAibCIsIGNvbCA9ICJyZWQiLCBsdHkgPSAyLCBsd2QgPSAzLCB4bGFiID0gImxhZ3MiLCB5bGFiID0gImF1dG9jb3ZhcmlhbmNlIGZ1bmN0aW9uIiwgCiAgICAgbWFpbiA9ICJFc3RpbWF0ZWQgQUNGIGZyb20gUmVhbGl6YXRpb25zIGFuZCBNYW51YWwgQ2FsY3VsYXRlZCBBQ0Ygb2YgQVJJTUEoMiwwLDEpIikKbGluZXMoc2VxKDAsIDQwKSwgcmVwKDAuMDUsIDQxKSwgdHlwZSA9ICJsIiwgY29sID0gImJsdWUiLCBsdHkgPSAyLCBsd2QgPSAxKQpsaW5lcyhzZXEoMCwgNDApLCByZXAoMC4wNSwgNDEpLCB0eXBlID0gImwiLCBjb2wgPSAiYmx1ZSIsIGx0eSA9IDIsIGx3ZCA9IDEpCmxpbmVzKHNlcSgwLCA0MCksIHJlcCgtMC4wNSwgNDEpLCB0eXBlID0gImwiLCBjb2wgPSAiYmx1ZSIsIGx0eSA9IDIsIGx3ZCA9IDEpCmxlZ2VuZCgidG9wcmlnaHQiLCBpbnNldCA9IC4wMiwgbGVnZW5kID0gYygiRXN0aW1hdGVkIEFDRiIsICI1JSBzaWduaWZpY2FuY2UgbGltaXRzIiwgIk1hbnVhbCBDYWxjdWxhdGVkIEFDRiIpLCAKICAgICAgIGNvbCA9IGMoImJsYWNrIiwgImJsdWUiLCAicmVkIiksIGx0eSA9IGMoMSwgMiwgMiksIGx3ZCA9IGMoMSwgMSwgMykpCmZvciAoaSBpbiBzZXEoMTApKXsKICAgIGxpbmVzKHNlcSgwLCA0MCksIG1hdF9hY2ZbaSxdLCB0eXBlID0gImwiLCBjb2wgPSAiYmxhY2siLCBsdHkgPSAxLCBsd2QgPSAxKQp9CmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTIsIGZpZy53aWR0aCA9IDEyfQpwYXIobWZyb3cgPSBjKDEwLCAxKSwgbWFyID0gYygwLjUsIDAuNSwgMC41LCAwLjUpLCBvbWEgPSBjKDIsIDIsIDIsIDIpKQpmb3IgKGkgaW4gc2VxKDEwKSl7CiAgICBwYWNmKGxpc3RzX3RzX2FyMm1hMVtbaV1dLCBsYWcubWF4ID0gMjAsIHhheHQgPSAibiIsIHhsYWIgPSBOVUxMLCB5bGFiID0gTlVMTCwgZnJhbWUucGxvdCA9IFRSVUUpCn0KdGl0bGUobWFpbiA9ICJQQUNGIG9mIDEwIFJlYWxpemF0aW9ucyBmcm9tIHRoZSBBUklNQSgyLDAsMSkgUHJvY2VzcyIsIGNleC5tYWluID0gMiwgb3V0ZXIgPSBUUlVFKQpheGlzKDEsIGF0ID0gc2VxKDAsIDIwKSwgbGFzID0gMCwgb3V0ZXIgPSBUUlVFKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gMTF9Cm1hdF9wYWNmIDwtIG1hdHJpeChucm93ID0gMTAsIG5jb2wgPSAyMCkKZm9yIChpIGluIHNlcSgxMCkpewogICAgbWF0X3BhY2ZbaSxdIDwtIHBhY2YobGlzdHNfdHNfYXIybWExW1tpXV0sIGxhZy5tYXggPSAyMCwgcGxvdCA9IEYpJGFjZlssMSwxXQp9CiMgRnVuY3Rpb25hbCBDYWxjdWxhdGlvbiBvZiBQQUNGCnZlY19wYWNmIDwtIEFSTUFhY2YoYygwLjgsIDAuMSksIDAuOCwgbGFnLm1heCA9IDIwLCBwYWNmID0gVFJVRSkKIyBQbG90IGRpZmZlcmVudCBQQUNGcwpwbG90KHNlcSgxLCAyMCksIHZlY19wYWNmLCB5bGltID0gYyhtaW4obWF0X3BhY2YpLCAxKSwKICAgICB0eXBlID0gImwiLCBjb2wgPSAicmVkIiwgbHR5ID0gMiwgbHdkID0gMywgeGF4dCA9ICJuIiwgYnR5ID0gIm4iLCB4bGFiID0gImxhZ3MiLCB5bGFiID0gImF1dG9jb3ZhcmlhbmNlIGZ1bmN0aW9uIiwgCiAgICAgbWFpbiA9ICJFc3RpbWF0ZWQgUEFDRiBmcm9tIFJlYWxpemF0aW9ucyBhbmQgRnVuY3Rpb24tQ2FsY3VsYXRlZCBQQUNGIG9mIEFSSU1BKDIsMCwxKSIpCmxpbmVzKHNlcSgxLCAyMCksIHJlcCgwLjA1LCAyMCksIHR5cGUgPSAibCIsIGNvbCA9ICJibHVlIiwgbHR5ID0gMiwgbHdkID0gMSkKbGluZXMoc2VxKDEsIDIwKSwgcmVwKC0wLjA1LCAyMCksIHR5cGUgPSAibCIsIGNvbCA9ICJibHVlIiwgbHR5ID0gMiwgbHdkID0gMSkKbGVnZW5kKCJ0b3ByaWdodCIsIGluc2V0ID0gLjAyLCBsZWdlbmQgPSBjKCJFc3RpbWF0ZWQgUEFDRiIsICI1JSBzaWduaWZpY2FuY2UgbGltaXRzIiwgIkZ1bi1DYWxjdWxhdGVkIFBBQ0YiKSwgCiAgICAgICBjb2wgPSBjKCJibGFjayIsICJibHVlIiwgInJlZCIpLCBsdHkgPSBjKDEsIDIsIDIpLCBsd2QgPSBjKDEsIDEsIDMpKQpmb3IgKGkgaW4gc2VxKDEwKSl7CiAgICBsaW5lcyhzZXEoMSwgMjApLCBtYXRfcGFjZltpLF0sIHR5cGUgPSAibCIsIGNvbCA9ICJibGFjayIsIGx0eSA9IDEsIGx3ZCA9IDEpCn0KYXhpcygxLCBhdCA9IHNlcSgxLCAyMCwgYnkgPSAxKSwgbGFzID0gMCwgb3V0ZXIgPSBGQUxTRSkKYGBgCgojIFF1ZXN0aW9uIDIsIFByZWRpY3RpbmcgdGhlIENhcmJvbi1EaW94aWRlIExldmVsIGluIGFuIE9mZmljZQoKYGBge3J9Cmxpc3RfY28yLmxvZy5tZWFuIDwtIGMoNi4xNTMsIDYuMzA4LCA2LjMyNywgNi4zNDQsIDYuMjY2LCA2LjEyMSwgNi4wOTYsIDYuMDgxLCAKICAgICAgICAgICAgICAgICAgICAgICA2LjE3OCwgNi40MTEsIDYuNDQyLCA2LjUwNSwgNi4xOTUsIDYuMDg1LCA2LjA4NiwgNi4wNzkpCmxpc3RfY28yLmxvZyA8LSBsaXN0X2NvMi5sb2cubWVhbiAtIDYuMjQKcHJlZF9jbzIubG9nXzEuaGF0IDwtIGZ1bmN0aW9uKHQsIGxpc3RfY28yLmxvZyl7CiAgICByZXR1cm4oMC41NDcgKiBsaXN0X2NvMi5sb2dbdF0gKyAwLjg2ICogbGlzdF9jbzIubG9nW3QtN10gLSAwLjQ3MDQyICogbGlzdF9jbzIubG9nW3QtOF0pCn0KcHJlZF9jbzIubG9nXzIuaGF0IDwtIGZ1bmN0aW9uKHQsIGxpc3RfY28yLmxvZyl7CiAgICByZXR1cm4oMC4yOTkyMDkgKiBsaXN0X2NvMi5sb2dbdF0gKyAwLjg2ICogbGlzdF9jbzIubG9nW3QtNV0gLSAwLjQ3MDQyICogbGlzdF9jbzIubG9nW3QtNl0gKwogICAgICAgICAgIDAuNDcwNDIgKiBsaXN0X2NvMi5sb2dbdC03XSAtIDAuMjU3MzE5NzQgKiBsaXN0X2NvMi5sb2dbdC04XSkKfQpjbzIubG9nXzE3LmhhdCA8LSBwcmVkX2NvMi5sb2dfMS5oYXQoMTYsIGxpc3RfY28yLmxvZykKY28yLmxvZ18xOC5oYXQgPC0gcHJlZF9jbzIubG9nXzIuaGF0KDE2LCBsaXN0X2NvMi5sb2cpCiMgUHJlZGljdGlvbiBJbnRlcnZhbApjYWxfdmVjX2ludGVydmFsUHJlZCA8LSBmdW5jdGlvbih5LmhhdCwgdmFyLCBwcm9iID0gMC45NSl7CiAgICBxdWFudGlsZU5vcm1EaXN0IDwtIHFub3JtKHAgPSAwLjk1KQogICAgYm91bmRVcCA8LSB5LmhhdCArIHF1YW50aWxlTm9ybURpc3QgKiBzcXJ0KHZhcikKICAgIGJvdW5kTG93IDwtIHkuaGF0IC0gcXVhbnRpbGVOb3JtRGlzdCAqIHNxcnQodmFyKQogICAgcmV0dXJuKGxpc3QoYm91bmRVcCA9IGRyb3AoYm91bmRVcCksIGJvdW5kTG93ID0gZHJvcChib3VuZExvdykpKQp9CnZlY19pbnRlcnZhbFByZWRfMTcuaGF0Lm1lYW4gPC0gY2FsX3ZlY19pbnRlcnZhbFByZWQoeS5oYXQgPSBjbzIubG9nXzE3LmhhdCArIDYuMjQsIHZhciA9IDQuMjI1ZS0zKQp2ZWNfaW50ZXJ2YWxQcmVkXzE4LmhhdC5tZWFuIDwtIGNhbF92ZWNfaW50ZXJ2YWxQcmVkKHkuaGF0ID0gY28yLmxvZ18xOC5oYXQgKyA2LjI0LCB2YXIgPSA2LjUzNjA3NUUtMykKYGBgCgpQbG90IHRoZSByZXN1bHQKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gMTF9CnBsb3Qoc2VxKDEsIDE2KSwgbGlzdF9jbzIubG9nLm1lYW4sIAogICAgIHR5cGUgPSAiYiIsIGNvbCA9ICJibHVlIiwgbHdkID0gMSwgbHR5ID0gMSwgeGF4dCA9ICJuIiwgYnR5ID0gIm4iLCB4bGltID0gYygwLCAxOSksIHlsaW0gPSBjKDYuMCwgNi42KSwKICAgICBtYWluID0gcGFzdGUoIlR3by1TdGVwIFByZWRpY3Rpb24gb2YgQ2FyYm9uLURpb3hpZGUgTGV2ZWwgaW4gYW4gT2ZmaWNlIGJ5IEFSSU1BKDEsOCwwKSBNb2RlbCIpLCAKICAgICB4bGFiID0gIlNlcmllcyIsIHlsYWIgPSAiRGVncmVlIikKcG9pbnRzKGMoMTcsIDE4KSwgYyhjbzIubG9nXzE3LmhhdCArIDYuMjQsIGNvMi5sb2dfMTguaGF0ICsgNi4yNCksIAogICAgICAgdHlwZSA9ICJiIiwgY29sID0gImJsdWUiLCBsdHkgPSAxLCBwY2ggPSAxNikgICMgUHJlZGljdGVkIHZhbHVlcwpsaW5lcyhjKDE2LCAxNyksIGMobGlzdF9jbzIubG9nLm1lYW5bMTZdLCBjbzIubG9nXzE3LmhhdCArIDYuMjQpLCAKICAgICAgdHlwZSA9ICJjIiwgY29sID0gImJsdWUiLCBsdHkgPSAxKSAgIyBDb25uZWN0IG9ic2VydmF0aW9ucyB3aXRoIG9uZSBzdGVwIHByZWRpY3Rpb24KbGVnZW5kKCJ0b3BsZWZ0IiwgaW5zZXQgPSAuMDIsIGxlZ2VuZCA9IGMoIk9ic2VydmF0aW9ucyIsICJQcmVkaWN0aW9uIiwgIlByZWQgSW50ZXJ2YWwiKSwgCiAgICAgICBjb2wgPSBjKCJibHVlIiwgImJsdWUiLCAicmVkIiksIHBjaCA9IGMoMSwgMTYsIDE1KSwgCiAgICAgICBsdHkgPSBjKDEsIDEsIDMpLCBsd2QgPSBjKDEsIDEsIDMpKQojIFBsb3QgdGhlIHByZWRpY3Rpb24gcmVzdWx0CnBvaW50cyhjKDE3LCAxNyksIHZlY19pbnRlcnZhbFByZWRfMTcuaGF0Lm1lYW4sIAogICAgICAgdHlwZSA9ICJiIiwgY29sID0gInJlZCIsIHBjaCA9IDE1LCBsdHkgPSAzLCBsd2QgPSAyKQpwb2ludHMoYygxOCwgMTgpLCB2ZWNfaW50ZXJ2YWxQcmVkXzE4LmhhdC5tZWFuLCAKICAgICAgIHR5cGUgPSAiYiIsIGNvbCA9ICJyZWQiLCBwY2ggPSAxNSwgbHR5ID0gMywgbHdkID0gMikKYXhpcygxLCBhdCA9IHNlcSgxLCAxOCwgYnkgPSAxKSwgbGFzID0gMCwgb3V0ZXIgPSBGQUxTRSkKYGBgCgojIFF1ZXN0aW9uIDMsIFNpbXVsYXRpbmcgU2Vhc29uYWwgUHJvY2Vzc2VzCgpEZWZpbmUgdGhlIGZ1bmN0aW9uIHRvIHBsb3QgdGhlIHJlc2lkdWFscyBmb3IgYW5hbHlzaXMuCgpgYGB7cn0KIyBQbG90IHRoZSB0aW1lIHNlcmllcyAvIHJlc2lkdWFscyBhbmQgaXRzIEFDRiBhbmQgUEFDRi4gTm8gTGp1bmctQm94IHBsb3QKcGxvdFRpbWVTZXJpZXNSZXNpZHVhbCA8LSBmdW5jdGlvbihkYXQsIG51bV9sYWcgPSA1MCwgbGlzdF9wYXJhLCAuLi4pewogICAgIyBJZiB0aGUgaW5wdXQgZGF0IGlzIGFyaW1hIG1vZGVsLCBqdXN0IHRha2UgaXRzIHJlc2lkdWFscyBhcmUgdGhlIGRhdC4KICAgIGlmKGNsYXNzKGRhdCkgPT0gIkFyaW1hIikKICAgICAgICBkYXQgPC0gZGF0JHJlc2lkdWFscwogICAgcGFyKG1mcm93ID0gYygzLCAxKSwgbWdwID0gYygyLCAwLjcsIDApLCBtYXIgPSBjKDEsIDEsIDEsIDEpLCBvbWEgPSBjKDIsIDIsIDQsIDIpLCAKICAgICAgICBjZXgubGFiID0gMC44LCBjZXguYXhpcyA9IDAuOCkKICAgIHBsb3QoZGF0KQogICAgdGl0bGUobWFpbiA9IHBhc3RlKCJUUywgQUNGLCBQQUNGIHdoZW4gcGhpXzEoIiwgbGlzdF9wYXJhWzFdLCAiKSwgcGhpXzIoIiwgbGlzdF9wYXJhWzJdLCAKICAgICAgICAgICAgICAgICAgICAgICAiKSwgcGhpLmNhcCgiLCBsaXN0X3BhcmFbM10sICIpIHRoZXRhKCIsIGxpc3RfcGFyYVs0XSwgIikgYW5kIHRoZXRhLmNhcCgiLCBsaXN0X3BhcmFbNV0sIAogICAgICAgICAgICAgICAgICAgICAgICIpIiksIGNleC5tYWluID0gMS41LCBsaW5lID0gMSwgb3V0ZXIgPSBUUlVFKQogICAgYWNmKGRhdCwgbGFnLm1heCA9IDIwLCB4YXh0ID0gIm4iKQogICAgYXhpcygxLCBhdCA9IHNlcSgwLCAyMCwgYnkgPSAxKSwgbGFzID0gMCwgb3V0ZXIgPSBGQUxTRSkKICAgIHBhY2YoZGF0LCBsYWcubWF4ID0gMjAsIHhheHQgPSAibiIpCiAgICBheGlzKDEsIGF0ID0gc2VxKDEsIDIwLCBieSA9IDEpLCBsYXMgPSAwLCBvdXRlciA9IEZBTFNFKQogICAgIyBManVuZy1Cb3ggUGxvdAogICAgIyB2YWx1ZV9wIDwtIHNhcHBseSgxOm51bV9sYWcsIGZ1bmN0aW9uKGkpIEJveC50ZXN0KGRhdCwgaSwgdHlwZSA9ICJManVuZy1Cb3giKSRwLnZhbHVlKQogICAgIyBwbG90KDFMOiBudW1fbGFnLCB2YWx1ZV9wLCBtYWluID0gInAgVmFsdWVzIGZvciBManVuZy1Cb3ggU3RhdGlzdGljIiwKICAgICMgICAgICB4bGFiID0gImxhZyIsIHlsYWIgPSAicCB2YWx1ZSIsIHlsaW0gPSBjKDAsMSkpCiAgICAjIGFibGluZShoID0gMC4wNSwgbHR5ID0gMiwgY29sID0gImJsdWUiKQp9CmBgYAoKYGBge3J9Cmp1ZF9zdGF0aW9uYXJ5X2FyaW1hIDwtIGZ1bmN0aW9uKHZlY19waGkpewogICAgIyBEaWZmZXJlbnQgZGVmaW5pdGlvbnMgb2YgQVJNQSBtb2RlbHMgaGF2ZSBkaWZmZXJlbnQgc2lnbnMgZm9yIHRoZSBBUiBhbmQvb3IgTUEgY29lZmZpY2llbnRzLgogICAgIyBIb3cgdG8gZGVjaWRlIHRoZSBzaWduIG9mIHBoaSBpcyB0aGF0IHBoaSBhbmQgcGFzdCBvYnNlcnZhdGlvbnMgYXJlIGluIGxlZnQtaGFuZC1zaWRlCiAgICAjIEVkd2FyZCBKLiBYdSwgMTkwNDAyCiAgICB2ZWNfcGhpIDwtIGMoMSwgdmVjX3BoaSkKICAgIHZlYy5yZXZfcGhpIDwtIHJldih2ZWNfcGhpKQogICAgdmVjX3Jvb3QgPC0gcG9seXJvb3QodmVjLnJldl9waGkpCiAgICB2ZWNfcm9vdC5hYnMgPC0gYWJzKHZlY19yb290KQogICAgdmVjX3Jvb3QuYWJzLnVuaXQgPC0gYWJzKHZlY19yb290KSA8PSByZXAoMSwgbGVuZ3RoKHZlY19yb290KSkKICAgIHJldHVybihhbGwodmVjX3Jvb3QuYWJzLnVuaXQpKQp9CmBgYAoKYGBge3J9Cmxpc3RfcGhpXzEgPC0gYygwLjgsIDAsIC0wLjcsIC0wLjgsIDAuNiwgMCkKbGlzdF9waGlfMiA8LSBjKDAsIDAsIDAsIDAsIDAuNSwgMCkKbGlzdF9waGkuY2FwXzEgPC0gYygwLCAtIDAuODUsIDAsIDAuNywgMC45LCAwKQpsaXN0X3RoZXRhXzEgPC0gYygwLCAwLCAwLCAwLCAwLCAtIDAuOSkKbGlzdF90aGV0YS5jYXBfMSA8LSBjKDAsIDAsIDAuOCwgMCwgMCwgLSAwLjcpCm1hdF9waGkgPC0gbWF0cml4KDAsIG5yb3cgPSA2LCBuY29sID0gMTQpCm1hdF90aGV0YSA8LSBtYXRyaXgoMCwgbnJvdyA9IDYsIG5jb2wgPSAxMykKbGlzdF9zdGF0aW9uYXJ5IDwtIGxvZ2ljYWwobGVuZ3RoID0gNikKZm9yIChpIGluIHNlcSg2KSl7CiAgICBwaGlfMSA8LSBsaXN0X3BoaV8xW2ldCiAgICBwaGlfMiA8LSBsaXN0X3BoaV8yW2ldCiAgICBwaGkuY2FwXzEgPC0gbGlzdF9waGkuY2FwXzFbaV0KICAgIHRoZXRhXzEgPC0gbGlzdF90aGV0YV8xW2ldCiAgICB0aGV0YS5jYXBfMSA8LSBsaXN0X3RoZXRhLmNhcF8xW2ldCiAgICBtYXRfcGhpW2ksXSA8LSBjKHBoaV8xLCBwaGlfMiwgcmVwKDAsIDkpLCBwaGkuY2FwXzEsIHBoaV8xICogcGhpLmNhcF8xLCBwaGlfMiAqIHBoaS5jYXBfMSkKICAgIG1hdF90aGV0YVtpLF0gPC0gYyh0aGV0YV8xLCByZXAoMCwgMTApLCB0aGV0YS5jYXBfMSwgdGhldGFfMSAqIHRoZXRhLmNhcF8xKQogICAgbGlzdF9zdGF0aW9uYXJ5W2ldIDwtIGp1ZF9zdGF0aW9uYXJ5X2FyaW1hKG1hdF9waGlbaSxdKQp9CmBgYAoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIGZpZy5oZWlnaHQgPSA0LCBmaWcud2lkdGggPSAxMX0KbGlzdF90c19hcjEzbWExMyA8LSB2ZWN0b3IoImxpc3QiLCA2KQpzZXQuc2VlZCg5OSkKZm9yKGkgaW4gc2VxKDYpKXsKICAgIGlmKGxpc3Rfc3RhdGlvbmFyeVtpXSl7CiAgICAgICAgbGlzdF9wYXJhIDwtIHJlcCgwLCA1KQogICAgICAgIGxpc3RfcGFyYVsxXSA8LSBsaXN0X3BoaV8xW2ldCiAgICAgICAgbGlzdF9wYXJhWzJdIDwtIGxpc3RfcGhpXzJbaV0KICAgICAgICBsaXN0X3BhcmFbM10gPC0gbGlzdF9waGkuY2FwXzFbaV0KICAgICAgICBsaXN0X3BhcmFbNF0gPC0gbGlzdF90aGV0YV8xW2ldCiAgICAgICAgbGlzdF9wYXJhWzVdIDwtIGxpc3RfdGhldGEuY2FwXzFbaV0KICAgICAgICBsaXN0X3RzX2FyMTNtYTEzW1tpXV0gPC0gYXJpbWEuc2ltKG1vZGVsID0gbGlzdChhciA9IC0gbWF0X3BoaVtpLF0sIG1hID0gIG1hdF90aGV0YVtpLF0pLCBuID0gMjAwKQogICAgICAgIHBsb3RUaW1lU2VyaWVzUmVzaWR1YWwobGlzdF90c19hcjEzbWExM1tbaV1dLCBsaXN0X3BhcmEgPSBsaXN0X3BhcmEpCiAgICB9Cn0KYGBgCgojIFNpbXVsYXRlIGFuZCBFc3RpbWF0aW9uCgpgYGB7cn0Kc2ltX2FyMW1hMSA8LSBmdW5jdGlvbihwaGksIHRoZXRhLCBzaWdtYSwgbnVtdGltZV9TaW0pewogICAgIyBEaWZmZXJlbnQgZGVmaW5pdGlvbnMgb2YgQVJNQSBtb2RlbHMgaGF2ZSBkaWZmZXJlbnQgc2lnbnMgZm9yIHRoZSBBUiBhbmQvb3IgTUEgY29lZmZpY2llbnRzLgogICAgc2V0LnNlZWQoOTkpCiAgICBsaXN0c190c19hcjFtYTEgPC0gdmVjdG9yKCJsaXN0IiwgMTAwKQogICAgbGlzdHNfbW9kX2FyMW1hMSA8LSB2ZWN0b3IoImxpc3QiLCAxMDApCiAgICB2ZWNfcGhpLmVzdCA8LSByZXAoMCwgMTAwKQogICAgdmVjX3RoZXRhLmVzdCA8LSByZXAoMCwgMTAwKQogICAgZm9yIChpIGluIHNlcSgxMDApKXsKICAgICAgICAjIHdoaWxlKGFueShjbGFzcyhvdXQgPC0gdHJ5Q2F0Y2goYXJpbWEobGlzdHNfdHNfYXIxbWExW1tpXV0gPC0gYXJpbWEuc2ltKG1vZGVsID0gbGlzdChhciA9IC0gcGhpXzEsIAogICAgICAgICMgICAgIG1hID0gdGhldGFfMSksIHNkID0gc2lnbWEsIG4gPSBudW10aW1lX1NpbSksIG9yZGVyID0gYygxLCAwLCAxKSwgaW5jbHVkZS5tZWFuID0gRkFMU0UpLCAKICAgICAgICAjICAgICBlcnJvciA9IGZ1bmN0aW9uKGUpIGUpKSA9PSAiZXJyb3IiKSl7CiAgICAgICAgICAgICMgaiA8LSBqICsgMQogICAgICAgICAgICAjIHNldC5zZWVkKGopCiAgICAgICAgIyB9CiAgICAgICAgbGlzdHNfdHNfYXIxbWExW1tpXV0gPC0gYXJpbWEuc2ltKG1vZGVsID0gbGlzdChhciA9IC0gcGhpLCBtYSA9IHRoZXRhKSwgc2QgPSBzaWdtYSwgbiA9IG51bXRpbWVfU2ltKQogICAgICAgIGxpc3RzX21vZF9hcjFtYTFbW2ldXSA8LSBhcmltYShsaXN0c190c19hcjFtYTFbW2ldXSwgb3JkZXIgPSBjKDEsIDAsIDEpLCBtZXRob2QgPSAiTUwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmNsdWRlLm1lYW4gPSBGQUxTRSkKICAgICAgICAjIFJlbWVtYmVyIHRvIHNwZWNpZnkgdGhlIGVzdGltYXRpb24gbWV0aG9kCiAgICAgICAgdmVjX3BoaS5lc3RbaV0gPC0gbGlzdHNfbW9kX2FyMW1hMVtbaV1dJGNvZWZbMV0KICAgICAgICB2ZWNfdGhldGEuZXN0W2ldIDwtIGxpc3RzX21vZF9hcjFtYTFbW2ldXSRjb2VmWzJdCiAgICB9CiAgICBxdWFuOTUgPC0gQXBwcm94UXVhbnRpbGUoaGlzdCh2ZWNfcGhpLmVzdCwgYnJlYWtzID0gNTAsIHBsb3QgPSBGQUxTRSksIDAuOTUpCiAgICBsaXN0X3Jlc3VsdCA8LSBsaXN0KHF1YW45NSA9IHF1YW45NSwgdmVjX3BoaS5lc3QgPSB2ZWNfcGhpLmVzdCwgdmVjX3RoZXRhLmVzdCA9IHZlY190aGV0YS5lc3QpCiAgICByZXR1cm4obGlzdF9yZXN1bHQpCn0KaGlzdFBoaV9zaW1fYXIxbWExIDwtIGZ1bmN0aW9uKHZlY19waGkuZXN0LCBwaGksIHRoZXRhLCBzaWdtYSwgbnVtdGltZV9TaW0pewogICAgZGVuX3BoaS5lc3QgPC0gZGVuc2l0eSh2ZWNfcGhpLmVzdCwgYWRqdXN0ID0gMC4yKQogICAgaGlzdF9waGkuZXN0IDwtIGhpc3QodmVjX3BoaS5lc3QsIGJyZWFrcyA9IDUwLCBwbG90ID0gRkFMU0UpCiAgICBoaXN0KHZlY19waGkuZXN0LCBicmVha3MgPSA1MCwgZnJlcSA9IEZBTFNFLCB5bGltID0gYygwLCBtYXgoaGlzdF9waGkuZXN0JGRlbnNpdHksIGRlbl9waGkuZXN0JHkpKSwgCiAgICAgICAgIHhsYWIgPSAicGhpXzEiLCBtYWluID0gTlVMTCkgICMgY2V4LmxhYiA9IDAuOCwgY2V4LmF4aXMgPSAwLjgKICAgIGxpbmVzKGRlbl9waGkuZXN0LCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpCiAgICB0aXRsZShtYWluID0gcGFzdGUoIkhpc3Qgb2YgcGhpIHdoZW4gdGltZXMoIixudW10aW1lX1NpbSwiKSwgcGhpKCIsIAogICAgICAgICAgICAgICAgICAgICAgIHBoaSwgIiksIHRoZXRhKCIsIHRoZXRhLCAiKSBhbmQgc2QoIiwgc2lnbWEsICIpIikpICAjIGNleC5tYWluID0gMC44Cn0KaGlzdFBoaS4yX3NpbV9hcjFtYTEgPC0gZnVuY3Rpb24odmVjX3BoaS5lc3RfMSwgcGhpXzEsIHRoZXRhXzEsIHNpZ21hXzEsIG51bXRpbWVfU2ltXzEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZWNfcGhpLmVzdF8yLCBwaGlfMiwgdGhldGFfMiwgc2lnbWFfMiwgbnVtdGltZV9TaW1fMil7CiAgICBwYXIobWZyb3cgPSBjKDEsIDIpLCBtYXIgPSBjKDAuNSwgMS41LCAwLjUsIDAuNSksIG9tYSA9IHJlcCgyLCA0KSwgCiAgICAgICAgY2V4LmxhYiA9IDAuOCwgY2V4LmF4aXMgPSAwLjgsIGNleC5tYWluID0gMC44KQogICAgaGlzdFBoaV9zaW1fYXIxbWExKHZlY19waGkuZXN0XzEsIHBoaV8xLCB0aGV0YV8xLCBzaWdtYV8xLCBudW10aW1lX1NpbV8xKQogICAgaGlzdFBoaV9zaW1fYXIxbWExKHZlY19waGkuZXN0XzIsIHBoaV8yLCB0aGV0YV8yLCBzaWdtYV8yLCBudW10aW1lX1NpbV8yKQp9Cmhpc3RQaGkuNF9zaW1fYXIxbWExIDwtIGZ1bmN0aW9uKG1hdF9waGkuZXN0LCB2ZWNfcGhpLCB2ZWNfdGhldGEsIHZlY19zaWdtYSwgdmVjX251bXRpbWVfU2ltKXsKICAgIHBhcihtZnJvdyA9IGMoMiwgMiksIG1hciA9IGMoMS41LCAxLjUsIDEuNSwgMS41KSwgb21hID0gcmVwKDEsIDQpLCAKICAgICAgICBjZXgubGFiID0gMC44LCBjZXguYXhpcyA9IDAuOCwgY2V4Lm1haW4gPSAwLjgpCiAgICBmb3IgKGkgaW4gc2VxKDEsIDQpKXsKICAgICAgICBoaXN0UGhpX3NpbV9hcjFtYTEobWF0X3BoaS5lc3RbaSxdLCB2ZWNfcGhpW2ldLCB2ZWNfdGhldGFbaV0sIHZlY19zaWdtYVtpXSwgdmVjX251bXRpbWVfU2ltW2ldKQogICAgfQp9CnBsb3RDb250b3VyX3NpbV9hcjFtYTEgPC0gZnVuY3Rpb24odmVjX3RoZXRhLmVzdCwgdmVjX3BoaS5lc3QsIHBoaSwgdGhldGEsIHNpZ21hLCBudW10aW1lX1NpbSl7CiAgICBrZGVfYXIxbWExXzEgPC0ga2RlMmQodmVjX3RoZXRhLmVzdCwgdmVjX3BoaS5lc3QsIG4gPSAyMCkKICAgIGNvbnRvdXIoa2RlX2FyMW1hMV8xLCB4bGFiID0gInRoZXRhIiwgeWxhYiA9ICJwaGkiLCBidHkgPSAibiIsIG1haW4gPSBOVUxMKSAKICAgIHBvaW50cyh0aGV0YSwgLSBwaGksIHBjaCA9IDQsIGNleCA9IDIsIGx3ZCA9IDIsIGNvbCA9ICJyZWQiKQogICAgdGl0bGUobWFpbiA9IHBhc3RlKCJDb250b3VyIG9mIHRoZXRhKCIsIHRoZXRhLCAiKSBhbmQgcGhpKCIsIHBoaSwgIikgd2hlbiB0aW1lcygiLCBudW10aW1lX1NpbSAsCiAgICAgICAgIiksIHNkKCIsIHNpZ21hLCAiKSIpKQp9CnBsb3RDb250b3VyLjJfc2ltX2FyMW1hMSA8LSBmdW5jdGlvbih2ZWNfdGhldGEuZXN0XzEsIHZlY19waGkuZXN0XzEsIHBoaV8xLCB0aGV0YV8xLCBzaWdtYV8xLCBudW10aW1lX1NpbV8xLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlY190aGV0YS5lc3RfMiwgdmVjX3BoaS5lc3RfMiwgcGhpXzIsIHRoZXRhXzIsIHNpZ21hXzIsIG51bXRpbWVfU2ltXzIpewogICAgcGFyKG1mcm93ID0gYygxLCAyKSwgbWFyID0gYygwLjUsIDEuNSwgMC41LCAwLjUpLCBvbWEgPSByZXAoMiwgNCksIAogICAgICAgIGNleC5sYWIgPSAwLjgsIGNleC5heGlzID0gMC44LCBjZXgubWFpbiA9IDAuOCkKICAgIHBsb3RDb250b3VyX3NpbV9hcjFtYTEodmVjX3RoZXRhLmVzdF8xLCB2ZWNfcGhpLmVzdF8xLCBwaGlfMSwgdGhldGFfMSwgc2lnbWFfMSwgbnVtdGltZV9TaW1fMSkKICAgIHBsb3RDb250b3VyX3NpbV9hcjFtYTEodmVjX3RoZXRhLmVzdF8yLCB2ZWNfcGhpLmVzdF8yLCBwaGlfMiwgdGhldGFfMiwgc2lnbWFfMiwgbnVtdGltZV9TaW1fMikKfQpwbG90Q29udG91ci40X3NpbV9hcjFtYTEgPC0gZnVuY3Rpb24obWF0X3RoZXRhLmVzdCwgbWF0X3BoaS5lc3QsIHZlY19waGksIHZlY190aGV0YSwgdmVjX3NpZ21hLCB2ZWNfbnVtdGltZV9TaW0pewogICAgcGFyKG1mcm93ID0gYygyLCAyKSwgbWFyID0gYygxLjUsIDEuNSwgMS41LCAxLjUpLCBvbWEgPSByZXAoMSwgNCksIAogICAgICAgIGNleC5sYWIgPSAwLjgsIGNleC5heGlzID0gMC44LCBjZXgubWFpbiA9IDAuOCkKICAgIGZvciAoaSBpbiBzZXEoMSwgNCkpewogICAgICAgIHBsb3RDb250b3VyX3NpbV9hcjFtYTEobWF0X3RoZXRhLmVzdFtpLF0sIG1hdF9waGkuZXN0W2ksXSwgdmVjX3BoaVtpXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZWNfdGhldGFbaV0sIHZlY19zaWdtYVtpXSwgdmVjX251bXRpbWVfU2ltW2ldKQogICAgfQp9CnBsb3RRUV9zaW1fYXIxbWExIDwtIGZ1bmN0aW9uKHZlY19waGkuZXN0LCBwaGksIHRoZXRhLCBzaWdtYSwgbnVtdGltZV9TaW0pewogICAgcXFub3JtKHZlY19waGkuZXN0LCBtYWluID0gTlVMTCwgYnR5ID0gIm4iKQogICAgcXFsaW5lKHZlY19waGkuZXN0KQogICAgdGl0bGUobWFpbiA9IHBhc3RlKCJOb3JtIFEtUSBQbG90IG9mIHBoaSB3aGVuIHRpbWVzKCIsIG51bXRpbWVfU2ltICwKICAgICAgICAgICAgICAgICAgICAgICAiKSwgcGhpKCIsIHBoaSwgIiksIHRoZXRhKCIsIHRoZXRhLCAiKSBhbmQgc2QoIiwgc2lnbWEsICIpIikpCn0KcGxvdFFRLjJfc2ltX2FyMW1hMSA8LSBmdW5jdGlvbih2ZWNfcGhpLmVzdF8xLCBwaGlfMSwgdGhldGFfMSwgc2lnbWFfMSwgbnVtdGltZV9TaW1fMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVjX3BoaS5lc3RfMiwgcGhpXzIsIHRoZXRhXzIsIHNpZ21hXzIsIG51bXRpbWVfU2ltXzIpewogICAgcGFyKG1mcm93ID0gYygxLCAyKSwgbWFyID0gYygwLjUsIDEuNSwgMC41LCAwLjUpLCBvbWEgPSByZXAoMiwgNCksIAogICAgICAgIGNleC5sYWIgPSAwLjgsIGNleC5heGlzID0gMC44LCBjZXgubWFpbiA9IDAuOCkKICAgIHBsb3RRUV9zaW1fYXIxbWExKHZlY19waGkuZXN0XzEsIHBoaV8xLCB0aGV0YV8xLCBzaWdtYV8xLCBudW10aW1lX1NpbV8xKQogICAgcGxvdFFRX3NpbV9hcjFtYTEodmVjX3BoaS5lc3RfMiwgcGhpXzIsIHRoZXRhXzIsIHNpZ21hXzIsIG51bXRpbWVfU2ltXzIpCn0KcGxvdFFRLjRfc2ltX2FyMW1hMSA8LSBmdW5jdGlvbihtYXRfcGhpLmVzdCwgdmVjX3BoaSwgdmVjX3RoZXRhLCB2ZWNfc2lnbWEsIHZlY19udW10aW1lX1NpbSl7CiAgICBwYXIobWZyb3cgPSBjKDIsIDIpLCBtYXIgPSBjKDEuNSwgMS41LCAxLjUsIDEuNSksIG9tYSA9IHJlcCgxLCA0KSwgCiAgICAgICAgY2V4LmxhYiA9IDAuOCwgY2V4LmF4aXMgPSAwLjgsIGNleC5tYWluID0gMC44KQogICAgZm9yIChpIGluIHNlcSgxLCA0KSl7CiAgICAgICAgcGxvdFFRX3NpbV9hcjFtYTEobWF0X3BoaS5lc3RbaSxdLCB2ZWNfcGhpW2ldLCB2ZWNfdGhldGFbaV0sIHZlY19zaWdtYVtpXSwgdmVjX251bXRpbWVfU2ltW2ldKQogICAgfQp9CmBgYAoKSnVkZ2Ugd2hldGhlciB0aGUgZ2l2ZW4gcHJvY2VzcyBhcmUgc3RhdGlvbmFyeS4KCmBgYHtyfQpqdWRfc3RhdGlvbmFyeV9hcmltYSgtIDAuOSkKanVkX3N0YXRpb25hcnlfYXJpbWEoLSAwLjk5NSkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodCA9IDUsIGZpZy53aWR0aCA9IDEwLCB3YXJuaW5nPUZBTFNFfQpsaXN0X3Jlc3VsdF8xIDwtIHNpbV9hcjFtYTEoLSAwLjksIDAuNCwgMC4xLCAzMDApCmxpc3RfcmVzdWx0XzIgPC0gc2ltX2FyMW1hMSgtIDAuOSwgMC40LCA1LCAzMDApCmxpc3RfcmVzdWx0XzMgPC0gc2ltX2FyMW1hMSgtIDAuOTk1LCAwLjQsIDAuMSwgMzAwKQpsaXN0X3Jlc3VsdF80IDwtIHNpbV9hcjFtYTEoLSAwLjk5NSwgMC40LCA1LCAzMDApCm1hdF9waGkuZXN0IDwtIG1hdHJpeChucm93ID0gNCwgbmNvbCA9IDEwMCkKbWF0X3BoaS5lc3RbMSxdIDwtIGxpc3RfcmVzdWx0XzEkdmVjX3BoaS5lc3QKbWF0X3BoaS5lc3RbMixdIDwtIGxpc3RfcmVzdWx0XzIkdmVjX3BoaS5lc3QKbWF0X3BoaS5lc3RbMyxdIDwtIGxpc3RfcmVzdWx0XzMkdmVjX3BoaS5lc3QKbWF0X3BoaS5lc3RbNCxdIDwtIGxpc3RfcmVzdWx0XzQkdmVjX3BoaS5lc3QKbWF0X3RoZXRhLmVzdCA8LSBtYXRyaXgobnJvdyA9IDQsIG5jb2wgPSAxMDApCm1hdF90aGV0YS5lc3RbMSxdIDwtIGxpc3RfcmVzdWx0XzEkdmVjX3RoZXRhLmVzdAptYXRfdGhldGEuZXN0WzIsXSA8LSBsaXN0X3Jlc3VsdF8yJHZlY190aGV0YS5lc3QKbWF0X3RoZXRhLmVzdFszLF0gPC0gbGlzdF9yZXN1bHRfMyR2ZWNfdGhldGEuZXN0Cm1hdF90aGV0YS5lc3RbNCxdIDwtIGxpc3RfcmVzdWx0XzQkdmVjX3RoZXRhLmVzdApgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gOCwgZmlnLndpZHRoID0gMTF9Cmhpc3RQaGkuNF9zaW1fYXIxbWExKG1hdF9waGkuZXN0LCBjKC0gMC45LCAtIDAuOSwgLSAwLjk5NSwgLSAwLjk5NSksIHJlcCgwLjQsIDQpLCBjKDAuMSwgNSwgMC4xLCA1KSwgcmVwKDMwMCwgNCkpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQgPSA4LCBmaWcud2lkdGggPSAxMX0KcGxvdENvbnRvdXIuNF9zaW1fYXIxbWExKG1hdF90aGV0YS5lc3QsIG1hdF9waGkuZXN0LCBjKC0gMC45LCAtIDAuOSwgLSAwLjk5NSwgLSAwLjk5NSksIHJlcCgwLjQsIDQpLCBjKDAuMSwgNSwgMC4xLCA1KSwgcmVwKDMwMCwgNCkpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQgPSA4LCBmaWcud2lkdGggPSAxMX0KcGxvdFFRLjRfc2ltX2FyMW1hMShtYXRfcGhpLmVzdCwgYygtIDAuOSwgLSAwLjksIC0gMC45OTUsIC0gMC45OTUpLCByZXAoMC40LCA0KSwgYygwLjEsIDUsIDAuMSwgNSksIHJlcCgzMDAsIDQpKQpgYGAKCmBgYHtyLCBlY2hvID0gRkFMU0V9CnF1YW45NS5mcmFtZSA8LSBkYXRhLmZyYW1lKHZlY19waGlfMSA9IGMoLSAwLjksIC0gMC45LCAtIDAuOTk1LCAtIDAuOTk1KSwKICAgIHZlY19zaWdtYSA9IGMoMC4xLCA1LCAwLjEsIDUpLCB2ZWNfcXVhbjk1ID0gYyhsaXN0X3Jlc3VsdF8xJHF1YW45NSwgbGlzdF9yZXN1bHRfMiRxdWFuOTUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdF9yZXN1bHRfMyRxdWFuOTUsIGxpc3RfcmVzdWx0XzQkcXVhbjk1KSkKa25pdHI6OmthYmxlKHF1YW45NS5mcmFtZSwgY29sLm5hbWVzID0gYygncGhpXzEnLCAnc2lnbWEnLCAnOTUlIHF1YW50aWxlJyksIAogICAgICAgICAgICAgY2FwdGlvbiA9ICc5NSUgcXVhbnRpbGUgZnJvbSBBUklNQSBGaXQnLCBhbGlnbiA9ICJsIiwgZnVsbF93aWR0aCA9IEYpCmBgYAoKIyMgVGhlIEVmZmVjdCBvZiBOdW1iZXIgb2YgU2ltdWxhdGVkIE9ic2VydmF0aW9ucwoKYGBge3IsIGZpZy5oZWlnaHQgPSA1LCBmaWcud2lkdGggPSAxMX0KbGlzdF9yZXN1bHRfNSA8LSBzaW1fYXIxbWExKC0gMC45LCAwLjQsIDEsIDEwMCkKbGlzdF9yZXN1bHRfNiA8LSBzaW1fYXIxbWExKC0gMC45LCAwLjQsIDEsIDEwMDApCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQgPSA1LCBmaWcud2lkdGggPSAxMX0KaGlzdFBoaS4yX3NpbV9hcjFtYTEobGlzdF9yZXN1bHRfNSR2ZWNfcGhpLmVzdCwgLSAwLjksIDAuNCwgMSwgMTAwLAogICAgICAgICAgICAgICAgICAgICBsaXN0X3Jlc3VsdF82JHZlY19waGkuZXN0LCAtIDAuOSwgMC40LCAxLCAxMDAwKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gMTF9CnBsb3RRUS4yX3NpbV9hcjFtYTEobGlzdF9yZXN1bHRfNSR2ZWNfcGhpLmVzdCwgLSAwLjksIDAuNCwgMSwgMTAwLAogICAgICAgICAgICAgICAgICAgIGxpc3RfcmVzdWx0XzYkdmVjX3BoaS5lc3QsIC0gMC45LCAwLjQsIDEsIDEwMDApCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQgPSA1LCBmaWcud2lkdGggPSAxMX0KcGxvdENvbnRvdXIuMl9zaW1fYXIxbWExKGxpc3RfcmVzdWx0XzUkdmVjX3RoZXRhLmVzdCwgbGlzdF9yZXN1bHRfNSR2ZWNfcGhpLmVzdCwgLTAuOSwgMC40LCAxLCAzMDAsCiAgICAgICAgICAgICAgICAgICAgICAgICBsaXN0X3Jlc3VsdF82JHZlY190aGV0YS5lc3QsIGxpc3RfcmVzdWx0XzYkdmVjX3BoaS5lc3QsIC0wLjksIDAuNCwgMSwgMTAwMCkKYGBgCgo=