Data Visualization Exercise

TidyTuesday 2021/week7

Wealth and Income over time, data from the Urban Institute and the US Census.

Load libaries

library(tidyverse)
library(tidytuesdayR)
library(scales)
library(ggtext)
library(colorspace) 
library(lemon) # reposition legend 
library(gggibbous) # moon line plot
library(ggstream) #ridge stream plot
library(CGPfunctions) #slope chart
 

Import Data

tuesdata <- tidytuesdayR::tt_load(2021, week = 7)
--- Compiling #TidyTuesday Information for 2021-02-09 ----
--- There are 11 files available ---
--- Starting Download ---

    Downloading file 1 of 11: `home_owner.csv`
    Downloading file 2 of 11: `income_aggregate.csv`
    Downloading file 3 of 11: `income_distribution.csv`
    Downloading file 4 of 11: `income_limits.csv`
    Downloading file 5 of 11: `income_mean.csv`
    Downloading file 6 of 11: `income_time.csv`
    Downloading file 7 of 11: `lifetime_earn.csv`
    Downloading file 8 of 11: `lifetime_wealth.csv`
    Downloading file 9 of 11: `race_wealth.csv`
    Downloading file 10 of 11: `retirement.csv`
    Downloading file 11 of 11: `student_debt.csv`
--- Download complete ---
lifetime_earn <- tuesdata$lifetime_earn
student_debt <- tuesdata$student_debt
retirement <- tuesdata$retirement
home_owner <- tuesdata$home_owner
race_wealth <- tuesdata$race_wealth
income_time <- tuesdata$income_time
income_limits <- tuesdata$income_limits
income_aggregate <- tuesdata$income_aggregate
income_distribution <- tuesdata$income_distribution
income_mean <- tuesdata$income_mean

P1: student_debt (percentage)

# loan_debt_pct
student_debt %>% 
  ggplot(aes(x=year, y= loan_debt_pct, color=race)) + 
  geom_line(size=1) + 
  scale_x_continuous(limits=c(1989, 2016.9), breaks=seq(1989,2016.9,3)) + 
  scale_y_continuous(limits=c(0,0.45), breaks=seq(0,0.45,0.1), labels=percent_format(accuracy=1)) +
  labs(x="",
       y="",
       title="Share of Families with Student Loan Debt in America",
       subtitle= "The percentage of <span style = 'color:#9e2a2b'><b>Black</b></span>-families with student loan debt <br> has been higher than <span style = 'color:#fb8500'><b>White</b></span>-families and  <span style = 'color:#006d77'><b>Hispanic</b></span>-families since 2001",
       caption="Data from Urban Institute and US Census") +
  scale_color_manual(values=c("#9e2a2b","#006d77","#fb8500")) + 
  theme_light() +
  theme(panel.grid.minor = element_blank(),
        panel.border = element_blank(),
        legend.position= "none",
        plot.title=element_text(size=14,face="bold"),
        plot.subtitle=ggtext::element_markdown()
        ) + 
  geom_text(data=student_debt,aes(y=0.43, x=2015, label="Black"), color="#9e2a2b", size=3) + 
  geom_text(data=student_debt,aes(y=0.345, x=2015, label="White"), color="#fb8500", size=3) + 
  geom_text(data=student_debt,aes(y=0.23, x=2014.8, label="Hispanic"), color="#006d77", size=3) +
  coord_cartesian(expand=FALSE)

P2: student_debt (average)

# loan_debt 
p1a = student_debt %>% 
  ggplot(aes(x=year, y= loan_debt, color=race)) + 
  geom_line(size=1) + 
  scale_x_continuous(limits=c(1989, 2016), breaks=seq(1989,2016,3)) + 
  scale_y_continuous(limits=c(0,15000), breaks=seq(0,15000, 2500), labels=scales::dollar_format()) +
  scale_color_manual(values=c("#9e2a2b","#006d77","#fb8500")) +
  theme_minimal() + 
  theme(panel.grid.minor = element_blank(),
        legend.position="none",
        plot.title=element_text(size=14,face="bold"),
        plot.subtitle = element_text(size=10)) + 
  # add rich text
  ggtext::geom_richtext(
    data=tibble(
    x=c(2014.5,2014.5,2014.5),y=c(12900,10200,6000),
    race1= c("Black","White","Hispanic"),
    lab = c("<b style='font-size:12pt;'>Black</b>", 
            "<b style='font-size:12pt;'>White</b>", 
              "<b style='font-size:12pt;'>Hispanic</b>"),
      angle = c(50, 42, 51)
    ), 
  aes(x,y,label=lab, color=race1,angle=angle),
  size=3, fill=NA, label.color=NA, 
  lineheight=.3) +
  labs(title="Student Loan Debt In America",
       subtitle=" Average family student loan debt for aged 25-55, by race and year normalized to 2016 dollars",
       caption="Data from Urban Institute and US Census",
       y="",
       x="")
p1b = p1a + 
  theme(
    ## turn title into filled textbox
    plot.title = ggtext::element_textbox_simple(
      color = "white", fill = "#1d3557",  size = 14, 
      padding = margin(8, 4, 8, 4), margin = margin(b = 5), lineheight= .9
    ),
    ## add round outline to caption
    plot.caption = ggtext::element_textbox_simple(
      width = NULL, linetype = 1, color="slategrey", padding = margin(3, 8, 3, 8), 
      margin = margin(t = 15), r = grid::unit(8, "pt")
    ),
    axis.title.x = ggtext::element_markdown(),
    axis.title.y = ggtext::element_markdown(),
  ) +
  ## textbox
  ggtext::geom_textbox(
    data = tibble(x = 1995, y = 12200, label = "From 2007 to 2016, the average student loan debt of <span style = 'color:#9e2a2b'><b>Black</b></span>-families is higher than <span style = 'color:#fb8500'><b>White</b></span>-families and  <span style = 'color:#006d77'><b>Hispanic</b></span>-families."),
    aes(x, y, label = label), inherit.aes = FALSE,
    size = 3,
    fill = "#e5e5e5", box.color = "#457b9d",
    width = unit(11, "lines")
  ) 

p1b

P3: student_debt (loan_debt and loan_debt_pct)

student_debt %>% 
  ggplot(aes(x=loan_debt, y= loan_debt_pct, color=race)) +
  geom_point(aes(shape=race),size=2) + 
  theme_minimal() + 
  scale_color_manual(values=c("#9e2a2b","#006d77","#fb8500")) + 
  scale_y_continuous(label=percent_format(accuracy=1)) +
  labs(title= "Student loan debt and share of families with student loan debt",
       color="Racial group",
       shape="Racial group",
       caption="Data from Urban Institute and US Census") +
  theme(legend.position="top",
        plot.title=element_text(face="bold",hjust=0.5),
        plot.caption=element_text(color="slategrey"))

NA

P4: race_wealth

rw = race_wealth %>% 
  filter(!is.na(wealth_family)) %>% 
  filter(year>=1989) %>% 
  filter(type=="Median") %>%
  filter(race!="Non-White") %>%
  mutate(wealth=round(wealth_family)) %>%
  mutate(grp = ifelse(wealth_family>100000,"Y","N"))
