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

Le langage R en général

Quelques rappels sur le langage R.

Symboles et opérateurs

Opérateur Rôle Exemple
+ Addition 1+1
- Soustraction 1-1
/ Division 1/1
* Multiplication 1*1
^ Puissance 10^2
Symbole Rôle Exemple
<- Assignation à une variable animaux <- c("chien", "chat")
() Exécution d’une fonction. Contient souvent des arguments c(1, 2, 3)
[] Sélection d’un sous-ensemble dans une variable, une base de données, etc. 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)
~ (tilde) Signe qui peut avoir plusieurs significations selon le contexte boxplot(heures.tv ~ sexe, data = hdv2003)
, Séparer des arguments d’une fonction table(hdv2003$sexe, hdv2003$cuisine)

Exemples d’utilisation des commentaires :

# Cette ligne n'est pas interprétée par R
c("chien", "chat") # Fonction


Exemples d’utilisation des parenthèses et des crochets :

[1] \chien\
chien
# En revanche :
animaux(1)

Raccourcis clavier essentiels dans RStudio

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

R est sensible…

… à la casse (minuscules/majuscules)

Exemple parmi d’autres, avec ici le nom des fonctions :

# Cette fonction est connue de R
factor(c(\chien\, \chat\))
[1] chien chat 
Levels: chat chien
# Mais si on fait une erreur de casse :
Factor(c(\chien\, \chat\))


De même pour les variables

chien

chat
# Mais si on fait une erreur de casse :
Animaux

… à la syntaxe

Dans les noms de variables et de fonctions, les seuls caractères employés sont :

  • lettres majuscules et minuscules (pas de caractères accentués)
  • tirets du bas (underscore) _ et points .

Attention à ne JAMAIS employer d’espaces.

Sur les données

Reconnaître les types / structures 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"
Warning message:
In scan(file = file, what = what, sep = sep, quote = quote, dec = dec,  :
  Fin de fichier (EOF) dans une chaîne de caractères entre guillements
typeof("1")
[1] "character"
typeof(NA)
[1] "logical"


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

# Ce calcul fonctionne :
1+1
[1] 2
# Mais...
1+\1\


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

Le concept de vecteur (suite de données de même type) dans R est proche de celui de variable en statistiques (série de données homogènes sur des individus), même si tous les vecteurs ne sont pas forcément des variables au sens statistique.

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\
homme

femme

homme
str(c(\homme\, \femme\, \homme\))
 chr [1:3] \homme\ \femme\ \homme\


Manipulation des vecteurs :

[1] \homme\
homme
genre[1:2]
[1] \homme\ \femme\
homme

femme
genre[c(1, 3)]
[1] \homme\ \homme\
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 En statistiques
factor Variable qualitative
levels Modalités de la variable


Pour voir les modalités (levels) :

levels(genre.f)
[1] \femme\ \homme\
femme

homme

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)


Décomposition :

  • nomDeLaFonction : nom de la fonction à appeler
  • () : les parenthèses signifient qu’on demande à R d’éxéuter 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 si on donne l’argument obligatoire, tout se passe bien :

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)
# Sans l'argument facultatif na.rm :
mean(notes)
# Avec l'argument facultatif na.rm :
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


Attention aux erreurs de notation !

variable
# Mais...
"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.

Pense-bête des fonctions les plus courantes

Ci-après, une liste des fonctions les plus courantes dans R. Les exemples donnés sont très succincts : reportez-vous aux supports de cours pour des “vrais” exemples plus développés.

Librairies / paquets

Nom de la fonction Utilité Exemple
install.packages Installer un paquet R install.packages("questionr")
library Charger un paquet R en mémoire library(questionr)
Nom du paquet Utilité
dplyr Paquet R permettant des recodages très avancés
questionr Paquet R français adapté aux enquêtes de sciences sociales, avec des fonctions utiles pour produire simplement des tableaux croisés, des tris à plat, etc.
tidyverse Ensemble de paquets utiles pour la manipulation de données
titanic Paquet contenant plusieurs jeux de données sur les passagers du titanic

Charger des données

Nom de la fonction Utilité Exemple
data Charger des données déjà présentes dans R ou dans des paquets data(hdv2003)
read.csv Charger des données depuis un fichier. Attention, le chemin vers votre fichier dépend de votre ordinateur et de votre système d’exploitation. read.csv('/chemin/vers/le/fichier.csv')

Explorer des données

Nom de la fonction Utilité Exemple
glimpse Avoir un aperçu rapide d’une variable ou d’une base de données (nombre de lignes, de colonnes, nom, type et aperçu des valeurs des variables) glimpse(hdv2003)
levels Liste des modalités (levels) des variables qualitatives (factor) levels(hdv2003$sexe)
names Liste des noms de variables dans une base de données names(hdv2003)
ncol Nombre de colonnes dans une base de données ncol(hdv2003)
nrow Nombre de lignes dans une base de données nrow(hdv2003)
summary Avoir un aperçu rapide d’une variable, avec statistiques descriptives sommaires selon le type de la variable summary(hdv2003$sexe)

Statistiques descriptives

Méthodes numériques

Nom de la fonction Utilité Exemple
addmargins Calcul des marges d’un tableau addmargins(table(hdv2003$sexe, hdv2003$cuisine))
cor Calcul du R de Pearson cor(hdv2003$age, hdv2003$freres.soeurs)
cprop Fréquences en colonne d’un tableau croisé cprop(table(hdv2003$sexe, hdv2003$cuisine))
freq Tri à plat avec fréquences, avec ou sans NAs freq(hdv2003$sexe)
lprop ou rprop Fréquences en ligne d’un tableau croisé lprop(table(hdv2003$sexe, hdv2003$cuisine))
mean Calcul de la moyenne mean(hdv2003$age)
median Calcul de la médiane median(hdv2003$age)
prop Fréquences totales d’un tableau croisé prop(table(hdv2003$sexe, hdv2003$cuisine))
quantile Calcul des quartiles quantile(hdv2003$age)
sd Calcul de l’écart-type sd(hdv2003$age)
summary Fonction “à tout faire” pour les statistiques descriptives univariées summary(hdv2003$sexe)
table Tri à plat ou tri croisé d’une variable ou de deux variables table(hdv2003$sexe, hdv2003$cuisine)
var Calcul de la variance var(hdv2003$age)

Méthodes graphiques

Nom de la fonction Utilité Exemple
barplot Diagramme en barres d’une variable barplot(hdv2003$sexe)
boxplot Boîte à moustaches simple ou multiples boxplot(hdv2003$sexe) ou boxplot(heures.tv ~ sexe, data = hdv2003)
hist Histogramme d’une variable quantitative hist(hdv2003$age)
mosaicplot Diagramme en mosaïques mosaicplot(sexe ~ cuisine, data = hdv2003))
plot Fonction “à tout faire” pour les graphiques : produit des graphiques différents selon le(s) variables données en argument. Utile pour faire des nuages de points par exemple. plot(hdv2003$age)

