library(lubridate)
library(gplots)  # heatmap.2
library(forecast)
package 'forecast' was built under R version 3.5.2
frameData <- function(){
    dat <- read.csv("TrainData1.csv", header = T)
    vec_tStamp_raw <- ymd_hm(dat[2: 26305, 1], "%Y%m%d %H:%M", tz="UTC")
    vec_tStamp <- vec_tStamp_raw[1: 26304]
    seq(1, 26304)[is.na(vec_tStamp)]
    dat.f <- data.frame("series" = seq(1, 26304), "year" = year(vec_tStamp), "month" = month(vec_tStamp), 
                        "day" = day(vec_tStamp), "hour" = hour(vec_tStamp), "power" = dat[2: 26305, 2], 
                        "u10" = dat[2: 26305, 3], "v10" = dat[2: 26305, 4], "u100" = dat[2: 26305, 5], 
                        "v100" = dat[2: 26305, 6])
    return(dat.f)
}
dat.f <- frameData()
rm(frameData)
plotBoxPlot <- function(dat, index = T, str_fact, str_y, str_con = "all"){
    par(bty="n")
    plot(factor(dat[str_fact][index,1]), dat.f[str_y][index,1], xlab = paste(str_fact), ylab = "Power Output",
        main = paste("Box Plot of Power Output By (", str_fact, ") when (", str_con, ")", sep = ""))
    # Add an average line to the box plot
    # y.ave <- ave(dat.f[str_y][index,1])
    # lines(c(1, 12), c(y.ave, y.ave), lty = 2, col = "red", lwd = 3)
    # legend("bottomleft", inset = .02, legend = "Average", col = "red", lty = 2, lwd = 3)    
}
plotBoxPlot(dat=dat.f, index=dat.f$year == 2016, str_fact="month", str_y="power", str_con="year 2016")

plotBoxPlot(dat=dat.f, index=dat.f$year == 2017, str_fact="month", str_y="power", str_con="year 2017")

plotBoxPlot(dat=dat.f, str_fact="hour", str_y="power")

Assumptions

Regressional Model

calNominalWindSpeed <- function(vec_windSpeed_1, vec_windSpeed_2, vec_windSpeed_3, vec_windSpeed_4, alpha = 0.5){
    vec_windSpeed.max_10 <- sqrt(vec_windSpeed_1^2 + vec_windSpeed_2^2)
    vec_windSpeed.max_100 <- sqrt(vec_windSpeed_3^2 + vec_windSpeed_4^2)
    vec_windSpeed.nominal <- alpha * vec_windSpeed.max_10 + (1 - alpha) * vec_windSpeed.max_100
    return(vec_windSpeed.nominal)
}
vec_windSpeed.nominal <- calNominalWindSpeed(dat.f$u10, dat.f$v10, dat.f$u100, dat.f$v100, 0.6)

mod_regress <- glm(dat.f$power ~ dat.f$speed + I(dat.f$speed^2) + I(dat.f$speed^3))
plot(dat.f$speed, dat.f$power, xlab = 'Wind Speed', ylab = 'Normalized Power Production')
lines(seq(0, 25, by = 0.1), mod_regress$coefficients[1] + 
          mod_regress$coefficients[2] * seq(0, 25, by = 0.1) +
          mod_regress$coefficients[3] * seq(0, 25, by = 0.1)^2 + 
          mod_regress$coefficients[4] * seq(0, 25, by = 0.1)^3, col = "red")

mod_regress <- glm(dat.f$power ~ dat.f$speed + I(dat.f$speed^3))
plot(dat.f$speed, dat.f$power, xlab = 'Wind Speed', ylab = 'Normalized Power Production')
lines(seq(0, 25, by = 0.1), mod_regress$coefficients[1] + 
          mod_regress$coefficients[2] * seq(0, 25, by = 0.1) +
          mod_regress$coefficients[3] * seq(0, 25, by = 0.1)^3, col = "red")

ARIMA Model

# Plot the time series / residuals and its ACF, PACF, and Ljung-Box plot
plotTimeSeriesResidual <- function(dat, num_lag = 20, str_name = "Model", ...){
    # If the input dat is arima model, just take its residuals are the dat.
    if(class(dat) == "Arima")
        dat <- dat$residuals
    par(mfrow = c(4, 1), mgp = c(2, 0.7, 0), mar = c(1, 1, 1, 1), oma = c(2, 2, 4, 2), 
        cex.lab = 0.8, cex.axis = 0.8)
    plot(dat, type = "l", bty = "n")
    title(main = paste("TS, ACF, PACF and p Values for Ljung-Box Statistic of", str_name), 
          cex.main = 1.5, line = 1, outer = TRUE)
    # ACF and PACF
    acf(dat, lag.max = num_lag, xaxt = "n", bty = "n", na.action = na.pass)
    axis(1, at = seq(0, num_lag, by = 1), las = 0, outer = FALSE)
    pacf(dat, lag.max = num_lag, xaxt = "n", bty = "n", na.action = na.pass)
    axis(1, at = seq(1, num_lag, by = 1), las = 0, outer = FALSE)
    # Ljung-Box Plot
    value_p <- sapply(1: num_lag, function(i) Box.test(dat, i, type = "Ljung-Box")$p.value)
    plot(1L: num_lag, value_p, xlab = "lag", ylab = "p value", ylim = c(0, 1), bty = "n", xaxt = "n")
    axis(1, at = seq(1, num_lag, by = 1), las = 0, outer = FALSE)
    abline(h = 0.05, lty = 2, col = "blue")
}

