Úvod k základným operáciám v R
Tento dokument demonštruje prácu so základnými typmi
hodnôt v R:
- numerické,
- textové,
- logické,
- vektory a
- matice.
Pri každej kategórii som zahrnula aj malé cvičenia
na sumarizáciu a preopakovanie.
Skaláre (jednočíselné hodnoty)
Numerické skaláre
a <- 8
b <- 3.5
c <- -2
# základné operácie
sucet <- a + b + c
sucin <- a * b * c
priemer <- (a + b + c) / 3
# kombinácie
vyraz1 <- (a^2 + b) / c
vyraz2 <- (a * b) - (b / c)
vyraz3 <- (a %% 3) + (b %% 2)
round(b, 1)
abs(c) # absolútna hodnota
sqrt(a) # druhá odmocnina
sucet; sucin; priemer
vyraz1; vyraz2; vyraz3
Malé cvičenie
Vypočítajte nasledujúce výrazy (pri hodnotách a = 8, b = 3.5, c =
-2):
- \(\frac{a^2 + b^2}{c}\)
- \(\frac{a}{b} + \frac{b}{c} +
\frac{c}{a}\)
- \((a+b+c)^2 - (a \cdot b \cdot
c)\)
a <- 8; b <- 3.5; c <- -2
( (a^2 + b^2) / c )
( (a/b) + (b/c) + (c/a) )
( (a+b+c)^2 - (a*b*c) )
Text
Vytváranie textovými premennými a práca s nimi
city <- "Bratislava" # premenná obsahujúca názov mesta
food <- "Pizza" # premenná obsahujúca jedlo
combo <- paste(city, food) # spojenie textov s medzerou medzi nimi
combo_nospace <- paste0(city, food) # spojenie textov bez medzery
list_line <- paste("coffee", "tea", "juice", sep = ",") # spájanie textov s oddeľovačom ,
city; food; combo; combo_nospace; list_line # vypísanie viacerých premenných za sebou
Dĺžka textového reťazca, podreťazec
sentence <- "Learning R is fun!"
nchar(sentence) # počet znakov v reťazci
substr(sentence, 3, 10) # výber znakov od 3. po 10. pozíciu
Takýmto spôsobom sa v R pracuje s textovými premennými.
Malé cvičenie
Vytvorte textovú premennú s názvom svojho obľúbeného športu a:
- spojte ju s mestom, kde sa šport hrá,
- vytvorte verziu bez medzery,
- zistite počet znakov v celom reťazci,
- vypíšte iba prvé 4 znaky.
sport <- "Hokej" # názov športu
place <- "Kosice" # názov mesta
joined <- paste(sport, place) # spojenie s medzerou
joined_nospace <- paste0(sport, place) # spojenie bez medzery
nchar(joined) # počet znakov v celom reťazci
substr(joined, 1, 4) # podreťazec - prvé 4 znaky
Logické (boolovské) hodnoty a premenné
Základy
r <- TRUE
s <- FALSE
!r # logická negácia (NOT)
r & s # logický súčin (AND) - pravda len keď obidva sú TRUE
r | s # logický súčet (OR) - pravda keď aspoň jeden je TRUE
xor(r, s) # exkluzívne OR - pravda len ak presne jeden z nich je TRUE
Logický výsledok porovnávania
5 > 2 # je 5 väčšie ako 2?
10 <= 15 # je 10 menšie alebo rovné 15?
"dog" == "dog" # rovnosť dvoch reťazcov
"apple" != "orange" # nerovnosť dvoch reťazcov
!FALSE # negácia hodnoty FALSE
7 == 3 + 4 # rovnosť čísla a výrazu
20 != 5 * 5 # porovnanie nerovnosti
100 >= 10^2 # mocnina a porovnanie
"car" < "cat" # porovnanie podľa abecedy (lexikograficky)
"Zoo" > "apple" # veľké písmená sú v ASCII pred malými
Zložitejšie logické operácie
y <- 25
y >= 20 & y <= 30 # súčasne (AND) - číslo je medzi 20 a 30
y < 0 | y > 100 # alebo (OR) - číslo je menšie ako 0 alebo väčšie ako 100
(y < 20 & y > 10) | (y > 30) # kombinácia AND a OR - platí, ak y je medzi 10 a 20 alebo väčšie ako 30
Zlučovanie viacerých log. premenných do vektora
checks <- c(TRUE, TRUE, FALSE, FALSE, TRUE) # vektor logických hodnôt
Malé cvičenie
Základy
Vytvorte dve logické premenné a
a b
.
- Zistite negáciu a
.
- Vypočítajte AND (&
) a OR (|
).
- Vyskúšajte aj XOR medzi nimi.
a <- TRUE
b <- FALSE
!a
a & b
a | b
xor(a, b)
Logický výsledok porovnávania
Skontrolujte, či platia nasledujúce podmienky:
- číslo 50 je väčšie ako 40 a menšie ako 60,
- číslo 15 nie je rovné 10,
- reťazec “banana” je rovný “banana”,
- reťazec “Apple” je menší ako “apple” (lexikograficky),
- overte, či 7 + 3 = 10 a či 20 - 5 != 15.
num <- 50
num >= 40 & num <= 60 # AND
15 != 10 # nerovnosť
"banana" == "banana" # rovnosť reťazcov
"Apple" < "apple" # lexikografické porovnanie
7 + 3 == 10 # rovnosť výrazu
20 - 5 != 15 # nerovnosť výrazu
Zložitejšie logické operácie
Použite číslo y <- 25
a:
- overte, či je medzi 20 a 30 (AND),
- overte, či je menšie ako 0 alebo väčšie ako 100 (OR),
- kombinujte podmienky: medzi 10 a 20 alebo väčšie ako 30,
- vyskúšajte negáciu celej kombinácie.
y <- 25
y >= 20 & y <= 30 # AND
y < 0 | y > 100 # OR
(y < 20 & y > 10) | (y > 30) # kombinácia AND a OR
!( (y < 20 & y > 10) | (y > 30) ) # negácia celej kombinácie
Zlučovanie viacerých log. premenných do vektora
Vytvorte vektor vals <- c(5, 15, 25, 35, 45)
a:
- zistite, ktoré hodnoty sú väčšie ako 20,
- ktoré hodnoty sú menšie ako 30,
- ktoré hodnoty sú zároveň väčšie ako 20 a menšie ako 40,
- skombinujte OR a AND vo výraze pre každý prvok, aby ste zistili, ktoré
hodnoty sú menšie ako 10 alebo väčšie ako 40.
vals <- c(5, 15, 25, 35, 45)
vals > 20 # TRUE pre prvky väčšie ako 20
vals < 30 # TRUE pre prvky menšie ako 30
vals > 20 & vals < 40 # kombinácia AND
(vals < 10 | vals > 40) # kombinácia OR
Numerické vektory
Generovanie vektorov
a1 <- c(10, 20, 30, 40)
a2 <- 5:12 # postupnosť čísel od 5 po 12
a3 <- seq(from = 2, to = 4, by = 0.5) # postupnosť s krokom 0.5
a4 <- rep(7, times = 6) # vektor so šiestimi sedmičkami
a5 <- runif(6, min = -1, max = 1) # náhodné čísla z intervalu [-1,1]
a6 <- rnorm(6, mean = 50, sd = 10) # normálne rozdelenie so stredom 50
a1; a2; a3; a4; a5; a6
Aritmetické operácie s vektormi
b <- c(2, 4, 6, 8)
b - 3 # každý prvok zmenšíme o 3
b / 2 # každý prvok vydelíme dvomi
(b^2) + 1 # druhá mocnina každého prvku plus 1
log(b) # prirodzený logaritmus prvkov
sum(c(2,4,6), c(1,1,1)) # skalárny súčin (skrátená forma)
crossprod(c(2,4,6), c(1,1,1)) # skalárny súčin - matica 1x1
c(2,4,6) * c(3,3,3) # Hadamardov súčin
Matematické operácie s 2 vektormi rovnakého rozmeru
length(c(10,20,30,40))
length(a5) # dĺžka vektora a5
c(10,20,30,40) + a5 # súčet vektorov
c(10,20,30,40) - a5 # rozdiel vektorov
Indexovanie a výber niektorych prvkov vektora
c1 <- c(9, 15, 2, 27, 5, 18, 0)
c1[3] # tretí prvok
c1[2:5] # druhý až piaty prvok
c1[-4] # všetko okrem štvrtého prvku
c1[c1 %% 3 == 0] # len tie prvky, ktoré sú deliteľné tromi
which(c1 < 10) # indexy prvkov menších ako 10
Práca s chýbajúcimi hodnotami
d <- c(NA, 4, 8, NA, 12, 16)
is.na(d)
sum(is.na(d)) # počet chýbajúcich hodnôt
mean(d, na.rm = TRUE) # priemer bez NA
median(d, na.rm = TRUE) # medián bez NA
Základné štatistiky a usporiadanie prvkov vektora podľa
veľkosti
e <- c(25, 7, 14, 32, 19, 3)
mean(e)
sd(e)
min(e)
max(e)
summary(e)
sort(e)
sort(e, decreasing = TRUE)
Malé cvičenie 1
Vytvorte vektor f
s číslami 50..100 a vypočítajte
aritmetický priemer všetkých nepárnych čísel.
f <- 50:100
mean(f[f %% 2 == 1])
Malé cvičenie 2
Vytvorte vektor 10 náhodných čísel z intervalu [-5,5] a spočítajte,
koľko z nich je kladných.
g <- runif(10, min = -5, max = 5)
g
sum(g > 0)
Malé cvičenie 3
Vytvorte vektor h
s hodnotami od 1 do 12 a zistite, aký
je rozdiel medzi súčtom čísel deliteľných 4 a súčtom čísel deliteľných
3.
h <- 1:12
sum4 <- sum(h[h %% 4 == 0])
sum3 <- sum(h[h %% 3 == 0])
sum4 - sum3
Môj návrh použitia novinky
V sekcii “Skaláre” som:
- použila aj tretiu premennú c - išlo konkrétne o zápornú hodnotu, čím
som rozšírila možnosti výpočtov o prácu so znamienkami,
- urobila vlastné zložitejšie kombinácie výpočtových operácií,
- použila ďalšie matematické funkcie, ako sú absolútna hodnota, druhá
odmocnina a zaokrúhľovanie na 1 desatinné miesto,
- som namiesto jedného jednoduchého cvičenia zahrnula tri rôzne úlohy,
kde sa kombinujú mocniny, zlomky, súčty a súčiny.
V sekcii “Text” som:
- pridala malé cvičenie, ktoré rozširuje prácu s textom a dáva
priestor na tvorenie vlastného príkladu.
V sekcii “Logické hodnoty” som:
- pridala viac príkladov logických porovnaní vrátane čísel, výrazov a
textov,
- doplnila jednotlivé operácie o podrobnejšie komentáre,
- ukázala kombinované logické výrazy s AND, OR a negáciou,
- pri zlučovaní logických premenných použila číselný vektor a
podmienkové filtrovanie,
- doplnila 4 bloky cvičení (jeden ku každej podkapitole), ktoré
rozvíjajú základné aj pokročilé znalosti.
V sekcii “Numerické vektory” som:
- pri aritmetických operáciách poukázala na odčítanie, delenie,
mocniny a logaritmickú funkciu,
- rozšírila operácie s dvomi vektormi o rozdiel vektorov,
- pri indexovaní a výbere pridala príklad výberu podľa deliteľnosti,
nielen podľa veľkosti,
- doplnila prácu s chýbajúcimi hodnotami a základné štatistiky o
ďalšie funkcie.
LS0tCnRpdGxlOiAiWsOha2xhZG7DqSBvcGVyw6FjaWUgdiBSIgphdXRob3I6ICJMaW5kYSBLYWthc292w6EgIDxicj4KKHMgdnl1xb5pdMOtbSBDaGF0R1BUKSIKZGF0ZTogIk9rdMOzYmVyIDIwMjUiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0aGVtZTogdW5pdGVkCiAgICBoaWdobGlnaHQ6IHRhbmdvCmVkaXRvcl9vcHRpb25zOiAKICBtYXJrZG93bjogCiAgICB3cmFwOiA3MgotLS0KCgojIMOadm9kIGsgesOha2xhZG7DvW0gb3BlcsOhY2nDoW0gdiBSCgpUZW50byBkb2t1bWVudCBkZW1vbsWhdHJ1amUgcHLDoWN1IHNvICoqesOha2xhZG7DvW1pIHR5cG1pIGhvZG7DtHQqKiB2IFI6CgoqIG51bWVyaWNrw6ksIAoqIHRleHRvdsOpLCAKKiBsb2dpY2vDqSwgCiogdmVrdG9yeSBhIAoqIG1hdGljZS4KClByaSBrYcW+ZGVqIGthdGVnw7NyaWkgc29tIHphaHJudWxhIGFqICoqbWFsw6kgY3ZpxI1lbmlhKiogbmEgc3VtYXJpesOhY2l1IGEgcHJlb3Bha292YW5pZS4KCi0tLQoKIyBTa2Fsw6FyZSAoamVkbm/EjcOtc2VsbsOpIGhvZG5vdHkpCgojIyBOdW1lcmlja8OpIHNrYWzDoXJlCgpgYGB7cn0KYSA8LSA4CmIgPC0gMy41CmMgPC0gLTIKCiMgesOha2xhZG7DqSBvcGVyw6FjaWUKc3VjZXQgPC0gYSArIGIgKyBjCnN1Y2luIDwtIGEgKiBiICogYwpwcmllbWVyIDwtIChhICsgYiArIGMpIC8gMwoKIyBrb21iaW7DoWNpZQp2eXJhejEgPC0gKGFeMiArIGIpIC8gYwp2eXJhejIgPC0gKGEgKiBiKSAtIChiIC8gYykKdnlyYXozIDwtIChhICUlIDMpICsgKGIgJSUgMikKCnJvdW5kKGIsIDEpCmFicyhjKSAgICAgICAjIGFic29sw7p0bmEgaG9kbm90YQpzcXJ0KGEpICAgICAgIyBkcnVow6Egb2Rtb2NuaW5hCgpzdWNldDsgc3VjaW47IHByaWVtZXIKdnlyYXoxOyB2eXJhejI7IHZ5cmF6MwpgYGAKCgojIyBNYWzDqSBjdmnEjWVuaWUKCj4gVnlwb8SNw610YWp0ZSBuYXNsZWR1asO6Y2UgdsO9cmF6eSAocHJpIGhvZG5vdMOhY2ggYSA9IDgsIGIgPSAzLjUsIGMgPSAtMik6CgoxLiBcKFxmcmFje2FeMiArIGJeMn17Y31cKSAgCjIuIFwoXGZyYWN7YX17Yn0gKyBcZnJhY3tifXtjfSArIFxmcmFje2N9e2F9XCkgIAozLiBcKChhK2IrYyleMiAtIChhIFxjZG90IGIgXGNkb3QgYylcKSAgCgpgYGB7cn0KYSA8LSA4OyBiIDwtIDMuNTsgYyA8LSAtMgoKKCAoYV4yICsgYl4yKSAvIGMgKQooIChhL2IpICsgKGIvYykgKyAoYy9hKSApCiggKGErYitjKV4yIC0gKGEqYipjKSApCmBgYAoKLS0tCgojIFRleHQgCgojIyBWeXR2w6FyYW5pZSB0ZXh0b3bDvW1pIHByZW1lbm7DvW1pIGEgcHLDoWNhIHMgbmltaQoKYGBge3J9CmNpdHkgPC0gIkJyYXRpc2xhdmEiICAgICAgICAgICAgICAgICAgICAgIyBwcmVtZW5uw6Egb2JzYWh1asO6Y2EgbsOhem92IG1lc3RhCmZvb2QgPC0gIlBpenphIiAgICAgICAgICAgICAgICAgICAgICAgICAgIyBwcmVtZW5uw6Egb2JzYWh1asO6Y2EgamVkbG8KY29tYm8gPC0gcGFzdGUoY2l0eSwgZm9vZCkgICAgICAgICAgICAgICAjIHNwb2plbmllIHRleHRvdiBzIG1lZHplcm91IG1lZHppIG5pbWkKY29tYm9fbm9zcGFjZSA8LSBwYXN0ZTAoY2l0eSwgZm9vZCkgICAgICAjIHNwb2plbmllIHRleHRvdiBiZXogbWVkemVyeQpsaXN0X2xpbmUgPC0gcGFzdGUoImNvZmZlZSIsICJ0ZWEiLCAianVpY2UiLCBzZXAgPSAiLCIpICAjIHNww6FqYW5pZSB0ZXh0b3YgcyBvZGRlxL5vdmHEjW9tICwKY2l0eTsgZm9vZDsgY29tYm87IGNvbWJvX25vc3BhY2U7IGxpc3RfbGluZSAgICMgdnlww61zYW5pZSB2aWFjZXLDvWNoIHByZW1lbm7DvWNoIHphIHNlYm91CmBgYAoKIyMgRMS6xb5rYSB0ZXh0b3bDqWhvIHJlxaVhemNhLCBwb2RyZcWlYXplYwoKYGBge3J9CnNlbnRlbmNlIDwtICJMZWFybmluZyBSIGlzIGZ1biEiCm5jaGFyKHNlbnRlbmNlKSAgICAgICAgICAgICAgICAgICMgcG/EjWV0IHpuYWtvdiB2IHJlxaVhemNpCnN1YnN0cihzZW50ZW5jZSwgMywgMTApICAgICAgICAgICMgdsO9YmVyIHpuYWtvdiBvZCAzLiBwbyAxMC4gcG96w61jaXUKYGBgCgoKPiBUYWvDvW10byBzcMO0c29ib20gc2EgdiBSIHByYWN1amUgcyB0ZXh0b3bDvW1pIHByZW1lbm7DvW1pLgoKIyMgTWFsw6kgY3ZpxI1lbmllCgo+IFZ5dHZvcnRlIHRleHRvdsO6IHByZW1lbm7DuiBzIG7DoXp2b20gc3ZvamhvIG9ixL7DumJlbsOpaG8gxaFwb3J0dSBhOiAgCj4gLSBzcG9qdGUganUgcyBtZXN0b20sIGtkZSBzYSDFoXBvcnQgaHLDoSwgIAo+IC0gdnl0dm9ydGUgdmVyeml1IGJleiBtZWR6ZXJ5LCAgCj4gLSB6aXN0aXRlIHBvxI1ldCB6bmFrb3YgdiBjZWxvbSByZcWlYXpjaSwgIAo+IC0gdnlww63FoXRlIGliYSBwcnbDqSA0IHpuYWt5LgoKYGBge3J9CnNwb3J0IDwtICJIb2tlaiIgICAgICAgICAgICAgICAgICAgICAjIG7DoXpvdiDFoXBvcnR1CnBsYWNlIDwtICJLb3NpY2UiICAgICAgICAgICAgICAgICAgICAjIG7DoXpvdiBtZXN0YQoKam9pbmVkIDwtIHBhc3RlKHNwb3J0LCBwbGFjZSkgICAgICAgICMgc3BvamVuaWUgcyBtZWR6ZXJvdQpqb2luZWRfbm9zcGFjZSA8LSBwYXN0ZTAoc3BvcnQsIHBsYWNlKSAjIHNwb2plbmllIGJleiBtZWR6ZXJ5CgpuY2hhcihqb2luZWQpICAgICAgICAgICAgICAgICAgICAgICAgIyBwb8SNZXQgem5ha292IHYgY2Vsb20gcmXFpWF6Y2kKc3Vic3RyKGpvaW5lZCwgMSwgNCkgICAgICAgICAgICAgICAgICMgcG9kcmXFpWF6ZWMgLSBwcnbDqSA0IHpuYWt5CmBgYAoKLS0tCgojIExvZ2lja8OpIChib29sb3Zza8OpKSBob2Rub3R5IGEgcHJlbWVubsOpCgojIyBaw6FrbGFkeQoKYGBge3J9CnIgPC0gVFJVRQpzIDwtIEZBTFNFCgohciAgICAgICAgICAgICAgICAgIyBsb2dpY2vDoSBuZWfDoWNpYSAoTk9UKQpyICYgcyAgICAgICAgICAgICAgIyBsb2dpY2vDvSBzw7rEjWluIChBTkQpIC0gcHJhdmRhIGxlbiBrZcSPIG9iaWR2YSBzw7ogVFJVRQpyIHwgcyAgICAgICAgICAgICAgIyBsb2dpY2vDvSBzw7rEjWV0IChPUikgLSBwcmF2ZGEga2XEjyBhc3BvxYggamVkZW4gamUgVFJVRQp4b3IociwgcykgICAgICAgICAgIyBleGtsdXrDrXZuZSBPUiAtIHByYXZkYSBsZW4gYWsgcHJlc25lIGplZGVuIHogbmljaCBqZSBUUlVFCmBgYAoKIyMgTG9naWNrw70gdsO9c2xlZG9rIHBvcm92bsOhdmFuaWEKCmBgYHtyfQo1ID4gMiAgICAgICAgICAgICAgICAgICMgamUgNSB2w6TEjcWhaWUgYWtvIDI/CjEwIDw9IDE1ICAgICAgICAgICAgICAgIyBqZSAxMCBtZW7FoWllIGFsZWJvIHJvdm7DqSAxNT8KImRvZyIgPT0gImRvZyIgICAgICAgICAjIHJvdm5vc8WlIGR2b2NoIHJlxaVhemNvdgoiYXBwbGUiICE9ICJvcmFuZ2UiICAgICMgbmVyb3Zub3PFpSBkdm9jaCByZcWlYXpjb3YKIUZBTFNFICAgICAgICAgICAgICAgICAjIG5lZ8OhY2lhIGhvZG5vdHkgRkFMU0UKCjcgPT0gMyArIDQgICAgICAgICAgICAgIyByb3Zub3PFpSDEjcOtc2xhIGEgdsO9cmF6dQoyMCAhPSA1ICogNSAgICAgICAgICAgICMgcG9yb3ZuYW5pZSBuZXJvdm5vc3RpCjEwMCA+PSAxMF4yICAgICAgICAgICAgIyBtb2NuaW5hIGEgcG9yb3ZuYW5pZQoiY2FyIiA8ICJjYXQiICAgICAgICAgICMgcG9yb3ZuYW5pZSBwb2TEvmEgYWJlY2VkeSAobGV4aWtvZ3JhZmlja3kpCiJab28iID4gImFwcGxlIiAgICAgICAgIyB2ZcS+a8OpIHDDrXNtZW7DoSBzw7ogdiBBU0NJSSBwcmVkIG1hbMO9bWkKYGBgCgojIyBabG/Fvml0ZWrFoWllIGxvZ2lja8OpIG9wZXLDoWNpZQoKYGBge3J9CnkgPC0gMjUKCnkgPj0gMjAgJiB5IDw9IDMwICAgICAgICMgc8O6xI1hc25lIChBTkQpIC0gxI3DrXNsbyBqZSBtZWR6aSAyMCBhIDMwCnkgPCAwIHwgeSA+IDEwMCAgICAgICAgICMgYWxlYm8gKE9SKSAtIMSNw61zbG8gamUgbWVuxaFpZSBha28gMCBhbGVibyB2w6TEjcWhaWUgYWtvIDEwMAooeSA8IDIwICYgeSA+IDEwKSB8ICh5ID4gMzApICAgIyBrb21iaW7DoWNpYSBBTkQgYSBPUiAtIHBsYXTDrSwgYWsgeSBqZSBtZWR6aSAxMCBhIDIwIGFsZWJvIHbDpMSNxaFpZSBha28gMzAKYGBgCgojIyBabHXEjW92YW5pZSB2aWFjZXLDvWNoIGxvZy4gcHJlbWVubsO9Y2ggZG8gdmVrdG9yYQoKYGBge3J9CmNoZWNrcyA8LSBjKFRSVUUsIFRSVUUsIEZBTFNFLCBGQUxTRSwgVFJVRSkgICAjIHZla3RvciBsb2dpY2vDvWNoIGhvZG7DtHQKCmBgYAoKIyMgTWFsw6kgY3ZpxI1lbmllCgojIyMgWsOha2xhZHkKCj4gVnl0dm9ydGUgZHZlIGxvZ2lja8OpIHByZW1lbm7DqSBgYWAgYSBgYmAuICAKPiAtIFppc3RpdGUgbmVnw6FjaXUgYGFgLiAgCj4gLSBWeXBvxI3DrXRhanRlIEFORCAoYCZgKSBhIE9SIChgfGApLiAgCj4gLSBWeXNrw7rFoWFqdGUgYWogWE9SIG1lZHppIG5pbWkuICAKCmBgYHtyfQphIDwtIFRSVUUKYiA8LSBGQUxTRQoKIWEKYSAmIGIKYSB8IGIKeG9yKGEsIGIpCmBgYAoKIyMjIExvZ2lja8O9IHbDvXNsZWRvayBwb3Jvdm7DoXZhbmlhCgo+IFNrb250cm9sdWp0ZSwgxI1pIHBsYXRpYSBuYXNsZWR1asO6Y2UgcG9kbWllbmt5OiAgCj4gLSDEjcOtc2xvIDUwIGplIHbDpMSNxaFpZSBha28gNDAgYSBtZW7FoWllIGFrbyA2MCwgIAo+IC0gxI3DrXNsbyAxNSBuaWUgamUgcm92bsOpIDEwLCAgCj4gLSByZcWlYXplYyAiYmFuYW5hIiBqZSByb3Zuw70gImJhbmFuYSIsICAKPiAtIHJlxaVhemVjICJBcHBsZSIgamUgbWVuxaHDrSBha28gImFwcGxlIiAobGV4aWtvZ3JhZmlja3kpLCAgCj4gLSBvdmVydGUsIMSNaSA3ICsgMyA9IDEwIGEgxI1pIDIwIC0gNSAhPSAxNS4KCmBgYHtyfQpudW0gPC0gNTAKbnVtID49IDQwICYgbnVtIDw9IDYwICAgICAgICMgQU5ECjE1ICE9IDEwICAgICAgICAgICAgICAgICAgICAgIyBuZXJvdm5vc8WlCiJiYW5hbmEiID09ICJiYW5hbmEiICAgICAgICAgIyByb3Zub3PFpSByZcWlYXpjb3YKIkFwcGxlIiA8ICJhcHBsZSIgICAgICAgICAgICAjIGxleGlrb2dyYWZpY2vDqSBwb3Jvdm5hbmllCjcgKyAzID09IDEwICAgICAgICAgICAgICAgICAgIyByb3Zub3PFpSB2w71yYXp1CjIwIC0gNSAhPSAxNSAgICAgICAgICAgICAgICAgICMgbmVyb3Zub3PFpSB2w71yYXp1CmBgYAoKIyMjIFpsb8W+aXRlasWhaWUgbG9naWNrw6kgb3BlcsOhY2llCgo+IFBvdcW+aXRlIMSNw61zbG8gYHkgPC0gMjVgIGE6ICAKPiAtIG92ZXJ0ZSwgxI1pIGplIG1lZHppIDIwIGEgMzAgKEFORCksICAKPiAtIG92ZXJ0ZSwgxI1pIGplIG1lbsWhaWUgYWtvIDAgYWxlYm8gdsOkxI3FoWllIGFrbyAxMDAgKE9SKSwgIAo+IC0ga29tYmludWp0ZSBwb2RtaWVua3k6IG1lZHppIDEwIGEgMjAgYWxlYm8gdsOkxI3FoWllIGFrbyAzMCwgIAo+IC0gdnlza8O6xaFhanRlIG5lZ8OhY2l1IGNlbGVqIGtvbWJpbsOhY2llLiAgCgpgYGB7cn0KeSA8LSAyNQoKeSA+PSAyMCAmIHkgPD0gMzAgICAgICAgICAgICAgICAgICAgICAgICAjIEFORAp5IDwgMCB8IHkgPiAxMDAgICAgICAgICAgICAgICAgICAgICAgICAgICMgT1IKKHkgPCAyMCAmIHkgPiAxMCkgfCAoeSA+IDMwKSAgICAgICAgICAgICAjIGtvbWJpbsOhY2lhIEFORCBhIE9SCiEoICh5IDwgMjAgJiB5ID4gMTApIHwgKHkgPiAzMCkgKSAgICAgICAgIyBuZWfDoWNpYSBjZWxlaiBrb21iaW7DoWNpZQpgYGAKCgojIyMgWmx1xI1vdmFuaWUgdmlhY2Vyw71jaCBsb2cuIHByZW1lbm7DvWNoIGRvIHZla3RvcmEKCj4gVnl0dm9ydGUgdmVrdG9yIGB2YWxzIDwtIGMoNSwgMTUsIDI1LCAzNSwgNDUpYCBhOiAgCj4gLSB6aXN0aXRlLCBrdG9yw6kgaG9kbm90eSBzw7ogdsOkxI3FoWllIGFrbyAyMCwgIAo+IC0ga3RvcsOpIGhvZG5vdHkgc8O6IG1lbsWhaWUgYWtvIDMwLCAgCj4gLSBrdG9yw6kgaG9kbm90eSBzw7ogesOhcm92ZcWIIHbDpMSNxaFpZSBha28gMjAgYSBtZW7FoWllIGFrbyA0MCwgIAo+IC0gc2tvbWJpbnVqdGUgT1IgYSBBTkQgdm8gdsO9cmF6ZSBwcmUga2HFvmTDvSBwcnZvaywgYWJ5IHN0ZSB6aXN0aWxpLCBrdG9yw6kgaG9kbm90eSBzw7ogbWVuxaFpZSBha28gMTAgYWxlYm8gdsOkxI3FoWllIGFrbyA0MC4gIAoKYGBge3J9CnZhbHMgPC0gYyg1LCAxNSwgMjUsIDM1LCA0NSkKCnZhbHMgPiAyMCAgICAgICAgICAgICAgICAgIyBUUlVFIHByZSBwcnZreSB2w6TEjcWhaWUgYWtvIDIwCnZhbHMgPCAzMCAgICAgICAgICAgICAgICAgIyBUUlVFIHByZSBwcnZreSBtZW7FoWllIGFrbyAzMAp2YWxzID4gMjAgJiB2YWxzIDwgNDAgICAgICMga29tYmluw6FjaWEgQU5ECih2YWxzIDwgMTAgfCB2YWxzID4gNDApICAgIyBrb21iaW7DoWNpYSBPUgpgYGAKCgoKLS0tCgojIE51bWVyaWNrw6kgdmVrdG9yeQoKIyMgR2VuZXJvdmFuaWUgdmVrdG9yb3YKCmBgYHtyfQphMSA8LSBjKDEwLCAyMCwgMzAsIDQwKQphMiA8LSA1OjEyICAgICAgICAgICAgICAgICAgICAgICAgIyBwb3N0dXBub3PFpSDEjcOtc2VsIG9kIDUgcG8gMTIKYTMgPC0gc2VxKGZyb20gPSAyLCB0byA9IDQsIGJ5ID0gMC41KSAgICMgcG9zdHVwbm9zxaUgcyBrcm9rb20gMC41CmE0IDwtIHJlcCg3LCB0aW1lcyA9IDYpICAgICAgICAgICAjIHZla3RvciBzbyDFoWllc3RpbWkgc2VkbWnEjWthbWkKYTUgPC0gcnVuaWYoNiwgbWluID0gLTEsIG1heCA9IDEpICMgbsOhaG9kbsOpIMSNw61zbGEgeiBpbnRlcnZhbHUgWy0xLDFdCmE2IDwtIHJub3JtKDYsIG1lYW4gPSA1MCwgc2QgPSAxMCkgIyBub3Jtw6FsbmUgcm96ZGVsZW5pZSBzbyBzdHJlZG9tIDUwCgphMTsgYTI7IGEzOyBhNDsgYTU7IGE2CmBgYAoKIyMgQXJpdG1ldGlja8OpIG9wZXLDoWNpZSBzIHZla3Rvcm1pCgpgYGB7cn0KYiA8LSBjKDIsIDQsIDYsIDgpCmIgLSAzICAgICAgICAgICAgICMga2HFvmTDvSBwcnZvayB6bWVuxaHDrW1lIG8gMwpiIC8gMiAgICAgICAgICAgICAjIGthxb5kw70gcHJ2b2sgdnlkZWzDrW1lIGR2b21pCihiXjIpICsgMSAgICAgICAgICMgZHJ1aMOhIG1vY25pbmEga2HFvmTDqWhvIHBydmt1IHBsdXMgMQpsb2coYikgICAgICAgICAgICAjIHByaXJvZHplbsO9IGxvZ2FyaXRtdXMgcHJ2a292CnN1bShjKDIsNCw2KSwgYygxLDEsMSkpICAgICAgICAgIyBza2Fsw6Fybnkgc8O6xI1pbiAoc2tyw6F0ZW7DoSBmb3JtYSkKY3Jvc3Nwcm9kKGMoMiw0LDYpLCBjKDEsMSwxKSkgICAjIHNrYWzDoXJueSBzw7rEjWluIC0gbWF0aWNhIDF4MQpjKDIsNCw2KSAqIGMoMywzLDMpICAgICAgICAgICAgICMgSGFkYW1hcmRvdiBzw7rEjWluCmBgYAoKIyMgTWF0ZW1hdGlja8OpIG9wZXLDoWNpZSBzIDIgdmVrdG9ybWkgcm92bmFrw6lobyByb3ptZXJ1CgpgYGB7cn0KbGVuZ3RoKGMoMTAsMjAsMzAsNDApKQpsZW5ndGgoYTUpICAgICAgICAgICAjIGTEusW+a2EgdmVrdG9yYSBhNQpjKDEwLDIwLDMwLDQwKSArIGE1ICAjIHPDusSNZXQgdmVrdG9yb3YKYygxMCwyMCwzMCw0MCkgLSBhNSAgIyByb3pkaWVsIHZla3Rvcm92CmBgYAoKIyMgSW5kZXhvdmFuaWUgYSB2w71iZXIgbmlla3RvcnljaCBwcnZrb3YgdmVrdG9yYQoKYGBge3J9CmMxIDwtIGMoOSwgMTUsIDIsIDI3LCA1LCAxOCwgMCkKYzFbM10gICAgICAgICAgIyB0cmV0w60gcHJ2b2sKYzFbMjo1XSAgICAgICAgIyBkcnVow70gYcW+IHBpYXR5IHBydm9rCmMxWy00XSAgICAgICAgICMgdsWhZXRrbyBva3JlbSDFoXR2cnTDqWhvIHBydmt1CmMxW2MxICUlIDMgPT0gMF0gICMgbGVuIHRpZSBwcnZreSwga3RvcsOpIHPDuiBkZWxpdGXEvm7DqSB0cm9taQp3aGljaChjMSA8IDEwKSAjIGluZGV4eSBwcnZrb3YgbWVuxaHDrWNoIGFrbyAxMApgYGAKCiMjIFByw6FjYSBzIGNow71iYWrDumNpbWkgaG9kbm90YW1pCgpgYGB7cn0KZCA8LSBjKE5BLCA0LCA4LCBOQSwgMTIsIDE2KQppcy5uYShkKSAgICAgICAgICAgICAgICAKc3VtKGlzLm5hKGQpKSAgICAgICAgICAgIyBwb8SNZXQgY2jDvWJhasO6Y2ljaCBob2Ruw7R0Cm1lYW4oZCwgbmEucm0gPSBUUlVFKSAgICMgcHJpZW1lciBiZXogTkEKbWVkaWFuKGQsIG5hLnJtID0gVFJVRSkgIyBtZWRpw6FuIGJleiBOQQpgYGAKCiMjIFrDoWtsYWRuw6kgxaF0YXRpc3Rpa3kgYSB1c3BvcmlhZGFuaWUgcHJ2a292IHZla3RvcmEgcG9kxL5hIHZlxL5rb3N0aQoKYGBge3J9CmUgPC0gYygyNSwgNywgMTQsIDMyLCAxOSwgMykKbWVhbihlKSAgICAgICAgICAgICAgICAgIApzZChlKSAgICAgICAgICAgICAgICAgICAgCm1pbihlKSAgICAgICAgICAgICAgICAgICAKbWF4KGUpICAgICAgICAgICAgICAgICAgIApzdW1tYXJ5KGUpICAgICAgICAgICAgICAgCnNvcnQoZSkgICAgICAgICAgICAgICAgICAKc29ydChlLCBkZWNyZWFzaW5nID0gVFJVRSkgCmBgYAoKIyMgTWFsw6kgY3ZpxI1lbmllIDEKPiBWeXR2b3J0ZSB2ZWt0b3IgYGZgIHMgxI3DrXNsYW1pIDUwLi4xMDAgYSB2eXBvxI3DrXRhanRlIGFyaXRtZXRpY2vDvSBwcmllbWVyIHbFoWV0a8O9Y2ggbmVww6FybnljaCDEjcOtc2VsLgoKYGBge3J9CmYgPC0gNTA6MTAwCm1lYW4oZltmICUlIDIgPT0gMV0pCmBgYAoKIyMgTWFsw6kgY3ZpxI1lbmllIDIKPiBWeXR2b3J0ZSB2ZWt0b3IgMTAgbsOhaG9kbsO9Y2ggxI3DrXNlbCB6IGludGVydmFsdSBbLTUsNV0gYSBzcG/EjcOtdGFqdGUsIGtvxL5rbyB6IG5pY2ggamUga2xhZG7DvWNoLgoKYGBge3J9CmcgPC0gcnVuaWYoMTAsIG1pbiA9IC01LCBtYXggPSA1KQpnCnN1bShnID4gMCkKYGBgCgojIyBNYWzDqSBjdmnEjWVuaWUgMwo+IFZ5dHZvcnRlIHZla3RvciBgaGAgcyBob2Rub3RhbWkgb2QgMSBkbyAxMiBhIHppc3RpdGUsIGFrw70gamUgcm96ZGllbCBtZWR6aSBzw7rEjXRvbSDEjcOtc2VsIGRlbGl0ZcS+bsO9Y2ggNCBhIHPDusSNdG9tIMSNw61zZWwgZGVsaXRlxL5uw71jaCAzLgoKYGBge3J9CmggPC0gMToxMgpzdW00IDwtIHN1bShoW2ggJSUgNCA9PSAwXSkKc3VtMyA8LSBzdW0oaFtoICUlIDMgPT0gMF0pCnN1bTQgLSBzdW0zCmBgYAoKIyBNw7RqIG7DoXZyaCBwb3XFvml0aWEgbm92aW5reQo+IFYgc2VrY2lpICoqIlNrYWzDoXJlIioqIHNvbToKCj4qIHBvdcW+aWxhIGFqIHRyZXRpdSBwcmVtZW5uw7ogYyAtIGnFoWxvIGtvbmtyw6l0bmUgbyB6w6Fwb3Juw7ogaG9kbm90dSwgxI3DrW0gc29tIHJvesWhw61yaWxhIG1vxb5ub3N0aSB2w71wb8SNdG92IG8gcHLDoWN1IHNvIHpuYW1pZW5rYW1pLAoKPiogdXJvYmlsYSB2bGFzdG7DqSB6bG/Fvml0ZWrFoWllIGtvbWJpbsOhY2llIHbDvXBvxI10b3bDvWNoIG9wZXLDoWNpw60sCgo+KiBwb3XFvmlsYSDEj2FsxaFpZSBtYXRlbWF0aWNrw6kgZnVua2NpZSwgYWtvIHPDuiBhYnNvbMO6dG5hIGhvZG5vdGEsIGRydWjDoSBvZG1vY25pbmEgYSB6YW9rcsO6aMS+b3ZhbmllIG5hIDEgZGVzYXRpbm7DqSBtaWVzdG8sCgo+KiBzb20gbmFtaWVzdG8gamVkbsOpaG8gamVkbm9kdWNow6lobyBjdmnEjWVuaWEgemFocm51bGEgdHJpIHLDtHpuZSDDumxvaHksIGtkZSBzYSBrb21iaW51asO6IG1vY25pbnksIHpsb21reSwgc8O6xI10eSBhIHPDusSNaW55LgoKPiBWIHNla2NpaSAqKiJUZXh0IioqIHNvbToKCj4qIHByaWRhbGEgbWFsw6kgY3ZpxI1lbmllLCBrdG9yw6kgcm96xaFpcnVqZSBwcsOhY3UgcyB0ZXh0b20gYSBkw6F2YSBwcmllc3RvciBuYSB0dm9yZW5pZSB2bGFzdG7DqWhvIHByw61rbGFkdS4KCj4gViBzZWtjaWkgKioiTG9naWNrw6kgaG9kbm90eSIqKiBzb206Cgo+KiBwcmlkYWxhIHZpYWMgcHLDrWtsYWRvdiBsb2dpY2vDvWNoIHBvcm92bmFuw60gdnLDoXRhbmUgxI3DrXNlbCwgdsO9cmF6b3YgYSB0ZXh0b3YsCgo+KiBkb3BsbmlsYSBqZWRub3RsaXbDqSBvcGVyw6FjaWUgbyBwb2Ryb2JuZWrFoWllIGtvbWVudMOhcmUsCgo+KiB1a8OhemFsYSBrb21iaW5vdmFuw6kgbG9naWNrw6kgdsO9cmF6eSBzIEFORCwgT1IgYSBuZWfDoWNpb3UsCgo+KiBwcmkgemx1xI1vdmFuw60gbG9naWNrw71jaCBwcmVtZW5uw71jaCBwb3XFvmlsYSDEjcOtc2VsbsO9IHZla3RvciBhIHBvZG1pZW5rb3bDqSBmaWx0cm92YW5pZSwKCj4qIGRvcGxuaWxhIDQgYmxva3kgY3ZpxI1lbsOtIChqZWRlbiBrdSBrYcW+ZGVqIHBvZGthcGl0b2xlKSwga3RvcsOpIHJvenbDrWphasO6IHrDoWtsYWRuw6kgYWogcG9rcm/EjWlsw6kgem5hbG9zdGkuCgo+IFYgc2VrY2lpICoqIk51bWVyaWNrw6kgdmVrdG9yeSIqKiBzb206Cgo+KiBwcmkgYXJpdG1ldGlja8O9Y2ggb3BlcsOhY2nDoWNoIHBvdWvDoXphbGEgbmEgb2TEjcOtdGFuaWUsIGRlbGVuaWUsIG1vY25pbnkgYSBsb2dhcml0bWlja8O6IGZ1bmtjaXUsCgo+KiByb3rFocOtcmlsYSBvcGVyw6FjaWUgcyBkdm9taSB2ZWt0b3JtaSBvIHJvemRpZWwgdmVrdG9yb3YsCgo+KiBwcmkgaW5kZXhvdmFuw60gYSB2w71iZXJlIHByaWRhbGEgcHLDrWtsYWQgdsO9YmVydSBwb2TEvmEgZGVsaXRlxL5ub3N0aSwgbmllbGVuIHBvZMS+YSB2ZcS+a29zdGksCgo+KiBkb3BsbmlsYSBwcsOhY3UgcyBjaMO9YmFqw7pjaW1pIGhvZG5vdGFtaSBhIHrDoWtsYWRuw6kgxaF0YXRpc3Rpa3kgbyDEj2FsxaFpZSBmdW5rY2llLg==