** Please click all the tabs (in sequence) to get the entire set of information in these pages. **

** You can download all the code by clicking “Code” as shown in this picture. **

First we’ll declare some useful configuration settings. Don’t worry if you don’t understand why.

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

Next add a few packages that are handy. These packages need to first be installed. If they’re not already in your system, you should see a note/yellow banner above from RStudio asking if it should install these packages for you. Silently mutter “Oh thanks RStudio” and click Yes.

# install.packages("knitr")
library(knitr)

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

Now there is one special package that is not installed in the usual way. “boxoffice” (through which we’ll get movie sales data). To install it, run this next chunk once (by ensuring it says “eval=TRUE”) then switch to eval=FALSE.

install.packages("devtools")
devtools::install_github("jacobkap/boxoffice")

Session 2: Let’s get our hands dirty

Our first text (this) and code chunk (below).

2+2 # 
[1] 4
1:5 # generate a sequence of integers
[1] 1 2 3 4 5
vector.1 <- 1:5 # assign the name vector.1 to this sequence
vector.1 + 5 # add 5 to every element of the vector
[1]  6  7  8  9 10
vector.2 <- vector.1 + 5:6 # add 5 to the 1st element, then 6 to second, 
vector.2 # print vector.2
[1]  6  8  8 10 10
mean(vector.1)
[1] 3
c(sum(vector.1), sum(vector.2), mean(vector.2), min(vector.2), max(vector.2))
[1] 15.0 42.0  8.4  6.0 10.0

The movies data

Ok, now that we’ve done some basic things let’s move on to something useful. We’ll pull data about movie sales from the “boxoffice” data source (for which we installed the boxoffice package above). First we have to decide what time frame we want the data for.

