2. Data Processing
frameData_1 <- function(){
dat <- read.table("windpowerforecasts.dat", header = T, sep = ";")
t_out <- dat[ , 1]
t_in <- dat[ , 2]
predStep <- dat[ , 3]
realMeasure <- dat[ , 4] / 10^3
predValue <- dat[ , 5] / 10^3
quan_5 <- dat[ , 6] / 10^3
quan_10 <- dat[ , 7] / 10^3
quan_15 <- dat[ , 8] / 10^3
quan_20 <- dat[ , 9] / 10^3
quan_25 <- dat[ , 10] / 10^3
quan_30 <- dat[ , 11] / 10^3
quan_35 <- dat[ , 12] / 10^3
quan_40 <- dat[ , 13] / 10^3
quan_45 <- dat[ , 14] / 10^3
quan_50 <- dat[ , 15] / 10^3
quan_55 <- dat[ , 16] / 10^3
quan_60 <- dat[ , 17] / 10^3
quan_65 <- dat[ , 18] / 10^3
quan_70 <- dat[ , 19] / 10^3
quan_75 <- dat[ , 20] / 10^3
quan_80 <- dat[ , 21] / 10^3
quan_85 <- dat[ , 22] / 10^3
quan_90 <- dat[ , 23] / 10^3
quan_95 <- dat[ , 24] / 10^3
quan_100 <- quan_95
quan_0 <- quan_5
dat.f <- data.frame(t_out, t_in, predStep, predValue, realMeasure, quan_95, quan_90, quan_85, quan_80, quan_75,
quan_70, quan_65, quan_60, quan_55, quan_50, quan_45, quan_40, quan_35, quan_30, quan_25,
quan_20, quan_15, quan_10, quan_5, quan_100, quan_0)
# Clean the data
t_in.time <- as.numeric(substr(dat.f$t_in, 9, 10))
dat.f["t_in.time"] <- t_in.time
dat.f <- dat.f[dat.f$t_in.time == 11, ]
dat.f <- dat.f[is.element(dat.f$predStep, seq(13, 36)), ]
dat.f <- dat.f[1:8760, ]
dat.f$t_in.time <- NULL
dat.f$t_in <- NULL
# Label the data
dat.f["time"] <- rep(seq(0, 23), 365)
vec_month <- as.numeric(substr(dat.f$t_out, 5, 6))
dat.f["month"] <- vec_month
vec_day <- as.numeric(substr(dat.f$t_out, 7, 8))
dat.f["day"] <- vec_day
# Return clean data
dat.f$t_out <- NULL
return(dat.f)
}
dat.f_q_17 <- frameData_1()
rm(frameData_1)
frameData_2 <- function(str_dat){
dat <- read.csv(str_dat, header = T, sep = ";")
seq <- dat[ , 1]
month <- dat[ , 4]
day <- dat[ , 5]
week <- dat[ , 6]
time <- dat[ , 7]
d <- dat[ , 8]
d[is.na(d)] <- 0
up <- dat[ , 9]
up[is.na(up)] <- 0
dw <- dat[ , 10]
dw[is.na(dw)] <- 0
dat.f <- data.frame(seq, month, week, day, time, d, up, dw)
return(dat.f)
}
dat.f_p_16 <- frameData_2("price_16.csv")
dat.f_p_16 <- dat.f_p_16[1: 8784, ] # 366 days
dat.f_p_17 <- frameData_2("price_17.csv")
dat.f_p_17 <- dat.f_p_17[1: 8760, ] # 365 days
rm(frameData_2)
Calculate Balancing Price in 2016
#' Function to Calculate Balancing Price
cal_price_b <- function(dat, num_days){
vec_price_b <- rep(0, length(dat$seq))
for (i in 1: num_days){
if (!is.na(dat$d[i])){
if (abs(dat$up[i] - dat$d[i]) <= abs(dat$dw[i] - dat$d[i])){
# dat$d[i] is more next to dat$dw[i], choose the other one
vec_price_b[i] <- dat$dw[i]
}
else if (abs(dat$up[i] - dat$d[i]) >= abs(dat$dw[i] - dat$d[i])){
vec_price_b[i] <- dat$up[i]
}
}
}
return(vec_price_b)
}
dat.f_p_16["b"] <- cal_price_b(dat.f_p_16, 8784)
dat.f_p_17["b"] <- cal_price_b(dat.f_p_17, 8760)
3. About Day-Ahead Price
3.1 Box Plot of Day-Ahead Price
sum(dat.f_p_16$d) / 8784
[1] 198.5279
par(bty="n")
plot(factor(dat.f_p_16$month), dat.f_p_16$d, main = "Box Plot of Day-Ahead Price By Months in the Year 2016",
xlab = "Month", ylab = "Price")
lines(c(1, 12), c(ave_p_16_d, ave_p_16_d), lty = 2, col = "red", lwd = 3)
legend("bottomleft", inset = .02, legend = "Yearly Average", col = "red", lty = 2, lwd = 3)

par(bty="n")
plot(factor(dat.f_p_16$time), dat.f_p_16$d, main = "Box Plot of Day-Ahead Price By Hours in the Year 2016",
xlab = "Hour", ylab = "Price")
lines(c(1, 24), c(ave_p_16_d, ave_p_16_d), lty = 2, col = "red", lwd = 3)
legend("bottomleft", inset = .02, legend = "Yearly Average", col = "red", lty = 2, lwd = 3)

plotBoxPlotTwo <- function(dat.f, ave){
# Divide the data to clusters
vec_index <- rep(0, 8784)
vec_index[(is.element(dat.f$time, c(23, seq(0, 6)))) & (is.element(dat.f$month, c(10, 11, 12, 1)))] <- 1
vec_index[(is.element(dat.f$time, seq(7, 18))) & (is.element(dat.f$month, c(10, 11, 12, 1)))] <- 2
vec_index[(is.element(dat.f$time, seq(19, 22))) & (is.element(dat.f$month, c(10, 11, 12, 1)))] <- 3
vec_index[(is.element(dat.f$time, c(23, seq(0, 6)))) & (is.element(dat.f$month, seq(2, 5)))] <- 4
vec_index[(is.element(dat.f$time, seq(7, 18))) & (is.element(dat.f$month, seq(2, 5)))] <- 5
vec_index[(is.element(dat.f$time, seq(19, 22))) & (is.element(dat.f$month, seq(2, 5)))] <- 6
dat.f_new <- data.frame(d = dat.f$d, index = vec_index)
#
par(bty = "n")
plot(factor(dat.f_new$index), dat.f_new$d, main = "Box Plot of Day-Ahead Price By Clusters in the Year 2016",
xlab = "Cluster", ylab = "Price", xaxt = "n")
axis(1, at = seq(1, 7), label = c("others", "Oct-Jan/0-6", "Oct-Jan/7-18", "Oct-Jan/19-22",
"Feb-May/0-6", "Feb-May/7-18", "Feb-May/19-22"), las = 0, outer = FALSE)
lines(c(1, 7), c(ave, ave), lty = 2, col = "red", lwd = 3)
legend("bottomleft", inset = .02, legend = "Yearly Average", col = "red", lty = 2, lwd = 3)
}
plotBoxPlotTwo(dat.f_p_16, ave_p_16_d)

3.1 Correlation Matrix of Prices over One Day
mat_p_16.h <- matrix(nrow = 366, ncol = 24)
for (i in 1: 24){
mat_p_16.h[ , i] <- dat.f_p_16[(dat.f_p_16$time == i-1), ]$d
}
# Using function heatmap.2 in library gplots to visualize the correlation matrix
heatmap.2(cor(mat_p_16.h[ , 1: 24]), dendrogram = "none", trace="none", Rowv = F, Colv = F)

3.2 Price Prediction using Expected Value
vec_p_mean.day_16 <- rep(0, 24)
for (i in 0: 23){
vec_p_mean.day_16[i+1]<- mean(dat.f_p_16[(dat.f_p_16$time == i), ]$d[!is.na(dat.f_p_16[(dat.f_p_16$time == i), ]$d)])
}; rm(i)
plot(seq(0, 23), vec_p_mean.day_16, type = "l", col = "blue", lwd = 2, lty = 1, xaxt = "n", bty = "n",
main = paste("Expected Day-Ahead Price of All Hours in a Future Day"), xlab = "Hour in one Day", ylab = "Price")
axis(1, at = seq(0, 23), label = seq(1, 24), las = 0, outer = FALSE)

3.3 Predict the Day-Ahead Price using Predicted Wind Power Generation
Update the regression relationship between predicted wind power generation and day-ahead price.
Because there will be more wind power generation in other companies as well, so the price may decrease. The aggregation of renewable generation can impact a lot on the day-ahead clearing price and the effect may be stable.
4. Prediction of Balancing Price
4.1 Regression Relationship between Day-ahead Price and Balancing Price
Predict the Balancing Price using Regression between Predicted Day-Ahead Price
plotPriceRegression <- function(dat.f_p){
reg_p_16 <- glm(dat.f_p_16$b ~ dat.f_p_16$d)
# confint(reg_p_16, level = 0.95)
intConf_p_16 <- predict.lm(reg_p_16, interval = "conf", level = 0.95)
plot(dat.f_p_16$d, dat.f_p_16$b, col = "blue", yaxt = "n", bty = "n",
xlab = "Day-Ahead Price", ylab = "Balancing Price",
ylim = c(-500, 2500), main = paste("Regression Relationship Between Day-Ahead Price and Balancing Price"))
lines(c(-400, 800), reg_p_16$coefficients[1] + reg_p_16$coefficients[2] * c(-400, 800), col = "red", lwd = 2)
lines(dat.f_p_16$d, intConf_p_16[, 2], lty = 2, col = "black", lwd = 0.5)
lines(dat.f_p_16$d, intConf_p_16[, 3], lty = 2, col = "black", lwd = 0.5)
axis(2, at = seq(-500, 2500, by = 500), las = 0, outer = FALSE)
legend("topleft", inset = .02, legend = c("Observation", "Regression", "95% Confidence Interval"),
col = c("blue", "red", "black"), lty = c(NULL, 1, 2), lwd = c(NaN, 2, 0.5), pch = c(1, NaN, NaN))
}
plotPriceRegression(dat.f_p_16)

