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)

# quelques couleurs manuelles
bleufonce <- "#3d5468"
bleuclair <- "#5b7c98"
rose <- "#ff5555"

Puis on importe le dataset dans notre session de R :

d <- read.csv("etude_fictive_diabetes.csv")
head(d)
##   X id   group sex age height weight_t0 diabetes steps_t0 t_compliance
## 1 1  1 control   F  72   1.61     80.25       II     2642           32
## 2 2  2 control   M  71   1.81     79.66        I     1675           48
## 3 3  3 control   F  32   1.72     67.25       II     2698            8
## 4 4  4 control   M  76   1.74     73.59        I     2519            2
## 5 5  5 control   F  34   1.53     83.98        I     2764           12
## 6 6  6 control   F  70   1.71     69.14       II     2606           24
##     age_group      bmi bmi_group diff_weight diff_steps is_depressed
## 1  plus de 60 30.95945     obese  -3.6168091  -26.66633            1
## 2  plus de 60 24.31550    normal  -2.6491665  656.62903            1
## 3 moins de 40 22.73188    normal  -1.5288284   17.31293            0
## 4  plus de 60 24.30638    normal  -3.0515988 -589.42996            1
## 5 moins de 40 35.87509     obese   0.8933788  761.91017            1
## 6  plus de 60 23.64488    normal  -0.3074968  216.47307            1
##   feels_sleepy n_meals_glycemia_out_of_target weight_tf steps_tf
## 1      morning                             53  76.63319 2615.334
## 2      morning                             19  77.01083 2331.629
## 3      morning                              4  65.72117 2715.313
## 4      morning                             17  70.53840 1929.570
## 5    afternoon                            188  84.87338 3525.910
## 6       always                              9  68.83250 2822.473

Nous sommes prêts à travailler sur ce jeu de données, et, pour ce qui nous intéresse ici, à analyser les données continues qu’il renferme.

Comparaison de moyennes

T test : adéquation à une norme

On observe des différences de poids \((X_i)\) chez nos individus entre le début et la fin de l’expérience. Est-ce que la différence de poids moyenne est différente de zéro ?

On souhaite réaliser le test d’hypothèse suivant :

  • H0 : la moyenne des \((X_i)\) vaut zero.
  • H1 : la moyenne des \((X_i)\) est différente de zéro.

Conditions d’application :

  • les variables aléatoires sont indépendantes et de même loi.
  • soit les variables aléatoires sont distribuées normalement, soit l’échantillon est “grand”.

On commence toujours par représenter nos données.

plot_diff_weight <- d %>% ggplot(aes(x=diff_weight)) +
    geom_histogram(alpha=0.7, position="identity", bins=20) +
    theme_bw() +
    ylab("effectif") + 
    xlab("différence de poids à 6 mois")
plot_diff_weight

Ici les conditions d’application semblent respectées.

Un résultat théorique certifie qu’une certaine statistique de test \(T\) calculée à partir :

  • de l’effectif,
  • de la moyenne empirique dans chaque groupe,
  • et de la variance empirique dans chaque groupe,

est distribuée suivant une loi de Student avec un certain nombre de “degrés de liberté”.

Il s’agit donc de calculer la valeur observée de cette statistique de test sur notre échantillon, et de la comparer aux quantiles de la loi théorique.

La fonction pour faire ça en R est la suivante :

t.test(x=d$diff_weight)
## 
##  One Sample t-test
## 
## data:  d$diff_weight
## t = -11.129, df = 499, p-value < 2.2e-16
## alternative hypothesis: true mean is not equal to 0
## 95 percent confidence interval:
##  -1.509690 -1.056617
## sample estimates:
## mean of x 
## -1.283153

L’output de la fonction nous rappelle :

  1. en première ligne l’échantillon sur lequel on a appliqué le test,
  2. en seconde ligne on récupère la valeur observée de la statistique de test, ainsi que le nombre de “degrés de liberté” de la loi théorique.
  3. en fin de seconde ligne, super importante : la p-value !!! Probabilité que la valeur de la statistique soit au moins aussi extrême qu’observée, sous H0.
  4. troisième ligne : un rappel de l’hypothèse alternative du test (modifiable avec l’argument alternative).
  5. un intervalle de confiance à 95% de la moyenne (bornes modifiables via l’argument conf.level).
  6. tout à la fin, l’estimation ponctuelle de la moyenne.

Que concluons-nous ?

T test : comparaison de 2 moyennes

On observe des valeurs \((X_{i,j})\) de nos individus \(i\) dans deux groupes \(j=1\) et \(j=2\). Ici les deux groupes correspondent au control vs. treatment, et les observations correspondent à une différence de poids entre le début et la fin de l’expérience.

Est-ce que la différence de poids moyenne est différente dans les deux groupes ?

On souhaite réaliser le test d’hypothèse suivant :

  • H0 : la moyenne des \((X_{i,1})\) est identique à celle des \((X_{i,2})\).
  • H1 : les deux moyennes sont différentes.

Conditions d’application :

  • les variables aléatoires sont indépendantes et de même loi.
  • soit les variables aléatoires sont distribuées normalement, soit l’échantillon est “grand”.

On commence toujours par représenter nos données et quantités d’intérêt.

m <- d %>% group_by(group) %>% summarise(mean=mean(diff_weight)) %>% select(mean)

plot_diff_weight_by_group <- d %>% ggplot(aes(x=diff_weight, fill=group)) +
    geom_histogram(alpha=0.5, position="identity", bins=20) +
    theme_bw() +
    ylab("effectif") + 
    xlab("différence de poids à 6 mois") +
    scale_fill_manual(values=c(bleuclair, rose)) +
    geom_vline(xintercept = c(m$mean[1], m$mean[2]), color=c(bleuclair, rose))
plot_diff_weight_by_group

Ici les conditions d’application semblent respectées.

Un résultat théorique certifie qu’une statistique de test calculée à partir de l’effectif, des moyennes empiriques des deux groupes et de la variance empirique des deux groupes, est distribuée suivant une loi de Student avec un certain nombre de “degrés de liberté”.

Il s’agit donc de calculer la valeur observée de cette statistique de test sur notre échantillon, et de la comparer aux quantiles de la loi théorique.

La fonction pour faire ça en R est la suivante :

t.test(diff_weight ~ group, data=d)
## 
##  Welch Two Sample t-test
## 
## data:  diff_weight by group
## t = 1.9787, df = 489.92, p-value = 0.04841
## alternative hypothesis: true difference in means between group control and group treatment is not equal to 0
## 95 percent confidence interval:
##  0.003200646 0.906752183
## sample estimates:
##   mean in group control mean in group treatment 
##               -1.055665               -1.510642

Ca se lit de façon très similaire à ce qu’on avait précédemment, les différences étant :

  1. L’IC à 95% correspond à celui de la différence des deux moyennes.
  2. Les estimations ponctuelles correspondent aux deux moyennes.

Que concluons-nous ?

ANOVA : comparaison de n moyennes

On souhaite plus précisément tester ici la différence d’au moins une moyenne parmi plusieurs groupes.

On dispose cette fois d’observations de la même quantité $(X_{i,j}) chez l’individu \(i\) dans le groupe \(j\), dans un nombre de groupes potentiellement supérieur à 2. Est-ce que la moyenne d’au moins un groupe diffère des autres groupes ?

Par exemple, ici, la différence de poids moyenne change-t-elle dans les trois classes d’âge ? (< 40, 40-60, > 60)

On teste formellement :

  • H0 : les moyennes des \((X_{i,1})\), des \((X_{i,2})\) et des \((X_{i,3})\) sont identiques.
  • H1 : au moins une des moyennes diffère.

Conditions d’application :

  • les variables aléatoires sont indépendantes et suivent une loi normale.
  • il y a égalité de variance entre les différents groupes.

Une fois n’est pas coutûme, commençons par représenter les données :

m <- d %>% group_by(age_group) %>% summarise(mean=mean(diff_weight)) %>% select(mean)

plot_diff_weight_by_age_group <- d %>% ggplot(aes(x=diff_weight, fill=as.factor(age_group))) +
    geom_histogram(alpha=0.5, position="identity", bins=20) +
    theme_bw() +
    ylab("effectif") + 
    xlab("différence de poids à 6 mois") +
    scale_fill_manual(values=c(bleufonce, bleuclair, rose)) +
    geom_vline(xintercept = c(m$mean[1], m$mean[2], m$mean[3]), color=c(bleufonce, bleuclair, rose))
plot_diff_weight_by_age_group

ggsave("../../Figures/illu_diabete_diff_weight_age_group.pdf", plot=plot_diff_weight_by_age_group, width=12, height=5)

Les conditions d’application semblent respectées (au moins graphiquement).

Un résultat théorique certifie cette fois qu’une certaine statistique de test, calculée à partir :

  • des effectifs des différents groupes
  • et des variances intra-groupes / inter-groupes,

est distribuée suivant une loi de Fisher avec un certain nombre de “degrés de liberté”.

Il s’agit donc de calculer la valeur observée de cette statistique de test sur notre échantillon, et de la comparer aux quantiles de la loi théorique.

La fonction pour faire ça en R est la suivante :

res_aov <- aov(diff_weight ~ age_group, data=d)
summary(res_aov)
##              Df Sum Sq Mean Sq F value Pr(>F)
## age_group     2      4   2.099   0.315   0.73
## Residuals   497   3313   6.666

Les deux points les plus intéressants de l’output sont :

  1. la “F value” qui est la valeur de la statistique de test,
  2. et la p-value : la probabilité sous H0 d’obtenir une statistique de test au moins aussi extrême qu’observée.

Que concluons-nous ?

Finissons par un petit test, permettant de se convaincre qu’une ANOVA avec deux groupes correspond à un T test.

