L’objectif de ce document est de proposer une initiation aux stats Bayésiennes, dans le contexte des essais cliniques, et auprès d’un public ayant déjà un certain bagage de statistiques fréquentistes.

On souhaite également ne pas rester dans l’abstraction, et proposer des petits exemples applicatifs que chacun puisse répliquer/modifier.

Pour les utilisateurs de R, on commence par charger un certain nombre de modules intéressants.

# le package moderne standard pour manipuler ses données
library(tidyverse)
# pour faire des graphes multiples
library(cowplot)
# pour afficher joliment les tableaux dans un document rmarkdown
library(knitr)
# pour la loi beta-binomiale dont je parle dans le doc
library(extraDistr)

# quelques couleurs manuelles pour intégrer les figures à la présentation associée
bleufonce <- "#3d5468"
bleuclair <- "#5b7c98"
rose <- "#ff5555"

Exemple introductif fréquentiste

Données binaires

Les stats Bayésiennes reposent sur un vocabulaire précis, qu’on va essayer d’aborder pas à pas autour d’un exemple minimaliste.

Cet exemple est le suivant : imaginez que vous étudiez un échantillon de \(n\) patients, classés en “répondeur” ou “non-répondeur”. La donnée observée est donc très simple : il s’agit de \(n_r\), le nombre de patients répondeurs.

On fixe la valeur de \(n\) et le nombre observé \(n_r\) de patients répondeurs à l’issue de l’étude, pour tout le document.

n <- 120
n_r <- 90

Modèle fréquentiste et vraisemblance

Si vous pensez comme un fréquentiste, vous créez probablement dans votre esprit le modèle suivant : il existe une probabilité \(p\) fixée d’être répondeur, et une probabilité \(1-p\) d’être non-répondeur.

Chaque individu est indépendant de tous les autres, et le nombre \(N_r\) de répondeur suit donc une loi binomiale :

\[ N_r \sim \mathcal{B}(n, p) \]

Si vous fixez \(p\), vous êtes capable de faire des simulations sous votre modèle et de représenter la distribution attendue pour vos données. La figure suivante nous illustre ça si \(p = 0.6\).

p <- 0.6
d <- tibble(x = 0:n) %>%
    mutate(density = dbinom(x, size=n, prob=p))
d %>% ggplot(aes(x = x, y = density)) +
    geom_bar(stat="identity", fill=bleuclair) +
    geom_vline(xintercept = n_r, col=rose) +
    xlab("Nombre de répondeurs") +
    ylab("Probabilité si p vaut 0.6") +
    theme_bw()

Estimation en fréquentiste

Si votre problème est un problème d’estimation du paramètre \(p\), vous allez typiquement chercher le paramètre \(\hat{p}\) maximisant la vraisemblance, c’est à dire :

\[ \hat{p} = \text{argmax}_p ~\mathbb{P}( N_r = n_r | p ) \]

Dans ce cas très précis, on pourrait montrer que ça donne exactement l’estimation qu’on aurait eu envie de faire intuitivement : \(\hat{p} = N_r / n\) ce qui donne, dans cet exemple, une estimation ponctuelle à 0.75. Visuellement, on a donc choisi \(p\) tel que la vraisemblance ressemble à ça :

p <- round(n_r/n,2)
d <- tibble(x = 0:n) %>%
    mutate(density = dbinom(x, size=n, prob=p))
d %>% ggplot(aes(x = x, y = density)) +
    geom_bar(stat="identity", fill=bleuclair) +
    geom_vline(xintercept = n_r, col=rose) +
    xlab("Nombre de répondeurs") +
    ylab(paste("Probabilité si p vaut ", p, sep="")) +
    theme_bw()

Dans un problème d’estimation classique, on aimerait en plus obtenir un intervalle de confiance pour \(p\), c’est à dire deux variables aléatoires \(\hat{a}\) et \(\hat{b}\) vérifiant :

\[ \mathbb{P}(p \in (\hat{a},\hat{b})) \geq 95\% \]

Notons que ce type de résultat mathématique n’est pas en soi si facile à comprendre. Ici, ce sont les bornes de l’intervalle qui sont des variables aléatoires. Celles qui seront finalement calculées ne serot plus les estimateurs (aléatoires), mais leurs estimations. La seule garantie donnée par ce résultat, c’est que si on répétait l’expérience un grand nombre de fois, 95% des intervalles qu’on donnerait contiendrait la vraie valeur de \(p\).

C’est de plus (en général) un problème difficile ! Même pour ce cas très simple, ça nécessite de reposer sur des théorèmes asymptotiques, et de produire des “beaux” résultats de maths.

Pour tous les modèles relativement simples / classiques, tout ça a déjà été fait pour nous, et il ne nous reste qu’à faire confiance aux outils implémentés pour obtenir l’estimation de notre intervalle :

ci <- prop.test(x=n_r, n=n)$conf.int

Ici l’intervalle de confiance à 95% englobe les valeurs [0.66, 0.82].

Modèle introductif version Bayésien

Vraisemblance identique

Si vous pensez comme un Bayésien, vous commencez par vous dire la même chose que précédemment : si vous connaissiez \(p\), la probabilité d’être répondeur, alors vous sauriez que le nombre de répondeur est :

\[ N_r | p ~~ \sim ~~ \mathcal{B}(n, p) \]

La loi de \(N_r\) (les données) sachant \(p\) (le paramètre) est appelée vraisemblance et est notée \(\mathbb{P}(N_r | p)\).

Choix d’un prior

Seulement voilà : le raisonnement Bayésien suppose qu’il n’y a pas une unique valeur de \(p\), mais qu’il y a en fait une distribution de probabilité sur le paramètre lui-même ! C’est ce qu’on appelle prior : \(\mathbb{P}(p)\).

Puisque \(p\) vit dans (0,1), il faut l’équiper d’une loi de probabilité sur (0,1), par exemple une loi uniforme.

tibble(x = seq(-0.1, 1.1, 0.001)) %>%
    mutate(y = dunif(x)) %>%
    ggplot(aes(x=x, y=y)) +
    geom_line(col = bleuclair) +
    xlab("Valeur de p") +
    ylab("densité") +
    theme_bw()

Marginale des observations

Dans un monde Bayésien, ce n’est que maintenant qu’on a choisi une vraisemblance et un prior qu’on peut simuler une réalisation de \(N_r\) sous notre modèle. On simule une réalisation de \(p\) tiré dans le prior, puis une réalisation de loi binomiale ayant cette valeur de \(p\) :

p_simu = runif(1, min=0, max=1)
n_r_simu = rbinom(1, size=n, prob=p_simu)

Ca revient à tirer une valeur dans la loi de \(N_r\), qu’on appelle loi marginale des observations. Cette loi peut s’exprimer comme :

\[ \mathbb{P}(N_r) = \int_0^1 \mathbb{P}(N_r | p) \mathbb{P}(p \in dp) dp \]

Il est très facile de simuler dans cette loi, mais elle n’est pas toujours facile à caractériser plus finement. Dans notre scénario, on peut toujours représenter l’allure de la distribution obtenue par simulation :

  1. on simule une valeur de \(p\) dans le prior de \(p\),
  2. on simule une valeur de \(N_r\) dans la distribution de \(N_r\) sachant que \(p\) est fixé à la valeur simulée à la première étape.
sim_n_r <- function(n, sample_size){
    p_simu = runif(sample_size, min=0, max=1)
    return (rbinom(sample_size, size=n, prob=p_simu))
}
tibble(x = sim_n_r(n, 1e5)) %>% 
    group_by(x) %>%
    summarize(n = n()/1e5) %>%
    ggplot(aes(x = x, y = n)) +
    geom_bar(stat="identity", fill=bleuclair) +
    theme_bw() +
    xlab("Nombre de répondeurs") +
    ylab("Probabilité")

Posterior

C’est LA quantité d’intérêt pour le statisticien ! Dans la réalité, on a observé UNE valeur \(n_r\). On cherche donc :

\[ \mathbb{P}(p | N_r = n_r) = \frac{ \mathbb{P}(N_r = n_r | p) \mathbb{P}(p) }{ \mathbb{P}(N_r = n_r) } \]

On obtient le posterior en combinant l’idée qu’on avait a priori sur \(p\) (le prior) avec ce qu’on apprend de notre expérience (la vraisemblance).

J’insiste également une nouvelle fois sur ce changement de paradigme majeur : on cherche une distribution de probabilité sur \(p\), et on arrête de penser qu’il y a une valeur unique de \(p\).

Plusieurs possibilités peuvent se présenter pour le calcul du posterior. Mais toutes utilisent déjà une règle commune : on va faire abstraction du dénominateur (la marginale de \(N_r\)) qui était pénible à calculer et qui ne sert ici que de facteur de normalisation. On commence donc toujours par ré-écrire l’équation précédente comme :

\[ \mathbb{P}(p | N_r = n_r) \propto \mathbb{P}(N_r = n_r | p) \mathbb{P}(p) \]

Puis, dans ce cas précis, tout est très simple car le prior de \(p\) est uniforme, ce qui fait qu’on peut ré-écrire notre équation comme :

\[\begin{align*} \mathbb{P}(p | N_r = n_r) &\propto \binom{90}{120} p^{90} (1-p)^{120 - 90} \\ &\propto p^{90} (1-p)^{120 - 90} \end{align*}\]

Où on reconnaît une loi Bêta de paramètres \(\alpha = 90+1\) et \(\beta = 120-90+1\). Le posterior a l’allure suivante :

alpha <- n_r + 1
beta <- n - n_r + 1
d_posterior <- tibble(x = seq(0, 1, 0.001)) %>%
    mutate(y = dbeta(x, shape1=alpha, shape2=beta))
plot_posterior <- d_posterior %>%
    ggplot(aes(x=x, y=y)) +
    geom_line(col = bleuclair) +
    xlab("Valeur de p") +
    ylab("densité du posterior") +
    theme_bw()
plot_posterior

Si on souhaite un estimateur ponctuel, il est d’usage d’utiliser le maximum a posteriori, c’est à dire la valeur de \(p\) qui maximise le posterior. Ici, le calcul nous donne exactement la même solution que dans le cas fréquentiste.

plot_posterior +
    geom_vline(xintercept = 90/120, col=rose)

Intervalle de crédibilité

Si on accepte qu’il n’existe pas une unique valeur du paramètre \(p\), l’intervalle de crédibilité du Bayésien est beaucoup plus intuitif que l’intervalle de confiance du fréquentiste.

Il s’agit en effet d’un intervalle \((a,b)\) tel que :

\[ \mathbb{P}(p \in (a,b) | N_r = 90) \geq 1-\alpha \]

Typiquement, si on souhaitait avoir un intervalle de crédibilité à 95%, on prendrait les valeurs, sur le support du posterior, contenues entre les quantiles de niveau 0.025 et 0.975.

low <- qbeta(0.025, shape1=alpha, shape2=beta)
up <- qbeta(0.975, shape1=alpha, shape2=beta)
plot_posterior +
    geom_vline(xintercept = c(low, up), col=rose)

Ici, l’intervalle de crédibilité à 95% est [0.67, 0.82].

Test d’hypothèse

Enfin, les tests d’hypothèse sont réalisés de façon bien plus intuitive que dans le cas fréquentiste.

  1. on calcule la probabilité a posteriori de chaque hypothèse,
  2. on base le choix sur ces deux probabilités.

Par exemple, si on souhaite décider entre :

  • H0 : \(p \leq 0.7\)
  • H1 : \(p > 0.7\),

Alors il nous suffit de s’accorder sur un threshold de probabilité a posteriori à partir duquel on choisit H1, et de calculer nos probabilités. Visuellement, on se base donc sur :

plot_posterior +
    geom_area(data = d_posterior %>% filter(x <= 0.7), fill=rose, alpha=0.5)

Les MCMCs, la cuisine du Bayésien

Tout ce qu’on a effectué ci-dessus était réalisé dans un cas simple idéalisé pour lequel on arrivait à faire des calculs (ou plutôt, raisonner quasi sans calculs) très facilement. Ce n’est malheureusement pas la majorité des cas.

Un prior plus complexe

Dans beaucoup de situations, le prior n’est pas aussi simple, et le posterior est donc plus difficile à caractériser. Modifions notre exemple précédent : plutôt que d’avoir \(p\) uniforme sur [0,1], des données préliminaires issues de la littérature, ou des avis d’experts du domaine, suggèrent que \(p\) serait centré sur la valeur 0.6, avec un écart-type de 0.3.

Sans trop réfléchir, on se propose donc de voir ce que ça donnerait avec le prior suivant : une loi normale de moyenne 0.6 et écart-type 0.3. Seulement voilà, la cuisine commence : la loi normale est définie sur \(\mathbb{R}\). Qu’à cela ne tienne : considérons qu’on tronque cette distribution pour qu’elle ait un support sur [0,1].

mu <- 0.6
sd <- 0.3
weight_inf_0 <- pnorm(0, mean=mu, sd=sd)
weight_sup_1 <- 1 - pnorm(1, mean=mu, sd=sd)
tibble(x = seq(0, 1, 0.001)) %>%
    mutate(y = dnorm(x, mean=mu, sd=sd)/(1 - weight_inf_0 - weight_sup_1)) %>%
    ggplot(aes(x=x, y=y)) +
    geom_line(col = bleuclair) +
    xlab("Valeur de p") +
    ylab("densité du prior") +
    theme_bw()

La marginale des observations

