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