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

Les résidus d’une régression sont souvent notés \(\varepsilon_t\) par convention. Ils représentent l’écart entre la variable dépendante de la régression et ses valeurs prédites par le modèles : \[\begin{align} &Y_t = a_0 + \beta X_t + \varepsilon_t \\ &\varepsilon_t = Y_t - \hat Y_t \end{align}\]

Et les résidus représentent réellement à quel point notre modèle est précis dans son estimation. Le modèle de régression est censé représenter correctement la dynamique de la variable dépendante \(Y_t\) en fonction de la dynamique d’autres variables (\(X_t\)), du temps (avec une trend, un cycle, une saisonnalité, etc… si on observe leur présence) et de la structure propre de la série (ARIMA). Cependant, on n’est pas censé représenter la variable dépendante avec une précision parfaite : le modèle peut sur-estimer ou sous-estimer de temps en temps la dynamique.

Cependant, quand on fait le modèle de régression, on part du principe que, si il est correct, on va correctement estimer la dynamique dans l’ensemble. On peut sur-estimer ou sous-estimer, mais en moyenne il faut que ces erreurs soient le plus proche possible de 0 : la moyenne des résidus doit donc être proche de 0. Egalement, on veut se tromper autant dans la sur-estimation que dans la sous-estimation (on ne veut pas sous-estimer la variable en permanence) : la somme des résidus doit être proche de 0. Egalement, on veut se tromper du même ordre peu importe la période : la moyenne et la variance des résidus doivent être constants. De cette condition découle une autre : les résidus doivent être indépendants. Autrement dit, le coefficient d’autocorrélation des résidus doit être nul (si on se trompe à une période, ça ne veut pas dire qu’on va se tromper à la période suivante) et ne doivent pas dépendre de \(Y_t\) (le coefficient de régression entre \(\varepsilon_t\) et \(Y_t\) doit être nul). Au final, les résidus doivent donc suivre une loi normale, centrée autour de zéro.

Si on résume ces cas : \[\begin{align} & \mathbb{E}(\varepsilon) = 0 \\ & \sum_{i=1}^N\varepsilon_i = 0 \\ & \mathbb{E}(\varepsilon)=\mathbb{E}(\varepsilon_{t+h}) \\ & \operatorname{Var}(\varepsilon) = \sigma^2_\varepsilon \\ & \operatorname{Cov}(\varepsilon_t, \varepsilon_{t-h})=0 \\ & \operatorname{Cov}(\varepsilon_t, Y_{t})=0\\ & \rightarrow\varepsilon_t \overset{\text{i.i.d.}}{\sim} \mathcal N(0,\sigma_\varepsilon^2) \end{align}\]

Note : \(i.i.d\) signifie identiquement et indépendamment distribués. Ces cas sont nombreux, mais au final on retombe assez vite sur ce qu’on a vu dans la séance sur la stationnarisation : on veut obtenir une suite de bruits blancs.

En effet, il faut imaginer que les séries temporelles ne sont qu’une suite de bruits blancs, et que ces bruits blancs sont impactés par des chocs exogènes (qui proviennent d’autres variables). Avec la régression, on retire l’influence de ces variables exogènes, et on est censé retomber sur la suite de bruits blancs originelle.

data_schularick <- read_excel("C:/users/fkraus/Desktop/data_schularick.xlsx") 

donnees_france <- data_schularick %>%
  filter(country=="France")%>%
  dplyr::select(year, unemp, cpi) %>%
  mutate(inflation = (log(cpi) - lag(log(cpi)))*100)%>%
  mutate(dinflation = inflation - lag(inflation))%>%
  mutate(dunemp = unemp - lag(unemp))%>%
  na.omit()%>%
  filter(year > 1950)

head(donnees_france)
require(fixest)
reg <- feols(inflation ~ dunemp, data=donnees_france)
etable(reg)
                              reg
Dependent Var.:         inflation
                                 
Constant        4.060*** (0.4607)
dunemp            1.663* (0.7335)
_______________ _________________
S.E. type                     IID
Observations                   70
R2                        0.07031
Adj. R2                   0.05664
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Analyse des résidus

On peut comparer la variable dépendante avec les valeurs prédites par le modèles :

fitted_val <- reg$fitted.values
residuals <- reg$residuals

donnees_france_2 <- donnees_france %>%
  cbind(fitted_val)%>%
  cbind(residuals)
ggplot(donnees_france_2, aes(x=year, y=inflation))+
  geom_line(lwd=1)+
  geom_line(aes(y=fitted_val), color="red", lty=2, lwd=1)+ 
  theme_bw()

On peut voir que notre modèle, bien qu’il utilise des variables correctement stationnarisées, ne représente par correctement la dynamique de la série : les fitted values ne suivent pas bien la série d’origine, particulièrement avant les années 1990.

Homoscedasticité

Pour vérifier l’homoscédasticité (=variance constante dans le temps), on peut déjà fait un graphique des résidus dans le temps.

ggplot(donnees_france_2, aes(x=year, y=residuals))+
  geom_line(lwd=1)+
  geom_hline(yintercept = 0, lty=2)+
  theme_bw()

On peut voir que la variance des résidus change drastiquement à partir de la fin des années 1980, ce qui pourrait indiquer que les résidus sont hétéroscédastiques. Cependant, l’analyse visuelle n’est pas un test formel. Pour vérifier l’homoscédasticité ou non des résidus, on doit utiliser le test de Breusch-Pagan (BP). Le test BP a pour hypothèse nulle l’hétéroscédasticité. Si la p-value est significative, on rejette donc l’hypothèse nulle et on conclut de l’homoscédasticité.

