knitr::opts_chunk$set(warning=FALSE, message=FALSE, fig.align = 'center')
options(tidyverse.quiet = TRUE)
library(readxl)
library(janitor)
library(glmmTMB)
library(lubridate)
library(broom.mixed)
library(knitr)
library(ggpubr)
library(sjPlot)
library(sf)
library(leaflet)
library(raster)
library(DHARMa)
library(ggspatial)
library(cowplot)
library(ggpubr)
library(mapview)
theme_set(theme_minimal())

1 Survey design

  • The objective of the study was to quantify spatio-temporal changes in fish density after a massive seabream escape event in July 2014.

  • Surveys were conducted in 14 July 2014, five days after the escape event, and then in August 2014 and September 2014.

  • Density was determined by snorkel-based dive surveys at eight different locations.

  • At each location two sites were surveyed, with six replicates per site, except Gorguel in July (12 replicates) and Escombreras in August and September when no surveys were conducted.

  • Sampling units consisted of 500 m2 transects sampled visually by snorkelers swimming 50 m in a straight line and observing the area within 2.5 m on either side (5 x 100 m2).

  • Snorkelers estimated the density and the size of each fish in the transect.

# get map of Murcia---
murcia <- 
  read_sf('C:/Users/javiera/OneDrive - Cawthron/UA/Consumo/data/CCAA/Comunidades_Autonomas_ETRS89_30N.shp') %>% 
  filter(Texto_Alt == "Murcia")

locations <- st_read("data/coords_gorguel.kml", quiet = T)

esc_d <- 
  read_csv('data/gorguel_density_data_clean.csv', show_col_types = FALSE) %>% 
  mutate(month = fct_relevel(month, c("July","August"))) 
esc_d %>% 
  tabyl(month, localidad) %>% 
  kable(caption = 'Transectos por Localidad y mes') 
Transectos por Localidad y mes
month Atamaría Azohía Cabo Palos Calacortina Escombreras Gorguel Portman Portus
July 12 12 12 12 12 24 12 12
August 12 12 12 12 0 12 12 12
September 12 12 12 12 0 12 12 12

2 Study locations

leaflet(locations) %>%
  setView(lng = -1,
          lat = 37.6,
          zoom = 11) %>%
  addTiles() %>%
  addProviderTiles("Esri.WorldImagery") %>%
  addCircleMarkers()

2.1 Bathymetry

murcia_bathy_cropped <- raster('data/murcia_bathy_cropped.grd')
mapview(murcia_bathy_cropped)@map

2.2 Map version 2

sf_use_s2(FALSE)
Spherical geometry (s2) switched off
murcia <- 
  read_sf('C:/Users/javiera/OneDrive - Cawthron/UA/Consumo/data/CCAA/Comunidades_Autonomas_ETRS89_30N.shp') %>% 
  filter(Texto_Alt == "Murcia") %>% 
  st_transform (4326) %>% 
  st_crop(
    xmin = -1.2,
    xmax = 0.7,
    ymin = 37.5,
    ymax = 37.65
  ) 
although coordinates are longitude/latitude, st_intersection assumes that they are planar

3 Data exploration

3.1 Distance

Locations were at increasing distance, in both direction (E and W), from the farm where the escape was originated.

esc_d %>% 
  distinct(localidad, distance, orientation) %>% 
  arrange(orientation, distance) %>% 
  kable(caption = "Distancia y direccion de cada sitio")
Distancia y direccion de cada sitio
localidad distance orientation
Gorguel 0.7 E
Portman 4.4 E
Atamaría 10.1 E
Cabo Palos 23.7 E
Escombreras 6.4 W
Calacortina 12.6 W
Portus 26.4 W
Azohía 45.3 W

3.2 Density distribution

Fish density data was standardized to number of fish per 100 m2, resulting in continuous variable containing a disproportionately high number of zero values (73.6% of the 276 transects) and the non-zero data was highly overdispersed.

ggarrange(
  ggplot(esc_d, aes(density)) +
  geom_histogram() + labs(subtitle = 'Untrasnformed'),
  ggplot(esc_d, aes(density)) +
  geom_histogram() +
  scale_x_continuous(trans = 'log1p') + labs(subtitle = 'log1p transformed')
  )
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

3.3 Density by Month

ggplot(esc_d, aes(month, density, fill = month)) +
  scale_y_continuous(trans = "log1p", breaks = c(0,10, 50, 250, 1000) ) +
  geom_boxplot(alpha = .4) +
  labs(x = 'Distance (m)' , y = Individuals~per~100~m^2, parse = T) +
  scale_fill_discrete(name = NULL)

3.4 Density by location, month and site

ggplot(esc_d, aes(month, density)) +
  geom_point(alpha = .5, size = 3, aes(color = factor(sitio)), position =     position_jitter(width = .1)) +
  scale_y_continuous(trans = "log1p", expand = c(0, Inf), ) +
  # scale_x_date(date_labels = "%b %d") +
  facet_wrap(~localidad) 

3.5 Density vs distance, month and direccion (E -W)

ggplot(esc_d, aes(distance, density, color = month, group = month)) +
  scale_y_continuous(trans = "log1p") +
  stat_summary(fun.data = mean_se) +
  stat_summary(fun.data = mean_se, geom = 'line') +
  facet_wrap(~orientation, scales = 'free_x') +
  theme(legend.position = 'bottom') +
  labs(x = 'Distance from escape (km)' , y = Number~of~fish~per~100~m^2, parse = T) +
  scale_color_discrete(name = NULL)

3.6 Distance no direction

ggplot(esc_d, aes(distance, density, color = month, group = month)) +
  scale_y_continuous(trans = "log1p", breaks = c(0,10, 50, 250, 1000) ) +
  geom_point(alpha = .4, position = position_jitter(width = .5)) +
  geom_smooth(stat = 'summary', fun.data = mean_se, alpha = .2) +
  theme(legend.position = 'bottom') +
  labs(x = 'Distance from escape (km)' , y = Individuals~per~100~m^2, parse = T) +
  scale_color_discrete(name = NULL)

3.7 Density by Orientation

