# baseline 의 RMSE : 
# 출도착지를 geohash lvl 5 로 나누어, 출도착지+시간별(1), 출발지+시간별(2), 시간별(3), 전체평속(4) 을 준비한다.
# traget 경로가 들어오면, (1), (2), (3), (4) 에서 존재하는 값만 취하여 평균값을 취한다.
# traget 경로의 distance 를 위의 평균 속도 값으로 나누어, trip duration 을 예상한다.
# Try2 도 위의 아이디어와 비슷하다.
# geohash 를 기준으로 경로별 특성값과 동승자수 요일, 계절(month) 의 feature 를 더하여 GLM 으로 시도한다. 
library(data.table)
library(dplyr)
library(magrittr)
library(tidyr)
library(stringi)
library(stringr)
library(xda)
library(caret)
library(doMC)
library(dummy)
library(leaflet)
library(rgdal)
library(lubridate)
library(gridExtra)
library(ggmap)
library(geohash)
train <- fread("/Users/CA/Downloads/NY_taxi/train.csv", na.strings = "")

Read 43.2% of 1458644 rows
Read 64.4% of 1458644 rows
Read 85.7% of 1458644 rows
Read 86.4% of 1458644 rows
Read 1458644 rows and 11 (of 11) columns from 0.187 GB file in 00:00:08
test <- fread("/Users/CA/Downloads/NY_taxi/test.csv", na.strings = "")

Read 56.0% of 625134 rows
Read 625134 rows and 9 (of 9) columns from 0.066 GB file in 00:00:04
numSummary(train)
numSummary(test)
charSummary(train)
charSummary(test)
coord2distance <- Vectorize(function(lng1, lat1, lng2, lat2) {
  rad_per_deg = pi / 180
  rkm = 6371
  rm = rkm * 1000
  
  dlng_rad = (lng2 - lng1) * rad_per_deg
  dlat_rad = (lat2 - lat1) * rad_per_deg
  
  lng1_rad = lng1 * rad_per_deg
  lat1_rad = lat1 * rad_per_deg
  lng2_rad = lng2 * rad_per_deg
  lat2_rad = lat2 * rad_per_deg
  
  a = sin(dlng_rad/2)**2 + cos(lng1_rad) * cos(lng2_rad) * sin(dlat_rad/2)**2
  c = 2 * atan2(sqrt(a), sqrt(1-a))
  
  return(rm * c)
})
refine <- function(df) {
  df %<>%
    mutate(pickup_datetime   = ymd_hms(pickup_datetime), 
           dropoff_datetime  = ymd_hms(dropoff_datetime),
           distance          = coord2distance( pickup_longitude, pickup_latitude, dropoff_longitude, dropoff_latitude),
           speed             = round(distance / 1000 / (trip_duration/3600),2)) %>%
    mutate(pickup_wday = wday(pickup_datetime, label = T), pickup_hour = hour(pickup_datetime)) %>%
    mutate(dropoff_wday = wday(dropoff_datetime, label = T), dropoff_hour = hour(dropoff_datetime)) %>%
    mutate(pickup_month = month(pickup_datetime, label = T), dropoff_month = month(dropoff_datetime)) %>%
    mutate_each_(funs(as.factor(.)), c("vendor_id", "store_and_fwd_flag", "passenger_count"))
  
  return(df)
}
train %<>% refine
summary(train)
      id            vendor_id  pickup_datetime               dropoff_datetime              passenger_count  
 Length:1458644     1:678342   Min.   :2016-01-01 00:00:17   Min.   :2016-01-01 00:03:31   1      :1033540  
 Class :character   2:780302   1st Qu.:2016-02-17 16:46:04   1st Qu.:2016-02-17 17:05:32   2      : 210318  
 Mode  :character              Median :2016-04-01 17:19:40   Median :2016-04-01 17:35:12   5      :  78088  
                               Mean   :2016-04-01 10:10:24   Mean   :2016-04-01 10:26:24   3      :  59896  
                               3rd Qu.:2016-05-15 03:56:08   3rd Qu.:2016-05-15 04:10:51   6      :  48333  
                               Max.   :2016-06-30 23:59:39   Max.   :2016-07-01 23:02:03   4      :  28404  
                                                                                           (Other):     65  
 pickup_longitude pickup_latitude dropoff_longitude dropoff_latitude store_and_fwd_flag trip_duration        distance     
 Min.   :-121.9   Min.   :34.4    Min.   :-121.9    Min.   :32.2     N:1450599          Min.   :      1   Min.   :     0  
 1st Qu.: -74.0   1st Qu.:40.7    1st Qu.: -74.0    1st Qu.:40.7     Y:   8045          1st Qu.:    397   1st Qu.:   848  
 Median : -74.0   Median :40.8    Median : -74.0    Median :40.8                        Median :    662   Median :  1531  
 Mean   : -74.0   Mean   :40.8    Mean   : -74.0    Mean   :40.8                        Mean   :    959   Mean   :  2876  
 3rd Qu.: -74.0   3rd Qu.:40.8    3rd Qu.: -74.0    3rd Qu.:40.8                        3rd Qu.:   1075   3rd Qu.:  2847  
 Max.   : -61.3   Max.   :51.9    Max.   : -61.3    Max.   :43.9                        Max.   :3526282   Max.   :851968  
                                                                                                                          
     speed      pickup_wday     pickup_hour   dropoff_wday    dropoff_hour   pickup_month    dropoff_month 
 Min.   :   0   Sun  :195366   Min.   : 0.0   Sun  :197224   Min.   : 0.0   Mar    :256189   Min.   :1.00  
 1st Qu.:   6   Mon  :187418   1st Qu.: 9.0   Mon  :187433   1st Qu.: 9.0   Apr    :251645   1st Qu.:2.00  
 Median :  10   Tues :202749   Median :14.0   Tues :202518   Median :14.0   May    :248487   Median :4.00  
 Mean   :  11   Wed  :210136   Mean   :13.6   Wed  :209790   Mean   :13.6   Feb    :238300   Mean   :3.52  
 3rd Qu.:  15   Thurs:218574   3rd Qu.:19.0   Thurs:217746   3rd Qu.:19.0   Jun    :234316   3rd Qu.:5.00  
 Max.   :8619   Fri  :223533   Max.   :23.0   Fri  :223031   Max.   :23.0   Jan    :229707   Max.   :7.00  
                Sat  :220868                  Sat  :220902                  (Other):     0                 