# Let's define time periods for which to collect data
date.seq <- paste(2000:2009,"-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
[1] 189   9
names(movies) # or, movies %>% names # names of the columns of the data frame
[1] "movie"          "distributor"    "gross"          "percent_change"
[5] "theaters"       "per_theater"    "total_gross"    "days"          
[9] "date"          
kable(head(movies))
movie distributor gross percent_change theaters per_theater total_gross days date
Cast Away 20th Century 7938594 -32 2927 2712 100628594 10 2000-12-31
What Women Want Paramount Pi 4955561 -40 3046 1627 110187561 17 2000-12-31
The Family Man Universal 3010330 -40 2395 1257 39170330 10 2000-12-31
The Emperor’s New Groove Walt Disney 2814336 -29 2887 975 47465336 17 2000-12-31
Miss Congeniality Warner Bros. 2142573 -64 2668 803 40784573 10 2000-12-31
How the Grinch Stole Chri Universal 1524105 -42 3170 481 251629105 45 2000-12-31

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"))) # na.omit() omits the rows with NA values; create new column Year. which extracts the Y (year) from the date

# Extract the Year, then Rank by Sales

movies <- movies %>% group_by(Year) %>% arrange(desc(total_gross)) %>%  mutate(rank=row_number())

Visualizations of box office sales

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.

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

p2 <- p1 + coord_trans(y = "log10") # convert y axis to log scale

grid.arrange(p1, p2, ncol=2) # arrange both plots side by side, in two columns

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))
movie Year rank total_gross
How the Grinch Stole Chri 2000 1 251629105
All the Pretty Horses 2000 10 7640564
Harry Potter and the Sorc 2001 1 288493000
A Beautiful Mind 2001 10 15949000
Harry Potter and the Cham 2002 1 243855000
The Hot Chick 2002 10 24021000
The Lord of the Rings: Th 2003 1 249400000
Peter Pan 2003 10 22000000
The Polar Express 2004 1 151623383
Harry Potter and the Gobl 2005 1 273281180
The Ringer 2005 10 17265628
The Polar Express 2006 1 176454984
Rocky Balboa 2006 10 47940632
I am Legend 2007 1 199345154
Mr. Magorium’s Wonder Emp 2007 10 31049456
The Dark Knight 2008 1 530924926
Yes Man 2008 10 60029690
The Twilight Saga: New Moon 2009 1 284512392
Paranormal Activity 2009 10 107792845

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()
LS0tCnRpdGxlOiAiU2Vzc2lvbiAyIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgoqKiBQbGVhc2UgY2xpY2sgYWxsIHRoZSB0YWJzIChpbiBzZXF1ZW5jZSkgdG8gZ2V0IHRoZSBlbnRpcmUgc2V0IG9mIGluZm9ybWF0aW9uIGluIHRoZXNlIHBhZ2VzLiAqKgoKKiogWW91IGNhbiBkb3dubG9hZCBhbGwgdGhlIGNvZGUgYnkgY2xpY2tpbmcgIkNvZGUiIGFzIHNob3duIGluIHRoaXMgcGljdHVyZS4gKioKCmBgYHtyIGZpZy5hbGlnbj0iY2VudGVyIiwgb3V0LndpZHRoPSI1MCUiLCBlY2hvPUZBTFNFfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiSW1hZ2VzL3Nlc3Npb24yLWNvZGUucG5nIikKYGBgCgpGaXJzdCB3ZSdsbCBkZWNsYXJlIHNvbWUgdXNlZnVsIGNvbmZpZ3VyYXRpb24gc2V0dGluZ3MuIERvbid0IHdvcnJ5IGlmIHlvdSBkb24ndCB1bmRlcnN0YW5kIHdoeS4gCgpgYGB7ciBzZXR1cH0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFKQpvcHRpb25zKHNjaXBlbj0xMDAwMDAwMCkKb3B0aW9ucyhkaWdpdHM9MykKYGBgCgpOZXh0IGFkZCBhIGZldyBwYWNrYWdlcyB0aGF0IGFyZSBoYW5keS4gVGhlc2UgcGFja2FnZXMgbmVlZCB0byBmaXJzdCBiZSBpbnN0YWxsZWQuIElmIHRoZXkncmUgbm90IGFscmVhZHkgaW4geW91ciBzeXN0ZW0sIHlvdSBzaG91bGQgc2VlIGEgbm90ZS95ZWxsb3cgYmFubmVyIGFib3ZlIGZyb20gUlN0dWRpbyBhc2tpbmcgaWYgaXQgc2hvdWxkIGluc3RhbGwgdGhlc2UgcGFja2FnZXMgZm9yIHlvdS4gU2lsZW50bHkgbXV0dGVyICJPaCB0aGFua3MgUlN0dWRpbyIgYW5kIGNsaWNrIFllcy4gCgpgYGB7ciBwYWNrYWdlc30KIyBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpCmxpYnJhcnkoa25pdHIpCgpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KGJveG9mZmljZSkKYGBgCgpOb3cgdGhlcmUgaXMgb25lIHNwZWNpYWwgcGFja2FnZSB0aGF0IGlzIG5vdCBpbnN0YWxsZWQgaW4gdGhlIHVzdWFsIHdheS4gImJveG9mZmljZSIgKHRocm91Z2ggd2hpY2ggd2UnbGwgZ2V0IG1vdmllIHNhbGVzIGRhdGEpLiBUbyBpbnN0YWxsIGl0LCBydW4gdGhpcyBuZXh0IGNodW5rIG9uY2UgKGJ5IGVuc3VyaW5nIGl0IHNheXMgImV2YWw9VFJVRSIpIHRoZW4gc3dpdGNoIHRvIGV2YWw9RkFMU0UuIAoKYGBge3Igb25ldGltZSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZXZhbD1GQUxTRX0gCmluc3RhbGwucGFja2FnZXMoImRldnRvb2xzIikKZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJqYWNvYmthcC9ib3hvZmZpY2UiKQpgYGAKCgojIyBTZXNzaW9uIDI6IExldCdzIGdldCBvdXIgaGFuZHMgZGlydHkgey50YWJzZXR9CgpPdXIgZmlyc3QgdGV4dCAodGhpcykgYW5kIGNvZGUgY2h1bmsgKGJlbG93KS4gCgpgYGB7ciBleGFtcGxlfQoyKzIgIyAKMTo1ICMgZ2VuZXJhdGUgYSBzZXF1ZW5jZSBvZiBpbnRlZ2Vycwp2ZWN0b3IuMSA8LSAxOjUgIyBhc3NpZ24gdGhlIG5hbWUgdmVjdG9yLjEgdG8gdGhpcyBzZXF1ZW5jZQp2ZWN0b3IuMSArIDUgIyBhZGQgNSB0byBldmVyeSBlbGVtZW50IG9mIHRoZSB2ZWN0b3IKdmVjdG9yLjIgPC0gdmVjdG9yLjEgKyA1OjYgIyBhZGQgNSB0byB0aGUgMXN0IGVsZW1lbnQsIHRoZW4gNiB0byBzZWNvbmQsIAp2ZWN0b3IuMiAjIHByaW50IHZlY3Rvci4yCm1lYW4odmVjdG9yLjEpCmMoc3VtKHZlY3Rvci4xKSwgc3VtKHZlY3Rvci4yKSwgbWVhbih2ZWN0b3IuMiksIG1pbih2ZWN0b3IuMiksIG1heCh2ZWN0b3IuMikpCmBgYAogCiMjIFRoZSBtb3ZpZXMgZGF0YSAKIApPaywgbm93IHRoYXQgd2UndmUgZG9uZSBzb21lIGJhc2ljIHRoaW5ncyBsZXQncyBtb3ZlIG9uIHRvIHNvbWV0aGluZyB1c2VmdWwuIFdlJ2xsIHB1bGwgZGF0YSBhYm91dCBtb3ZpZSBzYWxlcyBmcm9tIHRoZSAiYm94b2ZmaWNlIiBkYXRhIHNvdXJjZSAoZm9yIHdoaWNoIHdlIGluc3RhbGxlZCB0aGUgYm94b2ZmaWNlIHBhY2thZ2UgYWJvdmUpLiBGaXJzdCB3ZSBoYXZlIHRvIGRlY2lkZSB3aGF0IHRpbWUgZnJhbWUgd2Ugd2FudCB0aGUgZGF0YSBmb3IuICAKIApgYGB7ciBib3hvZmZpY2V9CiMgTGV0J3MgZGVmaW5lIHRpbWUgcGVyaW9kcyBmb3Igd2hpY2ggdG8gY29sbGVjdCBkYXRhCmRhdGUuc2VxIDwtIHBhc3RlKDIwMDA6MjAwOSwiLTEyLTMxIixzZXA9IiIpCgojIGRhdGUuc2VxIDwtIGMoYXMuRGF0ZSgiMjAxMy0xMi0zMSIpLGFzLkRhdGUoIjIwMTQtMTItMzEiKSxhcy5EYXRlKCIyMDE1LTEyLTMxIiksIGFzLkRhdGUoIjIwMTYtMTItMzEiKSxhcy5EYXRlKCIyMDE3LTEyLTMxIiksYXMuRGF0ZSgiMjAxOC0xMi0zMSIpLGFzLkRhdGUoIjIwMTktMTItMzEiKSkKCiMgRmV0Y2ggdGhlIGRhdGEgCm1vdmllcyA8LSBib3hvZmZpY2UoZGF0ZSA9IGFzLkRhdGUoZGF0ZS5zZXEpLCB0b3BfbiA9IDUwKQogCmRpbShtb3ZpZXMpICMgd2hhdCBpcyB0aGUgc2l6ZSBvZiB0aGUgZGF0YSBmcmFtZQpuYW1lcyhtb3ZpZXMpICMgb3IsIG1vdmllcyAlPiUgbmFtZXMgIyBuYW1lcyBvZiB0aGUgY29sdW1ucyBvZiB0aGUgZGF0YSBmcmFtZQprYWJsZShoZWFkKG1vdmllcykpCmBgYAoKCkEgZmV3IGNvbW1hbmRzIGZlYXR1cmVkIGFib3ZlIGluY2x1ZGUgMSkgYXNzaWdubWVudCB0byBhbiBvYmplY3QsIDIpIHNlbGVjdGlvbiBvZiBhIHN1YnNldCBvZiBkYXRhIGZyb20gYSBkYXRhIGZyYW1lLCAKCldlIGNhbiBtb2RpZnkgb3IgZXh0ZW5kIHRoZSBkYXRhLiBGb3IgaW5zdGFuY2UsIHdlJ2xsIHdhbnQgdG8gaXNvbGF0ZSB0aGUgWWVhciAoZnJvbSB0aGUgZGF0ZSBmaWVsZCkuIEFsc28sIGl0IHdpbGwgYmUgdXNlZnVsIHRvIHJhbmsgbW92aWVzIGJ5IHNhbGVzICh3aXRoaW4gZWFjaCB5ZWFyKSwgYW5kIGNyZWF0ZSBhIG5ldyByYW5rIHZhcmlhYmxlLiAKCmBgYHtyIG1vdmllcy5leHRlbmR9Cgptb3ZpZXMgPC0gbW92aWVzICU+JSBuYS5vbWl0KCkgJT4lIG11dGF0ZShZZWFyID0gIGFzLm51bWVyaWMoZm9ybWF0KGFzLkRhdGUoZGF0ZSksICIlWSIpKSkgIyBuYS5vbWl0KCkgb21pdHMgdGhlIHJvd3Mgd2l0aCBOQSB2YWx1ZXM7IGNyZWF0ZSBuZXcgY29sdW1uIFllYXIuIHdoaWNoIGV4dHJhY3RzIHRoZSBZICh5ZWFyKSBmcm9tIHRoZSBkYXRlCgojIEV4dHJhY3QgdGhlIFllYXIsIHRoZW4gUmFuayBieSBTYWxlcwoKbW92aWVzIDwtIG1vdmllcyAlPiUgZ3JvdXBfYnkoWWVhcikgJT4lIGFycmFuZ2UoZGVzYyh0b3RhbF9ncm9zcykpICU+JSAgbXV0YXRlKHJhbms9cm93X251bWJlcigpKQoKYGBgCgojIyMgVmlzdWFsaXphdGlvbnMgb2YgYm94IG9mZmljZSBzYWxlcwoKTm93IGxldCdzIHRha2UgYSBsb29rIGF0IHRoZSBkYXRhLiBZb3UgY2FuIGxvb2sgYXQgdGhlIGRhdGEgaW4gdGFidWxhciBmb3JtIChsZXQncyBkbyB0aGF0IGluIHRoZSBSU3R1ZGlvIGludGVyZmFjZSkuIEJ1dCBpdCB3aWxsIGJlIG1vcmUgaW5zaWdodGZ1bCB0byBjb25zdHJ1Y3QgdmlzdWFsaXphdGlvbnMgb2YgdGhlIGRhdGEuIExldCdzIHN0YXJ0IGJ5IGxvb2tpbmcgYXQgdG90YWxfZ3Jvc3MgcmV2ZW51ZXMgZm9yIGVhY2ggcmFuayB3aXRoaW4gZWFjaCB5ZWFyLiAKCmBgYHtyIG1vdmllcy5yYW5rLnBsb3QsZmlnLndpZHRoPTE0LGZpZy5oZWlnaHQ9M30KcDEgPC0gZ2dwbG90KGRhdGE9bW92aWVzLCBhZXMoeD1yYW5rLHk9dG90YWxfZ3Jvc3MpKSArIGdlb21fbGluZShhZXMoY29sb3I9YXMuZmFjdG9yKFllYXIpKSkgKyB0aGVtZV9jbGFzc2ljKCkKCnAyIDwtIHAxICsgY29vcmRfdHJhbnMoeSA9ICJsb2cxMCIpICMgY29udmVydCB5IGF4aXMgdG8gbG9nIHNjYWxlCgpncmlkLmFycmFuZ2UocDEsIHAyLCBuY29sPTIpICMgYXJyYW5nZSBib3RoIHBsb3RzIHNpZGUgYnkgc2lkZSwgaW4gdHdvIGNvbHVtbnMKYGBgCgoKV2hhdCBhcmUgdGhlIHRvcCBtb3ZpZXMgb2YgdGhlIHllYXIsIGFuZCBob3cgbXVjaCBhcmUgdGhleSB0b3RhbF9ncm9zc2luZz8gVG8gbWFrZSB0aGUgcXVlc3Rpb24gKG9yIGFuc3dlcnMpIG1vcmUgbWVhbmluZ2Z1bCBsZXQncyBsaW1pdCB0aGUgYW5hbHlzaXMgdG8gdGhlIHRvcCAxMCBtb3ZpZXMgZWFjaCB5ZWFyLiBUbyBnZXQgYSBzZW5zZSBvZiB0aGUgZGlmZmVyZW5jZXMgaW4gc2FsZXMsIGxldCdzIHRha2UgYSBxdWljayBsb29rIGF0IHRoZSAjMSBhbmQgIzEwIHJhbmtlZCBtb3ZpZXMgZWFjaCB5ZWFyLiAKCmBgYHtyIHRvcDEwfQptb3ZpZXMudG9wMTAgPC0gbW92aWVzICU+JSBmaWx0ZXIocmFuayAlaW4lIGMoMSwxMCkpICU+JSBncm91cF9ieShZZWFyKSAlPiUgYXJyYW5nZShyYW5rKQprYWJsZShtb3ZpZXMudG9wMTAgJT4lIHNlbGVjdChtb3ZpZSwgWWVhciwgcmFuaywgdG90YWxfZ3Jvc3MpICU+JSBhcnJhbmdlKFllYXIpKQpgYGAKCkxvb2tpbmcgYXQgdGhlIG51bWJlcnMgaXQgc2VlbXMgdGhhdCB0aGUgdG9wLTEgYW5kIHRvcC0xMCBoYXZlIGh1Z2VseSBkaWZmZXJlbnQgc2FsZXMgbnVtYmVycy4gUHV0dGluZyBhbGwgb2YgdGhlbSAoYW5kIGFsbCBiZXR3ZWVuIHRoZXNlIHJhbmtzKSBpbnRvIHRoZSBzYW1lIGNoYXJ0IHdpbGwgbWFrZSBpdCB2ZXJ5IGhhcmQgdG8gc2VlIHRoZSBkaWZmZXJlbmNlcy4gSW4gc3VjaCBjYXNlcyBpdCBpcyB1c2VmdWwgdG8gdXNlIGEgbG9nIHRyYW5zZm9ybWF0aW9uLCB3aGljaCBicmluZ3MgdGhlIG51bWJlcnMgY2xvc2VyIHRvZ2V0aGVyIGFuZCBlYXNpZXIgdG8gc2VlLiAKClRoZSBncmFwaCB3ZSdsbCBwcm9kdWNlIGhhcyB0aGUgcmFuayBhcyB0aGUgeCAoaG9yaXpvbnRhbCkgYXhpcyBhbmQgZ3Jvc3MgcmV2ZW51ZXMgYXMgdGhlIHkgKHZlcnRpY2FsIGF4aXMpLiBXZSdsbCBpZGVudGlmeSB0aGUgbW92aWUgaXRzZWxmIGJ5IHBsYWNpbmcgYSBkb3QgKGJ1bGxldCkgYmFzZWQgb24gaXRzICh4LHkpIHZhbHVlLCBhbmQgd3JpdGUgdGhlIG5hbWUgb2YgdGhlIG1vdmllIGFzIGNsb3NlIHRvIHRoZSBidWxsZXQgYXMgcG9zc2libGUuIAoKYGBge3IgbW92aWVzLnJhbmtzLCBmaWcud2lkdGg9MTUsZmlnLmhlaWdodD03fQpnZ3Bsb3QoZGF0YT1tb3ZpZXMgJT4lIGZpbHRlcihyYW5rIDwgMTEpLCBhZXMoeD1yYW5rLCB5PXRvdGFsX2dyb3NzLCBjb2xvcj1mYWN0b3IoWWVhcikpKSArIGdlb21fcG9pbnQoKSArIHRoZW1lX2NsYXNzaWMoKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9MTIpLCBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSwgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMS41KSksIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDEuNSksIG1hcmdpbiA9IG1hcmdpbih0ID0gMCwgciA9IDIwLCBiID0gMCwgbCA9IDEwKSkpICsgZ2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbCA9IG1vdmllKSwgbnVkZ2VfeT0xLCBmb3JjZT02LCBib3gucGFkZGluZyA9IHVuaXQoMC43NSwgImxpbmVzIiksIHNlZ21lbnQuY29sb3I9ImdyYXkiKSArIGNvb3JkX3RyYW5zKHkgPSAnbG9nMTAnKQpgYGAKCldobydzIG1ha2luZyB0aGUgd2lubmluZyBtb3ZpZXM/IFRoaXMgaXMgaWRlbnRpZmllZCBieSB0aGUgImRpc3RyaWJ1dG9yIiBjb2x1bW4uIFNvLCB0aGlzIHRpbWUgd2UnbGwgd3JpdGUgdGhlIGRpc3RyaWJ1dG9yJ3MgbmFtZSByYXRoZXIgdGhhbiB0aGUgbW92aWUgbmFtZS4gCgpgYGB7ciBtb3ZpZXMucmFua3MuZGlzdHJpYnV0b3IsICBmaWcud2lkdGg9MTUsZmlnLmhlaWdodD03fQpnZ3Bsb3QoZGF0YT1tb3ZpZXMgJT4lIGZpbHRlcihyYW5rIDwgMTEpLCBhZXMoeD1yYW5rLCB5PXRvdGFsX2dyb3NzLCBjb2xvcj1mYWN0b3IoWWVhcikpKSArIGdlb21fcG9pbnQoKSArIHRoZW1lX2NsYXNzaWMoKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9MTIpLCBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSwgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMS41KSksIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDEuNSksIG1hcmdpbiA9IG1hcmdpbih0ID0gMCwgciA9IDIwLCBiID0gMCwgbCA9IDEwKSkpICsgZ2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbCA9IGRpc3RyaWJ1dG9yKSwgbnVkZ2VfeT0xLCBmb3JjZT02LCBib3gucGFkZGluZyA9IHVuaXQoMC43NSwgImxpbmVzIiksIHNlZ21lbnQuY29sb3I9ImdyYXkiKSArIGNvb3JkX3RyYW5zKHkgPSAnbG9nMTAnKQoKIyBnZ3NhdmUoKQpgYGAKCgoKCgo=