1. Election Results

The votes for Iowa and nearby states:

library(dplyr)
library(ggplot2)
election2020 <- read.csv("election2020.csv")
state_abb <- data.frame(state = state.name, abb = state.abb)
election <- left_join(election2020, state_abb, "state")
nearby_states <- c("IA", "IL", "WI", "MN", "SD", "MO", "NE")
election_nearby <- filter(election, abb %in% nearby_states) %>%
    mutate(candidate = factor(candidate, c("Biden", "Other", "Trump")))

select(election_nearby, state, candidate, votes) %>%
    tidyr::pivot_wider(names_from = "candidate", values_from = "votes") %>%
    gt::gt()
state Biden Other Trump
Illinois 3471915 114937 2446891
Iowa 759061 43397 897672
Minnesota 1717077 76029 1484065
Missouri 1253014 54212 1718736
Nebraska 374583 24954 556846
South Dakota 150471 11095 261043
Wisconsin 1630866 56991 1610184

The three plots:

p <- ggplot(election_nearby, aes(x = state, y = votes, fill = candidate)) +
    scale_fill_manual(values = c(Trump = scales::muted("red"),
                                 Biden = scales::muted("blue"),
                                 Other = "grey")) +
    labs(x = "") +
    theme_minimal() +
    theme(axis.text.x = element_text(angle = 45, hjust = 1))

p_bar <- p + geom_col()
p_fill <- p + geom_col(position = "fill")
library(ggmosaic)
p_spine <- p +
    geom_mosaic(aes(x = product(abb), weight = votes, fill = candidate))
library(patchwork)
(p_bar + guides(fill = "none") + labs(title = "Stacked Bar Chart")) +
    (p_fill + guides(fill = "none") + labs(title = "Filled Bar Chart")) +
    (p_spine + labs(title = "Spine Plot"))
## Warning: `unite_()` was deprecated in tidyr 1.2.0.
## Please use `unite()` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was generated.

The stacked bar chart clearly shows the differing vote totals, but does not make it easy to compare vote proportions from one state to another. The filled version makes comparing proportions easy but does not show the differing vote totals. The spine chart also makes comparing proportions across states easy, and also reflects the differing vote totals in the widths of the bars. For the stated purpose the spine chart is the best choice.

2. Gapminder Tooltips

First create the plot object with a text aesthetic mapped to country:

library(dplyr)
library(ggplot2)
theme_set(theme_minimal() + theme(text = element_text(size = 16)))
library(gapminder)
gap <- filter(gapminder, year %% 10 == 7 & year >= 1977)
p <- ggplot(gap, aes(x = gdpPercap, y = lifeExp,
                     color = continent,
                     size = pop,
                     text = country)) +
    geom_point() +
    scale_size_area(max_size = 8) +
    scale_x_log10() +
    facet_wrap(~ year)

Then specify the text aesthetic as the tooltip in the ggplotly call. The style function from plotly can be used to adjust the background color.

library(plotly)
pp <- ggplotly(p, tooltip = "text")
style(pp, hoverlabel = list(bgcolor = "white"))

3. Cancellations and Destination Location

For the first three months of 2013, compute the number of flights, the average arrival delay, and the proportion of canceled flights to each of the destinations. Assume a flight is canceled it its departure time and arrival time are both missing.

It is useful to add a canceled variable to the flights table, assuming that canceled flights are those with both dep_time and arr_time missing:

library(dplyr)
library(nycflights13)
flights <- mutate(flights, canceled = is.na(dep_time) & is.na(arr_time))

For each destination and the first three months, compute the number of flights, percent canceled, and average arrival delay:

fl3 <- filter(flights, month <= 3) %>%
    group_by(dest) %>%
    summarize(n = n(),
              pcan = 100 * mean(canceled),
              delay = mean(arr_delay, na.rm = TRUE)) %>%
    ungroup()

Focus on the top 50 destinations in terms of the number of flights from NYC during the first three months of 2013.

fl3_50 <- top_n(fl3, 50, n)

Create a map with a point at each of these destinations, and encode the proportion of canceled flights in the point’s size. Comment on what you see.

To show the data on a map, add location information by joining with data from the airports table:

fl3_50 <- left_join(fl3_50,
                    select(airports, faa, lat, lon, alt),
                    c("dest" = "faa"))

A map showing the cancellation percentages for the top 50 destinations:

library(ggplot2)
pm <- ggplot(fl3_50, aes(x = lon, y = lat)) +
    borders("state") +
    coord_map() +
    theme_void()
pm + geom_point(aes(size = pcan)) + scale_size_area()
## Warning: Removed 1 rows containing missing values (geom_point).

Using alpha blending can help with the over-plotting along the east coast:

pm + geom_point(aes(size = pcan), alpha = 0.3) + scale_size_area()
## Warning: Removed 1 rows containing missing values (geom_point).

Cancellation percentages are higher for closer airports and airports likely to be experiencing similar weather conditions.

In addition to the location and proportion of canceled flights, whether the average arrival delay is more or less than 20 minutes could be encoded using color or shape. Try both approaches, comment on what you see and on the advantages and disadvantages of each approach.

Whether the average delay is 20 minutes or more can be encoded in using color or shape:

pm + geom_point(aes(size = pcan, color = delay >= 20)) + scale_size_area()
## Warning: Removed 1 rows containing missing values (geom_point).

pm + geom_point(aes(size = pcan, shape = delay >= 20)) + scale_size_area()
## Warning: Removed 1 rows containing missing values (geom_point).

For a 15 minute cutoff there are a few more high delay destinations:

pm + geom_point(aes(size = pcan, color = delay >= 15)) + scale_size_area()
## Warning: Removed 1 rows containing missing values (geom_point).

pm + geom_point(aes(size = pcan, shape = delay >= 15)) + scale_size_area()
## Warning: Removed 1 rows containing missing values (geom_point).

The size and shape channels interfere with each other quite a bit; color and size interfere with each other much less. Picking out the rarer shapes is also harder than spotting the different colors: color achieves better pop-out.

LS0tCnRpdGxlOiAiQXNzaWdubWVudCA3IE5vdGVzIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6ICJoaWRlIgotLS0KCSAgCmBgYHtyIGdsb2JhbF9vcHRpb25zLCBpbmNsdWRlID0gRkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChjb2xsYXBzZSA9IFRSVUUsIGZpZy5hbGlnbiA9ICJjZW50ZXIiKQpgYGAKCiMjIDEuIEVsZWN0aW9uIFJlc3VsdHMKCgpUaGUgdm90ZXMgZm9yIElvd2EgYW5kIG5lYXJieSBzdGF0ZXM6CgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFfQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGdncGxvdDIpCmVsZWN0aW9uMjAyMCA8LSByZWFkLmNzdigiZWxlY3Rpb24yMDIwLmNzdiIpCnN0YXRlX2FiYiA8LSBkYXRhLmZyYW1lKHN0YXRlID0gc3RhdGUubmFtZSwgYWJiID0gc3RhdGUuYWJiKQplbGVjdGlvbiA8LSBsZWZ0X2pvaW4oZWxlY3Rpb24yMDIwLCBzdGF0ZV9hYmIsICJzdGF0ZSIpCm5lYXJieV9zdGF0ZXMgPC0gYygiSUEiLCAiSUwiLCAiV0kiLCAiTU4iLCAiU0QiLCAiTU8iLCAiTkUiKQplbGVjdGlvbl9uZWFyYnkgPC0gZmlsdGVyKGVsZWN0aW9uLCBhYmIgJWluJSBuZWFyYnlfc3RhdGVzKSAlPiUKICAgIG11dGF0ZShjYW5kaWRhdGUgPSBmYWN0b3IoY2FuZGlkYXRlLCBjKCJCaWRlbiIsICJPdGhlciIsICJUcnVtcCIpKSkKCnNlbGVjdChlbGVjdGlvbl9uZWFyYnksIHN0YXRlLCBjYW5kaWRhdGUsIHZvdGVzKSAlPiUKICAgIHRpZHlyOjpwaXZvdF93aWRlcihuYW1lc19mcm9tID0gImNhbmRpZGF0ZSIsIHZhbHVlc19mcm9tID0gInZvdGVzIikgJT4lCiAgICBndDo6Z3QoKQpgYGAKClRoZSB0aHJlZSBwbG90czoKCgpgYGB7ciwgZmlnLndpZHRoID0gMTEsIGZpZy5oZWlnaHQgPSA0fQpwIDwtIGdncGxvdChlbGVjdGlvbl9uZWFyYnksIGFlcyh4ID0gc3RhdGUsIHkgPSB2b3RlcywgZmlsbCA9IGNhbmRpZGF0ZSkpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoVHJ1bXAgPSBzY2FsZXM6Om11dGVkKCJyZWQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQmlkZW4gPSBzY2FsZXM6Om11dGVkKCJibHVlIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE90aGVyID0gImdyZXkiKSkgKwogICAgbGFicyh4ID0gIiIpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQoKcF9iYXIgPC0gcCArIGdlb21fY29sKCkKcF9maWxsIDwtIHAgKyBnZW9tX2NvbChwb3NpdGlvbiA9ICJmaWxsIikKbGlicmFyeShnZ21vc2FpYykKcF9zcGluZSA8LSBwICsKICAgIGdlb21fbW9zYWljKGFlcyh4ID0gcHJvZHVjdChhYmIpLCB3ZWlnaHQgPSB2b3RlcywgZmlsbCA9IGNhbmRpZGF0ZSkpCmxpYnJhcnkocGF0Y2h3b3JrKQoocF9iYXIgKyBndWlkZXMoZmlsbCA9ICJub25lIikgKyBsYWJzKHRpdGxlID0gIlN0YWNrZWQgQmFyIENoYXJ0IikpICsKICAgIChwX2ZpbGwgKyBndWlkZXMoZmlsbCA9ICJub25lIikgKyBsYWJzKHRpdGxlID0gIkZpbGxlZCBCYXIgQ2hhcnQiKSkgKwogICAgKHBfc3BpbmUgKyBsYWJzKHRpdGxlID0gIlNwaW5lIFBsb3QiKSkKYGBgCgpUaGUgc3RhY2tlZCBiYXIgY2hhcnQgY2xlYXJseSBzaG93cyB0aGUgZGlmZmVyaW5nIHZvdGUgdG90YWxzLCBidXQKZG9lcyBub3QgbWFrZSBpdCBlYXN5IHRvIGNvbXBhcmUgdm90ZSBwcm9wb3J0aW9ucyBmcm9tIG9uZSBzdGF0ZSB0bwphbm90aGVyLiBUaGUgZmlsbGVkIHZlcnNpb24gbWFrZXMgY29tcGFyaW5nIHByb3BvcnRpb25zIGVhc3kgYnV0IGRvZXMKbm90IHNob3cgdGhlIGRpZmZlcmluZyB2b3RlIHRvdGFscy4gVGhlIHNwaW5lIGNoYXJ0IGFsc28gbWFrZXMKY29tcGFyaW5nIHByb3BvcnRpb25zIGFjcm9zcyBzdGF0ZXMgZWFzeSwgYW5kIGFsc28gcmVmbGVjdHMgdGhlCmRpZmZlcmluZyB2b3RlIHRvdGFscyBpbiB0aGUgd2lkdGhzIG9mIHRoZSBiYXJzLiBGb3IgdGhlIHN0YXRlZApwdXJwb3NlIHRoZSBzcGluZSBjaGFydCBpcyB0aGUgYmVzdCBjaG9pY2UuCgojIyAyLiBHYXBtaW5kZXIgVG9vbHRpcHMKCkZpcnN0IGNyZWF0ZSB0aGUgcGxvdCBvYmplY3Qgd2l0aCBhIGB0ZXh0YCBhZXN0aGV0aWMgbWFwcGVkIHRvIGBjb3VudHJ5YDoKCmBgYHtyLCBtZXNzYWdlID0gRkFMU0V9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKdGhlbWVfc2V0KHRoZW1lX21pbmltYWwoKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSkpCmxpYnJhcnkoZ2FwbWluZGVyKQpnYXAgPC0gZmlsdGVyKGdhcG1pbmRlciwgeWVhciAlJSAxMCA9PSA3ICYgeWVhciA+PSAxOTc3KQpwIDwtIGdncGxvdChnYXAsIGFlcyh4ID0gZ2RwUGVyY2FwLCB5ID0gbGlmZUV4cCwKICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBjb250aW5lbnQsCiAgICAgICAgICAgICAgICAgICAgIHNpemUgPSBwb3AsCiAgICAgICAgICAgICAgICAgICAgIHRleHQgPSBjb3VudHJ5KSkgKwogICAgZ2VvbV9wb2ludCgpICsKICAgIHNjYWxlX3NpemVfYXJlYShtYXhfc2l6ZSA9IDgpICsKICAgIHNjYWxlX3hfbG9nMTAoKSArCiAgICBmYWNldF93cmFwKH4geWVhcikKYGBgCgpUaGVuIHNwZWNpZnkgdGhlIGB0ZXh0YCBhZXN0aGV0aWMgYXMgdGhlIGB0b29sdGlwYCBpbiB0aGUgYGdncGxvdGx5YApjYWxsLiAgVGhlIGBzdHlsZWAgZnVuY3Rpb24gZnJvbSBgcGxvdGx5YCBjYW4gYmUgdXNlZCB0byBhZGp1c3QgdGhlCmJhY2tncm91bmQgY29sb3IuCgoKYGBge3IsIG1lc3NhZ2UgPSBGQUxTRX0KbGlicmFyeShwbG90bHkpCnBwIDwtIGdncGxvdGx5KHAsIHRvb2x0aXAgPSAidGV4dCIpCnN0eWxlKHBwLCBob3ZlcmxhYmVsID0gbGlzdChiZ2NvbG9yID0gIndoaXRlIikpCmBgYAkKCiMjIDMuIENhbmNlbGxhdGlvbnMgYW5kIERlc3RpbmF0aW9uIExvY2F0aW9uCgo+IEZvciB0aGUgZmlyc3QgdGhyZWUgbW9udGhzIG9mIDIwMTMsIGNvbXB1dGUgdGhlIG51bWJlciBvZiBmbGlnaHRzLAo+IHRoZSBhdmVyYWdlIGFycml2YWwgZGVsYXksIGFuZCB0aGUgcHJvcG9ydGlvbiBvZiBjYW5jZWxlZCBmbGlnaHRzIHRvCj4gZWFjaCBvZiB0aGUgZGVzdGluYXRpb25zLiBBc3N1bWUgYSBmbGlnaHQgaXMgY2FuY2VsZWQgaXQgaXRzCj4gZGVwYXJ0dXJlIHRpbWUgYW5kIGFycml2YWwgdGltZSBhcmUgYm90aCBtaXNzaW5nLgoKSXQgaXMgdXNlZnVsIHRvIGFkZCBhIGBjYW5jZWxlZGAgdmFyaWFibGUgdG8gdGhlIGBmbGlnaHRzYCB0YWJsZSwKYXNzdW1pbmcgdGhhdCBjYW5jZWxlZCBmbGlnaHRzIGFyZSB0aG9zZSB3aXRoIGJvdGggYGRlcF90aW1lYCBhbmQKYGFycl90aW1lYCBtaXNzaW5nOgoKYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyJ9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkobnljZmxpZ2h0czEzKQpmbGlnaHRzIDwtIG11dGF0ZShmbGlnaHRzLCBjYW5jZWxlZCA9IGlzLm5hKGRlcF90aW1lKSAmIGlzLm5hKGFycl90aW1lKSkKYGBgCgpGb3IgZWFjaCBkZXN0aW5hdGlvbiBhbmQgdGhlIGZpcnN0IHRocmVlIG1vbnRocywgY29tcHV0ZSB0aGUgbnVtYmVyIG9mCmZsaWdodHMsIHBlcmNlbnQgY2FuY2VsZWQsIGFuZCBhdmVyYWdlIGFycml2YWwgZGVsYXk6CgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyJ9CmZsMyA8LSBmaWx0ZXIoZmxpZ2h0cywgbW9udGggPD0gMykgJT4lCiAgICBncm91cF9ieShkZXN0KSAlPiUKICAgIHN1bW1hcml6ZShuID0gbigpLAogICAgICAgICAgICAgIHBjYW4gPSAxMDAgKiBtZWFuKGNhbmNlbGVkKSwKICAgICAgICAgICAgICBkZWxheSA9IG1lYW4oYXJyX2RlbGF5LCBuYS5ybSA9IFRSVUUpKSAlPiUKICAgIHVuZ3JvdXAoKQpgYGAKCj4gRm9jdXMgb24gdGhlIHRvcCA1MCBkZXN0aW5hdGlvbnMgaW4gdGVybXMgb2YgdGhlIG51bWJlciBvZiBmbGlnaHRzCj4gZnJvbSBOWUMgZHVyaW5nIHRoZSBmaXJzdCB0aHJlZSBtb250aHMgb2YgMjAxMy4KCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93In0KZmwzXzUwIDwtIHRvcF9uKGZsMywgNTAsIG4pCmBgYAoKPiBDcmVhdGUgYSBtYXAgd2l0aCBhIHBvaW50IGF0IGVhY2ggb2YgdGhlc2UgZGVzdGluYXRpb25zLCBhbmQgZW5jb2RlCj4gdGhlIHByb3BvcnRpb24gb2YgY2FuY2VsZWQgZmxpZ2h0cyBpbiB0aGUgcG9pbnQncyBzaXplLiBDb21tZW50IG9uCj4gd2hhdCB5b3Ugc2VlLgoKVG8gc2hvdyB0aGUgZGF0YSBvbiBhIG1hcCwgYWRkIGxvY2F0aW9uIGluZm9ybWF0aW9uIGJ5IGpvaW5pbmcgd2l0aApkYXRhIGZyb20gdGhlIGBhaXJwb3J0c2AgdGFibGU6CgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyJ9CmZsM181MCA8LSBsZWZ0X2pvaW4oZmwzXzUwLAogICAgICAgICAgICAgICAgICAgIHNlbGVjdChhaXJwb3J0cywgZmFhLCBsYXQsIGxvbiwgYWx0KSwKICAgICAgICAgICAgICAgICAgICBjKCJkZXN0IiA9ICJmYWEiKSkKYGBgCgpBIG1hcCBzaG93aW5nIHRoZSBjYW5jZWxsYXRpb24gcGVyY2VudGFnZXMgZm9yIHRoZSB0b3AgNTAgZGVzdGluYXRpb25zOgoKPCEtLSBTSlUgKFNhbiBKdWFuLCBQdWVydG8gUmljbywgaXMgb25lIG9mIHRoZSB0b3AgNTAgYnV0IG5vdCBpbiBgYWlycG9ydHNgIC0tPgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQpwbSA8LSBnZ3Bsb3QoZmwzXzUwLCBhZXMoeCA9IGxvbiwgeSA9IGxhdCkpICsKICAgIGJvcmRlcnMoInN0YXRlIikgKwogICAgY29vcmRfbWFwKCkgKwogICAgdGhlbWVfdm9pZCgpCnBtICsgZ2VvbV9wb2ludChhZXMoc2l6ZSA9IHBjYW4pKSArIHNjYWxlX3NpemVfYXJlYSgpCmBgYAoKVXNpbmcgYWxwaGEgYmxlbmRpbmcgY2FuIGhlbHAgd2l0aCB0aGUgb3Zlci1wbG90dGluZyBhbG9uZyB0aGUgZWFzdApjb2FzdDoKCmBgYHtyfQpwbSArIGdlb21fcG9pbnQoYWVzKHNpemUgPSBwY2FuKSwgYWxwaGEgPSAwLjMpICsgc2NhbGVfc2l6ZV9hcmVhKCkKYGBgCgpDYW5jZWxsYXRpb24gcGVyY2VudGFnZXMgYXJlIGhpZ2hlciBmb3IgY2xvc2VyIGFpcnBvcnRzIGFuZCBhaXJwb3J0cwpsaWtlbHkgdG8gYmUgZXhwZXJpZW5jaW5nIHNpbWlsYXIgd2VhdGhlciBjb25kaXRpb25zLiAKCj4gSW4gYWRkaXRpb24gdG8gdGhlIGxvY2F0aW9uIGFuZCBwcm9wb3J0aW9uIG9mIGNhbmNlbGVkIGZsaWdodHMsCj4gd2hldGhlciB0aGUgYXZlcmFnZSBhcnJpdmFsIGRlbGF5IGlzIG1vcmUgb3IgbGVzcyB0aGFuIDIwIG1pbnV0ZXMKPiBjb3VsZCBiZSBlbmNvZGVkIHVzaW5nIGNvbG9yIG9yIHNoYXBlLiBUcnkgYm90aCBhcHByb2FjaGVzLCBjb21tZW50Cj4gb24gd2hhdCB5b3Ugc2VlIGFuZCBvbiB0aGUgYWR2YW50YWdlcyBhbmQgZGlzYWR2YW50YWdlcyBvZiBlYWNoCj4gYXBwcm9hY2guCgpXaGV0aGVyIHRoZSBhdmVyYWdlIGRlbGF5IGlzIDIwIG1pbnV0ZXMgb3IgbW9yZSBjYW4gYmUgZW5jb2RlZCBpbgp1c2luZyBjb2xvciBvciBzaGFwZToKCmBgYHtyfQpwbSArIGdlb21fcG9pbnQoYWVzKHNpemUgPSBwY2FuLCBjb2xvciA9IGRlbGF5ID49IDIwKSkgKyBzY2FsZV9zaXplX2FyZWEoKQpwbSArIGdlb21fcG9pbnQoYWVzKHNpemUgPSBwY2FuLCBzaGFwZSA9IGRlbGF5ID49IDIwKSkgKyBzY2FsZV9zaXplX2FyZWEoKQpgYGAKCkZvciBhIDE1IG1pbnV0ZSBjdXRvZmYgdGhlcmUgYXJlIGEgZmV3IG1vcmUgaGlnaCBkZWxheSBkZXN0aW5hdGlvbnM6CgpgYGB7cn0KcG0gKyBnZW9tX3BvaW50KGFlcyhzaXplID0gcGNhbiwgY29sb3IgPSBkZWxheSA+PSAxNSkpICsgc2NhbGVfc2l6ZV9hcmVhKCkKcG0gKyBnZW9tX3BvaW50KGFlcyhzaXplID0gcGNhbiwgc2hhcGUgPSBkZWxheSA+PSAxNSkpICsgc2NhbGVfc2l6ZV9hcmVhKCkKYGBgCgpUaGUgc2l6ZSBhbmQgc2hhcGUgY2hhbm5lbHMgaW50ZXJmZXJlIHdpdGggZWFjaCBvdGhlciBxdWl0ZSBhIGJpdDsKY29sb3IgYW5kIHNpemUgaW50ZXJmZXJlIHdpdGggZWFjaCBvdGhlciBtdWNoIGxlc3MuIFBpY2tpbmcgb3V0IHRoZQpyYXJlciBzaGFwZXMgaXMgYWxzbyBoYXJkZXIgdGhhbiBzcG90dGluZyB0aGUgZGlmZmVyZW50IGNvbG9yczogY29sb3IKYWNoaWV2ZXMgYmV0dGVyIHBvcC1vdXQuCg==