1. Hvad kan man bruge R til?

1.1 Beregninger og tekst

R kan bruge matematiske tegn til at lave beregninger:

5+5
[1] 10

Eller til at skrive tekst:

"Jeg elsker Survey Design"
[1] "Jeg elsker Survey Design"

1.2 Logiske tegn

R kan også bruge logiske tegn til at fortælle, om noget er TRUE (sandt) eller FALSE (falsk).

< og > sammenligner tal

== undersøger, om to værdier er ens

<= betyder mindre end eller lig med

>= betyder større end eller lig med

!= betyder ikke lige med

# Er 4 fx større end 3?
4 > 3
[1] TRUE
# Og er 5 det samme som 4?
5 == 4
[1] FALSE

1.3 Gemme og bruge objekter

En vigtig forskel mellem R og en almindelig lommeregner er, at R kan gemme værdier.

Det gør vi med assignment operatoren <-, der ‘assigner’ værdier til et objekt.

Når man gemmer værdier, kan man bruge dem igen senere. De objekter, du har gemt, kan du se i dit Environment.

Vi kan fx gemme beregningen fra tidligere.

my_number
[1] 10

Vi kan også gemme tekst som et objekt:

my_text <- "Her kan du skrive hvad som helst!"
my_text
[1] "Her kan du skrive hvad som helst!"

Vi kan bruge gemte objekter i nye beregninger:

my_second_number <- my_number + 3
my_second_number
[1] 13
my_third_number <- my_second_number - my_number
my_third_number
[1] 3

my_number gemmer tallet 10

my_second_number gemmer tallet 13 (10 + 3)

my_third_number er derfor 13 - 10 = 3

Kort sagt: vi bruger objekter til at gemme værdier under et navn, så vi kan bruge den igen senere.

2. Funktioner, pakker og argumenter

2.1 Funktioner

Funktioner er kommandoer i R, der udfører en bestemt handling. Forskellige funktioner kan bruges til forskellige ting.

# Vi kan fx bruge funktionen `sqrt()` til at finde kvadratroden af en værdi:
sqrt(5+5)
[1] 3.162278

Funktioner skrives altid med parenteser, fx funktionens_navn(). Det, vi skriver inde i parentesen, er inputtet til funktionen.

2.2 Argumenter

Mange funktioner kan tilpasses ved hjælp af argumenter.

Argumenter fortæller funktionen, hvordan den skal udføre sin opgave og hvad den skal arbejde med.

# Vi kan fx bruge pakken `cowsay` til at få forskellige dyr til at sige noget med funktionen `say`:
say(what = "Jeg elsker at kode i R",
by = "cat")

Her er what og by argumenter:

what bestemmer, hvad der skal siges.

by bestemmer, hvem der skal sige det.

# Vi kan også bruge objekter, vi allerede har gemt, som input i et argument, fx objektet `my_text` fra tidligere:
say(what = my_text,
by = "fish")

help() og ?

Vi kan undersøge en funktion med ?, hvis vi er i tvivl om, hvilke argumenter funktionen har eller hvad de forskellige argumenter gør.

Fx kan vi skrive ?say og få informationer om, hvad vi kan skrive af input i funktionen.

2.3 Pakker

R indeholder mange funktioner i sig selv, men man kan få adgang til flere funktioner ved at installere og loade pakker.

En pakke er en samling af funktioner og andet indhold, som andre R-brugere har lavet.

Hvis vi skal bruge pakken cowsay, skal vi først installere den med funktionen install.packages():

install.packages("cowsay")
# Når pakken er installeret, skal den indlæses med funktionen `library()`, før vi kan bruge dens funktioner:
library(cowsay)

Vi behøver kun at installere pakker én gang, men vi skal bruge library() til at indlæse dem hver gang, vi starter en ny R-session.

2.4 Mapper og filstier

Når vi arbejder med data i R, skal vi ofte fortælle R, hvor en fil ligger. Det gør vi med filstier (file pahts). En filsti fortæller R, hvor den skal lede efter en bestemt fil eller mappe.

dir()

Funktionen dir() kan bruges til at se indholdet af den mappe, vi arbejder fra.

# Fx kan vi bruge dir() til at se, hvad der ligger i den mappe, vi befinder os i:
dir("UV1")
[1] "Exercise 1"                  "Exercise 2"                 
[3] "R notebook eksempel.nb.html" "R notebook eksempel.Rmd"    
[5] "R script eksempel.R"        
# Eller i en anden vilkårlig mappe, vi gerne vil undersøge:
dir("UV1/Exercise 1")
[1] "week_1_intro_solutions.R" "week_1_intro.R"          

getwd()

Funktionen getwd() kan bruges til at se, hvilken mappe det er. Det er her, R starter, når vi bruger relative filstier.

En relativ filsti beskriver, hvor en fil eller mappe ligge i forhold til den mappe, R arbejder ud fra.

Hvis vores working directory er hunt_01_Trash_Metal, og der i den mappe ligger undermappen Overkill, hvori filen Elimination.csv ligger, vil den relative filsti til Elimination.csv være:

Overkill/Elimination.csv

../ og ../../

Når vi arbejder med relative filstier, kan vi bruge .. til at vise indholdet af en mappe, der ligger et led ude i vores sti. Dvs. vi beder R om at gå ud af den nuværende mappe og en mappe tilbage.

# Hvis vi befinder os i mappen Overkill, der ligger i mappen hunt_01_Trash_Metal, kan vi vise indholdet af hunt_01_Trash_Metal ved at skrive:
dir("../")

Hvis vores working directory er hunt_01_Trash_Metal, og der i den mappe ligger undermappen Overkill, hvori filen Elimination.csv ligger, vil den relative filsti til Elimination.csv være:

"Overkill/Elimination.csv"

Hvis vi vil gå ud af to mapper, kan vi skrive dir("../../"). Så beder vi R om at gå ud af den nuværende mappe og derefter ud af den næste - altså to mapper tilbage i stien.

