Analysis of a Tesla Inc. (TSLA) historical stock price dataset from NASDAQ Historical Data: https://www.nasdaq.com/market-activity/stocks/tsla/historical

The dataset contains date, stock open/close prices, stock price daily high/low and volume of shares traded over the past 5 years as of October 15th, 2021.

library(tidyverse)
library(ggplot2)
library(gghighlight)
library(forecast)

#Importing the csv file to a Data Frame
tesla <- read.csv("tesla_stock.csv")

#Viewing the Data Frame
head(tesla)

Data Cleaning and Preparation

In this stage the data is checked for accuracy and completeness prior to beginning the analysis. Some of the issues addressed are as follows:

Missing Values

#Identifying total number of missing values
sum(is.na(tesla))
[1] 0

There are no missing values.

Correcting Formatting Issues

#Checking the data types
str(tesla)
'data.frame':   1258 obs. of  6 variables:
 $ Date      : chr  "10/14/2021" "10/13/2021" "10/12/2021" "10/11/2021" ...
 $ Close.Last: chr  "$818.32" "$811.08" "$805.72" "$791.94" ...
 $ Volume    : int  12247170 14120080 22020040 14200320 16738600 19195780 14632770 18432630 30483340 17031410 ...
 $ Open      : chr  "$815.49" "$810.47" "$800.93" "$787.65" ...
 $ High      : chr  "$820.25" "$815.41" "$812.32" "$801.24" ...
 $ Low       : chr  "$813.3501" "$805.78" "$796.57" "$785.5" ...

We need to format the Date column as date values and format the Close.Last, Open, High and Low as numbers.

#Formatting the Date column as date values
tesla$Date <- as.Date(tesla$Date, "%m/%d/%Y")

#Formatting Close.Last, Open, High and Low as numbers rounded to 2 decimal places
#(gsub("[$]","", column_name) allows us to remove the Dollar sign from the character string
tesla$Close.Last <-  round(as.numeric(gsub("[$]","", tesla$Close.Last)),2)
tesla$Open <-  round(as.numeric(gsub("[$]","", tesla$Open)),2)
tesla$High <-  round(as.numeric(gsub("[$]","", tesla$High)),2)
tesla$Low <- round(as.numeric(gsub("[$]","", tesla$Low)),2)

head(tesla)
NA

Creating New Features

Moving Average

We will create a new column to track the moving average of the daily Closing Stock Price over a set period. The moving average smooths out the stock price price data by creating a constantly updated average stock price. We will track the moving average across two periods:

  • 7 Day Period
  • 30 Day Period
#Calculating a moving average for stock price over the last 7 days
tesla$Moving_Average_7_Day <- round(ma(tesla$Close.Last, 7),2)
tesla$Moving_Average_30_Day <- round(ma(tesla$Close.Last, 30),2)

Identify Issues Revealed due to New Features

The Moving averages calculate an average based on previous data over the set period. However, for cases where there is not enough previous data, the moving average cannot calculate a value and leaves a missing value. To rectify these missing values we will have to remove the associated rows.

#Removing rows with missing data
tesla <- na.omit(tesla)

Exploratory Data Analysis

In this stage, we will examine the data to identify any patterns, trends and relationships between the variables. It will help us analyze the data and extract insights that can be used to make decisions.

Data Visualization will give us a clear idea of what the data means by giving it visual context.

Statistics

Lets take a look at the data as a whole to understand how the Tesla Stock Price has varied over the last 5 years.

summary(tesla)
      Date              Close.Last         Volume               Open             High             Low         Moving_Average_7_Day
 Min.   :2016-11-07   Min.   : 35.79   Min.   :  9800558   Min.   : 36.22   Min.   : 36.95   Min.   : 35.40   Min.   : 37.02      
 1st Qu.:2018-01-28   1st Qu.: 57.88   1st Qu.: 25252174   1st Qu.: 57.53   1st Qu.: 58.98   1st Qu.: 56.53   1st Qu.: 57.73      
 Median :2019-04-17   Median : 68.04   Median : 35270215   Median : 68.06   Median : 69.22   Median : 66.92   Median : 68.02      
 Mean   :2019-04-17   Mean   :202.45   Mean   : 44992494   Mean   :202.33   Mean   :206.90   Mean   :197.71   Mean   :202.47      
 3rd Qu.:2020-07-07   3rd Qu.:274.46   3rd Qu.: 53038012   3rd Qu.:279.20   3rd Qu.:282.14   3rd Qu.:263.54   3rd Qu.:271.12      
 Max.   :2021-09-23   Max.   :883.09   Max.   :304693800   Max.   :891.38   Max.   :900.40   Max.   :871.60   Max.   :859.24      
 Moving_Average_30_Day
 Min.   : 37.84       
 1st Qu.: 58.33       
 Median : 67.24       
 Mean   :202.56       
 3rd Qu.:257.06       
 Max.   :836.38       

As seen in the summary above:

  • Oldest data point is from 2016-11-07 and the most recent data point is from 2021-09-23.
  • Highest Closing Stock Price was $883.09, while the lowest Closing Stock Price $35.79.
  • Highest Opening Stock Price was $891.38, while the lowest Opening Stock Price $36.22.
  • The Highest Stock Price over the past 5 years was $900.40.
  • The Lowest Stock Price over the past 5 years was $35.40.
  • The Volume of Stocks traded averaged around 45 million with a maximum of around 304 million.

Tesla Stock Performace

