Abstract: In this workshop we introduce the concepts of stationarity, unitary root and cointegration of time-series variables.
##Stationarity of time series variables
In this section we will work with historical sales of consumer products to examine the concept of stationarity in time-series.
Introduction
In our previous workshop we learned about the random walk model applied to finance. We learned that the logarithm of the stock prices behaves similar to a random walk model with a positive drift (ϕ0>0).
As we learned, a random walk model can be expressed in the following equation:
\[Y_{t}=\varphi _{0}+Y_{T-1}+\varepsilon _{t}\] Following this model we did a simulation for the logarithm of the S&P500, and we found that most of the time the simulations of a random walk model behaves similar to the real log of the S&P500 index.
We learned that if ϕ0>0, then the series will have a growing trend over time. We also learned that the higher the standard deviation of the daily shock, the more likely that the series will radically move up and down. The standard deviation of the shock is actually the daily volatility of the daily returns of the series.
An important insight about the random walk model is that the random walk model is a non-stationary series. What does this mean?
In short, a stationary series is a series that its mean in any time period is about the same (no matter which time periods we select), and its standard deviation is about the same for any time period. There is another condition of stationarity related to auto-covariance of the series, but we will leave the concept of auto-covariance for a later workshop.
Then, the random-walk model will always behave as a non-stationary series.
Let’s analyze what part of the random walk equation makes the series stationary. We can re-write the previous random walk equation as follows:
\[Y_{t}=\varphi _{0}+\phi _{1}*Y_{T-1}+\varepsilon _{t}\] If the coefficient ϕ1=1, then this equation becomes the random walk equation. When ϕ1=1 the Yt series becomes non-stationary.
If ϕ1<1, then Yt becomes a stationary series.
Let’s work with an example.
##Data collection and data management
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")
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)
# 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
fecha <- sales_brands.df$date
sales_brands.df <- sales_brands.df[,-1]
# 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)
timezone of object (UTC) is different than current timezone ().
qbrand1tons salesbrand1 qbrand2tons salesbrand2 qbrand3tons salesbrand3 qbrand4tons salesbrand4 qbrand5tons salesbrand5
2015-01-01 106.62 60780.72 195.46 60700.51 293.10 75196.35 185.91 48228.51 28.94 2295.50
2015-02-01 105.82 60411.47 216.09 68289.15 494.46 105010.90 149.30 39922.14 24.66 1973.43
2015-03-01 88.82 53174.89 220.15 62529.54 356.88 90902.84 144.65 39788.22 23.75 1903.24
2015-04-01 86.69 50861.69 170.74 50575.68 291.07 72853.34 161.43 42692.59 21.00 1684.28
2015-05-01 87.23 51014.23 177.17 54327.48 318.09 75277.10 141.09 37167.52 23.44 1883.41
qbrand6tons salesbrand6 tonstotal salestotal
2015-01-01 338.38 55561.26 1148.41 302762.8
2015-02-01 284.52 51469.74 1274.85 327076.8
2015-03-01 251.34 50395.48 1085.59 298694.2
2015-04-01 230.29 49124.61 961.22 267792.2
2015-05-01 250.45 46906.63 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 behavior 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.
A SERIES WITH A GROWING OR DECLINING TREND IS NS.
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:
THE FIRST DIFFERENCE OF THE LOG OF A VARIABLE IS ACTUALLY THE % CHANGE OF THE VARIABLE FROM ONE PERIOD TO THE NEXT.
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*, which can be calculated as the difference between the log value of the series and its log value 12 months ago. We can check this difference using the diff() function with the lag argument set to 12:
plot(diff(ln_sales$qbrand2tons, lag = 12), type = "l", col = "red")

lines(diff(ln_sales$qbrand6tons, lag = 12), type = "l", col = "blue")

