Tidy Tuesday Week 22 Mario Kart 64 World Records, data from Mario Kart World Records

# Load libaries 
library(tidyverse)
library(ggtext)
library(ggpubr)
library(ggstatsplot)
library(gt)
library(ggsci)
library(wesanderson)

theme_set(theme_minimal())
# Import data
records <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2021/2021-05-25/records.csv')

── Column specification ──────────────────────────────────────────────────────────────────────────────────
cols(
  track = col_character(),
  type = col_character(),
  shortcut = col_character(),
  player = col_character(),
  system_played = col_character(),
  date = col_date(format = ""),
  time_period = col_character(),
  time = col_double(),
  record_duration = col_double()
)
drivers <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2021/2021-05-25/drivers.csv')

── Column specification ──────────────────────────────────────────────────────────────────────────────────
cols(
  position = col_double(),
  player = col_character(),
  total = col_double(),
  year = col_double(),
  records = col_double(),
  nation = col_character()
)
# Which Mario Kart Track Is The Fastest?
# shared on [Twitter](https://twitter.com/leeolney3/status/1396980461134614528/photo/1)

table1 = records %>% 
  group_by(track, type, shortcut) %>%
  summarise(time_min=min(time)) %>%
  ungroup() %>%
  mutate(type_sc= ifelse(shortcut=="Yes", paste(type, "with","Shortcut"),type))

# dot plot
table1 %>% 
  ggplot(aes(x=fct_rev(fct_reorder(track, time_min, .fun='min')), y=time_min, 
             color=factor(type_sc, levels=c("Three Lap with Shortcut",
                                            "Single Lap with Shortcut",
                                            "Single Lap",
                                            "Three Lap")))) +
  geom_line(aes(group=track), color="grey",size=2,alpha=0.4) +
  #geom_point(position=position_dodge(0.4),size=2.2) +
  geom_point(position = position_jitterdodge(dodge.width = 0.5, jitter.height = 0.5),size=2.7)  +
  theme(legend.position="top",
        legend.justification = "left",
        plot.title.position = "plot",
        plot.title=element_text(hjust=0.5, face="bold",size=18),
        plot.margin=ggplot2::margin(1,1,0.5,1,"cm"),
        axis.title.x=element_markdown(size=10.5),
        axis.title.y=element_markdown(size=10.5)) + 
  labs(color="", x="**Track**",y="**Minimum Time** (in seconds)<br>",
       title="Which Mario Kart Track Is The Fastest?",
       caption="Tidy Tuesday Week 22 | Data from Mario Kart World Records") + 
  scale_color_manual(values=c("#f95738","#ffa62b","#0091ad","#43B047")) + 
  coord_flip() 

# For how many tracks have shortcuts been discovered?
records %>% 
  count(track, shortcut) %>%
  count(shortcut)
# For which track did the world record improve the most?
records %>% 
 group_by(track) %>% 
  summarise(min_time = min(time), max_time=max(time), improved=max_time-min_time) %>%
  arrange(desc(improved)) %>%
  mutate(improved_pct= round(improved/max_time*100,3)) %>%
  arrange(desc(improved_pct)) %>% slice(1)
# On which track the shortcut saves the most time 
table2 = records %>% 
  group_by(track, type, shortcut) %>%
  summarise(time=mean(time)) %>%
  pivot_wider(names_from = shortcut,values_from=time) %>%
  filter(!is.na(Yes)) %>%
  mutate(time_saved=No-Yes) %>% 
  arrange(desc(time_saved))

# time saved by race type
by(table2$time_saved, table2$type, summary) #no difference in Single lap with and without shortcut
table2$type: Single Lap
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
      0       0       0       0       0       0 
------------------------------------------------------------------------------- 
table2$type: Three Lap
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  1.516  38.977  59.911  78.928 102.340 242.578 
# On which track the shortcut saves the most time 
# dot plot: three lap
table4 = records %>% 
  group_by(track, type, shortcut) %>%
  summarise(time=mean(time)) %>% 
  filter(type=="Three Lap") %>%
  filter(track!="Banshee Boardwalk",track!="Bowser's Castle",
         track!="Koopa Troopa Beach",track!="Moo Moo Farm") %>%
  mutate(time_saved=lag(time)-time) %>%
  mutate(pct = round(time_saved/lag(time),3)) 

table5 = table4 %>% filter(shortcut=="Yes")

table5 %>%
  ggplot(aes(y=reorder(track,pct), x=time)) + 
  geom_text(aes(label=paste0("-",scales::percent(pct,accuracy=0.1L))),size=2.9, hjust=1.2, color="#3C5488FF") +
  geom_point(data=table4, aes(color=shortcut),size=2,show.legend = F) + 
  geom_line(data=table4, aes(group=track), alpha=0.3,size=1) + 
  scale_x_continuous(limits=c(0,370)) + 
  theme(panel.grid.major.x=element_blank(),
       panel.grid.minor.x=element_blank(),
       axis.title.x=element_markdown(size=10),
       axis.title.y=element_markdown(size=10),
       plot.title.position = "plot",
       plot.subtitle=element_markdown(size=10)) + 
  labs(x="**Average time** (in seconds)",
       y="**Track**",
       title="On which track the shortcut saves the most time for 3-lap?",
       subtitle="Percentage is expressed as (<span style = 'color:#E64B35FF'>No Shortcut</span> - <span style = 'color:#3C5488FF'>With Shortcut</span>) / <span style = 'color:#E64B35FF'>No Shortcut</span><br>") + 
  scale_color_manual(values=c("#E64B35FF","#3C5488FF"))

# On which track the shortcut saves the most time 
# highlighted slope chart: three lap
table2 %>%
  filter(type=="Three Lap") %>%
  pivot_longer(No:Yes) %>%
  mutate(name=ifelse(name=="No","No Shortcut","With Shortcut")) %>%
  mutate(value=round(value,1), time_saved=round(time_saved,1)) -> table3

