Remember, before you can use the tidyverse, you need to load the package.
library(tidyverse)
First Steps
More plots with the mpg dataset
(Taken form R4DS)
- Run
ggplot(data = mpg)
. What do you see?
- How many rows are in mpg? How many columns?
- What does the
drv
variable describe? You may want to use ?mpg
to find out
- Make a scatter plot of
hwy
vs cyl
- What happens if you make a scatter plot of
class
vs drv
? Why is the plot not useful?
Plots with other datasets
- Take a look at the
iris
dataset. What are its dimensions? What do its columns represent?
- What are the ranges of each of the numeric columns. The
summary()
function might help you here
- Make a plot of sepal width vs sepal length, and set all of the points to be green
- Repeat the previous plot but colour each point by the species of the flower
Remaking plots
- Take a look at the first and last few rows of the
mtcars
dataset
- Access the
cyl
column of the dataset. Is this variable categorical, discrete, or continuous?
- What steps would you go about to remake the following plot?
More Aesthetics
Size, Transparency, and Shape
- Using the
mpg
dataset, make a plot of city mileage vs highway mileage where the size of each point is determined by engine size (displ
)
- Plot sepal length vs sepal width using the
iris
dataset and control the transparency (alpha
) of each point using the species
variable.
- Have a play with the
Orange
data set (note the capital ‘O’). Make a scatter plot of circumference against age where the shape of each point is determined by which tree the observation belongs to
- Remake the standard
hwy
vs displ
plot using the mpg
data set but make all of the points hollow diamonds. How about solid triangles?
Choosing Appropriate Aesthetics
(Q1/2 form R4DS)
- Which variables in
mpg
are categorical? Which are continuous/discrete? (The data set help file may be of use)
- Map a continuous variable to colour, size, and shape. How does this differ from when you map a categorical variable?
- Plot the standard
hwy
vs displ
graph using mpg
and map the variable class
to the size
aesthetic. Was this a good idea?
- Have a discussion with a partner or think for yourself: Which of the aesthetics you know are the clearest for displaying categorical data and which are best for continuous?
- In your own opinion, order the following aesthetics by how clear they are in representing a continuous variable: size, colour, transparency
Common Problems
- Using the
mpg
data set, make a plot of city milage against engine size. Map the variable class
to the aesthetic shape
. Is everything as you would expect?
- Type the following code into the console. Why do you recieve an error message?
ggplot(iris) +
geom_point(x = Sepal.Length, y = Petal.Length)
- Take a look at the
airquality
dataset. Type the following code into the console. Is the plot as you expected?
ggplot(airquality) +
geom_point(aes(x = Wind, y = Temp, col = Month))
- Why are the points in this plot not blue?
ggplot(mpg) +
geom_point(aes(x = displ, y = hwy, colour = 'blue'))
- What happens when you map a variable to multiple aesthetics (say colour and size)? (It’s okay to answer, “nothing”, to this question but make sure you verify that first!)
Facetting
Basic Faceting
(Taken form R4DS)
- What happens when you facet a continuous variable?
- What do the empty cells in a plot with
facet_grid(drv ~ cyl)
mean? How do they relate to this plot?
ggplot(mpg) +
geom_point(aes(x = drv, y = cyl))
- What plots does the following code make? What does the
.
do?
ggplot(mpg) +
geom_point(aes(x = displ, y = hwy)) +
facet_grid(drv ~ .)
ggplot(mpg) +
geom_point(aes(x = displ, y = hwy)) +
facet_grid(. ~ cyl)
- Take the first faceted plot from the presentation:
ggplot(mpg) +
geom_point(aes(x = displ, y = hwy)) +
facet_wrap(~ class, nrow = 2)
What are the advantages of faceting instead of the colour aesthetic? What are the disadvantages? How might the balance change if you had a larger data set?
- Read
?facet_wrap
. What does nrow
do? What does ncol
do? What other options control the layout of the individual panels? Why doesn’t facet_grid()
have nrow
and ncol
parameters?
- When using
facet_grid()
you should usually put the variable with more unique levels in the columns. Why?
Combining Facets with Aesthetics
- Create a scatter plot of petal length vs petal width using the
iris
dataset and facet by species
- Repeat the above plot whilst also colouring the species. Don’t forget to hide the colour legend
- Using the
mpg
dataset, plot hwy
vs cty
, map displ
to the size
aesthetic, map class
to point colour, and facet columns by cyl
and rows by drv
. This plot is ridiculous but it does demonstrate the flexibilty of ggplot2
Going Beyond
Labelling
- Run the following code. What does the extra
labs(...)
layer do?
ggplot(mpg) +
geom_point(aes(x = displ, y = hwy, colour = class)) +
labs(x = "Engine Displacment (litres)", y = "Highway Milage (miles/gallon)",
colour = "Car Type",
title = "A scatter plot of engine displacment vs highway milage",
subtitle = "Coloured by car type",
caption = "Source: EPA (http://fueleconomy.gov)")
- Use this to take the plot from the ‘Remaking plots’ section and beautify it
- Pick any plot of your choosing an give it appropriate axis labels, a title, and - if possible - a data source
Diamonds and Overplotting
- Have a look at the
diamonds
dataset
- Make a scatter plot of
price
against caret
(this may take a long time to run). Is this plot easy to read?
- How could you fix this problem? (perhaps you could manually set a certain aesthetic)
Explanatory and Response variables
- How do you decide which variable to map to the x-axis and which to plot to the y-axis?
- If you are unsure, web-search for the phrase “explanatory and response variables”
Positional Arguments
Begin with the following code
ggplot(mpg) +
geom_point(aes(x = displ, y = hwy, colour = factor(class)))
- Try removing
x =
and y =
from your geom_point
call. Does everything still work?
- Try removing
colour =
from your geom_point
call. Does everything still work?
- Take the original plot and specify the aesthetics in a different order, say
y
then colour
then x
. Does everything still work?
LS0tCnRpdGxlOiAiSW50byB0aGUgVGlkeXZlcnNlIgpzdWJ0aXRsZTogIlNlc3Npb24gT25lIEV4ZXJjaXNlcyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKUmVtZW1iZXIsIGJlZm9yZSB5b3UgY2FuIHVzZSB0aGUgdGlkeXZlcnNlLCB5b3UgbmVlZCB0byBsb2FkIHRoZSBwYWNrYWdlLgoKYGBge3IgbWVzc2FnZT1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKIyMgRmlyc3QgU3RlcHMKCiMjIyBNb3JlIHBsb3RzIHdpdGggdGhlIG1wZyBkYXRhc2V0CgooKipUYWtlbiBmb3JtIFI0RFMqKikKCjEuIFJ1biBgZ2dwbG90KGRhdGEgPSBtcGcpYC4gV2hhdCBkbyB5b3Ugc2VlPwoyLiBIb3cgbWFueSByb3dzIGFyZSBpbiBtcGc/IEhvdyBtYW55IGNvbHVtbnM/CjMuIFdoYXQgZG9lcyB0aGUgYGRydmAgdmFyaWFibGUgZGVzY3JpYmU/IFlvdSBtYXkgd2FudCB0byB1c2UgYD9tcGdgIHRvIGZpbmQgb3V0CjQuIE1ha2UgYSBzY2F0dGVyIHBsb3Qgb2YgYGh3eWAgdnMgYGN5bGAKNS4gV2hhdCBoYXBwZW5zIGlmIHlvdSBtYWtlIGEgc2NhdHRlciBwbG90IG9mIGBjbGFzc2AgdnMgYGRydmA/IFdoeSBpcyB0aGUgcGxvdCBub3QgdXNlZnVsPwoKIyMjIFBsb3RzIHdpdGggb3RoZXIgZGF0YXNldHMKCjEuIFRha2UgYSBsb29rIGF0IHRoZSBgaXJpc2AgZGF0YXNldC4gV2hhdCBhcmUgaXRzIGRpbWVuc2lvbnM/IFdoYXQgZG8gaXRzIGNvbHVtbnMgcmVwcmVzZW50PwoyLiBXaGF0IGFyZSB0aGUgcmFuZ2VzIG9mIGVhY2ggb2YgdGhlIG51bWVyaWMgY29sdW1ucy4gVGhlIGBzdW1tYXJ5KClgIGZ1bmN0aW9uIG1pZ2h0IGhlbHAgeW91IGhlcmUKMy4gTWFrZSBhIHBsb3Qgb2Ygc2VwYWwgd2lkdGggdnMgc2VwYWwgbGVuZ3RoLCBhbmQgc2V0IGFsbCBvZiB0aGUgcG9pbnRzIHRvIGJlIGdyZWVuCjQuIFJlcGVhdCB0aGUgcHJldmlvdXMgcGxvdCBidXQgY29sb3VyIGVhY2ggcG9pbnQgYnkgdGhlIHNwZWNpZXMgb2YgdGhlIGZsb3dlcgoKIyMjIFJlbWFraW5nIHBsb3RzCgoxLiBUYWtlIGEgbG9vayBhdCB0aGUgZmlyc3QgYW5kIGxhc3QgZmV3IHJvd3Mgb2YgdGhlIGBtdGNhcnNgIGRhdGFzZXQKMi4gQWNjZXNzIHRoZSBgY3lsYCBjb2x1bW4gb2YgdGhlIGRhdGFzZXQuIElzIHRoaXMgdmFyaWFibGUgY2F0ZWdvcmljYWwsIGRpc2NyZXRlLCBvciBjb250aW51b3VzPwozLiBXaGF0IHN0ZXBzIHdvdWxkIHlvdSBnbyBhYm91dCB0byByZW1ha2UgdGhlIGZvbGxvd2luZyBwbG90PwoKYGBge3IgZWNobz1GQUxTRX0KZ2dwbG90KG10Y2FycykgKwogIGdlb21fcG9pbnQoYWVzKHggPSBkaXNwLCB5ID0gaHAsIGNvbG91ciA9IGZhY3RvcihjeWwpKSkKYGBgCgojIyBNb3JlIEFlc3RoZXRpY3MgCgojIyMgU2l6ZSwgVHJhbnNwYXJlbmN5LCBhbmQgU2hhcGUKCjEuIFVzaW5nIHRoZSBgbXBnYCBkYXRhc2V0LCBtYWtlIGEgcGxvdCBvZiBjaXR5IG1pbGVhZ2UgdnMgaGlnaHdheSBtaWxlYWdlIHdoZXJlIHRoZSBzaXplIG9mIGVhY2ggcG9pbnQgaXMgZGV0ZXJtaW5lZCBieSBlbmdpbmUgc2l6ZSAoYGRpc3BsYCkKMi4gUGxvdCBzZXBhbCBsZW5ndGggdnMgc2VwYWwgd2lkdGggdXNpbmcgdGhlIGBpcmlzYCBkYXRhc2V0IGFuZCBjb250cm9sIHRoZSB0cmFuc3BhcmVuY3kgKGBhbHBoYWApIG9mIGVhY2ggcG9pbnQgdXNpbmcgdGhlIGBzcGVjaWVzYCB2YXJpYWJsZS4KMy4gSGF2ZSBhIHBsYXkgd2l0aCB0aGUgYE9yYW5nZWAgZGF0YSBzZXQgKG5vdGUgdGhlIGNhcGl0YWwgJ08nKS4gTWFrZSBhIHNjYXR0ZXIgcGxvdCBvZiBjaXJjdW1mZXJlbmNlIGFnYWluc3QgYWdlIHdoZXJlIHRoZSBzaGFwZSBvZiBlYWNoIHBvaW50IGlzIGRldGVybWluZWQgYnkgd2hpY2ggdHJlZSB0aGUgb2JzZXJ2YXRpb24gYmVsb25ncyB0bwo0LiBSZW1ha2UgdGhlIHN0YW5kYXJkIGBod3lgIHZzIGBkaXNwbGAgcGxvdCB1c2luZyB0aGUgYG1wZ2AgZGF0YSBzZXQgYnV0IG1ha2UgYWxsIG9mIHRoZSBwb2ludHMgaG9sbG93IGRpYW1vbmRzLiBIb3cgYWJvdXQgc29saWQgdHJpYW5nbGVzPwoKIyMjIENob29zaW5nIEFwcHJvcHJpYXRlIEFlc3RoZXRpY3MKCigqKlExLzIgZm9ybSBSNERTKiopCgoxLiBXaGljaCB2YXJpYWJsZXMgaW4gYG1wZ2AgYXJlIGNhdGVnb3JpY2FsPyBXaGljaCBhcmUgY29udGludW91cy9kaXNjcmV0ZT8gKFRoZSBkYXRhIHNldCBoZWxwIGZpbGUgbWF5IGJlIG9mIHVzZSkKMi4gTWFwIGEgY29udGludW91cyB2YXJpYWJsZSB0byBjb2xvdXIsIHNpemUsIGFuZCBzaGFwZS4gSG93IGRvZXMgdGhpcyBkaWZmZXIgZnJvbSB3aGVuIHlvdSBtYXAgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZT8KMy4gUGxvdCB0aGUgc3RhbmRhcmQgYGh3eWAgdnMgYGRpc3BsYCBncmFwaCB1c2luZyBgbXBnYCBhbmQgbWFwIHRoZSB2YXJpYWJsZSBgY2xhc3NgIHRvIHRoZSBgc2l6ZWAgYWVzdGhldGljLiBXYXMgdGhpcyBhIGdvb2QgaWRlYT8KNC4gSGF2ZSBhIGRpc2N1c3Npb24gd2l0aCBhIHBhcnRuZXIgb3IgdGhpbmsgZm9yIHlvdXJzZWxmOiBXaGljaCBvZiB0aGUgYWVzdGhldGljcyB5b3Uga25vdyBhcmUgdGhlIGNsZWFyZXN0IGZvciBkaXNwbGF5aW5nIGNhdGVnb3JpY2FsIGRhdGEgYW5kIHdoaWNoIGFyZSBiZXN0IGZvciBjb250aW51b3VzPyAKNS4gSW4geW91ciBvd24gb3Bpbmlvbiwgb3JkZXIgdGhlIGZvbGxvd2luZyBhZXN0aGV0aWNzIGJ5IGhvdyBjbGVhciB0aGV5IGFyZSBpbiByZXByZXNlbnRpbmcgYSBjb250aW51b3VzIHZhcmlhYmxlOiBzaXplLCBjb2xvdXIsIHRyYW5zcGFyZW5jeQoKIyMjIENvbW1vbiBQcm9ibGVtcwoKMS4gVXNpbmcgdGhlIGBtcGdgIGRhdGEgc2V0LCBtYWtlIGEgcGxvdCBvZiBjaXR5IG1pbGFnZSBhZ2FpbnN0IGVuZ2luZSBzaXplLiBNYXAgdGhlIHZhcmlhYmxlIGBjbGFzc2AgdG8gdGhlIGFlc3RoZXRpYyBgc2hhcGVgLiBJcyBldmVyeXRoaW5nIGFzIHlvdSB3b3VsZCBleHBlY3Q/CjIuIFR5cGUgdGhlIGZvbGxvd2luZyBjb2RlIGludG8gdGhlIGNvbnNvbGUuIFdoeSBkbyB5b3UgcmVjaWV2ZSBhbiBlcnJvciBtZXNzYWdlPwoKYGBge3IgZXZhbCA9IEZBTFNFfQpnZ3Bsb3QoaXJpcykgKwogIGdlb21fcG9pbnQoeCA9IFNlcGFsLkxlbmd0aCwgeSA9IFBldGFsLkxlbmd0aCkKYGBgCgozLiBUYWtlIGEgbG9vayBhdCB0aGUgYGFpcnF1YWxpdHlgIGRhdGFzZXQuIFR5cGUgdGhlIGZvbGxvd2luZyBjb2RlIGludG8gdGhlIGNvbnNvbGUuIElzIHRoZSBwbG90IGFzIHlvdSBleHBlY3RlZD8KCmBgYHtyIGV2YWwgPSBGQUxTRX0KZ2dwbG90KGFpcnF1YWxpdHkpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gV2luZCwgeSA9IFRlbXAsIGNvbCA9IE1vbnRoKSkKYGBgCgo0LiBXaHkgYXJlIHRoZSBwb2ludHMgaW4gdGhpcyBwbG90IG5vdCBibHVlPwoKYGBge3IgbWVzc2FnZSA9IEZBTFNFfQpnZ3Bsb3QobXBnKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBjb2xvdXIgPSAnYmx1ZScpKQpgYGAKCjUuIFdoYXQgaGFwcGVucyB3aGVuIHlvdSBtYXAgYSB2YXJpYWJsZSB0byBtdWx0aXBsZSBhZXN0aGV0aWNzIChzYXkgY29sb3VyIGFuZCBzaXplKT8gKEl0J3Mgb2theSB0byBhbnN3ZXIsICJub3RoaW5nIiwgdG8gdGhpcyBxdWVzdGlvbiBidXQgbWFrZSBzdXJlIHlvdSB2ZXJpZnkgdGhhdCBmaXJzdCEpCgojIyBGYWNldHRpbmcKCiMjIyBCYXNpYyBGYWNldGluZwoKKCoqVGFrZW4gZm9ybSBSNERTKiopCgoxLiBXaGF0IGhhcHBlbnMgd2hlbiB5b3UgZmFjZXQgYSBjb250aW51b3VzIHZhcmlhYmxlPwoyLiBXaGF0IGRvIHRoZSBlbXB0eSBjZWxscyBpbiBhIHBsb3Qgd2l0aCBgZmFjZXRfZ3JpZChkcnYgfiBjeWwpYCBtZWFuPyBIb3cgZG8gdGhleSByZWxhdGUgdG8gdGhpcyBwbG90PwoKYGBge3IgZXZhbCA9IEZBTFNFfQpnZ3Bsb3QobXBnKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGRydiwgeSA9IGN5bCkpCmBgYAoKMy4gV2hhdCBwbG90cyBkb2VzIHRoZSBmb2xsb3dpbmcgY29kZSBtYWtlPyBXaGF0IGRvZXMgdGhlIGAuYCBkbz8KCmBgYHtyIGV2YWwgPSBGQUxTRX0KZ2dwbG90KG1wZykgKwogIGdlb21fcG9pbnQoYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpICsKICBmYWNldF9ncmlkKGRydiB+IC4pCgpnZ3Bsb3QobXBnKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKwogIGZhY2V0X2dyaWQoLiB+IGN5bCkKYGBgCgo0LiBUYWtlIHRoZSBmaXJzdCBmYWNldGVkIHBsb3QgZnJvbSB0aGUgcHJlc2VudGF0aW9uOgoKYGBge3IgZXZhbCA9IEZBTFNFfQpnZ3Bsb3QobXBnKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKwogIGZhY2V0X3dyYXAofiBjbGFzcywgbnJvdyA9IDIpCmBgYAoKV2hhdCBhcmUgdGhlIGFkdmFudGFnZXMgb2YgZmFjZXRpbmcgaW5zdGVhZCBvZiB0aGUgY29sb3VyIGFlc3RoZXRpYz8gV2hhdCBhcmUgdGhlIGRpc2FkdmFudGFnZXM/IEhvdyBtaWdodCB0aGUgYmFsYW5jZSBjaGFuZ2UgaWYgeW91IGhhZCBhIGxhcmdlciBkYXRhIHNldD8KCjUuIFJlYWQgYD9mYWNldF93cmFwYC4gV2hhdCBkb2VzIGBucm93YCBkbz8gV2hhdCBkb2VzIGBuY29sYCBkbz8gV2hhdCBvdGhlciBvcHRpb25zIGNvbnRyb2wgdGhlIGxheW91dCBvZiB0aGUgaW5kaXZpZHVhbCBwYW5lbHM/IFdoeSBkb2Vzbid0IGBmYWNldF9ncmlkKClgIGhhdmUgYG5yb3dgIGFuZCBgbmNvbGAgcGFyYW1ldGVycz8KNi4gV2hlbiB1c2luZyBgZmFjZXRfZ3JpZCgpYCB5b3Ugc2hvdWxkIHVzdWFsbHkgcHV0IHRoZSB2YXJpYWJsZSB3aXRoIG1vcmUgdW5pcXVlIGxldmVscyBpbiB0aGUgY29sdW1ucy4gV2h5PwoKCiMjIyBDb21iaW5pbmcgRmFjZXRzIHdpdGggQWVzdGhldGljcwoKMS4gQ3JlYXRlIGEgc2NhdHRlciBwbG90IG9mIHBldGFsIGxlbmd0aCB2cyBwZXRhbCB3aWR0aCB1c2luZyB0aGUgYGlyaXNgIGRhdGFzZXQgYW5kIGZhY2V0IGJ5IHNwZWNpZXMKMi4gUmVwZWF0IHRoZSBhYm92ZSBwbG90IHdoaWxzdCBhbHNvIGNvbG91cmluZyB0aGUgc3BlY2llcy4gRG9uJ3QgZm9yZ2V0IHRvIGhpZGUgdGhlIGNvbG91ciBsZWdlbmQKMy4gVXNpbmcgdGhlIGBtcGdgIGRhdGFzZXQsIHBsb3QgYGh3eWAgdnMgYGN0eWAsIG1hcCBgZGlzcGxgIHRvIHRoZSBgc2l6ZWAgYWVzdGhldGljLCBtYXAgYGNsYXNzYCB0byBwb2ludCBjb2xvdXIsIGFuZCBmYWNldCBjb2x1bW5zIGJ5IGBjeWxgIGFuZCByb3dzIGJ5IGBkcnZgLiBUaGlzIHBsb3QgaXMgcmlkaWN1bG91cyBidXQgaXQgZG9lcyBkZW1vbnN0cmF0ZSB0aGUgZmxleGliaWx0eSBvZiBgZ2dwbG90MmAKCiMjIEdvaW5nIEJleW9uZAoKIyMjIExhYmVsbGluZwoKMS4gUnVuIHRoZSBmb2xsb3dpbmcgY29kZS4gV2hhdCBkb2VzIHRoZSBleHRyYSBgbGFicyguLi4pYCBsYXllciBkbz8KCmBgYHtyIGV2YWwgPSBGQUxTRX0KZ2dwbG90KG1wZykgKwogIGdlb21fcG9pbnQoYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgY29sb3VyID0gY2xhc3MpKSArCiAgbGFicyh4ID0gIkVuZ2luZSBEaXNwbGFjbWVudCAobGl0cmVzKSIsIHkgPSAiSGlnaHdheSBNaWxhZ2UgKG1pbGVzL2dhbGxvbikiLAogICAgICAgY29sb3VyID0gIkNhciBUeXBlIiwKICAgICAgIHRpdGxlID0gIkEgc2NhdHRlciBwbG90IG9mIGVuZ2luZSBkaXNwbGFjbWVudCB2cyBoaWdod2F5IG1pbGFnZSIsCiAgICAgICBzdWJ0aXRsZSA9ICJDb2xvdXJlZCBieSBjYXIgdHlwZSIsCiAgICAgICBjYXB0aW9uID0gIlNvdXJjZTogRVBBIChodHRwOi8vZnVlbGVjb25vbXkuZ292KSIpCmBgYAoKMi4gVXNlIHRoaXMgdG8gdGFrZSB0aGUgcGxvdCBmcm9tIHRoZSAnUmVtYWtpbmcgcGxvdHMnIHNlY3Rpb24gYW5kIGJlYXV0aWZ5IGl0CjMuIFBpY2sgYW55IHBsb3Qgb2YgeW91ciBjaG9vc2luZyBhbiBnaXZlIGl0IGFwcHJvcHJpYXRlIGF4aXMgbGFiZWxzLCBhIHRpdGxlLCBhbmQgLSBpZiBwb3NzaWJsZSAtIGEgZGF0YSBzb3VyY2UKCiMjIyBEaWFtb25kcyBhbmQgT3ZlcnBsb3R0aW5nCgoxLiBIYXZlIGEgbG9vayBhdCB0aGUgYGRpYW1vbmRzYCBkYXRhc2V0CjIuIE1ha2UgYSBzY2F0dGVyIHBsb3Qgb2YgYHByaWNlYCBhZ2FpbnN0IGBjYXJldGAgKHRoaXMgbWF5IHRha2UgYSBsb25nIHRpbWUgdG8gcnVuKS4gSXMgdGhpcyBwbG90IGVhc3kgdG8gcmVhZD8KMy4gSG93IGNvdWxkIHlvdSBmaXggdGhpcyBwcm9ibGVtPyAocGVyaGFwcyB5b3UgY291bGQgbWFudWFsbHkgc2V0IGEgY2VydGFpbiBhZXN0aGV0aWMpCgojIyMgRXhwbGFuYXRvcnkgYW5kIFJlc3BvbnNlIHZhcmlhYmxlcwoKMS4gSG93IGRvIHlvdSBkZWNpZGUgd2hpY2ggdmFyaWFibGUgdG8gbWFwIHRvIHRoZSB4LWF4aXMgYW5kIHdoaWNoIHRvIHBsb3QgdG8gdGhlIHktYXhpcz8KMi4gSWYgeW91IGFyZSB1bnN1cmUsIHdlYi1zZWFyY2ggZm9yIHRoZSBwaHJhc2UgImV4cGxhbmF0b3J5IGFuZCByZXNwb25zZSB2YXJpYWJsZXMiCgojIyMgUG9zaXRpb25hbCBBcmd1bWVudHMKCkJlZ2luIHdpdGggdGhlIGZvbGxvd2luZyBjb2RlCgpgYGB7ciBldmFsIEZBTFNFfQpnZ3Bsb3QobXBnKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBjb2xvdXIgPSBmYWN0b3IoY2xhc3MpKSkKYGBgCgoxLiBUcnkgcmVtb3ZpbmcgYHggPSBgIGFuZCBgeSA9IGAgZnJvbSB5b3VyIGBnZW9tX3BvaW50YCBjYWxsLiBEb2VzIGV2ZXJ5dGhpbmcgc3RpbGwgd29yaz8KMi4gVHJ5IHJlbW92aW5nIGBjb2xvdXIgPSBgIGZyb20geW91ciBgZ2VvbV9wb2ludGAgY2FsbC4gRG9lcyBldmVyeXRoaW5nIHN0aWxsIHdvcms/CjMuIFRha2UgdGhlIG9yaWdpbmFsIHBsb3QgYW5kIHNwZWNpZnkgdGhlIGFlc3RoZXRpY3MgaW4gYSBkaWZmZXJlbnQgb3JkZXIsIHNheSBgeWAgdGhlbiBgY29sb3VyYCB0aGVuIGB4YC4gRG9lcyBldmVyeXRoaW5nIHN0aWxsIHdvcms/Cg==