Introduction to Plotting with R

[The introduction remains the same as in the previous version]

1. Basic Plotting with Base R

[This section remains the same until the exercises]

Exercises

  1. Create a scatter plot using the mtcars dataset to visualize the relationship between horsepower (hp) and quarter-mile time (qsec). Use red triangles for the points.

Solution:

plot(mtcars$hp, mtcars$qsec, 
     main = "Horsepower vs. Quarter-Mile Time",
     xlab = "Horsepower", 
     ylab = "Quarter-Mile Time (seconds)",
     pch = 17, 
     col = "red")

  1. Using the iris dataset (another built-in R dataset), create a scatter plot of sepal length vs. sepal width. Color the points based on the species.
colors <- c("setosa" = "red", "versicolor" = "blue", "virginica" = "green")
species_colors <- colors[iris$Species]
colors[iris$Species]
    setosa     setosa     setosa     setosa     setosa     setosa     setosa     setosa     setosa     setosa     setosa     setosa 
     "red"      "red"      "red"      "red"      "red"      "red"      "red"      "red"      "red"      "red"      "red"      "red" 
    setosa     setosa     setosa     setosa     setosa     setosa     setosa     setosa     setosa     setosa     setosa     setosa 
     "red"      "red"      "red"      "red"      "red"      "red"      "red"      "red"      "red"      "red"      "red"      "red" 
    setosa     setosa     setosa     setosa     setosa     setosa     setosa     setosa     setosa     setosa     setosa     setosa 
     "red"      "red"      "red"      "red"      "red"      "red"      "red"      "red"      "red"      "red"      "red"      "red" 
    setosa     setosa     setosa     setosa     setosa     setosa     setosa     setosa     setosa     setosa     setosa     setosa 
     "red"      "red"      "red"      "red"      "red"      "red"      "red"      "red"      "red"      "red"      "red"      "red" 
    setosa     setosa versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor 
     "red"      "red"     "blue"     "blue"     "blue"     "blue"     "blue"     "blue"     "blue"     "blue"     "blue"     "blue" 
versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor 
    "blue"     "blue"     "blue"     "blue"     "blue"     "blue"     "blue"     "blue"     "blue"     "blue"     "blue"     "blue" 
versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor 
    "blue"     "blue"     "blue"     "blue"     "blue"     "blue"     "blue"     "blue"     "blue"     "blue"     "blue"     "blue" 
versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor 
    "blue"     "blue"     "blue"     "blue"     "blue"     "blue"     "blue"     "blue"     "blue"     "blue"     "blue"     "blue" 
versicolor versicolor versicolor versicolor  virginica  virginica  virginica  virginica  virginica  virginica  virginica  virginica 
    "blue"     "blue"     "blue"     "blue"    "green"    "green"    "green"    "green"    "green"    "green"    "green"    "green" 
 virginica  virginica  virginica  virginica  virginica  virginica  virginica  virginica  virginica  virginica  virginica  virginica 
   "green"    "green"    "green"    "green"    "green"    "green"    "green"    "green"    "green"    "green"    "green"    "green" 
 virginica  virginica  virginica  virginica  virginica  virginica  virginica  virginica  virginica  virginica  virginica  virginica 
   "green"    "green"    "green"    "green"    "green"    "green"    "green"    "green"    "green"    "green"    "green"    "green" 
 virginica  virginica  virginica  virginica  virginica  virginica  virginica  virginica  virginica  virginica  virginica  virginica 
   "green"    "green"    "green"    "green"    "green"    "green"    "green"    "green"    "green"    "green"    "green"    "green" 
 virginica  virginica  virginica  virginica  virginica  virginica 
   "green"    "green"    "green"    "green"    "green"    "green" 

Solution:

# Create a color vector based on species
colors <- c("setosa" = "red", "versicolor" = "blue", "virginica" = "green")
species_colors <- colors[iris$Species]

plot(iris$Sepal.Length, iris$Sepal.Width,
     main = "Iris Sepal Length vs. Sepal Width",
     xlab = "Sepal Length", 
     ylab = "Sepal Width",
     pch = 19,
     col = species_colors)

# Add a legend
legend("topright", legend = levels(iris$Species), 
       col = colors, pch = 19, title = "Species")

ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width, color = Species)) +
  geom_point() +
  labs(title = "Iris Sepal Length vs. Sepal Width",
       x = "Sepal Length",
       y = "Sepal Width",
       color = "Species") +
  theme_minimal()

2. Introduction to ggplot2

[This section remains the same until the exercises]

Exercises

  1. Using ggplot2 and the economics dataset (comes with ggplot2), create a line plot of unemployment over time. Use the date column for the x-axis and unemploy for the y-axis. Add appropriate labels and a title.

Solution:

ggplot(economics, aes(x = date, y = unemploy)) +
  geom_line(color = "blue") +
  labs(title = "Unemployment Over Time",
       x = "Date",
       y = "Number of Unemployed (in thousands)") +
  theme_minimal()
  1. With the mpg dataset (also included in ggplot2), create a scatter plot of engine displacement (displ) vs. highway miles per gallon (hwy). Color the points by the class of the vehicle. Add a title and appropriate axis labels.

