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() |>
    gt::fmt_integer()
state Biden Other Trump
Illinois 3,471,915 114,937 2,446,891
Iowa 759,061 43,397 897,672
Minnesota 1,717,077 76,029 1,484,065
Missouri 1,253,014 54,212 1,718,736
Nebraska 374,583 24,954 556,846
South Dakota 150,471 11,095 261,043
Wisconsin 1,630,866 56,991 1,610,184

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: The `scale_name` argument of `continuous_scale()` is deprecated as of ggplot2
## 3.5.0.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: The `trans` argument of `continuous_scale()` is deprecated as of ggplot2 3.5.0.
## ℹ Please use the `transform` argument instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: `unite_()` was deprecated in tidyr 1.2.0.
## ℹ Please use `unite()` instead.
## ℹ The deprecated feature was likely used in the ggmosaic package.
##   Please report the issue at <https://github.com/haleyjeppson/ggmosaic>.
## 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 <- slice_max(fl3, n, n = 50)

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 row containing missing values or values outside the scale range
## (`geom_point()`).

[The map only shows 49 airports since SJU (San Juan, Puerto Rico) is one of the top 50 but not in the airports date frame.]

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 row containing missing values or values outside the scale range
## (`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 row containing missing values or values outside the scale range
## (`geom_point()`).

pm + geom_point(aes(size = pcan, shape = delay >= 20)) + scale_size_area()
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`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 row containing missing values or values outside the scale range
## (`geom_point()`).

pm + geom_point(aes(size = pcan, shape = delay >= 15)) + scale_size_area()
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`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.

