Task is to perform a time series analysis for a stock price. Selecting a stock price and completing different tasks

Selected stock price: Netflix (NFLX)

Netflix is one of the world’s leading entertainment services with over 238 million paid memberships in over 190 countries enjoying TV series, films and games across a wide variety of genres and languages. Members can play, pause and resume watching as much as they want, anytime, anywhere, and can change their plans at any time”. (Netflix - Overview - Profile, 2018)

library(plotly)
library(xts)
library(dplyr)
library(zoo)
library(tseries)
library(stats)
library(forecast)
library(astsa)
library(corrplot)
library(AER)
library(vars)
library(dynlm)
library(vars)
library(TSstudio)
library(tidyverse)
library(sarima)
library(dygraphs)
Netflix <- read.csv("C:\\Users\\danyb\\OneDrive - Instituto Tecnologico y de Estudios Superiores de Monterrey\\Docs\\Documentos\\Business Intelligence\\Quinto Semestre\\Introduction to Econometrics\\Examen\\entretainment_stocks.csv")

Before analyze

str(Netflix)
## 'data.frame':    192 obs. of  7 variables:
##  $ Date               : chr  "1/1/2007" "2/1/2007" "3/1/2007" "4/1/2007" ...
##  $ Disney_Adj_Close   : num  29.1 28.4 28.5 29 29.3 ...
##  $ Netflix_Adj_Close  : num  3.26 3.22 3.31 3.17 3.13 2.77 2.46 2.5 2.96 3.78 ...
##  $ Nintendo_Adj_Close : num  37.1 33.1 36.3 40 43.6 ...
##  $ WBD_Adj_Close      : num  8.47 8.21 9.78 11.11 11.95 ...
##  $ EA_Adj_Close       : num  49.5 49.9 49.8 49.9 48.4 ...
##  $ Paramount_Adj_Close: num  22.1 21.5 21.6 22.6 23.7 ...

Column “Date” from dataset is on chr type, in order to graph time series, it needs to be date type.

Netflix$Date <- as.Date(Netflix$Date,"%m/%d/%Y")
str(Netflix)
## 'data.frame':    192 obs. of  7 variables:
##  $ Date               : Date, format: "2007-01-01" "2007-02-01" ...
##  $ Disney_Adj_Close   : num  29.1 28.4 28.5 29 29.3 ...
##  $ Netflix_Adj_Close  : num  3.26 3.22 3.31 3.17 3.13 2.77 2.46 2.5 2.96 3.78 ...
##  $ Nintendo_Adj_Close : num  37.1 33.1 36.3 40 43.6 ...
##  $ WBD_Adj_Close      : num  8.47 8.21 9.78 11.11 11.95 ...
##  $ EA_Adj_Close       : num  49.5 49.9 49.8 49.9 48.4 ...
##  $ Paramount_Adj_Close: num  22.1 21.5 21.6 22.6 23.7 ...
colSums(is.na(Netflix))
##                Date    Disney_Adj_Close   Netflix_Adj_Close  Nintendo_Adj_Close 
##                   0                   0                   0                   0 
##       WBD_Adj_Close        EA_Adj_Close Paramount_Adj_Close 
##                   0                   0                   0

There are no missing values on the dataset.

A) Visualization

Plot the stock price / variable using a time series format.

In order to get an interactive time series graph, it will be necessary to use “plot_ly”

plot_ly(data = Netflix, x = ~Date, y = ~Netflix_Adj_Close, type = "scatter", mode = "lines") %>%
  layout(title = "Netflix Stock Price",
         xaxis = list(title = "Date"),
         yaxis = list(title = "Netflix Adj Close")) %>%
  add_trace(text = ~paste("Adj Close: $", Netflix_Adj_Close, "Date:", Date),
            hoverinfo = "text")

In summary, there is a clear upward trend in Netflix’s stock price. The first significant increase took place in 2018, but the most notable one occurred in 2020, with consistent growth reaching its highest point in October 2021. However, it experienced a steep drop afterward, going from $690.31 USD to $174.87 in April 2022.

Decompose the time series data in observed, trend, seasonality, and random

NFLXts<-ts(Netflix$Netflix_Adj_Close,start=c(2007,1),end=c(2022,12),frequency=12)
Netdec<-decompose(NFLXts)
plot(Netdec)

i. Do the time series data show a trend?

Yes they do. It is possible to see a positive trend for this time series data.

ii. Do the time series data show seasonality? How is the change of the seasonal component over time?

The seasonal component exhibits a consistent pattern over time, indicating the presence of seasonality. Furthermore, there is no observable variation or changes in this component as time progresses.

Contribution

It’s interesting to observe the random factor in this time series. Initially, this factor remains fairly stable, but then it starts to fluctuate around the year 2017. Additionally, there is a noticeable spike, possibly in the year 2022, which coincides with Netflix’s most significant downturn. Upon further investigation, it was possible to found information about that year, such as the price increase in Netflix plans, increased competition in the market, Netflix’s exit from Russia, and its measures against password sharing.

B) Estimation

Detect if the time series data is stationary.

# Stationary Test 
adf.test(Netflix$Netflix_Adj_Close)
## 
##  Augmented Dickey-Fuller Test
## 
## data:  Netflix$Netflix_Adj_Close
## Dickey-Fuller = -2.9019, Lag order = 5, p-value = 0.1987
## alternative hypothesis: stationary
### H0: Non-stationary and HA: Stationary.  
### The P-Value is higher than 0.05 so it fails to Reject the H0. Time series data is non-stationary.
plot(Netflix$Netflix_Adj_Close,type="l",ylab="Original Price Stock",main = "Netflix Stock Price")

Considering the p-value of 0.1987 obtained in the ADF test for this time series, we fail to reject H0, which suggests that the time series is non-stationary. It can be confirmed by seeing the graph.

Detect if the time series data shows serial autocorrelation.