require(lmtest)
bptest(inflation ~ dunemp, data=donnees_france) 

    studentized Breusch-Pagan test

data:  inflation ~ dunemp
BP = 4.3177, df = 1, p-value = 0.03772

Ici, la p-value est significative, donc on conclut que les résidus de la régression sont hétéroscédastiques.

Normalité des résidus

ggplot(donnees_france_2, aes(residuals))+geom_density(fill="grey60", bounds=c(-Inf, Inf))+theme_bw()

Les résidus sont bien distribués autour de zéro, et la moyenne est relativement proche de zéro. En revanche, on peut voir que la queue de distribution à droite est relativement large, donc on tend à sous-estimer grandement le modèle à certains moments. La distribution n’est qu’une vérification visuelle, pas un test statistique. Pour un test formel, il faut se tourner vers le test de Shapiro qui teste la normalité d’une série. Le test de Shapiro a pour hypothèse nulle la normalité des résidus. Si la p-value est significative, on rejette donc l’hypothèse nulle, et on conclut de la non-normalité de la série.

shapiro.test(donnees_france_2$residuals)

    Shapiro-Wilk normality test

data:  donnees_france_2$residuals
W = 0.92324, p-value = 0.0003666

Ici, la p-value est significative, donc les résidus ne suivent pas une loi normale selon le test de Shapiro.

Indépendance

D’après l’hypothèse d’indépendance des résidus, les résidus d’une période ne doivent pas être expliqués par les résidus précédents. On peut tester cette hypothèse avec un simple autocorrélogramme :

acf(donnees_france_2$residuals)

Ici, on observe que les résidus ne semblent pas être indépendants, car les résidus passés expliquent de manière systématique les résidus actuels. Après l’analyse visuel, on peut faire le test formel. Le test Ljung-Box effectue le test d’indépendance des résidus, et a pour hypothèse nulle l’indépendance des résidus. Si la p-value est significative, on rejette l’hypothèse nulle et on conclut de l’autocorrélation (donc, l’absence d’indépendance) des résidus.

Box.test(donnees_france_2$residuals, lag = 10, type = "Ljung-Box")

    Box-Ljung test

data:  donnees_france_2$residuals
X-squared = 87.576, df = 10, p-value = 1.621e-14

Ici, il semble que nos résidus ne sont pas indépendants car la p-value est significative.

Note : certains de ces tests sont résumés dans la fonction checkresiduals() du package forecast:

require(forecast)
Le chargement a nécessité le package : forecast
Avis : le package ‘forecast’ a été compilé avec la version R 4.5.1Registered S3 method overwritten by 'quantmod':
  method            from
  as.zoo.data.frame zoo 
checkresiduals(reg)

    Ljung-Box test

data:  Residuals from feols
Q* = 87.576, df = 10, p-value = 1.621e-14

Model df: 0.   Total lags used: 10

Ainsi, dans l’ensemble, notre modèle est peu performant dans l’explication de la dynamique de l’inflation. En revanche, il explique correctement ce qu’il explique ! C’est un bon début, car cela veut dire qu’on peut maintenant ajouter d’autres variables explicatives dans le modèles (en testant, à chaque ajout, les effets sur les résidus pour vérifier qu’on ne crée par de problèmes qui seraient détectés dans les résidus) pour améliorer le pouvoir explicatif, tout en respectant le principe de parsimonie : on ne cherche pas à expliquer la totalité des variations de \(Y_t\), simplement à l’expliquer suffisamment pour que l’estimation de l’impact de \(\beta\) soit correct.

Overfitting

Parfois, on peut ajouter des variables qui vont créer un biais de collinéarité : les variables explicatives peuvent s’influencer entre elles, ou avoir un effet circulaire avec la variable dépendante, ce qui va créer un problème dans la régression.

reg_colin <- feols(inflation ~dunemp + lag(inflation), data= donnees_france)
etable(reg_colin)
                             reg_colin
Dependent Var.:              inflation
                                      
Constant              0e-16 (5.11e-17)
dunemp          4.44e-16*** (5.77e-17)
lag(inflation)         1*** (9.19e-18)
_______________ ______________________
S.E. type                          IID
Observations                        70
R2                                   1
Adj. R2                              1
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Et quand on regard l’écart entre les fitted valued et la variable dépendante, on obtient :

fitted_val_colin <- reg_colin$fitted.values
residuals_colin <- reg_colin$residuals

donnees_france_3 <- donnees_france %>%
  cbind(fitted_val_colin)%>%
  cbind(residuals_colin)
ggplot(donnees_france_3, aes(x=year, y=inflation))+
  geom_line(lwd=1)+
  geom_line(aes(y=fitted_val_colin), color="red", lty=2, lwd=1)+ 
  theme_bw()

Ici, on peut être tenté de dire que notre modèle est parfait parce qu’il explique bien notre variable dépendante. Mais ici, on a un problème de collinéarité : lag(dinflation) explique quasi-parfaitement dinflation, et l’ajouter dans le modèle créé de la collinéarité parfaite.

On peut tester la collinéarité avec un test VIF

require(car)
Le chargement a nécessité le package : car
Le chargement a nécessité le package : carData

Attachement du package : ‘car’

L'objet suivant est masqué depuis ‘package:dplyr’:

    recode

L'objet suivant est masqué depuis ‘package:purrr’:

    some
vif(reg_colin)
                  GVIF Df GVIF^(1/(2*Df))
dunemp         1.07563  0             Inf
lag(inflation) 1.07563  0             Inf

Ici, le GVIF corrigé (colonne à droite) tend vers l’infini. On essaie en général de garder un VIF au maximum a 6 ou 7, au delà il y a un problème.

