Ce document est à utiliser comme une table de référence, qui peut être consultée ponctuellement ou servir de support à des révisions.

Généralités

Opérateurs

Opérateur Rôle Exemple
+ Addition 1+1
- Soustraction 1-1
/ Division 1/1
* Multiplication 1*1
^ Puissance 10^2

Symboles

Symbole Rôle Exemple
<- Assignation à une variable animaux <- c("chien", "chat")
() Éxécution d’une fonction. Contient souvent des arguments c(1, 2, 3)
[] Sélection d’un sous-ensemble dans une variable animaux[1]
$ Sélection d’une variable dans un data.frame bdd$genre
# Commentaire : ignorer ce qui suit # Test
= Assignation d’un argument dans une fonction mean(x, na.rm = TRUE)

Exemples :

# Cette ligne n'est pas interprétée par R
c("chien", "chat") # Fonction
[1] "chien" "chat" 
animaux <- c("chien", "chat") # Assignation dans la variable animaux
animaux[1] # Sélection du premier élément
[1] "chien"
# En revanche :
animaux(1)
Erreur : impossible de trouver la fonction "animaux"

Raccourcis clavier essentiels

Touches Fonction
Ctrl+Entrée Exécuter la ligne où se trouve le curseur
Ctrl+Entrée Exécuter les lignes sélectionnées
Ctrl+L Effacer la console
Shift Obtenir les suggesions de complétion
Ctrl+S Sauvegarder le fichier

R est sensible à la casse

Attention aux appels de fonction :

factor(c("chien", "chat"))
[1] chien chat 
Levels: chat chien
# Mais...
Factor(c("chien", "chat"))
Erreur : impossible de trouver la fonction "Factor"

Et aux appels de variable :

animaux <- c("chien", "chat")
animaux
[1] "chien" "chat" 
# Mais...
Animaux
Erreur : objet 'Animaux' introuvable

Structures de données

Types de données

Pour identifier un type de données, on peut utiliser la fonction typeof().

Notation Rôle Exemple
1234 Un nombre (“double”) 1
"" ou '' Chaîne de caractères "animaux"
NA Absence de données NA

Résultats de la fonction typeof() :

typeof(1)
[1] "double"
typeof("1")
[1] "character"
typeof(NA)
[1] "logical"

Le type de données doit être bien compris sous peine d’erreurs !

1+1
[1] 2
# Mais...
1+"1"
Error in 1 + "1" : argument non numérique pour un opérateur binaire

Structures de données

Pour identifier une structure de données, on peut utiliser la fonction str().

Nom Fonction Concept équivalent en statistiques
vector c() Variable
factor factor() Variable qualitative
data.frame data.frame() Base de données

Vecteur

Dans R En statistiques
vector Variable
Suite de données de même type Série de données homogènes
c(1,2,3,4) # Équivalent à une variable quantitative
[1] 1 2 3 4
str(c(1,2,3,4))
 num [1:4] 1 2 3 4
c("homme", "femme", "homme") # Série de données textuelles
[1] "homme" "femme" "homme"
str(c("homme", "femme", "homme"))
 chr [1:3] "homme" "femme" "homme"

Manipulation des vecteurs :

genre <- c("homme", "femme", "homme")
genre[1]
[1] "homme"
genre[1:2]
[1] "homme" "femme"
genre[c(1, 3)]
[1] "homme" "homme"

Facteur

Les facteurs sont un type particulier de vecteurs dans R, de la même façon que les variables qualitatives sont un type de variable particulier dans R.

Dans R En statistiques
vector Variable qualitative
levels Modalités de la variable
genre <- c("homme", "femme", "homme")
# Transformation en facteur
genre.f <- factor(genre)
str(genre.f)
 Factor w/ 2 levels "femme","homme": 2 1 2
genre.f
[1] homme femme homme
Levels: femme homme

Pour voir les modalités (levels) :

levels(genre.f)

Data.frame

C’est l’équivalent d’une base de données en statistiques : une série de variables sur les mêmes individus.

Pour sélectionner une variable en particulier :

bdd$variable1

Les fonctions

Les fonctions sont un concept central des langages de programmation… et donc de R !

Anatomie d’une fonction

Toujours sous la forme :

nomDeLaFonction(arguments)
  • nomDeLaFonction : nom de la fonction à appeler
  • () : les parenthèses signifient qu’on demande à R d’éxécuter la fonction.
  • arguments : une liste d’arguments séparés par des virgules et une espace. Le nombre d’arguments dépend des fonctions.

