#load needed packages
library(tidyverse)
library(MASS)
library(forecast)
library(fpp)
library(corrplot)
library(magrittr)
library(zoo)
library(RColorBrewer)
library(gridExtra)
library(Amelia)
#bring in data

train_features = read.csv('dengue_features_train.csv')
train_labels   = read.csv('dengue_labels_train.csv')
densubformat = read.csv('submission_format.csv')
#separate data by city
sj_train_features = train_features %>% filter(city == 'sj')
sj_train_labels   = train_labels   %>% filter(city == 'sj')

iq_train_features = train_features %>% filter(city == 'iq')
iq_train_labels   = train_labels   %>% filter(city == 'iq')
#data shape for each city
cat('\nSan Juan\n',
    '\t features: ', sj_train_features %>% ncol, 
    '\t entries: ' , sj_train_features %>% nrow,
    '\t labels: '  , sj_train_labels %>% nrow)

San Juan
     features:  24   entries:  936   labels:  936
cat('\nIquitos\n',
    '\t features: ', iq_train_features %>% ncol, 
    '\t entries: ' , iq_train_features %>% nrow,
    '\t labels: '  , iq_train_labels %>% nrow)

Iquitos
     features:  24   entries:  520   labels:  520
#Look at Data 
head(sj_train_features[1:7])
tail(sj_train_features)
head(iq_train_features[1:7])
tail(iq_train_features)
#Remove "week_start_date"
sj_train_features %<>% dplyr::select(-week_start_date)
iq_train_features %<>% dplyr::select(-week_start_date)

apply(sj_train_features, 2, function(x) 
  round(100 * (length(which(is.na(x))))/length(x) , digits = 1)) %>%
  as.data.frame() %>%
  `names<-`('Percent of Missing Values')

#missing values

missmap(sj_train_features)



#example plot of variable with out the NA fix

sj_train_features %>%
  mutate(index = as.numeric(row.names(.))) %>%
  ggplot(aes(index, ndvi_ne)) + 
  geom_line(colour = 'dodgerblue') +
  ggtitle("Vegetation Index over Time")



#fill in the NA 
sj_train_features$ndvi_ne %<>% na.locf(fromLast = TRUE)
iq_train_features$ndvi_ne %<>% na.locf(fromLast = TRUE)
#distrubution of labels SJ
cat('\nSan Juan\n',
    '\t total cases mean: ',      sj_train_labels$total_cases %>% mean(), 
    '\t total cases variance: ' , sj_train_labels$total_cases %>% var() )

San Juan
     total cases mean:  34.18056     total cases variance:  2640.045
#distrubution of labels IQ
cat('\nIquitos\n',
    '\t total cases mean: ',      iq_train_labels$total_cases %>% mean(), 
    '\t total cases variance: ' , iq_train_labels$total_cases %>% var() )

Iquitos
     total cases mean:  7.565385     total cases variance:  115.8955
#Total cases of disease
rbind(iq_train_labels, sj_train_labels) %>% 
  ggplot(aes(x = total_cases,fill = ..count..)) + 
  geom_histogram(bins = 12, colour = 'black') + ggtitle('Total Cases of Dengue') +
  scale_y_continuous(breaks = seq(0,700,100)) + facet_wrap(~city)

#correlations ?
sj_train_features %<>% mutate('total_cases' = sj_train_labels$total_cases)
iq_train_features %<>% mutate('total_cases' = iq_train_labels$total_cases)

#san juan corr
sj_train_features %>% 
  dplyr::select(-city, -year, -weekofyear) %>%
  cor(use = 'pairwise.complete.obs') -> M1

corrplot(M1, type="lower", method="color",
         col=brewer.pal(n=8, name="RdBu"),diag=FALSE)



#iquitos corr
iq_train_features %>% 
  dplyr::select(-city, -year, -weekofyear) %>%
  cor(use = 'pairwise.complete.obs') -> M2

corrplot(M2, type="lower", method="color",
         col=brewer.pal(n=8, name="RdBu"),diag=FALSE)




#correlation bar
sort(M1[21,-21]) %>%  
  as.data.frame %>% 
  `names<-`('correlation') %>%
  ggplot(aes(x = reorder(row.names(.), -correlation), y = correlation, fill = correlation)) + 
  geom_bar(stat='identity', colour = 'black') + scale_fill_continuous(guide = FALSE) + scale_y_continuous(limits =  c(-.15,.25)) +
  labs(title = 'San Juan\n Correlations', x = NULL, y = NULL) + coord_flip() -> cor1

# can use ncol(M1) instead of 21 to generalize the code
sort(M2[21,-21]) %>%  
  as.data.frame %>% 
  `names<-`('correlation') %>%
  ggplot(aes(x = reorder(row.names(.), -correlation), y = correlation, fill = correlation)) + 
  geom_bar(stat='identity', colour = 'black') + scale_fill_continuous(guide = FALSE) + scale_y_continuous(limits =  c(-.15,.25)) +
  labs(title = 'Iquitos\n Correlations', x = NULL, y = NULL) + coord_flip() -> cor2

grid.arrange(cor1, cor2, nrow = 1)

preprocessData <- function(data_path, labels_path = NULL)
{
  # load data 
  df <- read.csv(data_path)
  
  # features we want
  features = c("reanalysis_specific_humidity_g_per_kg", "reanalysis_dew_point_temp_k",
               "station_avg_temp_c", "station_min_temp_c")
  
  # fill missing values
  df[features] %<>% na.locf(fromLast = TRUE) 
  
  # add city if labels data aren't provided
  if (is.null(labels_path)) features %<>% c("city", "year", "weekofyear")
  
  # select features we want
  df <- df[features]
  
  # add labels to dataframe
  if (!is.null(labels_path)) df %<>% cbind(read.csv(labels_path))
  
  # filter by city
  df_sj <- filter(df, city == 'sj')
  df_iq <- filter(df, city == 'iq')
  
  # return a list with the 2 data frames 
  return(list(df_sj, df_iq))
}


#preprocess files
preprocessData(data_path = 'dengue_features_train.csv', labels_path = 'dengue_labels_train.csv') -> trains
sj_train <- trains[[1]]; iq_train <- as.data.frame(trains[2])