# plot#1 : 시간별 운행량 변화 
p1 <- ggplot(data = train, mapping = aes(x = pickup_wday, group = vendor_id, fill = vendor_id)) + 
  geom_bar(position="identity", alpha=0.7) + 
  theme_bw()
p2 <- ggplot(data = train, mapping = aes(x = pickup_hour, group = vendor_id, fill = vendor_id)) + 
  geom_bar(position="identity", alpha=0.7) + 
  theme_bw()
p3 <- ggplot(data = train, mapping = aes(x = pickup_month, group = vendor_id, fill = vendor_id)) + 
  geom_bar(position="identity", alpha=0.7) + 
  theme_bw()
grid.arrange(p1, p2, p3, nrow = 2, ncol = 2)

# plot#2 : 시간별 운행 속도 변화 
## Q3. 요일/시간대별 평균 속도 
##      #=> 요일별 평균속도는 월/일/토 , 화/금 , 수/목 순으로 좋음 
##      #=> 시간별 평균속도는 퇴근시간대보다 일과시간이 나쁘고, 새벽시간대가 제일 좋음 
## Q4. 요일/시간대별 평균 운행 직선 거리 
##      #=> 요일별 평균 운행 직선 거리는 월/일 이 상대적으로 길고, 기타 요일에는 대동소이 
##      #=> 시간별 평균 운행 직선 거리는 평균속도 패턴과 동일.
avg_speed_by_wday    <- train %>% group_by(pickup_wday) %>% summarise(avg_speed_by_wday = mean(speed))
avg_distance_by_wday <- train %>% group_by(pickup_wday) %>% summarise(avg_distance_by_wday = mean(distance))
avg_speed_by_hour    <- train %>% group_by(pickup_hour) %>% summarise(avg_speed_by_hour = mean(speed))
avg_distance_by_hour <- train %>% group_by(pickup_hour) %>% summarise(avg_distance_by_hour = mean(distance))
daily_data  <- merge(avg_speed_by_wday, avg_distance_by_wday, by = "pickup_wday")
hourly_data <- merge(avg_speed_by_hour, avg_distance_by_hour, by = "pickup_hour") 
p1 <- ggplot(data = daily_data, aes(x = pickup_wday)) +
  geom_line(aes(y = avg_speed_by_wday, colour = "speed", group = 1)) +
  geom_line(aes(y = round(avg_distance_by_wday/250 ,2), colour = "distance", group = 1)) +
  scale_y_continuous(sec.axis = sec_axis(~.*250, name = "Distance ( meter )")) +
  labs(y = "Speed ( km/h )")
