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

pload indlæser pakker og installerer dem, hvis de ikke allerede er installeret. :: fortæller R, at p_load kommer fra pakken pacman.

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 bruge : 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 (dataframes), 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.

# Her beholder R kun 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 inkluderer gennemsnit, minimum og maksimum af værdierne i vores datasæt.

my_data %>%
  summarize()

# Vi kan også opsummere informationer om enkelte variable:
my_data %>% 
  pull(variabel_navn) %>% 
  summarize()

7. Strings

Når vi arbejder med tekstobjekter (character strings), fx fra åbne svarfelter i en survey, kan vi bruge forskellige funktioner fra pakken stringr til at rense og omformatere teksten. Alle funktionerne starter med str_.

Det kan være relevant for åbne spørgsmål, hvor respondenterne kan skrive frit. Her kan deres svar indeholde uønskede mellemrum, specialtegn, forskellige stavemåder eller andet, der kan gøre data sværere at analysere. Funktionerne fra stringr kan derfor gøre svarene mere ensartede og lettere at arbejde med.

str_trim()

Funktionen str_trim() fjerner mellemrum i starten og slutningen af tekstobjekter.

c(" København ", " Aarhus") %>% str_trim()
[1] "København" "Aarhus"   

str_replace()

Funktionen str_replace() erstatter den første forekomst af bestemt mønster med en værdi, vi selv angiver. Det kan fx være et mellemrum, et punktum eller en tom tekststreng (““), hvis mønsteret skal fjernes.

Vi kan fx erstatte _ med et mellemrum. Det første argument i funktionen angiver det nuværende mønster (fx _) og det andet argument vores valgfrie erstatning (fx et mellemrum).

"Aarhus_V_" %>% str_replace("_", " ")
[1] "Aarhus V_"

str_replace_all()

str_replace erstatter kun den første forekomst af et mønster i en tekst. Men man kunne forestille sig, at en respondent fx havde angivet sin fødeby som “Aarhus__V”.

"Aarhus__V" %>% str_replace("_", " ")
[1] "Aarhus _V"

Her fjerner str_replace kun den første _ med et mellemrum.

Hvis vi gerne vil fjerne alle forekomster af _, kan vi i stedet bruge funktionen str_replace_all, der erstatter alle forekomster af mønsteret:

"Aarhus__V" %>% str_replace_all("_", " ")
[1] "Aarhus  V"

Hvis vi gerne vil slippe for at have to mellemrum i “Aarhus V”, kan vi bruge + som input i funktionen. Det betyder, at vi gerne vil erstatte én eller flere forekomster af et mønster.

"Aarhus__V" %>% str_replace_all("_+", " ")
[1] "Aarhus V"

str_sub()

Funktionen str_sub() bruges til at klippe en bestemt del ud af en tekst ved at angive, hvor teksten skal starte og slutte:

"København S" %>% str_sub(start = 1, end = 9)
[1] "København"

Her angiver vi, at tekstobjektets startposition er tegn nr. 1 og slutpositionen er tegn nr. 9 - dvs. vi fortæller R, at den skal bevare tegn 1-9 i tekstobjektet.

Nogle gange arbejder vi med tekstobjekter, der ikke har lige mange bogstaver:

c("København S", "Aarhus V") %>% str_sub(start = 1, end = 9)
[1] "København" "Aarhus V" 

Hvis vi kun vil have bynavnene uden de angivne bydele, kan vi få R til at “tælle bagfra”. Det gør vi ved at bruge et -.

c("København S", "Aarhus V") %>% str_sub(start = 1, end = -3)
[1] "København" "Aarhus"   

Her fortæller vi R, at tekstobjektet skal starte med tegn nr. 1 og stoppe 3 tegn, før teksten slutter. På den måde kan vi fjerne de sidste to tegn for hvert bynavn, hhv. ” S” og ” V”.

