A propos de ce cours

Le contenu ci-dessous est largement inspiré

Le web regorge de ressources sur R:

Ce notebook R a été construit grâce à Markdown sous R studio.

En application de ce cours de découverte des fonctionnalités de base de R, nous utiliserons cette fiche d’exercices.
Il vous est demandé de traiter tous les exercices et de produire un rapport au format notebook de R.
Ce travail est individuel et à rendre par mail pour le 17 Mars.



Généralités sur le logiciel R

Le logiciel R

Le logiciel R est un logiciel de statistique distribué gratuitement par le CRAN (http://cran.r-project.org/). Il est largement utilisé par la communauté statistique, notamment les universitaires, et permet d’accéder à de très nombreux outils statistiques. R comporte les outils suivants:

  • les fonctions de base,
  • un langage de programmation orienté objet,
  • des librairies (aussi appelées packages) - plus de 1800 sur le site CRAN !

Console, script et éditeur

On peut utiliser R en ligne de commande:

  • Le symbole > indique que R attend une instruction.
  • L’utilisateur rentre ses instructions et les valide avec la touche Entrée.
  • Si possible R exécute les instructions, affiche éventuellement une sortie, puis de demande de nouvelles instructions.
  • En cas d’instruction incomplète, le symbole + s’affiche, indiquant que R attend la suite des instructions (instructions sur plusieurs lignes).
  • Le symbole # permet de commenter son code, les commandes de la ligne situées après ce symbole ne sont pas éxécutées. La ligne de commande n’est pas pratique dès que le code devient long et complexe. On écrit alors un script dans un fichier annexe, avec l’extension .R et on l’exécute grâce à la commande \(\texttt{source}\). Il faut éventuellement faire attention à la position du répertoire courant de R.
source("mon_fichier.R") # exécute les instructions contenues dans mon_fichier.R
getwd() # affiche le nom du répertoire courant (working directory)
setwd('C:/Utilisateurs/Dombry/MonTP') # modifie le répertoire courant

Les éditeurs permettent de gérer console, scripts et répertoire courant de manière flexible grâce à une interface graphique avancée. Les deux éditeurs les plus courants sont Rgui et Rstudio.

Rstudio

On utilisera dans ce cours l’interface graphique Rstudio téléchargeable sur le site https://www.rstudio.com/. Rstudio incorpore plusieurs fonctionnalités:

  • fenêtres pour console, éditeur, environnement, historique, graphiques…
  • raccourcis graphiques pour l’installation de package, le répéertoire de travail, le débugage…
  • des fonctionnalités supplémentaires à R, notamment Rmarkdown permettant l’écriture de notebooks permettant de mélanger texte, code R et sorties logiciels.

L’aide sous R

Il est essentiel de savoir utiliser l’aide de R afin d’avoir plus de précisions sur l’utilisation d’une fonction: syntaxe, arguments, options …

help(mean)
?plot

Lorsque l’on ne sait pas très bien quoi chercher, on peut consulter l’aide générale ou encore interroger sur un sujet donné.

help.start()
help.search("median")
??quantile

On peut accéder directement aux exemples d’une fonction ou aux démonstrations ainsi:

example(quantile)
demo(graphics)
demo()

Les packages

Un package est une bibliothèque de programmes externes , c’est-à-dire un ensemble de programmes R qui complète les fonctions de base et permet d’augmenter les fonctionnalités de R. Certains sont considérer comme indispensable et sont installés par défaut. Avant d’être utilisé, un package doit être installé (s’il ne l’est pas déjà) grâce à la commande \(\texttt{install.packages}\), puis obligatoirement charger grâce à la commande \(\texttt{library}\). Les commandes suivantes sont les plus utiles, on peut aussi utiliser l’interface graphique (onglet Tools).

install.packages(MASS, dependencies=T) #charger le package MASS avec ses dépendances
library(MASS) # charger un package existant.
library(help = MASS) # retourne la liste des fonctions de la librairie MASS 
update.packages(MASS) # mettre à jour le package MASS
library() # lister les les packages installés sur l'ordinateur
update.packages() # mettre à jour tous les packages

Exemple: la fonction \(\texttt{mvrnorm}\) du package MASS permet de simuler des vecteurs Gaussiens. Pour l’exécuter, on commence par charger le package, puis on consulte l’aide de la fonction avant de l’utiliser.

library(MASS) # charger un package existant.
?mvrnorm
mvrnorm(n=3,mu=c(0,1),Sigma=matrix(c(1,0,0.5,0.5),2,2))


Les objets R

Création, affichage, suppression d’un objet

La création d’un objet se fait généralement par affectation an donnant un nom à l’objet avec l’un des trois opérateurs <-, -> et =. Dans la suite, on privilégiera -> pour l’affectation. Si un objet n’existe pas, l’affectation le crée. Sinon, l’affectation écrase la valeur précédente sans message d’avertissement.

L’affichage se fait grâce à la commande \(\texttt{print}\) ou tout simplement en appelant l’objet par son nom.

La liste de tous les objets crées s’obtient par la commande \(\texttt{ls()}\). On supprime un ou plusieurs objets grâce à la commande \(\texttt{rm(objet1,objet2,objet3)}\). De manière alternative à ces commandes en ligne, la fenêtre Environment de l’interface graphique permet la gestion des variables.

Exemples:

a <- 41 # l'objet a est créé avec la valeur 41
a # on affiche a
print(a) # on affiche a
x <- a # x reçoit la valeur de a
x = a # x reçoit la valeur de a
a -> x # x reçoit la valeur de a
x <- cos # x est écrasé et devient une fonction
ls() # liste des objets crées
rm(a); ls() # on supprime a 
rm(list=ls()) # suppression de tous les objets

Les différents types d’objets

Les types d’objets les plus usuels sont les suivants:

  • null (objet vide): \(\texttt{NULL}\)
  • logical (booléen vrai/faux): \(\texttt{TRUE}\), \(\texttt{FALSE}\) abrégé en \(\texttt{T}\), \(\texttt{F}\)
  • numeric (nombre réel): \(\texttt{1}\), \(\texttt{2.3333}\), \(\texttt{pi}\), \(\texttt{1e-10}\)
  • complex (nombre complexe): \(\texttt{2+0i}\), \(\texttt{2i}\)
  • character (chaîne de caractères): \(\texttt{'hello'}\), \(\texttt{"1"}\)
  • list (liste = collections d’objets hétérogènes)
  • function (fonction): \(\texttt{exp}\), \(\texttt{solve}\), \(\texttt{length}\)

Chaque objet possède deux attributs intrinsèques: son mode \(\texttt{mode()}\) et sa longueur \(\texttt{length()}\). Certains objets on plus d’attributs dont on peut connaître la liste grâce à la fonction \(\texttt{attributes()}\).

1<2
a <- cos(13); mode(a)
b <- 'toto'; mode(b)
c <- runif; mode(c)

On peut tester si objet est d’un type donné grâce aux fonctions \(\texttt{is.null()}\), \(\texttt{is.numeric()}\), \(\texttt{is.character()}\) … Dans certains cas, on peut convertir un objet d’un type en un autre avec les commandes \(\texttt{as.numeric()}\), \(\texttt{as.character()}\)… A utiliser avec prudence !

a <- TRUE
a; as.numeric(a); as.character(a)

Dans certaines opérations, les booléens sont assimilés aux valeurs 0 (FALSE) et 1 (TRUE). Exemple:

13+F+F
sum(T,F,F,F,T)

Valeurs spéciales: NA, Inf, NaN

Il est utile en statistique de pouvoir indiqué qu’un objet n’est pas renseigné. Cela est fait grâce au symbole \(\texttt{NA}\) (Not Available). Exemple:

age <- c(27,25,28); age[4] <- NA # on crèe une variable age avec la 4eme valeur manquante
age; is.na(age) # affichage et repérage des valeurs manquantes
age+3 # NA a ses propres règles de calcul

Les valeurs \(\texttt{Inf}\) (infinity) et \(\texttt{NaN}\) (Not a Number) proviennent généralement de problèmes calculatoires. Exemple:

1/0; exp(2019); log(-2)

Les vecteurs

Les matrices

Les facteurs

Les listes

Les fonctions

LS0tDQp0aXRsZTogIkNvdXJzIGxvZ2ljaWVsIFIiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0DQotLS0NCg0KDQojIyMgQSBwcm9wb3MgZGUgY2UgY291cnMNCg0KTGUgY29udGVudSBjaS1kZXNzb3VzIGVzdCBsYXJnZW1lbnQgaW5zcGly6SAgDQoNCiogZHUgbGl2cmUgKlN0YXRpc3RpcXVlcyBhdmVjIFIqIGRlIENvcm5pbGxvbiBldCBhbC4gKGRpc3BvbmlibGUg4CBsYSBiaWJsaW90aOhxdWUpIA0KKiBkdSBjb3VycyBkZSBBbm5lIFBoaWxsaXBlLCBVbml2ZXJzaXTpIGRlIE5hbnRlcyAoW2Rpc3BvbmlibGUgc3VyIHNhIHBhZ2Ugd2ViXShodHRwczovL3d3dy5tYXRoLnNjaWVuY2VzLnVuaXYtbmFudGVzLmZyL35waGlsaXBwZS9kb3dubG9hZC9Bbm5lLVBoaWxpcHBlLWNvdXJzLVIucGRmKSkuIA0KDQpMZSB3ZWIgcmVnb3JnZSBkZSByZXNzb3VyY2VzIHN1ciBSOg0KDQoqIG9uIHBvdXJyYSBjb21tZW5jZXIgcGFyIGxhIGZpY2hlIFtCYXNlIFIgY2hlYXRzaGVldF0oaHR0cHM6Ly93d3cucnN0dWRpby5jb20vd3AtY29udGVudC91cGxvYWRzLzIwMTYvMDUvYmFzZS1yLnBkZikuDQoqIFBvdXIgcGx1cyBkZSBk6XRhaWxzLCBvbiBjb25zdWx0ZXJhIGRlIHBy6WbpcmVuY2UgbGEgW3BhZ2Ugb2ZmaWNpZWxsZSBkdSBDUkFOXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZykgYWluc2kgcXVlIGxlIG1hbnVlbCBbQW4gaW50cm9kdWN0aW9uIHRvIFJdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL2RvYy9tYW51YWxzL3ItcmVsZWFzZS9SLWludHJvLnBkZikuIA0KKiBQb3VyIHN1cnZvbGVyIHJhcGlkZW1lbnQgbGVzIGZvbmN0aW9ucyBpbXBvcnRhbnRlcywgbGEgW1IgcmVmZXJlbmNlIGNhcmRdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL2RvYy9jb250cmliL1Nob3J0LXJlZmNhcmQucGRmKSBlc3QgYmllbiB1dGlsZS4NCg0KQ2Ugbm90ZWJvb2sgUiBhIOl06SBjb25zdHJ1aXQgZ3LiY2Ug4CBNYXJrZG93biBzb3VzIFIgc3R1ZGlvLiANCg0KKiBDZXQgb3V0aWwgcGVybWV0IGxhIHLpZGFjdGlvbiBkZSByYXBwb3J0cyBpbnTpZ3JhbnQgZHUgdGV4dGUsIGR1IGNvZGUgZXQgZGVzIHNvcnRpZXMgbG9naWNpZWxzLg0KKiBMYSBzeW50YXhlIGVzdCBhc3NleiBmYWNpbGUsIG9uIHBvdXJyYSBjb25zdWx0ZXIgbGUgY29kZSBkZSBjZSBkb2N1bWVudCBwb3VyIHMneSBpbml0aWVyLiAgDQoqIFBvdXIgZGF2YW50YWdlIGRlIGTpdGFpbHMsIGNvbnN1bHRlciBsYSBbUm1hcmtkb3duIGNoZWF0c2hlZXRdKGh0dHBzOi8vd3d3LnJzdHVkaW8uY29tL3dwLWNvbnRlbnQvdXBsb2Fkcy8yMDE1LzAyL3JtYXJrZG93bi1jaGVhdHNoZWV0LnBkZikuIA0KDQpFbiBhcHBsaWNhdGlvbiBkZSBjZSBjb3VycyBkZSBk6WNvdXZlcnRlIGRlcyBmb25jdGlvbm5hbGl06XMgZGUgYmFzZSBkZSBSLCBub3VzIHV0aWxpc2Vyb25zIGNldHRlIFtmaWNoZSBkJ2V4ZXJjaWNlc10oaHR0cHM6Ly93d3cubWF0aC5zY2llbmNlcy51bml2LW5hbnRlcy5mci9+cGhpbGlwcGUvUl9mcmVld2FyZV9maWxlcy9PdXRpbC1pbmZvLXBvdXItc3RhdC5wZGYpLiAgDQoqKklsIHZvdXMgZXN0IGRlbWFuZOkgZGUgdHJhaXRlciB0b3VzIGxlcyBleGVyY2ljZXMgZXQgZGUgcHJvZHVpcmUgdW4gcmFwcG9ydCBhdSBmb3JtYXQgbm90ZWJvb2sgZGUgUioqLiAgDQpDZSB0cmF2YWlsIGVzdCAqKmluZGl2aWR1ZWwqKiBldCDgIHJlbmRyZSBwYXIgbWFpbCBwb3VyIGxlICoqMTcgTWFycyoqLiANCg0KKioqIA0KKioqDQoNCiMjIyBH6W7pcmFsaXTpcyBzdXIgbGUgbG9naWNpZWwgUg0KDQojIyMjIExlIGxvZ2ljaWVsIFINCkxlIGxvZ2ljaWVsIFIgZXN0IHVuIGxvZ2ljaWVsIGRlIHN0YXRpc3RpcXVlIGRpc3RyaWJ16SBncmF0dWl0ZW1lbnQgcGFyIGxlIENSQU4gKFtodHRwOi8vY3Jhbi5yLXByb2plY3Qub3JnL10oaHR0cDovL2NyYW4uci1wcm9qZWN0Lm9yZy8pKS4gSWwgZXN0IGxhcmdlbWVudCB1dGlsaXPpIHBhciBsYSBjb21tdW5hdXTpIHN0YXRpc3RpcXVlLCBub3RhbW1lbnQgbGVzIHVuaXZlcnNpdGFpcmVzLCBldCBwZXJtZXQgZCdhY2PpZGVyIOAgZGUgdHLocyBub21icmV1eCBvdXRpbHMgc3RhdGlzdGlxdWVzLiBSIGNvbXBvcnRlIGxlcyBvdXRpbHMgc3VpdmFudHM6DQoNCiogbGVzIGZvbmN0aW9ucyBkZSBiYXNlLA0KKiB1biBsYW5nYWdlIGRlIHByb2dyYW1tYXRpb24gb3JpZW506SBvYmpldCwNCiogZGVzIGxpYnJhaXJpZXMgKGF1c3NpIGFwcGVs6WVzIHBhY2thZ2VzKSAtIHBsdXMgZGUgMTgwMCBzdXIgbGUgc2l0ZSBDUkFOICENCg0KIyMjIyBDb25zb2xlLCBzY3JpcHQgZXQg6WRpdGV1ciANCk9uIHBldXQgdXRpbGlzZXIgUiBlbiBsaWduZSBkZSBjb21tYW5kZToNCg0KKiBMZSBzeW1ib2xlID4gaW5kaXF1ZSBxdWUgUiBhdHRlbmQgdW5lIGluc3RydWN0aW9uLg0KKiBMJ3V0aWxpc2F0ZXVyIHJlbnRyZSBzZXMgaW5zdHJ1Y3Rpb25zIGV0IGxlcyB2YWxpZGUgYXZlYyBsYSB0b3VjaGUgRW50cullLg0KKiBTaSBwb3NzaWJsZSBSIGV46WN1dGUgbGVzIGluc3RydWN0aW9ucywgYWZmaWNoZSDpdmVudHVlbGxlbWVudCB1bmUgc29ydGllLCBwdWlzIGRlIGRlbWFuZGUgZGUgbm91dmVsbGVzIGluc3RydWN0aW9ucy4NCiogRW4gY2FzIGQnaW5zdHJ1Y3Rpb24gaW5jb21wbOh0ZSwgbGUgc3ltYm9sZSArIHMnYWZmaWNoZSwgaW5kaXF1YW50IHF1ZSBSIGF0dGVuZCBsYSBzdWl0ZSBkZXMgaW5zdHJ1Y3Rpb25zIChpbnN0cnVjdGlvbnMgc3VyIHBsdXNpZXVycyBsaWduZXMpLg0KKiBMZSBzeW1ib2xlICMgcGVybWV0IGRlIGNvbW1lbnRlciBzb24gY29kZSwgIGxlcyBjb21tYW5kZXMgZGUgbGEgbGlnbmUgc2l0dellcyBhcHLocyBjZSBzeW1ib2xlIG5lIHNvbnQgcGFzIOl46WN1dOllcy4NCkxhIGxpZ25lIGRlIGNvbW1hbmRlIG4nZXN0IHBhcyBwcmF0aXF1ZSBk6HMgcXVlIGxlIGNvZGUgZGV2aWVudCBsb25nIGV0IGNvbXBsZXhlLiBPbiDpY3JpdCBhbG9ycyB1biBzY3JpcHQgZGFucyB1biBmaWNoaWVyIGFubmV4ZSwgYXZlYyBsJ2V4dGVuc2lvbiAuUiBldCBvbiBsJ2V46WN1dGUgZ3LiY2Ug4CBsYSBjb21tYW5kZSAkXHRleHR0dHtzb3VyY2V9JC4NCklsIGZhdXQg6XZlbnR1ZWxsZW1lbnQgZmFpcmUgYXR0ZW50aW9uIOAgbGEgcG9zaXRpb24gZHUgculwZXJ0b2lyZSBjb3VyYW50IGRlIFIuDQpgYGB7cn0NCnNvdXJjZSgibW9uX2ZpY2hpZXIuUiIpICMgZXjpY3V0ZSBsZXMgaW5zdHJ1Y3Rpb25zIGNvbnRlbnVlcyBkYW5zIG1vbl9maWNoaWVyLlINCmdldHdkKCkgIyBhZmZpY2hlIGxlIG5vbSBkdSBy6XBlcnRvaXJlIGNvdXJhbnQgKHdvcmtpbmcgZGlyZWN0b3J5KQ0Kc2V0d2QoJ0M6L1V0aWxpc2F0ZXVycy9Eb21icnkvTW9uVFAnKSAjIG1vZGlmaWUgbGUgculwZXJ0b2lyZSBjb3VyYW50DQpgYGANCg0KTGVzIOlkaXRldXJzIHBlcm1ldHRlbnQgZGUgZ+lyZXIgY29uc29sZSwgc2NyaXB0cyBldCBy6XBlcnRvaXJlIGNvdXJhbnQgIGRlIG1hbmnocmUgZmxleGlibGUgZ3LiY2Ug4CB1bmUgaW50ZXJmYWNlIGdyYXBoaXF1ZSBhdmFuY+llLiBMZXMgZGV1eCDpZGl0ZXVycyBsZXMgcGx1cyBjb3VyYW50cyBzb250IFJndWkgZXQgUnN0dWRpby4NCg0KIyMjIyBSc3R1ZGlvDQpPbiB1dGlsaXNlcmEgZGFucyBjZSBjb3VycyBsJ2ludGVyZmFjZSBncmFwaGlxdWUgUnN0dWRpbyB06WzpY2hhcmdlYWJsZSBzdXIgbGUgc2l0ZSBbaHR0cHM6Ly93d3cucnN0dWRpby5jb20vXShodHRwczovL3d3dy5yc3R1ZGlvLmNvbS8pLg0KUnN0dWRpbyBpbmNvcnBvcmUgcGx1c2lldXJzIGZvbmN0aW9ubmFsaXTpczoNCg0KKiBmZW7qdHJlcyBwb3VyICBjb25zb2xlLCDpZGl0ZXVyLCBlbnZpcm9ubmVtZW50LCBoaXN0b3JpcXVlLCBncmFwaGlxdWVzLi4uDQoqIHJhY2NvdXJjaXMgZ3JhcGhpcXVlcyBwb3VyIGwnaW5zdGFsbGF0aW9uIGRlIHBhY2thZ2UsIGxlIHLpcOllcnRvaXJlIGRlIHRyYXZhaWwsIGxlIGTpYnVnYWdlLi4uDQoqIGRlcyBmb25jdGlvbm5hbGl06XMgc3VwcGzpbWVudGFpcmVzIOAgUiwgbm90YW1tZW50IFJtYXJrZG93biBwZXJtZXR0YW50IGwn6WNyaXR1cmUgZGUgbm90ZWJvb2tzIHBlcm1ldHRhbnQgZGUgbelsYW5nZXIgdGV4dGUsIGNvZGUgUiBldCBzb3J0aWVzIGxvZ2ljaWVscy4NCg0KIyMjIyBMJ2FpZGUgc291cyBSDQpJbCBlc3QgZXNzZW50aWVsIGRlIHNhdm9pciB1dGlsaXNlciBsJ2FpZGUgZGUgUiBhZmluIGQnYXZvaXIgcGx1cyBkZSBwculjaXNpb25zIHN1ciBsJ3V0aWxpc2F0aW9uIGQndW5lIGZvbmN0aW9uOiBzeW50YXhlLCBhcmd1bWVudHMsIG9wdGlvbnMgLi4uIA0KYGBge3J9DQpoZWxwKG1lYW4pDQo/cGxvdA0KYGBgDQpMb3JzcXVlIGwnb24gbmUgc2FpdCBwYXMgdHLocyBiaWVuIHF1b2kgY2hlcmNoZXIsIG9uIHBldXQgY29uc3VsdGVyIGwnYWlkZSBn6W7pcmFsZSBvdSBlbmNvcmUgaW50ZXJyb2dlciBzdXIgdW4gc3VqZXQgZG9ubukuDQpgYGB7cn0NCmhlbHAuc3RhcnQoKQ0KaGVscC5zZWFyY2goIm1lZGlhbiIpDQo/P3F1YW50aWxlDQpgYGANCk9uIHBldXQgYWNj6WRlciBkaXJlY3RlbWVudCBhdXggZXhlbXBsZXMgZCd1bmUgZm9uY3Rpb24gb3UgYXV4IGTpbW9uc3RyYXRpb25zIGFpbnNpOg0KYGBge3J9DQpleGFtcGxlKHF1YW50aWxlKQ0KZGVtbyhncmFwaGljcykNCmRlbW8oKQ0KYGBgDQoNCiMjIyMgTGVzIHBhY2thZ2VzDQpVbiBwYWNrYWdlIGVzdCB1bmUgYmlibGlvdGjocXVlIGRlIHByb2dyYW1tZXMgZXh0ZXJuZXMgLCBjJ2VzdC3gLWRpcmUgdW4gZW5zZW1ibGUgZGUgcHJvZ3JhbW1lcyBSIHF1aSBjb21wbOh0ZSBsZXMgZm9uY3Rpb25zIGRlIGJhc2UgZXQgcGVybWV0IGQnYXVnbWVudGVyIGxlcyBmb25jdGlvbm5hbGl06XMgZGUgUi4gQ2VydGFpbnMgc29udCBjb25zaWTpcmVyIGNvbW1lIGluZGlzcGVuc2FibGUgZXQgc29udCBpbnN0YWxs6XMgcGFyIGTpZmF1dC4gQXZhbnQgZCfqdHJlIHV0aWxpc+ksIHVuIHBhY2thZ2UgZG9pdCDqdHJlIGluc3RhbGzpIChzJ2lsIG5lIGwnZXN0IHBhcyBk6WrgKSBncuJjZSDgIGxhIGNvbW1hbmRlICRcdGV4dHR0e2luc3RhbGwucGFja2FnZXN9JCwgcHVpcyBvYmxpZ2F0b2lyZW1lbnQgY2hhcmdlciBncuJjZSDgIGxhIGNvbW1hbmRlICRcdGV4dHR0e2xpYnJhcnl9JC4gTGVzIGNvbW1hbmRlcyBzdWl2YW50ZXMgc29udCBsZXMgcGx1cyB1dGlsZXMsIG9uIHBldXQgYXVzc2kgdXRpbGlzZXIgbCdpbnRlcmZhY2UgZ3JhcGhpcXVlIChvbmdsZXQgVG9vbHMpLg0KYGBge3J9DQppbnN0YWxsLnBhY2thZ2VzKE1BU1MsIGRlcGVuZGVuY2llcz1UKSAjY2hhcmdlciBsZSBwYWNrYWdlIE1BU1MgYXZlYyBzZXMgZOlwZW5kYW5jZXMNCmxpYnJhcnkoTUFTUykgIyBjaGFyZ2VyIHVuIHBhY2thZ2UgZXhpc3RhbnQuDQpsaWJyYXJ5KGhlbHAgPSBNQVNTKSAjIHJldG91cm5lIGxhIGxpc3RlIGRlcyBmb25jdGlvbnMgZGUgbGEgbGlicmFpcmllIE1BU1MgDQp1cGRhdGUucGFja2FnZXMoTUFTUykgIyBtZXR0cmUg4CBqb3VyIGxlIHBhY2thZ2UgTUFTUw0KbGlicmFyeSgpICMgbGlzdGVyIGxlcyBsZXMgcGFja2FnZXMgaW5zdGFsbOlzIHN1ciBsJ29yZGluYXRldXINCnVwZGF0ZS5wYWNrYWdlcygpICMgbWV0dHJlIOAgam91ciB0b3VzIGxlcyBwYWNrYWdlcw0KYGBgDQpFeGVtcGxlOiBsYSBmb25jdGlvbiAkXHRleHR0dHttdnJub3JtfSQgZHUgcGFja2FnZSBNQVNTIHBlcm1ldCBkZSBzaW11bGVyIGRlcyB2ZWN0ZXVycyBHYXVzc2llbnMuIFBvdXIgbCdleOljdXRlciwgb24gY29tbWVuY2UgcGFyIGNoYXJnZXIgbGUgcGFja2FnZSwgcHVpcyBvbiBjb25zdWx0ZSBsJ2FpZGUgZGUgbGEgZm9uY3Rpb24gYXZhbnQgZGUgbCd1dGlsaXNlci4NCmBgYHtyfQ0KbGlicmFyeShNQVNTKSAjIGNoYXJnZXIgdW4gcGFja2FnZSBleGlzdGFudC4NCj9tdnJub3JtDQptdnJub3JtKG49MyxtdT1jKDAsMSksU2lnbWE9bWF0cml4KGMoMSwwLDAuNSwwLjUpLDIsMikpDQpgYGANCg0KKioqIA0KKioqDQojIyMgTGVzIG9iamV0cyBSDQojIyMjIENy6WF0aW9uLCBhZmZpY2hhZ2UsIHN1cHByZXNzaW9uIGQndW4gb2JqZXQNCkxhIGNy6WF0aW9uIGQndW4gb2JqZXQgc2UgZmFpdCBn6W7pcmFsZW1lbnQgcGFyIGFmZmVjdGF0aW9uIGFuIGRvbm5hbnQgdW4gbm9tIOAgbCdvYmpldCBhdmVjIGwndW4gZGVzIHRyb2lzIG9w6XJhdGV1cnMgPC0sIC0+IGV0ID0uIERhbnMgbGEgc3VpdGUsIG9uIHByaXZpbOlnaWVyYSAtPiBwb3VyIGwnYWZmZWN0YXRpb24uIFNpIHVuIG9iamV0IG4nZXhpc3RlIHBhcywgbCdhZmZlY3RhdGlvbiBsZSBjcullLiBTaW5vbiwgKipsJ2FmZmVjdGF0aW9uIOljcmFzZSBsYSB2YWxldXIgcHLpY+lkZW50ZSBzYW5zIG1lc3NhZ2UgZCdhdmVydGlzc2VtZW50KiouDQoNCkwnYWZmaWNoYWdlIHNlIGZhaXQgZ3LiY2Ug4CBsYSBjb21tYW5kZSAkXHRleHR0dHtwcmludH0kIG91IHRvdXQgc2ltcGxlbWVudCBlbiBhcHBlbGFudCBsJ29iamV0IHBhciBzb24gbm9tLg0KDQpMYSBsaXN0ZSBkZSB0b3VzIGxlcyBvYmpldHMgY3LpZXMgcydvYnRpZW50IHBhciBsYSBjb21tYW5kZSAkXHRleHR0dHtscygpfSQuIE9uIHN1cHByaW1lIHVuIG91IHBsdXNpZXVycyBvYmpldHMgZ3LiY2Ug4CBsYSBjb21tYW5kZSAkXHRleHR0dHtybShvYmpldDEsb2JqZXQyLG9iamV0Myl9JC4gRGUgbWFuaehyZSBhbHRlcm5hdGl2ZSDgIGNlcyBjb21tYW5kZXMgZW4gbGlnbmUsIGxhIGZlbup0cmUgRW52aXJvbm1lbnQgZGUgbCdpbnRlcmZhY2UgZ3JhcGhpcXVlIHBlcm1ldCBsYSBnZXN0aW9uIGRlcyB2YXJpYWJsZXMuDQoNCkV4ZW1wbGVzOg0KYGBge3J9DQphIDwtIDQxICMgbCdvYmpldCBhIGVzdCBjcunpIGF2ZWMgbGEgdmFsZXVyIDQxDQphICMgb24gYWZmaWNoZSBhDQpwcmludChhKSAjIG9uIGFmZmljaGUgYQ0KeCA8LSBhICMgeCByZedvaXQgbGEgdmFsZXVyIGRlIGENCnggPSBhICMgeCByZedvaXQgbGEgdmFsZXVyIGRlIGENCmEgLT4geCAjIHggcmXnb2l0IGxhIHZhbGV1ciBkZSBhDQp4IDwtIGNvcyAjIHggZXN0IOljcmFz6SBldCBkZXZpZW50IHVuZSBmb25jdGlvbg0KbHMoKSAjIGxpc3RlIGRlcyBvYmpldHMgY3LpZXMNCnJtKGEpOyBscygpICMgb24gc3VwcHJpbWUgYSANCnJtKGxpc3Q9bHMoKSkgIyBzdXBwcmVzc2lvbiBkZSB0b3VzIGxlcyBvYmpldHMNCg0KYGBgDQoNCiMjIyMgTGVzIGRpZmbpcmVudHMgdHlwZXMgZCdvYmpldHMNCkxlcyB0eXBlcyBkJ29iamV0cyBsZXMgcGx1cyB1c3VlbHMgc29udCBsZXMgc3VpdmFudHM6DQoNCiogKipudWxsKiogKG9iamV0IHZpZGUpOiAkXHRleHR0dHtOVUxMfSQNCiogKipsb2dpY2FsKiogKGJvb2zpZW4gdnJhaS9mYXV4KTogJFx0ZXh0dHR7VFJVRX0kLCAkXHRleHR0dHtGQUxTRX0kIGFiculn6SBlbiAkXHRleHR0dHtUfSQsICRcdGV4dHR0e0Z9JA0KKiAqKm51bWVyaWMqKiAobm9tYnJlIHLpZWwpOiAkXHRleHR0dHsxfSQsICRcdGV4dHR0ezIuMzMzM30kLCAkXHRleHR0dHtwaX0kLCAkXHRleHR0dHsxZS0xMH0kDQoqICoqY29tcGxleCoqIChub21icmUgY29tcGxleGUpOiAkXHRleHR0dHsyKzBpfSQsICRcdGV4dHR0ezJpfSQNCiogKipjaGFyYWN0ZXIqKiAoY2hh7m5lIGRlIGNhcmFjdOhyZXMpOiAkXHRleHR0dHsnaGVsbG8nfSQsICRcdGV4dHR0eyIxIn0kDQoqICoqbGlzdCoqIChsaXN0ZSA9IGNvbGxlY3Rpb25zIGQnb2JqZXRzIGjpdOlyb2fobmVzKQ0KKiAqKmZ1bmN0aW9uKiogKGZvbmN0aW9uKTogJFx0ZXh0dHR7ZXhwfSQsICRcdGV4dHR0e3NvbHZlfSQsICRcdGV4dHR0e2xlbmd0aH0kDQoNCg0KQ2hhcXVlIG9iamV0IHBvc3PoZGUgZGV1eCBhdHRyaWJ1dHMgaW50cmluc+hxdWVzOiBzb24gbW9kZSAgJFx0ZXh0dHR7bW9kZSgpfSQgZXQgc2EgbG9uZ3VldXIgJFx0ZXh0dHR7bGVuZ3RoKCl9JC4gQ2VydGFpbnMgb2JqZXRzIG9uIHBsdXMgZCdhdHRyaWJ1dHMgZG9udCBvbiBwZXV0IGNvbm5h7nRyZSBsYSBsaXN0ZSBncuJjZSDgIGxhIGZvbmN0aW9uICRcdGV4dHR0e2F0dHJpYnV0ZXMoKX0kLg0KYGBge3J9DQoxPDINCmEgPC0gY29zKDEzKTsgbW9kZShhKQ0KYiA8LSAndG90byc7IG1vZGUoYikNCmMgPC0gcnVuaWY7IG1vZGUoYykNCmBgYA0KDQpPbiBwZXV0IHRlc3RlciBzaSBvYmpldCBlc3QgZCd1biB0eXBlIGRvbm7pIGdy4mNlIGF1eCBmb25jdGlvbnMgJFx0ZXh0dHR7aXMubnVsbCgpfSQsICRcdGV4dHR0e2lzLm51bWVyaWMoKX0kLCAkXHRleHR0dHtpcy5jaGFyYWN0ZXIoKX0kIC4uLiBEYW5zIGNlcnRhaW5zIGNhcywgb24gcGV1dCBjb252ZXJ0aXIgdW4gb2JqZXQgZCd1biB0eXBlIGVuIHVuIGF1dHJlIGF2ZWMgbGVzIGNvbW1hbmRlcyAkXHRleHR0dHthcy5udW1lcmljKCl9JCwgJFx0ZXh0dHR7YXMuY2hhcmFjdGVyKCl9JC4uLiBBIHV0aWxpc2VyIGF2ZWMgcHJ1ZGVuY2UgIQ0KYGBge3J9DQphIDwtIFRSVUUNCmE7IGFzLm51bWVyaWMoYSk7IGFzLmNoYXJhY3RlcihhKQ0KYGBgDQpEYW5zIGNlcnRhaW5lcyBvcOlyYXRpb25zLCBsZXMgYm9vbOllbnMgc29udCBhc3NpbWls6XMgYXV4IHZhbGV1cnMgMCAoRkFMU0UpIGV0IDEgKFRSVUUpLiBFeGVtcGxlOg0KYGBge3J9DQoxMytGK0YNCnN1bShULEYsRixGLFQpDQpgYGANCg0KIyMjIyBWYWxldXJzIHNw6WNpYWxlczogTkEsIEluZiwgTmFODQpJbCBlc3QgdXRpbGUgZW4gc3RhdGlzdGlxdWUgZGUgcG91dm9pciBpbmRpcXXpIHF1J3VuIG9iamV0IG4nZXN0IHBhcyByZW5zZWlnbukuIENlbGEgZXN0IGZhaXQgZ3LiY2UgYXUgc3ltYm9sZSAkXHRleHR0dHtOQX0kIChOb3QgQXZhaWxhYmxlKS4gRXhlbXBsZToNCmBgYHtyfQ0KYWdlIDwtIGMoMjcsMjUsMjgpOyBhZ2VbNF0gPC0gTkEgIyBvbiBjcuhlIHVuZSB2YXJpYWJsZSBhZ2UgYXZlYyBsYSA0ZW1lIHZhbGV1ciBtYW5xdWFudGUNCmFnZTsgaXMubmEoYWdlKSAjIGFmZmljaGFnZSBldCByZXDpcmFnZSBkZXMgdmFsZXVycyBtYW5xdWFudGVzDQphZ2UrMyAjIE5BIGEgc2VzIHByb3ByZXMgcuhnbGVzIGRlIGNhbGN1bA0KYGBgDQpMZXMgdmFsZXVycyAkXHRleHR0dHtJbmZ9JCAoaW5maW5pdHkpIGV0ICRcdGV4dHR0e05hTn0kIChOb3QgYSBOdW1iZXIpIHByb3ZpZW5uZW50IGfpbulyYWxlbWVudCBkZSBwcm9ibOhtZXMgY2FsY3VsYXRvaXJlcy4gRXhlbXBsZToNCmBgYHtyfQ0KMS8wOyBleHAoMjAxOSk7IGxvZygtMikNCg0KYGBgDQoNCiMjIyMgTGVzIHZlY3RldXJzDQojIyMjIExlcyBtYXRyaWNlcw0KIyMjIyBMZXMgZmFjdGV1cnMNCiMjIyMgTGVzIGxpc3Rlcw0KIyMjIyBMZXMgZm9uY3Rpb25z