Question 1.1
Read the 3h and the 6h data and plot the given quantities as a function of time. Do indicate which data is used for training and testing. Comment on the evolution of the values over time. It is OK if the plot is combined with results from the following questions.
dat_3h <- read.csv("house_data_3h.csv")
time <- dat_3h[ , 1]
heating <- dat_3h[ , 2]
tempExternal <- dat_3h[ , 3]
iSolar <- dat_3h[ , 4]
series <- seq(1, length(time))
dat.f_3h <- data.frame(series, time, heating, tempExternal, iSolar)
n_3h <- length(dat.f_3h$series) - 8
plot(dat.f_3h$series, dat.f_3h$heating,
type = "b", col = "blue", lwd = 2, lty = 1, cex = 0.8,
main = "Training and Testing Data of Heating in 3h Data", xlab = "Series", ylab = "W")
points(dat.f_3h$series[(n_3h+1):(n_3h+8)], dat.f_3h$heating[(n_3h+1):(n_3h+8)],
col = "blue", lty = 1, pch = 16, cex = 0.8)
legend("topleft", inset = .02, legend = c("Training Data", "Testing Data"), col = c("blue", "blue"),
pch = c(1, 16), lty = c(1, 1), lwd = c(2, 2))

plot(dat.f_3h$series, dat.f_3h$tempExternal,
type = "b", col = "blue", lwd = 2, lty = 1, cex = 0.8,
main = "Training and Testing Data of External Temperature in 3h Data", xlab = "Series", ylab = "Celsius Degree")
points(dat.f_3h$series[(n_3h+1):(n_3h+8)], dat.f_3h$tempExternal[(n_3h+1):(n_3h+8)],
col = "blue", lty = 1, pch = 16, cex = 0.8)
legend("bottomleft", inset = .02, legend = c("Training Data", "Testing Data"), col = c("blue", "blue"),
pch = c(1, 16), lty = c(1, 1), lwd = c(2, 2))

plot(dat.f_3h$series, dat.f_3h$iSolar,
type = "b", col = "blue", lwd = 2, lty = 1, cex = 0.8,
main = "Training and Testing Data of Solar Irradiation in 3h Data", xlab = "Series", ylab = "W / m2")
points(dat.f_3h$series[(n_3h+1):(n_3h+8)], dat.f_3h$iSolar[(n_3h+1):(n_3h+8)],
col = "blue", lty = 1, pch = 16, cex = 0.8)
legend("topleft", inset = .02, legend = c("Training Data", "Testing Data"), col = c("blue", "blue"),
pch = c(1, 16), lty = c(1, 1), lwd = c(2, 2))

dat_6h <- read.csv("house_data_6h.csv")
time <- dat_6h[ , 1]
heating <- dat_6h[ , 2]
tempExternal <- dat_6h[, 3]
iSolar <- dat_6h[ , 4]
series <- seq(1, length(time))
dat.f_6h <- data.frame(series, time, heating, tempExternal, iSolar)
n_6h <- length(dat.f_6h$series) - 4
plot(dat.f_6h$series, dat.f_6h$heating,
type = "b", col = "blue", lwd = 2, lty = 1, cex = 0.8,
main = "Training and Testing Data of Heating in 6h Data", xlab = "Series", ylab = "W")
points(dat.f_6h$series[(n_6h+1):(n_6h+8)], dat.f_6h$heating[(n_6h+1):(n_6h+8)],
col = "blue", lty = 1, pch = 16, cex = 0.8)
legend("topleft", inset = .02, legend = c("Training Data", "Testing Data"), col = c("blue", "blue"),
pch = c(1, 16), lty = c(1, 1), lwd = c(2, 2))

plot(dat.f_6h$series, dat.f_6h$tempExternal,
type = "b", col = "blue", lwd = 2, lty = 1, cex = 0.8,
main = "Training and Testing Data of External Temperature in 6h Data", xlab = "Series", ylab = "Celsius Degree")
points(dat.f_6h$series[(n_6h+1):(n_6h+8)], dat.f_6h$tempExternal[(n_6h+1):(n_6h+8)],
col = "blue", lty = 1, pch = 16, cex = 0.8)
legend("bottomleft", inset = .02, legend = c("Training Data", "Testing Data"), col = c("blue", "blue"),
pch = c(1, 16), lty = c(1, 1), lwd = c(2, 2))

plot(dat.f_6h$series, dat.f_6h$iSolar,
type = "b", col = "blue", lwd = 2, lty = 1, cex = 0.8,
main = "Training and Testing Data of Solar Irradiation in 6h Data", xlab = "Series", ylab = "W / m2")
points(dat.f_6h$series[(n_6h+1):(n_6h+8)], dat.f_6h$iSolar[(n_6h+1):(n_6h+8)],
col = "blue", lty = 1, pch = 16, cex = 0.8)
legend("topleft", inset = .02, legend = c("Training Data", "Testing Data"), col = c("blue", "blue"),
pch = c(1, 16), lty = c(1, 1), lwd = c(2, 2))

Question 1.2
The observations in the last 24 hours are kept only for comparisons, so they are not in the training data set.
Define functions for General Linear Model (GLM)
cal_vec_sse.hat <- function(mat_x, vec_y, vec_theta.hat, mat_capSigma = diag(length(mat_x[,1]))){
# Calculate the sum of squared error (sse), eq.
vec_epsilon <- vec_y - mat_x %*% vec_theta.hat
sse.hat <- t(vec_epsilon) %*% solve(mat_capSigma) %*% vec_epsilon
return(sse.hat)
}
cal_sigma.hat <- function(mat_x, vec_y, vec_theta.hat, mat_capSigma = diag(length(mat_x[,1]))){
# Estimator for the variance, eq 3.44, Theorem 3.4, P39
sigma.hat.square <- cal_vec_sse.hat(mat_x, vec_y, vec_theta.hat, mat_capSigma) /
(length(mat_x[,1]) - length(vec_theta.hat))
sigma.hat <- sqrt(drop(sigma.hat.square))
return(sigma.hat)
}
cal_mat_var.theta.hat <- function(mat_x, sigma.hat, mat_capSigma= diag(length(mat_x[,1]))){
# Calculate the variance of vec_theta.hat, eq 3.43, P39
mat_var.theta.hat <- sigma.hat^2 * solve(t(mat_x) %*% solve(mat_capSigma) %*% mat_x)
return(drop(mat_var.theta.hat))
}
cal_mat_intervalConf <- function(prob = 0.95, mat_x, vec_theta.hat, vec_y){
n <- length(mat_x[,1])
p <- length(vec_theta.hat)
quantileStudentDist <- qt(p = prob, df = n - p)
vec_var.y.hat <- (vec_y - mat_x %*% vec_theta.hat)^2
vec_boundUp <- mat_x %*% vec_theta.hat + quantileStudentDist * sqrt(vec_var.y.hat / n)
vec_boundLow <- mat_x %*% vec_theta.hat - quantileStudentDist * sqrt(vec_var.y.hat / n)
return(list(vec_boundUp = vec_boundUp, vec_boundLow = vec_boundLow))
}
Define functions of weighted least square estimation, with default “mat_capSigma” being identity matrix.
pred_vec_theta.hat <- function(mat_x, vec_y, mat_capSigma = diag(length(mat_x[,1]))){
vec_theta.hat <- solve(t(mat_x) %*% solve(mat_capSigma) %*% mat_x) %*% t(mat_x) %*% solve(mat_capSigma) %*% vec_y
return(vec_theta.hat)
}
1.2.1
Formulate a linear regression model to estimate theta, in which it is assumed that the residuals have a constant variance and are independent. Estimate the parameters using the 6h data and include a measure of uncertainty for each of the estimates.
mat_x_6h <- cbind(1, dat.f_6h$tempExternal[1:n_6h], dat.f_6h$iSolar[1:n_6h])
vec_y_6h <- dat.f_6h$heating[1:n_6h]
vec_theta.hat_ols_6h <- pred_vec_theta.hat(mat_x = mat_x_6h, vec_y = vec_y_6h)
sigma.hat_ols_6h <- cal_sigma.hat(mat_x = mat_x_6h, vec_theta.hat = vec_theta.hat_ols_6h, vec_y = vec_y_6h)
mat_var.theta.hat_ols_6h <- cal_mat_var.theta.hat(mat_x = mat_x_6h, sigma = sigma.hat_ols_6h)
tempInternal_ols_6h <- vec_theta.hat_ols_6h[1] / - vec_theta.hat_ols_6h[2]
tempInternal_ols_6h
[1] 28.29711
Plot the residuals for this model.
vec_epsilon_ols_6h <- vec_y_6h - mat_x_6h %*% vec_theta.hat_ols_6h
plot(dat.f_6h$series[1:n_6h], vec_epsilon_ols_6h, type = "b", col = "blue", lwd = 2,
main = "Residuals of Ordinary Least Square Estimation using 6h Data", xlab = "Series", ylab = "W")

Estimate the parameters using the 3h data and include a measure of uncertainty for each of the estimates.
mat_x_3h <- cbind(1, dat.f_3h$tempExternal[1:n_3h], dat.f_3h$iSolar[1:n_3h])
vec_y_3h <- dat.f_3h$heating[1:n_3h]
vec_theta.hat_ols_3h <- pred_vec_theta.hat(mat_x = mat_x_3h, vec_y = vec_y_3h)
sigma.hat_ols_3h <- cal_sigma.hat(mat_x = mat_x_3h, vec_theta.hat = vec_theta.hat_ols_3h, vec_y = vec_y_3h)
mat_var.theta.hat_ols_3h <- cal_mat_var.theta.hat(mat_x = mat_x_3h, sigma = sigma.hat_ols_3h)
tempInternal_ols_3h <- vec_theta.hat_ols_3h[1] / - vec_theta.hat_ols_3h[2]
tempInternal_ols_3h
[1] 28.32177
Plot the residuals for this model.
vec_epsilon_ols_3h <- vec_y_3h - mat_x_3h %*% vec_theta.hat_ols_3h
plot(dat.f_3h$series[1:n_3h], vec_epsilon_ols_3h, type = "b", col = "blue", lwd = 2,
main = "Residuals of Ordinary Least Square Estimation using 3h Data", xlab = "Series", ylab = "W")

1.2.2
Now, we assume that the correlation structure of the residiuals is an exponential decaying function of the time distance between two observations
do_mat_capSigma_expDecay <- function(rho, n){
mat_capSigma <- diag(n)
for (i in 1: n){
for (j in 1: n){
mat_capSigma[i, j] <- rho^(abs(i - j))
}
}
return(mat_capSigma)
}
do_newRho <- function(mat_x, vec_epsilon, sigma, n){
sum <- 0
for (i in 1: (n - 1)){
sum <- sum + vec_epsilon[i] * vec_epsilon[i+1]
}
rho <- sum / (sigma^2 * (n - 1))
return(rho)
}
cal_rho_expDecayRelaxAlgo <- function(mat_x, vec_y){
rho <- 0
n <- length(mat_x[,1])
for (t in 1: 5){
mat_capSigma <- do_mat_capSigma_expDecay(rho, n)
vec_theta.hat <- pred_vec_theta.hat(mat_x, vec_y, mat_capSigma)
sigma.hat <- cal_sigma.hat(mat_x, vec_y, vec_theta.hat)
vec_epsilon <- vec_y - mat_x %*% vec_theta.hat
rho <- do_newRho(mat_x, vec_epsilon, sigma.hat, n)
}
return(rho)
}
(rho_expDecay_6h <- cal_rho_expDecayRelaxAlgo(mat_x = mat_x_6h, vec_y = vec_y_6h))
[1] 0.05331725
mat_capSigma_expDecay_6h <- do_mat_capSigma_expDecay(rho = rho_expDecay_6h,
n = n_6h)
vec_theta.hat_expDecay_6h <- pred_vec_theta.hat(mat_x = mat_x_6h, vec_y = vec_y_6h,
mat_capSigma = mat_capSigma_expDecay_6h)
sigma.hat_expDecay_6h <- cal_sigma.hat(mat_x = mat_x_6h, vec_theta.hat = vec_theta.hat_expDecay_6h, vec_y = vec_y_6h)
mat_var.theta.hat_expDecay_6h <- cal_mat_var.theta.hat(mat_x = mat_x_6h, sigma = sigma.hat_expDecay_6h)
(tempInternal_expDecay_6h <- vec_theta.hat_expDecay_6h[1] / - vec_theta.hat_expDecay_6h[2])
[1] 28.36691
vec_epsilon_expDecay_6h <- vec_y_6h - mat_x_6h %*% vec_theta.hat_expDecay_6h
plot(dat.f_6h$series[1:n_6h], vec_epsilon_expDecay_6h,
type = "l", col = "red", lwd = 3,
main = "Comparison of Residuals from OLS and WLS(Exp Decay) using 6h Data", xlab = "Series", ylab = "W")
lines(dat.f_6h$series[1:n_6h], vec_epsilon_ols_6h,
type = "l", col = "blue", lty = 2, lwd = 2)
legend("bottomleft", inset = .02, legend = c("OLS(Identity)", "WLS(Exp Decay)"), col = c("blue", "red"),
lty = c(2, 1), lwd = c(2, 3), cex= 0.8)

| Sigma being Identity Matrixt |
0.0000000 |
96.34049 |
-3.404605 |
-0.1231323 |
3.748241 |
28.29711 |
| Sigma with Exp Decaying |
0.0533173 |
96.24318 |
-3.392797 |
-0.1224553 |
3.748756 |
28.36691 |
1.2.3
(rho_expDecay_3h <- cal_rho_expDecayRelaxAlgo(mat_x = mat_x_3h, vec_y = vec_y_3h))
[1] 0.5564169
mat_capSigma_expDecay_3h <- do_mat_capSigma_expDecay(rho = rho_expDecay_3h,
n = n_3h)
vec_theta.hat_expDecay_3h <- pred_vec_theta.hat(mat_x = mat_x_3h, vec_y = vec_y_3h,
mat_capSigma = mat_capSigma_expDecay_3h)
sigma.hat_expDecay_3h <- cal_sigma.hat(mat_x = mat_x_3h, vec_y = vec_y_3h, vec_theta.hat = vec_theta.hat_expDecay_3h)
mat_var.theta.hat_expDecay_3h <- cal_mat_var.theta.hat(mat_x = mat_x_3h, sigma = sigma.hat_expDecay_3h)
(tempInternal_expDecay_3h <- vec_theta.hat_expDecay_3h[1] / - vec_theta.hat_expDecay_3h[2])
[1] 28.87185
vec_epsilon_expDecay_3h <- vec_y_3h - mat_x_3h %*% vec_theta.hat_expDecay_3h
plot(dat.f_3h$series[1:n_3h], vec_epsilon_expDecay_3h,
type = "l", col = "red", lwd = 3,
main = "Comparison of Residuals from OLS and WLS(Exp Decay) using 3h Data", xlab = "Series", ylab = "W")
lines(dat.f_3h$series[1:n_3h], vec_epsilon_ols_3h,
type = "l", col = "blue", lty = 2, lwd = 2)
legend("bottomleft", inset = .02, legend = c("OLS(Identity)", "WLS(Exp Decay)"), col = c("blue", "red"),
lty = c(2, 1), lwd = c(2, 3), cex= 0.8)

| Sigma being Identity Matrixt |
0.0000000 |
95.34499 |
-3.366492 |
-0.1053378 |
4.543622 |
28.32177 |
| Sigma with Exp Decaying |
0.5564169 |
94.26587 |
-3.264975 |
-0.0946527 |
4.688327 |
28.87185 |
Question 3, Local Trend mode
3.1, Local Linear Trend Model
Define functions for trend model.
do_seq_zeroDecreaseRev <- function(n){return(rev(- seq(0, n-1)))}
do_mat_capSigma_trend <- function(lambda = 1, n){
mat_capSigma_trend <- diag(n)
seq_zdi <- do_seq_zeroDecreaseRev(n)
for (i in 1: n){
mat_capSigma_trend[i, i] <- 1 * lambda^seq_zdi[i]
}
return(mat_capSigma_trend)
}
cal_mat_capF_trend <- function(mat_x_trend, mat_capSigma_trend){
mat_capF <- t(mat_x_trend) %*% solve(mat_capSigma_trend) %*% mat_x_trend
return(mat_capF)
}
cal_vec_h_trend <- function(mat_x_trend, mat_capSigma_trend, vec_y_trend){
mat_h <- t(mat_x_trend) %*% solve(mat_capSigma_trend) %*% vec_y_trend
return(mat_h)
}
cal_vec_theta.hat_trend <- function(mat_x_trend, mat_capSigma_trend, vec_y_trend){
mat_capF <- cal_mat_capF_trend(mat_x_trend, mat_capSigma_trend)
mat_h <- cal_vec_h_trend(mat_x_trend, mat_capSigma_trend, vec_y_trend)
vec_theta.hat_trend <- solve(mat_capF) %*% mat_h
return(vec_theta.hat_trend)
}
cal_vec_intervalPred <- function(prob = 0.95, n, p, y.hat, var){
quantileStudentDist <- qt(p = 0.95, df = n - p)
boundUp <- y.hat + quantileStudentDist * sqrt(var)
boundLow <- y.hat - quantileStudentDist * sqrt(var)
return(list(boundUp = drop(boundUp), boundLow = drop(boundLow)))
}
cal_mat_intervalPred <- function(vec_l, prob = 0.95, n, p, vec_y.hat, vec_var){
vec_boundUp <- numeric(length(vec_l))
vec_boundLow <- numeric(length(vec_l))
for (l in vec_l){
interval <- cal_vec_intervalPred(prob, n, p, y.hat = vec_y.hat[l], var = vec_var[l])
vec_boundUp[l] <- interval$boundUp
vec_boundLow[l] <- interval$boundLow
}
return(list(vec_boundUp = vec_boundUp, vec_boundLow = vec_boundLow))
}
cal_vec_memoryTotal <- function(lambda, n){
vec_memoryTotal <- numeric(n)
vec_memoryTotal[1] <- 1
for (j in 1: (n-1)){
vec_memoryTotal[j+1] <- vec_memoryTotal[j] + lambda^j
}
return(vec_memoryTotal)
}
Convergence of Total Memory of Local Trend Model
n_trendL_1_6h <- n_6h
lambda_trendL_1_6h <- 0.8
vec_memoryTotal_1_6h <- cal_vec_memoryTotal(lambda= lambda_trendL_1_6h, n = n_trendL_1_6h)
plot(seq(1, n_trendL_1_6h), vec_memoryTotal_1_6h, col = "blue",
main = paste("Convergence of Total Memory of Local Trend Model (", lambda_trendL_1_6h,
") using 6h-sampling Data"),
xlab = "Series", ylab = "Total Memory")

