Import library

library(tidyverse)
library(gridExtra)
library(readxl)
library(lubridate)
library(hms)
library(forecast)
library(fastDummies)
library(imputeTS)
library(scales)
library(kableExtra)
library(modeltime)
library(Metrics)

Load dataset

df_raw <- read_excel("Data Awal dan Hasil Imputasi rev.xlsx", sheet = 2) %>% 
          mutate(Jam=as_hms(Jam), week = rep(1:51,each=336)[1:16992],
                 time=seq(ymd_hm("2018-1-1 0:00"), ymd_hm("2018-12-20 23:30"), by = 30*60),
                 month=month(time), wday=wday(time),day=day(time), 
                 hour=as_hms(time), yday=yday(time),
                 wtime=rep(seq(ymd_hm("2018-1-1 0:00"), 
                               ymd_hm("2018-1-7 23:30"), 
                               by = 30*60),51)[1:16992]) 
head(df_raw)
tail(df_raw)
dim(df_raw)
[1] 16992    23

Number of missing value for each dataset

Missing value
SUF1_CO 1930
SUF7_CO 628
SUF1_NO2 2426
SUF7_NO2 866
SUF1_O3 474
SUF7_O3 665
SUF1_PM10 7621
SUF7_PM10 2198
SUF1_SO2 1318

Percentage of missing value in SUF 1 dataset

SUF1_CO 11.4%
SUF1_NO2 14.3%
SUF1_O3 2.8%
SUF1_PM10 44.9%
SUF1_SO2 7.8%

Percentage of missing value in SUF 7 dataset

SUF7_CO 3.70%
SUF7_NO2 5.10%
SUF7_O3 3.91%
SUF7_PM10 12.94%
SUF7_SO2 9.58%
var_pollutant <- colnames(df_raw)[6:15]
var_pollutant
 [1] "SUF1_CO"   "SUF7_CO"   "SUF1_NO2"  "SUF7_NO2"  "SUF1_O3"   "SUF7_O3"   "SUF1_PM10" "SUF7_PM10" "SUF1_SO2"  "SUF7_SO2" 

Exploratory Analysis

Time Series Plot

p <- list()
for (i in 1:10){
  p[[i]] <- ggplot(df_raw, aes_(x=~time, y=as.name(var_pollutant[i]))) +
              geom_line() + xlab("") +
              scale_x_datetime(date_breaks = "2 month", date_labels = "%b")
}
grid.arrange(p[[1]], p[[3]], p[[5]],
             p[[7]], p[[9]], ncol=2, top="Time Series Plot on SUF 1")

grid.arrange(p[[2]], p[[4]], p[[6]],
             p[[8]], p[[10]], ncol=2, top="Time Series Plot on SUF 7")

Daily Time Series

p <- list()
for (i in 1:10){
  p[[i]] <- ggplot(df_raw, aes_(x=~hour, y=as.name(var_pollutant[i]), group=~yday)) +
              geom_line() + xlab("") + 
              scale_x_time(labels = label_time(format = '%H:%M'), 
                           breaks=hms(hours = seq(0, 24, 4)))
}
grid.arrange(p[[1]], p[[3]], p[[5]],
             p[[7]], p[[9]], ncol=2, top="Daily Time Series Plot on SUF 1")

grid.arrange(p[[2]], p[[4]], p[[6]],
             p[[8]], p[[10]], ncol=2, top="Daily Time Series Plot on SUF 7")

Weekly Time Series

p <- list()
for (i in 1:10){
  p[[i]] <- ggplot(df_raw, aes_(x=~wtime, y=as.name(var_pollutant[i]), group=~week)) +
              geom_line() + xlab("") + scale_x_datetime(date_breaks = "1 day", date_labels = "%a")
}
grid.arrange(p[[1]], p[[3]], p[[5]],
             p[[7]], p[[10]], ncol=2, top="Weekly Time Series Plot on SUF 1")

grid.arrange(p[[2]], p[[4]], p[[6]],
             p[[8]], p[[10]], ncol=2, top="Weekly Time Series Plot on SUF 7")

Imputation

df <- list()
df[["na"]] <- data.frame(is.na(df_raw))
df[["impute_1"]] <- df_raw %>% 
                    group_by(Hari, J) %>% 
                    mutate_if(is.double,~replace_na(.,median(., na.rm = TRUE))) %>% 
                    ungroup()
`mutate_if()` ignored the following grouping variables:
• Columns `Hari`, `J`
df[["impute_2"]] <- df_raw %>% 
                    group_by(Hari, J) %>% 
                    mutate_if(is.double,~replace_na(.,mean(., na.rm = TRUE))) %>% 
                    ungroup()
`mutate_if()` ignored the following grouping variables:
• Columns `Hari`, `J`
df[["impute_3"]] <- df_raw %>% 
                    group_by(Hari, J) %>% 
                    mutate_if(is.double,~na_interpolation(., option="linear")) %>% 
                    ungroup()
`mutate_if()` ignored the following grouping variables:
• Columns `Hari`, `J`
df[["impute_4"]] <- df_raw %>% 
                    group_by(Hari, J) %>% 
                    mutate_if(is.double,~na_ma(.)) %>% 
                    ungroup()
`mutate_if()` ignored the following grouping variables:
• Columns `Hari`, `J`

CO

