library(tidyverse)
Basics
Modify the code below to make the points larger triangles and
slightly transparent. See ?geom_point
for more information
on the point layer.
ggplot(mpg) +
geom_point(aes(x = displ, y = hwy))
Solution:
ggplot(mpg) +
geom_point(aes(x = displ, y = hwy), shape="triangle", size=4, alpha=0.5)
Using the mpg
dataset draw a line chart, a boxplot, and
a histogram
Solution:
ggplot(data=mpg)+
geom_line(aes(x=displ, y=hwy))
ggplot(data=mpg)+
geom_boxplot(aes(x=class, y=displ))
ggplot(data=mpg)+
geom_histogram(aes(x=hwy))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Stat
What does geom_col() do? How is it different from geom_bar()?
Look at the documentation for geom_bar using
?geom_bar
We learnt that geom_*()
and stat_*()
are
interchangeable. Can you look at ?geom_bar()
and figure out
which stat it uses as default. Modify the code below to use that stat
directly instead
ggplot(mpg) +
geom_bar(aes(x = class))
Solution: The description says “geom_bar() uses stat_count() by
default”. Using it directly below:
ggplot(mpg) +
stat_count(aes(x = class))
Use stat_summary()
to add a red dot at the mean
hwy
for each group
ggplot(mpg) +
geom_jitter(aes(x = class, y = hwy), width = 0.2)
Hint: You will need to change the default geom of
stat_summary()
Solution:
ggplot(mpg, aes(x=class, y=hwy)) +
geom_jitter(width = 0.2)+
stat_summary(geom = "point", fun="mean", color="red")
In our proportion bar chart, we need to set group = 1. Why? In other
words what is the problem with these two graphs?
p1<- ggplot(data = diamonds) +
geom_bar(mapping = aes(x = cut, y = after_stat(prop)))
p2<-ggplot(data = diamonds) +
geom_bar(mapping = aes(x = cut, fill = color, y = after_stat(prop)))
p1
p2
Solution: if group = 1 is not included, the proportions will be
calculated within each group. Modified code is below.
p1_new<- ggplot(data = diamonds) +
geom_bar(mapping = aes(x = cut, y = after_stat(prop), group=1))
p2_new<-ggplot(data = diamonds) +
geom_bar(mapping = aes(x = cut, fill = color, y = ..count.. / sum(..count..)))
p1_new
p2_new
*** What is the problem with this plot? How could we improve it?
ggplot(data = mpg, mapping = aes(x = cty, y = hwy)) +
geom_point( )
Solution: There is overplotting because there are multiple observations
for each combination of cty
and hwy
values.
ggplot(data = mpg, mapping = aes(x = cty, y = hwy)) +
geom_point(position="jitter" )
Scales
Use RColorBrewer::display.brewer.all()
to see all the
different palettes from Color Brewer and pick your favourite. Modify the
code below to use it
ggplot(mpg) +
geom_point(aes(x = displ, y = hwy, colour = class)) +
scale_colour_brewer(type = 'qual')
Solution:
data("mpg")
ggplot(mpg) +
geom_point(aes(x = displ, y = hwy, colour = class)) +
scale_colour_brewer(type = 'qual', palette = "Set1")
* * *
Modify the code below to create a bubble chart (scatterplot with size
mapped to a continuous variable) showing cyl
with size.
Make sure that only the present amount of cylinders (4, 5, 6, and 8) are
present in the legend.
ggplot(mpg) +
geom_point(aes(x = displ, y = hwy, colour = class)) +
scale_colour_brewer(type = 'qual')
Hint: The breaks
argument in the scale is used to
control which values are present in the legend.
Solution:
ggplot(mpg) +
geom_point(aes(x = displ, y = hwy, colour = class, size=cyl)) +
scale_colour_brewer(type = 'qual') +
scale_size(breaks = c(4, 5, 6, 8))
Explore the different types of size scales available in ggplot2. Is the
default the most appropriate here?
Solution: Default is mapping to the radius. But it is not intuitive.
Let’s try size mapping by area.
ggplot(mpg) +
geom_point(aes(x = displ, y = hwy, colour = class, size=cyl)) +
scale_colour_brewer(type = 'qual') +
scale_size_area(breaks = c(4, 5, 6, 8))
* * *
Modify the code below so that colour is no longer mapped to the
discrete class
variable, but to the continuous
cty
variable. What happens to the guide (legend)?
ggplot(mpg) +
geom_point(aes(x = displ, y = hwy, colour = class, size = cty))
Solution:
ggplot(mpg) +
geom_point(aes(x = displ, y = hwy, colour = cty, size = cty))
* * *
The type of guide can be controlled with the guide
argument in the scale, or with the guides()
function.
Continuous colours have a gradient colour bar by default, but setting it
to legend
will turn it back to the standard look. What
happens when multiple aesthetics are mapped to the same variable and
uses the guide type?
Solution:
ggplot(mpg) +
geom_point(aes(x = displ, y = hwy, colour = cty, size = cty))+
guides(color="legend")
ggplot combines both legends.
Facets
One of the great things about facets is that they share the axes
between the different panels. Sometimes this is undesirable though, and
the behavior can be changed with the scales
argument.
Experiment with the different possible settings in the plot below:
ggplot(mpg) +
geom_point(aes(x = displ, y = hwy)) +
facet_wrap(~ drv)
Solution:
ggplot(mpg) +
geom_point(aes(x = displ, y = hwy)) +
facet_wrap(~ drv, scales="free_y")
* * *
Usually the space occupied by each panel is equal. This can create
problems when different scales are used. Can you modify the code below
so that the y scale differs between the panels in the plot. What
happens?
ggplot(mpg) +
geom_bar(aes(y = manufacturer)) +
facet_grid(class ~ .)
Use the space
argument in facet_grid()
to
change the plot above so each bar has the same width again.
Solution:
data("mpg")
ggplot(mpg) +
geom_bar(aes(y = manufacturer)) +
facet_grid(class ~ ., space = "free_y", scales = "free_y")
LS0tCnRpdGxlOiAiTW9kdWxlIDQgLSBEYXRhIFZpc3VhbGl6YXRpb24iCmF1dGhvcjogTWVlbmFrc2hpIEt1c2h3YWhhCmRhdGU6ICcyMDIyLTA3LTI4JwpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIGNhY2hlID0gVFJVRSkKYGBgCgpgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKCiMjIyBCYXNpY3MKCk1vZGlmeSB0aGUgY29kZSBiZWxvdyB0byBtYWtlIHRoZSBwb2ludHMgbGFyZ2VyIHRyaWFuZ2xlcyBhbmQgc2xpZ2h0bHkgdHJhbnNwYXJlbnQuClNlZSBgP2dlb21fcG9pbnRgIGZvciBtb3JlIGluZm9ybWF0aW9uIG9uIHRoZSBwb2ludCBsYXllci4KCmBgYHtyfQpnZ3Bsb3QobXBnKSArIAogIGdlb21fcG9pbnQoYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpCmBgYAoKU29sdXRpb246CmBgYHtyfQpnZ3Bsb3QobXBnKSArIAogIGdlb21fcG9pbnQoYWVzKHggPSBkaXNwbCwgeSA9IGh3eSksIHNoYXBlPSJ0cmlhbmdsZSIsIHNpemU9NCwgYWxwaGE9MC41KQpgYGAKCiogKiAqCgpVc2luZyB0aGUgYG1wZ2AgZGF0YXNldCBkcmF3IGEgbGluZSBjaGFydCwgYSBib3hwbG90LCBhbmQgYSBoaXN0b2dyYW0KClNvbHV0aW9uOgpgYGB7cn0KZ2dwbG90KGRhdGE9bXBnKSsKICBnZW9tX2xpbmUoYWVzKHg9ZGlzcGwsIHk9aHd5KSkKZ2dwbG90KGRhdGE9bXBnKSsKICBnZW9tX2JveHBsb3QoYWVzKHg9Y2xhc3MsIHk9ZGlzcGwpKQpnZ3Bsb3QoZGF0YT1tcGcpKwogIGdlb21faGlzdG9ncmFtKGFlcyh4PWh3eSkpCmBgYAoKIyMjIFN0YXQKCldoYXQgZG9lcyBnZW9tX2NvbCgpIGRvPyBIb3cgaXMgaXQgZGlmZmVyZW50IGZyb20gZ2VvbV9iYXIoKT8KCkxvb2sgYXQgdGhlIGRvY3VtZW50YXRpb24gZm9yIGdlb21fYmFyIHVzaW5nIGA/Z2VvbV9iYXJgCgoqICogKgoKV2UgbGVhcm50IHRoYXQgYGdlb21fKigpYCBhbmQgYHN0YXRfKigpYCBhcmUgaW50ZXJjaGFuZ2VhYmxlLiBDYW4geW91IGxvb2sgYXQgYD9nZW9tX2JhcigpYCBhbmQgZmlndXJlIG91dCB3aGljaApzdGF0IGl0IHVzZXMgYXMgZGVmYXVsdC4gTW9kaWZ5IHRoZSBjb2RlIGJlbG93IHRvIHVzZSB0aGF0IHN0YXQgZGlyZWN0bHkgaW5zdGVhZAoKYGBge3J9CmdncGxvdChtcGcpICsgCiAgZ2VvbV9iYXIoYWVzKHggPSBjbGFzcykpCmBgYAoKU29sdXRpb246ClRoZSBkZXNjcmlwdGlvbiBzYXlzICJnZW9tX2JhcigpIHVzZXMgc3RhdF9jb3VudCgpIGJ5IGRlZmF1bHQiLiBVc2luZyBpdCBkaXJlY3RseSBiZWxvdzoKYGBge3J9CmdncGxvdChtcGcpICsgCiAgc3RhdF9jb3VudChhZXMoeCA9IGNsYXNzKSkKYGBgCgoqICogKgpVc2UgYHN0YXRfc3VtbWFyeSgpYCB0byBhZGQgYSByZWQgZG90IGF0IHRoZSBtZWFuIGBod3lgIGZvciBlYWNoIGdyb3VwCgpgYGB7cn0KZ2dwbG90KG1wZykgKyAKICBnZW9tX2ppdHRlcihhZXMoeCA9IGNsYXNzLCB5ID0gaHd5KSwgd2lkdGggPSAwLjIpCmBgYApIaW50OiBZb3Ugd2lsbCBuZWVkIHRvIGNoYW5nZSB0aGUgZGVmYXVsdCBnZW9tIG9mIGBzdGF0X3N1bW1hcnkoKWAKClNvbHV0aW9uOgpgYGB7cn0KZ2dwbG90KG1wZywgYWVzKHg9Y2xhc3MsIHk9aHd5KSkgKyAKICBnZW9tX2ppdHRlcih3aWR0aCA9IDAuMikrCiAgc3RhdF9zdW1tYXJ5KGdlb20gPSAicG9pbnQiLCBmdW49Im1lYW4iLCBjb2xvcj0icmVkIikKYGBgCgoKKiAqICoKCkluIG91ciBwcm9wb3J0aW9uIGJhciBjaGFydCwgd2UgbmVlZCB0byBzZXQgZ3JvdXAgPSAxLiBXaHk/IEluIG90aGVyIHdvcmRzIHdoYXQgaXMgdGhlIHByb2JsZW0gd2l0aCB0aGVzZSB0d28gZ3JhcGhzPwpgYGB7cn0KcDE8LSBnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzKSArIAogIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoeCA9IGN1dCwgeSA9IGFmdGVyX3N0YXQocHJvcCkpKQoKcDI8LWdncGxvdChkYXRhID0gZGlhbW9uZHMpICsgCiAgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4ID0gY3V0LCBmaWxsID0gY29sb3IsIHkgPSBhZnRlcl9zdGF0KHByb3ApKSkKCnAxCnAyCmBgYAoKU29sdXRpb246CmlmIGdyb3VwID0gMSBpcyBub3QgaW5jbHVkZWQsIHRoZSBwcm9wb3J0aW9ucyB3aWxsIGJlIGNhbGN1bGF0ZWQgd2l0aGluIGVhY2ggZ3JvdXAuIE1vZGlmaWVkIGNvZGUgaXMgYmVsb3cuIApgYGB7cn0KcDFfbmV3PC0gZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKyAKICBnZW9tX2JhcihtYXBwaW5nID0gYWVzKHggPSBjdXQsIHkgPSBhZnRlcl9zdGF0KHByb3ApLCBncm91cD0xKSkKCnAyX25ldzwtZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKyAKICBnZW9tX2JhcihtYXBwaW5nID0gYWVzKHggPSBjdXQsIGZpbGwgPSBjb2xvciwgeSA9IC4uY291bnQuLiAvIHN1bSguLmNvdW50Li4pKSkKCnAxX25ldwpwMl9uZXcKYGBgCioqKgpXaGF0IGlzIHRoZSBwcm9ibGVtIHdpdGggdGhpcyBwbG90PyBIb3cgY291bGQgd2UgaW1wcm92ZSBpdD8KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gY3R5LCB5ID0gaHd5KSkgKyAKICBnZW9tX3BvaW50KCApCmBgYApTb2x1dGlvbjoKVGhlcmUgaXMgb3ZlcnBsb3R0aW5nIGJlY2F1c2UgdGhlcmUgYXJlIG11bHRpcGxlIG9ic2VydmF0aW9ucyBmb3IgZWFjaCBjb21iaW5hdGlvbiBvZiBgY3R5YCBhbmQgYGh3eWAgdmFsdWVzLiAKYGBge3J9CmdncGxvdChkYXRhID0gbXBnLCBtYXBwaW5nID0gYWVzKHggPSBjdHksIHkgPSBod3kpKSArIAogIGdlb21fcG9pbnQocG9zaXRpb249ImppdHRlciIgKQpgYGAKCiMjIyBTY2FsZXMKClVzZSBgUkNvbG9yQnJld2VyOjpkaXNwbGF5LmJyZXdlci5hbGwoKWAgdG8gc2VlIGFsbCB0aGUgZGlmZmVyZW50IHBhbGV0dGVzIGZyb20KQ29sb3IgQnJld2VyIGFuZCBwaWNrIHlvdXIgZmF2b3VyaXRlLiBNb2RpZnkgdGhlIGNvZGUgYmVsb3cgdG8gdXNlIGl0CgpgYGB7cn0KZ2dwbG90KG1wZykgKyAKICBnZW9tX3BvaW50KGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIGNvbG91ciA9IGNsYXNzKSkgKyAKICBzY2FsZV9jb2xvdXJfYnJld2VyKHR5cGUgPSAncXVhbCcpCmBgYAoKU29sdXRpb246CmBgYHtyfQpkYXRhKCJtcGciKQpnZ3Bsb3QobXBnKSArIAogIGdlb21fcG9pbnQoYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgY29sb3VyID0gY2xhc3MpKSArIAogIHNjYWxlX2NvbG91cl9icmV3ZXIodHlwZSA9ICdxdWFsJywgcGFsZXR0ZSA9ICJTZXQxIikKYGBgCiogKiAqCgpNb2RpZnkgdGhlIGNvZGUgYmVsb3cgdG8gY3JlYXRlIGEgYnViYmxlIGNoYXJ0IChzY2F0dGVycGxvdCB3aXRoIHNpemUgbWFwcGVkIHRvCmEgY29udGludW91cyB2YXJpYWJsZSkgc2hvd2luZyBgY3lsYCB3aXRoIHNpemUuIE1ha2Ugc3VyZSB0aGF0IG9ubHkgdGhlIHByZXNlbnQgCmFtb3VudCBvZiBjeWxpbmRlcnMgKDQsIDUsIDYsIGFuZCA4KSBhcmUgcHJlc2VudCBpbiB0aGUgbGVnZW5kLgoKYGBge3J9CmdncGxvdChtcGcpICsgCiAgZ2VvbV9wb2ludChhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBjb2xvdXIgPSBjbGFzcykpICsgCiAgc2NhbGVfY29sb3VyX2JyZXdlcih0eXBlID0gJ3F1YWwnKQpgYGAKCkhpbnQ6IFRoZSBgYnJlYWtzYCBhcmd1bWVudCBpbiB0aGUgc2NhbGUgaXMgdXNlZCB0byBjb250cm9sIHdoaWNoIHZhbHVlcyBhcmUKcHJlc2VudCBpbiB0aGUgbGVnZW5kLgoKU29sdXRpb246CmBgYHtyfQpnZ3Bsb3QobXBnKSArIAogIGdlb21fcG9pbnQoYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgY29sb3VyID0gY2xhc3MsIHNpemU9Y3lsKSkgKyAKICBzY2FsZV9jb2xvdXJfYnJld2VyKHR5cGUgPSAncXVhbCcpICsKICBzY2FsZV9zaXplKGJyZWFrcyA9IGMoNCwgNSwgNiwgOCkpCmBgYApFeHBsb3JlIHRoZSBkaWZmZXJlbnQgdHlwZXMgb2Ygc2l6ZSBzY2FsZXMgYXZhaWxhYmxlIGluIGdncGxvdDIuIElzIHRoZSBkZWZhdWx0CnRoZSBtb3N0IGFwcHJvcHJpYXRlIGhlcmU/CgpTb2x1dGlvbjoKRGVmYXVsdCBpcyBtYXBwaW5nIHRvIHRoZSByYWRpdXMuIEJ1dCBpdCBpcyBub3QgaW50dWl0aXZlLiBMZXQncyB0cnkgc2l6ZSBtYXBwaW5nIGJ5IGFyZWEuIApgYGB7cn0KZ2dwbG90KG1wZykgKyAKICBnZW9tX3BvaW50KGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIGNvbG91ciA9IGNsYXNzLCBzaXplPWN5bCkpICsgCiAgc2NhbGVfY29sb3VyX2JyZXdlcih0eXBlID0gJ3F1YWwnKSArCiAgc2NhbGVfc2l6ZV9hcmVhKGJyZWFrcyA9IGMoNCwgNSwgNiwgOCkpCmBgYAoqICogKgoKTW9kaWZ5IHRoZSBjb2RlIGJlbG93IHNvIHRoYXQgY29sb3VyIGlzIG5vIGxvbmdlciBtYXBwZWQgdG8gdGhlIGRpc2NyZXRlIGBjbGFzc2AKdmFyaWFibGUsIGJ1dCB0byB0aGUgY29udGludW91cyBgY3R5YCB2YXJpYWJsZS4gV2hhdCBoYXBwZW5zIHRvIHRoZSBndWlkZSAobGVnZW5kKT8KCmBgYHtyfQpnZ3Bsb3QobXBnKSArIAogIGdlb21fcG9pbnQoYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgY29sb3VyID0gY2xhc3MsIHNpemUgPSBjdHkpKQpgYGAKClNvbHV0aW9uOgpgYGB7cn0KZ2dwbG90KG1wZykgKyAKICBnZW9tX3BvaW50KGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIGNvbG91ciA9IGN0eSwgc2l6ZSA9IGN0eSkpCmBgYAoqICogKgoKVGhlIHR5cGUgb2YgZ3VpZGUgY2FuIGJlIGNvbnRyb2xsZWQgd2l0aCB0aGUgYGd1aWRlYCBhcmd1bWVudCBpbiB0aGUgc2NhbGUsIG9yIAp3aXRoIHRoZSBgZ3VpZGVzKClgIGZ1bmN0aW9uLiBDb250aW51b3VzIGNvbG91cnMgaGF2ZSBhIGdyYWRpZW50IGNvbG91ciBiYXIgYnkgCmRlZmF1bHQsIGJ1dCBzZXR0aW5nIGl0IHRvIGBsZWdlbmRgIHdpbGwgdHVybiBpdCBiYWNrIHRvIHRoZSBzdGFuZGFyZCBsb29rLiBXaGF0IApoYXBwZW5zIHdoZW4gbXVsdGlwbGUgYWVzdGhldGljcyBhcmUgbWFwcGVkIHRvIHRoZSBzYW1lIHZhcmlhYmxlIGFuZCB1c2VzIHRoZSAKZ3VpZGUgdHlwZT8KClNvbHV0aW9uOgoKYGBge3J9CmdncGxvdChtcGcpICsgCiAgZ2VvbV9wb2ludChhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBjb2xvdXIgPSBjdHksIHNpemUgPSBjdHkpKSsKICBndWlkZXMoY29sb3I9ImxlZ2VuZCIpCmBgYApnZ3Bsb3QgY29tYmluZXMgYm90aCBsZWdlbmRzLiAKCiMjIyBGYWNldHMKCk9uZSBvZiB0aGUgZ3JlYXQgdGhpbmdzIGFib3V0IGZhY2V0cyBpcyB0aGF0IHRoZXkgc2hhcmUgdGhlIGF4ZXMgYmV0d2VlbiB0aGUgCmRpZmZlcmVudCBwYW5lbHMuIFNvbWV0aW1lcyB0aGlzIGlzIHVuZGVzaXJhYmxlIHRob3VnaCwgYW5kIHRoZSBiZWhhdmlvciBjYW4KYmUgY2hhbmdlZCB3aXRoIHRoZSBgc2NhbGVzYCBhcmd1bWVudC4gRXhwZXJpbWVudCB3aXRoIHRoZSBkaWZmZXJlbnQgcG9zc2libGUKc2V0dGluZ3MgaW4gdGhlIHBsb3QgYmVsb3c6CgpgYGB7cn0KZ2dwbG90KG1wZykgKyAKICBnZW9tX3BvaW50KGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArIAogIGZhY2V0X3dyYXAofiBkcnYpCmBgYAoKU29sdXRpb246CmBgYHtyfQpnZ3Bsb3QobXBnKSArIAogIGdlb21fcG9pbnQoYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpICsgCiAgZmFjZXRfd3JhcCh+IGRydiwgc2NhbGVzPSJmcmVlX3kiKQpgYGAKKiAqICoKClVzdWFsbHkgdGhlIHNwYWNlIG9jY3VwaWVkIGJ5IGVhY2ggcGFuZWwgaXMgZXF1YWwuIFRoaXMgY2FuIGNyZWF0ZSBwcm9ibGVtcyB3aGVuCmRpZmZlcmVudCBzY2FsZXMgYXJlIHVzZWQuIENhbiB5b3UgbW9kaWZ5IHRoZSBjb2RlIGJlbG93IHNvIHRoYXQgdGhlIHkgc2NhbGUgZGlmZmVycyAKYmV0d2VlbiB0aGUgcGFuZWxzIGluIHRoZSBwbG90LiBXaGF0IGhhcHBlbnM/CgpgYGB7cn0KZ2dwbG90KG1wZykgKyAKICBnZW9tX2JhcihhZXMoeSA9IG1hbnVmYWN0dXJlcikpICsgCiAgZmFjZXRfZ3JpZChjbGFzcyB+IC4pCmBgYAoKVXNlIHRoZSBgc3BhY2VgIGFyZ3VtZW50IGluIGBmYWNldF9ncmlkKClgIHRvIGNoYW5nZSB0aGUgcGxvdCBhYm92ZSBzbyBlYWNoIGJhciAKaGFzIHRoZSBzYW1lIHdpZHRoIGFnYWluLgoKU29sdXRpb246CmBgYHtyfQpkYXRhKCJtcGciKQpnZ3Bsb3QobXBnKSArIAogIGdlb21fYmFyKGFlcyh5ID0gbWFudWZhY3R1cmVyKSkgKyAKICBmYWNldF9ncmlkKGNsYXNzIH4gLiwgc3BhY2UgPSAiZnJlZV95Iiwgc2NhbGVzID0gImZyZWVfeSIpCmBgYAoK