Solution:

ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
  geom_point() +
  labs(title = "Engine Displacement vs. Highway MPG",
       x = "Engine Displacement (L)",
       y = "Highway MPG",
       color = "Vehicle Class") +
  theme_minimal()

3. Enhancing Plots with Color and Shape

[This section remains the same until the exercises]

Exercises

  1. Using the diamonds dataset (included in ggplot2), create a scatter plot of price vs. carat. Use color to represent the cut quality and shape to represent the clarity. Add appropriate labels and a title.

Solution:

ggplot(diamonds, aes(x = carat, y = price, color = cut, shape = clarity)) +
  geom_point(alpha = .6) +
  labs(title = "Diamond Price vs. Carat",
       x = "Carat",
       y = "Price (USD)",
       color = "Cut Quality",
       shape = "Clarity") +
  theme_minimal() +
  scale_color_brewer(palette = "Set1")
Warning: Using shapes for an ordinal variable is not advised
Warning: The shape palette can deal with a maximum of 6 discrete values because more than 6 becomes difficult to discriminate
ℹ you have requested 8 values. Consider specifying shapes manually if you need that many have them.
Warning: Removed 5445 rows containing missing values or values outside the scale range (`geom_point()`).

  1. With the iris dataset, create a scatter plot of petal length vs. petal width. Use color to represent the species. Instead of using different shapes, vary the size of the points based on the sepal width. Add a legend for both color and size.

Solution:

ggplot(iris, aes(x = Petal.Length, y = Petal.Width, color = Species, size = Sepal.Width)) +
  geom_point(alpha = 0.6) +
  labs(title = "Iris Petal Length vs. Petal Width",
       x = "Petal Length",
       y = "Petal Width",
       color = "Species",
       size = "Sepal Width") +
  theme_minimal() +
  scale_color_brewer(palette = "Set2")

4. Creating Bar Plots

[This section remains the same until the exercises]

Exercises

  1. Using the mpg dataset, create a bar plot showing the count of cars for each manufacturer. Order the bars from highest to lowest count. Add appropriate labels and a title.

Solution:

# Prepare data
manufacturer_counts <- mpg %>%
  count(manufacturer) %>%
  arrange(desc(n))

ggplot(manufacturer_counts, aes(x = reorder(manufacturer, -n), y = n)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  labs(title = "Number of Cars by Manufacturer",
       x = "Manufacturer",
       y = "Count") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))
  1. With the diamonds dataset, create a stacked bar plot showing the proportion of different cuts (fair, good, very good, premium, ideal) for each clarity category. Use different colors for each cut. Add a legend and appropriate labels.

Solution:

ggplot(diamonds, aes(x = clarity, fill = cut)) +
  geom_bar(position = "fill") +
  labs(title = "Proportion of Diamond Cuts by Clarity",
       x = "Clarity",
       y = "Proportion",
       fill = "Cut") +
  theme_minimal() +
  scale_fill_brewer(palette = "Set3")

5. Box Plots for Comparing Distributions

[This section remains the same until the exercises]

Exercises

  1. Using the diamonds dataset, create a box plot showing the distribution of price for each cut category. Add color to the boxes based on the cut. Include appropriate labels and a title.

Solution:

ggplot(diamonds, aes(x = cut, y = price, fill = cut)) +
  geom_boxplot() +
  labs(title = "Distribution of Diamond Prices by Cut",
       x = "Cut",
       y = "Price (USD)") +
  theme_minimal() +
  scale_fill_brewer(palette = "Set2") +
  theme(legend.position = "none")
  1. With the gapminder dataset (you may need to install the gapminder package), create a box plot showing the distribution of life expectancy for each continent. Arrange the continents in descending order of median life expectancy. Add color and appropriate labels.

Solution:

# Install and load gapminder if not already installed
# install.packages("gapminder")
library(gapminder)

# Calculate median life expectancy for each continent
continent_order <- gapminder %>%
  group_by(continent) %>%
  summarize(median_lifeExp = median(lifeExp)) %>%
  arrange(desc(median_lifeExp)) %>%
  pull(continent)

ggplot(gapminder, aes(x = factor(continent, levels = continent_order), y = lifeExp, fill = continent)) +
  geom_boxplot() +
  labs(title = "Distribution of Life Expectancy by Continent",
       x = "Continent",
       y = "Life Expectancy (years)") +
  theme_minimal() +
  scale_fill_brewer(palette = "Set3") +
  theme(legend.position = "none")

6. Histograms and Density Plots

[This section remains the same until the exercises]

Exercises

  1. Using the diamonds dataset, create a histogram of the ‘price’ variable. Experiment with different bin widths to see how it affects the visualization. Add a density curve on top of the histogram. Include appropriate labels and a title.

Solution:

ggplot(diamonds, aes(x = price)) +
  geom_histogram(aes(y = ..density..), binwidth = 500, fill = "lightblue", color = "black") +
  geom_density(color = "red", size = 1) +
  labs(title = "Distribution of Diamond Prices",
       x = "Price (USD)",
       y = "Density") +
  theme_minimal()
  1. With the faithful dataset (built into R), create two density plots on the same graph: one for eruption duration and one for waiting time between eruptions. Use different colors for each density curve and add a legend. Normalize the scales so that both curves use the same y-axis. Add appropriate labels and a title.

Solution:

# Prepare data
faithful_long <- faithful %>%
  pivot_longer(cols = everything(), names_to = "variable", values_to = "value")

ggplot(faithful_long, aes(x = value, fill = variable)) +
  geom_density(alpha = 0.5) +
  labs(title = "Density Plots of Old Faithful Eruptions",
       x = "Duration (minutes) / Waiting Time (minutes)",
       y = "Density",
       fill = "Variable") +
  scale_fill_manual(values = c("blue", "red"),
                    labels = c("Eruption duration", "Waiting time")) +
  theme_minimal()

7. Faceting for Multi-panel Plots

[This section remains the same until the exercises]

Exercises

  1. Using the diamonds dataset, create a scatter plot of price vs. carat. Facet the plot by cut, creating a 2x3 grid of subplots. Color the points by clarity. Add a smooth trend line to each facet. Include appropriate labels and a title.

Solution:

ggplot(diamonds, aes(x = carat, y = price, color = clarity)) +
  geom_point(alpha = 0.3) +
  geom_smooth(method = "lm", se = FALSE) +
  facet_wrap(~cut, nrow = 2) +
  labs(title = "Diamond Price vs. Carat by Cut and Clarity",
       x = "Carat",
       y = "Price (USD)",
       color = "Clarity") +
  theme_minimal() +
  scale_color_brewer(palette = "Set1")
  1. With the mpg dataset, create a box plot of highway fuel efficiency (hwy) for different car classes. Facet the plot by the number of cylinders (cyl). Color the boxes by the type of drive (drv). Arrange the facets in a single row. Add appropriate labels and a title.

Solution:

ggplot(mpg, aes(x = class, y = hwy, fill = drv)) +
  geom_boxplot() +
  facet_wrap(~cyl, nrow = 1) +
  labs(title = "Highway MPG by Class, Cylinders, and Drive Type",
       x = "Vehicle Class",
       y = "Highway MPG",
       fill = "Drive Type") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  scale_fill_brewer(palette = "Set2")

Conclusion

[The conclusion remains the same as in the previous version]

