Purpose of this notebook

The main purpose of this notebook is to learn how to get started in R and apply some basic commands like vectors, data importation, loops, if statements, and of course linear regression.

While this notebook is beginner friendly, it does require some basic understanding of how the OLS regression algorithm works.

Theory

Gross fixed capital formation (GFCF) includes spending on land improvements (fences, ditches, drains, and so on); plant, machinery, and equipment purchases; the construction of roads, railways, private residential dwellings, and commercial and industrial buildings.

Foreign direct investment (FDI) is an investment from a party in one country into a business or corporation in another country with the intention of establishing a lasting interest.

Data Importation

The Data was taken from the website “Perspective Monde”. Instead of downloading it as a CSV file and then importing it and extract vectors, they provide it in a ready format for R and Python as vectors and Data frames for convenience, which is what we did here:

Date_FDI=c(1970:2019)


# Vectors ( This writing is ignored while running the command because it's considered a comment )

FDI=c( 20000000, 23100000, 13000000, 5490000, -20400000, 5020000, 38014962.74, 7994056.273,
      11759988.24, 7437548.637, 89416222.59, 58581335.99, 79528177.1, 46123623.5, 46989196.56, 
      19975166.86, 549182.4961, 59574900.78, 84661627.57, 167056032.1, 165122977.8, 317462140.6,
      422470462.5, 491466064.6, 550924373.9, 334768272.9, 357393801.8, 1079341332, 308712164.4,
      826974026.9, 426553283.9, 2824557252, 480355698, 2312829823, 893325392.8, 1670609689, 
      2460787164, 2825801376, 2466288357, 1970323920, 1240625859, 2521362081, 2841954371, 
      3360909924, 3525384612, 3252913902, 2153363905, 2680109856, 3544387229, 1599761098)

Date_GFCF=c(1960:2018)

GFCF=c( 199877917.2, 229133346.5, 250410018.8, 306056694, 296850449.6, 313012548.2, 336528030.8, 
       415769192.8, 433356367.9,479596877.8, 590455488.6, 647326732.7, 690532081.4, 845163018.3, 
       1128655774, 2229981493, 2755187473, 3530966180, 3295653635, 3815239414, 5675430575, 
       5550459177, 5462138469, 4509216318, 3747639748, 3779465368, 4569944203, 
       4839690401, 5786813414, 7065573384, 7781959744, 8054243608, 8362423940, 8088129003, 
       8392956449, 9350603852, 9414815900, 8909512890, 10128138832, 10930128728, 10480934331, 
       10202074980, 11120357844, 13498857067,16273601240, 17759604422, 20021964801, 
       25416061424, 31838380450, 29413188368, 28576723851, 31926847056, 32032590051, 
       32894652311, 32860711609, 28703644911, 31025847566, 31424989682, 33556322647)

length=c(length(Date_FDI),length(FDI),length(Date_GFCF),length(GFCF))
print(length)
## [1] 50 50 59 59

If you want to import the data as an excel or csv file, use the following commands :

# For csv files
data = read.csv2("filename.csv")

# For Excel files, we have to install the 'readxl' package and then read it.
install.packages("readxl")
library(readxl)
data = read_excel("filename.xlsx", sheet="name")

# Extract vectors from csv file
vector = data$column_name

Data Cleaning

Note that the FDI has 50 observations starting from 1970 to 2019. The GFCF has 59 observations starting from 1960 to 2018. We will remove the first 10 observation from the GFCF as well as the last one from the FDI the last one so that the two vectors become equal in length:

GFCF_2 = GFCF[-(1:10)]
FDI_2 = FDI[-length(FDI)]
length_2=c(length(GFCF_2),length(FDI_2))
print(length_2)
## [1] 49 49

Now that the vectors are equal, we can bind them in a dataframe and visualize its head as follows:

data=data.frame(Year=c(1970:2018),GFCF_2,FDI_2)
print(head(data,2))
##   Year    GFCF_2    FDI_2
## 1 1970 590455489 20000000
## 2 1971 647326733 23100000
print(tail(data,2))
##    Year      GFCF_2      FDI_2
## 48 2017 31424989682 2680109856
## 49 2018 33556322647 3544387229

Data visualisation & Descriptive statistics

# Histograms

hist(GFCF_2,col='cornflowerblue')
hist(FDI_2,col='cornflowerblue')

# Line charts using the 'ggplot' library
library(ggplot2)
ggplot(data, aes(x=c(1970:2018), y=GFCF_2)) + geom_line(color="blue") + theme_bw()
ggplot(data, aes(x=c(1970:2018), y=FDI_2)) + geom_line(color="blue") + theme_bw()

The cat function allows you to print text next to actual commands, which is what we did to print descriptive statistics.

cat(cat('GFCF:'),cat(' min=',min(GFCF_2)),
     cat(' median=',median(GFCF_2)),
     cat(' max=',max(GFCF_2)),
     cat(' mean=',mean(GFCF_2)),
     cat(' standard_deviation=',sd(GFCF_2)))
## GFCF: min= 590455489 median= 8392956449 max= 33556322647 mean= 12835832651 standard_deviation= 11187944083
cat(cat('FDI:'),cat(' min=',min(FDI_2)),
     cat(' median=',median(FDI_2)),
     cat(' max=',max(FDI_2)),
     cat(' mean=',mean(FDI_2)),
     cat(' standard_deviation=',sd(FDI_2)))
## FDI: min= -20400000 median= 357393802 max= 3544387229 mean= 1001447986 standard_deviation= 1207213984
# Correlation
cat('Correlation between GFCF & FDI:', cor(FDI_2,GFCF_2))
## Correlation between GFCF & FDI: 0.9049102

Stationarity

The reason why I chose to work on Time series and not Cross sectional Data is because there is a strong chance that you will use R for Time series analysis if you’re reading this article.

There are tens of R libraries that are especially made for time series analysis. For now we will use the tseries library.

GFCF_3 = diff(GFCF_2,4)
tseries::adf.test(GFCF_3)
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo
## 
##  Augmented Dickey-Fuller Test
## 
## data:  GFCF_3
## Dickey-Fuller = -3.6347, Lag order = 3, p-value = 0.04113
## alternative hypothesis: stationary
FDI_3 = diff(FDI_2,1)
tseries::adf.test(FDI_3)
## Warning in tseries::adf.test(FDI_3): p-value smaller than printed p-value
## 
##  Augmented Dickey-Fuller Test
## 
## data:  FDI_3
## Dickey-Fuller = -7.1171, Lag order = 3, p-value = 0.01
## alternative hypothesis: stationary

The p-value is less than 5% for both the GFCF and the FDI after 4 and 1 differentiations (integreations) respectively.

Since the FDI vector has 3 more observations than the GFCF, we need to remove the first three values so they become equal in length while maintaining the same Date index.

FDI_3 = FDI_3[-(1:3)]
data_new = data.frame("Year"=c(1974:2018),"GFCF"=GFCF_3,"FDI"=FDI_3)
ggplot(data_new,aes(x=Year, y=GFCF)) + geom_line(color="blue") + theme_bw()
ggplot(data_new,aes(x=Year, y=FDI)) + geom_line(color="blue") + theme_bw()

Using the ggplot package requires binding the vectors in dataframes ( data_new ). You can see through the line charts that the series have become stationary. We can proceed to the OLS method.

Parameters Estimation and Prediction

We will now create a function that returns the value of these two functions:

  • Intercept : \(f(x,y)=\bar{Y}-\frac{Cov(X,Y)}{V(X)}\bar{X}\)
  • Slope : \(f(x,y)=\frac{Cov(X,Y)}{V(X)}\)

First we call the function function(X,Y){}, and then stock variables inside it using the X and Y variables you put as arguments. The return command is specific to the function command, it returns the values of the stocked variables.

GFCF_par=function(X,Y){ 
    Intercept=mean(Y)-(cov(X,Y)/var(X))*mean(X);Slope=(cov(X,Y)/var(X));
    return(cat(cat('Intercept:',Intercept),cat('   Slope:',Slope)))}
GFCF_par(FDI_3,GFCF_3)
## Intercept: 2706828303   Slope: 0.03674983

The below code is to create the Prediction vector \(\hat{Y}\) based on the calculated OLS parameters. Note that we will be referring to the intercept as \(\alpha\) and the slope as \(\beta\).

  • \(\hat{Y}=\hat{\alpha} + \hat{\beta}{X}\)
GFCF_hat=function(X,Y){ 
    Yhat=mean(Y)-(cov(X,Y)/var(X))*mean(X)+(cov(X,Y)/var(X))*X;
    return(Yhat)}

# show first 4 values
print(head(GFCF_hat(FDI_3,GFCF_3),4))
## [1] 2705876850 2707762483 2708040862 2705725040

The Sum of Squares

ESS

  • Estimated Sum of Squares = \(\sum{(\bar{Y}-{\hat{Y}_i})^2}\)

Loops are by far my favorite feature in programming in general, I use them all the time because they facilitate calculations and are so efficient.

There are three ways to create loops in R, that is for, while and repeat loops. We will break down the code below to explain how they work :

  • for loop:
    First we need to initialize a variable to stock the sums, let’s call it h. Inside the for loop, we set a list of indexes from 1 until the length of the Y vector, we call these indexes using the letter i in the loop. The h variable starts at 0, the first value it will take is \(g[1]+0\), the second value is \(g[2]+g[1]\), the third value is \(g[3]+g[2]\), and so on until we reach the last index.

  • while loop:
    The while loop is slightly different. You set a condition for the index i, in this case we calculate the sums as long as the index is less than the length of Y while(i<=length(Y)), and we set \(i=i+1\) to change the index after each iteration.

  • repeat loop:
    The repeat loop is kind of a combination of both the for and while loops. we repeat the sum operation like in the for loop, while maintaining the index up to iteration as in the while loop. What is specific for the repeat loop is that we have to set a condition where the loop would break, which is if the value of the index become higher than the length of the vector, stop the iterations if(i>length(Y)){break}}

# Using for loop
ESS=function(X,Y){g=((mean(Y)-(cov(X,Y)/var(X))*mean(X))+((cov(X,Y)/var(X))*X)-mean(Y))^2;
                  h=0;
                  for ( i in 1:length(Y)){h=g[i]+h};
                  return(cat('ESS=',h))}
ESS(FDI_3,GFCF_3)
## ESS= 3.324419e+16
# using while loop
ESS=function(X,Y){g=((mean(Y)-(cov(X,Y)/var(X))*mean(X))+((cov(X,Y)/var(X))*X)-mean(Y))^2;
                  h=0;i=1;
                  while(i<=length(Y)){h=g[i]+h;i=i+1};
                  return(cat('   ESS=',h))}
ESS(FDI_3,GFCF_3)
##    ESS= 3.324419e+16
# using repeat loop
ESS=function(X,Y){g=((mean(Y)-(cov(X,Y)/var(X))*mean(X))+((cov(X,Y)/var(X))*X)-mean(Y))^2;
                    h=0;i=1;
                    repeat{h=g[i]+h;i=i+1;if(i>length(Y)){break}};
                  return(cat('   ESS=',h))}
ESS(FDI_3,GFCF_3)
##    ESS= 3.324419e+16

RSS

  • Residual Sum of Squares = \(\sum{({Y_i}-{\hat{Y}_i})^2}\)
# Using for loop
RSS=function(X,Y){g=(Y-((mean(Y)-(cov(X,Y)/var(X))*mean(X))+((cov(X,Y)/var(X))*X)))^2;
                   h=0;
                   for ( i in 1:length(Y)){h=g[i]+h};
                  return(cat('RSS=',h))}
RSS(FDI_3,GFCF_3)
## RSS= 6.297181e+20
# using while loop
RSS=function(X,Y){g=(Y-((mean(Y)-(cov(X,Y)/var(X))*mean(X))+((cov(X,Y)/var(X))*X)))^2;
                    h=0;i=1;
                    while(i<=length(Y)){h=g[i]+h;i=i+1};
                  return(cat('    RSS=',h))}
RSS(FDI_3,GFCF_3)
##     RSS= 6.297181e+20
# using repeat loop
RSS=function(X,Y){g=(Y-((mean(Y)-(cov(X,Y)/var(X))*mean(X))+((cov(X,Y)/var(X))*X)))^2;
                    h=0;i=1;
                    repeat{h=g[i]+h;i=i+1;if(i>length(Y)){break}};
                  return(cat('    RSS=',h))}
RSS(FDI_3,GFCF_3)
##     RSS= 6.297181e+20

TSS

  • Total Sum of Squares = \(\sum{({Y_i}-{\bar{Y}})^2}\)
# using for loop
TSS=function(X,Y){g=(Y-mean(Y))^2;
                  h=0;
                  for ( i in 1:length(Y)){h=g[i]+h};
                  return(cat('TSS=',h))}
TSS(FDI_3,GFCF_3)
## TSS= 6.297513e+20
# using while loop
TSS=function(X,Y){g=(Y-mean(Y))^2;
                  h=0;i=1;
                  while(i<=length(Y)){h=g[i]+h;i=i+1};
                  return(cat('    TSS=',h))}
TSS(FDI_3,GFCF_3)
##     TSS= 6.297513e+20
# using repeat loop
TSS=function(X,Y){g=(Y-mean(Y))^2;
                    h=0;i=1;
                    repeat{h=g[i]+h;i=i+1;if(i>length(Y)){break}};
                  return(cat('    TSS=',h))}
TSS(FDI_3,GFCF_3)
##     TSS= 6.297513e+20

Coefficient of determination

  • \(R^2=\frac{ESS}{TSS}\)

In these loops, we have stocked the value of the ESS in the \(g\) variable, and the value of the TSS in the k variable. We fixed \(h=0\) and \(z=0\) to stock the value of the iterations just like we did above, and finally we used the return function to return the fraction \(h/z\).

# using for loop
R_squared=function(X,Y){g=((mean(Y)-(cov(X,Y)/var(X))*mean(X))+((cov(X,Y)/var(X))*X)-mean(Y))^2;
                       k=(Y-mean(Y))^2;
                       h=0;z=0;
                       for ( i in 1:length(Y)){h=g[i]+h;z=k[i]+z};
                       return(cat('R_squared=',h/z))}
R_squared(FDI_3,GFCF_3)
## R_squared= 5.27894e-05
# using while loop
Rsquared=function(X,Y){g=((mean(Y)-(cov(X,Y)/var(X))*mean(X))+((cov(X,Y)/var(X))*X)-mean(Y))^2;
                         k=(Y-mean(Y))^2;
                         h=0;z=0;i=1;
                         while(i<=length(Y)){h=g[i]+h;z=k[i]+z;i=i+1};
                       return(cat('      R_squared=',h/z))}
R_squared(FDI_3,GFCF_3)
## R_squared= 5.27894e-05
# using repeat loop
Rsquared=function(X,Y){g=((mean(Y)-(cov(X,Y)/var(X))*mean(X))+((cov(X,Y)/var(X))*X)-mean(Y))^2;
                         k=(Y-mean(Y))^2;
                         h=0;z=0;i=1;
                         repeat{h=g[i]+h;z=k[i]+z;i=i+1;if(i>length(Y)){break}};
                       return(cat('      R_squared=',h/z))}
R_squared(FDI_3,GFCF_3)
## R_squared= 5.27894e-05

Variances of the model’s parameters

Error variance: \(\sigma^2=\frac{RSS}{n-k-1}\) with \(n=\) numbers of observations and \(k=\) number of independent variables.

In these loops we simply used the code of the RSS, and divided its value by the degree of freedom in the return command.

# using for loop
VarError=function(X,Y){g=(Y-((mean(Y)-(cov(X,Y)/var(X))*mean(X))+((cov(X,Y)/var(X))*X)))^2;
                       h=0;
                       for ( i in 1:length(Y)){h=g[i]+h}
                       return(cat('Variance_of_Error=',(h/(length(Y)-2))))}
VarError(FDI_3,GFCF_3)
## Variance_of_Error= 1.464461e+19
# using while loop
VarError=function(X,Y){g=(Y-((mean(Y)-(cov(X,Y)/var(X))*mean(X))+((cov(X,Y)/var(X))*X)))^2;
                       h=0;i=1;
                       while(i<=length(Y)){h=g[i]+h;i=i+1};
                       return(cat('    Variance_of_Error=',(h/(length(Y)-2))))}
VarError(FDI_3,GFCF_3)
##     Variance_of_Error= 1.464461e+19
# using repeat loop
VarError=function(X,Y){g=(Y-((mean(Y)-(cov(X,Y)/var(X))*mean(X))+((cov(X,Y)/var(X))*X)))^2;
                       h=0;i=1;
                       repeat{h=g[i]+h;i=i+1;if(i>length(Y)){break}};
                       return(cat('    Variance_of_Error=',(h/(length(Y)-2))))}
VarError(FDI_3,GFCF_3)
##     Variance_of_Error= 1.464461e+19

Intercept Variance: \(\hat{\sigma}_{\hat{\alpha}}^2 = \sigma_{\epsilon}^2[\frac{1}{n}+\frac{\bar{X}^2}{\sum{(X_i-\bar{X})}^2}]\)

We used the code for the RSS for the variance of error, then we simply returned the formula in the return command.

# using for loop
VarIntercept=function(X,Y){g=(Y-((mean(Y)-(cov(X,Y)/var(X))*mean(X))+((cov(X,Y)/var(X))*X)))^2;
                           k=(X-mean(X))^2;
                           h=0;z=0;
                           for ( i in 1:length(Y) ){h=g[i]+h;z=k[i]+z};
                           return(cat('Variance_of_Intercept=:',(h/(length(Y)-2))*((1/length(Y))
                                                                                   +(mean(X)^2/z))))}
VarIntercept(FDI_3,GFCF_3)
## Variance_of_Intercept=: 3.291151e+17
# using while loop
VarIntercept=function(X,Y){g=(Y-((mean(Y)-(cov(X,Y)/var(X))*mean(X))+((cov(X,Y)/var(X))*X)))^2;
                           k=(X-mean(X))^2;
                           h=0;z=0;i=1;
                           while(i<=length(Y)){h=g[i]+h;z=k[i]+z;i=i+1};
                           return(cat('  Variance_of_Intercept=:',(h/(length(Y)-2))*((1/length(Y))
                                                                                     +(mean(X)^2/z))))}
VarIntercept(FDI_3,GFCF_3)
##   Variance_of_Intercept=: 3.291151e+17
# using repeat loop
VarIntercept=function(X,Y){g=(Y-((mean(Y)-(cov(X,Y)/var(X))*mean(X))+((cov(X,Y)/var(X))*X)))^2;
                           k=(X-mean(X))^2;
                           h=0;z=0;i=1;
                           repeat{h=g[i]+h;z=k[i]+z;i=i+1;if(i>length(Y)){break}};
                           return(cat('  Variance_of_Intercept=:',(h/(length(Y)-2))*((1/length(Y))
                                                                                     +(mean(X)^2/z))))}
VarIntercept(FDI_3,GFCF_3)
##   Variance_of_Intercept=: 3.291151e+17

Slope variance: \(\hat{\sigma}_{\hat{\beta}}^2 = \frac{\sigma_{\epsilon}^2}{\sum{(X_i-\bar{X})}^2}\)

Same method above. we used the return command to return the value of the function.

# using for loop
VarSlope=function(X,Y){g=(Y-((mean(Y)-(cov(X,Y)/var(X))*mean(X))+((cov(X,Y)/var(X))*X)))^2;
                       k=(X-mean(X))^2;
                       h=0;z=0;
                       for( i in 1:length(Y)){h=g[i]+h;z=k[i]+z};
                       return(cat('Variance_of_Slope=',(h/(length(Y)-2)/z)))}
VarSlope(FDI_3,GFCF_3)
## Variance_of_Slope= 0.5949392
# using while loop
VarSlope=function(X,Y){g=(Y-((mean(Y)-(cov(X,Y)/var(X))*mean(X))+((cov(X,Y)/var(X))*X)))^2;
                       k=(X-mean(X))^2;
                       h=0;z=0;i=1;
                       while(i<=length(Y)){h=g[i]+h;z=k[i]+z;i=i+1};
                       return(cat('     Variance_of_Slope=',(h/(length(Y)-2)/z)))}
VarSlope(FDI_3,GFCF_3)
##      Variance_of_Slope= 0.5949392
# using repeat loop
VarSlope=function(X,Y){g=(Y-((mean(Y)-(cov(X,Y)/var(X))*mean(X))+((cov(X,Y)/var(X))*X)))^2;
                       k=(X-mean(X))^2;
                       h=0;z=0;i=1;
                       repeat{h=g[i]+h;z=k[i]+z;i=i+1;if(i>length(Y)){break}};
                       return(cat('     Variance_of_Slope=',(h/(length(Y)-2)/z)))}
VarSlope(FDI_3,GFCF_3)
##      Variance_of_Slope= 0.5949392

Hypothesis testing

Student test: \(t_{\hat{\rho}}= \mid{\frac{\hat{\rho}}{\hat{\sigma}_{\hat{\rho}}}}\mid\)

This code looks complicated but it is far from that. Let’s break it down:

  • First We stocked the values of the intercept and the slope.
  • The \(g\) variable is used to stock \((Y_i-\hat{Y_i})^2\)
  • The \(k\) variable is used to stock \((X_i-\bar{X})^2\)
  • \(h\) and \(z\) are initialized as 0. At the end of the iterations they will respectively equal \(\sum{(Y_i-\hat{Y_i})^2}\) and \(\sum{(X_i-\bar{X})^2}\).
  • SdIntercept is to calculate the standard deviation of the intercept.
  • SdSlope is to calculate the standard deviation of the slope.
  • tIntercept is the value of the student test for the intercept : \({\frac{\hat{\alpha}}{\hat{\sigma}_{\hat{\alpha}}}}\)
  • tSlope is the value of the student test for the slope : \({\frac{\hat{\beta}}{\hat{\sigma}_{\hat{\beta}}}}\)
  • Finally we will use if statements to set the conditions for the test. For example if(abs(tIntercept)>qt(1-(alpha/2),length(Y)-2)) means that if the absolute value of the intercept’s t-test is higher than the Student theoretical value calculated using the qt function, then The intercept is statistically significant.
t_test=function(X,Y,alpha){Intercept=mean(Y)-(cov(X,Y)/var(X))*mean(X);
                           Slope=cov(X,Y)/var(X);
                           g=(Y-((mean(Y)-(cov(X,Y)/var(X))*mean(X))+((cov(X,Y)/var(X))*X)))^2;
                           k=(X-mean(X))^2;
                           h=0;z=0;
                           for ( i in 1:length(Y) ){h=g[i]+h;z=k[i]+z};
                           SdIntercept=sqrt((h/(length(Y)-2))*((1/length(Y))+(mean(X)^2/z)));
                           SdSlope=sqrt(h/(length(Y)-2)/z);
                           tIntercept=Intercept/SdIntercept;
                           tSlope=Slope/SdSlope;
                           if(abs(tIntercept)>qt(1-(alpha/2),length(Y)-2))
                           {print('The intercept is statistically significant')};
                           if(abs(tIntercept)<=qt(1-(alpha/2),length(Y)-2))
                           {print('The intercept is statistically *non* significant')};
                           if(abs(tSlope)>qt(1-(alpha/2),length(Y)-2))
                           {print('The slope is statistically significant')};
                           if(abs(tSlope)<=qt(1-(alpha/2),length(Y)-2))
                           {print('The slope is statistically *non* significant')}}
t_test(FDI_3,GFCF_3,0.05)
## [1] "The intercept is statistically significant"
## [1] "The slope is statistically *non* significant"

Note that we added an alpha as an argument to the function, which is the desired level of risk-tolerance.

# risk-tolerance level = 1%
t_test(FDI_3,GFCF_3,0.01)
## [1] "The intercept is statistically significant"
## [1] "The slope is statistically *non* significant"

Fisher test: \(F = \frac{R^2}{\frac{1-R^2}{n-k-1}}\)

For the Fisher test we calculated the test value using the \(R^2\), which is also the coeffcient of correlation squared ( another easy way to calculate it ).

To get the theoretical values for the Fisher test, we use the qf function.

F_test=function(X,Y,alpha){r=cov(X,Y)/(sd(X)*sd(Y));
                           Rsquared=r^2;
                           F=Rsquared/((1-Rsquared)/(length(Y)-2));
                           if(F>qf(1-alpha,1,length(Y)-2))
                           {print('The model is globally significative')};
                           if(F<=qf(1-alpha,1,length(Y)-2))
                           {print('The model is globally *non* significative')}}
F_test(FDI_3,GFCF_3,0.05)
## [1] "The model is globally *non* significative"
# risk-tolerance level = 1%
F_test(FDI_3,GFCF_3,0.01)
## [1] "The model is globally *non* significative"

ANOVA

Bonus: ANOVA table. To create an ANOVA from scratch like we did with all the above applications, we simply just organize the functions in a dataframe as follows :

i=1:length(GFCF_3)

ANOVA=data.frame(Source=c("x1,x2,...,xn","Residual","Total"),
                 Sum_Sq=c(sum((GFCF_hat(FDI_3,GFCF_3)[i]-mean(GFCF_3))^2),
                          sum((GFCF_3[i]-GFCF_hat(FDI_3,GFCF_3)[i])^2),
                          sum((GFCF_3[i]-mean(GFCF_3))^2)),
                 df=c(2,length(GFCF_3)-3,length(GFCF_3)-1),
                 Mean_Sq=c((sum((GFCF_hat(FDI_3,GFCF_3)[i]-mean(GFCF_3))^2))/2,
                          (sum((GFCF_3[i]-GFCF_hat(FDI_3,GFCF_3)[i])^2))/(length(GFCF_3)-3),
                           (sum((GFCF_3[i]-mean(GFCF_3))^2))/(length(GFCF_3)-1)))

print(ANOVA)
##         Source       Sum_Sq df      Mean_Sq
## 1 x1,x2,...,xn 3.324419e+16  2 1.662210e+16
## 2     Residual 6.297181e+20 42 1.499329e+19
## 3        Total 6.297513e+20 44 1.431253e+19

Why is Stationarity so important !

Stationarity means that the statistical properties of a time series do not change over time. If you keep the trend or the seasonal components in the series, your model will be wrong because it will model the actual components instead of the raw values, which will generate false high accuracy and biased insights.

Below is the built-in command to perform linear regression in R. Note that in the first regression we used non-stationary data and the model seemed to perform well and has high accuracy.

In the second regression we used stationary vectors and the model turned out to be insignificant. This doesn’t mean that the theory is wrong as we only used a simple model with two variables. Advanced time series models with multiple variables can accurately explain such theories and generate interesting insights.

