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)
head()
Funktionen head() bruges til hurtigt at få et overblik
over et datasæt ved at vise de første rækker. Det er især nyttigt, når
man lige har importeret et datasæt og vil se, hvordan data ser ud.
my_data %>%
head()
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==