Define Functions for Linear Trend Model
Use a local linear trend model on the outdoor temperature in the 6h training data using lambda = 0.8.
y = theta0 + theta1 * j + epsilon
Plot the training data and the corresponding one step predictions for all observations in the training data.
func_f_linear <- function(j){
return(rbind(1, j))
}
pred_y_trend_linear <- function(l, vec_theta.hat_trend){
y_pred_trend <- t(func_f_linear(l)) %*% vec_theta.hat_trend
return(y_pred_trend)
}
pred_var_trend_linear <- function(l, mat_x_trend, vec_y_trend, vec_theta.hat_trend, mat_capSigma_trend){
sigma.hat <- cal_sigma.hat(mat_x = mat_x_trend, vec_y = vec_y_trend,
vec_theta.hat = vec_theta.hat_trend, mat_capSigma = mat_capSigma_trend)
mat_capF_trend_trend <- cal_mat_capF_trend(mat_x_trend, mat_capSigma_trend)
var_pred_trend <- sigma.hat^2 %*% (1 + t(func_f_linear(l)) %*% solve(mat_capF_trend_trend) %*% func_f_linear(l))
return(var_pred_trend)
}
pred_vec_y_trend_linear <- function(vec_l, vec_theta.hat_trend){
vec_y_trend_linear <- numeric(length(vec_l))
for (i in (1: length(vec_l))){
vec_y_trend_linear[i] <- pred_y_trend_linear(vec_l[i], vec_theta.hat_trend)
}
return(vec_y_trend_linear)
}
pred_vec_var_trend_linear <- function(vec_l, mat_x_trend, vec_y.pred_trend, vec_theta.hat_trend, mat_capSigma_trend){
vec_var_trend_linear <- numeric(length(vec_l))
for (i in (1: length(vec_l))){
vec_var_trend_linear[i] <- pred_var_trend_linear(vec_l[i], mat_x_trend,
vec_y.pred_trend[i], vec_theta.hat_trend, mat_capSigma_trend)
}
return(vec_var_trend_linear)
}
1.3.1.1 Estimation
Estimation
mat_capSigma_trendL_1_6h <- do_mat_capSigma_trend(lambda = lambda_trendL_1_6h, n = n_trendL_1_6h)
vec_y_trendL_1_6h <- dat.f_6h$tempExternal[1:n_6h]
seq_zdi_trendL_1_6h <- do_seq_zeroDecreaseRev(n_trendL_1_6h)
mat_x_trendL_1_6h <- cbind(1, seq_zdi_trendL_1_6h)
vec_theta.hat_trendL_1_6h <- cal_vec_theta.hat_trend(mat_x_trend = mat_x_trendL_1_6h,
mat_capSigma_trend = mat_capSigma_trendL_1_6h,
vec_y_trend = vec_y_trendL_1_6h)
cal_mat_capF_trend(mat_x_trend = mat_x_trendL_1_6h,
mat_capSigma_trend = mat_capSigma_trendL_1_6h)
seq_zdi_trendL_1_6h
4.998962 -19.95638
seq_zdi_trendL_1_6h -19.956385 178.14739
cal_vec_h_trend(mat_x_trend = mat_x_trendL_1_6h,
mat_capSigma_trend = mat_capSigma_trendL_1_6h,
vec_y_trend = vec_y_trendL_1_6h)
[,1]
9.437496
seq_zdi_trendL_1_6h -62.490852
sigma.hat_trendL_1_6h <- cal_sigma.hat(mat_x = mat_x_trendL_1_6h, vec_y = vec_y_trendL_1_6h,
vec_theta.hat = vec_theta.hat_trendL_1_6h,
mat_capSigma = mat_capSigma_trendL_1_6h)
mat_var.theta.hat_trendL_1_6h <- cal_mat_var.theta.hat(mat_x = mat_x_trendL_1_6h, sigma.hat = sigma.hat_trendL_1_6h,
mat_capSigma = mat_capSigma_trendL_1_6h)
1.3.1.2 Prediction
vec_y.hat_trendL_1_6h <- mat_x_trendL_1_6h %*% vec_theta.hat_trendL_1_6h
vec_l_trendL_1_6h <- c(1, 2, 3, 4)
vec_y.pred_trendL_1_6h <- pred_vec_y_trend_linear(vec_l = vec_l_trendL_1_6h,
vec_theta.hat_trend = vec_theta.hat_trendL_1_6h)
vec_var.pred_trendL_1_6h <- pred_vec_var_trend_linear(vec_l = vec_l_trendL_1_6h,
mat_x_trend = mat_x_trendL_1_6h,
mat_capSigma_trend = mat_capSigma_trendL_1_6h,
vec_y.pred_trend = vec_y.pred_trendL_1_6h,
vec_theta.hat_trend = vec_theta.hat_trendL_1_6h)
mat_intervaPred_trendL_1_6h <- cal_mat_intervalPred(vec_l = vec_l_trendL_1_6h, prob = 0.95,
n = n_trendL_1_6h, p = length(vec_theta.hat_trendL_1_6h),
vec_y.hat = vec_y.pred_trendL_1_6h,
vec_var = vec_var.pred_trendL_1_6h)
1.3.1.4
plot(dat.f_6h$series[1:n_6h], dat.f_6h$tempExternal[1:n_6h],
type = "b", col = "blue", lwd = 1, lty = 1, xlim = c(0, n_6h + 4), ylim = c(-4, 12),
main = paste("Prediction of External Temperature by Linear Local Trend Model (", lambda_trendL_1_6h,
") using 6h Data"),
xlab = "Series", ylab = "Celsius Degree")
points(n_trendL_1_6h + seq(4), dat.f_6h$tempExternal[(n_trendL_1_6h+1): (n_trendL_1_6h+4)],
type = "b", col = "blue", lty = 1, pch = 16)
lines(dat.f_6h$series[(n_6h):(n_6h+1)], dat.f_6h$tempExternal[(n_6h):(n_6h+1)],
type = "c", col = "blue", lty = 1)
legend("bottomleft", inset = .02, legend = c("Training Data", "Testing Data", "Trend Model",
"Prediction", "Pred Interval"),
col = c("blue", "blue", "red", "red", "red"), pch = c(1, 16, NA, 15, 6),
lty = c(1, 1, 2, 3, 1), lwd = c(1, 1, 3, 3, 1))
# Plot the validation result
lines(dat.f_6h$series[1:n_6h], vec_y.hat_trendL_1_6h,
type = "l", col = "red", lty = 2, lwd = 3)
# Plot the prediction result
points(n_trendL_1_6h + vec_l_trendL_1_6h, vec_y.pred_trendL_1_6h,
type = "b", col = "red", pch = 15, lty = 3, lwd = 2)
lines(n_trendL_1_6h + vec_l_trendL_1_6h, mat_intervaPred_trendL_1_6h$vec_boundUp,
type = "b", col = 'red', lwd = 1, lty = 1, pch = 6, cex= 0.5)
lines(n_trendL_1_6h + vec_l_trendL_1_6h, mat_intervaPred_trendL_1_6h$vec_boundLow,
type = "b", col = 'red', lwd = 1, lty = 1, pch = 2, cex= 0.5)

3.2, Quadratic Local Trend Model (lambda = 0.8) of 6h-sampling Data
y = theta0 + theta1 * j + theta2 * j^2/2 + epsilon
Define Functions for Quadratic Local Trend Model
func_f_quadratic <- function(j){
return(rbind(1, j, j^2 / 2))
}
pred_y_trend_quadratic <- function(l, vec_theta.hat_trend){
y_pred_trend <- t(func_f_quadratic(l)) %*% vec_theta.hat_trend
return(y_pred_trend)
}
pred_vec_y_trend_quadratic <- function(vec_l, vec_theta.hat_trend){
vec_y.pred_trend_quadratic <- numeric(length(vec_l))
for (i in seq(1, length(vec_l))){
vec_y.pred_trend_quadratic[i] <- pred_y_trend_quadratic(vec_l[i], vec_theta.hat_trend)
}
return(vec_y.pred_trend_quadratic)
}
pred_var_trend_quadratic <- function(l, mat_x_trend, vec_y_trend, vec_theta.hat_trend, mat_capSigma_trend){
sigma.hat <- cal_sigma.hat(mat_x = mat_x_trend, vec_y = vec_y_trend,
vec_theta.hat = vec_theta.hat_trend, mat_capSigma = mat_capSigma_trend)
mat_capF_trend_trend <- cal_mat_capF_trend(mat_x_trend, mat_capSigma_trend)
var.pred_trend <- sigma.hat^2 %*% (1 + t(func_f_quadratic(l)) %*% solve(mat_capF_trend_trend) %*% func_f_quadratic(l))
return(var.pred_trend)
}
pred_vec_var_trend_quadratic <- function(vec_l, mat_x_trend, vec_y.pred_trend, vec_theta.hat_trend, mat_capSigma_trend){
vec_var.pred_trend_quadratic <- numeric(length(vec_l))
for (i in seq(1, length(vec_l))){
vec_var.pred_trend_quadratic[i] <- pred_var_trend_quadratic(vec_l[i],
mat_x_trend,
vec_y.pred_trend[i],
vec_theta.hat_trend,
mat_capSigma_trend)
}
return(vec_var.pred_trend_quadratic)
}
n_trendL_2_6h <- n_6h
lambda_trendL_2_6h <- 0.8
mat_capSigma_trendL_2_6h <- do_mat_capSigma_trend(lambda = lambda_trendL_2_6h, n = n_trendL_2_6h)
vec_y_trendL_2_6h <- dat.f_6h$tempExternal[1: n_trendL_2_6h]
seq_zdi_trendL_2_6h <- do_seq_zeroDecreaseRev(n_trendL_2_6h)
mat_x_trendL_2_6h <- cbind(1, seq_zdi_trendL_2_6h, seq_zdi_trendL_2_6h^2 / 2)
vec_theta.hat_trendL_2_6h <- cal_vec_theta.hat_trend(mat_x_trend = mat_x_trendL_2_6h,
mat_capSigma_trend = mat_capSigma_trendL_2_6h,
vec_y_trend = vec_y_trendL_2_6h)
sigma.hat_trendL_2_6h <- cal_sigma.hat(mat_x = mat_x_trendL_2_6h, vec_y = vec_y_trendL_2_6h,
vec_theta.hat = vec_theta.hat_trendL_2_6h,
mat_capSigma = mat_capSigma_trendL_2_6h)
mat_var.theta.hat_trendL_2_6h <- cal_mat_var.theta.hat(mat_x = mat_x_trendL_2_6h, sigma.hat = sigma.hat_trendL_2_6h,
mat_capSigma = mat_capSigma_trendL_2_6h)
Validate
vec_y.hat_trendL_2_6h <- mat_x_trendL_2_6h %*% vec_theta.hat_trendL_2_6h
vec_sse.hat_trendL_2_6h <- cal_vec_sse.hat(mat_x = mat_x_trendL_2_6h,
vec_y = vec_y_trendL_2_6h,
vec_theta.hat = vec_theta.hat_trendL_2_6h,
mat_capSigma = mat_capSigma_trendL_2_6h)
mat_intervaConf_trendL_2_6h <- cal_mat_intervalConf(prob = 0.95,
mat_x = mat_x_trendL_2_6h,
vec_theta.hat = vec_theta.hat_trendL_2_6h,
vec_y = vec_y_trendL_2_6h)
Predict
vec_l_trendL_2_6h <- c(1, 2, 3, 4)
vec_y.pred_trendL_2_6h <- pred_vec_y_trend_quadratic(vec_l = vec_l_trendL_2_6h,
vec_theta.hat_trend = vec_theta.hat_trendL_2_6h)
vec_var.pred_trendL_2_6h <- pred_vec_var_trend_quadratic(vec_l = vec_l_trendL_2_6h,
mat_x_trend = mat_x_trendL_2_6h,
mat_capSigma_trend = mat_capSigma_trendL_2_6h,
vec_y.pred_trend = vec_y.pred_trendL_2_6h,
vec_theta.hat_trend = vec_theta.hat_trendL_2_6h)
mat_intervaPred_trendL_2_6h <- cal_mat_intervalPred(vec_l = vec_l_trendL_2_6h, prob = 0.95,
n = n_trendL_2_6h, p = length(vec_theta.hat_trendL_2_6h),
vec_y.hat = vec_y.pred_trendL_2_6h,
vec_var = vec_var.pred_trendL_2_6h)
plot(dat.f_6h$series[1:n_6h], dat.f_6h$tempExternal[1:n_6h],
type = "b", col = "blue", lwd = 1, lty = 1, xlim = c(0, n_6h + 4), ylim = c(-4, 12),
main = paste("Prediction of External Temperature by Quadratic Local Trend Model (", lambda_trendL_2_6h,
") using 6h Data"),
xlab = "Series", ylab = "Celsius Degree")
points(n_trendL_2_6h + seq(4), dat.f_6h$tempExternal[(n_trendL_2_6h+1): (n_trendL_2_6h+4)],
type = "b", col = "blue", lty = 1, pch = 16)
lines(dat.f_6h$series[(n_6h):(n_6h+1)], dat.f_6h$tempExternal[(n_6h):(n_6h+1)],
type = "c", col = "blue", lty = 1)
# Plot the validation result
lines(dat.f_6h$series[1:n_6h], vec_y.hat_trendL_2_6h, type = "l", col = "red", lty = 2, lwd = 3)
# lines(dat.f_6h$series[1:n_6h], mat_intervaConf_trendL_2_6h$vec_boundUp, type = 'l', col = "red", lty = 3, lwd = 2)
# lines(dat.f_6h$series[1:n_6h], mat_intervaConf_trendL_2_6h$vec_boundLow, type = 'l', col = "red", lty = 3, lwd = 2)
# Plot the prediction result
points(n_trendL_2_6h + vec_l_trendL_2_6h, vec_y.pred_trendL_2_6h,
type = "b", col = "red", pch = 15, lty = 3, lwd = 2)
lines(n_trendL_2_6h + vec_l_trendL_2_6h, mat_intervaPred_trendL_2_6h$vec_boundUp,
type = "b", col = 'red', lwd = 1, lty = 1, pch = 6, cex= 0.5)
lines(n_trendL_2_6h + vec_l_trendL_2_6h, mat_intervaPred_trendL_2_6h$vec_boundLow,
type = "b", col = 'red', lwd = 1, lty = 1, pch = 2, cex= 0.5)
legend("bottomleft", inset = .02, legend = c("Training Data", "Testing Data", "Trend Model",
"Prediction", "Pred Interval"),
col = c("blue", "blue", "red", "red", "red"), pch = c(1, 16, NA, 15, 6),
lty = c(1, 1, 2, 3, 1), lwd = c(1, 1, 3, 3, 1))

Question 4
Trend Component of Solar Irradiation
library(forecast)
ts_trend_iSolar = ma(dat.f_6h$iSolar[1: n_6h], order = 4, centre = T)
plot(dat.f_6h$series[1: n_6h], dat.f_6h$iSolar[1: n_6h], type = "l", col = "blue", lty = 1, lwd = 2,
main = "Trend Component of Solar Irradiation", xlab = "Series", ylab = "W / m2")
lines(dat.f_6h$series[1: n_6h], ts_trend_iSolar, col = "red", lty = 2, lwd = 2)

ts_detrend_iSolar = dat.f_6h$iSolar[1: n_6h] / ts_trend_iSolar
plot(dat.f_6h$series[1: n_6h], ts_detrend_iSolar, type = "l", col = "blue", lty = 1, lwd = 2,
main = "Seasonal Component of Solar Irradiation", xlab = "Series", ylab = "W / m2")

mat_iSolar = t(matrix(data = ts_detrend_iSolar, nrow = 4))
vec_season_iSolar = colMeans(mat_iSolar, na.rm = T)
plot(rep(vec_season_iSolar, 9), type = "l", col = "blue", lty = 1, lwd = 2,
main = "Averaged Seasonal Component of Solar Irradiation", xlab = "Series", ylab = "W / m2")

ts_epsilon_iSolar = dat.f_6h$iSolar[1: n_6h] / (ts_trend_iSolar * vec_season_iSolar)
plot(ts_epsilon_iSolar, type = "l", col = "blue", lty = 1, lwd = 2,
main = "Epsilon Component of Solar Irradiation", xlab = "Series", ylab = "W / m2")

ts_recomposed_iSolar = ts_trend_iSolar * vec_season_iSolar * ts_epsilon_iSolar
plot(dat.f_6h$series[1: n_6h], ts_recomposed_iSolar, type = "l", col = "red", lty = 2, lwd = 3,
main = "Recomposed Solar Irradiation and Original Data", xlab = "Series", ylab = "W / m2")
lines(dat.f_6h$series[1: n_6h], dat.f_6h$iSolar[1: n_6h], col = "blue", lty = 1, lwd = 1)