model = lm(GFCF_2 ~ FDI_2)
summary(model)
## 
## Call:
## lm(formula = GFCF_2 ~ FDI_2)
## 
## Residuals:
##        Min         1Q     Median         3Q        Max 
## -1.792e+10 -2.001e+09 -3.150e+08  1.980e+09  1.374e+10 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 4.437e+09  8.970e+08   4.947 1.01e-05 ***
## FDI_2       8.386e+00  5.753e-01  14.576  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 4.812e+09 on 47 degrees of freedom
## Multiple R-squared:  0.8189, Adjusted R-squared:  0.815 
## F-statistic: 212.5 on 1 and 47 DF,  p-value: < 2.2e-16
model = lm(GFCF_3 ~ FDI_3)
summary(model)
## 
## Call:
## lm(formula = GFCF_3 ~ FDI_3)
## 
## Residuals:
##        Min         1Q     Median         3Q        Max 
## -5.920e+09 -2.012e+09 -9.433e+08  5.053e+08  1.287e+10 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 2.707e+09  5.737e+08   4.718 2.53e-05 ***
## FDI_3       3.675e-02  7.713e-01   0.048    0.962    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 3.827e+09 on 43 degrees of freedom
## Multiple R-squared:  5.279e-05,  Adjusted R-squared:  -0.0232 
## F-statistic: 0.00227 on 1 and 43 DF,  p-value: 0.9622
LS0tDQp0aXRsZTogIkxlYXJuIFIgYmFzaWNzIHdpdGggU2ltcGxlIExpbmVhciBSZWdyZXNzaW9uIGFuZCBUaW1lIHNlcmllcyINCmF1dGhvcjogIklicmFoZWVtIEVsIEFuc2FyaSINCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jX2Zsb2F0OiBUUlVFDQogICAgdGhlbWU6IGRlZmF1bHQNCiAgICB0b2M6IFRSVUUNCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFDQogICAgaGlnaGxpZ2h0OiB0YW5nbw0KLS0tDQoNCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpgYGANCg0KYGBge2NzcyBlY2hvPUZBTFNFfQ0KLmNvbHVtbnMge2Rpc3BsYXkgOiBmbGV4O30NCmgyIHtjb2xvcjogZGFya2JsdWU7IGZvbnQtZmFtaWx5OiBjdXJzaXZlIH0NCnAge2ZvbnQtZmFtaWx5OiBDb21pYyBTYW5zIE1TfQ0KLnIge2JvcmRlci1yYWRpdXM6IDFlbTsgZm9udC1mYW1pbHk6IEx1Y2lkYSBDb25zb2xlfQ0KLmF1dGhvciB7Y29sb3I6IGJsYWNrOyBmb250LWZhbWlseTogY3Vyc2l2ZTsgZm9udC1zaXplOiAxNnB4OyBmbG9hdDpyaWdodDt9DQoudGl0bGUge2NvbG9yOiAjMDAyNjRkOyBmb250LWZhbWlseTogY3Vyc2l2ZTsgdGV4dC1hbGlnbjogY2VudGVyIH0NCmBgYA0KDQojIyBQdXJwb3NlIG9mIHRoaXMgbm90ZWJvb2sNCg0KVGhlIG1haW4gcHVycG9zZSBvZiB0aGlzIG5vdGVib29rIGlzIHRvIGxlYXJuIGhvdyB0byBnZXQgc3RhcnRlZCBpbiBSIGFuZCBhcHBseSBzb21lIGJhc2ljIGNvbW1hbmRzIGxpa2UgdmVjdG9ycywgZGF0YSBpbXBvcnRhdGlvbiwgbG9vcHMsIGlmIHN0YXRlbWVudHMsIGFuZCBvZiBjb3Vyc2UgbGluZWFyIHJlZ3Jlc3Npb24uDQoNCldoaWxlIHRoaXMgbm90ZWJvb2sgaXMgYmVnaW5uZXIgZnJpZW5kbHksIGl0IGRvZXMgcmVxdWlyZSBzb21lIGJhc2ljIHVuZGVyc3RhbmRpbmcgb2YgaG93IHRoZSBPTFMgcmVncmVzc2lvbiBhbGdvcml0aG0gd29ya3MuDQoNCiMjIFRoZW9yeQ0KDQoqKkdyb3NzIGZpeGVkIGNhcGl0YWwgZm9ybWF0aW9uIChHRkNGKSoqIGluY2x1ZGVzIHNwZW5kaW5nIG9uIGxhbmQgaW1wcm92ZW1lbnRzIChmZW5jZXMsIGRpdGNoZXMsIGRyYWlucywgYW5kIHNvIG9uKTsgcGxhbnQsIG1hY2hpbmVyeSwgYW5kIGVxdWlwbWVudCBwdXJjaGFzZXM7IHRoZSBjb25zdHJ1Y3Rpb24gb2Ygcm9hZHMsIHJhaWx3YXlzLCBwcml2YXRlIHJlc2lkZW50aWFsIGR3ZWxsaW5ncywgYW5kIGNvbW1lcmNpYWwgYW5kIGluZHVzdHJpYWwgYnVpbGRpbmdzLg0KDQoqKkZvcmVpZ24gZGlyZWN0IGludmVzdG1lbnQgKEZESSkqKiBpcyBhbiBpbnZlc3RtZW50IGZyb20gYSBwYXJ0eSBpbiBvbmUgY291bnRyeSBpbnRvIGEgYnVzaW5lc3Mgb3IgY29ycG9yYXRpb24gaW4gYW5vdGhlciBjb3VudHJ5IHdpdGggdGhlIGludGVudGlvbiBvZiBlc3RhYmxpc2hpbmcgYSBsYXN0aW5nIGludGVyZXN0Lg0KDQojIyBEYXRhIEltcG9ydGF0aW9uDQoNClRoZSBEYXRhIHdhcyB0YWtlbiBmcm9tIHRoZSB3ZWJzaXRlICoqIlBlcnNwZWN0aXZlIE1vbmRlIioqLiBJbnN0ZWFkIG9mIGRvd25sb2FkaW5nIGl0IGFzIGEgQ1NWIGZpbGUgYW5kIHRoZW4gaW1wb3J0aW5nIGl0IGFuZCBleHRyYWN0IHZlY3RvcnMsIHRoZXkgcHJvdmlkZSBpdCBpbiBhIHJlYWR5IGZvcm1hdCBmb3IgUiBhbmQgUHl0aG9uIGFzIHZlY3RvcnMgYW5kIERhdGEgZnJhbWVzIGZvciBjb252ZW5pZW5jZSwgd2hpY2ggaXMgd2hhdCB3ZSBkaWQgaGVyZToNCg0KYGBge3J9DQpEYXRlX0ZEST1jKDE5NzA6MjAxOSkNCg0KDQojIFZlY3RvcnMgKCBUaGlzIHdyaXRpbmcgaXMgaWdub3JlZCB3aGlsZSBydW5uaW5nIHRoZSBjb21tYW5kIGJlY2F1c2UgaXQncyBjb25zaWRlcmVkIGEgY29tbWVudCApDQoNCkZEST1jKCAyMDAwMDAwMCwgMjMxMDAwMDAsIDEzMDAwMDAwLCA1NDkwMDAwLCAtMjA0MDAwMDAsIDUwMjAwMDAsIDM4MDE0OTYyLjc0LCA3OTk0MDU2LjI3MywNCiAgICAgIDExNzU5OTg4LjI0LCA3NDM3NTQ4LjYzNywgODk0MTYyMjIuNTksIDU4NTgxMzM1Ljk5LCA3OTUyODE3Ny4xLCA0NjEyMzYyMy41LCA0Njk4OTE5Ni41NiwgDQogICAgICAxOTk3NTE2Ni44NiwgNTQ5MTgyLjQ5NjEsIDU5NTc0OTAwLjc4LCA4NDY2MTYyNy41NywgMTY3MDU2MDMyLjEsIDE2NTEyMjk3Ny44LCAzMTc0NjIxNDAuNiwNCiAgICAgIDQyMjQ3MDQ2Mi41LCA0OTE0NjYwNjQuNiwgNTUwOTI0MzczLjksIDMzNDc2ODI3Mi45LCAzNTczOTM4MDEuOCwgMTA3OTM0MTMzMiwgMzA4NzEyMTY0LjQsDQogICAgICA4MjY5NzQwMjYuOSwgNDI2NTUzMjgzLjksIDI4MjQ1NTcyNTIsIDQ4MDM1NTY5OCwgMjMxMjgyOTgyMywgODkzMzI1MzkyLjgsIDE2NzA2MDk2ODksIA0KICAgICAgMjQ2MDc4NzE2NCwgMjgyNTgwMTM3NiwgMjQ2NjI4ODM1NywgMTk3MDMyMzkyMCwgMTI0MDYyNTg1OSwgMjUyMTM2MjA4MSwgMjg0MTk1NDM3MSwgDQogICAgICAzMzYwOTA5OTI0LCAzNTI1Mzg0NjEyLCAzMjUyOTEzOTAyLCAyMTUzMzYzOTA1LCAyNjgwMTA5ODU2LCAzNTQ0Mzg3MjI5LCAxNTk5NzYxMDk4KQ0KDQpEYXRlX0dGQ0Y9YygxOTYwOjIwMTgpDQoNCkdGQ0Y9YyggMTk5ODc3OTE3LjIsIDIyOTEzMzM0Ni41LCAyNTA0MTAwMTguOCwgMzA2MDU2Njk0LCAyOTY4NTA0NDkuNiwgMzEzMDEyNTQ4LjIsIDMzNjUyODAzMC44LCANCiAgICAgICA0MTU3NjkxOTIuOCwgNDMzMzU2MzY3LjksNDc5NTk2ODc3LjgsIDU5MDQ1NTQ4OC42LCA2NDczMjY3MzIuNywgNjkwNTMyMDgxLjQsIDg0NTE2MzAxOC4zLCANCiAgICAgICAxMTI4NjU1Nzc0LCAyMjI5OTgxNDkzLCAyNzU1MTg3NDczLCAzNTMwOTY2MTgwLCAzMjk1NjUzNjM1LCAzODE1MjM5NDE0LCA1Njc1NDMwNTc1LCANCiAgICAgICA1NTUwNDU5MTc3LCA1NDYyMTM4NDY5LCA0NTA5MjE2MzE4LCAzNzQ3NjM5NzQ4LCAzNzc5NDY1MzY4LCA0NTY5OTQ0MjAzLCANCiAgICAgICA0ODM5NjkwNDAxLCA1Nzg2ODEzNDE0LCA3MDY1NTczMzg0LCA3NzgxOTU5NzQ0LCA4MDU0MjQzNjA4LCA4MzYyNDIzOTQwLCA4MDg4MTI5MDAzLCANCiAgICAgICA4MzkyOTU2NDQ5LCA5MzUwNjAzODUyLCA5NDE0ODE1OTAwLCA4OTA5NTEyODkwLCAxMDEyODEzODgzMiwgMTA5MzAxMjg3MjgsIDEwNDgwOTM0MzMxLCANCiAgICAgICAxMDIwMjA3NDk4MCwgMTExMjAzNTc4NDQsIDEzNDk4ODU3MDY3LDE2MjczNjAxMjQwLCAxNzc1OTYwNDQyMiwgMjAwMjE5NjQ4MDEsIA0KICAgICAgIDI1NDE2MDYxNDI0LCAzMTgzODM4MDQ1MCwgMjk0MTMxODgzNjgsIDI4NTc2NzIzODUxLCAzMTkyNjg0NzA1NiwgMzIwMzI1OTAwNTEsIA0KICAgICAgIDMyODk0NjUyMzExLCAzMjg2MDcxMTYwOSwgMjg3MDM2NDQ5MTEsIDMxMDI1ODQ3NTY2LCAzMTQyNDk4OTY4MiwgMzM1NTYzMjI2NDcpDQoNCmxlbmd0aD1jKGxlbmd0aChEYXRlX0ZESSksbGVuZ3RoKEZESSksbGVuZ3RoKERhdGVfR0ZDRiksbGVuZ3RoKEdGQ0YpKQ0KcHJpbnQobGVuZ3RoKQ0KYGBgDQoNCklmIHlvdSB3YW50IHRvIGltcG9ydCB0aGUgZGF0YSBhcyBhbiBleGNlbCBvciBjc3YgZmlsZSwgdXNlIHRoZSBmb2xsb3dpbmcgY29tbWFuZHMgOg0KDQpgYGB7ciBldmFsPUZBTFNFfQ0KIyBGb3IgY3N2IGZpbGVzDQpkYXRhID0gcmVhZC5jc3YyKCJmaWxlbmFtZS5jc3YiKQ0KDQojIEZvciBFeGNlbCBmaWxlcywgd2UgaGF2ZSB0byBpbnN0YWxsIHRoZSAncmVhZHhsJyBwYWNrYWdlIGFuZCB0aGVuIHJlYWQgaXQuDQppbnN0YWxsLnBhY2thZ2VzKCJyZWFkeGwiKQ0KbGlicmFyeShyZWFkeGwpDQpkYXRhID0gcmVhZF9leGNlbCgiZmlsZW5hbWUueGxzeCIsIHNoZWV0PSJuYW1lIikNCg0KIyBFeHRyYWN0IHZlY3RvcnMgZnJvbSBjc3YgZmlsZQ0KdmVjdG9yID0gZGF0YSRjb2x1bW5fbmFtZQ0KYGBgDQoNCiMjIERhdGEgQ2xlYW5pbmcNCg0KTm90ZSB0aGF0IHRoZSBGREkgaGFzIDUwIG9ic2VydmF0aW9ucyBzdGFydGluZyBmcm9tIDE5NzAgdG8gMjAxOS4gVGhlIEdGQ0YgaGFzIDU5IG9ic2VydmF0aW9ucyBzdGFydGluZyBmcm9tIDE5NjAgdG8gMjAxOC4gV2Ugd2lsbCByZW1vdmUgdGhlIGZpcnN0IDEwIG9ic2VydmF0aW9uIGZyb20gdGhlIEdGQ0YgYXMgd2VsbCBhcyB0aGUgbGFzdCBvbmUgZnJvbSB0aGUgRkRJIHRoZSBsYXN0IG9uZSBzbyB0aGF0IHRoZSB0d28gdmVjdG9ycyBiZWNvbWUgZXF1YWwgaW4gbGVuZ3RoOg0KDQpgYGB7cn0NCkdGQ0ZfMiA9IEdGQ0ZbLSgxOjEwKV0NCkZESV8yID0gRkRJWy1sZW5ndGgoRkRJKV0NCmxlbmd0aF8yPWMobGVuZ3RoKEdGQ0ZfMiksbGVuZ3RoKEZESV8yKSkNCnByaW50KGxlbmd0aF8yKQ0KYGBgDQoNCk5vdyB0aGF0IHRoZSB2ZWN0b3JzIGFyZSBlcXVhbCwgd2UgY2FuIGJpbmQgdGhlbSBpbiBhIGRhdGFmcmFtZSBhbmQgdmlzdWFsaXplIGl0cyBoZWFkIGFzIGZvbGxvd3M6DQoNCmBgYHtyfQ0KZGF0YT1kYXRhLmZyYW1lKFllYXI9YygxOTcwOjIwMTgpLEdGQ0ZfMixGRElfMikNCnByaW50KGhlYWQoZGF0YSwyKSkNCnByaW50KHRhaWwoZGF0YSwyKSkNCmBgYA0KDQojIyBEYXRhIHZpc3VhbGlzYXRpb24gJiBEZXNjcmlwdGl2ZSBzdGF0aXN0aWNzDQoNCmBgYHtyIGZpZy5zaG93PSJob2xkIiwgb3V0LndpZHRoPSI1MCUifQ0KIyBIaXN0b2dyYW1zDQoNCmhpc3QoR0ZDRl8yLGNvbD0nY29ybmZsb3dlcmJsdWUnKQ0KaGlzdChGRElfMixjb2w9J2Nvcm5mbG93ZXJibHVlJykNCmBgYA0KDQpgYGB7ciBmaWcuc2hvdz0iaG9sZCIsIG91dC53aWR0aD0iNTAlIn0NCiMgTGluZSBjaGFydHMgdXNpbmcgdGhlICdnZ3Bsb3QnIGxpYnJhcnkNCmxpYnJhcnkoZ2dwbG90MikNCmdncGxvdChkYXRhLCBhZXMoeD1jKDE5NzA6MjAxOCksIHk9R0ZDRl8yKSkgKyBnZW9tX2xpbmUoY29sb3I9ImJsdWUiKSArIHRoZW1lX2J3KCkNCmdncGxvdChkYXRhLCBhZXMoeD1jKDE5NzA6MjAxOCksIHk9RkRJXzIpKSArIGdlb21fbGluZShjb2xvcj0iYmx1ZSIpICsgdGhlbWVfYncoKQ0KYGBgDQoNClRoZSBgY2F0YCBmdW5jdGlvbiBhbGxvd3MgeW91IHRvIHByaW50IHRleHQgbmV4dCB0byBhY3R1YWwgY29tbWFuZHMsIHdoaWNoIGlzIHdoYXQgd2UgZGlkIHRvIHByaW50IGRlc2NyaXB0aXZlIHN0YXRpc3RpY3MuIA0KDQpgYGB7cn0NCmNhdChjYXQoJ0dGQ0Y6JyksY2F0KCcgbWluPScsbWluKEdGQ0ZfMikpLA0KICAgICBjYXQoJyBtZWRpYW49JyxtZWRpYW4oR0ZDRl8yKSksDQogICAgIGNhdCgnIG1heD0nLG1heChHRkNGXzIpKSwNCiAgICAgY2F0KCcgbWVhbj0nLG1lYW4oR0ZDRl8yKSksDQogICAgIGNhdCgnIHN0YW5kYXJkX2RldmlhdGlvbj0nLHNkKEdGQ0ZfMikpKQ0KDQpjYXQoY2F0KCdGREk6JyksY2F0KCcgbWluPScsbWluKEZESV8yKSksDQogICAgIGNhdCgnIG1lZGlhbj0nLG1lZGlhbihGRElfMikpLA0KICAgICBjYXQoJyBtYXg9JyxtYXgoRkRJXzIpKSwNCiAgICAgY2F0KCcgbWVhbj0nLG1lYW4oRkRJXzIpKSwNCiAgICAgY2F0KCcgc3RhbmRhcmRfZGV2aWF0aW9uPScsc2QoRkRJXzIpKSkNCmBgYA0KDQpgYGB7cn0NCiMgQ29ycmVsYXRpb24NCmNhdCgnQ29ycmVsYXRpb24gYmV0d2VlbiBHRkNGICYgRkRJOicsIGNvcihGRElfMixHRkNGXzIpKQ0KYGBgDQoNCiMjIFN0YXRpb25hcml0eQ0KDQpUaGUgcmVhc29uIHdoeSBJIGNob3NlIHRvIHdvcmsgb24gVGltZSBzZXJpZXMgYW5kIG5vdCBDcm9zcyBzZWN0aW9uYWwgRGF0YSBpcyBiZWNhdXNlIHRoZXJlIGlzIGEgc3Ryb25nIGNoYW5jZSB0aGF0IHlvdSB3aWxsIHVzZSBSIGZvciBUaW1lIHNlcmllcyBhbmFseXNpcyBpZiB5b3UncmUgcmVhZGluZyB0aGlzIGFydGljbGUuDQoNClRoZXJlIGFyZSB0ZW5zIG9mIFIgbGlicmFyaWVzIHRoYXQgYXJlIGVzcGVjaWFsbHkgbWFkZSBmb3IgdGltZSBzZXJpZXMgYW5hbHlzaXMuIEZvciBub3cgd2Ugd2lsbCB1c2UgdGhlIGB0c2VyaWVzYCBsaWJyYXJ5Lg0KDQoNCmBgYHtyfQ0KR0ZDRl8zID0gZGlmZihHRkNGXzIsNCkNCnRzZXJpZXM6OmFkZi50ZXN0KEdGQ0ZfMykNCmBgYA0KDQpgYGB7cn0NCkZESV8zID0gZGlmZihGRElfMiwxKQ0KdHNlcmllczo6YWRmLnRlc3QoRkRJXzMpDQpgYGANCg0KVGhlICpwLXZhbHVlKiBpcyBsZXNzIHRoYW4gNSUgZm9yIGJvdGggdGhlIEdGQ0YgYW5kIHRoZSBGREkgYWZ0ZXIgNCBhbmQgMSBkaWZmZXJlbnRpYXRpb25zIChpbnRlZ3JlYXRpb25zKSByZXNwZWN0aXZlbHkuIA0KDQpTaW5jZSB0aGUgRkRJIHZlY3RvciBoYXMgMyBtb3JlIG9ic2VydmF0aW9ucyB0aGFuIHRoZSBHRkNGLCB3ZSBuZWVkIHRvIHJlbW92ZSB0aGUgZmlyc3QgdGhyZWUgdmFsdWVzIHNvIHRoZXkgYmVjb21lIGVxdWFsIGluIGxlbmd0aCB3aGlsZSBtYWludGFpbmluZyB0aGUgc2FtZSBEYXRlIGluZGV4Lg0KDQpgYGB7cn0NCkZESV8zID0gRkRJXzNbLSgxOjMpXQ0KZGF0YV9uZXcgPSBkYXRhLmZyYW1lKCJZZWFyIj1jKDE5NzQ6MjAxOCksIkdGQ0YiPUdGQ0ZfMywiRkRJIj1GRElfMykNCmBgYA0KDQoNCmBgYHtyIGZpZy5zaG93PSJob2xkIiwgb3V0LndpZHRoPSI1MCUifQ0KZ2dwbG90KGRhdGFfbmV3LGFlcyh4PVllYXIsIHk9R0ZDRikpICsgZ2VvbV9saW5lKGNvbG9yPSJibHVlIikgKyB0aGVtZV9idygpDQpnZ3Bsb3QoZGF0YV9uZXcsYWVzKHg9WWVhciwgeT1GREkpKSArIGdlb21fbGluZShjb2xvcj0iYmx1ZSIpICsgdGhlbWVfYncoKQ0KYGBgDQoNClVzaW5nIHRoZSBgZ2dwbG90YCBwYWNrYWdlIHJlcXVpcmVzIGJpbmRpbmcgdGhlIHZlY3RvcnMgaW4gZGF0YWZyYW1lcyAoIGRhdGFfbmV3ICkuIFlvdSBjYW4gc2VlIHRocm91Z2ggdGhlIGxpbmUgY2hhcnRzIHRoYXQgdGhlIHNlcmllcyBoYXZlIGJlY29tZSBzdGF0aW9uYXJ5LiBXZSBjYW4gcHJvY2VlZCB0byB0aGUgT0xTIG1ldGhvZC4NCg0KIyMgUGFyYW1ldGVycyBFc3RpbWF0aW9uIGFuZCBQcmVkaWN0aW9uDQoNCldlIHdpbGwgbm93IGNyZWF0ZSBhIGZ1bmN0aW9uIHRoYXQgcmV0dXJucyB0aGUgdmFsdWUgb2YgdGhlc2UgdHdvIGZ1bmN0aW9uczoNCg0KLSBJbnRlcmNlcHQgOiAkZih4LHkpPVxiYXJ7WX0tXGZyYWN7Q292KFgsWSl9e1YoWCl9XGJhcntYfSQNCi0gU2xvcGUgOiAkZih4LHkpPVxmcmFje0NvdihYLFkpfXtWKFgpfSQgDQoNCkZpcnN0IHdlIGNhbGwgdGhlIGZ1bmN0aW9uIGBmdW5jdGlvbihYLFkpe31gLCBhbmQgdGhlbiBzdG9jayB2YXJpYWJsZXMgaW5zaWRlIGl0IHVzaW5nIHRoZSBYIGFuZCBZIHZhcmlhYmxlcyB5b3UgcHV0IGFzIGFyZ3VtZW50cy4gVGhlIGByZXR1cm5gIGNvbW1hbmQgaXMgc3BlY2lmaWMgdG8gdGhlIGBmdW5jdGlvbmAgY29tbWFuZCwgaXQgcmV0dXJucyB0aGUgdmFsdWVzIG9mIHRoZSBzdG9ja2VkIHZhcmlhYmxlcy4NCg0KYGBge3J9DQpHRkNGX3Bhcj1mdW5jdGlvbihYLFkpeyANCiAgICBJbnRlcmNlcHQ9bWVhbihZKS0oY292KFgsWSkvdmFyKFgpKSptZWFuKFgpO1Nsb3BlPShjb3YoWCxZKS92YXIoWCkpOw0KICAgIHJldHVybihjYXQoY2F0KCdJbnRlcmNlcHQ6JyxJbnRlcmNlcHQpLGNhdCgnICAgU2xvcGU6JyxTbG9wZSkpKX0NCkdGQ0ZfcGFyKEZESV8zLEdGQ0ZfMykNCmBgYA0KDQpUaGUgYmVsb3cgY29kZSBpcyB0byBjcmVhdGUgdGhlIFByZWRpY3Rpb24gdmVjdG9yICRcaGF0e1l9JCBiYXNlZCBvbiB0aGUgY2FsY3VsYXRlZCBPTFMgcGFyYW1ldGVycy4gTm90ZSB0aGF0IHdlIHdpbGwgYmUgcmVmZXJyaW5nIHRvIHRoZSBpbnRlcmNlcHQgYXMgJFxhbHBoYSQgYW5kIHRoZSBzbG9wZSBhcyAkXGJldGEkLg0KDQotICRcaGF0e1l9PVxoYXR7XGFscGhhfSArIFxoYXR7XGJldGF9e1h9JA0KDQpgYGB7cn0NCkdGQ0ZfaGF0PWZ1bmN0aW9uKFgsWSl7IA0KICAgIFloYXQ9bWVhbihZKS0oY292KFgsWSkvdmFyKFgpKSptZWFuKFgpKyhjb3YoWCxZKS92YXIoWCkpKlg7DQogICAgcmV0dXJuKFloYXQpfQ0KDQojIHNob3cgZmlyc3QgNCB2YWx1ZXMNCnByaW50KGhlYWQoR0ZDRl9oYXQoRkRJXzMsR0ZDRl8zKSw0KSkNCmBgYA0KDQojIyBUaGUgU3VtIG9mIFNxdWFyZXMNCg0KIyMjIEVTUw0KDQotIEVzdGltYXRlZCBTdW0gb2YgU3F1YXJlcyA9ICRcc3VteyhcYmFye1l9LXtcaGF0e1l9X2l9KV4yfSQNCg0KTG9vcHMgYXJlIGJ5IGZhciBteSBmYXZvcml0ZSBmZWF0dXJlIGluIHByb2dyYW1taW5nIGluIGdlbmVyYWwsIEkgdXNlIHRoZW0gYWxsIHRoZSB0aW1lIGJlY2F1c2UgdGhleSBmYWNpbGl0YXRlIGNhbGN1bGF0aW9ucyBhbmQgYXJlIHNvIGVmZmljaWVudC4NCg0KVGhlcmUgYXJlIHRocmVlIHdheXMgdG8gY3JlYXRlIGxvb3BzIGluIFIsIHRoYXQgaXMgYGZvcmAsIGB3aGlsZWAgYW5kIGByZXBlYXRgIGxvb3BzLiBXZSB3aWxsIGJyZWFrIGRvd24gdGhlIGNvZGUgYmVsb3cgdG8gZXhwbGFpbiBob3cgdGhleSB3b3JrIDoNCg0KLSBgZm9yYCBsb29wOiA8YnI+IEZpcnN0IHdlIG5lZWQgdG8gaW5pdGlhbGl6ZSBhIHZhcmlhYmxlIHRvIHN0b2NrIHRoZSBzdW1zLCBsZXQncyBjYWxsIGl0ICoqaCoqLiBJbnNpZGUgdGhlICoqZm9yKiogbG9vcCwgd2Ugc2V0IGEgbGlzdCBvZiBpbmRleGVzIGZyb20gMSB1bnRpbCB0aGUgbGVuZ3RoIG9mIHRoZSBZIHZlY3Rvciwgd2UgY2FsbCB0aGVzZSBpbmRleGVzIHVzaW5nIHRoZSBsZXR0ZXIgKippKiogaW4gdGhlIGxvb3AuICBUaGUgKipoKiogdmFyaWFibGUgc3RhcnRzIGF0IDAsIHRoZSBmaXJzdCB2YWx1ZSBpdCB3aWxsIHRha2UgaXMgJGdbMV0rMCQsIHRoZSBzZWNvbmQgdmFsdWUgaXMgJGdbMl0rZ1sxXSQsIHRoZSB0aGlyZCB2YWx1ZSBpcyAkZ1szXStnWzJdJCwgYW5kIHNvIG9uIHVudGlsIHdlIHJlYWNoIHRoZSBsYXN0IGluZGV4Lg0KDQoNCi0gYHdoaWxlYCBsb29wOiA8YnI+IFRoZSB3aGlsZSBsb29wIGlzIHNsaWdodGx5IGRpZmZlcmVudC4gWW91IHNldCBhIGNvbmRpdGlvbiBmb3IgdGhlIGluZGV4ICoqaSoqLCBpbiB0aGlzIGNhc2Ugd2UgY2FsY3VsYXRlIHRoZSBzdW1zIGFzIGxvbmcgYXMgdGhlIGluZGV4IGlzIGxlc3MgdGhhbiB0aGUgbGVuZ3RoIG9mIFkgYHdoaWxlKGk8PWxlbmd0aChZKSlgLCBhbmQgd2Ugc2V0ICRpPWkrMSQgdG8gY2hhbmdlIHRoZSBpbmRleCBhZnRlciBlYWNoIGl0ZXJhdGlvbi4NCg0KLSBgcmVwZWF0YCBsb29wOiA8YnI+IFRoZSByZXBlYXQgbG9vcCBpcyBraW5kIG9mIGEgY29tYmluYXRpb24gb2YgYm90aCB0aGUgZm9yIGFuZCB3aGlsZSBsb29wcy4gd2UgcmVwZWF0IHRoZSBzdW0gb3BlcmF0aW9uIGxpa2UgaW4gdGhlIGZvciBsb29wLCB3aGlsZSBtYWludGFpbmluZyB0aGUgaW5kZXggdXAgdG8gaXRlcmF0aW9uIGFzIGluIHRoZSB3aGlsZSBsb29wLiBXaGF0IGlzIHNwZWNpZmljIGZvciB0aGUgcmVwZWF0IGxvb3AgaXMgdGhhdCB3ZSBoYXZlIHRvIHNldCBhIGNvbmRpdGlvbiB3aGVyZSB0aGUgbG9vcCB3b3VsZCBgYnJlYWtgLCB3aGljaCBpcyBpZiB0aGUgdmFsdWUgb2YgdGhlIGluZGV4IGJlY29tZSBoaWdoZXIgdGhhbiB0aGUgbGVuZ3RoIG9mIHRoZSB2ZWN0b3IsIHN0b3AgdGhlIGl0ZXJhdGlvbnMgYGlmKGk+bGVuZ3RoKFkpKXticmVha319YA0KDQoNCmBgYHtyfQ0KIyBVc2luZyBmb3IgbG9vcA0KRVNTPWZ1bmN0aW9uKFgsWSl7Zz0oKG1lYW4oWSktKGNvdihYLFkpL3ZhcihYKSkqbWVhbihYKSkrKChjb3YoWCxZKS92YXIoWCkpKlgpLW1lYW4oWSkpXjI7DQogICAgICAgICAgICAgICAgICBoPTA7DQogICAgICAgICAgICAgICAgICBmb3IgKCBpIGluIDE6bGVuZ3RoKFkpKXtoPWdbaV0raH07DQogICAgICAgICAgICAgICAgICByZXR1cm4oY2F0KCdFU1M9JyxoKSl9DQpFU1MoRkRJXzMsR0ZDRl8zKQ0KDQojIHVzaW5nIHdoaWxlIGxvb3ANCkVTUz1mdW5jdGlvbihYLFkpe2c9KChtZWFuKFkpLShjb3YoWCxZKS92YXIoWCkpKm1lYW4oWCkpKygoY292KFgsWSkvdmFyKFgpKSpYKS1tZWFuKFkpKV4yOw0KICAgICAgICAgICAgICAgICAgaD0wO2k9MTsNCiAgICAgICAgICAgICAgICAgIHdoaWxlKGk8PWxlbmd0aChZKSl7aD1nW2ldK2g7aT1pKzF9Ow0KICAgICAgICAgICAgICAgICAgcmV0dXJuKGNhdCgnICAgRVNTPScsaCkpfQ0KRVNTKEZESV8zLEdGQ0ZfMykNCg0KIyB1c2luZyByZXBlYXQgbG9vcA0KRVNTPWZ1bmN0aW9uKFgsWSl7Zz0oKG1lYW4oWSktKGNvdihYLFkpL3ZhcihYKSkqbWVhbihYKSkrKChjb3YoWCxZKS92YXIoWCkpKlgpLW1lYW4oWSkpXjI7DQogICAgICAgICAgICAgICAgICAgIGg9MDtpPTE7DQogICAgICAgICAgICAgICAgICAgIHJlcGVhdHtoPWdbaV0raDtpPWkrMTtpZihpPmxlbmd0aChZKSl7YnJlYWt9fTsNCiAgICAgICAgICAgICAgICAgIHJldHVybihjYXQoJyAgIEVTUz0nLGgpKX0NCkVTUyhGRElfMyxHRkNGXzMpDQpgYGANCg0KDQojIyMgUlNTDQoNCi0gUmVzaWR1YWwgU3VtIG9mIFNxdWFyZXMgPSAkXHN1bXsoe1lfaX0te1xoYXR7WX1faX0pXjJ9JA0KDQpgYGB7cn0NCiMgVXNpbmcgZm9yIGxvb3ANClJTUz1mdW5jdGlvbihYLFkpe2c9KFktKChtZWFuKFkpLShjb3YoWCxZKS92YXIoWCkpKm1lYW4oWCkpKygoY292KFgsWSkvdmFyKFgpKSpYKSkpXjI7DQogICAgICAgICAgICAgICAgICAgaD0wOw0KICAgICAgICAgICAgICAgICAgIGZvciAoIGkgaW4gMTpsZW5ndGgoWSkpe2g9Z1tpXStofTsNCiAgICAgICAgICAgICAgICAgIHJldHVybihjYXQoJ1JTUz0nLGgpKX0NClJTUyhGRElfMyxHRkNGXzMpDQoNCiMgdXNpbmcgd2hpbGUgbG9vcA0KUlNTPWZ1bmN0aW9uKFgsWSl7Zz0oWS0oKG1lYW4oWSktKGNvdihYLFkpL3ZhcihYKSkqbWVhbihYKSkrKChjb3YoWCxZKS92YXIoWCkpKlgpKSleMjsNCiAgICAgICAgICAgICAgICAgICAgaD0wO2k9MTsNCiAgICAgICAgICAgICAgICAgICAgd2hpbGUoaTw9bGVuZ3RoKFkpKXtoPWdbaV0raDtpPWkrMX07DQogICAgICAgICAgICAgICAgICByZXR1cm4oY2F0KCcgICAgUlNTPScsaCkpfQ0KUlNTKEZESV8zLEdGQ0ZfMykNCg0KIyB1c2luZyByZXBlYXQgbG9vcA0KUlNTPWZ1bmN0aW9uKFgsWSl7Zz0oWS0oKG1lYW4oWSktKGNvdihYLFkpL3ZhcihYKSkqbWVhbihYKSkrKChjb3YoWCxZKS92YXIoWCkpKlgpKSleMjsNCiAgICAgICAgICAgICAgICAgICAgaD0wO2k9MTsNCiAgICAgICAgICAgICAgICAgICAgcmVwZWF0e2g9Z1tpXStoO2k9aSsxO2lmKGk+bGVuZ3RoKFkpKXticmVha319Ow0KICAgICAgICAgICAgICAgICAgcmV0dXJuKGNhdCgnICAgIFJTUz0nLGgpKX0NClJTUyhGRElfMyxHRkNGXzMpDQpgYGANCg0KDQojIyMgVFNTDQoNCi0gVG90YWwgU3VtIG9mIFNxdWFyZXMgPSAkXHN1bXsoe1lfaX0te1xiYXJ7WX19KV4yfSQNCg0KYGBge3J9DQojIHVzaW5nIGZvciBsb29wDQpUU1M9ZnVuY3Rpb24oWCxZKXtnPShZLW1lYW4oWSkpXjI7DQogICAgICAgICAgICAgICAgICBoPTA7DQogICAgICAgICAgICAgICAgICBmb3IgKCBpIGluIDE6bGVuZ3RoKFkpKXtoPWdbaV0raH07DQogICAgICAgICAgICAgICAgICByZXR1cm4oY2F0KCdUU1M9JyxoKSl9DQpUU1MoRkRJXzMsR0ZDRl8zKQ0KDQojIHVzaW5nIHdoaWxlIGxvb3ANClRTUz1mdW5jdGlvbihYLFkpe2c9KFktbWVhbihZKSleMjsNCiAgICAgICAgICAgICAgICAgIGg9MDtpPTE7DQogICAgICAgICAgICAgICAgICB3aGlsZShpPD1sZW5ndGgoWSkpe2g9Z1tpXStoO2k9aSsxfTsNCiAgICAgICAgICAgICAgICAgIHJldHVybihjYXQoJyAgICBUU1M9JyxoKSl9DQpUU1MoRkRJXzMsR0ZDRl8zKQ0KDQojIHVzaW5nIHJlcGVhdCBsb29wDQpUU1M9ZnVuY3Rpb24oWCxZKXtnPShZLW1lYW4oWSkpXjI7DQogICAgICAgICAgICAgICAgICAgIGg9MDtpPTE7DQogICAgICAgICAgICAgICAgICAgIHJlcGVhdHtoPWdbaV0raDtpPWkrMTtpZihpPmxlbmd0aChZKSl7YnJlYWt9fTsNCiAgICAgICAgICAgICAgICAgIHJldHVybihjYXQoJyAgICBUU1M9JyxoKSl9DQpUU1MoRkRJXzMsR0ZDRl8zKQ0KYGBgDQoNCg0KIyMgQ29lZmZpY2llbnQgb2YgZGV0ZXJtaW5hdGlvbg0KDQotICRSXjI9XGZyYWN7RVNTfXtUU1N9JA0KDQpJbiB0aGVzZSBsb29wcywgd2UgaGF2ZSBzdG9ja2VkIHRoZSB2YWx1ZSBvZiB0aGUgKkVTUyogaW4gdGhlICRnJCB2YXJpYWJsZSwgYW5kIHRoZSB2YWx1ZSBvZiB0aGUgKlRTUyogaW4gdGhlIGsgdmFyaWFibGUuDQpXZSBmaXhlZCAkaD0wJCBhbmQgJHo9MCQgdG8gc3RvY2sgdGhlIHZhbHVlIG9mIHRoZSBpdGVyYXRpb25zIGp1c3QgbGlrZSB3ZSBkaWQgYWJvdmUsIGFuZCBmaW5hbGx5IHdlIHVzZWQgdGhlIGByZXR1cm5gIGZ1bmN0aW9uIHRvIHJldHVybiB0aGUgZnJhY3Rpb24gJGgveiQuDQoNCmBgYHtyfQ0KIyB1c2luZyBmb3IgbG9vcA0KUl9zcXVhcmVkPWZ1bmN0aW9uKFgsWSl7Zz0oKG1lYW4oWSktKGNvdihYLFkpL3ZhcihYKSkqbWVhbihYKSkrKChjb3YoWCxZKS92YXIoWCkpKlgpLW1lYW4oWSkpXjI7DQogICAgICAgICAgICAgICAgICAgICAgIGs9KFktbWVhbihZKSleMjsNCiAgICAgICAgICAgICAgICAgICAgICAgaD0wO3o9MDsNCiAgICAgICAgICAgICAgICAgICAgICAgZm9yICggaSBpbiAxOmxlbmd0aChZKSl7aD1nW2ldK2g7ej1rW2ldK3p9Ow0KICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4oY2F0KCdSX3NxdWFyZWQ9JyxoL3opKX0NClJfc3F1YXJlZChGRElfMyxHRkNGXzMpDQoNCiMgdXNpbmcgd2hpbGUgbG9vcA0KUnNxdWFyZWQ9ZnVuY3Rpb24oWCxZKXtnPSgobWVhbihZKS0oY292KFgsWSkvdmFyKFgpKSptZWFuKFgpKSsoKGNvdihYLFkpL3ZhcihYKSkqWCktbWVhbihZKSleMjsNCiAgICAgICAgICAgICAgICAgICAgICAgICBrPShZLW1lYW4oWSkpXjI7DQogICAgICAgICAgICAgICAgICAgICAgICAgaD0wO3o9MDtpPTE7DQogICAgICAgICAgICAgICAgICAgICAgICAgd2hpbGUoaTw9bGVuZ3RoKFkpKXtoPWdbaV0raDt6PWtbaV0rejtpPWkrMX07DQogICAgICAgICAgICAgICAgICAgICAgIHJldHVybihjYXQoJyAgICAgIFJfc3F1YXJlZD0nLGgveikpfQ0KUl9zcXVhcmVkKEZESV8zLEdGQ0ZfMykNCg0KIyB1c2luZyByZXBlYXQgbG9vcA0KUnNxdWFyZWQ9ZnVuY3Rpb24oWCxZKXtnPSgobWVhbihZKS0oY292KFgsWSkvdmFyKFgpKSptZWFuKFgpKSsoKGNvdihYLFkpL3ZhcihYKSkqWCktbWVhbihZKSleMjsNCiAgICAgICAgICAgICAgICAgICAgICAgICBrPShZLW1lYW4oWSkpXjI7DQogICAgICAgICAgICAgICAgICAgICAgICAgaD0wO3o9MDtpPTE7DQogICAgICAgICAgICAgICAgICAgICAgICAgcmVwZWF0e2g9Z1tpXStoO3o9a1tpXSt6O2k9aSsxO2lmKGk+bGVuZ3RoKFkpKXticmVha319Ow0KICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4oY2F0KCcgICAgICBSX3NxdWFyZWQ9JyxoL3opKX0NClJfc3F1YXJlZChGRElfMyxHRkNGXzMpDQpgYGANCg0KDQojIyBWYXJpYW5jZXMgb2YgdGhlIG1vZGVsJ3MgcGFyYW1ldGVycw0KDQoqKkVycm9yIHZhcmlhbmNlOiAqKiAkXHNpZ21hXjI9XGZyYWN7UlNTfXtuLWstMX0kIHdpdGggJG49JCBudW1iZXJzIG9mIG9ic2VydmF0aW9ucyBhbmQgJGs9JCBudW1iZXIgb2YgaW5kZXBlbmRlbnQgdmFyaWFibGVzLg0KDQpJbiB0aGVzZSBsb29wcyB3ZSBzaW1wbHkgdXNlZCB0aGUgY29kZSBvZiB0aGUgUlNTLCBhbmQgZGl2aWRlZCBpdHMgdmFsdWUgYnkgdGhlIGRlZ3JlZSBvZiBmcmVlZG9tIGluIHRoZSBgcmV0dXJuYCBjb21tYW5kLg0KDQpgYGB7cn0NCiMgdXNpbmcgZm9yIGxvb3ANClZhckVycm9yPWZ1bmN0aW9uKFgsWSl7Zz0oWS0oKG1lYW4oWSktKGNvdihYLFkpL3ZhcihYKSkqbWVhbihYKSkrKChjb3YoWCxZKS92YXIoWCkpKlgpKSleMjsNCiAgICAgICAgICAgICAgICAgICAgICAgaD0wOw0KICAgICAgICAgICAgICAgICAgICAgICBmb3IgKCBpIGluIDE6bGVuZ3RoKFkpKXtoPWdbaV0raH0NCiAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuKGNhdCgnVmFyaWFuY2Vfb2ZfRXJyb3I9JywoaC8obGVuZ3RoKFkpLTIpKSkpfQ0KVmFyRXJyb3IoRkRJXzMsR0ZDRl8zKQ0KDQojIHVzaW5nIHdoaWxlIGxvb3ANClZhckVycm9yPWZ1bmN0aW9uKFgsWSl7Zz0oWS0oKG1lYW4oWSktKGNvdihYLFkpL3ZhcihYKSkqbWVhbihYKSkrKChjb3YoWCxZKS92YXIoWCkpKlgpKSleMjsNCiAgICAgICAgICAgICAgICAgICAgICAgaD0wO2k9MTsNCiAgICAgICAgICAgICAgICAgICAgICAgd2hpbGUoaTw9bGVuZ3RoKFkpKXtoPWdbaV0raDtpPWkrMX07DQogICAgICAgICAgICAgICAgICAgICAgIHJldHVybihjYXQoJyAgICBWYXJpYW5jZV9vZl9FcnJvcj0nLChoLyhsZW5ndGgoWSktMikpKSl9DQpWYXJFcnJvcihGRElfMyxHRkNGXzMpDQoNCiMgdXNpbmcgcmVwZWF0IGxvb3ANClZhckVycm9yPWZ1bmN0aW9uKFgsWSl7Zz0oWS0oKG1lYW4oWSktKGNvdihYLFkpL3ZhcihYKSkqbWVhbihYKSkrKChjb3YoWCxZKS92YXIoWCkpKlgpKSleMjsNCiAgICAgICAgICAgICAgICAgICAgICAgaD0wO2k9MTsNCiAgICAgICAgICAgICAgICAgICAgICAgcmVwZWF0e2g9Z1tpXStoO2k9aSsxO2lmKGk+bGVuZ3RoKFkpKXticmVha319Ow0KICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4oY2F0KCcgICAgVmFyaWFuY2Vfb2ZfRXJyb3I9JywoaC8obGVuZ3RoKFkpLTIpKSkpfQ0KVmFyRXJyb3IoRkRJXzMsR0ZDRl8zKQ0KYGBgDQoNCg0KKipJbnRlcmNlcHQgVmFyaWFuY2U6ICoqICRcaGF0e1xzaWdtYX1fe1xoYXR7XGFscGhhfX1eMiA9IFxzaWdtYV97XGVwc2lsb259XjJbXGZyYWN7MX17bn0rXGZyYWN7XGJhcntYfV4yfXtcc3VteyhYX2ktXGJhcntYfSl9XjJ9XSQNCg0KV2UgdXNlZCB0aGUgY29kZSBmb3IgdGhlIFJTUyBmb3IgdGhlIHZhcmlhbmNlIG9mIGVycm9yLCB0aGVuIHdlIHNpbXBseSByZXR1cm5lZCB0aGUgZm9ybXVsYSBpbiB0aGUgYHJldHVybmAgY29tbWFuZC4NCg0KYGBge3J9DQojIHVzaW5nIGZvciBsb29wDQpWYXJJbnRlcmNlcHQ9ZnVuY3Rpb24oWCxZKXtnPShZLSgobWVhbihZKS0oY292KFgsWSkvdmFyKFgpKSptZWFuKFgpKSsoKGNvdihYLFkpL3ZhcihYKSkqWCkpKV4yOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgaz0oWC1tZWFuKFgpKV4yOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgaD0wO3o9MDsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciAoIGkgaW4gMTpsZW5ndGgoWSkgKXtoPWdbaV0raDt6PWtbaV0ren07DQogICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4oY2F0KCdWYXJpYW5jZV9vZl9JbnRlcmNlcHQ9OicsKGgvKGxlbmd0aChZKS0yKSkqKCgxL2xlbmd0aChZKSkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKyhtZWFuKFgpXjIveikpKSl9DQpWYXJJbnRlcmNlcHQoRkRJXzMsR0ZDRl8zKQ0KDQojIHVzaW5nIHdoaWxlIGxvb3ANClZhckludGVyY2VwdD1mdW5jdGlvbihYLFkpe2c9KFktKChtZWFuKFkpLShjb3YoWCxZKS92YXIoWCkpKm1lYW4oWCkpKygoY292KFgsWSkvdmFyKFgpKSpYKSkpXjI7DQogICAgICAgICAgICAgICAgICAgICAgICAgICBrPShYLW1lYW4oWCkpXjI7DQogICAgICAgICAgICAgICAgICAgICAgICAgICBoPTA7ej0wO2k9MTsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWxlKGk8PWxlbmd0aChZKSl7aD1nW2ldK2g7ej1rW2ldK3o7aT1pKzF9Ow0KICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuKGNhdCgnICBWYXJpYW5jZV9vZl9JbnRlcmNlcHQ9OicsKGgvKGxlbmd0aChZKS0yKSkqKCgxL2xlbmd0aChZKSkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICArKG1lYW4oWCleMi96KSkpKX0NClZhckludGVyY2VwdChGRElfMyxHRkNGXzMpDQoNCiMgdXNpbmcgcmVwZWF0IGxvb3ANClZhckludGVyY2VwdD1mdW5jdGlvbihYLFkpe2c9KFktKChtZWFuKFkpLShjb3YoWCxZKS92YXIoWCkpKm1lYW4oWCkpKygoY292KFgsWSkvdmFyKFgpKSpYKSkpXjI7DQogICAgICAgICAgICAgICAgICAgICAgICAgICBrPShYLW1lYW4oWCkpXjI7DQogICAgICAgICAgICAgICAgICAgICAgICAgICBoPTA7ej0wO2k9MTsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcGVhdHtoPWdbaV0raDt6PWtbaV0rejtpPWkrMTtpZihpPmxlbmd0aChZKSl7YnJlYWt9fTsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybihjYXQoJyAgVmFyaWFuY2Vfb2ZfSW50ZXJjZXB0PTonLChoLyhsZW5ndGgoWSktMikpKigoMS9sZW5ndGgoWSkpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKyhtZWFuKFgpXjIveikpKSl9DQpWYXJJbnRlcmNlcHQoRkRJXzMsR0ZDRl8zKQ0KYGBgDQoNCg0KKipTbG9wZSB2YXJpYW5jZTogKiogJFxoYXR7XHNpZ21hfV97XGhhdHtcYmV0YX19XjIgPSBcZnJhY3tcc2lnbWFfe1xlcHNpbG9ufV4yfXtcc3VteyhYX2ktXGJhcntYfSl9XjJ9JA0KDQpTYW1lIG1ldGhvZCBhYm92ZS4gd2UgdXNlZCB0aGUgYHJldHVybmAgY29tbWFuZCB0byByZXR1cm4gdGhlIHZhbHVlIG9mIHRoZSBmdW5jdGlvbi4NCg0KYGBge3J9DQojIHVzaW5nIGZvciBsb29wDQpWYXJTbG9wZT1mdW5jdGlvbihYLFkpe2c9KFktKChtZWFuKFkpLShjb3YoWCxZKS92YXIoWCkpKm1lYW4oWCkpKygoY292KFgsWSkvdmFyKFgpKSpYKSkpXjI7DQogICAgICAgICAgICAgICAgICAgICAgIGs9KFgtbWVhbihYKSleMjsNCiAgICAgICAgICAgICAgICAgICAgICAgaD0wO3o9MDsNCiAgICAgICAgICAgICAgICAgICAgICAgZm9yKCBpIGluIDE6bGVuZ3RoKFkpKXtoPWdbaV0raDt6PWtbaV0ren07DQogICAgICAgICAgICAgICAgICAgICAgIHJldHVybihjYXQoJ1ZhcmlhbmNlX29mX1Nsb3BlPScsKGgvKGxlbmd0aChZKS0yKS96KSkpfQ0KVmFyU2xvcGUoRkRJXzMsR0ZDRl8zKQ0KDQojIHVzaW5nIHdoaWxlIGxvb3ANClZhclNsb3BlPWZ1bmN0aW9uKFgsWSl7Zz0oWS0oKG1lYW4oWSktKGNvdihYLFkpL3ZhcihYKSkqbWVhbihYKSkrKChjb3YoWCxZKS92YXIoWCkpKlgpKSleMjsNCiAgICAgICAgICAgICAgICAgICAgICAgaz0oWC1tZWFuKFgpKV4yOw0KICAgICAgICAgICAgICAgICAgICAgICBoPTA7ej0wO2k9MTsNCiAgICAgICAgICAgICAgICAgICAgICAgd2hpbGUoaTw9bGVuZ3RoKFkpKXtoPWdbaV0raDt6PWtbaV0rejtpPWkrMX07DQogICAgICAgICAgICAgICAgICAgICAgIHJldHVybihjYXQoJyAgICAgVmFyaWFuY2Vfb2ZfU2xvcGU9JywoaC8obGVuZ3RoKFkpLTIpL3opKSl9DQpWYXJTbG9wZShGRElfMyxHRkNGXzMpDQoNCiMgdXNpbmcgcmVwZWF0IGxvb3ANClZhclNsb3BlPWZ1bmN0aW9uKFgsWSl7Zz0oWS0oKG1lYW4oWSktKGNvdihYLFkpL3ZhcihYKSkqbWVhbihYKSkrKChjb3YoWCxZKS92YXIoWCkpKlgpKSleMjsNCiAgICAgICAgICAgICAgICAgICAgICAgaz0oWC1tZWFuKFgpKV4yOw0KICAgICAgICAgICAgICAgICAgICAgICBoPTA7ej0wO2k9MTsNCiAgICAgICAgICAgICAgICAgICAgICAgcmVwZWF0e2g9Z1tpXStoO3o9a1tpXSt6O2k9aSsxO2lmKGk+bGVuZ3RoKFkpKXticmVha319Ow0KICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4oY2F0KCcgICAgIFZhcmlhbmNlX29mX1Nsb3BlPScsKGgvKGxlbmd0aChZKS0yKS96KSkpfQ0KVmFyU2xvcGUoRkRJXzMsR0ZDRl8zKQ0KYGBgDQoNCg0KDQojIyBIeXBvdGhlc2lzIHRlc3RpbmcNCg0KKipTdHVkZW50IHRlc3Q6KiogJHRfe1xoYXR7XHJob319PSBcbWlke1xmcmFje1xoYXR7XHJob319e1xoYXR7XHNpZ21hfV97XGhhdHtccmhvfX19fVxtaWQkDQoNClRoaXMgY29kZSBsb29rcyBjb21wbGljYXRlZCBidXQgaXQgaXMgZmFyIGZyb20gdGhhdC4gTGV0J3MgYnJlYWsgaXQgZG93bjoNCg0KLSBGaXJzdCBXZSBzdG9ja2VkIHRoZSB2YWx1ZXMgb2YgdGhlIGludGVyY2VwdCBhbmQgdGhlIHNsb3BlLg0KLSBUaGUgJGckIHZhcmlhYmxlIGlzIHVzZWQgdG8gc3RvY2sgJChZX2ktXGhhdHtZX2l9KV4yJA0KLSBUaGUgJGskIHZhcmlhYmxlIGlzIHVzZWQgdG8gc3RvY2sgJChYX2ktXGJhcntYfSleMiQNCi0gJGgkIGFuZCAkeiQgYXJlIGluaXRpYWxpemVkIGFzIDAuIEF0IHRoZSBlbmQgb2YgdGhlIGl0ZXJhdGlvbnMgdGhleSB3aWxsIHJlc3BlY3RpdmVseSBlcXVhbCAgJFxzdW17KFlfaS1caGF0e1lfaX0pXjJ9JCBhbmQgJFxzdW17KFhfaS1cYmFye1h9KV4yfSQuDQotICoqU2RJbnRlcmNlcHQqKiBpcyB0byBjYWxjdWxhdGUgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgaW50ZXJjZXB0Lg0KLSAqKlNkU2xvcGUqKiBpcyB0byBjYWxjdWxhdGUgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgc2xvcGUuDQotICoqdEludGVyY2VwdCoqIGlzIHRoZSB2YWx1ZSBvZiB0aGUgc3R1ZGVudCB0ZXN0IGZvciB0aGUgaW50ZXJjZXB0IDogJHtcZnJhY3tcaGF0e1xhbHBoYX19e1xoYXR7XHNpZ21hfV97XGhhdHtcYWxwaGF9fX19JA0KLSAqKnRTbG9wZSoqIGlzIHRoZSB2YWx1ZSBvZiB0aGUgc3R1ZGVudCB0ZXN0IGZvciB0aGUgc2xvcGUgOiAke1xmcmFje1xoYXR7XGJldGF9fXtcaGF0e1xzaWdtYX1fe1xoYXR7XGJldGF9fX19JA0KLSBGaW5hbGx5IHdlIHdpbGwgdXNlIGBpZiBzdGF0ZW1lbnRzYCB0byBzZXQgdGhlIGNvbmRpdGlvbnMgZm9yIHRoZSB0ZXN0LiBGb3IgZXhhbXBsZSBgaWYoYWJzKHRJbnRlcmNlcHQpPnF0KDEtKGFscGhhLzIpLGxlbmd0aChZKS0yKSlgIG1lYW5zIHRoYXQgaWYgdGhlIGFic29sdXRlIHZhbHVlIG9mIHRoZSBpbnRlcmNlcHQncyB0LXRlc3QgaXMgaGlnaGVyIHRoYW4gdGhlIFN0dWRlbnQgdGhlb3JldGljYWwgdmFsdWUgY2FsY3VsYXRlZCB1c2luZyB0aGUgYHF0YCBmdW5jdGlvbiwgdGhlbiBUaGUgaW50ZXJjZXB0IGlzIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQuDQoNCmBgYHtyfQ0KdF90ZXN0PWZ1bmN0aW9uKFgsWSxhbHBoYSl7SW50ZXJjZXB0PW1lYW4oWSktKGNvdihYLFkpL3ZhcihYKSkqbWVhbihYKTsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFNsb3BlPWNvdihYLFkpL3ZhcihYKTsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGc9KFktKChtZWFuKFkpLShjb3YoWCxZKS92YXIoWCkpKm1lYW4oWCkpKygoY292KFgsWSkvdmFyKFgpKSpYKSkpXjI7DQogICAgICAgICAgICAgICAgICAgICAgICAgICBrPShYLW1lYW4oWCkpXjI7DQogICAgICAgICAgICAgICAgICAgICAgICAgICBoPTA7ej0wOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yICggaSBpbiAxOmxlbmd0aChZKSApe2g9Z1tpXStoO3o9a1tpXSt6fTsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFNkSW50ZXJjZXB0PXNxcnQoKGgvKGxlbmd0aChZKS0yKSkqKCgxL2xlbmd0aChZKSkrKG1lYW4oWCleMi96KSkpOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgU2RTbG9wZT1zcXJ0KGgvKGxlbmd0aChZKS0yKS96KTsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHRJbnRlcmNlcHQ9SW50ZXJjZXB0L1NkSW50ZXJjZXB0Ow0KICAgICAgICAgICAgICAgICAgICAgICAgICAgdFNsb3BlPVNsb3BlL1NkU2xvcGU7DQogICAgICAgICAgICAgICAgICAgICAgICAgICBpZihhYnModEludGVyY2VwdCk+cXQoMS0oYWxwaGEvMiksbGVuZ3RoKFkpLTIpKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAge3ByaW50KCdUaGUgaW50ZXJjZXB0IGlzIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQnKX07DQogICAgICAgICAgICAgICAgICAgICAgICAgICBpZihhYnModEludGVyY2VwdCk8PXF0KDEtKGFscGhhLzIpLGxlbmd0aChZKS0yKSkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHtwcmludCgnVGhlIGludGVyY2VwdCBpcyBzdGF0aXN0aWNhbGx5ICpub24qIHNpZ25pZmljYW50Jyl9Ow0KICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYoYWJzKHRTbG9wZSk+cXQoMS0oYWxwaGEvMiksbGVuZ3RoKFkpLTIpKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAge3ByaW50KCdUaGUgc2xvcGUgaXMgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCcpfTsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmKGFicyh0U2xvcGUpPD1xdCgxLShhbHBoYS8yKSxsZW5ndGgoWSktMikpDQogICAgICAgICAgICAgICAgICAgICAgICAgICB7cHJpbnQoJ1RoZSBzbG9wZSBpcyBzdGF0aXN0aWNhbGx5ICpub24qIHNpZ25pZmljYW50Jyl9fQ0KdF90ZXN0KEZESV8zLEdGQ0ZfMywwLjA1KQ0KYGBgDQoNCk5vdGUgdGhhdCB3ZSBhZGRlZCBhbiAqYWxwaGEqIGFzIGFuIGFyZ3VtZW50IHRvIHRoZSBmdW5jdGlvbiwgd2hpY2ggaXMgdGhlIGRlc2lyZWQgbGV2ZWwgb2Ygcmlzay10b2xlcmFuY2UuDQoNCmBgYHtyfQ0KIyByaXNrLXRvbGVyYW5jZSBsZXZlbCA9IDElDQp0X3Rlc3QoRkRJXzMsR0ZDRl8zLDAuMDEpDQpgYGANCg0KKipGaXNoZXIgdGVzdDoqKiAkRiA9IFxmcmFje1JeMn17XGZyYWN7MS1SXjJ9e24tay0xfX0kDQoNCkZvciB0aGUgRmlzaGVyIHRlc3Qgd2UgY2FsY3VsYXRlZCB0aGUgdGVzdCB2YWx1ZSB1c2luZyB0aGUgJFJeMiQsIHdoaWNoIGlzIGFsc28gdGhlIGNvZWZmY2llbnQgb2YgY29ycmVsYXRpb24gc3F1YXJlZCAoIGFub3RoZXIgZWFzeSB3YXkgdG8gY2FsY3VsYXRlIGl0ICkuDQoNClRvIGdldCB0aGUgdGhlb3JldGljYWwgdmFsdWVzIGZvciB0aGUgRmlzaGVyIHRlc3QsIHdlIHVzZSB0aGUgYHFmYCBmdW5jdGlvbi4NCg0KYGBge3J9DQpGX3Rlc3Q9ZnVuY3Rpb24oWCxZLGFscGhhKXtyPWNvdihYLFkpLyhzZChYKSpzZChZKSk7DQogICAgICAgICAgICAgICAgICAgICAgICAgICBSc3F1YXJlZD1yXjI7DQogICAgICAgICAgICAgICAgICAgICAgICAgICBGPVJzcXVhcmVkLygoMS1Sc3F1YXJlZCkvKGxlbmd0aChZKS0yKSk7DQogICAgICAgICAgICAgICAgICAgICAgICAgICBpZihGPnFmKDEtYWxwaGEsMSxsZW5ndGgoWSktMikpDQogICAgICAgICAgICAgICAgICAgICAgICAgICB7cHJpbnQoJ1RoZSBtb2RlbCBpcyBnbG9iYWxseSBzaWduaWZpY2F0aXZlJyl9Ow0KICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYoRjw9cWYoMS1hbHBoYSwxLGxlbmd0aChZKS0yKSkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHtwcmludCgnVGhlIG1vZGVsIGlzIGdsb2JhbGx5ICpub24qIHNpZ25pZmljYXRpdmUnKX19DQpGX3Rlc3QoRkRJXzMsR0ZDRl8zLDAuMDUpDQpgYGANCg0KYGBge3J9DQojIHJpc2stdG9sZXJhbmNlIGxldmVsID0gMSUNCkZfdGVzdChGRElfMyxHRkNGXzMsMC4wMSkNCmBgYA0KDQojIyBBTk9WQQ0KDQoqKkJvbnVzOioqIEFOT1ZBIHRhYmxlLiBUbyBjcmVhdGUgYW4gQU5PVkEgZnJvbSBzY3JhdGNoIGxpa2Ugd2UgZGlkIHdpdGggYWxsIHRoZSBhYm92ZSBhcHBsaWNhdGlvbnMsIHdlIHNpbXBseSBqdXN0IG9yZ2FuaXplIHRoZSBmdW5jdGlvbnMgaW4gYSBkYXRhZnJhbWUgYXMgZm9sbG93cyA6DQoNCmBgYHtyfQ0KaT0xOmxlbmd0aChHRkNGXzMpDQoNCkFOT1ZBPWRhdGEuZnJhbWUoU291cmNlPWMoIngxLHgyLC4uLix4biIsIlJlc2lkdWFsIiwiVG90YWwiKSwNCiAgICAgICAgICAgICAgICAgU3VtX1NxPWMoc3VtKChHRkNGX2hhdChGRElfMyxHRkNGXzMpW2ldLW1lYW4oR0ZDRl8zKSleMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgIHN1bSgoR0ZDRl8zW2ldLUdGQ0ZfaGF0KEZESV8zLEdGQ0ZfMylbaV0pXjIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBzdW0oKEdGQ0ZfM1tpXS1tZWFuKEdGQ0ZfMykpXjIpKSwNCiAgICAgICAgICAgICAgICAgZGY9YygyLGxlbmd0aChHRkNGXzMpLTMsbGVuZ3RoKEdGQ0ZfMyktMSksDQogICAgICAgICAgICAgICAgIE1lYW5fU3E9Yygoc3VtKChHRkNGX2hhdChGRElfMyxHRkNGXzMpW2ldLW1lYW4oR0ZDRl8zKSleMikpLzIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIChzdW0oKEdGQ0ZfM1tpXS1HRkNGX2hhdChGRElfMyxHRkNGXzMpW2ldKV4yKSkvKGxlbmd0aChHRkNGXzMpLTMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgKHN1bSgoR0ZDRl8zW2ldLW1lYW4oR0ZDRl8zKSleMikpLyhsZW5ndGgoR0ZDRl8zKS0xKSkpDQoNCnByaW50KEFOT1ZBKQ0KYGBgDQoNCiMjIFdoeSBpcyBTdGF0aW9uYXJpdHkgc28gaW1wb3J0YW50ICENCg0KU3RhdGlvbmFyaXR5IG1lYW5zIHRoYXQgdGhlIHN0YXRpc3RpY2FsIHByb3BlcnRpZXMgb2YgYSB0aW1lIHNlcmllcyBkbyBub3QgY2hhbmdlIG92ZXIgdGltZS4gSWYgeW91IGtlZXAgdGhlIHRyZW5kIG9yIHRoZSBzZWFzb25hbCBjb21wb25lbnRzIGluIHRoZSBzZXJpZXMsIHlvdXIgbW9kZWwgd2lsbCBiZSB3cm9uZyBiZWNhdXNlIGl0IHdpbGwgbW9kZWwgdGhlIGFjdHVhbCBjb21wb25lbnRzIGluc3RlYWQgb2YgdGhlIHJhdyB2YWx1ZXMsIHdoaWNoIHdpbGwgZ2VuZXJhdGUgZmFsc2UgaGlnaCBhY2N1cmFjeSBhbmQgYmlhc2VkIGluc2lnaHRzLg0KDQpCZWxvdyBpcyB0aGUgYnVpbHQtaW4gY29tbWFuZCB0byBwZXJmb3JtIGxpbmVhciByZWdyZXNzaW9uIGluIFIuIE5vdGUgdGhhdCBpbiB0aGUgZmlyc3QgcmVncmVzc2lvbiB3ZSB1c2VkIG5vbi1zdGF0aW9uYXJ5IGRhdGEgYW5kIHRoZSBtb2RlbCBzZWVtZWQgdG8gcGVyZm9ybSB3ZWxsIGFuZCBoYXMgaGlnaCBhY2N1cmFjeS4NCg0KSW4gdGhlIHNlY29uZCByZWdyZXNzaW9uIHdlIHVzZWQgc3RhdGlvbmFyeSB2ZWN0b3JzIGFuZCB0aGUgbW9kZWwgdHVybmVkIG91dCB0byBiZSBpbnNpZ25pZmljYW50LiBUaGlzIGRvZXNuJ3QgbWVhbiB0aGF0IHRoZSB0aGVvcnkgaXMgd3JvbmcgYXMgd2Ugb25seSB1c2VkIGEgc2ltcGxlIG1vZGVsIHdpdGggdHdvIHZhcmlhYmxlcy4gQWR2YW5jZWQgdGltZSBzZXJpZXMgbW9kZWxzIHdpdGggbXVsdGlwbGUgdmFyaWFibGVzIGNhbiBhY2N1cmF0ZWx5IGV4cGxhaW4gc3VjaCB0aGVvcmllcyBhbmQgZ2VuZXJhdGUgaW50ZXJlc3RpbmcgaW5zaWdodHMuIA0KDQpgYGB7cn0NCm1vZGVsID0gbG0oR0ZDRl8yIH4gRkRJXzIpDQpzdW1tYXJ5KG1vZGVsKQ0KYGBgDQoNCmBgYHtyfQ0KbW9kZWwgPSBsbShHRkNGXzMgfiBGRElfMykNCnN1bW1hcnkobW9kZWwpDQpgYGANCg==