@import url('https://fonts.googleapis.com/css?family=Baloo');
h1, h2 {
  font-family: 'Baloo', cursive;
}
films <- rwars::get_all_films()$results

#get_all_starships doesn't work :/
#the ship ids are also not complete - there are gaps!
#so we'll loop through potential ids and get the ships where they exist
#not very efficient, but ok for a small API

getDataRobust <- function(ids, f) {
   
   getSingle <- function(id, f) { 
     tryCatch(f(id), error = function(e) { 
      NULL
     })
   }
   
   all <- map(ids, ~getSingle(.x, f))
   not_null <- all[!sapply(all, is.null)]
   
   not_null
}


ids <- 1:100
ships <- getDataRobust(ids, get_starship)
vehicles <- getDataRobust(ids, get_vehicle)

# since we don't want to do this loop every time, lets save the intermediate results
save(films, ships, vehicles, file = "sdata.Rdat")
load("sdata.Rdat")
episodes <- tibble(
  title = map_chr(films, "title"),
  episode = map_dbl(films, "episode_id"),
  starships = map_dbl(films, ~length(.x$starships)),
  vehicles = map_dbl(films, ~length(.x$vehicles)),
  planets = map_dbl(films, ~length(.x$planets))
)

episodes <- episodes %>% 
  mutate(ratio = starships / (vehicles + starships) * 100,
         total = vehicles + starships,
         label = paste0(title, "\n", vehicles," vehicles / ", starships, " starships")) %>% 
  arrange(episode) %>% 
  mutate(trilogy = c(rep("prequel", 3), rep("original", 3), rep("sequel", 1)))

One of the memorizing aspects of Star Wars is the number of spaceships. This report examines some characteristics of these ships.

The data for this report comes from and is accessed through the excellent rwars package.

Throughout the analysis the tidyverse is used. As a few examples, in the code you’ll see ggplot2, dplyr::filter, and purr::map.

A big imagination …

Some ships we all probably know by heart. Picture Yoda raising the X-wing out of the swamp or Han racing off in the Millennium Falcon.

Yet, the creators of Star Wars spent a good deal of time dreaming up ships and each episode contains a variety of unique ships.

ggplot(episodes, aes(episode, total)) + 
  geom_col() +
  geom_text(aes(label = total, y = total -1), color = "black") + 
  theme_fivethirtyeight() +   scale_color_fivethirtyeight() + 
  labs(
    title = "Increasing Imagination or More Lego Models to Sell?",
    subtitle = "Each epsiode in a trilogy introduced more ships",
    y = ""
  ) + 
  scale_y_continuous(labels = NULL) +
  scale_x_continuous(labels = c("I", "II", "III", "IV", "V", "VI", "VII"), breaks = 1:7, minor_breaks = NULL)

Bad data for episode 7?

Interestingly, it appears that prequels followed a trend in the original 3 movies by introducing more ships over time.

pop_ships <- tibble(
  name = map_chr(ships, "name"),
  films = map_dbl(ships, ~length(.x$films))
)

pop_vehs <- tibble(
  name = map_chr(vehicles, "name"),
  films = map_dbl(vehicles, ~length(.x$films))
)

all <- rbind(pop_ships, pop_vehs)

This graph makes it tempting to jump to conclusions, but there are only 76 unique ships! Some of the ships appear in more than one episode. To get a sense for some of the most popular ships, we can count the number of movies per ship:

pop_all <- rbind(pop_ships, pop_vehs) %>% 
  filter(films > 1)

ggplot(pop_all, aes(reorder(name, films), films)) + 
  geom_col() + 
  coord_flip() + 
  theme_fivethirtyeight() +   scale_color_fivethirtyeight() +
  labs(
    title = "Popular Ships",
    subtitle = "Ships that appear in multiple episodes",
    x = ""
  ) +
  scale_y_continuous(minor_breaks = NULL)

How big is the death star?

In addition to data on ship appearances by film, we also have data on ship characteristics such as size and shape. Using this data, lets try to get a sense for the scale of the infamous Death Star.

We start out small, looking at some familiar favorites such as the Millenium Falcon.

ship_episode <- tibble(
  crew = map_chr(ships, "crew") %>% parse_number(),
  cost = map_chr(ships, "cost_in_credits") %>% parse_number(),
  passengers = map_chr(ships, "passengers") %>% parse_number(),
  cargo = map_chr(ships, "cargo_capacity") %>% parse_number(), 
  name = map_chr(ships, "name")
)

plotShip <- function(data, outlier_bound = 10e100, main, label_ships) {
  
  mf <- data %>% 
    filter(name %in% label_ships)
  
  data <- data %>% 
    filter(crew < outlier_bound, passengers < outlier_bound)
  
  data %>% 
    ggplot(aes(crew, passengers, label = name)) + 
    geom_point() +
    labs(
      title  = main,
      subtitle = "Crew vs Passengers"
    ) + 
    theme_fivethirtyeight() +   scale_color_fivethirtyeight() +
    geom_point(data = mf) +
    geom_text_repel(data = mf, aes(label = name))
}
plotShip(ship_episode, outlier_bound = 100,
         "Reasonable Size", 
         label_ships = c("Millennium Falcon", "Rebel transport"))

There appears to be a slight trend between the number of crew and the number of passengers, though the Rebel Transport thorws things off. Keep your eye on Rebel Transport as we zoom out:

plotShip(ship_episode, 
         outlier_bound = 10e2, 
         "Large High School", 
         label_ships = c("Rebel transport", "CR90 corvette", "EF76 Nebulon-B escort frigate"))

Now we’re introducing some bigger ships. But we can go BIGGER:

plotShip(ship_episode, outlier_bound = 10e3,
         "Aircraft Carrier",
         c("CR90 corvette", "EF76 Nebulon-B escort frigate", "Republic attack cruiser"))

The Rebel Transport from our first plot is still visible in the lower left, but we’ve introduced ships much larger. The Republic Attack Cruiser presents an interesting mix of crew and passengers. Let’s zoom out again:

plotShip(ship_episode, outlier_bound = 10e4,
         "Football Stadium", c("Republic attack cruiser", "Star Destroyer", "Trade Federation cruiser"))

Now the Republic Attack Cruiser looks small. We’ve introduced some fan favorites and the memorable Star Destroyer. While 50,000 crew members may seem like a lot, we are no where close to the Death Star:

plotShip(ship_episode, main = "The State of Maine", 
        label_ships = c("Star Destroyer",
                        "Trade Federation cruiser",
                        "Death Star",
                        "Droid control ship",
                        "Executor"))

Don’t miss the Star Destryer sitting in the lower left. The scale of the Death Star is hard to imagine! We’ve also introduced two other gigantic ships: the Droid Control Ship (no crew …) and the Executor.