mod_arima_1 <- arima(dat.f$power, order = c(0, 1, 0), include.mean = F)
plotTimeSeriesResidual(mod_arima_1$residuals, num_lag = 48)

mod_arima_2 <- arima(mod_arima_1$residuals, order = c(0, 0, 1), seasonal = list(order = c(0, 0, 1), period = 48), 
                     include.mean = F)
plotTimeSeriesResidual(mod_arima_2$residuals, num_lag = 48)

# acf(mod_arima_2$residuals, lag.max = 48, na.action = na.pass)
# ts_power <- ts(dat.f$power, frequency = 24)
plotTimeSeriesResidual(dat.f$speed, num_lag = 48)

mod_arima_3 <- arima(dat.f$speed, order = c(0, 1, 0), include.mean = F)
plotTimeSeriesResidual(mod_arima_3$residuals, num_lag = 48)
mod_arima_4 <- arima(mod_arima_3$residuals, order = c(3, 0, 0), include.mean = F)
plotTimeSeriesResidual(mod_arima_4$residuals, num_lag = 48)

ccf(dat.f$speed, dat.f$power, na.action = na.pass)

ts_power <- ts(dat.f$power, frequency = 24)
y <- residuals(Arima(ts_power, model = mod_arima_5))
ccf(mod_arima_5$residuals, y, na.action = na.pass)

ts_power <- ts(dat.f$power[dat.f$month == 1], frequency = 24)
y <- residuals(Arima(ts_power, model = mod_arima_7))
ccf(mod_arima_7$residuals, y, na.action = na.pass)

ts_power <- ts(dat.f$power[dat.f$month == 1], frequency = 24)
y <- residuals(Arima(ts_power, model = mod_arima_9))
ccf(mod_arima_9$residuals, y, na.action = na.pass)
ccf(dat.f$u10, dat.f$v10)

ccf(dat.f$u10, dat.f$u100)

Ridge Regression

calRidgeRegress <- function(mat_x, vec_y, lambda){
    n <- length(mat_x[1,])
    mat_x[is.na(mat_x)] <- 0
    vec_y[is.na(vec_y)] <- 0
    vec_theta <- solve(t(mat_x) %*% mat_x + lambda * diag(n)) %*% t(mat_x) %*% vec_y
    return(vec_theta)
}
mat_x <- cbind(dat.f$u10[2: 26304], dat.f$v10[2: 26304], dat.f$u100[2: 26304], dat.f$v100[2: 26304],
               dat.f$u10[1: 26303], dat.f$v10[1: 26303], dat.f$u100[1: 26303], dat.f$v100[1: 26303])
vec_theta <- calRidgeRegress(mat_x, dat.f$power[2: 26304], 0.1)
frameData <- function(){
    dat <- read.csv("WeatherForecastInput1.csv", header = T)
    vec_tStamp_raw <- ymd_hm(dat[1: 24, 1], "%Y%m%d %H:%M", tz="UTC")
    vec_tStamp <- vec_tStamp_raw[1: 24]
    dat.f <- data.frame("series" = seq(1, 24), "year" = year(vec_tStamp), "month" = month(vec_tStamp), 
                        "day" = day(vec_tStamp), "hour" = hour(vec_tStamp), "u10" = dat[, 2], "v10" = dat[, 3], 
                        "u100" = dat[, 4], "v100" = dat[, 5])
    return(dat.f)
}
dat.f_pred <- frameData()
rm(frameData)
predPowerOutput <- function(mat_x, vec_theta_hat){
    vec_y_hat <- mat_x %*% vec_theta_hat
    return(vec_y_hat)
}
mat_x_pred <- cbind(dat.f_pred$u10, dat.f_pred$v10, dat.f_pred$u100, dat.f_pred$v100, 
    c(dat.f[26304,]$u10, dat.f_pred$u10[1: 23]), c(dat.f[26304,]$v10, dat.f_pred$v10[1: 23]), 
    c(dat.f[26304,]$u100, dat.f_pred$u100[1: 23]), c(dat.f[26304,]$v100, dat.f_pred$v100[1: 23]))
predPowerOutput(mat_x_pred, vec_theta)
           [,1]
 [1,] 0.4838088
 [2,] 0.4525539
 [3,] 0.5559471
 [4,] 0.6226099
 [5,] 0.5641014
 [6,] 0.5609152
 [7,] 0.5590238
 [8,] 0.6647319
 [9,] 0.8218065
[10,] 0.8912047
[11,] 0.8617088
[12,] 0.8974107
[13,] 0.7678256
[14,] 0.6689318
[15,] 0.6808180
[16,] 0.6932964
[17,] 0.6466008
[18,] 0.6154091
[19,] 0.5979905
[20,] 0.5572132
[21,] 0.5009179
[22,] 0.4996018
[23,] 0.4775083
[24,] 0.4206646
vec_x <- 0.5 * sqrt(dat.f_pred$u10^2 +  dat.f_pred$v10^2) + 0.5 * sqrt(dat.f_pred$u100^2 + dat.f_pred$v100^2)
plot(vec_x, vec_y_hat, xlim = c(0, 20), ylim = c(0, 1))

