This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

The source of these analyses have come from the book R for Data Science by Hadley Wickham and Garrett Grolemund.

  1. PREREQUISITES

We are going to run a collection of packages called the tidyverse and a collection of other packages. Packages are the fundamentals of reproducible R code. They include reusable functions, the documentation that describes how to use them, and sample data. Let’s install the package tidyverse.

install.packages("tidyverse")
Installing package into <U+393C><U+3E31>C:/Users/pkolo/Documents/R/win-library/3.3<U+393C><U+3E32>
(as <U+393C><U+3E31>lib<U+393C><U+3E32> is unspecified)
also installing the dependency <U+393C><U+3E31>dplyr<U+393C><U+3E32>

trying URL 'https://cran.rstudio.com/bin/windows/contrib/3.3/dplyr_0.5.0.zip'
Content type 'application/zip' length 2557408 bytes (2.4 MB)
downloaded 2.4 MB

trying URL 'https://cran.rstudio.com/bin/windows/contrib/3.3/tidyverse_1.1.1.zip'
Content type 'application/zip' length 41939 bytes (40 KB)
downloaded 40 KB
package ‘dplyr’ successfully unpacked and MD5 sums checked
package ‘tidyverse’ successfully unpacked and MD5 sums checked

The downloaded binary packages are in
    C:\Users\pkolo\AppData\Local\Temp\RtmpMFbiCE\downloaded_packages
library(tidyverse)
Loading tidyverse: ggplot2
Loading tidyverse: tibble
Loading tidyverse: tidyr
Loading tidyverse: readr
Loading tidyverse: purrr
Loading tidyverse: dplyr
Conflicts with tidy packages ------------------------------------------------------------------------------------
filter(): dplyr, stats
lag():    dplyr, stats
tidyverse
Error: object 'tidyverse' not found

The tidyverse package contains several other packages vital to data manipulation, visualization, and analysis. These are the core of tidyverse because they will be used in every analysis. Packages in tidyverse change frequently. It is important to find if some have been updated by running the following code for updated packages.

tidyverse_update()

Let’s show the files that are conflicting with the tidyverse package by running the code below.

tidyverse_conflicts()
Conflicts with tidy packages ------------------------------------------------------------------------------------
filter(): dplyr, stats
lag():    dplyr, stats

We can look at the objects in the package tidyverse using the function library().

library(tidyverse)
# > Loading tidyverse: ggplot2
# > Loading tidyverse: tibble
# > Loading tidyverse: tidyr
# > Loading tidyverse: readr
# > Loading tidyverse: purrr
# > Loading tidyverse: dplyr
# > Conflicts with tidy packages ------------------------------------------------------------------------------------
# > filter(): dplyr, stats
# > lag():    dplyr, stats

Additionally, we need to install other packages that are not parts of the tidyverse packages. As we tackle more data science projects in R, we will need these packages for new ways of thinking about data.

install.packages(c("nycflights13", "gapminder", "Lahman"))
Installing packages into <U+393C><U+3E31>C:/Users/pkolo/Documents/R/win-library/3.3<U+393C><U+3E32>
(as <U+393C><U+3E31>lib<U+393C><U+3E32> is unspecified)
trying URL 'https://cran.rstudio.com/bin/windows/contrib/3.3/nycflights13_0.2.2.zip'
Content type 'application/zip' length 7121335 bytes (6.8 MB)
downloaded 6.8 MB

trying URL 'https://cran.rstudio.com/bin/windows/contrib/3.3/gapminder_0.2.0.zip'
Content type 'application/zip' length 187323 bytes (182 KB)
downloaded 182 KB

trying URL 'https://cran.rstudio.com/bin/windows/contrib/3.3/Lahman_5.0-0.zip'
Content type 'application/zip' length 7769216 bytes (7.4 MB)
downloaded 7.4 MB
package ‘nycflights13’ successfully unpacked and MD5 sums checked
package ‘gapminder’ successfully unpacked and MD5 sums checked
package ‘Lahman’ successfully unpacked and MD5 sums checked

The downloaded binary packages are in
    C:\Users\pkolo\AppData\Local\Temp\RtmpMFbiCE\downloaded_packages

These packages provide data on airline flights, world development, and baseball that we will use to illustrate key data science ideas. The easiest way to include data in a question is to use dput() to generate the R code to recreate it. For example:

dput(mtcars)
mtcars <-
  structure(list(mpg = c(21, 21, 22.8, 21.4, 18.7, 18.1, 14.3, 
24.4, 22.8, 19.2, 17.8, 16.4, 17.3, 15.2, 10.4, 10.4, 14.7, 32.4, 
30.4, 33.9, 21.5, 15.5, 15.2, 13.3, 19.2, 27.3, 26, 30.4, 15.8, 
19.7, 15, 21.4), cyl = c(6, 6, 4, 6, 8, 6, 8, 4, 4, 6, 6, 8, 
8, 8, 8, 8, 8, 4, 4, 4, 4, 8, 8, 8, 8, 4, 4, 4, 8, 6, 8, 4), 
    disp = c(160, 160, 108, 258, 360, 225, 360, 146.7, 140.8, 
    167.6, 167.6, 275.8, 275.8, 275.8, 472, 460, 440, 78.7, 75.7, 
    71.1, 120.1, 318, 304, 350, 400, 79, 120.3, 95.1, 351, 145, 
    301, 121), hp = c(110, 110, 93, 110, 175, 105, 245, 62, 95, 
    123, 123, 180, 180, 180, 205, 215, 230, 66, 52, 65, 97, 150, 
    150, 245, 175, 66, 91, 113, 264, 175, 335, 109), drat = c(3.9, 
    3.9, 3.85, 3.08, 3.15, 2.76, 3.21, 3.69, 3.92, 3.92, 3.92, 
    3.07, 3.07, 3.07, 2.93, 3, 3.23, 4.08, 4.93, 4.22, 3.7, 2.76, 
    3.15, 3.73, 3.08, 4.08, 4.43, 3.77, 4.22, 3.62, 3.54, 4.11
    ), wt = c(2.62, 2.875, 2.32, 3.215, 3.44, 3.46, 3.57, 3.19, 
    3.15, 3.44, 3.44, 4.07, 3.73, 3.78, 5.25, 5.424, 5.345, 2.2, 
    1.615, 1.835, 2.465, 3.52, 3.435, 3.84, 3.845, 1.935, 2.14, 
    1.513, 3.17, 2.77, 3.57, 2.78), qsec = c(16.46, 17.02, 18.61, 
    19.44, 17.02, 20.22, 15.84, 20, 22.9, 18.3, 18.9, 17.4, 17.6, 
    18, 17.98, 17.82, 17.42, 19.47, 18.52, 19.9, 20.01, 16.87, 
    17.3, 15.41, 17.05, 18.9, 16.7, 16.9, 14.5, 15.5, 14.6, 18.6
    ), vs = c(0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 
    0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1), am = c(1, 
    1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 
    0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1), gear = c(4, 4, 4, 3, 
    3, 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 3, 3, 3, 
    3, 3, 4, 5, 5, 5, 5, 5, 4), carb = c(4, 4, 1, 1, 2, 1, 4, 
    2, 2, 4, 4, 3, 3, 3, 4, 4, 4, 1, 2, 1, 1, 2, 2, 4, 2, 1, 
    2, 2, 4, 6, 8, 2)), .Names = c("mpg", "cyl", "disp", "hp", 
"drat", "wt", "qsec", "vs", "am", "gear", "carb"), row.names = c("Mazda RX4", 
"Mazda RX4 Wag", "Datsun 710", "Hornet 4 Drive", "Hornet Sportabout", 
"Valiant", "Duster 360", "Merc 240D", "Merc 230", "Merc 280", 
"Merc 280C", "Merc 450SE", "Merc 450SL", "Merc 450SLC", "Cadillac Fleetwood", 
"Lincoln Continental", "Chrysler Imperial", "Fiat 128", "Honda Civic", 
"Toyota Corolla", "Toyota Corona", "Dodge Challenger", "AMC Javelin", 
"Camaro Z28", "Pontiac Firebird", "Fiat X1-9", "Porsche 914-2", 
"Lotus Europa", "Ford Pantera L", "Ferrari Dino", "Maserati Bora", 
"Volvo 142E"), class = "data.frame")

In the first part of this research, we will focus on the basic tools of data exploration. Data exploration is the art of looking at your data, rapidly generating some hypotheses, quckly testing them, then repeating again and again. These tools are vital to data exploration since they have immediate payoff: (1) VISUALIZATION is a great place to start with R programming. Here, we learn the basic structure of ggplot2, and powerful techniques of turning data into plots. (2) DATA TRANSFORMATION gives you the key verbs that help you select the most important variables, filter out key observations, create new variables, and compute summaries. (3) Finally, in EXPLANATORY DATA ANALYSIS, we combine visualization and transformation with curiosity and skepticism to ask and answer interesting questions about the data.

install.packages("tidyverse")
library(tidyverse)

Let’s use our graph to answer a question: Do cars with big engines use more fuel than cars with small engines? What does relationship between car engines and fuel efficiency look like? Negative? Positive? Nonlinear? Linear?

mpg

We can test our answer with the data frame found in the package ggplot2, also know as ggplot2:mpg. A data frame is a rectangular collection of variables (in columns) and observations ( in rows). mpg contains observations collected by the US Environmental Protection Agency on 38 models of car. This code would have produced a result similar as the one above.

ggplot2::mpg

# A tibble: 234 × 11
#   manufacturer      model displ  year   cyl      trans   drv   cty   hwy    fl   class
#          <chr>      <chr> <dbl> <int> <int>      <chr> <chr> <int> <int> <chr>   <chr>
#>1          audi         a4   1.8  1999     4   auto(l5)     f    18    29     p compact
#>2          audi         a4   1.8  1999     4 manual(m5)     f    21    29     p compact
#>3          audi         a4   2.0  2008     4 manual(m6)     f    20    31     p compact
#>4          audi         a4   2.0  2008     4   auto(av)     f    21    30     p compact
#>5          audi         a4   2.8  1999     6   auto(l5)     f    16    26     p compact
#>6          audi         a4   2.8  1999     6 manual(m5)     f    18    26     p compact
#>7          audi         a4   3.1  2008     6   auto(av)     f    18    27     p compact
#>8          audi a4 quattro   1.8  1999     4 manual(m5)     4    18    26     p compact
#>9          audi a4 quattro   1.8  1999     4   auto(l5)     4    16    25     p compact
#>10         audi a4 quattro   2.0  2008     4 manual(m6)     4    20    28     p compact
# ... with 224 more rows
?mpg

To answer the question stated in the first step, we need to select these two variables: displ (engine displacement in litres) and hwy (highway miles per gallon). To learn about mpg, just type mpg or ?mpg.

We are going to create a ggplot() plot of disp against hwy by running disp in the x-axis and hwy in the y-axis.

ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy))

The plot shows a negative relationship between engine size and fuel efficiency. The bigger the engine size, the more fuel a car consumes. The plot also exhibits the presence of some outliers. Cars with big engine sizes but higher fuel efficiency compared with cars of similar engine sizes. With ggplot() you begin plotting by inserting the first argument, ggplot(data = mpg). That creates an empty graph. The function geom_point() adds a layer of points to your plot, which creates a scatterplot. geom function takes the argument mapping, which is paired with aes(), and the x and y arguments of aes().

ggplot(data = data) +
  <Geom_Function>(mapping = aes(<MAPPINGS>)

Let Apply this knowledge to some exercices.

# Run ggplot(data = mpg); we get an empty plotting field
ggplot(data = mpg)

# How many columns and rows in mpg data ; We have 11 columns (variables) and 234 rows.
?mpg
# To see the description of a variable drv; drv = f: front-wheel drive, r = rear wheel drive, 4 = 4wd
?mpg
# Make a scatterplot of hwy vs cyl (number of cylinders)
ggplot(data = mpg) +
  
  geom_point(mapping = aes( x = cyl, y = hwy))

# What happens if we plot class ( type of car) and drv (types of wheels)
ggplot(data = mpg) +
  
  geom_point(mapping = aes(x = class , y = drv))

The plot attaches the types of car to its wheels. We know that 2seater cars are rear wheel drive, compact cars are 4wd and front wheel drive, midsize cars are front wheel drive and 4wd, minivans are front wheel drive, pickups are 4wd, subcompact cars are 4wd, front wheel drive, and rear wheel drive, finally suvs are 4wd, front wheel drive and rear wheel drive. Useful information for our analysis.


library(tidyverse):-

Let’s hypthesize that the outliers are hybrids. One way to test this hypothesis is to look at the class of cars. We can add a third variable, class, to the two dimensional scatterplot by mapping it to the aesthetic function. We can convey this information by mapping the aesthetics to the variables in our data.

ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy, color = class))

To map an aesthetic to a variable, associate the name of the aesthetic to the name of the variable inside aes().ggplot2 will automatically assign a unique level of the aesthetic to each unique value of the variable, a process known as Scaling.

