Marine Biodiversity Observation Network Pole to Pole of the Americas (MBON Pole to Pole)

Written by E. Montes () on Auguts 28, 2020.

This code creates a map showing the boundaries of a selected Large Marine Ecosystems (LME) and extracts records for selected taxa from the Ocean Biodiversity Information System (OBIS) using robis tools.

Step 1

First, let’s load required libraries

library(robis)
library(rgdal) # for `ogrInfo()` and `readOGR()`
library(tools) # for `file_path_sans_ext()`
library(dplyr) # for `inner_join()`, `filter()`, `summarise()`, and the pipe operator (%>%)
library(ggplot2) # for `fortify()` and for plotting
library(sp) # for `point.in.polygon()` and `spDists()`
library(tidyr) # for `gather()`
library(readr) # for `write_tsv()`
library(leaflet)
library(lubridate)

Step 2

Now let’s provide the function fortify.shape(), which puts the shapefile data in the object class data.frame, so that it can be used by ggplot2, and extract portions of the data (from the fortified data.frame object) for a smaller domain

fortify.shape <- function(x){
  x@data$id <- rownames(x@data)
  x.f <- fortify(x, region = "id")
  x.join <- inner_join(x.f, x@data, by = "id")
}

subset.shape <- function(x, domain){
  x.subset <- filter(x, long > domain[1] & 
                       long < domain[2] & 
                       lat > domain[3] & 
                       lat < domain[4])
  x.subset
}

Step 3

Let’s read the shapefile “LMEs66.shp” containing all polygons, fortify the global data and then extract domain. See numbers here

path.lme.coast <- ("~/lme-extractions/data")
fnam.lme.coast <- "LMEs66.shp"
dat.coast <- readOGR(dsn = path.lme.coast, 
                     layer = file_path_sans_ext(fnam.lme.coast))

# fortify the global data and then extract domain
dat.coast <- fortify.shape(dat.coast) # a 410951x8 dataframe

# Specify the desired LME:
dat.sel_1 <- subset(dat.coast, LME_NUMBER == 15) # S. Brazil. 
dat.sel_2 <- subset(dat.coast, LME_NUMBER == 16) # E. Brazil
dat.sel_3 <- subset(dat.coast, LME_NUMBER == 17) # N. Brazil
dat.sel_4 <- subset(dat.coast, LME_NUMBER == 14) # Patagonia
dat.sel_5 <- subset(dat.coast, LME_NUMBER == 13) # Humboldt C.
dat.sel_6 <- subset(dat.coast, LME_NUMBER == 12) # Caribbean
dat.sel_7 <- subset(dat.coast, LME_NUMBER == 11) # P. Ctral A.
dat.sel_8 <- subset(dat.coast, LME_NUMBER == 5) # GoM
dat.sel_9 <- subset(dat.coast, LME_NUMBER == 4) # Gulf of California
dat.sel_10 <- subset(dat.coast, LME_NUMBER == 3) # CCS
dat.sel_11 <- subset(dat.coast, LME_NUMBER == 2) # G. Alaska
dat.sel_12 <- subset(dat.coast, LME_NUMBER == 1) # E. Bearing S.
dat.sel_13 <- subset(dat.coast, LME_NUMBER == 54) # Chukchi S.
dat.sel_14 <- subset(dat.coast, LME_NUMBER == 55) # Beauford S.
dat.sel_15 <- subset(dat.coast, LME_NUMBER == 66) # Canadian Arctic
dat.sel_16 <- subset(dat.coast, LME_NUMBER == 18) # Canadian E. Arctic
dat.sel_17 <- subset(dat.coast, LME_NUMBER == 9) # Labrador S.
dat.sel_18 <- subset(dat.coast, LME_NUMBER == 8) # Scotian Shelf
dat.sel_19 <- subset(dat.coast, LME_NUMBER == 7) # NE US
dat.sel_20 <- subset(dat.coast, LME_NUMBER == 6) # SE US
dat.sel_21 <- subset(dat.coast, LME_NUMBER == 10) # Hawaii
dat.sel_22 <- subset(dat.coast, LME_NUMBER == 63) # Hudson Bay Complex
dat.sel_23 <- subset(dat.coast, LME_NUMBER == 19) # Greenland Sea
dat.sel_24 <- subset(dat.coast, LME_NUMBER == 21) # Norwegian Sea
dat.sel_25 <- subset(dat.coast, LME_NUMBER == 20) # Barents Sea
dat.sel_26 <- subset(dat.coast, LME_NUMBER == 58) # Kara Sea
dat.sel_27 <- subset(dat.coast, LME_NUMBER == 57) # Laptev Sea
dat.sel_28 <- subset(dat.coast, LME_NUMBER == 56) # E. Sibarian Sea

