Get to know the data through visualization
Each of the following questions are targeted at making sure we understand our data better. A great way to get a “feel” for a dataset is to visualize it. Answer each of the below questions with a (publishable-quality) picture.
1. How is lifeExp, pop and gdpPercap variables distributed?
Two ways to think about this: one is to plot each figure individually.
# Life Expectancy
gapminder %>%
ggplot(aes(lifeExp)) +
geom_histogram(bins=30) +
theme_bw()

# Population
gapminder %>%
ggplot(aes(pop)) +
geom_histogram(bins=30) +
theme_bw()

# GDP
gapminder %>%
ggplot(aes(gdpPercap)) +
geom_histogram(bins=30) +
theme_bw()

The better way is to plot all the functions at once using the pivot_longer() function from last time with facet_wrap()
gapminder %>%
pivot_longer(cols=c(lifeExp,pop,gdpPercap)) %>%
ggplot(aes(value)) +
geom_histogram(bins=30) +
facet_wrap(~name,scales="free") +
theme_bw()

We can quickly see that there is large right skews in both gdpPercap and pop. Let’s transform these variables and re-plot.
gapminder %>%
mutate(ln_pop = log(pop),
ln_gdppc = log(gdpPercap)) %>%
pivot_longer(cols=c(lifeExp,ln_pop,ln_gdppc)) %>%
ggplot(aes(value)) +
geom_histogram(bins=30) +
facet_wrap(~name,scales="free") +
theme_bw()

Now let’s make things look professional!
gapminder %>%
mutate(ln_pop = log(pop),
ln_gdppc = log(gdpPercap)) %>%
pivot_longer(cols=c(lifeExp,ln_pop,ln_gdppc)) %>%
mutate(name = case_when(
name == "lifeExp" ~ "Life Expectancy",
name == "ln_gdppc" ~ "Log GDP Per Capita",
name == "ln_pop" ~ "Log Population"
)) %>%
ggplot(aes(value,fill=name)) +
geom_histogram(bins=30,color="white",alpha=.5,show.legend = F) +
facet_wrap(~name,scales="free_x") +
labs(caption="Source: gapminder.org") +
scale_fill_economist() +
theme_fivethirtyeight() +
theme(text=element_text(family="serif",face="bold",size=16))

2. What’s the relationship between economic development and life expectancy? Is the relationship the same for all continents?
gapminder %>%
mutate(ln_pop = log(pop),
ln_gdppc = log(gdpPercap)) %>%
ggplot(aes(ln_gdppc,lifeExp)) +
geom_point() +
geom_smooth(method = "lm",se=F) # Let's fit a line to the data.

Useful but there are a number of small aesthetic adjustments we could make to really help use distinguish between what is going on.
gapminder %>%
mutate(ln_pop = log(pop),
ln_gdppc = log(gdpPercap)) %>%
ggplot(aes(ln_gdppc,lifeExp)) +
geom_point(alpha=.4,color="grey30") +
geom_smooth(method = "loess",se=F,color="darkred",size=1.5) +
theme_minimal()

Is the trend the same by continent?
gapminder %>%
mutate(ln_pop = log(pop),
ln_gdppc = log(gdpPercap)) %>%
ggplot(aes(ln_gdppc,lifeExp,color=continent)) +
geom_point(alpha=.4,) +
geom_smooth(method = "loess",se=F,size=1.5) +
theme_minimal()

Generally speaking, it appears so, but it’s difficult to hone in on any one continent. There is just a lot going on. Let’s consider two alternative ways of presenting this same data.
Way 1: separate plots using facet_
gapminder %>%
mutate(ln_pop = log(pop),
ln_gdppc = log(gdpPercap)) %>%
ggplot(aes(ln_gdppc,lifeExp,color=continent)) +
geom_point(alpha=.3,) +
geom_smooth(method = "loess",se=F,size=1.5) +
facet_wrap(~continent,nrow=1) +
labs(x="Log GDP Per Capita",y = "Life Expectancy",color="") +
scale_color_gdocs() +
theme_minimal() +
theme(legend.position = "bottom",
text = element_text(size=14,family="serif",face="bold"))

Way 2: Plot the trends but not the individual data points
gapminder %>%
mutate(ln_pop = log(pop),
ln_gdppc = log(gdpPercap)) %>%
ggplot(aes(ln_gdppc,lifeExp,color=continent)) +
geom_smooth(method = "loess",se=F,size=1.5) +
labs(x="Log GDP Per Capita",y = "Life Expectancy",color="") +
scale_color_gdocs() +
theme_minimal() +
theme(legend.position = "bottom",
text = element_text(size=14,family="serif",face="bold"))