Comme précédemment, il n’est pas évident de caractériser la loi de \(N_r\), mais on peut l’approcher par simulations :

sim_n_r <- function(n, sample_size){
    res <- c()
    for (i in 1:sample_size){
        p_simu = rnorm(1, mean=mu, sd=sd)
        while (p_simu < 0 | p_simu > 1){
            p_simu = rnorm(1, mean=mu, sd=sd)
        }
        n_r_simu <- rbinom(1, size=n, prob=p_simu)
        res <- c(res, n_r_simu)
    }
    return (res)
}
tibble(x = sim_n_r(n, 1e5)) %>% 
    group_by(x) %>%
    summarize(n = n()/1e5) %>%
    ggplot(aes(x = x, y = n)) +
    geom_bar(stat="identity", fill=bleuclair) +
    theme_bw() +
    xlab("Nombre de répondeurs") +
    ylab("Probabilité")

Le posterior

Comme précédemment, on peut écrire la règle de proportionnalité de base suivante :

\[ \mathbb{P}(p | N_r = n_r) \propto \mathbb{P}(N_r = n_r | p) \mathbb{P}(p) \]

Puis, en remplaçant avec ce qu’on connaît de la vraisemblance et du prior :

\[\begin{align*} \mathbb{P}(p | N_r = n_r) &= 0 ~~~\text{ si } p \notin [0,1]\\ &\propto p^{90} (1-p)^{120 - 90} e^{-\frac{1}{2} \left( \frac{p - 0.6}{0.3} \right)^2} ~~~\text{ sinon.} \end{align*}\]

Cette fois, impossible de reconnaître quoi que ce soit ! Dans ce cas de figure, qui est d’ailleurs la norme dans les applications de stats Bayésiennes, on doit s’appuyer sur des outils de simulations numériques pour échantillonner des valeurs dans le posterior sans arriver à le caractériser plus finement que ça.

Et l’outil central pour réaliser ces simulations s’appelle le MCMC, pour Markov Chain Monte Carlo.

Principe d’un MCMC

L’idée générale des techniques MCMC consiste à construire une chaîne de Markov, une suite de variables aléatoires bien particulière, qui converge vers notre distribution d’intérêt : le posterior qu’on note ici \(\nu\).

La façon la plus classique/facile de construire une telle chaîne consiste à utiliser l’algorithme de Metropolis-Hastings. Celui-ci repose sur le choix adhoc d’une loi de proposition de movement \(q\), avec \(\forall x,y, q(x, y)\) qui donne la probabilité de proposer l’état \(y\) sachant qu’on est dans l’état \(x\).

A deux-trois conditions techniques près, l’algorithme consiste à passer de l’état \(x_i\) au pas \(i\), à \(x_{i+1}\) au pas \(i+1\) en :

  1. proposant un état \(y\) en tirant dans la loi de \(q(x_i,.)\),
  2. calculant la quantité suivante : \[ r = \frac{\nu(y)q(y,x_i)}{\nu(x_i)q(x_i,y)} \]
  3. Si \(r \geq 1\), \(x_{i+1} = y\). Sinon \(x_{i+1} = y\) avec probabilité \(r\) et \(x_{i+1} = x_i\) sinon.

Il ne reste ensuite qu’à :

  • supprimer les premières itérations de la chaîne (pour réduire la dépendance aux conditions initiales),
  • échantillonner une valeur sur 10, ou sur 100, ou … (pour réduire l’auto-corrélation des valeurs).

Pour se prouver que c’est très simple à designer, on peut en construire une ici. Par simplicité, prenons une proposition de mouvement \(q\) très simple : la loi uniforme sur [0,1], quelle que soit la valeur de départ.

# notre distribution cible (posterior) est proportionnelle à nu
nu <- function(p){
    res <- p^n_r * (1-p)^(n-n_r) * exp(-0.5 * ((p - mu)/sd)^2 )
    return (res)
}

# on initialise une chaîne vide qu'on remplit un pas après l'autre
# attention, ce morceau de code peut prendre un certain temps à tourner
chain <- c()
nsteps <- 1e5
p <- 0.2
for (i in 1:nsteps){
    chain <- c(chain, p)
    y <- runif(1, min=0, max=1)
    r <- nu(y) / nu(p)
    if (r >= 1){
        p <- y
    }else{
        u = runif(1, min=0, max=1)
        if (u <= r){
            p <- y
        }
    }
}

Tout l’art de la cuisine de MCMC (sauce MH) consiste à choisir empiriquement une proposition de mouvement \(q\) qui “fonctionne” plutôt bien.

Il faut aussi choisir un peu au pif combien de valeurs on supprime au début de la chaîne (burn-in) et avec quelle fréquence on échantillonne. Pour ça, on peut regarder l’allure de la chaîne :

dmcmc <- tibble(p = chain,
                step = seq(1, nsteps)) 
dmcmc %>%
    ggplot(aes(x=step, y=p)) +
    geom_line(col = bleufonce) +
    theme_bw()

Sur cet exemple tout simple, le burn-in est facile à repérer visuellement. Si on enlève les \(10^4\) premières valeurs et qu’on conserve une valeur sur 10, on conserve assez de valeurs pour estimer notre posterior à partir de l’histogramme empirique suivant :

dmcmc %>%
    filter(step > 1e4 & step %% 10 == 0) %>%
    ggplot(aes(x=p)) +
    geom_histogram(aes(y=..density..), bins=50, col=bleuclair, fill=bleuclair, alpha=0.5) +
    geom_density(col=rose, alpha=0.5) +
    ylab("densité de probabilité") +
    theme_bw()

On peut finalement obtenir un intervalle de crédibilité à 95% en récupérant les quantiles empiriques de notre posterior :

ic95_mcmc <- dmcmc %>%
    filter(step > 1e4 & step %% 10 == 0) %>%
    pull(p) %>%
    quantile(probs = c(0.025, 0.975))

Ici, l’intervalle de crédibilité à 95% est [0.66, 0.82].

Le prior conjugué, un outil plus smart

Principe mathématique

On l’a vu, le MCMC permet de faire toute la cuisine qu’on souhaite, en mode Bayésien. Ce n’est pas encore visible avec cet exemple simple qui ne s’intéresse qu’à une seule variable \(p\), mais ça peut devenir très vite lourd d’un point de vue computationnel quand on a un espace de paramètres en plus grande dimension à explorer. En plus de ça, c’est très largement “inélégant” d’un point de vue maths, et on se retrouve souvent à utiliser tout et n’importe quoi comme prior, même des distributions absolument pas faites, à la base, pour avoir le support qu’on leur donne.

Une alternative plus élégante, mais qui nécessite de réfléchir un peu plus en amont, consiste à s’appuyer sur un modèle plus approprié, avec, par exemple, un prior conjugué. Sans entrer dans les détails, pour l’essentiel des distributions de vraisemblance que vous pourriez connaître (qui font partie d’une grande classe de distributions appelée famille exponentielle), il existe ce qu’on appelle des priors/posteriors conjugués, qui ont le bon goût d’avoir la même forme de distribution, avec des paramètres différents.

Prior conjugué sur notre exemple

Sur notre exemple, la vraisemblance est une loi binomiale. Le prior conjugué correspondant est une loi Bêta, avec la propriété suivante :

\[\begin{align*} &p \sim \mathcal{Beta}(\alpha, \beta) \text{ et } N_r | p \sim \mathcal{B}(n, p) \\ \Longrightarrow ~&p | N_r \sim \mathcal{Beta}(\alpha + N_r, \beta + n - N_r) \end{align*}\]

Ce genre de propriété est de plus très facile à démontrer, puisque :

  1. la distribution Beta est telle que \(\mathbb{P}(p) \propto p^{\alpha-1} (1-p)^{\beta-1}\).
  2. la distribution Binomiale de la vraisemblance nous donne \(\mathbb{P}(N_r | p) \propto p^{N_r} (1-p)^{n-N_r}\).
  3. et donc le posterior s’obtient en écrivant : \[\begin{align*} \mathbb{P}(p | N_r) &\propto \mathbb{P}(p) \mathbb{P}(N_r | p) \\ &\propto p^{alpha + N_r - 1} (1-p)^{\beta + n - N_r - 1} \end{align*}\]

Où on reconnaît, donc, une loi Bêta de paramètres \((\alpha + N_r, \beta + (n - N_r))\). C’est extrêmement pratique, puisque nos hyperparamètres ont maintenant une interprétation intuitive en terme de nombre de répondeurs/non-répondeurs qu’on aurait déjà vu avant de faire notre nouvelle expérience.

Par exemple, on pourrait regarder la biblio, se dire qu’une précédente étude a déjà regardé notre problème d’intérêt. Celle-ci avait enregistré \(\alpha = 50\) répondeurs et \(\beta = 60\) non-répondeurs. On va donc partir sur un prior avec loi Beta de paramètres \((\alpha=50, \beta=60)\).

alpha <- 50
beta <- 60
tibble(x = seq(0, 1, 0.001)) %>%
    mutate(y = dbeta(x, shape1=alpha, shape2=beta)) %>%
    ggplot(aes(x=x, y=y)) +
    geom_line(col = bleuclair) +
    xlab("Valeur de p") +
    ylab("densité du prior") +
    theme_bw()

Loi de la marginale

Dans tous ces cas avec un prior conjugué, la loi de la marginale des observations est aussi connue avec des formules fermées, bien qu’en général pas triviale. Ici, la loi de la marginale est appelée Bêta-binomiale, et son allure est affichée ci-dessous :

tibble(k = seq(0, n, 1)) %>%
    mutate(y = dbbinom(k, size=n, alpha=alpha, beta=beta)) %>%
    ggplot(aes(x=k, y=y)) +
    geom_line(col = bleuclair) +
    xlab("Nombre de répondeurs") +
    ylab("probabilité") +
    theme_bw()

Loi du posterior

Puisqu’on utilise un prior conjugué, le posterior nous est donné sur un plateau d’argent : il s’agit d’une loi Bêta de paramètres \(\alpha + N_r\), \(\beta + n - N_r\).

tibble(x = rep(seq(0, 1, length.out=500), 2),
       distribution = rep(c("prior", "posterior"), each=500)) %>%
    mutate(y = dbeta(x, 
                     shape1=rep(c(alpha, alpha + n_r), each=500), 
                     shape2=rep(c(beta, beta + n - n_r), each=500)) ) %>%
    ggplot(aes(x=x, y=y, col=distribution)) +
    geom_line() +
    xlab("Valeur de p") +
    ylab("densité") +
    theme_bw()

Sur cet exemple, on peut une nouvelle fois calculer un intervalle de crédibilité à 95%,

ic95_conj <- qbeta(c(0.025, 0.975), shape1=alpha+n_r, shape2=beta+n-n_r)

Ici, l’intervalle de crédibilité à 95% est [0.54, 0.67].

On remarque ici une vraie différence de posterior, et donc d’intervalle de crédibilité, par rapport aux exemples précédents. Ceci est entièrement dû à l’influence du prior, qui est pris en compte dans notre posterior et le “shifte” sur la gauche par rapport aux exemples précédents.

Conclusion

Je tente le tableau suivant pour résumer les avantages et inconvénients du fréquentiste et du Bayésien pour les essais cliniques, basés sur ce qui est décrit dans ce notebook :

Les autres points importants sont les suivants :

  • Pour les problèmes d’estimation, la notion d’intervalle de crédibilité est plus facile à comprendre que l’intervalle de confiance.
  • Pour les tests d’hypothèses, il est possible de faire des choix, en Bayésien, basés directement sur la probabilité des deux hypothèses sachant les données, ce qui est aussi notablement plus facile à comprendre.
  • La notion de non-informative prior est assez largement mensongère, à remplacer par celle de flat prior.
  • Les priors conjugués sont très intéressants dans les cas simples pour avoir un modèle simple et élégant.
  • Dans tous les autres cas, des MCMC permettent de déterminer la distribution à posteriori.