Step 4

Plotting the coastline and selected LME boundaries

# Define lat/lon limits here
xlims <- c(-150, -25)
ylims <- c(-60, 60)

# Generate a base map with the coastline:
p0 <- ggplot() + theme(text = element_text(size=18)) + 
  geom_path(data = dat.coast, aes(x = long, y = lat, group = group), 
            color = "black", size = 0.25) + 
  coord_map(projection = "mercator") + 
  scale_x_continuous(limits = xlims, expand = c(0, 0)) + 
  scale_y_continuous(limits = ylims, expand = c(0, 0)) + 
  labs(list(title = "", x = "Longitude", y = "Latitude"))

p0

# highlight LME of interest
p.sel <- p0 +
  geom_path(data = dat.sel_6,
            aes(x = long, y = lat, group = group),
            colour = "chartreuse4", size = 1) +
  geom_path(data = dat.sel_8,
            aes(x = long, y = lat, group = group),
            colour = "coral", size = 0.75)
p.sel

Step 5

This section extracts OBIS records of using the “occurrence” function or downloaded data, and plots time series or pie charts with distributions of large groups (annelids, molluscs, plants and echinoderms) in the upper 100m.

# Set extraction params
# LME codes (from OBIS URL)
# N Brazil=40017; E Brazil=40016; S Brazil=40015; Patagonia=40014; Humboldt=40013; Caribbean=40012; 
# P Ctral A=40011; CCS=40003; GoA=40002; NE USA=40007; E Bearing=40001; Canada E Arctic=40018; GoM=40005; 
# Chukchi=40054; SE USA=40006; Labrador=40009; Scotian S=40008

area = 40005  
depth = 100
mol_code = 51
echi_code = 1806
anne_code = 882
plan_code = 3

## read data from OBIS
## Molluscs
mollusc.100_2 = occurrence(areaid = area, taxonid = mol_code, enddepth = depth) 

## Ehinoderms
echino.100_2 = occurrence(areaid = area, taxonid = echi_code, enddepth = depth)

## Annelida
anne.100_2 = occurrence(areaid = area, taxonid = anne_code, enddepth = depth)

## Platae
plant.100_2 = occurrence(areaid = area, taxonid = plan_code, enddepth = depth)

## Merge the data frames
#subset data (year and phylum)
sub_mollusc <- data.frame(mollusc.100_2$date_year, mollusc.100_2$phylum) 
# rename column headers
names(sub_mollusc)[names(sub_mollusc) == "mollusc.100_2.date_year"] <- "year"
names(sub_mollusc)[names(sub_mollusc) == "mollusc.100_2.phylum"] <- "phylum"

sub_echino <- data.frame(echino.100_2$date_year, echino.100_2$phylum)
names(sub_echino)[names(sub_echino) == "echino.100_2.date_year"] <- "year"
names(sub_echino)[names(sub_echino) == "echino.100_2.phylum"] <- "phylum"

sub_anne <- data.frame(anne.100_2$date_year, anne.100_2$phylum)
names(sub_anne)[names(sub_anne) == "anne.100_2.date_year"] <- "year"
names(sub_anne)[names(sub_anne) == "anne.100_2.phylum"] <- "phylum"

sub_plant <- data.frame(plant.100_2$date_year, plant.100_2$phylum)
names(sub_plant)[names(sub_plant) == "plant.100_2.date_year"] <- "year"
names(sub_plant)[names(sub_plant) == "plant.100_2.phylum"] <- "phylum"

total.100 <- bind_rows(sub_mollusc, sub_echino, sub_anne, sub_plant)