rw %>%
  ggplot(aes(x=as.factor(year), race)) +
  geom_tile(aes(fill=wealth_family), color="white", size=2) + 
  geom_text(aes(label=comma(wealth), color=grp),size=3) +
  theme_minimal() +
  theme(legend.position="bottom",
        axis.ticks = element_blank(),
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        axis.text.y=element_text(face="bold"),
        legend.title = element_text(size=10, color="black"),
        plot.title=element_text(face="bold"),
        plot.title.position = "plot",
        plot.subtitle = element_text(),
        plot.caption=element_text(hjust=0, color="slategrey"),
        plot.caption.position = "plot"
        ) + 
  scale_x_discrete(position="top") + 
  scale_fill_continuous_sequential(palette="Dark Mint", trans="log10", label=dollar) +
  scale_color_manual(values=c("black","white")) + 
  labs(x="",
       y="",
       fill="Median Family Wealth",
       title= "Family Wealth in America by Race and Year",
      subtitle = "Normalized to 2016 dollars",
      caption = "Data from Urban Institute and US Census") +
  guides(fill= guide_colorbar(title.position="top",
                              title.hjust = .5,
                              barwidth = unit(20, "lines"),
                              barheight = unit(.5, "lines"))) +
  guides(color=FALSE) #remove text color legend 

P5: lifetime earn

lifetime_earn %>% 
  ggplot(aes(x=lifetime_earn, y=fct_rev(race))) +
  geom_line(aes(group=race),size=7,color="#b8b8d1",alpha=0.5) + 
  geom_point(aes(color=gender),size=8,alpha=0.9) + 
  scale_x_continuous(labels=scales::dollar_format(), limits=c(1000000, 3000000)) +
  theme_minimal() + 
  scale_color_manual(values=c("#3a6ea5","#bd632f")) +
  theme(legend.position="none",
        axis.text.y=element_blank(),
        plot.title = element_text(face="bold",hjust=0.5)) +
  geom_text(aes(x=1200000, y=3.25, label="Female"), color="#bd632f",size=3.6) + 
  geom_text(aes(x=1800000, y=3.25, label="Male"), color="#3a6ea5",size=3.6) + 
  geom_text(aes(x=1500000, y=3, label="Black"),size=3.5, family="Courier") + 
  geom_text(aes(x=1550000, y=2, label="Hispanic any race"),size=3.5, family="Courier") +
  geom_text(aes(x=2100000, y=1, label="White"),size=3.5, family="Courier") + 
  labs(y="",
       x="",
       title="Average lifetime earning in America by race and gender",
       caption="Data from Urban Institute and US Census")

P6: home_owner

summary(home_owner$year)
home_owner %>% 
  filter(year>2006) %>% 
  ggplot(aes(x=year, y=home_owner_pct)) +
  geom_line(aes(color=race), size=1.5, alpha=0.8) +
  geom_moon(data= (home_owner %>% filter(year>2006)), aes(ratio=1),size=5, fill="#adb5bd",color="white") +
  geom_moon(data= (home_owner %>% filter(year>2006)), aes(ratio=home_owner_pct, fill=race), size=5,color="white") + 
  scale_y_continuous(limits=c(0.35,0.75),labels= percent_format(accuracy=1)) +
  scale_x_continuous(breaks=seq(2007, 2016,1)) +
  theme_minimal() +
  theme(panel.grid.minor=element_blank(),
        legend.position="none",
        panel.grid=element_line(size=0.3),
        plot.caption = element_text(size=8, color="slategrey",hjust=0.5),
        plot.title = element_text(face="bold", hjust=0.5)) + 
  scale_color_manual(values=c("#9e2a2b","#006d77","#fb8500")) + 
  scale_fill_manual(values=c("#9e2a2b","#006d77","#fb8500")) + 
  geom_text(data=(home_owner %>% 
  filter(year>2006)),aes(y=0.71, x=2015, label="White"), color="#fb8500", size=3.5) + 
  geom_text(data=(home_owner %>% 
  filter(year>2006)),aes(y=0.49, x=2015, label="Hispanic"), color="#006d77", size=3.5) +
  geom_text(data=(home_owner %>% 
  filter(year>2006)),aes(y=0.39, x=2015, label="Black"), color="#9e2a2b", size=3.5) + 
  labs(x= "",
       y= "",
       title= "Home Ownership Percentage in America (2007 to 2016)",
       subtitle=" by year and racial group",
       caption = "Data from Urban Institute and US Census") + 
  theme(plot.title = ggtext::element_textbox_simple(
        color = "white", fill = "#1d3557",  size = 14, 
        padding = margin(8, 4, 8, 4), margin = margin(b = 5), lineheight= .9))

P7: Mean income (by quintile)

im2 = income_mean %>%
  filter(income_quintile != "Top 5%") %>%
  mutate(income_quintile = factor(income_quintile, levels = c("Lowest", "Second", "Middle", "Fourth", "Highest"))) %>%
  filter(dollar_type == "2019 Dollars") %>%
  filter(race =="All Races") %>%
  group_by(year) %>%
  mutate(pct = round(income_dollars/sum(income_dollars),2))
summary(im2$year)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   1967    1980    1993    1993    2006    2019 
ggplot(im2, aes(year, income_dollars, fill=(income_quintile), label=income_quintile)) + 
  geom_stream(type="ridge", bw=0.75) + 
  geom_stream_label(size = 3, type = "ridge", color="black", family="Courier Bold") +
  scale_fill_manual(values = c("#83c5be","#cbf3f0","#f4f3ee","#ffbf69","#ff9f1c")) + 
  theme_light() +
  theme(legend.position="none",
        panel.grid.minor = element_blank(),
        plot.title = element_text(face="bold"),
        plot.subtitle= element_text(size=10),
        plot.caption= element_text(hjust=0.5, color="slategrey")
        ) + 
  scale_x_continuous(breaks=seq(1970,2015,5)) + 
  scale_y_continuous(labels=dollar_format()) +
  coord_cartesian(expand=FALSE) + 
  labs(x="",
       y="",
       title="Income Changes",
       subtitle="Mean income received by quintile from 1967 to 2019, normalized to 2019 dollar",
       caption= "Data from Urban Institute and US Census")

# proportion 
ggplot(im2, aes(year, pct, fill=income_quintile, label=income_quintile)) + 
  geom_stream(type="proportional", bw=0.5) + 
  geom_stream_label(size = 3, type = "proportional", color="black", family="Courier Bold") +
  scale_fill_manual(values = c("#83c5be","#cbf3f0","#f4f3ee","#ffbf69","#ff9f1c")) + 
  theme_light() +
  theme(legend.position="none",
        ) + 
  scale_y_continuous(labels=percent_format(accuracy=1), breaks=seq(0,1,0.2)) + 
  scale_x_continuous(breaks=seq(1970,2015,5)) + 
  coord_cartesian(expand=FALSE)

P8: retirement (average by racial group)

retirement2 = retirement %>% 
  mutate(ret= round(retirement/1000)) %>%
  filter(year>2000)
retirement2$year=as.factor(retirement2$year)

newggslopegraph(dataframe = retirement2,
                Times = year,
                Measurement = ret,
                Grouping = race,
                LineThickness = 1,
                LineColor = c("White"="#fb8500","Hispanic"="#006d77", "Black"="#9e2a2b"),
                Title = "Average family liquid retirement savings by racial group",
                SubTitle = "Retirement dollars (in thousands) from 2001 to 2016, normalized to 2016 dollar ",
                Caption = "Data from Urban Institute and US Census",
                YTextSize = 3.4,
                DataTextSize = 3,
                DataLabelFillColor = "white",
                DataLabelPadding=0.05,
                CaptionJustify = "center"
                )

P9: income mean

