Let’s start by loading packages and reading the data:

library(tidyverse)
library(rgdal)
library(mapview)
library(mgcv)
library(tidymv)

frogs <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2022/2022-08-02/frogs.csv')

head(frogs)
## # A tibble: 6 x 16
##   Site  Subsite HabType SurveyDate Ordinal Frequency UTME_83 UTMN_83 Interval
##   <chr> <chr>   <chr>   <chr>        <dbl>     <dbl>   <dbl>   <dbl>    <dbl>
## 1 Cran~ SE Pond Pond    9/25/2018      268      164.  597369 4846486        0
## 2 Cran~ SE Pond Pond    10/2/2018      275      164.  597352 4846487        1
## 3 Cran~ SE Pond Pond    10/9/2018      282      164.  597345 4846458        2
## 4 Cran~ SE Pond Pond    10/15/2018     288      164.  597340 4846464        3
## 5 Cran~ SE Pond Pond    10/22/2018     295      164.  597344 4846460        4
## 6 Cran~ SE Pond Pond    11/1/2018      305      164.  597410 4846451        5
## # ... with 7 more variables: Female <dbl>, Water <chr>, Type <chr>,
## #   Structure <chr>, Substrate <chr>, Beaver <chr>, Detection <chr>

Things are relatively clean this week! Let’s start by replicating the image in GitHub. There are a few things worth note. First “Frequency” identifies unique frogs while “UTME_83” and “UTMN_83” indicate east and north coordinate locations. So let’s calculate distance from starting location, defined as interval = 0. Because the geographical scale isn’t particularly large, and so curvature of the Earth need not be taken into account, we will use the Euclidean distance:

dist <- function(x0,x1,y0,y1){
  sqrt((x0-x1)^2 + (y0-y1)^2)
}

To make sure we are on the right track, let’s take a look at the raw locations:

frogs %>% 
  ggplot(aes(x = UTME_83, y = UTMN_83, col = as.factor(Frequency))) +
  geom_point() +
  theme_bw() +
  theme(legend.position = "none",
        aspect.ratio = 1) +
  geom_text(aes(label = Subsite),
            nudge_y = 750, check_overlap = T)

We weren’t provided with any spatial files to re-create maps of this area, but the above comports well with the map provided in the paper.

We can get a little bit closer to that with a bit of spatial wrangling:

frogs %>% 
  dplyr::select(x = UTME_83, y = UTMN_83) -> point

coordinates(point) <- c("x","y")
proj4string(point)=CRS("+init=epsg:26910") 
coord <-spTransform(point,CRS("+init=epsg:4326"))

mapview(coord, xcol = "x", ycol = "y",  crs = 4326)

But that is about as far as I want to go with mapping the data (although someone did a cool dynamic visualization tracking frog movements…). Anyway, back to the main task. Let’s establish the start coordinates for each of our froggy-boiis and calculate their distances:

frogs %>% 
  filter(Interval == 0) %>% 
  dplyr::select(Frequency, x0 = UTME_83, y0 = UTMN_83) %>% 
  merge(.,frogs,by="Frequency") -> frogs

frogs$dist <- dist(x0 = frogs$x0,
                   x1 = frogs$UTME_83,
                   y0 = frogs$y0,
                   y1 = frogs$UTMN_83)

Excellent. Now let’s replicate the graphic. The description in the paper states that they only look at frogs with eight or more locations, so let’s take a gander:

as.Date(frogs$SurveyDate, format = "%m/%d/%Y") %>% 
  format(., "%b %d %Y") %>% 
  as.Date(.,"%b %d %Y") -> frogs$new_date

frogs %>% 
  group_by(Frequency) %>% 
  mutate(obs = max(Interval)) %>% 
  filter(obs >= 8) -> less_frogs