p1 <- ggplot(data = df[["impute_1"]] %>% mutate(missing=df[["na"]]$SUF1_CO), 
             aes(x=time,y=SUF1_CO, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Median Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p2 <- ggplot(data = df[["impute_2"]] %>% mutate(missing=df[["na"]]$SUF1_CO), 
             aes(x=time,y=SUF1_CO, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Mean Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p3 <- ggplot(data = df[["impute_3"]] %>% mutate(missing=df[["na"]]$SUF1_CO), 
             aes(x=time,y=SUF1_CO, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Linear Interpolation Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p4 <- ggplot(data = df[["impute_4"]] %>% mutate(missing=df[["na"]]$SUF1_CO), 
             aes(x=time,y=SUF1_CO, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Moving Average Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
grid.arrange(p1,p2,p3,p4,ncol=1)

p1 <- ggplot(data = df[["impute_1"]] %>% mutate(missing=df[["na"]]$SUF7_CO), 
             aes(x=time,y=SUF7_CO, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Median Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p2 <- ggplot(data = df[["impute_2"]] %>% mutate(missing=df[["na"]]$SUF7_CO), 
             aes(x=time,y=SUF7_CO, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Mean Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p3 <- ggplot(data = df[["impute_3"]] %>% mutate(missing=df[["na"]]$SUF7_CO), 
             aes(x=time,y=SUF7_CO, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Linear Interpolation Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p4 <- ggplot(data = df[["impute_4"]] %>% mutate(missing=df[["na"]]$SUF7_CO), 
             aes(x=time,y=SUF7_CO, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Moving Average Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
grid.arrange(p1,p2,p3,p4,ncol=1)

NO2

p1 <- ggplot(data = df[["impute_1"]] %>% mutate(missing=df[["na"]]$SUF1_NO2), 
             aes(x=time,y=SUF1_NO2, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Median Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p2 <- ggplot(data = df[["impute_2"]] %>% mutate(missing=df[["na"]]$SUF1_NO2), 
             aes(x=time,y=SUF1_NO2, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Mean Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p3 <- ggplot(data = df[["impute_3"]] %>% mutate(missing=df[["na"]]$SUF1_NO2), 
             aes(x=time,y=SUF1_NO2, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Linear Interpolation Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p4 <- ggplot(data = df[["impute_4"]] %>% mutate(missing=df[["na"]]$SUF1_NO2), 
             aes(x=time,y=SUF1_NO2, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Moving Average Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
grid.arrange(p1,p2,p3,p4,ncol=1)

p1 <- ggplot(data = df[["impute_1"]] %>% mutate(missing=df[["na"]]$SUF7_NO2), 
             aes(x=time,y=SUF7_NO2, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Median Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p2 <- ggplot(data = df[["impute_2"]] %>% mutate(missing=df[["na"]]$SUF7_NO2), 
             aes(x=time,y=SUF7_NO2, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Mean Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p3 <- ggplot(data = df[["impute_3"]] %>% mutate(missing=df[["na"]]$SUF7_NO2), 
             aes(x=time,y=SUF7_NO2, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Linear Interpolation Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p4 <- ggplot(data = df[["impute_4"]] %>% mutate(missing=df[["na"]]$SUF7_NO2), 
             aes(x=time,y=SUF7_NO2, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Moving Average Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
grid.arrange(p1,p2,p3,p4,ncol=1)

O3

p1 <- ggplot(data = df[["impute_1"]] %>% mutate(missing=df[["na"]]$SUF1_O3), 
             aes(x=time,y=SUF1_O3, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Median Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p2 <- ggplot(data = df[["impute_2"]] %>% mutate(missing=df[["na"]]$SUF1_O3), 
             aes(x=time,y=SUF1_O3, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Mean Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p3 <- ggplot(data = df[["impute_3"]] %>% mutate(missing=df[["na"]]$SUF1_O3), 
             aes(x=time,y=SUF1_O3, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Linear Interpolation Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p4 <- ggplot(data = df[["impute_4"]] %>% mutate(missing=df[["na"]]$SUF1_O3), 
             aes(x=time,y=SUF1_O3, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Moving Average Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
grid.arrange(p1,p2,p3,p4,ncol=1)

p1 <- ggplot(data = df[["impute_1"]] %>% mutate(missing=df[["na"]]$SUF7_O3), 
             aes(x=time,y=SUF7_O3, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Median Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p2 <- ggplot(data = df[["impute_2"]] %>% mutate(missing=df[["na"]]$SUF7_O3), 
             aes(x=time,y=SUF7_O3, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Mean Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p3 <- ggplot(data = df[["impute_3"]] %>% mutate(missing=df[["na"]]$SUF7_O3), 
             aes(x=time,y=SUF7_O3, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Linear Interpolation Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p4 <- ggplot(data = df[["impute_4"]] %>% mutate(missing=df[["na"]]$SUF7_O3), 
             aes(x=time,y=SUF7_O3, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Moving Average Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
grid.arrange(p1,p2,p3,p4,ncol=1)

PM10

p1 <- ggplot(data = df[["impute_1"]] %>% mutate(missing=df[["na"]]$SUF1_PM10), 
             aes(x=time,y=SUF1_PM10, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Median Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p2 <- ggplot(data = df[["impute_2"]] %>% mutate(missing=df[["na"]]$SUF1_PM10), 
             aes(x=time,y=SUF1_PM10, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Mean Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p3 <- ggplot(data = df[["impute_3"]] %>% mutate(missing=df[["na"]]$SUF1_PM10), 
             aes(x=time,y=SUF1_PM10, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Linear Interpolation Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p4 <- ggplot(data = df[["impute_4"]] %>% mutate(missing=df[["na"]]$SUF1_PM10), 
             aes(x=time,y=SUF1_PM10, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Moving Average Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
grid.arrange(p1,p2,p3,p4,ncol=1)

p1 <- ggplot(data = df[["impute_1"]] %>% mutate(missing=df[["na"]]$SUF7_PM10), 
             aes(x=time,y=SUF7_PM10, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Median Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p2 <- ggplot(data = df[["impute_2"]] %>% mutate(missing=df[["na"]]$SUF7_PM10), 
             aes(x=time,y=SUF7_PM10, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Mean Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p3 <- ggplot(data = df[["impute_3"]] %>% mutate(missing=df[["na"]]$SUF7_PM10), 
             aes(x=time,y=SUF7_PM10, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Linear Interpolation Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p4 <- ggplot(data = df[["impute_4"]] %>% mutate(missing=df[["na"]]$SUF7_PM10), 
             aes(x=time,y=SUF7_PM10, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Moving Average Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
grid.arrange(p1,p2,p3,p4,ncol=1)

SO2

p1 <- ggplot(data = df[["impute_1"]] %>% mutate(missing=df[["na"]]$SUF1_SO2), 
             aes(x=time,y=SUF1_SO2, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Median Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p2 <- ggplot(data = df[["impute_2"]] %>% mutate(missing=df[["na"]]$SUF1_SO2), 
             aes(x=time,y=SUF1_SO2, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Mean Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p3 <- ggplot(data = df[["impute_3"]] %>% mutate(missing=df[["na"]]$SUF1_SO2), 
             aes(x=time,y=SUF1_SO2, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Linear Interpolation Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p4 <- ggplot(data = df[["impute_4"]] %>% mutate(missing=df[["na"]]$SUF1_SO2), 
             aes(x=time,y=SUF1_SO2, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Moving Average Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
grid.arrange(p1,p2,p3,p4,ncol=1)

p1 <- ggplot(data = df[["impute_1"]] %>% mutate(missing=df[["na"]]$SUF7_SO2), 
             aes(x=time,y=SUF7_SO2, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Median Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p2 <- ggplot(data = df[["impute_2"]] %>% mutate(missing=df[["na"]]$SUF7_SO2), 
             aes(x=time,y=SUF7_SO2, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Mean Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p3 <- ggplot(data = df[["impute_3"]] %>% mutate(missing=df[["na"]]$SUF7_SO2), 
             aes(x=time,y=SUF7_SO2, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Linear Interpolation Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
p4 <- ggplot(data = df[["impute_4"]] %>% mutate(missing=df[["na"]]$SUF7_SO2), 
             aes(x=time,y=SUF7_SO2, color=missing)) + 
      geom_line(aes(group=1)) + xlab("") + ggtitle("Moving Average Imputation") +
      scale_x_datetime(date_breaks = "1 month", date_labels = "%b")
grid.arrange(p1,p2,p3,p4,ncol=1)

Modelling

Dummy variables

df[["dummy"]] <- dummy_cols(df_raw, select_columns = c("J","Hari")) %>% 
                 mutate(t=seq_along(time)) %>% 
                 select(starts_with("J_"), starts_with("Hari_"),t)
for (k in var_pollutant){
  name <- paste0(k,"_imp_1")
  df[[name]] <- bind_cols(df[["impute_1"]], df[["dummy"]]) %>% 
                select(time,starts_with(k), starts_with("J_"), starts_with("Hari_"),t)
  name <- paste0(k,"_imp_2")
  df[[name]] <- bind_cols(df[["impute_2"]], df[["dummy"]]) %>% 
                select(time,starts_with(k), starts_with("J_"), starts_with("Hari_"),t)
  name <- paste0(k,"_imp_3")
  df[[name]] <- bind_cols(df[["impute_3"]], df[["dummy"]]) %>% 
                select(time,starts_with(k), starts_with("J_"), starts_with("Hari_"),t)
  name <- paste0(k,"_imp_4")
  df[[name]] <- bind_cols(df[["impute_4"]], df[["dummy"]]) %>% 
                select(time,starts_with(k), starts_with("J_"), starts_with("Hari_"),t)
}
ind <- df_raw %>% make_ts_splits(.length_test = 48)
ind
split [16944|48|16992]

Model Fitting and Forecasting

applyForecast <- function(data){
  ind <- data %>% make_ts_splits(.length_test = 48)
  train <- data[ind$idx_train,]
  test  <- data[ind$idx_test,]
  yy <- colnames(data)[2]
  f <- paste0(yy,"~.-1-time-Hari_1")
  m <- lm(f, data = train)
  r.squared <- summary(m)$r.squared
  pred <- m %>% predict(test)
  RMSE <- rmse(test[yy] %>% pull(),pred)
  MAPE <- mape(test[yy] %>% pull(),pred)
  sMAPE <- smape(test[yy] %>% pull(),pred)
  p_train <- ggplot(train %>% mutate(predicted=m$fitted.values)) + 
             geom_line(aes_(x=~time,y=as.name(yy))) +  
             geom_line(aes(x=time,y=predicted), color="red")
  p_test  <- ggplot(test %>% mutate(predicted=pred)) + 
             geom_line(aes_(x=~time,y=as.name(yy))) +  
             geom_line(aes(x=time,y=predicted), color="red")
  results <- list(prediction=pred, 
                  r.squared=r.squared,
                  RMSE=RMSE,
                  MAPE=MAPE,
                  sMAPE=sMAPE,
                  plot_train=p_train,
                  plot_test=p_test)
}
df_pollutant <- names(df)[grepl("imp_",names(df))]
res <- list()
for (name in df_pollutant){res[[name]] <- applyForecast(df[[name]])}

Forecast Comparison

dd <- as_tibble(res[[1]][2:5])
for (name in df_pollutant[-1]){
  dd <- dd %>% add_row(as_tibble(res[[name]][2:5]))
}
results <- dd %>% mutate(model=df_pollutant)

CO

results[1:8,]

NO2

results[9:16,]

O3

results[17:24,]

PM10

results[25:32,]

SO2

results[33:40,]
LS0tCnRpdGxlOiAiVGltZSBTZXJpZXMgSW1wdXRhdGlvbiIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IAogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDoKICAgICAgdG9jX2NvbGxhcHNlZDogeWVzCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKIyMgSW1wb3J0IGxpYnJhcnkKYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShncmlkRXh0cmEpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShobXMpCmxpYnJhcnkoZm9yZWNhc3QpCmxpYnJhcnkoZmFzdER1bW1pZXMpCmxpYnJhcnkoaW1wdXRlVFMpCmxpYnJhcnkoc2NhbGVzKQpsaWJyYXJ5KGthYmxlRXh0cmEpCmxpYnJhcnkobW9kZWx0aW1lKQpsaWJyYXJ5KE1ldHJpY3MpCmBgYAoKIyMgTG9hZCBkYXRhc2V0CgpgYGB7cn0KZGZfcmF3IDwtIHJlYWRfZXhjZWwoIkRhdGEgQXdhbCBkYW4gSGFzaWwgSW1wdXRhc2kgcmV2Lnhsc3giLCBzaGVldCA9IDIpICU+JSAKICAgICAgICAgIG11dGF0ZShKYW09YXNfaG1zKEphbSksIHdlZWsgPSByZXAoMTo1MSxlYWNoPTMzNilbMToxNjk5Ml0sCiAgICAgICAgICAgICAgICAgdGltZT1zZXEoeW1kX2htKCIyMDE4LTEtMSAwOjAwIiksIHltZF9obSgiMjAxOC0xMi0yMCAyMzozMCIpLCBieSA9IDMwKjYwKSwKICAgICAgICAgICAgICAgICBtb250aD1tb250aCh0aW1lKSwgd2RheT13ZGF5KHRpbWUpLGRheT1kYXkodGltZSksIAogICAgICAgICAgICAgICAgIGhvdXI9YXNfaG1zKHRpbWUpLCB5ZGF5PXlkYXkodGltZSksCiAgICAgICAgICAgICAgICAgd3RpbWU9cmVwKHNlcSh5bWRfaG0oIjIwMTgtMS0xIDA6MDAiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWRfaG0oIjIwMTgtMS03IDIzOjMwIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSAzMCo2MCksNTEpWzE6MTY5OTJdKSAKaGVhZChkZl9yYXcpCmBgYAoKYGBge3J9CnRhaWwoZGZfcmF3KQpgYGAKCgpgYGB7cn0KZGltKGRmX3JhdykKYGBgCgpOdW1iZXIgb2YgbWlzc2luZyB2YWx1ZSBmb3IgZWFjaCBkYXRhc2V0CmBgYHtyIGVjaG89RkFMU0V9CmNvbFN1bXMoaXMubmEoZGZfcmF3KSlbNjoxNF0gJT4lCiAga2JsKGNhcHRpb24gPSAiTWlzc2luZyB2YWx1ZSIsIGNvbC5uYW1lcyA9ICIiKSAlPiUKICAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIiwgInJlc3BvbnNpdmUiKSwgCiAgICAgICAgICAgICAgICAgZnVsbF93aWR0aCA9IEYsIHBvc2l0aW9uID0gImxlZnQiKQpgYGAKCgpQZXJjZW50YWdlIG9mIG1pc3NpbmcgdmFsdWUgaW4gU1VGIDEgZGF0YXNldApgYGB7ciBlY2hvPUZBTFNFfQpsYWJlbF9wZXJjZW50KCkgKGNvbFN1bXMoaXMubmEoZGZfcmF3KSlbYyg2LDgsMTAsMTIsMTQpXS9kaW0oZGZfcmF3KVsxXSkgJT4lCiAga2JsKGNvbC5uYW1lcyA9ICIiKSAlPiUKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiLCAicmVzcG9uc2l2ZSIpLCAKICAgICAgICAgICAgICAgIGZ1bGxfd2lkdGggPSBGLCBwb3NpdGlvbiA9ICJsZWZ0IikKYGBgCgpQZXJjZW50YWdlIG9mIG1pc3NpbmcgdmFsdWUgaW4gU1VGIDcgZGF0YXNldApgYGB7ciBlY2hvPUZBTFNFfQpsYWJlbF9wZXJjZW50KCkgKGNvbFN1bXMoaXMubmEoZGZfcmF3KSlbYyg3LDksMTEsMTMsMTUpXS9kaW0oZGZfcmF3KVsxXSkgJT4lCiAga2JsKGNvbC5uYW1lcyA9ICIiKSAlPiUKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiLCAicmVzcG9uc2l2ZSIpLCAKICAgICAgICAgICAgICAgIGZ1bGxfd2lkdGggPSBGLCBwb3NpdGlvbiA9ICJsZWZ0IikKYGBgCgoKYGBge3J9CnZhcl9wb2xsdXRhbnQgPC0gY29sbmFtZXMoZGZfcmF3KVs2OjE1XQp2YXJfcG9sbHV0YW50CmBgYAoKIyMgRXhwbG9yYXRvcnkgQW5hbHlzaXMKCiMjIyBUaW1lIFNlcmllcyBQbG90CmBgYHtyfQpwIDwtIGxpc3QoKQpmb3IgKGkgaW4gMToxMCl7CiAgcFtbaV1dIDwtIGdncGxvdChkZl9yYXcsIGFlc18oeD1+dGltZSwgeT1hcy5uYW1lKHZhcl9wb2xsdXRhbnRbaV0pKSkgKwogICAgICAgICAgICAgIGdlb21fbGluZSgpICsgeGxhYigiIikgKwogICAgICAgICAgICAgIHNjYWxlX3hfZGF0ZXRpbWUoZGF0ZV9icmVha3MgPSAiMiBtb250aCIsIGRhdGVfbGFiZWxzID0gIiViIikKfQpgYGAKCgpgYGB7ciB3YXJuaW5nPUZBTFNFfQpncmlkLmFycmFuZ2UocFtbMV1dLCBwW1szXV0sIHBbWzVdXSwKICAgICAgICAgICAgIHBbWzddXSwgcFtbOV1dLCBuY29sPTIsIHRvcD0iVGltZSBTZXJpZXMgUGxvdCBvbiBTVUYgMSIpCmBgYAoKYGBge3Igd2FybmluZz1GQUxTRX0KZ3JpZC5hcnJhbmdlKHBbWzJdXSwgcFtbNF1dLCBwW1s2XV0sCiAgICAgICAgICAgICBwW1s4XV0sIHBbWzEwXV0sIG5jb2w9MiwgdG9wPSJUaW1lIFNlcmllcyBQbG90IG9uIFNVRiA3IikKYGBgCgojIyMgRGFpbHkgVGltZSBTZXJpZXMKYGBge3J9CnAgPC0gbGlzdCgpCmZvciAoaSBpbiAxOjEwKXsKICBwW1tpXV0gPC0gZ2dwbG90KGRmX3JhdywgYWVzXyh4PX5ob3VyLCB5PWFzLm5hbWUodmFyX3BvbGx1dGFudFtpXSksIGdyb3VwPX55ZGF5KSkgKwogICAgICAgICAgICAgIGdlb21fbGluZSgpICsgeGxhYigiIikgKyAKICAgICAgICAgICAgICBzY2FsZV94X3RpbWUobGFiZWxzID0gbGFiZWxfdGltZShmb3JtYXQgPSAnJUg6JU0nKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcz1obXMoaG91cnMgPSBzZXEoMCwgMjQsIDQpKSkKfQpgYGAKCgpgYGB7ciB3YXJuaW5nPUZBTFNFfQpncmlkLmFycmFuZ2UocFtbMV1dLCBwW1szXV0sIHBbWzVdXSwKICAgICAgICAgICAgIHBbWzddXSwgcFtbOV1dLCBuY29sPTIsIHRvcD0iRGFpbHkgVGltZSBTZXJpZXMgUGxvdCBvbiBTVUYgMSIpCmBgYAoKYGBge3Igd2FybmluZz1GQUxTRX0KZ3JpZC5hcnJhbmdlKHBbWzJdXSwgcFtbNF1dLCBwW1s2XV0sCiAgICAgICAgICAgICBwW1s4XV0sIHBbWzEwXV0sIG5jb2w9MiwgdG9wPSJEYWlseSBUaW1lIFNlcmllcyBQbG90IG9uIFNVRiA3IikKYGBgCgoKIyMjIFdlZWtseSBUaW1lIFNlcmllcwpgYGB7cn0KcCA8LSBsaXN0KCkKZm9yIChpIGluIDE6MTApewogIHBbW2ldXSA8LSBnZ3Bsb3QoZGZfcmF3LCBhZXNfKHg9fnd0aW1lLCB5PWFzLm5hbWUodmFyX3BvbGx1dGFudFtpXSksIGdyb3VwPX53ZWVrKSkgKwogICAgICAgICAgICAgIGdlb21fbGluZSgpICsgeGxhYigiIikgKyBzY2FsZV94X2RhdGV0aW1lKGRhdGVfYnJlYWtzID0gIjEgZGF5IiwgZGF0ZV9sYWJlbHMgPSAiJWEiKQp9CmBgYAoKCmBgYHtyIHdhcm5pbmc9RkFMU0V9CmdyaWQuYXJyYW5nZShwW1sxXV0sIHBbWzNdXSwgcFtbNV1dLAogICAgICAgICAgICAgcFtbN11dLCBwW1sxMF1dLCBuY29sPTIsIHRvcD0iV2Vla2x5IFRpbWUgU2VyaWVzIFBsb3Qgb24gU1VGIDEiKQpgYGAKCgoKYGBge3Igd2FybmluZz1GQUxTRX0KZ3JpZC5hcnJhbmdlKHBbWzJdXSwgcFtbNF1dLCBwW1s2XV0sCiAgICAgICAgICAgICBwW1s4XV0sIHBbWzEwXV0sIG5jb2w9MiwgdG9wPSJXZWVrbHkgVGltZSBTZXJpZXMgUGxvdCBvbiBTVUYgNyIpCmBgYAoKCiMjIEltcHV0YXRpb24KCgpgYGB7cn0KZGYgPC0gbGlzdCgpCmRmW1sibmEiXV0gPC0gZGF0YS5mcmFtZShpcy5uYShkZl9yYXcpKQpkZltbImltcHV0ZV8xIl1dIDwtIGRmX3JhdyAlPiUgCiAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoSGFyaSwgSikgJT4lIAogICAgICAgICAgICAgICAgICAgIG11dGF0ZV9pZihpcy5kb3VibGUsfnJlcGxhY2VfbmEoLixtZWRpYW4oLiwgbmEucm0gPSBUUlVFKSkpICU+JSAKICAgICAgICAgICAgICAgICAgICB1bmdyb3VwKCkKZGZbWyJpbXB1dGVfMiJdXSA8LSBkZl9yYXcgJT4lIAogICAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KEhhcmksIEopICU+JSAKICAgICAgICAgICAgICAgICAgICBtdXRhdGVfaWYoaXMuZG91YmxlLH5yZXBsYWNlX25hKC4sbWVhbiguLCBuYS5ybSA9IFRSVUUpKSkgJT4lIAogICAgICAgICAgICAgICAgICAgIHVuZ3JvdXAoKQpkZltbImltcHV0ZV8zIl1dIDwtIGRmX3JhdyAlPiUgCiAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoSGFyaSwgSikgJT4lIAogICAgICAgICAgICAgICAgICAgIG11dGF0ZV9pZihpcy5kb3VibGUsfm5hX2ludGVycG9sYXRpb24oLiwgb3B0aW9uPSJsaW5lYXIiKSkgJT4lIAogICAgICAgICAgICAgICAgICAgIHVuZ3JvdXAoKQpkZltbImltcHV0ZV80Il1dIDwtIGRmX3JhdyAlPiUgCiAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoSGFyaSwgSikgJT4lIAogICAgICAgICAgICAgICAgICAgIG11dGF0ZV9pZihpcy5kb3VibGUsfm5hX21hKC4pKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgdW5ncm91cCgpCmBgYAoKIyMjIENPCgpgYGB7ciwgZmlnLndpZHRoPTV9CnAxIDwtIGdncGxvdChkYXRhID0gZGZbWyJpbXB1dGVfMSJdXSAlPiUgbXV0YXRlKG1pc3Npbmc9ZGZbWyJuYSJdXSRTVUYxX0NPKSwgCiAgICAgICAgICAgICBhZXMoeD10aW1lLHk9U1VGMV9DTywgY29sb3I9bWlzc2luZykpICsgCiAgICAgIGdlb21fbGluZShhZXMoZ3JvdXA9MSkpICsgeGxhYigiIikgKyBnZ3RpdGxlKCJNZWRpYW4gSW1wdXRhdGlvbiIpICsKICAgICAgc2NhbGVfeF9kYXRldGltZShkYXRlX2JyZWFrcyA9ICIxIG1vbnRoIiwgZGF0ZV9sYWJlbHMgPSAiJWIiKQpwMiA8LSBnZ3Bsb3QoZGF0YSA9IGRmW1siaW1wdXRlXzIiXV0gJT4lIG11dGF0ZShtaXNzaW5nPWRmW1sibmEiXV0kU1VGMV9DTyksIAogICAgICAgICAgICAgYWVzKHg9dGltZSx5PVNVRjFfQ08sIGNvbG9yPW1pc3NpbmcpKSArIAogICAgICBnZW9tX2xpbmUoYWVzKGdyb3VwPTEpKSArIHhsYWIoIiIpICsgZ2d0aXRsZSgiTWVhbiBJbXB1dGF0aW9uIikgKwogICAgICBzY2FsZV94X2RhdGV0aW1lKGRhdGVfYnJlYWtzID0gIjEgbW9udGgiLCBkYXRlX2xhYmVscyA9ICIlYiIpCnAzIDwtIGdncGxvdChkYXRhID0gZGZbWyJpbXB1dGVfMyJdXSAlPiUgbXV0YXRlKG1pc3Npbmc9ZGZbWyJuYSJdXSRTVUYxX0NPKSwgCiAgICAgICAgICAgICBhZXMoeD10aW1lLHk9U1VGMV9DTywgY29sb3I9bWlzc2luZykpICsgCiAgICAgIGdlb21fbGluZShhZXMoZ3JvdXA9MSkpICsgeGxhYigiIikgKyBnZ3RpdGxlKCJMaW5lYXIgSW50ZXJwb2xhdGlvbiBJbXB1dGF0aW9uIikgKwogICAgICBzY2FsZV94X2RhdGV0aW1lKGRhdGVfYnJlYWtzID0gIjEgbW9udGgiLCBkYXRlX2xhYmVscyA9ICIlYiIpCnA0IDwtIGdncGxvdChkYXRhID0gZGZbWyJpbXB1dGVfNCJdXSAlPiUgbXV0YXRlKG1pc3Npbmc9ZGZbWyJuYSJdXSRTVUYxX0NPKSwgCiAgICAgICAgICAgICBhZXMoeD10aW1lLHk9U1VGMV9DTywgY29sb3I9bWlzc2luZykpICsgCiAgICAgIGdlb21fbGluZShhZXMoZ3JvdXA9MSkpICsgeGxhYigiIikgKyBnZ3RpdGxlKCJNb3ZpbmcgQXZlcmFnZSBJbXB1dGF0aW9uIikgKwogICAgICBzY2FsZV94X2RhdGV0aW1lKGRhdGVfYnJlYWtzID0gIjEgbW9udGgiLCBkYXRlX2xhYmVscyA9ICIlYiIpCmdyaWQuYXJyYW5nZShwMSxwMixwMyxwNCxuY29sPTEpCmBgYAoKCmBgYHtyLCBmaWcud2lkdGg9NX0KcDEgPC0gZ2dwbG90KGRhdGEgPSBkZltbImltcHV0ZV8xIl1dICU+JSBtdXRhdGUobWlzc2luZz1kZltbIm5hIl1dJFNVRjdfQ08pLCAKICAgICAgICAgICAgIGFlcyh4PXRpbWUseT1TVUY3X0NPLCBjb2xvcj1taXNzaW5nKSkgKyAKICAgICAgZ2VvbV9saW5lKGFlcyhncm91cD0xKSkgKyB4bGFiKCIiKSArIGdndGl0bGUoIk1lZGlhbiBJbXB1dGF0aW9uIikgKwogICAgICBzY2FsZV94X2RhdGV0aW1lKGRhdGVfYnJlYWtzID0gIjEgbW9udGgiLCBkYXRlX2xhYmVscyA9ICIlYiIpCnAyIDwtIGdncGxvdChkYXRhID0gZGZbWyJpbXB1dGVfMiJdXSAlPiUgbXV0YXRlKG1pc3Npbmc9ZGZbWyJuYSJdXSRTVUY3X0NPKSwgCiAgICAgICAgICAgICBhZXMoeD10aW1lLHk9U1VGN19DTywgY29sb3I9bWlzc2luZykpICsgCiAgICAgIGdlb21fbGluZShhZXMoZ3JvdXA9MSkpICsgeGxhYigiIikgKyBnZ3RpdGxlKCJNZWFuIEltcHV0YXRpb24iKSArCiAgICAgIHNjYWxlX3hfZGF0ZXRpbWUoZGF0ZV9icmVha3MgPSAiMSBtb250aCIsIGRhdGVfbGFiZWxzID0gIiViIikKcDMgPC0gZ2dwbG90KGRhdGEgPSBkZltbImltcHV0ZV8zIl1dICU+JSBtdXRhdGUobWlzc2luZz1kZltbIm5hIl1dJFNVRjdfQ08pLCAKICAgICAgICAgICAgIGFlcyh4PXRpbWUseT1TVUY3X0NPLCBjb2xvcj1taXNzaW5nKSkgKyAKICAgICAgZ2VvbV9saW5lKGFlcyhncm91cD0xKSkgKyB4bGFiKCIiKSArIGdndGl0bGUoIkxpbmVhciBJbnRlcnBvbGF0aW9uIEltcHV0YXRpb24iKSArCiAgICAgIHNjYWxlX3hfZGF0ZXRpbWUoZGF0ZV9icmVha3MgPSAiMSBtb250aCIsIGRhdGVfbGFiZWxzID0gIiViIikKcDQgPC0gZ2dwbG90KGRhdGEgPSBkZltbImltcHV0ZV80Il1dICU+JSBtdXRhdGUobWlzc2luZz1kZltbIm5hIl1dJFNVRjdfQ08pLCAKICAgICAgICAgICAgIGFlcyh4PXRpbWUseT1TVUY3X0NPLCBjb2xvcj1taXNzaW5nKSkgKyAKICAgICAgZ2VvbV9saW5lKGFlcyhncm91cD0xKSkgKyB4bGFiKCIiKSArIGdndGl0bGUoIk1vdmluZyBBdmVyYWdlIEltcHV0YXRpb24iKSArCiAgICAgIHNjYWxlX3hfZGF0ZXRpbWUoZGF0ZV9icmVha3MgPSAiMSBtb250aCIsIGRhdGVfbGFiZWxzID0gIiViIikKZ3JpZC5hcnJhbmdlKHAxLHAyLHAzLHA0LG5jb2w9MSkKYGBgCgoKCiMjIyBOTzIKCmBgYHtyLCBmaWcud2lkdGg9NX0KcDEgPC0gZ2dwbG90KGRhdGEgPSBkZltbImltcHV0ZV8xIl1dICU+JSBtdXRhdGUobWlzc2luZz1kZltbIm5hIl1dJFNVRjFfTk8yKSwgCiAgICAgICAgICAgICBhZXMoeD10aW1lLHk9U1VGMV9OTzIsIGNvbG9yPW1pc3NpbmcpKSArIAogICAgICBnZW9tX2xpbmUoYWVzKGdyb3VwPTEpKSArIHhsYWIoIiIpICsgZ2d0aXRsZSgiTWVkaWFuIEltcHV0YXRpb24iKSArCiAgICAgIHNjYWxlX3hfZGF0ZXRpbWUoZGF0ZV9icmVha3MgPSAiMSBtb250aCIsIGRhdGVfbGFiZWxzID0gIiViIikKcDIgPC0gZ2dwbG90KGRhdGEgPSBkZltbImltcHV0ZV8yIl1dICU+JSBtdXRhdGUobWlzc2luZz1kZltbIm5hIl1dJFNVRjFfTk8yKSwgCiAgICAgICAgICAgICBhZXMoeD10aW1lLHk9U1VGMV9OTzIsIGNvbG9yPW1pc3NpbmcpKSArIAogICAgICBnZW9tX2xpbmUoYWVzKGdyb3VwPTEpKSArIHhsYWIoIiIpICsgZ2d0aXRsZSgiTWVhbiBJbXB1dGF0aW9uIikgKwogICAgICBzY2FsZV94X2RhdGV0aW1lKGRhdGVfYnJlYWtzID0gIjEgbW9udGgiLCBkYXRlX2xhYmVscyA9ICIlYiIpCnAzIDwtIGdncGxvdChkYXRhID0gZGZbWyJpbXB1dGVfMyJdXSAlPiUgbXV0YXRlKG1pc3Npbmc9ZGZbWyJuYSJdXSRTVUYxX05PMiksIAogICAgICAgICAgICAgYWVzKHg9dGltZSx5PVNVRjFfTk8yLCBjb2xvcj1taXNzaW5nKSkgKyAKICAgICAgZ2VvbV9saW5lKGFlcyhncm91cD0xKSkgKyB4bGFiKCIiKSArIGdndGl0bGUoIkxpbmVhciBJbnRlcnBvbGF0aW9uIEltcHV0YXRpb24iKSArCiAgICAgIHNjYWxlX3hfZGF0ZXRpbWUoZGF0ZV9icmVha3MgPSAiMSBtb250aCIsIGRhdGVfbGFiZWxzID0gIiViIikKcDQgPC0gZ2dwbG90KGRhdGEgPSBkZltbImltcHV0ZV80Il1dICU+JSBtdXRhdGUobWlzc2luZz1kZltbIm5hIl1dJFNVRjFfTk8yKSwgCiAgICAgICAgICAgICBhZXMoeD10aW1lLHk9U1VGMV9OTzIsIGNvbG9yPW1pc3NpbmcpKSArIAogICAgICBnZW9tX2xpbmUoYWVzKGdyb3VwPTEpKSArIHhsYWIoIiIpICsgZ2d0aXRsZSgiTW92aW5nIEF2ZXJhZ2UgSW1wdXRhdGlvbiIpICsKICAgICAgc2NhbGVfeF9kYXRldGltZShkYXRlX2JyZWFrcyA9ICIxIG1vbnRoIiwgZGF0ZV9sYWJlbHMgPSAiJWIiKQpncmlkLmFycmFuZ2UocDEscDIscDMscDQsbmNvbD0xKQpgYGAKCgpgYGB7ciwgZmlnLndpZHRoPTV9CnAxIDwtIGdncGxvdChkYXRhID0gZGZbWyJpbXB1dGVfMSJdXSAlPiUgbXV0YXRlKG1pc3Npbmc9ZGZbWyJuYSJdXSRTVUY3X05PMiksIAogICAgICAgICAgICAgYWVzKHg9dGltZSx5PVNVRjdfTk8yLCBjb2xvcj1taXNzaW5nKSkgKyAKICAgICAgZ2VvbV9saW5lKGFlcyhncm91cD0xKSkgKyB4bGFiKCIiKSArIGdndGl0bGUoIk1lZGlhbiBJbXB1dGF0aW9uIikgKwogICAgICBzY2FsZV94X2RhdGV0aW1lKGRhdGVfYnJlYWtzID0gIjEgbW9udGgiLCBkYXRlX2xhYmVscyA9ICIlYiIpCnAyIDwtIGdncGxvdChkYXRhID0gZGZbWyJpbXB1dGVfMiJdXSAlPiUgbXV0YXRlKG1pc3Npbmc9ZGZbWyJuYSJdXSRTVUY3X05PMiksIAogICAgICAgICAgICAgYWVzKHg9dGltZSx5PVNVRjdfTk8yLCBjb2xvcj1taXNzaW5nKSkgKyAKICAgICAgZ2VvbV9saW5lKGFlcyhncm91cD0xKSkgKyB4bGFiKCIiKSArIGdndGl0bGUoIk1lYW4gSW1wdXRhdGlvbiIpICsKICAgICAgc2NhbGVfeF9kYXRldGltZShkYXRlX2JyZWFrcyA9ICIxIG1vbnRoIiwgZGF0ZV9sYWJlbHMgPSAiJWIiKQpwMyA8LSBnZ3Bsb3QoZGF0YSA9IGRmW1siaW1wdXRlXzMiXV0gJT4lIG11dGF0ZShtaXNzaW5nPWRmW1sibmEiXV0kU1VGN19OTzIpLCAKICAgICAgICAgICAgIGFlcyh4PXRpbWUseT1TVUY3X05PMiwgY29sb3I9bWlzc2luZykpICsgCiAgICAgIGdlb21fbGluZShhZXMoZ3JvdXA9MSkpICsgeGxhYigiIikgKyBnZ3RpdGxlKCJMaW5lYXIgSW50ZXJwb2xhdGlvbiBJbXB1dGF0aW9uIikgKwogICAgICBzY2FsZV94X2RhdGV0aW1lKGRhdGVfYnJlYWtzID0gIjEgbW9udGgiLCBkYXRlX2xhYmVscyA9ICIlYiIpCnA0IDwtIGdncGxvdChkYXRhID0gZGZbWyJpbXB1dGVfNCJdXSAlPiUgbXV0YXRlKG1pc3Npbmc9ZGZbWyJuYSJdXSRTVUY3X05PMiksIAogICAgICAgICAgICAgYWVzKHg9dGltZSx5PVNVRjdfTk8yLCBjb2xvcj1taXNzaW5nKSkgKyAKICAgICAgZ2VvbV9saW5lKGFlcyhncm91cD0xKSkgKyB4bGFiKCIiKSArIGdndGl0bGUoIk1vdmluZyBBdmVyYWdlIEltcHV0YXRpb24iKSArCiAgICAgIHNjYWxlX3hfZGF0ZXRpbWUoZGF0ZV9icmVha3MgPSAiMSBtb250aCIsIGRhdGVfbGFiZWxzID0gIiViIikKZ3JpZC5hcnJhbmdlKHAxLHAyLHAzLHA0LG5jb2w9MSkKYGBgCgojIyMgTzMKCmBgYHtyLCBmaWcud2lkdGg9NX0KcDEgPC0gZ2dwbG90KGRhdGEgPSBkZltbImltcHV0ZV8xIl1dICU+JSBtdXRhdGUobWlzc2luZz1kZltbIm5hIl1dJFNVRjFfTzMpLCAKICAgICAgICAgICAgIGFlcyh4PXRpbWUseT1TVUYxX08zLCBjb2xvcj1taXNzaW5nKSkgKyAKICAgICAgZ2VvbV9saW5lKGFlcyhncm91cD0xKSkgKyB4bGFiKCIiKSArIGdndGl0bGUoIk1lZGlhbiBJbXB1dGF0aW9uIikgKwogICAgICBzY2FsZV94X2RhdGV0aW1lKGRhdGVfYnJlYWtzID0gIjEgbW9udGgiLCBkYXRlX2xhYmVscyA9ICIlYiIpCnAyIDwtIGdncGxvdChkYXRhID0gZGZbWyJpbXB1dGVfMiJdXSAlPiUgbXV0YXRlKG1pc3Npbmc9ZGZbWyJuYSJdXSRTVUYxX08zKSwgCiAgICAgICAgICAgICBhZXMoeD10aW1lLHk9U1VGMV9PMywgY29sb3I9bWlzc2luZykpICsgCiAgICAgIGdlb21fbGluZShhZXMoZ3JvdXA9MSkpICsgeGxhYigiIikgKyBnZ3RpdGxlKCJNZWFuIEltcHV0YXRpb24iKSArCiAgICAgIHNjYWxlX3hfZGF0ZXRpbWUoZGF0ZV9icmVha3MgPSAiMSBtb250aCIsIGRhdGVfbGFiZWxzID0gIiViIikKcDMgPC0gZ2dwbG90KGRhdGEgPSBkZltbImltcHV0ZV8zIl1dICU+JSBtdXRhdGUobWlzc2luZz1kZltbIm5hIl1dJFNVRjFfTzMpLCAKICAgICAgICAgICAgIGFlcyh4PXRpbWUseT1TVUYxX08zLCBjb2xvcj1taXNzaW5nKSkgKyAKICAgICAgZ2VvbV9saW5lKGFlcyhncm91cD0xKSkgKyB4bGFiKCIiKSArIGdndGl0bGUoIkxpbmVhciBJbnRlcnBvbGF0aW9uIEltcHV0YXRpb24iKSArCiAgICAgIHNjYWxlX3hfZGF0ZXRpbWUoZGF0ZV9icmVha3MgPSAiMSBtb250aCIsIGRhdGVfbGFiZWxzID0gIiViIikKcDQgPC0gZ2dwbG90KGRhdGEgPSBkZltbImltcHV0ZV80Il1dICU+JSBtdXRhdGUobWlzc2luZz1kZltbIm5hIl1dJFNVRjFfTzMpLCAKICAgICAgICAgICAgIGFlcyh4PXRpbWUseT1TVUYxX08zLCBjb2xvcj1taXNzaW5nKSkgKyAKICAgICAgZ2VvbV9saW5lKGFlcyhncm91cD0xKSkgKyB4bGFiKCIiKSArIGdndGl0bGUoIk1vdmluZyBBdmVyYWdlIEltcHV0YXRpb24iKSArCiAgICAgIHNjYWxlX3hfZGF0ZXRpbWUoZGF0ZV9icmVha3MgPSAiMSBtb250aCIsIGRhdGVfbGFiZWxzID0gIiViIikKZ3JpZC5hcnJhbmdlKHAxLHAyLHAzLHA0LG5jb2w9MSkKYGBgCgoKYGBge3IsIGZpZy53aWR0aD01fQpwMSA8LSBnZ3Bsb3QoZGF0YSA9IGRmW1siaW1wdXRlXzEiXV0gJT4lIG11dGF0ZShtaXNzaW5nPWRmW1sibmEiXV0kU1VGN19PMyksIAogICAgICAgICAgICAgYWVzKHg9dGltZSx5PVNVRjdfTzMsIGNvbG9yPW1pc3NpbmcpKSArIAogICAgICBnZW9tX2xpbmUoYWVzKGdyb3VwPTEpKSArIHhsYWIoIiIpICsgZ2d0aXRsZSgiTWVkaWFuIEltcHV0YXRpb24iKSArCiAgICAgIHNjYWxlX3hfZGF0ZXRpbWUoZGF0ZV9icmVha3MgPSAiMSBtb250aCIsIGRhdGVfbGFiZWxzID0gIiViIikKcDIgPC0gZ2dwbG90KGRhdGEgPSBkZltbImltcHV0ZV8yIl1dICU+JSBtdXRhdGUobWlzc2luZz1kZltbIm5hIl1dJFNVRjdfTzMpLCAKICAgICAgICAgICAgIGFlcyh4PXRpbWUseT1TVUY3X08zLCBjb2xvcj1taXNzaW5nKSkgKyAKICAgICAgZ2VvbV9saW5lKGFlcyhncm91cD0xKSkgKyB4bGFiKCIiKSArIGdndGl0bGUoIk1lYW4gSW1wdXRhdGlvbiIpICsKICAgICAgc2NhbGVfeF9kYXRldGltZShkYXRlX2JyZWFrcyA9ICIxIG1vbnRoIiwgZGF0ZV9sYWJlbHMgPSAiJWIiKQpwMyA8LSBnZ3Bsb3QoZGF0YSA9IGRmW1siaW1wdXRlXzMiXV0gJT4lIG11dGF0ZShtaXNzaW5nPWRmW1sibmEiXV0kU1VGN19PMyksIAogICAgICAgICAgICAgYWVzKHg9dGltZSx5PVNVRjdfTzMsIGNvbG9yPW1pc3NpbmcpKSArIAogICAgICBnZW9tX2xpbmUoYWVzKGdyb3VwPTEpKSArIHhsYWIoIiIpICsgZ2d0aXRsZSgiTGluZWFyIEludGVycG9sYXRpb24gSW1wdXRhdGlvbiIpICsKICAgICAgc2NhbGVfeF9kYXRldGltZShkYXRlX2JyZWFrcyA9ICIxIG1vbnRoIiwgZGF0ZV9sYWJlbHMgPSAiJWIiKQpwNCA8LSBnZ3Bsb3QoZGF0YSA9IGRmW1siaW1wdXRlXzQiXV0gJT4lIG11dGF0ZShtaXNzaW5nPWRmW1sibmEiXV0kU1VGN19PMyksIAogICAgICAgICAgICAgYWVzKHg9dGltZSx5PVNVRjdfTzMsIGNvbG9yPW1pc3NpbmcpKSArIAogICAgICBnZW9tX2xpbmUoYWVzKGdyb3VwPTEpKSArIHhsYWIoIiIpICsgZ2d0aXRsZSgiTW92aW5nIEF2ZXJhZ2UgSW1wdXRhdGlvbiIpICsKICAgICAgc2NhbGVfeF9kYXRldGltZShkYXRlX2JyZWFrcyA9ICIxIG1vbnRoIiwgZGF0ZV9sYWJlbHMgPSAiJWIiKQpncmlkLmFycmFuZ2UocDEscDIscDMscDQsbmNvbD0xKQpgYGAKCiMjIyBQTTEwCmBgYHtyLCBmaWcud2lkdGg9NX0KcDEgPC0gZ2dwbG90KGRhdGEgPSBkZltbImltcHV0ZV8xIl1dICU+JSBtdXRhdGUobWlzc2luZz1kZltbIm5hIl1dJFNVRjFfUE0xMCksIAogICAgICAgICAgICAgYWVzKHg9dGltZSx5PVNVRjFfUE0xMCwgY29sb3I9bWlzc2luZykpICsgCiAgICAgIGdlb21fbGluZShhZXMoZ3JvdXA9MSkpICsgeGxhYigiIikgKyBnZ3RpdGxlKCJNZWRpYW4gSW1wdXRhdGlvbiIpICsKICAgICAgc2NhbGVfeF9kYXRldGltZShkYXRlX2JyZWFrcyA9ICIxIG1vbnRoIiwgZGF0ZV9sYWJlbHMgPSAiJWIiKQpwMiA8LSBnZ3Bsb3QoZGF0YSA9IGRmW1siaW1wdXRlXzIiXV0gJT4lIG11dGF0ZShtaXNzaW5nPWRmW1sibmEiXV0kU1VGMV9QTTEwKSwgCiAgICAgICAgICAgICBhZXMoeD10aW1lLHk9U1VGMV9QTTEwLCBjb2xvcj1taXNzaW5nKSkgKyAKICAgICAgZ2VvbV9saW5lKGFlcyhncm91cD0xKSkgKyB4bGFiKCIiKSArIGdndGl0bGUoIk1lYW4gSW1wdXRhdGlvbiIpICsKICAgICAgc2NhbGVfeF9kYXRldGltZShkYXRlX2JyZWFrcyA9ICIxIG1vbnRoIiwgZGF0ZV9sYWJlbHMgPSAiJWIiKQpwMyA8LSBnZ3Bsb3QoZGF0YSA9IGRmW1siaW1wdXRlXzMiXV0gJT4lIG11dGF0ZShtaXNzaW5nPWRmW1sibmEiXV0kU1VGMV9QTTEwKSwgCiAgICAgICAgICAgICBhZXMoeD10aW1lLHk9U1VGMV9QTTEwLCBjb2xvcj1taXNzaW5nKSkgKyAKICAgICAgZ2VvbV9saW5lKGFlcyhncm91cD0xKSkgKyB4bGFiKCIiKSArIGdndGl0bGUoIkxpbmVhciBJbnRlcnBvbGF0aW9uIEltcHV0YXRpb24iKSArCiAgICAgIHNjYWxlX3hfZGF0ZXRpbWUoZGF0ZV9icmVha3MgPSAiMSBtb250aCIsIGRhdGVfbGFiZWxzID0gIiViIikKcDQgPC0gZ2dwbG90KGRhdGEgPSBkZltbImltcHV0ZV80Il1dICU+JSBtdXRhdGUobWlzc2luZz1kZltbIm5hIl1dJFNVRjFfUE0xMCksIAogICAgICAgICAgICAgYWVzKHg9dGltZSx5PVNVRjFfUE0xMCwgY29sb3I9bWlzc2luZykpICsgCiAgICAgIGdlb21fbGluZShhZXMoZ3JvdXA9MSkpICsgeGxhYigiIikgKyBnZ3RpdGxlKCJNb3ZpbmcgQXZlcmFnZSBJbXB1dGF0aW9uIikgKwogICAgICBzY2FsZV94X2RhdGV0aW1lKGRhdGVfYnJlYWtzID0gIjEgbW9udGgiLCBkYXRlX2xhYmVscyA9ICIlYiIpCmdyaWQuYXJyYW5nZShwMSxwMixwMyxwNCxuY29sPTEpCmBgYAoKCmBgYHtyLCBmaWcud2lkdGg9NX0KcDEgPC0gZ2dwbG90KGRhdGEgPSBkZltbImltcHV0ZV8xIl1dICU+JSBtdXRhdGUobWlzc2luZz1kZltbIm5hIl1dJFNVRjdfUE0xMCksIAogICAgICAgICAgICAgYWVzKHg9dGltZSx5PVNVRjdfUE0xMCwgY29sb3I9bWlzc2luZykpICsgCiAgICAgIGdlb21fbGluZShhZXMoZ3JvdXA9MSkpICsgeGxhYigiIikgKyBnZ3RpdGxlKCJNZWRpYW4gSW1wdXRhdGlvbiIpICsKICAgICAgc2NhbGVfeF9kYXRldGltZShkYXRlX2JyZWFrcyA9ICIxIG1vbnRoIiwgZGF0ZV9sYWJlbHMgPSAiJWIiKQpwMiA8LSBnZ3Bsb3QoZGF0YSA9IGRmW1siaW1wdXRlXzIiXV0gJT4lIG11dGF0ZShtaXNzaW5nPWRmW1sibmEiXV0kU1VGN19QTTEwKSwgCiAgICAgICAgICAgICBhZXMoeD10aW1lLHk9U1VGN19QTTEwLCBjb2xvcj1taXNzaW5nKSkgKyAKICAgICAgZ2VvbV9saW5lKGFlcyhncm91cD0xKSkgKyB4bGFiKCIiKSArIGdndGl0bGUoIk1lYW4gSW1wdXRhdGlvbiIpICsKICAgICAgc2NhbGVfeF9kYXRldGltZShkYXRlX2JyZWFrcyA9ICIxIG1vbnRoIiwgZGF0ZV9sYWJlbHMgPSAiJWIiKQpwMyA8LSBnZ3Bsb3QoZGF0YSA9IGRmW1siaW1wdXRlXzMiXV0gJT4lIG11dGF0ZShtaXNzaW5nPWRmW1sibmEiXV0kU1VGN19QTTEwKSwgCiAgICAgICAgICAgICBhZXMoeD10aW1lLHk9U1VGN19QTTEwLCBjb2xvcj1taXNzaW5nKSkgKyAKICAgICAgZ2VvbV9saW5lKGFlcyhncm91cD0xKSkgKyB4bGFiKCIiKSArIGdndGl0bGUoIkxpbmVhciBJbnRlcnBvbGF0aW9uIEltcHV0YXRpb24iKSArCiAgICAgIHNjYWxlX3hfZGF0ZXRpbWUoZGF0ZV9icmVha3MgPSAiMSBtb250aCIsIGRhdGVfbGFiZWxzID0gIiViIikKcDQgPC0gZ2dwbG90KGRhdGEgPSBkZltbImltcHV0ZV80Il1dICU+JSBtdXRhdGUobWlzc2luZz1kZltbIm5hIl1dJFNVRjdfUE0xMCksIAogICAgICAgICAgICAgYWVzKHg9dGltZSx5PVNVRjdfUE0xMCwgY29sb3I9bWlzc2luZykpICsgCiAgICAgIGdlb21fbGluZShhZXMoZ3JvdXA9MSkpICsgeGxhYigiIikgKyBnZ3RpdGxlKCJNb3ZpbmcgQXZlcmFnZSBJbXB1dGF0aW9uIikgKwogICAgICBzY2FsZV94X2RhdGV0aW1lKGRhdGVfYnJlYWtzID0gIjEgbW9udGgiLCBkYXRlX2xhYmVscyA9ICIlYiIpCmdyaWQuYXJyYW5nZShwMSxwMixwMyxwNCxuY29sPTEpCmBgYAoKIyMjIFNPMgoKYGBge3IsIGZpZy53aWR0aD01fQpwMSA8LSBnZ3Bsb3QoZGF0YSA9IGRmW1siaW1wdXRlXzEiXV0gJT4lIG11dGF0ZShtaXNzaW5nPWRmW1sibmEiXV0kU1VGMV9TTzIpLCAKICAgICAgICAgICAgIGFlcyh4PXRpbWUseT1TVUYxX1NPMiwgY29sb3I9bWlzc2luZykpICsgCiAgICAgIGdlb21fbGluZShhZXMoZ3JvdXA9MSkpICsgeGxhYigiIikgKyBnZ3RpdGxlKCJNZWRpYW4gSW1wdXRhdGlvbiIpICsKICAgICAgc2NhbGVfeF9kYXRldGltZShkYXRlX2JyZWFrcyA9ICIxIG1vbnRoIiwgZGF0ZV9sYWJlbHMgPSAiJWIiKQpwMiA8LSBnZ3Bsb3QoZGF0YSA9IGRmW1siaW1wdXRlXzIiXV0gJT4lIG11dGF0ZShtaXNzaW5nPWRmW1sibmEiXV0kU1VGMV9TTzIpLCAKICAgICAgICAgICAgIGFlcyh4PXRpbWUseT1TVUYxX1NPMiwgY29sb3I9bWlzc2luZykpICsgCiAgICAgIGdlb21fbGluZShhZXMoZ3JvdXA9MSkpICsgeGxhYigiIikgKyBnZ3RpdGxlKCJNZWFuIEltcHV0YXRpb24iKSArCiAgICAgIHNjYWxlX3hfZGF0ZXRpbWUoZGF0ZV9icmVha3MgPSAiMSBtb250aCIsIGRhdGVfbGFiZWxzID0gIiViIikKcDMgPC0gZ2dwbG90KGRhdGEgPSBkZltbImltcHV0ZV8zIl1dICU+JSBtdXRhdGUobWlzc2luZz1kZltbIm5hIl1dJFNVRjFfU08yKSwgCiAgICAgICAgICAgICBhZXMoeD10aW1lLHk9U1VGMV9TTzIsIGNvbG9yPW1pc3NpbmcpKSArIAogICAgICBnZW9tX2xpbmUoYWVzKGdyb3VwPTEpKSArIHhsYWIoIiIpICsgZ2d0aXRsZSgiTGluZWFyIEludGVycG9sYXRpb24gSW1wdXRhdGlvbiIpICsKICAgICAgc2NhbGVfeF9kYXRldGltZShkYXRlX2JyZWFrcyA9ICIxIG1vbnRoIiwgZGF0ZV9sYWJlbHMgPSAiJWIiKQpwNCA8LSBnZ3Bsb3QoZGF0YSA9IGRmW1siaW1wdXRlXzQiXV0gJT4lIG11dGF0ZShtaXNzaW5nPWRmW1sibmEiXV0kU1VGMV9TTzIpLCAKICAgICAgICAgICAgIGFlcyh4PXRpbWUseT1TVUYxX1NPMiwgY29sb3I9bWlzc2luZykpICsgCiAgICAgIGdlb21fbGluZShhZXMoZ3JvdXA9MSkpICsgeGxhYigiIikgKyBnZ3RpdGxlKCJNb3ZpbmcgQXZlcmFnZSBJbXB1dGF0aW9uIikgKwogICAgICBzY2FsZV94X2RhdGV0aW1lKGRhdGVfYnJlYWtzID0gIjEgbW9udGgiLCBkYXRlX2xhYmVscyA9ICIlYiIpCmdyaWQuYXJyYW5nZShwMSxwMixwMyxwNCxuY29sPTEpCmBgYAoKCmBgYHtyLCBmaWcud2lkdGg9NX0KcDEgPC0gZ2dwbG90KGRhdGEgPSBkZltbImltcHV0ZV8xIl1dICU+JSBtdXRhdGUobWlzc2luZz1kZltbIm5hIl1dJFNVRjdfU08yKSwgCiAgICAgICAgICAgICBhZXMoeD10aW1lLHk9U1VGN19TTzIsIGNvbG9yPW1pc3NpbmcpKSArIAogICAgICBnZW9tX2xpbmUoYWVzKGdyb3VwPTEpKSArIHhsYWIoIiIpICsgZ2d0aXRsZSgiTWVkaWFuIEltcHV0YXRpb24iKSArCiAgICAgIHNjYWxlX3hfZGF0ZXRpbWUoZGF0ZV9icmVha3MgPSAiMSBtb250aCIsIGRhdGVfbGFiZWxzID0gIiViIikKcDIgPC0gZ2dwbG90KGRhdGEgPSBkZltbImltcHV0ZV8yIl1dICU+JSBtdXRhdGUobWlzc2luZz1kZltbIm5hIl1dJFNVRjdfU08yKSwgCiAgICAgICAgICAgICBhZXMoeD10aW1lLHk9U1VGN19TTzIsIGNvbG9yPW1pc3NpbmcpKSArIAogICAgICBnZW9tX2xpbmUoYWVzKGdyb3VwPTEpKSArIHhsYWIoIiIpICsgZ2d0aXRsZSgiTWVhbiBJbXB1dGF0aW9uIikgKwogICAgICBzY2FsZV94X2RhdGV0aW1lKGRhdGVfYnJlYWtzID0gIjEgbW9udGgiLCBkYXRlX2xhYmVscyA9ICIlYiIpCnAzIDwtIGdncGxvdChkYXRhID0gZGZbWyJpbXB1dGVfMyJdXSAlPiUgbXV0YXRlKG1pc3Npbmc9ZGZbWyJuYSJdXSRTVUY3X1NPMiksIAogICAgICAgICAgICAgYWVzKHg9dGltZSx5PVNVRjdfU08yLCBjb2xvcj1taXNzaW5nKSkgKyAKICAgICAgZ2VvbV9saW5lKGFlcyhncm91cD0xKSkgKyB4bGFiKCIiKSArIGdndGl0bGUoIkxpbmVhciBJbnRlcnBvbGF0aW9uIEltcHV0YXRpb24iKSArCiAgICAgIHNjYWxlX3hfZGF0ZXRpbWUoZGF0ZV9icmVha3MgPSAiMSBtb250aCIsIGRhdGVfbGFiZWxzID0gIiViIikKcDQgPC0gZ2dwbG90KGRhdGEgPSBkZltbImltcHV0ZV80Il1dICU+JSBtdXRhdGUobWlzc2luZz1kZltbIm5hIl1dJFNVRjdfU08yKSwgCiAgICAgICAgICAgICBhZXMoeD10aW1lLHk9U1VGN19TTzIsIGNvbG9yPW1pc3NpbmcpKSArIAogICAgICBnZW9tX2xpbmUoYWVzKGdyb3VwPTEpKSArIHhsYWIoIiIpICsgZ2d0aXRsZSgiTW92aW5nIEF2ZXJhZ2UgSW1wdXRhdGlvbiIpICsKICAgICAgc2NhbGVfeF9kYXRldGltZShkYXRlX2JyZWFrcyA9ICIxIG1vbnRoIiwgZGF0ZV9sYWJlbHMgPSAiJWIiKQpncmlkLmFycmFuZ2UocDEscDIscDMscDQsbmNvbD0xKQpgYGAKCiMjIE1vZGVsbGluZwoKIyMjIER1bW15IHZhcmlhYmxlcwpgYGB7ciB3YXJuaW5nPUZBTFNFfQpkZltbImR1bW15Il1dIDwtIGR1bW15X2NvbHMoZGZfcmF3LCBzZWxlY3RfY29sdW1ucyA9IGMoIkoiLCJIYXJpIikpICU+JSAKICAgICAgICAgICAgICAgICBtdXRhdGUodD1zZXFfYWxvbmcodGltZSkpICU+JSAKICAgICAgICAgICAgICAgICBzZWxlY3Qoc3RhcnRzX3dpdGgoIkpfIiksIHN0YXJ0c193aXRoKCJIYXJpXyIpLHQpCmBgYAoKCgpgYGB7cn0KZm9yIChrIGluIHZhcl9wb2xsdXRhbnQpewogIG5hbWUgPC0gcGFzdGUwKGssIl9pbXBfMSIpCiAgZGZbW25hbWVdXSA8LSBiaW5kX2NvbHMoZGZbWyJpbXB1dGVfMSJdXSwgZGZbWyJkdW1teSJdXSkgJT4lIAogICAgICAgICAgICAgICAgc2VsZWN0KHRpbWUsc3RhcnRzX3dpdGgoayksIHN0YXJ0c193aXRoKCJKXyIpLCBzdGFydHNfd2l0aCgiSGFyaV8iKSx0KQogIG5hbWUgPC0gcGFzdGUwKGssIl9pbXBfMiIpCiAgZGZbW25hbWVdXSA8LSBiaW5kX2NvbHMoZGZbWyJpbXB1dGVfMiJdXSwgZGZbWyJkdW1teSJdXSkgJT4lIAogICAgICAgICAgICAgICAgc2VsZWN0KHRpbWUsc3RhcnRzX3dpdGgoayksIHN0YXJ0c193aXRoKCJKXyIpLCBzdGFydHNfd2l0aCgiSGFyaV8iKSx0KQogIG5hbWUgPC0gcGFzdGUwKGssIl9pbXBfMyIpCiAgZGZbW25hbWVdXSA8LSBiaW5kX2NvbHMoZGZbWyJpbXB1dGVfMyJdXSwgZGZbWyJkdW1teSJdXSkgJT4lIAogICAgICAgICAgICAgICAgc2VsZWN0KHRpbWUsc3RhcnRzX3dpdGgoayksIHN0YXJ0c193aXRoKCJKXyIpLCBzdGFydHNfd2l0aCgiSGFyaV8iKSx0KQogIG5hbWUgPC0gcGFzdGUwKGssIl9pbXBfNCIpCiAgZGZbW25hbWVdXSA8LSBiaW5kX2NvbHMoZGZbWyJpbXB1dGVfNCJdXSwgZGZbWyJkdW1teSJdXSkgJT4lIAogICAgICAgICAgICAgICAgc2VsZWN0KHRpbWUsc3RhcnRzX3dpdGgoayksIHN0YXJ0c193aXRoKCJKXyIpLCBzdGFydHNfd2l0aCgiSGFyaV8iKSx0KQp9CmBgYAoKCmBgYHtyfQppbmQgPC0gZGZfcmF3ICU+JSBtYWtlX3RzX3NwbGl0cygubGVuZ3RoX3Rlc3QgPSA0OCkKaW5kCmBgYAoKCiMjIyBNb2RlbCBGaXR0aW5nIGFuZCBGb3JlY2FzdGluZwpgYGB7cn0KYXBwbHlGb3JlY2FzdCA8LSBmdW5jdGlvbihkYXRhKXsKICBpbmQgPC0gZGF0YSAlPiUgbWFrZV90c19zcGxpdHMoLmxlbmd0aF90ZXN0ID0gNDgpCiAgdHJhaW4gPC0gZGF0YVtpbmQkaWR4X3RyYWluLF0KICB0ZXN0ICA8LSBkYXRhW2luZCRpZHhfdGVzdCxdCiAgeXkgPC0gY29sbmFtZXMoZGF0YSlbMl0KICBmIDwtIHBhc3RlMCh5eSwifi4tMS10aW1lLUhhcmlfMSIpCiAgbSA8LSBsbShmLCBkYXRhID0gdHJhaW4pCiAgci5zcXVhcmVkIDwtIHN1bW1hcnkobSkkci5zcXVhcmVkCiAgcHJlZCA8LSBtICU+JSBwcmVkaWN0KHRlc3QpCiAgUk1TRSA8LSBybXNlKHRlc3RbeXldICU+JSBwdWxsKCkscHJlZCkKICBNQVBFIDwtIG1hcGUodGVzdFt5eV0gJT4lIHB1bGwoKSxwcmVkKQogIHNNQVBFIDwtIHNtYXBlKHRlc3RbeXldICU+JSBwdWxsKCkscHJlZCkKICBwX3RyYWluIDwtIGdncGxvdCh0cmFpbiAlPiUgbXV0YXRlKHByZWRpY3RlZD1tJGZpdHRlZC52YWx1ZXMpKSArIAogICAgICAgICAgICAgZ2VvbV9saW5lKGFlc18oeD1+dGltZSx5PWFzLm5hbWUoeXkpKSkgKyAgCiAgICAgICAgICAgICBnZW9tX2xpbmUoYWVzKHg9dGltZSx5PXByZWRpY3RlZCksIGNvbG9yPSJyZWQiKQogIHBfdGVzdCAgPC0gZ2dwbG90KHRlc3QgJT4lIG11dGF0ZShwcmVkaWN0ZWQ9cHJlZCkpICsgCiAgICAgICAgICAgICBnZW9tX2xpbmUoYWVzXyh4PX50aW1lLHk9YXMubmFtZSh5eSkpKSArICAKICAgICAgICAgICAgIGdlb21fbGluZShhZXMoeD10aW1lLHk9cHJlZGljdGVkKSwgY29sb3I9InJlZCIpCiAgcmVzdWx0cyA8LSBsaXN0KHByZWRpY3Rpb249cHJlZCwgCiAgICAgICAgICAgICAgICAgIHIuc3F1YXJlZD1yLnNxdWFyZWQsCiAgICAgICAgICAgICAgICAgIFJNU0U9Uk1TRSwKICAgICAgICAgICAgICAgICAgTUFQRT1NQVBFLAogICAgICAgICAgICAgICAgICBzTUFQRT1zTUFQRSwKICAgICAgICAgICAgICAgICAgcGxvdF90cmFpbj1wX3RyYWluLAogICAgICAgICAgICAgICAgICBwbG90X3Rlc3Q9cF90ZXN0KQp9CmBgYAoKCgoKYGBge3J9CmRmX3BvbGx1dGFudCA8LSBuYW1lcyhkZilbZ3JlcGwoImltcF8iLG5hbWVzKGRmKSldCnJlcyA8LSBsaXN0KCkKZm9yIChuYW1lIGluIGRmX3BvbGx1dGFudCl7cmVzW1tuYW1lXV0gPC0gYXBwbHlGb3JlY2FzdChkZltbbmFtZV1dKX0KYGBgCgoKIyMgRm9yZWNhc3QgQ29tcGFyaXNvbgpgYGB7cn0KZGQgPC0gYXNfdGliYmxlKHJlc1tbMV1dWzI6NV0pCmZvciAobmFtZSBpbiBkZl9wb2xsdXRhbnRbLTFdKXsKICBkZCA8LSBkZCAlPiUgYWRkX3Jvdyhhc190aWJibGUocmVzW1tuYW1lXV1bMjo1XSkpCn0KcmVzdWx0cyA8LSBkZCAlPiUgbXV0YXRlKG1vZGVsPWRmX3BvbGx1dGFudCkKYGBgCgoKIyMjIENPCmBgYHtyfQpyZXN1bHRzWzE6OCxdCmBgYAoKIyMjIE5PMgpgYGB7cn0KcmVzdWx0c1s5OjE2LF0KYGBgCgoKIyMjIE8zCmBgYHtyfQpyZXN1bHRzWzE3OjI0LF0KYGBgCgoKIyMjIFBNMTAKYGBge3J9CnJlc3VsdHNbMjU6MzIsXQpgYGAKCgojIyMgU08yCmBgYHtyfQpyZXN1bHRzWzMzOjQwLF0KYGBgCgoKCgoKCgoKCgoK