summary(income_mean$year)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   1967    1984    1999    1997    2010    2019 
im = income_mean %>%
  filter(income_quintile != "Top 5%") %>%
  mutate(income_quintile = factor(income_quintile, levels = c("Lowest", "Second", "Middle", "Fourth", "Highest"))) %>%
  filter(dollar_type == "2019 Dollars") %>%
  filter(race %in% c("White Alone", "Black Alone", "Hispanic")) %>%
  ggplot(aes(x = year, y = income_dollars, color = race, fill = race, group = race)) +
  geom_line() +
  facet_wrap(~income_quintile, scales = "free_y") + 
  scale_color_manual(values=c("#9e2a2b","#006d77","#fb8500")) + 
  theme_light() +
  theme(strip.text = element_text(face="bold"),
        strip.background= element_rect(fill="#1d3557")) + 
  labs(color="Racial Group",
       title="Income Quintile",
       subtitle="Mean income received by each fifth of each racial group from 1967 to 2019",
       x="Income (in dollars)",
       y="Year", caption= "Data from Urban Institute and US Census")

reposition_legend(im, 'center', panel='panel-3-2')

P10: income distribution

income_levels <- c(
  "Under $15,000",
  "$15,000 to $24,999",
  "$25,000 to $34,999",
  "$35,000 to $49,999",
  "$50,000 to $74,999",
  "$75,000 to $99,999",
  "$100,000 to $149,999",
  "$150,000 to $199,999",
  "$200,000 and over"
)


income_distribution %>%
  filter(race %in% c("Black Alone", "White Alone", "Hispanic (Any Race)")) %>%
  filter(year >= 1980) %>%
  mutate(income_bracket = factor(income_bracket, levels = income_levels)) %>%
  ggplot(aes(x = year, y = income_distribution, color = race, fill = race)) +
  geom_col(position = "fill") +
  theme_light() + 
  facet_wrap(~income_bracket) +
  scale_fill_manual(values=c("#ffc145","#c0c0c0","#3a6ea5")) + 
  scale_color_manual(values=c("#ffc145","#c0c0c0","#3a6ea5")) +
  coord_cartesian(expand=FALSE) + 
  theme(strip.text = element_text(face="bold", color="#273e47"),
        strip.background= element_rect(fill="white"),
        plot.caption = element_text(size=8, face="italic",hjust=0),
        plot.caption.position = "plot") + 
  labs(fill="Racial group", 
       color="Racial group",
       y="Income Distribution",
       x="Year",
       caption= "Data from Urban Institute and US Census")

