library(forecast)
library(gplots)

1. Requirement

Assignment 2 concentrates on participation in electricity markets with a portfolio of renewable energy generation. This portfolio actually consists of a single wind farm located in Western Denmark. Assign- ment 2 requires knowledge of both basic market concepts (day-ahead and balancing stages) and market participation aspects following the lectures, exercise sessions, games and reading material from the first 8 weeks of the course.

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.1 The maximum revenue from trade with Perfect Information:

calRevenueMax <- function(vec_p_d, vec_qReal){
    # If any data is missing, don't trade on that day
    vec_qReal[is.na(vec_qReal)] <- 0
    vec_qReal[is.na(vec_p_d)] <- 0
    vec_p_d[is.na(vec_qReal)] <- 0
    vec_p_d[is.na(vec_p_d)] <- 0
    # Calculate vector of maximum revenue and maximum accumulated revenue
    vec_rMax.h <- vec_p_d * vec_qReal
    vec_rMax.day <- rep(0, 365)
    vec_rAccuMax.day <- rep(0, 365)
    for (day in 1: 365){
        vec_rMax.day[day] <- sum(vec_rMax.h[(24 * (day-1) + 1): (24 * (day-1) + 24)])
        if (day == 1){
            vec_rAccuMax.day[day] <- vec_rMax.day[1]
        } else {
            vec_rAccuMax.day[day] <- vec_rMax.day[day] + vec_rAccuMax.day[day-1]
        }
    }; rm(day)
    plot(seq(1: 365), vec_rAccuMax.day, type = "l", col = "red", lty = 2, lwd = 2,
            main = paste("Maximum Accumulated Revenue Over the Year 2017 with Perfect Information"), 
            xlab = "month", ylab = "revenue (DKK)", xaxt = "n", bty = "n")
    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)
    return(vec_rAccuMax.day)
}
vec_rAccuMax.day <- calRevenueMax(dat.f_p_17$d, dat.f_q_17$realMeasure)

rm(calRevenueMax)

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==