p2 <- ggplot(data = hourly_data, aes(x = pickup_hour)) +
  geom_line(aes(y = avg_speed_by_hour, colour = "speed")) +
  geom_line(aes(y = round(avg_distance_by_hour/250 ,2), colour = "distance")) +
  scale_y_continuous(sec.axis = sec_axis(~.*250, name = "Distance ( meter )")) +
  labs(y = "Speed ( km/h )")
multiplot(p1, p2, cols = 1)

#p1 <- ggplot(data = hourly_data, aes(pickup_hour, avg_speed_by_hour)) + geom_line() + geom_point()
#p2 <- ggplot(data = hourly_data, aes(pickup_hour, avg_distance_by_hour)) + geom_line() + geom_point()
#grid.arrange(p1, p2, nrow = 2, ncol = 1)
#head(merge(avg_speed_by_wday, avg_distance_by_wday, by = "pickup_wday") %>% arrange(desc(avg_distance_by_wday)), n = 7)
#head(merge(avg_speed_by_hour, avg_distance_by_hour, by = "pickup_hour") %>% arrange(desc(avg_speed_by_hour)), n = 24)
# plot 3 : 탑승자 수 
table(train$passenger_count)

      0       1       2       3       4       5       6       7       8       9 
     60 1033540  210318   59896   28404   78088   48333       3       1       1 
train$passenger_count <- as.numeric(as.character(train$passenger_count))
avg_speed_by_pc <- train %>% 
                     filter(passenger_count %in% c(1,2,3,4,5,6)) %>% 
                     group_by(passenger_count) %>% 
                     summarise(avg_speed = mean(speed), avg_distnace = mean(distance))
avg_pc_by_hour <- train %>% 
                     filter(passenger_count %in% c(1,2,3,4,5,6)) %>% 
                     group_by(pickup_hour) %>% 
                     summarise(avg_pc = mean(passenger_count))
p1 <- ggplot(data = avg_speed_by_pc, aes(x = passenger_count)) +
  geom_line(aes(y = avg_speed, colour = "speed")) +
  geom_line(aes(y = round(avg_distnace/260 ,2), colour = "distance")) +
  scale_y_continuous(sec.axis = sec_axis(~.*260, name = "Distance ( meter )")) +
  labs(y = "Speed ( km/h )")
p2 <- ggplot(data = avg_pc_by_hour, aes(x = pickup_hour)) +
  geom_line(aes(y = avg_pc)) + labs(y = "average passenger count")
multiplot(p1, p2, cols = 1)