4.2 Multivariate Regression Model Between Day-Ahead Price and Balancing Price
# Construct matrix for price
mat_p_16.d <- matrix(ncol = 366, nrow = 24)
mat_p_16.b <- matrix(ncol = 366, nrow = 24)
for (i in 1: 24){
mat_p_16.d[i, ] <- dat.f_p_16[(dat.f_p_16$time == i-1),]$d
mat_p_16.b[i, ] <- dat.f_p_16[(dat.f_p_16$time == i-1),]$b
}
# Calculate the Regression Coefficient
mat <- matrix(ncol = 25, nrow = 24)
vec_mu <- rep(0, 24)
for (i in 1: 24){
mat[i, ] <- glm(mat_p_16.b[i, ] ~ mat_p_16.d[1, ] + mat_p_16.d[2, ] + mat_p_16.d[3, ] +
mat_p_16.d[4, ] + mat_p_16.d[5, ] + mat_p_16.d[6, ] +
mat_p_16.d[7, ] + mat_p_16.d[8, ] + mat_p_16.d[9, ] +
mat_p_16.d[10, ] + mat_p_16.d[11, ] + mat_p_16.d[12, ] +
mat_p_16.d[13, ] + mat_p_16.d[14, ] + mat_p_16.d[15, ] +
mat_p_16.d[16, ] + mat_p_16.d[17, ] + mat_p_16.d[18, ] +
mat_p_16.d[19, ] + mat_p_16.d[20, ] + mat_p_16.d[21, ] +
mat_p_16.d[22, ] + mat_p_16.d[23, ] + mat_p_16.d[24, ])$coefficients[1:25]
}
vec_mu <- mat[ , 1]
mat_c <- mat[ , 2: 25]
rm(mat)
# Check the result
all((mat_c - cov(t(mat_p_16.b), t(mat_p_16.d)) %*% solve(cov(t(mat_p_16.d)))) < 0.000001)
[1] TRUE
5 Trading Strategies
#' Function to trade in day-ahead market and calculate the revenue
tradeDayAhead <- function(vec_e_d, vec_p_d){
vec_r_d <- vec_e_d * vec_p_d
return(vec_r_d)
}
#' Function to get the real measured values in that day
getRealValue <- function(vec_p_d_all, vec_p_b_all, vec_e_all, day){
# list_realValue <- getRealValue(dat.f_p$d, dat.f_p$b, dat.f_q$realMeasure)
vec_p_d <- vec_p_d_all[(24 * (day-1) + 1): (24 * (day-1) + 24)]
vec_p_b <- vec_p_b_all[(24 * (day-1) + 1): (24 * (day-1) + 24)]
vec_e <- vec_e_all[(24 * (day-1) + 1): (24 * (day-1) + 24)]
return(list(d = vec_p_d, b = vec_p_b, e = vec_e))
}
#' Function to trade in balancing market and calculate the revenue
tradeBalancing <- function(vec_e_d, vec_e, vec_p_up, vec_p_dw){
vec_e_up <- rep(0, 24)
vec_e_dw <- rep(0, 24)
vec_r_b <- rep(0, 24)
# If na, we don't trade that day anyway
vec_e[is.na(vec_e)] <- 0
for (i in 1: 24){
# 1. Calculate regulation quantity
if (vec_e[i] <= vec_e_d[i]){ # Output too less
vec_e_up[i] <- vec_e[i] - vec_e_d[i]
vec_e_dw[i] <- 0
} else { # Output too much
vec_e_up[i] <- 0
vec_e_dw[i] <- vec_e[i] - vec_e_d[i]
}
# 2. Calculate the revenue in balancing market
if (vec_e_up[i] > 0){
print("Error:", vec_e_up[i], "is greater than 0.")
}
vec_r_b[i] <- vec_p_up[i] * vec_e_up[i] + vec_p_dw[i] * vec_e_dw[i]
}
return(vec_r_b)
}
5.1 Trading Strategy using Deterministic Wind Power Forecasts
5.2 Trading Strategy using Probabilistic Wind Power Forecasts
#' Calculate up-regulation and down-regulation prices using day-ahead price and balancing price
calReguPrice <- function(vec_p_d, vec_p_b){
# If Na, we don't trade that day anyway
vec_p_d[is.na(vec_p_d)] <- 0
vec_p_b[is.na(vec_p_b)] <- 0
#
vec_p_up <- rep(0, 24)
vec_p_dw <- rep(0, 24)
for (i in 1: 24){
# 1. Calculate the predicted regulation price
if (vec_p_b[i] >= vec_p_d[i]){ # higher balancing price
vec_p_up[i] <- vec_p_b[i]
vec_p_dw[i] <- vec_p_d[i]
} else { # lower balancing price
vec_p_up[i] <- vec_p_d[i]
vec_p_dw[i] <- vec_p_b[i]
}
}
return(list(up = vec_p_up, dw = vec_p_dw))
}
#' Function to calculate the trading volume in day-ahead market using Prob-Fore strategy
useStrategyProb <- function(vec_p_d_hat, vec_p_up_hat, vec_p_dw_hat, dat.f){
vec_psi_up_hat <- rep(0, 24)
vec_psi_dw_hat <- rep(0, 24)
vec_ratio <- rep(0, 24)
vec_e_d <- rep(0, 24)
for (i in 1: 24){
vec_psi_up_hat[i] <- vec_p_up_hat[i] - vec_p_d_hat[i]
vec_psi_dw_hat[i] <- vec_p_d_hat[i] - vec_p_dw_hat[i]
vec_ratio[i] <- vec_psi_dw_hat[i] / (vec_psi_up_hat[i] + vec_psi_dw_hat[i])
str <- paste("quan_", as.integer(vec_ratio[i] * 100 / 5) * 5, sep = "")
vec_e_d[i] <- dat.f[str][i,1]
}
return(vec_e_d)
}
#'
plotPredCDFun <- function(dat.f, day = 1, h = 1){
seq_prob <- seq(0, 100, by = 5)
vec_q <- rep(0, length(seq_prob))
for (i in 1: length(seq_prob)){
str <- paste("quan_", seq_prob[i], sep = "")
vec_q[i] <- dat.f[str][(24 * (day - 1) + h),1]
}
plot(c(vec_q, 160), c(seq_prob, 100), type = "l", col = "blue", lwd = 2,
main = paste("CDF and Expected Value of Predicted Wind Power Output in", day, "day at", h, "O'clock"),
xlab = "Wind Power Output (MW)", ylab = "Probability", xaxt = "n", yaxt = "n", bty = "n")
axis(1, at = seq(0, 160, by = 20), las = 0, outer = FALSE)
axis(2, at = seq(0, 100, by = 20), labels = seq(0, 1, by = 0.2), las = 0, outer = FALSE)
legend("topleft", inset = .02, legend = c("CDFunction", "Expected Value"),
col = c("blue", "red"), lty = c(1, 2), lwd = c(2, 2))
# Add the expected value in the plot
predValue <- dat.f$predValue[(24 * (day - 1) + h)]
lines(c(predValue, predValue), c(0, 100), col = "red", lwd = 2, lty = 2)
# points(predValue, 50, col = "red", lwd = 2, pch = 4, cex = 3)
}
plotPredCDFun(dat.f_q_17, 114, 19)

6 Performance Evaluation
#' Function to plot the accumulated revenue
#' If vec_rAccuMax.day is not NaN, plot the maximum accumulated revenue as well
plotRevenueDay <- function(vec_rAccu.day, vec_rAccuMax.day = NaN, str_strategy, num_day = 365, year = 2017){
if (!(is.na(vec_rAccuMax.day[1]))){
yMin <- min(vec_rAccu.day, vec_rAccuMax.day)
yMax <- max(vec_rAccu.day, vec_rAccuMax.day)
} else {
yMin <- min(vec_rAccu.day)
yMax <- max(vec_rAccu.day)
}
plot(seq(1: num_day), vec_rAccu.day, type = "l", ylim = c(yMin, yMax), col = "blue", lwd = 2,
main = paste("Accumulated Revenue Over the Year", year, "using", str_strategy, "Strategy"),
xlab = "month", ylab = "revenue (DKK)", xaxt = "n", bty = "n")
# text(365, vec_rAccu.day[365], paste(vec_rAccu.day[365]), pos = 1)
axis(1, at = c(1, 32, 60, 91, 122, 152, 183, 214, 244, 275, 305, 336),
substr(month.name, 1, 3), las = 0, outer = FALSE)
if (!(is.na(vec_rAccuMax.day[1]))){
legend("topleft", inset = .02, legend = c("Strategic Trading", "Perfect Info"),
col = c("blue", "red"), lty = c(1, 2), lwd = c(2, 2))
lines(seq(1: num_day), vec_rAccuMax.day, type = "l", col = "red", lwd = 2, lty = 2)
} else {
legend("topleft", inset = .02, legend = c("Strategy"),
col = c("blue"), lty = c(2), lwd = c(2))
}
}
6.2 Base Trading Strategy using Fixed Volume
vec_rAccu.day <- rep(0, 365)
vec_r.day <- rep(0, 365)
# For every day in 2017, calculate the revenue
for (day in 1: 365){
# 1. Calculate trade volume
vec_e_d <- rep(150, 24)
# If any data is missing, don't trade on that day
list_real <- getRealValue(dat.f_p_17$d, dat.f_p_17$b, dat.f_q_17$realMeasure, day)
vec_e_d[is.na(list_real$d)] <- 0
vec_e_d[is.na(list_real$b)] <- 0
vec_e_d[is.na(list_real$e)] <- 0
vec_e_d[(is.na(vec_e_d))] <- 0
list_real$e[is.na(list_real$d)] <- 0
list_real$e[is.na(list_real$b)] <- 0
list_real$e[is.na(list_real$e)] <- 0
# 2. Trade in day-ahead market
vec_r_d <- tradeDayAhead(vec_e_d, list_real$d)
# 3. Trade in balancing marekt
list_pRegu <- calReguPrice(list_real$d, list_real$b)
vec_r_b <- tradeBalancing(vec_e_d, list_real$e, list_pRegu$up, list_pRegu$dw)
# 4. Calculate the revenue in this day
vec_r.day[day] <- sum(vec_r_d + vec_r_b)
if (day == 1){
vec_rAccu.day[day] <- vec_r.day[day]
} else {
vec_rAccu.day[day] <- vec_r.day[day] + vec_rAccu.day[day-1]
}
}; rm(vec_e_d, vec_r_d, list_real, list_pRegu, vec_r_b)
plotRevenueDay(vec_rAccu.day, vec_rAccuMax.day, "\"Fixed Volume\"")

print(paste("Result: total revenue =", vec_rAccu.day[365]))
[1] "Result: total revenue = 129705990.68789"
print(paste("Result: gamma =", vec_rAccu.day[365] / vec_rAccuMax.day[365]))
[1] "Result: gamma = 0.890662217817209"
rm(vec_rAccu.day, vec_r.day)
6.3 Trading Strategy using Deterministic Wind Power Forecasts
vec_rAccu.day <- rep(0, 365)
vec_r.day <- rep(0, 365)
# For every day in 2017, calculate the revenue
for (day in 1: 365){
# 1. Calculate trade volume
vec_e_d <- dat.f_q_17$predValue[(24 * (day-1) + 1): (24 * (day-1) + 24)]
vec_e_d <- 1.0 * vec_e_d
# If any data is missing, don't trade on that day
list_real <- getRealValue(dat.f_p_17$d, dat.f_p_17$b, dat.f_q_17$realMeasure, day)
vec_e_d[is.na(list_real$d)] <- 0
vec_e_d[is.na(list_real$b)] <- 0
vec_e_d[is.na(list_real$e)] <- 0
vec_e_d[(is.na(vec_e_d))] <- 0
list_real$e[is.na(list_real$d)] <- 0
list_real$e[is.na(list_real$b)] <- 0
list_real$e[is.na(list_real$e)] <- 0
# 2. Trade in day-ahead market
vec_r_d <- tradeDayAhead(vec_e_d, list_real$d)
# 3. Trade in balancing marekt
list_pRegu <- calReguPrice(list_real$d, list_real$b)
vec_r_b <- tradeBalancing(vec_e_d, list_real$e, list_pRegu$up, list_pRegu$dw)
# 4. Calculate the revenue in this day
vec_r.day[day] <- sum(vec_r_d + vec_r_b)
if (day == 1){
vec_rAccu.day[day] <- vec_r.day[day]
} else {
vec_rAccu.day[day] <- vec_r.day[day] + vec_rAccu.day[day-1]
}
}; rm(vec_e_d, vec_r_d, list_real, list_pRegu, vec_r_b)
plotRevenueDay(vec_rAccu.day, vec_rAccuMax.day, "\"Deterministic Forecast\"")

print(paste("Result: total revenue =", vec_rAccu.day[365]))
[1] "Result: total revenue = 140634479.24337"
print(paste("Result: gamma =", vec_rAccu.day[365] / vec_rAccuMax.day[365]))
[1] "Result: gamma = 0.965705720454151"
rm(vec_rAccu.day, vec_r.day)
6.4 Trading Strategy using Probablistic Wind Power Forecasts
vec_rAccu.day <- rep(0, 365)
vec_r.day <- rep(0, 365)
# 1. Predict day-ahead and balancing prices
vec_p_d_hat <- vec_p_mean.day_16
vec_p_b_hat <- (mat_c %*% vec_p_d_hat)[ , 1] # vec_p_b_hat <- rep(0, 24)
list_pRegu_hat <- calReguPrice(vec_p_d_hat, vec_p_b_hat)
# For every day in 2017, calculate the revenue
for (day in 1: 365){
# 2. Calculate trade volume
vec_e_d <- useStrategyProb(vec_p_d_hat, list_pRegu_hat$up, list_pRegu_hat$dw, dat.f_q_17)
# If any data is missing, don't trade on that day
list_real <- getRealValue(dat.f_p_17$d, dat.f_p_17$b, dat.f_q_17$realMeasure, day)
vec_e_d[is.na(list_real$d)] <- 0
vec_e_d[is.na(list_real$b)] <- 0
vec_e_d[is.na(list_real$e)] <- 0
list_real$e[is.na(list_real$d)] <- 0
list_real$e[is.na(list_real$b)] <- 0
list_real$e[is.na(list_real$e)] <- 0
# 3. Trade in day-ahead market
vec_r_d <- tradeDayAhead(vec_e_d, list_real$d)
# 4. Trade in balancing marekt
list_pRegu <- calReguPrice(list_real$d, list_real$b)
vec_r_b <- tradeBalancing(vec_e_d, list_real$e, list_pRegu$up, list_pRegu$dw)
# 5. Calculate the revenue in this day
vec_r.day[day] <- sum(vec_r_d + vec_r_b)
if (day == 1){
vec_rAccu.day[day] <- vec_r.day[day]
} else {
vec_rAccu.day[day] <- vec_r.day[day] + vec_rAccu.day[day-1]
}
}; rm(vec_e_d, vec_r_d, list_real, list_pRegu, vec_r_b)
plotRevenueDay(vec_rAccu.day, vec_rAccuMax.day, "\"Prob Forecast\"")

