In this section, we’ll learn some skills about manipulating factor (categorical) data.
We’ll do this by making a bar plot progressively making it more complex. We’ll then dive into boxplots, a way to view the distribution of a variable across the categories of a different variable.
Reviewing Factors
Factors are frequently how R represents categorical data.
There are two kinds of factors:
factor
- used for nominal data (“Ducks”, “Cats”, “Dogs”)`
ordered
- used for ordinal data (“10-30”,“31-40”,“41-60”)
We’ll manipulate our barplot and add more information using factors.
Here’s the simple dataset we’ll use to investigate how to work with factors in ggplot
. Here we also introduce how to read in data stored in an R data file (an RDS) into a data frame in R. Note the similarities with reading in CSV files (read_rds()
versus read_csv()
.)
We display the pets
data frame by simply running the line containing pets
.
library(tidyverse)
pets <- read_rds("data/pets.rds")
pets
We see that name
and animal
are stored as factor
s and age_category
is stored as an ordinal factor
. Note that name
has three levels ordered as "0-2"
, "3-4"
, and "5-8"
.
A Basic Barplot using geom_bar()
By default, the geom_bar()
function counts the number of values with each factor level. Note that you don’t map to a y-aesthetic here, because the y values are the counts.
Given this dataset, we might want to ask how many pets have the same name. What is the most popular name?
ggplot(data = pets, mapping = aes(x = name)) +
geom_bar()
Your Task
Try mapping another variable to fill
(try both weight
and animal
). Are the results what you expected?
# Test out `weight` and `animal` here
Faceting
Say you have another factor
variable and you want to stratify the plots based on that. You can do that by supplying the name of that variable as a facet. Here, we facet our barplot by shots_current
.
ggplot(data = pets, mapping = aes(x = name)) +
geom_bar() +
## have to specify facets using notation
facet_wrap(facets = ~ shots_current) +
## we make the x axis x angled for better legibility
theme(axis.text.x = element_text(angle = 90))
You might notice that there are blank spots for the categories in each facet. We can restrict the factors in each by using scale = "free_x"
argument in facet_wrap()
.
ggplot(data = pets, mapping = aes(x = name)) +
geom_bar() +
## have to specify facets using notation
facet_wrap(facets = ~ shots_current, scale = "free_x") +
## we make the x axis x angled for better legibility
theme(axis.text.x = element_text(angle = 90))
Your Task
How many animals named “Morris” did not receive shots?
What happens when you replace the scale
argument with "free_y"
?
ggplot(data = pets, mapping = aes(x = name)) +
geom_bar() +
facet_wrap(facets = ~ shots_current, scale = "free_y") +
theme(axis.text.x = element_text(angle = 90))
What’s up with this ~
in the facets
?
This is known as formula notation and might make a little more sense if we explore how to create a grid of smaller plots across two different variables. Note that animal
appears on the vertical y
axis and shots_current
goes on the horizontal x
axis. This is how to read this ~
in most settings in R.
ggplot(data = pets, mapping = aes(x = name)) +
geom_bar() +
facet_grid(facets = animal ~ shots_current) +
theme(axis.text.x = element_text(angle = 90))
Stacked Bars
Let’s see how many of each animal got shots. We can do this by mapping shots_current
to fill
. Note that we can also use color
here to specify the highlighting color of the bars.
# We map color (the outline of the plot) to black to make it look prettier
# Note that we don't include `aes` in the `color = "black"` since we aren't
# mapping an aesthetic to a variable but rather just changing the setting.
ggplot(data = pets, mapping = aes(x = animal, fill = shots_current)) +
geom_bar(color = "black")
Proportional Barchart
We may only be interested in the relative proportions between the different categories. Visualizing this is useful for various 2 x 2 tests on proportions.
What percent of dogs did not receive shots?
ggplot(data = pets, mapping = aes(x = animal, fill = shots_current)) +
geom_bar(position = "fill", color = "black")
Dodge those bars!
Instead of stacking, we can also dodge the bars (move the bars so they’re beside each other).
ggplot(data = pets, mapping = aes(x = animal, fill = shots_current)) +
geom_bar(position = "dodge", color = "black")
Your Task: Bar Charts
Given the pets
data.frame
, plot a stacked proportional barchart that shows age category by shots being current. Is the proportion of animals receiving shots the same across each age category?
Hints: think about what to map to x
, and what to map to fill
.
Intermediate Folks: facet this plot by animal
.
# Space for your answer here.
# Intermediate: Space for your answer here.
Boxplots
Boxplots allow us to assess distributions of a continuous variable conditioned on categorical variables.
What does this tell us?
ggplot(pets, aes(x = shots_current, y = weight)) +
geom_boxplot()
Violin Plots
Violin plots are another useful way to visualize the data. They provide a more nuanced look at the data. They’re a density plot that’s mirrored around the y-axis.
ggplot(pets, aes(x = age_category, y = weight, fill = age_category)) +
geom_violin()
Your task: How heavy are our pets?
Visualize weight
by animal
type as both a boxplot and a violin plot. What do you conclude? Which kind of animal weighs more on average than the other?
Note that the horizontal axis needs to correspond to the categorical variable and the vertical axis needs to correspond to a numeric variable.
Intermediate challenge: How would we plot both boxplots and a violin plot on the same graph?
## Space for your answer here
## Intermediate: Space for your answer here
What you learned in this section
- Visualizing factor data
- Simple, stacked, stacked proportional, and dodged barplots
- Faceting a graph
- Boxplots and violin plots
LS0tCnRpdGxlOiAiUGFydCAyIC0gV29ya2luZyB3aXRoIEZhY3RvcnMiCmF1dGhvcjogIlRlZCBMYWRlcmFzIgpkYXRlOiAiNS8xOC8yMDE3IgpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGRmX3ByaW50OiBwYWdlZAotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQobWVzc2FnZSA9IEZBTFNFKQpgYGAKCkluIHRoaXMgc2VjdGlvbiwgd2UnbGwgbGVhcm4gc29tZSBza2lsbHMgYWJvdXQgbWFuaXB1bGF0aW5nIGZhY3RvciAoY2F0ZWdvcmljYWwpIGRhdGEuCgpXZSdsbCBkbyB0aGlzIGJ5IG1ha2luZyBhIGJhciBwbG90IHByb2dyZXNzaXZlbHkgbWFraW5nIGl0IG1vcmUgY29tcGxleC4gV2UnbGwgdGhlbiBkaXZlIGludG8gYm94cGxvdHMsIGEgd2F5IHRvIHZpZXcgdGhlIGRpc3RyaWJ1dGlvbiBvZiBhIHZhcmlhYmxlIGFjcm9zcyB0aGUgY2F0ZWdvcmllcyBvZiBhIGRpZmZlcmVudCB2YXJpYWJsZS4KCiMjIFJldmlld2luZyBGYWN0b3JzIAoKRmFjdG9ycyBhcmUgZnJlcXVlbnRseSBob3cgUiByZXByZXNlbnRzIGNhdGVnb3JpY2FsIGRhdGEuCgpUaGVyZSBhcmUgdHdvIGtpbmRzIG9mIGZhY3RvcnM6IAoKKyBgZmFjdG9yYCAtIHVzZWQgZm9yICpub21pbmFsKiBkYXRhICgiRHVja3MiLCAiQ2F0cyIsICJEb2dzIilgCisgYG9yZGVyZWRgLSB1c2VkIGZvciAqb3JkaW5hbCogZGF0YSAoIjEwLTMwIiwiMzEtNDAiLCI0MS02MCIpCgpXZSdsbCBtYW5pcHVsYXRlIG91ciBiYXJwbG90IGFuZCBhZGQgbW9yZSBpbmZvcm1hdGlvbiB1c2luZyBmYWN0b3JzLgoKSGVyZSdzIHRoZSBzaW1wbGUgZGF0YXNldCB3ZSdsbCB1c2UgdG8gaW52ZXN0aWdhdGUgaG93IHRvIHdvcmsgd2l0aCBmYWN0b3JzIGluIGBnZ3Bsb3RgLiBIZXJlIHdlIGFsc28gaW50cm9kdWNlIGhvdyB0byByZWFkIGluIGRhdGEgc3RvcmVkIGluIGFuIFIgZGF0YSBmaWxlIChhbiBSRFMpIGludG8gYSBkYXRhIGZyYW1lIGluIFIuIE5vdGUgdGhlIHNpbWlsYXJpdGllcyB3aXRoIHJlYWRpbmcgaW4gQ1NWIGZpbGVzIChgcmVhZF9yZHMoKWAgdmVyc3VzIGByZWFkX2NzdigpYC4pCgpXZSBkaXNwbGF5IHRoZSBgcGV0c2AgZGF0YSBmcmFtZSBieSBzaW1wbHkgcnVubmluZyB0aGUgbGluZSBjb250YWluaW5nIGBwZXRzYC4KCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKcGV0cyA8LSByZWFkX3JkcygiZGF0YS9wZXRzLnJkcyIpCnBldHMKYGBgCgpXZSBzZWUgdGhhdCBgbmFtZWAgYW5kIGBhbmltYWxgIGFyZSBzdG9yZWQgYXMgYGZhY3RvcmBzIGFuZCBgYWdlX2NhdGVnb3J5YCBpcyBzdG9yZWQgYXMgYW4gb3JkaW5hbCBgZmFjdG9yYC4gTm90ZSB0aGF0IGBuYW1lYCBoYXMgdGhyZWUgbGV2ZWxzIG9yZGVyZWQgYXMgYCIwLTIiYCwgYCIzLTQiYCwgYW5kIGAiNS04ImAuCgojIyBBIEJhc2ljIEJhcnBsb3QgdXNpbmcgYGdlb21fYmFyKClgCgpCeSBkZWZhdWx0LCB0aGUgYGdlb21fYmFyKClgIGZ1bmN0aW9uIGNvdW50cyB0aGUgbnVtYmVyIG9mIHZhbHVlcyB3aXRoIGVhY2ggZmFjdG9yIGxldmVsLiBOb3RlIHRoYXQgeW91IGRvbid0IG1hcCB0byBhIHktYWVzdGhldGljIGhlcmUsIGJlY2F1c2UgdGhlIHkgdmFsdWVzIGFyZSB0aGUgY291bnRzLgoKR2l2ZW4gdGhpcyBkYXRhc2V0LCB3ZSBtaWdodCB3YW50IHRvIGFzayBob3cgbWFueSBwZXRzIGhhdmUgdGhlIHNhbWUgbmFtZS4gV2hhdCBpcyB0aGUgbW9zdCBwb3B1bGFyIG5hbWU/CgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBwZXRzLCBtYXBwaW5nID0gYWVzKHggPSBuYW1lKSkgKyAKICBnZW9tX2JhcigpCmBgYAoKIyMgWW91ciBUYXNrCgpUcnkgbWFwcGluZyBhbm90aGVyIHZhcmlhYmxlIHRvIGBmaWxsYCAodHJ5IGJvdGggYHdlaWdodGAgYW5kIGBhbmltYWxgKS4gQXJlIHRoZSByZXN1bHRzIHdoYXQgeW91IGV4cGVjdGVkPwoKYGBge3J9CiMgVGVzdCBvdXQgYHdlaWdodGAgYW5kIGBhbmltYWxgIGhlcmUKCmBgYAoKCiMjIEZhY2V0aW5nCgpTYXkgeW91IGhhdmUgYW5vdGhlciBgZmFjdG9yYCB2YXJpYWJsZSBhbmQgeW91IHdhbnQgdG8gc3RyYXRpZnkgdGhlIHBsb3RzIGJhc2VkIG9uIHRoYXQuIFlvdSBjYW4gZG8gdGhhdCBieSBzdXBwbHlpbmcgdGhlIG5hbWUgb2YgdGhhdCB2YXJpYWJsZSBhcyBhIGZhY2V0LiBIZXJlLCB3ZSBmYWNldCBvdXIgYmFycGxvdCBieSBgc2hvdHNfY3VycmVudGAuCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBwZXRzLCBtYXBwaW5nID0gYWVzKHggPSBuYW1lKSkgKyAKICBnZW9tX2JhcigpICsgCiAgIyMgaGF2ZSB0byBzcGVjaWZ5IGZhY2V0cyB1c2luZyBub3RhdGlvbgogIGZhY2V0X3dyYXAoZmFjZXRzID0gfiBzaG90c19jdXJyZW50KSArIAogICMjIHdlIG1ha2UgdGhlIHggYXhpcyB4IGFuZ2xlZCBmb3IgYmV0dGVyIGxlZ2liaWxpdHkKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkKYGBgCgpZb3UgbWlnaHQgbm90aWNlIHRoYXQgdGhlcmUgYXJlIGJsYW5rIHNwb3RzIGZvciB0aGUgY2F0ZWdvcmllcyBpbiBlYWNoIGZhY2V0LiBXZSBjYW4gcmVzdHJpY3QgdGhlIGZhY3RvcnMgaW4gZWFjaCBieSB1c2luZyBgc2NhbGUgPSAiZnJlZV94ImAgYXJndW1lbnQgaW4gYGZhY2V0X3dyYXAoKWAuCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBwZXRzLCBtYXBwaW5nID0gYWVzKHggPSBuYW1lKSkgKyAKICBnZW9tX2JhcigpICsgCiAgIyMgaGF2ZSB0byBzcGVjaWZ5IGZhY2V0cyB1c2luZyBub3RhdGlvbgogIGZhY2V0X3dyYXAoZmFjZXRzID0gfiBzaG90c19jdXJyZW50LCBzY2FsZSA9ICJmcmVlX3giKSArIAogICMjIHdlIG1ha2UgdGhlIHggYXhpcyB4IGFuZ2xlZCBmb3IgYmV0dGVyIGxlZ2liaWxpdHkKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkKYGBgCgoKIyMgWW91ciBUYXNrCgpIb3cgbWFueSBhbmltYWxzIG5hbWVkICJNb3JyaXMiIGRpZCBub3QgcmVjZWl2ZSBzaG90cz8KCmBgYHtyfQoKYGBgCgoKV2hhdCBoYXBwZW5zIHdoZW4geW91IHJlcGxhY2UgdGhlIGBzY2FsZWAgYXJndW1lbnQgd2l0aCBgImZyZWVfeSJgPwoKYGBge3J9CmdncGxvdChkYXRhID0gcGV0cywgbWFwcGluZyA9IGFlcyh4ID0gbmFtZSkpICsgCiAgZ2VvbV9iYXIoKSArIAogIGZhY2V0X3dyYXAoZmFjZXRzID0gfiBzaG90c19jdXJyZW50LCBzY2FsZSA9ICJmcmVlX3kiKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpCmBgYAoKIyMjIFdoYXQncyB1cCB3aXRoIHRoaXMgYH5gIGluIHRoZSBgZmFjZXRzYD8KClRoaXMgaXMga25vd24gYXMgZm9ybXVsYSBub3RhdGlvbiBhbmQgbWlnaHQgbWFrZSBhIGxpdHRsZSBtb3JlIHNlbnNlIGlmIHdlIGV4cGxvcmUgaG93IHRvIGNyZWF0ZSBhIGdyaWQgb2Ygc21hbGxlciBwbG90cyBhY3Jvc3MgdHdvIGRpZmZlcmVudCB2YXJpYWJsZXMuIE5vdGUgdGhhdCBgYW5pbWFsYCBhcHBlYXJzIG9uIHRoZSB2ZXJ0aWNhbCBgeWAgYXhpcyBhbmQgYHNob3RzX2N1cnJlbnRgIGdvZXMgb24gdGhlIGhvcml6b250YWwgYHhgIGF4aXMuIFRoaXMgaXMgaG93IHRvIHJlYWQgdGhpcyBgfmAgaW4gbW9zdCBzZXR0aW5ncyBpbiBSLgoKYGBge3J9CmdncGxvdChkYXRhID0gcGV0cywgbWFwcGluZyA9IGFlcyh4ID0gbmFtZSkpICsgCiAgZ2VvbV9iYXIoKSArIAogIGZhY2V0X2dyaWQoZmFjZXRzID0gYW5pbWFsIH4gc2hvdHNfY3VycmVudCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKQpgYGAKCgojIyBTdGFja2VkIEJhcnMKCkxldCdzIHNlZSBob3cgbWFueSBvZiBlYWNoIGFuaW1hbCBnb3Qgc2hvdHMuIFdlIGNhbiBkbyB0aGlzIGJ5IG1hcHBpbmcgYHNob3RzX2N1cnJlbnRgIHRvIGBmaWxsYC4gTm90ZSB0aGF0IHdlIGNhbiBhbHNvIHVzZSBgY29sb3JgIGhlcmUgdG8gc3BlY2lmeSB0aGUgaGlnaGxpZ2h0aW5nIGNvbG9yIG9mIHRoZSBiYXJzLgoKYGBge3J9CiMgV2UgbWFwIGNvbG9yICh0aGUgb3V0bGluZSBvZiB0aGUgcGxvdCkgdG8gYmxhY2sgdG8gbWFrZSBpdCBsb29rIHByZXR0aWVyCiMgTm90ZSB0aGF0IHdlIGRvbid0IGluY2x1ZGUgYGFlc2AgaW4gdGhlIGBjb2xvciA9ICJibGFjayJgIHNpbmNlIHdlIGFyZW4ndAojIG1hcHBpbmcgYW4gYWVzdGhldGljIHRvIGEgdmFyaWFibGUgYnV0IHJhdGhlciBqdXN0IGNoYW5naW5nIHRoZSBzZXR0aW5nLgpnZ3Bsb3QoZGF0YSA9IHBldHMsIG1hcHBpbmcgPSBhZXMoeCA9IGFuaW1hbCwgZmlsbCA9IHNob3RzX2N1cnJlbnQpKSArIAogIGdlb21fYmFyKGNvbG9yID0gImJsYWNrIikKYGBgCgojIyBQcm9wb3J0aW9uYWwgQmFyY2hhcnQKCldlIG1heSBvbmx5IGJlIGludGVyZXN0ZWQgaW4gdGhlIHJlbGF0aXZlIHByb3BvcnRpb25zIGJldHdlZW4gdGhlIGRpZmZlcmVudCBjYXRlZ29yaWVzLiBWaXN1YWxpemluZyB0aGlzIGlzIHVzZWZ1bCBmb3IgdmFyaW91cyAyIHggMiB0ZXN0cyBvbiBwcm9wb3J0aW9ucy4KCldoYXQgcGVyY2VudCBvZiBkb2dzIGRpZCBub3QgcmVjZWl2ZSBzaG90cz8KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IHBldHMsIG1hcHBpbmcgPSBhZXMoeCA9IGFuaW1hbCwgZmlsbCA9IHNob3RzX2N1cnJlbnQpKSArIAogIGdlb21fYmFyKHBvc2l0aW9uID0gImZpbGwiLCBjb2xvciA9ICJibGFjayIpCmBgYAoKIyMgRG9kZ2UgdGhvc2UgYmFycyEKCkluc3RlYWQgb2Ygc3RhY2tpbmcsIHdlIGNhbiBhbHNvIGRvZGdlIHRoZSBiYXJzIChtb3ZlIHRoZSBiYXJzIHNvIHRoZXkncmUgYmVzaWRlIGVhY2ggb3RoZXIpLgoKYGBge3J9CmdncGxvdChkYXRhID0gcGV0cywgbWFwcGluZyA9IGFlcyh4ID0gYW5pbWFsLCBmaWxsID0gc2hvdHNfY3VycmVudCkpICsgCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiLCBjb2xvciA9ICJibGFjayIpCmBgYAoKIyMgWW91ciBUYXNrOiBCYXIgQ2hhcnRzCgpHaXZlbiB0aGUgYHBldHNgIGBkYXRhLmZyYW1lYCwgcGxvdCBhIHN0YWNrZWQgcHJvcG9ydGlvbmFsIGJhcmNoYXJ0IHRoYXQgc2hvd3MgYWdlIGNhdGVnb3J5IGJ5IHNob3RzIGJlaW5nIGN1cnJlbnQuIElzIHRoZSBwcm9wb3J0aW9uIG9mIGFuaW1hbHMgcmVjZWl2aW5nIHNob3RzIHRoZSBzYW1lIGFjcm9zcyBlYWNoIGFnZSBjYXRlZ29yeT8KCkhpbnRzOiB0aGluayBhYm91dCB3aGF0IHRvIG1hcCB0byBgeGAsIGFuZCB3aGF0IHRvIG1hcCB0byBgZmlsbGAuCgpJbnRlcm1lZGlhdGUgRm9sa3M6IGZhY2V0IHRoaXMgcGxvdCBieSBgYW5pbWFsYC4gCgpgYGB7cn0KIyBTcGFjZSBmb3IgeW91ciBhbnN3ZXIgaGVyZS4KCmBgYAoKYGBge3J9CiMgSW50ZXJtZWRpYXRlOiBTcGFjZSBmb3IgeW91ciBhbnN3ZXIgaGVyZS4KCmBgYAoKCiMjIEJveHBsb3RzCgpCb3hwbG90cyBhbGxvdyB1cyB0byBhc3Nlc3MgZGlzdHJpYnV0aW9ucyBvZiBhIGNvbnRpbnVvdXMgdmFyaWFibGUgY29uZGl0aW9uZWQgb24gY2F0ZWdvcmljYWwgdmFyaWFibGVzLgoKV2hhdCBkb2VzIHRoaXMgdGVsbCB1cz8gCgpgYGB7cn0KZ2dwbG90KHBldHMsIGFlcyh4ID0gc2hvdHNfY3VycmVudCwgeSA9IHdlaWdodCkpICsgCiAgZ2VvbV9ib3hwbG90KCkKYGBgCgojIyBWaW9saW4gUGxvdHMKClZpb2xpbiBwbG90cyBhcmUgYW5vdGhlciB1c2VmdWwgd2F5IHRvIHZpc3VhbGl6ZSB0aGUgZGF0YS4gVGhleSBwcm92aWRlIGEgbW9yZSBudWFuY2VkIGxvb2sgYXQgdGhlIGRhdGEuIFRoZXkncmUgYSBkZW5zaXR5IHBsb3QgdGhhdCdzIG1pcnJvcmVkIGFyb3VuZCB0aGUgeS1heGlzLgoKYGBge3J9CmdncGxvdChwZXRzLCBhZXMoeCA9IGFnZV9jYXRlZ29yeSwgeSA9IHdlaWdodCwgZmlsbCA9IGFnZV9jYXRlZ29yeSkpICsgCiAgZ2VvbV92aW9saW4oKQpgYGAKCiMjIFlvdXIgdGFzazogSG93IGhlYXZ5IGFyZSBvdXIgcGV0cz8KClZpc3VhbGl6ZSBgd2VpZ2h0YCBieSBgYW5pbWFsYCB0eXBlIGFzIGJvdGggYSBib3hwbG90IGFuZCBhIHZpb2xpbiBwbG90LiBXaGF0IGRvIHlvdSBjb25jbHVkZT8gV2hpY2gga2luZCBvZiBhbmltYWwgd2VpZ2hzIG1vcmUgb24gYXZlcmFnZSB0aGFuIHRoZSBvdGhlcj8KCk5vdGUgdGhhdCB0aGUgaG9yaXpvbnRhbCBheGlzIG5lZWRzIHRvIGNvcnJlc3BvbmQgdG8gdGhlIGNhdGVnb3JpY2FsIHZhcmlhYmxlIGFuZCB0aGUgdmVydGljYWwgYXhpcyBuZWVkcyB0byBjb3JyZXNwb25kIHRvIGEgbnVtZXJpYyB2YXJpYWJsZS4KCkludGVybWVkaWF0ZSBjaGFsbGVuZ2U6IEhvdyB3b3VsZCB3ZSBwbG90IGJvdGggYm94cGxvdHMgYW5kIGEgdmlvbGluIHBsb3Qgb24gdGhlIHNhbWUgZ3JhcGg/CgpgYGB7cn0KIyMgU3BhY2UgZm9yIHlvdXIgYW5zd2VyIGhlcmUKCmBgYAoKYGBge3J9CiMjIEludGVybWVkaWF0ZTogU3BhY2UgZm9yIHlvdXIgYW5zd2VyIGhlcmUKCmBgYAoKCiMjIFdoYXQgeW91IGxlYXJuZWQgaW4gdGhpcyBzZWN0aW9uCgotIFZpc3VhbGl6aW5nIGZhY3RvciBkYXRhCi0gU2ltcGxlLCBzdGFja2VkLCBzdGFja2VkIHByb3BvcnRpb25hbCwgYW5kIGRvZGdlZCBiYXJwbG90cyAKLSBGYWNldGluZyBhIGdyYXBoCi0gQm94cGxvdHMgYW5kIHZpb2xpbiBwbG90cw==