LS0tCnRpdGxlOiAiTllfVFJZMiIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CiMgYmFzZWxpbmUg7J2YIFJNU0UgOiAKIyDstpzrj4TssKnsp4DrpbwgZ2VvaGFzaCBsdmwgNSDroZwg64KY64iE7Ja0LCDstpzrj4TssKnsp4Ar7Iuc6rCE67OEKDEpLCDstpzrsJzsp4Ar7Iuc6rCE67OEKDIpLCDsi5zqsITrs4QoMyksIOyghOyytO2PieyGjSg0KSDsnYQg7KSA67mE7ZWc64ukLgojIHRyYWdldCDqsr3roZzqsIAg65Ok7Ja07Jik66m0LCAoMSksICgyKSwgKDMpLCAoNCkg7JeQ7IScIOyhtOyerO2VmOuKlCDqsJLrp4wg7Leo7ZWY7JesIO2Pieq3oOqwkuydhCDst6jtlZzri6QuCiMgdHJhZ2V0IOqyveuhnOydmCBkaXN0YW5jZSDrpbwg7JyE7J2YIO2Pieq3oCDsho3rj4Qg6rCS7Jy866GcIOuCmOuIhOyWtCwgdHJpcCBkdXJhdGlvbiDsnYQg7JiI7IOB7ZWc64ukLgpgYGAKCmBgYHtyfQojIFRyeTIg64+EIOychOydmCDslYTsnbTrlJTslrTsmYAg67mE7Iq37ZWY64ukLgojIGdlb2hhc2gg66W8IOq4sOykgOycvOuhnCDqsr3roZzrs4Qg7Yq57ISx6rCS6rO8IOuPmeyKueyekOyImCDsmpTsnbwsIOqzhOygiChtb250aCkg7J2YIGZlYXR1cmUg66W8IOuNlO2VmOyXrCBHTE0g7Jy866GcIOyLnOuPhO2VnOuLpC4gCmBgYAoKYGBge3J9CmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShkcGx5cikKbGlicmFyeShtYWdyaXR0cikKbGlicmFyeSh0aWR5cikKbGlicmFyeShzdHJpbmdpKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkoeGRhKQpsaWJyYXJ5KGNhcmV0KQpsaWJyYXJ5KGRvTUMpCmxpYnJhcnkoZHVtbXkpCmxpYnJhcnkobGVhZmxldCkKbGlicmFyeShyZ2RhbCkKbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KGdnbWFwKQpsaWJyYXJ5KGdlb2hhc2gpCmBgYAoKYGBge3J9CnRyYWluIDwtIGZyZWFkKCIvVXNlcnMvQ0EvRG93bmxvYWRzL05ZX3RheGkvdHJhaW4uY3N2IiwgbmEuc3RyaW5ncyA9ICIiKQp0ZXN0IDwtIGZyZWFkKCIvVXNlcnMvQ0EvRG93bmxvYWRzL05ZX3RheGkvdGVzdC5jc3YiLCBuYS5zdHJpbmdzID0gIiIpCmBgYAoKYGBge3J9Cm51bVN1bW1hcnkodHJhaW4pCm51bVN1bW1hcnkodGVzdCkKYGBgCgpgYGB7cn0KY2hhclN1bW1hcnkodHJhaW4pCmNoYXJTdW1tYXJ5KHRlc3QpCmBgYAoKYGBge3J9CmNvb3JkMmRpc3RhbmNlIDwtIFZlY3Rvcml6ZShmdW5jdGlvbihsbmcxLCBsYXQxLCBsbmcyLCBsYXQyKSB7CiAgcmFkX3Blcl9kZWcgPSBwaSAvIDE4MAogIHJrbSA9IDYzNzEKICBybSA9IHJrbSAqIDEwMDAKICAKICBkbG5nX3JhZCA9IChsbmcyIC0gbG5nMSkgKiByYWRfcGVyX2RlZwogIGRsYXRfcmFkID0gKGxhdDIgLSBsYXQxKSAqIHJhZF9wZXJfZGVnCiAgCiAgbG5nMV9yYWQgPSBsbmcxICogcmFkX3Blcl9kZWcKICBsYXQxX3JhZCA9IGxhdDEgKiByYWRfcGVyX2RlZwogIGxuZzJfcmFkID0gbG5nMiAqIHJhZF9wZXJfZGVnCiAgbGF0Ml9yYWQgPSBsYXQyICogcmFkX3Blcl9kZWcKICAKICBhID0gc2luKGRsbmdfcmFkLzIpKioyICsgY29zKGxuZzFfcmFkKSAqIGNvcyhsbmcyX3JhZCkgKiBzaW4oZGxhdF9yYWQvMikqKjIKICBjID0gMiAqIGF0YW4yKHNxcnQoYSksIHNxcnQoMS1hKSkKICAKICByZXR1cm4ocm0gKiBjKQp9KQpgYGAKCmBgYHtyfQpyZWZpbmUgPC0gZnVuY3Rpb24oZGYpIHsKICBkZiAlPD4lCiAgICBtdXRhdGUocGlja3VwX2RhdGV0aW1lICAgPSB5bWRfaG1zKHBpY2t1cF9kYXRldGltZSksIAogICAgICAgICAgIGRyb3BvZmZfZGF0ZXRpbWUgID0geW1kX2htcyhkcm9wb2ZmX2RhdGV0aW1lKSwKICAgICAgICAgICBkaXN0YW5jZSAgICAgICAgICA9IGNvb3JkMmRpc3RhbmNlKCBwaWNrdXBfbG9uZ2l0dWRlLCBwaWNrdXBfbGF0aXR1ZGUsIGRyb3BvZmZfbG9uZ2l0dWRlLCBkcm9wb2ZmX2xhdGl0dWRlKSwKICAgICAgICAgICBzcGVlZCAgICAgICAgICAgICA9IHJvdW5kKGRpc3RhbmNlIC8gMTAwMCAvICh0cmlwX2R1cmF0aW9uLzM2MDApLDIpKSAlPiUKICAgIG11dGF0ZShwaWNrdXBfd2RheSA9IHdkYXkocGlja3VwX2RhdGV0aW1lLCBsYWJlbCA9IFQpLCBwaWNrdXBfaG91ciA9IGhvdXIocGlja3VwX2RhdGV0aW1lKSkgJT4lCiAgICBtdXRhdGUoZHJvcG9mZl93ZGF5ID0gd2RheShkcm9wb2ZmX2RhdGV0aW1lLCBsYWJlbCA9IFQpLCBkcm9wb2ZmX2hvdXIgPSBob3VyKGRyb3BvZmZfZGF0ZXRpbWUpKSAlPiUKICAgIG11dGF0ZShwaWNrdXBfbW9udGggPSBtb250aChwaWNrdXBfZGF0ZXRpbWUsIGxhYmVsID0gVCksIGRyb3BvZmZfbW9udGggPSBtb250aChkcm9wb2ZmX2RhdGV0aW1lKSkgJT4lCiAgICBtdXRhdGVfZWFjaF8oZnVucyhhcy5mYWN0b3IoLikpLCBjKCJ2ZW5kb3JfaWQiLCAic3RvcmVfYW5kX2Z3ZF9mbGFnIiwgInBhc3Nlbmdlcl9jb3VudCIpKQogIAogIHJldHVybihkZikKfQoKdHJhaW4gJTw+JSByZWZpbmUKc3VtbWFyeSh0cmFpbikKYGBgCgpgYGB7cn0KIyBwbG90IzEgOiDsi5zqsITrs4Qg7Jq07ZaJ65+JIOuzgO2ZlCAKCnAxIDwtIGdncGxvdChkYXRhID0gdHJhaW4sIG1hcHBpbmcgPSBhZXMoeCA9IHBpY2t1cF93ZGF5LCBncm91cCA9IHZlbmRvcl9pZCwgZmlsbCA9IHZlbmRvcl9pZCkpICsgCiAgZ2VvbV9iYXIocG9zaXRpb249ImlkZW50aXR5IiwgYWxwaGE9MC43KSArIAogIHRoZW1lX2J3KCkKcDIgPC0gZ2dwbG90KGRhdGEgPSB0cmFpbiwgbWFwcGluZyA9IGFlcyh4ID0gcGlja3VwX2hvdXIsIGdyb3VwID0gdmVuZG9yX2lkLCBmaWxsID0gdmVuZG9yX2lkKSkgKyAKICBnZW9tX2Jhcihwb3NpdGlvbj0iaWRlbnRpdHkiLCBhbHBoYT0wLjcpICsgCiAgdGhlbWVfYncoKQpwMyA8LSBnZ3Bsb3QoZGF0YSA9IHRyYWluLCBtYXBwaW5nID0gYWVzKHggPSBwaWNrdXBfbW9udGgsIGdyb3VwID0gdmVuZG9yX2lkLCBmaWxsID0gdmVuZG9yX2lkKSkgKyAKICBnZW9tX2Jhcihwb3NpdGlvbj0iaWRlbnRpdHkiLCBhbHBoYT0wLjcpICsgCiAgdGhlbWVfYncoKQoKZ3JpZC5hcnJhbmdlKHAxLCBwMiwgcDMsIG5yb3cgPSAyLCBuY29sID0gMikKYGBgCgpgYGB7ciwgaW5jbHVkZT1GQUxTRX0KbXVsdGlwbG90IDwtIGZ1bmN0aW9uKC4uLiwgcGxvdGxpc3Q9TlVMTCwgZmlsZSwgY29scz0xLCBsYXlvdXQ9TlVMTCkgewogIGxpYnJhcnkoZ3JpZCkKCiAgIyBNYWtlIGEgbGlzdCBmcm9tIHRoZSAuLi4gYXJndW1lbnRzIGFuZCBwbG90bGlzdAogIHBsb3RzIDwtIGMobGlzdCguLi4pLCBwbG90bGlzdCkKCiAgbnVtUGxvdHMgPSBsZW5ndGgocGxvdHMpCgogICMgSWYgbGF5b3V0IGlzIE5VTEwsIHRoZW4gdXNlICdjb2xzJyB0byBkZXRlcm1pbmUgbGF5b3V0CiAgaWYgKGlzLm51bGwobGF5b3V0KSkgewogICAgIyBNYWtlIHRoZSBwYW5lbAogICAgIyBuY29sOiBOdW1iZXIgb2YgY29sdW1ucyBvZiBwbG90cwogICAgIyBucm93OiBOdW1iZXIgb2Ygcm93cyBuZWVkZWQsIGNhbGN1bGF0ZWQgZnJvbSAjIG9mIGNvbHMKICAgIGxheW91dCA8LSBtYXRyaXgoc2VxKDEsIGNvbHMgKiBjZWlsaW5nKG51bVBsb3RzL2NvbHMpKSwKICAgICAgICAgICAgICAgICAgICBuY29sID0gY29scywgbnJvdyA9IGNlaWxpbmcobnVtUGxvdHMvY29scykpCiAgfQoKIGlmIChudW1QbG90cz09MSkgewogICAgcHJpbnQocGxvdHNbWzFdXSkKCiAgfSBlbHNlIHsKICAgICMgU2V0IHVwIHRoZSBwYWdlCiAgICBncmlkLm5ld3BhZ2UoKQogICAgcHVzaFZpZXdwb3J0KHZpZXdwb3J0KGxheW91dCA9IGdyaWQubGF5b3V0KG5yb3cobGF5b3V0KSwgbmNvbChsYXlvdXQpKSkpCgogICAgIyBNYWtlIGVhY2ggcGxvdCwgaW4gdGhlIGNvcnJlY3QgbG9jYXRpb24KICAgIGZvciAoaSBpbiAxOm51bVBsb3RzKSB7CiAgICAgICMgR2V0IHRoZSBpLGogbWF0cml4IHBvc2l0aW9ucyBvZiB0aGUgcmVnaW9ucyB0aGF0IGNvbnRhaW4gdGhpcyBzdWJwbG90CiAgICAgIG1hdGNoaWR4IDwtIGFzLmRhdGEuZnJhbWUod2hpY2gobGF5b3V0ID09IGksIGFyci5pbmQgPSBUUlVFKSkKCiAgICAgIHByaW50KHBsb3RzW1tpXV0sIHZwID0gdmlld3BvcnQobGF5b3V0LnBvcy5yb3cgPSBtYXRjaGlkeCRyb3csCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGF5b3V0LnBvcy5jb2wgPSBtYXRjaGlkeCRjb2wpKQogICAgfQogIH0KfQpgYGAKCmBgYHtyfQojIHBsb3QjMiA6IOyLnOqwhOuzhCDsmrTtlokg7IaN64+EIOuzgO2ZlCAKCiMjIFEzLiDsmpTsnbwv7Iuc6rCE64yA67OEIO2Pieq3oCDsho3rj4QgCiMjICAgICAgIz0+IOyalOydvOuzhCDtj4nqt6Dsho3rj4TripQg7JuUL+ydvC/thqAgLCDtmZQv6riIICwg7IiYL+uqqSDsiJzsnLzroZwg7KKL7J2MIAojIyAgICAgICM9PiDsi5zqsITrs4Qg7Y+J6reg7IaN64+E64qUIO2HtOq3vOyLnOqwhOuMgOuztOuLpCDsnbzqs7zsi5zqsITsnbQg64KY7IGY6rOgLCDsg4jrsr3si5zqsITrjIDqsIAg7KCc7J28IOyii+ydjCAKIyMgUTQuIOyalOydvC/si5zqsITrjIDrs4Qg7Y+J6regIOyatO2WiSDsp4HshKAg6rGw66asIAojIyAgICAgICM9PiDsmpTsnbzrs4Qg7Y+J6regIOyatO2WiSDsp4HshKAg6rGw66as64qUIOyblC/snbwg7J20IOyDgeuMgOyggeycvOuhnCDquLjqs6AsIOq4sO2DgCDsmpTsnbzsl5DripQg64yA64+Z7IaM7J20IAojIyAgICAgICM9PiDsi5zqsITrs4Qg7Y+J6regIOyatO2WiSDsp4HshKAg6rGw66as64qUIO2Pieq3oOyGjeuPhCDtjKjthLTqs7wg64+Z7J28LgoKYXZnX3NwZWVkX2J5X3dkYXkgICAgPC0gdHJhaW4gJT4lIGdyb3VwX2J5KHBpY2t1cF93ZGF5KSAlPiUgc3VtbWFyaXNlKGF2Z19zcGVlZF9ieV93ZGF5ID0gbWVhbihzcGVlZCkpCmF2Z19kaXN0YW5jZV9ieV93ZGF5IDwtIHRyYWluICU+JSBncm91cF9ieShwaWNrdXBfd2RheSkgJT4lIHN1bW1hcmlzZShhdmdfZGlzdGFuY2VfYnlfd2RheSA9IG1lYW4oZGlzdGFuY2UpKQoKYXZnX3NwZWVkX2J5X2hvdXIgICAgPC0gdHJhaW4gJT4lIGdyb3VwX2J5KHBpY2t1cF9ob3VyKSAlPiUgc3VtbWFyaXNlKGF2Z19zcGVlZF9ieV9ob3VyID0gbWVhbihzcGVlZCkpCmF2Z19kaXN0YW5jZV9ieV9ob3VyIDwtIHRyYWluICU+JSBncm91cF9ieShwaWNrdXBfaG91cikgJT4lIHN1bW1hcmlzZShhdmdfZGlzdGFuY2VfYnlfaG91ciA9IG1lYW4oZGlzdGFuY2UpKQoKZGFpbHlfZGF0YSAgPC0gbWVyZ2UoYXZnX3NwZWVkX2J5X3dkYXksIGF2Z19kaXN0YW5jZV9ieV93ZGF5LCBieSA9ICJwaWNrdXBfd2RheSIpCmhvdXJseV9kYXRhIDwtIG1lcmdlKGF2Z19zcGVlZF9ieV9ob3VyLCBhdmdfZGlzdGFuY2VfYnlfaG91ciwgYnkgPSAicGlja3VwX2hvdXIiKSAKCnAxIDwtIGdncGxvdChkYXRhID0gZGFpbHlfZGF0YSwgYWVzKHggPSBwaWNrdXBfd2RheSkpICsKICBnZW9tX2xpbmUoYWVzKHkgPSBhdmdfc3BlZWRfYnlfd2RheSwgY29sb3VyID0gInNwZWVkIiwgZ3JvdXAgPSAxKSkgKwogIGdlb21fbGluZShhZXMoeSA9IHJvdW5kKGF2Z19kaXN0YW5jZV9ieV93ZGF5LzI1MCAsMiksIGNvbG91ciA9ICJkaXN0YW5jZSIsIGdyb3VwID0gMSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoc2VjLmF4aXMgPSBzZWNfYXhpcyh+LioyNTAsIG5hbWUgPSAiRGlzdGFuY2UgKCBtZXRlciApIikpICsKICBsYWJzKHkgPSAiU3BlZWQgKCBrbS9oICkiKQoKcDIgPC0gZ2dwbG90KGRhdGEgPSBob3VybHlfZGF0YSwgYWVzKHggPSBwaWNrdXBfaG91cikpICsKICBnZW9tX2xpbmUoYWVzKHkgPSBhdmdfc3BlZWRfYnlfaG91ciwgY29sb3VyID0gInNwZWVkIikpICsKICBnZW9tX2xpbmUoYWVzKHkgPSByb3VuZChhdmdfZGlzdGFuY2VfYnlfaG91ci8yNTAgLDIpLCBjb2xvdXIgPSAiZGlzdGFuY2UiKSkgKwogIHNjYWxlX3lfY29udGludW91cyhzZWMuYXhpcyA9IHNlY19heGlzKH4uKjI1MCwgbmFtZSA9ICJEaXN0YW5jZSAoIG1ldGVyICkiKSkgKwogIGxhYnMoeSA9ICJTcGVlZCAoIGttL2ggKSIpCgptdWx0aXBsb3QocDEsIHAyLCBjb2xzID0gMSkKCiNwMSA8LSBnZ3Bsb3QoZGF0YSA9IGhvdXJseV9kYXRhLCBhZXMocGlja3VwX2hvdXIsIGF2Z19zcGVlZF9ieV9ob3VyKSkgKyBnZW9tX2xpbmUoKSArIGdlb21fcG9pbnQoKQojcDIgPC0gZ2dwbG90KGRhdGEgPSBob3VybHlfZGF0YSwgYWVzKHBpY2t1cF9ob3VyLCBhdmdfZGlzdGFuY2VfYnlfaG91cikpICsgZ2VvbV9saW5lKCkgKyBnZW9tX3BvaW50KCkKI2dyaWQuYXJyYW5nZShwMSwgcDIsIG5yb3cgPSAyLCBuY29sID0gMSkKCiNoZWFkKG1lcmdlKGF2Z19zcGVlZF9ieV93ZGF5LCBhdmdfZGlzdGFuY2VfYnlfd2RheSwgYnkgPSAicGlja3VwX3dkYXkiKSAlPiUgYXJyYW5nZShkZXNjKGF2Z19kaXN0YW5jZV9ieV93ZGF5KSksIG4gPSA3KQojaGVhZChtZXJnZShhdmdfc3BlZWRfYnlfaG91ciwgYXZnX2Rpc3RhbmNlX2J5X2hvdXIsIGJ5ID0gInBpY2t1cF9ob3VyIikgJT4lIGFycmFuZ2UoZGVzYyhhdmdfc3BlZWRfYnlfaG91cikpLCBuID0gMjQpCmBgYAoKYGBge3J9CiMgcGxvdCAzIDog7YOR7Iq57J6QIOyImCAKdGFibGUodHJhaW4kcGFzc2VuZ2VyX2NvdW50KQp0cmFpbiRwYXNzZW5nZXJfY291bnQgPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIodHJhaW4kcGFzc2VuZ2VyX2NvdW50KSkKCmF2Z19zcGVlZF9ieV9wYyA8LSB0cmFpbiAlPiUgCiAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihwYXNzZW5nZXJfY291bnQgJWluJSBjKDEsMiwzLDQsNSw2KSkgJT4lIAogICAgICAgICAgICAgICAgICAgICBncm91cF9ieShwYXNzZW5nZXJfY291bnQpICU+JSAKICAgICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlKGF2Z19zcGVlZCA9IG1lYW4oc3BlZWQpLCBhdmdfZGlzdG5hY2UgPSBtZWFuKGRpc3RhbmNlKSkKCmF2Z19wY19ieV9ob3VyIDwtIHRyYWluICU+JSAKICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHBhc3Nlbmdlcl9jb3VudCAlaW4lIGMoMSwyLDMsNCw1LDYpKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KHBpY2t1cF9ob3VyKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZShhdmdfcGMgPSBtZWFuKHBhc3Nlbmdlcl9jb3VudCkpCgpwMSA8LSBnZ3Bsb3QoZGF0YSA9IGF2Z19zcGVlZF9ieV9wYywgYWVzKHggPSBwYXNzZW5nZXJfY291bnQpKSArCiAgZ2VvbV9saW5lKGFlcyh5ID0gYXZnX3NwZWVkLCBjb2xvdXIgPSAic3BlZWQiKSkgKwogIGdlb21fbGluZShhZXMoeSA9IHJvdW5kKGF2Z19kaXN0bmFjZS8yNjAgLDIpLCBjb2xvdXIgPSAiZGlzdGFuY2UiKSkgKwogIHNjYWxlX3lfY29udGludW91cyhzZWMuYXhpcyA9IHNlY19heGlzKH4uKjI2MCwgbmFtZSA9ICJEaXN0YW5jZSAoIG1ldGVyICkiKSkgKwogIGxhYnMoeSA9ICJTcGVlZCAoIGttL2ggKSIpCgpwMiA8LSBnZ3Bsb3QoZGF0YSA9IGF2Z19wY19ieV9ob3VyLCBhZXMoeCA9IHBpY2t1cF9ob3VyKSkgKwogIGdlb21fbGluZShhZXMoeSA9IGF2Z19wYykpICsgbGFicyh5ID0gImF2ZXJhZ2UgcGFzc2VuZ2VyIGNvdW50IikKCm11bHRpcGxvdChwMSwgcDIsIGNvbHMgPSAxKQpgYGAKCgpgYGB7cn0KYGBg