Predict the solar irradiation in the last day
n_trendL_3_6h <- n_6h - 4
lambda_trendL_3_6h <- 0.8
mat_capSigma_trendL_3_6h <- do_mat_capSigma_trend(lambda = lambda_trendL_3_6h, n = n_trendL_3_6h)
vec_y_trendL_3_6h <- as.numeric(ts_trend_iSolar)[3: 36]
seq_zdi_trendL_3_6h <- do_seq_zeroDecreaseRev(n_trendL_3_6h)
mat_x_trendL_3_6h <- cbind(1, seq_zdi_trendL_3_6h, seq_zdi_trendL_3_6h^2 / 2)
vec_theta.hat_trendL_3_6h <- cal_vec_theta.hat_trend(mat_x_trend = mat_x_trendL_3_6h,
mat_capSigma_trend = mat_capSigma_trendL_3_6h,
vec_y_trend = vec_y_trendL_3_6h)
sigma.hat_trendL_3_6h <- cal_sigma.hat(mat_x = mat_x_trendL_3_6h,
vec_y = vec_y_trendL_3_6h,
vec_theta.hat = vec_theta.hat_trendL_3_6h,
mat_capSigma = mat_capSigma_trendL_3_6h)
mat_var.theta.hat_trendL_3_6h <- cal_mat_var.theta.hat(mat_x = mat_x_trendL_3_6h,
sigma.hat = sigma.hat_trendL_3_6h,
mat_capSigma = mat_capSigma_trendL_3_6h)
vec_y.hat_trendL_3_6h <- mat_x_trendL_3_6h %*% vec_theta.hat_trendL_3_6h
vec_l_trendL_3_6h <- c(3, 4, 5, 6)
vec_y.pred_trendL_3_6h <- pred_vec_y_trend_quadratic(vec_l = vec_l_trendL_3_6h,
vec_theta.hat_trend = vec_theta.hat_trendL_3_6h)
vec_y.pred_trendL_3_6h[1] <- vec_y.pred_trendL_3_6h[1] * vec_season_iSolar[3]
vec_y.pred_trendL_3_6h[2] <- vec_y.pred_trendL_3_6h[2] * vec_season_iSolar[4]
vec_y.pred_trendL_3_6h[3] <- vec_y.pred_trendL_3_6h[3] * vec_season_iSolar[1]
vec_y.pred_trendL_3_6h[4] <- vec_y.pred_trendL_3_6h[4] * vec_season_iSolar[2]
vec_var.pred_trendL_3_6h <- pred_vec_var_trend_quadratic(vec_l = vec_l_trendL_3_6h,
mat_x_trend = mat_x_trendL_3_6h,
mat_capSigma_trend = mat_capSigma_trendL_3_6h,
vec_y.pred_trend = vec_y.pred_trendL_3_6h,
vec_theta.hat_trend = vec_theta.hat_trendL_3_6h)
mat_intervaPred_trendL_3_6h <- cal_mat_intervalPred(vec_l = vec_l_trendL_3_6h,
prob = 0.95,
n = n_trendL_3_6h,
p = length(vec_theta.hat_trendL_3_6h),
vec_y.hat = vec_y.pred_trendL_3_6h,
vec_var = vec_var.pred_trendL_3_6h)
mat_intervaPred_trendL_3_6h$vec_boundUp[1] <- mat_intervaPred_trendL_3_6h$vec_boundUp[1] * vec_season_iSolar[3]
mat_intervaPred_trendL_3_6h$vec_boundUp[2] <- mat_intervaPred_trendL_3_6h$vec_boundUp[2] * vec_season_iSolar[4]
mat_intervaPred_trendL_3_6h$vec_boundUp[3] <- mat_intervaPred_trendL_3_6h$vec_boundUp[3] * vec_season_iSolar[1]
mat_intervaPred_trendL_3_6h$vec_boundUp[4] <- mat_intervaPred_trendL_3_6h$vec_boundUp[4] * vec_season_iSolar[2]
mat_intervaPred_trendL_3_6h$vec_boundLow[1] <- mat_intervaPred_trendL_3_6h$vec_boundLow[1] * vec_season_iSolar[3]
mat_intervaPred_trendL_3_6h$vec_boundLow[2] <- mat_intervaPred_trendL_3_6h$vec_boundLow[2] * vec_season_iSolar[4]
mat_intervaPred_trendL_3_6h$vec_boundLow[3] <- mat_intervaPred_trendL_3_6h$vec_boundLow[3] * vec_season_iSolar[1]
mat_intervaPred_trendL_3_6h$vec_boundLow[4] <- mat_intervaPred_trendL_3_6h$vec_boundLow[4] * vec_season_iSolar[2]
plot(dat.f_6h$series[1:n_6h], dat.f_6h$iSolar[1:n_6h],
type = "b", col = "blue", lwd = 1, lty = 1, xlim = c(0, 42), ylim = c(0, 400),
main = paste("Prediction of Solar Irradiation by Seasonal Local Trend Model (", lambda_trendL_3_6h,
") using 6h-sampling Data"),
xlab = "Series", ylab = "Celsius Degree")
lines(dat.f_6h$series[(n_6h+1):(n_6h+4)], dat.f_6h$iSolar[(n_6h+1):(n_6h+4)],
type = "b", col = "blue", lwd = 1, lty = 1, pch = 16)
lines(dat.f_6h$series[(n_6h):(n_6h+1)], dat.f_6h$iSolar[(n_6h):(n_6h+1)],
type = "c", col = "blue", lwd = 1, lty = 1)
# Plot the Validation Result
lines(dat.f_6h$series[3: (n_6h-2)], vec_y.hat_trendL_3_6h,
type = "l", col = "red", lty = 2, lwd = 3)
# lines(ts_trend_iSolar * vec_season_iSolar, col = 'red', lty = 3, lwd = 2)
# Plot the prediction Result
lines(2 + n_trendL_3_6h + vec_l_trendL_3_6h, vec_y.pred_trendL_3_6h,
type = "b", col = "red", pch = 15, lty = 3, lwd = 3)
points(2 + n_trendL_3_6h + vec_l_trendL_3_6h, mat_intervaPred_trendL_3_6h$vec_boundUp, col = 'red', pch = 6, cex= 0.5)
points(2 + n_trendL_3_6h + vec_l_trendL_3_6h, mat_intervaPred_trendL_3_6h$vec_boundLow, col = 'red', pch = 2, cex= 0.5)
legend("topleft", inset = .02, legend = c("Training Data", "Testing Data", "Trend Compo", "Prediction", "Pred Interval"),
col = c("blue", "blue", "red", "red", "red"), pch = c(1, 16, NA, 15, 6),
lty = c(1, 1, 2, 3, 1), lwd = c(1, 1, 3, 3, 1), cex = 0.8)

Predict the observations for the last day (test data) of the spatial heating based on the 6h data. For this, use the estimated model in question 1.2 and the outdoor temperature from question 1.3.
mat_x.pred_2_6h <- cbind(rep(1, 4), vec_y.pred_trendL_2_6h, vec_y.pred_trendL_3_6h)
vec_y.pred_2_6h <- mat_x.pred_2_6h %*% vec_theta.hat_expDecay_6h
plot(dat.f_6h$series[1:(n_6h)], dat.f_6h$heating[1:(n_6h)],
type = "b", col = "blue", lwd = 1, lty = 1, xlim = c(0, 42),
main = "Predicted Heating in the last Day using 6h Data", xlab = "Series", ylab = "W")
lines(dat.f_6h$series[(n_6h+1):(n_6h+4)], dat.f_6h$heating[(n_6h+1):(n_6h+4)],
type = "b", col = "blue", lty = 1, pch = 16)
lines(dat.f_6h$series[(n_6h):(n_6h+1)], dat.f_6h$heating[(n_6h):(n_6h+1)],
type = "c", col = "blue", lty = 1)
legend("topleft", inset = .02, legend = c("Training Data", "Testing Data", "Prediction"), col = c("blue", "blue", "red"),
pch = c(1, 16, 15), lty = c(1, 1, 3), lwd = c(1, 1, 2), cex = 0.8)
# Plot the prediction result
lines(dat.f_6h$series[(n_6h+1):(n_6h+4)], vec_y.pred_2_6h,
type = "b", col = "red", pch = 15, lty = 3, lwd = 2)

