noaa <- readLines('http://www.ssd.noaa.gov/PS/TROP/2018/adt/archive.html')
library(stringr)
library(readr)
pattern = 'http[^\"]+text[^\"]+\\.txt'
urls <- str_extract(noaa,pattern)
urls <- urls[!is.na(urls)]
header1 <- c("date", "time", "intensity_ci", "intensity_mslp", "intensity_vmax","tno_fnl","tno_adj","tno_ini","constrnt","wkng","rpd","temp_ctr","temp_mean","scene","est_rmw","mw","lat","lon","mthd","sat","vza","comments")
widths1 <- c(9,7,5,7,6,5,4,4,10,5,5,8,7,8,7,6,8,8,6,9,5,NA)
header2 = header <- c("date", "time", "intensity_ci", "intensity_mslp", "intensity_mslpplat", "intensity_vmax","tno_fnl","tno_adj","tno_ini","constrnt","wkng","rpd","temp_ctr","temp_mean","scene","est_rmw","mw","lat","lon","mthd","sat","vza","comments")
widths2 <- c(9,7,5,7,8,6,5,4,4,10,5,5,8,7,8,7,6,8,8,6,9,5,NA)
first <- T
q <- 1
#REMOVE
for(url in urls) {
  print(q)
  q <- q + 1
  lines <- readLines(url)
  name <- strsplit(substr(url,52,10000), "-")[[1]][1]
  # check if "BiasAdj" in line 4 -- if so, need an extra column!
  if(length(grep("BiasAdj",lines))) {
    widths <- widths2
    h <- header2
  } else {
    widths <- widths1
    h <- header1
  }
  
  if(url=="http://www.ssd.noaa.gov/PS/TROP/DATA/2018/adt/text/17P-list.txt") {
    # Special rule for this file due to incorrect negative MSLP values offsetting columns
    for(i in 5:55) {
      lines[i] = paste0(substr(lines[i],1,22), substr(lines[i],24,nchar(lines[i])), sep='')
    }
  }
  lines <- lines[5:(length(lines)-3)]
  
  data <- read_fwf(paste0(lines,collapse="\n"), fwf_widths(widths, col_names=h), na="N/A")
  data$est_rmw <- as.character(data$est_rmw)
  data$typhoon_name <- name
  if(first) {
    first = F
    typhoon <- data
  } else {
    typhoon <- bind_rows(typhoon, data)
  }
}
write.csv(typhoon,"../../Data/shipping/typhoon.csv", row.names=F)
library(plotly)
library(dplyr)
# load data
df <- read.csv("../../Data/Shipping/shipping_dataset.csv", stringsAsFactors = F, na="NA")
df_ships <- read.csv("../../Data/Shipping/index.csv", stringsAsFactors = F, na="NA")
df_ports <- read.csv("../../Data/Shipping/port_dataset.csv", stringsAsFactors = F, na="NA")
typhoon <- read.csv("../../Data/Shipping/typhoon.csv", stringsAsFactors = F)
# rename lat and lon to avoid conflicts
df_ports <- df_ports %>% rename(port_lat=lat, port_lon=lon)
# Join in ships and ports
df <- left_join(df, df_ships)
Joining, by = "imo"
df <- df %>% filter(!imo == 9528029 | reported_destination == "AU ADL")
df <- left_join(df,df_ports, by=c("left_port"="port"))
df <- df %>% rename(left_lat=port_lat, left_lon=port_lon)
df <- left_join(df,df_ports, by=c("arrive_port"="port"))
df <- df %>% rename(arrive_lat=port_lat, arrive_lon=port_lon)
# fix dates
df$last_update = as.POSIXct(df$last_update, tz="UTC",origin="1970-01-01")
df$left_time = as.POSIXct(df$left_time, tz="UTC",origin="1970-01-01")
df$arrive_time = as.POSIXct(df$arrive_time, tz="UTC",origin="1970-01-01")
# Fix typhoon dates
typhoon$date <- as.POSIXct(paste(typhoon$date,typhoon$time), format="%Y%b%d %H%M%S", tz="UTC", origin="1970-01-01")
# Fix typhoon longitude -- they have lon * -1 in the data
typhoon$lon <- typhoon$lon * -1
typhoon_all <- typhoon
# filter to dates in sample
typhoon <- typhoon %>% filter(date > as.POSIXct("2018-08-30", tz="UTC"))
df <- df %>% filter(last_update > as.POSIXct("2018-08-30", tz="UTC"))
geo <- list(
  showland = TRUE,
  showlakes = TRUE,
  showcountries = TRUE,
  showocean = TRUE,
  countrywidth = 0.5,
  landcolor = toRGB("grey90"),
  lakecolor = toRGB("aliceblue"),
  oceancolor = toRGB("aliceblue"),
  projection = list(
    type = 'orthographic',  # detailed at https://plot.ly/r/reference/#layout-geo-projection
    rotation = list(
      lon = 100,
      lat = 1,
      roll = 0
    )
  ),
  lonaxis = list(
    showgrid = TRUE,
    gridcolor = toRGB("gray40"),
    gridwidth = 0.5
  ),
  lataxis = list(
    showgrid = TRUE,
    gridcolor = toRGB("gray40"),
    gridwidth = 0.5
  )
)
library(RColorBrewer)
# plot with boats, ports, and typhoons
palette = brewer.pal(8, "Dark2")[c(1,8,3,2)]
p <- plot_geo(colors=palette) %>%
  add_markers(data=df_ports, x = ~port_lon, y = ~port_lat, color = "Port") %>%
  add_markers(data=df[df$run == 1,], x = ~lon, y = ~lat, color = ~ship_type,
              text=~paste('Ship name',shipname)) %>%
  add_markers(data=typhoon[typhoon$date > as.POSIXct("2018-08-31 00:00:00", tz="UTC") & typhoon$date < as.POSIXct("2018-09-01 00:00:00", tz="UTC"),], x = ~lon, y = ~lat, color="TYPHOON", colors=toRGB("red"), text=~paste("Name", typhoon_name)) %>%
   layout(
    showlegend = TRUE, geo = geo,
    title = 'Singaporean owned container and tanker ships, August 31, 2018'
  )