res_aov_2 <- aov(diff_weight ~ group, data=d)
summary(res_aov_2)
##              Df Sum Sq Mean Sq F value Pr(>F)  
## group         1     26  25.875   3.915 0.0484 *
## Residuals   498   3291   6.609                 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
t.test(diff_weight ~ group, data=d)
## 
##  Welch Two Sample t-test
## 
## data:  diff_weight by group
## t = 1.9787, df = 489.92, p-value = 0.04841
## alternative hypothesis: true difference in means between group control and group treatment is not equal to 0
## 95 percent confidence interval:
##  0.003200646 0.906752183
## sample estimates:
##   mean in group control mean in group treatment 
##               -1.055665               -1.510642

Test de Wilcoxon

L’alter-ego non-paramétrique du T test est le test de Wilcoxon (aussi appelé Mann-Whitney ou Wilcoxon-Mann-Whitney).

  • Avantage : conditions d’application toujours remplies.
  • Inconvénient : moins puissant qu’un T test.

Dans notre cas, étant donné le grand effectif de notre essai clinique, le T test était un choix très approprié. On peut cependant se convaincre du fonctionnement d’un test de Wilcoxon en l’essayant :

wilcox.test(diff_weight ~ group, data=d)
## 
##  Wilcoxon rank sum test with continuity correction
## 
## data:  diff_weight by group
## W = 34330, p-value = 0.0566
## alternative hypothesis: true location shift is not equal to 0

Test de Kruskal-Wallis

De même, testons l’utilisation de l’alter-ego de l’ANOVA en version non-paramétrique :

kruskal.test(diff_weight ~ age_group, data=d)
## 
##  Kruskal-Wallis rank sum test
## 
## data:  diff_weight by age_group
## Kruskal-Wallis chi-squared = 0.60933, df = 2, p-value = 0.7374

On se convainc aussi facilement qu’un test de Kruskal-Wallis avec une variable à deux modalités revient à faire un test de Wilcoxon :

kruskal.test(diff_weight ~ group, data=d)
## 
##  Kruskal-Wallis rank sum test
## 
## data:  diff_weight by group
## Kruskal-Wallis chi-squared = 3.6355, df = 1, p-value = 0.05656

Régression linéaire univariée

Une droite de régression commune

On dispose cette fois d’observations d’une variables \((Y_i)\) d’intérêt, par exemple encore une fois la différence de poids. Et d’une autre variable quantitative \((X_i)\) correspondant à quelque chose qui pourrait être corrélé à nos \((Y_i)\), par exemple ici le temps pendant lequel le patient a strictement observé son traitement (compliance).

Est-ce que le gain de poids dépend de la compliance, dans le groupe traité ?

Le coefficient de corrélation \(\rho\) correspond à la covariance des deux quantités normalisée par les écarts-types des deux quantités. Il est compris entre -1 et 1 et renseigne sur la dispersion des données en 2D. En cas de corrélation linéaire parfaite, il vaut 1 ou -1.

Formellement on peut tester, avec le test de Bravais-Pearson :

  • H0 : \(\rho = 0\),
  • H1 : \(\rho \neq 0\).

Conditions d’application : les \((Y_i, X_i)\) doivent être appariées et distribuées normalement.

Commençons par représenter les données, avec une droite de régression partagé par tous les points :

plot_diff_weight_vs_compliance <- d %>% 
    ggplot(aes(y=diff_weight, x=t_compliance)) +
    geom_point() +
    geom_smooth(method="lm", se=F, formula="y ~ x", col=bleufonce) +
    theme_bw() +
    xlab("t_compliance") + 
    ylab("différence de poids à 6 mois")
plot_diff_weight_vs_compliance

On peut à présent effectuer un test de corrélation en prenant tous les points ensemble :

cor.test(d$diff_weight, d$t_compliance)
## 
##  Pearson's product-moment correlation
## 
## data:  d$diff_weight and d$t_compliance
## t = -3.5459, df = 498, p-value = 0.0004283
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  -0.2412955 -0.0702008
## sample estimates:
##        cor 
## -0.1569254

Que concluons-nous ?

Une droite dans chaque groupe

Deuxième essai plus intéressant : regarder l’influence de t_compliance séparément dans les deux bras de l’essai clinique. On commence par observer les données :

plot_diff_weight_vs_compliance_2 <- d %>% 
    ggplot(aes(y=diff_weight, x=t_compliance, color = group)) +
    geom_point() +
    geom_smooth(method="lm", se=F, formula="y ~ x") +
    theme_bw() +
    xlab("t_compliance") + 
    ylab("différence de poids à 6 mois") +
    scale_color_manual(values=c(bleuclair, rose))
plot_diff_weight_vs_compliance_2

ggsave("../../Figures/illu_diabete_diff_weight_reglin.pdf", plot=plot_diff_weight_vs_compliance_2, width=12, height=5)

Puis un test de corrélation en prenant uniquement le groupe control :

d_control <- d %>% filter(group == "control")
cor.test(d_control$diff_weight, d_control$t_compliance)
## 
##  Pearson's product-moment correlation
## 
## data:  d_control$diff_weight and d_control$t_compliance
## t = -0.58815, df = 248, p-value = 0.557
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  -0.1606448  0.0871489
## sample estimates:
##         cor 
## -0.03732163

Et enfin, le même test de corrélation en prenant uniquement le groupe treatment :

d_treatment <- d %>% filter(group == "treatment")
cor.test(d_treatment$diff_weight, d_treatment$t_compliance)
## 
##  Pearson's product-moment correlation
## 
## data:  d_treatment$diff_weight and d_treatment$t_compliance
## t = -4.3818, df = 248, p-value = 1.739e-05
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  -0.3795073 -0.1489484
## sample estimates:
##        cor 
## -0.2680618

Que concluons-nous ?

Le modèle linéaire

Description

Le modèle linéaire présente l’intérêt d’unifier tous ces tests dans un unique framework.

Il consiste à modéliser une variable de réponse \(Y_i\) chez l’individu \(i\) comme une fonction linéaire de nos variables explicatrices \(X_{i,j}\), à laquelle on rajoute un bruit Gaussien centré. Une fonction linéaire n’est rien de plus qu’une somme pondérée de nos variables \(X_{i,j}\), soit :

\[ Y_i = a_1 X_{i,1} + a_2 X_{i,2} + ... + a_J X_{i,J} + \epsilon_i, ~~~\text{ avec } \epsilon_i \sim \mathcal{N}(0, \sigma^2) \]

On suppose que tous les \((Y_i)\) sont indépendantes et suivent la même loi. Le but du jeu, pour le statisticien, consiste à fitter les valeurs des coefficients \(a_j\) grâce aux observations.

Bonne nouvelle : la syntaxe de R pour fitter un modèle linéaire est assez rapide et intuitive.

Un simple intercept

Premier cas simple : on aimerait modéliser la différence de poids comme étant uniquement une moyenne + un petit bruit Gaussien, et calculer cette moyenne comme on l’avait fait lors du premier test de Student.

res_lm_1 <- lm(formula="diff_weight ~ 1", data=d)
summary(res_lm_1)
## 
## Call:
## lm(formula = "diff_weight ~ 1", data = d)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -8.9290 -1.7337  0.1193  1.7881  7.7890 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -1.2832     0.1153  -11.13   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 2.578 on 499 degrees of freedom

Vérifier qu’on retombe bien sur la même chose que précédemment.

Un effet de variable discrète

Deuxième cas simple : on aimerait modéliser la différence de poids comme étant la somme d’un coefficient particulier chez les individus du groupe “control” et un autre coefficient chez les individus du groupe “treatment”. Soit exactement ce qu’on avait fait avec un test de Student comparant les deux moyennes.

Il se trouve que R, lorsqu’on lui donne à manger une variable à plusieurs modalités, va automatiquement la “scinder” en sous-variables indicatrices de chaque modalité. La syntaxe reste donc très simple :

# première version avec moyenne commune aux deux groupes
# et un petit ajout pour le groupe traitement
res_lm_group <- lm(formula="diff_weight ~ group", data=d)
summary(res_lm_group)
## 
## Call:
## lm(formula = "diff_weight ~ group", data = d)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -8.7016 -1.6078  0.1307  1.7151  8.0165 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)     -1.0557     0.1626  -6.493 2.04e-10 ***
## grouptreatment  -0.4550     0.2299  -1.979   0.0484 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 2.571 on 498 degrees of freedom
## Multiple R-squared:  0.007801,   Adjusted R-squared:  0.005809 
## F-statistic: 3.915 on 1 and 498 DF,  p-value: 0.0484
# deuxième version avec moyenne dans chaque groupe
res_lm_group_2 <- lm(formula="diff_weight ~ 0 + group", data=d)
summary(res_lm_group_2)
## 
## Call:
## lm(formula = "diff_weight ~ 0 + group", data = d)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -8.7016 -1.6078  0.1307  1.7151  8.0165 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## groupcontrol    -1.0557     0.1626  -6.493 2.04e-10 ***
## grouptreatment  -1.5106     0.1626  -9.291  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 2.571 on 498 degrees of freedom
## Multiple R-squared:  0.2051, Adjusted R-squared:  0.2019 
## F-statistic: 64.24 on 2 and 498 DF,  p-value: < 2.2e-16

On a donc exactement le même modèle sous-jacent, avec des estimations de paramètres identiques. Cependant, ici, les p-value indiquées correspondent à un test d’adéquation du paramètre à 0. Si on souhaite comparer les deux moyennes et retomber sur le même résultat qu’au début du document, il faut donc passer par la première version et regarder le test d’adéquation du paramètre à 0.

Troisième possibilité, notre différence de poids dépend d’une variable prenant 3 modalités ou plus (comme on avait proposé lors de la réalisation du test ANOVA ci-dessus). La même syntaxe fonctionne toujours aussi bien :

