1 Data wrangling

1.1 The gapminder dataset

1.1.1 Loading the gapminder and dplyr packages

Before you can work with the gapminder dataset, you’ll need to load two R packages that contain the tools for working with it, then display the gapminder dataset so that you can see what it contains.

Download the tidyverse for beginners Cheat Sheet

# Load the gapminder package
Warning messages:
1: In readChar(file, size, TRUE) : truncating string with embedded nuls
2: In readChar(file, size, TRUE) : truncating string with embedded nuls
3: In readChar(file, size, TRUE) : truncating string with embedded nuls
library(gapminder)
# Load the dplyr package
library(dplyr)
# Load the ggplot2 package
library(ggplot2)
gapminder

How many observations (rows) are in the dataset?

nrow(gapminder)
[1] 1704

1.2 The filter verb

1.2.1 Filtering for one year

The filter verb extracts particular observations based on a condition. In this exercise you’ll filter for observations from a particular year.

gapminder %>%  
  filter(year == 2007)

1.2.2 Filtering for one country and one year

You can also use the filter() verb to set two conditions, which could retrieve a single observation.

Just like in the last exercise, you can do this in two lines of code, starting with gapminder %>% and having the filter() on the second line. Keeping one verb on each line helps keep the code readable. Note that each time, you’ll put the pipe %>% at the end of the first line (like gapminder %>%); putting the pipe at the beginning of the second line will throw an error.

gapminder %>% 
  filter(year == 2007, country== "United States")

1.3 The arrange verb

1.3.1 arrange()

You use arrange() to sort observations in ascending or descending order of a particular variable.

gapminder %>% 
  arrange(desc(gdpPercap))

You’ll often need to use the pipe operator (%>%) to combine multiple dplyr verbs in a row.

gapminder %>% 
  filter(year==2007) %>% 
  arrange(desc(gdpPercap))

1.4 The mutate verb

gapminder %>% 
  mutate(pop = pop/1000000)

Adding a new variable (new column)

gapminder %>% 
  mutate(gdp = gdpPercap * pop)
# Filter, mutate, and arrange the gapminder dataset
gapminder %>%
  filter(year == 2007) %>% 
  mutate(lifeExpMonths = 12 * lifeExp) %>% 
  arrange(desc(lifeExpMonths))

1.4.1 Using mutate to change or create a column

Suppose we want life expectancy to be measured in months instead of years: you’d have to multiply the existing value by 12. You can use the mutate() verb to change this column, or to create a new column that’s calculated this way.

# Use mutate to change lifeExp to be in months
gapminder %>%
  mutate(lifeExp = 12 * lifeExp)

# Use mutate to create a new column called lifeExpMonths
gapminder %>%
  mutate(lifeExpMonths = 12 * lifeExp)

1.4.2 Combining filter, mutate, and arrange

In this exercise, you’ll combine all three of the verbs you’ve learned in this chapter, to find the countries with the highest life expectancy, in months, in the year 2007.

# Filter, mutate, and arrange the gapminder dataset
gapminder %>%
  filter(year == 2007) %>% 
  mutate(lifeExpMonths = 12 * lifeExp) %>% 
  arrange(desc(lifeExpMonths))
NA

2 Data Visualization

2.1 Visualizing with ggplot2

2.1.0.1 Variable Assignment

Throughout the exercises in this chapter, you’ll be visualizing a subset of the gapminder data from the year 1952. First, you’ll have to load the ggplot2 package, and create a gapminder_1952 dataset to visualize.

gapminder_2007 <- gapminder %>% 
  filter(year == 2007)

gapminder_2007

# Create gapminder_1952
gapminder_1952 <- gapminder %>%
  filter(year == 1952)

2.1.1 Comparing population and GDP per capita

To create a scatter plot with GDP per capita on the x-axis and life expectancy on the y-axis (the code for that graph is shown here). When you’re exploring data visually, you’ll often need to try different combinations of variables and aesthetics.

gapminder_1952 <- gapminder %>%
  filter(year == 1952)

# Change to put pop on the x-axis and gdpPercap on the y-axis
ggplot(gapminder_1952, aes(x = pop, y = gdpPercap)) +
  geom_point()

2.1.2 Comparing population and life expectancy

In this exercise, you’ll use ggplot2 to create a scatter plot from scratch, to compare each country’s population with its life expectancy in the year 1952.

gapminder_1952 <- gapminder %>%
  filter(year == 1952)

# Create a scatter plot with pop on the x-axis and lifeExp on the y-axis
ggplot(gapminder_1952, aes(x = pop, y = lifeExp)) +
  geom_point()

2.1.2.1 Other Visualizations

When you’re exploring data visually, you’ll often need to try different combinations of variables and aesthetics.

ggplot(gapminder_2007, aes(x = gdpPercap, y = lifeExp)) +
  geom_point()

2.2 Log Scales

2.2.1 Putting the x-axis on a log scale

ggplot(gapminder_2007, aes(x = gdpPercap, y = lifeExp)) +
  geom_point() +
  scale_x_log10()

You previously created a scatter plot with population on the x-axis and life expectancy on the y-axis. Since population is spread over several orders of magnitude, with some countries having a much higher population than others, it’s a good idea to put the x-axis on a log scale.

# Change this plot to put the x-axis on a log scale
ggplot(gapminder_1952, aes(x = pop, y = lifeExp)) +
  geom_point() +
  scale_x_log10()

2.2.2 Putting the x- and y- axes on a log scale

Suppose you want to create a scatter plot with population on the x-axis and GDP per capita on the y-axis. Both population and GDP per-capita are better represented with log scales, since they vary over many orders of magnitude.

ggplot(gapminder_1952, aes(x = pop, y = gdpPercap)) +
  geom_point() +
  scale_x_log10() +
  scale_y_log10()

2.3 Additional aesthetics

2.3.0.1 Color

In this lesson you learned how to use the color aesthetic, which can be used to show which continent each point in a scatter plot represents.

ggplot(gapminder_2007, aes(x = gdpPercap, y = lifeExp, color = continent)) +
    geom_point() +
    scale_x_log10()

2.3.1 Adding size and color to a plot

In the last exercise, you created a scatter plot communicating information about each country’s population, life expectancy, and continent. Now you’ll use the size of the points to communicate even more.

# Scatter plot comparing pop and lifeExp, with color representing continent
ggplot(gapminder_1952, aes(x = pop, y = lifeExp, color = continent, size = gdpPercap)) +
    geom_point() +
    scale_x_log10()

Now you’ll use the size of the points to communicate even more.

ggplot(gapminder_2007, aes(x = gdpPercap, y = lifeExp, color = continent, size = pop)) +
    geom_point() +
    scale_x_log10()

# Add the size aesthetic to represent a country's gdpPercap
ggplot(gapminder_1952, aes(x = pop, y = lifeExp, color = continent, size = gdpPercap)) +
  geom_point() +
  scale_x_log10()

2.4 Faceting

2.4.1 Creating a subgraph for each continent

Divide a graph into subplots based on one of its variables, such as the continent.

ggplot(gapminder_2007, aes(x = gdpPercap, y = lifeExp)) +
    geom_point() +
    scale_x_log10() +
    facet_wrap(~ continent)

# Scatter plot comparing pop and lifeExp, faceted by continent
ggplot(gapminder_1952, aes(x = pop, y = lifeExp)) +
    geom_point() +
    scale_x_log10() +
    facet_wrap(~ continent)

2.4.2 Faceting by year

You can create a graph showing all the country-level data from 1952 to 2007, to understand how global statistics have changed over time.

# Scatter plot comparing gdpPercap and lifeExp, with color representing continent
# and size representing population, faceted by year
ggplot(gapminder, aes(x = gdpPercap, y = lifeExp, color = continent, size = pop)) +
  geom_point() +
  scale_x_log10() +
  facet_wrap(~ year)

3 Grouping and summarizing

3.1 The summarize verb

3.1.1 Summarizing the median life expectancy

You’ve seen how to find the mean life expectancy and the total population across a set of observations, but mean() and sum() are only two of the functions R provides for summarizing a collection of numbers. Here, you’ll learn to use the median() function in combination with summarize().

gapminder %>% 
  summarize(meanLifeExp = mean(lifeExp))
gapminder %>% 
  filter(year == 2007) %>% 
  summarize(meanLifeExp = mean(lifeExp),
            totalPop = sum(as.numeric(pop)))
gapminder %>% 
  summarize(medianLifeExp = median(lifeExp))

3.1.2 Summarizing the median life expectancy in 1957

Rather than summarizing the entire dataset, you may want to find the median life expectancy for only one particular year. In this case, you’ll find the median in the year 1957.

gapminder %>% 
  filter(year == 1957) %>% 
  summarize(medianLifeExp = median(lifeExp))

3.1.3 Summarizing multiple variables in 1957

The summarize() verb allows you to summarize multiple variables at once. In this case, you’ll use the median() function to find the median life expectancy and the max() function to find the maximum GDP per capita.

# Filter for 1957 then summarize the median life expectancy and the maximum GDP per capita
gapminder %>% 
  filter(year == 1957) %>% 
  summarize(medianLifeExp = median(lifeExp),
  maxGdpPercap = max(gdpPercap))