LS0tCnRpdGxlOiAiV2luZCBQb3dlciBPdXRwdXQgRm9yZWNhc3QiCm91dHB1dDogaHRtbF9ub3RlYm9vawphdXRob3I6IEVkd2FyZCBKLiBYdQpkYXRlOiBBcHJpbCAyMnRoLCAyMDE5Ci0tLQoKYGBge3IsIGluY2x1ZGU9RkFMU0V9CiMgQ2xlYXIgdmFyaWFibGVzCnJtKGxpc3Q9bHMoKSkKbGlicmFyeShrbml0cikKYGBgCgpgYGB7cn0KbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkoZ3Bsb3RzKSAgIyBoZWF0bWFwLjIKbGlicmFyeShmb3JlY2FzdCkKYGBgCgpgYGB7ciwgd2FybmluZz1GQUxTRX0KZnJhbWVEYXRhIDwtIGZ1bmN0aW9uKCl7CiAgICBkYXQgPC0gcmVhZC5jc3YoIlRyYWluRGF0YTEuY3N2IiwgaGVhZGVyID0gVCkKICAgIHZlY190U3RhbXBfcmF3IDwtIHltZF9obShkYXRbMjogMjYzMDUsIDFdLCAiJVklbSVkICVIOiVNIiwgdHo9IlVUQyIpCiAgICB2ZWNfdFN0YW1wIDwtIHZlY190U3RhbXBfcmF3WzE6IDI2MzA0XQogICAgc2VxKDEsIDI2MzA0KVtpcy5uYSh2ZWNfdFN0YW1wKV0KICAgIGRhdC5mIDwtIGRhdGEuZnJhbWUoInNlcmllcyIgPSBzZXEoMSwgMjYzMDQpLCAieWVhciIgPSB5ZWFyKHZlY190U3RhbXApLCAibW9udGgiID0gbW9udGgodmVjX3RTdGFtcCksIAogICAgICAgICAgICAgICAgICAgICAgICAiZGF5IiA9IGRheSh2ZWNfdFN0YW1wKSwgImhvdXIiID0gaG91cih2ZWNfdFN0YW1wKSwgInBvd2VyIiA9IGRhdFsyOiAyNjMwNSwgMl0sIAogICAgICAgICAgICAgICAgICAgICAgICAidTEwIiA9IGRhdFsyOiAyNjMwNSwgM10sICJ2MTAiID0gZGF0WzI6IDI2MzA1LCA0XSwgInUxMDAiID0gZGF0WzI6IDI2MzA1LCA1XSwgCiAgICAgICAgICAgICAgICAgICAgICAgICJ2MTAwIiA9IGRhdFsyOiAyNjMwNSwgNl0pCiAgICByZXR1cm4oZGF0LmYpCn0KZGF0LmYgPC0gZnJhbWVEYXRhKCkKcm0oZnJhbWVEYXRhKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gMTF9CnBsb3RCb3hQbG90IDwtIGZ1bmN0aW9uKGRhdCwgaW5kZXggPSBULCBzdHJfZmFjdCwgc3RyX3ksIHN0cl9jb24gPSAiYWxsIil7CiAgICBwYXIoYnR5PSJuIikKICAgIHBsb3QoZmFjdG9yKGRhdFtzdHJfZmFjdF1baW5kZXgsMV0pLCBkYXQuZltzdHJfeV1baW5kZXgsMV0sIHhsYWIgPSBwYXN0ZShzdHJfZmFjdCksIHlsYWIgPSAiUG93ZXIgT3V0cHV0IiwKICAgICAgICBtYWluID0gcGFzdGUoIkJveCBQbG90IG9mIFBvd2VyIE91dHB1dCBCeSAoIiwgc3RyX2ZhY3QsICIpIHdoZW4gKCIsIHN0cl9jb24sICIpIiwgc2VwID0gIiIpKQogICAgIyBBZGQgYW4gYXZlcmFnZSBsaW5lIHRvIHRoZSBib3ggcGxvdAogICAgIyB5LmF2ZSA8LSBhdmUoZGF0LmZbc3RyX3ldW2luZGV4LDFdKQogICAgIyBsaW5lcyhjKDEsIDEyKSwgYyh5LmF2ZSwgeS5hdmUpLCBsdHkgPSAyLCBjb2wgPSAicmVkIiwgbHdkID0gMykKICAgICMgbGVnZW5kKCJib3R0b21sZWZ0IiwgaW5zZXQgPSAuMDIsIGxlZ2VuZCA9ICJBdmVyYWdlIiwgY29sID0gInJlZCIsIGx0eSA9IDIsIGx3ZCA9IDMpICAgIAp9CnBsb3RCb3hQbG90KGRhdD1kYXQuZiwgaW5kZXg9ZGF0LmYkeWVhciA9PSAyMDE2LCBzdHJfZmFjdD0ibW9udGgiLCBzdHJfeT0icG93ZXIiLCBzdHJfY29uPSJ5ZWFyIDIwMTYiKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gMTF9CnBsb3RCb3hQbG90KGRhdD1kYXQuZiwgaW5kZXg9ZGF0LmYkeWVhciA9PSAyMDE3LCBzdHJfZmFjdD0ibW9udGgiLCBzdHJfeT0icG93ZXIiLCBzdHJfY29uPSJ5ZWFyIDIwMTciKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gMTF9CnBsb3RCb3hQbG90KGRhdD1kYXQuZiwgc3RyX2ZhY3Q9ImhvdXIiLCBzdHJfeT0icG93ZXIiKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gNn0KbnVtX2RheSA8LSBsZW5ndGgoZGF0LmZbKGRhdC5mJGhvdXIgPT0gMiksIF0kcG93ZXIpCm1hdF9wb3dlci5oIDwtIG1hdHJpeChucm93ID0gbnVtX2RheSwgbmNvbCA9IDI0KQpmb3IgKGkgaW4gMTogMjQpewogICAgIyBwcmludChsZW5ndGgoZGF0LmZbKGRhdC5mJGhvdXIgPT0gaS0xKSwgXSRwb3dlcikpCiAgICBtYXRfcG93ZXIuaFsgLCBpXSA8LSBkYXQuZlsoZGF0LmYkaG91ciA9PSBpLTEpLCBdJHBvd2VyCn07IHJtKGkpCiMgVXNpbmcgZnVuY3Rpb24gaGVhdG1hcC4yIGluIGxpYnJhcnkgZ3Bsb3RzIHRvIHZpc3VhbGl6ZSB0aGUgY29ycmVsYXRpb24gbWF0cml4CmhlYXRtYXAuMihjb3IobWF0X3Bvd2VyLmhbICwgMTogMjRdLCB1c2UgPSAiY29tcGxldGUub2JzIiksIGRlbmRyb2dyYW0gPSAibm9uZSIsIHRyYWNlPSJub25lIiwgUm93diA9IEYsIENvbHYgPSBGKQpgYGAKCiMgQXNzdW1wdGlvbnMKCi0gdGhlIHdpbmQgdHVyYmluZSB3aWxsIGFsd2F5cyB0b3dhcmRzIHRoZSBkaXJlY3Rpb24gd2l0aCBtYXggd2luZCBzcGVlZAotIGRpcmVjdGx5IHJlbGF0ZWQgdG8gdGhlIDNyZCBwb3dlciBvZiB3aW5kIHNwZWVkCi0gb3B0aW1hbCByZXByZXNlbnRhdGl2ZSB3aW5kIHNwZWVkIGlzIGxpbmVhciBjb21iaW5hdGlvbiBvZiBtYXggd2luZCBzcGVlZCBpbiBkaWZmZXJlbnQgaGVpZ2h0CgojIyBSZWdyZXNzaW9uYWwgTW9kZWwKCmBgYHtyfQpjYWxOb21pbmFsV2luZFNwZWVkIDwtIGZ1bmN0aW9uKHZlY193aW5kU3BlZWRfMSwgdmVjX3dpbmRTcGVlZF8yLCB2ZWNfd2luZFNwZWVkXzMsIHZlY193aW5kU3BlZWRfNCwgYWxwaGEgPSAwLjUpewogICAgdmVjX3dpbmRTcGVlZC5tYXhfMTAgPC0gc3FydCh2ZWNfd2luZFNwZWVkXzFeMiArIHZlY193aW5kU3BlZWRfMl4yKQogICAgdmVjX3dpbmRTcGVlZC5tYXhfMTAwIDwtIHNxcnQodmVjX3dpbmRTcGVlZF8zXjIgKyB2ZWNfd2luZFNwZWVkXzReMikKICAgIHZlY193aW5kU3BlZWQubm9taW5hbCA8LSBhbHBoYSAqIHZlY193aW5kU3BlZWQubWF4XzEwICsgKDEgLSBhbHBoYSkgKiB2ZWNfd2luZFNwZWVkLm1heF8xMDAKICAgIHJldHVybih2ZWNfd2luZFNwZWVkLm5vbWluYWwpCn0KZGF0LmZbInNwZWVkIl0gPC0gY2FsTm9taW5hbFdpbmRTcGVlZChkYXQuZiR1MTAsIGRhdC5mJHYxMCwgZGF0LmYkdTEwMCwgZGF0LmYkdjEwMCwgMC42KQpgYGAKCmBgYHtyLCAgZmlnLmhlaWdodCA9IDYsIGZpZy53aWR0aCA9IDExfQptb2RfcmVncmVzcyA8LSBnbG0oZGF0LmYkcG93ZXIgfiBJKGRhdC5mJHNwZWVkXjIpICsgSShkYXQuZiRzcGVlZF4zKSkKcGxvdChkYXQuZiRzcGVlZCwgZGF0LmYkcG93ZXIsIHhsYWIgPSAnV2luZCBTcGVlZCcsIHlsYWIgPSAnTm9ybWFsaXplZCBQb3dlciBQcm9kdWN0aW9uJykKYGBgCgpgYGB7ciwgIGZpZy5oZWlnaHQgPSA2LCBmaWcud2lkdGggPSAxMX0KbW9kX3JlZ3Jlc3MgPC0gZ2xtKGRhdC5mJHBvd2VyIH4gZGF0LmYkc3BlZWQgKyBJKGRhdC5mJHNwZWVkXjIpICsgSShkYXQuZiRzcGVlZF4zKSkKcGxvdChkYXQuZiRzcGVlZCwgZGF0LmYkcG93ZXIsIHhsYWIgPSAnV2luZCBTcGVlZCcsIHlsYWIgPSAnTm9ybWFsaXplZCBQb3dlciBQcm9kdWN0aW9uJykKbGluZXMoc2VxKDAsIDI1LCBieSA9IDAuMSksIG1vZF9yZWdyZXNzJGNvZWZmaWNpZW50c1sxXSArIAogICAgICAgICAgbW9kX3JlZ3Jlc3MkY29lZmZpY2llbnRzWzJdICogc2VxKDAsIDI1LCBieSA9IDAuMSkgKwogICAgICAgICAgbW9kX3JlZ3Jlc3MkY29lZmZpY2llbnRzWzNdICogc2VxKDAsIDI1LCBieSA9IDAuMSleMiArIAogICAgICAgICAgbW9kX3JlZ3Jlc3MkY29lZmZpY2llbnRzWzRdICogc2VxKDAsIDI1LCBieSA9IDAuMSleMywgY29sID0gInJlZCIpCmBgYAoKYGBge3IsICBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gMTF9Cm1vZF9yZWdyZXNzIDwtIGdsbShkYXQuZiRwb3dlciB+IGRhdC5mJHNwZWVkICszIEkoZGF0LmYkc3BlZWReMykpCnBsb3QoZGF0LmYkc3BlZWQsIGRhdC5mJHBvd2VyLCB4bGFiID0gJ1dpbmQgU3BlZWQnLCB5bGFiID0gJ05vcm1hbGl6ZWQgUG93ZXIgUHJvZHVjdGlvbicpCmxpbmVzKHNlcSgwLCAyNSwgYnkgPSAwLjEpLCBtb2RfcmVncmVzcyRjb2VmZmljaWVudHNbMV0gKyAKICAgICAgICAgIG1vZF9yZWdyZXNzJGNvZWZmaWNpZW50c1syXSAqIHNlcSgwLCAyNSwgYnkgPSAwLjEpICsKICAgICAgICAgIG1vZF9yZWdyZXNzJGNvZWZmaWNpZW50c1szXSAqIHNlcSgwLCAyNSwgYnkgPSAwLjEpXjMsIGNvbCA9ICJyZWQiKQpgYGAKCmBgYHtyLCBlY2hvID0gRkFMU0V9CiMgRnVuY3Rpb24gdG8gcGxvdCB0aGUgcHJlZGljdGlvbiByZXN1bHQgb2YgcmVncmVzc2lvbiBtb2RlbCBiYXNlZCBvbiB3aW5kIHNwZWVkLgpwcmVkaWN0UmVncmVzc2lvbi53aW5kU3BlZWQgPC0gZnVuY3Rpb24oeDEucHJlZCwgeDIsIHksIG1vZGVsUmVncmVzc2lvbil7CiAgICBkYXRhRnJhbWVQcmVkaWN0IDwtIGRhdGEuZnJhbWUoeDEgPSB4MS5wcmVkLCB4MiA9IHJlcChtZWFuKHgyKSwgbGVuZ3RoKHgxLnByZWQpKSkKICAgIHZhbHVlUHJlZCA8LSBwcmVkaWN0LmxtKG1vZGVsUmVncmVzc2lvbiwgZGF0YUZyYW1lUHJlZGljdCwgc2UuZml0ID0gVFJVRSkKICAgIGludGVydmFsUHJlZCA8LSBwcmVkaWN0LmxtKG1vZGVsUmVncmVzc2lvbiwgbmV3ZGF0YSA9IGRhdGFGcmFtZVByZWRpY3QsIGludGVydmFsID0gInByZWQiLCBsZXZlbCA9IDAuOTUpCiAgICBpbnRlcnZhbENvbmYgPC0gcHJlZGljdC5sbShtb2RlbFJlZ3Jlc3Npb24sIG5ld2RhdGEgPSBkYXRhRnJhbWVQcmVkaWN0LCBpbnRlcnZhbCA9ICJjb25mIiwgbGV2ZWwgPSAwLjk1KQogICAgcGxvdChkYXRhRnJhbWVQcmVkaWN0JHgxLCB2YWx1ZVByZWQkZml0LCBwY2ggPSAyMCwgeWxpbSA9IGMobWluKHksIGludGVydmFsUHJlZCksIG1heCh5LCBpbnRlcnZhbFByZWQpKSwgCiAgICAgICAgIHhsaW0gPSBjKG1pbih4MSwgZGF0YUZyYW1lUHJlZGljdCR4MSksIG1heCh4MSwgZGF0YUZyYW1lUHJlZGljdCR4MSkpLCAKICAgICAgICAgeGxhYiA9ICdXaW5kIFNwZWVkJywgeWxhYiA9ICdOb3JtYWxpemVkIFBvd2VyIFByb2R1Y3Rpb24nKQogICAgbWF0bGluZXMoZGF0YUZyYW1lUHJlZGljdCR4MSwgaW50ZXJ2YWxQcmVkLCBsdHkgPSBjKDEsIDIsIDIpLCBjb2wgPSBjKCJibGFjayIsICJibHVlIiwgImJsdWUiKSwgbHdkID0gMikKICAgIHBvaW50cyh4MSwgeSkgICMgVHJhbnNmb3JtZWQgb2JzZXJ2YXRpb25zCiAgICBsaW5lcyhkYXRhRnJhbWVQcmVkaWN0JHgxLCBpbnRlcnZhbENvbmZbLCAyXSwgbHR5ID0gMywgY29sID0gInJlZCIsIGx3ZCA9IDIpCiAgICBsaW5lcyhkYXRhRnJhbWVQcmVkaWN0JHgxLCBpbnRlcnZhbENvbmZbLCAzXSwgbHR5ID0gMywgY29sID0gInJlZCIsIGx3ZCA9IDIpCiAgICBsZWdlbmQoImJvdHRvbXJpZ2h0IiwgaW5zZXQgPSAuMDIsIGxlZ2VuZCA9IGMoIlJlZ3Jlc3Npb24gQ3VydmUiLCAiUHJlZGljdGlvbiBJbnRlcnZhbCIsICJDb25maWRlbmNlIEludGVyY2FsIiksIAogICAgICAgICAgIGNvbCA9IGMoImJsYWNrIiwgImJsdWUiLCAicmVkIiksIGx0eSA9IGMoMSwgMiwgMyksIGx3ZCA9IGMoMiwgMiwgMiksIGNleCA9IDAuOCkKfQpgYGAKCiMgQVJJTUEgTW9kZWwKCmBgYHtyfQojIFBsb3QgdGhlIHRpbWUgc2VyaWVzIC8gcmVzaWR1YWxzIGFuZCBpdHMgQUNGLCBQQUNGLCBhbmQgTGp1bmctQm94IHBsb3QKcGxvdFRpbWVTZXJpZXNSZXNpZHVhbCA8LSBmdW5jdGlvbihkYXQsIG51bV9sYWcgPSAyMCwgc3RyX25hbWUgPSAiTW9kZWwiLCAuLi4pewogICAgIyBJZiB0aGUgaW5wdXQgZGF0IGlzIGFyaW1hIG1vZGVsLCBqdXN0IHRha2UgaXRzIHJlc2lkdWFscyBhcmUgdGhlIGRhdC4KICAgIGlmKGNsYXNzKGRhdCkgPT0gIkFyaW1hIikKICAgICAgICBkYXQgPC0gZGF0JHJlc2lkdWFscwogICAgcGFyKG1mcm93ID0gYyg0LCAxKSwgbWdwID0gYygyLCAwLjcsIDApLCBtYXIgPSBjKDEsIDEsIDEsIDEpLCBvbWEgPSBjKDIsIDIsIDQsIDIpLCAKICAgICAgICBjZXgubGFiID0gMC44LCBjZXguYXhpcyA9IDAuOCkKICAgIHBsb3QoZGF0LCB0eXBlID0gImwiLCBidHkgPSAibiIpCiAgICB0aXRsZShtYWluID0gcGFzdGUoIlRTLCBBQ0YsIFBBQ0YgYW5kIHAgVmFsdWVzIGZvciBManVuZy1Cb3ggU3RhdGlzdGljIG9mIiwgc3RyX25hbWUpLCAKICAgICAgICAgIGNleC5tYWluID0gMS41LCBsaW5lID0gMSwgb3V0ZXIgPSBUUlVFKQogICAgIyBBQ0YgYW5kIFBBQ0YKICAgIGFjZihkYXQsIGxhZy5tYXggPSBudW1fbGFnLCB4YXh0ID0gIm4iLCBidHkgPSAibiIsIG5hLmFjdGlvbiA9IG5hLnBhc3MpCiAgICBheGlzKDEsIGF0ID0gc2VxKDAsIG51bV9sYWcsIGJ5ID0gMSksIGxhcyA9IDAsIG91dGVyID0gRkFMU0UpCiAgICBwYWNmKGRhdCwgbGFnLm1heCA9IG51bV9sYWcsIHhheHQgPSAibiIsIGJ0eSA9ICJuIiwgbmEuYWN0aW9uID0gbmEucGFzcykKICAgIGF4aXMoMSwgYXQgPSBzZXEoMSwgbnVtX2xhZywgYnkgPSAxKSwgbGFzID0gMCwgb3V0ZXIgPSBGQUxTRSkKICAgICMgTGp1bmctQm94IFBsb3QKICAgIHZhbHVlX3AgPC0gc2FwcGx5KDE6IG51bV9sYWcsIGZ1bmN0aW9uKGkpIEJveC50ZXN0KGRhdCwgaSwgdHlwZSA9ICJManVuZy1Cb3giKSRwLnZhbHVlKQogICAgcGxvdCgxTDogbnVtX2xhZywgdmFsdWVfcCwgeGxhYiA9ICJsYWciLCB5bGFiID0gInAgdmFsdWUiLCB5bGltID0gYygwLCAxKSwgYnR5ID0gIm4iLCB4YXh0ID0gIm4iKQogICAgYXhpcygxLCBhdCA9IHNlcSgxLCBudW1fbGFnLCBieSA9IDEpLCBsYXMgPSAwLCBvdXRlciA9IEZBTFNFKQogICAgYWJsaW5lKGggPSAwLjA1LCBsdHkgPSAyLCBjb2wgPSAiYmx1ZSIpCn0KYGBgCgpgYGB7ciwgZmlnLmhlaWdodCA9IDExLCBmaWcud2lkdGggPSAxMX0KIyB0c19wb3dlciA8LSB0cyhkYXQuZiRwb3dlciwgZnJlcXVlbmN5ID0gMjQpCnBsb3RUaW1lU2VyaWVzUmVzaWR1YWwoZGF0LmYkcG93ZXIsIG51bV9sYWcgPSA0OCkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodCA9IDExLCBmaWcud2lkdGggPSAxMX0KbW9kX2FyaW1hXzEgPC0gYXJpbWEoZGF0LmYkcG93ZXIsIG9yZGVyID0gYygwLCAxLCAwKSwgaW5jbHVkZS5tZWFuID0gRikKcGxvdFRpbWVTZXJpZXNSZXNpZHVhbChtb2RfYXJpbWFfMSRyZXNpZHVhbHMsIG51bV9sYWcgPSA0OCkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodCA9IDExLCBmaWcud2lkdGggPSAxMX0KbW9kX2FyaW1hXzIgPC0gYXJpbWEobW9kX2FyaW1hXzEkcmVzaWR1YWxzLCBvcmRlciA9IGMoMCwgMCwgMSksIHNlYXNvbmFsID0gbGlzdChvcmRlciA9IGMoMCwgMCwgMSksIHBlcmlvZCA9IDQ4KSwgCiAgICAgICAgICAgICAgICAgICAgIGluY2x1ZGUubWVhbiA9IEYpCnBsb3RUaW1lU2VyaWVzUmVzaWR1YWwobW9kX2FyaW1hXzIkcmVzaWR1YWxzLCBudW1fbGFnID0gNDgpCiMgYWNmKG1vZF9hcmltYV8yJHJlc2lkdWFscywgbGFnLm1heCA9IDQ4LCBuYS5hY3Rpb24gPSBuYS5wYXNzKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTEsIGZpZy53aWR0aCA9IDExfQojIHRzX3Bvd2VyIDwtIHRzKGRhdC5mJHBvd2VyLCBmcmVxdWVuY3kgPSAyNCkKcGxvdFRpbWVTZXJpZXNSZXNpZHVhbChkYXQuZiRzcGVlZCwgbnVtX2xhZyA9IDQ4KQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTEsIGZpZy53aWR0aCA9IDExfQptb2RfYXJpbWFfMyA8LSBhcmltYShkYXQuZiRzcGVlZCwgb3JkZXIgPSBjKDAsIDEsIDApLCBpbmNsdWRlLm1lYW4gPSBGKQpwbG90VGltZVNlcmllc1Jlc2lkdWFsKG1vZF9hcmltYV8zJHJlc2lkdWFscywgbnVtX2xhZyA9IDQ4KQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTEsIGZpZy53aWR0aCA9IDExfQptb2RfYXJpbWFfNCA8LSBhcmltYShtb2RfYXJpbWFfMyRyZXNpZHVhbHMsIG9yZGVyID0gYygzLCAwLCAwKSwgaW5jbHVkZS5tZWFuID0gRikKcGxvdFRpbWVTZXJpZXNSZXNpZHVhbChtb2RfYXJpbWFfNCRyZXNpZHVhbHMsIG51bV9sYWcgPSA0OCkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodCA9IDExLCBmaWcud2lkdGggPSAxMX0KdHNfc3BlZWQgPC0gdHMoZGF0LmYkc3BlZWQsIGZyZXF1ZW5jeSA9IDI0KQptb2RfYXJpbWFfNSA8LSBhdXRvLmFyaW1hKHRzX3NwZWVkKQpwbG90VGltZVNlcmllc1Jlc2lkdWFsKG1vZF9hcmltYV81JHJlc2lkdWFscywgbnVtX2xhZyA9IDQ4KQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gMTF9CmNjZihkYXQuZiRzcGVlZCwgZGF0LmYkcG93ZXIsIG5hLmFjdGlvbiA9IG5hLnBhc3MpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQgPSA2LCBmaWcud2lkdGggPSAxMX0KdHNfcG93ZXIgPC0gdHMoZGF0LmYkcG93ZXIsIGZyZXF1ZW5jeSA9IDI0KQp5IDwtIHJlc2lkdWFscyhBcmltYSh0c19wb3dlciwgbW9kZWwgPSBtb2RfYXJpbWFfNSkpCmNjZihtb2RfYXJpbWFfNSRyZXNpZHVhbHMsIHksIG5hLmFjdGlvbiA9IG5hLnBhc3MpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQgPSAxMSwgZmlnLndpZHRoID0gMTF9CnRzX3NwZWVkIDwtIHRzKGRhdC5mJHNwZWVkW2RhdC5mJG1vbnRoID09IDFdLCBmcmVxdWVuY3kgPSAyNCkKbW9kX2FyaW1hXzYgPC0gYXJpbWEodHNfc3BlZWQsIG9yZGVyID0gYygwLCAwLCAwKSwgc2Vhc29uYWwgPSBsaXN0KG9yZGVyID0gYygwLCAwLCAxKSwgcGVyaW9kID0gNDgpKQpwbG90VGltZVNlcmllc1Jlc2lkdWFsKG1vZF9hcmltYV82JHJlc2lkdWFscywgbnVtX2xhZyA9IDQ4KQptb2RfYXJpbWFfNyA8LSBhdXRvLmFyaW1hKG1vZF9hcmltYV82JHJlc2lkdWFscykKcGxvdFRpbWVTZXJpZXNSZXNpZHVhbChtb2RfYXJpbWFfNyRyZXNpZHVhbHMsIG51bV9sYWcgPSA0OCkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodCA9IDYsIGZpZy53aWR0aCA9IDExfQp0c19wb3dlciA8LSB0cyhkYXQuZiRwb3dlcltkYXQuZiRtb250aCA9PSAxXSwgZnJlcXVlbmN5ID0gMjQpCnkgPC0gcmVzaWR1YWxzKEFyaW1hKHRzX3Bvd2VyLCBtb2RlbCA9IG1vZF9hcmltYV83KSkKY2NmKG1vZF9hcmltYV83JHJlc2lkdWFscywgeSwgbmEuYWN0aW9uID0gbmEucGFzcykKYGBgCgpgYGB7ciwgZmlnLmhlaWdodCA9IDExLCBmaWcud2lkdGggPSAxMX0KdHNfc3BlZWQuMyA8LSB0cyhkYXQuZiRzcGVlZFtkYXQuZiRtb250aCA9PSAxXV4zLCBmcmVxdWVuY3kgPSAyNCkKbW9kX2FyaW1hXzkgPC0gYXV0by5hcmltYSh0c19zcGVlZC4zKQpwbG90VGltZVNlcmllc1Jlc2lkdWFsKG1vZF9hcmltYV85JHJlc2lkdWFscywgbnVtX2xhZyA9IDQ4KQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gMTF9CnRzX3Bvd2VyIDwtIHRzKGRhdC5mJHBvd2VyW2RhdC5mJG1vbnRoID09IDFdLCBmcmVxdWVuY3kgPSAyNCkKeSA8LSByZXNpZHVhbHMoQXJpbWEodHNfcG93ZXIsIG1vZGVsID0gbW9kX2FyaW1hXzkpKQpjY2YobW9kX2FyaW1hXzkkcmVzaWR1YWxzLCB5LCBuYS5hY3Rpb24gPSBuYS5wYXNzKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gMTF9CmNjZihkYXQuZiR1MTAsIGRhdC5mJHYxMCkKY2NmKGRhdC5mJHUxMCwgZGF0LmYkdTEwMCkKYGBgCgojIFJpZGdlIFJlZ3Jlc3Npb24KCmBgYHtyfQpjYWxSaWRnZVJlZ3Jlc3MgPC0gZnVuY3Rpb24obWF0X3gsIHZlY195LCBsYW1iZGEpewogICAgbiA8LSBsZW5ndGgobWF0X3hbMSxdKQogICAgbWF0X3hbaXMubmEobWF0X3gpXSA8LSAwCiAgICB2ZWNfeVtpcy5uYSh2ZWNfeSldIDwtIDAKICAgIHZlY190aGV0YSA8LSBzb2x2ZSh0KG1hdF94KSAlKiUgbWF0X3ggKyBsYW1iZGEgKiBkaWFnKG4pKSAlKiUgdChtYXRfeCkgJSolIHZlY195CiAgICByZXR1cm4odmVjX3RoZXRhKQp9Cm1hdF94IDwtIGNiaW5kKGRhdC5mJHUxMFsyOiAyNjMwNF0sIGRhdC5mJHYxMFsyOiAyNjMwNF0sIGRhdC5mJHUxMDBbMjogMjYzMDRdLCBkYXQuZiR2MTAwWzI6IDI2MzA0XSwKICAgICAgICAgICAgICAgZGF0LmYkdTEwWzE6IDI2MzAzXSwgZGF0LmYkdjEwWzE6IDI2MzAzXSwgZGF0LmYkdTEwMFsxOiAyNjMwM10sIGRhdC5mJHYxMDBbMTogMjYzMDNdKQp2ZWNfdGhldGEgPC0gY2FsUmlkZ2VSZWdyZXNzKG1hdF94LCBkYXQuZiRwb3dlclsyOiAyNjMwNF0sIDAuMSkKYGBgCgpgYGB7ciwgd2FybmluZz1GQUxTRX0KZnJhbWVEYXRhIDwtIGZ1bmN0aW9uKCl7CiAgICBkYXQgPC0gcmVhZC5jc3YoIldlYXRoZXJGb3JlY2FzdElucHV0MS5jc3YiLCBoZWFkZXIgPSBUKQogICAgdmVjX3RTdGFtcF9yYXcgPC0geW1kX2htKGRhdFsxOiAyNCwgMV0sICIlWSVtJWQgJUg6JU0iLCB0ej0iVVRDIikKICAgIHZlY190U3RhbXAgPC0gdmVjX3RTdGFtcF9yYXdbMTogMjRdCiAgICBkYXQuZiA8LSBkYXRhLmZyYW1lKCJzZXJpZXMiID0gc2VxKDEsIDI0KSwgInllYXIiID0geWVhcih2ZWNfdFN0YW1wKSwgIm1vbnRoIiA9IG1vbnRoKHZlY190U3RhbXApLCAKICAgICAgICAgICAgICAgICAgICAgICAgImRheSIgPSBkYXkodmVjX3RTdGFtcCksICJob3VyIiA9IGhvdXIodmVjX3RTdGFtcCksICJ1MTAiID0gZGF0WywgMl0sICJ2MTAiID0gZGF0WywgM10sIAogICAgICAgICAgICAgICAgICAgICAgICAidTEwMCIgPSBkYXRbLCA0XSwgInYxMDAiID0gZGF0WywgNV0pCiAgICByZXR1cm4oZGF0LmYpCn0KZGF0LmZfcHJlZCA8LSBmcmFtZURhdGEoKQpybShmcmFtZURhdGEpCmBgYAoKYGBge3J9CnByZWRQb3dlck91dHB1dCA8LSBmdW5jdGlvbihtYXRfeCwgdmVjX3RoZXRhX2hhdCl7CiAgICB2ZWNfeV9oYXQgPC0gbWF0X3ggJSolIHZlY190aGV0YV9oYXQKICAgIHJldHVybih2ZWNfeV9oYXQpCn0KbWF0X3hfcHJlZCA8LSBjYmluZChkYXQuZl9wcmVkJHUxMCwgZGF0LmZfcHJlZCR2MTAsIGRhdC5mX3ByZWQkdTEwMCwgZGF0LmZfcHJlZCR2MTAwLCAKICAgIGMoZGF0LmZbMjYzMDQsXSR1MTAsIGRhdC5mX3ByZWQkdTEwWzE6IDIzXSksIGMoZGF0LmZbMjYzMDQsXSR2MTAsIGRhdC5mX3ByZWQkdjEwWzE6IDIzXSksIAogICAgYyhkYXQuZlsyNjMwNCxdJHUxMDAsIGRhdC5mX3ByZWQkdTEwMFsxOiAyM10pLCBjKGRhdC5mWzI2MzA0LF0kdjEwMCwgZGF0LmZfcHJlZCR2MTAwWzE6IDIzXSkpCnZlY195X2hhdCA8LSBwcmVkUG93ZXJPdXRwdXQobWF0X3hfcHJlZCwgdmVjX3RoZXRhKQpgYGAKCmBgYHtyfQp2ZWNfeCA8LSAwLjUgKiBzcXJ0KGRhdC5mX3ByZWQkdTEwXjIgKyAgZGF0LmZfcHJlZCR2MTBeMikgKyAwLjUgKiBzcXJ0KGRhdC5mX3ByZWQkdTEwMF4yICsgZGF0LmZfcHJlZCR2MTAwXjIpCnBsb3QodmVjX3gsIHZlY195X2hhdCwgeGxpbSA9IGMoMCwgMjApLCB5bGltID0gYygwLCAxKSkKYGBgCgo=