summary(sj_train)
 reanalysis_specific_humidity_g_per_kg reanalysis_dew_point_temp_k
 Min.   :11.72                         Min.   :289.6              
 1st Qu.:15.23                         1st Qu.:293.8              
 Median :16.83                         Median :295.4              
 Mean   :16.54                         Mean   :295.1              
 3rd Qu.:17.85                         3rd Qu.:296.4              
 Max.   :19.44                         Max.   :297.8              
 station_avg_temp_c station_min_temp_c city          year        weekofyear   
 Min.   :22.84      Min.   :17.80      iq:  0   Min.   :1990   Min.   : 1.00  
 1st Qu.:25.81      1st Qu.:21.70      sj:936   1st Qu.:1994   1st Qu.:13.75  
 Median :27.21      Median :22.80               Median :1999   Median :26.50  
 Mean   :27.00      Mean   :22.59               Mean   :1999   Mean   :26.50  
 3rd Qu.:28.18      3rd Qu.:23.90               3rd Qu.:2003   3rd Qu.:39.25  
 Max.   :30.07      Max.   :25.60               Max.   :2008   Max.   :53.00  
  total_cases    
 Min.   :  0.00  
 1st Qu.:  9.00  
 Median : 19.00  
 Mean   : 34.18  
 3rd Qu.: 37.00  
 Max.   :461.00  
summary(iq_train)
 reanalysis_specific_humidity_g_per_kg reanalysis_dew_point_temp_k
 Min.   :12.11                         Min.   :290.1              
 1st Qu.:16.12                         1st Qu.:294.6              
 Median :17.43                         Median :295.9              
 Mean   :17.10                         Mean   :295.5              
 3rd Qu.:18.19                         3rd Qu.:296.6              
 Max.   :20.46                         Max.   :298.4              
 station_avg_temp_c station_min_temp_c city          year        weekofyear   
 Min.   :21.40      Min.   :14.70      iq:520   Min.   :2000   Min.   : 1.00  
 1st Qu.:27.00      1st Qu.:20.60      sj:  0   1st Qu.:2003   1st Qu.:13.75  
 Median :27.57      Median :21.35               Median :2005   Median :26.50  
 Mean   :27.52      Mean   :21.20               Mean   :2005   Mean   :26.50  
 3rd Qu.:28.09      3rd Qu.:22.00               3rd Qu.:2007   3rd Qu.:39.25  
 Max.   :30.80      Max.   :24.20               Max.   :2010   Max.   :53.00  
  total_cases     
 Min.   :  0.000  
 1st Qu.:  1.000  
 Median :  5.000  
 Mean   :  7.565  
 3rd Qu.:  9.000  
 Max.   :116.000  
#split into train and test
sj_train_subtrain <- head(sj_train, 800)
sj_train_subtest  <- tail(sj_train, nrow(sj_train) - 800)

iq_train_subtrain <- head(iq_train, 400)
iq_train_subtest  <- tail(iq_train, nrow(sj_train) - 400)
#negative binomial model replication


mae <- function(error) return(mean(abs(error)) )

get_bst_model <- function(train, test)
{
  
  # Step 1: specify the form of the model
  form <- "total_cases ~ 1 +
            reanalysis_specific_humidity_g_per_kg +
            reanalysis_dew_point_temp_k + 
            station_avg_temp_c +
            station_min_temp_c"
  
  grid = 10 ^(seq(-8, -3,1))
  
  best_alpha = c()
  best_score = 1000
  
  # Step 2: Find the best hyper parameter, alpha
  for (i in grid)
  {
    model = glm.nb(formula = form,
                   data = train,
                   init.theta = i)
    
    results <-  predict(model, test)
    score   <-  mae(test$total_cases - results)
    
    if (score < best_score) {
      best_alpha <- i
      best_score <- score
      cat('\nbest score = ', best_score, '\twith alpha = ', best_alpha)
    }
  }
  
  # Step 3: refit on entire dataset
  combined <- rbind(train, test)
  combined_model = glm.nb(formula=form,
                          data = combined,
                          init.theta = best_alpha)
  
  return (combined_model)
}
sj_model <- get_bst_model(sj_train_subtrain, sj_train_subtest)

best score =  21.01167  with alpha =  1e-08
iq_model <- get_bst_model(iq_train_subtrain, iq_train_subtest)

best score =  6.421811  with alpha =  1e-08
best score =  6.421811  with alpha =  1e-06
best score =  6.421811  with alpha =  1e-05
#plot san juan

sj_train$fitted = predict(sj_model, sj_train, type = 'response')
sj_train %>% 
  mutate(index = as.numeric(row.names(.))) %>%
  ggplot(aes(x = index)) + ggtitle("San Juan") +
  geom_line(aes(y = total_cases, colour = "total_cases")) + 
  geom_line(aes(y = fitted, colour = "fitted"))

#plot Iquitos
iq_train$fitted = predict(iq_model, iq_train, type = 'response')
iq_train %>% 
  mutate(index = as.numeric(row.names(.))) %>%
  ggplot(aes(x = index)) + ggtitle("Iquitos") + 
  geom_line(aes(y = total_cases, colour = "total_cases")) + 
  geom_line(aes(y = fitted, colour = "fitted"))

#submit predictions
tests <- preprocessData('dengue_features_test.csv')
sj_test <- tests[[1]]; iq_test <- tests[[2]]

sj_test$predicted = predict(sj_model , sj_test, type = 'response')
iq_test$predicted = predict(iq_model , iq_test, type = 'response')

submissions = read.csv('submission_format.csv')
inner_join(submissions, rbind(sj_test,iq_test)) %>%
  dplyr::select(city, year, weekofyear, total_cases = predicted) ->
  predictions
Joining, by = c("city", "year", "weekofyear")
predictions$total_cases %<>% round()
write.csv(predictions, 'negbinomialpredictions.csv', row.names = FALSE)
#time series plot 

sj.ts<-ts(sj_train_features$total_cases, frequency=52, start=c(1990, 18))
plot(sj.ts)


iq.ts<-ts(iq_train_features$total_cases, frequency=52, start=c(2000, 26))
plot(iq.ts)