p
# plot with boats, ports, and typhoons
palette = brewer.pal(8, "Dark2")[c(1,3,2)]
p <- plot_geo(colors=palette) %>%
  add_markers(data=df[df$run == 14,], x = ~lon, y = ~lat, color = ~ship_type,
              text=~paste('Ship name',shipname)) %>%
  add_markers(data=typhoon[typhoon$typhoon_name == "JEBI_Y",], x = ~lon, y = ~lat, color="Typhoon Jebi", text=~paste("Name", typhoon_name, "</br>Time: ", date)) %>%
   layout(
    showlegend = TRUE, geo = geo,
    title = 'Singaporean container/tanker ships, September 4, 2018, evening'
  )
p
world1 <- sf::st_as_sf(map('world', plot = FALSE, fill = TRUE))

p <- ggplot(data = world1) + 
  geom_sf() + 
  geom_point(data = df, aes(x = lon, y = lat, frame=run))
ggplotly(p) %>%
   animation_opts(
    1500, easing = "elastic", redraw = FALSE
  )
# distance between two geo coordinates
library(geosphere)

# Linear interpolation for matching hurricane locations
linear_interp <- function(from, to, mid, d_from, d_to) {
  d_from * (mid - from) / (to - from) + d_to * (to - mid) / (to - from)
}

# for line in df
# line_last_update, line$lat, line_lon
# typhoon %>% group_by(typhoon_name) %>%

df$date_only <- as.Date(df$last_update, "UTC")
typhoon$ty_date_only <- as.Date(typhoon$date, "UTC")
typhoon <- typhoon %>% rename(ty_lat=lat, ty_lon=lon, ty_date=date)

first <- TRUE
for(d in unique(df$date_only)) {
  df2 <- df[df$date_only == d,]
  ty2 <- typhoon[typhoon$ty_date_only == d,]
  dfm <- as.matrix(df2[,c("lon","lat")])
  tym <- as.matrix(ty2[,c("ty_lon","ty_lat")])
  mat <- distm(dfm, tym, fun = distVincentyEllipsoid)
  df2 <- cbind(df2, ty2[max.col(-mat),])
  if(first) {
    df3 <- df2
    first <- FALSE
  } else {
    df3 <- bind_rows(df3, df2)
  }
}
write.csv(df3,"../../Data/shipping/combined.csv", row.names=F)
summary(fit)

Call:
glm(formula = delayed ~ (typhoon_100 + typhoon_500 + typhoon_1000):typhoon_intensity, 
    family = binomial, data = df3)

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-0.5770  -0.4648  -0.4648  -0.4648   2.2974  

Coefficients: (1 not defined because of singularities)
                                         Estimate Std. Error  z value Pr(>|z|)    
(Intercept)                               -2.1709     0.0144 -150.788   <2e-16 ***
typhoon_100:typhoon_intensity(0,34]       -0.2838     0.6195   -0.458   0.6469    
typhoon_100:typhoon_intensity(34,53]      -0.2609     0.4545   -0.574   0.5660    
typhoon_100:typhoon_intensity(53,92.4]    -7.7742    72.4631   -0.107   0.9146    
typhoon_100:typhoon_intensity(92.4,150]        NA         NA       NA       NA    
typhoon_500:typhoon_intensity(0,34]       -0.1955     0.1779   -1.099   0.2717    
typhoon_500:typhoon_intensity(34,53]       0.3250     0.1949    1.668   0.0953 .  
typhoon_500:typhoon_intensity(53,92.4]     0.2382     0.2517    0.946   0.3440    
typhoon_500:typhoon_intensity(92.4,150]   -0.5626     0.7576   -0.743   0.4577    
typhoon_1000:typhoon_intensity(0,34]       0.1935     0.1001    1.932   0.0533 .  
typhoon_1000:typhoon_intensity(34,53]      0.1373     0.1468    0.935   0.3496    
typhoon_1000:typhoon_intensity(53,92.4]    0.1409     0.1610    0.875   0.3814    
typhoon_1000:typhoon_intensity(92.4,150]   0.1686     0.1889    0.892   0.3722    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 37178  on 55846  degrees of freedom
Residual deviance: 37157  on 55835  degrees of freedom
  (7204 observations deleted due to missingness)
AIC: 37181

Number of Fisher Scoring iterations: 8

OLD BELOW

library(readr)
library(dplyr)
library(ggplot2)

url_csv <- 'https://raw.githubusercontent.com/d4tagirl/R-Ladies-growth-maps/master/rladies.csv'
rladies <- read_csv(url(url_csv)) %>% 
  select(-1)
rladies2 <- rladies
rladies$frame <- 1
rladies2$frame <- 2
rladies2$lat <- rladies2$lat + 5
rladies3 <- rbind(rladies,rladies2)
rladies2$frame <- 3
rladies2$lat <- rladies2$lat + 5
rladies3 <- rbind(rladies3,rladies2)
rladies2$frame <- 4
rladies2$lat <- rladies2$lat + 5
rladies3 <- rbind(rladies3,rladies2)
rladies2$frame <- 5
rladies2$lat <- rladies2$lat + 5
rladies3 <- rbind(rladies3,rladies2)

library(plotly)

g <- list(resolution = 50,
          showland = TRUE,
          showlakes = TRUE,
          landcolor = toRGB("grey80"),
          countrycolor = toRGB("grey80"),
          lakecolor = toRGB("white"),
          projection = list(type = "equirectangular"),
          coastlinewidth = 2,
          lataxis = list(
            range = c(20, 60),
            showgrid = TRUE,
            tickmode = "linear",
            dtick = 10
          ),
          lonaxis = list(
            range = c(-100, 20),
            showgrid = TRUE,
            tickmode = "linear",
            dtick = 20
          ))

plot_geo() %>%
  add_markers(data = rladies3,
              x = ~lon,
              y = ~lat,
              frame = ~frame,
              color=I("purple"),
              hoverinfo = "text",
              text = ~paste('city: ', location,
                            '<br /> created: ', created_at,
                            '<br /> followers: ', followers)) %>%
  layout(geo = g) %>%
  animation_opts(
    1000, easing = "elastic", redraw = FALSE
  )

maps, maptools, sf, ggplot @v3, rgeos

world1 <- sf::st_as_sf(map('world', plot = FALSE, fill = TRUE))

p <- ggplot(data = world1) + 
  geom_sf() + 
  geom_point(data = rladies3, aes(x = lon, y = lat, frame=frame))
ggplotly(p) %>%
   animation_opts(
    1500, easing = "elastic", redraw = FALSE
  )
