Motivation: Back in May/June, I made some graphs for a Bay Area Disc Association (BADA) blog post to show how quickly and drastically COVID-19 impacted program registrations. I use updated data (through November) to illustrate a number of ways to visualize time series data.

#As usual, call libraries.
library(tidyverse); library(janitor);library(data.table);library(lubridate);
library(magick);library(magrittr);library(scales);library(ggtext)

We went into the BADA admin portal (well, Jesse did since he works there) and downloaded transactions (filter: by product == event, so we are just getting events data) from (1) Jan 2017-Jan 2019 and (2) Jan 2019-present.1

Now, I pull in the BADA data.2 I want purchases data (since transactions can include multiple purchases) and I want registrations over time. I filter to omit refunds since those are not unique registrations.

d1<-clean_names(fread("badata/data17-18/purchases.csv"))%>%select(-postal_code)
d2<-clean_names(fread("badata/data19-20/purchases.csv"))%>%select(-postal_code)
Detected 45 column names but the data has 48 columns (i.e. invalid file). Added 3 extra default column names at the end.
d3<-clean_names(fread("badata/datalate-20/purchases.csv"))%>%select(-postal_code)
purc<-bind_rows(d1, d2, d3)

# make date variables
badata<-purc%>%
  mutate(date=ymd_hms(processed_at))%>%
  mutate(month=floor_date(date, "month"),
         week=floor_date(date, "week"))

#filter to exclude refunds
badata1<-badata%>%
  filter(total_paid_refund==0)

Next, I get into graphing. FYI for all the graphs I make I add in the BADA logo as well as a still image of Millhouse playing frisbee by himself. I do this with the magick package – see here for general package info and here for another example of using this package.

Basics

Time Series in levels

I simply calculate and plot the total count of purchases for events (registrations by month).

data1<-badata1%>%
  group_by(month)%>%
  summarise(n=n())%>%
  # have to add 0s for months with no purchases
  add_row(tibble_row(month=ymd("2020-06-01"),n=0))%>%
  add_row(tibble_row(month=ymd("2020-07-01"),n=0))%>%
  add_row(tibble_row(month=ymd("2020-08-01"),n=0))
`summarise()` ungrouping output (override with `.groups` argument)
  
ggplot(data1, aes(x=month, y=n)) + 
  geom_point(size=1.2)+ geom_line(size=.7)+ 
  geom_hline(yintercept = 0, color=alpha("red", 0.5), linetype= "twodash", size=1)+
  theme_minimal()+theme(text=element_text(family="Palatino", size=13), 
                        legend.position = "top", panel.grid.minor = element_blank(),
                        plot.title = element_text(size=22),
                        axis.text.x = element_text(face = "bold"),
                        axis.text.y = element_text(face = "bold"))+ 
  labs(y="", x="", 
       caption="Data: BADA event/program registrations, Jan 1, 2017 - November 22, 2020. | Visual: Alex Albright.") +
  scale_y_continuous(limits=c(0,2000))+
  ggtitle("\nBADA registrations plummet during pandemic", subtitle = "Total program registrations by month")

ggsave("draft/bada0.png", width=12, height=6, dpi = 300)


#add logo
background <- image_read("draft/bada0.png")
logo <- image_read("images/logo.png")
logo <- logo %>%
  image_scale("350") 
new <- image_composite(background, logo, offset = "+3100+30")
image_write(new, "draft/bada0.png", flatten = F)

# add milhouse
background <- image_read("draft/bada0.png")
logo <- image_read("images/milhouse1.png")
logo <- logo %>%
  image_scale("350") 
new <- image_composite(background, logo, offset = "+2850+1290")
image_write(new, "final_graphs/bada-time-series.png", flatten = F)

Issue: there’s a ton of seasonality (some months always have higher registrations than others). This comes up with lots of covid graphs we’ve seen in the last year!

Ways to deal:

  1. compare month by month
  2. YOY plot
  3. remove month fixed effects

[1] Compare month by month

I calculate and plot the total count of purchases for events (registrations by month). This time I plot the years on top of one another and look across months. (But the counts by month-year are the same as what’s shown in the simple full time series above.)

data1<-badata1%>%
  mutate(month=month(date))%>%
  mutate(year=year(date))%>%
  group_by(month, year)%>%
  summarise(n=n())%>%ungroup%>%
  add_row(tibble_row(month=6, year=2020, n=0))%>%
  add_row(tibble_row(month=7, year=2020, n=0))%>%
  add_row(tibble_row(month=8, year=2020, n=0))
`summarise()` regrouping output by 'month' (override with `.groups` argument)
ggplot(data1, aes(x=month, y=n, color=factor(year), linetype=factor(year))) + 
  geom_point(size=1.2)+ geom_line(size=.7)+ 
  theme_minimal()+theme(text=element_text(family="Palatino", size=13), 
                        legend.position = "top", panel.grid.minor = element_blank(),
                        plot.title = element_text(size=22),
                        axis.text.x = element_text(face = "bold"),
                        axis.text.y = element_text(face = "bold"))+ 
  labs(y="", x="", 
       caption="Data: BADA event/program registrations, Jan 1, 2017 - November 22, 2020. | Visual: Alex Albright.") +
  scale_x_continuous(limits=c(1,12), breaks=1:12, 
                     labels=c("January", "February", "March", "April", 
                              "May", "June", "July", "August", 
                              "September", "October", "November", "December"))+
  scale_y_continuous(limits=c(0,2000))+
  scale_color_manual(name="Year", 
                     values = c(alpha(c("#41B6C4", "#225EA8", "#737373"), 0.5), "red"))+
  scale_linetype_manual(name="Year", values=c("twodash", "twodash", "twodash", "solid"))+
  #geom_rect(aes(ymin = -100, ymax = 100, xmin = 3.5, xmax = 5.5), alpha = 0.01, fill="mediumseagreen")+
  ggtitle("\nBADA registrations plummet during pandemic", subtitle = "Total program registrations by month")

