setwd(dir = "~/Desktop/R/R2")
require(readxl)
require(tidyverse)
require(ggplot2)
require(urca)
require(fixest)
require(lmtest)
require(forecast)
data_schularick <- read_excel("~/Desktop/R/data_schularick.xlsx")
dk <- data_schularick %>%
filter(country == "Denmark") %>%
dplyr::select(year, cpi, xrusd) %>%
filter(year > 1960)
head(dk)
PARTIE 1: RÉGRESSION LINÉTAIRE
Introduction
L’objectif dans cette première partie de projet, est d’analyser le
pass-through du taux de change sur l’inflation au Danemark en étudiant
la manière dont les variations du taux de change se transmettent aux
prix à la consommation.
Pour répondre à cette question, nous étudions d’abord le comportement
des séries CPI et XRUSD, puis nous vérifions leur stationnarité à l’aide
de tests ADF. Une fois les séries correctement stationnarisées, nous
analysons leur relation à travers un nuage de points et une régression
linéaire. Enfin, nous vérifions si les hypothèses classiques du modèle
MCO sont respectées grâce à l’étude des résidus afin de savoir si notre
estimation statistique est pertinente.
I. Analyse des séries CPI et XRUSD
On utulisera la base de donnée datascularick sur laquelle dispose les
données pour notre pays, le Danemark. Nous allons donc étudier l’indice
des prix à la consommation et le taux de change de la monnaie locale vis
à vis du dollar sur une période post 1960.
Rappelons qu’avant toute régression linéaire et/ou analyse
économétrique, il faut s’assurer que les variables soient stationnaires.
Nous allons donc ici, par représentation graphique, émettre une première
hypothèse sur leur stationnarité ou non, avant de l’affirmer ou de
l’infirmer via des tests ADF.
1. Étude de la variable CPI
A. Visualisation du CPI
Nous commencerons par analyser la premiere variable: le CPI
plot(dk$year, dk$cpi, type = "l",
main = "CPI Denmark",
xlab = "Année", ylab = "Indice de prix")

Tout d’abord, l’indice des prix à la consommation montre une tendance
haussière très marqué durant la période 1960-2020. Il n’y a aucun
fluctuation autour de la moyenne, au contraire la trajectoire est
ascendante.
Rappelons également qu’une série DS est définie comme une série qui
présente une racine unitaire, une série dont le niveau dépend fortement
de ses valeurs passées. Ce type de série ne revient pas vers sa moyenne
mais s’en éloigne durablement ce qui crée une tendance de long terme.
C’est exactement que l’on peut remarquer pour notre variable.
Ainsi nous pouvons affirmer que visuellement, le CPI n’est pas
stationnaire et est probablement un DS.
De plus, un processus DS étant défini par la présence d’une racine
unitaire, on s’attend alors à ce que les valeurs passées influencent
fortement les valeurs présentes = autocorrélation
On peut le vérifier avec l’autocorrélogramme:
acf(dk$cpi)

