Notebook description: Basic data wrangling and visualization practice

Data source: TidyTuesday Washington Hiking from Washington Trails Association

Load packages

library(rvest)
library(tidyverse)
library(here)
library(ggplot2)
library(plotly)
library(Hmisc)
library(ggsci)

Get data

scrape_trails <- function(start_int){
  page_url <- paste0(
    "https://www.wta.org/go-outside/hikes?b_start:int=",
    start_int
  )
  
  page_html <- read_html(page_url)
  
  page_html %>% 
    
    html_nodes(".search-result-item") %>% 
    
    map(
      function(hike){
        
        hike_name <- hike %>% html_nodes(".listitem-title") %>% html_nodes("span") %>%  html_text()
        hike_location <- hike %>% html_node("h3") %>% html_text()
        
        hike_stats <- hike %>% html_node(".hike-stats")
        
        hike_length <- hike_stats %>% html_nodes(".hike-length") %>%html_nodes("span") %>%  html_text()
        hike_gain <- hike_stats %>% html_nodes(".hike-gain") %>%html_nodes("span") %>%  html_text()
        hike_highpoint <- hike_stats %>% html_nodes(".hike-highpoint") %>%html_nodes("span") %>%  html_text()
        hike_rating <- hike_stats %>% html_nodes(".hike-rating") %>%html_nodes(".current-rating") %>%  html_text()
        
        hike_desc <- hike %>% html_nodes(".listing-summary") %>% html_text()
        
        hike_features <- hike %>% html_nodes(".trip-features") %>% html_nodes("img") %>% html_attr("title") %>% list()
        
        tibble(
          name = hike_name,
          location = hike_location,
          length = hike_length,
          gain = hike_gain,
          highpoint = hike_highpoint,
          rating = hike_rating,
          features = hike_features,
          description = hike_desc
        )
      }) %>% 
    bind_rows() %>% 
    mutate(description = str_remove(description, "\n") %>% str_squish())
}

start_int <- c(1, seq(30, 3840, by = 30))

hike_data <- start_int %>% 
  map_dfr(scrape_trails)
clean_hike_data <- hike_data %>% 
  mutate(
    trip = case_when(
      grepl("roundtrip",length) ~ "roundtrip",
      grepl("one-way",length) ~ "one-way",
      grepl("of trails",length) ~ "trails"),
    
    length_total = as.numeric(gsub("(\\d+[.]\\d+).*","\\1", length)) * ((trip == "one-way") + 1),
    
    gain = as.numeric(gain),
    highpoint = as.numeric(highpoint),
    
    location_general = gsub("(.*)\\s[-][-].*","\\1",location)
  )
hike_plot <- ggplot(clean_hike_data) + 
  geom_rect(aes(
    xmin = 0,
    xmax = length_total,
    ymin = 0,
    ymax = gain,
    label = name
  ),
  alpha = .4,
  fill = "#228B22",
  color = "#765C48"
  ) + 
  facet_wrap(
    ~ location_general,
    scales = "free_x"
  ) +
  labs(
    title = "Washington State Hikes",
    x = "Hike Length (miles)",
    y = "Hike Elevation Gain (ft)",
    caption = "Data from Washingon Trails Association (wta.org) | Viz by @ellis_hughes"
  )

ggplotly(hike_plot)
dim(clean_hike_data)
colnames(clean_hike_data)

Dog friendly trails

clean_hike_data$dogs = ifelse(grepl("leash", clean_hike_data$features), "Yes","No")
Hmisc::describe(clean_hike_data$dogs)

*1044 out of 1957 trails allow dogs on leash

clean_hike_data %>% group_by(location_general,dogs) %>% tally() %>% ggplot(aes(x=dogs, y=n, fill=dogs)) + geom_col() + facet_wrap(~location_general) + theme_minimal() + theme(
    panel.grid.major.x = element_blank(),
    panel.border = element_blank(),
    axis.ticks.x = element_blank(),
    axis.ticks.y = element_blank(),
    panel.grid.major.y = element_blank(),
    panel.grid.minor.x = element_blank(),
    panel.grid.minor.y = element_blank(),
    axis.text.x=element_blank(),
    plot.title = element_text(size=12, face="bold"),
    plot.subtitle = element_text(size=10, color="#343a40"),
    legend.title=element_text(size=9),
    legend.position = "top") + scale_fill_jama() + 
    labs(y="", x="", fill="Dogs allowed on leash", title = "Dog Friendly Trails In Washington", subtitle="1044 out of 1957 trails allow dogs on leash", caption="Data from Washingon Trails Association (wta.org)")

Ratings

summary(as.numeric(clean_hike_data$rating))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   2.600   3.400   2.986   4.000   5.000 
sum(is.na(clean_hike_data$rating))
[1] 0
median_values <- clean_hike_data %>%
  group_by(location_general) %>%
  summarise(
    med = median(as.numeric(rating))) %>% ungroup()

ggplot(clean_hike_data, aes(x = reorder(location_general, rating, FUN = median), y = rating)) +
  geom_boxplot(aes(color = location_general)) +
  geom_point(data = median_values, aes(x = location_general, y = med, fill = location_general), shape = 23, size = 5, color = "grey") +
  guides(fill = FALSE, color = FALSE) +
  coord_flip() +
  labs(y = "Rating", x = "General Location", title = "Washington Trail Ratings by General Location", caption = "Data from Washingon Trails Association (wta.org)") +
  theme_light() +
  scale_color_futurama() +
  scale_fill_futurama() +
 theme(
    axis.ticks.x = element_blank(),
    axis.ticks.y = element_blank(),
    panel.grid.major.y = element_blank(),
    panel.grid.minor.x = element_blank(),
    panel.grid.major.x = element_blank(),
    plot.title = element_text(size=12, face="bold"),
    axis.title = element_text(size=10),
    panel.border = element_blank(),
    legend.position="none"
  ) 

One-way vs Roundtrip trails

clean_hike_data %>% group_by(location_general,trip) %>% tally() %>% filter(trip !="trails") %>% ggplot(aes(x=location_general, y=n, fill=trip)) + geom_col(position="dodge") + coord_flip() + theme_light() + theme(
    panel.grid.major.x = element_blank(),
    panel.border = element_blank(),
    axis.ticks.x = element_blank(),
    axis.ticks.y = element_blank(),
    panel.grid.major.y = element_blank(),
    panel.grid.minor.x = element_blank(),
    panel.grid.minor.y = element_blank(),
    plot.title = element_text(size=12, face="bold"),
    plot.subtitle = element_text(size=10, color="#343a40"),
    legend.title=element_text(size=9),
    legend.position = "right") +
    labs(y="", x="", fill="", title = "One-way vs Roundtrip trails in Washington", caption="Data from Washingon Trails Association (wta.org)") +
    scale_fill_jama()

Features

#cleaning script from @alexcookson
hike_data_raw <- read_rds(url('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2020/2020-11-24/hike_data.rds'))

hike <- hike_data_raw %>%
  distinct(name, location, .keep_all = TRUE) %>%
  mutate(trail_id = row_number()) %>%
  relocate(trail_id) %>%
  mutate(across(.cols = c(length, gain, highpoint, rating), parse_number)) %>%
  rename(length_miles = length,
         gain_ft = gain,
         highpoint_ft = highpoint) %>%
  mutate(rating = ifelse(rating == 0, NA, rating))

features <- hike %>%
  select(trail_id, features) %>%
  unnest(features) %>%
  rename(feature = features)
features %>% group_by(feature) %>% tally(sort=T) %>% 
  ggplot(aes(x=reorder(feature,n), y=n)) +
  geom_segment(aes(x=reorder(feature,n), xend=feature, y=0, yend=n), color="#084c61") +
  geom_point(color="#4f772d", size=3, alpha=0.9) + scale_color_viridis() +
  theme_light() +
  coord_flip() + 
  theme(
    panel.border = element_blank(),
    axis.ticks.x = element_blank(),
    axis.ticks.y = element_blank(),
    panel.grid.major.y = element_blank(),
    panel.grid.minor.x = element_blank(),
    panel.grid.minor.y = element_blank(),
    plot.title = element_text(size=12, face="bold"),
    axis.title= element_text(size=10),
    legend.position = "right") +
    labs(y="Number of Trails", x="Feature", fill="", title = "Washington Trails Features", caption="Data from Washingon Trails Association (wta.org)")