table3 %>%
  ggplot(aes(x=name, y=value, group=track)) + 
  geom_line(aes(color=I(ifelse(track=="Wario Stadium", '#E64B35FF', '#8491b4FF')))) + 
  geom_point(aes(color=I(ifelse(track=="Wario Stadium", '#E64B35FF', '#8491b4FF')))) + 
  theme(legend.position = "none") + 
  scale_x_discrete(position="top") +
  geom_text(data= table3 %>% filter(track=="Wario Stadium") %>% filter(name=="No Shortcut"), 
            aes(label=paste0(value,"s")), size=3, color="#E64B35FF", hjust=1.2) +
  geom_text(data= table3 %>% filter(track=="Wario Stadium") %>% filter(name=="With Shortcut"), 
            aes(label=paste0(value,"s")), size=3, color="#E64B35FF", hjust=-0.5) + 
  geom_text(aes(x="No Shortcut",y=265.2, label="Wario Stadium"),size=3, color="#E64B35FF",hjust=1.7) + 
  theme(axis.text.x=element_text(face="bold",size=10, color="black"),
        axis.title.y=element_markdown(size=10),
        plot.title.position = "plot") +
  labs(x="",y="**Average time saved** (in seconds)",
       title="On which track the shortcut saves the most time for 3-lap?")

# When were shortcuts discovered?
records %>% group_by(track, shortcut) %>%
  summarise(sc_dis=min(date)) %>%
  filter(shortcut=="Yes") %>%
  mutate(shortcut=ifelse(shortcut=="Yes",1,"")) %>%
  ggplot(aes(y=shortcut,x=sc_dis)) + 
  geom_segment(aes(x=min(sc_dis), xend=max(sc_dis), y=shortcut, yend=shortcut)) +
  geom_point(aes(color=factor(sc_dis)),size=6,show.legend=F, shape=18) + 
  geom_text(aes(label=sc_dis), size=3, vjust=3, color="black") + 
  geom_text(aes(x=min(sc_dis),label="Luigi Raceway",y=1.03), size=3, color="#E64B35FF") + 
  geom_text(aes(x=as.Date(c("1997-03-07")),label="Rainbow Road\nYoshi Valley",y=1.048), 
            size=3, color="#00A087FF", hjust=0,nudge_x=-1.6) +
  geom_text(aes(x=as.Date(c("1997-03-10")),label="Choco Mountain\nD.K.'s Jungle Parkway\nFrappe Snowland\nKalimari Desert\nMario Raceway\nRoyal Raceway\nSherbet Land\nToad's Turnpike\nWario Stadium",y=1.125), size=3,hjust=0,nudge_x=-1.1, color="#3C5488FF") +
  scale_y_continuous(limits=c(0.85,1.35)) +
  scale_x_date(labels=scales::date_format("%d-%m-%Y"), limits=as.Date(c('1997-02-13','1997-03-14')),
               expand = c(0, 0), breaks = "1 week") +
  theme(axis.text=element_blank(),
        axis.title = element_blank(),
        panel.grid.minor=element_blank(),
        panel.grid.major.y=element_blank(),
        panel.grid.major.x=element_line(size=0.35)) + 
  geom_bracket(xmin=as.Date(c("1997-02-16")), xmax=as.Date(c("1997-03-07")), y.position=1.1, 
               label="19 days", label.size=3) +
  geom_bracket(xmin=as.Date(c("1997-03-07")), xmax=as.Date(c("1997-03-10")), y.position=1.25, 
               label="3 days", label.size=3) + 
  scale_color_manual(values=c("#E64B35FF","#00A087FF","#3C5488FF")) + 
  labs(title="When were shortcuts discovered?")

NA
# Which is the longest standing world record?
records %>% arrange(desc(record_duration)) %>% slice(1)
# Distribution of record duration across race types
ggbetweenstats(data=records, x=type, y=record_duration,
               title="Distribution of record duration across race types",
               type="np",
               plotgrid.args=list(nrow=1),
               messages=FALSE,
               results.subtitle = FALSE,
               xlab="Type",
               ylab="Record duration",
               point.args = list(position = ggplot2::position_jitterdodge(dodge.width = 0.6), 
                                 alpha= 0.4, size = 2, stroke = 0)) + 
  ggplot2::scale_color_manual(values=c("#4DBBD5FF","#00A087FF"))

# How did the world records develop over time?
# count of world records over time
#records %>% 
  #mutate(type_sc= ifelse(shortcut=="Yes", paste(type, "with","Shortcut"),type)) %>%
  #group_by(date) %>% tally() %>% ggscatterhist(x="date",y="n", size=1, margin.plot="density")


# How did the world records develop over time?
# count of records over time by type and shortcut 
records %>% 
  mutate(type_sc= ifelse(shortcut=="Yes", paste(type, "with","Shortcut"),type)) %>%
  group_by(date) %>% count(type_sc) %>%
  ggplot(aes(x=date, y=n, color=type_sc)) + 
  geom_point(size=1,show.legend=F, alpha=0.9) + 
  facet_wrap(~type_sc,ncol=2) + 
  scale_color_npg() + 
  theme(panel.grid.minor = element_blank(),
        axis.title.x=element_markdown(size=10),
        axis.title.y=element_markdown(size=10),
        plot.title.position="plot",
        strip.text = element_text(face="bold",color="#343a40")
        ) + 
  labs(x="**Date**",y="**Record count**", title="Records over time by lap type and shortcut")

# Which is the longest standing world record?
records %>% filter(record_duration==max(record_duration))
# Who is the player with the most world records?
drivers %>% distinct(player, total) %>% slice(1)
# Who are recent players? (players in 2021)
records %>% filter(date>"2020-12-31") %>% 
  group_by(player) %>% 
  summarise(latest_date=max(date), record_count=length(player)) 
# Unique and new player count across the years
# reference:https://jack-davison.github.io/posts/2021-05-25-exploring-fun-questions-tidytuesday-2021-week-22-mario-kart-64/

d1 = drivers %>% distinct(player, year, records) %>%
  drop_na() %>% group_by(year) %>% summarise(unique_player=n_distinct(player))

d2 = drivers %>% distinct(player, year, records) %>%
  drop_na() %>% group_by(player) %>%
  filter(year==min(year)) %>% 
  ungroup() %>% count(year) %>% rename(new_player=n)

