Lire un fichier csv sur le web

PATH <- 'http://ziedzaier.com/wp-content/uploads/2019/07/mtcars.csv'
mtcars <- read.csv(PATH, header =  TRUE, sep = ',',stringsAsFactors =FALSE)

dim(mtcars)
[1] 32 12
names(mtcars)
 [1] "X"    "mpg"  "cyl"  "disp" "hp"   "drat" "wt"   "qsec" "vs"   "am"   "gear" "carb"
head(mtcars)
NA
library(ggplot2)

tracer un diagramme de dispersion des variables mpg et drat. un fichier pdf avec le graphique est cree dans votre repertoire de projet

p <- ggplot(mtcars, aes(x = drat, y = mpg)) +
    geom_point()
print(p)

Sauvegarder le Graphe en format png

ggsave("mon_premier_graphe.png")
Saving 7 x 7 in image

distinguer les valeurs d’un groupe de données - gear

p <- ggplot(mtcars, aes(x = mpg, y = drat)) +
    geom_point(aes(color = factor(gear)))
print(p)

rendre vos données moins sensibles aux valeurs aberrantes avec le redimensionnement - echelle logarithmique

p <-ggplot(mtcars, aes(x = log(mpg), y = log(drat))) +
    geom_point(aes(color = factor(am)))
print(p)

Ajouter un autre niveau d’information au graphique en tracant la valeur ajustée d’une régression linéaire. L’argument stat_smooth () contrôle la méthode de lissage - method = “lm”: régression linéaire col = “# C42126”: Code de la couleur rouge de la ligne et se = FALSE: ne pas afficher l’erreur standard size = 1: l’épaisseur de la ligne est 1

mon_graphe <- ggplot(mtcars, aes(x = log(mpg), y = log(drat))) +
    geom_point(aes(color = factor(vs))) +
    stat_smooth(method = "lm",
        col = "yellow",
        se = FALSE,
        size = 1)
print(mon_graphe)

ajouter votre titre

mon_graphe <-mon_graphe +
    labs(
        title = "Dispersion des variables mpg et drat"
         ) + 
  xlab('Valeur de log(draf)') + 
  ylab('Valeur de log(mpg)') 

print(mon_graphe)

library(ggplot2)

bar chart basique un count sur la variable cyl

p <- ggplot(mtcars, aes(x = factor(cyl))) +
    geom_bar() +
    labs(
        title = "Bar chart basique un count sur la variable cyl"
         ) + 
  xlab('Nombre de cylindres') + 
  ylab('Nombre de données') 

print(p)

Changer la couleur des barres

p <- ggplot(mtcars, aes(x = factor(cyl))) +
    geom_bar(fill = "blue") +
    theme_classic()+
    labs(
        title = "Bar chart basique un count sur la variable cyl"
         ) + 
  xlab('Nombre de cylindres') + 
  ylab('Nombre de données') 
print(p)

Couleur par groupe

p <- ggplot(mtcars, aes(factor(cyl),
        fill = factor(cyl))) +
    geom_bar() +
    theme_classic()+
    labs(
        title = "Bar chart basique un count sur la variable cyl"
         ) + 
  xlab('Nombre de cylindres') + 
  ylab('Nombre de données') 
print(p)

library(dplyr)

Ajouter un autre niveau de groupe

data <- mtcars %>%
mutate(am = factor(am, labels = c("auto", "man")),
    cyl = factor(cyl))
p <- ggplot(data, aes(x = cyl, fill = am)) +
    geom_bar() +
    theme_bw() +
    labs(
        title = "Bar chart basique un count sur la variable cyl"
         ) + 
  xlab('Nombre de cylindres') + 
  ylab('Nombre de données') 

print(p)

Multi Barres

p <- ggplot(data, aes(x = cyl, fill = am)) +
    geom_bar(position = position_dodge()) +
    theme_bw()+
    labs(
        title = "Multi Barres  basique le count sur la variable cyl en factor AM"
         ) + 
  xlab('Nombre de cylindres') + 
  ylab('Nombre de données') 
print(p)

Vous créez un bloc de données nommé donnee_histograme qui renvoie simplement la moyenne par le nombre de cylindres dans la voiture. appeler cette nouvelle variable moyenne_mpg et arrondissez la moyenne avec deux décimales.

donnee_histograme <- mtcars %>%
mutate(cyl = factor(cyl)) %>%
group_by(cyl)  %>% summarize(moyenne_mpg = round(mean(mpg), 2))

Vous pouvez tracer l’histogramme. La variable cyl fait référence à l’axe des x et moyenne_mpg à l’axe des y. Vous devez passer l’argument stat = “identity” pour référencer la variable sur l’axe des ordonnées en tant que valeur numérique. geom_bar utilise stat = “bin” comme valeur par défaut. Vous modifiez l’orientation du graphique de vertical à horizontal avec coord_flip()


graphe <- ggplot(donnee_histograme, aes(x = cyl, y = moyenne_mpg, fill = cyl)) +
    geom_bar(stat = "identity",
        width = 0.5) +
    coord_flip() +
    theme_classic()
print(graphe)

graphe <- graphe + geom_text(aes(label = moyenne_mpg),
        hjust = 1.5,
        color = "white",
        size = 3) +
    theme_classic()

print(graphe)

lire un fichier csv sur le web

PATH <- 'http://ziedzaier.com/wp-content/uploads/2019/07/airquality.csv'
qualite_air <- read.csv(PATH, header =  TRUE, sep = ',',stringsAsFactors =FALSE)
print(head(qualite_air,5))
library(dplyr)
library(ggplot2)

Importer les données

donnee_air <- qualite_air %>%
  select(-c(Solar.R, Temp)) %>%
  mutate(Month = factor(Month, order = TRUE, labels = c("May", "June", "July", "August", "September")),
         jour_divise = factor(ifelse(Day < 10, "debut", ifelse(Day < 20, "milieu", "fin"))))
donnee_air_pas_na <-donnee_air %>% na.omit()

Supprimez les variables inutiles

onvertir le mois en facteur

Créez une nouvelle variable catégorique divisant le mois en trois niveaux: début, milieu et fin.

Supprimer les observations manquantes

Stocker le graphique Vous passez l’ensemble de données donnee_air_pas_na à ggplot. Dans l’argument aes (), vous ajoutez les axes x et y.

box_plot <- ggplot(donnee_air_pas_na, aes(x = Month, y = Ozone))

Ajouter le tracé de la boîte à objets géométriques Utilisez geom_boxplot () pour créer un diagramme en moustache

box_plot <- box_plot +
    geom_boxplot()
print(box_plot)