In this case, it is difficult to evaluate graphically whether both series are stationary. 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 (ϕ1=1).
DICKY-FULLER ASSUMES THAT THE SERIES IS NON STATIONARY.
You need to install the package tseries to do the following analysis.
We can run the Dicky-Fuller test for the seasonal difference of the product 6 log sales as follows:
library(tseries)
adf.test(na.omit(diff(ln_sales$qbrand2tons, lag = 12)), alternative = "stationary")
Augmented Dickey-Fuller Test
data: na.omit(diff(ln_sales$qbrand2tons, lag = 12))
Dickey-Fuller = -3.574, Lag order = 3, p-value = 0.04701
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. Use the default value of k.
The null hypothesis of the Dicky-Fuller test is that the series is non-stationary. Actually, the *null-hypothesis of this test is that the ϕ1=1, which implies that the series is non-stationary. This is the reason why the Dicky-Fuller test is called a unit-root** test.
HO = ϕ1=1 -> NON STATIONARY
As any statistical test, if the p-value of the test is less than 0.05, then we have statistical evidence (at the 95% confidence level) to REJECT the null-hypothesis.
This is another way to do the same Dickey Fuller test:
# I create a variable for the seasonal difference of the log sales:
s12.lnbrand2tons <- na.omit(diff(ln_sales$qbrand2tons, lag = 12))
# I run Dicky-Fuller test for this seasonal difference:
adf.test(s12.lnbrand2tons, alternative = "stationary")
Augmented Dickey-Fuller Test
data: s12.lnbrand2tons
Dickey-Fuller = -3.574, Lag order = 3, p-value = 0.04701
alternative hypothesis: stationary
The Dicky Fuller test reports a p-value less than 0.05, indicating that we can reject the null hypothesis that states a unit root for these series (ϕ1=1). In other words, since the p-value is less than 0.05 we can say that there is statistical evidence to conclude that the seasonal difference of the log series (the annual % change) (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.
RUN A DICKY-FULLER TEST FOR THE ANNUAL % DIFFERENCE OF BRAND 6, AND PROVIDE AN INTERPRETATION
s12.lnbrand6tons <- na.omit(diff(ln_sales$qbrand6tons, lag = 12))
adf.test(s12.lnbrand6tons, alternative = "stationary")
Augmented Dickey-Fuller Test
data: s12.lnbrand6tons
Dickey-Fuller = -2.3423, Lag order = 3, p-value = 0.4387
alternative hypothesis: stationary
FOR THE VERY 6TH BRAND, WE MAY INTERPRET THAT THERE IS STATISTICAL EVIDENCE TO CONCLUDE THAT THE SEASONAL DIFFERENCE OF THE ANNUAL % CHANGE (s12.lnbrand6tons) IS NON STATIONARY. IN THIS CASE, THE DICKY FULLER TEST REPORTS A P-VALUE HIGHER THAN 0.05, INDICATING US THAT WE CAN ACCEPT THE NULL HYPOTHESIS THAT STATES HO = ϕ1=1 -> NON STATIONARY.
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 % change (in continuously compounding) 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 can use the seasonal difference of the log of sales to design a time-series model.
##Spurious regression
When we want to examine the relationship between two non-stationary variables by running a regression model, we have the risk to end up with a non-valid - spurious - regression. Before we understand why a regression model can be spurious, we start with and example using 2 real-world variables.
Install the wbstats package using RStudio. This package was written by the World Bank, and it has functions to download data of all countries around the world. The function wb downloads hundreds of time-series variables that the World Bank tracks for all countries. If you want to know more about this package, you can check its documentation in the cran web site (https://cran.r-project.org/web/packages/wbstats/wbstats.pdf)
We will download the infant mortality rate and the exports for Mexico. It is supposed that these variables have nothing in common, so we would not expect a significant relationship.
library(wbstats)
# Mexico - Infant mortality
infantm<-wb_data(indicator = c("SP.DYN.IMRT.IN"),
country="MEX", start_date = 1980, end_date = 2020)
# Mexico - Export value
exports<-wb_data(indicator = c("TX.VAL.MRCH.XD.WD"),
country="MEX", start_date = 1980, end_date = 2020)
The wb function brings a data frame with the requested data. We can plot the data to have an idea of these 2 variables:
plot.ts(infantm$SP.DYN.IMRT.IN)

plot.ts(exports$TX.VAL.MRCH.XD.WD)

Now run a regression using these series. Report the result of the regression. Did you find significant relationship? is your result what you expected?
COMO PODEMOS VER, CLARAMENTE EXISTE UNA RELACIÓN INVERSA ENTRE LAS VARIABLES; MIENTRAS QUE UNA CRECE, LA OTRA DECRECE. SIN EMBARGO, EL HECHO DE QUE ESTAS VARIABLES ESTÉN RELACIONADAS, NO NECESARIAMENTE NOS INDICA QUE ESTÁN COEINTEGRADAS, Y PARA ELLO EMPLEAREMOS EL DICKEY FULLER TEST.
m1 <- lm(exports$TX.VAL.MRCH.XD.WD ~ infantm$SP.DYN.IMRT.IN)
summary(m1)
Call:
lm(formula = exports$TX.VAL.MRCH.XD.WD ~ infantm$SP.DYN.IMRT.IN)
Residuals:
Min 1Q Median 3Q Max
-49.331 -39.723 -7.456 37.848 77.194
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 275.1783 16.0408 17.16 < 2e-16 ***
infantm$SP.DYN.IMRT.IN -6.1847 0.5327 -11.61 4.6e-14 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 41.65 on 38 degrees of freedom
(1 observation deleted due to missingness)
Multiple R-squared: 0.7801, Adjusted R-squared: 0.7743
F-statistic: 134.8 on 1 and 38 DF, p-value: 4.602e-14
RESEARCH ABOUT SPURIOUS REGRESSION. With your words briefly explain in which cases you can end up with a spurious regression
UNA RELACIÓN ESPURIA HACE REFERENCIA A LA APARIENCIA QUE EXISTE EN UNA RELACIÓN DE CAUSALIDAD ENTRE VARIABLES CUANDO EN REALIDAD ESTA NO EXISTE. ES DECIR, QUE AUNQUE PARECIERA QUE ALGUNAS VARIABLES ESTÁN CORRELACIONADAS, REALMENTE NO HAY UNA RELACIÓN CAUSAL ENTRE ESTAS, POR LO TANTO ES ESPURIA. POR EJEMPLO, LAS VENTAS DE NIEVES EN LA CIUDAD DE QUERÉTARO Y LAS MUERTES POR COVID-19 EN ESTADOS UNIDOS. AUNQUE EXISTIERA LA POSIBILIDAD DE DETERMINAR CIERTA RELACIÓN, EN CASO DE QUE EXISTA, SERÍA ESPURIA, PORQUE REALMENTE NO TIENEN NADA QUE LA UNA CON LA OTRA.
##Cointegration
When two non-stationary series are strongly related in the long run, then we say that both series are cointegrated. The question is how strong this long-term relationship needs to be in order to consider 2 non-stationary series as cointegrated.
To do a cointegration statistical test of 2 non-stationary series, we need to do the following:
Run a linear regression of the 2 non-stationary series
Get the residuals of this regression
Do a Dicky-Fuller test to check whether this regression residuals (errors) is a stationary series. If the p-value<0.05, then we can say that there is statistical evidence to consider both non-stationary series as cointegrated.
If 2 non-stationary series are NOT cointegrated, then its linear regression becomes a spurious regression. In other words, when 2 non-stationary series are not cointegrated, the result of a linear regression using these 2 variables will not be reliable or valid.
Are the infant mortality and export series cointegrated? Is the regression spurious or valid? Run and interpret the corresponding test
Here is a code to help you respond this question.
library(tseries)
# The errors/residual of the regression are stored in the residuals
# attribute of the m1 model:
adf.test(m1$residuals, k = 0)
Augmented Dickey-Fuller Test
data: m1$residuals
Dickey-Fuller = -1.5881, Lag order = 0, p-value = 0.7351
alternative hypothesis: stationary
Tras haber empleado el Dickey-Fuller test, podemos determinar que la relación entre la mortalidad infantil y las exportaciones es espuria. Ya que, aunque acertadamente podemos apreciar una relación inversa; no hay suficiente soporte estadístico para determinar que ambas variables estén correlacionadas. Simplemente es una relación espuria. Con el valor p, en este caso de 73.51%, terminamos por concluir que la Ho es correcta, mientras que la Ha es rechazada. Es decir, si nos fiamos de dicha relación para emplear algun estudio, existe un 73.51% de equivocación en nuestros hallazgos.
##Cointegration between Financial series
Using daily data of Mexico IPCyC market index and the S&P 500, examine whether two series are cointegrated. Generate an index for each instrument. To do these indexes, create a variable that represents how 1.00 peso or 1.00 dollar invested in each instrument would be changing over time.
- From Jan 1, 2015 to Oct 2, 2017.
- From Oct 3, 2017 to Feb 28, 2018
For both cases, run a cointegration test and INTERPRET your results.
rm(list=ls())
options(scipen=999)
library(quantmod)
getSymbols(Symbols= c("^MXX", "^GSPC"), from="2015-01-01", to= "2017-10-02",
periodicity = "daily", src = "yahoo")
[1] "^MXX" "^GSPC"
prices = Ad(merge(MXX,GSPC))
prices = na.omit(prices)
MXX1 = as.numeric(MXX$MXX.Adjusted[1])
GSPC1 = as.numeric(GSPC$GSPC.Adjusted[1])
ONEMXP = prices$MXX.Adjusted / MXX1
ONEUSD = prices$GSPC.Adjusted / GSPC1
plot(ONEMXP$MXX.Adjusted)

plot(ONEUSD$GSPC.Adjusted)

m3 <- lm(ONEMXP$MXX.Adjusted ~ ONEUSD$GSPC.Adjusted)
summary(m3)
Call:
lm(formula = ONEMXP$MXX.Adjusted ~ ONEUSD$GSPC.Adjusted)
Residuals:
Min 1Q Median 3Q Max
-0.06656 -0.01835 0.00244 0.01944 0.06810
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.35668 0.01383 25.79 <0.0000000000000002 ***
ONEUSD$GSPC.Adjusted 0.69852 0.01311 53.29 <0.0000000000000002 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.02702 on 672 degrees of freedom
Multiple R-squared: 0.8086, Adjusted R-squared: 0.8083
F-statistic: 2840 on 1 and 672 DF, p-value: < 0.00000000000000022
library(tseries)
adf.test(m3$residuals, k = 0)
Augmented Dickey-Fuller Test
data: m3$residuals
Dickey-Fuller = -3.5752, Lag order = 0, p-value = 0.03508
alternative hypothesis: stationary
ES BIEN SABIDO QUE LA ECONOMÍA MEXICANA DEPENDE DE LA ECONOMÍA ESTADOUNIDENSE EN GRAN PORCENTAJE; NO OBSTANTE, CON EL FIN DE DETERMINAR QUE DICHA CORRELACIÓN NO SEA ESPURIA, DECIDIMOS CORRER EL DICKEY-FULLER TEST Y LOGRAMOS DETERMINAR QUE EFECTIVAMENTE AMBOS ÍNDICES ESTÁN COINTEGRADOS, ASÍ COMO LA EXISTENTE CORRELACIÓN ENTRE ESTAS VARIABLES. CON UN VALOR P DE 3.5%, TAMBIÉN COMPROBAMOS ESTADÍSTICAMENTE QUE AMBAS SERIES SON NO ESTACIONARIAS Y UNA VEZ MÁS, QUE ESTÁN COINTEGRADAS LAS VARIABLES.
rm(list=ls())
options(scipen=999)
library(quantmod)
getSymbols(Symbols= c("^MXX", "^GSPC"), from="2017-10-03", to= "2018-02-28",
periodicity = "daily", src = "yahoo")
[1] "^MXX" "^GSPC"
prices2 = Ad(merge(MXX,GSPC))
prices2 = na.omit(prices2)
MXX2 = as.numeric(MXX$MXX.Adjusted[1])
GSPC2 = as.numeric(GSPC$GSPC.Adjusted[1])
ONEMXP2 = prices2$MXX.Adjusted / MXX2
ONEUSD2 = prices2$GSPC.Adjusted / GSPC2
plot(ONEMXP2$MXX.Adjusted)

plot(ONEUSD2$GSPC.Adjusted)

m4 <- lm(ONEMXP2$MXX.Adjusted ~ ONEUSD2$GSPC.Adjusted)
summary(m4)
Call:
lm(formula = ONEMXP2$MXX.Adjusted ~ ONEUSD2$GSPC.Adjusted)
Residuals:
Min 1Q Median 3Q Max
-0.037454 -0.014008 -0.002567 0.017749 0.040777
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.79716 0.05928 13.447 < 0.0000000000000002 ***
ONEUSD2$GSPC.Adjusted 0.16206 0.05640 2.874 0.00501 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.02006 on 95 degrees of freedom
Multiple R-squared: 0.07997, Adjusted R-squared: 0.07028
F-statistic: 8.257 on 1 and 95 DF, p-value: 0.005008
library(tseries)
adf.test(m4$residuals, k = 0)
Augmented Dickey-Fuller Test
data: m4$residuals
Dickey-Fuller = -2.0418, Lag order = 0, p-value = 0.5592
alternative hypothesis: stationary
EN ESTE SEGUNDO PERIODO DE TIEMPO, CURIOSAMENTE OBTENEMOS DISTINTOS RESULTADOS. LA REGRESIÓN LINEAL ESTÁ CLARA, SI EXISTE UNA RELACIÓN POSITIVA ENTRE AMBAS VARIABLES Y EL VALOR P (DE LA REGRESIÓN LINEAL) NOS RECTIFICA CON CERTEZA SU ALTA RELACIÓN. NO OBSTANTE, TRAS HABER CORRIDO EL DICKEY FULLER TEST, PODEMOS OBSERVAR CÓMO ESTE VALOR SUPERA POR MUCHO EL 5%; INDICANDONOS QUE NO EXISTE COINTEGRACIÓN ENTRE LAS VARIABLES Y QUE AMBAS SERIES SON ESTACIONARIAS.
LS0tCnRpdGxlOiAiV29ya3Nob3AgMiwgVGltZSBTZXJpZXMiCmF1dGhvcjogUmFmYWVsIFJvbW8gLSBBMDE3MDE0OTMKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKQWJzdHJhY3Q6CkluIHRoaXMgd29ya3Nob3Agd2UgaW50cm9kdWNlIHRoZSBjb25jZXB0cyBvZiBzdGF0aW9uYXJpdHksIHVuaXRhcnkgcm9vdCBhbmQgY29pbnRlZ3JhdGlvbiBvZiB0aW1lLXNlcmllcyB2YXJpYWJsZXMuIAoKIyNTdGF0aW9uYXJpdHkgb2YgdGltZSBzZXJpZXMgdmFyaWFibGVzCgpJbiB0aGlzIHNlY3Rpb24gd2Ugd2lsbCB3b3JrIHdpdGggaGlzdG9yaWNhbCBzYWxlcyBvZiBjb25zdW1lciBwcm9kdWN0cyB0byBleGFtaW5lIHRoZSBjb25jZXB0IG9mIHN0YXRpb25hcml0eSBpbiB0aW1lLXNlcmllcy4KCkludHJvZHVjdGlvbgoKSW4gb3VyIHByZXZpb3VzIHdvcmtzaG9wIHdlIGxlYXJuZWQgYWJvdXQgdGhlIHJhbmRvbSB3YWxrIG1vZGVsIGFwcGxpZWQgdG8gZmluYW5jZS4gV2UgbGVhcm5lZCB0aGF0IHRoZSBsb2dhcml0aG0gb2YgdGhlIHN0b2NrIHByaWNlcyBiZWhhdmVzIHNpbWlsYXIgdG8gYSByYW5kb20gd2FsayBtb2RlbCB3aXRoIGEgcG9zaXRpdmUgZHJpZnQgKM+VMD4wKS4KCkFzIHdlIGxlYXJuZWQsIGEgcmFuZG9tIHdhbGsgbW9kZWwgY2FuIGJlIGV4cHJlc3NlZCBpbiB0aGUgZm9sbG93aW5nIGVxdWF0aW9uOgoKJCRZX3t0fT1cdmFycGhpIF97MH0rWV97VC0xfStcdmFyZXBzaWxvbiBfe3R9JCQKRm9sbG93aW5nIHRoaXMgbW9kZWwgd2UgZGlkIGEgc2ltdWxhdGlvbiBmb3IgdGhlIGxvZ2FyaXRobSBvZiB0aGUgUyZQNTAwLCBhbmQgd2UgZm91bmQgdGhhdCBtb3N0IG9mIHRoZSB0aW1lIHRoZSBzaW11bGF0aW9ucyBvZiBhIHJhbmRvbSB3YWxrIG1vZGVsIGJlaGF2ZXMgc2ltaWxhciB0byB0aGUgcmVhbCBsb2cgb2YgdGhlIFMmUDUwMCBpbmRleC4KCldlIGxlYXJuZWQgdGhhdCBpZiDPlTA+MCwgdGhlbiB0aGUgc2VyaWVzIHdpbGwgaGF2ZSBhIGdyb3dpbmcgdHJlbmQgb3ZlciB0aW1lLiBXZSBhbHNvIGxlYXJuZWQgdGhhdCB0aGUgaGlnaGVyIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIGRhaWx5IHNob2NrLCB0aGUgbW9yZSBsaWtlbHkgdGhhdCB0aGUgc2VyaWVzIHdpbGwgcmFkaWNhbGx5IG1vdmUgdXAgYW5kIGRvd24uIFRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIHNob2NrIGlzIGFjdHVhbGx5IHRoZSBkYWlseSB2b2xhdGlsaXR5IG9mIHRoZSBkYWlseSByZXR1cm5zIG9mIHRoZSBzZXJpZXMuCgpBbiBpbXBvcnRhbnQgaW5zaWdodCBhYm91dCB0aGUgcmFuZG9tIHdhbGsgbW9kZWwgaXMgdGhhdCB0aGUgcmFuZG9tIHdhbGsgbW9kZWwgaXMgYSBub24tc3RhdGlvbmFyeSBzZXJpZXMuIFdoYXQgZG9lcyB0aGlzIG1lYW4/CgpJbiBzaG9ydCwgYSBzdGF0aW9uYXJ5IHNlcmllcyBpcyBhIHNlcmllcyB0aGF0IGl0cyBtZWFuIGluIGFueSB0aW1lIHBlcmlvZCBpcyBhYm91dCB0aGUgc2FtZSAobm8gbWF0dGVyIHdoaWNoIHRpbWUgcGVyaW9kcyB3ZSBzZWxlY3QpLCBhbmQgaXRzIHN0YW5kYXJkIGRldmlhdGlvbiBpcyBhYm91dCB0aGUgc2FtZSBmb3IgYW55IHRpbWUgcGVyaW9kLiBUaGVyZSBpcyBhbm90aGVyIGNvbmRpdGlvbiBvZiBzdGF0aW9uYXJpdHkgcmVsYXRlZCB0byBhdXRvLWNvdmFyaWFuY2Ugb2YgdGhlIHNlcmllcywgYnV0IHdlIHdpbGwgbGVhdmUgdGhlIGNvbmNlcHQgb2YgYXV0by1jb3ZhcmlhbmNlIGZvciBhIGxhdGVyIHdvcmtzaG9wLgoKVGhlbiwgdGhlIHJhbmRvbS13YWxrIG1vZGVsIHdpbGwgYWx3YXlzIGJlaGF2ZSBhcyBhIG5vbi1zdGF0aW9uYXJ5IHNlcmllcy4KCkxldOKAmXMgYW5hbHl6ZSB3aGF0IHBhcnQgb2YgdGhlIHJhbmRvbSB3YWxrIGVxdWF0aW9uIG1ha2VzIHRoZSBzZXJpZXMgc3RhdGlvbmFyeS4gV2UgY2FuIHJlLXdyaXRlIHRoZSBwcmV2aW91cyByYW5kb20gd2FsayBlcXVhdGlvbiBhcyBmb2xsb3dzOgoKJCRZX3t0fT1cdmFycGhpIF97MH0rXHBoaSBfezF9Kllfe1QtMX0rXHZhcmVwc2lsb24gX3t0fSQkCklmIHRoZSBjb2VmZmljaWVudCDPlTE9MSwgdGhlbiB0aGlzIGVxdWF0aW9uIGJlY29tZXMgdGhlIHJhbmRvbSB3YWxrIGVxdWF0aW9uLiBXaGVuIM+VMT0xIHRoZSBZdCBzZXJpZXMgYmVjb21lcyBub24tc3RhdGlvbmFyeS4KCklmIM+VMTwxLCB0aGVuIFl0IGJlY29tZXMgYSBzdGF0aW9uYXJ5IHNlcmllcy4KCkxldOKAmXMgd29yayB3aXRoIGFuIGV4YW1wbGUuCgojI0RhdGEgY29sbGVjdGlvbiBhbmQgZGF0YSBtYW5hZ2VtZW50CgpXZSB3aWxsIHdvcmsgd2l0aCBhbiBvbmxpbmUgZGF0YXNldCB0aGF0IGNvbnRhaW5zIHNhbGVzIGRhdGEgb2YgZGlmZmVyZW50IGNvbnN1bWVyIHByb2R1Y3RzLiBUaGUgZGF0YSB3YXMgY3JlYXRlZCB1c2luZyByZWFsIHByb2R1Y3RzLCBidXQgdGhlIG5hbWVzIG9mIHRoZSBwcm9kdWN0cyB3ZXJlIGNoYW5nZWQgZHVlIHRvIHByaXZhY3kgaXNzdWVzLgoKRG93bmxvYWQgdGhlIGV4Y2VsIGZpbGUgZnJvbSBhIHdlYiBzaXRlOgoKYGBge3J9CmRvd25sb2FkLmZpbGUoImh0dHA6Ly93d3cuYXByYWRpZS5jb20vZWMyMDA0L3NhbGVzYnJhbmRzMy54bHN4IiwgInNhbGVzYnJhbmRzMy54bHN4IiwgbW9kZT0id2IiKQpgYGAKClRoaXMgZGF0YXNldCBoYXMgc2FsZXMgaW5mb3JtYXRpb24gb2Ygc2V2ZXJhbCBicmFuZHMgb2YgY29uc3VtZXIgcHJvZHVjdHMgdGhhdCBiZWxvbmcgdG8gb25lIGNhdGVnb3J5IChmb3IgZXhhbXBsZSwgdGhlIGNhdGVnb3J5IGNhbiBiZSBDZXJlYWxzIG9yIENhbmRpZXMpLiBUaGUgY29udGVudCBvZiB0aGlzIGRhdGFzZXQgaXMgdmVyeSBzaW1pbGFyIHRvIGEgcmVhbC13b3JsZCBjYXRlZ29yeS4gQ29uc3VtZXIgcHJvZHVjdHMgdXN1YWxseSBzaG93IHNvbWUgc2Vhc29uYWxpdHkgYW5kIHRyZW5kIG92ZXIgdGltZS4gV2Ugd2lsbCBsZWFybiBob3cgdG8gaGFuZGxlIHRoZXNlIGZlYXR1cmVzIGxhdGVyLgoKQWxzbywgeW91IGhhdmUgdG8gaW5zdGFsbCB0aGUgcmVhZHhsIHBhY2thZ2UuIFRoaXMgcGFja2FnZSByZWFkcyBkYXRhIGZyb20gRXhjZWwgZmlsZXMuIFdlIGxvYWQgdGhpcyBwYWNrYWdlOgoKYGBge3J9CmxpYnJhcnkocmVhZHhsKQpgYGAKCk5vdywgd2UgaW1wb3J0IHRoZSBFeGNlbCBmaWxlIGludG8gYW4gUiBkYXRhZnJhbWU6CgpgYGB7cn0Kc2FsZXNfYnJhbmRzIDwtIHJlYWRfZXhjZWwoInNhbGVzYnJhbmRzMy54bHN4Iiwgc2hlZXQgPSAiUmVzdWx0YWRvIikKCiMgQWx3YXlzIGZhbWlsaWFyaXplIHdpdGggdGhlIGRhdGEKaGVhZChzYWxlc19icmFuZHMsIDUpCmBgYAoKQXMgeW91IGNhbiBzZWUsIHdlIGhhdmUgaW1wb3J0ZWQgYSBtb250aGx5IGRhdGFzZXQgd2hlcmUgdGhlIHZhcmlhYmxlIGRhdGUgc2hvd3MgdGhlIGZpcnN0IGRheSBvZiB0aGUgbW9udGggaW4gYSB5eXl5LW1tLWRkIGZvcm1hdC4KCkluIG9yZGVyIHRvIHBlcmZvcm0gc29tZSB0aW1lLXNlcmllcyBhbmFseXNpcywgaXQgaXMgcmVjb21tZW5kZWQgdG8gdXNlIHh0cyBvYmplY3RzLiBXZSB3aWxsIGNvbnN0cnVjdCBhIHh0cyBvYmplY3QgdXNpbmcgdGhlIHh0cygpIG1ldGhvZC4gVGhlIG9iamVjdHMgb2YgeHRzIGNsYXNzIGFyZSBjb21wb3NlZCBieSAyIG9iamVjdHM6IHRoZSBjb3JlIGRhdGEgYW5kIHRoZSBpbmRleCAoY2xhc3MgRGF0ZSwgUE9TSVgsIGV0YykuCgpgYGB7cn0KIyBMb2FkIGxpYnJhcnkgeHRzLiBJbnN0YWxsIHRoZSBwYWNrYWdlIGlmIHlvdSBoYXZlbid0IGFscmVhZHkuCmxpYnJhcnkoeHRzKQoKIyBXZSB3aWxsIHN0YXJ0IGJ5IHR1cm5pbmcgc2FsZXNfYnJhbmRzIGludG8gYSBkYXRhIGZyYW1lIAojIGJlY2F1c2UgZGF0YSBmcmFtZXMgYXJlIGVhc2llciB0byBtYW5pcHVsYXRlCnNhbGVzX2JyYW5kcy5kZiA8LSBhcy5kYXRhLmZyYW1lKHNhbGVzX2JyYW5kcykKCiMgRGl2aWRlIHRoZSBpbmRleCBhbmQgdGhlIGNvcmUgZGF0YQpmZWNoYSA8LSBzYWxlc19icmFuZHMuZGYkZGF0ZQpzYWxlc19icmFuZHMuZGYgPC0gc2FsZXNfYnJhbmRzLmRmWywtMV0KCiMgSm9pbiBib3RoIG9iamVjdHMgdXNpbmcgeHRzKCkgYW5kIGFzc2lnbiB0aGUgcmVzdWx0aW5nIG9iamVjdCB0byBzYWxlcy54dHMKc2FsZXMueHRzIDwtIHh0cyh4ID0gc2FsZXNfYnJhbmRzLmRmLCBvcmRlci5ieSA9IGZlY2hhKQoKaGVhZChzYWxlcy54dHMsIDUpCgojIERvIHlvdSBub3RpY2UgYW55IGRpZmZlcmVuY2UgYmV0d2VlbiBkYXRhIGZyYW1lcyBhbmQgeHRzIG9iamVjdHM/CgojZGVsZXRlIHZhcmlhYmxlIGZlY2hhCnJtKGZlY2hhKQpgYGAKCiMjU3RhdGlvbmFyeSB2cyBOb24tc3RhdGlvbmFyeQoKV2UgY2FuIGhhdmUgYW4gb3ZlcnZpZXcgb2YgdGhlIGJlaGF2aW9yIG9mIHNhbGVzIG9mIHRoZXNlIGNvbnN1bWVyIHByb2R1Y3RzIHVzaW5nIHRoZSBwbG90IGNvbW1hbmQuIExldOKAmXMgZm9jdXMgb24gYnJhbmQgMiBhbmQgNi4gVG8gc2VlIHZvbHVtZSBzYWxlcyAodGhlIG51bWJlciBvZiB0b25zIHNvbGQpIG9mIGJyYW5kIDI6CgpgYGB7cn0KcGxvdChzYWxlcy54dHMkcWJyYW5kMnRvbnMpCmBgYAoKSXQgc2VlbXMgdGhhdCB0aGlzIHByb2R1Y3QgaGFzIGEgZ3Jvd2luZyB0cmVuZCBvdmVyIHRpbWUsIGV4Y2VwdCBmb3IgdGhlIGxhc3QgeWVhci4KCldlIGNhbiBncmFwaCBjb25zdW1lciBicmFuZCA2OgoKYGBge3J9CnBsb3Qoc2FsZXMueHRzJHFicmFuZDZ0b25zKQpgYGAKClRoaXMgYnJhbmQgaGFzIGEgY2xlYXIgZ3Jvd2luZyB0cmVuZCBvdmVyIHRpbWUuIEFzIHdlIGNhbiBzZWUsIG1hbnkgY29uc3VtZXIgcHJvZHVjdHMgaGF2ZSBhIGdyb3dpbmcgb3IgYSBkZWNsaW5pbmcgdHJlbmQuIEFuZCBvdGhlciBwcm9kdWN0cyBtaWdodCBzZWVtIHRvIGJlIHN0YXRpb25hcnkgb3ZlciB0aW1lLCB3aXRoIHNhbGVzIG92ZXIgYW4gYXZlcmFnZSBvdmVyIHRpbWUuCgpBIHNlcmllcyB3aXRoIGEgZ3Jvd2luZyBvciBkZWNsaW5pbmcgdHJlbmQgaXMgbm9uLXN0YXRpb25hcnkuIE1vc3Qgb2YgdGhlIHZhcmlhYmxlcyB0aGF0IHJlcHJlc2VudCBzYWxlcyBvZiBhbnkgcHJvZHVjdCBjYW4gYmUgdHJlYXRlZCBhcyBub24tc3RhdGlvbmFyeS4gVGhlbiwgYSBydWxlIG9mIHRodW1iIHdoZW4gd2Ugd29yayB3aXRoIGJ1c2luZXNzIHZhcmlhYmxlcyBzdWNoIGFzIHZvbHVtZSBzYWxlcywgdmFsdWUgc2FsZXMsIGNvc3Qgb2YgZ29vZCBzb2xkLCBldGMgaXMgdG8gdHJhbnNmb3JtIHRoZSBzZXJpZXMgaW50byBhIHN0YXRpb25hcnkgc2VyaWVzLgoKQSBTRVJJRVMgV0lUSCBBIEdST1dJTkcgT1IgREVDTElOSU5HIFRSRU5EIElTIE5TLgoKV2hlbiB5b3Ugd29yayB3aXRoIHNhbGVzIGRhdGEsIEkgc3Ryb25nbHkgcmVjb21tZW5kIHRvIGNyZWF0ZSB0aGUgZmlyc3QgZGlmZmVyZW5jZSBvZiB0aGUgbG9nYXJpdGhtIG9mIHRoZSB2YXJpYWJsZS4gVGhpcyBpcyBhY3R1YWxseSBpdHMgcGVyY2VudGFnZSBjaGFuZ2UgKGluIGNvbnRpbnVvdXNseSBjb21wb3VuZGVkKS4gSWYgeW91IGRvIHRoaXMgcHJvY2VzcyB0byBtb3N0IG9mIHJlYWwtd29ybGQgc2FsZXMgdmFyaWFibGUgdGhlIHJlc3VsdCB3aWxsIGJlIHN0YXRpb25hcnkgbW9zdCBvZiB0aGUgdGltZSAoYWJvdXQgOTUlIG9mIHRoZSB2YXJpYWJsZXMpLiBUaGUgb3RoZXIgcmVhc29uIHdoeSBpdCBpcyByZWNvbW1lbmRlZCB0byBkbyB0aGlzIHRyYW5zZm9ybWF0aW9uIGlzIHRoYXQgdGhlIGZpcnN0IGRpZmZlcmVuY2Ugb2YgdGhlIGxvZyBvZiBhIHZhcmlhYmxlIGlzIGFjdHVhbGx5IHRoZSAlIGNoYW5nZSBvZiB0aGUgdmFyaWFibGUgZnJvbSBvbmUgcGVyaW9kIHRvIHRoZSBuZXh0IChpbiBjb250aW51b3VzbHkgY29tcG91bmRlZCBwZXJjZW50YWdlKS4gVGhlbiwgd2UgY2FuIGRvIHRoaXMgdHJhbnNmb3JtYXRpb24gYXMgZm9sbG93czoKClRIRSBGSVJTVCBESUZGRVJFTkNFIE9GIFRIRSBMT0cgT0YgQSBWQVJJQUJMRSBJUyBBQ1RVQUxMWSBUSEUgJSBDSEFOR0UgT0YgVEhFIFZBUklBQkxFIEZST00gT05FIFBFUklPRCBUTyBUSEUgTkVYVC4KCldlIGZpcnN0IGNyZWF0ZSB0aGUgbmF0dXJhbCBsb2cgb2YgZWFjaCBzYWxlcyB2YXJpYWJsZSAoaW4gdG9ucykuIFdlIGNhbiBhcHBseSB0aGUgbG9nIGZ1bmN0aW9uIHRvIHRoZSB4dHMgb2JqZWN0IHRvIGdldCB0aGUgbG9nIG9mIGFsbCBzZXJpZXM6CgpgYGB7cn0KbG5fc2FsZXMgPC0gbG9nKHNhbGVzLnh0cykKYGBgCgpUaGUgbmV3IG9iamVjdCBoYXMgdGhlIHNhbWUgc3RydWN0dXJlIGFzIHNhbGVzLnh0cyBidXQgdGhlIGNvbHVtbnMgY29udGFpbiB0aGUgbmF0dXJhbCBsb2dhcml0aG0gb2YgdGhlIGRhdGEuIFRoaXMgaXMgZHVlIHRvIFIgdmVjdG9yaXphdGlvbiwgYSBrZXkgZmVhdHVyZSBvZiBSLgoKTm93LCBJIGNhbiB3b3JrIHdpdGggdGhlIGZpcnN0IGRpZmZlcmVuY2UgbW9udGgtYnktbW9udGggdXNpbmcgdGhlIGRpZmYoKSBmdW5jdGlvbiBmb3IgZWFjaCB2YXJpYWJsZS4gRm9yIGV4YW1wbGUsIHRvIGdyYXBoIHRoZSBmaXJzdCBkaWZmZXJlbmNlIG9mIHRoZSBsb2cgb2Ygdm9sdW1lIHNhbGVzIGZvciBib3RoIGJyYW5kcyA6CgpgYGB7cn0KcGxvdChkaWZmKGxuX3NhbGVzJHFicmFuZDJ0b25zKSwgdHlwZSA9ICJsIiwgY29sID0gInJlZCIpCmxpbmVzKGRpZmYobG5fc2FsZXMkcWJyYW5kNnRvbnMpLCB0eXBlID0gImwiLCBjb2wgPSAiYmx1ZSIpCmBgYAoKVGhlIGZpcnN0IGRpZmZlcmVuY2Ugb2YgdGhlIGxvZyB2YWx1ZSBpbiBSIGlzIGRpZmYobG5fc2FsZXMkcWJyYW5kMnRvbnMpLiBUaGUgZGlmZigpIGZ1bmN0aW9uIGdlbmVyYXRlcyBvbiB0aGUgZmx5IHRoaXMgZmlyc3QgZGlmZmVyZW5jZSBhczoKCmRpZmYobG5fc2FsZXNxYnJhbmQydG9uc+KIlykgPSDiiJdsbnNhbGVzcWJyYW5kMnRvbnMgLSBsYWcobG5fc2FsZXMkcWJyYW5kMnRvbnMsIDEpCgpSZW1lbWJlciB0aGF0IHRoZSBkb2xsYXIgc2lnbiBvcGVyYXRvciAoJCkgaXMgdXNlZCB0byBhY2Nlc3MvcmVmZXIgdG8gdGhlIGNvbHVtbnMgb2YgYSBkYXRhIGZyYW1lIG9yIHh0cyBvYmplY3QuCgpXZSBjYW4gc2VlIG5vdyB0aGF0IHRoZSAyIHNlcmllcyBsb29rIGxpa2Ugc3RhdGlvbmFyeSBzaW5jZSB0aGVpciBtZWFucyB0ZW5kIHRvIGJlIGluIHRoZSBzYW1lIGxldmVsLgoKUiBwZXJmb3JtcyB0aGUgZmlyc3QgZGlmZmVyZW5jZSBjYWxjdWxhdGlvbiB0ZW1wb3JhcmlseSB0byBkbyBhIGdyYXBoLCBhbmQgdGhlbiwgdGhpcyB2YXJpYWJsZSBpcyBub3Qgc2F2ZWQgaW4gdGhlIGRhdGFzZXQgb3IgZW52aXJvbm1lbnQuIEluIG90aGVyIHdvcmRzLCB3ZSBkbyBub3QgbmVlZCB0byBnZW5lcmF0ZSB0aGUgZmlyc3QgZGlmZmVyZW5jZSBhcyBhbm90aGVyIHZhcmlhYmxlIChjb2x1bW4pLCBidXQgd2UgY2FuIGlmIHdlIG5lZWQgdG8uCgpBbm90aGVyIHRyYW5zZm9ybWF0aW9uIHdpdGggbW9udGhseSBkYXRhIGlzICoqYW5udWFsIHBlcmNlbnRhZ2UgY2hhbmdlKiwgd2hpY2ggY2FuIGJlIGNhbGN1bGF0ZWQgYXMgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgbG9nIHZhbHVlIG9mIHRoZSBzZXJpZXMgYW5kIGl0cyBsb2cgdmFsdWUgMTIgbW9udGhzIGFnby4gV2UgY2FuIGNoZWNrIHRoaXMgZGlmZmVyZW5jZSB1c2luZyB0aGUgZGlmZigpIGZ1bmN0aW9uIHdpdGggdGhlIGxhZyBhcmd1bWVudCBzZXQgdG8gMTI6CgpgYGB7cn0KcGxvdChkaWZmKGxuX3NhbGVzJHFicmFuZDJ0b25zLCBsYWcgPSAxMiksIHR5cGUgPSAibCIsIGNvbCA9ICJyZWQiKQpsaW5lcyhkaWZmKGxuX3NhbGVzJHFicmFuZDZ0b25zLCBsYWcgPSAxMiksIHR5cGUgPSAibCIsIGNvbCA9ICJibHVlIikKYGBgCkluIHRoaXMgY2FzZSwgaXQgaXMgZGlmZmljdWx0IHRvIGV2YWx1YXRlIGdyYXBoaWNhbGx5IHdoZXRoZXIgYm90aCBzZXJpZXMgYXJlIHN0YXRpb25hcnkuIFdlIG5lZWQgdG8gZG8gYSBzdGF0aXN0aWNhbCB0ZXN0IHRvIGNoZWNrIHdoZXRoZXIgYSBzZXJpZXMgY2FuIGJlIHRyZWF0ZWQgYXMgc3RhdGlvbmFyeSBvciBub3QuIFNvbWUgc2VyaWVzIG1pZ2h0IG5vdCBsb29rIHN0YXRpb25hcnkgZm9yIG91ciBleWVzLCBidXQgd2UgbmVlZCB0byBydW4gc3RhdGlzdGljYWwgdGVzdHMgdG8gZGVjaWRlIHdoZXRoZXIgdG8gdHJlYXQgdGhlIHNlcmllcyBzdGF0aW9uYXJ5IG9yIG5vdC4KClRoZXJlIGlzIGEgc3RhdGlzdGljYWwgd2F5IHRvIGV2YWx1YXRlIHdoZXRoZXIgdGhlc2Ugc2VyaWVzIGFyZSBzdGF0aW9uYXJ5LiBXZSBuZWVkIGEgc3RhdGlzdGljYWwgY29uZmlybWF0aW9uIGluIGFkZGl0aW9uIHRvIHRoZSB2aXN1YWwgdG9vbHMuIFRoZSBEaWNreS1GdWxsZXIgdGVzdCBpcyBvbmUgb2YgdGhlIG1vc3QgdXNlZCBzdGF0aXN0aWNhbCB0ZXN0cyBmb3Igc3RhdGlvbmFyeS4gVGhpcyB0ZXN0IGlzIGNhbGxlZCBhIHVuaXQgcm9vdCB0ZXN0LiBUaGUgRGlja3ktRnVsbGVyIHRlc3QgYXNzdW1lcyB0aGF0IHRoZSBzZXJpZXMgaXMgbm9uIHN0YXRpb25hcnkuIEluIG90aGVyIHdvcmRzLCBpdCBhc3N1bWVzIHRoYXQgdGhlIHNlcmllcyBmb2xsb3dzIGEgcmFuZG9tIHdhbGsgd2l0aCBhIHVuaXQgcm9vdCAoz5UxPTEpLgoKRElDS1ktRlVMTEVSIEFTU1VNRVMgVEhBVCBUSEUgU0VSSUVTIElTIE5PTiBTVEFUSU9OQVJZLgoKWW91IG5lZWQgdG8gaW5zdGFsbCB0aGUgcGFja2FnZSB0c2VyaWVzIHRvIGRvIHRoZSBmb2xsb3dpbmcgYW5hbHlzaXMuCgpXZSBjYW4gcnVuIHRoZSBEaWNreS1GdWxsZXIgdGVzdCBmb3IgdGhlIHNlYXNvbmFsIGRpZmZlcmVuY2Ugb2YgdGhlIHByb2R1Y3QgNiBsb2cgc2FsZXMgYXMgZm9sbG93czoKCmBgYHtyfQpsaWJyYXJ5KHRzZXJpZXMpCmFkZi50ZXN0KG5hLm9taXQoZGlmZihsbl9zYWxlcyRxYnJhbmQydG9ucywgbGFnID0gMTIpKSwgYWx0ZXJuYXRpdmUgPSAic3RhdGlvbmFyeSIpCmBgYAoKVGhlIGFkZi50ZXN0KCkgZnVuY3Rpb24gZnJvbSB0aGUgdHNlcmllcyBwYWNrYWdlIHdpbGwgZG8gYSBEaWNrZXktRnVsbGVyIHRlc3QgaWYgd2Ugc2V0IGxhZ3MgKGspIGVxdWFsIHRvIDAuIFVzZSB0aGUgZGVmYXVsdCB2YWx1ZSBvZiBrLgoKVGhlIG51bGwgaHlwb3RoZXNpcyBvZiB0aGUgRGlja3ktRnVsbGVyIHRlc3QgaXMgdGhhdCB0aGUgc2VyaWVzIGlzIG5vbi1zdGF0aW9uYXJ5LiBBY3R1YWxseSwgdGhlICpudWxsLWh5cG90aGVzaXMgb2YgdGhpcyB0ZXN0IGlzIHRoYXQgdGhlIM+VMT0xLCB3aGljaCBpbXBsaWVzIHRoYXQgdGhlIHNlcmllcyBpcyBub24tc3RhdGlvbmFyeS4gVGhpcyBpcyB0aGUgcmVhc29uIHdoeSB0aGUgRGlja3ktRnVsbGVyIHRlc3QgaXMgY2FsbGVkIGEgdW5pdC1yb290KiogdGVzdC4KCkhPID0gz5UxPTEgLT4gTk9OIFNUQVRJT05BUlkKCkFzIGFueSBzdGF0aXN0aWNhbCB0ZXN0LCBpZiB0aGUgcC12YWx1ZSBvZiB0aGUgdGVzdCBpcyBsZXNzIHRoYW4gMC4wNSwgdGhlbiB3ZSBoYXZlIHN0YXRpc3RpY2FsIGV2aWRlbmNlIChhdCB0aGUgOTUlIGNvbmZpZGVuY2UgbGV2ZWwpIHRvIFJFSkVDVCB0aGUgbnVsbC1oeXBvdGhlc2lzLgoKVGhpcyBpcyBhbm90aGVyIHdheSB0byBkbyB0aGUgc2FtZSBEaWNrZXkgRnVsbGVyIHRlc3Q6CgpgYGB7cn0KIyBJIGNyZWF0ZSBhIHZhcmlhYmxlIGZvciB0aGUgc2Vhc29uYWwgZGlmZmVyZW5jZSBvZiB0aGUgbG9nIHNhbGVzOgpzMTIubG5icmFuZDJ0b25zIDwtIG5hLm9taXQoZGlmZihsbl9zYWxlcyRxYnJhbmQydG9ucywgbGFnID0gMTIpKQojIEkgcnVuIERpY2t5LUZ1bGxlciB0ZXN0IGZvciB0aGlzIHNlYXNvbmFsIGRpZmZlcmVuY2U6CmFkZi50ZXN0KHMxMi5sbmJyYW5kMnRvbnMsIGFsdGVybmF0aXZlID0gInN0YXRpb25hcnkiKQpgYGAKClRoZSBEaWNreSBGdWxsZXIgdGVzdCByZXBvcnRzIGEgcC12YWx1ZSBsZXNzIHRoYW4gMC4wNSwgaW5kaWNhdGluZyB0aGF0IHdlIGNhbiByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyB0aGF0IHN0YXRlcyBhIHVuaXQgcm9vdCBmb3IgdGhlc2Ugc2VyaWVzICjPlTE9MSkuIEluIG90aGVyIHdvcmRzLCBzaW5jZSB0aGUgcC12YWx1ZSBpcyBsZXNzIHRoYW4gMC4wNSB3ZSBjYW4gc2F5IHRoYXQgdGhlcmUgaXMgc3RhdGlzdGljYWwgZXZpZGVuY2UgdG8gY29uY2x1ZGUgdGhhdCB0aGUgc2Vhc29uYWwgZGlmZmVyZW5jZSBvZiB0aGUgbG9nIHNlcmllcyAodGhlIGFubnVhbCAlIGNoYW5nZSkgKHMxMi5sbmJyYW5kMnRvbnMpIGlzIHN0YXRpb25hcnkuCgpUaGVuIGZvciB0aGUgdmFyaWFibGUgczEyLmxuYnJhbmQydG9ucyB3ZSBjYW4gc2F5IHRoYXQgdGhlcmUgaXMgc3RhdGlzdGljYWwgZXZpZGVuY2UgdG8gc2F5IHRoYXQgdGhlIHNlcmllcyBpcyBzdGF0aW9uYXJ5LgoKUlVOIEEgRElDS1ktRlVMTEVSIFRFU1QgRk9SIFRIRSBBTk5VQUwgJSBESUZGRVJFTkNFIE9GIEJSQU5EIDYsIEFORCBQUk9WSURFIEFOIElOVEVSUFJFVEFUSU9OCgpgYGB7cn0KCnMxMi5sbmJyYW5kNnRvbnMgPC0gbmEub21pdChkaWZmKGxuX3NhbGVzJHFicmFuZDZ0b25zLCBsYWcgPSAxMikpCmFkZi50ZXN0KHMxMi5sbmJyYW5kNnRvbnMsIGFsdGVybmF0aXZlID0gInN0YXRpb25hcnkiKQpgYGAKCkZPUiBUSEUgVkVSWSA2VEggQlJBTkQsIFdFIE1BWSBJTlRFUlBSRVQgVEhBVCBUSEVSRSBJUyBTVEFUSVNUSUNBTCBFVklERU5DRSBUTyBDT05DTFVERSBUSEFUIFRIRSBTRUFTT05BTCBESUZGRVJFTkNFIE9GIFRIRSBBTk5VQUwgJSBDSEFOR0UgKHMxMi5sbmJyYW5kNnRvbnMpIElTIE5PTiBTVEFUSU9OQVJZLiBJTiBUSElTIENBU0UsIFRIRSBESUNLWSBGVUxMRVIgVEVTVCBSRVBPUlRTIEEgUC1WQUxVRSBISUdIRVIgVEhBTiAwLjA1LCBJTkRJQ0FUSU5HIFVTIFRIQVQgV0UgQ0FOIEFDQ0VQVCBUSEUgTlVMTCBIWVBPVEhFU0lTIFRIQVQgU1RBVEVTIEhPID0gz5UxPTEgLT4gTk9OIFNUQVRJT05BUlkuCgoKRm9yIHRoZSBjYXNlIG9mIG1vbnRobHkgdGltZXMgc2VyaWVzIHZhcmlhYmxlcyBsaWtlIHNhbGVzIG9mIHByb2R1Y3RzIG9yIHNhbGVzIG9mIGEgY29tcGFueSwgSSBzdHJvbmdseSByZWNvbW1lbmQgdG8gd29yayB3aXRoIHRoZSBzZWFzb25hbCBkaWZmZXJlbmNlIG9mIHRoZSBsb2cgb2Ygc2FsZXMgKHMxMi5sbmJyYW5kMnRvbnMpLCB3aGljaCBpcyB0aGUgYW5udWFsICUgY2hhbmdlIChpbiBjb250aW51b3VzbHkgY29tcG91bmRpbmcpIG1vbnRoIGJ5IG1vbnRoLiBUaGUgcmVhc29uIGlzIGJlY2F1c2UgbW9zdCBvZiBjb25zdW1lciBwcm9kdWN0cyBoYXZlIGEgc2Vhc29uYWwgcGF0dGVybi4gV2UgY2FuIGRvIHRoaXMgT05MWSBpZiB0aGUgc2Vhc29uYWwgZGlmZmVyZW5jZSBvZiB0aGUgbG9nIGlzIFNUQVRJT05BUlkuCgpGb3IgdGhlc2UgMiBwcm9kdWN0cywgdGhlbiwgSSBjYW4gdXNlIHRoZSBzZWFzb25hbCBkaWZmZXJlbmNlIG9mIHRoZSBsb2cgb2Ygc2FsZXMgdG8gZGVzaWduIGEgdGltZS1zZXJpZXMgbW9kZWwuCgojI1NwdXJpb3VzIHJlZ3Jlc3Npb24KCldoZW4gd2Ugd2FudCB0byBleGFtaW5lIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0d28gbm9uLXN0YXRpb25hcnkgdmFyaWFibGVzIGJ5IHJ1bm5pbmcgYSByZWdyZXNzaW9uIG1vZGVsLCB3ZSBoYXZlIHRoZSByaXNrIHRvIGVuZCB1cCB3aXRoIGEgbm9uLXZhbGlkIC0gc3B1cmlvdXMgLSByZWdyZXNzaW9uLiBCZWZvcmUgd2UgdW5kZXJzdGFuZCB3aHkgYSByZWdyZXNzaW9uIG1vZGVsIGNhbiBiZSBzcHVyaW91cywgd2Ugc3RhcnQgd2l0aCBhbmQgZXhhbXBsZSB1c2luZyAyIHJlYWwtd29ybGQgdmFyaWFibGVzLgoKSW5zdGFsbCB0aGUgd2JzdGF0cyBwYWNrYWdlIHVzaW5nIFJTdHVkaW8uIFRoaXMgcGFja2FnZSB3YXMgd3JpdHRlbiBieSB0aGUgV29ybGQgQmFuaywgYW5kIGl0IGhhcyBmdW5jdGlvbnMgdG8gZG93bmxvYWQgZGF0YSBvZiBhbGwgY291bnRyaWVzIGFyb3VuZCB0aGUgd29ybGQuIFRoZSBmdW5jdGlvbiB3YiBkb3dubG9hZHMgaHVuZHJlZHMgb2YgdGltZS1zZXJpZXMgdmFyaWFibGVzIHRoYXQgdGhlIFdvcmxkIEJhbmsgdHJhY2tzIGZvciBhbGwgY291bnRyaWVzLiBJZiB5b3Ugd2FudCB0byBrbm93IG1vcmUgYWJvdXQgdGhpcyBwYWNrYWdlLCB5b3UgY2FuIGNoZWNrIGl0cyBkb2N1bWVudGF0aW9uIGluIHRoZSBjcmFuIHdlYiBzaXRlIChodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvd2JzdGF0cy93YnN0YXRzLnBkZikKCldlIHdpbGwgZG93bmxvYWQgdGhlIGluZmFudCBtb3J0YWxpdHkgcmF0ZSBhbmQgdGhlIGV4cG9ydHMgZm9yIE1leGljby4gSXQgaXMgc3VwcG9zZWQgdGhhdCB0aGVzZSB2YXJpYWJsZXMgaGF2ZSBub3RoaW5nIGluIGNvbW1vbiwgc28gd2Ugd291bGQgbm90IGV4cGVjdCBhIHNpZ25pZmljYW50IHJlbGF0aW9uc2hpcC4KCmBgYHtyfQpsaWJyYXJ5KHdic3RhdHMpCgojIE1leGljbyAtIEluZmFudCBtb3J0YWxpdHkKaW5mYW50bTwtd2JfZGF0YShpbmRpY2F0b3IgPSBjKCJTUC5EWU4uSU1SVC5JTiIpLCAKICAgICAgY291bnRyeT0iTUVYIiwgc3RhcnRfZGF0ZSA9IDE5ODAsIGVuZF9kYXRlID0gMjAyMCkKCiMgTWV4aWNvIC0gRXhwb3J0IHZhbHVlCmV4cG9ydHM8LXdiX2RhdGEoaW5kaWNhdG9yID0gYygiVFguVkFMLk1SQ0guWEQuV0QiKSwgCiAgICAgIGNvdW50cnk9Ik1FWCIsIHN0YXJ0X2RhdGUgPSAxOTgwLCBlbmRfZGF0ZSA9IDIwMjApCmBgYAoKVGhlIHdiIGZ1bmN0aW9uIGJyaW5ncyBhIGRhdGEgZnJhbWUgd2l0aCB0aGUgcmVxdWVzdGVkIGRhdGEuIFdlIGNhbiBwbG90IHRoZSBkYXRhIHRvIGhhdmUgYW4gaWRlYSBvZiB0aGVzZSAyIHZhcmlhYmxlczoKCmBgYHtyfQpwbG90LnRzKGluZmFudG0kU1AuRFlOLklNUlQuSU4pCmBgYApgYGB7cn0KcGxvdC50cyhleHBvcnRzJFRYLlZBTC5NUkNILlhELldEKQpgYGAKCk5vdyBydW4gYSByZWdyZXNzaW9uIHVzaW5nIHRoZXNlIHNlcmllcy4gUmVwb3J0IHRoZSByZXN1bHQgb2YgdGhlIHJlZ3Jlc3Npb24uIERpZCB5b3UgZmluZCBzaWduaWZpY2FudCByZWxhdGlvbnNoaXA/IGlzIHlvdXIgcmVzdWx0IHdoYXQgeW91IGV4cGVjdGVkPyAKCkNPTU8gUE9ERU1PUyBWRVIsIENMQVJBTUVOVEUgRVhJU1RFIFVOQSBSRUxBQ0nDk04gSU5WRVJTQSBFTlRSRSBMQVMgVkFSSUFCTEVTOyBNSUVOVFJBUyBRVUUgVU5BIENSRUNFLCBMQSBPVFJBIERFQ1JFQ0UuIFNJTiBFTUJBUkdPLCBFTCBIRUNITyBERSBRVUUgRVNUQVMgVkFSSUFCTEVTIEVTVMOJTiBSRUxBQ0lPTkFEQVMsIE5PIE5FQ0VTQVJJQU1FTlRFIE5PUyBJTkRJQ0EgUVVFIEVTVMOBTiBDT0VJTlRFR1JBREFTLCBZIFBBUkEgRUxMTyBFTVBMRUFSRU1PUyBFTCBESUNLRVkgRlVMTEVSIFRFU1QuCgpgYGB7cn0KbTEgPC0gbG0oZXhwb3J0cyRUWC5WQUwuTVJDSC5YRC5XRCB+IGluZmFudG0kU1AuRFlOLklNUlQuSU4pCnN1bW1hcnkobTEpCmBgYAoKUkVTRUFSQ0ggQUJPVVQgU1BVUklPVVMgUkVHUkVTU0lPTi4gV2l0aCB5b3VyIHdvcmRzIGJyaWVmbHkgZXhwbGFpbiBpbiB3aGljaCBjYXNlcyB5b3UgY2FuIGVuZCB1cCB3aXRoIGEgc3B1cmlvdXMgcmVncmVzc2lvbiAKClVOQSBSRUxBQ0nDk04gRVNQVVJJQSBIQUNFIFJFRkVSRU5DSUEgQSBMQSBBUEFSSUVOQ0lBIFFVRSBFWElTVEUgRU4gVU5BIFJFTEFDScOTTiBERSBDQVVTQUxJREFEIEVOVFJFIFZBUklBQkxFUyBDVUFORE8gRU4gUkVBTElEQUQgRVNUQSBOTyBFWElTVEUuIEVTIERFQ0lSLCBRVUUgQVVOUVVFIFBBUkVDSUVSQSBRVUUgQUxHVU5BUyBWQVJJQUJMRVMgRVNUw4FOIENPUlJFTEFDSU9OQURBUywgUkVBTE1FTlRFIE5PIEhBWSBVTkEgUkVMQUNJw5NOIENBVVNBTCBFTlRSRSBFU1RBUywgUE9SIExPIFRBTlRPIEVTIEVTUFVSSUEuIFBPUiBFSkVNUExPLCBMQVMgVkVOVEFTIERFIE5JRVZFUyBFTiBMQSBDSVVEQUQgREUgUVVFUsOJVEFSTyBZIExBUyBNVUVSVEVTIFBPUiBDT1ZJRC0xOSBFTiBFU1RBRE9TIFVOSURPUy4gQVVOUVVFIEVYSVNUSUVSQSBMQSBQT1NJQklMSURBRCBERSBERVRFUk1JTkFSIENJRVJUQSBSRUxBQ0nDk04sIEVOIENBU08gREUgUVVFIEVYSVNUQSwgU0VSw41BIEVTUFVSSUEsIFBPUlFVRSBSRUFMTUVOVEUgTk8gVElFTkVOIE5BREEgUVVFIExBIFVOQSBDT04gTEEgT1RSQS4gCgojI0NvaW50ZWdyYXRpb24KCldoZW4gdHdvIG5vbi1zdGF0aW9uYXJ5IHNlcmllcyBhcmUgc3Ryb25nbHkgcmVsYXRlZCBpbiB0aGUgbG9uZyBydW4sIHRoZW4gd2Ugc2F5IHRoYXQgYm90aCBzZXJpZXMgYXJlIGNvaW50ZWdyYXRlZC4gVGhlIHF1ZXN0aW9uIGlzIGhvdyBzdHJvbmcgdGhpcyBsb25nLXRlcm0gcmVsYXRpb25zaGlwIG5lZWRzIHRvIGJlIGluIG9yZGVyIHRvIGNvbnNpZGVyIDIgbm9uLXN0YXRpb25hcnkgc2VyaWVzIGFzIGNvaW50ZWdyYXRlZC4KClRvIGRvIGEgY29pbnRlZ3JhdGlvbiBzdGF0aXN0aWNhbCB0ZXN0IG9mIDIgbm9uLXN0YXRpb25hcnkgc2VyaWVzLCB3ZSBuZWVkIHRvIGRvIHRoZSBmb2xsb3dpbmc6CgogICAxLiBSdW4gYSBsaW5lYXIgcmVncmVzc2lvbiBvZiB0aGUgMiBub24tc3RhdGlvbmFyeSBzZXJpZXMKCiAgIDIuIEdldCB0aGUgcmVzaWR1YWxzIG9mIHRoaXMgcmVncmVzc2lvbgoKICAgMy4gRG8gYSBEaWNreS1GdWxsZXIgdGVzdCB0byBjaGVjayB3aGV0aGVyIHRoaXMgcmVncmVzc2lvbiByZXNpZHVhbHMgKGVycm9ycykgaXMgYSBzdGF0aW9uYXJ5IHNlcmllcy4gSWYgdGhlIHAtdmFsdWU8MC4wNSwgdGhlbiB3ZSBjYW4gc2F5IHRoYXQgdGhlcmUgaXMgc3RhdGlzdGljYWwgZXZpZGVuY2UgdG8gY29uc2lkZXIgYm90aCBub24tc3RhdGlvbmFyeSBzZXJpZXMgYXMgY29pbnRlZ3JhdGVkLgoKSWYgMiBub24tc3RhdGlvbmFyeSBzZXJpZXMgYXJlIE5PVCBjb2ludGVncmF0ZWQsIHRoZW4gaXRzIGxpbmVhciByZWdyZXNzaW9uIGJlY29tZXMgYSBzcHVyaW91cyByZWdyZXNzaW9uLiBJbiBvdGhlciB3b3Jkcywgd2hlbiAyIG5vbi1zdGF0aW9uYXJ5IHNlcmllcyBhcmUgbm90IGNvaW50ZWdyYXRlZCwgdGhlIHJlc3VsdCBvZiBhIGxpbmVhciByZWdyZXNzaW9uIHVzaW5nIHRoZXNlIDIgdmFyaWFibGVzIHdpbGwgbm90IGJlIHJlbGlhYmxlIG9yIHZhbGlkLgoKQXJlIHRoZSBpbmZhbnQgbW9ydGFsaXR5IGFuZCBleHBvcnQgc2VyaWVzIGNvaW50ZWdyYXRlZD8gSXMgdGhlIHJlZ3Jlc3Npb24gc3B1cmlvdXMgb3IgdmFsaWQ/IFJ1biBhbmQgaW50ZXJwcmV0IHRoZSBjb3JyZXNwb25kaW5nIHRlc3QKCkhlcmUgaXMgYSBjb2RlIHRvIGhlbHAgeW91IHJlc3BvbmQgdGhpcyBxdWVzdGlvbi4KCmBgYHtyfQpsaWJyYXJ5KHRzZXJpZXMpCiMgVGhlIGVycm9ycy9yZXNpZHVhbCBvZiB0aGUgcmVncmVzc2lvbiBhcmUgc3RvcmVkIGluIHRoZSByZXNpZHVhbHMKIyAgIGF0dHJpYnV0ZSBvZiB0aGUgbTEgbW9kZWw6CmFkZi50ZXN0KG0xJHJlc2lkdWFscywgayA9IDApCmBgYAoKVHJhcyBoYWJlciBlbXBsZWFkbyBlbCBEaWNrZXktRnVsbGVyIHRlc3QsIHBvZGVtb3MgZGV0ZXJtaW5hciBxdWUgbGEgcmVsYWNpw7NuIGVudHJlIGxhIG1vcnRhbGlkYWQgaW5mYW50aWwgeSBsYXMgZXhwb3J0YWNpb25lcyBlcyBlc3B1cmlhLiBZYSBxdWUsIGF1bnF1ZSBhY2VydGFkYW1lbnRlIHBvZGVtb3MgYXByZWNpYXIgdW5hIHJlbGFjacOzbiBpbnZlcnNhOyBubyBoYXkgc3VmaWNpZW50ZSBzb3BvcnRlIGVzdGFkw61zdGljbyBwYXJhIGRldGVybWluYXIgcXVlIGFtYmFzIHZhcmlhYmxlcyBlc3TDqW4gY29ycmVsYWNpb25hZGFzLiBTaW1wbGVtZW50ZSBlcyB1bmEgcmVsYWNpw7NuIGVzcHVyaWEuIENvbiBlbCB2YWxvciBwLCBlbiBlc3RlIGNhc28gZGUgNzMuNTElLCB0ZXJtaW5hbW9zIHBvciBjb25jbHVpciBxdWUgbGEgSG8gZXMgY29ycmVjdGEsIG1pZW50cmFzIHF1ZSBsYSBIYSBlcyByZWNoYXphZGEuIEVzIGRlY2lyLCBzaSBub3MgZmlhbW9zIGRlIGRpY2hhIHJlbGFjacOzbiBwYXJhIGVtcGxlYXIgYWxndW4gZXN0dWRpbywgZXhpc3RlIHVuIDczLjUxJSBkZSBlcXVpdm9jYWNpw7NuIGVuIG51ZXN0cm9zIGhhbGxhemdvcy4gCgojI0NvaW50ZWdyYXRpb24gYmV0d2VlbiBGaW5hbmNpYWwgc2VyaWVzCgpVc2luZyBkYWlseSBkYXRhIG9mIE1leGljbyBJUEN5QyBtYXJrZXQgaW5kZXggYW5kIHRoZSBTJlAgNTAwLCBleGFtaW5lIHdoZXRoZXIgdHdvIHNlcmllcyBhcmUgY29pbnRlZ3JhdGVkLiBHZW5lcmF0ZSBhbiBpbmRleCBmb3IgZWFjaCBpbnN0cnVtZW50LiBUbyBkbyB0aGVzZSBpbmRleGVzLCBjcmVhdGUgYSB2YXJpYWJsZSB0aGF0IHJlcHJlc2VudHMgaG93IDEuMDAgcGVzbyBvciAxLjAwIGRvbGxhciBpbnZlc3RlZCBpbiBlYWNoIGluc3RydW1lbnQgd291bGQgYmUgY2hhbmdpbmcgb3ZlciB0aW1lLgoKICAgMS4gRnJvbSBKYW4gMSwgMjAxNSB0byBPY3QgMiwgMjAxNy4KICAgMi4gRnJvbSBPY3QgMywgMjAxNyB0byBGZWIgMjgsIDIwMTgKCkZvciBib3RoIGNhc2VzLCBydW4gYSBjb2ludGVncmF0aW9uIHRlc3QgYW5kIElOVEVSUFJFVCB5b3VyIHJlc3VsdHMuCgpgYGB7cn0Kcm0obGlzdD1scygpKQpvcHRpb25zKHNjaXBlbj05OTkpCgpsaWJyYXJ5KHF1YW50bW9kKQoKZ2V0U3ltYm9scyhTeW1ib2xzPSBjKCJeTVhYIiwgIl5HU1BDIiksIGZyb209IjIwMTUtMDEtMDEiLCB0bz0gIjIwMTctMTAtMDIiLCAKICAgICAgICAgICBwZXJpb2RpY2l0eSA9ICJkYWlseSIsIHNyYyA9ICJ5YWhvbyIpCgpwcmljZXMgPSBBZChtZXJnZShNWFgsR1NQQykpCnByaWNlcyA9IG5hLm9taXQocHJpY2VzKQoKTVhYMSA9IGFzLm51bWVyaWMoTVhYJE1YWC5BZGp1c3RlZFsxXSkKR1NQQzEgPSBhcy5udW1lcmljKEdTUEMkR1NQQy5BZGp1c3RlZFsxXSkKCk9ORU1YUCA9IHByaWNlcyRNWFguQWRqdXN0ZWQgLyBNWFgxCk9ORVVTRCA9IHByaWNlcyRHU1BDLkFkanVzdGVkIC8gR1NQQzEKCnBsb3QoT05FTVhQJE1YWC5BZGp1c3RlZCkKcGxvdChPTkVVU0QkR1NQQy5BZGp1c3RlZCkKCm0zIDwtIGxtKE9ORU1YUCRNWFguQWRqdXN0ZWQgfiBPTkVVU0QkR1NQQy5BZGp1c3RlZCkKc3VtbWFyeShtMykKCmxpYnJhcnkodHNlcmllcykKYWRmLnRlc3QobTMkcmVzaWR1YWxzLCBrID0gMCkKYGBgCgpFUyBCSUVOIFNBQklETyBRVUUgTEEgRUNPTk9Nw41BIE1FWElDQU5BIERFUEVOREUgREUgTEEgRUNPTk9Nw41BIEVTVEFET1VOSURFTlNFIEVOIEdSQU4gUE9SQ0VOVEFKRTsgTk8gT0JTVEFOVEUsIENPTiBFTCBGSU4gREUgREVURVJNSU5BUiBRVUUgRElDSEEgQ09SUkVMQUNJw5NOIE5PIFNFQSBFU1BVUklBLCBERUNJRElNT1MgQ09SUkVSIEVMIERJQ0tFWS1GVUxMRVIgVEVTVCBZIExPR1JBTU9TIERFVEVSTUlOQVIgUVVFIEVGRUNUSVZBTUVOVEUgQU1CT1Mgw41ORElDRVMgRVNUw4FOIENPSU5URUdSQURPUywgQVPDjSBDT01PIExBIEVYSVNURU5URSBDT1JSRUxBQ0nDk04gRU5UUkUgRVNUQVMgVkFSSUFCTEVTLiBDT04gVU4gVkFMT1IgUCBERSAzLjUlLCBUQU1CScOJTiBDT01QUk9CQU1PUyBFU1RBRMONU1RJQ0FNRU5URSBRVUUgQU1CQVMgU0VSSUVTIFNPTiBOTyBFU1RBQ0lPTkFSSUFTIFkgVU5BIFZFWiBNw4FTLCBRVUUgRVNUw4FOIENPSU5URUdSQURBUyBMQVMgVkFSSUFCTEVTLiAKCmBgYHtyfQpybShsaXN0PWxzKCkpCm9wdGlvbnMoc2NpcGVuPTk5OSkKCmxpYnJhcnkocXVhbnRtb2QpCgpnZXRTeW1ib2xzKFN5bWJvbHM9IGMoIl5NWFgiLCAiXkdTUEMiKSwgZnJvbT0iMjAxNy0xMC0wMyIsIHRvPSAiMjAxOC0wMi0yOCIsIAogICAgICAgICAgIHBlcmlvZGljaXR5ID0gImRhaWx5Iiwgc3JjID0gInlhaG9vIikKCnByaWNlczIgPSBBZChtZXJnZShNWFgsR1NQQykpCnByaWNlczIgPSBuYS5vbWl0KHByaWNlczIpCgpNWFgyID0gYXMubnVtZXJpYyhNWFgkTVhYLkFkanVzdGVkWzFdKQpHU1BDMiA9IGFzLm51bWVyaWMoR1NQQyRHU1BDLkFkanVzdGVkWzFdKQoKT05FTVhQMiA9IHByaWNlczIkTVhYLkFkanVzdGVkIC8gTVhYMgpPTkVVU0QyID0gcHJpY2VzMiRHU1BDLkFkanVzdGVkIC8gR1NQQzIKCnBsb3QoT05FTVhQMiRNWFguQWRqdXN0ZWQpCnBsb3QoT05FVVNEMiRHU1BDLkFkanVzdGVkKQoKbTQgPC0gbG0oT05FTVhQMiRNWFguQWRqdXN0ZWQgfiBPTkVVU0QyJEdTUEMuQWRqdXN0ZWQpCnN1bW1hcnkobTQpCgpsaWJyYXJ5KHRzZXJpZXMpCmFkZi50ZXN0KG00JHJlc2lkdWFscywgayA9IDApCmBgYAoKRU4gRVNURSBTRUdVTkRPIFBFUklPRE8gREUgVElFTVBPLCBDVVJJT1NBTUVOVEUgT0JURU5FTU9TIERJU1RJTlRPUyBSRVNVTFRBRE9TLiBMQSBSRUdSRVNJw5NOIExJTkVBTCBFU1TDgSBDTEFSQSwgU0kgRVhJU1RFIFVOQSBSRUxBQ0nDk04gUE9TSVRJVkEgRU5UUkUgQU1CQVMgVkFSSUFCTEVTIFkgRUwgVkFMT1IgUCAoREUgTEEgUkVHUkVTScOTTiBMSU5FQUwpIE5PUyBSRUNUSUZJQ0EgQ09OIENFUlRFWkEgU1UgQUxUQSBSRUxBQ0nDk04uIE5PIE9CU1RBTlRFLCBUUkFTIEhBQkVSIENPUlJJRE8gRUwgRElDS0VZIEZVTExFUiBURVNULCBQT0RFTU9TIE9CU0VSVkFSIEPDk01PIEVTVEUgVkFMT1IgU1VQRVJBIFBPUiBNVUNITyBFTCA1JTsgSU5ESUNBTkRPTk9TIFFVRSBOTyBFWElTVEUgQ09JTlRFR1JBQ0nDk04gRU5UUkUgTEFTIFZBUklBQkxFUyBZIFFVRSBBTUJBUyBTRVJJRVMgU09OIEVTVEFDSU9OQVJJQVMuIAoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCg==