Data Visualization Notes

These are my notes for GRD 610A: Data Visualization II in Winter 2021 at the College for Creative Studies. These notes are for my work in the book Data Visualization by Kieran Healy (Princeton University Press, 2019).

Get Started

Everything has a name

Objects in R are created and referred to by their names. Certain names are not allowed because they are reserved words such as TRUE, if, mean(), and NA. Names also cannot start with a number or contain spaces. There are different naming conventions.

Snake Case
my_data
this_is_snake_case

Camel Case
myData
thisIsCamelCase

Pascal Case
MyData
ThisIsPascalCase

Pick one naming convention and stick with it. Be consistent; don’t switch between conventions. I recommend snake case.

# This is a comment (it starts with #)

my_data <- c(1, 2, 3, 4) # Assign using <- ; use ALT + - or OPTION + -

My_Data  
## Error in eval(expr, envir, enclos): object 'My_Data' not found
# Cannot be found because we called it my_data (lowercase)

# Now we can see it
my_data 
## [1] 1 2 3 4

Everything is an object; using functions

Think of functions like a recipe. The arguments of the function are the ingredients and what happens within the function is the sequence of cooking steps.

c(1, 2, 3, 1, 3, 5, 25) # c() is the combine function, it puts things together into a vector/list
## [1]  1  2  3  1  3  5 25
my_numbers <- c(1, 2, 3, 1, 3, 5, 25)
your_numbers <- c(5, 31, 71, 1, 3, 21, 6)

my_numbers
## [1]  1  2  3  1  3  5 25
mean(x = my_numbers)
## [1] 5.714286
mean(my_numbers) # you don't have to specify the argument names, but order matters if you do not specify
## [1] 5.714286
mean(x = your_numbers)
## [1] 19.71429
my_summary <- summary(my_numbers)

my_summary
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   1.000   1.500   3.000   5.714   4.000  25.000
table(my_numbers)
## my_numbers
##  1  2  3  5 25 
##  2  1  2  1  1
sd(my_numbers)
## [1] 8.616153
my_numbers * 5
## [1]   5  10  15   5  15  25 125
my_numbers + 1
## [1]  2  3  4  2  4  6 26
my_numbers + my_numbers # How is this different than the last line?
## [1]  2  4  6  2  6 10 50
# If you're not sure what an object is, ask for its class or type

class(my_numbers)
## [1] "numeric"
class(my_summary)
## [1] "summaryDefault" "table"
class(summary)
## [1] "function"
my_new_vector <- c(my_numbers, "Apple") # What happens if we combine a word with numbers?

my_new_vector
## [1] "1"     "2"     "3"     "1"     "3"     "5"     "25"    "Apple"
class(my_new_vector)
## [1] "character"
# Let's look at a new dataset

titanic
##       fate    sex    n percent
## 1 perished   male 1364    62.0
## 2 perished female  126     5.7
## 3 survived   male  367    16.7
## 4 survived female  344    15.6
class(titanic) 
## [1] "data.frame"
# Titanic is a data frame, which is like a table
# The $ operator can be used to access a column of a data frame by name

titanic$percent
## [1] 62.0  5.7 16.7 15.6
# Tibbles are slightly different than data frames. They are also data tables, but they provide more information.

titanic_tb <- as_tibble(titanic)

titanic_tb # How is does this compare to titanic above?
## # A tibble: 4 x 4
##   fate     sex        n percent
##   <fct>    <fct>  <dbl>   <dbl>
## 1 perished male    1364    62  
## 2 perished female   126     5.7
## 3 survived male     367    16.7
## 4 survived female   344    15.6
# To see inside an object, ask for its structure

str(my_numbers)
##  num [1:7] 1 2 3 1 3 5 25
str(my_summary)
##  'summaryDefault' Named num [1:6] 1 1.5 3 5.71 4 ...
##  - attr(*, "names")= chr [1:6] "Min." "1st Qu." "Median" "Mean" ...

Programming in R can be challenging and it takes time to get used to. Be patient and take a break if you get stuck. Make sure parentheses are opened and closed. Complete your commands (look out for the + in the console). Take your time and lookout for typos.

Get Data into R

In this section, we will get data from a URL and make a quick figure.

# Data source
url <- "https://cdn.rawgit.com/kjhealy/viz-organdata/master/organdonation.csv"

# Read the CSV from the URL
organs <- read_csv(file = url)

# Take a quick look at the data
glimpse(organs)
## Rows: 238
## Columns: 21
## $ country          <chr> "Australia", "Australia", "Australia", "Australia"...
## $ year             <dbl> NA, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998...
## $ donors           <dbl> NA, 12.09, 12.35, 12.51, 10.25, 10.18, 10.59, 10.2...
## $ pop              <dbl> 17065, 17284, 17495, 17667, 17855, 18072, 18311, 1...
## $ pop.dens         <dbl> 0.2204433, 0.2232723, 0.2259980, 0.2282198, 0.2306...
## $ gdp              <dbl> 16774, 17171, 17914, 18883, 19849, 21079, 21923, 2...
## $ gdp.lag          <dbl> 16591, 16774, 17171, 17914, 18883, 19849, 21079, 2...
## $ health           <dbl> 1300, 1379, 1455, 1540, 1626, 1737, 1846, 1948, 20...
## $ health.lag       <dbl> 1224, 1300, 1379, 1455, 1540, 1626, 1737, 1846, 19...
## $ pubhealth        <dbl> 4.8, 5.4, 5.4, 5.4, 5.4, 5.5, 5.6, 5.7, 5.9, 6.1, ...
## $ roads            <dbl> 136.59537, 122.25179, 112.83224, 110.54508, 107.98...
## $ cerebvas         <dbl> 682, 647, 630, 611, 631, 592, 576, 525, 516, 493, ...
## $ assault          <dbl> 21, 19, 17, 18, 17, 16, 17, 17, 16, 15, 16, 15, 14...
## $ external         <dbl> 444, 425, 406, 376, 387, 371, 395, 385, 410, 409, ...
## $ txp.pop          <dbl> 0.9375916, 0.9257116, 0.9145470, 0.9056433, 0.8961...
## $ world            <chr> "Liberal", "Liberal", "Liberal", "Liberal", "Liber...
## $ opt              <chr> "In", "In", "In", "In", "In", "In", "In", "In", "I...
## $ consent.law      <chr> "Informed", "Informed", "Informed", "Informed", "I...
## $ consent.practice <chr> "Informed", "Informed", "Informed", "Informed", "I...
## $ consistent       <chr> "Yes", "Yes", "Yes", "Yes", "Yes", "Yes", "Yes", "...
## $ ccode            <chr> "Oz", "Oz", "Oz", "Oz", "Oz", "Oz", "Oz", "Oz", "O...
# View(organs) # Run in RStudio
# Another way to view data 
gapminder
## # A tibble: 1,704 x 6
##    country     continent  year lifeExp      pop gdpPercap
##    <fct>       <fct>     <int>   <dbl>    <int>     <dbl>
##  1 Afghanistan Asia       1952    28.8  8425333      779.
##  2 Afghanistan Asia       1957    30.3  9240934      821.
##  3 Afghanistan Asia       1962    32.0 10267083      853.
##  4 Afghanistan Asia       1967    34.0 11537966      836.
##  5 Afghanistan Asia       1972    36.1 13079460      740.
##  6 Afghanistan Asia       1977    38.4 14880372      786.
##  7 Afghanistan Asia       1982    39.9 12881816      978.
##  8 Afghanistan Asia       1987    40.8 13867957      852.
##  9 Afghanistan Asia       1992    41.7 16317921      649.
## 10 Afghanistan Asia       1997    41.8 22227415      635.
## # ... with 1,694 more rows
# Make a plot object
p <- ggplot(data = gapminder,
            mapping = aes(x = gdpPercap, 
                          y = lifeExp))

# Create a scatterplot
p + geom_point()

Make a Plot

ggplot2 is an R library/package that allows us to map data to visual elements. Using it we can control the way the data appears in the plot and how each element of the plot will be displayed. Aesthetic Mappings make the connection between the data and how it is displayed on the plot (location, size, color, shape, etc.). Geoms define the type of plot (scatterplot, line plot, box plot, bar chart, etc.). Code is added together to make the plot using + the plus sign. More pieces can be added to the plot that define the scales, legend, labels, axes, style or theme of the plot, etc. Each part can be added using different functions with arguments specifying the look of the plot; the plot is built up piece by piece.

Tidy Data

In tidy data:
1. Each variable forms a column.
2. Each observation forms a row.
3. Each type of observational unit forms a table.

From Wickham, H. (2014). Tidy Data. Journal of Statistical Software, 59(10).

Mapping

Build a plot layer by layer, starting with telling ggplot what data to use and how to map or link it to parts of the plot, like the x and y axes. Then add on the type of geom.

p <- ggplot(data = gapminder,
              mapping = aes(x = gdpPercap,
                            y = lifeExp)) 

  p + geom_point()

Layer by Layer

Trying different geom_ functions.

p <- ggplot(data = gapminder,
            mapping = aes(x = gdpPercap,
                          y = lifeExp))

p + geom_smooth()

p + geom_point() + # add the points back into the plot 
  geom_smooth() 

p + geom_point() + 
  geom_smooth(method = "lm") # use a linear model

p + geom_point() +
  geom_smooth(method = "gam") + # generalized additive model
  scale_x_log10() # transform x-axis to log-10 scale

p + geom_point() +
  geom_smooth(method = "gam") +
  scale_x_log10(labels = scales::dollar) # format x-axis in dollars

Mapping Aesthetics

Using the aesthetics mapping, different parts of the data can be encoded in different ways.

p <- ggplot(data = gapminder,
            mapping = aes(x = gdpPercap,
                          y = lifeExp,
                          color = "purple")) # ggplot adds the value "purple" to all rows

p + geom_point() +
  geom_smooth(method = "loess") +
  scale_x_log10()

# To actually turn all of the points purple, we need to set the color property of the geom_ function

p <- ggplot(data = gapminder,
            mapping = aes(x = gdpPercap,
                          y = lifeExp))

p + geom_point(color = "purple") + # set point color to purple
  geom_smooth(method = "loess") +
  scale_x_log10()

p + geom_point(alpha = 0.3) + # make points more transparent
  geom_smooth(color = "orange", # make line orange
              se = FALSE, # remove standard error band
              size = 8, # increase thickness of the line
              method = "lm") +
  scale_x_log10()

