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