Workshop 3, Financial Econometrics II
Alberto Dorantes, Ph.D. Aug 24, 2021
Abstract
The main purpose of this workshop is to illustrate the foundations of
Autoregressive Moving Average models - ARMA. We will apply the ARMA
model to a dataset of sales of real consumer products.
Introduction
The main purpose of this workshop is to illustrate what are
Autoregressive Moving Average models - ARMA - and how they are
constructed. This methodology is part of the Box-Jenkins models for time
series, which provide a series of tools to understand past behavior and
predict future values of time series. Given a time series Yt, the ARMA
model can be be denoted as ARMA(p,q) where p is the number of
autoregressive terms and q refers to the number of moving-average
terms.
The AR(p) model
In general the autoregressive models assume that there is some kind
of autocorrelation phenomenon in the time series. The concept of
autocorrelation implies the correlation of a random variables with its
past and future values. This is the building block behind these
models.
In time-series Econometrics we can talk about an autocorrelation in
the dependent variable (also called, endogeneous variable). This means
the future values of an economic or financial variable can be explained
somehow by its previous values. This is the foundation of what
econometricians have called an Autoregressive Model also denoted as AR
model. The autoregressive notation of the stochastic model defined by Yt
can be described as follows:
Yt=ϕ0+ϕ1Yt−1+ϕ2Yt−2+…+ϕpYt−p+ϵt
Where ϕ1,…ϕp are the parameters of the model, ϵt refers to the error
term or random shock. We can express the same equation as follows:
Yt=ϕ0+∑k=1pϕkYt−k+ϵt
In order to apply this model we have to prove the series Yt is
stationary. We will learn later how to test statistically whether a
series can be considered stationary or not. If the series is not
stationary, we can calculate the first difference of the series, and
most of the time the resulting series will become stationary.
In linear regression models, the method to estimate the regression
coefficients is the Ordinary Least Squares (OLS). For ARMA models, the
best method to estimate the autoregressive coefficients is the Maximum
Likelihood (ML) method. The ML method works with iterations, while OLS
has an analytic solution (in othe words, a formula). Fortunately, R can
estimate this for you.
In a traditional linear regression model using time series variables,
we assume that the errors are not correlated among them. If this
assumption is violated (the errors are autocorrelated), then we can use
autoregressive models that will include autoregressive terms to leave
errors with no correlation (independent errors, also called, white
noise).
Now I will explain what is a moving average model.
The MA(q) model
The AR(p) model is a process with a long-term memory. Why? this is
because a shock today will impact in the future forever. If you read the
mathematical equation, this can be interpreted as follows. The value of
the series tomorrow will depend on the value of today, after applying
the filter ϕ1. Then, the value of tomorrow already has informationabout
the value of today. And the value of tomorrow will impact the value of 2
days from now. Then, the value of today will have an impact in the whole
future of the series.
However, the impact of the value of today will be diminishihg
exponentially according to (ϕ1)N, where N is the number of periods in
the future. Since |ϕ1|<1, then the bigger the exponent N -which
refers to a further future period- the smaller the effect.
If we want to model a series with a short-term memory, then we have
to think in a different equation:
Yt=θ0+θ1ϵt−1+θ2ϵt−2+…+θqϵt−q+ϵt
This is called a “Moving-Average” model with q terms. In this case,
the value of today is not directly affected by its previous own value,
but the past random shocks. In the case of q=1, this process doesnot
have long memory since the value of today is only affected by the shock
of yesterday.
The more q terms included into the model, then the longer the memory
of the model. Most of the cases, real-world series only include very few
q terms.
In the MA(q) model, θ0, … θq are the parameters of the model, ϵt−k
refers to past external errors/shocks, and the current external shock is
defined as ϵt, so:
Yt=θ0+ϵt+∑k=1qθkϵt−k
We can interpret an MA model as a random process where the current
value of the series is influenced by the current random shock, and by
some percentages of previous random q shocks/errors. The percentages are
actually the values of the coefficients θ.
In Finance, when we want to model the behavior of market returns, we
know that there are thousands of events that affect how the market
returns are moving today. These thousands of events are basically
summarized in a “random shock” that nobody knows what will be its
magnitud and direction (positive or negative effect).
Now I will put together both AR and MA model into one, the ARMA
model.
ARMA(p,q) model
Now we can combine both AR(p) terms and MA(q) terms into ONE model,
that is called ARMA(p,q):
Yt=ϕ0+∑k=1pϕkYt−k+∑k=1qθkϵt−k+ϵt
We combine AR and MA terms to model Y in case Y can be modeled
including short-term and long-term memory. The long-term memory is
modeled with the AR terms, while the short-term memory is modeled with
the MA terms. We will practice with an example to ilustrate this
theoretical model.
Hand-on activity
We will work with an online dataset that contains sales data of
different consumer products. The data was created using real products,
but the names of the products were changed due to privacy issues.
Download the excel file from a web site:
download.file("http://www.apradie.com/ec2004/salesbrands3.xlsx", "salesbrands3.xlsx", mode="wb")
trying URL 'http://www.apradie.com/ec2004/salesbrands3.xlsx'
Content type 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' length 18194 bytes (17 KB)
==================================================
downloaded 17 KB
This dataset has sales information of several brands of consumer
products that belong to one category (for example, the category can be
Cereals or Candies). The content of this dataset is very similar to a
real-world category. Consumer products usually show some seasonality and
trend over time. We will learn how to handle these features later.
Also, you have to install the readxl package. This package reads data
from Excel files. We load this package:
library(readxl)
Now, we import the Excel file into an R dataframe:
sales_brands <- read_excel("salesbrands3.xlsx", sheet = "Resultado")
# Always familiarize with the data
head(sales_brands, 5)
As you can see, we have imported a monthly dataset where the variable
date shows the first day of the month in a yyyy-mm-dd format.
In order to perform some time-series analysis, it is recommended to
use xts objects. We will construct a xts object using the xts() method.
The objects of xts class are composed by 2 objects: the core data and
the index (class Date, POSIX, etc).
# Load library xts. Install the package if you haven't already.
library(xts)
Loading required package: zoo
Attaching package: ‘zoo’
The following objects are masked from ‘package:base’:
as.Date, as.Date.numeric
# We will start by turning sales_brands into a data frame
# because data frames are easier to manipulate
sales_brands.df <- as.data.frame(sales_brands)
# Divide the index and the core data:
# I get the date in a new variable fecha:
fecha <- sales_brands.df$date
# The first column of the sales_brand.df is the date.
# I drop this column since I copied to fecha:
sales_brands.df <- sales_brands.df[,-1]
# Now I join both objects using xts() and assign the resulting object to sales.xts
sales.xts <- xts(x = sales_brands.df, order.by = fecha)
head(sales.xts, 5)
qbrand1tons salesbrand1 qbrand2tons salesbrand2
2015-01-01 106.62 60780.72 195.46 60700.51
2015-02-01 105.82 60411.47 216.09 68289.15
2015-03-01 88.82 53174.89 220.15 62529.54
2015-04-01 86.69 50861.69 170.74 50575.68
2015-05-01 87.23 51014.23 177.17 54327.48
qbrand3tons salesbrand3 qbrand4tons salesbrand4
2015-01-01 293.10 75196.35 185.91 48228.51
2015-02-01 494.46 105010.90 149.30 39922.14
2015-03-01 356.88 90902.84 144.65 39788.22
2015-04-01 291.07 72853.34 161.43 42692.59
2015-05-01 318.09 75277.10 141.09 37167.52
qbrand5tons salesbrand5 qbrand6tons salesbrand6
2015-01-01 28.94 2295.50 338.38 55561.26
2015-02-01 24.66 1973.43 284.52 51469.74
2015-03-01 23.75 1903.24 251.34 50395.48
2015-04-01 21.00 1684.28 230.29 49124.61
2015-05-01 23.44 1883.41 250.45 46906.63
tonstotal salestotal
2015-01-01 1148.41 302762.8
2015-02-01 1274.85 327076.8
2015-03-01 1085.59 298694.2
2015-04-01 961.22 267792.2
2015-05-01 997.47 266576.4
# Do you notice any difference between data frames and xts objects?
#delete variable fecha
rm(fecha)
Stationary vs Non-stationary
We can have an overview of the behaviour of sales of these consumer
products using the plot command. Let’s focus on brand 2 and 6. To see
volume sales (the number of tons sold) of brand 2:
plot(sales.xts$qbrand2tons)

It seems that this product has a growing trend over time, except for
the last year.
We can graph consumer brand 6
plot(sales.xts$qbrand6tons)

This brand has a clear growing trend over time. As we can see, many
consumer products have a growing or a declining trend. And other
products might seem to be stationary over time, with sales over an
average over time.
A series with a growing or declining trend is non-stationary. Most of
the variables that represent sales of any product can be treated as
non-stationary. Then, a rule of thumb when we work with business
variables such as volume sales, value sales, cost of good sold, etc is
to transform the series into a stationary series.
When you work with sales data, I strongly recommend to create the
first difference of the logarithm of the variable. This is actually its
percentage change (in continuously compounded). If you do this process
to most of real-world sales variable the result will be stationary most
of the time (about 95% of the variables). The other reason why it is
recommended to do this transformation is that the first difference of
the log of a variable is actually the % change of the variable from one
period to the next (in continuously compounded percentage). Then, we can
do this transformation as follows:
We first create the natural log of each sales variable (in tons). We
can apply the log function to the xts object to get the log of all
series:
ln_sales <- log(sales.xts)
The new object has the same structure as sales.xts but the columns
contain the natural logarithm of the data. This is due to R
vectorization, a key feature of R.
Now, I can work with the first difference month-by-month using the
diff() function for each variable. For example, to graph the first
difference of the log of volume sales for both brands :
plot(diff(ln_sales$qbrand2tons), type = "l", col = "red")
lines(diff(ln_sales$qbrand6tons), type = "l", col = "blue")

The first difference of the log value in R is
diff(ln_sales$qbrand2tons). The diff() function generates on the fly
this first difference as:
diff(ln_salesqbrand2tons)=lnsalesqbrand2tons -
lag(ln_sales$qbrand2tons, 1)
Remember that the dollar sign operator ($) is used to access/refer to
the columns of a data frame or xts object.
We can see now that the 2 series look like stationary since their
means tend to be in the same level.
R performs the first difference calculation temporarily to do a
graph, and then, this variable is not saved in the dataset or
environment. In other words, we do not need to generate the first
difference as another variable (column), but we can if we need to.
Another transformation with monthly data is annual percentage change.
In this case, this is the difference between the log value of the series
and its value 12 periods ago. We can check this difference using the
diff() function with the lag argument set to 12:
# I create a variable for the seasonal difference of the log of sales, which
# is the annual % change of sales (in continuously compounded):
s12.lnqbrand2 = diff(ln_sales$qbrand2tons, lag = 12)
# I plot this new variable, the annual % change of sales for product 2:
plot(s12.lnqbrand2, type = "l", col = "red")