p + geom_point(alpha = 0.3) + # make points more transparent
  geom_smooth(method = "gam") +
  scale_x_log10(labels = scales::dollar) +
  # Add title and labels
  labs(x = "GDP per Capita", 
       y = "Life Expectancy in Years",
       title = "Economic Growth and Life Expectancy",
       subtitle = "Data points are country-years",
       caption = "Source: Gapminder")

# Map data by continent
p <- ggplot(data = gapminder,
            mapping = aes(x = gdpPercap,
                          y = lifeExp,
                          color = continent))

p + geom_point() +
  geom_smooth(method = "loess") +
  scale_x_log10()

p <- ggplot(data = gapminder,
            mapping = aes(x = gdpPercap,
                          y = lifeExp,
                          color = continent,
                          fill = continent)) # now the error bands will also have the color

p + geom_point() +
  geom_smooth(method = "loess") +
  scale_x_log10()

Aesthetics by Geom

p <- ggplot(data = gapminder,
            mapping = aes(x = gdpPercap,
                          y = lifeExp))

p + geom_point(mapping = aes(color = continent)) + # points will be colored by continent
  geom_smooth(method = "loess") + # the smoothed line will be for all data
  scale_x_log10()

p + geom_point(mapping = aes(color = log(pop))) + # points will be colored by population
  scale_x_log10()

Saving

Use here() to save plots in the current directory. This function can also be used to reference folders within the current directory. For this class, use .svg to save in vector format and embed in Adobe Illustrator. The function to save a plot is ggsave() which will automatically save the last plot and can also be provided a ggplot object to save.

Where to Go Next

Pick at least two of the questions presented under the Where to Go Next section and answer them.

Show the Right Numbers

“Code almost never works properly the first time you write it.” (p. 73)

Grouping

p <- ggplot(data = gapminder,
            mapping = aes(x = year,
                          y = gdpPercap)) 

p + geom_line() # Something is wrong, we didn't tell it how to group

p + geom_line(aes(group = country)) # Now there is a line per country

Faceting

Facet = small multiple (i.e. a separate graph for each value of the variable)

p <- ggplot(data = gapminder,
            mapping = aes(x = year,
                          y = gdpPercap))

p + geom_line(aes(group = country)) +
  facet_wrap(~continent) # make a separate plot for each continent

# Make it look a little nicer
p + geom_line(color = "gray70",
              aes(group = country)) +
  geom_smooth(size = 1.1, method = "loess", se = FALSE) +
  scale_y_log10(labels = scales::dollar) +
  facet_wrap(~continent, ncol = 5) +
  labs(x = "Year",
       y = "GDP per capita",
       title = "GDP per capita on Five Continents")

# New dataset 2016 General Social Survey with more categorical data
glimpse(gss_sm)
## Rows: 2,867
## Columns: 32
## $ year        <dbl> 2016, 2016, 2016, 2016, 2016, 2016, 2016, 2016, 2016, 2...
## $ id          <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, ...
## $ ballot      <labelled> 1, 2, 3, 1, 3, 2, 1, 3, 1, 3, 2, 1, 2, 3, 2, 3, 3,...
## $ age         <dbl> 47, 61, 72, 43, 55, 53, 50, 23, 45, 71, 33, 86, 32, 60,...
## $ childs      <dbl> 3, 0, 2, 4, 2, 2, 2, 3, 3, 4, 5, 4, 3, 5, 7, 2, 6, 5, 0...
## $ sibs        <labelled> 2, 3, 3, 3, 2, 2, 2, 6, 5, 1, 4, 4, 3, 6, 0, 1, 3,...
## $ degree      <fct> Bachelor, High School, Bachelor, High School, Graduate,...
## $ race        <fct> White, White, White, White, White, White, White, Other,...
## $ sex         <fct> Male, Male, Male, Female, Female, Female, Male, Female,...
## $ region      <fct> New England, New England, New England, New England, New...
## $ income16    <fct> $170000 or over, $50000 to 59999, $75000 to $89999, $17...
## $ relig       <fct> None, None, Catholic, Catholic, None, None, None, Catho...
## $ marital     <fct> Married, Never Married, Married, Married, Married, Marr...
## $ padeg       <fct> Graduate, Lt High School, High School, NA, Bachelor, NA...
## $ madeg       <fct> High School, High School, Lt High School, High School, ...
## $ partyid     <fct> "Independent", "Ind,near Dem", "Not Str Republican", "N...
## $ polviews    <fct> Moderate, Liberal, Conservative, Moderate, Slightly Lib...
## $ happy       <fct> Pretty Happy, Pretty Happy, Very Happy, Pretty Happy, V...
## $ partners    <fct> NA, 1 Partner, 1 Partner, NA, 1 Partner, 1 Partner, NA,...
## $ grass       <fct> NA, Legal, Not Legal, NA, Legal, Legal, NA, Not Legal, ...
## $ zodiac      <fct> Aquarius, Scorpio, Pisces, Cancer, Scorpio, Scorpio, Ca...
## $ pres12      <labelled> 3, 1, 2, 2, 1, 1, NA, NA, NA, 2, NA, NA, 1, 1, 2, ...
## $ wtssall     <dbl> 0.9569935, 0.4784968, 0.9569935, 1.9139870, 1.4354903, ...
## $ income_rc   <fct> Gt $170000, Gt $50000, Gt $75000, Gt $170000, Gt $17000...
## $ agegrp      <fct> Age 45-55, Age 55-65, Age 65+, Age 35-45, Age 45-55, Ag...
## $ ageq        <fct> Age 34-49, Age 49-62, Age 62+, Age 34-49, Age 49-62, Ag...
## $ siblings    <fct> 2, 3, 3, 3, 2, 2, 2, 6+, 5, 1, 4, 4, 3, 6+, 0, 1, 3, 6+...
## $ kids        <fct> 3, 0, 2, 4+, 2, 2, 2, 3, 3, 4+, 4+, 4+, 3, 4+, 4+, 2, 4...
## $ religion    <fct> None, None, Catholic, Catholic, None, None, None, Catho...
## $ bigregion   <fct> Northeast, Northeast, Northeast, Northeast, Northeast, ...
## $ partners_rc <fct> NA, 1, 1, NA, 1, 1, NA, 1, NA, 3, 1, NA, 1, NA, 0, 1, 0...
## $ obama       <dbl> 0, 1, 0, 0, 1, 1, NA, NA, NA, 0, NA, NA, 1, 1, 0, 1, 0,...
# Practice using facet_grid() to facet between multiple variables
p <- ggplot(data = gss_sm,
            mapping = aes(x = age,
                          y = childs))

p + geom_point(alpha = 0.2) +
  geom_smooth() +
  facet_grid(sex ~ race)
## Warning: Removed 18 rows containing non-finite values (stat_smooth).
## Warning: Removed 18 rows containing missing values (geom_point).

Transforming

Each geom_ function has an associated stat_ function that is used to plot the data. Sometimes this involves transforming the data in some way.

p <- ggplot(data = gss_sm,
            mapping = aes(x = bigregion))

p + geom_bar() # makes a bar graph that counts the number of observations per region; count is computed for us

p + geom_bar(mapping = aes(y = ..prop..)) # the prop statistic can show us proportions

# But this is not right, each shows 100%

# So, we need to fix the automatic grouping that is occurring by region
p + geom_bar(mapping = aes(y = ..prop.., group = 1)) # using group = 1 is basically a placeholder that says all the data is in the same group

# Look at a different variable
table(gss_sm$religion)
## 
## Protestant   Catholic     Jewish       None      Other 
##       1371        649         51        619        159
p <- ggplot(data = gss_sm,
            mapping = aes(x = religion, color = religion))

p + geom_bar() # only the outline has a color - we need to use fill

p <- ggplot(data = gss_sm,
            mapping = aes(x = religion, fill = religion))

p + geom_bar()

# Remove the legend
p + geom_bar() +
  guides(fill = FALSE)

# How can we look at two variables together
p <- ggplot(data = gss_sm,
            mapping = aes(x = bigregion,
                          fill = religion))

p + geom_bar() # Stacked bar chart of counts

p + geom_bar(position = "fill") # Stacked bar chart of proportions

p + geom_bar(position = "dodge") # Bar chart of counts side by side

p + geom_bar(position = "dodge",
             mapping = aes(y = ..prop..)) # Bar chart of proportions side by side

# Not quite right - all are 100% 

p + geom_bar(position = "dodge",
             mapping = aes(y = ..prop..,
                           group = religion)) # Bar chart of proportions side by side

# The proportions sum to 1 by religion across the regions

p <- ggplot(data = gss_sm,
            mapping = aes(x = religion))

p + geom_bar(position = "dodge",
             mapping = aes(y = ..prop..,
                           group = bigregion)) +
  facet_wrap(~bigregion, ncol = 2)

# Now the proportions sum to 1 by region across religions

Histograms create bins of numerical data and display the distribution of the data within those bins.

# A new dataset
glimpse(midwest)
## Rows: 437
## Columns: 28
## $ PID                  <int> 561, 562, 563, 564, 565, 566, 567, 568, 569, 5...
## $ county               <chr> "ADAMS", "ALEXANDER", "BOND", "BOONE", "BROWN"...
## $ state                <chr> "IL", "IL", "IL", "IL", "IL", "IL", "IL", "IL"...
## $ area                 <dbl> 0.052, 0.014, 0.022, 0.017, 0.018, 0.050, 0.01...
## $ poptotal             <int> 66090, 10626, 14991, 30806, 5836, 35688, 5322,...
## $ popdensity           <dbl> 1270.9615, 759.0000, 681.4091, 1812.1176, 324....
## $ popwhite             <int> 63917, 7054, 14477, 29344, 5264, 35157, 5298, ...
## $ popblack             <int> 1702, 3496, 429, 127, 547, 50, 1, 111, 16, 165...
## $ popamerindian        <int> 98, 19, 35, 46, 14, 65, 8, 30, 8, 331, 51, 26,...
## $ popasian             <int> 249, 48, 16, 150, 5, 195, 15, 61, 23, 8033, 89...
## $ popother             <int> 124, 9, 34, 1139, 6, 221, 0, 84, 6, 1596, 20, ...
## $ percwhite            <dbl> 96.71206, 66.38434, 96.57128, 95.25417, 90.198...
## $ percblack            <dbl> 2.57527614, 32.90043290, 2.86171703, 0.4122573...
## $ percamerindan        <dbl> 0.14828264, 0.17880670, 0.23347342, 0.14932156...
## $ percasian            <dbl> 0.37675897, 0.45172219, 0.10673071, 0.48691813...
## $ percother            <dbl> 0.18762294, 0.08469791, 0.22680275, 3.69733169...
## $ popadults            <int> 43298, 6724, 9669, 19272, 3979, 23444, 3583, 1...
## $ perchsd              <dbl> 75.10740, 59.72635, 69.33499, 75.47219, 68.861...
## $ percollege           <dbl> 19.63139, 11.24331, 17.03382, 17.27895, 14.476...
## $ percprof             <dbl> 4.355859, 2.870315, 4.488572, 4.197800, 3.3676...
## $ poppovertyknown      <int> 63628, 10529, 14235, 30337, 4815, 35107, 5241,...
## $ percpovertyknown     <dbl> 96.27478, 99.08714, 94.95697, 98.47757, 82.505...
## $ percbelowpoverty     <dbl> 13.151443, 32.244278, 12.068844, 7.209019, 13....
## $ percchildbelowpovert <dbl> 18.011717, 45.826514, 14.036061, 11.179536, 13...
## $ percadultpoverty     <dbl> 11.009776, 27.385647, 10.852090, 5.536013, 11....
## $ percelderlypoverty   <dbl> 12.443812, 25.228976, 12.697410, 6.217047, 19....
## $ inmetro              <int> 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1...
## $ category             <chr> "AAR", "LHR", "AAR", "ALU", "AAR", "AAR", "LAR...
p <- ggplot(data = midwest,
            mapping = aes(x = area))