LS0tCnRpdGxlOiAiV2FzaGluZ3RvbiBUcmFpbHMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCioqTm90ZWJvb2sgZGVzY3JpcHRpb24qKjogQmFzaWMgZGF0YSB3cmFuZ2xpbmcgYW5kIHZpc3VhbGl6YXRpb24gcHJhY3RpY2UgCgoqKkRhdGEgc291cmNlKio6IFRpZHlUdWVzZGF5IFtXYXNoaW5ndG9uIEhpa2luZ10oaHR0cHM6Ly9naXRodWIuY29tL3Jmb3JkYXRhc2NpZW5jZS90aWR5dHVlc2RheS9ibG9iL21hc3Rlci9kYXRhLzIwMjAvMjAyMC0xMS0yNC9yZWFkbWUubWQpIGZyb20gW1dhc2hpbmd0b24gVHJhaWxzIEFzc29jaWF0aW9uXShodHRwczovL3d3dy53dGEub3JnL2dvLW91dHNpZGUvaGlrZXM/Yl9zdGFydDppbnQ9MSkKCiMjIyBMb2FkIHBhY2thZ2VzCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0KbGlicmFyeShydmVzdCkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoaGVyZSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShIbWlzYykKbGlicmFyeShnZ3NjaSkKYGBgCgojIyMgR2V0IGRhdGEKYGBge3J9CnNjcmFwZV90cmFpbHMgPC0gZnVuY3Rpb24oc3RhcnRfaW50KXsKICBwYWdlX3VybCA8LSBwYXN0ZTAoCiAgICAiaHR0cHM6Ly93d3cud3RhLm9yZy9nby1vdXRzaWRlL2hpa2VzP2Jfc3RhcnQ6aW50PSIsCiAgICBzdGFydF9pbnQKICApCiAgCiAgcGFnZV9odG1sIDwtIHJlYWRfaHRtbChwYWdlX3VybCkKICAKICBwYWdlX2h0bWwgJT4lIAogICAgCiAgICBodG1sX25vZGVzKCIuc2VhcmNoLXJlc3VsdC1pdGVtIikgJT4lIAogICAgCiAgICBtYXAoCiAgICAgIGZ1bmN0aW9uKGhpa2UpewogICAgICAgIAogICAgICAgIGhpa2VfbmFtZSA8LSBoaWtlICU+JSBodG1sX25vZGVzKCIubGlzdGl0ZW0tdGl0bGUiKSAlPiUgaHRtbF9ub2Rlcygic3BhbiIpICU+JSAgaHRtbF90ZXh0KCkKICAgICAgICBoaWtlX2xvY2F0aW9uIDwtIGhpa2UgJT4lIGh0bWxfbm9kZSgiaDMiKSAlPiUgaHRtbF90ZXh0KCkKICAgICAgICAKICAgICAgICBoaWtlX3N0YXRzIDwtIGhpa2UgJT4lIGh0bWxfbm9kZSgiLmhpa2Utc3RhdHMiKQogICAgICAgIAogICAgICAgIGhpa2VfbGVuZ3RoIDwtIGhpa2Vfc3RhdHMgJT4lIGh0bWxfbm9kZXMoIi5oaWtlLWxlbmd0aCIpICU+JWh0bWxfbm9kZXMoInNwYW4iKSAlPiUgIGh0bWxfdGV4dCgpCiAgICAgICAgaGlrZV9nYWluIDwtIGhpa2Vfc3RhdHMgJT4lIGh0bWxfbm9kZXMoIi5oaWtlLWdhaW4iKSAlPiVodG1sX25vZGVzKCJzcGFuIikgJT4lICBodG1sX3RleHQoKQogICAgICAgIGhpa2VfaGlnaHBvaW50IDwtIGhpa2Vfc3RhdHMgJT4lIGh0bWxfbm9kZXMoIi5oaWtlLWhpZ2hwb2ludCIpICU+JWh0bWxfbm9kZXMoInNwYW4iKSAlPiUgIGh0bWxfdGV4dCgpCiAgICAgICAgaGlrZV9yYXRpbmcgPC0gaGlrZV9zdGF0cyAlPiUgaHRtbF9ub2RlcygiLmhpa2UtcmF0aW5nIikgJT4laHRtbF9ub2RlcygiLmN1cnJlbnQtcmF0aW5nIikgJT4lICBodG1sX3RleHQoKQogICAgICAgIAogICAgICAgIGhpa2VfZGVzYyA8LSBoaWtlICU+JSBodG1sX25vZGVzKCIubGlzdGluZy1zdW1tYXJ5IikgJT4lIGh0bWxfdGV4dCgpCiAgICAgICAgCiAgICAgICAgaGlrZV9mZWF0dXJlcyA8LSBoaWtlICU+JSBodG1sX25vZGVzKCIudHJpcC1mZWF0dXJlcyIpICU+JSBodG1sX25vZGVzKCJpbWciKSAlPiUgaHRtbF9hdHRyKCJ0aXRsZSIpICU+JSBsaXN0KCkKICAgICAgICAKICAgICAgICB0aWJibGUoCiAgICAgICAgICBuYW1lID0gaGlrZV9uYW1lLAogICAgICAgICAgbG9jYXRpb24gPSBoaWtlX2xvY2F0aW9uLAogICAgICAgICAgbGVuZ3RoID0gaGlrZV9sZW5ndGgsCiAgICAgICAgICBnYWluID0gaGlrZV9nYWluLAogICAgICAgICAgaGlnaHBvaW50ID0gaGlrZV9oaWdocG9pbnQsCiAgICAgICAgICByYXRpbmcgPSBoaWtlX3JhdGluZywKICAgICAgICAgIGZlYXR1cmVzID0gaGlrZV9mZWF0dXJlcywKICAgICAgICAgIGRlc2NyaXB0aW9uID0gaGlrZV9kZXNjCiAgICAgICAgKQogICAgICB9KSAlPiUgCiAgICBiaW5kX3Jvd3MoKSAlPiUgCiAgICBtdXRhdGUoZGVzY3JpcHRpb24gPSBzdHJfcmVtb3ZlKGRlc2NyaXB0aW9uLCAiXG4iKSAlPiUgc3RyX3NxdWlzaCgpKQp9CgpzdGFydF9pbnQgPC0gYygxLCBzZXEoMzAsIDM4NDAsIGJ5ID0gMzApKQoKaGlrZV9kYXRhIDwtIHN0YXJ0X2ludCAlPiUgCiAgbWFwX2RmcihzY3JhcGVfdHJhaWxzKQoKc2F2ZVJEUyhoaWtlX2RhdGEsZmlsZSA9ICIvaGlrZV9kYXRhLnJkcyIpCmBgYAoKCmBgYHtyfQpjbGVhbl9oaWtlX2RhdGEgPC0gaGlrZV9kYXRhICU+JSAKICBtdXRhdGUoCiAgICB0cmlwID0gY2FzZV93aGVuKAogICAgICBncmVwbCgicm91bmR0cmlwIixsZW5ndGgpIH4gInJvdW5kdHJpcCIsCiAgICAgIGdyZXBsKCJvbmUtd2F5IixsZW5ndGgpIH4gIm9uZS13YXkiLAogICAgICBncmVwbCgib2YgdHJhaWxzIixsZW5ndGgpIH4gInRyYWlscyIpLAogICAgCiAgICBsZW5ndGhfdG90YWwgPSBhcy5udW1lcmljKGdzdWIoIihcXGQrWy5dXFxkKykuKiIsIlxcMSIsIGxlbmd0aCkpICogKCh0cmlwID09ICJvbmUtd2F5IikgKyAxKSwKICAgIAogICAgZ2FpbiA9IGFzLm51bWVyaWMoZ2FpbiksCiAgICBoaWdocG9pbnQgPSBhcy5udW1lcmljKGhpZ2hwb2ludCksCiAgICAKICAgIGxvY2F0aW9uX2dlbmVyYWwgPSBnc3ViKCIoLiopXFxzWy1dWy1dLioiLCJcXDEiLGxvY2F0aW9uKQogICkKCmBgYAoKYGBge3IsIGZpZy5zaG93PSdoaWRlJywgbWVzc2FnZT1GQUxTRX0KaGlrZV9wbG90IDwtIGdncGxvdChjbGVhbl9oaWtlX2RhdGEpICsgCiAgZ2VvbV9yZWN0KGFlcygKICAgIHhtaW4gPSAwLAogICAgeG1heCA9IGxlbmd0aF90b3RhbCwKICAgIHltaW4gPSAwLAogICAgeW1heCA9IGdhaW4sCiAgICBsYWJlbCA9IG5hbWUKICApLAogIGFscGhhID0gLjQsCiAgZmlsbCA9ICIjMjI4QjIyIiwKICBjb2xvciA9ICIjNzY1QzQ4IgogICkgKyAKICBmYWNldF93cmFwKAogICAgfiBsb2NhdGlvbl9nZW5lcmFsLAogICAgc2NhbGVzID0gImZyZWVfeCIKICApICsKICBsYWJzKAogICAgdGl0bGUgPSAiV2FzaGluZ3RvbiBTdGF0ZSBIaWtlcyIsCiAgICB4ID0gIkhpa2UgTGVuZ3RoIChtaWxlcykiLAogICAgeSA9ICJIaWtlIEVsZXZhdGlvbiBHYWluIChmdCkiLAogICAgY2FwdGlvbiA9ICJEYXRhIGZyb20gV2FzaGluZ29uIFRyYWlscyBBc3NvY2lhdGlvbiAod3RhLm9yZykgfCBWaXogYnkgQGVsbGlzX2h1Z2hlcyIKICApCgpnZ3Bsb3RseShoaWtlX3Bsb3QpCmBgYAoKCmBgYHtyfQpkaW0oY2xlYW5faGlrZV9kYXRhKQpjb2xuYW1lcyhjbGVhbl9oaWtlX2RhdGEpCmBgYAoKIyMjIERvZyBmcmllbmRseSB0cmFpbHMgCgpgYGB7cn0KY2xlYW5faGlrZV9kYXRhJGRvZ3MgPSBpZmVsc2UoZ3JlcGwoImxlYXNoIiwgY2xlYW5faGlrZV9kYXRhJGZlYXR1cmVzKSwgIlllcyIsIk5vIikKSG1pc2M6OmRlc2NyaWJlKGNsZWFuX2hpa2VfZGF0YSRkb2dzKQpgYGAKKjEwNDQgb3V0IG9mIDE5NTcgdHJhaWxzIGFsbG93IGRvZ3Mgb24gbGVhc2ggCgpgYGB7cn0KY2xlYW5faGlrZV9kYXRhICU+JSBncm91cF9ieShsb2NhdGlvbl9nZW5lcmFsLGRvZ3MpICU+JSB0YWxseSgpICU+JSBnZ3Bsb3QoYWVzKHg9ZG9ncywgeT1uLCBmaWxsPWRvZ3MpKSArIGdlb21fY29sKCkgKyBmYWNldF93cmFwKH5sb2NhdGlvbl9nZW5lcmFsKSArIHRoZW1lX21pbmltYWwoKSArIHRoZW1lKAogICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEyLCBmYWNlPSJib2xkIiksCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTAsIGNvbG9yPSIjMzQzYTQwIiksCiAgICBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9OSksCiAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIikgKyBzY2FsZV9maWxsX2phbWEoKSArIAogICAgbGFicyh5PSIiLCB4PSIiLCBmaWxsPSJEb2dzIGFsbG93ZWQgb24gbGVhc2giLCB0aXRsZSA9ICJEb2cgRnJpZW5kbHkgVHJhaWxzIEluIFdhc2hpbmd0b24iLCBzdWJ0aXRsZT0iMTA0NCBvdXQgb2YgMTk1NyB0cmFpbHMgYWxsb3cgZG9ncyBvbiBsZWFzaCIsIGNhcHRpb249IkRhdGEgZnJvbSBXYXNoaW5nb24gVHJhaWxzIEFzc29jaWF0aW9uICh3dGEub3JnKSIpCmBgYAoKIyMjIFJhdGluZ3MKYGBge3J9CnN1bW1hcnkoYXMubnVtZXJpYyhjbGVhbl9oaWtlX2RhdGEkcmF0aW5nKSkKc3VtKGlzLm5hKGNsZWFuX2hpa2VfZGF0YSRyYXRpbmcpKQpgYGAKCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0KbWVkaWFuX3ZhbHVlcyA8LSBjbGVhbl9oaWtlX2RhdGEgJT4lCiAgZ3JvdXBfYnkobG9jYXRpb25fZ2VuZXJhbCkgJT4lCiAgc3VtbWFyaXNlKAogICAgbWVkID0gbWVkaWFuKGFzLm51bWVyaWMocmF0aW5nKSkpICU+JSB1bmdyb3VwKCkKCmdncGxvdChjbGVhbl9oaWtlX2RhdGEsIGFlcyh4ID0gcmVvcmRlcihsb2NhdGlvbl9nZW5lcmFsLCByYXRpbmcsIEZVTiA9IG1lZGlhbiksIHkgPSByYXRpbmcpKSArCiAgZ2VvbV9ib3hwbG90KGFlcyhjb2xvciA9IGxvY2F0aW9uX2dlbmVyYWwpKSArCiAgZ2VvbV9wb2ludChkYXRhID0gbWVkaWFuX3ZhbHVlcywgYWVzKHggPSBsb2NhdGlvbl9nZW5lcmFsLCB5ID0gbWVkLCBmaWxsID0gbG9jYXRpb25fZ2VuZXJhbCksIHNoYXBlID0gMjMsIHNpemUgPSA1LCBjb2xvciA9ICJncmV5IikgKwogIGd1aWRlcyhmaWxsID0gRkFMU0UsIGNvbG9yID0gRkFMU0UpICsKICBjb29yZF9mbGlwKCkgKwogIGxhYnMoeSA9ICJSYXRpbmciLCB4ID0gIkdlbmVyYWwgTG9jYXRpb24iLCB0aXRsZSA9ICJXYXNoaW5ndG9uIFRyYWlsIFJhdGluZ3MgYnkgR2VuZXJhbCBMb2NhdGlvbiIsIGNhcHRpb24gPSAiRGF0YSBmcm9tIFdhc2hpbmdvbiBUcmFpbHMgQXNzb2NpYXRpb24gKHd0YS5vcmcpIikgKwogIHRoZW1lX2xpZ2h0KCkgKwogIHNjYWxlX2NvbG9yX2Z1dHVyYW1hKCkgKwogIHNjYWxlX2ZpbGxfZnV0dXJhbWEoKSArCiB0aGVtZSgKICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xMiwgZmFjZT0iYm9sZCIpLAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSwKICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIKICApIApgYGAKCiMjIyBPbmUtd2F5IHZzIFJvdW5kdHJpcCB0cmFpbHMgCmBgYHtyfQpjbGVhbl9oaWtlX2RhdGEgJT4lIGdyb3VwX2J5KGxvY2F0aW9uX2dlbmVyYWwsdHJpcCkgJT4lIHRhbGx5KCkgJT4lIGZpbHRlcih0cmlwICE9InRyYWlscyIpICU+JSBnZ3Bsb3QoYWVzKHg9bG9jYXRpb25fZ2VuZXJhbCwgeT1uLCBmaWxsPXRyaXApKSArIGdlb21fY29sKHBvc2l0aW9uPSJkb2RnZSIpICsgY29vcmRfZmxpcCgpICsgdGhlbWVfbGlnaHQoKSArIHRoZW1lKAogICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEyLCBmYWNlPSJib2xkIiksCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTAsIGNvbG9yPSIjMzQzYTQwIiksCiAgICBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9OSksCiAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKSArCiAgICBsYWJzKHk9IiIsIHg9IiIsIGZpbGw9IiIsIHRpdGxlID0gIk9uZS13YXkgdnMgUm91bmR0cmlwIHRyYWlscyBpbiBXYXNoaW5ndG9uIiwgY2FwdGlvbj0iRGF0YSBmcm9tIFdhc2hpbmdvbiBUcmFpbHMgQXNzb2NpYXRpb24gKHd0YS5vcmcpIikgKwogICAgc2NhbGVfZmlsbF9qYW1hKCkKYGBgCgojIyMgRmVhdHVyZXMgCmBgYHtyfQojY2xlYW5pbmcgc2NyaXB0IGZyb20gQGFsZXhjb29rc29uCmhpa2VfZGF0YV9yYXcgPC0gcmVhZF9yZHModXJsKCdodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vcmZvcmRhdGFzY2llbmNlL3RpZHl0dWVzZGF5L21hc3Rlci9kYXRhLzIwMjAvMjAyMC0xMS0yNC9oaWtlX2RhdGEucmRzJykpCgpoaWtlIDwtIGhpa2VfZGF0YV9yYXcgJT4lCiAgZGlzdGluY3QobmFtZSwgbG9jYXRpb24sIC5rZWVwX2FsbCA9IFRSVUUpICU+JQogIG11dGF0ZSh0cmFpbF9pZCA9IHJvd19udW1iZXIoKSkgJT4lCiAgcmVsb2NhdGUodHJhaWxfaWQpICU+JQogIG11dGF0ZShhY3Jvc3MoLmNvbHMgPSBjKGxlbmd0aCwgZ2FpbiwgaGlnaHBvaW50LCByYXRpbmcpLCBwYXJzZV9udW1iZXIpKSAlPiUKICByZW5hbWUobGVuZ3RoX21pbGVzID0gbGVuZ3RoLAogICAgICAgICBnYWluX2Z0ID0gZ2FpbiwKICAgICAgICAgaGlnaHBvaW50X2Z0ID0gaGlnaHBvaW50KSAlPiUKICBtdXRhdGUocmF0aW5nID0gaWZlbHNlKHJhdGluZyA9PSAwLCBOQSwgcmF0aW5nKSkKCmZlYXR1cmVzIDwtIGhpa2UgJT4lCiAgc2VsZWN0KHRyYWlsX2lkLCBmZWF0dXJlcykgJT4lCiAgdW5uZXN0KGZlYXR1cmVzKSAlPiUKICByZW5hbWUoZmVhdHVyZSA9IGZlYXR1cmVzKQpgYGAKCmBgYHtyfQpmZWF0dXJlcyAlPiUgZ3JvdXBfYnkoZmVhdHVyZSkgJT4lIHRhbGx5KHNvcnQ9VCkgJT4lIAogIGdncGxvdChhZXMoeD1yZW9yZGVyKGZlYXR1cmUsbiksIHk9bikpICsKICBnZW9tX3NlZ21lbnQoYWVzKHg9cmVvcmRlcihmZWF0dXJlLG4pLCB4ZW5kPWZlYXR1cmUsIHk9MCwgeWVuZD1uKSwgY29sb3I9IiMwODRjNjEiKSArCiAgZ2VvbV9wb2ludChjb2xvcj0iIzRmNzcyZCIsIHNpemU9MywgYWxwaGE9MC45KSArIHNjYWxlX2NvbG9yX3ZpcmlkaXMoKSArCiAgdGhlbWVfbGlnaHQoKSArCiAgY29vcmRfZmxpcCgpICsgCiAgdGhlbWUoCiAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ncmlkLm1pbm9yLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTIsIGZhY2U9ImJvbGQiKSwKICAgIGF4aXMudGl0bGU9IGVsZW1lbnRfdGV4dChzaXplPTEwKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpICsKICAgIGxhYnMoeT0iTnVtYmVyIG9mIFRyYWlscyIsIHg9IkZlYXR1cmUiLCBmaWxsPSIiLCB0aXRsZSA9ICJXYXNoaW5ndG9uIFRyYWlscyBGZWF0dXJlcyIsIGNhcHRpb249IkRhdGEgZnJvbSBXYXNoaW5nb24gVHJhaWxzIEFzc29jaWF0aW9uICh3dGEub3JnKSIpCmBgYAoK