LS0tCnRpdGxlOiAiSW5pdGlhdGlvbiBhdXggc3RhdGlzdGlxdWVzIEJhecOpc2llbm5lcyIKYXV0aG9yOiAiTWFyYyBNYW5jZWF1IgpkYXRlOiAiMjAyMy0xMiIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiBUUlVFCiAgICB0b2NfZGVwdGg6IDIKICAgIHRvY19mbG9hdDogVFJVRQogICAgaGlnaGxpZ2h0OiAidGFuZ28iCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFCi0tLQoKYGBge3IgZWNobz1GfQprbml0cjo6b3B0c19jaHVuayRzZXQoZmlnLndpZHRoPTEwKQpgYGAKCkwnb2JqZWN0aWYgZGUgY2UgZG9jdW1lbnQgZXN0IGRlIHByb3Bvc2VyIHVuZSBpbml0aWF0aW9uIGF1eCBzdGF0cyBCYXnDqXNpZW5uZXMsCmRhbnMgbGUgY29udGV4dGUgZGVzIGVzc2FpcyBjbGluaXF1ZXMsIGV0IGF1cHLDqHMgZCd1biBwdWJsaWMgYXlhbnQgZMOpasOgCnVuIGNlcnRhaW4gYmFnYWdlIGRlIHN0YXRpc3RpcXVlcyBmcsOpcXVlbnRpc3Rlcy4KCk9uIHNvdWhhaXRlIMOpZ2FsZW1lbnQgbmUgcGFzIHJlc3RlciBkYW5zIGwnYWJzdHJhY3Rpb24sCmV0IHByb3Bvc2VyIGRlcyBwZXRpdHMgZXhlbXBsZXMgYXBwbGljYXRpZnMgcXVlIGNoYWN1bgpwdWlzc2UgcsOpcGxpcXVlci9tb2RpZmllci4KClBvdXIgbGVzIHV0aWxpc2F0ZXVycyBkZSBSLCBvbiBjb21tZW5jZSBwYXIgY2hhcmdlciB1biBjZXJ0YWluIG5vbWJyZSBkZSBtb2R1bGVzIGludMOpcmVzc2FudHMuCgpgYGB7ciBtZXNzYWdlPUZ9CiMgbGUgcGFja2FnZSBtb2Rlcm5lIHN0YW5kYXJkIHBvdXIgbWFuaXB1bGVyIHNlcyBkb25uw6llcwpsaWJyYXJ5KHRpZHl2ZXJzZSkKIyBwb3VyIGZhaXJlIGRlcyBncmFwaGVzIG11bHRpcGxlcwpsaWJyYXJ5KGNvd3Bsb3QpCiMgcG91ciBhZmZpY2hlciBqb2xpbWVudCBsZXMgdGFibGVhdXggZGFucyB1biBkb2N1bWVudCBybWFya2Rvd24KbGlicmFyeShrbml0cikKIyBwb3VyIGxhIGxvaSBiZXRhLWJpbm9taWFsZSBkb250IGplIHBhcmxlIGRhbnMgbGUgZG9jCmxpYnJhcnkoZXh0cmFEaXN0cikKCiMgcXVlbHF1ZXMgY291bGV1cnMgbWFudWVsbGVzIHBvdXIgaW50w6lncmVyIGxlcyBmaWd1cmVzIMOgIGxhIHByw6lzZW50YXRpb24gYXNzb2Npw6llCmJsZXVmb25jZSA8LSAiIzNkNTQ2OCIKYmxldWNsYWlyIDwtICIjNWI3Yzk4Igpyb3NlIDwtICIjZmY1NTU1IgpgYGAKCgojIEV4ZW1wbGUgaW50cm9kdWN0aWYgZnLDqXF1ZW50aXN0ZQoKIyMgRG9ubsOpZXMgYmluYWlyZXMKCkxlcyBzdGF0cyBCYXnDqXNpZW5uZXMgcmVwb3NlbnQgc3VyIHVuIHZvY2FidWxhaXJlIHByw6ljaXMsCnF1J29uIHZhIGVzc2F5ZXIgZCdhYm9yZGVyIHBhcyDDoCBwYXMgYXV0b3VyIGQndW4gZXhlbXBsZQptaW5pbWFsaXN0ZS4KCkNldCBleGVtcGxlIGVzdCBsZSBzdWl2YW50IDogaW1hZ2luZXogcXVlIHZvdXMgw6l0dWRpZXogdW4gw6ljaGFudGlsbG9uCmRlICRuJCBwYXRpZW50cywgY2xhc3PDqXMgZW4gInLDqXBvbmRldXIiIG91ICJub24tcsOpcG9uZGV1ciIuCkxhIGRvbm7DqWUgb2JzZXJ2w6llIGVzdCBkb25jIHRyw6hzIHNpbXBsZSA6IGlsIHMnYWdpdCBkZSAkbl9yJCwKbGUgbm9tYnJlIGRlIHBhdGllbnRzIHLDqXBvbmRldXJzLgoKT24gZml4ZSBsYSB2YWxldXIgZGUgJG4kIGV0IGxlIG5vbWJyZSBvYnNlcnbDqSAkbl9yJCBkZSBwYXRpZW50cwpyw6lwb25kZXVycyDDoCBsJ2lzc3VlIGRlIGwnw6l0dWRlLCBwb3VyIHRvdXQgbGUgZG9jdW1lbnQuCgpgYGB7cn0KbiA8LSAxMjAKbl9yIDwtIDkwCmBgYAoKIyMgTW9kw6hsZSBmcsOpcXVlbnRpc3RlIGV0IHZyYWlzZW1ibGFuY2UKClNpIHZvdXMgcGVuc2V6IGNvbW1lIHVuIGZyw6lxdWVudGlzdGUsIHZvdXMgY3LDqWV6IHByb2JhYmxlbWVudCBkYW5zIHZvdHJlIGVzcHJpdApsZSBtb2TDqGxlIHN1aXZhbnQgOiBpbCBleGlzdGUgdW5lIHByb2JhYmlsaXTDqSAkcCQgZml4w6llIGQnw6p0cmUgcsOpcG9uZGV1ciwKZXQgdW5lIHByb2JhYmlsaXTDqSAkMS1wJCBkJ8OqdHJlIG5vbi1yw6lwb25kZXVyLgoKQ2hhcXVlIGluZGl2aWR1IGVzdCBpbmTDqXBlbmRhbnQgZGUgdG91cyBsZXMgYXV0cmVzLApldCBsZSBub21icmUgJE5fciQgZGUgcsOpcG9uZGV1ciBzdWl0IGRvbmMgdW5lIGxvaSBiaW5vbWlhbGUgOgoKJCQKTl9yIFxzaW0gXG1hdGhjYWx7Qn0obiwgcCkKJCQKClNpIHZvdXMgZml4ZXogJHAkLCB2b3VzIMOqdGVzIGNhcGFibGUgZGUgZmFpcmUgZGVzIHNpbXVsYXRpb25zCnNvdXMgdm90cmUgbW9kw6hsZSBldCBkZSByZXByw6lzZW50ZXIgbGEgZGlzdHJpYnV0aW9uIGF0dGVuZHVlCnBvdXIgdm9zIGRvbm7DqWVzLiBMYSBmaWd1cmUgc3VpdmFudGUgbm91cyBpbGx1c3RyZSDDp2Egc2kgJHAgPSAwLjYkLgoKYGBge3J9CnAgPC0gMC42CmQgPC0gdGliYmxlKHggPSAwOm4pICU+JQoJbXV0YXRlKGRlbnNpdHkgPSBkYmlub20oeCwgc2l6ZT1uLCBwcm9iPXApKQpkICU+JSBnZ3Bsb3QoYWVzKHggPSB4LCB5ID0gZGVuc2l0eSkpICsKCWdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgZmlsbD1ibGV1Y2xhaXIpICsKCWdlb21fdmxpbmUoeGludGVyY2VwdCA9IG5fciwgY29sPXJvc2UpICsKCXhsYWIoIk5vbWJyZSBkZSByw6lwb25kZXVycyIpICsKCXlsYWIoIlByb2JhYmlsaXTDqSBzaSBwIHZhdXQgMC42IikgKwoJdGhlbWVfYncoKQpgYGAKYGBge3IgZWNobz1GfQojIGVucmVnaXN0cmVtZW50IGRlIGxhIGZpZ3VyZSBwb3VyIHVzYWdlIGRhbnMgbGEgcHLDqXNlbnRhdGlvbiBhc3NvY2nDqWUKZ2dzYXZlKCJvdXQvYmF5ZXNpZW5fZnJlcXVlbnRpc3RlX3ZyYWlzZW1ibGFuY2UucGRmIiwgd2lkdGg9MTAsIGhlaWdodD01KQpgYGAKCiMjIEVzdGltYXRpb24gZW4gZnLDqXF1ZW50aXN0ZQoKU2kgdm90cmUgcHJvYmzDqG1lIGVzdCB1biBwcm9ibMOobWUgZCdlc3RpbWF0aW9uIGR1IHBhcmFtw6h0cmUgJHAkLAp2b3VzIGFsbGV6IHR5cGlxdWVtZW50IGNoZXJjaGVyIGxlIHBhcmFtw6h0cmUgJFxoYXR7cH0kIG1heGltaXNhbnQKbGEgdnJhaXNlbWJsYW5jZSwgYydlc3Qgw6AgZGlyZSA6CgokJApcaGF0e3B9ID0gXHRleHR7YXJnbWF4fV9wIH5cbWF0aGJie1B9KCBOX3IgPSBuX3IgfCBwICkKJCQKCkRhbnMgY2UgY2FzIHRyw6hzIHByw6ljaXMsIG9uIHBvdXJyYWl0IG1vbnRyZXIgcXVlIMOnYSBkb25uZQpleGFjdGVtZW50IGwnZXN0aW1hdGlvbiBxdSdvbiBhdXJhaXQgZXUgZW52aWUgZGUgZmFpcmUKaW50dWl0aXZlbWVudCA6ICRcaGF0e3B9ID0gTl9yIC8gbiQgY2UgcXVpIGRvbm5lLApkYW5zIGNldCBleGVtcGxlLCB1bmUgZXN0aW1hdGlvbiBwb25jdHVlbGxlIMOgCmByIHJvdW5kKG5fci9uLCAyKWAuClZpc3VlbGxlbWVudCwgb24gYSBkb25jIGNob2lzaSAkcCQgdGVsIHF1ZSBsYSB2cmFpc2VtYmxhbmNlCnJlc3NlbWJsZSDDoCDDp2EgOgoKYGBge3J9CnAgPC0gcm91bmQobl9yL24sMikKZCA8LSB0aWJibGUoeCA9IDA6bikgJT4lCgltdXRhdGUoZGVuc2l0eSA9IGRiaW5vbSh4LCBzaXplPW4sIHByb2I9cCkpCmQgJT4lIGdncGxvdChhZXMoeCA9IHgsIHkgPSBkZW5zaXR5KSkgKwoJZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBmaWxsPWJsZXVjbGFpcikgKwoJZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbl9yLCBjb2w9cm9zZSkgKwoJeGxhYigiTm9tYnJlIGRlIHLDqXBvbmRldXJzIikgKwoJeWxhYihwYXN0ZSgiUHJvYmFiaWxpdMOpIHNpIHAgdmF1dCAiLCBwLCBzZXA9IiIpKSArCgl0aGVtZV9idygpCmBgYApgYGB7ciBlY2hvPUZ9CiMgZW5yZWdpc3RyZW1lbnQgZGUgbGEgZmlndXJlIHBvdXIgdXNhZ2UgZGFucyBsYSBwcsOpc2VudGF0aW9uIGFzc29jacOpZQpnZ3NhdmUoIm91dC9iYXllc2llbl9mcmVxdWVudGlzdGVfdnJhaXNlbWJsYW5jZV9tYXgucGRmIiwgd2lkdGg9MTAsIGhlaWdodD01KQpgYGAKCkRhbnMgdW4gcHJvYmzDqG1lIGQnZXN0aW1hdGlvbiBjbGFzc2lxdWUsIG9uIGFpbWVyYWl0CmVuIHBsdXMgb2J0ZW5pciB1biBpbnRlcnZhbGxlIGRlIGNvbmZpYW5jZSBwb3VyICRwJCwKYydlc3Qgw6AgZGlyZSBkZXV4IHZhcmlhYmxlcyBhbMOpYXRvaXJlcyAkXGhhdHthfSQgZXQgJFxoYXR7Yn0kIHbDqXJpZmlhbnQgOgoKJCQKXG1hdGhiYntQfShwIFxpbiAoXGhhdHthfSxcaGF0e2J9KSkgXGdlcSA5NVwlCiQkCgpOb3RvbnMgcXVlIGNlIHR5cGUgZGUgcsOpc3VsdGF0IG1hdGjDqW1hdGlxdWUgbidlc3QgcGFzIGVuIHNvaQpzaSBmYWNpbGUgw6AgY29tcHJlbmRyZS4gSWNpLCBjZSBzb250IGxlcyBib3JuZXMgZGUgbCdpbnRlcnZhbGxlCnF1aSBzb250IGRlcyB2YXJpYWJsZXMgYWzDqWF0b2lyZXMuCkNlbGxlcyBxdWkgc2Vyb250IGZpbmFsZW1lbnQgY2FsY3Vsw6llcyBuZSBzZXJvdCBwbHVzIGxlcyBlc3RpbWF0ZXVycyAoYWzDqWF0b2lyZXMpLAptYWlzIGxldXJzIGVzdGltYXRpb25zLgpMYSBzZXVsZSBnYXJhbnRpZSBkb25uw6llIHBhciBjZSByw6lzdWx0YXQsIGMnZXN0IHF1ZSBzaSBvbiByw6lww6l0YWl0CmwnZXhww6lyaWVuY2UgdW4gZ3JhbmQgbm9tYnJlIGRlIGZvaXMsIDk1JSBkZXMgaW50ZXJ2YWxsZXMgcXUnb24KZG9ubmVyYWl0IGNvbnRpZW5kcmFpdCBsYSB2cmFpZSB2YWxldXIgZGUgJHAkLgoKQydlc3QgZGUgcGx1cyAoZW4gZ8OpbsOpcmFsKSB1biBwcm9ibMOobWUgZGlmZmljaWxlICEKTcOqbWUgcG91ciBjZSBjYXMgdHLDqHMgc2ltcGxlLCDDp2EgbsOpY2Vzc2l0ZSBkZSByZXBvc2VyCnN1ciBkZXMgdGjDqW9yw6htZXMgYXN5bXB0b3RpcXVlcywgZXQgZGUgcHJvZHVpcmUgZGVzICJiZWF1eCIKcsOpc3VsdGF0cyBkZSBtYXRocy4KClBvdXIgdG91cyBsZXMgbW9kw6hsZXMgcmVsYXRpdmVtZW50IHNpbXBsZXMgLyBjbGFzc2lxdWVzLAp0b3V0IMOnYSBhIGTDqWrDoCDDqXTDqSBmYWl0IHBvdXIgbm91cywgZXQgaWwgbmUgbm91cwpyZXN0ZSBxdSfDoCBmYWlyZSBjb25maWFuY2UgYXV4IG91dGlscyBpbXBsw6ltZW50w6lzCnBvdXIgb2J0ZW5pciBsJ2VzdGltYXRpb24gZGUgbm90cmUgaW50ZXJ2YWxsZSA6CgpgYGB7cn0KY2kgPC0gcHJvcC50ZXN0KHg9bl9yLCBuPW4pJGNvbmYuaW50CmBgYAoKPiBJY2kgbCdpbnRlcnZhbGxlIGRlIGNvbmZpYW5jZSDDoCA5NSUgZW5nbG9iZSBsZXMgdmFsZXVycyAKW2ByIHJvdW5kKGNpWzFdLCAyKWAsIGByIHJvdW5kKGNpWzJdLDIpYF0uCgoKCiMgTW9kw6hsZSBpbnRyb2R1Y3RpZiB2ZXJzaW9uIEJhecOpc2llbgoKIyMgVnJhaXNlbWJsYW5jZSBpZGVudGlxdWUKClNpIHZvdXMgcGVuc2V6IGNvbW1lIHVuIEJhecOpc2llbiwgdm91cyBjb21tZW5jZXogcGFyIHZvdXMgZGlyZQpsYSBtw6ptZSBjaG9zZSBxdWUgcHLDqWPDqWRlbW1lbnQgOiBzaSB2b3VzIGNvbm5haXNzaWV6ICRwJCwKbGEgcHJvYmFiaWxpdMOpIGQnw6p0cmUgcsOpcG9uZGV1ciwgYWxvcnMgdm91cyBzYXVyaWV6CnF1ZSBsZSBub21icmUgZGUgcsOpcG9uZGV1ciBlc3QgOgoKJCQKTl9yIHwgcCB+fiBcc2ltIH5+IFxtYXRoY2Fse0J9KG4sIHApCiQkCgpMYSBsb2kgZGUgJE5fciQgKGxlcyBkb25uw6llcykgc2FjaGFudCAkcCQgKGxlIHBhcmFtw6h0cmUpCmVzdCBhcHBlbMOpZSAqdnJhaXNlbWJsYW5jZSogZXQgZXN0IG5vdMOpZSAkXG1hdGhiYntQfShOX3IgfCBwKSQuCgojIyBDaG9peCBkJ3VuIHByaW9yCgpTZXVsZW1lbnQgdm9pbMOgIDogbGUgcmFpc29ubmVtZW50IEJhecOpc2llbiBzdXBwb3NlIHF1J2lsCm4neSBhIHBhcyB1bmUgdW5pcXVlIHZhbGV1ciBkZSAkcCQsIG1haXMgcXUnaWwgeSBhIGVuIGZhaXQKdW5lIGRpc3RyaWJ1dGlvbiBkZSBwcm9iYWJpbGl0w6kgc3VyIGxlIHBhcmFtw6h0cmUgbHVpLW3Dqm1lICEKQydlc3QgY2UgcXUnb24gYXBwZWxsZSAqcHJpb3IqIDogJFxtYXRoYmJ7UH0ocCkkLgoKUHVpc3F1ZSAkcCQgdml0IGRhbnMgKDAsMSksIGlsIGZhdXQgbCfDqXF1aXBlciBkJ3VuZSBsb2kKZGUgcHJvYmFiaWxpdMOpIHN1ciAoMCwxKSwgcGFyIGV4ZW1wbGUgdW5lIGxvaSB1bmlmb3JtZS4KCmBgYHtyfQp0aWJibGUoeCA9IHNlcSgtMC4xLCAxLjEsIDAuMDAxKSkgJT4lCgltdXRhdGUoeSA9IGR1bmlmKHgpKSAlPiUKCWdncGxvdChhZXMoeD14LCB5PXkpKSArCglnZW9tX2xpbmUoY29sID0gYmxldWNsYWlyKSArCgl4bGFiKCJWYWxldXIgZGUgcCIpICsKCXlsYWIoImRlbnNpdMOpIikgKwoJdGhlbWVfYncoKQpgYGAKYGBge3IgZWNobz1GfQojIGVucmVnaXN0cmVtZW50IGRlIGxhIGZpZ3VyZSBwb3VyIHVzYWdlIGRhbnMgbGEgcHLDqXNlbnRhdGlvbiBhc3NvY2nDqWUKZ2dzYXZlKCJvdXQvYmF5ZXNpZW5fZnJlcXVlbnRpc3RlX3ByaW9yX3VuaWYucGRmIiwgd2lkdGg9MTAsIGhlaWdodD01KQpgYGAKCiMjIE1hcmdpbmFsZSBkZXMgb2JzZXJ2YXRpb25zCgpEYW5zIHVuIG1vbmRlIEJhecOpc2llbiwgY2Ugbidlc3QgcXVlIG1haW50ZW5hbnQgcXUnb24gYQpjaG9pc2kgdW5lIHZyYWlzZW1ibGFuY2UgZXQgdW4gcHJpb3IgcXUnb24gcGV1dCBzaW11bGVyCnVuZSByw6lhbGlzYXRpb24gZGUgJE5fciQgc291cyBub3RyZSBtb2TDqGxlLgpPbiBzaW11bGUgdW5lIHLDqWFsaXNhdGlvbiBkZSAkcCQgdGlyw6kgZGFucyBsZSBwcmlvciwKcHVpcyB1bmUgcsOpYWxpc2F0aW9uIGRlIGxvaSBiaW5vbWlhbGUgYXlhbnQgY2V0dGUgdmFsZXVyIGRlICRwJCA6CgpgYGB7cn0KcF9zaW11ID0gcnVuaWYoMSwgbWluPTAsIG1heD0xKQpuX3Jfc2ltdSA9IHJiaW5vbSgxLCBzaXplPW4sIHByb2I9cF9zaW11KQpgYGAKCkNhIHJldmllbnQgw6AgdGlyZXIgdW5lIHZhbGV1ciBkYW5zIGxhIGxvaSBkZSAkTl9yJCwKcXUnb24gYXBwZWxsZSAqbG9pIG1hcmdpbmFsZSogZGVzIG9ic2VydmF0aW9ucy4KQ2V0dGUgbG9pIHBldXQgcydleHByaW1lciBjb21tZSA6CgokJApcbWF0aGJie1B9KE5fcikgPSBcaW50XzBeMSBcbWF0aGJie1B9KE5fciB8IHApIFxtYXRoYmJ7UH0ocCBcaW4gZHApIGRwCiQkCgpJbCBlc3QgdHLDqHMgZmFjaWxlIGRlIHNpbXVsZXIgZGFucyBjZXR0ZSBsb2ksIAptYWlzIGVsbGUgbidlc3QgcGFzIHRvdWpvdXJzIGZhY2lsZSDDoCBjYXJhY3TDqXJpc2VyIHBsdXMgZmluZW1lbnQuCkRhbnMgbm90cmUgc2PDqW5hcmlvLCBvbiBwZXV0IHRvdWpvdXJzIHJlcHLDqXNlbnRlcgpsJ2FsbHVyZSBkZSBsYSBkaXN0cmlidXRpb24gb2J0ZW51ZSBwYXIgc2ltdWxhdGlvbiA6CgoxLiBvbiBzaW11bGUgdW5lIHZhbGV1ciBkZSAkcCQgZGFucyBsZSBwcmlvciBkZSAkcCQsCjIuIG9uIHNpbXVsZSB1bmUgdmFsZXVyIGRlICROX3IkIGRhbnMgbGEgZGlzdHJpYnV0aW9uIGRlICROX3IkIHNhY2hhbnQKICAgcXVlICRwJCBlc3QgZml4w6kgw6AgbGEgdmFsZXVyIHNpbXVsw6llIMOgIGxhIHByZW1pw6hyZSDDqXRhcGUuCgpgYGB7ciBtYXJnaW5hbGVfb2JzXzEsIGNhY2hlPVR9CnNpbV9uX3IgPC0gZnVuY3Rpb24obiwgc2FtcGxlX3NpemUpewoJcF9zaW11ID0gcnVuaWYoc2FtcGxlX3NpemUsIG1pbj0wLCBtYXg9MSkKCXJldHVybiAocmJpbm9tKHNhbXBsZV9zaXplLCBzaXplPW4sIHByb2I9cF9zaW11KSkKfQp0aWJibGUoeCA9IHNpbV9uX3IobiwgMWU1KSkgJT4lIAoJZ3JvdXBfYnkoeCkgJT4lCglzdW1tYXJpemUobiA9IG4oKS8xZTUpICU+JQoJZ2dwbG90KGFlcyh4ID0geCwgeSA9IG4pKSArCglnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIGZpbGw9YmxldWNsYWlyKSArCgl0aGVtZV9idygpICsKCXhsYWIoIk5vbWJyZSBkZSByw6lwb25kZXVycyIpICsKCXlsYWIoIlByb2JhYmlsaXTDqSIpCmBgYApgYGB7ciBlY2hvPUZ9CiMgZW5yZWdpc3RyZW1lbnQgZGUgbGEgZmlndXJlIHBvdXIgdXNhZ2UgZGFucyBsYSBwcsOpc2VudGF0aW9uIGFzc29jacOpZQpnZ3NhdmUoIm91dC9iYXllc2llbl9mcmVxdWVudGlzdGVfcHJpb3JfdW5pZl9tYXJnaW5hbGUucGRmIiwgd2lkdGg9MTAsIGhlaWdodD01KQpgYGAKCgojIyBQb3N0ZXJpb3IKCkMnZXN0IExBIHF1YW50aXTDqSBkJ2ludMOpcsOqdCBwb3VyIGxlIHN0YXRpc3RpY2llbiAhCkRhbnMgbGEgcsOpYWxpdMOpLCBvbiBhIG9ic2VydsOpIFVORSB2YWxldXIgJG5fciQuCk9uIGNoZXJjaGUgZG9uYyA6CgokJApcbWF0aGJie1B9KHAgfCBOX3IgPSBuX3IpID0gXGZyYWN7IFxtYXRoYmJ7UH0oTl9yID0gbl9yIHwgcCkgXG1hdGhiYntQfShwKSB9eyBcbWF0aGJie1B9KE5fciA9IG5fcikgfQokJAoKPiBPbiBvYnRpZW50IGxlIHBvc3RlcmlvciBlbiBjb21iaW5hbnQgbCdpZMOpZSBxdSdvbiBhdmFpdCBhIHByaW9yaQpzdXIgJHAkIChsZSBwcmlvcikgYXZlYyBjZSBxdSdvbiBhcHByZW5kIGRlIG5vdHJlIGV4cMOpcmllbmNlIChsYSB2cmFpc2VtYmxhbmNlKS4KCkonaW5zaXN0ZSDDqWdhbGVtZW50IHVuZSBub3V2ZWxsZSBmb2lzIHN1ciBjZSBjaGFuZ2VtZW50IGRlIHBhcmFkaWdtZSBtYWpldXIgOgpvbiBjaGVyY2hlIHVuZSBkaXN0cmlidXRpb24gZGUgcHJvYmFiaWxpdMOpIHN1ciAkcCQsCmV0IG9uIGFycsOqdGUgZGUgcGVuc2VyIHF1J2lsIHkgYSB1bmUgdmFsZXVyIHVuaXF1ZSBkZSAkcCQuCgpQbHVzaWV1cnMgcG9zc2liaWxpdMOpcyBwZXV2ZW50IHNlIHByw6lzZW50ZXIgcG91ciBsZSBjYWxjdWwgZHUgcG9zdGVyaW9yLgpNYWlzIHRvdXRlcyB1dGlsaXNlbnQgZMOpasOgIHVuZSByw6hnbGUgY29tbXVuZSA6Cm9uIHZhIGZhaXJlIGFic3RyYWN0aW9uIGR1IGTDqW5vbWluYXRldXIgKGxhIG1hcmdpbmFsZSBkZSAkTl9yJCkKcXVpIMOpdGFpdCBww6luaWJsZSDDoCBjYWxjdWxlciBldCBxdWkgbmUgc2VydCBpY2kgcXVlIGRlIGZhY3RldXIKZGUgbm9ybWFsaXNhdGlvbi4KT24gY29tbWVuY2UgZG9uYyB0b3Vqb3VycyBwYXIgcsOpLcOpY3JpcmUgbCfDqXF1YXRpb24gcHLDqWPDqWRlbnRlIGNvbW1lIDoKCiQkClxtYXRoYmJ7UH0ocCB8IE5fciA9IG5fcikgXHByb3B0byBcbWF0aGJie1B9KE5fciA9IG5fciB8IHApIFxtYXRoYmJ7UH0ocCkKJCQKClB1aXMsIGRhbnMgY2UgY2FzIHByw6ljaXMsIHRvdXQgZXN0IHRyw6hzIHNpbXBsZSBjYXIgbGUgcHJpb3IgZGUgJHAkIGVzdCB1bmlmb3JtZSwKY2UgcXVpIGZhaXQgcXUnb24gcGV1dCByw6ktw6ljcmlyZSBub3RyZSDDqXF1YXRpb24gY29tbWUgOgoKXGJlZ2lue2FsaWduKn0KXG1hdGhiYntQfShwIHwgTl9yID0gbl9yKSAKJlxwcm9wdG8gXGJpbm9tezkwfXsxMjB9IHBeezkwfSAoMS1wKV57MTIwIC0gOTB9IFxcCiZccHJvcHRvIHBeezkwfSAoMS1wKV57MTIwIC0gOTB9ClxlbmR7YWxpZ24qfQoKT8O5IG9uIHJlY29ubmHDrnQgdW5lIGxvaSBCw6p0YSBkZSBwYXJhbcOodHJlcyAkXGFscGhhID0gOTArMSQgZXQgJFxiZXRhID0gMTIwLTkwKzEkLgpMZSBwb3N0ZXJpb3IgYSBsJ2FsbHVyZSBzdWl2YW50ZSA6CgpgYGB7cn0KYWxwaGEgPC0gbl9yICsgMQpiZXRhIDwtIG4gLSBuX3IgKyAxCmRfcG9zdGVyaW9yIDwtIHRpYmJsZSh4ID0gc2VxKDAsIDEsIDAuMDAxKSkgJT4lCgltdXRhdGUoeSA9IGRiZXRhKHgsIHNoYXBlMT1hbHBoYSwgc2hhcGUyPWJldGEpKQpwbG90X3Bvc3RlcmlvciA8LSBkX3Bvc3RlcmlvciAlPiUKCWdncGxvdChhZXMoeD14LCB5PXkpKSArCglnZW9tX2xpbmUoY29sID0gYmxldWNsYWlyKSArCgl4bGFiKCJWYWxldXIgZGUgcCIpICsKCXlsYWIoImRlbnNpdMOpIGR1IHBvc3RlcmlvciIpICsKCXRoZW1lX2J3KCkKcGxvdF9wb3N0ZXJpb3IKYGBgCmBgYHtyIGVjaG89Rn0KIyBlbnJlZ2lzdHJlbWVudCBkZSBsYSBmaWd1cmUgcG91ciB1c2FnZSBkYW5zIGxhIHByw6lzZW50YXRpb24gYXNzb2Npw6llCmdnc2F2ZSgib3V0L2JheWVzaWVuX2ZyZXF1ZW50aXN0ZV9wcmlvcl91bmlmX3Bvc3Rlcmlvci5wZGYiLCB3aWR0aD0xMCwgaGVpZ2h0PTUpCmBgYAoKU2kgb24gc291aGFpdGUgdW4gZXN0aW1hdGV1ciBwb25jdHVlbCwgaWwgZXN0IGQndXNhZ2UgZCd1dGlsaXNlciBsZSBtYXhpbXVtIGEgcG9zdGVyaW9yaSwKYydlc3Qgw6AgZGlyZSBsYSB2YWxldXIgZGUgJHAkIHF1aSBtYXhpbWlzZSBsZSBwb3N0ZXJpb3IuCkljaSwgbGUgY2FsY3VsIG5vdXMgZG9ubmUgZXhhY3RlbWVudCBsYSBtw6ptZSBzb2x1dGlvbiBxdWUgZGFucyBsZSBjYXMgZnLDqXF1ZW50aXN0ZS4KCmBgYHtyfQpwbG90X3Bvc3RlcmlvciArCglnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSA5MC8xMjAsIGNvbD1yb3NlKQpgYGAKYGBge3IgZWNobz1GfQojIGVucmVnaXN0cmVtZW50IGRlIGxhIGZpZ3VyZSBwb3VyIHVzYWdlIGRhbnMgbGEgcHLDqXNlbnRhdGlvbiBhc3NvY2nDqWUKZ2dzYXZlKCJvdXQvYmF5ZXNpZW5fZnJlcXVlbnRpc3RlX3ByaW9yX3VuaWZfbWFwLnBkZiIsIHdpZHRoPTEwLCBoZWlnaHQ9NSkKYGBgCgojIyBJbnRlcnZhbGxlIGRlIGNyw6lkaWJpbGl0w6kKClNpIG9uIGFjY2VwdGUgcXUnaWwgbidleGlzdGUgcGFzIHVuZSB1bmlxdWUgdmFsZXVyIGR1IHBhcmFtw6h0cmUgJHAkLApsJ2ludGVydmFsbGUgKmRlIGNyw6lkaWJpbGl0w6kqIGR1IEJhecOpc2llbiBlc3QgYmVhdWNvdXAgcGx1cyBpbnR1aXRpZiBxdWUgCmwnaW50ZXJ2YWxsZSAqZGUgY29uZmlhbmNlKiBkdSBmcsOpcXVlbnRpc3RlLgoKSWwgcydhZ2l0IGVuIGVmZmV0IGQndW4gaW50ZXJ2YWxsZSAkKGEsYikkIHRlbCBxdWUgOgoKJCQKXG1hdGhiYntQfShwIFxpbiAoYSxiKSB8IE5fciA9IDkwKSBcZ2VxIDEtXGFscGhhCiQkCgpUeXBpcXVlbWVudCwgc2kgb24gc291aGFpdGFpdCBhdm9pciB1biBpbnRlcnZhbGxlIGRlIGNyw6lkaWJpbGl0w6kgw6AgOTUlLApvbiBwcmVuZHJhaXQgbGVzIHZhbGV1cnMsIHN1ciBsZSBzdXBwb3J0IGR1IHBvc3RlcmlvciwgY29udGVudWVzCmVudHJlIGxlcyBxdWFudGlsZXMgZGUgbml2ZWF1IDAuMDI1IGV0IDAuOTc1LgoKYGBge3J9CmxvdyA8LSBxYmV0YSgwLjAyNSwgc2hhcGUxPWFscGhhLCBzaGFwZTI9YmV0YSkKdXAgPC0gcWJldGEoMC45NzUsIHNoYXBlMT1hbHBoYSwgc2hhcGUyPWJldGEpCnBsb3RfcG9zdGVyaW9yICsKCWdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMobG93LCB1cCksIGNvbD1yb3NlKQpgYGAKYGBge3IgZWNobz1GfQojIGVucmVnaXN0cmVtZW50IGRlIGxhIGZpZ3VyZSBwb3VyIHVzYWdlIGRhbnMgbGEgcHLDqXNlbnRhdGlvbiBhc3NvY2nDqWUKZ2dzYXZlKCJvdXQvYmF5ZXNpZW5fZnJlcXVlbnRpc3RlX3ByaW9yX3VuaWZfY2kucGRmIiwgd2lkdGg9MTAsIGhlaWdodD01KQpgYGAKCj4gSWNpLCBsJ2ludGVydmFsbGUgZGUgY3LDqWRpYmlsaXTDqSDDoCA5NSUgZXN0IFtgciByb3VuZChsb3csMilgLCBgciByb3VuZCh1cCwyKWBdLgoKIyMgVGVzdCBkJ2h5cG90aMOoc2UKCkVuZmluLCBsZXMgdGVzdHMgZCdoeXBvdGjDqHNlIHNvbnQgcsOpYWxpc8OpcyBkZSBmYcOnb24gYmllbiBwbHVzIGludHVpdGl2ZQpxdWUgZGFucyBsZSBjYXMgZnLDqXF1ZW50aXN0ZS4KCjEuIG9uIGNhbGN1bGUgbGEgcHJvYmFiaWxpdMOpIGEgcG9zdGVyaW9yaSBkZSBjaGFxdWUgaHlwb3Row6hzZSwKMi4gb24gYmFzZSBsZSBjaG9peCBzdXIgY2VzIGRldXggcHJvYmFiaWxpdMOpcy4KClBhciBleGVtcGxlLCBzaSBvbiBzb3VoYWl0ZSBkw6ljaWRlciBlbnRyZSA6CgoqIEgwIDogJHAgXGxlcSAwLjckCiogSDEgOiAkcCA+IDAuNyQsCgpBbG9ycyBpbCBub3VzIHN1ZmZpdCBkZSBzJ2FjY29yZGVyIHN1ciB1biB0aHJlc2hvbGQgZGUgcHJvYmFiaWxpdMOpIGEgcG9zdGVyaW9yaQrDoCBwYXJ0aXIgZHVxdWVsIG9uIGNob2lzaXQgSDEsIGV0IGRlIGNhbGN1bGVyIG5vcyBwcm9iYWJpbGl0w6lzLgpWaXN1ZWxsZW1lbnQsIG9uIHNlIGJhc2UgZG9uYyBzdXIgOgoKYGBge3J9CnBsb3RfcG9zdGVyaW9yICsKCWdlb21fYXJlYShkYXRhID0gZF9wb3N0ZXJpb3IgJT4lIGZpbHRlcih4IDw9IDAuNyksIGZpbGw9cm9zZSwgYWxwaGE9MC41KQpgYGAKYGBge3IgZWNobz1GfQojIGVucmVnaXN0cmVtZW50IGRlIGxhIGZpZ3VyZSBwb3VyIHVzYWdlIGRhbnMgbGEgcHLDqXNlbnRhdGlvbiBhc3NvY2nDqWUKZ2dzYXZlKCJvdXQvYmF5ZXNpZW5fZnJlcXVlbnRpc3RlX3ByaW9yX3VuaWZfdGVzdC5wZGYiLCB3aWR0aD0xMCwgaGVpZ2h0PTUpCmBgYAoKCiMgTGVzIE1DTUNzLCBsYSBjdWlzaW5lIGR1IEJhecOpc2llbgoKVG91dCBjZSBxdSdvbiBhIGVmZmVjdHXDqSBjaS1kZXNzdXMgw6l0YWl0IHLDqWFsaXPDqSBkYW5zIHVuIGNhcyBzaW1wbGUgaWTDqWFsaXPDqQpwb3VyIGxlcXVlbCBvbiBhcnJpdmFpdCDDoCBmYWlyZSBkZXMgY2FsY3VscyAob3UgcGx1dMO0dCwgcmFpc29ubmVyIHF1YXNpIHNhbnMgY2FsY3VscykgdHLDqHMgZmFjaWxlbWVudC4KQ2Ugbidlc3QgbWFsaGV1cmV1c2VtZW50IHBhcyBsYSBtYWpvcml0w6kgZGVzIGNhcy4KCiMjIFVuIHByaW9yIHBsdXMgY29tcGxleGUKCkRhbnMgYmVhdWNvdXAgZGUgc2l0dWF0aW9ucywgbGUgcHJpb3Igbidlc3QgcGFzIGF1c3NpIHNpbXBsZSwgZXQgbGUgcG9zdGVyaW9yIGVzdCBkb25jIHBsdXMgZGlmZmljaWxlCsOgIGNhcmFjdMOpcmlzZXIuCk1vZGlmaW9ucyBub3RyZSBleGVtcGxlIHByw6ljw6lkZW50IDogcGx1dMO0dCBxdWUgZCdhdm9pciAkcCQgdW5pZm9ybWUgc3VyIFswLDFdLApkZXMgZG9ubsOpZXMgcHLDqWxpbWluYWlyZXMgaXNzdWVzIGRlIGxhIGxpdHTDqXJhdHVyZSwgb3UgZGVzIGF2aXMgZCdleHBlcnRzIGR1IGRvbWFpbmUsIApzdWdnw6hyZW50IHF1ZSAkcCQgc2VyYWl0IGNlbnRyw6kgc3VyIGxhIHZhbGV1ciAwLjYsCmF2ZWMgdW4gw6ljYXJ0LXR5cGUgZGUgMC4zLgoKU2FucyB0cm9wIHLDqWZsw6ljaGlyLCBvbiBzZSBwcm9wb3NlIGRvbmMgZGUgdm9pciBjZSBxdWUgw6dhIGRvbm5lcmFpdCBhdmVjIGxlIHByaW9yIHN1aXZhbnQgOgp1bmUgbG9pIG5vcm1hbGUgZGUgbW95ZW5uZSAwLjYgZXQgw6ljYXJ0LXR5cGUgMC4zLgpTZXVsZW1lbnQgdm9pbMOgLCBsYSBjdWlzaW5lIGNvbW1lbmNlIDogbGEgbG9pIG5vcm1hbGUgZXN0IGTDqWZpbmllIHN1ciAkXG1hdGhiYntSfSQuClF1J8OgIGNlbGEgbmUgdGllbm5lIDogY29uc2lkw6lyb25zIHF1J29uIHRyb25xdWUgY2V0dGUgZGlzdHJpYnV0aW9uIHBvdXIgcXUnZWxsZSBhaXQKdW4gc3VwcG9ydCBzdXIgWzAsMV0uCgpgYGB7ciBmaWcud2lkdGg9MTB9Cm11IDwtIDAuNgpzZCA8LSAwLjMKd2VpZ2h0X2luZl8wIDwtIHBub3JtKDAsIG1lYW49bXUsIHNkPXNkKQp3ZWlnaHRfc3VwXzEgPC0gMSAtIHBub3JtKDEsIG1lYW49bXUsIHNkPXNkKQp0aWJibGUoeCA9IHNlcSgwLCAxLCAwLjAwMSkpICU+JQoJbXV0YXRlKHkgPSBkbm9ybSh4LCBtZWFuPW11LCBzZD1zZCkvKDEgLSB3ZWlnaHRfaW5mXzAgLSB3ZWlnaHRfc3VwXzEpKSAlPiUKCWdncGxvdChhZXMoeD14LCB5PXkpKSArCglnZW9tX2xpbmUoY29sID0gYmxldWNsYWlyKSArCgl4bGFiKCJWYWxldXIgZGUgcCIpICsKCXlsYWIoImRlbnNpdMOpIGR1IHByaW9yIikgKwoJdGhlbWVfYncoKQpgYGAKYGBge3IgZWNobz1GfQojIGVucmVnaXN0cmVtZW50IGRlIGxhIGZpZ3VyZSBwb3VyIHVzYWdlIGRhbnMgbGEgcHLDqXNlbnRhdGlvbiBhc3NvY2nDqWUKZ2dzYXZlKCJvdXQvYmF5ZXNpZW5fZnJlcXVlbnRpc3RlX3ByaW9yX2luYWRlcXVhdC5wZGYiLCB3aWR0aD0xMCwgaGVpZ2h0PTUpCmBgYAoKIyMgTGEgbWFyZ2luYWxlIGRlcyBvYnNlcnZhdGlvbnMKCkNvbW1lIHByw6ljw6lkZW1tZW50LCBpbCBuJ2VzdCBwYXMgw6l2aWRlbnQgZGUgY2FyYWN0w6lyaXNlciBsYSBsb2kgZGUgJE5fciQsCm1haXMgb24gcGV1dCBsJ2FwcHJvY2hlciBwYXIgc2ltdWxhdGlvbnMgOgoKYGBge3IgbWFyZ2luYWxlX29ic18yLCBjYWNoZT1UfQpzaW1fbl9yIDwtIGZ1bmN0aW9uKG4sIHNhbXBsZV9zaXplKXsKCXJlcyA8LSBjKCkKCWZvciAoaSBpbiAxOnNhbXBsZV9zaXplKXsKCQlwX3NpbXUgPSBybm9ybSgxLCBtZWFuPW11LCBzZD1zZCkKCQl3aGlsZSAocF9zaW11IDwgMCB8IHBfc2ltdSA+IDEpewoJCQlwX3NpbXUgPSBybm9ybSgxLCBtZWFuPW11LCBzZD1zZCkKCQl9CgkJbl9yX3NpbXUgPC0gcmJpbm9tKDEsIHNpemU9biwgcHJvYj1wX3NpbXUpCgkJcmVzIDwtIGMocmVzLCBuX3Jfc2ltdSkKCX0KCXJldHVybiAocmVzKQp9CnRpYmJsZSh4ID0gc2ltX25fcihuLCAxZTUpKSAlPiUgCglncm91cF9ieSh4KSAlPiUKCXN1bW1hcml6ZShuID0gbigpLzFlNSkgJT4lCglnZ3Bsb3QoYWVzKHggPSB4LCB5ID0gbikpICsKCWdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgZmlsbD1ibGV1Y2xhaXIpICsKCXRoZW1lX2J3KCkgKwoJeGxhYigiTm9tYnJlIGRlIHLDqXBvbmRldXJzIikgKwoJeWxhYigiUHJvYmFiaWxpdMOpIikKYGBgCmBgYHtyIGVjaG89Rn0KIyBlbnJlZ2lzdHJlbWVudCBkZSBsYSBmaWd1cmUgcG91ciB1c2FnZSBkYW5zIGxhIHByw6lzZW50YXRpb24gYXNzb2Npw6llCmdnc2F2ZSgib3V0L2JheWVzaWVuX2ZyZXF1ZW50aXN0ZV9wcmlvcl9pbmFkZXF1YXRfbWFyZ2luYWxlLnBkZiIsIHdpZHRoPTEwLCBoZWlnaHQ9NSkKYGBgCgojIyBMZSBwb3N0ZXJpb3IKCkNvbW1lIHByw6ljw6lkZW1tZW50LCBvbiBwZXV0IMOpY3JpcmUgbGEgcsOoZ2xlIGRlIHByb3BvcnRpb25uYWxpdMOpIGRlIGJhc2Ugc3VpdmFudGUgOgoKJCQKXG1hdGhiYntQfShwIHwgTl9yID0gbl9yKSBccHJvcHRvIFxtYXRoYmJ7UH0oTl9yID0gbl9yIHwgcCkgXG1hdGhiYntQfShwKQokJAoKUHVpcywgZW4gcmVtcGxhw6dhbnQgYXZlYyBjZSBxdSdvbiBjb25uYcOudCBkZSBsYSB2cmFpc2VtYmxhbmNlIGV0IGR1IHByaW9yIDoKClxiZWdpbnthbGlnbip9ClxtYXRoYmJ7UH0ocCB8IE5fciA9IG5fcikgCiY9IDAgfn5+XHRleHR7IHNpIH0gcCBcbm90aW4gWzAsMV1cXAomXHByb3B0byBwXns5MH0gKDEtcCleezEyMCAtIDkwfSBlXnstXGZyYWN7MX17Mn0gXGxlZnQoIFxmcmFje3AgLSAwLjZ9ezAuM30gXHJpZ2h0KV4yfSB+fn5cdGV4dHsgc2lub24ufQpcZW5ke2FsaWduKn0KCkNldHRlIGZvaXMsIGltcG9zc2libGUgZGUgcmVjb25uYcOudHJlIHF1b2kgcXVlIGNlIHNvaXQgIQpEYW5zIGNlIGNhcyBkZSBmaWd1cmUsIHF1aSBlc3QgZCdhaWxsZXVycyBsYSBub3JtZSBkYW5zIGxlcyBhcHBsaWNhdGlvbnMgZGUgc3RhdHMgQmF5w6lzaWVubmVzLApvbiBkb2l0IHMnYXBwdXllciBzdXIgZGVzIG91dGlscyBkZSBzaW11bGF0aW9ucyBudW3DqXJpcXVlcyBwb3VyIMOpY2hhbnRpbGxvbm5lciBkZXMgdmFsZXVycwpkYW5zIGxlIHBvc3RlcmlvciBzYW5zIGFycml2ZXIgw6AgbGUgY2FyYWN0w6lyaXNlciBwbHVzIGZpbmVtZW50IHF1ZSDDp2EuCgpFdCBsJ291dGlsIGNlbnRyYWwgcG91ciByw6lhbGlzZXIgY2VzIHNpbXVsYXRpb25zIHMnYXBwZWxsZSBsZSAqTUNNQyosIHBvdXIKKk1hcmtvdiBDaGFpbiBNb250ZSBDYXJsbyouCgojIyBQcmluY2lwZSBkJ3VuIE1DTUMKCkwnaWTDqWUgZ8OpbsOpcmFsZSBkZXMgdGVjaG5pcXVlcyBNQ01DIGNvbnNpc3RlIMOgIGNvbnN0cnVpcmUgdW5lICpjaGHDrm5lIGRlIE1hcmtvdiosCnVuZSBzdWl0ZSBkZSB2YXJpYWJsZXMgYWzDqWF0b2lyZXMgYmllbiBwYXJ0aWN1bGnDqHJlLCBxdWkgY29udmVyZ2UgdmVycyBub3RyZSBkaXN0cmlidXRpb24KZCdpbnTDqXLDqnQgOiBsZSBwb3N0ZXJpb3IgcXUnb24gbm90ZSBpY2kgJFxudSQuCgpMYSBmYcOnb24gbGEgcGx1cyBjbGFzc2lxdWUvZmFjaWxlIGRlIGNvbnN0cnVpcmUgdW5lIHRlbGxlIGNoYcOubmUgY29uc2lzdGUgw6AgdXRpbGlzZXIKbCdhbGdvcml0aG1lIGRlICpNZXRyb3BvbGlzLUhhc3RpbmdzKi4KQ2VsdWktY2kgcmVwb3NlIHN1ciBsZSBjaG9peCBhZGhvYyBkJ3VuZSBsb2kgZGUgcHJvcG9zaXRpb24gZGUgbW92ZW1lbnQgJHEkLCBhdmVjCiRcZm9yYWxsIHgseSwgIHEoeCwgeSkkIHF1aSBkb25uZSBsYSBwcm9iYWJpbGl0w6kgZGUgcHJvcG9zZXIgbCfDqXRhdCAkeSQgc2FjaGFudCBxdSdvbgplc3QgZGFucyBsJ8OpdGF0ICR4JC4KCkEgZGV1eC10cm9pcyBjb25kaXRpb25zIHRlY2huaXF1ZXMgcHLDqHMsIGwnYWxnb3JpdGhtZSBjb25zaXN0ZSDDoApwYXNzZXIgZGUgbCfDqXRhdCAkeF9pJCBhdSBwYXMgJGkkLCDDoCAkeF97aSsxfSQgYXUgcGFzICRpKzEkIGVuIDoKCjEuIHByb3Bvc2FudCB1biDDqXRhdCAkeSQgZW4gdGlyYW50IGRhbnMgbGEgbG9pIGRlICRxKHhfaSwuKSQsCjIuIGNhbGN1bGFudCBsYSBxdWFudGl0w6kgc3VpdmFudGUgOgogICAkJAogICByID0gXGZyYWN7XG51KHkpcSh5LHhfaSl9e1xudSh4X2kpcSh4X2kseSl9CiAgICQkCjMuIFNpICRyIFxnZXEgMSQsICR4X3tpKzF9ID0geSQuIFNpbm9uICR4X3tpKzF9ID0geSQgYXZlYyBwcm9iYWJpbGl0w6kgJHIkIGV0ICR4X3tpKzF9ID0geF9pJCBzaW5vbi4KCklsIG5lIHJlc3RlIGVuc3VpdGUgcXUnw6AgOgoKKiBzdXBwcmltZXIgbGVzIHByZW1pw6hyZXMgaXTDqXJhdGlvbnMgZGUgbGEgY2hhw65uZSAocG91ciByw6lkdWlyZSBsYSBkw6lwZW5kYW5jZSBhdXggY29uZGl0aW9ucyBpbml0aWFsZXMpLAoqIMOpY2hhbnRpbGxvbm5lciB1bmUgdmFsZXVyIHN1ciAxMCwgb3Ugc3VyIDEwMCwgb3UgLi4uIChwb3VyIHLDqWR1aXJlIGwnYXV0by1jb3Jyw6lsYXRpb24gZGVzIHZhbGV1cnMpLgoKUG91ciBzZSBwcm91dmVyIHF1ZSBjJ2VzdCB0csOocyBzaW1wbGUgw6AgZGVzaWduZXIsIG9uIHBldXQgZW4gY29uc3RydWlyZSB1bmUgaWNpLgpQYXIgc2ltcGxpY2l0w6ksIHByZW5vbnMgdW5lIHByb3Bvc2l0aW9uIGRlIG1vdXZlbWVudCAkcSQgdHLDqHMgc2ltcGxlIDogbGEgbG9pIHVuaWZvcm1lIHN1ciBbMCwxXSwKcXVlbGxlIHF1ZSBzb2l0IGxhIHZhbGV1ciBkZSBkw6lwYXJ0LgoKYGBge3IgbWNtYywgY2FjaGU9VH0KIyBub3RyZSBkaXN0cmlidXRpb24gY2libGUgKHBvc3RlcmlvcikgZXN0IHByb3BvcnRpb25uZWxsZSDDoCBudQpudSA8LSBmdW5jdGlvbihwKXsKCXJlcyA8LSBwXm5fciAqICgxLXApXihuLW5fcikgKiBleHAoLTAuNSAqICgocCAtIG11KS9zZCleMiApCglyZXR1cm4gKHJlcykKfQoKIyBvbiBpbml0aWFsaXNlIHVuZSBjaGHDrm5lIHZpZGUgcXUnb24gcmVtcGxpdCB1biBwYXMgYXByw6hzIGwnYXV0cmUKIyBhdHRlbnRpb24sIGNlIG1vcmNlYXUgZGUgY29kZSBwZXV0IHByZW5kcmUgdW4gY2VydGFpbiB0ZW1wcyDDoCB0b3VybmVyCmNoYWluIDwtIGMoKQpuc3RlcHMgPC0gMWU1CnAgPC0gMC4yCmZvciAoaSBpbiAxOm5zdGVwcyl7CgljaGFpbiA8LSBjKGNoYWluLCBwKQoJeSA8LSBydW5pZigxLCBtaW49MCwgbWF4PTEpCglyIDwtIG51KHkpIC8gbnUocCkKCWlmIChyID49IDEpewoJCXAgPC0geQoJfWVsc2V7CgkJdSA9IHJ1bmlmKDEsIG1pbj0wLCBtYXg9MSkKCQlpZiAodSA8PSByKXsKCQkJcCA8LSB5CgkJfQoJfQp9CmBgYAoKVG91dCBsJ2FydCBkZSBsYSBjdWlzaW5lIGRlIE1DTUMgKHNhdWNlIE1IKSBjb25zaXN0ZSDDoCBjaG9pc2lyIGVtcGlyaXF1ZW1lbnQgdW5lCnByb3Bvc2l0aW9uIGRlIG1vdXZlbWVudCAkcSQgcXVpICJmb25jdGlvbm5lIiBwbHV0w7R0IGJpZW4uCgpJbCBmYXV0IGF1c3NpIGNob2lzaXIgdW4gcGV1IGF1IHBpZiBjb21iaWVuIGRlIHZhbGV1cnMgb24gc3VwcHJpbWUgYXUgZMOpYnV0IGRlIGxhIGNoYcOubmUgKGJ1cm4taW4pCmV0IGF2ZWMgcXVlbGxlIGZyw6lxdWVuY2Ugb24gw6ljaGFudGlsbG9ubmUuClBvdXIgw6dhLCBvbiBwZXV0IHJlZ2FyZGVyIGwnYWxsdXJlIGRlIGxhIGNoYcOubmUgOgoKYGBge3J9CmRtY21jIDwtIHRpYmJsZShwID0gY2hhaW4sCgkJCQlzdGVwID0gc2VxKDEsIG5zdGVwcykpIApkbWNtYyAlPiUKCWdncGxvdChhZXMoeD1zdGVwLCB5PXApKSArCglnZW9tX2xpbmUoY29sID0gYmxldWZvbmNlKSArCgl0aGVtZV9idygpCmBgYApgYGB7ciBlY2hvPUZ9CiMgZW5yZWdpc3RyZW1lbnQgZGUgbGEgZmlndXJlIHBvdXIgdXNhZ2UgZGFucyBsYSBwcsOpc2VudGF0aW9uIGFzc29jacOpZQpnZ3NhdmUoIm91dC9iYXllc2llbl9mcmVxdWVudGlzdGVfcHJpb3JfaW5hZGVxdWF0X21jbWNfY29udmVyZ2VuY2UucGRmIiwgd2lkdGg9MTAsIGhlaWdodD01KQpgYGAKClN1ciBjZXQgZXhlbXBsZSB0b3V0IHNpbXBsZSwgbGUgYnVybi1pbiBlc3QgZmFjaWxlIMOgIHJlcMOpcmVyIHZpc3VlbGxlbWVudC4KU2kgb24gZW5sw6h2ZSBsZXMgJDEwXjQkIHByZW1pw6hyZXMgdmFsZXVycyBldCBxdSdvbiBjb25zZXJ2ZSB1bmUgdmFsZXVyIHN1ciAxMCwKb24gY29uc2VydmUgYXNzZXogZGUgdmFsZXVycyBwb3VyIGVzdGltZXIgbm90cmUgcG9zdGVyaW9yIMOgIHBhcnRpciBkZSBsJ2hpc3RvZ3JhbW1lCmVtcGlyaXF1ZSBzdWl2YW50IDoKCmBgYHtyfQpkbWNtYyAlPiUKCWZpbHRlcihzdGVwID4gMWU0ICYgc3RlcCAlJSAxMCA9PSAwKSAlPiUKCWdncGxvdChhZXMoeD1wKSkgKwoJZ2VvbV9oaXN0b2dyYW0oYWVzKHk9Li5kZW5zaXR5Li4pLCBiaW5zPTUwLCBjb2w9YmxldWNsYWlyLCBmaWxsPWJsZXVjbGFpciwgYWxwaGE9MC41KSArCglnZW9tX2RlbnNpdHkoY29sPXJvc2UsIGFscGhhPTAuNSkgKwoJeWxhYigiZGVuc2l0w6kgZGUgcHJvYmFiaWxpdMOpIikgKwoJdGhlbWVfYncoKQpgYGAKYGBge3IgZWNobz1GfQojIGVucmVnaXN0cmVtZW50IGRlIGxhIGZpZ3VyZSBwb3VyIHVzYWdlIGRhbnMgbGEgcHLDqXNlbnRhdGlvbiBhc3NvY2nDqWUKZ2dzYXZlKCJvdXQvYmF5ZXNpZW5fZnJlcXVlbnRpc3RlX3ByaW9yX2luYWRlcXVhdF9tY21jX3Bvc3Rlcmlvci5wZGYiLCB3aWR0aD0xMCwgaGVpZ2h0PTUpCmBgYAoKT24gcGV1dCBmaW5hbGVtZW50IG9idGVuaXIgdW4gaW50ZXJ2YWxsZSBkZSBjcsOpZGliaWxpdMOpIMOgIDk1JSBlbiByw6ljdXDDqXJhbnQgbGVzIHF1YW50aWxlcyBlbXBpcmlxdWVzCmRlIG5vdHJlIHBvc3RlcmlvciA6CgpgYGB7cn0KaWM5NV9tY21jIDwtIGRtY21jICU+JQoJZmlsdGVyKHN0ZXAgPiAxZTQgJiBzdGVwICUlIDEwID09IDApICU+JQoJcHVsbChwKSAlPiUKCXF1YW50aWxlKHByb2JzID0gYygwLjAyNSwgMC45NzUpKQpgYGAKCj4gSWNpLCBsJ2ludGVydmFsbGUgZGUgY3LDqWRpYmlsaXTDqSDDoCA5NSUgZXN0IApbYHIgcm91bmQoaWM5NV9tY21jWzFdLCAyKWAsIGByIHJvdW5kKGljOTVfbWNtY1syXSwgMilgXS4KCgojIExlIHByaW9yIGNvbmp1Z3XDqSwgdW4gb3V0aWwgcGx1cyBzbWFydAoKIyMgUHJpbmNpcGUgbWF0aMOpbWF0aXF1ZQoKT24gbCdhIHZ1LCBsZSBNQ01DIHBlcm1ldCBkZSBmYWlyZSB0b3V0ZSBsYSBjdWlzaW5lIHF1J29uIHNvdWhhaXRlLCBlbiBtb2RlIEJhecOpc2llbi4KQ2Ugbidlc3QgcGFzIGVuY29yZSB2aXNpYmxlIGF2ZWMgY2V0IGV4ZW1wbGUgc2ltcGxlIHF1aSBuZSBzJ2ludMOpcmVzc2UgcXUnw6AgdW5lIHNldWxlIHZhcmlhYmxlCiRwJCwgbWFpcyDDp2EgcGV1dCBkZXZlbmlyIHRyw6hzIHZpdGUgbG91cmQgZCd1biBwb2ludCBkZSB2dWUgY29tcHV0YXRpb25uZWwgcXVhbmQKb24gYSB1biBlc3BhY2UgZGUgcGFyYW3DqHRyZXMgZW4gcGx1cyBncmFuZGUgZGltZW5zaW9uIMOgIGV4cGxvcmVyLgpFbiBwbHVzIGRlIMOnYSwgYydlc3QgdHLDqHMgbGFyZ2VtZW50ICJpbsOpbMOpZ2FudCIgZCd1biBwb2ludCBkZSB2dWUgbWF0aHMsCmV0IG9uIHNlIHJldHJvdXZlIHNvdXZlbnQgw6AgdXRpbGlzZXIgdG91dCBldCBuJ2ltcG9ydGUgcXVvaSBjb21tZSBwcmlvciwKbcOqbWUgZGVzIGRpc3RyaWJ1dGlvbnMgYWJzb2x1bWVudCBwYXMgZmFpdGVzLCDDoCBsYSBiYXNlLCBwb3VyIGF2b2lyIGxlIHN1cHBvcnQKcXUnb24gbGV1ciBkb25uZS4KClVuZSBhbHRlcm5hdGl2ZSBwbHVzIMOpbMOpZ2FudGUsIG1haXMgcXVpIG7DqWNlc3NpdGUgZGUgcsOpZmzDqWNoaXIgdW4gcGV1IHBsdXMgZW4gYW1vbnQsCmNvbnNpc3RlIMOgIHMnYXBwdXllciBzdXIgdW4gbW9kw6hsZSBwbHVzIGFwcHJvcHJpw6ksIGF2ZWMsIHBhciBleGVtcGxlLAp1biAqcHJpb3IgY29uanVndcOpKi4KU2FucyBlbnRyZXIgZGFucyBsZXMgZMOpdGFpbHMsIHBvdXIgbCdlc3NlbnRpZWwgZGVzIGRpc3RyaWJ1dGlvbnMgZGUgdnJhaXNlbWJsYW5jZSBxdWUgdm91cyBwb3Vycmllegpjb25uYcOudHJlIChxdWkgZm9udCBwYXJ0aWUgZCd1bmUgZ3JhbmRlIGNsYXNzZSBkZSBkaXN0cmlidXRpb25zIGFwcGVsw6llICpmYW1pbGxlIGV4cG9uZW50aWVsbGUqKSwKaWwgZXhpc3RlIGNlIHF1J29uIGFwcGVsbGUgZGVzIHByaW9ycy9wb3N0ZXJpb3JzIGNvbmp1Z3XDqXMsIHF1aSBvbnQgbGUgYm9uIGdvw7t0CmQnYXZvaXIgbGEgbcOqbWUgZm9ybWUgZGUgZGlzdHJpYnV0aW9uLCBhdmVjIGRlcyBwYXJhbcOodHJlcyBkaWZmw6lyZW50cy4KCgojIyBQcmlvciBjb25qdWd1w6kgc3VyIG5vdHJlIGV4ZW1wbGUKClN1ciBub3RyZSBleGVtcGxlLCBsYSB2cmFpc2VtYmxhbmNlIGVzdCB1bmUgbG9pIGJpbm9taWFsZS4KTGUgcHJpb3IgY29uanVndcOpIGNvcnJlc3BvbmRhbnQgZXN0IHVuZSBsb2kgQsOqdGEsIGF2ZWMgbGEgcHJvcHJpw6l0w6kgc3VpdmFudGUgOgoKXGJlZ2lue2FsaWduKn0KJnAgXHNpbSBcbWF0aGNhbHtCZXRhfShcYWxwaGEsIFxiZXRhKSBcdGV4dHsgZXQgfSBOX3IgfCBwIFxzaW0gXG1hdGhjYWx7Qn0obiwgcCkgXFwKXExvbmdyaWdodGFycm93IH4mcCB8IE5fciBcc2ltIFxtYXRoY2Fse0JldGF9KFxhbHBoYSArIE5fciwgXGJldGEgKyBuIC0gTl9yKQpcZW5ke2FsaWduKn0KCkNlIGdlbnJlIGRlIHByb3ByacOpdMOpIGVzdCBkZSBwbHVzIHRyw6hzIGZhY2lsZSDDoCBkw6ltb250cmVyLCBwdWlzcXVlIDoKCjEuIGxhIGRpc3RyaWJ1dGlvbiBCZXRhIGVzdCB0ZWxsZSBxdWUgJFxtYXRoYmJ7UH0ocCkgXHByb3B0byBwXntcYWxwaGEtMX0gKDEtcClee1xiZXRhLTF9JC4KMi4gbGEgZGlzdHJpYnV0aW9uIEJpbm9taWFsZSBkZSBsYSB2cmFpc2VtYmxhbmNlIG5vdXMgZG9ubmUgJFxtYXRoYmJ7UH0oTl9yIHwgcCkgXHByb3B0byBwXntOX3J9ICgxLXApXntuLU5fcn0kLgozLiBldCBkb25jIGxlIHBvc3RlcmlvciBzJ29idGllbnQgZW4gw6ljcml2YW50IDoKICAgXGJlZ2lue2FsaWduKn0KICAgXG1hdGhiYntQfShwIHwgTl9yKSAKICAgJlxwcm9wdG8gXG1hdGhiYntQfShwKSBcbWF0aGJie1B9KE5fciB8IHApIFxcCiAgICZccHJvcHRvIHBee2FscGhhICsgTl9yIC0gMX0gKDEtcClee1xiZXRhICsgbiAtIE5fciAtIDF9CiAgIFxlbmR7YWxpZ24qfQoKT8O5IG9uIHJlY29ubmHDrnQsIGRvbmMsIHVuZSBsb2kgQsOqdGEgZGUgcGFyYW3DqHRyZXMgJChcYWxwaGEgKyBOX3IsIFxiZXRhICsgKG4gLSBOX3IpKSQuCkMnZXN0IGV4dHLDqm1lbWVudCBwcmF0aXF1ZSwgcHVpc3F1ZSBub3MgaHlwZXJwYXJhbcOodHJlcyBvbnQgbWFpbnRlbmFudCB1bmUgaW50ZXJwcsOpdGF0aW9uCmludHVpdGl2ZSBlbiB0ZXJtZSBkZSBub21icmUgZGUgcsOpcG9uZGV1cnMvbm9uLXLDqXBvbmRldXJzIHF1J29uIGF1cmFpdCBkw6lqw6AgdnUgYXZhbnQgZGUgZmFpcmUKbm90cmUgbm91dmVsbGUgZXhww6lyaWVuY2UuCgpQYXIgZXhlbXBsZSwgb24gcG91cnJhaXQgcmVnYXJkZXIgbGEgYmlibGlvLCBzZSBkaXJlIHF1J3VuZSBwcsOpY8OpZGVudGUgw6l0dWRlIGEgZMOpasOgCnJlZ2FyZMOpIG5vdHJlIHByb2Jsw6htZSBkJ2ludMOpcsOqdC4gCkNlbGxlLWNpIGF2YWl0IGVucmVnaXN0csOpICRcYWxwaGEgPSA1MCQgcsOpcG9uZGV1cnMgZXQgJFxiZXRhID0gNjAkIG5vbi1yw6lwb25kZXVycy4KT24gdmEgZG9uYyBwYXJ0aXIgc3VyIHVuIHByaW9yIGF2ZWMgbG9pIEJldGEgZGUgcGFyYW3DqHRyZXMgJChcYWxwaGE9NTAsIFxiZXRhPTYwKSQuCgpgYGB7ciBmaWcud2lkdGg9MTB9CmFscGhhIDwtIDUwCmJldGEgPC0gNjAKdGliYmxlKHggPSBzZXEoMCwgMSwgMC4wMDEpKSAlPiUKCW11dGF0ZSh5ID0gZGJldGEoeCwgc2hhcGUxPWFscGhhLCBzaGFwZTI9YmV0YSkpICU+JQoJZ2dwbG90KGFlcyh4PXgsIHk9eSkpICsKCWdlb21fbGluZShjb2wgPSBibGV1Y2xhaXIpICsKCXhsYWIoIlZhbGV1ciBkZSBwIikgKwoJeWxhYigiZGVuc2l0w6kgZHUgcHJpb3IiKSArCgl0aGVtZV9idygpCmBgYApgYGB7ciBlY2hvPUZ9CiMgZW5yZWdpc3RyZW1lbnQgZGUgbGEgZmlndXJlIHBvdXIgdXNhZ2UgZGFucyBsYSBwcsOpc2VudGF0aW9uIGFzc29jacOpZQpnZ3NhdmUoIm91dC9iYXllc2llbl9mcmVxdWVudGlzdGVfcHJpb3JfY29uai5wZGYiLCB3aWR0aD0xMCwgaGVpZ2h0PTUpCmBgYAoKCiMjIExvaSBkZSBsYSBtYXJnaW5hbGUKCkRhbnMgdG91cyBjZXMgY2FzIGF2ZWMgdW4gcHJpb3IgY29uanVndcOpLCBsYSBsb2kgZGUgbGEgbWFyZ2luYWxlIGRlcyBvYnNlcnZhdGlvbnMKZXN0IGF1c3NpIGNvbm51ZSBhdmVjIGRlcyBmb3JtdWxlcyBmZXJtw6llcywgYmllbiBxdSdlbiBnw6luw6lyYWwgcGFzIHRyaXZpYWxlLgpJY2ksIGxhIGxvaSBkZSBsYSBtYXJnaW5hbGUgZXN0IGFwcGVsw6llICpCw6p0YS1iaW5vbWlhbGUqLApldCBzb24gYWxsdXJlIGVzdCBhZmZpY2jDqWUgY2ktZGVzc291cyA6CgpgYGB7ciBmaWcud2lkdGg9MTB9CnRpYmJsZShrID0gc2VxKDAsIG4sIDEpKSAlPiUKCW11dGF0ZSh5ID0gZGJiaW5vbShrLCBzaXplPW4sIGFscGhhPWFscGhhLCBiZXRhPWJldGEpKSAlPiUKCWdncGxvdChhZXMoeD1rLCB5PXkpKSArCglnZW9tX2xpbmUoY29sID0gYmxldWNsYWlyKSArCgl4bGFiKCJOb21icmUgZGUgcsOpcG9uZGV1cnMiKSArCgl5bGFiKCJwcm9iYWJpbGl0w6kiKSArCgl0aGVtZV9idygpCmBgYApgYGB7ciBlY2hvPUZ9CiMgZW5yZWdpc3RyZW1lbnQgZGUgbGEgZmlndXJlIHBvdXIgdXNhZ2UgZGFucyBsYSBwcsOpc2VudGF0aW9uIGFzc29jacOpZQpnZ3NhdmUoIm91dC9iYXllc2llbl9mcmVxdWVudGlzdGVfcHJpb3JfY29ual9tYXJnaW5hbGUucGRmIiwgd2lkdGg9MTAsIGhlaWdodD01KQpgYGAKCgojIyBMb2kgZHUgcG9zdGVyaW9yCgpQdWlzcXUnb24gdXRpbGlzZSB1biBwcmlvciBjb25qdWd1w6ksIGxlIHBvc3RlcmlvciBub3VzIGVzdCBkb25uw6kgc3VyIHVuIHBsYXRlYXUgZCdhcmdlbnQgOgppbCBzJ2FnaXQgZCd1bmUgbG9pIELDqnRhIGRlIHBhcmFtw6h0cmVzICRcYWxwaGEgKyBOX3IkLCAkXGJldGEgKyBuIC0gTl9yJC4KCmBgYHtyIGZpZy53aWR0aD0xMH0KdGliYmxlKHggPSByZXAoc2VxKDAsIDEsIGxlbmd0aC5vdXQ9NTAwKSwgMiksCgkgICBkaXN0cmlidXRpb24gPSByZXAoYygicHJpb3IiLCAicG9zdGVyaW9yIiksIGVhY2g9NTAwKSkgJT4lCgltdXRhdGUoeSA9IGRiZXRhKHgsIAoJCQkJCSBzaGFwZTE9cmVwKGMoYWxwaGEsIGFscGhhICsgbl9yKSwgZWFjaD01MDApLCAKCQkJCQkgc2hhcGUyPXJlcChjKGJldGEsIGJldGEgKyBuIC0gbl9yKSwgZWFjaD01MDApKSApICU+JQoJZ2dwbG90KGFlcyh4PXgsIHk9eSwgY29sPWRpc3RyaWJ1dGlvbikpICsKCWdlb21fbGluZSgpICsKCXhsYWIoIlZhbGV1ciBkZSBwIikgKwoJeWxhYigiZGVuc2l0w6kiKSArCgl0aGVtZV9idygpCmBgYApgYGB7ciBlY2hvPUZ9CiMgZW5yZWdpc3RyZW1lbnQgZGUgbGEgZmlndXJlIHBvdXIgdXNhZ2UgZGFucyBsYSBwcsOpc2VudGF0aW9uIGFzc29jacOpZQpnZ3NhdmUoIm91dC9iYXllc2llbl9mcmVxdWVudGlzdGVfcHJpb3JfY29ual9wb3N0ZXJpb3IucGRmIiwgd2lkdGg9MTAsIGhlaWdodD01KQpgYGAKClN1ciBjZXQgZXhlbXBsZSwgb24gcGV1dCB1bmUgbm91dmVsbGUgZm9pcyBjYWxjdWxlciB1biBpbnRlcnZhbGxlIGRlIGNyw6lkaWJpbGl0w6kgw6AgOTUlLAoKYGBge3J9CmljOTVfY29uaiA8LSBxYmV0YShjKDAuMDI1LCAwLjk3NSksIHNoYXBlMT1hbHBoYStuX3IsIHNoYXBlMj1iZXRhK24tbl9yKQpgYGAKCj4gSWNpLCBsJ2ludGVydmFsbGUgZGUgY3LDqWRpYmlsaXTDqSDDoCA5NSUgZXN0IApbYHIgcm91bmQoaWM5NV9jb25qWzFdLCAyKWAsIGByIHJvdW5kKGljOTVfY29ualsyXSwgMilgXS4KCk9uIHJlbWFycXVlIGljaSB1bmUgdnJhaWUgZGlmZsOpcmVuY2UgZGUgcG9zdGVyaW9yLCBldCBkb25jIGQnaW50ZXJ2YWxsZSBkZSBjcsOpZGliaWxpdMOpLApwYXIgcmFwcG9ydCBhdXggZXhlbXBsZXMgcHLDqWPDqWRlbnRzLgpDZWNpIGVzdCBlbnRpw6hyZW1lbnQgZMO7IMOgIGwnaW5mbHVlbmNlIGR1IHByaW9yLCBxdWkgZXN0IHByaXMgZW4gY29tcHRlIGRhbnMgbm90cmUgcG9zdGVyaW9yCmV0IGxlICJzaGlmdGUiIHN1ciBsYSBnYXVjaGUgcGFyIHJhcHBvcnQgYXV4IGV4ZW1wbGVzIHByw6ljw6lkZW50cy4KCgojIENvbmNsdXNpb24KCkplIHRlbnRlIGxlIHRhYmxlYXUgc3VpdmFudCBwb3VyIHLDqXN1bWVyIGxlcyBhdmFudGFnZXMgZXQgaW5jb252w6luaWVudHMgZHUgZnLDqXF1ZW50aXN0ZSBldCBkdSBCYXnDqXNpZW4KcG91ciBsZXMgZXNzYWlzIGNsaW5pcXVlcywgYmFzw6lzIHN1ciBjZSBxdWkgZXN0IGTDqWNyaXQgZGFucyBjZSBub3RlYm9vayA6CgpgYGB7ciwgZWNobz1GLCBmaWcud2lkdGg9MTB9CmRfYXZhbnRhZ2UgPC0gdGliYmxlKGl0ZW0gPSByZXAoYygiaW50ZXJwcsOpdGF0aW9uIiwgInRow6lvcmllIiwgImNhbGN1bCBudW3DqXJpcXVlIiwgImJlc29pbiBkJ2h5cG90aMOoc2VzIiksIGVhY2ggPSAyKSwKCQkJCQkgbWV0aG9kID0gcmVwKGMoIkJhecOpc2llbiIsICJGcsOpcXVlbnRpc3RlIiksIDQpLAoJCQkJCSBhdmFudGFnZSA9IGMoImF2YW50YWdlIiwgImluY29udsOpbmllbnQiLCAiYXZhbnRhZ2UiLCAiaW5jb252w6luaWVudCIsICJpbmNvbnbDqW5pZW50IiwgImF2YW50YWdlIiwgImluY29udsOpbmllbnQiLCAiYXZhbnRhZ2UiKSwKCQkJCQkgY29udGVudCA9IGMoInBsdXMgaW50dWl0aXZlIiwgIm1vaW5zIGludHVpdGl2ZSIsCgkJCQkJCQkJICJyw6lzdWx0YXRzIHBsdXMgc2ltcGxlc1xuZGVtYW5kYW50IG1vaW5zIGRlIGJhZ2FnZSBtYXRow6ltYXRpcXVlIiwgInRow6lvcmllIHNvdXZlbnQgcGx1cyBhcmR1ZSIsCgkJCQkJCQkJICJiZXNvaW4gZGUgcGx1cyBkZSByZXNzb3VyY2VzIG51bcOpcmlxdWVzIiwgInBsdXTDtHQgcGx1cyByYXBpZGUiLAoJCQkJCQkJCSAiaHlwb3Row6hzZXMgZm9ydGVzLCBkw6lwZW5kYW5jZSBhdXggcHJpb3JzIiwgIm1vaW5zIGQnaHlwb3Row6hzZXMgbsOpY2Vzc2FpcmVzIikpCgpkX2F2YW50YWdlICU+JSAKCWdncGxvdChhZXMoeD1tZXRob2QsIHk9aXRlbSwgZmlsbD1hdmFudGFnZSwgbGFiZWw9Y29udGVudCkpICsKCWdlb21fdGlsZShhbHBoYT0wLjUpICsKCWdlb21fdGV4dCgpICsKCXhsYWIoIiIpICsKCXlsYWIoIiIpICsKCXNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImF2YW50YWdlIj0iIzVjOTI1MCIsICJpbmNvbnbDqW5pZW50Ij0iI2UyNjU0YiIpKSArCgl0aGVtZV9jbGFzc2ljKCkgKwoJdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikKYGBgCmBgYHtyIGVjaG89Rn0KIyBlbnJlZ2lzdHJlbWVudCBkZSBsYSBmaWd1cmUgcG91ciB1c2FnZSBkYW5zIGxhIHByw6lzZW50YXRpb24gYXNzb2Npw6llCmdnc2F2ZSgib3V0L2JheWVzaWVuX2ZyZXF1ZW50aXN0ZV9hdmFudGFnZXNfaW5jb252ZW5pZW50cy5wZGYiLCB3aWR0aD0xNSwgaGVpZ2h0PTUpCmBgYAoKTGVzIGF1dHJlcyBwb2ludHMgaW1wb3J0YW50cyBzb250IGxlcyBzdWl2YW50cyA6CgoqIFBvdXIgbGVzIHByb2Jsw6htZXMgZCdlc3RpbWF0aW9uLCBsYSBub3Rpb24gZCdpbnRlcnZhbGxlIGRlIGNyw6lkaWJpbGl0w6kgZXN0IHBsdXMgZmFjaWxlCiAgw6AgY29tcHJlbmRyZSBxdWUgbCdpbnRlcnZhbGxlIGRlIGNvbmZpYW5jZS4KKiBQb3VyIGxlcyB0ZXN0cyBkJ2h5cG90aMOoc2VzLCBpbCBlc3QgcG9zc2libGUgZGUgZmFpcmUgZGVzIGNob2l4LCBlbiBCYXnDqXNpZW4sIGJhc8OpcwogIGRpcmVjdGVtZW50IHN1ciBsYSBwcm9iYWJpbGl0w6kgZGVzIGRldXggaHlwb3Row6hzZXMgc2FjaGFudCBsZXMgZG9ubsOpZXMsCiAgY2UgcXVpIGVzdCBhdXNzaSBub3RhYmxlbWVudCBwbHVzIGZhY2lsZSDDoCBjb21wcmVuZHJlLgoqIExhIG5vdGlvbiBkZSAqbm9uLWluZm9ybWF0aXZlIHByaW9yKiBlc3QgYXNzZXogbGFyZ2VtZW50IG1lbnNvbmfDqHJlLCAKICDDoCByZW1wbGFjZXIgcGFyIGNlbGxlIGRlICpmbGF0IHByaW9yKi4KKiBMZXMgcHJpb3JzIGNvbmp1Z3XDqXMgc29udCB0csOocyBpbnTDqXJlc3NhbnRzIGRhbnMgbGVzIGNhcyBzaW1wbGVzCiAgcG91ciBhdm9pciB1biBtb2TDqGxlIHNpbXBsZSBldCDDqWzDqWdhbnQuCiogRGFucyB0b3VzIGxlcyBhdXRyZXMgY2FzLCBkZXMgTUNNQyBwZXJtZXR0ZW50IGRlIGTDqXRlcm1pbmVyIGxhCiAgZGlzdHJpYnV0aW9uIMOgIHBvc3RlcmlvcmkuCgoKCg==