less_frogs %>% 
  ggplot(aes(x = new_date, y = dist, col = as.factor(Frequency))) +
    facet_grid(~HabType) +
    geom_point() +
    geom_line() +
    theme_bw() +
    theme(legend.position = "none",
          axis.text.x = element_text(angle = 45, hjust = 1),
          axis.line = element_line(color='black'),
          plot.background = element_blank(),
          panel.grid.minor = element_blank(),
          panel.grid.major = element_blank()) +
    scale_x_date(date_labels = "%b %d",
                 date_breaks = "7 days") +
    ylab("Distance from Release Site (m)") +
    xlab("")

Good enough for government work; the image is identical to the published image other than (1) coloring by individual frog rather than Habitat Type, which is already indicated by the facet and (2) minor differences in the x-axis.

Now what more can we do? Instead of looking at the distance from the release site, we might instead be interested in the total movement the frog. This could differ from the above if, say, a frog was hopping in a circle equal distance from their capture site.

frogs %>% 
  group_by(Frequency) %>% 
  mutate(x_lag = lag(UTME_83),
         y_lag = lag(UTMN_83),
         move = dist(x0 = x_lag,
                     x1 = UTME_83,
                     y0 = y_lag,
                     y1 = UTMN_83)) -> frogs

frogs %>% 
  group_by(Frequency) %>% 
  mutate(obs = max(Interval)) %>% 
  filter(obs >= 8) -> less_frogs

less_frogs %>% 
  ggplot(aes(x = new_date, y = move, col = as.factor(Frequency))) +
    facet_grid(~HabType) +
    geom_point() +
    geom_line() +
    theme_bw() +
    theme(legend.position = "none",
          axis.text.x = element_text(angle = 45, hjust = 1),
          axis.line = element_line(color='black'),
          plot.background = element_blank(),
          panel.grid.minor = element_blank(),
          panel.grid.major = element_blank()) +
    scale_x_date(date_labels = "%b %d",
                 date_breaks = "7 days") +
    ylab("Distance from Previous Location (m)") +
    xlab("") -> f1
f1
## Warning: Removed 27 rows containing missing values (geom_point).
## Warning: Removed 27 row(s) containing missing values (geom_path).

One might say that the frogs hop around a bit. Let’s do a bit better by rescaling the y axis.

f1 +
  scale_y_continuous(trans = "log")
## Warning: Transformation introduced infinite values in continuous y-axis

## Warning: Transformation introduced infinite values in continuous y-axis
## Warning: Removed 27 rows containing missing values (geom_point).
## Warning: Removed 27 row(s) containing missing values (geom_path).

Two things are worth note. First is that there appear to be slight downward trend for each group. Let’s apply a cyclic smoother to these individual curves. Noting that “Ordinal” is the day of the year we will take the quick brutish approach to the problem, estimating a smooth curve for each frog in separate models. To make it a bit more interesting, we will only look at the top-hoppers.

less_frogs$id <- as.factor(less_frogs$Frequency)
ids <- unique(less_frogs$id)


lapply(ids, function(i){
  less_frogs %>% 
    filter(id == i) %>% 
    gam(log(move + 1) ~ s(Ordinal, bs = "cc", k = 5), data = .)
}) -> mods

pred_base <- data.frame(Ordinal = unique(less_frogs$Ordinal))

preds <- list()
for(i in 1:length(mods)){
  mod <- mods[[i]]
  pred_frame <- pred_base
  pred_frame$id <- ids[i]
  pred_frame$p <- predict(mod,pred_frame)
  preds[[i]] <- pred_frame
}

preds <- do.call("rbind",preds)

preds %>% 
  group_by(id) %>% 
  mutate(var = sd(p)) -> preds

preds %>%
  filter(var > 0.5) %>% 
  ggplot(aes(x = Ordinal, y = p, color = id)) +
  geom_line(lwd = 1.01) +
  theme_bw() +
  theme(legend.position = "none") +
  xlab("Time") +
  ylab("Distance") +
  ggtitle("Some Hoppy Boiis")

These frogs all, more or less, hopped away after capture, found a location they liked for a bit, then kept on hopping.

That’s all I am doing with this data. I still think it would be fun to play around with the image of this hoppy boii, but will leave that for another day.

