NOTE: the tasks are sequential. Consequently, PART II must be done after PART I, etc.

DATA

The data consists of monhtly financial information pertaining to 30 large US firms. They are characterised by their ticker:

A - F G - M O - Z
AAPL (Apple) GE (General Electric) ORCL (Oracle)
BA (Boeing) HD (Home Depot) PFE (Pfizer)
BAC (Bank of America) IBM PG (Procter & Gamble)
C (Citigroup) INTC (Intel) T (AT&T)
CSCO (Cisco) JNJ (Johnson & Johnson) UNH (United Health)
CVS (CVS Health) JPM (JP Morgan) UPS
CVX (Chevron) K (Kellogg) VZ (Verizon)
D (Dominion Energy) MCK (McKesson) WFC (Wells Fargo)
DIS (Disney) MRK (Merck) WMT (Walmart)
F (Ford) MSFT (Microsoft) XOM (Exxon)

There are 3 attributes: closing price (Close), market capitalisation in M$ (Mkt_Cap) and price-to-book ratio (P2B). Finally, the time range is 2000-2018.


PART I: GRAPHS

  1. Set the working directory, load the data (‘data.RData’) and the tidyverse package.
  2. First, take a look at the data using the head() function and then the summary() function.
  3. Plot (with a line) the price of the Microsoft (MSFT) share through time.
  4. Plot (with a line) the price of Apple (AAPL), IBM and Microsoft with one color for each company.
    Obviously, there is a scale problem: we’ll try to solve it in the next section.
# Load the data in the bottom right pane
library(tidyverse)
load("data.RData")
data <- data %>% arrange(Tick, Date) # Arranges/orders the data
head(data)                           # Shows the first 6 lines
summary(data)                        # Descriptive statistics
      Tick           Date                Close            Mkt_Cap            P2B           
 AAPL   : 221   Min.   :2000-01-03   Min.   :  1.004   Min.   :  4491   Min.   :   0.0922  
 BA     : 221   1st Qu.:2004-08-02   1st Qu.: 28.050   1st Qu.: 63498   1st Qu.:   2.0783  
 BAC    : 221   Median :2009-03-02   Median : 42.535   Median :128864   Median :   3.1054  
 C      : 221   Mean   :2009-03-02   Mean   : 57.519   Mean   :145819   Mean   :   6.6966  
 CSCO   : 221   3rd Qu.:2013-10-01   3rd Qu.: 66.045   3rd Qu.:198487   3rd Qu.:   5.2977  
 CVS    : 221   Max.   :2018-05-01   Max.   :557.000   Max.   :887952   Max.   :1259.1554  
 (Other):5304                                                                              
data %>% filter(Tick == "MSFT") %>% ggplot(aes(x = Date, y = Close)) + geom_line() # First plot

data %>% filter(Tick == "MSFT" | Tick == "IBM" | Tick == "AAPL") %>% ggplot(aes(x = Date, y = Mkt_Cap)) + geom_line(aes(color = Tick))

# data %>% filter(Tick %in% c("MSFT", "IBM", "AAPL")) %>% ggplot(aes(x = Date, y = Close)) + geom_line(aes(color = Tick)) # Alternative solution

PART II: DATA HANDLING

Simple filters

  1. Filter the data to keep only MSFT figures.
  2. Filter the data to keep only year 2018.
  3. Do both at the same time
# filter(data, Tick == "MSFT")      # Point 1)
# filter(data, Date > "2017-12-31") # Point 2)
filter(data, Tick == "MSFT" & Date > "2017-12-31")

Modifying data: normalised prices

The aim of this subsection is to add a new column to the data dataframe. This column would be equal to prices normalised to one on the first date. This makes graphical comparison across firms easier. This could be done with a loop (see comments below). We proceed otherwise for pedagogical purposes: use the tidyverse!

  1. Create a matrix with prices only (call it prices): first, select the Tick, Date and Close columns. Second, use the spread() function. Finally, remove the Date column with select().
  2. Normalise each series by its first value; this way they all start by one. Hint: you can create a function and apply it on the matrix using apply(). Call this new matrix tmp.
  3. Create a date vector with all dates.
  4. Concatenate (using cbind()) the date vector back on the tmp matrix.
  5. Using the gather() function, which is the inverse of spread(), put the data back into its original form! Hint: call the new column NClose, for normalised Close. Also, arrange it by Tick and Date.
  6. Finally, create a new NClose column in the full dataset and plot (line) the price of Apple, IBM and Microsoft (MSFT) with one color for each company.
prices <- data %>% select(Tick, Date, Close) %>% spread(key = Tick, value = Close) %>% select(-Date) # Point 1)
normalize <- function(v){return(v/v[1])} # Normalises a vector by its first value
tmp <- prices %>% apply(2,normalize)     # That's point 2) of the exercises
date <- filter(data, Tick == "AAPL") %>% select(Date)                         # Point 3)
tmp <- cbind(date,tmp)                                                        # Point 4)
tmp <- gather(tmp, key = Tick, value = NClose, -Date) %>% arrange(Tick, Date) # Point 5)
data$NClose <- tmp$NClose                                                     # Point 6)
data %>% filter(Tick == "MSFT" | Tick == "IBM" | Tick == "AAPL") %>% ggplot(aes(x = Date, y = NClose)) + geom_line(aes(color = Tick))

# Alternative solution below, using a loop:
prices2 <- data %>% select(Tick, Date, Close) %>% spread(key = Tick, value = Close) 
for(i in 2:31){ # Don't touch the first column! 
    prices2[,i] <- prices2[,i] / prices2[1,i]
}
tmp <- gather(prices2, key = Tick, value = NClose, -Date) %>% arrange(Tick, Date) # Point 5)

This gives a better idea of the remarkable performance of Apple during the 19 years of the sample.

Modifying data: computing returns (1)

  1. Going further: using the same process and the price matrix, add an important column to the dataset, namely the monthly returns of each stock (hint: combine the apply() and the lag() functions). In the process, keep the matrix of returns in a tmp variable.
  2. Using tmp, compute the covariance matrix of the first 14 stocks (in alphabetical order). Because of the NAs, you will need the option (argument) use = “complete.obs” in the cor() function.
tmp <- prices / apply(prices, 2, lag) - 1 # Computes the returns
tmp2 <- cbind(date,tmp)                   # Binds the dates
tmp2 <- gather(tmp2, key = Tick, value = Return, -Date) %>% arrange(Tick, Date)
data$Return <- tmp2$Return
# The short version below: 
data$Return <- data$Close / lag(data$Close) - 1 # Compute returns at once, but the first return of all stocks is wrong!
data[data$Date == "2000-01-03",]$Return <- NA   # Remove the false returns!
# Below, we show how to do this using a loop, but this is clearly not optimal!
# data2 <- c() 
# ticks <- levels(data$Tick)
# for(i in 1:length(ticks)){
#     tmp <- data %>% filter(Tick == ticks[i]) %>% mutate(Return = Close/lag(Close) - 1)
#     data2 <- rbind(data2, tmp) 
# }    
C <- cor(tmp[,1:14], use = "complete.obs") %>% round(2) %>% data.frame()
print(C)
if(!require(ggcorrplot)){install.packages("ggcorrplot")} # Below, we visualise the correlation matrix using the ggcorrplot package
library(ggcorrplot)
ggcorrplot(C, hc.order = TRUE, type = "upper", outline.col = "white") +
    theme(text = element_text(size=8), axis.text.x = element_text(angle=90, hjust=1))

Visually, the largest correlation is between Citigroup and Bank of America, which highlights the importance of the sector for asset co-movements.

Modifying data: computing returns (2)

There exists a much simpler way to proceed! The power of group_by() combined with summarise()

data %>% group_by(Tick) %>% mutate(return = Close/lag(Close) - 1)

Thanks to the grouping, the formula inside mutate() is applied sequentially stock-by-stock!


PART III: PIVOT TABLES

  1. First, we are (again) going to augment the database by adding a Year column. The code is:
if(!require(lubridate)){install.packages("lubridate")} 
# This is a package that handles dates effectively. SKIP this step if already installed.
library(lubridate)
data <- data %>% mutate(Year = year(Date)) # Adding a Year column for yearly statistics.
  1. Group the data by company and by year and create a new variable Avg_Cap which computes the average market capitalisation.
  2. Plot (line) the corresponding results: x-axis is Year, y-axis is Avg_Cap with one color for each firm. => Hard to read. Beyond 10 firms, the graph becomes less insightful. Try to do the same with a barplot.
  3. Pick one year (e.g., 2005) and show the average capitalization of firms in decreasing order.
  4. From data, create a pivot table (call it pt) that computes the average capitalization, average P2B and average return for each firm. Hint: for returns, there are some NAs, so use the argument na.rm = T in the mean().
data %>% group_by(Tick, Year) %>% 
    summarise(Avg_Cap = mean(Mkt_Cap)) %>% # This is point 1)
    ggplot(aes(x=Year, y =Avg_Cap)) + geom_line(aes(color = Tick))                  # Point 2)

data %>% group_by(Tick, Year) %>% 
    summarise(Avg_Cap = mean(Mkt_Cap)) %>% 
    ggplot(aes(x=Year, y =Avg_Cap)) + geom_bar(aes(fill = Tick), stat = "identity") # Point 2)

data %>% group_by(Tick, Year) %>% 
    summarise(Avg_Cap = mean(Mkt_Cap)) %>% 
    filter(Year == 2005) %>% 
    arrange(desc(Avg_Cap))                                  # Point 3)
pt <- data %>% group_by(Tick) %>% 
    summarise(Avg_Cap = mean(Mkt_Cap), Avg_P2B = mean(P2B), Avg_Ret = mean(Return, na.rm = T)) # Point 4: beware of NA problems!
pt

PART IV: FACTOR ANALYSIS

Research in financial economics has shown that firms’ characteristics are likely to drive profitability. We try to investigate this idea below.
1) Using data, plot (scatter plot, i.e., with points) y = returns versus x = Mkt_Cap. 2) Same exercise but with pt (pivot table from PART III), x = Avg_Cap and y = Avg_Ret. 3) Same exercise as 2), but after removing AAPL from the sample 4) From pt, plot x = Avg_P2B and y = Avg_ret. Comment?

data %>% ggplot(aes(x = Mkt_Cap, y = Return)) + geom_point() + stat_smooth()  # Point 1)

pt %>% ggplot(aes(x = Avg_Cap, y = Avg_Ret)) + geom_point() + stat_smooth() + # Point 2)
    geom_text(aes(label = Tick)) # You can add this line to see the firm names.

pt %>% ggplot(aes(x = Avg_Cap, y = Avg_Ret)) + geom_point() + stat_smooth(method = "lm") # lm is for 'linear model', hence the straight line.

pt %>% filter(Tick != "AAPL") %>% ggplot(aes(x = Avg_Cap, y = Avg_Ret)) + # Point 3): we remove AAPL
    geom_point() + stat_smooth(method = "lm")

pt %>% ggplot(aes(x = Avg_P2B, y = Avg_Ret)) + geom_point() + stat_smooth(method = "lm") +
    geom_text(aes(label = Tick))

In the last graph, there is an outlier for the average P2B: error in the data? Further investigation would show that in 2017, the book value of Boeing was very small and hence its P2B ratio was extremely high.
In the above graphs, we see the mild negative relationship between firm size and average return. Though our sample is much too small and our study not rigourous, this resembles the so-called size effect according to which small firms are more profitable than large firms (though not in financial bad times).


PART V: LOOPS

Create a loop over all dates that computes the aggregate market capitalisation of all 30 firms at each date (call it Agg_Cap). Plot the corresponing series. (Note: this is a very inefficient way to do this.)

dates <- data$Date %>% 
    as.factor() %>% 
    levels() %>%
    as.Date()       # Creating a vector of dates.
dates <- data %>% 
    filter(Tick == "AAPL") %>% 
    select(Date) %>% 
    as.matrix() %>% # This is to get rid of the dataframe structure to avoid column numbers 
    as.Date()       # Similar though not exactly the same result
