On enregistre le chemin du dossier :

setwd("C:/Users/fkraus/Desktop/TD/2025-2026/ECONOMETRIE/séance2")

et on importe les données

donnees <- read_excel("C:/Users/fkraus/Desktop/data_schularick.xlsx") %>%
  filter(country=="France")

head(donnees)

En économétrie, si on veut effectuer la régression suivante : \[\begin{equation} Y_t = a_0 + \beta X_t + \varepsilon_t \end{equation}\]

Il faut d’abord s’assurer que \(Y_t\) et \(X_t\) sont stationnaires, sinon l’estimation du coefficient \(\beta\) associé à \(X_t\) risque d’être biaisé (donc ne reflète pas la vraie relation entre les deux variables). Si ce n’est pas le cas, il faut les stationnariser en respectant la bonne approche (voir le rappel de cours).

Si on s’intéresse par exemple aux salaires :

donnees_wage <- donnees %>%
  select(year, wage) %>%
  mutate(wage_growth = (log(wage)- lag(log(wage)))*100 )%>%
  mutate(dwage_growth = wage_growth- lag(wage_growth))%>%

  mutate(dwage = wage- lag(wage))%>%
  mutate(ddwage = dwage- lag(dwage))%>%

  filter(year >= 1960) %>%
  na.omit()

head(donnees_wage)

ggplot(donnees_wage, aes(x=year, y=wage))+
  geom_line(lwd=1)+
  theme_bw()

La série ne semble pas être stationnaire : la moyenne n’est pas 0, la série semble être autocorrélée et dépendente du temps. On peut le vérifier rapidement avec un autocorrélogramme

acf(donnees_wage$wage)

La série est autocorrélée, au moins jusqu’à 15 lags. On peut vérifier formellement la non-stationnarité avec le test de Dickey-Fuller simple (sans trend ni constante) :