ggplot(esc_d, aes(month, density, fill = orientation)) +
  scale_y_continuous(trans = "log1p", breaks = c(0,10, 50, 250, 1000) ) +
  geom_boxplot(alpha = .4) +
  labs(x = NULL , y = Individuals~per~100~m^2, parse = T) +
  scale_fill_discrete(name = NULL)

4 Fish density modelling

Fish count data was standardised to number of fish per 100 m2, resulting in continuous variable that was overdispered and contained a large number of zero values. As such, density data was analysed using generalised linear models fitted with Tweedie error distribution which is more robust to overdispersed and zero-rich data than other distribution families (e.g. negative binomial, gamma). Zero-inflation was tested with the testZeroInflation function of the package DHARMa that compares the observed number of zeros with the zeros expected from simulations.

Models were fitted with distance a continuous covariate, month as categorical with three levels (July, August and September), and their interaction (Distance x Month). The main effect of Orientation (W and E) was also included as a categorical fixed effect. Site nested in location was included a random factor to quatify the variability in density at a small spatial scale (100s m). Models were selected based on the AIC values and validated using simulated residulas using the simulateResiduals function in the package DHARMa.

The contribution of fixed and random effects to the performance of the model was calculated using marginal R2 (accounting for fixed effects only) and conditional pseudo-R2 (accounting for fixed and random effects, Nakagawa and Schielzeth, 2013).

4.1 Test for zero-inflation

zi_model <-
  glmmTMB(
    density ~ distance * month + orientation + (1|localidad:sitio),
    zi =  ~ distance + month,
    family = tweedie(link = "log"),
    data = esc_d
  )

testZeroInflation(zi_model)

    DHARMa zero-inflation test via comparison to expected zeros with
    simulation under H0 = fitted model

data:  simulationOutput
ratioObsSim = 0.98653, p-value = 0.816
alternative hypothesis: two.sided

glance(zi_model)

The test showed that the expected distribution of zeros is not larger than the observed values, thus there is no need to incorporate zero-inflation in the model.

4.2 GLMM without zero-inflation

m1 <-
  glmmTMB(
    density ~ distance * month + orientation + (1|localidad:sitio),
    family = tweedie(link = "log"),
    data = esc_d
  )


drop1(m1)
Single term deletions

Model:
density ~ distance * month + orientation + (1 | localidad:sitio)
               Df    AIC
<none>            718.69
orientation     1 716.97
distance:month  2 721.76

The lowest AIC value (716.97) was for the model with the distance and month interaction and no effect of orientation (density ~ distance * month).

All AIC values were lower than that for the zero-inflated model.

4.3 Model validation

final_model <-
  glmmTMB(
    density ~ distance * month  + (1|localidad:sitio),
    family = tweedie(link = "log"),
    data = esc_d
  )

simulationOutput <- simulateResiduals(fittedModel = final_model, plot = F)
plot(simulationOutput)

# testResiduals(final_model)

There are no residual patterns or over-dispersion. The residuals test identified one outlier that could be potentially removed and some mild deviation that is not of concern.

4.4 Model inference

effect component group term estimate std.error statistic p.value
fixed cond NA (Intercept) 3.77 0.72 5.21 0.00
fixed cond NA distance -0.19 0.03 -7.13 0.00
fixed cond NA monthAugust -4.16 0.82 -5.07 0.00
fixed cond NA monthSeptember -5.23 1.06 -4.95 0.00
fixed cond NA distance:monthAugust 0.10 0.04 2.51 0.01
fixed cond NA distance:monthSeptember 0.11 0.06 1.72 0.09
ran_pars cond localidad:sitio sd__(Intercept) 0.78 NA NA NA

The model predicted an average fish density (intercept of the model) of 43 individuals per 100 m2 (10.49 – 178.96 95% CI) at the location of the escape. The density reduction rate varied significantly with sampling month (Distance x month, P<0.05).

Fish density significantly decreased with distance, more specifically by 17% for every km away from the escape location. Fish density was predicted to decrease to 2% and 1% after one and two month of the escape event, respectively

Additionally, there was relatively site-to-site variability in fish density, evidenced by the small standard deviation for the effect of site nested in location, and the small difference between the conditional the R2 value marginal value (0.38 and 0.41, respectively).

5 Fish size distribution

In addition to fish density, divers estimated total fish length of all fish in the transects.

size <- read_csv('data/size_data.csv')
size_raw <- read_csv('data/size_data_raw.csv')

5.1 Histograms of total fish length by month and location


ggplot(size_raw, aes(size, fill = localidad)) +
  geom_histogram(bins = 15) +
  facet_wrap(~month, scales = 'free_y') 

NA

5.2 Mean (±SD) total length by month and locality

ggplot(size_raw, aes(fct_relevel(month,"July","August"), size, color = fct_reorder(loc_dist, distance) , group = fct_reorder(loc_dist, distance) )) +
  stat_summary(fun.data = mean_sdl,   position = position_dodge(width = .7)) +
  scale_color_discrete(name = NULL) +
  labs(x = NULL, y = "Total fish length (cm)" )

5.3 Test for size between month

Length frequencies between months were compared using a randomization Kolmogorov & Smirnov test using the function clus.lf in the fishmethods package.

From package help file:

Length frequency distributions of fishes are commonly tested for differences among groups (e.g., regions, sexes, etc.) using a two-sample Kolmogov-Smirnov test (K-S). Like most statistical tests, the K-S test requires that observations are collected at random and are independent of each other to satisfy assumptions. These basic assumptions are violated when gears (e.g., trawls, haul seines, gillnets, etc.) are used to sample fish because individuals are collected in clusters . In this case, the “haul”, not the individual fish, is the primary sampling unit and statistical comparisons must take this into account.

library(fishmethods)

clus_res <- 
clus.lf(group=size$month,haul=paste(size$transecto,size$toponimia),
        len=size$size, number=size$number, 
        binsize=5,resamples=100)

clus_res$results %>% kable

There were significant differences in fish size frequency distribution between months, except between August and September.