3.2 The group_by verb

3.2.1 Summarizing by year

In a previous exercise, you found the median life expectancy and the maximum GDP per capita in the year 1957. Now, you’ll perform those two summaries within each year in the dataset, using the group_by verb.

gapminder %>% 
  group_by(year) %>% 
  summarize(meanLifeExp = mean(lifeExp),
            totalPop = sum(as.numeric(pop)))
`summarise()` ungrouping output (override with `.groups` argument)

3.2.2 Summarizing by continent

You can group by any variable in your dataset to create a summary. Rather than comparing across time, you might be interested in comparing among continents. You’ll want to do that within one year of the dataset: let’s use 1957.

gapminder %>% 
  filter(year == 2007) %>% 
  group_by(continent) %>% 
  summarize(meanLifeExp = mean(lifeExp),
            totalPop = sum(as.numeric(pop)))
`summarise()` ungrouping output (override with `.groups` argument)

3.2.3 Summarizing by continent and year

Instead of grouping just by year, or just by continent, you’ll now group by both continent and year to summarize within each.

gapminder %>% 
  group_by(year, continent) %>% 
  summarize(meanLifeExp = mean(lifeExp),
            totalPop = sum(as.numeric(pop)))
`summarise()` regrouping output by 'year' (override with `.groups` argument)

3.3 Visualized summarized data

3.3.1 Visualizing median life expectancy over time

In the last chapter, you summarized the gapminder data to calculate the median life expectancy within each year. This code is provided for you, and is saved (with <-) as the by_year dataset.

Now you can use the ggplot2 package to turn this into a visualization of changing life expectancy over time.

by_year <- gapminder %>% 
  group_by(year) %>% 
  summarize(totalPop = sum(as.numeric(pop)),
  meanLifeExp = mean(lifeExp))
`summarise()` ungrouping output (override with `.groups` argument)
#plotting the data
ggplot(by_year, aes(x = year, y = totalPop)) +
  geom_point() +
  expand_limits(y = 0) #specify y axis to star at zero

3.3.2 Visualizing median GDP per capita per continent over time

In the last exercise you were able to see how the median life expectancy of countries changed over time. Now you’ll examine the median GDP per capita instead, and see how the trend differs among continents.

by_year_continent <- gapminder %>% 
  group_by(year, continent) %>% 
  summarize(totalPop = sum(as.numeric(pop)),
  meanLifeExp = mean(lifeExp))
`summarise()` regrouping output by 'year' (override with `.groups` argument)
ggplot(by_year_continent, aes(x = year, y = totalPop, color = continent)) +
  geom_point() +
  expand_limits(y = 0)

3.3.2.1 Comparing median life expectancy and median GDP per continent in 2007

In these exercises you’ve generally created plots that show change over time. But as another way of exploring your data visually, you can also use ggplot2 to plot summarized data to compare continents within a single year.

# Summarize the median GDP and median life expectancy per continent in 2007
by_continent_2007 <- gapminder %>%
  filter(year == 2007) %>%
  group_by(continent) %>%
  summarize(medianLifeExp = median(lifeExp),
  medianGdpPercap = median(gdpPercap))
`summarise()` ungrouping output (override with `.groups` argument)
# Use a scatter plot to compare the median GDP and median life expectancy
ggplot(by_continent_2007, aes(x = medianGdpPercap, y = medianLifeExp, color = continent)) +
  geom_point() +
  expand_limits(y = 0)

4 Types of visualizations

4.1 Line Plots

4.1.1 Visualizing median GDP per capita over time

A line plot is useful for visualizing trends over time. In this exercise, you’ll examine how the median GDP per capita has changed over time.

geom_line()

ggplot(by_year_continent, aes(x = year, y = totalPop, color = continent)) +
  geom_line() +
  expand_limits(y = 0)

# Summarize the median gdpPercap by year, then save it as by_year
by_year <- gapminder %>% 
  group_by(year) %>% 
  summarize(medianGdpPercap = median(gdpPercap))
`summarise()` ungrouping output (override with `.groups` argument)
# Create a line plot showing the change in medianGdpPercap over time
ggplot(by_year, aes(x = year, y = medianGdpPercap)) +
  geom_line() +
  expand_limits(y = 0)

4.1.2 Visualizing median GDP per capita by continent over time

In the last exercise you used a line plot to visualize the increase in median GDP per capita over time. Now you’ll examine the change within each continent.

# Summarize the median gdpPercap by year & continent, save as by_year_continent
by_year_continent <- gapminder %>% 
  group_by(year, continent) %>% 
  summarize(medianGdpPercap = median(gdpPercap))
`summarise()` regrouping output by 'year' (override with `.groups` argument)
# Create a line plot showing the change in medianGdpPercap by continent over time
ggplot(by_year_continent, aes(x = year, y = medianGdpPercap, color = continent)) +
  geom_line() +
  expand_limits(y = 0)

4.2 Bar plots

4.2.1 Visualizing median GDP per capita by continent

A bar plot is useful for visualizing summary statistics, such as the median GDP in each continent.

# Summarize the median gdpPercap by continent in 1952
by_continent <- gapminder %>%
  filter(year == 1952) %>%
  group_by(continent) %>%
  summarize(medianGdpPercap = median(gdpPercap))
`summarise()` ungrouping output (override with `.groups` argument)
# Create a bar plot showing medianGdp by continent
ggplot(by_continent, aes(x = continent, y = medianGdpPercap)) +
  geom_col()

4.2.2 Visualizing GDP per capita by country in Oceania

Bar plot comparing the GDP per capita between the two countries in the Oceania continent (Australia and New Zealand).

# Filter for observations in the Oceania continent in 1952
oceania_1952 <- gapminder %>%
  filter(year == 1952, continent == "Oceania")

# Create a bar plot of gdpPercap by country
ggplot(oceania_1952, aes(x = country, y = gdpPercap)) +
  geom_col()

4.3 Histograms

4.3.1 Visualizing population

A histogram is useful for examining the distribution of a numeric variable. In this exercise, you’ll create a histogram showing the distribution of country populations (by millions) in the year 1952.

ggplot(gapminder_2007, aes(x = lifeExp)) +
  geom_histogram()

Using Binwidth

ggplot(gapminder_2007, aes(x = lifeExp)) +
  geom_histogram(binwidth = 5)

gapminder_1952 <- gapminder %>%
  filter(year == 1952) %>%
  mutate(pop_by_mil = pop / 1000000)

# Create a histogram of population (pop_by_mil)
ggplot(gapminder_1952, aes(x = pop_by_mil)) +
  geom_histogram(bins = 50)

4.3.2 Visualizing population with x-axis on a log scale

In the last exercise you created a histogram of populations across countries. You might have noticed that there were several countries with a much higher population than others, which causes the distribution to be very skewed, with most of the distribution crammed into a small part of the graph. (Consider that it’s hard to tell the median or the minimum population from that histogram).

To make the histogram more informative, you can try putting the x-axis on a log scale.

gapminder_1952 <- gapminder %>%
  filter(year == 1952)

# Create a histogram of population (pop), with x on a log scale
ggplot(gapminder_1952, aes(x = pop)) +
  geom_histogram(bins = 50) +
  scale_x_log10()

4.4 Box plots

4.4.1 Comparing GDP per capita across continents

A boxplot is useful for comparing a distribution of values across several groups. In this exercise, you’ll examine the distribution of GDP per capita by continent. Since GDP per capita varies across several orders of magnitude, you’ll need to put the y-axis on a log scale.

ggplot(gapminder_2007, aes(x = continent, y = lifeExp)) +
  geom_boxplot()

gapminder_1952 <- gapminder %>%
  filter(year == 1952)

# Create a boxplot comparing gdpPercap among continents
ggplot(gapminder_1952, aes(x = continent, y = gdpPercap)) +
  geom_boxplot() +
  scale_y_log10()

4.5 Adding a title to your graph

There are many other options for customizing a ggplot2 graph, which you can learn about in other DataCamp courses. You can also learn about them from online resources, which is an important skill to develop.

As the final exercise in this course, you’ll practice looking up ggplot2 instructions by completing a task we haven’t shown you how to do.

# Add a title to this graph: "Comparing GDP per capita across continents"
ggplot(gapminder_1952, aes(x = continent, y = gdpPercap)) +
  geom_boxplot() +
  scale_y_log10() +
  ggtitle("Comparing GDP per capita across continents")