LS0tCnRpdGxlOiAiQ3JlYXRpbmcgUGxvdHMgZnJvbSBEYXRhZnJhbWVzIGluIFI6IFNvbHV0aW9ucyIKYXV0aG9yOiAiTmF5ZWwgQmV0dGFjaGUiCmRhdGU6ICIyMDI0LTA5LTE4IgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCiMgSW50cm9kdWN0aW9uIHRvIFBsb3R0aW5nIHdpdGggUgoKW1RoZSBpbnRyb2R1Y3Rpb24gcmVtYWlucyB0aGUgc2FtZSBhcyBpbiB0aGUgcHJldmlvdXMgdmVyc2lvbl0KCiMjIDEuIEJhc2ljIFBsb3R0aW5nIHdpdGggQmFzZSBSCgpbVGhpcyBzZWN0aW9uIHJlbWFpbnMgdGhlIHNhbWUgdW50aWwgdGhlIGV4ZXJjaXNlc10KCiMjIyBFeGVyY2lzZXMKCjEuICBDcmVhdGUgYSBzY2F0dGVyIHBsb3QgdXNpbmcgdGhlIGBtdGNhcnNgIGRhdGFzZXQgdG8gdmlzdWFsaXplIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBob3JzZXBvd2VyIChgaHBgKSBhbmQgcXVhcnRlci1taWxlIHRpbWUgKGBxc2VjYCkuIFVzZSByZWQgdHJpYW5nbGVzIGZvciB0aGUgcG9pbnRzLgoKU29sdXRpb246CgpgYGB7cn0KcGxvdChtdGNhcnMkaHAsIG10Y2FycyRxc2VjLCAKICAgICBtYWluID0gIkhvcnNlcG93ZXIgdnMuIFF1YXJ0ZXItTWlsZSBUaW1lIiwKICAgICB4bGFiID0gIkhvcnNlcG93ZXIiLCAKICAgICB5bGFiID0gIlF1YXJ0ZXItTWlsZSBUaW1lIChzZWNvbmRzKSIsCiAgICAgcGNoID0gMTcsIAogICAgIGNvbCA9ICJyZWQiKQpgYGAKCjIuICBVc2luZyB0aGUgYGlyaXNgIGRhdGFzZXQgKGFub3RoZXIgYnVpbHQtaW4gUiBkYXRhc2V0KSwgY3JlYXRlIGEgc2NhdHRlciBwbG90IG9mIHNlcGFsIGxlbmd0aCB2cy4gc2VwYWwgd2lkdGguIENvbG9yIHRoZSBwb2ludHMgYmFzZWQgb24gdGhlIHNwZWNpZXMuCgpgYGB7cn0KY29sb3JzIDwtIGMoInNldG9zYSIgPSAicmVkIiwgInZlcnNpY29sb3IiID0gImJsdWUiLCAidmlyZ2luaWNhIiA9ICJncmVlbiIpCnNwZWNpZXNfY29sb3JzIDwtIGNvbG9yc1tpcmlzJFNwZWNpZXNdCmNvbG9yc1tpcmlzJFNwZWNpZXNdCmBgYAoKClNvbHV0aW9uOgoKYGBge3J9CiMgQ3JlYXRlIGEgY29sb3IgdmVjdG9yIGJhc2VkIG9uIHNwZWNpZXMKY29sb3JzIDwtIGMoInNldG9zYSIgPSAicmVkIiwgInZlcnNpY29sb3IiID0gImJsdWUiLCAidmlyZ2luaWNhIiA9ICJncmVlbiIpCnNwZWNpZXNfY29sb3JzIDwtIGNvbG9yc1tpcmlzJFNwZWNpZXNdCgpwbG90KGlyaXMkU2VwYWwuTGVuZ3RoLCBpcmlzJFNlcGFsLldpZHRoLAogICAgIG1haW4gPSAiSXJpcyBTZXBhbCBMZW5ndGggdnMuIFNlcGFsIFdpZHRoIiwKICAgICB4bGFiID0gIlNlcGFsIExlbmd0aCIsIAogICAgIHlsYWIgPSAiU2VwYWwgV2lkdGgiLAogICAgIHBjaCA9IDE5LAogICAgIGNvbCA9IHNwZWNpZXNfY29sb3JzKQoKIyBBZGQgYSBsZWdlbmQKbGVnZW5kKCJ0b3ByaWdodCIsIGxlZ2VuZCA9IGxldmVscyhpcmlzJFNwZWNpZXMpLCAKICAgICAgIGNvbCA9IGNvbG9ycywgcGNoID0gMTksIHRpdGxlID0gIlNwZWNpZXMiKQpgYGAKYGBgIHtyfQpnZ3Bsb3QoaXJpcywgYWVzKHggPSBTZXBhbC5MZW5ndGgsIHkgPSBTZXBhbC5XaWR0aCwgY29sb3IgPSBTcGVjaWVzKSkgKwogIGdlb21fcG9pbnQoKSArCiAgbGFicyh0aXRsZSA9ICJJcmlzIFNlcGFsIExlbmd0aCB2cy4gU2VwYWwgV2lkdGgiLAogICAgICAgeCA9ICJTZXBhbCBMZW5ndGgiLAogICAgICAgeSA9ICJTZXBhbCBXaWR0aCIsCiAgICAgICBjb2xvciA9ICJTcGVjaWVzIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCiMjIDIuIEludHJvZHVjdGlvbiB0byBnZ3Bsb3QyCgpbVGhpcyBzZWN0aW9uIHJlbWFpbnMgdGhlIHNhbWUgdW50aWwgdGhlIGV4ZXJjaXNlc10KCiMjIyBFeGVyY2lzZXMKCjEuICBVc2luZyBgZ2dwbG90MmAgYW5kIHRoZSBgZWNvbm9taWNzYCBkYXRhc2V0IChjb21lcyB3aXRoIGdncGxvdDIpLCBjcmVhdGUgYSBsaW5lIHBsb3Qgb2YgdW5lbXBsb3ltZW50IG92ZXIgdGltZS4gVXNlIHRoZSBgZGF0ZWAgY29sdW1uIGZvciB0aGUgeC1heGlzIGFuZCBgdW5lbXBsb3lgIGZvciB0aGUgeS1heGlzLiBBZGQgYXBwcm9wcmlhdGUgbGFiZWxzIGFuZCBhIHRpdGxlLgoKU29sdXRpb246CgpgYGB7cn0KZ2dwbG90KGVjb25vbWljcywgYWVzKHggPSBkYXRlLCB5ID0gdW5lbXBsb3kpKSArCiAgZ2VvbV9saW5lKGNvbG9yID0gImJsdWUiKSArCiAgbGFicyh0aXRsZSA9ICJVbmVtcGxveW1lbnQgT3ZlciBUaW1lIiwKICAgICAgIHggPSAiRGF0ZSIsCiAgICAgICB5ID0gIk51bWJlciBvZiBVbmVtcGxveWVkIChpbiB0aG91c2FuZHMpIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCjIuICBXaXRoIHRoZSBgbXBnYCBkYXRhc2V0IChhbHNvIGluY2x1ZGVkIGluIGdncGxvdDIpLCBjcmVhdGUgYSBzY2F0dGVyIHBsb3Qgb2YgZW5naW5lIGRpc3BsYWNlbWVudCAoYGRpc3BsYCkgdnMuIGhpZ2h3YXkgbWlsZXMgcGVyIGdhbGxvbiAoYGh3eWApLiBDb2xvciB0aGUgcG9pbnRzIGJ5IHRoZSBgY2xhc3NgIG9mIHRoZSB2ZWhpY2xlLiBBZGQgYSB0aXRsZSBhbmQgYXBwcm9wcmlhdGUgYXhpcyBsYWJlbHMuCgpTb2x1dGlvbjoKCmBgYHtyfQpnZ3Bsb3QobXBnLCBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBjb2xvciA9IGNsYXNzKSkgKwogIGdlb21fcG9pbnQoKSArCiAgbGFicyh0aXRsZSA9ICJFbmdpbmUgRGlzcGxhY2VtZW50IHZzLiBIaWdod2F5IE1QRyIsCiAgICAgICB4ID0gIkVuZ2luZSBEaXNwbGFjZW1lbnQgKEwpIiwKICAgICAgIHkgPSAiSGlnaHdheSBNUEciLAogICAgICAgY29sb3IgPSAiVmVoaWNsZSBDbGFzcyIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgojIyAzLiBFbmhhbmNpbmcgUGxvdHMgd2l0aCBDb2xvciBhbmQgU2hhcGUKCltUaGlzIHNlY3Rpb24gcmVtYWlucyB0aGUgc2FtZSB1bnRpbCB0aGUgZXhlcmNpc2VzXQoKIyMjIEV4ZXJjaXNlcwoKMS4gIFVzaW5nIHRoZSBgZGlhbW9uZHNgIGRhdGFzZXQgKGluY2x1ZGVkIGluIGdncGxvdDIpLCBjcmVhdGUgYSBzY2F0dGVyIHBsb3Qgb2YgcHJpY2UgdnMuIGNhcmF0LiBVc2UgY29sb3IgdG8gcmVwcmVzZW50IHRoZSBjdXQgcXVhbGl0eSBhbmQgc2hhcGUgdG8gcmVwcmVzZW50IHRoZSBjbGFyaXR5LiBBZGQgYXBwcm9wcmlhdGUgbGFiZWxzIGFuZCBhIHRpdGxlLgoKU29sdXRpb246CgpgYGB7cn0KZ2dwbG90KGRpYW1vbmRzLCBhZXMoeCA9IGNhcmF0LCB5ID0gcHJpY2UsIGNvbG9yID0gY3V0LCBzaGFwZSA9IGNsYXJpdHkpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IC42KSArCiAgbGFicyh0aXRsZSA9ICJEaWFtb25kIFByaWNlIHZzLiBDYXJhdCIsCiAgICAgICB4ID0gIkNhcmF0IiwKICAgICAgIHkgPSAiUHJpY2UgKFVTRCkiLAogICAgICAgY29sb3IgPSAiQ3V0IFF1YWxpdHkiLAogICAgICAgc2hhcGUgPSAiQ2xhcml0eSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIlNldDEiKQpgYGAKCjIuICBXaXRoIHRoZSBgaXJpc2AgZGF0YXNldCwgY3JlYXRlIGEgc2NhdHRlciBwbG90IG9mIHBldGFsIGxlbmd0aCB2cy4gcGV0YWwgd2lkdGguIFVzZSBjb2xvciB0byByZXByZXNlbnQgdGhlIHNwZWNpZXMuIEluc3RlYWQgb2YgdXNpbmcgZGlmZmVyZW50IHNoYXBlcywgdmFyeSB0aGUgc2l6ZSBvZiB0aGUgcG9pbnRzIGJhc2VkIG9uIHRoZSBzZXBhbCB3aWR0aC4gQWRkIGEgbGVnZW5kIGZvciBib3RoIGNvbG9yIGFuZCBzaXplLgoKU29sdXRpb246CgpgYGB7cn0KZ2dwbG90KGlyaXMsIGFlcyh4ID0gUGV0YWwuTGVuZ3RoLCB5ID0gUGV0YWwuV2lkdGgsIGNvbG9yID0gU3BlY2llcywgc2l6ZSA9IFNlcGFsLldpZHRoKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjYpICsKICBsYWJzKHRpdGxlID0gIklyaXMgUGV0YWwgTGVuZ3RoIHZzLiBQZXRhbCBXaWR0aCIsCiAgICAgICB4ID0gIlBldGFsIExlbmd0aCIsCiAgICAgICB5ID0gIlBldGFsIFdpZHRoIiwKICAgICAgIGNvbG9yID0gIlNwZWNpZXMiLAogICAgICAgc2l6ZSA9ICJTZXBhbCBXaWR0aCIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIlNldDIiKQpgYGAKCiMjIDQuIENyZWF0aW5nIEJhciBQbG90cwoKW1RoaXMgc2VjdGlvbiByZW1haW5zIHRoZSBzYW1lIHVudGlsIHRoZSBleGVyY2lzZXNdCgojIyMgRXhlcmNpc2VzCgoxLiAgVXNpbmcgdGhlIGBtcGdgIGRhdGFzZXQsIGNyZWF0ZSBhIGJhciBwbG90IHNob3dpbmcgdGhlIGNvdW50IG9mIGNhcnMgZm9yIGVhY2ggbWFudWZhY3R1cmVyLiBPcmRlciB0aGUgYmFycyBmcm9tIGhpZ2hlc3QgdG8gbG93ZXN0IGNvdW50LiBBZGQgYXBwcm9wcmlhdGUgbGFiZWxzIGFuZCBhIHRpdGxlLgoKU29sdXRpb246CgpgYGB7cn0KIyBQcmVwYXJlIGRhdGEKbWFudWZhY3R1cmVyX2NvdW50cyA8LSBtcGcgJT4lCiAgY291bnQobWFudWZhY3R1cmVyKSAlPiUKICBhcnJhbmdlKGRlc2MobikpCgpnZ3Bsb3QobWFudWZhY3R1cmVyX2NvdW50cywgYWVzKHggPSByZW9yZGVyKG1hbnVmYWN0dXJlciwgLW4pLCB5ID0gbikpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJza3libHVlIikgKwogIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIENhcnMgYnkgTWFudWZhY3R1cmVyIiwKICAgICAgIHggPSAiTWFudWZhY3R1cmVyIiwKICAgICAgIHkgPSAiQ291bnQiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQpgYGAKCjIuICBXaXRoIHRoZSBgZGlhbW9uZHNgIGRhdGFzZXQsIGNyZWF0ZSBhIHN0YWNrZWQgYmFyIHBsb3Qgc2hvd2luZyB0aGUgcHJvcG9ydGlvbiBvZiBkaWZmZXJlbnQgY3V0cyAoZmFpciwgZ29vZCwgdmVyeSBnb29kLCBwcmVtaXVtLCBpZGVhbCkgZm9yIGVhY2ggY2xhcml0eSBjYXRlZ29yeS4gVXNlIGRpZmZlcmVudCBjb2xvcnMgZm9yIGVhY2ggY3V0LiBBZGQgYSBsZWdlbmQgYW5kIGFwcHJvcHJpYXRlIGxhYmVscy4KClNvbHV0aW9uOgoKYGBge3J9CmdncGxvdChkaWFtb25kcywgYWVzKHggPSBjbGFyaXR5LCBmaWxsID0gY3V0KSkgKwogIGdlb21fYmFyKHBvc2l0aW9uID0gImZpbGwiKSArCiAgbGFicyh0aXRsZSA9ICJQcm9wb3J0aW9uIG9mIERpYW1vbmQgQ3V0cyBieSBDbGFyaXR5IiwKICAgICAgIHggPSAiQ2xhcml0eSIsCiAgICAgICB5ID0gIlByb3BvcnRpb24iLAogICAgICAgZmlsbCA9ICJDdXQiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDMiKQpgYGAKCiMjIDUuIEJveCBQbG90cyBmb3IgQ29tcGFyaW5nIERpc3RyaWJ1dGlvbnMKCltUaGlzIHNlY3Rpb24gcmVtYWlucyB0aGUgc2FtZSB1bnRpbCB0aGUgZXhlcmNpc2VzXQoKIyMjIEV4ZXJjaXNlcwoKMS4gIFVzaW5nIHRoZSBgZGlhbW9uZHNgIGRhdGFzZXQsIGNyZWF0ZSBhIGJveCBwbG90IHNob3dpbmcgdGhlIGRpc3RyaWJ1dGlvbiBvZiBwcmljZSBmb3IgZWFjaCBjdXQgY2F0ZWdvcnkuIEFkZCBjb2xvciB0byB0aGUgYm94ZXMgYmFzZWQgb24gdGhlIGN1dC4gSW5jbHVkZSBhcHByb3ByaWF0ZSBsYWJlbHMgYW5kIGEgdGl0bGUuCgpTb2x1dGlvbjoKCmBgYHtyfQpnZ3Bsb3QoZGlhbW9uZHMsIGFlcyh4ID0gY3V0LCB5ID0gcHJpY2UsIGZpbGwgPSBjdXQpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGxhYnModGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIERpYW1vbmQgUHJpY2VzIGJ5IEN1dCIsCiAgICAgICB4ID0gIkN1dCIsCiAgICAgICB5ID0gIlByaWNlIChVU0QpIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgoyLiAgV2l0aCB0aGUgYGdhcG1pbmRlcmAgZGF0YXNldCAoeW91IG1heSBuZWVkIHRvIGluc3RhbGwgdGhlIGdhcG1pbmRlciBwYWNrYWdlKSwgY3JlYXRlIGEgYm94IHBsb3Qgc2hvd2luZyB0aGUgZGlzdHJpYnV0aW9uIG9mIGxpZmUgZXhwZWN0YW5jeSBmb3IgZWFjaCBjb250aW5lbnQuIEFycmFuZ2UgdGhlIGNvbnRpbmVudHMgaW4gZGVzY2VuZGluZyBvcmRlciBvZiBtZWRpYW4gbGlmZSBleHBlY3RhbmN5LiBBZGQgY29sb3IgYW5kIGFwcHJvcHJpYXRlIGxhYmVscy4KClNvbHV0aW9uOgoKYGBge3J9CiMgSW5zdGFsbCBhbmQgbG9hZCBnYXBtaW5kZXIgaWYgbm90IGFscmVhZHkgaW5zdGFsbGVkCiMgaW5zdGFsbC5wYWNrYWdlcygiZ2FwbWluZGVyIikKbGlicmFyeShnYXBtaW5kZXIpCgojIENhbGN1bGF0ZSBtZWRpYW4gbGlmZSBleHBlY3RhbmN5IGZvciBlYWNoIGNvbnRpbmVudApjb250aW5lbnRfb3JkZXIgPC0gZ2FwbWluZGVyICU+JQogIGdyb3VwX2J5KGNvbnRpbmVudCkgJT4lCiAgc3VtbWFyaXplKG1lZGlhbl9saWZlRXhwID0gbWVkaWFuKGxpZmVFeHApKSAlPiUKICBhcnJhbmdlKGRlc2MobWVkaWFuX2xpZmVFeHApKSAlPiUKICBwdWxsKGNvbnRpbmVudCkKCmdncGxvdChnYXBtaW5kZXIsIGFlcyh4ID0gZmFjdG9yKGNvbnRpbmVudCwgbGV2ZWxzID0gY29udGluZW50X29yZGVyKSwgeSA9IGxpZmVFeHAsIGZpbGwgPSBjb250aW5lbnQpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGxhYnModGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIExpZmUgRXhwZWN0YW5jeSBieSBDb250aW5lbnQiLAogICAgICAgeCA9ICJDb250aW5lbnQiLAogICAgICAgeSA9ICJMaWZlIEV4cGVjdGFuY3kgKHllYXJzKSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MyIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKIyMgNi4gSGlzdG9ncmFtcyBhbmQgRGVuc2l0eSBQbG90cwoKW1RoaXMgc2VjdGlvbiByZW1haW5zIHRoZSBzYW1lIHVudGlsIHRoZSBleGVyY2lzZXNdCgojIyMgRXhlcmNpc2VzCgoxLiAgVXNpbmcgdGhlIGBkaWFtb25kc2AgZGF0YXNldCwgY3JlYXRlIGEgaGlzdG9ncmFtIG9mIHRoZSAncHJpY2UnIHZhcmlhYmxlLiBFeHBlcmltZW50IHdpdGggZGlmZmVyZW50IGJpbiB3aWR0aHMgdG8gc2VlIGhvdyBpdCBhZmZlY3RzIHRoZSB2aXN1YWxpemF0aW9uLiBBZGQgYSBkZW5zaXR5IGN1cnZlIG9uIHRvcCBvZiB0aGUgaGlzdG9ncmFtLiBJbmNsdWRlIGFwcHJvcHJpYXRlIGxhYmVscyBhbmQgYSB0aXRsZS4KClNvbHV0aW9uOgoKYGBge3J9CmdncGxvdChkaWFtb25kcywgYWVzKHggPSBwcmljZSkpICsKICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IC4uZGVuc2l0eS4uKSwgYmlud2lkdGggPSA1MDAsIGZpbGwgPSAibGlnaHRibHVlIiwgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV9kZW5zaXR5KGNvbG9yID0gInJlZCIsIHNpemUgPSAxKSArCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgRGlhbW9uZCBQcmljZXMiLAogICAgICAgeCA9ICJQcmljZSAoVVNEKSIsCiAgICAgICB5ID0gIkRlbnNpdHkiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKMi4gIFdpdGggdGhlIGBmYWl0aGZ1bGAgZGF0YXNldCAoYnVpbHQgaW50byBSKSwgY3JlYXRlIHR3byBkZW5zaXR5IHBsb3RzIG9uIHRoZSBzYW1lIGdyYXBoOiBvbmUgZm9yIGVydXB0aW9uIGR1cmF0aW9uIGFuZCBvbmUgZm9yIHdhaXRpbmcgdGltZSBiZXR3ZWVuIGVydXB0aW9ucy4gVXNlIGRpZmZlcmVudCBjb2xvcnMgZm9yIGVhY2ggZGVuc2l0eSBjdXJ2ZSBhbmQgYWRkIGEgbGVnZW5kLiBOb3JtYWxpemUgdGhlIHNjYWxlcyBzbyB0aGF0IGJvdGggY3VydmVzIHVzZSB0aGUgc2FtZSB5LWF4aXMuIEFkZCBhcHByb3ByaWF0ZSBsYWJlbHMgYW5kIGEgdGl0bGUuCgpTb2x1dGlvbjoKCmBgYHtyfQojIFByZXBhcmUgZGF0YQpmYWl0aGZ1bF9sb25nIDwtIGZhaXRoZnVsICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gZXZlcnl0aGluZygpLCBuYW1lc190byA9ICJ2YXJpYWJsZSIsIHZhbHVlc190byA9ICJ2YWx1ZSIpCgpnZ3Bsb3QoZmFpdGhmdWxfbG9uZywgYWVzKHggPSB2YWx1ZSwgZmlsbCA9IHZhcmlhYmxlKSkgKwogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNSkgKwogIGxhYnModGl0bGUgPSAiRGVuc2l0eSBQbG90cyBvZiBPbGQgRmFpdGhmdWwgRXJ1cHRpb25zIiwKICAgICAgIHggPSAiRHVyYXRpb24gKG1pbnV0ZXMpIC8gV2FpdGluZyBUaW1lIChtaW51dGVzKSIsCiAgICAgICB5ID0gIkRlbnNpdHkiLAogICAgICAgZmlsbCA9ICJWYXJpYWJsZSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJibHVlIiwgInJlZCIpLAogICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkVydXB0aW9uIGR1cmF0aW9uIiwgIldhaXRpbmcgdGltZSIpKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKIyMgNy4gRmFjZXRpbmcgZm9yIE11bHRpLXBhbmVsIFBsb3RzCgpbVGhpcyBzZWN0aW9uIHJlbWFpbnMgdGhlIHNhbWUgdW50aWwgdGhlIGV4ZXJjaXNlc10KCiMjIyBFeGVyY2lzZXMKCjEuICBVc2luZyB0aGUgYGRpYW1vbmRzYCBkYXRhc2V0LCBjcmVhdGUgYSBzY2F0dGVyIHBsb3Qgb2YgcHJpY2UgdnMuIGNhcmF0LiBGYWNldCB0aGUgcGxvdCBieSBjdXQsIGNyZWF0aW5nIGEgMngzIGdyaWQgb2Ygc3VicGxvdHMuIENvbG9yIHRoZSBwb2ludHMgYnkgY2xhcml0eS4gQWRkIGEgc21vb3RoIHRyZW5kIGxpbmUgdG8gZWFjaCBmYWNldC4gSW5jbHVkZSBhcHByb3ByaWF0ZSBsYWJlbHMgYW5kIGEgdGl0bGUuCgpTb2x1dGlvbjoKCmBgYHtyfQpnZ3Bsb3QoZGlhbW9uZHMsIGFlcyh4ID0gY2FyYXQsIHkgPSBwcmljZSwgY29sb3IgPSBjbGFyaXR5KSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjMpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFKSArCiAgZmFjZXRfd3JhcCh+Y3V0LCBucm93ID0gMikgKwogIGxhYnModGl0bGUgPSAiRGlhbW9uZCBQcmljZSB2cy4gQ2FyYXQgYnkgQ3V0IGFuZCBDbGFyaXR5IiwKICAgICAgIHggPSAiQ2FyYXQiLAogICAgICAgeSA9ICJQcmljZSAoVVNEKSIsCiAgICAgICBjb2xvciA9ICJDbGFyaXR5IikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIpCmBgYAoKMi4gIFdpdGggdGhlIGBtcGdgIGRhdGFzZXQsIGNyZWF0ZSBhIGJveCBwbG90IG9mIGhpZ2h3YXkgZnVlbCBlZmZpY2llbmN5IChod3kpIGZvciBkaWZmZXJlbnQgY2FyIGNsYXNzZXMuIEZhY2V0IHRoZSBwbG90IGJ5IHRoZSBudW1iZXIgb2YgY3lsaW5kZXJzIChjeWwpLiBDb2xvciB0aGUgYm94ZXMgYnkgdGhlIHR5cGUgb2YgZHJpdmUgKGRydikuIEFycmFuZ2UgdGhlIGZhY2V0cyBpbiBhIHNpbmdsZSByb3cuIEFkZCBhcHByb3ByaWF0ZSBsYWJlbHMgYW5kIGEgdGl0bGUuCgpTb2x1dGlvbjoKCmBgYHtyfQpnZ3Bsb3QobXBnLCBhZXMoeCA9IGNsYXNzLCB5ID0gaHd5LCBmaWxsID0gZHJ2KSkgKwogIGdlb21fYm94cGxvdCgpICsKICBmYWNldF93cmFwKH5jeWwsIG5yb3cgPSAxKSArCiAgbGFicyh0aXRsZSA9ICJIaWdod2F5IE1QRyBieSBDbGFzcywgQ3lsaW5kZXJzLCBhbmQgRHJpdmUgVHlwZSIsCiAgICAgICB4ID0gIlZlaGljbGUgQ2xhc3MiLAogICAgICAgeSA9ICJIaWdod2F5IE1QRyIsCiAgICAgICBmaWxsID0gIkRyaXZlIFR5cGUiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIikKYGBgCgojIyBDb25jbHVzaW9uCgpbVGhlIGNvbmNsdXNpb24gcmVtYWlucyB0aGUgc2FtZSBhcyBpbiB0aGUgcHJldmlvdXMgdmVyc2lvbl0K