ggplot(tesla, aes(x=Date)) + 
  geom_line(aes(y = Close.Last, colour="Close Price")) + 
  geom_line(aes(y =  Open, colour="Open Price")) +
  geom_line(aes(y =  High, colour="High Price")) +
  geom_line(aes(y =  Low, colour="Low Price")) +
  labs(title="Tesla Stock Price Over the Last 5 Years", x="Year", y="Tesla Stock Price ($)", colour = "Price") +
  scale_color_manual(values = c("black", "steelblue","gold","darkviolet")) +
  scale_x_date(date_minor_breaks = "1 month") +
  theme_bw() +
  theme(axis.text.x = element_text(size = 10), axis.title.x = element_text(size = 12),
        axis.text.y = element_text(size = 10), axis.title.y = element_text(size = 12),
        plot.title = element_text(size = 15))

The plot above shows the Daily Closing, Opening, High and Low Stock Prices. The spread of the lines indicates the fluctuations in Daily Stock Prices. The four lines stick together with little variation until early 2020, which is when we begin to see a lot more fluctuation in price but in general there is steep increase in stock price. We can examine the Closing Stock Price to get a clearer idea of this behavior.

Closing Stock Price

#Plotting the Closing Stock Price over the last 5 years
ggplot(tesla, aes(x=Date, y=Close.Last )) + 
  geom_line() + 
  labs(title="Tesla Closing Stock Price Over the Last 5 Years", x="Year", y="Tesla Closing Stock Price ($)") +
  scale_x_date(date_minor_breaks = "1 month") +
  theme_bw() +
  theme(axis.text.x = element_text(size = 10), axis.title.x = element_text(size = 12),
        axis.text.y = element_text(size = 10), axis.title.y = element_text(size = 12),
        plot.title = element_text(size = 15))

As seen previously above there is a steep rise in the Tesla Stock Price since early 2020. Lets take a closer look at the stock price during this time.

Closing Stock Price since Jan 2020

#Plotting the Stock Price since beginning of Jan 2020 onwards
ggplot(tesla, aes(x=Date, y=Close.Last )) + 
  geom_line() + 
  labs(title="Tesla Closing Stock Price in 2020", x="Month", y="Tesla Closing Stock Price ($)") +
  scale_x_date(date_breaks = "1 month", date_labels = "%b", limit=c(as.Date("2020-01-01"),as.Date("2021-09-23"))) +
  ylim(0,900) +
  theme_bw() +
  theme(axis.text.x = element_text(size = 10), axis.title.x = element_text(size = 12),
        axis.text.y = element_text(size = 10), axis.title.y = element_text(size = 12),
        plot.title = element_text(size = 15))
Warning: Removed 792 row(s) containing missing values (geom_path).

The stock price has continued to increase significantly since Jan 2020, reaching a peak around Feb 2021.

#The most recent stock price
recent_stock <- tesla %>% filter(Date == max(tesla$Date))

#Stock price at the beginning of 2020
#Note: No data for date 2020-01-01
stock_start_2020 <- tesla %>% filter(Date == as.Date("2020-01-02"))

#Stock price at the end of 2020
stock_end_2020 <- tesla %>% filter(Date == as.Date("2020-12-31"))

#Calculating the percentage increase since the start of 2020 and the most recent date 
pct_recent = round((((recent_stock$Close.Last-stock_start_2020$Close.Last)/stock_start_2020$Close.Last)*100),0) 

#Calculating the percentage increase between the start and end of 2020 
pct_2020 = round((((stock_end_2020$Close.Last-stock_start_2020$Close.Last)/stock_start_2020$Close.Last)*100),0) 

cat("The stock price increase: \n Jan 2020-Present",pct_recent,"% \n Jan 2020 - Dec 2020 End:",pct_2020,"%") 
The stock price increase: 
 Jan 2020-Present 776 % 
 Jan 2020 - Dec 2020 End: 720 %

The stock price has increased 776% between the beginning of 2020 and the present. In fact, it increased by 720% just in 2020 alone.

Moving Average

#Plotting the Closing Stock price vs the 7 Day Moving Average
ggplot(tesla, aes(x=Date)) + 
  geom_line(aes(y = Close.Last, colour="Close Price")) + 
  geom_line(aes(y =  Moving_Average_7_Day, colour="7 Day")) +
  labs(title="Tesla Stock Price vs. 7 Day Moving Average", x="Year", y="Tesla Stock Price ($)", colour = "Price & Moving Average") +
  scale_color_manual(values = c("black","tan3")) +
  scale_x_date(date_minor_breaks = "1 month") +
  theme_bw() +
  theme(axis.text.x = element_text(size = 10), axis.title.x = element_text(size = 12),
        axis.text.y = element_text(size = 10), axis.title.y = element_text(size = 12),
        plot.title = element_text(size = 15))

#Plotting the Closing Stock price vs the 30 Day Moving Average
ggplot(tesla, aes(x=Date)) + 
  geom_line(aes(y = Close.Last, colour="Close Price")) + 
  geom_line(aes(y =  Moving_Average_30_Day, colour="30 Day")) +
  labs(title="Tesla Stock Price vs. 30 Day Moving Average", x="Year", y="Tesla Stock Price ($)", colour = "Price & Moving Average") +
  scale_color_manual(values = c("black","orange")) +
  scale_x_date(date_minor_breaks = "1 month") +
  theme_bw() +
  theme(axis.text.x = element_text(size = 10), axis.title.x = element_text(size = 12),
        axis.text.y = element_text(size = 10), axis.title.y = element_text(size = 12),
        plot.title = element_text(size = 15))

The 30 Day Moving Average gives us a much smoother curve than the 7 Day Moving Average. Therefore, using the 30 Day Moving Average we can clearly see the points where the stock price deviated noticeably from the predicted price. The stock price fluctuations seem to be most significant in the period after early 2020, which correlates with our earlier observation.

Stock Trading Volume

