Workshop 7, Financial Econometrics II

Abstract

In this workshop we introduce the concept of cointegration of time-series variables.

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 - spuious - 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?

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.842 -41.039  -4.786  39.072  73.624 

Coefficients:
                       Estimate Std. Error t value Pr(>|t|)    
(Intercept)            280.3572    15.5425   18.04  < 2e-16 ***
infantm$SP.DYN.IMRT.IN  -6.3166     0.5205  -12.13 8.14e-15 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 41.48 on 39 degrees of freedom
Multiple R-squared:  0.7906,    Adjusted R-squared:  0.7852 
F-statistic: 147.3 on 1 and 39 DF,  p-value: 8.139e-15
hist(infantm$SP.DYN.IMRT.IN)

hist(exports$TX.VAL.MRCH.XD.WD)

cor(infantm$SP.DYN.IMRT.IN, exports$TX.VAL.MRCH.XD.WD)
[1] -0.889162
cor.test(infantm$SP.DYN.IMRT.IN, exports$TX.VAL.MRCH.XD.WD)

    Pearson's product-moment correlation

data:  infantm$SP.DYN.IMRT.IN and exports$TX.VAL.MRCH.XD.WD
t = -12.135, df = 39, p-value = 8.139e-15
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.9397443 -0.8004851
sample estimates:
      cor 
-0.889162 
scatter.smooth(infantm$SP.DYN.IMRT.IN, exports$TX.VAL.MRCH.XD.WD)

AFTER A QUICK TEST WE CAN SEE THAT THERE IS A STRONG CORRELATION BETWEEN THE TWO VARIABLES. ACCORDING TO THE RESULTS FROM THE MODEL, THERE IS A NEGATIVELY AND SIGNIFCANT RELATIONSHIP, AND I THINK THIS IS ACCURATE SINCE THE HIGHER THE EXPORTS THE LOWER THE IMPACT ON CHILD MORTALITY, ALTHOUGH IMPORTS MIGHT BE OTHER STORY.

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.842 -41.039  -4.786  39.072  73.624 

Coefficients:
                       Estimate Std. Error t value Pr(>|t|)    
(Intercept)            280.3572    15.5425   18.04  < 2e-16 ***
infantm$SP.DYN.IMRT.IN  -6.3166     0.5205  -12.13 8.14e-15 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 41.48 on 39 degrees of freedom
Multiple R-squared:  0.7906,    Adjusted R-squared:  0.7852 
F-statistic: 147.3 on 1 and 39 DF,  p-value: 8.139e-15

Research about spurious regression, and explain in which cases you can end up with a spurious regression

RESEARCH BROUGHT TO ME THE REALIZATION THAT I FOUND A WORD FOR SOMETHING I’VE SOMETIMES ENCOUNTERED. A SPURIOUS RELATIONSHIP IS A MATHEMATICAL RELATION IN WHICH TWO OR MORE VARIABLES ARE ASSOCIATED BUT NOT REALLY RELATED, AND THIS CAN BE DUE TO COINICIDENCE OR AN UNSEEN FACTOR.

Are the series cointegrated? Is the regression spurious or valid? Run the corresponding test

library(tseries)
adf.test(m1$residuals, k = 0)

    Augmented Dickey-Fuller Test

data:  m1$residuals
Dickey-Fuller = -2.1794, Lag order = 0, p-value = 0.503
alternative hypothesis: stationary

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.

Cointegration From Jan 1, 2015 to Oct 2, 2017

library(quantmod)
Loading required package: xts
Loading required package: zoo

Attaching package: ‘zoo’

The following objects are masked from ‘package:base’:

    as.Date, as.Date.numeric

Loading required package: TTR
library(tseries)
getSymbols(Symbols<-c("^MXX", "^GSPC"), periodicity= "daily", from = "2015-01-01", to = "2017-10-02")
‘getSymbols’ currently uses auto.assign=TRUE by default, but will
use auto.assign=FALSE in 0.5-0. You will still be able to use
‘loadSymbols’ to automatically load data. getOption("getSymbols.env")
and getOption("getSymbols.auto.assign") will still be checked for
alternate defaults.

This message is shown once per session and may be disabled by setting 
options("getSymbols.warning4.0"=FALSE). See ?getSymbols for details.
[1] "^MXX"  "^GSPC"
data = na.omit(merge (MXX, GSPC))
firstmxx = as.numeric(MXX$MXX.Adjusted[1])
firstusa = as.numeric(GSPC$GSPC.Adjusted[1])
invmxx <- data$MXX.Adjusted / firstmxx
invusa <- data$GSPC.Adjusted / firstusa
plot(invmxx)

plot(invusa)

m1 <- lm(invmxx$MXX.Adjusted ~ invusa$GSPC.Adjusted)
summary(m1)

