Daniel Farías | A01236327

Kathia Ruiz | A01571094

Naila Salinas | A00832702

Sofia Badillo | A02384253

Company selected: Iberdrola SA (IBDRY)

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)

a. Background

Iberdrola SA is one of the biggest renewable energy companies in the world, with a Spain origin and 170 years of history. It is the world’s largest wind power producer and one of the world’s largest electric utilities by market capitalization. It is focus in energy transition to to reduce the negative effects of climate change and the need for a clean, reliable and smart business model. (Iberdrola SA, 2023)

Consumer Price Index is the official measure of inflation of consumer prices of the United Kingdom, based on 700 different goods and services excluding the cost of housing. (Iberdrola SA, 2023)

The variable´s performance that would be analyzed is the “Adjusted Close Price”. Stock prices usually fluctuate, they have an opening, high, low and closing price for each day. The closing price, is the price at which a trading session ends. However, there are instances when certain events get to alter the stock price, that’s when the adjusted close price is needed. It helps determine the fair value of the stock and the maintenance of an accurate historical record of the stock’s performance. (ICICI, 2023)

b. Visualization

Plot the stock price

# Import database
#file.choose()
IB <- read.csv("C:\\Users\\danyb\\OneDrive - Instituto Tecnologico y de Estudios Superiores de Monterrey\\Docs\\Documentos\\Business Intelligence\\Quinto Semestre\\Introduction to Econometrics\\ts_stock_prices\\ts_stock_prices\\IBDRY.csv")  
# setting time series format 
str(IB)
## 'data.frame':    417 obs. of  7 variables:
##  $ Date     : chr  "2015-01-05" "2015-01-12" "2015-01-19" "2015-01-26" ...
##  $ Open     : num  26.4 26.1 26.4 27.5 27.2 ...
##  $ High     : num  26.4 26.2 27.6 28.1 28.2 ...
##  $ Low      : num  25.7 25.5 26.2 27.4 26.9 ...
##  $ Close    : num  26.1 26 27.3 27.5 27 ...
##  $ Adj.Close: num  17.9 17.8 18.7 18.8 18.5 ...
##  $ Volume   : int  156400 193600 202600 300400 155400 161900 95600 161500 185400 137500 ...

It is possible to see that the variable “Date” is on character format. It is necessary for this analysis to have it in Date format.

IB$Date <- as.Date(IB$Date) #"%d/%m/%Y" this is only used when having the correct format
summary(IB$Adj.Close)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   16.96   19.96   26.19   30.45   40.60   53.90

This little summary of “Adj.Close” shows important information about the company value stocks. First, it illustrates that the minimum value for the stock in all the times is $16.96, while its maximum value is $53.90.

#Time to see for NA values.
sum(is.na(IB))  
## [1] 0
colSums(is.na(IB))  
##      Date      Open      High       Low     Close Adj.Close    Volume 
##         0         0         0         0         0         0         0

There are no missing values on the dataset.

# visualizing time series data 
# time series plot 1
plot(IB$Date,IB$Adj.Close,type="l",col="steelblue", lwd=2, xlab ="Date",ylab ="Adjusted Close Price", main = "Iberdrola SA Stock Price")

This graph shows the adjusted closing price of the stock over the years.

  • In 2016, it started at around $20. It is on this year when price of the stock got its lowest value.
  • It began to rise before 2018, nearly hitting $30 that year.
  • There was a drop in 2020, likely due to the pandemic.
  • The stock reached its highest point around 2021.
  • Towards the end of 2021, there was a significant decline.
  • Since then, it has been relatively stable with fewer major fluctuations.

It is pretended to have more specifically information, that is why different visualization of this data are going to be done below.

# time series plot 2
IBxts<-xts(IB$Adj.Close,order.by=IB$Date)
plot(IBxts)

In this second graph we can see the performance of the variable more clearly thanks to the grids that help to better visualize the behavior of the variable through the years, but it is on the next graph where we could see very specifically information.

# time series plot 3
dygraph(IBxts, main = "Iberdrola SA Stock Price") %>% 
  dyOptions(colors = RColorBrewer::brewer.pal(4, "Dark2")) %>%
  dyShading(from = "2017-02-6",
            to = "2022-12-22", 
            color = "#FFE6E6")

This graph illustrates a significant increase in the stock price, particularly noticeable from February 6, 2017, to December 14, 2022. The price began at $19.15 and reached a final value of $44.93 in 2022, marking an approximate increase of $25.78 USD during this period. A noticeable decline can be observed starting in March 2020, confirming our theory that this drop was due to the pandemic. However, the stock began to recover in May 2020, reaching its peak value on January 4, 2021.

# time series plot 3
dygraph(IBxts, main = "Iberdrola SA Stock Price") %>% 
  dyOptions(colors = RColorBrewer::brewer.pal(4, "Dark2")) %>%
  dyShading(from = "2022-01-1",
            to = "2022-12-22", 
            color = "#FFE6E6")

To answer the question about the variable’s performance in the last year, we’ve prepared another graph, focusing on this specific period.

  • It began the year with an approximate value of $42.
  • In late February, there was a decline, but it quickly recovered to its starting price.
  • The peak for the year was at $45.23, in May.
  • However, it hit its lowest point in October.
  • By December, it closed the year almost reaching a price of $45.

Decomposing time series to identify important behaviors.

# 1) Decompose a time series
# Decomposition: observed + trend + seasonal + random
# observed: data observations 
# trend: increasing / decreasing value of data observations
# seasonality: repeating short-term cycle in time series 
# noise: random variation in time series 

IBts<-ts(IB$Adj.Close,frequency=52,start=c(2015,1))
IB_ts_decompose<-decompose(IBts)
plot(IB_ts_decompose)   

In the decomposition of the time series it is possible to get a better understanding of its behavior based on its characteristics. The observed variable part shows a similar performance to the ones previously described on the time series plots. The trend part shows a more clear positive trend than what could be seen in the plots. With this, it can be inferred that while the stock may face periodic decreases, it generally maintains a favorable positive trend.The seasonal part clearly shows a pattern of dates where the stock price is more favorable. Lastly, it is possible to see similar behaviors divided in two different periods of the random part for the variable, one before 2020, and one after it.

c. Estimation

Is time series stationary?

# Stationary Test 
adf.test(IB$Adj.Close)
## 
##  Augmented Dickey-Fuller Test
## 
## data:  IB$Adj.Close
## Dickey-Fuller = -2.3197, Lag order = 7, p-value = 0.4424
## 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.

The p-value obtained from the test is 0.4424, which is higher than the typical significance level of 0.05. Since the p-value is greater than 0.05, we fail to reject the null hypothesis (H0), which means that the time series data (in this case, “Adj.Close”) is considered non-stationary.

Does time series show serial autocorrelation?