LS0tCnRpdGxlOiAiU3VydmV5IERlc2lnbiBGdW5rdGlvbnNvdmVyc2lndCIKYXV0aG9yOiAiSnVsaWFuZSBTdGFyY2tlIE5lZXJnYWFyZCIKZGF0ZTogIjIwMjYtMTAtMjEiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMgMS4gU2NyaXB0IGVsbGVyIE5vdGVib29rPwpJIHbDpmxnZXIgc2Vsdiwgb20gSSB2aWwgYXJiZWpkZSBpIHNjcmlwdHMgZWxsZXIgTm90ZWJvb2stZmlsZXIsIG7DpXIgSSBrb2RlciBpIFIuIAoKU2NyaXB0cyBoZWRkZXIgKmZpbG5hdm4uUiogb2cgTm90ZWJvb2tzIGhlZGRlciAqZmlsbmF2bi5SbWQqLCBzb20gc3TDpXIgZm9yIFIgTWFya2Rvd24uCgpGb3Jza2VsbGVuIHDDpSBkZSB0byBlciwgYXQgc2NyaXB0cyBzb20gdWRnYW5nc3B1bmt0IGFudGFnZXIsIGF0IG1hbiBza3JpdmVyIGtvZGUsIGltZW5zIE5vdGVib29rIGFudGFnZXIsIGF0IG1hbiBza3JpdmVyIHRla3N0LCBodmlzIGlra2UgbWFuIGFuZ2l2ZXIgbm9nZXQgYW5kZXQuIAoKRGVyZm9yIGJydWdlciB2aSBgI2AgaSBzY3JpcHRzIHRpbCBhdCBza3JpdmUgbm90ZXIsIGltZW5zIHZpIGJydWdlciAnY2h1bmtzJyBpIE5vdGVib29rIHRpbCBhdCBza3JpdmUgZmVsdGVyIG1lZCBrb2RlLiBDaHVua3MgZXIgYW5naXZldCBtZWQgYGB7cn0gYGAuCgpgYGB7cn0KIyBEZXQgaGVyIGVyIGV0IGNodW5rCmBgYAoKVGFzdGF0dXJnZW52ZWplbiB0aWwgYXQgbGF2ZSBjaHVua3MgZXIgYEN0cmxgICsgYEFsdGAgKyBgSWAgcMOlIFdpbmRvd3Mgb2cgYENtZGAgKyBgT3B0aW9uYCArIGBJYCBww6UgTWFjLiAKCkRldCBzbWFydGUgdmVkIE5vdGVib29rcyBlciwgYXQgdmkga2FuIGbDpSB2aXN0IHZvcmVzIG91dHB1dCB1bmRlciBrb2RlbiwgaW1lbnMgc2NyaXB0cyBrdW4gdmlzZXIgb3V0cHV0dGV0IGkgQ29uc29sZW4uIERlcnVkb3ZlciBsYXZlciBOb3RlYm9va3MgYXV0b21hdGlzayBlbiBodG1sLmZpbCwgc8OlIG1hbiBrYW4gZGVsZSBzaW4ga29kZSBtZWQgYW5kcmUsIHVkZW4gYXQgZGUgc2thbCDDpWJuZSBSLiBEZXQgaGVyIGVyIGZ4IGVuIGh0bWwtZmlsIGZyYSBlbiBOb3RlYm9vayA6KQoKVGlsIGdlbmfDpmxkIGVyIHNjcmlwdHMgbWVyZSBzaW1wbGUgb2cga2FuIGRlcmZvciB2aXJrZSBtZXJlIG92ZXJza3VlbGlnZSBhdCBicnVnZSwgaXPDpnIgaHZpcyBtYW4gc2thbCBsYXZlIG1hbmdlIGJlcmVnbmluZ2VyLgoKIyMgMi4gSHZhZCBrYW4gdmkgYXJiZWpkZSBtZWQgaSBSPwojIyMgMi4xIEJlcmVnbmluZ2VyIG9nIHRla3N0ClIga2FuIGJydWdlIG1hdGVtYXRpc2tlIHRlZ24gdGlsIGF0IGxhdmUgYmVyZWduaW5nZXIuIFZpIGthbiBrw7hyZSBrb2RlbiBtZWQgdGFzdGF0dXJnZW52ZWplbiBgQ3RybGAgKyBgRW50ZXJgIHDDpSBXaW5kb3dzIGVsbGVyIGBDbWRgICsgYEVudGVyYCBww6UgTWFjLiAKYGBge3J9CjUrNQpgYGAKVmkga2FuIG9nc8OlIGJydWdlIFIgdGlsIGF0IHNrcml2ZSB0ZWtzdDoKYGBge3J9CiJKZWcgZWxza2VyIFN1cnZleSBEZXNpZ24iCmBgYAojIyMgMi4yIExvZ2lza2UgdGVnbgpSIGthbiBicnVnZSBsb2dpc2tlIHRlZ24gdGlsIGF0IGZvcnTDpmxsZSwgb20gbm9nZXQgZXIgYFRSVUVgIChzYW5kdCkgZWxsZXIgYEZBTFNFYCAoZmFsc2spLgoKYDxgIG9nIGA+YCBzYW1tZW5saWduZXIgdGFsCgpgPT1gIHVuZGVyc8O4Z2VyLCBvbSB0byB2w6ZyZGllciBlciBlbnMKCmA8PWAgYmV0eWRlciBtaW5kcmUgZW5kIGVsbGVyIGxpZyBtZWQKCmA+PWAgYmV0eWRlciBzdMO4cnJlIGVuZCBlbGxlciBsaWcgbWVkCgpgIT1gIGJldHlkZXIgaWtrZSBsaWdlIG1lZAoKYGBge3J9CiMgRXIgNCBmeCBzdMO4cnJlIGVuZCAzPwo0ID4gMwpgYGAKYGBge3J9CiMgT2cgZXIgNSBkZXQgc2FtbWUgc29tIDQ/CjUgPT0gNApgYGAKCiMjIyAyLjMgR2VtbWUgb2cgYnJ1Z2Ugb2JqZWt0ZXIKRW4gdmlndGlnIGZvcnNrZWwgbWVsbGVtIFIgb2cgZW4gYWxtaW5kZWxpZyBsb21tZXJlZ25lciBlciwgYXQgUiBrYW4gZ2VtbWUgdsOmcmRpZXIuCgpEZXQgZ8O4ciB2aSBtZWQgYXNzaWdubWVudCBvcGVyYXRvcmVuIGA8LWAsIGRlciAnYXNzaWduZXInIHbDpnJkaWVyIHRpbCBldCBvYmpla3QuIFRhc3RhdHVyZ2VudmVqZW4gZXIgYEFsdGAgKyBgLWAgcMOlIFdpbmRvd3MgZWxsZXIgYE9wdGlvbmAgKyBgLWAKCk7DpXIgbWFuIGdlbW1lciB2w6ZyZGllciwga2FuIG1hbiBicnVnZSBkZW0gaWdlbiBzZW5lcmUuIERlIG9iamVrdGVyLCB2aSBoYXIgZ2VtdCwga2FuIHZpIHNlIGkgdm9yZXMgRW52aXJvbm1lbnQuCgpWaSBrYW4gZnggZ2VtbWUgYmVyZWduaW5nZW4gZnJhIHRpZGxpZ2VyZS4gCmBgYHtyfQojIEhlciBiZXJlZ25lciBSIDUgKyA1IG9nIGdlbW1lciByZXN1bHRhdGV0IDEwIGkgb2JqZWt0ZXQgbXlfbnVtYmVyCm15X251bWJlciA8LSA1ICsgNQpteV9udW1iZXIKYGBgCgpWaSBrYW4gb2dzw6UgZ2VtbWUgdGVrc3Qgc29tIGV0IG9iamVrdDoKCmBgYHtyfQpteV90ZXh0IDwtICJIZXIga2FuIGR1IHNrcml2ZSBodmFkIHNvbSBoZWxzdCEiCm15X3RleHQKYGBgClZpIGthbiBicnVnZSBnZW10ZSBvYmpla3RlciBpIG55ZSBiZXJlZ25pbmdlcjoKYGBge3J9Cm15X3NlY29uZF9udW1iZXIgPC0gbXlfbnVtYmVyICsgMwpteV9zZWNvbmRfbnVtYmVyCmBgYAoKYGBge3J9Cm15X3RoaXJkX251bWJlciA8LSBteV9zZWNvbmRfbnVtYmVyIC0gbXlfbnVtYmVyCm15X3RoaXJkX251bWJlcgpgYGAKCmBteV9udW1iZXJgIGdlbW1lciB0YWxsZXQgMTAKCmBteV9zZWNvbmRfbnVtYmVyYCBnZW1tZXIgdGFsbGV0IDEzIGAoMTAgKyAzKWAKCmBteV90aGlyZF9udW1iZXJgIGVyIGRlcmZvciBgMTMgLSAxMCA9IDNgCgpLb3J0IHNhZ3Q6IHZpIGJydWdlciBvYmpla3RlciB0aWwgYXQgZ2VtbWUgdsOmcmRpZXIgdW5kZXIgZXQgbmF2biwgc8OlIHZpIGthbiBicnVnZSBkZW4gaWdlbiBzZW5lcmUuCgojIyAzLiBGdW5rdGlvbmVyLCBwYWtrZXIgb2cgYXJndW1lbnRlcgoKIyMjIDMuMSBGdW5rdGlvbmVyCkZ1bmt0aW9uZXIgZXIga29tbWFuZG9lciBpIFIsIGRlciB1ZGbDuHJlciBlbiBiZXN0ZW10IGhhbmRsaW5nLiBGb3Jza2VsbGlnZSBmdW5rdGlvbmVyIGthbiBicnVnZXMgdGlsIGZvcnNrZWxsaWdlIHRpbmcuCgpgYGB7cn0KIyBWaSBrYW4gZnggYnJ1Z2UgZnVua3Rpb25lbiBzcXJ0KCkgdGlsIGF0IGZpbmRlIGt2YWRyYXRyb2RlbiBhZiBlbiB2w6ZyZGk6CnNxcnQoNSs1KQpgYGAKCkZ1bmt0aW9uZXIgc2tyaXZlcyBhbHRpZCBtZWQgcGFyZW50ZXNlciBgZnVua3Rpb24oKWAuIERldCwgdmkgc2tyaXZlciBpbmRlIGkgcGFyZW50ZXNlbiwgZXIgaW5wdXR0ZXQgdGlsIGZ1bmt0aW9uZW4uCgojIyMgMy4yIEFyZ3VtZW50ZXIKTWFuZ2UgZnVua3Rpb25lciBrYW4gdGlscGFzc2VzIHZlZCBoasOmbHAgYWYgYXJndW1lbnRlci4KCkFyZ3VtZW50ZXIgZm9ydMOmbGxlciBmdW5rdGlvbmVuLCBodm9yZGFuIGRlbiBza2FsIHVkZsO4cmUgc2luIG9wZ2F2ZSBvZyBodmFkIGRlbiBza2FsIGFyYmVqZGUgbWVkLgoKVmkga2FuIGZ4IGJydWdlIHBha2tlbiBgY293c2F5YCB0aWwgYXQgZsOlIGZvcnNrZWxsaWdlIGR5ciB0aWwgYXQgc2lnZSBub2dldCBtZWQgZnVua3Rpb25lbiBgc2F5YDogCmBgYHtyLCBldmFsPUZBTFNFfQpzYXkod2hhdCA9ICJKZWcgZWxza2VyIGF0IGtvZGUgaSBSIiwKYnkgPSAiY2F0IikKYGBgCkhlciBlciBgd2hhdGAgb2cgYGJ5YCBhcmd1bWVudGVyOgoKYHdoYXRgIGJlc3RlbW1lciwgaHZhZCBkZXIgc2thbCBzaWdlcy4KCmBieWAgYmVzdGVtbWVyLCBodmVtIGRlciBza2FsIHNpZ2UgZGV0LgoKVmkga2FuIG9nc8OlIGJydWdlIG9iamVrdGVyLCB2aSBhbGxlcmVkZSBoYXIgZ2VtdCwgc29tIGlucHV0IGkgZXQgYXJndW1lbnQsIGZ4IG9iamVrdGV0IGBteV90ZXh0YCBmcmEgdGlkbGlnZXJlOgpgYGB7ciwgZXZhbD1GQUxTRX0Kc2F5KHdoYXQgPSBteV90ZXh0LApieSA9ICJmaXNoIikKYGBgCgojIyMjIGBoZWxwKClgIG9nIGA/YAoKVmkga2FuIHVuZGVyc8O4Z2UgZW4gZnVua3Rpb24gbWVkIGA/YCwgaHZpcyB2aSBlciBpIHR2aXZsIG9tLCBodmlsa2UgYXJndW1lbnRlciBmdW5rdGlvbmVuIGhhciBlbGxlciBodmFkIGRlIGZvcnNrZWxsaWdlIGFyZ3VtZW50ZXIgZ8O4ci4KCkZ4IGthbiB2aSBza3JpdmUgYD9zYXlgIG9nIGbDpSBpbmZvcm1hdGlvbmVyIG9tLCBodmFkIHZpIGthbiBza3JpdmUgYWYgaW5wdXQgaSBmdW5rdGlvbmVuLgoKIyMjIDMuMyBQYWtrZXIKUiBpbmRlaG9sZGVyIG1hbmdlIGZ1bmt0aW9uZXIgaSBzaWcgc2VsdiwgbWVuIG1hbiBrYW4gZsOlIGFkZ2FuZyB0aWwgZmxlcmUgZnVua3Rpb25lciB2ZWQgYXQgaW5zdGFsbGVyZSBvZyBsb2FkZSBwYWtrZXIuCgpFbiBwYWtrZSBlciBlbiBzYW1saW5nIGFmIGZ1bmt0aW9uZXIgb2cgYW5kZXQgaW5kaG9sZCwgc29tIGFuZHJlIFItYnJ1Z2VyZSBoYXIgbGF2ZXQuCgpIdmlzIHZpIHNrYWwgYnJ1Z2UgcGFra2VuIGBjb3dzYXlgLCBza2FsIHZpIGbDuHJzdCBpbnN0YWxsZXJlIGRlbiBtZWQgZnVua3Rpb25lbiBgaW5zdGFsbC5wYWNrYWdlcygpYDoKCmBgYHtyLCBldmFsPUZBTFNFfQppbnN0YWxsLnBhY2thZ2VzKCJjb3dzYXkiKQpgYGAKCk7DpXIgcGFra2VuIGVyIGluc3RhbGxlcmV0LCBza2FsIGRlbiBpbmRsw6ZzZXMgbWVkIGZ1bmt0aW9uZW4gYGxpYnJhcnkoKWAsIGbDuHIgdmkga2FuIGJydWdlIGRlbnMgZnVua3Rpb25lcjoKYGBge3IsIGV2YWw9RkFMU0V9CmxpYnJhcnkoY293c2F5KQpgYGAKClZpIGJlaMO4dmVyIGt1biBhdCBpbnN0YWxsZXJlIHBha2tlciDDqW4gZ2FuZywgbWVuIHZpIHNrYWwgYnJ1Z2UgYGxpYnJhcnkoKWAgdGlsIGF0IGluZGzDpnNlIGRlbSBodmVyIGdhbmcsIHZpIHN0YXJ0ZXIgZW4gbnkgUi1zZXNzaW9uLgoKIyMjIDMuNCBQYWNtYW4KClZpIGthbiBicnVnZSBwYWtrZW4gYHBhY21hbmAgdGlsIGF0IGluc3RhbGxlcmUgb2cgaW5kbMOmc2UgcGFra2VyIHDDpSBzYW1tZSB0aWQgbWVkIGZ1bmt0aW9uZW4gYHBfbG9hZGAuIERldCBrcsOmdmVyLCBhdCB2aSBmw7hyc3QgaGFyIGluc3RhbGxlcmV0IGBwYWNtYW5gLgoKYHBfbG9hZGAgc3ZhcmVyIGFsdHPDpSB0aWwgYXQga8O4cmUgYGluc3RhbGxfcGFja2FnZXMoKWAgb2cgYGxpYnJhcnkoKWAgaSDDqW4ga29tbWFuZG8uCgpgYGB7cn0KcGFjbWFuOjpwX2xvYWQoImNvd3NheSIpCmBgYAoKIyMjIDMuNSBNYXBwZXIgb2cgZmlsc3RpZXIKCk7DpXIgdmkgYXJiZWpkZXIgbWVkIGRhdGEgaSBSLCBza2FsIHZpIG9mdGUgZm9ydMOmbGxlIFIsIGh2b3IgZW4gZmlsIGxpZ2dlci4gRGV0IGfDuHIgdmkgbWVkIGZpbHN0aWVyIChmaWxlIHBhaHRzKS4gRW4gZmlsc3RpIGZvcnTDpmxsZXIgUiwgaHZvciBkZW4gc2thbCBsZWRlIGVmdGVyIGVuIGJlc3RlbXQgZmlsIGVsbGVyIG1hcHBlLgoKIyMjIyBgZGlyKClgCgpGdW5rdGlvbmVuIGBkaXIoKWAga2FuIGJydWdlcyB0aWwgYXQgc2UgaW5kaG9sZGV0IGFmIGRlbiBtYXBwZSwgdmkgYXJiZWpkZXIgZnJhLgoKYGBge3J9CiMgRngga2FuIHZpIGJydWdlIGRpcigpIHRpbCBhdCBzZSwgaHZhZCBkZXIgbGlnZ2VyIGkgZGVuIG1hcHBlLCB2aSBiZWZpbmRlciBvcyBpOgpkaXIoIlVWMSIpCmBgYAoKYGBge3J9CiMgRWxsZXIgaSBlbiBhbmRlbiB2aWxrw6VybGlnIG1hcHBlLCB2aSBnZXJuZSB2aWwgdW5kZXJzw7hnZToKZGlyKCJVVjEvRXhlcmNpc2UgMSIpCmBgYAoKIyMjIyBgZ2V0d2QoKWAKCkZ1bmt0aW9uZW4gYGdldHdkKClgIGthbiBicnVnZXMgdGlsIGF0IHNlLCBodmlsa2VuIG1hcHBlIHZpIGFyYmVqZGVyIGZyYS4gRGV0IGVyIGhlciwgUiBzdGFydGVyLCBuw6VyIHZpIGJydWdlciByZWxhdGl2ZSBmaWxzdGllci4KCkVuIHJlbGF0aXYgZmlsc3RpIGJlc2tyaXZlciwgaHZvciBlbiBmaWwgZWxsZXIgbWFwcGUgbGlnZ2UgaSBmb3Job2xkIHRpbCBkZW4gbWFwcGUsIFIgYXJiZWpkZXIgdWQgZnJhLgoKSHZpcyB2b3JlcyB3b3JraW5nIGRpcmVjdG9yeSBlciBgaHVudF8wMV9UcmFzaF9NZXRhbGAsIG9nIGRlciBpIGRlbiBtYXBwZSBsaWdnZXIgdW5kZXJtYXBwZW4gYE92ZXJraWxsYCwgaHZvcmkgZmlsZW4gYEVsaW1pbmF0aW9uLmNzdmAgbGlnZ2VyLCB2aWwgZGVuIHJlbGF0aXZlIGZpbHN0aSB0aWwgYEVsaW1pbmF0aW9uLmNzdmAgdsOmcmU6CgpgYGB7ciwgZXZhbD1GQUxTRX0KIk92ZXJraWxsL0VsaW1pbmF0aW9uLmNzdiIKYGBgCgojIyMjIGAuLi9gIG9nIGAuLi8uLi9gCgpOw6VyIHZpIGFyYmVqZGVyIG1lZCByZWxhdGl2ZSBmaWxzdGllciwga2FuIHZpIGJydWdlIGAuLmAgdGlsIGF0IHZpc2UgaW5kaG9sZGV0IGFmIGVuIG1hcHBlLCBkZXIgbGlnZ2VyIGV0IGxlZCB1ZGUgaSB2b3JlcyBzdGkuIER2cy4gdmkgYmVkZXIgUiBvbSBhdCBnw6UgdWQgYWYgZGVuIG51dsOmcmVuZGUgbWFwcGUgb2cgZW4gbWFwcGUgdGlsYmFnZS4KCkh2aXMgdmkgYmVmaW5kZXIgb3MgaSBtYXBwZW4gT3ZlcmtpbGwsIGRlciBsaWdnZXIgaSBodW50XzAxX1RyYXNoX01ldGFsLCBrYW4gdmkgdmlzZSBpbmRob2xkZXQgYWYgaHVudF8wMV9UcmFzaF9NZXRhbCB2ZWQgYXQgc2tyaXZlOgoKYGBge3IsIGV2YWw9RkFMU0V9CmRpcigiLi4vIikKYGBgCgpIdmlzIHZpIHZpbCBnw6UgdWQgYWYgdG8gbWFwcGVyLCBrYW4gdmkgc2tyaXZlIGBkaXIoIi4uLy4uLyIpYC4gU8OlIGJlZGVyIHZpIFIgb20gYXQgZ8OlIHVkIGFmIGRlbiBudXbDpnJlbmRlIG1hcHBlIG9nIGRlcmVmdGVyIHVkIGFmIGRlbiBuw6ZzdGUgLSBhbHRzw6UgdG8gbWFwcGVyIHRpbGJhZ2UgaSBzdGllbi4KCiMjIyAzLjYgT3BzdW1tZXJpbmcKCmBkaXIoKWAgdmlzZXIgaW5kaG9sZGV0IGFmIGVuIG1hcHBlCgpgZGlyKCIuLi8iKWAgdmlzZXIsIGh2YWQgZGVyIGxpZ2dlciBpIG1hcHBlbiB1ZGVuIGZvciB2b3JlcyBwcm9qZWt0bWFwcGUKCmBkaXIoIi4uLy4uLyIpYCB2aXNlciwgaHZhZCBkZXIgbGlnZ2VyIHRvIG1hcHBlciB1ZGUKCmBnZXR3ZCgpYCB2aXNlciwgaHZvciB2b3JlcyByZWxhdGl2ZSBmaWxzdGkgc3RhcnRlciAoZHZzLiB2b3JlcyBudXbDpnJlbmRlIHdvcmtpbmcgZGlyZWN0b3J5KQoKYGhlbHAoKWAgb2cgYD9gIMOlYm5lciBkb2t1bWVudGF0aW9uZW4gZm9yIGVuIGZ1bmt0aW9uCgpgaW5zdGFsbC5wYWNrYWdlc2AgaW5zdGFsbGVyZXIgZW4gcGFra2UKCmBsaWJyYXJ5KClgIGluZGzDpnNlciBlbiBpbnN0YWxsZXJldCBwYWtrZQoKYHBsb2FkYCBpbmRsw6ZzZXIgcGFra2VyIG9nIGluc3RhbGxlcmVyIGRlbSwgaHZpcyBkZSBpa2tlIGFsbGVyZWRlIGVyIGluc3RhbGxlcmV0LiBgOjpgIGZvcnTDpmxsZXIgUiwgYXQgYHBfbG9hZGAga29tbWVyIGZyYSBwYWtrZW4gYHBhY21hbmAuCgojIyA0LiBWZWt0b3JlcgojIyMgNC4xIEh2YWQgZXIgZW4gdmVrdG9yPwpFbiB2ZWt0b3IgZXIgZXQgb2JqZWt0LCBkZXIgaW5kZWhvbGRlciBmbGVyZSB2w6ZyZGllciBpIGVuIGJlc3RlbXQgcsOma2tlZsO4bGdlLiBEZXQga2FuIHbDpnJlIHRhbCwgdGVrc3QgZWxsZXIgbG9naXNrZSB2w6ZyZGllci4gRHZzLiB2ZWt0b3JlciBlciBlbiBtw6VkZSBhdCBnZW1tZSBsaXN0ZXIgYWYgdsOmcmRpZXIgaSBSLiBOw6VyIHZpIGFyYmVqZGVyIG1lZCB2YXJpYWJsZSBpIGV0IGRhdGFzw6Z0LCBlciBlbiB2YXJpYWJlbCBkZXQgc2FtbWUgc29tIGVuIHZla3Rvci4KClZpIGxhdmVyIHZla3RvcmVyIG1lZCBjb21iaW5lLWZ1bmt0aW9uZW4gYGMoKWA6CmBgYHtyfQojIFZla3RvcmVyIGthbiBpbmRlaG9sZGUgdGFsCm15X3ZlY3RvciA8LSBjKDEsIDI5LCAxMywgMikKbXlfdmVjdG9yCgojIG9nIHRla3N0Cm15X3RleHRfdmVjdG9yIDwtIGMoIkFwcGxlIiwgIkJhbmFuYSIsICJQZWFyIikKbXlfdGV4dF92ZWN0b3IKYGBgCgpIdmVyIHbDpnJkaSBpIGVuIHZla3RvciBoYXIgZW4gYmVzdGVtdCBwb3NpdGlvbi4gRHZzLiByw6Zra2Vmw7hsZ2VuIGFmIHbDpnJkaWVyIGkgZW4gdmVrdG9yIGFsdGlkIGVyIGRlbiBzYW1tZSAtIG5yLiAxLCAyLCAzIG9zdi4uLgoKVmkga2FuIHVkdsOmbGdlIGJlc3RlbXRlIHbDpnJkaWVyIGZyYSBlbiB2ZWt0b3IgbWVkIGBbXWAgb2cgYnJ1Z2UgYDpgIHRpbCBhdCB2w6ZsZ2UgZXQgaW50ZXJ2YWwgYWYgdsOmcmRpZXIgaSB2ZWt0b3JlbjoKYGBge3J9Cm15X3ZlY3RvclsxXSAjIGdpdmVyIG9zIGRlbiBmw7hyc3RlIHbDpnJkaSBpIHLDpmtrZW4KbXlfdmVjdG9yWzJdICMgZ2l2ZXIgb3MgZGVuIGFuZGVuIHbDpnJkaSBpIHLDpmtrZW4KbXlfdmVjdG9yWzE6M10gIyBnaXZlciBvcyBmw7hyc3RlIHRpbCB0cmVkamUgdsOmcmRpIGkgdmVrdG9yZW4KYGBgCiMjIyA0LjIgQmVyZWduaW5nZXIgbWVkIHZla3RvcmVyCkVuIGFmIGZvcmRlbGVuZSB2ZWQgdmVrdG9yZXIgZXIsIGF0IHZpIGthbiBsYXZlIGJlcmVnbmluZ2VyIHDDpSBoZWxlIHZla3RvcmVuLCBkdnMuIGFsbGUgdsOmcmRpZXIsIHDDpSDDqW4gZ2FuZy4KYGBge3J9CiMgRngga2FuIHZpIGzDpmdnZSAyIHRpbCBodmVyIHbDpnJkaSBpIHZla3RvcmVuCm15X3ZlY3RvciArIDIKYGBgCgpWaSBrYW4gb2dzw6UgYnJ1Z2UgZnVua3Rpb25lciBww6UgaGVsZSB2ZWt0b3JlbiwgZng6CmBgYHtyfQpzdW0obXlfdmVjdG9yKSAjIHN1bW1lbiBhZiB2w6ZyZGllcm5lCm1lYW4obXlfdmVjdG9yKSAjIGdlbm5lbXNuaXR0ZXQgYWYgdsOmcmRpZXJuZQptaW4obXlfdmVjdG9yKSAjIGRlbiBtaW5kc3RlIHbDpnJkaSBpIHZla3RvcmVuCm1heChteV92ZWN0b3IpICMgZGVuIHN0w7hyc3RlIHbDpnJkaQpyYW5nZShteV92ZWN0b3IpICMgZGVuIHN0w7hyc3RlIG9nIG1pbmRzdGUgdsOmcmRpCmBgYApEZXQga2FuIHbDpnJlIGJydWdiYXJ0LCBodmlzIHZpIGhhciBtYW5nZSB2w6ZyZGllciBpIGVuIHZla3RvciAtIGZ4IGV0IHN1cnZleXNww7hyZ3Ntw6VsIG1lZCBtYW5nZSBzdmFyLgoKIyMgNS4gRGF0YWZyYW1lcwoKTsOlciB2aSBza2FsIGluZGzDpnNlIGRhdGEsIGthbiB2aSBicnVnZSBmb3Jza2VsbGlnZSBmdW5rdGlvbmVyIGFmaMOmbmdpZ3QgYWYsIGh2aWxrZW4gdHlwZSBmaWwgdm9yZXMgZGF0YXPDpnQgZXIuIEZ4IGthbiBgcmVhZF9jc3YoKWAgYnJ1Z2VzIHRpbCBhdCBpbmRsw6ZzZSAuY3N2LWZpbGVyLCBpbWVucyBgcmVhZF9leGNlbCgpYCBsYWRlciBvcyBpbmRsw6ZzZSBlbiBFeGNlbC1maWwuCgpgYGB7ciwgZXZhbD1GQUxTRX0KIyBWaSBicnVnZXIgYXNzaWdubWVudCBvcGVyYXRvcmVuIGA8LWAgdGlsIGF0IGdlbW1lIGRldCBpbXBvcnRlcmVkZSBkYXRhc8OmdCBpIGV0IG9iamVrdApteV9kYXRhIDwtIHJlYWQuY3N2KCJuYXZuX3DDpV9kYXRhc8OmdC5jc3YiKQpgYGAKCk7DpXIgdmkgYXJiZWpkZXIgbWVkIHRhYnVsw6ZyZSBkYXRhIChkYXRhZnJhbWVzKSwgZXIgaHZlciBrb2xvbm5lIGVuIHZla3Rvci4gVmkga2FuIGJydWdlIGAkYCB0aWwgYXQgdWR2w6ZsZ2UgZW4gYmVzdGVtdCBrb2xvbm5lIGkgZXQgZGF0YXPDpnR0ZXQuIAoKSHZpcyB2aSBoYXIgZGF0YWZyYW1lbiBgJ215X2RhdGEnYCBvZyB2aWwgdsOmbGdlIHZla3RvcmVuIGBWMWAsIHNlciBkZXQgc8OlZGFuIGhlciB1ZDoKYGBge3IsIGV2YWw9RkFMU0V9Cm15X2RhdGEkVjEKYGBgCgpVZG92ZXIga29sb25uZXIgYmVzdMOlciBkYXRhZnJhbWVzIG9nc8OlIGFmIHLDpmtrZXIuIFZpIGthbiBicnVnZSBgW11gIHRpbCBhdCB1ZHbDpmxnZSBiZXN0ZW10ZSByw6Zra2VyIG9nIGtvbG9ubmVyLCBsaWdlc29tIG7DpXIgdmkgYXJiZWpkZXIgbWVkIHZla3RvcmVyOgpgYGB7ciwgZXZhbD1GQUxTRX0KbXlfZGF0YVs0LDNdICMgUiB2aXNlciByw6Zra2UgNCwga29sb25uZSAzIGkgdm9yZXMgZGF0YWZyYW1lCm15X2RhdGFbNCwgXSAjIFIgdmlzZXIgaGVsZSByw6Zra2UgNCBpIHZvcmVzIGRhdGFmcmFtZQpteV9kYXRhWyAsM10gIyBSIHZpc2VyIGhlbGUga29sb25uZSAzIGkgdm9yZXMgZGF0YWZyYW1lCm15X2RhdGFbLCAidmFyaWFiZWxfbmF2biJdICMgUiB2aXNlciBoZWxlIGtvbG9ubmVuIGZvciBlbiBnaXZlbiB2YXJpYWJlbApgYGAKCkh1c2ssIGF0IHLDpmtrZWbDuGxnZW4gYWx0aWQgZXIgYFtyw6Zra2UsIGtvbG9ubmVdYC4KCiMjIDUuMSBCZXRpbmdlbHNlcgpWaSBrYW4gb2dzw6UgdWR2w6ZsZ2UgYmVzdGVtdGUgdsOmcmRpZXIgZWxsZXIgcsOma2tlciBpIGVuIHZla3RvciBlbGxlciBkYXRhZnJhbWUgbWVkIGxvZ2lza2UgYmV0aW5nZWxzZXIuIEtvZGVuIHZpbCBrdW4gZ2l2ZSBvcyBkZSB2w6ZyZGllciBpIHZla3RvcmVuLCBodm9yIGJldGluZ2Vsc2VuIGVyIGBUUlVFYC4KCgpgYGB7cn0KIyBIZXIgYmVob2xkZXIgUiBrdW4gZGUgdsOmcmRpZXIgaSB2ZWtvcmVuLCBkZXIgZXIgbWluZHJlIGVuZCAyNToKbXlfdmVjdG9yW215X3ZlY3RvciA8IDI1XQpgYGAKClZpIGthbiBnw7hyZSBkZXQgc2FtbWUgcMOlIGRhdGFmcmFtZXMuIAoKYGBge3IsIGV2YWw9RkFMU0V9CiMgSGVyIGJlaG9sZGVyIFIga3VuIGRlIHbDpnJkaWVyIGkgZGF0YWZyYW1lbiwgZGVyIGVyIG1pbmRyZSBlbmQgNzA6Cm15X2RhdGFbbXlfZGF0YSR2YXJpYWJlbF9uYXZuIDwgNzAsIF0KYGBgCiMjIDYuIGB0aWR5dmVyc2VgCgpSIGVyIGV0IG9wZW4tc291cmNlIHByb2dyYW0sIG9nIHZpIGJydWdlciBkZXJmb3IgYWxsZSBtdWxpZ2UgcGFra2VyIGxhdmV0IGFmIGFuZHJlIGJydWdlcmUsIG7DpXIgdmkga29kZXIuCgpgdGlkeXZlcnNlYCBlciBlbiBzYW1saW5nIGFmIHBha2tlciwgZGVyIGRlbGVyIOKAnGtvZGVmaWxvc29maeKAnSwgc29tIGfDuHIgZGV0IGxldHRlcmUgYXQgYnJ1Z2UgZGVtIHNhbW1lbi4gUGFra2VybmUgZ8O4ciBkZXQgbWVyZSBvdmVyc2t1ZWxpZ3QgYXQgYXJiZWpkZSBkYXRhLgoKIyMjIFBpcGVzIGAlPiVgCk7DpXIgbWFuIHNrcml2ZXIga29kZSBpIFIsIGVyIGRldCBtZWdldCBhbG1pbmRlbGlndCBhdCBicnVnZSBiYWJ1c2hrYS1zdHJ1a3R1ciBtZWQgcGFyZW50ZXNlciBpIHBhcmVudGVzZXIsIGh2aWxrZXQgaHVydGlndCBrYW4gYmxpdmUgdW92ZXJza3VlbGlndC4gRGV0IGthbGRlciBtYW4gJ25lc3RpbmcnLgoKYGBge3J9CiMgRWtzZW1wZWwgcMOlICduZXN0ZWQnIGtvZGUgaSBiYWJ1c2hrYS1zdHJ1a3R1ciBtZWQgcGFyZW50ZXNlciBpIHBhcmVudGVzZXI6CnNxcnQoYWJzKHN1bShjKC0xLC0yLC0zKSkpKQpgYGAKClBpcGVzIChgJT4lYCkgZ2l2ZXIgb3MgbXVsaWdoZWQgZm9yIGF0IHNrcml2ZSBrb2RlIG1lcmUgZWZmZWt0aXZ0IHZlZCBhdCBzw6Z0dGUgZmxlcmUgdHJpbiBhZiBrb2RlIHNhbW1lbiBpIGVuIGxldGzDpnNlbGlnIHLDpmtrZWbDuGxnZS4gSGVsdCBrb3J0IGthbiBodmVyIHBpcGUgZm9yc3TDpXMgc29tIGV0ICJhbmQgdGhlbi4uLiIgZWxsZXIgIm9nIHPDpSBnw7hyIHZpIHPDpWRhbiBoZXIuLi4gb2cgc8OlIGfDuHIgdmkgc8OlZGFuIGhlci4uLiIuIAoKUGlwZXMgdGFnZXIgYWx0c8OlIGV0IG9iamVrdCBlbGxlciBldCBvdXRwdXQgcMOlIHZlbnN0cmUgc2lkZSBvZyDigJxwaXBlcuKAnSBkZXQgdmlkZXJlIHNvbSBldCBhcmd1bWVudCB0aWwgZW4gZnVua3Rpb24gcMOlIGjDuGpyZSBzaWRlIGFmIHBpcGVuLgoKYGBge3J9CiMgU2FtbWUga29kZSBtZWQgcGlwZS1mdW5rdGlvbmVuOgpjKC0xLCAtMiwgLTMpICU+JSBzdW0oKSAlPiUgYWJzKCkgJT4lIHNxcnQoKQpgYGAKClRhc3RhdHVyZ2VudmVqZW4gdGlsIGF0IGxhdmUgZW4gJT4lIGVyIGBDdHJsYCArIGBTaGlmdGAgKyBgTWAgcMOlIFdpbmRvd3Mgb2cgYENtZGAgKyBgU2hpZnRgICsgYE1gIHDDpSBNYWMuCgpgYGB7cn0KIyBNYW4ga2FuIG9nc8OlIGxhdmUgbGluamVza2lmdCBmb3IgYXQgZ8O4cmUga29kZW4gZW5kbnUgbWVyZSBsZXRsw6ZzZWxpZzoKYygtMSwtMiwtMykgJT4lCnN1bSgpICU+JQphYnMoKSAlPiUKc3FydCgpCmBgYAoKIyMjIGZpbHRlcigpCkZ1bmt0aW9uZW4gYGZpbHRlcigpYCBmcmEgdGlkeXZlcnNlIGfDuHIgZGV0IG11bGlndCBhdCB1ZHbDpmxnZSByw6Zra2VyIGkgZXQgZGF0YXPDpnQsIGRlciBvcGZ5bGRlciBlbiBiZXN0ZW10IGJldGluZ2Vsc2UuIFZpIGthbiBhbHRzw6UgYnJ1Z2UgYGZpbHRlcigpYCB0aWwga3VuIGF0IHNlIG9ic2VydmF0aW9uZXIsIGRlciBlciByZWxldmFudGUgZm9yIG9zLgpgYGB7ciwgZXZhbD1GQUxTRX0KIyBIZXIgYmVob2xkZXIgUiBrdW4gZGUgcsOma2tlciwgaHZvciB2w6ZyZGllcm5lIGFmIGB2YXJpYWJlbF9uYXZuYCBlciBzdMO4cnJlIGVuZCA3MDoKbXlfZGF0YSAlPiUKZmlsdGVyKHZhcmlhYmVsX25hdm4gPiA3MCkKYGBgCgojIyMgcHVsbCgpCkZ1bmt0aW9uZW4gYHB1bGwoKWAgaGVudGVyIGVuIGJlc3RlbXQga29sb25uZSB1ZCBhZiBldCBkYXRhc8OmdCBvZyBnaXZlciBvcyBlbiB2ZWt0b3IgbWVkIHbDpnJkaWVybmUgZnJhIGtvbG9ubmVuLgpgYGB7ciwgZXZhbD1GQUxTRX0KIyBIZXIgaGVudGVyIFIgYWxsZSB2w6ZyZGllcm5lIGZyYSBrb2xvbm5lbiBgdmFyaWFiZWxfbmF2bmAuCm15X2RhdGEgJT4lCiAgcHVsbCh2YXJpYWJlbF9uYXZuKQpgYGAKCiMjIyBoZWFkKCkKRnVua3Rpb25lbiBgaGVhZCgpYCBicnVnZXMgdGlsIGh1cnRpZ3QgYXQgZsOlIGV0IG92ZXJibGlrIG92ZXIgZXQgZGF0YXPDpnQgdmVkIGF0IHZpc2UgZGUgZsO4cnN0ZSByw6Zra2VyLiBEZXQgZXIgaXPDpnIgbnl0dGlndCwgbsOlciBtYW4gbGlnZSBoYXIgaW1wb3J0ZXJldCBldCBkYXRhc8OmdCBvZyB2aWwgc2UsIGh2b3JkYW4gZGF0YSBzZXIgdWQuCmBgYHtyLCBldmFsPUZBTFNFfQpteV9kYXRhICU+JQogIGhlYWQoKQpgYGAKCiMjIyBzdW1tYXJpemUoKQpGdW5rdGlvbmVuIGBzdW1tYXJpemUoKWAgYnJ1Z2VzIHRpbCBhdCBsYXZlIGJlcmVnbmluZ2VyLCBkZXIgb3BzdW1tZXJlciBkYXRhLiBEZXQga2FuIGlua2x1ZGVyZXIgZ2VubmVtc25pdCwgbWluaW11bSBvZyBtYWtzaW11bSBhZiB2w6ZyZGllcm5lIGkgdm9yZXMgZGF0YXPDpnQuCmBgYHtyLCBldmFsPUZBTFNFfQpteV9kYXRhICU+JQogIHN1bW1hcml6ZSgpCgojIFZpIGthbiBvZ3PDpSBvcHN1bW1lcmUgaW5mb3JtYXRpb25lciBvbSBlbmtlbHRlIHZhcmlhYmxlOgpteV9kYXRhICU+JSAKICBwdWxsKHZhcmlhYmVsX25hdm4pICU+JSAKICBzdW1tYXJpemUoKQpgYGAKCiMjIDcuIFN0cmluZ3MKCk7DpXIgdmkgYXJiZWpkZXIgbWVkIHRla3N0b2JqZWt0ZXIgKCpjaGFyYWN0ZXIgc3RyaW5ncyopLCBmeCBmcmEgw6VibmUgc3ZhcmZlbHRlciBpIGVuIHN1cnZleSwga2FuIHZpIGJydWdlIGZvcnNrZWxsaWdlIGZ1bmt0aW9uZXIgZnJhIHBha2tlbiBgc3RyaW5ncmAgdGlsIGF0IHJlbnNlIG9nIG9tZm9ybWF0ZXJlIHRla3N0ZW4uIEFsbGUgZnVua3Rpb25lcm5lIHN0YXJ0ZXIgbWVkIGBzdHJfYC4KCkRldCBrYW4gdsOmcmUgcmVsZXZhbnQgZm9yIMOlYm5lIHNww7hyZ3Ntw6VsLCBodm9yIHJlc3BvbmRlbnRlcm5lIGthbiBza3JpdmUgZnJpdC4gSGVyIGthbiBkZXJlcyBzdmFyIGluZGVob2xkZSB1w7huc2tlZGUgbWVsbGVtcnVtLCBzcGVjaWFsdGVnbiwgZm9yc2tlbGxpZ2Ugc3RhdmVtw6VkZXIgZWxsZXIgYW5kZXQsIGRlciBrYW4gZ8O4cmUgZGF0YSBzdsOmcmVyZSBhdCBhbmFseXNlcmUuIEZ1bmt0aW9uZXJuZSBmcmEgYHN0cmluZ3JgIGthbiBkZXJmb3IgZ8O4cmUgc3ZhcmVuZSBtZXJlIGVuc2FydGVkZSBvZyBsZXR0ZXJlIGF0IGFyYmVqZGUgbWVkLgoKIyMjIHN0cl90cmltKCkKRnVua3Rpb25lbiBgc3RyX3RyaW0oKWAgZmplcm5lciBtZWxsZW1ydW0gaSBzdGFydGVuIG9nIHNsdXRuaW5nZW4gYWYgdGVrc3RvYmpla3Rlci4KCmBgYHtyfQpjKCIgS8O4YmVuaGF2biAiLCAiIEFhcmh1cyIpICU+JSBzdHJfdHJpbSgpCmBgYAoKIyMjIHN0cl9yZXBsYWNlKCkKRnVua3Rpb25lbiBgc3RyX3JlcGxhY2UoKWAgZXJzdGF0dGVyIGRlbiBmw7hyc3RlIGZvcmVrb21zdCBhZiBiZXN0ZW10IG3DuG5zdGVyIG1lZCBlbiB2w6ZyZGksIHZpIHNlbHYgYW5naXZlci4gRGV0IGthbiBmeCB2w6ZyZSBldCBtZWxsZW1ydW0sIGV0IHB1bmt0dW0gZWxsZXIgZW4gdG9tIHRla3N0c3RyZW5nICgiIiksIGh2aXMgbcO4bnN0ZXJldCBza2FsIGZqZXJuZXMuCgpWaSBrYW4gZnggZXJzdGF0dGUgXyBtZWQgZXQgbWVsbGVtcnVtLiBEZXQgZsO4cnN0ZSBhcmd1bWVudCBpIGZ1bmt0aW9uZW4gYW5naXZlciBkZXQgbnV2w6ZyZW5kZSBtw7huc3RlciAoZnggYF9gKSBvZyBkZXQgYW5kZXQgYXJndW1lbnQgdm9yZXMgdmFsZ2ZyaWUgZXJzdGF0bmluZyAoZnggZXQgbWVsbGVtcnVtKS4KCmBgYHtyfQoiQWFyaHVzX1YiICU+JSBzdHJfcmVwbGFjZSgiXyIsICIgIikKYGBgCgojIyMgc3RyX3JlcGxhY2VfYWxsKCkKCmBzdHJfcmVwbGFjZWAgZXJzdGF0dGVyIGt1biBkZW4gZsO4cnN0ZSBmb3Jla29tc3QgYWYgZXQgbcO4bnN0ZXIgaSBlbiB0ZWtzdC4gTWVuIG1hbiBrdW5uZSBmb3Jlc3RpbGxlIHNpZywgYXQgZW4gcmVzcG9uZGVudCBmeCBoYXZkZSBhbmdpdmV0IHNpbiBmw7hkZWJ5IHNvbSAiQWFyaHVzX19WIi4KCmBgYHtyfQoiQWFyaHVzX19WIiAlPiUgc3RyX3JlcGxhY2UoIl8iLCAiICIpCmBgYAoKSGVyIGZqZXJuZXIgYHN0cl9yZXBsYWNlYCBrdW4gZGVuIGbDuHJzdGUgYF9gIG1lZCBldCBtZWxsZW1ydW0uIAoKSHZpcyB2aSBnZXJuZSB2aWwgZmplcm5lIGFsbGUgZm9yZWtvbXN0ZXIgYWYgYF9gLCBrYW4gdmkgaSBzdGVkZXQgYnJ1Z2UgZnVua3Rpb25lbiBgc3RyX3JlcGxhY2VfYWxsYCwgZGVyIGVyc3RhdHRlciBhbGxlIGZvcmVrb21zdGVyIGFmIG3DuG5zdGVyZXQ6CgpgYGB7cn0KIkFhcmh1c19fViIgJT4lIHN0cl9yZXBsYWNlX2FsbCgiXyIsICIgIikKYGBgCgpIdmlzIHZpIGdlcm5lIHZpbCBzbGlwcGUgZm9yIGF0IGhhdmUgdG8gbWVsbGVtcnVtIGkgIkFhcmh1cyBWIiwga2FuIHZpIGJydWdlIGArYCBzb20gaW5wdXQgaSBmdW5rdGlvbmVuLiBEZXQgYmV0eWRlciwgYXQgdmkgZ2VybmUgdmlsIGVyc3RhdHRlIMOpbiBlbGxlciBmbGVyZSBmb3Jla29tc3RlciBhZiBldCBtw7huc3Rlci4KCmBgYHtyfQoiQWFyaHVzX19WIiAlPiUgc3RyX3JlcGxhY2VfYWxsKCJfKyIsICIgIikKYGBgCgojIyMgc3RyX3N1YigpCgpGdW5rdGlvbmVuIHN0cl9zdWIoKSBicnVnZXMgdGlsIGF0IGtsaXBwZSBlbiBiZXN0ZW10IGRlbCB1ZCBhZiBlbiB0ZWtzdCB2ZWQgYXQgYW5naXZlLCBodm9yIHRla3N0ZW4gc2thbCBzdGFydGUgb2cgc2x1dHRlOgoKYGBge3J9CiJLw7hiZW5oYXZuIFMiICU+JSBzdHJfc3ViKHN0YXJ0ID0gMSwgZW5kID0gOSkKYGBgCgpIZXIgYW5naXZlciB2aSwgYXQgdGVrc3RvYmpla3RldHMgc3RhcnRwb3NpdGlvbiBlciB0ZWduIG5yLiAxIG9nIHNsdXRwb3NpdGlvbmVuIGVyIHRlZ24gbnIuIDkgLSBkdnMuIHZpIGZvcnTDpmxsZXIgUiwgYXQgZGVuIHNrYWwgYmV2YXJlIHRlZ24gMS05IGkgdGVrc3RvYmpla3RldC4KCk5vZ2xlIGdhbmdlIGFyYmVqZGVyIHZpIG1lZCB0ZWtzdG9iamVrdGVyLCBkZXIgaWtrZSBoYXIgbGlnZSBtYW5nZSBib2dzdGF2ZXI6CmBgYHtyfQpjKCJLw7hiZW5oYXZuIFMiLCAiQWFyaHVzIFYiKSAlPiUgc3RyX3N1YihzdGFydCA9IDEsIGVuZCA9IDkpCmBgYAoKSHZpcyB2aSBrdW4gdmlsIGhhdmUgYnluYXZuZW5lIHVkZW4gZGUgYW5naXZuZSBieWRlbGUsIGthbiB2aSBmw6UgUiB0aWwgYXQgInTDpmxsZSBiYWdmcmEiLiBEZXQgZ8O4ciB2aSB2ZWQgYXQgYnJ1Z2UgZXQgYC1gLgoKYGBge3J9CmMoIkvDuGJlbmhhdm4gUyIsICJBYXJodXMgViIpICU+JSBzdHJfc3ViKHN0YXJ0ID0gMSwgZW5kID0gLTMpCmBgYAoKSGVyIGZvcnTDpmxsZXIgdmkgUiwgYXQgdGVrc3RvYmpla3RldCBza2FsIHN0YXJ0ZSBtZWQgdGVnbiBuci4gMSBvZyBzdG9wcGUgMyB0ZWduLCBmw7hyIHRla3N0ZW4gc2x1dHRlci4gUMOlIGRlbiBtw6VkZSBrYW4gdmkgZmplcm5lIGRlIHNpZHN0ZSB0byB0ZWduIGZvciBodmVydCBieW5hdm4sIGhodi4gIiBTIiBvZyAiIFYiLg==