res_lm_group_3 <- lm(formula="diff_weight ~ 0 + age_group", data=d)
summary(res_lm_group_3)
## 
## Call:
## lm(formula = "diff_weight ~ 0 + age_group", data = d)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -9.0199 -1.7538  0.0998  1.7780  7.6981 
## 
## Coefficients:
##                         Estimate Std. Error t value Pr(>|t|)    
## age_groupentre 40 et 60  -1.1923     0.2080  -5.731 1.73e-08 ***
## age_groupmoins de 40     -1.3993     0.1883  -7.432 4.72e-13 ***
## age_groupplus de 60      -1.2335     0.2054  -6.005 3.69e-09 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 2.582 on 497 degrees of freedom
## Multiple R-squared:  0.1999, Adjusted R-squared:  0.195 
## F-statistic: 41.38 on 3 and 497 DF,  p-value: < 2.2e-16

L’output standard du modèle linéaire ne nous calcule des p-values que pour les tests d’adéquation de chaque paramètre à 0. Bien que l’ANOVA soit effectivement un test réalisé au sein du même framework de modèle linéaire, la p-value associée n’est récupérable, en pratique avec R, que via la fonction aov vue précédemment.

Un effet de variable continue

Dernier exemple similaire à ce qu’on avait fait précédemment : expliquer notre variable de réponse “différence de poids” par le “temps de compliance”.

res_lm_compliance <- lm(formula="diff_weight ~ t_compliance", data=d)
summary(res_lm_compliance)
## 
## Call:
## lm(formula = "diff_weight ~ t_compliance", data = d)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -8.1795 -1.6306  0.0848  1.7868  7.6839 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -0.855739   0.165900  -5.158 3.61e-07 ***
## t_compliance -0.020148   0.005682  -3.546 0.000428 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 2.549 on 498 degrees of freedom
## Multiple R-squared:  0.02463,    Adjusted R-squared:  0.02267 
## F-statistic: 12.57 on 1 and 498 DF,  p-value: 0.0004283

Vers plus de complexification

Et si on souhaite un effet additif du groupe et du temps de compliance :

res_lm_compliance_group <- lm(formula="diff_weight ~ 0 + group + t_compliance", data=d)
summary(res_lm_compliance_group)
## 
## Call:
## lm(formula = "diff_weight ~ 0 + group + t_compliance", data = d)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -8.4145 -1.6278  0.0921  1.7597  7.9167 
## 
## Coefficients:
##                 Estimate Std. Error t value Pr(>|t|)    
## groupcontrol   -0.618262   0.201687  -3.065 0.002292 ** 
## grouptreatment -1.085678   0.199611  -5.439 8.42e-08 ***
## t_compliance   -0.020325   0.005664  -3.588 0.000366 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 2.541 on 497 degrees of freedom
## Multiple R-squared:  0.2252, Adjusted R-squared:  0.2205 
## F-statistic: 48.14 on 3 and 497 DF,  p-value: < 2.2e-16

Ce n’est pas exactement ce qu’on avait fait tout à l’heure sur le graphe : on avait alors deux régressions linéaires, une dans chaque groupe. R possède encore une fois une syntaxe pratique pour ça :

res_lm_compliance_group_2 <- lm(formula="diff_weight ~ 0 + group * t_compliance", data=d)
summary(res_lm_compliance_group_2)
## 
## Call:
## lm(formula = "diff_weight ~ 0 + group * t_compliance", data = d)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -8.2949 -1.5933  0.1597  1.6771  7.8364 
## 
## Coefficients:
##                              Estimate Std. Error t value Pr(>|t|)    
## groupcontrol                -0.960433   0.233093  -4.120 4.43e-05 ***
## grouptreatment              -0.743698   0.231290  -3.215  0.00139 ** 
## t_compliance                -0.004425   0.007897  -0.560  0.57549    
## grouptreatment:t_compliance -0.032257   0.011248  -2.868  0.00431 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 2.522 on 496 degrees of freedom
## Multiple R-squared:  0.2378, Adjusted R-squared:  0.2317 
## F-statistic: 38.69 on 4 and 496 DF,  p-value: < 2.2e-16

On a introduit super facilement ce qu’on appelle des interactions entre nos variables. Le modèle linéaire, et la syntaxe de R, sont donc des outils de modélisation extrêmement puissants/versatiles. Ils demandent à bien réfléchir en amont à ce qu’on souhaite étudier pour éviter une trop grande multiplication de tests statistiques.

Quel serait selon vous le modèle linéaire le plus approprié pour diff_weight ?

Quel serait selon vous le modèle linéaire le plus approprié pour diff_steps ?

Conclusion

Nous avons vu ici un certain nombre de méthodes permettant d’analyser des variables continues. Les points principaux à retenir sont les suivants :

  1. Pour comparer deux moyennes, ou une moyenne à une norme, le T test est la bonne option, à condition que les données soient en grand nombre, ou qu’elles soient distribuées normalement.
  2. Pour comparer plus que deux moyennes, une ANOVA fait l’affaire, sous des conditions identiques.
  3. Lorsque les conditions d’application des tests paramétriques ne sont pas rencontrées, on peut recourir à des tests non-paramétriques : Wilcoxon et Kruskal-Wallis.
  4. Pour quantifier la corrélation entre deux variables continues distribuées normalement, un test de corrélation de Pearson peut être utilisé.
  5. Le modèle linéaire unifie tous les tests paramétriques précédents dans un unique framework, où une variable de réponse continue \(Y\) est modélisée comme une combinaison linéaire de variables explicatives \(X\) (discrètes ou continues).