## Plot the data
ts_plot <- ggplot() +
  geom_histogram(data = total.100, aes(x = year, fill = phylum), binwidth = 2) + 
  scale_fill_brewer(palette = "Spectral") + 
  xlim(c(1960, 2017)) + 
  theme(axis.text=element_text(size=12),
        axis.title=element_text(size=14,face="bold")) +
  theme(axis.text.x = element_text(size=14, angle=0), 
        axis.text.y = element_text(size=14, angle=0))
ts_plot

# ggsave(ts_plot, filename = "test.png", device = "png", width = 20, height = 10,  dpi=300)

## Plot pie chart 
# Group plants in a single group
all_tbl <- table(total.100$phylum)
all_df <- as.data.frame(all_tbl)
p_list = c("Chlorophyta", "Rhodophyta", "Tracheophyta")
rest_list = c("Annelida", "Echinodermata", "Mollusca")
p_idx = match(p_list, rownames(all_tbl))
rest_idx = match(rest_list, rownames(all_tbl))
p_sum = sum(all_df$Freq[p_idx], na.rm = TRUE)
freq_val <- c(all_df$Freq[rest_idx], p_sum)
group_id <- c(c(rest_list), "Plants")
f_tbl <- data.frame(group = group_id, freq = freq_val)
  
cols <- rainbow(nrow(f_tbl))
groups_pie <- pie(f_tbl$freq, labels = f_tbl$group, col = cols)
  
LS0tCnRpdGxlOiAiT0JJUyBleHRyYWN0aW9ucyBmcm9tIExhcmdlIE1hcmluZSBFY29zeXN0ZW0gcmVnaW9ucyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQojIE1hcmluZSBCaW9kaXZlcnNpdHkgT2JzZXJ2YXRpb24gTmV0d29yayBQb2xlIHRvIFBvbGUgb2YgdGhlIEFtZXJpY2FzIChbTUJPTiBQb2xlIHRvIFBvbGVdKGh0dHBzOi8vbWFyaW5lYm9uLm9yZy9wMnAvKSkKCldyaXR0ZW4gYnkgRS4gTW9udGVzIChlbW9udGVzaEB1c2YuZWR1KSBvbiBBdWd1dHMgMjgsIDIwMjAuCgoKVGhpcyBjb2RlIGNyZWF0ZXMgYSBtYXAgc2hvd2luZyB0aGUgYm91bmRhcmllcyBvZiBhIHNlbGVjdGVkIExhcmdlIE1hcmluZSBFY29zeXN0ZW1zIChbTE1FXShodHRwOi8vbG1lLmVkYy51cmkuZWR1L2luZGV4LnBocC9sbWUtaW50cm9kdWN0aW9uKSkgYW5kIGV4dHJhY3RzIHJlY29yZHMgZm9yIHNlbGVjdGVkIHRheGEgZnJvbSB0aGUgW09jZWFuIEJpb2RpdmVyc2l0eSBJbmZvcm1hdGlvbiBTeXN0ZW0gKE9CSVMpXShodHRwczovL29iaXMub3JnLykgdXNpbmcgW3JvYmlzXShodHRwczovL29iaXMub3JnL21hbnVhbC9hY2Nlc3NyLykgdG9vbHMuIAoKIyBTdGVwIDEKRmlyc3QsIGxldCdzIGxvYWQgcmVxdWlyZWQgbGlicmFyaWVzCmBgYHtyfQpsaWJyYXJ5KHJvYmlzKQpsaWJyYXJ5KHJnZGFsKSAjIGZvciBgb2dySW5mbygpYCBhbmQgYHJlYWRPR1IoKWAKbGlicmFyeSh0b29scykgIyBmb3IgYGZpbGVfcGF0aF9zYW5zX2V4dCgpYApsaWJyYXJ5KGRwbHlyKSAjIGZvciBgaW5uZXJfam9pbigpYCwgYGZpbHRlcigpYCwgYHN1bW1hcmlzZSgpYCwgYW5kIHRoZSBwaXBlIG9wZXJhdG9yICglPiUpCmxpYnJhcnkoZ2dwbG90MikgIyBmb3IgYGZvcnRpZnkoKWAgYW5kIGZvciBwbG90dGluZwpsaWJyYXJ5KHNwKSAjIGZvciBgcG9pbnQuaW4ucG9seWdvbigpYCBhbmQgYHNwRGlzdHMoKWAKbGlicmFyeSh0aWR5cikgIyBmb3IgYGdhdGhlcigpYApsaWJyYXJ5KHJlYWRyKSAjIGZvciBgd3JpdGVfdHN2KClgCmxpYnJhcnkobGVhZmxldCkKbGlicmFyeShsdWJyaWRhdGUpCmBgYAoKIyBTdGVwIDIKTm93IGxldCdzIHByb3ZpZGUgdGhlIGZ1bmN0aW9uIGZvcnRpZnkuc2hhcGUoKSwgd2hpY2ggcHV0cyB0aGUgc2hhcGVmaWxlIGRhdGEgaW4gdGhlIG9iamVjdCBjbGFzcyBkYXRhLmZyYW1lLCBzbyB0aGF0IGl0IGNhbiBiZSB1c2VkIGJ5IGdncGxvdDIsIGFuZCBleHRyYWN0IHBvcnRpb25zIG9mIHRoZSBkYXRhIChmcm9tIHRoZSBmb3J0aWZpZWQgZGF0YS5mcmFtZSBvYmplY3QpIGZvciBhIHNtYWxsZXIgZG9tYWluCmBgYHtyfQpmb3J0aWZ5LnNoYXBlIDwtIGZ1bmN0aW9uKHgpewogIHhAZGF0YSRpZCA8LSByb3duYW1lcyh4QGRhdGEpCiAgeC5mIDwtIGZvcnRpZnkoeCwgcmVnaW9uID0gImlkIikKICB4LmpvaW4gPC0gaW5uZXJfam9pbih4LmYsIHhAZGF0YSwgYnkgPSAiaWQiKQp9CgpzdWJzZXQuc2hhcGUgPC0gZnVuY3Rpb24oeCwgZG9tYWluKXsKICB4LnN1YnNldCA8LSBmaWx0ZXIoeCwgbG9uZyA+IGRvbWFpblsxXSAmIAogICAgICAgICAgICAgICAgICAgICAgIGxvbmcgPCBkb21haW5bMl0gJiAKICAgICAgICAgICAgICAgICAgICAgICBsYXQgPiBkb21haW5bM10gJiAKICAgICAgICAgICAgICAgICAgICAgICBsYXQgPCBkb21haW5bNF0pCiAgeC5zdWJzZXQKfQpgYGAKCiMgU3RlcCAzCkxldCdzIHJlYWQgdGhlIHNoYXBlZmlsZSAiTE1FczY2LnNocCIgY29udGFpbmluZyBhbGwgcG9seWdvbnMsIGZvcnRpZnkgdGhlIGdsb2JhbCBkYXRhIGFuZCB0aGVuIGV4dHJhY3QgZG9tYWluLiBTZWUgbnVtYmVycyBbaGVyZV0oaHR0cDovL2xtZS5lZGMudXJpLmVkdS9pbmRleC5waHAvbG1lLWludHJvZHVjdGlvbikKYGBge3J9CnBhdGgubG1lLmNvYXN0IDwtICgifi9sbWUtZXh0cmFjdGlvbnMvZGF0YSIpCmZuYW0ubG1lLmNvYXN0IDwtICJMTUVzNjYuc2hwIgpkYXQuY29hc3QgPC0gcmVhZE9HUihkc24gPSBwYXRoLmxtZS5jb2FzdCwgCiAgICAgICAgICAgICAgICAgICAgIGxheWVyID0gZmlsZV9wYXRoX3NhbnNfZXh0KGZuYW0ubG1lLmNvYXN0KSkKCiMgZm9ydGlmeSB0aGUgZ2xvYmFsIGRhdGEgYW5kIHRoZW4gZXh0cmFjdCBkb21haW4KZGF0LmNvYXN0IDwtIGZvcnRpZnkuc2hhcGUoZGF0LmNvYXN0KSAjIGEgNDEwOTUxeDggZGF0YWZyYW1lCgojIFNwZWNpZnkgdGhlIGRlc2lyZWQgTE1FOgpkYXQuc2VsXzEgPC0gc3Vic2V0KGRhdC5jb2FzdCwgTE1FX05VTUJFUiA9PSAxNSkgIyBTLiBCcmF6aWwuIApkYXQuc2VsXzIgPC0gc3Vic2V0KGRhdC5jb2FzdCwgTE1FX05VTUJFUiA9PSAxNikgIyBFLiBCcmF6aWwKZGF0LnNlbF8zIDwtIHN1YnNldChkYXQuY29hc3QsIExNRV9OVU1CRVIgPT0gMTcpICMgTi4gQnJhemlsCmRhdC5zZWxfNCA8LSBzdWJzZXQoZGF0LmNvYXN0LCBMTUVfTlVNQkVSID09IDE0KSAjIFBhdGFnb25pYQpkYXQuc2VsXzUgPC0gc3Vic2V0KGRhdC5jb2FzdCwgTE1FX05VTUJFUiA9PSAxMykgIyBIdW1ib2xkdCBDLgpkYXQuc2VsXzYgPC0gc3Vic2V0KGRhdC5jb2FzdCwgTE1FX05VTUJFUiA9PSAxMikgIyBDYXJpYmJlYW4KZGF0LnNlbF83IDwtIHN1YnNldChkYXQuY29hc3QsIExNRV9OVU1CRVIgPT0gMTEpICMgUC4gQ3RyYWwgQS4KZGF0LnNlbF84IDwtIHN1YnNldChkYXQuY29hc3QsIExNRV9OVU1CRVIgPT0gNSkgIyBHb00KZGF0LnNlbF85IDwtIHN1YnNldChkYXQuY29hc3QsIExNRV9OVU1CRVIgPT0gNCkgIyBHdWxmIG9mIENhbGlmb3JuaWEKZGF0LnNlbF8xMCA8LSBzdWJzZXQoZGF0LmNvYXN0LCBMTUVfTlVNQkVSID09IDMpICMgQ0NTCmRhdC5zZWxfMTEgPC0gc3Vic2V0KGRhdC5jb2FzdCwgTE1FX05VTUJFUiA9PSAyKSAjIEcuIEFsYXNrYQpkYXQuc2VsXzEyIDwtIHN1YnNldChkYXQuY29hc3QsIExNRV9OVU1CRVIgPT0gMSkgIyBFLiBCZWFyaW5nIFMuCmRhdC5zZWxfMTMgPC0gc3Vic2V0KGRhdC5jb2FzdCwgTE1FX05VTUJFUiA9PSA1NCkgIyBDaHVrY2hpIFMuCmRhdC5zZWxfMTQgPC0gc3Vic2V0KGRhdC5jb2FzdCwgTE1FX05VTUJFUiA9PSA1NSkgIyBCZWF1Zm9yZCBTLgpkYXQuc2VsXzE1IDwtIHN1YnNldChkYXQuY29hc3QsIExNRV9OVU1CRVIgPT0gNjYpICMgQ2FuYWRpYW4gQXJjdGljCmRhdC5zZWxfMTYgPC0gc3Vic2V0KGRhdC5jb2FzdCwgTE1FX05VTUJFUiA9PSAxOCkgIyBDYW5hZGlhbiBFLiBBcmN0aWMKZGF0LnNlbF8xNyA8LSBzdWJzZXQoZGF0LmNvYXN0LCBMTUVfTlVNQkVSID09IDkpICMgTGFicmFkb3IgUy4KZGF0LnNlbF8xOCA8LSBzdWJzZXQoZGF0LmNvYXN0LCBMTUVfTlVNQkVSID09IDgpICMgU2NvdGlhbiBTaGVsZgpkYXQuc2VsXzE5IDwtIHN1YnNldChkYXQuY29hc3QsIExNRV9OVU1CRVIgPT0gNykgIyBORSBVUwpkYXQuc2VsXzIwIDwtIHN1YnNldChkYXQuY29hc3QsIExNRV9OVU1CRVIgPT0gNikgIyBTRSBVUwpkYXQuc2VsXzIxIDwtIHN1YnNldChkYXQuY29hc3QsIExNRV9OVU1CRVIgPT0gMTApICMgSGF3YWlpCmRhdC5zZWxfMjIgPC0gc3Vic2V0KGRhdC5jb2FzdCwgTE1FX05VTUJFUiA9PSA2MykgIyBIdWRzb24gQmF5IENvbXBsZXgKZGF0LnNlbF8yMyA8LSBzdWJzZXQoZGF0LmNvYXN0LCBMTUVfTlVNQkVSID09IDE5KSAjIEdyZWVubGFuZCBTZWEKZGF0LnNlbF8yNCA8LSBzdWJzZXQoZGF0LmNvYXN0LCBMTUVfTlVNQkVSID09IDIxKSAjIE5vcndlZ2lhbiBTZWEKZGF0LnNlbF8yNSA8LSBzdWJzZXQoZGF0LmNvYXN0LCBMTUVfTlVNQkVSID09IDIwKSAjIEJhcmVudHMgU2VhCmRhdC5zZWxfMjYgPC0gc3Vic2V0KGRhdC5jb2FzdCwgTE1FX05VTUJFUiA9PSA1OCkgIyBLYXJhIFNlYQpkYXQuc2VsXzI3IDwtIHN1YnNldChkYXQuY29hc3QsIExNRV9OVU1CRVIgPT0gNTcpICMgTGFwdGV2IFNlYQpkYXQuc2VsXzI4IDwtIHN1YnNldChkYXQuY29hc3QsIExNRV9OVU1CRVIgPT0gNTYpICMgRS4gU2liYXJpYW4gU2VhCmBgYAoKIyBTdGVwIDQKUGxvdHRpbmcgdGhlIGNvYXN0bGluZSBhbmQgc2VsZWN0ZWQgTE1FIGJvdW5kYXJpZXMKYGBge3J9CiMgRGVmaW5lIGxhdC9sb24gbGltaXRzIGhlcmUKeGxpbXMgPC0gYygtMTUwLCAtMjUpCnlsaW1zIDwtIGMoLTYwLCA2MCkKCiMgR2VuZXJhdGUgYSBiYXNlIG1hcCB3aXRoIHRoZSBjb2FzdGxpbmU6CnAwIDwtIGdncGxvdCgpICsgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE4KSkgKyAKICBnZW9tX3BhdGgoZGF0YSA9IGRhdC5jb2FzdCwgYWVzKHggPSBsb25nLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwKSwgCiAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDAuMjUpICsgCiAgY29vcmRfbWFwKHByb2plY3Rpb24gPSAibWVyY2F0b3IiKSArIAogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSB4bGltcywgZXhwYW5kID0gYygwLCAwKSkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0geWxpbXMsIGV4cGFuZCA9IGMoMCwgMCkpICsgCiAgbGFicyhsaXN0KHRpdGxlID0gIiIsIHggPSAiTG9uZ2l0dWRlIiwgeSA9ICJMYXRpdHVkZSIpKQoKcDAKCiMgaGlnaGxpZ2h0IExNRSBvZiBpbnRlcmVzdApwLnNlbCA8LSBwMCArCiAgZ2VvbV9wYXRoKGRhdGEgPSBkYXQuc2VsXzYsCiAgICAgICAgICAgIGFlcyh4ID0gbG9uZywgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCksCiAgICAgICAgICAgIGNvbG91ciA9ICJjaGFydHJldXNlNCIsIHNpemUgPSAxKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBkYXQuc2VsXzgsCiAgICAgICAgICAgIGFlcyh4ID0gbG9uZywgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCksCiAgICAgICAgICAgIGNvbG91ciA9ICJjb3JhbCIsIHNpemUgPSAwLjc1KQpwLnNlbAoKYGBgCgojIFN0ZXAgNQpUaGlzIHNlY3Rpb24gZXh0cmFjdHMgT0JJUyByZWNvcmRzIG9mIHVzaW5nIHRoZSAib2NjdXJyZW5jZSIgZnVuY3Rpb24gb3IgZG93bmxvYWRlZCBkYXRhLCBhbmQgcGxvdHMgdGltZSBzZXJpZXMgb3IgcGllIGNoYXJ0cyB3aXRoIGRpc3RyaWJ1dGlvbnMgb2YgbGFyZ2UgZ3JvdXBzIChhbm5lbGlkcywgbW9sbHVzY3MsIHBsYW50cyBhbmQgZWNoaW5vZGVybXMpIGluIHRoZSB1cHBlciAxMDBtLgpgYGB7cn0KIyBTZXQgZXh0cmFjdGlvbiBwYXJhbXMKIyBMTUUgY29kZXMgKGZyb20gT0JJUyBVUkwpCiMgTiBCcmF6aWw9NDAwMTc7IEUgQnJhemlsPTQwMDE2OyBTIEJyYXppbD00MDAxNTsgUGF0YWdvbmlhPTQwMDE0OyBIdW1ib2xkdD00MDAxMzsgQ2FyaWJiZWFuPTQwMDEyOyAKIyBQIEN0cmFsIEE9NDAwMTE7IENDUz00MDAwMzsgR29BPTQwMDAyOyBORSBVU0E9NDAwMDc7IEUgQmVhcmluZz00MDAwMTsgQ2FuYWRhIEUgQXJjdGljPTQwMDE4OyBHb009NDAwMDU7IAojIENodWtjaGk9NDAwNTQ7IFNFIFVTQT00MDAwNjsgTGFicmFkb3I9NDAwMDk7IFNjb3RpYW4gUz00MDAwOAoKYXJlYSA9IDQwMDA1ICAKZGVwdGggPSAxMDAKbW9sX2NvZGUgPSA1MQplY2hpX2NvZGUgPSAxODA2CmFubmVfY29kZSA9IDg4MgpwbGFuX2NvZGUgPSAzCgojIyByZWFkIGRhdGEgZnJvbSBPQklTCiMjIE1vbGx1c2NzCm1vbGx1c2MuMTAwXzIgPSBvY2N1cnJlbmNlKGFyZWFpZCA9IGFyZWEsIHRheG9uaWQgPSBtb2xfY29kZSwgZW5kZGVwdGggPSBkZXB0aCkgCgojIyBFaGlub2Rlcm1zCmVjaGluby4xMDBfMiA9IG9jY3VycmVuY2UoYXJlYWlkID0gYXJlYSwgdGF4b25pZCA9IGVjaGlfY29kZSwgZW5kZGVwdGggPSBkZXB0aCkKCiMjIEFubmVsaWRhCmFubmUuMTAwXzIgPSBvY2N1cnJlbmNlKGFyZWFpZCA9IGFyZWEsIHRheG9uaWQgPSBhbm5lX2NvZGUsIGVuZGRlcHRoID0gZGVwdGgpCgojIyBQbGF0YWUKcGxhbnQuMTAwXzIgPSBvY2N1cnJlbmNlKGFyZWFpZCA9IGFyZWEsIHRheG9uaWQgPSBwbGFuX2NvZGUsIGVuZGRlcHRoID0gZGVwdGgpCgojIyBNZXJnZSB0aGUgZGF0YSBmcmFtZXMKI3N1YnNldCBkYXRhICh5ZWFyIGFuZCBwaHlsdW0pCnN1Yl9tb2xsdXNjIDwtIGRhdGEuZnJhbWUobW9sbHVzYy4xMDBfMiRkYXRlX3llYXIsIG1vbGx1c2MuMTAwXzIkcGh5bHVtKSAKIyByZW5hbWUgY29sdW1uIGhlYWRlcnMKbmFtZXMoc3ViX21vbGx1c2MpW25hbWVzKHN1Yl9tb2xsdXNjKSA9PSAibW9sbHVzYy4xMDBfMi5kYXRlX3llYXIiXSA8LSAieWVhciIKbmFtZXMoc3ViX21vbGx1c2MpW25hbWVzKHN1Yl9tb2xsdXNjKSA9PSAibW9sbHVzYy4xMDBfMi5waHlsdW0iXSA8LSAicGh5bHVtIgoKc3ViX2VjaGlubyA8LSBkYXRhLmZyYW1lKGVjaGluby4xMDBfMiRkYXRlX3llYXIsIGVjaGluby4xMDBfMiRwaHlsdW0pCm5hbWVzKHN1Yl9lY2hpbm8pW25hbWVzKHN1Yl9lY2hpbm8pID09ICJlY2hpbm8uMTAwXzIuZGF0ZV95ZWFyIl0gPC0gInllYXIiCm5hbWVzKHN1Yl9lY2hpbm8pW25hbWVzKHN1Yl9lY2hpbm8pID09ICJlY2hpbm8uMTAwXzIucGh5bHVtIl0gPC0gInBoeWx1bSIKCnN1Yl9hbm5lIDwtIGRhdGEuZnJhbWUoYW5uZS4xMDBfMiRkYXRlX3llYXIsIGFubmUuMTAwXzIkcGh5bHVtKQpuYW1lcyhzdWJfYW5uZSlbbmFtZXMoc3ViX2FubmUpID09ICJhbm5lLjEwMF8yLmRhdGVfeWVhciJdIDwtICJ5ZWFyIgpuYW1lcyhzdWJfYW5uZSlbbmFtZXMoc3ViX2FubmUpID09ICJhbm5lLjEwMF8yLnBoeWx1bSJdIDwtICJwaHlsdW0iCgpzdWJfcGxhbnQgPC0gZGF0YS5mcmFtZShwbGFudC4xMDBfMiRkYXRlX3llYXIsIHBsYW50LjEwMF8yJHBoeWx1bSkKbmFtZXMoc3ViX3BsYW50KVtuYW1lcyhzdWJfcGxhbnQpID09ICJwbGFudC4xMDBfMi5kYXRlX3llYXIiXSA8LSAieWVhciIKbmFtZXMoc3ViX3BsYW50KVtuYW1lcyhzdWJfcGxhbnQpID09ICJwbGFudC4xMDBfMi5waHlsdW0iXSA8LSAicGh5bHVtIgoKdG90YWwuMTAwIDwtIGJpbmRfcm93cyhzdWJfbW9sbHVzYywgc3ViX2VjaGlubywgc3ViX2FubmUsIHN1Yl9wbGFudCkKCiMjIFBsb3QgdGhlIGRhdGEKdHNfcGxvdCA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9oaXN0b2dyYW0oZGF0YSA9IHRvdGFsLjEwMCwgYWVzKHggPSB5ZWFyLCBmaWxsID0gcGh5bHVtKSwgYmlud2lkdGggPSAyKSArIAogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU3BlY3RyYWwiKSArIAogIHhsaW0oYygxOTYwLCAyMDE3KSkgKyAKICB0aGVtZShheGlzLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTIpLAogICAgICAgIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTQsZmFjZT0iYm9sZCIpKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xNCwgYW5nbGU9MCksIAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemU9MTQsIGFuZ2xlPTApKQp0c19wbG90CgojIGdnc2F2ZSh0c19wbG90LCBmaWxlbmFtZSA9ICJ0ZXN0LnBuZyIsIGRldmljZSA9ICJwbmciLCB3aWR0aCA9IDIwLCBoZWlnaHQgPSAxMCwgIGRwaT0zMDApCgojIyBQbG90IHBpZSBjaGFydCAKIyBHcm91cCBwbGFudHMgaW4gYSBzaW5nbGUgZ3JvdXAKYWxsX3RibCA8LSB0YWJsZSh0b3RhbC4xMDAkcGh5bHVtKQphbGxfZGYgPC0gYXMuZGF0YS5mcmFtZShhbGxfdGJsKQpwX2xpc3QgPSBjKCJDaGxvcm9waHl0YSIsICJSaG9kb3BoeXRhIiwgIlRyYWNoZW9waHl0YSIpCnJlc3RfbGlzdCA9IGMoIkFubmVsaWRhIiwgIkVjaGlub2Rlcm1hdGEiLCAiTW9sbHVzY2EiKQpwX2lkeCA9IG1hdGNoKHBfbGlzdCwgcm93bmFtZXMoYWxsX3RibCkpCnJlc3RfaWR4ID0gbWF0Y2gocmVzdF9saXN0LCByb3duYW1lcyhhbGxfdGJsKSkKcF9zdW0gPSBzdW0oYWxsX2RmJEZyZXFbcF9pZHhdLCBuYS5ybSA9IFRSVUUpCmZyZXFfdmFsIDwtIGMoYWxsX2RmJEZyZXFbcmVzdF9pZHhdLCBwX3N1bSkKZ3JvdXBfaWQgPC0gYyhjKHJlc3RfbGlzdCksICJQbGFudHMiKQpmX3RibCA8LSBkYXRhLmZyYW1lKGdyb3VwID0gZ3JvdXBfaWQsIGZyZXEgPSBmcmVxX3ZhbCkKICAKY29scyA8LSByYWluYm93KG5yb3coZl90YmwpKQpncm91cHNfcGllIDwtIHBpZShmX3RibCRmcmVxLCBsYWJlbHMgPSBmX3RibCRncm91cCwgY29sID0gY29scykKICAKYGBgCgoK