LS0tDQp0aXRsZTogIkVzY2FwZXMgR29yZ3VlbCINCmF1dGhvcjogIkphdmllciBBdGFsYWgiDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlQiwgJVknKWAiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgbnVtYmVyX3NlY3Rpb246IHllcw0KICAgIHRoZW1lOiBkZWZhdWx0DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDINCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IG5vDQogICAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMNCi0tLQ0KDQohW10oZmlndXJlcy9sb2dvLXVhLmpwZyl7d2lkdGg9IjMwNyJ9DQoNCmBgYHtyIHNldHVwLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZpZy5hbGlnbiA9ICdjZW50ZXInKQ0Kb3B0aW9ucyh0aWR5dmVyc2UucXVpZXQgPSBUUlVFKQ0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGphbml0b3IpDQpsaWJyYXJ5KGdsbW1UTUIpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkoYnJvb20ubWl4ZWQpDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShnZ3B1YnIpDQpsaWJyYXJ5KHNqUGxvdCkNCmxpYnJhcnkoc2YpDQpsaWJyYXJ5KGxlYWZsZXQpDQpsaWJyYXJ5KHJhc3RlcikNCmxpYnJhcnkoREhBUk1hKQ0KbGlicmFyeShnZ3NwYXRpYWwpDQpsaWJyYXJ5KGNvd3Bsb3QpDQpsaWJyYXJ5KGdncHVicikNCmxpYnJhcnkobWFwdmlldykNCnRoZW1lX3NldCh0aGVtZV9taW5pbWFsKCkpDQpgYGANCg0KIyBTdXJ2ZXkgZGVzaWduDQoNCi0gICBUaGUgb2JqZWN0aXZlIG9mIHRoZSBzdHVkeSB3YXMgdG8gcXVhbnRpZnkgc3BhdGlvLXRlbXBvcmFsIGNoYW5nZXMgaW4gZmlzaCBkZW5zaXR5IGFmdGVyIGEgbWFzc2l2ZSBzZWFicmVhbSBlc2NhcGUgZXZlbnQgaW4gSnVseSAyMDE0Lg0KDQotICAgU3VydmV5cyB3ZXJlIGNvbmR1Y3RlZCBpbiAxNCBKdWx5IDIwMTQsIGZpdmUgZGF5cyBhZnRlciB0aGUgZXNjYXBlIGV2ZW50LCBhbmQgdGhlbiBpbiBBdWd1c3QgMjAxNCBhbmQgU2VwdGVtYmVyIDIwMTQuDQoNCi0gICBEZW5zaXR5IHdhcyBkZXRlcm1pbmVkIGJ5IHNub3JrZWwtYmFzZWQgZGl2ZSBzdXJ2ZXlzIGF0IGVpZ2h0IGRpZmZlcmVudCBsb2NhdGlvbnMuDQoNCi0gICBBdCBlYWNoIGxvY2F0aW9uIHR3byBzaXRlcyB3ZXJlIHN1cnZleWVkLCB3aXRoIHNpeCByZXBsaWNhdGVzIHBlciBzaXRlLCBleGNlcHQgR29yZ3VlbCBpbiBKdWx5ICgxMiByZXBsaWNhdGVzKSBhbmQgRXNjb21icmVyYXMgaW4gQXVndXN0IGFuZCBTZXB0ZW1iZXIgd2hlbiBubyBzdXJ2ZXlzIHdlcmUgY29uZHVjdGVkLg0KDQotICAgU2FtcGxpbmcgdW5pdHMgY29uc2lzdGVkIG9mIDUwMCBtXjJeIHRyYW5zZWN0cyBzYW1wbGVkIHZpc3VhbGx5IGJ5IHNub3JrZWxlcnMgc3dpbW1pbmcgNTAgbSBpbiBhIHN0cmFpZ2h0IGxpbmUgYW5kIG9ic2VydmluZyB0aGUgYXJlYSB3aXRoaW4gMi41IG0gb24gZWl0aGVyIHNpZGUgKDUgeCAxMDAgbV4yXikuDQoNCi0gICBTbm9ya2VsZXJzIGVzdGltYXRlZCB0aGUgZGVuc2l0eSBhbmQgdGhlIHNpemUgb2YgZWFjaCBmaXNoIGluIHRoZSB0cmFuc2VjdC4NCg0KYGBge3J9DQojIGdldCBtYXAgb2YgTXVyY2lhLS0tDQptdXJjaWEgPC0gDQogIHJlYWRfc2YoJ0M6L1VzZXJzL2phdmllcmEvT25lRHJpdmUgLSBDYXd0aHJvbi9VQS9Db25zdW1vL2RhdGEvQ0NBQS9Db211bmlkYWRlc19BdXRvbm9tYXNfRVRSUzg5XzMwTi5zaHAnKSAlPiUgDQogIGZpbHRlcihUZXh0b19BbHQgPT0gIk11cmNpYSIpDQoNCmxvY2F0aW9ucyA8LSBzdF9yZWFkKCJkYXRhL2Nvb3Jkc19nb3JndWVsLmttbCIsIHF1aWV0ID0gVCkNCg0KZXNjX2QgPC0gDQogIHJlYWRfY3N2KCdkYXRhL2dvcmd1ZWxfZGVuc2l0eV9kYXRhX2NsZWFuLmNzdicsIHNob3dfY29sX3R5cGVzID0gRkFMU0UpICU+JSANCiAgbXV0YXRlKG1vbnRoID0gZmN0X3JlbGV2ZWwobW9udGgsIGMoIkp1bHkiLCJBdWd1c3QiKSkpIA0KDQpgYGANCg0KYGBge3J9DQplc2NfZCAlPiUgDQogIHRhYnlsKG1vbnRoLCBsb2NhbGlkYWQpICU+JSANCiAga2FibGUoY2FwdGlvbiA9ICdUcmFuc2VjdG9zIHBvciBMb2NhbGlkYWQgeSBtZXMnKSANCmBgYA0KDQojIFN0dWR5IGxvY2F0aW9ucw0KDQpgYGB7cn0NCmxlYWZsZXQobG9jYXRpb25zKSAlPiUNCiAgc2V0VmlldyhsbmcgPSAtMSwNCiAgICAgICAgICBsYXQgPSAzNy42LA0KICAgICAgICAgIHpvb20gPSAxMSkgJT4lDQogIGFkZFRpbGVzKCkgJT4lDQogIGFkZFByb3ZpZGVyVGlsZXMoIkVzcmkuV29ybGRJbWFnZXJ5IikgJT4lDQogIGFkZENpcmNsZU1hcmtlcnMoKQ0KYGBgDQoNCiMjIEJhdGh5bWV0cnkNCg0KYGBge3J9DQptdXJjaWFfYmF0aHlfY3JvcHBlZCA8LSByYXN0ZXIoJ2RhdGEvbXVyY2lhX2JhdGh5X2Nyb3BwZWQuZ3JkJykNCm1hcHZpZXcobXVyY2lhX2JhdGh5X2Nyb3BwZWQpQG1hcA0KYGBgDQoNCiMjIE1hcCB2ZXJzaW9uIDINCg0KYGBge3J9DQpjb29yZHMgPC0gcmVhZF9jc3YoJ2RhdGEvY29vcmRzLmNzdicpDQpzcGFpbiA8LSANCiAgcmVhZF9zZignQzovVXNlcnMvamF2aWVyYS9PbmVEcml2ZSAtIENhd3Rocm9uL1VBL0NvbnN1bW8vZGF0YS9DQ0FBL0NvbXVuaWRhZGVzX0F1dG9ub21hc19FVFJTODlfMzBOLnNocCcpICU+JSANCiAgZmlsdGVyKCFUZXh0byVpbiUgYygiQ2FuYXJpYXMiLCJDZXV0YSIsIk1lbGlsbGEiKSkgJT4lIA0KICBzdF90cmFuc2Zvcm0gKDQzMjYpIA0KDQpzZl91c2VfczIoRkFMU0UpDQptdXJjaWEgPC0gDQogIHJlYWRfc2YoJ0M6L1VzZXJzL2phdmllcmEvT25lRHJpdmUgLSBDYXd0aHJvbi9VQS9Db25zdW1vL2RhdGEvQ0NBQS9Db211bmlkYWRlc19BdXRvbm9tYXNfRVRSUzg5XzMwTi5zaHAnKSAlPiUgDQogIGZpbHRlcihUZXh0b19BbHQgPT0gIk11cmNpYSIpICU+JSANCiAgc3RfdHJhbnNmb3JtICg0MzI2KSAlPiUgDQogIHN0X2Nyb3AoDQogICAgeG1pbiA9IC0xLjIsDQogICAgeG1heCA9IDAuNywNCiAgICB5bWluID0gMzcuNSwNCiAgICB5bWF4ID0gMzcuNjUNCiAgKSANCg0Kc2l0ZXNfbWFwIDwtIA0KZ2dwbG90KCkgKyANCiAgZ2VvbV9zZihkYXRhID0gbXVyY2lhLCBmaWxsID0gJ2dyYXk5MCcpICsNCiAgZ2VvbV9wb2ludChkYXRhID0gY29vcmRzLCBhZXMoWCxZKSkgKw0KICBnZ3JlcGVsOjpnZW9tX2xhYmVsX3JlcGVsKGRhdGEgPSBjb29yZHMsIGFlcyhYLFksIGxhYmVsID0gbG9jYWxpZGFkKSwgY29sb3IgPTEgLCBzaXplID0gMi41KSArDQogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMKSArDQogIGFubm90YXRpb25fbm9ydGhfYXJyb3coDQogICAgbG9jYXRpb24gPSAiYnIiLA0KICAgIHdoaWNoX25vcnRoID0gInRydWUiLA0KICAgIHBhZF94ID0gdW5pdCgwLjA1LCAiaW4iKSwNCiAgICBwYWRfeSA9IHVuaXQoMC4yLCAiaW4iKSwNCiAgICBzdHlsZSA9IG5vcnRoX2Fycm93X2ZhbmN5X29yaWVudGVlcmluZw0KICApICsNCiAgYW5ub3RhdGlvbl9zY2FsZShsb2NhdGlvbiA9ICJiciIsIHdpZHRoX2hpbnQgPSAwLjE1KSANCg0KDQpzcGFpbl9tYXAgPC0gDQogIGdncGxvdCgpICsgDQogIGdlb21fc2YoZGF0YSA9IHNwYWluLCBmaWxsID0gJ2dyYXk5MCcpICsNCiAgbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwpICsNCiAgIyBjb29yZF9tYXAoeGxpbSA9IGMoMTY2LCAxNzkpLCB5bGltID0gYygtNDcuNSwgLTM0KSkgKw0KICBhbm5vdGF0ZSgNCiAgICAicmVjdCIsDQogICAgeG1pbiA9IC0xLjIsDQogICAgeG1heCA9IC0wLjcsDQogICAgeW1pbiA9IDM3LjUsDQogICAgeW1heCA9IDM3LjcsDQogICAgY29sb3IgPSAyLA0KICAgIGZpbGwgPSAndHJhbnNwYXJlbnQnLA0KICAgIHNpemUgPSAxDQogICkgKw0KICB0aGVtZV92b2lkKCkgKw0KICB0aGVtZSgNCiAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3IgPSAnZ3JheTMwJywgZmlsbD0gTkEpDQogICkgDQoNCmZpZ19tYXAgPC0gDQogIGNvd3Bsb3Q6OmdnZHJhdygpICsNCiAgZHJhd19wbG90KHNpdGVzX21hcCkgKw0KICBkcmF3X3Bsb3QoDQogICAgc3BhaW5fbWFwLA0KICAgIHggPSAwLjgsDQogICAgeSA9IC43NSwNCiAgICB3aWR0aCA9IC4yLA0KICAgIGhlaWdodCA9IC4yDQogICkNCmZpZ19tYXANCmBgYA0KDQojIERhdGEgZXhwbG9yYXRpb24NCg0KIyMgRGlzdGFuY2UNCg0KTG9jYXRpb25zIHdlcmUgYXQgaW5jcmVhc2luZyBkaXN0YW5jZSwgaW4gYm90aCBkaXJlY3Rpb24gKEUgYW5kIFcpLCBmcm9tIHRoZSBmYXJtIHdoZXJlIHRoZSBlc2NhcGUgd2FzIG9yaWdpbmF0ZWQuDQoNCmBgYHtyfQ0KZXNjX2QgJT4lIA0KICBkaXN0aW5jdChsb2NhbGlkYWQsIGRpc3RhbmNlLCBvcmllbnRhdGlvbikgJT4lIA0KICBhcnJhbmdlKG9yaWVudGF0aW9uLCBkaXN0YW5jZSkgJT4lIA0KICBrYWJsZShjYXB0aW9uID0gIkRpc3RhbmNpYSB5IGRpcmVjY2lvbiBkZSBjYWRhIHNpdGlvIg0KYGBgDQoNCiMjIERlbnNpdHkgZGlzdHJpYnV0aW9uDQoNCkZpc2ggZGVuc2l0eSBkYXRhIHdhcyBzdGFuZGFyZGl6ZWQgdG8gbnVtYmVyIG9mIGZpc2ggcGVyIDEwMCBtMiwgcmVzdWx0aW5nIGluIGNvbnRpbnVvdXMgdmFyaWFibGUgY29udGFpbmluZyBhIGRpc3Byb3BvcnRpb25hdGVseSBoaWdoIG51bWJlciBvZiB6ZXJvIHZhbHVlcyAoNzMuNiUgb2YgdGhlIDI3NiB0cmFuc2VjdHMpIGFuZCB0aGUgbm9uLXplcm8gZGF0YSB3YXMgaGlnaGx5IG92ZXJkaXNwZXJzZWQuDQoNCmBgYHtyLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD0xMH0NCmdnYXJyYW5nZSgNCiAgZ2dwbG90KGVzY19kLCBhZXMoZGVuc2l0eSkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oKSArIGxhYnMoc3VidGl0bGUgPSAnVW50cmFzbmZvcm1lZCcpLA0KICBnZ3Bsb3QoZXNjX2QsIGFlcyhkZW5zaXR5KSkgKw0KICBnZW9tX2hpc3RvZ3JhbSgpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKHRyYW5zID0gJ2xvZzFwJykgKyBsYWJzKHN1YnRpdGxlID0gJ2xvZzFwIHRyYW5zZm9ybWVkJykNCiAgKQ0KYGBgDQoNCiMjIERlbnNpdHkgYnkgTW9udGgNCg0KYGBge3J9DQpnZ3Bsb3QoZXNjX2QsIGFlcyhtb250aCwgZGVuc2l0eSwgZmlsbCA9IG1vbnRoKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXModHJhbnMgPSAibG9nMXAiLCBicmVha3MgPSBjKDAsMTAsIDUwLCAyNTAsIDEwMDApICkgKw0KICBnZW9tX2JveHBsb3QoYWxwaGEgPSAuNCkgKw0KICBsYWJzKHggPSAnRGlzdGFuY2UgKG0pJyAsIHkgPSBJbmRpdmlkdWFsc35wZXJ+MTAwfm1eMiwgcGFyc2UgPSBUKSArDQogIHNjYWxlX2ZpbGxfZGlzY3JldGUobmFtZSA9IE5VTEwpDQpgYGANCg0KIyMgRGVuc2l0eSBieSBsb2NhdGlvbiwgbW9udGggYW5kIHNpdGUNCg0KYGBge3J9DQpnZ3Bsb3QoZXNjX2QsIGFlcyhtb250aCwgZGVuc2l0eSkpICsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IC41LCBzaXplID0gMywgYWVzKGNvbG9yID0gZmFjdG9yKHNpdGlvKSksIHBvc2l0aW9uID0gICAgIHBvc2l0aW9uX2ppdHRlcih3aWR0aCA9IC4xKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXModHJhbnMgPSAibG9nMXAiLCBleHBhbmQgPSBjKDAsIEluZiksICkgKw0KICAjIHNjYWxlX3hfZGF0ZShkYXRlX2xhYmVscyA9ICIlYiAlZCIpICsNCiAgZmFjZXRfd3JhcCh+bG9jYWxpZGFkKSANCmBgYA0KDQojIyBEZW5zaXR5IHZzIGRpc3RhbmNlLCBtb250aCBhbmQgZGlyZWNjaW9uIChFIC1XKQ0KDQpgYGB7cn0NCmdncGxvdChlc2NfZCwgYWVzKGRpc3RhbmNlLCBkZW5zaXR5LCBjb2xvciA9IG1vbnRoLCBncm91cCA9IG1vbnRoKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXModHJhbnMgPSAibG9nMXAiKSArDQogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fc2UpICsNCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9zZSwgZ2VvbSA9ICdsaW5lJykgKw0KICBmYWNldF93cmFwKH5vcmllbnRhdGlvbiwgc2NhbGVzID0gJ2ZyZWVfeCcpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ2JvdHRvbScpICsNCiAgbGFicyh4ID0gJ0Rpc3RhbmNlIGZyb20gZXNjYXBlIChrbSknICwgeSA9IE51bWJlcn5vZn5maXNofnBlcn4xMDB+bV4yLCBwYXJzZSA9IFQpICsNCiAgc2NhbGVfY29sb3JfZGlzY3JldGUobmFtZSA9IE5VTEwpDQoNCmBgYA0KDQojIyBEaXN0YW5jZSBubyBkaXJlY3Rpb24NCg0KYGBge3J9DQpnZ3Bsb3QoZXNjX2QsIGFlcyhkaXN0YW5jZSwgZGVuc2l0eSwgY29sb3IgPSBtb250aCwgZ3JvdXAgPSBtb250aCkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zID0gImxvZzFwIiwgYnJlYWtzID0gYygwLDEwLCA1MCwgMjUwLCAxMDAwKSApICsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IC40LCBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcih3aWR0aCA9IC41KSkgKw0KICBnZW9tX3Ntb290aChzdGF0ID0gJ3N1bW1hcnknLCBmdW4uZGF0YSA9IG1lYW5fc2UsIGFscGhhID0gLjIpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ2JvdHRvbScpICsNCiAgbGFicyh4ID0gJ0Rpc3RhbmNlIGZyb20gZXNjYXBlIChrbSknICwgeSA9IEluZGl2aWR1YWxzfnBlcn4xMDB+bV4yLCBwYXJzZSA9IFQpICsNCiAgc2NhbGVfY29sb3JfZGlzY3JldGUobmFtZSA9IE5VTEwpDQoNCmBgYA0KDQojIyBEZW5zaXR5IGJ5IE9yaWVudGF0aW9uDQoNCmBgYHtyfQ0KZ2dwbG90KGVzY19kLCBhZXMobW9udGgsIGRlbnNpdHksIGZpbGwgPSBvcmllbnRhdGlvbikpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zID0gImxvZzFwIiwgYnJlYWtzID0gYygwLDEwLCA1MCwgMjUwLCAxMDAwKSApICsNCiAgZ2VvbV9ib3hwbG90KGFscGhhID0gLjQpICsNCiAgbGFicyh4ID0gTlVMTCAsIHkgPSBJbmRpdmlkdWFsc35wZXJ+MTAwfm1eMiwgcGFyc2UgPSBUKSArDQogIHNjYWxlX2ZpbGxfZGlzY3JldGUobmFtZSA9IE5VTEwpDQpgYGANCg0KIyBGaXNoIGRlbnNpdHkgbW9kZWxsaW5nDQoNCkZpc2ggY291bnQgZGF0YSB3YXMgc3RhbmRhcmRpc2VkIHRvIG51bWJlciBvZiBmaXNoIHBlciAxMDAgbTIsIHJlc3VsdGluZyBpbiBjb250aW51b3VzIHZhcmlhYmxlIHRoYXQgd2FzIG92ZXJkaXNwZXJlZCBhbmQgY29udGFpbmVkIGEgbGFyZ2UgbnVtYmVyIG9mIHplcm8gdmFsdWVzLiBBcyBzdWNoLCBkZW5zaXR5IGRhdGEgd2FzIGFuYWx5c2VkIHVzaW5nIGdlbmVyYWxpc2VkIGxpbmVhciBtb2RlbHMgZml0dGVkIHdpdGggVHdlZWRpZSBlcnJvciBkaXN0cmlidXRpb24gd2hpY2ggaXMgbW9yZSByb2J1c3QgdG8gb3ZlcmRpc3BlcnNlZCBhbmQgemVyby1yaWNoIGRhdGEgdGhhbiBvdGhlciBkaXN0cmlidXRpb24gZmFtaWxpZXMgKGUuZy4gbmVnYXRpdmUgYmlub21pYWwsIGdhbW1hKS4gWmVyby1pbmZsYXRpb24gd2FzIHRlc3RlZCB3aXRoIHRoZSB0ZXN0WmVyb0luZmxhdGlvbiBmdW5jdGlvbiBvZiB0aGUgcGFja2FnZSBESEFSTWEgdGhhdCBjb21wYXJlcyB0aGUgb2JzZXJ2ZWQgbnVtYmVyIG9mIHplcm9zIHdpdGggdGhlIHplcm9zIGV4cGVjdGVkIGZyb20gc2ltdWxhdGlvbnMuDQoNCk1vZGVscyB3ZXJlIGZpdHRlZCB3aXRoIGRpc3RhbmNlIGEgY29udGludW91cyBjb3ZhcmlhdGUsIG1vbnRoIGFzIGNhdGVnb3JpY2FsIHdpdGggdGhyZWUgbGV2ZWxzIChKdWx5LCBBdWd1c3QgYW5kIFNlcHRlbWJlciksIGFuZCB0aGVpciBpbnRlcmFjdGlvbiAoRGlzdGFuY2UgeCBNb250aCkuIFRoZSBtYWluIGVmZmVjdCBvZiBPcmllbnRhdGlvbiAoVyBhbmQgRSkgd2FzIGFsc28gaW5jbHVkZWQgYXMgYSBjYXRlZ29yaWNhbCBmaXhlZCBlZmZlY3QuIFNpdGUgbmVzdGVkIGluIGxvY2F0aW9uIHdhcyBpbmNsdWRlZCBhIHJhbmRvbSBmYWN0b3IgdG8gcXVhdGlmeSB0aGUgdmFyaWFiaWxpdHkgaW4gZGVuc2l0eSBhdCBhIHNtYWxsIHNwYXRpYWwgc2NhbGUgKDEwMHMgbSkuIE1vZGVscyB3ZXJlIHNlbGVjdGVkIGJhc2VkIG9uIHRoZSBBSUMgdmFsdWVzIGFuZCB2YWxpZGF0ZWQgdXNpbmcgc2ltdWxhdGVkIHJlc2lkdWxhcyB1c2luZyB0aGUgc2ltdWxhdGVSZXNpZHVhbHMgZnVuY3Rpb24gaW4gdGhlIHBhY2thZ2UgREhBUk1hLg0KDQpUaGUgY29udHJpYnV0aW9uIG9mIGZpeGVkIGFuZCByYW5kb20gZWZmZWN0cyB0byB0aGUgcGVyZm9ybWFuY2Ugb2YgdGhlIG1vZGVsIHdhcyBjYWxjdWxhdGVkIHVzaW5nIG1hcmdpbmFsIFIyIChhY2NvdW50aW5nIGZvciBmaXhlZCBlZmZlY3RzIG9ubHkpIGFuZCBjb25kaXRpb25hbCBwc2V1ZG8tUjIgKGFjY291bnRpbmcgZm9yIGZpeGVkIGFuZCByYW5kb20gZWZmZWN0cywgTmFrYWdhd2EgYW5kIFNjaGllbHpldGgsIDIwMTMpLg0KDQojIyBUZXN0IGZvciB6ZXJvLWluZmxhdGlvbg0KDQpgYGB7cn0NCnppX21vZGVsIDwtDQogIGdsbW1UTUIoDQogICAgZGVuc2l0eSB+IGRpc3RhbmNlICogbW9udGggKyBvcmllbnRhdGlvbiArICgxfGxvY2FsaWRhZDpzaXRpbyksDQogICAgemkgPSAgfiBkaXN0YW5jZSArIG1vbnRoLA0KICAgIGZhbWlseSA9IHR3ZWVkaWUobGluayA9ICJsb2ciKSwNCiAgICBkYXRhID0gZXNjX2QNCiAgKQ0KDQp0ZXN0WmVyb0luZmxhdGlvbih6aV9tb2RlbCkNCg0KZ2xhbmNlKHppX21vZGVsKQ0KYGBgDQoNClRoZSB0ZXN0IHNob3dlZCB0aGF0IHRoZSBleHBlY3RlZCBkaXN0cmlidXRpb24gb2YgemVyb3MgaXMgbm90IGxhcmdlciB0aGFuIHRoZSBvYnNlcnZlZCB2YWx1ZXMsIHRodXMgdGhlcmUgaXMgbm8gbmVlZCB0byBpbmNvcnBvcmF0ZSB6ZXJvLWluZmxhdGlvbiBpbiB0aGUgbW9kZWwuDQoNCiMjIEdMTU0gd2l0aG91dCB6ZXJvLWluZmxhdGlvbg0KDQpgYGB7cn0NCm0xIDwtDQogIGdsbW1UTUIoDQogICAgZGVuc2l0eSB+IGRpc3RhbmNlICogbW9udGggKyBvcmllbnRhdGlvbiArICgxfGxvY2FsaWRhZDpzaXRpbyksDQogICAgZmFtaWx5ID0gdHdlZWRpZShsaW5rID0gImxvZyIpLA0KICAgIGRhdGEgPSBlc2NfZA0KICApDQoNCg0KZHJvcDEobTEpDQoNCmBgYA0KDQpUaGUgbG93ZXN0IEFJQyB2YWx1ZSAoNzE2Ljk3KSB3YXMgZm9yIHRoZSBtb2RlbCB3aXRoIHRoZSBkaXN0YW5jZSBhbmQgbW9udGggaW50ZXJhY3Rpb24gYW5kIG5vIGVmZmVjdCBvZiBvcmllbnRhdGlvbiAoZGVuc2l0eSBcfiBkaXN0YW5jZSBcKiBtb250aCkuDQoNCkFsbCBBSUMgdmFsdWVzIHdlcmUgbG93ZXIgdGhhbiB0aGF0IGZvciB0aGUgemVyby1pbmZsYXRlZCBtb2RlbC4NCg0KIyMgTW9kZWwgdmFsaWRhdGlvbg0KDQpgYGB7cn0NCmZpbmFsX21vZGVsIDwtDQogIGdsbW1UTUIoDQogICAgZGVuc2l0eSB+IGRpc3RhbmNlICogbW9udGggICsgKDF8bG9jYWxpZGFkOnNpdGlvKSwNCiAgICBmYW1pbHkgPSB0d2VlZGllKGxpbmsgPSAibG9nIiksDQogICAgZGF0YSA9IGVzY19kDQogICkNCg0Kc2ltdWxhdGlvbk91dHB1dCA8LSBzaW11bGF0ZVJlc2lkdWFscyhmaXR0ZWRNb2RlbCA9IGZpbmFsX21vZGVsLCBwbG90ID0gRikNCnBsb3Qoc2ltdWxhdGlvbk91dHB1dCkNCiMgdGVzdFJlc2lkdWFscyhmaW5hbF9tb2RlbCkNCmBgYA0KDQpUaGVyZSBhcmUgbm8gcmVzaWR1YWwgcGF0dGVybnMgb3Igb3Zlci1kaXNwZXJzaW9uLiBUaGUgcmVzaWR1YWxzIHRlc3QgaWRlbnRpZmllZCBvbmUgb3V0bGllciB0aGF0IGNvdWxkIGJlIHBvdGVudGlhbGx5IHJlbW92ZWQgYW5kIHNvbWUgbWlsZCBkZXZpYXRpb24gdGhhdCBpcyBub3Qgb2YgY29uY2Vybi4NCg0KIyMgTW9kZWwgaW5mZXJlbmNlDQoNCmBgYHtyfQ0KdGlkeShmaW5hbF9tb2RlbCkgJT4lIGthYmxlKGRpZ2l0cyA9IDIpDQpgYGANCg0KVGhlIG1vZGVsIHByZWRpY3RlZCBhbiBhdmVyYWdlIGZpc2ggZGVuc2l0eSAoaW50ZXJjZXB0IG9mIHRoZSBtb2RlbCkgb2YgNDMgaW5kaXZpZHVhbHMgcGVyIDEwMCBtXjJeICgxMC40OSAtLSAxNzguOTYgOTUlIENJKSBhdCB0aGUgbG9jYXRpb24gb2YgdGhlIGVzY2FwZS4gVGhlIGRlbnNpdHkgcmVkdWN0aW9uIHJhdGUgdmFyaWVkIHNpZ25pZmljYW50bHkgd2l0aCBzYW1wbGluZyBtb250aCAoRGlzdGFuY2UgeCBtb250aCwgUFw8MC4wNSkuDQoNCkZpc2ggZGVuc2l0eSBzaWduaWZpY2FudGx5IGRlY3JlYXNlZCB3aXRoIGRpc3RhbmNlLCBtb3JlIHNwZWNpZmljYWxseSBieSAxNyUgZm9yIGV2ZXJ5IGttIGF3YXkgZnJvbSB0aGUgZXNjYXBlIGxvY2F0aW9uLiBGaXNoIGRlbnNpdHkgd2FzIHByZWRpY3RlZCB0byBkZWNyZWFzZSB0byAyJSBhbmQgMSUgYWZ0ZXIgb25lIGFuZCB0d28gbW9udGggb2YgdGhlIGVzY2FwZSBldmVudCwgcmVzcGVjdGl2ZWx5DQoNCkFkZGl0aW9uYWxseSwgdGhlcmUgd2FzIHJlbGF0aXZlbHkgc2l0ZS10by1zaXRlIHZhcmlhYmlsaXR5IGluIGZpc2ggZGVuc2l0eSwgZXZpZGVuY2VkIGJ5IHRoZSBzbWFsbCBzdGFuZGFyZCBkZXZpYXRpb24gZm9yIHRoZSBlZmZlY3Qgb2Ygc2l0ZSBuZXN0ZWQgaW4gbG9jYXRpb24sIGFuZCB0aGUgc21hbGwgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBjb25kaXRpb25hbCB0aGUgUl4yXiB2YWx1ZSBtYXJnaW5hbCB2YWx1ZSAoMC4zOCBhbmQgMC40MSwgcmVzcGVjdGl2ZWx5KS4NCg0KIyBGaXNoIHNpemUgZGlzdHJpYnV0aW9uDQoNCkluIGFkZGl0aW9uIHRvIGZpc2ggZGVuc2l0eSwgZGl2ZXJzIGVzdGltYXRlZCB0b3RhbCBmaXNoIGxlbmd0aCBvZiBhbGwgZmlzaCBpbiB0aGUgdHJhbnNlY3RzLg0KDQpgYGB7cn0NCnNpemUgPC0gcmVhZF9jc3YoJ2RhdGEvc2l6ZV9kYXRhLmNzdicpDQpzaXplX3JhdyA8LSByZWFkX2NzdignZGF0YS9zaXplX2RhdGFfcmF3LmNzdicpDQpgYGANCg0KIyMgSGlzdG9ncmFtcyBvZiB0b3RhbCBmaXNoIGxlbmd0aCBieSBtb250aCBhbmQgbG9jYXRpb24NCg0KYGBge3IsIGZpZy53aWR0aD0xMn0NCg0KZ2dwbG90KHNpemVfcmF3LCBhZXMoc2l6ZSwgZmlsbCA9IGxvY2FsaWRhZCkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDE1KSArDQogIGZhY2V0X3dyYXAofm1vbnRoLCBzY2FsZXMgPSAnZnJlZV95JykgDQogIA0KYGBgDQoNCiMjIE1lYW4gKMKxU0QpIHRvdGFsIGxlbmd0aCBieSBtb250aCBhbmQgbG9jYWxpdHkNCg0KYGBge3J9DQpnZ3Bsb3Qoc2l6ZV9yYXcsIGFlcyhmY3RfcmVsZXZlbChtb250aCwiSnVseSIsIkF1Z3VzdCIpLCBzaXplLCBjb2xvciA9IGZjdF9yZW9yZGVyKGxvY19kaXN0LCBkaXN0YW5jZSkgLCBncm91cCA9IGZjdF9yZW9yZGVyKGxvY19kaXN0LCBkaXN0YW5jZSkgKSkgKw0KICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX3NkbCwgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gLjcpKSArDQogIHNjYWxlX2NvbG9yX2Rpc2NyZXRlKG5hbWUgPSBOVUxMKSArDQogIGxhYnMoeCA9IE5VTEwsIHkgPSAiVG90YWwgZmlzaCBsZW5ndGggKGNtKSIgKQ0KDQpgYGANCg0KIyMgVGVzdCBmb3Igc2l6ZSBiZXR3ZWVuIG1vbnRoDQoNCkxlbmd0aCBmcmVxdWVuY2llcyBiZXR3ZWVuIG1vbnRocyB3ZXJlIGNvbXBhcmVkIHVzaW5nIGEgcmFuZG9taXphdGlvbiBLb2xtb2dvcm92ICYgU21pcm5vdiB0ZXN0IHVzaW5nIHRoZSBmdW5jdGlvbiAqY2x1cy5sZiogaW4gdGhlIGZpc2htZXRob2RzIHBhY2thZ2UuDQoNCkZyb20gcGFja2FnZSBoZWxwIGZpbGU6DQoNCipMZW5ndGggZnJlcXVlbmN5IGRpc3RyaWJ1dGlvbnMgb2YgZmlzaGVzIGFyZSBjb21tb25seSB0ZXN0ZWQgZm9yIGRpZmZlcmVuY2VzIGFtb25nIGdyb3VwcyAoZS5nLiwgcmVnaW9ucywgc2V4ZXMsIGV0Yy4pIHVzaW5nIGEgdHdvLXNhbXBsZSBLb2xtb2dvdi1TbWlybm92IHRlc3QgKEstUykuIExpa2UgbW9zdCBzdGF0aXN0aWNhbCB0ZXN0cywgdGhlIEstUyB0ZXN0IHJlcXVpcmVzIHRoYXQgb2JzZXJ2YXRpb25zIGFyZSBjb2xsZWN0ZWQgYXQgcmFuZG9tIGFuZCBhcmUgaW5kZXBlbmRlbnQgb2YgZWFjaCBvdGhlciB0byBzYXRpc2Z5IGFzc3VtcHRpb25zLiBUaGVzZSBiYXNpYyBhc3N1bXB0aW9ucyBhcmUgdmlvbGF0ZWQgd2hlbiBnZWFycyAoZS5nLiwgdHJhd2xzLCBoYXVsIHNlaW5lcywgZ2lsbG5ldHMsIGV0Yy4pIGFyZSB1c2VkIHRvIHNhbXBsZSBmaXNoIGJlY2F1c2UgaW5kaXZpZHVhbHMgYXJlIGNvbGxlY3RlZCBpbiBjbHVzdGVycyAuIEluIHRoaXMgY2FzZSwgdGhlICJoYXVsIiwgbm90IHRoZSBpbmRpdmlkdWFsIGZpc2gsIGlzIHRoZSBwcmltYXJ5IHNhbXBsaW5nIHVuaXQgYW5kIHN0YXRpc3RpY2FsIGNvbXBhcmlzb25zIG11c3QgdGFrZSB0aGlzIGludG8gYWNjb3VudC4qDQoNCmBgYHtyfQ0KbGlicmFyeShmaXNobWV0aG9kcykNCg0KY2x1c19yZXMgPC0gDQpjbHVzLmxmKGdyb3VwPXNpemUkbW9udGgsaGF1bD1wYXN0ZShzaXplJHRyYW5zZWN0byxzaXplJHRvcG9uaW1pYSksDQogICAgICAgIGxlbj1zaXplJHNpemUsIG51bWJlcj1zaXplJG51bWJlciwgDQogICAgICAgIGJpbnNpemU9NSxyZXNhbXBsZXM9MTAwKQ0KDQpjbHVzX3JlcyRyZXN1bHRzICU+JSBrYWJsZQ0KYGBgDQoNClRoZXJlIHdlcmUgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZXMgaW4gZmlzaCBzaXplIGZyZXF1ZW5jeSBkaXN0cmlidXRpb24gYmV0d2VlbiBtb250aHMsIGV4Y2VwdCBiZXR3ZWVuIEF1Z3VzdCBhbmQgU2VwdGVtYmVyLg0K