3. Which countries in Africa have the lowest levels of life expectancy?
Two ways we could go about answering a question like this. The first might just be an ordered barplot. Here we might rephrase the question as: “Which countries in Africa have the lowest levels of life expectancy on average?”
gapminder %>%
filter(continent == "Africa") %>%
group_by(country) %>%
summarize(lifeExp = mean(lifeExp),.groups="drop") %>%
ggplot(aes(lifeExp,country)) +
geom_col()

Nice, but ordering the factor fields would go a long way. Doing so is easy using the tidy forcats package (which is part of the tidyverse), and why we’re at it, lets’ add a little polish.
gapminder %>%
filter(continent == "Africa") %>%
group_by(country) %>%
summarize(lifeExp = mean(lifeExp),.groups="drop") %>%
ggplot(aes(lifeExp,fct_reorder(country,desc(lifeExp)),fill=lifeExp)) +
geom_col(show.legend = F) +
scale_fill_gradient2_tableau() +
labs(x="Life Expectancy",y="",
title = "Average Life Expectancy in Africa",
subtitle = "1952 - 2007",
caption = "Source gapminder.org") +
theme_hc() +
theme(text=element_text(family = "serif",face="bold",size=14))

Another way we could approach this is to lay everything out spatially. ggplot with the maps package provides a useful way to extract map data on the fly.
map_data("world") %>%
ggplot(aes(x=long,y=lat,group=group)) +
geom_polygon()

Our focus is the African continent, so we’ll just focus on that portion of the data using the data wrangling principals.
# Simplify the map data
world <-
map_data("world") %>%
select(long,lat,group,country=region) %>%
# Again standardize the country names
mutate(country = countrycode::countrycode(country,"country.name","country.name")) %>%
mutate(country = ifelse(country == "South Sudan","Sudan",country))
# subset the relevant African countries in the data.
africa <-
gapminder %>%
filter(continent == "Africa") %>%
group_by(country) %>%
summarize(lifeExp = mean(lifeExp),.groups="drop") %>%
mutate(country = countrycode::countrycode(country,"country.name","country.name")) %>%
inner_join(world,by="country")
Let’s plot the map.
africa %>%
ggplot(aes(x=long,y=lat,group=group)) +
geom_polygon()

Now let’s fill in the fields on the map using the average life expectancy values.
africa %>%
ggplot(aes(x=long,y=lat,group=group,fill=lifeExp)) +
geom_polygon(color="white",size=.25) +
scale_fill_gradient2_tableau() +
theme_map() +
labs(fill="Life Expectancy",
title = "Average Life Expectancy in Africa",
subtitle = "1952 - 2007",
caption = "Source gapminder.org") +
theme(text=element_text(family = "serif",face="bold",size=14))

What if we wanted to look at how these spatial patterns shifted over time? Not a problem, we just need to tweak the data and plot code a little bit.
# DON'T aggregate the lifeExp variable this time.
gapminder %>%
filter(continent == "Africa") %>%
mutate(country = countrycode::countrycode(country,"country.name","country.name")) %>%
inner_join(world,by="country") %>%
ggplot(aes(x=long,y=lat,group=group,fill=lifeExp)) +
geom_polygon(color="white",size=.25) +
scale_fill_gradient2_tableau() +
theme_map() +
labs(fill="Life Expectancy",
title = "Average Life Expectancy in Africa",
subtitle = "1952 - 2007",
caption = "Source gapminder.org") +
facet_wrap(~year) +
theme(text=element_text(family = "serif",face="bold",size=18),
legend.position = "bottom")