# ANIMATION: https://github.com/plotly/plotly.js/blob/master/src/plots/animation_attributes.js
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpgYGB7ciB0eXBob29ucywgZXZhbD1GfQ0Kbm9hYSA8LSByZWFkTGluZXMoJ2h0dHA6Ly93d3cuc3NkLm5vYWEuZ292L1BTL1RST1AvMjAxOC9hZHQvYXJjaGl2ZS5odG1sJykNCmxpYnJhcnkoc3RyaW5ncikNCmxpYnJhcnkocmVhZHIpDQpwYXR0ZXJuID0gJ2h0dHBbXlwiXSt0ZXh0W15cIl0rXFwudHh0Jw0KdXJscyA8LSBzdHJfZXh0cmFjdChub2FhLHBhdHRlcm4pDQp1cmxzIDwtIHVybHNbIWlzLm5hKHVybHMpXQ0KaGVhZGVyMSA8LSBjKCJkYXRlIiwgInRpbWUiLCAiaW50ZW5zaXR5X2NpIiwgImludGVuc2l0eV9tc2xwIiwgImludGVuc2l0eV92bWF4IiwidG5vX2ZubCIsInRub19hZGoiLCJ0bm9faW5pIiwiY29uc3RybnQiLCJ3a25nIiwicnBkIiwidGVtcF9jdHIiLCJ0ZW1wX21lYW4iLCJzY2VuZSIsImVzdF9ybXciLCJtdyIsImxhdCIsImxvbiIsIm10aGQiLCJzYXQiLCJ2emEiLCJjb21tZW50cyIpDQp3aWR0aHMxIDwtIGMoOSw3LDUsNyw2LDUsNCw0LDEwLDUsNSw4LDcsOCw3LDYsOCw4LDYsOSw1LE5BKQ0KaGVhZGVyMiA9IGhlYWRlciA8LSBjKCJkYXRlIiwgInRpbWUiLCAiaW50ZW5zaXR5X2NpIiwgImludGVuc2l0eV9tc2xwIiwgImludGVuc2l0eV9tc2xwcGxhdCIsICJpbnRlbnNpdHlfdm1heCIsInRub19mbmwiLCJ0bm9fYWRqIiwidG5vX2luaSIsImNvbnN0cm50Iiwid2tuZyIsInJwZCIsInRlbXBfY3RyIiwidGVtcF9tZWFuIiwic2NlbmUiLCJlc3Rfcm13IiwibXciLCJsYXQiLCJsb24iLCJtdGhkIiwic2F0IiwidnphIiwiY29tbWVudHMiKQ0Kd2lkdGhzMiA8LSBjKDksNyw1LDcsOCw2LDUsNCw0LDEwLDUsNSw4LDcsOCw3LDYsOCw4LDYsOSw1LE5BKQ0KZmlyc3QgPC0gVA0KcSA8LSAxDQojUkVNT1ZFDQpmb3IodXJsIGluIHVybHMpIHsNCiAgcHJpbnQocSkNCiAgcSA8LSBxICsgMQ0KICBsaW5lcyA8LSByZWFkTGluZXModXJsKQ0KICBuYW1lIDwtIHN0cnNwbGl0KHN1YnN0cih1cmwsNTIsMTAwMDApLCAiLSIpW1sxXV1bMV0NCiAgIyBjaGVjayBpZiAiQmlhc0FkaiIgaW4gbGluZSA0IC0tIGlmIHNvLCBuZWVkIGFuIGV4dHJhIGNvbHVtbiENCiAgaWYobGVuZ3RoKGdyZXAoIkJpYXNBZGoiLGxpbmVzKSkpIHsNCiAgICB3aWR0aHMgPC0gd2lkdGhzMg0KICAgIGggPC0gaGVhZGVyMg0KICB9IGVsc2Ugew0KICAgIHdpZHRocyA8LSB3aWR0aHMxDQogICAgaCA8LSBoZWFkZXIxDQogIH0NCiAgDQogIGlmKHVybD09Imh0dHA6Ly93d3cuc3NkLm5vYWEuZ292L1BTL1RST1AvREFUQS8yMDE4L2FkdC90ZXh0LzE3UC1saXN0LnR4dCIpIHsNCiAgICAjIFNwZWNpYWwgcnVsZSBmb3IgdGhpcyBmaWxlIGR1ZSB0byBpbmNvcnJlY3QgbmVnYXRpdmUgTVNMUCB2YWx1ZXMgb2Zmc2V0dGluZyBjb2x1bW5zDQogICAgZm9yKGkgaW4gNTo1NSkgew0KICAgICAgbGluZXNbaV0gPSBwYXN0ZTAoc3Vic3RyKGxpbmVzW2ldLDEsMjIpLCBzdWJzdHIobGluZXNbaV0sMjQsbmNoYXIobGluZXNbaV0pKSwgc2VwPScnKQ0KICAgIH0NCiAgfQ0KICBsaW5lcyA8LSBsaW5lc1s1OihsZW5ndGgobGluZXMpLTMpXQ0KICANCiAgZGF0YSA8LSByZWFkX2Z3ZihwYXN0ZTAobGluZXMsY29sbGFwc2U9IlxuIiksIGZ3Zl93aWR0aHMod2lkdGhzLCBjb2xfbmFtZXM9aCksIG5hPSJOL0EiKQ0KICBkYXRhJGVzdF9ybXcgPC0gYXMuY2hhcmFjdGVyKGRhdGEkZXN0X3JtdykNCiAgZGF0YSR0eXBob29uX25hbWUgPC0gbmFtZQ0KICBpZihmaXJzdCkgew0KICAgIGZpcnN0ID0gRg0KICAgIHR5cGhvb24gPC0gZGF0YQ0KICB9IGVsc2Ugew0KICAgIHR5cGhvb24gPC0gYmluZF9yb3dzKHR5cGhvb24sIGRhdGEpDQogIH0NCn0NCndyaXRlLmNzdih0eXBob29uLCIuLi8uLi9EYXRhL3NoaXBwaW5nL3R5cGhvb24uY3N2Iiwgcm93Lm5hbWVzPUYpDQpgYGANCg0KYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9DQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoZHBseXIpDQoNCiMgbG9hZCBkYXRhDQpkZiA8LSByZWFkLmNzdigiLi4vLi4vRGF0YS9TaGlwcGluZy9zaGlwcGluZ19kYXRhc2V0LmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGLCBuYT0iTkEiKQ0KZGZfc2hpcHMgPC0gcmVhZC5jc3YoIi4uLy4uL0RhdGEvU2hpcHBpbmcvaW5kZXguY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEYsIG5hPSJOQSIpDQpkZl9wb3J0cyA8LSByZWFkLmNzdigiLi4vLi4vRGF0YS9TaGlwcGluZy9wb3J0X2RhdGFzZXQuY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEYsIG5hPSJOQSIpDQp0eXBob29uIDwtIHJlYWQuY3N2KCIuLi8uLi9EYXRhL1NoaXBwaW5nL3R5cGhvb24uY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpDQoNCiMgcmVuYW1lIGxhdCBhbmQgbG9uIHRvIGF2b2lkIGNvbmZsaWN0cw0KZGZfcG9ydHMgPC0gZGZfcG9ydHMgJT4lIHJlbmFtZShwb3J0X2xhdD1sYXQsIHBvcnRfbG9uPWxvbikNCg0KIyBKb2luIGluIHNoaXBzIGFuZCBwb3J0cw0KZGYgPC0gbGVmdF9qb2luKGRmLCBkZl9zaGlwcykNCmRmIDwtIGRmICU+JSBmaWx0ZXIoIWltbyA9PSA5NTI4MDI5IHwgcmVwb3J0ZWRfZGVzdGluYXRpb24gPT0gIkFVIEFETCIpDQpkZiA8LSBsZWZ0X2pvaW4oZGYsZGZfcG9ydHMsIGJ5PWMoImxlZnRfcG9ydCI9InBvcnQiKSkNCmRmIDwtIGRmICU+JSByZW5hbWUobGVmdF9sYXQ9cG9ydF9sYXQsIGxlZnRfbG9uPXBvcnRfbG9uKQ0KZGYgPC0gbGVmdF9qb2luKGRmLGRmX3BvcnRzLCBieT1jKCJhcnJpdmVfcG9ydCI9InBvcnQiKSkNCmRmIDwtIGRmICU+JSByZW5hbWUoYXJyaXZlX2xhdD1wb3J0X2xhdCwgYXJyaXZlX2xvbj1wb3J0X2xvbikNCg0KIyBmaXggZGF0ZXMNCmRmJGxhc3RfdXBkYXRlID0gYXMuUE9TSVhjdChkZiRsYXN0X3VwZGF0ZSwgdHo9IlVUQyIsb3JpZ2luPSIxOTcwLTAxLTAxIikNCmRmJGxlZnRfdGltZSA9IGFzLlBPU0lYY3QoZGYkbGVmdF90aW1lLCB0ej0iVVRDIixvcmlnaW49IjE5NzAtMDEtMDEiKQ0KZGYkYXJyaXZlX3RpbWUgPSBhcy5QT1NJWGN0KGRmJGFycml2ZV90aW1lLCB0ej0iVVRDIixvcmlnaW49IjE5NzAtMDEtMDEiKQ0KDQojIEZpeCB0eXBob29uIGRhdGVzDQp0eXBob29uJGRhdGUgPC0gYXMuUE9TSVhjdChwYXN0ZSh0eXBob29uJGRhdGUsdHlwaG9vbiR0aW1lKSwgZm9ybWF0PSIlWSViJWQgJUglTSVTIiwgdHo9IlVUQyIsIG9yaWdpbj0iMTk3MC0wMS0wMSIpDQojIEZpeCB0eXBob29uIGxvbmdpdHVkZSAtLSB0aGV5IGhhdmUgbG9uICogLTEgaW4gdGhlIGRhdGENCnR5cGhvb24kbG9uIDwtIHR5cGhvb24kbG9uICogLTENCg0KdHlwaG9vbl9hbGwgPC0gdHlwaG9vbg0KIyBmaWx0ZXIgdG8gZGF0ZXMgaW4gc2FtcGxlDQp0eXBob29uIDwtIHR5cGhvb24gJT4lIGZpbHRlcihkYXRlID4gYXMuUE9TSVhjdCgiMjAxOC0wOC0zMCIsIHR6PSJVVEMiKSkNCg0KDQoNCmRmIDwtIGRmICU+JSBmaWx0ZXIobGFzdF91cGRhdGUgPiBhcy5QT1NJWGN0KCIyMDE4LTA4LTMwIiwgdHo9IlVUQyIpKQ0KDQpnZW8gPC0gbGlzdCgNCiAgc2hvd2xhbmQgPSBUUlVFLA0KICBzaG93bGFrZXMgPSBUUlVFLA0KICBzaG93Y291bnRyaWVzID0gVFJVRSwNCiAgc2hvd29jZWFuID0gVFJVRSwNCiAgY291bnRyeXdpZHRoID0gMC41LA0KICBsYW5kY29sb3IgPSB0b1JHQigiZ3JleTkwIiksDQogIGxha2Vjb2xvciA9IHRvUkdCKCJhbGljZWJsdWUiKSwNCiAgb2NlYW5jb2xvciA9IHRvUkdCKCJhbGljZWJsdWUiKSwNCiAgcHJvamVjdGlvbiA9IGxpc3QoDQogICAgdHlwZSA9ICdvcnRob2dyYXBoaWMnLCAgIyBkZXRhaWxlZCBhdCBodHRwczovL3Bsb3QubHkvci9yZWZlcmVuY2UvI2xheW91dC1nZW8tcHJvamVjdGlvbg0KICAgIHJvdGF0aW9uID0gbGlzdCgNCiAgICAgIGxvbiA9IDEwMCwNCiAgICAgIGxhdCA9IDEsDQogICAgICByb2xsID0gMA0KICAgICkNCiAgKSwNCiAgbG9uYXhpcyA9IGxpc3QoDQogICAgc2hvd2dyaWQgPSBUUlVFLA0KICAgIGdyaWRjb2xvciA9IHRvUkdCKCJncmF5NDAiKSwNCiAgICBncmlkd2lkdGggPSAwLjUNCiAgKSwNCiAgbGF0YXhpcyA9IGxpc3QoDQogICAgc2hvd2dyaWQgPSBUUlVFLA0KICAgIGdyaWRjb2xvciA9IHRvUkdCKCJncmF5NDAiKSwNCiAgICBncmlkd2lkdGggPSAwLjUNCiAgKQ0KKQ0KbGlicmFyeShSQ29sb3JCcmV3ZXIpDQoNCiMgcGxvdCB3aXRoIGJvYXRzLCBwb3J0cywgYW5kIHR5cGhvb25zDQpwYWxldHRlID0gYnJld2VyLnBhbCg4LCAiRGFyazIiKVtjKDEsOCwzLDIpXQ0KcCA8LSBwbG90X2dlbyhjb2xvcnM9cGFsZXR0ZSkgJT4lDQogIGFkZF9tYXJrZXJzKGRhdGE9ZGZfcG9ydHMsIHggPSB+cG9ydF9sb24sIHkgPSB+cG9ydF9sYXQsIGNvbG9yID0gIlBvcnQiKSAlPiUNCiAgYWRkX21hcmtlcnMoZGF0YT1kZltkZiRydW4gPT0gMSxdLCB4ID0gfmxvbiwgeSA9IH5sYXQsIGNvbG9yID0gfnNoaXBfdHlwZSwNCiAgICAgICAgICAgICAgdGV4dD1+cGFzdGUoJ1NoaXAgbmFtZScsc2hpcG5hbWUpKSAlPiUNCiAgYWRkX21hcmtlcnMoZGF0YT10eXBob29uW3R5cGhvb24kZGF0ZSA+IGFzLlBPU0lYY3QoIjIwMTgtMDgtMzEgMDA6MDA6MDAiLCB0ej0iVVRDIikgJiB0eXBob29uJGRhdGUgPCBhcy5QT1NJWGN0KCIyMDE4LTA5LTAxIDAwOjAwOjAwIiwgdHo9IlVUQyIpLF0sIHggPSB+bG9uLCB5ID0gfmxhdCwgY29sb3I9IlRZUEhPT04iLCBjb2xvcnM9dG9SR0IoInJlZCIpLCB0ZXh0PX5wYXN0ZSgiTmFtZSIsIHR5cGhvb25fbmFtZSkpICU+JQ0KICAgbGF5b3V0KA0KICAgIHNob3dsZWdlbmQgPSBUUlVFLCBnZW8gPSBnZW8sDQogICAgdGl0bGUgPSAnU2luZ2Fwb3JlYW4gb3duZWQgY29udGFpbmVyIGFuZCB0YW5rZXIgc2hpcHMsIEF1Z3VzdCAzMSwgMjAxOCcNCiAgKQ0KcA0KYGBgDQoNCmBgYHtyLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD04fQ0KIyBwbG90IHdpdGggYm9hdHMgYW5kIHR5cGhvb25zDQpwYWxldHRlID0gYnJld2VyLnBhbCg4LCAiRGFyazIiKVtjKDEsMywyKV0NCnAgPC0gcGxvdF9nZW8oY29sb3JzPXBhbGV0dGUpICU+JQ0KICBhZGRfbWFya2VycyhkYXRhPWRmW2RmJHJ1biA9PSAxNCxdLCB4ID0gfmxvbiwgeSA9IH5sYXQsIGNvbG9yID0gfnNoaXBfdHlwZSwNCiAgICAgICAgICAgICAgdGV4dD1+cGFzdGUoJ1NoaXAgbmFtZScsc2hpcG5hbWUpKSAlPiUNCiAgYWRkX21hcmtlcnMoZGF0YT10eXBob29uW3R5cGhvb24kdHlwaG9vbl9uYW1lID09ICJKRUJJX1kiLF0sIHggPSB+bG9uLCB5ID0gfmxhdCwgY29sb3I9IlR5cGhvb24gSmViaSIsIHRleHQ9fnBhc3RlKCJOYW1lIiwgdHlwaG9vbl9uYW1lLCAiPC9icj5UaW1lOiAiLCBkYXRlKSkgJT4lDQogICBsYXlvdXQoDQogICAgc2hvd2xlZ2VuZCA9IFRSVUUsIGdlbyA9IGdlbywNCiAgICB0aXRsZSA9ICdTaW5nYXBvcmVhbiBjb250YWluZXIvdGFua2VyIHNoaXBzLCBTZXB0ZW1iZXIgNCwgMjAxOCwgZXZlbmluZycNCiAgKQ0KcA0KYGBgDQoNCmBgYHtyIGFuaW1hdGVkX3NoaXBzfQ0Kd29ybGQxIDwtIHNmOjpzdF9hc19zZihtYXAoJ3dvcmxkJywgcGxvdCA9IEZBTFNFLCBmaWxsID0gVFJVRSkpDQoNCnAgPC0gZ2dwbG90KGRhdGEgPSB3b3JsZDEpICsgDQogIGdlb21fc2YoKSArIA0KICBnZW9tX3BvaW50KGRhdGEgPSBkZiwgYWVzKHggPSBsb24sIHkgPSBsYXQsIGZyYW1lPXJ1bikpDQpnZ3Bsb3RseShwKSAlPiUNCiAgIGFuaW1hdGlvbl9vcHRzKA0KICAgIDE1MDAsIGVhc2luZyA9ICJlbGFzdGljIiwgcmVkcmF3ID0gRkFMU0UNCiAgKQ0KYGBgDQoNCmBgYHtyLCBldmFsPUZ9DQojIGRpc3RhbmNlIGJldHdlZW4gdHdvIGdlbyBjb29yZGluYXRlcw0KbGlicmFyeShnZW9zcGhlcmUpDQoNCiMgTGluZWFyIGludGVycG9sYXRpb24gZm9yIG1hdGNoaW5nIGh1cnJpY2FuZSBsb2NhdGlvbnMNCmxpbmVhcl9pbnRlcnAgPC0gZnVuY3Rpb24oZnJvbSwgdG8sIG1pZCwgZF9mcm9tLCBkX3RvKSB7DQogIGRfZnJvbSAqIChtaWQgLSBmcm9tKSAvICh0byAtIGZyb20pICsgZF90byAqICh0byAtIG1pZCkgLyAodG8gLSBmcm9tKQ0KfQ0KDQojIGZvciBsaW5lIGluIGRmDQojIGxpbmVfbGFzdF91cGRhdGUsIGxpbmUkbGF0LCBsaW5lX2xvbg0KIyB0eXBob29uICU+JSBncm91cF9ieSh0eXBob29uX25hbWUpICU+JQ0KDQpkZiRkYXRlX29ubHkgPC0gYXMuRGF0ZShkZiRsYXN0X3VwZGF0ZSwgIlVUQyIpDQp0eXBob29uJHR5X2RhdGVfb25seSA8LSBhcy5EYXRlKHR5cGhvb24kZGF0ZSwgIlVUQyIpDQp0eXBob29uIDwtIHR5cGhvb24gJT4lIHJlbmFtZSh0eV9sYXQ9bGF0LCB0eV9sb249bG9uLCB0eV9kYXRlPWRhdGUpDQoNCmZpcnN0IDwtIFRSVUUNCmZvcihkIGluIHVuaXF1ZShkZiRkYXRlX29ubHkpKSB7DQogIGRmMiA8LSBkZltkZiRkYXRlX29ubHkgPT0gZCxdDQogIHR5MiA8LSB0eXBob29uW3R5cGhvb24kdHlfZGF0ZV9vbmx5ID09IGQsXQ0KICBkZm0gPC0gYXMubWF0cml4KGRmMlssYygibG9uIiwibGF0IildKQ0KICB0eW0gPC0gYXMubWF0cml4KHR5MlssYygidHlfbG9uIiwidHlfbGF0IildKQ0KICBtYXQgPC0gZGlzdG0oZGZtLCB0eW0sIGZ1biA9IGRpc3RWaW5jZW50eUVsbGlwc29pZCkNCiAgZGYyIDwtIGNiaW5kKGRmMiwgdHkyW21heC5jb2woLW1hdCksXSkNCiAgaWYoZmlyc3QpIHsNCiAgICBkZjMgPC0gZGYyDQogICAgZmlyc3QgPC0gRkFMU0UNCiAgfSBlbHNlIHsNCiAgICBkZjMgPC0gYmluZF9yb3dzKGRmMywgZGYyKQ0KICB9DQp9DQp3cml0ZS5jc3YoZGYzLCIuLi8uLi9EYXRhL3NoaXBwaW5nL2NvbWJpbmVkLmNzdiIsIHJvdy5uYW1lcz1GKQ0KDQpgYGANCg0KYGBge3J9DQojIGRpc3RhbmNlIGJldHdlZW4gdHdvIGdlbyBjb29yZGluYXRlcw0KbGlicmFyeShnZW9zcGhlcmUpDQoNCmRmMyA8LSByZWFkLmNzdigiLi4vLi4vRGF0YS9TaGlwcGluZy9jb21iaW5lZC5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gRikNCg0KZGYzJGRpc3RfdG9wb3J0IDwtIGRpc3RWaW5jZW50eUVsbGlwc29pZChhcy5tYXRyaXgoZGYzWyxjKCJsb24iLCJsYXQiKV0pLCBhcy5tYXRyaXgoZGYzWyxjKCJhcnJpdmVfbG9uIiwiYXJyaXZlX2xhdCIpXSkpDQpkZjMkZGlzdF9mcm9tcG9ydCA8LSBkaXN0VmluY2VudHlFbGxpcHNvaWQoYXMubWF0cml4KGRmM1ssYygibG9uIiwibGF0IildKSwgYXMubWF0cml4KGRmM1ssYygibGVmdF9sb24iLCJsZWZ0X2xhdCIpXSkpDQpkZjMkZGlzdF90eXBob29uIDwtIGRpc3RWaW5jZW50eUVsbGlwc29pZChhcy5tYXRyaXgoZGYzWyxjKCJsb24iLCJsYXQiKV0pLCBhcy5tYXRyaXgoZGYzWyxjKCJ0eV9sb24iLCJ0eV9sYXQiKV0pKQ0KDQpkZjMgPC0gZGYzICU+JQ0KICBhcnJhbmdlKGltbywgbGFzdF91cGRhdGUpICU+JQ0KICBncm91cF9ieShpbW8pICU+JQ0KICBtdXRhdGUoZGVsYXllZD1pZmVsc2UoYXJyaXZlX3RpbWU+bGFnKGFycml2ZV90aW1lKSAmIGFycml2ZV90aW1lID4gbGFzdF91cGRhdGUsMSwwKSkgJT4lDQogIHVuZ3JvdXAoKQ0KDQoNCg0KZGYzJHR5cGhvb25fMTAwID0gaWZlbHNlKGRmMyRkaXN0X3R5cGhvb248MTAwMDAwLDEsMCkNCmRmMyR0eXBob29uXzUwMCA9IGlmZWxzZShkZjMkZGlzdF90eXBob29uPDUwMDAwMCwxLDApDQpkZjMkdHlwaG9vbl8xMDAwID0gaWZlbHNlKGRmMyRkaXN0X3R5cGhvb248MTAwMDAwMCwxLDApDQoNCmRmMyR0eXBob29uX2ludGVuc2l0eSA9IGN1dChkZjMkaW50ZW5zaXR5X3ZtYXgsIGMoOTIuNCwxNTApKQ0KDQpmaXQgPC0gZ2xtKGRlbGF5ZWQgfiB0eXBob29uXzEwMCArIHR5cGhvb25fNTAwICsgdHlwaG9vbl8xMDAwLCBkYXRhPWRmMywgZmFtaWx5PWJpbm9taWFsKQ0Kc3VtbWFyeShmaXQpDQpmaXQgPC0gZ2xtKGRlbGF5ZWQgfiAodHlwaG9vbl8xMDAgKyB0eXBob29uXzUwMCArIHR5cGhvb25fMTAwMCkgOiB0eXBob29uX2ludGVuc2l0eSwgZGF0YT1kZjMsIGZhbWlseT1iaW5vbWlhbCkNCnN1bW1hcnkoZml0KQ0KDQojZGYkZGlzdF90b3BvcnQgPC0gZGlzdFZpbmNlbnR5RWxsaXBzb2lkKGFzLm1hdHJpeChkZlssYygibG9uIiwibGF0IildKSwgYXMubWF0cml4KGRmWyxjKCJhcnJpdmVfbG9uIiwiYXJyaXZlX2xhdCIpXSkpDQojZGYkZGlzdF90b3BvcnQgPC0gZGlzdFZpbmNlbnR5RWxsaXBzb2lkKGFzLm1hdHJpeChkZlssYygibG9uIiwibGF0IildKSwgYXMubWF0cml4KGRmWyxjKCJsZWZ0X2xvbiIsImxlZnRfbGF0IildKSkNCiMgbWVyZ2luZyB0eXBob29ucyBhbmQgc2hpcHMuLi4NCg0KI3VuaXF1ZShhcy5EYXRlKGRmJGxhc3RfdXBkYXRlLCAiVVRDIikpDQoNCg0KYGBgDQoNCg0KDQoNCg0KDQpPTEQgQkVMT1cNCg0KYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9DQpsaWJyYXJ5KHJlYWRyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZ2dwbG90MikNCg0KdXJsX2NzdiA8LSAnaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2Q0dGFnaXJsL1ItTGFkaWVzLWdyb3d0aC1tYXBzL21hc3Rlci9ybGFkaWVzLmNzdicNCnJsYWRpZXMgPC0gcmVhZF9jc3YodXJsKHVybF9jc3YpKSAlPiUgDQogIHNlbGVjdCgtMSkNCnJsYWRpZXMyIDwtIHJsYWRpZXMNCnJsYWRpZXMkZnJhbWUgPC0gMQ0KcmxhZGllczIkZnJhbWUgPC0gMg0KcmxhZGllczIkbGF0IDwtIHJsYWRpZXMyJGxhdCArIDUNCnJsYWRpZXMzIDwtIHJiaW5kKHJsYWRpZXMscmxhZGllczIpDQpybGFkaWVzMiRmcmFtZSA8LSAzDQpybGFkaWVzMiRsYXQgPC0gcmxhZGllczIkbGF0ICsgNQ0KcmxhZGllczMgPC0gcmJpbmQocmxhZGllczMscmxhZGllczIpDQpybGFkaWVzMiRmcmFtZSA8LSA0DQpybGFkaWVzMiRsYXQgPC0gcmxhZGllczIkbGF0ICsgNQ0KcmxhZGllczMgPC0gcmJpbmQocmxhZGllczMscmxhZGllczIpDQpybGFkaWVzMiRmcmFtZSA8LSA1DQpybGFkaWVzMiRsYXQgPC0gcmxhZGllczIkbGF0ICsgNQ0KcmxhZGllczMgPC0gcmJpbmQocmxhZGllczMscmxhZGllczIpDQoNCmxpYnJhcnkocGxvdGx5KQ0KDQpnIDwtIGxpc3QocmVzb2x1dGlvbiA9IDUwLA0KICAgICAgICAgIHNob3dsYW5kID0gVFJVRSwNCiAgICAgICAgICBzaG93bGFrZXMgPSBUUlVFLA0KICAgICAgICAgIGxhbmRjb2xvciA9IHRvUkdCKCJncmV5ODAiKSwNCiAgICAgICAgICBjb3VudHJ5Y29sb3IgPSB0b1JHQigiZ3JleTgwIiksDQogICAgICAgICAgbGFrZWNvbG9yID0gdG9SR0IoIndoaXRlIiksDQogICAgICAgICAgcHJvamVjdGlvbiA9IGxpc3QodHlwZSA9ICJlcXVpcmVjdGFuZ3VsYXIiKSwNCiAgICAgICAgICBjb2FzdGxpbmV3aWR0aCA9IDIsDQogICAgICAgICAgbGF0YXhpcyA9IGxpc3QoDQogICAgICAgICAgICByYW5nZSA9IGMoMjAsIDYwKSwNCiAgICAgICAgICAgIHNob3dncmlkID0gVFJVRSwNCiAgICAgICAgICAgIHRpY2ttb2RlID0gImxpbmVhciIsDQogICAgICAgICAgICBkdGljayA9IDEwDQogICAgICAgICAgKSwNCiAgICAgICAgICBsb25heGlzID0gbGlzdCgNCiAgICAgICAgICAgIHJhbmdlID0gYygtMTAwLCAyMCksDQogICAgICAgICAgICBzaG93Z3JpZCA9IFRSVUUsDQogICAgICAgICAgICB0aWNrbW9kZSA9ICJsaW5lYXIiLA0KICAgICAgICAgICAgZHRpY2sgPSAyMA0KICAgICAgICAgICkpDQoNCnBsb3RfZ2VvKCkgJT4lDQogIGFkZF9tYXJrZXJzKGRhdGEgPSBybGFkaWVzMywNCiAgICAgICAgICAgICAgeCA9IH5sb24sDQogICAgICAgICAgICAgIHkgPSB+bGF0LA0KICAgICAgICAgICAgICBmcmFtZSA9IH5mcmFtZSwNCiAgICAgICAgICAgICAgY29sb3I9SSgicHVycGxlIiksDQogICAgICAgICAgICAgIGhvdmVyaW5mbyA9ICJ0ZXh0IiwNCiAgICAgICAgICAgICAgdGV4dCA9IH5wYXN0ZSgnY2l0eTogJywgbG9jYXRpb24sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgJzxiciAvPiBjcmVhdGVkOiAnLCBjcmVhdGVkX2F0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICc8YnIgLz4gZm9sbG93ZXJzOiAnLCBmb2xsb3dlcnMpKSAlPiUNCiAgbGF5b3V0KGdlbyA9IGcpICU+JQ0KICBhbmltYXRpb25fb3B0cygNCiAgICAxMDAwLCBlYXNpbmcgPSAiZWxhc3RpYyIsIHJlZHJhdyA9IEZBTFNFDQogICkNCmBgYA0KDQptYXBzLCBtYXB0b29scywgc2YsIGdncGxvdCBAdjMsIHJnZW9zDQoNCmBgYHtyLCAgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OH0NCndvcmxkMSA8LSBzZjo6c3RfYXNfc2YobWFwKCd3b3JsZCcsIHBsb3QgPSBGQUxTRSwgZmlsbCA9IFRSVUUpKQ0KDQpwIDwtIGdncGxvdChkYXRhID0gd29ybGQxKSArIA0KICBnZW9tX3NmKCkgKyANCiAgZ2VvbV9wb2ludChkYXRhID0gcmxhZGllczMsIGFlcyh4ID0gbG9uLCB5ID0gbGF0LCBmcmFtZT1mcmFtZSkpDQpnZ3Bsb3RseShwKSAlPiUNCiAgIGFuaW1hdGlvbl9vcHRzKA0KICAgIDE1MDAsIGVhc2luZyA9ICJlbGFzdGljIiwgcmVkcmF3ID0gRkFMU0UNCiAgKQ0KIyBBTklNQVRJT046IGh0dHBzOi8vZ2l0aHViLmNvbS9wbG90bHkvcGxvdGx5LmpzL2Jsb2IvbWFzdGVyL3NyYy9wbG90cy9hbmltYXRpb25fYXR0cmlidXRlcy5qcw0KYGBgDQo=