# Serial Autocorrelation
# ACF plots: correlation between two periods in a time series is referred as autocorrelation function (acf)
acf(Netflix$Netflix_Adj_Close,main="Significant Autocorrelations")  # Generally, non-stationary time series data show the presence of serial autocorrelation.  

The graph suggest that there is a significant autocorrelation in the variable of the model, giving as a result that one period have a significant impact for the next period behavior, which can become a problem when estimating a model. It may not be adequately capturing the structure of the time series.

Estimate 2 different time series regression models.

1. ARMA transforming to diff and log

summary(NET_ARMA<-arma(diff(log(Netflix$Netflix_Adj_Close)),order=c(1,1)))
## 
## Call:
## arma(x = diff(log(Netflix$Netflix_Adj_Close)), order = c(1, 1))
## 
## Model:
## ARMA(1,1)
## 
## Residuals:
##       Min        1Q    Median        3Q       Max 
## -0.733068 -0.077751  0.006555  0.077652  0.539031 
## 
## Coefficient(s):
##            Estimate  Std. Error  t value Pr(>|t|)
## ar1         0.36348     0.34178    1.063    0.288
## ma1        -0.22747     0.35478   -0.641    0.521
## intercept   0.01518     0.01175    1.292    0.196
## 
## Fit:
## sigma^2 estimated as 0.02369,  Conditional Sum-of-Squares = 4.48,  AIC = -166.81

2. ARIMA transforming to diff and log

NET_ARIMA <- Arima(diff(log(Netflix$Netflix_Adj_Close)),order=c(1,1,1))
summary(NET_ARIMA)
## Series: diff(log(Netflix$Netflix_Adj_Close)) 
## ARIMA(1,1,1) 
## 
## Coefficients:
##          ar1      ma1
##       0.1438  -1.0000
## s.e.  0.0719   0.0217
## 
## sigma^2 = 0.02387:  log likelihood = 83.78
## AIC=-161.55   AICc=-161.42   BIC=-151.81
## 
## Training set error measures:
##                        ME      RMSE       MAE  MPE MAPE      MASE        ACF1
## Training set -0.002676514 0.1532704 0.1071805 -Inf  Inf 0.6820546 -0.01191508

C) Evaluation

Comparing and selecting model using diagnostic tests.

ARMA

# model evaluation 
# Testing serial autocorrelation in regression residuals 
# Ho: There is no serial autocorrelation 
# Ha: There is serial autocorrelation
NET_ARMA_R<-NET_ARMA$residuals
Box.test(NET_ARMA_R,lag=1,type="Ljung-Box")  
## 
##  Box-Ljung test
## 
## data:  NET_ARMA_R
## X-squared = 0.0027965, df = 1, p-value = 0.9578
# Accept the Ho. The P-value is > 0.05 indicating that ARMA model does not show residual serial autocorrelation. 

Having a p-value of 0.9578 (>0.05), we fail to reject H0, indicating that this ARMA model does not show residual serial autocorrelation in its residuals, and they behave independently.

#When estimating this ARMA model, first value is null, so we need to omit it.
NET_ARMA$fitted.values <- na.omit(NET_ARMA$fitted.values)
NET_ARMA$residuals <- na.omit(NET_ARMA$residuals)
#Testing residuals
adf.test(NET_ARMA$residuals)
## Warning in adf.test(NET_ARMA$residuals): p-value smaller than printed p-value
## 
##  Augmented Dickey-Fuller Test
## 
## data:  NET_ARMA$residuals
## Dickey-Fuller = -6.3544, Lag order = 5, p-value = 0.01
## alternative hypothesis: stationary

For ADF residuals, p-value is lower than 0.05, so we fail to reject H0, and it can be concluded that residuals are stationary.

hist(NET_ARMA$residuals)

It follows a normal distribution,

#testing values
adf.test(NET_ARMA$fitted.values)
## Warning in adf.test(NET_ARMA$fitted.values): p-value smaller than printed
## p-value
## 
##  Augmented Dickey-Fuller Test
## 
## data:  NET_ARMA$fitted.values
## Dickey-Fuller = -5.7383, Lag order = 5, p-value = 0.01
## alternative hypothesis: stationary

We got a p-value of 0.01, failing to reject H0, which means that there is an stationary time series data.

plot(diff(log(Netflix$Netflix_Adj_Close)),type="l",ylab="diff Price Stock",main = "Netflix Stock Price")

We got stationary time series data by correctly transforming them to diff and log.

ARIMA

# model evaluation 
# Testing serial autocorrelation in regression residuals 
# Ho: There is no serial autocorrelation 
# Ha: There is serial autocorrelation
NET_ARIMA_R<-NET_ARIMA$residuals
Box.test(NET_ARIMA_R,lag=1,type="Ljung-Box")  
## 
##  Box-Ljung test
## 
## data:  NET_ARIMA_R
## X-squared = 0.027544, df = 1, p-value = 0.8682
# Accept the Ho. The P-value is > 0.05 indicating that ARMA model does not show residual serial autocorrelation. 

Having a p-value of 0.8682 (>0.05), we fail to reject H0, indicating that this ARMA model does not show residual serial autocorrelation in its residuals, and they behave independently.

#Testing residuals.
adf.test(NET_ARIMA$residuals)
## Warning in adf.test(NET_ARIMA$residuals): p-value smaller than printed p-value
## 
##  Augmented Dickey-Fuller Test
## 
## data:  NET_ARIMA$residuals
## Dickey-Fuller = -6.2735, Lag order = 5, p-value = 0.01
## alternative hypothesis: stationary

For ADF residuals in ARIMA, p-value is lower than 0.05, so we fail to reject H0, and it can be concluded that residuals are stationary.

#Testing values
adf.test(NET_ARIMA$fitted)
## Warning in adf.test(NET_ARIMA$fitted): p-value smaller than printed p-value
## 
##  Augmented Dickey-Fuller Test
## 
## data:  NET_ARIMA$fitted
## Dickey-Fuller = -5.1742, Lag order = 5, p-value = 0.01
## alternative hypothesis: stationary