Les arguments

Fonction qui n’a besoin d’aucun argument :

getwd()

La fonction c() accepte un nombre illimité d’arguments :

c(1, 2, 3, 4)

Certaines fonctions ont des arguments obligatoires :

mean()

Mais :

notes <- c(10, 20)
mean(notes)

Certaines fonctions prennent des arguments falcutatifs, qui peuvent être nommés. Dans ce cas, le nom de l’argument est suivi d’un signe = puis de sa valeur.

notes <- c(10, 20, NA)
mean(notes, na.rm = TRUE)

Fonctions imbriquées

Il est bien sûr possible d’imbriquer nos fonctions :

mean(c(c(10, 20), NA), na.rm = TRUE)

Ce qui est identique à :

notes <- c(10, 20)
notes2 <- c(notes, NA)
mean(notes2, na.rm = TRUE)

Pour comprendre les fonctions imbriquées, il faut donc procéder par étapes, en partant de l’intérieur des parenthèses pour aller vers l’extérieur.

Les variables

Dans un langage de programmation, les variables permettent d’atteindre un niveau d’abstraction supplémentaire, en attribuant un nom à un objet pour le réutiliser par la suite. Elles améliorent également la lisibilité du programme.

variable <- "coucou"
variable
[1] "coucou"

Attention aux erreurs de notation !

variable
[1] "coucou"
# Mais...
"variable"
[1] "variable"

Variable informatique / variable statistique

Attention : le concept de variable informatique est très différent de variable statistique. En effet, une variable informatique peut stocker n’importe quel type de données, alors qu’une variable statistique correspond à une série de données homogènes collectées sur des individus.

Les deux concepts se recoupent parfois :

notes <- c(10, 20, 16)

Ici, la variable notes peut correspondre à une variable statistique.

En revanche :

test <- mean(notes)

Dans ce cas, la variable informatique test contient la moyenne des notes, ce qui n’est pas équivalent à une variable au sens statistique.