# Serial Autocorrelation
# ACF plots: correlation between two periods in a time series is referred as autocorrelation function (acf)
acf(IB$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 a period have a significant impact for the next period behavior, which can become a problem because the model may not be adequately capturing the structure of the time series.

Estimating models.

In order to make different models, we are going to compare possible results using “log” and “diff” to get a stationary time series data.

plot(IB$Date,log(IB$Adj.Close), type="l",col="blue", lwd=2, xlab ="Date",ylab ="log(Stock Price)", main = "IBDRY Stock Price") #convertí variable a log y es muy similar

Transforming with log is really similar to the original one.

adf.test(log(IB$Adj.Close))
## 
##  Augmented Dickey-Fuller Test
## 
## data:  log(IB$Adj.Close)
## Dickey-Fuller = -2.1693, Lag order = 7, p-value = 0.5059
## alternative hypothesis: stationary

It is still non-stationary due the p-value of 0.5059.

plot(diff(log(IB$Adj.Close)),type="l",ylab="first order difference",main = "Diff - GE Stock Price") #diferencias, ya es estacionaria

It becomes different when using “diff” and “log”. It could be stationary.

adf.test(diff(log(IB$Adj.Close)))
## Warning in adf.test(diff(log(IB$Adj.Close))): p-value smaller than printed
## p-value
## 
##  Augmented Dickey-Fuller Test
## 
## data:  diff(log(IB$Adj.Close))
## Dickey-Fuller = -8.4297, Lag order = 7, p-value = 0.01
## alternative hypothesis: stationary

We got a p-value of 0.01 using this option, which make the time series stationary. This is one of the options that we can test.

1. ARMA With log.

Transforming the variable into log, in order to get stationary time series data. When modeling, fitted.values will contain a null that doesn’t allow to continue doing operations, so we are going to omit it. This also happens in teacher’s code. This use to be because the first value of the original data does not have anything before to be compared.

# time series modeling 
summary(IB_ARMA<-arma(log(IB$Adj.Close),order=c(1,1)))
## 
## Call:
## arma(x = log(IB$Adj.Close), order = c(1, 1))
## 
## Model:
## ARMA(1,1)
## 
## Residuals:
##        Min         1Q     Median         3Q        Max 
## -0.1985876 -0.0196660  0.0005597  0.0198321  0.1085765 
## 
## Coefficient(s):
##            Estimate  Std. Error  t value Pr(>|t|)    
## ar1        0.995734    0.004385  227.062   <2e-16 ***
## ma1       -0.109437    0.049321   -2.219   0.0265 *  
## intercept  0.016535    0.014798    1.117   0.2638    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Fit:
## sigma^2 estimated as 0.001151,  Conditional Sum-of-Squares = 0.48,  AIC = -1632.55

We got a negative AIC value, which could be a good parameter to evaluate the model later. It is also interesting to see the coefficients for ar1 and ma1, the ar1 coefficient is 0.995734, which could be interpreted as a great impact in the estimating model, it is also the more significant one. The cause for this results could be the non-stationary time series data.

IB_ARMA$fitted.values <- na.omit(IB_ARMA$fitted.values)

We transformed the variable to log, but in order to get the correct values in its original format, it is necessary to apply exp.

IB_estimated_stock_price<-exp(IB_ARMA$fitted.values)

Now we can plot the result.

plot(IB_estimated_stock_price)

2. ARMA With log and diff.

It is necessary to transform the variable to log and diff because of non-stationary time series data. As we saw before, this combination can transform a non-stationary time series to a stationary one.

# time series modeling 
summary(IB_ARMA2<-arma(diff(log(IB$Adj.Close),order=c(1,1))))
## 
## Call:
## arma(x = diff(log(IB$Adj.Close), order = c(1, 1)))
## 
## Model:
## ARMA(1,1)
## 
## Residuals:
##        Min         1Q     Median         3Q        Max 
## -0.1965592 -0.0195813  0.0007618  0.0205598  0.1092452 
## 
## Coefficient(s):
##             Estimate  Std. Error  t value Pr(>|t|)    
## ar1        0.7819195   0.0870985    8.977   <2e-16 ***
## ma1       -0.8722668   0.0670454  -13.010   <2e-16 ***
## intercept  0.0004729   0.0002853    1.658   0.0974 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Fit:
## sigma^2 estimated as 0.001147,  Conditional Sum-of-Squares = 0.48,  AIC = -1629.88

Although we got a higher AIC value, coefficients and significance for factors changed, but if this model is calculated with stationary data, it could be better due the risk of forecasting with non-stationary. For the next part, it will be necessary to omit null values, and 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.

IB_ARMA2$fitted.values <- na.omit(IB_ARMA2$fitted.values)
fv_exp<-c(exp(IB_ARMA2$fitted.values)) #reverting "log" operation using "exp"
IBv<-c(IB$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 we can plot the result.

plot(ts_Fixed_Values)

ARIMA MODEL

IB_ARIMA <- Arima(IB$Adj.Close,order=c(1,1,1))
summary(IB_ARIMA)
## Series: IB$Adj.Close 
## ARIMA(1,1,1) 
## 
## Coefficients:
##           ar1     ma1
##       -0.1545  0.0740
## s.e.   0.4457  0.4489
## 
## sigma^2 = 1.377:  log likelihood = -655.81
## AIC=1317.62   AICc=1317.68   BIC=1329.71
## 
## Training set error measures:
##                      ME     RMSE       MAE       MPE     MAPE      MASE
## Training set 0.06965504 1.169198 0.7981992 0.1753621 2.526616 0.9990932
##                      ACF1
## Training set -0.003636467
plot(IB_ARIMA$fitted)

ts_IB <- IB$Adj.Close
ets_model <- ets(ts_IB)
forecast_values <- forecast(ets_model, h = 10)
print(forecast_values)
##     Point Forecast    Lo 80    Hi 80    Lo 95    Hi 95
## 418       44.84566 42.89646 46.79486 41.86461 47.82671
## 419       44.84566 42.24638 47.44494 40.87040 48.82092
## 420       44.84566 41.72864 47.96268 40.07859 49.61273
## 421       44.84566 41.28505 48.40628 39.40017 50.29115
## 422       44.84566 40.89056 48.80076 38.79686 50.89446
## 423       44.84566 40.53170 49.15962 38.24802 51.44330
## 424       44.84566 40.20019 49.49113 37.74103 51.95030
## 425       44.84566 39.89054 49.80078 37.26746 52.42386
## 426       44.84566 39.59889 50.09243 36.82141 52.86991
## 427       44.84566 39.32237 50.36895 36.39852 53.29280
plot(forecast_values, main = "ETS Model")

Evaluate

# model evaluation 
# Testing serial autocorrelation in regression residuals 
# Ho: There is no serial autocorrelation 
# Ha: There is serial autocorrelation
IB_ARMA_residuals<-IB_ARMA$residuals
Box.test(IB_ARMA_residuals,lag=5,type="Ljung-Box")  
## 
##  Box-Ljung test
## 
## data:  IB_ARMA_residuals
## X-squared = 2.7633, df = 5, p-value = 0.7364
# Accept the Ho. The P-value is > 0.05 indicating that ARMA model does not show residual serial autocorrelation. 
adf.test(IB_ARMA$fitted.values) #this test was being applied to the variable with fixed values.
## 
##  Augmented Dickey-Fuller Test
## 
## data:  IB_ARMA$fitted.values
## Dickey-Fuller = -2.1065, Lag order = 7, p-value = 0.5324
## alternative hypothesis: stationary
# That's why we are always going to have a similar p-value in this test, and the previous one.
# It needs to be applied to fitted.values of the model, in order to get a real p-value.

p-value for “Ljung-Box” indicates that this model does not show residual serial autocorrelation, but we can’t ignore the fact that p-value for augmented Dickey-Fuller Test shows that H0 could be not rejected, which means that time series model is non-stationary. Forecasting with non-stationary series might bring incorrect forecasts.

IB_ARMA2_residuals<-IB_ARMA2$residuals
Box.test(IB_ARMA2_residuals,lag=5,type="Ljung-Box")  
## 
##  Box-Ljung test
## 
## data:  IB_ARMA2_residuals
## X-squared = 2.634, df = 5, p-value = 0.7562
# Accept the Ho. The P-value is > 0.05 indicating that ARMA model does not show residual serial autocorrelation. 
adf.test(IB_ARMA2$fitted.values)
## Warning in adf.test(IB_ARMA2$fitted.values): p-value smaller than printed
## p-value
## 
##  Augmented Dickey-Fuller Test
## 
## data:  IB_ARMA2$fitted.values
## Dickey-Fuller = -5.3041, Lag order = 7, p-value = 0.01
## alternative hypothesis: stationary
#These values are the result of using model ARMA in the original time series, transforming it into log and diff.

For this model, we got a higher p-value for residuals, indicating that this model does not have residual serial autocorrelation, in addition, this model has a p-value for ADF test of 0.01, which reject the H0 hypothesis, meaning that we have an stationary time series.

IB_ARIMA_RESIDUALS<-IB_ARIMA$residuals
Box.test(IB_ARIMA_RESIDUALS,lag=5,type="Ljung-Box")  
## 
##  Box-Ljung test
## 
## data:  IB_ARIMA_RESIDUALS
## X-squared = 2.382, df = 5, p-value = 0.7942
# Accept the Ho. The P-value is > 0.05 indicating that ARMA model does not show residual serial autocorrelation. 
adf.test(IB_ARIMA$fitted)
## 
##  Augmented Dickey-Fuller Test
## 
## data:  IB_ARIMA$fitted
## Dickey-Fuller = -2.2549, Lag order = 7, p-value = 0.4698
## alternative hypothesis: stationary

The first case is repeated on ARIMA model, we have an ADF p-value higher than 0.05, which means that we can not reject the H0, meaning that this model might have a non-stationary time series data.

Choosing a model.

Having the results for the diagnostic tests of the three models, we can make a decision about which one to use for generating potentially accurate forecasts. Based on these results, we have decided to use model 2, which transforms the time series into a logarithmic and differenced format. This approach helps achieve a stationary time series, reducing the margin of error when making forecasts.

Forecast

# forecasting (ARMA2)
IB_ARMA2_forecast<-forecast(ts_Fixed_Values,h=5) #h=5 for 5 periods.
IB_ARMA2_forecast
##     Point Forecast    Lo 80    Hi 80    Lo 95    Hi 95
## 418       45.83929 43.91120 47.76738 42.89053 48.78805
## 419       45.83929 43.26796 48.41061 41.90679 49.77178
## 420       45.83929 42.75573 48.92284 41.12340 50.55517
## 421       45.83929 42.31688 49.36169 40.45224 51.22634
## 422       45.83929 41.92664 49.75193 39.85542 51.82316

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 $42.89 and $48.79
  • Period 2: Price between $41.91 and $49.77
  • Period 3: Price between $41.12 and $50.56
  • Period 4: Price between $40.45 and $51.23
  • Period 5: Price between $39.85 and $51.82

The graphs for this forecast are plotted below.

plot(IB_ARMA2_forecast)

autoplot(IB_ARMA2_forecast)

References:

Iberdrola SA (2023). Iberdrola. https://www.iberdrola.com/conocenos/nuestra-empresa

LS0tDQp0aXRsZTogIkFzc2lnbm1lbnQgMyINCmF1dGhvcjogIlRlYW0gNCBFY29ub21ldHJpY3MiDQpkYXRlOiAiMjAyMy0wOS0wMyINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogIHBkZl9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KLS0tDQpEYW5pZWwgRmFyw61hcyB8IEEwMTIzNjMyNw0KDQpLYXRoaWEgUnVpeiB8IEEwMTU3MTA5NA0KDQpOYWlsYSBTYWxpbmFzIHwgQTAwODMyNzAyIA0KDQpTb2ZpYSBCYWRpbGxvIHwgQTAyMzg0MjUzDQoNCioqQ29tcGFueSBzZWxlY3RlZDogSWJlcmRyb2xhIFNBIChJQkRSWSkqKg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRX0NCmxpYnJhcnkoeHRzKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoem9vKQ0KbGlicmFyeSh0c2VyaWVzKQ0KbGlicmFyeShzdGF0cykNCmxpYnJhcnkoZm9yZWNhc3QpDQpsaWJyYXJ5KGFzdHNhKQ0KbGlicmFyeShjb3JycGxvdCkNCmxpYnJhcnkoQUVSKQ0KbGlicmFyeSh2YXJzKQ0KbGlicmFyeShkeW5sbSkNCmxpYnJhcnkodmFycykNCmxpYnJhcnkoVFNzdHVkaW8pDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoc2FyaW1hKQ0KbGlicmFyeShkeWdyYXBocykNCmBgYA0KDQoNCg0KDQojIGEuIEJhY2tncm91bmQgDQoNCkliZXJkcm9sYSBTQSBpcyBvbmUgb2YgdGhlIGJpZ2dlc3QgcmVuZXdhYmxlIGVuZXJneSBjb21wYW5pZXMgaW4gdGhlIHdvcmxkLCB3aXRoIGEgU3BhaW4gb3JpZ2luIGFuZCAxNzAgeWVhcnMgb2YgaGlzdG9yeS4gSXQgaXMgdGhlIHdvcmxkJ3MgbGFyZ2VzdCB3aW5kIHBvd2VyIHByb2R1Y2VyIGFuZCBvbmUgb2YgdGhlIHdvcmxkJ3MgbGFyZ2VzdCBlbGVjdHJpYyB1dGlsaXRpZXMgYnkgbWFya2V0IGNhcGl0YWxpemF0aW9uLiBJdCBpcyBmb2N1cyBpbiBlbmVyZ3kgdHJhbnNpdGlvbiB0byB0byByZWR1Y2UgdGhlIG5lZ2F0aXZlIGVmZmVjdHMgb2YgY2xpbWF0ZSBjaGFuZ2UgYW5kIHRoZSBuZWVkIGZvciBhIGNsZWFuLCByZWxpYWJsZSBhbmQgc21hcnQgYnVzaW5lc3MgbW9kZWwuIChJYmVyZHJvbGEgU0EsIDIwMjMpDQoNCkNvbnN1bWVyIFByaWNlIEluZGV4IGlzIHRoZSBvZmZpY2lhbCBtZWFzdXJlIG9mIGluZmxhdGlvbiBvZiBjb25zdW1lciBwcmljZXMgb2YgdGhlIFVuaXRlZCBLaW5nZG9tLCBiYXNlZCBvbiA3MDAgZGlmZmVyZW50IGdvb2RzIGFuZCBzZXJ2aWNlcyBleGNsdWRpbmcgdGhlIGNvc3Qgb2YgaG91c2luZy4gKEliZXJkcm9sYSBTQSwgMjAyMykNCg0KVGhlIHZhcmlhYmxlwrRzIHBlcmZvcm1hbmNlIHRoYXQgd291bGQgYmUgYW5hbHl6ZWQgaXMgdGhlICJBZGp1c3RlZCBDbG9zZSBQcmljZSIuIFN0b2NrIHByaWNlcyB1c3VhbGx5IGZsdWN0dWF0ZSwgdGhleSBoYXZlIGFuIG9wZW5pbmcsIGhpZ2gsIGxvdyBhbmQgY2xvc2luZyBwcmljZSBmb3IgZWFjaCBkYXkuIFRoZSBjbG9zaW5nIHByaWNlLCBpcyB0aGUgcHJpY2UgYXQgd2hpY2ggYSB0cmFkaW5nIHNlc3Npb24gZW5kcy4gSG93ZXZlciwgdGhlcmUgYXJlIGluc3RhbmNlcyB3aGVuIGNlcnRhaW4gZXZlbnRzIGdldCB0byBhbHRlciB0aGUgc3RvY2sgcHJpY2UsIHRoYXQncyB3aGVuIHRoZSBhZGp1c3RlZCBjbG9zZSBwcmljZSBpcyBuZWVkZWQuIEl0IGhlbHBzIGRldGVybWluZSB0aGUgZmFpciB2YWx1ZSBvZiB0aGUgc3RvY2sgYW5kIHRoZSBtYWludGVuYW5jZSBvZiBhbiBhY2N1cmF0ZSBoaXN0b3JpY2FsIHJlY29yZCBvZiB0aGUgc3RvY2sncyBwZXJmb3JtYW5jZS4gKElDSUNJLCAyMDIzKQ0KDQoNCiMgYi4gVmlzdWFsaXphdGlvbg0KIyMgUGxvdCB0aGUgc3RvY2sgcHJpY2UNCg0KYGBge3J9DQojIEltcG9ydCBkYXRhYmFzZQ0KI2ZpbGUuY2hvb3NlKCkNCklCIDwtIHJlYWQuY3N2KCJDOlxcVXNlcnNcXGRhbnliXFxPbmVEcml2ZSAtIEluc3RpdHV0byBUZWNub2xvZ2ljbyB5IGRlIEVzdHVkaW9zIFN1cGVyaW9yZXMgZGUgTW9udGVycmV5XFxEb2NzXFxEb2N1bWVudG9zXFxCdXNpbmVzcyBJbnRlbGxpZ2VuY2VcXFF1aW50byBTZW1lc3RyZVxcSW50cm9kdWN0aW9uIHRvIEVjb25vbWV0cmljc1xcdHNfc3RvY2tfcHJpY2VzXFx0c19zdG9ja19wcmljZXNcXElCRFJZLmNzdiIpICANCmBgYA0KDQpgYGB7cn0NCiMgc2V0dGluZyB0aW1lIHNlcmllcyBmb3JtYXQgDQpzdHIoSUIpDQpgYGANCkl0IGlzIHBvc3NpYmxlIHRvIHNlZSB0aGF0IHRoZSB2YXJpYWJsZSAiRGF0ZSIgaXMgb24gY2hhcmFjdGVyIGZvcm1hdC4gSXQgaXMgbmVjZXNzYXJ5IGZvciB0aGlzIGFuYWx5c2lzIHRvIGhhdmUgaXQgaW4gRGF0ZSBmb3JtYXQuDQpgYGB7cn0NCklCJERhdGUgPC0gYXMuRGF0ZShJQiREYXRlKSAjIiVkLyVtLyVZIiB0aGlzIGlzIG9ubHkgdXNlZCB3aGVuIGhhdmluZyB0aGUgY29ycmVjdCBmb3JtYXQNCnN1bW1hcnkoSUIkQWRqLkNsb3NlKQ0KYGBgDQpUaGlzIGxpdHRsZSBzdW1tYXJ5IG9mICJBZGouQ2xvc2UiIHNob3dzIGltcG9ydGFudCBpbmZvcm1hdGlvbiBhYm91dCB0aGUgY29tcGFueSB2YWx1ZSBzdG9ja3MuDQpGaXJzdCwgaXQgaWxsdXN0cmF0ZXMgdGhhdCB0aGUgbWluaW11bSB2YWx1ZSBmb3IgdGhlIHN0b2NrIGluIGFsbCB0aGUgdGltZXMgaXMgJDE2Ljk2LCB3aGlsZSBpdHMgbWF4aW11bSB2YWx1ZSBpcyAkNTMuOTAuDQoNCg0KYGBge3J9DQojVGltZSB0byBzZWUgZm9yIE5BIHZhbHVlcy4NCnN1bShpcy5uYShJQikpICANCmNvbFN1bXMoaXMubmEoSUIpKSAgDQpgYGANCg0KVGhlcmUgYXJlIG5vIG1pc3NpbmcgdmFsdWVzIG9uIHRoZSBkYXRhc2V0Lg0KDQpgYGB7cn0NCiMgdmlzdWFsaXppbmcgdGltZSBzZXJpZXMgZGF0YSANCiMgdGltZSBzZXJpZXMgcGxvdCAxDQpwbG90KElCJERhdGUsSUIkQWRqLkNsb3NlLHR5cGU9ImwiLGNvbD0ic3RlZWxibHVlIiwgbHdkPTIsIHhsYWIgPSJEYXRlIix5bGFiID0iQWRqdXN0ZWQgQ2xvc2UgUHJpY2UiLCBtYWluID0gIkliZXJkcm9sYSBTQSBTdG9jayBQcmljZSIpDQoNCmBgYA0KDQpUaGlzIGdyYXBoIHNob3dzIHRoZSBhZGp1c3RlZCBjbG9zaW5nIHByaWNlIG9mIHRoZSBzdG9jayBvdmVyIHRoZSB5ZWFycy4NCg0KKiBJbiAyMDE2LCBpdCBzdGFydGVkIGF0IGFyb3VuZCAkMjAuIEl0IGlzIG9uIHRoaXMgeWVhciB3aGVuIHByaWNlIG9mIHRoZSBzdG9jayBnb3QgaXRzIGxvd2VzdCB2YWx1ZS4NCiogSXQgYmVnYW4gdG8gcmlzZSBiZWZvcmUgMjAxOCwgbmVhcmx5IGhpdHRpbmcgJDMwIHRoYXQgeWVhci4NCiogVGhlcmUgd2FzIGEgZHJvcCBpbiAyMDIwLCBsaWtlbHkgZHVlIHRvIHRoZSBwYW5kZW1pYy4NCiogVGhlIHN0b2NrIHJlYWNoZWQgaXRzIGhpZ2hlc3QgcG9pbnQgYXJvdW5kIDIwMjEuDQoqIFRvd2FyZHMgdGhlIGVuZCBvZiAyMDIxLCB0aGVyZSB3YXMgYSBzaWduaWZpY2FudCBkZWNsaW5lLg0KKiBTaW5jZSB0aGVuLCBpdCBoYXMgYmVlbiByZWxhdGl2ZWx5IHN0YWJsZSB3aXRoIGZld2VyIG1ham9yIGZsdWN0dWF0aW9ucy4NCg0KSXQgaXMgcHJldGVuZGVkIHRvIGhhdmUgbW9yZSBzcGVjaWZpY2FsbHkgaW5mb3JtYXRpb24sIHRoYXQgaXMgd2h5IGRpZmZlcmVudCB2aXN1YWxpemF0aW9uIG9mIHRoaXMgZGF0YSBhcmUgZ29pbmcgdG8gYmUgZG9uZSBiZWxvdy4NCg0KYGBge3J9DQojIHRpbWUgc2VyaWVzIHBsb3QgMg0KSUJ4dHM8LXh0cyhJQiRBZGouQ2xvc2Usb3JkZXIuYnk9SUIkRGF0ZSkNCnBsb3QoSUJ4dHMpDQpgYGANCg0KSW4gdGhpcyBzZWNvbmQgZ3JhcGggd2UgY2FuIHNlZSB0aGUgcGVyZm9ybWFuY2Ugb2YgdGhlIHZhcmlhYmxlIG1vcmUgY2xlYXJseSB0aGFua3MgdG8gdGhlIGdyaWRzIHRoYXQgaGVscCB0byBiZXR0ZXIgdmlzdWFsaXplIHRoZSBiZWhhdmlvciBvZiB0aGUgdmFyaWFibGUgdGhyb3VnaCB0aGUgeWVhcnMsIGJ1dCBpdCBpcyBvbiB0aGUgbmV4dCBncmFwaCB3aGVyZSB3ZSBjb3VsZCBzZWUgdmVyeSBzcGVjaWZpY2FsbHkgaW5mb3JtYXRpb24uDQoNCmBgYHtyfQ0KIyB0aW1lIHNlcmllcyBwbG90IDMNCmR5Z3JhcGgoSUJ4dHMsIG1haW4gPSAiSWJlcmRyb2xhIFNBIFN0b2NrIFByaWNlIikgJT4lIA0KICBkeU9wdGlvbnMoY29sb3JzID0gUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKDQsICJEYXJrMiIpKSAlPiUNCiAgZHlTaGFkaW5nKGZyb20gPSAiMjAxNy0wMi02IiwNCiAgICAgICAgICAgIHRvID0gIjIwMjItMTItMjIiLCANCiAgICAgICAgICAgIGNvbG9yID0gIiNGRkU2RTYiKQ0KDQpgYGANCg0KDQpUaGlzIGdyYXBoIGlsbHVzdHJhdGVzIGEgc2lnbmlmaWNhbnQgaW5jcmVhc2UgaW4gdGhlIHN0b2NrIHByaWNlLCBwYXJ0aWN1bGFybHkgbm90aWNlYWJsZSBmcm9tIEZlYnJ1YXJ5IDYsIDIwMTcsIHRvIERlY2VtYmVyIDE0LCAyMDIyLiBUaGUgcHJpY2UgYmVnYW4gYXQgJDE5LjE1IGFuZCByZWFjaGVkIGEgZmluYWwgdmFsdWUgb2YgJDQ0LjkzIGluIDIwMjIsIG1hcmtpbmcgYW4gYXBwcm94aW1hdGUgaW5jcmVhc2Ugb2YgJDI1Ljc4IFVTRCBkdXJpbmcgdGhpcyBwZXJpb2QuIEEgbm90aWNlYWJsZSBkZWNsaW5lIGNhbiBiZSBvYnNlcnZlZCBzdGFydGluZyBpbiBNYXJjaCAyMDIwLCBjb25maXJtaW5nIG91ciB0aGVvcnkgdGhhdCB0aGlzIGRyb3Agd2FzIGR1ZSB0byB0aGUgcGFuZGVtaWMuIEhvd2V2ZXIsIHRoZSBzdG9jayBiZWdhbiB0byByZWNvdmVyIGluIE1heSAyMDIwLCByZWFjaGluZyBpdHMgcGVhayB2YWx1ZSBvbiBKYW51YXJ5IDQsIDIwMjEuDQoNCmBgYHtyfQ0KIyB0aW1lIHNlcmllcyBwbG90IDMNCmR5Z3JhcGgoSUJ4dHMsIG1haW4gPSAiSWJlcmRyb2xhIFNBIFN0b2NrIFByaWNlIikgJT4lIA0KICBkeU9wdGlvbnMoY29sb3JzID0gUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKDQsICJEYXJrMiIpKSAlPiUNCiAgZHlTaGFkaW5nKGZyb20gPSAiMjAyMi0wMS0xIiwNCiAgICAgICAgICAgIHRvID0gIjIwMjItMTItMjIiLCANCiAgICAgICAgICAgIGNvbG9yID0gIiNGRkU2RTYiKQ0KDQpgYGANCg0KDQpUbyBhbnN3ZXIgdGhlIHF1ZXN0aW9uIGFib3V0IHRoZSB2YXJpYWJsZSdzIHBlcmZvcm1hbmNlIGluIHRoZSBsYXN0IHllYXIsIHdlJ3ZlIHByZXBhcmVkIGFub3RoZXIgZ3JhcGgsIGZvY3VzaW5nIG9uIHRoaXMgc3BlY2lmaWMgcGVyaW9kLg0KDQoqIEl0IGJlZ2FuIHRoZSB5ZWFyIHdpdGggYW4gYXBwcm94aW1hdGUgdmFsdWUgb2YgJDQyLg0KKiBJbiBsYXRlIEZlYnJ1YXJ5LCB0aGVyZSB3YXMgYSBkZWNsaW5lLCBidXQgaXQgcXVpY2tseSByZWNvdmVyZWQgdG8gaXRzIHN0YXJ0aW5nIHByaWNlLg0KKiBUaGUgcGVhayBmb3IgdGhlIHllYXIgd2FzIGF0ICQ0NS4yMywgaW4gTWF5Lg0KKiBIb3dldmVyLCBpdCBoaXQgaXRzIGxvd2VzdCBwb2ludCBpbiBPY3RvYmVyLg0KKiBCeSBEZWNlbWJlciwgaXQgY2xvc2VkIHRoZSB5ZWFyIGFsbW9zdCByZWFjaGluZyBhIHByaWNlIG9mICQ0NS4NCg0KIyMgRGVjb21wb3NpbmcgdGltZSBzZXJpZXMgdG8gaWRlbnRpZnkgaW1wb3J0YW50IGJlaGF2aW9ycy4NCg0KYGBge3J9DQojIDEpIERlY29tcG9zZSBhIHRpbWUgc2VyaWVzDQojIERlY29tcG9zaXRpb246IG9ic2VydmVkICsgdHJlbmQgKyBzZWFzb25hbCArIHJhbmRvbQ0KIyBvYnNlcnZlZDogZGF0YSBvYnNlcnZhdGlvbnMgDQojIHRyZW5kOiBpbmNyZWFzaW5nIC8gZGVjcmVhc2luZyB2YWx1ZSBvZiBkYXRhIG9ic2VydmF0aW9ucw0KIyBzZWFzb25hbGl0eTogcmVwZWF0aW5nIHNob3J0LXRlcm0gY3ljbGUgaW4gdGltZSBzZXJpZXMgDQojIG5vaXNlOiByYW5kb20gdmFyaWF0aW9uIGluIHRpbWUgc2VyaWVzIA0KDQpJQnRzPC10cyhJQiRBZGouQ2xvc2UsZnJlcXVlbmN5PTUyLHN0YXJ0PWMoMjAxNSwxKSkNCklCX3RzX2RlY29tcG9zZTwtZGVjb21wb3NlKElCdHMpDQpwbG90KElCX3RzX2RlY29tcG9zZSkgICANCmBgYA0KDQpJbiB0aGUgZGVjb21wb3NpdGlvbiBvZiB0aGUgdGltZSBzZXJpZXMgaXQgaXMgcG9zc2libGUgdG8gZ2V0IGEgYmV0dGVyIHVuZGVyc3RhbmRpbmcgb2YgaXRzIGJlaGF2aW9yIGJhc2VkIG9uIGl0cyBjaGFyYWN0ZXJpc3RpY3MuIFRoZSBvYnNlcnZlZCB2YXJpYWJsZSBwYXJ0IHNob3dzIGEgc2ltaWxhciBwZXJmb3JtYW5jZSB0byB0aGUgb25lcyBwcmV2aW91c2x5IGRlc2NyaWJlZCBvbiB0aGUgdGltZSBzZXJpZXMgcGxvdHMuIFRoZSB0cmVuZCBwYXJ0IHNob3dzIGEgbW9yZSBjbGVhciBwb3NpdGl2ZSB0cmVuZCB0aGFuIHdoYXQgY291bGQgYmUgc2VlbiBpbiB0aGUgcGxvdHMuIFdpdGggdGhpcywgaXQgY2FuIGJlIGluZmVycmVkIHRoYXQgd2hpbGUgdGhlIHN0b2NrIG1heSBmYWNlIHBlcmlvZGljIGRlY3JlYXNlcywgaXQgZ2VuZXJhbGx5IG1haW50YWlucyBhIGZhdm9yYWJsZSBwb3NpdGl2ZSB0cmVuZC5UaGUgKipzZWFzb25hbCoqIHBhcnQgY2xlYXJseSBzaG93cyBhICoqcGF0dGVybioqIG9mIGRhdGVzIHdoZXJlIHRoZSBzdG9jayBwcmljZSBpcyBtb3JlIGZhdm9yYWJsZS4gTGFzdGx5LCBpdCBpcyBwb3NzaWJsZSB0byBzZWUgc2ltaWxhciBiZWhhdmlvcnMgZGl2aWRlZCBpbiB0d28gZGlmZmVyZW50IHBlcmlvZHMgb2YgdGhlIHJhbmRvbSBwYXJ0IGZvciB0aGUgdmFyaWFibGUsIG9uZSBiZWZvcmUgMjAyMCwgYW5kIG9uZSBhZnRlciBpdC4NCg0KDQojIGMuIEVzdGltYXRpb24NCg0KIyMgSXMgdGltZSBzZXJpZXMgc3RhdGlvbmFyeT8NCmBgYHtyfQ0KIyBTdGF0aW9uYXJ5IFRlc3QgDQphZGYudGVzdChJQiRBZGouQ2xvc2UpDQoNCiMjIyBIMDogTm9uLXN0YXRpb25hcnkgYW5kIEhBOiBTdGF0aW9uYXJ5LiAgDQojIyMgVGhlIFAtVmFsdWUgaXMgaGlnaGVyIHRoYW4gMC4wNSBzbyBpdCBmYWlscyB0byBSZWplY3QgdGhlIEgwLiBUaW1lIHNlcmllcyBkYXRhIGlzIG5vbi1zdGF0aW9uYXJ5Lg0KYGBgDQoNClRoZSBwLXZhbHVlIG9idGFpbmVkIGZyb20gdGhlIHRlc3QgaXMgMC40NDI0LCB3aGljaCBpcyBoaWdoZXIgdGhhbiB0aGUgdHlwaWNhbCBzaWduaWZpY2FuY2UgbGV2ZWwgb2YgMC4wNS4NClNpbmNlIHRoZSBwLXZhbHVlIGlzIGdyZWF0ZXIgdGhhbiAwLjA1LCB3ZSBmYWlsIHRvIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzIChIMCksIHdoaWNoIG1lYW5zIHRoYXQgdGhlIHRpbWUgc2VyaWVzIGRhdGEgKGluIHRoaXMgY2FzZSwgIkFkai5DbG9zZSIpIGlzIGNvbnNpZGVyZWQgbm9uLXN0YXRpb25hcnkuDQoNCiMjIERvZXMgdGltZSBzZXJpZXMgc2hvdyBzZXJpYWwgYXV0b2NvcnJlbGF0aW9uPw0KYGBge3J9DQojIFNlcmlhbCBBdXRvY29ycmVsYXRpb24NCiMgQUNGIHBsb3RzOiBjb3JyZWxhdGlvbiBiZXR3ZWVuIHR3byBwZXJpb2RzIGluIGEgdGltZSBzZXJpZXMgaXMgcmVmZXJyZWQgYXMgYXV0b2NvcnJlbGF0aW9uIGZ1bmN0aW9uIChhY2YpDQphY2YoSUIkQWRqLkNsb3NlLG1haW49IlNpZ25pZmljYW50IEF1dG9jb3JyZWxhdGlvbnMiKSAgIyBHZW5lcmFsbHksIG5vbi1zdGF0aW9uYXJ5IHRpbWUgc2VyaWVzIGRhdGEgc2hvdyB0aGUgcHJlc2VuY2Ugb2Ygc2VyaWFsIGF1dG9jb3JyZWxhdGlvbi4gIA0KDQpgYGANCg0KVGhlIGdyYXBoIHN1Z2dlc3QgdGhhdCB0aGVyZSBpcyBhIHNpZ25pZmljYW50IGF1dG9jb3JyZWxhdGlvbiBpbiB0aGUgdmFyaWFibGUgb2YgdGhlIG1vZGVsLCBnaXZpbmcgYXMgYSByZXN1bHQgdGhhdCBhIHBlcmlvZCBoYXZlIGEgc2lnbmlmaWNhbnQgaW1wYWN0IGZvciB0aGUgbmV4dCBwZXJpb2QgYmVoYXZpb3IsIHdoaWNoIGNhbiBiZWNvbWUgYSBwcm9ibGVtIGJlY2F1c2UgdGhlIG1vZGVsIG1heSBub3QgYmUgYWRlcXVhdGVseSBjYXB0dXJpbmcgdGhlIHN0cnVjdHVyZSBvZiB0aGUgdGltZSBzZXJpZXMuDQoNCiMjIEVzdGltYXRpbmcgbW9kZWxzLg0KDQpJbiBvcmRlciB0byBtYWtlIGRpZmZlcmVudCBtb2RlbHMsIHdlIGFyZSBnb2luZyB0byBjb21wYXJlIHBvc3NpYmxlIHJlc3VsdHMgdXNpbmcgImxvZyIgYW5kICJkaWZmIiB0byBnZXQgYSBzdGF0aW9uYXJ5IHRpbWUgc2VyaWVzIGRhdGEuDQpgYGB7cn0NCnBsb3QoSUIkRGF0ZSxsb2coSUIkQWRqLkNsb3NlKSwgdHlwZT0ibCIsY29sPSJibHVlIiwgbHdkPTIsIHhsYWIgPSJEYXRlIix5bGFiID0ibG9nKFN0b2NrIFByaWNlKSIsIG1haW4gPSAiSUJEUlkgU3RvY2sgUHJpY2UiKSAjY29udmVydMOtIHZhcmlhYmxlIGEgbG9nIHkgZXMgbXV5IHNpbWlsYXINCmBgYA0KDQpUcmFuc2Zvcm1pbmcgd2l0aCBsb2cgaXMgcmVhbGx5IHNpbWlsYXIgdG8gdGhlIG9yaWdpbmFsIG9uZS4NCmBgYHtyfQ0KYWRmLnRlc3QobG9nKElCJEFkai5DbG9zZSkpDQpgYGANCkl0IGlzIHN0aWxsIG5vbi1zdGF0aW9uYXJ5IGR1ZSB0aGUgcC12YWx1ZSBvZiAwLjUwNTkuDQoNCmBgYHtyfQ0KcGxvdChkaWZmKGxvZyhJQiRBZGouQ2xvc2UpKSx0eXBlPSJsIix5bGFiPSJmaXJzdCBvcmRlciBkaWZmZXJlbmNlIixtYWluID0gIkRpZmYgLSBHRSBTdG9jayBQcmljZSIpICNkaWZlcmVuY2lhcywgeWEgZXMgZXN0YWNpb25hcmlhDQpgYGANCkl0IGJlY29tZXMgZGlmZmVyZW50IHdoZW4gdXNpbmcgImRpZmYiIGFuZCAibG9nIi4gSXQgY291bGQgYmUgc3RhdGlvbmFyeS4NCg0KYGBge3J9DQphZGYudGVzdChkaWZmKGxvZyhJQiRBZGouQ2xvc2UpKSkNCmBgYA0KDQpXZSBnb3QgYSBwLXZhbHVlIG9mIDAuMDEgdXNpbmcgdGhpcyBvcHRpb24sIHdoaWNoIG1ha2UgdGhlIHRpbWUgc2VyaWVzIHN0YXRpb25hcnkuIFRoaXMgaXMgb25lIG9mIHRoZSBvcHRpb25zIHRoYXQgd2UgY2FuIHRlc3QuDQoNCg0KIyMjIDEuIEFSTUEgV2l0aCBsb2cuDQpUcmFuc2Zvcm1pbmcgdGhlIHZhcmlhYmxlIGludG8gbG9nLCBpbiBvcmRlciB0byBnZXQgc3RhdGlvbmFyeSB0aW1lIHNlcmllcyBkYXRhLg0KV2hlbiBtb2RlbGluZywgZml0dGVkLnZhbHVlcyB3aWxsIGNvbnRhaW4gYSBudWxsIHRoYXQgZG9lc24ndCBhbGxvdyB0byBjb250aW51ZSBkb2luZyBvcGVyYXRpb25zLCBzbyB3ZSBhcmUgZ29pbmcgdG8gb21pdCBpdC4gVGhpcyBhbHNvIGhhcHBlbnMgaW4gdGVhY2hlcidzIGNvZGUuIFRoaXMgdXNlIHRvIGJlIGJlY2F1c2UgdGhlIGZpcnN0IHZhbHVlIG9mIHRoZSBvcmlnaW5hbCBkYXRhIGRvZXMgbm90IGhhdmUgYW55dGhpbmcgYmVmb3JlIHRvIGJlIGNvbXBhcmVkLg0KDQpgYGB7cn0NCiMgdGltZSBzZXJpZXMgbW9kZWxpbmcgDQpzdW1tYXJ5KElCX0FSTUE8LWFybWEobG9nKElCJEFkai5DbG9zZSksb3JkZXI9YygxLDEpKSkNCmBgYA0KV2UgZ290IGEgbmVnYXRpdmUgQUlDIHZhbHVlLCB3aGljaCBjb3VsZCBiZSBhIGdvb2QgcGFyYW1ldGVyIHRvIGV2YWx1YXRlIHRoZSBtb2RlbCBsYXRlci4gSXQgaXMgYWxzbyBpbnRlcmVzdGluZyB0byBzZWUgdGhlIGNvZWZmaWNpZW50cyBmb3IgYXIxIGFuZCBtYTEsIHRoZSBhcjEgY29lZmZpY2llbnQgaXMgMC45OTU3MzQsIHdoaWNoIGNvdWxkIGJlIGludGVycHJldGVkIGFzIGEgZ3JlYXQgaW1wYWN0IGluIHRoZSBlc3RpbWF0aW5nIG1vZGVsLCBpdCBpcyBhbHNvIHRoZSBtb3JlIHNpZ25pZmljYW50IG9uZS4gVGhlIGNhdXNlIGZvciB0aGlzIHJlc3VsdHMgY291bGQgYmUgdGhlIG5vbi1zdGF0aW9uYXJ5IHRpbWUgc2VyaWVzIGRhdGEuDQoNCmBgYHtyfQ0KSUJfQVJNQSRmaXR0ZWQudmFsdWVzIDwtIG5hLm9taXQoSUJfQVJNQSRmaXR0ZWQudmFsdWVzKQ0KYGBgDQoNCldlIHRyYW5zZm9ybWVkIHRoZSB2YXJpYWJsZSB0byBsb2csIGJ1dCBpbiBvcmRlciB0byBnZXQgdGhlIGNvcnJlY3QgdmFsdWVzIGluIGl0cyBvcmlnaW5hbCBmb3JtYXQsIGl0IGlzIG5lY2Vzc2FyeSB0byBhcHBseSBleHAuDQoNCmBgYHtyfQ0KSUJfZXN0aW1hdGVkX3N0b2NrX3ByaWNlPC1leHAoSUJfQVJNQSRmaXR0ZWQudmFsdWVzKQ0KYGBgDQoNCk5vdyB3ZSBjYW4gcGxvdCB0aGUgcmVzdWx0Lg0KDQpgYGB7cn0NCnBsb3QoSUJfZXN0aW1hdGVkX3N0b2NrX3ByaWNlKQ0KYGBgDQoNCiMjIyAyLiBBUk1BIFdpdGggbG9nIGFuZCBkaWZmLg0KDQpJdCBpcyBuZWNlc3NhcnkgdG8gdHJhbnNmb3JtIHRoZSB2YXJpYWJsZSB0byBsb2cgYW5kIGRpZmYgYmVjYXVzZSBvZiBub24tc3RhdGlvbmFyeSB0aW1lIHNlcmllcyBkYXRhLiBBcyB3ZSBzYXcgYmVmb3JlLCB0aGlzIGNvbWJpbmF0aW9uIGNhbiB0cmFuc2Zvcm0gYSBub24tc3RhdGlvbmFyeSB0aW1lIHNlcmllcyB0byBhIHN0YXRpb25hcnkgb25lLg0KYGBge3J9DQojIHRpbWUgc2VyaWVzIG1vZGVsaW5nIA0Kc3VtbWFyeShJQl9BUk1BMjwtYXJtYShkaWZmKGxvZyhJQiRBZGouQ2xvc2UpLG9yZGVyPWMoMSwxKSkpKQ0KYGBgDQoNCkFsdGhvdWdoIHdlIGdvdCBhIGhpZ2hlciBBSUMgdmFsdWUsIGNvZWZmaWNpZW50cyBhbmQgc2lnbmlmaWNhbmNlIGZvciBmYWN0b3JzIGNoYW5nZWQsIGJ1dCBpZiB0aGlzIG1vZGVsIGlzIGNhbGN1bGF0ZWQgd2l0aCBzdGF0aW9uYXJ5IGRhdGEsIGl0IGNvdWxkIGJlIGJldHRlciBkdWUgdGhlIHJpc2sgb2YgZm9yZWNhc3Rpbmcgd2l0aCBub24tc3RhdGlvbmFyeS4NCkZvciB0aGUgbmV4dCBwYXJ0LCBpdCB3aWxsIGJlIG5lY2Vzc2FyeSB0byBvbWl0IG51bGwgdmFsdWVzLCBhbmQgdHJhbnNmb3JtIHRoZSBmaXR0ZWQudmFsdWVzIG9mIHRoZSBtb2RlbCBpbnRvIGl0cyBvcmlnaW5hbCBmb3JtLCByZXZlcnNpbmcgbG9nIGFuZCBmaXJzdCBvcmRlcmluZyBkaWZmZXJlbmNlLg0KDQpXZSBuZWVkIHRvIGNvbnZlcnQgdGhlc2UgdmFsdWVzIGludG8gYSB2ZWN0b3IgImMiIGR1ZSB0aGUgZGlmZmVyZW50IGxlbmd0aCBiZXR3ZWVuIGZpdHRlZC52YWx1ZXMgYW5kIHRoZSBvcmlnaW5hbCBvbmVzLCB0aGF0IHdlIHdpbGwgYmUgbmVlZGluZyBpdCB0byByZXZlcnNlIHRoZSAiZGlmZiIgdHJhbnNmb3JtYXRpb24uIEhhdmluZyB0aGlzIHRpbWUgc2VyaWVzIGFzIHZlY3RvciBhbGxvd3MgdG8gc3VtIHRoZW0gdXAsIGRlc3BpdGUgb2YgbGVuZ3RoIGRpZmZlcmVuY2UuIEZpbmFsbHksIHdlIGFyZSBnb2luZyB0byBjb252ZXJ0IHRoZW0gaW50byB0aW1lIHNlcmllcyBhZ2FpbiwgaW4gb3JkZXIgdG8gbWFrZSBhIGZvcmVjYXN0Lg0KDQpgYGB7cn0NCklCX0FSTUEyJGZpdHRlZC52YWx1ZXMgPC0gbmEub21pdChJQl9BUk1BMiRmaXR0ZWQudmFsdWVzKQ0KZnZfZXhwPC1jKGV4cChJQl9BUk1BMiRmaXR0ZWQudmFsdWVzKSkgI3JldmVydGluZyAibG9nIiBvcGVyYXRpb24gdXNpbmcgImV4cCINCklCdjwtYyhJQiRBZGouQ2xvc2UpICNDb252ZXJ0aW5nIHRoZSBvcmlnaW5hbCB2YWx1ZXMgaW50byBhIHZlY3Rvci4NCkZpeGVkX1ZhbHVlczwtZnZfZXhwK0lCdiAjcmV2ZXJ0aW5nICJkaWZmIiBvcGVyYXRpb24gc3VtbWluZyB0aGUgb3JpZ2luYWwgdmFsdWVzIHRvIHRoZSBkaWZmZXJlbmNlcy4NCnRzX0ZpeGVkX1ZhbHVlcyA8LSB0cyhGaXhlZF9WYWx1ZXMsIHN0YXJ0ID0gMSwgZW5kID0gbGVuZ3RoKEZpeGVkX1ZhbHVlcyksIGZyZXF1ZW5jeSA9IDEpICNNYWtlIGl0IHRpbWUgc2VyaWVzDQpgYGANCg0KDQpOb3cgd2UgY2FuIHBsb3QgdGhlIHJlc3VsdC4NCg0KDQpgYGB7cn0NCnBsb3QodHNfRml4ZWRfVmFsdWVzKQ0KYGBgDQoNCg0KIyMjIEFSSU1BIE1PREVMDQoNCmBgYHtyfQ0KSUJfQVJJTUEgPC0gQXJpbWEoSUIkQWRqLkNsb3NlLG9yZGVyPWMoMSwxLDEpKQ0Kc3VtbWFyeShJQl9BUklNQSkNCmBgYA0KYGBge3J9DQpwbG90KElCX0FSSU1BJGZpdHRlZCkNCmBgYA0KYGBge3J9DQp0c19JQiA8LSBJQiRBZGouQ2xvc2UNCmV0c19tb2RlbCA8LSBldHModHNfSUIpDQpmb3JlY2FzdF92YWx1ZXMgPC0gZm9yZWNhc3QoZXRzX21vZGVsLCBoID0gMTApDQpwcmludChmb3JlY2FzdF92YWx1ZXMpDQpwbG90KGZvcmVjYXN0X3ZhbHVlcywgbWFpbiA9ICJFVFMgTW9kZWwiKQ0KYGBgDQoNCg0KIyBFdmFsdWF0ZQ0KDQoNCmBgYHtyfQ0KIyBtb2RlbCBldmFsdWF0aW9uIA0KIyBUZXN0aW5nIHNlcmlhbCBhdXRvY29ycmVsYXRpb24gaW4gcmVncmVzc2lvbiByZXNpZHVhbHMgDQojIEhvOiBUaGVyZSBpcyBubyBzZXJpYWwgYXV0b2NvcnJlbGF0aW9uIA0KIyBIYTogVGhlcmUgaXMgc2VyaWFsIGF1dG9jb3JyZWxhdGlvbg0KSUJfQVJNQV9yZXNpZHVhbHM8LUlCX0FSTUEkcmVzaWR1YWxzDQpCb3gudGVzdChJQl9BUk1BX3Jlc2lkdWFscyxsYWc9NSx0eXBlPSJManVuZy1Cb3giKSAgDQojIEFjY2VwdCB0aGUgSG8uIFRoZSBQLXZhbHVlIGlzID4gMC4wNSBpbmRpY2F0aW5nIHRoYXQgQVJNQSBtb2RlbCBkb2VzIG5vdCBzaG93IHJlc2lkdWFsIHNlcmlhbCBhdXRvY29ycmVsYXRpb24uIA0KYGBgDQpgYGB7cn0NCmFkZi50ZXN0KElCX0FSTUEkZml0dGVkLnZhbHVlcykgI3RoaXMgdGVzdCB3YXMgYmVpbmcgYXBwbGllZCB0byB0aGUgdmFyaWFibGUgd2l0aCBmaXhlZCB2YWx1ZXMuDQojIFRoYXQncyB3aHkgd2UgYXJlIGFsd2F5cyBnb2luZyB0byBoYXZlIGEgc2ltaWxhciBwLXZhbHVlIGluIHRoaXMgdGVzdCwgYW5kIHRoZSBwcmV2aW91cyBvbmUuDQojIEl0IG5lZWRzIHRvIGJlIGFwcGxpZWQgdG8gZml0dGVkLnZhbHVlcyBvZiB0aGUgbW9kZWwsIGluIG9yZGVyIHRvIGdldCBhIHJlYWwgcC12YWx1ZS4NCmBgYA0KcC12YWx1ZSBmb3IgIkxqdW5nLUJveCIgaW5kaWNhdGVzIHRoYXQgdGhpcyBtb2RlbCBkb2VzIG5vdCBzaG93IHJlc2lkdWFsIHNlcmlhbCBhdXRvY29ycmVsYXRpb24sIGJ1dCB3ZSBjYW4ndCBpZ25vcmUgdGhlIGZhY3QgdGhhdCBwLXZhbHVlIGZvciBhdWdtZW50ZWQgRGlja2V5LUZ1bGxlciBUZXN0IHNob3dzIHRoYXQgSDAgY291bGQgYmUgbm90IHJlamVjdGVkLCB3aGljaCBtZWFucyB0aGF0IHRpbWUgc2VyaWVzIG1vZGVsIGlzIG5vbi1zdGF0aW9uYXJ5LiBGb3JlY2FzdGluZyB3aXRoIG5vbi1zdGF0aW9uYXJ5IHNlcmllcyBtaWdodCBicmluZyBpbmNvcnJlY3QgZm9yZWNhc3RzLg0KDQoNCmBgYHtyfQ0KSUJfQVJNQTJfcmVzaWR1YWxzPC1JQl9BUk1BMiRyZXNpZHVhbHMNCkJveC50ZXN0KElCX0FSTUEyX3Jlc2lkdWFscyxsYWc9NSx0eXBlPSJManVuZy1Cb3giKSAgDQojIEFjY2VwdCB0aGUgSG8uIFRoZSBQLXZhbHVlIGlzID4gMC4wNSBpbmRpY2F0aW5nIHRoYXQgQVJNQSBtb2RlbCBkb2VzIG5vdCBzaG93IHJlc2lkdWFsIHNlcmlhbCBhdXRvY29ycmVsYXRpb24uIA0KYGBgDQpgYGB7cn0NCmFkZi50ZXN0KElCX0FSTUEyJGZpdHRlZC52YWx1ZXMpDQojVGhlc2UgdmFsdWVzIGFyZSB0aGUgcmVzdWx0IG9mIHVzaW5nIG1vZGVsIEFSTUEgaW4gdGhlIG9yaWdpbmFsIHRpbWUgc2VyaWVzLCB0cmFuc2Zvcm1pbmcgaXQgaW50byBsb2cgYW5kIGRpZmYuDQpgYGANCkZvciB0aGlzIG1vZGVsLCB3ZSBnb3QgYSBoaWdoZXIgcC12YWx1ZSBmb3IgcmVzaWR1YWxzLCBpbmRpY2F0aW5nIHRoYXQgdGhpcyBtb2RlbCBkb2VzIG5vdCBoYXZlIHJlc2lkdWFsIHNlcmlhbCBhdXRvY29ycmVsYXRpb24sIGluIGFkZGl0aW9uLCB0aGlzIG1vZGVsIGhhcyBhIHAtdmFsdWUgZm9yIEFERiB0ZXN0IG9mIDAuMDEsIHdoaWNoIHJlamVjdCB0aGUgSDAgaHlwb3RoZXNpcywgbWVhbmluZyB0aGF0IHdlIGhhdmUgYW4gc3RhdGlvbmFyeSB0aW1lIHNlcmllcy4NCg0KYGBge3J9DQpJQl9BUklNQV9SRVNJRFVBTFM8LUlCX0FSSU1BJHJlc2lkdWFscw0KQm94LnRlc3QoSUJfQVJJTUFfUkVTSURVQUxTLGxhZz01LHR5cGU9IkxqdW5nLUJveCIpICANCiMgQWNjZXB0IHRoZSBIby4gVGhlIFAtdmFsdWUgaXMgPiAwLjA1IGluZGljYXRpbmcgdGhhdCBBUk1BIG1vZGVsIGRvZXMgbm90IHNob3cgcmVzaWR1YWwgc2VyaWFsIGF1dG9jb3JyZWxhdGlvbi4gDQpgYGANCmBgYHtyfQ0KYWRmLnRlc3QoSUJfQVJJTUEkZml0dGVkKQ0KYGBgDQpUaGUgZmlyc3QgY2FzZSBpcyByZXBlYXRlZCBvbiBBUklNQSBtb2RlbCwgd2UgaGF2ZSBhbiBBREYgcC12YWx1ZSBoaWdoZXIgdGhhbiAwLjA1LCB3aGljaCBtZWFucyB0aGF0IHdlIGNhbiBub3QgcmVqZWN0IHRoZSBIMCwgbWVhbmluZyB0aGF0IHRoaXMgbW9kZWwgbWlnaHQgaGF2ZSBhIG5vbi1zdGF0aW9uYXJ5IHRpbWUgc2VyaWVzIGRhdGEuDQoNCg0KIyMgQ2hvb3NpbmcgYSBtb2RlbC4NCg0KSGF2aW5nIHRoZSByZXN1bHRzIGZvciB0aGUgZGlhZ25vc3RpYyB0ZXN0cyBvZiB0aGUgdGhyZWUgbW9kZWxzLCB3ZSBjYW4gbWFrZSBhIGRlY2lzaW9uIGFib3V0IHdoaWNoIG9uZSB0byB1c2UgZm9yIGdlbmVyYXRpbmcgcG90ZW50aWFsbHkgYWNjdXJhdGUgZm9yZWNhc3RzLiBCYXNlZCBvbiB0aGVzZSByZXN1bHRzLCB3ZSBoYXZlIGRlY2lkZWQgKip0byB1c2UgbW9kZWwgMioqLCB3aGljaCB0cmFuc2Zvcm1zIHRoZSB0aW1lIHNlcmllcyBpbnRvIGEgbG9nYXJpdGhtaWMgYW5kIGRpZmZlcmVuY2VkIGZvcm1hdC4gVGhpcyBhcHByb2FjaCBoZWxwcyBhY2hpZXZlIGEgc3RhdGlvbmFyeSB0aW1lIHNlcmllcywgcmVkdWNpbmcgdGhlIG1hcmdpbiBvZiBlcnJvciB3aGVuIG1ha2luZyBmb3JlY2FzdHMuDQoNCg0KIyBGb3JlY2FzdA0KDQpgYGB7cn0NCiMgZm9yZWNhc3RpbmcgKEFSTUEyKQ0KSUJfQVJNQTJfZm9yZWNhc3Q8LWZvcmVjYXN0KHRzX0ZpeGVkX1ZhbHVlcyxoPTUpICNoPTUgZm9yIDUgcGVyaW9kcy4NCklCX0FSTUEyX2ZvcmVjYXN0DQpgYGANCg0KDQpXaGVuIGdlbmVyYXRpbmcgYSBmb3JlY2FzdCB3aXRoIHRoaXMgbW9kZWwsIHdlIGNhbiBvYnRhaW4gYW4gZXN0aW1hdGUgb2Ygd2hhdCB0aGUgc3RvY2sgcHJpY2UgZm9yIHRoZSBuZXh0IDUgcGVyaW9kcyBjb3VsZCBiZS4gVGFraW5nIGludG8gYWNjb3VudCBhIDk1JSBjb25maWRlbmNlIGxldmVsLCB0aGVzZSB2YWx1ZXMgd291bGQgYmUgYXMgZm9sbG93czoNCg0KKiBQZXJpb2QgMTogUHJpY2UgYmV0d2VlbiAkNDIuODkgYW5kICQ0OC43OQ0KKiBQZXJpb2QgMjogUHJpY2UgYmV0d2VlbiAkNDEuOTEgYW5kICQ0OS43Nw0KKiBQZXJpb2QgMzogUHJpY2UgYmV0d2VlbiAkNDEuMTIgYW5kICQ1MC41Ng0KKiBQZXJpb2QgNDogUHJpY2UgYmV0d2VlbiAkNDAuNDUgYW5kICQ1MS4yMw0KKiBQZXJpb2QgNTogUHJpY2UgYmV0d2VlbiAkMzkuODUgYW5kICQ1MS44Mg0KDQpUaGUgZ3JhcGhzIGZvciB0aGlzIGZvcmVjYXN0IGFyZSBwbG90dGVkIGJlbG93Lg0KYGBge3J9DQpwbG90KElCX0FSTUEyX2ZvcmVjYXN0KQ0KYXV0b3Bsb3QoSUJfQVJNQTJfZm9yZWNhc3QpDQpgYGANCg0KDQoNClJlZmVyZW5jZXM6DQoNCkliZXJkcm9sYSBTQSAoMjAyMykuIEliZXJkcm9sYS4gaHR0cHM6Ly93d3cuaWJlcmRyb2xhLmNvbS9jb25vY2Vub3MvbnVlc3RyYS1lbXByZXNhIA==