p + geom_histogram() # count is computed automatically by the default stat function

p + geom_histogram(bins = 10) # set 10 bins

# Look at only two states
oh_wi <- c("OH", "WI")

p <- ggplot(data = subset(midwest, subset = state %in% oh_wi),
            mapping = aes(x = percollege,
                          fill = state))

p + geom_histogram(alpha = 0.4, bins = 20) # Overlapping histograms

# Density estimate of the underlying distribution - density plot
p <- ggplot(data = midwest,
            mapping = aes(x = area))

p + geom_density()

# Density by state
p <- ggplot(data = midwest,
            mapping = aes(x = area,
                          fill = state,
                          color = state))

p + geom_density(alpha = 0.3)

# Compare to geom_line(stat = "density")

p + geom_line(stat = "density")

# Scaled density
p <- ggplot(data = subset(midwest, subset = state %in% oh_wi),
            mapping = aes(x = percollege,
                          fill = state,
                          color = state))

p + geom_density(alpha = 0.3,
                 mapping = aes(y = ..scaled..))

Avoiding transformations - sometimes the data is already aggregated or summarized and we do not need a transformation.

titanic # this data is already summarized
##       fate    sex    n percent
## 1 perished   male 1364    62.0
## 2 perished female  126     5.7
## 3 survived   male  367    16.7
## 4 survived female  344    15.6
p <- ggplot(data = titanic,
            mapping = aes(x = fate,
                          y = percent,
                          fill = sex))

p + geom_bar(position = "dodge",
             stat = "identity") + # plot values as provided, do not summarize/count/etc.
  theme(legend.position = "top") # this puts the legend at the top of the graph

oecd_sum # another dataset that is already summarized
## # A tibble: 57 x 5
## # Groups:   year [57]
##     year other   usa  diff hi_lo
##    <int> <dbl> <dbl> <dbl> <chr>
##  1  1960  68.6  69.9 1.3   Below
##  2  1961  69.2  70.4 1.2   Below
##  3  1962  68.9  70.2 1.30  Below
##  4  1963  69.1  70   0.9   Below
##  5  1964  69.5  70.3 0.800 Below
##  6  1965  69.6  70.3 0.7   Below
##  7  1966  69.9  70.3 0.400 Below
##  8  1967  70.1  70.7 0.6   Below
##  9  1968  70.1  70.4 0.3   Below
## 10  1969  70.1  70.6 0.5   Below
## # ... with 47 more rows
p <- ggplot(data = oecd_sum,
            mapping = aes(x = year, 
                          y = diff,
                          fill = hi_lo))

p + geom_col() + # this is the same as geom_bar with stat = "identity"
  guides(fill = FALSE) + # no legend
  labs(x = NULL, # no x-axis label
       y = "Difference in Years",
       title = "The US Life Expectancy Gap",
       subtitle = "Difference between US and OECD average life expectancies, 1960-2015",
       caption = "Data: OECD. After a chart by Christopher Ingraham, Washington Post, December 27th 2017")
## Warning: Removed 1 rows containing missing values (position_stack).

Where to Go Next

Pick at least two of the questions presented under the Where to Go Next section and answer them.

Graph Tables, Make Labels, Add Notes

Summarizing Data

It is best practice to calculate the summary statistics first and then plot them, rather than using the stat_ functions within geom_ functions. This is because it makes the code easier to understand and read and allows us to double check the data and aggregations more easily.

The pipe operator %>% from dplyr allows us to pass data from one operation or function to another. Usually there is a sequence of steps: group, filter/select, mutate, then summarize.

Within group_by(), grouping levels (left to right) go from outermost to innermost. Functions used to create new variables (such as summarize()) will be applied to the innermost group level first.

# Create a tibble/datat table with the percent of each religion by region
rel_by_region <- gss_sm %>%
  group_by(bigregion, religion) %>%
  summarize(N = n()) %>%
  mutate(freq = N / sum(N),
         pct = round((freq * 100), 0))

# Check the percentages sum to 100 by region
rel_by_region %>% 
  group_by(bigregion) %>%
  summarise(total = sum(pct))
## # A tibble: 4 x 2
##   bigregion total
##   <fct>     <dbl>
## 1 Northeast   100
## 2 Midwest     101
## 3 South       100
## 4 West        101
# Make a plot (note: Healy stops using the argument name)
p <- ggplot(data = rel_by_region,
            mapping = aes(x = bigregion,
                          y = pct,
                          fill = religion))

p + 
  geom_col(position = "dodge2") +
  labs(x = "Region",
       y = "Percent",
       fill = "Reiligion") +
  theme(legend.position = "top")

# Let's rearrange it a little
p <- ggplot(data = rel_by_region,
            mapping = aes(x = religion,
                          y = pct,
                          fill = religion))

p + 
  geom_col(position = "dodge2") +
  labs(x = NULL, # don't put a label on the axis
       y = "Percent",
       fill = "Religion") +
  guides(fill = FALSE) +
  coord_flip() + # switches the x and y axes after the plot is made
  facet_grid(~ bigregion)

Continuous Variables by Group or Category

Will be revisited in Week 9, but we will look at some more dplyr examples here.

# Get information about consent laws by country
by_country <- organdata %>%
  group_by(consent_law, country) %>%
  summarize(donors_mean = mean(donors, na.rm = TRUE),
            donors_sd = sd(donors, na.rm = TRUE),
            gdp_mean = mean(gdp, na.rm = TRUE),
            health_mean = mean(health, na.rm = TRUE),
            roads_mean = mean(roads, na.rm = TRUE),
            cerebvas_mean = mean(cerebvas, na.rm = TRUE))

by_country
## # A tibble: 17 x 8
## # Groups:   consent_law [2]
##    consent_law country donors_mean donors_sd gdp_mean health_mean roads_mean
##    <chr>       <chr>         <dbl>     <dbl>    <dbl>       <dbl>      <dbl>
##  1 Informed    Austra~        10.6     1.14    22179.       1958.      105. 
##  2 Informed    Canada         14.0     0.751   23711.       2272.      109. 
##  3 Informed    Denmark        13.1     1.47    23722.       2054.      102. 
##  4 Informed    Germany        13.0     0.611   22163.       2349.      113. 
##  5 Informed    Ireland        19.8     2.48    20824.       1480.      118. 
##  6 Informed    Nether~        13.7     1.55    23013.       1993.       76.1
##  7 Informed    United~        13.5     0.775   21359.       1561.       67.9
##  8 Informed    United~        20.0     1.33    29212.       3988.      155. 
##  9 Presumed    Austria        23.5     2.42    23876.       1875.      150. 
## 10 Presumed    Belgium        21.9     1.94    22500.       1958.      155. 
## 11 Presumed    Finland        18.4     1.53    21019.       1615.       93.6
## 12 Presumed    France         16.8     1.60    22603.       2160.      156. 
## 13 Presumed    Italy          11.1     4.28    21554.       1757       122. 
## 14 Presumed    Norway         15.4     1.11    26448.       2217.       70.0
## 15 Presumed    Spain          28.1     4.96    16933        1289.      161. 
## 16 Presumed    Sweden         13.1     1.75    22415.       1951.       72.3
## 17 Presumed    Switze~        14.2     1.71    27233        2776.       96.4
## # ... with 1 more variable: cerebvas_mean <dbl>
# Another way to do this in a shorter step
by_country <- organdata %>%
  group_by(consent_law, country) %>%
  summarize_if(is.numeric, 
               list(mean = mean, sd = sd), # note funs is deprecated
               na.rm = TRUE) %>% 
  ungroup()


# Make a simple plot of our summarized data
p <- ggplot(data = by_country,
            mapping = aes(x = donors_mean,
                          y = reorder(country, donors_mean), # this puts the countries in order by donors_mean
                          color = consent_law))

p + 
  geom_point(size = 3) +
  labs(x = "Donor Procurement Rate",
       y = "", # another way of putting no label on an axis
       color = "Consent Law")

Plot Text Directly

Week 6

Write and Draw in the Plot Area

Week 6

Understanding Scales, Guides, and Themes

Week 6

Where to Go Next

Pick at least two of the questions presented under the Where to Go Next section and answer them.

Work with Models

Draw Maps

Refine your Plots