# I do the same for product 6:
s12.lnqbrand6 = diff(ln_sales$qbrand6tons, lag = 12)
# I plot this new variable, the annual % change of sales for product 2:
plot(s12.lnqbrand6, type = "l", col = "blue")

In this case, the series for both brands do not look stationary. But
we need to do a statistical test to check whether a series can be
treated as stationary or not. Some series might not look stationary for
our eyes, but we need to run statistical tests to decide whether to
treat the series stationary or not. There is a statistical way to
evaluate whether these series are stationary. We need a statistical
confirmation in addition to the visual tools.
The Dicky-Fuller test is one of the most used statistical tests for
stationary. This test is called a unit root test. The Dicky Fuller test
assumes that the series is non stationary. In other words, it assumes
that the series follows a random walk with a unit root (phi1=1). We can
run this test in R using the adf.test function from the tseries
package.
You need to install the package tseries to do the following
analysis.
library(tseries)
Registered S3 method overwritten by 'quantmod':
method from
as.zoo.data.frame zoo
‘tseries’ version: 0.10-49
‘tseries’ is a package for time series analysis
and computational finance.
See ‘library(help="tseries")’ for details.
# Before running the Dicky-Fuller test, we need to drop NA (missing) values of
# the variable:
s12.lnqbrand2 = na.omit(s12.lnqbrand2)
adf.test(s12.lnqbrand2, alternative = "stationary",k=0)
Augmented Dickey-Fuller Test
data: s12.lnqbrand2
Dickey-Fuller = -3.5079, Lag order = 0, p-value =
0.05421
alternative hypothesis: stationary
The adf.test() function from the tseries package will do a
Dickey-Fuller test if we set lags (k) equal to 0.
This is another way to do the same Dickey Fuller test:
The Dicky Fuller test reports a p-value. In this case, it is barely
greater than 0.05. In this case, we will consider the pvalue to be 0.05,
so we will have 95% confidence (1-pvalue) to reject the null hypothesis
that states a unit root for these series (ϕ1=1). In other words, for the
series with a Dicky-Fuller p-value less or equal than 0.05 we can say
that there is statistical evidence to conclude that the differenced
series (s12.lnbrand2tons) is stationary.
Then for the variable s12.lnbrand2tons we can say that there is
statistical evidence to say that the series is stationary.
If we try the same for brand 6 we will find that its seasonal
difference (s12.lnbrand6tons) is also stationary. Try this by
yourself.
For the case of monthly times series variables like sales of products
or sales of a company, I strongly recommend to work with the seasonal
difference of the log of sales (s12.lnbrand2tons), which is the annual
percentage change month by month. The reason is because most of consumer
products have a seasonal pattern. We can do this ONLY if the seasonal
difference of the log is STATIONARY.
For these 2 products, then, I will use the seasonal difference of the
log of sales.
Autocorrelations (AC) and Partial-autocorrelations (PAC)
In time series analysis, a correlogram is an chart of correlation
statistics also known as an autocorrelation plot. This is a plot of the
sample autocorrelations of the dependent variable Yt and the time lags.
In R, the command to compute the autocorrelations is acf2() from the
astsa package, which gives you both, the autocorrelation (ACF) figures
and the partial-autocorrelations (PACF), as well. Let’s examine the
autocorrelations of brand 2.
You need to install the astsa package to do auto-correlation
plots.
library(astsa)
acf2(s12.lnqbrand2)
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
ACF 0.59 0.51 0.35 0.21 0.05 -0.04 -0.13 -0.09
PACF 0.59 0.26 -0.04 -0.11 -0.15 -0.06 -0.05 0.11

The acf2() function gives you the autocorrelogram, which is the
autocorrelations in a graph where it is easy to identify which lags of
the variable have a significant autocorrelation.
The X axis represents the lag numbers, while the Y axis is the level
of autocorrelation. The vertical lines are the levels of
autocorrelations between the current value of Y (Yt) and its own lags.
The dotted, blue line delimits the 95% confidence interval for the
autocorrelations. Then, if the autocorrelation goes out of the 95% C.I.,
then the autocorrelation of the variable Yt with its corresponding lag
Yt−1 (AutoCorr(Yt,Yt−1)) is statistically different than zero. We can
see that only the lag 1 (Yt−1) and lag 2 (Yt−2) is significantly
autocorrelated (positively) with the current value of the variable since
this autocorrelation is significantly greater than zero.
What is the meaning of the first significant lag? In this case, this
means that the value of Y at any point in time t has an average
autocorrelation equal to ϕ1 (if the model ends up being an AR(1)) with
its own value at t−1. The autocorrelation of Yt with its previous value
Yt−1 can be calculated manually as the correlation, wich is equal to
their covariance divided by the product of their standard deviation.
Remembering the formula for correlation between 2 variables Y and X:
CORR(Y,X)=COV(Y,X)SD(Y)∗SD(X) In the case of “Autocorrelation”, we
only have one variable Y, so we are looking at the correlation of Yt
with its own previous value Yt−1. Then, applying the correlation formula
between Yt and Yt−1 (instead of X), we can calculate this
autocorrelation as:
AUTOCORR(Yt,Yt−1)=AUTOCOV(Yt,Yt−1)SD(Yt)∗SD(Yt−1) Since Y is supposed
to be stationary series, then the standard deviation of Yt has to be the
same as the standard deviation of Yt−1. Then:
AUTOCORR(Yt,Yt−1)=AUTOCOV(Yt,Yt−1)VAR(Yt)=γ(1)σ2y Fortunately, R does
the calculation of all the autocorrelations of Yt with its own lags, and
these autocorrelations are plotted using the acf2 command (as seen
above).
Unlike the ACF plot, the partial-autocorrelation (PACF) plot shows
the autocorrelation of the lag with the variable after considering the
effect of lower-order autocorrelations. The autocorrelation and partial
autocorrelation between Yt and Yt−1 are the same, since there is no
lower-order autocorrelations. The autocorrelation between Yt and Yt−1
and the partial autocorrelation between Yt and Yt−1 will be different
since the partial autocorrelation is calculated AFTER the
autocorrelation between Yt and Yt−1 is taken into consideration.
In other words, the PACF plot shows the amount of autocorrelation
between Yt and its lag K (Yt−k) that is not explained by lower-order
autocorrelations (Yt with (Yt−k) and all the corresponding
autocorrelations until Yt−1).
We see that in the ac plot lag 1 and 2 autocorrelations are positive
and significant, and the following lag autocorrelations are also
positive but not significant. We see that for each lag the
autocorrelation diminishes. In the partial autocorrelation (PACF) we can
see that ONLY the autocorrelation of lag 1 is significant and positive,
and immediatly the rest of the correlation go close to zero suddenly.
This is a classical AR(1) signature with only the first lag. We do not
need to include LAG 2 since the pac indicates to include only LAG1.
Then we can see that the partial autocorrelation plot (PACF) helps us
to identify the # of AR terms. Then, according to this PACF we see that
only lag 1 is autocorrelated with the current value AFTER considering
the effect of the lower-level autocorreations of lags 2,3,4, etc. In
other words, the annual %change in sales of the current month seems to
be positively correlated with the annual % change in sales 1 months
ago.
Running an AR(1) model
A first order autoregressive model using only the lag 1 can be
expresed as follows for an stochastic process Yt:
Yt=ϕ0+ϕ1Yt−1+ϵt
The process is stationary only if ∣ϕ1∣<1
I can run an AR model in R for brand 2 to test whether the absolute
value of ϕ1 is lower than 1. In R the function to run AR, MA, ARMA and
ARIMA models is the same: sarima() from the astsa package. Of course,
the syntax of the function’s arguments has to be adjusted to each model.
So, let’s run an AR model with lag 1 for brand 2.
You need to install the forecast package.
# Load package forecast
library(forecast)
This is forecast 8.16
Want to meet other forecasters? Join the International Institute of Forecasters:
http://forecasters.org/
Attaching package: ‘forecast’
The following object is masked from ‘package:astsa’:
gas
# Use function Arima
m1 <- Arima(s12.lnqbrand2, order = c(1,0,0))
summary(m1)
Series: s12.lnqbrand2
ARIMA(1,0,0) with non-zero mean
Coefficients:
ar1 mean
0.6266 0.0515
s.e. 0.1236 0.0355
sigma^2 = 0.008241: log likelihood = 41.95
AIC=-77.9 AICc=-77.27 BIC=-72.69
Training set error measures:
ME RMSE MAE MPE
Training set 0.003930423 0.08859139 0.06879971 -52.73237
MAPE MASE ACF1
Training set 144.4614 0.7041704 -0.2125151
According to the result, we can see that the coefficient ϕ1 is
positive, its absolute value is less than one, and it is significant
since its p-value is less than 0.05. In these cases we can say that the
autocorrelation is positive at the 95% confidence level.
We can write the equation of first order models for brand 2 as
follows:
s12.lnbrand2tons(t) = 0.0515 + 0.6266 * s12.lnbrand2tons(t-1)+
error(t)
Now we can use this model to do predictions. We will learn how to do
predictions in the following workshop.
QUESTION: INTERPRET THE COEFFICIENTS OF THIS AR(1) MODEL THE
PARAMETERS OF THE AR(1) MODEL COMPRISE REGRESSION COEFFICIENTS AT
SUCCESSIVE TIME LAGS, THAT ENCODE SEQUENTIAL DEPENDENCIES OF THE SYSTEM
IN A SIMPLE AND EFFECTIVE MATTER.
Challenge
Design an ARMA model for the brand 1 using the annual % growth. Run
the model and interpret it.
plot(sales.xts$qbrand1tons)

plot(diff(ln_sales$qbrand1tons), type = "l", col = "green")

s12.lnqbrand1 = diff(ln_sales$qbrand1tons, lag = 12)
plot(s12.lnqbrand1, type = "l", col = "green")

library(tseries)
# Before running the Dicky-Fuller test, we need to drop NA (missing) values of
# the variable:
s12.lnqbrand1 = na.omit(s12.lnqbrand1)
adf.test(s12.lnqbrand1, alternative = "stationary",k=0)
Warning in adf.test(s12.lnqbrand1, alternative = "stationary", k = 0) :
p-value smaller than printed p-value
Augmented Dickey-Fuller Test
data: s12.lnqbrand1
Dickey-Fuller = -4.6658, Lag order = 0, p-value = 0.01
alternative hypothesis: stationary
library(astsa)
acf2(s12.lnqbrand1)
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
ACF 0.63 0.48 0.39 0.20 0.22 0.31 0.38 0.34
PACF 0.63 0.15 0.06 -0.16 0.16 0.24 0.20 -0.10