LS0tDQp0aXRsZTogIlRpZHlUdWVzZGF5IDIwMjIsIFdlZWsgMzEiDQphdXRob3I6ICJDaHJpc3RvcGhlciBTY2h3YXJ6Ig0KZGF0ZTogIjgvMDIvMjAyMiINCnBhZ2VzOg0KICBleHRyYTogdHJ1ZQ0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDoNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpgYGANCg0KTGV0J3Mgc3RhcnQgYnkgbG9hZGluZyBwYWNrYWdlcyBhbmQgcmVhZGluZyB0aGUgZGF0YToNCg0KYGBge3IsIHdhcm5pbmc9RixtZXNzYWdlPUZBTFNFfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHJnZGFsKQ0KbGlicmFyeShtYXB2aWV3KQ0KbGlicmFyeShtZ2N2KQ0KbGlicmFyeSh0aWR5bXYpDQoNCmZyb2dzIDwtIHJlYWRyOjpyZWFkX2NzdignaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3Jmb3JkYXRhc2NpZW5jZS90aWR5dHVlc2RheS9tYXN0ZXIvZGF0YS8yMDIyLzIwMjItMDgtMDIvZnJvZ3MuY3N2JykNCg0KaGVhZChmcm9ncykNCmBgYA0KVGhpbmdzIGFyZSByZWxhdGl2ZWx5IGNsZWFuIHRoaXMgd2VlayEgIExldCdzIHN0YXJ0IGJ5IHJlcGxpY2F0aW5nIHRoZSBpbWFnZSBpbiBHaXRIdWIuICBUaGVyZSBhcmUgYSBmZXcgdGhpbmdzIHdvcnRoIG5vdGUuICBGaXJzdCAiRnJlcXVlbmN5IiBpZGVudGlmaWVzIHVuaXF1ZSBmcm9ncyB3aGlsZSAiVVRNRV84MyIgYW5kICJVVE1OXzgzIiBpbmRpY2F0ZSBlYXN0IGFuZCBub3J0aCBjb29yZGluYXRlIGxvY2F0aW9ucy4gIFNvIGxldCdzIGNhbGN1bGF0ZSBkaXN0YW5jZSBmcm9tIHN0YXJ0aW5nIGxvY2F0aW9uLCBkZWZpbmVkIGFzIGludGVydmFsID0gMC4gIEJlY2F1c2UgdGhlIGdlb2dyYXBoaWNhbCBzY2FsZSBpc24ndCBwYXJ0aWN1bGFybHkgbGFyZ2UsIGFuZCBzbyBjdXJ2YXR1cmUgb2YgdGhlIEVhcnRoIG5lZWQgbm90IGJlIHRha2VuIGludG8gYWNjb3VudCwgd2Ugd2lsbCB1c2UgdGhlIEV1Y2xpZGVhbiBkaXN0YW5jZToNCg0KYGBge3J9DQpkaXN0IDwtIGZ1bmN0aW9uKHgwLHgxLHkwLHkxKXsNCiAgc3FydCgoeDAteDEpXjIgKyAoeTAteTEpXjIpDQp9DQpgYGANCg0KVG8gbWFrZSBzdXJlIHdlIGFyZSBvbiB0aGUgcmlnaHQgdHJhY2ssIGxldCdzIHRha2UgYSBsb29rIGF0IHRoZSByYXcgbG9jYXRpb25zOg0KDQpgYGB7ciwgZmlnLmFsaWduID0gJ2NlbnRlcid9DQpmcm9ncyAlPiUgDQogIGdncGxvdChhZXMoeCA9IFVUTUVfODMsIHkgPSBVVE1OXzgzLCBjb2wgPSBhcy5mYWN0b3IoRnJlcXVlbmN5KSkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgdGhlbWVfYncoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgYXNwZWN0LnJhdGlvID0gMSkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gU3Vic2l0ZSksDQogICAgICAgICAgICBudWRnZV95ID0gNzUwLCBjaGVja19vdmVybGFwID0gVCkNCmBgYA0KDQoNCldlIHdlcmVuJ3QgcHJvdmlkZWQgd2l0aCBhbnkgc3BhdGlhbCBmaWxlcyB0byByZS1jcmVhdGUgbWFwcyBvZiB0aGlzIGFyZWEsIGJ1dCB0aGUgYWJvdmUgY29tcG9ydHMgd2VsbCB3aXRoIHRoZSBtYXAgcHJvdmlkZWQgaW4gdGhlIHBhcGVyLg0KDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KIyBEZWZpbmUgdmFyaWFibGUgY29udGFpbmluZyB1cmwNCnVybCA8LSAiaHR0cHM6Ly9iaW9vbmUub3JnL0NvbnRlbnRJbWFnZXMvSm91cm5hbHMvaHBldC81Ni8xLzIwLTA2MC9ncmFwaGljL1dlYkltYWdlcy9pbWctejItMS5qcGdfMDguanBnIg0KYGBgDQoNCjxjZW50ZXI+PGltZyBzcmM9ImByIHVybGAiPjwvY2VudGVyPg0KDQoNCldlIGNhbiBnZXQgYSBsaXR0bGUgYml0IGNsb3NlciB0byB0aGF0IHdpdGggYSBiaXQgb2Ygc3BhdGlhbCB3cmFuZ2xpbmc6DQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCg0KZnJvZ3MgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHggPSBVVE1FXzgzLCB5ID0gVVRNTl84MykgLT4gcG9pbnQNCg0KY29vcmRpbmF0ZXMocG9pbnQpIDwtIGMoIngiLCJ5IikNCnByb2o0c3RyaW5nKHBvaW50KT1DUlMoIitpbml0PWVwc2c6MjY5MTAiKSANCmNvb3JkIDwtc3BUcmFuc2Zvcm0ocG9pbnQsQ1JTKCIraW5pdD1lcHNnOjQzMjYiKSkNCg0KbWFwdmlldyhjb29yZCwgeGNvbCA9ICJ4IiwgeWNvbCA9ICJ5IiwgIGNycyA9IDQzMjYpDQpgYGANCg0KQnV0IHRoYXQgaXMgYWJvdXQgYXMgZmFyIGFzIEkgd2FudCB0byBnbyB3aXRoIG1hcHBpbmcgdGhlIGRhdGEgKGFsdGhvdWdoIHNvbWVvbmUgZGlkIGEgY29vbCBkeW5hbWljIHZpc3VhbGl6YXRpb24gdHJhY2tpbmcgZnJvZyBtb3ZlbWVudHMuLi4pLiAgQW55d2F5LCBiYWNrIHRvIHRoZSBtYWluIHRhc2suICBMZXQncyBlc3RhYmxpc2ggdGhlIHN0YXJ0IGNvb3JkaW5hdGVzIGZvciBlYWNoIG9mIG91ciBmcm9nZ3ktYm9paXMgYW5kIGNhbGN1bGF0ZSB0aGVpciBkaXN0YW5jZXM6DQoNCmBgYHtyfQ0KDQpmcm9ncyAlPiUgDQogIGZpbHRlcihJbnRlcnZhbCA9PSAwKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoRnJlcXVlbmN5LCB4MCA9IFVUTUVfODMsIHkwID0gVVRNTl84MykgJT4lIA0KICBtZXJnZSguLGZyb2dzLGJ5PSJGcmVxdWVuY3kiKSAtPiBmcm9ncw0KDQpmcm9ncyRkaXN0IDwtIGRpc3QoeDAgPSBmcm9ncyR4MCwNCiAgICAgICAgICAgICAgICAgICB4MSA9IGZyb2dzJFVUTUVfODMsDQogICAgICAgICAgICAgICAgICAgeTAgPSBmcm9ncyR5MCwNCiAgICAgICAgICAgICAgICAgICB5MSA9IGZyb2dzJFVUTU5fODMpDQpgYGANCg0KRXhjZWxsZW50LiAgTm93IGxldCdzIHJlcGxpY2F0ZSB0aGUgZ3JhcGhpYy4gIFRoZSBkZXNjcmlwdGlvbiBpbiB0aGUgcGFwZXIgc3RhdGVzIHRoYXQgdGhleSBvbmx5IGxvb2sgYXQgZnJvZ3Mgd2l0aCBlaWdodCBvciBtb3JlIGxvY2F0aW9ucywgc28gbGV0J3MgdGFrZSBhIGdhbmRlcjoNCg0KYGBge3IsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KDQphcy5EYXRlKGZyb2dzJFN1cnZleURhdGUsIGZvcm1hdCA9ICIlbS8lZC8lWSIpICU+JSANCiAgZm9ybWF0KC4sICIlYiAlZCAlWSIpICU+JSANCiAgYXMuRGF0ZSguLCIlYiAlZCAlWSIpIC0+IGZyb2dzJG5ld19kYXRlDQoNCmZyb2dzICU+JSANCiAgZ3JvdXBfYnkoRnJlcXVlbmN5KSAlPiUgDQogIG11dGF0ZShvYnMgPSBtYXgoSW50ZXJ2YWwpKSAlPiUgDQogIGZpbHRlcihvYnMgPj0gOCkgLT4gbGVzc19mcm9ncw0KDQpsZXNzX2Zyb2dzICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gbmV3X2RhdGUsIHkgPSBkaXN0LCBjb2wgPSBhcy5mYWN0b3IoRnJlcXVlbmN5KSkpICsNCiAgICBmYWNldF9ncmlkKH5IYWJUeXBlKSArDQogICAgZ2VvbV9wb2ludCgpICsNCiAgICBnZW9tX2xpbmUoKSArDQogICAgdGhlbWVfYncoKSArDQogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG9yPSdibGFjaycpLA0KICAgICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCkpICsNCiAgICBzY2FsZV94X2RhdGUoZGF0ZV9sYWJlbHMgPSAiJWIgJWQiLA0KICAgICAgICAgICAgICAgICBkYXRlX2JyZWFrcyA9ICI3IGRheXMiKSArDQogICAgeWxhYigiRGlzdGFuY2UgZnJvbSBSZWxlYXNlIFNpdGUgKG0pIikgKw0KICAgIHhsYWIoIiIpDQoNCmBgYA0KDQpHb29kIGVub3VnaCBmb3IgZ292ZXJubWVudCB3b3JrOyB0aGUgaW1hZ2UgaXMgaWRlbnRpY2FsIHRvIHRoZSBwdWJsaXNoZWQgaW1hZ2Ugb3RoZXIgdGhhbiAoMSkgY29sb3JpbmcgYnkgaW5kaXZpZHVhbCBmcm9nIHJhdGhlciB0aGFuIEhhYml0YXQgVHlwZSwgd2hpY2ggaXMgYWxyZWFkeSBpbmRpY2F0ZWQgYnkgdGhlIGZhY2V0IGFuZCAoMikgbWlub3IgZGlmZmVyZW5jZXMgaW4gdGhlIHgtYXhpcy4NCg0KTm93IHdoYXQgbW9yZSBjYW4gd2UgZG8/ICBJbnN0ZWFkIG9mIGxvb2tpbmcgYXQgdGhlIGRpc3RhbmNlIGZyb20gdGhlIHJlbGVhc2Ugc2l0ZSwgd2UgbWlnaHQgaW5zdGVhZCBiZSBpbnRlcmVzdGVkIGluIHRoZSB0b3RhbCBtb3ZlbWVudCB0aGUgZnJvZy4gIFRoaXMgY291bGQgZGlmZmVyIGZyb20gdGhlIGFib3ZlIGlmLCBzYXksIGEgZnJvZyB3YXMgaG9wcGluZyBpbiBhIGNpcmNsZSBlcXVhbCBkaXN0YW5jZSBmcm9tIHRoZWlyIGNhcHR1cmUgc2l0ZS4NCg0KYGBge3IsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KDQpmcm9ncyAlPiUgDQogIGdyb3VwX2J5KEZyZXF1ZW5jeSkgJT4lIA0KICBtdXRhdGUoeF9sYWcgPSBsYWcoVVRNRV84MyksDQogICAgICAgICB5X2xhZyA9IGxhZyhVVE1OXzgzKSwNCiAgICAgICAgIG1vdmUgPSBkaXN0KHgwID0geF9sYWcsDQogICAgICAgICAgICAgICAgICAgICB4MSA9IFVUTUVfODMsDQogICAgICAgICAgICAgICAgICAgICB5MCA9IHlfbGFnLA0KICAgICAgICAgICAgICAgICAgICAgeTEgPSBVVE1OXzgzKSkgLT4gZnJvZ3MNCg0KZnJvZ3MgJT4lIA0KICBncm91cF9ieShGcmVxdWVuY3kpICU+JSANCiAgbXV0YXRlKG9icyA9IG1heChJbnRlcnZhbCkpICU+JSANCiAgZmlsdGVyKG9icyA+PSA4KSAtPiBsZXNzX2Zyb2dzDQoNCmxlc3NfZnJvZ3MgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBuZXdfZGF0ZSwgeSA9IG1vdmUsIGNvbCA9IGFzLmZhY3RvcihGcmVxdWVuY3kpKSkgKw0KICAgIGZhY2V0X2dyaWQofkhhYlR5cGUpICsNCiAgICBnZW9tX3BvaW50KCkgKw0KICAgIGdlb21fbGluZSgpICsNCiAgICB0aGVtZV9idygpICsNCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwNCiAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoY29sb3I9J2JsYWNrJyksDQogICAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICAgIHNjYWxlX3hfZGF0ZShkYXRlX2xhYmVscyA9ICIlYiAlZCIsDQogICAgICAgICAgICAgICAgIGRhdGVfYnJlYWtzID0gIjcgZGF5cyIpICsNCiAgICB5bGFiKCJEaXN0YW5jZSBmcm9tIFByZXZpb3VzIExvY2F0aW9uIChtKSIpICsNCiAgICB4bGFiKCIiKSAtPiBmMQ0KZjENCg0KYGBgDQoNCk9uZSBtaWdodCBzYXkgdGhhdCB0aGUgZnJvZ3MgaG9wIGFyb3VuZCBhIGJpdC4gIExldCdzIGRvIGEgYml0IGJldHRlciBieSByZXNjYWxpbmcgdGhlIHkgYXhpcy4NCg0KYGBge3IsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KZjEgKw0KICBzY2FsZV95X2NvbnRpbnVvdXModHJhbnMgPSAibG9nIikNCmBgYA0KDQpUd28gdGhpbmdzIGFyZSB3b3J0aCBub3RlLiAgRmlyc3QgaXMgdGhhdCB0aGVyZSBhcHBlYXIgdG8gYmUgc2xpZ2h0IGRvd253YXJkIHRyZW5kIGZvciBlYWNoIGdyb3VwLiAgTGV0J3MgYXBwbHkgYSBjeWNsaWMgc21vb3RoZXIgdG8gdGhlc2UgaW5kaXZpZHVhbCBjdXJ2ZXMuICBOb3RpbmcgdGhhdCAiT3JkaW5hbCIgaXMgdGhlIGRheSBvZiB0aGUgeWVhciB3ZSB3aWxsIHRha2UgdGhlIHF1aWNrIGJydXRpc2ggYXBwcm9hY2ggdG8gdGhlIHByb2JsZW0sIGVzdGltYXRpbmcgYSBzbW9vdGggY3VydmUgZm9yIGVhY2ggZnJvZyBpbiBzZXBhcmF0ZSBtb2RlbHMuICBUbyBtYWtlIGl0IGEgYml0IG1vcmUgaW50ZXJlc3RpbmcsIHdlIHdpbGwgb25seSBsb29rIGF0IHRoZSB0b3AtaG9wcGVycy4NCg0KYGBge3IsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KbGVzc19mcm9ncyRpZCA8LSBhcy5mYWN0b3IobGVzc19mcm9ncyRGcmVxdWVuY3kpDQppZHMgPC0gdW5pcXVlKGxlc3NfZnJvZ3MkaWQpDQoNCg0KbGFwcGx5KGlkcywgZnVuY3Rpb24oaSl7DQogIGxlc3NfZnJvZ3MgJT4lIA0KICAgIGZpbHRlcihpZCA9PSBpKSAlPiUgDQogICAgZ2FtKGxvZyhtb3ZlICsgMSkgfiBzKE9yZGluYWwsIGJzID0gImNjIiwgayA9IDUpLCBkYXRhID0gLikNCn0pIC0+IG1vZHMNCg0KcHJlZF9iYXNlIDwtIGRhdGEuZnJhbWUoT3JkaW5hbCA9IHVuaXF1ZShsZXNzX2Zyb2dzJE9yZGluYWwpKQ0KDQpwcmVkcyA8LSBsaXN0KCkNCmZvcihpIGluIDE6bGVuZ3RoKG1vZHMpKXsNCiAgbW9kIDwtIG1vZHNbW2ldXQ0KICBwcmVkX2ZyYW1lIDwtIHByZWRfYmFzZQ0KICBwcmVkX2ZyYW1lJGlkIDwtIGlkc1tpXQ0KICBwcmVkX2ZyYW1lJHAgPC0gcHJlZGljdChtb2QscHJlZF9mcmFtZSkNCiAgcHJlZHNbW2ldXSA8LSBwcmVkX2ZyYW1lDQp9DQoNCnByZWRzIDwtIGRvLmNhbGwoInJiaW5kIixwcmVkcykNCg0KcHJlZHMgJT4lIA0KICBncm91cF9ieShpZCkgJT4lIA0KICBtdXRhdGUodmFyID0gc2QocCkpIC0+IHByZWRzDQoNCnByZWRzICU+JQ0KICBmaWx0ZXIodmFyID4gMC41KSAlPiUgDQogIGdncGxvdChhZXMoeCA9IE9yZGluYWwsIHkgPSBwLCBjb2xvciA9IGlkKSkgKw0KICBnZW9tX2xpbmUobHdkID0gMS4wMSkgKw0KICB0aGVtZV9idygpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArDQogIHhsYWIoIlRpbWUiKSArDQogIHlsYWIoIkRpc3RhbmNlIikgKw0KICBnZ3RpdGxlKCJTb21lIEhvcHB5IEJvaWlzIikNCmBgYA0KDQpUaGVzZSBmcm9ncyBhbGwsIG1vcmUgb3IgbGVzcywgaG9wcGVkIGF3YXkgYWZ0ZXIgY2FwdHVyZSwgZm91bmQgYSBsb2NhdGlvbiB0aGV5IGxpa2VkIGZvciBhIGJpdCwgdGhlbiBrZXB0IG9uIGhvcHBpbmcuICANCg0KVGhhdCdzIGFsbCBJIGFtIGRvaW5nIHdpdGggdGhpcyBkYXRhLiAgSSBzdGlsbCB0aGluayBpdCB3b3VsZCBiZSBmdW4gdG8gcGxheSBhcm91bmQgd2l0aCB0aGUgaW1hZ2Ugb2YgdGhpcyBob3BweSBib2lpLCBidXQgd2lsbCBsZWF2ZSB0aGF0IGZvciBhbm90aGVyIGRheS4NCg0KYGBge3IsIGVjaG89RkFMU0UsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KIyBEZWZpbmUgdmFyaWFibGUgY29udGFpbmluZyB1cmwNCnVybCA8LSAiaHR0cHM6Ly9naXRodWIuY29tL3Jmb3JkYXRhc2NpZW5jZS90aWR5dHVlc2RheS9ibG9iL21hc3Rlci9kYXRhLzIwMjIvMjAyMi0wOC0wMi9waWMxLnBuZz9yYXc9dHJ1ZSINCmBgYA0KDQo8Y2VudGVyPjxpbWcgc3JjPSJgciB1cmxgIj48L2NlbnRlcj4NCg0K