2.5 Opsummering

dir() viser indholdet af en mappe

dir("../") viser, hvad der ligger i mappen uden for vores projektmappe

dir("../../") viser, hvad der ligger to mapper ude

getwd() viser, hvor vores relative filsti starter (dvs. vores nuværende working directory)

help() og ? åbner dokumentationen for en funktion

install.packages installerer en pakke

library() indlæser en installeret pakke

3. Vektorer

3.1 Hvad er en vektor?

En vektor er et objekt, der indeholder flere værdier i en bestemt rækkefølge. Det kan være tal, tekst eller logiske værdier. Dvs. vektorer er en måde at gemme lister af værdier i R. Når vi arbejder med variable i et datasæt, er en variabel det samme som en vektor.

Vi laver vektorer med combine-funktionen c():

# Vektorer kan indeholde tal
my_vector <- c(1, 29, 13, 2)

# og tekst
my_text_vector <- c("Apple", "Banana", "Pear")

Hver værdi i en vektor har en bestemt position. Dvs. rækkefølgen af værdier i en vektor altid er den samme - nr. 1, 2, 3 osv…

Vi kan udvælge bestemte værdier fra en vektor med [] og : til at vælge et interval af værdier i vektoren:

my_vector[1] # giver os den første værdi i rækken
[1] 1
my_vector[2] # giver os den anden værdi i rækken
[1] 29
my_vector[1:3] # giver os første til tredje værdi i vektoren
[1]  1 29 13

3.2 Beregninger med vektorer

En af fordelene ved vektorer er, at vi kan lave beregninger på hele vektoren, dvs. alle værdier, på én gang.

# Fx kan vi lægge 2 til hver værdi i vektoren
my_vector + 2
[1]  3 31 15  4

Vi kan også bruge funktioner på hele vektoren, fx:

sum(my_vector) # summen af værdierne
[1] 45
mean(my_vector) # gennemsnittet af værdierne
[1] 11.25
min(my_vector) # den mindste værdi i vektoren
[1] 1
max(my_vector) # den største værdi
[1] 29
range(my_vector) # den største og mindste værdi
[1]  1 29

Det kan være brugbart, hvis vi har mange værdier i en vektor - fx et surveyspørgsmål med mange svar.

4. Dataframes

Når vi arbejder med tabulære data (data frames), er hver kolonne en vektor.

Vi kan bruge $ til at udvælge en bestemt kolonne i et datasættet. Hvis vi har dataframen 'my_data' og vil vælge vektoren V1, ser det sådan her ud:

my_data$V1

Udover kolonner består dataframes også af rækker. Vi kan bruge [] til at udvælge bestemte rækker og kolonner, ligesom når vi arbejder med vektorer:

my_data[4,3] # R viser række 4, kolonne 3 i vores dataframe
my_data[4, ] # R viser hele række 4 i vores dataframe
my_data[ ,3] # R viser hele kolonne 3 i vores dataframe
my_data[, "variabel_navn"] # R viser hele kolonnen for en given variabel

Husk, at rækkefølgen altid er [række, kolonne].

4.1 Betingelser

Vi kan også udvælge bestemte værdier eller rækker i en vektor eller dataframe med logiske betingelser.

# Koden vil fx kun give os de værdier i vektoren, hvor betingelsen er `TRUE`. Dvs. at R her kun beholder de værdier i vekoren, der er mindre end 25:
my_vector[my_vector < 25]
# Vi kan gøre det samme på dataframes. Her beholder R kun de værdier i dataframen, der er mindre end 70:
my_data[my_data$variabel_navn < 70, ]

5. tidyverse

R er et open-source program, og vi bruger derfor alle mulige pakker lavet af andre brugere, når vi koder.

tidyverse er en samling af pakker, der deler “kodefilosofi”, som gør det lettere at bruge dem sammen. Pakkerne gør det mere overskueligt at arbejde data.

Pipes %>%

Når man skriver kode i R, er det meget almindeligt at bruge babushka-struktur med parenteser i parenteser. Det kalder man ‘nesting’ og kan hurtigt blive uoverskueligt.

Pipes giver os mulighed for at skrive mere letlæselig kode ved at sætte flere trin af kode sammen i en rækkefølge, der er lettere at læse.

# Eksempel på 'nested' kode i babushka-struktur med parenteser i parenteser:
sqrt(abs(sum(c(-1,-2,-3))))
[1] 2.44949
# Samme kode med pipe-funktionen:
c(-1, -2, -3) %>% sum() %>% abs() %>% sqrt()
[1] 2.44949

Helt kort kan pipes forstås som et “and then…”; altså “og så gør vi sådan her… og så gør vi sådan her…”

# Man kan også lave linjeskift for at gøre koden endnu mere letlæselig:
c(-1,-2,-3) %>%
sum() %>%
abs() %>%
sqrt()
[1] 2.44949

Pipes tager altså et objekt eller et output på venstre side og “piper” det videre som et argument til en funktion på højre side af pipen.

filter()

Funktionen filter() fra tidyverse gør det muligt at udvælge rækker i et datasæt, der opfylder en bestemt betingelse. Vi kan altså bruge filter() til kun at se observationer, der er relevante for os.

# Her beholder R kun de rækker, hvor værdierne af `variabel` er større end 70:
my_data %>%
filter(variabel > 70)

pull()

Funktionen pull() henter en bestemt kolonne ud af et datasæt og giver os en vektor med værdierne fra kolonnen.

# Her henter R alle værdierne fra kolonnen `variabel`.
my_data %>%
pull(variabel)

summarize()

Funktionen summarize() bruges til at lave beregninger, der opsummerer data. Det kan fx være et gennemsnit, minimum eller maksimum af værdierne i vores datasæt.

my_data %>%
summarize()
LS0tCnRpdGxlOiAiU3VydmV5IERlc2lnbiBGdW5rdGlvbnNvdmVyc2lndCIKYXV0aG9yOiAiSnVsaWFuZSBTdGFyY2tlIE5lZXJnYWFyZCIKZGF0ZTogIjIwMjYtMTAtMDEiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMjIDEuIEh2YWQga2FuIG1hbiBicnVnZSBSIHRpbD8KIyMjIDEuMSBCZXJlZ25pbmdlciBvZyB0ZWtzdApSIGthbiBicnVnZSBtYXRlbWF0aXNrZSB0ZWduIHRpbCBhdCBsYXZlIGJlcmVnbmluZ2VyOgpgYGB7cn0KNSs1CmBgYApFbGxlciB0aWwgYXQgc2tyaXZlIHRla3N0OgpgYGB7cn0KIkplZyBlbHNrZXIgU3VydmV5IERlc2lnbiIKYGBgCiMjIyAxLjIgTG9naXNrZSB0ZWduClIga2FuIG9nc8OlIGJydWdlIGxvZ2lza2UgdGVnbiB0aWwgYXQgZm9ydMOmbGxlLCBvbSBub2dldCBlciBgVFJVRWAgKHNhbmR0KSBlbGxlciBgRkFMU0VgIChmYWxzaykuCgpgPGAgb2cgYD5gIHNhbW1lbmxpZ25lciB0YWwKCmA9PWAgdW5kZXJzw7hnZXIsIG9tIHRvIHbDpnJkaWVyIGVyIGVucwoKYDw9YCBiZXR5ZGVyIG1pbmRyZSBlbmQgZWxsZXIgbGlnIG1lZAoKYD49YCBiZXR5ZGVyIHN0w7hycmUgZW5kIGVsbGVyIGxpZyBtZWQKCmAhPWAgYmV0eWRlciBpa2tlIGxpZ2UgbWVkCgpgYGB7cn0KIyBFciA0IGZ4IHN0w7hycmUgZW5kIDM/CjQgPiAzCmBgYApgYGB7cn0KIyBPZyBlciA1IGRldCBzYW1tZSBzb20gND8KNSA9PSA0CmBgYAoKIyMjIDEuMyBHZW1tZSBvZyBicnVnZSBvYmpla3RlcgpFbiB2aWd0aWcgZm9yc2tlbCBtZWxsZW0gUiBvZyBlbiBhbG1pbmRlbGlnIGxvbW1lcmVnbmVyIGVyLCBhdCBSIGthbiBnZW1tZSB2w6ZyZGllci4KCkRldCBnw7hyIHZpIG1lZCBhc3NpZ25tZW50IG9wZXJhdG9yZW4gYDwtYCwgZGVyICdhc3NpZ25lcicgdsOmcmRpZXIgdGlsIGV0IG9iamVrdC4KCk7DpXIgbWFuIGdlbW1lciB2w6ZyZGllciwga2FuIG1hbiBicnVnZSBkZW0gaWdlbiBzZW5lcmUuIERlIG9iamVrdGVyLCBkdSBoYXIgZ2VtdCwga2FuIGR1IHNlIGkgZGl0IEVudmlyb25tZW50LgoKVmkga2FuIGZ4IGdlbW1lIGJlcmVnbmluZ2VuIGZyYSB0aWRsaWdlcmUuIApgYGB7cn0KIyBIZXIgYmVyZWduZXIgUiBgNSArIDVgIG9nIGdlbW1lciByZXN1bHRhdGV0IGAxMGAgaSBvYmpla3RldCBgbXlfbnVtYmVyYApteV9udW1iZXIgPC0gNSs1Cm15X251bWJlcgpgYGAKClZpIGthbiBvZ3PDpSBnZW1tZSB0ZWtzdCBzb20gZXQgb2JqZWt0OgoKYGBge3J9Cm15X3RleHQgPC0gIkhlciBrYW4gZHUgc2tyaXZlIGh2YWQgc29tIGhlbHN0ISIKbXlfdGV4dApgYGAKVmkga2FuIGJydWdlIGdlbXRlIG9iamVrdGVyIGkgbnllIGJlcmVnbmluZ2VyOgpgYGB7cn0KbXlfc2Vjb25kX251bWJlciA8LSBteV9udW1iZXIgKyAzCm15X3NlY29uZF9udW1iZXIKYGBgCgpgYGB7cn0KbXlfdGhpcmRfbnVtYmVyIDwtIG15X3NlY29uZF9udW1iZXIgLSBteV9udW1iZXIKbXlfdGhpcmRfbnVtYmVyCmBgYAoKYG15X251bWJlcmAgZ2VtbWVyIHRhbGxldCAxMAoKYG15X3NlY29uZF9udW1iZXJgIGdlbW1lciB0YWxsZXQgMTMgYCgxMCArIDMpYAoKYG15X3RoaXJkX251bWJlcmAgZXIgZGVyZm9yIGAxMyAtIDEwID0gM2AKCktvcnQgc2FndDogdmkgYnJ1Z2VyIG9iamVrdGVyIHRpbCBhdCBnZW1tZSB2w6ZyZGllciB1bmRlciBldCBuYXZuLCBzw6Ugdmkga2FuIGJydWdlIGRlbiBpZ2VuIHNlbmVyZS4KCiMjIDIuIEZ1bmt0aW9uZXIsIHBha2tlciBvZyBhcmd1bWVudGVyCgojIyMgMi4xIEZ1bmt0aW9uZXIKRnVua3Rpb25lciBlciBrb21tYW5kb2VyIGkgUiwgZGVyIHVkZsO4cmVyIGVuIGJlc3RlbXQgaGFuZGxpbmcuIEZvcnNrZWxsaWdlIGZ1bmt0aW9uZXIga2FuIGJydWdlcyB0aWwgZm9yc2tlbGxpZ2UgdGluZy4KCmBgYHtyfQojIFZpIGthbiBmeCBicnVnZSBmdW5rdGlvbmVuIGBzcXJ0KClgIHRpbCBhdCBmaW5kZSBrdmFkcmF0cm9kZW4gYWYgZW4gdsOmcmRpOgpzcXJ0KDUrNSkKYGBgCgpGdW5rdGlvbmVyIHNrcml2ZXMgYWx0aWQgbWVkIHBhcmVudGVzZXIsIGZ4IGBmdW5rdGlvbmVuc19uYXZuKClgLiBEZXQsIHZpIHNrcml2ZXIgaW5kZSBpIHBhcmVudGVzZW4sIGVyIGlucHV0dGV0IHRpbCBmdW5rdGlvbmVuLgoKIyMjIDIuMiBBcmd1bWVudGVyCk1hbmdlIGZ1bmt0aW9uZXIga2FuIHRpbHBhc3NlcyB2ZWQgaGrDpmxwIGFmIGFyZ3VtZW50ZXIuCgpBcmd1bWVudGVyIGZvcnTDpmxsZXIgZnVua3Rpb25lbiwgaHZvcmRhbiBkZW4gc2thbCB1ZGbDuHJlIHNpbiBvcGdhdmUgb2cgaHZhZCBkZW4gc2thbCBhcmJlamRlIG1lZC4KYGBge3IsIGV2YWw9RkFMU0V9CiMgVmkga2FuIGZ4IGJydWdlIHBha2tlbiBgY293c2F5YCB0aWwgYXQgZsOlIGZvcnNrZWxsaWdlIGR5ciB0aWwgYXQgc2lnZSBub2dldCBtZWQgZnVua3Rpb25lbiBgc2F5YDoKc2F5KHdoYXQgPSAiSmVnIGVsc2tlciBhdCBrb2RlIGkgUiIsCmJ5ID0gImNhdCIpCmBgYApIZXIgZXIgYHdoYXRgIG9nIGBieWAgYXJndW1lbnRlcjoKCmB3aGF0YCBiZXN0ZW1tZXIsIGh2YWQgZGVyIHNrYWwgc2lnZXMuCgpgYnlgIGJlc3RlbW1lciwgaHZlbSBkZXIgc2thbCBzaWdlIGRldC4KYGBge3IsIGV2YWw9RkFMU0V9CiMgVmkga2FuIG9nc8OlIGJydWdlIG9iamVrdGVyLCB2aSBhbGxlcmVkZSBoYXIgZ2VtdCwgc29tIGlucHV0IGkgZXQgYXJndW1lbnQsIGZ4IG9iamVrdGV0IGBteV90ZXh0YCBmcmEgdGlkbGlnZXJlOgpzYXkod2hhdCA9IG15X3RleHQsCmJ5ID0gImZpc2giKQpgYGAKIyMjIGBoZWxwKClgIG9nIGA/YAoKVmkga2FuIHVuZGVyc8O4Z2UgZW4gZnVua3Rpb24gbWVkIGA/YCwgaHZpcyB2aSBlciBpIHR2aXZsIG9tLCBodmlsa2UgYXJndW1lbnRlciBmdW5rdGlvbmVuIGhhciBlbGxlciBodmFkIGRlIGZvcnNrZWxsaWdlIGFyZ3VtZW50ZXIgZ8O4ci4KCkZ4IGthbiB2aSBza3JpdmUgYD9zYXlgIG9nIGbDpSBpbmZvcm1hdGlvbmVyIG9tLCBodmFkIHZpIGthbiBza3JpdmUgYWYgaW5wdXQgaSBmdW5rdGlvbmVuLgoKIyMjIDIuMyBQYWtrZXIKUiBpbmRlaG9sZGVyIG1hbmdlIGZ1bmt0aW9uZXIgaSBzaWcgc2VsdiwgbWVuIG1hbiBrYW4gZsOlIGFkZ2FuZyB0aWwgZmxlcmUgZnVua3Rpb25lciB2ZWQgYXQgaW5zdGFsbGVyZSBvZyBsb2FkZSBwYWtrZXIuCgpFbiBwYWtrZSBlciBlbiBzYW1saW5nIGFmIGZ1bmt0aW9uZXIgb2cgYW5kZXQgaW5kaG9sZCwgc29tIGFuZHJlIFItYnJ1Z2VyZSBoYXIgbGF2ZXQuCgpIdmlzIHZpIHNrYWwgYnJ1Z2UgcGFra2VuIGBjb3dzYXlgLCBza2FsIHZpIGbDuHJzdCBpbnN0YWxsZXJlIGRlbiBtZWQgZnVua3Rpb25lbiBgaW5zdGFsbC5wYWNrYWdlcygpYDoKCmBgYHtyLCBldmFsPUZBTFNFfQppbnN0YWxsLnBhY2thZ2VzKCJjb3dzYXkiKQpgYGAKCmBgYHtyLCBldmFsPUZBTFNFfQojIE7DpXIgcGFra2VuIGVyIGluc3RhbGxlcmV0LCBza2FsIGRlbiBpbmRsw6ZzZXMgbWVkIGZ1bmt0aW9uZW4gYGxpYnJhcnkoKWAsIGbDuHIgdmkga2FuIGJydWdlIGRlbnMgZnVua3Rpb25lcjoKbGlicmFyeShjb3dzYXkpCmBgYAoKVmkgYmVow7h2ZXIga3VuIGF0IGluc3RhbGxlcmUgcGFra2VyIMOpbiBnYW5nLCBtZW4gdmkgc2thbCBicnVnZSBgbGlicmFyeSgpYCB0aWwgYXQgaW5kbMOmc2UgZGVtIGh2ZXIgZ2FuZywgdmkgc3RhcnRlciBlbiBueSBSLXNlc3Npb24uCgojIyMgMi40IE1hcHBlciBvZyBmaWxzdGllcgoKTsOlciB2aSBhcmJlamRlciBtZWQgZGF0YSBpIFIsIHNrYWwgdmkgb2Z0ZSBmb3J0w6ZsbGUgUiwgaHZvciBlbiBmaWwgbGlnZ2VyLiBEZXQgZ8O4ciB2aSBtZWQgZmlsc3RpZXIgKGZpbGUgcGFodHMpLiBFbiBmaWxzdGkgZm9ydMOmbGxlciBSLCBodm9yIGRlbiBza2FsIGxlZGUgZWZ0ZXIgZW4gYmVzdGVtdCBmaWwgZWxsZXIgbWFwcGUuCgojIyMjIGBkaXIoKWAKCkZ1bmt0aW9uZW4gYGRpcigpYCBrYW4gYnJ1Z2VzIHRpbCBhdCBzZSBpbmRob2xkZXQgYWYgZGVuIG1hcHBlLCB2aSBhcmJlamRlciBmcmEuCgpgYGB7cn0KIyBGeCBrYW4gdmkgYnJ1Z2UgZGlyKCkgdGlsIGF0IHNlLCBodmFkIGRlciBsaWdnZXIgaSBkZW4gbWFwcGUsIHZpIGJlZmluZGVyIG9zIGk6CmRpcigiVVYxIikKYGBgCgpgYGB7cn0KIyBFbGxlciBpIGVuIGFuZGVuIHZpbGvDpXJsaWcgbWFwcGUsIHZpIGdlcm5lIHZpbCB1bmRlcnPDuGdlOgpkaXIoIlVWMS9FeGVyY2lzZSAxIikKYGBgCgojIyMjIGBnZXR3ZCgpYAoKRnVua3Rpb25lbiBgZ2V0d2QoKWAga2FuIGJydWdlcyB0aWwgYXQgc2UsIGh2aWxrZW4gbWFwcGUgZGV0IGVyLiBEZXQgZXIgaGVyLCBSIHN0YXJ0ZXIsIG7DpXIgdmkgYnJ1Z2VyIHJlbGF0aXZlIGZpbHN0aWVyLgoKRW4gcmVsYXRpdiBmaWxzdGkgYmVza3JpdmVyLCBodm9yIGVuIGZpbCBlbGxlciBtYXBwZSBsaWdnZSBpIGZvcmhvbGQgdGlsIGRlbiBtYXBwZSwgUiBhcmJlamRlciB1ZCBmcmEuCgpIdmlzIHZvcmVzIHdvcmtpbmcgZGlyZWN0b3J5IGVyIGBodW50XzAxX1RyYXNoX01ldGFsYCwgb2cgZGVyIGkgZGVuIG1hcHBlIGxpZ2dlciB1bmRlcm1hcHBlbiBgT3ZlcmtpbGxgLCBodm9yaSBmaWxlbiBgRWxpbWluYXRpb24uY3N2YCBsaWdnZXIsIHZpbCBkZW4gcmVsYXRpdmUgZmlsc3RpIHRpbCBgRWxpbWluYXRpb24uY3N2YCB2w6ZyZToKCmBgYHtyLCBldmFsPUZBTFNFfQpPdmVya2lsbC9FbGltaW5hdGlvbi5jc3YKYGBgCgojIyMjIGAuLi9gIG9nIGAuLi8uLi9gCgpOw6VyIHZpIGFyYmVqZGVyIG1lZCByZWxhdGl2ZSBmaWxzdGllciwga2FuIHZpIGJydWdlIGAuLmAgdGlsIGF0IHZpc2UgaW5kaG9sZGV0IGFmIGVuIG1hcHBlLCBkZXIgbGlnZ2VyIGV0IGxlZCB1ZGUgaSB2b3JlcyBzdGkuIER2cy4gdmkgYmVkZXIgUiBvbSBhdCBnw6UgdWQgYWYgZGVuIG51dsOmcmVuZGUgbWFwcGUgb2cgZW4gbWFwcGUgdGlsYmFnZS4KCmBgYHtyLCBldmFsPUZBTFNFfQojIEh2aXMgdmkgYmVmaW5kZXIgb3MgaSBtYXBwZW4gT3ZlcmtpbGwsIGRlciBsaWdnZXIgaSBtYXBwZW4gaHVudF8wMV9UcmFzaF9NZXRhbCwga2FuIHZpIHZpc2UgaW5kaG9sZGV0IGFmIGh1bnRfMDFfVHJhc2hfTWV0YWwgdmVkIGF0IHNrcml2ZToKZGlyKCIuLi8iKQpgYGAKCkh2aXMgdm9yZXMgd29ya2luZyBkaXJlY3RvcnkgZXIgYGh1bnRfMDFfVHJhc2hfTWV0YWxgLCBvZyBkZXIgaSBkZW4gbWFwcGUgbGlnZ2VyIHVuZGVybWFwcGVuIGBPdmVya2lsbGAsIGh2b3JpIGZpbGVuIGBFbGltaW5hdGlvbi5jc3ZgIGxpZ2dlciwgdmlsIGRlbiByZWxhdGl2ZSBmaWxzdGkgdGlsIGBFbGltaW5hdGlvbi5jc3ZgIHbDpnJlOgoKYGBge3IsIGV2YWw9RkFMU0V9CiJPdmVya2lsbC9FbGltaW5hdGlvbi5jc3YiCmBgYAoKSHZpcyB2aSB2aWwgZ8OlIHVkIGFmIHRvIG1hcHBlciwga2FuIHZpIHNrcml2ZSBgZGlyKCIuLi8uLi8iKWAuIFPDpSBiZWRlciB2aSBSIG9tIGF0IGfDpSB1ZCBhZiBkZW4gbnV2w6ZyZW5kZSBtYXBwZSBvZyBkZXJlZnRlciB1ZCBhZiBkZW4gbsOmc3RlIC0gYWx0c8OlIHRvIG1hcHBlciB0aWxiYWdlIGkgc3RpZW4uCgojIyMgMi41IE9wc3VtbWVyaW5nCgpgZGlyKClgIHZpc2VyIGluZGhvbGRldCBhZiBlbiBtYXBwZQoKYGRpcigiLi4vIilgIHZpc2VyLCBodmFkIGRlciBsaWdnZXIgaSBtYXBwZW4gdWRlbiBmb3Igdm9yZXMgcHJvamVrdG1hcHBlCgpgZGlyKCIuLi8uLi8iKWAgdmlzZXIsIGh2YWQgZGVyIGxpZ2dlciB0byBtYXBwZXIgdWRlCgpgZ2V0d2QoKWAgdmlzZXIsIGh2b3Igdm9yZXMgcmVsYXRpdmUgZmlsc3RpIHN0YXJ0ZXIgKGR2cy4gdm9yZXMgbnV2w6ZyZW5kZSB3b3JraW5nIGRpcmVjdG9yeSkKCmBoZWxwKClgIG9nIGA/YCDDpWJuZXIgZG9rdW1lbnRhdGlvbmVuIGZvciBlbiBmdW5rdGlvbgoKYGluc3RhbGwucGFja2FnZXNgIGluc3RhbGxlcmVyIGVuIHBha2tlCgpgbGlicmFyeSgpYCBpbmRsw6ZzZXIgZW4gaW5zdGFsbGVyZXQgcGFra2UKCiMjIDMuIFZla3RvcmVyCiMjIyAzLjEgSHZhZCBlciBlbiB2ZWt0b3I/CkVuIHZla3RvciBlciBldCBvYmpla3QsIGRlciBpbmRlaG9sZGVyIGZsZXJlIHbDpnJkaWVyIGkgZW4gYmVzdGVtdCByw6Zra2Vmw7hsZ2UuIERldCBrYW4gdsOmcmUgdGFsLCB0ZWtzdCBlbGxlciBsb2dpc2tlIHbDpnJkaWVyLiBEdnMuIHZla3RvcmVyIGVyIGVuIG3DpWRlIGF0IGdlbW1lIGxpc3RlciBhZiB2w6ZyZGllciBpIFIuIE7DpXIgdmkgYXJiZWpkZXIgbWVkIHZhcmlhYmxlIGkgZXQgZGF0YXPDpnQsIGVyIGVuIHZhcmlhYmVsIGRldCBzYW1tZSBzb20gZW4gdmVrdG9yLgoKVmkgbGF2ZXIgdmVrdG9yZXIgbWVkIGNvbWJpbmUtZnVua3Rpb25lbiBgYygpYDoKYGBge3J9CiMgVmVrdG9yZXIga2FuIGluZGVob2xkZSB0YWwKbXlfdmVjdG9yIDwtIGMoMSwgMjksIDEzLCAyKQoKIyBvZyB0ZWtzdApteV90ZXh0X3ZlY3RvciA8LSBjKCJBcHBsZSIsICJCYW5hbmEiLCAiUGVhciIpCmBgYAoKSHZlciB2w6ZyZGkgaSBlbiB2ZWt0b3IgaGFyIGVuIGJlc3RlbXQgcG9zaXRpb24uIER2cy4gcsOma2tlZsO4bGdlbiBhZiB2w6ZyZGllciBpIGVuIHZla3RvciBhbHRpZCBlciBkZW4gc2FtbWUgLSBuci4gMSwgMiwgMyBvc3YuLi4KClZpIGthbiB1ZHbDpmxnZSBiZXN0ZW10ZSB2w6ZyZGllciBmcmEgZW4gdmVrdG9yIG1lZCBgW11gIG9nIGA6YCB0aWwgYXQgdsOmbGdlIGV0IGludGVydmFsIGFmIHbDpnJkaWVyIGkgdmVrdG9yZW46CmBgYHtyfQpteV92ZWN0b3JbMV0gIyBnaXZlciBvcyBkZW4gZsO4cnN0ZSB2w6ZyZGkgaSByw6Zra2VuCm15X3ZlY3RvclsyXSAjIGdpdmVyIG9zIGRlbiBhbmRlbiB2w6ZyZGkgaSByw6Zra2VuCm15X3ZlY3RvclsxOjNdICMgZ2l2ZXIgb3MgZsO4cnN0ZSB0aWwgdHJlZGplIHbDpnJkaSBpIHZla3RvcmVuCmBgYAojIyMgMy4yIEJlcmVnbmluZ2VyIG1lZCB2ZWt0b3JlcgpFbiBhZiBmb3JkZWxlbmUgdmVkIHZla3RvcmVyIGVyLCBhdCB2aSBrYW4gbGF2ZSBiZXJlZ25pbmdlciBww6UgaGVsZSB2ZWt0b3JlbiwgZHZzLiBhbGxlIHbDpnJkaWVyLCBww6Ugw6luIGdhbmcuCmBgYHtyfQojIEZ4IGthbiB2aSBsw6ZnZ2UgMiB0aWwgaHZlciB2w6ZyZGkgaSB2ZWt0b3JlbgpteV92ZWN0b3IgKyAyCmBgYAoKVmkga2FuIG9nc8OlIGJydWdlIGZ1bmt0aW9uZXIgcMOlIGhlbGUgdmVrdG9yZW4sIGZ4OgpgYGB7cn0Kc3VtKG15X3ZlY3RvcikgIyBzdW1tZW4gYWYgdsOmcmRpZXJuZQptZWFuKG15X3ZlY3RvcikgIyBnZW5uZW1zbml0dGV0IGFmIHbDpnJkaWVybmUKbWluKG15X3ZlY3RvcikgIyBkZW4gbWluZHN0ZSB2w6ZyZGkgaSB2ZWt0b3JlbgptYXgobXlfdmVjdG9yKSAjIGRlbiBzdMO4cnN0ZSB2w6ZyZGkKcmFuZ2UobXlfdmVjdG9yKSAjIGRlbiBzdMO4cnN0ZSBvZyBtaW5kc3RlIHbDpnJkaQpgYGAKRGV0IGthbiB2w6ZyZSBicnVnYmFydCwgaHZpcyB2aSBoYXIgbWFuZ2UgdsOmcmRpZXIgaSBlbiB2ZWt0b3IgLSBmeCBldCBzdXJ2ZXlzcMO4cmdzbcOlbCBtZWQgbWFuZ2Ugc3Zhci4KCiMjIDQuIERhdGFmcmFtZXMKCk7DpXIgdmkgYXJiZWpkZXIgbWVkIHRhYnVsw6ZyZSBkYXRhIChgZGF0YSBmcmFtZXNgKSwgZXIgaHZlciBrb2xvbm5lIGVuIHZla3Rvci4KClZpIGthbiBicnVnZSBgJGAgdGlsIGF0IHVkdsOmbGdlIGVuIGJlc3RlbXQga29sb25uZSBpIGV0IGRhdGFzw6Z0dGV0LiBIdmlzIHZpIGhhciBkYXRhZnJhbWVuIGAnbXlfZGF0YSdgIG9nIHZpbCB2w6ZsZ2UgdmVrdG9yZW4gYFYxYCwgc2VyIGRldCBzw6VkYW4gaGVyIHVkOgpgYGB7ciwgZXZhbD1GQUxTRX0KbXlfZGF0YSRWMQpgYGAKClVkb3ZlciBrb2xvbm5lciBiZXN0w6VyIGRhdGFmcmFtZXMgb2dzw6UgYWYgcsOma2tlci4gVmkga2FuIGJydWdlIGBbXWAgdGlsIGF0IHVkdsOmbGdlIGJlc3RlbXRlIHLDpmtrZXIgb2cga29sb25uZXIsIGxpZ2Vzb20gbsOlciB2aSBhcmJlamRlciBtZWQgdmVrdG9yZXI6CmBgYHtyLCBldmFsPUZBTFNFfQpteV9kYXRhWzQsM10gIyBSIHZpc2VyIHLDpmtrZSA0LCBrb2xvbm5lIDMgaSB2b3JlcyBkYXRhZnJhbWUKbXlfZGF0YVs0LCBdICMgUiB2aXNlciBoZWxlIHLDpmtrZSA0IGkgdm9yZXMgZGF0YWZyYW1lCm15X2RhdGFbICwzXSAjIFIgdmlzZXIgaGVsZSBrb2xvbm5lIDMgaSB2b3JlcyBkYXRhZnJhbWUKbXlfZGF0YVssICJ2YXJpYWJlbF9uYXZuIl0gIyBSIHZpc2VyIGhlbGUga29sb25uZW4gZm9yIGVuIGdpdmVuIHZhcmlhYmVsCmBgYAoKSHVzaywgYXQgcsOma2tlZsO4bGdlbiBhbHRpZCBlciBgW3LDpmtrZSwga29sb25uZV1gLgoKIyMgNC4xIEJldGluZ2Vsc2VyClZpIGthbiBvZ3PDpSB1ZHbDpmxnZSBiZXN0ZW10ZSB2w6ZyZGllciBlbGxlciByw6Zra2VyIGkgZW4gdmVrdG9yIGVsbGVyIGRhdGFmcmFtZSBtZWQgbG9naXNrZSBiZXRpbmdlbHNlci4KYGBge3J9CiMgS29kZW4gdmlsIGZ4IGt1biBnaXZlIG9zIGRlIHbDpnJkaWVyIGkgdmVrdG9yZW4sIGh2b3IgYmV0aW5nZWxzZW4gZXIgYFRSVUVgLiBEdnMuIGF0IFIgaGVyIGt1biBiZWhvbGRlciBkZSB2w6ZyZGllciBpIHZla29yZW4sIGRlciBlciBtaW5kcmUgZW5kIDI1OgpteV92ZWN0b3JbbXlfdmVjdG9yIDwgMjVdCmBgYAoKYGBge3IsIGV2YWw9RkFMU0V9CiMgVmkga2FuIGfDuHJlIGRldCBzYW1tZSBww6UgZGF0YWZyYW1lcy4gSGVyIGJlaG9sZGVyIFIga3VuIGRlIHbDpnJkaWVyIGkgZGF0YWZyYW1lbiwgZGVyIGVyIG1pbmRyZSBlbmQgNzA6Cm15X2RhdGFbbXlfZGF0YSR2YXJpYWJlbF9uYXZuIDwgNzAsIF0KYGBgCiMjIDUuIGB0aWR5dmVyc2VgCgpSIGVyIGV0IG9wZW4tc291cmNlIHByb2dyYW0sIG9nIHZpIGJydWdlciBkZXJmb3IgYWxsZSBtdWxpZ2UgcGFra2VyIGxhdmV0IGFmIGFuZHJlIGJydWdlcmUsIG7DpXIgdmkga29kZXIuCgpgdGlkeXZlcnNlYCBlciBlbiBzYW1saW5nIGFmIHBha2tlciwgZGVyIGRlbGVyIOKAnGtvZGVmaWxvc29maeKAnSwgc29tIGfDuHIgZGV0IGxldHRlcmUgYXQgYnJ1Z2UgZGVtIHNhbW1lbi4gUGFra2VybmUgZ8O4ciBkZXQgbWVyZSBvdmVyc2t1ZWxpZ3QgYXQgYXJiZWpkZSBkYXRhLgoKIyMjIyBQaXBlcyBgJT4lYApOw6VyIG1hbiBza3JpdmVyIGtvZGUgaSBSLCBlciBkZXQgbWVnZXQgYWxtaW5kZWxpZ3QgYXQgYnJ1Z2UgYmFidXNoa2Etc3RydWt0dXIgbWVkIHBhcmVudGVzZXIgaSBwYXJlbnRlc2VyLiBEZXQga2FsZGVyIG1hbiAnbmVzdGluZycgb2cga2FuIGh1cnRpZ3QgYmxpdmUgdW92ZXJza3VlbGlndC4KClBpcGVzIGdpdmVyIG9zIG11bGlnaGVkIGZvciBhdCBza3JpdmUgbWVyZSBsZXRsw6ZzZWxpZyBrb2RlIHZlZCBhdCBzw6Z0dGUgZmxlcmUgdHJpbiBhZiBrb2RlIHNhbW1lbiBpIGVuIHLDpmtrZWbDuGxnZSwgZGVyIGVyIGxldHRlcmUgYXQgbMOmc2UuCgpgYGB7cn0KIyBFa3NlbXBlbCBww6UgJ25lc3RlZCcga29kZSBpIGJhYnVzaGthLXN0cnVrdHVyIG1lZCBwYXJlbnRlc2VyIGkgcGFyZW50ZXNlcjoKc3FydChhYnMoc3VtKGMoLTEsLTIsLTMpKSkpCmBgYAoKYGBge3J9CiMgU2FtbWUga29kZSBtZWQgcGlwZS1mdW5rdGlvbmVuOgpjKC0xLCAtMiwgLTMpICU+JSBzdW0oKSAlPiUgYWJzKCkgJT4lIHNxcnQoKQpgYGAKCkhlbHQga29ydCBrYW4gcGlwZXMgZm9yc3TDpXMgc29tIGV0ICJhbmQgdGhlbi4uLiI7IGFsdHPDpSAib2cgc8OlIGfDuHIgdmkgc8OlZGFuIGhlci4uLiBvZyBzw6UgZ8O4ciB2aSBzw6VkYW4gaGVyLi4uIgoKYGBge3J9CiMgTWFuIGthbiBvZ3PDpSBsYXZlIGxpbmplc2tpZnQgZm9yIGF0IGfDuHJlIGtvZGVuIGVuZG51IG1lcmUgbGV0bMOmc2VsaWc6CmMoLTEsLTIsLTMpICU+JQpzdW0oKSAlPiUKYWJzKCkgJT4lCnNxcnQoKQpgYGAKClBpcGVzIHRhZ2VyIGFsdHPDpSBldCBvYmpla3QgZWxsZXIgZXQgb3V0cHV0IHDDpSB2ZW5zdHJlIHNpZGUgb2cg4oCccGlwZXLigJ0gZGV0IHZpZGVyZSBzb20gZXQgYXJndW1lbnQgdGlsIGVuIGZ1bmt0aW9uIHDDpSBow7hqcmUgc2lkZSBhZiBwaXBlbi4KCiMjIyMgYGZpbHRlcigpYApGdW5rdGlvbmVuIGBmaWx0ZXIoKWAgZnJhIHRpZHl2ZXJzZSBnw7hyIGRldCBtdWxpZ3QgYXQgdWR2w6ZsZ2UgcsOma2tlciBpIGV0IGRhdGFzw6Z0LCBkZXIgb3BmeWxkZXIgZW4gYmVzdGVtdCBiZXRpbmdlbHNlLiBWaSBrYW4gYWx0c8OlIGJydWdlIGBmaWx0ZXIoKWAgdGlsIGt1biBhdCBzZSBvYnNlcnZhdGlvbmVyLCBkZXIgZXIgcmVsZXZhbnRlIGZvciBvcy4KYGBge3IsIGV2YWw9RkFMU0V9CiMgSGVyIGJlaG9sZGVyIFIga3VuIGRlIHLDpmtrZXIsIGh2b3IgdsOmcmRpZXJuZSBhZiBgdmFyaWFiZWxgIGVyIHN0w7hycmUgZW5kIDcwOgpteV9kYXRhICU+JQpmaWx0ZXIodmFyaWFiZWwgPiA3MCkKYGBgCgojIyMjIGBwdWxsKClgCkZ1bmt0aW9uZW4gYHB1bGwoKWAgaGVudGVyIGVuIGJlc3RlbXQga29sb25uZSB1ZCBhZiBldCBkYXRhc8OmdCBvZyBnaXZlciBvcyBlbiB2ZWt0b3IgbWVkIHbDpnJkaWVybmUgZnJhIGtvbG9ubmVuLgpgYGB7ciwgZXZhbD1GQUxTRX0KIyBIZXIgaGVudGVyIFIgYWxsZSB2w6ZyZGllcm5lIGZyYSBrb2xvbm5lbiBgdmFyaWFiZWxgLgpteV9kYXRhICU+JQpwdWxsKHZhcmlhYmVsKQpgYGAKCiMjIyMgYGhlYWQoKWAKRnVua3Rpb25lbiBgaGVhZCgpYCBicnVnZXMgdGlsIGh1cnRpZ3QgYXQgZsOlIGV0IG92ZXJibGlrIG92ZXIgZXQgZGF0YXPDpnQgdmVkIGF0IHZpc2UgZGUgZsO4cnN0ZSByw6Zra2VyLiBEZXQgZXIgaXPDpnIgbnl0dGlndCwgbsOlciBtYW4gbGlnZSBoYXIgaW1wb3J0ZXJldCBldCBkYXRhc8OmdCBvZyB2aWwgc2UsIGh2b3JkYW4gZGF0YSBzZXIgdWQuCmBgYHtyLCBldmFsPUZBTFNFfQpteV9kYXRhICU+JQpoZWFkKCkKYGBgCgojIyMjIGBzdW1tYXJpemUoKWAKRnVua3Rpb25lbiBgc3VtbWFyaXplKClgIGJydWdlcyB0aWwgYXQgbGF2ZSBiZXJlZ25pbmdlciwgZGVyIG9wc3VtbWVyZXIgZGF0YS4gRGV0IGthbiBmeCB2w6ZyZSBldCBnZW5uZW1zbml0LCBtaW5pbXVtIGVsbGVyIG1ha3NpbXVtIGFmIHbDpnJkaWVybmUgaSB2b3JlcyBkYXRhc8OmdC4KYGBge3IsIGV2YWw9RkFMU0V9Cm15X2RhdGEgJT4lCnN1bW1hcml6ZSgpCmBgYA==