Recodage

Nom de la fonction Utilité Exemple
case_when Utilisable pour tout type de recodage Voir plus bas
fct_collapse Recodage des modalités d’une variable Voir plus bas
as.factor Convertir une variable en facteur as.factor(hdv2003$freres.soeurs)
as.numeric Convertir une variable en variable numérique as.numeric(hdv2003$freres.soeurs)
as.character Convertir une variable en variable textuelle as.character(hdv2003$freres.soeurs)

Exemple avec la syntaxe case_when

Cette syntaxe est un peu compliquée, mais permet d’effectuer quasiment tous les recodages envisageables. La syntaxe est la suivante :

base_de_donnees <- mutate(base_de_donnees,
                          nouveau_nom_variable = case_when(
  condition 1 ~ nouvelle valeur 1,
  condition 2 ~ nouvelle valeur 2,
  TRUE ~ valeur par défaut
  ))

Avec cette syntaxe, on peut notamment faire des recodages :

  • variable qualitative vers quantitative et inversement
  • découpage d’une variable quantitative en classes
  • regrouper ou changer les modalités d’une variable

Exemple avec la syntaxe fct_collapse

On peut également envisager d’utiliser fct_collapse pour regrouper des modalités d’une variable qualitative :

mines$prenom1_f <- fct_collapse(mines$prenom1_f,
  "Jean-Philippe" = c("Jean- Phillipe"), # Recoder "Jean- Phillipe" en "Jean-Philippe"
  "Philippe" = c("Phillipe", "Phillippe") # Recoder "Phillipe" et "Phillippe" en "Philippe"
)

Test d’hypothèse

Seule fonction à connaître ici : chisq.test qui prend en argument un tableau croisé en effectifs.

library(questionr)
data(hdv2003)