#Plotting the Closing Stock Price over the last 5 years
ggplot(tesla, aes(x=Date, y=Volume, color ="orange")) + 
  geom_point() +
  geom_line(aes(y =  45000000, color="red")) +
  labs(title="Tesla Stock Trading Volume Over the Last 5 Years", x="Year", y="Number of Stocks Traded") +
  scale_x_date(date_minor_breaks = "1 month") +
  theme_bw() +
  theme(axis.text.x = element_text(size = 10), axis.title.x = element_text(size = 12),
        axis.text.y = element_text(size = 10), axis.title.y = element_text(size = 12),
        plot.title = element_text(size = 15)) + 
  theme(legend.position = "none") 

The volume of stocks traded has generally remained around or been under the average of 45 million (indicated by the line), however there is an increase in volume during the year 2020, though the it does seem to be getting back to normal since the beginning of 2021.

Summary of Data Analysis

The Tesla Stock Price has increase significantly since 2016. The stock price remained relatively steady until early 2020 when it began to rise drastically. The stock price has increased 776% between the beginning of 2020 and the present. In fact, it increased by 720% just in 2020 alone. While the stock price reaches its peak around Feb 2021, it has continued its general upward trend. However, during the period of price increase the Daily stock price would fluctuate significantly compared to its relatively stable price prior to 2020.

The volume of stocks traded during the last 5 years has generally remained around or been under the average of 45 million, however there is an increase in volume during the year 2020, which corresponds to the steep increase in stock price. We would typically expect an increase in trading activity like this during a period when the company’s stocks are rapidly rising.