Chaque tiret vertical représente l’influence d’un délai (lag)
particulier sur l’évolution de la série à la période \(t\). Le premier tiret peut être négligé
ici, c’est l’influence de la série sur elle-même à la même période.
En l’absence d’autocorrélation en revanche, le reste des tirets est
censé être non-significatif (donc les tirets ne doivent pas dépasser la
ligne horizontale bleue). Ici, on voit bien que les délais jusqu’à 15
périodes (donc 15 ans avant) influencent la série à la période \(t\). C’est une indications très forte que
la série n’est pas stationnaire.
Visuellement, on conclu que la variable CPI serait probablement non
stationnaire, mais qu’en est il réellement ? Pour le verifier
formellement, nous devons utiliser les tests ADF qui nous permettra de
savoir si la variable est un TS ou un DS.
B. Tests de Stationnarité (ADF) sur CPI
L’analyse graphique du CPI révèle un trend haussier ce qui suggère
une non-stationnarité en niveau. Nous devons tester les trois tests ADF
(trend, drift et none). Pour déterminer la nature de la
non-stationnarité du CPI, on commence par tester la présence d’une
tendance déterministe en utilisant le modèle “trend”.
Rappel 1:
H0: la serie n’est pas stationnaire - Si t-stat < valeur critique
→ on rejette H0 - Si t-stat > valeur critique → on ne rejette pas
H0
summary(ur.df(dk$cpi, 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
-2.86447 -0.48159 -0.07759 0.62536 2.82975
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.76188 0.35925 2.121 0.0386 *
z.lag.1 -0.02557 0.01911 -1.338 0.1866
tt 0.06771 0.05727 1.182 0.2423
z.diff.lag 0.79734 0.08565 9.309 8.1e-13 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.9837 on 54 degrees of freedom
Multiple R-squared: 0.6258, Adjusted R-squared: 0.605
F-statistic: 30.11 on 3 and 54 DF, p-value: 1.411e-11
Value of test-statistic is: -1.3378 2.5808 1.4574
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
Ici, aucune tendance n’est détectée, “tt” (0.2423) n’étant pas
significative nous pouvons affirmer que le CPI n’est pas un trend.
Si aucune tendance n’est détectée, on teste ensuite le modèle avec
drift afin de tester si une constante affecte la dynamique de la
série.
summary(ur.df(dk$cpi, 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
-2.8107 -0.5295 -0.1019 0.5483 2.8707
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.852702 0.352201 2.421 0.0188 *
z.lag.1 -0.003183 0.002593 -1.227 0.2249
z.diff.lag 0.776554 0.084130 9.230 9.07e-13 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.9873 on 55 degrees of freedom
Multiple R-squared: 0.6162, Adjusted R-squared: 0.6022
F-statistic: 44.14 on 2 and 55 DF, p-value: 3.667e-12
Value of test-statistic is: -1.2274 3.1497
Critical values for test statistics:
1pct 5pct 10pct
tau2 -3.51 -2.89 -2.58
phi1 6.70 4.71 3.86
Rappel 2:
Pr(>|t|) = p-value du t-test -> indique si le coefficient est
statistiquement significatif (donc présence de drift) z.diff.lag =
présence d’autocorrélation ?? t stat = à comparer aux valeurs critiques
pour conclure sur la stationnarité
Dans ce modèle, la significativité du drift est évaluée par la
constante. Celle-ci est significative (p = 0.0188) ce qui indique
qu’un drift est présent. Ainsi, lorsque le drift est détecté, on doit
ensuite vérifier si l’autocorrélation est significative. Pour cela, on
regarde la variable “z.diff.lag” = 9.07e-13 ** qui est
siginificative. -> la série dépend de ses propres valeurs
passées.
En plus d’un t-stat superieur aux valeurs critiques (on ne rejette
pas H0), dans ce cas nous pouvons affirmer que le CPI est un DS.
2. Étude de la variable XRUSD
A. Visualisation de XRUSD
Visualisation de la variable XRUSD:
plot(dk$year, dk$xrusd, type = "l",
main = "XRUSD",
xlab = "Année", ylab = "DKK par USD")

Concernant le taux de change XRUSD, il n’y a pas de trend déterminé
mais nous pouvons affirmer que la série fluctue autour d’une moyenne.
Or, nous observons que sur certaines périodes notamment en 1985 et en
2000, il y a des fluctuations beaucoup plus fortes nous laissant penser
que la variance peut changer dans le temps = variance n’est pas contante
(même si l’on observe un retour à la “moyenne” assez vite)
Ce comportement est incompatible avec la stationnarité, car rappelons
le; Une série stationnaire est une série dont les propriétés
statistiques – moyenne, variance et covariance – sont constantes dans le
temps. Formellement, on doit avoir : (Y_t)=, (Y_t)=^2, et
(Y_t,Y_{t-h})=(h). Toute violation de ces conditions implique une
non-stationnarité.
Cependant ici, nous mesurerons nos propos en affirmant qu’il y a
effectivement des chocs, qu’il y a effectiviement quelques amplitudes
inégales, pour autant la série revient plus ou moins autour de sa
moyenne après ces derniers donc nous ne pouvons pas rejeter visuellement
une stationnarité.
B. Tests de Stationnarité (ADF) sur XRUSD
Dans un second temps, afin de vérifier formellement la stationnarité
de nos séries, nous appliquons le test de Dickey-Fuller augmenté (ADF).
L’idée est de savoir si la série est stationnaire ou non.
Nous commençons par estimer le modèle avec tendance déterministe
(type = “trend”), puis, en l’absence de tendance significative, nous
testons le modèle avec constante uniquement (type = “drift”), et enfin,
si la constante elle-même n’est pas significative, nous estimons le
modèle sans constante (type = “none”).
acf(dk$xrusd)

Contrairement au CPI, cette autocorrélation décroît progressivement
et disparaît rapidement après les premiers lags. On n’observe pas une
autocorrélation sur toute la série. Visuellement, cela suggère que XRUSD
pourrait être stationnaire ou proche de l’être car la dépendance existe
mais reste modérée et s’éteint rapidement.
Pour trancher formellement, il est nécessaire d’avoir recours aux
tests ADF qui permettront de déterminer si XRUSD suit un processus TS ou
DS.
Même chose pour XRUSD, on a tester les trois tests ADF (trend, drift,
none):
summary(ur.df(dk$xrusd, 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
-1.42662 -0.44158 -0.02216 0.37511 1.74513
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 2.352715 0.618315 3.805 0.000364 ***
z.lag.1 -0.325384 0.082166 -3.960 0.000221 ***
tt -0.006841 0.005317 -1.286 0.203762
z.diff.lag 0.441086 0.123031 3.585 0.000724 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.648 on 54 degrees of freedom
Multiple R-squared: 0.2839, Adjusted R-squared: 0.2441
F-statistic: 7.137 on 3 and 54 DF, p-value: 0.000401
Value of test-statistic is: -3.9601 5.2414 7.8494
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
Pour “trend”, la tendance tt n’est pas significative (t-stat =
–1.286, p = 0.2038). On en conclut qu’il n’y a pas de trend déterministe
et que le processus n’est pas un TS.
summary(ur.df(dk$xrusd, 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
-1.50179 -0.46566 0.05874 0.30895 1.72165
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.93817 0.53085 3.651 0.000583 ***
z.lag.1 -0.29433 0.07901 -3.725 0.000461 ***
z.diff.lag 0.42369 0.12301 3.444 0.001103 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.6518 on 55 degrees of freedom
Multiple R-squared: 0.262, Adjusted R-squared: 0.2351
F-statistic: 9.761 on 2 and 55 DF, p-value: 0.0002356
Value of test-statistic is: -3.7254 6.9518
Critical values for test statistics:
1pct 5pct 10pct
tau2 -3.51 -2.89 -2.58
phi1 6.70 4.71 3.86
Pour ce test de regression drift, la constante est significative (p
< 0.01), ce qui révèle la présence d’un drift. En plus de ça, il y a
de l’autocorrélation significative 5% (0.001103 **). Cependant, la
précense d’un drift + autocorrélation n’implique pas directement la
présence d’un DS. Si le drift est significatif avec une autocorrélation
significative (comme ici) mais que t-stat = –3.7254 est inférieure à la
valeur critique à 1 % (–3.51), cela conduit à rejeter très fortement
l’H0.
Ainsi, bien que le graphique du taux de change XRUSD laisse entrevoir
des variations d’amplitude inégales, XRUSD est stationnaire.
Pour résumer, nous avons donc:
-CPI: DS -XRUSD: Stationnaire
Afin d’effectuer notre regression linéaire, il convient ici de
stationnariser la variable “CPI”.
II. Stationnarisation des séries CPI et XRUDS
1. Mise en différence
Dans le cas des processus stationnaires en différence (DS), il suffit
de passer la série en différence \(\Delta Y_t
= Y_t - Y_{t-1}\) pour la rendre stationnaire.
dk <- dk %>%
mutate(dcpi = cpi - lag(cpi)) %>%
na.omit()
2. Vérification de la Stationnarité
Après avoir identifié que le CPI est un processus DS et l’avoir
“stationnarisé” en appliquant une différence première, il faut vérifier
si cette transformation a bien rendu la série stationnaire. Comme la
série différenciée ne contient ni tendance déterministe ni constante, le
test ADF approprié est le modèle “none” qui teste uniquement la présence
d’une racine unitaire (stationnaire ou non).
dk <- dk %>%
mutate(dcpi = c(NA, diff(cpi))) %>%
na.omit()
summary(ur.df(dk$dcpi, 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
-2.6849 -0.3856 0.1642 0.6789 2.8243
Coefficients:
Estimate Std. Error t value Pr(>|t|)
z.lag.1 -0.04604 0.04579 -1.006 0.3191
z.diff.lag -0.22395 0.13294 -1.685 0.0978 .
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 1.024 on 54 degrees of freedom
Multiple R-squared: 0.07814, Adjusted R-squared: 0.04399
F-statistic: 2.288 on 2 and 54 DF, p-value: 0.1112
Value of test-statistic is: -1.0055
Critical values for test statistics:
1pct 5pct 10pct
tau1 -2.6 -1.95 -1.61
On remarque encore une fois que la t-stat est superieur aux valeurs
critiques, donc la difference première n’a pas suffit pour rendre CPI
stationnaire = il faut passer en difference seconde.
dk <- dk %>%
mutate(
dcpi = c(NA, diff(cpi)),
ddcpi = c(NA, diff(dcpi))
)
Il faut supprimer les NA (valeurs manquantes) générées par les
différences successives puisqu’une régression ou un test ADF ne peut pas
être estimé avec des observations manquantes. Nous utilisons donc la
série sans NA avec “ddcpi_clean <- na.omit(dk$ddcpi)” afin de tester
correctement la stationnarité.
ddcpi_clean <- na.omit(dk$ddcpi)
summary(ur.df(ddcpi_clean, 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
-2.80753 -0.57796 0.05711 0.58136 2.73969
Coefficients:
Estimate Std. Error t value Pr(>|t|)
z.lag.1 -1.3745 0.2180 -6.304 6.35e-08 ***
z.diff.lag 0.1017 0.1381 0.736 0.465
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 1.046 on 52 degrees of freedom
Multiple R-squared: 0.6266, Adjusted R-squared: 0.6122
F-statistic: 43.63 on 2 and 52 DF, p-value: 7.534e-12
Value of test-statistic is: -6.304
Critical values for test statistics:
1pct 5pct 10pct
tau1 -2.6 -1.95 -1.61
Après avoir établi que le CPI était non-stationnaire en niveau et en
première différence, nous avons appliqué une seconde différence. Le test
ADF “none” sur la série ddCPI montre un t-stat de –6.20 largement
inférieur aux valeurs critiques (–2.6 au seuil de 1 %). Nous rejetons
donc fortement l’hypothèse nulle de racine unitaire. Ainsi ddCPI est
stationnaire. Enfin, nous allons représenter le CPI avant et après la
difference seconde:
# Graphique en niveau: CPI non stationnaire
ggplot(dk, aes(x = year, y = cpi)) +
geom_line(lwd = 1) +
labs(title = "CPI Denmark - Niveau",
x = "Année", y = "Indice des prix") +
theme_bw()

# Graphique de CPI après la difference seconde
ggplot(dk, aes(x = year, y = ddcpi)) +
geom_line() +
labs(title = "CPI Denmark - Différence seconde (Δ²CPI)",
x = "Année", y = "Δ²CPI") +
theme_bw()

->Le CPI est donc un processus intégré d’ordre 2,
I(2).
III. Relation entre les deux variables CPI et XRUSD
1. Nuage de points
Pour estimer graphiquement le lien entre les variables, il est
nécessaire de les visualier via un nuage de points.
ggplot(data = dk, aes(x = xrusd, y = ddcpi)) +
geom_point() +
geom_smooth(method = "lm") +
labs(
title = "d²CPI en fonction de XRUSD",
x = "XRUSD",
y = "Δ²CPI"
) +
theme_bw()

Le nuage de points représentant la relation entre le taux de change
XRUSD et la difference seconde du CPI (d²CPI) ne laisse apparaître
aucune relation linéaire nette. Les points sont largement dispersés sans
structure claire ce qui suggère qu’il n’existe pas de corrélation
visuelle entre les deux variables. La droite de régression présente une
pente légèrement négative (si XRUSD s’apprécie alors CPI diminue
légèrement)
Une régression linéaire est nécessaire pour confirmer ou infirmer
l’existence d’un pass-through significatif entre XRUSD et
l’inflation.
2. Regréssion linéaire
reg_lin <- feols(ddcpi ~ xrusd, data = dk)
etable(reg_lin)
reg_lin
Dependent Var.: ddcpi
Constant 0.5015 (0.8181)
xrusd -0.0757 (0.1220)
_______________ ________________
S.E. type IID
Observations 56
R2 0.00708
Adj. R2 -0.01131
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
On voit ici que le coefficient associé au taux de change XRUSD n’est
pas significatif à 5%. Il n’existe pas de relation statistiquement
détectable entre les variations du taux de change et les variations du
niveau des prix stationnarisé. Dans ce cadre, le pass-through du taux de
change vers l’inflation n’apparaît pas, les fluctuations du taux de
change ne se transmettent donc pas directement aux prix à la
consommation.
IV. Vérification des hypothèses des MCO
1. Analyse des valeurs ajustées et des résidus
Les résidus représentent l’erreur de prédiction du modèle : ils
mesurent à quel point la régression parvient — ou échoue — à reproduire
la dynamique réelle de la variable expliquée. Dans l’idéal, un bon
modèle MCO produit des résidus « neutres » : en moyenne proches de zéro,
sans tendance particulière, avec une variance constante et aucune
dépendance dans le temps. Autrement dit, si le modèle est correctement
spécifié, les résidus doivent se comporter comme un bruit blanc.
L’analyse des résidus permet donc de vérifier si les hypothèses
classiques du MCO sont respectées, et donc si la régression peut être
considérée comme fiable et interprétable.
On peut imaginer qu’une série temporelle est, à l’origine, une simple
suite de bruits blancs perturbée au fil du temps par divers chocs
exogènes. Le rôle de la régression est précisément de retirer
l’influence de ces chocs : si le modèle est correctement spécifié, les
résidus doivent donc retrouver le comportement d’un bruit blanc =série
sans structure, centrée, indépendante et de variance constante.
Pour évaluer la qualité de notre modèle, nous comparons les valeurs
observées de Δ²CPI aux valeurs ajustées par la régression afin de
visualiser la capacité explicative réelle du modèle
fitted_val <- reg_lin$fitted.values
residuals <- reg_lin$residuals
dk_clean <- dk %>%
dplyr::select(year, xrusd, ddcpi) %>%
na.omit()
dk2 <- dk_clean %>%
cbind(fitted_val) %>%
cbind(residuals)
ggplot(dk2, aes(x = year, y = ddcpi)) +
geom_line(lwd = 1) +
geom_line(aes(y = fitted_val), color = "red", lty = 2, lwd = 1) +
labs(
title = "Valeurs observées vs valeurs ajustées",
x = "Année",
y = "Δ²CPI"
) +
theme_bw()

Le graphique montre que les valeurs ajustées par le modèle restent
presque constantes tandis que les valeurs observées de Δ²CPI fluctuent
fortement. ->le modèle explique très peu la dynamique réelle de la
série.
Nous devons maintenant vérifier si les hypothèses classiques du
modèle des MCO sont respectées afin de garantir la validité statistique
de notre estimation.
2. Tests de diagnostic des résidus
dk_clean <- dk %>%
dplyr::select(year, xrusd, ddcpi) %>%
na.omit()
dk2 <- dk_clean %>%
mutate(
residuals = reg_lin$residuals,
fitted_values = reg_lin$fitted.values
)
head(dk2)
Juste avant de réaliser un test formel, nous commençons par examiner
graphiquement les résidus au cours du temps afin d’évaluer visuellement
si leur variance est constante. -Une variance stable indiquerait une
homoscédasticité -des variations marquées de l’amplitude des résidus
suggéreraient une hétéroscédasticité potentielle.
ggplot(dk2, aes(x = year, y = residuals)) +
geom_line(lwd = 1) +
geom_hline(yintercept = 0, lty = 2) +
labs(title = "Résidus de la régression dans le temps",
x = "Année", y = "Résidus") +
theme_bw()

On peut voir que la variance des résidues modérée dans les années
1970–1980, mais à partir du début des années 2008-2010, l’amplitude des
résidus augmente fortements. Cette évolution amène à penser que les
résidus pourraient être 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 utilise donc le test de
Breusch-Pagan.
1. Hétéroscédasticité: Breusch-Pagan
bptest(ddcpi ~ xrusd, data = dk)
studentized Breusch-Pagan test
data: ddcpi ~ xrusd
BP = 4.9343, df = 1, p-value = 0.02633
Dans notre cas, le test BP donne une statistique de 4.9343 pour 1
degré de liberté avec une p-value = 0.02633. Comme la p-value est
significative à 5%, on rejette l’hypothèse nulle d’homoscédasticité et
on conclut que les résidus sont hétéroscédastiques.
2. Normalité: Shapiro-Wilk
ggplot(dk2, 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. 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(dk2$residuals)
Shapiro-Wilk normality test
data: dk2$residuals
W = 0.94218, p-value = 0.009632
La p-value est significative, donc les résidus ne suivent pas une loi
normale selon le test de Shapiro. Cela signifie que les erreurs du
modèle ne sont pas distribuées de façon symétrique autour de zéro.
3. Indépendance: Ljung-Box
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(dk2$residuals)

Ici, on observe un pic significatif au lag 1. Les autres lags ne sont
pas significatifs. Après l’analyse visuelle, il convient d’utiliser 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(dk2$residuals, lag = 10, type = "Ljung-Box")
Box-Ljung test
data: dk2$residuals
X-squared = 8.401, df = 10, p-value = 0.5897
La p-value du test de Ljung-Box n’est pas significative. On ne
rejette donc pas l’hypothèse nulle d’indépendance des résidus. Ce test
confirme ce que nous avons vu; les résidus apparaissent indépendants et
il n’y a pas d’autocorrélation entre eux.
Concernant les MCO, plusieurs hypothèses sont violées: -les résidus
sont hétéroscédastiques -ils ne suivent pas une loi normale -mais ils
apparaissent indépendants
V. Conclusion
Dans l’ensemble, notre modèle est peu performant dans l’explication
de la dynamique de l’inflation au Danemark. Le coefficient du taux de
change (β) n’est pas significatif donc les variations du taux de change
n’expliquent pas les variations de Δ²CPI. Pour répondre à notre
question, on ne détecte aucun pass-through dans notre modèle: les
variations du taux de change n’ont aucun impact significatif sur le CPI
###= le pass-through est nul.
Enfin, pour clôre cette première partie, nous comparerons notre étude
à celle de la BIS. Dans notre étude nous utilisons une régression
linéaire simple en séries temporelles (plusieurs “t” pour un seul
individu, ici le Danemark), où l’inflation stationnarisée (Δ²CPI) est
expliquée par le taux de change XRUSD. Il s’agit donc d’un modèle
univarié qui tient compte d’une seule relation directe. Dans l’étude de
la BIS, les auteurs utilisent des modèles multivariés estimés en panel.
Leur approche permet donc de mieux expliquer le “pass-through”, avec une
richesse de données beaucoup plus importante.
Pour rapprocher notre étude de la leur, il faudrait avant tout
travailler avec des données plus fréquentes ce qui permettrait fortement
d’enrichir notre analyse du pass-through.
PARTIE 2: PRÉVISIONS DU PIB
Pour continuer maintenant, nous devons prévoir la croissance future
de notre pays d’intérêt sur les 5 prochaines années. Pour cela, vous
vous servirez des modèles ARMA afin de faire des prévisions. Vous
choisirez le modèle optimal et effectuerez une prévision unique de la
croissance du PIB. Vous commenterez ensuite les résultats obtenus, et
conseillerez le responsable politique sur la politique appropriée.
Commentez également les limites liées à votre prévision.
donnees_dk <- data_schularick %>%
filter(country=="Denmark")%>%
select(year, gdp)%>%
mutate(gdp_growth = (log(gdp) - lag(log(gdp)))*100 )%>%
na.omit()%>%
filter(year >= 1950 & year < 2020)
head(donnees_dk)
On commence à partir de 1950 car avant c’était la Seconde Guerre
Mondiale, et on a retiré 2020 car c’est une année exceptionnelle, avec
un choc purement exogène (donc impossible de le relier à des variations
passées du PIB).
donnees_dk %>%
ggplot(aes(x=year, y=gdp_growth))+
geom_line()

Nous remarquons qu’à partir des années 60 jusqu’en 1985 environ, le
PIB du Danemak est a son apogé avec une croissance moyenne par an
d’envirion 10%. Cependant après 1985, il y a une chute drastique du PIB
chutant à environ 2.5%. Nous observons un pic du PIB qui est baissier
juste avant les années 2010 qui est dû à la crise des subprimes.
df <- donnees_dk %>% arrange(year)
y_ts <- ts(
df$gdp_growth,
start = min(df$year),
frequency = 1
)
ici, on met les données en ordre chronologique puis on convertit
notre variable du PIB en une serie temporelle annuelle afin de pouvoir
appliquer le modèle temporel ARIMA.
require(forecast)
fit_arima <- auto.arima(y_ts)
fit_arima
Series: y_ts
ARIMA(0,1,1)
Coefficients:
ma1
-0.6236
s.e. 0.0880
sigma^2 = 6.778: log likelihood = -163.67
AIC=331.35 AICc=331.53 BIC=335.82
On estime ensuite le modèle ARIMA. La sélection automatique du modèle
nous donne le modèle ARIMA(0,1,1) -> MA(1) comme celui minimisant le
critère AIC. Ce modèle est donc considéré comme le plus adapté pour
capturer la dynamique du PIB danois.
On peut donc regarder la dynamique des résidus du modèle MA(1) qui
correspondent à la composante du PIB non expliquée par le modèle et les
comparer aux valeurs observées pour évaluer la qualité de
l’ajustement.
Juste avant, il faut extraire les valeurs ajustées (fitted values) du
modèle ARIMA correspondant aux valeurs que le modèle ARIMA aurait
prédites pour chaque année de la période d’estimation. Cela permet de
comparer ce que le modèle prévoit contre ce qui s’est réellement
passé.
fitted_arima <- fitted(fit_arima)
Nous construisons ensuite un tableau comprenant les valeurs observées
du PIB et les valeurs ajustées par ARIMA afin de comparer la qualité
d’ajustement du modèle sur l’échantillon:
df_in_sample <- data.frame(
year = as.numeric(time(y_ts)),
gdp_growth = as.numeric(y_ts),
arima_fitted = as.numeric(fitted_arima)
)
head(df_in_sample)
Ainsi nous obtenons:
ggplot(df_in_sample, aes(x = year)) +
geom_line(aes(y = gdp_growth), linetype = "solid") +
geom_line(aes(y = arima_fitted), linetype = "dashed", color="red") +
labs(
title = "In-sample: actual vs ARIMA fitted",
y = "Value"
)

Le graphique compare les valeurs observées du PIB (trait noir) aux
valeurs ajustées par le modèle ARIMA (trait rouge). On voit que le
modèle capture la tendance centrale de l’évolution générale du PIB, mais
reste tout de même légèrement éloigné des fluctuations réelles. En
effet, les valeurs ajustées apparaissent plus “lisses” et moins
volatiles que les observations, exemple avec le pic baissier causé par
la GCF.
On va, afin de réaliser nos prévisions, établir la taille de notre
échantillon sur lequel on appliquera le modèle de prévision ARIMA. Ici,
la taille de l’échantillon est de 15 ans.
n <- length(y_ts)
h <- 15 # tu fixes ici
Ici, on va venir diviser la partie en deux: “train” sert à estimer le
modèle ARIMA, et “test” sert à vérifier la qualité des prévisions
hors-échantillon.
y_train <- window(y_ts, end = time(y_ts)[n - h])
y_test <- window(y_ts, start = time(y_ts)[n - h + 1])
On estime ensuite un modèle ARIMA seulement sur la partie train, puis
on génère des prévisions sur les 15 années du test accompagnées des
intervalles de confiance à 80 % et 95 %. Enfin, on construit un tableau
comparant les valeurs réelles du PIB avec les prévisions ARIMA et leurs
intervalles ce qui permet de visualiser et d’évaluer la performance
prédictive du modèle.
fit_arima_oos <- auto.arima(y_train)
fc_arima_oos <- forecast(fit_arima_oos, h = h, level = c(80, 95))
years_test <- as.numeric(time(y_test))
arima_insample <- data.frame(
year = years_test,
gdp_growth = as.numeric(y_test),
arima_forecast = as.numeric(fc_arima_oos$mean),
arima_lower_95 = fc_arima_oos$lower[, "95%"],
arima_upper_95 = fc_arima_oos$upper[, "95%"]
)
arima_insample
NA
Représentation graphique:
ggplot(arima_insample, aes(x = year)) +
geom_line(aes(y = gdp_growth), linetype = "solid") +
geom_line(aes(y = arima_forecast), linetype = "dashed") +
geom_ribbon(aes(ymin = arima_lower_95, ymax = arima_upper_95),
alpha = 0.2) +
labs(
title = "Out-of-sample: ARIMA forecast vs actual",
y = "Value"
)

Le graphique compare les valeurs réelles du PIB aux prévisions du
modèle ARIMA (courbe pointillée), accompagnées de leur intervalle de
confiance à 95 % correspondant à la zone grisée.
Nous remarquons que le modèle prévoit une trajectoire relativement
stable alors que les valeurs réelles présentent des fluctuations
importantes notamment le pic négatif très marqué au moment de la crise
financière de 2008. Ce choc écononomique n’est pas anticipé par le
modèle ARIMA ce qui montre sa principale limite. Pour autant, ce modèle
capture relativement bien la tendance générale mais ne peut prévoir à
l’avance les crises (ce qui va de soi).
Enfin, nous allons procéder aux prévisions concernant la croissance
du PIB danois sur les 5 prochaines années.
h <- 5
fc_arima <- forecast(fit_arima, h = h)
plot(fc_arima)

Avec le modèle ARIMA, on peut anticiper que la croissance du PIB va
rester entre à peu près -1/2% et 7-8% jusqu’en 2024, ce qui reste un
intervalle très large. Dans la réalité, la crise du Covid a créé une
baisse importante du PIB danois en 2020 avec une décroissance de -1.8%,
contre un rebond assez important en 2021 s’élevant à 7.4%. Rien qu’avec
ce rebond, on pourrait être tenté d’invalider nos prévisions.
Finalement, une fois de plus les chocs imprévisibles démontrent les
limites de ce modèle.
Concernant la mise en place d’une politique appropriée, au vu de nos
estimations “plates”, il est difficile de conseiller sur une politique
en particulier. Nous pouvons, par ailleurs, affirmer qu’en se basant
uniquement sur nos prévisions, il n’y aurait a priori pas de crise à
prévoir. (Rappelons que le modèle ARIMA ne prévoit pas les crises, ici
le but est simplement de répondre à la question sur la politique
appropriée en se basant simplement sur nos prévisions.)
PARTIE 3: MODÈLE À CORRECTION D’ERREURS
votre_pays <- "Denmark"
donnees_df <- data_schularick %>%
filter(country == votre_pays) %>%
filter(year > 1960) %>%
select(year, revenue, expenditure) %>%
mutate(
revenue_growth = c(NA, diff(log(revenue)) ),
expenditure_growth = c(NA, diff(log(expenditure)) )
) %>%
na.omit()
head(donnees_df)
Tout d’abord, nous tester si nos deux variables sont
stationnaires.
summary(ur.df(donnees_df$revenue_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
-0.138896 -0.023615 -0.002589 0.046756 0.167424
Coefficients:
Estimate Std. Error t value Pr(>|t|)
z.lag.1 -0.11866 0.07170 -1.655 0.104
z.diff.lag -0.68040 0.09532 -7.138 2.24e-09 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.05348 on 55 degrees of freedom
Multiple R-squared: 0.5599, Adjusted R-squared: 0.5439
F-statistic: 34.98 on 2 and 55 DF, p-value: 1.577e-10
Value of test-statistic is: -1.655
Critical values for test statistics:
1pct 5pct 10pct
tau1 -2.6 -1.95 -1.61
Le test ADF donne un tstat de –1.655. Comme –1.655 est supérieur à la
valeur critique de 5% (–1.95) mais à peine plus faible que celle de 10%
(–1.61), revenue_growth apparaît non stationnaire. Nous devons donc
réaliser un second test ADF, cette fois-ci en passant en difference
première:
summary(ur.df(diff(donnees_df$revenue_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
-0.147019 -0.032890 -0.005967 0.030594 0.140596
Coefficients:
Estimate Std. Error t value Pr(>|t|)
z.lag.1 -2.2542 0.2403 -9.382 6.23e-13 ***
z.diff.lag 0.2935 0.1292 2.272 0.0271 *
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.05239 on 54 degrees of freedom
Multiple R-squared: 0.8794, Adjusted R-squared: 0.8749
F-statistic: 196.8 on 2 and 54 DF, p-value: < 2.2e-16
Value of test-statistic is: -9.3815
Critical values for test statistics:
1pct 5pct 10pct
tau1 -2.6 -1.95 -1.61
Le test ADF nous dévoile une tstat très inférieure aux valeurs
critiques (t = –9.38 < –2.6 à 1 %). Ainsi la série différenciée est
stationnaire. Nous obtenons donc: revenue_growth est un processus
intégré d’ordre 1, I(1).
Ensuite, il convient ici de faire la même chose pour la variable
“expenditure_growth”
summary(ur.df(donnees_df$expenditure_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
-0.070330 -0.021074 0.006501 0.018314 0.161241
Coefficients:
Estimate Std. Error t value Pr(>|t|)
z.lag.1 -0.08708 0.06252 -1.393 0.169267
z.diff.lag -0.44478 0.12227 -3.638 0.000608 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.04714 on 55 degrees of freedom
Multiple R-squared: 0.2481, Adjusted R-squared: 0.2207
F-statistic: 9.072 on 2 and 55 DF, p-value: 0.0003935
Value of test-statistic is: -1.3929
Critical values for test statistics:
1pct 5pct 10pct
tau1 -2.6 -1.95 -1.61
Le test ADF montre que la tstat est de –1.39 qui est supérieure aux
seuils critiques, ce qui conduit à affirmer que la série n’est pas
stationnaire et doit être différenciée pour le devenir.
summary(ur.df(diff(donnees_df$expenditure_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
-0.099124 -0.026948 -0.000348 0.015206 0.143290
Coefficients:
Estimate Std. Error t value Pr(>|t|)
z.lag.1 -1.7549 0.2362 -7.429 8.29e-10 ***
z.diff.lag 0.1774 0.1369 1.296 0.2
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.04751 on 54 degrees of freedom
Multiple R-squared: 0.737, Adjusted R-squared: 0.7273
F-statistic: 75.67 on 2 and 54 DF, p-value: < 2.2e-16
Value of test-statistic is: -7.429
Critical values for test statistics:
1pct 5pct 10pct
tau1 -2.6 -1.95 -1.61
Après passage en différence première, la tstat (–7.43) devient
largement inférieure a ux valeurs critiques ce qui confirme que la
difference premiere de notre série expenditure_growth est
stationnaire.
Ainsi, les deux séries étudiées; revenue_growth et
expenditure_growth, apparaissent non stationnaires en niveau car leurs
tstat sont supérieures aux valeurs critiques.
En revanche, après passage en différence première les deux séries
deviennent clairement stationnaires : -ADF(Δrevenue_growth) = –9.38
-ADF(Δexpenditure_growth) = –7.4 Ainsi, les deux variables sont
intégrées d’ordre 1, I(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 un risque de
régression fallacieuse si on fait la régression classique. Etant donné
la présence de cointégration dans notre modèle, on teste la validité du
modèle à correction d’erreurs:
fs <- feols(revenue_growth ~ expenditure_growth, data = donnees_df)
donnees_df$resid <- residuals(fs)
summary(ur.df(donnees_df$resid, 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
-0.140695 -0.031834 -0.004368 0.028508 0.155290
Coefficients:
Estimate Std. Error t value Pr(>|t|)
z.lag.1 -0.8870 0.1928 -4.601 2.52e-05 ***
z.diff.lag -0.1349 0.1385 -0.974 0.334
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.05276 on 55 degrees of freedom
Multiple R-squared: 0.4997, Adjusted R-squared: 0.4815
F-statistic: 27.46 on 2 and 55 DF, p-value: 5.371e-09
Value of test-statistic is: -4.6005
Critical values for test statistics:
1pct 5pct 10pct
tau1 -2.6 -1.95 -1.61
Comme la tstat est –4.60 < –2.6, nous pouvons affirmer que les
résidus sont stationnaire et que donc il existe bien une relation de
long terme entre revenue_growth et expenditure_growth.
Ainsi, comme les deux séries sont intégrées du même ordre et leurs
résidus sont stationnaires on peut alors utiliser un modèle à correction
d’erreur (ECM) à l’étape 2.
On crée ensuite la variable lresiduals qui représente l’écart de la
relation long terme à la période précédente, car c’est cette déviation
qui permet au modèle de mesurer la vitesse de retour vers l’équilibre.
-> pour mesurer la vitesse à laquelle le système corrige les
déséquilibres de long terme.
donnees_df_2 <- donnees_df %>%
mutate(lresiduals = dplyr::lag(resid, 1))
Puis, en sachant que nos deux variables sont stationnaires une fois
la difference premiere réalisée, il faut donc creer les “variables”
différences premières des deux séries car le modèle à correction
d’erreur nécessite de travailler avec des variables stationnaires en
variation (ΔYₜ et ΔXₜ), afin de capturer correctement la dynamique de
court terme.
Par ailleurs, puisque nos deux variables deviennent stationnaires
après passage en différence première, il est nécessaire de créer les
series en difference premiere “drevenue_growth” et “dexpenditure_growth”
car le modèle à correction d’erreur doit utiliser nos variables
stationnaires (ΔYₜ et ΔXₜ) afin de capturer la dynamique de court
terme.
donnees_df_2 <- donnees_df_2 %>%
mutate(
d_revenue_growth = c(NA, diff(revenue_growth)),
d_expenditure_growth = c(NA, diff(expenditure_growth))
) %>%
na.omit()
Ainsi on réalise donc le modèle à correction d’erreur permettant
d’étudier simultanément la relation court et long terme (corréction des
écarts) entre les variations des dépenses publiques et celles des
revenus publics.
ecm <- feols(
d_revenue_growth ~ d_expenditure_growth + lresiduals,
data = donnees_df_2
)
etable(ecm)
ecm
Dependent Var.: d_revenue_growth
Constant -0.0011 (0.0070)
d_expenditure_growth 0.6273*** (0.1302)
lresiduals -1.006*** (0.1380)
____________________ __________________
S.E. type IID
Observations 58
R2 0.57356
Adj. R2 0.55805
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Le coefficient de d_expenditure_growth 0.6273*** est positif et très
significatif, cela signifie qu’à court terme une hausse des dépenses
publiques s’accompagne d’une hausse des revenus publics. Le coefficient
de lresiduals -1.006*** est négatif, très significatif et légèrement
inférieur à –1 ce qui indique une forte force de rappel vers l’équilibre
de long terme. Cela signifie que lorsque les revenus s’éloignent de leur
trajectoire “théorique”, l’ajustement se fait rapidement.
Par ailleurs, les résidus de la première étape sont stationnaires,
donc l’ECM est valide. De plus, puisque le coefficient de lagresiduals
est négatif très significatif et compris entre –1 et 0 (ici nous dirons
pour des raions de simplicité que -1.006*** est environ égal à -1), il
est préférable d’utiliser le modèle à correction d’erreur plutôt qu’un
OLS classique pour représenter la relation entre revenue_growth et
expenditure_growth car l’ECM intègre à la fois l’ajustement court terme
et la relation d’équilibre de long terme alors que l’OLS non.
Avant de terminer, il faut garantir la fiabilité de notre modèle à
correction d’erreur en regardant si les résidus verifient trois
hypothèses. Nous testerons donc: -l’homoscédasticité à l’aide du test de
Breusch-Pagan qui permet de vérifier que la variance des résidus reste
constante dans le temps.
-ensuite la normalité des résidus via le test Shapiro-Wilk qui teste
la normalité d’une série
-Et enfin, l’indépendance des résidus grâce au test Ljung-Box afin de
s’assurer qu’il n’y a pas d’autocorrélation “les résidus d’une période
ne doivent pas être expliqués par les résidus précédents.”
res_ecm <- residuals(ecm)
bptest(d_revenue_growth ~ d_expenditure_growth + lresiduals, data = donnees_df_2)
studentized Breusch-Pagan test
data: d_revenue_growth ~ d_expenditure_growth + lresiduals
BP = 0.64861, df = 2, p-value = 0.723
Dans notre cas, le test BP donne une statistique de 0.64861 pour 1
degré de liberté avec une p-value = 0.723. Comme la p-value n’est pas
significative, on ne rejette pas l’hypothèse nulle d’homoscédasticité et
on conclut que les résidus sont homoscédastiques.
shapiro.test(res_ecm)
Shapiro-Wilk normality test
data: res_ecm
W = 0.97386, p-value = 0.2427
La p-value est significative, donc les résidus ne suivent pas une loi
normale selon le test de Shapiro. Cela signifie que les erreurs du
modèle ne sont pas distribuées de façon symétrique autour de zéro.
Box.test(res_ecm, lag = 10, type = "Ljung-Box")
Box-Ljung test
data: res_ecm
X-squared = 6.9619, df = 10, p-value = 0.729
La p-value du test de Ljung-Box n’est pas significative. On ne
rejette donc pas l’hypothèse nulle d’indépendance des résidus. Les
résidus apparaissent indépendants et il n’y a pas d’autocorrélation
entre eux.
Pour terminer, le test de Breusch-Pagan indique une homoscédasticité
des résidus (variance des erreurs reste stable dans le temps). En
revanche, le test de Shapiro-Wilk montre que les résidus ne suivent pas
une loi normale. Enfin, le test de Ljung-Box révèle que les résidus sont
indépendants donc sans autocorrélation. Ainsi, malgré une non-normalité
des erreurs l’ECM reste globalement correcte, car les propriétés
essentielles de variance constante et d’absence de dépendance temporelle
sont respectées.
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CnNldHdkKGRpciA9ICJ+L0Rlc2t0b3AvUi9SMiIpCgpyZXF1aXJlKHJlYWR4bCkKcmVxdWlyZSh0aWR5dmVyc2UpCnJlcXVpcmUoZ2dwbG90MikKcmVxdWlyZSh1cmNhKQpyZXF1aXJlKGZpeGVzdCkKcmVxdWlyZShsbXRlc3QpCnJlcXVpcmUoZm9yZWNhc3QpCgpgYGAKCmBgYHtyfQpkYXRhX3NjaHVsYXJpY2sgPC0gcmVhZF9leGNlbCgifi9EZXNrdG9wL1IvZGF0YV9zY2h1bGFyaWNrLnhsc3giKQpgYGAKCmBgYHtyfQpkayA8LSBkYXRhX3NjaHVsYXJpY2sgJT4lCiAgZmlsdGVyKGNvdW50cnkgPT0gIkRlbm1hcmsiKSAlPiUKICBkcGx5cjo6c2VsZWN0KHllYXIsIGNwaSwgeHJ1c2QpICU+JQogIGZpbHRlcih5ZWFyID4gMTk2MCkKCmhlYWQoZGspCmBgYAoKIyBQQVJUSUUgMTogUsOJR1JFU1NJT04gTElOw4lUQUlSRSAKIyBJbnRyb2R1Y3Rpb24KKioqCgpMJ29iamVjdGlmIGRhbnMgY2V0dGUgcHJlbWnDqHJlIHBhcnRpZSBkZSBwcm9qZXQsIGVzdCBk4oCZYW5hbHlzZXIgbGUgcGFzcy10aHJvdWdoIApkdSB0YXV4IGRlIGNoYW5nZSBzdXIgbOKAmWluZmxhdGlvbiBhdSBEYW5lbWFyayBlbiDDqXR1ZGlhbnQgbGEgbWFuacOocmUgZG9udCBsZXMgCnZhcmlhdGlvbnMgZHUgdGF1eCBkZSBjaGFuZ2Ugc2UgdHJhbnNtZXR0ZW50IGF1eCBwcml4IMOgIGxhIGNvbnNvbW1hdGlvbi4gCgpQb3VyIHLDqXBvbmRyZSDDoCBjZXR0ZSBxdWVzdGlvbiwgbm91cyDDqXR1ZGlvbnMgZOKAmWFib3JkIGxlIGNvbXBvcnRlbWVudCBkZXMgc8OpcmllcyAKQ1BJIGV0IFhSVVNELCBwdWlzIG5vdXMgdsOpcmlmaW9ucyBsZXVyIHN0YXRpb25uYXJpdMOpIMOgIGzigJlhaWRlIGRlIHRlc3RzIEFERi4gClVuZSBmb2lzIGxlcyBzw6lyaWVzIGNvcnJlY3RlbWVudCBzdGF0aW9ubmFyaXPDqWVzLCBub3VzIGFuYWx5c29ucyBsZXVyIHJlbGF0aW9uIMOgIAp0cmF2ZXJzIHVuIG51YWdlIGRlIHBvaW50cyBldCB1bmUgcsOpZ3Jlc3Npb24gbGluw6lhaXJlLiBFbmZpbiwgbm91cyB2w6lyaWZpb25zIHNpIApsZXMgaHlwb3Row6hzZXMgY2xhc3NpcXVlcyBkdSBtb2TDqGxlIE1DTyBzb250IHJlc3BlY3TDqWVzIGdyw6JjZSDDoCBs4oCZw6l0dWRlIGRlcyAKcsOpc2lkdXMgYWZpbiBkZSBzYXZvaXIgc2kgbm90cmUgZXN0aW1hdGlvbiBzdGF0aXN0aXF1ZSBlc3QgcGVydGluZW50ZS4KCgojIEkuIEFuYWx5c2UgZGVzIHPDqXJpZXMgQ1BJIGV0IFhSVVNEIAoqKioKT24gdXR1bGlzZXJhIGxhIGJhc2UgZGUgZG9ubsOpZSBkYXRhc2N1bGFyaWNrIHN1ciBsYXF1ZWxsZSBkaXNwb3NlIGxlcyBkb25uw6llcyAKcG91ciBub3RyZSBwYXlzLCBsZSBEYW5lbWFyay4gTm91cyBhbGxvbnMgZG9uYyDDqXR1ZGllciBsJ2luZGljZSBkZXMgcHJpeCDDoCBsYSAKY29uc29tbWF0aW9uIGV0IGxlIHRhdXggZGUgY2hhbmdlIGRlIGxhIG1vbm5haWUgbG9jYWxlIHZpcyDDoCB2aXMgZHUgZG9sbGFyIHN1ciAKdW5lIHDDqXJpb2RlIHBvc3QgMTk2MC4gIAoKClJhcHBlbG9ucyBxdeKAmWF2YW50IHRvdXRlIHLDqWdyZXNzaW9uIGxpbsOpYWlyZSBldC9vdSBhbmFseXNlIMOpY29ub23DqXRyaXF1ZSwgaWwgCmZhdXQgc+KAmWFzc3VyZXIgcXVlIGxlcyB2YXJpYWJsZXMgc29pZW50IHN0YXRpb25uYWlyZXMuIE5vdXMgYWxsb25zIGRvbmMgaWNpLCAKcGFyIHJlcHLDqXNlbnRhdGlvbiBncmFwaGlxdWUsIMOpbWV0dHJlIHVuZSBwcmVtacOocmUgaHlwb3Row6hzZSBzdXIgbGV1ciBzdGF0aW9ubmFyaXTDqSAKb3Ugbm9uLCBhdmFudCBkZSBs4oCZYWZmaXJtZXIgb3UgZGUgbOKAmWluZmlybWVyIHZpYSBkZXMgdGVzdHMgQURGLgoKCiMjIDEuIMOJdHVkZSBkZSBsYSB2YXJpYWJsZSBDUEkKCiMjIyBBLiBWaXN1YWxpc2F0aW9uIGR1IENQSQoKTm91cyBjb21tZW5jZXJvbnMgcGFyIGFuYWx5c2VyIGxhIHByZW1pZXJlIHZhcmlhYmxlOiBsZSBDUEkgCgpgYGB7cn0KcGxvdChkayR5ZWFyLCBkayRjcGksIHR5cGUgPSAibCIsCiAgbWFpbiA9ICJDUEkgRGVubWFyayIsCiAgeGxhYiA9ICJBbm7DqWUiLCB5bGFiID0gIkluZGljZSBkZSBwcml4IikKYGBgCgpUb3V0IGQnYWJvcmQsIGwnaW5kaWNlIGRlcyBwcml4IMOgIGxhIGNvbnNvbW1hdGlvbiBtb250cmUgdW5lIHRlbmRhbmNlIGhhdXNzacOocmUKdHLDqHMgbWFycXXDqSBkdXJhbnQgbGEgcMOpcmlvZGUgMTk2MC0yMDIwLiBJbCBuJ3kgYSBhdWN1biBmbHVjdHVhdGlvbiBhdXRvdXIgCmRlIGxhIG1veWVubmUsIGF1IGNvbnRyYWlyZSBsYSB0cmFqZWN0b2lyZSBlc3QgYXNjZW5kYW50ZS4gCgpSYXBwZWxvbnMgw6lnYWxlbWVudCBxdSd1bmUgc8OpcmllIERTIGVzdCBkw6lmaW5pZSBjb21tZSB1bmUgc8OpcmllIHF1aSBwcsOpc2VudGUgdW5lIApyYWNpbmUgdW5pdGFpcmUsIHVuZSBzw6lyaWUgZG9udCBsZSBuaXZlYXUgZMOpcGVuZCBmb3J0ZW1lbnQgZGUgc2VzIHZhbGV1cnMgCnBhc3PDqWVzLiBDZSB0eXBlIGRlIHPDqXJpZSBuZSByZXZpZW50IHBhcyB2ZXJzIHNhIG1veWVubmUgbWFpcyBz4oCZZW4gw6lsb2lnbmUgCmR1cmFibGVtZW50IGNlIHF1aSBjcsOpZSB1bmUgdGVuZGFuY2UgZGUgbG9uZyB0ZXJtZS4gQydlc3QgZXhhY3RlbWVudCBxdWUgbCdvbiAKcGV1dCByZW1hcnF1ZXIgcG91ciBub3RyZSB2YXJpYWJsZS4gCgpBaW5zaSBub3VzIHBvdXZvbnMgYWZmaXJtZXIgcXVlIHZpc3VlbGxlbWVudCwgbGUgQ1BJIG4nZXN0IHBhcyBzdGF0aW9ubmFpcmUgZXQgCmVzdCBwcm9iYWJsZW1lbnQgdW4gRFMuIAoKRGUgcGx1cywgdW4gcHJvY2Vzc3VzIERTIMOpdGFudCBkw6lmaW5pIHBhciBsYSBwcsOpc2VuY2UgZOKAmXVuZSByYWNpbmUgdW5pdGFpcmUsIG9uIApz4oCZYXR0ZW5kIGFsb3JzIMOgIGNlIHF1ZSBsZXMgdmFsZXVycyBwYXNzw6llcyBpbmZsdWVuY2VudCBmb3J0ZW1lbnQgbGVzIHZhbGV1cnMgCnByw6lzZW50ZXMgPSBhdXRvY29ycsOpbGF0aW9uIAoKT24gcGV1dCBsZSB2w6lyaWZpZXIgYXZlYyBsJ2F1dG9jb3Jyw6lsb2dyYW1tZTogCgpgYGB7cn0KYWNmKGRrJGNwaSkKYGBgCgpDaGFxdWUgdGlyZXQgdmVydGljYWwgcmVwcsOpc2VudGUgbCdpbmZsdWVuY2UgZCd1biBkw6lsYWkgKGxhZykgcGFydGljdWxpZXIgc3VyIApsJ8Opdm9sdXRpb24gZGUgbGEgc8OpcmllIMOgIGxhIHDDqXJpb2RlICR0JC4gTGUgcHJlbWllciB0aXJldCBwZXV0IMOqdHJlIG7DqWdsaWfDqSAKaWNpLCBjJ2VzdCBsJ2luZmx1ZW5jZSBkZSBsYSBzw6lyaWUgc3VyIGVsbGUtbcOqbWUgw6AgbGEgbcOqbWUgcMOpcmlvZGUuIAoKRW4gbCdhYnNlbmNlIGQnYXV0b2NvcnLDqWxhdGlvbiBlbiByZXZhbmNoZSwgbGUgcmVzdGUgZGVzIHRpcmV0cyBlc3QgY2Vuc8OpIMOqdHJlIApub24tc2lnbmlmaWNhdGlmIChkb25jIGxlcyB0aXJldHMgbmUgZG9pdmVudCBwYXMgZMOpcGFzc2VyIGxhIGxpZ25lIGhvcml6b250YWxlIApibGV1ZSkuIEljaSwgb24gdm9pdCBiaWVuIHF1ZSBsZXMgZMOpbGFpcyBqdXNxdSfDoCAxNSBww6lyaW9kZXMgKGRvbmMgMTUgYW5zIGF2YW50KSAKaW5mbHVlbmNlbnQgbGEgc8OpcmllIMOgIGxhIHDDqXJpb2RlICR0JC4gCkMnZXN0IHVuZSBpbmRpY2F0aW9ucyB0csOocyBmb3J0ZSBxdWUgbGEgc8OpcmllIG4nZXN0IHBhcyBzdGF0aW9ubmFpcmUuCgpWaXN1ZWxsZW1lbnQsIG9uIGNvbmNsdSBxdWUgbGEgdmFyaWFibGUgQ1BJIHNlcmFpdCBwcm9iYWJsZW1lbnQgbm9uIApzdGF0aW9ubmFpcmUsIG1haXMgcXUnZW4gZXN0IGlsIHLDqWVsbGVtZW50ID8gUG91ciBsZSB2ZXJpZmllciBmb3JtZWxsZW1lbnQsIG5vdXMgCmRldm9ucyB1dGlsaXNlciBsZXMgdGVzdHMgQURGIHF1aSBub3VzIHBlcm1ldHRyYSBkZSBzYXZvaXIgc2kgbGEgdmFyaWFibGUgZXN0IHVuIApUUyBvdSB1biBEUy4gCgoKIyMjIEIuIFRlc3RzIGRlIFN0YXRpb25uYXJpdMOpIChBREYpIHN1ciBDUEkgCgpM4oCZYW5hbHlzZSBncmFwaGlxdWUgZHUgQ1BJIHLDqXbDqGxlIHVuIHRyZW5kIGhhdXNzaWVyIGNlIHF1aSBzdWdnw6hyZSB1bmUgCm5vbi1zdGF0aW9ubmFyaXTDqSBlbiBuaXZlYXUuIE5vdXMgZGV2b25zIHRlc3RlciBsZXMgdHJvaXMgdGVzdHMgQURGCih0cmVuZCwgZHJpZnQgZXQgbm9uZSkuClBvdXIgZMOpdGVybWluZXIgbGEgbmF0dXJlIGRlIGxhIG5vbi1zdGF0aW9ubmFyaXTDqSBkdSBDUEksIG9uIGNvbW1lbmNlIHBhciB0ZXN0ZXIgCmxhIHByw6lzZW5jZSBk4oCZdW5lIHRlbmRhbmNlIGTDqXRlcm1pbmlzdGUgZW4gdXRpbGlzYW50IGxlIG1vZMOobGUgInRyZW5kIi4KCgojIyMjIyBSYXBwZWwgMTogCkgwOiBsYSBzZXJpZSBuJ2VzdCBwYXMgc3RhdGlvbm5haXJlCiAgLSBTaSB0LXN0YXQgPCB2YWxldXIgY3JpdGlxdWUg4oaSIG9uIHJlamV0dGUgSDAKICAtIFNpIHQtc3RhdCA+IHZhbGV1ciBjcml0aXF1ZSDihpIgb24gbmUgcmVqZXR0ZSBwYXMgSDAKCmBgYHtyfQpzdW1tYXJ5KHVyLmRmKGRrJGNwaSwgdHlwZSA9ICJ0cmVuZCIpKQpgYGAKCkljaSwgYXVjdW5lIHRlbmRhbmNlIG4nZXN0IGTDqXRlY3TDqWUsICJ0dCIgKDAuMjQyMykgbifDqXRhbnQgcGFzIHNpZ25pZmljYXRpdmUgCm5vdXMgcG91dm9ucyBhZmZpcm1lciBxdWUgbGUgQ1BJIG4nZXN0IHBhcyB1biB0cmVuZC4gCgpTaSBhdWN1bmUgdGVuZGFuY2Ugbidlc3QgZMOpdGVjdMOpZSwgb24gdGVzdGUgZW5zdWl0ZSBsZSBtb2TDqGxlIGF2ZWMgZHJpZnQgYWZpbiBkZSAKdGVzdGVyIHNpIHVuZSBjb25zdGFudGUgYWZmZWN0ZSBsYSBkeW5hbWlxdWUgZGUgbGEgc8OpcmllLiAKCmBgYHtyfQpzdW1tYXJ5KHVyLmRmKGRrJGNwaSwgdHlwZSA9ICJkcmlmdCIpKQpgYGAKCiMjIyMjIFJhcHBlbCAyOiAKUHIoPnx0fCkgPSBwLXZhbHVlIGR1IHQtdGVzdCAtPiBpbmRpcXVlIHNpIGxlIGNvZWZmaWNpZW50IGVzdCBzdGF0aXN0aXF1ZW1lbnQgCiAgICAgICAgICAgc2lnbmlmaWNhdGlmIChkb25jIHByw6lzZW5jZSBkZSBkcmlmdCkKei5kaWZmLmxhZyA9IHByw6lzZW5jZSBkJ2F1dG9jb3Jyw6lsYXRpb24gPz8gCnQgc3RhdCA9IMOgIGNvbXBhcmVyIGF1eCB2YWxldXJzIGNyaXRpcXVlcyBwb3VyIGNvbmNsdXJlIHN1ciBsYSBzdGF0aW9ubmFyaXTDqQoKRGFucyBjZSBtb2TDqGxlLCBsYSBzaWduaWZpY2F0aXZpdMOpIGR1IGRyaWZ0IGVzdCDDqXZhbHXDqWUgcGFyIGxhIGNvbnN0YW50ZS4gCkNlbGxlLWNpIGVzdCBzaWduaWZpY2F0aXZlIChwID0gMC4wMTg4KikgY2UgcXVpIGluZGlxdWUgcXXigJl1biBkcmlmdCBlc3QgCnByw6lzZW50LiAKQWluc2ksIGxvcnNxdWUgbGUgZHJpZnQgZXN0IGTDqXRlY3TDqSwgb24gZG9pdCBlbnN1aXRlIHbDqXJpZmllciBzaSAKbOKAmWF1dG9jb3Jyw6lsYXRpb24gZXN0IHNpZ25pZmljYXRpdmUuIFBvdXIgY2VsYSwgb24gcmVnYXJkZSBsYSB2YXJpYWJsZSAKInouZGlmZi5sYWciID0gOS4wN2UtMTMgKioqIHF1aSBlc3Qgc2lnaW5pZmljYXRpdmUuIAotPiBsYSBzw6lyaWUgZMOpcGVuZCBkZSBzZXMgcHJvcHJlcyB2YWxldXJzIHBhc3PDqWVzLiAKCkVuIHBsdXMgZCd1biB0LXN0YXQgc3VwZXJpZXVyIGF1eCB2YWxldXJzIGNyaXRpcXVlcyAob24gbmUgcmVqZXR0ZSBwYXMgSDApLCAKZGFucyBjZSBjYXMgbm91cyBwb3V2b25zIGFmZmlybWVyIHF1ZSBsZSBDUEkgZXN0IHVuIERTLgoKCgojIyAyLiDDiXR1ZGUgZGUgbGEgdmFyaWFibGUgWFJVU0QKCiMjIyBBLiBWaXN1YWxpc2F0aW9uIGRlIFhSVVNECgpWaXN1YWxpc2F0aW9uIGRlIGxhIHZhcmlhYmxlIFhSVVNEOiAKCmBgYHtyfQpwbG90KGRrJHllYXIsIGRrJHhydXNkLCB0eXBlID0gImwiLAogICAgIG1haW4gPSAiWFJVU0QiLAogICAgIHhsYWIgPSAiQW5uw6llIiwgeWxhYiA9ICJES0sgcGFyIFVTRCIpCmBgYAoKQ29uY2VybmFudCBsZSB0YXV4IGRlIGNoYW5nZSBYUlVTRCwgaWwgbid5IGEgcGFzIGRlIHRyZW5kIGTDqXRlcm1pbsOpIG1haXMgbm91cyAKcG91dm9ucyBhZmZpcm1lciBxdWUgbGEgc8OpcmllIGZsdWN0dWUgYXV0b3VyIGQndW5lIG1veWVubmUuIE9yLCBub3VzIG9ic2Vydm9ucyAKcXVlIHN1ciBjZXJ0YWluZXMgcMOpcmlvZGVzIG5vdGFtbWVudCBlbiAxOTg1IGV0IGVuIDIwMDAsIGlsIHkgYSBkZXMgCmZsdWN0dWF0aW9ucyBiZWF1Y291cCBwbHVzIGZvcnRlcyBub3VzIGxhaXNzYW50IHBlbnNlciBxdWUgbGEgdmFyaWFuY2UgcGV1dCAKY2hhbmdlciBkYW5zIGxlIHRlbXBzID0gdmFyaWFuY2Ugbidlc3QgcGFzIGNvbnRhbnRlIChtw6ptZSBzaSBsJ29uIG9ic2VydmUgdW4gCnJldG91ciDDoCBsYSAibW95ZW5uZSIgYXNzZXogdml0ZSkKCkNlIGNvbXBvcnRlbWVudCBlc3QgaW5jb21wYXRpYmxlIGF2ZWMgbGEgc3RhdGlvbm5hcml0w6ksIGNhciByYXBwZWxvbnMgbGU7IApVbmUgc8OpcmllIHN0YXRpb25uYWlyZSBlc3QgdW5lIHPDqXJpZSBkb250IGxlcyBwcm9wcmnDqXTDqXMgc3RhdGlzdGlxdWVzIOKAkyBtb3llbm5lLCAKdmFyaWFuY2UgZXQgY292YXJpYW5jZSDigJMgc29udCBjb25zdGFudGVzIGRhbnMgbGUgdGVtcHMuIEZvcm1lbGxlbWVudCwgb24gZG9pdCAKYXZvaXIgOiBcbWF0aGJie0V9KFlfdCk9XG11LCBcb3BlcmF0b3JuYW1le1Zhcn0oWV90KT1cc2lnbWFeMiwgZXQgClxvcGVyYXRvcm5hbWV7Q292fShZX3QsWV97dC1ofSk9XGdhbW1hKGgpLiAKVG91dGUgdmlvbGF0aW9uIGRlIGNlcyBjb25kaXRpb25zIGltcGxpcXVlIHVuZSBub24tc3RhdGlvbm5hcml0w6kuCgpDZXBlbmRhbnQgaWNpLCBub3VzIG1lc3VyZXJvbnMgbm9zIHByb3BvcyBlbiBhZmZpcm1hbnQgcXUnaWwgeSBhIGVmZmVjdGl2ZW1lbnQgCmRlcyBjaG9jcywgcXUnaWwgeSBhIGVmZmVjdGl2aWVtZW50IHF1ZWxxdWVzIGFtcGxpdHVkZXMgaW7DqWdhbGVzLCBwb3VyIGF1dGFudCAKbGEgc8OpcmllIHJldmllbnQgcGx1cyBvdSBtb2lucyBhdXRvdXIgZGUgc2EgbW95ZW5uZSBhcHLDqHMgY2VzIGRlcm5pZXJzIGRvbmMgbm91cyAKbmUgcG91dm9ucyBwYXMgcmVqZXRlciB2aXN1ZWxsZW1lbnQgdW5lIHN0YXRpb25uYXJpdMOpLiAKCgojIyMgQi4gVGVzdHMgZGUgU3RhdGlvbm5hcml0w6kgKEFERikgc3VyIFhSVVNEIAoKRGFucyB1biBzZWNvbmQgdGVtcHMsIGFmaW4gZGUgdsOpcmlmaWVyIGZvcm1lbGxlbWVudCBsYSBzdGF0aW9ubmFyaXTDqSBkZSBub3MgCnPDqXJpZXMsIG5vdXMgYXBwbGlxdW9ucyBsZSB0ZXN0IGRlIERpY2tleS1GdWxsZXIgYXVnbWVudMOpIChBREYpLiAKTOKAmWlkw6llIGVzdCBkZSBzYXZvaXIgc2kgbGEgc8OpcmllIGVzdCBzdGF0aW9ubmFpcmUgb3Ugbm9uLiAKCk5vdXMgY29tbWVuw6dvbnMgcGFyIGVzdGltZXIgbGUgbW9kw6hsZSBhdmVjIHRlbmRhbmNlIGTDqXRlcm1pbmlzdGUgKHR5cGUgPSAidHJlbmQiKSwgCnB1aXMsIGVuIGzigJlhYnNlbmNlIGRlIHRlbmRhbmNlIHNpZ25pZmljYXRpdmUsIG5vdXMgdGVzdG9ucyBsZSBtb2TDqGxlIGF2ZWMgY29uc3RhbnRlIAp1bmlxdWVtZW50ICh0eXBlID0gImRyaWZ0IiksIGV0IGVuZmluLCBzaSBsYSBjb25zdGFudGUgZWxsZS1tw6ptZSBu4oCZZXN0IHBhcyAKc2lnbmlmaWNhdGl2ZSwgbm91cyBlc3RpbW9ucyBsZSBtb2TDqGxlIHNhbnMgY29uc3RhbnRlICh0eXBlID0gIm5vbmUiKS4gCgpgYGB7cn0KYWNmKGRrJHhydXNkKQpgYGAKCkNvbnRyYWlyZW1lbnQgYXUgQ1BJLCBjZXR0ZSBhdXRvY29ycsOpbGF0aW9uIGTDqWNyb8OudCBwcm9ncmVzc2l2ZW1lbnQgZXQgZGlzcGFyYcOudCAKcmFwaWRlbWVudCBhcHLDqHMgbGVzIHByZW1pZXJzIGxhZ3MuIE9uIG7igJlvYnNlcnZlIHBhcyB1bmUgYXV0b2NvcnLDqWxhdGlvbiBzdXIgCnRvdXRlIGxhIHPDqXJpZS4KVmlzdWVsbGVtZW50LCBjZWxhIHN1Z2fDqHJlIHF1ZSBYUlVTRCBwb3VycmFpdCDDqnRyZSBzdGF0aW9ubmFpcmUgb3UgcHJvY2hlIGRlIAps4oCZw6p0cmUgY2FyIGxhIGTDqXBlbmRhbmNlIGV4aXN0ZSBtYWlzIHJlc3RlIG1vZMOpcsOpZSBldCBz4oCZw6l0ZWludCByYXBpZGVtZW50LiAKClBvdXIgdHJhbmNoZXIgZm9ybWVsbGVtZW50LCBpbCBlc3QgbsOpY2Vzc2FpcmUgZOKAmWF2b2lyIHJlY291cnMgYXV4IHRlc3RzIEFERiBxdWkgCnBlcm1ldHRyb250IGRlIGTDqXRlcm1pbmVyIHNpIFhSVVNEIHN1aXQgdW4gcHJvY2Vzc3VzIFRTIG91IERTLgoKTcOqbWUgY2hvc2UgcG91ciBYUlVTRCwgb24gYSB0ZXN0ZXIgbGVzIHRyb2lzIHRlc3RzIEFERiAodHJlbmQsIGRyaWZ0LCBub25lKToKCmBgYHtyfQpzdW1tYXJ5KHVyLmRmKGRrJHhydXNkLCB0eXBlPSJ0cmVuZCIpKQpgYGAKClBvdXIgInRyZW5kIiwgbGEgdGVuZGFuY2UgdHQgbuKAmWVzdCBwYXMgc2lnbmlmaWNhdGl2ZSAodC1zdGF0ID0g4oCTMS4yODYsIApwID0gMC4yMDM4KS4KT24gZW4gY29uY2x1dCBxdeKAmWlsIG7igJl5IGEgcGFzIGRlIHRyZW5kIGTDqXRlcm1pbmlzdGUgZXQgcXVlIGxlIHByb2Nlc3N1cyBu4oCZZXN0IApwYXMgdW4gVFMuCgpgYGB7cn0Kc3VtbWFyeSh1ci5kZihkayR4cnVzZCwgdHlwZT0iZHJpZnQiKSkKYGBgCgpQb3VyIGNlIHRlc3QgZGUgcmVncmVzc2lvbiBkcmlmdCwgbGEgY29uc3RhbnRlIGVzdCBzaWduaWZpY2F0aXZlIChwIDwgMC4wMSksIGNlIApxdWkgcsOpdsOobGUgbGEgcHLDqXNlbmNlIGTigJl1biBkcmlmdC4gRW4gcGx1cyBkZSDDp2EsIGlsIHkgYSBkZSBsJ2F1dG9jb3Jyw6lsYXRpb24gCnNpZ25pZmljYXRpdmUgNSUgKDAuMDAxMTAzICoqKS4gCkNlcGVuZGFudCwgbGEgcHLDqWNlbnNlIGQndW4gZHJpZnQgKyBhdXRvY29ycsOpbGF0aW9uIG4naW1wbGlxdWUgcGFzIGRpcmVjdGVtZW50IApsYSBwcsOpc2VuY2UgZCd1biBEUy4gU2kgbGUgZHJpZnQgZXN0IHNpZ25pZmljYXRpZiBhdmVjIHVuZSBhdXRvY29ycsOpbGF0aW9uIApzaWduaWZpY2F0aXZlIChjb21tZSBpY2kpIG1haXMgcXVlIHQtc3RhdCA9IOKAkzMuNzI1NCBlc3QgaW5mw6lyaWV1cmUgw6AgCmxhIHZhbGV1ciBjcml0aXF1ZSDDoCAxICUgKOKAkzMuNTEpLCBjZWxhIGNvbmR1aXQgw6AgcmVqZXRlciB0csOocyBmb3J0ZW1lbnQgCmzigJlIMC4gCgpBaW5zaSwgYmllbiBxdWUgbGUgZ3JhcGhpcXVlIGR1IHRhdXggZGUgY2hhbmdlIFhSVVNEIGxhaXNzZSBlbnRyZXZvaXIgZGVzIAp2YXJpYXRpb25zIGTigJlhbXBsaXR1ZGUgaW7DqWdhbGVzLCBYUlVTRCBlc3Qgc3RhdGlvbm5haXJlLiAKCgojIyMjIFBvdXIgcsOpc3VtZXIsIG5vdXMgYXZvbnMgZG9uYzogCioqLUNQSTogRFMqKiAKKiotWFJVU0Q6IFN0YXRpb25uYWlyZSoqIAoKQWZpbiBkJ2VmZmVjdHVlciBub3RyZSByZWdyZXNzaW9uIGxpbsOpYWlyZSwgaWwgY29udmllbnQgaWNpIGRlIHN0YXRpb25uYXJpc2VyCmxhIHZhcmlhYmxlICJDUEkiLiAKCgoKCgojIElJLiBTdGF0aW9ubmFyaXNhdGlvbiBkZXMgc8OpcmllcyBDUEkgZXQgWFJVRFMgCioqKgoKCiMjIDEuIE1pc2UgZW4gZGlmZsOpcmVuY2UKCgpEYW5zIGxlIGNhcyBkZXMgcHJvY2Vzc3VzIHN0YXRpb25uYWlyZXMgZW4gZGlmZsOpcmVuY2UgKERTKSwgaWwgc3VmZml0IGRlIHBhc3NlciAKbGEgc8OpcmllIGVuIGRpZmbDqXJlbmNlICRcRGVsdGEgWV90ID0gWV90IC0gWV97dC0xfSQgcG91ciBsYSByZW5kcmUgc3RhdGlvbm5haXJlLgoKYGBge3J9CmRrIDwtIGRrICU+JQogIG11dGF0ZShkY3BpID0gY3BpIC0gbGFnKGNwaSkpICU+JQogIG5hLm9taXQoKQoKYGBgCgoKCiMjIDIuIFbDqXJpZmljYXRpb24gZGUgbGEgU3RhdGlvbm5hcml0w6kKCkFwcsOocyBhdm9pciBpZGVudGlmacOpIHF1ZSBsZSBDUEkgZXN0IHVuIHByb2Nlc3N1cyBEUyBldCBs4oCZYXZvaXIgCiJzdGF0aW9ubmFyaXPDqSIgZW4gYXBwbGlxdWFudCB1bmUgZGlmZsOpcmVuY2UgcHJlbWnDqHJlLCBpbCBmYXV0IHbDqXJpZmllciBzaSBjZXR0ZSAKdHJhbnNmb3JtYXRpb24gYSBiaWVuIHJlbmR1IGxhIHPDqXJpZSBzdGF0aW9ubmFpcmUuIENvbW1lIGxhIHPDqXJpZSBkaWZmw6lyZW5jacOpZSAKbmUgY29udGllbnQgbmkgdGVuZGFuY2UgZMOpdGVybWluaXN0ZSBuaSBjb25zdGFudGUsIGxlIHRlc3QgQURGIGFwcHJvcHJpw6kgZXN0IGxlIAptb2TDqGxlICJub25lIiBxdWkgdGVzdGUgdW5pcXVlbWVudCBsYSBwcsOpc2VuY2UgZOKAmXVuZSByYWNpbmUgdW5pdGFpcmUgKHN0YXRpb25uYWlyZQpvdSBub24pLgoKYGBge3J9CmRrIDwtIGRrICU+JQogIG11dGF0ZShkY3BpID0gYyhOQSwgZGlmZihjcGkpKSkgJT4lCiAgbmEub21pdCgpCgpzdW1tYXJ5KHVyLmRmKGRrJGRjcGksIHR5cGUgPSAibm9uZSIpKQpgYGAKCk9uIHJlbWFycXVlIGVuY29yZSB1bmUgZm9pcyBxdWUgbGEgdC1zdGF0IGVzdCBzdXBlcmlldXIgYXV4IHZhbGV1cnMgY3JpdGlxdWVzLCAKZG9uYyBsYSBkaWZmZXJlbmNlIHByZW1pw6hyZSBuJ2EgcGFzIHN1ZmZpdCBwb3VyIHJlbmRyZSBDUEkgc3RhdGlvbm5haXJlID0gaWwgCmZhdXQgcGFzc2VyIGVuIGRpZmZlcmVuY2Ugc2Vjb25kZS4KCmBgYHtyfQpkayA8LSBkayAlPiUKICBtdXRhdGUoCiAgICBkY3BpICA9IGMoTkEsIGRpZmYoY3BpKSksICAgIAogICAgZGRjcGkgPSBjKE5BLCBkaWZmKGRjcGkpKSAgICAKICApCmBgYAoKSWwgZmF1dCBzdXBwcmltZXIgbGVzIE5BICh2YWxldXJzIG1hbnF1YW50ZXMpIGfDqW7DqXLDqWVzIHBhciBsZXMgZGlmZsOpcmVuY2VzIApzdWNjZXNzaXZlcyBwdWlzcXXigJl1bmUgcsOpZ3Jlc3Npb24gb3UgdW4gdGVzdCBBREYgbmUgcGV1dCBwYXMgw6p0cmUgZXN0aW3DqSBhdmVjIApkZXMgb2JzZXJ2YXRpb25zIG1hbnF1YW50ZXMuIApOb3VzIHV0aWxpc29ucyBkb25jIGxhIHPDqXJpZSBzYW5zIE5BIGF2ZWMgImRkY3BpX2NsZWFuIDwtIG5hLm9taXQoZGskZGRjcGkpIiAKYWZpbiBkZSB0ZXN0ZXIgY29ycmVjdGVtZW50IGxhIHN0YXRpb25uYXJpdMOpLgoKYGBge3J9CmRkY3BpX2NsZWFuIDwtIG5hLm9taXQoZGskZGRjcGkpCnN1bW1hcnkodXIuZGYoZGRjcGlfY2xlYW4sIHR5cGUgPSAibm9uZSIpKQpgYGAKCkFwcsOocyBhdm9pciDDqXRhYmxpIHF1ZSBsZSBDUEkgw6l0YWl0IG5vbi1zdGF0aW9ubmFpcmUgZW4gbml2ZWF1IGV0IGVuIHByZW1pw6hyZSAKZGlmZsOpcmVuY2UsIG5vdXMgYXZvbnMgYXBwbGlxdcOpIHVuZSBzZWNvbmRlIGRpZmbDqXJlbmNlLiAKTGUgdGVzdCBBREYg4oCcbm9uZeKAnSBzdXIgbGEgc8OpcmllIGRkQ1BJIG1vbnRyZSB1biB0LXN0YXQgZGUg4oCTNi4yMCBsYXJnZW1lbnQgCmluZsOpcmlldXIgYXV4IHZhbGV1cnMgY3JpdGlxdWVzICjigJMyLjYgYXUgc2V1aWwgZGUgMSAlKS4gCk5vdXMgcmVqZXRvbnMgZG9uYyBmb3J0ZW1lbnQgbOKAmWh5cG90aMOoc2UgbnVsbGUgZGUgcmFjaW5lIHVuaXRhaXJlLiBBaW5zaSBkZENQSSAKZXN0IHN0YXRpb25uYWlyZS4gCkVuZmluLCBub3VzIGFsbG9ucyByZXByw6lzZW50ZXIgbGUgQ1BJIGF2YW50IGV0IGFwcsOocyBsYSBkaWZmZXJlbmNlIHNlY29uZGU6CgpgYGB7cn0KCiMgR3JhcGhpcXVlIGVuIG5pdmVhdTogQ1BJIG5vbiBzdGF0aW9ubmFpcmUKZ2dwbG90KGRrLCBhZXMoeCA9IHllYXIsIHkgPSBjcGkpKSArCiAgZ2VvbV9saW5lKGx3ZCA9IDEpICsKICBsYWJzKHRpdGxlID0gIkNQSSBEZW5tYXJrIC0gTml2ZWF1IiwKICAgICAgIHggPSAiQW5uw6llIiwgeSA9ICJJbmRpY2UgZGVzIHByaXgiKSArCiAgdGhlbWVfYncoKQoKIyBHcmFwaGlxdWUgZGUgQ1BJIGFwcsOocyBsYSBkaWZmZXJlbmNlIHNlY29uZGUKZ2dwbG90KGRrLCBhZXMoeCA9IHllYXIsIHkgPSBkZGNwaSkpICsKICBnZW9tX2xpbmUoKSArCiAgbGFicyh0aXRsZSA9ICJDUEkgRGVubWFyayAtIERpZmbDqXJlbmNlIHNlY29uZGUgKM6UwrJDUEkpIiwKICAgICAgIHggPSAiQW5uw6llIiwgeSA9ICLOlMKyQ1BJIikgKwogIHRoZW1lX2J3KCkKCmBgYAoKKiotPkxlIENQSSBlc3QgZG9uYyB1biBwcm9jZXNzdXMgaW50w6lncsOpIGTigJlvcmRyZSAyLCBJKDIpLioqCgoKCgojIElJSS4gUmVsYXRpb24gZW50cmUgbGVzIGRldXggdmFyaWFibGVzIENQSSBldCBYUlVTRAoqKioKCgojIyAxLiBOdWFnZSBkZSBwb2ludHMKCgpQb3VyIGVzdGltZXIgZ3JhcGhpcXVlbWVudCBsZSBsaWVuIGVudHJlIGxlcyB2YXJpYWJsZXMsIGlsIGVzdCBuw6ljZXNzYWlyZSBkZSBsZXMgCnZpc3VhbGllciB2aWEgdW4gbnVhZ2UgZGUgcG9pbnRzLiAKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IGRrLCBhZXMoeCA9IHhydXNkLCB5ID0gZGRjcGkpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKSArCiAgbGFicygKICAgIHRpdGxlID0gImTCskNQSSBlbiBmb25jdGlvbiBkZSBYUlVTRCIsCiAgICB4ID0gIlhSVVNEIiwKICAgIHkgPSAizpTCskNQSSIKICApICsKICB0aGVtZV9idygpCmBgYAoKTGUgbnVhZ2UgZGUgcG9pbnRzIHJlcHLDqXNlbnRhbnQgbGEgcmVsYXRpb24gZW50cmUgbGUgdGF1eCBkZSBjaGFuZ2UgWFJVU0QgZXQgbGEgCmRpZmZlcmVuY2Ugc2Vjb25kZSBkdSBDUEkgKGTCskNQSSkgbmUgbGFpc3NlIGFwcGFyYcOudHJlIGF1Y3VuZSByZWxhdGlvbiBsaW7DqWFpcmUgCm5ldHRlLiBMZXMgcG9pbnRzIHNvbnQgbGFyZ2VtZW50IGRpc3BlcnPDqXMgc2FucyBzdHJ1Y3R1cmUgY2xhaXJlIGNlIHF1aSBzdWdnw6hyZSAKcXXigJlpbCBu4oCZZXhpc3RlIHBhcyBkZSBjb3Jyw6lsYXRpb24gdmlzdWVsbGUgZW50cmUgbGVzIGRldXggdmFyaWFibGVzLgpMYSBkcm9pdGUgZGUgcsOpZ3Jlc3Npb24gcHLDqXNlbnRlIHVuZSBwZW50ZSBsw6lnw6hyZW1lbnQgbsOpZ2F0aXZlIChzaSBYUlVTRCAKcydhcHByw6ljaWUgYWxvcnMgQ1BJIGRpbWludWUgbMOpZ8OocmVtZW50KQoKVW5lIHLDqWdyZXNzaW9uIGxpbsOpYWlyZSBlc3QgbsOpY2Vzc2FpcmUgcG91ciBjb25maXJtZXIgb3UgaW5maXJtZXIgbOKAmWV4aXN0ZW5jZSAKZOKAmXVuIHBhc3MtdGhyb3VnaCBzaWduaWZpY2F0aWYgZW50cmUgWFJVU0QgZXQgbOKAmWluZmxhdGlvbi4KCgoKIyMgMi4gUmVncsOpc3Npb24gbGluw6lhaXJlCgpgYGB7cn0KcmVnX2xpbiA8LSBmZW9scyhkZGNwaSB+IHhydXNkLCBkYXRhID0gZGspCmV0YWJsZShyZWdfbGluKQpgYGAKT24gdm9pdCBpY2kgcXVlIGxlIGNvZWZmaWNpZW50IGFzc29jacOpIGF1IHRhdXggZGUgY2hhbmdlIFhSVVNEIG7igJllc3QgcGFzIApzaWduaWZpY2F0aWYgw6AgNSUuIElsIG7igJlleGlzdGUgcGFzIGRlIHJlbGF0aW9uIHN0YXRpc3RpcXVlbWVudCBkw6l0ZWN0YWJsZSBlbnRyZSAKbGVzIHZhcmlhdGlvbnMgZHUgdGF1eCBkZSBjaGFuZ2UgZXQgbGVzIHZhcmlhdGlvbnMgZHUgbml2ZWF1IGRlcyBwcml4IApzdGF0aW9ubmFyaXPDqS4gCkRhbnMgY2UgY2FkcmUsIGxlIHBhc3MtdGhyb3VnaCBkdSB0YXV4IGRlIGNoYW5nZSB2ZXJzIGzigJlpbmZsYXRpb24gbuKAmWFwcGFyYcOudCAKcGFzLCBsZXMgZmx1Y3R1YXRpb25zIGR1IHRhdXggZGUgY2hhbmdlIG5lIHNlIHRyYW5zbWV0dGVudCBkb25jIHBhcyBkaXJlY3RlbWVudCAKYXV4IHByaXggw6AgbGEgY29uc29tbWF0aW9uLgoKCgoKCiMgSVYuIFbDqXJpZmljYXRpb24gZGVzIGh5cG90aMOoc2VzIGRlcyBNQ08KKioqCgoKIyMgMS4gQW5hbHlzZSBkZXMgdmFsZXVycyBhanVzdMOpZXMgZXQgZGVzIHLDqXNpZHVzCgoKTGVzIHLDqXNpZHVzIHJlcHLDqXNlbnRlbnQgbOKAmWVycmV1ciBkZSBwcsOpZGljdGlvbiBkdSBtb2TDqGxlIDogaWxzIG1lc3VyZW50IMOgIHF1ZWwKcG9pbnQgbGEgcsOpZ3Jlc3Npb24gcGFydmllbnQg4oCUIG91IMOpY2hvdWUg4oCUIMOgIHJlcHJvZHVpcmUgbGEgZHluYW1pcXVlIHLDqWVsbGUgZGUgCmxhIHZhcmlhYmxlIGV4cGxpcXXDqWUuIERhbnMgbOKAmWlkw6lhbCwgdW4gYm9uIG1vZMOobGUgTUNPIHByb2R1aXQgZGVzIHLDqXNpZHVzIArCqyBuZXV0cmVzIMK7IDogZW4gbW95ZW5uZSBwcm9jaGVzIGRlIHrDqXJvLCBzYW5zIHRlbmRhbmNlIHBhcnRpY3VsacOocmUsIGF2ZWMgdW5lIAp2YXJpYW5jZSBjb25zdGFudGUgZXQgYXVjdW5lIGTDqXBlbmRhbmNlIGRhbnMgbGUgdGVtcHMuIEF1dHJlbWVudCBkaXQsIHNpIGxlIAptb2TDqGxlIGVzdCBjb3JyZWN0ZW1lbnQgc3DDqWNpZmnDqSwgbGVzIHLDqXNpZHVzIGRvaXZlbnQgc2UgY29tcG9ydGVyIGNvbW1lIHVuIApicnVpdCBibGFuYy4KTOKAmWFuYWx5c2UgZGVzIHLDqXNpZHVzIHBlcm1ldCBkb25jIGRlIHbDqXJpZmllciBzaSBsZXMgaHlwb3Row6hzZXMgY2xhc3NpcXVlcyBkdSAKTUNPIHNvbnQgcmVzcGVjdMOpZXMsIGV0IGRvbmMgc2kgbGEgcsOpZ3Jlc3Npb24gcGV1dCDDqnRyZSBjb25zaWTDqXLDqWUgY29tbWUgZmlhYmxlIApldCBpbnRlcnByw6l0YWJsZS4KCk9uIHBldXQgaW1hZ2luZXIgcXXigJl1bmUgc8OpcmllIHRlbXBvcmVsbGUgZXN0LCDDoCBs4oCZb3JpZ2luZSwgdW5lIHNpbXBsZSBzdWl0ZSBkZQpicnVpdHMgYmxhbmNzIHBlcnR1cmLDqWUgYXUgZmlsIGR1IHRlbXBzIHBhciBkaXZlcnMgY2hvY3MgZXhvZ8OobmVzLiBMZSByw7RsZSBkZSBsYSAKcsOpZ3Jlc3Npb24gZXN0IHByw6ljaXPDqW1lbnQgZGUgcmV0aXJlciBs4oCZaW5mbHVlbmNlIGRlIGNlcyBjaG9jcyA6IHNpIGxlIG1vZMOobGUgCmVzdCBjb3JyZWN0ZW1lbnQgc3DDqWNpZmnDqSwgbGVzIHLDqXNpZHVzIGRvaXZlbnQgZG9uYyByZXRyb3V2ZXIgbGUgY29tcG9ydGVtZW50IApk4oCZdW4gYnJ1aXQgYmxhbmMgPXPDqXJpZSBzYW5zIHN0cnVjdHVyZSwgY2VudHLDqWUsIGluZMOpcGVuZGFudGUgZXQgZGUgdmFyaWFuY2UgCmNvbnN0YW50ZS4KClBvdXIgw6l2YWx1ZXIgbGEgcXVhbGl0w6kgZGUgbm90cmUgbW9kw6hsZSwgbm91cyBjb21wYXJvbnMgbGVzIHZhbGV1cnMgb2JzZXJ2w6llcyAKZGUgzpTCskNQSSBhdXggdmFsZXVycyBhanVzdMOpZXMgcGFyIGxhIHLDqWdyZXNzaW9uIGFmaW4gZGUgdmlzdWFsaXNlciBsYSBjYXBhY2l0w6kgCmV4cGxpY2F0aXZlIHLDqWVsbGUgZHUgbW9kw6hsZQoKYGBge3J9CmZpdHRlZF92YWwgPC0gcmVnX2xpbiRmaXR0ZWQudmFsdWVzCnJlc2lkdWFscyA8LSByZWdfbGluJHJlc2lkdWFscwoKZGtfY2xlYW4gPC0gZGsgJT4lCiAgZHBseXI6OnNlbGVjdCh5ZWFyLCB4cnVzZCwgZGRjcGkpICU+JQogIG5hLm9taXQoKQoKZGsyIDwtIGRrX2NsZWFuICU+JQogIGNiaW5kKGZpdHRlZF92YWwpICU+JQogIGNiaW5kKHJlc2lkdWFscykKCmdncGxvdChkazIsIGFlcyh4ID0geWVhciwgeSA9IGRkY3BpKSkgKwogIGdlb21fbGluZShsd2QgPSAxKSArCiAgZ2VvbV9saW5lKGFlcyh5ID0gZml0dGVkX3ZhbCksIGNvbG9yID0gInJlZCIsIGx0eSA9IDIsIGx3ZCA9IDEpICsKICBsYWJzKAogICAgdGl0bGUgPSAiVmFsZXVycyBvYnNlcnbDqWVzIHZzIHZhbGV1cnMgYWp1c3TDqWVzIiwKICAgIHggPSAiQW5uw6llIiwKICAgIHkgPSAizpTCskNQSSIKICApICsKICB0aGVtZV9idygpCmBgYAoKTGUgZ3JhcGhpcXVlIG1vbnRyZSBxdWUgbGVzIHZhbGV1cnMgYWp1c3TDqWVzIHBhciBsZSBtb2TDqGxlIHJlc3RlbnQgcHJlc3F1ZSAKY29uc3RhbnRlcyB0YW5kaXMgcXVlIGxlcyB2YWxldXJzIG9ic2VydsOpZXMgZGUgzpTCskNQSSBmbHVjdHVlbnQgZm9ydGVtZW50LgotPmxlIG1vZMOobGUgZXhwbGlxdWUgdHLDqHMgcGV1IGxhIGR5bmFtaXF1ZSByw6llbGxlIGRlIGxhIHPDqXJpZS4gCgpOb3VzIGRldm9ucyBtYWludGVuYW50IHbDqXJpZmllciBzaSBsZXMgaHlwb3Row6hzZXMgY2xhc3NpcXVlcyBkdSBtb2TDqGxlIGRlcyBNQ08gCnNvbnQgcmVzcGVjdMOpZXMgYWZpbiBkZSBnYXJhbnRpciBsYSB2YWxpZGl0w6kgc3RhdGlzdGlxdWUgZGUgbm90cmUgZXN0aW1hdGlvbi4KCgoKIyMgMi4gVGVzdHMgZGUgZGlhZ25vc3RpYyBkZXMgcsOpc2lkdXMKCgpgYGB7cn0KZGtfY2xlYW4gPC0gZGsgJT4lCiAgZHBseXI6OnNlbGVjdCh5ZWFyLCB4cnVzZCwgZGRjcGkpICU+JQogIG5hLm9taXQoKQoKZGsyIDwtIGRrX2NsZWFuICU+JQogIG11dGF0ZSgKICAgIHJlc2lkdWFscyAgICAgPSByZWdfbGluJHJlc2lkdWFscywKICAgIGZpdHRlZF92YWx1ZXMgPSByZWdfbGluJGZpdHRlZC52YWx1ZXMKICApCgpoZWFkKGRrMikKYGBgCgpKdXN0ZSBhdmFudCBkZSByw6lhbGlzZXIgdW4gdGVzdCBmb3JtZWwsIG5vdXMgY29tbWVuw6dvbnMgcGFyIGV4YW1pbmVyIApncmFwaGlxdWVtZW50IGxlcyByw6lzaWR1cyBhdSBjb3VycyBkdSB0ZW1wcyBhZmluIGTigJnDqXZhbHVlciB2aXN1ZWxsZW1lbnQgc2kgbGV1ciAKdmFyaWFuY2UgZXN0IGNvbnN0YW50ZS4gCi1VbmUgdmFyaWFuY2Ugc3RhYmxlIGluZGlxdWVyYWl0IHVuZSBob21vc2PDqWRhc3RpY2l0w6kKLWRlcyB2YXJpYXRpb25zIG1hcnF1w6llcyBkZSBs4oCZYW1wbGl0dWRlIGRlcyByw6lzaWR1cyBzdWdnw6lyZXJhaWVudCB1bmUgCiBow6l0w6lyb3Njw6lkYXN0aWNpdMOpIHBvdGVudGllbGxlLgoKYGBge3J9CmdncGxvdChkazIsIGFlcyh4ID0geWVhciwgeSA9IHJlc2lkdWFscykpICsKICBnZW9tX2xpbmUobHdkID0gMSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGx0eSA9IDIpICsKICBsYWJzKHRpdGxlID0gIlLDqXNpZHVzIGRlIGxhIHLDqWdyZXNzaW9uIGRhbnMgbGUgdGVtcHMiLAogICAgICAgeCA9ICJBbm7DqWUiLCB5ID0gIlLDqXNpZHVzIikgKwogIHRoZW1lX2J3KCkKYGBgCgpPbiBwZXV0IHZvaXIgcXVlIGxhIHZhcmlhbmNlIGRlcyByw6lzaWR1ZXMgbW9kw6lyw6llIGRhbnMgbGVzIGFubsOpZXMgMTk3MOKAkzE5ODAsIAptYWlzIMOgIHBhcnRpciBkdSBkw6lidXQgZGVzIGFubsOpZXMgMjAwOC0yMDEwLCBs4oCZYW1wbGl0dWRlIGRlcyByw6lzaWR1cyBhdWdtZW50ZSAKZm9ydGVtZW50cy4gQ2V0dGUgw6l2b2x1dGlvbiBhbcOobmUgw6AgcGVuc2VyIHF1ZSBsZXMgcsOpc2lkdXMgcG91cnJhaWVudCDDqnRyZSAKaMOpdMOpcm9zY8OpZGFzdGlxdWVzLiAKCkNlcGVuZGFudCwgbOKAmWFuYWx5c2UgdmlzdWVsbGUgbuKAmWVzdCBwYXMgdW4gdGVzdCBmb3JtZWwuIFBvdXIgdsOpcmlmaWVyIAps4oCZaG9tb3Njw6lkYXN0aWNpdMOpIG91IG5vbiBkZXMgcsOpc2lkdXMsIG9uIHV0aWxpc2UgZG9uYyBsZSB0ZXN0IGRlIEJyZXVzY2gtUGFnYW4uCgoKIyMjIDEuIEjDqXTDqXJvc2PDqWRhc3RpY2l0w6k6IEJyZXVzY2gtUGFnYW4KCmBgYHtyfQpicHRlc3QoZGRjcGkgfiB4cnVzZCwgZGF0YSA9IGRrKQpgYGAKRGFucyBub3RyZSBjYXMsIGxlIHRlc3QgQlAgZG9ubmUgdW5lIHN0YXRpc3RpcXVlIGRlIDQuOTM0MyBwb3VyIDEgZGVncsOpIGRlIApsaWJlcnTDqSBhdmVjIHVuZSBwLXZhbHVlID0gMC4wMjYzMy4gQ29tbWUgbGEgcC12YWx1ZSBlc3Qgc2lnbmlmaWNhdGl2ZSDDoCA1JSwgb24gCnJlamV0dGUgbOKAmWh5cG90aMOoc2UgbnVsbGUgZOKAmWhvbW9zY8OpZGFzdGljaXTDqSBldCBvbiBjb25jbHV0IHF1ZSBsZXMgcsOpc2lkdXMgc29udCAKaMOpdMOpcm9zY8OpZGFzdGlxdWVzLgoKCiMjIyAyLiBOb3JtYWxpdMOpOiBTaGFwaXJvLVdpbGsKCmBgYHtyfQpnZ3Bsb3QoZGsyLCBhZXMocmVzaWR1YWxzKSkgKwogIGdlb21fZGVuc2l0eShmaWxsPSJncmV5NjAiLCBib3VuZHM9YygtSW5mLCBJbmYpKSArCiAgdGhlbWVfYncoKQpgYGAKCkxlcyByw6lzaWR1cyBzb250IGJpZW4gZGlzdHJpYnXDqXMgYXV0b3VyIGRlIHrDqXJvIGV0IGxhIG1veWVubmUgZXN0IHJlbGF0aXZlbWVudCAKcHJvY2hlIGRlIHrDqXJvLgpMYSBkaXN0cmlidXRpb24gbuKAmWVzdCBxdeKAmXVuZSB2w6lyaWZpY2F0aW9uIHZpc3VlbGxlLCBwYXMgdW4gdGVzdCBzdGF0aXN0aXF1ZS4KUG91ciB1biB0ZXN0IGZvcm1lbCwgaWwgZmF1dCBzZSB0b3VybmVyIHZlcnMgbGUgdGVzdCBkZSBTaGFwaXJvIHF1aSB0ZXN0ZSBsYSAKbm9ybWFsaXTDqSBk4oCZdW5lIHPDqXJpZS4KCkxlIHRlc3QgZGUgU2hhcGlybyBhIHBvdXIgaHlwb3Row6hzZSBudWxsZSBsYSBub3JtYWxpdMOpIGRlcyByw6lzaWR1cy4KU2kgbGEgcC12YWx1ZSBlc3Qgc2lnbmlmaWNhdGl2ZSwgb24gcmVqZXR0ZSBkb25jIGzigJloeXBvdGjDqHNlIG51bGxlLCBldCBvbiAKY29uY2x1dCBkZSBsYSBub24tbm9ybWFsaXTDqSBkZSBsYSBzw6lyaWUuCgpgYGB7cn0Kc2hhcGlyby50ZXN0KGRrMiRyZXNpZHVhbHMpCmBgYApMYSBwLXZhbHVlIGVzdCBzaWduaWZpY2F0aXZlLCBkb25jIGxlcyByw6lzaWR1cyBuZSBzdWl2ZW50IHBhcyB1bmUgbG9pIG5vcm1hbGUgCnNlbG9uIGxlIHRlc3QgZGUgU2hhcGlyby4gQ2VsYSBzaWduaWZpZSBxdWUgbGVzIGVycmV1cnMgZHUgbW9kw6hsZSBuZSBzb250IHBhcyAKZGlzdHJpYnXDqWVzIGRlIGZhw6dvbiBzeW3DqXRyaXF1ZSBhdXRvdXIgZGUgesOpcm8uCgoKIyMjIDMuIEluZMOpcGVuZGFuY2U6IExqdW5nLUJveAoKROKAmWFwcsOocyBs4oCZaHlwb3Row6hzZSBk4oCZaW5kw6lwZW5kYW5jZSBkZXMgcsOpc2lkdXMsIGxlcyByw6lzaWR1cyBk4oCZdW5lIHDDqXJpb2RlIG5lIApkb2l2ZW50IHBhcyDDqnRyZSBleHBsaXF1w6lzIHBhciBsZXMgcsOpc2lkdXMgcHLDqWPDqWRlbnRzLgpPbiBwZXV0IHRlc3RlciBjZXR0ZSBoeXBvdGjDqHNlIGF2ZWMgdW4gc2ltcGxlIGF1dG9jb3Jyw6lsb2dyYW1tZToKCmBgYHtyfQphY2YoZGsyJHJlc2lkdWFscykKYGBgCgpJY2ksIG9uIG9ic2VydmUgdW4gcGljIHNpZ25pZmljYXRpZiBhdSBsYWcgMS4gTGVzIGF1dHJlcyBsYWdzIG5lIHNvbnQgcGFzIApzaWduaWZpY2F0aWZzLiAKQXByw6hzIGzigJlhbmFseXNlIHZpc3VlbGxlLCBpbCBjb252aWVudCBk4oCZdXRpbGlzZXIgbGUgdGVzdCBmb3JtZWwuCgpMZSB0ZXN0IExqdW5nLUJveCBlZmZlY3R1ZSBsZSB0ZXN0IGTigJlpbmTDqXBlbmRhbmNlIGRlcyByw6lzaWR1cywgZXQgYSBwb3VyIApoeXBvdGjDqHNlIG51bGxlIGzigJlpbmTDqXBlbmRhbmNlIGRlcyByw6lzaWR1cy4KU2kgbGEgcC12YWx1ZSBlc3Qgc2lnbmlmaWNhdGl2ZSwgb24gcmVqZXR0ZSBs4oCZaHlwb3Row6hzZSBudWxsZSBldCBvbiBjb25jbHV0IGRlIAps4oCZYXV0b2NvcnLDqWxhdGlvbiAoZG9uYyBs4oCZYWJzZW5jZSBk4oCZaW5kw6lwZW5kYW5jZSkgZGVzIHLDqXNpZHVzLgoKYGBge3J9CkJveC50ZXN0KGRrMiRyZXNpZHVhbHMsIGxhZyA9IDEwLCB0eXBlID0gIkxqdW5nLUJveCIpCmBgYApMYSBwLXZhbHVlIGR1IHRlc3QgZGUgTGp1bmctQm94IG7igJllc3QgcGFzIHNpZ25pZmljYXRpdmUuIE9uIG5lIHJlamV0dGUgZG9uYyBwYXMgCmzigJloeXBvdGjDqHNlIG51bGxlIGTigJlpbmTDqXBlbmRhbmNlIGRlcyByw6lzaWR1cy4gCkNlIHRlc3QgY29uZmlybWUgY2UgcXVlIG5vdXMgYXZvbnMgdnU7IGxlcyByw6lzaWR1cyBhcHBhcmFpc3NlbnQgaW5kw6lwZW5kYW50cyBldCAKaWwgbuKAmXkgYSBwYXMgZOKAmWF1dG9jb3Jyw6lsYXRpb24gZW50cmUgZXV4LiAKCkNvbmNlcm5hbnQgbGVzIE1DTywgcGx1c2lldXJzIGh5cG90aMOoc2VzIHNvbnQgdmlvbMOpZXM6Ci1sZXMgcsOpc2lkdXMgc29udCBow6l0w6lyb3Njw6lkYXN0aXF1ZXMgCi1pbHMgbmUgc3VpdmVudCBwYXMgdW5lIGxvaSBub3JtYWxlIAotbWFpcyBpbHMgYXBwYXJhaXNzZW50IGluZMOpcGVuZGFudHMgCgoKCgoKIyBWLiBDb25jbHVzaW9uCioqKgpEYW5zIGzigJllbnNlbWJsZSwgbm90cmUgbW9kw6hsZSBlc3QgcGV1IHBlcmZvcm1hbnQgZGFucyBs4oCZZXhwbGljYXRpb24gZGUgbGEgCmR5bmFtaXF1ZSBkZSBs4oCZaW5mbGF0aW9uIGF1IERhbmVtYXJrLgpMZSBjb2VmZmljaWVudCBkdSB0YXV4IGRlIGNoYW5nZSAozrIpIG7igJllc3QgcGFzIHNpZ25pZmljYXRpZiBkb25jIGxlcyB2YXJpYXRpb25zIApkdSB0YXV4IGRlIGNoYW5nZSBu4oCZZXhwbGlxdWVudCBwYXMgbGVzIHZhcmlhdGlvbnMgZGUgzpTCskNQSS4KUG91ciByw6lwb25kcmUgw6Agbm90cmUgcXVlc3Rpb24sIG9uIG5lIGTDqXRlY3RlIGF1Y3VuIHBhc3MtdGhyb3VnaCBkYW5zIG5vdHJlIAptb2TDqGxlOiBsZXMgdmFyaWF0aW9ucyBkdSB0YXV4IGRlIGNoYW5nZSBu4oCZb250IGF1Y3VuIGltcGFjdCBzaWduaWZpY2F0aWYgc3VyIGxlCkNQSSAKIyMjPSAqKmxlIHBhc3MtdGhyb3VnaCBlc3QgbnVsLioqCgoKRW5maW4sIHBvdXIgY2zDtHJlIGNldHRlIHByZW1pw6hyZSBwYXJ0aWUsIG5vdXMgY29tcGFyZXJvbnMgbm90cmUgw6l0dWRlIMOgIGNlbGxlIGRlIApsYSBCSVMuCkRhbnMgbm90cmUgw6l0dWRlIG5vdXMgdXRpbGlzb25zIHVuZSByw6lncmVzc2lvbiBsaW7DqWFpcmUgc2ltcGxlIGVuIHPDqXJpZXMgdGVtcG9yZWxsZXMKKHBsdXNpZXVycyAidCIgcG91ciB1biBzZXVsIGluZGl2aWR1LCBpY2kgbGUgRGFuZW1hcmspLCBvw7kgbOKAmWluZmxhdGlvbiBzdGF0aW9ubmFyaXPDqWUKKM6UwrJDUEkpIGVzdCBleHBsaXF1w6llIHBhciBsZSB0YXV4IGRlIGNoYW5nZSBYUlVTRC4gSWwgc+KAmWFnaXQgZG9uYyBk4oCZdW4gbW9kw6hsZSAKdW5pdmFyacOpIHF1aSAgdGllbnQgY29tcHRlIGTigJl1bmUgc2V1bGUgcmVsYXRpb24gZGlyZWN0ZS4KRGFucyBs4oCZw6l0dWRlIGRlIGxhIEJJUywgbGVzIGF1dGV1cnMgdXRpbGlzZW50IGRlcyBtb2TDqGxlcyBtdWx0aXZhcmnDqXMgZXN0aW3DqXMgZW4gCnBhbmVsLiBMZXVyIGFwcHJvY2hlIHBlcm1ldCBkb25jIGRlIG1pZXV4IGV4cGxpcXVlciBsZSAicGFzcy10aHJvdWdoIiwgYXZlYyB1bmUgCnJpY2hlc3NlIGRlIGRvbm7DqWVzIGJlYXVjb3VwIHBsdXMgaW1wb3J0YW50ZS4gCgpQb3VyIHJhcHByb2NoZXIgbm90cmUgw6l0dWRlIGRlIGxhIGxldXIsIGlsIGZhdWRyYWl0IGF2YW50IHRvdXQgdHJhdmFpbGxlciBhdmVjIApkZXMgZG9ubsOpZXMgcGx1cyBmcsOpcXVlbnRlcyBjZSBxdWkgcGVybWV0dHJhaXQgZm9ydGVtZW50IGQnZW5yaWNoaXIgbm90cmUgYW5hbHlzZSAKZHUgcGFzcy10aHJvdWdoLgoKCgoKCgoKCioqKgoqKioKIyBQQVJUSUUgMjogUFLDiVZJU0lPTlMgRFUgUElCCioqKgoKUG91ciBjb250aW51ZXIgbWFpbnRlbmFudCwgbm91cyBkZXZvbnMgcHLDqXZvaXIgbGEgY3JvaXNzYW5jZSBmdXR1cmUgZGUgbm90cmUgcGF5cyAKZOKAmWludMOpcsOqdCBzdXIgbGVzIDUgcHJvY2hhaW5lcyBhbm7DqWVzLiAKUG91ciBjZWxhLCB2b3VzIHZvdXMgc2VydmlyZXogZGVzIG1vZMOobGVzIEFSTUEgYWZpbiBkZSBmYWlyZSBkZXMgcHLDqXZpc2lvbnMuIFZvdXMgCmNob2lzaXJleiBsZSBtb2TDqGxlIG9wdGltYWwgZXQgZWZmZWN0dWVyZXogdW5lIHByw6l2aXNpb24gdW5pcXVlIGRlIGxhIGNyb2lzc2FuY2UgCmR1IFBJQi4gVm91cyBjb21tZW50ZXJleiBlbnN1aXRlIGxlcyByw6lzdWx0YXRzIG9idGVudXMsIGV0IGNvbnNlaWxsZXJleiBsZSAKcmVzcG9uc2FibGUgcG9saXRpcXVlIHN1ciBsYSBwb2xpdGlxdWUgYXBwcm9wcmnDqWUuIENvbW1lbnRleiDDqWdhbGVtZW50IGxlcyAKbGltaXRlcyBsacOpZXMgw6Agdm90cmUgcHLDqXZpc2lvbi4KCgoKYGBge3J9CmRvbm5lZXNfZGsgPC0gZGF0YV9zY2h1bGFyaWNrICU+JQogIGZpbHRlcihjb3VudHJ5PT0iRGVubWFyayIpJT4lCiAgc2VsZWN0KHllYXIsIGdkcCklPiUKICBtdXRhdGUoZ2RwX2dyb3d0aCA9IChsb2coZ2RwKSAtIGxhZyhsb2coZ2RwKSkpKjEwMCAgICklPiUKICBuYS5vbWl0KCklPiUKICBmaWx0ZXIoeWVhciA+PSAxOTUwICYgeWVhciA8IDIwMjApCmhlYWQoZG9ubmVlc19kaykKYGBgCgpPbiBjb21tZW5jZSDDoCBwYXJ0aXIgZGUgMTk1MCBjYXIgYXZhbnQgYyfDqXRhaXQgbGEgU2Vjb25kZSBHdWVycmUgTW9uZGlhbGUsIGV0IG9uIAphIHJldGlyw6kgMjAyMCBjYXIgYydlc3QgdW5lIGFubsOpZSBleGNlcHRpb25uZWxsZSwgYXZlYyB1biBjaG9jIHB1cmVtZW50IGV4b2fDqG5lIAooZG9uYyBpbXBvc3NpYmxlIGRlIGxlIHJlbGllciDDoCBkZXMgdmFyaWF0aW9ucyBwYXNzw6llcyBkdSBQSUIpLgoKYGBge3J9CmRvbm5lZXNfZGsgJT4lCiAgZ2dwbG90KGFlcyh4PXllYXIsIHk9Z2RwX2dyb3d0aCkpKwogIGdlb21fbGluZSgpCmBgYAoKTm91cyByZW1hcnF1b25zIHF1J8OgIHBhcnRpciBkZXMgYW5uw6llcyA2MCBqdXNxdSdlbiAxOTg1IGVudmlyb24sIGxlIFBJQiBkdSAKRGFuZW1hayBlc3QgYSBzb24gYXBvZ8OpIGF2ZWMgdW5lIGNyb2lzc2FuY2UgbW95ZW5uZSBwYXIgYW4gZCdlbnZpcmlvbiAxMCUuIApDZXBlbmRhbnQgYXByw6hzIDE5ODUsIGlsIHkgYSB1bmUgY2h1dGUgZHJhc3RpcXVlIGR1IFBJQiBjaHV0YW50IMOgIGVudmlyb24gMi41JS4gCk5vdXMgb2JzZXJ2b25zIHVuIHBpYyBkdSBQSUIgcXVpIGVzdCBiYWlzc2llciBqdXN0ZSBhdmFudCBsZXMgYW5uw6llcyAyMDEwIHF1aSAKZXN0IGTDuyDDoCBsYSBjcmlzZSBkZXMgc3VicHJpbWVzLiAKCgpgYGB7cn0KZGYgPC0gZG9ubmVlc19kayAlPiUgYXJyYW5nZSh5ZWFyKQoKeV90cyA8LSB0cygKICBkZiRnZHBfZ3Jvd3RoLAogIHN0YXJ0ICAgICA9IG1pbihkZiR5ZWFyKSwKICBmcmVxdWVuY3kgPSAxICAgICAgICAKKQpgYGAKCmljaSwgb24gbWV0IGxlcyBkb25uw6llcyBlbiBvcmRyZSBjaHJvbm9sb2dpcXVlIHB1aXMgb24gY29udmVydGl0IG5vdHJlIHZhcmlhYmxlIApkdSBQSUIgZW4gdW5lIHNlcmllIHRlbXBvcmVsbGUgYW5udWVsbGUgYWZpbiBkZSBwb3V2b2lyIGFwcGxpcXVlciBsZSBtb2TDqGxlIAp0ZW1wb3JlbCBBUklNQS4KCmBgYHtyfQpyZXF1aXJlKGZvcmVjYXN0KQpmaXRfYXJpbWEgPC0gYXV0by5hcmltYSh5X3RzKQpmaXRfYXJpbWEKYGBgCgpPbiBlc3RpbWUgZW5zdWl0ZSBsZSBtb2TDqGxlIEFSSU1BLiBMYSBzw6lsZWN0aW9uIGF1dG9tYXRpcXVlIGR1IG1vZMOobGUgbm91cyBkb25uZSAKbGUgbW9kw6hsZSBBUklNQSgwLDEsMSkgLT4gTUEoMSkgY29tbWUgY2VsdWkgbWluaW1pc2FudCBsZSBjcml0w6hyZSBBSUMuCkNlIG1vZMOobGUgZXN0IGRvbmMgY29uc2lkw6lyw6kgY29tbWUgbGUgcGx1cyBhZGFwdMOpIHBvdXIgY2FwdHVyZXIgbGEgZHluYW1pcXVlIGR1IApQSUIgZGFub2lzLgoKT24gcGV1dCBkb25jIHJlZ2FyZGVyIGxhIGR5bmFtaXF1ZSBkZXMgcsOpc2lkdXMgZHUgbW9kw6hsZSBNQSgxKSBxdWkgY29ycmVzcG9uZGVudCAKw6AgbGEgY29tcG9zYW50ZSBkdSBQSUIgbm9uIGV4cGxpcXXDqWUgcGFyIGxlIG1vZMOobGUgZXQgbGVzIGNvbXBhcmVyIGF1eCB2YWxldXJzIApvYnNlcnbDqWVzIHBvdXIgw6l2YWx1ZXIgbGEgcXVhbGl0w6kgZGUgbOKAmWFqdXN0ZW1lbnQuIAoKSnVzdGUgYXZhbnQsIGlsIGZhdXQgZXh0cmFpcmUgbGVzIHZhbGV1cnMgYWp1c3TDqWVzIChmaXR0ZWQgdmFsdWVzKSBkdSBtb2TDqGxlIEFSSU1BCmNvcnJlc3BvbmRhbnQgYXV4IHZhbGV1cnMgcXVlIGxlIG1vZMOobGUgQVJJTUEgYXVyYWl0IHByw6lkaXRlcyBwb3VyIGNoYXF1ZSBhbm7DqWUgCmRlIGxhIHDDqXJpb2RlIGTigJllc3RpbWF0aW9uLiBDZWxhIHBlcm1ldCBkZSBjb21wYXJlciBjZSBxdWUgbGUgbW9kw6hsZSBwcsOpdm9pdCBjb250cmUKY2UgcXVpIHMnZXN0IHLDqWVsbGVtZW50IHBhc3PDqS4gCgpgYGB7cn0KCmZpdHRlZF9hcmltYSA8LSBmaXR0ZWQoZml0X2FyaW1hKQpgYGAKCk5vdXMgY29uc3RydWlzb25zIGVuc3VpdGUgdW4gdGFibGVhdSBjb21wcmVuYW50IGxlcyB2YWxldXJzIG9ic2VydsOpZXMgZHUgUElCIGV0IApsZXMgdmFsZXVycyBhanVzdMOpZXMgcGFyIEFSSU1BIGFmaW4gZGUgY29tcGFyZXIgbGEgcXVhbGl0w6kgZOKAmWFqdXN0ZW1lbnQgZHUgbW9kw6hsZSAKc3VyIGzigJnDqWNoYW50aWxsb246CgpgYGB7cn0KZGZfaW5fc2FtcGxlIDwtIGRhdGEuZnJhbWUoCiAgeWVhciAgICAgICAgID0gYXMubnVtZXJpYyh0aW1lKHlfdHMpKSwKICBnZHBfZ3Jvd3RoICAgPSBhcy5udW1lcmljKHlfdHMpLAogIGFyaW1hX2ZpdHRlZCA9IGFzLm51bWVyaWMoZml0dGVkX2FyaW1hKQopCmhlYWQoZGZfaW5fc2FtcGxlKQpgYGAKCkFpbnNpIG5vdXMgb2J0ZW5vbnM6IAoKYGBge3J9CmdncGxvdChkZl9pbl9zYW1wbGUsIGFlcyh4ID0geWVhcikpICsKICBnZW9tX2xpbmUoYWVzKHkgPSBnZHBfZ3Jvd3RoKSwgbGluZXR5cGUgPSAic29saWQiKSArCiAgZ2VvbV9saW5lKGFlcyh5ID0gYXJpbWFfZml0dGVkKSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3I9InJlZCIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiSW4tc2FtcGxlOiBhY3R1YWwgdnMgQVJJTUEgZml0dGVkIiwKICAgIHkgPSAiVmFsdWUiCiAgKQpgYGAKCkxlIGdyYXBoaXF1ZSBjb21wYXJlIGxlcyB2YWxldXJzIG9ic2VydsOpZXMgZHUgUElCICh0cmFpdCBub2lyKSBhdXggdmFsZXVycyBhanVzdMOpZXMgCnBhciBsZSBtb2TDqGxlIEFSSU1BICh0cmFpdCByb3VnZSkuCk9uIHZvaXQgcXVlIGxlIG1vZMOobGUgY2FwdHVyZSBsYSB0ZW5kYW5jZSBjZW50cmFsZSBkZSBsJ8Opdm9sdXRpb24gZ8OpbsOpcmFsZSBkdSBQSUIsIAptYWlzIHJlc3RlIHRvdXQgZGUgbcOqbWUgbMOpZ8OocmVtZW50IMOpbG9pZ27DqSBkZXMgZmx1Y3R1YXRpb25zIHLDqWVsbGVzLiBFbiBlZmZldCwgCmxlcyB2YWxldXJzIGFqdXN0w6llcyBhcHBhcmFpc3NlbnQgcGx1cyAibGlzc2VzIiBldCBtb2lucyB2b2xhdGlsZXMgcXVlIGxlcyAKb2JzZXJ2YXRpb25zLCBleGVtcGxlIGF2ZWMgbGUgcGljIGJhaXNzaWVyIGNhdXPDqSBwYXIgbGEgR0NGLiAKCk9uIHZhLCBhZmluIGRlIHLDqWFsaXNlciBub3MgcHLDqXZpc2lvbnMsIMOpdGFibGlyIGxhIHRhaWxsZSBkZSBub3RyZSDDqWNoYW50aWxsb24gCnN1ciBsZXF1ZWwgb24gYXBwbGlxdWVyYSBsZSBtb2TDqGxlIGRlIHByw6l2aXNpb24gQVJJTUEuIEljaSwgbGEgdGFpbGxlIGRlCmwnw6ljaGFudGlsbG9uIGVzdCBkZSAxNSBhbnMuIAoKCmBgYHtyfQpuIDwtIGxlbmd0aCh5X3RzKQpoIDwtIDE1ICAjIHR1IGZpeGVzIGljaQpgYGAKCkljaSwgb24gdmEgdmVuaXIgZGl2aXNlciBsYSBwYXJ0aWUgZW4gZGV1eDogInRyYWluIiBzZXJ0IMOgIGVzdGltZXIgbGUgbW9kw6hsZSBBUklNQSwgCmV0ICJ0ZXN0IiBzZXJ0IMOgIHbDqXJpZmllciBsYSBxdWFsaXTDqSBkZXMgcHLDqXZpc2lvbnMgaG9ycy3DqWNoYW50aWxsb24uCgoKYGBge3J9CnlfdHJhaW4gPC0gd2luZG93KHlfdHMsIGVuZCA9IHRpbWUoeV90cylbbiAtIGhdKQp5X3Rlc3QgIDwtIHdpbmRvdyh5X3RzLCBzdGFydCA9IHRpbWUoeV90cylbbiAtIGggKyAxXSkKYGBgCgpPbiBlc3RpbWUgZW5zdWl0ZSB1biBtb2TDqGxlIEFSSU1BIHNldWxlbWVudCBzdXIgbGEgcGFydGllIHRyYWluLCBwdWlzIG9uIGfDqW7DqHJlIApkZXMgcHLDqXZpc2lvbnMgc3VyIGxlcyAxNSBhbm7DqWVzIGR1IHRlc3QgYWNjb21wYWduw6llcyBkZXMgaW50ZXJ2YWxsZXMgZGUgY29uZmlhbmNlIArDoCA4MCAlIGV0IDk1ICUuCkVuZmluLCBvbiBjb25zdHJ1aXQgdW4gdGFibGVhdSBjb21wYXJhbnQgbGVzIHZhbGV1cnMgcsOpZWxsZXMgZHUgUElCIGF2ZWMgbGVzIHByw6l2aXNpb25zIApBUklNQSBldCBsZXVycyBpbnRlcnZhbGxlcyBjZSBxdWkgcGVybWV0IGRlIHZpc3VhbGlzZXIgZXQgZOKAmcOpdmFsdWVyIGxhIHBlcmZvcm1hbmNlIApwcsOpZGljdGl2ZSBkdSBtb2TDqGxlLgoKYGBge3J9CmZpdF9hcmltYV9vb3MgPC0gYXV0by5hcmltYSh5X3RyYWluKQpmY19hcmltYV9vb3MgIDwtIGZvcmVjYXN0KGZpdF9hcmltYV9vb3MsIGggPSBoLCBsZXZlbCA9IGMoODAsIDk1KSkKCnllYXJzX3Rlc3QgPC0gYXMubnVtZXJpYyh0aW1lKHlfdGVzdCkpCgphcmltYV9pbnNhbXBsZSA8LSBkYXRhLmZyYW1lKAogIHllYXIgICAgICAgICAgID0geWVhcnNfdGVzdCwKICBnZHBfZ3Jvd3RoICAgICA9IGFzLm51bWVyaWMoeV90ZXN0KSwKICBhcmltYV9mb3JlY2FzdCA9IGFzLm51bWVyaWMoZmNfYXJpbWFfb29zJG1lYW4pLAogIGFyaW1hX2xvd2VyXzk1ID0gZmNfYXJpbWFfb29zJGxvd2VyWywgIjk1JSJdLAogIGFyaW1hX3VwcGVyXzk1ID0gZmNfYXJpbWFfb29zJHVwcGVyWywgIjk1JSJdCikKYXJpbWFfaW5zYW1wbGUKCmBgYAoKUmVwcsOpc2VudGF0aW9uIGdyYXBoaXF1ZTogCgpgYGB7cn0KZ2dwbG90KGFyaW1hX2luc2FtcGxlLCBhZXMoeCA9IHllYXIpKSArCiAgZ2VvbV9saW5lKGFlcyh5ID0gZ2RwX2dyb3d0aCksIGxpbmV0eXBlID0gInNvbGlkIikgKwogIGdlb21fbGluZShhZXMoeSA9IGFyaW1hX2ZvcmVjYXN0KSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fcmliYm9uKGFlcyh5bWluID0gYXJpbWFfbG93ZXJfOTUsIHltYXggPSBhcmltYV91cHBlcl85NSksCiAgICAgICAgICAgICAgYWxwaGEgPSAwLjIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiT3V0LW9mLXNhbXBsZTogQVJJTUEgZm9yZWNhc3QgdnMgYWN0dWFsIiwKICAgIHkgPSAiVmFsdWUiCiAgKQpgYGAKCkxlIGdyYXBoaXF1ZSBjb21wYXJlIGxlcyB2YWxldXJzIHLDqWVsbGVzIGR1IFBJQiAgYXV4IHByw6l2aXNpb25zIGR1IG1vZMOobGUgQVJJTUEgCihjb3VyYmUgcG9pbnRpbGzDqWUpLCBhY2NvbXBhZ27DqWVzIGRlIGxldXIgaW50ZXJ2YWxsZSBkZSBjb25maWFuY2Ugw6AgOTUgJSAKY29ycmVzcG9uZGFudCDDoCBsYSB6b25lIGdyaXPDqWUuIAoKTm91cyByZW1hcnF1b25zIHF1ZSBsZSBtb2TDqGxlIHByw6l2b2l0IHVuZSB0cmFqZWN0b2lyZSByZWxhdGl2ZW1lbnQgc3RhYmxlIGFsb3JzIApxdWUgbGVzIHZhbGV1cnMgcsOpZWxsZXMgcHLDqXNlbnRlbnQgZGVzIGZsdWN0dWF0aW9ucyBpbXBvcnRhbnRlcyBub3RhbW1lbnQgbGUgcGljIApuw6lnYXRpZiB0csOocyBtYXJxdcOpIGF1IG1vbWVudCBkZSBsYSBjcmlzZSBmaW5hbmNpw6hyZSBkZSAyMDA4LgpDZSBjaG9jIMOpY29ub25vbWlxdWUgbidlc3QgcGFzIGFudGljaXDDqSBwYXIgbGUgbW9kw6hsZSBBUklNQSBjZSBxdWkgbW9udHJlIHNhIApwcmluY2lwYWxlIGxpbWl0ZS4gUG91ciBhdXRhbnQsIGNlIG1vZMOobGUgY2FwdHVyZSByZWxhdGl2ZW1lbnQgYmllbiBsYSB0ZW5kYW5jZQpnw6luw6lyYWxlIG1haXMgbmUgcGV1dCBwcsOpdm9pciDDoCBsJ2F2YW5jZSBsZXMgY3Jpc2VzIChjZSBxdWkgdmEgZGUgc29pKS4KCkVuZmluLCBub3VzIGFsbG9ucyBwcm9jw6lkZXIgYXV4IHByw6l2aXNpb25zIGNvbmNlcm5hbnQgbGEgY3JvaXNzYW5jZSBkdSBQSUIgZGFub2lzCnN1ciBsZXMgNSBwcm9jaGFpbmVzIGFubsOpZXMuIAoKYGBge3J9CmggPC0gNQpmY19hcmltYSAgPC0gZm9yZWNhc3QoZml0X2FyaW1hLCBoID0gaCkKcGxvdChmY19hcmltYSkKYGBgCgpBdmVjIGxlIG1vZMOobGUgQVJJTUEsIG9uIHBldXQgYW50aWNpcGVyIHF1ZSBsYSBjcm9pc3NhbmNlIGR1IFBJQiB2YSByZXN0ZXIgZW50cmUKw6AgcGV1IHByw6hzIC0xLzIlIGV0IDctOCUganVzcXXigJllbiAyMDI0LCBjZSBxdWkgcmVzdGUgdW4gaW50ZXJ2YWxsZSB0csOocyBsYXJnZS4gCkRhbnMgbGEgcsOpYWxpdMOpLCBsYSBjcmlzZSBkdSBDb3ZpZCBhIGNyw6nDqSB1bmUgYmFpc3NlIGltcG9ydGFudGUgZHUgUElCIGRhbm9pcyAKZW4gMjAyMCBhdmVjIHVuZSBkw6ljcm9pc3NhbmNlIGRlIC0xLjglLCBjb250cmUgdW4gcmVib25kIGFzc2V6IGltcG9ydGFudCBlbiAyMDIxCnMnw6lsZXZhbnQgw6AgNy40JS4gUmllbiBxdSdhdmVjIGNlIHJlYm9uZCwgb24gcG91cnJhaXQgw6p0cmUgdGVudMOpIGQnaW52YWxpZGVyIG5vcwpwcsOpdmlzaW9ucy4gCkZpbmFsZW1lbnQsIHVuZSBmb2lzIGRlIHBsdXMgbGVzIGNob2NzIGltcHLDqXZpc2libGVzIGTDqW1vbnRyZW50IGxlcyBsaW1pdGVzIGRlIGNlIAptb2TDqGxlLiAKCkNvbmNlcm5hbnQgbGEgbWlzZSBlbiBwbGFjZSBkJ3VuZSBwb2xpdGlxdWUgYXBwcm9wcmnDqWUsIGF1IHZ1IGRlIG5vcyBlc3RpbWF0aW9ucwoicGxhdGVzIiwgaWwgZXN0IGRpZmZpY2lsZSBkZSBjb25zZWlsbGVyIHN1ciB1bmUgcG9saXRpcXVlIGVuIHBhcnRpY3VsaWVyLiBOb3VzIApwb3V2b25zLCBwYXIgYWlsbGV1cnMsIGFmZmlybWVyIHF1J2VuIHNlIGJhc2FudCB1bmlxdWVtZW50IHN1ciBub3MgcHLDqXZpc2lvbnMsIGlsCm4neSBhdXJhaXQgYSBwcmlvcmkgcGFzIGRlIGNyaXNlIMOgIHByw6l2b2lyLiAKKFJhcHBlbG9ucyBxdWUgbGUgbW9kw6hsZSBBUklNQSBuZSBwcsOpdm9pdCBwYXMgbGVzIGNyaXNlcywgaWNpIGxlIGJ1dCBlc3Qgc2ltcGxlbWVudApkZSByw6lwb25kcmUgw6AgbGEgcXVlc3Rpb24gc3VyIGxhIHBvbGl0aXF1ZSBhcHByb3ByacOpZSBlbiBzZSBiYXNhbnQgc2ltcGxlbWVudCBzdXIgCm5vcyBwcsOpdmlzaW9ucy4pCgoKCioqKgoqKioKIyBQQVJUSUUgMzogTU9Ew4hMRSDDgCBDT1JSRUNUSU9OIEQnRVJSRVVSUwoqKioKCgpgYGB7cn0Kdm90cmVfcGF5cyA8LSAiRGVubWFyayIKCmRvbm5lZXNfZGYgPC0gZGF0YV9zY2h1bGFyaWNrICU+JQogIGZpbHRlcihjb3VudHJ5ID09IHZvdHJlX3BheXMpICU+JQogIGZpbHRlcih5ZWFyID4gMTk2MCkgJT4lCiAgc2VsZWN0KHllYXIsIHJldmVudWUsIGV4cGVuZGl0dXJlKSAlPiUKICBtdXRhdGUoCiAgICByZXZlbnVlX2dyb3d0aCAgICAgPSBjKE5BLCBkaWZmKGxvZyhyZXZlbnVlKSkgKSwKICAgIGV4cGVuZGl0dXJlX2dyb3d0aCA9IGMoTkEsIGRpZmYobG9nKGV4cGVuZGl0dXJlKSkgKQogICkgJT4lCiAgbmEub21pdCgpCgpoZWFkKGRvbm5lZXNfZGYpCmBgYAoKVG91dCBkJ2Fib3JkLCBub3VzIHRlc3RlciBzaSBub3MgZGV1eCB2YXJpYWJsZXMgc29udCBzdGF0aW9ubmFpcmVzLiAKCmBgYHtyfQpzdW1tYXJ5KHVyLmRmKGRvbm5lZXNfZGYkcmV2ZW51ZV9ncm93dGgsIHR5cGU9Im5vbmUiKSkKYGBgCgpMZSB0ZXN0IEFERiBkb25uZSB1biB0c3RhdCBkZSDigJMxLjY1NS4gQ29tbWUg4oCTMS42NTUgZXN0IHN1cMOpcmlldXIgw6AgbGEgdmFsZXVyIGNyaXRpcXVlIApkZSA1JSAo4oCTMS45NSkgbWFpcyDDoCBwZWluZSBwbHVzIGZhaWJsZSBxdWUgY2VsbGUgZGUgMTAlICjigJMxLjYxKSwgcmV2ZW51ZV9ncm93dGggCmFwcGFyYcOudCBub24gc3RhdGlvbm5haXJlLiBOb3VzIGRldm9ucyBkb25jIHLDqWFsaXNlciB1biBzZWNvbmQgdGVzdCBBREYsIGNldHRlIApmb2lzLWNpIGVuIHBhc3NhbnQgZW4gZGlmZmVyZW5jZSBwcmVtacOocmU6IAoKYGBge3J9CnN1bW1hcnkodXIuZGYoZGlmZihkb25uZWVzX2RmJHJldmVudWVfZ3Jvd3RoKSwgdHlwZT0ibm9uZSIpKQpgYGAKCkxlIHRlc3QgQURGIG5vdXMgZMOpdm9pbGUgdW5lIHRzdGF0IHRyw6hzIGluZsOpcmlldXJlIGF1eCB2YWxldXJzIGNyaXRpcXVlcyAKKHQgPSDigJM5LjM4IDwg4oCTMi42IMOgIDEgJSkuIEFpbnNpIGxhIHPDqXJpZSBkaWZmw6lyZW5jacOpZSBlc3Qgc3RhdGlvbm5haXJlLgpOb3VzIG9idGVub25zIGRvbmM6IHJldmVudWVfZ3Jvd3RoIGVzdCB1biBwcm9jZXNzdXMgaW50w6lncsOpIGTigJlvcmRyZSAxLCBJKDEpLgoKRW5zdWl0ZSwgaWwgY29udmllbnQgaWNpIGRlIGZhaXJlIGxhIG3Dqm1lIGNob3NlIHBvdXIgbGEgdmFyaWFibGUgImV4cGVuZGl0dXJlX2dyb3d0aCIKCmBgYHtyfQpzdW1tYXJ5KHVyLmRmKGRvbm5lZXNfZGYkZXhwZW5kaXR1cmVfZ3Jvd3RoLCB0eXBlPSJub25lIikpCmBgYAoKTGUgdGVzdCBBREYgbW9udHJlIHF1ZSBsYSB0c3RhdCBlc3QgZGUg4oCTMS4zOSBxdWkgZXN0IHN1cMOpcmlldXJlIGF1eCBzZXVpbHMgY3JpdGlxdWVzLCAKY2UgcXVpIGNvbmR1aXQgw6AgYWZmaXJtZXIgcXVlIGxhIHPDqXJpZSBu4oCZZXN0ICBwYXMgc3RhdGlvbm5haXJlIGV0IGRvaXQgw6p0cmUgZGlmZsOpcmVuY2nDqWUgCnBvdXIgbGUgZGV2ZW5pci4KCmBgYHtyfQpzdW1tYXJ5KHVyLmRmKGRpZmYoZG9ubmVlc19kZiRleHBlbmRpdHVyZV9ncm93dGgpLCB0eXBlPSJub25lIikpCmBgYAoKQXByw6hzIHBhc3NhZ2UgZW4gZGlmZsOpcmVuY2UgcHJlbWnDqHJlLCBsYSB0c3RhdCAo4oCTNy40MykgZGV2aWVudCBsYXJnZW1lbnQgaW5mw6lyaWV1cmUgYQp1eCB2YWxldXJzIGNyaXRpcXVlcyBjZSBxdWkgY29uZmlybWUgcXVlIGxhIGRpZmZlcmVuY2UgcHJlbWllcmUgZGUgbm90cmUgc8OpcmllCmV4cGVuZGl0dXJlX2dyb3d0aCBlc3Qgc3RhdGlvbm5haXJlLgoKQWluc2ksIGxlcyBkZXV4IHPDqXJpZXMgw6l0dWRpw6llczsgcmV2ZW51ZV9ncm93dGggZXQgZXhwZW5kaXR1cmVfZ3Jvd3RoLCBhcHBhcmFpc3NlbnQgCm5vbiBzdGF0aW9ubmFpcmVzIGVuIG5pdmVhdSBjYXIgbGV1cnMgdHN0YXQgc29udCBzdXDDqXJpZXVyZXMgYXV4IHZhbGV1cnMgY3JpdGlxdWVzLgoKRW4gcmV2YW5jaGUsIGFwcsOocyBwYXNzYWdlIGVuIGRpZmbDqXJlbmNlIHByZW1pw6hyZSBsZXMgZGV1eCBzw6lyaWVzIGRldmllbm5lbnQgCmNsYWlyZW1lbnQgc3RhdGlvbm5haXJlcyA6Ci1BREYozpRyZXZlbnVlX2dyb3d0aCkgPSDigJM5LjM4Ci1BREYozpRleHBlbmRpdHVyZV9ncm93dGgpID0g4oCTNy40CkFpbnNpLCBsZXMgZGV1eCB2YXJpYWJsZXMgc29udCBpbnTDqWdyw6llcyBk4oCZb3JkcmUgMSwgSSgxKS4KCgpMZXMgZGV1eCBtb2TDqGxlcyBvcHRpbWF1eCBwb3VyIG5vcyB2YXJpYWJsZXMgc29udCBkZXMgbW9kw6hsZXMgQVJNQSBhdmVjIHVuIG9yZHJlIApk4oCZaW50w6lncmF0aW9uIMOpZ2FsIMOgIDEuIElsIHkgYSBkb25jIHVuIHJpc3F1ZSBkZSByw6lncmVzc2lvbiBmYWxsYWNpZXVzZSBzaSBvbiAKZmFpdCBsYSByw6lncmVzc2lvbiBjbGFzc2lxdWUuIEV0YW50IGRvbm7DqSBsYSBwcsOpc2VuY2UgZGUgY29pbnTDqWdyYXRpb24gZGFucyBub3RyZSAKbW9kw6hsZSwgb24gdGVzdGUgbGEgdmFsaWRpdMOpIGR1IG1vZMOobGUgw6AgY29ycmVjdGlvbiBk4oCZZXJyZXVyczogCgpgYGB7cn0KZnMgPC0gZmVvbHMocmV2ZW51ZV9ncm93dGggfiBleHBlbmRpdHVyZV9ncm93dGgsIGRhdGEgPSBkb25uZWVzX2RmKQpkb25uZWVzX2RmJHJlc2lkIDwtIHJlc2lkdWFscyhmcykKc3VtbWFyeSh1ci5kZihkb25uZWVzX2RmJHJlc2lkLCB0eXBlID0gIm5vbmUiKSkKYGBgCgpDb21tZSBsYSB0c3RhdCBlc3Qg4oCTNC42MCA8IOKAkzIuNiwgbm91cyBwb3V2b25zIGFmZmlybWVyIHF1ZSBsZXMgcsOpc2lkdXMgc29udCAKc3RhdGlvbm5haXJlIGV0IHF1ZSBkb25jIGlsIGV4aXN0ZSBiaWVuIHVuZSByZWxhdGlvbiBkZSBsb25nIHRlcm1lIGVudHJlIApyZXZlbnVlX2dyb3d0aCBldCBleHBlbmRpdHVyZV9ncm93dGguCgpBaW5zaSwgY29tbWUgbGVzIGRldXggc8OpcmllcyBzb250IGludMOpZ3LDqWVzIGR1IG3Dqm1lIG9yZHJlIGV0IGxldXJzIHLDqXNpZHVzIHNvbnQgCnN0YXRpb25uYWlyZXMgb24gcGV1dCBhbG9ycyB1dGlsaXNlciB1biBtb2TDqGxlIMOgIGNvcnJlY3Rpb24gZOKAmWVycmV1ciAoRUNNKSDDoCAKbOKAmcOpdGFwZSAyLgoKCgpPbiBjcsOpZSBlbnN1aXRlIGxhIHZhcmlhYmxlIGxyZXNpZHVhbHMgcXVpIHJlcHLDqXNlbnRlIGzigJnDqWNhcnQgZGUgbGEgcmVsYXRpb24gbG9uZyAKdGVybWUgw6AgbGEgcMOpcmlvZGUgcHLDqWPDqWRlbnRlLCBjYXIgY+KAmWVzdCBjZXR0ZSBkw6l2aWF0aW9uIHF1aSBwZXJtZXQgYXUgbW9kw6hsZSBkZSAKbWVzdXJlciBsYSB2aXRlc3NlIGRlIHJldG91ciB2ZXJzIGzigJnDqXF1aWxpYnJlLgotPiBwb3VyIG1lc3VyZXIgbGEgdml0ZXNzZSDDoCBsYXF1ZWxsZSBsZSBzeXN0w6htZSBjb3JyaWdlIGxlcyBkw6lzw6lxdWlsaWJyZXMgZGUgbG9uZyAKdGVybWUuCgpgYGB7cn0KZG9ubmVlc19kZl8yIDwtIGRvbm5lZXNfZGYgJT4lCiAgbXV0YXRlKGxyZXNpZHVhbHMgPSBkcGx5cjo6bGFnKHJlc2lkLCAxKSkKYGBgCgpQdWlzLCBlbiBzYWNoYW50IHF1ZSBub3MgZGV1eCB2YXJpYWJsZXMgc29udCBzdGF0aW9ubmFpcmVzIHVuZSBmb2lzIGxhIGRpZmZlcmVuY2UKcHJlbWllcmUgcsOpYWxpc8OpZSwgaWwgZmF1dCBkb25jIGNyZWVyIGxlcyAidmFyaWFibGVzIiBkaWZmw6lyZW5jZXMgcHJlbWnDqHJlcyBkZXMgZGV1eCBzw6lyaWVzIGNhciBsZSBtb2TDqGxlIMOgIGNvcnJlY3Rpb24gZOKAmWVycmV1ciBuw6ljZXNzaXRlIGRlIHRyYXZhaWxsZXIgYXZlYyBkZXMgdmFyaWFibGVzIHN0YXRpb25uYWlyZXMgZW4gdmFyaWF0aW9uICjOlFnigpwgZXQgzpRY4oKcKSwgYWZpbiBkZSBjYXB0dXJlciBjb3JyZWN0ZW1lbnQgbGEgZHluYW1pcXVlIGRlIGNvdXJ0IHRlcm1lLgoKUGFyIGFpbGxldXJzLCBwdWlzcXVlIG5vcyBkZXV4IHZhcmlhYmxlcyBkZXZpZW5uZW50IHN0YXRpb25uYWlyZXMgYXByw6hzIHBhc3NhZ2UgCmVuIGRpZmbDqXJlbmNlIHByZW1pw6hyZSwgaWwgZXN0IG7DqWNlc3NhaXJlIGRlIGNyw6llciBsZXMgc2VyaWVzIGVuIGRpZmZlcmVuY2UgcHJlbWllcmUKImRyZXZlbnVlX2dyb3d0aCIgZXQgImRleHBlbmRpdHVyZV9ncm93dGgiIGNhciBsZSBtb2TDqGxlIMOgIGNvcnJlY3Rpb24gZOKAmWVycmV1ciAKZG9pdCB1dGlsaXNlciBub3MgdmFyaWFibGVzIHN0YXRpb25uYWlyZXMgKM6UWeKCnCBldCDOlFjigpwpIGFmaW4gZGUgY2FwdHVyZXIgbGEgZHluYW1pcXVlCmRlIGNvdXJ0IHRlcm1lLiAKYGBge3J9CmRvbm5lZXNfZGZfMiA8LSBkb25uZWVzX2RmXzIgJT4lCiAgbXV0YXRlKAogICAgZF9yZXZlbnVlX2dyb3d0aCAgICAgPSBjKE5BLCBkaWZmKHJldmVudWVfZ3Jvd3RoKSksCiAgICBkX2V4cGVuZGl0dXJlX2dyb3d0aCA9IGMoTkEsIGRpZmYoZXhwZW5kaXR1cmVfZ3Jvd3RoKSkKICApICU+JQogIG5hLm9taXQoKQpgYGAKCkFpbnNpIG9uIHLDqWFsaXNlIGRvbmMgbGUgbW9kw6hsZSDDoCBjb3JyZWN0aW9uIGTigJllcnJldXIgcGVybWV0dGFudCBk4oCZw6l0dWRpZXIgCnNpbXVsdGFuw6ltZW50IGxhIHJlbGF0aW9uIGNvdXJ0IGV0IGxvbmcgdGVybWUgKGNvcnLDqWN0aW9uIGRlcyDDqWNhcnRzKSBlbnRyZSBsZXMgCnZhcmlhdGlvbnMgZGVzIGTDqXBlbnNlcyBwdWJsaXF1ZXMgZXQgY2VsbGVzIGRlcyByZXZlbnVzIHB1YmxpY3MuCgpgYGB7cn0KZWNtIDwtIGZlb2xzKAogIGRfcmV2ZW51ZV9ncm93dGggfiBkX2V4cGVuZGl0dXJlX2dyb3d0aCArIGxyZXNpZHVhbHMsCiAgZGF0YSA9IGRvbm5lZXNfZGZfMgopCgpldGFibGUoZWNtKQpgYGAKCkxlIGNvZWZmaWNpZW50IGRlIGRfZXhwZW5kaXR1cmVfZ3Jvd3RoIDAuNjI3MyoqKiBlc3QgcG9zaXRpZiBldCB0csOocyBzaWduaWZpY2F0aWYsIApjZWxhIHNpZ25pZmllIHF14oCZw6AgY291cnQgdGVybWUgdW5lIGhhdXNzZSBkZXMgZMOpcGVuc2VzIHB1YmxpcXVlcyBz4oCZYWNjb21wYWduZSAKZOKAmXVuZSBoYXVzc2UgZGVzIHJldmVudXMgcHVibGljcy4KTGUgY29lZmZpY2llbnQgZGUgbHJlc2lkdWFscyAtMS4wMDYqKiogZXN0IG7DqWdhdGlmLCB0csOocyBzaWduaWZpY2F0aWYgZXQgbMOpZ8OocmVtZW50IAppbmbDqXJpZXVyIMOgIOKAkzEgY2UgcXVpIGluZGlxdWUgdW5lIGZvcnRlIGZvcmNlIGRlIHJhcHBlbCB2ZXJzIGzigJnDqXF1aWxpYnJlIGRlIGxvbmcgCnRlcm1lLiBDZWxhIHNpZ25pZmllIHF1ZSBsb3JzcXVlIGxlcyByZXZlbnVzIHPigJnDqWxvaWduZW50IGRlIGxldXIgdHJhamVjdG9pcmUgCiJ0aMOpb3JpcXVlIiwgbOKAmWFqdXN0ZW1lbnQgc2UgZmFpdCByYXBpZGVtZW50LgoKUGFyIGFpbGxldXJzLCBsZXMgcsOpc2lkdXMgZGUgbGEgcHJlbWnDqHJlIMOpdGFwZSBzb250IHN0YXRpb25uYWlyZXMsIGRvbmMgbOKAmUVDTSBlc3QgCnZhbGlkZS4gCkRlIHBsdXMsIHB1aXNxdWUgbGUgY29lZmZpY2llbnQgZGUgbGFncmVzaWR1YWxzIGVzdCBuw6lnYXRpZiB0csOocyBzaWduaWZpY2F0aWYgCmV0IGNvbXByaXMgZW50cmUg4oCTMSBldCAwIChpY2kgbm91cyBkaXJvbnMgcG91ciBkZXMgcmFpb25zIGRlIHNpbXBsaWNpdMOpIHF1ZSAtMS4wMDYqKioKZXN0IGVudmlyb24gw6lnYWwgw6AgLTEpLCBpbCBlc3QgcHLDqWbDqXJhYmxlIGTigJl1dGlsaXNlciBsZSBtb2TDqGxlIMOgIGNvcnJlY3Rpb24gCmTigJllcnJldXIgcGx1dMO0dCBxdeKAmXVuIE9MUyBjbGFzc2lxdWUgcG91ciByZXByw6lzZW50ZXIgbGEgcmVsYXRpb24gZW50cmUgcmV2ZW51ZV9ncm93dGggCmV0IGV4cGVuZGl0dXJlX2dyb3d0aCBjYXIgbOKAmUVDTSBpbnTDqGdyZSDDoCBsYSBmb2lzIGzigJlhanVzdGVtZW50IGNvdXJ0IHRlcm1lIGV0IApsYSByZWxhdGlvbiBkJ8OpcXVpbGlicmUgZGUgbG9uZyB0ZXJtZSBhbG9ycyBxdWUgbCdPTFMgbm9uLgoKCkF2YW50IGRlIHRlcm1pbmVyLCBpbCBmYXV0IGdhcmFudGlyIGxhIGZpYWJpbGl0w6kgZGUgbm90cmUgbW9kw6hsZSDDoCBjb3JyZWN0aW9uIApk4oCZZXJyZXVyIGVuIHJlZ2FyZGFudCBzaSBsZXMgcsOpc2lkdXMgdmVyaWZpZW50IHRyb2lzIGh5cG90aMOoc2VzLiBOb3VzIHRlc3Rlcm9ucwpkb25jOiAKLWzigJlob21vc2PDqWRhc3RpY2l0w6kgw6AgbOKAmWFpZGUgZHUgdGVzdCBkZSBCcmV1c2NoLVBhZ2FuIHF1aSBwZXJtZXQgZGUgdsOpcmlmaWVyIHF1ZSAKbGEgdmFyaWFuY2UgZGVzIHLDqXNpZHVzIHJlc3RlIGNvbnN0YW50ZSBkYW5zIGxlIHRlbXBzLgoKLWVuc3VpdGUgbGEgbm9ybWFsaXTDqSBkZXMgcsOpc2lkdXMgdmlhIGxlIHRlc3QgU2hhcGlyby1XaWxrIHF1aSB0ZXN0ZSBsYSAKbm9ybWFsaXTDqSBk4oCZdW5lIHPDqXJpZQoKLUV0IGVuZmluLCBs4oCZaW5kw6lwZW5kYW5jZSBkZXMgcsOpc2lkdXMgZ3LDomNlIGF1IHRlc3QgTGp1bmctQm94IGFmaW4gZGUgc+KAmWFzc3VyZXIgCnF14oCZaWwgbuKAmXkgYSBwYXMgZOKAmWF1dG9jb3Jyw6lsYXRpb24gImxlcyByw6lzaWR1cyBk4oCZdW5lIHDDqXJpb2RlIG5lIGRvaXZlbnQgcGFzIMOqdHJlIApleHBsaXF1w6lzIHBhciBsZXMgcsOpc2lkdXMgcHLDqWPDqWRlbnRzLiIKCgpgYGB7cn0KcmVzX2VjbSA8LSByZXNpZHVhbHMoZWNtKQpicHRlc3QoZF9yZXZlbnVlX2dyb3d0aCB+IGRfZXhwZW5kaXR1cmVfZ3Jvd3RoICsgbHJlc2lkdWFscywgZGF0YSA9IGRvbm5lZXNfZGZfMikKYGBgCkRhbnMgbm90cmUgY2FzLCBsZSB0ZXN0IEJQIGRvbm5lIHVuZSBzdGF0aXN0aXF1ZSBkZSAwLjY0ODYxIHBvdXIgMSBkZWdyw6kgZGUgCmxpYmVydMOpIGF2ZWMgdW5lIHAtdmFsdWUgPSAwLjcyMy4gQ29tbWUgbGEgcC12YWx1ZSBu4oCZZXN0IHBhcyBzaWduaWZpY2F0aXZlLCBvbiAKbmUgcmVqZXR0ZSBwYXMgbOKAmWh5cG90aMOoc2UgbnVsbGUgZOKAmWhvbW9zY8OpZGFzdGljaXTDqSBldCBvbiBjb25jbHV0IHF1ZSBsZXMgcsOpc2lkdXMgCnNvbnQgaG9tb3Njw6lkYXN0aXF1ZXMuCgoKCmBgYHtyfQpzaGFwaXJvLnRlc3QocmVzX2VjbSkKYGBgCkxhIHAtdmFsdWUgZXN0IHNpZ25pZmljYXRpdmUsIGRvbmMgbGVzIHLDqXNpZHVzIG5lIHN1aXZlbnQgcGFzIHVuZSBsb2kgbm9ybWFsZSAKc2Vsb24gbGUgdGVzdCBkZSBTaGFwaXJvLiBDZWxhIHNpZ25pZmllIHF1ZSBsZXMgZXJyZXVycyBkdSBtb2TDqGxlIG5lIHNvbnQgcGFzIApkaXN0cmlidcOpZXMgZGUgZmHDp29uIHN5bcOpdHJpcXVlIGF1dG91ciBkZSB6w6lyby4KCgoKYGBge3J9CkJveC50ZXN0KHJlc19lY20sIGxhZyA9IDEwLCB0eXBlID0gIkxqdW5nLUJveCIpCmBgYApMYSBwLXZhbHVlIGR1IHRlc3QgZGUgTGp1bmctQm94IG7igJllc3QgcGFzIHNpZ25pZmljYXRpdmUuIE9uIG5lIHJlamV0dGUgZG9uYyBwYXMgCmzigJloeXBvdGjDqHNlIG51bGxlIGTigJlpbmTDqXBlbmRhbmNlIGRlcyByw6lzaWR1cy4gCkxlcyByw6lzaWR1cyBhcHBhcmFpc3NlbnQgaW5kw6lwZW5kYW50cyBldCBpbCBu4oCZeSBhIHBhcyBk4oCZYXV0b2NvcnLDqWxhdGlvbiBlbnRyZSBldXguIAoKUG91ciB0ZXJtaW5lciwgbGUgdGVzdCBkZSBCcmV1c2NoLVBhZ2FuIGluZGlxdWUgdW5lIGhvbW9zY8OpZGFzdGljaXTDqSBkZXMgcsOpc2lkdXMKKHZhcmlhbmNlIGRlcyBlcnJldXJzIHJlc3RlIHN0YWJsZSBkYW5zIGxlIHRlbXBzKS4gRW4gcmV2YW5jaGUsIGxlIHRlc3QgZGUgClNoYXBpcm8tV2lsayBtb250cmUgcXVlIGxlcyByw6lzaWR1cyBuZSBzdWl2ZW50IHBhcyB1bmUgbG9pIG5vcm1hbGUuIEVuZmluLCBsZSB0ZXN0IApkZSBManVuZy1Cb3ggcsOpdsOobGUgcXVlIGxlcyByw6lzaWR1cyBzb250IGluZMOpcGVuZGFudHMgZG9uYyBzYW5zIGF1dG9jb3Jyw6lsYXRpb24uCkFpbnNpLCBtYWxncsOpIHVuZSBub24tbm9ybWFsaXTDqSBkZXMgZXJyZXVycyBs4oCZRUNNIHJlc3RlIGdsb2JhbGVtZW50IGNvcnJlY3RlLCBjYXIgCmxlcyBwcm9wcmnDqXTDqXMgZXNzZW50aWVsbGVzIGRlIHZhcmlhbmNlIGNvbnN0YW50ZSBldCBk4oCZYWJzZW5jZSBkZSBkw6lwZW5kYW5jZSAKdGVtcG9yZWxsZSBzb250IHJlc3BlY3TDqWVzLgoKCgoKCgoKCgoKCgoKCgoKCgoKCgo=