library(tidyverse) # Always remember to set working directory and load packages.
A data frame is a table of variables (in columns) and observations/cases (in rows). The mpg data frame contains observations collected by the US Environment Protection Agency on 38 models of cars. You can learn more about any data frame by running ?mpg
mpg # The mpg data frame.
ggplot2 is a system for describing and building graphs. You can do a lot with the ggplot2 system since you can apply it in many places. ggplot2 starts with the function ggplot( ) that creates a coordinate system that you can then add layers to.
geom_point( ) is a function used to add a layer of points to a plot (in this case a scatterplot). Functions are followed by parentheses, like sum( ), mean( ), or ggplot( ). An aesthetic is a visual property of the objects in your plot and is one way of adding variables to a plot. Aesthetics include things like the size, the shape, or the color of your points. The first argument specifies the dataset to use in the graph–by itself all this does is create an empty graph. Graphs are completed by adding layers.
ggplot(data = mpg) + # The first argument specifies the dataset. *The "+" sign is always on first line.*
geom_point(mapping = aes(x = displ, y = hwy)) # Using the geom function to add layers (in this case points) to a graph. The x and y axes are assigned to displ and hwy variables.

In the code below a third variable (class) is added to a two-dimensional scatterplot by mapping it to an aesthetic by associating the name of the aesthetic (color) to the name of the variable inside aes( ) (class). ggplot2 assigns a unique level of the aesthetic (e.g., color) to each unique value of the variable (this is known as scaling). ggplot2 also adds a legend that explains which aesthetic levels correspond to which values.
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy, color = class)) # Third variable (class) added.

If we mapped the class variable to the size aesthetic instead, like in the graph below, the exact size of each point would revealthe car class. This gives us a warning because mapping an unordered (nominal) varilable like class to an ordered (ordinal) aesthetic like size does not give a good representation of the data.
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy, size = class)) # Class variable set as size, which doesn't make sense.

Other aesethetics include the alpha aesthetic shown in graph below which controls the transparency of the points.
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy, alpha = class)) # Here alpha controls transparency

The alpha aesthetic can also control the shape of the points. ggplot2 will only use six shapes at a time, any additional groups in your dataset will go unplotted.
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy, shape = class)) # Here alpha controls shape

You can set the aesthetic properties of a geom manually—for example, to make all the points blue. In the plot below this this doesn’t convey information about the variable, it just made all the data points blue.
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy), color = "blue") # Need to place argument name outside of aes ()

3.3.1 Exercises
- What’s gone wrong with this code? Why aren’t the points blue?
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy, color = "blue")) # Points not blue becasue argument is placed *inside* aes.

ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy), color = "blue") # Argument needs to be placed *outside* aes.

- What are the variables in mpg?
- Categorical variables in R are called characters. They are stored as strings (i.e., text) which are text placaed within quotes. Categorical variables in mpg include: manufacturer, model, trans (type of transmission), drv (front-wheel drive, rear-wheel, 4wd), fl (fuel type), and class (type of car).
- Continuous varibles in R are called doubles or integers. Continuous variables in mpg include: displ (engine displacement in litres), cyl (number of cylinders), cty (city miles/gallon), and hwy (highway gallons/mile).
mpg # Also run ?mpg for description of dataset
- Map a continuous variable to color, size, and shape. How do these aesthetics behave differently for categorical vs. continuous variables?
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy, color = cty)) # A continuous variable mapped to color. This makes sense for city miles/gallon.

ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy, size = cty)) # A continuous variable mapped to size. This also makes sense for city miles/gallon.

ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy, shape = cty)) # A continuous variable mapped to shape.
# Error: A continuous variable can not be mapped to shape
# This doesn't make sense because there's nothing continuous about shapes (use for categorical variables)
Why? For the aesthetics color, size, and shape the continuous variables are visualized on a spectrum whereas categorical variables are binned into discrete categories.
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy, color = class)) # Categorical variables are discrete categories.

- What happens if you map the same variable to multiple aesthetics?
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy, color = cty, size = cty)) # Both aesthetics are mapped and multiple legends are generated.

- What does the stroke aesthetic do? What shapes does it work with? (Hint: use ?geom_point).
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy), stroke = 3, shape = 21) # Stroke adjusts thickness of border for shapes that can take on different colors both inside and outside.

- What happens if you map an aesthetic to something other than a variable name, like aes(colour = displ < 5)?
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy, color = displ < 5)) # R executes code and creates a temporary variable containing the results of the operation. Here, the new variable takes on a value of TRUE if the engine displacement is less than 5 or FALSE if the engine displacement is more than or equal to 5.

LS0tCnRpdGxlOiAiZ2dwbG90MiBCYXNpY3MiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkgIyBBbHdheXMgcmVtZW1iZXIgdG8gc2V0IHdvcmtpbmcgZGlyZWN0b3J5IGFuZCBsb2FkIHBhY2thZ2VzLgpgYGAKCioqKgoKQSAqKmRhdGEgZnJhbWUqKiBpcyBhIHRhYmxlIG9mIHZhcmlhYmxlcyAoaW4gY29sdW1ucykgYW5kIG9ic2VydmF0aW9ucy9jYXNlcyAoaW4gcm93cykuIFRoZSBtcGcgZGF0YSBmcmFtZSBjb250YWlucyBvYnNlcnZhdGlvbnMgY29sbGVjdGVkIGJ5IHRoZSBVUyBFbnZpcm9ubWVudCBQcm90ZWN0aW9uIEFnZW5jeSBvbiAzOCBtb2RlbHMgb2YgY2Fycy4gWW91IGNhbiBsZWFybiBtb3JlIGFib3V0IGFueSBkYXRhIGZyYW1lIGJ5IHJ1bm5pbmcgP21wZwpgYGB7cn0KbXBnICMgVGhlIG1wZyBkYXRhIGZyYW1lLgpgYGAKCioqZ2dwbG90MioqIGlzIGEgc3lzdGVtIGZvciBkZXNjcmliaW5nIGFuZCBidWlsZGluZyBncmFwaHMuIFlvdSBjYW4gZG8gYSBsb3Qgd2l0aCB0aGUgZ2dwbG90MiBzeXN0ZW0gc2luY2UgeW91IGNhbiBhcHBseSBpdCBpbiBtYW55IHBsYWNlcy4gZ2dwbG90MiBzdGFydHMgd2l0aCB0aGUgZnVuY3Rpb24gZ2dwbG90KCApIHRoYXQgY3JlYXRlcyBhIGNvb3JkaW5hdGUgc3lzdGVtIHRoYXQgeW91IGNhbiB0aGVuIGFkZCBsYXllcnMgdG8uIAoKZ2VvbV9wb2ludCggKSBpcyBhICoqZnVuY3Rpb24qKiB1c2VkIHRvIGFkZCBhIGxheWVyIG9mIHBvaW50cyB0byBhIHBsb3QgKGluIHRoaXMgY2FzZSBhIHNjYXR0ZXJwbG90KS4gRnVuY3Rpb25zIGFyZSBmb2xsb3dlZCBieSBwYXJlbnRoZXNlcywgbGlrZSBzdW0oICksIG1lYW4oICksIG9yIGdncGxvdCggKS4gQW4gKiphZXN0aGV0aWMqKiBpcyBhIHZpc3VhbCBwcm9wZXJ0eSBvZiB0aGUgb2JqZWN0cyBpbiB5b3VyIHBsb3QgYW5kIGlzIG9uZSB3YXkgb2YgYWRkaW5nIHZhcmlhYmxlcyB0byBhIHBsb3QuIEFlc3RoZXRpY3MgaW5jbHVkZSB0aGluZ3MgbGlrZSB0aGUgc2l6ZSwgdGhlIHNoYXBlLCBvciB0aGUgY29sb3Igb2YgeW91ciBwb2ludHMuIFRoZSBmaXJzdCBhcmd1bWVudCBzcGVjaWZpZXMgdGhlIGRhdGFzZXQgdG8gdXNlIGluIHRoZSBncmFwaC0tYnkgaXRzZWxmIGFsbCB0aGlzIGRvZXMgaXMgY3JlYXRlIGFuIGVtcHR5IGdyYXBoLiBHcmFwaHMgYXJlIGNvbXBsZXRlZCBieSBhZGRpbmcgbGF5ZXJzLiAKYGBge3J9CmdncGxvdChkYXRhID0gbXBnKSArICMgVGhlIGZpcnN0IGFyZ3VtZW50IHNwZWNpZmllcyB0aGUgZGF0YXNldC4gKlRoZSAiKyIgc2lnbiBpcyBhbHdheXMgb24gZmlyc3QgbGluZS4qCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpICMgVXNpbmcgdGhlIGdlb20gZnVuY3Rpb24gdG8gYWRkIGxheWVycyAoaW4gdGhpcyBjYXNlIHBvaW50cykgdG8gYSBncmFwaC4gVGhlIHggYW5kIHkgYXhlcyBhcmUgYXNzaWduZWQgdG8gZGlzcGwgYW5kIGh3eSB2YXJpYWJsZXMuICAKYGBgCgpJbiB0aGUgY29kZSBiZWxvdyBhIHRoaXJkIHZhcmlhYmxlIChjbGFzcykgaXMgYWRkZWQgdG8gYSB0d28tZGltZW5zaW9uYWwgc2NhdHRlcnBsb3QgYnkgbWFwcGluZyBpdCB0byBhbiBhZXN0aGV0aWMgYnkgYXNzb2NpYXRpbmcgdGhlIG5hbWUgb2YgdGhlIGFlc3RoZXRpYyAoY29sb3IpIHRvIHRoZSBuYW1lIG9mIHRoZSB2YXJpYWJsZSBpbnNpZGUgYWVzKCApIChjbGFzcykuIGdncGxvdDIgYXNzaWducyBhIHVuaXF1ZSBsZXZlbCBvZiB0aGUgYWVzdGhldGljIChlLmcuLCBjb2xvcikgdG8gZWFjaCB1bmlxdWUgdmFsdWUgb2YgdGhlIHZhcmlhYmxlICh0aGlzIGlzIGtub3duIGFzICoqc2NhbGluZyoqKS4gZ2dwbG90MiBhbHNvIGFkZHMgYSBsZWdlbmQgdGhhdCBleHBsYWlucyB3aGljaCBhZXN0aGV0aWMgbGV2ZWxzIGNvcnJlc3BvbmQgdG8gd2hpY2ggdmFsdWVzLgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcpICsgCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgY29sb3IgPSBjbGFzcykpICMgVGhpcmQgdmFyaWFibGUgKGNsYXNzKSBhZGRlZC4KYGBgCgpJZiB3ZSBtYXBwZWQgdGhlIGNsYXNzIHZhcmlhYmxlIHRvIHRoZSAqc2l6ZSogYWVzdGhldGljIGluc3RlYWQsIGxpa2UgaW4gdGhlIGdyYXBoIGJlbG93LCB0aGUgZXhhY3Qgc2l6ZSBvZiBlYWNoIHBvaW50IHdvdWxkIHJldmVhbHRoZSBjYXIgY2xhc3MuIFRoaXMgZ2l2ZXMgdXMgYSB3YXJuaW5nIGJlY2F1c2UgbWFwcGluZyBhbiB1bm9yZGVyZWQgKG5vbWluYWwpIHZhcmlsYWJsZSBsaWtlIGNsYXNzIHRvIGFuIG9yZGVyZWQgKG9yZGluYWwpIGFlc3RoZXRpYyBsaWtlIHNpemUgZG9lcyBub3QgZ2l2ZSBhIGdvb2QgcmVwcmVzZW50YXRpb24gb2YgdGhlIGRhdGEuIApgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcpICsgCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgc2l6ZSA9IGNsYXNzKSkgIyBDbGFzcyB2YXJpYWJsZSBzZXQgYXMgc2l6ZSwgd2hpY2ggZG9lc24ndCBtYWtlIHNlbnNlLgpgYGAKCk90aGVyIGFlc2V0aGV0aWNzIGluY2x1ZGUgdGhlICoqYWxwaGEqKiBhZXN0aGV0aWMgc2hvd24gaW4gZ3JhcGggYmVsb3cgd2hpY2ggY29udHJvbHMgdGhlICp0cmFuc3BhcmVuY3kqIG9mIHRoZSBwb2ludHMuIApgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcpICsgCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgYWxwaGEgPSBjbGFzcykpICMgSGVyZSBhbHBoYSBjb250cm9scyB0cmFuc3BhcmVuY3kKYGBgCgpUaGUgYWxwaGEgYWVzdGhldGljIGNhbiBhbHNvIGNvbnRyb2wgdGhlICpzaGFwZSogb2YgdGhlIHBvaW50cy4gZ2dwbG90MiB3aWxsIG9ubHkgdXNlIHNpeCBzaGFwZXMgYXQgYSB0aW1lLCBhbnkgYWRkaXRpb25hbCBncm91cHMgaW4geW91ciBkYXRhc2V0IHdpbGwgZ28gdW5wbG90dGVkLgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcpICsgCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgc2hhcGUgPSBjbGFzcykpICMgSGVyZSBzaGFwZSBpcyB1c2VkIGZvciBjbGFzcwpgYGAKCllvdSBjYW4gc2V0IHRoZSBhZXN0aGV0aWMgcHJvcGVydGllcyBvZiBhIGdlb20gbWFudWFsbHktLS1mb3IgZXhhbXBsZSwgdG8gbWFrZSBhbGwgdGhlIHBvaW50cyBibHVlLiBJbiB0aGUgcGxvdCBiZWxvdyB0aGlzIHRoaXMgZG9lc24ndCBjb252ZXkgaW5mb3JtYXRpb24gYWJvdXQgdGhlIHZhcmlhYmxlLCBpdCBqdXN0IG1hZGUgYWxsIHRoZSBkYXRhIHBvaW50cyBibHVlLiAKYGBge3J9CmdncGxvdChkYXRhID0gbXBnKSArIAogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpLCBjb2xvciA9ICJibHVlIikgIyBOZWVkIHRvIHBsYWNlIGFyZ3VtZW50IG5hbWUgb3V0c2lkZSBvZiBhZXMgKCkKYGBgCioqKgojIyMjIDMuMy4xIEV4ZXJjaXNlcwoKMS4gV2hhdOKAmXMgZ29uZSB3cm9uZyB3aXRoIHRoaXMgY29kZT8gV2h5IGFyZW4ndCB0aGUgcG9pbnRzIGJsdWU/CmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IG1wZykgKyAKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBjb2xvciA9ICJibHVlIikpICMgUG9pbnRzIG5vdCBibHVlIGJlY2FzdWUgYXJndW1lbnQgaXMgcGxhY2VkICppbnNpZGUqIGFlcy4KCmdncGxvdChkYXRhID0gbXBnKSArIAogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpLCBjb2xvciA9ICJibHVlIikgIyBBcmd1bWVudCBuZWVkcyB0byBiZSBwbGFjZWQgKm91dHNpZGUqIGFlcy4KYGBgCjIuIFdoYXQgYXJlIHRoZSB2YXJpYWJsZXMgaW4gbXBnPwogICArICoqQ2F0ZWdvcmljYWwgdmFyaWFibGVzKiogaW4gUiBhcmUgY2FsbGVkICoqY2hhcmFjdGVycyoqLiBUaGV5IGFyZSBzdG9yZWQgYXMgKipzdHJpbmdzKiogKGkuZS4sIHRleHQpIHdoaWNoIGFyZSB0ZXh0IHBsYWNhZWQgd2l0aGluIHF1b3Rlcy4gQ2F0ZWdvcmljYWwgdmFyaWFibGVzIGluIG1wZyBpbmNsdWRlOiBtYW51ZmFjdHVyZXIsIG1vZGVsLCB0cmFucyAodHlwZSBvZiB0cmFuc21pc3Npb24pLCBkcnYgKGZyb250LXdoZWVsIGRyaXZlLCByZWFyLXdoZWVsLCA0d2QpLCBmbCAoZnVlbCB0eXBlKSwgYW5kIGNsYXNzICh0eXBlIG9mIGNhcikuCiAgICsgKipDb250aW51b3VzIHZhcmlibGVzKiogaW4gUiBhcmUgY2FsbGVkICoqZG91YmxlcyoqIG9yICoqaW50ZWdlcnMqKi4gQ29udGludW91cyB2YXJpYWJsZXMgaW4gbXBnIGluY2x1ZGU6IGRpc3BsIChlbmdpbmUgZGlzcGxhY2VtZW50IGluIGxpdHJlcyksIGN5bCAobnVtYmVyIG9mICBjeWxpbmRlcnMpLCBjdHkgKGNpdHkgbWlsZXMvZ2FsbG9uKSwgYW5kIGh3eSAoaGlnaHdheSBnYWxsb25zL21pbGUpLgpgYGB7cn0KbXBnICMgQWxzbyBydW4gP21wZyBmb3IgZGVzY3JpcHRpb24gb2YgZGF0YXNldApgYGAKCjMuIE1hcCBhIGNvbnRpbnVvdXMgdmFyaWFibGUgdG8gY29sb3IsIHNpemUsIGFuZCBzaGFwZS4gSG93IGRvIHRoZXNlIGFlc3RoZXRpY3MgYmVoYXZlIGRpZmZlcmVudGx5IGZvciBjYXRlZ29yaWNhbCB2cy4gY29udGludW91cyB2YXJpYWJsZXM/CmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IG1wZykgKwogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIGNvbG9yID0gY3R5KSkgIyBBIGNvbnRpbnVvdXMgdmFyaWFibGUgbWFwcGVkIHRvIGNvbG9yLiBUaGlzIG1ha2VzIHNlbnNlIGZvciBjaXR5IG1pbGVzL2dhbGxvbi4KYGBgCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBzaXplID0gY3R5KSkgIyBBIGNvbnRpbnVvdXMgdmFyaWFibGUgbWFwcGVkIHRvIHNpemUuIFRoaXMgYWxzbyBtYWtlcyBzZW5zZSBmb3IgY2l0eSBtaWxlcy9nYWxsb24uCmBgYApgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBzaGFwZSA9IGN0eSkpICMgQSBjb250aW51b3VzIHZhcmlhYmxlIG1hcHBlZCB0byBzaGFwZS4gCiMgRXJyb3I6IEEgY29udGludW91cyB2YXJpYWJsZSBjYW4gbm90IGJlIG1hcHBlZCB0byBzaGFwZQojIFRoaXMgZG9lc24ndCBtYWtlIHNlbnNlIGJlY2F1c2UgdGhlcmUncyBub3RoaW5nIGNvbnRpbnVvdXMgYWJvdXQgc2hhcGVzICh1c2UgZm9yIGNhdGVnb3JpY2FsIHZhcmlhYmxlcykKYGBgCgpXaHk/IEZvciB0aGUgYWVzdGhldGljcyBjb2xvciwgc2l6ZSwgYW5kIHNoYXBlIHRoZSBjb250aW51b3VzIHZhcmlhYmxlcyBhcmUgdmlzdWFsaXplZCBvbiBhIHNwZWN0cnVtIHdoZXJlYXMgY2F0ZWdvcmljYWwgdmFyaWFibGVzIGFyZSBiaW5uZWQgaW50byBkaXNjcmV0ZSBjYXRlZ29yaWVzLgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBjb2xvciA9IGNsYXNzKSkgIyBIZXJlIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUgaGFzIGRpZmZlcmVudCBjb2xvcnMgdG8gcmVwcmVzZW50IGRpc2NyZXRlIGNhdGVnb3JpZXMuIFdpdGggYSBjb250aW51b3VzIHZhcmlhYmxlIGNvbG9yIHdvdWxkIGJlIHRoZSBzYW1lIHdpdGggY29sb3Igb24gYSBzcGVjdHJ1bSB0byBzaG93IHZhcmlhdGlvbi4KYGBgCgo0LiBXaGF0IGhhcHBlbnMgaWYgeW91IG1hcCB0aGUgc2FtZSB2YXJpYWJsZSB0byBtdWx0aXBsZSBhZXN0aGV0aWNzPwpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBjb2xvciA9IGN0eSwgc2l6ZSA9IGN0eSkpICMgQm90aCBhZXN0aGV0aWNzIGFyZSBtYXBwZWQgYW5kIG11bHRpcGxlIGxlZ2VuZHMgYXJlIGdlbmVyYXRlZC4KYGBgCgo1LiBXaGF0IGRvZXMgdGhlIHN0cm9rZSBhZXN0aGV0aWMgZG8/IFdoYXQgc2hhcGVzIGRvZXMgaXQgd29yayB3aXRoPyAoSGludDogdXNlID9nZW9tX3BvaW50KS4gCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IG1wZykgKwogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpLCBzdHJva2UgPSAzLCBzaGFwZSA9IDIxKSAjIFN0cm9rZSBhZGp1c3RzIHRoaWNrbmVzcyBvZiBib3JkZXIgZm9yIHNoYXBlcyB0aGF0IGNhbiB0YWtlIG9uIGRpZmZlcmVudCBjb2xvcnMgKmJvdGgqIGluc2lkZSBhbmQgb3V0c2lkZS4KYGBgCgo2LiBXaGF0IGhhcHBlbnMgaWYgeW91IG1hcCBhbiBhZXN0aGV0aWMgdG8gc29tZXRoaW5nIG90aGVyIHRoYW4gYSB2YXJpYWJsZSBuYW1lLCBsaWtlIGFlcyhjb2xvdXIgPSBkaXNwbCA8IDUpPwpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBjb2xvciA9IGRpc3BsIDwgNSkpICMgUiBleGVjdXRlcyBjb2RlIGFuZCBjcmVhdGVzIGEgdGVtcG9yYXJ5IHZhcmlhYmxlIGNvbnRhaW5pbmcgdGhlIHJlc3VsdHMgb2YgdGhlIG9wZXJhdGlvbi4gSGVyZSwgdGhlIG5ldyB2YXJpYWJsZSB0YWtlcyBvbiBhIHZhbHVlIG9mIFRSVUUgaWYgdGhlIGVuZ2luZSBkaXNwbGFjZW1lbnQgaXMgbGVzcyB0aGFuIDUgb3IgRkFMU0UgaWYgdGhlIGVuZ2luZSBkaXNwbGFjZW1lbnQgaXMgbW9yZSB0aGFuIG9yIGVxdWFsIHRvIDUuCmBgYAo=