Donc ici, ajouter le lag de l’inflation va créer plus de problème qu’il n’en résout. Cependant, cette régression a pour mérite de montrer que l’inflation, même si elle est considérée comme étant stationnaire, continue d’avoir une structure auto-régressive importante, au point où si on la néglige, on perd un pouvoir explicatif très important. C’est la raison pour laquelle il faut s’intéresser à la structure Auto-Régressive (AR) des séries temporelles, à leur degré d’intégration (I) et à leur moyenne mobile (Moving Average - MA), dans le cadre des modèles ARIMA que l’on verra dans la séance 4.

LS0tDQp0aXRsZTogIlIgTm90ZWJvb2sgOiBBbmFseXNlIGRlcyByw6lzaWR1cyAiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCmh0bWxfbm90ZWJvb2s6IA0KICAgIHRvYzogdHJ1ZSAjIHBvdXIgYWZmaWNoZXIgdW5lIHRhYmxlIGRlcyBtYXRpw6hyZXMgYXUgZMOpYnV0IGR1IGRvY3VtZW50IChUYWJsZSBvZiBDb250ZW50KQ0KICAgIHRvY19kZXB0aDogNCAjIGxlIG5pdmVhdSBkJ2FmZmljaGFnZSBkZXMgdGl0cmVzLCBzb3VzLXRpdHJlcywgc2VjdGlvbi4uLiANCiAgICB0b2NfZmxvYXQ6IGZhbHNlDQotLS0NCg0KYGBge3J9DQpzZXR3ZChkaXIgPSAiQzovVXNlcnMvZmtyYXVzL0Rlc2t0b3AvVEQvMjAyNS0yMDI2L0VDT05PTUVUUklFL3PDqWFuY2U0IikNCmBgYA0KDQpMZXMgcsOpc2lkdXMgZCd1bmUgcsOpZ3Jlc3Npb24gc29udCBzb3V2ZW50IG5vdMOpcyAkXHZhcmVwc2lsb25fdCQgcGFyIGNvbnZlbnRpb24uIElscyByZXByw6lzZW50ZW50IGwnw6ljYXJ0IGVudHJlIGxhIHZhcmlhYmxlIGTDqXBlbmRhbnRlIGRlIGxhIHLDqWdyZXNzaW9uIGV0IHNlcyB2YWxldXJzIHByw6lkaXRlcyBwYXIgbGUgbW9kw6hsZXMgOg0KXGJlZ2lue2FsaWdufQ0KICZZX3QgPSBhXzAgKyBcYmV0YSBYX3QgKyBcdmFyZXBzaWxvbl90IFxcDQogJlx2YXJlcHNpbG9uX3QgPSBZX3QgLSBcaGF0IFlfdA0KXGVuZHthbGlnbn0NCg0KRXQgbGVzIHLDqXNpZHVzIHJlcHLDqXNlbnRlbnQgcsOpZWxsZW1lbnQgw6AgcXVlbCBwb2ludCBub3RyZSBtb2TDqGxlIGVzdCBwcsOpY2lzIGRhbnMgc29uIGVzdGltYXRpb24uIExlIG1vZMOobGUgZGUgcsOpZ3Jlc3Npb24gZXN0IGNlbnPDqSByZXByw6lzZW50ZXIgY29ycmVjdGVtZW50IGxhIGR5bmFtaXF1ZSBkZSBsYSB2YXJpYWJsZSBkw6lwZW5kYW50ZSAkWV90JCBlbiBmb25jdGlvbiBkZSBsYSBkeW5hbWlxdWUgZCdhdXRyZXMgdmFyaWFibGVzICgkWF90JCksIGR1IHRlbXBzIChhdmVjIHVuZSB0cmVuZCwgdW4gY3ljbGUsIHVuZSBzYWlzb25uYWxpdMOpLCBldGMuLi4gc2kgb24gb2JzZXJ2ZSBsZXVyIHByw6lzZW5jZSkgZXQgZGUgbGEgc3RydWN0dXJlIHByb3ByZSBkZSBsYSBzw6lyaWUgKEFSSU1BKS4gQ2VwZW5kYW50LCBvbiBuJ2VzdCBwYXMgY2Vuc8OpIHJlcHLDqXNlbnRlciBsYSB2YXJpYWJsZSBkw6lwZW5kYW50ZSBhdmVjIHVuZSBwcsOpY2lzaW9uIHBhcmZhaXRlIDogbGUgbW9kw6hsZSBwZXV0IHN1ci1lc3RpbWVyIG91IHNvdXMtZXN0aW1lciBkZSB0ZW1wcyBlbiB0ZW1wcyBsYSBkeW5hbWlxdWUuIA0KDQpDZXBlbmRhbnQsIHF1YW5kIG9uIGZhaXQgbGUgbW9kw6hsZSBkZSByw6lncmVzc2lvbiwgb24gcGFydCBkdSBwcmluY2lwZSBxdWUsIHNpIGlsIGVzdCBjb3JyZWN0LCBvbiB2YSBjb3JyZWN0ZW1lbnQgZXN0aW1lciBsYSBkeW5hbWlxdWUgZGFucyBsJ2Vuc2VtYmxlLiBPbiBwZXV0IHN1ci1lc3RpbWVyIG91IHNvdXMtZXN0aW1lciwgbWFpcyBlbiBtb3llbm5lIGlsIGZhdXQgcXVlIGNlcyBlcnJldXJzIHNvaWVudCBsZSBwbHVzIHByb2NoZSBwb3NzaWJsZSBkZSAwIDogKipsYSBtb3llbm5lIGRlcyByw6lzaWR1cyBkb2l0IGRvbmMgw6p0cmUgcHJvY2hlIGRlIDAqKi4gRWdhbGVtZW50LCBvbiB2ZXV0IHNlIHRyb21wZXIgYXV0YW50IGRhbnMgbGEgc3VyLWVzdGltYXRpb24gcXVlIGRhbnMgbGEgc291cy1lc3RpbWF0aW9uIChvbiBuZSB2ZXV0IHBhcyBzb3VzLWVzdGltZXIgbGEgdmFyaWFibGUgZW4gcGVybWFuZW5jZSkgOiAqKmxhIHNvbW1lIGRlcyByw6lzaWR1cyBkb2l0IMOqdHJlIHByb2NoZSBkZSAwKiouIEVnYWxlbWVudCwgb24gdmV1dCBzZSB0cm9tcGVyIGR1IG3Dqm1lIG9yZHJlIHBldSBpbXBvcnRlIGxhIHDDqXJpb2RlIDogKipsYSBtb3llbm5lIGV0IGxhIHZhcmlhbmNlIGRlcyByw6lzaWR1cyBkb2l2ZW50IMOqdHJlIGNvbnN0YW50cy4qKiBEZSBjZXR0ZSBjb25kaXRpb24gZMOpY291bGUgdW5lIGF1dHJlIDogKipsZXMgcsOpc2lkdXMgZG9pdmVudCDDqnRyZSBpbmTDqXBlbmRhbnRzLioqIEF1dHJlbWVudCBkaXQsICoqbGUgY29lZmZpY2llbnQgZCdhdXRvY29ycsOpbGF0aW9uIGRlcyByw6lzaWR1cyBkb2l0IMOqdHJlIG51bCoqIChzaSBvbiBzZSB0cm9tcGUgw6AgdW5lIHDDqXJpb2RlLCDDp2EgbmUgdmV1dCBwYXMgZGlyZSBxdSdvbiB2YSBzZSB0cm9tcGVyIMOgIGxhIHDDqXJpb2RlIHN1aXZhbnRlKSBldCBuZSBkb2l2ZW50IHBhcyBkw6lwZW5kcmUgZGUgJFlfdCQgKGxlIGNvZWZmaWNpZW50IGRlIHLDqWdyZXNzaW9uIGVudHJlICRcdmFyZXBzaWxvbl90JCBldCAkWV90JCBkb2l0IMOqdHJlIG51bCkuIEF1IGZpbmFsLCAqKmxlcyByw6lzaWR1cyBkb2l2ZW50IGRvbmMgc3VpdnJlIHVuZSBsb2kgbm9ybWFsZSwgY2VudHLDqWUgYXV0b3VyIGRlIHrDqXJvLioqDQoNClNpIG9uIHLDqXN1bWUgY2VzIGNhcyA6DQpcYmVnaW57YWxpZ259DQomIFxtYXRoYmJ7RX0oXHZhcmVwc2lsb24pID0gMCBcXA0KJiBcc3VtX3tpPTF9Xk5cdmFyZXBzaWxvbl9pID0gMCBcXA0KJiBcbWF0aGJie0V9KFx2YXJlcHNpbG9uKT1cbWF0aGJie0V9KFx2YXJlcHNpbG9uX3t0K2h9KSBcXA0KJiBcb3BlcmF0b3JuYW1le1Zhcn0oXHZhcmVwc2lsb24pID0gXHNpZ21hXjJfXHZhcmVwc2lsb24gXFwNCiYgXG9wZXJhdG9ybmFtZXtDb3Z9KFx2YXJlcHNpbG9uX3QsIFx2YXJlcHNpbG9uX3t0LWh9KT0wIFxcDQomIFxvcGVyYXRvcm5hbWV7Q292fShcdmFyZXBzaWxvbl90LCBZX3t0fSk9MFxcDQomIFxyaWdodGFycm93XHZhcmVwc2lsb25fdCBcb3ZlcnNldHtcdGV4dHtpLmkuZC59fXtcc2ltfSBcbWF0aGNhbCBOKDAsXHNpZ21hX1x2YXJlcHNpbG9uXjIpDQpcZW5ke2FsaWdufQ0KDQoqTm90ZSA6ICRpLmkuZCQgc2lnbmlmaWUgaWRlbnRpcXVlbWVudCBldCBpbmTDqXBlbmRhbW1lbnQgZGlzdHJpYnXDqXMqLiBDZXMgY2FzIHNvbnQgbm9tYnJldXgsIG1haXMgYXUgZmluYWwgb24gcmV0b21iZSBhc3NleiB2aXRlIHN1ciBjZSBxdSdvbiBhIHZ1IGRhbnMgbGEgc8OpYW5jZSBzdXIgbGEgc3RhdGlvbm5hcmlzYXRpb24gOiBvbiB2ZXV0IG9idGVuaXIgdW5lIHN1aXRlIGRlIGJydWl0cyBibGFuY3MuDQoNCkVuIGVmZmV0LCBpbCBmYXV0IGltYWdpbmVyIHF1ZSBsZXMgc8OpcmllcyB0ZW1wb3JlbGxlcyBuZSBzb250IHF1J3VuZSBzdWl0ZSBkZSBicnVpdHMgYmxhbmNzLCBldCBxdWUgY2VzIGJydWl0cyBibGFuY3Mgc29udCBpbXBhY3TDqXMgcGFyIGRlcyBjaG9jcyBleG9nw6huZXMgKHF1aSBwcm92aWVubmVudCBkJ2F1dHJlcyB2YXJpYWJsZXMpLiBBdmVjIGxhIHLDqWdyZXNzaW9uLCBvbiByZXRpcmUgbCdpbmZsdWVuY2UgZGUgY2VzIHZhcmlhYmxlcyBleG9nw6huZXMsIGV0IG9uIGVzdCBjZW5zw6kgcmV0b21iZXIgc3VyIGxhIHN1aXRlIGRlIGJydWl0cyBibGFuY3Mgb3JpZ2luZWxsZS4NCg0KYGBge3J9DQpkYXRhX3NjaHVsYXJpY2sgPC0gcmVhZF9leGNlbCgiQzovdXNlcnMvZmtyYXVzL0Rlc2t0b3AvZGF0YV9zY2h1bGFyaWNrLnhsc3giKSANCg0KZG9ubmVlc19mcmFuY2UgPC0gZGF0YV9zY2h1bGFyaWNrICU+JQ0KICBmaWx0ZXIoY291bnRyeT09IkZyYW5jZSIpJT4lDQogIGRwbHlyOjpzZWxlY3QoeWVhciwgdW5lbXAsIGNwaSkgJT4lDQogIG11dGF0ZShpbmZsYXRpb24gPSAobG9nKGNwaSkgLSBsYWcobG9nKGNwaSkpKSoxMDApJT4lDQogIG11dGF0ZShkaW5mbGF0aW9uID0gaW5mbGF0aW9uIC0gbGFnKGluZmxhdGlvbikpJT4lDQogIG11dGF0ZShkdW5lbXAgPSB1bmVtcCAtIGxhZyh1bmVtcCkpJT4lDQogIG5hLm9taXQoKSU+JQ0KICBmaWx0ZXIoeWVhciA+IDE5NTApDQoNCmhlYWQoZG9ubmVlc19mcmFuY2UpDQpgYGANCg0KDQpgYGB7cn0NCnJlcXVpcmUoZml4ZXN0KQ0KcmVnIDwtIGZlb2xzKGluZmxhdGlvbiB+IGR1bmVtcCwgZGF0YT1kb25uZWVzX2ZyYW5jZSkNCmV0YWJsZShyZWcpDQpgYGANCiMgQW5hbHlzZSBkZXMgcsOpc2lkdXMNCk9uIHBldXQgY29tcGFyZXIgbGEgdmFyaWFibGUgZMOpcGVuZGFudGUgYXZlYyBsZXMgdmFsZXVycyBwcsOpZGl0ZXMgcGFyIGxlIG1vZMOobGVzIDoNCmBgYHtyfQ0KZml0dGVkX3ZhbCA8LSByZWckZml0dGVkLnZhbHVlcw0KcmVzaWR1YWxzIDwtIHJlZyRyZXNpZHVhbHMNCg0KZG9ubmVlc19mcmFuY2VfMiA8LSBkb25uZWVzX2ZyYW5jZSAlPiUNCiAgY2JpbmQoZml0dGVkX3ZhbCklPiUNCiAgY2JpbmQocmVzaWR1YWxzKQ0KZ2dwbG90KGRvbm5lZXNfZnJhbmNlXzIsIGFlcyh4PXllYXIsIHk9aW5mbGF0aW9uKSkrDQogIGdlb21fbGluZShsd2Q9MSkrDQogIGdlb21fbGluZShhZXMoeT1maXR0ZWRfdmFsKSwgY29sb3I9InJlZCIsIGx0eT0yLCBsd2Q9MSkrIA0KICB0aGVtZV9idygpDQpgYGANCk9uIHBldXQgdm9pciBxdWUgbm90cmUgbW9kw6hsZSwgYmllbiBxdSdpbCB1dGlsaXNlIGRlcyB2YXJpYWJsZXMgY29ycmVjdGVtZW50IHN0YXRpb25uYXJpc8OpZXMsIG5lIHJlcHLDqXNlbnRlIHBhciBjb3JyZWN0ZW1lbnQgbGEgZHluYW1pcXVlIGRlIGxhIHPDqXJpZSA6IGxlcyAqZml0dGVkIHZhbHVlcyogbmUgc3VpdmVudCBwYXMgYmllbiBsYSBzw6lyaWUgZCdvcmlnaW5lLCBwYXJ0aWN1bGnDqHJlbWVudCBhdmFudCBsZXMgYW5uw6llcyAxOTkwLg0KDQojIyBIb21vc2NlZGFzdGljaXTDqQ0KDQpQb3VyIHbDqXJpZmllciBsJ2hvbW9zY8OpZGFzdGljaXTDqSAoPXZhcmlhbmNlIGNvbnN0YW50ZSBkYW5zIGxlIHRlbXBzKSwgb24gcGV1dCBkw6lqw6AgZmFpdCB1biBncmFwaGlxdWUgZGVzIHLDqXNpZHVzIGRhbnMgbGUgdGVtcHMuDQpgYGB7cn0NCmdncGxvdChkb25uZWVzX2ZyYW5jZV8yLCBhZXMoeD15ZWFyLCB5PXJlc2lkdWFscykpKw0KICBnZW9tX2xpbmUobHdkPTEpKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsdHk9MikrDQogIHRoZW1lX2J3KCkNCmBgYA0KT24gcGV1dCB2b2lyIHF1ZSBsYSB2YXJpYW5jZSBkZXMgcsOpc2lkdXMgY2hhbmdlIGRyYXN0aXF1ZW1lbnQgw6AgcGFydGlyIGRlIGxhIGZpbiBkZXMgYW5uw6llcyAxOTgwLCBjZSBxdWkgcG91cnJhaXQgaW5kaXF1ZXIgcXVlIGxlcyByw6lzaWR1cyBzb250IGjDqXTDqXJvc2PDqWRhc3RpcXVlcy4gQ2VwZW5kYW50LCBsJ2FuYWx5c2UgdmlzdWVsbGUgbidlc3QgcGFzIHVuIHRlc3QgZm9ybWVsLiBQb3VyIHbDqXJpZmllciBsJ2hvbW9zY8OpZGFzdGljaXTDqSBvdSBub24gZGVzIHLDqXNpZHVzLCBvbiBkb2l0IHV0aWxpc2VyIGxlIHRlc3QgZGUgQnJldXNjaC1QYWdhbiAoQlApLiBMZSB0ZXN0IEJQIGEgcG91ciBoeXBvdGjDqHNlIG51bGxlIGwnaMOpdMOpcm9zY8OpZGFzdGljaXTDqS4gU2kgbGEgcC12YWx1ZSBlc3Qgc2lnbmlmaWNhdGl2ZSwgb24gcmVqZXR0ZSBkb25jIGwnaHlwb3Row6hzZSBudWxsZSBldCBvbiBjb25jbHV0IGRlIGwnaG9tb3Njw6lkYXN0aWNpdMOpLg0KDQpgYGB7cn0NCnJlcXVpcmUobG10ZXN0KQ0KYnB0ZXN0KGluZmxhdGlvbiB+IGR1bmVtcCwgZGF0YT1kb25uZWVzX2ZyYW5jZSkgDQpgYGANCkljaSwgbGEgcC12YWx1ZSBlc3Qgc2lnbmlmaWNhdGl2ZSwgZG9uYyBvbiBjb25jbHV0IHF1ZSBsZXMgcsOpc2lkdXMgZGUgbGEgcsOpZ3Jlc3Npb24gc29udCBow6l0w6lyb3Njw6lkYXN0aXF1ZXMuDQoNCiMjIE5vcm1hbGl0w6kgZGVzIHLDqXNpZHVzDQpgYGB7cn0NCmdncGxvdChkb25uZWVzX2ZyYW5jZV8yLCBhZXMocmVzaWR1YWxzKSkrZ2VvbV9kZW5zaXR5KGZpbGw9ImdyZXk2MCIsIGJvdW5kcz1jKC1JbmYsIEluZikpK3RoZW1lX2J3KCkNCmBgYA0KTGVzIHLDqXNpZHVzIHNvbnQgYmllbiBkaXN0cmlidcOpcyBhdXRvdXIgZGUgesOpcm8sIGV0IGxhIG1veWVubmUgZXN0IHJlbGF0aXZlbWVudCBwcm9jaGUgZGUgesOpcm8uIEVuIHJldmFuY2hlLCBvbiBwZXV0IHZvaXIgcXVlIGxhIHF1ZXVlIGRlIGRpc3RyaWJ1dGlvbiDDoCBkcm9pdGUgZXN0IHJlbGF0aXZlbWVudCBsYXJnZSwgZG9uYyBvbiB0ZW5kIMOgIHNvdXMtZXN0aW1lciBncmFuZGVtZW50IGxlIG1vZMOobGUgw6AgY2VydGFpbnMgbW9tZW50cy4gTGEgZGlzdHJpYnV0aW9uIG4nZXN0IHF1J3VuZSB2w6lyaWZpY2F0aW9uIHZpc3VlbGxlLCBwYXMgdW4gdGVzdCBzdGF0aXN0aXF1ZS4gUG91ciB1biB0ZXN0IGZvcm1lbCwgaWwgZmF1dCBzZSB0b3VybmVyIHZlcnMgbGUgdGVzdCBkZSBTaGFwaXJvIHF1aSB0ZXN0ZSBsYSBub3JtYWxpdMOpIGQndW5lIHPDqXJpZS4gTGUgdGVzdCBkZSBTaGFwaXJvIGEgcG91ciBoeXBvdGjDqHNlIG51bGxlIGxhIG5vcm1hbGl0w6kgZGVzIHLDqXNpZHVzLiBTaSBsYSBwLXZhbHVlIGVzdCBzaWduaWZpY2F0aXZlLCBvbiByZWpldHRlIGRvbmMgbCdoeXBvdGjDqHNlIG51bGxlLCBldCBvbiBjb25jbHV0IGRlIGxhIG5vbi1ub3JtYWxpdMOpIGRlIGxhIHPDqXJpZS4NCg0KYGBge3J9DQpzaGFwaXJvLnRlc3QoZG9ubmVlc19mcmFuY2VfMiRyZXNpZHVhbHMpDQpgYGANCkljaSwgbGEgcC12YWx1ZSBlc3Qgc2lnbmlmaWNhdGl2ZSwgZG9uYyBsZXMgcsOpc2lkdXMgbmUgc3VpdmVudCBwYXMgdW5lIGxvaSBub3JtYWxlIHNlbG9uIGxlIHRlc3QgZGUgU2hhcGlyby4NCg0KDQoNCg0KIyMgSW5kw6lwZW5kYW5jZQ0KRCdhcHLDqHMgbCdoeXBvdGjDqHNlIGQnaW5kw6lwZW5kYW5jZSBkZXMgcsOpc2lkdXMsIGxlcyByw6lzaWR1cyBkJ3VuZSBww6lyaW9kZSBuZSBkb2l2ZW50IHBhcyDDqnRyZSBleHBsaXF1w6lzIHBhciBsZXMgcsOpc2lkdXMgcHLDqWPDqWRlbnRzLiBPbiBwZXV0IHRlc3RlciBjZXR0ZSBoeXBvdGjDqHNlIGF2ZWMgdW4gc2ltcGxlIGF1dG9jb3Jyw6lsb2dyYW1tZSA6DQpgYGB7cn0NCmFjZihkb25uZWVzX2ZyYW5jZV8yJHJlc2lkdWFscykNCmBgYA0KDQpJY2ksIG9uIG9ic2VydmUgcXVlIGxlcyByw6lzaWR1cyBuZSBzZW1ibGVudCBwYXMgw6p0cmUgaW5kw6lwZW5kYW50cywgY2FyIGxlcyByw6lzaWR1cyBwYXNzw6lzIGV4cGxpcXVlbnQgZGUgbWFuacOocmUgc3lzdMOpbWF0aXF1ZSBsZXMgcsOpc2lkdXMgYWN0dWVscy4gQXByw6hzIGwnYW5hbHlzZSB2aXN1ZWwsIG9uIHBldXQgZmFpcmUgbGUgdGVzdCBmb3JtZWwuIExlIHRlc3QgTGp1bmctQm94IGVmZmVjdHVlIGxlIHRlc3QgZCdpbmTDqXBlbmRhbmNlIGRlcyByw6lzaWR1cywgZXQgYSBwb3VyIGh5cG90aMOoc2UgbnVsbGUgbCdpbmTDqXBlbmRhbmNlIGRlcyByw6lzaWR1cy4gU2kgbGEgcC12YWx1ZSBlc3Qgc2lnbmlmaWNhdGl2ZSwgb24gcmVqZXR0ZSBsJ2h5cG90aMOoc2UgbnVsbGUgZXQgb24gY29uY2x1dCBkZSBsJ2F1dG9jb3Jyw6lsYXRpb24gKGRvbmMsIGwnYWJzZW5jZSBkJ2luZMOpcGVuZGFuY2UpIGRlcyByw6lzaWR1cy4NCmBgYHtyfQ0KQm94LnRlc3QoZG9ubmVlc19mcmFuY2VfMiRyZXNpZHVhbHMsIGxhZyA9IDEwLCB0eXBlID0gIkxqdW5nLUJveCIpDQpgYGANCkljaSwgaWwgc2VtYmxlIHF1ZSBub3MgcsOpc2lkdXMgbmUgc29udCBwYXMgaW5kw6lwZW5kYW50cyBjYXIgbGEgcC12YWx1ZSBlc3Qgc2lnbmlmaWNhdGl2ZS4NCg0KKk5vdGUgOiBjZXJ0YWlucyBkZSBjZXMgdGVzdHMgc29udCByw6lzdW3DqXMgZGFucyBsYSBmb25jdGlvbiBgY2hlY2tyZXNpZHVhbHMoKWAgZHUgcGFja2FnZSBgZm9yZWNhc3RgKjoNCmBgYHtyfQ0KcmVxdWlyZShmb3JlY2FzdCkNCmNoZWNrcmVzaWR1YWxzKHJlZykNCmBgYA0KDQoNCg0KQWluc2ksIGRhbnMgbCdlbnNlbWJsZSwgbm90cmUgbW9kw6hsZSBlc3QgcGV1IHBlcmZvcm1hbnQgZGFucyBsJ2V4cGxpY2F0aW9uIGRlIGxhIGR5bmFtaXF1ZSBkZSBsJ2luZmxhdGlvbi4gRW4gcmV2YW5jaGUsIGlsIGV4cGxpcXVlIGNvcnJlY3RlbWVudCBjZSBxdSdpbCBleHBsaXF1ZSAhIEMnZXN0IHVuIGJvbiBkw6lidXQsIGNhciBjZWxhIHZldXQgZGlyZSBxdSdvbiBwZXV0IG1haW50ZW5hbnQgYWpvdXRlciBkJ2F1dHJlcyB2YXJpYWJsZXMgZXhwbGljYXRpdmVzIGRhbnMgbGUgbW9kw6hsZXMgKGVuIHRlc3RhbnQsIMOgIGNoYXF1ZSBham91dCwgbGVzIGVmZmV0cyBzdXIgbGVzIHLDqXNpZHVzIHBvdXIgdsOpcmlmaWVyIHF1J29uIG5lIGNyw6llIHBhciBkZSBwcm9ibMOobWVzIHF1aSBzZXJhaWVudCBkw6l0ZWN0w6lzIGRhbnMgbGVzIHLDqXNpZHVzKSBwb3VyIGFtw6lsaW9yZXIgbGUgcG91dm9pciBleHBsaWNhdGlmLCB0b3V0IGVuIHJlc3BlY3RhbnQgbGUgcHJpbmNpcGUgZGUgcGFyc2ltb25pZSA6IG9uIG5lIGNoZXJjaGUgcGFzIMOgIGV4cGxpcXVlciBsYSB0b3RhbGl0w6kgZGVzIHZhcmlhdGlvbnMgZGUgJFlfdCQsIHNpbXBsZW1lbnQgw6AgbCdleHBsaXF1ZXIgc3VmZmlzYW1tZW50IHBvdXIgcXVlIGwnZXN0aW1hdGlvbiBkZSBsJ2ltcGFjdCBkZSAkXGJldGEkIHNvaXQgY29ycmVjdC4NCg0KDQoNCiMgT3ZlcmZpdHRpbmcNCg0KUGFyZm9pcywgb24gcGV1dCBham91dGVyIGRlcyB2YXJpYWJsZXMgcXVpIHZvbnQgY3LDqWVyIHVuIGJpYWlzIGRlIGNvbGxpbsOpYXJpdMOpIDogbGVzIHZhcmlhYmxlcyBleHBsaWNhdGl2ZXMgcGV1dmVudCBzJ2luZmx1ZW5jZXIgZW50cmUgZWxsZXMsIG91IGF2b2lyIHVuIGVmZmV0IGNpcmN1bGFpcmUgYXZlYyBsYSB2YXJpYWJsZSBkw6lwZW5kYW50ZSwgY2UgcXVpIHZhIGNyw6llciB1biBwcm9ibMOobWUgZGFucyBsYSByw6lncmVzc2lvbi4gDQoNCmBgYHtyfQ0KcmVnX2NvbGluIDwtIGZlb2xzKGluZmxhdGlvbiB+ZHVuZW1wICsgbGFnKGluZmxhdGlvbiksIGRhdGE9IGRvbm5lZXNfZnJhbmNlKQ0KZXRhYmxlKHJlZ19jb2xpbikNCmBgYA0KDQpFdCBxdWFuZCBvbiByZWdhcmQgbCfDqWNhcnQgZW50cmUgbGVzICpmaXR0ZWQgdmFsdWVkKiBldCBsYSB2YXJpYWJsZSBkw6lwZW5kYW50ZSwgb24gb2J0aWVudCA6DQpgYGB7cn0NCmZpdHRlZF92YWxfY29saW4gPC0gcmVnX2NvbGluJGZpdHRlZC52YWx1ZXMNCnJlc2lkdWFsc19jb2xpbiA8LSByZWdfY29saW4kcmVzaWR1YWxzDQoNCmRvbm5lZXNfZnJhbmNlXzMgPC0gZG9ubmVlc19mcmFuY2UgJT4lDQogIGNiaW5kKGZpdHRlZF92YWxfY29saW4pJT4lDQogIGNiaW5kKHJlc2lkdWFsc19jb2xpbikNCmdncGxvdChkb25uZWVzX2ZyYW5jZV8zLCBhZXMoeD15ZWFyLCB5PWluZmxhdGlvbikpKw0KICBnZW9tX2xpbmUobHdkPTEpKw0KICBnZW9tX2xpbmUoYWVzKHk9Zml0dGVkX3ZhbF9jb2xpbiksIGNvbG9yPSJyZWQiLCBsdHk9MiwgbHdkPTEpKyANCiAgdGhlbWVfYncoKQ0KYGBgDQpJY2ksIG9uIHBldXQgw6p0cmUgdGVudMOpIGRlIGRpcmUgcXVlIG5vdHJlIG1vZMOobGUgZXN0IHBhcmZhaXQgcGFyY2UgcXUnaWwgZXhwbGlxdWUgYmllbiBub3RyZSB2YXJpYWJsZSBkw6lwZW5kYW50ZS4gTWFpcyBpY2ksIG9uIGEgdW4gcHJvYmzDqG1lIGRlIGNvbGxpbsOpYXJpdMOpIDogYGxhZyhkaW5mbGF0aW9uKWAgZXhwbGlxdWUgcXVhc2ktcGFyZmFpdGVtZW50IGBkaW5mbGF0aW9uYCwgZXQgbCdham91dGVyIGRhbnMgbGUgbW9kw6hsZSBjcsOpw6kgZGUgbGEgY29sbGluw6lhcml0w6kgcGFyZmFpdGUuDQoNCg0KT24gcGV1dCB0ZXN0ZXIgbGEgY29sbGluw6lhcml0w6kgYXZlYyB1biB0ZXN0IFZJRg0KYGBge3J9DQpyZXF1aXJlKGNhcikNCnZpZihyZWdfY29saW4pDQpgYGANCkljaSwgbGUgR1ZJRiBjb3JyaWfDqSAoY29sb25uZSDDoCBkcm9pdGUpIHRlbmQgdmVycyBsJ2luZmluaS4gT24gZXNzYWllIGVuIGfDqW7DqXJhbCBkZSBnYXJkZXIgdW4gVklGICoqYXUgbWF4aW11bSoqIGEgNiBvdSA3LCBhdSBkZWzDoCBpbCB5IGEgdW4gcHJvYmzDqG1lLg0KDQoNCkRvbmMgaWNpLCAqKmFqb3V0ZXIgbGUgbGFnIGRlIGwnaW5mbGF0aW9uIHZhIGNyw6llciBwbHVzIGRlIHByb2Jsw6htZSBxdSdpbCBuJ2VuIHLDqXNvdXQqKi4gQ2VwZW5kYW50LCBjZXR0ZSByw6lncmVzc2lvbiBhIHBvdXIgbcOpcml0ZSBkZSBtb250cmVyIHF1ZSBsJ2luZmxhdGlvbiwgbcOqbWUgc2kgZWxsZSBlc3QgY29uc2lkw6lyw6llIGNvbW1lIMOpdGFudCBzdGF0aW9ubmFpcmUsIGNvbnRpbnVlIGQnYXZvaXIgdW5lIHN0cnVjdHVyZSBhdXRvLXLDqWdyZXNzaXZlIGltcG9ydGFudGUsIGF1IHBvaW50IG/DuSBzaSBvbiBsYSBuw6lnbGlnZSwgb24gcGVyZCB1biBwb3V2b2lyIGV4cGxpY2F0aWYgdHLDqHMgaW1wb3J0YW50LiBDJ2VzdCBsYSByYWlzb24gcG91ciBsYXF1ZWxsZSBpbCBmYXV0IHMnaW50w6lyZXNzZXIgw6AgbGEgc3RydWN0dXJlIEF1dG8tUsOpZ3Jlc3NpdmUgKEFSKSBkZXMgc8OpcmllcyB0ZW1wb3JlbGxlcywgw6AgbGV1ciBkZWdyw6kgZCdpbnTDqWdyYXRpb24gKEkpIGV0IMOgIGxldXIgbW95ZW5uZSBtb2JpbGUgKE1vdmluZyBBdmVyYWdlIC0gTUEpLCBkYW5zIGxlIGNhZHJlIGRlcyBtb2TDqGxlcyBBUklNQSBxdWUgbCdvbiB2ZXJyYSBkYW5zIGxhIHPDqWFuY2UgNC4NCg0KDQoNCg0K