table1 <- table(hdv2003$sexe, hdv2003$cuisine)
chisq.test(table1)
LS0tCnRpdGxlOiAiUGVuc2UtYsOqdGUgUiBwb3VyIGTDqWJ1dGFudMK3ZcK3cyIKc3VidGl0bGU6ICJDUEVTIC0gTcOpdGhvZGVzIHF1YW50aXRhdGl2ZXMiCmRhdGU6ICJKYW52aWVyIDIwMTgiCmF1dGhvcjogIkdhYnJpZWwgQWxjYXJhcyIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIHRvYzogeWVzCi0tLQoKQ2UgZG9jdW1lbnQgZXN0IMOgIHV0aWxpc2VyIGNvbW1lIHVuZSB0YWJsZSBkZSByw6lmw6lyZW5jZSwgcXVpIHBldXQgw6p0cmUgY29uc3VsdMOpZSBwb25jdHVlbGxlbWVudCBvdSBzZXJ2aXIgZGUgc3VwcG9ydCDDoCBkZXMgcsOpdmlzaW9ucy4KCiMgTGUgbGFuZ2FnZSBSIGVuIGfDqW7DqXJhbAoKUXVlbHF1ZXMgcmFwcGVscyBzdXIgbGUgbGFuZ2FnZSBSLgoKIyMgU3ltYm9sZXMgZXQgb3DDqXJhdGV1cnMKCnwgT3DDqXJhdGV1ciB8IFLDtGxlICAgICAgICAgICB8IEV4ZW1wbGUgfAp8IC0tLSAgICAgICB8IC0tLSAgICAgICAgICAgIHwgLS0tCnwgYCtgICAgICAgIHwgQWRkaXRpb24gICAgICAgfCBgMSsxYCAgIHwKfCBgLWAgICAgICAgfCBTb3VzdHJhY3Rpb24gICB8IGAxLTFgICAgfAp8IGAvYCAgICAgICB8IERpdmlzaW9uICAgICAgIHwgYDEvMWAgICB8CnwgYCpgICAgICAgIHwgTXVsdGlwbGljYXRpb24gfCBgMSoxYCAgIHwKfCBgXmAgICAgICAgfCBQdWlzc2FuY2UgICAgICB8IGAxMF4yYCAgfAoKfCBTeW1ib2xlICAgICB8IFLDtGxlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgRXhlbXBsZSAgICAgfAp8IC0tLSAgICAgICAgIHwgLS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IC0tLQp8IGA8LWAgICAgICAgIHwgQXNzaWduYXRpb24gw6AgdW5lIHZhcmlhYmxlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBgYW5pbWF1eCA8LSBjKCJjaGllbiIsICJjaGF0IilgIHwKfCBgKClgICAgICAgICB8IEV4w6ljdXRpb24gZCd1bmUgZm9uY3Rpb24uIENvbnRpZW50IHNvdXZlbnQgZGVzIGFyZ3VtZW50cyAgICAgICAgICAgICAgICAgIHwgYGMoMSwgMiwgMylgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgW11gICAgICAgICB8IFPDqWxlY3Rpb24gZCd1biBzb3VzLWVuc2VtYmxlIGRhbnMgdW5lIHZhcmlhYmxlLCB1bmUgYmFzZSBkZSBkb25uw6llcywgZXRjLiB8IGBhbmltYXV4WzFdYCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IGAkYCAgICAgICAgIHwgU8OpbGVjdGlvbiBkJ3VuZSB2YXJpYWJsZSBkYW5zIHVuIGRhdGEuZnJhbWUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBgYmRkJGdlbnJlYCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IGAjYCAgICAgICAgIHwgQ29tbWVudGFpcmUgOiBpZ25vcmVyIGNlIHF1aSBzdWl0ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IGAjIFRlc3RgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgYD1gICAgICAgICAgfCBBc3NpZ25hdGlvbiBkJ3VuIGFyZ3VtZW50IGRhbnMgdW5lIGZvbmN0aW9uICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgYG1lYW4oeCwgbmEucm0gPSBUUlVFKWAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgfmAgKHRpbGRlKSB8IFNpZ25lIHF1aSBwZXV0IGF2b2lyIHBsdXNpZXVycyBzaWduaWZpY2F0aW9ucyBzZWxvbiBsZSBjb250ZXh0ZSAgICAgICAgICAgfCBgYm94cGxvdChoZXVyZXMudHYgfiBzZXhlLCBkYXRhID0gaGR2MjAwMylgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgYCxgICAgICAgICAgfCBTw6lwYXJlciBkZXMgYXJndW1lbnRzIGQndW5lIGZvbmN0aW9uICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IGB0YWJsZShoZHYyMDAzJHNleGUsIGhkdjIwMDMkY3Vpc2luZSlgICAgIHwKCkV4ZW1wbGVzIGQndXRpbGlzYXRpb24gZGVzIGNvbW1lbnRhaXJlcyA6CgpgYGB7ciwgZXJyb3IgPSBUUlVFLCBldmFsID0gRkFMU0V9CiMgQ2V0dGUgbGlnbmUgbidlc3QgcGFzIGludGVycHLDqXTDqWUgcGFyIFIKYygiY2hpZW4iLCAiY2hhdCIpICMgRm9uY3Rpb24KYGBgCgo8YnIgLz5FeGVtcGxlcyBkJ3V0aWxpc2F0aW9uIGRlcyBwYXJlbnRow6hzZXMgZXQgZGVzIGNyb2NoZXRzIDoKCmBgYHtyLCBlcnJvciA9IFRSVUV9CmFuaW1hdXggPC0gYygiY2hpZW4iLCAiY2hhdCIpICMgQXNzaWduYXRpb24gZGFucyBsYSB2YXJpYWJsZSBhbmltYXV4CmFuaW1hdXhbMV0gIyBTw6lsZWN0aW9uIGR1IHByZW1pZXIgw6lsw6ltZW50CgojIEVuIHJldmFuY2hlIDoKYW5pbWF1eCgxKQpgYGAKCiMjIFJhY2NvdXJjaXMgY2xhdmllciBlc3NlbnRpZWxzIGRhbnMgUlN0dWRpbwoKfCBUb3VjaGVzICAgICAgICAgICAgICAgIHwgRm9uY3Rpb24gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgLS0tLSAgICAgICAgICAgICAgICAgICB8IC0tLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IDxrYmQ+Q3RybCtFbnRyw6llPC9rYmQ+IHwgRXjDqXV0ZXIgbGEgbGlnbmUgb8O5IHNlIHRyb3V2ZSBsZSBjdXJzZXVyIHwKfCA8a2JkPkN0cmwrRW50csOpZTwva2JkPiB8IEV4w6l1dGVyIGxlcyBsaWduZXMgc8OpbGVjdGlvbm7DqWVzICAgICAgICAgfAp8IDxrYmQ+Q3RybCtMPC9rYmQ+ICAgICAgfCBFZmZhY2VyIGxhIGNvbnNvbGUgICAgICAgICAgICAgICAgICAgICAgIHwKfCA8a2JkPlRhYjwva2JkPiAgICAgICAgIHwgT2J0ZW5pciBsZXMgc3VnZ2VzaW9ucyBkZSBjb21wbMOpdGlvbiAgICAgfAp8IDxrYmQ+Q3RybCtTPC9rYmQ+ICAgICAgfCBTYXV2ZWdhcmRlciBsZSBmaWNoaWVyICAgICAgICAgICAgICAgICAgIHwKCiMjIFIgZXN0IHNlbnNpYmxlLi4uCgojIyMgLi4uIMOgIGxhIGNhc3NlIChtaW51c2N1bGVzL21hanVzY3VsZXMpCgpFeGVtcGxlIHBhcm1pIGQnYXV0cmVzLCBhdmVjIGljaSBsZSBub20gZGVzIGZvbmN0aW9ucyA6CgpgYGB7ciwgZXJyb3IgPSBUUlVFfQojIENldHRlIGZvbmN0aW9uIGVzdCBjb25udWUgZGUgUgpmYWN0b3IoYygiY2hpZW4iLCAiY2hhdCIpKQoKIyBNYWlzIHNpIG9uIGZhaXQgdW5lIGVycmV1ciBkZSBjYXNzZSA6CkZhY3RvcihjKCJjaGllbiIsICJjaGF0IikpCmBgYAoKPGJyIC8+RGUgbcOqbWUgcG91ciBsZXMgdmFyaWFibGVzCgpgYGB7ciwgZXJyb3IgPSBUUlVFfQphbmltYXV4IDwtIGMoImNoaWVuIiwgImNoYXQiKQojIENldHRlIHZhcmlhYmxlIGVzdCBjb25udWUgZGUgUgphbmltYXV4CgojIE1haXMgc2kgb24gZmFpdCB1bmUgZXJyZXVyIGRlIGNhc3NlIDoKQW5pbWF1eApgYGAKCiMjIyAuLi4gw6AgbGEgc3ludGF4ZQoKRGFucyBsZXMgbm9tcyBkZSB2YXJpYWJsZXMgZXQgZGUgZm9uY3Rpb25zLCBsZXMgc2V1bHMgY2FyYWN0w6hyZXMgZW1wbG95w6lzIHNvbnQgOgoKLSBsZXR0cmVzIG1hanVzY3VsZXMgZXQgbWludXNjdWxlcyAocGFzIGRlIGNhcmFjdMOocmVzIGFjY2VudHXDqXMpCi0gdGlyZXRzIGR1IGJhcyAodW5kZXJzY29yZSkgYF9gIGV0IHBvaW50cyBgLmAKCkF0dGVudGlvbiDDoCBuZSBKQU1BSVMgZW1wbG95ZXIgZCdlc3BhY2VzLgoKIyMgU3VyIGxlcyBkb25uw6llcwoKIyMjIFJlY29ubmHDrnRyZSBsZXMgdHlwZXMgLyBzdHJ1Y3R1cmVzIGRlIGRvbm7DqWVzCgpQb3VyIGlkZW50aWZpZXIgdW4gdHlwZSBkZSBkb25uw6llcywgb24gcGV1dCB1dGlsaXNlciBsYSBmb25jdGlvbiBgdHlwZW9mKClgLgoKfCBOb3RhdGlvbiB8IFLDtGxlIHwgRXhlbXBsZSB8CnwgLS0tIHwgLS0tIHwgLS0tIAp8IGAxMjM0YCB8IFVuIG5vbWJyZSAoImRvdWJsZSIpIHwgYDFgIHwKfCBgIiJgIG91IGAnJ2AgfCBDaGHDrm5lIGRlIGNhcmFjdMOocmVzIHwgYCJhbmltYXV4ImAgfAp8IGBOQWAgfCBBYnNlbmNlIGRlIGRvbm7DqWVzIHwgYE5BYCB8CgpSw6lzdWx0YXRzIGRlIGxhIGZvbmN0aW9uIGB0eXBlb2YoKWAgOgoKYGBge3J9CnR5cGVvZigxKQp0eXBlb2YoIjEiKQp0eXBlb2YoTkEpCmBgYAoKPGJyIC8+KipMZSB0eXBlIGRlIGRvbm7DqWVzIGRvaXQgw6p0cmUgYmllbiBjb21wcmlzIHNvdXMgcGVpbmUgZCdlcnJldXJzICEqKgoKYGBge3IsIGVycm9yID0gVFJVRX0KIyBDZSBjYWxjdWwgZm9uY3Rpb25uZSA6CjErMQojIE1haXMuLi4KMSsiMSIKYGBgCgo8YnIgLz5Qb3VyIGlkZW50aWZpZXIgdW5lIHN0cnVjdHVyZSBkZSBkb25uw6llcywgb24gcGV1dCB1dGlsaXNlciBsYSBmb25jdGlvbiBgc3RyKClgLgoKfCBOb20gfCBGb25jdGlvbiB8IENvbmNlcHQgw6lxdWl2YWxlbnQgZW4gc3RhdGlzdGlxdWVzIHwKfCAtLS0gfCAtLS0gfCAtLS0gCnwgdmVjdG9yIHwgYGMoKWAgfCBWYXJpYWJsZSB8CnwgZmFjdG9yIHwgYGZhY3RvcigpYCB8IFZhcmlhYmxlIHF1YWxpdGF0aXZlIHwKfCBkYXRhLmZyYW1lIHwgYGRhdGEuZnJhbWUoKWAgfCBCYXNlIGRlIGRvbm7DqWVzIHwKCiMjIyBWZWN0ZXVyCgpMZSBjb25jZXB0IGRlIHZlY3RldXIgKHN1aXRlIGRlIGRvbm7DqWVzIGRlIG3Dqm1lIHR5cGUpIGRhbnMgUiBlc3QgcHJvY2hlIGRlIGNlbHVpIGRlIHZhcmlhYmxlIGVuIHN0YXRpc3RpcXVlcyAoc8OpcmllIGRlIGRvbm7DqWVzIGhvbW9nw6huZXMgc3VyIGRlcyBpbmRpdmlkdXMpLCBtw6ptZSBzaSB0b3VzIGxlcyB2ZWN0ZXVycyBuZSBzb250IHBhcyBmb3Jjw6ltZW50IGRlcyB2YXJpYWJsZXMgYXUgc2VucyBzdGF0aXN0aXF1ZS4KCmBgYHtyfQpjKDEsMiwzLDQpICMgw4lxdWl2YWxlbnQgw6AgdW5lIHZhcmlhYmxlIHF1YW50aXRhdGl2ZQpzdHIoYygxLDIsMyw0KSkKYygiaG9tbWUiLCAiZmVtbWUiLCAiaG9tbWUiKSAjIFPDqXJpZSBkZSBkb25uw6llcyB0ZXh0dWVsbGVzCnN0cihjKCJob21tZSIsICJmZW1tZSIsICJob21tZSIpKQpgYGAKCjxiciAvPioqTWFuaXB1bGF0aW9uIGRlcyB2ZWN0ZXVycyA6KioKCmBgYHtyfQpnZW5yZSA8LSBjKCJob21tZSIsICJmZW1tZSIsICJob21tZSIpCmdlbnJlWzFdCmdlbnJlWzE6Ml0KZ2VucmVbYygxLCAzKV0KYGBgCgojIyMgRmFjdGV1cgoKTGVzIGZhY3RldXJzIHNvbnQgdW4gdHlwZSBwYXJ0aWN1bGllciBkZSB2ZWN0ZXVycyBkYW5zIFIsIGRlIGxhIG3Dqm1lIGZhw6dvbiBxdWUgbGVzIHZhcmlhYmxlcyBxdWFsaXRhdGl2ZXMgc29udCB1biB0eXBlIGRlIHZhcmlhYmxlIHBhcnRpY3VsaWVyLgoKfCBEYW5zIFIgfCBFbiBzdGF0aXN0aXF1ZXMgICAgICAgICAgfAp8IC0tLSAgICB8IC0tLSAgICAgICAgICAgICAgICAgICAgICB8CnwgZmFjdG9yIHwgVmFyaWFibGUgcXVhbGl0YXRpdmUgICAgIHwKfCBsZXZlbHMgfCBNb2RhbGl0w6lzIGRlIGxhIHZhcmlhYmxlIHwKCmBgYHtyfQpnZW5yZSA8LSBjKCJob21tZSIsICJmZW1tZSIsICJob21tZSIpCgojIFRyYW5zZm9ybWF0aW9uIGVuIGZhY3RldXIKZ2VucmUuZiA8LSBhcy5mYWN0b3IoZ2VucmUpCnN1bW1hcnkoZ2VucmUuZikKYGBgCgo8YnIgLz5Qb3VyIHZvaXIgbGVzIG1vZGFsaXTDqXMgKGBsZXZlbHNgKSA6CgpgYGB7cn0KbGV2ZWxzKGdlbnJlLmYpCmBgYAoKIyMjIERhdGEuZnJhbWUKCkMnZXN0IGwnw6lxdWl2YWxlbnQgZCd1bmUgYmFzZSBkZSBkb25uw6llcyBlbiBzdGF0aXN0aXF1ZXMgOiB1bmUgc8OpcmllIGRlIHZhcmlhYmxlcyBzdXIgbGVzIG3Dqm1lcyBpbmRpdmlkdXMuCgpQb3VyIHPDqWxlY3Rpb25uZXIgdW5lIHZhcmlhYmxlIGVuIHBhcnRpY3VsaWVyIDoKCmBgYHtyLCBldmFsPUZBTFNFfQpiZGQkdmFyaWFibGUxCmBgYAoKIyMjIExlcyBmb25jdGlvbnMKCkxlcyBmb25jdGlvbnMgc29udCB1biBjb25jZXB0IGNlbnRyYWwgZGVzIGxhbmdhZ2VzIGRlIHByb2dyYW1tYXRpb24uLi4gZXQgZG9uYyBkZSBSICEKCjxiciAvPjxiciAvPgoKIyMjIyBBbmF0b21pZSBkJ3VuZSBmb25jdGlvbgoKVG91am91cnMgc291cyBsYSBmb3JtZSA6CgpgYGAKbm9tRGVMYUZvbmN0aW9uKGFyZ3VtZW50cykKYGBgCgo8YnIgLz5Ew6ljb21wb3NpdGlvbiA6CgorIGBub21EZUxhRm9uY3Rpb25gIDogKipub20gZGUgbGEgZm9uY3Rpb24gw6AgYXBwZWxlcioqCisgYCgpYCA6IGxlcyBwYXJlbnRow6hzZXMgc2lnbmlmaWVudCBxdScqKm9uIGRlbWFuZGUgw6AgUiBkJ8OpeMOpdXRlciBsYSBmb25jdGlvbioqLgorIGBhcmd1bWVudHNgIDogdW5lIGxpc3RlIGQnYXJndW1lbnRzIHPDqXBhcsOpcyBwYXIgZGVzIHZpcmd1bGVzIGV0IHVuZSBlc3BhY2UuIExlIG5vbWJyZSBkJ2FyZ3VtZW50cyBkw6lwZW5kIGRlcyBmb25jdGlvbnMuCgo8YnIgLz48YnIgLz4KCiMjIyMgTGVzIGFyZ3VtZW50cwoKRm9uY3Rpb24gcXVpIG4nYSBiZXNvaW4gZCdhdWN1biBhcmd1bWVudCA6CgpgYGB7cn0KZ2V0d2QoKQpgYGAKCjxiciAvPkxhIGZvbmN0aW9uIGBjKClgIGFjY2VwdGUgdW4gbm9tYnJlIGlsbGltaXTDqSBkJ2FyZ3VtZW50cyA6CgpgYGB7cn0KYygxLCAyLCAzLCA0KQpgYGAKCjxiciAvPkNlcnRhaW5lcyBmb25jdGlvbnMgb250IGRlcyBhcmd1bWVudHMgb2JsaWdhdG9pcmVzIDoKCmBgYHtyLCBlcnJvciA9IFRSVUV9Cm1lYW4oKQpgYGAKCjxiciAvPk1haXMgc2kgb24gZG9ubmUgbCdhcmd1bWVudCBvYmxpZ2F0b2lyZSwgdG91dCBzZSBwYXNzZSBiaWVuIDoKCmBgYHtyfQpub3RlcyA8LSBjKDEwLCAyMCkKbWVhbihub3RlcykKYGBgCgo8YnIgLz5DZXJ0YWluZXMgZm9uY3Rpb25zIHByZW5uZW50IGRlcyBhcmd1bWVudHMgZmFsY3V0YXRpZnMsIHF1aSBwZXV2ZW50IMOqdHJlIG5vbW3DqXMuIERhbnMgY2UgY2FzLCBsZSBub20gZGUgbCdhcmd1bWVudCBlc3Qgc3VpdmkgZCd1biBzaWduZSBgPWAgcHVpcyBkZSBzYSB2YWxldXIuCgpgYGB7cn0Kbm90ZXMgPC0gYygxMCwgMjAsIE5BKQojIFNhbnMgbCdhcmd1bWVudCBmYWN1bHRhdGlmIG5hLnJtIDoKbWVhbihub3RlcykKIyBBdmVjIGwnYXJndW1lbnQgZmFjdWx0YXRpZiBuYS5ybSA6Cm1lYW4obm90ZXMsIG5hLnJtID0gVFJVRSkKYGBgCjxiciAvPjxiciAvPgoKIyMjIyBGb25jdGlvbnMgaW1icmlxdcOpZXMKCklsIGVzdCBiaWVuIHPDu3IgcG9zc2libGUgZCdpbWJyaXF1ZXIgbm9zIGZvbmN0aW9ucyA6CgpgYGB7cn0KbWVhbihjKGMoMTAsIDIwKSwgTkEpLCBuYS5ybSA9IFRSVUUpCmBgYAoKPGJyIC8+Q2UgcXVpIGVzdCBpZGVudGlxdWUgw6AgOiAKCmBgYHtyfQpub3RlcyA8LSBjKDEwLCAyMCkKbm90ZXMyIDwtIGMobm90ZXMsIE5BKQptZWFuKG5vdGVzMiwgbmEucm0gPSBUUlVFKQpgYGAKCjxiciAvPlBvdXIgY29tcHJlbmRyZSBsZXMgZm9uY3Rpb25zIGltYnJpcXXDqWVzLCBpbCBmYXV0IGRvbmMgcHJvY8OpZGVyIHBhciDDqXRhcGVzLCBlbiBwYXJ0YW50IGRlIGwnaW50w6lyaWV1ciBkZXMgcGFyZW50aMOoc2VzIHBvdXIgYWxsZXIgdmVycyBsJ2V4dMOpcmlldXIuCgo8YnIgLz4KCiMjIyBMZXMgdmFyaWFibGVzCgpEYW5zIHVuIGxhbmdhZ2UgZGUgcHJvZ3JhbW1hdGlvbiwgbGVzIHZhcmlhYmxlcyBwZXJtZXR0ZW50IGQnYXR0ZWluZHJlIHVuIG5pdmVhdSBkJ2Fic3RyYWN0aW9uIHN1cHBsw6ltZW50YWlyZSwgZW4gYXR0cmlidWFudCB1biBub20gw6AgdW4gb2JqZXQgcG91ciBsZSByw6l1dGlsaXNlciBwYXIgbGEgc3VpdGUuIEVsbGVzIGFtw6lsaW9yZW50IMOpZ2FsZW1lbnQgbGEgbGlzaWJpbGl0w6kgZHUgcHJvZ3JhbW1lLgoKYGBge3J9CnZhcmlhYmxlIDwtICJjb3Vjb3UiCnZhcmlhYmxlCmBgYAoKPGJyIC8+QXR0ZW50aW9uIGF1eCBlcnJldXJzIGRlIG5vdGF0aW9uICEKCmBgYHtyfQp2YXJpYWJsZQojIE1haXMuLi4KInZhcmlhYmxlIgpgYGAKCjxiciAvPgoKIyMjIyBWYXJpYWJsZSBpbmZvcm1hdGlxdWUgLyB2YXJpYWJsZSBzdGF0aXN0aXF1ZQoKKipBdHRlbnRpb24gOioqIGxlIGNvbmNlcHQgZGUgdmFyaWFibGUgKmluZm9ybWF0aXF1ZSogZXN0IHRyw6hzIGRpZmbDqXJlbnQgZGUgdmFyaWFibGUgKnN0YXRpc3RpcXVlKi4gRW4gZWZmZXQsIHVuZSB2YXJpYWJsZSBpbmZvcm1hdGlxdWUgcGV1dCBzdG9ja2VyIG4naW1wb3J0ZSBxdWVsIHR5cGUgZGUgZG9ubsOpZXMsIGFsb3JzIHF1J3VuZSB2YXJpYWJsZSBzdGF0aXN0aXF1ZSBjb3JyZXNwb25kIMOgIHVuZSBzw6lyaWUgZGUgZG9ubsOpZXMgaG9tb2fDqG5lcyBjb2xsZWN0w6llcyBzdXIgZGVzIGluZGl2aWR1cy4KCkxlcyBkZXV4IGNvbmNlcHRzIHNlIHJlY291cGVudCBwYXJmb2lzIDoKCmBgYHtyfQpub3RlcyA8LSBjKDEwLCAyMCwgMTYpCmBgYAoKPGJyIC8+SWNpLCBsYSB2YXJpYWJsZSBgbm90ZXNgIHBldXQgY29ycmVzcG9uZHJlIMOgIHVuZSB2YXJpYWJsZSBzdGF0aXN0aXF1ZS4KCkVuIHJldmFuY2hlIDoKCmBgYHtyfQp0ZXN0IDwtIG1lYW4obm90ZXMpCmBgYAoKPGJyIC8+RGFucyBjZSBjYXMsIGxhIHZhcmlhYmxlIGluZm9ybWF0aXF1ZSBgdGVzdGAgY29udGllbnQgbGEgbW95ZW5uZSBkZXMgbm90ZXMsIGNlIHF1aSBuJ2VzdCBwYXMgw6lxdWl2YWxlbnQgw6AgdW5lIHZhcmlhYmxlIGF1IHNlbnMgc3RhdGlzdGlxdWUuCgojIFBlbnNlLWLDqnRlIGRlcyBmb25jdGlvbnMgbGVzIHBsdXMgY291cmFudGVzCgpDaS1hcHLDqHMsIHVuZSBsaXN0ZSBkZXMgZm9uY3Rpb25zIGxlcyBwbHVzIGNvdXJhbnRlcyBkYW5zIFIuIExlcyBleGVtcGxlcyBkb25uw6lzIHNvbnQgdHLDqHMgc3VjY2luY3RzIDogcmVwb3J0ZXotdm91cyBhdXggc3VwcG9ydHMgZGUgY291cnMgcG91ciBkZXMgInZyYWlzIiBleGVtcGxlcyBwbHVzIGTDqXZlbG9wcMOpcy4KCiMjIExpYnJhaXJpZXMgLyBwYXF1ZXRzCgp8IE5vbSBkZSBsYSBmb25jdGlvbiB8IFV0aWxpdMOpICAgICAgICAgICAgICAgICAgICAgICAgfCBFeGVtcGxlICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCAtLS0gICAgICAgICAgICAgICAgfCAtLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAtLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgaW5zdGFsbC5wYWNrYWdlc2AgfCBJbnN0YWxsZXIgdW4gcGFxdWV0IFIgICAgICAgICAgfCBgaW5zdGFsbC5wYWNrYWdlcygicXVlc3Rpb25yIilgIHwKfCBgbGlicmFyeWAgICAgICAgICAgfCBDaGFyZ2VyIHVuIHBhcXVldCBSIGVuIG3DqW1vaXJlIHwgYGxpYnJhcnkocXVlc3Rpb25yKWAgICAgICAgICAgICB8Cgp8IE5vbSBkdSBwYXF1ZXQgfCBVdGlsaXTDqSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgLS0tICAgICAgICAgICB8IC0tLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IGBkcGx5cmAgICAgICAgfCBQYXF1ZXQgUiBwZXJtZXR0YW50IGRlcyByZWNvZGFnZXMgdHLDqHMgYXZhbmPDqXMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IGBxdWVzdGlvbnJgICAgfCBQYXF1ZXQgUiBmcmFuw6dhaXMgYWRhcHTDqSBhdXggZW5xdcOqdGVzIGRlIHNjaWVuY2VzIHNvY2lhbGVzLCBhdmVjIGRlcyBmb25jdGlvbnMgdXRpbGVzIHBvdXIgcHJvZHVpcmUgc2ltcGxlbWVudCBkZXMgdGFibGVhdXggY3JvaXPDqXMsIGRlcyB0cmlzIMOgIHBsYXQsIGV0Yy4gfAp8IGB0aWR5dmVyc2VgICAgfCBFbnNlbWJsZSBkZSBwYXF1ZXRzIHV0aWxlcyBwb3VyIGxhIG1hbmlwdWxhdGlvbiBkZSBkb25uw6llcyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgYHRpdGFuaWNgICAgICB8IFBhcXVldCBjb250ZW5hbnQgcGx1c2lldXJzIGpldXggZGUgZG9ubsOpZXMgc3VyIGxlcyBwYXNzYWdlcnMgZHUgdGl0YW5pYyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKCiMjIENoYXJnZXIgZGVzIGRvbm7DqWVzCgp8IE5vbSBkZSBsYSBmb25jdGlvbiB8IFV0aWxpdMOpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBFeGVtcGxlIHwKfCAtLS0gICAgICAgICAgICAgICAgfCAtLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAtLS0gICB8CnwgYGRhdGFgICAgICAgICAgICAgIHwgQ2hhcmdlciBkZXMgZG9ubsOpZXMgZMOpasOgIHByw6lzZW50ZXMgZGFucyBSIG91IGRhbnMgZGVzIHBhcXVldHMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IGBkYXRhKGhkdjIwMDMpYCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IGByZWFkLmNzdmAgICAgICAgICB8IENoYXJnZXIgZGVzIGRvbm7DqWVzIGRlcHVpcyB1biBmaWNoaWVyLiBBdHRlbnRpb24sIGxlIGNoZW1pbiB2ZXJzIHZvdHJlIGZpY2hpZXIgZMOpcGVuZCBkZSB2b3RyZSBvcmRpbmF0ZXVyIGV0IGRlIHZvdHJlIHN5c3TDqG1lIGQnZXhwbG9pdGF0aW9uLiB8IGByZWFkLmNzdignL2NoZW1pbi92ZXJzL2xlL2ZpY2hpZXIuY3N2JylgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAoKIyMgRXhwbG9yZXIgZGVzIGRvbm7DqWVzCgp8IE5vbSBkZSBsYSBmb25jdGlvbiB8IFV0aWxpdMOpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgRXhlbXBsZSB8CnwgLS0tICAgICAgICAgICAgICAgIHwgLS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IC0tLSAgIHwKfCBgZ2xpbXBzZWAgICAgICAgICAgfCBBdm9pciB1biBhcGVyw6d1IHJhcGlkZSBkJ3VuZSB2YXJpYWJsZSBvdSBkJ3VuZSBiYXNlIGRlIGRvbm7DqWVzIChub21icmUgZGUgbGlnbmVzLCBkZSBjb2xvbm5lcywgbm9tLCB0eXBlIGV0IGFwZXLDp3UgZGVzICB2YWxldXJzIGRlcyB2YXJpYWJsZXMpIHwgYGdsaW1wc2UoaGR2MjAwMylgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgYGxldmVsc2AgICAgICAgICAgIHwgTGlzdGUgZGVzIG1vZGFsaXTDqXMgKGBsZXZlbHNgKSBkZXMgdmFyaWFibGVzIHF1YWxpdGF0aXZlcyAoYGZhY3RvcmApICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBgbGV2ZWxzKGhkdjIwMDMkc2V4ZSlgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgYG5hbWVzYCAgICAgICAgICAgIHwgTGlzdGUgZGVzIG5vbXMgZGUgdmFyaWFibGVzIGRhbnMgdW5lIGJhc2UgZGUgZG9ubsOpZXMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBgbmFtZXMoaGR2MjAwMylgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgbmNvbGAgICAgICAgICAgICAgfCBOb21icmUgZGUgY29sb25uZXMgZGFucyB1bmUgYmFzZSBkZSBkb25uw6llcyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IGBuY29sKGhkdjIwMDMpYCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IGBucm93YCAgICAgICAgICAgICB8IE5vbWJyZSBkZSBsaWduZXMgZGFucyB1bmUgYmFzZSBkZSBkb25uw6llcyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgYG5yb3coaGR2MjAwMylgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IGBzdW1tYXJ5YCAgICAgICAgICB8IEF2b2lyIHVuIGFwZXLDp3UgcmFwaWRlIGQndW5lIHZhcmlhYmxlLCBhdmVjIHN0YXRpc3RpcXVlcyBkZXNjcmlwdGl2ZXMgc29tbWFpcmVzIHNlbG9uIGxlIHR5cGUgZGUgbGEgdmFyaWFibGUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgYHN1bW1hcnkoaGR2MjAwMyRzZXhlKWAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAoKIyMgU3RhdGlzdGlxdWVzIGRlc2NyaXB0aXZlcwoKIyMjIE3DqXRob2RlcyBudW3DqXJpcXVlcwoKfCBOb20gZGUgbGEgZm9uY3Rpb24gfCBVdGlsaXTDqSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgRXhlbXBsZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IC0tLSAgICAgICAgICAgICAgICB8IC0tLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IC0tLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgYWRkbWFyZ2luc2AgICAgICAgfCBDYWxjdWwgZGVzIG1hcmdlcyBkJ3VuIHRhYmxlYXUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBgYWRkbWFyZ2lucyh0YWJsZShoZHYyMDAzJHNleGUsIGhkdjIwMDMkY3Vpc2luZSkpYCB8CnwgYGNvcmAgICAgICAgICAgICAgIHwgQ2FsY3VsIGR1IFIgZGUgUGVhcnNvbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgYGNvcihoZHYyMDAzJGFnZSwgaGR2MjAwMyRmcmVyZXMuc29ldXJzKWAgICAgICAgICAgfAp8IGBjcHJvcGAgICAgICAgICAgICB8IEZyw6lxdWVuY2VzIGVuIGNvbG9ubmUgZCd1biB0YWJsZWF1IGNyb2lzw6kgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgYGNwcm9wKHRhYmxlKGhkdjIwMDMkc2V4ZSwgaGR2MjAwMyRjdWlzaW5lKSlgICAgICAgfAp8IGBmcmVxYCAgICAgICAgICAgICB8IFRyaSDDoCBwbGF0IGF2ZWMgZnLDqXF1ZW5jZXMsIGF2ZWMgb3Ugc2FucyBOQXMgICAgICAgICAgICAgICAgICAgICAgICAgIHwgYGZyZXEoaGR2MjAwMyRzZXhlKWAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IGBscHJvcGAgb3UgYHJwcm9wYCB8IEZyw6lxdWVuY2VzIGVuIGxpZ25lIGQndW4gdGFibGVhdSBjcm9pc8OpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgYGxwcm9wKHRhYmxlKGhkdjIwMDMkc2V4ZSwgaGR2MjAwMyRjdWlzaW5lKSlgICAgICAgfAp8IGBtZWFuYCAgICAgICAgICAgICB8IENhbGN1bCBkZSBsYSBtb3llbm5lICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IGBtZWFuKGhkdjIwMDMkYWdlKWAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgbWVkaWFuYCAgICAgICAgICAgfCBDYWxjdWwgZGUgbGEgbcOpZGlhbmUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgYG1lZGlhbihoZHYyMDAzJGFnZSlgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IGBwcm9wYCAgICAgICAgICAgICB8IEZyw6lxdWVuY2VzIHRvdGFsZXMgZCd1biB0YWJsZWF1IGNyb2lzw6kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgYHByb3AodGFibGUoaGR2MjAwMyRzZXhlLCBoZHYyMDAzJGN1aXNpbmUpKWAgICAgICAgfAp8IGBxdWFudGlsZWAgICAgICAgICB8IENhbGN1bCBkZXMgcXVhcnRpbGVzICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IGBxdWFudGlsZShoZHYyMDAzJGFnZSlgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgc2RgICAgICAgICAgICAgICAgfCBDYWxjdWwgZGUgbCfDqWNhcnQtdHlwZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgYHNkKGhkdjIwMDMkYWdlKWAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IGBzdW1tYXJ5YCAgICAgICAgICB8IEZvbmN0aW9uICLDoCB0b3V0IGZhaXJlIiBwb3VyIGxlcyBzdGF0aXN0aXF1ZXMgZGVzY3JpcHRpdmVzIHVuaXZhcmnDqWVzIHwgYHN1bW1hcnkoaGR2MjAwMyRzZXhlKWAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IGB0YWJsZWAgICAgICAgICAgICB8IFRyaSDDoCBwbGF0IG91IHRyaSBjcm9pc8OpIGQndW5lIHZhcmlhYmxlIG91IGRlIGRldXggdmFyaWFibGVzICAgICAgICAgIHwgYHRhYmxlKGhkdjIwMDMkc2V4ZSwgaGR2MjAwMyRjdWlzaW5lKWAgICAgICAgICAgICAgfAp8IGB2YXJgICAgICAgICAgICAgICB8IENhbGN1bCBkZSBsYSB2YXJpYW5jZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IGB2YXIoaGR2MjAwMyRhZ2UpYCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKCiMjIyBNw6l0aG9kZXMgZ3JhcGhpcXVlcwoKfCBOb20gZGUgbGEgZm9uY3Rpb24gfCBVdGlsaXTDqSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBFeGVtcGxlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IC0tLSAgICAgICAgICAgICAgICB8IC0tLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgLS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgYGJhcnBsb3RgICAgICAgICAgIHwgRGlhZ3JhbW1lIGVuIGJhcnJlcyBkJ3VuZSB2YXJpYWJsZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBgYmFycGxvdChoZHYyMDAzJHNleGUpYCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgYm94cGxvdGAgICAgICAgICAgfCBCb8OudGUgw6AgbW91c3RhY2hlcyBzaW1wbGUgb3UgbXVsdGlwbGVzICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgYGJveHBsb3QoaGR2MjAwMyRzZXhlKWAgb3UgYGJveHBsb3QoaGV1cmVzLnR2IH4gc2V4ZSwgZGF0YSA9IGhkdjIwMDMpYCB8CnwgYGhpc3RgICAgICAgICAgICAgIHwgSGlzdG9ncmFtbWUgZCd1bmUgdmFyaWFibGUgcXVhbnRpdGF0aXZlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBgaGlzdChoZHYyMDAzJGFnZSlgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgYG1vc2FpY3Bsb3RgICAgICAgIHwgRGlhZ3JhbW1lIGVuIG1vc2HDr3F1ZXMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgYG1vc2FpY3Bsb3Qoc2V4ZSB+IGN1aXNpbmUsIGRhdGEgPSBoZHYyMDAzKSlgICAgICAgICB8CnwgYHBsb3RgICAgICAgICAgICAgIHwgRm9uY3Rpb24gIsOgIHRvdXQgZmFpcmUiIHBvdXIgbGVzIGdyYXBoaXF1ZXMgOiBwcm9kdWl0IGRlcyBncmFwaGlxdWVzIGRpZmbDqXJlbnRzIHNlbG9uIGxlKHMpIHZhcmlhYmxlcyBkb25uw6llcyBlbiBhcmd1bWVudC4gVXRpbGUgcG91ciBmYWlyZSBkZXMgbnVhZ2VzIGRlIHBvaW50cyBwYXIgZXhlbXBsZS4gfCBgcGxvdChoZHYyMDAzJGFnZSlgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CgojIyBSZWNvZGFnZQoKfCBOb20gZGUgbGEgZm9uY3Rpb24gfCBVdGlsaXTDqSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBFeGVtcGxlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCAtLS0gICAgICAgICAgICAgICAgfCAtLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IC0tLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IGBjYXNlX3doZW5gICAgICAgICB8IFV0aWxpc2FibGUgcG91ciB0b3V0IHR5cGUgZGUgcmVjb2RhZ2UgICAgICAgIHwgVm9pciBwbHVzIGJhcyAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgYGZjdF9jb2xsYXBzZWAgICAgIHwgUmVjb2RhZ2UgZGVzIG1vZGFsaXTDqXMgZCd1bmUgdmFyaWFibGUgICAgICAgIHwgVm9pciBwbHVzIGJhcyAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgYGFzLmZhY3RvcmAgICAgICAgIHwgQ29udmVydGlyIHVuZSB2YXJpYWJsZSBlbiBmYWN0ZXVyICAgICAgICAgICAgfCBgYXMuZmFjdG9yKGhkdjIwMDMkZnJlcmVzLnNvZXVycylgICAgIHwKfCBgYXMubnVtZXJpY2AgICAgICAgfCBDb252ZXJ0aXIgdW5lIHZhcmlhYmxlIGVuIHZhcmlhYmxlIG51bcOpcmlxdWUgfCBgYXMubnVtZXJpYyhoZHYyMDAzJGZyZXJlcy5zb2V1cnMpYCAgIHwKfCBgYXMuY2hhcmFjdGVyYCAgICAgfCBDb252ZXJ0aXIgdW5lIHZhcmlhYmxlIGVuIHZhcmlhYmxlIHRleHR1ZWxsZSB8IGBhcy5jaGFyYWN0ZXIoaGR2MjAwMyRmcmVyZXMuc29ldXJzKWAgfAoKIyMjIEV4ZW1wbGUgYXZlYyBsYSBzeW50YXhlIGBjYXNlX3doZW5gCgpDZXR0ZSBzeW50YXhlIGVzdCB1biBwZXUgY29tcGxpcXXDqWUsIG1haXMgcGVybWV0IGQnZWZmZWN0dWVyIHF1YXNpbWVudCB0b3VzIGxlcyByZWNvZGFnZXMgZW52aXNhZ2VhYmxlcy4gTGEgc3ludGF4ZSBlc3QgbGEgc3VpdmFudGUgOgoKYGBge3IsIGV2YWwgPSBGQUxTRX0KYmFzZV9kZV9kb25uZWVzIDwtIG11dGF0ZShiYXNlX2RlX2Rvbm5lZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbm91dmVhdV9ub21fdmFyaWFibGUgPSBjYXNlX3doZW4oCiAgY29uZGl0aW9uIDEgfiBub3V2ZWxsZSB2YWxldXIgMSwKICBjb25kaXRpb24gMiB+IG5vdXZlbGxlIHZhbGV1ciAyLAogIFRSVUUgfiB2YWxldXIgcGFyIGTDqWZhdXQKICApKQpgYGAKCkF2ZWMgY2V0dGUgc3ludGF4ZSwgb24gcGV1dCBub3RhbW1lbnQgZmFpcmUgZGVzIHJlY29kYWdlcyA6CgotIHZhcmlhYmxlIHF1YWxpdGF0aXZlIHZlcnMgcXVhbnRpdGF0aXZlIGV0IGludmVyc2VtZW50Ci0gZMOpY291cGFnZSBkJ3VuZSB2YXJpYWJsZSBxdWFudGl0YXRpdmUgZW4gY2xhc3NlcwotIHJlZ3JvdXBlciBvdSBjaGFuZ2VyIGxlcyBtb2RhbGl0w6lzIGQndW5lIHZhcmlhYmxlCgojIyMgRXhlbXBsZSBhdmVjIGxhIHN5bnRheGUgYGZjdF9jb2xsYXBzZWAKCk9uIHBldXQgw6lnYWxlbWVudCBlbnZpc2FnZXIgZCd1dGlsaXNlciBgZmN0X2NvbGxhcHNlYCBwb3VyIHJlZ3JvdXBlciBkZXMgbW9kYWxpdMOpcyBkJ3VuZSB2YXJpYWJsZSBxdWFsaXRhdGl2ZSA6CgpgYGB7ciwgZXZhbCA9IEZBTFNFfQptaW5lcyRwcmVub20xX2YgPC0gZmN0X2NvbGxhcHNlKG1pbmVzJHByZW5vbTFfZiwKICAiSmVhbi1QaGlsaXBwZSIgPSBjKCJKZWFuLSBQaGlsbGlwZSIpLCAjIFJlY29kZXIgIkplYW4tIFBoaWxsaXBlIiBlbiAiSmVhbi1QaGlsaXBwZSIKICAiUGhpbGlwcGUiID0gYygiUGhpbGxpcGUiLCAiUGhpbGxpcHBlIikgIyBSZWNvZGVyICJQaGlsbGlwZSIgZXQgIlBoaWxsaXBwZSIgZW4gIlBoaWxpcHBlIgopCmBgYAoKIyMgVGVzdCBkJ2h5cG90aMOoc2UKClNldWxlIGZvbmN0aW9uIMOgIGNvbm5hw650cmUgaWNpIDogYGNoaXNxLnRlc3RgIHF1aSBwcmVuZCBlbiBhcmd1bWVudCB1biB0YWJsZWF1IGNyb2lzw6kgZW4gZWZmZWN0aWZzLgoKYGBge3IgY2hpIHNxdWFyZWQgdGVzdH0KbGlicmFyeShxdWVzdGlvbnIpCmRhdGEoaGR2MjAwMykKCnRhYmxlMSA8LSB0YWJsZShoZHYyMDAzJHNleGUsIGhkdjIwMDMkY3Vpc2luZSkKY2hpc3EudGVzdCh0YWJsZTEpCmBgYAo=