print(paste("Result: total revenue =", vec_rAccu.day[365]))
[1] "Result: total revenue = 133768823.07183"
print(paste("Result: gamma =", vec_rAccu.day[365] / vec_rAccuMax.day[365]))
[1] "Result: gamma = 0.918560785049983"
rm(vec_rAccu.day, vec_r.day)
vec_rAccu.day <- rep(0, 365)
vec_r.day <- rep(0, 365)
# 1. Predict day-ahead and balancing prices
vec_p_d_hat <- vec_p_mean.day_16
vec_p_b_hat <- (mat_c %*% vec_p_d_hat)[ , 1] # vec_p_b_hat <- rep(0, 24)
list_pRegu_hat <- calReguPrice(vec_p_d_hat, vec_p_b_hat)
# For every day in 2017, calculate the revenue
for (day in 1: 365){
# 2. Calculate trade volume
vec_e_d <- useStrategyProb(vec_p_d_hat, list_pRegu_hat$up, list_pRegu_hat$dw, dat.f_q_17)
vec_e_d <- vec_e_d * 0.7
# If any data is missing, don't trade on that day
list_real <- getRealValue(dat.f_p_17$d, dat.f_p_17$b, dat.f_q_17$realMeasure, day)
vec_e_d[is.na(list_real$d)] <- 0
vec_e_d[is.na(list_real$b)] <- 0
vec_e_d[is.na(list_real$e)] <- 0
list_real$e[is.na(list_real$d)] <- 0
list_real$e[is.na(list_real$b)] <- 0
list_real$e[is.na(list_real$e)] <- 0
# 3. Trade in day-ahead market
vec_r_d <- tradeDayAhead(vec_e_d, list_real$d)
# 4. Trade in balancing marekt
list_pRegu <- calReguPrice(list_real$d, list_real$b)
vec_r_b <- tradeBalancing(vec_e_d, list_real$e, list_pRegu$up, list_pRegu$dw)
# 5. Calculate the revenue in this day
vec_r.day[day] <- sum(vec_r_d + vec_r_b)
if (day == 1){
vec_rAccu.day[day] <- vec_r.day[day]
} else {
vec_rAccu.day[day] <- vec_r.day[day] + vec_rAccu.day[day-1]
}
}; rm(vec_e_d, vec_r_d, list_real, list_pRegu, vec_r_b)
plotRevenueDay(vec_rAccu.day, vec_rAccuMax.day, "\"Prob Forecast\"")