ggsave("draft/bada1.png", width=10 , height=6, dpi = 300)


#add logo
background <- image_read("draft/bada1.png")
logo <- image_read("images/logo.png")
logo <- logo %>%
  image_scale("400") 
new <- image_composite(background, logo, offset = "+2400+30")
image_write(new, "draft/bada1.png", flatten = F)

# add milhouse
background <- image_read("draft/bada1.png")
logo <- image_read("images/milhouse1.png")
logo <- logo %>%
  image_scale("350") 
new <- image_composite(background, logo, offset = "+850+1290")
image_write(new, "final_graphs/bada-month-comparison.png", flatten = F)

YOY plot

Focus on year over year (YOY) change using 3 prior years (2017-2019) as the reference. I could also do this just relative to 2019. It’ll look pretty similar.

data1<-badata1%>%
  mutate(month=month(date))%>%
  mutate(year=year(date))%>%
  group_by(month, year)%>%
  summarise(n=n())%>%
  mutate(yeargroup=if_else(year<2020, "2017-2019", "2020"))%>%
  group_by(month, yeargroup)%>%
  summarise(avg=mean(n))%>%
  pivot_wider(names_from = yeargroup, values_from = avg)%>%
  mutate(change=(`2020`-`2017-2019`)/`2017-2019`)%>%
  mutate(`2020`=if_else(is.na(`2020`) & month<=11, 0, `2020`))%>%
  mutate(`change`=if_else(is.na(`change`)& month<=11, -1, `change`))
`summarise()` regrouping output by 'month' (override with `.groups` argument)
`summarise()` regrouping output by 'month' (override with `.groups` argument)
ggplot(data1, aes(x=month, y=change)) + 
  geom_point(size=2)+ geom_line(size=1)+ 
  theme_minimal()+theme(text=element_text(family="Palatino", size=13), 
                        legend.position = "top", panel.grid.minor = element_blank(),
                        plot.title = element_text(size=22),
                        axis.text.x = element_text(face = "bold"))+
  theme(text=element_text(family="Palatino", size=13), 
                        legend.position = "top", panel.grid.minor = element_blank(),
                        plot.title = element_text(size=21))+ 
  labs(y="", x="", caption="Data: BADA event/program registrations, Jan 1, 2017 - November 22, 2020. | Visual: Alex Albright.<br>*For each month, % change is calculated off of the month's registration mean from the past 3 years (2017-2019)*.") +
  theme(plot.caption = element_markdown(lineheight = 1.2),
        axis.text.y = element_markdown(size=12),
        axis.text.x = element_markdown(size=12))+
  geom_hline(yintercept = 0, color=alpha("#41B6C4", 0.5), linetype= "twodash", size=1)+
  geom_hline(yintercept = -1, color=alpha("red", 0.5), linetype= "twodash", size=1)+
  scale_y_continuous(breaks=seq(-1, 0.5, 0.5), 
                     labels=c("**-100%**<br>*(down to ~0)*","**-50%**<br>*(cut in half)*", 
                              "**0%**<br>*(average)*", "**+50%**<br>*(above average)*"))+
  scale_x_continuous(limits=c(1,12), breaks=1:12, 
                     labels=c("January", "February", "March", "April", 
                              "May", "June", "July", "August", 
                              "September", "October", "November", "December"))+
  ggtitle("\nBADA registrations plummet during pandemic", subtitle = "% change in BADA registrations in 2020")
ggsave("draft/bada2.png", width=12, height=6, dpi = 300)


#add logo
background <- image_read("draft/bada2.png")
logo <- image_read("images/logo.png")
logo <- logo %>%
  image_scale("300") 
new <- image_composite(background, logo, offset = "+50+30")
image_write(new, "draft/bada2.png", flatten = F)

# add milhouse
background <- image_read("draft/bada2.png")
logo <- image_read("images/milhouse1.png")
logo <- logo %>%
  image_scale("350") 
new <- image_composite(background, logo, offset = "+1790+1230")
image_write(new, "final_graphs/bada-yoy.png", flatten = F)

Econ-y stuff

Residualizing

Let’s adjust for monthly variations by removing month fixed effects. Essentially, registrations for a month and year \(registrations_{m,y}\) are a function of the month fixed effect \(\overline{registrations_m}\) and then some residual \(\epsilon_{m,y}\).

In Gelman, Hill, Vehtari lingo, we can also say this is a “comparison within groups using varying intercept models.” We allow for a different intercept for each month (or, we are demeaning by month) and then plotting the unexplained variation (residuals) for each month-year!

\[registrations_{m,y}=\overline{registrations_m} + \epsilon_{m,y}\]

#Regress registrations on a month factor variables and then plot residuals over month-year:

library(broom)
data1<-badata1%>%
  group_by(month)%>%
  summarise(n=n())%>%
  # have to add 0s for months with no purchases
  add_row(tibble_row(month=ymd("2020-06-01"),n=0))%>%
  add_row(tibble_row(month=ymd("2020-07-01"),n=0))%>%
  add_row(tibble_row(month=ymd("2020-08-01"),n=0))
`summarise()` ungrouping output (override with `.groups` argument)
data1<-data1%>%mutate(month_only=month(month))%>%
  mutate(month_only=factor(month_only),
         month=factor(month))

mod<-lm(n~month_only, data=data1)

df <- augment(mod)
df<-inner_join(df, data1)
Joining, by = c("n", "month_only")
df<-df%>%mutate(month=ymd(month))

ggplot(df, aes(x= month, y = .resid, group=1)) + 
  geom_point(size=1.2)+ geom_line(size=.7)+
  geom_hline(yintercept = 0, color=alpha("red", 0.5), linetype= "twodash", size=1)+
  theme_minimal()+theme(text=element_text(family="Palatino", size=13), 
                        legend.position = "top", panel.grid.minor = element_blank(),
                        plot.title = element_text(size=22),
                        axis.text.x = element_text(face = "bold"),
                        axis.text.y = element_text(face = "bold"))+ 
  labs(y="", x="", 
       caption="Data: BADA event/program registrations, Jan 1, 2017 - November 22, 2020. | Visual: Alex Albright.") +
  scale_x_date(date_labels = "%Y")+
  ggtitle("\nBADA registrations plummet during pandemic", subtitle = "Residualized program registrations (removing month fixed effects)")

