require(readxl)
require(tidyverse)

Théorie pratique

Au sein de la séance concernant la stationnarisation, on a vu que - pour stationnariser un processus - il fallait passer les observations en différences. Si deux séries sont intégrées du même ordre d, on parle alors de cointégration : il peut exister une évolution de long-terme constante entre les deux séries. Cette cointégration rend les séries non-stationnaires car elles sont affectées toutes les deux d’une tendance de long-terme commune, et le modèle basique OLS ne suffit pas à isoler la relation entre \(X\) et \(Y\) de leur tendance commune.

En effet, utiliser un modèle OLS avec des variables qui ont une relation commune de long-terme - donc des variables endogènes va créer un problème de corrélation (donc de régression) fallacieuse (spurious correlation). Autrement dit, le coefficient de la régression va afficher un résultat significatif même si \(Y\) et \(X\) n’ont aucune relation réelle.

Un résumé (en anglais) concernant la cointégration peut être trouvé ici : https://www.jstor.org/stable/pdf/3592936.pdf

Il faut alors utiliser des Modèles à Correction d’Erreurs.

Cependant, ce n’est pas nécessairement le cas. Dans certaines configuration, on peut faire un modèle de régression qui n’est pas fallacieux. Pour vérifier s’il faut utiliser un modèle à correction d’erreur, il faut suivre l’algorithme en deux étapes d’Engle & Granger (https://www.jstor.org/stable/pdf/1913236.pdf) :

La première étape est d’estimer la relation de long-terme entre les deux variables : \[ Y_t = \beta X_t + \varepsilon_t \]

Si les résidus de cette régression sont stationnaires, alors il convient d’estimer le modèle à correction d’erreurs. Les résidus de cette régression peuvent être notés :

\[ \varepsilon_t = Y_t - \beta X_t \] et décrivent la relation de long-terme entre \(Y_t\) e\(X_t\).

La deuxième étape utilise, en plus de \(X_t\) en différence noté \(\Delta X_t\) le lag de ces résidus comme variable explicative de la série \(Y_t\) en différence, notée \(\Delta Y_t\), afin de capturer la relation de court-terme. Formellement, la régression est notée : \[ \Delta Y_t = \gamma \varepsilon_{t-1} + \alpha_1\Delta X_t + \mu_t \] Ici, la relation de court-terme est capturée par le coefficient \(\gamma\). Pour s’assurer que le modèle à correction d’erreur est le modèle approprié, il faut que ce coefficient soit significatif, et compris entre -1 et 0 : \[ -1 \le \gamma < 0 \] Le coefficient \(\gamma\) est aussi appelé force de rappel vers l’équilibre. C’est la vitesse à laquelle la série revient vers la relation de long-terme en cas de déviation : c’est la raison pour laquelle il faut que le coefficient associé à cette force de rappel soit négatif et significatif.

Si le coefficient \(\gamma\) ne respecte pas les conditions imposées par le modèle, alors on préferera utiliser le modèle OLS classique plutôt que le modèle à correction d’erreurs.

Application

On peut tester la relation entre la croissance des salaires et le niveau de chômage à l’échelle macroéconomique. Notamment, si on veut connaître l’effet de l’augmentation du niveau des salaires sur le taux de chômage - si on suit les séances qu’on a fait jusqu’à maintenant - on testerai la stationnarité, et on utiliserai les variables stationnaires dans la régression.

require(urca)
require(tidyverse)
data_schularick <- read_excel("C:/users/fkraus/Desktop/data_schularick.xlsx")
donnees_france <- data_schularick %>%
  filter(country=="France")%>%
  select(year, wage, unemp)%>%
  mutate(wage_growth = c(NA, diff(log(wage))*100 )) %>%
  mutate(d_wage_growth = c(NA, diff(wage_growth))) %>%
  mutate(d_unemp = c(NA, diff(unemp)))%>%
  #filter(year > 1950) %>%
  na.omit()

La première étape est de vérifier la présence d’une potentielle cointégration :


summary(ur.df(donnees_france$unemp, type="none")) # effectivement, c'est bien un DS

############################################### 
# Augmented Dickey-Fuller Test Unit Root Test # 
############################################### 

Test regression none 


Call:
lm(formula = z.diff ~ z.lag.1 - 1 + z.diff.lag)

Residuals:
    Min      1Q  Median      3Q     Max 
-7.1343 -0.2489  0.1880  0.6974  8.8330 

Coefficients:
           Estimate Std. Error t value Pr(>|t|)
z.lag.1    -0.02731    0.02304  -1.186    0.238
z.diff.lag  0.05434    0.09906   0.549    0.584

Residual standard error: 1.813 on 102 degrees of freedom
Multiple R-squared:  0.01515,   Adjusted R-squared:  -0.004164 
F-statistic: 0.7844 on 2 and 102 DF,  p-value: 0.4591


Value of test-statistic is: -1.1857 

Critical values for test statistics: 
      1pct  5pct 10pct
tau1 -2.58 -1.95 -1.62
summary(ur.df(diff(donnees_france$unemp), type="none"))

############################################### 
# Augmented Dickey-Fuller Test Unit Root Test # 
############################################### 

Test regression none 


Call:
lm(formula = z.diff ~ z.lag.1 - 1 + z.diff.lag)

Residuals:
    Min      1Q  Median      3Q     Max 
-7.3656 -0.4818 -0.0361  0.4951  8.8538 

Coefficients:
           Estimate Std. Error t value Pr(>|t|)    
z.lag.1    -1.11380    0.13615  -8.181 8.76e-13 ***
z.diff.lag  0.15950    0.09823   1.624    0.108    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.81 on 101 degrees of freedom
Multiple R-squared:  0.4935,    Adjusted R-squared:  0.4835 
F-statistic: 49.21 on 2 and 101 DF,  p-value: 1.204e-15


Value of test-statistic is: -8.1806 

Critical values for test statistics: 
      1pct  5pct 10pct
tau1 -2.58 -1.95 -1.62

summary(ur.df(donnees_france$wage_growth, type="none"))# non-stationnaire a 1%

############################################### 
# Augmented Dickey-Fuller Test Unit Root Test # 
############################################### 

Test regression none 


Call:
lm(formula = z.diff ~ z.lag.1 - 1 + z.diff.lag)

Residuals:
     Min       1Q   Median       3Q      Max 
-11.8623  -0.9928   0.2193   1.5765  25.9674 

Coefficients:
           Estimate Std. Error t value Pr(>|t|)    
z.lag.1    -0.15739    0.06499  -2.422 0.017211 *  
z.diff.lag -0.36637    0.09241  -3.965 0.000137 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 4.957 on 102 degrees of freedom
Multiple R-squared:  0.2408,    Adjusted R-squared:  0.2259 
F-statistic: 16.17 on 2 and 102 DF,  p-value: 7.935e-07


Value of test-statistic is: -2.4218 

Critical values for test statistics: 
      1pct  5pct 10pct
tau1 -2.58 -1.95 -1.62
summary(ur.df(donnees_france$d_wage_growth, type="none"))#stationnaire

############################################### 
# Augmented Dickey-Fuller Test Unit Root Test # 
############################################### 

Test regression none 


Call:
lm(formula = z.diff ~ z.lag.1 - 1 + z.diff.lag)

Residuals:
     Min       1Q   Median       3Q      Max 
-14.2640  -1.9744  -0.1527   1.2019  25.1798 

Coefficients:
           Estimate Std. Error t value Pr(>|t|)    
z.lag.1    -2.02645    0.15448 -13.118  < 2e-16 ***
z.diff.lag  0.40462    0.09094   4.449  2.2e-05 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 4.529 on 102 degrees of freedom
Multiple R-squared:  0.7655,    Adjusted R-squared:  0.7609 
F-statistic: 166.4 on 2 and 102 DF,  p-value: < 2.2e-16


Value of test-statistic is: -13.1177 

Critical values for test statistics: 
      1pct  5pct 10pct
tau1 -2.58 -1.95 -1.62

On peut voir que les deux séries (croissance des salaires, et taux de chômage) sont intégrées du même ordre : il faut passer les séries en différence première pour les stationnariser. On peut également le voir en faisant un auto.arima :

auto.arima(donnees_france$wage_growth)#0.1.0
Series: donnees_france$wage_growth 
ARIMA(2,1,0) 

Coefficients:
          ar1      ar2
      -0.6448  -0.4535
s.e.   0.0866   0.0857

sigma^2 = 20.27:  log likelihood = -306.31
AIC=618.62   AICc=618.86   BIC=626.58
auto.arima(donnees_france$unemp)#1.1.0
Series: donnees_france$unemp 
ARIMA(0,1,0) 

sigma^2 = 3.241:  log likelihood = -210.72
AIC=423.45   AICc=423.49   BIC=426.1

Les deux modèles optimaux pour nos variables sont des modèles ARMA avec un ordre d’intégration égal à 1. Il y a donc bien un risque de régression fallacieuse si on fait la régression classique. Si on suivait la procédure comme dans les séances précédentes, on aurait fait la régression suivante :

reg_spurious <- feols(d_unemp ~ d_wage_growth, data=donnees_france)
etable(reg_spurious)
                      reg_spurious
Dependent Var.:            d_unemp
                                  
Constant           0.0425 (0.1603)
d_wage_growth   -0.0865** (0.0296)
_______________ __________________
S.E. type                      IID
Observations                   106
R2                         0.07572
Adj. R2                    0.06684
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Etant donné la présence de cointégration dans notre modèle, on teste la validité du modèle à correction d’erreurs :

fs <-feols(unemp ~ wage_growth, data=donnees_france) #première étape
donnees_france$resid <- residuals(fs)

donnees_france_2 <- donnees_france %>%
  mutate(lresiduals = dplyr::lag(resid,1))

summary(ur.df(donnees_france$resid, type="none")) # les résidus ne sont pas stationnaires 

############################################### 
# Augmented Dickey-Fuller Test Unit Root Test # 
############################################### 

Test regression none 


Call:
lm(formula = z.diff ~ z.lag.1 - 1 + z.diff.lag)

Residuals:
    Min      1Q  Median      3Q     Max 
-4.9953 -0.8411  0.0229  0.8206  8.2357 

Coefficients:
           Estimate Std. Error t value Pr(>|t|)   
z.lag.1    -0.16609    0.06039  -2.750  0.00704 **
z.diff.lag -0.12643    0.09847  -1.284  0.20209   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.865 on 102 degrees of freedom
Multiple R-squared:  0.1094,    Adjusted R-squared:  0.0919 
F-statistic: 6.262 on 2 and 102 DF,  p-value: 0.002721


Value of test-statistic is: -2.7503 

Critical values for test statistics: 
      1pct  5pct 10pct
tau1 -2.58 -1.95 -1.62
ss <- feols(d_unemp ~ d_wage_growth +lresiduals,data=donnees_france_2) #deuxième étape
NOTE: 1 observation removed because of NA values (RHS: 1).
etable(ss)
                                ss
Dependent Var.:            d_unemp
                                  
Constant           0.0448 (0.1592)
d_wage_growth   -0.0981** (0.0298)
lresiduals       -0.1066* (0.0511)
_______________ __________________
S.E. type                      IID
Observations                   105
R2                         0.11349
Adj. R2                    0.09611
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Ici, les résidus de la première étape sont stationnaires, donc on peut s’attendre à accepter la validité de l’ECM. Egalement, on voit que le coefficient associé à lag(resid) est négatif, significatif et compris entre -1 et 0, donc on préferera utiliser le modèle à correction d’erreur plutôt qu’un OLS classique pour représenter la relation entre unemp et wage_growth.

LS0tDQp0aXRsZTogIlPDqWFuY2UgNyA6IE1vZMOobGVzIMOgIGNvcnJlY3Rpb24gZCdlcnJldXJzIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCmBgYHtyfQ0KcmVxdWlyZShyZWFkeGwpDQpyZXF1aXJlKHRpZHl2ZXJzZSkNCmBgYA0KDQojIFRow6lvcmllIHByYXRpcXVlDQpBdSBzZWluIGRlIGxhIHPDqWFuY2UgY29uY2VybmFudCBsYSBzdGF0aW9ubmFyaXNhdGlvbiwgb24gYSB2dSBxdWUgLSBwb3VyIHN0YXRpb25uYXJpc2VyIHVuIHByb2Nlc3N1cyAtIGlsIGZhbGxhaXQgcGFzc2VyIGxlcyBvYnNlcnZhdGlvbnMgZW4gZGlmZsOpcmVuY2VzLiBTaSBkZXV4IHPDqXJpZXMgc29udCBpbnTDqWdyw6llcyBkdSBtw6ptZSBvcmRyZSBgZGAsIG9uIHBhcmxlIGFsb3JzIGRlIGNvaW50w6lncmF0aW9uIDogaWwgKipwZXV0IGV4aXN0ZXIqKiB1bmUgw6l2b2x1dGlvbiBkZSBsb25nLXRlcm1lIGNvbnN0YW50ZSBlbnRyZSBsZXMgZGV1eCBzw6lyaWVzLiBDZXR0ZSBjb2ludMOpZ3JhdGlvbiByZW5kIGxlcyBzw6lyaWVzIG5vbi1zdGF0aW9ubmFpcmVzIGNhciBlbGxlcyBzb250IGFmZmVjdMOpZXMgdG91dGVzIGxlcyBkZXV4IGTigJl1bmUgdGVuZGFuY2UgZGUgbG9uZy10ZXJtZSBjb21tdW5lLCBldCBsZSBtb2TDqGxlIGJhc2lxdWUgT0xTIG5lIHN1ZmZpdCBwYXMgw6AgaXNvbGVyIGxhIHJlbGF0aW9uIGVudHJlICRYJCBldCAkWSQgZGUgbGV1ciB0ZW5kYW5jZSBjb21tdW5lLiANCg0KRW4gZWZmZXQsIHV0aWxpc2VyIHVuIG1vZMOobGUgT0xTIGF2ZWMgZGVzIHZhcmlhYmxlcyBxdWkgb250IHVuZSByZWxhdGlvbiBjb21tdW5lIGRlIGxvbmctdGVybWUgLSBkb25jIGRlcyB2YXJpYWJsZXMgZW5kb2fDqG5lcyB2YSBjcsOpZXIgdW4gcHJvYmzDqG1lIGRlIGNvcnLDqWxhdGlvbiAoZG9uYyBkZSByw6lncmVzc2lvbikgZmFsbGFjaWV1c2UgKCpzcHVyaW91cyBjb3JyZWxhdGlvbiopLiBBdXRyZW1lbnQgZGl0LCBsZSBjb2VmZmljaWVudCBkZSBsYSByw6lncmVzc2lvbiB2YSBhZmZpY2hlciB1biByw6lzdWx0YXQgc2lnbmlmaWNhdGlmIG3Dqm1lIHNpICRZJCBldCAkWCQgbidvbnQgYXVjdW5lIHJlbGF0aW9uIHLDqWVsbGUuDQoNClVuIHLDqXN1bcOpIChlbiBhbmdsYWlzKSBjb25jZXJuYW50IGxhIGNvaW50w6lncmF0aW9uIHBldXQgw6p0cmUgdHJvdXbDqSBpY2kgOiBodHRwczovL3d3dy5qc3Rvci5vcmcvc3RhYmxlL3BkZi8zNTkyOTM2LnBkZg0KDQpJbCBmYXV0IGFsb3JzIHV0aWxpc2VyIGRlcyAqTW9kw6hsZXMgw6AgQ29ycmVjdGlvbiBkJ0VycmV1cnMqLg0KDQpDZXBlbmRhbnQsIGNlIG4nZXN0IHBhcyBuw6ljZXNzYWlyZW1lbnQgbGUgY2FzLiBEYW5zIGNlcnRhaW5lcyBjb25maWd1cmF0aW9uLCBvbiBwZXV0IGZhaXJlIHVuIG1vZMOobGUgZGUgcsOpZ3Jlc3Npb24gcXVpIG4nZXN0IHBhcyBmYWxsYWNpZXV4LiBQb3VyIHbDqXJpZmllciBzJ2lsIGZhdXQgdXRpbGlzZXIgdW4gbW9kw6hsZSDDoCBjb3JyZWN0aW9uIGQnZXJyZXVyLCBpbCBmYXV0IHN1aXZyZSBsJ2FsZ29yaXRobWUgZW4gZGV1eCDDqXRhcGVzIGQnRW5nbGUgJiBHcmFuZ2VyIChodHRwczovL3d3dy5qc3Rvci5vcmcvc3RhYmxlL3BkZi8xOTEzMjM2LnBkZikgOg0KDQpMYSBwcmVtacOocmUgw6l0YXBlIGVzdCBkJ2VzdGltZXIgbGEgcmVsYXRpb24gZGUgbG9uZy10ZXJtZSBlbnRyZSBsZXMgZGV1eCB2YXJpYWJsZXMgOg0KJCQNCllfdCA9IFxiZXRhIFhfdCArIFx2YXJlcHNpbG9uX3QNCiQkDQoNClNpIGxlcyByw6lzaWR1cyBkZSBjZXR0ZSByw6lncmVzc2lvbiBzb250IHN0YXRpb25uYWlyZXMsIGFsb3JzIGlsIGNvbnZpZW50IGQnZXN0aW1lciBsZSBtb2TDqGxlIMOgIGNvcnJlY3Rpb24gZCdlcnJldXJzLiBMZXMgcsOpc2lkdXMgZGUgY2V0dGUgcsOpZ3Jlc3Npb24gcGV1dmVudCDDqnRyZSBub3TDqXMgOg0KDQokJA0KXHZhcmVwc2lsb25fdCA9IFlfdCAtIFxiZXRhIFhfdCANCiQkDQpldCBkw6ljcml2ZW50IGxhIHJlbGF0aW9uIGRlIGxvbmctdGVybWUgZW50cmUgJFlfdCQgZSRYX3QkLiANCg0KDQpMYSBkZXV4acOobWUgw6l0YXBlIHV0aWxpc2UsIGVuIHBsdXMgZGUgJFhfdCQgZW4gZGlmZsOpcmVuY2Ugbm90w6kgJFxEZWx0YSBYX3QkIGxlIGxhZyBkZSBjZXMgcsOpc2lkdXMgY29tbWUgdmFyaWFibGUgZXhwbGljYXRpdmUgZGUgbGEgc8OpcmllICRZX3QkIGVuIGRpZmbDqXJlbmNlLCBub3TDqWUgJFxEZWx0YSBZX3QkLCBhZmluIGRlIGNhcHR1cmVyIGxhIHJlbGF0aW9uIGRlIGNvdXJ0LXRlcm1lLiBGb3JtZWxsZW1lbnQsIGxhIHLDqWdyZXNzaW9uIGVzdCBub3TDqWUgOg0KJCQNClxEZWx0YSBZX3QgPSBcZ2FtbWEgXHZhcmVwc2lsb25fe3QtMX0gKyBcYWxwaGFfMVxEZWx0YSBYX3QgKyBcbXVfdA0KJCQNCkljaSwgbGEgcmVsYXRpb24gZGUgY291cnQtdGVybWUgZXN0IGNhcHR1csOpZSBwYXIgbGUgY29lZmZpY2llbnQgJFxnYW1tYSQuIFBvdXIgcydhc3N1cmVyIHF1ZSBsZSBtb2TDqGxlIMOgIGNvcnJlY3Rpb24gZCdlcnJldXIgZXN0IGxlIG1vZMOobGUgYXBwcm9wcmnDqSwgaWwgZmF1dCBxdWUgY2UgY29lZmZpY2llbnQgc29pdCBzaWduaWZpY2F0aWYsIGV0IGNvbXByaXMgZW50cmUgLTEgZXQgMCA6DQokJA0KLTEgXGxlIFxnYW1tYSA8IDAgDQokJA0KTGUgY29lZmZpY2llbnQgJFxnYW1tYSQgZXN0IGF1c3NpIGFwcGVsw6kgZm9yY2UgZGUgcmFwcGVsIHZlcnMgbOKAmcOpcXVpbGlicmUuIEMnZXN0IGxhIHZpdGVzc2Ugw6AgbGFxdWVsbGUgbGEgc8OpcmllIHJldmllbnQgdmVycyBsYSByZWxhdGlvbiBkZSBsb25nLXRlcm1lIGVuIGNhcyBkZSBkw6l2aWF0aW9uIDogYydlc3QgbGEgcmFpc29uIHBvdXIgbGFxdWVsbGUgaWwgZmF1dCBxdWUgbGUgY29lZmZpY2llbnQgYXNzb2Npw6kgw6AgY2V0dGUgZm9yY2UgZGUgcmFwcGVsIHNvaXQgbsOpZ2F0aWYgZXQgc2lnbmlmaWNhdGlmLg0KDQpTaSBsZSBjb2VmZmljaWVudCAkXGdhbW1hJCBuZSByZXNwZWN0ZSBwYXMgbGVzIGNvbmRpdGlvbnMgaW1wb3PDqWVzIHBhciBsZSBtb2TDqGxlLCBhbG9ycyBvbiBwcsOpZmVyZXJhIHV0aWxpc2VyIGxlIG1vZMOobGUgT0xTIGNsYXNzaXF1ZSBwbHV0w7R0IHF1ZSBsZSBtb2TDqGxlIMOgIGNvcnJlY3Rpb24gZCdlcnJldXJzLg0KDQojIEFwcGxpY2F0aW9uDQoNCk9uIHBldXQgdGVzdGVyIGxhIHJlbGF0aW9uIGVudHJlIGxhIGNyb2lzc2FuY2UgZGVzIHNhbGFpcmVzIGV0IGxlIG5pdmVhdSBkZSBjaMO0bWFnZSDDoCBsJ8OpY2hlbGxlIG1hY3Jvw6ljb25vbWlxdWUuIE5vdGFtbWVudCwgc2kgb24gdmV1dCBjb25uYcOudHJlIGwnZWZmZXQgZGUgbCdhdWdtZW50YXRpb24gZHUgbml2ZWF1IGRlcyBzYWxhaXJlcyBzdXIgbGUgdGF1eCBkZSBjaMO0bWFnZSAtIHNpIG9uIHN1aXQgbGVzIHPDqWFuY2VzIHF1J29uIGEgZmFpdCBqdXNxdSfDoCBtYWludGVuYW50IC0gb24gdGVzdGVyYWkgbGEgc3RhdGlvbm5hcml0w6ksIGV0IG9uIHV0aWxpc2VyYWkgbGVzIHZhcmlhYmxlcyBzdGF0aW9ubmFpcmVzIGRhbnMgbGEgcsOpZ3Jlc3Npb24uIA0KDQpgYGB7cn0NCnJlcXVpcmUodXJjYSkNCnJlcXVpcmUodGlkeXZlcnNlKQ0KZGF0YV9zY2h1bGFyaWNrIDwtIHJlYWRfZXhjZWwoIkM6L3VzZXJzL2ZrcmF1cy9EZXNrdG9wL2RhdGFfc2NodWxhcmljay54bHN4IikNCmRvbm5lZXNfZnJhbmNlIDwtIGRhdGFfc2NodWxhcmljayAlPiUNCiAgZmlsdGVyKGNvdW50cnk9PSJGcmFuY2UiKSU+JQ0KICBzZWxlY3QoeWVhciwgd2FnZSwgdW5lbXApJT4lDQogIG11dGF0ZSh3YWdlX2dyb3d0aCA9IGMoTkEsIGRpZmYobG9nKHdhZ2UpKSoxMDAgKSkgJT4lDQogIG11dGF0ZShkX3dhZ2VfZ3Jvd3RoID0gYyhOQSwgZGlmZih3YWdlX2dyb3d0aCkpKSAlPiUNCiAgbXV0YXRlKGRfdW5lbXAgPSBjKE5BLCBkaWZmKHVuZW1wKSkpJT4lDQogICNmaWx0ZXIoeWVhciA+IDE5NTApICU+JQ0KICBuYS5vbWl0KCkNCg0KYGBgDQoNCg0KDQpMYSBwcmVtacOocmUgw6l0YXBlIGVzdCBkZSB2w6lyaWZpZXIgbGEgcHLDqXNlbmNlIGQndW5lIHBvdGVudGllbGxlIGNvaW50w6lncmF0aW9uIDoNCmBgYHtyfQ0KDQpzdW1tYXJ5KHVyLmRmKGRvbm5lZXNfZnJhbmNlJHVuZW1wLCB0eXBlPSJub25lIikpICNub24tc3RhdGlvbm5haXJlIMOgIDElDQpzdW1tYXJ5KHVyLmRmKGRpZmYoZG9ubmVlc19mcmFuY2UkdW5lbXApLCB0eXBlPSJub25lIikpICMgc3RhdGlvbm5haXJlDQpgYGANCmBgYHtyfQ0KDQpzdW1tYXJ5KHVyLmRmKGRvbm5lZXNfZnJhbmNlJHdhZ2VfZ3Jvd3RoLCB0eXBlPSJub25lIikpIyBub24tc3RhdGlvbm5haXJlIGEgMSUNCnN1bW1hcnkodXIuZGYoZG9ubmVlc19mcmFuY2UkZF93YWdlX2dyb3d0aCwgdHlwZT0ibm9uZSIpKSNzdGF0aW9ubmFpcmUgw6AgMSUNCg0KYGBgDQpPbiBwZXV0IHZvaXIgcXVlIGxlcyBkZXV4IHPDqXJpZXMgKGNyb2lzc2FuY2UgZGVzIHNhbGFpcmVzLCBldCB0YXV4IGRlIGNow7RtYWdlKSBzb250IGludMOpZ3LDqWVzIGR1IG3Dqm1lIG9yZHJlIDogaWwgZmF1dCBwYXNzZXIgbGVzIHPDqXJpZXMgZW4gZGlmZsOpcmVuY2UgcHJlbWnDqHJlIHBvdXIgbGVzIHN0YXRpb25uYXJpc2VyLiBPbiBwZXV0IMOpZ2FsZW1lbnQgbGUgdm9pciBlbiBmYWlzYW50IHVuIGF1dG8uYXJpbWEgOg0KDQpgYGB7cn0NCmF1dG8uYXJpbWEoZG9ubmVlc19mcmFuY2Ukd2FnZV9ncm93dGgpIzIuMS4wDQphdXRvLmFyaW1hKGRvbm5lZXNfZnJhbmNlJHVuZW1wKSMwLjEuMA0KYGBgDQpMZXMgZGV1eCBtb2TDqGxlcyBvcHRpbWF1eCBwb3VyIG5vcyB2YXJpYWJsZXMgc29udCBkZXMgbW9kw6hsZXMgQVJNQSBhdmVjIHVuIG9yZHJlIGQnaW50w6lncmF0aW9uIMOpZ2FsIMOgIDEuIElsIHkgYSBkb25jIGJpZW4gdW4gcmlzcXVlIGRlIHLDqWdyZXNzaW9uIGZhbGxhY2lldXNlIHNpIG9uIGZhaXQgbGEgcsOpZ3Jlc3Npb24gY2xhc3NpcXVlLiBTaSBvbiBzdWl2YWl0IGxhIHByb2PDqWR1cmUgY29tbWUgZGFucyBsZXMgc8OpYW5jZXMgcHLDqWPDqWRlbnRlcywgb24gYXVyYWl0IGZhaXQgbGEgcsOpZ3Jlc3Npb24gc3VpdmFudGUgOg0KYGBge3J9DQpyZWdfc3B1cmlvdXMgPC0gZmVvbHMoZF91bmVtcCB+IGRfd2FnZV9ncm93dGgsIGRhdGE9ZG9ubmVlc19mcmFuY2UpDQpldGFibGUocmVnX3NwdXJpb3VzKQ0KYGBgDQpFdGFudCBkb25uw6kgbGEgcHLDqXNlbmNlIGRlIGNvaW50w6lncmF0aW9uIGRhbnMgbm90cmUgbW9kw6hsZSwgb24gdGVzdGUgbGEgdmFsaWRpdMOpIGR1IG1vZMOobGUgw6AgY29ycmVjdGlvbiBkJ2VycmV1cnMgOg0KDQpgYGB7cn0NCmZzIDwtZmVvbHModW5lbXAgfiB3YWdlX2dyb3d0aCwgZGF0YT1kb25uZWVzX2ZyYW5jZSkgI3ByZW1pw6hyZSDDqXRhcGUNCmRvbm5lZXNfZnJhbmNlJHJlc2lkIDwtIHJlc2lkdWFscyhmcykNCg0KZG9ubmVlc19mcmFuY2VfMiA8LSBkb25uZWVzX2ZyYW5jZSAlPiUNCiAgbXV0YXRlKGxyZXNpZHVhbHMgPSBkcGx5cjo6bGFnKHJlc2lkLDEpKQ0KDQpzdW1tYXJ5KHVyLmRmKGRvbm5lZXNfZnJhbmNlJHJlc2lkLCB0eXBlPSJub25lIikpICMgbGVzIHLDqXNpZHVzIG5lIHNvbnQgcGFzIHN0YXRpb25uYWlyZXMgDQoNCnNzIDwtIGZlb2xzKGRfdW5lbXAgfiBkX3dhZ2VfZ3Jvd3RoICtscmVzaWR1YWxzLGRhdGE9ZG9ubmVlc19mcmFuY2VfMikgI2RldXhpw6htZSDDqXRhcGUNCmV0YWJsZShzcykNCmBgYA0KDQpJY2ksIGxlcyByw6lzaWR1cyBkZSBsYSBwcmVtacOocmUgw6l0YXBlIHNvbnQgc3RhdGlvbm5haXJlcywgZG9uYyBvbiBwZXV0IHMnYXR0ZW5kcmUgw6AgYWNjZXB0ZXIgbGEgdmFsaWRpdMOpIGRlIGwnRUNNLiBFZ2FsZW1lbnQsIG9uIHZvaXQgcXVlIGxlIGNvZWZmaWNpZW50IGFzc29jacOpIMOgIGBsYWcocmVzaWQpYCBlc3QgbsOpZ2F0aWYsIHNpZ25pZmljYXRpZiBldCBjb21wcmlzIGVudHJlIC0xIGV0IDAsIGRvbmMgb24gcHLDqWZlcmVyYSB1dGlsaXNlciBsZSBtb2TDqGxlIMOgIGNvcnJlY3Rpb24gZCdlcnJldXIgcGx1dMO0dCBxdSd1biBPTFMgY2xhc3NpcXVlIHBvdXIgcmVwcsOpc2VudGVyIGxhIHJlbGF0aW9uIGVudHJlIGB1bmVtcGAgZXQgYHdhZ2VfZ3Jvd3RoYC4NCg0KDQoNCg0K