#train and test sets
sj.train.ts<-window(sj.ts, end=c(2004,37))
sj.test.ts<-window(sj.ts,start=c(2004,38))

iq.train.ts<-window(iq.ts, end=c(2008,27))
iq.test.ts<-window(iq.ts,start=c(2008,28))
#neural network models

sj.fit.nnet<-nnetar(sj.train.ts)
sj.fit.nnet
Series: sj.train.ts 
Model:  NNAR(14,1,8)[52] 
Call:   nnetar(y = sj.train.ts)

Average of 20 networks, each of which is
a 15-8-1 network with 137 weights
options were - linear output units 

sigma^2 estimated as 44.45
iq.fit.nnet<-nnetar(iq.train.ts)
iq.fit.nnet
Series: iq.train.ts 
Model:  NNAR(3,1,2)[52] 
Call:   nnetar(y = iq.train.ts)

Average of 20 networks, each of which is
a 4-2-1 network with 13 weights
options were - linear output units 

sigma^2 estimated as 34.12
#neural net forecast

sj.fcast.nnet<-forecast(sj.fit.nnet,h=260)
plot(sj.fcast.nnet) 
lines(sj.test.ts, col="red")  
legend("topright",lty=1,col=c("red","blue"),c("actual values","forecast"))



iq.fcast.nnet<-forecast(iq.fit.nnet,h=156)
plot(iq.fcast.nnet) 
lines(iq.test.ts, col="red")  
legend("topright",lty=1,col=c("red","blue"),c("actual values","forecast"))


#accuracy
acc.sj.nnet <- accuracy(sj.fcast.nnet, sj.test.ts)
acc.sj.nnet
                      ME      RMSE       MAE  MPE MAPE      MASE        ACF1
Training set 0.006646099  6.667078  4.885579 -Inf  Inf 0.1225886 -0.01376727
Test set     7.338365616 32.377485 18.987895 -Inf  Inf 0.4764430  0.93389023
             Theil's U
Training set        NA
Test set             0
tsdisplay(residuals(sj.fcast.nnet))



acc.iq.nnet <- accuracy(iq.fcast.nnet,iq.test.ts)
acc.iq.nnet
                      ME      RMSE      MAE  MPE MAPE      MASE         ACF1
Training set -0.01527385  5.840966 3.543559 -Inf  Inf 0.3871471 -0.001184902
Test set      5.28822909 12.685205 7.300727 -Inf  Inf 0.7976317  0.844531021
             Theil's U
Training set        NA
Test set             0
tsdisplay(residuals(iq.fcast.nnet))


#solutions for neural net model
NNET_sj_sol=data.frame(densubformat[1:260, -4],total_cases=round(sj.fcast.nnet$mean))
NNET_iq_sol=data.frame(densubformat[261:416,-4],total_cases=round(iq.fcast.nnet$mean))

Dengue_NNET_solution=bind_rows(NNET_sj_sol,NNET_iq_sol)
Vectorizing 'ts' elements may not preserve their attributesVectorizing 'ts' elements may not preserve their attributes
write.csv(Dengue_NNET_solution,file="Dengue_NNET_predictions.csv",row.names=F)
#arima model SJ

sj.arima=Arima(sj.train.ts,order=c(1,1,2),seasonal=c(0,0,0))
sj.arima
Series: sj.train.ts 
ARIMA(1,1,2) 

Coefficients:
          ar1     ma1     ma2
      -0.7820  0.9503  0.1979
s.e.   0.2153  0.2147  0.0347

sigma^2 estimated as 192.5:  log likelihood=-3023.21
AIC=6054.43   AICc=6054.48   BIC=6072.89
sj.arima.fc=forecast(sj.arima,h=260)
acc.sj.arima = accuracy(sj.arima.fc,sj.test.ts)
acc.sj.arima
                       ME     RMSE       MAE  MPE MAPE      MASE        ACF1
Training set  0.006577048 13.83894  8.379156  NaN  Inf 0.2102492 0.007353076
Test set     14.740977080 34.48529 18.234742 -Inf  Inf 0.4575449 0.932173942
             Theil's U
Training set        NA
Test set             0
plot(sj.arima.fc)

tsdisplay(residuals(sj.arima.fc))



#arima modle IQ
iq.arima=Arima(iq.train.ts,order=c(0,1,2),seasonal=c(0,0,1))
iq.arima
Series: iq.train.ts 
ARIMA(0,1,2)(0,0,1)[52] 

Coefficients:
          ma1      ma2    sma1
      -0.2731  -0.3054  0.0385
s.e.   0.0469   0.0479  0.0437

sigma^2 estimated as 53.12:  log likelihood=-1418.7
AIC=2845.39   AICc=2845.49   BIC=2861.52
iq.arima.fc=forecast(iq.arima,h=156)
acc.iq.arima = accuracy(iq.arima.fc,iq.test.ts)
acc.iq.arima
                      ME      RMSE      MAE  MPE MAPE      MASE        ACF1
Training set 0.008711802  7.253488 3.808308  NaN  Inf 0.4160719 -0.00938541
Test set     7.897047615 13.832998 8.248390 -Inf  Inf 0.9011674  0.84182636
             Theil's U
Training set        NA
Test set             0
plot(iq.arima.fc)

tsdisplay(residuals(iq.arima.fc))


#solution for arima model
Arima_sj_sol=data.frame(densubformat[1:260,-4],total_cases=round(sj.arima.fc$mean))
Arima_iq_sol=data.frame(densubformat[261:416,-4],total_cases=round(iq.arima.fc$mean))

Dengue_Arima_solution=bind_rows(Arima_sj_sol,Arima_iq_sol)
Vectorizing 'ts' elements may not preserve their attributesVectorizing 'ts' elements may not preserve their attributes
write.csv(Dengue_Arima_solution,file="Dengue_Arima_predictions.csv",row.names=F)
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQpgYGB7cn0KI2xvYWQgbmVlZGVkIHBhY2thZ2VzCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KE1BU1MpCmxpYnJhcnkoZm9yZWNhc3QpCmxpYnJhcnkoZnBwKQpsaWJyYXJ5KGNvcnJwbG90KQpsaWJyYXJ5KG1hZ3JpdHRyKQpsaWJyYXJ5KHpvbykKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KEFtZWxpYSkKYGBgCgoKYGBge3J9CiNicmluZyBpbiBkYXRhCgp0cmFpbl9mZWF0dXJlcyA9IHJlYWQuY3N2KCdkZW5ndWVfZmVhdHVyZXNfdHJhaW4uY3N2JykKdHJhaW5fbGFiZWxzICAgPSByZWFkLmNzdignZGVuZ3VlX2xhYmVsc190cmFpbi5jc3YnKQpkZW5zdWJmb3JtYXQgPSByZWFkLmNzdignc3VibWlzc2lvbl9mb3JtYXQuY3N2JykKYGBgCgoKYGBge3J9CiNzZXBhcmF0ZSBkYXRhIGJ5IGNpdHkKc2pfdHJhaW5fZmVhdHVyZXMgPSB0cmFpbl9mZWF0dXJlcyAlPiUgZmlsdGVyKGNpdHkgPT0gJ3NqJykKc2pfdHJhaW5fbGFiZWxzICAgPSB0cmFpbl9sYWJlbHMgICAlPiUgZmlsdGVyKGNpdHkgPT0gJ3NqJykKCmlxX3RyYWluX2ZlYXR1cmVzID0gdHJhaW5fZmVhdHVyZXMgJT4lIGZpbHRlcihjaXR5ID09ICdpcScpCmlxX3RyYWluX2xhYmVscyAgID0gdHJhaW5fbGFiZWxzICAgJT4lIGZpbHRlcihjaXR5ID09ICdpcScpCmBgYAoKCmBgYHtyfQojZGF0YSBzaGFwZSBmb3IgZWFjaCBjaXR5CmNhdCgnXG5TYW4gSnVhblxuJywKICAgICdcdCBmZWF0dXJlczogJywgc2pfdHJhaW5fZmVhdHVyZXMgJT4lIG5jb2wsIAogICAgJ1x0IGVudHJpZXM6ICcgLCBzal90cmFpbl9mZWF0dXJlcyAlPiUgbnJvdywKICAgICdcdCBsYWJlbHM6ICcgICwgc2pfdHJhaW5fbGFiZWxzICU+JSBucm93KQpjYXQoJ1xuSXF1aXRvc1xuJywKICAgICdcdCBmZWF0dXJlczogJywgaXFfdHJhaW5fZmVhdHVyZXMgJT4lIG5jb2wsIAogICAgJ1x0IGVudHJpZXM6ICcgLCBpcV90cmFpbl9mZWF0dXJlcyAlPiUgbnJvdywKICAgICdcdCBsYWJlbHM6ICcgICwgaXFfdHJhaW5fbGFiZWxzICU+JSBucm93KQpgYGAKCgpgYGB7cn0KI0xvb2sgYXQgRGF0YSAKaGVhZChzal90cmFpbl9mZWF0dXJlc1sxOjddKQp0YWlsKHNqX3RyYWluX2ZlYXR1cmVzKQpoZWFkKGlxX3RyYWluX2ZlYXR1cmVzWzE6N10pCnRhaWwoaXFfdHJhaW5fZmVhdHVyZXMpCmBgYAoKCmBgYHtyfQojUmVtb3ZlICJ3ZWVrX3N0YXJ0X2RhdGUiCnNqX3RyYWluX2ZlYXR1cmVzICU8PiUgZHBseXI6OnNlbGVjdCgtd2Vla19zdGFydF9kYXRlKQppcV90cmFpbl9mZWF0dXJlcyAlPD4lIGRwbHlyOjpzZWxlY3QoLXdlZWtfc3RhcnRfZGF0ZSkKCmFwcGx5KHNqX3RyYWluX2ZlYXR1cmVzLCAyLCBmdW5jdGlvbih4KSAKICByb3VuZCgxMDAgKiAobGVuZ3RoKHdoaWNoKGlzLm5hKHgpKSkpL2xlbmd0aCh4KSAsIGRpZ2l0cyA9IDEpKSAlPiUKICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgYG5hbWVzPC1gKCdQZXJjZW50IG9mIE1pc3NpbmcgVmFsdWVzJykKCiNtaXNzaW5nIHZhbHVlcwoKbWlzc21hcChzal90cmFpbl9mZWF0dXJlcykKCgojZXhhbXBsZSBwbG90IG9mIHZhcmlhYmxlIHdpdGggb3V0IHRoZSBOQSBmaXgKCnNqX3RyYWluX2ZlYXR1cmVzICU+JQogIG11dGF0ZShpbmRleCA9IGFzLm51bWVyaWMocm93Lm5hbWVzKC4pKSkgJT4lCiAgZ2dwbG90KGFlcyhpbmRleCwgbmR2aV9uZSkpICsgCiAgZ2VvbV9saW5lKGNvbG91ciA9ICdkb2RnZXJibHVlJykgKwogIGdndGl0bGUoIlZlZ2V0YXRpb24gSW5kZXggb3ZlciBUaW1lIikKCgojZmlsbCBpbiB0aGUgTkEgCnNqX3RyYWluX2ZlYXR1cmVzJG5kdmlfbmUgJTw+JSBuYS5sb2NmKGZyb21MYXN0ID0gVFJVRSkKaXFfdHJhaW5fZmVhdHVyZXMkbmR2aV9uZSAlPD4lIG5hLmxvY2YoZnJvbUxhc3QgPSBUUlVFKQpgYGAKCgpgYGB7cn0KI2Rpc3RydWJ1dGlvbiBvZiBsYWJlbHMgU0oKY2F0KCdcblNhbiBKdWFuXG4nLAogICAgJ1x0IHRvdGFsIGNhc2VzIG1lYW46ICcsICAgICAgc2pfdHJhaW5fbGFiZWxzJHRvdGFsX2Nhc2VzICU+JSBtZWFuKCksIAogICAgJ1x0IHRvdGFsIGNhc2VzIHZhcmlhbmNlOiAnICwgc2pfdHJhaW5fbGFiZWxzJHRvdGFsX2Nhc2VzICU+JSB2YXIoKSApCiNkaXN0cnVidXRpb24gb2YgbGFiZWxzIElRCmNhdCgnXG5JcXVpdG9zXG4nLAogICAgJ1x0IHRvdGFsIGNhc2VzIG1lYW46ICcsICAgICAgaXFfdHJhaW5fbGFiZWxzJHRvdGFsX2Nhc2VzICU+JSBtZWFuKCksIAogICAgJ1x0IHRvdGFsIGNhc2VzIHZhcmlhbmNlOiAnICwgaXFfdHJhaW5fbGFiZWxzJHRvdGFsX2Nhc2VzICU+JSB2YXIoKSApCmBgYAoKCmBgYHtyfQojVG90YWwgY2FzZXMgb2YgZGlzZWFzZQpyYmluZChpcV90cmFpbl9sYWJlbHMsIHNqX3RyYWluX2xhYmVscykgJT4lIAogIGdncGxvdChhZXMoeCA9IHRvdGFsX2Nhc2VzLGZpbGwgPSAuLmNvdW50Li4pKSArIAogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAxMiwgY29sb3VyID0gJ2JsYWNrJykgKyBnZ3RpdGxlKCdUb3RhbCBDYXNlcyBvZiBEZW5ndWUnKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDcwMCwxMDApKSArIGZhY2V0X3dyYXAofmNpdHkpCmBgYAoKCmBgYHtyfQojY29ycmVsYXRpb25zID8Kc2pfdHJhaW5fZmVhdHVyZXMgJTw+JSBtdXRhdGUoJ3RvdGFsX2Nhc2VzJyA9IHNqX3RyYWluX2xhYmVscyR0b3RhbF9jYXNlcykKaXFfdHJhaW5fZmVhdHVyZXMgJTw+JSBtdXRhdGUoJ3RvdGFsX2Nhc2VzJyA9IGlxX3RyYWluX2xhYmVscyR0b3RhbF9jYXNlcykKCiNzYW4ganVhbiBjb3JyCnNqX3RyYWluX2ZlYXR1cmVzICU+JSAKICBkcGx5cjo6c2VsZWN0KC1jaXR5LCAteWVhciwgLXdlZWtvZnllYXIpICU+JQogIGNvcih1c2UgPSAncGFpcndpc2UuY29tcGxldGUub2JzJykgLT4gTTEKCmNvcnJwbG90KE0xLCB0eXBlPSJsb3dlciIsIG1ldGhvZD0iY29sb3IiLAogICAgICAgICBjb2w9YnJld2VyLnBhbChuPTgsIG5hbWU9IlJkQnUiKSxkaWFnPUZBTFNFKQoKCiNpcXVpdG9zIGNvcnIKaXFfdHJhaW5fZmVhdHVyZXMgJT4lIAogIGRwbHlyOjpzZWxlY3QoLWNpdHksIC15ZWFyLCAtd2Vla29meWVhcikgJT4lCiAgY29yKHVzZSA9ICdwYWlyd2lzZS5jb21wbGV0ZS5vYnMnKSAtPiBNMgoKY29ycnBsb3QoTTIsIHR5cGU9Imxvd2VyIiwgbWV0aG9kPSJjb2xvciIsCiAgICAgICAgIGNvbD1icmV3ZXIucGFsKG49OCwgbmFtZT0iUmRCdSIpLGRpYWc9RkFMU0UpCgoKCiNjb3JyZWxhdGlvbiBiYXIKc29ydChNMVsyMSwtMjFdKSAlPiUgIAogIGFzLmRhdGEuZnJhbWUgJT4lIAogIGBuYW1lczwtYCgnY29ycmVsYXRpb24nKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKHJvdy5uYW1lcyguKSwgLWNvcnJlbGF0aW9uKSwgeSA9IGNvcnJlbGF0aW9uLCBmaWxsID0gY29ycmVsYXRpb24pKSArIAogIGdlb21fYmFyKHN0YXQ9J2lkZW50aXR5JywgY29sb3VyID0gJ2JsYWNrJykgKyBzY2FsZV9maWxsX2NvbnRpbnVvdXMoZ3VpZGUgPSBGQUxTRSkgKyBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gIGMoLS4xNSwuMjUpKSArCiAgbGFicyh0aXRsZSA9ICdTYW4gSnVhblxuIENvcnJlbGF0aW9ucycsIHggPSBOVUxMLCB5ID0gTlVMTCkgKyBjb29yZF9mbGlwKCkgLT4gY29yMQoKIyBjYW4gdXNlIG5jb2woTTEpIGluc3RlYWQgb2YgMjEgdG8gZ2VuZXJhbGl6ZSB0aGUgY29kZQpzb3J0KE0yWzIxLC0yMV0pICU+JSAgCiAgYXMuZGF0YS5mcmFtZSAlPiUgCiAgYG5hbWVzPC1gKCdjb3JyZWxhdGlvbicpICU+JQogIGdncGxvdChhZXMoeCA9IHJlb3JkZXIocm93Lm5hbWVzKC4pLCAtY29ycmVsYXRpb24pLCB5ID0gY29ycmVsYXRpb24sIGZpbGwgPSBjb3JyZWxhdGlvbikpICsgCiAgZ2VvbV9iYXIoc3RhdD0naWRlbnRpdHknLCBjb2xvdXIgPSAnYmxhY2snKSArIHNjYWxlX2ZpbGxfY29udGludW91cyhndWlkZSA9IEZBTFNFKSArIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSAgYygtLjE1LC4yNSkpICsKICBsYWJzKHRpdGxlID0gJ0lxdWl0b3NcbiBDb3JyZWxhdGlvbnMnLCB4ID0gTlVMTCwgeSA9IE5VTEwpICsgY29vcmRfZmxpcCgpIC0+IGNvcjIKCmdyaWQuYXJyYW5nZShjb3IxLCBjb3IyLCBucm93ID0gMSkKYGBgCgoKYGBge3J9CnByZXByb2Nlc3NEYXRhIDwtIGZ1bmN0aW9uKGRhdGFfcGF0aCwgbGFiZWxzX3BhdGggPSBOVUxMKQp7CiAgIyBsb2FkIGRhdGEgCiAgZGYgPC0gcmVhZC5jc3YoZGF0YV9wYXRoKQogIAogICMgZmVhdHVyZXMgd2Ugd2FudAogIGZlYXR1cmVzID0gYygicmVhbmFseXNpc19zcGVjaWZpY19odW1pZGl0eV9nX3Blcl9rZyIsICJyZWFuYWx5c2lzX2Rld19wb2ludF90ZW1wX2siLAogICAgICAgICAgICAgICAic3RhdGlvbl9hdmdfdGVtcF9jIiwgInN0YXRpb25fbWluX3RlbXBfYyIpCiAgCiAgIyBmaWxsIG1pc3NpbmcgdmFsdWVzCiAgZGZbZmVhdHVyZXNdICU8PiUgbmEubG9jZihmcm9tTGFzdCA9IFRSVUUpIAogIAogICMgYWRkIGNpdHkgaWYgbGFiZWxzIGRhdGEgYXJlbid0IHByb3ZpZGVkCiAgaWYgKGlzLm51bGwobGFiZWxzX3BhdGgpKSBmZWF0dXJlcyAlPD4lIGMoImNpdHkiLCAieWVhciIsICJ3ZWVrb2Z5ZWFyIikKICAKICAjIHNlbGVjdCBmZWF0dXJlcyB3ZSB3YW50CiAgZGYgPC0gZGZbZmVhdHVyZXNdCiAgCiAgIyBhZGQgbGFiZWxzIHRvIGRhdGFmcmFtZQogIGlmICghaXMubnVsbChsYWJlbHNfcGF0aCkpIGRmICU8PiUgY2JpbmQocmVhZC5jc3YobGFiZWxzX3BhdGgpKQogIAogICMgZmlsdGVyIGJ5IGNpdHkKICBkZl9zaiA8LSBmaWx0ZXIoZGYsIGNpdHkgPT0gJ3NqJykKICBkZl9pcSA8LSBmaWx0ZXIoZGYsIGNpdHkgPT0gJ2lxJykKICAKICAjIHJldHVybiBhIGxpc3Qgd2l0aCB0aGUgMiBkYXRhIGZyYW1lcyAKICByZXR1cm4obGlzdChkZl9zaiwgZGZfaXEpKQp9CgoKI3ByZXByb2Nlc3MgZmlsZXMKcHJlcHJvY2Vzc0RhdGEoZGF0YV9wYXRoID0gJ2Rlbmd1ZV9mZWF0dXJlc190cmFpbi5jc3YnLCBsYWJlbHNfcGF0aCA9ICdkZW5ndWVfbGFiZWxzX3RyYWluLmNzdicpIC0+IHRyYWlucwpzal90cmFpbiA8LSB0cmFpbnNbWzFdXTsgaXFfdHJhaW4gPC0gYXMuZGF0YS5mcmFtZSh0cmFpbnNbMl0pCgpzdW1tYXJ5KHNqX3RyYWluKQpzdW1tYXJ5KGlxX3RyYWluKQpgYGAKCgpgYGB7cn0KI3NwbGl0IGludG8gdHJhaW4gYW5kIHRlc3QKc2pfdHJhaW5fc3VidHJhaW4gPC0gaGVhZChzal90cmFpbiwgODAwKQpzal90cmFpbl9zdWJ0ZXN0ICA8LSB0YWlsKHNqX3RyYWluLCBucm93KHNqX3RyYWluKSAtIDgwMCkKCmlxX3RyYWluX3N1YnRyYWluIDwtIGhlYWQoaXFfdHJhaW4sIDQwMCkKaXFfdHJhaW5fc3VidGVzdCAgPC0gdGFpbChpcV90cmFpbiwgbnJvdyhzal90cmFpbikgLSA0MDApCmBgYAoKCmBgYHtyfQojbmVnYXRpdmUgYmlub21pYWwgbW9kZWwgcmVwbGljYXRpb24KCgptYWUgPC0gZnVuY3Rpb24oZXJyb3IpIHJldHVybihtZWFuKGFicyhlcnJvcikpICkKCmdldF9ic3RfbW9kZWwgPC0gZnVuY3Rpb24odHJhaW4sIHRlc3QpCnsKICAKICAjIFN0ZXAgMTogc3BlY2lmeSB0aGUgZm9ybSBvZiB0aGUgbW9kZWwKICBmb3JtIDwtICJ0b3RhbF9jYXNlcyB+IDEgKwogICAgICAgICAgICByZWFuYWx5c2lzX3NwZWNpZmljX2h1bWlkaXR5X2dfcGVyX2tnICsKICAgICAgICAgICAgcmVhbmFseXNpc19kZXdfcG9pbnRfdGVtcF9rICsgCiAgICAgICAgICAgIHN0YXRpb25fYXZnX3RlbXBfYyArCiAgICAgICAgICAgIHN0YXRpb25fbWluX3RlbXBfYyIKICAKICBncmlkID0gMTAgXihzZXEoLTgsIC0zLDEpKQogIAogIGJlc3RfYWxwaGEgPSBjKCkKICBiZXN0X3Njb3JlID0gMTAwMAogIAogICMgU3RlcCAyOiBGaW5kIHRoZSBiZXN0IGh5cGVyIHBhcmFtZXRlciwgYWxwaGEKICBmb3IgKGkgaW4gZ3JpZCkKICB7CiAgICBtb2RlbCA9IGdsbS5uYihmb3JtdWxhID0gZm9ybSwKICAgICAgICAgICAgICAgICAgIGRhdGEgPSB0cmFpbiwKICAgICAgICAgICAgICAgICAgIGluaXQudGhldGEgPSBpKQogICAgCiAgICByZXN1bHRzIDwtICBwcmVkaWN0KG1vZGVsLCB0ZXN0KQogICAgc2NvcmUgICA8LSAgbWFlKHRlc3QkdG90YWxfY2FzZXMgLSByZXN1bHRzKQogICAgCiAgICBpZiAoc2NvcmUgPCBiZXN0X3Njb3JlKSB7CiAgICAgIGJlc3RfYWxwaGEgPC0gaQogICAgICBiZXN0X3Njb3JlIDwtIHNjb3JlCiAgICAgIGNhdCgnXG5iZXN0IHNjb3JlID0gJywgYmVzdF9zY29yZSwgJ1x0d2l0aCBhbHBoYSA9ICcsIGJlc3RfYWxwaGEpCiAgICB9CiAgfQogIAogICMgU3RlcCAzOiByZWZpdCBvbiBlbnRpcmUgZGF0YXNldAogIGNvbWJpbmVkIDwtIHJiaW5kKHRyYWluLCB0ZXN0KQogIGNvbWJpbmVkX21vZGVsID0gZ2xtLm5iKGZvcm11bGE9Zm9ybSwKICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gY29tYmluZWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgaW5pdC50aGV0YSA9IGJlc3RfYWxwaGEpCiAgCiAgcmV0dXJuIChjb21iaW5lZF9tb2RlbCkKfQpzal9tb2RlbCA8LSBnZXRfYnN0X21vZGVsKHNqX3RyYWluX3N1YnRyYWluLCBzal90cmFpbl9zdWJ0ZXN0KQppcV9tb2RlbCA8LSBnZXRfYnN0X21vZGVsKGlxX3RyYWluX3N1YnRyYWluLCBpcV90cmFpbl9zdWJ0ZXN0KQpgYGAKCgpgYGB7cn0KI3Bsb3Qgc2FuIGp1YW4KCnNqX3RyYWluJGZpdHRlZCA9IHByZWRpY3Qoc2pfbW9kZWwsIHNqX3RyYWluLCB0eXBlID0gJ3Jlc3BvbnNlJykKc2pfdHJhaW4gJT4lIAogIG11dGF0ZShpbmRleCA9IGFzLm51bWVyaWMocm93Lm5hbWVzKC4pKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gaW5kZXgpKSArIGdndGl0bGUoIlNhbiBKdWFuIikgKwogIGdlb21fbGluZShhZXMoeSA9IHRvdGFsX2Nhc2VzLCBjb2xvdXIgPSAidG90YWxfY2FzZXMiKSkgKyAKICBnZW9tX2xpbmUoYWVzKHkgPSBmaXR0ZWQsIGNvbG91ciA9ICJmaXR0ZWQiKSkKYGBgCgoKYGBge3J9CiNwbG90IElxdWl0b3MKaXFfdHJhaW4kZml0dGVkID0gcHJlZGljdChpcV9tb2RlbCwgaXFfdHJhaW4sIHR5cGUgPSAncmVzcG9uc2UnKQppcV90cmFpbiAlPiUgCiAgbXV0YXRlKGluZGV4ID0gYXMubnVtZXJpYyhyb3cubmFtZXMoLikpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBpbmRleCkpICsgZ2d0aXRsZSgiSXF1aXRvcyIpICsgCiAgZ2VvbV9saW5lKGFlcyh5ID0gdG90YWxfY2FzZXMsIGNvbG91ciA9ICJ0b3RhbF9jYXNlcyIpKSArIAogIGdlb21fbGluZShhZXMoeSA9IGZpdHRlZCwgY29sb3VyID0gImZpdHRlZCIpKQpgYGAKCgpgYGB7cn0KI3N1Ym1pdCBwcmVkaWN0aW9ucwp0ZXN0cyA8LSBwcmVwcm9jZXNzRGF0YSgnZGVuZ3VlX2ZlYXR1cmVzX3Rlc3QuY3N2JykKc2pfdGVzdCA8LSB0ZXN0c1tbMV1dOyBpcV90ZXN0IDwtIHRlc3RzW1syXV0KCnNqX3Rlc3QkcHJlZGljdGVkID0gcHJlZGljdChzal9tb2RlbCAsIHNqX3Rlc3QsIHR5cGUgPSAncmVzcG9uc2UnKQppcV90ZXN0JHByZWRpY3RlZCA9IHByZWRpY3QoaXFfbW9kZWwgLCBpcV90ZXN0LCB0eXBlID0gJ3Jlc3BvbnNlJykKCnN1Ym1pc3Npb25zID0gcmVhZC5jc3YoJ3N1Ym1pc3Npb25fZm9ybWF0LmNzdicpCmlubmVyX2pvaW4oc3VibWlzc2lvbnMsIHJiaW5kKHNqX3Rlc3QsaXFfdGVzdCkpICU+JQogIGRwbHlyOjpzZWxlY3QoY2l0eSwgeWVhciwgd2Vla29meWVhciwgdG90YWxfY2FzZXMgPSBwcmVkaWN0ZWQpIC0+CiAgcHJlZGljdGlvbnMKCnByZWRpY3Rpb25zJHRvdGFsX2Nhc2VzICU8PiUgcm91bmQoKQp3cml0ZS5jc3YocHJlZGljdGlvbnMsICduZWdiaW5vbWlhbHByZWRpY3Rpb25zLmNzdicsIHJvdy5uYW1lcyA9IEZBTFNFKQpgYGAKCgpgYGB7cn0KI3RpbWUgc2VyaWVzIHBsb3QgCgpzai50czwtdHMoc2pfdHJhaW5fZmVhdHVyZXMkdG90YWxfY2FzZXMsIGZyZXF1ZW5jeT01Miwgc3RhcnQ9YygxOTkwLCAxOCkpCnBsb3Qoc2oudHMpCgppcS50czwtdHMoaXFfdHJhaW5fZmVhdHVyZXMkdG90YWxfY2FzZXMsIGZyZXF1ZW5jeT01Miwgc3RhcnQ9YygyMDAwLCAyNikpCnBsb3QoaXEudHMpCgoKI3RyYWluIGFuZCB0ZXN0IHNldHMKc2oudHJhaW4udHM8LXdpbmRvdyhzai50cywgZW5kPWMoMjAwNCwzNykpCnNqLnRlc3QudHM8LXdpbmRvdyhzai50cyxzdGFydD1jKDIwMDQsMzgpKQoKaXEudHJhaW4udHM8LXdpbmRvdyhpcS50cywgZW5kPWMoMjAwOCwyNykpCmlxLnRlc3QudHM8LXdpbmRvdyhpcS50cyxzdGFydD1jKDIwMDgsMjgpKQpgYGAKCgpgYGB7cn0KI25ldXJhbCBuZXR3b3JrIG1vZGVscwoKc2ouZml0Lm5uZXQ8LW5uZXRhcihzai50cmFpbi50cykKc2ouZml0Lm5uZXQKCgppcS5maXQubm5ldDwtbm5ldGFyKGlxLnRyYWluLnRzKQppcS5maXQubm5ldAoKI25ldXJhbCBuZXQgZm9yZWNhc3QKCnNqLmZjYXN0Lm5uZXQ8LWZvcmVjYXN0KHNqLmZpdC5ubmV0LGg9MjYwKQpwbG90KHNqLmZjYXN0Lm5uZXQpIApsaW5lcyhzai50ZXN0LnRzLCBjb2w9InJlZCIpICAKbGVnZW5kKCJ0b3ByaWdodCIsbHR5PTEsY29sPWMoInJlZCIsImJsdWUiKSxjKCJhY3R1YWwgdmFsdWVzIiwiZm9yZWNhc3QiKSkKCgppcS5mY2FzdC5ubmV0PC1mb3JlY2FzdChpcS5maXQubm5ldCxoPTE1NikKcGxvdChpcS5mY2FzdC5ubmV0KSAKbGluZXMoaXEudGVzdC50cywgY29sPSJyZWQiKSAgCmxlZ2VuZCgidG9wcmlnaHQiLGx0eT0xLGNvbD1jKCJyZWQiLCJibHVlIiksYygiYWN0dWFsIHZhbHVlcyIsImZvcmVjYXN0IikpCgojYWNjdXJhY3kKYWNjLnNqLm5uZXQgPC0gYWNjdXJhY3koc2ouZmNhc3Qubm5ldCwgc2oudGVzdC50cykKYWNjLnNqLm5uZXQKCgp0c2Rpc3BsYXkocmVzaWR1YWxzKHNqLmZjYXN0Lm5uZXQpKQoKCmFjYy5pcS5ubmV0IDwtIGFjY3VyYWN5KGlxLmZjYXN0Lm5uZXQsaXEudGVzdC50cykKYWNjLmlxLm5uZXQKCnRzZGlzcGxheShyZXNpZHVhbHMoaXEuZmNhc3Qubm5ldCkpCgojc29sdXRpb25zIGZvciBuZXVyYWwgbmV0IG1vZGVsCk5ORVRfc2pfc29sPWRhdGEuZnJhbWUoZGVuc3ViZm9ybWF0WzE6MjYwLCAtNF0sdG90YWxfY2FzZXM9cm91bmQoc2ouZmNhc3Qubm5ldCRtZWFuKSkKTk5FVF9pcV9zb2w9ZGF0YS5mcmFtZShkZW5zdWJmb3JtYXRbMjYxOjQxNiwtNF0sdG90YWxfY2FzZXM9cm91bmQoaXEuZmNhc3Qubm5ldCRtZWFuKSkKCkRlbmd1ZV9OTkVUX3NvbHV0aW9uPWJpbmRfcm93cyhOTkVUX3NqX3NvbCxOTkVUX2lxX3NvbCkKd3JpdGUuY3N2KERlbmd1ZV9OTkVUX3NvbHV0aW9uLGZpbGU9IkRlbmd1ZV9OTkVUX3ByZWRpY3Rpb25zLmNzdiIscm93Lm5hbWVzPUYpCmBgYAoKCmBgYHtyfQojYXJpbWEgbW9kZWwgU0oKCnNqLmFyaW1hPUFyaW1hKHNqLnRyYWluLnRzLG9yZGVyPWMoMSwxLDIpLHNlYXNvbmFsPWMoMCwwLDApKQpzai5hcmltYQpzai5hcmltYS5mYz1mb3JlY2FzdChzai5hcmltYSxoPTI2MCkKYWNjLnNqLmFyaW1hID0gYWNjdXJhY3koc2ouYXJpbWEuZmMsc2oudGVzdC50cykKYWNjLnNqLmFyaW1hCnBsb3Qoc2ouYXJpbWEuZmMpCnRzZGlzcGxheShyZXNpZHVhbHMoc2ouYXJpbWEuZmMpKQoKCiNhcmltYSBtb2RsZSBJUQppcS5hcmltYT1BcmltYShpcS50cmFpbi50cyxvcmRlcj1jKDAsMSwyKSxzZWFzb25hbD1jKDAsMCwxKSkKaXEuYXJpbWEKaXEuYXJpbWEuZmM9Zm9yZWNhc3QoaXEuYXJpbWEsaD0xNTYpCmFjYy5pcS5hcmltYSA9IGFjY3VyYWN5KGlxLmFyaW1hLmZjLGlxLnRlc3QudHMpCmFjYy5pcS5hcmltYQpwbG90KGlxLmFyaW1hLmZjKQp0c2Rpc3BsYXkocmVzaWR1YWxzKGlxLmFyaW1hLmZjKSkKCiNzb2x1dGlvbiBmb3IgYXJpbWEgbW9kZWwKQXJpbWFfc2pfc29sPWRhdGEuZnJhbWUoZGVuc3ViZm9ybWF0WzE6MjYwLC00XSx0b3RhbF9jYXNlcz1yb3VuZChzai5hcmltYS5mYyRtZWFuKSkKQXJpbWFfaXFfc29sPWRhdGEuZnJhbWUoZGVuc3ViZm9ybWF0WzI2MTo0MTYsLTRdLHRvdGFsX2Nhc2VzPXJvdW5kKGlxLmFyaW1hLmZjJG1lYW4pKQoKRGVuZ3VlX0FyaW1hX3NvbHV0aW9uPWJpbmRfcm93cyhBcmltYV9zal9zb2wsQXJpbWFfaXFfc29sKQoKd3JpdGUuY3N2KERlbmd1ZV9BcmltYV9zb2x1dGlvbixmaWxlPSJEZW5ndWVfQXJpbWFfcHJlZGljdGlvbnMuY3N2Iixyb3cubmFtZXM9RikKCmBgYAoK