Call:
lm(formula = invmxx$MXX.Adjusted ~ invusa$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   <2e-16 ***
invusa$GSPC.Adjusted  0.69852    0.01311   53.29   <2e-16 ***
---
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: < 2.2e-16
adf.test(m1$residuals, k=0)

    Augmented Dickey-Fuller Test

data:  m1$residuals
Dickey-Fuller = -3.5752, Lag order = 0, p-value =
0.03508
alternative hypothesis: stationary

BASED OFF THE P VALUE, WE CAN TELL THAT THE RESIDUALS ARE FROM AS TATIONARY VARIABLE, AND THUS BOTH INDEXES ARE COINTEGRATED. ALSO, BASED OFF THE COEFICCIENTS, WE CAN TELL THAT FOR EACH PESO EARNED IN THE US MARKET, THERE IS A PROFIT OF 70 CENTS.

Cointegration From Oct 3, 2017 to Feb 28, 2018

getSymbols(Symbols<-c("^MXX", "^GSPC"), periodicity= "daily", from = "2017-10-03", to = "2018-02-28")
[1] "^MXX"  "^GSPC"
data_1 = na.omit(merge (MXX, GSPC))
firstmxx_1 = as.numeric(MXX$MXX.Adjusted[1])
firstusa_1 = as.numeric(GSPC$GSPC.Adjusted[1])
# When I divided a price with its original price I assigned 1.00 peso 
invmxx_1 <- data_1$MXX.Adjusted / firstmxx_1
invusa_1 <- data_1$GSPC.Adjusted / firstusa_1
plot(invmxx_1)

plot(invusa_1)

m2 <- lm(invmxx_1$MXX.Adjusted ~ invusa_1$GSPC.Adjusted)
summary(m2)

Call:
lm(formula = invmxx_1$MXX.Adjusted ~ invusa_1$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  < 2e-16 ***
invusa_1$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
adf.test(m2$residuals, k=0)

    Augmented Dickey-Fuller Test

data:  m2$residuals
Dickey-Fuller = -2.0418, Lag order = 0, p-value = 0.5592
alternative hypothesis: stationary

THESE SERIES ARE NOT COINTEGRATED, AND WE CAN TELL THAT THE ANALYSIS CAME DOWN AS SPURIOUS.

Holding return of a portfolio of 2 stocks

Once we have an idea about cointegration, we will review how to form a portfolio of 2 assets and calculate its holding return over time. The holding period return of an asset from day 1 to day N (HPR) can be calculated with any of the following ways:

HPR = (Price of the stock at day N / Price of the stock at day 1) - 1

HPR = exp ( Sum of all continuous compounded returns from day 1 to day N) - 1

The expected return of a portfolio of 2 assets is estimated as a weighted average of the expected stock returns:

E[Rp]=w1∗E[R1]+w2∗E(R2)

The holding return of a portfolio of 2 assets for a specific period of time is estimated as a weighted average of the holding returns of the assets:

HPRp=w1∗HPR1+w2∗HPR2

Download daily prices from CEMEX and ALFA from Jan 1, 2015 to Dec 31, 2017.

Calculate their holding period returns of both stocks

Create a portfolio 1 assigning 30% to CEMEX and 70% for ALFA and calculate the HPR of the portfolio

Create a portfolio 2 assigning -100% to CEMEX and +200% to ALFA and calcuate the HPR of this portfolio

getSymbols(Symbols<-c("CEMEXCPO.MX", "ALFAA.MX"), periodicity= "daily", from = "2015-01-01", to = "2017-12-01")
[1] "CEMEXCPO.MX" "ALFAA.MX"   

First I calculate the daily continously compunded return

CEMEXCPO.MX$stockreturn <- log(CEMEXCPO.MX$CEMEXCPO.MX.Adjusted / (lag(CEMEXCPO.MX$CEMEXCPO.MX.Adjusted,1)))
ALFAA.MX$stockreturn <- log(ALFAA.MX$ALFAA.MX.Adjusted / (lag(ALFAA.MX$ALFAA.MX.Adjusted,1)))
n <- (nrow(CEMEXCPO.MX))
price0 <- as.numeric(CEMEXCPO.MX$CEMEXCPO.MX.Adjusted[1])
pricen <- as.numeric(CEMEXCPO.MX$CEMEXCPO.MX.Adjusted[n])
HPRCEMEX <- ((pricen /price0)-1)*100
print(paste("HPR of CEMEX = ", HPRCEMEX))
[1] "HPR of CEMEX =  9.26812986347962"
n_1 <- (nrow(ALFAA.MX))
price0_1 <- as.numeric(ALFAA.MX$ALFAA.MX.Adjusted[1])
pricen_1 <- as.numeric(ALFAA.MX$ALFAA.MX.Adjusted[n])
HPRALFAA <- ((pricen_1 /price0_1)-1 )*100
print(paste("HPR of ALFAA = ", HPRALFAA))
[1] "HPR of ALFAA =  -34.9480141260153"
p1 <- HPRCEMEX*0.3 + HPRALFAA*0.7 
print(paste("HPR of portfolio 1 ", p1))
[1] "HPR of portfolio 1  -21.6831709291668"
p2 <- HPRCEMEX*-1 + HPRALFAA*2
print(paste("HPR of portfolio 2 ", p2))
[1] "HPR of portfolio 2  -79.1641581155102"

What does a negative sign mean a portfolio? Briefly explain with the previous example.

THIS NEGATIVE SIGN SHOWS THAT ON ONE HAND WE ARE SHORT SELLING A STOCK TO GAIN LEVERAGE AND PURCHASE MORE STOCKS FROM A DIFFERENT INSTRUMENT.

CHALLENGE: Statistical arbitrage

Using the CEMEX and the ALFAA daily price series from Jan 1, 2015 to Dec 31, 2017, examine whether these two series are cointegrated. Assume you are in December 31, 2017. If the series are cointegrated that means that the residual of the regression between these series is a stationary series. Then, if this is the case, what can you do to take advantage in financial trading? FROM MY POV, BASED ON THE COINTEGRATION WE CAN ONLY ASSUME THAT IF THE RESIDUALS COMMING FROM A MODEL SHOW AN INCREASE THEN THE DEPENDENT VARIABLE WILL SKYROCKET AND THE INDEPENDENT VARIABLE WILL TANK. IF THE RESIDUALS SHOW A DECREASE THEN WE CAN INFER THAT THE INDEPENDENT VARIABLE WIL SKYROCKET AND THE DEPENDENT VARIABLE WILL TANK.

If you were to invest from Jan 1, 2018 to Feb 28, 2018 in a portfolio of these stocks, which weights would you assign? I WOULD INVEST HEAVILY INTO ALFAA AND SHORT MY POSITION OF CEMEX.

This is called statistical arbitrage, and some technical analysts use this technique to find arbitrage opportunities (be careful, this is not a safe strategy to follow)

dataset<- merge(ALFAA.MX$ALFAA.MX.Adjusted, CEMEXCPO.MX$CEMEXCPO.MX.Adjusted)
reg1 <- lm( dataset$ALFAA.MX.Adjusted  ~ dataset$CEMEXCPO.MX.Adjusted)
summary(reg1)

Call:
lm(formula = dataset$ALFAA.MX.Adjusted ~ dataset$CEMEXCPO.MX.Adjusted)

Residuals:
    Min      1Q  Median      3Q     Max 
-8.6538 -1.0994  0.4569  1.6883  5.3340 

Coefficients:
                             Estimate Std. Error t value
(Intercept)                  42.77131    0.47469   90.10
dataset$CEMEXCPO.MX.Adjusted -1.02755    0.03503  -29.33
                             Pr(>|t|)    
(Intercept)                    <2e-16 ***
dataset$CEMEXCPO.MX.Adjusted   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 2.55 on 733 degrees of freedom
Multiple R-squared:   0.54, Adjusted R-squared:  0.5393 
F-statistic: 860.4 on 1 and 733 DF,  p-value: < 2.2e-16
adf.test(reg1$residuals, k=0)

    Augmented Dickey-Fuller Test

data:  reg1$residuals
Dickey-Fuller = -3.8521, Lag order = 0, p-value =
0.01639
alternative hypothesis: stationary
rm(list = ls())
getSymbols(("CEMEXCPO.MX"), periodicity= "daily", from = "2018-01-01", to = "2018-02-28")
[1] "CEMEXCPO.MX"
getSymbols(("ALFAA.MX"), periodicity= "daily", from = "2018-01-01", to = "2018-02-28")
[1] "ALFAA.MX"
n <- (nrow(CEMEXCPO.MX))
price0 <- as.numeric(CEMEXCPO.MX$CEMEXCPO.MX.Adjusted[1])
pricen <- as.numeric(CEMEXCPO.MX$CEMEXCPO.MX.Adjusted[n])
HPRCEMEX <- ((pricen /price0)-1)*100
print(paste("HPR of CEMEX = ", HPRCEMEX))
[1] "HPR of CEMEX =  -15.7929645407336"
n_1 <- (nrow(ALFAA.MX))
price0_1 <- as.numeric(ALFAA.MX$ALFAA.MX.Adjusted[1])
pricen_1 <- as.numeric(ALFAA.MX$ALFAA.MX.Adjusted[n])
HPRALFAA <- ((pricen_1 /price0_1)-1 )*100
print(paste("HPR of ALFAA = ", HPRALFAA))
[1] "HPR of ALFAA =  1.18957542276574"

Calculate the HPR of your portfolio from Jan 1st to Feb 28, 2018.

PSTEFAN <- HPRALFAA*2+ HPRCEMEX*-1
print(paste("HPR of my portfolio = ", PSTEFAN))
[1] "HPR of my portfolio =  18.1721153862651"
LS0tCnRpdGxlOiAiV29ya3Nob3AgNywgRmluYW5jaWFsIEVjb25vbWV0cmljcyAyIgphdXRob3I6IFN0ZWZhbiBTY2h3ZWl0emVyLCBBMDEyMDk3NTUKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQojIyBXb3Jrc2hvcCA3LCBGaW5hbmNpYWwgRWNvbm9tZXRyaWNzIElJCgojIEFic3RyYWN0CkluIHRoaXMgd29ya3Nob3Agd2UgaW50cm9kdWNlIHRoZSBjb25jZXB0IG9mIGNvaW50ZWdyYXRpb24gb2YgdGltZS1zZXJpZXMgdmFyaWFibGVzLgoKIyMgU3B1cmlvdXMgcmVncmVzc2lvbgoKV2hlbiB3ZSB3YW50IHRvIGV4YW1pbmUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHR3byBub24tc3RhdGlvbmFyeSB2YXJpYWJsZXMgYnkgcnVubmluZyBhIHJlZ3Jlc3Npb24gbW9kZWwsIHdlIGhhdmUgdGhlIHJpc2sgdG8gZW5kIHVwIHdpdGggYSBub24tdmFsaWQgLSBzcHVpb3VzIC0gcmVncmVzc2lvbi4gQmVmb3JlIHdlIHVuZGVyc3RhbmQgd2h5IGEgcmVncmVzc2lvbiBtb2RlbCBjYW4gYmUgc3B1cmlvdXMsIHdlIHN0YXJ0IHdpdGggYW5kIGV4YW1wbGUgdXNpbmcgMiByZWFsLXdvcmxkIHZhcmlhYmxlcy4KCkluc3RhbGwgdGhlIHdic3RhdHMgcGFja2FnZSB1c2luZyBSU3R1ZGlvLiBUaGlzIHBhY2thZ2Ugd2FzIHdyaXR0ZW4gYnkgdGhlIFdvcmxkIEJhbmssIGFuZCBpdCBoYXMgZnVuY3Rpb25zIHRvIGRvd25sb2FkIGRhdGEgb2YgYWxsIGNvdW50cmllcyBhcm91bmQgdGhlIHdvcmxkLiBUaGUgZnVuY3Rpb24gd2IgZG93bmxvYWRzIGh1bmRyZWRzIG9mIHRpbWUtc2VyaWVzIHZhcmlhYmxlcyB0aGF0IHRoZSBXb3JsZCBCYW5rIHRyYWNrcyBmb3IgYWxsIGNvdW50cmllcy4gSWYgeW91IHdhbnQgdG8ga25vdyBtb3JlIGFib3V0IHRoaXMgcGFja2FnZSwgeW91IGNhbiBjaGVjayBpdHMgZG9jdW1lbnRhdGlvbiBpbiB0aGUgY3JhbiB3ZWIgc2l0ZSAoaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3dic3RhdHMvd2JzdGF0cy5wZGYpCgpXZSB3aWxsIGRvd25sb2FkIHRoZSBpbmZhbnQgbW9ydGFsaXR5IHJhdGUgYW5kIHRoZSBleHBvcnRzIGZvciBNZXhpY28uIEl0IGlzIHN1cHBvc2VkIHRoYXQgdGhlc2UgdmFyaWFibGVzIGhhdmUgbm90aGluZyBpbiBjb21tb24sIHNvIHdlIHdvdWxkIG5vdCBleHBlY3QgYSBzaWduaWZpY2FudCByZWxhdGlvbnNoaXAuCgpgYGB7cn0KbGlicmFyeSh3YnN0YXRzKQpgYGAKCmBgYHtyfQojIE1leGljbyAtIEluZmFudCBtb3J0YWxpdHkKaW5mYW50bTwtd2JfZGF0YShpbmRpY2F0b3IgPSBjKCJTUC5EWU4uSU1SVC5JTiIpLCAKICAgICAgY291bnRyeT0iTUVYIiwgc3RhcnRfZGF0ZSA9IDE5ODAsIGVuZF9kYXRlID0gMjAyMCkKIyBNZXhpY28gLSBFeHBvcnQgdmFsdWUKZXhwb3J0czwtd2JfZGF0YShpbmRpY2F0b3IgPSBjKCJUWC5WQUwuTVJDSC5YRC5XRCIpLCAKICAgICAgY291bnRyeT0iTUVYIiwgc3RhcnRfZGF0ZSA9IDE5ODAsIGVuZF9kYXRlID0gMjAyMCkKYGBgCgpUaGUgd2IgZnVuY3Rpb24gYnJpbmdzIGEgZGF0YSBmcmFtZSB3aXRoIHRoZSByZXF1ZXN0ZWQgZGF0YS4gV2UgY2FuIHBsb3QgdGhlIGRhdGEgdG8gaGF2ZSBhbiBpZGVhIG9mIHRoZXNlIDIgdmFyaWFibGVzOgoKYGBge3J9CnBsb3QudHMoaW5mYW50bSRTUC5EWU4uSU1SVC5JTikKYGBgCgpgYGB7cn0KcGxvdC50cyhleHBvcnRzJFRYLlZBTC5NUkNILlhELldEKQpgYGAKTm93IHJ1biBhIHJlZ3Jlc3Npb24gdXNpbmcgdGhlc2Ugc2VyaWVzLiBSZXBvcnQgdGhlIHJlc3VsdCBvZiB0aGUgcmVncmVzc2lvbi4gRGlkIHlvdSBmaW5kIHNpZ25pZmljYW50IHJlbGF0aW9uc2hpcD8gaXMgeW91ciByZXN1bHQgd2hhdCB5b3UgZXhwZWN0ZWQ/CgpgYGB7cn0KbTEgPC0gbG0oZXhwb3J0cyRUWC5WQUwuTVJDSC5YRC5XRCB+IGluZmFudG0kU1AuRFlOLklNUlQuSU4pCgpzdW1tYXJ5KG0xKQpgYGAKCmBgYHtyfQpoaXN0KGluZmFudG0kU1AuRFlOLklNUlQuSU4pCmBgYAoKCmBgYHtyfQpoaXN0KGV4cG9ydHMkVFguVkFMLk1SQ0guWEQuV0QpCmBgYAoKYGBge3J9CmNvcihpbmZhbnRtJFNQLkRZTi5JTVJULklOLCBleHBvcnRzJFRYLlZBTC5NUkNILlhELldEKQpgYGAKYGBge3J9CmNvci50ZXN0KGluZmFudG0kU1AuRFlOLklNUlQuSU4sIGV4cG9ydHMkVFguVkFMLk1SQ0guWEQuV0QpCmBgYApgYGB7cn0Kc2NhdHRlci5zbW9vdGgoaW5mYW50bSRTUC5EWU4uSU1SVC5JTiwgZXhwb3J0cyRUWC5WQUwuTVJDSC5YRC5XRCkKYGBgCgpBRlRFUiBBIFFVSUNLIFRFU1QgV0UgQ0FOIFNFRSBUSEFUIFRIRVJFIElTIEEgU1RST05HIENPUlJFTEFUSU9OIEJFVFdFRU4gVEhFIFRXTyBWQVJJQUJMRVMuIEFDQ09SRElORyBUTyBUSEUgUkVTVUxUUyBGUk9NIFRIRSBNT0RFTCwgVEhFUkUgSVMgQSBORUdBVElWRUxZIEFORCBTSUdOSUZDQU5UIFJFTEFUSU9OU0hJUCwgQU5EIEkgVEhJTksgVEhJUyBJUyBBQ0NVUkFURSBTSU5DRSBUSEUgSElHSEVSIFRIRSBFWFBPUlRTIFRIRSBMT1dFUiBUSEUgSU1QQUNUIE9OIENISUxEIE1PUlRBTElUWSwgQUxUSE9VR0ggSU1QT1JUUyBNSUdIVCBCRSBPVEhFUiBTVE9SWS4KCmBgYHtyfQptMSA8LSBsbShleHBvcnRzJFRYLlZBTC5NUkNILlhELldEIH4gaW5mYW50bSRTUC5EWU4uSU1SVC5JTikKc3VtbWFyeShtMSkKYGBgCgpSZXNlYXJjaCBhYm91dCBzcHVyaW91cyByZWdyZXNzaW9uLCBhbmQgZXhwbGFpbiBpbiB3aGljaCBjYXNlcyB5b3UgY2FuIGVuZCB1cCB3aXRoIGEgc3B1cmlvdXMgcmVncmVzc2lvbgoKUkVTRUFSQ0ggQlJPVUdIVCBUTyBNRSBUSEUgUkVBTElaQVRJT04gVEhBVCBJIEZPVU5EIEEgV09SRCBGT1IgU09NRVRISU5HIEknVkUgU09NRVRJTUVTIEVOQ09VTlRFUkVELiBBIFNQVVJJT1VTIFJFTEFUSU9OU0hJUCBJUyBBIE1BVEhFTUFUSUNBTCBSRUxBVElPTiBJTiBXSElDSCBUV08gT1IgTU9SRSBWQVJJQUJMRVMgQVJFIEFTU09DSUFURUQgQlVUIE5PVCBSRUFMTFkgUkVMQVRFRCwgQU5EIFRISVMgQ0FOIEJFIERVRSBUTyBDT0lOSUNJREVOQ0UgT1IgQU4gVU5TRUVOIEZBQ1RPUi4KCkFyZSB0aGUgc2VyaWVzIGNvaW50ZWdyYXRlZD8gSXMgdGhlIHJlZ3Jlc3Npb24gc3B1cmlvdXMgb3IgdmFsaWQ/IFJ1biB0aGUgY29ycmVzcG9uZGluZyB0ZXN0CgpgYGB7cn0KbGlicmFyeSh0c2VyaWVzKQpgYGAKCmBgYHtyfQphZGYudGVzdChtMSRyZXNpZHVhbHMsIGsgPSAwKQpgYGAKCiMjIENvaW50ZWdyYXRpb24gYmV0d2VlbiBGaW5hbmNpYWwgc2VyaWVzCgpVc2luZyBkYWlseSBkYXRhIG9mIE1leGljbyBJUEN5QyBtYXJrZXQgaW5kZXggYW5kIHRoZSBTJlAgNTAwLCBleGFtaW5lIHdoZXRoZXIgdHdvIHNlcmllcyBhcmUgY29pbnRlZ3JhdGVkLiBHZW5lcmF0ZSBhbiBpbmRleCBmb3IgZWFjaCBpbnN0cnVtZW50LiBUbyBkbyB0aGVzZSBpbmRleGVzLCBjcmVhdGUgYSB2YXJpYWJsZSB0aGF0IHJlcHJlc2VudHMgaG93IDEuMDAgcGVzbyBvciAxLjAwIGRvbGxhciBpbnZlc3RlZCBpbiBlYWNoIGluc3RydW1lbnQgd291bGQgYmUgY2hhbmdpbmcgb3ZlciB0aW1lLgoKRnJvbSBKYW4gMSwgMjAxNSB0byBPY3QgMiwgMjAxNy4KCkZyb20gT2N0IDMsIDIwMTcgdG8gRmViIDI4LCAyMDE4CgpGb3IgYm90aCBjYXNlcywgcnVuIGEgY29pbnRlZ3JhdGlvbiB0ZXN0IGFuZCBJTlRFUlBSRVQgeW91ciByZXN1bHRzLgoKIyBDb2ludGVncmF0aW9uIEZyb20gSmFuIDEsIDIwMTUgdG8gT2N0IDIsIDIwMTcKCmBgYHtyfQpsaWJyYXJ5KHF1YW50bW9kKQpgYGAKYGBge3J9CmxpYnJhcnkodHNlcmllcykKZ2V0U3ltYm9scyhTeW1ib2xzPC1jKCJeTVhYIiwgIl5HU1BDIiksIHBlcmlvZGljaXR5PSAiZGFpbHkiLCBmcm9tID0gIjIwMTUtMDEtMDEiLCB0byA9ICIyMDE3LTEwLTAyIikKYGBgCgpgYGB7cn0KZGF0YSA9IG5hLm9taXQobWVyZ2UgKE1YWCwgR1NQQykpCmBgYAoKYGBge3J9CmZpcnN0bXh4ID0gYXMubnVtZXJpYyhNWFgkTVhYLkFkanVzdGVkWzFdKQpmaXJzdHVzYSA9IGFzLm51bWVyaWMoR1NQQyRHU1BDLkFkanVzdGVkWzFdKQpgYGAKCmBgYHtyfQppbnZteHggPC0gZGF0YSRNWFguQWRqdXN0ZWQgLyBmaXJzdG14eAppbnZ1c2EgPC0gZGF0YSRHU1BDLkFkanVzdGVkIC8gZmlyc3R1c2EKYGBgCgpgYGB7cn0KcGxvdChpbnZteHgpCmBgYAoKYGBge3J9CnBsb3QoaW52dXNhKQpgYGAKCmBgYHtyfQptMSA8LSBsbShpbnZteHgkTVhYLkFkanVzdGVkIH4gaW52dXNhJEdTUEMuQWRqdXN0ZWQpCnN1bW1hcnkobTEpCmBgYAoKYGBge3J9CmFkZi50ZXN0KG0xJHJlc2lkdWFscywgaz0wKQpgYGAKCkJBU0VEIE9GRiBUSEUgUCBWQUxVRSwgV0UgQ0FOIFRFTEwgVEhBVCBUSEUgUkVTSURVQUxTIEFSRSBGUk9NIEFTIFRBVElPTkFSWSBWQVJJQUJMRSwgQU5EIFRIVVMgQk9USCBJTkRFWEVTIEFSRSBDT0lOVEVHUkFURUQuCkFMU08sIEJBU0VEIE9GRiBUSEUgQ09FRklDQ0lFTlRTLCBXRSBDQU4gVEVMTCBUSEFUIEZPUiBFQUNIIFBFU08gRUFSTkVEIElOIFRIRSBVUyBNQVJLRVQsIFRIRVJFIElTIEEgUFJPRklUIE9GIDcwIENFTlRTLiAKCiMgQ29pbnRlZ3JhdGlvbiBGcm9tIE9jdCAzLCAyMDE3IHRvIEZlYiAyOCwgMjAxOAoKYGBge3J9CmdldFN5bWJvbHMoU3ltYm9sczwtYygiXk1YWCIsICJeR1NQQyIpLCBwZXJpb2RpY2l0eT0gImRhaWx5IiwgZnJvbSA9ICIyMDE3LTEwLTAzIiwgdG8gPSAiMjAxOC0wMi0yOCIpCmBgYApgYGB7cn0KZGF0YV8xID0gbmEub21pdChtZXJnZSAoTVhYLCBHU1BDKSkKYGBgCgpgYGB7cn0KZmlyc3RteHhfMSA9IGFzLm51bWVyaWMoTVhYJE1YWC5BZGp1c3RlZFsxXSkKZmlyc3R1c2FfMSA9IGFzLm51bWVyaWMoR1NQQyRHU1BDLkFkanVzdGVkWzFdKQojIFdoZW4gSSBkaXZpZGVkIGEgcHJpY2Ugd2l0aCBpdHMgb3JpZ2luYWwgcHJpY2UgSSBhc3NpZ25lZCAxLjAwIHBlc28gCmludm14eF8xIDwtIGRhdGFfMSRNWFguQWRqdXN0ZWQgLyBmaXJzdG14eF8xCmludnVzYV8xIDwtIGRhdGFfMSRHU1BDLkFkanVzdGVkIC8gZmlyc3R1c2FfMQpgYGAKCmBgYHtyfQpwbG90KGludm14eF8xKQpgYGAKYGBge3J9CnBsb3QoaW52dXNhXzEpCmBgYAoKYGBge3J9Cm0yIDwtIGxtKGludm14eF8xJE1YWC5BZGp1c3RlZCB+IGludnVzYV8xJEdTUEMuQWRqdXN0ZWQpCnN1bW1hcnkobTIpCmBgYAoKYGBge3J9CmFkZi50ZXN0KG0yJHJlc2lkdWFscywgaz0wKQpgYGAKVEhFU0UgU0VSSUVTIEFSRSBOT1QgQ09JTlRFR1JBVEVELCBBTkQgV0UgQ0FOIFRFTEwgVEhBVCBUSEUgQU5BTFlTSVMgQ0FNRSBET1dOIEFTIFNQVVJJT1VTLgoKIyMgSG9sZGluZyByZXR1cm4gb2YgYSBwb3J0Zm9saW8gb2YgMiBzdG9ja3MKCk9uY2Ugd2UgaGF2ZSBhbiBpZGVhIGFib3V0IGNvaW50ZWdyYXRpb24sIHdlIHdpbGwgcmV2aWV3IGhvdyB0byBmb3JtIGEgcG9ydGZvbGlvIG9mIDIgYXNzZXRzIGFuZCBjYWxjdWxhdGUgaXRzIGhvbGRpbmcgcmV0dXJuIG92ZXIgdGltZS4gVGhlIGhvbGRpbmcgcGVyaW9kIHJldHVybiBvZiBhbiBhc3NldCBmcm9tIGRheSAxIHRvIGRheSBOIChIUFIpIGNhbiBiZSBjYWxjdWxhdGVkIHdpdGggYW55IG9mIHRoZSBmb2xsb3dpbmcgd2F5czoKCkhQUiA9IChQcmljZSBvZiB0aGUgc3RvY2sgYXQgZGF5IE4gLyBQcmljZSBvZiB0aGUgc3RvY2sgYXQgZGF5IDEpIC0gMQoKSFBSID0gZXhwICggU3VtIG9mIGFsbCBjb250aW51b3VzIGNvbXBvdW5kZWQgcmV0dXJucyBmcm9tIGRheSAxIHRvIGRheSBOKSAtIDEKClRoZSBleHBlY3RlZCByZXR1cm4gb2YgYSBwb3J0Zm9saW8gb2YgMiBhc3NldHMgaXMgZXN0aW1hdGVkIGFzIGEgd2VpZ2h0ZWQgYXZlcmFnZSBvZiB0aGUgZXhwZWN0ZWQgc3RvY2sgcmV0dXJuczoKCkVbUnBdPXcx4oiXRVtSMV0rdzLiiJdFKFIyKQoKVGhlIGhvbGRpbmcgcmV0dXJuIG9mIGEgcG9ydGZvbGlvIG9mIDIgYXNzZXRzIGZvciBhIHNwZWNpZmljIHBlcmlvZCBvZiB0aW1lIGlzIGVzdGltYXRlZCBhcyBhIHdlaWdodGVkIGF2ZXJhZ2Ugb2YgdGhlIGhvbGRpbmcgcmV0dXJucyBvZiB0aGUgYXNzZXRzOgoKSFBScD13MeKIl0hQUjErdzLiiJdIUFIyCgpEb3dubG9hZCBkYWlseSBwcmljZXMgZnJvbSBDRU1FWCBhbmQgQUxGQSBmcm9tIEphbiAxLCAyMDE1IHRvIERlYyAzMSwgMjAxNy4KCkNhbGN1bGF0ZSB0aGVpciBob2xkaW5nIHBlcmlvZCByZXR1cm5zIG9mIGJvdGggc3RvY2tzCgpDcmVhdGUgYSBwb3J0Zm9saW8gMSBhc3NpZ25pbmcgMzAlIHRvIENFTUVYIGFuZCA3MCUgZm9yIEFMRkEgYW5kIGNhbGN1bGF0ZSB0aGUgSFBSIG9mIHRoZSBwb3J0Zm9saW8KCkNyZWF0ZSBhIHBvcnRmb2xpbyAyIGFzc2lnbmluZyAtMTAwJSB0byBDRU1FWCBhbmQgKzIwMCUgdG8gQUxGQSBhbmQgY2FsY3VhdGUgdGhlIEhQUiBvZiB0aGlzIHBvcnRmb2xpbwoKCmBgYHtyfQpnZXRTeW1ib2xzKFN5bWJvbHM8LWMoIkNFTUVYQ1BPLk1YIiwgIkFMRkFBLk1YIiksIHBlcmlvZGljaXR5PSAiZGFpbHkiLCBmcm9tID0gIjIwMTUtMDEtMDEiLCB0byA9ICIyMDE3LTEyLTAxIikKYGBgCgpGaXJzdCBJIGNhbGN1bGF0ZSB0aGUgZGFpbHkgY29udGlub3VzbHkgY29tcHVuZGVkIHJldHVybgoKYGBge3J9CkNFTUVYQ1BPLk1YJHN0b2NrcmV0dXJuIDwtIGxvZyhDRU1FWENQTy5NWCRDRU1FWENQTy5NWC5BZGp1c3RlZCAvIChsYWcoQ0VNRVhDUE8uTVgkQ0VNRVhDUE8uTVguQWRqdXN0ZWQsMSkpKQpBTEZBQS5NWCRzdG9ja3JldHVybiA8LSBsb2coQUxGQUEuTVgkQUxGQUEuTVguQWRqdXN0ZWQgLyAobGFnKEFMRkFBLk1YJEFMRkFBLk1YLkFkanVzdGVkLDEpKSkKYGBgCgpgYGB7cn0KbiA8LSAobnJvdyhDRU1FWENQTy5NWCkpCnByaWNlMCA8LSBhcy5udW1lcmljKENFTUVYQ1BPLk1YJENFTUVYQ1BPLk1YLkFkanVzdGVkWzFdKQpwcmljZW4gPC0gYXMubnVtZXJpYyhDRU1FWENQTy5NWCRDRU1FWENQTy5NWC5BZGp1c3RlZFtuXSkKSFBSQ0VNRVggPC0gKChwcmljZW4gL3ByaWNlMCktMSkqMTAwCnByaW50KHBhc3RlKCJIUFIgb2YgQ0VNRVggPSAiLCBIUFJDRU1FWCkpCmBgYApgYGB7cn0Kbl8xIDwtIChucm93KEFMRkFBLk1YKSkKcHJpY2UwXzEgPC0gYXMubnVtZXJpYyhBTEZBQS5NWCRBTEZBQS5NWC5BZGp1c3RlZFsxXSkKcHJpY2VuXzEgPC0gYXMubnVtZXJpYyhBTEZBQS5NWCRBTEZBQS5NWC5BZGp1c3RlZFtuXSkKSFBSQUxGQUEgPC0gKChwcmljZW5fMSAvcHJpY2UwXzEpLTEgKSoxMDAKcHJpbnQocGFzdGUoIkhQUiBvZiBBTEZBQSA9ICIsIEhQUkFMRkFBKSkKYGBgCmBgYHtyfQpwMSA8LSBIUFJDRU1FWCowLjMgKyBIUFJBTEZBQSowLjcgCnByaW50KHBhc3RlKCJIUFIgb2YgcG9ydGZvbGlvIDEgIiwgcDEpKQpgYGAKYGBge3J9CnAyIDwtIEhQUkNFTUVYKi0xICsgSFBSQUxGQUEqMgpwcmludChwYXN0ZSgiSFBSIG9mIHBvcnRmb2xpbyAyICIsIHAyKSkKYGBgCldoYXQgZG9lcyBhIG5lZ2F0aXZlIHNpZ24gbWVhbiBhIHBvcnRmb2xpbz8gQnJpZWZseSBleHBsYWluIHdpdGggdGhlIHByZXZpb3VzIGV4YW1wbGUuCgpUSElTIE5FR0FUSVZFIFNJR04gU0hPV1MgVEhBVCBPTiBPTkUgSEFORCBXRSBBUkUgU0hPUlQgU0VMTElORyBBIFNUT0NLIFRPIEdBSU4gTEVWRVJBR0UgQU5EIFBVUkNIQVNFIE1PUkUgU1RPQ0tTIEZST00gQSBESUZGRVJFTlQgSU5TVFJVTUVOVC4KCgojIyBDSEFMTEVOR0U6IFN0YXRpc3RpY2FsIGFyYml0cmFnZQoKVXNpbmcgdGhlIENFTUVYIGFuZCB0aGUgQUxGQUEgZGFpbHkgcHJpY2Ugc2VyaWVzIGZyb20gSmFuIDEsIDIwMTUgdG8gRGVjIDMxLCAyMDE3LCBleGFtaW5lIHdoZXRoZXIgdGhlc2UgdHdvIHNlcmllcyBhcmUgY29pbnRlZ3JhdGVkLiBBc3N1bWUgeW91IGFyZSBpbiBEZWNlbWJlciAzMSwgMjAxNy4gSWYgdGhlIHNlcmllcyBhcmUgY29pbnRlZ3JhdGVkIHRoYXQgbWVhbnMgdGhhdCB0aGUgcmVzaWR1YWwgb2YgdGhlIHJlZ3Jlc3Npb24gYmV0d2VlbiB0aGVzZSBzZXJpZXMgaXMgYSBzdGF0aW9uYXJ5IHNlcmllcy4gVGhlbiwgaWYgdGhpcyBpcyB0aGUgY2FzZSwgd2hhdCBjYW4geW91IGRvIHRvIHRha2UgYWR2YW50YWdlIGluIGZpbmFuY2lhbCB0cmFkaW5nPyBGUk9NIE1ZIFBPViwgQkFTRUQgT04gVEhFIENPSU5URUdSQVRJT04gV0UgQ0FOIE9OTFkgQVNTVU1FIFRIQVQgSUYgVEhFIFJFU0lEVUFMUyBDT01NSU5HIEZST00gQSBNT0RFTCBTSE9XIEFOIElOQ1JFQVNFIFRIRU4gVEhFIERFUEVOREVOVCBWQVJJQUJMRSBXSUxMIFNLWVJPQ0tFVCBBTkQgVEhFIElOREVQRU5ERU5UIFZBUklBQkxFIFdJTEwgVEFOSy4gSUYgVEhFIFJFU0lEVUFMUyBTSE9XIEEgREVDUkVBU0UgVEhFTiBXRSBDQU4gSU5GRVIgVEhBVCBUSEUgSU5ERVBFTkRFTlQgVkFSSUFCTEUgV0lMIFNLWVJPQ0tFVCBBTkQgVEhFIERFUEVOREVOVCBWQVJJQUJMRSBXSUxMIFRBTksuCgpJZiB5b3Ugd2VyZSB0byBpbnZlc3QgZnJvbSBKYW4gMSwgMjAxOCB0byBGZWIgMjgsIDIwMTggaW4gYSBwb3J0Zm9saW8gb2YgdGhlc2Ugc3RvY2tzLCB3aGljaCB3ZWlnaHRzIHdvdWxkIHlvdSBhc3NpZ24/CkkgV09VTEQgSU5WRVNUIEhFQVZJTFkgSU5UTyBBTEZBQSBBTkQgU0hPUlQgTVkgUE9TSVRJT04gT0YgQ0VNRVguCgoKVGhpcyBpcyBjYWxsZWQgc3RhdGlzdGljYWwgYXJiaXRyYWdlLCBhbmQgc29tZSB0ZWNobmljYWwgYW5hbHlzdHMgdXNlIHRoaXMgdGVjaG5pcXVlIHRvIGZpbmQgYXJiaXRyYWdlIG9wcG9ydHVuaXRpZXMgKGJlIGNhcmVmdWwsIHRoaXMgaXMgbm90IGEgc2FmZSBzdHJhdGVneSB0byBmb2xsb3cpCgpgYGB7cn0KZGF0YXNldDwtIG1lcmdlKEFMRkFBLk1YJEFMRkFBLk1YLkFkanVzdGVkLCBDRU1FWENQTy5NWCRDRU1FWENQTy5NWC5BZGp1c3RlZCkKcmVnMSA8LSBsbSggZGF0YXNldCRBTEZBQS5NWC5BZGp1c3RlZCAgfiBkYXRhc2V0JENFTUVYQ1BPLk1YLkFkanVzdGVkKQpzdW1tYXJ5KHJlZzEpCmBgYAoKYGBge3J9CmFkZi50ZXN0KHJlZzEkcmVzaWR1YWxzLCBrPTApCmBgYAoKYGBge3J9CnJtKGxpc3QgPSBscygpKQpnZXRTeW1ib2xzKCgiQ0VNRVhDUE8uTVgiKSwgcGVyaW9kaWNpdHk9ICJkYWlseSIsIGZyb20gPSAiMjAxOC0wMS0wMSIsIHRvID0gIjIwMTgtMDItMjgiKQpgYGAKYGBge3J9CmdldFN5bWJvbHMoKCJBTEZBQS5NWCIpLCBwZXJpb2RpY2l0eT0gImRhaWx5IiwgZnJvbSA9ICIyMDE4LTAxLTAxIiwgdG8gPSAiMjAxOC0wMi0yOCIpCmBgYApgYGB7cn0KbiA8LSAobnJvdyhDRU1FWENQTy5NWCkpCnByaWNlMCA8LSBhcy5udW1lcmljKENFTUVYQ1BPLk1YJENFTUVYQ1BPLk1YLkFkanVzdGVkWzFdKQpwcmljZW4gPC0gYXMubnVtZXJpYyhDRU1FWENQTy5NWCRDRU1FWENQTy5NWC5BZGp1c3RlZFtuXSkKSFBSQ0VNRVggPC0gKChwcmljZW4gL3ByaWNlMCktMSkqMTAwCnByaW50KHBhc3RlKCJIUFIgb2YgQ0VNRVggPSAiLCBIUFJDRU1FWCkpCmBgYApgYGB7cn0Kbl8xIDwtIChucm93KEFMRkFBLk1YKSkKcHJpY2UwXzEgPC0gYXMubnVtZXJpYyhBTEZBQS5NWCRBTEZBQS5NWC5BZGp1c3RlZFsxXSkKcHJpY2VuXzEgPC0gYXMubnVtZXJpYyhBTEZBQS5NWCRBTEZBQS5NWC5BZGp1c3RlZFtuXSkKSFBSQUxGQUEgPC0gKChwcmljZW5fMSAvcHJpY2UwXzEpLTEgKSoxMDAKcHJpbnQocGFzdGUoIkhQUiBvZiBBTEZBQSA9ICIsIEhQUkFMRkFBKSkKYGBgCgpDYWxjdWxhdGUgdGhlIEhQUiBvZiB5b3VyIHBvcnRmb2xpbyBmcm9tIEphbiAxc3QgdG8gRmViIDI4LCAyMDE4LgoKYGBge3J9ClBTVEVGQU4gPC0gSFBSQUxGQUEqMisgSFBSQ0VNRVgqLTEKcHJpbnQocGFzdGUoIkhQUiBvZiBteSBwb3J0Zm9saW8gPSAiLCBQU1RFRkFOKSkKYGBgCgo=