We got a p-value of 0.01, failing to reject H0, which means that there is an stationary time series data.

Selection

It can be observed that both models ARMA and ARIMA have good test values to be taken into account. However, ARMA model has a lower AIC value, and a higher value for “Ljung_Box Test”, this is why we are gonna select this model.

acf(NET_ARMA$fitted.values,main="Significant Autocorrelations")

This model also helps to eliminate serial autocorrelation.

D) Forecast

Forecast for the next 5 periods.

For the next part, it will be necessary to transform the fitted.values of the model into its original form, reversing log and first ordering difference.

We need to convert these values into a vector “c” due the different length between fitted.values and the original ones, that we will be needing it to reverse the “diff” transformation. Having this time series as vector allows to sum them up, despite of length difference. Finally, we are going to convert them into time series again, in order to make a forecast.

fv_exp<-c(exp(NET_ARMA$fitted.values)) #reverting "log" operation using "exp"
IBv<-c(Netflix$Netflix_Adj_Close) #Converting the original values into a vector.
Fixed_Values<-fv_exp+IBv #reverting "diff" operation summing the original values to the differences.
## Warning in fv_exp + IBv: longitud de objeto mayor no es múltiplo de la longitud
## de uno menor
ts_Fixed_Values <- ts(Fixed_Values, start = 1, end = length(Fixed_Values), frequency = 1) #Make it time series

Now it is possible to make the forecast correctly

NStock_forecast<-forecast(ts_Fixed_Values,h=5) #h=5 for 5 periods.
NStock_forecast
##     Point Forecast    Lo 80    Hi 80    Lo 95    Hi 95
## 193       296.1937 240.2485 352.1388 210.6329 381.7544
## 194       296.4846 216.8991 376.0702 174.7690 418.2002
## 195       296.7756 198.7233 394.8279 146.8175 446.7337
## 196       297.0666 183.1687 410.9644 122.8748 471.2583
## 197       297.3575 169.2521 425.4629 101.4372 493.2778

When generating a forecast with this model, we can obtain an estimate of what the stock price for the next 5 periods could be. Taking into account a 95% confidence level, these values would be as follows:

  • Period 1: Price between $210.63 and $381.75
  • Period 2: Price between $174.77 and $418.20
  • Period 3: Price between $146.82 and $446.73
  • Period 4: Price between $122.87 and $471.26
  • Period 5: Price between $101.44 and $493.28

Pointed values for this forecast are:

  • Period 1: Price of $296.19
  • Period 2: Price of $296.48
  • Period 3: Price of $296.78
  • Period 4: Price of $297.07
  • Period 5: Price of $296.36

The graphs for this forecast are plotted below.

plot(NStock_forecast)

autoplot(NStock_forecast)

References Netflix - Overview - Profile. (2018). Netflix.net. https://ir.netflix.net/ir-overview/profile/default.aspx

LS0tDQp0aXRsZTogIkV4YW0gcGFydCAzIg0KYXV0aG9yOiAiSmVzw7pzIERhbmllbCBGYXLDrWFzIEJ1c3RhbWFudGUiDQpkYXRlOiAiMjAyMy0wOS0wOCINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogICAgY29kZV9kb3dubG9hZDogeWVzDQotLS0NCg0KDQpUYXNrIGlzIHRvIHBlcmZvcm0gYSB0aW1lIHNlcmllcyBhbmFseXNpcyBmb3IgYSBzdG9jayBwcmljZS4gU2VsZWN0aW5nIGEgc3RvY2sgcHJpY2UgYW5kIGNvbXBsZXRpbmcgZGlmZmVyZW50IHRhc2tzDQoNClNlbGVjdGVkIHN0b2NrIHByaWNlOiAqKk5ldGZsaXggKE5GTFgpKioNCg0KKk5ldGZsaXggaXMgb25lIG9mIHRoZSB3b3JsZCdzIGxlYWRpbmcgZW50ZXJ0YWlubWVudCBzZXJ2aWNlcyB3aXRoIG92ZXIgMjM4IG1pbGxpb24gcGFpZCBtZW1iZXJzaGlwcyBpbiBvdmVyIDE5MCBjb3VudHJpZXMgZW5qb3lpbmcgVFYgc2VyaWVzLCBmaWxtcyBhbmQgZ2FtZXMgYWNyb3NzIGEgd2lkZSB2YXJpZXR5IG9mIGdlbnJlcyBhbmQgbGFuZ3VhZ2VzLiBNZW1iZXJzIGNhbiBwbGF5LCBwYXVzZSBhbmQgcmVzdW1lIHdhdGNoaW5nIGFzIG11Y2ggYXMgdGhleSB3YW50LCBhbnl0aW1lLCBhbnl3aGVyZSwgYW5kIGNhbiBjaGFuZ2UgdGhlaXIgcGxhbnMgYXQgYW55IHRpbWUiLioNCihOZXRmbGl4IC0gT3ZlcnZpZXcgLSBQcm9maWxlLCAyMDE4KQ0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRX0NCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeSh4dHMpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh6b28pDQpsaWJyYXJ5KHRzZXJpZXMpDQpsaWJyYXJ5KHN0YXRzKQ0KbGlicmFyeShmb3JlY2FzdCkNCmxpYnJhcnkoYXN0c2EpDQpsaWJyYXJ5KGNvcnJwbG90KQ0KbGlicmFyeShBRVIpDQpsaWJyYXJ5KHZhcnMpDQpsaWJyYXJ5KGR5bmxtKQ0KbGlicmFyeSh2YXJzKQ0KbGlicmFyeShUU3N0dWRpbykNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShzYXJpbWEpDQpsaWJyYXJ5KGR5Z3JhcGhzKQ0KYGBgDQoNCmBgYHtyfQ0KTmV0ZmxpeCA8LSByZWFkLmNzdigiQzpcXFVzZXJzXFxkYW55YlxcT25lRHJpdmUgLSBJbnN0aXR1dG8gVGVjbm9sb2dpY28geSBkZSBFc3R1ZGlvcyBTdXBlcmlvcmVzIGRlIE1vbnRlcnJleVxcRG9jc1xcRG9jdW1lbnRvc1xcQnVzaW5lc3MgSW50ZWxsaWdlbmNlXFxRdWludG8gU2VtZXN0cmVcXEludHJvZHVjdGlvbiB0byBFY29ub21ldHJpY3NcXEV4YW1lblxcZW50cmV0YWlubWVudF9zdG9ja3MuY3N2IikNCmBgYA0KDQoNCg0KKipCZWZvcmUgYW5hbHl6ZSoqDQpgYGB7cn0NCnN0cihOZXRmbGl4KQ0KYGBgDQoNCkNvbHVtbiAiRGF0ZSIgZnJvbSBkYXRhc2V0IGlzIG9uIGNociB0eXBlLCBpbiBvcmRlciB0byBncmFwaCB0aW1lIHNlcmllcywgaXQgbmVlZHMgdG8gYmUgZGF0ZSB0eXBlLg0KDQoNCmBgYHtyfQ0KTmV0ZmxpeCREYXRlIDwtIGFzLkRhdGUoTmV0ZmxpeCREYXRlLCIlbS8lZC8lWSIpDQpzdHIoTmV0ZmxpeCkNCmBgYA0KDQpgYGB7cn0NCmNvbFN1bXMoaXMubmEoTmV0ZmxpeCkpDQpgYGANClRoZXJlIGFyZSBubyBtaXNzaW5nIHZhbHVlcyBvbiB0aGUgZGF0YXNldC4NCg0KIyAqKkEpIFZpc3VhbGl6YXRpb24qKg0KDQoNCiMjIFBsb3QgdGhlIHN0b2NrIHByaWNlIC8gdmFyaWFibGUgdXNpbmcgYSB0aW1lIHNlcmllcyBmb3JtYXQuDQoNCg0KSW4gb3JkZXIgdG8gZ2V0IGFuIGludGVyYWN0aXZlIHRpbWUgc2VyaWVzIGdyYXBoLCBpdCB3aWxsIGJlIG5lY2Vzc2FyeSB0byB1c2UgInBsb3RfbHkiDQpgYGB7cn0NCnBsb3RfbHkoZGF0YSA9IE5ldGZsaXgsIHggPSB+RGF0ZSwgeSA9IH5OZXRmbGl4X0Fkal9DbG9zZSwgdHlwZSA9ICJzY2F0dGVyIiwgbW9kZSA9ICJsaW5lcyIpICU+JQ0KICBsYXlvdXQodGl0bGUgPSAiTmV0ZmxpeCBTdG9jayBQcmljZSIsDQogICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiRGF0ZSIpLA0KICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIk5ldGZsaXggQWRqIENsb3NlIikpICU+JQ0KICBhZGRfdHJhY2UodGV4dCA9IH5wYXN0ZSgiQWRqIENsb3NlOiAkIiwgTmV0ZmxpeF9BZGpfQ2xvc2UsICJEYXRlOiIsIERhdGUpLA0KICAgICAgICAgICAgaG92ZXJpbmZvID0gInRleHQiKQ0KYGBgDQoNCkluIHN1bW1hcnksIHRoZXJlIGlzIGEgY2xlYXIgdXB3YXJkIHRyZW5kIGluIE5ldGZsaXgncyBzdG9jayBwcmljZS4gVGhlIGZpcnN0IHNpZ25pZmljYW50IGluY3JlYXNlIHRvb2sgcGxhY2UgaW4gMjAxOCwgYnV0IHRoZSBtb3N0IG5vdGFibGUgb25lIG9jY3VycmVkIGluIDIwMjAsIHdpdGggY29uc2lzdGVudCBncm93dGggcmVhY2hpbmcgaXRzIGhpZ2hlc3QgcG9pbnQgaW4gT2N0b2JlciAyMDIxLiBIb3dldmVyLCBpdCBleHBlcmllbmNlZCBhIHN0ZWVwIGRyb3AgYWZ0ZXJ3YXJkLCBnb2luZyBmcm9tICQ2OTAuMzEgVVNEIHRvICQxNzQuODcgaW4gQXByaWwgMjAyMi4NCg0KDQojIyBEZWNvbXBvc2UgdGhlIHRpbWUgc2VyaWVzIGRhdGEgaW4gb2JzZXJ2ZWQsIHRyZW5kLCBzZWFzb25hbGl0eSwgYW5kIHJhbmRvbQ0KDQpgYGB7cn0NCk5GTFh0czwtdHMoTmV0ZmxpeCROZXRmbGl4X0Fkal9DbG9zZSxzdGFydD1jKDIwMDcsMSksZW5kPWMoMjAyMiwxMiksZnJlcXVlbmN5PTEyKQ0KTmV0ZGVjPC1kZWNvbXBvc2UoTkZMWHRzKQ0KcGxvdChOZXRkZWMpDQpgYGANCioqaS4gRG8gdGhlIHRpbWUgc2VyaWVzIGRhdGEgc2hvdyBhIHRyZW5kPyoqDQoNClllcyB0aGV5IGRvLiBJdCBpcyBwb3NzaWJsZSB0byBzZWUgYSBwb3NpdGl2ZSB0cmVuZCBmb3IgdGhpcyB0aW1lIHNlcmllcyBkYXRhLg0KDQoqKmlpLiBEbyB0aGUgdGltZSBzZXJpZXMgZGF0YSBzaG93IHNlYXNvbmFsaXR5PyBIb3cgaXMgdGhlIGNoYW5nZSBvZiB0aGUgc2Vhc29uYWwgY29tcG9uZW50IG92ZXIgdGltZT8qKg0KDQpUaGUgc2Vhc29uYWwgY29tcG9uZW50IGV4aGliaXRzIGEgY29uc2lzdGVudCBwYXR0ZXJuIG92ZXIgdGltZSwgaW5kaWNhdGluZyB0aGUgcHJlc2VuY2Ugb2Ygc2Vhc29uYWxpdHkuIEZ1cnRoZXJtb3JlLCB0aGVyZSBpcyBubyBvYnNlcnZhYmxlIHZhcmlhdGlvbiBvciBjaGFuZ2VzIGluIHRoaXMgY29tcG9uZW50IGFzIHRpbWUgcHJvZ3Jlc3Nlcy4NCg0KIyMjICoqQ29udHJpYnV0aW9uKioNCg0KSXQncyBpbnRlcmVzdGluZyB0byBvYnNlcnZlIHRoZSByYW5kb20gZmFjdG9yIGluIHRoaXMgdGltZSBzZXJpZXMuIEluaXRpYWxseSwgdGhpcyBmYWN0b3IgcmVtYWlucyBmYWlybHkgc3RhYmxlLCBidXQgdGhlbiBpdCBzdGFydHMgdG8gZmx1Y3R1YXRlIGFyb3VuZCB0aGUgeWVhciAyMDE3LiBBZGRpdGlvbmFsbHksIHRoZXJlIGlzIGEgbm90aWNlYWJsZSBzcGlrZSwgcG9zc2libHkgaW4gdGhlIHllYXIgMjAyMiwgd2hpY2ggY29pbmNpZGVzIHdpdGggTmV0ZmxpeCdzIG1vc3Qgc2lnbmlmaWNhbnQgZG93bnR1cm4uIFVwb24gZnVydGhlciBpbnZlc3RpZ2F0aW9uLCBpdCB3YXMgcG9zc2libGUgdG8gZm91bmQgaW5mb3JtYXRpb24gYWJvdXQgdGhhdCB5ZWFyLCBzdWNoIGFzIHRoZSBwcmljZSBpbmNyZWFzZSBpbiBOZXRmbGl4IHBsYW5zLCBpbmNyZWFzZWQgY29tcGV0aXRpb24gaW4gdGhlIG1hcmtldCwgTmV0ZmxpeCdzIGV4aXQgZnJvbSBSdXNzaWEsIGFuZCBpdHMgbWVhc3VyZXMgYWdhaW5zdCBwYXNzd29yZCBzaGFyaW5nLg0KDQoNCiMgKipCKSBFc3RpbWF0aW9uKioNCg0KDQojIyBEZXRlY3QgaWYgdGhlIHRpbWUgc2VyaWVzIGRhdGEgaXMgc3RhdGlvbmFyeS4NCmBgYHtyfQ0KIyBTdGF0aW9uYXJ5IFRlc3QgDQphZGYudGVzdChOZXRmbGl4JE5ldGZsaXhfQWRqX0Nsb3NlKQ0KDQojIyMgSDA6IE5vbi1zdGF0aW9uYXJ5IGFuZCBIQTogU3RhdGlvbmFyeS4gIA0KIyMjIFRoZSBQLVZhbHVlIGlzIGhpZ2hlciB0aGFuIDAuMDUgc28gaXQgZmFpbHMgdG8gUmVqZWN0IHRoZSBIMC4gVGltZSBzZXJpZXMgZGF0YSBpcyBub24tc3RhdGlvbmFyeS4NCmBgYA0KYGBge3J9DQpwbG90KE5ldGZsaXgkTmV0ZmxpeF9BZGpfQ2xvc2UsdHlwZT0ibCIseWxhYj0iT3JpZ2luYWwgUHJpY2UgU3RvY2siLG1haW4gPSAiTmV0ZmxpeCBTdG9jayBQcmljZSIpDQpgYGANCg0KQ29uc2lkZXJpbmcgdGhlIHAtdmFsdWUgb2YgMC4xOTg3IG9idGFpbmVkIGluIHRoZSBBREYgdGVzdCBmb3IgdGhpcyB0aW1lIHNlcmllcywgd2UgZmFpbCB0byByZWplY3QgSDAsIHdoaWNoIHN1Z2dlc3RzIHRoYXQgdGhlIHRpbWUgc2VyaWVzIGlzIG5vbi1zdGF0aW9uYXJ5LiBJdCBjYW4gYmUgY29uZmlybWVkIGJ5IHNlZWluZyB0aGUgZ3JhcGguDQoNCiMjIERldGVjdCBpZiB0aGUgdGltZSBzZXJpZXMgZGF0YSBzaG93cyBzZXJpYWwgYXV0b2NvcnJlbGF0aW9uLg0KDQoNCmBgYHtyfQ0KIyBTZXJpYWwgQXV0b2NvcnJlbGF0aW9uDQojIEFDRiBwbG90czogY29ycmVsYXRpb24gYmV0d2VlbiB0d28gcGVyaW9kcyBpbiBhIHRpbWUgc2VyaWVzIGlzIHJlZmVycmVkIGFzIGF1dG9jb3JyZWxhdGlvbiBmdW5jdGlvbiAoYWNmKQ0KYWNmKE5ldGZsaXgkTmV0ZmxpeF9BZGpfQ2xvc2UsbWFpbj0iU2lnbmlmaWNhbnQgQXV0b2NvcnJlbGF0aW9ucyIpICAjIEdlbmVyYWxseSwgbm9uLXN0YXRpb25hcnkgdGltZSBzZXJpZXMgZGF0YSBzaG93IHRoZSBwcmVzZW5jZSBvZiBzZXJpYWwgYXV0b2NvcnJlbGF0aW9uLiAgDQpgYGANCg0KVGhlIGdyYXBoIHN1Z2dlc3QgdGhhdCB0aGVyZSBpcyBhIHNpZ25pZmljYW50IGF1dG9jb3JyZWxhdGlvbiBpbiB0aGUgdmFyaWFibGUgb2YgdGhlIG1vZGVsLCBnaXZpbmcgYXMgYSByZXN1bHQgdGhhdCBvbmUgcGVyaW9kIGhhdmUgYSBzaWduaWZpY2FudCBpbXBhY3QgZm9yIHRoZSBuZXh0IHBlcmlvZCBiZWhhdmlvciwgd2hpY2ggY2FuIGJlY29tZSBhIHByb2JsZW0gd2hlbiBlc3RpbWF0aW5nIGEgbW9kZWwuIEl0IG1heSBub3QgYmUgYWRlcXVhdGVseSBjYXB0dXJpbmcgdGhlIHN0cnVjdHVyZSBvZiB0aGUgdGltZSBzZXJpZXMuDQoNCg0KIyMgRXN0aW1hdGUgMiBkaWZmZXJlbnQgdGltZSBzZXJpZXMgcmVncmVzc2lvbiBtb2RlbHMuDQoNCiMjIyAqKjEuIEFSTUEgdHJhbnNmb3JtaW5nIHRvIGRpZmYgYW5kIGxvZyoqDQpgYGB7cn0NCnN1bW1hcnkoTkVUX0FSTUE8LWFybWEoZGlmZihsb2coTmV0ZmxpeCROZXRmbGl4X0Fkal9DbG9zZSkpLG9yZGVyPWMoMSwxKSkpDQpgYGANCg0KKioyLiBBUklNQSB0cmFuc2Zvcm1pbmcgdG8gZGlmZiBhbmQgbG9nKioNCg0KDQpgYGB7cn0NCk5FVF9BUklNQSA8LSBBcmltYShkaWZmKGxvZyhOZXRmbGl4JE5ldGZsaXhfQWRqX0Nsb3NlKSksb3JkZXI9YygxLDEsMSkpDQpzdW1tYXJ5KE5FVF9BUklNQSkNCmBgYA0KDQojICoqQykgRXZhbHVhdGlvbioqDQoNCg0KIyMgQ29tcGFyaW5nIGFuZCBzZWxlY3RpbmcgbW9kZWwgdXNpbmcgZGlhZ25vc3RpYyB0ZXN0cy4NCg0KIyMjIEFSTUENCg0KYGBge3J9DQojIG1vZGVsIGV2YWx1YXRpb24gDQojIFRlc3Rpbmcgc2VyaWFsIGF1dG9jb3JyZWxhdGlvbiBpbiByZWdyZXNzaW9uIHJlc2lkdWFscyANCiMgSG86IFRoZXJlIGlzIG5vIHNlcmlhbCBhdXRvY29ycmVsYXRpb24gDQojIEhhOiBUaGVyZSBpcyBzZXJpYWwgYXV0b2NvcnJlbGF0aW9uDQpORVRfQVJNQV9SPC1ORVRfQVJNQSRyZXNpZHVhbHMNCkJveC50ZXN0KE5FVF9BUk1BX1IsbGFnPTEsdHlwZT0iTGp1bmctQm94IikgIA0KIyBBY2NlcHQgdGhlIEhvLiBUaGUgUC12YWx1ZSBpcyA+IDAuMDUgaW5kaWNhdGluZyB0aGF0IEFSTUEgbW9kZWwgZG9lcyBub3Qgc2hvdyByZXNpZHVhbCBzZXJpYWwgYXV0b2NvcnJlbGF0aW9uLiANCmBgYA0KDQpIYXZpbmcgYSBwLXZhbHVlIG9mIDAuOTU3OCAoPjAuMDUpLCB3ZSBmYWlsIHRvIHJlamVjdCBIMCwgaW5kaWNhdGluZyB0aGF0IHRoaXMgQVJNQSBtb2RlbCBkb2VzIG5vdCBzaG93IHJlc2lkdWFsIHNlcmlhbCBhdXRvY29ycmVsYXRpb24gaW4gaXRzIHJlc2lkdWFscywgYW5kIHRoZXkgYmVoYXZlIGluZGVwZW5kZW50bHkuDQpgYGB7cn0NCiNXaGVuIGVzdGltYXRpbmcgdGhpcyBBUk1BIG1vZGVsLCBmaXJzdCB2YWx1ZSBpcyBudWxsLCBzbyB3ZSBuZWVkIHRvIG9taXQgaXQuDQpORVRfQVJNQSRmaXR0ZWQudmFsdWVzIDwtIG5hLm9taXQoTkVUX0FSTUEkZml0dGVkLnZhbHVlcykNCk5FVF9BUk1BJHJlc2lkdWFscyA8LSBuYS5vbWl0KE5FVF9BUk1BJHJlc2lkdWFscykNCiNUZXN0aW5nIHJlc2lkdWFscw0KYWRmLnRlc3QoTkVUX0FSTUEkcmVzaWR1YWxzKQ0KYGBgDQoNCkZvciBBREYgcmVzaWR1YWxzLCBwLXZhbHVlIGlzIGxvd2VyIHRoYW4gMC4wNSwgc28gd2UgZmFpbCB0byByZWplY3QgSDAsIGFuZCBpdCBjYW4gYmUgY29uY2x1ZGVkIHRoYXQgcmVzaWR1YWxzIGFyZSBzdGF0aW9uYXJ5LiANCg0KYGBge3J9DQpoaXN0KE5FVF9BUk1BJHJlc2lkdWFscykNCmBgYA0KDQoNCkl0IGZvbGxvd3MgYSBub3JtYWwgZGlzdHJpYnV0aW9uLA0KDQpgYGB7cn0NCiN0ZXN0aW5nIHZhbHVlcw0KYWRmLnRlc3QoTkVUX0FSTUEkZml0dGVkLnZhbHVlcykNCmBgYA0KDQpXZSBnb3QgYSBwLXZhbHVlIG9mIDAuMDEsIGZhaWxpbmcgdG8gcmVqZWN0IEgwLCB3aGljaCBtZWFucyB0aGF0IHRoZXJlIGlzIGFuIHN0YXRpb25hcnkgdGltZSBzZXJpZXMgZGF0YS4NCg0KYGBge3J9DQpwbG90KGRpZmYobG9nKE5ldGZsaXgkTmV0ZmxpeF9BZGpfQ2xvc2UpKSx0eXBlPSJsIix5bGFiPSJkaWZmIFByaWNlIFN0b2NrIixtYWluID0gIk5ldGZsaXggU3RvY2sgUHJpY2UiKQ0KYGBgDQoNCg0KV2UgZ290IHN0YXRpb25hcnkgdGltZSBzZXJpZXMgZGF0YSBieSBjb3JyZWN0bHkgdHJhbnNmb3JtaW5nIHRoZW0gdG8gZGlmZiBhbmQgbG9nLg0KDQojIyMgQVJJTUENCmBgYHtyfQ0KIyBtb2RlbCBldmFsdWF0aW9uIA0KIyBUZXN0aW5nIHNlcmlhbCBhdXRvY29ycmVsYXRpb24gaW4gcmVncmVzc2lvbiByZXNpZHVhbHMgDQojIEhvOiBUaGVyZSBpcyBubyBzZXJpYWwgYXV0b2NvcnJlbGF0aW9uIA0KIyBIYTogVGhlcmUgaXMgc2VyaWFsIGF1dG9jb3JyZWxhdGlvbg0KTkVUX0FSSU1BX1I8LU5FVF9BUklNQSRyZXNpZHVhbHMNCkJveC50ZXN0KE5FVF9BUklNQV9SLGxhZz0xLHR5cGU9IkxqdW5nLUJveCIpICANCiMgQWNjZXB0IHRoZSBIby4gVGhlIFAtdmFsdWUgaXMgPiAwLjA1IGluZGljYXRpbmcgdGhhdCBBUk1BIG1vZGVsIGRvZXMgbm90IHNob3cgcmVzaWR1YWwgc2VyaWFsIGF1dG9jb3JyZWxhdGlvbi4gDQpgYGANCg0KSGF2aW5nIGEgcC12YWx1ZSBvZiAwLjg2ODIgKD4wLjA1KSwgd2UgZmFpbCB0byByZWplY3QgSDAsIGluZGljYXRpbmcgdGhhdCB0aGlzIEFSTUEgbW9kZWwgZG9lcyBub3Qgc2hvdyByZXNpZHVhbCBzZXJpYWwgYXV0b2NvcnJlbGF0aW9uIGluIGl0cyByZXNpZHVhbHMsIGFuZCB0aGV5IGJlaGF2ZSBpbmRlcGVuZGVudGx5Lg0KYGBge3J9DQojVGVzdGluZyByZXNpZHVhbHMuDQphZGYudGVzdChORVRfQVJJTUEkcmVzaWR1YWxzKQ0KYGBgDQoNCkZvciBBREYgcmVzaWR1YWxzIGluIEFSSU1BLCBwLXZhbHVlIGlzIGxvd2VyIHRoYW4gMC4wNSwgc28gd2UgZmFpbCB0byByZWplY3QgSDAsIGFuZCBpdCBjYW4gYmUgY29uY2x1ZGVkIHRoYXQgcmVzaWR1YWxzIGFyZSBzdGF0aW9uYXJ5LiANCg0KDQpgYGB7cn0NCiNUZXN0aW5nIHZhbHVlcw0KYWRmLnRlc3QoTkVUX0FSSU1BJGZpdHRlZCkNCmBgYA0KV2UgZ290IGEgcC12YWx1ZSBvZiAwLjAxLCBmYWlsaW5nIHRvIHJlamVjdCBIMCwgd2hpY2ggbWVhbnMgdGhhdCB0aGVyZSBpcyBhbiBzdGF0aW9uYXJ5IHRpbWUgc2VyaWVzIGRhdGEuDQoNCiMjIyBTZWxlY3Rpb24NCkl0IGNhbiBiZSBvYnNlcnZlZCB0aGF0IGJvdGggbW9kZWxzIEFSTUEgYW5kIEFSSU1BIGhhdmUgZ29vZCB0ZXN0IHZhbHVlcyB0byBiZSB0YWtlbiBpbnRvIGFjY291bnQuIEhvd2V2ZXIsIEFSTUEgbW9kZWwgaGFzIGEgbG93ZXIgQUlDIHZhbHVlLCBhbmQgYSBoaWdoZXIgdmFsdWUgZm9yICJManVuZ19Cb3ggVGVzdCIsIHRoaXMgaXMgd2h5IHdlIGFyZSBnb25uYSBzZWxlY3QgdGhpcyBtb2RlbC4NCg0KDQpgYGB7cn0NCmFjZihORVRfQVJNQSRmaXR0ZWQudmFsdWVzLG1haW49IlNpZ25pZmljYW50IEF1dG9jb3JyZWxhdGlvbnMiKQ0KYGBgDQoNClRoaXMgbW9kZWwgYWxzbyBoZWxwcyB0byBlbGltaW5hdGUgc2VyaWFsIGF1dG9jb3JyZWxhdGlvbi4NCg0KIyAqKkQpIEZvcmVjYXN0KioNCg0KDQojIyBGb3JlY2FzdCBmb3IgdGhlIG5leHQgNSBwZXJpb2RzLg0KRm9yIHRoZSBuZXh0IHBhcnQsIGl0IHdpbGwgYmUgbmVjZXNzYXJ5IHRvIHRyYW5zZm9ybSB0aGUgZml0dGVkLnZhbHVlcyBvZiB0aGUgbW9kZWwgaW50byBpdHMgb3JpZ2luYWwgZm9ybSwgcmV2ZXJzaW5nIGxvZyBhbmQgZmlyc3Qgb3JkZXJpbmcgZGlmZmVyZW5jZS4NCg0KV2UgbmVlZCB0byBjb252ZXJ0IHRoZXNlIHZhbHVlcyBpbnRvIGEgdmVjdG9yICJjIiBkdWUgdGhlIGRpZmZlcmVudCBsZW5ndGggYmV0d2VlbiBmaXR0ZWQudmFsdWVzIGFuZCB0aGUgb3JpZ2luYWwgb25lcywgdGhhdCB3ZSB3aWxsIGJlIG5lZWRpbmcgaXQgdG8gcmV2ZXJzZSB0aGUgImRpZmYiIHRyYW5zZm9ybWF0aW9uLiBIYXZpbmcgdGhpcyB0aW1lIHNlcmllcyBhcyB2ZWN0b3IgYWxsb3dzIHRvIHN1bSB0aGVtIHVwLCBkZXNwaXRlIG9mIGxlbmd0aCBkaWZmZXJlbmNlLiBGaW5hbGx5LCB3ZSBhcmUgZ29pbmcgdG8gY29udmVydCB0aGVtIGludG8gdGltZSBzZXJpZXMgYWdhaW4sIGluIG9yZGVyIHRvIG1ha2UgYSBmb3JlY2FzdC4NCg0KYGBge3J9DQpmdl9leHA8LWMoZXhwKE5FVF9BUk1BJGZpdHRlZC52YWx1ZXMpKSAjcmV2ZXJ0aW5nICJsb2ciIG9wZXJhdGlvbiB1c2luZyAiZXhwIg0KSUJ2PC1jKE5ldGZsaXgkTmV0ZmxpeF9BZGpfQ2xvc2UpICNDb252ZXJ0aW5nIHRoZSBvcmlnaW5hbCB2YWx1ZXMgaW50byBhIHZlY3Rvci4NCkZpeGVkX1ZhbHVlczwtZnZfZXhwK0lCdiAjcmV2ZXJ0aW5nICJkaWZmIiBvcGVyYXRpb24gc3VtbWluZyB0aGUgb3JpZ2luYWwgdmFsdWVzIHRvIHRoZSBkaWZmZXJlbmNlcy4NCnRzX0ZpeGVkX1ZhbHVlcyA8LSB0cyhGaXhlZF9WYWx1ZXMsIHN0YXJ0ID0gMSwgZW5kID0gbGVuZ3RoKEZpeGVkX1ZhbHVlcyksIGZyZXF1ZW5jeSA9IDEpICNNYWtlIGl0IHRpbWUgc2VyaWVzDQpgYGANCg0KDQpOb3cgaXQgaXMgcG9zc2libGUgdG8gbWFrZSB0aGUgZm9yZWNhc3QgY29ycmVjdGx5DQoNCg0KYGBge3J9DQpOU3RvY2tfZm9yZWNhc3Q8LWZvcmVjYXN0KHRzX0ZpeGVkX1ZhbHVlcyxoPTUpICNoPTUgZm9yIDUgcGVyaW9kcy4NCk5TdG9ja19mb3JlY2FzdA0KYGBgDQoNCldoZW4gZ2VuZXJhdGluZyBhIGZvcmVjYXN0IHdpdGggdGhpcyBtb2RlbCwgd2UgY2FuIG9idGFpbiBhbiBlc3RpbWF0ZSBvZiB3aGF0IHRoZSBzdG9jayBwcmljZSBmb3IgdGhlIG5leHQgNSBwZXJpb2RzIGNvdWxkIGJlLiBUYWtpbmcgaW50byBhY2NvdW50IGEgOTUlIGNvbmZpZGVuY2UgbGV2ZWwsIHRoZXNlIHZhbHVlcyB3b3VsZCBiZSBhcyBmb2xsb3dzOg0KDQoqIFBlcmlvZCAxOiBQcmljZSBiZXR3ZWVuICQyMTAuNjMgYW5kICQzODEuNzUNCiogUGVyaW9kIDI6IFByaWNlIGJldHdlZW4gJDE3NC43NyBhbmQgJDQxOC4yMA0KKiBQZXJpb2QgMzogUHJpY2UgYmV0d2VlbiAkMTQ2LjgyIGFuZCAkNDQ2LjczDQoqIFBlcmlvZCA0OiBQcmljZSBiZXR3ZWVuICQxMjIuODcgYW5kICQ0NzEuMjYNCiogUGVyaW9kIDU6IFByaWNlIGJldHdlZW4gJDEwMS40NCBhbmQgJDQ5My4yOA0KDQoNClBvaW50ZWQgdmFsdWVzIGZvciB0aGlzIGZvcmVjYXN0IGFyZToNCg0KKiBQZXJpb2QgMTogUHJpY2Ugb2YgJDI5Ni4xOQ0KKiBQZXJpb2QgMjogUHJpY2Ugb2YgJDI5Ni40OA0KKiBQZXJpb2QgMzogUHJpY2Ugb2YgJDI5Ni43OA0KKiBQZXJpb2QgNDogUHJpY2Ugb2YgJDI5Ny4wNw0KKiBQZXJpb2QgNTogUHJpY2Ugb2YgJDI5Ni4zNg0KDQpUaGUgZ3JhcGhzIGZvciB0aGlzIGZvcmVjYXN0IGFyZSBwbG90dGVkIGJlbG93Lg0KDQoNCg0KYGBge3J9DQpwbG90KE5TdG9ja19mb3JlY2FzdCkNCmBgYA0KYGBge3J9DQphdXRvcGxvdChOU3RvY2tfZm9yZWNhc3QpDQpgYGANCg0KKipSZWZlcmVuY2VzKioNCk5ldGZsaXggLSBPdmVydmlldyAtIFByb2ZpbGUuICgyMDE4KS4gTmV0ZmxpeC5uZXQuIGh0dHBzOi8vaXIubmV0ZmxpeC5uZXQvaXItb3ZlcnZpZXcvcHJvZmlsZS9kZWZhdWx0LmFzcHgNCg0K4oCMDQoNCg==