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=