LS0tCnRpdGxlOiAiVGVzbGEgU3RvY2sgRGF0YSBBbmFseXNpcyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQpBbmFseXNpcyBvZiBhIFRlc2xhIEluYy4gKFRTTEEpIGhpc3RvcmljYWwgc3RvY2sgcHJpY2UgZGF0YXNldCBmcm9tIE5BU0RBUSBIaXN0b3JpY2FsIERhdGE6IGh0dHBzOi8vd3d3Lm5hc2RhcS5jb20vbWFya2V0LWFjdGl2aXR5L3N0b2Nrcy90c2xhL2hpc3RvcmljYWwKClRoZSBkYXRhc2V0IGNvbnRhaW5zIGRhdGUsIHN0b2NrIG9wZW4vY2xvc2UgcHJpY2VzLCBzdG9jayBwcmljZSBkYWlseSBoaWdoL2xvdyBhbmQgdm9sdW1lIG9mIHNoYXJlcyB0cmFkZWQgb3ZlciB0aGUgcGFzdCA1IHllYXJzIGFzIG9mIE9jdG9iZXIgMTV0aCwgMjAyMS4gCgoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2doaWdobGlnaHQpCmxpYnJhcnkoZm9yZWNhc3QpCgojSW1wb3J0aW5nIHRoZSBjc3YgZmlsZSB0byBhIERhdGEgRnJhbWUKdGVzbGEgPC0gcmVhZC5jc3YoInRlc2xhX3N0b2NrLmNzdiIpCgojVmlld2luZyB0aGUgRGF0YSBGcmFtZQpoZWFkKHRlc2xhKQpgYGAKCiMgRGF0YSBDbGVhbmluZyBhbmQgUHJlcGFyYXRpb24KSW4gdGhpcyBzdGFnZSB0aGUgZGF0YSBpcyBjaGVja2VkIGZvciBhY2N1cmFjeSBhbmQgY29tcGxldGVuZXNzIHByaW9yIHRvIGJlZ2lubmluZyB0aGUgYW5hbHlzaXMuIFNvbWUgb2YgdGhlIGlzc3VlcyBhZGRyZXNzZWQgYXJlIGFzIGZvbGxvd3M6CgotIFJlbW92ZSBleHRyYW5lb3VzIGRhdGEKLSBDaGVjayBmb3IgaW4gbWlzc2luZyB2YWx1ZXMKLSBSZXBsYWNlIG1pc3NpbmcgdmFsdWVzCi0gRGVsZXRlIGRhdGEgdGhhdCBjYW5ub3QgYmUgY29ycmVjdGVkL3JlcGxhY2VkCi0gQ29ycmVjdCBhbnkgZGF0YSBmb3JtYXR0aW5nIGlzc3VlcwotIENyZWF0aW5nIG5ldyBmZWF0dXJlcwotIElkZW50aWZ5IGVycm9ycyByZXZlYWxlZCB3aGVuIG5ldyB2YXJpYWJsZXMgYXJlIGNyZWF0ZWQKCiMjIE1pc3NpbmcgVmFsdWVzCmBgYHtyfQojSWRlbnRpZnlpbmcgdG90YWwgbnVtYmVyIG9mIG1pc3NpbmcgdmFsdWVzCnN1bShpcy5uYSh0ZXNsYSkpCmBgYApUaGVyZSBhcmUgbm8gbWlzc2luZyB2YWx1ZXMuIAoKIyMgQ29ycmVjdGluZyBGb3JtYXR0aW5nIElzc3VlcwpgYGB7cn0KI0NoZWNraW5nIHRoZSBkYXRhIHR5cGVzCnN0cih0ZXNsYSkKYGBgCldlIG5lZWQgdG8gZm9ybWF0IHRoZSBEYXRlIGNvbHVtbiBhcyBkYXRlIHZhbHVlcyBhbmQgZm9ybWF0IHRoZSBDbG9zZS5MYXN0LCBPcGVuLCBIaWdoIGFuZCBMb3cgYXMgbnVtYmVycy4KCmBgYHtyfQojRm9ybWF0dGluZyB0aGUgRGF0ZSBjb2x1bW4gYXMgZGF0ZSB2YWx1ZXMKdGVzbGEkRGF0ZSA8LSBhcy5EYXRlKHRlc2xhJERhdGUsICIlbS8lZC8lWSIpCgojRm9ybWF0dGluZyBDbG9zZS5MYXN0LCBPcGVuLCBIaWdoIGFuZCBMb3cgYXMgbnVtYmVycyByb3VuZGVkIHRvIDIgZGVjaW1hbCBwbGFjZXMKIyhnc3ViKCJbJF0iLCIiLCBjb2x1bW5fbmFtZSkgYWxsb3dzIHVzIHRvIHJlbW92ZSB0aGUgRG9sbGFyIHNpZ24gZnJvbSB0aGUgY2hhcmFjdGVyIHN0cmluZwp0ZXNsYSRDbG9zZS5MYXN0IDwtICByb3VuZChhcy5udW1lcmljKGdzdWIoIlskXSIsIiIsIHRlc2xhJENsb3NlLkxhc3QpKSwyKQp0ZXNsYSRPcGVuIDwtICByb3VuZChhcy5udW1lcmljKGdzdWIoIlskXSIsIiIsIHRlc2xhJE9wZW4pKSwyKQp0ZXNsYSRIaWdoIDwtICByb3VuZChhcy5udW1lcmljKGdzdWIoIlskXSIsIiIsIHRlc2xhJEhpZ2gpKSwyKQp0ZXNsYSRMb3cgPC0gcm91bmQoYXMubnVtZXJpYyhnc3ViKCJbJF0iLCIiLCB0ZXNsYSRMb3cpKSwyKQoKaGVhZCh0ZXNsYSkKCmBgYAojIyBDcmVhdGluZyBOZXcgRmVhdHVyZXMKIyMjIE1vdmluZyBBdmVyYWdlCldlIHdpbGwgY3JlYXRlIGEgbmV3IGNvbHVtbiB0byB0cmFjayB0aGUgbW92aW5nIGF2ZXJhZ2Ugb2YgdGhlIGRhaWx5IENsb3NpbmcgU3RvY2sgUHJpY2Ugb3ZlciBhIHNldCBwZXJpb2QuIFRoZSBtb3ZpbmcgYXZlcmFnZSBzbW9vdGhzIG91dCB0aGUgc3RvY2sgcHJpY2UgcHJpY2UgZGF0YSBieSBjcmVhdGluZyBhIGNvbnN0YW50bHkgdXBkYXRlZCBhdmVyYWdlIHN0b2NrIHByaWNlLiBXZSB3aWxsIHRyYWNrIHRoZSBtb3ZpbmcgYXZlcmFnZSBhY3Jvc3MgdHdvIHBlcmlvZHM6CgotIDcgRGF5IFBlcmlvZAotIDMwIERheSBQZXJpb2QKCmBgYHtyfQojQ2FsY3VsYXRpbmcgYSBtb3ZpbmcgYXZlcmFnZSBmb3Igc3RvY2sgcHJpY2Ugb3ZlciB0aGUgbGFzdCA3IGRheXMKdGVzbGEkTW92aW5nX0F2ZXJhZ2VfN19EYXkgPC0gcm91bmQobWEodGVzbGEkQ2xvc2UuTGFzdCwgNyksMikKdGVzbGEkTW92aW5nX0F2ZXJhZ2VfMzBfRGF5IDwtIHJvdW5kKG1hKHRlc2xhJENsb3NlLkxhc3QsIDMwKSwyKQpgYGAKCiMjIElkZW50aWZ5IElzc3VlcyBSZXZlYWxlZCBkdWUgdG8gTmV3IEZlYXR1cmVzClRoZSBNb3ZpbmcgYXZlcmFnZXMgY2FsY3VsYXRlIGFuIGF2ZXJhZ2UgYmFzZWQgb24gcHJldmlvdXMgZGF0YSBvdmVyIHRoZSBzZXQgcGVyaW9kLiBIb3dldmVyLCBmb3IgY2FzZXMgd2hlcmUgdGhlcmUgaXMgbm90IGVub3VnaCBwcmV2aW91cyBkYXRhLCB0aGUgbW92aW5nIGF2ZXJhZ2UgY2Fubm90IGNhbGN1bGF0ZSBhIHZhbHVlIGFuZCBsZWF2ZXMgYSBtaXNzaW5nIHZhbHVlLiBUbyByZWN0aWZ5IHRoZXNlIG1pc3NpbmcgdmFsdWVzIHdlIHdpbGwgaGF2ZSB0byByZW1vdmUgdGhlIGFzc29jaWF0ZWQgcm93cy4KYGBge3J9CiNSZW1vdmluZyByb3dzIHdpdGggbWlzc2luZyBkYXRhCnRlc2xhIDwtIG5hLm9taXQodGVzbGEpCmBgYAoKIyBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzCkluIHRoaXMgc3RhZ2UsIHdlIHdpbGwgZXhhbWluZSB0aGUgZGF0YSB0byBpZGVudGlmeSBhbnkgcGF0dGVybnMsIHRyZW5kcyBhbmQgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIHRoZSB2YXJpYWJsZXMuIEl0IHdpbGwgaGVscCB1cyBhbmFseXplIHRoZSBkYXRhIGFuZCBleHRyYWN0IGluc2lnaHRzIHRoYXQgY2FuIGJlIHVzZWQgdG8gbWFrZSBkZWNpc2lvbnMuCgpEYXRhIFZpc3VhbGl6YXRpb24gd2lsbCBnaXZlIHVzIGEgY2xlYXIgaWRlYSBvZiB3aGF0IHRoZSBkYXRhIG1lYW5zIGJ5IGdpdmluZyBpdCB2aXN1YWwgY29udGV4dC4KCiMjIFN0YXRpc3RpY3MKTGV0cyB0YWtlIGEgbG9vayBhdCB0aGUgZGF0YSBhcyBhIHdob2xlIHRvIHVuZGVyc3RhbmQgaG93IHRoZSBUZXNsYSBTdG9jayBQcmljZSBoYXMgdmFyaWVkIG92ZXIgdGhlIGxhc3QgNSB5ZWFycy4KYGBge3J9CnN1bW1hcnkodGVzbGEpCmBgYApBcyBzZWVuIGluIHRoZSBzdW1tYXJ5IGFib3ZlOgoKLSBPbGRlc3QgZGF0YSBwb2ludCBpcyBmcm9tIDxiPjIwMTYtMTEtMDc8L2I+IGFuZCB0aGUgbW9zdCByZWNlbnQgZGF0YSBwb2ludCBpcyBmcm9tIDxiPjIwMjEtMDktMjM8L2I+LiAKLSBIaWdoZXN0IENsb3NpbmcgU3RvY2sgUHJpY2Ugd2FzIDxiPiQ4ODMuMDk8L2I+LCB3aGlsZSB0aGUgbG93ZXN0IENsb3NpbmcgU3RvY2sgUHJpY2UgPGI+JDM1Ljc5PC9iPi4KLSBIaWdoZXN0IE9wZW5pbmcgU3RvY2sgUHJpY2Ugd2FzIDxiPiQ4OTEuMzg8L2I+LCB3aGlsZSB0aGUgbG93ZXN0IE9wZW5pbmcgU3RvY2sgUHJpY2UgPGI+JDM2LjIyPC9iPi4KLSBUaGUgSGlnaGVzdCBTdG9jayBQcmljZSBvdmVyIHRoZSBwYXN0IDUgeWVhcnMgd2FzIDxiPiQ5MDAuNDA8L2I+LgotIFRoZSBMb3dlc3QgU3RvY2sgUHJpY2Ugb3ZlciB0aGUgcGFzdCA1IHllYXJzIHdhcyA8Yj4kMzUuNDA8L2I+LgotIFRoZSBWb2x1bWUgb2YgU3RvY2tzIHRyYWRlZCBhdmVyYWdlZCBhcm91bmQgPGI+NDUgbWlsbGlvbjwvYj4gd2l0aCBhIG1heGltdW0gb2YgYXJvdW5kIDxiPjMwNCBtaWxsaW9uPC9iPi4gIAoKIyMgVGVzbGEgU3RvY2sgUGVyZm9ybWFjZQoKYGBge3J9CmdncGxvdCh0ZXNsYSwgYWVzKHg9RGF0ZSkpICsgCiAgZ2VvbV9saW5lKGFlcyh5ID0gQ2xvc2UuTGFzdCwgY29sb3VyPSJDbG9zZSBQcmljZSIpKSArIAogIGdlb21fbGluZShhZXMoeSA9ICBPcGVuLCBjb2xvdXI9Ik9wZW4gUHJpY2UiKSkgKwogIGdlb21fbGluZShhZXMoeSA9ICBIaWdoLCBjb2xvdXI9IkhpZ2ggUHJpY2UiKSkgKwogIGdlb21fbGluZShhZXMoeSA9ICBMb3csIGNvbG91cj0iTG93IFByaWNlIikpICsKICBsYWJzKHRpdGxlPSJUZXNsYSBTdG9jayBQcmljZSBPdmVyIHRoZSBMYXN0IDUgWWVhcnMiLCB4PSJZZWFyIiwgeT0iVGVzbGEgU3RvY2sgUHJpY2UgKCQpIiwgY29sb3VyID0gIlByaWNlIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsICJzdGVlbGJsdWUiLCJnb2xkIiwiZGFya3Zpb2xldCIpKSArCiAgc2NhbGVfeF9kYXRlKGRhdGVfbWlub3JfYnJlYWtzID0gIjEgbW9udGgiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpKQpgYGAKClRoZSBwbG90IGFib3ZlIHNob3dzIHRoZSBEYWlseSBDbG9zaW5nLCBPcGVuaW5nLCBIaWdoIGFuZCBMb3cgU3RvY2sgUHJpY2VzLiBUaGUgc3ByZWFkIG9mIHRoZSBsaW5lcyBpbmRpY2F0ZXMgdGhlIGZsdWN0dWF0aW9ucyBpbiBEYWlseSBTdG9jayBQcmljZXMuIFRoZSBmb3VyIGxpbmVzIHN0aWNrIHRvZ2V0aGVyIHdpdGggbGl0dGxlIHZhcmlhdGlvbiB1bnRpbCBlYXJseSAyMDIwLCB3aGljaCBpcyB3aGVuIHdlIGJlZ2luIHRvIHNlZSBhIGxvdCBtb3JlIGZsdWN0dWF0aW9uIGluIHByaWNlIGJ1dCBpbiBnZW5lcmFsIHRoZXJlIGlzIHN0ZWVwIGluY3JlYXNlIGluIHN0b2NrIHByaWNlLiBXZSBjYW4gZXhhbWluZSB0aGUgQ2xvc2luZyBTdG9jayBQcmljZSB0byBnZXQgYSBjbGVhcmVyIGlkZWEgb2YgdGhpcyBiZWhhdmlvci4KCgojIyBDbG9zaW5nIFN0b2NrIFByaWNlCmBgYHtyfQojUGxvdHRpbmcgdGhlIENsb3NpbmcgU3RvY2sgUHJpY2Ugb3ZlciB0aGUgbGFzdCA1IHllYXJzCmdncGxvdCh0ZXNsYSwgYWVzKHg9RGF0ZSwgeT1DbG9zZS5MYXN0ICkpICsgCiAgZ2VvbV9saW5lKCkgKyAKICBsYWJzKHRpdGxlPSJUZXNsYSBDbG9zaW5nIFN0b2NrIFByaWNlIE92ZXIgdGhlIExhc3QgNSBZZWFycyIsIHg9IlllYXIiLCB5PSJUZXNsYSBDbG9zaW5nIFN0b2NrIFByaWNlICgkKSIpICsKICBzY2FsZV94X2RhdGUoZGF0ZV9taW5vcl9icmVha3MgPSAiMSBtb250aCIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLCBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLCBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSkpCmBgYAoKQXMgc2VlbiBwcmV2aW91c2x5IGFib3ZlIHRoZXJlIGlzIGEgc3RlZXAgcmlzZSBpbiB0aGUgVGVzbGEgU3RvY2sgUHJpY2Ugc2luY2UgZWFybHkgMjAyMC4gTGV0cyB0YWtlIGEgY2xvc2VyIGxvb2sgYXQgdGhlIHN0b2NrIHByaWNlIGR1cmluZyB0aGlzIHRpbWUuCgojIyMgQ2xvc2luZyBTdG9jayBQcmljZSBzaW5jZSBKYW4gMjAyMApgYGB7cn0KI1Bsb3R0aW5nIHRoZSBTdG9jayBQcmljZSBzaW5jZSBiZWdpbm5pbmcgb2YgSmFuIDIwMjAgb253YXJkcwpnZ3Bsb3QodGVzbGEsIGFlcyh4PURhdGUsIHk9Q2xvc2UuTGFzdCApKSArIAogIGdlb21fbGluZSgpICsgCiAgbGFicyh0aXRsZT0iVGVzbGEgQ2xvc2luZyBTdG9jayBQcmljZSBpbiAyMDIwIiwgeD0iTW9udGgiLCB5PSJUZXNsYSBDbG9zaW5nIFN0b2NrIFByaWNlICgkKSIpICsKICBzY2FsZV94X2RhdGUoZGF0ZV9icmVha3MgPSAiMSBtb250aCIsIGRhdGVfbGFiZWxzID0gIiViIiwgbGltaXQ9Yyhhcy5EYXRlKCIyMDIwLTAxLTAxIiksYXMuRGF0ZSgiMjAyMS0wOS0yMyIpKSkgKwogIHlsaW0oMCw5MDApICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLCBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLCBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSkpCmBgYAoKClRoZSBzdG9jayBwcmljZSBoYXMgY29udGludWVkIHRvIGluY3JlYXNlIHNpZ25pZmljYW50bHkgc2luY2UgSmFuIDIwMjAsIHJlYWNoaW5nIGEgcGVhayBhcm91bmQgRmViIDIwMjEuIAoKYGBge3J9CiNUaGUgbW9zdCByZWNlbnQgc3RvY2sgcHJpY2UKcmVjZW50X3N0b2NrIDwtIHRlc2xhICU+JSBmaWx0ZXIoRGF0ZSA9PSBtYXgodGVzbGEkRGF0ZSkpCgojU3RvY2sgcHJpY2UgYXQgdGhlIGJlZ2lubmluZyBvZiAyMDIwCiNOb3RlOiBObyBkYXRhIGZvciBkYXRlIDIwMjAtMDEtMDEKc3RvY2tfc3RhcnRfMjAyMCA8LSB0ZXNsYSAlPiUgZmlsdGVyKERhdGUgPT0gYXMuRGF0ZSgiMjAyMC0wMS0wMiIpKQoKI1N0b2NrIHByaWNlIGF0IHRoZSBlbmQgb2YgMjAyMApzdG9ja19lbmRfMjAyMCA8LSB0ZXNsYSAlPiUgZmlsdGVyKERhdGUgPT0gYXMuRGF0ZSgiMjAyMC0xMi0zMSIpKQoKI0NhbGN1bGF0aW5nIHRoZSBwZXJjZW50YWdlIGluY3JlYXNlIHNpbmNlIHRoZSBzdGFydCBvZiAyMDIwIGFuZCB0aGUgbW9zdCByZWNlbnQgZGF0ZSAKcGN0X3JlY2VudCA9IHJvdW5kKCgoKHJlY2VudF9zdG9jayRDbG9zZS5MYXN0LXN0b2NrX3N0YXJ0XzIwMjAkQ2xvc2UuTGFzdCkvc3RvY2tfc3RhcnRfMjAyMCRDbG9zZS5MYXN0KSoxMDApLDApIAoKI0NhbGN1bGF0aW5nIHRoZSBwZXJjZW50YWdlIGluY3JlYXNlIGJldHdlZW4gdGhlIHN0YXJ0IGFuZCBlbmQgb2YgMjAyMCAKcGN0XzIwMjAgPSByb3VuZCgoKChzdG9ja19lbmRfMjAyMCRDbG9zZS5MYXN0LXN0b2NrX3N0YXJ0XzIwMjAkQ2xvc2UuTGFzdCkvc3RvY2tfc3RhcnRfMjAyMCRDbG9zZS5MYXN0KSoxMDApLDApIAoKY2F0KCJUaGUgc3RvY2sgcHJpY2UgaW5jcmVhc2U6IFxuIEphbiAyMDIwLVByZXNlbnQ6IixwY3RfcmVjZW50LCIlIFxuIEphbiAyMDIwIC0gRGVjIDIwMjAgRW5kOiIscGN0XzIwMjAsIiUiKSAKCmBgYApUaGUgc3RvY2sgcHJpY2UgaGFzIGluY3JlYXNlZCA8Yj43NzYlPC9iPiBiZXR3ZWVuIHRoZSBiZWdpbm5pbmcgb2YgMjAyMCBhbmQgdGhlIHByZXNlbnQuIEluIGZhY3QsIGl0IGluY3JlYXNlZCBieSA8Yj43MjAlPC9iPiBqdXN0IGluIDIwMjAgYWxvbmUuCgojIyBNb3ZpbmcgQXZlcmFnZQpgYGB7cn0KI1Bsb3R0aW5nIHRoZSBDbG9zaW5nIFN0b2NrIHByaWNlIHZzIHRoZSA3IERheSBNb3ZpbmcgQXZlcmFnZQpnZ3Bsb3QodGVzbGEsIGFlcyh4PURhdGUpKSArIAogIGdlb21fbGluZShhZXMoeSA9IENsb3NlLkxhc3QsIGNvbG91cj0iQ2xvc2UgUHJpY2UiKSkgKyAKICBnZW9tX2xpbmUoYWVzKHkgPSAgTW92aW5nX0F2ZXJhZ2VfN19EYXksIGNvbG91cj0iNyBEYXkiKSkgKwogIGxhYnModGl0bGU9IlRlc2xhIFN0b2NrIFByaWNlIHZzLiA3IERheSBNb3ZpbmcgQXZlcmFnZSIsIHg9IlllYXIiLCB5PSJUZXNsYSBTdG9jayBQcmljZSAoJCkiLCBjb2xvdXIgPSAiUHJpY2UgJiBNb3ZpbmcgQXZlcmFnZSIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCJ0YW4zIikpICsKICBzY2FsZV94X2RhdGUoZGF0ZV9taW5vcl9icmVha3MgPSAiMSBtb250aCIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLCBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLCBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSkpCmBgYAoKYGBge3J9CiNQbG90dGluZyB0aGUgQ2xvc2luZyBTdG9jayBwcmljZSB2cyB0aGUgMzAgRGF5IE1vdmluZyBBdmVyYWdlCmdncGxvdCh0ZXNsYSwgYWVzKHg9RGF0ZSkpICsgCiAgZ2VvbV9saW5lKGFlcyh5ID0gQ2xvc2UuTGFzdCwgY29sb3VyPSJDbG9zZSBQcmljZSIpKSArIAogIGdlb21fbGluZShhZXMoeSA9ICBNb3ZpbmdfQXZlcmFnZV8zMF9EYXksIGNvbG91cj0iMzAgRGF5IikpICsKICBsYWJzKHRpdGxlPSJUZXNsYSBTdG9jayBQcmljZSB2cy4gMzAgRGF5IE1vdmluZyBBdmVyYWdlIiwgeD0iWWVhciIsIHk9IlRlc2xhIFN0b2NrIFByaWNlICgkKSIsIGNvbG91ciA9ICJQcmljZSAmIE1vdmluZyBBdmVyYWdlIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIm9yYW5nZSIpKSArCiAgc2NhbGVfeF9kYXRlKGRhdGVfbWlub3JfYnJlYWtzID0gIjEgbW9udGgiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpKQpgYGAKClRoZSAzMCBEYXkgTW92aW5nIEF2ZXJhZ2UgZ2l2ZXMgdXMgYSBtdWNoIHNtb290aGVyIGN1cnZlIHRoYW4gdGhlIDcgRGF5IE1vdmluZyBBdmVyYWdlLiBUaGVyZWZvcmUsIHVzaW5nIHRoZSAzMCBEYXkgTW92aW5nIEF2ZXJhZ2Ugd2UgY2FuIGNsZWFybHkgc2VlIHRoZSBwb2ludHMgd2hlcmUgdGhlIHN0b2NrIHByaWNlIGRldmlhdGVkIG5vdGljZWFibHkgZnJvbSB0aGUgcHJlZGljdGVkIHByaWNlLiBUaGUgc3RvY2sgcHJpY2UgZmx1Y3R1YXRpb25zIHNlZW0gdG8gYmUgbW9zdCBzaWduaWZpY2FudCBpbiB0aGUgcGVyaW9kIGFmdGVyIGVhcmx5IDIwMjAsIHdoaWNoIGNvcnJlbGF0ZXMgd2l0aCBvdXIgZWFybGllciBvYnNlcnZhdGlvbi4gCgojIyBTdG9jayBUcmFkaW5nIFZvbHVtZQpgYGB7cn0KI1Bsb3R0aW5nIHRoZSBDbG9zaW5nIFN0b2NrIFByaWNlIG92ZXIgdGhlIGxhc3QgNSB5ZWFycwpnZ3Bsb3QodGVzbGEsIGFlcyh4PURhdGUsIHk9Vm9sdW1lLCBjb2xvciA9Im9yYW5nZSIpKSArIAogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9saW5lKGFlcyh5ID0gIDQ1MDAwMDAwLCBjb2xvcj0icmVkIikpICsKICBsYWJzKHRpdGxlPSJUZXNsYSBTdG9jayBUcmFkaW5nIFZvbHVtZSBPdmVyIHRoZSBMYXN0IDUgWWVhcnMiLCB4PSJZZWFyIiwgeT0iTnVtYmVyIG9mIFN0b2NrcyBUcmFkZWQiKSArCiAgc2NhbGVfeF9kYXRlKGRhdGVfbWlub3JfYnJlYWtzID0gIjEgbW9udGgiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgCmBgYAoKVGhlIHZvbHVtZSBvZiBzdG9ja3MgdHJhZGVkIGhhcyBnZW5lcmFsbHkgcmVtYWluZWQgYXJvdW5kIG9yIGJlZW4gdW5kZXIgdGhlIGF2ZXJhZ2Ugb2YgNDUgbWlsbGlvbiAoaW5kaWNhdGVkIGJ5IHRoZSBsaW5lKSwgaG93ZXZlciB0aGVyZSBpcyBhbiBpbmNyZWFzZSBpbiB2b2x1bWUgZHVyaW5nIHRoZSB5ZWFyIDIwMjAsIHRob3VnaCB0aGUgaXQgZG9lcyBzZWVtIHRvIGJlIGdldHRpbmcgYmFjayB0byBub3JtYWwgc2luY2UgdGhlIGJlZ2lubmluZyBvZiAyMDIxLgoKIyBTdW1tYXJ5IG9mIERhdGEgQW5hbHlzaXMKCi0gT2xkZXN0IGRhdGEgcG9pbnQgaXMgZnJvbSA8Yj4yMDE2LTExLTA3PC9iPiBhbmQgdGhlIG1vc3QgcmVjZW50IGRhdGEgcG9pbnQgaXMgZnJvbSA8Yj4yMDIxLTA5LTIzPC9iPi4gCi0gSGlnaGVzdCBDbG9zaW5nIFN0b2NrIFByaWNlIHdhcyA8Yj4kODgzLjA5PC9iPiwgd2hpbGUgdGhlIGxvd2VzdCBDbG9zaW5nIFN0b2NrIFByaWNlIDxiPiQzNS43OTwvYj4uCi0gSGlnaGVzdCBPcGVuaW5nIFN0b2NrIFByaWNlIHdhcyA8Yj4kODkxLjM4PC9iPiwgd2hpbGUgdGhlIGxvd2VzdCBPcGVuaW5nIFN0b2NrIFByaWNlIDxiPiQzNi4yMjwvYj4uCi0gVGhlIEhpZ2hlc3QgU3RvY2sgUHJpY2Ugb3ZlciB0aGUgcGFzdCA1IHllYXJzIHdhcyA8Yj4kOTAwLjQwPC9iPi4KLSBUaGUgTG93ZXN0IFN0b2NrIFByaWNlIG92ZXIgdGhlIHBhc3QgNSB5ZWFycyB3YXMgPGI+JDM1LjQwPC9iPi4KLSBUaGUgVm9sdW1lIG9mIFN0b2NrcyB0cmFkZWQgYXZlcmFnZWQgYXJvdW5kIDxiPjQ1IG1pbGxpb248L2I+IHdpdGggYSBtYXhpbXVtIG9mIGFyb3VuZCA8Yj4zMDQgbWlsbGlvbjwvYj4uICAKClRoZSBUZXNsYSBTdG9jayBQcmljZSBoYXMgaW5jcmVhc2Ugc2lnbmlmaWNhbnRseSBzaW5jZSAyMDE2LiBUaGUgc3RvY2sgcHJpY2UgcmVtYWluZWQgcmVsYXRpdmVseSBzdGVhZHkgdW50aWwgZWFybHkgMjAyMCB3aGVuIGl0IGJlZ2FuIHRvIHJpc2UgZHJhc3RpY2FsbHkuIFRoZSBzdG9jayBwcmljZSBoYXMgaW5jcmVhc2VkIDxiPjc3NiU8L2I+IGJldHdlZW4gdGhlIGJlZ2lubmluZyBvZiAyMDIwIGFuZCB0aGUgcHJlc2VudC4gSW4gZmFjdCwgaXQgaW5jcmVhc2VkIGJ5IDxiPjcyMCU8L2I+IGp1c3QgaW4gMjAyMCBhbG9uZS4gV2hpbGUgdGhlIHN0b2NrIHByaWNlIHJlYWNoZXMgaXRzIHBlYWsgYXJvdW5kIDxiPkZlYiAyMDIxPC9iPiwgaXQgaGFzIGNvbnRpbnVlZCBpdHMgZ2VuZXJhbCB1cHdhcmQgdHJlbmQuIEhvd2V2ZXIsIGR1cmluZyB0aGUgcGVyaW9kIG9mIHByaWNlIGluY3JlYXNlIHRoZSBEYWlseSBzdG9jayBwcmljZSB3b3VsZCBmbHVjdHVhdGUgc2lnbmlmaWNhbnRseSBjb21wYXJlZCB0byBpdHMgcmVsYXRpdmVseSBzdGFibGUgcHJpY2UgcHJpb3IgdG8gMjAyMC4gCgpUaGUgdm9sdW1lIG9mIHN0b2NrcyB0cmFkZWQgZHVyaW5nIHRoZSBsYXN0IDUgeWVhcnMgaGFzIGdlbmVyYWxseSByZW1haW5lZCBhcm91bmQgb3IgYmVlbiB1bmRlciB0aGUgYXZlcmFnZSBvZiA0NSBtaWxsaW9uLCBob3dldmVyIHRoZXJlIGlzIGFuIGluY3JlYXNlIGluIHZvbHVtZSBkdXJpbmcgdGhlIHllYXIgMjAyMCwgd2hpY2ggY29ycmVzcG9uZHMgdG8gdGhlIHN0ZWVwIGluY3JlYXNlIGluIHN0b2NrIHByaWNlLiBXZSB3b3VsZCB0eXBpY2FsbHkgZXhwZWN0IGFuIGluY3JlYXNlIGluIHRyYWRpbmcgYWN0aXZpdHkgbGlrZSB0aGlzIGR1cmluZyBhIHBlcmlvZCB3aGVuIHRoZSBjb21wYW55J3Mgc3RvY2tzIGFyZSByYXBpZGx5IHJpc2luZy4gCgo=