# Load package forecast
library(forecast)
# Use function Arima
m1 <- Arima(s12.lnqbrand1, order = c(1,0,0))
summary(m1)
Series: s12.lnqbrand1
ARIMA(1,0,0) with non-zero mean
Coefficients:
ar1 mean
0.6330 0.0717
s.e. 0.1178 0.0244
sigma^2 = 0.003824: log likelihood = 58.07
AIC=-110.14 AICc=-109.51 BIC=-104.92
Training set error measures:
ME RMSE MAE MPE
Training set -0.001543299 0.06034798 0.04710515 -113.7927
MAPE MASE ACF1
Training set 194.7673 0.5835665 -0.1170992
:)
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKYXV0aG9yOiBTdGVmYW4gU2Nod2VpdHplciBBMDEyMDk3NTUKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQojIyBXb3Jrc2hvcCAzLCBGaW5hbmNpYWwgRWNvbm9tZXRyaWNzIElJCkFsYmVydG8gRG9yYW50ZXMsIFBoLkQuCkF1ZyAyNCwgMjAyMQoKIyBBYnN0cmFjdApUaGUgbWFpbiBwdXJwb3NlIG9mIHRoaXMgd29ya3Nob3AgaXMgdG8gaWxsdXN0cmF0ZSB0aGUgZm91bmRhdGlvbnMgb2YgQXV0b3JlZ3Jlc3NpdmUgTW92aW5nIEF2ZXJhZ2UgbW9kZWxzIC0gQVJNQS4gV2Ugd2lsbCBhcHBseSB0aGUgQVJNQSBtb2RlbCB0byBhIGRhdGFzZXQgb2Ygc2FsZXMgb2YgcmVhbCBjb25zdW1lciBwcm9kdWN0cy4KCiMgSW50cm9kdWN0aW9uClRoZSBtYWluIHB1cnBvc2Ugb2YgdGhpcyB3b3Jrc2hvcCBpcyB0byBpbGx1c3RyYXRlIHdoYXQgYXJlIEF1dG9yZWdyZXNzaXZlIE1vdmluZyBBdmVyYWdlIG1vZGVscyAtIEFSTUEgLSBhbmQgaG93IHRoZXkgYXJlIGNvbnN0cnVjdGVkLiBUaGlzIG1ldGhvZG9sb2d5IGlzIHBhcnQgb2YgdGhlIEJveC1KZW5raW5zIG1vZGVscyBmb3IgdGltZSBzZXJpZXMsIHdoaWNoIHByb3ZpZGUgYSBzZXJpZXMgb2YgdG9vbHMgdG8gdW5kZXJzdGFuZCBwYXN0IGJlaGF2aW9yIGFuZCBwcmVkaWN0IGZ1dHVyZSB2YWx1ZXMgb2YgdGltZSBzZXJpZXMuIEdpdmVuIGEgdGltZSBzZXJpZXMgWXQsIHRoZSBBUk1BIG1vZGVsIGNhbiBiZSBiZSBkZW5vdGVkIGFzIEFSTUEocCxxKSB3aGVyZSBwIGlzIHRoZSBudW1iZXIgb2YgYXV0b3JlZ3Jlc3NpdmUgdGVybXMgYW5kIHEgcmVmZXJzIHRvIHRoZSBudW1iZXIgb2YgbW92aW5nLWF2ZXJhZ2UgdGVybXMuCgojIFRoZSBBUihwKSBtb2RlbApJbiBnZW5lcmFsIHRoZSBhdXRvcmVncmVzc2l2ZSBtb2RlbHMgYXNzdW1lIHRoYXQgdGhlcmUgaXMgc29tZSBraW5kIG9mIGF1dG9jb3JyZWxhdGlvbiBwaGVub21lbm9uIGluIHRoZSB0aW1lIHNlcmllcy4gVGhlIGNvbmNlcHQgb2YgYXV0b2NvcnJlbGF0aW9uIGltcGxpZXMgdGhlIGNvcnJlbGF0aW9uIG9mIGEgcmFuZG9tIHZhcmlhYmxlcyB3aXRoIGl0cyBwYXN0IGFuZCBmdXR1cmUgdmFsdWVzLiBUaGlzIGlzIHRoZSBidWlsZGluZyBibG9jayBiZWhpbmQgdGhlc2UgbW9kZWxzLgoKSW4gdGltZS1zZXJpZXMgRWNvbm9tZXRyaWNzIHdlIGNhbiB0YWxrIGFib3V0IGFuIGF1dG9jb3JyZWxhdGlvbiBpbiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIChhbHNvIGNhbGxlZCwgZW5kb2dlbmVvdXMgdmFyaWFibGUpLiBUaGlzIG1lYW5zIHRoZSBmdXR1cmUgdmFsdWVzIG9mIGFuIGVjb25vbWljIG9yIGZpbmFuY2lhbCB2YXJpYWJsZSBjYW4gYmUgZXhwbGFpbmVkIHNvbWVob3cgYnkgaXRzIHByZXZpb3VzIHZhbHVlcy4gVGhpcyBpcyB0aGUgZm91bmRhdGlvbiBvZiB3aGF0IGVjb25vbWV0cmljaWFucyBoYXZlIGNhbGxlZCBhbiBBdXRvcmVncmVzc2l2ZSBNb2RlbCBhbHNvIGRlbm90ZWQgYXMgQVIgbW9kZWwuIFRoZSBhdXRvcmVncmVzc2l2ZSBub3RhdGlvbiBvZiB0aGUgc3RvY2hhc3RpYyBtb2RlbCBkZWZpbmVkIGJ5IFl0IGNhbiBiZSBkZXNjcmliZWQgYXMgZm9sbG93czoKCll0Pc+VMCvPlTFZdOKIkjErz5UyWXTiiJIyKy4uLivPlXBZdOKIknArz7V0CgpXaGVyZSDPlTEsLi4uz5VwIGFyZSB0aGUgcGFyYW1ldGVycyBvZiB0aGUgbW9kZWwsIM+1dCByZWZlcnMgdG8gdGhlIGVycm9yIHRlcm0gb3IgcmFuZG9tIHNob2NrLiBXZSBjYW4gZXhwcmVzcyB0aGUgc2FtZSBlcXVhdGlvbiBhcyBmb2xsb3dzOgoKWXQ9z5UwK+KIkWs9MXDPlWtZdOKIkmsrz7V0CgpJbiBvcmRlciB0byBhcHBseSB0aGlzIG1vZGVsIHdlIGhhdmUgdG8gcHJvdmUgdGhlIHNlcmllcyBZdCBpcyBzdGF0aW9uYXJ5LiBXZSB3aWxsIGxlYXJuIGxhdGVyIGhvdyB0byB0ZXN0IHN0YXRpc3RpY2FsbHkgd2hldGhlciBhIHNlcmllcyBjYW4gYmUgY29uc2lkZXJlZCBzdGF0aW9uYXJ5IG9yIG5vdC4gSWYgdGhlIHNlcmllcyBpcyBub3Qgc3RhdGlvbmFyeSwgd2UgY2FuIGNhbGN1bGF0ZSB0aGUgZmlyc3QgZGlmZmVyZW5jZSBvZiB0aGUgc2VyaWVzLCBhbmQgbW9zdCBvZiB0aGUgdGltZSB0aGUgcmVzdWx0aW5nIHNlcmllcyB3aWxsIGJlY29tZSBzdGF0aW9uYXJ5LgoKSW4gbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWxzLCB0aGUgbWV0aG9kIHRvIGVzdGltYXRlIHRoZSByZWdyZXNzaW9uIGNvZWZmaWNpZW50cyBpcyB0aGUgT3JkaW5hcnkgTGVhc3QgU3F1YXJlcyAoT0xTKS4gRm9yIEFSTUEgbW9kZWxzLCB0aGUgYmVzdCBtZXRob2QgdG8gZXN0aW1hdGUgdGhlIGF1dG9yZWdyZXNzaXZlIGNvZWZmaWNpZW50cyBpcyB0aGUgTWF4aW11bSBMaWtlbGlob29kIChNTCkgbWV0aG9kLiBUaGUgTUwgbWV0aG9kIHdvcmtzIHdpdGggaXRlcmF0aW9ucywgd2hpbGUgT0xTIGhhcyBhbiBhbmFseXRpYyBzb2x1dGlvbiAoaW4gb3RoZSB3b3JkcywgYSBmb3JtdWxhKS4gRm9ydHVuYXRlbHksIFIgY2FuIGVzdGltYXRlIHRoaXMgZm9yIHlvdS4KCkluIGEgdHJhZGl0aW9uYWwgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgdXNpbmcgdGltZSBzZXJpZXMgdmFyaWFibGVzLCB3ZSBhc3N1bWUgdGhhdCB0aGUgZXJyb3JzIGFyZSBub3QgY29ycmVsYXRlZCBhbW9uZyB0aGVtLiBJZiB0aGlzIGFzc3VtcHRpb24gaXMgdmlvbGF0ZWQgKHRoZSBlcnJvcnMgYXJlIGF1dG9jb3JyZWxhdGVkKSwgdGhlbiB3ZSBjYW4gdXNlIGF1dG9yZWdyZXNzaXZlIG1vZGVscyB0aGF0IHdpbGwgaW5jbHVkZSBhdXRvcmVncmVzc2l2ZSB0ZXJtcyB0byBsZWF2ZSBlcnJvcnMgd2l0aCBubyBjb3JyZWxhdGlvbiAoaW5kZXBlbmRlbnQgZXJyb3JzLCBhbHNvIGNhbGxlZCwgd2hpdGUgbm9pc2UpLgoKTm93IEkgd2lsbCBleHBsYWluIHdoYXQgaXMgYSBtb3ZpbmcgYXZlcmFnZSBtb2RlbC4KCiMgVGhlIE1BKHEpIG1vZGVsClRoZSBBUihwKSBtb2RlbCBpcyBhIHByb2Nlc3Mgd2l0aCBhIGxvbmctdGVybSBtZW1vcnkuIFdoeT8gdGhpcyBpcyBiZWNhdXNlIGEgc2hvY2sgdG9kYXkgd2lsbCBpbXBhY3QgaW4gdGhlIGZ1dHVyZSBmb3JldmVyLiBJZiB5b3UgcmVhZCB0aGUgbWF0aGVtYXRpY2FsIGVxdWF0aW9uLCB0aGlzIGNhbiBiZSBpbnRlcnByZXRlZCBhcyBmb2xsb3dzLiBUaGUgdmFsdWUgb2YgdGhlIHNlcmllcyB0b21vcnJvdyB3aWxsIGRlcGVuZCBvbiB0aGUgdmFsdWUgb2YgdG9kYXksIGFmdGVyIGFwcGx5aW5nIHRoZSBmaWx0ZXIgz5UxLiBUaGVuLCB0aGUgdmFsdWUgb2YgdG9tb3Jyb3cgYWxyZWFkeSBoYXMgaW5mb3JtYXRpb25hYm91dCB0aGUgdmFsdWUgb2YgdG9kYXkuIEFuZCB0aGUgdmFsdWUgb2YgdG9tb3Jyb3cgd2lsbCBpbXBhY3QgdGhlIHZhbHVlIG9mIDIgZGF5cyBmcm9tIG5vdy4gVGhlbiwgdGhlIHZhbHVlIG9mIHRvZGF5IHdpbGwgaGF2ZSBhbiBpbXBhY3QgaW4gdGhlIHdob2xlIGZ1dHVyZSBvZiB0aGUgc2VyaWVzLgoKSG93ZXZlciwgdGhlIGltcGFjdCBvZiB0aGUgdmFsdWUgb2YgdG9kYXkgd2lsbCBiZSBkaW1pbmlzaGloZyBleHBvbmVudGlhbGx5IGFjY29yZGluZyB0byAoz5UxKU4sIHdoZXJlIE4gaXMgdGhlIG51bWJlciBvZiBwZXJpb2RzIGluIHRoZSBmdXR1cmUuIFNpbmNlIHzPlTF8PDEsIHRoZW4gdGhlIGJpZ2dlciB0aGUgZXhwb25lbnQgTiAtd2hpY2ggcmVmZXJzIHRvIGEgZnVydGhlciBmdXR1cmUgcGVyaW9kLSB0aGUgc21hbGxlciB0aGUgZWZmZWN0LgoKSWYgd2Ugd2FudCB0byBtb2RlbCBhIHNlcmllcyB3aXRoIGEgc2hvcnQtdGVybSBtZW1vcnksIHRoZW4gd2UgaGF2ZSB0byB0aGluayBpbiBhIGRpZmZlcmVudCBlcXVhdGlvbjoKCll0Pc64MCvOuDHPtXTiiJIxK864Ms+1dOKIkjIrLi4uK864cc+1dOKIknErz7V0CgpUaGlzIGlzIGNhbGxlZCBhIOKAnE1vdmluZy1BdmVyYWdl4oCdIG1vZGVsIHdpdGggcSB0ZXJtcy4gSW4gdGhpcyBjYXNlLCB0aGUgdmFsdWUgb2YgdG9kYXkgaXMgbm90IGRpcmVjdGx5IGFmZmVjdGVkIGJ5IGl0cyBwcmV2aW91cyBvd24gdmFsdWUsIGJ1dCB0aGUgcGFzdCByYW5kb20gc2hvY2tzLiBJbiB0aGUgY2FzZSBvZiBxPTEsIHRoaXMgcHJvY2VzcyBkb2Vzbm90IGhhdmUgbG9uZyBtZW1vcnkgc2luY2UgdGhlIHZhbHVlIG9mIHRvZGF5IGlzIG9ubHkgYWZmZWN0ZWQgYnkgdGhlIHNob2NrIG9mIHllc3RlcmRheS4KClRoZSBtb3JlIHEgdGVybXMgaW5jbHVkZWQgaW50byB0aGUgbW9kZWwsIHRoZW4gdGhlIGxvbmdlciB0aGUgbWVtb3J5IG9mIHRoZSBtb2RlbC4gTW9zdCBvZiB0aGUgY2FzZXMsIHJlYWwtd29ybGQgc2VyaWVzIG9ubHkgaW5jbHVkZSB2ZXJ5IGZldyBxIHRlcm1zLgoKSW4gdGhlIE1BKHEpIG1vZGVsLCDOuDAsIOKApiDOuHEgYXJlIHRoZSBwYXJhbWV0ZXJzIG9mIHRoZSBtb2RlbCwgz7V04oiSayByZWZlcnMgdG8gcGFzdCBleHRlcm5hbCBlcnJvcnMvc2hvY2tzLCBhbmQgdGhlIGN1cnJlbnQgZXh0ZXJuYWwgc2hvY2sgaXMgZGVmaW5lZCBhcyDPtXQsIHNvOgoKWXQ9zrgwK8+1dCviiJFrPTFxzrhrz7V04oiSawoKV2UgY2FuIGludGVycHJldCBhbiBNQSBtb2RlbCBhcyBhIHJhbmRvbSBwcm9jZXNzIHdoZXJlIHRoZSBjdXJyZW50IHZhbHVlIG9mIHRoZSBzZXJpZXMgaXMgaW5mbHVlbmNlZCBieSB0aGUgY3VycmVudCByYW5kb20gc2hvY2ssIGFuZCBieSBzb21lIHBlcmNlbnRhZ2VzIG9mIHByZXZpb3VzIHJhbmRvbSBxIHNob2Nrcy9lcnJvcnMuIFRoZSBwZXJjZW50YWdlcyBhcmUgYWN0dWFsbHkgdGhlIHZhbHVlcyBvZiB0aGUgY29lZmZpY2llbnRzIM64LgoKSW4gRmluYW5jZSwgd2hlbiB3ZSB3YW50IHRvIG1vZGVsIHRoZSBiZWhhdmlvciBvZiBtYXJrZXQgcmV0dXJucywgd2Uga25vdyB0aGF0IHRoZXJlIGFyZSB0aG91c2FuZHMgb2YgZXZlbnRzIHRoYXQgYWZmZWN0IGhvdyB0aGUgbWFya2V0IHJldHVybnMgYXJlIG1vdmluZyB0b2RheS4gVGhlc2UgdGhvdXNhbmRzIG9mIGV2ZW50cyBhcmUgYmFzaWNhbGx5IHN1bW1hcml6ZWQgaW4gYSDigJxyYW5kb20gc2hvY2vigJ0gdGhhdCBub2JvZHkga25vd3Mgd2hhdCB3aWxsIGJlIGl0cyBtYWduaXR1ZCBhbmQgZGlyZWN0aW9uIChwb3NpdGl2ZSBvciBuZWdhdGl2ZSBlZmZlY3QpLgoKTm93IEkgd2lsbCBwdXQgdG9nZXRoZXIgYm90aCBBUiBhbmQgTUEgbW9kZWwgaW50byBvbmUsIHRoZSBBUk1BIG1vZGVsLgoKIyBBUk1BKHAscSkgbW9kZWwKTm93IHdlIGNhbiBjb21iaW5lIGJvdGggQVIocCkgdGVybXMgYW5kIE1BKHEpIHRlcm1zIGludG8gT05FIG1vZGVsLCB0aGF0IGlzIGNhbGxlZCBBUk1BKHAscSk6CgpZdD3PlTAr4oiRaz0xcM+Va1l04oiSayviiJFrPTFxzrhrz7V04oiSayvPtXQKCldlIGNvbWJpbmUgQVIgYW5kIE1BIHRlcm1zIHRvIG1vZGVsIFkgaW4gY2FzZSBZIGNhbiBiZSBtb2RlbGVkIGluY2x1ZGluZyBzaG9ydC10ZXJtIGFuZCBsb25nLXRlcm0gbWVtb3J5LiBUaGUgbG9uZy10ZXJtIG1lbW9yeSBpcyBtb2RlbGVkIHdpdGggdGhlIEFSIHRlcm1zLCB3aGlsZSB0aGUgc2hvcnQtdGVybSBtZW1vcnkgaXMgbW9kZWxlZCB3aXRoIHRoZSBNQSB0ZXJtcy4gV2Ugd2lsbCBwcmFjdGljZSB3aXRoIGFuIGV4YW1wbGUgdG8gaWx1c3RyYXRlIHRoaXMgdGhlb3JldGljYWwgbW9kZWwuCgojIEhhbmQtb24gYWN0aXZpdHkKV2Ugd2lsbCB3b3JrIHdpdGggYW4gb25saW5lIGRhdGFzZXQgdGhhdCBjb250YWlucyBzYWxlcyBkYXRhIG9mIGRpZmZlcmVudCBjb25zdW1lciBwcm9kdWN0cy4gVGhlIGRhdGEgd2FzIGNyZWF0ZWQgdXNpbmcgcmVhbCBwcm9kdWN0cywgYnV0IHRoZSBuYW1lcyBvZiB0aGUgcHJvZHVjdHMgd2VyZSBjaGFuZ2VkIGR1ZSB0byBwcml2YWN5IGlzc3Vlcy4KCkRvd25sb2FkIHRoZSBleGNlbCBmaWxlIGZyb20gYSB3ZWIgc2l0ZToKYGBge3J9CmRvd25sb2FkLmZpbGUoImh0dHA6Ly93d3cuYXByYWRpZS5jb20vZWMyMDA0L3NhbGVzYnJhbmRzMy54bHN4IiwgInNhbGVzYnJhbmRzMy54bHN4IiwgbW9kZT0id2IiKQpgYGAKVGhpcyBkYXRhc2V0IGhhcyBzYWxlcyBpbmZvcm1hdGlvbiBvZiBzZXZlcmFsIGJyYW5kcyBvZiBjb25zdW1lciBwcm9kdWN0cyB0aGF0IGJlbG9uZyB0byBvbmUgY2F0ZWdvcnkgKGZvciBleGFtcGxlLCB0aGUgY2F0ZWdvcnkgY2FuIGJlIENlcmVhbHMgb3IgQ2FuZGllcykuIFRoZSBjb250ZW50IG9mIHRoaXMgZGF0YXNldCBpcyB2ZXJ5IHNpbWlsYXIgdG8gYSByZWFsLXdvcmxkIGNhdGVnb3J5LiBDb25zdW1lciBwcm9kdWN0cyB1c3VhbGx5IHNob3cgc29tZSBzZWFzb25hbGl0eSBhbmQgdHJlbmQgb3ZlciB0aW1lLiBXZSB3aWxsIGxlYXJuIGhvdyB0byBoYW5kbGUgdGhlc2UgZmVhdHVyZXMgbGF0ZXIuCgpBbHNvLCB5b3UgaGF2ZSB0byBpbnN0YWxsIHRoZSByZWFkeGwgcGFja2FnZS4gVGhpcyBwYWNrYWdlIHJlYWRzIGRhdGEgZnJvbSBFeGNlbCBmaWxlcy4gV2UgbG9hZCB0aGlzIHBhY2thZ2U6CgpgYGB7cn0KbGlicmFyeShyZWFkeGwpCmBgYAoKTm93LCB3ZSBpbXBvcnQgdGhlIEV4Y2VsIGZpbGUgaW50byBhbiBSIGRhdGFmcmFtZToKCmBgYHtyfQpzYWxlc19icmFuZHMgPC0gcmVhZF9leGNlbCgic2FsZXNicmFuZHMzLnhsc3giLCBzaGVldCA9ICJSZXN1bHRhZG8iKQoKIyBBbHdheXMgZmFtaWxpYXJpemUgd2l0aCB0aGUgZGF0YQpoZWFkKHNhbGVzX2JyYW5kcywgNSkKYGBgCkFzIHlvdSBjYW4gc2VlLCB3ZSBoYXZlIGltcG9ydGVkIGEgbW9udGhseSBkYXRhc2V0IHdoZXJlIHRoZSB2YXJpYWJsZSBkYXRlIHNob3dzIHRoZSBmaXJzdCBkYXkgb2YgdGhlIG1vbnRoIGluIGEgeXl5eS1tbS1kZCBmb3JtYXQuCgpJbiBvcmRlciB0byBwZXJmb3JtIHNvbWUgdGltZS1zZXJpZXMgYW5hbHlzaXMsIGl0IGlzIHJlY29tbWVuZGVkIHRvIHVzZSB4dHMgb2JqZWN0cy4gV2Ugd2lsbCBjb25zdHJ1Y3QgYSB4dHMgb2JqZWN0IHVzaW5nIHRoZSB4dHMoKSBtZXRob2QuIFRoZSBvYmplY3RzIG9mIHh0cyBjbGFzcyBhcmUgY29tcG9zZWQgYnkgMiBvYmplY3RzOiB0aGUgY29yZSBkYXRhIGFuZCB0aGUgaW5kZXggKGNsYXNzIERhdGUsIFBPU0lYLCBldGMpLgoKYGBge3J9CiMgTG9hZCBsaWJyYXJ5IHh0cy4gSW5zdGFsbCB0aGUgcGFja2FnZSBpZiB5b3UgaGF2ZW4ndCBhbHJlYWR5LgpsaWJyYXJ5KHh0cykKCiMgV2Ugd2lsbCBzdGFydCBieSB0dXJuaW5nIHNhbGVzX2JyYW5kcyBpbnRvIGEgZGF0YSBmcmFtZSAKIyBiZWNhdXNlIGRhdGEgZnJhbWVzIGFyZSBlYXNpZXIgdG8gbWFuaXB1bGF0ZQpzYWxlc19icmFuZHMuZGYgPC0gYXMuZGF0YS5mcmFtZShzYWxlc19icmFuZHMpCgojIERpdmlkZSB0aGUgaW5kZXggYW5kIHRoZSBjb3JlIGRhdGE6CiMgSSBnZXQgdGhlIGRhdGUgaW4gYSBuZXcgdmFyaWFibGUgZmVjaGE6CmZlY2hhIDwtIHNhbGVzX2JyYW5kcy5kZiRkYXRlCiMgVGhlIGZpcnN0IGNvbHVtbiBvZiB0aGUgc2FsZXNfYnJhbmQuZGYgaXMgdGhlIGRhdGUuIAojICBJIGRyb3AgdGhpcyBjb2x1bW4gc2luY2UgSSBjb3BpZWQgdG8gZmVjaGE6IApzYWxlc19icmFuZHMuZGYgPC0gc2FsZXNfYnJhbmRzLmRmWywtMV0KCiMgTm93IEkgam9pbiBib3RoIG9iamVjdHMgdXNpbmcgeHRzKCkgYW5kIGFzc2lnbiB0aGUgcmVzdWx0aW5nIG9iamVjdCB0byBzYWxlcy54dHMKc2FsZXMueHRzIDwtIHh0cyh4ID0gc2FsZXNfYnJhbmRzLmRmLCBvcmRlci5ieSA9IGZlY2hhKQoKaGVhZChzYWxlcy54dHMsIDUpCmBgYAoKYGBge3J9CiMgRG8geW91IG5vdGljZSBhbnkgZGlmZmVyZW5jZSBiZXR3ZWVuIGRhdGEgZnJhbWVzIGFuZCB4dHMgb2JqZWN0cz8KCiNkZWxldGUgdmFyaWFibGUgZmVjaGEKcm0oZmVjaGEpCmBgYAoKIyBTdGF0aW9uYXJ5IHZzIE5vbi1zdGF0aW9uYXJ5CgpXZSBjYW4gaGF2ZSBhbiBvdmVydmlldyBvZiB0aGUgYmVoYXZpb3VyIG9mIHNhbGVzIG9mIHRoZXNlIGNvbnN1bWVyIHByb2R1Y3RzIHVzaW5nIHRoZSBwbG90IGNvbW1hbmQuIExldOKAmXMgZm9jdXMgb24gYnJhbmQgMiBhbmQgNi4gVG8gc2VlIHZvbHVtZSBzYWxlcyAodGhlIG51bWJlciBvZiB0b25zIHNvbGQpIG9mIGJyYW5kIDI6CgpgYGB7cn0KcGxvdChzYWxlcy54dHMkcWJyYW5kMnRvbnMpCmBgYAoKSXQgc2VlbXMgdGhhdCB0aGlzIHByb2R1Y3QgaGFzIGEgZ3Jvd2luZyB0cmVuZCBvdmVyIHRpbWUsIGV4Y2VwdCBmb3IgdGhlIGxhc3QgeWVhci4KCldlIGNhbiBncmFwaCBjb25zdW1lciBicmFuZCA2CgpgYGB7cn0KcGxvdChzYWxlcy54dHMkcWJyYW5kNnRvbnMpCmBgYAoKVGhpcyBicmFuZCBoYXMgYSBjbGVhciBncm93aW5nIHRyZW5kIG92ZXIgdGltZS4gQXMgd2UgY2FuIHNlZSwgbWFueSBjb25zdW1lciBwcm9kdWN0cyBoYXZlIGEgZ3Jvd2luZyBvciBhIGRlY2xpbmluZyB0cmVuZC4gQW5kIG90aGVyIHByb2R1Y3RzIG1pZ2h0IHNlZW0gdG8gYmUgc3RhdGlvbmFyeSBvdmVyIHRpbWUsIHdpdGggc2FsZXMgb3ZlciBhbiBhdmVyYWdlIG92ZXIgdGltZS4KCkEgc2VyaWVzIHdpdGggYSBncm93aW5nIG9yIGRlY2xpbmluZyB0cmVuZCBpcyBub24tc3RhdGlvbmFyeS4gTW9zdCBvZiB0aGUgdmFyaWFibGVzIHRoYXQgcmVwcmVzZW50IHNhbGVzIG9mIGFueSBwcm9kdWN0IGNhbiBiZSB0cmVhdGVkIGFzIG5vbi1zdGF0aW9uYXJ5LiBUaGVuLCBhIHJ1bGUgb2YgdGh1bWIgd2hlbiB3ZSB3b3JrIHdpdGggYnVzaW5lc3MgdmFyaWFibGVzIHN1Y2ggYXMgdm9sdW1lIHNhbGVzLCB2YWx1ZSBzYWxlcywgY29zdCBvZiBnb29kIHNvbGQsIGV0YyBpcyB0byB0cmFuc2Zvcm0gdGhlIHNlcmllcyBpbnRvIGEgc3RhdGlvbmFyeSBzZXJpZXMuCgpXaGVuIHlvdSB3b3JrIHdpdGggc2FsZXMgZGF0YSwgSSBzdHJvbmdseSByZWNvbW1lbmQgdG8gY3JlYXRlIHRoZSBmaXJzdCBkaWZmZXJlbmNlIG9mIHRoZSBsb2dhcml0aG0gb2YgdGhlIHZhcmlhYmxlLiBUaGlzIGlzIGFjdHVhbGx5IGl0cyBwZXJjZW50YWdlIGNoYW5nZSAoaW4gY29udGludW91c2x5IGNvbXBvdW5kZWQpLiBJZiB5b3UgZG8gdGhpcyBwcm9jZXNzIHRvIG1vc3Qgb2YgcmVhbC13b3JsZCBzYWxlcyB2YXJpYWJsZSB0aGUgcmVzdWx0IHdpbGwgYmUgc3RhdGlvbmFyeSBtb3N0IG9mIHRoZSB0aW1lIChhYm91dCA5NSUgb2YgdGhlIHZhcmlhYmxlcykuIFRoZSBvdGhlciByZWFzb24gd2h5IGl0IGlzIHJlY29tbWVuZGVkIHRvIGRvIHRoaXMgdHJhbnNmb3JtYXRpb24gaXMgdGhhdCB0aGUgZmlyc3QgZGlmZmVyZW5jZSBvZiB0aGUgbG9nIG9mIGEgdmFyaWFibGUgaXMgYWN0dWFsbHkgdGhlICUgY2hhbmdlIG9mIHRoZSB2YXJpYWJsZSBmcm9tIG9uZSBwZXJpb2QgdG8gdGhlIG5leHQgKGluIGNvbnRpbnVvdXNseSBjb21wb3VuZGVkIHBlcmNlbnRhZ2UpLiBUaGVuLCB3ZSBjYW4gZG8gdGhpcyB0cmFuc2Zvcm1hdGlvbiBhcyBmb2xsb3dzOgoKV2UgZmlyc3QgY3JlYXRlIHRoZSBuYXR1cmFsIGxvZyBvZiBlYWNoIHNhbGVzIHZhcmlhYmxlIChpbiB0b25zKS4gV2UgY2FuIGFwcGx5IHRoZSBsb2cgZnVuY3Rpb24gdG8gdGhlIHh0cyBvYmplY3QgdG8gZ2V0IHRoZSBsb2cgb2YgYWxsIHNlcmllczoKCmBgYHtyfQpsbl9zYWxlcyA8LSBsb2coc2FsZXMueHRzKQpgYGAKClRoZSBuZXcgb2JqZWN0IGhhcyB0aGUgc2FtZSBzdHJ1Y3R1cmUgYXMgc2FsZXMueHRzIGJ1dCB0aGUgY29sdW1ucyBjb250YWluIHRoZSBuYXR1cmFsIGxvZ2FyaXRobSBvZiB0aGUgZGF0YS4gVGhpcyBpcyBkdWUgdG8gUiB2ZWN0b3JpemF0aW9uLCBhIGtleSBmZWF0dXJlIG9mIFIuCgpOb3csIEkgY2FuIHdvcmsgd2l0aCB0aGUgZmlyc3QgZGlmZmVyZW5jZSBtb250aC1ieS1tb250aCB1c2luZyB0aGUgZGlmZigpIGZ1bmN0aW9uIGZvciBlYWNoIHZhcmlhYmxlLiBGb3IgZXhhbXBsZSwgdG8gZ3JhcGggdGhlIGZpcnN0IGRpZmZlcmVuY2Ugb2YgdGhlIGxvZyBvZiB2b2x1bWUgc2FsZXMgZm9yIGJvdGggYnJhbmRzIDoKCmBgYHtyfQpwbG90KGRpZmYobG5fc2FsZXMkcWJyYW5kMnRvbnMpLCB0eXBlID0gImwiLCBjb2wgPSAicmVkIikKYGBgCgpgYGB7cn0KbGluZXMoZGlmZihsbl9zYWxlcyRxYnJhbmQ2dG9ucyksIHR5cGUgPSAibCIsIGNvbCA9ICJibHVlIikKYGBgCgpUaGUgZmlyc3QgZGlmZmVyZW5jZSBvZiB0aGUgbG9nIHZhbHVlIGluIFIgaXMgZGlmZihsbl9zYWxlcyRxYnJhbmQydG9ucykuIFRoZSBkaWZmKCkgZnVuY3Rpb24gZ2VuZXJhdGVzIG9uIHRoZSBmbHkgdGhpcyBmaXJzdCBkaWZmZXJlbmNlIGFzOgoKZGlmZihsbl9zYWxlc3FicmFuZDJ0b25zKT1sbnNhbGVzcWJyYW5kMnRvbnMgLSBsYWcobG5fc2FsZXMkcWJyYW5kMnRvbnMsIDEpCgpSZW1lbWJlciB0aGF0IHRoZSBkb2xsYXIgc2lnbiBvcGVyYXRvciAoJCkgaXMgdXNlZCB0byBhY2Nlc3MvcmVmZXIgdG8gdGhlIGNvbHVtbnMgb2YgYSBkYXRhIGZyYW1lIG9yIHh0cyBvYmplY3QuCgpXZSBjYW4gc2VlIG5vdyB0aGF0IHRoZSAyIHNlcmllcyBsb29rIGxpa2Ugc3RhdGlvbmFyeSBzaW5jZSB0aGVpciBtZWFucyB0ZW5kIHRvIGJlIGluIHRoZSBzYW1lIGxldmVsLgoKUiBwZXJmb3JtcyB0aGUgZmlyc3QgZGlmZmVyZW5jZSBjYWxjdWxhdGlvbiB0ZW1wb3JhcmlseSB0byBkbyBhIGdyYXBoLCBhbmQgdGhlbiwgdGhpcyB2YXJpYWJsZSBpcyBub3Qgc2F2ZWQgaW4gdGhlIGRhdGFzZXQgb3IgZW52aXJvbm1lbnQuIEluIG90aGVyIHdvcmRzLCB3ZSBkbyBub3QgbmVlZCB0byBnZW5lcmF0ZSB0aGUgZmlyc3QgZGlmZmVyZW5jZSBhcyBhbm90aGVyIHZhcmlhYmxlIChjb2x1bW4pLCBidXQgd2UgY2FuIGlmIHdlIG5lZWQgdG8uCgpBbm90aGVyIHRyYW5zZm9ybWF0aW9uIHdpdGggbW9udGhseSBkYXRhIGlzIGFubnVhbCBwZXJjZW50YWdlIGNoYW5nZS4gSW4gdGhpcyBjYXNlLCB0aGlzIGlzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIGxvZyB2YWx1ZSBvZiB0aGUgc2VyaWVzIGFuZCBpdHMgdmFsdWUgMTIgcGVyaW9kcyBhZ28uIFdlIGNhbiBjaGVjayB0aGlzIGRpZmZlcmVuY2UgdXNpbmcgdGhlIGRpZmYoKSBmdW5jdGlvbiB3aXRoIHRoZSBsYWcgYXJndW1lbnQgc2V0IHRvIDEyOgoKYGBge3J9CiMgSSBjcmVhdGUgYSB2YXJpYWJsZSBmb3IgdGhlIHNlYXNvbmFsIGRpZmZlcmVuY2Ugb2YgdGhlIGxvZyBvZiBzYWxlcywgd2hpY2gKIyAgIGlzIHRoZSBhbm51YWwgJSBjaGFuZ2Ugb2Ygc2FsZXMgKGluIGNvbnRpbnVvdXNseSBjb21wb3VuZGVkKToKczEyLmxucWJyYW5kMiA9IGRpZmYobG5fc2FsZXMkcWJyYW5kMnRvbnMsIGxhZyA9IDEyKQoKIyBJIHBsb3QgdGhpcyBuZXcgdmFyaWFibGUsIHRoZSBhbm51YWwgJSBjaGFuZ2Ugb2Ygc2FsZXMgZm9yIHByb2R1Y3QgMjoKcGxvdChzMTIubG5xYnJhbmQyLCB0eXBlID0gImwiLCBjb2wgPSAicmVkIikKYGBgCgpgYGB7cn0KIyBJIGRvIHRoZSBzYW1lIGZvciBwcm9kdWN0IDY6CnMxMi5sbnFicmFuZDYgPSBkaWZmKGxuX3NhbGVzJHFicmFuZDZ0b25zLCBsYWcgPSAxMikKIyBJIHBsb3QgdGhpcyBuZXcgdmFyaWFibGUsIHRoZSBhbm51YWwgJSBjaGFuZ2Ugb2Ygc2FsZXMgZm9yIHByb2R1Y3QgMjoKcGxvdChzMTIubG5xYnJhbmQ2LCB0eXBlID0gImwiLCBjb2wgPSAiYmx1ZSIpCmBgYAoKSW4gdGhpcyBjYXNlLCB0aGUgc2VyaWVzIGZvciBib3RoIGJyYW5kcyBkbyBub3QgbG9vayBzdGF0aW9uYXJ5LiBCdXQgd2UgbmVlZCB0byBkbyBhIHN0YXRpc3RpY2FsIHRlc3QgdG8gY2hlY2sgd2hldGhlciBhIHNlcmllcyBjYW4gYmUgdHJlYXRlZCBhcyBzdGF0aW9uYXJ5IG9yIG5vdC4gU29tZSBzZXJpZXMgbWlnaHQgbm90IGxvb2sgc3RhdGlvbmFyeSBmb3Igb3VyIGV5ZXMsIGJ1dCB3ZSBuZWVkIHRvIHJ1biBzdGF0aXN0aWNhbCB0ZXN0cyB0byBkZWNpZGUgd2hldGhlciB0byB0cmVhdCB0aGUgc2VyaWVzIHN0YXRpb25hcnkgb3Igbm90LiBUaGVyZSBpcyBhIHN0YXRpc3RpY2FsIHdheSB0byBldmFsdWF0ZSB3aGV0aGVyIHRoZXNlIHNlcmllcyBhcmUgc3RhdGlvbmFyeS4gV2UgbmVlZCBhIHN0YXRpc3RpY2FsIGNvbmZpcm1hdGlvbiBpbiBhZGRpdGlvbiB0byB0aGUgdmlzdWFsIHRvb2xzLgoKVGhlIERpY2t5LUZ1bGxlciB0ZXN0IGlzIG9uZSBvZiB0aGUgbW9zdCB1c2VkIHN0YXRpc3RpY2FsIHRlc3RzIGZvciBzdGF0aW9uYXJ5LiBUaGlzIHRlc3QgaXMgY2FsbGVkIGEgdW5pdCByb290IHRlc3QuIFRoZSBEaWNreSBGdWxsZXIgdGVzdCBhc3N1bWVzIHRoYXQgdGhlIHNlcmllcyBpcyBub24gc3RhdGlvbmFyeS4gSW4gb3RoZXIgd29yZHMsIGl0IGFzc3VtZXMgdGhhdCB0aGUgc2VyaWVzIGZvbGxvd3MgYSByYW5kb20gd2FsayB3aXRoIGEgdW5pdCByb290IChwaGkxPTEpLiBXZSBjYW4gcnVuIHRoaXMgdGVzdCBpbiBSIHVzaW5nIHRoZSBhZGYudGVzdCBmdW5jdGlvbiBmcm9tIHRoZSB0c2VyaWVzIHBhY2thZ2UuCgpZb3UgbmVlZCB0byBpbnN0YWxsIHRoZSBwYWNrYWdlIHRzZXJpZXMgdG8gZG8gdGhlIGZvbGxvd2luZyBhbmFseXNpcy4KCmBgYHtyfQpsaWJyYXJ5KHRzZXJpZXMpCiMgQmVmb3JlIHJ1bm5pbmcgdGhlIERpY2t5LUZ1bGxlciB0ZXN0LCB3ZSBuZWVkIHRvIGRyb3AgTkEgKG1pc3NpbmcpIHZhbHVlcyBvZiAKIyAgIHRoZSB2YXJpYWJsZToKczEyLmxucWJyYW5kMiA9IG5hLm9taXQoczEyLmxucWJyYW5kMikKYWRmLnRlc3QoczEyLmxucWJyYW5kMiwgYWx0ZXJuYXRpdmUgPSAic3RhdGlvbmFyeSIsaz0wKQpgYGAKClRoZSBhZGYudGVzdCgpIGZ1bmN0aW9uIGZyb20gdGhlIHRzZXJpZXMgcGFja2FnZSB3aWxsIGRvIGEgRGlja2V5LUZ1bGxlciB0ZXN0IGlmIHdlIHNldCBsYWdzIChrKSBlcXVhbCB0byAwLgoKVGhpcyBpcyBhbm90aGVyIHdheSB0byBkbyB0aGUgc2FtZSBEaWNrZXkgRnVsbGVyIHRlc3Q6CgpUaGUgRGlja3kgRnVsbGVyIHRlc3QgcmVwb3J0cyBhIHAtdmFsdWUuIEluIHRoaXMgY2FzZSwgaXQgaXMgYmFyZWx5IGdyZWF0ZXIgdGhhbiAwLjA1LiBJbiB0aGlzIGNhc2UsIHdlIHdpbGwgY29uc2lkZXIgdGhlIHB2YWx1ZSB0byBiZSAwLjA1LCBzbyB3ZSB3aWxsIGhhdmUgOTUlIGNvbmZpZGVuY2UgKDEtcHZhbHVlKSB0byByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyB0aGF0IHN0YXRlcyBhIHVuaXQgcm9vdCBmb3IgdGhlc2Ugc2VyaWVzICjPlTE9MSkuIEluIG90aGVyIHdvcmRzLCBmb3IgdGhlIHNlcmllcyB3aXRoIGEgRGlja3ktRnVsbGVyIHAtdmFsdWUgbGVzcyBvciBlcXVhbCB0aGFuIDAuMDUgd2UgY2FuIHNheSB0aGF0IHRoZXJlIGlzIHN0YXRpc3RpY2FsIGV2aWRlbmNlIHRvIGNvbmNsdWRlIHRoYXQgdGhlIGRpZmZlcmVuY2VkIHNlcmllcyAoczEyLmxuYnJhbmQydG9ucykgaXMgc3RhdGlvbmFyeS4KClRoZW4gZm9yIHRoZSB2YXJpYWJsZSBzMTIubG5icmFuZDJ0b25zIHdlIGNhbiBzYXkgdGhhdCB0aGVyZSBpcyBzdGF0aXN0aWNhbCBldmlkZW5jZSB0byBzYXkgdGhhdCB0aGUgc2VyaWVzIGlzIHN0YXRpb25hcnkuCgpJZiB3ZSB0cnkgdGhlIHNhbWUgZm9yIGJyYW5kIDYgd2Ugd2lsbCBmaW5kIHRoYXQgaXRzIHNlYXNvbmFsIGRpZmZlcmVuY2UgKHMxMi5sbmJyYW5kNnRvbnMpIGlzIGFsc28gc3RhdGlvbmFyeS4gVHJ5IHRoaXMgYnkgeW91cnNlbGYuCgpGb3IgdGhlIGNhc2Ugb2YgbW9udGhseSB0aW1lcyBzZXJpZXMgdmFyaWFibGVzIGxpa2Ugc2FsZXMgb2YgcHJvZHVjdHMgb3Igc2FsZXMgb2YgYSBjb21wYW55LCBJIHN0cm9uZ2x5IHJlY29tbWVuZCB0byB3b3JrIHdpdGggdGhlIHNlYXNvbmFsIGRpZmZlcmVuY2Ugb2YgdGhlIGxvZyBvZiBzYWxlcyAoczEyLmxuYnJhbmQydG9ucyksIHdoaWNoIGlzIHRoZSBhbm51YWwgcGVyY2VudGFnZSBjaGFuZ2UgbW9udGggYnkgbW9udGguIFRoZSByZWFzb24gaXMgYmVjYXVzZSBtb3N0IG9mIGNvbnN1bWVyIHByb2R1Y3RzIGhhdmUgYSBzZWFzb25hbCBwYXR0ZXJuLiBXZSBjYW4gZG8gdGhpcyBPTkxZIGlmIHRoZSBzZWFzb25hbCBkaWZmZXJlbmNlIG9mIHRoZSBsb2cgaXMgU1RBVElPTkFSWS4KCkZvciB0aGVzZSAyIHByb2R1Y3RzLCB0aGVuLCBJIHdpbGwgdXNlIHRoZSBzZWFzb25hbCBkaWZmZXJlbmNlIG9mIHRoZSBsb2cgb2Ygc2FsZXMuCgojIEF1dG9jb3JyZWxhdGlvbnMgKEFDKSBhbmQgUGFydGlhbC1hdXRvY29ycmVsYXRpb25zIChQQUMpCgpJbiB0aW1lIHNlcmllcyBhbmFseXNpcywgYSBjb3JyZWxvZ3JhbSBpcyBhbiBjaGFydCBvZiBjb3JyZWxhdGlvbiBzdGF0aXN0aWNzIGFsc28ga25vd24gYXMgYW4gYXV0b2NvcnJlbGF0aW9uIHBsb3QuIFRoaXMgaXMgYSBwbG90IG9mIHRoZSBzYW1wbGUgYXV0b2NvcnJlbGF0aW9ucyBvZiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIFl0IGFuZCB0aGUgdGltZSBsYWdzLiBJbiBSLCB0aGUgY29tbWFuZCB0byBjb21wdXRlIHRoZSBhdXRvY29ycmVsYXRpb25zIGlzIGFjZjIoKSBmcm9tIHRoZSBhc3RzYSBwYWNrYWdlLCB3aGljaCBnaXZlcyB5b3UgYm90aCwgdGhlIGF1dG9jb3JyZWxhdGlvbiAoQUNGKSBmaWd1cmVzIGFuZCB0aGUgcGFydGlhbC1hdXRvY29ycmVsYXRpb25zIChQQUNGKSwgYXMgd2VsbC4gTGV04oCZcyBleGFtaW5lIHRoZSBhdXRvY29ycmVsYXRpb25zIG9mIGJyYW5kIDIuCgpZb3UgbmVlZCB0byBpbnN0YWxsIHRoZSBhc3RzYSBwYWNrYWdlIHRvIGRvIGF1dG8tY29ycmVsYXRpb24gcGxvdHMuCgpgYGB7cn0KbGlicmFyeShhc3RzYSkKYWNmMihzMTIubG5xYnJhbmQyKQpgYGAKClRoZSBhY2YyKCkgZnVuY3Rpb24gZ2l2ZXMgeW91IHRoZSBhdXRvY29ycmVsb2dyYW0sIHdoaWNoIGlzIHRoZSBhdXRvY29ycmVsYXRpb25zIGluIGEgZ3JhcGggd2hlcmUgaXQgaXMgZWFzeSB0byBpZGVudGlmeSB3aGljaCBsYWdzIG9mIHRoZSB2YXJpYWJsZSBoYXZlIGEgc2lnbmlmaWNhbnQgYXV0b2NvcnJlbGF0aW9uLgoKVGhlIFggYXhpcyByZXByZXNlbnRzIHRoZSBsYWcgbnVtYmVycywgd2hpbGUgdGhlIFkgYXhpcyBpcyB0aGUgbGV2ZWwgb2YgYXV0b2NvcnJlbGF0aW9uLiBUaGUgdmVydGljYWwgbGluZXMgYXJlIHRoZSBsZXZlbHMgb2YgYXV0b2NvcnJlbGF0aW9ucyBiZXR3ZWVuIHRoZSBjdXJyZW50IHZhbHVlIG9mIFkgKFl0KSBhbmQgaXRzIG93biBsYWdzLiBUaGUgZG90dGVkLCBibHVlIGxpbmUgZGVsaW1pdHMgdGhlIDk1JSBjb25maWRlbmNlIGludGVydmFsIGZvciB0aGUgYXV0b2NvcnJlbGF0aW9ucy4gVGhlbiwgaWYgdGhlIGF1dG9jb3JyZWxhdGlvbiBnb2VzIG91dCBvZiB0aGUgOTUlIEMuSS4sIHRoZW4gdGhlIGF1dG9jb3JyZWxhdGlvbiBvZiB0aGUgdmFyaWFibGUgWXQgd2l0aCBpdHMgY29ycmVzcG9uZGluZyBsYWcgWXTiiJIxIChBdXRvQ29ycihZdCxZdOKIkjEpKSBpcyBzdGF0aXN0aWNhbGx5IGRpZmZlcmVudCB0aGFuIHplcm8uIFdlIGNhbiBzZWUgdGhhdCBvbmx5IHRoZSBsYWcgMSAoWXTiiJIxKSBhbmQgbGFnIDIgKFl04oiSMikgaXMgc2lnbmlmaWNhbnRseSBhdXRvY29ycmVsYXRlZCAocG9zaXRpdmVseSkgd2l0aCB0aGUgY3VycmVudCB2YWx1ZSBvZiB0aGUgdmFyaWFibGUgc2luY2UgdGhpcyBhdXRvY29ycmVsYXRpb24gaXMgc2lnbmlmaWNhbnRseSBncmVhdGVyIHRoYW4gemVyby4KCldoYXQgaXMgdGhlIG1lYW5pbmcgb2YgdGhlIGZpcnN0IHNpZ25pZmljYW50IGxhZz8gSW4gdGhpcyBjYXNlLCB0aGlzIG1lYW5zIHRoYXQgdGhlIHZhbHVlIG9mIFkgYXQgYW55IHBvaW50IGluIHRpbWUgdCBoYXMgYW4gYXZlcmFnZSBhdXRvY29ycmVsYXRpb24gZXF1YWwgdG8gz5UxIChpZiB0aGUgbW9kZWwgZW5kcyB1cCBiZWluZyBhbiBBUigxKSkgd2l0aCBpdHMgb3duIHZhbHVlIGF0IHTiiJIxLiBUaGUgYXV0b2NvcnJlbGF0aW9uIG9mIFl0IHdpdGggaXRzIHByZXZpb3VzIHZhbHVlIFl04oiSMSBjYW4gYmUgY2FsY3VsYXRlZCBtYW51YWxseSBhcyB0aGUgY29ycmVsYXRpb24sIHdpY2ggaXMgZXF1YWwgdG8gdGhlaXIgY292YXJpYW5jZSBkaXZpZGVkIGJ5IHRoZSBwcm9kdWN0IG9mIHRoZWlyIHN0YW5kYXJkIGRldmlhdGlvbi4gUmVtZW1iZXJpbmcgdGhlIGZvcm11bGEgZm9yIGNvcnJlbGF0aW9uIGJldHdlZW4gMiB2YXJpYWJsZXMgWSBhbmQgWDoKCkNPUlIoWSxYKT1DT1YoWSxYKVNEKFkp4oiXU0QoWCkKSW4gdGhlIGNhc2Ugb2Yg4oCcQXV0b2NvcnJlbGF0aW9u4oCdLCB3ZSBvbmx5IGhhdmUgb25lIHZhcmlhYmxlIFksIHNvIHdlIGFyZSBsb29raW5nIGF0IHRoZSBjb3JyZWxhdGlvbiBvZiBZdCB3aXRoIGl0cyBvd24gcHJldmlvdXMgdmFsdWUgWXTiiJIxLiBUaGVuLCBhcHBseWluZyB0aGUgY29ycmVsYXRpb24gZm9ybXVsYSBiZXR3ZWVuIFl0IGFuZCBZdOKIkjEgKGluc3RlYWQgb2YgWCksIHdlIGNhbiBjYWxjdWxhdGUgdGhpcyBhdXRvY29ycmVsYXRpb24gYXM6CgpBVVRPQ09SUihZdCxZdOKIkjEpPUFVVE9DT1YoWXQsWXTiiJIxKVNEKFl0KeKIl1NEKFl04oiSMSkKU2luY2UgWSBpcyBzdXBwb3NlZCB0byBiZSBzdGF0aW9uYXJ5IHNlcmllcywgdGhlbiB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIFl0IGhhcyB0byBiZSB0aGUgc2FtZSBhcyB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIFl04oiSMS4gVGhlbjoKCkFVVE9DT1JSKFl0LFl04oiSMSk9QVVUT0NPVihZdCxZdOKIkjEpVkFSKFl0KT3OsygxKc+DMnkKRm9ydHVuYXRlbHksIFIgZG9lcyB0aGUgY2FsY3VsYXRpb24gb2YgYWxsIHRoZSBhdXRvY29ycmVsYXRpb25zIG9mIFl0IHdpdGggaXRzIG93biBsYWdzLCBhbmQgdGhlc2UgYXV0b2NvcnJlbGF0aW9ucyBhcmUgcGxvdHRlZCB1c2luZyB0aGUgYWNmMiBjb21tYW5kIChhcyBzZWVuIGFib3ZlKS4KClVubGlrZSB0aGUgQUNGIHBsb3QsIHRoZSBwYXJ0aWFsLWF1dG9jb3JyZWxhdGlvbiAoUEFDRikgcGxvdCBzaG93cyB0aGUgYXV0b2NvcnJlbGF0aW9uIG9mIHRoZSBsYWcgd2l0aCB0aGUgdmFyaWFibGUgYWZ0ZXIgY29uc2lkZXJpbmcgdGhlIGVmZmVjdCBvZiBsb3dlci1vcmRlciBhdXRvY29ycmVsYXRpb25zLiBUaGUgYXV0b2NvcnJlbGF0aW9uIGFuZCBwYXJ0aWFsIGF1dG9jb3JyZWxhdGlvbiBiZXR3ZWVuIFl0IGFuZCBZdOKIkjEgYXJlIHRoZSBzYW1lLCBzaW5jZSB0aGVyZSBpcyBubyBsb3dlci1vcmRlciBhdXRvY29ycmVsYXRpb25zLiBUaGUgYXV0b2NvcnJlbGF0aW9uIGJldHdlZW4gWXQgYW5kIFl04oiSMSBhbmQgdGhlIHBhcnRpYWwgYXV0b2NvcnJlbGF0aW9uIGJldHdlZW4gWXQgYW5kIFl04oiSMSB3aWxsIGJlIGRpZmZlcmVudCBzaW5jZSB0aGUgcGFydGlhbCBhdXRvY29ycmVsYXRpb24gaXMgY2FsY3VsYXRlZCBBRlRFUiB0aGUgYXV0b2NvcnJlbGF0aW9uIGJldHdlZW4gWXQgYW5kIFl04oiSMSBpcyB0YWtlbiBpbnRvIGNvbnNpZGVyYXRpb24uCgpJbiBvdGhlciB3b3JkcywgdGhlIFBBQ0YgcGxvdCBzaG93cyB0aGUgYW1vdW50IG9mIGF1dG9jb3JyZWxhdGlvbiBiZXR3ZWVuIFl0IGFuZCBpdHMgbGFnIEsgKFl04oiSaykgdGhhdCBpcyBub3QgZXhwbGFpbmVkIGJ5IGxvd2VyLW9yZGVyIGF1dG9jb3JyZWxhdGlvbnMgKFl0IHdpdGggKFl04oiSaykgYW5kIGFsbCB0aGUgY29ycmVzcG9uZGluZyBhdXRvY29ycmVsYXRpb25zIHVudGlsIFl04oiSMSkuCgpXZSBzZWUgdGhhdCBpbiB0aGUgYWMgcGxvdCBsYWcgMSBhbmQgMiBhdXRvY29ycmVsYXRpb25zIGFyZSBwb3NpdGl2ZSBhbmQgc2lnbmlmaWNhbnQsIGFuZCB0aGUgZm9sbG93aW5nIGxhZyBhdXRvY29ycmVsYXRpb25zIGFyZSBhbHNvIHBvc2l0aXZlIGJ1dCBub3Qgc2lnbmlmaWNhbnQuIFdlIHNlZSB0aGF0IGZvciBlYWNoIGxhZyB0aGUgYXV0b2NvcnJlbGF0aW9uIGRpbWluaXNoZXMuIEluIHRoZSBwYXJ0aWFsIGF1dG9jb3JyZWxhdGlvbiAoUEFDRikgd2UgY2FuIHNlZSB0aGF0IE9OTFkgdGhlIGF1dG9jb3JyZWxhdGlvbiBvZiBsYWcgMSBpcyBzaWduaWZpY2FudCBhbmQgcG9zaXRpdmUsIGFuZCBpbW1lZGlhdGx5IHRoZSByZXN0IG9mIHRoZSBjb3JyZWxhdGlvbiBnbyBjbG9zZSB0byB6ZXJvIHN1ZGRlbmx5LiBUaGlzIGlzIGEgY2xhc3NpY2FsIEFSKDEpIHNpZ25hdHVyZSB3aXRoIG9ubHkgdGhlIGZpcnN0IGxhZy4gV2UgZG8gbm90IG5lZWQgdG8gaW5jbHVkZSBMQUcgMiBzaW5jZSB0aGUgcGFjIGluZGljYXRlcyB0byBpbmNsdWRlIG9ubHkgTEFHMS4KClRoZW4gd2UgY2FuIHNlZSB0aGF0IHRoZSBwYXJ0aWFsIGF1dG9jb3JyZWxhdGlvbiBwbG90IChQQUNGKSBoZWxwcyB1cyB0byBpZGVudGlmeSB0aGUgIyBvZiBBUiB0ZXJtcy4gVGhlbiwgYWNjb3JkaW5nIHRvIHRoaXMgUEFDRiB3ZSBzZWUgdGhhdCBvbmx5IGxhZyAxIGlzIGF1dG9jb3JyZWxhdGVkIHdpdGggdGhlIGN1cnJlbnQgdmFsdWUgQUZURVIgY29uc2lkZXJpbmcgdGhlIGVmZmVjdCBvZiB0aGUgbG93ZXItbGV2ZWwgYXV0b2NvcnJlYXRpb25zIG9mIGxhZ3MgMiwzLDQsIGV0Yy4gSW4gb3RoZXIgd29yZHMsIHRoZSBhbm51YWwgJWNoYW5nZSBpbiBzYWxlcyBvZiB0aGUgY3VycmVudCBtb250aCBzZWVtcyB0byBiZSBwb3NpdGl2ZWx5IGNvcnJlbGF0ZWQgd2l0aCB0aGUgYW5udWFsICUgY2hhbmdlIGluIHNhbGVzIDEgbW9udGhzIGFnby4KCiMgUnVubmluZyBhbiBBUigxKSBtb2RlbAoKQSBmaXJzdCBvcmRlciBhdXRvcmVncmVzc2l2ZSBtb2RlbCB1c2luZyBvbmx5IHRoZSBsYWcgMSBjYW4gYmUgZXhwcmVzZWQgYXMgZm9sbG93cyBmb3IgYW4gc3RvY2hhc3RpYyBwcm9jZXNzIFl0OgoKWXQ9z5UwK8+VMVl04oiSMSvPtXQKClRoZSBwcm9jZXNzIGlzIHN0YXRpb25hcnkgb25seSBpZiDiiKPPlTHiiKM8MQoKSSBjYW4gcnVuIGFuIEFSIG1vZGVsIGluIFIgZm9yIGJyYW5kIDIgdG8gdGVzdCB3aGV0aGVyIHRoZSBhYnNvbHV0ZSB2YWx1ZSBvZiDPlTEgaXMgbG93ZXIgdGhhbiAxLiBJbiBSIHRoZSBmdW5jdGlvbiB0byBydW4gQVIsIE1BLCBBUk1BIGFuZCBBUklNQSBtb2RlbHMgaXMgdGhlIHNhbWU6IHNhcmltYSgpIGZyb20gdGhlIGFzdHNhIHBhY2thZ2UuIE9mIGNvdXJzZSwgdGhlIHN5bnRheCBvZiB0aGUgZnVuY3Rpb27igJlzIGFyZ3VtZW50cyBoYXMgdG8gYmUgYWRqdXN0ZWQgdG8gZWFjaCBtb2RlbC4gU28sIGxldOKAmXMgcnVuIGFuIEFSIG1vZGVsIHdpdGggbGFnIDEgZm9yIGJyYW5kIDIuCgpZb3UgbmVlZCB0byBpbnN0YWxsIHRoZSBmb3JlY2FzdCBwYWNrYWdlLgoKYGBge3J9CiMgTG9hZCBwYWNrYWdlIGZvcmVjYXN0CmxpYnJhcnkoZm9yZWNhc3QpCgojIFVzZSBmdW5jdGlvbiBBcmltYQptMSA8LSBBcmltYShzMTIubG5xYnJhbmQyLCBvcmRlciA9IGMoMSwwLDApKQpzdW1tYXJ5KG0xKQpgYGAKQWNjb3JkaW5nIHRvIHRoZSByZXN1bHQsIHdlIGNhbiBzZWUgdGhhdCB0aGUgY29lZmZpY2llbnQgz5UxIGlzIHBvc2l0aXZlLCBpdHMgYWJzb2x1dGUgdmFsdWUgaXMgbGVzcyB0aGFuIG9uZSwgYW5kIGl0IGlzIHNpZ25pZmljYW50IHNpbmNlIGl0cyBwLXZhbHVlIGlzIGxlc3MgdGhhbiAwLjA1LiBJbiB0aGVzZSBjYXNlcyB3ZSBjYW4gc2F5IHRoYXQgdGhlIGF1dG9jb3JyZWxhdGlvbiBpcyBwb3NpdGl2ZSBhdCB0aGUgOTUlIGNvbmZpZGVuY2UgbGV2ZWwuCgpXZSBjYW4gd3JpdGUgdGhlIGVxdWF0aW9uIG9mIGZpcnN0IG9yZGVyIG1vZGVscyBmb3IgYnJhbmQgMiBhcyBmb2xsb3dzOgoKczEyLmxuYnJhbmQydG9ucyh0KSA9IDAuMDUxNSArIDAuNjI2NiAqIHMxMi5sbmJyYW5kMnRvbnModC0xKSsgZXJyb3IodCkKCk5vdyB3ZSBjYW4gdXNlIHRoaXMgbW9kZWwgdG8gZG8gcHJlZGljdGlvbnMuIFdlIHdpbGwgbGVhcm4gaG93IHRvIGRvIHByZWRpY3Rpb25zIGluIHRoZSBmb2xsb3dpbmcgd29ya3Nob3AuCgpRVUVTVElPTjogSU5URVJQUkVUIFRIRSBDT0VGRklDSUVOVFMgT0YgVEhJUyBBUigxKSBNT0RFTApUSEUgUEFSQU1FVEVSUyBPRiBUSEUgQVIoMSkgTU9ERUwgQ09NUFJJU0UgUkVHUkVTU0lPTiBDT0VGRklDSUVOVFMgQVQgU1VDQ0VTU0lWRSBUSU1FIExBR1MsIFRIQVQgRU5DT0RFIFNFUVVFTlRJQUwgREVQRU5ERU5DSUVTIE9GIFRIRSBTWVNURU0gSU4gQSBTSU1QTEUgQU5EIEVGRkVDVElWRSBNQVRURVIuCgojIENoYWxsZW5nZQpEZXNpZ24gYW4gQVJNQSBtb2RlbCBmb3IgdGhlIGJyYW5kIDEgdXNpbmcgdGhlIGFubnVhbCAlIGdyb3d0aC4gUnVuIHRoZSBtb2RlbCBhbmQgaW50ZXJwcmV0IGl0LgpgYGB7cn0KcGxvdChzYWxlcy54dHMkcWJyYW5kMXRvbnMpCmBgYAoKYGBge3J9CnBsb3QoZGlmZihsbl9zYWxlcyRxYnJhbmQxdG9ucyksIHR5cGUgPSAibCIsIGNvbCA9ICJncmVlbiIpCmBgYApgYGB7cn0KczEyLmxucWJyYW5kMSA9IGRpZmYobG5fc2FsZXMkcWJyYW5kMXRvbnMsIGxhZyA9IDEyKQpwbG90KHMxMi5sbnFicmFuZDEsIHR5cGUgPSAibCIsIGNvbCA9ICJncmVlbiIpCgpgYGAKYGBge3J9CmxpYnJhcnkodHNlcmllcykKIyBCZWZvcmUgcnVubmluZyB0aGUgRGlja3ktRnVsbGVyIHRlc3QsIHdlIG5lZWQgdG8gZHJvcCBOQSAobWlzc2luZykgdmFsdWVzIG9mIAojICAgdGhlIHZhcmlhYmxlOgpzMTIubG5xYnJhbmQxID0gbmEub21pdChzMTIubG5xYnJhbmQxKQphZGYudGVzdChzMTIubG5xYnJhbmQxLCBhbHRlcm5hdGl2ZSA9ICJzdGF0aW9uYXJ5IixrPTApCmBgYApgYGB7cn0KbGlicmFyeShhc3RzYSkKYWNmMihzMTIubG5xYnJhbmQxKQpgYGAKYGBge3J9CiMgTG9hZCBwYWNrYWdlIGZvcmVjYXN0CmxpYnJhcnkoZm9yZWNhc3QpCgojIFVzZSBmdW5jdGlvbiBBcmltYQptMSA8LSBBcmltYShzMTIubG5xYnJhbmQxLCBvcmRlciA9IGMoMSwwLDApKQpzdW1tYXJ5KG0xKQpgYGAKOikK