knitr::opts_chunk$set(echo = TRUE, warning=FALSE, message=FALSE)
options(scipen=10000000)
options(digits=3)
library(knitr)

library(dplyr)
library(tidyverse)
library(ggplot2)
library(gridExtra)
library(ggrepel)
library(boxoffice)

Session 1: Setup and Examples

Session Overview

We’ll get everyone setup (quickly, as long as you did the Prequisites and Preparation Steps above), get familiar with RStudio, learn how to extend it with new packages (and load them). Then look at some good examples of getting useful insights or making tough decisions with the help of data analysis, and finally see how to get large amounts of data from external websites.

  • Setup your RStudio account, install important packages
  • Create a file, add useful packages (via the library() command)
  • Have fun playing around with data about movie sales
  • Write notes (to yourself), storytelling, and code inside the file.
  • Execute chunks of the file or the entire file.
  • Publish your results to the web!

After the basic steps of learning our way around RStudio, we’ll do something fun! We’ll write some code to download movie sales data, process it, and visualize it.

For the rest and details, see https://rpubs.com/hkb/DAX-Session1.

Session Plan

Boxoffice Movie Data

There are many sites that supply box office sales data. We’ll pick one for now (boxofficemojo.com) and do some analyses, but later you will repeat and run your own analyses with other data sources. Here’s the code and a sample of the data retrieved.

# Let's define time periods for which to collect data
date.seq <- paste(2010:2019,"-12-31",sep="")

# date.seq <- c(as.Date("2013-12-31"),as.Date("2014-12-31"),as.Date("2015-12-31"), as.Date("2016-12-31"),as.Date("2017-12-31"),as.Date("2018-12-31"),as.Date("2019-12-31"))

# Fetch the data 
movies <- boxoffice(date = as.Date(date.seq), top_n = 50)
 
dim(movies) # what is the size of the data frame
names(movies) # or, movies %>% names # names of the columns of the data frame
kable(head(movies))

A few commands featured above include 1) assignment to an object, 2) selection of a subset of data from a data frame,

We can modify or extend the data. For instance, we’ll want to isolate the Year (from the date field). Also, it will be useful to rank movies by sales (within each year), and create a new rank variable.


movies <- movies %>% na.omit() %>% mutate(Year =  as.numeric(format(as.Date(date), "%Y")))

# Extract the Year, then Rank by Sales
movies <- movies %>% group_by(Year) %>% arrange(desc(total_gross)) %>%  mutate(rank=row_number())

Now let’s take a look at the data. You can look at the data in tabular form (let’s do that in the RStudio interface). But it will be more insightful to construct visualizations of the data. Let’s start by looking at total_gross revenues for each rank within each year.

Visualizations of box office sales

p1 <- ggplot(movies, aes(x=rank,y=total_gross)) + geom_line(aes(color=as.factor(Year))) + theme_classic()

p2 <- p1 + coord_trans(y = "log10") 

grid.arrange(p1, p2, ncol=2)

What are the top movies of the year, and how much are they total_grossing? To make the question (or answers) more meaningful let’s limit the analysis to the top 10 movies each year. To get a sense of the differences in sales, let’s take a quick look at the #1 and #10 ranked movies each year.

movies.top10 <- movies %>% filter(rank %in% c(1,10)) %>% group_by(Year) %>% arrange(rank)
kable(movies.top10 %>% select(movie, Year, rank, total_gross) %>% arrange(Year))
plot(1:10000, log(1:10000),type="l")

Looking at the numbers it seems that the top-1 and top-10 have hugely different sales numbers. Putting all of them (and all between these ranks) into the same chart will make it very hard to see the differences. In such cases it is useful to use a log transformation, which brings the numbers closer together and easier to see.

The graph we’ll produce has the rank as the x (horizontal) axis and gross revenues as the y (vertical axis). We’ll identify the movie itself by placing a dot (bullet) based on its (x,y) value, and write the name of the movie as close to the bullet as possible.

ggplot(data=movies %>% filter(rank < 11), aes(x=rank, y=total_gross, color=factor(Year))) + geom_point() + theme_classic() + theme(axis.text.x = element_text(size=12), axis.text.y = element_text(size=12), axis.title.x = element_text(size = rel(1.5)), axis.title.y = element_text(size = rel(1.5), margin = margin(t = 0, r = 20, b = 0, l = 10))) + geom_text_repel(aes(label = movie), nudge_y=1, force=6, box.padding = unit(0.75, "lines"), segment.color="gray") + coord_trans(y = 'log10')

Who’s making the winning movies? This is identified by the “distributor” column. So, this time we’ll write the distributor’s name rather than the movie name.

ggplot(data=movies %>% filter(rank < 11), aes(x=rank, y=total_gross, color=factor(Year))) + geom_point() + theme_classic() + theme(axis.text.x = element_text(size=12), axis.text.y = element_text(size=12), axis.title.x = element_text(size = rel(1.5)), axis.title.y = element_text(size = rel(1.5), margin = margin(t = 0, r = 20, b = 0, l = 10))) + geom_text_repel(aes(label = distributor), nudge_y=1, force=6, box.padding = unit(0.75, "lines"), segment.color="gray") + coord_trans(y = 'log10')

# ggsave()
LS0tCnRpdGxlOiAiU2Vzc2lvbiAxIgphdXRob3I6ICJIS0IiCmRhdGU6ICI3LzIyLzIwMjAiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCmBgYHtyIHNldHVwfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UpCm9wdGlvbnMoc2NpcGVuPTEwMDAwMDAwKQpvcHRpb25zKGRpZ2l0cz0zKQpgYGAKCmBgYHtyIHBhY2thZ2VzfQpsaWJyYXJ5KGtuaXRyKQoKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShncmlkRXh0cmEpCmxpYnJhcnkoZ2dyZXBlbCkKbGlicmFyeShib3hvZmZpY2UpCmBgYAoKIyMgU2Vzc2lvbiAxOiBTZXR1cCBhbmQgRXhhbXBsZXMgey50YWJzZXR9CgoKIyMjIFNlc3Npb24gT3ZlcnZpZXcKCldlJ2xsIGdldCBldmVyeW9uZSBzZXR1cCAocXVpY2tseSwgYXMgbG9uZyBhcyB5b3UgZGlkIHRoZSBQcmVxdWlzaXRlcyBhbmQgUHJlcGFyYXRpb24gU3RlcHMgYWJvdmUpLCBnZXQgZmFtaWxpYXIgd2l0aCBSU3R1ZGlvLCBsZWFybiBob3cgdG8gZXh0ZW5kIGl0IHdpdGggbmV3IHBhY2thZ2VzIChhbmQgbG9hZCB0aGVtKS4gVGhlbiBsb29rIGF0IHNvbWUgZ29vZCBleGFtcGxlcyBvZiBnZXR0aW5nIHVzZWZ1bCBpbnNpZ2h0cyBvciBtYWtpbmcgdG91Z2ggZGVjaXNpb25zIHdpdGggdGhlIGhlbHAgb2YgZGF0YSBhbmFseXNpcywgYW5kIGZpbmFsbHkgc2VlIGhvdyB0byBnZXQgbGFyZ2UgYW1vdW50cyBvZiBkYXRhIGZyb20gZXh0ZXJuYWwgd2Vic2l0ZXMuCgoqIFNldHVwIHlvdXIgUlN0dWRpbyBhY2NvdW50LCBpbnN0YWxsIGltcG9ydGFudCBwYWNrYWdlcwoqIENyZWF0ZSBhIGZpbGUsIGFkZCB1c2VmdWwgcGFja2FnZXMgKHZpYSB0aGUgbGlicmFyeSgpIGNvbW1hbmQpCiogSGF2ZSBmdW4gcGxheWluZyBhcm91bmQgd2l0aCBkYXRhIGFib3V0IG1vdmllIHNhbGVzCiogV3JpdGUgbm90ZXMgKHRvIHlvdXJzZWxmKSwgc3Rvcnl0ZWxsaW5nLCBhbmQgY29kZSBpbnNpZGUgdGhlIGZpbGUuIAoqIEV4ZWN1dGUgY2h1bmtzIG9mIHRoZSBmaWxlIG9yIHRoZSBlbnRpcmUgZmlsZS4gCiogUHVibGlzaCB5b3VyIHJlc3VsdHMgdG8gdGhlIHdlYiEgCgpBZnRlciB0aGUgYmFzaWMgc3RlcHMgb2YgbGVhcm5pbmcgb3VyIHdheSBhcm91bmQgUlN0dWRpbywgd2UnbGwgZG8gc29tZXRoaW5nIGZ1biEgV2UnbGwgd3JpdGUgc29tZSBjb2RlIHRvIGRvd25sb2FkIG1vdmllIHNhbGVzIGRhdGEsIHByb2Nlc3MgaXQsIGFuZCB2aXN1YWxpemUgaXQuIAoKRm9yIHRoZSByZXN0IGFuZCBkZXRhaWxzLCBzZWUgaHR0cHM6Ly9ycHVicy5jb20vaGtiL0RBWC1TZXNzaW9uMS4KCiMjIyBTZXNzaW9uIFBsYW4KCgo8IS0tIFNlcXVlbmNlOiAKKiBSZWNvcmRpbmcgLyBzaGFyaW5nIGNvbnRhY3QgaW5mb3JtYXRpb24KKiBJbnRyb2R1Y3Rpb25zIChzJ3RoaW5nIHdlbGwga25vd24gYW5kIG5vdCBzbyB3ZWxsIGtub3duIGFib3V0IHlvdSkgCiAgLSBGb3JtYXQgLyBab29tIHJ1bGVzIC0gbWljIG11dGUsIHZpZGVvLCBzY3JlZW4gc2hhcmluZyAKICAtIExlYXJuaW5nIG9iamVjdGl2ZXMgLSBpZGVudGlmeSB5b3VyIG93biAoYXNzaWdubWVudCkKICAtIE92ZXJ2aWV3L0NoZWNrbGlzdCBvZiBSU3R1ZGlvIHNldHVwOiBNYWxsaWthIHNoYXJlLCBpbnN0YWxsIHBhY2thZ2VzLCBuZXcgc2VjdGlvbiBvbiBUby1Eb3MsIGNvZGUgY2h1bmsKICAtIHB1Ymxpc2ggdGhlIHBhZ2UsIHBvc3QgdXJsIG9uIFpvb20gY2hhdAogIC0gZm9ybSBncm91cCAob2YgMykgLSBjb21wbGV0ZSBhc3NpZ25tZW50cyAobGVhcm5pbmcgb2JqZWN0aXZlcywgYW5kIHdoaWNoIGdyYXBoIHR5cGVzKQoqIFdoeSBhcmUgd2UgaGVyZT8ga2lsbCB0aW1lOyBmdW47IGxlYXJuaW5nIHNvbWV0aGluZzsgCiogV29yayBpbiBSU3R1ZGlvLCBSTWFya2Rvd24KICAtIFJTdHVkaW8gZW52aXJvbm1lbnQgYW5kIG1lbnVzLCBwYW5lL2xheW91dAogIC0gU2VsZWN0IGNvZGUgY2h1bmtzIGFuZCBleGVjdXRlICgiUnVuIikKICAtICJrbml0IiBhbmQgcHVibGlzaCB0aGUgZG9jdW1lbnQKKiBNb3ZpZSBkYXRhIGFuYWx5c2lzLCB0YWtlIG5vdGVzLCBwdWJsaXNoIHRvIHdlYgoqIFBvc3QtY2xhc3MgYXNzaWdubWVudHMKICAtIENyZWF0ZSBhIHF1ZXN0aW9uIHRvIGFuc3dlciB3aXRoIHRoZSBtb3ZpZSBkYXRhOiBlLmcuLCAiRG8gQS1saXN0IHN0YXJzIGd1YXJhbnRlZSBoaWdoIGJveCBvZmZpY2Ugc2FsZXM/IE9yIGlzIGl0IHN1cGVyaGVybyBjaGFyYWN0ZXJzPyIKICAtIHJlcGVhdCB0aGUgbW92aWUgcmV2ZW51ZXMgdmlzdWFsaXphdGlvbiB3aXRoIGRhdGEgZnJvbSAyMDAwLTIwMDksIGlkZW50aWZ5IGFueSBsYXJnZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZSAyMDAwLTA5IGFuZCAyMDEwLTE5IHJlc3VsdHMuICAKLS0+IAoKIyMjIEJveG9mZmljZSBNb3ZpZSBEYXRhCgpUaGVyZSBhcmUgbWFueSBzaXRlcyB0aGF0IHN1cHBseSBib3ggb2ZmaWNlIHNhbGVzIGRhdGEuIFdlJ2xsIHBpY2sgb25lIGZvciBub3cgKGJveG9mZmljZW1vam8uY29tKSBhbmQgZG8gc29tZSBhbmFseXNlcywgYnV0IGxhdGVyIHlvdSB3aWxsIHJlcGVhdCBhbmQgcnVuIHlvdXIgb3duIGFuYWx5c2VzIHdpdGggb3RoZXIgZGF0YSBzb3VyY2VzLiBIZXJlJ3MgdGhlIGNvZGUgYW5kIGEgc2FtcGxlIG9mIHRoZSBkYXRhIHJldHJpZXZlZC4gCgpgYGB7ciBib3hvZmZpY2V9CiMgTGV0J3MgZGVmaW5lIHRpbWUgcGVyaW9kcyBmb3Igd2hpY2ggdG8gY29sbGVjdCBkYXRhCmRhdGUuc2VxIDwtIHBhc3RlKDIwMTA6MjAxOSwiLTEyLTMxIixzZXA9IiIpCgojIGRhdGUuc2VxIDwtIGMoYXMuRGF0ZSgiMjAxMy0xMi0zMSIpLGFzLkRhdGUoIjIwMTQtMTItMzEiKSxhcy5EYXRlKCIyMDE1LTEyLTMxIiksIGFzLkRhdGUoIjIwMTYtMTItMzEiKSxhcy5EYXRlKCIyMDE3LTEyLTMxIiksYXMuRGF0ZSgiMjAxOC0xMi0zMSIpLGFzLkRhdGUoIjIwMTktMTItMzEiKSkKCiMgRmV0Y2ggdGhlIGRhdGEgCm1vdmllcyA8LSBib3hvZmZpY2UoZGF0ZSA9IGFzLkRhdGUoZGF0ZS5zZXEpLCB0b3BfbiA9IDUwKQogCmRpbShtb3ZpZXMpICMgd2hhdCBpcyB0aGUgc2l6ZSBvZiB0aGUgZGF0YSBmcmFtZQpuYW1lcyhtb3ZpZXMpICMgb3IsIG1vdmllcyAlPiUgbmFtZXMgIyBuYW1lcyBvZiB0aGUgY29sdW1ucyBvZiB0aGUgZGF0YSBmcmFtZQprYWJsZShoZWFkKG1vdmllcykpCmBgYAoKQSBmZXcgY29tbWFuZHMgZmVhdHVyZWQgYWJvdmUgaW5jbHVkZSAxKSBhc3NpZ25tZW50IHRvIGFuIG9iamVjdCwgMikgc2VsZWN0aW9uIG9mIGEgc3Vic2V0IG9mIGRhdGEgZnJvbSBhIGRhdGEgZnJhbWUsIAoKV2UgY2FuIG1vZGlmeSBvciBleHRlbmQgdGhlIGRhdGEuIEZvciBpbnN0YW5jZSwgd2UnbGwgd2FudCB0byBpc29sYXRlIHRoZSBZZWFyIChmcm9tIHRoZSBkYXRlIGZpZWxkKS4gQWxzbywgaXQgd2lsbCBiZSB1c2VmdWwgdG8gcmFuayBtb3ZpZXMgYnkgc2FsZXMgKHdpdGhpbiBlYWNoIHllYXIpLCBhbmQgY3JlYXRlIGEgbmV3IHJhbmsgdmFyaWFibGUuIAoKYGBge3IgbW92aWVzLmV4dGVuZH0KCm1vdmllcyA8LSBtb3ZpZXMgJT4lIG5hLm9taXQoKSAlPiUgbXV0YXRlKFllYXIgPSAgYXMubnVtZXJpYyhmb3JtYXQoYXMuRGF0ZShkYXRlKSwgIiVZIikpKQoKIyBFeHRyYWN0IHRoZSBZZWFyLCB0aGVuIFJhbmsgYnkgU2FsZXMKbW92aWVzIDwtIG1vdmllcyAlPiUgZ3JvdXBfYnkoWWVhcikgJT4lIGFycmFuZ2UoZGVzYyh0b3RhbF9ncm9zcykpICU+JSAgbXV0YXRlKHJhbms9cm93X251bWJlcigpKQoKYGBgCgpOb3cgbGV0J3MgdGFrZSBhIGxvb2sgYXQgdGhlIGRhdGEuIFlvdSBjYW4gbG9vayBhdCB0aGUgZGF0YSBpbiB0YWJ1bGFyIGZvcm0gKGxldCdzIGRvIHRoYXQgaW4gdGhlIFJTdHVkaW8gaW50ZXJmYWNlKS4gQnV0IGl0IHdpbGwgYmUgbW9yZSBpbnNpZ2h0ZnVsIHRvIGNvbnN0cnVjdCB2aXN1YWxpemF0aW9ucyBvZiB0aGUgZGF0YS4gTGV0J3Mgc3RhcnQgYnkgbG9va2luZyBhdCB0b3RhbF9ncm9zcyByZXZlbnVlcyBmb3IgZWFjaCByYW5rIHdpdGhpbiBlYWNoIHllYXIuIAoKIyMjIFZpc3VhbGl6YXRpb25zIG9mIGJveCBvZmZpY2Ugc2FsZXMKCmBgYHtyIG1vdmllcy5yYW5rLnBsb3QsZmlnLndpZHRoPTE0LGZpZy5oZWlnaHQ9M30KcDEgPC0gZ2dwbG90KG1vdmllcywgYWVzKHg9cmFuayx5PXRvdGFsX2dyb3NzKSkgKyBnZW9tX2xpbmUoYWVzKGNvbG9yPWFzLmZhY3RvcihZZWFyKSkpICsgdGhlbWVfY2xhc3NpYygpCgpwMiA8LSBwMSArIGNvb3JkX3RyYW5zKHkgPSAibG9nMTAiKSAKCmdyaWQuYXJyYW5nZShwMSwgcDIsIG5jb2w9MikKYGBgCgpXaGF0IGFyZSB0aGUgdG9wIG1vdmllcyBvZiB0aGUgeWVhciwgYW5kIGhvdyBtdWNoIGFyZSB0aGV5IHRvdGFsX2dyb3NzaW5nPyBUbyBtYWtlIHRoZSBxdWVzdGlvbiAob3IgYW5zd2VycykgbW9yZSBtZWFuaW5nZnVsIGxldCdzIGxpbWl0IHRoZSBhbmFseXNpcyB0byB0aGUgdG9wIDEwIG1vdmllcyBlYWNoIHllYXIuIFRvIGdldCBhIHNlbnNlIG9mIHRoZSBkaWZmZXJlbmNlcyBpbiBzYWxlcywgbGV0J3MgdGFrZSBhIHF1aWNrIGxvb2sgYXQgdGhlICMxIGFuZCAjMTAgcmFua2VkIG1vdmllcyBlYWNoIHllYXIuIAoKYGBge3IgdG9wMTB9Cm1vdmllcy50b3AxMCA8LSBtb3ZpZXMgJT4lIGZpbHRlcihyYW5rICVpbiUgYygxLDEwKSkgJT4lIGdyb3VwX2J5KFllYXIpICU+JSBhcnJhbmdlKHJhbmspCmthYmxlKG1vdmllcy50b3AxMCAlPiUgc2VsZWN0KG1vdmllLCBZZWFyLCByYW5rLCB0b3RhbF9ncm9zcykgJT4lIGFycmFuZ2UoWWVhcikpCmBgYAoKYGBge3IgZXhhbXBsZX0KcGxvdCgxOjEwMDAwLCBsb2coMToxMDAwMCksdHlwZT0ibCIpCmBgYAoKCgoKCkxvb2tpbmcgYXQgdGhlIG51bWJlcnMgaXQgc2VlbXMgdGhhdCB0aGUgdG9wLTEgYW5kIHRvcC0xMCBoYXZlIGh1Z2VseSBkaWZmZXJlbnQgc2FsZXMgbnVtYmVycy4gUHV0dGluZyBhbGwgb2YgdGhlbSAoYW5kIGFsbCBiZXR3ZWVuIHRoZXNlIHJhbmtzKSBpbnRvIHRoZSBzYW1lIGNoYXJ0IHdpbGwgbWFrZSBpdCB2ZXJ5IGhhcmQgdG8gc2VlIHRoZSBkaWZmZXJlbmNlcy4gSW4gc3VjaCBjYXNlcyBpdCBpcyB1c2VmdWwgdG8gdXNlIGEgbG9nIHRyYW5zZm9ybWF0aW9uLCB3aGljaCBicmluZ3MgdGhlIG51bWJlcnMgY2xvc2VyIHRvZ2V0aGVyIGFuZCBlYXNpZXIgdG8gc2VlLiAKClRoZSBncmFwaCB3ZSdsbCBwcm9kdWNlIGhhcyB0aGUgcmFuayBhcyB0aGUgeCAoaG9yaXpvbnRhbCkgYXhpcyBhbmQgZ3Jvc3MgcmV2ZW51ZXMgYXMgdGhlIHkgKHZlcnRpY2FsIGF4aXMpLiBXZSdsbCBpZGVudGlmeSB0aGUgbW92aWUgaXRzZWxmIGJ5IHBsYWNpbmcgYSBkb3QgKGJ1bGxldCkgYmFzZWQgb24gaXRzICh4LHkpIHZhbHVlLCBhbmQgd3JpdGUgdGhlIG5hbWUgb2YgdGhlIG1vdmllIGFzIGNsb3NlIHRvIHRoZSBidWxsZXQgYXMgcG9zc2libGUuIAoKYGBge3IgbW92aWVzLnJhbmtzLCBmaWcud2lkdGg9MTUsZmlnLmhlaWdodD03fQpnZ3Bsb3QoZGF0YT1tb3ZpZXMgJT4lIGZpbHRlcihyYW5rIDwgMTEpLCBhZXMoeD1yYW5rLCB5PXRvdGFsX2dyb3NzLCBjb2xvcj1mYWN0b3IoWWVhcikpKSArIGdlb21fcG9pbnQoKSArIHRoZW1lX2NsYXNzaWMoKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9MTIpLCBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSwgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMS41KSksIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDEuNSksIG1hcmdpbiA9IG1hcmdpbih0ID0gMCwgciA9IDIwLCBiID0gMCwgbCA9IDEwKSkpICsgZ2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbCA9IG1vdmllKSwgbnVkZ2VfeT0xLCBmb3JjZT02LCBib3gucGFkZGluZyA9IHVuaXQoMC43NSwgImxpbmVzIiksIHNlZ21lbnQuY29sb3I9ImdyYXkiKSArIGNvb3JkX3RyYW5zKHkgPSAnbG9nMTAnKQpgYGAKCldobydzIG1ha2luZyB0aGUgd2lubmluZyBtb3ZpZXM/IFRoaXMgaXMgaWRlbnRpZmllZCBieSB0aGUgImRpc3RyaWJ1dG9yIiBjb2x1bW4uIFNvLCB0aGlzIHRpbWUgd2UnbGwgd3JpdGUgdGhlIGRpc3RyaWJ1dG9yJ3MgbmFtZSByYXRoZXIgdGhhbiB0aGUgbW92aWUgbmFtZS4gCgpgYGB7ciBtb3ZpZXMucmFua3MuZGlzdHJpYnV0b3IsICBmaWcud2lkdGg9MTUsZmlnLmhlaWdodD03fQpnZ3Bsb3QoZGF0YT1tb3ZpZXMgJT4lIGZpbHRlcihyYW5rIDwgMTEpLCBhZXMoeD1yYW5rLCB5PXRvdGFsX2dyb3NzLCBjb2xvcj1mYWN0b3IoWWVhcikpKSArIGdlb21fcG9pbnQoKSArIHRoZW1lX2NsYXNzaWMoKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9MTIpLCBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSwgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMS41KSksIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDEuNSksIG1hcmdpbiA9IG1hcmdpbih0ID0gMCwgciA9IDIwLCBiID0gMCwgbCA9IDEwKSkpICsgZ2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbCA9IGRpc3RyaWJ1dG9yKSwgbnVkZ2VfeT0xLCBmb3JjZT02LCBib3gucGFkZGluZyA9IHVuaXQoMC43NSwgImxpbmVzIiksIHNlZ21lbnQuY29sb3I9ImdyYXkiKSArIGNvb3JkX3RyYW5zKHkgPSAnbG9nMTAnKQoKIyBnZ3NhdmUoKQpgYGAK