LS0tDQp0aXRsZTogIkJENyBSIHByYXRpcXVlIg0KQXV0ZXVyOiBaWmFpZXINCnJlZmFpdCBwYXI6IEpaOA0KRGF0ZTogMjAxOS0xMC0wMQ0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KTGlyZSB1biBmaWNoaWVyIGNzdiBzdXIgbGUgd2ViDQoNCmBgYHtyfQ0KUEFUSCA8LSAnaHR0cDovL3ppZWR6YWllci5jb20vd3AtY29udGVudC91cGxvYWRzLzIwMTkvMDcvbXRjYXJzLmNzdicNCm10Y2FycyA8LSByZWFkLmNzdihQQVRILCBoZWFkZXIgPSAgVFJVRSwgc2VwID0gJywnLHN0cmluZ3NBc0ZhY3RvcnMgPUZBTFNFKQ0KDQpgYGANCg0KYGBge3J9DQoNCmRpbShtdGNhcnMpDQoNCmBgYA0KYGBge3J9DQpuYW1lcyhtdGNhcnMpDQpgYGANCg0KDQpgYGB7cn0NCmhlYWQobXRjYXJzKQ0KDQpgYGANCg0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmBgYA0KDQp0cmFjZXIgdW4gZGlhZ3JhbW1lIGRlIGRpc3BlcnNpb24gZGVzIHZhcmlhYmxlcyBtcGcgZXQgZHJhdC4NCnVuIGZpY2hpZXIgcGRmIGF2ZWMgbGUgZ3JhcGhpcXVlIGVzdCBjcmVlIGRhbnMgdm90cmUgcmVwZXJ0b2lyZSBkZSBwcm9qZXQNCmBgYHtyfQ0KcCA8LSBnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IGRyYXQsIHkgPSBtcGcpKSArDQogICAgZ2VvbV9wb2ludCgpDQpwcmludChwKQ0KYGBgDQoNClNhdXZlZ2FyZGVyIGxlIEdyYXBoZSBlbiBmb3JtYXQgcG5nDQpgYGB7cn0NCmdnc2F2ZSgibW9uX3ByZW1pZXJfZ3JhcGhlLnBuZyIpDQpgYGANCmRpc3Rpbmd1ZXIgbGVzIHZhbGV1cnMgZOKAmXVuIGdyb3VwZSBkZSBkb25uw6llcyAtIGdlYXINCmBgYHtyfQ0KcCA8LSBnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IG1wZywgeSA9IGRyYXQpKSArDQogICAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBmYWN0b3IoZ2VhcikpKQ0KcHJpbnQocCkNCmBgYA0KDQoNCnJlbmRyZSB2b3MgZG9ubsOpZXMgbW9pbnMgc2Vuc2libGVzIGF1eCB2YWxldXJzIGFiZXJyYW50ZXMgYXZlYyBsZSByZWRpbWVuc2lvbm5lbWVudCAtIGVjaGVsbGUgbG9nYXJpdGhtaXF1ZQ0KDQpgYGB7cn0NCnAgPC1nZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IGxvZyhtcGcpLCB5ID0gbG9nKGRyYXQpKSkgKw0KICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gZmFjdG9yKGFtKSkpDQpwcmludChwKQ0KYGBgDQoNCkFqb3V0ZXIgdW4gYXV0cmUgbml2ZWF1IGTigJlpbmZvcm1hdGlvbiBhdSBncmFwaGlxdWUgZW4gdHJhY2FudCBsYSB2YWxldXIgYWp1c3TDqWUgZCd1bmUgcsOpZ3Jlc3Npb24gbGluw6lhaXJlLg0KIEwnYXJndW1lbnQgc3RhdF9zbW9vdGggKCkgY29udHLDtGxlIGxhIG3DqXRob2RlIGRlIGxpc3NhZ2UgLSBtZXRob2QgPSAibG0iOiByw6lncmVzc2lvbiBsaW7DqWFpcmUNCmNvbCA9ICIjIEM0MjEyNiI6IENvZGUgZGUgbGEgY291bGV1ciByb3VnZSBkZSBsYSBsaWduZSBldCBzZSA9IEZBTFNFOiBuZSBwYXMgYWZmaWNoZXIgbCdlcnJldXIgc3RhbmRhcmQNCiBzaXplID0gMTogbCfDqXBhaXNzZXVyICBkZSBsYSBsaWduZSBlc3QgMQ0KDQpgYGB7cn0NCm1vbl9ncmFwaGUgPC0gZ2dwbG90KG10Y2FycywgYWVzKHggPSBsb2cobXBnKSwgeSA9IGxvZyhkcmF0KSkpICsNCiAgICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGZhY3Rvcih2cykpKSArDQogICAgc3RhdF9zbW9vdGgobWV0aG9kID0gImxtIiwNCiAgICAgICAgY29sID0gInllbGxvdyIsDQogICAgICAgIHNlID0gRkFMU0UsDQogICAgICAgIHNpemUgPSAxKQ0KcHJpbnQobW9uX2dyYXBoZSkNCmBgYA0KDQpham91dGVyIHZvdHJlIHRpdHJlDQpgYGB7cn0NCm1vbl9ncmFwaGUgPC1tb25fZ3JhcGhlICsNCiAgICBsYWJzKA0KICAgICAgICB0aXRsZSA9ICJEaXNwZXJzaW9uIGRlcyB2YXJpYWJsZXMgbXBnIGV0IGRyYXQiDQogICAgICAgICApICsgDQogIHhsYWIoJ1ZhbGV1ciBkZSBsb2coZHJhZiknKSArIA0KICB5bGFiKCdWYWxldXIgZGUgbG9nKG1wZyknKSANCg0KcHJpbnQobW9uX2dyYXBoZSkNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmBgYA0KDQpiYXIgY2hhcnQgYmFzaXF1ZSB1biBjb3VudCBzdXIgbGEgdmFyaWFibGUgY3lsDQpgYGB7cn0NCnAgPC0gZ2dwbG90KG10Y2FycywgYWVzKHggPSBmYWN0b3IoY3lsKSkpICsNCiAgICBnZW9tX2JhcigpICsNCiAgICBsYWJzKA0KICAgICAgICB0aXRsZSA9ICJCYXIgY2hhcnQgYmFzaXF1ZSB1biBjb3VudCBzdXIgbGEgdmFyaWFibGUgY3lsIg0KICAgICAgICAgKSArIA0KICB4bGFiKCdOb21icmUgZGUgY3lsaW5kcmVzJykgKyANCiAgeWxhYignTm9tYnJlIGRlIGRvbm7DqWVzJykgDQoNCnByaW50KHApDQpgYGANCg0KQ2hhbmdlciBsYSBjb3VsZXVyIGRlcyBiYXJyZXMNCmBgYHtyfQ0KcCA8LSBnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IGZhY3RvcihjeWwpKSkgKw0KICAgIGdlb21fYmFyKGZpbGwgPSAiYmx1ZSIpICsNCiAgICB0aGVtZV9jbGFzc2ljKCkrDQogICAgbGFicygNCiAgICAgICAgdGl0bGUgPSAiQmFyIGNoYXJ0IGJhc2lxdWUgdW4gY291bnQgc3VyIGxhIHZhcmlhYmxlIGN5bCINCiAgICAgICAgICkgKyANCiAgeGxhYignTm9tYnJlIGRlIGN5bGluZHJlcycpICsgDQogIHlsYWIoJ05vbWJyZSBkZSBkb25uw6llcycpIA0KcHJpbnQocCkNCmBgYA0KDQpDb3VsZXVyIHBhciBncm91cGUNCg0KYGBge3J9DQpwIDwtIGdncGxvdChtdGNhcnMsIGFlcyhmYWN0b3IoY3lsKSwNCiAgICAgICAgZmlsbCA9IGZhY3RvcihjeWwpKSkgKw0KICAgIGdlb21fYmFyKCkgKw0KICAgIHRoZW1lX2NsYXNzaWMoKSsNCiAgICBsYWJzKA0KICAgICAgICB0aXRsZSA9ICJCYXIgY2hhcnQgYmFzaXF1ZSB1biBjb3VudCBzdXIgbGEgdmFyaWFibGUgY3lsIg0KICAgICAgICAgKSArIA0KICB4bGFiKCdOb21icmUgZGUgY3lsaW5kcmVzJykgKyANCiAgeWxhYignTm9tYnJlIGRlIGRvbm7DqWVzJykgDQpwcmludChwKQ0KYGBgDQoNCg0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KYGBgDQoNCkFqb3V0ZXIgdW4gYXV0cmUgbml2ZWF1IGRlIGdyb3VwZQ0KYGBge3J9DQpkYXRhIDwtIG10Y2FycyAlPiUNCm11dGF0ZShhbSA9IGZhY3RvcihhbSwgbGFiZWxzID0gYygiYXV0byIsICJtYW4iKSksDQogICAgY3lsID0gZmFjdG9yKGN5bCkpDQpwIDwtIGdncGxvdChkYXRhLCBhZXMoeCA9IGN5bCwgZmlsbCA9IGFtKSkgKw0KICAgIGdlb21fYmFyKCkgKw0KICAgIHRoZW1lX2J3KCkgKw0KICAgIGxhYnMoDQogICAgICAgIHRpdGxlID0gIkJhciBjaGFydCBiYXNpcXVlIHVuIGNvdW50IHN1ciBsYSB2YXJpYWJsZSBjeWwiDQogICAgICAgICApICsgDQogIHhsYWIoJ05vbWJyZSBkZSBjeWxpbmRyZXMnKSArIA0KICB5bGFiKCdOb21icmUgZGUgZG9ubsOpZXMnKSANCg0KcHJpbnQocCkNCmBgYA0KDQpNdWx0aSBCYXJyZXMNCmBgYHtyfQ0KcCA8LSBnZ3Bsb3QoZGF0YSwgYWVzKHggPSBjeWwsIGZpbGwgPSBhbSkpICsNCiAgICBnZW9tX2Jhcihwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKCkpICsNCiAgICB0aGVtZV9idygpKw0KICAgIGxhYnMoDQogICAgICAgIHRpdGxlID0gIk11bHRpIEJhcnJlcyAgYmFzaXF1ZSBsZSBjb3VudCBzdXIgbGEgdmFyaWFibGUgY3lsIGVuIGZhY3RvciBBTSINCiAgICAgICAgICkgKyANCiAgeGxhYignTm9tYnJlIGRlIGN5bGluZHJlcycpICsgDQogIHlsYWIoJ05vbWJyZSBkZSBkb25uw6llcycpIA0KcHJpbnQocCkNCmBgYA0KDQpWb3VzIGNyw6lleiB1biBibG9jIGRlIGRvbm7DqWVzIG5vbW3DqSBkb25uZWVfaGlzdG9ncmFtZSBxdWkgcmVudm9pZSANCnNpbXBsZW1lbnQgbGEgbW95ZW5uZSBwYXIgbGUgbm9tYnJlIGRlIGN5bGluZHJlcyBkYW5zIGxhIHZvaXR1cmUuIA0KYXBwZWxlciBjZXR0ZSBub3V2ZWxsZSB2YXJpYWJsZSBtb3llbm5lX21wZyBldCBhcnJvbmRpc3NleiBsYSBtb3llbm5lIGF2ZWMgZGV1eCBkw6ljaW1hbGVzLg0KYGBge3J9DQpkb25uZWVfaGlzdG9ncmFtZSA8LSBtdGNhcnMgJT4lDQptdXRhdGUoY3lsID0gZmFjdG9yKGN5bCkpICU+JQ0KZ3JvdXBfYnkoY3lsKSAgJT4lIHN1bW1hcml6ZShtb3llbm5lX21wZyA9IHJvdW5kKG1lYW4obXBnKSwgMikpDQpgYGANCg0KVm91cyBwb3V2ZXogdHJhY2VyIGwnaGlzdG9ncmFtbWUuDQpMYSB2YXJpYWJsZSBjeWwgZmFpdCByw6lmw6lyZW5jZSDDoCBsJ2F4ZSBkZXMgeCBldCBtb3llbm5lX21wZyDDoCBsJ2F4ZSBkZXMgeS4NClZvdXMgZGV2ZXogcGFzc2VyIGwnYXJndW1lbnQgc3RhdCA9ICJpZGVudGl0eSIgcG91ciByw6lmw6lyZW5jZXIgbGEgdmFyaWFibGUgc3VyIGwnYXhlIGRlcyBvcmRvbm7DqWVzDQogZW4gdGFudCBxdWUgdmFsZXVyIG51bcOpcmlxdWUuIGdlb21fYmFyIHV0aWxpc2Ugc3RhdCA9ICJiaW4iIGNvbW1lIHZhbGV1ciBwYXIgZMOpZmF1dC4NClZvdXMgbW9kaWZpZXogbCdvcmllbnRhdGlvbiBkdSBncmFwaGlxdWUgZGUgdmVydGljYWwgw6AgaG9yaXpvbnRhbCBhdmVjIGNvb3JkX2ZsaXAoKQ0KYGBge3J9DQoNCmdyYXBoZSA8LSBnZ3Bsb3QoZG9ubmVlX2hpc3RvZ3JhbWUsIGFlcyh4ID0gY3lsLCB5ID0gbW95ZW5uZV9tcGcsIGZpbGwgPSBjeWwpKSArDQogICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsDQogICAgICAgIHdpZHRoID0gMC41KSArDQogICAgY29vcmRfZmxpcCgpICsNCiAgICB0aGVtZV9jbGFzc2ljKCkNCnByaW50KGdyYXBoZSkNCmBgYA0KDQpgYGB7cn0NCmdyYXBoZSA8LSBncmFwaGUgKyBnZW9tX3RleHQoYWVzKGxhYmVsID0gbW95ZW5uZV9tcGcpLA0KICAgICAgICBoanVzdCA9IDEuNSwNCiAgICAgICAgY29sb3IgPSAid2hpdGUiLA0KICAgICAgICBzaXplID0gMykgKw0KICAgIHRoZW1lX2NsYXNzaWMoKQ0KDQpwcmludChncmFwaGUpDQpgYGANCmxpcmUgdW4gZmljaGllciBjc3Ygc3VyIGxlIHdlYg0KDQpgYGB7cn0NClBBVEggPC0gJ2h0dHA6Ly96aWVkemFpZXIuY29tL3dwLWNvbnRlbnQvdXBsb2Fkcy8yMDE5LzA3L2FpcnF1YWxpdHkuY3N2Jw0KcXVhbGl0ZV9haXIgPC0gcmVhZC5jc3YoUEFUSCwgaGVhZGVyID0gIFRSVUUsIHNlcCA9ICcsJyxzdHJpbmdzQXNGYWN0b3JzID1GQUxTRSkNCnByaW50KGhlYWQocXVhbGl0ZV9haXIsNSkpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KYGBgDQoNCkltcG9ydGVyIGxlcyBkb25uw6llcw0KYGBge3J9DQpkb25uZWVfYWlyIDwtIHF1YWxpdGVfYWlyICU+JQ0KICBzZWxlY3QoLWMoU29sYXIuUiwgVGVtcCkpICU+JQ0KICBtdXRhdGUoTW9udGggPSBmYWN0b3IoTW9udGgsIG9yZGVyID0gVFJVRSwgbGFiZWxzID0gYygiTWF5IiwgIkp1bmUiLCAiSnVseSIsICJBdWd1c3QiLCAiU2VwdGVtYmVyIikpLA0KICAgICAgICAgam91cl9kaXZpc2UgPSBmYWN0b3IoaWZlbHNlKERheSA8IDEwLCAiZGVidXQiLCBpZmVsc2UoRGF5IDwgMjAsICJtaWxpZXUiLCAiZmluIikpKSkNCmRvbm5lZV9haXJfcGFzX25hIDwtZG9ubmVlX2FpciAlPiUgbmEub21pdCgpDQpgYGANClN1cHByaW1leiBsZXMgdmFyaWFibGVzIGludXRpbGVzDQpgYGB7cn0NCg0KYGBgDQoNCm9udmVydGlyIGxlIG1vaXMgZW4gZmFjdGV1cg0KYGBge3J9DQoNCg0KYGBgDQoNCkNyw6lleiB1bmUgbm91dmVsbGUgdmFyaWFibGUgY2F0w6lnb3JpcXVlIGRpdmlzYW50IGxlIG1vaXMgZW4gdHJvaXMgbml2ZWF1eDogZMOpYnV0LCBtaWxpZXUgZXQgZmluLg0KYGBge3J9DQoNCg0KYGBgDQoNClN1cHByaW1lciBsZXMgb2JzZXJ2YXRpb25zIG1hbnF1YW50ZXMNCmBgYHtyfQ0KDQpgYGANCg0KU3RvY2tlciBsZSBncmFwaGlxdWUNClZvdXMgcGFzc2V6IGwnZW5zZW1ibGUgZGUgZG9ubsOpZXMgZG9ubmVlX2Fpcl9wYXNfbmEgw6AgZ2dwbG90Lg0KRGFucyBsJ2FyZ3VtZW50IGFlcyAoKSwgdm91cyBham91dGV6IGxlcyBheGVzIHggZXQgeS4NCmBgYHtyfQ0KYm94X3Bsb3QgPC0gZ2dwbG90KGRvbm5lZV9haXJfcGFzX25hLCBhZXMoeCA9IE1vbnRoLCB5ID0gT3pvbmUpKQ0KDQpgYGANCg0KDQpBam91dGVyIGxlIHRyYWPDqSBkZSBsYSBib8OudGUgw6Agb2JqZXRzIGfDqW9tw6l0cmlxdWVzDQpVdGlsaXNleiBnZW9tX2JveHBsb3QgKCkgcG91ciBjcsOpZXIgdW4gZGlhZ3JhbW1lIGVuIG1vdXN0YWNoZQ0KDQpgYGB7cn0NCmJveF9wbG90IDwtIGJveF9wbG90ICsNCiAgICBnZW9tX2JveHBsb3QoKQ0KcHJpbnQoYm94X3Bsb3QpDQpgYGANCg0K