LS0tCnRpdGxlOiAiU3RhdGlzdGlxdWVzIGF1IExBUEVDIC0tIEFuYWx5c2UgZGUgZG9ubsOpZXMgY29udGludWVzIgphdXRob3I6ICJNYXJjIE1hbmNlYXUiCmRhdGU6ICIyMDI0LTAxIgpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IFRSVUUKICAgIHRvY19kZXB0aDogMgogICAgdG9jX2Zsb2F0OiBUUlVFCiAgICBoaWdobGlnaHQ6ICJ0YW5nbyIKICAgIGNvZGVfZG93bmxvYWQ6IFRSVUUKLS0tCgpQb3VyIGxlcyB1dGlsaXNhdGV1cnMgZGUgUiwgb24gY29tbWVuY2UgcGFyIGNoYXJnZXIgdW4gY2VydGFpbiBub21icmUgZGUgbW9kdWxlcyBpbnTDqXJlc3NhbnRzLgoKYGBge3IgbWVzc2FnZT1GfQojIGxlIHBhY2thZ2UgbW9kZXJuZSBzdGFuZGFyZCBwb3VyIG1hbmlwdWxlciBzZXMgZG9ubsOpZXMKbGlicmFyeSh0aWR5dmVyc2UpCgojIHF1ZWxxdWVzIGNvdWxldXJzIG1hbnVlbGxlcwpibGV1Zm9uY2UgPC0gIiMzZDU0NjgiCmJsZXVjbGFpciA8LSAiIzViN2M5OCIKcm9zZSA8LSAiI2ZmNTU1NSIKYGBgCgpQdWlzIG9uIGltcG9ydGUgbGUgZGF0YXNldCBkYW5zIG5vdHJlIHNlc3Npb24gZGUgUiA6CgpgYGB7cn0KZCA8LSByZWFkLmNzdigiZXR1ZGVfZmljdGl2ZV9kaWFiZXRlcy5jc3YiKQpoZWFkKGQpCmBgYAoKTm91cyBzb21tZXMgcHLDqnRzIMOgIHRyYXZhaWxsZXIgc3VyIGNlIGpldSBkZSBkb25uw6llcywgZXQsIHBvdXIgY2UgcXVpIG5vdXMgaW50w6lyZXNzZSBpY2ksCsOgIGFuYWx5c2VyIGxlcyBkb25uw6llcyBjb250aW51ZXMgcXUnaWwgcmVuZmVybWUuCgoKIyBDb21wYXJhaXNvbiBkZSBtb3llbm5lcwoKIyMgVCB0ZXN0IDogYWTDqXF1YXRpb24gw6AgdW5lIG5vcm1lCgpPbiBvYnNlcnZlIGRlcyBkaWZmw6lyZW5jZXMgZGUgcG9pZHMgJChYX2kpJCBjaGV6IG5vcyBpbmRpdmlkdXMgZW50cmUgbGUgZMOpYnV0IGV0IGxhIGZpbiBkZSBsJ2V4cMOpcmllbmNlLgpFc3QtY2UgcXVlIGxhIGRpZmbDqXJlbmNlIGRlIHBvaWRzIG1veWVubmUgZXN0IGRpZmbDqXJlbnRlIGRlIHrDqXJvID8KCk9uIHNvdWhhaXRlIHLDqWFsaXNlciBsZSB0ZXN0IGQnaHlwb3Row6hzZSBzdWl2YW50IDoKCiogSDAgOiBsYSBtb3llbm5lIGRlcyAkKFhfaSkkIHZhdXQgemVyby4KKiBIMSA6IGxhIG1veWVubmUgZGVzICQoWF9pKSQgZXN0IGRpZmbDqXJlbnRlIGRlIHrDqXJvLgoKQ29uZGl0aW9ucyBkJ2FwcGxpY2F0aW9uIDoKCiogbGVzIHZhcmlhYmxlcyBhbMOpYXRvaXJlcyBzb250IGluZMOpcGVuZGFudGVzIGV0IGRlIG3Dqm1lIGxvaS4KKiBzb2l0IGxlcyB2YXJpYWJsZXMgYWzDqWF0b2lyZXMgc29udCBkaXN0cmlidcOpZXMgbm9ybWFsZW1lbnQsIHNvaXQgbCfDqWNoYW50aWxsb24gZXN0ICJncmFuZCIuCgpPbiBjb21tZW5jZSB0b3Vqb3VycyBwYXIgcmVwcsOpc2VudGVyIG5vcyBkb25uw6llcy4KCmBgYHtyIGZpZy53aWR0aD0xMH0KcGxvdF9kaWZmX3dlaWdodCA8LSBkICU+JSBnZ3Bsb3QoYWVzKHg9ZGlmZl93ZWlnaHQpKSArCiAgICBnZW9tX2hpc3RvZ3JhbShhbHBoYT0wLjcsIHBvc2l0aW9uPSJpZGVudGl0eSIsIGJpbnM9MjApICsKICAgIHRoZW1lX2J3KCkgKwogICAgeWxhYigiZWZmZWN0aWYiKSArIAogICAgeGxhYigiZGlmZsOpcmVuY2UgZGUgcG9pZHMgw6AgNiBtb2lzIikKcGxvdF9kaWZmX3dlaWdodApgYGAKCkljaSBsZXMgY29uZGl0aW9ucyBkJ2FwcGxpY2F0aW9uIHNlbWJsZW50IHJlc3BlY3TDqWVzLgoKVW4gcsOpc3VsdGF0IHRow6lvcmlxdWUgY2VydGlmaWUgcXUndW5lIGNlcnRhaW5lIHN0YXRpc3RpcXVlIGRlIHRlc3QgJFQkIGNhbGN1bMOpZSDDoCBwYXJ0aXIgOgoKKiBkZSBsJ2VmZmVjdGlmLCAKKiBkZSBsYSBtb3llbm5lIGVtcGlyaXF1ZSBkYW5zIGNoYXF1ZSBncm91cGUsIAoqIGV0IGRlIGxhIHZhcmlhbmNlIGVtcGlyaXF1ZSBkYW5zIGNoYXF1ZSBncm91cGUsIAoKZXN0IGRpc3RyaWJ1w6llIHN1aXZhbnQgdW5lIGxvaSBkZSBTdHVkZW50IGF2ZWMgdW4gY2VydGFpbiBub21icmUgZGUgImRlZ3LDqXMgZGUgbGliZXJ0w6kiLgoKSWwgcydhZ2l0IGRvbmMgZGUgY2FsY3VsZXIgbGEgdmFsZXVyIG9ic2VydsOpZSBkZSBjZXR0ZSBzdGF0aXN0aXF1ZSBkZSB0ZXN0IHN1ciBub3RyZSDDqWNoYW50aWxsb24sIApldCBkZSBsYSBjb21wYXJlciBhdXggcXVhbnRpbGVzIGRlIGxhIGxvaSB0aMOpb3JpcXVlLgoKTGEgZm9uY3Rpb24gcG91ciBmYWlyZSDDp2EgZW4gUiBlc3QgbGEgc3VpdmFudGUgOgoKYGBge3J9CnQudGVzdCh4PWQkZGlmZl93ZWlnaHQpCmBgYAoKTCdvdXRwdXQgZGUgbGEgZm9uY3Rpb24gbm91cyByYXBwZWxsZSA6CgoxLiBlbiBwcmVtacOocmUgbGlnbmUgbCfDqWNoYW50aWxsb24gc3VyIGxlcXVlbCBvbiBhIGFwcGxpcXXDqSBsZSB0ZXN0LAoyLiBlbiBzZWNvbmRlIGxpZ25lIG9uIHLDqWN1cMOocmUgbGEgdmFsZXVyIG9ic2VydsOpZSBkZSBsYSBzdGF0aXN0aXF1ZSBkZSB0ZXN0LCAKICAgYWluc2kgcXVlIGxlIG5vbWJyZSBkZSAiZGVncsOpcyBkZSBsaWJlcnTDqSIgZGUgbGEgbG9pIHRow6lvcmlxdWUuCjMuIGVuIGZpbiBkZSBzZWNvbmRlIGxpZ25lLCBzdXBlciBpbXBvcnRhbnRlIDogbGEgcC12YWx1ZSAhISEgCiAgIFByb2JhYmlsaXTDqSBxdWUgbGEgdmFsZXVyIGRlIGxhIHN0YXRpc3RpcXVlIHNvaXQgYXUgbW9pbnMgYXVzc2kgZXh0csOqbWUgcXUnb2JzZXJ2w6llLCBzb3VzIEgwLgo0LiB0cm9pc2nDqG1lIGxpZ25lIDogdW4gcmFwcGVsIGRlIGwnaHlwb3Row6hzZSBhbHRlcm5hdGl2ZSBkdSB0ZXN0IChtb2RpZmlhYmxlIGF2ZWMgbCdhcmd1bWVudCBgYWx0ZXJuYXRpdmVgKS4KNS4gdW4gaW50ZXJ2YWxsZSBkZSBjb25maWFuY2Ugw6AgOTUlIGRlIGxhIG1veWVubmUgKGJvcm5lcyBtb2RpZmlhYmxlcyB2aWEgbCdhcmd1bWVudCBgY29uZi5sZXZlbGApLgo2LiB0b3V0IMOgIGxhIGZpbiwgbCdlc3RpbWF0aW9uIHBvbmN0dWVsbGUgZGUgbGEgbW95ZW5uZS4KCj4gUXVlIGNvbmNsdW9ucy1ub3VzID8KCgojIyBUIHRlc3QgOiBjb21wYXJhaXNvbiBkZSAyIG1veWVubmVzCgpPbiBvYnNlcnZlIGRlcyB2YWxldXJzICQoWF97aSxqfSkkIGRlIG5vcyBpbmRpdmlkdXMgJGkkIGRhbnMgZGV1eCBncm91cGVzICRqPTEkIGV0ICRqPTIkLiAKSWNpIGxlcyBkZXV4IGdyb3VwZXMgY29ycmVzcG9uZGVudCBhdSBjb250cm9sIHZzLiB0cmVhdG1lbnQsIApldCBsZXMgb2JzZXJ2YXRpb25zIGNvcnJlc3BvbmRlbnQgw6AgdW5lIGRpZmbDqXJlbmNlIGRlIHBvaWRzIGVudHJlIGxlIGTDqWJ1dCBldCBsYSBmaW4gZGUgbCdleHDDqXJpZW5jZS4KCkVzdC1jZSBxdWUgbGEgZGlmZsOpcmVuY2UgZGUgcG9pZHMgbW95ZW5uZSBlc3QgZGlmZsOpcmVudGUgZGFucyBsZXMgZGV1eCBncm91cGVzID8KCk9uIHNvdWhhaXRlIHLDqWFsaXNlciBsZSB0ZXN0IGQnaHlwb3Row6hzZSBzdWl2YW50IDoKCiogSDAgOiBsYSBtb3llbm5lIGRlcyAkKFhfe2ksMX0pJCBlc3QgaWRlbnRpcXVlIMOgIGNlbGxlIGRlcyAkKFhfe2ksMn0pJC4KKiBIMSA6IGxlcyBkZXV4IG1veWVubmVzIHNvbnQgZGlmZsOpcmVudGVzLgoKQ29uZGl0aW9ucyBkJ2FwcGxpY2F0aW9uIDoKCiogbGVzIHZhcmlhYmxlcyBhbMOpYXRvaXJlcyBzb250IGluZMOpcGVuZGFudGVzIGV0IGRlIG3Dqm1lIGxvaS4KKiBzb2l0IGxlcyB2YXJpYWJsZXMgYWzDqWF0b2lyZXMgc29udCBkaXN0cmlidcOpZXMgbm9ybWFsZW1lbnQsIHNvaXQgbCfDqWNoYW50aWxsb24gZXN0ICJncmFuZCIuCgpPbiBjb21tZW5jZSB0b3Vqb3VycyBwYXIgcmVwcsOpc2VudGVyIG5vcyBkb25uw6llcyBldCBxdWFudGl0w6lzIGQnaW50w6lyw6p0LgoKYGBge3IgZmlnLndpZHRoPTEwfQptIDwtIGQgJT4lIGdyb3VwX2J5KGdyb3VwKSAlPiUgc3VtbWFyaXNlKG1lYW49bWVhbihkaWZmX3dlaWdodCkpICU+JSBzZWxlY3QobWVhbikKCnBsb3RfZGlmZl93ZWlnaHRfYnlfZ3JvdXAgPC0gZCAlPiUgZ2dwbG90KGFlcyh4PWRpZmZfd2VpZ2h0LCBmaWxsPWdyb3VwKSkgKwogICAgZ2VvbV9oaXN0b2dyYW0oYWxwaGE9MC41LCBwb3NpdGlvbj0iaWRlbnRpdHkiLCBiaW5zPTIwKSArCiAgICB0aGVtZV9idygpICsKICAgIHlsYWIoImVmZmVjdGlmIikgKyAKICAgIHhsYWIoImRpZmbDqXJlbmNlIGRlIHBvaWRzIMOgIDYgbW9pcyIpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKGJsZXVjbGFpciwgcm9zZSkpICsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMobSRtZWFuWzFdLCBtJG1lYW5bMl0pLCBjb2xvcj1jKGJsZXVjbGFpciwgcm9zZSkpCnBsb3RfZGlmZl93ZWlnaHRfYnlfZ3JvdXAKYGBgCgpJY2kgbGVzIGNvbmRpdGlvbnMgZCdhcHBsaWNhdGlvbiBzZW1ibGVudCByZXNwZWN0w6llcy4KClVuIHLDqXN1bHRhdCB0aMOpb3JpcXVlIGNlcnRpZmllIHF1J3VuZSBzdGF0aXN0aXF1ZSBkZSB0ZXN0IGNhbGN1bMOpZSDDoCBwYXJ0aXIgZGUgbCdlZmZlY3RpZiwgCmRlcyBtb3llbm5lcyBlbXBpcmlxdWVzIGRlcyBkZXV4IGdyb3VwZXMgZXQgZGUgbGEgdmFyaWFuY2UgZW1waXJpcXVlIGRlcyBkZXV4IGdyb3VwZXMsIAplc3QgZGlzdHJpYnXDqWUgc3VpdmFudCB1bmUgbG9pIGRlIFN0dWRlbnQgYXZlYyB1biBjZXJ0YWluIG5vbWJyZSBkZSAiZGVncsOpcyBkZSBsaWJlcnTDqSIuCgpJbCBzJ2FnaXQgZG9uYyBkZSBjYWxjdWxlciBsYSB2YWxldXIgb2JzZXJ2w6llIGRlIGNldHRlIHN0YXRpc3RpcXVlIGRlIHRlc3Qgc3VyIG5vdHJlIMOpY2hhbnRpbGxvbiwgCmV0IGRlIGxhIGNvbXBhcmVyIGF1eCBxdWFudGlsZXMgZGUgbGEgbG9pIHRow6lvcmlxdWUuCgpMYSBmb25jdGlvbiBwb3VyIGZhaXJlIMOnYSBlbiBSIGVzdCBsYSBzdWl2YW50ZSA6CgpgYGB7cn0KdC50ZXN0KGRpZmZfd2VpZ2h0IH4gZ3JvdXAsIGRhdGE9ZCkKYGBgCgpDYSBzZSBsaXQgZGUgZmHDp29uIHRyw6hzIHNpbWlsYWlyZSDDoCBjZSBxdSdvbiBhdmFpdCBwcsOpY8OpZGVtbWVudCwgbGVzIGRpZmbDqXJlbmNlcyDDqXRhbnQgOgoKMS4gTCdJQyDDoCA5NSUgY29ycmVzcG9uZCDDoCBjZWx1aSBkZSBsYSBkaWZmw6lyZW5jZSBkZXMgZGV1eCBtb3llbm5lcy4KMi4gTGVzIGVzdGltYXRpb25zIHBvbmN0dWVsbGVzIGNvcnJlc3BvbmRlbnQgYXV4IGRldXggbW95ZW5uZXMuCgo+IFF1ZSBjb25jbHVvbnMtbm91cyA/CgoKIyMgQU5PVkEgOiBjb21wYXJhaXNvbiBkZSBuIG1veWVubmVzCgpPbiBzb3VoYWl0ZSBwbHVzIHByw6ljaXPDqW1lbnQgdGVzdGVyIGljaSBsYSBkaWZmw6lyZW5jZSBkJ2F1IG1vaW5zIHVuZSBtb3llbm5lIHBhcm1pIHBsdXNpZXVycyBncm91cGVzLgoKT24gZGlzcG9zZSBjZXR0ZSBmb2lzIGQnb2JzZXJ2YXRpb25zIGRlIGxhIG3Dqm1lIHF1YW50aXTDqSAkKFhfe2ksan0pIGNoZXogbCdpbmRpdmlkdSAkaSQgZGFucyBsZSBncm91cGUgJGokLCAKZGFucyB1biBub21icmUgZGUgZ3JvdXBlcyBwb3RlbnRpZWxsZW1lbnQgc3Vww6lyaWV1ciDDoCAyLgpFc3QtY2UgcXVlIGxhIG1veWVubmUgZCdhdSBtb2lucyB1biBncm91cGUgZGlmZsOocmUgZGVzIGF1dHJlcyBncm91cGVzID8KClBhciBleGVtcGxlLCBpY2ksIGxhIGRpZmbDqXJlbmNlIGRlIHBvaWRzIG1veWVubmUgY2hhbmdlLXQtZWxsZSBkYW5zIGxlcyB0cm9pcyBjbGFzc2VzIGQnw6JnZSA/ICg8IDQwLCA0MC02MCwgPiA2MCkKCk9uIHRlc3RlIGZvcm1lbGxlbWVudCA6CgoqIEgwIDogbGVzIG1veWVubmVzIGRlcyAkKFhfe2ksMX0pJCwgZGVzICQoWF97aSwyfSkkIGV0IGRlcyAkKFhfe2ksM30pJCBzb250IGlkZW50aXF1ZXMuCiogSDEgOiBhdSBtb2lucyB1bmUgZGVzIG1veWVubmVzIGRpZmbDqHJlLgoKQ29uZGl0aW9ucyBkJ2FwcGxpY2F0aW9uIDoKCiogbGVzIHZhcmlhYmxlcyBhbMOpYXRvaXJlcyBzb250IGluZMOpcGVuZGFudGVzIGV0IHN1aXZlbnQgdW5lIGxvaSBub3JtYWxlLgoqIGlsIHkgYSDDqWdhbGl0w6kgZGUgdmFyaWFuY2UgZW50cmUgbGVzIGRpZmbDqXJlbnRzIGdyb3VwZXMuCgpVbmUgZm9pcyBuJ2VzdCBwYXMgY291dMO7bWUsIGNvbW1lbsOnb25zIHBhciByZXByw6lzZW50ZXIgbGVzIGRvbm7DqWVzIDoKCmBgYHtyIGZpZy53aWR0aD0xMH0KbSA8LSBkICU+JSBncm91cF9ieShhZ2VfZ3JvdXApICU+JSBzdW1tYXJpc2UobWVhbj1tZWFuKGRpZmZfd2VpZ2h0KSkgJT4lIHNlbGVjdChtZWFuKQoKcGxvdF9kaWZmX3dlaWdodF9ieV9hZ2VfZ3JvdXAgPC0gZCAlPiUgZ2dwbG90KGFlcyh4PWRpZmZfd2VpZ2h0LCBmaWxsPWFzLmZhY3RvcihhZ2VfZ3JvdXApKSkgKwogICAgZ2VvbV9oaXN0b2dyYW0oYWxwaGE9MC41LCBwb3NpdGlvbj0iaWRlbnRpdHkiLCBiaW5zPTIwKSArCiAgICB0aGVtZV9idygpICsKICAgIHlsYWIoImVmZmVjdGlmIikgKyAKICAgIHhsYWIoImRpZmbDqXJlbmNlIGRlIHBvaWRzIMOgIDYgbW9pcyIpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKGJsZXVmb25jZSwgYmxldWNsYWlyLCByb3NlKSkgKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYyhtJG1lYW5bMV0sIG0kbWVhblsyXSwgbSRtZWFuWzNdKSwgY29sb3I9YyhibGV1Zm9uY2UsIGJsZXVjbGFpciwgcm9zZSkpCnBsb3RfZGlmZl93ZWlnaHRfYnlfYWdlX2dyb3VwCmdnc2F2ZSgiLi4vLi4vRmlndXJlcy9pbGx1X2RpYWJldGVfZGlmZl93ZWlnaHRfYWdlX2dyb3VwLnBkZiIsIHBsb3Q9cGxvdF9kaWZmX3dlaWdodF9ieV9hZ2VfZ3JvdXAsIHdpZHRoPTEyLCBoZWlnaHQ9NSkKYGBgCgpMZXMgY29uZGl0aW9ucyBkJ2FwcGxpY2F0aW9uIHNlbWJsZW50IHJlc3BlY3TDqWVzIChhdSBtb2lucyBncmFwaGlxdWVtZW50KS4KClVuIHLDqXN1bHRhdCB0aMOpb3JpcXVlIGNlcnRpZmllIGNldHRlIGZvaXMgcXUndW5lIGNlcnRhaW5lIHN0YXRpc3RpcXVlIGRlIHRlc3QsIApjYWxjdWzDqWUgw6AgcGFydGlyIDoKCiogZGVzIGVmZmVjdGlmcyBkZXMgZGlmZsOpcmVudHMgZ3JvdXBlcwoqIGV0IGRlcyB2YXJpYW5jZXMgaW50cmEtZ3JvdXBlcyAvIGludGVyLWdyb3VwZXMsCgplc3QgZGlzdHJpYnXDqWUgc3VpdmFudCB1bmUgbG9pIGRlIEZpc2hlciBhdmVjIHVuIGNlcnRhaW4gbm9tYnJlIGRlICJkZWdyw6lzIGRlIGxpYmVydMOpIi4KCklsIHMnYWdpdCBkb25jIGRlIGNhbGN1bGVyIGxhIHZhbGV1ciBvYnNlcnbDqWUgZGUgY2V0dGUgc3RhdGlzdGlxdWUgZGUgdGVzdCBzdXIgbm90cmUgw6ljaGFudGlsbG9uLCAKZXQgZGUgbGEgY29tcGFyZXIgYXV4IHF1YW50aWxlcyBkZSBsYSBsb2kgdGjDqW9yaXF1ZS4KCkxhIGZvbmN0aW9uIHBvdXIgZmFpcmUgw6dhIGVuIFIgZXN0IGxhIHN1aXZhbnRlIDoKCmBgYHtyfQpyZXNfYW92IDwtIGFvdihkaWZmX3dlaWdodCB+IGFnZV9ncm91cCwgZGF0YT1kKQpzdW1tYXJ5KHJlc19hb3YpCmBgYAoKTGVzIGRldXggcG9pbnRzIGxlcyBwbHVzIGludMOpcmVzc2FudHMgZGUgbCdvdXRwdXQgc29udCA6CgoxLiBsYSAiRiB2YWx1ZSIgcXVpIGVzdCBsYSB2YWxldXIgZGUgbGEgc3RhdGlzdGlxdWUgZGUgdGVzdCwKMi4gZXQgbGEgcC12YWx1ZSA6IGxhIHByb2JhYmlsaXTDqSBzb3VzIEgwIGQnb2J0ZW5pciB1bmUgc3RhdGlzdGlxdWUgZGUgdGVzdCBhdSBtb2lucyBhdXNzaSBleHRyw6ptZSBxdSdvYnNlcnbDqWUuCgo+IFF1ZSBjb25jbHVvbnMtbm91cyA/CgpGaW5pc3NvbnMgcGFyIHVuIHBldGl0IHRlc3QsIHBlcm1ldHRhbnQgZGUgc2UgY29udmFpbmNyZSBxdSd1bmUgQU5PVkEgYXZlYyBkZXV4IGdyb3VwZXMgY29ycmVzcG9uZCDDoCB1biBUIHRlc3QuCgpgYGB7cn0KcmVzX2Fvdl8yIDwtIGFvdihkaWZmX3dlaWdodCB+IGdyb3VwLCBkYXRhPWQpCnN1bW1hcnkocmVzX2Fvdl8yKQp0LnRlc3QoZGlmZl93ZWlnaHQgfiBncm91cCwgZGF0YT1kKQpgYGAKCgojIyBUZXN0IGRlIFdpbGNveG9uCgpMJ2FsdGVyLWVnbyBub24tcGFyYW3DqXRyaXF1ZSBkdSBUIHRlc3QgZXN0IGxlIHRlc3QgZGUgV2lsY294b24KKGF1c3NpIGFwcGVsw6kgTWFubi1XaGl0bmV5IG91IFdpbGNveG9uLU1hbm4tV2hpdG5leSkuCgoqIEF2YW50YWdlIDogY29uZGl0aW9ucyBkJ2FwcGxpY2F0aW9uIHRvdWpvdXJzIHJlbXBsaWVzLgoqIEluY29udsOpbmllbnQgOiBtb2lucyBwdWlzc2FudCBxdSd1biBUIHRlc3QuCgpEYW5zIG5vdHJlIGNhcywgw6l0YW50IGRvbm7DqSBsZSBncmFuZCBlZmZlY3RpZiBkZSBub3RyZSBlc3NhaSBjbGluaXF1ZSwKbGUgVCB0ZXN0IMOpdGFpdCB1biBjaG9peCB0csOocyBhcHByb3ByacOpLgpPbiBwZXV0IGNlcGVuZGFudCBzZSBjb252YWluY3JlIGR1IGZvbmN0aW9ubmVtZW50IGQndW4gdGVzdCBkZSBXaWxjb3hvbgplbiBsJ2Vzc2F5YW50IDoKCmBgYHtyfQp3aWxjb3gudGVzdChkaWZmX3dlaWdodCB+IGdyb3VwLCBkYXRhPWQpCmBgYAoKIyMgVGVzdCBkZSBLcnVza2FsLVdhbGxpcwoKRGUgbcOqbWUsIHRlc3RvbnMgbCd1dGlsaXNhdGlvbiBkZSBsJ2FsdGVyLWVnbyBkZSBsJ0FOT1ZBIGVuIHZlcnNpb24gbm9uLXBhcmFtw6l0cmlxdWUgOgoKYGBge3J9CmtydXNrYWwudGVzdChkaWZmX3dlaWdodCB+IGFnZV9ncm91cCwgZGF0YT1kKQpgYGAKCk9uIHNlIGNvbnZhaW5jIGF1c3NpIGZhY2lsZW1lbnQgcXUndW4gdGVzdCBkZSBLcnVza2FsLVdhbGxpcyBhdmVjIHVuZSB2YXJpYWJsZQrDoCBkZXV4IG1vZGFsaXTDqXMgcmV2aWVudCDDoCBmYWlyZSB1biB0ZXN0IGRlIFdpbGNveG9uIDoKCmBgYHtyfQprcnVza2FsLnRlc3QoZGlmZl93ZWlnaHQgfiBncm91cCwgZGF0YT1kKQpgYGAKCgojIFLDqWdyZXNzaW9uIGxpbsOpYWlyZSB1bml2YXJpw6llCgojIyBVbmUgZHJvaXRlIGRlIHLDqWdyZXNzaW9uIGNvbW11bmUKCk9uIGRpc3Bvc2UgY2V0dGUgZm9pcyBkJ29ic2VydmF0aW9ucyBkJ3VuZSB2YXJpYWJsZXMgJChZX2kpJCBkJ2ludMOpcsOqdCwgCnBhciBleGVtcGxlIGVuY29yZSB1bmUgZm9pcyBsYSBkaWZmw6lyZW5jZSBkZSBwb2lkcy4gCkV0IGQndW5lIGF1dHJlIHZhcmlhYmxlIHF1YW50aXRhdGl2ZSAkKFhfaSkkIGNvcnJlc3BvbmRhbnQgw6AgcXVlbHF1ZSBjaG9zZSBxdWkgcG91cnJhaXQgw6p0cmUgY29ycsOpbMOpIMOgIG5vcyAkKFlfaSkkLCAKcGFyIGV4ZW1wbGUgaWNpIGxlIHRlbXBzIHBlbmRhbnQgbGVxdWVsIGxlIHBhdGllbnQgYSBzdHJpY3RlbWVudCBvYnNlcnbDqSBzb24gdHJhaXRlbWVudCAoY29tcGxpYW5jZSkuCgpFc3QtY2UgcXVlIGxlIGdhaW4gZGUgcG9pZHMgZMOpcGVuZCBkZSBsYSBjb21wbGlhbmNlLCBkYW5zIGxlIGdyb3VwZSB0cmFpdMOpID8KCkxlIGNvZWZmaWNpZW50IGRlIGNvcnLDqWxhdGlvbiAkXHJobyQgY29ycmVzcG9uZCDDoCBsYSBjb3ZhcmlhbmNlIGRlcyBkZXV4IHF1YW50aXTDqXMgbm9ybWFsaXPDqWUgcGFyIGxlcyDDqWNhcnRzLXR5cGVzIGRlcyBkZXV4IHF1YW50aXTDqXMuIApJbCBlc3QgY29tcHJpcyBlbnRyZSAtMSBldCAxIGV0IHJlbnNlaWduZSBzdXIgbGEgZGlzcGVyc2lvbiBkZXMgZG9ubsOpZXMgZW4gMkQuIApFbiBjYXMgZGUgY29ycsOpbGF0aW9uIGxpbsOpYWlyZSBwYXJmYWl0ZSwgaWwgdmF1dCAxIG91IC0xLgoKRm9ybWVsbGVtZW50IG9uIHBldXQgdGVzdGVyLCBhdmVjIGxlIHRlc3QgZGUgQnJhdmFpcy1QZWFyc29uIDoKCiogSDAgOiAkXHJobyA9IDAkLAoqIEgxIDogJFxyaG8gXG5lcSAwJC4KCkNvbmRpdGlvbnMgZCdhcHBsaWNhdGlvbiA6IGxlcyAkKFlfaSwgWF9pKSQgZG9pdmVudCDDqnRyZSBhcHBhcmnDqWVzIGV0IGRpc3RyaWJ1w6llcyBub3JtYWxlbWVudC4KCkNvbW1lbsOnb25zIHBhciByZXByw6lzZW50ZXIgbGVzIGRvbm7DqWVzLCBhdmVjIHVuZSBkcm9pdGUgZGUgcsOpZ3Jlc3Npb24KcGFydGFnw6kgcGFyIHRvdXMgbGVzIHBvaW50cyA6CgpgYGB7ciBmaWcud2lkdGg9MTB9CnBsb3RfZGlmZl93ZWlnaHRfdnNfY29tcGxpYW5jZSA8LSBkICU+JSAKCWdncGxvdChhZXMoeT1kaWZmX3dlaWdodCwgeD10X2NvbXBsaWFuY2UpKSArCiAgICBnZW9tX3BvaW50KCkgKwogICAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIsIHNlPUYsIGZvcm11bGE9InkgfiB4IiwgY29sPWJsZXVmb25jZSkgKwogICAgdGhlbWVfYncoKSArCiAgICB4bGFiKCJ0X2NvbXBsaWFuY2UiKSArIAogICAgeWxhYigiZGlmZsOpcmVuY2UgZGUgcG9pZHMgw6AgNiBtb2lzIikKcGxvdF9kaWZmX3dlaWdodF92c19jb21wbGlhbmNlCmBgYAoKT24gcGV1dCDDoCBwcsOpc2VudCBlZmZlY3R1ZXIgdW4gdGVzdCBkZSBjb3Jyw6lsYXRpb24gZW4gcHJlbmFudCB0b3VzIGxlcyBwb2ludHMgZW5zZW1ibGUgOgoKYGBge3J9CmNvci50ZXN0KGQkZGlmZl93ZWlnaHQsIGQkdF9jb21wbGlhbmNlKQpgYGAKCj4gUXVlIGNvbmNsdW9ucy1ub3VzID8KCgojIyBVbmUgZHJvaXRlIGRhbnMgY2hhcXVlIGdyb3VwZQoKRGV1eGnDqG1lIGVzc2FpIHBsdXMgaW50w6lyZXNzYW50IDogcmVnYXJkZXIgbCdpbmZsdWVuY2UgZGUgYHRfY29tcGxpYW5jZWAKc8OpcGFyw6ltZW50IGRhbnMgbGVzIGRldXggYnJhcyBkZSBsJ2Vzc2FpIGNsaW5pcXVlLgpPbiBjb21tZW5jZSBwYXIgb2JzZXJ2ZXIgbGVzIGRvbm7DqWVzIDoKCmBgYHtyIGZpZy53aWR0aD0xMH0KcGxvdF9kaWZmX3dlaWdodF92c19jb21wbGlhbmNlXzIgPC0gZCAlPiUgCglnZ3Bsb3QoYWVzKHk9ZGlmZl93ZWlnaHQsIHg9dF9jb21wbGlhbmNlLCBjb2xvciA9IGdyb3VwKSkgKwogICAgZ2VvbV9wb2ludCgpICsKICAgIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iLCBzZT1GLCBmb3JtdWxhPSJ5IH4geCIpICsKICAgIHRoZW1lX2J3KCkgKwogICAgeGxhYigidF9jb21wbGlhbmNlIikgKyAKICAgIHlsYWIoImRpZmbDqXJlbmNlIGRlIHBvaWRzIMOgIDYgbW9pcyIpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YyhibGV1Y2xhaXIsIHJvc2UpKQpwbG90X2RpZmZfd2VpZ2h0X3ZzX2NvbXBsaWFuY2VfMgpnZ3NhdmUoIi4uLy4uL0ZpZ3VyZXMvaWxsdV9kaWFiZXRlX2RpZmZfd2VpZ2h0X3JlZ2xpbi5wZGYiLCBwbG90PXBsb3RfZGlmZl93ZWlnaHRfdnNfY29tcGxpYW5jZV8yLCB3aWR0aD0xMiwgaGVpZ2h0PTUpCmBgYAoKUHVpcyB1biB0ZXN0IGRlIGNvcnLDqWxhdGlvbiBlbiBwcmVuYW50IHVuaXF1ZW1lbnQgbGUgZ3JvdXBlIGBjb250cm9sYCA6CgpgYGB7cn0KZF9jb250cm9sIDwtIGQgJT4lIGZpbHRlcihncm91cCA9PSAiY29udHJvbCIpCmNvci50ZXN0KGRfY29udHJvbCRkaWZmX3dlaWdodCwgZF9jb250cm9sJHRfY29tcGxpYW5jZSkKYGBgCgpFdCBlbmZpbiwgbGUgbcOqbWUgdGVzdCBkZSBjb3Jyw6lsYXRpb24gZW4gcHJlbmFudCB1bmlxdWVtZW50IGxlIGdyb3VwZSBgdHJlYXRtZW50YCA6CgpgYGB7cn0KZF90cmVhdG1lbnQgPC0gZCAlPiUgZmlsdGVyKGdyb3VwID09ICJ0cmVhdG1lbnQiKQpjb3IudGVzdChkX3RyZWF0bWVudCRkaWZmX3dlaWdodCwgZF90cmVhdG1lbnQkdF9jb21wbGlhbmNlKQpgYGAKCj4gUXVlIGNvbmNsdW9ucy1ub3VzID8KCgojIExlIG1vZMOobGUgbGluw6lhaXJlCgojIyBEZXNjcmlwdGlvbgoKTGUgbW9kw6hsZSBsaW7DqWFpcmUgcHLDqXNlbnRlIGwnaW50w6lyw6p0IGQndW5pZmllciB0b3VzIGNlcyB0ZXN0cyBkYW5zIHVuIHVuaXF1ZSBmcmFtZXdvcmsuCgpJbCBjb25zaXN0ZSDDoCBtb2TDqWxpc2VyIHVuZSAqdmFyaWFibGUgZGUgcsOpcG9uc2UqICRZX2kkIGNoZXogbCdpbmRpdmlkdSAkaSQgCmNvbW1lIHVuZSBmb25jdGlvbiBsaW7DqWFpcmUgZGUgbm9zICp2YXJpYWJsZXMgZXhwbGljYXRyaWNlcyogJFhfe2ksan0kLCAKw6AgbGFxdWVsbGUgb24gcmFqb3V0ZSB1biAqYnJ1aXQqIEdhdXNzaWVuIGNlbnRyw6kuIApVbmUgZm9uY3Rpb24gbGluw6lhaXJlIG4nZXN0IHJpZW4gZGUgcGx1cyBxdSd1bmUgc29tbWUgcG9uZMOpcsOpZSBkZSBub3MgdmFyaWFibGVzICRYX3tpLGp9JCwgc29pdCA6CgokJCAKWV9pID0gYV8xIFhfe2ksMX0gKyBhXzIgWF97aSwyfSArIC4uLiArIGFfSiBYX3tpLEp9ICsgXGVwc2lsb25faSwgfn5+XHRleHR7IGF2ZWMgfSBcZXBzaWxvbl9pIFxzaW0gXG1hdGhjYWx7Tn0oMCwgXHNpZ21hXjIpCiQkCgpPbiBzdXBwb3NlIHF1ZSB0b3VzIGxlcyAkKFlfaSkkIHNvbnQgaW5kw6lwZW5kYW50ZXMgZXQgc3VpdmVudCBsYSBtw6ptZSBsb2kuCkxlIGJ1dCBkdSBqZXUsIHBvdXIgbGUgc3RhdGlzdGljaWVuLCBjb25zaXN0ZSDDoCBmaXR0ZXIgbGVzIHZhbGV1cnMgZGVzIGNvZWZmaWNpZW50cyAkYV9qJCBncsOiY2UgYXV4IG9ic2VydmF0aW9ucy4KCkJvbm5lIG5vdXZlbGxlIDogbGEgc3ludGF4ZSBkZSBSIHBvdXIgZml0dGVyIHVuIG1vZMOobGUgbGluw6lhaXJlIGVzdCBhc3NleiByYXBpZGUgZXQgaW50dWl0aXZlLgoKIyMgVW4gc2ltcGxlIGludGVyY2VwdAoKUHJlbWllciBjYXMgc2ltcGxlIDogb24gYWltZXJhaXQgbW9kw6lsaXNlciBsYSBkaWZmw6lyZW5jZSBkZSBwb2lkcyBjb21tZSDDqXRhbnQgdW5pcXVlbWVudCB1bmUgbW95ZW5uZSArIHVuIHBldGl0IGJydWl0IEdhdXNzaWVuLCAKZXQgY2FsY3VsZXIgY2V0dGUgbW95ZW5uZSBjb21tZSBvbiBsJ2F2YWl0IGZhaXQgbG9ycyBkdSBwcmVtaWVyIHRlc3QgZGUgU3R1ZGVudC4KCmBgYHtyfQpyZXNfbG1fMSA8LSBsbShmb3JtdWxhPSJkaWZmX3dlaWdodCB+IDEiLCBkYXRhPWQpCnN1bW1hcnkocmVzX2xtXzEpCmBgYAoKPiBWw6lyaWZpZXIgcXUnb24gcmV0b21iZSBiaWVuIHN1ciBsYSBtw6ptZSBjaG9zZSBxdWUgcHLDqWPDqWRlbW1lbnQuCgojIyBVbiBlZmZldCBkZSB2YXJpYWJsZSBkaXNjcsOodGUKCkRldXhpw6htZSBjYXMgc2ltcGxlIDogb24gYWltZXJhaXQgbW9kw6lsaXNlciBsYSBkaWZmw6lyZW5jZSBkZSBwb2lkcyBjb21tZSDDqXRhbnQgCmxhIHNvbW1lIGQndW4gY29lZmZpY2llbnQgcGFydGljdWxpZXIgY2hleiBsZXMgaW5kaXZpZHVzIGR1IGdyb3VwZSAiY29udHJvbCIgCmV0IHVuIGF1dHJlIGNvZWZmaWNpZW50IGNoZXogbGVzIGluZGl2aWR1cyBkdSBncm91cGUgInRyZWF0bWVudCIuIApTb2l0IGV4YWN0ZW1lbnQgY2UgcXUnb24gYXZhaXQgZmFpdCBhdmVjIHVuIHRlc3QgZGUgU3R1ZGVudCBjb21wYXJhbnQgbGVzIGRldXggbW95ZW5uZXMuCgpJbCBzZSB0cm91dmUgcXVlIFIsIGxvcnNxdSdvbiBsdWkgZG9ubmUgw6AgbWFuZ2VyIHVuZSB2YXJpYWJsZSDDoCBwbHVzaWV1cnMgbW9kYWxpdMOpcywgCnZhIGF1dG9tYXRpcXVlbWVudCBsYSAic2NpbmRlciIgZW4gc291cy12YXJpYWJsZXMgaW5kaWNhdHJpY2VzIGRlIGNoYXF1ZSBtb2RhbGl0w6kuIApMYSBzeW50YXhlIHJlc3RlIGRvbmMgdHLDqHMgc2ltcGxlIDoKCmBgYHtyfQojIHByZW1pw6hyZSB2ZXJzaW9uIGF2ZWMgbW95ZW5uZSBjb21tdW5lIGF1eCBkZXV4IGdyb3VwZXMKIyBldCB1biBwZXRpdCBham91dCBwb3VyIGxlIGdyb3VwZSB0cmFpdGVtZW50CnJlc19sbV9ncm91cCA8LSBsbShmb3JtdWxhPSJkaWZmX3dlaWdodCB+IGdyb3VwIiwgZGF0YT1kKQpzdW1tYXJ5KHJlc19sbV9ncm91cCkKYGBgCgpgYGB7cn0KIyBkZXV4acOobWUgdmVyc2lvbiBhdmVjIG1veWVubmUgZGFucyBjaGFxdWUgZ3JvdXBlCnJlc19sbV9ncm91cF8yIDwtIGxtKGZvcm11bGE9ImRpZmZfd2VpZ2h0IH4gMCArIGdyb3VwIiwgZGF0YT1kKQpzdW1tYXJ5KHJlc19sbV9ncm91cF8yKQpgYGAKCk9uIGEgZG9uYyBleGFjdGVtZW50IGxlIG3Dqm1lIG1vZMOobGUgc291cy1qYWNlbnQsIGF2ZWMgZGVzIGVzdGltYXRpb25zIGRlIHBhcmFtw6h0cmVzIGlkZW50aXF1ZXMuIApDZXBlbmRhbnQsIGljaSwgbGVzIHAtdmFsdWUgaW5kaXF1w6llcyBjb3JyZXNwb25kZW50IMOgIHVuIHRlc3QgZCdhZMOpcXVhdGlvbiBkdSBwYXJhbcOodHJlIMOgIDAuIApTaSBvbiBzb3VoYWl0ZSBjb21wYXJlciBsZXMgZGV1eCBtb3llbm5lcyBldCByZXRvbWJlciBzdXIgbGUgbcOqbWUgcsOpc3VsdGF0IHF1J2F1IGTDqWJ1dCBkdSBkb2N1bWVudCwgCmlsIGZhdXQgZG9uYyBwYXNzZXIgcGFyIGxhIHByZW1pw6hyZSB2ZXJzaW9uIGV0IHJlZ2FyZGVyIGxlIHRlc3QgZCdhZMOpcXVhdGlvbiBkdSBwYXJhbcOodHJlIMOgIDAuCgpUcm9pc2nDqG1lIHBvc3NpYmlsaXTDqSwgbm90cmUgZGlmZsOpcmVuY2UgZGUgcG9pZHMgZMOpcGVuZCBkJ3VuZSB2YXJpYWJsZSBwcmVuYW50IDMgbW9kYWxpdMOpcyBvdSBwbHVzIAooY29tbWUgb24gYXZhaXQgcHJvcG9zw6kgbG9ycyBkZSBsYSByw6lhbGlzYXRpb24gZHUgdGVzdCBBTk9WQSBjaS1kZXNzdXMpLiAKTGEgbcOqbWUgc3ludGF4ZSBmb25jdGlvbm5lIHRvdWpvdXJzIGF1c3NpIGJpZW4gOgoKYGBge3J9CnJlc19sbV9ncm91cF8zIDwtIGxtKGZvcm11bGE9ImRpZmZfd2VpZ2h0IH4gMCArIGFnZV9ncm91cCIsIGRhdGE9ZCkKc3VtbWFyeShyZXNfbG1fZ3JvdXBfMykKYGBgCgpMJ291dHB1dCBzdGFuZGFyZCBkdSBtb2TDqGxlIGxpbsOpYWlyZSBuZSBub3VzIGNhbGN1bGUgZGVzIHAtdmFsdWVzCnF1ZSBwb3VyIGxlcyB0ZXN0cyBkJ2Fkw6lxdWF0aW9uIGRlIGNoYXF1ZSBwYXJhbcOodHJlIMOgIDAuCkJpZW4gcXVlIGwnQU5PVkEgc29pdCBlZmZlY3RpdmVtZW50IHVuIHRlc3QgcsOpYWxpc8OpIGF1IHNlaW4gZHUgbcOqbWUKZnJhbWV3b3JrIGRlIG1vZMOobGUgbGluw6lhaXJlLCBsYSBwLXZhbHVlIGFzc29jacOpZSBuJ2VzdCByw6ljdXDDqXJhYmxlLAplbiBwcmF0aXF1ZSBhdmVjIFIsIHF1ZSB2aWEgbGEgZm9uY3Rpb24gYGFvdmAgdnVlIHByw6ljw6lkZW1tZW50LgoKIyMgVW4gZWZmZXQgZGUgdmFyaWFibGUgY29udGludWUKCkRlcm5pZXIgZXhlbXBsZSBzaW1pbGFpcmUgw6AgY2UgcXUnb24gYXZhaXQgZmFpdCBwcsOpY8OpZGVtbWVudCA6IApleHBsaXF1ZXIgbm90cmUgdmFyaWFibGUgZGUgcsOpcG9uc2UgImRpZmbDqXJlbmNlIGRlIHBvaWRzIiBwYXIgbGUgInRlbXBzIGRlIGNvbXBsaWFuY2UiLgoKYGBge3J9CnJlc19sbV9jb21wbGlhbmNlIDwtIGxtKGZvcm11bGE9ImRpZmZfd2VpZ2h0IH4gdF9jb21wbGlhbmNlIiwgZGF0YT1kKQpzdW1tYXJ5KHJlc19sbV9jb21wbGlhbmNlKQpgYGAKCiMjIFZlcnMgcGx1cyBkZSBjb21wbGV4aWZpY2F0aW9uCgpFdCBzaSBvbiBzb3VoYWl0ZSB1biBlZmZldCBhZGRpdGlmIGR1IGdyb3VwZSBldCBkdSB0ZW1wcyBkZSBjb21wbGlhbmNlIDoKCmBgYHtyfQpyZXNfbG1fY29tcGxpYW5jZV9ncm91cCA8LSBsbShmb3JtdWxhPSJkaWZmX3dlaWdodCB+IDAgKyBncm91cCArIHRfY29tcGxpYW5jZSIsIGRhdGE9ZCkKc3VtbWFyeShyZXNfbG1fY29tcGxpYW5jZV9ncm91cCkKYGBgCgpDZSBuJ2VzdCBwYXMgZXhhY3RlbWVudCBjZSBxdSdvbiBhdmFpdCBmYWl0IHRvdXQgw6AgbCdoZXVyZSBzdXIgbGUgZ3JhcGhlIDogCm9uIGF2YWl0IGFsb3JzIGRldXggcsOpZ3Jlc3Npb25zIGxpbsOpYWlyZXMsIHVuZSBkYW5zIGNoYXF1ZSBncm91cGUuIApSIHBvc3PDqGRlIGVuY29yZSB1bmUgZm9pcyB1bmUgc3ludGF4ZSBwcmF0aXF1ZSBwb3VyIMOnYSA6CgpgYGB7cn0KcmVzX2xtX2NvbXBsaWFuY2VfZ3JvdXBfMiA8LSBsbShmb3JtdWxhPSJkaWZmX3dlaWdodCB+IDAgKyBncm91cCAqIHRfY29tcGxpYW5jZSIsIGRhdGE9ZCkKc3VtbWFyeShyZXNfbG1fY29tcGxpYW5jZV9ncm91cF8yKQpgYGAKCk9uIGEgaW50cm9kdWl0IHN1cGVyIGZhY2lsZW1lbnQgY2UgcXUnb24gYXBwZWxsZSBkZXMgKmludGVyYWN0aW9ucyogZW50cmUgbm9zIHZhcmlhYmxlcy4KTGUgbW9kw6hsZSBsaW7DqWFpcmUsIGV0IGxhIHN5bnRheGUgZGUgUiwgc29udCBkb25jIGRlcyBvdXRpbHMgZGUgbW9kw6lsaXNhdGlvbiBleHRyw6ptZW1lbnQgcHVpc3NhbnRzL3ZlcnNhdGlsZXMuCklscyBkZW1hbmRlbnQgw6AgYmllbiByw6lmbMOpY2hpciBlbiBhbW9udCDDoCBjZSBxdSdvbiBzb3VoYWl0ZSDDqXR1ZGllciAKcG91ciDDqXZpdGVyIHVuZSB0cm9wIGdyYW5kZSBtdWx0aXBsaWNhdGlvbiBkZSB0ZXN0cyBzdGF0aXN0aXF1ZXMuCgo+IFF1ZWwgc2VyYWl0IHNlbG9uIHZvdXMgbGUgbW9kw6hsZSBsaW7DqWFpcmUgbGUgcGx1cyBhcHByb3ByacOpIHBvdXIgYGRpZmZfd2VpZ2h0YCA/Cgo+IFF1ZWwgc2VyYWl0IHNlbG9uIHZvdXMgbGUgbW9kw6hsZSBsaW7DqWFpcmUgbGUgcGx1cyBhcHByb3ByacOpIHBvdXIgYGRpZmZfc3RlcHNgID8KCiMgQ29uY2x1c2lvbgoKTm91cyBhdm9ucyB2dSBpY2kgdW4gY2VydGFpbiBub21icmUgZGUgbcOpdGhvZGVzIHBlcm1ldHRhbnQgZCdhbmFseXNlciBkZXMgdmFyaWFibGVzIGNvbnRpbnVlcy4KTGVzIHBvaW50cyBwcmluY2lwYXV4IMOgIHJldGVuaXIgc29udCBsZXMgc3VpdmFudHMgOgoKMS4gUG91ciBjb21wYXJlciBkZXV4IG1veWVubmVzLCBvdSB1bmUgbW95ZW5uZSDDoCB1bmUgbm9ybWUsIGxlIFQgdGVzdCBlc3QgbGEgYm9ubmUgb3B0aW9uLAogICDDoCBjb25kaXRpb24gcXVlIGxlcyBkb25uw6llcyBzb2llbnQgZW4gZ3JhbmQgbm9tYnJlLCBvdSBxdSdlbGxlcyBzb2llbnQgZGlzdHJpYnXDqWVzIG5vcm1hbGVtZW50LgoyLiBQb3VyIGNvbXBhcmVyIHBsdXMgcXVlIGRldXggbW95ZW5uZXMsIHVuZSBBTk9WQSBmYWl0IGwnYWZmYWlyZSwgc291cyBkZXMgY29uZGl0aW9ucyBpZGVudGlxdWVzLgozLiBMb3JzcXVlIGxlcyBjb25kaXRpb25zIGQnYXBwbGljYXRpb24gZGVzIHRlc3RzIHBhcmFtw6l0cmlxdWVzIG5lIHNvbnQgcGFzIHJlbmNvbnRyw6llcywKICAgb24gcGV1dCByZWNvdXJpciDDoCBkZXMgdGVzdHMgbm9uLXBhcmFtw6l0cmlxdWVzIDogV2lsY294b24gZXQgS3J1c2thbC1XYWxsaXMuCjQuIFBvdXIgcXVhbnRpZmllciBsYSBjb3Jyw6lsYXRpb24gZW50cmUgZGV1eCB2YXJpYWJsZXMgY29udGludWVzIGRpc3RyaWJ1w6llcyBub3JtYWxlbWVudCwKICAgdW4gdGVzdCBkZSBjb3Jyw6lsYXRpb24gZGUgUGVhcnNvbiBwZXV0IMOqdHJlIHV0aWxpc8OpLgo1LiBMZSBtb2TDqGxlIGxpbsOpYWlyZSB1bmlmaWUgdG91cyBsZXMgdGVzdHMgcGFyYW3DqXRyaXF1ZXMgcHLDqWPDqWRlbnRzIGRhbnMgdW4gdW5pcXVlIGZyYW1ld29yaywKICAgb8O5IHVuZSB2YXJpYWJsZSBkZSByw6lwb25zZSBjb250aW51ZSAkWSQgZXN0IG1vZMOpbGlzw6llIGNvbW1lIHVuZSBjb21iaW5haXNvbiBsaW7DqWFpcmUKICAgZGUgdmFyaWFibGVzIGV4cGxpY2F0aXZlcyAkWCQgKGRpc2Nyw6h0ZXMgb3UgY29udGludWVzKS4KCgo=