The scatterplot reveals that the 2seater cars are the ones with big engines and higher fuel mileage than others in the same class.

ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ , y = hwy, size = class))

# Using size for discete variable is not advised.

We could mapped the class variable to the alpha aesthetic, which controls the tranparency of the points, or the shape of the points.

# Left plot
ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy, alpha = class))

# Second Plot
#Right plot
ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy, shape = class))

The shape palette can only deal with a minimum of 6 discrete values because more than 6 becomes difficult to discriminate. Here we have 7 values, which explain the missing shape for SUV. Once you map an aesthetic, ggplot2 takes care of the rest. It selects a reasonable scale to use with the aesthetic, and it constructs a legend that explains the mapping between levels and values. For x and y aesthetics, ggplot2 does not create a legend, but it creates an axis line with tick marks and a label. The axis line acts as a legend; it explains the mapping between locations and values. We can also set the aesthetic properties of the goem manually.

ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy), color = "blue")

  1. The name of a color should be a string character; and (2) the size of a point in mm.
# what is wrong with this code:
ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy , color = "blue"))

# Manufacturer, model, trans ,drv, fl, class are categorical variables, while displ, year, cyl, cty, hwy are continuous variable.
mpg
# SIZE
ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy, size = cyl))
ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy, color = year))

ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy, shape = cyl))

A continuous variable cannot be mapped with shape, while a categorical variable can be mapped with shape. Let’s check the following example:

ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy, shape = drv))

ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy, color = hwy))

Mapping the same variable to multiple aesthetics works. Stroke is used to modify the width of the border.

ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy), fill = "red", color = "red", stroke = 3, show.legend = FALSE)

What happens if we map an aesthetic to something other than a variable, like aes(color = displ > 5).

ggplot(data = mpg) +
  geom_point(mapping = aes(x = cyl, y = hwy, color = displ > 5))

the plot shows values of cars that have displ greater than 5 in a different color.One way to add categorical variables is to split your plot into facets, subplots that each displays one subset of the data.

To facet your plot with a single variable is to use facet_wrap(). The first argument of facet_wrap() should be a formula, which you create with ~ followed by a variable name. Here, “formula” is the name of the data structure in R, not a synonym for “equation”). Important: the variable you pass to facet_wrap() should be discrete.

ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy), color = "blue") +
               facet_wrap( ~ class, nrow = 2)

Here the function facet_wrap() maps a third variable on the classes of cars. facet_wrap wraps a 1d sequence of panels into 2d. This is generally a better use of screen space than facet_grid because most displays are roughly rectangular. Here, we see that big engine cars, like pickups and SUV, have lower highway fuel efficiencies. To facet your plot on the combination of two variables, add the facet_grid() to your plot call. The first argument facet_grid() is also a formula. This time the formula will contain two variable names separated by ~.

ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy), color = "darkblue") +
  facet_grid(drv ~ cyl)

If we prefer not to facet in the rows or columns dimension, we should use . instead of a variable name. For example facet_grid(. ~ cyl).

ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy), color = "red") +
  facet_grid(. ~ cyl)

Cars with small engine sizes and number of cylinders have better highway miles per gallon, while those with big engine sizes and number of cylinders have lower highway miles per gallon, in general. Another example of facet_grid(. ~ variable name). This time we are going to use the variable class.

ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy), color = "magenta") +
  facet_grid(. ~ class)

Again pickups and suvs have lower highway miles per gallon compared to other cars in the mpg data frame. We use color = “magenta” to add some aesthetics to our plot. Now, let’s apply these skills to some exercices.

# Apply facet_wrap() or facet_grid() to some continuous variables.
ggplot(data = mpg) +
  geom_point(mapping = aes(x = drv, y = hwy), color = "red") +
  facet_wrap(~ cty, nrow = 3)

ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy), color = "mediumblue") +
  facet_wrap(~ cyl, nrow = 2)

Most of the cars in our mpg data are 4, 6, and 8 cylinder vehicles. 8 cylinder cars have lower highway miles per gallon because of their bigger engine sizes.

# What do empty cells in plot with facet_grid( drv ~ cyl) mean? how do they relate to this plot?
ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy)) +
  facet_grid(drv ~ cyl)

The empty cells relate to the absence of observations for these particular cells.

ggplot(data = mpg) +
  geom_point(mapping = aes(x = drv, y = cyl), color = "red")

The second plot provides a better understanding of the previous plot because it breaks down types of wheels by specific cylinders. From this plot, rear wheel cars have 6 and 8 cylinders; front wheel drives have 4, 5, 6, and 8 cylinders; 4 wheel drive vehicles have 4, 6, and 8 cylinders. There are no vehicles with 7 cylinders in our mpg data.

# What plots do the following codes make? What does . mean?
ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy), color = "brown") +
  facet_grid(drv ~ .)

This plot displays the engine displacement sizes on the x-axis, and their corresponding highway miles per gallon and equivalent wheel drive on y-axis. Front wheel cars tend to have small engine sizes and higher highway miles per gallon. The symbol (.) is used in place of a variable.

ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy), color = "orangered3") +
  facet_grid(. ~ cyl)

This time displ and cyl are on the x-axis (displ below on the x-axis, cyl above on the x-axis). On the y-axis, we now only have hwy. a formula with the rows (of the tabular display) on the LHS and the columns (of the tabular display) on the RHS; the dot in the formula is used to indicate there should be no faceting on this dimension (either row or column).

# Take the first faceted plot in this section.
ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy), color = "midnightblue") +
  facet_wrap( ~ class, nrow = 2)

Facets give us a clear and concise distribution of the data points. Here, the facets perfectly distribute mpg observations by engine sizes and highway miles per gallon by vehicle classes. The disadvantage is the size of dataset. With larger datasets, some observations will not appear on the plot. In this plot, nrow refers to the number of rows. Likewise, ncol refers to the number of columns.

Scales, shrink, labeller, as.table, switch, drop, dir, strip.position are other options that control the layout of the plot. Below is how you can use facet_wrap() with other options:

facet_wrap(facets, nrow = NULL, ncol = NULL, scales = “fixed”, shrink = TRUE, labeller = “label_value”, as.table = TRUE, switch = NULL, drop = TRUE, dir = “h”, strip.position = “top”)

facet_grid() doesn’t need nrow and ncol because they are already defined by faceting variables. The dot in the formula is used to indicate there should be no faceting on this dimension (either row or column).

When using facet_grid() you put the variable with unique levels in the columns to make it easier to visualize the plot, thus to facilitate understanding.

  1. GEOMETRIC OBJECTS

A geom is the geometrical object that a plot uses to represent data. We usually define plots by the type of geom that they use. For example, bar plot uses bar geoms, line chart uses line geoms, boxplot uses boxplot geoms, and so on. Scatterplots break the trend. The following plots use different geoms. The first one uses geom_point() and the second one uses geom_smooth(), a smooth line fitted to the data points.

ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy))

ggplot(data = mpg) +
  geom_smooth(mapping = aes(x = displ, y = hwy, method = 'loess'))

We could set the linetype of a line. Here we could set our linetype = drv in the geom_smooth() function.

ggplot(data = mpg) +
  geom_smooth(mapping = aes(x = displ, y = hwy, linetype = drv))

geom_smooth() separates the cars into 3 lines based on their drv values, which describe a car’s drivetrain. One line describes all the cars with drv value of 4 (four wheel drive), one line describes all the cars with drv value of f(front-wheel drive), and one line describes all cars with drv values of r (rear-wheel drive).

Many geoms, like geom_smooths, use a single geometric object to display multiple rows of data. For these geoms,you can set the aesthetic group to a categorical variable to draw multiple objects. In practice ggplot2 will automatically group the data for these geoms whenever you map an easthetic to a discrete variable( as in the linetype example).

ggplot(data = mpg) +
  geom_smooth(mapping = aes(x = displ, y = hwy))

ggplot(data = mpg) +
  geom_smooth(mapping = aes(x = displ, y = hwy, group = drv))

ggplot(data = mpg) +
  geom_smooth(mapping = aes(x = displ, y = hwy, color = drv), show.legend = TRUE)

To display multiple geoms in the plot and add multiple geom functions, run this code:

ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy)) +
  geom_smooth(mapping = aes(x = displ, y = hwy))

This plot shows that the fitted line over and under-specifies the data points. The data points revolve around the fitted line throughout the displ values. However, this code repeats the same information. The following code will produce the same information as the previous one.

ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) +
  geom_point() +
  geom_smooth()

We can also display different aesthetics in different layers.

ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) +
  geom_point(mapping = aes(color = class)) +
  geom_smooth()

ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) +
  geom_point(mapping = aes(color = drv)) +
  geom_smooth()

We can use the same idea to specify different data for each layer. Here our smooth line displays only a subset of the mpg data, the subcompact cars. The local argument in geom_smooth() overrides the global argument in ggplot() for that layer only.

ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) +
  geom_point(mapping = aes(color = class)) +
  geom_smooth(data = filter(mpg, class == "subcompact"), se = FALSE) 

The geom_smooth(data = filter(mpg, class == “subcompact”), se = FALSE) function selects only subcompact cars.

ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) +
  geom_point(mapping = aes(color = class)) +
  geom_smooth(data = filter(mpg, class == "subcompact"), se = TRUE)

se displays the confidence interval around the smooth line.

# geom_line() connects observations in order of the variable on the x axis.

# geom_boxplot() draws boxplot used to compactly display the distribution of a continuous variable.

# geom_histogram() is used to draw histogram, which displays the count with bars.

# geom_area() is used to display the area of the chart.
ggplot(data = mpg, mapping = aes(x = displ, y = hwy, color = drv)) +
  geom_point() +
  geom_smooth(se = FALSE)

ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) +
  geom_point(mapping = aes(color = drv)) +
  geom_smooth(se = FALSE)

# show.legend = FALSE removes the legend from the plot.
ggplot(data = mpg) +
  geom_smooth(mapping = aes(x = displ, y = hwy, color = drv))

When we remove show.legend = FALSE, R automatically adds the legend by default. The se = TRUE argument to geom_smooth() function adds the confidence interval around the fitted line. The opposite removes the confidence interval around the fitted line.

ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) +
  geom_point() +
  geom_smooth()

ggplot() +
geom_point(data = mpg, mapping = aes(x = displ, y = hwy)) +
geom_smooth(data = mpg, mapping = aes(x = displ, y = hwy))

Two different codes that produce the same plot.

ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) +
  geom_point(size = 5) +
    geom_smooth(se = FALSE)

ggplot(data = mpg, mapping = aes(x = displ, y = hwy, group = drv)) +
  geom_point(size = 5) +
  geom_smooth(se = FALSE)

ggplot(data = mpg, mapping = aes(x = displ, y = hwy, color = drv)) +
  geom_point(size = 4) +
  geom_smooth(se = FALSE)

ggplot(data = mpg, mapping = aes(x = displ, y = hwy, color = drv)) +
  geom_point(size = 4) +
  geom_smooth(data = filter(mpg, drv == 'r'), se = FALSE)

ggplot(data = mpg, mapping = aes(x = displ, y = hwy, color = drv)) +
  geom_point(size = 5) +
  geom_smooth(se = FALSE, color = "blue")

ggplot(data = mpg, mapping = aes(x = displ, y = hwy, color = drv, linetype = drv)) +
  geom_point(size = 5) +
  geom_smooth(se = FALSE, color = "blue")

ggplot(data = mpg, mapping = aes(x = displ, y = hwy, color = drv)) +
  geom_point( size = 5)

LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpUaGlzIGlzIGFuIFtSIE1hcmtkb3duXShodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tKSBOb3RlYm9vay4gV2hlbiB5b3UgZXhlY3V0ZSBjb2RlIHdpdGhpbiB0aGUgbm90ZWJvb2ssIHRoZSByZXN1bHRzIGFwcGVhciBiZW5lYXRoIHRoZSBjb2RlLiANCg0KVGhlIHNvdXJjZSBvZiB0aGVzZSBhbmFseXNlcyBoYXZlIGNvbWUgZnJvbSB0aGUgYm9vayBSIGZvciBEYXRhIFNjaWVuY2UgYnkgSGFkbGV5IFdpY2toYW0gYW5kIEdhcnJldHQgR3JvbGVtdW5kLg0KDQoxLiBQUkVSRVFVSVNJVEVTDQoNCldlIGFyZSBnb2luZyB0byBydW4gYSBjb2xsZWN0aW9uIG9mIHBhY2thZ2VzIGNhbGxlZCB0aGUgdGlkeXZlcnNlIGFuZCBhIGNvbGxlY3Rpb24gb2Ygb3RoZXIgcGFja2FnZXMuIFBhY2thZ2VzIGFyZSB0aGUNCmZ1bmRhbWVudGFscyBvZiByZXByb2R1Y2libGUgUiBjb2RlLiBUaGV5IGluY2x1ZGUgcmV1c2FibGUgZnVuY3Rpb25zLCB0aGUgZG9jdW1lbnRhdGlvbiB0aGF0IGRlc2NyaWJlcyBob3cgdG8gdXNlIHRoZW0sDQphbmQgc2FtcGxlIGRhdGEuIExldCdzIGluc3RhbGwgdGhlIHBhY2thZ2UgdGlkeXZlcnNlLg0KDQpgYGB7ciBJbnN0YWxsIHRoZSB0aWR5dmVyc2UgcGFja2FnZX0NCmluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmBgYA0KDQpUaGUgdGlkeXZlcnNlIHBhY2thZ2UgY29udGFpbnMgc2V2ZXJhbCBvdGhlciBwYWNrYWdlcyB2aXRhbCB0byBkYXRhIG1hbmlwdWxhdGlvbiwgdmlzdWFsaXphdGlvbiwgYW5kIGFuYWx5c2lzLiBUaGVzZSBhcmUgdGhlIGNvcmUgb2YgdGlkeXZlcnNlIGJlY2F1c2UgdGhleSB3aWxsIGJlIHVzZWQgaW4gZXZlcnkgYW5hbHlzaXMuIFBhY2thZ2VzIGluIHRpZHl2ZXJzZSBjaGFuZ2UgZnJlcXVlbnRseS4gSXQgaXMgaW1wb3J0YW50IHRvIGZpbmQgaWYgc29tZSBoYXZlIGJlZW4gdXBkYXRlZCBieSBydW5uaW5nIHRoZSBmb2xsb3dpbmcgY29kZSBmb3IgdXBkYXRlZCBwYWNrYWdlcy4gDQpgYGB7ciBVcGRhdGUgdGhlIHRpZHl2ZXJzZSBwYWNrYWdlfQ0KdGlkeXZlcnNlX3VwZGF0ZSgpDQpgYGANCkxldCdzIHNob3cgdGhlIGZpbGVzIHRoYXQgYXJlIGNvbmZsaWN0aW5nIHdpdGggdGhlIHRpZHl2ZXJzZSBwYWNrYWdlIGJ5IHJ1bm5pbmcgdGhlIGNvZGUgYmVsb3cuDQpgYGB7ciBDaGVjayBDb25mbGljdGluZyBQYWNrYWdlc30NCnRpZHl2ZXJzZV9jb25mbGljdHMoKQ0KYGBgDQpXZSBjYW4gbG9vayBhdCB0aGUgb2JqZWN0cyBpbiB0aGUgcGFja2FnZSB0aWR5dmVyc2UgdXNpbmcgdGhlIGZ1bmN0aW9uIGxpYnJhcnkoKS4NCmBgYHtyIE9iamVjdHMgaW4gdGhlIHRpZHl2ZXJzZSBwYWNrYWdlfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQojID4gTG9hZGluZyB0aWR5dmVyc2U6IGdncGxvdDINCiMgPiBMb2FkaW5nIHRpZHl2ZXJzZTogdGliYmxlDQojID4gTG9hZGluZyB0aWR5dmVyc2U6IHRpZHlyDQojID4gTG9hZGluZyB0aWR5dmVyc2U6IHJlYWRyDQojID4gTG9hZGluZyB0aWR5dmVyc2U6IHB1cnJyDQojID4gTG9hZGluZyB0aWR5dmVyc2U6IGRwbHlyDQojID4gQ29uZmxpY3RzIHdpdGggdGlkeSBwYWNrYWdlcyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgPiBmaWx0ZXIoKTogZHBseXIsIHN0YXRzDQojID4gbGFnKCk6ICAgIGRwbHlyLCBzdGF0cw0KYGBgDQoNCkFkZGl0aW9uYWxseSwgd2UgbmVlZCB0byBpbnN0YWxsIG90aGVyIHBhY2thZ2VzIHRoYXQgYXJlIG5vdCBwYXJ0cyBvZiB0aGUgdGlkeXZlcnNlIHBhY2thZ2VzLiBBcyB3ZSB0YWNrbGUgbW9yZSBkYXRhDQpzY2llbmNlIHByb2plY3RzIGluIFIsIHdlIHdpbGwgbmVlZCB0aGVzZSBwYWNrYWdlcyBmb3IgbmV3IHdheXMgb2YgdGhpbmtpbmcgYWJvdXQgZGF0YS4NCmBgYHtyIE90aGVyIHBhY2thZ2VzfQ0KaW5zdGFsbC5wYWNrYWdlcyhjKCJueWNmbGlnaHRzMTMiLCAiZ2FwbWluZGVyIiwgIkxhaG1hbiIpKQ0KYGBgDQpUaGVzZSBwYWNrYWdlcyBwcm92aWRlIGRhdGEgb24gYWlybGluZSBmbGlnaHRzLCB3b3JsZCBkZXZlbG9wbWVudCwgYW5kIGJhc2ViYWxsIHRoYXQgd2Ugd2lsbCB1c2UgdG8gaWxsdXN0cmF0ZSBrZXkgZGF0YSBzY2llbmNlIGlkZWFzLiBUaGUgZWFzaWVzdCB3YXkgdG8gaW5jbHVkZSBkYXRhIGluIGEgcXVlc3Rpb24gaXMgdG8gdXNlIGRwdXQoKSB0byBnZW5lcmF0ZSB0aGUgUiBjb2RlIHRvIHJlY3JlYXRlIGl0LiBGb3IgZXhhbXBsZToNCmBgYHtyfQ0KZHB1dChtdGNhcnMpDQptdGNhcnMgPC0NCiAgc3RydWN0dXJlKGxpc3QobXBnID0gYygyMSwgMjEsIDIyLjgsIDIxLjQsIDE4LjcsIDE4LjEsIDE0LjMsIA0KMjQuNCwgMjIuOCwgMTkuMiwgMTcuOCwgMTYuNCwgMTcuMywgMTUuMiwgMTAuNCwgMTAuNCwgMTQuNywgMzIuNCwgDQozMC40LCAzMy45LCAyMS41LCAxNS41LCAxNS4yLCAxMy4zLCAxOS4yLCAyNy4zLCAyNiwgMzAuNCwgMTUuOCwgDQoxOS43LCAxNSwgMjEuNCksIGN5bCA9IGMoNiwgNiwgNCwgNiwgOCwgNiwgOCwgNCwgNCwgNiwgNiwgOCwgDQo4LCA4LCA4LCA4LCA4LCA0LCA0LCA0LCA0LCA4LCA4LCA4LCA4LCA0LCA0LCA0LCA4LCA2LCA4LCA0KSwgDQogICAgZGlzcCA9IGMoMTYwLCAxNjAsIDEwOCwgMjU4LCAzNjAsIDIyNSwgMzYwLCAxNDYuNywgMTQwLjgsIA0KICAgIDE2Ny42LCAxNjcuNiwgMjc1LjgsIDI3NS44LCAyNzUuOCwgNDcyLCA0NjAsIDQ0MCwgNzguNywgNzUuNywgDQogICAgNzEuMSwgMTIwLjEsIDMxOCwgMzA0LCAzNTAsIDQwMCwgNzksIDEyMC4zLCA5NS4xLCAzNTEsIDE0NSwgDQogICAgMzAxLCAxMjEpLCBocCA9IGMoMTEwLCAxMTAsIDkzLCAxMTAsIDE3NSwgMTA1LCAyNDUsIDYyLCA5NSwgDQogICAgMTIzLCAxMjMsIDE4MCwgMTgwLCAxODAsIDIwNSwgMjE1LCAyMzAsIDY2LCA1MiwgNjUsIDk3LCAxNTAsIA0KICAgIDE1MCwgMjQ1LCAxNzUsIDY2LCA5MSwgMTEzLCAyNjQsIDE3NSwgMzM1LCAxMDkpLCBkcmF0ID0gYygzLjksIA0KICAgIDMuOSwgMy44NSwgMy4wOCwgMy4xNSwgMi43NiwgMy4yMSwgMy42OSwgMy45MiwgMy45MiwgMy45MiwgDQogICAgMy4wNywgMy4wNywgMy4wNywgMi45MywgMywgMy4yMywgNC4wOCwgNC45MywgNC4yMiwgMy43LCAyLjc2LCANCiAgICAzLjE1LCAzLjczLCAzLjA4LCA0LjA4LCA0LjQzLCAzLjc3LCA0LjIyLCAzLjYyLCAzLjU0LCA0LjExDQogICAgKSwgd3QgPSBjKDIuNjIsIDIuODc1LCAyLjMyLCAzLjIxNSwgMy40NCwgMy40NiwgMy41NywgMy4xOSwgDQogICAgMy4xNSwgMy40NCwgMy40NCwgNC4wNywgMy43MywgMy43OCwgNS4yNSwgNS40MjQsIDUuMzQ1LCAyLjIsIA0KICAgIDEuNjE1LCAxLjgzNSwgMi40NjUsIDMuNTIsIDMuNDM1LCAzLjg0LCAzLjg0NSwgMS45MzUsIDIuMTQsIA0KICAgIDEuNTEzLCAzLjE3LCAyLjc3LCAzLjU3LCAyLjc4KSwgcXNlYyA9IGMoMTYuNDYsIDE3LjAyLCAxOC42MSwgDQogICAgMTkuNDQsIDE3LjAyLCAyMC4yMiwgMTUuODQsIDIwLCAyMi45LCAxOC4zLCAxOC45LCAxNy40LCAxNy42LCANCiAgICAxOCwgMTcuOTgsIDE3LjgyLCAxNy40MiwgMTkuNDcsIDE4LjUyLCAxOS45LCAyMC4wMSwgMTYuODcsIA0KICAgIDE3LjMsIDE1LjQxLCAxNy4wNSwgMTguOSwgMTYuNywgMTYuOSwgMTQuNSwgMTUuNSwgMTQuNiwgMTguNg0KICAgICksIHZzID0gYygwLCAwLCAxLCAxLCAwLCAxLCAwLCAxLCAxLCAxLCAxLCAwLCAwLCAwLCAwLCAwLCANCiAgICAwLCAxLCAxLCAxLCAxLCAwLCAwLCAwLCAwLCAxLCAwLCAxLCAwLCAwLCAwLCAxKSwgYW0gPSBjKDEsIA0KICAgIDEsIDEsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDEsIDEsIDEsIA0KICAgIDAsIDAsIDAsIDAsIDAsIDEsIDEsIDEsIDEsIDEsIDEsIDEpLCBnZWFyID0gYyg0LCA0LCA0LCAzLCANCiAgICAzLCAzLCAzLCA0LCA0LCA0LCA0LCAzLCAzLCAzLCAzLCAzLCAzLCA0LCA0LCA0LCAzLCAzLCAzLCANCiAgICAzLCAzLCA0LCA1LCA1LCA1LCA1LCA1LCA0KSwgY2FyYiA9IGMoNCwgNCwgMSwgMSwgMiwgMSwgNCwgDQogICAgMiwgMiwgNCwgNCwgMywgMywgMywgNCwgNCwgNCwgMSwgMiwgMSwgMSwgMiwgMiwgNCwgMiwgMSwgDQogICAgMiwgMiwgNCwgNiwgOCwgMikpLCAuTmFtZXMgPSBjKCJtcGciLCAiY3lsIiwgImRpc3AiLCAiaHAiLCANCiJkcmF0IiwgInd0IiwgInFzZWMiLCAidnMiLCAiYW0iLCAiZ2VhciIsICJjYXJiIiksIHJvdy5uYW1lcyA9IGMoIk1hemRhIFJYNCIsIA0KIk1hemRhIFJYNCBXYWciLCAiRGF0c3VuIDcxMCIsICJIb3JuZXQgNCBEcml2ZSIsICJIb3JuZXQgU3BvcnRhYm91dCIsIA0KIlZhbGlhbnQiLCAiRHVzdGVyIDM2MCIsICJNZXJjIDI0MEQiLCAiTWVyYyAyMzAiLCAiTWVyYyAyODAiLCANCiJNZXJjIDI4MEMiLCAiTWVyYyA0NTBTRSIsICJNZXJjIDQ1MFNMIiwgIk1lcmMgNDUwU0xDIiwgIkNhZGlsbGFjIEZsZWV0d29vZCIsIA0KIkxpbmNvbG4gQ29udGluZW50YWwiLCAiQ2hyeXNsZXIgSW1wZXJpYWwiLCAiRmlhdCAxMjgiLCAiSG9uZGEgQ2l2aWMiLCANCiJUb3lvdGEgQ29yb2xsYSIsICJUb3lvdGEgQ29yb25hIiwgIkRvZGdlIENoYWxsZW5nZXIiLCAiQU1DIEphdmVsaW4iLCANCiJDYW1hcm8gWjI4IiwgIlBvbnRpYWMgRmlyZWJpcmQiLCAiRmlhdCBYMS05IiwgIlBvcnNjaGUgOTE0LTIiLCANCiJMb3R1cyBFdXJvcGEiLCAiRm9yZCBQYW50ZXJhIEwiLCAiRmVycmFyaSBEaW5vIiwgIk1hc2VyYXRpIEJvcmEiLCANCiJWb2x2byAxNDJFIiksIGNsYXNzID0gImRhdGEuZnJhbWUiKQ0KYGBgDQoNCkluIHRoZSBmaXJzdCBwYXJ0IG9mIHRoaXMgcmVzZWFyY2gsIHdlIHdpbGwgZm9jdXMgb24gdGhlIGJhc2ljIHRvb2xzIG9mIGRhdGEgZXhwbG9yYXRpb24uIERhdGEgZXhwbG9yYXRpb24gaXMgdGhlIGFydCBvZiBsb29raW5nIGF0IHlvdXIgZGF0YSwgcmFwaWRseSBnZW5lcmF0aW5nIHNvbWUgaHlwb3RoZXNlcywgcXVja2x5IHRlc3RpbmcgdGhlbSwgdGhlbiByZXBlYXRpbmcgYWdhaW4gYW5kIGFnYWluLiBUaGVzZSB0b29scyBhcmUgdml0YWwgdG8gZGF0YSBleHBsb3JhdGlvbiBzaW5jZSB0aGV5IGhhdmUgaW1tZWRpYXRlIHBheW9mZjoNCigxKSBWSVNVQUxJWkFUSU9OIGlzIGEgZ3JlYXQgcGxhY2UgdG8gc3RhcnQgd2l0aCBSIHByb2dyYW1taW5nLiBIZXJlLCB3ZSBsZWFybiB0aGUgYmFzaWMgc3RydWN0dXJlIG9mIGdncGxvdDIsIGFuZCBwb3dlcmZ1bCB0ZWNobmlxdWVzIG9mIHR1cm5pbmcgZGF0YSBpbnRvIHBsb3RzLg0KKDIpIERBVEEgVFJBTlNGT1JNQVRJT04gZ2l2ZXMgeW91IHRoZSBrZXkgdmVyYnMgdGhhdCBoZWxwIHlvdSBzZWxlY3QgdGhlIG1vc3QgaW1wb3J0YW50IHZhcmlhYmxlcywgZmlsdGVyIG91dCBrZXkgb2JzZXJ2YXRpb25zLCBjcmVhdGUgbmV3IHZhcmlhYmxlcywgYW5kIGNvbXB1dGUgc3VtbWFyaWVzLg0KKDMpIEZpbmFsbHksIGluIEVYUExBTkFUT1JZIERBVEEgQU5BTFlTSVMsIHdlIGNvbWJpbmUgdmlzdWFsaXphdGlvbiBhbmQgdHJhbnNmb3JtYXRpb24gd2l0aCBjdXJpb3NpdHkgYW5kIHNrZXB0aWNpc20gdG8gYXNrIGFuZCBhbnN3ZXIgaW50ZXJlc3RpbmcgcXVlc3Rpb25zIGFib3V0IHRoZSBkYXRhLg0KDQpgYGB7ciBGSVJTVCBTVEVQIElOIE9VUiBBTkFMWVNJU30NCmluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmBgYA0KTGV0J3MgdXNlIG91ciBncmFwaCB0byBhbnN3ZXIgYSBxdWVzdGlvbjogRG8gY2FycyB3aXRoIGJpZyBlbmdpbmVzIHVzZSBtb3JlIGZ1ZWwgdGhhbiBjYXJzIHdpdGggc21hbGwgZW5naW5lcz8gV2hhdCBkb2VzIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGNhciBlbmdpbmVzIGFuZCBmdWVsIGVmZmljaWVuY3kgbG9vayBsaWtlPyBOZWdhdGl2ZT8gUG9zaXRpdmU/IE5vbmxpbmVhcj8gTGluZWFyPw0KDQpgYGB7ciBUaGUgbXBnIGRhdGEgZnJhbWV9DQptcGcNCiMgQSB0aWJibGU6IDIzNCDXIDExDQojID4gICBtYW51ZmFjdHVyZXIgICAgICBtb2RlbCBkaXNwbCAgeWVhciAgIGN5bCAgICAgIHRyYW5zICAgZHJ2ICAgY3R5ICAgaHd5ICAgIGZsICAgY2xhc3MNCiMgPiAgICAgICAgICA8Y2hyPiAgICAgIDxjaHI+IDxkYmw+IDxpbnQ+IDxpbnQ+ICAgICAgPGNocj4gPGNocj4gPGludD4gPGludD4gPGNocj4gICA8Y2hyPg0KIz4xICAgICAgICAgIGF1ZGkgICAgICAgICBhNCAgIDEuOCAgMTk5OSAgICAgNCAgIGF1dG8obDUpICAgICBmICAgIDE4ICAgIDI5ICAgICBwIGNvbXBhY3QNCiM+MiAgICAgICAgICBhdWRpICAgICAgICAgYTQgICAxLjggIDE5OTkgICAgIDQgbWFudWFsKG01KSAgICAgZiAgICAyMSAgICAyOSAgICAgcCBjb21wYWN0DQojPjMgICAgICAgICAgYXVkaSAgICAgICAgIGE0ICAgMi4wICAyMDA4ICAgICA0IG1hbnVhbChtNikgICAgIGYgICAgMjAgICAgMzEgICAgIHAgY29tcGFjdA0KIz40ICAgICAgICAgIGF1ZGkgICAgICAgICBhNCAgIDIuMCAgMjAwOCAgICAgNCAgIGF1dG8oYXYpICAgICBmICAgIDIxICAgIDMwICAgICBwIGNvbXBhY3QNCiM+NSAgICAgICAgICBhdWRpICAgICAgICAgYTQgICAyLjggIDE5OTkgICAgIDYgICBhdXRvKGw1KSAgICAgZiAgICAxNiAgICAyNiAgICAgcCBjb21wYWN0DQojPjYgICAgICAgICAgYXVkaSAgICAgICAgIGE0ICAgMi44ICAxOTk5ICAgICA2IG1hbnVhbChtNSkgICAgIGYgICAgMTggICAgMjYgICAgIHAgY29tcGFjdA0KIz43ICAgICAgICAgIGF1ZGkgICAgICAgICBhNCAgIDMuMSAgMjAwOCAgICAgNiAgIGF1dG8oYXYpICAgICBmICAgIDE4ICAgIDI3ICAgICBwIGNvbXBhY3QNCiM+OCAgICAgICAgICBhdWRpIGE0IHF1YXR0cm8gICAxLjggIDE5OTkgICAgIDQgbWFudWFsKG01KSAgICAgNCAgICAxOCAgICAyNiAgICAgcCBjb21wYWN0DQojPjkgICAgICAgICAgYXVkaSBhNCBxdWF0dHJvICAgMS44ICAxOTk5ICAgICA0ICAgYXV0byhsNSkgICAgIDQgICAgMTYgICAgMjUgICAgIHAgY29tcGFjdA0KIz4xMCAgICAgICAgIGF1ZGkgYTQgcXVhdHRybyAgIDIuMCAgMjAwOCAgICAgNCBtYW51YWwobTYpICAgICA0ICAgIDIwICAgIDI4ICAgICBwIGNvbXBhY3QNCiMgLi4uIHdpdGggMjI0IG1vcmUgcm93cw0KYGBgDQoNCldlIGNhbiB0ZXN0IG91ciBhbnN3ZXIgd2l0aCB0aGUgZGF0YSBmcmFtZSBmb3VuZCBpbiB0aGUgcGFja2FnZSBnZ3Bsb3QyLCBhbHNvIGtub3cgYXMgZ2dwbG90MjptcGcuIEEgZGF0YSBmcmFtZSBpcyBhDQpyZWN0YW5ndWxhciBjb2xsZWN0aW9uIG9mIHZhcmlhYmxlcyAoaW4gY29sdW1ucykgYW5kIG9ic2VydmF0aW9ucyAoIGluIHJvd3MpLiBtcGcgY29udGFpbnMgb2JzZXJ2YXRpb25zIGNvbGxlY3RlZCBieSB0aGUgVVMgRW52aXJvbm1lbnRhbCBQcm90ZWN0aW9uIEFnZW5jeSBvbiAzOCBtb2RlbHMgb2YgY2FyLiBUaGlzIGNvZGUgd291bGQgaGF2ZSBwcm9kdWNlZCBhIHJlc3VsdCBzaW1pbGFyIGFzIHRoZSBvbmUNCmFib3ZlLg0KDQpgYGB7ciBBbHRlcm5hdGl2ZSBDb2RlIGZvciB0aGUgY29udGVudCBvZiBtcGd9DQpnZ3Bsb3QyOjptcGcNCg0KIyBBIHRpYmJsZTogMjM0INcgMTENCiMgICBtYW51ZmFjdHVyZXIgICAgICBtb2RlbCBkaXNwbCAgeWVhciAgIGN5bCAgICAgIHRyYW5zICAgZHJ2ICAgY3R5ICAgaHd5ICAgIGZsICAgY2xhc3MNCiMgICAgICAgICAgPGNocj4gICAgICA8Y2hyPiA8ZGJsPiA8aW50PiA8aW50PiAgICAgIDxjaHI+IDxjaHI+IDxpbnQ+IDxpbnQ+IDxjaHI+ICAgPGNocj4NCiM+MSAgICAgICAgICBhdWRpICAgICAgICAgYTQgICAxLjggIDE5OTkgICAgIDQgICBhdXRvKGw1KSAgICAgZiAgICAxOCAgICAyOSAgICAgcCBjb21wYWN0DQojPjIgICAgICAgICAgYXVkaSAgICAgICAgIGE0ICAgMS44ICAxOTk5ICAgICA0IG1hbnVhbChtNSkgICAgIGYgICAgMjEgICAgMjkgICAgIHAgY29tcGFjdA0KIz4zICAgICAgICAgIGF1ZGkgICAgICAgICBhNCAgIDIuMCAgMjAwOCAgICAgNCBtYW51YWwobTYpICAgICBmICAgIDIwICAgIDMxICAgICBwIGNvbXBhY3QNCiM+NCAgICAgICAgICBhdWRpICAgICAgICAgYTQgICAyLjAgIDIwMDggICAgIDQgICBhdXRvKGF2KSAgICAgZiAgICAyMSAgICAzMCAgICAgcCBjb21wYWN0DQojPjUgICAgICAgICAgYXVkaSAgICAgICAgIGE0ICAgMi44ICAxOTk5ICAgICA2ICAgYXV0byhsNSkgICAgIGYgICAgMTYgICAgMjYgICAgIHAgY29tcGFjdA0KIz42ICAgICAgICAgIGF1ZGkgICAgICAgICBhNCAgIDIuOCAgMTk5OSAgICAgNiBtYW51YWwobTUpICAgICBmICAgIDE4ICAgIDI2ICAgICBwIGNvbXBhY3QNCiM+NyAgICAgICAgICBhdWRpICAgICAgICAgYTQgICAzLjEgIDIwMDggICAgIDYgICBhdXRvKGF2KSAgICAgZiAgICAxOCAgICAyNyAgICAgcCBjb21wYWN0DQojPjggICAgICAgICAgYXVkaSBhNCBxdWF0dHJvICAgMS44ICAxOTk5ICAgICA0IG1hbnVhbChtNSkgICAgIDQgICAgMTggICAgMjYgICAgIHAgY29tcGFjdA0KIz45ICAgICAgICAgIGF1ZGkgYTQgcXVhdHRybyAgIDEuOCAgMTk5OSAgICAgNCAgIGF1dG8obDUpICAgICA0ICAgIDE2ICAgIDI1ICAgICBwIGNvbXBhY3QNCiM+MTAgICAgICAgICBhdWRpIGE0IHF1YXR0cm8gICAyLjAgIDIwMDggICAgIDQgbWFudWFsKG02KSAgICAgNCAgICAyMCAgICAyOCAgICAgcCBjb21wYWN0DQojIC4uLiB3aXRoIDIyNCBtb3JlIHJvd3MNCg0KYGBgDQoNCmBgYHtyIENoZWNrIFZhcmlhYmxlcyBuYW1lcyBkZXNjcmlwdGlvbn0NCj9tcGcNCg0KIyBGdWVsIGVjb25vbXkgZGF0YSBmcm9tIDE5OTkgYW5kIDIwMDggZm9yIDM4IHBvcHVsYXIgbW9kZWxzIG9mIGNhcg0KDQojIERlc2NyaXB0aW9uDQoNCiMgVGhpcyBkYXRhc2V0IGNvbnRhaW5zIGEgc3Vic2V0IG9mIHRoZSBmdWVsIGVjb25vbXkgZGF0YSB0aGF0IHRoZSBFUEEgbWFrZXMgYXZhaWxhYmxlIG9uIGh0dHA6Ly9mdWVsZWNvbm9teS5nb3YuIEl0ICMgY29udGFpbnMgb25seSBtb2RlbHMgd2hpY2ggaGFkIGEgbmV3IHJlbGVhc2UgZXZlcnkgeWVhciBiZXR3ZWVuIDE5OTkgYW5kIDIwMDggLSB0aGlzIHdhcyB1c2VkIGFzIGEgcHJveHkgZm9yIHRoZSANCiMgcG9wdWxhcml0eSBvZiB0aGUgY2FyLg0KDQojIFVzYWdlDQoNCiMgbXBnDQojIEZvcm1hdA0KDQojIEEgZGF0YSBmcmFtZSB3aXRoIDIzNCByb3dzIGFuZCAxMSB2YXJpYWJsZXMNCg0KIyAoMSkgbWFudWZhY3R1cmVyDQojICgyKSBtb2RlbCA9IG1vZGVsIG5hbWUNCg0KIyAoMykgZGlzcGwgPSBlbmdpbmUgZGlzcGxhY2VtZW50LCBpbiBsaXRyZXMNCg0KIyAoNCkgeWVhciA9IHllYXIgb2YgbWFudWZhY3R1cmUNCg0KIyAoNSkgY3lsID0gbnVtYmVyIG9mIGN5bGluZGVycw0KDQojICg2KSB0cmFucyA9IHR5cGUgb2YgdHJhbnNtaXNzaW9uDQoNCiMgKDcpIGRydiBmID0gZnJvbnQtd2hlZWwgZHJpdmUsIHIgPSByZWFyIHdoZWVsIGRyaXZlLCA0ID0gNHdkDQoNCiMgKDgpIGN0eSA9IGNpdHkgbWlsZXMgcGVyIGdhbGxvbg0KDQojICg5KSBod3kgPSBoaWdod2F5IG1pbGVzIHBlciBnYWxsb24NCg0KIyAoMTApIGZsID0gZnVlbCB0eXBlDQoNCiMgKDExKSBjbGFzcyA9ICJ0eXBlIiBvZiBjYXINCg0KYGBgDQpUbyBhbnN3ZXIgdGhlIHF1ZXN0aW9uIHN0YXRlZCBpbiB0aGUgZmlyc3Qgc3RlcCwgd2UgbmVlZCB0byBzZWxlY3QgdGhlc2UgdHdvIHZhcmlhYmxlczogZGlzcGwgKGVuZ2luZSBkaXNwbGFjZW1lbnQgaW4gbGl0cmVzKSBhbmQgaHd5IChoaWdod2F5IG1pbGVzIHBlciBnYWxsb24pLiBUbyBsZWFybiBhYm91dCBtcGcsIGp1c3QgdHlwZSBtcGcgb3IgP21wZy4NCg0KV2UgYXJlIGdvaW5nIHRvIGNyZWF0ZSBhIGdncGxvdCgpIHBsb3Qgb2YgZGlzcCBhZ2FpbnN0IGh3eSBieSBydW5uaW5nIGRpc3AgaW4gdGhlIHgtYXhpcyBhbmQgaHd5IGluIHRoZSB5LWF4aXMuDQoNCmBgYHtyIENyZWF0ZSBhIGdncGxvdH0NCmdncGxvdChkYXRhID0gbXBnKSArDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKQ0KYGBgDQoNClRoZSBwbG90IHNob3dzIGEgbmVnYXRpdmUgcmVsYXRpb25zaGlwIGJldHdlZW4gZW5naW5lIHNpemUgYW5kIGZ1ZWwgZWZmaWNpZW5jeS4gVGhlIGJpZ2dlciB0aGUgZW5naW5lIHNpemUsIHRoZSBtb3JlIGZ1ZWwgYSBjYXIgY29uc3VtZXMuIFRoZSBwbG90IGFsc28gZXhoaWJpdHMgdGhlIHByZXNlbmNlIG9mIHNvbWUgb3V0bGllcnMuIENhcnMgd2l0aCBiaWcgZW5naW5lIHNpemVzIGJ1dCBoaWdoZXIgZnVlbA0KZWZmaWNpZW5jeSBjb21wYXJlZCB3aXRoIGNhcnMgb2Ygc2ltaWxhciBlbmdpbmUgc2l6ZXMuDQpXaXRoIGdncGxvdCgpIHlvdSBiZWdpbiBwbG90dGluZyBieSBpbnNlcnRpbmcgdGhlIGZpcnN0IGFyZ3VtZW50LCBnZ3Bsb3QoZGF0YSA9IG1wZykuIFRoYXQgY3JlYXRlcyBhbiBlbXB0eSBncmFwaC4gVGhlIGZ1bmN0aW9uIGdlb21fcG9pbnQoKSBhZGRzIGEgbGF5ZXIgb2YgcG9pbnRzIHRvIHlvdXIgcGxvdCwgd2hpY2ggY3JlYXRlcyBhIHNjYXR0ZXJwbG90LiBnZW9tIGZ1bmN0aW9uIHRha2VzIHRoZSBhcmd1bWVudCBtYXBwaW5nLCB3aGljaCBpcyBwYWlyZWQgd2l0aCBhZXMoKSwgYW5kIHRoZSB4IGFuZCB5IGFyZ3VtZW50cyBvZiBhZXMoKS4NCg0KYGBge3IgZ2dwbG90KCkgZ3JhcGhpbmcgVGVtcGxhdGV9DQpnZ3Bsb3QoZGF0YSA9IGRhdGEpICsNCiAgPEdlb21fRnVuY3Rpb24+KG1hcHBpbmcgPSBhZXMoPE1BUFBJTkdTPikNCmBgYA0KDQpMZXQgQXBwbHkgdGhpcyBrbm93bGVkZ2UgdG8gc29tZSBleGVyY2ljZXMuDQpgYGB7ciBFWEVSQ0lTRVN9DQojIFJ1biBnZ3Bsb3QoZGF0YSA9IG1wZyk7IHdlIGdldCBhbiBlbXB0eSBwbG90dGluZyBmaWVsZA0KZ2dwbG90KGRhdGEgPSBtcGcpDQoNCiMgSG93IG1hbnkgY29sdW1ucyBhbmQgcm93cyBpbiBtcGcgZGF0YSA7IFdlIGhhdmUgMTEgY29sdW1ucyAodmFyaWFibGVzKSBhbmQgMjM0IHJvd3MuDQoNCj9tcGcNCg0KIyBUbyBzZWUgdGhlIGRlc2NyaXB0aW9uIG9mIGEgdmFyaWFibGUgZHJ2OyBkcnYgPSBmOiBmcm9udC13aGVlbCBkcml2ZSwgciA9IHJlYXIgd2hlZWwgZHJpdmUsIDQgPSA0d2QNCg0KP21wZw0KDQojIE1ha2UgYSBzY2F0dGVycGxvdCBvZiBod3kgdnMgY3lsIChudW1iZXIgb2YgY3lsaW5kZXJzKQ0KDQpnZ3Bsb3QoZGF0YSA9IG1wZykgKw0KICANCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKCB4ID0gY3lsLCB5ID0gaHd5KSkNCg0KIyBXaGF0IGhhcHBlbnMgaWYgd2UgcGxvdCBjbGFzcyAoIHR5cGUgb2YgY2FyKSBhbmQgZHJ2ICh0eXBlcyBvZiB3aGVlbHMpDQoNCmdncGxvdChkYXRhID0gbXBnKSArDQogIA0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGNsYXNzICwgeSA9IGRydikpDQpgYGANClRoZSBwbG90IGF0dGFjaGVzIHRoZSB0eXBlcyBvZiBjYXIgdG8gaXRzIHdoZWVscy4gV2Uga25vdyB0aGF0IDJzZWF0ZXIgY2FycyBhcmUgcmVhciB3aGVlbCBkcml2ZSwgY29tcGFjdCBjYXJzIGFyZSA0d2QgYW5kIGZyb250IHdoZWVsIGRyaXZlLCBtaWRzaXplIGNhcnMgYXJlIGZyb250IHdoZWVsIGRyaXZlIGFuZCA0d2QsIG1pbml2YW5zIGFyZSBmcm9udCB3aGVlbCBkcml2ZSwgcGlja3VwcyBhcmUgNHdkLCBzdWJjb21wYWN0IGNhcnMgYXJlIDR3ZCwgZnJvbnQgd2hlZWwgZHJpdmUsIGFuZCByZWFyIHdoZWVsIGRyaXZlLCBmaW5hbGx5IHN1dnMgYXJlIDR3ZCwgZnJvbnQgd2hlZWwgZHJpdmUgYW5kIHJlYXIgd2hlZWwgZHJpdmUuIFVzZWZ1bCBpbmZvcm1hdGlvbiBmb3Igb3VyIGFuYWx5c2lzLiANCg0KYGBge3IgQ2hlY2tpbmcgT3V0bGllcnMgaW4gdGhlIHBsb3QgZGlzcCB2cyBod3l9DQoNCmxpYnJhcnkodGlkeXZlcnNlKTotDQoNCmBgYA0KTGV0J3MgaHlwdGhlc2l6ZSB0aGF0IHRoZSBvdXRsaWVycyBhcmUgaHlicmlkcy4gT25lIHdheSB0byB0ZXN0IHRoaXMgaHlwb3RoZXNpcyBpcyB0byBsb29rIGF0IHRoZSBjbGFzcyBvZiBjYXJzLiBXZSBjYW4gYWRkIGEgdGhpcmQgdmFyaWFibGUsIGNsYXNzLCB0byB0aGUgdHdvIGRpbWVuc2lvbmFsIHNjYXR0ZXJwbG90IGJ5IG1hcHBpbmcgaXQgdG8gdGhlIGFlc3RoZXRpYyBmdW5jdGlvbi4gV2UgY2FuIGNvbnZleSB0aGlzIGluZm9ybWF0aW9uIGJ5IG1hcHBpbmcgdGhlIGFlc3RoZXRpY3MgdG8gdGhlIHZhcmlhYmxlcyBpbiBvdXIgZGF0YS4NCg0KYGBge3IgQWRkaW5nIGNsYXNzIG9mIGNhcnMgdG8gdGhlIGFlc3RoZXRpYyBmdW5jdGlvbn0NCmdncGxvdChkYXRhID0gbXBnKSArIA0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBjb2xvciA9IGNsYXNzKSk6LQ0KYGBgDQpUbyBtYXAgYW4gYWVzdGhldGljIHRvIGEgdmFyaWFibGUsIGFzc29jaWF0ZSB0aGUgbmFtZSBvZiB0aGUgYWVzdGhldGljIHRvIHRoZSBuYW1lIG9mIHRoZSB2YXJpYWJsZSBpbnNpZGUgYWVzKCkuZ2dwbG90MiB3aWxsIGF1dG9tYXRpY2FsbHkgYXNzaWduIGEgdW5pcXVlIGxldmVsIG9mIHRoZSBhZXN0aGV0aWMgdG8gZWFjaCB1bmlxdWUgdmFsdWUgb2YgdGhlIHZhcmlhYmxlLCBhIHByb2Nlc3Mga25vd24gYXMgU2NhbGluZy4NCg0KVGhlIHNjYXR0ZXJwbG90IHJldmVhbHMgdGhhdCB0aGUgMnNlYXRlciBjYXJzIGFyZSB0aGUgb25lcyB3aXRoIGJpZyBlbmdpbmVzIGFuZCBoaWdoZXIgZnVlbCBtaWxlYWdlIHRoYW4gb3RoZXJzIGluIHRoZSBzYW1lIGNsYXNzLg0KYGBge3IgTWFwcGluZyB0aGUgdmFyaWFibGUgY2xhc3MgdG8gdGhlIHNpemUgYWVzdGhldGljfQ0KZ2dwbG90KGRhdGEgPSBtcGcpICsNCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCAsIHkgPSBod3ksIHNpemUgPSBjbGFzcykpOi0NCiMgVXNpbmcgc2l6ZSBmb3IgZGlzY2V0ZSB2YXJpYWJsZSBpcyBub3QgYWR2aXNlZC4NCg0KYGBgDQpXZSBjb3VsZCBtYXBwZWQgdGhlIGNsYXNzIHZhcmlhYmxlIHRvIHRoZSBhbHBoYSBhZXN0aGV0aWMsIHdoaWNoIGNvbnRyb2xzIHRoZSB0cmFucGFyZW5jeSBvZiB0aGUgcG9pbnRzLCBvciB0aGUgc2hhcGUgb2YgdGhlIHBvaW50cy4NCmBgYHtyIEFkZCBjbGFzcyB0byB0aGUgYWxwaGEgYWVzdGhldGljfQ0KIyBGaXJzdCBQbG90DQpnZ3Bsb3QoZGF0YSA9IG1wZykgKw0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBhbHBoYSA9IGNsYXNzKSkNCmBgYA0KYGBge3J9DQojIFNlY29uZCBQbG90DQojUmlnaHQgcGxvdA0KZ2dwbG90KGRhdGEgPSBtcGcpICsNCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgc2hhcGUgPSBjbGFzcykpDQpgYGANCg0KVGhlIHNoYXBlIHBhbGV0dGUgY2FuIG9ubHkgZGVhbCB3aXRoIGEgbWluaW11bSBvZiA2IGRpc2NyZXRlIHZhbHVlcyBiZWNhdXNlIG1vcmUgdGhhbiA2IGJlY29tZXMgZGlmZmljdWx0IHRvIGRpc2NyaW1pbmF0ZS4gSGVyZSB3ZSBoYXZlIDcgdmFsdWVzLCB3aGljaCBleHBsYWluIHRoZSBtaXNzaW5nIHNoYXBlIGZvciBTVVYuDQpPbmNlIHlvdSBtYXAgYW4gYWVzdGhldGljLCBnZ3Bsb3QyIHRha2VzIGNhcmUgb2YgdGhlIHJlc3QuIEl0IHNlbGVjdHMgYSByZWFzb25hYmxlIHNjYWxlIHRvIHVzZSB3aXRoIHRoZSBhZXN0aGV0aWMsIGFuZCBpdCBjb25zdHJ1Y3RzIGEgbGVnZW5kIHRoYXQgZXhwbGFpbnMgdGhlIG1hcHBpbmcgYmV0d2VlbiBsZXZlbHMgYW5kIHZhbHVlcy4gRm9yIHggYW5kIHkgYWVzdGhldGljcywgZ2dwbG90MiBkb2VzIG5vdCBjcmVhdGUgYSBsZWdlbmQsIGJ1dCBpdCBjcmVhdGVzIGFuIGF4aXMgbGluZSB3aXRoIHRpY2sgbWFya3MgYW5kIGEgbGFiZWwuIFRoZSBheGlzIGxpbmUgYWN0cyBhcyBhIGxlZ2VuZDsgaXQgZXhwbGFpbnMgdGhlIG1hcHBpbmcgYmV0d2VlbiBsb2NhdGlvbnMgYW5kIHZhbHVlcy4NCldlIGNhbiBhbHNvIHNldCB0aGUgYWVzdGhldGljIHByb3BlcnRpZXMgb2YgdGhlIGdvZW0gbWFudWFsbHkuDQoNCmBgYHtyIE1ha2UgYWxsIHRoZSBhZXN0aGV0aWMgcG9pbnRzIGJsdWV9DQpnZ3Bsb3QoZGF0YSA9IG1wZykgKw0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSwgY29sb3IgPSAiYmx1ZSIpKQ0KDQpgYGANCg0KKDEpIFRoZSBuYW1lIG9mIGEgY29sb3Igc2hvdWxkIGJlIGEgc3RyaW5nIGNoYXJhY3RlcjsgYW5kICgyKSB0aGUgc2l6ZSBvZiBhIHBvaW50IGluIG1tLg0KDQpgYGB7ciBSZXNwb25zZXMgdG8gRXhlcmNpc2VzfQ0KIyB3aGF0IGlzIHdyb25nIHdpdGggdGhpcyBjb2RlOiBzaG91bGRuJ3QgYXBwbHkgY29sb3IgdG8gYWVzdGhldGljLg0KZ2dwbG90KGRhdGEgPSBtcGcpICsNCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSAsIGNvbG9yID0gImJsdWUiKSkNCg0KYGBgDQoNCmBgYHtyfQ0KIyBNYW51ZmFjdHVyZXIsIG1vZGVsLCB0cmFucyAsZHJ2LCBmbCwgY2xhc3MgYXJlIGNhdGVnb3JpY2FsIHZhcmlhYmxlcywgd2hpbGUgZGlzcGwsIHllYXIsIGN5bCwgY3R5LCBod3kgYXJlIGNvbnRpbnVvdXMgdmFyaWFibGUuDQptcGcNCmBgYA0KYGBge3IgTWFwIGEgY29udGludW91cyB2YXJpYWJsZSBvZiBzaXplLCBjb2xvciwgc2hhcGV9DQojIFNJWkUNCmdncGxvdChkYXRhID0gbXBnKSArDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIHNpemUgPSBjeWwpKQ0KYGBgDQpgYGB7ciBNYXBwaW5nIGEgY29udGludW91cyB2YXJpYWJsZSBvZiBjb2xvcn0NCiMgQ09MT1INCmdncGxvdChkYXRhID0gbXBnKSArDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIGNvbG9yID0geWVhcikpDQpgYGANCg0KYGBge3IgTWFwcGluZyBhIGNvbnRpbnVvdXMgdmFyaWFibGUgb2Ygc2hhcGV9DQpnZ3Bsb3QoZGF0YSA9IG1wZykgKw0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBzaGFwZSA9IGN5bCkpDQoNCmBgYA0KQSBjb250aW51b3VzIHZhcmlhYmxlIGNhbm5vdCBiZSBtYXBwZWQgd2l0aCBzaGFwZSwgd2hpbGUgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSBjYW4gYmUgbWFwcGVkIHdpdGggc2hhcGUuIExldCdzIGNoZWNrIHRoZSBmb2xsb3dpbmcgZXhhbXBsZToNCmBgYHtyIE1hcHBpbmcgbWFudWZhY3R1cmVyIHRvIHNoYXBlfQ0KZ2dwbG90KGRhdGEgPSBtcGcpICsNCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgc2hhcGUgPSBkcnYpKQ0KYGBgDQpgYGB7ciBNYXBwaW5nIHRoZSBzYW1lIHZhcmlhYmxlIGluIG11bHRpcGxlIGFlc3RoZXRpY3N9DQpnZ3Bsb3QoZGF0YSA9IG1wZykgKw0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBjb2xvciA9IGh3eSkpDQoNCmBgYA0KDQpNYXBwaW5nIHRoZSBzYW1lIHZhcmlhYmxlIHRvIG11bHRpcGxlIGFlc3RoZXRpY3Mgd29ya3MuIFN0cm9rZSBpcyB1c2VkIHRvIG1vZGlmeSB0aGUgd2lkdGggb2YgdGhlIGJvcmRlci4NCmBgYHtyIFVzaW5nIHN0cm9rZSB0byBtb2RpZnkgdGhlIHdpZHRoIG9mIHRoZSBib3JkZXJ9DQpnZ3Bsb3QoZGF0YSA9IG1wZykgKw0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSwgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJyZWQiLCBzdHJva2UgPSAzLCBzaG93LmxlZ2VuZCA9IEZBTFNFKQ0KYGBgDQogV2hhdCBoYXBwZW5zIGlmIHdlIG1hcCBhbiBhZXN0aGV0aWMgdG8gc29tZXRoaW5nIG90aGVyIHRoYW4gYSB2YXJpYWJsZSwgbGlrZSBhZXMoY29sb3IgPSBkaXNwbCA+IDUpLg0KIA0KIA0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IG1wZykgKw0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGN5bCwgeSA9IGh3eSwgY29sb3IgPSBkaXNwbCA+IDUpKQ0KYGBgDQp0aGUgcGxvdCBzaG93cyB2YWx1ZXMgb2YgY2FycyB0aGF0IGhhdmUgZGlzcGwgZ3JlYXRlciB0aGFuIDUgaW4gYSBkaWZmZXJlbnQgY29sb3IuT25lIHdheSB0byBhZGQgY2F0ZWdvcmljYWwgdmFyaWFibGVzIGlzIHRvIHNwbGl0IHlvdXIgcGxvdCBpbnRvIGZhY2V0cywgc3VicGxvdHMgdGhhdCBlYWNoIGRpc3BsYXlzIG9uZSBzdWJzZXQgb2YgdGhlIGRhdGEuDQoNClRvIGZhY2V0IHlvdXIgcGxvdCB3aXRoIGEgc2luZ2xlIHZhcmlhYmxlIGlzIHRvIHVzZSBmYWNldF93cmFwKCkuIFRoZSBmaXJzdCBhcmd1bWVudCBvZiBmYWNldF93cmFwKCkgc2hvdWxkIGJlIGEgZm9ybXVsYSwgd2hpY2ggeW91IGNyZWF0ZSB3aXRoIH4gZm9sbG93ZWQgYnkgYSB2YXJpYWJsZSBuYW1lLiBIZXJlLCAiZm9ybXVsYSIgaXMgdGhlIG5hbWUgb2YgdGhlIGRhdGEgc3RydWN0dXJlIGluIFIsIG5vdCBhIHN5bm9ueW0gZm9yICJlcXVhdGlvbiIpLiBJbXBvcnRhbnQ6IHRoZSB2YXJpYWJsZSB5b3UgcGFzcyB0byBmYWNldF93cmFwKCkgc2hvdWxkIGJlIGRpc2NyZXRlLg0KDQpgYGB7ciBGQUNFVFM6IEFkZGluZyBDTEFTUyBUbyBUaGUgRnVuY3Rpb24gZmFjZXRfd3JhcCgpfQ0KZ2dwbG90KGRhdGEgPSBtcGcpICsNCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSksIGNvbG9yID0gImJsdWUiKSArDQogICAgICAgICAgICAgICBmYWNldF93cmFwKCB+IGNsYXNzLCBucm93ID0gMikNCmBgYA0KSGVyZSB0aGUgZnVuY3Rpb24gZmFjZXRfd3JhcCgpIG1hcHMgYSB0aGlyZCB2YXJpYWJsZSBvbiB0aGUgY2xhc3NlcyBvZiBjYXJzLiBmYWNldF93cmFwIHdyYXBzIGEgMWQgc2VxdWVuY2Ugb2YgcGFuZWxzIGludG8gMmQuIFRoaXMgaXMgZ2VuZXJhbGx5IGEgYmV0dGVyIHVzZSBvZiBzY3JlZW4gc3BhY2UgdGhhbiBmYWNldF9ncmlkIGJlY2F1c2UgbW9zdCBkaXNwbGF5cyBhcmUgcm91Z2hseSByZWN0YW5ndWxhci4gSGVyZSwgd2Ugc2VlIHRoYXQgYmlnIGVuZ2luZSBjYXJzLCBsaWtlIHBpY2t1cHMgYW5kIFNVViwgaGF2ZSBsb3dlciBoaWdod2F5IGZ1ZWwgZWZmaWNpZW5jaWVzLiBUbyBmYWNldCB5b3VyIHBsb3Qgb24gdGhlIGNvbWJpbmF0aW9uIG9mIHR3byB2YXJpYWJsZXMsIGFkZCB0aGUgZmFjZXRfZ3JpZCgpIHRvIHlvdXIgcGxvdCBjYWxsLiBUaGUgZmlyc3QgYXJndW1lbnQgZmFjZXRfZ3JpZCgpIGlzIGFsc28gYSBmb3JtdWxhLiBUaGlzIHRpbWUgdGhlIGZvcm11bGEgd2lsbCBjb250YWluIHR3byB2YXJpYWJsZSBuYW1lcyBzZXBhcmF0ZWQgYnkgfi4NCg0KYGBge3IgQWRkaW5nIGZhY2V0X2dyaWQoKSBGdW5jdGlvbiBUbyB0aGUgUGxvdH0NCmdncGxvdChkYXRhID0gbXBnKSArDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpLCBjb2xvciA9ICJkYXJrYmx1ZSIpICsNCiAgZmFjZXRfZ3JpZChkcnYgfiBjeWwpDQoNCmBgYA0KDQpJZiB3ZSBwcmVmZXIgbm90IHRvIGZhY2V0IGluIHRoZSByb3dzIG9yIGNvbHVtbnMgZGltZW5zaW9uLCB3ZSBzaG91bGQgdXNlIC4gaW5zdGVhZCBvZiBhIHZhcmlhYmxlIG5hbWUuIEZvciBleGFtcGxlIGZhY2V0X2dyaWQoLiB+IGN5bCkuDQoNCmBgYHtyIFVzZSAuIEluc3RlYWQgT2YgQSBWYXJpYWJsZX0NCmdncGxvdChkYXRhID0gbXBnKSArDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpLCBjb2xvciA9ICJyZWQiKSArDQogIGZhY2V0X2dyaWQoLiB+IGN5bCkNCmBgYA0KQ2FycyB3aXRoIHNtYWxsIGVuZ2luZSBzaXplcyBhbmQgbnVtYmVyIG9mIGN5bGluZGVycyBoYXZlIGJldHRlciBoaWdod2F5IG1pbGVzIHBlciBnYWxsb24sIHdoaWxlIHRob3NlIHdpdGggYmlnIGVuZ2luZSBzaXplcyBhbmQgbnVtYmVyIG9mIGN5bGluZGVycyBoYXZlIGxvd2VyIGhpZ2h3YXkgbWlsZXMgcGVyIGdhbGxvbiwgaW4gZ2VuZXJhbC4gQW5vdGhlciBleGFtcGxlIG9mIGZhY2V0X2dyaWQoLiB+IHZhcmlhYmxlIG5hbWUpLiBUaGlzIHRpbWUgd2UgYXJlIGdvaW5nIHRvIHVzZSB0aGUgdmFyaWFibGUgY2xhc3MuDQoNCmBgYHtyIFVzZSAuIEluIHBsYWNlIE9mIEEgVmFyaWFibGV9DQpnZ3Bsb3QoZGF0YSA9IG1wZykgKw0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSwgY29sb3IgPSAibWFnZW50YSIpICsNCiAgZmFjZXRfZ3JpZCguIH4gY2xhc3MpDQpgYGANCkFnYWluIHBpY2t1cHMgYW5kIHN1dnMgaGF2ZSBsb3dlciBoaWdod2F5IG1pbGVzIHBlciBnYWxsb24gY29tcGFyZWQgdG8gb3RoZXIgY2FycyBpbiB0aGUgbXBnIGRhdGEgZnJhbWUuIFdlIHVzZSBjb2xvciA9ICJtYWdlbnRhIiB0byBhZGQgc29tZSBhZXN0aGV0aWNzIHRvIG91ciBwbG90LiBOb3csIGxldCdzIGFwcGx5IHRoZXNlIHNraWxscyB0byBzb21lIGV4ZXJjaWNlcy4NCg0KYGBge3IgQXBwbGljYXRpb25zfQ0KIyBBcHBseSBmYWNldF93cmFwKCkgb3IgZmFjZXRfZ3JpZCgpIHRvIHNvbWUgY29udGludW91cyB2YXJpYWJsZXMuDQpnZ3Bsb3QoZGF0YSA9IG1wZykgKw0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRydiwgeSA9IGh3eSksIGNvbG9yID0gInJlZCIpICsNCiAgZmFjZXRfd3JhcCh+IGN0eSwgbnJvdyA9IDMpDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IG1wZykgKw0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSwgY29sb3IgPSAibWVkaXVtYmx1ZSIpICsNCiAgZmFjZXRfd3JhcCh+IGN5bCwgbnJvdyA9IDIpDQpgYGANCk1vc3Qgb2YgdGhlIGNhcnMgaW4gb3VyIG1wZyBkYXRhIGFyZSA0LCA2LCBhbmQgOCBjeWxpbmRlciB2ZWhpY2xlcy4gOCBjeWxpbmRlciBjYXJzIGhhdmUgbG93ZXIgaGlnaHdheSBtaWxlcyBwZXIgZ2FsbG9uIGJlY2F1c2Ugb2YgdGhlaXIgYmlnZ2VyIGVuZ2luZSBzaXplcy4NCg0KYGBge3J9DQojIFdoYXQgZG8gZW1wdHkgY2VsbHMgaW4gcGxvdCB3aXRoIGZhY2V0X2dyaWQoIGRydiB+IGN5bCkgbWVhbj8gaG93IGRvIHRoZXkgcmVsYXRlIHRvIHRoaXMgcGxvdD8NCmdncGxvdChkYXRhID0gbXBnKSArDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArDQogIGZhY2V0X2dyaWQoZHJ2IH4gY3lsKQ0KYGBgDQpUaGUgZW1wdHkgY2VsbHMgcmVsYXRlIHRvIHRoZSBhYnNlbmNlIG9mIG9ic2VydmF0aW9ucyBmb3IgdGhlc2UgcGFydGljdWxhciBjZWxscy4gDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBtcGcpICsNCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkcnYsIHkgPSBjeWwpLCBjb2xvciA9ICJyZWQiKQ0KYGBgDQpUaGUgc2Vjb25kIHBsb3QgcHJvdmlkZXMgYSBiZXR0ZXIgdW5kZXJzdGFuZGluZyBvZiB0aGUgcHJldmlvdXMgcGxvdCBiZWNhdXNlIGl0IGJyZWFrcyBkb3duIHR5cGVzIG9mIHdoZWVscyBieSBzcGVjaWZpYyBjeWxpbmRlcnMuIEZyb20gdGhpcyBwbG90LCByZWFyIHdoZWVsIGNhcnMgaGF2ZSA2IGFuZCA4IGN5bGluZGVyczsgZnJvbnQgd2hlZWwgZHJpdmVzIGhhdmUgNCwgNSwgNiwgYW5kIDggY3lsaW5kZXJzOyA0IHdoZWVsIGRyaXZlIHZlaGljbGVzIGhhdmUgNCwgNiwgYW5kIDggY3lsaW5kZXJzLiBUaGVyZSBhcmUgbm8gdmVoaWNsZXMgd2l0aCA3IGN5bGluZGVycyBpbiBvdXIgbXBnIGRhdGEuDQoNCmBgYHtyfQ0KIyBXaGF0IHBsb3RzIGRvIHRoZSBmb2xsb3dpbmcgY29kZXMgbWFrZT8gV2hhdCBkb2VzIC4gbWVhbj8NCmdncGxvdChkYXRhID0gbXBnKSArDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpLCBjb2xvciA9ICJicm93biIpICsNCiAgZmFjZXRfZ3JpZChkcnYgfiAuKQ0KYGBgDQpUaGlzIHBsb3QgZGlzcGxheXMgdGhlIGVuZ2luZSBkaXNwbGFjZW1lbnQgc2l6ZXMgb24gdGhlIHgtYXhpcywgYW5kIHRoZWlyIGNvcnJlc3BvbmRpbmcgaGlnaHdheSBtaWxlcyBwZXIgZ2FsbG9uIGFuZCBlcXVpdmFsZW50IHdoZWVsIGRyaXZlIG9uIHktYXhpcy4gRnJvbnQgd2hlZWwgY2FycyB0ZW5kIHRvIGhhdmUgc21hbGwgZW5naW5lIHNpemVzIGFuZCBoaWdoZXIgaGlnaHdheSBtaWxlcyBwZXIgZ2FsbG9uLiBUaGUgc3ltYm9sICguKSBpcyB1c2VkIGluIHBsYWNlIG9mIGEgdmFyaWFibGUuDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBtcGcpICsNCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSksIGNvbG9yID0gIm9yYW5nZXJlZDMiKSArDQogIGZhY2V0X2dyaWQoLiB+IGN5bCkNCmBgYA0KVGhpcyB0aW1lIGRpc3BsIGFuZCBjeWwgYXJlIG9uIHRoZSB4LWF4aXMgKGRpc3BsIGJlbG93IG9uIHRoZSB4LWF4aXMsIGN5bCBhYm92ZSBvbiB0aGUgeC1heGlzKS4gT24gdGhlIHktYXhpcywgd2Ugbm93IG9ubHkgaGF2ZSBod3kuIGEgZm9ybXVsYSB3aXRoIHRoZSByb3dzIChvZiB0aGUgdGFidWxhciBkaXNwbGF5KSBvbiB0aGUgTEhTIGFuZCB0aGUgY29sdW1ucyAob2YgdGhlIHRhYnVsYXIgZGlzcGxheSkgb24gdGhlIFJIUzsgdGhlIGRvdCBpbiB0aGUgZm9ybXVsYSBpcyB1c2VkIHRvIGluZGljYXRlIHRoZXJlIHNob3VsZCBiZSBubyBmYWNldGluZyBvbiB0aGlzIGRpbWVuc2lvbiAoZWl0aGVyIHJvdyBvciBjb2x1bW4pLg0KDQpgYGB7cn0NCiMgVGFrZSB0aGUgZmlyc3QgZmFjZXRlZCBwbG90IGluIHRoaXMgc2VjdGlvbi4NCmdncGxvdChkYXRhID0gbXBnKSArDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpLCBjb2xvciA9ICJtaWRuaWdodGJsdWUiKSArDQogIGZhY2V0X3dyYXAoIH4gY2xhc3MsIG5yb3cgPSAyKQ0KYGBgDQpGYWNldHMgZ2l2ZSB1cyBhIGNsZWFyIGFuZCBjb25jaXNlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgZGF0YSBwb2ludHMuIEhlcmUsIHRoZSBmYWNldHMgcGVyZmVjdGx5IGRpc3RyaWJ1dGUgbXBnIG9ic2VydmF0aW9ucyBieSBlbmdpbmUgc2l6ZXMgYW5kIGhpZ2h3YXkgbWlsZXMgcGVyIGdhbGxvbiBieSB2ZWhpY2xlIGNsYXNzZXMuIFRoZSBkaXNhZHZhbnRhZ2UgaXMgdGhlIHNpemUgb2YgZGF0YXNldC4gV2l0aCBsYXJnZXIgZGF0YXNldHMsIHNvbWUgb2JzZXJ2YXRpb25zIHdpbGwgbm90IGFwcGVhciBvbiB0aGUgcGxvdC4gSW4gdGhpcyBwbG90LCBucm93IHJlZmVycyB0byB0aGUgbnVtYmVyIG9mIHJvd3MuIExpa2V3aXNlLCBuY29sIHJlZmVycyB0byB0aGUgbnVtYmVyIG9mIGNvbHVtbnMuDQoNClNjYWxlcywgc2hyaW5rLCBsYWJlbGxlciwgYXMudGFibGUsIHN3aXRjaCwgZHJvcCwgZGlyLCBzdHJpcC5wb3NpdGlvbiBhcmUgb3RoZXIgb3B0aW9ucyB0aGF0IGNvbnRyb2wgdGhlIGxheW91dCBvZiB0aGUgcGxvdC4gQmVsb3cgaXMgaG93IHlvdSBjYW4gdXNlIGZhY2V0X3dyYXAoKSB3aXRoIG90aGVyIG9wdGlvbnM6DQoNCmZhY2V0X3dyYXAoZmFjZXRzLCBucm93ID0gTlVMTCwgbmNvbCA9IE5VTEwsIHNjYWxlcyA9ICJmaXhlZCIsDQpzaHJpbmsgPSBUUlVFLCBsYWJlbGxlciA9ICJsYWJlbF92YWx1ZSIsIGFzLnRhYmxlID0gVFJVRSwNCnN3aXRjaCA9IE5VTEwsIGRyb3AgPSBUUlVFLCBkaXIgPSAiaCIsIHN0cmlwLnBvc2l0aW9uID0gInRvcCIpDQoNCmZhY2V0X2dyaWQoKSBkb2Vzbid0IG5lZWQgbnJvdyBhbmQgbmNvbCBiZWNhdXNlIHRoZXkgYXJlIGFscmVhZHkgZGVmaW5lZCBieSBmYWNldGluZyB2YXJpYWJsZXMuIFRoZSBkb3QgaW4gdGhlIGZvcm11bGEgaXMgdXNlZCB0byBpbmRpY2F0ZSB0aGVyZSBzaG91bGQgYmUgbm8gZmFjZXRpbmcgb24gdGhpcyBkaW1lbnNpb24gKGVpdGhlciByb3cgb3IgY29sdW1uKS4NCg0KV2hlbiB1c2luZyBmYWNldF9ncmlkKCkgeW91IHB1dCB0aGUgdmFyaWFibGUgd2l0aCB1bmlxdWUgbGV2ZWxzIGluIHRoZSBjb2x1bW5zIHRvIG1ha2UgaXQgZWFzaWVyIHRvIHZpc3VhbGl6ZSB0aGUgcGxvdCwgdGh1cyB0byBmYWNpbGl0YXRlIHVuZGVyc3RhbmRpbmcuIA0KDQoyLiBHRU9NRVRSSUMgT0JKRUNUUw0KDQpBIGdlb20gaXMgdGhlIGdlb21ldHJpY2FsIG9iamVjdCB0aGF0IGEgcGxvdCB1c2VzIHRvIHJlcHJlc2VudCBkYXRhLiBXZSB1c3VhbGx5IGRlZmluZSBwbG90cyBieSB0aGUgdHlwZSBvZiBnZW9tIHRoYXQgdGhleSB1c2UuIEZvciBleGFtcGxlLCBiYXIgcGxvdCB1c2VzIGJhciBnZW9tcywgbGluZSBjaGFydCB1c2VzIGxpbmUgZ2VvbXMsIGJveHBsb3QgdXNlcyBib3hwbG90IGdlb21zLCBhbmQgc28gb24uIFNjYXR0ZXJwbG90cyBicmVhayB0aGUgdHJlbmQuIFRoZSBmb2xsb3dpbmcgcGxvdHMgdXNlIGRpZmZlcmVudCBnZW9tcy4gVGhlIGZpcnN0IG9uZSB1c2VzIGdlb21fcG9pbnQoKSBhbmQgdGhlIHNlY29uZCBvbmUgdXNlcyBnZW9tX3Ntb290aCgpLCBhIHNtb290aCBsaW5lIGZpdHRlZCB0byB0aGUgZGF0YSBwb2ludHMuDQoNCmBgYHtyIEZpcnN0IFBsb3Qgd2l0aCBnZW9tX3BvaW50KCl9DQpnZ3Bsb3QoZGF0YSA9IG1wZykgKw0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkNCmBgYA0KDQpgYGB7ciBTZWNvbmQgUGxvdCB3aXRoIGdlb21fc21vb3RoKCksIEEgU21vb3RoIEZpdHRlZCBMaW5lfQ0KZ2dwbG90KGRhdGEgPSBtcGcpICsNCiAgZ2VvbV9zbW9vdGgobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIG1ldGhvZCA9ICdsb2VzcycpKQ0KDQpgYGANCldlIGNvdWxkIHNldCB0aGUgbGluZXR5cGUgb2YgYSBsaW5lLiBIZXJlIHdlIGNvdWxkIHNldCBvdXIgbGluZXR5cGUgPSBkcnYgaW4gdGhlIGdlb21fc21vb3RoKCkgZnVuY3Rpb24uDQoNCmBgYHtyIFBsb3Qgd2l0aCBBIExpbmV0eXBlfQ0KZ2dwbG90KGRhdGEgPSBtcGcpICsNCiAgZ2VvbV9zbW9vdGgobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIGxpbmV0eXBlID0gZHJ2KSkNCg0KYGBgDQoNCmdlb21fc21vb3RoKCkgc2VwYXJhdGVzIHRoZSBjYXJzIGludG8gMyBsaW5lcyBiYXNlZCBvbiB0aGVpciBkcnYgdmFsdWVzLCB3aGljaCBkZXNjcmliZSBhIGNhcidzIGRyaXZldHJhaW4uIE9uZSBsaW5lIGRlc2NyaWJlcyBhbGwgdGhlIGNhcnMgd2l0aCBkcnYgdmFsdWUgb2YgNCAoZm91ciB3aGVlbCBkcml2ZSksIG9uZSBsaW5lIGRlc2NyaWJlcyBhbGwgdGhlIGNhcnMgd2l0aCBkcnYgdmFsdWUgb2YgZihmcm9udC13aGVlbCBkcml2ZSksIGFuZCBvbmUgbGluZSBkZXNjcmliZXMgYWxsIGNhcnMgd2l0aCBkcnYgdmFsdWVzIG9mIHIgKHJlYXItd2hlZWwgZHJpdmUpLg0KDQpNYW55IGdlb21zLCBsaWtlIGdlb21fc21vb3RocywgdXNlIGEgc2luZ2xlIGdlb21ldHJpYyBvYmplY3QgdG8gZGlzcGxheSBtdWx0aXBsZSByb3dzIG9mIGRhdGEuIEZvciB0aGVzZSBnZW9tcyx5b3UgY2FuIHNldCB0aGUgYWVzdGhldGljIGdyb3VwIHRvIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUgdG8gZHJhdyBtdWx0aXBsZSBvYmplY3RzLiBJbiBwcmFjdGljZSBnZ3Bsb3QyIHdpbGwgYXV0b21hdGljYWxseSBncm91cCB0aGUgZGF0YSBmb3IgdGhlc2UgZ2VvbXMgd2hlbmV2ZXIgeW91IG1hcCBhbiBlYXN0aGV0aWMgdG8gYSBkaXNjcmV0ZSB2YXJpYWJsZSggYXMgaW4gdGhlIGxpbmV0eXBlIGV4YW1wbGUpLg0KDQpgYGB7ciBQbG90IHdpdGggTm8gZ3JvdXAgZWFzdGhldGljIGZvciBkaXNjcmV0ZSB2YXJpYWJsZX0NCmdncGxvdChkYXRhID0gbXBnKSArDQogIGdlb21fc21vb3RoKG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkNCmBgYA0KYGBge3IgUGxvdCB3aXRoIEdyb3VwIEFlc3RoZXRpYyBmb3IgZHJ2IHZhcmlhYmxlfQ0KZ2dwbG90KGRhdGEgPSBtcGcpICsNCiAgZ2VvbV9zbW9vdGgobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIGdyb3VwID0gZHJ2KSkNCmBgYA0KDQpgYGB7ciBQbG90IHdpdGggQ29sb3IgQWVzdGhldGljIGZvciBkcnYgYW5kIGxlZ2VuZH0NCmdncGxvdChkYXRhID0gbXBnKSArDQogIGdlb21fc21vb3RoKG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBjb2xvciA9IGRydiksIHNob3cubGVnZW5kID0gVFJVRSkNCg0KYGBgDQpUbyBkaXNwbGF5IG11bHRpcGxlIGdlb21zIGluIHRoZSBwbG90IGFuZCBhZGQgbXVsdGlwbGUgZ2VvbSBmdW5jdGlvbnMsIHJ1biB0aGlzIGNvZGU6DQoNCmBgYHtyIE11bHRpcGxlIEdlb21zIGFuZCBmdW5jdGlvbnMgaW4gYSBzaW5nbGUgcGxvdH0NCmdncGxvdChkYXRhID0gbXBnKSArDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArDQogIGdlb21fc21vb3RoKG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkNCg0KYGBgDQoNClRoaXMgcGxvdCBzaG93cyB0aGF0IHRoZSBmaXR0ZWQgbGluZSBvdmVyIGFuZCB1bmRlci1zcGVjaWZpZXMgdGhlIGRhdGEgcG9pbnRzLiBUaGUgZGF0YSBwb2ludHMgcmV2b2x2ZSBhcm91bmQgdGhlIGZpdHRlZCBsaW5lIHRocm91Z2hvdXQgdGhlIGRpc3BsIHZhbHVlcy4gSG93ZXZlciwgdGhpcyBjb2RlIHJlcGVhdHMgdGhlIHNhbWUgaW5mb3JtYXRpb24uIFRoZSBmb2xsb3dpbmcgY29kZSB3aWxsIHByb2R1Y2UgdGhlIHNhbWUgaW5mb3JtYXRpb24gYXMgdGhlIHByZXZpb3VzIG9uZS4NCg0KYGBge3IgU2FtZSBDb2RlIEFzIHRoZSBQcmV2aW91cyBPbmV9DQpnZ3Bsb3QoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArDQogIGdlb21fcG9pbnQoKSArDQogIGdlb21fc21vb3RoKCkNCmBgYA0KDQpXZSBjYW4gYWxzbyBkaXNwbGF5IGRpZmZlcmVudCBhZXN0aGV0aWNzIGluIGRpZmZlcmVudCBsYXllcnMuDQoNCmBgYHtyIEFlc3RoZXRpY3MgV2l0aCBEaWZmZXJlbnQgTGF5ZXJzfQ0KZ2dwbG90KGRhdGEgPSBtcGcsIG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKw0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoY29sb3IgPSBjbGFzcykpICsNCiAgZ2VvbV9zbW9vdGgoKQ0KYGBgDQoNCmBgYHtyIFNhbWUgQ29kZSBBcyBUaGUgcHJldmlvdXMgb25lfQ0KZ2dwbG90KGRhdGEgPSBtcGcsIG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKw0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoY29sb3IgPSBkcnYpKSArDQogIGdlb21fc21vb3RoKCkNCmBgYA0KDQpXZSBjYW4gdXNlIHRoZSBzYW1lIGlkZWEgdG8gc3BlY2lmeSBkaWZmZXJlbnQgZGF0YSBmb3IgZWFjaCBsYXllci4gSGVyZSBvdXIgc21vb3RoIGxpbmUgZGlzcGxheXMgb25seSBhIHN1YnNldCBvZiB0aGUgbXBnIGRhdGEsIHRoZSBzdWJjb21wYWN0IGNhcnMuIFRoZSBsb2NhbCBhcmd1bWVudCBpbiBnZW9tX3Ntb290aCgpIG92ZXJyaWRlcyB0aGUgZ2xvYmFsIGFyZ3VtZW50IGluIGdncGxvdCgpIGZvciB0aGF0IGxheWVyIG9ubHkuDQoNCmBgYHtyIFBsb3QgZm9yIFN1YmNvbXBhY3Qgc3Vic2V0IG9ubHl9DQpnZ3Bsb3QoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyhjb2xvciA9IGNsYXNzKSkgKw0KICBnZW9tX3Ntb290aChkYXRhID0gZmlsdGVyKG1wZywgY2xhc3MgPT0gInN1YmNvbXBhY3QiKSwgc2UgPSBGQUxTRSkgDQpgYGANCg0KVGhlIGdlb21fc21vb3RoKGRhdGEgPSBmaWx0ZXIobXBnLCBjbGFzcyA9PSAic3ViY29tcGFjdCIpLCBzZSA9IEZBTFNFKSBmdW5jdGlvbiBzZWxlY3RzIG9ubHkgc3ViY29tcGFjdCBjYXJzLg0KDQpgYGB7ciBTZXR0aW5nIHNlfQ0KZ2dwbG90KGRhdGEgPSBtcGcsIG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKw0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoY29sb3IgPSBjbGFzcykpICsNCiAgZ2VvbV9zbW9vdGgoZGF0YSA9IGZpbHRlcihtcGcsIGNsYXNzID09ICJzdWJjb21wYWN0IiksIHNlID0gVFJVRSkNCmBgYA0KDQpzZSBkaXNwbGF5cyB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbCBhcm91bmQgdGhlIHNtb290aCBsaW5lLg0KDQpgYGB7ciBQcmFjdGljZSBFeGVyY2lzZXN9DQojIGdlb21fbGluZSgpIGNvbm5lY3RzIG9ic2VydmF0aW9ucyBpbiBvcmRlciBvZiB0aGUgdmFyaWFibGUgb24gdGhlIHggYXhpcy4NCg0KIyBnZW9tX2JveHBsb3QoKSBkcmF3cyBib3hwbG90IHVzZWQgdG8gY29tcGFjdGx5IGRpc3BsYXkgdGhlIGRpc3RyaWJ1dGlvbiBvZiBhIGNvbnRpbnVvdXMgdmFyaWFibGUuDQoNCiMgZ2VvbV9oaXN0b2dyYW0oKSBpcyB1c2VkIHRvIGRyYXcgaGlzdG9ncmFtLCB3aGljaCBkaXNwbGF5cyB0aGUgY291bnQgd2l0aCBiYXJzLg0KDQojIGdlb21fYXJlYSgpIGlzIHVzZWQgdG8gZGlzcGxheSB0aGUgYXJlYSBvZiB0aGUgY2hhcnQuDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIGNvbG9yID0gZHJ2KSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX3Ntb290aChzZSA9IEZBTFNFKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBtcGcsIG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKw0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoY29sb3IgPSBkcnYpKSArDQogIGdlb21fc21vb3RoKHNlID0gRkFMU0UpDQpgYGANCmBgYHtyfQ0KIyBzaG93LmxlZ2VuZCA9IEZBTFNFIHJlbW92ZXMgdGhlIGxlZ2VuZCBmcm9tIHRoZSBwbG90Lg0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBtcGcpICsNCiAgZ2VvbV9zbW9vdGgobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIGNvbG9yID0gZHJ2KSkNCmBgYA0KIFdoZW4gd2UgcmVtb3ZlIHNob3cubGVnZW5kID0gRkFMU0UsIFIgYXV0b21hdGljYWxseSBhZGRzIHRoZSBsZWdlbmQgYnkgZGVmYXVsdC4NCiBUaGUgc2UgPSBUUlVFIGFyZ3VtZW50IHRvIGdlb21fc21vb3RoKCkgZnVuY3Rpb24gYWRkcyB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbCBhcm91bmQgdGhlIGZpdHRlZCBsaW5lLiBUaGUgb3Bwb3NpdGUgcmVtb3ZlcyB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbCBhcm91bmQgdGhlIGZpdHRlZCBsaW5lLg0KIA0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArDQogIGdlb21fcG9pbnQoKSArDQogIGdlb21fc21vb3RoKCkNCmBgYA0KYGBge3J9DQpnZ3Bsb3QoKSArDQpnZW9tX3BvaW50KGRhdGEgPSBtcGcsIG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKw0KZ2VvbV9zbW9vdGgoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKQ0KYGBgDQoNClR3byBkaWZmZXJlbnQgY29kZXMgdGhhdCBwcm9kdWNlIHRoZSBzYW1lIHBsb3QuDQoNCmBgYHtyIFJlY3JlYXRlIHRoZSBSIGNvZGUgdXNlZCB0byBnZW5lcmF0ZSB0aGVzZSBwbG90c30NCmdncGxvdChkYXRhID0gbXBnLCBtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpICsNCiAgZ2VvbV9wb2ludChzaXplID0gNSkgKw0KICAgIGdlb21fc21vb3RoKHNlID0gRkFMU0UpDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIGdyb3VwID0gZHJ2KSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSA1KSArDQogIGdlb21fc21vb3RoKHNlID0gRkFMU0UpDQpgYGANCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBtcGcsIG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBjb2xvciA9IGRydikpICsNCiAgZ2VvbV9wb2ludChzaXplID0gNCkgKw0KICBnZW9tX3Ntb290aChzZSA9IEZBTFNFKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBtcGcsIG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBjb2xvciA9IGRydikpICsNCiAgZ2VvbV9wb2ludChzaXplID0gNCkgKw0KICBnZW9tX3Ntb290aChkYXRhID0gZmlsdGVyKG1wZywgZHJ2ID09ICdyJyksIHNlID0gRkFMU0UpDQpgYGANCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBtcGcsIG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBjb2xvciA9IGRydikpICsNCiAgZ2VvbV9wb2ludChzaXplID0gNSkgKw0KICBnZW9tX3Ntb290aChzZSA9IEZBTFNFLCBjb2xvciA9ICJibHVlIikNCmBgYA0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gbXBnLCBtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgY29sb3IgPSBkcnYsIGxpbmV0eXBlID0gZHJ2KSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSA1KSArDQogIGdlb21fc21vb3RoKHNlID0gRkFMU0UsIGNvbG9yID0gImJsdWUiKQ0KYGBgDQpgYGB7cn0NCmdncGxvdChkYXRhID0gbXBnLCBtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgY29sb3IgPSBkcnYpKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDUpDQpgYGANCg0K