Manipuler la base de données

Charger des données dans R

Nous allons charger les données depuis un fichier [disque dur] dans notre environnement R [mémoire vive] :

library(tidyverse)
# Charger des données dans la variable cpes
cpes <- read_csv("./cpes_quanti/bdd_alimentation.csv")
Parsed with column specification:
cols(
  .default = col_character(),
  ne.annee = col_integer(),
  cpes.promo = col_integer(),
  bac.annee = col_integer(),
  bourse = col_integer(),
  repas.qui.seul.midi = col_integer(),
  repas.qui.seul.soir = col_integer(),
  repas.qui.cpes.midi = col_integer(),
  repas.qui.copain.midi = col_integer(),
  repas.qui.copain.soir = col_integer(),
  repas.qui.amis.midi = col_integer(),
  repas.qui.parents.midi = col_integer(),
  repas.qui.parents.soir = col_integer(),
  repas.qui.famille.midi = col_integer(),
  repas.qui.famille.soir = col_integer(),
  repas.qui.autre = col_integer(),
  repas.travail.midi = col_integer(),
  repas.travail.soir = col_integer(),
  repas.abs.midi = col_integer(),
  repas.abs.soir = col_integer(),
  repas.abs.temps = col_integer()
  # ... with 42 more columns
)
See spec(...) for full column specifications.
cpes$genre <- as.factor(cpes$genre)

Nota Bene :

  • Le chemin entre guillemets s’exprime différement selon le système d’exploitation. Si vous n’êtes pas encore à l’aise avec la ligne de commande, vous pouvez passer par l’exploreur graphique.
  • Préférez les chemins relatifs à votre fichier (“./bdd_alimentation.csv”) plutôt qu’absolu (“/home/nom/dossier/bdd_alimentation.csv”)
  • Au besoin, on peut utiliser les commandes getwd() et setwd() pour configurer le dossier de travail (working directory)

On peut vérifier que les données sont bien chargées :

# Visualiser les données comme dans un tableur
View(cpes)

Statistiques descriptives univariées

Décrire ses données ne signifie pas les restituer, mais synthétiser des informations pour en tirer une vision d’ensemble.

Qu’est-ce que décrire en statistiques ?

Statistique descriptive : ensemble des méthodes statistiques synthétisant les données afin de décrire une population.

La statistique descriptive permet donc de passer des données atomisées (au niveau de l’individu) aux données agrégées (au niveau de la population).

Elle s’oppose à la statistique inférentielle qui appartien à un régime explicatif.

La statistique descriptive

On peut décrire :

  • une seule variable : statistique descriptive univariées (ce cours)
  • deux variables : statistique descriptive bivariée (semaine prochaine)
  • plusieurs variables : statistique descriptive multidimensionnelle

Les méthodes de la statistique descriptive comprennent :

  • les tableaux
  • les diagrammes
  • les paramètres statistiques (valeurs numériques caractéristiques d’une variable quantitative)

Distribution d’une variable

Variable qualitative : tri à plat

Le tri à plat permet de décrire la distribution d’une variable catégorielle. Il s’agit de produire un tableau regroupant l’effectif et la fréquence de chacune des modalités d’une telle variable.

Tableau des effectifs

Effectif : nombre d’observations pour laquelle la variable étudiée prend la modalité en question. (\(n_{modalite}\))

summary(cpes$genre)
femme homme 
   94    34 

Ou :

table(cpes$genre) # "table" = "faire un tableau"

femme homme 
   94    34 

Ou bien, sous forme de diagramme en barres :

plot(cpes$genre) # "plot" = "faire graphique"

Exercice : faire un tri à plat du diplôme de la mère.

Tableau des fréquences

Fréquence : proportion de l’effectif d’une modalité par rapport à l’effectif total. (\(\frac{n_{modalite}}{n}\))

Dans R : “à la main”

table(cpes$genre)/length(cpes$genre)

   femme    homme 
0.734375 0.265625 

Ou avec le package “questionr” :

library("questionr")
freq(cpes$genre)

Niveau expert :

freq(cpes$genre,
     digits = 2, # 2 chiffres après la virgule
     total = TRUE, # Ajouter le total des colonnes
     exclude = NA # Ne pas afficher les NA
     )

Exercice : tri à plat avec fréquences pour la filière du cpes.

Tableau des fréquences cumulées

Lorsque le tri à plat porte sur une variable catégorielle ordonnée (les modalités peuvent être triées dans un ordre logique), le tri à plat peut inclure, outre l’effectif et la fréquence, la fréquence cumulée.

La fréquence cumulée d’une modalité est égale à la somme de sa fréquence et des fréquences de toutes les modalités précédentes dans l’ordre logique de classement des modalités.

pere.dipl <- ordered(cpes$pere.dipl, levels = c("doctorat", "master", "licence", "CAP", "aucun"))
tri.pere.dipl <- freq(pere.dipl, total = TRUE, cum = TRUE)
tri.pere.dipl

Variable quantitative

Pour une variable quantitative, un tri à plat est souvent peu approprié, en particulier dans le cas d’une variable continue. En revanche, réaliser un tri à plat est techniquement possible, et peut s’avérer utile dans certains cas.

Exemple avec une variable dichotomique :

table(cpes$pere.bac, useNA = "always")

   0    1 <NA> 
  30   97    1 

En revanche, il est toujours utile de visualiser la distribution d’une variable quantitative sous forme d’un histogramme.

hist(cpes$repas.qui.seul.midi)

Question : comment visualer la distribution du nombre de repas pris seul le midi ET le soir ?

Les indicateurs

On distingue deux types d’indicateurs permettant de décrire les variables quantitatives:

Ces deux ensembles d’indicateurs sont complémentaires. Ils doivent être employés ensemble.

Indicateurs de tendance centrale

Le mode

Le mode est la modalité ou la valeur la plus fréquente d’une distribution.

Dans le cas d’une variable qualitative, le mode est la modalité qui a l’effectif le plus élevé.

Pour une variable quantitative discrète, le mode est la valeur qui a l’effectif le plus élevé.