print(paste("Result: total revenue =", vec_rAccu.day[365]))
[1] "Result: total revenue = 133651552.544013"
print(paste("Result: gamma =", vec_rAccu.day[365] / vec_rAccuMax.day[365]))
[1] "Result: gamma = 0.917755514392583"
rm(vec_rAccu.day, vec_r.day)
LS0tCnRpdGxlOiAiRFRVMzE3NjFBMjogUmVFbmVyZ3kgUGFydGljaXBhdGlvbiBpbiBNYXJrZXQiCm91dHB1dDogaHRtbF9ub3RlYm9vawphdXRob3I6IEVkd2FyZCBKLiBYdQpkYXRlOiBBcHJpbCAxMnRoLCAyMDE5Ci0tLQoKYGBge3IgZ2xvYmFsX29wdGlvbnMsIHNldCB1cCwgaW5jbHVkZT1GQUxTRX0Kcm0obGlzdD1scygpKSAjVG8gY2xlYXIgbmFtZXNwYWNlCmxpYnJhcnkoa25pdHIpCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gMTIsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFKQpgYGAKCmBgYHtyfQpsaWJyYXJ5KGZvcmVjYXN0KQpsaWJyYXJ5KGdwbG90cykKYGBgCgojIDEuIFJlcXVpcmVtZW50CgpBc3NpZ25tZW50IDIgY29uY2VudHJhdGVzIG9uIHBhcnRpY2lwYXRpb24gaW4gZWxlY3RyaWNpdHkgbWFya2V0cyB3aXRoIGEgcG9ydGZvbGlvIG9mIHJlbmV3YWJsZSBlbmVyZ3kgZ2VuZXJhdGlvbi4gVGhpcyBwb3J0Zm9saW8gYWN0dWFsbHkgY29uc2lzdHMgb2YgYSBzaW5nbGUgd2luZCBmYXJtIGxvY2F0ZWQgaW4gV2VzdGVybiBEZW5tYXJrLiBBc3NpZ24tIG1lbnQgMiByZXF1aXJlcyBrbm93bGVkZ2Ugb2YgYm90aCBiYXNpYyBtYXJrZXQgY29uY2VwdHMgKGRheS1haGVhZCBhbmQgYmFsYW5jaW5nIHN0YWdlcykgYW5kIG1hcmtldCBwYXJ0aWNpcGF0aW9uIGFzcGVjdHMgZm9sbG93aW5nIHRoZSBsZWN0dXJlcywgZXhlcmNpc2Ugc2Vzc2lvbnMsIGdhbWVzIGFuZCByZWFkaW5nIG1hdGVyaWFsIGZyb20gdGhlIGZpcnN0IDggd2Vla3Mgb2YgdGhlIGNvdXJzZS4KCiMgMi4gRGF0YSBQcm9jZXNzaW5nCgpgYGB7cn0KZnJhbWVEYXRhXzEgPC0gZnVuY3Rpb24oKXsKICAgIGRhdCA8LSByZWFkLnRhYmxlKCJ3aW5kcG93ZXJmb3JlY2FzdHMuZGF0IiwgaGVhZGVyID0gVCwgc2VwID0gIjsiKQogICAgdF9vdXQgPC0gZGF0WyAsIDFdCiAgICB0X2luIDwtIGRhdFsgLCAyXQogICAgcHJlZFN0ZXAgPC0gZGF0WyAsIDNdCiAgICByZWFsTWVhc3VyZSA8LSBkYXRbICwgNF0gLyAxMF4zCiAgICBwcmVkVmFsdWUgPC0gZGF0WyAsIDVdIC8gMTBeMwogICAgcXVhbl81IDwtIGRhdFsgLCA2XSAvIDEwXjMKICAgIHF1YW5fMTAgPC0gZGF0WyAsIDddIC8gMTBeMwogICAgcXVhbl8xNSA8LSBkYXRbICwgOF0gLyAxMF4zCiAgICBxdWFuXzIwIDwtIGRhdFsgLCA5XSAvIDEwXjMKICAgIHF1YW5fMjUgPC0gZGF0WyAsIDEwXSAvIDEwXjMKICAgIHF1YW5fMzAgPC0gZGF0WyAsIDExXSAvIDEwXjMKICAgIHF1YW5fMzUgPC0gZGF0WyAsIDEyXSAvIDEwXjMKICAgIHF1YW5fNDAgPC0gZGF0WyAsIDEzXSAvIDEwXjMKICAgIHF1YW5fNDUgPC0gZGF0WyAsIDE0XSAvIDEwXjMKICAgIHF1YW5fNTAgPC0gZGF0WyAsIDE1XSAvIDEwXjMKICAgIHF1YW5fNTUgPC0gZGF0WyAsIDE2XSAvIDEwXjMKICAgIHF1YW5fNjAgPC0gZGF0WyAsIDE3XSAvIDEwXjMKICAgIHF1YW5fNjUgPC0gZGF0WyAsIDE4XSAvIDEwXjMKICAgIHF1YW5fNzAgPC0gZGF0WyAsIDE5XSAvIDEwXjMKICAgIHF1YW5fNzUgPC0gZGF0WyAsIDIwXSAvIDEwXjMKICAgIHF1YW5fODAgPC0gZGF0WyAsIDIxXSAvIDEwXjMKICAgIHF1YW5fODUgPC0gZGF0WyAsIDIyXSAvIDEwXjMKICAgIHF1YW5fOTAgPC0gZGF0WyAsIDIzXSAvIDEwXjMKICAgIHF1YW5fOTUgPC0gZGF0WyAsIDI0XSAvIDEwXjMKICAgIHF1YW5fMTAwIDwtIHF1YW5fOTUKICAgIHF1YW5fMCA8LSBxdWFuXzUKICAgIGRhdC5mIDwtIGRhdGEuZnJhbWUodF9vdXQsIHRfaW4sIHByZWRTdGVwLCBwcmVkVmFsdWUsIHJlYWxNZWFzdXJlLCBxdWFuXzk1LCBxdWFuXzkwLCBxdWFuXzg1LCBxdWFuXzgwLCBxdWFuXzc1LAogICAgICAgICAgICAgICAgICAgICAgICBxdWFuXzcwLCBxdWFuXzY1LCBxdWFuXzYwLCBxdWFuXzU1LCBxdWFuXzUwLCBxdWFuXzQ1LCBxdWFuXzQwLCBxdWFuXzM1LCBxdWFuXzMwLCBxdWFuXzI1LAogICAgICAgICAgICAgICAgICAgICAgICBxdWFuXzIwLCBxdWFuXzE1LCBxdWFuXzEwLCBxdWFuXzUsIHF1YW5fMTAwLCBxdWFuXzApCiAgICAjIENsZWFuIHRoZSBkYXRhCiAgICB0X2luLnRpbWUgPC0gYXMubnVtZXJpYyhzdWJzdHIoZGF0LmYkdF9pbiwgOSwgMTApKQogICAgZGF0LmZbInRfaW4udGltZSJdIDwtIHRfaW4udGltZQogICAgZGF0LmYgPC0gZGF0LmZbZGF0LmYkdF9pbi50aW1lID09IDExLCBdCiAgICBkYXQuZiA8LSBkYXQuZltpcy5lbGVtZW50KGRhdC5mJHByZWRTdGVwLCBzZXEoMTMsIDM2KSksIF0KICAgIGRhdC5mIDwtIGRhdC5mWzE6ODc2MCwgXQogICAgZGF0LmYkdF9pbi50aW1lIDwtIE5VTEwKICAgIGRhdC5mJHRfaW4gPC0gTlVMTAogICAgIyBMYWJlbCB0aGUgZGF0YQogICAgZGF0LmZbInRpbWUiXSA8LSByZXAoc2VxKDAsIDIzKSwgMzY1KQogICAgdmVjX21vbnRoIDwtIGFzLm51bWVyaWMoc3Vic3RyKGRhdC5mJHRfb3V0LCA1LCA2KSkKICAgIGRhdC5mWyJtb250aCJdIDwtIHZlY19tb250aAogICAgdmVjX2RheSA8LSBhcy5udW1lcmljKHN1YnN0cihkYXQuZiR0X291dCwgNywgOCkpCiAgICBkYXQuZlsiZGF5Il0gPC0gdmVjX2RheQogICAgIyBSZXR1cm4gY2xlYW4gZGF0YQogICAgZGF0LmYkdF9vdXQgPC0gTlVMTAogICAgcmV0dXJuKGRhdC5mKQp9CmRhdC5mX3FfMTcgPC0gZnJhbWVEYXRhXzEoKQpybShmcmFtZURhdGFfMSkKYGBgCgpgYGB7cn0KZnJhbWVEYXRhXzIgPC0gZnVuY3Rpb24oc3RyX2RhdCl7CiAgICBkYXQgPC0gcmVhZC5jc3Yoc3RyX2RhdCwgaGVhZGVyID0gVCwgc2VwID0gIjsiKQogICAgc2VxIDwtIGRhdFsgLCAxXQogICAgbW9udGggPC0gZGF0WyAsIDRdCiAgICBkYXkgPC0gZGF0WyAsIDVdCiAgICB3ZWVrIDwtIGRhdFsgLCA2XQogICAgdGltZSA8LSBkYXRbICwgN10KICAgIGQgPC0gZGF0WyAsIDhdCiAgICBkW2lzLm5hKGQpXSA8LSAwCiAgICB1cCA8LSBkYXRbICwgOV0KICAgIHVwW2lzLm5hKHVwKV0gPC0gMAogICAgZHcgPC0gZGF0WyAsIDEwXQogICAgZHdbaXMubmEoZHcpXSA8LSAwCiAgICBkYXQuZiA8LSBkYXRhLmZyYW1lKHNlcSwgbW9udGgsIHdlZWssIGRheSwgdGltZSwgZCwgdXAsIGR3KQogICAgcmV0dXJuKGRhdC5mKQp9CmRhdC5mX3BfMTYgPC0gZnJhbWVEYXRhXzIoInByaWNlXzE2LmNzdiIpCmRhdC5mX3BfMTYgPC0gZGF0LmZfcF8xNlsxOiA4Nzg0LCBdICAjIDM2NiBkYXlzCmRhdC5mX3BfMTcgPC0gZnJhbWVEYXRhXzIoInByaWNlXzE3LmNzdiIpCmRhdC5mX3BfMTcgPC0gZGF0LmZfcF8xN1sxOiA4NzYwLCBdICAjIDM2NSBkYXlzCnJtKGZyYW1lRGF0YV8yKQpgYGAKCiMjIENhbGN1bGF0ZSBCYWxhbmNpbmcgUHJpY2UgaW4gMjAxNgoKYGBge3J9CiMnIEZ1bmN0aW9uIHRvIENhbGN1bGF0ZSBCYWxhbmNpbmcgUHJpY2UKY2FsX3ByaWNlX2IgPC0gZnVuY3Rpb24oZGF0LCBudW1fZGF5cyl7CiAgICB2ZWNfcHJpY2VfYiA8LSByZXAoMCwgbGVuZ3RoKGRhdCRzZXEpKQogICAgZm9yIChpIGluIDE6IG51bV9kYXlzKXsKICAgICAgICBpZiAoIWlzLm5hKGRhdCRkW2ldKSl7CiAgICAgICAgICAgIGlmIChhYnMoZGF0JHVwW2ldIC0gZGF0JGRbaV0pIDw9IGFicyhkYXQkZHdbaV0gLSBkYXQkZFtpXSkpeyAgCiAgICAgICAgICAgICAgICAjIGRhdCRkW2ldIGlzIG1vcmUgbmV4dCB0byBkYXQkZHdbaV0sIGNob29zZSB0aGUgb3RoZXIgb25lCiAgICAgICAgICAgICAgICB2ZWNfcHJpY2VfYltpXSA8LSBkYXQkZHdbaV0KICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlIGlmIChhYnMoZGF0JHVwW2ldIC0gZGF0JGRbaV0pID49IGFicyhkYXQkZHdbaV0gLSBkYXQkZFtpXSkpewogICAgICAgICAgICAgICAgdmVjX3ByaWNlX2JbaV0gPC0gZGF0JHVwW2ldCiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CiAgICByZXR1cm4odmVjX3ByaWNlX2IpCn0KZGF0LmZfcF8xNlsiYiJdIDwtIGNhbF9wcmljZV9iKGRhdC5mX3BfMTYsIDg3ODQpCmRhdC5mX3BfMTdbImIiXSA8LSBjYWxfcHJpY2VfYihkYXQuZl9wXzE3LCA4NzYwKQpgYGAKCiMgMy4gQWJvdXQgRGF5LUFoZWFkIFByaWNlCgojIyAzLjEgQm94IFBsb3Qgb2YgRGF5LUFoZWFkIFByaWNlCgpgYGB7cn0KYXZlX3BfMTZfZCA8LSBzdW0oZGF0LmZfcF8xNiRkKSAvIDg3ODQKYGBgCgoKYGBge3IsIGZpZy5oZWlnaHQgPSA2LCBmaWcud2lkdGggPSAxMX0KcGFyKGJ0eT0ibiIpCnBsb3QoZmFjdG9yKGRhdC5mX3BfMTYkbW9udGgpLCBkYXQuZl9wXzE2JGQsIG1haW4gPSAiQm94IFBsb3Qgb2YgRGF5LUFoZWFkIFByaWNlIEJ5IE1vbnRocyBpbiB0aGUgWWVhciAyMDE2IiwgCiAgICAgeGxhYiA9ICJNb250aCIsIHlsYWIgPSAiUHJpY2UiKQpsaW5lcyhjKDEsIDEyKSwgYyhhdmVfcF8xNl9kLCBhdmVfcF8xNl9kKSwgbHR5ID0gMiwgY29sID0gInJlZCIsIGx3ZCA9IDMpCmxlZ2VuZCgiYm90dG9tbGVmdCIsIGluc2V0ID0gLjAyLCBsZWdlbmQgPSAiWWVhcmx5IEF2ZXJhZ2UiLCBjb2wgPSAicmVkIiwgbHR5ID0gMiwgbHdkID0gMykKYGBgCgpgYGB7ciwgZmlnLmhlaWdodCA9IDYsIGZpZy53aWR0aCA9IDExfQpwYXIoYnR5PSJuIikKcGxvdChmYWN0b3IoZGF0LmZfcF8xNiR0aW1lKSwgZGF0LmZfcF8xNiRkLCBtYWluID0gIkJveCBQbG90IG9mIERheS1BaGVhZCBQcmljZSBCeSBIb3VycyBpbiB0aGUgWWVhciAyMDE2IiwgCiAgICAgeGxhYiA9ICJIb3VyIiwgeWxhYiA9ICJQcmljZSIpCmxpbmVzKGMoMSwgMjQpLCBjKGF2ZV9wXzE2X2QsIGF2ZV9wXzE2X2QpLCBsdHkgPSAyLCBjb2wgPSAicmVkIiwgbHdkID0gMykKbGVnZW5kKCJib3R0b21sZWZ0IiwgaW5zZXQgPSAuMDIsIGxlZ2VuZCA9ICJZZWFybHkgQXZlcmFnZSIsIGNvbCA9ICJyZWQiLCBsdHkgPSAyLCBsd2QgPSAzKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gMTF9CnBsb3RCb3hQbG90VHdvIDwtIGZ1bmN0aW9uKGRhdC5mLCBhdmUpewogICAgIyBEaXZpZGUgdGhlIGRhdGEgdG8gY2x1c3RlcnMgCiAgICB2ZWNfaW5kZXggPC0gcmVwKDAsIDg3ODQpCiAgICB2ZWNfaW5kZXhbKGlzLmVsZW1lbnQoZGF0LmYkdGltZSwgYygyMywgc2VxKDAsIDYpKSkpICYgKGlzLmVsZW1lbnQoZGF0LmYkbW9udGgsIGMoMTAsIDExLCAxMiwgMSkpKV0gPC0gMQogICAgdmVjX2luZGV4Wyhpcy5lbGVtZW50KGRhdC5mJHRpbWUsIHNlcSg3LCAxOCkpKSAmIChpcy5lbGVtZW50KGRhdC5mJG1vbnRoLCBjKDEwLCAxMSwgMTIsIDEpKSldIDwtIDIKICAgIHZlY19pbmRleFsoaXMuZWxlbWVudChkYXQuZiR0aW1lLCBzZXEoMTksIDIyKSkpICYgKGlzLmVsZW1lbnQoZGF0LmYkbW9udGgsIGMoMTAsIDExLCAxMiwgMSkpKV0gPC0gMwogICAgdmVjX2luZGV4Wyhpcy5lbGVtZW50KGRhdC5mJHRpbWUsIGMoMjMsIHNlcSgwLCA2KSkpKSAmIChpcy5lbGVtZW50KGRhdC5mJG1vbnRoLCBzZXEoMiwgNSkpKV0gPC0gNAogICAgdmVjX2luZGV4Wyhpcy5lbGVtZW50KGRhdC5mJHRpbWUsIHNlcSg3LCAxOCkpKSAmIChpcy5lbGVtZW50KGRhdC5mJG1vbnRoLCBzZXEoMiwgNSkpKV0gPC0gNQogICAgdmVjX2luZGV4Wyhpcy5lbGVtZW50KGRhdC5mJHRpbWUsIHNlcSgxOSwgMjIpKSkgJiAoaXMuZWxlbWVudChkYXQuZiRtb250aCwgc2VxKDIsIDUpKSldIDwtIDYKICAgIGRhdC5mX25ldyA8LSBkYXRhLmZyYW1lKGQgPSBkYXQuZiRkLCBpbmRleCA9IHZlY19pbmRleCkKICAgICMgCiAgICBwYXIoYnR5ID0gIm4iKQogICAgcGxvdChmYWN0b3IoZGF0LmZfbmV3JGluZGV4KSwgZGF0LmZfbmV3JGQsIG1haW4gPSAiQm94IFBsb3Qgb2YgRGF5LUFoZWFkIFByaWNlIEJ5IENsdXN0ZXJzIGluIHRoZSBZZWFyIDIwMTYiLCAKICAgICAgICAgeGxhYiA9ICJDbHVzdGVyIiwgeWxhYiA9ICJQcmljZSIsIHhheHQgPSAibiIpCiAgICBheGlzKDEsIGF0ID0gc2VxKDEsIDcpLCBsYWJlbCA9IGMoIm90aGVycyIsICJPY3QtSmFuLzAtNiIsICJPY3QtSmFuLzctMTgiLCAiT2N0LUphbi8xOS0yMiIsIAogICAgICAgICJGZWItTWF5LzAtNiIsICJGZWItTWF5LzctMTgiLCAiRmViLU1heS8xOS0yMiIpLCBsYXMgPSAwLCBvdXRlciA9IEZBTFNFKQogICAgbGluZXMoYygxLCA3KSwgYyhhdmUsIGF2ZSksIGx0eSA9IDIsIGNvbCA9ICJyZWQiLCBsd2QgPSAzKQogICAgbGVnZW5kKCJib3R0b21sZWZ0IiwgaW5zZXQgPSAuMDIsIGxlZ2VuZCA9ICJZZWFybHkgQXZlcmFnZSIsIGNvbCA9ICJyZWQiLCBsdHkgPSAyLCBsd2QgPSAzKQp9CnBsb3RCb3hQbG90VHdvKGRhdC5mX3BfMTYsIGF2ZV9wXzE2X2QpCmBgYAoKIyMgMy4xIENvcnJlbGF0aW9uIE1hdHJpeCBvZiBQcmljZXMgb3ZlciBPbmUgRGF5CgpgYGB7ciwgZmlnLmhlaWdodCA9IDYsIGZpZy53aWR0aCA9IDZ9Cm1hdF9wXzE2LmggPC0gbWF0cml4KG5yb3cgPSAzNjYsIG5jb2wgPSAyNCkKZm9yIChpIGluIDE6IDI0KXsKICAgIG1hdF9wXzE2LmhbICwgaV0gPC0gZGF0LmZfcF8xNlsoZGF0LmZfcF8xNiR0aW1lID09IGktMSksIF0kZAp9CiMgVXNpbmcgZnVuY3Rpb24gaGVhdG1hcC4yIGluIGxpYnJhcnkgZ3Bsb3RzIHRvIHZpc3VhbGl6ZSB0aGUgY29ycmVsYXRpb24gbWF0cml4CmhlYXRtYXAuMihjb3IobWF0X3BfMTYuaFsgLCAxOiAyNF0pLCBkZW5kcm9ncmFtID0gIm5vbmUiLCB0cmFjZT0ibm9uZSIsIFJvd3YgPSBGLCBDb2x2ID0gRikKYGBgCgojIyAzLjIgUHJpY2UgUHJlZGljdGlvbiB1c2luZyBFeHBlY3RlZCBWYWx1ZQoKYGBge3IsIGZpZy5oZWlnaHQgPSA0LCBmaWcud2lkdGggPSAxMX0KdmVjX3BfbWVhbi5kYXlfMTYgPC0gcmVwKDAsIDI0KQpmb3IgKGkgaW4gMDogMjMpewogICAgdmVjX3BfbWVhbi5kYXlfMTZbaSsxXTwtIG1lYW4oZGF0LmZfcF8xNlsoZGF0LmZfcF8xNiR0aW1lID09IGkpLCBdJGRbIWlzLm5hKGRhdC5mX3BfMTZbKGRhdC5mX3BfMTYkdGltZSA9PSBpKSwgXSRkKV0pCn07IHJtKGkpCnBsb3Qoc2VxKDAsIDIzKSwgdmVjX3BfbWVhbi5kYXlfMTYsIHR5cGUgPSAibCIsIGNvbCA9ICJibHVlIiwgbHdkID0gMiwgbHR5ID0gMSwgeGF4dCA9ICJuIiwgYnR5ID0gIm4iLAogICAgIG1haW4gPSBwYXN0ZSgiRXhwZWN0ZWQgRGF5LUFoZWFkIFByaWNlIG9mIEFsbCBIb3VycyBpbiBhIEZ1dHVyZSBEYXkiKSwgeGxhYiA9ICJIb3VyIGluIG9uZSBEYXkiLCB5bGFiID0gIlByaWNlIikKYXhpcygxLCBhdCA9IHNlcSgwLCAyMyksIGxhYmVsID0gc2VxKDEsIDI0KSwgbGFzID0gMCwgb3V0ZXIgPSBGQUxTRSkKYGBgCgojIyAzLjMgUHJlZGljdCB0aGUgRGF5LUFoZWFkIFByaWNlIHVzaW5nIFByZWRpY3RlZCBXaW5kIFBvd2VyIEdlbmVyYXRpb24KClVwZGF0ZSB0aGUgcmVncmVzc2lvbiByZWxhdGlvbnNoaXAgYmV0d2VlbiBwcmVkaWN0ZWQgd2luZCBwb3dlciBnZW5lcmF0aW9uIGFuZCBkYXktYWhlYWQgcHJpY2UuCgpCZWNhdXNlIHRoZXJlIHdpbGwgYmUgbW9yZSB3aW5kIHBvd2VyIGdlbmVyYXRpb24gaW4gb3RoZXIgY29tcGFuaWVzIGFzIHdlbGwsIHNvIHRoZSBwcmljZSBtYXkgZGVjcmVhc2UuIFRoZSBhZ2dyZWdhdGlvbiBvZiByZW5ld2FibGUgZ2VuZXJhdGlvbiBjYW4gaW1wYWN0IGEgbG90IG9uIHRoZSBkYXktYWhlYWQgY2xlYXJpbmcgcHJpY2UgYW5kIHRoZSBlZmZlY3QgbWF5IGJlIHN0YWJsZS4KCiMgNC4gUHJlZGljdGlvbiBvZiBCYWxhbmNpbmcgUHJpY2UKCiMjIDQuMSBSZWdyZXNzaW9uIFJlbGF0aW9uc2hpcCBiZXR3ZWVuIERheS1haGVhZCBQcmljZSBhbmQgQmFsYW5jaW5nIFByaWNlCgpQcmVkaWN0IHRoZSBCYWxhbmNpbmcgUHJpY2UgdXNpbmcgUmVncmVzc2lvbiBiZXR3ZWVuIFByZWRpY3RlZCBEYXktQWhlYWQgUHJpY2UKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNCwgZmlnLndpZHRoID0gMTF9CnBsb3RQcmljZVJlZ3Jlc3Npb24gPC0gZnVuY3Rpb24oZGF0LmZfcCl7CiAgICByZWdfcF8xNiA8LSBnbG0oZGF0LmZfcF8xNiRiIH4gZGF0LmZfcF8xNiRkKQogICAgIyBjb25maW50KHJlZ19wXzE2LCBsZXZlbCA9IDAuOTUpCiAgICBpbnRDb25mX3BfMTYgPC0gcHJlZGljdC5sbShyZWdfcF8xNiwgaW50ZXJ2YWwgPSAiY29uZiIsIGxldmVsID0gMC45NSkKICAgIHBsb3QoZGF0LmZfcF8xNiRkLCBkYXQuZl9wXzE2JGIsIGNvbCA9ICJibHVlIiwgeWF4dCA9ICJuIiwgYnR5ID0gIm4iLCAKICAgICAgICB4bGFiID0gIkRheS1BaGVhZCBQcmljZSIsIHlsYWIgPSAiQmFsYW5jaW5nIFByaWNlIiwgCiAgICAgICAgeWxpbSA9IGMoLTUwMCwgMjUwMCksIG1haW4gPSBwYXN0ZSgiUmVncmVzc2lvbiBSZWxhdGlvbnNoaXAgQmV0d2VlbiBEYXktQWhlYWQgUHJpY2UgYW5kIEJhbGFuY2luZyBQcmljZSIpKQogICAgbGluZXMoYygtNDAwLCA4MDApLCByZWdfcF8xNiRjb2VmZmljaWVudHNbMV0gKyByZWdfcF8xNiRjb2VmZmljaWVudHNbMl0gKiBjKC00MDAsIDgwMCksIGNvbCA9ICJyZWQiLCBsd2QgPSAyKQogICAgbGluZXMoZGF0LmZfcF8xNiRkLCBpbnRDb25mX3BfMTZbLCAyXSwgbHR5ID0gMiwgY29sID0gImJsYWNrIiwgbHdkID0gMC41KQogICAgbGluZXMoZGF0LmZfcF8xNiRkLCBpbnRDb25mX3BfMTZbLCAzXSwgbHR5ID0gMiwgY29sID0gImJsYWNrIiwgbHdkID0gMC41KQogICAgYXhpcygyLCBhdCA9IHNlcSgtNTAwLCAyNTAwLCBieSA9IDUwMCksIGxhcyA9IDAsIG91dGVyID0gRkFMU0UpCiAgICBsZWdlbmQoInRvcGxlZnQiLCBpbnNldCA9IC4wMiwgbGVnZW5kID0gYygiT2JzZXJ2YXRpb24iLCAiUmVncmVzc2lvbiIsICI5NSUgQ29uZmlkZW5jZSBJbnRlcnZhbCIpLCAKICAgICAgICBjb2wgPSBjKCJibHVlIiwgInJlZCIsICJibGFjayIpLCBsdHkgPSBjKE5VTEwsIDEsIDIpLCBsd2QgPSBjKE5hTiwgMiwgMC41KSwgcGNoID0gYygxLCBOYU4sIE5hTikpCn0KcGxvdFByaWNlUmVncmVzc2lvbihkYXQuZl9wXzE2KQpgYGAKCiMjIDQuMiBNdWx0aXZhcmlhdGUgUmVncmVzc2lvbiBNb2RlbCBCZXR3ZWVuIERheS1BaGVhZCBQcmljZSBhbmQgQmFsYW5jaW5nIFByaWNlCgpgYGB7cn0KIyBDb25zdHJ1Y3QgbWF0cml4IGZvciBwcmljZQptYXRfcF8xNi5kIDwtIG1hdHJpeChuY29sID0gMzY2LCBucm93ID0gMjQpCm1hdF9wXzE2LmIgPC0gbWF0cml4KG5jb2wgPSAzNjYsIG5yb3cgPSAyNCkKZm9yIChpIGluIDE6IDI0KXsKICAgIG1hdF9wXzE2LmRbaSwgXSA8LSBkYXQuZl9wXzE2WyhkYXQuZl9wXzE2JHRpbWUgPT0gaS0xKSxdJGQKICAgIG1hdF9wXzE2LmJbaSwgXSA8LSBkYXQuZl9wXzE2WyhkYXQuZl9wXzE2JHRpbWUgPT0gaS0xKSxdJGIKfQojIENhbGN1bGF0ZSB0aGUgUmVncmVzc2lvbiBDb2VmZmljaWVudAptYXQgPC0gbWF0cml4KG5jb2wgPSAyNSwgbnJvdyA9IDI0KQp2ZWNfbXUgPC0gcmVwKDAsIDI0KQpmb3IgKGkgaW4gMTogMjQpewogICAgbWF0W2ksIF0gPC0gZ2xtKG1hdF9wXzE2LmJbaSwgXSB+IG1hdF9wXzE2LmRbMSwgXSArIG1hdF9wXzE2LmRbMiwgXSArIG1hdF9wXzE2LmRbMywgXSArIAogICAgICAgIG1hdF9wXzE2LmRbNCwgXSArIG1hdF9wXzE2LmRbNSwgXSArIG1hdF9wXzE2LmRbNiwgXSArCiAgICAgICAgbWF0X3BfMTYuZFs3LCBdICsgbWF0X3BfMTYuZFs4LCBdICsgbWF0X3BfMTYuZFs5LCBdICsKICAgICAgICBtYXRfcF8xNi5kWzEwLCBdICsgbWF0X3BfMTYuZFsxMSwgXSArIG1hdF9wXzE2LmRbMTIsIF0gKwogICAgICAgIG1hdF9wXzE2LmRbMTMsIF0gKyBtYXRfcF8xNi5kWzE0LCBdICsgbWF0X3BfMTYuZFsxNSwgXSArCiAgICAgICAgbWF0X3BfMTYuZFsxNiwgXSArIG1hdF9wXzE2LmRbMTcsIF0gKyBtYXRfcF8xNi5kWzE4LCBdICsKICAgICAgICBtYXRfcF8xNi5kWzE5LCBdICsgbWF0X3BfMTYuZFsyMCwgXSArIG1hdF9wXzE2LmRbMjEsIF0gKwogICAgICAgIG1hdF9wXzE2LmRbMjIsIF0gKyBtYXRfcF8xNi5kWzIzLCBdICsgbWF0X3BfMTYuZFsyNCwgXSkkY29lZmZpY2llbnRzWzE6MjVdCn0KdmVjX211IDwtIG1hdFsgLCAxXQptYXRfYyA8LSBtYXRbICwgMjogMjVdCnJtKG1hdCkKIyBDaGVjayB0aGUgcmVzdWx0CmFsbCgobWF0X2MgLSBjb3YodChtYXRfcF8xNi5iKSwgdChtYXRfcF8xNi5kKSkgJSolIHNvbHZlKGNvdih0KG1hdF9wXzE2LmQpKSkpIDwgMC4wMDAwMDEpCmBgYAoKIyA1IFRyYWRpbmcgU3RyYXRlZ2llcwoKYGBge3J9CiMnIEZ1bmN0aW9uIHRvIHRyYWRlIGluIGRheS1haGVhZCBtYXJrZXQgYW5kIGNhbGN1bGF0ZSB0aGUgcmV2ZW51ZQp0cmFkZURheUFoZWFkIDwtIGZ1bmN0aW9uKHZlY19lX2QsIHZlY19wX2QpewogICAgdmVjX3JfZCA8LSB2ZWNfZV9kICogdmVjX3BfZAogICAgcmV0dXJuKHZlY19yX2QpCn0KIycgRnVuY3Rpb24gdG8gZ2V0IHRoZSByZWFsIG1lYXN1cmVkIHZhbHVlcyBpbiB0aGF0IGRheQpnZXRSZWFsVmFsdWUgPC0gZnVuY3Rpb24odmVjX3BfZF9hbGwsIHZlY19wX2JfYWxsLCB2ZWNfZV9hbGwsIGRheSl7CiAgICAjIGxpc3RfcmVhbFZhbHVlIDwtIGdldFJlYWxWYWx1ZShkYXQuZl9wJGQsIGRhdC5mX3AkYiwgZGF0LmZfcSRyZWFsTWVhc3VyZSkKICAgIHZlY19wX2QgPC0gdmVjX3BfZF9hbGxbKDI0ICogKGRheS0xKSArIDEpOiAoMjQgKiAoZGF5LTEpICsgMjQpXQogICAgdmVjX3BfYiA8LSB2ZWNfcF9iX2FsbFsoMjQgKiAoZGF5LTEpICsgMSk6ICgyNCAqIChkYXktMSkgKyAyNCldCiAgICB2ZWNfZSA8LSB2ZWNfZV9hbGxbKDI0ICogKGRheS0xKSArIDEpOiAoMjQgKiAoZGF5LTEpICsgMjQpXQogICAgcmV0dXJuKGxpc3QoZCA9IHZlY19wX2QsIGIgPSB2ZWNfcF9iLCBlID0gdmVjX2UpKQp9CiMnIEZ1bmN0aW9uIHRvIHRyYWRlIGluIGJhbGFuY2luZyBtYXJrZXQgYW5kIGNhbGN1bGF0ZSB0aGUgcmV2ZW51ZQp0cmFkZUJhbGFuY2luZyA8LSBmdW5jdGlvbih2ZWNfZV9kLCB2ZWNfZSwgdmVjX3BfdXAsIHZlY19wX2R3KXsKICAgIHZlY19lX3VwIDwtIHJlcCgwLCAyNCkKICAgIHZlY19lX2R3IDwtIHJlcCgwLCAyNCkKICAgIHZlY19yX2IgPC0gcmVwKDAsIDI0KQogICAgIyBJZiBuYSwgd2UgZG9uJ3QgdHJhZGUgdGhhdCBkYXkgYW55d2F5CiAgICB2ZWNfZVtpcy5uYSh2ZWNfZSldIDwtIDAKICAgIGZvciAoaSBpbiAxOiAyNCl7CiAgICAgICAgIyAxLiBDYWxjdWxhdGUgcmVndWxhdGlvbiBxdWFudGl0eQogICAgICAgIGlmICh2ZWNfZVtpXSA8PSB2ZWNfZV9kW2ldKXsgICMgT3V0cHV0IHRvbyBsZXNzCiAgICAgICAgICAgIHZlY19lX3VwW2ldIDwtIHZlY19lW2ldIC0gdmVjX2VfZFtpXQogICAgICAgICAgICB2ZWNfZV9kd1tpXSA8LSAwCiAgICAgICAgfSBlbHNlIHsgICMgT3V0cHV0IHRvbyBtdWNoCiAgICAgICAgICAgIHZlY19lX3VwW2ldIDwtIDAKICAgICAgICAgICAgdmVjX2VfZHdbaV0gPC0gdmVjX2VbaV0gLSB2ZWNfZV9kW2ldCiAgICAgICAgfQogICAgICAgICMgMi4gQ2FsY3VsYXRlIHRoZSByZXZlbnVlIGluIGJhbGFuY2luZyBtYXJrZXQKICAgICAgICBpZiAodmVjX2VfdXBbaV0gPiAwKXsKICAgICAgICAgICAgcHJpbnQoIkVycm9yOiIsIHZlY19lX3VwW2ldLCAiaXMgZ3JlYXRlciB0aGFuIDAuIikKICAgICAgICB9CiAgICAgICAgdmVjX3JfYltpXSA8LSB2ZWNfcF91cFtpXSAqIHZlY19lX3VwW2ldICsgdmVjX3BfZHdbaV0gKiB2ZWNfZV9kd1tpXQogICAgfQogICAgcmV0dXJuKHZlY19yX2IpCn0KYGBgCgojIyA1LjEgVHJhZGluZyBTdHJhdGVneSB1c2luZyBEZXRlcm1pbmlzdGljIFdpbmQgUG93ZXIgRm9yZWNhc3RzCgoKIyMgNS4yIFRyYWRpbmcgU3RyYXRlZ3kgdXNpbmcgUHJvYmFiaWxpc3RpYyBXaW5kIFBvd2VyIEZvcmVjYXN0cwoKYGBge3J9CiMnIENhbGN1bGF0ZSB1cC1yZWd1bGF0aW9uIGFuZCBkb3duLXJlZ3VsYXRpb24gcHJpY2VzIHVzaW5nIGRheS1haGVhZCBwcmljZSBhbmQgYmFsYW5jaW5nIHByaWNlCmNhbFJlZ3VQcmljZSA8LSBmdW5jdGlvbih2ZWNfcF9kLCB2ZWNfcF9iKXsKICAgICMgSWYgTmEsIHdlIGRvbid0IHRyYWRlIHRoYXQgZGF5IGFueXdheQogICAgdmVjX3BfZFtpcy5uYSh2ZWNfcF9kKV0gPC0gMAogICAgdmVjX3BfYltpcy5uYSh2ZWNfcF9iKV0gPC0gMAogICAgIyAKICAgIHZlY19wX3VwIDwtIHJlcCgwLCAyNCkKICAgIHZlY19wX2R3IDwtIHJlcCgwLCAyNCkKICAgIGZvciAoaSBpbiAxOiAyNCl7CiAgICAgICAgIyAxLiBDYWxjdWxhdGUgdGhlIHByZWRpY3RlZCByZWd1bGF0aW9uIHByaWNlCiAgICAgICAgaWYgKHZlY19wX2JbaV0gPj0gdmVjX3BfZFtpXSl7ICAjIGhpZ2hlciBiYWxhbmNpbmcgcHJpY2UKICAgICAgICAgICAgdmVjX3BfdXBbaV0gPC0gdmVjX3BfYltpXQogICAgICAgICAgICB2ZWNfcF9kd1tpXSA8LSB2ZWNfcF9kW2ldCiAgICAgICAgfSBlbHNlIHsgICMgbG93ZXIgYmFsYW5jaW5nIHByaWNlCiAgICAgICAgICAgIHZlY19wX3VwW2ldIDwtIHZlY19wX2RbaV0KICAgICAgICAgICAgdmVjX3BfZHdbaV0gPC0gdmVjX3BfYltpXQogICAgICAgIH0KICAgIH0KICAgIHJldHVybihsaXN0KHVwID0gdmVjX3BfdXAsIGR3ID0gdmVjX3BfZHcpKQp9CiMnIEZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSB0aGUgdHJhZGluZyB2b2x1bWUgaW4gZGF5LWFoZWFkIG1hcmtldCB1c2luZyBQcm9iLUZvcmUgc3RyYXRlZ3kKdXNlU3RyYXRlZ3lQcm9iIDwtIGZ1bmN0aW9uKHZlY19wX2RfaGF0LCB2ZWNfcF91cF9oYXQsIHZlY19wX2R3X2hhdCwgZGF0LmYpewogICAgdmVjX3BzaV91cF9oYXQgPC0gcmVwKDAsIDI0KQogICAgdmVjX3BzaV9kd19oYXQgPC0gcmVwKDAsIDI0KQogICAgdmVjX3JhdGlvIDwtIHJlcCgwLCAyNCkKICAgIHZlY19lX2QgPC0gcmVwKDAsIDI0KQogICAgZm9yIChpIGluIDE6IDI0KXsKICAgICAgICB2ZWNfcHNpX3VwX2hhdFtpXSA8LSB2ZWNfcF91cF9oYXRbaV0gLSB2ZWNfcF9kX2hhdFtpXQogICAgICAgIHZlY19wc2lfZHdfaGF0W2ldIDwtIHZlY19wX2RfaGF0W2ldIC0gdmVjX3BfZHdfaGF0W2ldCiAgICAgICAgdmVjX3JhdGlvW2ldIDwtIHZlY19wc2lfZHdfaGF0W2ldIC8gKHZlY19wc2lfdXBfaGF0W2ldICsgdmVjX3BzaV9kd19oYXRbaV0pCiAgICAgICAgc3RyIDwtIHBhc3RlKCJxdWFuXyIsIGFzLmludGVnZXIodmVjX3JhdGlvW2ldICogMTAwIC8gNSkgKiA1LCBzZXAgPSAiIikKICAgICAgICB2ZWNfZV9kW2ldIDwtIGRhdC5mW3N0cl1baSwxXQogICAgfQogICAgcmV0dXJuKHZlY19lX2QpCn0KIycKcGxvdFByZWRDREZ1biA8LSBmdW5jdGlvbihkYXQuZiwgZGF5ID0gMSwgaCA9IDEpewogICAgc2VxX3Byb2IgPC0gc2VxKDAsIDEwMCwgYnkgPSA1KQogICAgdmVjX3EgPC0gcmVwKDAsIGxlbmd0aChzZXFfcHJvYikpCiAgICBmb3IgKGkgaW4gMTogbGVuZ3RoKHNlcV9wcm9iKSl7CiAgICAgICAgc3RyIDwtIHBhc3RlKCJxdWFuXyIsIHNlcV9wcm9iW2ldLCBzZXAgPSAiIikKICAgICAgICB2ZWNfcVtpXSA8LSBkYXQuZltzdHJdWygyNCAqIChkYXkgLSAxKSArIGgpLDFdCiAgICB9CiAgICBwbG90KGModmVjX3EsIDE2MCksIGMoc2VxX3Byb2IsIDEwMCksIHR5cGUgPSAibCIsIGNvbCA9ICJibHVlIiwgbHdkID0gMiwKICAgICAgICAgbWFpbiA9IHBhc3RlKCJDREYgYW5kIEV4cGVjdGVkIFZhbHVlIG9mIFByZWRpY3RlZCBXaW5kIFBvd2VyIE91dHB1dCBpbiIsIGRheSwgImRheSBhdCIsIGgsICJPJ2Nsb2NrIiksIAogICAgICAgICB4bGFiID0gIldpbmQgUG93ZXIgT3V0cHV0IChNVykiLCB5bGFiID0gIlByb2JhYmlsaXR5IiwgeGF4dCA9ICJuIiwgeWF4dCA9ICJuIiwgYnR5ID0gIm4iKQogICAgYXhpcygxLCBhdCA9IHNlcSgwLCAxNjAsIGJ5ID0gMjApLCBsYXMgPSAwLCBvdXRlciA9IEZBTFNFKQogICAgYXhpcygyLCBhdCA9IHNlcSgwLCAxMDAsIGJ5ID0gMjApLCBsYWJlbHMgPSBzZXEoMCwgMSwgYnkgPSAwLjIpLCBsYXMgPSAwLCBvdXRlciA9IEZBTFNFKQogICAgbGVnZW5kKCJ0b3BsZWZ0IiwgaW5zZXQgPSAuMDIsIGxlZ2VuZCA9IGMoIkNERnVuY3Rpb24iLCAiRXhwZWN0ZWQgVmFsdWUiKSwgCiAgICAgICAgICAgIGNvbCA9IGMoImJsdWUiLCAicmVkIiksIGx0eSA9IGMoMSwgMiksIGx3ZCA9IGMoMiwgMikpCiAgICAjIEFkZCB0aGUgZXhwZWN0ZWQgdmFsdWUgaW4gdGhlIHBsb3QKICAgIHByZWRWYWx1ZSA8LSBkYXQuZiRwcmVkVmFsdWVbKDI0ICogKGRheSAtIDEpICsgaCldCiAgICBsaW5lcyhjKHByZWRWYWx1ZSwgcHJlZFZhbHVlKSwgYygwLCAxMDApLCBjb2wgPSAicmVkIiwgbHdkID0gMiwgbHR5ID0gMikKICAgICMgcG9pbnRzKHByZWRWYWx1ZSwgNTAsIGNvbCA9ICJyZWQiLCBsd2QgPSAyLCBwY2ggPSA0LCBjZXggPSAzKQp9CmBgYAoKYGBge3IsIGZpZy5oZWlnaHQgPSA2LCBmaWcud2lkdGggPSAxMX0KcGxvdFByZWRDREZ1bihkYXQuZl9xXzE3LCAxMTQsIDE5KQpgYGAKCiMgNiBQZXJmb3JtYW5jZSBFdmFsdWF0aW9uCgpgYGB7cn0KIycgRnVuY3Rpb24gdG8gcGxvdCB0aGUgYWNjdW11bGF0ZWQgcmV2ZW51ZQojJyBJZiB2ZWNfckFjY3VNYXguZGF5IGlzIG5vdCBOYU4sIHBsb3QgdGhlIG1heGltdW0gYWNjdW11bGF0ZWQgcmV2ZW51ZSBhcyB3ZWxsCnBsb3RSZXZlbnVlRGF5IDwtIGZ1bmN0aW9uKHZlY19yQWNjdS5kYXksIHZlY19yQWNjdU1heC5kYXkgPSBOYU4sIHN0cl9zdHJhdGVneSwgbnVtX2RheSA9IDM2NSwgeWVhciA9IDIwMTcpewogICAgaWYgKCEoaXMubmEodmVjX3JBY2N1TWF4LmRheVsxXSkpKXsKICAgICAgICB5TWluIDwtIG1pbih2ZWNfckFjY3UuZGF5LCB2ZWNfckFjY3VNYXguZGF5KQogICAgICAgIHlNYXggPC0gbWF4KHZlY19yQWNjdS5kYXksIHZlY19yQWNjdU1heC5kYXkpCiAgICB9IGVsc2UgewogICAgICAgIHlNaW4gPC0gbWluKHZlY19yQWNjdS5kYXkpCiAgICAgICAgeU1heCA8LSBtYXgodmVjX3JBY2N1LmRheSkKICAgIH0KICAgIHBsb3Qoc2VxKDE6IG51bV9kYXkpLCB2ZWNfckFjY3UuZGF5LCB0eXBlID0gImwiLCB5bGltID0gYyh5TWluLCB5TWF4KSwgY29sID0gImJsdWUiLCBsd2QgPSAyLAogICAgICAgICAgICBtYWluID0gcGFzdGUoIkFjY3VtdWxhdGVkIFJldmVudWUgT3ZlciB0aGUgWWVhciIsIHllYXIsICJ1c2luZyIsIHN0cl9zdHJhdGVneSwgIlN0cmF0ZWd5IiksIAogICAgICAgICAgICB4bGFiID0gIm1vbnRoIiwgeWxhYiA9ICJyZXZlbnVlIChES0spIiwgeGF4dCA9ICJuIiwgYnR5ID0gIm4iKQogICAgIyB0ZXh0KDM2NSwgdmVjX3JBY2N1LmRheVszNjVdLCBwYXN0ZSh2ZWNfckFjY3UuZGF5WzM2NV0pLCBwb3MgPSAxKQogICAgYXhpcygxLCBhdCA9IGMoMSwgMzIsIDYwLCA5MSwgMTIyLCAxNTIsIDE4MywgMjE0LCAyNDQsIDI3NSwgMzA1LCAzMzYpLAogICAgICAgICBzdWJzdHIobW9udGgubmFtZSwgMSwgMyksIGxhcyA9IDAsIG91dGVyID0gRkFMU0UpCiAgICBpZiAoIShpcy5uYSh2ZWNfckFjY3VNYXguZGF5WzFdKSkpewogICAgICAgIGxlZ2VuZCgidG9wbGVmdCIsIGluc2V0ID0gLjAyLCBsZWdlbmQgPSBjKCJTdHJhdGVnaWMgVHJhZGluZyIsICJQZXJmZWN0IEluZm8iKSwgCiAgICAgICAgICAgIGNvbCA9IGMoImJsdWUiLCAicmVkIiksIGx0eSA9IGMoMSwgMiksIGx3ZCA9IGMoMiwgMikpCiAgICAgICAgbGluZXMoc2VxKDE6IG51bV9kYXkpLCB2ZWNfckFjY3VNYXguZGF5LCB0eXBlID0gImwiLCBjb2wgPSAicmVkIiwgbHdkID0gMiwgbHR5ID0gMikKICAgIH0gZWxzZSB7CiAgICAgICAgbGVnZW5kKCJ0b3BsZWZ0IiwgaW5zZXQgPSAuMDIsIGxlZ2VuZCA9IGMoIlN0cmF0ZWd5IiksIAogICAgICAgICAgICBjb2wgPSBjKCJibHVlIiksIGx0eSA9IGMoMiksIGx3ZCA9IGMoMikpCiAgICB9IAp9CmBgYAoKIyMgNi4xIFRoZSBtYXhpbXVtIHJldmVudWUgZnJvbSB0cmFkZSB3aXRoIFBlcmZlY3QgSW5mb3JtYXRpb246CgpgYGB7ciwgZmlnLmhlaWdodCA9IDYsIGZpZy53aWR0aCA9IDExfQpjYWxSZXZlbnVlTWF4IDwtIGZ1bmN0aW9uKHZlY19wX2QsIHZlY19xUmVhbCl7CiAgICAjIElmIGFueSBkYXRhIGlzIG1pc3NpbmcsIGRvbid0IHRyYWRlIG9uIHRoYXQgZGF5CiAgICB2ZWNfcVJlYWxbaXMubmEodmVjX3FSZWFsKV0gPC0gMAogICAgdmVjX3FSZWFsW2lzLm5hKHZlY19wX2QpXSA8LSAwCiAgICB2ZWNfcF9kW2lzLm5hKHZlY19xUmVhbCldIDwtIDAKICAgIHZlY19wX2RbaXMubmEodmVjX3BfZCldIDwtIDAKICAgICMgQ2FsY3VsYXRlIHZlY3RvciBvZiBtYXhpbXVtIHJldmVudWUgYW5kIG1heGltdW0gYWNjdW11bGF0ZWQgcmV2ZW51ZQogICAgdmVjX3JNYXguaCA8LSB2ZWNfcF9kICogdmVjX3FSZWFsCiAgICB2ZWNfck1heC5kYXkgPC0gcmVwKDAsIDM2NSkKICAgIHZlY19yQWNjdU1heC5kYXkgPC0gcmVwKDAsIDM2NSkKICAgIGZvciAoZGF5IGluIDE6IDM2NSl7CiAgICAgICAgdmVjX3JNYXguZGF5W2RheV0gPC0gc3VtKHZlY19yTWF4LmhbKDI0ICogKGRheS0xKSArIDEpOiAoMjQgKiAoZGF5LTEpICsgMjQpXSkKICAgICAgICBpZiAoZGF5ID09IDEpewogICAgICAgICAgICB2ZWNfckFjY3VNYXguZGF5W2RheV0gPC0gdmVjX3JNYXguZGF5WzFdCiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgdmVjX3JBY2N1TWF4LmRheVtkYXldIDwtIHZlY19yTWF4LmRheVtkYXldICsgdmVjX3JBY2N1TWF4LmRheVtkYXktMV0KICAgICAgICB9CiAgICB9OyBybShkYXkpCiAgICBwbG90KHNlcSgxOiAzNjUpLCB2ZWNfckFjY3VNYXguZGF5LCB0eXBlID0gImwiLCBjb2wgPSAicmVkIiwgbHR5ID0gMiwgbHdkID0gMiwKICAgICAgICAgICAgbWFpbiA9IHBhc3RlKCJNYXhpbXVtIEFjY3VtdWxhdGVkIFJldmVudWUgT3ZlciB0aGUgWWVhciAyMDE3IHdpdGggUGVyZmVjdCBJbmZvcm1hdGlvbiIpLCAKICAgICAgICAgICAgeGxhYiA9ICJtb250aCIsIHlsYWIgPSAicmV2ZW51ZSAoREtLKSIsIHhheHQgPSAibiIsIGJ0eSA9ICJuIikKICAgIGF4aXMoMSwgYXQgPSBjKDEsIDMyLCA2MCwgOTEsIDEyMiwgMTUyLCAxODMsIDIxNCwgMjQ0LCAyNzUsIDMwNSwgMzM2KSwKICAgICAgICAgc3Vic3RyKG1vbnRoLm5hbWUsIDEsIDMpLCBsYXMgPSAwLCBvdXRlciA9IEZBTFNFKQogICAgcmV0dXJuKHZlY19yQWNjdU1heC5kYXkpCn0KdmVjX3JBY2N1TWF4LmRheSA8LSBjYWxSZXZlbnVlTWF4KGRhdC5mX3BfMTckZCwgZGF0LmZfcV8xNyRyZWFsTWVhc3VyZSkKcm0oY2FsUmV2ZW51ZU1heCkKYGBgCgojIyA2LjIgQmFzZSBUcmFkaW5nIFN0cmF0ZWd5IHVzaW5nIEZpeGVkIFZvbHVtZQoKYGBge3IsIGZpZy5oZWlnaHQgPSA2LCBmaWcud2lkdGggPSAxMX0KdmVjX3JBY2N1LmRheSA8LSByZXAoMCwgMzY1KQp2ZWNfci5kYXkgPC0gcmVwKDAsIDM2NSkKIyBGb3IgZXZlcnkgZGF5IGluIDIwMTcsIGNhbGN1bGF0ZSB0aGUgcmV2ZW51ZQpmb3IgKGRheSBpbiAxOiAzNjUpewogICAgIyAxLiBDYWxjdWxhdGUgdHJhZGUgdm9sdW1lCiAgICB2ZWNfZV9kIDwtIHJlcCgxNTAsIDI0KQogICAgIyBJZiBhbnkgZGF0YSBpcyBtaXNzaW5nLCBkb24ndCB0cmFkZSBvbiB0aGF0IGRheQogICAgbGlzdF9yZWFsIDwtIGdldFJlYWxWYWx1ZShkYXQuZl9wXzE3JGQsIGRhdC5mX3BfMTckYiwgZGF0LmZfcV8xNyRyZWFsTWVhc3VyZSwgZGF5KQogICAgdmVjX2VfZFtpcy5uYShsaXN0X3JlYWwkZCldIDwtIDAKICAgIHZlY19lX2RbaXMubmEobGlzdF9yZWFsJGIpXSA8LSAwCiAgICB2ZWNfZV9kW2lzLm5hKGxpc3RfcmVhbCRlKV0gPC0gMAogICAgdmVjX2VfZFsoaXMubmEodmVjX2VfZCkpXSA8LSAwCiAgICBsaXN0X3JlYWwkZVtpcy5uYShsaXN0X3JlYWwkZCldIDwtIDAKICAgIGxpc3RfcmVhbCRlW2lzLm5hKGxpc3RfcmVhbCRiKV0gPC0gMAogICAgbGlzdF9yZWFsJGVbaXMubmEobGlzdF9yZWFsJGUpXSA8LSAwCiAgICAjIDIuIFRyYWRlIGluIGRheS1haGVhZCBtYXJrZXQKICAgIHZlY19yX2QgPC0gdHJhZGVEYXlBaGVhZCh2ZWNfZV9kLCBsaXN0X3JlYWwkZCkKICAgICMgMy4gVHJhZGUgaW4gYmFsYW5jaW5nIG1hcmVrdAogICAgbGlzdF9wUmVndSA8LSBjYWxSZWd1UHJpY2UobGlzdF9yZWFsJGQsIGxpc3RfcmVhbCRiKQogICAgdmVjX3JfYiA8LSB0cmFkZUJhbGFuY2luZyh2ZWNfZV9kLCBsaXN0X3JlYWwkZSwgbGlzdF9wUmVndSR1cCwgbGlzdF9wUmVndSRkdykKICAgICMgNC4gQ2FsY3VsYXRlIHRoZSByZXZlbnVlIGluIHRoaXMgZGF5CiAgICB2ZWNfci5kYXlbZGF5XSA8LSBzdW0odmVjX3JfZCArIHZlY19yX2IpCiAgICBpZiAoZGF5ID09IDEpewogICAgICAgIHZlY19yQWNjdS5kYXlbZGF5XSA8LSB2ZWNfci5kYXlbZGF5XQogICAgfSBlbHNlIHsKICAgICAgICB2ZWNfckFjY3UuZGF5W2RheV0gPC0gdmVjX3IuZGF5W2RheV0gKyB2ZWNfckFjY3UuZGF5W2RheS0xXQogICAgfQp9OyBybSh2ZWNfZV9kLCB2ZWNfcl9kLCBsaXN0X3JlYWwsIGxpc3RfcFJlZ3UsIHZlY19yX2IpCnBsb3RSZXZlbnVlRGF5KHZlY19yQWNjdS5kYXksIHZlY19yQWNjdU1heC5kYXksICJcIkZpeGVkIFZvbHVtZVwiIikKcHJpbnQocGFzdGUoIlJlc3VsdDogdG90YWwgcmV2ZW51ZSA9IiwgdmVjX3JBY2N1LmRheVszNjVdKSkKcHJpbnQocGFzdGUoIlJlc3VsdDogZ2FtbWEgPSIsIHZlY19yQWNjdS5kYXlbMzY1XSAvIHZlY19yQWNjdU1heC5kYXlbMzY1XSkpCnJtKHZlY19yQWNjdS5kYXksIHZlY19yLmRheSkKYGBgCgojIyA2LjMgVHJhZGluZyBTdHJhdGVneSB1c2luZyBEZXRlcm1pbmlzdGljIFdpbmQgUG93ZXIgRm9yZWNhc3RzCgpgYGB7ciwgZmlnLmhlaWdodCA9IDYsIGZpZy53aWR0aCA9IDExfQp2ZWNfckFjY3UuZGF5IDwtIHJlcCgwLCAzNjUpCnZlY19yLmRheSA8LSByZXAoMCwgMzY1KQojIEZvciBldmVyeSBkYXkgaW4gMjAxNywgY2FsY3VsYXRlIHRoZSByZXZlbnVlCmZvciAoZGF5IGluIDE6IDM2NSl7CiAgICAjIDEuIENhbGN1bGF0ZSB0cmFkZSB2b2x1bWUKICAgIHZlY19lX2QgPC0gZGF0LmZfcV8xNyRwcmVkVmFsdWVbKDI0ICogKGRheS0xKSArIDEpOiAoMjQgKiAoZGF5LTEpICsgMjQpXQogICAgdmVjX2VfZCA8LSAxLjAgKiB2ZWNfZV9kCiAgICAjIElmIGFueSBkYXRhIGlzIG1pc3NpbmcsIGRvbid0IHRyYWRlIG9uIHRoYXQgZGF5CiAgICBsaXN0X3JlYWwgPC0gZ2V0UmVhbFZhbHVlKGRhdC5mX3BfMTckZCwgZGF0LmZfcF8xNyRiLCBkYXQuZl9xXzE3JHJlYWxNZWFzdXJlLCBkYXkpCiAgICB2ZWNfZV9kW2lzLm5hKGxpc3RfcmVhbCRkKV0gPC0gMAogICAgdmVjX2VfZFtpcy5uYShsaXN0X3JlYWwkYildIDwtIDAKICAgIHZlY19lX2RbaXMubmEobGlzdF9yZWFsJGUpXSA8LSAwCiAgICB2ZWNfZV9kWyhpcy5uYSh2ZWNfZV9kKSldIDwtIDAKICAgIGxpc3RfcmVhbCRlW2lzLm5hKGxpc3RfcmVhbCRkKV0gPC0gMAogICAgbGlzdF9yZWFsJGVbaXMubmEobGlzdF9yZWFsJGIpXSA8LSAwCiAgICBsaXN0X3JlYWwkZVtpcy5uYShsaXN0X3JlYWwkZSldIDwtIDAKICAgICMgMi4gVHJhZGUgaW4gZGF5LWFoZWFkIG1hcmtldAogICAgdmVjX3JfZCA8LSB0cmFkZURheUFoZWFkKHZlY19lX2QsIGxpc3RfcmVhbCRkKQogICAgIyAzLiBUcmFkZSBpbiBiYWxhbmNpbmcgbWFyZWt0CiAgICBsaXN0X3BSZWd1IDwtIGNhbFJlZ3VQcmljZShsaXN0X3JlYWwkZCwgbGlzdF9yZWFsJGIpCiAgICB2ZWNfcl9iIDwtIHRyYWRlQmFsYW5jaW5nKHZlY19lX2QsIGxpc3RfcmVhbCRlLCBsaXN0X3BSZWd1JHVwLCBsaXN0X3BSZWd1JGR3KQogICAgIyA0LiBDYWxjdWxhdGUgdGhlIHJldmVudWUgaW4gdGhpcyBkYXkKICAgIHZlY19yLmRheVtkYXldIDwtIHN1bSh2ZWNfcl9kICsgdmVjX3JfYikKICAgIGlmIChkYXkgPT0gMSl7CiAgICAgICAgdmVjX3JBY2N1LmRheVtkYXldIDwtIHZlY19yLmRheVtkYXldCiAgICB9IGVsc2UgewogICAgICAgIHZlY19yQWNjdS5kYXlbZGF5XSA8LSB2ZWNfci5kYXlbZGF5XSArIHZlY19yQWNjdS5kYXlbZGF5LTFdCiAgICB9Cn07IHJtKHZlY19lX2QsIHZlY19yX2QsIGxpc3RfcmVhbCwgbGlzdF9wUmVndSwgdmVjX3JfYikKcGxvdFJldmVudWVEYXkodmVjX3JBY2N1LmRheSwgdmVjX3JBY2N1TWF4LmRheSwgIlwiRGV0ZXJtaW5pc3RpYyBGb3JlY2FzdFwiIikKcHJpbnQocGFzdGUoIlJlc3VsdDogdG90YWwgcmV2ZW51ZSA9IiwgdmVjX3JBY2N1LmRheVszNjVdKSkKcHJpbnQocGFzdGUoIlJlc3VsdDogZ2FtbWEgPSIsIHZlY19yQWNjdS5kYXlbMzY1XSAvIHZlY19yQWNjdU1heC5kYXlbMzY1XSkpCnJtKHZlY19yQWNjdS5kYXksIHZlY19yLmRheSkKYGBgCgojIyA2LjQgVHJhZGluZyBTdHJhdGVneSB1c2luZyBQcm9iYWJsaXN0aWMgV2luZCBQb3dlciBGb3JlY2FzdHMKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gMTF9CnZlY19yQWNjdS5kYXkgPC0gcmVwKDAsIDM2NSkKdmVjX3IuZGF5IDwtIHJlcCgwLCAzNjUpCiMgMS4gUHJlZGljdCBkYXktYWhlYWQgYW5kIGJhbGFuY2luZyBwcmljZXMKdmVjX3BfZF9oYXQgPC0gdmVjX3BfbWVhbi5kYXlfMTYKdmVjX3BfYl9oYXQgPC0gKG1hdF9jICUqJSB2ZWNfcF9kX2hhdClbICwgMV0gICMgdmVjX3BfYl9oYXQgPC0gcmVwKDAsIDI0KQpsaXN0X3BSZWd1X2hhdCA8LSBjYWxSZWd1UHJpY2UodmVjX3BfZF9oYXQsIHZlY19wX2JfaGF0KQojIEZvciBldmVyeSBkYXkgaW4gMjAxNywgY2FsY3VsYXRlIHRoZSByZXZlbnVlCmZvciAoZGF5IGluIDE6IDM2NSl7CiAgICAjIDIuIENhbGN1bGF0ZSB0cmFkZSB2b2x1bWUKICAgIHZlY19lX2QgPC0gdXNlU3RyYXRlZ3lQcm9iKHZlY19wX2RfaGF0LCBsaXN0X3BSZWd1X2hhdCR1cCwgbGlzdF9wUmVndV9oYXQkZHcsIGRhdC5mX3FfMTcpCiAgICAjIElmIGFueSBkYXRhIGlzIG1pc3NpbmcsIGRvbid0IHRyYWRlIG9uIHRoYXQgZGF5CiAgICBsaXN0X3JlYWwgPC0gZ2V0UmVhbFZhbHVlKGRhdC5mX3BfMTckZCwgZGF0LmZfcF8xNyRiLCBkYXQuZl9xXzE3JHJlYWxNZWFzdXJlLCBkYXkpCiAgICB2ZWNfZV9kW2lzLm5hKGxpc3RfcmVhbCRkKV0gPC0gMAogICAgdmVjX2VfZFtpcy5uYShsaXN0X3JlYWwkYildIDwtIDAKICAgIHZlY19lX2RbaXMubmEobGlzdF9yZWFsJGUpXSA8LSAwCiAgICBsaXN0X3JlYWwkZVtpcy5uYShsaXN0X3JlYWwkZCldIDwtIDAgCiAgICBsaXN0X3JlYWwkZVtpcy5uYShsaXN0X3JlYWwkYildIDwtIDAKICAgIGxpc3RfcmVhbCRlW2lzLm5hKGxpc3RfcmVhbCRlKV0gPC0gMAogICAgIyAzLiBUcmFkZSBpbiBkYXktYWhlYWQgbWFya2V0CiAgICB2ZWNfcl9kIDwtIHRyYWRlRGF5QWhlYWQodmVjX2VfZCwgbGlzdF9yZWFsJGQpCiAgICAjIDQuIFRyYWRlIGluIGJhbGFuY2luZyBtYXJla3QKICAgIGxpc3RfcFJlZ3UgPC0gY2FsUmVndVByaWNlKGxpc3RfcmVhbCRkLCBsaXN0X3JlYWwkYikKICAgIHZlY19yX2IgPC0gdHJhZGVCYWxhbmNpbmcodmVjX2VfZCwgbGlzdF9yZWFsJGUsIGxpc3RfcFJlZ3UkdXAsIGxpc3RfcFJlZ3UkZHcpCiAgICAjIDUuIENhbGN1bGF0ZSB0aGUgcmV2ZW51ZSBpbiB0aGlzIGRheQogICAgdmVjX3IuZGF5W2RheV0gPC0gc3VtKHZlY19yX2QgKyB2ZWNfcl9iKQogICAgaWYgKGRheSA9PSAxKXsKICAgICAgICB2ZWNfckFjY3UuZGF5W2RheV0gPC0gdmVjX3IuZGF5W2RheV0KICAgIH0gZWxzZSB7CiAgICAgICAgdmVjX3JBY2N1LmRheVtkYXldIDwtIHZlY19yLmRheVtkYXldICsgdmVjX3JBY2N1LmRheVtkYXktMV0KICAgIH0KfTsgcm0odmVjX2VfZCwgdmVjX3JfZCwgbGlzdF9yZWFsLCBsaXN0X3BSZWd1LCB2ZWNfcl9iKQpwbG90UmV2ZW51ZURheSh2ZWNfckFjY3UuZGF5LCB2ZWNfckFjY3VNYXguZGF5LCAiXCJQcm9iIEZvcmVjYXN0XCIiKQpwcmludChwYXN0ZSgiUmVzdWx0OiB0b3RhbCByZXZlbnVlID0iLCB2ZWNfckFjY3UuZGF5WzM2NV0pKQpwcmludChwYXN0ZSgiUmVzdWx0OiBnYW1tYSA9IiwgdmVjX3JBY2N1LmRheVszNjVdIC8gdmVjX3JBY2N1TWF4LmRheVszNjVdKSkKcm0odmVjX3JBY2N1LmRheSwgdmVjX3IuZGF5KQpgYGAKCgpgYGB7ciwgZmlnLmhlaWdodCA9IDYsIGZpZy53aWR0aCA9IDExfQpjYWxSZXZlbnVlUHJvYlN0cmF0ZWd5IDwtIGZ1bmN0aW9uKHZlY19wX21lYW4uZGF5XzE2LCBkYXQuZl9wXzE3LCBkYXQuZl9xXzE3LCByZXZlbnVlTWF4KXsKICAgIHZlY19yQWNjdS5kYXkgPC0gcmVwKDAsIDM2NSkKICAgIHZlY19yLmRheSA8LSByZXAoMCwgMzY1KQogICAgIyAxLiBQcmVkaWN0IGRheS1haGVhZCBhbmQgYmFsYW5jaW5nIHByaWNlcwogICAgdmVjX3BfZF9oYXQgPC0gdmVjX3BfbWVhbi5kYXlfMTYKICAgIHZlY19wX2JfaGF0IDwtIChtYXRfYyAlKiUgdmVjX3BfZF9oYXQpWyAsIDFdICAjIHZlY19wX2JfaGF0IDwtIHJlcCgwLCAyNCkKICAgIGxpc3RfcFJlZ3VfaGF0IDwtIGNhbFJlZ3VQcmljZSh2ZWNfcF9kX2hhdCwgdmVjX3BfYl9oYXQpCiAgICAjIEZvciBldmVyeSBkYXkgaW4gMjAxNywgY2FsY3VsYXRlIHRoZSByZXZlbnVlCiAgICBmb3IgKGRheSBpbiAxOiAzNjUpewogICAgICAgICMgMi4gQ2FsY3VsYXRlIHRyYWRlIHZvbHVtZQogICAgICAgIHZlY19lX2QgPC0gdXNlU3RyYXRlZ3lQcm9iKHZlY19wX2RfaGF0LCBsaXN0X3BSZWd1X2hhdCR1cCwgbGlzdF9wUmVndV9oYXQkZHcsIGRhdC5mX3FfMTcpCiAgICAgICAgdmVjX2VfZCA8LSB2ZWNfZV9kICogMC43CiAgICAgICAgIyBJZiBhbnkgZGF0YSBpcyBtaXNzaW5nLCBkb24ndCB0cmFkZSBvbiB0aGF0IGRheQogICAgICAgIGxpc3RfcmVhbCA8LSBnZXRSZWFsVmFsdWUoZGF0LmZfcF8xNyRkLCBkYXQuZl9wXzE3JGIsIGRhdC5mX3FfMTckcmVhbE1lYXN1cmUsIGRheSkKICAgICAgICB2ZWNfZV9kW2lzLm5hKGxpc3RfcmVhbCRkKV0gPC0gMAogICAgICAgIHZlY19lX2RbaXMubmEobGlzdF9yZWFsJGIpXSA8LSAwCiAgICAgICAgdmVjX2VfZFtpcy5uYShsaXN0X3JlYWwkZSldIDwtIDAKICAgICAgICBsaXN0X3JlYWwkZVtpcy5uYShsaXN0X3JlYWwkZCldIDwtIDAgCiAgICAgICAgbGlzdF9yZWFsJGVbaXMubmEobGlzdF9yZWFsJGIpXSA8LSAwCiAgICAgICAgbGlzdF9yZWFsJGVbaXMubmEobGlzdF9yZWFsJGUpXSA8LSAwCiAgICAgICAgIyAzLiBUcmFkZSBpbiBkYXktYWhlYWQgbWFya2V0CiAgICAgICAgdmVjX3JfZCA8LSB0cmFkZURheUFoZWFkKHZlY19lX2QsIGxpc3RfcmVhbCRkKQogICAgICAgICMgNC4gVHJhZGUgaW4gYmFsYW5jaW5nIG1hcmVrdAogICAgICAgIGxpc3RfcFJlZ3UgPC0gY2FsUmVndVByaWNlKGxpc3RfcmVhbCRkLCBsaXN0X3JlYWwkYikKICAgICAgICB2ZWNfcl9iIDwtIHRyYWRlQmFsYW5jaW5nKHZlY19lX2QsIGxpc3RfcmVhbCRlLCBsaXN0X3BSZWd1JHVwLCBsaXN0X3BSZWd1JGR3KQogICAgICAgICMgNS4gQ2FsY3VsYXRlIHRoZSByZXZlbnVlIGluIHRoaXMgZGF5CiAgICAgICAgdmVjX3IuZGF5W2RheV0gPC0gc3VtKHZlY19yX2QgKyB2ZWNfcl9iKQogICAgICAgIGlmIChkYXkgPT0gMSl7CiAgICAgICAgICAgIHZlY19yQWNjdS5kYXlbZGF5XSA8LSB2ZWNfci5kYXlbZGF5XQogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHZlY19yQWNjdS5kYXlbZGF5XSA8LSB2ZWNfci5kYXlbZGF5XSArIHZlY19yQWNjdS5kYXlbZGF5LTFdCiAgICAgICAgfQogICAgfQogICAgcGxvdFJldmVudWVEYXkodmVjX3JBY2N1LmRheSwgdmVjX3JBY2N1TWF4LmRheSwgIlwiUHJvYiBGb3JlY2FzdFwiIikKICAgIHByaW50KHBhc3RlKCJSZXN1bHQ6IHRvdGFsIHJldmVudWUgPSIsIHZlY19yQWNjdS5kYXlbMzY1XSkpCiAgICBnYW1tYSA8LSB2ZWNfckFjY3UuZGF5WzM2NV0gLyByZXZlbnVlTWF4CiAgICBwcmludChwYXN0ZSgiUmVzdWx0OiBnYW1tYSA9IiwgZ2FtbWEpKQogICAgcmV0dXJuKGdhbW1hKQp9Cm9wdGltKHBhciA9IGMoMCwgMSksIGZuID0gbWluLlJTUywgZGF0YSA9IGRhdCkKYGBgCgoKCgoKCgoKCgoKCg==