LS0tCnRpdGxlOiAiUiBDaGVhdHNoZWV0IHBvdXIgZMOpYnV0YW50cyIKZGF0ZTogIkTDqWNlbWJyZSAyMDE2IgphdXRob3I6ICJHYWJyaWVsIEFsY2FyYXMiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazogCiAgICB0b2M6IHllcwotLS0KCkNlIGRvY3VtZW50IGVzdCDDoCB1dGlsaXNlciBjb21tZSB1bmUgdGFibGUgZGUgcsOpZsOpcmVuY2UsIHF1aSBwZXV0IMOqdHJlIGNvbnN1bHTDqWUgcG9uY3R1ZWxsZW1lbnQgb3Ugc2VydmlyIGRlIHN1cHBvcnQgw6AgZGVzIHLDqXZpc2lvbnMuCgojIEfDqW7DqXJhbGl0w6lzCgojIyBPcMOpcmF0ZXVycwoKfCBPcMOpcmF0ZXVyIHwgUsO0bGUgfCBFeGVtcGxlIHwKfCAtLS0gfCAtLS0gfCAtLS0gCnwgYCtgIHwgQWRkaXRpb24gfCBgMSsxYCB8CnwgYC1gIHwgU291c3RyYWN0aW9uIHwgYDEtMWAgfAp8IGAvYCB8IERpdmlzaW9uIHwgYDEvMWAgfAp8IGAqYCB8IE11bHRpcGxpY2F0aW9uIHwgYDEqMWAgfAp8IGBeYCB8IFB1aXNzYW5jZSB8IGAxMF4yYCB8CgojIyBTeW1ib2xlcwoKfCBTeW1ib2xlIHwgUsO0bGUgfCBFeGVtcGxlIHwKfCAtLS0gfCAtLS0gfCAtLS0gCnwgYDwtYCB8IEFzc2lnbmF0aW9uIMOgIHVuZSB2YXJpYWJsZSB8IGBhbmltYXV4IDwtIGMoImNoaWVuIiwgImNoYXQiKWAgfAp8IGAoKWAgfCDDiXjDqWN1dGlvbiBkJ3VuZSBmb25jdGlvbi4gQ29udGllbnQgc291dmVudCBkZXMgYXJndW1lbnRzIHwgYGMoMSwgMiwgMylgIHwKfCBgW11gIHwgU8OpbGVjdGlvbiBkJ3VuIHNvdXMtZW5zZW1ibGUgZGFucyB1bmUgdmFyaWFibGUgfCBgYW5pbWF1eFsxXWAgfAp8IGAkYCB8IFPDqWxlY3Rpb24gZCd1bmUgdmFyaWFibGUgZGFucyB1biBkYXRhLmZyYW1lIHwgYGJkZCRnZW5yZWAgfAp8IGAjYCB8IENvbW1lbnRhaXJlIDogaWdub3JlciBjZSBxdWkgc3VpdCB8IGAjIFRlc3RgIHwKfCBgPWAgfCBBc3NpZ25hdGlvbiBkJ3VuIGFyZ3VtZW50IGRhbnMgdW5lIGZvbmN0aW9uIHwgYG1lYW4oeCwgbmEucm0gPSBUUlVFKWAgfAoKCioqRXhlbXBsZXMgOioqCgpgYGB7cn0KIyBDZXR0ZSBsaWduZSBuJ2VzdCBwYXMgaW50ZXJwcsOpdMOpZSBwYXIgUgpjKCJjaGllbiIsICJjaGF0IikgIyBGb25jdGlvbgphbmltYXV4IDwtIGMoImNoaWVuIiwgImNoYXQiKSAjIEFzc2lnbmF0aW9uIGRhbnMgbGEgdmFyaWFibGUgYW5pbWF1eAphbmltYXV4WzFdICMgU8OpbGVjdGlvbiBkdSBwcmVtaWVyIMOpbMOpbWVudAoKIyBFbiByZXZhbmNoZSA6CmFuaW1hdXgoMSkKYGBgCgojIyBSYWNjb3VyY2lzIGNsYXZpZXIgZXNzZW50aWVscwoKfCBUb3VjaGVzIHwgRm9uY3Rpb24gfAp8IC0tLS0gfCAtLS0tIHwKfCBgQ3RybCtFbnRyw6llYCB8IEV4w6ljdXRlciBsYSBsaWduZSBvw7kgc2UgdHJvdXZlIGxlIGN1cnNldXIgfAp8IGBDdHJsK0VudHLDqWVgIHwgRXjDqWN1dGVyIGxlcyBsaWduZXMgc8OpbGVjdGlvbm7DqWVzIHwKfCBgQ3RybCtMYCB8IEVmZmFjZXIgbGEgY29uc29sZSB8CnwgYFNoaWZ0YCB8IE9idGVuaXIgbGVzIHN1Z2dlc2lvbnMgZGUgY29tcGzDqXRpb24gfAp8IGBDdHJsK1NgIHwgU2F1dmVnYXJkZXIgbGUgZmljaGllciB8CgojIyBSIGVzdCBzZW5zaWJsZSDDoCBsYSBjYXNzZQoKQXR0ZW50aW9uIGF1eCBhcHBlbHMgZGUgZm9uY3Rpb24gOgoKYGBge3J9CmZhY3RvcihjKCJjaGllbiIsICJjaGF0IikpCgojIE1haXMuLi4KRmFjdG9yKGMoImNoaWVuIiwgImNoYXQiKSkKYGBgCgpFdCBhdXggYXBwZWxzIGRlIHZhcmlhYmxlIDoKCmBgYHtyfQphbmltYXV4IDwtIGMoImNoaWVuIiwgImNoYXQiKQphbmltYXV4CgojIE1haXMuLi4KQW5pbWF1eApgYGAKCiMgU3RydWN0dXJlcyBkZSBkb25uw6llcwoKIyMgVHlwZXMgZGUgZG9ubsOpZXMKClBvdXIgaWRlbnRpZmllciB1biB0eXBlIGRlIGRvbm7DqWVzLCBvbiBwZXV0IHV0aWxpc2VyIGxhIGZvbmN0aW9uIGB0eXBlb2YoKWAuCgp8IE5vdGF0aW9uIHwgUsO0bGUgfCBFeGVtcGxlIHwKfCAtLS0gfCAtLS0gfCAtLS0gCnwgYDEyMzRgIHwgVW4gbm9tYnJlICgiZG91YmxlIikgfCBgMWAgfAp8IGAiImAgb3UgYCcnYCB8IENoYcOubmUgZGUgY2FyYWN0w6hyZXMgfCBgImFuaW1hdXgiYCB8CnwgYE5BYCB8IEFic2VuY2UgZGUgZG9ubsOpZXMgfCBgTkFgIHwKClLDqXN1bHRhdHMgZGUgbGEgZm9uY3Rpb24gYHR5cGVvZigpYCA6CgpgYGB7cn0KdHlwZW9mKDEpCnR5cGVvZigiMSIpCnR5cGVvZihOQSkKYGBgCgoqKkxlIHR5cGUgZGUgZG9ubsOpZXMgZG9pdCDDqnRyZSBiaWVuIGNvbXByaXMgc291cyBwZWluZSBkJ2VycmV1cnMgISoqCgpgYGB7cn0KMSsxCiMgTWFpcy4uLgoxKyIxIgpgYGAKCiMjIFN0cnVjdHVyZXMgZGUgZG9ubsOpZXMKClBvdXIgaWRlbnRpZmllciB1bmUgc3RydWN0dXJlIGRlIGRvbm7DqWVzLCBvbiBwZXV0IHV0aWxpc2VyIGxhIGZvbmN0aW9uIGBzdHIoKWAuCgp8IE5vbSB8IEZvbmN0aW9uIHwgQ29uY2VwdCDDqXF1aXZhbGVudCBlbiBzdGF0aXN0aXF1ZXMgfAp8IC0tLSB8IC0tLSB8IC0tLSAKfCB2ZWN0b3IgfCBgYygpYCB8IFZhcmlhYmxlIHwKfCBmYWN0b3IgfCBgZmFjdG9yKClgIHwgVmFyaWFibGUgcXVhbGl0YXRpdmUgfAp8IGRhdGEuZnJhbWUgfCBgZGF0YS5mcmFtZSgpYCB8IEJhc2UgZGUgZG9ubsOpZXMgfAoKIyMjIFZlY3RldXIKCnwgRGFucyBSIHwgRW4gc3RhdGlzdGlxdWVzIHwKfCAtLS0gfCAtLS0gfAp8IHZlY3RvciB8IFZhcmlhYmxlIHwKfCBTdWl0ZSBkZSBkb25uw6llcyBkZSBtw6ptZSB0eXBlIHwgU8OpcmllIGRlIGRvbm7DqWVzIGhvbW9nw6huZXMgfAoKYGBge3J9CmMoMSwyLDMsNCkgIyDDiXF1aXZhbGVudCDDoCB1bmUgdmFyaWFibGUgcXVhbnRpdGF0aXZlCnN0cihjKDEsMiwzLDQpKQpjKCJob21tZSIsICJmZW1tZSIsICJob21tZSIpICMgU8OpcmllIGRlIGRvbm7DqWVzIHRleHR1ZWxsZXMKc3RyKGMoImhvbW1lIiwgImZlbW1lIiwgImhvbW1lIikpCmBgYAoKKipNYW5pcHVsYXRpb24gZGVzIHZlY3RldXJzIDoqKgoKYGBge3J9CmdlbnJlIDwtIGMoImhvbW1lIiwgImZlbW1lIiwgImhvbW1lIikKZ2VucmVbMV0KZ2VucmVbMToyXQpnZW5yZVtjKDEsIDMpXQpgYGAKCiMjIyBGYWN0ZXVyCgpMZXMgZmFjdGV1cnMgc29udCB1biB0eXBlIHBhcnRpY3VsaWVyIGRlIHZlY3RldXJzIGRhbnMgUiwgZGUgbGEgbcOqbWUgZmHDp29uIHF1ZSBsZXMgdmFyaWFibGVzIHF1YWxpdGF0aXZlcyBzb250IHVuIHR5cGUgZGUgdmFyaWFibGUgcGFydGljdWxpZXIgZGFucyBSLgoKfCBEYW5zIFIgfCBFbiBzdGF0aXN0aXF1ZXMgfAp8IC0tLSB8IC0tLSB8CnwgdmVjdG9yIHwgVmFyaWFibGUgcXVhbGl0YXRpdmUgfAp8IGxldmVscyB8IE1vZGFsaXTDqXMgZGUgbGEgdmFyaWFibGUgfAoKYGBge3J9CmdlbnJlIDwtIGMoImhvbW1lIiwgImZlbW1lIiwgImhvbW1lIikKCiMgVHJhbnNmb3JtYXRpb24gZW4gZmFjdGV1cgpnZW5yZS5mIDwtIGZhY3RvcihnZW5yZSkKc3RyKGdlbnJlLmYpCmdlbnJlLmYKYGBgCgpQb3VyIHZvaXIgbGVzIG1vZGFsaXTDqXMgKGBsZXZlbHNgKSA6CgpgYGB7cn0KbGV2ZWxzKGdlbnJlLmYpCmBgYAoKIyMjIERhdGEuZnJhbWUKCkMnZXN0IGwnw6lxdWl2YWxlbnQgZCd1bmUgYmFzZSBkZSBkb25uw6llcyBlbiBzdGF0aXN0aXF1ZXMgOiB1bmUgc8OpcmllIGRlIHZhcmlhYmxlcyBzdXIgbGVzIG3Dqm1lcyBpbmRpdmlkdXMuCgpQb3VyIHPDqWxlY3Rpb25uZXIgdW5lIHZhcmlhYmxlIGVuIHBhcnRpY3VsaWVyIDoKCmBgYHtyLCBldmFsPUZBTFNFfQpiZGQkdmFyaWFibGUxCmBgYAoKIyBMZXMgZm9uY3Rpb25zCgpMZXMgZm9uY3Rpb25zIHNvbnQgdW4gY29uY2VwdCBjZW50cmFsIGRlcyBsYW5nYWdlcyBkZSBwcm9ncmFtbWF0aW9uLi4uIGV0IGRvbmMgZGUgUiAhCgojIyBBbmF0b21pZSBkJ3VuZSBmb25jdGlvbgoKVG91am91cnMgc291cyBsYSBmb3JtZSA6CgpgYGAKbm9tRGVMYUZvbmN0aW9uKGFyZ3VtZW50cykKYGBgCgorIGBub21EZUxhRm9uY3Rpb25gIDogKipub20gZGUgbGEgZm9uY3Rpb24gw6AgYXBwZWxlcioqCisgYCgpYCA6IGxlcyBwYXJlbnRow6hzZXMgc2lnbmlmaWVudCBxdScqKm9uIGRlbWFuZGUgw6AgUiBkJ8OpeMOpY3V0ZXIgbGEgZm9uY3Rpb24qKi4KKyBgYXJndW1lbnRzYCA6IHVuZSBsaXN0ZSBkJ2FyZ3VtZW50cyBzw6lwYXLDqXMgcGFyIGRlcyB2aXJndWxlcyBldCB1bmUgZXNwYWNlLiBMZSBub21icmUgZCdhcmd1bWVudHMgZMOpcGVuZCBkZXMgZm9uY3Rpb25zLgoKIyMjIExlcyBhcmd1bWVudHMKCkZvbmN0aW9uIHF1aSBuJ2EgYmVzb2luIGQnYXVjdW4gYXJndW1lbnQgOgoKYGBge3J9CmdldHdkKCkKYGBgCgpMYSBmb25jdGlvbiBgYygpYCBhY2NlcHRlIHVuIG5vbWJyZSBpbGxpbWl0w6kgZCdhcmd1bWVudHMgOgoKYGBge3J9CmMoMSwgMiwgMywgNCkKYGBgCgpDZXJ0YWluZXMgZm9uY3Rpb25zIG9udCBkZXMgYXJndW1lbnRzIG9ibGlnYXRvaXJlcyA6CgpgYGB7cn0KbWVhbigpCmBgYAoKTWFpcyA6CgpgYGB7cn0Kbm90ZXMgPC0gYygxMCwgMjApCm1lYW4obm90ZXMpCmBgYAoKQ2VydGFpbmVzIGZvbmN0aW9ucyBwcmVubmVudCBkZXMgYXJndW1lbnRzIGZhbGN1dGF0aWZzLCBxdWkgcGV1dmVudCDDqnRyZSBub21tw6lzLiBEYW5zIGNlIGNhcywgbGUgbm9tIGRlIGwnYXJndW1lbnQgZXN0IHN1aXZpIGQndW4gc2lnbmUgYD1gIHB1aXMgZGUgc2EgdmFsZXVyLgoKYGBge3J9Cm5vdGVzIDwtIGMoMTAsIDIwLCBOQSkKbWVhbihub3RlcywgbmEucm0gPSBUUlVFKQpgYGAKCiMjIEZvbmN0aW9ucyBpbWJyaXF1w6llcwoKSWwgZXN0IGJpZW4gc8O7ciBwb3NzaWJsZSBkJ2ltYnJpcXVlciBub3MgZm9uY3Rpb25zIDoKCmBgYHtyfQptZWFuKGMoYygxMCwgMjApLCBOQSksIG5hLnJtID0gVFJVRSkKYGBgCgpDZSBxdWkgZXN0IGlkZW50aXF1ZSDDoCA6IAoKYGBge3J9Cm5vdGVzIDwtIGMoMTAsIDIwKQpub3RlczIgPC0gYyhub3RlcywgTkEpCm1lYW4obm90ZXMyLCBuYS5ybSA9IFRSVUUpCmBgYAoKUG91ciBjb21wcmVuZHJlIGxlcyBmb25jdGlvbnMgaW1icmlxdcOpZXMsIGlsIGZhdXQgZG9uYyBwcm9jw6lkZXIgcGFyIMOpdGFwZXMsIGVuIHBhcnRhbnQgZGUgbCdpbnTDqXJpZXVyIGRlcyBwYXJlbnRow6hzZXMgcG91ciBhbGxlciB2ZXJzIGwnZXh0w6lyaWV1ci4KCiMgTGVzIHZhcmlhYmxlcwoKRGFucyB1biBsYW5nYWdlIGRlIHByb2dyYW1tYXRpb24sIGxlcyB2YXJpYWJsZXMgcGVybWV0dGVudCBkJ2F0dGVpbmRyZSB1biBuaXZlYXUgZCdhYnN0cmFjdGlvbiBzdXBwbMOpbWVudGFpcmUsIGVuIGF0dHJpYnVhbnQgdW4gbm9tIMOgIHVuIG9iamV0IHBvdXIgbGUgcsOpdXRpbGlzZXIgcGFyIGxhIHN1aXRlLiBFbGxlcyBhbcOpbGlvcmVudCDDqWdhbGVtZW50IGxhIGxpc2liaWxpdMOpIGR1IHByb2dyYW1tZS4KCmBgYHtyfQp2YXJpYWJsZSA8LSAiY291Y291Igp2YXJpYWJsZQpgYGAKCkF0dGVudGlvbiBhdXggZXJyZXVycyBkZSBub3RhdGlvbiAhCgpgYGB7cn0KdmFyaWFibGUKIyBNYWlzLi4uCiJ2YXJpYWJsZSIKYGBgCgojIyBWYXJpYWJsZSBpbmZvcm1hdGlxdWUgLyB2YXJpYWJsZSBzdGF0aXN0aXF1ZQoKKipBdHRlbnRpb24gOioqIGxlIGNvbmNlcHQgZGUgdmFyaWFibGUgKmluZm9ybWF0aXF1ZSogZXN0IHRyw6hzIGRpZmbDqXJlbnQgZGUgdmFyaWFibGUgKnN0YXRpc3RpcXVlKi4gRW4gZWZmZXQsIHVuZSB2YXJpYWJsZSBpbmZvcm1hdGlxdWUgcGV1dCBzdG9ja2VyIG4naW1wb3J0ZSBxdWVsIHR5cGUgZGUgZG9ubsOpZXMsIGFsb3JzIHF1J3VuZSB2YXJpYWJsZSBzdGF0aXN0aXF1ZSBjb3JyZXNwb25kIMOgIHVuZSBzw6lyaWUgZGUgZG9ubsOpZXMgaG9tb2fDqG5lcyBjb2xsZWN0w6llcyBzdXIgZGVzIGluZGl2aWR1cy4KCkxlcyBkZXV4IGNvbmNlcHRzIHNlIHJlY291cGVudCBwYXJmb2lzIDoKCmBgYHtyfQpub3RlcyA8LSBjKDEwLCAyMCwgMTYpCmBgYAoKSWNpLCBsYSB2YXJpYWJsZSBgbm90ZXNgIHBldXQgY29ycmVzcG9uZHJlIMOgIHVuZSB2YXJpYWJsZSBzdGF0aXN0aXF1ZS4KCkVuIHJldmFuY2hlIDoKCmBgYHtyfQp0ZXN0IDwtIG1lYW4obm90ZXMpCmBgYAoKRGFucyBjZSBjYXMsIGxhIHZhcmlhYmxlIGluZm9ybWF0aXF1ZSBgdGVzdGAgY29udGllbnQgbGEgbW95ZW5uZSBkZXMgbm90ZXMsIGNlIHF1aSBuJ2VzdCBwYXMgw6lxdWl2YWxlbnQgw6AgdW5lIHZhcmlhYmxlIGF1IHNlbnMgc3RhdGlzdGlxdWUu