Agg_Cap <- 0
for(t in 1:length(dates)){
    Agg_Cap[t] <- data %>%
        filter(Date == dates[t]) %>%
        select(Mkt_Cap) %>%
        sum()
}
data.frame(dates, Agg_Cap) %>% ggplot(aes(x = dates, y = Agg_Cap)) + geom_line()

LS0tCnRpdGxlOiAiRmluYW5jaWFsIERhdGEgU2NpZW5jZSBFeGVyY2lzZXMiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCi0tLQoKTk9URTogdGhlIHRhc2tzIGFyZSBzZXF1ZW50aWFsLiBDb25zZXF1ZW50bHksIFBBUlQgSUkgbXVzdCBiZSBkb25lIGFmdGVyIFBBUlQgSSwgZXRjLiAKCiMjIERBVEEgIAoKVGhlIGRhdGEgY29uc2lzdHMgb2YgbW9uaHRseSBmaW5hbmNpYWwgaW5mb3JtYXRpb24gcGVydGFpbmluZyB0byAzMCBsYXJnZSBVUyBmaXJtcy4gVGhleSBhcmUgY2hhcmFjdGVyaXNlZCBieSB0aGVpciB0aWNrZXI6ICAKCnxBIC0gRnwgRyAtIE0gfE8gLSBafAp8IC0tLSB8IC0tLS0tIHwgLS0tIHwKfCAqKkFBUEwqKiAoQXBwbGUpfCAqKkdFKiogKEdlbmVyYWwgRWxlY3RyaWMpIHwgKipPUkNMKiogKE9yYWNsZSkKfCAqKkJBKiogKEJvZWluZykgfCAqKkhEKiogKEhvbWUgRGVwb3QpIHwgKipQRkUqKiAoUGZpemVyKQp8ICoqQkFDKiogKEJhbmsgb2YgQW1lcmljYSkgfCAqKklCTSoqIHwgKipQRyoqIChQcm9jdGVyICYgR2FtYmxlKQp8ICoqQyoqIChDaXRpZ3JvdXApIHwgKipJTlRDKiogKEludGVsKSB8ICoqVCoqIChBVCZUKQp8ICoqQ1NDTyoqIChDaXNjbykgfCAqKkpOSioqIChKb2huc29uICYgSm9obnNvbikgfCAgKipVTkgqKiAoVW5pdGVkIEhlYWx0aCkKfCAqKkNWUyoqIChDVlMgSGVhbHRoKSB8ICoqSlBNKiogKEpQIE1vcmdhbikgfCAqKlVQUyoqIAp8ICoqQ1ZYKiogKENoZXZyb24pIHwgKipLKiogKEtlbGxvZ2cpIHwgKipWWioqIChWZXJpem9uKQp8ICoqRCoqIChEb21pbmlvbiBFbmVyZ3kpIHwgKipNQ0sqKiAoTWNLZXNzb24pIHwgKipXRkMqKiAoV2VsbHMgRmFyZ28pCnwgKipESVMqKiAoRGlzbmV5KSB8ICoqTVJLKiogKE1lcmNrKSB8ICoqV01UKiogKFdhbG1hcnQpCnwgKipGKiogKEZvcmQpIHwgKipNU0ZUKiogKE1pY3Jvc29mdCkgfCAqKlhPTSoqIChFeHhvbikKCgpUaGVyZSBhcmUgMyBhdHRyaWJ1dGVzOiBjbG9zaW5nIHByaWNlICgqKkNsb3NlKiopLCBtYXJrZXQgY2FwaXRhbGlzYXRpb24gaW4gTSQgKCoqTWt0X0NhcCoqKSBhbmQgcHJpY2UtdG8tYm9vayByYXRpbyAoKipQMkIqKikuCkZpbmFsbHksIHRoZSB0aW1lIHJhbmdlIGlzIDIwMDAtMjAxOC4KCioqKgojIyBQQVJUIEk6IEdSQVBIUyAgCgowKSBTZXQgdGhlIHdvcmtpbmcgZGlyZWN0b3J5LCBsb2FkIHRoZSBkYXRhICgnZGF0YS5SRGF0YScpIGFuZCB0aGUgdGlkeXZlcnNlIHBhY2thZ2UuICAKMSkgRmlyc3QsIHRha2UgYSBsb29rIGF0IHRoZSBkYXRhIHVzaW5nIHRoZSBoZWFkKCkgZnVuY3Rpb24gYW5kIHRoZW4gdGhlIHN1bW1hcnkoKSBmdW5jdGlvbi4KMikgUGxvdCAod2l0aCBhIGxpbmUpIHRoZSBwcmljZSBvZiB0aGUgTWljcm9zb2Z0IChNU0ZUKSBzaGFyZSB0aHJvdWdoIHRpbWUuICAKMykgUGxvdCAod2l0aCBhIGxpbmUpIHRoZSBwcmljZSBvZiBBcHBsZSAoQUFQTCksIElCTSBhbmQgTWljcm9zb2Z0IHdpdGggb25lIGNvbG9yIGZvciBlYWNoIGNvbXBhbnkuICAKT2J2aW91c2x5LCB0aGVyZSBpcyBhIHNjYWxlIHByb2JsZW06IHdlJ2xsIHRyeSB0byBzb2x2ZSBpdCBpbiB0aGUgbmV4dCBzZWN0aW9uLgoKCmBgYHtyIFVQIFRPIFlPVSEgMSwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9CiMgTG9hZCB0aGUgZGF0YSBpbiB0aGUgYm90dG9tIHJpZ2h0IHBhbmUKbGlicmFyeSh0aWR5dmVyc2UpCmxvYWQoImRhdGEuUkRhdGEiKQpkYXRhIDwtIGRhdGEgJT4lIGFycmFuZ2UoVGljaywgRGF0ZSkgIyBBcnJhbmdlcy9vcmRlcnMgdGhlIGRhdGEKaGVhZChkYXRhKSAgICAgICAgICAgICAgICAgICAgICAgICAgICMgU2hvd3MgdGhlIGZpcnN0IDYgbGluZXMKc3VtbWFyeShkYXRhKSAgICAgICAgICAgICAgICAgICAgICAgICMgRGVzY3JpcHRpdmUgc3RhdGlzdGljcwpkYXRhICU+JSBmaWx0ZXIoVGljayA9PSAiTVNGVCIpICU+JSBnZ3Bsb3QoYWVzKHggPSBEYXRlLCB5ID0gQ2xvc2UpKSArIGdlb21fbGluZSgpICMgRmlyc3QgcGxvdApkYXRhICU+JSBmaWx0ZXIoVGljayA9PSAiTVNGVCIgfCBUaWNrID09ICJJQk0iIHwgVGljayA9PSAiQUFQTCIpICU+JSBnZ3Bsb3QoYWVzKHggPSBEYXRlLCB5ID0gTWt0X0NhcCkpICsgZ2VvbV9saW5lKGFlcyhjb2xvciA9IFRpY2spKQojIGRhdGEgJT4lIGZpbHRlcihUaWNrICVpbiUgYygiTVNGVCIsICJJQk0iLCAiQUFQTCIpKSAlPiUgZ2dwbG90KGFlcyh4ID0gRGF0ZSwgeSA9IENsb3NlKSkgKyBnZW9tX2xpbmUoYWVzKGNvbG9yID0gVGljaykpICMgQWx0ZXJuYXRpdmUgc29sdXRpb24KYGBgCgoqKioKIyMgUEFSVCBJSTogREFUQSBIQU5ETElORwojIyMgU2ltcGxlIGZpbHRlcnMKMSkgRmlsdGVyIHRoZSBkYXRhIHRvIGtlZXAgb25seSBNU0ZUIGZpZ3VyZXMuICAgCjIpIEZpbHRlciB0aGUgZGF0YSB0byBrZWVwIG9ubHkgeWVhciAyMDE4LiAgIAozKSBEbyBib3RoIGF0IHRoZSBzYW1lIHRpbWUKCmBgYHtyIFVQIFRPIFlPVSEgMn0KIyBmaWx0ZXIoZGF0YSwgVGljayA9PSAiTVNGVCIpICAgICAgIyBQb2ludCAxKQojIGZpbHRlcihkYXRhLCBEYXRlID4gIjIwMTctMTItMzEiKSAjIFBvaW50IDIpCmZpbHRlcihkYXRhLCBUaWNrID09ICJNU0ZUIiAmIERhdGUgPiAiMjAxNy0xMi0zMSIpCmBgYAoKCiMjIyBNb2RpZnlpbmcgZGF0YTogbm9ybWFsaXNlZCBwcmljZXMKKlRoZSBhaW0gb2YgdGhpcyBzdWJzZWN0aW9uIGlzIHRvIGFkZCBhIG5ldyBjb2x1bW4gdG8gdGhlIGRhdGEgZGF0YWZyYW1lLiBUaGlzIGNvbHVtbiB3b3VsZCBiZSBlcXVhbCB0byBwcmljZXMgbm9ybWFsaXNlZCB0byBvbmUgb24gdGhlIGZpcnN0IGRhdGUuIFRoaXMgbWFrZXMgZ3JhcGhpY2FsIGNvbXBhcmlzb24gYWNyb3NzIGZpcm1zIGVhc2llci4gVGhpcyBjb3VsZCBiZSBkb25lIHdpdGggYSBsb29wIChzZWUgY29tbWVudHMgYmVsb3cpLiBXZSBwcm9jZWVkIG90aGVyd2lzZSBmb3IgcGVkYWdvZ2ljYWwgcHVycG9zZXM6IHVzZSB0aGUgdGlkeXZlcnNlISogICAKCgoxKSBDcmVhdGUgYSBtYXRyaXggd2l0aCBwcmljZXMgb25seSAoY2FsbCBpdCBwcmljZXMpOiBmaXJzdCwgc2VsZWN0IHRoZSAqKlRpY2sqKiwgKipEYXRlKiogYW5kICoqQ2xvc2UqKiBjb2x1bW5zLiBTZWNvbmQsIHVzZSB0aGUgc3ByZWFkKCkgZnVuY3Rpb24uIEZpbmFsbHksIHJlbW92ZSB0aGUgRGF0ZSBjb2x1bW4gd2l0aCBzZWxlY3QoKS4gICAgCjIpIE5vcm1hbGlzZSBlYWNoIHNlcmllcyBieSBpdHMgZmlyc3QgdmFsdWU7IHRoaXMgd2F5IHRoZXkgYWxsIHN0YXJ0IGJ5IG9uZS4gSGludDogeW91IGNhbiBjcmVhdGUgYSBmdW5jdGlvbiBhbmQgYXBwbHkgaXQgb24gdGhlIG1hdHJpeCB1c2luZyBhcHBseSgpLiBDYWxsIHRoaXMgbmV3IG1hdHJpeCB0bXAuCjMpIENyZWF0ZSBhIGRhdGUgdmVjdG9yIHdpdGggYWxsIGRhdGVzLgo0KSBDb25jYXRlbmF0ZSAodXNpbmcgY2JpbmQoKSkgdGhlIGRhdGUgdmVjdG9yIGJhY2sgb24gdGhlIHRtcCBtYXRyaXguICAKNSkgVXNpbmcgdGhlIGdhdGhlcigpIGZ1bmN0aW9uLCB3aGljaCBpcyB0aGUgaW52ZXJzZSBvZiBzcHJlYWQoKSwgcHV0IHRoZSBkYXRhIGJhY2sgaW50byBpdHMgb3JpZ2luYWwgZm9ybSEgSGludDogY2FsbCB0aGUgbmV3IGNvbHVtbiBOQ2xvc2UsIGZvciBub3JtYWxpc2VkIENsb3NlLiBBbHNvLCBhcnJhbmdlIGl0IGJ5IFRpY2sgYW5kIERhdGUuICAKNikgRmluYWxseSwgY3JlYXRlIGEgbmV3IE5DbG9zZSBjb2x1bW4gaW4gdGhlIGZ1bGwgZGF0YXNldCBhbmQgcGxvdCAobGluZSkgdGhlIHByaWNlIG9mIEFwcGxlLCBJQk0gYW5kIE1pY3Jvc29mdCAoTVNGVCkgd2l0aCBvbmUgY29sb3IgZm9yIGVhY2ggY29tcGFueS4KCgpgYGB7ciBVUCBUTyBZT1UhIDN9CnByaWNlcyA8LSBkYXRhICU+JSBzZWxlY3QoVGljaywgRGF0ZSwgQ2xvc2UpICU+JSBzcHJlYWQoa2V5ID0gVGljaywgdmFsdWUgPSBDbG9zZSkgJT4lIHNlbGVjdCgtRGF0ZSkgIyBQb2ludCAxKQpub3JtYWxpemUgPC0gZnVuY3Rpb24odil7cmV0dXJuKHYvdlsxXSl9ICMgTm9ybWFsaXNlcyBhIHZlY3RvciBieSBpdHMgZmlyc3QgdmFsdWUKdG1wIDwtIHByaWNlcyAlPiUgYXBwbHkoMixub3JtYWxpemUpICAgICAjIFRoYXQncyBwb2ludCAyKSBvZiB0aGUgZXhlcmNpc2VzCmRhdGUgPC0gZmlsdGVyKGRhdGEsIFRpY2sgPT0gIkFBUEwiKSAlPiUgc2VsZWN0KERhdGUpICAgICAgICAgICAgICAgICAgICAgICAgICMgUG9pbnQgMykKdG1wIDwtIGNiaW5kKGRhdGUsdG1wKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBQb2ludCA0KQp0bXAgPC0gZ2F0aGVyKHRtcCwga2V5ID0gVGljaywgdmFsdWUgPSBOQ2xvc2UsIC1EYXRlKSAlPiUgYXJyYW5nZShUaWNrLCBEYXRlKSAjIFBvaW50IDUpCmRhdGEkTkNsb3NlIDwtIHRtcCROQ2xvc2UgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgUG9pbnQgNikKZGF0YSAlPiUgZmlsdGVyKFRpY2sgPT0gIk1TRlQiIHwgVGljayA9PSAiSUJNIiB8IFRpY2sgPT0gIkFBUEwiKSAlPiUgZ2dwbG90KGFlcyh4ID0gRGF0ZSwgeSA9IE5DbG9zZSkpICsgZ2VvbV9saW5lKGFlcyhjb2xvciA9IFRpY2spKQojIEFsdGVybmF0aXZlIHNvbHV0aW9uIGJlbG93LCB1c2luZyBhIGxvb3A6CnByaWNlczIgPC0gZGF0YSAlPiUgc2VsZWN0KFRpY2ssIERhdGUsIENsb3NlKSAlPiUgc3ByZWFkKGtleSA9IFRpY2ssIHZhbHVlID0gQ2xvc2UpIApmb3IoaSBpbiAyOjMxKXsgIyBEb24ndCB0b3VjaCB0aGUgZmlyc3QgY29sdW1uISAKICAgIHByaWNlczJbLGldIDwtIHByaWNlczJbLGldIC8gcHJpY2VzMlsxLGldCn0KdG1wIDwtIGdhdGhlcihwcmljZXMyLCBrZXkgPSBUaWNrLCB2YWx1ZSA9IE5DbG9zZSwgLURhdGUpICU+JSBhcnJhbmdlKFRpY2ssIERhdGUpICMgUG9pbnQgNSkKYGBgCgpUaGlzIGdpdmVzIGEgYmV0dGVyIGlkZWEgb2YgdGhlIHJlbWFya2FibGUgcGVyZm9ybWFuY2Ugb2YgQXBwbGUgZHVyaW5nIHRoZSAxOSB5ZWFycyBvZiB0aGUgc2FtcGxlLgoKIyMjIE1vZGlmeWluZyBkYXRhOiBjb21wdXRpbmcgcmV0dXJucyAoMSkKMSkgR29pbmcgZnVydGhlcjogdXNpbmcgdGhlIHNhbWUgcHJvY2VzcyBhbmQgdGhlIHByaWNlIG1hdHJpeCwgYWRkIGFuIGltcG9ydGFudCBjb2x1bW4gdG8gdGhlIGRhdGFzZXQsIG5hbWVseSB0aGUgbW9udGhseSByZXR1cm5zIG9mIGVhY2ggc3RvY2sgKGhpbnQ6IGNvbWJpbmUgdGhlICoqYXBwbHkqKigpIGFuZCB0aGUgKipsYWcqKigpIGZ1bmN0aW9ucykuIEluIHRoZSBwcm9jZXNzLCBrZWVwIHRoZSBtYXRyaXggb2YgcmV0dXJucyBpbiBhIHRtcCB2YXJpYWJsZS4gIAoyKSBVc2luZyB0bXAsIGNvbXB1dGUgdGhlIGNvdmFyaWFuY2UgbWF0cml4IG9mIHRoZSBmaXJzdCAxNCBzdG9ja3MgKGluIGFscGhhYmV0aWNhbCBvcmRlcikuIEJlY2F1c2Ugb2YgdGhlIE5BcywgeW91IHdpbGwgbmVlZCB0aGUgb3B0aW9uIChhcmd1bWVudCkgdXNlID0gImNvbXBsZXRlLm9icyIgaW4gdGhlIGNvcigpIGZ1bmN0aW9uLgoKYGBge3IgVVAgVE8gWU9VISA0fQp0bXAgPC0gcHJpY2VzIC8gYXBwbHkocHJpY2VzLCAyLCBsYWcpIC0gMSAjIENvbXB1dGVzIHRoZSByZXR1cm5zCnRtcDIgPC0gY2JpbmQoZGF0ZSx0bXApICAgICAgICAgICAgICAgICAgICMgQmluZHMgdGhlIGRhdGVzCnRtcDIgPC0gZ2F0aGVyKHRtcDIsIGtleSA9IFRpY2ssIHZhbHVlID0gUmV0dXJuLCAtRGF0ZSkgJT4lIGFycmFuZ2UoVGljaywgRGF0ZSkKZGF0YSRSZXR1cm4gPC0gdG1wMiRSZXR1cm4KCiMgVGhlIHNob3J0IHZlcnNpb24gYmVsb3c6IApkYXRhJFJldHVybiA8LSBkYXRhJENsb3NlIC8gbGFnKGRhdGEkQ2xvc2UpIC0gMSAjIENvbXB1dGUgcmV0dXJucyBhdCBvbmNlLCBidXQgdGhlIGZpcnN0IHJldHVybiBvZiBhbGwgc3RvY2tzIGlzIHdyb25nIQpkYXRhW2RhdGEkRGF0ZSA9PSAiMjAwMC0wMS0wMyIsXSRSZXR1cm4gPC0gTkEgICAjIFJlbW92ZSB0aGUgZmFsc2UgcmV0dXJucyEKCgojIEJlbG93LCB3ZSBzaG93IGhvdyB0byBkbyB0aGlzIHVzaW5nIGEgbG9vcCwgYnV0IHRoaXMgaXMgY2xlYXJseSBub3Qgb3B0aW1hbCEKIyBkYXRhMiA8LSBjKCkgCiMgdGlja3MgPC0gbGV2ZWxzKGRhdGEkVGljaykKIyBmb3IoaSBpbiAxOmxlbmd0aCh0aWNrcykpewojICAgICB0bXAgPC0gZGF0YSAlPiUgZmlsdGVyKFRpY2sgPT0gdGlja3NbaV0pICU+JSBtdXRhdGUoUmV0dXJuID0gQ2xvc2UvbGFnKENsb3NlKSAtIDEpCiMgICAgIGRhdGEyIDwtIHJiaW5kKGRhdGEyLCB0bXApIAojIH0gICAgCgpDIDwtIGNvcih0bXBbLDE6MTRdLCB1c2UgPSAiY29tcGxldGUub2JzIikgJT4lIHJvdW5kKDIpICU+JSBkYXRhLmZyYW1lKCkKcHJpbnQoQykKaWYoIXJlcXVpcmUoZ2djb3JycGxvdCkpe2luc3RhbGwucGFja2FnZXMoImdnY29ycnBsb3QiKX0gIyBCZWxvdywgd2UgdmlzdWFsaXNlIHRoZSBjb3JyZWxhdGlvbiBtYXRyaXggdXNpbmcgdGhlIGdnY29ycnBsb3QgcGFja2FnZQpsaWJyYXJ5KGdnY29ycnBsb3QpCmdnY29ycnBsb3QoQywgaGMub3JkZXIgPSBUUlVFLCB0eXBlID0gInVwcGVyIiwgb3V0bGluZS5jb2wgPSAid2hpdGUiKSArCiAgICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9OCksIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTkwLCBoanVzdD0xKSkKYGBgCgpWaXN1YWxseSwgdGhlIGxhcmdlc3QgY29ycmVsYXRpb24gaXMgYmV0d2VlbiBDaXRpZ3JvdXAgYW5kIEJhbmsgb2YgQW1lcmljYSwgd2hpY2ggaGlnaGxpZ2h0cyB0aGUgaW1wb3J0YW5jZSBvZiB0aGUgc2VjdG9yIGZvciBhc3NldCBjby1tb3ZlbWVudHMuCgojIyMgTW9kaWZ5aW5nIGRhdGE6IGNvbXB1dGluZyByZXR1cm5zICgyKQpUaGVyZSBleGlzdHMgYSBtdWNoIHNpbXBsZXIgd2F5IHRvIHByb2NlZWQhIFRoZSBwb3dlciBvZiAqKmdyb3VwX2J5KiooKSBjb21iaW5lZCB3aXRoICoqc3VtbWFyaXNlKCkqKi4uLgpgYGB7ciByZXR1cm5zX3NpbXBsZX0KZGF0YSAlPiUgZ3JvdXBfYnkoVGljaykgJT4lIG11dGF0ZShyZXR1cm4gPSBDbG9zZS9sYWcoQ2xvc2UpIC0gMSkKYGBgCgpUaGFua3MgdG8gdGhlIGdyb3VwaW5nLCB0aGUgZm9ybXVsYSBpbnNpZGUgKiptdXRhdGUqKigpIGlzIGFwcGxpZWQgc2VxdWVudGlhbGx5IHN0b2NrLWJ5LXN0b2NrIQoKCioqKgojIyBQQVJUIElJSTogUElWT1QgVEFCTEVTCgowKSBGaXJzdCwgd2UgYXJlIChhZ2FpbikgZ29pbmcgdG8gYXVnbWVudCB0aGUgZGF0YWJhc2UgYnkgYWRkaW5nIGEgWWVhciBjb2x1bW4uIFRoZSBjb2RlIGlzOiAgCmBgYHtyIGRhdGUsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQppZighcmVxdWlyZShsdWJyaWRhdGUpKXtpbnN0YWxsLnBhY2thZ2VzKCJsdWJyaWRhdGUiKX0gCiMgVGhpcyBpcyBhIHBhY2thZ2UgdGhhdCBoYW5kbGVzIGRhdGVzIGVmZmVjdGl2ZWx5LiBTS0lQIHRoaXMgc3RlcCBpZiBhbHJlYWR5IGluc3RhbGxlZC4KbGlicmFyeShsdWJyaWRhdGUpCmRhdGEgPC0gZGF0YSAlPiUgbXV0YXRlKFllYXIgPSB5ZWFyKERhdGUpKSAjIEFkZGluZyBhIFllYXIgY29sdW1uIGZvciB5ZWFybHkgc3RhdGlzdGljcy4KYGBgCgoxKSBHcm91cCB0aGUgZGF0YSBieSBjb21wYW55IGFuZCBieSB5ZWFyIGFuZCBjcmVhdGUgYSBuZXcgdmFyaWFibGUgKkF2Z19DYXAqIHdoaWNoIGNvbXB1dGVzIHRoZSBhdmVyYWdlIG1hcmtldCBjYXBpdGFsaXNhdGlvbi4gIAoyKSBQbG90IChsaW5lKSB0aGUgY29ycmVzcG9uZGluZyByZXN1bHRzOiB4LWF4aXMgaXMgWWVhciwgeS1heGlzIGlzIEF2Z19DYXAgd2l0aCBvbmUgY29sb3IgZm9yIGVhY2ggZmlybS4gPT4gSGFyZCB0byByZWFkLiBCZXlvbmQgMTAgZmlybXMsIHRoZSBncmFwaCBiZWNvbWVzIGxlc3MgaW5zaWdodGZ1bC4gVHJ5IHRvIGRvIHRoZSBzYW1lIHdpdGggYSBiYXJwbG90LgozKSBQaWNrIG9uZSB5ZWFyIChlLmcuLCAyMDA1KSBhbmQgc2hvdyB0aGUgYXZlcmFnZSBjYXBpdGFsaXphdGlvbiBvZiBmaXJtcyBpbiBkZWNyZWFzaW5nIG9yZGVyLgo0KSBGcm9tIGRhdGEsIGNyZWF0ZSBhIHBpdm90IHRhYmxlIChjYWxsIGl0IHB0KSB0aGF0IGNvbXB1dGVzIHRoZSBhdmVyYWdlIGNhcGl0YWxpemF0aW9uLCBhdmVyYWdlIFAyQiBhbmQgYXZlcmFnZSByZXR1cm4gZm9yIGVhY2ggZmlybS4gSGludDogZm9yIHJldHVybnMsIHRoZXJlIGFyZSBzb21lIE5Bcywgc28gdXNlIHRoZSBhcmd1bWVudCBuYS5ybSA9IFQgaW4gdGhlIG1lYW4oKS4KCmBgYHtyIFVQIFRPIFlPVSEgNX0KZGF0YSAlPiUgZ3JvdXBfYnkoVGljaywgWWVhcikgJT4lIAogICAgc3VtbWFyaXNlKEF2Z19DYXAgPSBtZWFuKE1rdF9DYXApKSAlPiUgIyBUaGlzIGlzIHBvaW50IDEpCiAgICBnZ3Bsb3QoYWVzKHg9WWVhciwgeSA9QXZnX0NhcCkpICsgZ2VvbV9saW5lKGFlcyhjb2xvciA9IFRpY2spKSAgICAgICAgICAgICAgICAgICMgUG9pbnQgMikKZGF0YSAlPiUgZ3JvdXBfYnkoVGljaywgWWVhcikgJT4lIAogICAgc3VtbWFyaXNlKEF2Z19DYXAgPSBtZWFuKE1rdF9DYXApKSAlPiUgCiAgICBnZ3Bsb3QoYWVzKHg9WWVhciwgeSA9QXZnX0NhcCkpICsgZ2VvbV9iYXIoYWVzKGZpbGwgPSBUaWNrKSwgc3RhdCA9ICJpZGVudGl0eSIpICMgUG9pbnQgMikKZGF0YSAlPiUgZ3JvdXBfYnkoVGljaywgWWVhcikgJT4lIAogICAgc3VtbWFyaXNlKEF2Z19DYXAgPSBtZWFuKE1rdF9DYXApKSAlPiUgCiAgICBmaWx0ZXIoWWVhciA9PSAyMDA1KSAlPiUgCiAgICBhcnJhbmdlKGRlc2MoQXZnX0NhcCkpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgUG9pbnQgMykKcHQgPC0gZGF0YSAlPiUgZ3JvdXBfYnkoVGljaykgJT4lIAogICAgc3VtbWFyaXNlKEF2Z19DYXAgPSBtZWFuKE1rdF9DYXApLCBBdmdfUDJCID0gbWVhbihQMkIpLCBBdmdfUmV0ID0gbWVhbihSZXR1cm4sIG5hLnJtID0gVCkpICMgUG9pbnQgNDogYmV3YXJlIG9mIE5BIHByb2JsZW1zIQpwdApgYGAKCioqKgojIyBQQVJUIElWOiBGQUNUT1IgQU5BTFlTSVMKUmVzZWFyY2ggaW4gZmluYW5jaWFsIGVjb25vbWljcyBoYXMgc2hvd24gdGhhdCBmaXJtcycgY2hhcmFjdGVyaXN0aWNzIGFyZSBsaWtlbHkgdG8gZHJpdmUgcHJvZml0YWJpbGl0eS4gV2UgdHJ5IHRvIGludmVzdGlnYXRlIHRoaXMgaWRlYSBiZWxvdy4gIAoxKSBVc2luZyBkYXRhLCBwbG90IChzY2F0dGVyIHBsb3QsIGkuZS4sIHdpdGggcG9pbnRzKSB5ID0gcmV0dXJucyB2ZXJzdXMgeCA9IE1rdF9DYXAuIAoyKSBTYW1lIGV4ZXJjaXNlIGJ1dCB3aXRoIHB0IChwaXZvdCB0YWJsZSBmcm9tIFBBUlQgSUlJKSwgeCA9IEF2Z19DYXAgYW5kIHkgPSBBdmdfUmV0LgozKSBTYW1lIGV4ZXJjaXNlIGFzIDIpLCBidXQgYWZ0ZXIgcmVtb3ZpbmcgQUFQTCBmcm9tIHRoZSBzYW1wbGUKNCkgRnJvbSBwdCwgcGxvdCB4ID0gQXZnX1AyQiBhbmQgeSA9IEF2Z19yZXQuIENvbW1lbnQ/CmBgYHtyIFVQIFRPIFlPVSEgNiwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0V9CmRhdGEgJT4lIGdncGxvdChhZXMoeCA9IE1rdF9DYXAsIHkgPSBSZXR1cm4pKSArIGdlb21fcG9pbnQoKSArIHN0YXRfc21vb3RoKCkgICMgUG9pbnQgMSkKcHQgJT4lIGdncGxvdChhZXMoeCA9IEF2Z19DYXAsIHkgPSBBdmdfUmV0KSkgKyBnZW9tX3BvaW50KCkgKyBzdGF0X3Ntb290aCgpICsgIyBQb2ludCAyKQogICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IFRpY2spKSAjIFlvdSBjYW4gYWRkIHRoaXMgbGluZSB0byBzZWUgdGhlIGZpcm0gbmFtZXMuCnB0ICU+JSBnZ3Bsb3QoYWVzKHggPSBBdmdfQ2FwLCB5ID0gQXZnX1JldCkpICsgZ2VvbV9wb2ludCgpICsgc3RhdF9zbW9vdGgobWV0aG9kID0gImxtIikgIyBsbSBpcyBmb3IgJ2xpbmVhciBtb2RlbCcsIGhlbmNlIHRoZSBzdHJhaWdodCBsaW5lLgpwdCAlPiUgZmlsdGVyKFRpY2sgIT0gIkFBUEwiKSAlPiUgZ2dwbG90KGFlcyh4ID0gQXZnX0NhcCwgeSA9IEF2Z19SZXQpKSArICMgUG9pbnQgMyk6IHdlIHJlbW92ZSBBQVBMCiAgICBnZW9tX3BvaW50KCkgKyBzdGF0X3Ntb290aChtZXRob2QgPSAibG0iKQpwdCAlPiUgZ2dwbG90KGFlcyh4ID0gQXZnX1AyQiwgeSA9IEF2Z19SZXQpKSArIGdlb21fcG9pbnQoKSArIHN0YXRfc21vb3RoKG1ldGhvZCA9ICJsbSIpICsKICAgIGdlb21fdGV4dChhZXMobGFiZWwgPSBUaWNrKSkKYGBgCgoKSW4gdGhlIGxhc3QgZ3JhcGgsIHRoZXJlIGlzIGFuIG91dGxpZXIgZm9yIHRoZSBhdmVyYWdlIFAyQjogZXJyb3IgaW4gdGhlIGRhdGE/IEZ1cnRoZXIgaW52ZXN0aWdhdGlvbiB3b3VsZCBzaG93IHRoYXQgaW4gMjAxNywgdGhlIGJvb2sgdmFsdWUgb2YgQm9laW5nIHdhcyB2ZXJ5IHNtYWxsIGFuZCBoZW5jZSBpdHMgUDJCIHJhdGlvIHdhcyBleHRyZW1lbHkgaGlnaC4gICAgIApJbiB0aGUgYWJvdmUgZ3JhcGhzLCB3ZSBzZWUgdGhlIG1pbGQgbmVnYXRpdmUgcmVsYXRpb25zaGlwIGJldHdlZW4gZmlybSBzaXplIGFuZCBhdmVyYWdlIHJldHVybi4gVGhvdWdoIG91ciBzYW1wbGUgaXMgbXVjaCB0b28gc21hbGwgYW5kIG91ciBzdHVkeSBub3Qgcmlnb3Vyb3VzLCB0aGlzIHJlc2VtYmxlcyB0aGUgc28tY2FsbGVkIHNpemUgZWZmZWN0IGFjY29yZGluZyB0byB3aGljaCBzbWFsbCBmaXJtcyBhcmUgbW9yZSBwcm9maXRhYmxlIHRoYW4gbGFyZ2UgZmlybXMgKHRob3VnaCBub3QgaW4gZmluYW5jaWFsICpiYWQgdGltZXMqKS4KCioqKgojIyBQQVJUIFY6IExPT1BTCkNyZWF0ZSBhIGxvb3Agb3ZlciBhbGwgZGF0ZXMgdGhhdCBjb21wdXRlcyB0aGUgYWdncmVnYXRlIG1hcmtldCBjYXBpdGFsaXNhdGlvbiBvZiBhbGwgMzAgZmlybXMgYXQgZWFjaCBkYXRlIChjYWxsIGl0IEFnZ19DYXApLiBQbG90IHRoZSBjb3JyZXNwb25pbmcgc2VyaWVzLiAoKipOb3RlKio6IHRoaXMgaXMgYSB2ZXJ5IGluZWZmaWNpZW50IHdheSB0byBkbyB0aGlzLikKCgpgYGB7ciBVUCBUTyBZT1UhIDd9CmRhdGVzIDwtIGRhdGEkRGF0ZSAlPiUgCiAgICBhcy5mYWN0b3IoKSAlPiUgCiAgICBsZXZlbHMoKSAlPiUKICAgIGFzLkRhdGUoKSAgICAgICAjIENyZWF0aW5nIGEgdmVjdG9yIG9mIGRhdGVzLgpkYXRlcyA8LSBkYXRhICU+JSAKICAgIGZpbHRlcihUaWNrID09ICJBQVBMIikgJT4lIAogICAgc2VsZWN0KERhdGUpICU+JSAKICAgIGFzLm1hdHJpeCgpICU+JSAjIFRoaXMgaXMgdG8gZ2V0IHJpZCBvZiB0aGUgZGF0YWZyYW1lIHN0cnVjdHVyZSB0byBhdm9pZCBjb2x1bW4gbnVtYmVycyAKICAgIGFzLkRhdGUoKSAgICAgICAjIFNpbWlsYXIgdGhvdWdoIG5vdCBleGFjdGx5IHRoZSBzYW1lIHJlc3VsdAoKQWdnX0NhcCA8LSAwCmZvcih0IGluIDE6bGVuZ3RoKGRhdGVzKSl7CiAgICBBZ2dfQ2FwW3RdIDwtIGRhdGEgJT4lCiAgICAgICAgZmlsdGVyKERhdGUgPT0gZGF0ZXNbdF0pICU+JQogICAgICAgIHNlbGVjdChNa3RfQ2FwKSAlPiUKICAgICAgICBzdW0oKQp9CmRhdGEuZnJhbWUoZGF0ZXMsIEFnZ19DYXApICU+JSBnZ3Bsb3QoYWVzKHggPSBkYXRlcywgeSA9IEFnZ19DYXApKSArIGdlb21fbGluZSgpCgpgYGAKCg==