Pour une variable quantitative continue, le mode n’a aucun sens, car chaque valeur a une grande probabilité d’être unique. Dans ce cas, on ne peut le calculer qu’à condition de découper la variable en classes.

Mode d’une variable qualitative

cpes$cpes.filiere <- as.factor(cpes$cpes.filiere)
plot(cpes$cpes.filiere)

Mode d’une variable quantitative discrète

hist(cpes$repas.ou.fast.midi + cpes$repas.ou.fast.soir)

Mode d’une variable quantitative continue

La médiane

La médiane est la valeur d’une variable telle que la moitié des valeurs lui est supérieure et l’autre moitié inférieure. Elle peut être calculée pour des variables qualitatives ordonnée ou pour des variables quantitatives.

Médiane d’une variable ordonnée

Il s’agit de la classe qui contient la valeur séparant les observations ordonnées en deux sous-ensembles de taille égale.

tri.pere.dipl

Médiane d’une variable quantitative

Il suffit de classer les observations par ordre croissant. Si la variable a un nombre d’observations n impair, la médiane est la valeur de rang \(\frac{n+1}{2}\).

Si la variable a un nombre d’observations n pair, la médiane est la moyenne des observation de rang \(\frac{n}{2}\) et \(\frac{n}{2} + 1\).

# Calcul de l'âge des enquếtés
age <- 2016 - cpes$ne.annee
# Visualiser la répartition des âges
hist(age, breaks = 16:22)

Calcul de la médiane :

median(age)
[1] 19

La moyenne

La moyenne est la somme des valeurs d’une variable divisée par le nombre d’observations. On note \(\bar{x}\) la moyenne de la variable \(X\) comprenant \(n\) observations \(x_i\):

\(\bar{x} = \frac{1}{n} \sum\limits_{i=1}^n x_i\)

Elle ne s’applique qu’aux variables quantitatives.

mean(age)
[1] 18.875

En arrondissant deux chiffres après la virgule :

round(mean(age), 2)
[1] 18.88

Propriétés de la moyenne

La somme des écarts des valeurs à la moyenne est nulle. Soit \(\bar{x}\) la moyenne d’une variable x de valeur X.

\(\sum\limits_{i=1}^n (x_i - \bar{x}) = 0\)

# Vérification :
sum(age - mean(age))
[1] 0

La moyenne est très sensible à la présence de valeurs extrêmes.

# Vérification : imaginons qu'un étudiant du CPES a 80 ans
age.fake <- c(age, 80)
round(mean(age.fake), 2)
[1] 19.35

Indicateurs de dispersion

La dispersion statistique d’une distribution correspond à la tendance qu’ont les valeurs d’une variable à s’étaler autour d’une valeur centrale (moyenne, médiane, etc.). Cette tendance est inégale entre les variables.

Étendue

L’étendue d’une variable quantitative est la différence entre sa valeur maximum et sa valeur minimale.

Étendue de X = \(X_{max} - X_{min}\)

max(age) - min(age)
[1] 4

Quantiles

Les quantiles sont les \(x - 1\) valeurs qui séparent les observations ordonnées d’une variable en x sous-ensembles de même effectif.

  • La médiane est un quantile particulier qui sépare une distribution en deux sous-ensemble.
  • Les 3 quartiles séparent la distribution en quatre sous-ensemble.
  • les 9 déciles en dix sous-ensembles
  • les 99 centiles en cent sous-ensembles

Exemple avec les quartiles :

summary(cpes$courses.prix)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
   0.00   11.00   25.00   31.81   35.00  210.00      15 

Ou encore :

quartiles <- quantile(cpes$courses.prix, na.rm = TRUE)
quartiles
  0%  25%  50%  75% 100% 
   0   11   25   35  210 

Les quantiles permettent de calculer deux types d’indicateurs de dispersion:

  • l’intervalle interquantile désigne la différence entre la valeur du dernier quantile et la valeur du premier quantile.
  • le rapport interquantile désigne le rapport de la valeur du dernier quantile sur la valeur du premier quantile.

Intervalle interquartile :

quartiles[4] - quartiles[2]
75% 
 24 

Rapport interquartile :

quartiles[4] / quartiles[2]
     75% 
3.181818 

Représentation graphique des quartiles : les boîtes à moustaches

boxplot(cpes$courses.prix)

La boite à moustache (box and whisker plot ou boxplot) est un diagramme présentant plusieurs indicateurs de tendance centrale et de dispersion d’une variable quantitative. On y trouve en particulier :

  • la médiane est un trait gras au milieu de la boite
  • les premiers et troisième quartiles délimitent une boite autour de la médiane
  • les moustaches (whiskers) s’étendent des deux côtés de la boite jusqu’à \(1,5 \times \text{intervalle inter-quartile}\)
  • les valeurs extrêmes (outliers), les valeurs qui ne sont pas comprises à l’intérieur des moustaches, sont représentées par des points

Variance

La variance est égale à la moyenne des carrés des écarts à la moyenne. On la note \(\sigma^2\). Soit \(\sigma_x^2\) la variance de la variable x, comprenant n observations, et \(\bar(x)\) sa moyenne.

\(\sigma_x^2 = \frac{1}{n} * \sum\limits_{i=1}^n (X_i - \bar{x})^2\)

mean(cpes$courses.prix, na.rm = TRUE)
[1] 31.80566
var(cpes$courses.prix, na.rm = TRUE)
[1] 1156.537

L’écart-type

L’écart-type est la racine carrée de la moyenne des carrés des écarts à la moyenne, c’est-à-dire la racine carrée de la variance. On le note \(\sigma\). Ainsi:

\(\sigma_x = \sqrt{\frac{1}{n} * \sum\limits_{i=1}^n (X_i - \bar{x})^2} = \sqrt{\sigma_x^2}\)

mean(cpes$courses.prix, na.rm = TRUE)
[1] 31.80566
sd(cpes$courses.prix, na.rm = TRUE)
[1] 34.00789

Comprendre graphiquement l’écart-type :

