1. What is the default geom associated with stat_summary()? How could you rewrite the previous plot to use that geom function instead of the stat function?

The “previous plot” referred to in the question is the following.

suppressPackageStartupMessages(library(tidyverse))
package 㤼㸱tidyverse㤼㸲 was built under R version 3.6.3
ggplot(data = diamonds) +
  stat_summary(
    mapping = aes(x = cut, y = depth),
    fun.ymin = min,
    fun.ymax = max,
    fun.y = median
  )

The default geom for stat_summary() is geom_pointrange(). The default stat for geom_pointrange() is identity() but we can add the argument stat = "summary" to use stat_summary() instead of stat_identity().

ggplot(data = diamonds) +
  geom_pointrange(
    mapping = aes(x = cut, y = depth),
    stat = "summary"
  )

The resulting message says that stat_summary() uses the mean and sd to calculate the middle point and endpoints of the line. However, in the original plot the min and max values were used for the endpoints. To recreate the original plot we need to specify values for fun.ymin, fun.ymax, and fun.y.

ggplot(data = diamonds) +
  geom_pointrange(
    mapping = aes(x = cut, y = depth),
    stat = "summary",
    fun.ymin = min,
    fun.ymax = max,
    fun.y = median
  )

2. What does geom_col() do? How is it different to geom_bar()?

The geom_col() function has different default stat than geom_bar(). The default stat of geom_col() is stat_identity(), which leaves the data as is. The geom_col() function expects that the data contains x values and y values which represent the bar height.

The default stat of geom_bar() is stat_bin(). The geom_bar() function only expects an x variable. The stat, stat_bin(), preprocesses input data by counting the number of observations for each value of x. The y aesthetic uses the values of these counts.

3. Most geoms and stats come in pairs that are almost always used in concert. Read through the documentation and make a list of all the pairs. What do they have in common?

The following tables lists the pairs of geoms and stats that are almost always used in concert.

Complementary geoms and stats

geom stat
geom_bar() stat_count()
geom_bin2d() stat_bin_2d()
geom_boxplot() stat_boxplot()
geom_contour() stat_contour()
geom_count() stat_sum()
geom_density() stat_density()
geom_density_2d() stat_density_2d()
geom_hex() stat_hex()
geom_freqpoly() stat_bin()
geom_histogram() stat_bin()
geom_qq_line() stat_qq_line()
geom_qq() stat_qq()
geom_quantile() stat_quantile()
geom_smooth() stat_smooth()
geom_violin() stat_violin()
geom_sf() stat_sf()

They tend to have their names in common, stat_smooth() and geom_smooth(). However, this is not always the case, with geom_bar() and stat_count() and geom_histogram() and geom_bin() as notable counter-examples. Also, the pairs of geoms and stats that are used in concert almost always have each other as the default stat (for a geom) or geom (for a stat).

The following tables contain the geoms and stats in ggplot2.

ggplot2 geom layers and their default stats.

geom default stat shared docs
geom_abline()
geom_hline()
geom_vline()
geom_bar() stat_count() x
geom_col()
geom_bin2d() stat_bin_2d() x
geom_blank()
geom_boxplot() stat_boxplot() x
geom_countour() stat_countour() x
geom_count() stat_sum() x
geom_density() stat_density() x
geom_density_2d() stat_density_2d() x
geom_dotplot()
geom_errorbarh()
geom_hex() stat_hex() x
geom_freqpoly() stat_bin() x
geom_histogram() stat_bin() x
geom_crossbar()
geom_errorbar()
geom_linerange()
geom_pointrange()
geom_map()
geom_point()
geom_map()
geom_path()
geom_line()
geom_step()
geom_point()
geom_polygon()
geom_qq_line() stat_qq_line() x
geom_qq() stat_qq() x
geom_quantile() stat_quantile() x
geom_ribbon()
geom_area()
geom_rug()
geom_smooth() stat_smooth() x
geom_spoke()
geom_label()
geom_text()
geom_raster()
geom_rect()
geom_tile()
geom_violin() stat_ydensity() x
geom_sf() stat_sf() x

ggplot2 stat layers and their default geoms.

stat default geom shared docs
stat_ecdf() geom_step()
stat_ellipse() geom_path()
stat_function() geom_path()
stat_identity() geom_point()
stat_summary_2d() geom_tile()
stat_summary_hex() geom_hex()
stat_summary_bin() geom_pointrange()
stat_summary() geom_pointrange()
stat_unique() geom_point()
stat_count() geom_bar() x
stat_bin_2d() geom_tile() x
stat_boxplot() geom_boxplot() x
stat_countour() geom_contour() x
stat_sum() geom_point() x
stat_density() geom_area() x
stat_density_2d() geom_density_2d() x
stat_bin_hex() geom_hex() x
stat_bin() geom_bar() x
stat_qq_line() geom_path() x
stat_qq() geom_point() x
stat_quantile() geom_quantile() x
stat_smooth() geom_smooth() x
stat_ydensity() geom_violin() x
stat_sf() geom_rect() x

4. What variables does stat_smooth() compute? What parameters control its behavior?

The function stat_smooth() calculates the following variables:

  • y: predicted value
  • ymin: lower value of the confidence interval
  • ymax: upper value of the confidence interval
  • se: standard error

The “Computed Variables” section of the stat_smooth() documentation contains these variables.

The parameters that control the behavior of stat_smooth() include

  • method: the method used to
  • formula: the formula are parameters such as method which determines which method is used to calculate the predictions and confidence interval, and some other arguments that are passed to that.
  • na.rm:

5. In our proportion bar chart, we need to set group = 1 Why? In other words, what is the problem with these two graphs?

If group = 1 is not included, then all the bars in the plot will have the same height, a height of 1. The function geom_bar() assumes that the groups are equal to the x values since the stat computes the counts within the group.

ggplot(data = diamonds) +
  geom_bar(mapping = aes(x = cut, y = ..prop..))

The problem with these two plots is that the proportions are calculated within the groups.

ggplot(data = diamonds) +
  geom_bar(mapping = aes(x = cut, y = ..prop..))


ggplot(data = diamonds) +
  geom_bar(mapping = aes(x = cut, fill = color, y = ..prop..))

The following code will produce the intended stacked bar charts for the case with no fill aesthetic.

ggplot(data = diamonds) +
  geom_bar(mapping = aes(x = cut, y = ..prop.., group = 1))

With the fill aesthetic, the heights of the bars need to be normalized.

ggplot(data = diamonds) +
  geom_bar(aes(x = cut, y = ..count.. / sum(..count..), fill = color))

LS0tDQp0aXRsZTogIlN0YXRpc3RpY2FsIFRyYW5zZm9ybXMgRGVtbyINCm91dHB1dDogDQogIGh0bWxfbm90ZWJvb2s6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQotLS0NCg0KIyMjIDEuIFdoYXQgaXMgdGhlIGRlZmF1bHQgZ2VvbSBhc3NvY2lhdGVkIHdpdGggYHN0YXRfc3VtbWFyeSgpYD8gSG93IGNvdWxkIHlvdSByZXdyaXRlIHRoZSBwcmV2aW91cyBwbG90IHRvIHVzZSB0aGF0IGdlb20gZnVuY3Rpb24gaW5zdGVhZCBvZiB0aGUgc3RhdCBmdW5jdGlvbj8NCg0KVGhlIOKAnHByZXZpb3VzIHBsb3TigJ0gcmVmZXJyZWQgdG8gaW4gdGhlIHF1ZXN0aW9uIGlzIHRoZSBmb2xsb3dpbmcuDQpgYGB7ciBwcmV2aW91c30NCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KHRpZHl2ZXJzZSkpDQpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzKSArDQogIHN0YXRfc3VtbWFyeSgNCiAgICBtYXBwaW5nID0gYWVzKHggPSBjdXQsIHkgPSBkZXB0aCksDQogICAgZnVuLnltaW4gPSBtaW4sDQogICAgZnVuLnltYXggPSBtYXgsDQogICAgZnVuLnkgPSBtZWRpYW4NCiAgKQ0KYGBgDQoNClRoZSBkZWZhdWx0IGdlb20gZm9yIFtzdGF0X3N1bW1hcnkoKV0oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL3N0YXRfc3VtbWFyeS5odG1sKSBpcyBgZ2VvbV9wb2ludHJhbmdlKClgLiBUaGUgZGVmYXVsdCBzdGF0IGZvciBbZ2VvbV9wb2ludHJhbmdlKCldKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnL3JlZmVyZW5jZS9nZW9tX2xpbmVyYW5nZS5odG1sKSBpcyBgaWRlbnRpdHkoKWAgYnV0IHdlIGNhbiBhZGQgdGhlIGFyZ3VtZW50IGBzdGF0ID0gInN1bW1hcnkiYCB0byB1c2UgYHN0YXRfc3VtbWFyeSgpYCBpbnN0ZWFkIG9mIGBzdGF0X2lkZW50aXR5KClgLg0KDQpgYGB7ciBub3N1bW1hcnl9DQpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzKSArDQogIGdlb21fcG9pbnRyYW5nZSgNCiAgICBtYXBwaW5nID0gYWVzKHggPSBjdXQsIHkgPSBkZXB0aCksDQogICAgc3RhdCA9ICJzdW1tYXJ5Ig0KICApDQpgYGANCg0KVGhlIHJlc3VsdGluZyBtZXNzYWdlIHNheXMgdGhhdCBgc3RhdF9zdW1tYXJ5KClgIHVzZXMgdGhlIGBtZWFuYCBhbmQgYHNkYCB0byBjYWxjdWxhdGUgdGhlIG1pZGRsZSBwb2ludCBhbmQgZW5kcG9pbnRzIG9mIHRoZSBsaW5lLiBIb3dldmVyLCBpbiB0aGUgb3JpZ2luYWwgcGxvdCB0aGUgbWluIGFuZCBtYXggdmFsdWVzIHdlcmUgdXNlZCBmb3IgdGhlIGVuZHBvaW50cy4gVG8gcmVjcmVhdGUgdGhlIG9yaWdpbmFsIHBsb3Qgd2UgbmVlZCB0byBzcGVjaWZ5IHZhbHVlcyBmb3IgYGZ1bi55bWluYCwgYGZ1bi55bWF4YCwgYW5kIGBmdW4ueWAuDQoNCmBgYHtyIG5ld3ZhbHVlc30NCmdncGxvdChkYXRhID0gZGlhbW9uZHMpICsNCiAgZ2VvbV9wb2ludHJhbmdlKA0KICAgIG1hcHBpbmcgPSBhZXMoeCA9IGN1dCwgeSA9IGRlcHRoKSwNCiAgICBzdGF0ID0gInN1bW1hcnkiLA0KICAgIGZ1bi55bWluID0gbWluLA0KICAgIGZ1bi55bWF4ID0gbWF4LA0KICAgIGZ1bi55ID0gbWVkaWFuDQogICkNCmBgYA0KDQoNCiMjIyAyLiBXaGF0IGRvZXMgYGdlb21fY29sKClgIGRvPyBIb3cgaXMgaXQgZGlmZmVyZW50IHRvIGBnZW9tX2JhcigpYD8NCg0KVGhlIGBnZW9tX2NvbCgpYCBmdW5jdGlvbiBoYXMgZGlmZmVyZW50IGRlZmF1bHQgc3RhdCB0aGFuIGBnZW9tX2JhcigpYC4gVGhlIGRlZmF1bHQgc3RhdCBvZiBgZ2VvbV9jb2woKWAgaXMgYHN0YXRfaWRlbnRpdHkoKWAsIHdoaWNoIGxlYXZlcyB0aGUgZGF0YSBhcyBpcy4gVGhlIGBnZW9tX2NvbCgpYCBmdW5jdGlvbiBleHBlY3RzIHRoYXQgdGhlIGRhdGEgY29udGFpbnMgYHhgIHZhbHVlcyBhbmQgYHlgIHZhbHVlcyB3aGljaCByZXByZXNlbnQgdGhlIGJhciBoZWlnaHQuDQoNClRoZSBkZWZhdWx0IHN0YXQgb2YgYGdlb21fYmFyKClgIGlzIGBzdGF0X2JpbigpYC4gVGhlIGBnZW9tX2JhcigpYCBmdW5jdGlvbiBvbmx5IGV4cGVjdHMgYW4gYHhgIHZhcmlhYmxlLiBUaGUgc3RhdCwgYHN0YXRfYmluKClgLCBwcmVwcm9jZXNzZXMgaW5wdXQgZGF0YSBieSBjb3VudGluZyB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBmb3IgZWFjaCB2YWx1ZSBvZiBgeGAuIFRoZSBgeWAgYWVzdGhldGljIHVzZXMgdGhlIHZhbHVlcyBvZiB0aGVzZSBjb3VudHMuDQoNCiMjIyAzLiBNb3N0IGdlb21zIGFuZCBzdGF0cyBjb21lIGluIHBhaXJzIHRoYXQgYXJlIGFsbW9zdCBhbHdheXMgdXNlZCBpbiBjb25jZXJ0LiBSZWFkIHRocm91Z2ggdGhlIGRvY3VtZW50YXRpb24gYW5kIG1ha2UgYSBsaXN0IG9mIGFsbCB0aGUgcGFpcnMuIFdoYXQgZG8gdGhleSBoYXZlIGluIGNvbW1vbj8NCg0KVGhlIGZvbGxvd2luZyB0YWJsZXMgbGlzdHMgdGhlIHBhaXJzIG9mIGdlb21zIGFuZCBzdGF0cyB0aGF0IGFyZSBhbG1vc3QgYWx3YXlzIHVzZWQgaW4gY29uY2VydC4NCg0KKipDb21wbGVtZW50YXJ5IGdlb21zIGFuZCBzdGF0cyoqDQoNCnwgZ2VvbSAgICAgICAgICAgICAgICB8IHN0YXQgICAgICAgICAgICAgICAgfA0KfC0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS18DQp8IGBnZW9tX2JhcigpYCAgICAgICAgfCBgc3RhdF9jb3VudCgpYCAgICAgIHwNCnwgYGdlb21fYmluMmQoKWAgICAgICB8IGBzdGF0X2Jpbl8yZCgpYCAgICAgfA0KfCBgZ2VvbV9ib3hwbG90KClgICAgIHwgYHN0YXRfYm94cGxvdCgpYCAgICB8DQp8IGBnZW9tX2NvbnRvdXIoKWAgICAgfCBgc3RhdF9jb250b3VyKClgICAgIHwNCnwgYGdlb21fY291bnQoKWAgICAgICB8IGBzdGF0X3N1bSgpYCAgICAgICAgfA0KfCBgZ2VvbV9kZW5zaXR5KClgICAgIHwgYHN0YXRfZGVuc2l0eSgpYCAgICB8DQp8IGBnZW9tX2RlbnNpdHlfMmQoKWAgfCBgc3RhdF9kZW5zaXR5XzJkKClgIHwNCnwgYGdlb21faGV4KClgICAgICAgICB8IGBzdGF0X2hleCgpYCAgICAgICAgfA0KfCBgZ2VvbV9mcmVxcG9seSgpYCAgIHwgYHN0YXRfYmluKClgICAgICAgICB8DQp8IGBnZW9tX2hpc3RvZ3JhbSgpYCAgfCBgc3RhdF9iaW4oKWAgICAgICAgIHwNCnwgYGdlb21fcXFfbGluZSgpYCAgICB8IGBzdGF0X3FxX2xpbmUoKWAgICAgfA0KfCBgZ2VvbV9xcSgpYCAgICAgICAgIHwgYHN0YXRfcXEoKWAgICAgICAgICB8DQp8IGBnZW9tX3F1YW50aWxlKClgICAgfCBgc3RhdF9xdWFudGlsZSgpYCAgIHwNCnwgYGdlb21fc21vb3RoKClgICAgICB8IGBzdGF0X3Ntb290aCgpYCAgICAgfA0KfCBgZ2VvbV92aW9saW4oKWAgICAgIHwgYHN0YXRfdmlvbGluKClgICAgICB8DQp8IGBnZW9tX3NmKClgICAgICAgICAgfCBgc3RhdF9zZigpYCAgICAgICAgIHwNCg0KVGhleSB0ZW5kIHRvIGhhdmUgdGhlaXIgbmFtZXMgaW4gY29tbW9uLCBgc3RhdF9zbW9vdGgoKWAgYW5kIGBnZW9tX3Ntb290aCgpYC4gSG93ZXZlciwgdGhpcyBpcyBub3QgYWx3YXlzIHRoZSBjYXNlLCB3aXRoIGBnZW9tX2JhcigpYCBhbmQgYHN0YXRfY291bnQoKWAgYW5kIGBnZW9tX2hpc3RvZ3JhbSgpYCBhbmQgYGdlb21fYmluKClgIGFzIG5vdGFibGUgY291bnRlci1leGFtcGxlcy4gQWxzbywgdGhlIHBhaXJzIG9mIGdlb21zIGFuZCBzdGF0cyB0aGF0IGFyZSB1c2VkIGluIGNvbmNlcnQgYWxtb3N0IGFsd2F5cyBoYXZlIGVhY2ggb3RoZXIgYXMgdGhlIGRlZmF1bHQgc3RhdCAoZm9yIGEgZ2VvbSkgb3IgZ2VvbSAoZm9yIGEgc3RhdCkuDQoNClRoZSBmb2xsb3dpbmcgdGFibGVzIGNvbnRhaW4gdGhlIGdlb21zIGFuZCBzdGF0cyBpbiBbZ2dwbG90Ml0oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlLykuDQoNCioqZ2dwbG90MiBnZW9tIGxheWVycyBhbmQgdGhlaXIgZGVmYXVsdCBzdGF0cy4qKg0KDQp8IGdlb20gICAgICAgICAgICAgICAgfCBkZWZhdWx0IHN0YXQgICAgICB8IHNoYXJlZCBkb2NzIHwNCnwtLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tfA0KfCBgZ2VvbV9hYmxpbmUoKWAgICAgIHwgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICB8DQp8IGBnZW9tX2hsaW5lKClgICAgICAgfCAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgIHwNCnwgYGdlb21fdmxpbmUoKWAgICAgICB8ICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgfA0KfCBgZ2VvbV9iYXIoKWAgICAgICAgIHwgYHN0YXRfY291bnQoKWAgICAgICB8IHggICAgICAgICAgIHwNCnwgYGdlb21fY29sKClgICAgICAgICB8ICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgfA0KfCBgZ2VvbV9iaW4yZCgpYCAgICAgIHwgYHN0YXRfYmluXzJkKClgICAgICB8IHggICAgICAgICAgIHwNCnwgYGdlb21fYmxhbmsoKWAgICAgICB8ICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgfA0KfCBgZ2VvbV9ib3hwbG90KClgICAgIHwgYHN0YXRfYm94cGxvdCgpYCAgICB8IHggICAgICAgICAgIHwNCnwgYGdlb21fY291bnRvdXIoKWAgICB8IGBzdGF0X2NvdW50b3VyKClgICAgfCB4ICAgICAgICAgICB8DQp8IGBnZW9tX2NvdW50KClgICAgICAgfCBgc3RhdF9zdW0oKWAgICAgICAgIHwgeCAgICAgICAgICAgfA0KfCBgZ2VvbV9kZW5zaXR5KClgICAgIHwgYHN0YXRfZGVuc2l0eSgpYCAgICB8IHggICAgICAgICAgIHwNCnwgYGdlb21fZGVuc2l0eV8yZCgpYCB8IGBzdGF0X2RlbnNpdHlfMmQoKWAgfCB4ICAgICAgICAgICB8DQp8IGBnZW9tX2RvdHBsb3QoKWAgICAgfCAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgIHwNCnwgYGdlb21fZXJyb3JiYXJoKClgICB8ICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgfA0KfCBgZ2VvbV9oZXgoKWAgICAgICAgIHwgYHN0YXRfaGV4KClgICAgICAgICB8IHggICAgICAgICAgIHwNCnwgYGdlb21fZnJlcXBvbHkoKWAgICB8IGBzdGF0X2JpbigpYCAgICAgICAgfCB4ICAgICAgICAgICB8DQp8IGBnZW9tX2hpc3RvZ3JhbSgpYCAgfCBgc3RhdF9iaW4oKWAgICAgICAgIHwgeCAgICAgICAgICAgfA0KfCBgZ2VvbV9jcm9zc2JhcigpYCAgIHwgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICB8DQp8IGBnZW9tX2Vycm9yYmFyKClgICAgfCAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgIHwNCnwgYGdlb21fbGluZXJhbmdlKClgICB8ICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgfA0KfCBgZ2VvbV9wb2ludHJhbmdlKClgIHwgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICB8DQp8IGBnZW9tX21hcCgpYCAgICAgICAgfCAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgIHwNCnwgYGdlb21fcG9pbnQoKWAgICAgICB8ICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgfA0KfCBgZ2VvbV9tYXAoKWAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICB8DQp8IGBnZW9tX3BhdGgoKWAgICAgICAgfCAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgIHwNCnwgYGdlb21fbGluZSgpYCAgICAgICB8ICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgfA0KfCBgZ2VvbV9zdGVwKClgICAgICAgIHwgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICB8DQp8IGBnZW9tX3BvaW50KClgICAgICAgfCAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgIHwNCnwgYGdlb21fcG9seWdvbigpYCAgICB8ICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgfA0KfCBgZ2VvbV9xcV9saW5lKClgICAgIHwgYHN0YXRfcXFfbGluZSgpYCAgICB8IHggICAgICAgICAgIHwNCnwgYGdlb21fcXEoKWAgICAgICAgICB8IGBzdGF0X3FxKClgICAgICAgICAgfCB4ICAgICAgICAgICB8DQp8IGBnZW9tX3F1YW50aWxlKClgICAgfCBgc3RhdF9xdWFudGlsZSgpYCAgIHwgeCAgICAgICAgICAgfA0KfCBgZ2VvbV9yaWJib24oKWAgICAgIHwgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICB8DQp8IGBnZW9tX2FyZWEoKWAgICAgICAgfCAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgIHwNCnwgYGdlb21fcnVnKClgICAgICAgICB8ICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgfA0KfCBgZ2VvbV9zbW9vdGgoKWAgICAgIHwgYHN0YXRfc21vb3RoKClgICAgICB8IHggICAgICAgICAgIHwNCnwgYGdlb21fc3Bva2UoKWAgICAgICB8ICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgfA0KfCBgZ2VvbV9sYWJlbCgpYCAgICAgIHwgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICB8DQp8IGBnZW9tX3RleHQoKWAgICAgICAgfCAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgIHwNCnwgYGdlb21fcmFzdGVyKClgICAgICB8ICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgfA0KfCBgZ2VvbV9yZWN0KClgICAgICAgIHwgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICB8DQp8IGBnZW9tX3RpbGUoKWAgICAgICAgfCAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgIHwNCnwgYGdlb21fdmlvbGluKClgICAgICB8IGBzdGF0X3lkZW5zaXR5KClgICAgfCB4ICAgICAgICAgICB8DQp8IGBnZW9tX3NmKClgICAgICAgICAgfCBgc3RhdF9zZigpYCAgICAgICAgIHwgeCAgICAgICAgICAgfA0KDQoqKmdncGxvdDIgc3RhdCBsYXllcnMgYW5kIHRoZWlyIGRlZmF1bHQgZ2VvbXMuKioNCg0KfCBzdGF0ICAgICAgICAgICAgICAgICB8IGRlZmF1bHQgZ2VvbSAgICAgICAgfCBzaGFyZWQgZG9jcyB8DQp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLXwNCnwgYHN0YXRfZWNkZigpYCAgICAgICAgfCBgZ2VvbV9zdGVwKClgICAgICAgIHwgICAgICAgICAgICAgfA0KfCBgc3RhdF9lbGxpcHNlKClgICAgICB8IGBnZW9tX3BhdGgoKWAgICAgICAgfCAgICAgICAgICAgICB8DQp8IGBzdGF0X2Z1bmN0aW9uKClgICAgIHwgYGdlb21fcGF0aCgpYCAgICAgICB8ICAgICAgICAgICAgIHwNCnwgYHN0YXRfaWRlbnRpdHkoKWAgICAgfCBgZ2VvbV9wb2ludCgpYCAgICAgIHwgICAgICAgICAgICAgfA0KfCBgc3RhdF9zdW1tYXJ5XzJkKClgICB8IGBnZW9tX3RpbGUoKWAgICAgICAgfCAgICAgICAgICAgICB8DQp8IGBzdGF0X3N1bW1hcnlfaGV4KClgIHwgYGdlb21faGV4KClgICAgICAgICB8ICAgICAgICAgICAgIHwNCnwgYHN0YXRfc3VtbWFyeV9iaW4oKWAgfCBgZ2VvbV9wb2ludHJhbmdlKClgIHwgICAgICAgICAgICAgfA0KfCBgc3RhdF9zdW1tYXJ5KClgICAgICB8IGBnZW9tX3BvaW50cmFuZ2UoKWAgfCAgICAgICAgICAgICB8DQp8IGBzdGF0X3VuaXF1ZSgpYCAgICAgIHwgYGdlb21fcG9pbnQoKWAgICAgICB8ICAgICAgICAgICAgIHwNCnwgYHN0YXRfY291bnQoKWAgICAgICAgfCBgZ2VvbV9iYXIoKWAgICAgICAgIHwgeCAgICAgICAgICAgfA0KfCBgc3RhdF9iaW5fMmQoKWAgICAgICB8IGBnZW9tX3RpbGUoKWAgICAgICAgfCB4ICAgICAgICAgICB8DQp8IGBzdGF0X2JveHBsb3QoKWAgICAgIHwgYGdlb21fYm94cGxvdCgpYCAgICB8IHggICAgICAgICAgIHwNCnwgYHN0YXRfY291bnRvdXIoKWAgICAgfCBgZ2VvbV9jb250b3VyKClgICAgIHwgeCAgICAgICAgICAgfA0KfCBgc3RhdF9zdW0oKWAgICAgICAgICB8IGBnZW9tX3BvaW50KClgICAgICAgfCB4ICAgICAgICAgICB8DQp8IGBzdGF0X2RlbnNpdHkoKWAgICAgIHwgYGdlb21fYXJlYSgpYCAgICAgICB8IHggICAgICAgICAgIHwNCnwgYHN0YXRfZGVuc2l0eV8yZCgpYCAgfCBgZ2VvbV9kZW5zaXR5XzJkKClgIHwgeCAgICAgICAgICAgfA0KfCBgc3RhdF9iaW5faGV4KClgICAgICB8IGBnZW9tX2hleCgpYCAgICAgICAgfCB4ICAgICAgICAgICB8DQp8IGBzdGF0X2JpbigpYCAgICAgICAgIHwgYGdlb21fYmFyKClgICAgICAgICB8IHggICAgICAgICAgIHwNCnwgYHN0YXRfcXFfbGluZSgpYCAgICAgfCBgZ2VvbV9wYXRoKClgICAgICAgIHwgeCAgICAgICAgICAgfA0KfCBgc3RhdF9xcSgpYCAgICAgICAgICB8IGBnZW9tX3BvaW50KClgICAgICAgfCB4ICAgICAgICAgICB8DQp8IGBzdGF0X3F1YW50aWxlKClgICAgIHwgYGdlb21fcXVhbnRpbGUoKWAgICB8IHggICAgICAgICAgIHwNCnwgYHN0YXRfc21vb3RoKClgICAgICAgfCBgZ2VvbV9zbW9vdGgoKWAgICAgIHwgeCAgICAgICAgICAgfA0KfCBgc3RhdF95ZGVuc2l0eSgpYCAgICB8IGBnZW9tX3Zpb2xpbigpYCAgICAgfCB4ICAgICAgICAgICB8DQp8IGBzdGF0X3NmKClgICAgICAgICAgIHwgYGdlb21fcmVjdCgpYCAgICAgICB8IHggICAgICAgICAgIHwNCg0KDQojIyMgNC4gV2hhdCB2YXJpYWJsZXMgZG9lcyBgc3RhdF9zbW9vdGgoKWAgY29tcHV0ZT8gV2hhdCBwYXJhbWV0ZXJzIGNvbnRyb2wgaXRzIGJlaGF2aW9yPw0KDQpUaGUgZnVuY3Rpb24gYHN0YXRfc21vb3RoKClgIGNhbGN1bGF0ZXMgdGhlIGZvbGxvd2luZyB2YXJpYWJsZXM6DQoNCiAtIGB5YDogcHJlZGljdGVkIHZhbHVlDQogLSBgeW1pbmA6IGxvd2VyIHZhbHVlIG9mIHRoZSBjb25maWRlbmNlIGludGVydmFsDQogLSBgeW1heGA6IHVwcGVyIHZhbHVlIG9mIHRoZSBjb25maWRlbmNlIGludGVydmFsDQogLSBgc2VgOiBzdGFuZGFyZCBlcnJvcg0KDQpUaGUg4oCcQ29tcHV0ZWQgVmFyaWFibGVz4oCdIHNlY3Rpb24gb2YgdGhlIGBzdGF0X3Ntb290aCgpYCBkb2N1bWVudGF0aW9uIGNvbnRhaW5zIHRoZXNlIHZhcmlhYmxlcy4NCg0KVGhlIHBhcmFtZXRlcnMgdGhhdCBjb250cm9sIHRoZSBiZWhhdmlvciBvZiBgc3RhdF9zbW9vdGgoKWAgaW5jbHVkZQ0KDQogLSBgbWV0aG9kYDogdGhlIG1ldGhvZCB1c2VkIHRvDQogLSBgZm9ybXVsYWA6IHRoZSBmb3JtdWxhIGFyZSBwYXJhbWV0ZXJzIHN1Y2ggYXMgbWV0aG9kIHdoaWNoIGRldGVybWluZXMgd2hpY2ggbWV0aG9kIGlzIHVzZWQgdG8gY2FsY3VsYXRlIHRoZSBwcmVkaWN0aW9ucyBhbmQgY29uZmlkZW5jZSBpbnRlcnZhbCwgYW5kIHNvbWUgb3RoZXIgYXJndW1lbnRzIHRoYXQgYXJlIHBhc3NlZCB0byB0aGF0Lg0KIC0gYG5hLnJtYDoNCg0KIyMjIDUuIEluIG91ciBwcm9wb3J0aW9uIGJhciBjaGFydCwgd2UgbmVlZCB0byBzZXQgYGdyb3VwID0gMWAgV2h5PyBJbiBvdGhlciB3b3Jkcywgd2hhdCBpcyB0aGUgcHJvYmxlbSB3aXRoIHRoZXNlIHR3byBncmFwaHM/DQoNCklmIGBncm91cCA9IDFgIGlzIG5vdCBpbmNsdWRlZCwgdGhlbiBhbGwgdGhlIGJhcnMgaW4gdGhlIHBsb3Qgd2lsbCBoYXZlIHRoZSBzYW1lIGhlaWdodCwgYSBoZWlnaHQgb2YgMS4gVGhlIGZ1bmN0aW9uIGBnZW9tX2JhcigpYCBhc3N1bWVzIHRoYXQgdGhlIGdyb3VwcyBhcmUgZXF1YWwgdG8gdGhlIGB4YCB2YWx1ZXMgc2luY2UgdGhlIHN0YXQgY29tcHV0ZXMgdGhlIGNvdW50cyB3aXRoaW4gdGhlIGdyb3VwLg0KDQpgYGB7ciBkaWFtb25kc30NCmdncGxvdChkYXRhID0gZGlhbW9uZHMpICsNCiAgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4ID0gY3V0LCB5ID0gLi5wcm9wLi4pKQ0KYGBgDQoNClRoZSBwcm9ibGVtIHdpdGggdGhlc2UgdHdvIHBsb3RzIGlzIHRoYXQgdGhlIHByb3BvcnRpb25zIGFyZSBjYWxjdWxhdGVkIHdpdGhpbiB0aGUgZ3JvdXBzLg0KDQpgYGB7ciB0d29wbG90c30NCmdncGxvdChkYXRhID0gZGlhbW9uZHMpICsNCiAgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4ID0gY3V0LCB5ID0gLi5wcm9wLi4pKQ0KDQpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzKSArDQogIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoeCA9IGN1dCwgZmlsbCA9IGNvbG9yLCB5ID0gLi5wcm9wLi4pKQ0KYGBgDQoNClRoZSBmb2xsb3dpbmcgY29kZSB3aWxsIHByb2R1Y2UgdGhlIGludGVuZGVkIHN0YWNrZWQgYmFyIGNoYXJ0cyBmb3IgdGhlIGNhc2Ugd2l0aCBubyBgZmlsbGAgYWVzdGhldGljLg0KDQpgYGB7ciBub2ZpbGx9DQpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzKSArDQogIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoeCA9IGN1dCwgeSA9IC4ucHJvcC4uLCBncm91cCA9IDEpKQ0KYGBgDQoNCldpdGggdGhlIGBmaWxsYCBhZXN0aGV0aWMsIHRoZSBoZWlnaHRzIG9mIHRoZSBiYXJzIG5lZWQgdG8gYmUgbm9ybWFsaXplZC4NCg0KYGBge3Igbm9ybWFsfQ0KZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKw0KICBnZW9tX2JhcihhZXMoeCA9IGN1dCwgeSA9IC4uY291bnQuLiAvIHN1bSguLmNvdW50Li4pLCBmaWxsID0gY29sb3IpKQ0KYGBgDQoNCg0K