Appendix
# Calculate the capF and h in scalar way
func_capF_linear <- function(n, lambda){
all <- 0
for (j in 0: (n-1)){
all <- all + func_f_linear(-j) %*% t(func_f_linear(-j))
}
return(all)
}
func_h_linear <- function(n, lambda, vec_y){
all <- 0
for (j in 0: (n-1)){
all <- all + func_f_linear(-j) %*% vec_y
}
return(all)
}
cal_mat_intervalConf <- function(prob = 0.95, mat_x, vec_theta.hat, sse.hat){
n <- length(mat_x[,1])
p <- length(vec_theta.hat)
quantileStudentDist <- qt(p = prob, df = n - p)
vec_boundUp <- mat_x %*% vec_theta.hat + rep(quantileStudentDist * sqrt(sse.hat / n), n)
vec_boundLow <- mat_x %*% vec_theta.hat - rep(quantileStudentDist * sqrt(sse.hat / n), n)
return(list(vec_boundUp = vec_boundUp, vec_boundLow = vec_boundLow))
}
LS0tCnRpdGxlOiAiZHR1MDI0MTdhMTogU3RlYWR5IFN0YXRlIEJ1aWxkaW5nIE1vZGVsIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKYXV0aG9yOiBFZHdhcmQgSi4gWHUgKEppZSBYdSksIHMxODEyMzgKZGF0ZTogMTF0aCBNYXJjaCwgMjAxOQotLS0KCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQojIENsZWFyIHZhcmlhYmxlcwpybShsaXN0PWxzKCkpCmxpYnJhcnkoa25pdHIpCmBgYAoKIyBRdWVzdGlvbiAxLjEKClJlYWQgdGhlIDNoIGFuZCB0aGUgNmggZGF0YSBhbmQgcGxvdCB0aGUgZ2l2ZW4gcXVhbnRpdGllcyBhcyBhIGZ1bmN0aW9uIG9mIHRpbWUuIERvIGluZGljYXRlIHdoaWNoIGRhdGEgaXMgdXNlZCBmb3IgdHJhaW5pbmcgYW5kIHRlc3RpbmcuIENvbW1lbnQgb24gdGhlIGV2b2x1dGlvbiBvZiB0aGUgdmFsdWVzIG92ZXIgdGltZS4gSXQgaXMgT0sgaWYgdGhlIHBsb3QgaXMgY29tYmluZWQgd2l0aCByZXN1bHRzIGZyb20gdGhlIGZvbGxvd2luZyBxdWVzdGlvbnMuCgpgYGB7ciwgd2FybmluZz1GQUxTRX0KZGF0XzNoIDwtIHJlYWQuY3N2KCJob3VzZV9kYXRhXzNoLmNzdiIpCnRpbWUgPC0gZGF0XzNoWyAsIDFdCmhlYXRpbmcgPC0gZGF0XzNoWyAsIDJdCnRlbXBFeHRlcm5hbCA8LSBkYXRfM2hbICwgM10KaVNvbGFyIDwtIGRhdF8zaFsgLCA0XQpzZXJpZXMgPC0gc2VxKDEsIGxlbmd0aCh0aW1lKSkKZGF0LmZfM2ggPC0gZGF0YS5mcmFtZShzZXJpZXMsIHRpbWUsIGhlYXRpbmcsIHRlbXBFeHRlcm5hbCwgaVNvbGFyKQpuXzNoIDwtIGxlbmd0aChkYXQuZl8zaCRzZXJpZXMpIC0gOApgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gMTAsIHdhcm5pbmc9RkFMU0V9CnBsb3QoZGF0LmZfM2gkc2VyaWVzLCBkYXQuZl8zaCRoZWF0aW5nLCAKICAgICB0eXBlID0gImIiLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIsIGx0eSA9IDEsIGNleCA9IDAuOCwKICAgICBtYWluID0gIlRyYWluaW5nIGFuZCBUZXN0aW5nIERhdGEgb2YgSGVhdGluZyBpbiAzaCBEYXRhIiwgeGxhYiA9ICJTZXJpZXMiLCB5bGFiID0gIlciKQpwb2ludHMoZGF0LmZfM2gkc2VyaWVzWyhuXzNoKzEpOihuXzNoKzgpXSwgZGF0LmZfM2gkaGVhdGluZ1sobl8zaCsxKToobl8zaCs4KV0sIAogICAgICAgY29sID0gImJsdWUiLCBsdHkgPSAxLCBwY2ggPSAxNiwgY2V4ID0gMC44KQpsZWdlbmQoInRvcGxlZnQiLCBpbnNldCA9IC4wMiwgbGVnZW5kID0gYygiVHJhaW5pbmcgRGF0YSIsICJUZXN0aW5nIERhdGEiKSwgY29sID0gYygiYmx1ZSIsICJibHVlIiksIAogICAgICAgcGNoID0gYygxLCAxNiksIGx0eSA9IGMoMSwgMSksIGx3ZCA9IGMoMiwgMikpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQgPSA1LCBmaWcud2lkdGggPSAxMH0KcGxvdChkYXQuZl8zaCRzZXJpZXMsIGRhdC5mXzNoJHRlbXBFeHRlcm5hbCwgCiAgICAgdHlwZSA9ICJiIiwgY29sID0gImJsdWUiLCBsd2QgPSAyLCBsdHkgPSAxLCBjZXggPSAwLjgsCiAgICAgbWFpbiA9ICJUcmFpbmluZyBhbmQgVGVzdGluZyBEYXRhIG9mIEV4dGVybmFsIFRlbXBlcmF0dXJlIGluIDNoIERhdGEiLCB4bGFiID0gIlNlcmllcyIsIHlsYWIgPSAiQ2Vsc2l1cyBEZWdyZWUiKQpwb2ludHMoZGF0LmZfM2gkc2VyaWVzWyhuXzNoKzEpOihuXzNoKzgpXSwgZGF0LmZfM2gkdGVtcEV4dGVybmFsWyhuXzNoKzEpOihuXzNoKzgpXSwgCiAgICAgICBjb2wgPSAiYmx1ZSIsIGx0eSA9IDEsIHBjaCA9IDE2LCBjZXggPSAwLjgpCmxlZ2VuZCgiYm90dG9tbGVmdCIsIGluc2V0ID0gLjAyLCBsZWdlbmQgPSBjKCJUcmFpbmluZyBEYXRhIiwgIlRlc3RpbmcgRGF0YSIpLCBjb2wgPSBjKCJibHVlIiwgImJsdWUiKSwgCiAgICAgICBwY2ggPSBjKDEsIDE2KSwgbHR5ID0gYygxLCAxKSwgbHdkID0gYygyLCAyKSkKYGBgCgpgYGB7ciwgd2FybmluZz1GQUxTRSwgZmlnLmhlaWdodCA9IDUsIGZpZy53aWR0aCA9IDEwfQpwbG90KGRhdC5mXzNoJHNlcmllcywgZGF0LmZfM2gkaVNvbGFyLCAKICAgICB0eXBlID0gImIiLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIsIGx0eSA9IDEsIGNleCA9IDAuOCwgCiAgICAgbWFpbiA9ICJUcmFpbmluZyBhbmQgVGVzdGluZyBEYXRhIG9mIFNvbGFyIElycmFkaWF0aW9uIGluIDNoIERhdGEiLCB4bGFiID0gIlNlcmllcyIsIHlsYWIgPSAiVyAvIG0yIikKcG9pbnRzKGRhdC5mXzNoJHNlcmllc1sobl8zaCsxKToobl8zaCs4KV0sIGRhdC5mXzNoJGlTb2xhclsobl8zaCsxKToobl8zaCs4KV0sIAogICAgICAgY29sID0gImJsdWUiLCBsdHkgPSAxLCBwY2ggPSAxNiwgY2V4ID0gMC44KQpsZWdlbmQoInRvcGxlZnQiLCBpbnNldCA9IC4wMiwgbGVnZW5kID0gYygiVHJhaW5pbmcgRGF0YSIsICJUZXN0aW5nIERhdGEiKSwgY29sID0gYygiYmx1ZSIsICJibHVlIiksIAogICAgICAgcGNoID0gYygxLCAxNiksIGx0eSA9IGMoMSwgMSksIGx3ZCA9IGMoMiwgMikpCmBgYAoKYGBge3IsIHdhcm5pbmc9RkFMU0V9CmRhdF82aCA8LSByZWFkLmNzdigiaG91c2VfZGF0YV82aC5jc3YiKQp0aW1lIDwtIGRhdF82aFsgLCAxXQpoZWF0aW5nIDwtIGRhdF82aFsgLCAyXQp0ZW1wRXh0ZXJuYWwgPC0gZGF0XzZoWywgM10KaVNvbGFyIDwtIGRhdF82aFsgLCA0XQpzZXJpZXMgPC0gc2VxKDEsIGxlbmd0aCh0aW1lKSkKZGF0LmZfNmggPC0gZGF0YS5mcmFtZShzZXJpZXMsIHRpbWUsIGhlYXRpbmcsIHRlbXBFeHRlcm5hbCwgaVNvbGFyKQpuXzZoIDwtIGxlbmd0aChkYXQuZl82aCRzZXJpZXMpIC0gNApgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gMTB9CnBsb3QoZGF0LmZfNmgkc2VyaWVzLCBkYXQuZl82aCRoZWF0aW5nLAogICAgIHR5cGUgPSAiYiIsIGNvbCA9ICJibHVlIiwgbHdkID0gMiwgbHR5ID0gMSwgY2V4ID0gMC44LCAKICAgICBtYWluID0gIlRyYWluaW5nIGFuZCBUZXN0aW5nIERhdGEgb2YgSGVhdGluZyBpbiA2aCBEYXRhIiwgeGxhYiA9ICJTZXJpZXMiLCB5bGFiID0gIlciKQpwb2ludHMoZGF0LmZfNmgkc2VyaWVzWyhuXzZoKzEpOihuXzZoKzgpXSwgZGF0LmZfNmgkaGVhdGluZ1sobl82aCsxKToobl82aCs4KV0sIAogICAgICAgY29sID0gImJsdWUiLCBsdHkgPSAxLCBwY2ggPSAxNiwgY2V4ID0gMC44KQpsZWdlbmQoInRvcGxlZnQiLCBpbnNldCA9IC4wMiwgbGVnZW5kID0gYygiVHJhaW5pbmcgRGF0YSIsICJUZXN0aW5nIERhdGEiKSwgY29sID0gYygiYmx1ZSIsICJibHVlIiksIAogICAgICAgcGNoID0gYygxLCAxNiksIGx0eSA9IGMoMSwgMSksIGx3ZCA9IGMoMiwgMikpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQgPSA1LCBmaWcud2lkdGggPSAxMH0KcGxvdChkYXQuZl82aCRzZXJpZXMsIGRhdC5mXzZoJHRlbXBFeHRlcm5hbCwgCiAgICAgdHlwZSA9ICJiIiwgY29sID0gImJsdWUiLCBsd2QgPSAyLCBsdHkgPSAxLCBjZXggPSAwLjgsIAogICAgIG1haW4gPSAiVHJhaW5pbmcgYW5kIFRlc3RpbmcgRGF0YSBvZiBFeHRlcm5hbCBUZW1wZXJhdHVyZSBpbiA2aCBEYXRhIiwgeGxhYiA9ICJTZXJpZXMiLCB5bGFiID0gIkNlbHNpdXMgRGVncmVlIikKcG9pbnRzKGRhdC5mXzZoJHNlcmllc1sobl82aCsxKToobl82aCs4KV0sIGRhdC5mXzZoJHRlbXBFeHRlcm5hbFsobl82aCsxKToobl82aCs4KV0sIAogICAgICAgY29sID0gImJsdWUiLCBsdHkgPSAxLCBwY2ggPSAxNiwgY2V4ID0gMC44KQpsZWdlbmQoImJvdHRvbWxlZnQiLCBpbnNldCA9IC4wMiwgbGVnZW5kID0gYygiVHJhaW5pbmcgRGF0YSIsICJUZXN0aW5nIERhdGEiKSwgY29sID0gYygiYmx1ZSIsICJibHVlIiksIAogICAgICAgcGNoID0gYygxLCAxNiksIGx0eSA9IGMoMSwgMSksIGx3ZCA9IGMoMiwgMikpCmBgYAoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIGZpZy5oZWlnaHQgPSA1LCBmaWcud2lkdGggPSAxMH0KcGxvdChkYXQuZl82aCRzZXJpZXMsIGRhdC5mXzZoJGlTb2xhciwgCiAgICAgdHlwZSA9ICJiIiwgY29sID0gImJsdWUiLCBsd2QgPSAyLCBsdHkgPSAxLCBjZXggPSAwLjgsIAogICAgIG1haW4gPSAiVHJhaW5pbmcgYW5kIFRlc3RpbmcgRGF0YSBvZiBTb2xhciBJcnJhZGlhdGlvbiBpbiA2aCBEYXRhIiwgeGxhYiA9ICJTZXJpZXMiLCB5bGFiID0gIlcgLyBtMiIpCnBvaW50cyhkYXQuZl82aCRzZXJpZXNbKG5fNmgrMSk6KG5fNmgrOCldLCBkYXQuZl82aCRpU29sYXJbKG5fNmgrMSk6KG5fNmgrOCldLCAKICAgICAgIGNvbCA9ICJibHVlIiwgbHR5ID0gMSwgcGNoID0gMTYsIGNleCA9IDAuOCkKbGVnZW5kKCJ0b3BsZWZ0IiwgaW5zZXQgPSAuMDIsIGxlZ2VuZCA9IGMoIlRyYWluaW5nIERhdGEiLCAiVGVzdGluZyBEYXRhIiksIGNvbCA9IGMoImJsdWUiLCAiYmx1ZSIpLCAKICAgICAgIHBjaCA9IGMoMSwgMTYpLCBsdHkgPSBjKDEsIDEpLCBsd2QgPSBjKDIsIDIpKQpgYGAKCiMgUXVlc3Rpb24gMS4yCgpUaGUgb2JzZXJ2YXRpb25zIGluIHRoZSBsYXN0IDI0IGhvdXJzIGFyZSBrZXB0IG9ubHkgZm9yIGNvbXBhcmlzb25zLCBzbyB0aGV5IGFyZSBub3QgaW4gdGhlIHRyYWluaW5nIGRhdGEgc2V0LgoKIyMgRGVmaW5lIGZ1bmN0aW9ucyBmb3IgR2VuZXJhbCBMaW5lYXIgTW9kZWwgKEdMTSkKCmBgYHtyfQpjYWxfdmVjX3NzZS5oYXQgPC0gZnVuY3Rpb24obWF0X3gsIHZlY195LCB2ZWNfdGhldGEuaGF0LCBtYXRfY2FwU2lnbWEgPSBkaWFnKGxlbmd0aChtYXRfeFssMV0pKSl7CiAgICAjIENhbGN1bGF0ZSB0aGUgc3VtIG9mIHNxdWFyZWQgZXJyb3IgKHNzZSksIGVxLgogICAgdmVjX2Vwc2lsb24gPC0gdmVjX3kgLSBtYXRfeCAlKiUgdmVjX3RoZXRhLmhhdAogICAgc3NlLmhhdCA8LSB0KHZlY19lcHNpbG9uKSAlKiUgc29sdmUobWF0X2NhcFNpZ21hKSAlKiUgdmVjX2Vwc2lsb24KICAgIHJldHVybihzc2UuaGF0KQp9CmNhbF9zaWdtYS5oYXQgPC0gZnVuY3Rpb24obWF0X3gsIHZlY195LCB2ZWNfdGhldGEuaGF0LCBtYXRfY2FwU2lnbWEgPSBkaWFnKGxlbmd0aChtYXRfeFssMV0pKSl7CiAgICAjIEVzdGltYXRvciBmb3IgdGhlIHZhcmlhbmNlLCBlcSAzLjQ0LCBUaGVvcmVtIDMuNCwgUDM5CiAgICBzaWdtYS5oYXQuc3F1YXJlIDwtIGNhbF92ZWNfc3NlLmhhdChtYXRfeCwgdmVjX3ksIHZlY190aGV0YS5oYXQsIG1hdF9jYXBTaWdtYSkgLwogICAgICAgICAgICAgICAgICAgICAgICAobGVuZ3RoKG1hdF94WywxXSkgLSBsZW5ndGgodmVjX3RoZXRhLmhhdCkpCiAgICBzaWdtYS5oYXQgPC0gc3FydChkcm9wKHNpZ21hLmhhdC5zcXVhcmUpKQogICAgcmV0dXJuKHNpZ21hLmhhdCkKfQpjYWxfbWF0X3Zhci50aGV0YS5oYXQgPC0gZnVuY3Rpb24obWF0X3gsIHNpZ21hLmhhdCwgbWF0X2NhcFNpZ21hPSBkaWFnKGxlbmd0aChtYXRfeFssMV0pKSl7CiAgICAjIENhbGN1bGF0ZSB0aGUgdmFyaWFuY2Ugb2YgdmVjX3RoZXRhLmhhdCwgZXEgMy40MywgUDM5CiAgICBtYXRfdmFyLnRoZXRhLmhhdCA8LSBzaWdtYS5oYXReMiAqIHNvbHZlKHQobWF0X3gpICUqJSBzb2x2ZShtYXRfY2FwU2lnbWEpICUqJSBtYXRfeCkKICAgIHJldHVybihkcm9wKG1hdF92YXIudGhldGEuaGF0KSkKfQpjYWxfbWF0X2ludGVydmFsQ29uZiA8LSBmdW5jdGlvbihwcm9iID0gMC45NSwgbWF0X3gsIHZlY190aGV0YS5oYXQsIHZlY195KXsKICAgIG4gPC0gbGVuZ3RoKG1hdF94WywxXSkKICAgIHAgPC0gbGVuZ3RoKHZlY190aGV0YS5oYXQpCiAgICBxdWFudGlsZVN0dWRlbnREaXN0IDwtIHF0KHAgPSBwcm9iLCBkZiA9IG4gLSBwKQogICAgdmVjX3Zhci55LmhhdCA8LSAodmVjX3kgLSBtYXRfeCAlKiUgdmVjX3RoZXRhLmhhdCleMgogICAgdmVjX2JvdW5kVXAgPC0gbWF0X3ggJSolIHZlY190aGV0YS5oYXQgKyBxdWFudGlsZVN0dWRlbnREaXN0ICogc3FydCh2ZWNfdmFyLnkuaGF0IC8gbikKICAgIHZlY19ib3VuZExvdyA8LSBtYXRfeCAlKiUgdmVjX3RoZXRhLmhhdCAtIHF1YW50aWxlU3R1ZGVudERpc3QgKiBzcXJ0KHZlY192YXIueS5oYXQgLyBuKQogICAgcmV0dXJuKGxpc3QodmVjX2JvdW5kVXAgPSB2ZWNfYm91bmRVcCwgdmVjX2JvdW5kTG93ID0gdmVjX2JvdW5kTG93KSkKfQpgYGAKCiMjIERlZmluZSBmdW5jdGlvbnMgb2Ygd2VpZ2h0ZWQgbGVhc3Qgc3F1YXJlIGVzdGltYXRpb24sIHdpdGggZGVmYXVsdCAibWF0X2NhcFNpZ21hIiBiZWluZyBpZGVudGl0eSBtYXRyaXguCgpgYGB7cn0KcHJlZF92ZWNfdGhldGEuaGF0IDwtIGZ1bmN0aW9uKG1hdF94LCB2ZWNfeSwgbWF0X2NhcFNpZ21hID0gZGlhZyhsZW5ndGgobWF0X3hbLDFdKSkpewogICAgdmVjX3RoZXRhLmhhdCA8LSBzb2x2ZSh0KG1hdF94KSAlKiUgc29sdmUobWF0X2NhcFNpZ21hKSAlKiUgbWF0X3gpICUqJSB0KG1hdF94KSAlKiUgc29sdmUobWF0X2NhcFNpZ21hKSAlKiUgdmVjX3kKICAgIHJldHVybih2ZWNfdGhldGEuaGF0KQp9CmBgYAoKIyMgMS4yLjEKCkZvcm11bGF0ZSBhIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIHRvIGVzdGltYXRlIHRoZXRhLCBpbiB3aGljaCBpdCBpcyBhc3N1bWVkIHRoYXQgdGhlIHJlc2lkdWFscyBoYXZlIGEgY29uc3RhbnQgdmFyaWFuY2UgYW5kIGFyZSBpbmRlcGVuZGVudC4gRXN0aW1hdGUgdGhlIHBhcmFtZXRlcnMgdXNpbmcgdGhlIDZoIGRhdGEgYW5kIGluY2x1ZGUgYSBtZWFzdXJlIG9mIHVuY2VydGFpbnR5IGZvciBlYWNoIG9mIHRoZSBlc3RpbWF0ZXMuIAoKYGBge3IsIHdhcm5pbmc9RkFMU0V9Cm1hdF94XzZoIDwtIGNiaW5kKDEsIGRhdC5mXzZoJHRlbXBFeHRlcm5hbFsxOm5fNmhdLCBkYXQuZl82aCRpU29sYXJbMTpuXzZoXSkKdmVjX3lfNmggPC0gZGF0LmZfNmgkaGVhdGluZ1sxOm5fNmhdCnZlY190aGV0YS5oYXRfb2xzXzZoIDwtIHByZWRfdmVjX3RoZXRhLmhhdChtYXRfeCA9IG1hdF94XzZoLCB2ZWNfeSA9IHZlY195XzZoKQpzaWdtYS5oYXRfb2xzXzZoIDwtIGNhbF9zaWdtYS5oYXQobWF0X3ggPSBtYXRfeF82aCwgdmVjX3RoZXRhLmhhdCA9IHZlY190aGV0YS5oYXRfb2xzXzZoLCB2ZWNfeSA9IHZlY195XzZoKQptYXRfdmFyLnRoZXRhLmhhdF9vbHNfNmggPC0gY2FsX21hdF92YXIudGhldGEuaGF0KG1hdF94ID0gbWF0X3hfNmgsIHNpZ21hID0gc2lnbWEuaGF0X29sc182aCkKdGVtcEludGVybmFsX29sc182aCA8LSB2ZWNfdGhldGEuaGF0X29sc182aFsxXSAvIC0gdmVjX3RoZXRhLmhhdF9vbHNfNmhbMl0KdGVtcEludGVybmFsX29sc182aApgYGAKClBsb3QgdGhlIHJlc2lkdWFscyBmb3IgdGhpcyBtb2RlbC4KCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gMTB9CnZlY19lcHNpbG9uX29sc182aCA8LSB2ZWNfeV82aCAtIG1hdF94XzZoICUqJSB2ZWNfdGhldGEuaGF0X29sc182aApwbG90KGRhdC5mXzZoJHNlcmllc1sxOm5fNmhdLCB2ZWNfZXBzaWxvbl9vbHNfNmgsIHR5cGUgPSAiYiIsIGNvbCA9ICJibHVlIiwgbHdkID0gMiwgCiAgICAgbWFpbiA9ICJSZXNpZHVhbHMgb2YgT3JkaW5hcnkgTGVhc3QgU3F1YXJlIEVzdGltYXRpb24gdXNpbmcgNmggRGF0YSIsIHhsYWIgPSAiU2VyaWVzIiwgeWxhYiA9ICJXIikKYGBgCgpFc3RpbWF0ZSB0aGUgcGFyYW1ldGVycyB1c2luZyB0aGUgM2ggZGF0YSBhbmQgaW5jbHVkZSBhIG1lYXN1cmUgb2YgdW5jZXJ0YWludHkgZm9yIGVhY2ggb2YgdGhlIGVzdGltYXRlcy4gCgpgYGB7ciwgd2FybmluZz1GQUxTRX0KbWF0X3hfM2ggPC0gY2JpbmQoMSwgZGF0LmZfM2gkdGVtcEV4dGVybmFsWzE6bl8zaF0sIGRhdC5mXzNoJGlTb2xhclsxOm5fM2hdKQp2ZWNfeV8zaCA8LSBkYXQuZl8zaCRoZWF0aW5nWzE6bl8zaF0KdmVjX3RoZXRhLmhhdF9vbHNfM2ggPC0gcHJlZF92ZWNfdGhldGEuaGF0KG1hdF94ID0gbWF0X3hfM2gsIHZlY195ID0gdmVjX3lfM2gpCnNpZ21hLmhhdF9vbHNfM2ggPC0gY2FsX3NpZ21hLmhhdChtYXRfeCA9IG1hdF94XzNoLCB2ZWNfdGhldGEuaGF0ID0gdmVjX3RoZXRhLmhhdF9vbHNfM2gsIHZlY195ID0gdmVjX3lfM2gpCm1hdF92YXIudGhldGEuaGF0X29sc18zaCA8LSBjYWxfbWF0X3Zhci50aGV0YS5oYXQobWF0X3ggPSBtYXRfeF8zaCwgc2lnbWEgPSBzaWdtYS5oYXRfb2xzXzNoKQp0ZW1wSW50ZXJuYWxfb2xzXzNoIDwtIHZlY190aGV0YS5oYXRfb2xzXzNoWzFdIC8gLSB2ZWNfdGhldGEuaGF0X29sc18zaFsyXQp0ZW1wSW50ZXJuYWxfb2xzXzNoCmBgYAoKUGxvdCB0aGUgcmVzaWR1YWxzIGZvciB0aGlzIG1vZGVsLgoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIGZpZy5oZWlnaHQgPSA1LCBmaWcud2lkdGggPSAxMH0KdmVjX2Vwc2lsb25fb2xzXzNoIDwtIHZlY195XzNoIC0gbWF0X3hfM2ggJSolIHZlY190aGV0YS5oYXRfb2xzXzNoCnBsb3QoZGF0LmZfM2gkc2VyaWVzWzE6bl8zaF0sIHZlY19lcHNpbG9uX29sc18zaCwgdHlwZSA9ICJiIiwgY29sID0gImJsdWUiLCBsd2QgPSAyLCAKICAgICBtYWluID0gIlJlc2lkdWFscyBvZiBPcmRpbmFyeSBMZWFzdCBTcXVhcmUgRXN0aW1hdGlvbiB1c2luZyAzaCBEYXRhIiwgeGxhYiA9ICJTZXJpZXMiLCB5bGFiID0gIlciKQpgYGAKCiMjIDEuMi4yCgpOb3csIHdlIGFzc3VtZSB0aGF0IHRoZSBjb3JyZWxhdGlvbiBzdHJ1Y3R1cmUgb2YgdGhlIHJlc2lkaXVhbHMgaXMgYW4gZXhwb25lbnRpYWwgZGVjYXlpbmcgZnVuY3Rpb24gb2YgdGhlIHRpbWUgZGlzdGFuY2UgYmV0d2VlbiB0d28gb2JzZXJ2YXRpb25zCgpgYGB7cn0KZG9fbWF0X2NhcFNpZ21hX2V4cERlY2F5IDwtIGZ1bmN0aW9uKHJobywgbil7CiAgICBtYXRfY2FwU2lnbWEgPC0gZGlhZyhuKQogICAgZm9yIChpIGluIDE6IG4pewogICAgICAgIGZvciAoaiBpbiAxOiBuKXsKICAgICAgICAgICAgbWF0X2NhcFNpZ21hW2ksIGpdIDwtIHJob14oYWJzKGkgLSBqKSkKICAgICAgICB9CiAgICB9CiAgICByZXR1cm4obWF0X2NhcFNpZ21hKQp9CmRvX25ld1JobyA8LSBmdW5jdGlvbihtYXRfeCwgdmVjX2Vwc2lsb24sIHNpZ21hLCBuKXsKICAgIHN1bSA8LSAwCiAgICBmb3IgKGkgaW4gMTogKG4gLSAxKSl7CiAgICAgICAgc3VtIDwtIHN1bSArIHZlY19lcHNpbG9uW2ldICogdmVjX2Vwc2lsb25baSsxXQogICAgfQogICAgcmhvIDwtIHN1bSAvIChzaWdtYV4yICogKG4gLSAxKSkKICAgIHJldHVybihyaG8pCn0KY2FsX3Job19leHBEZWNheVJlbGF4QWxnbyA8LSBmdW5jdGlvbihtYXRfeCwgdmVjX3kpewogICAgcmhvIDwtIDAKICAgIG4gPC0gbGVuZ3RoKG1hdF94WywxXSkKICAgIGZvciAodCBpbiAxOiA1KXsKICAgICAgICBtYXRfY2FwU2lnbWEgPC0gZG9fbWF0X2NhcFNpZ21hX2V4cERlY2F5KHJobywgbikKICAgICAgICB2ZWNfdGhldGEuaGF0IDwtIHByZWRfdmVjX3RoZXRhLmhhdChtYXRfeCwgdmVjX3ksIG1hdF9jYXBTaWdtYSkKICAgICAgICBzaWdtYS5oYXQgPC0gY2FsX3NpZ21hLmhhdChtYXRfeCwgdmVjX3ksIHZlY190aGV0YS5oYXQpCiAgICAgICAgdmVjX2Vwc2lsb24gPC0gdmVjX3kgLSBtYXRfeCAlKiUgdmVjX3RoZXRhLmhhdAogICAgICAgIHJobyA8LSBkb19uZXdSaG8obWF0X3gsIHZlY19lcHNpbG9uLCBzaWdtYS5oYXQsIG4pCiAgICB9CiAgICByZXR1cm4ocmhvKQp9CmBgYAoKYGBge3J9CihyaG9fZXhwRGVjYXlfNmggPC0gY2FsX3Job19leHBEZWNheVJlbGF4QWxnbyhtYXRfeCA9IG1hdF94XzZoLCB2ZWNfeSA9IHZlY195XzZoKSkKbWF0X2NhcFNpZ21hX2V4cERlY2F5XzZoIDwtIGRvX21hdF9jYXBTaWdtYV9leHBEZWNheShyaG8gPSByaG9fZXhwRGVjYXlfNmgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4gPSBuXzZoKQp2ZWNfdGhldGEuaGF0X2V4cERlY2F5XzZoIDwtIHByZWRfdmVjX3RoZXRhLmhhdChtYXRfeCA9IG1hdF94XzZoLCB2ZWNfeSA9IHZlY195XzZoLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hdF9jYXBTaWdtYSA9IG1hdF9jYXBTaWdtYV9leHBEZWNheV82aCkKc2lnbWEuaGF0X2V4cERlY2F5XzZoIDwtIGNhbF9zaWdtYS5oYXQobWF0X3ggPSBtYXRfeF82aCwgdmVjX3RoZXRhLmhhdCA9IHZlY190aGV0YS5oYXRfZXhwRGVjYXlfNmgsIHZlY195ID0gdmVjX3lfNmgpCm1hdF92YXIudGhldGEuaGF0X2V4cERlY2F5XzZoIDwtIGNhbF9tYXRfdmFyLnRoZXRhLmhhdChtYXRfeCA9IG1hdF94XzZoLCBzaWdtYSA9IHNpZ21hLmhhdF9leHBEZWNheV82aCkKKHRlbXBJbnRlcm5hbF9leHBEZWNheV82aCA8LSB2ZWNfdGhldGEuaGF0X2V4cERlY2F5XzZoWzFdIC8gLSB2ZWNfdGhldGEuaGF0X2V4cERlY2F5XzZoWzJdKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gMTAsIHdhcm5pbmc9RkFMU0V9CnZlY19lcHNpbG9uX2V4cERlY2F5XzZoIDwtIHZlY195XzZoIC0gbWF0X3hfNmggJSolIHZlY190aGV0YS5oYXRfZXhwRGVjYXlfNmgKcGxvdChkYXQuZl82aCRzZXJpZXNbMTpuXzZoXSwgdmVjX2Vwc2lsb25fZXhwRGVjYXlfNmgsIAogICAgIHR5cGUgPSAibCIsIGNvbCA9ICJyZWQiLCBsd2QgPSAzLCAKICAgICBtYWluID0gIkNvbXBhcmlzb24gb2YgUmVzaWR1YWxzIGZyb20gT0xTIGFuZCBXTFMoRXhwIERlY2F5KSB1c2luZyA2aCBEYXRhIiwgeGxhYiA9ICJTZXJpZXMiLCB5bGFiID0gIlciKQpsaW5lcyhkYXQuZl82aCRzZXJpZXNbMTpuXzZoXSwgdmVjX2Vwc2lsb25fb2xzXzZoLCAKICAgICAgdHlwZSA9ICJsIiwgY29sID0gImJsdWUiLCBsdHkgPSAyLCBsd2QgPSAyKQpsZWdlbmQoImJvdHRvbWxlZnQiLCBpbnNldCA9IC4wMiwgbGVnZW5kID0gYygiT0xTKElkZW50aXR5KSIsICJXTFMoRXhwIERlY2F5KSIpLCBjb2wgPSBjKCJibHVlIiwgInJlZCIpLCAKICAgICAgIGx0eSA9IGMoMiwgMSksIGx3ZCA9IGMoMiwgMyksIGNleD0gMC44KQpgYGAKCmBgYHtyLCBlY2hvID0gRkFMU0V9Cmxpc3RfY2FwU2lnbWEgPC0gYygnU2lnbWEgYmVpbmcgSWRlbnRpdHkgTWF0cml4dCcsICdTaWdtYSB3aXRoIEV4cCBEZWNheWluZycpCmxpc3RfcmhvXzZoIDwtIGMoMCwgcmhvX2V4cERlY2F5XzZoKQpsaXN0X3NpZ21hLmhhdF82aCA8LSBjKHNpZ21hLmhhdF9vbHNfNmgsIHNpZ21hLmhhdF9leHBEZWNheV82aCkKbGlzdF90aGV0YTEuaGF0XzZoIDwtIGModmVjX3RoZXRhLmhhdF9vbHNfNmhbMV0sIHZlY190aGV0YS5oYXRfZXhwRGVjYXlfNmhbMV0pCmxpc3RfdGhldGEyLmhhdF82aCA8LSBjKHZlY190aGV0YS5oYXRfb2xzXzZoWzJdLCB2ZWNfdGhldGEuaGF0X2V4cERlY2F5XzZoWzJdKQpsaXN0X3RoZXRhMy5oYXRfNmggPC0gYyh2ZWNfdGhldGEuaGF0X29sc182aFszXSwgdmVjX3RoZXRhLmhhdF9leHBEZWNheV82aFszXSkKbGlzdF90ZW1vSW50ZXJ2YWxfNmggPC0gYyh0ZW1wSW50ZXJuYWxfb2xzXzZoLCB0ZW1wSW50ZXJuYWxfZXhwRGVjYXlfNmgpCnRhYmxlXzZoIDwtIGRhdGEuZnJhbWUobGlzdF9jYXBTaWdtYSwgbGlzdF9yaG9fNmgsIGxpc3RfdGhldGExLmhhdF82aCwgbGlzdF90aGV0YTIuaGF0XzZoLCAKICAgICAgICAgICAgICAgICAgICAgICBsaXN0X3RoZXRhMy5oYXRfNmgsIGxpc3Rfc2lnbWEuaGF0XzZoLCBsaXN0X3RlbW9JbnRlcnZhbF82aCkKa2FibGUodGFibGVfNmgsIGNvbC5uYW1lcyA9IGMoJ2NhcFNpZ21hJywgJ3JobycsICd0aGV0YTEuaGF0JywgJ3RoZXRhMi5oYXQnLCAndGhldGEzLmhhdCcsICdzaWdtYS5oYXQnLCAndGVtcEludGVybmFsJyksIAogICAgICBjYXB0aW9uID0gJ0NvbXBhcmlzb24gd2hlbiBTaWdtYXMgYXJlIGRpZmZlcmVudCcsIGFsaWduID0gImwiKQpgYGAKCiMjIDEuMi4zCgpgYGB7cn0KKHJob19leHBEZWNheV8zaCA8LSBjYWxfcmhvX2V4cERlY2F5UmVsYXhBbGdvKG1hdF94ID0gbWF0X3hfM2gsIHZlY195ID0gdmVjX3lfM2gpKQptYXRfY2FwU2lnbWFfZXhwRGVjYXlfM2ggPC0gZG9fbWF0X2NhcFNpZ21hX2V4cERlY2F5KHJobyA9IHJob19leHBEZWNheV8zaCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbiA9IG5fM2gpCnZlY190aGV0YS5oYXRfZXhwRGVjYXlfM2ggPC0gcHJlZF92ZWNfdGhldGEuaGF0KG1hdF94ID0gbWF0X3hfM2gsIHZlY195ID0gdmVjX3lfM2gsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hdF9jYXBTaWdtYSA9IG1hdF9jYXBTaWdtYV9leHBEZWNheV8zaCkKc2lnbWEuaGF0X2V4cERlY2F5XzNoIDwtIGNhbF9zaWdtYS5oYXQobWF0X3ggPSBtYXRfeF8zaCwgdmVjX3kgPSB2ZWNfeV8zaCwgdmVjX3RoZXRhLmhhdCA9IHZlY190aGV0YS5oYXRfZXhwRGVjYXlfM2gpCm1hdF92YXIudGhldGEuaGF0X2V4cERlY2F5XzNoIDwtIGNhbF9tYXRfdmFyLnRoZXRhLmhhdChtYXRfeCA9IG1hdF94XzNoLCBzaWdtYSA9IHNpZ21hLmhhdF9leHBEZWNheV8zaCkKKHRlbXBJbnRlcm5hbF9leHBEZWNheV8zaCA8LSB2ZWNfdGhldGEuaGF0X2V4cERlY2F5XzNoWzFdIC8gLSB2ZWNfdGhldGEuaGF0X2V4cERlY2F5XzNoWzJdKQpgYGAKCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gMTB9CnZlY19lcHNpbG9uX2V4cERlY2F5XzNoIDwtIHZlY195XzNoIC0gbWF0X3hfM2ggJSolIHZlY190aGV0YS5oYXRfZXhwRGVjYXlfM2gKcGxvdChkYXQuZl8zaCRzZXJpZXNbMTpuXzNoXSwgdmVjX2Vwc2lsb25fZXhwRGVjYXlfM2gsIAogICAgIHR5cGUgPSAibCIsIGNvbCA9ICJyZWQiLCBsd2QgPSAzLCAKICAgICBtYWluID0gIkNvbXBhcmlzb24gb2YgUmVzaWR1YWxzIGZyb20gT0xTIGFuZCBXTFMoRXhwIERlY2F5KSB1c2luZyAzaCBEYXRhIiwgeGxhYiA9ICJTZXJpZXMiLCB5bGFiID0gIlciKQpsaW5lcyhkYXQuZl8zaCRzZXJpZXNbMTpuXzNoXSwgdmVjX2Vwc2lsb25fb2xzXzNoLCAKICAgICAgdHlwZSA9ICJsIiwgY29sID0gImJsdWUiLCBsdHkgPSAyLCBsd2QgPSAyKQpsZWdlbmQoImJvdHRvbWxlZnQiLCBpbnNldCA9IC4wMiwgbGVnZW5kID0gYygiT0xTKElkZW50aXR5KSIsICJXTFMoRXhwIERlY2F5KSIpLCBjb2wgPSBjKCJibHVlIiwgInJlZCIpLCAKICAgICAgIGx0eSA9IGMoMiwgMSksIGx3ZCA9IGMoMiwgMyksIGNleD0gMC44KQpgYGAKCmBgYHtyLCBlY2hvID0gRkFMU0V9Cmxpc3RfY2FwU2lnbWEgPC0gYygnU2lnbWEgYmVpbmcgSWRlbnRpdHkgTWF0cml4dCcsICdTaWdtYSB3aXRoIEV4cCBEZWNheWluZycpCmxpc3RfcmhvXzNoIDwtIGMoMCwgcmhvX2V4cERlY2F5XzNoKQpsaXN0X3NpZ21hLmhhdF8zaCA8LSBjKHNpZ21hLmhhdF9vbHNfM2gsIHNpZ21hLmhhdF9leHBEZWNheV8zaCkKbGlzdF90aGV0YTEuaGF0XzNoIDwtIGModmVjX3RoZXRhLmhhdF9vbHNfM2hbMV0sIHZlY190aGV0YS5oYXRfZXhwRGVjYXlfM2hbMV0pCmxpc3RfdGhldGEyLmhhdF8zaCA8LSBjKHZlY190aGV0YS5oYXRfb2xzXzNoWzJdLCB2ZWNfdGhldGEuaGF0X2V4cERlY2F5XzNoWzJdKQpsaXN0X3RoZXRhMy5oYXRfM2ggPC0gYyh2ZWNfdGhldGEuaGF0X29sc18zaFszXSwgdmVjX3RoZXRhLmhhdF9leHBEZWNheV8zaFszXSkKbGlzdF90ZW1vSW50ZXJ2YWxfM2ggPC0gYyh0ZW1wSW50ZXJuYWxfb2xzXzNoLCB0ZW1wSW50ZXJuYWxfZXhwRGVjYXlfM2gpCnRhYmxlXzNoIDwtIGRhdGEuZnJhbWUobGlzdF9jYXBTaWdtYSwgbGlzdF9yaG9fM2gsIGxpc3RfdGhldGExLmhhdF8zaCwgbGlzdF90aGV0YTIuaGF0XzNoLCAKICAgICAgICAgICAgICAgICAgICAgICBsaXN0X3RoZXRhMy5oYXRfM2gsIGxpc3Rfc2lnbWEuaGF0XzNoLCBsaXN0X3RlbW9JbnRlcnZhbF8zaCkKa2FibGUodGFibGVfM2gsIGNvbC5uYW1lcyA9IGMoJ2NhcFNpZ21hJywgJ3JobycsICd0aGV0YTEuaGF0JywgJ3RoZXRhMi5oYXQnLCAndGhldGEzLmhhdCcsICdzaWdtYS5oYXQnLCAndGVtcEludGVybmFsJyksIAogICAgICBjYXB0aW9uID0gJ0NvbXBhcmlzb24gd2hlbiBTaWdtYXMgYXJlIGRpZmZlcmVudCcsIGFsaWduID0gImwiKQpgYGAKCiMgUXVlc3Rpb24gMywgIExvY2FsIFRyZW5kIG1vZGUKCiMjIDMuMSwgIExvY2FsIExpbmVhciBUcmVuZCBNb2RlbAoKRGVmaW5lIGZ1bmN0aW9ucyBmb3IgdHJlbmQgbW9kZWwuCgpgYGB7cn0KZG9fc2VxX3plcm9EZWNyZWFzZVJldiA8LSBmdW5jdGlvbihuKXtyZXR1cm4ocmV2KC0gc2VxKDAsIG4tMSkpKX0KZG9fbWF0X2NhcFNpZ21hX3RyZW5kIDwtIGZ1bmN0aW9uKGxhbWJkYSA9IDEsIG4pewogICAgbWF0X2NhcFNpZ21hX3RyZW5kIDwtIGRpYWcobikKICAgIHNlcV96ZGkgPC0gZG9fc2VxX3plcm9EZWNyZWFzZVJldihuKQogICAgZm9yIChpIGluIDE6IG4pewogICAgICAgIG1hdF9jYXBTaWdtYV90cmVuZFtpLCBpXSA8LSAxICogbGFtYmRhXnNlcV96ZGlbaV0KICAgIH0KICAgIHJldHVybihtYXRfY2FwU2lnbWFfdHJlbmQpCn0KY2FsX21hdF9jYXBGX3RyZW5kIDwtIGZ1bmN0aW9uKG1hdF94X3RyZW5kLCBtYXRfY2FwU2lnbWFfdHJlbmQpewogICAgbWF0X2NhcEYgPC0gdChtYXRfeF90cmVuZCkgJSolIHNvbHZlKG1hdF9jYXBTaWdtYV90cmVuZCkgJSolIG1hdF94X3RyZW5kCiAgICByZXR1cm4obWF0X2NhcEYpCn0KY2FsX3ZlY19oX3RyZW5kIDwtIGZ1bmN0aW9uKG1hdF94X3RyZW5kLCBtYXRfY2FwU2lnbWFfdHJlbmQsIHZlY195X3RyZW5kKXsKICAgIG1hdF9oIDwtIHQobWF0X3hfdHJlbmQpICUqJSBzb2x2ZShtYXRfY2FwU2lnbWFfdHJlbmQpICUqJSB2ZWNfeV90cmVuZAogICAgcmV0dXJuKG1hdF9oKQp9CmNhbF92ZWNfdGhldGEuaGF0X3RyZW5kIDwtIGZ1bmN0aW9uKG1hdF94X3RyZW5kLCBtYXRfY2FwU2lnbWFfdHJlbmQsIHZlY195X3RyZW5kKXsKICAgIG1hdF9jYXBGIDwtIGNhbF9tYXRfY2FwRl90cmVuZChtYXRfeF90cmVuZCwgbWF0X2NhcFNpZ21hX3RyZW5kKQogICAgbWF0X2ggPC0gY2FsX3ZlY19oX3RyZW5kKG1hdF94X3RyZW5kLCBtYXRfY2FwU2lnbWFfdHJlbmQsIHZlY195X3RyZW5kKQogICAgdmVjX3RoZXRhLmhhdF90cmVuZCA8LSBzb2x2ZShtYXRfY2FwRikgJSolIG1hdF9oCiAgICByZXR1cm4odmVjX3RoZXRhLmhhdF90cmVuZCkKfQpjYWxfdmVjX2ludGVydmFsUHJlZCA8LSBmdW5jdGlvbihwcm9iID0gMC45NSwgbiwgcCwgeS5oYXQsIHZhcil7CiAgICBxdWFudGlsZVN0dWRlbnREaXN0IDwtIHF0KHAgPSAwLjk1LCBkZiA9IG4gLSBwKQogICAgYm91bmRVcCA8LSB5LmhhdCArIHF1YW50aWxlU3R1ZGVudERpc3QgKiBzcXJ0KHZhcikKICAgIGJvdW5kTG93IDwtIHkuaGF0IC0gcXVhbnRpbGVTdHVkZW50RGlzdCAqIHNxcnQodmFyKQogICAgcmV0dXJuKGxpc3QoYm91bmRVcCA9IGRyb3AoYm91bmRVcCksIGJvdW5kTG93ID0gZHJvcChib3VuZExvdykpKQp9CmNhbF9tYXRfaW50ZXJ2YWxQcmVkIDwtIGZ1bmN0aW9uKHZlY19sLCBwcm9iID0gMC45NSwgbiwgcCwgdmVjX3kuaGF0LCB2ZWNfdmFyKXsKICAgIHZlY19ib3VuZFVwIDwtIG51bWVyaWMobGVuZ3RoKHZlY19sKSkKICAgIHZlY19ib3VuZExvdyA8LSBudW1lcmljKGxlbmd0aCh2ZWNfbCkpCiAgICBmb3IgKGkgaW4gc2VxKDEsIGxlbmd0aCh2ZWNfbCkpKXsKICAgICAgICBpbnRlcnZhbCA8LSBjYWxfdmVjX2ludGVydmFsUHJlZChwcm9iLCBuLCBwLCB5LmhhdCA9IHZlY195LmhhdFtpXSwgdmFyID0gdmVjX3ZhcltpXSkKICAgICAgICB2ZWNfYm91bmRVcFtpXSA8LSBpbnRlcnZhbCRib3VuZFVwCiAgICAgICAgdmVjX2JvdW5kTG93W2ldIDwtIGludGVydmFsJGJvdW5kTG93CiAgICB9CiAgICByZXR1cm4obGlzdCh2ZWNfYm91bmRVcCA9IHZlY19ib3VuZFVwLCB2ZWNfYm91bmRMb3cgPSB2ZWNfYm91bmRMb3cpKQp9CmNhbF92ZWNfbWVtb3J5VG90YWwgPC0gZnVuY3Rpb24obGFtYmRhLCBuKXsKICAgIHZlY19tZW1vcnlUb3RhbCA8LSBudW1lcmljKG4pCiAgICB2ZWNfbWVtb3J5VG90YWxbMV0gPC0gMQogICAgZm9yIChqIGluIDE6IChuLTEpKXsKICAgICB2ZWNfbWVtb3J5VG90YWxbaisxXSA8LSB2ZWNfbWVtb3J5VG90YWxbal0gKyBsYW1iZGFeagogICAgfQogICAgcmV0dXJuKHZlY19tZW1vcnlUb3RhbCkKfQpgYGAKCkNvbnZlcmdlbmNlIG9mIFRvdGFsIE1lbW9yeSBvZiBMb2NhbCBUcmVuZCBNb2RlbAoKYGBge3IsIGZpZy5oZWlnaHQgPSA1LCBmaWcud2lkdGggPSAxMH0Kbl90cmVuZExfMV82aCA8LSBuXzZoCmxhbWJkYV90cmVuZExfMV82aCA8LSAwLjgKdmVjX21lbW9yeVRvdGFsXzFfNmggPC0gY2FsX3ZlY19tZW1vcnlUb3RhbChsYW1iZGE9IGxhbWJkYV90cmVuZExfMV82aCwgbiA9IG5fdHJlbmRMXzFfNmgpCnBsb3Qoc2VxKDEsIG5fdHJlbmRMXzFfNmgpLCB2ZWNfbWVtb3J5VG90YWxfMV82aCwgY29sID0gImJsdWUiLAogICAgIG1haW4gPSBwYXN0ZSgiQ29udmVyZ2VuY2Ugb2YgVG90YWwgTWVtb3J5IG9mIExvY2FsIFRyZW5kIE1vZGVsICgiLCBsYW1iZGFfdHJlbmRMXzFfNmgsIAogICAgICAgICAgICAgICAgICAiKSB1c2luZyA2aC1zYW1wbGluZyBEYXRhIiksIAogICAgIHhsYWIgPSAiU2VyaWVzIiwgeWxhYiA9ICJUb3RhbCBNZW1vcnkiKQpgYGAKCkRlZmluZSBGdW5jdGlvbnMgZm9yIExpbmVhciBUcmVuZCBNb2RlbAoKVXNlIGEgbG9jYWwgbGluZWFyIHRyZW5kIG1vZGVsIG9uIHRoZSBvdXRkb29yIHRlbXBlcmF0dXJlIGluIHRoZSA2aCB0cmFpbmluZyBkYXRhIHVzaW5nIGxhbWJkYSA9IDAuOC4KCnkgPSB0aGV0YTAgKyB0aGV0YTEgKiBqICsgZXBzaWxvbgoKUGxvdCB0aGUgdHJhaW5pbmcgZGF0YSBhbmQgdGhlIGNvcnJlc3BvbmRpbmcgb25lIHN0ZXAgcHJlZGljdGlvbnMgZm9yIGFsbCBvYnNlcnZhdGlvbnMgaW4gdGhlIHRyYWluaW5nIGRhdGEuCgpgYGB7cn0KZnVuY19mX2xpbmVhciA8LSBmdW5jdGlvbihqKXsKICAgIHJldHVybihyYmluZCgxLCBqKSkKfQpwcmVkX3lfdHJlbmRfbGluZWFyIDwtIGZ1bmN0aW9uKGwsIHZlY190aGV0YS5oYXRfdHJlbmQpewogICAgeV9wcmVkX3RyZW5kIDwtIHQoZnVuY19mX2xpbmVhcihsKSkgJSolIHZlY190aGV0YS5oYXRfdHJlbmQKICAgIHJldHVybih5X3ByZWRfdHJlbmQpCn0KcHJlZF92YXJfdHJlbmRfbGluZWFyIDwtIGZ1bmN0aW9uKGwsIG1hdF94X3RyZW5kLCB2ZWNfeV90cmVuZCwgdmVjX3RoZXRhLmhhdF90cmVuZCwgbWF0X2NhcFNpZ21hX3RyZW5kKXsKICAgIHNpZ21hLmhhdCA8LSBjYWxfc2lnbWEuaGF0KG1hdF94ID0gbWF0X3hfdHJlbmQsIHZlY195ID0gdmVjX3lfdHJlbmQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICB2ZWNfdGhldGEuaGF0ID0gdmVjX3RoZXRhLmhhdF90cmVuZCwgbWF0X2NhcFNpZ21hID0gbWF0X2NhcFNpZ21hX3RyZW5kKQogICAgbWF0X2NhcEZfdHJlbmRfdHJlbmQgPC0gY2FsX21hdF9jYXBGX3RyZW5kKG1hdF94X3RyZW5kLCBtYXRfY2FwU2lnbWFfdHJlbmQpCiAgICB2YXJfcHJlZF90cmVuZCA8LSBzaWdtYS5oYXReMiAlKiUgKDEgKyB0KGZ1bmNfZl9saW5lYXIobCkpICUqJSBzb2x2ZShtYXRfY2FwRl90cmVuZF90cmVuZCkgJSolIGZ1bmNfZl9saW5lYXIobCkpCiAgICByZXR1cm4odmFyX3ByZWRfdHJlbmQpCn0KcHJlZF92ZWNfeV90cmVuZF9saW5lYXIgPC0gZnVuY3Rpb24odmVjX2wsIHZlY190aGV0YS5oYXRfdHJlbmQpewogICAgdmVjX3lfdHJlbmRfbGluZWFyIDwtIG51bWVyaWMobGVuZ3RoKHZlY19sKSkKICAgIGZvciAoaSBpbiAoMTogbGVuZ3RoKHZlY19sKSkpewogICAgICAgIHZlY195X3RyZW5kX2xpbmVhcltpXSA8LSBwcmVkX3lfdHJlbmRfbGluZWFyKHZlY19sW2ldLCB2ZWNfdGhldGEuaGF0X3RyZW5kKQogICAgfQogICAgcmV0dXJuKHZlY195X3RyZW5kX2xpbmVhcikKfQpwcmVkX3ZlY192YXJfdHJlbmRfbGluZWFyIDwtIGZ1bmN0aW9uKHZlY19sLCBtYXRfeF90cmVuZCwgdmVjX3kucHJlZF90cmVuZCwgdmVjX3RoZXRhLmhhdF90cmVuZCwgbWF0X2NhcFNpZ21hX3RyZW5kKXsKICAgIHZlY192YXJfdHJlbmRfbGluZWFyIDwtIG51bWVyaWMobGVuZ3RoKHZlY19sKSkKICAgIGZvciAoaSBpbiAoMTogbGVuZ3RoKHZlY19sKSkpewogICAgICAgIHZlY192YXJfdHJlbmRfbGluZWFyW2ldIDwtIHByZWRfdmFyX3RyZW5kX2xpbmVhcih2ZWNfbFtpXSwgbWF0X3hfdHJlbmQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZWNfeS5wcmVkX3RyZW5kW2ldLCB2ZWNfdGhldGEuaGF0X3RyZW5kLCBtYXRfY2FwU2lnbWFfdHJlbmQpCiAgICB9CiAgICByZXR1cm4odmVjX3Zhcl90cmVuZF9saW5lYXIpCn0KYGBgCgojIyMgMS4zLjEuMSBFc3RpbWF0aW9uCgpFc3RpbWF0aW9uCgpgYGB7cn0KbWF0X2NhcFNpZ21hX3RyZW5kTF8xXzZoIDwtIGRvX21hdF9jYXBTaWdtYV90cmVuZChsYW1iZGEgPSBsYW1iZGFfdHJlbmRMXzFfNmgsIG4gPSBuX3RyZW5kTF8xXzZoKQp2ZWNfeV90cmVuZExfMV82aCA8LSBkYXQuZl82aCR0ZW1wRXh0ZXJuYWxbMTpuXzZoXQpzZXFfemRpX3RyZW5kTF8xXzZoIDwtIGRvX3NlcV96ZXJvRGVjcmVhc2VSZXYobl90cmVuZExfMV82aCkKbWF0X3hfdHJlbmRMXzFfNmggPC0gY2JpbmQoMSwgc2VxX3pkaV90cmVuZExfMV82aCkKdmVjX3RoZXRhLmhhdF90cmVuZExfMV82aCA8LSBjYWxfdmVjX3RoZXRhLmhhdF90cmVuZChtYXRfeF90cmVuZCA9IG1hdF94X3RyZW5kTF8xXzZoLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hdF9jYXBTaWdtYV90cmVuZCA9IG1hdF9jYXBTaWdtYV90cmVuZExfMV82aCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlY195X3RyZW5kID0gdmVjX3lfdHJlbmRMXzFfNmgpCmNhbF9tYXRfY2FwRl90cmVuZChtYXRfeF90cmVuZCA9IG1hdF94X3RyZW5kTF8xXzZoLCAKICAgICAgICAgICAgICAgICAgIG1hdF9jYXBTaWdtYV90cmVuZCA9IG1hdF9jYXBTaWdtYV90cmVuZExfMV82aCkKY2FsX3ZlY19oX3RyZW5kKG1hdF94X3RyZW5kID0gbWF0X3hfdHJlbmRMXzFfNmgsIAogICAgICAgICAgICAgICAgbWF0X2NhcFNpZ21hX3RyZW5kID0gbWF0X2NhcFNpZ21hX3RyZW5kTF8xXzZoLAogICAgICAgICAgICAgICAgdmVjX3lfdHJlbmQgPSB2ZWNfeV90cmVuZExfMV82aCkKc2lnbWEuaGF0X3RyZW5kTF8xXzZoIDwtIGNhbF9zaWdtYS5oYXQobWF0X3ggPSBtYXRfeF90cmVuZExfMV82aCwgdmVjX3kgPSB2ZWNfeV90cmVuZExfMV82aCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlY190aGV0YS5oYXQgPSB2ZWNfdGhldGEuaGF0X3RyZW5kTF8xXzZoLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF0X2NhcFNpZ21hID0gbWF0X2NhcFNpZ21hX3RyZW5kTF8xXzZoKQptYXRfdmFyLnRoZXRhLmhhdF90cmVuZExfMV82aCA8LSBjYWxfbWF0X3Zhci50aGV0YS5oYXQobWF0X3ggPSBtYXRfeF90cmVuZExfMV82aCwgc2lnbWEuaGF0ID0gc2lnbWEuaGF0X3RyZW5kTF8xXzZoLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hdF9jYXBTaWdtYSA9IG1hdF9jYXBTaWdtYV90cmVuZExfMV82aCkKYGBgCgojIyMgMS4zLjEuMiBQcmVkaWN0aW9uCgpgYGB7cn0KdmVjX3kuaGF0X3RyZW5kTF8xXzZoIDwtIG1hdF94X3RyZW5kTF8xXzZoICUqJSB2ZWNfdGhldGEuaGF0X3RyZW5kTF8xXzZoCnZlY19sX3RyZW5kTF8xXzZoIDwtIGMoMSwgMiwgMywgNCkKdmVjX3kucHJlZF90cmVuZExfMV82aCA8LSBwcmVkX3ZlY195X3RyZW5kX2xpbmVhcih2ZWNfbCA9IHZlY19sX3RyZW5kTF8xXzZoLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZWNfdGhldGEuaGF0X3RyZW5kID0gdmVjX3RoZXRhLmhhdF90cmVuZExfMV82aCkKdmVjX3Zhci5wcmVkX3RyZW5kTF8xXzZoIDwtIHByZWRfdmVjX3Zhcl90cmVuZF9saW5lYXIodmVjX2wgPSB2ZWNfbF90cmVuZExfMV82aCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hdF94X3RyZW5kID0gbWF0X3hfdHJlbmRMXzFfNmgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXRfY2FwU2lnbWFfdHJlbmQgPSBtYXRfY2FwU2lnbWFfdHJlbmRMXzFfNmgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZWNfeS5wcmVkX3RyZW5kID0gdmVjX3kucHJlZF90cmVuZExfMV82aCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVjX3RoZXRhLmhhdF90cmVuZCA9IHZlY190aGV0YS5oYXRfdHJlbmRMXzFfNmgpCm1hdF9pbnRlcnZhUHJlZF90cmVuZExfMV82aCA8LSBjYWxfbWF0X2ludGVydmFsUHJlZCh2ZWNfbCA9IHZlY19sX3RyZW5kTF8xXzZoLCBwcm9iID0gMC45NSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuID0gbl90cmVuZExfMV82aCwgcCA9IGxlbmd0aCh2ZWNfdGhldGEuaGF0X3RyZW5kTF8xXzZoKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZWNfeS5oYXQgPSB2ZWNfeS5wcmVkX3RyZW5kTF8xXzZoLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlY192YXIgPSB2ZWNfdmFyLnByZWRfdHJlbmRMXzFfNmgpCmBgYAoKIyMjIDEuMy4xLjQKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gMTAsIHdhcm5pbmc9RkFMU0V9CnBsb3QoZGF0LmZfNmgkc2VyaWVzWzE6bl82aF0sIGRhdC5mXzZoJHRlbXBFeHRlcm5hbFsxOm5fNmhdLCAKICAgICB0eXBlID0gImIiLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDEsIGx0eSA9IDEsIHhsaW0gPSBjKDAsIG5fNmggKyA0KSwgeWxpbSA9IGMoLTQsIDEyKSwKICAgICBtYWluID0gcGFzdGUoIlByZWRpY3Rpb24gb2YgRXh0ZXJuYWwgVGVtcGVyYXR1cmUgYnkgTGluZWFyIExvY2FsIFRyZW5kIE1vZGVsICgiLCBsYW1iZGFfdHJlbmRMXzFfNmgsIAogICAgICAgICAgICAgICAgICAiKSB1c2luZyA2aCBEYXRhIiksIAogICAgIHhsYWIgPSAiU2VyaWVzIiwgeWxhYiA9ICJDZWxzaXVzIERlZ3JlZSIpCnBvaW50cyhuX3RyZW5kTF8xXzZoICsgc2VxKDQpLCBkYXQuZl82aCR0ZW1wRXh0ZXJuYWxbKG5fdHJlbmRMXzFfNmgrMSk6IChuX3RyZW5kTF8xXzZoKzQpXSwgCiAgICAgICB0eXBlID0gImIiLCBjb2wgPSAiYmx1ZSIsIGx0eSA9IDEsIHBjaCA9IDE2KQpsaW5lcyhkYXQuZl82aCRzZXJpZXNbKG5fNmgpOihuXzZoKzEpXSwgZGF0LmZfNmgkdGVtcEV4dGVybmFsWyhuXzZoKToobl82aCsxKV0sIAogICAgICB0eXBlID0gImMiLCBjb2wgPSAiYmx1ZSIsIGx0eSA9IDEpCmxlZ2VuZCgiYm90dG9tbGVmdCIsIGluc2V0ID0gLjAyLCBsZWdlbmQgPSBjKCJUcmFpbmluZyBEYXRhIiwgIlRlc3RpbmcgRGF0YSIsICJUcmVuZCBNb2RlbCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUHJlZGljdGlvbiIsICJQcmVkIEludGVydmFsIiksIAogICAgICAgY29sID0gYygiYmx1ZSIsICJibHVlIiwgInJlZCIsICJyZWQiLCAicmVkIiksIHBjaCA9IGMoMSwgMTYsIE5BLCAxNSwgNiksIAogICAgICAgbHR5ID0gYygxLCAxLCAyLCAzLCAxKSwgbHdkID0gYygxLCAxLCAzLCAzLCAxKSkKIyBQbG90IHRoZSB2YWxpZGF0aW9uIHJlc3VsdApsaW5lcyhkYXQuZl82aCRzZXJpZXNbMTpuXzZoXSwgdmVjX3kuaGF0X3RyZW5kTF8xXzZoLCAKICAgICAgdHlwZSA9ICJsIiwgY29sID0gInJlZCIsIGx0eSA9IDIsIGx3ZCA9IDMpCiMgUGxvdCB0aGUgcHJlZGljdGlvbiByZXN1bHQKcG9pbnRzKG5fdHJlbmRMXzFfNmggKyB2ZWNfbF90cmVuZExfMV82aCwgdmVjX3kucHJlZF90cmVuZExfMV82aCwgCiAgICAgICB0eXBlID0gImIiLCBjb2wgPSAicmVkIiwgcGNoID0gMTUsIGx0eSA9IDMsIGx3ZCA9IDIpCmxpbmVzKG5fdHJlbmRMXzFfNmggKyB2ZWNfbF90cmVuZExfMV82aCwgbWF0X2ludGVydmFQcmVkX3RyZW5kTF8xXzZoJHZlY19ib3VuZFVwLCAKICAgICAgdHlwZSA9ICJiIiwgY29sID0gJ3JlZCcsIGx3ZCA9IDEsIGx0eSA9IDEsIHBjaCA9IDYsIGNleD0gMC41KQoKbGluZXMobl90cmVuZExfMV82aCArIHZlY19sX3RyZW5kTF8xXzZoLCBtYXRfaW50ZXJ2YVByZWRfdHJlbmRMXzFfNmgkdmVjX2JvdW5kTG93LCAKICAgICAgdHlwZSA9ICJiIiwgY29sID0gJ3JlZCcsIGx3ZCA9IDEsIGx0eSA9IDEsIHBjaCA9IDIsIGNleD0gMC41KQpgYGAKCgojIyAzLjIsICBRdWFkcmF0aWMgTG9jYWwgVHJlbmQgTW9kZWwgKGxhbWJkYSA9IDAuOCkgb2YgNmgtc2FtcGxpbmcgRGF0YQoKeSA9IHRoZXRhMCArIHRoZXRhMSBcKiBqICsgdGhldGEyIFwqIGpeMi8yICsgZXBzaWxvbgoKRGVmaW5lIEZ1bmN0aW9ucyBmb3IgUXVhZHJhdGljIExvY2FsIFRyZW5kIE1vZGVsCgpgYGB7cn0KZnVuY19mX3F1YWRyYXRpYyA8LSBmdW5jdGlvbihqKXsKICAgIHJldHVybihyYmluZCgxLCBqLCBqXjIgLyAyKSkKfQpwcmVkX3lfdHJlbmRfcXVhZHJhdGljIDwtIGZ1bmN0aW9uKGwsIHZlY190aGV0YS5oYXRfdHJlbmQpewogICAgeV9wcmVkX3RyZW5kIDwtIHQoZnVuY19mX3F1YWRyYXRpYyhsKSkgJSolIHZlY190aGV0YS5oYXRfdHJlbmQKICAgIHJldHVybih5X3ByZWRfdHJlbmQpCn0KcHJlZF92ZWNfeV90cmVuZF9xdWFkcmF0aWMgPC0gZnVuY3Rpb24odmVjX2wsIHZlY190aGV0YS5oYXRfdHJlbmQpewogICAgdmVjX3kucHJlZF90cmVuZF9xdWFkcmF0aWMgPC0gbnVtZXJpYyhsZW5ndGgodmVjX2wpKQogICAgZm9yIChpIGluIHNlcSgxLCBsZW5ndGgodmVjX2wpKSl7CiAgICAgICAgdmVjX3kucHJlZF90cmVuZF9xdWFkcmF0aWNbaV0gPC0gcHJlZF95X3RyZW5kX3F1YWRyYXRpYyh2ZWNfbFtpXSwgdmVjX3RoZXRhLmhhdF90cmVuZCkKICAgIH0KICAgIHJldHVybih2ZWNfeS5wcmVkX3RyZW5kX3F1YWRyYXRpYykKfQpwcmVkX3Zhcl90cmVuZF9xdWFkcmF0aWMgPC0gZnVuY3Rpb24obCwgbWF0X3hfdHJlbmQsIHZlY195X3RyZW5kLCB2ZWNfdGhldGEuaGF0X3RyZW5kLCBtYXRfY2FwU2lnbWFfdHJlbmQpewogICAgc2lnbWEuaGF0IDwtIGNhbF9zaWdtYS5oYXQobWF0X3ggPSBtYXRfeF90cmVuZCwgdmVjX3kgPSB2ZWNfeV90cmVuZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlY190aGV0YS5oYXQgPSB2ZWNfdGhldGEuaGF0X3RyZW5kLCBtYXRfY2FwU2lnbWEgPSBtYXRfY2FwU2lnbWFfdHJlbmQpCiAgICBtYXRfY2FwRl90cmVuZF90cmVuZCA8LSBjYWxfbWF0X2NhcEZfdHJlbmQobWF0X3hfdHJlbmQsIG1hdF9jYXBTaWdtYV90cmVuZCkKICAgIHZhci5wcmVkX3RyZW5kIDwtIHNpZ21hLmhhdF4yICUqJSAoMSArIHQoZnVuY19mX3F1YWRyYXRpYyhsKSkgJSolIHNvbHZlKG1hdF9jYXBGX3RyZW5kX3RyZW5kKSAlKiUgZnVuY19mX3F1YWRyYXRpYyhsKSkKICAgIHJldHVybih2YXIucHJlZF90cmVuZCkKfQpwcmVkX3ZlY192YXJfdHJlbmRfcXVhZHJhdGljIDwtIGZ1bmN0aW9uKHZlY19sLCBtYXRfeF90cmVuZCwgdmVjX3kucHJlZF90cmVuZCwgdmVjX3RoZXRhLmhhdF90cmVuZCwgbWF0X2NhcFNpZ21hX3RyZW5kKXsKICAgIHZlY192YXIucHJlZF90cmVuZF9xdWFkcmF0aWMgPC0gbnVtZXJpYyhsZW5ndGgodmVjX2wpKQogICAgZm9yIChpIGluIHNlcSgxLCBsZW5ndGgodmVjX2wpKSl7CiAgICAgICAgdmVjX3Zhci5wcmVkX3RyZW5kX3F1YWRyYXRpY1tpXSA8LSBwcmVkX3Zhcl90cmVuZF9xdWFkcmF0aWModmVjX2xbaV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hdF94X3RyZW5kLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZWNfeS5wcmVkX3RyZW5kW2ldLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZWNfdGhldGEuaGF0X3RyZW5kLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXRfY2FwU2lnbWFfdHJlbmQpCiAgICB9CiAgICByZXR1cm4odmVjX3Zhci5wcmVkX3RyZW5kX3F1YWRyYXRpYykKfQpgYGAKCmBgYHtyfQpuX3RyZW5kTF8yXzZoIDwtIG5fNmgKbGFtYmRhX3RyZW5kTF8yXzZoIDwtIDAuOAptYXRfY2FwU2lnbWFfdHJlbmRMXzJfNmggPC0gZG9fbWF0X2NhcFNpZ21hX3RyZW5kKGxhbWJkYSA9IGxhbWJkYV90cmVuZExfMl82aCwgbiA9IG5fdHJlbmRMXzJfNmgpCnZlY195X3RyZW5kTF8yXzZoIDwtIGRhdC5mXzZoJHRlbXBFeHRlcm5hbFsxOiBuX3RyZW5kTF8yXzZoXQpzZXFfemRpX3RyZW5kTF8yXzZoIDwtIGRvX3NlcV96ZXJvRGVjcmVhc2VSZXYobl90cmVuZExfMl82aCkKbWF0X3hfdHJlbmRMXzJfNmggPC0gY2JpbmQoMSwgc2VxX3pkaV90cmVuZExfMl82aCwgc2VxX3pkaV90cmVuZExfMl82aF4yIC8gMikKdmVjX3RoZXRhLmhhdF90cmVuZExfMl82aCA8LSBjYWxfdmVjX3RoZXRhLmhhdF90cmVuZChtYXRfeF90cmVuZCA9IG1hdF94X3RyZW5kTF8yXzZoLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF0X2NhcFNpZ21hX3RyZW5kID0gbWF0X2NhcFNpZ21hX3RyZW5kTF8yXzZoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZWNfeV90cmVuZCA9IHZlY195X3RyZW5kTF8yXzZoKQpzaWdtYS5oYXRfdHJlbmRMXzJfNmggPC0gY2FsX3NpZ21hLmhhdChtYXRfeCA9IG1hdF94X3RyZW5kTF8yXzZoLCB2ZWNfeSA9IHZlY195X3RyZW5kTF8yXzZoLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVjX3RoZXRhLmhhdCA9IHZlY190aGV0YS5oYXRfdHJlbmRMXzJfNmgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXRfY2FwU2lnbWEgPSBtYXRfY2FwU2lnbWFfdHJlbmRMXzJfNmgpCm1hdF92YXIudGhldGEuaGF0X3RyZW5kTF8yXzZoIDwtIGNhbF9tYXRfdmFyLnRoZXRhLmhhdChtYXRfeCA9IG1hdF94X3RyZW5kTF8yXzZoLCBzaWdtYS5oYXQgPSBzaWdtYS5oYXRfdHJlbmRMXzJfNmgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF0X2NhcFNpZ21hID0gbWF0X2NhcFNpZ21hX3RyZW5kTF8yXzZoKQpgYGAKClZhbGlkYXRlCgpgYGB7cn0KdmVjX3kuaGF0X3RyZW5kTF8yXzZoIDwtIG1hdF94X3RyZW5kTF8yXzZoICUqJSB2ZWNfdGhldGEuaGF0X3RyZW5kTF8yXzZoCnZlY19zc2UuaGF0X3RyZW5kTF8yXzZoIDwtIGNhbF92ZWNfc3NlLmhhdChtYXRfeCA9IG1hdF94X3RyZW5kTF8yXzZoLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlY195ID0gdmVjX3lfdHJlbmRMXzJfNmgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVjX3RoZXRhLmhhdCA9IHZlY190aGV0YS5oYXRfdHJlbmRMXzJfNmgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF0X2NhcFNpZ21hID0gbWF0X2NhcFNpZ21hX3RyZW5kTF8yXzZoKQptYXRfaW50ZXJ2YUNvbmZfdHJlbmRMXzJfNmggPC0gY2FsX21hdF9pbnRlcnZhbENvbmYocHJvYiA9IDAuOTUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF0X3ggPSBtYXRfeF90cmVuZExfMl82aCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZWNfdGhldGEuaGF0ID0gdmVjX3RoZXRhLmhhdF90cmVuZExfMl82aCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZWNfeSA9IHZlY195X3RyZW5kTF8yXzZoKQpgYGAKClByZWRpY3QKCmBgYHtyfQp2ZWNfbF90cmVuZExfMl82aCA8LSBjKDEsIDIsIDMsIDQpCnZlY195LnByZWRfdHJlbmRMXzJfNmggPC0gcHJlZF92ZWNfeV90cmVuZF9xdWFkcmF0aWModmVjX2wgPSB2ZWNfbF90cmVuZExfMl82aCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVjX3RoZXRhLmhhdF90cmVuZCA9IHZlY190aGV0YS5oYXRfdHJlbmRMXzJfNmgpCnZlY192YXIucHJlZF90cmVuZExfMl82aCA8LSBwcmVkX3ZlY192YXJfdHJlbmRfcXVhZHJhdGljKHZlY19sID0gdmVjX2xfdHJlbmRMXzJfNmgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXRfeF90cmVuZCA9IG1hdF94X3RyZW5kTF8yXzZoLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF0X2NhcFNpZ21hX3RyZW5kID0gbWF0X2NhcFNpZ21hX3RyZW5kTF8yXzZoLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVjX3kucHJlZF90cmVuZCA9IHZlY195LnByZWRfdHJlbmRMXzJfNmgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlY190aGV0YS5oYXRfdHJlbmQgPSB2ZWNfdGhldGEuaGF0X3RyZW5kTF8yXzZoKQptYXRfaW50ZXJ2YVByZWRfdHJlbmRMXzJfNmggPC0gY2FsX21hdF9pbnRlcnZhbFByZWQodmVjX2wgPSB2ZWNfbF90cmVuZExfMl82aCwgcHJvYiA9IDAuOTUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbiA9IG5fdHJlbmRMXzJfNmgsIHAgPSBsZW5ndGgodmVjX3RoZXRhLmhhdF90cmVuZExfMl82aCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVjX3kuaGF0ID0gdmVjX3kucHJlZF90cmVuZExfMl82aCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZWNfdmFyID0gdmVjX3Zhci5wcmVkX3RyZW5kTF8yXzZoKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gMTAsIHdhcm5pbmc9RkFMU0V9CnBsb3QoZGF0LmZfNmgkc2VyaWVzWzE6bl82aF0sIGRhdC5mXzZoJHRlbXBFeHRlcm5hbFsxOm5fNmhdLCAKICAgICB0eXBlID0gImIiLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDEsIGx0eSA9IDEsIHhsaW0gPSBjKDAsIG5fNmggKyA0KSwgeWxpbSA9IGMoLTQsIDEyKSwKICAgICBtYWluID0gcGFzdGUoIlByZWRpY3Rpb24gb2YgRXh0ZXJuYWwgVGVtcGVyYXR1cmUgYnkgUXVhZHJhdGljIExvY2FsIFRyZW5kIE1vZGVsICgiLCBsYW1iZGFfdHJlbmRMXzJfNmgsIAogICAgICAgICAgICAgICAgICAiKSB1c2luZyA2aCBEYXRhIiksIAogICAgIHhsYWIgPSAiU2VyaWVzIiwgeWxhYiA9ICJDZWxzaXVzIERlZ3JlZSIpCnBvaW50cyhuX3RyZW5kTF8yXzZoICsgc2VxKDQpLCBkYXQuZl82aCR0ZW1wRXh0ZXJuYWxbKG5fdHJlbmRMXzJfNmgrMSk6IChuX3RyZW5kTF8yXzZoKzQpXSwgCiAgICAgICB0eXBlID0gImIiLCBjb2wgPSAiYmx1ZSIsIGx0eSA9IDEsIHBjaCA9IDE2KQpsaW5lcyhkYXQuZl82aCRzZXJpZXNbKG5fNmgpOihuXzZoKzEpXSwgZGF0LmZfNmgkdGVtcEV4dGVybmFsWyhuXzZoKToobl82aCsxKV0sIAogICAgICB0eXBlID0gImMiLCBjb2wgPSAiYmx1ZSIsIGx0eSA9IDEpCiMgUGxvdCB0aGUgdmFsaWRhdGlvbiByZXN1bHQKbGluZXMoZGF0LmZfNmgkc2VyaWVzWzE6bl82aF0sIHZlY195LmhhdF90cmVuZExfMl82aCwgdHlwZSA9ICJsIiwgY29sID0gInJlZCIsIGx0eSA9IDIsIGx3ZCA9IDMpCiMgbGluZXMoZGF0LmZfNmgkc2VyaWVzWzE6bl82aF0sIG1hdF9pbnRlcnZhQ29uZl90cmVuZExfMl82aCR2ZWNfYm91bmRVcCwgdHlwZSA9ICdsJywgY29sID0gInJlZCIsIGx0eSA9IDMsIGx3ZCA9IDIpCiMgbGluZXMoZGF0LmZfNmgkc2VyaWVzWzE6bl82aF0sIG1hdF9pbnRlcnZhQ29uZl90cmVuZExfMl82aCR2ZWNfYm91bmRMb3csIHR5cGUgPSAnbCcsIGNvbCA9ICJyZWQiLCBsdHkgPSAzLCBsd2QgPSAyKQojIFBsb3QgdGhlIHByZWRpY3Rpb24gcmVzdWx0CnBvaW50cyhuX3RyZW5kTF8yXzZoICsgdmVjX2xfdHJlbmRMXzJfNmgsIHZlY195LnByZWRfdHJlbmRMXzJfNmgsIAogICAgICAgdHlwZSA9ICJiIiwgY29sID0gInJlZCIsIHBjaCA9IDE1LCBsdHkgPSAzLCBsd2QgPSAyKQpsaW5lcyhuX3RyZW5kTF8yXzZoICsgdmVjX2xfdHJlbmRMXzJfNmgsIG1hdF9pbnRlcnZhUHJlZF90cmVuZExfMl82aCR2ZWNfYm91bmRVcCwgCiAgICAgIHR5cGUgPSAiYiIsIGNvbCA9ICdyZWQnLCBsd2QgPSAxLCBsdHkgPSAxLCBwY2ggPSA2LCBjZXg9IDAuNSkKbGluZXMobl90cmVuZExfMl82aCArIHZlY19sX3RyZW5kTF8yXzZoLCBtYXRfaW50ZXJ2YVByZWRfdHJlbmRMXzJfNmgkdmVjX2JvdW5kTG93LCAKICAgICAgdHlwZSA9ICJiIiwgY29sID0gJ3JlZCcsIGx3ZCA9IDEsIGx0eSA9IDEsIHBjaCA9IDIsIGNleD0gMC41KQpsZWdlbmQoImJvdHRvbWxlZnQiLCBpbnNldCA9IC4wMiwgbGVnZW5kID0gYygiVHJhaW5pbmcgRGF0YSIsICJUZXN0aW5nIERhdGEiLCAiVHJlbmQgTW9kZWwiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlByZWRpY3Rpb24iLCAiUHJlZCBJbnRlcnZhbCIpLCAKICAgICAgIGNvbCA9IGMoImJsdWUiLCAiYmx1ZSIsICJyZWQiLCAicmVkIiwgInJlZCIpLCBwY2ggPSBjKDEsIDE2LCBOQSwgMTUsIDYpLCAKICAgICAgIGx0eSA9IGMoMSwgMSwgMiwgMywgMSksIGx3ZCA9IGMoMSwgMSwgMywgMywgMSkpCmBgYAoKIyBRdWVzdGlvbiA0CgpUcmVuZCBDb21wb25lbnQgb2YgU29sYXIgSXJyYWRpYXRpb24KCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gMTB9CmxpYnJhcnkoZm9yZWNhc3QpCnRzX3RyZW5kX2lTb2xhciA9IG1hKGRhdC5mXzZoJGlTb2xhclsxOiBuXzZoXSwgb3JkZXIgPSA0LCBjZW50cmUgPSBUKQpwbG90KGRhdC5mXzZoJHNlcmllc1sxOiBuXzZoXSwgZGF0LmZfNmgkaVNvbGFyWzE6IG5fNmhdLCB0eXBlID0gImwiLCBjb2wgPSAiYmx1ZSIsIGx0eSA9IDEsIGx3ZCA9IDIsIAogICAgIG1haW4gPSAiVHJlbmQgQ29tcG9uZW50IG9mIFNvbGFyIElycmFkaWF0aW9uIiwgeGxhYiA9ICJTZXJpZXMiLCB5bGFiID0gIlcgLyBtMiIpCmxpbmVzKGRhdC5mXzZoJHNlcmllc1sxOiBuXzZoXSwgdHNfdHJlbmRfaVNvbGFyLCBjb2wgPSAicmVkIiwgbHR5ID0gMiwgbHdkID0gMikKYGBgCgpgYGB7ciwgd2FybmluZz1GQUxTRSwgZmlnLmhlaWdodCA9IDUsIGZpZy53aWR0aCA9IDEwfQp0c19kZXRyZW5kX2lTb2xhciA9IGRhdC5mXzZoJGlTb2xhclsxOiBuXzZoXSAvIHRzX3RyZW5kX2lTb2xhcgpwbG90KGRhdC5mXzZoJHNlcmllc1sxOiBuXzZoXSwgdHNfZGV0cmVuZF9pU29sYXIsIHR5cGUgPSAibCIsIGNvbCA9ICJibHVlIiwgbHR5ID0gMSwgbHdkID0gMiwgCiAgICAgbWFpbiA9ICJTZWFzb25hbCBDb21wb25lbnQgb2YgU29sYXIgSXJyYWRpYXRpb24iLCB4bGFiID0gIlNlcmllcyIsIHlsYWIgPSAiVyAvIG0yIikKYGBgCgpgYGB7ciwgd2FybmluZz1GQUxTRSwgZmlnLmhlaWdodCA9IDUsIGZpZy53aWR0aCA9IDEwfQptYXRfaVNvbGFyID0gdChtYXRyaXgoZGF0YSA9IHRzX2RldHJlbmRfaVNvbGFyLCBucm93ID0gNCkpCnZlY19zZWFzb25faVNvbGFyID0gY29sTWVhbnMobWF0X2lTb2xhciwgbmEucm0gPSBUKQpwbG90KHJlcCh2ZWNfc2Vhc29uX2lTb2xhciwgOSksIHR5cGUgPSAibCIsIGNvbCA9ICJibHVlIiwgbHR5ID0gMSwgbHdkID0gMiwgCiAgICAgbWFpbiA9ICJBdmVyYWdlZCBTZWFzb25hbCBDb21wb25lbnQgb2YgU29sYXIgSXJyYWRpYXRpb24iLCB4bGFiID0gIlNlcmllcyIsIHlsYWIgPSAiVyAvIG0yIikKYGBgCgpgYGB7ciwgd2FybmluZz1GQUxTRSwgZmlnLmhlaWdodCA9IDUsIGZpZy53aWR0aCA9IDEwfQp0c19lcHNpbG9uX2lTb2xhciA9IGRhdC5mXzZoJGlTb2xhclsxOiBuXzZoXSAvICh0c190cmVuZF9pU29sYXIgKiB2ZWNfc2Vhc29uX2lTb2xhcikKcGxvdCh0c19lcHNpbG9uX2lTb2xhciwgdHlwZSA9ICJsIiwgY29sID0gImJsdWUiLCBsdHkgPSAxLCBsd2QgPSAyLCAKICAgICBtYWluID0gIkVwc2lsb24gQ29tcG9uZW50IG9mIFNvbGFyIElycmFkaWF0aW9uIiwgeGxhYiA9ICJTZXJpZXMiLCB5bGFiID0gIlcgLyBtMiIpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQgPSA1LCBmaWcud2lkdGggPSAxMCwgd2FybmluZz1GQUxTRX0KdHNfcmVjb21wb3NlZF9pU29sYXIgPSB0c190cmVuZF9pU29sYXIgKiB2ZWNfc2Vhc29uX2lTb2xhciAqIHRzX2Vwc2lsb25faVNvbGFyCnBsb3QoZGF0LmZfNmgkc2VyaWVzWzE6IG5fNmhdLCB0c19yZWNvbXBvc2VkX2lTb2xhciwgdHlwZSA9ICJsIiwgY29sID0gInJlZCIsIGx0eSA9IDIsIGx3ZCA9IDMsIAogICAgIG1haW4gPSAiUmVjb21wb3NlZCBTb2xhciBJcnJhZGlhdGlvbiBhbmQgT3JpZ2luYWwgRGF0YSIsIHhsYWIgPSAiU2VyaWVzIiwgeWxhYiA9ICJXIC8gbTIiKQpsaW5lcyhkYXQuZl82aCRzZXJpZXNbMTogbl82aF0sIGRhdC5mXzZoJGlTb2xhclsxOiBuXzZoXSwgY29sID0gImJsdWUiLCBsdHkgPSAxLCBsd2QgPSAxKQpgYGAKClByZWRpY3QgdGhlIHNvbGFyIGlycmFkaWF0aW9uIGluIHRoZSBsYXN0IGRheQoKYGBge3J9Cm5fdHJlbmRMXzNfNmggPC0gbl82aCAtIDQKbGFtYmRhX3RyZW5kTF8zXzZoIDwtIDAuOAptYXRfY2FwU2lnbWFfdHJlbmRMXzNfNmggPC0gZG9fbWF0X2NhcFNpZ21hX3RyZW5kKGxhbWJkYSA9IGxhbWJkYV90cmVuZExfM182aCwgbiA9IG5fdHJlbmRMXzNfNmgpCnZlY195X3RyZW5kTF8zXzZoIDwtIGFzLm51bWVyaWModHNfdHJlbmRfaVNvbGFyKVszOiAzNl0Kc2VxX3pkaV90cmVuZExfM182aCA8LSBkb19zZXFfemVyb0RlY3JlYXNlUmV2KG5fdHJlbmRMXzNfNmgpCm1hdF94X3RyZW5kTF8zXzZoIDwtIGNiaW5kKDEsIHNlcV96ZGlfdHJlbmRMXzNfNmgsIHNlcV96ZGlfdHJlbmRMXzNfNmheMiAvIDIpCnZlY190aGV0YS5oYXRfdHJlbmRMXzNfNmggPC0gY2FsX3ZlY190aGV0YS5oYXRfdHJlbmQobWF0X3hfdHJlbmQgPSBtYXRfeF90cmVuZExfM182aCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF0X2NhcFNpZ21hX3RyZW5kID0gbWF0X2NhcFNpZ21hX3RyZW5kTF8zXzZoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlY195X3RyZW5kID0gdmVjX3lfdHJlbmRMXzNfNmgpCnNpZ21hLmhhdF90cmVuZExfM182aCA8LSBjYWxfc2lnbWEuaGF0KG1hdF94ID0gbWF0X3hfdHJlbmRMXzNfNmgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZWNfeSA9IHZlY195X3RyZW5kTF8zXzZoLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVjX3RoZXRhLmhhdCA9IHZlY190aGV0YS5oYXRfdHJlbmRMXzNfNmgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXRfY2FwU2lnbWEgPSBtYXRfY2FwU2lnbWFfdHJlbmRMXzNfNmgpCm1hdF92YXIudGhldGEuaGF0X3RyZW5kTF8zXzZoIDwtIGNhbF9tYXRfdmFyLnRoZXRhLmhhdChtYXRfeCA9IG1hdF94X3RyZW5kTF8zXzZoLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZ21hLmhhdCA9IHNpZ21hLmhhdF90cmVuZExfM182aCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXRfY2FwU2lnbWEgPSBtYXRfY2FwU2lnbWFfdHJlbmRMXzNfNmgpCmBgYAoKYGBge3J9CnZlY195LmhhdF90cmVuZExfM182aCA8LSBtYXRfeF90cmVuZExfM182aCAlKiUgdmVjX3RoZXRhLmhhdF90cmVuZExfM182aApgYGAKCgpgYGB7cn0KdmVjX2xfdHJlbmRMXzNfNmggPC0gYygzLCA0LCA1LCA2KQp2ZWNfeS5wcmVkX3RyZW5kTF8zXzZoIDwtIHByZWRfdmVjX3lfdHJlbmRfcXVhZHJhdGljKHZlY19sID0gdmVjX2xfdHJlbmRMXzNfNmgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlY190aGV0YS5oYXRfdHJlbmQgPSB2ZWNfdGhldGEuaGF0X3RyZW5kTF8zXzZoKQp2ZWNfeS5wcmVkX3RyZW5kTF8zXzZoWzFdIDwtIHZlY195LnByZWRfdHJlbmRMXzNfNmhbMV0gKiB2ZWNfc2Vhc29uX2lTb2xhclszXQp2ZWNfeS5wcmVkX3RyZW5kTF8zXzZoWzJdIDwtIHZlY195LnByZWRfdHJlbmRMXzNfNmhbMl0gKiB2ZWNfc2Vhc29uX2lTb2xhcls0XQp2ZWNfeS5wcmVkX3RyZW5kTF8zXzZoWzNdIDwtIHZlY195LnByZWRfdHJlbmRMXzNfNmhbM10gKiB2ZWNfc2Vhc29uX2lTb2xhclsxXQp2ZWNfeS5wcmVkX3RyZW5kTF8zXzZoWzRdIDwtIHZlY195LnByZWRfdHJlbmRMXzNfNmhbNF0gKiB2ZWNfc2Vhc29uX2lTb2xhclsyXQp2ZWNfdmFyLnByZWRfdHJlbmRMXzNfNmggPC0gcHJlZF92ZWNfdmFyX3RyZW5kX3F1YWRyYXRpYyh2ZWNfbCA9IHZlY19sX3RyZW5kTF8zXzZoLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF0X3hfdHJlbmQgPSBtYXRfeF90cmVuZExfM182aCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hdF9jYXBTaWdtYV90cmVuZCA9IG1hdF9jYXBTaWdtYV90cmVuZExfM182aCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlY195LnByZWRfdHJlbmQgPSB2ZWNfeS5wcmVkX3RyZW5kTF8zXzZoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZWNfdGhldGEuaGF0X3RyZW5kID0gdmVjX3RoZXRhLmhhdF90cmVuZExfM182aCkKbWF0X2ludGVydmFQcmVkX3RyZW5kTF8zXzZoIDwtIGNhbF9tYXRfaW50ZXJ2YWxQcmVkKHZlY19sID0gdmVjX2xfdHJlbmRMXzNfNmgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvYiA9IDAuOTUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbiA9IG5fdHJlbmRMXzNfNmgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcCA9IGxlbmd0aCh2ZWNfdGhldGEuaGF0X3RyZW5kTF8zXzZoKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZWNfeS5oYXQgPSB2ZWNfeS5wcmVkX3RyZW5kTF8zXzZoLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlY192YXIgPSB2ZWNfdmFyLnByZWRfdHJlbmRMXzNfNmgpCm1hdF9pbnRlcnZhUHJlZF90cmVuZExfM182aCR2ZWNfYm91bmRVcFsxXSA8LSBtYXRfaW50ZXJ2YVByZWRfdHJlbmRMXzNfNmgkdmVjX2JvdW5kVXBbMV0gKiB2ZWNfc2Vhc29uX2lTb2xhclszXQptYXRfaW50ZXJ2YVByZWRfdHJlbmRMXzNfNmgkdmVjX2JvdW5kVXBbMl0gPC0gbWF0X2ludGVydmFQcmVkX3RyZW5kTF8zXzZoJHZlY19ib3VuZFVwWzJdICogdmVjX3NlYXNvbl9pU29sYXJbNF0KbWF0X2ludGVydmFQcmVkX3RyZW5kTF8zXzZoJHZlY19ib3VuZFVwWzNdIDwtIG1hdF9pbnRlcnZhUHJlZF90cmVuZExfM182aCR2ZWNfYm91bmRVcFszXSAqIHZlY19zZWFzb25faVNvbGFyWzFdCm1hdF9pbnRlcnZhUHJlZF90cmVuZExfM182aCR2ZWNfYm91bmRVcFs0XSA8LSBtYXRfaW50ZXJ2YVByZWRfdHJlbmRMXzNfNmgkdmVjX2JvdW5kVXBbNF0gKiB2ZWNfc2Vhc29uX2lTb2xhclsyXQptYXRfaW50ZXJ2YVByZWRfdHJlbmRMXzNfNmgkdmVjX2JvdW5kTG93WzFdIDwtIG1hdF9pbnRlcnZhUHJlZF90cmVuZExfM182aCR2ZWNfYm91bmRMb3dbMV0gKiB2ZWNfc2Vhc29uX2lTb2xhclszXQptYXRfaW50ZXJ2YVByZWRfdHJlbmRMXzNfNmgkdmVjX2JvdW5kTG93WzJdIDwtIG1hdF9pbnRlcnZhUHJlZF90cmVuZExfM182aCR2ZWNfYm91bmRMb3dbMl0gKiB2ZWNfc2Vhc29uX2lTb2xhcls0XQptYXRfaW50ZXJ2YVByZWRfdHJlbmRMXzNfNmgkdmVjX2JvdW5kTG93WzNdIDwtIG1hdF9pbnRlcnZhUHJlZF90cmVuZExfM182aCR2ZWNfYm91bmRMb3dbM10gKiB2ZWNfc2Vhc29uX2lTb2xhclsxXQptYXRfaW50ZXJ2YVByZWRfdHJlbmRMXzNfNmgkdmVjX2JvdW5kTG93WzRdIDwtIG1hdF9pbnRlcnZhUHJlZF90cmVuZExfM182aCR2ZWNfYm91bmRMb3dbNF0gKiB2ZWNfc2Vhc29uX2lTb2xhclsyXQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gMTAsIHdhcm5pbmc9RkFMU0V9CnBsb3QoZGF0LmZfNmgkc2VyaWVzWzE6bl82aF0sIGRhdC5mXzZoJGlTb2xhclsxOm5fNmhdLCAKICAgICB0eXBlID0gImIiLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDEsIGx0eSA9IDEsIHhsaW0gPSBjKDAsIDQyKSwgeWxpbSA9IGMoMCwgNDAwKSwKICAgICBtYWluID0gcGFzdGUoIlByZWRpY3Rpb24gb2YgU29sYXIgSXJyYWRpYXRpb24gYnkgU2Vhc29uYWwgTG9jYWwgVHJlbmQgTW9kZWwgKCIsIGxhbWJkYV90cmVuZExfM182aCwgCiAgICAgICAgICAgICAgICAgICIpIHVzaW5nIDZoLXNhbXBsaW5nIERhdGEiKSwgCiAgICAgeGxhYiA9ICJTZXJpZXMiLCB5bGFiID0gIkNlbHNpdXMgRGVncmVlIikKbGluZXMoZGF0LmZfNmgkc2VyaWVzWyhuXzZoKzEpOihuXzZoKzQpXSwgZGF0LmZfNmgkaVNvbGFyWyhuXzZoKzEpOihuXzZoKzQpXSwgCiAgICAgIHR5cGUgPSAiYiIsIGNvbCA9ICJibHVlIiwgbHdkID0gMSwgbHR5ID0gMSwgcGNoID0gMTYpCmxpbmVzKGRhdC5mXzZoJHNlcmllc1sobl82aCk6KG5fNmgrMSldLCBkYXQuZl82aCRpU29sYXJbKG5fNmgpOihuXzZoKzEpXSwgCiAgICAgIHR5cGUgPSAiYyIsIGNvbCA9ICJibHVlIiwgbHdkID0gMSwgbHR5ID0gMSkKIyBQbG90IHRoZSBWYWxpZGF0aW9uIFJlc3VsdApsaW5lcyhkYXQuZl82aCRzZXJpZXNbMzogKG5fNmgtMildLCB2ZWNfeS5oYXRfdHJlbmRMXzNfNmgsIAogICAgICB0eXBlID0gImwiLCBjb2wgPSAicmVkIiwgbHR5ID0gMiwgbHdkID0gMykKIyBsaW5lcyh0c190cmVuZF9pU29sYXIgKiB2ZWNfc2Vhc29uX2lTb2xhciwgY29sID0gJ3JlZCcsIGx0eSA9IDMsIGx3ZCA9IDIpCiMgUGxvdCB0aGUgcHJlZGljdGlvbiBSZXN1bHQKbGluZXMoMiArIG5fdHJlbmRMXzNfNmggKyB2ZWNfbF90cmVuZExfM182aCwgdmVjX3kucHJlZF90cmVuZExfM182aCwgCiAgICAgIHR5cGUgPSAiYiIsIGNvbCA9ICJyZWQiLCBwY2ggPSAxNSwgbHR5ID0gMywgbHdkID0gMykKcG9pbnRzKDIgKyBuX3RyZW5kTF8zXzZoICsgdmVjX2xfdHJlbmRMXzNfNmgsIG1hdF9pbnRlcnZhUHJlZF90cmVuZExfM182aCR2ZWNfYm91bmRVcCwgY29sID0gJ3JlZCcsIHBjaCA9IDYsIGNleD0gMC41KQpwb2ludHMoMiArIG5fdHJlbmRMXzNfNmggKyB2ZWNfbF90cmVuZExfM182aCwgbWF0X2ludGVydmFQcmVkX3RyZW5kTF8zXzZoJHZlY19ib3VuZExvdywgY29sID0gJ3JlZCcsIHBjaCA9IDIsIGNleD0gMC41KQpsZWdlbmQoInRvcGxlZnQiLCBpbnNldCA9IC4wMiwgbGVnZW5kID0gYygiVHJhaW5pbmcgRGF0YSIsICJUZXN0aW5nIERhdGEiLCAiVHJlbmQgQ29tcG8iLCAiUHJlZGljdGlvbiIsICJQcmVkIEludGVydmFsIiksIAogICAgICAgY29sID0gYygiYmx1ZSIsICJibHVlIiwgInJlZCIsICJyZWQiLCAicmVkIiksIHBjaCA9IGMoMSwgMTYsIE5BLCAxNSwgNiksIAogICAgICAgbHR5ID0gYygxLCAxLCAyLCAzLCAxKSwgbHdkID0gYygxLCAxLCAzLCAzLCAxKSwgY2V4ID0gMC44KQpgYGAKClByZWRpY3QgdGhlIG9ic2VydmF0aW9ucyBmb3IgdGhlIGxhc3QgZGF5ICh0ZXN0IGRhdGEpIG9mIHRoZSBzcGF0aWFsIGhlYXRpbmcgYmFzZWQgb24gdGhlIDZoIGRhdGEuIEZvciB0aGlzLCB1c2UgdGhlIGVzdGltYXRlZCBtb2RlbCBpbiBxdWVzdGlvbiAxLjIgYW5kIHRoZSBvdXRkb29yIHRlbXBlcmF0dXJlIGZyb20gcXVlc3Rpb24gMS4zLiAKCmBgYHtyfQptYXRfeC5wcmVkXzJfNmggPC0gY2JpbmQocmVwKDEsIDQpLCB2ZWNfeS5wcmVkX3RyZW5kTF8yXzZoLCB2ZWNfeS5wcmVkX3RyZW5kTF8zXzZoKSAKdmVjX3kucHJlZF8yXzZoICA8LSBtYXRfeC5wcmVkXzJfNmggJSolIHZlY190aGV0YS5oYXRfZXhwRGVjYXlfNmgKYGBgCgpgYGB7ciwgZmlnLmhlaWdodCA9IDUsIGZpZy53aWR0aCA9IDEwLCB3YXJuaW5nPUZBTFNFfQpwbG90KGRhdC5mXzZoJHNlcmllc1sxOihuXzZoKV0sIGRhdC5mXzZoJGhlYXRpbmdbMToobl82aCldLCAKICAgICB0eXBlID0gImIiLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDEsIGx0eSA9IDEsIHhsaW0gPSBjKDAsIDQyKSwKICAgICBtYWluID0gIlByZWRpY3RlZCBIZWF0aW5nIGluIHRoZSBsYXN0IERheSB1c2luZyA2aCBEYXRhIiwgeGxhYiA9ICJTZXJpZXMiLCB5bGFiID0gIlciKQpsaW5lcyhkYXQuZl82aCRzZXJpZXNbKG5fNmgrMSk6KG5fNmgrNCldLCBkYXQuZl82aCRoZWF0aW5nWyhuXzZoKzEpOihuXzZoKzQpXSwgCiAgICAgIHR5cGUgPSAiYiIsIGNvbCA9ICJibHVlIiwgbHR5ID0gMSwgcGNoID0gMTYpCmxpbmVzKGRhdC5mXzZoJHNlcmllc1sobl82aCk6KG5fNmgrMSldLCBkYXQuZl82aCRoZWF0aW5nWyhuXzZoKToobl82aCsxKV0sIAogICAgICB0eXBlID0gImMiLCBjb2wgPSAiYmx1ZSIsIGx0eSA9IDEpCmxlZ2VuZCgidG9wbGVmdCIsIGluc2V0ID0gLjAyLCBsZWdlbmQgPSBjKCJUcmFpbmluZyBEYXRhIiwgIlRlc3RpbmcgRGF0YSIsICJQcmVkaWN0aW9uIiksIGNvbCA9IGMoImJsdWUiLCAiYmx1ZSIsICJyZWQiKSwgCiAgICAgICBwY2ggPSBjKDEsIDE2LCAxNSksIGx0eSA9IGMoMSwgMSwgMyksIGx3ZCA9IGMoMSwgMSwgMiksIGNleCA9IDAuOCkKIyBQbG90IHRoZSBwcmVkaWN0aW9uIHJlc3VsdApsaW5lcyhkYXQuZl82aCRzZXJpZXNbKG5fNmgrMSk6KG5fNmgrNCldLCB2ZWNfeS5wcmVkXzJfNmgsIAogICAgICB0eXBlID0gImIiLCBjb2wgPSAicmVkIiwgcGNoID0gMTUsIGx0eSA9IDMsIGx3ZCA9IDIpCmBgYAoKCgojIEFwcGVuZGl4CgpgYGB7cn0KIyBDYWxjdWxhdGUgdGhlIGNhcEYgYW5kIGggaW4gc2NhbGFyIHdheQpmdW5jX2NhcEZfbGluZWFyIDwtIGZ1bmN0aW9uKG4sIGxhbWJkYSl7CiAgICBhbGwgPC0gMAogICAgZm9yIChqIGluIDA6IChuLTEpKXsKICAgICAgICBhbGwgPC0gYWxsICsgZnVuY19mX2xpbmVhcigtaikgJSolIHQoZnVuY19mX2xpbmVhcigtaikpCiAgICB9CiAgICByZXR1cm4oYWxsKQp9CmZ1bmNfaF9saW5lYXIgPC0gZnVuY3Rpb24obiwgbGFtYmRhLCB2ZWNfeSl7CiAgICBhbGwgPC0gMAogICAgZm9yIChqIGluIDA6IChuLTEpKXsKICAgICAgICBhbGwgPC0gYWxsICsgZnVuY19mX2xpbmVhcigtaikgJSolIHZlY195CiAgICB9CiAgICByZXR1cm4oYWxsKQp9CmBgYAoKYGBge3J9CmNhbF9tYXRfaW50ZXJ2YWxDb25mIDwtIGZ1bmN0aW9uKHByb2IgPSAwLjk1LCBtYXRfeCwgdmVjX3RoZXRhLmhhdCwgc3NlLmhhdCl7CiAgICBuIDwtIGxlbmd0aChtYXRfeFssMV0pCiAgICBwIDwtIGxlbmd0aCh2ZWNfdGhldGEuaGF0KQogICAgcXVhbnRpbGVTdHVkZW50RGlzdCA8LSBxdChwID0gcHJvYiwgZGYgPSBuIC0gcCkgCiAgICB2ZWNfYm91bmRVcCA8LSBtYXRfeCAlKiUgdmVjX3RoZXRhLmhhdCArIHJlcChxdWFudGlsZVN0dWRlbnREaXN0ICogc3FydChzc2UuaGF0IC8gbiksIG4pCiAgICB2ZWNfYm91bmRMb3cgPC0gbWF0X3ggJSolIHZlY190aGV0YS5oYXQgLSByZXAocXVhbnRpbGVTdHVkZW50RGlzdCAqIHNxcnQoc3NlLmhhdCAvIG4pLCBuKQogICAgcmV0dXJuKGxpc3QodmVjX2JvdW5kVXAgPSB2ZWNfYm91bmRVcCwgdmVjX2JvdW5kTG93ID0gdmVjX2JvdW5kTG93KSkKfQpgYGAKCg==