ggsave("draft/bada3.png", width=12, height=6, dpi = 300)


#add logo
background <- image_read("draft/bada3.png")
logo <- image_read("images/logo.png")
logo <- logo %>%
  image_scale("350") 
new <- image_composite(background, logo, offset = "+3100+30")
image_write(new, "draft/bada3.png", flatten = F)

# add milhouse
background <- image_read("draft/bada3.png")
logo <- image_read("images/milhouse1.png")
logo <- logo %>%
  image_scale("350") 
new <- image_composite(background, logo, offset = "+3180+1050")
image_write(new, "final_graphs/bada-residuals.png", flatten = F)

  1. It couldn’t handle downloading them all at once, thus the two separate downloads. I also came back to this project in November after a break since May, so I downloaded the most recent stuff separately then.↩︎

  2. I’m not sharing the raw data for this since it’s BADA admin data and not publicly available.↩︎

LS0tCnRpdGxlOiAiVGltZSBTZXJpZXMgR3JhcGhzIHdpdGggQkFEQSBEYXRhIgphdXRob3I6IEFsZXggQWxicmlnaHQKZGF0ZTogIjExLzIzLzIwIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgoqKk1vdGl2YXRpb246KiogQmFjayBpbiBNYXkvSnVuZSwgSSBtYWRlIHNvbWUgZ3JhcGhzIGZvciBhIFtCYXkgQXJlYSBEaXNjIEFzc29jaWF0aW9uIChCQURBKSBibG9nIHBvc3RdKGh0dHBzOi8vYmF5YXJlYWRpc2Mub3JnL3AvdGhhbmtzLWZvci1zdXBwb3J0aW5nLXlvdXItdGVhbSkgdG8gc2hvdyBob3cgcXVpY2tseSBhbmQgZHJhc3RpY2FsbHkgQ09WSUQtMTkgaW1wYWN0ZWQgcHJvZ3JhbSByZWdpc3RyYXRpb25zLiBJIHVzZSB1cGRhdGVkIGRhdGEgKHRocm91Z2ggTm92ZW1iZXIpIHRvIGlsbHVzdHJhdGUgYSBudW1iZXIgb2Ygd2F5cyB0byB2aXN1YWxpemUgdGltZSBzZXJpZXMgZGF0YS4KCmBgYHtyIHdhcm5pbmc9RkFMU0V9CiNBcyB1c3VhbCwgY2FsbCBsaWJyYXJpZXMuCmxpYnJhcnkodGlkeXZlcnNlKTsgbGlicmFyeShqYW5pdG9yKTtsaWJyYXJ5KGRhdGEudGFibGUpO2xpYnJhcnkobHVicmlkYXRlKTsKbGlicmFyeShtYWdpY2spO2xpYnJhcnkobWFncml0dHIpO2xpYnJhcnkoc2NhbGVzKTtsaWJyYXJ5KGdndGV4dCkKYGBgCgpXZSB3ZW50IGludG8gdGhlIEJBREEgYWRtaW4gcG9ydGFsICh3ZWxsLCBKZXNzZSBkaWQgc2luY2UgaGUgd29ya3MgdGhlcmUpIGFuZCBkb3dubG9hZGVkIHRyYW5zYWN0aW9ucyAoZmlsdGVyOiBieSBwcm9kdWN0ID09IGBldmVudGAsIHNvIHdlIGFyZSBqdXN0IGdldHRpbmcgZXZlbnRzIGRhdGEpIGZyb20gKDEpIEphbiAyMDE3LUphbiAyMDE5IGFuZCAoMikgSmFuIDIwMTktcHJlc2VudC5eW0l0IGNvdWxkbid0IGhhbmRsZSBkb3dubG9hZGluZyB0aGVtIGFsbCBhdCBvbmNlLCB0aHVzIHRoZSB0d28gc2VwYXJhdGUgZG93bmxvYWRzLiBJIGFsc28gY2FtZSBiYWNrIHRvIHRoaXMgcHJvamVjdCBpbiBOb3ZlbWJlciBhZnRlciBhIGJyZWFrIHNpbmNlIE1heSwgc28gSSBkb3dubG9hZGVkIHRoZSBtb3N0IHJlY2VudCBzdHVmZiBzZXBhcmF0ZWx5IHRoZW4uXQoKTm93LCBJIHB1bGwgaW4gdGhlIEJBREEgZGF0YS5eW0knbSBub3Qgc2hhcmluZyB0aGUgcmF3IGRhdGEgZm9yIHRoaXMgc2luY2UgaXQncyBCQURBIGFkbWluIGRhdGEgYW5kIG5vdCBwdWJsaWNseSBhdmFpbGFibGUuXSBJIHdhbnQgYHB1cmNoYXNlc2AgZGF0YSAoc2luY2UgYHRyYW5zYWN0aW9uc2AgY2FuIGluY2x1ZGUgbXVsdGlwbGUgcHVyY2hhc2VzKSBhbmQgSSB3YW50IHJlZ2lzdHJhdGlvbnMgb3ZlciB0aW1lLiBJIGZpbHRlciB0byBvbWl0IHJlZnVuZHMgc2luY2UgdGhvc2UgYXJlIG5vdCB1bmlxdWUgcmVnaXN0cmF0aW9ucy4KCmBgYHtyfQpkMTwtY2xlYW5fbmFtZXMoZnJlYWQoImJhZGF0YS9kYXRhMTctMTgvcHVyY2hhc2VzLmNzdiIpKSU+JXNlbGVjdCgtcG9zdGFsX2NvZGUpCmQyPC1jbGVhbl9uYW1lcyhmcmVhZCgiYmFkYXRhL2RhdGExOS0yMC9wdXJjaGFzZXMuY3N2IikpJT4lc2VsZWN0KC1wb3N0YWxfY29kZSkKZDM8LWNsZWFuX25hbWVzKGZyZWFkKCJiYWRhdGEvZGF0YWxhdGUtMjAvcHVyY2hhc2VzLmNzdiIpKSU+JXNlbGVjdCgtcG9zdGFsX2NvZGUpCnB1cmM8LWJpbmRfcm93cyhkMSwgZDIsIGQzKQoKIyBtYWtlIGRhdGUgdmFyaWFibGVzCmJhZGF0YTwtcHVyYyU+JQogIG11dGF0ZShkYXRlPXltZF9obXMocHJvY2Vzc2VkX2F0KSklPiUKICBtdXRhdGUobW9udGg9Zmxvb3JfZGF0ZShkYXRlLCAibW9udGgiKSwKICAgICAgICAgd2Vlaz1mbG9vcl9kYXRlKGRhdGUsICJ3ZWVrIikpCgojZmlsdGVyIHRvIGV4Y2x1ZGUgcmVmdW5kcwpiYWRhdGExPC1iYWRhdGElPiUKICBmaWx0ZXIodG90YWxfcGFpZF9yZWZ1bmQ9PTApCmBgYAoKTmV4dCwgSSBnZXQgaW50byBncmFwaGluZy4gRllJIGZvciBhbGwgdGhlIGdyYXBocyBJIG1ha2UgSSBhZGQgaW4gdGhlIEJBREEgbG9nbyBhcyB3ZWxsIGFzIGEgc3RpbGwgaW1hZ2Ugb2YgW01pbGxob3VzZSBwbGF5aW5nIGZyaXNiZWUgYnkgaGltc2VsZi5dKGh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9aTlEalVzNGUyZ3MpIEkgZG8gdGhpcyB3aXRoIHRoZSBgbWFnaWNrYCBwYWNrYWdlIC0tIHNlZSBbaGVyZV0oaHR0cHM6Ly93d3cuZGFuaWVscGhhZGxleS5jb20vZ2dwbG90LWxvZ28vKSBmb3IgZ2VuZXJhbCBwYWNrYWdlIGluZm8gYW5kIFtoZXJlXShodHRwczovL3JwdWJzLmNvbS9hcGFsYnJpZ2h0L3NlbmF0ZS12b3Rlcy12aXN1YWxpemVkKSBmb3IgYW5vdGhlciBleGFtcGxlIG9mIHVzaW5nIHRoaXMgcGFja2FnZS4KCiMgQmFzaWNzCgojIyBUaW1lIFNlcmllcyBpbiBsZXZlbHMKCkkgc2ltcGx5IGNhbGN1bGF0ZSBhbmQgcGxvdCB0aGUgdG90YWwgY291bnQgb2YgcHVyY2hhc2VzIGZvciBldmVudHMgKHJlZ2lzdHJhdGlvbnMgYnkgbW9udGgpLgoKYGBge3J9CmRhdGExPC1iYWRhdGExJT4lCiAgZ3JvdXBfYnkobW9udGgpJT4lCiAgc3VtbWFyaXNlKG49bigpKSU+JQogICMgaGF2ZSB0byBhZGQgMHMgZm9yIG1vbnRocyB3aXRoIG5vIHB1cmNoYXNlcwogIGFkZF9yb3codGliYmxlX3Jvdyhtb250aD15bWQoIjIwMjAtMDYtMDEiKSxuPTApKSU+JQogIGFkZF9yb3codGliYmxlX3Jvdyhtb250aD15bWQoIjIwMjAtMDctMDEiKSxuPTApKSU+JQogIGFkZF9yb3codGliYmxlX3Jvdyhtb250aD15bWQoIjIwMjAtMDgtMDEiKSxuPTApKQogIApnZ3Bsb3QoZGF0YTEsIGFlcyh4PW1vbnRoLCB5PW4pKSArIAogIGdlb21fcG9pbnQoc2l6ZT0xLjIpKyBnZW9tX2xpbmUoc2l6ZT0uNykrIAogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGNvbG9yPWFscGhhKCJyZWQiLCAwLjUpLCBsaW5ldHlwZT0gInR3b2Rhc2giLCBzaXplPTEpKwogIHRoZW1lX21pbmltYWwoKSt0aGVtZSh0ZXh0PWVsZW1lbnRfdGV4dChmYW1pbHk9IlBhbGF0aW5vIiwgc2l6ZT0xMyksIAogICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIyKSwKICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiksCiAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpKSsgCiAgbGFicyh5PSIiLCB4PSIiLCAKICAgICAgIGNhcHRpb249IkRhdGE6IEJBREEgZXZlbnQvcHJvZ3JhbSByZWdpc3RyYXRpb25zLCBKYW4gMSwgMjAxNyAtIE5vdmVtYmVyIDIyLCAyMDIwLiB8IFZpc3VhbDogQWxleCBBbGJyaWdodC4iKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cz1jKDAsMjAwMCkpKwogIGdndGl0bGUoIlxuQkFEQSByZWdpc3RyYXRpb25zIHBsdW1tZXQgZHVyaW5nIHBhbmRlbWljIiwgc3VidGl0bGUgPSAiVG90YWwgcHJvZ3JhbSByZWdpc3RyYXRpb25zIGJ5IG1vbnRoIikKCmdnc2F2ZSgiZHJhZnQvYmFkYTAucG5nIiwgd2lkdGg9MTIsIGhlaWdodD02LCBkcGkgPSAzMDApCgojYWRkIGxvZ28KYmFja2dyb3VuZCA8LSBpbWFnZV9yZWFkKCJkcmFmdC9iYWRhMC5wbmciKQpsb2dvIDwtIGltYWdlX3JlYWQoImltYWdlcy9sb2dvLnBuZyIpCmxvZ28gPC0gbG9nbyAlPiUKICBpbWFnZV9zY2FsZSgiMzUwIikgCm5ldyA8LSBpbWFnZV9jb21wb3NpdGUoYmFja2dyb3VuZCwgbG9nbywgb2Zmc2V0ID0gIiszMTAwKzMwIikKaW1hZ2Vfd3JpdGUobmV3LCAiZHJhZnQvYmFkYTAucG5nIiwgZmxhdHRlbiA9IEYpCgojIGFkZCBtaWxob3VzZQpiYWNrZ3JvdW5kIDwtIGltYWdlX3JlYWQoImRyYWZ0L2JhZGEwLnBuZyIpCmxvZ28gPC0gaW1hZ2VfcmVhZCgiaW1hZ2VzL21pbGhvdXNlMS5wbmciKQpsb2dvIDwtIGxvZ28gJT4lCiAgaW1hZ2Vfc2NhbGUoIjM1MCIpIApuZXcgPC0gaW1hZ2VfY29tcG9zaXRlKGJhY2tncm91bmQsIGxvZ28sIG9mZnNldCA9ICIrMjg1MCsxMjkwIikKaW1hZ2Vfd3JpdGUobmV3LCAiZmluYWxfZ3JhcGhzL2JhZGEtdGltZS1zZXJpZXMucG5nIiwgZmxhdHRlbiA9IEYpCmBgYAoKSXNzdWU6IHRoZXJlJ3MgYSB0b24gb2Ygc2Vhc29uYWxpdHkgKHNvbWUgbW9udGhzIGFsd2F5cyBoYXZlIGhpZ2hlciByZWdpc3RyYXRpb25zIHRoYW4gb3RoZXJzKS4gVGhpcyBjb21lcyB1cCB3aXRoIGxvdHMgb2YgY292aWQgZ3JhcGhzIHdlJ3ZlIHNlZW4gaW4gdGhlIGxhc3QgeWVhciEKCldheXMgdG8gZGVhbDoKCjEuIGNvbXBhcmUgbW9udGggYnkgbW9udGgKMi4gWU9ZIHBsb3QKMy4gcmVtb3ZlIG1vbnRoIGZpeGVkIGVmZmVjdHMKCiMjIFsxXSBDb21wYXJlIG1vbnRoIGJ5IG1vbnRoCgpJIGNhbGN1bGF0ZSBhbmQgcGxvdCB0aGUgdG90YWwgY291bnQgb2YgcHVyY2hhc2VzIGZvciBldmVudHMgKHJlZ2lzdHJhdGlvbnMgYnkgbW9udGgpLiBUaGlzIHRpbWUgSSBwbG90IHRoZSB5ZWFycyBvbiB0b3Agb2Ygb25lIGFub3RoZXIgYW5kIGxvb2sgYWNyb3NzIG1vbnRocy4gKEJ1dCB0aGUgY291bnRzIGJ5IG1vbnRoLXllYXIgYXJlIHRoZSBzYW1lIGFzIHdoYXQncyBzaG93biBpbiB0aGUgc2ltcGxlIGZ1bGwgdGltZSBzZXJpZXMgYWJvdmUuKQoKYGBge3J9CmRhdGExPC1iYWRhdGExJT4lCiAgbXV0YXRlKG1vbnRoPW1vbnRoKGRhdGUpKSU+JQogIG11dGF0ZSh5ZWFyPXllYXIoZGF0ZSkpJT4lCiAgZ3JvdXBfYnkobW9udGgsIHllYXIpJT4lCiAgc3VtbWFyaXNlKG49bigpKSU+JXVuZ3JvdXAlPiUKICBhZGRfcm93KHRpYmJsZV9yb3cobW9udGg9NiwgeWVhcj0yMDIwLCBuPTApKSU+JQogIGFkZF9yb3codGliYmxlX3Jvdyhtb250aD03LCB5ZWFyPTIwMjAsIG49MCkpJT4lCiAgYWRkX3Jvdyh0aWJibGVfcm93KG1vbnRoPTgsIHllYXI9MjAyMCwgbj0wKSkKCmdncGxvdChkYXRhMSwgYWVzKHg9bW9udGgsIHk9biwgY29sb3I9ZmFjdG9yKHllYXIpLCBsaW5ldHlwZT1mYWN0b3IoeWVhcikpKSArIAogIGdlb21fcG9pbnQoc2l6ZT0xLjIpKyBnZW9tX2xpbmUoc2l6ZT0uNykrIAogIHRoZW1lX21pbmltYWwoKSt0aGVtZSh0ZXh0PWVsZW1lbnRfdGV4dChmYW1pbHk9IlBhbGF0aW5vIiwgc2l6ZT0xMyksIAogICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIyKSwKICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiksCiAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpKSsgCiAgbGFicyh5PSIiLCB4PSIiLCAKICAgICAgIGNhcHRpb249IkRhdGE6IEJBREEgZXZlbnQvcHJvZ3JhbSByZWdpc3RyYXRpb25zLCBKYW4gMSwgMjAxNyAtIE5vdmVtYmVyIDIyLCAyMDIwLiB8IFZpc3VhbDogQWxleCBBbGJyaWdodC4iKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cz1jKDEsMTIpLCBicmVha3M9MToxMiwgCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscz1jKCJKYW51YXJ5IiwgIkZlYnJ1YXJ5IiwgIk1hcmNoIiwgIkFwcmlsIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNYXkiLCAiSnVuZSIsICJKdWx5IiwgIkF1Z3VzdCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2VwdGVtYmVyIiwgIk9jdG9iZXIiLCAiTm92ZW1iZXIiLCAiRGVjZW1iZXIiKSkrCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cz1jKDAsMjAwMCkpKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lPSJZZWFyIiwgCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoYWxwaGEoYygiIzQxQjZDNCIsICIjMjI1RUE4IiwgIiM3MzczNzMiKSwgMC41KSwgInJlZCIpKSsKICBzY2FsZV9saW5ldHlwZV9tYW51YWwobmFtZT0iWWVhciIsIHZhbHVlcz1jKCJ0d29kYXNoIiwgInR3b2Rhc2giLCAidHdvZGFzaCIsICJzb2xpZCIpKSsKICAjZ2VvbV9yZWN0KGFlcyh5bWluID0gLTEwMCwgeW1heCA9IDEwMCwgeG1pbiA9IDMuNSwgeG1heCA9IDUuNSksIGFscGhhID0gMC4wMSwgZmlsbD0ibWVkaXVtc2VhZ3JlZW4iKSsKICBnZ3RpdGxlKCJcbkJBREEgcmVnaXN0cmF0aW9ucyBwbHVtbWV0IGR1cmluZyBwYW5kZW1pYyIsIHN1YnRpdGxlID0gIlRvdGFsIHByb2dyYW0gcmVnaXN0cmF0aW9ucyBieSBtb250aCIpCgpnZ3NhdmUoImRyYWZ0L2JhZGExLnBuZyIsIHdpZHRoPTEwICwgaGVpZ2h0PTYsIGRwaSA9IDMwMCkKCiNhZGQgbG9nbwpiYWNrZ3JvdW5kIDwtIGltYWdlX3JlYWQoImRyYWZ0L2JhZGExLnBuZyIpCmxvZ28gPC0gaW1hZ2VfcmVhZCgiaW1hZ2VzL2xvZ28ucG5nIikKbG9nbyA8LSBsb2dvICU+JQogIGltYWdlX3NjYWxlKCI0MDAiKSAKbmV3IDwtIGltYWdlX2NvbXBvc2l0ZShiYWNrZ3JvdW5kLCBsb2dvLCBvZmZzZXQgPSAiKzI0MDArMzAiKQppbWFnZV93cml0ZShuZXcsICJkcmFmdC9iYWRhMS5wbmciLCBmbGF0dGVuID0gRikKCiMgYWRkIG1pbGhvdXNlCmJhY2tncm91bmQgPC0gaW1hZ2VfcmVhZCgiZHJhZnQvYmFkYTEucG5nIikKbG9nbyA8LSBpbWFnZV9yZWFkKCJpbWFnZXMvbWlsaG91c2UxLnBuZyIpCmxvZ28gPC0gbG9nbyAlPiUKICBpbWFnZV9zY2FsZSgiMzUwIikgCm5ldyA8LSBpbWFnZV9jb21wb3NpdGUoYmFja2dyb3VuZCwgbG9nbywgb2Zmc2V0ID0gIis4NTArMTI5MCIpCmltYWdlX3dyaXRlKG5ldywgImZpbmFsX2dyYXBocy9iYWRhLW1vbnRoLWNvbXBhcmlzb24ucG5nIiwgZmxhdHRlbiA9IEYpCmBgYAoKIyMgWU9ZIHBsb3QgCgpGb2N1cyBvbiB5ZWFyIG92ZXIgeWVhciAoWU9ZKSBjaGFuZ2UgdXNpbmcgMyBwcmlvciB5ZWFycyAoMjAxNy0yMDE5KSBhcyB0aGUgcmVmZXJlbmNlLiBJIGNvdWxkIGFsc28gZG8gdGhpcyBqdXN0IHJlbGF0aXZlIHRvIDIwMTkuIEl0J2xsIGxvb2sgcHJldHR5IHNpbWlsYXIuCgpgYGB7cn0KZGF0YTE8LWJhZGF0YTElPiUKICBtdXRhdGUobW9udGg9bW9udGgoZGF0ZSkpJT4lCiAgbXV0YXRlKHllYXI9eWVhcihkYXRlKSklPiUKICBncm91cF9ieShtb250aCwgeWVhciklPiUKICBzdW1tYXJpc2Uobj1uKCkpJT4lCiAgbXV0YXRlKHllYXJncm91cD1pZl9lbHNlKHllYXI8MjAyMCwgIjIwMTctMjAxOSIsICIyMDIwIikpJT4lCiAgZ3JvdXBfYnkobW9udGgsIHllYXJncm91cCklPiUKICBzdW1tYXJpc2UoYXZnPW1lYW4obikpJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHllYXJncm91cCwgdmFsdWVzX2Zyb20gPSBhdmcpJT4lCiAgbXV0YXRlKGNoYW5nZT0oYDIwMjBgLWAyMDE3LTIwMTlgKS9gMjAxNy0yMDE5YCklPiUKICBtdXRhdGUoYDIwMjBgPWlmX2Vsc2UoaXMubmEoYDIwMjBgKSAmIG1vbnRoPD0xMSwgMCwgYDIwMjBgKSklPiUKICBtdXRhdGUoYGNoYW5nZWA9aWZfZWxzZShpcy5uYShgY2hhbmdlYCkmIG1vbnRoPD0xMSwgLTEsIGBjaGFuZ2VgKSkKCmdncGxvdChkYXRhMSwgYWVzKHg9bW9udGgsIHk9Y2hhbmdlKSkgKyAKICBnZW9tX3BvaW50KHNpemU9MikrIGdlb21fbGluZShzaXplPTEpKyAKICB0aGVtZV9taW5pbWFsKCkrdGhlbWUodGV4dD1lbGVtZW50X3RleHQoZmFtaWx5PSJQYWxhdGlubyIsIHNpemU9MTMpLCAKICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0yMiksCiAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpKSsKICB0aGVtZSh0ZXh0PWVsZW1lbnRfdGV4dChmYW1pbHk9IlBhbGF0aW5vIiwgc2l6ZT0xMyksIAogICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIxKSkrIAogIGxhYnMoeT0iIiwgeD0iIiwgY2FwdGlvbj0iRGF0YTogQkFEQSBldmVudC9wcm9ncmFtIHJlZ2lzdHJhdGlvbnMsIEphbiAxLCAyMDE3IC0gTm92ZW1iZXIgMjIsIDIwMjAuIHwgVmlzdWFsOiBBbGV4IEFsYnJpZ2h0Ljxicj4qRm9yIGVhY2ggbW9udGgsICUgY2hhbmdlIGlzIGNhbGN1bGF0ZWQgb2ZmIG9mIHRoZSBtb250aCdzIHJlZ2lzdHJhdGlvbiBtZWFuIGZyb20gdGhlIHBhc3QgMyB5ZWFycyAoMjAxNy0yMDE5KSouIikgKwogIHRoZW1lKHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfbWFya2Rvd24obGluZWhlaWdodCA9IDEuMiksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X21hcmtkb3duKHNpemU9MTIpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9tYXJrZG93bihzaXplPTEyKSkrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3I9YWxwaGEoIiM0MUI2QzQiLCAwLjUpLCBsaW5ldHlwZT0gInR3b2Rhc2giLCBzaXplPTEpKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC0xLCBjb2xvcj1hbHBoYSgicmVkIiwgMC41KSwgbGluZXR5cGU9ICJ0d29kYXNoIiwgc2l6ZT0xKSsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgtMSwgMC41LCAwLjUpLCAKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoIioqLTEwMCUqKjxicj4qKGRvd24gdG8gfjApKiIsIioqLTUwJSoqPGJyPiooY3V0IGluIGhhbGYpKiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiKiowJSoqPGJyPiooYXZlcmFnZSkqIiwgIioqKzUwJSoqPGJyPiooYWJvdmUgYXZlcmFnZSkqIikpKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHM9YygxLDEyKSwgYnJlYWtzPTE6MTIsIAogICAgICAgICAgICAgICAgICAgICBsYWJlbHM9YygiSmFudWFyeSIsICJGZWJydWFyeSIsICJNYXJjaCIsICJBcHJpbCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWF5IiwgIkp1bmUiLCAiSnVseSIsICJBdWd1c3QiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNlcHRlbWJlciIsICJPY3RvYmVyIiwgIk5vdmVtYmVyIiwgIkRlY2VtYmVyIikpKwogIGdndGl0bGUoIlxuQkFEQSByZWdpc3RyYXRpb25zIHBsdW1tZXQgZHVyaW5nIHBhbmRlbWljIiwgc3VidGl0bGUgPSAiJSBjaGFuZ2UgaW4gQkFEQSByZWdpc3RyYXRpb25zIGluIDIwMjAiKQpnZ3NhdmUoImRyYWZ0L2JhZGEyLnBuZyIsIHdpZHRoPTEyLCBoZWlnaHQ9NiwgZHBpID0gMzAwKQoKI2FkZCBsb2dvCmJhY2tncm91bmQgPC0gaW1hZ2VfcmVhZCgiZHJhZnQvYmFkYTIucG5nIikKbG9nbyA8LSBpbWFnZV9yZWFkKCJpbWFnZXMvbG9nby5wbmciKQpsb2dvIDwtIGxvZ28gJT4lCiAgaW1hZ2Vfc2NhbGUoIjMwMCIpIApuZXcgPC0gaW1hZ2VfY29tcG9zaXRlKGJhY2tncm91bmQsIGxvZ28sIG9mZnNldCA9ICIrNTArMzAiKQppbWFnZV93cml0ZShuZXcsICJkcmFmdC9iYWRhMi5wbmciLCBmbGF0dGVuID0gRikKCiMgYWRkIG1pbGhvdXNlCmJhY2tncm91bmQgPC0gaW1hZ2VfcmVhZCgiZHJhZnQvYmFkYTIucG5nIikKbG9nbyA8LSBpbWFnZV9yZWFkKCJpbWFnZXMvbWlsaG91c2UxLnBuZyIpCmxvZ28gPC0gbG9nbyAlPiUKICBpbWFnZV9zY2FsZSgiMzUwIikgCm5ldyA8LSBpbWFnZV9jb21wb3NpdGUoYmFja2dyb3VuZCwgbG9nbywgb2Zmc2V0ID0gIisxNzkwKzEyMzAiKQppbWFnZV93cml0ZShuZXcsICJmaW5hbF9ncmFwaHMvYmFkYS15b3kucG5nIiwgZmxhdHRlbiA9IEYpCmBgYAojIEVjb24teSBzdHVmZgoKIyMgUmVzaWR1YWxpemluZwoKTGV0J3MgYWRqdXN0IGZvciBtb250aGx5IHZhcmlhdGlvbnMgYnkgcmVtb3ZpbmcgbW9udGggZml4ZWQgZWZmZWN0cy4gRXNzZW50aWFsbHksIHJlZ2lzdHJhdGlvbnMgZm9yIGEgbW9udGggYW5kIHllYXIgJHJlZ2lzdHJhdGlvbnNfe20seX0kIGFyZSBhIGZ1bmN0aW9uIG9mIHRoZSBtb250aCBmaXhlZCBlZmZlY3QgJFxvdmVybGluZXtyZWdpc3RyYXRpb25zX219JCBhbmQgdGhlbiBzb21lIHJlc2lkdWFsICRcZXBzaWxvbl97bSx5fSQuCgpJbiBbR2VsbWFuLCBIaWxsLCBWZWh0YXJpXShodHRwczovL2F2ZWh0YXJpLmdpdGh1Yi5pby9ST1MtRXhhbXBsZXMvKSBsaW5nbywgd2UgY2FuIGFsc28gc2F5IHRoaXMgaXMgYSAiY29tcGFyaXNvbiB3aXRoaW4gZ3JvdXBzIHVzaW5nIHZhcnlpbmcgaW50ZXJjZXB0IG1vZGVscy4iIFdlIGFsbG93IGZvciBhIGRpZmZlcmVudCBpbnRlcmNlcHQgZm9yIGVhY2ggbW9udGggKG9yLCB3ZSBhcmUgZGVtZWFuaW5nIGJ5IG1vbnRoKSBhbmQgdGhlbiBwbG90dGluZyB0aGUgdW5leHBsYWluZWQgdmFyaWF0aW9uIChyZXNpZHVhbHMpIGZvciBlYWNoIG1vbnRoLXllYXIhCgokJHJlZ2lzdHJhdGlvbnNfe20seX09XG92ZXJsaW5le3JlZ2lzdHJhdGlvbnNfbX0gKyBcZXBzaWxvbl97bSx5fSQkCgpgYGB7cn0KI1JlZ3Jlc3MgcmVnaXN0cmF0aW9ucyBvbiBhIG1vbnRoIGZhY3RvciB2YXJpYWJsZXMgYW5kIHRoZW4gcGxvdCByZXNpZHVhbHMgb3ZlciBtb250aC15ZWFyOgoKbGlicmFyeShicm9vbSkKZGF0YTE8LWJhZGF0YTElPiUKICBncm91cF9ieShtb250aCklPiUKICBzdW1tYXJpc2Uobj1uKCkpJT4lCiAgIyBoYXZlIHRvIGFkZCAwcyBmb3IgbW9udGhzIHdpdGggbm8gcHVyY2hhc2VzCiAgYWRkX3Jvdyh0aWJibGVfcm93KG1vbnRoPXltZCgiMjAyMC0wNi0wMSIpLG49MCkpJT4lCiAgYWRkX3Jvdyh0aWJibGVfcm93KG1vbnRoPXltZCgiMjAyMC0wNy0wMSIpLG49MCkpJT4lCiAgYWRkX3Jvdyh0aWJibGVfcm93KG1vbnRoPXltZCgiMjAyMC0wOC0wMSIpLG49MCkpCgpkYXRhMTwtZGF0YTElPiVtdXRhdGUobW9udGhfb25seT1tb250aChtb250aCkpJT4lCiAgbXV0YXRlKG1vbnRoX29ubHk9ZmFjdG9yKG1vbnRoX29ubHkpLAogICAgICAgICBtb250aD1mYWN0b3IobW9udGgpKQoKbW9kPC1sbShufm1vbnRoX29ubHksIGRhdGE9ZGF0YTEpCgpkZiA8LSBhdWdtZW50KG1vZCkKZGY8LWlubmVyX2pvaW4oZGYsIGRhdGExKQpkZjwtZGYlPiVtdXRhdGUobW9udGg9eW1kKG1vbnRoKSkKCmdncGxvdChkZiwgYWVzKHg9IG1vbnRoLCB5ID0gLnJlc2lkLCBncm91cD0xKSkgKyAKICBnZW9tX3BvaW50KHNpemU9MS4yKSsgZ2VvbV9saW5lKHNpemU9LjcpKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGNvbG9yPWFscGhhKCJyZWQiLCAwLjUpLCBsaW5ldHlwZT0gInR3b2Rhc2giLCBzaXplPTEpKwogIHRoZW1lX21pbmltYWwoKSt0aGVtZSh0ZXh0PWVsZW1lbnRfdGV4dChmYW1pbHk9IlBhbGF0aW5vIiwgc2l6ZT0xMyksIAogICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIyKSwKICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiksCiAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpKSsgCiAgbGFicyh5PSIiLCB4PSIiLCAKICAgICAgIGNhcHRpb249IkRhdGE6IEJBREEgZXZlbnQvcHJvZ3JhbSByZWdpc3RyYXRpb25zLCBKYW4gMSwgMjAxNyAtIE5vdmVtYmVyIDIyLCAyMDIwLiB8IFZpc3VhbDogQWxleCBBbGJyaWdodC4iKSArCiAgc2NhbGVfeF9kYXRlKGRhdGVfbGFiZWxzID0gIiVZIikrCiAgZ2d0aXRsZSgiXG5CQURBIHJlZ2lzdHJhdGlvbnMgcGx1bW1ldCBkdXJpbmcgcGFuZGVtaWMiLCBzdWJ0aXRsZSA9ICJSZXNpZHVhbGl6ZWQgcHJvZ3JhbSByZWdpc3RyYXRpb25zIChyZW1vdmluZyBtb250aCBmaXhlZCBlZmZlY3RzKSIpCgpnZ3NhdmUoImRyYWZ0L2JhZGEzLnBuZyIsIHdpZHRoPTEyLCBoZWlnaHQ9NiwgZHBpID0gMzAwKQoKI2FkZCBsb2dvCmJhY2tncm91bmQgPC0gaW1hZ2VfcmVhZCgiZHJhZnQvYmFkYTMucG5nIikKbG9nbyA8LSBpbWFnZV9yZWFkKCJpbWFnZXMvbG9nby5wbmciKQpsb2dvIDwtIGxvZ28gJT4lCiAgaW1hZ2Vfc2NhbGUoIjM1MCIpIApuZXcgPC0gaW1hZ2VfY29tcG9zaXRlKGJhY2tncm91bmQsIGxvZ28sIG9mZnNldCA9ICIrMzEwMCszMCIpCmltYWdlX3dyaXRlKG5ldywgImRyYWZ0L2JhZGEzLnBuZyIsIGZsYXR0ZW4gPSBGKQoKIyBhZGQgbWlsaG91c2UKYmFja2dyb3VuZCA8LSBpbWFnZV9yZWFkKCJkcmFmdC9iYWRhMy5wbmciKQpsb2dvIDwtIGltYWdlX3JlYWQoImltYWdlcy9taWxob3VzZTEucG5nIikKbG9nbyA8LSBsb2dvICU+JQogIGltYWdlX3NjYWxlKCIzNTAiKSAKbmV3IDwtIGltYWdlX2NvbXBvc2l0ZShiYWNrZ3JvdW5kLCBsb2dvLCBvZmZzZXQgPSAiKzMxODArMTA1MCIpCmltYWdlX3dyaXRlKG5ldywgImZpbmFsX2dyYXBocy9iYWRhLXJlc2lkdWFscy5wbmciLCBmbGF0dGVuID0gRikKYGBgCg==