Workshop 4, Financial Econometrics II Alberto Dorantes, Ph.D. Mar 15, 2022

Abstract

In this workshop we learn how to design/calibrate a seasonal ARIMA model (SARIMA) for a time series.

Introduction to ARIMA-SARIMA Models

A seasonal ARIMA model, also called ARIMA/SARIMA model, is usually applied to monthly or quarterly time series. This model is very effective for any of the following type of economic/financial series:

Historical monthly or quarterly sales data

Historical monthly or quarterly price data

Historical monthly or quarterly data related to any variable of any financial statement. For example: cost of good sold, sales and general administrative expenses, income tax, EBIT, etc.

Historical monthly or quarterly data related to any macro economic variable. For example: inflation indexes, GDP indexes, exchange rates, etc.

These models are not so effective for daily stock prices or financial indexes. The main reason is that one of the most important conditions for a financial market to exist is that no body can predict stock prices since the log of stock prices are supposed to behave as a Random Walk! However, these models are useful in this context compared to just doing intuitive guesses.

Calibration Steps for ARIMA-SARIMA

Each ARIMA-SARIMA model needs to be CALIBRATED. The general steps to calibrate a model are the following:

Check if the series has seasonality. If the series shows a seasonal pattern, start with the seasonal difference of the log of the series, which is the % annual growth of the series. Usually monthly and quarterly data of many economic and financial series have seasonal pattern. I recommend that if you have monthly or quarterly data of any financial or economic variable, start testing whether the seasonal difference of the log of the series is stationary. If you have daily data, it is hard to model for seasonality. In the case of daily data, start testing whether the first difference of the log is stationary.

In this step you start with a version of the series.

For next steps we will assume that we decided to use the seasonal difference of the log of the series.

Test whether the seasonal difference is stationary. If so, continue to next step. If not, then change the variable to the first difference of the log of the series, which is the % change for each period. Most of the economic and financial series become stationary with the first log difference.

Run the ACF and PACF plots to identify the ARIMA-SARIMA parameters p, d, q, P, D, Q. The ACF is the auto-correlation plot, and the PACF is the partial autocorrelation plot. Both plots show auto*correlations between the variable and its own lags.

An ARIMA/SARIMA model has the following “parameters” that need to be defined:

arima(p,d,q) sarima(P,D,Q,#Periods)

p: refers to the number of autoregressive (AR) terms. Usually this parameter is either 0,1 or 2.

d: refers to how many first differences where needed to the series in order to make the series stationary. Usually this parameter is either 0 or 1.

q: refers to the number of moving average (MA) terms in the model. Usually this parameter is either 0,1 or 2.

P: refers to the number of SEASONAL autoregressive terms. Usually this parameter is either 0 or 1.

D: refers to how many SEASONAL differences were needed to the series to make the series stationary. Usually this parameter is either 0 or 1.

Q: refers to the number of SEASONAL moving average terms. Usually this parameter is either 0 or 1.

#periods: refers to the number of periods in the year. For example, if the data is monthly, then #periods=12.

These parameters are usually expressed as: ARIMA(p,d,q) SARIMA(P,D,Q, #periods).

When you identify the first values of these paremeters, then you will have your first CALIBRATION of the model.

Estimate/Run the ARIMA-SARIMA model

Run the ACF and PACF of the residuals/errors of the model to check whether the errors is a white noise series. In other words, if there is no significant autocorrelations of the errors.

If there is one or more significant autocorrelations, we can include other term(s) in the ARIMA-SARIMA model, and go back to step 4.

If there the errors seem like a white noise (no signficant autocorrelations), then we can continue and finish the calibration process.

Interpret the model

Run a forecast using the model

Let’s start practicing with these models.

Example - model for air passengers

Identifying seasonality in a time-series

We will work with a simple dataset that has the number of air passengers of an US Airline. This series might have a strong seasonality since people used to fly in vacation periods, which is the the same each year.

Download the excel file from a web site:

download.file("http://www.apradie.com/ec2004/air2.xlsx", "air2.xlsx", mode="wb")
trying URL 'http://www.apradie.com/ec2004/air2.xlsx'
Content type 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' length 5924 bytes
==================================================
downloaded 5924 bytes

In order to read Excel files, we need the readxl package:

library(readxl)

Now, we read the data from the Excel file:

dataset <- read_excel("air2.xlsx")
# I familiarize with the data
head(dataset)

In order to perform time-series analysis, it is better to use xts objects. We can construct this by using the xts() method of the xts package. Objects of class xts are composed by 2 elements: the core data and the index (class Date, POSIX,etc).

# Load library xts and zoo. Install the packages if you haven't already.
library(xts)
library(zoo)
library(tseries)
library(forecast)


# I get the date of the dataset:
date <- dataset$month
# I join both objects using xts() and assign it to a new object called air.xts
air.xts<- xts(x=dataset$air, frequency = "monthly", order.by=date)
names(air.xts)<-c("Passengers")
class(air.xts)
[1] "xts" "zoo"
# I see behaviour of air passengers over time 
plot(air.xts$Passengers)

This dataset contains air passengers by month from an airline. Do the following:

Does the series look stationary? Obviously not, it looks with a clear growing trend, and a seasonality pattern. The mean of the series GROWS OVER TIME.

Get the natural logarithm of the series:

lnair.xts = log(air.xts)

Testing for stationary

Since we see a clear seasonality pattern, it is strongly recommended to use the seasonal difference of the log of the series. So, we will check whether we can treat the seasonal difference of the log as STATIONARY.

We start by plotting the seasonal difference of the log, which is the annual % growth (in cc) of the air passengers:

plot(diff(lnair.xts,lag=12))

It is hard to see whether this is stationary or not, so we have to run the Dicky-Fuller test. Run the Dicky-Fuller test using the adf.test function of the tseries packages.

adf.test(na.omit(diff(lnair.xts,lag=12)),alternative="stationary",k=0)
Warning in adf.test(na.omit(diff(lnair.xts, lag = 12)), alternative = "stationary",  :
  p-value smaller than printed p-value

    Augmented Dickey-Fuller Test

data:  na.omit(diff(lnair.xts, lag = 12))
Dickey-Fuller = -4.988, Lag order = 0, p-value = 0.01
alternative hypothesis: stationary

We got a p-value<0.05, so we can treat the seasonal difference (the annual % growth) as stationary and continue with this series to calibrate an ARIMA-SARIMA model.

ACF and PACF plots

Once we confirm that our series is stationary, then the first step is to do the AC and PAC plots to identify how many AR and MA terms we can include in our ARIMA/SARIMA model.

Remember that we can compute the autocorrelation plots with the acf2 function from the astsa package. Let’s examine the autocorrelations of our series. Remember that our series is the seasonal difference of the log of air passengers, which is the annual % growth of air passengers month by month.

library(astsa)

Attaching package: ‘astsa’

The following object is masked from ‘package:forecast’:

    gas
# I create a ts object from the xts; the acf2 works better with ts objects
lnair =ts(lnair.xts$Passengers)
acf2(diff(lnair,lag=12))
     [,1] [,2]  [,3] [,4] [,5]  [,6]  [,7] [,8]  [,9] [,10]
ACF  0.71 0.62  0.48 0.44 0.39  0.32  0.24 0.19  0.15 -0.01
PACF 0.71 0.23 -0.06 0.10 0.05 -0.06 -0.06 0.01 -0.01 -0.29
     [,11] [,12] [,13] [,14] [,15] [,16] [,17] [,18] [,19]
ACF  -0.11 -0.24 -0.14 -0.14 -0.10 -0.15 -0.10 -0.11 -0.14
PACF -0.16 -0.14  0.29  0.06  0.05 -0.04  0.13 -0.06 -0.15
     [,20] [,21] [,22]
ACF  -0.16 -0.11 -0.08
PACF -0.02  0.12 -0.18

I used the ts function to transform the dataset into a ts dataset since this type of R object will allow us to easily run and forecast arima-sarima models.

ACF and PACF interpretation

The ACF shows the autocorrelations (AC) between the series and its lags, and the PACF shows the partial autocorrelations (PAC) between the series and its lags.

The VERTICAL lines show the MAGNITUD of the AUTOCORRELATION between a LAG and the current value of the series.

The blue horizontal dotted lines in the plots cover the 95% confidence interval for the autocorrelations. So, if the vertical line croses the blue dotted line, it means that that specific autocorrelation is SIGNIFICANTLY DIFFERENT THAN ZERO (it could be positive or negative).

Now what is the general interpretation of the these plots?

First, we always have to remember what we are modelling. In this case we are modelling the seasonal difference of the log, which is the ANNUAL % GROWTH of passengers month by month.

In the ACF plot I see that the first 8 ACs are positive and significant, and they gradually decay. For example, the AC of LAG 1 is about 70% (almost 0.70). This means that ANNUAL % growth of air passengers is strongly correlated (with a correlation of 70%) with ITS OWN ANNUAL % GROWTH of the PREVIOUS month (its LAG 1).

The AC of LAG 2 is about 62%, so the ANNUAL % GROWTH of passengers is strongly correlated with ITS OWN ANNUAL % GROWTH of 2 MONTHS AGO (its LAG 2)… and so on.

It is important to mention that the ACF plot shows autocorrelations independently of each other.

In the case of PACF, we see PARTIAL autocorrelations, which measure HOW MUCH ELSE the series is correlated with each its own LAGS, AFTER CONSIDERING the effect of LOWER-ORDER LAG AUTOCORRELATIONS.

I see that the PACF shows only the first 2 autocorrelations to be positive AND SINGIFICANT, and the magnitude of the following autocorrelations goes down to zero or negative very quickly.

When the ACF plot shows a SLOW DECLINE of autocorrelations, and the PACF shows a FAST DECLINE of autocorrelatinos, this is a clear PATTERN OF AN AR(p) MODEL. In this case, the # of AR terms is determined by the SIGNIFICANT LAGS in the PACF plot.

We see that also the AC of LAG 10 is statistically significant and negative, but it is recommended first to start with the AR(2) model, and then check the residuals of the model to see whether there is another significant lag.

Then, in this case we start with an ARIMA with p=2 and q=0.

Read Dr. Nau slides to review more PATTERNS of ACF and PACF plots.

Estimate the ARIMA-SARIMA model

In this case, I can start with the following calibration. Now we can use the log series, and leave the model to automatically calculate the SEASONAL difference. Then, I will use the log of the series (log of air passengers) and define my model as:

arima(p,d,q) sarima(P,D,Q,#periods in the year)

In our example, the values for the parameters are:

arima(2,0,0) sarima(0,1,0,12)

What this model tells us?

You first have to look at the # of periods. In this case, you have 12 periods in a year, so your series should be monthly.

Then you look at d and D (first differences and the seasonal differences). In this case, d=0 and D=1. What does this mean? this means that we are modeling the SEASONAL difference (D=1) of the log of the variable, which is the annual % growth (month by month). Since d=0 this means that we are NOT using the first difference of the series.

Then you look at the p, q, P, Q. p tells you how many AR terms are included in your model. In this case, p=2, so your model includes the first 2 AR terms. Since q, P and Q are zero, then your model does not include any of these type of terms.

How this model can be expressed mathematically?

Since you are modeling the seasonal difference, you can express this model as the following equation:

△12lnair=ϕ0+ϕ1(L1△12lnairt)+ϕ2(L2△12lnairt)+εt

Using a simpler notation, this equation can be expressed as:

s12.lnairt=ϕ0+ϕ1L1.s12.lnairt+ϕ2L2.s12.lnairt+εt

Remember that s12.lnair is the seasonal difference of the log of air passengers, which is the annual %growth of air passengers month by month. Then we can read this mathematical expression as: “The annual %growth (month by month) of air passengers at time t can be determined by its own annual % growth of air passengers at time t-1 and t-2 (the %growth of the previous 2 months), and by a random shock”

Running the ARIMA/SARIMA

Now we can estimate the ARIMA-SARIMA model using the Arima function of the forecast package.

In this case, instead of creating a variable for the seasonal difference of the log (s12.lnair), we will configure the parameters of the Arima function so that the log transformation and the seasonal difference will be calculated before estimating the arima coefficients.

In our first calibration we discussed above, we defined the following values of the ARIMA-SARIMA model for the log of the number of air passengers:

arima(2,0,0) sarima(0,1,0,12)

This means that D=1, so R will calculate the seasonal difference, and then estimate the arima model and include 2 AR terms and no MA terms.

We can run this model in R as follows:

m1 <- Arima(air.xts$Passengers, # We use the Passengers column of the dataset
        order = c(2,0,0), # we indicate that p=0; d=0; q=0 
        seasonal = list(order=c(0,1,0),period=12), #P=0; D=1; Q=0, #periods=12
        include.constant = TRUE, # Here we indicate to include the phi0 coefficient
        lambda = 0) # Here we indicate to apply the natural log to the series  
m1
Series: air.xts$Passengers 
ARIMA(2,0,0)(0,1,0)[12] with drift 
Box Cox transformation: lambda= 0 

Coefficients:
         ar1     ar2   drift
      0.5540  0.2378  0.0096
s.e.  0.0845  0.0848  0.0014

sigma^2 = 0.001742:  log likelihood = 233.13
AIC=-458.26   AICc=-457.95   BIC=-446.73

If we set lamda = 0 this means that the the model will use the log of the variable (passengers); this is one of the Box-Jenkins mathematical transformations, and it is the most common for financial and economic series.

We can alternatively use the function sarima from the astsa model to run the same arima model. The sarima function provides more detail in the output, but the Arima function has advantages when we want to get the forecast with the model. We run sarima for the same model as:

m1a<-sarima(log(air.xts$Passengers), p=2, d=0, q=0,P=0,D=1,Q=0,S=12)
initial  value -2.794390 
iter   2 value -2.940651
iter   3 value -3.175869
iter   4 value -3.186870
iter   5 value -3.189461
iter   6 value -3.189605
iter   7 value -3.189606
iter   8 value -3.189607
iter   9 value -3.189607
iter  10 value -3.189608
iter  11 value -3.189609
iter  12 value -3.189609
iter  12 value -3.189609
iter  12 value -3.189609
final  value -3.189609 
converged
initial  value -3.184486 
iter   2 value -3.184596
iter   3 value -3.184959
iter   4 value -3.185009
iter   5 value -3.185059
iter   6 value -3.185073
iter   7 value -3.185076
iter   8 value -3.185076
iter   8 value -3.185076
final  value -3.185076 
converged

m1a
$fit

Call:
arima(x = xdata, order = c(p, d, q), seasonal = list(order = c(P, D, Q), period = S), 
    xreg = constant, transform.pars = trans, fixed = fixed, optim.control = list(trace = trc, 
        REPORT = 1, reltol = tol))

Coefficients:
         ar1     ar2  constant
      0.5540  0.2378    0.0096
s.e.  0.0845  0.0848    0.0014

sigma^2 estimated as 0.001701:  log likelihood = 233.13,  aic = -458.26

$degrees_of_freedom
[1] 129

$ttable
         Estimate     SE t.value p.value
ar1        0.5540 0.0845  6.5597  0.0000
ar2        0.2378 0.0848  2.8037  0.0058
constant   0.0096 0.0014  6.8655  0.0000

$AIC
[1] -3.471669

$AICc
[1] -3.470249

$BIC
[1] -3.384312

As we see, we need to take the log first and then specify the model. The result is exactly the same as the Arima result, but with sarima we can see the coefficients, their p-values and other important plots of the model. Also, we can see important plots such as ACF of the errors.

Interpretation of an ARIMA-SARIMA model

Since the Arima function does not display the p values and t values of the coefficients, we can use the function coeftest from the lmtest library.

You have to install the lmtest library and the load it:

library(lmtest)

Now we can see the coefficients and their corresponding standard error, pvalue and t value. We apply the coeftest function to the m1 model created with Arima:

coeftest(m1)

z test of coefficients:

       Estimate Std. Error z value  Pr(>|z|)    
ar1   0.5540129  0.0844571  6.5597 5.392e-11 ***
ar2   0.2377939  0.0848135  2.8037  0.005052 ** 
drift 0.0095854  0.0013962  6.8655 6.625e-12 ***
---
Signif. codes:  
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

The drift coefficient is the phi0 coefficient. phi0 and both lags are positive and SIGNIFICANT. What does this mean? First, I have to remember which variable I am modelling. I am modeling the seasonal difference of log passengers, which is the annual % growth of air passengers month by month. Then, I can interpret this ARIMA-SARIMA model as follows:

The annual % growth of air passengers is positively and significantly related with its annual % growth of air passengers of last month (lag1). In a similar way, the annual % growth of air passengers is positively and significantly related with the annual % growth of two months ago. More specifically, 55.4% of annual growth of last month is passed to this month’s annual % growth, and only 23.78% of the annual growth of 2 months ago is passed to the current annual % growth.

In other words, for each percentual point of annual growth of previous month, it is expected that the current annual growth will grow about 0.55 percent points

It is interesting to see that the sum of phi1 and phi2 (0.55+0.23) MUST be < 1 in order for the series to be stationary. If you include more arima terms, the sum of the phi’s must be less than one. If you include MA terms, the sum of the theta coefficients also must be less than one. In addition, the constant or phi0 is positive and significant, indicating that the annual growth of air passengers has a positive tendency to grow over time.

The mathematical model is:

E[s12.lnair]=0.0096+0.554∗L1.s12.lnair+0.2378∗L2.s12.lnair or s12.lnair=0.0096+0.554∗L1.s12.lnair+0.2378∗L2.s12.lnair+error

Autocorrelations of the Model residuals/errors

We need to generate a series for the residuals of the ARIMA-SARIMA model. To do this, get the residuals as follows:

air_res <- m1$residuals
head(air_res)
Time Series:
Start = 1 
End = 432001 
Frequency = 1.15740740740741e-05 
[1] 0.004708908 0.004751501 0.004854026 0.004821445
[5] 0.004747833 0.004847728

Test whether the residuals is a white noise series

Test whether the residual series (the air_res variable) is a white noise running the ac and pac plots. A white noise is a series that has no signicant autocorrelations with any of its own lags.

acf2(air_res)
     [,1] [,2]  [,3] [,4] [,5] [,6]  [,7] [,8] [,9] [,10]
ACF  0.01 0.01 -0.13 0.02 0.09 0.05 -0.03 0.05 0.20 -0.01
PACF 0.01 0.01 -0.13 0.02 0.10 0.03 -0.03 0.08 0.21 -0.04
     [,11] [,12] [,13] [,14] [,15] [,16] [,17] [,18] [,19]
ACF  -0.09 -0.40  0.04  0.01  0.11 -0.11  0.07  0.04 -0.05
PACF -0.10 -0.37  0.01 -0.04  0.01 -0.09  0.16  0.11 -0.08
     [,20] [,21] [,22]
ACF  -0.13 -0.03 -0.03
PACF -0.08  0.16 -0.09

INTERPRET these plots THESE PLOTS ARE MEANT TO TEST WHETHER THE RESIDUAL SERIES HAVE WHITE NOISE RUNNING IN THEIR PLOTS. AS DEFINED EARLIER, WHITE NOISE IS A SERIES THAT HAS NO SIGNIFICANT AUTOCORRELATIONS WITH ANY OF THE LAGS. THE PLOTS SUGGEST THESE RESIDUALS ARENT WHITE NOISE DUE TO THE AMOUNT OF INCIDENCY IN THE 750000 AND 100000 LAG MARKERS.

Can you add another AR or MA term to improve the previous model and then to make the residual a white noise ?

YES, WE CAN ADD MORE TERMS AND ESTIMATE THE ARIMA-SARIMA MODEL AS INSTRUCTED EARLIER IN THIS WORKSHOP.

Forecast air passengers

We re-run the Arima model we run above, but now we will transform the dataset from xts to a ts R object to improve the visualization of the forecast:

#Convert the xts to a ts dataset:
air.ts <- ts(coredata(air.xts$Passengers),start=c(1949,1),frequency=12)
# We display the content of the ts dataset:
air.ts
     Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
1949 112 118 132 129 121 135 148 148 136 119 104 118
1950 115 126 141 135 125 149 170 170 158 133 114 140
1951 145 150 178 163 172 178 199 199 184 162 146 166
1952 171 180 193 181 183 218 230 242 209 191 172 194
1953 196 196 236 235 229 243 264 272 237 211 180 201
1954 204 188 235 227 234 264 302 293 259 229 203 229
1955 242 233 267 269 270 315 364 347 312 274 237 278
1956 284 277 317 313 318 374 413 405 355 306 271 306
1957 315 301 356 348 355 422 465 467 404 347 305 336
1958 340 318 362 348 363 435 491 505 404 359 310 337
1959 360 342 406 396 420 472 548 559 463 407 362 405
1960 417 391 419 461 472 535 622 606 508 461 390 432
# Run the Arima model:
m1 <- Arima(air.ts, order = c(2,0,0), # p=2:include 2 AR terms; q=0: No MA terms;
       seasonal = list(order=c(0,1,0), # D=1: use seasonal difference; No Seasonal terms
                       period=12),  # periods=12 period in the year
        include.constant = TRUE, # include the phi0 (drift) coefficient
        lambda = 0) # do the log transformation
m1
Series: air.ts 
ARIMA(2,0,0)(0,1,0)[12] with drift 
Box Cox transformation: lambda= 0 

Coefficients:
         ar1     ar2   drift
      0.5540  0.2378  0.0096
s.e.  0.0845  0.0848  0.0014

sigma^2 = 0.001742:  log likelihood = 233.13
AIC=-458.26   AICc=-457.95   BIC=-446.73
# We can see the pvalues of each ARIMA-SARIMA coefficient using the
#   coeftest from the lmtest library:
coeftest(m1)

z test of coefficients:

       Estimate Std. Error z value  Pr(>|z|)    
ar1   0.5540129  0.0844571  6.5597 5.392e-11 ***
ar2   0.2377939  0.0848135  2.8037  0.005052 ** 
drift 0.0095854  0.0013962  6.8655 6.625e-12 ***
---
Signif. codes:  
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

The pvalue of the drift, ϕ0, and the pvalues of the AR coefficients, ϕ1 and ϕ2, are very significant (<0.05). Then we keep these terms in the model.

Using the last Arima model, run a forecast for the following 24 months.

We run the forescast using the arima model m1 (the one I run with the Arima function. We indicate to do a forecast for 24 months, specifying h=24:

forecast_air <- forecast(m1, h=24)
# I stored the information of the forecast in forecast_air

# I plot the forecast
autoplot(forecast_air)

The forecast_air R object has both, historical data and forecast data. A very nice feature of the forecast function after using Arima function, is that we DO NOT HAVE TO do transformations to get the original scale of the variable, which is in tons. The Arima function automatically does the log transformation, and the forecast function automatically does the exponential transofrmation to get the forecast in tons!

The forecast_air R object is a list type of object that contains several elements.

attributes(forecast_air)
$names
 [1] "method"    "model"     "level"     "mean"     
 [5] "lower"     "upper"     "x"         "series"   
 [9] "fitted"    "residuals"

$class
[1] "forecast"

The forecast values are in the mean attribute:

forecast_air$mean
          Jan      Feb      Mar      Apr      May      Jun
1961 450.5662 424.4918 457.4920 505.5161 519.5149 590.6793
1962 503.1498 474.3893 511.5911 565.5928 581.5127 661.4150
          Jul      Aug      Sep      Oct      Nov      Dec
1961 688.5216 672.2711 564.5825 513.1307 434.6578 481.9836
1962 771.2137 753.2077 632.6921 575.1384 487.2573 540.3795

forecast_air also has historical data (x), residuals, the lower and upper limit of the 95% confidence interval of the forecast, etc !

Q CHALLENGE - Modelling consumer sales with an ARIMA/SARIMA model

FYI BEFORE YOU CONTINUE READING MY WORKSHOP, PLEASE KNOW THAT I DIDN’T MANAGE TO SOLVE IT. I TRIED MANY TIMES BUT I COULDN’T HACK IT. THEORETICAL QUESTIONS WERE ANSWERED BUT I COULDN’T MODEL.

Go to the course site (Material) and download Dr. Nau slides about ARIMA/SARIMA models. Read the slides and focus on his recommendations to select the number of p, d, q, P, D, Q for any ARIMA/SARIMA model. Download the following Dataset:

download.file("http://www.apradie.com/ec2004/salesfab2.xlsx", "salesfabs2.xlsx", mode="wb")
trying URL 'http://www.apradie.com/ec2004/salesfab2.xlsx'
Content type 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' length 11096 bytes (10 KB)
==================================================
downloaded 10 KB

Now, we read the data from the Excel file and construct an xts dataset:

sales_brands <- read_xlsx("salesfabs2.xlsx", sheet = "Sheet1")

#I create an xts object to handle the object and dates in a better way:

# I construct a date variable as a sequence of dates using the month column:
date <- seq(as.Date(sales_brands$month[1]),
                      by="month",
                      length.out = nrow(sales_brands) )
# I delete the first column since it has the month, and I will construct
#   an xts dataset with the index equal to the month
sales_brands = sales_brands[,-1]

# I create the xts object:
sales_brands<- xts(x=sales_brands, frequency = "monthly", order.by=date)

This dataset contains consumer national monthly sales of a Category of products. The sales is in tons (qfab#) and prices (pfab#) and include sales of few products. You have to do the following:

dataset <- read_excel("salesfabs2.xlsx")
# I familiarize with the data
head(dataset)
# I join both objects using xts() and assign it to a new object called price.xts
price.xts<- xts(x=sales_brands$price, frequency = "monthly", order.by=date)
class(price.xts)
[1] "xts" "zoo"
# Load library xts and zoo. Install the packages if you haven't already.
library(xts)
library(zoo)
library(tseries)
library(forecast)


# I get the date of the dataset:
date <- dataset$month
# I join both objects using xts() and assign it to a new object called volume.xts
volume.xts<- xts(x=sales_brands$volume, frequency = "monthly", order.by=date)
class(volume.xts)
[1] "xts" "zoo"

Generate the log variables for price (pfab1) and sales in volume (qfab1) for product 1.

lnprice.xts = log(price.xts)
lnvolume.xts = log(volume.xts)

Now you have to work in a model for qfab1, sales in tons of product 1:

plot(volume.xts$date)
Error in `$.zoo`(volume.xts, date) : 
  not possible for univariate zoo series

Graph the natural log of sales in tons of this product. WHAT DO YOU OBSERVE about the series? does it look stationary or nonstationary? does it look with seasonality?

plot(diff(lnvolume.xts,lag=1000))
Error in lag.xts(x, k = lag, na.pad = na.pad) : 
  abs(k) must be less than nrow(x)

If the series is not stationary, try whether the seasonal difference of the log looks as stationary (s12.lnqfab1). Do a time series plot, run and INTERPRET the Dicky-Fuller test

adf.test(na.omit(diff(lnvolume.xts,lag=1000)),alternative="stationary",k=0)
Error in lag.xts(x, k = lag, na.pad = na.pad) : 
  abs(k) must be less than nrow(x)

According to Dr Nau slides and what you learned in this workshop, calibrate the best ARIMA/SARIMA model.

I’VE TRIED MANY TIMES, CANT DO IT?

library(astsa)
# I create a ts object from the xts; the acf2 works better with ts objects
lnvolume.xts =ts(lnvolume.xts$tons)
Error in `$.zoo`(lnvolume.xts, tons) : 
  not possible for univariate zoo series

What is a white noise series? RESPOND WITH YOUR WORDS

WHEN WHITE NOISE IS PRESENT, ANY PAIR OF VALUES THAT CAN BE TAKEN AT ANY GIVEN TIME ARE NOT CORRELATED. IT IS A STATIONARY TIME SERIES WITH NO AUTOCORRELATION.

Create a variable for the residuals of your model. Run the ACF plot and the PACF plot for this residual. Does the residual look like a white noise?

m1 <- Arima(volume.xts$tons, order = c(2,0,0), seasonal = list(order=c(0,1,0),period=12), include.constant = TRUE, lambda = 0)m1
Error: unexpected symbol in "m1 <- Arima(volume.xts$tons, order = c(2,0,0), seasonal = list(order=c(0,1,0),period=12), include.constant = TRUE, lambda = 0)m1"
m1a<-sarima(log(volume.xts$tons), p=2, d=0, q=0,P=0,D=1,Q=0,S=12)
Error in `$.zoo`(volume.xts, tons) : 
  not possible for univariate zoo series

Why do you think that the residuals of your best model should look like A White noise? RESPOND WITH YOUR OWN WORDS

I’VE TRIED MANY TIMES, CANT DO IT.

Create 24 new observations in the future I’VE TRIED MANY TIMES, CANT DO IT. Create a forecast for the future observations using your last model I’VE TRIED MANY TIMES, CANT DO IT. (optional) Estimate the Akaike Information Criterion (AIC) of the model. To do this, run the following command right after running your arima model: I’VE TRIED MANY TIMES, CANT DO IT.

Do a quick research about what is the AIC of the model and EXPLAIN WITH YOUR OWN WORDS

AIC STANDS FOR AKIAKE INFORMATION CRITERION. THIS MATHEMATHICAL METHOD FOR EVALUATION ALLOWS TO KNOW HOW WELL A MODEL FITS THE DATA IT ORIGINATED FROM. IT’S USE IN STATISTICS IS FOR COMPARING DIFFERENT MODELS IN ORDER TO CHOOSE THE BEST ONE. IN ORDER TO CALCULATE AIC, ONE NEEDS THE FOLLOWING.

THE NUMBER OF INDEPENDENT VARIABLES USED TO BUILD SAID MODEL. THE MAXIMUM LIKELIHOOD ESTIMATE OF THE MODEL

“The best-fit model according to AIC is the one that explains the greatest amount of variation using the fewest possible independent variables.” (R. BEVANS, 2021).

Bevans, R. (2021, June 18). An introduction to the akaike information criterion. Scribbr. Retrieved March 16, 2022, from https://www.scribbr.com/statistics/akaike-information-criterion/#:~:text=The%20Akaike%20information%20criterion%20(AIC,best%20fit%20for%20the%20data.

LS0tCnRpdGxlOiAiV29ya3Nob3AgNCwgRmluYW5jaWFsIEVjb25vbWV0cmljcyBJSSIKYXV0aG9yOiBTdGVmYW4gU2Nod2VpdHplciBBMDEyMDk3NTUKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQpXb3Jrc2hvcCA0LCBGaW5hbmNpYWwgRWNvbm9tZXRyaWNzIElJCkFsYmVydG8gRG9yYW50ZXMsIFBoLkQuCk1hciAxNSwgMjAyMgoKIyBBYnN0cmFjdAoKSW4gdGhpcyB3b3Jrc2hvcCB3ZSBsZWFybiBob3cgdG8gZGVzaWduL2NhbGlicmF0ZSBhIHNlYXNvbmFsIEFSSU1BIG1vZGVsIChTQVJJTUEpIGZvciBhIHRpbWUgc2VyaWVzLgoKIyMgIEludHJvZHVjdGlvbiB0byBBUklNQS1TQVJJTUEgTW9kZWxzCkEgc2Vhc29uYWwgQVJJTUEgbW9kZWwsIGFsc28gY2FsbGVkIEFSSU1BL1NBUklNQSBtb2RlbCwgaXMgdXN1YWxseSBhcHBsaWVkIHRvIG1vbnRobHkgb3IgcXVhcnRlcmx5IHRpbWUgc2VyaWVzLiBUaGlzIG1vZGVsIGlzIHZlcnkgZWZmZWN0aXZlIGZvciBhbnkgb2YgdGhlIGZvbGxvd2luZyB0eXBlIG9mIGVjb25vbWljL2ZpbmFuY2lhbCBzZXJpZXM6CgpIaXN0b3JpY2FsIG1vbnRobHkgb3IgcXVhcnRlcmx5IHNhbGVzIGRhdGEKCkhpc3RvcmljYWwgbW9udGhseSBvciBxdWFydGVybHkgcHJpY2UgZGF0YQoKSGlzdG9yaWNhbCBtb250aGx5IG9yIHF1YXJ0ZXJseSBkYXRhIHJlbGF0ZWQgdG8gYW55IHZhcmlhYmxlIG9mIGFueSBmaW5hbmNpYWwgc3RhdGVtZW50LiBGb3IgZXhhbXBsZTogY29zdCBvZiBnb29kIHNvbGQsIHNhbGVzIGFuZCBnZW5lcmFsIGFkbWluaXN0cmF0aXZlIGV4cGVuc2VzLCBpbmNvbWUgdGF4LCBFQklULCBldGMuCgpIaXN0b3JpY2FsIG1vbnRobHkgb3IgcXVhcnRlcmx5IGRhdGEgcmVsYXRlZCB0byBhbnkgbWFjcm8gZWNvbm9taWMgdmFyaWFibGUuIEZvciBleGFtcGxlOiBpbmZsYXRpb24gaW5kZXhlcywgR0RQIGluZGV4ZXMsIGV4Y2hhbmdlIHJhdGVzLCBldGMuCgpUaGVzZSBtb2RlbHMgYXJlIG5vdCBzbyBlZmZlY3RpdmUgZm9yIGRhaWx5IHN0b2NrIHByaWNlcyBvciBmaW5hbmNpYWwgaW5kZXhlcy4gVGhlIG1haW4gcmVhc29uIGlzIHRoYXQgb25lIG9mIHRoZSBtb3N0IGltcG9ydGFudCBjb25kaXRpb25zIGZvciBhIGZpbmFuY2lhbCBtYXJrZXQgdG8gZXhpc3QgaXMgdGhhdCBubyBib2R5IGNhbiBwcmVkaWN0IHN0b2NrIHByaWNlcyBzaW5jZSB0aGUgbG9nIG9mIHN0b2NrIHByaWNlcyBhcmUgc3VwcG9zZWQgdG8gYmVoYXZlIGFzIGEgUmFuZG9tIFdhbGshIEhvd2V2ZXIsIHRoZXNlIG1vZGVscyBhcmUgdXNlZnVsIGluIHRoaXMgY29udGV4dCBjb21wYXJlZCB0byBqdXN0IGRvaW5nIGludHVpdGl2ZSBndWVzc2VzLgoKIyMgQ2FsaWJyYXRpb24gU3RlcHMgZm9yIEFSSU1BLVNBUklNQQpFYWNoIEFSSU1BLVNBUklNQSBtb2RlbCBuZWVkcyB0byBiZSBDQUxJQlJBVEVELiBUaGUgZ2VuZXJhbCBzdGVwcyB0byBjYWxpYnJhdGUgYSBtb2RlbCBhcmUgdGhlIGZvbGxvd2luZzoKCkNoZWNrIGlmIHRoZSBzZXJpZXMgaGFzIHNlYXNvbmFsaXR5LiBJZiB0aGUgc2VyaWVzIHNob3dzIGEgc2Vhc29uYWwgcGF0dGVybiwgc3RhcnQgd2l0aCB0aGUgc2Vhc29uYWwgZGlmZmVyZW5jZSBvZiB0aGUgbG9nIG9mIHRoZSBzZXJpZXMsIHdoaWNoIGlzIHRoZSAlIGFubnVhbCBncm93dGggb2YgdGhlIHNlcmllcy4gVXN1YWxseSBtb250aGx5IGFuZCBxdWFydGVybHkgZGF0YSBvZiBtYW55IGVjb25vbWljIGFuZCBmaW5hbmNpYWwgc2VyaWVzIGhhdmUgc2Vhc29uYWwgcGF0dGVybi4KSSByZWNvbW1lbmQgdGhhdCBpZiB5b3UgaGF2ZSBtb250aGx5IG9yIHF1YXJ0ZXJseSBkYXRhIG9mIGFueSBmaW5hbmNpYWwgb3IgZWNvbm9taWMgdmFyaWFibGUsIHN0YXJ0IHRlc3Rpbmcgd2hldGhlciB0aGUgc2Vhc29uYWwgZGlmZmVyZW5jZSBvZiB0aGUgbG9nIG9mIHRoZSBzZXJpZXMgaXMgc3RhdGlvbmFyeS4gSWYgeW91IGhhdmUgZGFpbHkgZGF0YSwgaXQgaXMgaGFyZCB0byBtb2RlbCBmb3Igc2Vhc29uYWxpdHkuIEluIHRoZSBjYXNlIG9mIGRhaWx5IGRhdGEsIHN0YXJ0IHRlc3Rpbmcgd2hldGhlciB0aGUgZmlyc3QgZGlmZmVyZW5jZSBvZiB0aGUgbG9nIGlzIHN0YXRpb25hcnkuCgpJbiB0aGlzIHN0ZXAgeW91IHN0YXJ0IHdpdGggYSB2ZXJzaW9uIG9mIHRoZSBzZXJpZXMuCgpGb3IgbmV4dCBzdGVwcyB3ZSB3aWxsIGFzc3VtZSB0aGF0IHdlIGRlY2lkZWQgdG8gdXNlIHRoZSBzZWFzb25hbCBkaWZmZXJlbmNlIG9mIHRoZSBsb2cgb2YgdGhlIHNlcmllcy4KClRlc3Qgd2hldGhlciB0aGUgc2Vhc29uYWwgZGlmZmVyZW5jZSBpcyBzdGF0aW9uYXJ5LiBJZiBzbywgY29udGludWUgdG8gbmV4dCBzdGVwLiBJZiBub3QsIHRoZW4gY2hhbmdlIHRoZSB2YXJpYWJsZSB0byB0aGUgZmlyc3QgZGlmZmVyZW5jZSBvZiB0aGUgbG9nIG9mIHRoZSBzZXJpZXMsIHdoaWNoIGlzIHRoZSAlIGNoYW5nZSBmb3IgZWFjaCBwZXJpb2QuIE1vc3Qgb2YgdGhlIGVjb25vbWljIGFuZCBmaW5hbmNpYWwgc2VyaWVzIGJlY29tZSBzdGF0aW9uYXJ5IHdpdGggdGhlIGZpcnN0IGxvZyBkaWZmZXJlbmNlLgoKUnVuIHRoZSBBQ0YgYW5kIFBBQ0YgcGxvdHMgdG8gaWRlbnRpZnkgdGhlIEFSSU1BLVNBUklNQSBwYXJhbWV0ZXJzIHAsIGQsIHEsIFAsIEQsIFEuIFRoZSBBQ0YgaXMgdGhlIGF1dG8tY29ycmVsYXRpb24gcGxvdCwgYW5kIHRoZSBQQUNGIGlzIHRoZSBwYXJ0aWFsIGF1dG9jb3JyZWxhdGlvbiBwbG90LiBCb3RoIHBsb3RzIHNob3cgYXV0bypjb3JyZWxhdGlvbnMgYmV0d2VlbiB0aGUgdmFyaWFibGUgYW5kIGl0cyBvd24gbGFncy4KCkFuIEFSSU1BL1NBUklNQSBtb2RlbCBoYXMgdGhlIGZvbGxvd2luZyDigJxwYXJhbWV0ZXJz4oCdIHRoYXQgbmVlZCB0byBiZSBkZWZpbmVkOgoKYXJpbWEocCxkLHEpIHNhcmltYShQLEQsUSwjUGVyaW9kcykKCnA6IHJlZmVycyB0byB0aGUgbnVtYmVyIG9mIGF1dG9yZWdyZXNzaXZlIChBUikgdGVybXMuIFVzdWFsbHkgdGhpcyBwYXJhbWV0ZXIgaXMgZWl0aGVyIDAsMSBvciAyLgoKZDogcmVmZXJzIHRvIGhvdyBtYW55IGZpcnN0IGRpZmZlcmVuY2VzIHdoZXJlIG5lZWRlZCB0byB0aGUgc2VyaWVzIGluIG9yZGVyIHRvIG1ha2UgdGhlIHNlcmllcyBzdGF0aW9uYXJ5LiBVc3VhbGx5IHRoaXMgcGFyYW1ldGVyIGlzIGVpdGhlciAwIG9yIDEuCgpxOiByZWZlcnMgdG8gdGhlIG51bWJlciBvZiBtb3ZpbmcgYXZlcmFnZSAoTUEpIHRlcm1zIGluIHRoZSBtb2RlbC4gVXN1YWxseSB0aGlzIHBhcmFtZXRlciBpcyBlaXRoZXIgMCwxIG9yIDIuCgpQOiByZWZlcnMgdG8gdGhlIG51bWJlciBvZiBTRUFTT05BTCBhdXRvcmVncmVzc2l2ZSB0ZXJtcy4gVXN1YWxseSB0aGlzIHBhcmFtZXRlciBpcyBlaXRoZXIgMCBvciAxLgoKRDogcmVmZXJzIHRvIGhvdyBtYW55IFNFQVNPTkFMIGRpZmZlcmVuY2VzIHdlcmUgbmVlZGVkIHRvIHRoZSBzZXJpZXMgdG8gbWFrZSB0aGUgc2VyaWVzIHN0YXRpb25hcnkuIFVzdWFsbHkgdGhpcyBwYXJhbWV0ZXIgaXMgZWl0aGVyIDAgb3IgMS4KClE6IHJlZmVycyB0byB0aGUgbnVtYmVyIG9mIFNFQVNPTkFMIG1vdmluZyBhdmVyYWdlIHRlcm1zLiBVc3VhbGx5IHRoaXMgcGFyYW1ldGVyIGlzIGVpdGhlciAwIG9yIDEuCgojcGVyaW9kczogcmVmZXJzIHRvIHRoZSBudW1iZXIgb2YgcGVyaW9kcyBpbiB0aGUgeWVhci4gRm9yIGV4YW1wbGUsIGlmIHRoZSBkYXRhIGlzIG1vbnRobHksIHRoZW4gI3BlcmlvZHM9MTIuCgpUaGVzZSBwYXJhbWV0ZXJzIGFyZSB1c3VhbGx5IGV4cHJlc3NlZCBhczogQVJJTUEocCxkLHEpIFNBUklNQShQLEQsUSwgI3BlcmlvZHMpLgoKV2hlbiB5b3UgaWRlbnRpZnkgdGhlIGZpcnN0IHZhbHVlcyBvZiB0aGVzZSBwYXJlbWV0ZXJzLCB0aGVuIHlvdSB3aWxsIGhhdmUgeW91ciBmaXJzdCBDQUxJQlJBVElPTiBvZiB0aGUgbW9kZWwuCgpFc3RpbWF0ZS9SdW4gdGhlIEFSSU1BLVNBUklNQSBtb2RlbAoKUnVuIHRoZSBBQ0YgYW5kIFBBQ0Ygb2YgdGhlIHJlc2lkdWFscy9lcnJvcnMgb2YgdGhlIG1vZGVsIHRvIGNoZWNrIHdoZXRoZXIgdGhlIGVycm9ycyBpcyBhIHdoaXRlIG5vaXNlIHNlcmllcy4gSW4gb3RoZXIgd29yZHMsIGlmIHRoZXJlIGlzIG5vIHNpZ25pZmljYW50IGF1dG9jb3JyZWxhdGlvbnMgb2YgdGhlIGVycm9ycy4KCklmIHRoZXJlIGlzIG9uZSBvciBtb3JlIHNpZ25pZmljYW50IGF1dG9jb3JyZWxhdGlvbnMsIHdlIGNhbiBpbmNsdWRlIG90aGVyIHRlcm0ocykgaW4gdGhlIEFSSU1BLVNBUklNQSBtb2RlbCwgYW5kIGdvIGJhY2sgdG8gc3RlcCA0LgoKSWYgdGhlcmUgdGhlIGVycm9ycyBzZWVtIGxpa2UgYSB3aGl0ZSBub2lzZSAobm8gc2lnbmZpY2FudCBhdXRvY29ycmVsYXRpb25zKSwgdGhlbiB3ZSBjYW4gY29udGludWUgYW5kIGZpbmlzaCB0aGUgY2FsaWJyYXRpb24gcHJvY2Vzcy4KCkludGVycHJldCB0aGUgbW9kZWwKClJ1biBhIGZvcmVjYXN0IHVzaW5nIHRoZSBtb2RlbAoKTGV04oCZcyBzdGFydCBwcmFjdGljaW5nIHdpdGggdGhlc2UgbW9kZWxzLgoKIyMgRXhhbXBsZSAtIG1vZGVsIGZvciBhaXIgcGFzc2VuZ2VycwoKIyBJZGVudGlmeWluZyBzZWFzb25hbGl0eSBpbiBhIHRpbWUtc2VyaWVzCldlIHdpbGwgd29yayB3aXRoIGEgc2ltcGxlIGRhdGFzZXQgdGhhdCBoYXMgdGhlIG51bWJlciBvZiBhaXIgcGFzc2VuZ2VycyBvZiBhbiBVUyBBaXJsaW5lLiBUaGlzIHNlcmllcyBtaWdodCBoYXZlIGEgc3Ryb25nIHNlYXNvbmFsaXR5IHNpbmNlIHBlb3BsZSB1c2VkIHRvIGZseSBpbiB2YWNhdGlvbiBwZXJpb2RzLCB3aGljaCBpcyB0aGUgdGhlIHNhbWUgZWFjaCB5ZWFyLgoKRG93bmxvYWQgdGhlIGV4Y2VsIGZpbGUgZnJvbSBhIHdlYiBzaXRlOgoKYGBge3J9CmRvd25sb2FkLmZpbGUoImh0dHA6Ly93d3cuYXByYWRpZS5jb20vZWMyMDA0L2FpcjIueGxzeCIsICJhaXIyLnhsc3giLCBtb2RlPSJ3YiIpCmBgYApJbiBvcmRlciB0byByZWFkIEV4Y2VsIGZpbGVzLCB3ZSBuZWVkIHRoZSByZWFkeGwgcGFja2FnZToKCmBgYHtyfQpsaWJyYXJ5KHJlYWR4bCkKYGBgCgpOb3csIHdlIHJlYWQgdGhlIGRhdGEgZnJvbSB0aGUgRXhjZWwgZmlsZToKCmBgYHtyfQpkYXRhc2V0IDwtIHJlYWRfZXhjZWwoImFpcjIueGxzeCIpCiMgSSBmYW1pbGlhcml6ZSB3aXRoIHRoZSBkYXRhCmhlYWQoZGF0YXNldCkKYGBgCgpJbiBvcmRlciB0byBwZXJmb3JtIHRpbWUtc2VyaWVzIGFuYWx5c2lzLCBpdCBpcyBiZXR0ZXIgdG8gdXNlIHh0cyBvYmplY3RzLiBXZSBjYW4gY29uc3RydWN0IHRoaXMgYnkgdXNpbmcgdGhlIHh0cygpIG1ldGhvZCBvZiB0aGUgeHRzIHBhY2thZ2UuIE9iamVjdHMgb2YgY2xhc3MgeHRzIGFyZSBjb21wb3NlZCBieSAyIGVsZW1lbnRzOiB0aGUgY29yZSBkYXRhIGFuZCB0aGUgaW5kZXggKGNsYXNzIERhdGUsIFBPU0lYLGV0YykuCgpgYGB7cn0KIyBMb2FkIGxpYnJhcnkgeHRzIGFuZCB6b28uIEluc3RhbGwgdGhlIHBhY2thZ2VzIGlmIHlvdSBoYXZlbid0IGFscmVhZHkuCmxpYnJhcnkoeHRzKQpsaWJyYXJ5KHpvbykKbGlicmFyeSh0c2VyaWVzKQpsaWJyYXJ5KGZvcmVjYXN0KQoKCiMgSSBnZXQgdGhlIGRhdGUgb2YgdGhlIGRhdGFzZXQ6CmRhdGUgPC0gZGF0YXNldCRtb250aAojIEkgam9pbiBib3RoIG9iamVjdHMgdXNpbmcgeHRzKCkgYW5kIGFzc2lnbiBpdCB0byBhIG5ldyBvYmplY3QgY2FsbGVkIGFpci54dHMKYWlyLnh0czwtIHh0cyh4PWRhdGFzZXQkYWlyLCBmcmVxdWVuY3kgPSAibW9udGhseSIsIG9yZGVyLmJ5PWRhdGUpCm5hbWVzKGFpci54dHMpPC1jKCJQYXNzZW5nZXJzIikKY2xhc3MoYWlyLnh0cykKYGBgCmBgYHtyfQojIEkgc2VlIGJlaGF2aW91ciBvZiBhaXIgcGFzc2VuZ2VycyBvdmVyIHRpbWUgCnBsb3QoYWlyLnh0cyRQYXNzZW5nZXJzKQpgYGAKVGhpcyBkYXRhc2V0IGNvbnRhaW5zIGFpciBwYXNzZW5nZXJzIGJ5IG1vbnRoIGZyb20gYW4gYWlybGluZS4gRG8gdGhlIGZvbGxvd2luZzoKCkRvZXMgdGhlIHNlcmllcyBsb29rIHN0YXRpb25hcnk/IE9idmlvdXNseSBub3QsIGl0IGxvb2tzIHdpdGggYSBjbGVhciBncm93aW5nIHRyZW5kLCBhbmQgYSBzZWFzb25hbGl0eSBwYXR0ZXJuLiBUaGUgbWVhbiBvZiB0aGUgc2VyaWVzIEdST1dTIE9WRVIgVElNRS4KCkdldCB0aGUgbmF0dXJhbCBsb2dhcml0aG0gb2YgdGhlIHNlcmllczoKYGBge3J9CmxuYWlyLnh0cyA9IGxvZyhhaXIueHRzKQpgYGAKCiMgVGVzdGluZyBmb3Igc3RhdGlvbmFyeQoKU2luY2Ugd2Ugc2VlIGEgY2xlYXIgc2Vhc29uYWxpdHkgcGF0dGVybiwgaXQgaXMgc3Ryb25nbHkgcmVjb21tZW5kZWQgdG8gdXNlIHRoZSBzZWFzb25hbCBkaWZmZXJlbmNlIG9mIHRoZSBsb2cgb2YgdGhlIHNlcmllcy4gU28sIHdlIHdpbGwgY2hlY2sgd2hldGhlciB3ZSBjYW4gdHJlYXQgdGhlIHNlYXNvbmFsIGRpZmZlcmVuY2Ugb2YgdGhlIGxvZyBhcyBTVEFUSU9OQVJZLgoKV2Ugc3RhcnQgYnkgcGxvdHRpbmcgdGhlIHNlYXNvbmFsIGRpZmZlcmVuY2Ugb2YgdGhlIGxvZywgd2hpY2ggaXMgdGhlIGFubnVhbCAlIGdyb3d0aCAoaW4gY2MpIG9mIHRoZSBhaXIgcGFzc2VuZ2VyczoKCmBgYHtyfQpwbG90KGRpZmYobG5haXIueHRzLGxhZz0xMikpCmBgYApJdCBpcyBoYXJkIHRvIHNlZSB3aGV0aGVyIHRoaXMgaXMgc3RhdGlvbmFyeSBvciBub3QsIHNvIHdlIGhhdmUgdG8gcnVuIHRoZSBEaWNreS1GdWxsZXIgdGVzdC4gUnVuIHRoZSBEaWNreS1GdWxsZXIgdGVzdCB1c2luZyB0aGUgYWRmLnRlc3QgZnVuY3Rpb24gb2YgdGhlIHRzZXJpZXMgcGFja2FnZXMuCgpgYGB7cn0KYWRmLnRlc3QobmEub21pdChkaWZmKGxuYWlyLnh0cyxsYWc9MTIpKSxhbHRlcm5hdGl2ZT0ic3RhdGlvbmFyeSIsaz0wKQpgYGAKV2UgZ290IGEgcC12YWx1ZTwwLjA1LCBzbyB3ZSBjYW4gdHJlYXQgdGhlIHNlYXNvbmFsIGRpZmZlcmVuY2UgKHRoZSBhbm51YWwgJSBncm93dGgpIGFzIHN0YXRpb25hcnkgYW5kIGNvbnRpbnVlIHdpdGggdGhpcyBzZXJpZXMgdG8gY2FsaWJyYXRlIGFuIEFSSU1BLVNBUklNQSBtb2RlbC4KCiMgQUNGIGFuZCBQQUNGIHBsb3RzCgpPbmNlIHdlIGNvbmZpcm0gdGhhdCBvdXIgc2VyaWVzIGlzIHN0YXRpb25hcnksIHRoZW4gdGhlIGZpcnN0IHN0ZXAgaXMgdG8gZG8gdGhlIEFDIGFuZCBQQUMgcGxvdHMgdG8gaWRlbnRpZnkgaG93IG1hbnkgQVIgYW5kIE1BIHRlcm1zIHdlIGNhbiBpbmNsdWRlIGluIG91ciBBUklNQS9TQVJJTUEgbW9kZWwuCgpSZW1lbWJlciB0aGF0IHdlIGNhbiBjb21wdXRlIHRoZSBhdXRvY29ycmVsYXRpb24gcGxvdHMgd2l0aCB0aGUgYWNmMiBmdW5jdGlvbiBmcm9tIHRoZSBhc3RzYSBwYWNrYWdlLiBMZXTigJlzIGV4YW1pbmUgdGhlIGF1dG9jb3JyZWxhdGlvbnMgb2Ygb3VyIHNlcmllcy4gUmVtZW1iZXIgdGhhdCBvdXIgc2VyaWVzIGlzIHRoZSBzZWFzb25hbCBkaWZmZXJlbmNlIG9mIHRoZSBsb2cgb2YgYWlyIHBhc3NlbmdlcnMsIHdoaWNoIGlzIHRoZSBhbm51YWwgJSBncm93dGggb2YgYWlyIHBhc3NlbmdlcnMgbW9udGggYnkgbW9udGguCgpgYGB7cn0KbGlicmFyeShhc3RzYSkKIyBJIGNyZWF0ZSBhIHRzIG9iamVjdCBmcm9tIHRoZSB4dHM7IHRoZSBhY2YyIHdvcmtzIGJldHRlciB3aXRoIHRzIG9iamVjdHMKbG5haXIgPXRzKGxuYWlyLnh0cyRQYXNzZW5nZXJzKQphY2YyKGRpZmYobG5haXIsbGFnPTEyKSkKYGBgCkkgdXNlZCB0aGUgdHMgZnVuY3Rpb24gdG8gdHJhbnNmb3JtIHRoZSBkYXRhc2V0IGludG8gYSB0cyBkYXRhc2V0IHNpbmNlIHRoaXMgdHlwZSBvZiBSIG9iamVjdCB3aWxsIGFsbG93IHVzIHRvIGVhc2lseSBydW4gYW5kIGZvcmVjYXN0IGFyaW1hLXNhcmltYSBtb2RlbHMuCgojIEFDRiBhbmQgUEFDRiBpbnRlcnByZXRhdGlvbgpUaGUgQUNGIHNob3dzIHRoZSBhdXRvY29ycmVsYXRpb25zIChBQykgYmV0d2VlbiB0aGUgc2VyaWVzIGFuZCBpdHMgbGFncywgYW5kIHRoZSBQQUNGIHNob3dzIHRoZSBwYXJ0aWFsIGF1dG9jb3JyZWxhdGlvbnMgKFBBQykgYmV0d2VlbiB0aGUgc2VyaWVzIGFuZCBpdHMgbGFncy4KClRoZSBWRVJUSUNBTCBsaW5lcyBzaG93IHRoZSBNQUdOSVRVRCBvZiB0aGUgQVVUT0NPUlJFTEFUSU9OIGJldHdlZW4gYSBMQUcgYW5kIHRoZSBjdXJyZW50IHZhbHVlIG9mIHRoZSBzZXJpZXMuCgpUaGUgYmx1ZSBob3Jpem9udGFsIGRvdHRlZCBsaW5lcyBpbiB0aGUgcGxvdHMgY292ZXIgdGhlIDk1JSBjb25maWRlbmNlIGludGVydmFsIGZvciB0aGUgYXV0b2NvcnJlbGF0aW9ucy4gU28sIGlmIHRoZSB2ZXJ0aWNhbCBsaW5lIGNyb3NlcyB0aGUgYmx1ZSBkb3R0ZWQgbGluZSwgaXQgbWVhbnMgdGhhdCB0aGF0IHNwZWNpZmljIGF1dG9jb3JyZWxhdGlvbiBpcyBTSUdOSUZJQ0FOVExZIERJRkZFUkVOVCBUSEFOIFpFUk8gKGl0IGNvdWxkIGJlIHBvc2l0aXZlIG9yIG5lZ2F0aXZlKS4KCk5vdyB3aGF0IGlzIHRoZSBnZW5lcmFsIGludGVycHJldGF0aW9uIG9mIHRoZSB0aGVzZSBwbG90cz8KCkZpcnN0LCB3ZSBhbHdheXMgaGF2ZSB0byByZW1lbWJlciB3aGF0IHdlIGFyZSBtb2RlbGxpbmcuIEluIHRoaXMgY2FzZSB3ZSBhcmUgbW9kZWxsaW5nIHRoZSBzZWFzb25hbCBkaWZmZXJlbmNlIG9mIHRoZSBsb2csIHdoaWNoIGlzIHRoZSBBTk5VQUwgJSBHUk9XVEggb2YgcGFzc2VuZ2VycyBtb250aCBieSBtb250aC4KCkluIHRoZSBBQ0YgcGxvdCBJIHNlZSB0aGF0IHRoZSBmaXJzdCA4IEFDcyBhcmUgcG9zaXRpdmUgYW5kIHNpZ25pZmljYW50LCBhbmQgdGhleSBncmFkdWFsbHkgZGVjYXkuIEZvciBleGFtcGxlLCB0aGUgQUMgb2YgTEFHIDEgaXMgYWJvdXQgNzAlIChhbG1vc3QgMC43MCkuIFRoaXMgbWVhbnMgdGhhdCBBTk5VQUwgJSBncm93dGggb2YgYWlyIHBhc3NlbmdlcnMgaXMgc3Ryb25nbHkgY29ycmVsYXRlZCAod2l0aCBhIGNvcnJlbGF0aW9uIG9mIDcwJSkgd2l0aCBJVFMgT1dOIEFOTlVBTCAlIEdST1dUSCBvZiB0aGUgUFJFVklPVVMgbW9udGggKGl0cyBMQUcgMSkuCgpUaGUgQUMgb2YgTEFHIDIgaXMgYWJvdXQgNjIlLCBzbyB0aGUgQU5OVUFMICUgR1JPV1RIIG9mIHBhc3NlbmdlcnMgaXMgc3Ryb25nbHkgY29ycmVsYXRlZCB3aXRoIElUUyBPV04gQU5OVUFMICUgR1JPV1RIIG9mIDIgTU9OVEhTIEFHTyAoaXRzIExBRyAyKeKApiBhbmQgc28gb24uCgpJdCBpcyBpbXBvcnRhbnQgdG8gbWVudGlvbiB0aGF0IHRoZSBBQ0YgcGxvdCBzaG93cyBhdXRvY29ycmVsYXRpb25zIGluZGVwZW5kZW50bHkgb2YgZWFjaCBvdGhlci4KCkluIHRoZSBjYXNlIG9mIFBBQ0YsIHdlIHNlZSBQQVJUSUFMIGF1dG9jb3JyZWxhdGlvbnMsIHdoaWNoIG1lYXN1cmUgSE9XIE1VQ0ggRUxTRSB0aGUgc2VyaWVzIGlzIGNvcnJlbGF0ZWQgd2l0aCBlYWNoIGl0cyBvd24gTEFHUywgQUZURVIgQ09OU0lERVJJTkcgdGhlIGVmZmVjdCBvZiBMT1dFUi1PUkRFUiBMQUcgQVVUT0NPUlJFTEFUSU9OUy4KCkkgc2VlIHRoYXQgdGhlIFBBQ0Ygc2hvd3Mgb25seSB0aGUgZmlyc3QgMiBhdXRvY29ycmVsYXRpb25zIHRvIGJlIHBvc2l0aXZlIEFORCBTSU5HSUZJQ0FOVCwgYW5kIHRoZSBtYWduaXR1ZGUgb2YgdGhlIGZvbGxvd2luZyBhdXRvY29ycmVsYXRpb25zIGdvZXMgZG93biB0byB6ZXJvIG9yIG5lZ2F0aXZlIHZlcnkgcXVpY2tseS4KCldoZW4gdGhlIEFDRiBwbG90IHNob3dzIGEgU0xPVyBERUNMSU5FIG9mIGF1dG9jb3JyZWxhdGlvbnMsIGFuZCB0aGUgUEFDRiBzaG93cyBhIEZBU1QgREVDTElORSBvZiBhdXRvY29ycmVsYXRpbm9zLCB0aGlzIGlzIGEgY2xlYXIgUEFUVEVSTiBPRiBBTiBBUihwKSBNT0RFTC4gSW4gdGhpcyBjYXNlLCB0aGUgIyBvZiBBUiB0ZXJtcyBpcyBkZXRlcm1pbmVkIGJ5IHRoZSBTSUdOSUZJQ0FOVCBMQUdTIGluIHRoZSBQQUNGIHBsb3QuCgpXZSBzZWUgdGhhdCBhbHNvIHRoZSBBQyBvZiBMQUcgMTAgaXMgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBhbmQgbmVnYXRpdmUsIGJ1dCBpdCBpcyByZWNvbW1lbmRlZCBmaXJzdCB0byBzdGFydCB3aXRoIHRoZSBBUigyKSBtb2RlbCwgYW5kIHRoZW4gY2hlY2sgdGhlIHJlc2lkdWFscyBvZiB0aGUgbW9kZWwgdG8gc2VlIHdoZXRoZXIgdGhlcmUgaXMgYW5vdGhlciBzaWduaWZpY2FudCBsYWcuCgpUaGVuLCBpbiB0aGlzIGNhc2Ugd2Ugc3RhcnQgd2l0aCBhbiBBUklNQSB3aXRoIHA9MiBhbmQgcT0wLgoKUmVhZCBEci4gTmF1IHNsaWRlcyB0byByZXZpZXcgbW9yZSBQQVRURVJOUyBvZiBBQ0YgYW5kIFBBQ0YgcGxvdHMuCgojIEVzdGltYXRlIHRoZSBBUklNQS1TQVJJTUEgbW9kZWwKSW4gdGhpcyBjYXNlLCBJIGNhbiBzdGFydCB3aXRoIHRoZSBmb2xsb3dpbmcgY2FsaWJyYXRpb24uIE5vdyB3ZSBjYW4gdXNlIHRoZSBsb2cgc2VyaWVzLCBhbmQgbGVhdmUgdGhlIG1vZGVsIHRvIGF1dG9tYXRpY2FsbHkgY2FsY3VsYXRlIHRoZSBTRUFTT05BTCBkaWZmZXJlbmNlLiBUaGVuLCBJIHdpbGwgdXNlIHRoZSBsb2cgb2YgdGhlIHNlcmllcyAobG9nIG9mIGFpciBwYXNzZW5nZXJzKSBhbmQgZGVmaW5lIG15IG1vZGVsIGFzOgoKYXJpbWEocCxkLHEpIHNhcmltYShQLEQsUSwjcGVyaW9kcyBpbiB0aGUgeWVhcikKCkluIG91ciBleGFtcGxlLCB0aGUgdmFsdWVzIGZvciB0aGUgcGFyYW1ldGVycyBhcmU6CgphcmltYSgyLDAsMCkgc2FyaW1hKDAsMSwwLDEyKQoKV2hhdCB0aGlzIG1vZGVsIHRlbGxzIHVzPwoKWW91IGZpcnN0IGhhdmUgdG8gbG9vayBhdCB0aGUgIyBvZiBwZXJpb2RzLiBJbiB0aGlzIGNhc2UsIHlvdSBoYXZlIDEyIHBlcmlvZHMgaW4gYSB5ZWFyLCBzbyB5b3VyIHNlcmllcyBzaG91bGQgYmUgbW9udGhseS4KClRoZW4geW91IGxvb2sgYXQgZCBhbmQgRCAoZmlyc3QgZGlmZmVyZW5jZXMgYW5kIHRoZSBzZWFzb25hbCBkaWZmZXJlbmNlcykuIEluIHRoaXMgY2FzZSwgZD0wIGFuZCBEPTEuIFdoYXQgZG9lcyB0aGlzIG1lYW4/IHRoaXMgbWVhbnMgdGhhdCB3ZSBhcmUgbW9kZWxpbmcgdGhlIFNFQVNPTkFMIGRpZmZlcmVuY2UgKEQ9MSkgb2YgdGhlIGxvZyBvZiB0aGUgdmFyaWFibGUsIHdoaWNoIGlzIHRoZSBhbm51YWwgJSBncm93dGggKG1vbnRoIGJ5IG1vbnRoKS4gU2luY2UgZD0wIHRoaXMgbWVhbnMgdGhhdCB3ZSBhcmUgTk9UIHVzaW5nIHRoZSBmaXJzdCBkaWZmZXJlbmNlIG9mIHRoZSBzZXJpZXMuCgpUaGVuIHlvdSBsb29rIGF0IHRoZSBwLCBxLCBQLCBRLiBwIHRlbGxzIHlvdSBob3cgbWFueSBBUiB0ZXJtcyBhcmUgaW5jbHVkZWQgaW4geW91ciBtb2RlbC4gSW4gdGhpcyBjYXNlLCBwPTIsIHNvIHlvdXIgbW9kZWwgaW5jbHVkZXMgdGhlIGZpcnN0IDIgQVIgdGVybXMuIFNpbmNlIHEsIFAgYW5kIFEgYXJlIHplcm8sIHRoZW4geW91ciBtb2RlbCBkb2VzIG5vdCBpbmNsdWRlIGFueSBvZiB0aGVzZSB0eXBlIG9mIHRlcm1zLgoKSG93IHRoaXMgbW9kZWwgY2FuIGJlIGV4cHJlc3NlZCBtYXRoZW1hdGljYWxseT8KClNpbmNlIHlvdSBhcmUgbW9kZWxpbmcgdGhlIHNlYXNvbmFsIGRpZmZlcmVuY2UsIHlvdSBjYW4gZXhwcmVzcyB0aGlzIG1vZGVsIGFzIHRoZSBmb2xsb3dpbmcgZXF1YXRpb246CgrilrMxMmxuYWlyPc+VMCvPlTEoTDHilrMxMmxuYWlydCkrz5UyKEwy4pazMTJsbmFpcnQpK861dAoKVXNpbmcgYSBzaW1wbGVyIG5vdGF0aW9uLCB0aGlzIGVxdWF0aW9uIGNhbiBiZSBleHByZXNzZWQgYXM6CgpzMTIubG5haXJ0Pc+VMCvPlTFMMS5zMTIubG5haXJ0K8+VMkwyLnMxMi5sbmFpcnQrzrV0CgpSZW1lbWJlciB0aGF0IHMxMi5sbmFpciBpcyB0aGUgc2Vhc29uYWwgZGlmZmVyZW5jZSBvZiB0aGUgbG9nIG9mIGFpciBwYXNzZW5nZXJzLCB3aGljaCBpcyB0aGUgYW5udWFsICVncm93dGggb2YgYWlyIHBhc3NlbmdlcnMgbW9udGggYnkgbW9udGguIFRoZW4gd2UgY2FuIHJlYWQgdGhpcyBtYXRoZW1hdGljYWwgZXhwcmVzc2lvbiBhczog4oCcVGhlIGFubnVhbCAlZ3Jvd3RoIChtb250aCBieSBtb250aCkgb2YgYWlyIHBhc3NlbmdlcnMgYXQgdGltZSB0IGNhbiBiZSBkZXRlcm1pbmVkIGJ5IGl0cyBvd24gYW5udWFsICUgZ3Jvd3RoIG9mIGFpciBwYXNzZW5nZXJzIGF0IHRpbWUgdC0xIGFuZCB0LTIgKHRoZSAlZ3Jvd3RoIG9mIHRoZSBwcmV2aW91cyAyIG1vbnRocyksIGFuZCBieSBhIHJhbmRvbSBzaG9ja+KAnQoKIyMgUnVubmluZyB0aGUgQVJJTUEvU0FSSU1BCk5vdyB3ZSBjYW4gZXN0aW1hdGUgdGhlIEFSSU1BLVNBUklNQSBtb2RlbCB1c2luZyB0aGUgQXJpbWEgZnVuY3Rpb24gb2YgdGhlIGZvcmVjYXN0IHBhY2thZ2UuCgpJbiB0aGlzIGNhc2UsIGluc3RlYWQgb2YgY3JlYXRpbmcgYSB2YXJpYWJsZSBmb3IgdGhlIHNlYXNvbmFsIGRpZmZlcmVuY2Ugb2YgdGhlIGxvZyAoczEyLmxuYWlyKSwgd2Ugd2lsbCBjb25maWd1cmUgdGhlIHBhcmFtZXRlcnMgb2YgdGhlIEFyaW1hIGZ1bmN0aW9uIHNvIHRoYXQgdGhlIGxvZyB0cmFuc2Zvcm1hdGlvbiBhbmQgdGhlIHNlYXNvbmFsIGRpZmZlcmVuY2Ugd2lsbCBiZSBjYWxjdWxhdGVkIGJlZm9yZSBlc3RpbWF0aW5nIHRoZSBhcmltYSBjb2VmZmljaWVudHMuCgpJbiBvdXIgZmlyc3QgY2FsaWJyYXRpb24gd2UgZGlzY3Vzc2VkIGFib3ZlLCB3ZSBkZWZpbmVkIHRoZSBmb2xsb3dpbmcgdmFsdWVzIG9mIHRoZSBBUklNQS1TQVJJTUEgbW9kZWwgZm9yIHRoZSBsb2cgb2YgdGhlIG51bWJlciBvZiBhaXIgcGFzc2VuZ2VyczoKCmFyaW1hKDIsMCwwKSBzYXJpbWEoMCwxLDAsMTIpCgpUaGlzIG1lYW5zIHRoYXQgRD0xLCBzbyBSIHdpbGwgY2FsY3VsYXRlIHRoZSBzZWFzb25hbCBkaWZmZXJlbmNlLCBhbmQgdGhlbiBlc3RpbWF0ZSB0aGUgYXJpbWEgbW9kZWwgYW5kIGluY2x1ZGUgMiBBUiB0ZXJtcyBhbmQgbm8gTUEgdGVybXMuCgpXZSBjYW4gcnVuIHRoaXMgbW9kZWwgaW4gUiBhcyBmb2xsb3dzOgoKYGBge3J9Cm0xIDwtIEFyaW1hKGFpci54dHMkUGFzc2VuZ2VycywgIyBXZSB1c2UgdGhlIFBhc3NlbmdlcnMgY29sdW1uIG9mIHRoZSBkYXRhc2V0CiAgICAgICAgb3JkZXIgPSBjKDIsMCwwKSwgIyB3ZSBpbmRpY2F0ZSB0aGF0IHA9MDsgZD0wOyBxPTAgCiAgICAgICAgc2Vhc29uYWwgPSBsaXN0KG9yZGVyPWMoMCwxLDApLHBlcmlvZD0xMiksICNQPTA7IEQ9MTsgUT0wLCAjcGVyaW9kcz0xMgogICAgICAgIGluY2x1ZGUuY29uc3RhbnQgPSBUUlVFLCAjIEhlcmUgd2UgaW5kaWNhdGUgdG8gaW5jbHVkZSB0aGUgcGhpMCBjb2VmZmljaWVudAogICAgICAgIGxhbWJkYSA9IDApICMgSGVyZSB3ZSBpbmRpY2F0ZSB0byBhcHBseSB0aGUgbmF0dXJhbCBsb2cgdG8gdGhlIHNlcmllcyAgCm0xCmBgYAoKSWYgd2Ugc2V0IGxhbWRhID0gMCB0aGlzIG1lYW5zIHRoYXQgdGhlIHRoZSBtb2RlbCB3aWxsIHVzZSB0aGUgbG9nIG9mIHRoZSB2YXJpYWJsZSAocGFzc2VuZ2Vycyk7IHRoaXMgaXMgb25lIG9mIHRoZSBCb3gtSmVua2lucyBtYXRoZW1hdGljYWwgdHJhbnNmb3JtYXRpb25zLCBhbmQgaXQgaXMgdGhlIG1vc3QgY29tbW9uIGZvciBmaW5hbmNpYWwgYW5kIGVjb25vbWljIHNlcmllcy4KCldlIGNhbiBhbHRlcm5hdGl2ZWx5IHVzZSB0aGUgZnVuY3Rpb24gc2FyaW1hIGZyb20gdGhlIGFzdHNhIG1vZGVsIHRvIHJ1biB0aGUgc2FtZSBhcmltYSBtb2RlbC4gVGhlIHNhcmltYSBmdW5jdGlvbiBwcm92aWRlcyBtb3JlIGRldGFpbCBpbiB0aGUgb3V0cHV0LCBidXQgdGhlIEFyaW1hIGZ1bmN0aW9uIGhhcyBhZHZhbnRhZ2VzIHdoZW4gd2Ugd2FudCB0byBnZXQgdGhlIGZvcmVjYXN0IHdpdGggdGhlIG1vZGVsLiBXZSBydW4gc2FyaW1hIGZvciB0aGUgc2FtZSBtb2RlbCBhczoKCmBgYHtyfQptMWE8LXNhcmltYShsb2coYWlyLnh0cyRQYXNzZW5nZXJzKSwgcD0yLCBkPTAsIHE9MCxQPTAsRD0xLFE9MCxTPTEyKQpgYGAKCmBgYHtyfQptMWEKYGBgCkFzIHdlIHNlZSwgd2UgbmVlZCB0byB0YWtlIHRoZSBsb2cgZmlyc3QgYW5kIHRoZW4gc3BlY2lmeSB0aGUgbW9kZWwuIFRoZSByZXN1bHQgaXMgZXhhY3RseSB0aGUgc2FtZSBhcyB0aGUgQXJpbWEgcmVzdWx0LCBidXQgd2l0aCBzYXJpbWEgd2UgY2FuIHNlZSB0aGUgY29lZmZpY2llbnRzLCB0aGVpciBwLXZhbHVlcyBhbmQgb3RoZXIgaW1wb3J0YW50IHBsb3RzIG9mIHRoZSBtb2RlbC4gQWxzbywgd2UgY2FuIHNlZSBpbXBvcnRhbnQgcGxvdHMgc3VjaCBhcyBBQ0Ygb2YgdGhlIGVycm9ycy4KCiMgSW50ZXJwcmV0YXRpb24gb2YgYW4gQVJJTUEtU0FSSU1BIG1vZGVsCgpTaW5jZSB0aGUgQXJpbWEgZnVuY3Rpb24gZG9lcyBub3QgZGlzcGxheSB0aGUgcCB2YWx1ZXMgYW5kIHQgdmFsdWVzIG9mIHRoZSBjb2VmZmljaWVudHMsIHdlIGNhbiB1c2UgdGhlIGZ1bmN0aW9uIGNvZWZ0ZXN0IGZyb20gdGhlIGxtdGVzdCBsaWJyYXJ5LgoKWW91IGhhdmUgdG8gaW5zdGFsbCB0aGUgbG10ZXN0IGxpYnJhcnkgYW5kIHRoZSBsb2FkIGl0OgoKYGBge3J9CmxpYnJhcnkobG10ZXN0KQpgYGAKCk5vdyB3ZSBjYW4gc2VlIHRoZSBjb2VmZmljaWVudHMgYW5kIHRoZWlyIGNvcnJlc3BvbmRpbmcgc3RhbmRhcmQgZXJyb3IsIHB2YWx1ZSBhbmQgdCB2YWx1ZS4gV2UgYXBwbHkgdGhlIGNvZWZ0ZXN0IGZ1bmN0aW9uIHRvIHRoZSBtMSBtb2RlbCBjcmVhdGVkIHdpdGggQXJpbWE6CgpgYGB7cn0KY29lZnRlc3QobTEpCmBgYAoKVGhlIGRyaWZ0IGNvZWZmaWNpZW50IGlzIHRoZSBwaGkwIGNvZWZmaWNpZW50LiBwaGkwIGFuZCBib3RoIGxhZ3MgYXJlIHBvc2l0aXZlIGFuZCBTSUdOSUZJQ0FOVC4gV2hhdCBkb2VzIHRoaXMgbWVhbj8gRmlyc3QsIEkgaGF2ZSB0byByZW1lbWJlciB3aGljaCB2YXJpYWJsZSBJIGFtIG1vZGVsbGluZy4gSSBhbSBtb2RlbGluZyB0aGUgc2Vhc29uYWwgZGlmZmVyZW5jZSBvZiBsb2cgcGFzc2VuZ2Vycywgd2hpY2ggaXMgdGhlIGFubnVhbCAlIGdyb3d0aCBvZiBhaXIgcGFzc2VuZ2VycyBtb250aCBieSBtb250aC4gVGhlbiwgSSBjYW4gaW50ZXJwcmV0IHRoaXMgQVJJTUEtU0FSSU1BIG1vZGVsIGFzIGZvbGxvd3M6CgpUaGUgYW5udWFsICUgZ3Jvd3RoIG9mIGFpciBwYXNzZW5nZXJzIGlzIHBvc2l0aXZlbHkgYW5kIHNpZ25pZmljYW50bHkgcmVsYXRlZCB3aXRoIGl0cyBhbm51YWwgJSBncm93dGggb2YgYWlyIHBhc3NlbmdlcnMgb2YgbGFzdCBtb250aCAobGFnMSkuIEluIGEgc2ltaWxhciB3YXksIHRoZSBhbm51YWwgJSBncm93dGggb2YgYWlyIHBhc3NlbmdlcnMgaXMgcG9zaXRpdmVseSBhbmQgc2lnbmlmaWNhbnRseSByZWxhdGVkIHdpdGggdGhlIGFubnVhbCAlIGdyb3d0aCBvZiB0d28gbW9udGhzIGFnby4gTW9yZSBzcGVjaWZpY2FsbHksIDU1LjQlIG9mIGFubnVhbCBncm93dGggb2YgbGFzdCBtb250aCBpcyBwYXNzZWQgdG8gdGhpcyBtb250aOKAmXMgYW5udWFsICUgZ3Jvd3RoLCBhbmQgb25seSAyMy43OCUgb2YgdGhlIGFubnVhbCBncm93dGggb2YgMiBtb250aHMgYWdvIGlzIHBhc3NlZCB0byB0aGUgY3VycmVudCBhbm51YWwgJSBncm93dGguCgpJbiBvdGhlciB3b3JkcywgZm9yIGVhY2ggcGVyY2VudHVhbCBwb2ludCBvZiBhbm51YWwgZ3Jvd3RoIG9mIHByZXZpb3VzIG1vbnRoLCBpdCBpcyBleHBlY3RlZCB0aGF0IHRoZSBjdXJyZW50IGFubnVhbCBncm93dGggd2lsbCBncm93IGFib3V0IDAuNTUgcGVyY2VudCBwb2ludHMKCkl0IGlzIGludGVyZXN0aW5nIHRvIHNlZSB0aGF0IHRoZSBzdW0gb2YgcGhpMSBhbmQgcGhpMiAoMC41NSswLjIzKSBNVVNUIGJlIDwgMSBpbiBvcmRlciBmb3IgdGhlIHNlcmllcyB0byBiZSBzdGF0aW9uYXJ5LiBJZiB5b3UgaW5jbHVkZSBtb3JlIGFyaW1hIHRlcm1zLCB0aGUgc3VtIG9mIHRoZSBwaGnigJlzIG11c3QgYmUgbGVzcyB0aGFuIG9uZS4gSWYgeW91IGluY2x1ZGUgTUEgdGVybXMsIHRoZSBzdW0gb2YgdGhlIHRoZXRhIGNvZWZmaWNpZW50cyBhbHNvIG11c3QgYmUgbGVzcyB0aGFuIG9uZS4gSW4gYWRkaXRpb24sIHRoZSBjb25zdGFudCBvciBwaGkwIGlzIHBvc2l0aXZlIGFuZCBzaWduaWZpY2FudCwgaW5kaWNhdGluZyB0aGF0IHRoZSBhbm51YWwgZ3Jvd3RoIG9mIGFpciBwYXNzZW5nZXJzIGhhcyBhIHBvc2l0aXZlIHRlbmRlbmN5IHRvIGdyb3cgb3ZlciB0aW1lLgoKVGhlIG1hdGhlbWF0aWNhbCBtb2RlbCBpczoKCkVbczEyLmxuYWlyXT0wLjAwOTYrMC41NTTiiJdMMS5zMTIubG5haXIrMC4yMzc44oiXTDIuczEyLmxuYWlyCm9yCnMxMi5sbmFpcj0wLjAwOTYrMC41NTTiiJdMMS5zMTIubG5haXIrMC4yMzc44oiXTDIuczEyLmxuYWlyK2Vycm9yCgojIEF1dG9jb3JyZWxhdGlvbnMgb2YgdGhlIE1vZGVsIHJlc2lkdWFscy9lcnJvcnMKCldlIG5lZWQgdG8gZ2VuZXJhdGUgYSBzZXJpZXMgZm9yIHRoZSByZXNpZHVhbHMgb2YgdGhlIEFSSU1BLVNBUklNQSBtb2RlbC4gVG8gZG8gdGhpcywgZ2V0IHRoZSByZXNpZHVhbHMgYXMgZm9sbG93czoKCmBgYHtyfQphaXJfcmVzIDwtIG0xJHJlc2lkdWFscwpoZWFkKGFpcl9yZXMpCmBgYAojIFRlc3Qgd2hldGhlciB0aGUgcmVzaWR1YWxzIGlzIGEgd2hpdGUgbm9pc2Ugc2VyaWVzClRlc3Qgd2hldGhlciB0aGUgcmVzaWR1YWwgc2VyaWVzICh0aGUgYWlyX3JlcyB2YXJpYWJsZSkgaXMgYSB3aGl0ZSBub2lzZSBydW5uaW5nIHRoZSBhYyBhbmQgcGFjIHBsb3RzLiBBIHdoaXRlIG5vaXNlIGlzIGEgc2VyaWVzIHRoYXQgaGFzIG5vIHNpZ25pY2FudCBhdXRvY29ycmVsYXRpb25zIHdpdGggYW55IG9mIGl0cyBvd24gbGFncy4KCmBgYHtyfQphY2YyKGFpcl9yZXMpCmBgYAoKSU5URVJQUkVUIHRoZXNlIHBsb3RzClRIRVNFIFBMT1RTIEFSRSBNRUFOVCBUTyBURVNUIFdIRVRIRVIgVEhFIFJFU0lEVUFMIFNFUklFUyBIQVZFIFdISVRFIE5PSVNFIFJVTk5JTkcgSU4gVEhFSVIgUExPVFMuIEFTIERFRklORUQgRUFSTElFUiwgV0hJVEUgTk9JU0UgSVMgQSBTRVJJRVMgVEhBVCBIQVMgTk8gU0lHTklGSUNBTlQgQVVUT0NPUlJFTEFUSU9OUyBXSVRIIEFOWSBPRiBUSEUgTEFHUy4gVEhFIFBMT1RTIFNVR0dFU1QgVEhFU0UgUkVTSURVQUxTIEFSRU5UIFdISVRFIE5PSVNFIERVRSBUTyBUSEUgQU1PVU5UIE9GIElOQ0lERU5DWSBJTiBUSEUgNzUwMDAwIEFORCAxMDAwMDAgTEFHIE1BUktFUlMuIAoKQ2FuIHlvdSBhZGQgYW5vdGhlciBBUiBvciBNQSB0ZXJtIHRvIGltcHJvdmUgdGhlIHByZXZpb3VzIG1vZGVsIGFuZCB0aGVuIHRvIG1ha2UgdGhlIHJlc2lkdWFsIGEgd2hpdGUgbm9pc2UgPwoKWUVTLCBXRSBDQU4gQUREIE1PUkUgVEVSTVMgQU5EIEVTVElNQVRFIFRIRSBBUklNQS1TQVJJTUEgTU9ERUwgQVMgSU5TVFJVQ1RFRCBFQVJMSUVSIElOIFRISVMgV09SS1NIT1AuIAoKIyBGb3JlY2FzdCBhaXIgcGFzc2VuZ2VycwpXZSByZS1ydW4gdGhlIEFyaW1hIG1vZGVsIHdlIHJ1biBhYm92ZSwgYnV0IG5vdyB3ZSB3aWxsIHRyYW5zZm9ybSB0aGUgZGF0YXNldCBmcm9tIHh0cyB0byBhIHRzIFIgb2JqZWN0IHRvIGltcHJvdmUgdGhlIHZpc3VhbGl6YXRpb24gb2YgdGhlIGZvcmVjYXN0OgoKYGBge3J9CiNDb252ZXJ0IHRoZSB4dHMgdG8gYSB0cyBkYXRhc2V0OgphaXIudHMgPC0gdHMoY29yZWRhdGEoYWlyLnh0cyRQYXNzZW5nZXJzKSxzdGFydD1jKDE5NDksMSksZnJlcXVlbmN5PTEyKQojIFdlIGRpc3BsYXkgdGhlIGNvbnRlbnQgb2YgdGhlIHRzIGRhdGFzZXQ6CmFpci50cwpgYGAKCmBgYHtyfQojIFJ1biB0aGUgQXJpbWEgbW9kZWw6Cm0xIDwtIEFyaW1hKGFpci50cywgb3JkZXIgPSBjKDIsMCwwKSwgIyBwPTI6aW5jbHVkZSAyIEFSIHRlcm1zOyBxPTA6IE5vIE1BIHRlcm1zOwogICAgICAgc2Vhc29uYWwgPSBsaXN0KG9yZGVyPWMoMCwxLDApLCAjIEQ9MTogdXNlIHNlYXNvbmFsIGRpZmZlcmVuY2U7IE5vIFNlYXNvbmFsIHRlcm1zCiAgICAgICAgICAgICAgICAgICAgICAgcGVyaW9kPTEyKSwgICMgcGVyaW9kcz0xMiBwZXJpb2QgaW4gdGhlIHllYXIKICAgICAgICBpbmNsdWRlLmNvbnN0YW50ID0gVFJVRSwgIyBpbmNsdWRlIHRoZSBwaGkwIChkcmlmdCkgY29lZmZpY2llbnQKICAgICAgICBsYW1iZGEgPSAwKSAjIGRvIHRoZSBsb2cgdHJhbnNmb3JtYXRpb24KbTEKYGBgCmBgYHtyfQojIFdlIGNhbiBzZWUgdGhlIHB2YWx1ZXMgb2YgZWFjaCBBUklNQS1TQVJJTUEgY29lZmZpY2llbnQgdXNpbmcgdGhlCiMgICBjb2VmdGVzdCBmcm9tIHRoZSBsbXRlc3QgbGlicmFyeToKY29lZnRlc3QobTEpCmBgYApUaGUgcHZhbHVlIG9mIHRoZSBkcmlmdCwgz5UwLCBhbmQgdGhlIHB2YWx1ZXMgb2YgdGhlIEFSIGNvZWZmaWNpZW50cywgz5UxIGFuZCDPlTIsIGFyZSB2ZXJ5IHNpZ25pZmljYW50ICg8MC4wNSkuIFRoZW4gd2Uga2VlcCB0aGVzZSB0ZXJtcyBpbiB0aGUgbW9kZWwuCgpVc2luZyB0aGUgbGFzdCBBcmltYSBtb2RlbCwgcnVuIGEgZm9yZWNhc3QgZm9yIHRoZSBmb2xsb3dpbmcgMjQgbW9udGhzLgoKV2UgcnVuIHRoZSBmb3Jlc2Nhc3QgdXNpbmcgdGhlIGFyaW1hIG1vZGVsIG0xICh0aGUgb25lIEkgcnVuIHdpdGggdGhlIEFyaW1hIGZ1bmN0aW9uLiBXZSBpbmRpY2F0ZSB0byBkbyBhIGZvcmVjYXN0IGZvciAyNCBtb250aHMsIHNwZWNpZnlpbmcgaD0yNDoKCmBgYHtyfQpmb3JlY2FzdF9haXIgPC0gZm9yZWNhc3QobTEsIGg9MjQpCiMgSSBzdG9yZWQgdGhlIGluZm9ybWF0aW9uIG9mIHRoZSBmb3JlY2FzdCBpbiBmb3JlY2FzdF9haXIKCiMgSSBwbG90IHRoZSBmb3JlY2FzdAphdXRvcGxvdChmb3JlY2FzdF9haXIpCmBgYApUaGUgZm9yZWNhc3RfYWlyIFIgb2JqZWN0IGhhcyBib3RoLCBoaXN0b3JpY2FsIGRhdGEgYW5kIGZvcmVjYXN0IGRhdGEuIEEgdmVyeSBuaWNlIGZlYXR1cmUgb2YgdGhlIGZvcmVjYXN0IGZ1bmN0aW9uIGFmdGVyIHVzaW5nIEFyaW1hIGZ1bmN0aW9uLCBpcyB0aGF0IHdlIERPIE5PVCBIQVZFIFRPIGRvIHRyYW5zZm9ybWF0aW9ucyB0byBnZXQgdGhlIG9yaWdpbmFsIHNjYWxlIG9mIHRoZSB2YXJpYWJsZSwgd2hpY2ggaXMgaW4gdG9ucy4gVGhlIEFyaW1hIGZ1bmN0aW9uIGF1dG9tYXRpY2FsbHkgZG9lcyB0aGUgbG9nIHRyYW5zZm9ybWF0aW9uLCBhbmQgdGhlIGZvcmVjYXN0IGZ1bmN0aW9uIGF1dG9tYXRpY2FsbHkgZG9lcyB0aGUgZXhwb25lbnRpYWwgdHJhbnNvZnJtYXRpb24gdG8gZ2V0IHRoZSBmb3JlY2FzdCBpbiB0b25zIQoKVGhlIGZvcmVjYXN0X2FpciBSIG9iamVjdCBpcyBhIGxpc3QgdHlwZSBvZiBvYmplY3QgdGhhdCBjb250YWlucyBzZXZlcmFsIGVsZW1lbnRzLgoKYGBge3J9CmF0dHJpYnV0ZXMoZm9yZWNhc3RfYWlyKQpgYGAKVGhlIGZvcmVjYXN0IHZhbHVlcyBhcmUgaW4gdGhlIG1lYW4gYXR0cmlidXRlOgoKYGBge3J9CmZvcmVjYXN0X2FpciRtZWFuCmBgYAoKZm9yZWNhc3RfYWlyIGFsc28gaGFzIGhpc3RvcmljYWwgZGF0YSAoeCksIHJlc2lkdWFscywgdGhlIGxvd2VyIGFuZCB1cHBlciBsaW1pdCBvZiB0aGUgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgb2YgdGhlIGZvcmVjYXN0LCBldGMgIQoKIyBRIENIQUxMRU5HRSAtIE1vZGVsbGluZyBjb25zdW1lciBzYWxlcyB3aXRoIGFuIEFSSU1BL1NBUklNQSBtb2RlbAoKRllJCkJFRk9SRSBZT1UgQ09OVElOVUUgUkVBRElORyBNWSBXT1JLU0hPUCwgUExFQVNFIEtOT1cgVEhBVCBJIERJRE4nVCBNQU5BR0UgVE8gU09MVkUgSVQuIEkgVFJJRUQgTUFOWSBUSU1FUyBCVVQgSSBDT1VMRE4nVCBIQUNLIElULiBUSEVPUkVUSUNBTCBRVUVTVElPTlMgV0VSRSBBTlNXRVJFRCBCVVQgSSBDT1VMRE4nVCBNT0RFTC4gCgpHbyB0byB0aGUgY291cnNlIHNpdGUgKE1hdGVyaWFsKSBhbmQgZG93bmxvYWQgRHIuIE5hdSBzbGlkZXMgYWJvdXQgQVJJTUEvU0FSSU1BIG1vZGVscy4gUmVhZCB0aGUgc2xpZGVzIGFuZCBmb2N1cyBvbiBoaXMgcmVjb21tZW5kYXRpb25zIHRvIHNlbGVjdCB0aGUgbnVtYmVyIG9mIHAsIGQsIHEsIFAsIEQsIFEgZm9yIGFueSBBUklNQS9TQVJJTUEgbW9kZWwuIERvd25sb2FkIHRoZSBmb2xsb3dpbmcgRGF0YXNldDoKCmBgYHtyfQpkb3dubG9hZC5maWxlKCJodHRwOi8vd3d3LmFwcmFkaWUuY29tL2VjMjAwNC9zYWxlc2ZhYjIueGxzeCIsICJzYWxlc2ZhYnMyLnhsc3giLCBtb2RlPSJ3YiIpCmBgYApOb3csIHdlIHJlYWQgdGhlIGRhdGEgZnJvbSB0aGUgRXhjZWwgZmlsZSBhbmQgY29uc3RydWN0IGFuIHh0cyBkYXRhc2V0OgoKYGBge3J9CnNhbGVzX2JyYW5kcyA8LSByZWFkX3hsc3goInNhbGVzZmFiczIueGxzeCIsIHNoZWV0ID0gIlNoZWV0MSIpCgojSSBjcmVhdGUgYW4geHRzIG9iamVjdCB0byBoYW5kbGUgdGhlIG9iamVjdCBhbmQgZGF0ZXMgaW4gYSBiZXR0ZXIgd2F5OgoKIyBJIGNvbnN0cnVjdCBhIGRhdGUgdmFyaWFibGUgYXMgYSBzZXF1ZW5jZSBvZiBkYXRlcyB1c2luZyB0aGUgbW9udGggY29sdW1uOgpkYXRlIDwtIHNlcShhcy5EYXRlKHNhbGVzX2JyYW5kcyRtb250aFsxXSksCiAgICAgICAgICAgICAgICAgICAgICBieT0ibW9udGgiLAogICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoLm91dCA9IG5yb3coc2FsZXNfYnJhbmRzKSApCiMgSSBkZWxldGUgdGhlIGZpcnN0IGNvbHVtbiBzaW5jZSBpdCBoYXMgdGhlIG1vbnRoLCBhbmQgSSB3aWxsIGNvbnN0cnVjdAojICAgYW4geHRzIGRhdGFzZXQgd2l0aCB0aGUgaW5kZXggZXF1YWwgdG8gdGhlIG1vbnRoCnNhbGVzX2JyYW5kcyA9IHNhbGVzX2JyYW5kc1ssLTFdCgojIEkgY3JlYXRlIHRoZSB4dHMgb2JqZWN0OgpzYWxlc19icmFuZHM8LSB4dHMoeD1zYWxlc19icmFuZHMsIGZyZXF1ZW5jeSA9ICJtb250aGx5Iiwgb3JkZXIuYnk9ZGF0ZSkKYGBgCgpUaGlzIGRhdGFzZXQgY29udGFpbnMgY29uc3VtZXIgbmF0aW9uYWwgbW9udGhseSBzYWxlcyBvZiBhIENhdGVnb3J5IG9mIHByb2R1Y3RzLiBUaGUgc2FsZXMgaXMgaW4gdG9ucyAocWZhYiMpIGFuZCBwcmljZXMgKHBmYWIjKSBhbmQgaW5jbHVkZSBzYWxlcyBvZiBmZXcgcHJvZHVjdHMuIFlvdSBoYXZlIHRvIGRvIHRoZSBmb2xsb3dpbmc6CgpgYGB7cn0KZGF0YXNldCA8LSByZWFkX2V4Y2VsKCJzYWxlc2ZhYnMyLnhsc3giKQojIEkgZmFtaWxpYXJpemUgd2l0aCB0aGUgZGF0YQpoZWFkKGRhdGFzZXQpCmBgYAoKYGBge3J9CiMgSSBqb2luIGJvdGggb2JqZWN0cyB1c2luZyB4dHMoKSBhbmQgYXNzaWduIGl0IHRvIGEgbmV3IG9iamVjdCBjYWxsZWQgcHJpY2UueHRzCnByaWNlLnh0czwtIHh0cyh4PXNhbGVzX2JyYW5kcyRwcmljZSwgZnJlcXVlbmN5ID0gIm1vbnRobHkiLCBvcmRlci5ieT1kYXRlKQpjbGFzcyhwcmljZS54dHMpCmBgYApgYGB7cn0KIyBMb2FkIGxpYnJhcnkgeHRzIGFuZCB6b28uIEluc3RhbGwgdGhlIHBhY2thZ2VzIGlmIHlvdSBoYXZlbid0IGFscmVhZHkuCmxpYnJhcnkoeHRzKQpsaWJyYXJ5KHpvbykKbGlicmFyeSh0c2VyaWVzKQpsaWJyYXJ5KGZvcmVjYXN0KQoKCiMgSSBnZXQgdGhlIGRhdGUgb2YgdGhlIGRhdGFzZXQ6CmRhdGUgPC0gZGF0YXNldCRtb250aAojIEkgam9pbiBib3RoIG9iamVjdHMgdXNpbmcgeHRzKCkgYW5kIGFzc2lnbiBpdCB0byBhIG5ldyBvYmplY3QgY2FsbGVkIHZvbHVtZS54dHMKdm9sdW1lLnh0czwtIHh0cyh4PXNhbGVzX2JyYW5kcyR2b2x1bWUsIGZyZXF1ZW5jeSA9ICJtb250aGx5Iiwgb3JkZXIuYnk9ZGF0ZSkKY2xhc3Modm9sdW1lLnh0cykKYGBgCgoKR2VuZXJhdGUgdGhlIGxvZyB2YXJpYWJsZXMgZm9yIHByaWNlIChwZmFiMSkgYW5kIHNhbGVzIGluIHZvbHVtZSAocWZhYjEpIGZvciBwcm9kdWN0IDEuCgpgYGB7cn0KbG5wcmljZS54dHMgPSBsb2cocHJpY2UueHRzKQpgYGAKYGBge3J9Cmxudm9sdW1lLnh0cyA9IGxvZyh2b2x1bWUueHRzKQpgYGAKCgpOb3cgeW91IGhhdmUgdG8gd29yayBpbiBhIG1vZGVsIGZvciBxZmFiMSwgc2FsZXMgaW4gdG9ucyBvZiBwcm9kdWN0IDE6CgpgYGB7cn0KcGxvdCh2b2x1bWUueHRzJGRhdGUpCmBgYAoKCkdyYXBoIHRoZSBuYXR1cmFsIGxvZyBvZiBzYWxlcyBpbiB0b25zIG9mIHRoaXMgcHJvZHVjdC4gV0hBVCBETyBZT1UgT0JTRVJWRSBhYm91dCB0aGUgc2VyaWVzPyBkb2VzIGl0IGxvb2sgc3RhdGlvbmFyeSBvciBub25zdGF0aW9uYXJ5PyBkb2VzIGl0IGxvb2sgd2l0aCBzZWFzb25hbGl0eT8KCgpgYGB7cn0KcGxvdChkaWZmKGxudm9sdW1lLnh0cyxsYWc9MTIpKQpgYGAKCgpJZiB0aGUgc2VyaWVzIGlzIG5vdCBzdGF0aW9uYXJ5LCB0cnkgd2hldGhlciB0aGUgc2Vhc29uYWwgZGlmZmVyZW5jZSBvZiB0aGUgbG9nIGxvb2tzIGFzIHN0YXRpb25hcnkgKHMxMi5sbnFmYWIxKS4gRG8gYSB0aW1lIHNlcmllcyBwbG90LCBydW4gYW5kIElOVEVSUFJFVCB0aGUgRGlja3ktRnVsbGVyIHRlc3QKCgpgYGB7cn0KYWRmLnRlc3QobmEub21pdChkaWZmKGxudm9sdW1lLnh0cyxsYWc9MCkpLGFsdGVybmF0aXZlPSJzdGF0aW9uYXJ5IixrPTApCmBgYAoKQWNjb3JkaW5nIHRvIERyIE5hdSBzbGlkZXMgYW5kIHdoYXQgeW91IGxlYXJuZWQgaW4gdGhpcyB3b3Jrc2hvcCwgY2FsaWJyYXRlIHRoZSBiZXN0IEFSSU1BL1NBUklNQSBtb2RlbC4KCkknVkUgVFJJRUQgTUFOWSBUSU1FUywgQ0FOVCBETyBJVD8KYGBge3J9CmxpYnJhcnkoYXN0c2EpCiMgSSBjcmVhdGUgYSB0cyBvYmplY3QgZnJvbSB0aGUgeHRzOyB0aGUgYWNmMiB3b3JrcyBiZXR0ZXIgd2l0aCB0cyBvYmplY3RzCmxudm9sdW1lLnh0cyA9dHMobG52b2x1bWUueHRzJHRvbnMpCmFjZjIoZGlmZihsbmFpcixsYWc9MTIpKQpgYGAKCldoYXQgaXMgYSB3aGl0ZSBub2lzZSBzZXJpZXM/IFJFU1BPTkQgV0lUSCBZT1VSIFdPUkRTCgpXSEVOIFdISVRFIE5PSVNFIElTIFBSRVNFTlQsIEFOWSBQQUlSIE9GIFZBTFVFUyBUSEFUIENBTiBCRSBUQUtFTiBBVCBBTlkgR0lWRU4gVElNRSBBUkUgTk9UIENPUlJFTEFURUQuIElUIElTIEEgU1RBVElPTkFSWSBUSU1FIFNFUklFUyBXSVRIIE5PIEFVVE9DT1JSRUxBVElPTi4KCkNyZWF0ZSBhIHZhcmlhYmxlIGZvciB0aGUgcmVzaWR1YWxzIG9mIHlvdXIgbW9kZWwuIFJ1biB0aGUgQUNGIHBsb3QgYW5kIHRoZSBQQUNGIHBsb3QgZm9yIHRoaXMgcmVzaWR1YWwuIERvZXMgdGhlIHJlc2lkdWFsIGxvb2sgbGlrZSBhIHdoaXRlIG5vaXNlPwpgYGB7cn0KbTEgPC0gQXJpbWEodm9sdW1lLnh0cyR0b25zLCBvcmRlciA9IGMoMiwwLDApLCBzZWFzb25hbCA9IGxpc3Qob3JkZXI9YygwLDEsMCkscGVyaW9kPTEyKSwgaW5jbHVkZS5jb25zdGFudCA9IFRSVUUsIGxhbWJkYSA9IDApbTEKYGBgCmBgYHtyfQptMWE8LXNhcmltYShsb2codm9sdW1lLnh0cyR0b25zKSwgcD0yLCBkPTAsIHE9MCxQPTAsRD0xLFE9MCxTPTEyKQpgYGAKCldoeSBkbyB5b3UgdGhpbmsgdGhhdCB0aGUgcmVzaWR1YWxzIG9mIHlvdXIgYmVzdCBtb2RlbCBzaG91bGQgbG9vayBsaWtlIEEgV2hpdGUgbm9pc2U/IFJFU1BPTkQgV0lUSCBZT1VSIE9XTiBXT1JEUwoKSSdWRSBUUklFRCBNQU5ZIFRJTUVTLCBDQU5UIERPIElULgoKQ3JlYXRlIDI0IG5ldyBvYnNlcnZhdGlvbnMgaW4gdGhlIGZ1dHVyZQpJJ1ZFIFRSSUVEIE1BTlkgVElNRVMsIENBTlQgRE8gSVQuCkNyZWF0ZSBhIGZvcmVjYXN0IGZvciB0aGUgZnV0dXJlIG9ic2VydmF0aW9ucyB1c2luZyB5b3VyIGxhc3QgbW9kZWwKSSdWRSBUUklFRCBNQU5ZIFRJTUVTLCBDQU5UIERPIElULgoob3B0aW9uYWwpIEVzdGltYXRlIHRoZSBBa2Fpa2UgSW5mb3JtYXRpb24gQ3JpdGVyaW9uIChBSUMpIG9mIHRoZSBtb2RlbC4gVG8gZG8gdGhpcywgcnVuIHRoZSBmb2xsb3dpbmcgY29tbWFuZCByaWdodCBhZnRlciBydW5uaW5nIHlvdXIgYXJpbWEgbW9kZWw6CkknVkUgVFJJRUQgTUFOWSBUSU1FUywgQ0FOVCBETyBJVC4KCkRvIGEgcXVpY2sgcmVzZWFyY2ggYWJvdXQgd2hhdCBpcyB0aGUgQUlDIG9mIHRoZSBtb2RlbCBhbmQgRVhQTEFJTiBXSVRIIFlPVVIgT1dOIFdPUkRTCgpBSUMgU1RBTkRTIEZPUiBBS0lBS0UgSU5GT1JNQVRJT04gQ1JJVEVSSU9OLiBUSElTIE1BVEhFTUFUSElDQUwgTUVUSE9EIEZPUiBFVkFMVUFUSU9OIEFMTE9XUyBUTyBLTk9XIEhPVyBXRUxMIEEgTU9ERUwgRklUUyBUSEUgREFUQSBJVCBPUklHSU5BVEVEIEZST00uIElUJ1MgVVNFIElOIFNUQVRJU1RJQ1MgSVMgRk9SIENPTVBBUklORyBESUZGRVJFTlQgTU9ERUxTIElOIE9SREVSIFRPIENIT09TRSBUSEUgQkVTVCBPTkUuIElOIE9SREVSIFRPIENBTENVTEFURSBBSUMsIE9ORSBORUVEUyBUSEUgRk9MTE9XSU5HLiAKClRIRSBOVU1CRVIgT0YgSU5ERVBFTkRFTlQgVkFSSUFCTEVTIFVTRUQgVE8gQlVJTEQgU0FJRCBNT0RFTC4KVEhFIE1BWElNVU0gTElLRUxJSE9PRCBFU1RJTUFURSBPRiBUSEUgTU9ERUwKCiJUaGUgYmVzdC1maXQgbW9kZWwgYWNjb3JkaW5nIHRvIEFJQyBpcyB0aGUgb25lIHRoYXQgZXhwbGFpbnMgdGhlIGdyZWF0ZXN0IGFtb3VudCBvZiB2YXJpYXRpb24gdXNpbmcgdGhlIGZld2VzdCBwb3NzaWJsZSBpbmRlcGVuZGVudCB2YXJpYWJsZXMuIiAoUi4gQkVWQU5TLCAyMDIxKS4KCkJldmFucywgUi4gKDIwMjEsIEp1bmUgMTgpLiBBbiBpbnRyb2R1Y3Rpb24gdG8gdGhlIGFrYWlrZSBpbmZvcm1hdGlvbiBjcml0ZXJpb24uIFNjcmliYnIuIFJldHJpZXZlZCBNYXJjaCAxNiwgMjAyMiwgZnJvbSBodHRwczovL3d3dy5zY3JpYmJyLmNvbS9zdGF0aXN0aWNzL2FrYWlrZS1pbmZvcm1hdGlvbi1jcml0ZXJpb24vIzp+OnRleHQ9VGhlJTIwQWthaWtlJTIwaW5mb3JtYXRpb24lMjBjcml0ZXJpb24lMjAoQUlDLGJlc3QlMjBmaXQlMjBmb3IlMjB0aGUlMjBkYXRhLiAKCgoK