LS0tCnRpdGxlOiB8CiB8IEVuaGFuY2UgYW5kIEFkdmFuY2UKIHwgSW50cm9kdWN0aW9uIHRvIFIKc3VidGl0bGU6IHwgCiAgfCBEYXRhIFZpc3VhbGl6YXRpb24gQXBwbGljYXRpb24gLSBHYXBtaW5kZXIgRGF0YSAoQU5TV0VSUykKYXV0aG9yOiBFcmljIER1bmZvcmQKYWZmaWxpYXRpb246ICJHZW9yZ2V0b3duIFVuaXZlcnNpdHkiCmRhdGU6ICJTdW1tZXIgMjAyMCIgCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIHRoZW1lOiBmbGF0bHkKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfZGVwdGg6IDUKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT0gRn0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVycm9yPUYsd2FybmluZyA9IEYsY29tbWVudD1GKQpgYGAKCgpgYGB7ciBkZXBlbmRlbmNpZXN9CiNpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQpyZXF1aXJlKHRpZHl2ZXJzZSkgIyBUaGUgdGlkeXZlcnNlIHBhY2thZ2UgY292ZXJlZCBsYXN0IHRpbWUgCgojIGluc3RhbGwucGFja2FnZXMoImdndGhlbWVzIikKcmVxdWlyZShnZ3RoZW1lcykgIyBmb3IgZ3JlYXQgdmlzdWFsaXphdGlvbiBjb2xvcnMgYW5kIHRoZW1lcy4gCgojIGluc3RhbGwucGFja2FnZXMoIm1hcHMiKQpyZXF1aXJlKG1hcHMpICMgZm9yIHNvbWUgbWFwcyBkYXRhCgojIEdhcG1pbmRlciBkYXRhIChmb3IgZXhhbXBsZSkKI2luc3RhbGwucGFja2FnZXMoImdhcG1pbmRlciIpCnJlcXVpcmUoZ2FwbWluZGVyKQpgYGAKCiMgRGF0YSAKClRoZSBbYEdhcG1pbmRlcmAgZGF0YXNldF0oaHR0cHM6Ly93d3cuZ2FwbWluZGVyLm9yZy8pIGlzIGEgZmFtb3VzIGRhdGFzZXQgdXNlZCBieSBIYW5zIFJvc2xpbmcgdG8gdmlzdWFsaXplIGRldmVsb3BtZW50IG91dGNvbWVzLiBUaGUgZGF0YSBjb3ZlcnMgMTk1MiB0byAyMDA3IGluIGZpdmUgeWVhciBpbnRlcnZhbHMgYW5kIG1lYXN1cmVzIGxpZmUgZXhwZWN0YW5jeSwgcG9wdWxhdGlvbiwgYW5kIEdEUCBQZXIgQ2FwaXRhLiAKCmBgYHtyfQpnYXBtaW5kZXIgJT4lIGhlYWQoKQpgYGAKCgojIEdldCB0byBrbm93IHRoZSBkYXRhIHRocm91Z2ggdmlzdWFsaXphdGlvbgoKRWFjaCBvZiB0aGUgZm9sbG93aW5nIHF1ZXN0aW9ucyBhcmUgdGFyZ2V0ZWQgYXQgbWFraW5nIHN1cmUgd2UgdW5kZXJzdGFuZCBvdXIgZGF0YSBiZXR0ZXIuIEEgZ3JlYXQgd2F5IHRvIGdldCBhICJmZWVsIiBmb3IgYSBkYXRhc2V0IGlzIHRvIHZpc3VhbGl6ZSBpdC4gQW5zd2VyIGVhY2ggb2YgdGhlIGJlbG93IHF1ZXN0aW9ucyB3aXRoIGEgKHB1Ymxpc2hhYmxlLXF1YWxpdHkpIHBpY3R1cmUuIAoKIyMjIyAxLiBIb3cgaXMgYGxpZmVFeHBgLCBgcG9wYCBhbmQgYGdkcFBlcmNhcGAgdmFyaWFibGVzIGRpc3RyaWJ1dGVkPwoKVHdvIHdheXMgdG8gdGhpbmsgYWJvdXQgdGhpczogb25lIGlzIHRvIHBsb3QgZWFjaCBmaWd1cmUgaW5kaXZpZHVhbGx5LiAKYGBge3IsZmlnLmFsaWduPSJjZW50ZXIiLGZpZy53aWR0aD03LGZpZy5oZWlnaHQ9NH0KIyBMaWZlIEV4cGVjdGFuY3kKZ2FwbWluZGVyICU+JSAKICBnZ3Bsb3QoYWVzKGxpZmVFeHApKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucz0zMCkgKwogIHRoZW1lX2J3KCkgCgojIFBvcHVsYXRpb24KZ2FwbWluZGVyICU+JSAKICBnZ3Bsb3QoYWVzKHBvcCkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zPTMwKSArCiAgdGhlbWVfYncoKSAKCiMgR0RQCmdhcG1pbmRlciAlPiUgCiAgZ2dwbG90KGFlcyhnZHBQZXJjYXApKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucz0zMCkgKwogIHRoZW1lX2J3KCkgCmBgYAoKClRoZSBiZXR0ZXIgd2F5IGlzIHRvIHBsb3QgYWxsIHRoZSBmdW5jdGlvbnMgYXQgb25jZSB1c2luZyB0aGUgYHBpdm90X2xvbmdlcigpYCBmdW5jdGlvbiBmcm9tIGxhc3QgdGltZSB3aXRoIGBmYWNldF93cmFwKClgCgpgYGB7cixmaWcuYWxpZ249ImNlbnRlciIsZmlnLndpZHRoPTEwLGZpZy5oZWlnaHQ9NH0KZ2FwbWluZGVyICU+JSAKICBwaXZvdF9sb25nZXIoY29scz1jKGxpZmVFeHAscG9wLGdkcFBlcmNhcCkpICU+JSAKICBnZ3Bsb3QoYWVzKHZhbHVlKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnM9MzApICsKICBmYWNldF93cmFwKH5uYW1lLHNjYWxlcz0iZnJlZSIpICsKICB0aGVtZV9idygpIApgYGAKV2UgY2FuIHF1aWNrbHkgc2VlIHRoYXQgdGhlcmUgaXMgbGFyZ2UgcmlnaHQgc2tld3MgaW4gYm90aCBgZ2RwUGVyY2FwYCBhbmQgYHBvcGAuIExldCdzIHRyYW5zZm9ybSB0aGVzZSB2YXJpYWJsZXMgYW5kIHJlLXBsb3QuCgpgYGB7cixmaWcuYWxpZ249ImNlbnRlciIsZmlnLndpZHRoPTEwLGZpZy5oZWlnaHQ9NH0KZ2FwbWluZGVyICU+JSAKICBtdXRhdGUobG5fcG9wID0gbG9nKHBvcCksCiAgICAgICAgIGxuX2dkcHBjID0gIGxvZyhnZHBQZXJjYXApKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKGNvbHM9YyhsaWZlRXhwLGxuX3BvcCxsbl9nZHBwYykpICU+JSAKICBnZ3Bsb3QoYWVzKHZhbHVlKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnM9MzApICsKICBmYWNldF93cmFwKH5uYW1lLHNjYWxlcz0iZnJlZSIpICsKICB0aGVtZV9idygpIApgYGAKCk5vdyBsZXQncyBtYWtlIHRoaW5ncyBsb29rIHByb2Zlc3Npb25hbCEKCmBgYHtyLGZpZy5hbGlnbj0iY2VudGVyIixmaWcud2lkdGg9MTAsZmlnLmhlaWdodD00fQpnYXBtaW5kZXIgJT4lIAogIG11dGF0ZShsbl9wb3AgPSBsb2cocG9wKSwKICAgICAgICAgbG5fZ2RwcGMgPSAgbG9nKGdkcFBlcmNhcCkpICU+JSAKICBwaXZvdF9sb25nZXIoY29scz1jKGxpZmVFeHAsbG5fcG9wLGxuX2dkcHBjKSkgJT4lIAogIG11dGF0ZShuYW1lID0gY2FzZV93aGVuKAogICAgbmFtZSA9PSAibGlmZUV4cCIgfiAiTGlmZSBFeHBlY3RhbmN5IiwKICAgIG5hbWUgPT0gImxuX2dkcHBjIiB+ICJMb2cgR0RQIFBlciBDYXBpdGEiLAogICAgbmFtZSA9PSAibG5fcG9wIiB+ICJMb2cgUG9wdWxhdGlvbiIKICApKSAlPiUgCiAgZ2dwbG90KGFlcyh2YWx1ZSxmaWxsPW5hbWUpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucz0zMCxjb2xvcj0id2hpdGUiLGFscGhhPS41LHNob3cubGVnZW5kID0gRikgKwogIGZhY2V0X3dyYXAofm5hbWUsc2NhbGVzPSJmcmVlX3giKSArCiAgbGFicyhjYXB0aW9uPSJTb3VyY2U6IGdhcG1pbmRlci5vcmciKSArCiAgc2NhbGVfZmlsbF9lY29ub21pc3QoKSArCiAgdGhlbWVfZml2ZXRoaXJ0eWVpZ2h0KCkgKwogIHRoZW1lKHRleHQ9ZWxlbWVudF90ZXh0KGZhbWlseT0ic2VyaWYiLGZhY2U9ImJvbGQiLHNpemU9MTYpKQpgYGAKCgoKIyMjIyAyLiBXaGF0J3MgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGVjb25vbWljIGRldmVsb3BtZW50IGFuZCBsaWZlIGV4cGVjdGFuY3k/IElzIHRoZSByZWxhdGlvbnNoaXAgdGhlIHNhbWUgZm9yIGFsbCBjb250aW5lbnRzPwoKYGBge3IsZmlnLmFsaWduPSJjZW50ZXIiLGZpZy53aWR0aD0xMCxmaWcuaGVpZ2h0PTR9CmdhcG1pbmRlciAlPiUgCiAgbXV0YXRlKGxuX3BvcCA9IGxvZyhwb3ApLAogICAgICAgICBsbl9nZHBwYyA9ICBsb2coZ2RwUGVyY2FwKSkgJT4lIAogIGdncGxvdChhZXMobG5fZ2RwcGMsbGlmZUV4cCkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsc2U9RikgIyBMZXQncyBmaXQgYSBsaW5lIHRvIHRoZSBkYXRhLgpgYGAKClVzZWZ1bCBidXQgdGhlcmUgYXJlIGEgbnVtYmVyIG9mIHNtYWxsIGFlc3RoZXRpYyBhZGp1c3RtZW50cyB3ZSBjb3VsZCBtYWtlIHRvIHJlYWxseSBoZWxwIHVzZSBkaXN0aW5ndWlzaCBiZXR3ZWVuIHdoYXQgaXMgZ29pbmcgb24uIAoKYGBge3IsZmlnLmFsaWduPSJjZW50ZXIiLGZpZy53aWR0aD0xMCxmaWcuaGVpZ2h0PTR9CmdhcG1pbmRlciAlPiUgCiAgbXV0YXRlKGxuX3BvcCA9IGxvZyhwb3ApLAogICAgICAgICBsbl9nZHBwYyA9ICBsb2coZ2RwUGVyY2FwKSkgJT4lIAogIGdncGxvdChhZXMobG5fZ2RwcGMsbGlmZUV4cCkpICsKICBnZW9tX3BvaW50KGFscGhhPS40LGNvbG9yPSJncmV5MzAiKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxvZXNzIixzZT1GLGNvbG9yPSJkYXJrcmVkIixzaXplPTEuNSkgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCklzIHRoZSB0cmVuZCB0aGUgc2FtZSBieSBjb250aW5lbnQ/CgpgYGB7cixmaWcuYWxpZ249ImNlbnRlciIsZmlnLndpZHRoPTEwLGZpZy5oZWlnaHQ9NH0KZ2FwbWluZGVyICU+JSAKICBtdXRhdGUobG5fcG9wID0gbG9nKHBvcCksCiAgICAgICAgIGxuX2dkcHBjID0gIGxvZyhnZHBQZXJjYXApKSAlPiUgCiAgZ2dwbG90KGFlcyhsbl9nZHBwYyxsaWZlRXhwLGNvbG9yPWNvbnRpbmVudCkpICsKICBnZW9tX3BvaW50KGFscGhhPS40LCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsc2U9RixzaXplPTEuNSkgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCkdlbmVyYWxseSBzcGVha2luZywgaXQgYXBwZWFycyBzbywgYnV0IGl0J3MgZGlmZmljdWx0IHRvIGhvbmUgaW4gb24gYW55IG9uZSBjb250aW5lbnQuIFRoZXJlIGlzIGp1c3QgYSBsb3QgZ29pbmcgb24uIExldCdzIGNvbnNpZGVyIHR3byBhbHRlcm5hdGl2ZSB3YXlzIG9mIHByZXNlbnRpbmcgdGhpcyBzYW1lIGRhdGEuIAoKV2F5IDE6IHNlcGFyYXRlIHBsb3RzIHVzaW5nIGBmYWNldF9gCgpgYGB7cixmaWcuYWxpZ249ImNlbnRlciIsZmlnLndpZHRoPTEwLGZpZy5oZWlnaHQ9NH0KZ2FwbWluZGVyICU+JSAKICBtdXRhdGUobG5fcG9wID0gbG9nKHBvcCksCiAgICAgICAgIGxuX2dkcHBjID0gIGxvZyhnZHBQZXJjYXApKSAlPiUgCiAgZ2dwbG90KGFlcyhsbl9nZHBwYyxsaWZlRXhwLGNvbG9yPWNvbnRpbmVudCkpICsKICBnZW9tX3BvaW50KGFscGhhPS4zLCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsc2U9RixzaXplPTEuNSkgKwogIGZhY2V0X3dyYXAofmNvbnRpbmVudCxucm93PTEpICsKICBsYWJzKHg9IkxvZyBHRFAgUGVyIENhcGl0YSIseSA9ICJMaWZlIEV4cGVjdGFuY3kiLGNvbG9yPSIiKSArCiAgc2NhbGVfY29sb3JfZ2RvY3MoKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTQsZmFtaWx5PSJzZXJpZiIsZmFjZT0iYm9sZCIpKQpgYGAKCldheSAyOiBQbG90IHRoZSB0cmVuZHMgYnV0IG5vdCB0aGUgaW5kaXZpZHVhbCBkYXRhIHBvaW50cwoKYGBge3IsZmlnLmFsaWduPSJjZW50ZXIiLGZpZy53aWR0aD03LGZpZy5oZWlnaHQ9NX0KZ2FwbWluZGVyICU+JSAKICBtdXRhdGUobG5fcG9wID0gbG9nKHBvcCksCiAgICAgICAgIGxuX2dkcHBjID0gIGxvZyhnZHBQZXJjYXApKSAlPiUgCiAgZ2dwbG90KGFlcyhsbl9nZHBwYyxsaWZlRXhwLGNvbG9yPWNvbnRpbmVudCkpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLHNlPUYsc2l6ZT0xLjUpICsKICBsYWJzKHg9IkxvZyBHRFAgUGVyIENhcGl0YSIseSA9ICJMaWZlIEV4cGVjdGFuY3kiLGNvbG9yPSIiKSArCiAgc2NhbGVfY29sb3JfZ2RvY3MoKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTQsZmFtaWx5PSJzZXJpZiIsZmFjZT0iYm9sZCIpKQpgYGAKCiMjIyMgMy4gV2hpY2ggY291bnRyaWVzIGluIEFmcmljYSBoYXZlIHRoZSBsb3dlc3QgbGV2ZWxzIG9mIGxpZmUgZXhwZWN0YW5jeT8KClR3byB3YXlzIHdlIGNvdWxkIGdvIGFib3V0IGFuc3dlcmluZyBhIHF1ZXN0aW9uIGxpa2UgdGhpcy4gVGhlIGZpcnN0IG1pZ2h0IGp1c3QgYmUgYW4gb3JkZXJlZCBiYXJwbG90LiBIZXJlIHdlIG1pZ2h0IHJlcGhyYXNlIHRoZSBxdWVzdGlvbiBhczogIldoaWNoIGNvdW50cmllcyBpbiBBZnJpY2EgaGF2ZSB0aGUgbG93ZXN0IGxldmVscyBvZiBsaWZlIGV4cGVjdGFuY3kgX29uIGF2ZXJhZ2VfPyIKCmBgYHtyLGZpZy5hbGlnbj0iY2VudGVyIixmaWcud2lkdGg9NyxmaWcuaGVpZ2h0PTd9CmdhcG1pbmRlciAlPiUgCiAgZmlsdGVyKGNvbnRpbmVudCA9PSAiQWZyaWNhIikgJT4lIAogIGdyb3VwX2J5KGNvdW50cnkpICU+JSAKICBzdW1tYXJpemUobGlmZUV4cCA9IG1lYW4obGlmZUV4cCksLmdyb3Vwcz0iZHJvcCIpICU+JSAKICBnZ3Bsb3QoYWVzKGxpZmVFeHAsY291bnRyeSkpICsKICBnZW9tX2NvbCgpIApgYGAKCk5pY2UsIGJ1dCBvcmRlcmluZyB0aGUgZmFjdG9yIGZpZWxkcyB3b3VsZCBnbyBhIGxvbmcgd2F5LiBEb2luZyBzbyBpcyBlYXN5IHVzaW5nIHRoZSB0aWR5IGBmb3JjYXRzYCBwYWNrYWdlICh3aGljaCBpcyBwYXJ0IG9mIHRoZSB0aWR5dmVyc2UpLCBhbmQgd2h5IHdlJ3JlIGF0IGl0LCBsZXRzJyBhZGQgYSBsaXR0bGUgcG9saXNoLiAKCmBgYHtyLGZpZy5hbGlnbj0iY2VudGVyIixmaWcud2lkdGg9NyxmaWcuaGVpZ2h0PTcuNX0KZ2FwbWluZGVyICU+JSAKICBmaWx0ZXIoY29udGluZW50ID09ICJBZnJpY2EiKSAlPiUgCiAgZ3JvdXBfYnkoY291bnRyeSkgJT4lIAogIHN1bW1hcml6ZShsaWZlRXhwID0gbWVhbihsaWZlRXhwKSwuZ3JvdXBzPSJkcm9wIikgJT4lIAogIGdncGxvdChhZXMobGlmZUV4cCxmY3RfcmVvcmRlcihjb3VudHJ5LGRlc2MobGlmZUV4cCkpLGZpbGw9bGlmZUV4cCkpICsKICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEYpICsKICBzY2FsZV9maWxsX2dyYWRpZW50Ml90YWJsZWF1KCkgKwogIGxhYnMoeD0iTGlmZSBFeHBlY3RhbmN5Iix5PSIiLAogICAgICAgdGl0bGUgPSAiQXZlcmFnZSBMaWZlIEV4cGVjdGFuY3kgaW4gQWZyaWNhIiwKICAgICAgIHN1YnRpdGxlID0gIjE5NTIgLSAyMDA3IiwKICAgICAgIGNhcHRpb24gPSAiU291cmNlIGdhcG1pbmRlci5vcmciKSArCiAgdGhlbWVfaGMoKSArCiAgdGhlbWUodGV4dD1lbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIixmYWNlPSJib2xkIixzaXplPTE0KSkKYGBgCgpBbm90aGVyIHdheSB3ZSBjb3VsZCBhcHByb2FjaCB0aGlzIGlzIHRvIGxheSBldmVyeXRoaW5nIG91dCBzcGF0aWFsbHkuIGdncGxvdCB3aXRoIHRoZSBgbWFwc2AgcGFja2FnZSBwcm92aWRlcyBhIHVzZWZ1bCB3YXkgdG8gZXh0cmFjdCBtYXAgZGF0YSBvbiB0aGUgZmx5LiAKCmBgYHtyLGZpZy5hbGlnbj0iY2VudGVyIixmaWcud2lkdGg9MTEsZmlnLmhlaWdodD03fQptYXBfZGF0YSgid29ybGQiKSAlPiUKICBnZ3Bsb3QoYWVzKHg9bG9uZyx5PWxhdCxncm91cD1ncm91cCkpICsKICBnZW9tX3BvbHlnb24oKQpgYGAKCk91ciBmb2N1cyBpcyB0aGUgQWZyaWNhbiBjb250aW5lbnQsIHNvIHdlJ2xsIGp1c3QgZm9jdXMgb24gdGhhdCBwb3J0aW9uIG9mIHRoZSBkYXRhIHVzaW5nIHRoZSBkYXRhIHdyYW5nbGluZyBwcmluY2lwYWxzLiAKCmBgYHtyfQoKIyBTaW1wbGlmeSB0aGUgbWFwIGRhdGEgCndvcmxkIDwtIAogIG1hcF9kYXRhKCJ3b3JsZCIpICU+JSAKICBzZWxlY3QobG9uZyxsYXQsZ3JvdXAsY291bnRyeT1yZWdpb24pICU+JSAKICAKICAjIEFnYWluIHN0YW5kYXJkaXplIHRoZSBjb3VudHJ5IG5hbWVzCiAgbXV0YXRlKGNvdW50cnkgPSBjb3VudHJ5Y29kZTo6Y291bnRyeWNvZGUoY291bnRyeSwiY291bnRyeS5uYW1lIiwiY291bnRyeS5uYW1lIikpICU+JSAKICBtdXRhdGUoY291bnRyeSA9IGlmZWxzZShjb3VudHJ5ID09ICJTb3V0aCBTdWRhbiIsIlN1ZGFuIixjb3VudHJ5KSkKCiMgc3Vic2V0IHRoZSByZWxldmFudCBBZnJpY2FuIGNvdW50cmllcyBpbiB0aGUgZGF0YS4KYWZyaWNhIDwtIAogIGdhcG1pbmRlciAlPiUgCiAgZmlsdGVyKGNvbnRpbmVudCA9PSAiQWZyaWNhIikgJT4lIAogIGdyb3VwX2J5KGNvdW50cnkpICU+JSAKICBzdW1tYXJpemUobGlmZUV4cCA9IG1lYW4obGlmZUV4cCksLmdyb3Vwcz0iZHJvcCIpICAlPiUgCiAgbXV0YXRlKGNvdW50cnkgPSBjb3VudHJ5Y29kZTo6Y291bnRyeWNvZGUoY291bnRyeSwiY291bnRyeS5uYW1lIiwiY291bnRyeS5uYW1lIikpICU+JSAKICBpbm5lcl9qb2luKHdvcmxkLGJ5PSJjb3VudHJ5IikKYGBgCgpMZXQncyBwbG90IHRoZSBtYXAuIAoKYGBge3IsZmlnLmFsaWduPSJjZW50ZXIiLGZpZy53aWR0aD02LGZpZy5oZWlnaHQ9N30KYWZyaWNhICU+JSAKICBnZ3Bsb3QoYWVzKHg9bG9uZyx5PWxhdCxncm91cD1ncm91cCkpICsKICBnZW9tX3BvbHlnb24oKQpgYGAKCgpOb3cgbGV0J3MgZmlsbCBpbiB0aGUgZmllbGRzIG9uIHRoZSBtYXAgdXNpbmcgdGhlIGF2ZXJhZ2UgbGlmZSBleHBlY3RhbmN5IHZhbHVlcy4KCmBgYHtyLGZpZy5hbGlnbj0iY2VudGVyIixmaWcud2lkdGg9NixmaWcuaGVpZ2h0PTd9CmFmcmljYSAlPiUgCiAgZ2dwbG90KGFlcyh4PWxvbmcseT1sYXQsZ3JvdXA9Z3JvdXAsZmlsbD1saWZlRXhwKSkgKwogIGdlb21fcG9seWdvbihjb2xvcj0id2hpdGUiLHNpemU9LjI1KSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudDJfdGFibGVhdSgpICsKICB0aGVtZV9tYXAoKSArCiAgbGFicyhmaWxsPSJMaWZlIEV4cGVjdGFuY3kiLAogICAgICAgdGl0bGUgPSAiQXZlcmFnZSBMaWZlIEV4cGVjdGFuY3kgaW4gQWZyaWNhIiwKICAgICAgIHN1YnRpdGxlID0gIjE5NTIgLSAyMDA3IiwKICAgICAgIGNhcHRpb24gPSAiU291cmNlIGdhcG1pbmRlci5vcmciKSArCiAgdGhlbWUodGV4dD1lbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIixmYWNlPSJib2xkIixzaXplPTE0KSkKYGBgCgpXaGF0IGlmIHdlIHdhbnRlZCB0byBsb29rIGF0IGhvdyB0aGVzZSBzcGF0aWFsIHBhdHRlcm5zIHNoaWZ0ZWQgb3ZlciB0aW1lPyBOb3QgYSBwcm9ibGVtLCB3ZSBqdXN0IG5lZWQgdG8gdHdlYWsgdGhlIGRhdGEgYW5kIHBsb3QgY29kZSBhIGxpdHRsZSBiaXQuIAoKYGBge3IsZmlnLmFsaWduPSJjZW50ZXIiLGZpZy53aWR0aD0xNSxmaWcuaGVpZ2h0PTE1fQojIERPTidUIGFnZ3JlZ2F0ZSB0aGUgbGlmZUV4cCB2YXJpYWJsZSB0aGlzIHRpbWUuIApnYXBtaW5kZXIgJT4lIAogIGZpbHRlcihjb250aW5lbnQgPT0gIkFmcmljYSIpICU+JSAKICBtdXRhdGUoY291bnRyeSA9IGNvdW50cnljb2RlOjpjb3VudHJ5Y29kZShjb3VudHJ5LCJjb3VudHJ5Lm5hbWUiLCJjb3VudHJ5Lm5hbWUiKSkgJT4lIAogIGlubmVyX2pvaW4od29ybGQsYnk9ImNvdW50cnkiKSAlPiUgCiAgZ2dwbG90KGFlcyh4PWxvbmcseT1sYXQsZ3JvdXA9Z3JvdXAsZmlsbD1saWZlRXhwKSkgKwogIGdlb21fcG9seWdvbihjb2xvcj0id2hpdGUiLHNpemU9LjI1KSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudDJfdGFibGVhdSgpICsKICB0aGVtZV9tYXAoKSArCiAgbGFicyhmaWxsPSJMaWZlIEV4cGVjdGFuY3kiLAogICAgICAgdGl0bGUgPSAiQXZlcmFnZSBMaWZlIEV4cGVjdGFuY3kgaW4gQWZyaWNhIiwKICAgICAgIHN1YnRpdGxlID0gIjE5NTIgLSAyMDA3IiwKICAgICAgIGNhcHRpb24gPSAiU291cmNlIGdhcG1pbmRlci5vcmciKSArCiAgZmFjZXRfd3JhcCh+eWVhcikgKwogIHRoZW1lKHRleHQ9ZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIsZmFjZT0iYm9sZCIsc2l6ZT0xOCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCmBgYAoKCgoKCg==