Note: These are exercises from Wickham (2016, 2nd ed).

Set up

library(ggplot2)

For viewing the data set, type mpg. To see them a bit more comfortably, use View(mpg) (note the capital V).

mpg

Examples and exercises Part 1

Let’s look at the components for creating a chart with ggplot2, using a scatterplot as the example.

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

The pattern shown here is fundamental for gglplot: * data and aesthetic mappings are provided in ggplot(), then * layers are added with +.

A short version of the above is

ggplot(mpg, aes(displ, hwy)) + 
  geom_point()

This produces exactly the same output as the longer version above.

Exercises

The solutions are provided by running the code. But make sure you try first to figure things out for yourself. You can run commands in the Console, or by creating an R Script, typing commands, marking with the mouse what you want to execute, and click ‘’’Run’’’.

  1. How would you plot the relationship between cty, the average city mileage, and hwy, the averabe highway mileage? How would you describe this relationship?
  2. Describe the data, aesthetic mappings, and and layers used for each of the following plots. Sometimes you will have to guess, but common sense should help. Try to imagine what the graph will look like before running the command.
    • ggplot(mpg, aes(cty, hwy)) + geom_point()
    • ggplot(diamonds, aes(carat, price)) + geom_point()
    • ggplot(economics, aes(date, unemploy)) + geom_line()
    • ggplot(mpg, aes(cty)) + geom_histogram()

Solutions

Exercise 1

  1. How would you plot the relationship between cty, the average city mileage, and hwy, the averabe highway mileage? How would you describe this relationship?
ggplot(mpg, aes(cty, hwy)) + 
  geom_point()

The point here to make is that this very linear relationship is of course caused by another factor, motor size. That is to say, the description “the higher/lower cty, the higher/lower hwy” is to taken as strictly descriptive.

Exercise 2

ggplot(mpg, aes(cty, hwy)) + geom_point()
ggplot(diamonds, aes(carat, price)) + geom_point()
ggplot(economics, aes(date, unemploy)) + geom_line()
ggplot(mpg, aes(cty)) + geom_histogram()

Examples and exercises Part 2

Aesthetic attributes

To add variables to a plot, we need to map them onto aesthetics. In two dimensions, we can use the x and the y axis, as shown in the scatterplots above. For adding a third (or fourth, etc.) variable we need to use aesthetics such as shape, color, and size. (In the example class the type of car, such as pickup, drv is the drivetain, such as forward (f), rear (r) or 4-wheel (4) drive, and cyl is the number of cylinders).

As always, try to imagine what the plot in each case will look before you click the Run Current Chunk button.

ggplot(mpg, aes(displ, hwy, colour = class)) + 
  geom_point()
ggplot(mpg, aes(displ, hwy, shape = drv)) + 
  geom_point()
ggplot(mpg, aes(displ, hwy, size = cyl)) + 
  geom_point()

Do you find the scale provided by ggplot useful in these instances? You probably do, because they allow you to translate the aestethics (colour, size, shape) back into values of the variable. Ggplot is also pretty smart about the choice of scales, but of course these defaults can all be overridden.

For setting the colour to a specific value, such as “blue”, the colour needs to be outside of the aes() expression, in a layer (remember, layers are described folling the + sign):

ggplot(mpg, aes(displ, hwy)) + geom_point(colour = "blue")

Question: Ggplot does not provide a scale (a legend) with this graph. Why? Is this a bug? Should you attempt to provide one manually?

Exercises Part 2

From Whickham 2.4.1, page 16. Formulate them in a more closed format, so that students get at least one task that is concrete, before exploring their own combinations - which definitely should be encouraged.

  1. What happens when you map colour to highway mileage (hwy), say, a continuos variable?
  2. What happens when you map shape to hwy (or other continuous variables)? Why?
  3. What happens with you use more than one aesthetic in a plot?
  4. What happens when you map trans (values are “auto”, “manual” etc.) to shape? Why?
  5. How is drive train (drv, with values f, r, 4) related to fuel economy? How is it related to engine size and class?

Solutions for exercises Part 2

Go here – Dalal?

Exercises Part 3

Examples

A boxplot, or box-and-whiskers plot, summarizes a distribution of scores for variable

ggplot(mpg, aes(drv, hwy)) + 
  geom_boxplot()

Histograms and Frequency Polygons show the distribution of scores of a single numeric variable.

ggplot(mpg, aes(hwy)) + 
  geom_histogram()
ggplot(mpg, aes(hwy)) + 
  geom_freqpoly()

Note that the y axis shows counts, that is, frequencies, not values (scores).

A bar chart is the analog of a histogram, but for discrete variables

ggplot(mpg, aes(manufacturer)) + 
  geom_bar()

As a final example, we look at time line plots. Here, the x-axis shows time (e.g, years), and the y axis shows measurements for numeric variables, or counts (frequencies) for categorical data. We use the economics data set, which contains basic economy data for the US, such as unemployment (unemploy) numbers, over years, for the next example.

ggplot(economics, aes(date, unemploy / pop)) +
  geom_line()

Question: How did we overcome the problem that the orginal data set, economics, does not contain values of the unemployment rate directly, but only the number of unemployed people, and the population size?

And to show just one example of overwriting defaults, let’s look at the labels for the axis. While ‘date’ is clear enough, the label ‘unemploy/pop’ label is a bit mysterious. Let’s change this to “unemployment rate”

ggplot(economics, aes(date, unemploy / pop)) +
  geom_line() + 
  ylab("unemployment rate")

Exercises Part 3

Go here

Solutions for Exercises Part 3

Go here.

LS0tCnRpdGxlOiAnTW9kdWxlIDIgRXhlcmNpc2VzOiBCYXNpYyBncmFwaGljcyB3aXRoIGdncGxvdCcKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OiBkZWZhdWx0CiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQpOb3RlOiBUaGVzZSBhcmUgZXhlcmNpc2VzIGZyb20gV2lja2hhbSAoMjAxNiwgMm5kIGVkKS4KCiMjIyBTZXQgdXAKCmBgYHtyIGxvYWQgbGlicmFyeX0KbGlicmFyeShnZ3Bsb3QyKQpgYGAKRm9yIHZpZXdpbmcgdGhlIGRhdGEgc2V0LCB0eXBlIGBtcGdgLiBUbyBzZWUgdGhlbSBhIGJpdCBtb3JlIGNvbWZvcnRhYmx5LCB1c2UgYFZpZXcobXBnKWAgKG5vdGUgdGhlIGNhcGl0YWwgVikuIAoKYGBge3J9Cm1wZwpgYGAKCgojIyBFeGFtcGxlcyBhbmQgZXhlcmNpc2VzIFBhcnQgMQpMZXQncyBsb29rIGF0IHRoZSBjb21wb25lbnRzIGZvciBjcmVhdGluZyBhIGNoYXJ0IHdpdGggZ2dwbG90MiwgdXNpbmcgYSBzY2F0dGVycGxvdCBhcyB0aGUgZXhhbXBsZS4KYGBge3J9CmdncGxvdChtcGcsIGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArCiAgZ2VvbV9wb2ludCgpCmBgYAoqIG1wZyBpcyB0aGUgZGF0YSBzZXQgdGhhdCBjb21lcyB3aXRoIGdncGxvdAoqIEFlc3RoZXRpYyBtYXBwaW5nczogZW5naW5lIGRpc3BsYWNlbWVudCBpcyBtYXBwZWQgdG8geCBheGlzLCBtaWxlYWdlIChod3kpIHRvIHRoZSB5IGF4aXMKKiBBIGxheWVyIHdpdGggcG9pbnRzIGFzIHRoZSBnZW9tZXRyeSBpcyBhZGRlZAoKVGhlICoqcGF0dGVybioqIHNob3duIGhlcmUgaXMgZnVuZGFtZW50YWwgZm9yIGdnbHBsb3Q6IAoqIGRhdGEgYW5kIGFlc3RoZXRpYyBtYXBwaW5ncyBhcmUgcHJvdmlkZWQgaW4gZ2dwbG90KCksIHRoZW4KKiBsYXllcnMgYXJlIGFkZGVkIHdpdGggKy4gCgpBIHNob3J0IHZlcnNpb24gb2YgdGhlIGFib3ZlIGlzIApgYGB7cn0KZ2dwbG90KG1wZywgYWVzKGRpc3BsLCBod3kpKSArIAogIGdlb21fcG9pbnQoKQpgYGAKVGhpcyBwcm9kdWNlcyBleGFjdGx5IHRoZSBzYW1lIG91dHB1dCBhcyB0aGUgbG9uZ2VyIHZlcnNpb24gYWJvdmUuIAoKIyMjIEV4ZXJjaXNlcwpUaGUgc29sdXRpb25zIGFyZSBwcm92aWRlZCBieSBydW5uaW5nIHRoZSBjb2RlLiBCdXQgbWFrZSBzdXJlIHlvdSB0cnkgZmlyc3QgdG8gZmlndXJlIHRoaW5ncyBvdXQgZm9yIHlvdXJzZWxmLiBZb3UgY2FuIHJ1biBjb21tYW5kcyBpbiB0aGUgQ29uc29sZSwgb3IgYnkgY3JlYXRpbmcgYW4gUiBTY3JpcHQsIHR5cGluZyBjb21tYW5kcywgbWFya2luZyB3aXRoIHRoZSBtb3VzZSB3aGF0IHlvdSB3YW50IHRvIGV4ZWN1dGUsIGFuZCBjbGljayAnJydSdW4nJycuIAoKMS4gSG93IHdvdWxkIHlvdSBwbG90IHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBgY3R5YCwgdGhlIGF2ZXJhZ2UgY2l0eSBtaWxlYWdlLCAgYW5kIGBod3lgLCB0aGUgYXZlcmFiZSBoaWdod2F5IG1pbGVhZ2U/IEhvdyB3b3VsZCB5b3UgZGVzY3JpYmUgdGhpcyByZWxhdGlvbnNoaXA/CjIuIERlc2NyaWJlIHRoZSBkYXRhLCBhZXN0aGV0aWMgbWFwcGluZ3MsIGFuZCBhbmQgbGF5ZXJzIHVzZWQgZm9yIGVhY2ggb2YgdGhlIGZvbGxvd2luZyBwbG90cy4gU29tZXRpbWVzIHlvdSB3aWxsIGhhdmUgdG8gZ3Vlc3MsIGJ1dCBjb21tb24gc2Vuc2Ugc2hvdWxkIGhlbHAuIFRyeSB0byBpbWFnaW5lIHdoYXQgdGhlIGdyYXBoIHdpbGwgbG9vayBsaWtlIGJlZm9yZSBydW5uaW5nIHRoZSBjb21tYW5kLiAgICAKICAgICArIGdncGxvdChtcGcsIGFlcyhjdHksIGh3eSkpICsgZ2VvbV9wb2ludCgpCiAgICAgKyBnZ3Bsb3QoZGlhbW9uZHMsIGFlcyhjYXJhdCwgcHJpY2UpKSArIGdlb21fcG9pbnQoKQogICAgICsgZ2dwbG90KGVjb25vbWljcywgYWVzKGRhdGUsIHVuZW1wbG95KSkgKyBnZW9tX2xpbmUoKQogICAgICsgZ2dwbG90KG1wZywgYWVzKGN0eSkpICsgZ2VvbV9oaXN0b2dyYW0oKQoKLS0tLS0KIyMjIFNvbHV0aW9ucwojIyMjIEV4ZXJjaXNlIDEKCjEuIEhvdyB3b3VsZCB5b3UgcGxvdCB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gYGN0eWAsIHRoZSBhdmVyYWdlIGNpdHkgbWlsZWFnZSwgIGFuZCBgaHd5YCwgdGhlIGF2ZXJhYmUgaGlnaHdheSBtaWxlYWdlPyBIb3cgd291bGQgeW91IGRlc2NyaWJlIHRoaXMgcmVsYXRpb25zaGlwPyAKCmBgYHtyfQpnZ3Bsb3QobXBnLCBhZXMoY3R5LCBod3kpKSArIAogIGdlb21fcG9pbnQoKQpgYGAKVGhlIHBvaW50IGhlcmUgdG8gbWFrZSBpcyB0aGF0IHRoaXMgdmVyeSBsaW5lYXIgcmVsYXRpb25zaGlwIGlzIG9mIGNvdXJzZSBjYXVzZWQgYnkgYW5vdGhlciBmYWN0b3IsIG1vdG9yIHNpemUuIFRoYXQgaXMgdG8gc2F5LCB0aGUgZGVzY3JpcHRpb24gInRoZSBoaWdoZXIvbG93ZXIgY3R5LCB0aGUgaGlnaGVyL2xvd2VyIGh3eSIgaXMgdG8gdGFrZW4gYXMgc3RyaWN0bHkgZGVzY3JpcHRpdmUuCgojIyMjIEV4ZXJjaXNlIDIKYGBge3J9CmdncGxvdChtcGcsIGFlcyhjdHksIGh3eSkpICsgZ2VvbV9wb2ludCgpCmBgYAoKYGBge3J9CmdncGxvdChkaWFtb25kcywgYWVzKGNhcmF0LCBwcmljZSkpICsgZ2VvbV9wb2ludCgpCmBgYAoKYGBge3J9CmdncGxvdChlY29ub21pY3MsIGFlcyhkYXRlLCB1bmVtcGxveSkpICsgZ2VvbV9saW5lKCkKYGBgCgpgYGB7cn0KZ2dwbG90KG1wZywgYWVzKGN0eSkpICsgZ2VvbV9oaXN0b2dyYW0oKQpgYGAKCgojIyBFeGFtcGxlcyBhbmQgZXhlcmNpc2VzIFBhcnQgMgoKIyMjIEFlc3RoZXRpYyBhdHRyaWJ1dGVzCgpUbyBhZGQgdmFyaWFibGVzIHRvIGEgcGxvdCwgd2UgbmVlZCB0byBtYXAgdGhlbSBvbnRvIGFlc3RoZXRpY3MuIEluIHR3byBkaW1lbnNpb25zLCB3ZSBjYW4gdXNlIHRoZSB4IGFuZCB0aGUgeSBheGlzLCBhcyBzaG93biBpbiB0aGUgc2NhdHRlcnBsb3RzIGFib3ZlLiBGb3IgYWRkaW5nIGEgdGhpcmQgKG9yIGZvdXJ0aCwgZXRjLikgdmFyaWFibGUgd2UgbmVlZCB0byB1c2UgYWVzdGhldGljcyBzdWNoIGFzIHNoYXBlLCBjb2xvciwgYW5kIHNpemUuIChJbiB0aGUgZXhhbXBsZSBjbGFzcyB0aGUgdHlwZSBvZiBjYXIsIHN1Y2ggYXMgcGlja3VwLCBkcnYgaXMgdGhlIGRyaXZldGFpbiwgc3VjaCBhcyBmb3J3YXJkIChmKSwgcmVhciAocikgb3IgNC13aGVlbCAoNCkgZHJpdmUsIGFuZCBjeWwgaXMgdGhlIG51bWJlciBvZiBjeWxpbmRlcnMpLgoKQXMgYWx3YXlzLCB0cnkgdG8gaW1hZ2luZSB3aGF0IHRoZSBwbG90IGluIGVhY2ggY2FzZSB3aWxsIGxvb2sgYmVmb3JlIHlvdSBjbGljayB0aGUgYFJ1biBDdXJyZW50IENodW5rYCBidXR0b24uIAoKYGBge3J9CmdncGxvdChtcGcsIGFlcyhkaXNwbCwgaHd5LCBjb2xvdXIgPSBjbGFzcykpICsgCiAgZ2VvbV9wb2ludCgpCmdncGxvdChtcGcsIGFlcyhkaXNwbCwgaHd5LCBzaGFwZSA9IGRydikpICsgCiAgZ2VvbV9wb2ludCgpCmdncGxvdChtcGcsIGFlcyhkaXNwbCwgaHd5LCBzaXplID0gY3lsKSkgKyAKICBnZW9tX3BvaW50KCkKYGBgCkRvIHlvdSBmaW5kIHRoZSBzY2FsZSBwcm92aWRlZCBieSBnZ3Bsb3QgdXNlZnVsIGluIHRoZXNlIGluc3RhbmNlcz8gWW91IHByb2JhYmx5IGRvLCBiZWNhdXNlIHRoZXkgYWxsb3cgeW91IHRvIHRyYW5zbGF0ZSB0aGUgYWVzdGV0aGljcyAoY29sb3VyLCBzaXplLCBzaGFwZSkgYmFjayBpbnRvIHZhbHVlcyBvZiB0aGUgdmFyaWFibGUuIEdncGxvdCBpcyBhbHNvIHByZXR0eSBzbWFydCBhYm91dCB0aGUgY2hvaWNlIG9mIHNjYWxlcywgYnV0IG9mIGNvdXJzZSB0aGVzZSBkZWZhdWx0cyBjYW4gYWxsIGJlIG92ZXJyaWRkZW4uIAoKRm9yIHNldHRpbmcgdGhlIGNvbG91ciB0byBhIHNwZWNpZmljIHZhbHVlLCBzdWNoIGFzICJibHVlIiwgdGhlIGNvbG91ciBuZWVkcyB0byBiZSBvdXRzaWRlIG9mIHRoZSBgYWVzKClgIGV4cHJlc3Npb24sIGluIGEgbGF5ZXIgKHJlbWVtYmVyLCBsYXllcnMgYXJlIGRlc2NyaWJlZCBmb2xsaW5nIHRoZSBgK2Agc2lnbik6IAoKYGBge3J9CmdncGxvdChtcGcsIGFlcyhkaXNwbCwgaHd5KSkgKyBnZW9tX3BvaW50KGNvbG91ciA9ICJibHVlIikKYGBgCioqUXVlc3Rpb246KiogR2dwbG90IGRvZXMgbm90IHByb3ZpZGUgYSBzY2FsZSAoYSBsZWdlbmQpICB3aXRoIHRoaXMgZ3JhcGguIFdoeT8gSXMgdGhpcyBhIGJ1Zz8gU2hvdWxkIHlvdSBhdHRlbXB0IHRvIHByb3ZpZGUgb25lIG1hbnVhbGx5PyAKCiMjIyBFeGVyY2lzZXMgUGFydCAyCgpGcm9tIFdoaWNraGFtIDIuNC4xLCBwYWdlIDE2LiBGb3JtdWxhdGUgdGhlbSBpbiBhIG1vcmUgY2xvc2VkIGZvcm1hdCwgc28gdGhhdCBzdHVkZW50cyBnZXQgYXQgbGVhc3Qgb25lIHRhc2sgdGhhdCBpcyBjb25jcmV0ZSwgYmVmb3JlIGV4cGxvcmluZyB0aGVpciBvd24gY29tYmluYXRpb25zIC0gd2hpY2ggZGVmaW5pdGVseSBzaG91bGQgYmUgZW5jb3VyYWdlZC4gCgoxLiBXaGF0IGhhcHBlbnMgd2hlbiB5b3UgbWFwIGNvbG91ciB0byBoaWdod2F5IG1pbGVhZ2UgKGh3eSksIHNheSwgYSBjb250aW51b3MgdmFyaWFibGU/IAoyLiBXaGF0IGhhcHBlbnMgd2hlbiB5b3UgbWFwIHNoYXBlIHRvIGh3eSAob3Igb3RoZXIgY29udGludW91cyB2YXJpYWJsZXMpPyBXaHk/CjMuIFdoYXQgaGFwcGVucyB3aXRoIHlvdSB1c2UgbW9yZSB0aGFuIG9uZSBhZXN0aGV0aWMgaW4gYSBwbG90PyAKMy4gV2hhdCBoYXBwZW5zIHdoZW4geW91IG1hcCB0cmFucyAodmFsdWVzIGFyZSAiYXV0byIsICJtYW51YWwiIGV0Yy4pIHRvIHNoYXBlPyBXaHk/IAo0LiBIb3cgaXMgZHJpdmUgdHJhaW4gKGRydiwgd2l0aCB2YWx1ZXMgZiwgciwgNCkgcmVsYXRlZCB0byBmdWVsIGVjb25vbXk/IEhvdyBpcyBpdCByZWxhdGVkIHRvIGVuZ2luZSBzaXplIGFuZCBjbGFzcz8gCgojIyMgU29sdXRpb25zIGZvciBleGVyY2lzZXMgUGFydCAyCgpHbyBoZXJlIC0tIERhbGFsPwoKIyMgRXhlcmNpc2VzIFBhcnQgMwoKIyMjIEV4YW1wbGVzCgpBICoqYm94cGxvdCoqLCBvciBib3gtYW5kLXdoaXNrZXJzIHBsb3QsIHN1bW1hcml6ZXMgYSBkaXN0cmlidXRpb24gb2Ygc2NvcmVzIGZvciB2YXJpYWJsZQoKYGBge3J9CmdncGxvdChtcGcsIGFlcyhkcnYsIGh3eSkpICsgCiAgZ2VvbV9ib3hwbG90KCkKYGBgCgoqKkhpc3RvZ3JhbXMqKiBhbmQgKipGcmVxdWVuY3kgUG9seWdvbnMqKiBzaG93IHRoZSBkaXN0cmlidXRpb24gb2Ygc2NvcmVzIG9mIGEgc2luZ2xlIG51bWVyaWMgdmFyaWFibGUuCgpgYGB7cn0KZ2dwbG90KG1wZywgYWVzKGh3eSkpICsgCiAgZ2VvbV9oaXN0b2dyYW0oKQpnZ3Bsb3QobXBnLCBhZXMoaHd5KSkgKyAKICBnZW9tX2ZyZXFwb2x5KCkKYGBgCgpOb3RlIHRoYXQgdGhlIHkgYXhpcyBzaG93cyAqY291bnRzKiwgdGhhdCBpcywgZnJlcXVlbmNpZXMsICAqbm90IHZhbHVlcyogKHNjb3JlcykuIAoKQSAqKmJhciBjaGFydCoqIGlzIHRoZSBhbmFsb2cgb2YgYSBoaXN0b2dyYW0sIGJ1dCBmb3IgZGlzY3JldGUgdmFyaWFibGVzCgpgYGB7cn0KZ2dwbG90KG1wZywgYWVzKG1hbnVmYWN0dXJlcikpICsgCiAgZ2VvbV9iYXIoKQpgYGAKQXMgYSBmaW5hbCBleGFtcGxlLCB3ZSBsb29rIGF0ICoqdGltZSBsaW5lKiogcGxvdHMuIEhlcmUsIHRoZSB4LWF4aXMgc2hvd3MgdGltZSAoZS5nLCB5ZWFycyksIGFuZCB0aGUgeSBheGlzIHNob3dzIG1lYXN1cmVtZW50cyBmb3IgbnVtZXJpYyB2YXJpYWJsZXMsICBvciBjb3VudHMgKGZyZXF1ZW5jaWVzKSBmb3IgY2F0ZWdvcmljYWwgZGF0YS4gV2UgdXNlIHRoZSBlY29ub21pY3MgZGF0YSBzZXQsIHdoaWNoIGNvbnRhaW5zIGJhc2ljIGVjb25vbXkgZGF0YSBmb3IgdGhlIFVTLCBzdWNoIGFzIHVuZW1wbG95bWVudCAoYHVuZW1wbG95YCkgbnVtYmVycywgb3ZlciB5ZWFycywgZm9yIHRoZSBuZXh0IGV4YW1wbGUuICAKCmBgYHtyfQpnZ3Bsb3QoZWNvbm9taWNzLCBhZXMoZGF0ZSwgdW5lbXBsb3kgLyBwb3ApKSArCiAgZ2VvbV9saW5lKCkKYGBgCioqUXVlc3Rpb246KiogSG93IGRpZCB3ZSBvdmVyY29tZSB0aGUgcHJvYmxlbSB0aGF0IHRoZSBvcmdpbmFsIGRhdGEgc2V0LCBgZWNvbm9taWNzYCwgZG9lcyBub3QgY29udGFpbiB2YWx1ZXMgb2YgdGhlIHVuZW1wbG95bWVudCAqcmF0ZSogZGlyZWN0bHksIGJ1dCBvbmx5IHRoZSBudW1iZXIgb2YgdW5lbXBsb3llZCBwZW9wbGUsIGFuZCB0aGUgcG9wdWxhdGlvbiBzaXplPyAKCkFuZCB0byBzaG93IGp1c3Qgb25lIGV4YW1wbGUgb2Ygb3ZlcndyaXRpbmcgZGVmYXVsdHMsIGxldCdzIGxvb2sgYXQgdGhlIGxhYmVscyBmb3IgdGhlIGF4aXMuIFdoaWxlICdkYXRlJyBpcyBjbGVhciBlbm91Z2gsIHRoZSBsYWJlbCAndW5lbXBsb3kvcG9wJyBsYWJlbCBpcyBhIGJpdCBteXN0ZXJpb3VzLiBMZXQncyBjaGFuZ2UgdGhpcyB0byAidW5lbXBsb3ltZW50IHJhdGUiCgpgYGB7cn0KZ2dwbG90KGVjb25vbWljcywgYWVzKGRhdGUsIHVuZW1wbG95IC8gcG9wKSkgKwogIGdlb21fbGluZSgpICsgCiAgeWxhYigidW5lbXBsb3ltZW50IHJhdGUiKQpgYGAKCiMjIyBFeGVyY2lzZXMgUGFydCAzCgpHbyBoZXJlCgojIyMgU29sdXRpb25zIGZvciBFeGVyY2lzZXMgUGFydCAzCgpHbyBoZXJlLiAK