LS0tDQp0aXRsZTogIkludHJvZHVjdGlvbiB0byBUaWR5dmVyc2UiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgdG9jX2NvbGxhcHNlZDogZmFsc2UNCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUNCiAgICANCnRvY19kZXB0aDogMw0KLS0tDQojIERhdGEgd3JhbmdsaW5nDQoNCiMjIFRoZSBnYXBtaW5kZXIgZGF0YXNldA0KDQojIyMgTG9hZGluZyB0aGUgZ2FwbWluZGVyIGFuZCBkcGx5ciBwYWNrYWdlcw0KDQpCZWZvcmUgeW91IGNhbiB3b3JrIHdpdGggdGhlIGdhcG1pbmRlciBkYXRhc2V0LCB5b3UnbGwgbmVlZCB0byBsb2FkIHR3byBSIHBhY2thZ2VzIHRoYXQgY29udGFpbiB0aGUgdG9vbHMgZm9yIHdvcmtpbmcgd2l0aCBpdCwgdGhlbiBkaXNwbGF5IHRoZSBnYXBtaW5kZXIgZGF0YXNldCBzbyB0aGF0IHlvdSBjYW4gc2VlIHdoYXQgaXQgY29udGFpbnMuDQoNCkRvd25sb2FkIHRoZSBbdGlkeXZlcnNlIGZvciBiZWdpbm5lcnMgQ2hlYXQgU2hlZXRdKGh0dHBzOi8vZGF0YWNhbXAtY29tbXVuaXR5LXByb2QuczMuYW1hem9uYXdzLmNvbS9lNjNhOGY2Yi0yYWEzLTQwMDYtODllMC1iYWRjMjk0YjE3OWMpDQpgYGB7cn0NCiMgTG9hZCB0aGUgZ2FwbWluZGVyIHBhY2thZ2UNCmxpYnJhcnkoZ2FwbWluZGVyKQ0KIyBMb2FkIHRoZSBkcGx5ciBwYWNrYWdlDQpsaWJyYXJ5KGRwbHlyKQ0KIyBMb2FkIHRoZSBnZ3Bsb3QyIHBhY2thZ2UNCmxpYnJhcnkoZ2dwbG90MikNCmBgYA0KYGBge3J9DQpnYXBtaW5kZXINCmBgYA0KSG93IG1hbnkgb2JzZXJ2YXRpb25zIChyb3dzKSBhcmUgaW4gdGhlIGRhdGFzZXQ/DQpgYGB7cn0NCm5yb3coZ2FwbWluZGVyKQ0KYGBgDQojIyBUaGUgZmlsdGVyIHZlcmINCg0KIyMjIEZpbHRlcmluZyBmb3Igb25lIHllYXINCg0KVGhlIGZpbHRlciB2ZXJiIGV4dHJhY3RzIHBhcnRpY3VsYXIgb2JzZXJ2YXRpb25zIGJhc2VkIG9uIGEgY29uZGl0aW9uLiBJbiB0aGlzIGV4ZXJjaXNlIHlvdSdsbCBmaWx0ZXIgZm9yIG9ic2VydmF0aW9ucyBmcm9tIGEgcGFydGljdWxhciB5ZWFyLg0KDQpgYGB7cn0NCmdhcG1pbmRlciAlPiUgIA0KICBmaWx0ZXIoeWVhciA9PSAyMDA3KQ0KYGBgDQojIyMgRmlsdGVyaW5nIGZvciBvbmUgY291bnRyeSBhbmQgb25lIHllYXINCg0KWW91IGNhbiBhbHNvIHVzZSB0aGUgZmlsdGVyKCkgdmVyYiB0byBzZXQgdHdvIGNvbmRpdGlvbnMsIHdoaWNoIGNvdWxkIHJldHJpZXZlIGEgc2luZ2xlIG9ic2VydmF0aW9uLg0KDQpKdXN0IGxpa2UgaW4gdGhlIGxhc3QgZXhlcmNpc2UsIHlvdSBjYW4gZG8gdGhpcyBpbiB0d28gbGluZXMgb2YgY29kZSwgc3RhcnRpbmcgd2l0aCBnYXBtaW5kZXIgJT4lIGFuZCBoYXZpbmcgdGhlIGZpbHRlcigpIG9uIHRoZSBzZWNvbmQgbGluZS4gS2VlcGluZyBvbmUgdmVyYiBvbiBlYWNoIGxpbmUgaGVscHMga2VlcCB0aGUgY29kZSByZWFkYWJsZS4gTm90ZSB0aGF0IGVhY2ggdGltZSwgeW91J2xsIHB1dCB0aGUgcGlwZSAlPiUgYXQgdGhlIGVuZCBvZiB0aGUgZmlyc3QgbGluZSAobGlrZSBnYXBtaW5kZXIgJT4lKTsgcHV0dGluZyB0aGUgcGlwZSBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBzZWNvbmQgbGluZSB3aWxsIHRocm93IGFuIGVycm9yLg0KYGBge3J9DQpnYXBtaW5kZXIgJT4lIA0KICBmaWx0ZXIoeWVhciA9PSAyMDA3LCBjb3VudHJ5PT0gIlVuaXRlZCBTdGF0ZXMiKQ0KYGBgDQojIyBUaGUgYXJyYW5nZSB2ZXJiDQoNCiMjIyBhcnJhbmdlKCkNCg0KWW91IHVzZSBhcnJhbmdlKCkgdG8gc29ydCBvYnNlcnZhdGlvbnMgaW4gYXNjZW5kaW5nIG9yIGRlc2NlbmRpbmcgb3JkZXIgb2YgYSBwYXJ0aWN1bGFyIHZhcmlhYmxlLg0KYGBge3J9DQpnYXBtaW5kZXIgJT4lIA0KICBhcnJhbmdlKGRlc2MoZ2RwUGVyY2FwKSkNCmBgYA0KWW91J2xsIG9mdGVuIG5lZWQgdG8gdXNlIHRoZSBwaXBlIG9wZXJhdG9yICglPiUpIHRvIGNvbWJpbmUgbXVsdGlwbGUgZHBseXIgdmVyYnMgaW4gYSByb3cuDQpgYGB7cn0NCmdhcG1pbmRlciAlPiUgDQogIGZpbHRlcih5ZWFyPT0yMDA3KSAlPiUgDQogIGFycmFuZ2UoZGVzYyhnZHBQZXJjYXApKQ0KYGBgDQojIyBUaGUgbXV0YXRlIHZlcmINCg0KYGBge3J9DQpnYXBtaW5kZXIgJT4lIA0KICBtdXRhdGUocG9wID0gcG9wLzEwMDAwMDApDQpgYGANCkFkZGluZyBhIG5ldyB2YXJpYWJsZSAobmV3IGNvbHVtbikNCg0KYGBge3J9DQpnYXBtaW5kZXIgJT4lIA0KICBtdXRhdGUoZ2RwID0gZ2RwUGVyY2FwICogcG9wKQ0KYGBgDQoNCmBgYHtyfQ0KIyBGaWx0ZXIsIG11dGF0ZSwgYW5kIGFycmFuZ2UgdGhlIGdhcG1pbmRlciBkYXRhc2V0DQpnYXBtaW5kZXIgJT4lDQogIGZpbHRlcih5ZWFyID09IDIwMDcpICU+JSANCiAgbXV0YXRlKGxpZmVFeHBNb250aHMgPSAxMiAqIGxpZmVFeHApICU+JSANCiAgYXJyYW5nZShkZXNjKGxpZmVFeHBNb250aHMpKQ0KYGBgDQojIyMgVXNpbmcgbXV0YXRlIHRvIGNoYW5nZSBvciBjcmVhdGUgYSBjb2x1bW4NCg0KU3VwcG9zZSB3ZSB3YW50IGxpZmUgZXhwZWN0YW5jeSB0byBiZSBtZWFzdXJlZCBpbiBtb250aHMgaW5zdGVhZCBvZiB5ZWFyczogeW91J2QgaGF2ZSB0byBtdWx0aXBseSB0aGUgZXhpc3RpbmcgdmFsdWUgYnkgMTIuIFlvdSBjYW4gdXNlIHRoZSBtdXRhdGUoKSB2ZXJiIHRvIGNoYW5nZSB0aGlzIGNvbHVtbiwgb3IgdG8gY3JlYXRlIGEgbmV3IGNvbHVtbiB0aGF0J3MgY2FsY3VsYXRlZCB0aGlzIHdheS4NCg0KYGBge3J9DQojIFVzZSBtdXRhdGUgdG8gY2hhbmdlIGxpZmVFeHAgdG8gYmUgaW4gbW9udGhzDQpnYXBtaW5kZXIgJT4lDQogIG11dGF0ZShsaWZlRXhwID0gMTIgKiBsaWZlRXhwKQ0KDQojIFVzZSBtdXRhdGUgdG8gY3JlYXRlIGEgbmV3IGNvbHVtbiBjYWxsZWQgbGlmZUV4cE1vbnRocw0KZ2FwbWluZGVyICU+JQ0KICBtdXRhdGUobGlmZUV4cE1vbnRocyA9IDEyICogbGlmZUV4cCkNCmBgYA0KIyMjIENvbWJpbmluZyBmaWx0ZXIsIG11dGF0ZSwgYW5kIGFycmFuZ2UNCg0KSW4gdGhpcyBleGVyY2lzZSwgeW91J2xsIGNvbWJpbmUgYWxsIHRocmVlIG9mIHRoZSB2ZXJicyB5b3UndmUgbGVhcm5lZCBpbiB0aGlzIGNoYXB0ZXIsIHRvIGZpbmQgdGhlIGNvdW50cmllcyB3aXRoIHRoZSBoaWdoZXN0IGxpZmUgZXhwZWN0YW5jeSwgaW4gbW9udGhzLCBpbiB0aGUgeWVhciAyMDA3Lg0KDQpgYGB7cn0NCiMgRmlsdGVyLCBtdXRhdGUsIGFuZCBhcnJhbmdlIHRoZSBnYXBtaW5kZXIgZGF0YXNldA0KZ2FwbWluZGVyICU+JQ0KICBmaWx0ZXIoeWVhciA9PSAyMDA3KSAlPiUgDQogIG11dGF0ZShsaWZlRXhwTW9udGhzID0gMTIgKiBsaWZlRXhwKSAlPiUgDQogIGFycmFuZ2UoZGVzYyhsaWZlRXhwTW9udGhzKSkNCg0KYGBgDQojIERhdGEgVmlzdWFsaXphdGlvbg0KDQojIyBWaXN1YWxpemluZyB3aXRoIGdncGxvdDINCg0KIyMjIyBWYXJpYWJsZSBBc3NpZ25tZW50DQoNClRocm91Z2hvdXQgdGhlIGV4ZXJjaXNlcyBpbiB0aGlzIGNoYXB0ZXIsIHlvdSdsbCBiZSB2aXN1YWxpemluZyBhIHN1YnNldCBvZiB0aGUgZ2FwbWluZGVyIGRhdGEgZnJvbSB0aGUgeWVhciAxOTUyLiBGaXJzdCwgeW91J2xsIGhhdmUgdG8gbG9hZCB0aGUgZ2dwbG90MiBwYWNrYWdlLCBhbmQgY3JlYXRlIGEgZ2FwbWluZGVyXzE5NTIgZGF0YXNldCB0byB2aXN1YWxpemUuDQpgYGB7cn0NCmdhcG1pbmRlcl8yMDA3IDwtIGdhcG1pbmRlciAlPiUgDQogIGZpbHRlcih5ZWFyID09IDIwMDcpDQoNCmdhcG1pbmRlcl8yMDA3DQoNCiMgQ3JlYXRlIGdhcG1pbmRlcl8xOTUyDQpnYXBtaW5kZXJfMTk1MiA8LSBnYXBtaW5kZXIgJT4lDQogIGZpbHRlcih5ZWFyID09IDE5NTIpDQpgYGANCg0KIyMjIENvbXBhcmluZyBwb3B1bGF0aW9uIGFuZCBHRFAgcGVyIGNhcGl0YQ0KDQpUbyBjcmVhdGUgYSBzY2F0dGVyIHBsb3Qgd2l0aCBHRFAgcGVyIGNhcGl0YSBvbiB0aGUgeC1heGlzIGFuZCBsaWZlIGV4cGVjdGFuY3kgb24gdGhlIHktYXhpcyAodGhlIGNvZGUgZm9yIHRoYXQgZ3JhcGggaXMgc2hvd24gaGVyZSkuIFdoZW4geW91J3JlIGV4cGxvcmluZyBkYXRhIHZpc3VhbGx5LCB5b3UnbGwgb2Z0ZW4gbmVlZCB0byB0cnkgZGlmZmVyZW50IGNvbWJpbmF0aW9ucyBvZiB2YXJpYWJsZXMgYW5kIGFlc3RoZXRpY3MuDQoNCmBgYHtyfQ0KZ2FwbWluZGVyXzE5NTIgPC0gZ2FwbWluZGVyICU+JQ0KICBmaWx0ZXIoeWVhciA9PSAxOTUyKQ0KDQojIENoYW5nZSB0byBwdXQgcG9wIG9uIHRoZSB4LWF4aXMgYW5kIGdkcFBlcmNhcCBvbiB0aGUgeS1heGlzDQpnZ3Bsb3QoZ2FwbWluZGVyXzE5NTIsIGFlcyh4ID0gcG9wLCB5ID0gZ2RwUGVyY2FwKSkgKw0KICBnZW9tX3BvaW50KCkNCmBgYA0KIyMjIENvbXBhcmluZyBwb3B1bGF0aW9uIGFuZCBsaWZlIGV4cGVjdGFuY3kNCg0KSW4gdGhpcyBleGVyY2lzZSwgeW91J2xsIHVzZSBnZ3Bsb3QyIHRvIGNyZWF0ZSBhIHNjYXR0ZXIgcGxvdCBmcm9tIHNjcmF0Y2gsIHRvIGNvbXBhcmUgZWFjaCBjb3VudHJ5J3MgcG9wdWxhdGlvbiB3aXRoIGl0cyBsaWZlIGV4cGVjdGFuY3kgaW4gdGhlIHllYXIgMTk1Mi4NCg0KYGBge3J9DQpnYXBtaW5kZXJfMTk1MiA8LSBnYXBtaW5kZXIgJT4lDQogIGZpbHRlcih5ZWFyID09IDE5NTIpDQoNCiMgQ3JlYXRlIGEgc2NhdHRlciBwbG90IHdpdGggcG9wIG9uIHRoZSB4LWF4aXMgYW5kIGxpZmVFeHAgb24gdGhlIHktYXhpcw0KZ2dwbG90KGdhcG1pbmRlcl8xOTUyLCBhZXMoeCA9IHBvcCwgeSA9IGxpZmVFeHApKSArDQogIGdlb21fcG9pbnQoKQ0KYGBgDQoNCg0KIyMjIyBPdGhlciBWaXN1YWxpemF0aW9ucw0KDQpXaGVuIHlvdSdyZSBleHBsb3JpbmcgZGF0YSB2aXN1YWxseSwgeW91J2xsIG9mdGVuIG5lZWQgdG8gdHJ5IGRpZmZlcmVudCBjb21iaW5hdGlvbnMgb2YgdmFyaWFibGVzIGFuZCBhZXN0aGV0aWNzLg0KDQpgYGB7cn0NCmdncGxvdChnYXBtaW5kZXJfMjAwNywgYWVzKHggPSBnZHBQZXJjYXAsIHkgPSBsaWZlRXhwKSkgKw0KICBnZW9tX3BvaW50KCkNCmBgYA0KDQoNCiMjIExvZyBTY2FsZXMNCg0KDQojIyMgUHV0dGluZyB0aGUgeC1heGlzIG9uIGEgbG9nIHNjYWxlDQoNCmBgYHtyfQ0KZ2dwbG90KGdhcG1pbmRlcl8yMDA3LCBhZXMoeCA9IGdkcFBlcmNhcCwgeSA9IGxpZmVFeHApKSArDQogIGdlb21fcG9pbnQoKSArDQogIHNjYWxlX3hfbG9nMTAoKQ0KYGBgDQpZb3UgcHJldmlvdXNseSBjcmVhdGVkIGEgc2NhdHRlciBwbG90IHdpdGggcG9wdWxhdGlvbiBvbiB0aGUgeC1heGlzIGFuZCBsaWZlIGV4cGVjdGFuY3kgb24gdGhlIHktYXhpcy4gU2luY2UgcG9wdWxhdGlvbiBpcyBzcHJlYWQgb3ZlciBzZXZlcmFsIG9yZGVycyBvZiBtYWduaXR1ZGUsIHdpdGggc29tZSBjb3VudHJpZXMgaGF2aW5nIGEgbXVjaCBoaWdoZXIgcG9wdWxhdGlvbiB0aGFuIG90aGVycywgaXQncyBhIGdvb2QgaWRlYSB0byBwdXQgdGhlIHgtYXhpcyBvbiBhIGxvZyBzY2FsZS4NCmBgYHtyfQ0KIyBDaGFuZ2UgdGhpcyBwbG90IHRvIHB1dCB0aGUgeC1heGlzIG9uIGEgbG9nIHNjYWxlDQpnZ3Bsb3QoZ2FwbWluZGVyXzE5NTIsIGFlcyh4ID0gcG9wLCB5ID0gbGlmZUV4cCkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgc2NhbGVfeF9sb2cxMCgpDQpgYGANCiMjIyBQdXR0aW5nIHRoZSB4LSBhbmQgeS0gYXhlcyBvbiBhIGxvZyBzY2FsZQ0KDQpTdXBwb3NlIHlvdSB3YW50IHRvIGNyZWF0ZSBhIHNjYXR0ZXIgcGxvdCB3aXRoIHBvcHVsYXRpb24gb24gdGhlIHgtYXhpcyBhbmQgR0RQIHBlciBjYXBpdGEgb24gdGhlIHktYXhpcy4gQm90aCBwb3B1bGF0aW9uIGFuZCBHRFAgcGVyLWNhcGl0YSBhcmUgYmV0dGVyIHJlcHJlc2VudGVkIHdpdGggbG9nIHNjYWxlcywgc2luY2UgdGhleSB2YXJ5IG92ZXIgbWFueSBvcmRlcnMgb2YgbWFnbml0dWRlLg0KYGBge3J9DQpnZ3Bsb3QoZ2FwbWluZGVyXzE5NTIsIGFlcyh4ID0gcG9wLCB5ID0gZ2RwUGVyY2FwKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBzY2FsZV94X2xvZzEwKCkgKw0KICBzY2FsZV95X2xvZzEwKCkNCmBgYA0KIyMgQWRkaXRpb25hbCBhZXN0aGV0aWNzDQoNCiMjIyMgQ29sb3INCg0KSW4gdGhpcyBsZXNzb24geW91IGxlYXJuZWQgaG93IHRvIHVzZSB0aGUgY29sb3IgYWVzdGhldGljLCB3aGljaCBjYW4gYmUgdXNlZCB0byBzaG93IHdoaWNoIGNvbnRpbmVudCBlYWNoIHBvaW50IGluIGEgc2NhdHRlciBwbG90IHJlcHJlc2VudHMuDQpgYGB7cn0NCmdncGxvdChnYXBtaW5kZXJfMjAwNywgYWVzKHggPSBnZHBQZXJjYXAsIHkgPSBsaWZlRXhwLCBjb2xvciA9IGNvbnRpbmVudCkpICsNCiAgICBnZW9tX3BvaW50KCkgKw0KICAgIHNjYWxlX3hfbG9nMTAoKQ0KYGBgDQojIyMgQWRkaW5nIHNpemUgYW5kIGNvbG9yIHRvIGEgcGxvdA0KDQpJbiB0aGUgbGFzdCBleGVyY2lzZSwgeW91IGNyZWF0ZWQgYSBzY2F0dGVyIHBsb3QgY29tbXVuaWNhdGluZyBpbmZvcm1hdGlvbiBhYm91dCBlYWNoIGNvdW50cnkncyBwb3B1bGF0aW9uLCBsaWZlIGV4cGVjdGFuY3ksIGFuZCBjb250aW5lbnQuIE5vdyB5b3UnbGwgdXNlIHRoZSBzaXplIG9mIHRoZSBwb2ludHMgdG8gY29tbXVuaWNhdGUgZXZlbiBtb3JlLg0KYGBge3J9DQojIFNjYXR0ZXIgcGxvdCBjb21wYXJpbmcgcG9wIGFuZCBsaWZlRXhwLCB3aXRoIGNvbG9yIHJlcHJlc2VudGluZyBjb250aW5lbnQNCmdncGxvdChnYXBtaW5kZXJfMTk1MiwgYWVzKHggPSBwb3AsIHkgPSBsaWZlRXhwLCBjb2xvciA9IGNvbnRpbmVudCwgc2l6ZSA9IGdkcFBlcmNhcCkpICsNCiAgICBnZW9tX3BvaW50KCkgKw0KICAgIHNjYWxlX3hfbG9nMTAoKQ0KYGBgDQoNCk5vdyB5b3UnbGwgdXNlIHRoZSBzaXplIG9mIHRoZSBwb2ludHMgdG8gY29tbXVuaWNhdGUgZXZlbiBtb3JlLg0KYGBge3J9DQpnZ3Bsb3QoZ2FwbWluZGVyXzIwMDcsIGFlcyh4ID0gZ2RwUGVyY2FwLCB5ID0gbGlmZUV4cCwgY29sb3IgPSBjb250aW5lbnQsIHNpemUgPSBwb3ApKSArDQogICAgZ2VvbV9wb2ludCgpICsNCiAgICBzY2FsZV94X2xvZzEwKCkNCmBgYA0KYGBge3J9DQojIEFkZCB0aGUgc2l6ZSBhZXN0aGV0aWMgdG8gcmVwcmVzZW50IGEgY291bnRyeSdzIGdkcFBlcmNhcA0KZ2dwbG90KGdhcG1pbmRlcl8xOTUyLCBhZXMoeCA9IHBvcCwgeSA9IGxpZmVFeHAsIGNvbG9yID0gY29udGluZW50LCBzaXplID0gZ2RwUGVyY2FwKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBzY2FsZV94X2xvZzEwKCkNCmBgYA0KIyMgRmFjZXRpbmcNCg0KIyMjIENyZWF0aW5nIGEgc3ViZ3JhcGggZm9yIGVhY2ggY29udGluZW50DQoNCg0KRGl2aWRlIGEgZ3JhcGggaW50byBzdWJwbG90cyBiYXNlZCBvbiBvbmUgb2YgaXRzIHZhcmlhYmxlcywgc3VjaCBhcyB0aGUgY29udGluZW50Lg0KYGBge3J9DQpnZ3Bsb3QoZ2FwbWluZGVyXzIwMDcsIGFlcyh4ID0gZ2RwUGVyY2FwLCB5ID0gbGlmZUV4cCkpICsNCiAgICBnZW9tX3BvaW50KCkgKw0KICAgIHNjYWxlX3hfbG9nMTAoKSArDQogICAgZmFjZXRfd3JhcCh+IGNvbnRpbmVudCkNCmBgYA0KYGBge3J9DQojIFNjYXR0ZXIgcGxvdCBjb21wYXJpbmcgcG9wIGFuZCBsaWZlRXhwLCBmYWNldGVkIGJ5IGNvbnRpbmVudA0KZ2dwbG90KGdhcG1pbmRlcl8xOTUyLCBhZXMoeCA9IHBvcCwgeSA9IGxpZmVFeHApKSArDQogICAgZ2VvbV9wb2ludCgpICsNCiAgICBzY2FsZV94X2xvZzEwKCkgKw0KICAgIGZhY2V0X3dyYXAofiBjb250aW5lbnQpDQpgYGANCiMjIyBGYWNldGluZyBieSB5ZWFyDQoNCllvdSBjYW4gY3JlYXRlIGEgZ3JhcGggc2hvd2luZyBhbGwgdGhlIGNvdW50cnktbGV2ZWwgZGF0YSBmcm9tIDE5NTIgdG8gMjAwNywgdG8gdW5kZXJzdGFuZCBob3cgZ2xvYmFsIHN0YXRpc3RpY3MgaGF2ZSBjaGFuZ2VkIG92ZXIgdGltZS4NCmBgYHtyfQ0KIyBTY2F0dGVyIHBsb3QgY29tcGFyaW5nIGdkcFBlcmNhcCBhbmQgbGlmZUV4cCwgd2l0aCBjb2xvciByZXByZXNlbnRpbmcgY29udGluZW50DQojIGFuZCBzaXplIHJlcHJlc2VudGluZyBwb3B1bGF0aW9uLCBmYWNldGVkIGJ5IHllYXINCmdncGxvdChnYXBtaW5kZXIsIGFlcyh4ID0gZ2RwUGVyY2FwLCB5ID0gbGlmZUV4cCwgY29sb3IgPSBjb250aW5lbnQsIHNpemUgPSBwb3ApKSArDQogIGdlb21fcG9pbnQoKSArDQogIHNjYWxlX3hfbG9nMTAoKSArDQogIGZhY2V0X3dyYXAofiB5ZWFyKQ0KYGBgDQoNCiMgR3JvdXBpbmcgYW5kIHN1bW1hcml6aW5nDQoNCiMjIFRoZSBzdW1tYXJpemUgdmVyYg0KDQojIyMgU3VtbWFyaXppbmcgdGhlIG1lZGlhbiBsaWZlIGV4cGVjdGFuY3kNCg0KWW91J3ZlIHNlZW4gaG93IHRvIGZpbmQgdGhlIG1lYW4gbGlmZSBleHBlY3RhbmN5IGFuZCB0aGUgdG90YWwgcG9wdWxhdGlvbiBhY3Jvc3MgYSBzZXQgb2Ygb2JzZXJ2YXRpb25zLCBidXQgbWVhbigpIGFuZCBzdW0oKSBhcmUgb25seSB0d28gb2YgdGhlIGZ1bmN0aW9ucyBSIHByb3ZpZGVzIGZvciBzdW1tYXJpemluZyBhIGNvbGxlY3Rpb24gb2YgbnVtYmVycy4gSGVyZSwgeW91J2xsIGxlYXJuIHRvIHVzZSB0aGUgbWVkaWFuKCkgZnVuY3Rpb24gaW4gY29tYmluYXRpb24gd2l0aCBzdW1tYXJpemUoKS4NCmBgYHtyfQ0KZ2FwbWluZGVyICU+JSANCiAgc3VtbWFyaXplKG1lYW5MaWZlRXhwID0gbWVhbihsaWZlRXhwKSkNCmBgYA0KYGBge3J9DQpnYXBtaW5kZXIgJT4lIA0KICBmaWx0ZXIoeWVhciA9PSAyMDA3KSAlPiUgDQogIHN1bW1hcml6ZShtZWFuTGlmZUV4cCA9IG1lYW4obGlmZUV4cCksDQogICAgICAgICAgICB0b3RhbFBvcCA9IHN1bShhcy5udW1lcmljKHBvcCkpKQ0KYGBgDQpgYGB7cn0NCmdhcG1pbmRlciAlPiUgDQogIHN1bW1hcml6ZShtZWRpYW5MaWZlRXhwID0gbWVkaWFuKGxpZmVFeHApKQ0KYGBgDQojIyMgU3VtbWFyaXppbmcgdGhlIG1lZGlhbiBsaWZlIGV4cGVjdGFuY3kgaW4gMTk1Nw0KDQpSYXRoZXIgdGhhbiBzdW1tYXJpemluZyB0aGUgZW50aXJlIGRhdGFzZXQsIHlvdSBtYXkgd2FudCB0byBmaW5kIHRoZSBtZWRpYW4gbGlmZSBleHBlY3RhbmN5IGZvciBvbmx5IG9uZSBwYXJ0aWN1bGFyIHllYXIuIEluIHRoaXMgY2FzZSwgeW91J2xsIGZpbmQgdGhlIG1lZGlhbiBpbiB0aGUgeWVhciAxOTU3Lg0KYGBge3J9DQpnYXBtaW5kZXIgJT4lIA0KICBmaWx0ZXIoeWVhciA9PSAxOTU3KSAlPiUgDQogIHN1bW1hcml6ZShtZWRpYW5MaWZlRXhwID0gbWVkaWFuKGxpZmVFeHApKQ0KYGBgDQojIyMgU3VtbWFyaXppbmcgbXVsdGlwbGUgdmFyaWFibGVzIGluIDE5NTcNCg0KVGhlIHN1bW1hcml6ZSgpIHZlcmIgYWxsb3dzIHlvdSB0byBzdW1tYXJpemUgbXVsdGlwbGUgdmFyaWFibGVzIGF0IG9uY2UuIEluIHRoaXMgY2FzZSwgeW91J2xsIHVzZSB0aGUgbWVkaWFuKCkgZnVuY3Rpb24gdG8gZmluZCB0aGUgbWVkaWFuIGxpZmUgZXhwZWN0YW5jeSBhbmQgdGhlIG1heCgpIGZ1bmN0aW9uIHRvIGZpbmQgdGhlIG1heGltdW0gR0RQIHBlciBjYXBpdGEuDQpgYGB7cn0NCiMgRmlsdGVyIGZvciAxOTU3IHRoZW4gc3VtbWFyaXplIHRoZSBtZWRpYW4gbGlmZSBleHBlY3RhbmN5IGFuZCB0aGUgbWF4aW11bSBHRFAgcGVyIGNhcGl0YQ0KZ2FwbWluZGVyICU+JSANCiAgZmlsdGVyKHllYXIgPT0gMTk1NykgJT4lIA0KICBzdW1tYXJpemUobWVkaWFuTGlmZUV4cCA9IG1lZGlhbihsaWZlRXhwKSwNCiAgbWF4R2RwUGVyY2FwID0gbWF4KGdkcFBlcmNhcCkpDQpgYGANCiMjIFRoZSBncm91cF9ieSB2ZXJiDQoNCiMjIyBTdW1tYXJpemluZyBieSB5ZWFyDQoNCkluIGEgcHJldmlvdXMgZXhlcmNpc2UsIHlvdSBmb3VuZCB0aGUgbWVkaWFuIGxpZmUgZXhwZWN0YW5jeSBhbmQgdGhlIG1heGltdW0gR0RQIHBlciBjYXBpdGEgaW4gdGhlIHllYXIgMTk1Ny4gTm93LCB5b3UnbGwgcGVyZm9ybSB0aG9zZSB0d28gc3VtbWFyaWVzIHdpdGhpbiBlYWNoIHllYXIgaW4gdGhlIGRhdGFzZXQsIHVzaW5nIHRoZSBncm91cF9ieSB2ZXJiLg0KYGBge3J9DQpnYXBtaW5kZXIgJT4lIA0KICBncm91cF9ieSh5ZWFyKSAlPiUgDQogIHN1bW1hcml6ZShtZWFuTGlmZUV4cCA9IG1lYW4obGlmZUV4cCksDQogICAgICAgICAgICB0b3RhbFBvcCA9IHN1bShhcy5udW1lcmljKHBvcCkpKQ0KYGBgDQojIyMgU3VtbWFyaXppbmcgYnkgY29udGluZW50DQoNCllvdSBjYW4gZ3JvdXAgYnkgYW55IHZhcmlhYmxlIGluIHlvdXIgZGF0YXNldCB0byBjcmVhdGUgYSBzdW1tYXJ5LiBSYXRoZXIgdGhhbiBjb21wYXJpbmcgYWNyb3NzIHRpbWUsIHlvdSBtaWdodCBiZSBpbnRlcmVzdGVkIGluIGNvbXBhcmluZyBhbW9uZyBjb250aW5lbnRzLiBZb3UnbGwgd2FudCB0byBkbyB0aGF0IHdpdGhpbiBvbmUgeWVhciBvZiB0aGUgZGF0YXNldDogbGV0J3MgdXNlIDE5NTcuDQpgYGB7cn0NCmdhcG1pbmRlciAlPiUgDQogIGZpbHRlcih5ZWFyID09IDIwMDcpICU+JSANCiAgZ3JvdXBfYnkoY29udGluZW50KSAlPiUgDQogIHN1bW1hcml6ZShtZWFuTGlmZUV4cCA9IG1lYW4obGlmZUV4cCksDQogICAgICAgICAgICB0b3RhbFBvcCA9IHN1bShhcy5udW1lcmljKHBvcCkpKQ0KYGBgDQojIyMgU3VtbWFyaXppbmcgYnkgY29udGluZW50IGFuZCB5ZWFyDQoNCkluc3RlYWQgb2YgZ3JvdXBpbmcganVzdCBieSB5ZWFyLCBvciBqdXN0IGJ5IGNvbnRpbmVudCwgeW91J2xsIG5vdyBncm91cCBieSBib3RoIGNvbnRpbmVudCBhbmQgeWVhciB0byBzdW1tYXJpemUgd2l0aGluIGVhY2guDQpgYGB7cn0NCmdhcG1pbmRlciAlPiUgDQogIGdyb3VwX2J5KHllYXIsIGNvbnRpbmVudCkgJT4lIA0KICBzdW1tYXJpemUobWVhbkxpZmVFeHAgPSBtZWFuKGxpZmVFeHApLA0KICAgICAgICAgICAgdG90YWxQb3AgPSBzdW0oYXMubnVtZXJpYyhwb3ApKSkNCmBgYA0KIyMgVmlzdWFsaXplZCBzdW1tYXJpemVkIGRhdGENCg0KIyMjIFZpc3VhbGl6aW5nIG1lZGlhbiBsaWZlIGV4cGVjdGFuY3kgb3ZlciB0aW1lDQoNCkluIHRoZSBsYXN0IGNoYXB0ZXIsIHlvdSBzdW1tYXJpemVkIHRoZSBnYXBtaW5kZXIgZGF0YSB0byBjYWxjdWxhdGUgdGhlIG1lZGlhbiBsaWZlIGV4cGVjdGFuY3kgd2l0aGluIGVhY2ggeWVhci4gVGhpcyBjb2RlIGlzIHByb3ZpZGVkIGZvciB5b3UsIGFuZCBpcyBzYXZlZCAod2l0aCA8LSkgYXMgdGhlIGJ5X3llYXIgZGF0YXNldC4NCg0KTm93IHlvdSBjYW4gdXNlIHRoZSBnZ3Bsb3QyIHBhY2thZ2UgdG8gdHVybiB0aGlzIGludG8gYSB2aXN1YWxpemF0aW9uIG9mIGNoYW5naW5nIGxpZmUgZXhwZWN0YW5jeSBvdmVyIHRpbWUuDQpgYGB7cn0NCmJ5X3llYXIgPC0gZ2FwbWluZGVyICU+JSANCiAgZ3JvdXBfYnkoeWVhcikgJT4lIA0KICBzdW1tYXJpemUodG90YWxQb3AgPSBzdW0oYXMubnVtZXJpYyhwb3ApKSwNCiAgbWVhbkxpZmVFeHAgPSBtZWFuKGxpZmVFeHApKQ0KDQojcGxvdHRpbmcgdGhlIGRhdGENCmdncGxvdChieV95ZWFyLCBhZXMoeCA9IHllYXIsIHkgPSB0b3RhbFBvcCkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZXhwYW5kX2xpbWl0cyh5ID0gMCkgI3NwZWNpZnkgeSBheGlzIHRvIHN0YXIgYXQgemVybw0KYGBgDQojIyMgVmlzdWFsaXppbmcgbWVkaWFuIEdEUCBwZXIgY2FwaXRhIHBlciBjb250aW5lbnQgb3ZlciB0aW1lDQoNCkluIHRoZSBsYXN0IGV4ZXJjaXNlIHlvdSB3ZXJlIGFibGUgdG8gc2VlIGhvdyB0aGUgbWVkaWFuIGxpZmUgZXhwZWN0YW5jeSBvZiBjb3VudHJpZXMgY2hhbmdlZCBvdmVyIHRpbWUuIE5vdyB5b3UnbGwgZXhhbWluZSB0aGUgbWVkaWFuIEdEUCBwZXIgY2FwaXRhIGluc3RlYWQsIGFuZCBzZWUgaG93IHRoZSB0cmVuZCBkaWZmZXJzIGFtb25nIGNvbnRpbmVudHMuDQpgYGB7cn0NCmJ5X3llYXJfY29udGluZW50IDwtIGdhcG1pbmRlciAlPiUgDQogIGdyb3VwX2J5KHllYXIsIGNvbnRpbmVudCkgJT4lIA0KICBzdW1tYXJpemUodG90YWxQb3AgPSBzdW0oYXMubnVtZXJpYyhwb3ApKSwNCiAgbWVhbkxpZmVFeHAgPSBtZWFuKGxpZmVFeHApKQ0KDQpnZ3Bsb3QoYnlfeWVhcl9jb250aW5lbnQsIGFlcyh4ID0geWVhciwgeSA9IHRvdGFsUG9wLCBjb2xvciA9IGNvbnRpbmVudCkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZXhwYW5kX2xpbWl0cyh5ID0gMCkNCmBgYA0KIyMjIyBDb21wYXJpbmcgbWVkaWFuIGxpZmUgZXhwZWN0YW5jeSBhbmQgbWVkaWFuIEdEUCBwZXIgY29udGluZW50IGluIDIwMDcNCg0KSW4gdGhlc2UgZXhlcmNpc2VzIHlvdSd2ZSBnZW5lcmFsbHkgY3JlYXRlZCBwbG90cyB0aGF0IHNob3cgY2hhbmdlIG92ZXIgdGltZS4gQnV0IGFzIGFub3RoZXIgd2F5IG9mIGV4cGxvcmluZyB5b3VyIGRhdGEgdmlzdWFsbHksIHlvdSBjYW4gYWxzbyB1c2UgZ2dwbG90MiB0byBwbG90IHN1bW1hcml6ZWQgZGF0YSB0byBjb21wYXJlIGNvbnRpbmVudHMgd2l0aGluIGEgc2luZ2xlIHllYXIuDQpgYGB7cn0NCiMgU3VtbWFyaXplIHRoZSBtZWRpYW4gR0RQIGFuZCBtZWRpYW4gbGlmZSBleHBlY3RhbmN5IHBlciBjb250aW5lbnQgaW4gMjAwNw0KYnlfY29udGluZW50XzIwMDcgPC0gZ2FwbWluZGVyICU+JQ0KICBmaWx0ZXIoeWVhciA9PSAyMDA3KSAlPiUNCiAgZ3JvdXBfYnkoY29udGluZW50KSAlPiUNCiAgc3VtbWFyaXplKG1lZGlhbkxpZmVFeHAgPSBtZWRpYW4obGlmZUV4cCksDQogIG1lZGlhbkdkcFBlcmNhcCA9IG1lZGlhbihnZHBQZXJjYXApKQ0KDQojIFVzZSBhIHNjYXR0ZXIgcGxvdCB0byBjb21wYXJlIHRoZSBtZWRpYW4gR0RQIGFuZCBtZWRpYW4gbGlmZSBleHBlY3RhbmN5DQpnZ3Bsb3QoYnlfY29udGluZW50XzIwMDcsIGFlcyh4ID0gbWVkaWFuR2RwUGVyY2FwLCB5ID0gbWVkaWFuTGlmZUV4cCwgY29sb3IgPSBjb250aW5lbnQpKSArDQogIGdlb21fcG9pbnQoKSArDQogIGV4cGFuZF9saW1pdHMoeSA9IDApDQpgYGANCiMgVHlwZXMgb2YgdmlzdWFsaXphdGlvbnMNCg0KIyMgTGluZSBQbG90cw0KDQojIyMgVmlzdWFsaXppbmcgbWVkaWFuIEdEUCBwZXIgY2FwaXRhIG92ZXIgdGltZQ0KDQpBIGxpbmUgcGxvdCBpcyB1c2VmdWwgZm9yIHZpc3VhbGl6aW5nIHRyZW5kcyBvdmVyIHRpbWUuIEluIHRoaXMgZXhlcmNpc2UsIHlvdSdsbCBleGFtaW5lIGhvdyB0aGUgbWVkaWFuIEdEUCBwZXIgY2FwaXRhIGhhcyBjaGFuZ2VkIG92ZXIgdGltZS4NCg0KZ2VvbV9saW5lKCkNCmBgYHtyfQ0KZ2dwbG90KGJ5X3llYXJfY29udGluZW50LCBhZXMoeCA9IHllYXIsIHkgPSB0b3RhbFBvcCwgY29sb3IgPSBjb250aW5lbnQpKSArDQogIGdlb21fbGluZSgpICsNCiAgZXhwYW5kX2xpbWl0cyh5ID0gMCkNCmBgYA0KYGBge3J9DQojIFN1bW1hcml6ZSB0aGUgbWVkaWFuIGdkcFBlcmNhcCBieSB5ZWFyLCB0aGVuIHNhdmUgaXQgYXMgYnlfeWVhcg0KYnlfeWVhciA8LSBnYXBtaW5kZXIgJT4lIA0KICBncm91cF9ieSh5ZWFyKSAlPiUgDQogIHN1bW1hcml6ZShtZWRpYW5HZHBQZXJjYXAgPSBtZWRpYW4oZ2RwUGVyY2FwKSkNCg0KIyBDcmVhdGUgYSBsaW5lIHBsb3Qgc2hvd2luZyB0aGUgY2hhbmdlIGluIG1lZGlhbkdkcFBlcmNhcCBvdmVyIHRpbWUNCmdncGxvdChieV95ZWFyLCBhZXMoeCA9IHllYXIsIHkgPSBtZWRpYW5HZHBQZXJjYXApKSArDQogIGdlb21fbGluZSgpICsNCiAgZXhwYW5kX2xpbWl0cyh5ID0gMCkNCmBgYA0KIyMjIFZpc3VhbGl6aW5nIG1lZGlhbiBHRFAgcGVyIGNhcGl0YSBieSBjb250aW5lbnQgb3ZlciB0aW1lDQoNCkluIHRoZSBsYXN0IGV4ZXJjaXNlIHlvdSB1c2VkIGEgbGluZSBwbG90IHRvIHZpc3VhbGl6ZSB0aGUgaW5jcmVhc2UgaW4gbWVkaWFuIEdEUCBwZXIgY2FwaXRhIG92ZXIgdGltZS4gTm93IHlvdSdsbCBleGFtaW5lIHRoZSBjaGFuZ2Ugd2l0aGluIGVhY2ggY29udGluZW50Lg0KYGBge3J9DQojIFN1bW1hcml6ZSB0aGUgbWVkaWFuIGdkcFBlcmNhcCBieSB5ZWFyICYgY29udGluZW50LCBzYXZlIGFzIGJ5X3llYXJfY29udGluZW50DQpieV95ZWFyX2NvbnRpbmVudCA8LSBnYXBtaW5kZXIgJT4lIA0KICBncm91cF9ieSh5ZWFyLCBjb250aW5lbnQpICU+JSANCiAgc3VtbWFyaXplKG1lZGlhbkdkcFBlcmNhcCA9IG1lZGlhbihnZHBQZXJjYXApKQ0KDQojIENyZWF0ZSBhIGxpbmUgcGxvdCBzaG93aW5nIHRoZSBjaGFuZ2UgaW4gbWVkaWFuR2RwUGVyY2FwIGJ5IGNvbnRpbmVudCBvdmVyIHRpbWUNCmdncGxvdChieV95ZWFyX2NvbnRpbmVudCwgYWVzKHggPSB5ZWFyLCB5ID0gbWVkaWFuR2RwUGVyY2FwLCBjb2xvciA9IGNvbnRpbmVudCkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBleHBhbmRfbGltaXRzKHkgPSAwKQ0KYGBgDQojIyBCYXIgcGxvdHMNCg0KIyMjIFZpc3VhbGl6aW5nIG1lZGlhbiBHRFAgcGVyIGNhcGl0YSBieSBjb250aW5lbnQNCg0KQSBiYXIgcGxvdCBpcyB1c2VmdWwgZm9yIHZpc3VhbGl6aW5nIHN1bW1hcnkgc3RhdGlzdGljcywgc3VjaCBhcyB0aGUgbWVkaWFuIEdEUCBpbiBlYWNoIGNvbnRpbmVudC4NCmBgYHtyfQ0KIyBTdW1tYXJpemUgdGhlIG1lZGlhbiBnZHBQZXJjYXAgYnkgY29udGluZW50IGluIDE5NTINCmJ5X2NvbnRpbmVudCA8LSBnYXBtaW5kZXIgJT4lDQogIGZpbHRlcih5ZWFyID09IDE5NTIpICU+JQ0KICBncm91cF9ieShjb250aW5lbnQpICU+JQ0KICBzdW1tYXJpemUobWVkaWFuR2RwUGVyY2FwID0gbWVkaWFuKGdkcFBlcmNhcCkpDQoNCiMgQ3JlYXRlIGEgYmFyIHBsb3Qgc2hvd2luZyBtZWRpYW5HZHAgYnkgY29udGluZW50DQpnZ3Bsb3QoYnlfY29udGluZW50LCBhZXMoeCA9IGNvbnRpbmVudCwgeSA9IG1lZGlhbkdkcFBlcmNhcCkpICsNCiAgZ2VvbV9jb2woKQ0KYGBgDQojIyMgVmlzdWFsaXppbmcgR0RQIHBlciBjYXBpdGEgYnkgY291bnRyeSBpbiBPY2VhbmlhDQoNCkJhciBwbG90IGNvbXBhcmluZyB0aGUgR0RQIHBlciBjYXBpdGEgYmV0d2VlbiB0aGUgdHdvIGNvdW50cmllcyBpbiB0aGUgT2NlYW5pYSBjb250aW5lbnQgKEF1c3RyYWxpYSBhbmQgTmV3IFplYWxhbmQpLg0KYGBge3J9DQojIEZpbHRlciBmb3Igb2JzZXJ2YXRpb25zIGluIHRoZSBPY2VhbmlhIGNvbnRpbmVudCBpbiAxOTUyDQpvY2VhbmlhXzE5NTIgPC0gZ2FwbWluZGVyICU+JQ0KICBmaWx0ZXIoeWVhciA9PSAxOTUyLCBjb250aW5lbnQgPT0gIk9jZWFuaWEiKQ0KDQojIENyZWF0ZSBhIGJhciBwbG90IG9mIGdkcFBlcmNhcCBieSBjb3VudHJ5DQpnZ3Bsb3Qob2NlYW5pYV8xOTUyLCBhZXMoeCA9IGNvdW50cnksIHkgPSBnZHBQZXJjYXApKSArDQogIGdlb21fY29sKCkNCmBgYA0KIyMgSGlzdG9ncmFtcw0KDQojIyMgVmlzdWFsaXppbmcgcG9wdWxhdGlvbg0KDQpBIGhpc3RvZ3JhbSBpcyB1c2VmdWwgZm9yIGV4YW1pbmluZyB0aGUgZGlzdHJpYnV0aW9uIG9mIGEgbnVtZXJpYyB2YXJpYWJsZS4gSW4gdGhpcyBleGVyY2lzZSwgeW91J2xsIGNyZWF0ZSBhIGhpc3RvZ3JhbSBzaG93aW5nIHRoZSBkaXN0cmlidXRpb24gb2YgY291bnRyeSBwb3B1bGF0aW9ucyAoYnkgbWlsbGlvbnMpIGluIHRoZSB5ZWFyIDE5NTIuDQpgYGB7cn0NCmdncGxvdChnYXBtaW5kZXJfMjAwNywgYWVzKHggPSBsaWZlRXhwKSkgKw0KICBnZW9tX2hpc3RvZ3JhbSgpDQpgYGANClVzaW5nIEJpbndpZHRoDQpgYGB7cn0NCmdncGxvdChnYXBtaW5kZXJfMjAwNywgYWVzKHggPSBsaWZlRXhwKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDUpDQpgYGANCmBgYHtyfQ0KZ2FwbWluZGVyXzE5NTIgPC0gZ2FwbWluZGVyICU+JQ0KICBmaWx0ZXIoeWVhciA9PSAxOTUyKSAlPiUNCiAgbXV0YXRlKHBvcF9ieV9taWwgPSBwb3AgLyAxMDAwMDAwKQ0KDQojIENyZWF0ZSBhIGhpc3RvZ3JhbSBvZiBwb3B1bGF0aW9uIChwb3BfYnlfbWlsKQ0KZ2dwbG90KGdhcG1pbmRlcl8xOTUyLCBhZXMoeCA9IHBvcF9ieV9taWwpKSArDQogIGdlb21faGlzdG9ncmFtKGJpbnMgPSA1MCkNCmBgYA0KIyMjIFZpc3VhbGl6aW5nIHBvcHVsYXRpb24gd2l0aCB4LWF4aXMgb24gYSBsb2cgc2NhbGUNCg0KSW4gdGhlIGxhc3QgZXhlcmNpc2UgeW91IGNyZWF0ZWQgYSBoaXN0b2dyYW0gb2YgcG9wdWxhdGlvbnMgYWNyb3NzIGNvdW50cmllcy4gWW91IG1pZ2h0IGhhdmUgbm90aWNlZCB0aGF0IHRoZXJlIHdlcmUgc2V2ZXJhbCBjb3VudHJpZXMgd2l0aCBhIG11Y2ggaGlnaGVyIHBvcHVsYXRpb24gdGhhbiBvdGhlcnMsIHdoaWNoIGNhdXNlcyB0aGUgZGlzdHJpYnV0aW9uIHRvIGJlIHZlcnkgc2tld2VkLCB3aXRoIG1vc3Qgb2YgdGhlIGRpc3RyaWJ1dGlvbiBjcmFtbWVkIGludG8gYSBzbWFsbCBwYXJ0IG9mIHRoZSBncmFwaC4gKENvbnNpZGVyIHRoYXQgaXQncyBoYXJkIHRvIHRlbGwgdGhlIG1lZGlhbiBvciB0aGUgbWluaW11bSBwb3B1bGF0aW9uIGZyb20gdGhhdCBoaXN0b2dyYW0pLg0KDQpUbyBtYWtlIHRoZSBoaXN0b2dyYW0gbW9yZSBpbmZvcm1hdGl2ZSwgeW91IGNhbiB0cnkgcHV0dGluZyB0aGUgeC1heGlzIG9uIGEgbG9nIHNjYWxlLg0KYGBge3J9DQpnYXBtaW5kZXJfMTk1MiA8LSBnYXBtaW5kZXIgJT4lDQogIGZpbHRlcih5ZWFyID09IDE5NTIpDQoNCiMgQ3JlYXRlIGEgaGlzdG9ncmFtIG9mIHBvcHVsYXRpb24gKHBvcCksIHdpdGggeCBvbiBhIGxvZyBzY2FsZQ0KZ2dwbG90KGdhcG1pbmRlcl8xOTUyLCBhZXMoeCA9IHBvcCkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDUwKSArDQogIHNjYWxlX3hfbG9nMTAoKQ0KYGBgDQojIyBCb3ggcGxvdHMNCg0KIyMjIENvbXBhcmluZyBHRFAgcGVyIGNhcGl0YSBhY3Jvc3MgY29udGluZW50cw0KDQpBIGJveHBsb3QgaXMgdXNlZnVsIGZvciBjb21wYXJpbmcgYSBkaXN0cmlidXRpb24gb2YgdmFsdWVzIGFjcm9zcyBzZXZlcmFsIGdyb3Vwcy4gSW4gdGhpcyBleGVyY2lzZSwgeW91J2xsIGV4YW1pbmUgdGhlIGRpc3RyaWJ1dGlvbiBvZiBHRFAgcGVyIGNhcGl0YSBieSBjb250aW5lbnQuIFNpbmNlIEdEUCBwZXIgY2FwaXRhIHZhcmllcyBhY3Jvc3Mgc2V2ZXJhbCBvcmRlcnMgb2YgbWFnbml0dWRlLCB5b3UnbGwgbmVlZCB0byBwdXQgdGhlIHktYXhpcyBvbiBhIGxvZyBzY2FsZS4gDQpgYGB7cn0NCmdncGxvdChnYXBtaW5kZXJfMjAwNywgYWVzKHggPSBjb250aW5lbnQsIHkgPSBsaWZlRXhwKSkgKw0KICBnZW9tX2JveHBsb3QoKQ0KYGBgDQpgYGB7cn0NCmdhcG1pbmRlcl8xOTUyIDwtIGdhcG1pbmRlciAlPiUNCiAgZmlsdGVyKHllYXIgPT0gMTk1MikNCg0KIyBDcmVhdGUgYSBib3hwbG90IGNvbXBhcmluZyBnZHBQZXJjYXAgYW1vbmcgY29udGluZW50cw0KZ2dwbG90KGdhcG1pbmRlcl8xOTUyLCBhZXMoeCA9IGNvbnRpbmVudCwgeSA9IGdkcFBlcmNhcCkpICsNCiAgZ2VvbV9ib3hwbG90KCkgKw0KICBzY2FsZV95X2xvZzEwKCkNCmBgYA0KIyMgQWRkaW5nIGEgdGl0bGUgdG8geW91ciBncmFwaA0KDQpUaGVyZSBhcmUgbWFueSBvdGhlciBvcHRpb25zIGZvciBjdXN0b21pemluZyBhIGdncGxvdDIgZ3JhcGgsIHdoaWNoIHlvdSBjYW4gbGVhcm4gYWJvdXQgaW4gb3RoZXIgRGF0YUNhbXAgY291cnNlcy4gWW91IGNhbiBhbHNvIGxlYXJuIGFib3V0IHRoZW0gZnJvbSBvbmxpbmUgcmVzb3VyY2VzLCB3aGljaCBpcyBhbiBpbXBvcnRhbnQgc2tpbGwgdG8gZGV2ZWxvcC4NCg0KQXMgdGhlIGZpbmFsIGV4ZXJjaXNlIGluIHRoaXMgY291cnNlLCB5b3UnbGwgcHJhY3RpY2UgbG9va2luZyB1cCBnZ3Bsb3QyIGluc3RydWN0aW9ucyBieSBjb21wbGV0aW5nIGEgdGFzayB3ZSBoYXZlbid0IHNob3duIHlvdSBob3cgdG8gZG8uDQpgYGB7cn0NCiMgQWRkIGEgdGl0bGUgdG8gdGhpcyBncmFwaDogIkNvbXBhcmluZyBHRFAgcGVyIGNhcGl0YSBhY3Jvc3MgY29udGluZW50cyINCmdncGxvdChnYXBtaW5kZXJfMTk1MiwgYWVzKHggPSBjb250aW5lbnQsIHkgPSBnZHBQZXJjYXApKSArDQogIGdlb21fYm94cGxvdCgpICsNCiAgc2NhbGVfeV9sb2cxMCgpICsNCiAgZ2d0aXRsZSgiQ29tcGFyaW5nIEdEUCBwZXIgY2FwaXRhIGFjcm9zcyBjb250aW5lbnRzIikNCmBgYA0KDQo=