LS0tCnRpdGxlOiAiV2VhbHRoIGFuZCBJbmNvbWUiCmRhdGU6ICIyMDIxLTAyLTA5IgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIyBEYXRhIFZpc3VhbGl6YXRpb24gRXhlcmNpc2UKCltfX1RpZHlUdWVzZGF5X19dKGh0dHBzOi8vZ2l0aHViLmNvbS9yZm9yZGF0YXNjaWVuY2UvdGlkeXR1ZXNkYXkpIDIwMjEvd2VlazcgCgpbV2VhbHRoIGFuZCBJbmNvbWUgb3ZlciB0aW1lXShodHRwczovL2dpdGh1Yi5jb20vcmZvcmRhdGFzY2llbmNlL3RpZHl0dWVzZGF5L2Jsb2IvbWFzdGVyL2RhdGEvMjAyMS8yMDIxLTAyLTA5L3JlYWRtZS5tZCksIGRhdGEgZnJvbSB0aGUgW1VyYmFuIEluc3RpdHV0ZV0oaHR0cHM6Ly9hcHBzLnVyYmFuLm9yZy9mZWF0dXJlcy93ZWFsdGgtaW5lcXVhbGl0eS1jaGFydHMvKSBhbmQgdGhlIFtVUyBDZW5zdXNdKGh0dHBzOi8vd3d3LmNlbnN1cy5nb3YvZGF0YS90YWJsZXMvdGltZS1zZXJpZXMvZGVtby9pbmNvbWUtcG92ZXJ0eS9oaXN0b3JpY2FsLWluY29tZS1ob3VzZWhvbGRzLmh0bWwpLgoKCiMjIyBMb2FkIGxpYmFyaWVzCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeSh0aWR5dHVlc2RheVIpCmxpYnJhcnkoc2NhbGVzKQpsaWJyYXJ5KGdndGV4dCkKbGlicmFyeShjb2xvcnNwYWNlKSAKbGlicmFyeShsZW1vbikgIyByZXBvc2l0aW9uIGxlZ2VuZCAKbGlicmFyeShnZ2dpYmJvdXMpICMgbW9vbiBsaW5lIHBsb3QKbGlicmFyeShnZ3N0cmVhbSkgI3JpZGdlIHN0cmVhbSBwbG90CmxpYnJhcnkoQ0dQZnVuY3Rpb25zKSAjc2xvcGUgY2hhcnQKIApgYGAKIAogCiMjIyBJbXBvcnQgRGF0YQpgYGB7cn0KdHVlc2RhdGEgPC0gdGlkeXR1ZXNkYXlSOjp0dF9sb2FkKDIwMjEsIHdlZWsgPSA3KQoKbGlmZXRpbWVfZWFybiA8LSB0dWVzZGF0YSRsaWZldGltZV9lYXJuCnN0dWRlbnRfZGVidCA8LSB0dWVzZGF0YSRzdHVkZW50X2RlYnQKcmV0aXJlbWVudCA8LSB0dWVzZGF0YSRyZXRpcmVtZW50CmhvbWVfb3duZXIgPC0gdHVlc2RhdGEkaG9tZV9vd25lcgpyYWNlX3dlYWx0aCA8LSB0dWVzZGF0YSRyYWNlX3dlYWx0aAppbmNvbWVfdGltZSA8LSB0dWVzZGF0YSRpbmNvbWVfdGltZQppbmNvbWVfbGltaXRzIDwtIHR1ZXNkYXRhJGluY29tZV9saW1pdHMKaW5jb21lX2FnZ3JlZ2F0ZSA8LSB0dWVzZGF0YSRpbmNvbWVfYWdncmVnYXRlCmluY29tZV9kaXN0cmlidXRpb24gPC0gdHVlc2RhdGEkaW5jb21lX2Rpc3RyaWJ1dGlvbgppbmNvbWVfbWVhbiA8LSB0dWVzZGF0YSRpbmNvbWVfbWVhbgpgYGAKCgojIyMgUDE6IHN0dWRlbnRfZGVidCAocGVyY2VudGFnZSkgCiogc2hhcmVkIG9uIFt0d2l0dGVyXShodHRwczovL3R3aXR0ZXIuY29tL2xlZW9sbmV5My9zdGF0dXMvMTM1ODg2NDM3NDQyMTc0MTU3MC9waG90by8xKSAKCmBgYHtyfQojIGxvYW5fZGVidF9wY3QKc3R1ZGVudF9kZWJ0ICU+JSAKICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT0gbG9hbl9kZWJ0X3BjdCwgY29sb3I9cmFjZSkpICsgCiAgZ2VvbV9saW5lKHNpemU9MSkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzPWMoMTk4OSwgMjAxNi45KSwgYnJlYWtzPXNlcSgxOTg5LDIwMTYuOSwzKSkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzPWMoMCwwLjQ1KSwgYnJlYWtzPXNlcSgwLDAuNDUsMC4xKSwgbGFiZWxzPXBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5PTEpKSArCiAgbGFicyh4PSIiLAogICAgICAgeT0iIiwKICAgICAgIHRpdGxlPSJTaGFyZSBvZiBGYW1pbGllcyB3aXRoIFN0dWRlbnQgTG9hbiBEZWJ0IGluIEFtZXJpY2EiLAogICAgICAgc3VidGl0bGU9ICJUaGUgcGVyY2VudGFnZSBvZiA8c3BhbiBzdHlsZSA9ICdjb2xvcjojOWUyYTJiJz48Yj5CbGFjazwvYj48L3NwYW4+LWZhbWlsaWVzIHdpdGggc3R1ZGVudCBsb2FuIGRlYnQgPGJyPiBoYXMgYmVlbiBoaWdoZXIgdGhhbiA8c3BhbiBzdHlsZSA9ICdjb2xvcjojZmI4NTAwJz48Yj5XaGl0ZTwvYj48L3NwYW4+LWZhbWlsaWVzIGFuZCAgPHNwYW4gc3R5bGUgPSAnY29sb3I6IzAwNmQ3Nyc+PGI+SGlzcGFuaWM8L2I+PC9zcGFuPi1mYW1pbGllcyBzaW5jZSAyMDAxIiwKICAgICAgIGNhcHRpb249IkRhdGEgZnJvbSBVcmJhbiBJbnN0aXR1dGUgYW5kIFVTIENlbnN1cyIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiM5ZTJhMmIiLCIjMDA2ZDc3IiwiI2ZiODUwMCIpKSArIAogIHRoZW1lX2xpZ2h0KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbj0gIm5vbmUiLAogICAgICAgIHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTQsZmFjZT0iYm9sZCIpLAogICAgICAgIHBsb3Quc3VidGl0bGU9Z2d0ZXh0OjplbGVtZW50X21hcmtkb3duKCkKICAgICAgICApICsgCiAgZ2VvbV90ZXh0KGRhdGE9c3R1ZGVudF9kZWJ0LGFlcyh5PTAuNDMsIHg9MjAxNSwgbGFiZWw9IkJsYWNrIiksIGNvbG9yPSIjOWUyYTJiIiwgc2l6ZT0zKSArIAogIGdlb21fdGV4dChkYXRhPXN0dWRlbnRfZGVidCxhZXMoeT0wLjM0NSwgeD0yMDE1LCBsYWJlbD0iV2hpdGUiKSwgY29sb3I9IiNmYjg1MDAiLCBzaXplPTMpICsgCiAgZ2VvbV90ZXh0KGRhdGE9c3R1ZGVudF9kZWJ0LGFlcyh5PTAuMjMsIHg9MjAxNC44LCBsYWJlbD0iSGlzcGFuaWMiKSwgY29sb3I9IiMwMDZkNzciLCBzaXplPTMpICsKICBjb29yZF9jYXJ0ZXNpYW4oZXhwYW5kPUZBTFNFKQpgYGAKCiMjIyBQMjogc3R1ZGVudF9kZWJ0IChhdmVyYWdlKSAgCiogZ2VvbV90ZXh0Ym94IGFuZCBnZW9tX3JpY2h0ZXh0IHJlZmVyZW5jZTogW2dncGxvdCBXaXphcmRyeSBIYW5kcy1PbiBieSBDw6lkcmljIFNjaGVyZXJdKGh0dHBzOi8vejN0dC5naXRodWIuaW8vT3V0bGllckNvbmYyMDIxLykKCmBgYHtyfQojIGxvYW5fZGVidCAKcDFhID0gc3R1ZGVudF9kZWJ0ICU+JSAKICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT0gbG9hbl9kZWJ0LCBjb2xvcj1yYWNlKSkgKyAKICBnZW9tX2xpbmUoc2l6ZT0xKSArIAogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHM9YygxOTg5LCAyMDE2KSwgYnJlYWtzPXNlcSgxOTg5LDIwMTYsMykpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cz1jKDAsMTUwMDApLCBicmVha3M9c2VxKDAsMTUwMDAsIDI1MDApLCBsYWJlbHM9c2NhbGVzOjpkb2xsYXJfZm9ybWF0KCkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiM5ZTJhMmIiLCIjMDA2ZDc3IiwiI2ZiODUwMCIpKSArCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb249Im5vbmUiLAogICAgICAgIHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTQsZmFjZT0iYm9sZCIpLAogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCkpICsgCiAgIyBhZGQgcmljaCB0ZXh0CiAgZ2d0ZXh0OjpnZW9tX3JpY2h0ZXh0KAogICAgZGF0YT10aWJibGUoCiAgICB4PWMoMjAxNC41LDIwMTQuNSwyMDE0LjUpLHk9YygxMjkwMCwxMDIwMCw2MDAwKSwKICAgIHJhY2UxPSBjKCJCbGFjayIsIldoaXRlIiwiSGlzcGFuaWMiKSwKICAgIGxhYiA9IGMoIjxiIHN0eWxlPSdmb250LXNpemU6MTJwdDsnPkJsYWNrPC9iPiIsIAogICAgICAgICAgICAiPGIgc3R5bGU9J2ZvbnQtc2l6ZToxMnB0Oyc+V2hpdGU8L2I+IiwgCiAgICAgICAgICAgICAgIjxiIHN0eWxlPSdmb250LXNpemU6MTJwdDsnPkhpc3BhbmljPC9iPiIpLAogICAgICBhbmdsZSA9IGMoNTAsIDQyLCA1MSkKICAgICksIAogIGFlcyh4LHksbGFiZWw9bGFiLCBjb2xvcj1yYWNlMSxhbmdsZT1hbmdsZSksCiAgc2l6ZT0zLCBmaWxsPU5BLCBsYWJlbC5jb2xvcj1OQSwgCiAgbGluZWhlaWdodD0uMykgKwogIGxhYnModGl0bGU9IlN0dWRlbnQgTG9hbiBEZWJ0IEluIEFtZXJpY2EiLAogICAgICAgc3VidGl0bGU9IiBBdmVyYWdlIGZhbWlseSBzdHVkZW50IGxvYW4gZGVidCBmb3IgYWdlZCAyNS01NSwgYnkgcmFjZSBhbmQgeWVhciBub3JtYWxpemVkIHRvIDIwMTYgZG9sbGFycyIsCiAgICAgICBjYXB0aW9uPSJEYXRhIGZyb20gVXJiYW4gSW5zdGl0dXRlIGFuZCBVUyBDZW5zdXMiLAogICAgICAgeT0iIiwKICAgICAgIHg9IiIpCmBgYAoKCmBgYHtyfQpwMWIgPSBwMWEgKyAKICB0aGVtZSgKICAgICMjIHR1cm4gdGl0bGUgaW50byBmaWxsZWQgdGV4dGJveAogICAgcGxvdC50aXRsZSA9IGdndGV4dDo6ZWxlbWVudF90ZXh0Ym94X3NpbXBsZSgKICAgICAgY29sb3IgPSAid2hpdGUiLCBmaWxsID0gIiMxZDM1NTciLCAgc2l6ZSA9IDE0LCAKICAgICAgcGFkZGluZyA9IG1hcmdpbig4LCA0LCA4LCA0KSwgbWFyZ2luID0gbWFyZ2luKGIgPSA1KSwgbGluZWhlaWdodD0gLjkKICAgICksCiAgICAjIyBhZGQgcm91bmQgb3V0bGluZSB0byBjYXB0aW9uCiAgICBwbG90LmNhcHRpb24gPSBnZ3RleHQ6OmVsZW1lbnRfdGV4dGJveF9zaW1wbGUoCiAgICAgIHdpZHRoID0gTlVMTCwgbGluZXR5cGUgPSAxLCBjb2xvcj0ic2xhdGVncmV5IiwgcGFkZGluZyA9IG1hcmdpbigzLCA4LCAzLCA4KSwgCiAgICAgIG1hcmdpbiA9IG1hcmdpbih0ID0gMTUpLCByID0gZ3JpZDo6dW5pdCg4LCAicHQiKQogICAgKSwKICAgIGF4aXMudGl0bGUueCA9IGdndGV4dDo6ZWxlbWVudF9tYXJrZG93bigpLAogICAgYXhpcy50aXRsZS55ID0gZ2d0ZXh0OjplbGVtZW50X21hcmtkb3duKCksCiAgKSArCiAgIyMgdGV4dGJveAogIGdndGV4dDo6Z2VvbV90ZXh0Ym94KAogICAgZGF0YSA9IHRpYmJsZSh4ID0gMTk5NSwgeSA9IDEyMjAwLCBsYWJlbCA9ICJGcm9tIDIwMDcgdG8gMjAxNiwgdGhlIGF2ZXJhZ2Ugc3R1ZGVudCBsb2FuIGRlYnQgb2YgPHNwYW4gc3R5bGUgPSAnY29sb3I6IzllMmEyYic+PGI+QmxhY2s8L2I+PC9zcGFuPi1mYW1pbGllcyBpcyBoaWdoZXIgdGhhbiA8c3BhbiBzdHlsZSA9ICdjb2xvcjojZmI4NTAwJz48Yj5XaGl0ZTwvYj48L3NwYW4+LWZhbWlsaWVzIGFuZCAgPHNwYW4gc3R5bGUgPSAnY29sb3I6IzAwNmQ3Nyc+PGI+SGlzcGFuaWM8L2I+PC9zcGFuPi1mYW1pbGllcy4iKSwKICAgIGFlcyh4LCB5LCBsYWJlbCA9IGxhYmVsKSwgaW5oZXJpdC5hZXMgPSBGQUxTRSwKICAgIHNpemUgPSAzLAogICAgZmlsbCA9ICIjZTVlNWU1IiwgYm94LmNvbG9yID0gIiM0NTdiOWQiLAogICAgd2lkdGggPSB1bml0KDExLCAibGluZXMiKQogICkgCgpwMWIKYGBgCgojIyMgUDM6IHN0dWRlbnRfZGVidCAobG9hbl9kZWJ0IGFuZCBsb2FuX2RlYnRfcGN0KQoKYGBge3J9CnN0dWRlbnRfZGVidCAlPiUgCiAgZ2dwbG90KGFlcyh4PWxvYW5fZGVidCwgeT0gbG9hbl9kZWJ0X3BjdCwgY29sb3I9cmFjZSkpICsKICBnZW9tX3BvaW50KGFlcyhzaGFwZT1yYWNlKSxzaXplPTIpICsgCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjOWUyYTJiIiwiIzAwNmQ3NyIsIiNmYjg1MDAiKSkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWw9cGVyY2VudF9mb3JtYXQoYWNjdXJhY3k9MSkpICsKICBsYWJzKHRpdGxlPSAiU3R1ZGVudCBsb2FuIGRlYnQgYW5kIHNoYXJlIG9mIGZhbWlsaWVzIHdpdGggc3R1ZGVudCBsb2FuIGRlYnQiLAogICAgICAgY29sb3I9IlJhY2lhbCBncm91cCIsCiAgICAgICBzaGFwZT0iUmFjaWFsIGdyb3VwIiwKICAgICAgIGNhcHRpb249IkRhdGEgZnJvbSBVcmJhbiBJbnN0aXR1dGUgYW5kIFVTIENlbnN1cyIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249InRvcCIsCiAgICAgICAgcGxvdC50aXRsZT1lbGVtZW50X3RleHQoZmFjZT0iYm9sZCIsaGp1c3Q9MC41KSwKICAgICAgICBwbG90LmNhcHRpb249ZWxlbWVudF90ZXh0KGNvbG9yPSJzbGF0ZWdyZXkiKSkKYGBgCgojIyMgUDQ6IHJhY2Vfd2VhbHRoIAoKYGBge3J9CnJ3ID0gcmFjZV93ZWFsdGggJT4lIAogIGZpbHRlcighaXMubmEod2VhbHRoX2ZhbWlseSkpICU+JSAKICBmaWx0ZXIoeWVhcj49MTk4OSkgJT4lIAogIGZpbHRlcih0eXBlPT0iTWVkaWFuIikgJT4lCiAgZmlsdGVyKHJhY2UhPSJOb24tV2hpdGUiKSAlPiUKICBtdXRhdGUod2VhbHRoPXJvdW5kKHdlYWx0aF9mYW1pbHkpKSAlPiUKICBtdXRhdGUoZ3JwID0gaWZlbHNlKHdlYWx0aF9mYW1pbHk+MTAwMDAwLCJZIiwiTiIpKQpgYGAKCmBgYHtyfQpydyAlPiUKICBnZ3Bsb3QoYWVzKHg9YXMuZmFjdG9yKHllYXIpLCByYWNlKSkgKwogIGdlb21fdGlsZShhZXMoZmlsbD13ZWFsdGhfZmFtaWx5KSwgY29sb3I9IndoaXRlIiwgc2l6ZT0yKSArIAogIGdlb21fdGV4dChhZXMobGFiZWw9Y29tbWEod2VhbHRoKSwgY29sb3I9Z3JwKSxzaXplPTMpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIiwKICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEwLCBjb2xvcj0iYmxhY2siKSwKICAgICAgICBwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChmYWNlPSJib2xkIiksCiAgICAgICAgcGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwKICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KCksCiAgICAgICAgcGxvdC5jYXB0aW9uPWVsZW1lbnRfdGV4dChoanVzdD0wLCBjb2xvcj0ic2xhdGVncmV5IiksCiAgICAgICAgcGxvdC5jYXB0aW9uLnBvc2l0aW9uID0gInBsb3QiCiAgICAgICAgKSArIAogIHNjYWxlX3hfZGlzY3JldGUocG9zaXRpb249InRvcCIpICsgCiAgc2NhbGVfZmlsbF9jb250aW51b3VzX3NlcXVlbnRpYWwocGFsZXR0ZT0iRGFyayBNaW50IiwgdHJhbnM9ImxvZzEwIiwgbGFiZWw9ZG9sbGFyKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJibGFjayIsIndoaXRlIikpICsgCiAgbGFicyh4PSIiLAogICAgICAgeT0iIiwKICAgICAgIGZpbGw9Ik1lZGlhbiBGYW1pbHkgV2VhbHRoIiwKICAgICAgIHRpdGxlPSAiRmFtaWx5IFdlYWx0aCBpbiBBbWVyaWNhIGJ5IFJhY2UgYW5kIFllYXIiLAogICAgICBzdWJ0aXRsZSA9ICJOb3JtYWxpemVkIHRvIDIwMTYgZG9sbGFycyIsCiAgICAgIGNhcHRpb24gPSAiRGF0YSBmcm9tIFVyYmFuIEluc3RpdHV0ZSBhbmQgVVMgQ2Vuc3VzIikgKwogIGd1aWRlcyhmaWxsPSBndWlkZV9jb2xvcmJhcih0aXRsZS5wb3NpdGlvbj0idG9wIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUuaGp1c3QgPSAuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFyd2lkdGggPSB1bml0KDIwLCAibGluZXMiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFyaGVpZ2h0ID0gdW5pdCguNSwgImxpbmVzIikpKSArCiAgZ3VpZGVzKGNvbG9yPUZBTFNFKSAjcmVtb3ZlIHRleHQgY29sb3IgbGVnZW5kIApgYGAKCiMjIyBQNTogbGlmZXRpbWUgZWFybiAKKiBwbG90IGRlc2lnbiByZWZlcmVuY2U6IFtUb2JpYXMgU3RhbGRlcl0oaHR0cHM6Ly90d2l0dGVyLmNvbS90b2ViMTgvc3RhdHVzLzEzNTg0MDgzOTQ3MjIzOTQxMTcvcGhvdG8vMSkgCmBgYHtyfQpsaWZldGltZV9lYXJuICU+JSAKICBnZ3Bsb3QoYWVzKHg9bGlmZXRpbWVfZWFybiwgeT1mY3RfcmV2KHJhY2UpKSkgKwogIGdlb21fbGluZShhZXMoZ3JvdXA9cmFjZSksc2l6ZT03LGNvbG9yPSIjYjhiOGQxIixhbHBoYT0wLjUpICsgCiAgZ2VvbV9wb2ludChhZXMoY29sb3I9Z2VuZGVyKSxzaXplPTgsYWxwaGE9MC45KSArIAogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHM9c2NhbGVzOjpkb2xsYXJfZm9ybWF0KCksIGxpbWl0cz1jKDEwMDAwMDAsIDMwMDAwMDApKSArCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjM2E2ZWE1IiwiI2JkNjMyZiIpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlPSJib2xkIixoanVzdD0wLjUpKSArCiAgZ2VvbV90ZXh0KGFlcyh4PTEyMDAwMDAsIHk9My4yNSwgbGFiZWw9IkZlbWFsZSIpLCBjb2xvcj0iI2JkNjMyZiIsc2l6ZT0zLjYpICsgCiAgZ2VvbV90ZXh0KGFlcyh4PTE4MDAwMDAsIHk9My4yNSwgbGFiZWw9Ik1hbGUiKSwgY29sb3I9IiMzYTZlYTUiLHNpemU9My42KSArIAogIGdlb21fdGV4dChhZXMoeD0xNTAwMDAwLCB5PTMsIGxhYmVsPSJCbGFjayIpLHNpemU9My41LCBmYW1pbHk9IkNvdXJpZXIiKSArIAogIGdlb21fdGV4dChhZXMoeD0xNTUwMDAwLCB5PTIsIGxhYmVsPSJIaXNwYW5pYyBhbnkgcmFjZSIpLHNpemU9My41LCBmYW1pbHk9IkNvdXJpZXIiKSArCiAgZ2VvbV90ZXh0KGFlcyh4PTIxMDAwMDAsIHk9MSwgbGFiZWw9IldoaXRlIiksc2l6ZT0zLjUsIGZhbWlseT0iQ291cmllciIpICsgCiAgbGFicyh5PSIiLAogICAgICAgeD0iIiwKICAgICAgIHRpdGxlPSJBdmVyYWdlIGxpZmV0aW1lIGVhcm5pbmcgaW4gQW1lcmljYSBieSByYWNlIGFuZCBnZW5kZXIiLAogICAgICAgY2FwdGlvbj0iRGF0YSBmcm9tIFVyYmFuIEluc3RpdHV0ZSBhbmQgVVMgQ2Vuc3VzIikKYGBgCgoKIyMjIFA2OiBob21lX293bmVyCmBgYHtyfQpzdW1tYXJ5KGhvbWVfb3duZXIkeWVhcikKYGBgCgpgYGB7cn0KaG9tZV9vd25lciAlPiUgCiAgZmlsdGVyKHllYXI+MjAwNikgJT4lIAogIGdncGxvdChhZXMoeD15ZWFyLCB5PWhvbWVfb3duZXJfcGN0KSkgKwogIGdlb21fbGluZShhZXMoY29sb3I9cmFjZSksIHNpemU9MS41LCBhbHBoYT0wLjgpICsKICBnZW9tX21vb24oZGF0YT0gKGhvbWVfb3duZXIgJT4lIGZpbHRlcih5ZWFyPjIwMDYpKSwgYWVzKHJhdGlvPTEpLHNpemU9NSwgZmlsbD0iI2FkYjViZCIsY29sb3I9IndoaXRlIikgKwogIGdlb21fbW9vbihkYXRhPSAoaG9tZV9vd25lciAlPiUgZmlsdGVyKHllYXI+MjAwNikpLCBhZXMocmF0aW89aG9tZV9vd25lcl9wY3QsIGZpbGw9cmFjZSksIHNpemU9NSxjb2xvcj0id2hpdGUiKSArIAogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHM9YygwLjM1LDAuNzUpLGxhYmVscz0gcGVyY2VudF9mb3JtYXQoYWNjdXJhY3k9MSkpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgyMDA3LCAyMDE2LDEpKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb249Im5vbmUiLAogICAgICAgIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKHNpemU9MC4zKSwKICAgICAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoc2l6ZT04LCBjb2xvcj0ic2xhdGVncmV5IixoanVzdD0wLjUpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIsIGhqdXN0PTAuNSkpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjOWUyYTJiIiwiIzAwNmQ3NyIsIiNmYjg1MDAiKSkgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiIzllMmEyYiIsIiMwMDZkNzciLCIjZmI4NTAwIikpICsgCiAgZ2VvbV90ZXh0KGRhdGE9KGhvbWVfb3duZXIgJT4lIAogIGZpbHRlcih5ZWFyPjIwMDYpKSxhZXMoeT0wLjcxLCB4PTIwMTUsIGxhYmVsPSJXaGl0ZSIpLCBjb2xvcj0iI2ZiODUwMCIsIHNpemU9My41KSArIAogIGdlb21fdGV4dChkYXRhPShob21lX293bmVyICU+JSAKICBmaWx0ZXIoeWVhcj4yMDA2KSksYWVzKHk9MC40OSwgeD0yMDE1LCBsYWJlbD0iSGlzcGFuaWMiKSwgY29sb3I9IiMwMDZkNzciLCBzaXplPTMuNSkgKwogIGdlb21fdGV4dChkYXRhPShob21lX293bmVyICU+JSAKICBmaWx0ZXIoeWVhcj4yMDA2KSksYWVzKHk9MC4zOSwgeD0yMDE1LCBsYWJlbD0iQmxhY2siKSwgY29sb3I9IiM5ZTJhMmIiLCBzaXplPTMuNSkgKyAKICBsYWJzKHg9ICIiLAogICAgICAgeT0gIiIsCiAgICAgICB0aXRsZT0gIkhvbWUgT3duZXJzaGlwIFBlcmNlbnRhZ2UgaW4gQW1lcmljYSAoMjAwNyB0byAyMDE2KSIsCiAgICAgICBzdWJ0aXRsZT0iIGJ5IHllYXIgYW5kIHJhY2lhbCBncm91cCIsCiAgICAgICBjYXB0aW9uID0gIkRhdGEgZnJvbSBVcmJhbiBJbnN0aXR1dGUgYW5kIFVTIENlbnN1cyIpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGdndGV4dDo6ZWxlbWVudF90ZXh0Ym94X3NpbXBsZSgKICAgICAgICBjb2xvciA9ICJ3aGl0ZSIsIGZpbGwgPSAiIzFkMzU1NyIsICBzaXplID0gMTQsIAogICAgICAgIHBhZGRpbmcgPSBtYXJnaW4oOCwgNCwgOCwgNCksIG1hcmdpbiA9IG1hcmdpbihiID0gNSksIGxpbmVoZWlnaHQ9IC45KSkKYGBgCgojIyMgUDc6IE1lYW4gaW5jb21lIChieSBxdWludGlsZSkKCmBgYHtyfQppbTIgPSBpbmNvbWVfbWVhbiAlPiUKICBmaWx0ZXIoaW5jb21lX3F1aW50aWxlICE9ICJUb3AgNSUiKSAlPiUKICBtdXRhdGUoaW5jb21lX3F1aW50aWxlID0gZmFjdG9yKGluY29tZV9xdWludGlsZSwgbGV2ZWxzID0gYygiTG93ZXN0IiwgIlNlY29uZCIsICJNaWRkbGUiLCAiRm91cnRoIiwgIkhpZ2hlc3QiKSkpICU+JQogIGZpbHRlcihkb2xsYXJfdHlwZSA9PSAiMjAxOSBEb2xsYXJzIikgJT4lCiAgZmlsdGVyKHJhY2UgPT0iQWxsIFJhY2VzIikgJT4lCiAgZ3JvdXBfYnkoeWVhcikgJT4lCiAgbXV0YXRlKHBjdCA9IHJvdW5kKGluY29tZV9kb2xsYXJzL3N1bShpbmNvbWVfZG9sbGFycyksMikpCnN1bW1hcnkoaW0yJHllYXIpCmBgYAoKYGBge3J9CmdncGxvdChpbTIsIGFlcyh5ZWFyLCBpbmNvbWVfZG9sbGFycywgZmlsbD0oaW5jb21lX3F1aW50aWxlKSwgbGFiZWw9aW5jb21lX3F1aW50aWxlKSkgKyAKICBnZW9tX3N0cmVhbSh0eXBlPSJyaWRnZSIsIGJ3PTAuNzUpICsgCiAgZ2VvbV9zdHJlYW1fbGFiZWwoc2l6ZSA9IDMsIHR5cGUgPSAicmlkZ2UiLCBjb2xvcj0iYmxhY2siLCBmYW1pbHk9IkNvdXJpZXIgQm9sZCIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjODNjNWJlIiwiI2NiZjNmMCIsIiNmNGYzZWUiLCIjZmZiZjY5IiwiI2ZmOWYxYyIpKSArIAogIHRoZW1lX2xpZ2h0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiKSwKICAgICAgICBwbG90LnN1YnRpdGxlPSBlbGVtZW50X3RleHQoc2l6ZT0xMCksCiAgICAgICAgcGxvdC5jYXB0aW9uPSBlbGVtZW50X3RleHQoaGp1c3Q9MC41LCBjb2xvcj0ic2xhdGVncmV5IikKICAgICAgICApICsgCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1zZXEoMTk3MCwyMDE1LDUpKSArIAogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9ZG9sbGFyX2Zvcm1hdCgpKSArCiAgY29vcmRfY2FydGVzaWFuKGV4cGFuZD1GQUxTRSkgKyAKICBsYWJzKHg9IiIsCiAgICAgICB5PSIiLAogICAgICAgdGl0bGU9IkluY29tZSBDaGFuZ2VzIiwKICAgICAgIHN1YnRpdGxlPSJNZWFuIGluY29tZSByZWNlaXZlZCBieSBxdWludGlsZSBmcm9tIDE5NjcgdG8gMjAxOSwgbm9ybWFsaXplZCB0byAyMDE5IGRvbGxhciIsCiAgICAgICBjYXB0aW9uPSAiRGF0YSBmcm9tIFVyYmFuIEluc3RpdHV0ZSBhbmQgVVMgQ2Vuc3VzIikKYGBgCgoKYGBge3J9CiMgcHJvcG9ydGlvbiAKZ2dwbG90KGltMiwgYWVzKHllYXIsIHBjdCwgZmlsbD1pbmNvbWVfcXVpbnRpbGUsIGxhYmVsPWluY29tZV9xdWludGlsZSkpICsgCiAgZ2VvbV9zdHJlYW0odHlwZT0icHJvcG9ydGlvbmFsIiwgYnc9MC41KSArIAogIGdlb21fc3RyZWFtX2xhYmVsKHNpemUgPSAzLCB0eXBlID0gInByb3BvcnRpb25hbCIsIGNvbG9yPSJibGFjayIsIGZhbWlseT0iQ291cmllciBCb2xkIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiM4M2M1YmUiLCIjY2JmM2YwIiwiI2Y0ZjNlZSIsIiNmZmJmNjkiLCIjZmY5ZjFjIikpICsgCiAgdGhlbWVfbGlnaHQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiwKICAgICAgICApICsgCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1wZXJjZW50X2Zvcm1hdChhY2N1cmFjeT0xKSwgYnJlYWtzPXNlcSgwLDEsMC4yKSkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgxOTcwLDIwMTUsNSkpICsgCiAgY29vcmRfY2FydGVzaWFuKGV4cGFuZD1GQUxTRSkKYGBgCgoKIyMjIFA4OiByZXRpcmVtZW50IChhdmVyYWdlIGJ5IHJhY2lhbCBncm91cCkKCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpyZXRpcmVtZW50MiA9IHJldGlyZW1lbnQgJT4lIAogIG11dGF0ZShyZXQ9IHJvdW5kKHJldGlyZW1lbnQvMTAwMCkpICU+JQogIGZpbHRlcih5ZWFyPjIwMDApCnJldGlyZW1lbnQyJHllYXI9YXMuZmFjdG9yKHJldGlyZW1lbnQyJHllYXIpCgpuZXdnZ3Nsb3BlZ3JhcGgoZGF0YWZyYW1lID0gcmV0aXJlbWVudDIsCiAgICAgICAgICAgICAgICBUaW1lcyA9IHllYXIsCiAgICAgICAgICAgICAgICBNZWFzdXJlbWVudCA9IHJldCwKICAgICAgICAgICAgICAgIEdyb3VwaW5nID0gcmFjZSwKICAgICAgICAgICAgICAgIExpbmVUaGlja25lc3MgPSAxLAogICAgICAgICAgICAgICAgTGluZUNvbG9yID0gYygiV2hpdGUiPSIjZmI4NTAwIiwiSGlzcGFuaWMiPSIjMDA2ZDc3IiwgIkJsYWNrIj0iIzllMmEyYiIpLAogICAgICAgICAgICAgICAgVGl0bGUgPSAiQXZlcmFnZSBmYW1pbHkgbGlxdWlkIHJldGlyZW1lbnQgc2F2aW5ncyBieSByYWNpYWwgZ3JvdXAiLAogICAgICAgICAgICAgICAgU3ViVGl0bGUgPSAiUmV0aXJlbWVudCBkb2xsYXJzIChpbiB0aG91c2FuZHMpIGZyb20gMjAwMSB0byAyMDE2LCBub3JtYWxpemVkIHRvIDIwMTYgZG9sbGFyICIsCiAgICAgICAgICAgICAgICBDYXB0aW9uID0gIkRhdGEgZnJvbSBVcmJhbiBJbnN0aXR1dGUgYW5kIFVTIENlbnN1cyIsCiAgICAgICAgICAgICAgICBZVGV4dFNpemUgPSAzLjQsCiAgICAgICAgICAgICAgICBEYXRhVGV4dFNpemUgPSAzLAogICAgICAgICAgICAgICAgRGF0YUxhYmVsRmlsbENvbG9yID0gIndoaXRlIiwKICAgICAgICAgICAgICAgIERhdGFMYWJlbFBhZGRpbmc9MC4wNSwKICAgICAgICAgICAgICAgIENhcHRpb25KdXN0aWZ5ID0gImNlbnRlciIKICAgICAgICAgICAgICAgICkKYGBgCgoKIyMjIFA5OiBpbmNvbWUgbWVhbgoqIHJlZmVyZW5jZTogW1RpZHlUdWVzZGF5J3MgY2xlYW5pbmcgc2NyaXB0XShodHRwczovL2dpdGh1Yi5jb20vcmZvcmRhdGFzY2llbmNlL3RpZHl0dWVzZGF5L2Jsb2IvbWFzdGVyL2RhdGEvMjAyMS8yMDIxLTAyLTA5L3JlYWRtZS5tZCkKCmBgYHtyfQpzdW1tYXJ5KGluY29tZV9tZWFuJHllYXIpCmBgYAoKCmBgYHtyfQppbSA9IGluY29tZV9tZWFuICU+JQogIGZpbHRlcihpbmNvbWVfcXVpbnRpbGUgIT0gIlRvcCA1JSIpICU+JQogIG11dGF0ZShpbmNvbWVfcXVpbnRpbGUgPSBmYWN0b3IoaW5jb21lX3F1aW50aWxlLCBsZXZlbHMgPSBjKCJMb3dlc3QiLCAiU2Vjb25kIiwgIk1pZGRsZSIsICJGb3VydGgiLCAiSGlnaGVzdCIpKSkgJT4lCiAgZmlsdGVyKGRvbGxhcl90eXBlID09ICIyMDE5IERvbGxhcnMiKSAlPiUKICBmaWx0ZXIocmFjZSAlaW4lIGMoIldoaXRlIEFsb25lIiwgIkJsYWNrIEFsb25lIiwgIkhpc3BhbmljIikpICU+JQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBpbmNvbWVfZG9sbGFycywgY29sb3IgPSByYWNlLCBmaWxsID0gcmFjZSwgZ3JvdXAgPSByYWNlKSkgKwogIGdlb21fbGluZSgpICsKICBmYWNldF93cmFwKH5pbmNvbWVfcXVpbnRpbGUsIHNjYWxlcyA9ICJmcmVlX3kiKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzllMmEyYiIsIiMwMDZkNzciLCIjZmI4NTAwIikpICsgCiAgdGhlbWVfbGlnaHQoKSArCiAgdGhlbWUoc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChmYWNlPSJib2xkIiksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZD0gZWxlbWVudF9yZWN0KGZpbGw9IiMxZDM1NTciKSkgKyAKICBsYWJzKGNvbG9yPSJSYWNpYWwgR3JvdXAiLAogICAgICAgdGl0bGU9IkluY29tZSBRdWludGlsZSIsCiAgICAgICBzdWJ0aXRsZT0iTWVhbiBpbmNvbWUgcmVjZWl2ZWQgYnkgZWFjaCBmaWZ0aCBvZiBlYWNoIHJhY2lhbCBncm91cCBmcm9tIDE5NjcgdG8gMjAxOSIsCiAgICAgICB4PSJJbmNvbWUgKGluIGRvbGxhcnMpIiwKICAgICAgIHk9IlllYXIiLCBjYXB0aW9uPSAiRGF0YSBmcm9tIFVyYmFuIEluc3RpdHV0ZSBhbmQgVVMgQ2Vuc3VzIikKCnJlcG9zaXRpb25fbGVnZW5kKGltLCAnY2VudGVyJywgcGFuZWw9J3BhbmVsLTMtMicpCmBgYAoKIyMjIFAxMDogaW5jb21lIGRpc3RyaWJ1dGlvbgoqIHJlZmVyZW5jZTogW1RpZHlUdWVzZGF5J3MgY2xlYW5pbmcgc2NyaXB0XShodHRwczovL2dpdGh1Yi5jb20vcmZvcmRhdGFzY2llbmNlL3RpZHl0dWVzZGF5L2Jsb2IvbWFzdGVyL2RhdGEvMjAyMS8yMDIxLTAyLTA5L3JlYWRtZS5tZCkKCmBgYHtyfQppbmNvbWVfbGV2ZWxzIDwtIGMoCiAgIlVuZGVyICQxNSwwMDAiLAogICIkMTUsMDAwIHRvICQyNCw5OTkiLAogICIkMjUsMDAwIHRvICQzNCw5OTkiLAogICIkMzUsMDAwIHRvICQ0OSw5OTkiLAogICIkNTAsMDAwIHRvICQ3NCw5OTkiLAogICIkNzUsMDAwIHRvICQ5OSw5OTkiLAogICIkMTAwLDAwMCB0byAkMTQ5LDk5OSIsCiAgIiQxNTAsMDAwIHRvICQxOTksOTk5IiwKICAiJDIwMCwwMDAgYW5kIG92ZXIiCikKCgppbmNvbWVfZGlzdHJpYnV0aW9uICU+JQogIGZpbHRlcihyYWNlICVpbiUgYygiQmxhY2sgQWxvbmUiLCAiV2hpdGUgQWxvbmUiLCAiSGlzcGFuaWMgKEFueSBSYWNlKSIpKSAlPiUKICBmaWx0ZXIoeWVhciA+PSAxOTgwKSAlPiUKICBtdXRhdGUoaW5jb21lX2JyYWNrZXQgPSBmYWN0b3IoaW5jb21lX2JyYWNrZXQsIGxldmVscyA9IGluY29tZV9sZXZlbHMpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gaW5jb21lX2Rpc3RyaWJ1dGlvbiwgY29sb3IgPSByYWNlLCBmaWxsID0gcmFjZSkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJmaWxsIikgKwogIHRoZW1lX2xpZ2h0KCkgKyAKICBmYWNldF93cmFwKH5pbmNvbWVfYnJhY2tldCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCIjZmZjMTQ1IiwiI2MwYzBjMCIsIiMzYTZlYTUiKSkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiNmZmMxNDUiLCIjYzBjMGMwIiwiIzNhNmVhNSIpKSArCiAgY29vcmRfY2FydGVzaWFuKGV4cGFuZD1GQUxTRSkgKyAKICB0aGVtZShzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiLCBjb2xvcj0iIzI3M2U0NyIpLAogICAgICAgIHN0cmlwLmJhY2tncm91bmQ9IGVsZW1lbnRfcmVjdChmaWxsPSJ3aGl0ZSIpLAogICAgICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChzaXplPTgsIGZhY2U9Iml0YWxpYyIsaGp1c3Q9MCksCiAgICAgICAgcGxvdC5jYXB0aW9uLnBvc2l0aW9uID0gInBsb3QiKSArIAogIGxhYnMoZmlsbD0iUmFjaWFsIGdyb3VwIiwgCiAgICAgICBjb2xvcj0iUmFjaWFsIGdyb3VwIiwKICAgICAgIHk9IkluY29tZSBEaXN0cmlidXRpb24iLAogICAgICAgeD0iWWVhciIsCiAgICAgICBjYXB0aW9uPSAiRGF0YSBmcm9tIFVyYmFuIEluc3RpdHV0ZSBhbmQgVVMgQ2Vuc3VzIikKYGBgCgoKCgoK