summary(ur.df(donnees_wage$wage, 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.5505 -0.4883  0.2147  0.9324  4.4657 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
z.lag.1    -0.001323   0.002940   -0.45    0.654    
z.diff.lag  0.955035   0.087201   10.95 1.21e-15 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.608 on 57 degrees of freedom
Multiple R-squared:  0.8298,    Adjusted R-squared:  0.8238 
F-statistic: 138.9 on 2 and 57 DF,  p-value: < 2.2e-16


Value of test-statistic is: -0.4501 

Critical values for test statistics: 
     1pct  5pct 10pct
tau1 -2.6 -1.95 -1.61

On voit que la t-stat est inférieure à la valeur critique en valeur absolue. La série n’est donc effectivement pas stationnaire. Il s’agit donc maintenant de déterminer quel est le type de non-stationnarité : TS ou DS.

La première étape est de tester le modèle avec tendance :

summary(ur.df(donnees_wage$wage, type="trend"))

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

Test regression trend 


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

Residuals:
    Min      1Q  Median      3Q     Max 
-7.7181 -0.5671 -0.2237  0.6397  4.4543 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  0.04774    0.70143   0.068    0.946    
z.lag.1     -0.04146    0.02573  -1.611    0.113    
tt           0.13807    0.09529   1.449    0.153    
z.diff.lag   0.81708    0.10594   7.713 2.57e-10 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.56 on 55 degrees of freedom
Multiple R-squared:  0.5487,    Adjusted R-squared:  0.5241 
F-statistic: 22.29 on 3 and 55 DF,  p-value: 1.416e-09


Value of test-statistic is: -1.6114 1.9189 1.9625 

Critical values for test statistics: 
      1pct  5pct 10pct
tau3 -4.04 -3.45 -3.15
phi2  6.50  4.88  4.16
phi3  8.73  6.49  5.47

La trend tt n’est pas significative, donc ça n’est pas un TS. La série n’est également pas stationnaire au vue des t-stats. On teste donc le modèle avec constante :

summary(ur.df(donnees_wage$wage, type="drift"))

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

Test regression drift 


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

Residuals:
    Min      1Q  Median      3Q     Max 
-7.4485 -0.7179 -0.1890  0.6986  4.5739 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)  0.830322   0.451908   1.837   0.0715 .  
z.lag.1     -0.004492   0.003357  -1.338   0.1863    
z.diff.lag   0.840684   0.105703   7.953 9.23e-11 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.575 on 56 degrees of freedom
Multiple R-squared:  0.5315,    Adjusted R-squared:  0.5148 
F-statistic: 31.77 on 2 and 56 DF,  p-value: 6.024e-10


Value of test-statistic is: -1.3381 1.7935 

Critical values for test statistics: 
      1pct  5pct 10pct
tau2 -3.51 -2.89 -2.58
phi1  6.70  4.71  3.86

La constante est significative à 10% seulement (donc faiblement significative, mais il y a peut-être un drift) et est non-stationnaire. Cela indique que la série est sûrement un DS.

On peut essayer de voir si la série en différence première est stationnaire. La série en différence première ressemble à ça :

ggplot(donnees_wage, aes(x=year, y=dwage))+
  geom_line()+
  theme_bw()

En faisant le test de Dickey Fuller sans trend ni drift :

summary(ur.df(donnees_wage$dwage, 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.8761 -0.4656  0.1566  0.8051  4.5683 

Coefficients:
           Estimate Std. Error t value Pr(>|t|)
z.lag.1     -0.0592     0.0552  -1.072    0.288
z.diff.lag  -0.2767     0.1689  -1.639    0.107

Residual standard error: 1.574 on 57 degrees of freedom
Multiple R-squared:  0.07473,   Adjusted R-squared:  0.04226 
F-statistic: 2.302 on 2 and 57 DF,  p-value: 0.1093


Value of test-statistic is: -1.0723 

Critical values for test statistics: 
     1pct  5pct 10pct
tau1 -2.6 -1.95 -1.61

On voit que la série en différence n’est pas stationnaire. Il faudrait donc la passer en deuxième différence éventuellement. La série en deuxième différence ressemble à :

ggplot(donnees_wage, aes(x=year, y=ddwage))+
  geom_line()+
  theme_bw()

Et le test de ADF sans trend ni constante :

summary(ur.df(donnees_wage$ddwage, 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.7822 -0.6872 -0.0051  0.8011  3.8641 

Coefficients:
           Estimate Std. Error t value Pr(>|t|)   
z.lag.1     -0.9537     0.2875  -3.317  0.00159 **
z.diff.lag  -0.2643     0.1754  -1.507  0.13744   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.559 on 57 degrees of freedom
Multiple R-squared:  0.5347,    Adjusted R-squared:  0.5183 
F-statistic: 32.75 on 2 and 57 DF,  p-value: 3.401e-10


Value of test-statistic is: -3.3174 

Critical values for test statistics: 
     1pct  5pct 10pct
tau1 -2.6 -1.95 -1.61

Ici, la série apparaît stationnaire. On peut vérifier qu’elle ne possède pas de trend ni de constante avec les tests avec trend et avec constante :

summary(ur.df(donnees_wage$ddwage, type="trend"))

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

Test regression trend 


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

Residuals:
    Min      1Q  Median      3Q     Max 
-7.1615 -0.4416  0.0439  0.8844  3.8220 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  0.49561    0.42274   1.172 0.246098    
z.lag.1     -1.00288    0.28834  -3.478 0.000995 ***
tt          -0.01912    0.01193  -1.603 0.114654    
z.diff.lag  -0.24092    0.17534  -1.374 0.175008    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.548 on 55 degrees of freedom
Multiple R-squared:  0.5557,    Adjusted R-squared:  0.5314 
F-statistic: 22.93 on 3 and 55 DF,  p-value: 9.303e-10


Value of test-statistic is: -3.4781 4.6586 6.7385 

Critical values for test statistics: 
      1pct  5pct 10pct
tau3 -4.04 -3.45 -3.15
phi2  6.50  4.88  4.16
phi3  8.73  6.49  5.47

La trend n’est pas significative. Et on peut tester avec le modèle sans trend mais avec constante :

summary(ur.df(donnees_wage$ddwage, type="drift"))

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

Test regression drift 


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

Residuals:
    Min      1Q  Median      3Q     Max 
-7.6766 -0.5904  0.0940  0.9070  3.9575 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)   
(Intercept) -0.09976    0.20473  -0.487  0.62798   
z.lag.1     -0.94471    0.29003  -3.257  0.00191 **
z.diff.lag  -0.26902    0.17689  -1.521  0.13394   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.569 on 56 degrees of freedom
Multiple R-squared:  0.5349,    Adjusted R-squared:  0.5183 
F-statistic:  32.2 on 2 and 56 DF,  p-value: 4.914e-10


Value of test-statistic is: -3.2573 5.5476 

Critical values for test statistics: 
      1pct  5pct 10pct
tau2 -3.51 -2.89 -2.58
phi1  6.70  4.71  3.86

La constante n’est pas significative. On confirme donc que la série est bien stationnaire en deuxième différence, elle est intégrée d’ordre 2 : \(I(2)\).

Un autre moyen, souvent beaucoup plus rapide, est d’utiliser la différence de logarithme (approximation du taux de croissance, voir séance 1). La série de taux de croissance des salaires ressemble à :

ggplot(donnees_wage, aes(x=year, y=wage_growth))+
  geom_line()+
  theme_bw()

On peut tester la stationnarité sur la série en niveau:

summary(ur.df(donnees_wage$wage_growth, 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 
-5.4265 -0.8092  0.0276  1.0395  5.4030 

Coefficients:
           Estimate Std. Error t value Pr(>|t|)
z.lag.1    -0.03734    0.03129  -1.194    0.238
z.diff.lag -0.06192    0.13512  -0.458    0.649

Residual standard error: 1.913 on 57 degrees of freedom
Multiple R-squared:  0.0297,    Adjusted R-squared:  -0.004345 
F-statistic: 0.8724 on 2 and 57 DF,  p-value: 0.4235


Value of test-statistic is: -1.1936 

Critical values for test statistics: 
     1pct  5pct 10pct
tau1 -2.6 -1.95 -1.61

La série n’est pas stationnaire. On peut regarder quel est le type de non-stationnarité :

summary(ur.df(donnees_wage$wage_growth, type="trend"))

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

Test regression trend 


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

Residuals:
    Min      1Q  Median      3Q     Max 
-4.6965 -1.0707 -0.0846  0.8896  5.8030 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)  
(Intercept)  1.87140    1.02273   1.830   0.0727 .
z.lag.1     -0.13897    0.07024  -1.979   0.0529 .
tt          -0.03916    0.02045  -1.915   0.0607 .
z.diff.lag  -0.02744    0.13655  -0.201   0.8415  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.885 on 55 degrees of freedom
Multiple R-squared:  0.08066,   Adjusted R-squared:  0.03052 
F-statistic: 1.609 on 3 and 55 DF,  p-value: 0.1979


Value of test-statistic is: -1.9786 1.7207 2.2225 

Critical values for test statistics: 
      1pct  5pct 10pct
tau3 -4.04 -3.45 -3.15
phi2  6.50  4.88  4.16
phi3  8.73  6.49  5.47

La trend est significative à 10%, et l’autocorrélation est également significative : la série suit donc un processus DS, et il faut la passer en différence pour la rendre potentiellement stationnaire.

summary(ur.df(donnees_wage$dwage_growth, 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 
-5.9796 -1.0785 -0.1413  0.8066  4.9599 

Coefficients:
           Estimate Std. Error t value Pr(>|t|)    
z.lag.1    -1.00872    0.19986  -5.047 4.89e-06 ***
z.diff.lag -0.06274    0.13628  -0.460    0.647    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.933 on 57 degrees of freedom
Multiple R-squared:  0.5243,    Adjusted R-squared:  0.5076 
F-statistic: 31.41 on 2 and 57 DF,  p-value: 6.38e-10


Value of test-statistic is: -5.047 

Critical values for test statistics: 
     1pct  5pct 10pct
tau1 -2.6 -1.95 -1.61

Ici, au vu de la t-stat, la série de croissance des salaires (wage_growth) est stationnaire en différence première, elle est intégrée d’ordre 1 : \(I(1)\).

En séries temporelles, il faut s’assurer que la totalité des variables qui sont incluses dans un modèle de régression soient stationnaires, donc il faut répéter cette opération autant de fois qu’il y a de variables.

LS0tDQp0aXRsZTogIlIgTm90ZWJvb2sgOiBTdGF0aW9ubmFyaXTDqSBldCBBdXRvY29ycsOpbGF0aW9uIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGRmX3ByaW50OiBwYWdlZA0KICBodG1sX25vdGVib29rOiANCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZGVwdGg6IDMNCiAgICB0b2NfZmxvYXQ6IGZhbHNlDQogIHdvcmRfZG9jdW1lbnQ6IGRlZmF1bHQNCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0DQotLS0NCg0KT24gZW5yZWdpc3RyZSBsZSBjaGVtaW4gZHUgZG9zc2llciA6DQpgYGB7cn0NCnNldHdkKCJDOi9Vc2Vycy9ma3JhdXMvRGVza3RvcC9URC8yMDI1LTIwMjYvRUNPTk9NRVRSSUUvc8OpYW5jZTIiKQ0KYGBgDQoNCmV0IG9uIGltcG9ydGUgbGVzIGRvbm7DqWVzDQpgYGB7cn0NCmRvbm5lZXMgPC0gcmVhZF9leGNlbCgiQzovVXNlcnMvZmtyYXVzL0Rlc2t0b3AvZGF0YV9zY2h1bGFyaWNrLnhsc3giKSAlPiUNCiAgZmlsdGVyKGNvdW50cnk9PSJGcmFuY2UiKQ0KDQpoZWFkKGRvbm5lZXMpDQpgYGANCg0KDQpFbiDDqWNvbm9tw6l0cmllLCBzaSBvbiB2ZXV0IGVmZmVjdHVlciBsYSByw6lncmVzc2lvbiBzdWl2YW50ZSA6DQpcYmVnaW57ZXF1YXRpb259DQogWV90ID0gYV8wICsgXGJldGEgWF90ICsgXHZhcmVwc2lsb25fdA0KXGVuZHtlcXVhdGlvbn0NCg0KSWwgZmF1dCBkJ2Fib3JkIHMnYXNzdXJlciBxdWUgJFlfdCQgZXQgJFhfdCQgc29udCAqKnN0YXRpb25uYWlyZXMqKiwgc2lub24gbCdlc3RpbWF0aW9uIGR1IGNvZWZmaWNpZW50ICRcYmV0YSQgYXNzb2Npw6kgw6AgJFhfdCQgcmlzcXVlIGQnw6p0cmUgYmlhaXPDqSAoZG9uYyBuZSByZWZsw6h0ZSBwYXMgbGEgKip2cmFpZSoqIHJlbGF0aW9uIGVudHJlIGxlcyBkZXV4IHZhcmlhYmxlcykuIFNpIGNlIG4nZXN0IHBhcyBsZSBjYXMsIGlsIGZhdXQgbGVzIHN0YXRpb25uYXJpc2VyIGVuIHJlc3BlY3RhbnQgbGEgYm9ubmUgYXBwcm9jaGUgKHZvaXIgbGUgcmFwcGVsIGRlIGNvdXJzKS4gDQoNClNpIG9uIHMnaW50w6lyZXNzZSBwYXIgZXhlbXBsZSBhdXggc2FsYWlyZXMgOg0KYGBge3J9DQpkb25uZWVzX3dhZ2UgPC0gZG9ubmVlcyAlPiUNCiAgc2VsZWN0KHllYXIsIHdhZ2UpICU+JQ0KICBtdXRhdGUod2FnZV9ncm93dGggPSAobG9nKHdhZ2UpLSBsYWcobG9nKHdhZ2UpKSkqMTAwICklPiUNCiAgbXV0YXRlKGR3YWdlX2dyb3d0aCA9IHdhZ2VfZ3Jvd3RoLSBsYWcod2FnZV9ncm93dGgpKSU+JQ0KDQogIG11dGF0ZShkd2FnZSA9IHdhZ2UtIGxhZyh3YWdlKSklPiUNCiAgbXV0YXRlKGRkd2FnZSA9IGR3YWdlLSBsYWcoZHdhZ2UpKSU+JQ0KDQogIGZpbHRlcih5ZWFyID49IDE5NjApICU+JQ0KICBuYS5vbWl0KCkNCg0KaGVhZChkb25uZWVzX3dhZ2UpDQoNCmdncGxvdChkb25uZWVzX3dhZ2UsIGFlcyh4PXllYXIsIHk9d2FnZSkpKw0KICBnZW9tX2xpbmUobHdkPTEpKw0KICB0aGVtZV9idygpDQpgYGANCg0KTGEgc8OpcmllIG5lIHNlbWJsZSBwYXMgw6p0cmUgc3RhdGlvbm5haXJlIDogbGEgbW95ZW5uZSBuJ2VzdCBwYXMgMCwgbGEgc8OpcmllIHNlbWJsZSDDqnRyZSBhdXRvY29ycsOpbMOpZSBldCBkw6lwZW5kZW50ZSBkdSB0ZW1wcy4gT24gcGV1dCBsZSB2w6lyaWZpZXIgcmFwaWRlbWVudCBhdmVjIHVuIGF1dG9jb3Jyw6lsb2dyYW1tZQ0KDQpgYGB7cn0NCmFjZihkb25uZWVzX3dhZ2Ukd2FnZSkNCmBgYA0KDQpMYSBzw6lyaWUgZXN0IGF1dG9jb3Jyw6lsw6llLCBhdSBtb2lucyBqdXNxdSfDoCAxNSBsYWdzLiBPbiBwZXV0IHbDqXJpZmllciBmb3JtZWxsZW1lbnQgbGEgbm9uLXN0YXRpb25uYXJpdMOpIGF2ZWMgbGUgdGVzdCBkZSBEaWNrZXktRnVsbGVyIHNpbXBsZSAoc2FucyB0cmVuZCBuaSBjb25zdGFudGUpIDoNCmBgYHtyfQ0Kc3VtbWFyeSh1ci5kZihkb25uZWVzX3dhZ2Ukd2FnZSwgdHlwZT0ibm9uZSIpKQ0KYGBgDQpPbiB2b2l0IHF1ZSBsYSAqdC1zdGF0KiBlc3QgaW5mw6lyaWV1cmUgw6AgbGEgdmFsZXVyIGNyaXRpcXVlIGVuIHZhbGV1ciBhYnNvbHVlLiBMYSBzw6lyaWUgbidlc3QgZG9uYyBlZmZlY3RpdmVtZW50IHBhcyBzdGF0aW9ubmFpcmUuIElsIHMnYWdpdCBkb25jIG1haW50ZW5hbnQgZGUgZMOpdGVybWluZXIgcXVlbCBlc3QgbGUgdHlwZSBkZSBub24tc3RhdGlvbm5hcml0w6kgOiBUUyBvdSBEUy4NCg0KTGEgcHJlbWnDqHJlIMOpdGFwZSBlc3QgZGUgdGVzdGVyIGxlIG1vZMOobGUgYXZlYyB0ZW5kYW5jZSA6DQpgYGB7cn0NCnN1bW1hcnkodXIuZGYoZG9ubmVlc193YWdlJHdhZ2UsIHR5cGU9InRyZW5kIikpDQpgYGANCkxhIHRyZW5kIGB0dGAgbidlc3QgcGFzIHNpZ25pZmljYXRpdmUsIGRvbmMgw6dhIG4nZXN0IHBhcyB1biBUUy4gTGEgc8OpcmllIG4nZXN0IMOpZ2FsZW1lbnQgcGFzIHN0YXRpb25uYWlyZSBhdSB2dWUgZGVzICp0LXN0YXRzKi4NCk9uIHRlc3RlIGRvbmMgbGUgbW9kw6hsZSBhdmVjIGNvbnN0YW50ZSA6DQpgYGB7cn0NCnN1bW1hcnkodXIuZGYoZG9ubmVlc193YWdlJHdhZ2UsIHR5cGU9ImRyaWZ0IikpDQpgYGANCkxhIGNvbnN0YW50ZSBlc3Qgc2lnbmlmaWNhdGl2ZSDDoCAxMCUgc2V1bGVtZW50IChkb25jIGZhaWJsZW1lbnQgc2lnbmlmaWNhdGl2ZSwgbWFpcyBpbCB5IGEgcGV1dC3DqnRyZSB1biBkcmlmdCkgZXQgZXN0IG5vbi1zdGF0aW9ubmFpcmUuIENlbGEgaW5kaXF1ZSBxdWUgbGEgc8OpcmllIGVzdCBzw7tyZW1lbnQgdW4gRFMuDQoNCk9uIHBldXQgZXNzYXllciBkZSB2b2lyIHNpIGxhIHPDqXJpZSBlbiBkaWZmw6lyZW5jZSBwcmVtacOocmUgZXN0IHN0YXRpb25uYWlyZS4gTGEgc8OpcmllIGVuIGRpZmbDqXJlbmNlIHByZW1pw6hyZSByZXNzZW1ibGUgw6Agw6dhIDoNCmBgYHtyfQ0KZ2dwbG90KGRvbm5lZXNfd2FnZSwgYWVzKHg9eWVhciwgeT1kd2FnZSkpKw0KICBnZW9tX2xpbmUoKSsNCiAgdGhlbWVfYncoKQ0KYGBgDQoNCkVuIGZhaXNhbnQgbGUgdGVzdCBkZSBEaWNrZXkgRnVsbGVyIHNhbnMgdHJlbmQgbmkgZHJpZnQgOg0KYGBge3J9DQpzdW1tYXJ5KHVyLmRmKGRvbm5lZXNfd2FnZSRkd2FnZSwgdHlwZT0ibm9uZSIpKQ0KYGBgDQpPbiB2b2l0IHF1ZSBsYSBzw6lyaWUgZW4gZGlmZsOpcmVuY2Ugbidlc3QgcGFzIHN0YXRpb25uYWlyZS4gSWwgZmF1ZHJhaXQgZG9uYyBsYSBwYXNzZXIgZW4gZGV1eGnDqG1lIGRpZmbDqXJlbmNlIMOpdmVudHVlbGxlbWVudC4gTGEgc8OpcmllIGVuIGRldXhpw6htZSBkaWZmw6lyZW5jZSByZXNzZW1ibGUgw6AgOg0KYGBge3J9DQpnZ3Bsb3QoZG9ubmVlc193YWdlLCBhZXMoeD15ZWFyLCB5PWRkd2FnZSkpKw0KICBnZW9tX2xpbmUoKSsNCiAgdGhlbWVfYncoKQ0KYGBgDQpFdCBsZSB0ZXN0IGRlIEFERiBzYW5zIHRyZW5kIG5pIGNvbnN0YW50ZSA6DQpgYGB7cn0NCnN1bW1hcnkodXIuZGYoZG9ubmVlc193YWdlJGRkd2FnZSwgdHlwZT0ibm9uZSIpKQ0KYGBgDQpJY2ksIGxhIHPDqXJpZSBhcHBhcmHDrnQgc3RhdGlvbm5haXJlLiBPbiBwZXV0IHbDqXJpZmllciBxdSdlbGxlIG5lIHBvc3PDqGRlIHBhcyBkZSB0cmVuZCBuaSBkZSBjb25zdGFudGUgYXZlYyBsZXMgdGVzdHMgYXZlYyB0cmVuZCBldCBhdmVjIGNvbnN0YW50ZSA6DQpgYGB7cn0NCnN1bW1hcnkodXIuZGYoZG9ubmVlc193YWdlJGRkd2FnZSwgdHlwZT0idHJlbmQiKSkNCmBgYA0KTGEgdHJlbmQgbidlc3QgcGFzIHNpZ25pZmljYXRpdmUuDQpFdCBvbiBwZXV0IHRlc3RlciBhdmVjIGxlIG1vZMOobGUgc2FucyB0cmVuZCBtYWlzIGF2ZWMgY29uc3RhbnRlIDoNCmBgYHtyfQ0Kc3VtbWFyeSh1ci5kZihkb25uZWVzX3dhZ2UkZGR3YWdlLCB0eXBlPSJkcmlmdCIpKQ0KDQpgYGANCkxhIGNvbnN0YW50ZSBuJ2VzdCBwYXMgc2lnbmlmaWNhdGl2ZS4gT24gY29uZmlybWUgZG9uYyBxdWUgbGEgc8OpcmllIGVzdCBiaWVuIHN0YXRpb25uYWlyZSBlbiBkZXV4acOobWUgZGlmZsOpcmVuY2UsIGVsbGUgZXN0IGludMOpZ3LDqWUgZCdvcmRyZSAyIDogJEkoMikkLg0KDQoNCg0KDQpVbiBhdXRyZSBtb3llbiwgc291dmVudCBiZWF1Y291cCBwbHVzIHJhcGlkZSwgZXN0IGQndXRpbGlzZXIgbGEgZGlmZsOpcmVuY2UgZGUgbG9nYXJpdGhtZSAoYXBwcm94aW1hdGlvbiBkdSB0YXV4IGRlIGNyb2lzc2FuY2UsIHZvaXIgc8OpYW5jZSAxKS4gTGEgc8OpcmllIGRlIHRhdXggZGUgY3JvaXNzYW5jZSBkZXMgc2FsYWlyZXMgcmVzc2VtYmxlIMOgIDoNCmBgYHtyfQ0KZ2dwbG90KGRvbm5lZXNfd2FnZSwgYWVzKHg9eWVhciwgeT13YWdlX2dyb3d0aCkpKw0KICBnZW9tX2xpbmUoKSsNCiAgdGhlbWVfYncoKQ0KYGBgDQoNCg0KT24gcGV1dCB0ZXN0ZXIgbGEgc3RhdGlvbm5hcml0w6kgc3VyIGxhIHPDqXJpZSBlbiBuaXZlYXU6DQpgYGB7cn0NCnN1bW1hcnkodXIuZGYoZG9ubmVlc193YWdlJHdhZ2VfZ3Jvd3RoLCB0eXBlPSJub25lIikpDQpgYGANCkxhIHPDqXJpZSBuJ2VzdCBwYXMgc3RhdGlvbm5haXJlLiBPbiBwZXV0IHJlZ2FyZGVyIHF1ZWwgZXN0IGxlIHR5cGUgZGUgbm9uLXN0YXRpb25uYXJpdMOpIDoNCmBgYHtyfQ0Kc3VtbWFyeSh1ci5kZihkb25uZWVzX3dhZ2Ukd2FnZV9ncm93dGgsIHR5cGU9InRyZW5kIikpDQpgYGANCkxhIHRyZW5kIGVzdCBzaWduaWZpY2F0aXZlIMOgIDEwJSwgZXQgbCdhdXRvY29ycsOpbGF0aW9uIGVzdCDDqWdhbGVtZW50IHNpZ25pZmljYXRpdmUgOiBsYSBzw6lyaWUgc3VpdCBkb25jIHVuIHByb2Nlc3N1cyBEUywgZXQgaWwgZmF1dCBsYSBwYXNzZXIgZW4gZGlmZsOpcmVuY2UgcG91ciBsYSByZW5kcmUgcG90ZW50aWVsbGVtZW50IHN0YXRpb25uYWlyZS4NCg0KYGBge3J9DQpzdW1tYXJ5KHVyLmRmKGRvbm5lZXNfd2FnZSRkd2FnZV9ncm93dGgsIHR5cGU9Im5vbmUiKSkNCg0KYGBgDQpJY2ksIGF1IHZ1IGRlIGxhICp0LXN0YXQqLCBsYSBzw6lyaWUgZGUgY3JvaXNzYW5jZSBkZXMgc2FsYWlyZXMgKGB3YWdlX2dyb3d0aGApIGVzdCBzdGF0aW9ubmFpcmUgZW4gZGlmZsOpcmVuY2UgcHJlbWnDqHJlLCBlbGxlIGVzdCBpbnTDqWdyw6llIGQnb3JkcmUgMSA6ICRJKDEpJC4gDQoNCg0KRW4gc8OpcmllcyB0ZW1wb3JlbGxlcywgaWwgZmF1dCBzJ2Fzc3VyZXIgcXVlIGxhIHRvdGFsaXTDqSBkZXMgdmFyaWFibGVzIHF1aSBzb250IGluY2x1c2VzIGRhbnMgdW4gbW9kw6hsZSBkZSByw6lncmVzc2lvbiBzb2llbnQgc3RhdGlvbm5haXJlcywgZG9uYyBpbCBmYXV0IHLDqXDDqXRlciBjZXR0ZSBvcMOpcmF0aW9uIGF1dGFudCBkZSBmb2lzIHF1J2lsIHkgYSBkZSB2YXJpYWJsZXMuDQoNCg0K