d1 %>% left_join(d2) %>% replace(is.na(.), 0) %>%
  pivot_longer(unique_player:new_player) %>%
  mutate(name=ifelse(name=="unique_player","Unique Player","New Player")) %>%
  ggplot(aes(x=year, y=value, fill=value)) + 
  geom_col() + 
  facet_grid(~fct_rev(name)) + 
  scale_x_continuous(
    breaks = seq(min(drivers$year), max(drivers$year), 4)) + 
  scale_fill_gradientn(colours = wes_palette("Zissou1", 25, type = "continuous")) + 
  theme(panel.grid.minor = element_blank(),
        axis.title.x=element_markdown(size=10),
        axis.title.y=element_markdown(size=10),
        plot.title.position="plot",
        legend.position="none",
        strip.text=element_text(face="bold",size=10),
        axis.text.x = element_text(vjust =5)) + 
  labs(x="**Year**",y="**Count**",
       title="Unique and new player count across the years\n")

# Which is the fastest track?
records %>% group_by(type,track) %>% summarise(min_time=min(time)) %>% 
  pivot_wider(names_from=type, values_from=min_time) %>% 
  rename(Track=track) %>% 
  ungroup() %>% 
  DT::datatable(rownames=FALSE,options = list(order = list(list(1, 'asc'))))
# Maximum Record by track and lap type  
# reference: https://twitter.com/Juanma_MN/status/1397249648931360768/photo/1
records %>% group_by(track, type) %>% summarise(max_duration=max(record_duration)) %>%
  ggplot(aes(y=reorder(track,max_duration, max), x=max_duration, color=type)) + 
  geom_point(size=2) + 
  geom_line(aes(group=track), color="grey") + 
  scale_color_manual(values=c("#E64B35FF","#3C5488FF")) + 
  theme(axis.title.x=element_markdown(size=10),
        axis.title.y=element_markdown(size=10),
        plot.title = element_markdown(),
        plot.title.position="plot",
        legend.position="none") + 
  labs(y="**Track**",x="**Maximum record duration** (in days)",
       title="Maximum record duration of <span style = 'color:#E64B35FF'>Single Lap</span> and <span style = 'color:#3C5488FF'>Three Lap</span> races, by Track",
       subtitle="")

LS0tCnRpdGxlOiAiVGlkeSBUdWVzZGF5IDIyLzIwMjEiCm91dHB1dDogaHRtbF9ub3RlYm9vawpkYXRlOiAiMjAyMS8wNS8yNiIKLS0tCgpbVGlkeSBUdWVzZGF5XShodHRwczovL2dpdGh1Yi5jb20vcmZvcmRhdGFzY2llbmNlL3RpZHl0dWVzZGF5KSBXZWVrIDIyIFtNYXJpbyBLYXJ0IDY0IFdvcmxkIFJlY29yZHNdKGh0dHBzOi8vZ2l0aHViLmNvbS9yZm9yZGF0YXNjaWVuY2UvdGlkeXR1ZXNkYXkvYmxvYi9tYXN0ZXIvZGF0YS8yMDIxLzIwMjEtMDUtMjUvcmVhZG1lLm1kKSwgZGF0YSBmcm9tIFtNYXJpbyBLYXJ0IFdvcmxkIFJlY29yZHNdKGh0dHBzOi8vbWt3cnMuY29tLykgCgoKYGBge3J9CiMgTG9hZCBsaWJyYXJpZXMgCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdndGV4dCkKbGlicmFyeShnZ3B1YnIpCmxpYnJhcnkoZ2dzdGF0c3Bsb3QpCmxpYnJhcnkoZ3QpCmxpYnJhcnkoZ2dzY2kpCmxpYnJhcnkod2VzYW5kZXJzb24pCgp0aGVtZV9zZXQodGhlbWVfbWluaW1hbCgpKQpgYGAKCmBgYHtyfQojIEltcG9ydCBkYXRhCnJlY29yZHMgPC0gcmVhZHI6OnJlYWRfY3N2KCdodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vcmZvcmRhdGFzY2llbmNlL3RpZHl0dWVzZGF5L21hc3Rlci9kYXRhLzIwMjEvMjAyMS0wNS0yNS9yZWNvcmRzLmNzdicpCmRyaXZlcnMgPC0gcmVhZHI6OnJlYWRfY3N2KCdodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vcmZvcmRhdGFzY2llbmNlL3RpZHl0dWVzZGF5L21hc3Rlci9kYXRhLzIwMjEvMjAyMS0wNS0yNS9kcml2ZXJzLmNzdicpCmBgYAoKCmBgYHtyLCB3YXJuaW5nPUYsIG1lc3NhZ2U9RiwgZmlnLmhlaWdodD0zLjUsIGZpZy53aWR0aD00LjV9CiMgV2hpY2ggTWFyaW8gS2FydCBUcmFjayBJcyBUaGUgRmFzdGVzdD8KIyBzaGFyZWQgb24gW1R3aXR0ZXJdKGh0dHBzOi8vdHdpdHRlci5jb20vbGVlb2xuZXkzL3N0YXR1cy8xMzk2OTgwNDYxMTM0NjE0NTI4L3Bob3RvLzEpCgp0YWJsZTEgPSByZWNvcmRzICU+JSAKICBncm91cF9ieSh0cmFjaywgdHlwZSwgc2hvcnRjdXQpICU+JQogIHN1bW1hcmlzZSh0aW1lX21pbj1taW4odGltZSkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUodHlwZV9zYz0gaWZlbHNlKHNob3J0Y3V0PT0iWWVzIiwgcGFzdGUodHlwZSwgIndpdGgiLCJTaG9ydGN1dCIpLHR5cGUpKQoKIyBkb3QgcGxvdAp0YWJsZTEgJT4lIAogIGdncGxvdChhZXMoeD1mY3RfcmV2KGZjdF9yZW9yZGVyKHRyYWNrLCB0aW1lX21pbiwgLmZ1bj0nbWluJykpLCB5PXRpbWVfbWluLCAKICAgICAgICAgICAgIGNvbG9yPWZhY3Rvcih0eXBlX3NjLCBsZXZlbHM9YygiVGhyZWUgTGFwIHdpdGggU2hvcnRjdXQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTaW5nbGUgTGFwIHdpdGggU2hvcnRjdXQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTaW5nbGUgTGFwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVGhyZWUgTGFwIikpKSkgKwogIGdlb21fbGluZShhZXMoZ3JvdXA9dHJhY2spLCBjb2xvcj0iZ3JleSIsc2l6ZT0yLGFscGhhPTAuNCkgKwogICNnZW9tX3BvaW50KHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKDAuNCksc2l6ZT0yLjIpICsKICBnZW9tX3BvaW50KHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyZG9kZ2UoZG9kZ2Uud2lkdGggPSAwLjUsIGppdHRlci5oZWlnaHQgPSAwLjUpLHNpemU9Mi43KSAgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0idG9wIiwKICAgICAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9ICJsZWZ0IiwKICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiLAogICAgICAgIHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSwgZmFjZT0iYm9sZCIsc2l6ZT0xOCksCiAgICAgICAgcGxvdC5tYXJnaW49Z2dwbG90Mjo6bWFyZ2luKDEsMSwwLjUsMSwiY20iKSwKICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9tYXJrZG93bihzaXplPTEwLjUpLAogICAgICAgIGF4aXMudGl0bGUueT1lbGVtZW50X21hcmtkb3duKHNpemU9MTAuNSkpICsgCiAgbGFicyhjb2xvcj0iIiwgeD0iKipUcmFjayoqIix5PSIqKk1pbmltdW0gVGltZSoqIChpbiBzZWNvbmRzKTxicj4iLAogICAgICAgdGl0bGU9IldoaWNoIE1hcmlvIEthcnQgVHJhY2sgSXMgVGhlIEZhc3Rlc3Q/IiwKICAgICAgIGNhcHRpb249IlRpZHkgVHVlc2RheSBXZWVrIDIyIHwgRGF0YSBmcm9tIE1hcmlvIEthcnQgV29ybGQgUmVjb3JkcyIpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjZjk1NzM4IiwiI2ZmYTYyYiIsIiMwMDkxYWQiLCIjNDNCMDQ3IikpICsgCiAgY29vcmRfZmxpcCgpIApgYGAKCmBgYHtyfQojIEZvciBob3cgbWFueSB0cmFja3MgaGF2ZSBzaG9ydGN1dHMgYmVlbiBkaXNjb3ZlcmVkPwpyZWNvcmRzICU+JSAKICBjb3VudCh0cmFjaywgc2hvcnRjdXQpICU+JQogIGNvdW50KHNob3J0Y3V0KQpgYGAKCmBgYHtyfQojIEZvciB3aGljaCB0cmFjayBkaWQgdGhlIHdvcmxkIHJlY29yZCBpbXByb3ZlIHRoZSBtb3N0PwpyZWNvcmRzICU+JSAKIGdyb3VwX2J5KHRyYWNrKSAlPiUgCiAgc3VtbWFyaXNlKG1pbl90aW1lID0gbWluKHRpbWUpLCBtYXhfdGltZT1tYXgodGltZSksIGltcHJvdmVkPW1heF90aW1lLW1pbl90aW1lKSAlPiUKICBhcnJhbmdlKGRlc2MoaW1wcm92ZWQpKSAlPiUKICBtdXRhdGUoaW1wcm92ZWRfcGN0PSByb3VuZChpbXByb3ZlZC9tYXhfdGltZSoxMDAsMykpICU+JQogIGFycmFuZ2UoZGVzYyhpbXByb3ZlZF9wY3QpKSAlPiUgc2xpY2UoMSkKYGBgCgoKYGBge3IsIHdhcm5pbmc9RiwgbWVzc2FnZT1GfQojIE9uIHdoaWNoIHRyYWNrIHRoZSBzaG9ydGN1dCBzYXZlcyB0aGUgbW9zdCB0aW1lIAp0YWJsZTIgPSByZWNvcmRzICU+JSAKICBncm91cF9ieSh0cmFjaywgdHlwZSwgc2hvcnRjdXQpICU+JQogIHN1bW1hcmlzZSh0aW1lPW1lYW4odGltZSkpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBzaG9ydGN1dCx2YWx1ZXNfZnJvbT10aW1lKSAlPiUKICBmaWx0ZXIoIWlzLm5hKFllcykpICU+JQogIG11dGF0ZSh0aW1lX3NhdmVkPU5vLVllcykgJT4lIAogIGFycmFuZ2UoZGVzYyh0aW1lX3NhdmVkKSkKCiMgdGltZSBzYXZlZCBieSByYWNlIHR5cGUKYnkodGFibGUyJHRpbWVfc2F2ZWQsIHRhYmxlMiR0eXBlLCBzdW1tYXJ5KSAjbm8gZGlmZmVyZW5jZSBpbiBTaW5nbGUgbGFwIHdpdGggYW5kIHdpdGhvdXQgc2hvcnRjdXQKYGBgCgoKYGBge3Isd2FybmluZz1GLCBtZXNzYWdlPUYsIGZpZy53aWR0aD0zLjc1LCBmaWcuaGVpZ2h0PTIuNzV9CiMgT24gd2hpY2ggdHJhY2sgdGhlIHNob3J0Y3V0IHNhdmVzIHRoZSBtb3N0IHRpbWUgCiMgZG90IHBsb3Q6IHRocmVlIGxhcAp0YWJsZTQgPSByZWNvcmRzICU+JSAKICBncm91cF9ieSh0cmFjaywgdHlwZSwgc2hvcnRjdXQpICU+JQogIHN1bW1hcmlzZSh0aW1lPW1lYW4odGltZSkpICU+JSAKICBmaWx0ZXIodHlwZT09IlRocmVlIExhcCIpICU+JQogIGZpbHRlcih0cmFjayE9IkJhbnNoZWUgQm9hcmR3YWxrIix0cmFjayE9IkJvd3NlcidzIENhc3RsZSIsCiAgICAgICAgIHRyYWNrIT0iS29vcGEgVHJvb3BhIEJlYWNoIix0cmFjayE9Ik1vbyBNb28gRmFybSIpICU+JQogIG11dGF0ZSh0aW1lX3NhdmVkPWxhZyh0aW1lKS10aW1lKSAlPiUKICBtdXRhdGUocGN0ID0gcm91bmQodGltZV9zYXZlZC9sYWcodGltZSksMykpIAoKdGFibGU1ID0gdGFibGU0ICU+JSBmaWx0ZXIoc2hvcnRjdXQ9PSJZZXMiKQoKdGFibGU1ICU+JQogIGdncGxvdChhZXMoeT1yZW9yZGVyKHRyYWNrLHBjdCksIHg9dGltZSkpICsgCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1wYXN0ZTAoIi0iLHNjYWxlczo6cGVyY2VudChwY3QsYWNjdXJhY3k9MC4xTCkpKSxzaXplPTIuOSwgaGp1c3Q9MS4yLCBjb2xvcj0iIzNDNTQ4OEZGIikgKwogIGdlb21fcG9pbnQoZGF0YT10YWJsZTQsIGFlcyhjb2xvcj1zaG9ydGN1dCksc2l6ZT0yLHNob3cubGVnZW5kID0gRikgKyAKICBnZW9tX2xpbmUoZGF0YT10YWJsZTQsIGFlcyhncm91cD10cmFjayksIGFscGhhPTAuMyxzaXplPTEpICsgCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cz1jKDAsMzcwKSkgKyAKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgcGFuZWwuZ3JpZC5taW5vci54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgIGF4aXMudGl0bGUueD1lbGVtZW50X21hcmtkb3duKHNpemU9MTApLAogICAgICAgYXhpcy50aXRsZS55PWVsZW1lbnRfbWFya2Rvd24oc2l6ZT0xMCksCiAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiLAogICAgICAgcGxvdC5zdWJ0aXRsZT1lbGVtZW50X21hcmtkb3duKHNpemU9MTApKSArIAogIGxhYnMoeD0iKipBdmVyYWdlIHRpbWUqKiAoaW4gc2Vjb25kcykiLAogICAgICAgeT0iKipUcmFjayoqIiwKICAgICAgIHRpdGxlPSJPbiB3aGljaCB0cmFjayB0aGUgc2hvcnRjdXQgc2F2ZXMgdGhlIG1vc3QgdGltZSBmb3IgMy1sYXA/IiwKICAgICAgIHN1YnRpdGxlPSJQZXJjZW50YWdlIGlzIGV4cHJlc3NlZCBhcyAoPHNwYW4gc3R5bGUgPSAnY29sb3I6I0U2NEIzNUZGJz5ObyBTaG9ydGN1dDwvc3Bhbj4gLSA8c3BhbiBzdHlsZSA9ICdjb2xvcjojM0M1NDg4RkYnPldpdGggU2hvcnRjdXQ8L3NwYW4+KSAvIDxzcGFuIHN0eWxlID0gJ2NvbG9yOiNFNjRCMzVGRic+Tm8gU2hvcnRjdXQ8L3NwYW4+PGJyPiIpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjRTY0QjM1RkYiLCIjM0M1NDg4RkYiKSkKYGBgIAoKCmBgYHtyLCB3YXJuaW5nPUYsIG1lc3NhZ2U9Rn0KIyBPbiB3aGljaCB0cmFjayB0aGUgc2hvcnRjdXQgc2F2ZXMgdGhlIG1vc3QgdGltZSAKIyBoaWdobGlnaHRlZCBzbG9wZSBjaGFydDogdGhyZWUgbGFwCnRhYmxlMiAlPiUKICBmaWx0ZXIodHlwZT09IlRocmVlIExhcCIpICU+JQogIHBpdm90X2xvbmdlcihObzpZZXMpICU+JQogIG11dGF0ZShuYW1lPWlmZWxzZShuYW1lPT0iTm8iLCJObyBTaG9ydGN1dCIsIldpdGggU2hvcnRjdXQiKSkgJT4lCiAgbXV0YXRlKHZhbHVlPXJvdW5kKHZhbHVlLDEpLCB0aW1lX3NhdmVkPXJvdW5kKHRpbWVfc2F2ZWQsMSkpIC0+IHRhYmxlMwoKdGFibGUzICU+JQogIGdncGxvdChhZXMoeD1uYW1lLCB5PXZhbHVlLCBncm91cD10cmFjaykpICsgCiAgZ2VvbV9saW5lKGFlcyhjb2xvcj1JKGlmZWxzZSh0cmFjaz09IldhcmlvIFN0YWRpdW0iLCAnI0U2NEIzNUZGJywgJyM4NDkxYjRGRicpKSkpICsgCiAgZ2VvbV9wb2ludChhZXMoY29sb3I9SShpZmVsc2UodHJhY2s9PSJXYXJpbyBTdGFkaXVtIiwgJyNFNjRCMzVGRicsICcjODQ5MWI0RkYnKSkpKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKyAKICBzY2FsZV94X2Rpc2NyZXRlKHBvc2l0aW9uPSJ0b3AiKSArCiAgZ2VvbV90ZXh0KGRhdGE9IHRhYmxlMyAlPiUgZmlsdGVyKHRyYWNrPT0iV2FyaW8gU3RhZGl1bSIpICU+JSBmaWx0ZXIobmFtZT09Ik5vIFNob3J0Y3V0IiksIAogICAgICAgICAgICBhZXMobGFiZWw9cGFzdGUwKHZhbHVlLCJzIikpLCBzaXplPTMsIGNvbG9yPSIjRTY0QjM1RkYiLCBoanVzdD0xLjIpICsKICBnZW9tX3RleHQoZGF0YT0gdGFibGUzICU+JSBmaWx0ZXIodHJhY2s9PSJXYXJpbyBTdGFkaXVtIikgJT4lIGZpbHRlcihuYW1lPT0iV2l0aCBTaG9ydGN1dCIpLCAKICAgICAgICAgICAgYWVzKGxhYmVsPXBhc3RlMCh2YWx1ZSwicyIpKSwgc2l6ZT0zLCBjb2xvcj0iI0U2NEIzNUZGIiwgaGp1c3Q9LTAuNSkgKyAKICBnZW9tX3RleHQoYWVzKHg9Ik5vIFNob3J0Y3V0Iix5PTI2NS4yLCBsYWJlbD0iV2FyaW8gU3RhZGl1bSIpLHNpemU9MywgY29sb3I9IiNFNjRCMzVGRiIsaGp1c3Q9MS43KSArIAogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChmYWNlPSJib2xkIixzaXplPTEwLCBjb2xvcj0iYmxhY2siKSwKICAgICAgICBheGlzLnRpdGxlLnk9ZWxlbWVudF9tYXJrZG93bihzaXplPTEwKSwKICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiKSArCiAgbGFicyh4PSIiLHk9IioqQXZlcmFnZSB0aW1lIHNhdmVkKiogKGluIHNlY29uZHMpIiwKICAgICAgIHRpdGxlPSJPbiB3aGljaCB0cmFjayB0aGUgc2hvcnRjdXQgc2F2ZXMgdGhlIG1vc3QgdGltZSBmb3IgMy1sYXA/IikKYGBgCgoKYGBge3IsIHdhcm5pbmc9RiwgbWVzc2FnZT1GfQojIFdoZW4gd2VyZSBzaG9ydGN1dHMgZGlzY292ZXJlZD8KcmVjb3JkcyAlPiUgZ3JvdXBfYnkodHJhY2ssIHNob3J0Y3V0KSAlPiUKICBzdW1tYXJpc2Uoc2NfZGlzPW1pbihkYXRlKSkgJT4lCiAgZmlsdGVyKHNob3J0Y3V0PT0iWWVzIikgJT4lCiAgbXV0YXRlKHNob3J0Y3V0PWlmZWxzZShzaG9ydGN1dD09IlllcyIsMSwiIikpICU+JQogIGdncGxvdChhZXMoeT1zaG9ydGN1dCx4PXNjX2RpcykpICsgCiAgZ2VvbV9zZWdtZW50KGFlcyh4PW1pbihzY19kaXMpLCB4ZW5kPW1heChzY19kaXMpLCB5PXNob3J0Y3V0LCB5ZW5kPXNob3J0Y3V0KSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yPWZhY3RvcihzY19kaXMpKSxzaXplPTYsc2hvdy5sZWdlbmQ9Riwgc2hhcGU9MTgpICsgCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1zY19kaXMpLCBzaXplPTMsIHZqdXN0PTMsIGNvbG9yPSJibGFjayIpICsgCiAgZ2VvbV90ZXh0KGFlcyh4PW1pbihzY19kaXMpLGxhYmVsPSJMdWlnaSBSYWNld2F5Iix5PTEuMDMpLCBzaXplPTMsIGNvbG9yPSIjRTY0QjM1RkYiKSArIAogIGdlb21fdGV4dChhZXMoeD1hcy5EYXRlKGMoIjE5OTctMDMtMDciKSksbGFiZWw9IlJhaW5ib3cgUm9hZFxuWW9zaGkgVmFsbGV5Iix5PTEuMDQ4KSwgCiAgICAgICAgICAgIHNpemU9MywgY29sb3I9IiMwMEEwODdGRiIsIGhqdXN0PTAsbnVkZ2VfeD0tMS42KSArCiAgZ2VvbV90ZXh0KGFlcyh4PWFzLkRhdGUoYygiMTk5Ny0wMy0xMCIpKSxsYWJlbD0iQ2hvY28gTW91bnRhaW5cbkQuSy4ncyBKdW5nbGUgUGFya3dheVxuRnJhcHBlIFNub3dsYW5kXG5LYWxpbWFyaSBEZXNlcnRcbk1hcmlvIFJhY2V3YXlcblJveWFsIFJhY2V3YXlcblNoZXJiZXQgTGFuZFxuVG9hZCdzIFR1cm5waWtlXG5XYXJpbyBTdGFkaXVtIix5PTEuMTI1KSwgc2l6ZT0zLGhqdXN0PTAsbnVkZ2VfeD0tMS4xLCBjb2xvcj0iIzNDNTQ4OEZGIikgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHM9YygwLjg1LDEuMzUpKSArCiAgc2NhbGVfeF9kYXRlKGxhYmVscz1zY2FsZXM6OmRhdGVfZm9ybWF0KCIlZC0lbS0lWSIpLCBsaW1pdHM9YXMuRGF0ZShjKCcxOTk3LTAyLTEzJywnMTk5Ny0wMy0xNCcpKSwKICAgICAgICAgICAgICAgZXhwYW5kID0gYygwLCAwKSwgYnJlYWtzID0gIjEgd2VlayIpICsKICB0aGVtZShheGlzLnRleHQ9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vcj1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci55PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yLng9ZWxlbWVudF9saW5lKHNpemU9MC4zNSkpICsgCiAgZ2VvbV9icmFja2V0KHhtaW49YXMuRGF0ZShjKCIxOTk3LTAyLTE2IikpLCB4bWF4PWFzLkRhdGUoYygiMTk5Ny0wMy0wNyIpKSwgeS5wb3NpdGlvbj0xLjEsIAogICAgICAgICAgICAgICBsYWJlbD0iMTkgZGF5cyIsIGxhYmVsLnNpemU9MykgKwogIGdlb21fYnJhY2tldCh4bWluPWFzLkRhdGUoYygiMTk5Ny0wMy0wNyIpKSwgeG1heD1hcy5EYXRlKGMoIjE5OTctMDMtMTAiKSksIHkucG9zaXRpb249MS4yNSwgCiAgICAgICAgICAgICAgIGxhYmVsPSIzIGRheXMiLCBsYWJlbC5zaXplPTMpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjRTY0QjM1RkYiLCIjMDBBMDg3RkYiLCIjM0M1NDg4RkYiKSkgKyAKICBsYWJzKHRpdGxlPSJXaGVuIHdlcmUgc2hvcnRjdXRzIGRpc2NvdmVyZWQ/IikKICAKYGBgCgoKYGBge3J9CiMgV2hpY2ggaXMgdGhlIGxvbmdlc3Qgc3RhbmRpbmcgd29ybGQgcmVjb3JkPwpyZWNvcmRzICU+JSBhcnJhbmdlKGRlc2MocmVjb3JkX2R1cmF0aW9uKSkgJT4lIHNsaWNlKDEpCmBgYAoKYGBge3IsIG1lc3NhZ2U9Rn0KIyBEaXN0cmlidXRpb24gb2YgcmVjb3JkIGR1cmF0aW9uIGFjcm9zcyByYWNlIHR5cGVzCmdnYmV0d2VlbnN0YXRzKGRhdGE9cmVjb3JkcywgeD10eXBlLCB5PXJlY29yZF9kdXJhdGlvbiwKICAgICAgICAgICAgICAgdGl0bGU9IkRpc3RyaWJ1dGlvbiBvZiByZWNvcmQgZHVyYXRpb24gYWNyb3NzIHJhY2UgdHlwZXMiLAogICAgICAgICAgICAgICB0eXBlPSJucCIsCiAgICAgICAgICAgICAgIHBsb3RncmlkLmFyZ3M9bGlzdChucm93PTEpLAogICAgICAgICAgICAgICBtZXNzYWdlcz1GQUxTRSwKICAgICAgICAgICAgICAgcmVzdWx0cy5zdWJ0aXRsZSA9IEZBTFNFLAogICAgICAgICAgICAgICB4bGFiPSJUeXBlIiwKICAgICAgICAgICAgICAgeWxhYj0iUmVjb3JkIGR1cmF0aW9uIiwKICAgICAgICAgICAgICAgcG9pbnQuYXJncyA9IGxpc3QocG9zaXRpb24gPSBnZ3Bsb3QyOjpwb3NpdGlvbl9qaXR0ZXJkb2RnZShkb2RnZS53aWR0aCA9IDAuNiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYT0gMC40LCBzaXplID0gMiwgc3Ryb2tlID0gMCkpICsgCiAgZ2dwbG90Mjo6c2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjNERCQkQ1RkYiLCIjMDBBMDg3RkYiKSkKYGBgCgpgYGB7cn0KIyBIb3cgZGlkIHRoZSB3b3JsZCByZWNvcmRzIGRldmVsb3Agb3ZlciB0aW1lPwojIGNvdW50IG9mIHdvcmxkIHJlY29yZHMgb3ZlciB0aW1lCiNyZWNvcmRzICU+JSAKICAjbXV0YXRlKHR5cGVfc2M9IGlmZWxzZShzaG9ydGN1dD09IlllcyIsIHBhc3RlKHR5cGUsICJ3aXRoIiwiU2hvcnRjdXQiKSx0eXBlKSkgJT4lCiAgI2dyb3VwX2J5KGRhdGUpICU+JSB0YWxseSgpICU+JSBnZ3NjYXR0ZXJoaXN0KHg9ImRhdGUiLHk9Im4iLCBzaXplPTEsIG1hcmdpbi5wbG90PSJkZW5zaXR5IikKCgojIEhvdyBkaWQgdGhlIHdvcmxkIHJlY29yZHMgZGV2ZWxvcCBvdmVyIHRpbWU/CiMgY291bnQgb2YgcmVjb3JkcyBvdmVyIHRpbWUgYnkgdHlwZSBhbmQgc2hvcnRjdXQgCnJlY29yZHMgJT4lIAogIG11dGF0ZSh0eXBlX3NjPSBpZmVsc2Uoc2hvcnRjdXQ9PSJZZXMiLCBwYXN0ZSh0eXBlLCAid2l0aCIsIlNob3J0Y3V0IiksdHlwZSkpICU+JQogIGdyb3VwX2J5KGRhdGUpICU+JSBjb3VudCh0eXBlX3NjKSAlPiUKICBnZ3Bsb3QoYWVzKHg9ZGF0ZSwgeT1uLCBjb2xvcj10eXBlX3NjKSkgKyAKICBnZW9tX3BvaW50KHNpemU9MSxzaG93LmxlZ2VuZD1GLCBhbHBoYT0wLjkpICsgCiAgZmFjZXRfd3JhcCh+dHlwZV9zYyxuY29sPTIpICsgCiAgc2NhbGVfY29sb3JfbnBnKCkgKyAKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueD1lbGVtZW50X21hcmtkb3duKHNpemU9MTApLAogICAgICAgIGF4aXMudGl0bGUueT1lbGVtZW50X21hcmtkb3duKHNpemU9MTApLAogICAgICAgIHBsb3QudGl0bGUucG9zaXRpb249InBsb3QiLAogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIsY29sb3I9IiMzNDNhNDAiKQogICAgICAgICkgKyAKICBsYWJzKHg9IioqRGF0ZSoqIix5PSIqKlJlY29yZCBjb3VudCoqIiwgdGl0bGU9IlJlY29yZHMgb3ZlciB0aW1lIGJ5IGxhcCB0eXBlIGFuZCBzaG9ydGN1dCIpCmBgYAoKCmBgYHtyfQojIFdoaWNoIGlzIHRoZSBsb25nZXN0IHN0YW5kaW5nIHdvcmxkIHJlY29yZD8KcmVjb3JkcyAlPiUgZmlsdGVyKHJlY29yZF9kdXJhdGlvbj09bWF4KHJlY29yZF9kdXJhdGlvbikpCiMgV2hvIGlzIHRoZSBwbGF5ZXIgd2l0aCB0aGUgbW9zdCB3b3JsZCByZWNvcmRzPwpkcml2ZXJzICU+JSBkaXN0aW5jdChwbGF5ZXIsIHRvdGFsKSAlPiUgc2xpY2UoMSkKIyBXaG8gYXJlIHJlY2VudCBwbGF5ZXJzPyAocGxheWVycyBpbiAyMDIxKQpyZWNvcmRzICU+JSBmaWx0ZXIoZGF0ZT4iMjAyMC0xMi0zMSIpICU+JSAKICBncm91cF9ieShwbGF5ZXIpICU+JSAKICBzdW1tYXJpc2UobGF0ZXN0X2RhdGU9bWF4KGRhdGUpLCByZWNvcmRfY291bnQ9bGVuZ3RoKHBsYXllcikpIApgYGAKCgoKCmBgYHtyLCB3YXJuaW5nPUYsIG1lc3NhZ2U9Rn0KIyBVbmlxdWUgYW5kIG5ldyBwbGF5ZXIgY291bnQgYWNyb3NzIHRoZSB5ZWFycwojIHJlZmVyZW5jZTpodHRwczovL2phY2stZGF2aXNvbi5naXRodWIuaW8vcG9zdHMvMjAyMS0wNS0yNS1leHBsb3JpbmctZnVuLXF1ZXN0aW9ucy10aWR5dHVlc2RheS0yMDIxLXdlZWstMjItbWFyaW8ta2FydC02NC8KCmQxID0gZHJpdmVycyAlPiUgZGlzdGluY3QocGxheWVyLCB5ZWFyLCByZWNvcmRzKSAlPiUKICBkcm9wX25hKCkgJT4lIGdyb3VwX2J5KHllYXIpICU+JSBzdW1tYXJpc2UodW5pcXVlX3BsYXllcj1uX2Rpc3RpbmN0KHBsYXllcikpCgpkMiA9IGRyaXZlcnMgJT4lIGRpc3RpbmN0KHBsYXllciwgeWVhciwgcmVjb3JkcykgJT4lCiAgZHJvcF9uYSgpICU+JSBncm91cF9ieShwbGF5ZXIpICU+JQogIGZpbHRlcih5ZWFyPT1taW4oeWVhcikpICU+JSAKICB1bmdyb3VwKCkgJT4lIGNvdW50KHllYXIpICU+JSByZW5hbWUobmV3X3BsYXllcj1uKQoKZDEgJT4lIGxlZnRfam9pbihkMikgJT4lIHJlcGxhY2UoaXMubmEoLiksIDApICU+JQogIHBpdm90X2xvbmdlcih1bmlxdWVfcGxheWVyOm5ld19wbGF5ZXIpICU+JQogIG11dGF0ZShuYW1lPWlmZWxzZShuYW1lPT0idW5pcXVlX3BsYXllciIsIlVuaXF1ZSBQbGF5ZXIiLCJOZXcgUGxheWVyIikpICU+JQogIGdncGxvdChhZXMoeD15ZWFyLCB5PXZhbHVlLCBmaWxsPXZhbHVlKSkgKyAKICBnZW9tX2NvbCgpICsgCiAgZmFjZXRfZ3JpZCh+ZmN0X3JldihuYW1lKSkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMoCiAgICBicmVha3MgPSBzZXEobWluKGRyaXZlcnMkeWVhciksIG1heChkcml2ZXJzJHllYXIpLCA0KSkgKyAKICBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvdXJzID0gd2VzX3BhbGV0dGUoIlppc3NvdTEiLCAyNSwgdHlwZSA9ICJjb250aW51b3VzIikpICsgCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9tYXJrZG93bihzaXplPTEwKSwKICAgICAgICBheGlzLnRpdGxlLnk9ZWxlbWVudF9tYXJrZG93bihzaXplPTEwKSwKICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uPSJwbG90IiwKICAgICAgICBsZWdlbmQucG9zaXRpb249Im5vbmUiLAogICAgICAgIHN0cmlwLnRleHQ9ZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiLHNpemU9MTApLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHZqdXN0ID01KSkgKyAKICBsYWJzKHg9IioqWWVhcioqIix5PSIqKkNvdW50KioiLAogICAgICAgdGl0bGU9IlVuaXF1ZSBhbmQgbmV3IHBsYXllciBjb3VudCBhY3Jvc3MgdGhlIHllYXJzXG4iKQpgYGAKCmBgYHtyLCB3YXJuaW5nPUYsIG1lc3NhZ2U9Rn0KIyBXaGljaCBpcyB0aGUgZmFzdGVzdCB0cmFjaz8KcmVjb3JkcyAlPiUgZ3JvdXBfYnkodHlwZSx0cmFjaykgJT4lIHN1bW1hcmlzZShtaW5fdGltZT1taW4odGltZSkpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tPXR5cGUsIHZhbHVlc19mcm9tPW1pbl90aW1lKSAlPiUgCiAgcmVuYW1lKFRyYWNrPXRyYWNrKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBEVDo6ZGF0YXRhYmxlKHJvd25hbWVzPUZBTFNFLG9wdGlvbnMgPSBsaXN0KG9yZGVyID0gbGlzdChsaXN0KDEsICdhc2MnKSkpKQpgYGAKCmBgYHtyLCBtZXNzYWdlPUZ9CiMgTWF4aW11bSBSZWNvcmQgYnkgdHJhY2sgYW5kIGxhcCB0eXBlICAKIyByZWZlcmVuY2U6IGh0dHBzOi8vdHdpdHRlci5jb20vSnVhbm1hX01OL3N0YXR1cy8xMzk3MjQ5NjQ4OTMxMzYwNzY4L3Bob3RvLzEKcmVjb3JkcyAlPiUgZ3JvdXBfYnkodHJhY2ssIHR5cGUpICU+JSBzdW1tYXJpc2UobWF4X2R1cmF0aW9uPW1heChyZWNvcmRfZHVyYXRpb24pKSAlPiUKICBnZ3Bsb3QoYWVzKHk9cmVvcmRlcih0cmFjayxtYXhfZHVyYXRpb24sIG1heCksIHg9bWF4X2R1cmF0aW9uLCBjb2xvcj10eXBlKSkgKyAKICBnZW9tX3BvaW50KHNpemU9MikgKyAKICBnZW9tX2xpbmUoYWVzKGdyb3VwPXRyYWNrKSwgY29sb3I9ImdyZXkiKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiI0U2NEIzNUZGIiwiIzNDNTQ4OEZGIikpICsgCiAgdGhlbWUoYXhpcy50aXRsZS54PWVsZW1lbnRfbWFya2Rvd24oc2l6ZT0xMCksCiAgICAgICAgYXhpcy50aXRsZS55PWVsZW1lbnRfbWFya2Rvd24oc2l6ZT0xMCksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfbWFya2Rvd24oKSwKICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uPSJwbG90IiwKICAgICAgICBsZWdlbmQucG9zaXRpb249Im5vbmUiKSArIAogIGxhYnMoeT0iKipUcmFjayoqIix4PSIqKk1heGltdW0gcmVjb3JkIGR1cmF0aW9uKiogKGluIGRheXMpIiwKICAgICAgIHRpdGxlPSJNYXhpbXVtIHJlY29yZCBkdXJhdGlvbiBvZiA8c3BhbiBzdHlsZSA9ICdjb2xvcjojRTY0QjM1RkYnPlNpbmdsZSBMYXA8L3NwYW4+IGFuZCA8c3BhbiBzdHlsZSA9ICdjb2xvcjojM0M1NDg4RkYnPlRocmVlIExhcDwvc3Bhbj4gcmFjZXMsIGJ5IFRyYWNrIiwKICAgICAgIHN1YnRpdGxlPSIiKQpgYGAKCgoK