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)

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==