1. Script eller Notebook?
I vælger selv, om I vil arbejde i scripts eller Notebook-filer, når I
koder i R.
Scripts hedder filnavn.R og Notebooks hedder
filnavn.Rmd, som står for R Markdown.
Forskellen på de to er, at scripts som udgangspunkt antager, at man
skriver kode, imens Notebook antager, at man skriver tekst, hvis ikke
man angiver noget andet.
Derfor bruger vi # i scripts til at skrive noter, imens
vi bruger ‘chunks’ i Notebook til at skrive felter med kode. Chunks er
angivet med {r}
# Det her er et chunk
Tastaturgenvejen til at lave chunks er Ctrl +
Alt + I på Windows og Cmd +
Option + I på Mac.
Det smarte ved Notebooks er, at vi kan få vist vores output under
koden, imens scripts kun viser outputtet i Consolen. Derudover laver
Notebooks automatisk en html.fil, så man kan dele sin kode med andre,
uden at de skal åbne R. Det her er fx en html-fil fra en Notebook :)
Til gengæld er scripts mere simple og kan derfor virke mere
overskuelige at bruge, især hvis man skal lave mange beregninger.
2. Hvad kan vi arbejde med i R?
2.1 Beregninger og tekst
R kan bruge matematiske tegn til at lave beregninger. Vi kan køre
koden med tastaturgenvejen Ctrl + Enter på
Windows eller Cmd + Enter på Mac.
5+5
[1] 10
Vi kan også bruge R til at skrive tekst:
"Jeg elsker Survey Design"
[1] "Jeg elsker Survey Design"
2.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
2.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. Tastaturgenvejen er Alt +
- på Windows eller Option + -
Når man gemmer værdier, kan man bruge dem igen senere. De objekter,
vi har gemt, kan vi se i vores Environment.
Vi kan fx gemme beregningen fra tidligere.
# Her beregner R `5 + 5` og gemmer resultatet `10` i objektet `my_number`
my_number <- 5+5
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.
3. Funktioner, pakker og argumenter
3.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 funktion(). Det,
vi skriver inde i parentesen, er inputtet til funktionen.
3.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.
3.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.
3.4 Pacman
Vi kan bruge pakken pacman til at installere og indlæse
pakker på samme tid med funktionen p_load. Det kræver, at
vi først har installeret pacman.
p_load svarer altså til at køre
install_packages() og library() i én
kommando.
pacman::p_load("cowsay")
3.5 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" "R notebook eksempel.nb.html" "R notebook eksempel.Rmd" "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
vi arbejder fra. 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
hunt_01_Trash_Metal, kan vi vise indholdet af hunt_01_Trash_Metal ved at
skrive:
dir("../")
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.
3.6 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
4. Vektorer
4.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)
my_vector
[1] 1 29 13 2
# og tekst
my_text_vector <- c("Apple", "Banana", "Pear")
my_text_vector
[1] "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
4.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.
5. Dataframes
Når vi skal indlæse data, kan vi bruge forskellige funktioner
afhængigt af, hvilken type fil vores datasæt er. Fx kan
read_csv() bruges til at indlæse .csv-filer, imens
read_excel() lader os indlæse en Excel-fil.
# Vi bruger assignment operatoren `<-` til at gemme det importerede datasæt i et objekt
my_data <- read.csv("navn_på_datasæt.csv")
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].
5.1 Betingelser
Vi kan også udvælge bestemte værdier eller rækker i en vektor eller
dataframe med logiske betingelser.
Koden vil kun give os de værdier i vektoren, hvor betingelsen er
TRUE.
# 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]
[1] 1 13 2
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, ]
6. 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, hvilket hurtigt kan blive
uoverskueligt. Det kalder man ‘nesting’.
# Eksempel på 'nested' kode i babushka-struktur med parenteser i parenteser:
sqrt(abs(sum(c(-1,-2,-3))))
[1] 2.44949
Pipes (%>%) giver os mulighed for at skrive kode mere
effektivt ved at sætte flere trin af kode sammen i en letlæselig
rækkefølge. Helt kort kan hver pipe forstås som et “and then…” eller “og
så gør vi sådan her… og så gør vi sådan her…”.
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.
# Samme kode med pipe-funktionen:
c(-1, -2, -3) %>% sum() %>% abs() %>% sqrt()
[1] 2.44949
Tastaturgenvejen til at lave en %>% er Ctrl +
Shift + M på Windows og Cmd +
Shift + M på Mac.
# Man kan også lave linjeskift for at gøre koden endnu mere letlæselig:
c(-1,-2,-3) %>%
sum() %>%
abs() %>%
sqrt()
[1] 2.44949
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_navn` er større end 70:
my_data %>%
filter(variabel_navn > 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_navn`.
my_data %>%
pull(variabel_navn)
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()
LS0tCnRpdGxlOiAiU3VydmV5IERlc2lnbiBGdW5rdGlvbnNvdmVyc2lndCIKYXV0aG9yOiAiSnVsaWFuZSBTdGFyY2tlIE5lZXJnYWFyZCIKZGF0ZTogIjIwMjYtMTAtMDEiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMgMS4gU2NyaXB0IGVsbGVyIE5vdGVib29rPwpJIHbDpmxnZXIgc2Vsdiwgb20gSSB2aWwgYXJiZWpkZSBpIHNjcmlwdHMgZWxsZXIgTm90ZWJvb2stZmlsZXIsIG7DpXIgSSBrb2RlciBpIFIuIAoKU2NyaXB0cyBoZWRkZXIgKmZpbG5hdm4uUiogb2cgTm90ZWJvb2tzIGhlZGRlciAqZmlsbmF2bi5SbWQqLCBzb20gc3TDpXIgZm9yIFIgTWFya2Rvd24uCgpGb3Jza2VsbGVuIHDDpSBkZSB0byBlciwgYXQgc2NyaXB0cyBzb20gdWRnYW5nc3B1bmt0IGFudGFnZXIsIGF0IG1hbiBza3JpdmVyIGtvZGUsIGltZW5zIE5vdGVib29rIGFudGFnZXIsIGF0IG1hbiBza3JpdmVyIHRla3N0LCBodmlzIGlra2UgbWFuIGFuZ2l2ZXIgbm9nZXQgYW5kZXQuIAoKRGVyZm9yIGJydWdlciB2aSBgI2AgaSBzY3JpcHRzIHRpbCBhdCBza3JpdmUgbm90ZXIsIGltZW5zIHZpIGJydWdlciAnY2h1bmtzJyBpIE5vdGVib29rIHRpbCBhdCBza3JpdmUgZmVsdGVyIG1lZCBrb2RlLiBDaHVua3MgZXIgYW5naXZldCBtZWQgYGBge3J9IGBgYAoKYGBge3J9CiMgRGV0IGhlciBlciBldCBjaHVuawpgYGAKClRhc3RhdHVyZ2VudmVqZW4gdGlsIGF0IGxhdmUgY2h1bmtzIGVyIGBDdHJsYCArIGBBbHRgICsgYElgIHDDpSBXaW5kb3dzIG9nIGBDbWRgICsgYE9wdGlvbmAgKyBgSWAgcMOlIE1hYy4gCgpEZXQgc21hcnRlIHZlZCBOb3RlYm9va3MgZXIsIGF0IHZpIGthbiBmw6UgdmlzdCB2b3JlcyBvdXRwdXQgdW5kZXIga29kZW4sIGltZW5zIHNjcmlwdHMga3VuIHZpc2VyIG91dHB1dHRldCBpIENvbnNvbGVuLiBEZXJ1ZG92ZXIgbGF2ZXIgTm90ZWJvb2tzIGF1dG9tYXRpc2sgZW4gaHRtbC5maWwsIHPDpSBtYW4ga2FuIGRlbGUgc2luIGtvZGUgbWVkIGFuZHJlLCB1ZGVuIGF0IGRlIHNrYWwgw6VibmUgUi4gRGV0IGhlciBlciBmeCBlbiBodG1sLWZpbCBmcmEgZW4gTm90ZWJvb2sgOikKClRpbCBnZW5nw6ZsZCBlciBzY3JpcHRzIG1lcmUgc2ltcGxlIG9nIGthbiBkZXJmb3Igdmlya2UgbWVyZSBvdmVyc2t1ZWxpZ2UgYXQgYnJ1Z2UsIGlzw6ZyIGh2aXMgbWFuIHNrYWwgbGF2ZSBtYW5nZSBiZXJlZ25pbmdlci4KCiMjIDIuIEh2YWQga2FuIHZpIGFyYmVqZGUgbWVkIGkgUj8KIyMjIDIuMSBCZXJlZ25pbmdlciBvZyB0ZWtzdApSIGthbiBicnVnZSBtYXRlbWF0aXNrZSB0ZWduIHRpbCBhdCBsYXZlIGJlcmVnbmluZ2VyLiBWaSBrYW4ga8O4cmUga29kZW4gbWVkIHRhc3RhdHVyZ2VudmVqZW4gYEN0cmxgICsgYEVudGVyYCBww6UgV2luZG93cyBlbGxlciBgQ21kYCArIGBFbnRlcmAgcMOlIE1hYy4gCmBgYHtyfQo1KzUKYGBgClZpIGthbiBvZ3PDpSBicnVnZSBSIHRpbCBhdCBza3JpdmUgdGVrc3Q6CmBgYHtyfQoiSmVnIGVsc2tlciBTdXJ2ZXkgRGVzaWduIgpgYGAKIyMjIDIuMiBMb2dpc2tlIHRlZ24KUiBrYW4gb2dzw6UgYnJ1Z2UgbG9naXNrZSB0ZWduIHRpbCBhdCBmb3J0w6ZsbGUsIG9tIG5vZ2V0IGVyIGBUUlVFYCAoc2FuZHQpIGVsbGVyIGBGQUxTRWAgKGZhbHNrKS4KCmA8YCBvZyBgPmAgc2FtbWVubGlnbmVyIHRhbAoKYD09YCB1bmRlcnPDuGdlciwgb20gdG8gdsOmcmRpZXIgZXIgZW5zCgpgPD1gIGJldHlkZXIgbWluZHJlIGVuZCBlbGxlciBsaWcgbWVkCgpgPj1gIGJldHlkZXIgc3TDuHJyZSBlbmQgZWxsZXIgbGlnIG1lZAoKYCE9YCBiZXR5ZGVyIGlra2UgbGlnZSBtZWQKCmBgYHtyfQojIEVyIDQgZnggc3TDuHJyZSBlbmQgMz8KNCA+IDMKYGBgCmBgYHtyfQojIE9nIGVyIDUgZGV0IHNhbW1lIHNvbSA0Pwo1ID09IDQKYGBgCgojIyMgMi4zIEdlbW1lIG9nIGJydWdlIG9iamVrdGVyCkVuIHZpZ3RpZyBmb3Jza2VsIG1lbGxlbSBSIG9nIGVuIGFsbWluZGVsaWcgbG9tbWVyZWduZXIgZXIsIGF0IFIga2FuIGdlbW1lIHbDpnJkaWVyLgoKRGV0IGfDuHIgdmkgbWVkIGFzc2lnbm1lbnQgb3BlcmF0b3JlbiBgPC1gLCBkZXIgJ2Fzc2lnbmVyJyB2w6ZyZGllciB0aWwgZXQgb2JqZWt0LiBUYXN0YXR1cmdlbnZlamVuIGVyIGBBbHRgICsgYC1gIHDDpSBXaW5kb3dzIGVsbGVyIGBPcHRpb25gICsgYC1gCgpOw6VyIG1hbiBnZW1tZXIgdsOmcmRpZXIsIGthbiBtYW4gYnJ1Z2UgZGVtIGlnZW4gc2VuZXJlLiBEZSBvYmpla3RlciwgdmkgaGFyIGdlbXQsIGthbiB2aSBzZSBpIHZvcmVzIEVudmlyb25tZW50LgoKVmkga2FuIGZ4IGdlbW1lIGJlcmVnbmluZ2VuIGZyYSB0aWRsaWdlcmUuIApgYGB7cn0KIyBIZXIgYmVyZWduZXIgUiA1ICsgNSBvZyBnZW1tZXIgcmVzdWx0YXRldCAxMCBpIG9iamVrdGV0IG15X251bWJlcgpteV9udW1iZXIgPC0gNSs1Cm15X251bWJlcgpgYGAKClZpIGthbiBvZ3PDpSBnZW1tZSB0ZWtzdCBzb20gZXQgb2JqZWt0OgoKYGBge3J9Cm15X3RleHQgPC0gIkhlciBrYW4gZHUgc2tyaXZlIGh2YWQgc29tIGhlbHN0ISIKbXlfdGV4dApgYGAKVmkga2FuIGJydWdlIGdlbXRlIG9iamVrdGVyIGkgbnllIGJlcmVnbmluZ2VyOgpgYGB7cn0KbXlfc2Vjb25kX251bWJlciA8LSBteV9udW1iZXIgKyAzCm15X3NlY29uZF9udW1iZXIKYGBgCgpgYGB7cn0KbXlfdGhpcmRfbnVtYmVyIDwtIG15X3NlY29uZF9udW1iZXIgLSBteV9udW1iZXIKbXlfdGhpcmRfbnVtYmVyCmBgYAoKYG15X251bWJlcmAgZ2VtbWVyIHRhbGxldCAxMAoKYG15X3NlY29uZF9udW1iZXJgIGdlbW1lciB0YWxsZXQgMTMgYCgxMCArIDMpYAoKYG15X3RoaXJkX251bWJlcmAgZXIgZGVyZm9yIGAxMyAtIDEwID0gM2AKCktvcnQgc2FndDogdmkgYnJ1Z2VyIG9iamVrdGVyIHRpbCBhdCBnZW1tZSB2w6ZyZGllciB1bmRlciBldCBuYXZuLCBzw6Ugdmkga2FuIGJydWdlIGRlbiBpZ2VuIHNlbmVyZS4KCiMjIDMuIEZ1bmt0aW9uZXIsIHBha2tlciBvZyBhcmd1bWVudGVyCgojIyMgMy4xIEZ1bmt0aW9uZXIKRnVua3Rpb25lciBlciBrb21tYW5kb2VyIGkgUiwgZGVyIHVkZsO4cmVyIGVuIGJlc3RlbXQgaGFuZGxpbmcuIEZvcnNrZWxsaWdlIGZ1bmt0aW9uZXIga2FuIGJydWdlcyB0aWwgZm9yc2tlbGxpZ2UgdGluZy4KCmBgYHtyfQojIFZpIGthbiBmeCBicnVnZSBmdW5rdGlvbmVuIHNxcnQoKSB0aWwgYXQgZmluZGUga3ZhZHJhdHJvZGVuIGFmIGVuIHbDpnJkaToKc3FydCg1KzUpCmBgYAoKRnVua3Rpb25lciBza3JpdmVzIGFsdGlkIG1lZCBwYXJlbnRlc2VyIGBmdW5rdGlvbigpYC4gRGV0LCB2aSBza3JpdmVyIGluZGUgaSBwYXJlbnRlc2VuLCBlciBpbnB1dHRldCB0aWwgZnVua3Rpb25lbi4KCiMjIyAzLjIgQXJndW1lbnRlcgpNYW5nZSBmdW5rdGlvbmVyIGthbiB0aWxwYXNzZXMgdmVkIGhqw6ZscCBhZiBhcmd1bWVudGVyLgoKQXJndW1lbnRlciBmb3J0w6ZsbGVyIGZ1bmt0aW9uZW4sIGh2b3JkYW4gZGVuIHNrYWwgdWRmw7hyZSBzaW4gb3BnYXZlIG9nIGh2YWQgZGVuIHNrYWwgYXJiZWpkZSBtZWQuCgpWaSBrYW4gZnggYnJ1Z2UgcGFra2VuIGBjb3dzYXlgIHRpbCBhdCBmw6UgZm9yc2tlbGxpZ2UgZHlyIHRpbCBhdCBzaWdlIG5vZ2V0IG1lZCBmdW5rdGlvbmVuIGBzYXlgOiAKYGBge3IsIGV2YWw9RkFMU0V9CnNheSh3aGF0ID0gIkplZyBlbHNrZXIgYXQga29kZSBpIFIiLApieSA9ICJjYXQiKQpgYGAKSGVyIGVyIGB3aGF0YCBvZyBgYnlgIGFyZ3VtZW50ZXI6Cgpgd2hhdGAgYmVzdGVtbWVyLCBodmFkIGRlciBza2FsIHNpZ2VzLgoKYGJ5YCBiZXN0ZW1tZXIsIGh2ZW0gZGVyIHNrYWwgc2lnZSBkZXQuCgpWaSBrYW4gb2dzw6UgYnJ1Z2Ugb2JqZWt0ZXIsIHZpIGFsbGVyZWRlIGhhciBnZW10LCBzb20gaW5wdXQgaSBldCBhcmd1bWVudCwgZnggb2JqZWt0ZXQgYG15X3RleHRgIGZyYSB0aWRsaWdlcmU6CmBgYHtyLCBldmFsPUZBTFNFfQpzYXkod2hhdCA9IG15X3RleHQsCmJ5ID0gImZpc2giKQpgYGAKCiMjIyMgYGhlbHAoKWAgb2cgYD9gCgpWaSBrYW4gdW5kZXJzw7hnZSBlbiBmdW5rdGlvbiBtZWQgYD9gLCBodmlzIHZpIGVyIGkgdHZpdmwgb20sIGh2aWxrZSBhcmd1bWVudGVyIGZ1bmt0aW9uZW4gaGFyIGVsbGVyIGh2YWQgZGUgZm9yc2tlbGxpZ2UgYXJndW1lbnRlciBnw7hyLgoKRngga2FuIHZpIHNrcml2ZSBgP3NheWAgb2cgZsOlIGluZm9ybWF0aW9uZXIgb20sIGh2YWQgdmkga2FuIHNrcml2ZSBhZiBpbnB1dCBpIGZ1bmt0aW9uZW4uCgojIyMgMy4zIFBha2tlcgpSIGluZGVob2xkZXIgbWFuZ2UgZnVua3Rpb25lciBpIHNpZyBzZWx2LCBtZW4gbWFuIGthbiBmw6UgYWRnYW5nIHRpbCBmbGVyZSBmdW5rdGlvbmVyIHZlZCBhdCBpbnN0YWxsZXJlIG9nIGxvYWRlIHBha2tlci4KCkVuIHBha2tlIGVyIGVuIHNhbWxpbmcgYWYgZnVua3Rpb25lciBvZyBhbmRldCBpbmRob2xkLCBzb20gYW5kcmUgUi1icnVnZXJlIGhhciBsYXZldC4KCkh2aXMgdmkgc2thbCBicnVnZSBwYWtrZW4gYGNvd3NheWAsIHNrYWwgdmkgZsO4cnN0IGluc3RhbGxlcmUgZGVuIG1lZCBmdW5rdGlvbmVuIGBpbnN0YWxsLnBhY2thZ2VzKClgOgoKYGBge3IsIGV2YWw9RkFMU0V9Cmluc3RhbGwucGFja2FnZXMoImNvd3NheSIpCmBgYAoKTsOlciBwYWtrZW4gZXIgaW5zdGFsbGVyZXQsIHNrYWwgZGVuIGluZGzDpnNlcyBtZWQgZnVua3Rpb25lbiBgbGlicmFyeSgpYCwgZsO4ciB2aSBrYW4gYnJ1Z2UgZGVucyBmdW5rdGlvbmVyOgpgYGB7ciwgZXZhbD1GQUxTRX0KbGlicmFyeShjb3dzYXkpCmBgYAoKVmkgYmVow7h2ZXIga3VuIGF0IGluc3RhbGxlcmUgcGFra2VyIMOpbiBnYW5nLCBtZW4gdmkgc2thbCBicnVnZSBgbGlicmFyeSgpYCB0aWwgYXQgaW5kbMOmc2UgZGVtIGh2ZXIgZ2FuZywgdmkgc3RhcnRlciBlbiBueSBSLXNlc3Npb24uCgojIyMgMy40IFBhY21hbgoKVmkga2FuIGJydWdlIHBha2tlbiBgcGFjbWFuYCB0aWwgYXQgaW5zdGFsbGVyZSBvZyBpbmRsw6ZzZSBwYWtrZXIgcMOlIHNhbW1lIHRpZCBtZWQgZnVua3Rpb25lbiBgcF9sb2FkYC4gRGV0IGtyw6Z2ZXIsIGF0IHZpIGbDuHJzdCBoYXIgaW5zdGFsbGVyZXQgYHBhY21hbmAuCgpgcF9sb2FkYCBzdmFyZXIgYWx0c8OlIHRpbCBhdCBrw7hyZSBgaW5zdGFsbF9wYWNrYWdlcygpYCBvZyBgbGlicmFyeSgpYCBpIMOpbiBrb21tYW5kby4KCmBgYHtyfQpwYWNtYW46OnBfbG9hZCgiY293c2F5IikKYGBgCgojIyMgMy41IE1hcHBlciBvZyBmaWxzdGllcgoKTsOlciB2aSBhcmJlamRlciBtZWQgZGF0YSBpIFIsIHNrYWwgdmkgb2Z0ZSBmb3J0w6ZsbGUgUiwgaHZvciBlbiBmaWwgbGlnZ2VyLiBEZXQgZ8O4ciB2aSBtZWQgZmlsc3RpZXIgKGZpbGUgcGFodHMpLiBFbiBmaWxzdGkgZm9ydMOmbGxlciBSLCBodm9yIGRlbiBza2FsIGxlZGUgZWZ0ZXIgZW4gYmVzdGVtdCBmaWwgZWxsZXIgbWFwcGUuCgojIyMjIGBkaXIoKWAKCkZ1bmt0aW9uZW4gYGRpcigpYCBrYW4gYnJ1Z2VzIHRpbCBhdCBzZSBpbmRob2xkZXQgYWYgZGVuIG1hcHBlLCB2aSBhcmJlamRlciBmcmEuCgpgYGB7cn0KIyBGeCBrYW4gdmkgYnJ1Z2UgZGlyKCkgdGlsIGF0IHNlLCBodmFkIGRlciBsaWdnZXIgaSBkZW4gbWFwcGUsIHZpIGJlZmluZGVyIG9zIGk6CmRpcigiVVYxIikKYGBgCgpgYGB7cn0KIyBFbGxlciBpIGVuIGFuZGVuIHZpbGvDpXJsaWcgbWFwcGUsIHZpIGdlcm5lIHZpbCB1bmRlcnPDuGdlOgpkaXIoIlVWMS9FeGVyY2lzZSAxIikKYGBgCgojIyMjIGBnZXR3ZCgpYAoKRnVua3Rpb25lbiBgZ2V0d2QoKWAga2FuIGJydWdlcyB0aWwgYXQgc2UsIGh2aWxrZW4gbWFwcGUgdmkgYXJiZWpkZXIgZnJhLiBEZXQgZXIgaGVyLCBSIHN0YXJ0ZXIsIG7DpXIgdmkgYnJ1Z2VyIHJlbGF0aXZlIGZpbHN0aWVyLgoKRW4gcmVsYXRpdiBmaWxzdGkgYmVza3JpdmVyLCBodm9yIGVuIGZpbCBlbGxlciBtYXBwZSBsaWdnZSBpIGZvcmhvbGQgdGlsIGRlbiBtYXBwZSwgUiBhcmJlamRlciB1ZCBmcmEuCgpIdmlzIHZvcmVzIHdvcmtpbmcgZGlyZWN0b3J5IGVyIGBodW50XzAxX1RyYXNoX01ldGFsYCwgb2cgZGVyIGkgZGVuIG1hcHBlIGxpZ2dlciB1bmRlcm1hcHBlbiBgT3ZlcmtpbGxgLCBodm9yaSBmaWxlbiBgRWxpbWluYXRpb24uY3N2YCBsaWdnZXIsIHZpbCBkZW4gcmVsYXRpdmUgZmlsc3RpIHRpbCBgRWxpbWluYXRpb24uY3N2YCB2w6ZyZToKCmBgYHtyLCBldmFsPUZBTFNFfQoiT3ZlcmtpbGwvRWxpbWluYXRpb24uY3N2IgpgYGAKCiMjIyMgYC4uL2Agb2cgYC4uLy4uL2AKCk7DpXIgdmkgYXJiZWpkZXIgbWVkIHJlbGF0aXZlIGZpbHN0aWVyLCBrYW4gdmkgYnJ1Z2UgYC4uYCB0aWwgYXQgdmlzZSBpbmRob2xkZXQgYWYgZW4gbWFwcGUsIGRlciBsaWdnZXIgZXQgbGVkIHVkZSBpIHZvcmVzIHN0aS4gRHZzLiB2aSBiZWRlciBSIG9tIGF0IGfDpSB1ZCBhZiBkZW4gbnV2w6ZyZW5kZSBtYXBwZSBvZyBlbiBtYXBwZSB0aWxiYWdlLgoKSHZpcyB2aSBiZWZpbmRlciBvcyBpIG1hcHBlbiBPdmVya2lsbCwgZGVyIGxpZ2dlciBpIGh1bnRfMDFfVHJhc2hfTWV0YWwsIGthbiB2aSB2aXNlIGluZGhvbGRldCBhZiBodW50XzAxX1RyYXNoX01ldGFsIHZlZCBhdCBza3JpdmU6CgpgYGB7ciwgZXZhbD1GQUxTRX0KZGlyKCIuLi8iKQpgYGAKCkh2aXMgdmkgdmlsIGfDpSB1ZCBhZiB0byBtYXBwZXIsIGthbiB2aSBza3JpdmUgYGRpcigiLi4vLi4vIilgLiBTw6UgYmVkZXIgdmkgUiBvbSBhdCBnw6UgdWQgYWYgZGVuIG51dsOmcmVuZGUgbWFwcGUgb2cgZGVyZWZ0ZXIgdWQgYWYgZGVuIG7DpnN0ZSAtIGFsdHPDpSB0byBtYXBwZXIgdGlsYmFnZSBpIHN0aWVuLgoKIyMjIDMuNiBPcHN1bW1lcmluZwoKYGRpcigpYCB2aXNlciBpbmRob2xkZXQgYWYgZW4gbWFwcGUKCmBkaXIoIi4uLyIpYCB2aXNlciwgaHZhZCBkZXIgbGlnZ2VyIGkgbWFwcGVuIHVkZW4gZm9yIHZvcmVzIHByb2pla3RtYXBwZQoKYGRpcigiLi4vLi4vIilgIHZpc2VyLCBodmFkIGRlciBsaWdnZXIgdG8gbWFwcGVyIHVkZQoKYGdldHdkKClgIHZpc2VyLCBodm9yIHZvcmVzIHJlbGF0aXZlIGZpbHN0aSBzdGFydGVyIChkdnMuIHZvcmVzIG51dsOmcmVuZGUgd29ya2luZyBkaXJlY3RvcnkpCgpgaGVscCgpYCBvZyBgP2Agw6VibmVyIGRva3VtZW50YXRpb25lbiBmb3IgZW4gZnVua3Rpb24KCmBpbnN0YWxsLnBhY2thZ2VzYCBpbnN0YWxsZXJlciBlbiBwYWtrZQoKYGxpYnJhcnkoKWAgaW5kbMOmc2VyIGVuIGluc3RhbGxlcmV0IHBha2tlCgojIyA0LiBWZWt0b3JlcgojIyMgNC4xIEh2YWQgZXIgZW4gdmVrdG9yPwpFbiB2ZWt0b3IgZXIgZXQgb2JqZWt0LCBkZXIgaW5kZWhvbGRlciBmbGVyZSB2w6ZyZGllciBpIGVuIGJlc3RlbXQgcsOma2tlZsO4bGdlLiBEZXQga2FuIHbDpnJlIHRhbCwgdGVrc3QgZWxsZXIgbG9naXNrZSB2w6ZyZGllci4gRHZzLiB2ZWt0b3JlciBlciBlbiBtw6VkZSBhdCBnZW1tZSBsaXN0ZXIgYWYgdsOmcmRpZXIgaSBSLiBOw6VyIHZpIGFyYmVqZGVyIG1lZCB2YXJpYWJsZSBpIGV0IGRhdGFzw6Z0LCBlciBlbiB2YXJpYWJlbCBkZXQgc2FtbWUgc29tIGVuIHZla3Rvci4KClZpIGxhdmVyIHZla3RvcmVyIG1lZCBjb21iaW5lLWZ1bmt0aW9uZW4gYGMoKWA6CmBgYHtyfQojIFZla3RvcmVyIGthbiBpbmRlaG9sZGUgdGFsCm15X3ZlY3RvciA8LSBjKDEsIDI5LCAxMywgMikKbXlfdmVjdG9yCgojIG9nIHRla3N0Cm15X3RleHRfdmVjdG9yIDwtIGMoIkFwcGxlIiwgIkJhbmFuYSIsICJQZWFyIikKbXlfdGV4dF92ZWN0b3IKYGBgCgpIdmVyIHbDpnJkaSBpIGVuIHZla3RvciBoYXIgZW4gYmVzdGVtdCBwb3NpdGlvbi4gRHZzLiByw6Zra2Vmw7hsZ2VuIGFmIHbDpnJkaWVyIGkgZW4gdmVrdG9yIGFsdGlkIGVyIGRlbiBzYW1tZSAtIG5yLiAxLCAyLCAzIG9zdi4uLgoKVmkga2FuIHVkdsOmbGdlIGJlc3RlbXRlIHbDpnJkaWVyIGZyYSBlbiB2ZWt0b3IgbWVkIGBbXWAgb2cgYDpgIHRpbCBhdCB2w6ZsZ2UgZXQgaW50ZXJ2YWwgYWYgdsOmcmRpZXIgaSB2ZWt0b3JlbjoKYGBge3J9Cm15X3ZlY3RvclsxXSAjIGdpdmVyIG9zIGRlbiBmw7hyc3RlIHbDpnJkaSBpIHLDpmtrZW4KbXlfdmVjdG9yWzJdICMgZ2l2ZXIgb3MgZGVuIGFuZGVuIHbDpnJkaSBpIHLDpmtrZW4KbXlfdmVjdG9yWzE6M10gIyBnaXZlciBvcyBmw7hyc3RlIHRpbCB0cmVkamUgdsOmcmRpIGkgdmVrdG9yZW4KYGBgCiMjIyA0LjIgQmVyZWduaW5nZXIgbWVkIHZla3RvcmVyCkVuIGFmIGZvcmRlbGVuZSB2ZWQgdmVrdG9yZXIgZXIsIGF0IHZpIGthbiBsYXZlIGJlcmVnbmluZ2VyIHDDpSBoZWxlIHZla3RvcmVuLCBkdnMuIGFsbGUgdsOmcmRpZXIsIHDDpSDDqW4gZ2FuZy4KYGBge3J9CiMgRngga2FuIHZpIGzDpmdnZSAyIHRpbCBodmVyIHbDpnJkaSBpIHZla3RvcmVuCm15X3ZlY3RvciArIDIKYGBgCgpWaSBrYW4gb2dzw6UgYnJ1Z2UgZnVua3Rpb25lciBww6UgaGVsZSB2ZWt0b3JlbiwgZng6CmBgYHtyfQpzdW0obXlfdmVjdG9yKSAjIHN1bW1lbiBhZiB2w6ZyZGllcm5lCm1lYW4obXlfdmVjdG9yKSAjIGdlbm5lbXNuaXR0ZXQgYWYgdsOmcmRpZXJuZQptaW4obXlfdmVjdG9yKSAjIGRlbiBtaW5kc3RlIHbDpnJkaSBpIHZla3RvcmVuCm1heChteV92ZWN0b3IpICMgZGVuIHN0w7hyc3RlIHbDpnJkaQpyYW5nZShteV92ZWN0b3IpICMgZGVuIHN0w7hyc3RlIG9nIG1pbmRzdGUgdsOmcmRpCmBgYApEZXQga2FuIHbDpnJlIGJydWdiYXJ0LCBodmlzIHZpIGhhciBtYW5nZSB2w6ZyZGllciBpIGVuIHZla3RvciAtIGZ4IGV0IHN1cnZleXNww7hyZ3Ntw6VsIG1lZCBtYW5nZSBzdmFyLgoKIyMgNS4gRGF0YWZyYW1lcwoKTsOlciB2aSBza2FsIGluZGzDpnNlIGRhdGEsIGthbiB2aSBicnVnZSBmb3Jza2VsbGlnZSBmdW5rdGlvbmVyIGFmaMOmbmdpZ3QgYWYsIGh2aWxrZW4gdHlwZSBmaWwgdm9yZXMgZGF0YXPDpnQgZXIuIEZ4IGthbiBgcmVhZF9jc3YoKWAgYnJ1Z2VzIHRpbCBhdCBpbmRsw6ZzZSAuY3N2LWZpbGVyLCBpbWVucyBgcmVhZF9leGNlbCgpYCBsYWRlciBvcyBpbmRsw6ZzZSBlbiBFeGNlbC1maWwuCgpgYGB7ciwgZXZhbD1GQUxTRX0KIyBWaSBicnVnZXIgYXNzaWdubWVudCBvcGVyYXRvcmVuIGA8LWAgdGlsIGF0IGdlbW1lIGRldCBpbXBvcnRlcmVkZSBkYXRhc8OmdCBpIGV0IG9iamVrdApteV9kYXRhIDwtIHJlYWQuY3N2KCJuYXZuX3DDpV9kYXRhc8OmdC5jc3YiKQpgYGAKCk7DpXIgdmkgYXJiZWpkZXIgbWVkIHRhYnVsw6ZyZSBkYXRhIChgZGF0YSBmcmFtZXNgKSwgZXIgaHZlciBrb2xvbm5lIGVuIHZla3Rvci4gVmkga2FuIGJydWdlIGAkYCB0aWwgYXQgdWR2w6ZsZ2UgZW4gYmVzdGVtdCBrb2xvbm5lIGkgZXQgZGF0YXPDpnR0ZXQuIAoKSHZpcyB2aSBoYXIgZGF0YWZyYW1lbiBgJ215X2RhdGEnYCBvZyB2aWwgdsOmbGdlIHZla3RvcmVuIGBWMWAsIHNlciBkZXQgc8OlZGFuIGhlciB1ZDoKYGBge3IsIGV2YWw9RkFMU0V9Cm15X2RhdGEkVjEKYGBgCgpVZG92ZXIga29sb25uZXIgYmVzdMOlciBkYXRhZnJhbWVzIG9nc8OlIGFmIHLDpmtrZXIuIFZpIGthbiBicnVnZSBgW11gIHRpbCBhdCB1ZHbDpmxnZSBiZXN0ZW10ZSByw6Zra2VyIG9nIGtvbG9ubmVyLCBsaWdlc29tIG7DpXIgdmkgYXJiZWpkZXIgbWVkIHZla3RvcmVyOgpgYGB7ciwgZXZhbD1GQUxTRX0KbXlfZGF0YVs0LDNdICMgUiB2aXNlciByw6Zra2UgNCwga29sb25uZSAzIGkgdm9yZXMgZGF0YWZyYW1lCm15X2RhdGFbNCwgXSAjIFIgdmlzZXIgaGVsZSByw6Zra2UgNCBpIHZvcmVzIGRhdGFmcmFtZQpteV9kYXRhWyAsM10gIyBSIHZpc2VyIGhlbGUga29sb25uZSAzIGkgdm9yZXMgZGF0YWZyYW1lCm15X2RhdGFbLCAidmFyaWFiZWxfbmF2biJdICMgUiB2aXNlciBoZWxlIGtvbG9ubmVuIGZvciBlbiBnaXZlbiB2YXJpYWJlbApgYGAKCkh1c2ssIGF0IHLDpmtrZWbDuGxnZW4gYWx0aWQgZXIgYFtyw6Zra2UsIGtvbG9ubmVdYC4KCiMjIDUuMSBCZXRpbmdlbHNlcgpWaSBrYW4gb2dzw6UgdWR2w6ZsZ2UgYmVzdGVtdGUgdsOmcmRpZXIgZWxsZXIgcsOma2tlciBpIGVuIHZla3RvciBlbGxlciBkYXRhZnJhbWUgbWVkIGxvZ2lza2UgYmV0aW5nZWxzZXIuIAoKS29kZW4gdmlsIGt1biBnaXZlIG9zIGRlIHbDpnJkaWVyIGkgdmVrdG9yZW4sIGh2b3IgYmV0aW5nZWxzZW4gZXIgYFRSVUVgLgoKYGBge3J9CiMgSGVyIGJlaG9sZGVyIFIga3VuIGRlIHbDpnJkaWVyIGkgdmVrb3JlbiwgZGVyIGVyIG1pbmRyZSBlbmQgMjU6Cm15X3ZlY3RvcltteV92ZWN0b3IgPCAyNV0KYGBgCgpWaSBrYW4gZ8O4cmUgZGV0IHNhbW1lIHDDpSBkYXRhZnJhbWVzLiAKCmBgYHtyLCBldmFsPUZBTFNFfQojIEhlciBiZWhvbGRlciBSIGt1biBkZSB2w6ZyZGllciBpIGRhdGFmcmFtZW4sIGRlciBlciBtaW5kcmUgZW5kIDcwOgpteV9kYXRhW215X2RhdGEkdmFyaWFiZWxfbmF2biA8IDcwLCBdCmBgYAojIyA2LiBgdGlkeXZlcnNlYAoKUiBlciBldCBvcGVuLXNvdXJjZSBwcm9ncmFtLCBvZyB2aSBicnVnZXIgZGVyZm9yIGFsbGUgbXVsaWdlIHBha2tlciBsYXZldCBhZiBhbmRyZSBicnVnZXJlLCBuw6VyIHZpIGtvZGVyLgoKYHRpZHl2ZXJzZWAgZXIgZW4gc2FtbGluZyBhZiBwYWtrZXIsIGRlciBkZWxlciDigJxrb2RlZmlsb3NvZmnigJ0sIHNvbSBnw7hyIGRldCBsZXR0ZXJlIGF0IGJydWdlIGRlbSBzYW1tZW4uIFBha2tlcm5lIGfDuHIgZGV0IG1lcmUgb3ZlcnNrdWVsaWd0IGF0IGFyYmVqZGUgZGF0YS4KCiMjIyBQaXBlcyBgJT4lYApOw6VyIG1hbiBza3JpdmVyIGtvZGUgaSBSLCBlciBkZXQgbWVnZXQgYWxtaW5kZWxpZ3QgYXQgYnJ1Z2UgYmFidXNoa2Etc3RydWt0dXIgbWVkIHBhcmVudGVzZXIgaSBwYXJlbnRlc2VyLCBodmlsa2V0IGh1cnRpZ3Qga2FuIGJsaXZlIHVvdmVyc2t1ZWxpZ3QuIERldCBrYWxkZXIgbWFuICduZXN0aW5nJy4KCmBgYHtyfQojIEVrc2VtcGVsIHDDpSAnbmVzdGVkJyBrb2RlIGkgYmFidXNoa2Etc3RydWt0dXIgbWVkIHBhcmVudGVzZXIgaSBwYXJlbnRlc2VyOgpzcXJ0KGFicyhzdW0oYygtMSwtMiwtMykpKSkKYGBgCgpQaXBlcyAoYCU+JWApIGdpdmVyIG9zIG11bGlnaGVkIGZvciBhdCBza3JpdmUga29kZSBtZXJlIGVmZmVrdGl2dCB2ZWQgYXQgc8OmdHRlIGZsZXJlIHRyaW4gYWYga29kZSBzYW1tZW4gaSBlbiBsZXRsw6ZzZWxpZyByw6Zra2Vmw7hsZ2UuIEhlbHQga29ydCBrYW4gaHZlciBwaXBlIGZvcnN0w6VzIHNvbSBldCAiYW5kIHRoZW4uLi4iIGVsbGVyICJvZyBzw6UgZ8O4ciB2aSBzw6VkYW4gaGVyLi4uIG9nIHPDpSBnw7hyIHZpIHPDpWRhbiBoZXIuLi4iLiAKClBpcGVzIHRhZ2VyIGFsdHPDpSBldCBvYmpla3QgZWxsZXIgZXQgb3V0cHV0IHDDpSB2ZW5zdHJlIHNpZGUgb2cg4oCccGlwZXLigJ0gZGV0IHZpZGVyZSBzb20gZXQgYXJndW1lbnQgdGlsIGVuIGZ1bmt0aW9uIHDDpSBow7hqcmUgc2lkZSBhZiBwaXBlbi4KCmBgYHtyfQojIFNhbW1lIGtvZGUgbWVkIHBpcGUtZnVua3Rpb25lbjoKYygtMSwgLTIsIC0zKSAlPiUgc3VtKCkgJT4lIGFicygpICU+JSBzcXJ0KCkKYGBgCgpUYXN0YXR1cmdlbnZlamVuIHRpbCBhdCBsYXZlIGVuICU+JSBlciBgQ3RybGAgKyBgU2hpZnRgICsgYE1gIHDDpSBXaW5kb3dzIG9nIGBDbWRgICsgYFNoaWZ0YCArIGBNYCBww6UgTWFjLgoKYGBge3J9CiMgTWFuIGthbiBvZ3PDpSBsYXZlIGxpbmplc2tpZnQgZm9yIGF0IGfDuHJlIGtvZGVuIGVuZG51IG1lcmUgbGV0bMOmc2VsaWc6CmMoLTEsLTIsLTMpICU+JQpzdW0oKSAlPiUKYWJzKCkgJT4lCnNxcnQoKQpgYGAKCiMjIyBmaWx0ZXIoKQpGdW5rdGlvbmVuIGBmaWx0ZXIoKWAgZnJhIHRpZHl2ZXJzZSBnw7hyIGRldCBtdWxpZ3QgYXQgdWR2w6ZsZ2UgcsOma2tlciBpIGV0IGRhdGFzw6Z0LCBkZXIgb3BmeWxkZXIgZW4gYmVzdGVtdCBiZXRpbmdlbHNlLiBWaSBrYW4gYWx0c8OlIGJydWdlIGBmaWx0ZXIoKWAgdGlsIGt1biBhdCBzZSBvYnNlcnZhdGlvbmVyLCBkZXIgZXIgcmVsZXZhbnRlIGZvciBvcy4KYGBge3IsIGV2YWw9RkFMU0V9CiMgSGVyIGJlaG9sZGVyIFIga3VuIGRlIHLDpmtrZXIsIGh2b3IgdsOmcmRpZXJuZSBhZiBgdmFyaWFiZWxfbmF2bmAgZXIgc3TDuHJyZSBlbmQgNzA6Cm15X2RhdGEgJT4lCmZpbHRlcih2YXJpYWJlbF9uYXZuID4gNzApCmBgYAoKIyMjIHB1bGwoKQpGdW5rdGlvbmVuIGBwdWxsKClgIGhlbnRlciBlbiBiZXN0ZW10IGtvbG9ubmUgdWQgYWYgZXQgZGF0YXPDpnQgb2cgZ2l2ZXIgb3MgZW4gdmVrdG9yIG1lZCB2w6ZyZGllcm5lIGZyYSBrb2xvbm5lbi4KYGBge3IsIGV2YWw9RkFMU0V9CiMgSGVyIGhlbnRlciBSIGFsbGUgdsOmcmRpZXJuZSBmcmEga29sb25uZW4gYHZhcmlhYmVsX25hdm5gLgpteV9kYXRhICU+JQpwdWxsKHZhcmlhYmVsX25hdm4pCmBgYAoKIyMjIGhlYWQoKQpGdW5rdGlvbmVuIGBoZWFkKClgIGJydWdlcyB0aWwgaHVydGlndCBhdCBmw6UgZXQgb3ZlcmJsaWsgb3ZlciBldCBkYXRhc8OmdCB2ZWQgYXQgdmlzZSBkZSBmw7hyc3RlIHLDpmtrZXIuIERldCBlciBpc8OmciBueXR0aWd0LCBuw6VyIG1hbiBsaWdlIGhhciBpbXBvcnRlcmV0IGV0IGRhdGFzw6Z0IG9nIHZpbCBzZSwgaHZvcmRhbiBkYXRhIHNlciB1ZC4KYGBge3IsIGV2YWw9RkFMU0V9Cm15X2RhdGEgJT4lCmhlYWQoKQpgYGAKCiMjIyBzdW1tYXJpemUoKQpGdW5rdGlvbmVuIGBzdW1tYXJpemUoKWAgYnJ1Z2VzIHRpbCBhdCBsYXZlIGJlcmVnbmluZ2VyLCBkZXIgb3BzdW1tZXJlciBkYXRhLiBEZXQga2FuIGZ4IHbDpnJlIGV0IGdlbm5lbXNuaXQsIG1pbmltdW0gZWxsZXIgbWFrc2ltdW0gYWYgdsOmcmRpZXJuZSBpIHZvcmVzIGRhdGFzw6Z0LgpgYGB7ciwgZXZhbD1GQUxTRX0KbXlfZGF0YSAlPiUKc3VtbWFyaXplKCkKYGBgCg==