plot(cpes$courses.prix)
abline(b = 0, a = mean(cpes$courses.prix, na.rm = TRUE), col = "red")

LS0tCnRpdGxlOiAiRXhwbG9yZXIgdW5lIGJhc2UgZGUgZG9ubsOpZXMiCmF1dGhvcjogIkdhYnJpZWwgQWxjYXJhcyIKZGF0ZTogIjYgbm92ZW1icmUgMjAxNyIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvYzogeWVzCnN1YnRpdGxlOiBDUEVTIDIgLSBUZWNobmlxdWVzIHF1YW50aXRhdGl2ZXMKLS0tCgojIE1hbmlwdWxlciBsYSBiYXNlIGRlIGRvbm7DqWVzCgojIyBDaGFyZ2VyIGRlcyBkb25uw6llcyBkYW5zIFIKCk5vdXMgYWxsb25zIGNoYXJnZXIgbGVzIGRvbm7DqWVzIGRlcHVpcyB1biBmaWNoaWVyIFtkaXNxdWUgZHVyXSBkYW5zIG5vdHJlIGVudmlyb25uZW1lbnQgUiBbbcOpbW9pcmUgdml2ZV0gOgoKYGBge3IsIGVjaG89VFJVRX0KbGlicmFyeSh0aWR5dmVyc2UpCiMgQ2hhcmdlciBkZXMgZG9ubsOpZXMgZGFucyBsYSB2YXJpYWJsZSBjcGVzCmNwZXMgPC0gcmVhZF9jc3YoIi4vY3Blc19xdWFudGkvYmRkX2FsaW1lbnRhdGlvbi5jc3YiKQpjcGVzJGdlbnJlIDwtIGFzLmZhY3RvcihjcGVzJGdlbnJlKQpgYGAKCk5vdGEgQmVuZSA6CgorIExlIGNoZW1pbiBlbnRyZSBndWlsbGVtZXRzIHMnZXhwcmltZSBkaWZmw6lyZW1lbnQgc2Vsb24gbGUgc3lzdMOobWUgZCdleHBsb2l0YXRpb24uIFNpIHZvdXMgbifDqnRlcyBwYXMgZW5jb3JlIMOgIGwnYWlzZSBhdmVjIGxhIGxpZ25lIGRlIGNvbW1hbmRlLCB2b3VzIHBvdXZleiBwYXNzZXIgcGFyIGwnZXhwbG9yZXVyIGdyYXBoaXF1ZS4KKyBQcsOpZsOpcmV6IGxlcyBjaGVtaW5zIHJlbGF0aWZzIMOgIHZvdHJlIGZpY2hpZXIgKCIuL2JkZF9hbGltZW50YXRpb24uY3N2IikgcGx1dMO0dCBxdSdhYnNvbHUgKCIvaG9tZS9ub20vZG9zc2llci9iZGRfYWxpbWVudGF0aW9uLmNzdiIpCisgQXUgYmVzb2luLCBvbiBwZXV0IHV0aWxpc2VyIGxlcyBjb21tYW5kZXMgYGdldHdkKClgIGV0IGBzZXR3ZCgpYCBwb3VyIGNvbmZpZ3VyZXIgbGUgZG9zc2llciBkZSB0cmF2YWlsICgqKncqKm9ya2luZyAqKmQqKmlyZWN0b3J5KQoKT24gcGV1dCB2w6lyaWZpZXIgcXVlIGxlcyBkb25uw6llcyBzb250IGJpZW4gY2hhcmfDqWVzIDoKCmBgYHtyLCBlY2hvPVRSVUUsIGV2YWw9RkFMU0V9CiMgVmlzdWFsaXNlciBsZXMgZG9ubsOpZXMgY29tbWUgZGFucyB1biB0YWJsZXVyClZpZXcoY3BlcykKYGBgCgojIFN0YXRpc3RpcXVlcyBkZXNjcmlwdGl2ZXMgdW5pdmFyacOpZXMKCkTDqWNyaXJlIHNlcyBkb25uw6llcyBuZSBzaWduaWZpZSBwYXMgbGVzIHJlc3RpdHVlciwgbWFpcyBzeW50aMOpdGlzZXIgZGVzIGluZm9ybWF0aW9ucyBwb3VyIGVuIHRpcmVyIHVuZSB2aXNpb24gZCdlbnNlbWJsZS4KCiMjIFF1J2VzdC1jZSBxdWUgZMOpY3JpcmUgZW4gc3RhdGlzdGlxdWVzID8KCioqU3RhdGlzdGlxdWUgZGVzY3JpcHRpdmUgOiBlbnNlbWJsZSBkZXMgbcOpdGhvZGVzIHN0YXRpc3RpcXVlcyBzeW50aMOpdGlzYW50IGxlcyBkb25uw6llcyBhZmluIGRlIGTDqWNyaXJlIHVuZSBwb3B1bGF0aW9uKiouCgpMYSBzdGF0aXN0aXF1ZSBkZXNjcmlwdGl2ZSBwZXJtZXQgZG9uYyBkZSBwYXNzZXIgZGVzIGRvbm7DqWVzICoqYXRvbWlzw6llcyoqIChhdSBuaXZlYXUgZGUgbCdpbmRpdmlkdSkgYXV4IGRvbm7DqWVzICoqYWdyw6lnw6llcyoqIChhdSBuaXZlYXUgZGUgbGEgcG9wdWxhdGlvbikuCgpFbGxlIHMnb3Bwb3NlIMOgIGxhIHN0YXRpc3RpcXVlICoqaW5mw6lyZW50aWVsbGUqKiBxdWkgYXBwYXJ0aWVuIMOgIHVuIHLDqWdpbWUgZXhwbGljYXRpZi4KCiMjIExhIHN0YXRpc3RpcXVlIGRlc2NyaXB0aXZlCgpPbiBwZXV0IGTDqWNyaXJlIDoKCisgdW5lIHNldWxlIHZhcmlhYmxlIDogc3RhdGlzdGlxdWUgZGVzY3JpcHRpdmUgdW5pdmFyacOpZXMgKGNlIGNvdXJzKQorIGRldXggdmFyaWFibGVzIDogc3RhdGlzdGlxdWUgZGVzY3JpcHRpdmUgYml2YXJpw6llIChzZW1haW5lIHByb2NoYWluZSkKKyBwbHVzaWV1cnMgdmFyaWFibGVzIDogc3RhdGlzdGlxdWUgZGVzY3JpcHRpdmUgbXVsdGlkaW1lbnNpb25uZWxsZQoKTGVzIG3DqXRob2RlcyBkZSBsYSBzdGF0aXN0aXF1ZSBkZXNjcmlwdGl2ZSBjb21wcmVubmVudCA6CgorIGxlcyB0YWJsZWF1eCAKKyBsZXMgZGlhZ3JhbW1lcworIGxlcyBwYXJhbcOodHJlcyBzdGF0aXN0aXF1ZXMgKHZhbGV1cnMgbnVtw6lyaXF1ZXMgY2FyYWN0w6lyaXN0aXF1ZXMgZCd1bmUgdmFyaWFibGUgcXVhbnRpdGF0aXZlKQoKIyBEaXN0cmlidXRpb24gZCd1bmUgdmFyaWFibGUKCiMjIFZhcmlhYmxlIHF1YWxpdGF0aXZlIDogdHJpIMOgIHBsYXQKCkxlICoqdHJpIMOgIHBsYXQqKiBwZXJtZXQgZGUgZMOpY3JpcmUgbGEgKipkaXN0cmlidXRpb24qKiBkJ3VuZSB2YXJpYWJsZSBjYXTDqWdvcmllbGxlLiBJbCBzJ2FnaXQgZGUgcHJvZHVpcmUgdW4gdGFibGVhdSByZWdyb3VwYW50IGwnKiplZmZlY3RpZioqIGV0IGxhICoqZnLDqXF1ZW5jZSoqIGRlIGNoYWN1bmUgZGVzIG1vZGFsaXTDqXMgZCd1bmUgdGVsbGUgdmFyaWFibGUuCgojIyMgVGFibGVhdSBkZXMgZWZmZWN0aWZzCgoqKkVmZmVjdGlmKiogOiBub21icmUgZCdvYnNlcnZhdGlvbnMgcG91ciBsYXF1ZWxsZSBsYSB2YXJpYWJsZSDDqXR1ZGnDqWUgcHJlbmQgbGEgbW9kYWxpdMOpIGVuIHF1ZXN0aW9uLiAoJG5fe21vZGFsaXRlfSQpCgpgYGB7cn0Kc3VtbWFyeShjcGVzJGdlbnJlKQpgYGAKCk91IDogCgpgYGB7cn0KdGFibGUoY3BlcyRnZW5yZSkgIyAidGFibGUiID0gImZhaXJlIHVuIHRhYmxlYXUiCmBgYAoKT3UgYmllbiwgc291cyBmb3JtZSBkZSAqKmRpYWdyYW1tZSBlbiBiYXJyZXMqKiA6CgpgYGB7cn0KcGxvdChjcGVzJGdlbnJlKSAjICJwbG90IiA9ICJmYWlyZSBncmFwaGlxdWUiCmBgYAoKRXhlcmNpY2UgOiBmYWlyZSB1biB0cmkgw6AgcGxhdCBkdSBkaXBsw7RtZSBkZSBsYSBtw6hyZS4KCiMjIyBUYWJsZWF1IGRlcyBmcsOpcXVlbmNlcwoKKipGcsOpcXVlbmNlKiogOiBwcm9wb3J0aW9uIGRlIGwnZWZmZWN0aWYgZCd1bmUgbW9kYWxpdMOpIHBhciByYXBwb3J0IMOgIGwnZWZmZWN0aWYgdG90YWwuICgkXGZyYWN7bl97bW9kYWxpdGV9fXtufSQpCgpEYW5zIFIgOiAiw6AgbGEgbWFpbiIKYGBge3J9CnRhYmxlKGNwZXMkZ2VucmUpL2xlbmd0aChjcGVzJGdlbnJlKQpgYGAKCk91IGF2ZWMgbGUgcGFja2FnZSAicXVlc3Rpb25yIiA6IAoKYGBge3J9CmxpYnJhcnkoInF1ZXN0aW9uciIpCmZyZXEoY3BlcyRnZW5yZSkKYGBgCgpOaXZlYXUgZXhwZXJ0IDoKCmBgYHtyfQpmcmVxKGNwZXMkZ2VucmUsCiAgICAgZGlnaXRzID0gMiwgIyAyIGNoaWZmcmVzIGFwcsOocyBsYSB2aXJndWxlCiAgICAgdG90YWwgPSBUUlVFLCAjIEFqb3V0ZXIgbGUgdG90YWwgZGVzIGNvbG9ubmVzCiAgICAgZXhjbHVkZSA9IE5BICMgTmUgcGFzIGFmZmljaGVyIGxlcyBOQQogICAgICkKYGBgCgpFeGVyY2ljZSA6IHRyaSDDoCBwbGF0IGF2ZWMgZnLDqXF1ZW5jZXMgcG91ciBsYSBmaWxpw6hyZSBkdSBjcGVzLgoKIyMjIFRhYmxlYXUgZGVzIGZyw6lxdWVuY2VzIGN1bXVsw6llcwoKTG9yc3F1ZSBsZSB0cmkgw6AgcGxhdCBwb3J0ZSBzdXIgdW5lIHZhcmlhYmxlIGNhdMOpZ29yaWVsbGUgKipvcmRvbm7DqWUqKiAobGVzIG1vZGFsaXTDqXMgcGV1dmVudCDDqnRyZSB0cmnDqWVzIGRhbnMgdW4gb3JkcmUgbG9naXF1ZSksIGxlIHRyaSDDoCBwbGF0IHBldXQgaW5jbHVyZSwgb3V0cmUgbCdlZmZlY3RpZiBldCBsYSBmcsOpcXVlbmNlLCBsYSAqKmZyw6lxdWVuY2UgY3VtdWzDqWUqKi4KCkxhIGZyw6lxdWVuY2UgY3VtdWzDqWUgZCd1bmUgbW9kYWxpdMOpIGVzdCDDqWdhbGUgw6AgbGEgc29tbWUgZGUgc2EgZnLDqXF1ZW5jZSBldCBkZXMgZnLDqXF1ZW5jZXMgZGUgdG91dGVzIGxlcyBtb2RhbGl0w6lzIHByw6ljw6lkZW50ZXMgZGFucyBsJ29yZHJlIGxvZ2lxdWUgZGUgY2xhc3NlbWVudCBkZXMgbW9kYWxpdMOpcy4KCmBgYHtyfQpwZXJlLmRpcGwgPC0gb3JkZXJlZChjcGVzJHBlcmUuZGlwbCwgbGV2ZWxzID0gYygiZG9jdG9yYXQiLCAibWFzdGVyIiwgImxpY2VuY2UiLCAiQ0FQIiwgImF1Y3VuIikpCnRyaS5wZXJlLmRpcGwgPC0gZnJlcShwZXJlLmRpcGwsIHRvdGFsID0gVFJVRSwgY3VtID0gVFJVRSkKdHJpLnBlcmUuZGlwbApgYGAKCiMjIFZhcmlhYmxlIHF1YW50aXRhdGl2ZQoKUG91ciB1bmUgdmFyaWFibGUgcXVhbnRpdGF0aXZlLCB1biB0cmkgw6AgcGxhdCBlc3Qgc291dmVudCBwZXUgYXBwcm9wcmnDqSwgZW4gcGFydGljdWxpZXIgZGFucyBsZSBjYXMgZCd1bmUgdmFyaWFibGUgY29udGludWUuIEVuIHJldmFuY2hlLCByw6lhbGlzZXIgdW4gdHJpIMOgIHBsYXQgZXN0IHRlY2huaXF1ZW1lbnQgcG9zc2libGUsIGV0IHBldXQgcydhdsOpcmVyIHV0aWxlIGRhbnMgY2VydGFpbnMgY2FzLgoKRXhlbXBsZSBhdmVjIHVuZSB2YXJpYWJsZSBkaWNob3RvbWlxdWUgOgoKYGBge3J9CnRhYmxlKGNwZXMkcGVyZS5iYWMsIHVzZU5BID0gImFsd2F5cyIpCmBgYAoKRW4gcmV2YW5jaGUsIGlsIGVzdCB0b3Vqb3VycyB1dGlsZSBkZSB2aXN1YWxpc2VyIGxhIGRpc3RyaWJ1dGlvbiBkJ3VuZSB2YXJpYWJsZSBxdWFudGl0YXRpdmUgc291cyBmb3JtZSBkJ3VuIGhpc3RvZ3JhbW1lLgoKYGBge3IsIGVjaG89VFJVRX0KaGlzdChjcGVzJHJlcGFzLnF1aS5zZXVsLm1pZGkpCmBgYAoKClF1ZXN0aW9uIDogY29tbWVudCB2aXN1YWxlciBsYSBkaXN0cmlidXRpb24gZHUgbm9tYnJlIGRlIHJlcGFzIHByaXMgc2V1bCBsZSBtaWRpIEVUIGxlIHNvaXIgPwoKIyBMZXMgaW5kaWNhdGV1cnMKCk9uIGRpc3Rpbmd1ZSBkZXV4IHR5cGVzIGQnaW5kaWNhdGV1cnMgcGVybWV0dGFudCBkZSBkw6ljcmlyZSBsZXMgdmFyaWFibGVzIHF1YW50aXRhdGl2ZXM6CgorIExlcyAqKmluZGljYXRldXJzIGRlIHRlbmRhbmNlIGNlbnRyYWxlKiogZMOpY3JpdmVudCBsZSBjxZN1ciBkZSBsYSBkaXN0cmlidXRpb24uIElscyBkw6lzaWduZW50IGxlcyB2YWxldXJzIGF1dG91ciBkZXNxdWVscyBlc3QgY29uY2VudHLDqWUgbGEgdmFyaWFibGUuIElsIGVuIGV4aXN0ZSB0cm9pcywgbGUgKiptb2RlKiosIGxhICoqbW95ZW5uZSoqIGV0IGxhICoqbcOpZGlhbmUqKi4KKyBMZXMgKippbmRpY2F0ZXVycyBkZSBkaXNwZXJzaW9uKiogZMOpY3JpdmVudCBsJ8OpdGVuZHVlIGRlIGxhIGRpc3RyaWJ1dGlvbiA6IGxhIHRlbmRhbmNlIGRlcyB2YWxldXJzIMOgIHMnw6l0YWxlciBhdXRvdXIgZCd1bmUgdmFsZXVyIGNlbnRyYWxlLiBPbiB0cm91dmUgcGFybWkgZXV4IGxhICoqdmFyaWFuY2UqKiBldCBsJyoqw6ljYXJ0LXR5cGUqKi4KCkNlcyBkZXV4IGVuc2VtYmxlcyBkJ2luZGljYXRldXJzIHNvbnQgY29tcGzDqW1lbnRhaXJlcy4gSWxzIGRvaXZlbnQgw6p0cmUgZW1wbG95w6lzIGVuc2VtYmxlLgoKIyMgSW5kaWNhdGV1cnMgZGUgdGVuZGFuY2UgY2VudHJhbGUKCiMjIyBMZSBtb2RlCgpMZSBtb2RlIGVzdCBsYSBtb2RhbGl0w6kgb3UgbGEgdmFsZXVyICoqbGEgcGx1cyBmcsOpcXVlbnRlKiogZCd1bmUgZGlzdHJpYnV0aW9uLiAKCkRhbnMgbGUgY2FzIGQndW5lICoqdmFyaWFibGUgcXVhbGl0YXRpdmUqKiwgbGUgbW9kZSBlc3QgbGEgbW9kYWxpdMOpIHF1aSBhICoqbCdlZmZlY3RpZiBsZSBwbHVzIMOpbGV2w6kqKi4KClBvdXIgdW5lIHZhcmlhYmxlIHF1YW50aXRhdGl2ZSBkaXNjcsOodGUsIGxlIG1vZGUgZXN0IGxhIHZhbGV1ciBxdWkgYSBsJ2VmZmVjdGlmIGxlIHBsdXMgw6lsZXbDqS4KClBvdXIgdW5lIHZhcmlhYmxlIHF1YW50aXRhdGl2ZSBjb250aW51ZSwgbGUgbW9kZSBuJ2EgYXVjdW4gc2VucywgY2FyIGNoYXF1ZSB2YWxldXIgYSB1bmUgZ3JhbmRlIHByb2JhYmlsaXTDqSBkJ8OqdHJlIHVuaXF1ZS4gRGFucyBjZSBjYXMsIG9uIG5lIHBldXQgbGUgY2FsY3VsZXIgcXUnw6AgY29uZGl0aW9uIGRlIGTDqWNvdXBlciBsYSB2YXJpYWJsZSBlbiBjbGFzc2VzLgoKIyMjIyBNb2RlIGQndW5lIHZhcmlhYmxlIHF1YWxpdGF0aXZlCgpgYGB7cn0KY3BlcyRjcGVzLmZpbGllcmUgPC0gYXMuZmFjdG9yKGNwZXMkY3Blcy5maWxpZXJlKQpwbG90KGNwZXMkY3Blcy5maWxpZXJlKQpgYGAKCiMjIyMgTW9kZSBkJ3VuZSB2YXJpYWJsZSBxdWFudGl0YXRpdmUgZGlzY3LDqHRlCgpgYGB7cn0KaGlzdChjcGVzJHJlcGFzLm91LmZhc3QubWlkaSArIGNwZXMkcmVwYXMub3UuZmFzdC5zb2lyKQpgYGAKCiMjIyMgTW9kZSBkJ3VuZSB2YXJpYWJsZSBxdWFudGl0YXRpdmUgY29udGludWUKCmBgYHtyfQpgYGAKCiMjIyBMYSBtw6lkaWFuZQoKTGEgKiptw6lkaWFuZSoqIGVzdCBsYSB2YWxldXIgZCd1bmUgdmFyaWFibGUgdGVsbGUgcXVlIGxhIG1vaXRpw6kgZGVzIHZhbGV1cnMgbHVpIGVzdCBzdXDDqXJpZXVyZSBldCBsJ2F1dHJlIG1vaXRpw6kgaW5mw6lyaWV1cmUuIEVsbGUgcGV1dCDDqnRyZSBjYWxjdWzDqWUgcG91ciBkZXMgKip2YXJpYWJsZXMgcXVhbGl0YXRpdmVzIG9yZG9ubsOpZSoqIG91IHBvdXIgZGVzICoqdmFyaWFibGVzIHF1YW50aXRhdGl2ZXMqKi4KCiMjIyMgTcOpZGlhbmUgZCd1bmUgdmFyaWFibGUgb3Jkb25uw6llCgpJbCBzJ2FnaXQgZGUgbGEgY2xhc3NlIHF1aSBjb250aWVudCBsYSB2YWxldXIgc8OpcGFyYW50IGxlcyBvYnNlcnZhdGlvbnMgb3Jkb25uw6llcyBlbiBkZXV4IHNvdXMtZW5zZW1ibGVzIGRlIHRhaWxsZSDDqWdhbGUuCgpgYGB7cn0KdHJpLnBlcmUuZGlwbApgYGAKCiMjIyMgTcOpZGlhbmUgZCd1bmUgdmFyaWFibGUgcXVhbnRpdGF0aXZlCgpJbCBzdWZmaXQgZGUgY2xhc3NlciBsZXMgb2JzZXJ2YXRpb25zIHBhciBvcmRyZSBjcm9pc3NhbnQuIFNpIGxhIHZhcmlhYmxlIGEgdW4gbm9tYnJlIGQnb2JzZXJ2YXRpb25zIG4gaW1wYWlyLCBsYSBtw6lkaWFuZSBlc3QgbGEgdmFsZXVyIGRlIHJhbmcgJFxmcmFje24rMX17Mn0kLgoKU2kgbGEgdmFyaWFibGUgYSB1biBub21icmUgZCdvYnNlcnZhdGlvbnMgbiBwYWlyLCBsYSBtw6lkaWFuZSBlc3QgbGEgbW95ZW5uZSBkZXMgb2JzZXJ2YXRpb24gZGUgcmFuZyAkXGZyYWN7bn17Mn0kIGV0ICRcZnJhY3tufXsyfSArIDEkLgoKYGBge3J9CiMgQ2FsY3VsIGRlIGwnw6JnZSBkZXMgZW5xdeG6v3TDqXMKYWdlIDwtIDIwMTYgLSBjcGVzJG5lLmFubmVlCgojIFZpc3VhbGlzZXIgbGEgcsOpcGFydGl0aW9uIGRlcyDDomdlcwpoaXN0KGFnZSwgYnJlYWtzID0gMTY6MjIpCmBgYAoKQ2FsY3VsIGRlIGxhIG3DqWRpYW5lIDogCgpgYGB7cn0KbWVkaWFuKGFnZSkKYGBgCgojIyMgTGEgbW95ZW5uZQoKTGEgbW95ZW5uZSBlc3QgbGEgc29tbWUgZGVzIHZhbGV1cnMgZCd1bmUgdmFyaWFibGUgZGl2aXPDqWUgcGFyIGxlIG5vbWJyZSBkJ29ic2VydmF0aW9ucy4gT24gbm90ZSAkXGJhcnt4fSQgbGEgbW95ZW5uZSBkZSBsYSB2YXJpYWJsZSAkWCQgY29tcHJlbmFudCAkbiQgb2JzZXJ2YXRpb25zICR4X2kkOiAKCiRcYmFye3h9ID0gXGZyYWN7MX17bn0gXHN1bVxsaW1pdHNfe2k9MX1ebiB4X2kkCgpFbGxlIG5lIHMnYXBwbGlxdWUgcXUnYXV4IHZhcmlhYmxlcyBxdWFudGl0YXRpdmVzLgoKYGBge3J9Cm1lYW4oYWdlKQpgYGAKCkVuIGFycm9uZGlzc2FudCBkZXV4IGNoaWZmcmVzIGFwcsOocyBsYSB2aXJndWxlIDoKCmBgYHtyfQpyb3VuZChtZWFuKGFnZSksIDIpCmBgYAoKIyMjIyBQcm9wcmnDqXTDqXMgZGUgbGEgbW95ZW5uZQoKTGEgc29tbWUgZGVzIMOpY2FydHMgZGVzIHZhbGV1cnMgw6AgbGEgbW95ZW5uZSBlc3QgbnVsbGUuIFNvaXQgJFxiYXJ7eH0kIGxhIG1veWVubmUgZCd1bmUgdmFyaWFibGUgeCBkZSB2YWxldXIgWC4KCiRcc3VtXGxpbWl0c197aT0xfV5uICh4X2kgLSBcYmFye3h9KSA9IDAkCgpgYGB7cn0KIyBWw6lyaWZpY2F0aW9uIDoKc3VtKGFnZSAtIG1lYW4oYWdlKSkKYGBgCgpMYSBtb3llbm5lIGVzdCB0csOocyBzZW5zaWJsZSDDoCBsYSBwcsOpc2VuY2UgZGUgdmFsZXVycyBleHRyw6ptZXMuCgpgYGB7cn0KIyBWw6lyaWZpY2F0aW9uIDogaW1hZ2lub25zIHF1J3VuIMOpdHVkaWFudCBkdSBDUEVTIGEgODAgYW5zCmFnZS5mYWtlIDwtIGMoYWdlLCA4MCkKcm91bmQobWVhbihhZ2UuZmFrZSksIDIpCmBgYAoKCiMjIEluZGljYXRldXJzIGRlIGRpc3BlcnNpb24KCkxhIGRpc3BlcnNpb24gc3RhdGlzdGlxdWUgZCd1bmUgZGlzdHJpYnV0aW9uIGNvcnJlc3BvbmQgw6AgbGEgdGVuZGFuY2UgcXUnb250IGxlcyB2YWxldXJzIGQndW5lIHZhcmlhYmxlIMOgIHMnw6l0YWxlciBhdXRvdXIgZCd1bmUgdmFsZXVyIGNlbnRyYWxlIChtb3llbm5lLCBtw6lkaWFuZSwgZXRjLikuIENldHRlIHRlbmRhbmNlIGVzdCBpbsOpZ2FsZSBlbnRyZSBsZXMgdmFyaWFibGVzLgoKIyMjIMOJdGVuZHVlCgpMJyoqw6l0ZW5kdWUqKiBkJ3VuZSB2YXJpYWJsZSBxdWFudGl0YXRpdmUgZXN0IGxhIGRpZmbDqXJlbmNlIGVudHJlIHNhIHZhbGV1ciBtYXhpbXVtIGV0IHNhIHZhbGV1ciBtaW5pbWFsZS4KCsOJdGVuZHVlIGRlIFggPSAkWF97bWF4fSAtIFhfe21pbn0kCgpgYGB7cn0KbWF4KGFnZSkgLSBtaW4oYWdlKQpgYGAKCiMjIyBRdWFudGlsZXMKCkxlcyAqKnF1YW50aWxlcyoqIHNvbnQgbGVzICR4IC0gMSQgdmFsZXVycyBxdWkgc8OpcGFyZW50IGxlcyBvYnNlcnZhdGlvbnMgb3Jkb25uw6llcyBkJ3VuZSB2YXJpYWJsZSBlbiB4IHNvdXMtZW5zZW1ibGVzIGRlIG3Dqm1lIGVmZmVjdGlmLiAKCisgTGEgKiptw6lkaWFuZSoqIGVzdCB1biBxdWFudGlsZSBwYXJ0aWN1bGllciBxdWkgc8OpcGFyZSB1bmUgZGlzdHJpYnV0aW9uIGVuIGRldXggc291cy1lbnNlbWJsZS4gCisgTGVzIDMgKipxdWFydGlsZXMqKiBzw6lwYXJlbnQgbGEgZGlzdHJpYnV0aW9uIGVuIHF1YXRyZSBzb3VzLWVuc2VtYmxlLgorIGxlcyA5ICoqZMOpY2lsZXMqKiBlbiBkaXggc291cy1lbnNlbWJsZXMKKyBsZXMgOTkgKipjZW50aWxlcyoqIGVuIGNlbnQgc291cy1lbnNlbWJsZXMKKyAuLi4KCkV4ZW1wbGUgYXZlYyBsZXMgcXVhcnRpbGVzIDoKCmBgYHtyfQpzdW1tYXJ5KGNwZXMkY291cnNlcy5wcml4KQpgYGAKCk91IGVuY29yZSA6CgpgYGB7cn0KcXVhcnRpbGVzIDwtIHF1YW50aWxlKGNwZXMkY291cnNlcy5wcml4LCBuYS5ybSA9IFRSVUUpCnF1YXJ0aWxlcwpgYGAKCkxlcyBxdWFudGlsZXMgcGVybWV0dGVudCBkZSBjYWxjdWxlciBkZXV4IHR5cGVzIGQnaW5kaWNhdGV1cnMgZGUgZGlzcGVyc2lvbjoKCisgbCcqKmludGVydmFsbGUgaW50ZXJxdWFudGlsZSoqIGTDqXNpZ25lIGxhIGRpZmbDqXJlbmNlIGVudHJlIGxhIHZhbGV1ciBkdSBkZXJuaWVyIHF1YW50aWxlIGV0IGxhIHZhbGV1ciBkdSBwcmVtaWVyIHF1YW50aWxlLgorIGxlICoqcmFwcG9ydCBpbnRlcnF1YW50aWxlKiogZMOpc2lnbmUgbGUgcmFwcG9ydCBkZSBsYSB2YWxldXIgZHUgZGVybmllciBxdWFudGlsZSBzdXIgbGEgdmFsZXVyIGR1IHByZW1pZXIgcXVhbnRpbGUuCgpJbnRlcnZhbGxlIGludGVycXVhcnRpbGUgOgoKYGBge3J9CnF1YXJ0aWxlc1s0XSAtIHF1YXJ0aWxlc1syXQpgYGAKClJhcHBvcnQgaW50ZXJxdWFydGlsZSA6CgpgYGB7cn0KcXVhcnRpbGVzWzRdIC8gcXVhcnRpbGVzWzJdCmBgYAoKUmVwcsOpc2VudGF0aW9uIGdyYXBoaXF1ZSBkZXMgcXVhcnRpbGVzIDogbGVzIGJvw650ZXMgw6AgbW91c3RhY2hlcwoKCmBgYHtyfQpib3hwbG90KGNwZXMkY291cnNlcy5wcml4KQpgYGAKCkxhICoqYm9pdGUgw6AgbW91c3RhY2hlKiogKCpib3ggYW5kIHdoaXNrZXIgcGxvdCogb3UgKmJveHBsb3QqKSBlc3QgdW4gZGlhZ3JhbW1lIHByw6lzZW50YW50IHBsdXNpZXVycyBpbmRpY2F0ZXVycyBkZSB0ZW5kYW5jZSBjZW50cmFsZSBldCBkZSBkaXNwZXJzaW9uIGQndW5lIHZhcmlhYmxlIHF1YW50aXRhdGl2ZS4gT24geSB0cm91dmUgZW4gcGFydGljdWxpZXIgOgoKKyBsYSAqKm3DqWRpYW5lKiogZXN0IHVuIHRyYWl0IGdyYXMgYXUgbWlsaWV1IGRlIGxhIGJvaXRlCisgbGVzIHByZW1pZXJzIGV0IHRyb2lzacOobWUgKipxdWFydGlsZXMqKiBkw6lsaW1pdGVudCB1bmUgYm9pdGUgYXV0b3VyIGRlIGxhIG3DqWRpYW5lCisgbGVzICoqbW91c3RhY2hlcyoqICgqd2hpc2tlcnMqKSBzJ8OpdGVuZGVudCBkZXMgZGV1eCBjw7R0w6lzIGRlIGxhIGJvaXRlIGp1c3F1J8OgICQxLDUgXHRpbWVzIFx0ZXh0e2ludGVydmFsbGUgaW50ZXItcXVhcnRpbGV9JAorIGxlcyAqKnZhbGV1cnMgZXh0csOqbWVzKiogKCpvdXRsaWVycyopLCBsZXMgdmFsZXVycyBxdWkgbmUgc29udCBwYXMgY29tcHJpc2VzIMOgIGwnaW50w6lyaWV1ciBkZXMgbW91c3RhY2hlcywgc29udCByZXByw6lzZW50w6llcyBwYXIgZGVzIHBvaW50cwoKIyMjIFZhcmlhbmNlCgpMYSAqKnZhcmlhbmNlKiogZXN0IMOpZ2FsZSDDoCAqKmxhIG1veWVubmUgZGVzIGNhcnLDqXMgZGVzIMOpY2FydHMgw6AgbGEgbW95ZW5uZSoqLiBPbiBsYSBub3RlICRcc2lnbWFeMiQuIFNvaXQgJFxzaWdtYV94XjIkIGxhIHZhcmlhbmNlIGRlIGxhIHZhcmlhYmxlIHgsIGNvbXByZW5hbnQgbiBvYnNlcnZhdGlvbnMsIGV0ICRcYmFyKHgpJCBzYSBtb3llbm5lLgoKJFxzaWdtYV94XjIgPSBcZnJhY3sxfXtufSAqIFxzdW1cbGltaXRzX3tpPTF9Xm4gKFhfaSAtIFxiYXJ7eH0pXjIkCgpgYGB7cn0KbWVhbihjcGVzJGNvdXJzZXMucHJpeCwgbmEucm0gPSBUUlVFKQp2YXIoY3BlcyRjb3Vyc2VzLnByaXgsIG5hLnJtID0gVFJVRSkKYGBgCgojIyMgTCfDqWNhcnQtdHlwZQoKTCcqKsOpY2FydC10eXBlKiogZXN0ICoqbGEgcmFjaW5lIGNhcnLDqWUgZGUgbGEgbW95ZW5uZSBkZXMgY2FycsOpcyBkZXMgw6ljYXJ0cyDDoCBsYSBtb3llbm5lKiosIGMnZXN0LcOgLWRpcmUgKipsYSByYWNpbmUgY2FycsOpZSBkZSBsYSB2YXJpYW5jZSoqLiBPbiBsZSBub3RlICRcc2lnbWEkLiBBaW5zaToKCiRcc2lnbWFfeCA9IFxzcXJ0e1xmcmFjezF9e259ICogXHN1bVxsaW1pdHNfe2k9MX1ebiAoWF9pIC0gXGJhcnt4fSleMn0gPSBcc3FydHtcc2lnbWFfeF4yfSQKCmBgYHtyfQptZWFuKGNwZXMkY291cnNlcy5wcml4LCBuYS5ybSA9IFRSVUUpCnNkKGNwZXMkY291cnNlcy5wcml4LCBuYS5ybSA9IFRSVUUpCmBgYAoKQ29tcHJlbmRyZSBncmFwaGlxdWVtZW50IGwnw6ljYXJ0LXR5cGUgOgoKYGBge3J9CnBsb3QoY3BlcyRjb3Vyc2VzLnByaXgpCmFibGluZShiID0gMCwgYSA9IG1lYW4oY3BlcyRjb3Vyc2VzLnByaXgsIG5hLnJtID0gVFJVRSksIGNvbCA9ICJyZWQiKQoKYGBg