LS0tCnRpdGxlOiAiQXNzaWdubWVudCA3IE5vdGVzIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6ICJoaWRlIgotLS0KCmBgYHtyIGdsb2JhbF9vcHRpb25zLCBpbmNsdWRlID0gRkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChjb2xsYXBzZSA9IFRSVUUsIGZpZy5hbGlnbiA9ICJjZW50ZXIiKQpgYGAKCiMjIDEuIEVsZWN0aW9uIFJlc3VsdHMKCgpUaGUgdm90ZXMgZm9yIElvd2EgYW5kIG5lYXJieSBzdGF0ZXM6CgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFfQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGdncGxvdDIpCmVsZWN0aW9uMjAyMCA8LSByZWFkLmNzdigiZWxlY3Rpb24yMDIwLmNzdiIpCnN0YXRlX2FiYiA8LSBkYXRhLmZyYW1lKHN0YXRlID0gc3RhdGUubmFtZSwgYWJiID0gc3RhdGUuYWJiKQplbGVjdGlvbiA8LSBsZWZ0X2pvaW4oZWxlY3Rpb24yMDIwLCBzdGF0ZV9hYmIsICJzdGF0ZSIpCm5lYXJieV9zdGF0ZXMgPC0gYygiSUEiLCAiSUwiLCAiV0kiLCAiTU4iLCAiU0QiLCAiTU8iLCAiTkUiKQplbGVjdGlvbl9uZWFyYnkgPC0gZmlsdGVyKGVsZWN0aW9uLCBhYmIgJWluJSBuZWFyYnlfc3RhdGVzKSB8PgogICAgbXV0YXRlKGNhbmRpZGF0ZSA9IGZhY3RvcihjYW5kaWRhdGUsIGMoIkJpZGVuIiwgIk90aGVyIiwgIlRydW1wIikpKQoKc2VsZWN0KGVsZWN0aW9uX25lYXJieSwgc3RhdGUsIGNhbmRpZGF0ZSwgdm90ZXMpIHw+CiAgICB0aWR5cjo6cGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9ICJjYW5kaWRhdGUiLCB2YWx1ZXNfZnJvbSA9ICJ2b3RlcyIpIHw+CiAgICBndDo6Z3QoKSB8PgogICAgZ3Q6OmZtdF9pbnRlZ2VyKCkKYGBgCgpUaGUgdGhyZWUgcGxvdHM6CgoKYGBge3IsIGZpZy53aWR0aCA9IDExLCBmaWcuaGVpZ2h0ID0gNH0KcCA8LSBnZ3Bsb3QoZWxlY3Rpb25fbmVhcmJ5LCBhZXMoeCA9IHN0YXRlLCB5ID0gdm90ZXMsIGZpbGwgPSBjYW5kaWRhdGUpKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKFRydW1wID0gc2NhbGVzOjptdXRlZCgicmVkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEJpZGVuID0gc2NhbGVzOjptdXRlZCgiYmx1ZSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBPdGhlciA9ICJncmV5IikpICsKICAgIGxhYnMoeCA9ICIiKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKCnBfYmFyIDwtIHAgKyBnZW9tX2NvbCgpCnBfZmlsbCA8LSBwICsgZ2VvbV9jb2wocG9zaXRpb24gPSAiZmlsbCIpCmxpYnJhcnkoZ2dtb3NhaWMpCnBfc3BpbmUgPC0gcCArCiAgICBnZW9tX21vc2FpYyhhZXMoeCA9IHByb2R1Y3QoYWJiKSwgd2VpZ2h0ID0gdm90ZXMsIGZpbGwgPSBjYW5kaWRhdGUpKQpsaWJyYXJ5KHBhdGNod29yaykKKHBfYmFyICsgZ3VpZGVzKGZpbGwgPSAibm9uZSIpICsgbGFicyh0aXRsZSA9ICJTdGFja2VkIEJhciBDaGFydCIpKSArCiAgICAocF9maWxsICsgZ3VpZGVzKGZpbGwgPSAibm9uZSIpICsgbGFicyh0aXRsZSA9ICJGaWxsZWQgQmFyIENoYXJ0IikpICsKICAgIChwX3NwaW5lICsgbGFicyh0aXRsZSA9ICJTcGluZSBQbG90IikpCmBgYAoKVGhlIHN0YWNrZWQgYmFyIGNoYXJ0IGNsZWFybHkgc2hvd3MgdGhlIGRpZmZlcmluZyB2b3RlIHRvdGFscywgYnV0CmRvZXMgbm90IG1ha2UgaXQgZWFzeSB0byBjb21wYXJlIHZvdGUgcHJvcG9ydGlvbnMgZnJvbSBvbmUgc3RhdGUgdG8KYW5vdGhlci4gVGhlIGZpbGxlZCB2ZXJzaW9uIG1ha2VzIGNvbXBhcmluZyBwcm9wb3J0aW9ucyBlYXN5IGJ1dCBkb2VzCm5vdCBzaG93IHRoZSBkaWZmZXJpbmcgdm90ZSB0b3RhbHMuIFRoZSBzcGluZSBjaGFydCBhbHNvIG1ha2VzCmNvbXBhcmluZyBwcm9wb3J0aW9ucyBhY3Jvc3Mgc3RhdGVzIGVhc3ksIGFuZCBhbHNvIHJlZmxlY3RzIHRoZQpkaWZmZXJpbmcgdm90ZSB0b3RhbHMgaW4gdGhlIHdpZHRocyBvZiB0aGUgYmFycy4gRm9yIHRoZSBzdGF0ZWQKcHVycG9zZSB0aGUgc3BpbmUgY2hhcnQgaXMgdGhlIGJlc3QgY2hvaWNlLgoKIyMgMi4gR2FwbWluZGVyIFRvb2x0aXBzCgpGaXJzdCBjcmVhdGUgdGhlIHBsb3Qgb2JqZWN0IHdpdGggYSBgdGV4dGAgYWVzdGhldGljIG1hcHBlZCB0byBgY291bnRyeWA6CgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFfQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGdncGxvdDIpCnRoZW1lX3NldCh0aGVtZV9taW5pbWFsKCkgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNikpKQpsaWJyYXJ5KGdhcG1pbmRlcikKZ2FwIDwtIGZpbHRlcihnYXBtaW5kZXIsIHllYXIgJSUgMTAgPT0gNyAmIHllYXIgPj0gMTk3NykKcCA8LSBnZ3Bsb3QoZ2FwLCBhZXMoeCA9IGdkcFBlcmNhcCwgeSA9IGxpZmVFeHAsCiAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gY29udGluZW50LAogICAgICAgICAgICAgICAgICAgICBzaXplID0gcG9wLAogICAgICAgICAgICAgICAgICAgICB0ZXh0ID0gY291bnRyeSkpICsKICAgIGdlb21fcG9pbnQoKSArCiAgICBzY2FsZV9zaXplX2FyZWEobWF4X3NpemUgPSA4KSArCiAgICBzY2FsZV94X2xvZzEwKCkgKwogICAgZmFjZXRfd3JhcCh+IHllYXIpCmBgYAoKVGhlbiBzcGVjaWZ5IHRoZSBgdGV4dGAgYWVzdGhldGljIGFzIHRoZSBgdG9vbHRpcGAgaW4gdGhlIGBnZ3Bsb3RseWAKY2FsbC4gIFRoZSBgc3R5bGVgIGZ1bmN0aW9uIGZyb20gYHBsb3RseWAgY2FuIGJlIHVzZWQgdG8gYWRqdXN0IHRoZQpiYWNrZ3JvdW5kIGNvbG9yLgoKCmBgYHtyLCBtZXNzYWdlID0gRkFMU0V9CmxpYnJhcnkocGxvdGx5KQpwcCA8LSBnZ3Bsb3RseShwLCB0b29sdGlwID0gInRleHQiKQpzdHlsZShwcCwgaG92ZXJsYWJlbCA9IGxpc3QoYmdjb2xvciA9ICJ3aGl0ZSIpKQpgYGAKCiMjIDMuIENhbmNlbGxhdGlvbnMgYW5kIERlc3RpbmF0aW9uIExvY2F0aW9uCgo+IEZvciB0aGUgZmlyc3QgdGhyZWUgbW9udGhzIG9mIDIwMTMsIGNvbXB1dGUgdGhlIG51bWJlciBvZiBmbGlnaHRzLAo+IHRoZSBhdmVyYWdlIGFycml2YWwgZGVsYXksIGFuZCB0aGUgcHJvcG9ydGlvbiBvZiBjYW5jZWxlZCBmbGlnaHRzIHRvCj4gZWFjaCBvZiB0aGUgZGVzdGluYXRpb25zLiBBc3N1bWUgYSBmbGlnaHQgaXMgY2FuY2VsZWQgaXQgaXRzCj4gZGVwYXJ0dXJlIHRpbWUgYW5kIGFycml2YWwgdGltZSBhcmUgYm90aCBtaXNzaW5nLgoKSXQgaXMgdXNlZnVsIHRvIGFkZCBhIGBjYW5jZWxlZGAgdmFyaWFibGUgdG8gdGhlIGBmbGlnaHRzYCB0YWJsZSwKYXNzdW1pbmcgdGhhdCBjYW5jZWxlZCBmbGlnaHRzIGFyZSB0aG9zZSB3aXRoIGJvdGggYGRlcF90aW1lYCBhbmQKYGFycl90aW1lYCBtaXNzaW5nOgoKYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyJ9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkobnljZmxpZ2h0czEzKQpmbGlnaHRzIDwtIG11dGF0ZShmbGlnaHRzLCBjYW5jZWxlZCA9IGlzLm5hKGRlcF90aW1lKSAmIGlzLm5hKGFycl90aW1lKSkKYGBgCgpGb3IgZWFjaCBkZXN0aW5hdGlvbiBhbmQgdGhlIGZpcnN0IHRocmVlIG1vbnRocywgY29tcHV0ZSB0aGUgbnVtYmVyIG9mCmZsaWdodHMsIHBlcmNlbnQgY2FuY2VsZWQsIGFuZCBhdmVyYWdlIGFycml2YWwgZGVsYXk6CgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyJ9CmZsMyA8LSBmaWx0ZXIoZmxpZ2h0cywgbW9udGggPD0gMykgfD4KICAgIGdyb3VwX2J5KGRlc3QpIHw+CiAgICBzdW1tYXJpemUobiA9IG4oKSwKICAgICAgICAgICAgICBwY2FuID0gMTAwICogbWVhbihjYW5jZWxlZCksCiAgICAgICAgICAgICAgZGVsYXkgPSBtZWFuKGFycl9kZWxheSwgbmEucm0gPSBUUlVFKSkgfD4KICAgIHVuZ3JvdXAoKQpgYGAKCj4gRm9jdXMgb24gdGhlIHRvcCA1MCBkZXN0aW5hdGlvbnMgaW4gdGVybXMgb2YgdGhlIG51bWJlciBvZiBmbGlnaHRzCj4gZnJvbSBOWUMgZHVyaW5nIHRoZSBmaXJzdCB0aHJlZSBtb250aHMgb2YgMjAxMy4KCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93In0KZmwzXzUwIDwtIHNsaWNlX21heChmbDMsIG4sIG4gPSA1MCkKYGBgCgo+IENyZWF0ZSBhIG1hcCB3aXRoIGEgcG9pbnQgYXQgZWFjaCBvZiB0aGVzZSBkZXN0aW5hdGlvbnMsIGFuZCBlbmNvZGUKPiB0aGUgcHJvcG9ydGlvbiBvZiBjYW5jZWxlZCBmbGlnaHRzIGluIHRoZSBwb2ludCdzIHNpemUuIENvbW1lbnQgb24KPiB3aGF0IHlvdSBzZWUuCgpUbyBzaG93IHRoZSBkYXRhIG9uIGEgbWFwLCBhZGQgbG9jYXRpb24gaW5mb3JtYXRpb24gYnkgam9pbmluZyB3aXRoCmRhdGEgZnJvbSB0aGUgYGFpcnBvcnRzYCB0YWJsZToKCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93In0KZmwzXzUwIDwtIGxlZnRfam9pbihmbDNfNTAsCiAgICAgICAgICAgICAgICAgICAgc2VsZWN0KGFpcnBvcnRzLCBmYWEsIGxhdCwgbG9uLCBhbHQpLAogICAgICAgICAgICAgICAgICAgIGMoImRlc3QiID0gImZhYSIpKQpgYGAKCkEgbWFwIHNob3dpbmcgdGhlIGNhbmNlbGxhdGlvbiBwZXJjZW50YWdlcyBmb3IgdGhlIHRvcCA1MCBkZXN0aW5hdGlvbnM6CgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQpwbSA8LSBnZ3Bsb3QoZmwzXzUwLCBhZXMoeCA9IGxvbiwgeSA9IGxhdCkpICsKICAgIGJvcmRlcnMoInN0YXRlIikgKwogICAgY29vcmRfbWFwKCkgKwogICAgdGhlbWVfdm9pZCgpCnBtICsgZ2VvbV9wb2ludChhZXMoc2l6ZSA9IHBjYW4pKSArIHNjYWxlX3NpemVfYXJlYSgpCmBgYAoKW1RoZSBtYXAgb25seSBzaG93cyA0OSBhaXJwb3J0cyBzaW5jZSBTSlUgKFNhbiBKdWFuLCBQdWVydG8gUmljbykgaXMKb25lIG9mIHRoZSB0b3AgNTAgYnV0IG5vdCBpbiB0aGUgYGFpcnBvcnRzYCBkYXRlIGZyYW1lLl0KClVzaW5nIGFscGhhIGJsZW5kaW5nIGNhbiBoZWxwIHdpdGggdGhlIG92ZXItcGxvdHRpbmcgYWxvbmcgdGhlIGVhc3QKY29hc3Q6CgpgYGB7cn0KcG0gKyBnZW9tX3BvaW50KGFlcyhzaXplID0gcGNhbiksIGFscGhhID0gMC4zKSArIHNjYWxlX3NpemVfYXJlYSgpCmBgYAoKQ2FuY2VsbGF0aW9uIHBlcmNlbnRhZ2VzIGFyZSBoaWdoZXIgZm9yIGNsb3NlciBhaXJwb3J0cyBhbmQgYWlycG9ydHMKbGlrZWx5IHRvIGJlIGV4cGVyaWVuY2luZyBzaW1pbGFyIHdlYXRoZXIgY29uZGl0aW9ucy4gCgo+IEluIGFkZGl0aW9uIHRvIHRoZSBsb2NhdGlvbiBhbmQgcHJvcG9ydGlvbiBvZiBjYW5jZWxlZCBmbGlnaHRzLAo+IHdoZXRoZXIgdGhlIGF2ZXJhZ2UgYXJyaXZhbCBkZWxheSBpcyBtb3JlIG9yIGxlc3MgdGhhbiAyMCBtaW51dGVzCj4gY291bGQgYmUgZW5jb2RlZCB1c2luZyBjb2xvciBvciBzaGFwZS4gVHJ5IGJvdGggYXBwcm9hY2hlcywgY29tbWVudAo+IG9uIHdoYXQgeW91IHNlZSBhbmQgb24gdGhlIGFkdmFudGFnZXMgYW5kIGRpc2FkdmFudGFnZXMgb2YgZWFjaAo+IGFwcHJvYWNoLgoKV2hldGhlciB0aGUgYXZlcmFnZSBkZWxheSBpcyAyMCBtaW51dGVzIG9yIG1vcmUgY2FuIGJlIGVuY29kZWQgaW4KdXNpbmcgY29sb3Igb3Igc2hhcGU6CgpgYGB7cn0KcG0gKyBnZW9tX3BvaW50KGFlcyhzaXplID0gcGNhbiwgY29sb3IgPSBkZWxheSA+PSAyMCkpICsgc2NhbGVfc2l6ZV9hcmVhKCkKcG0gKyBnZW9tX3BvaW50KGFlcyhzaXplID0gcGNhbiwgc2hhcGUgPSBkZWxheSA+PSAyMCkpICsgc2NhbGVfc2l6ZV9hcmVhKCkKYGBgCgpGb3IgYSAxNSBtaW51dGUgY3V0b2ZmIHRoZXJlIGFyZSBhIGZldyBtb3JlIGhpZ2ggZGVsYXkgZGVzdGluYXRpb25zOgoKYGBge3J9CnBtICsgZ2VvbV9wb2ludChhZXMoc2l6ZSA9IHBjYW4sIGNvbG9yID0gZGVsYXkgPj0gMTUpKSArIHNjYWxlX3NpemVfYXJlYSgpCnBtICsgZ2VvbV9wb2ludChhZXMoc2l6ZSA9IHBjYW4sIHNoYXBlID0gZGVsYXkgPj0gMTUpKSArIHNjYWxlX3NpemVfYXJlYSgpCmBgYAoKVGhlIHNpemUgYW5kIHNoYXBlIGNoYW5uZWxzIGludGVyZmVyZSB3aXRoIGVhY2ggb3RoZXIgcXVpdGUgYSBiaXQ7CmNvbG9yIGFuZCBzaXplIGludGVyZmVyZSB3aXRoIGVhY2ggb3RoZXIgbXVjaCBsZXNzLiBQaWNraW5nIG91dCB0aGUKcmFyZXIgc2hhcGVzIGlzIGFsc28gaGFyZGVyIHRoYW4gc3BvdHRpbmcgdGhlIGRpZmZlcmVudCBjb2xvcnM6IGNvbG9yCmFjaGlldmVzIGJldHRlciBwb3Atb3V0Lgo=