LS0tDQp0aXRsZTogIkRhdGEgVmlzdWFsaXphdGlvbiBOb3RlcyINCmF1dGhvcjogIkplbm4gU2NoaWxsaW5nIg0KZGF0ZTogIjIwMjEtMDItMTciDQpvdXRwdXQ6DQogaHRtbF9kb2N1bWVudDoNCiAgdGhlbWU6ICJmbGF0bHkiICMgVGhlbWUgR2FsbGVyeTogaHR0cHM6Ly93d3cuZGF0YWRyZWFtaW5nLm9yZy9wb3N0L3ItbWFya2Rvd24tdGhlbWUtZ2FsbGVyeS8NCiAgdG9jOiBUUlVFDQogIHRvY19mbG9hdDogVFJVRQ0KICBjb2RlX2Rvd25sb2FkOiBUUlVFDQotLS0NCiAgIA0KIyMgRGF0YSBWaXN1YWxpemF0aW9uIE5vdGVzDQoNClRoZXNlIGFyZSBteSBub3RlcyBmb3IgKipHUkQgNjEwQTogRGF0YSBWaXN1YWxpemF0aW9uIElJKiogaW4gV2ludGVyIDIwMjEgYXQgdGhlIENvbGxlZ2UgZm9yIENyZWF0aXZlIFN0dWRpZXMuIFRoZXNlIG5vdGVzIGFyZSBmb3IgbXkgd29yayBpbiB0aGUgYm9vayAqRGF0YSBWaXN1YWxpemF0aW9uKiBieSBLaWVyYW4gSGVhbHkgKFByaW5jZXRvbiBVbml2ZXJzaXR5IFByZXNzLCAyMDE5KS4gDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KDQojIyBCeSBkZWZhdWx0LCBzaG93IGNvZGUgZm9yIGFsbCBjaHVua3MgaW4gdGhlIGtuaXR0ZWQgZG9jdW1lbnQsDQojIyBhcyB3ZWxsIGFzIHRoZSBvdXRwdXQuIFRvIG92ZXJyaWRlIGZvciBhIHBhcnRpY3VsYXIgY2h1bmsNCiMjIHVzZSBlY2hvID0gRkFMU0UgaW4gaXRzIG9wdGlvbnMuDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIG1lc3NhZ2UgPSBGQUxTRSkgDQoNCiMjIFNldCB0aGUgZGVmYXVsdCBzaXplIG9mIGZpZ3VyZXMNCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcud2lkdGg9OCwgZmlnLmhlaWdodD01KSAgDQoNCiMjIExvYWQgdGhlIGxpYnJhcmllcyB3ZSB3aWxsIGJlIHVzaW5nDQpsaWJyYXJ5KGdhcG1pbmRlcikNCmxpYnJhcnkoaGVyZSkNCmxpYnJhcnkoc29jdml6KQ0KbGlicmFyeSh0aWR5dmVyc2UpDQoNCiMjIExpYnJhcmllczogSW5zdGFsbCBvbmNlIHBlciBtYWNoaW5lLCBsb2FkIG9uY2UgcGVyIFIgc2Vzc2lvbg0KDQojIyBXZWVrIDIgLyBDaGFwdGVyIDIgTm90ZXMgcHVibGlzaGVkIGhlcmU6IGh0dHBzOi8vcnB1YnMuY29tL2plbm5zY2hpbGxpbmcvZGdyNjEwYV93MjFfdzJfbm90ZXMNCg0KYGBgDQoNCg0KIyMgR2V0IFN0YXJ0ZWQNCg0KIyMjIEV2ZXJ5dGhpbmcgaGFzIGEgbmFtZQ0KT2JqZWN0cyBpbiBSIGFyZSBjcmVhdGVkIGFuZCByZWZlcnJlZCB0byBieSB0aGVpciBuYW1lcy4gQ2VydGFpbiBuYW1lcyBhcmUgbm90IGFsbG93ZWQgYmVjYXVzZSB0aGV5IGFyZSByZXNlcnZlZCB3b3JkcyBzdWNoIGFzIGBgVFJVRWBgLCBgYGlmYGAsIGBgbWVhbigpYGAsIGFuZCBgYE5BYGAuIE5hbWVzIGFsc28gY2Fubm90IHN0YXJ0IHdpdGggYSBudW1iZXIgb3IgY29udGFpbiBzcGFjZXMuIFRoZXJlIGFyZSBkaWZmZXJlbnQgbmFtaW5nIGNvbnZlbnRpb25zLiAgDQoNCioqU25ha2UgQ2FzZSoqICANCmBgbXlfZGF0YWBgICANCmBgdGhpc19pc19zbmFrZV9jYXNlYGAgIA0KDQoqKkNhbWVsIENhc2UqKiAgDQpgYG15RGF0YWBgICANCmBgdGhpc0lzQ2FtZWxDYXNlYGANCg0KKipQYXNjYWwgQ2FzZSoqICANCmBgTXlEYXRhYGAgIA0KYGBUaGlzSXNQYXNjYWxDYXNlYGANCg0KUGljayBvbmUgbmFtaW5nIGNvbnZlbnRpb24gYW5kIHN0aWNrIHdpdGggaXQuIEJlIGNvbnNpc3RlbnQ7IGRvbid0IHN3aXRjaCBiZXR3ZWVuIGNvbnZlbnRpb25zLiBJIHJlY29tbWVuZCBzbmFrZSBjYXNlLg0KDQpgYGB7ciBuYW1pbmcsIGVycm9yPVRSVUV9DQoNCiMgVGhpcyBpcyBhIGNvbW1lbnQgKGl0IHN0YXJ0cyB3aXRoICMpDQoNCm15X2RhdGEgPC0gYygxLCAyLCAzLCA0KSAjIEFzc2lnbiB1c2luZyA8LSA7IHVzZSBBTFQgKyAtIG9yIE9QVElPTiArIC0NCg0KTXlfRGF0YSAgDQojIENhbm5vdCBiZSBmb3VuZCBiZWNhdXNlIHdlIGNhbGxlZCBpdCBteV9kYXRhIChsb3dlcmNhc2UpDQoNCiMgTm93IHdlIGNhbiBzZWUgaXQNCm15X2RhdGEgDQoNCmBgYA0KDQojIyMgRXZlcnl0aGluZyBpcyBhbiBvYmplY3Q7IHVzaW5nIGZ1bmN0aW9ucw0KVGhpbmsgb2YgZnVuY3Rpb25zIGxpa2UgYSByZWNpcGUuIFRoZSBhcmd1bWVudHMgb2YgdGhlIGZ1bmN0aW9uIGFyZSB0aGUgaW5ncmVkaWVudHMgYW5kIHdoYXQgaGFwcGVucyB3aXRoaW4gdGhlIGZ1bmN0aW9uIGlzIHRoZSBzZXF1ZW5jZSBvZiBjb29raW5nIHN0ZXBzLiANCmBgYHtyIG9iamVjdHMtZnVuY3Rpb25zfQ0KDQpjKDEsIDIsIDMsIDEsIDMsIDUsIDI1KSAjIGMoKSBpcyB0aGUgY29tYmluZSBmdW5jdGlvbiwgaXQgcHV0cyB0aGluZ3MgdG9nZXRoZXIgaW50byBhIHZlY3Rvci9saXN0DQoNCm15X251bWJlcnMgPC0gYygxLCAyLCAzLCAxLCAzLCA1LCAyNSkNCnlvdXJfbnVtYmVycyA8LSBjKDUsIDMxLCA3MSwgMSwgMywgMjEsIDYpDQoNCm15X251bWJlcnMNCg0KbWVhbih4ID0gbXlfbnVtYmVycykNCm1lYW4obXlfbnVtYmVycykgIyB5b3UgZG9uJ3QgaGF2ZSB0byBzcGVjaWZ5IHRoZSBhcmd1bWVudCBuYW1lcywgYnV0IG9yZGVyIG1hdHRlcnMgaWYgeW91IGRvIG5vdCBzcGVjaWZ5DQoNCm1lYW4oeCA9IHlvdXJfbnVtYmVycykNCg0KbXlfc3VtbWFyeSA8LSBzdW1tYXJ5KG15X251bWJlcnMpDQoNCm15X3N1bW1hcnkNCg0KdGFibGUobXlfbnVtYmVycykNCg0Kc2QobXlfbnVtYmVycykNCg0KbXlfbnVtYmVycyAqIDUNCg0KbXlfbnVtYmVycyArIDENCg0KbXlfbnVtYmVycyArIG15X251bWJlcnMgIyBIb3cgaXMgdGhpcyBkaWZmZXJlbnQgdGhhbiB0aGUgbGFzdCBsaW5lPw0KDQojIElmIHlvdSdyZSBub3Qgc3VyZSB3aGF0IGFuIG9iamVjdCBpcywgYXNrIGZvciBpdHMgY2xhc3Mgb3IgdHlwZQ0KDQpjbGFzcyhteV9udW1iZXJzKQ0KDQpjbGFzcyhteV9zdW1tYXJ5KQ0KDQpjbGFzcyhzdW1tYXJ5KQ0KDQpteV9uZXdfdmVjdG9yIDwtIGMobXlfbnVtYmVycywgIkFwcGxlIikgIyBXaGF0IGhhcHBlbnMgaWYgd2UgY29tYmluZSBhIHdvcmQgd2l0aCBudW1iZXJzPw0KDQpteV9uZXdfdmVjdG9yDQoNCmNsYXNzKG15X25ld192ZWN0b3IpDQoNCiMgTGV0J3MgbG9vayBhdCBhIG5ldyBkYXRhc2V0DQoNCnRpdGFuaWMNCg0KY2xhc3ModGl0YW5pYykgDQoNCiMgVGl0YW5pYyBpcyBhIGRhdGEgZnJhbWUsIHdoaWNoIGlzIGxpa2UgYSB0YWJsZQ0KIyBUaGUgJCBvcGVyYXRvciBjYW4gYmUgdXNlZCB0byBhY2Nlc3MgYSBjb2x1bW4gb2YgYSBkYXRhIGZyYW1lIGJ5IG5hbWUNCg0KdGl0YW5pYyRwZXJjZW50DQoNCiMgVGliYmxlcyBhcmUgc2xpZ2h0bHkgZGlmZmVyZW50IHRoYW4gZGF0YSBmcmFtZXMuIFRoZXkgYXJlIGFsc28gZGF0YSB0YWJsZXMsIGJ1dCB0aGV5IHByb3ZpZGUgbW9yZSBpbmZvcm1hdGlvbi4NCg0KdGl0YW5pY190YiA8LSBhc190aWJibGUodGl0YW5pYykNCg0KdGl0YW5pY190YiAjIEhvdyBpcyBkb2VzIHRoaXMgY29tcGFyZSB0byB0aXRhbmljIGFib3ZlPw0KDQojIFRvIHNlZSBpbnNpZGUgYW4gb2JqZWN0LCBhc2sgZm9yIGl0cyBzdHJ1Y3R1cmUNCg0Kc3RyKG15X251bWJlcnMpDQoNCnN0cihteV9zdW1tYXJ5KQ0KDQpgYGANClByb2dyYW1taW5nIGluIFIgY2FuIGJlIGNoYWxsZW5naW5nIGFuZCBpdCB0YWtlcyB0aW1lIHRvIGdldCB1c2VkIHRvLiBCZSBwYXRpZW50IGFuZCB0YWtlIGEgYnJlYWsgaWYgeW91IGdldCBzdHVjay4gTWFrZSBzdXJlIHBhcmVudGhlc2VzIGFyZSBvcGVuZWQgYW5kIGNsb3NlZC4gQ29tcGxldGUgeW91ciBjb21tYW5kcyAobG9vayBvdXQgZm9yIHRoZSArIGluIHRoZSBjb25zb2xlKS4gVGFrZSB5b3VyIHRpbWUgYW5kIGxvb2tvdXQgZm9yIHR5cG9zLiANCg0KIyMjIEdldCBEYXRhIGludG8gUg0KSW4gdGhpcyBzZWN0aW9uLCB3ZSB3aWxsIGdldCBkYXRhIGZyb20gYSBVUkwgYW5kIG1ha2UgYSBxdWljayBmaWd1cmUuDQoNCmBgYHtyIGdldC1kYXRhfQ0KDQojIERhdGEgc291cmNlDQp1cmwgPC0gImh0dHBzOi8vY2RuLnJhd2dpdC5jb20va2poZWFseS92aXotb3JnYW5kYXRhL21hc3Rlci9vcmdhbmRvbmF0aW9uLmNzdiINCg0KIyBSZWFkIHRoZSBDU1YgZnJvbSB0aGUgVVJMDQpvcmdhbnMgPC0gcmVhZF9jc3YoZmlsZSA9IHVybCkNCg0KIyBUYWtlIGEgcXVpY2sgbG9vayBhdCB0aGUgZGF0YQ0KZ2xpbXBzZShvcmdhbnMpDQoNCiMgVmlldyhvcmdhbnMpICMgUnVuIGluIFJTdHVkaW8NCg0KYGBgDQoNCmBgYHtyIG1ha2UtZmlndXJlfQ0KDQojIEFub3RoZXIgd2F5IHRvIHZpZXcgZGF0YSANCmdhcG1pbmRlcg0KDQojIE1ha2UgYSBwbG90IG9iamVjdA0KcCA8LSBnZ3Bsb3QoZGF0YSA9IGdhcG1pbmRlciwNCiAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IGdkcFBlcmNhcCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsaWZlRXhwKSkNCg0KIyBDcmVhdGUgYSBzY2F0dGVycGxvdA0KcCArIGdlb21fcG9pbnQoKQ0KDQpgYGANCg0KDQojIyBNYWtlIGEgUGxvdA0KDQpgYGdncGxvdDJgYCBpcyBhbiBgYFJgYCBsaWJyYXJ5L3BhY2thZ2UgdGhhdCBhbGxvd3MgdXMgdG8gbWFwIGRhdGEgdG8gdmlzdWFsIGVsZW1lbnRzLiBVc2luZyBpdCB3ZSBjYW4gY29udHJvbCB0aGUgd2F5IHRoZSBkYXRhIGFwcGVhcnMgaW4gdGhlIHBsb3QgYW5kIGhvdyBlYWNoIGVsZW1lbnQgb2YgdGhlIHBsb3Qgd2lsbCBiZSBkaXNwbGF5ZWQuICoqQWVzdGhldGljIE1hcHBpbmdzKiogbWFrZSB0aGUgY29ubmVjdGlvbiBiZXR3ZWVuIHRoZSBkYXRhIGFuZCBob3cgaXQgaXMgZGlzcGxheWVkIG9uIHRoZSBwbG90IChsb2NhdGlvbiwgc2l6ZSwgY29sb3IsIHNoYXBlLCBldGMuKS4gKipHZW9tcyoqIGRlZmluZSB0aGUgdHlwZSBvZiBwbG90IChzY2F0dGVycGxvdCwgbGluZSBwbG90LCBib3ggcGxvdCwgYmFyIGNoYXJ0LCBldGMuKS4gQ29kZSBpcyBhZGRlZCB0b2dldGhlciB0byBtYWtlIHRoZSBwbG90IHVzaW5nIGBgK2BgIHRoZSBwbHVzIHNpZ24uIE1vcmUgcGllY2VzIGNhbiBiZSBhZGRlZCB0byB0aGUgcGxvdCB0aGF0IGRlZmluZSB0aGUgc2NhbGVzLCBsZWdlbmQsIGxhYmVscywgYXhlcywgc3R5bGUgb3IgdGhlbWUgb2YgdGhlIHBsb3QsIGV0Yy4gRWFjaCBwYXJ0IGNhbiBiZSBhZGRlZCB1c2luZyBkaWZmZXJlbnQgZnVuY3Rpb25zIHdpdGggYXJndW1lbnRzIHNwZWNpZnlpbmcgdGhlIGxvb2sgb2YgdGhlIHBsb3Q7IHRoZSBwbG90IGlzIGJ1aWx0IHVwIHBpZWNlIGJ5IHBpZWNlLiANCg0KIyMjIFRpZHkgRGF0YQ0KSW4gdGlkeSBkYXRhOiAgDQoxLiBFYWNoIHZhcmlhYmxlIGZvcm1zIGEgY29sdW1uLiAgDQoyLiBFYWNoIG9ic2VydmF0aW9uIGZvcm1zIGEgcm93LiAgDQozLiBFYWNoIHR5cGUgb2Ygb2JzZXJ2YXRpb25hbCB1bml0IGZvcm1zIGEgdGFibGUuICANCg0KRnJvbSBXaWNraGFtLCBILiAoMjAxNCkuIFRpZHkgRGF0YS4gKkpvdXJuYWwgb2YgU3RhdGlzdGljYWwgU29mdHdhcmUqLCA1OSgxMCkuDQoNCiMjIyBNYXBwaW5nDQpCdWlsZCBhIHBsb3QgbGF5ZXIgYnkgbGF5ZXIsIHN0YXJ0aW5nIHdpdGggdGVsbGluZyBnZ3Bsb3Qgd2hhdCBkYXRhIHRvIHVzZSBhbmQgaG93IHRvIG1hcCBvciBsaW5rIGl0ICB0byBwYXJ0cyBvZiB0aGUgcGxvdCwgbGlrZSB0aGUgeCBhbmQgeSBheGVzLiBUaGVuIGFkZCBvbiB0aGUgdHlwZSBvZiBgYGdlb21gYC4gDQoNCmBgYHtyIGNoLTMtZmlnLTF9DQoNCnAgPC0gZ2dwbG90KGRhdGEgPSBnYXBtaW5kZXIsDQogICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IGdkcFBlcmNhcCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbGlmZUV4cCkpIA0KDQogIHAgKyBnZW9tX3BvaW50KCkNCg0KYGBgDQoNCiMjIyBMYXllciBieSBMYXllcg0KDQpUcnlpbmcgZGlmZmVyZW50IGBgZ2VvbV9gYCBmdW5jdGlvbnMuDQoNCmBgYHtyIGNoLTMtZmlnLTJ9DQoNCnAgPC0gZ2dwbG90KGRhdGEgPSBnYXBtaW5kZXIsDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBnZHBQZXJjYXAsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsaWZlRXhwKSkNCg0KcCArIGdlb21fc21vb3RoKCkNCg0KcCArIGdlb21fcG9pbnQoKSArICMgYWRkIHRoZSBwb2ludHMgYmFjayBpbnRvIHRoZSBwbG90IA0KICBnZW9tX3Ntb290aCgpIA0KDQpwICsgZ2VvbV9wb2ludCgpICsgDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIpICMgdXNlIGEgbGluZWFyIG1vZGVsDQoNCnAgKyBnZW9tX3BvaW50KCkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAiZ2FtIikgKyAjIGdlbmVyYWxpemVkIGFkZGl0aXZlIG1vZGVsDQogIHNjYWxlX3hfbG9nMTAoKSAjIHRyYW5zZm9ybSB4LWF4aXMgdG8gbG9nLTEwIHNjYWxlDQoNCnAgKyBnZW9tX3BvaW50KCkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAiZ2FtIikgKw0KICBzY2FsZV94X2xvZzEwKGxhYmVscyA9IHNjYWxlczo6ZG9sbGFyKSAjIGZvcm1hdCB4LWF4aXMgaW4gZG9sbGFycw0KDQpgYGANCg0KIyMjIE1hcHBpbmcgQWVzdGhldGljcw0KDQpVc2luZyB0aGUgYWVzdGhldGljcyBtYXBwaW5nLCBkaWZmZXJlbnQgcGFydHMgb2YgdGhlIGRhdGEgY2FuIGJlIGVuY29kZWQgaW4gZGlmZmVyZW50IHdheXMuICANCg0KYGBge3IgY2gzLWZpZy0zfQ0KDQoNCnAgPC0gZ2dwbG90KGRhdGEgPSBnYXBtaW5kZXIsDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBnZHBQZXJjYXAsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsaWZlRXhwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJwdXJwbGUiKSkgIyBnZ3Bsb3QgYWRkcyB0aGUgdmFsdWUgInB1cnBsZSIgdG8gYWxsIHJvd3MNCg0KcCArIGdlb21fcG9pbnQoKSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIpICsNCiAgc2NhbGVfeF9sb2cxMCgpDQoNCiMgVG8gYWN0dWFsbHkgdHVybiBhbGwgb2YgdGhlIHBvaW50cyBwdXJwbGUsIHdlIG5lZWQgdG8gc2V0IHRoZSBjb2xvciBwcm9wZXJ0eSBvZiB0aGUgZ2VvbV8gZnVuY3Rpb24NCg0KcCA8LSBnZ3Bsb3QoZGF0YSA9IGdhcG1pbmRlciwNCiAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IGdkcFBlcmNhcCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxpZmVFeHApKQ0KDQpwICsgZ2VvbV9wb2ludChjb2xvciA9ICJwdXJwbGUiKSArICMgc2V0IHBvaW50IGNvbG9yIHRvIHB1cnBsZQ0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiKSArDQogIHNjYWxlX3hfbG9nMTAoKQ0KDQpwICsgZ2VvbV9wb2ludChhbHBoYSA9IDAuMykgKyAjIG1ha2UgcG9pbnRzIG1vcmUgdHJhbnNwYXJlbnQNCiAgZ2VvbV9zbW9vdGgoY29sb3IgPSAib3JhbmdlIiwgIyBtYWtlIGxpbmUgb3JhbmdlDQogICAgICAgICAgICAgIHNlID0gRkFMU0UsICMgcmVtb3ZlIHN0YW5kYXJkIGVycm9yIGJhbmQNCiAgICAgICAgICAgICAgc2l6ZSA9IDgsICMgaW5jcmVhc2UgdGhpY2tuZXNzIG9mIHRoZSBsaW5lDQogICAgICAgICAgICAgIG1ldGhvZCA9ICJsbSIpICsNCiAgc2NhbGVfeF9sb2cxMCgpDQoNCg0KcCArIGdlb21fcG9pbnQoYWxwaGEgPSAwLjMpICsgIyBtYWtlIHBvaW50cyBtb3JlIHRyYW5zcGFyZW50DQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJnYW0iKSArDQogIHNjYWxlX3hfbG9nMTAobGFiZWxzID0gc2NhbGVzOjpkb2xsYXIpICsNCiAgIyBBZGQgdGl0bGUgYW5kIGxhYmVscw0KICBsYWJzKHggPSAiR0RQIHBlciBDYXBpdGEiLCANCiAgICAgICB5ID0gIkxpZmUgRXhwZWN0YW5jeSBpbiBZZWFycyIsDQogICAgICAgdGl0bGUgPSAiRWNvbm9taWMgR3Jvd3RoIGFuZCBMaWZlIEV4cGVjdGFuY3kiLA0KICAgICAgIHN1YnRpdGxlID0gIkRhdGEgcG9pbnRzIGFyZSBjb3VudHJ5LXllYXJzIiwNCiAgICAgICBjYXB0aW9uID0gIlNvdXJjZTogR2FwbWluZGVyIikNCg0KIyBNYXAgZGF0YSBieSBjb250aW5lbnQNCnAgPC0gZ2dwbG90KGRhdGEgPSBnYXBtaW5kZXIsDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBnZHBQZXJjYXAsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsaWZlRXhwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGNvbnRpbmVudCkpDQoNCnAgKyBnZW9tX3BvaW50KCkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiKSArDQogIHNjYWxlX3hfbG9nMTAoKQ0KDQoNCnAgPC0gZ2dwbG90KGRhdGEgPSBnYXBtaW5kZXIsDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBnZHBQZXJjYXAsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsaWZlRXhwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGNvbnRpbmVudCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGNvbnRpbmVudCkpICMgbm93IHRoZSBlcnJvciBiYW5kcyB3aWxsIGFsc28gaGF2ZSB0aGUgY29sb3INCg0KcCArIGdlb21fcG9pbnQoKSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIpICsNCiAgc2NhbGVfeF9sb2cxMCgpDQoNCmBgYA0KDQojIyMgQWVzdGhldGljcyBieSBHZW9tDQoNCmBgYHtyIGNoMy1maWctNH0NCg0KcCA8LSBnZ3Bsb3QoZGF0YSA9IGdhcG1pbmRlciwNCiAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IGdkcFBlcmNhcCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxpZmVFeHApKQ0KDQpwICsgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKGNvbG9yID0gY29udGluZW50KSkgKyAjIHBvaW50cyB3aWxsIGJlIGNvbG9yZWQgYnkgY29udGluZW50DQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIpICsgIyB0aGUgc21vb3RoZWQgbGluZSB3aWxsIGJlIGZvciBhbGwgZGF0YQ0KICBzY2FsZV94X2xvZzEwKCkNCg0KcCArIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyhjb2xvciA9IGxvZyhwb3ApKSkgKyAjIHBvaW50cyB3aWxsIGJlIGNvbG9yZWQgYnkgcG9wdWxhdGlvbg0KICBzY2FsZV94X2xvZzEwKCkNCg0KDQpgYGANCg0KIyMjIFNhdmluZyAgDQpVc2UgYGBoZXJlKClgYCB0byBzYXZlIHBsb3RzIGluIHRoZSBjdXJyZW50IGRpcmVjdG9yeS4gVGhpcyBmdW5jdGlvbiBjYW4gYWxzbyBiZSB1c2VkIHRvIHJlZmVyZW5jZSBmb2xkZXJzIHdpdGhpbiB0aGUgY3VycmVudCBkaXJlY3RvcnkuIEZvciB0aGlzIGNsYXNzLCB1c2UgYGAuc3ZnYGAgdG8gc2F2ZSBpbiB2ZWN0b3IgZm9ybWF0IGFuZCBlbWJlZCBpbiBBZG9iZSBJbGx1c3RyYXRvci4gVGhlIGZ1bmN0aW9uIHRvIHNhdmUgYSBwbG90IGlzIGBgZ2dzYXZlKClgYCB3aGljaCB3aWxsIGF1dG9tYXRpY2FsbHkgc2F2ZSB0aGUgbGFzdCBwbG90IGFuZCBjYW4gYWxzbyBiZSBwcm92aWRlZCBhIGBgZ2dwbG90YGAgb2JqZWN0IHRvIHNhdmUuIA0KDQojIyMgV2hlcmUgdG8gR28gTmV4dCAgDQpQaWNrIGF0IGxlYXN0IHR3byBvZiB0aGUgcXVlc3Rpb25zIHByZXNlbnRlZCB1bmRlciB0aGUgKldoZXJlIHRvIEdvIE5leHQqIHNlY3Rpb24gYW5kIGFuc3dlciB0aGVtLg0KDQojIyBTaG93IHRoZSBSaWdodCBOdW1iZXJzICANCg0KKioiQ29kZSBhbG1vc3QgbmV2ZXIgd29ya3MgcHJvcGVybHkgdGhlIGZpcnN0IHRpbWUgeW91IHdyaXRlIGl0LiIqKiAocC4gNzMpICANCg0KIyMjIEdyb3VwaW5nICANCg0KYGBge3IgZ3JvdXAtcGxvdH0NCg0KcCA8LSBnZ3Bsb3QoZGF0YSA9IGdhcG1pbmRlciwNCiAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBnZHBQZXJjYXApKSANCg0KcCArIGdlb21fbGluZSgpICMgU29tZXRoaW5nIGlzIHdyb25nLCB3ZSBkaWRuJ3QgdGVsbCBpdCBob3cgdG8gZ3JvdXANCg0KcCArIGdlb21fbGluZShhZXMoZ3JvdXAgPSBjb3VudHJ5KSkgIyBOb3cgdGhlcmUgaXMgYSBsaW5lIHBlciBjb3VudHJ5DQoNCmBgYA0KDQoNCiMjIyBGYWNldGluZyAgDQoNCkZhY2V0ID0gc21hbGwgbXVsdGlwbGUgKGkuZS4gYSBzZXBhcmF0ZSBncmFwaCBmb3IgZWFjaCB2YWx1ZSBvZiB0aGUgdmFyaWFibGUpICANCg0KYGBge3IgZmFjZXQtcGxvdHN9DQoNCnAgPC0gZ2dwbG90KGRhdGEgPSBnYXBtaW5kZXIsDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gZ2RwUGVyY2FwKSkNCg0KcCArIGdlb21fbGluZShhZXMoZ3JvdXAgPSBjb3VudHJ5KSkgKw0KICBmYWNldF93cmFwKH5jb250aW5lbnQpICMgbWFrZSBhIHNlcGFyYXRlIHBsb3QgZm9yIGVhY2ggY29udGluZW50DQoNCiMgTWFrZSBpdCBsb29rIGEgbGl0dGxlIG5pY2VyDQpwICsgZ2VvbV9saW5lKGNvbG9yID0gImdyYXk3MCIsDQogICAgICAgICAgICAgIGFlcyhncm91cCA9IGNvdW50cnkpKSArDQogIGdlb21fc21vb3RoKHNpemUgPSAxLjEsIG1ldGhvZCA9ICJsb2VzcyIsIHNlID0gRkFMU0UpICsNCiAgc2NhbGVfeV9sb2cxMChsYWJlbHMgPSBzY2FsZXM6OmRvbGxhcikgKw0KICBmYWNldF93cmFwKH5jb250aW5lbnQsIG5jb2wgPSA1KSArDQogIGxhYnMoeCA9ICJZZWFyIiwNCiAgICAgICB5ID0gIkdEUCBwZXIgY2FwaXRhIiwNCiAgICAgICB0aXRsZSA9ICJHRFAgcGVyIGNhcGl0YSBvbiBGaXZlIENvbnRpbmVudHMiKQ0KDQojIE5ldyBkYXRhc2V0IDIwMTYgR2VuZXJhbCBTb2NpYWwgU3VydmV5IHdpdGggbW9yZSBjYXRlZ29yaWNhbCBkYXRhDQpnbGltcHNlKGdzc19zbSkNCg0KIyBQcmFjdGljZSB1c2luZyBmYWNldF9ncmlkKCkgdG8gZmFjZXQgYmV0d2VlbiBtdWx0aXBsZSB2YXJpYWJsZXMNCnAgPC0gZ2dwbG90KGRhdGEgPSBnc3Nfc20sDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBhZ2UsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBjaGlsZHMpKQ0KDQpwICsgZ2VvbV9wb2ludChhbHBoYSA9IDAuMikgKw0KICBnZW9tX3Ntb290aCgpICsNCiAgZmFjZXRfZ3JpZChzZXggfiByYWNlKQ0KDQpgYGANCg0KDQojIyMgVHJhbnNmb3JtaW5nICANCg0KRWFjaCBgYGdlb21fYGAgZnVuY3Rpb24gaGFzIGFuIGFzc29jaWF0ZWQgYGBzdGF0X2BgIGZ1bmN0aW9uIHRoYXQgaXMgdXNlZCB0byBwbG90IHRoZSBkYXRhLiBTb21ldGltZXMgdGhpcyBpbnZvbHZlcyB0cmFuc2Zvcm1pbmcgdGhlIGRhdGEgaW4gc29tZSB3YXkuIA0KDQpgYGB7ciB0cmFuc2Zvcm0tcGxvdH0NCg0KcCA8LSBnZ3Bsb3QoZGF0YSA9IGdzc19zbSwNCiAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IGJpZ3JlZ2lvbikpDQoNCnAgKyBnZW9tX2JhcigpICMgbWFrZXMgYSBiYXIgZ3JhcGggdGhhdCBjb3VudHMgdGhlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgcGVyIHJlZ2lvbjsgY291bnQgaXMgY29tcHV0ZWQgZm9yIHVzDQoNCnAgKyBnZW9tX2JhcihtYXBwaW5nID0gYWVzKHkgPSAuLnByb3AuLikpICMgdGhlIHByb3Agc3RhdGlzdGljIGNhbiBzaG93IHVzIHByb3BvcnRpb25zDQoNCiMgQnV0IHRoaXMgaXMgbm90IHJpZ2h0LCBlYWNoIHNob3dzIDEwMCUNCg0KIyBTbywgd2UgbmVlZCB0byBmaXggdGhlIGF1dG9tYXRpYyBncm91cGluZyB0aGF0IGlzIG9jY3VycmluZyBieSByZWdpb24NCnAgKyBnZW9tX2JhcihtYXBwaW5nID0gYWVzKHkgPSAuLnByb3AuLiwgZ3JvdXAgPSAxKSkgIyB1c2luZyBncm91cCA9IDEgaXMgYmFzaWNhbGx5IGEgcGxhY2Vob2xkZXIgdGhhdCBzYXlzIGFsbCB0aGUgZGF0YSBpcyBpbiB0aGUgc2FtZSBncm91cA0KDQojIExvb2sgYXQgYSBkaWZmZXJlbnQgdmFyaWFibGUNCnRhYmxlKGdzc19zbSRyZWxpZ2lvbikNCg0KcCA8LSBnZ3Bsb3QoZGF0YSA9IGdzc19zbSwNCiAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHJlbGlnaW9uLCBjb2xvciA9IHJlbGlnaW9uKSkNCg0KcCArIGdlb21fYmFyKCkgIyBvbmx5IHRoZSBvdXRsaW5lIGhhcyBhIGNvbG9yIC0gd2UgbmVlZCB0byB1c2UgZmlsbA0KDQpwIDwtIGdncGxvdChkYXRhID0gZ3NzX3NtLA0KICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gcmVsaWdpb24sIGZpbGwgPSByZWxpZ2lvbikpDQoNCnAgKyBnZW9tX2JhcigpDQoNCiMgUmVtb3ZlIHRoZSBsZWdlbmQNCnAgKyBnZW9tX2JhcigpICsNCiAgZ3VpZGVzKGZpbGwgPSBGQUxTRSkNCg0KYGBgDQpgYGB7ciBmcmVxdWVuY3ktcGxvdHN9DQoNCiMgSG93IGNhbiB3ZSBsb29rIGF0IHR3byB2YXJpYWJsZXMgdG9nZXRoZXINCnAgPC0gZ2dwbG90KGRhdGEgPSBnc3Nfc20sDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBiaWdyZWdpb24sDQogICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSByZWxpZ2lvbikpDQoNCnAgKyBnZW9tX2JhcigpICMgU3RhY2tlZCBiYXIgY2hhcnQgb2YgY291bnRzDQoNCnAgKyBnZW9tX2Jhcihwb3NpdGlvbiA9ICJmaWxsIikgIyBTdGFja2VkIGJhciBjaGFydCBvZiBwcm9wb3J0aW9ucw0KDQpwICsgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiKSAjIEJhciBjaGFydCBvZiBjb3VudHMgc2lkZSBieSBzaWRlDQoNCnAgKyBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIsDQogICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh5ID0gLi5wcm9wLi4pKSAjIEJhciBjaGFydCBvZiBwcm9wb3J0aW9ucyBzaWRlIGJ5IHNpZGUNCg0KIyBOb3QgcXVpdGUgcmlnaHQgLSBhbGwgYXJlIDEwMCUgDQoNCnAgKyBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIsDQogICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh5ID0gLi5wcm9wLi4sDQogICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IHJlbGlnaW9uKSkgIyBCYXIgY2hhcnQgb2YgcHJvcG9ydGlvbnMgc2lkZSBieSBzaWRlDQoNCiMgVGhlIHByb3BvcnRpb25zIHN1bSB0byAxIGJ5IHJlbGlnaW9uIGFjcm9zcyB0aGUgcmVnaW9ucw0KDQpwIDwtIGdncGxvdChkYXRhID0gZ3NzX3NtLA0KICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gcmVsaWdpb24pKQ0KDQpwICsgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiLA0KICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeSA9IC4ucHJvcC4uLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBiaWdyZWdpb24pKSArDQogIGZhY2V0X3dyYXAofmJpZ3JlZ2lvbiwgbmNvbCA9IDIpDQoNCiMgTm93IHRoZSBwcm9wb3J0aW9ucyBzdW0gdG8gMSBieSByZWdpb24gYWNyb3NzIHJlbGlnaW9ucw0KDQoNCmBgYA0KSGlzdG9ncmFtcyBjcmVhdGUgYmlucyBvZiBudW1lcmljYWwgZGF0YSBhbmQgZGlzcGxheSB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBkYXRhIHdpdGhpbiB0aG9zZSBiaW5zLiAgDQoNCmBgYHtyIGhpc3RvZ3JhbS1kZW5zaXR5LXBsb3RzfQ0KDQojIEEgbmV3IGRhdGFzZXQNCmdsaW1wc2UobWlkd2VzdCkNCg0KcCA8LSBnZ3Bsb3QoZGF0YSA9IG1pZHdlc3QsDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBhcmVhKSkNCg0KcCArIGdlb21faGlzdG9ncmFtKCkgIyBjb3VudCBpcyBjb21wdXRlZCBhdXRvbWF0aWNhbGx5IGJ5IHRoZSBkZWZhdWx0IHN0YXQgZnVuY3Rpb24NCg0KcCArIGdlb21faGlzdG9ncmFtKGJpbnMgPSAxMCkgIyBzZXQgMTAgYmlucw0KDQojIExvb2sgYXQgb25seSB0d28gc3RhdGVzDQpvaF93aSA8LSBjKCJPSCIsICJXSSIpDQoNCnAgPC0gZ2dwbG90KGRhdGEgPSBzdWJzZXQobWlkd2VzdCwgc3Vic2V0ID0gc3RhdGUgJWluJSBvaF93aSksDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBwZXJjb2xsZWdlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gc3RhdGUpKQ0KDQpwICsgZ2VvbV9oaXN0b2dyYW0oYWxwaGEgPSAwLjQsIGJpbnMgPSAyMCkgIyBPdmVybGFwcGluZyBoaXN0b2dyYW1zDQoNCiMgRGVuc2l0eSBlc3RpbWF0ZSBvZiB0aGUgdW5kZXJseWluZyBkaXN0cmlidXRpb24gLSBkZW5zaXR5IHBsb3QNCnAgPC0gZ2dwbG90KGRhdGEgPSBtaWR3ZXN0LA0KICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gYXJlYSkpDQoNCnAgKyBnZW9tX2RlbnNpdHkoKQ0KDQojIERlbnNpdHkgYnkgc3RhdGUNCnAgPC0gZ2dwbG90KGRhdGEgPSBtaWR3ZXN0LA0KICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gYXJlYSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IHN0YXRlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IHN0YXRlKSkNCg0KcCArIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuMykNCg0KIyBDb21wYXJlIHRvIGdlb21fbGluZShzdGF0ID0gImRlbnNpdHkiKQ0KDQpwICsgZ2VvbV9saW5lKHN0YXQgPSAiZGVuc2l0eSIpDQoNCiMgU2NhbGVkIGRlbnNpdHkNCnAgPC0gZ2dwbG90KGRhdGEgPSBzdWJzZXQobWlkd2VzdCwgc3Vic2V0ID0gc3RhdGUgJWluJSBvaF93aSksDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBwZXJjb2xsZWdlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gc3RhdGUsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gc3RhdGUpKQ0KDQpwICsgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC4zLA0KICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHkgPSAuLnNjYWxlZC4uKSkNCg0KYGBgDQpBdm9pZGluZyB0cmFuc2Zvcm1hdGlvbnMgLSBzb21ldGltZXMgdGhlIGRhdGEgaXMgYWxyZWFkeSBhZ2dyZWdhdGVkIG9yIHN1bW1hcml6ZWQgYW5kIHdlIGRvIG5vdCBuZWVkIGEgdHJhbnNmb3JtYXRpb24uDQoNCmBgYHtyIG5vLXRyYW5zZm9ybS1wbG90c30NCg0KdGl0YW5pYyAjIHRoaXMgZGF0YSBpcyBhbHJlYWR5IHN1bW1hcml6ZWQNCg0KcCA8LSBnZ3Bsb3QoZGF0YSA9IHRpdGFuaWMsDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBmYXRlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gcGVyY2VudCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IHNleCkpDQoNCnAgKyBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIsDQogICAgICAgICAgICAgc3RhdCA9ICJpZGVudGl0eSIpICsgIyBwbG90IHZhbHVlcyBhcyBwcm92aWRlZCwgZG8gbm90IHN1bW1hcml6ZS9jb3VudC9ldGMuDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSAjIHRoaXMgcHV0cyB0aGUgbGVnZW5kIGF0IHRoZSB0b3Agb2YgdGhlIGdyYXBoDQoNCm9lY2Rfc3VtICMgYW5vdGhlciBkYXRhc2V0IHRoYXQgaXMgYWxyZWFkeSBzdW1tYXJpemVkDQoNCnAgPC0gZ2dwbG90KGRhdGEgPSBvZWNkX3N1bSwNCiAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gZGlmZiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGhpX2xvKSkNCg0KcCArIGdlb21fY29sKCkgKyAjIHRoaXMgaXMgdGhlIHNhbWUgYXMgZ2VvbV9iYXIgd2l0aCBzdGF0ID0gImlkZW50aXR5Ig0KICBndWlkZXMoZmlsbCA9IEZBTFNFKSArICMgbm8gbGVnZW5kDQogIGxhYnMoeCA9IE5VTEwsICMgbm8geC1heGlzIGxhYmVsDQogICAgICAgeSA9ICJEaWZmZXJlbmNlIGluIFllYXJzIiwNCiAgICAgICB0aXRsZSA9ICJUaGUgVVMgTGlmZSBFeHBlY3RhbmN5IEdhcCIsDQogICAgICAgc3VidGl0bGUgPSAiRGlmZmVyZW5jZSBiZXR3ZWVuIFVTIGFuZCBPRUNEIGF2ZXJhZ2UgbGlmZSBleHBlY3RhbmNpZXMsIDE5NjAtMjAxNSIsDQogICAgICAgY2FwdGlvbiA9ICJEYXRhOiBPRUNELiBBZnRlciBhIGNoYXJ0IGJ5IENocmlzdG9waGVyIEluZ3JhaGFtLCBXYXNoaW5ndG9uIFBvc3QsIERlY2VtYmVyIDI3dGggMjAxNyIpDQoNCmBgYA0KDQojIyMgV2hlcmUgdG8gR28gTmV4dCAgDQpQaWNrIGF0IGxlYXN0IHR3byBvZiB0aGUgcXVlc3Rpb25zIHByZXNlbnRlZCB1bmRlciB0aGUgKldoZXJlIHRvIEdvIE5leHQqIHNlY3Rpb24gYW5kIGFuc3dlciB0aGVtLg0KDQoNCiMjIEdyYXBoIFRhYmxlcywgTWFrZSBMYWJlbHMsIEFkZCBOb3Rlcw0KDQojIyMgU3VtbWFyaXppbmcgRGF0YQ0KDQpJdCBpcyBiZXN0IHByYWN0aWNlIHRvIGNhbGN1bGF0ZSB0aGUgc3VtbWFyeSBzdGF0aXN0aWNzIGZpcnN0IGFuZCB0aGVuIHBsb3QgdGhlbSwgcmF0aGVyIHRoYW4gdXNpbmcgdGhlIGBzdGF0X2AgZnVuY3Rpb25zIHdpdGhpbiBgZ2VvbV9gIGZ1bmN0aW9ucy4gVGhpcyBpcyBiZWNhdXNlIGl0IG1ha2VzIHRoZSBjb2RlIGVhc2llciB0byB1bmRlcnN0YW5kIGFuZCByZWFkIGFuZCBhbGxvd3MgdXMgdG8gZG91YmxlIGNoZWNrIHRoZSBkYXRhIGFuZCBhZ2dyZWdhdGlvbnMgbW9yZSBlYXNpbHkuDQoNClRoZSBwaXBlIG9wZXJhdG9yIGAlPiVgIGZyb20gYGRwbHlyYCBhbGxvd3MgdXMgdG8gcGFzcyBkYXRhIGZyb20gb25lIG9wZXJhdGlvbiBvciBmdW5jdGlvbiB0byBhbm90aGVyLiBVc3VhbGx5IHRoZXJlIGlzIGEgc2VxdWVuY2Ugb2Ygc3RlcHM6IGdyb3VwLCBmaWx0ZXIvc2VsZWN0LCBtdXRhdGUsIHRoZW4gc3VtbWFyaXplLiANCg0KV2l0aGluIGBncm91cF9ieSgpYCwgZ3JvdXBpbmcgbGV2ZWxzIChsZWZ0IHRvIHJpZ2h0KSBnbyBmcm9tIG91dGVybW9zdCB0byBpbm5lcm1vc3QuIEZ1bmN0aW9ucyB1c2VkIHRvIGNyZWF0ZSBuZXcgdmFyaWFibGVzIChzdWNoIGFzIGBzdW1tYXJpemUoKWApIHdpbGwgYmUgYXBwbGllZCB0byB0aGUgaW5uZXJtb3N0IGdyb3VwIGxldmVsIGZpcnN0LiANCg0KYGBge3Igc3VtbWFyaXplfQ0KDQojIENyZWF0ZSBhIHRpYmJsZS9kYXRhdCB0YWJsZSB3aXRoIHRoZSBwZXJjZW50IG9mIGVhY2ggcmVsaWdpb24gYnkgcmVnaW9uDQpyZWxfYnlfcmVnaW9uIDwtIGdzc19zbSAlPiUNCiAgZ3JvdXBfYnkoYmlncmVnaW9uLCByZWxpZ2lvbikgJT4lDQogIHN1bW1hcml6ZShOID0gbigpKSAlPiUNCiAgbXV0YXRlKGZyZXEgPSBOIC8gc3VtKE4pLA0KICAgICAgICAgcGN0ID0gcm91bmQoKGZyZXEgKiAxMDApLCAwKSkNCg0KIyBDaGVjayB0aGUgcGVyY2VudGFnZXMgc3VtIHRvIDEwMCBieSByZWdpb24NCnJlbF9ieV9yZWdpb24gJT4lIA0KICBncm91cF9ieShiaWdyZWdpb24pICU+JQ0KICBzdW1tYXJpc2UodG90YWwgPSBzdW0ocGN0KSkNCg0KIyBNYWtlIGEgcGxvdCAobm90ZTogSGVhbHkgc3RvcHMgdXNpbmcgdGhlIGFyZ3VtZW50IG5hbWUpDQpwIDwtIGdncGxvdChkYXRhID0gcmVsX2J5X3JlZ2lvbiwNCiAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IGJpZ3JlZ2lvbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHBjdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IHJlbGlnaW9uKSkNCg0KcCArIA0KICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZTIiKSArDQogIGxhYnMoeCA9ICJSZWdpb24iLA0KICAgICAgIHkgPSAiUGVyY2VudCIsDQogICAgICAgZmlsbCA9ICJSZWlsaWdpb24iKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQ0KDQojIExldCdzIHJlYXJyYW5nZSBpdCBhIGxpdHRsZQ0KcCA8LSBnZ3Bsb3QoZGF0YSA9IHJlbF9ieV9yZWdpb24sDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSByZWxpZ2lvbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHBjdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IHJlbGlnaW9uKSkNCg0KcCArIA0KICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZTIiKSArDQogIGxhYnMoeCA9IE5VTEwsICMgZG9uJ3QgcHV0IGEgbGFiZWwgb24gdGhlIGF4aXMNCiAgICAgICB5ID0gIlBlcmNlbnQiLA0KICAgICAgIGZpbGwgPSAiUmVsaWdpb24iKSArDQogIGd1aWRlcyhmaWxsID0gRkFMU0UpICsNCiAgY29vcmRfZmxpcCgpICsgIyBzd2l0Y2hlcyB0aGUgeCBhbmQgeSBheGVzIGFmdGVyIHRoZSBwbG90IGlzIG1hZGUNCiAgZmFjZXRfZ3JpZCh+IGJpZ3JlZ2lvbikNCg0KYGBgDQoNCiMjIyBDb250aW51b3VzIFZhcmlhYmxlcyBieSBHcm91cCBvciBDYXRlZ29yeQ0KDQpXaWxsIGJlIHJldmlzaXRlZCBpbiBXZWVrIDksIGJ1dCB3ZSB3aWxsIGxvb2sgYXQgc29tZSBtb3JlIGBkcGx5cmAgZXhhbXBsZXMgaGVyZS4NCg0KYGBge3IgYm94LXBsb3RzfQ0KDQojIEdldCBpbmZvcm1hdGlvbiBhYm91dCBjb25zZW50IGxhd3MgYnkgY291bnRyeQ0KYnlfY291bnRyeSA8LSBvcmdhbmRhdGEgJT4lDQogIGdyb3VwX2J5KGNvbnNlbnRfbGF3LCBjb3VudHJ5KSAlPiUNCiAgc3VtbWFyaXplKGRvbm9yc19tZWFuID0gbWVhbihkb25vcnMsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBkb25vcnNfc2QgPSBzZChkb25vcnMsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBnZHBfbWVhbiA9IG1lYW4oZ2RwLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgaGVhbHRoX21lYW4gPSBtZWFuKGhlYWx0aCwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgIHJvYWRzX21lYW4gPSBtZWFuKHJvYWRzLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgY2VyZWJ2YXNfbWVhbiA9IG1lYW4oY2VyZWJ2YXMsIG5hLnJtID0gVFJVRSkpDQoNCmJ5X2NvdW50cnkNCg0KIyBBbm90aGVyIHdheSB0byBkbyB0aGlzIGluIGEgc2hvcnRlciBzdGVwDQpieV9jb3VudHJ5IDwtIG9yZ2FuZGF0YSAlPiUNCiAgZ3JvdXBfYnkoY29uc2VudF9sYXcsIGNvdW50cnkpICU+JQ0KICBzdW1tYXJpemVfaWYoaXMubnVtZXJpYywgDQogICAgICAgICAgICAgICBsaXN0KG1lYW4gPSBtZWFuLCBzZCA9IHNkKSwgIyBub3RlIGZ1bnMgaXMgZGVwcmVjYXRlZA0KICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSAlPiUgDQogIHVuZ3JvdXAoKQ0KDQoNCiMgTWFrZSBhIHNpbXBsZSBwbG90IG9mIG91ciBzdW1tYXJpemVkIGRhdGENCnAgPC0gZ2dwbG90KGRhdGEgPSBieV9jb3VudHJ5LA0KICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gZG9ub3JzX21lYW4sDQogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSByZW9yZGVyKGNvdW50cnksIGRvbm9yc19tZWFuKSwgIyB0aGlzIHB1dHMgdGhlIGNvdW50cmllcyBpbiBvcmRlciBieSBkb25vcnNfbWVhbg0KICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGNvbnNlbnRfbGF3KSkNCg0KcCArIA0KICBnZW9tX3BvaW50KHNpemUgPSAzKSArDQogIGxhYnMoeCA9ICJEb25vciBQcm9jdXJlbWVudCBSYXRlIiwNCiAgICAgICB5ID0gIiIsICMgYW5vdGhlciB3YXkgb2YgcHV0dGluZyBubyBsYWJlbCBvbiBhbiBheGlzDQogICAgICAgY29sb3IgPSAiQ29uc2VudCBMYXciKQ0KDQpgYGANCg0KIyMjIFBsb3QgVGV4dCBEaXJlY3RseQ0KDQpXZWVrIDYNCg0KIyMjIFdyaXRlIGFuZCBEcmF3IGluIHRoZSBQbG90IEFyZWENCg0KV2VlayA2DQoNCiMjIyBVbmRlcnN0YW5kaW5nIFNjYWxlcywgR3VpZGVzLCBhbmQgVGhlbWVzDQoNCldlZWsgNg0KDQoNCiMjIyBXaGVyZSB0byBHbyBOZXh0ICANClBpY2sgYXQgbGVhc3QgdHdvIG9mIHRoZSBxdWVzdGlvbnMgcHJlc2VudGVkIHVuZGVyIHRoZSAqV2hlcmUgdG8gR28gTmV4dCogc2VjdGlvbiBhbmQgYW5zd2VyIHRoZW0uDQoNCiMjIFdvcmsgd2l0aCBNb2RlbHMNCg0KYGBge3J9DQoNCmBgYA0KDQojIyBEcmF3IE1hcHMNCg0KYGBge3J9DQoNCmBgYA0KDQoNCiMjIFJlZmluZSB5b3VyIFBsb3RzDQoNCmBgYHtyfQ0KDQpgYGANCg0KDQo=