LS0tCnRpdGxlOiAiRXhwbG9yaW5nIFNoaXBzIGluIFN0YXIgV2FycyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge2Nzc30KQGltcG9ydCB1cmwoJ2h0dHBzOi8vZm9udHMuZ29vZ2xlYXBpcy5jb20vY3NzP2ZhbWlseT1CYWxvbycpOwpoMSwgaDIgewogIGZvbnQtZmFtaWx5OiAnQmFsb28nLCBjdXJzaXZlOwp9CmBgYAoKCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShyd2FycykKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KGdndGhlbWVzKQpsaWJyYXJ5KHJlYWRyKQpsaWJyYXJ5KHBsb3RseSkKYGBgCgpgYGB7ciBnZXRkYXRhLCBldmFsID0gRkFMU0V9CmZpbG1zIDwtIHJ3YXJzOjpnZXRfYWxsX2ZpbG1zKCkkcmVzdWx0cwoKI2dldF9hbGxfc3RhcnNoaXBzIGRvZXNuJ3Qgd29yayA6LwojdGhlIHNoaXAgaWRzIGFyZSBhbHNvIG5vdCBjb21wbGV0ZSAtIHRoZXJlIGFyZSBnYXBzIQojc28gd2UnbGwgbG9vcCB0aHJvdWdoIHBvdGVudGlhbCBpZHMgYW5kIGdldCB0aGUgc2hpcHMgd2hlcmUgdGhleSBleGlzdAojbm90IHZlcnkgZWZmaWNpZW50LCBidXQgb2sgZm9yIGEgc21hbGwgQVBJCgpnZXREYXRhUm9idXN0IDwtIGZ1bmN0aW9uKGlkcywgZikgewogICAKICAgZ2V0U2luZ2xlIDwtIGZ1bmN0aW9uKGlkLCBmKSB7IAogICAgIHRyeUNhdGNoKGYoaWQpLCBlcnJvciA9IGZ1bmN0aW9uKGUpIHsgCiAgICAgIE5VTEwKICAgICB9KQogICB9CiAgIAogICBhbGwgPC0gbWFwKGlkcywgfmdldFNpbmdsZSgueCwgZikpCiAgIG5vdF9udWxsIDwtIGFsbFshc2FwcGx5KGFsbCwgaXMubnVsbCldCiAgIAogICBub3RfbnVsbAp9CgoKaWRzIDwtIDE6MTAwCnNoaXBzIDwtIGdldERhdGFSb2J1c3QoaWRzLCBnZXRfc3RhcnNoaXApCnZlaGljbGVzIDwtIGdldERhdGFSb2J1c3QoaWRzLCBnZXRfdmVoaWNsZSkKCiMgc2luY2Ugd2UgZG9uJ3Qgd2FudCB0byBkbyB0aGlzIGxvb3AgZXZlcnkgdGltZSwgbGV0cyBzYXZlIHRoZSBpbnRlcm1lZGlhdGUgcmVzdWx0cwpzYXZlKGZpbG1zLCBzaGlwcywgdmVoaWNsZXMsIGZpbGUgPSAic2RhdGEuUmRhdCIpCmBgYAoKYGBge3IgcHJvY2Vzc2RhdGF9CmxvYWQoInNkYXRhLlJkYXQiKQplcGlzb2RlcyA8LSB0aWJibGUoCiAgdGl0bGUgPSBtYXBfY2hyKGZpbG1zLCAidGl0bGUiKSwKICBlcGlzb2RlID0gbWFwX2RibChmaWxtcywgImVwaXNvZGVfaWQiKSwKICBzdGFyc2hpcHMgPSBtYXBfZGJsKGZpbG1zLCB+bGVuZ3RoKC54JHN0YXJzaGlwcykpLAogIHZlaGljbGVzID0gbWFwX2RibChmaWxtcywgfmxlbmd0aCgueCR2ZWhpY2xlcykpLAogIHBsYW5ldHMgPSBtYXBfZGJsKGZpbG1zLCB+bGVuZ3RoKC54JHBsYW5ldHMpKQopCgplcGlzb2RlcyA8LSBlcGlzb2RlcyAlPiUgCiAgbXV0YXRlKHJhdGlvID0gc3RhcnNoaXBzIC8gKHZlaGljbGVzICsgc3RhcnNoaXBzKSAqIDEwMCwKICAgICAgICAgdG90YWwgPSB2ZWhpY2xlcyArIHN0YXJzaGlwcywKICAgICAgICAgbGFiZWwgPSBwYXN0ZTAodGl0bGUsICJcbiIsIHZlaGljbGVzLCIgdmVoaWNsZXMgLyAiLCBzdGFyc2hpcHMsICIgc3RhcnNoaXBzIikpICU+JSAKICBhcnJhbmdlKGVwaXNvZGUpICU+JSAKICBtdXRhdGUodHJpbG9neSA9IGMocmVwKCJwcmVxdWVsIiwgMyksIHJlcCgib3JpZ2luYWwiLCAzKSwgcmVwKCJzZXF1ZWwiLCAxKSkpCgpgYGAKCk9uZSBvZiB0aGUgbWVtb3JpemluZyBhc3BlY3RzIG9mIFN0YXIgV2FycyBpcyB0aGUgbnVtYmVyIG9mIHNwYWNlc2hpcHMuIFRoaXMgcmVwb3J0IGV4YW1pbmVzIHNvbWUgY2hhcmFjdGVyaXN0aWNzIG9mIHRoZXNlIHNoaXBzLiAKClRoZSBkYXRhIGZvciB0aGlzIHJlcG9ydCBjb21lcyBmcm9tIFtdKFNXQVBJLmNvKSBhbmQgaXMgYWNjZXNzZWQgdGhyb3VnaCB0aGUgZXhjZWxsZW50IFtyd2FycyBwYWNrYWdlXShnaXRodWIuY29tL2lyb25ob2xkcy9yd2FycykuCgpUaHJvdWdob3V0IHRoZSBhbmFseXNpcyB0aGUgW3RpZHl2ZXJzZV0odGlkeXZlcnNlLm9yZykgaXMgdXNlZC4gQXMgYSBmZXcgZXhhbXBsZXMsIGluIHRoZSBjb2RlIHlvdSdsbCBzZWUgYGdncGxvdDJgLCBgZHBseXI6OmZpbHRlcmAsIGFuZCBgcHVycjo6bWFwYC4KCiMjIEEgYmlnIGltYWdpbmF0aW9uIC4uLiAKClNvbWUgc2hpcHMgd2UgYWxsIHByb2JhYmx5IGtub3cgYnkgaGVhcnQuIFBpY3R1cmUgWW9kYSByYWlzaW5nIHRoZSBYLXdpbmcgb3V0IG9mIHRoZSBzd2FtcCBvciBIYW4gcmFjaW5nIG9mZiBpbiB0aGUgTWlsbGVubml1bSBGYWxjb24uCgpZZXQsIHRoZSBjcmVhdG9ycyBvZiBTdGFyIFdhcnMgc3BlbnQgYSBnb29kIGRlYWwgb2YgdGltZSBkcmVhbWluZyB1cCBzaGlwcyBhbmQgZWFjaCBlcGlzb2RlIGNvbnRhaW5zIGEgdmFyaWV0eSBvZiB1bmlxdWUgc2hpcHMuCgpgYGB7ciBzaGlwc30KZ2dwbG90KGVwaXNvZGVzLCBhZXMoZXBpc29kZSwgdG90YWwpKSArIAogIGdlb21fY29sKCkgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSB0b3RhbCwgeSA9IHRvdGFsIC0xKSwgY29sb3IgPSAiYmxhY2siKSArIAogIHRoZW1lX2ZpdmV0aGlydHllaWdodCgpICsgICBzY2FsZV9jb2xvcl9maXZldGhpcnR5ZWlnaHQoKSArIAogIGxhYnMoCiAgICB0aXRsZSA9ICJJbmNyZWFzaW5nIEltYWdpbmF0aW9uIG9yIE1vcmUgTGVnbyBNb2RlbHMgdG8gU2VsbD8iLAogICAgc3VidGl0bGUgPSAiRWFjaCBlcHNpb2RlIGluIGEgdHJpbG9neSBpbnRyb2R1Y2VkIG1vcmUgc2hpcHMiLAogICAgeSA9ICIiCiAgKSArIAogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBOVUxMKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IGMoIkkiLCAiSUkiLCAiSUlJIiwgIklWIiwgIlYiLCAiVkkiLCAiVklJIiksIGJyZWFrcyA9IDE6NywgbWlub3JfYnJlYWtzID0gTlVMTCkKYGBgCgoqQmFkIGRhdGEgZm9yIGVwaXNvZGUgNz8qCgpJbnRlcmVzdGluZ2x5LCBpdCBhcHBlYXJzIHRoYXQgcHJlcXVlbHMgZm9sbG93ZWQgYSB0cmVuZCBpbiB0aGUgb3JpZ2luYWwgMyBtb3ZpZXMgYnkgaW50cm9kdWNpbmcgbW9yZSBzaGlwcyBvdmVyIHRpbWUuCgoKYGBge3Igc2hpcGluZm99CnBvcF9zaGlwcyA8LSB0aWJibGUoCiAgbmFtZSA9IG1hcF9jaHIoc2hpcHMsICJuYW1lIiksCiAgZmlsbXMgPSBtYXBfZGJsKHNoaXBzLCB+bGVuZ3RoKC54JGZpbG1zKSkKKQoKcG9wX3ZlaHMgPC0gdGliYmxlKAogIG5hbWUgPSBtYXBfY2hyKHZlaGljbGVzLCAibmFtZSIpLAogIGZpbG1zID0gbWFwX2RibCh2ZWhpY2xlcywgfmxlbmd0aCgueCRmaWxtcykpCikKCmFsbCA8LSByYmluZChwb3Bfc2hpcHMsIHBvcF92ZWhzKQpgYGAKCgpUaGlzIGdyYXBoIG1ha2VzIGl0IHRlbXB0aW5nIHRvIGp1bXAgdG8gY29uY2x1c2lvbnMsIGJ1dCB0aGVyZSBhcmUgb25seSBgciBucm93KGFsbClgIHVuaXF1ZSBzaGlwcyEgU29tZSBvZiB0aGUgc2hpcHMgYXBwZWFyIGluIG1vcmUgdGhhbiBvbmUgZXBpc29kZS4gVG8gZ2V0IGEgc2Vuc2UgZm9yIHNvbWUgb2YgdGhlIG1vc3QgcG9wdWxhciBzaGlwcywgd2UgY2FuIGNvdW50IHRoZSBudW1iZXIgb2YgbW92aWVzIHBlciBzaGlwOgoKCmBgYHtyIHNoaXBwbG90fQpwb3BfYWxsIDwtIHJiaW5kKHBvcF9zaGlwcywgcG9wX3ZlaHMpICU+JSAKICBmaWx0ZXIoZmlsbXMgPiAxKQoKZ2dwbG90KHBvcF9hbGwsIGFlcyhyZW9yZGVyKG5hbWUsIGZpbG1zKSwgZmlsbXMpKSArIAogIGdlb21fY29sKCkgKyAKICBjb29yZF9mbGlwKCkgKyAKICB0aGVtZV9maXZldGhpcnR5ZWlnaHQoKSArICAgc2NhbGVfY29sb3JfZml2ZXRoaXJ0eWVpZ2h0KCkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJQb3B1bGFyIFNoaXBzIiwKICAgIHN1YnRpdGxlID0gIlNoaXBzIHRoYXQgYXBwZWFyIGluIG11bHRpcGxlIGVwaXNvZGVzIiwKICAgIHggPSAiIgogICkgKwogIHNjYWxlX3lfY29udGludW91cyhtaW5vcl9icmVha3MgPSBOVUxMKQpgYGAKCgojIyBIb3cgYmlnIGlzIHRoZSBkZWF0aCBzdGFyPwoKSW4gYWRkaXRpb24gdG8gZGF0YSBvbiBzaGlwIGFwcGVhcmFuY2VzIGJ5IGZpbG0sIHdlIGFsc28gaGF2ZSBkYXRhIG9uIHNoaXAgY2hhcmFjdGVyaXN0aWNzIHN1Y2ggYXMgc2l6ZSBhbmQgc2hhcGUuIFVzaW5nIHRoaXMgZGF0YSwgbGV0cyB0cnkgdG8gZ2V0IGEgc2Vuc2UgZm9yIHRoZSBzY2FsZSBvZiB0aGUgaW5mYW1vdXMgRGVhdGggU3Rhci4gCgpXZSBzdGFydCBvdXQgc21hbGwsIGxvb2tpbmcgYXQgc29tZSBmYW1pbGlhciBmYXZvcml0ZXMgc3VjaCBhcyB0aGUgTWlsbGVuaXVtIEZhbGNvbi4KCmBgYHtyfQpzaGlwX2VwaXNvZGUgPC0gdGliYmxlKAogIGNyZXcgPSBtYXBfY2hyKHNoaXBzLCAiY3JldyIpICU+JSBwYXJzZV9udW1iZXIoKSwKICBjb3N0ID0gbWFwX2NocihzaGlwcywgImNvc3RfaW5fY3JlZGl0cyIpICU+JSBwYXJzZV9udW1iZXIoKSwKICBwYXNzZW5nZXJzID0gbWFwX2NocihzaGlwcywgInBhc3NlbmdlcnMiKSAlPiUgcGFyc2VfbnVtYmVyKCksCiAgY2FyZ28gPSBtYXBfY2hyKHNoaXBzLCAiY2FyZ29fY2FwYWNpdHkiKSAlPiUgcGFyc2VfbnVtYmVyKCksIAogIG5hbWUgPSBtYXBfY2hyKHNoaXBzLCAibmFtZSIpCikKCnBsb3RTaGlwIDwtIGZ1bmN0aW9uKGRhdGEsIG91dGxpZXJfYm91bmQgPSAxMGUxMDAsIG1haW4sIGxhYmVsX3NoaXBzKSB7CiAgCiAgbWYgPC0gZGF0YSAlPiUgCiAgICBmaWx0ZXIobmFtZSAlaW4lIGxhYmVsX3NoaXBzKQogIAogIGRhdGEgPC0gZGF0YSAlPiUgCiAgICBmaWx0ZXIoY3JldyA8IG91dGxpZXJfYm91bmQsIHBhc3NlbmdlcnMgPCBvdXRsaWVyX2JvdW5kKQogIAogIGRhdGEgJT4lIAogICAgZ2dwbG90KGFlcyhjcmV3LCBwYXNzZW5nZXJzLCBsYWJlbCA9IG5hbWUpKSArIAogICAgZ2VvbV9wb2ludCgpICsKICAgIGxhYnMoCiAgICAgIHRpdGxlICA9IG1haW4sCiAgICAgIHN1YnRpdGxlID0gIkNyZXcgdnMgUGFzc2VuZ2VycyIKICAgICkgKyAKICAgIHRoZW1lX2ZpdmV0aGlydHllaWdodCgpICsgICBzY2FsZV9jb2xvcl9maXZldGhpcnR5ZWlnaHQoKSArCiAgICBnZW9tX3BvaW50KGRhdGEgPSBtZikgKwogICAgZ2VvbV90ZXh0X3JlcGVsKGRhdGEgPSBtZiwgYWVzKGxhYmVsID0gbmFtZSkpCn0KYGBgCgpgYGB7ciB6b29tMX0KcGxvdFNoaXAoc2hpcF9lcGlzb2RlLCBvdXRsaWVyX2JvdW5kID0gMTAwLAogICAgICAgICAiUmVhc29uYWJsZSBTaXplIiwgCiAgICAgICAgIGxhYmVsX3NoaXBzID0gYygiTWlsbGVubml1bSBGYWxjb24iLCAiUmViZWwgdHJhbnNwb3J0IikpCmBgYAoKClRoZXJlIGFwcGVhcnMgdG8gYmUgYSBzbGlnaHQgdHJlbmQgYmV0d2VlbiB0aGUgbnVtYmVyIG9mIGNyZXcgYW5kIHRoZSBudW1iZXIgb2YgcGFzc2VuZ2VycywgdGhvdWdoIHRoZSBSZWJlbCBUcmFuc3BvcnQgdGhvcndzIHRoaW5ncyBvZmYuIEtlZXAgeW91ciBleWUgb24gUmViZWwgVHJhbnNwb3J0IGFzIHdlIHpvb20gb3V0OgoKYGBge3J9CnBsb3RTaGlwKHNoaXBfZXBpc29kZSwgCiAgICAgICAgIG91dGxpZXJfYm91bmQgPSAxMGUyLCAKICAgICAgICAgIkxhcmdlIEhpZ2ggU2Nob29sIiwgCiAgICAgICAgIGxhYmVsX3NoaXBzID0gYygiUmViZWwgdHJhbnNwb3J0IiwgIkNSOTAgY29ydmV0dGUiLCAiRUY3NiBOZWJ1bG9uLUIgZXNjb3J0IGZyaWdhdGUiKSkKYGBgCk5vdyB3ZSdyZSBpbnRyb2R1Y2luZyBzb21lIGJpZ2dlciBzaGlwcy4gQnV0IHdlIGNhbiBnbyBCSUdHRVI6CgpgYGB7cn0KcGxvdFNoaXAoc2hpcF9lcGlzb2RlLCBvdXRsaWVyX2JvdW5kID0gMTBlMywKICAgICAgICAgIkFpcmNyYWZ0IENhcnJpZXIiLAogICAgICAgICBjKCJDUjkwIGNvcnZldHRlIiwgIkVGNzYgTmVidWxvbi1CIGVzY29ydCBmcmlnYXRlIiwgIlJlcHVibGljIGF0dGFjayBjcnVpc2VyIikpCmBgYApUaGUgUmViZWwgVHJhbnNwb3J0IGZyb20gb3VyIGZpcnN0IHBsb3QgaXMgc3RpbGwgdmlzaWJsZSBpbiB0aGUgbG93ZXIgbGVmdCwgYnV0IHdlJ3ZlIGludHJvZHVjZWQgc2hpcHMgbXVjaCBsYXJnZXIuIFRoZSBSZXB1YmxpYyBBdHRhY2sgQ3J1aXNlciBwcmVzZW50cyBhbiBpbnRlcmVzdGluZyBtaXggb2YgY3JldyBhbmQgcGFzc2VuZ2Vycy4gTGV0J3Mgem9vbSBvdXQgYWdhaW46CgpgYGB7cn0KcGxvdFNoaXAoc2hpcF9lcGlzb2RlLCBvdXRsaWVyX2JvdW5kID0gMTBlNCwKICAgICAgICAgIkZvb3RiYWxsIFN0YWRpdW0iLCBjKCJSZXB1YmxpYyBhdHRhY2sgY3J1aXNlciIsICJTdGFyIERlc3Ryb3llciIsICJUcmFkZSBGZWRlcmF0aW9uIGNydWlzZXIiKSkKYGBgCgpOb3cgdGhlIFJlcHVibGljIEF0dGFjayBDcnVpc2VyIGxvb2tzIHNtYWxsLiBXZSd2ZSBpbnRyb2R1Y2VkIHNvbWUgZmFuIGZhdm9yaXRlcyBhbmQgdGhlIG1lbW9yYWJsZSBTdGFyIERlc3Ryb3llci4gV2hpbGUgNTAsMDAwIGNyZXcgbWVtYmVycyBtYXkgc2VlbSBsaWtlIGEgbG90LCB3ZSBhcmUgbm8gd2hlcmUgY2xvc2UgdG8gdGhlIERlYXRoIFN0YXI6CgpgYGB7cn0KcGxvdFNoaXAoc2hpcF9lcGlzb2RlLCBtYWluID0gIlRoZSBTdGF0ZSBvZiBNYWluZSIsIAogICAgICAgIGxhYmVsX3NoaXBzID0gYygiU3RhciBEZXN0cm95ZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAiVHJhZGUgRmVkZXJhdGlvbiBjcnVpc2VyIiwKICAgICAgICAgICAgICAgICAgICAgICAgIkRlYXRoIFN0YXIiLAogICAgICAgICAgICAgICAgICAgICAgICAiRHJvaWQgY29udHJvbCBzaGlwIiwKICAgICAgICAgICAgICAgICAgICAgICAgIkV4ZWN1dG9yIikpCmBgYAoKRG9uJ3QgbWlzcyB0aGUgU3RhciBEZXN0cnllciBzaXR0aW5nIGluIHRoZSBsb3dlciBsZWZ0LiBUaGUgc2NhbGUgb2YgdGhlIERlYXRoIFN0YXIgaXMgaGFyZCB0byBpbWFnaW5lISBXZSd2ZSBhbHNvIGludHJvZHVjZWQgdHdvIG90aGVyIGdpZ2FudGljIHNoaXBzOiB0aGUgRHJvaWQgQ29udHJvbCBTaGlwIChubyBjcmV3IC4uLikgYW5kIHRoZSBFeGVjdXRvci4K