Globálne nastavenie Chunkov

V nižšie uvedenom Chunku je urobené základné globálne nastavenie Chunkov v celom Notebooku.

  • echo nastavuje, či chceme v Notebooku vypisovať jednotlivé kódy R
  • message je nastavený na FALSE, čo znamená, že sa budú potláčať pracovné výstupy z R, t.j. napríklad výsledok otvárania knižníc, a niektoré iné výstupy, ktoré ale pre celkový Notebook nemajú takmer žiaden význam a sú vhodné skôr pri ladení kódov.
  • warning nastavený na FALSE potláča zobrazenie chybových hlášok
knitr::opts_chunk$set(
  echo = TRUE,
  message = FALSE,
  warning = FALSE
)

Úvod k základným operáciám v R

Tento notebook demonštruje základné operácie v jazyku R so:

  • skalárnymi číslami (t.j. 1 číslo),
  • textovými (znakovými) reťazcami,
  • logickými (boolovskými) hodnotami a premennými,
  • (numerickými) vektormi,
  • maticami.

Tam, kde je to užitočné, sú zahrnuté malé cvičenia.


Skaláre (jednočíselné hodnoty)

Numerické skaláre

# Priradenie konštanty do premennej
a <- 7
b <- 3.5

# Arithmetic
sum_ab      <- a + b        # sucet
diff_ab     <- a - b        # rozdiel
prod_ab     <- a * b        # násobenie
quot_ab     <- a / b        # delenie
power_ab    <- a ^ b        # umocňovanie
mod_ab      <- a %% 3       # zbytok po delení tromi (tzv modulo)


# Rounding
round_b   <- round(b)       # zaokruhlovanie smerom k najblizsiemu celemu cislu
ceil_b    <- ceiling(b)     # najblizsie vyssie cele cislo
floor_b   <- floor(b)       # najblizsie nizsie cele cislo

a; b
sum_ab; diff_ab; prod_ab; quot_ab; power_ab; mod_ab; int_div_ab
round_b; ceil_b; floor_b

Poznámky

  • ^ operátor umocňovania.
  • %% je modulo, teda zbytok po delení,
  • round(x, digits = 0) zaokrúhľovanie na určitý počet desatinných miest (digits=). ak digits = 0, potom ide o celočíselné zaokrúhľovanie

Malé cvičenie

Vypočítajte:

\[(sqrt(12^2 + 5^2) + (8^3 - 2^2)) / (4 * (3+2))\]

vysledok <- (sqrt(12^2 + 5^2) + (8^3 - 2^2)) / (4 * (3+2))
vysledok
[1] 26.05

Text

Vytváranie textovými premennými a práca s nimi

first <- "Vladimir"                       # definovanie obsahu textovej premennej first
last  <- "Gazda"                          # definovanie obsahu text. premennej last
full  <- paste(first, last)               # spojenie dvoch text. premennych do jednej (s medzerou)
full_nospace <- paste0(first, last)       # spojenie bez medzery
csv_line <- paste("apple", "banana", "pear", sep = ",")  # spojenie textov s oddelovacom ,
first; last; full; full_nospace; csv_line   # bodkočiarka tu nahradzuje odskok na novy riadok 

Dĺžka textového reťazca, podreťazec

x <- "R is great!"
nchar(x)                 # počet znakov  v retazci "R is great!"
substr(x, 1, 5)          # podreťazec od 1. do 5. znaku

Tip: Knižnica stringr mnohé zaujímavé možnosti práce s textami, ale implicitné knižnice R pokrývajú väčšinu bežných potrieb páce s textami.


Logické (boolovské) hodnoty a premenné

Základy

p <- TRUE
q <- FALSE
!p                 # NOT
p & q              # AND
p | q              # OR
xor(p, q)          # exclusive OR - platí len jedno z p,alebo q

Logický výsledok porovnávania

3 < 5
7 >= 7
"cat" == "cat"
"cat" != "dog"   # vykricnik je tu v zmysle negacie. Napr.:   !=, !>, !<, !TRUE
!TRUE

Zložitejšie logické operácie

x <- 10
x > 5 & x < 20      # a sucasne - logicky prienik (sucin)
x < 0 | x > 100     # alebo - logicke zjednotenie (sucet)
                    # pri zlozitejsich vztahoch pouzivajte zatvorky ()

Zlučovanie viacerých log. premenných do vektora

vals <- c(TRUE, FALSE, TRUE, TRUE)   # definicia vektora s logickymi hodnotami

Numerické vektory

Generovanie vektorov

v1 <- c(2, 4, 6, 8)
v2 <- 1:5                  # postupnost 1,2,3,4,5
v3 <- seq(from = 0, to = 1, by = 0.25)  # postupnost s krokom 0.25
v4 <- rep(3, times = 5)    # 3,3,3,3,3  # 5 clenna postupnost trojak
v5 <- runif(5)             # generovanie rovnomerne rozdelenych premennych v intervale [0,1]
v6 <- rnorm(5)             # generovanie normalne rozdelenych premennych
v1; v2; v3; v4; v5

Aritmetické operácie s vektormi

v <- c(1, 2, 3, 4)
v + 10           # kazdy prvok vektora zvacsime o 10
v * 2            # kazdy prvok vektora prenasobime 2
(v + 1) / 2
exp(v)           # exponencialna funkcia z kazdeho prvku vektora
sum(c(1,2,3),c(1,1,1))          # skalarny sucin - vysledok je skalar
crossprod(c(1,2,3),c(1,1,1))    # skalarny sucin - vysledok je matica 1x1
c(1,2,3)*c(1,1,1)               # Hadamardov sucin (sucin zodpovedajucich prvkov vektora)

Matematické operácie s 2 vektormi rovnakého rozmeru

length(c(1,2,3,4,5))
length(v5)            #vektor v5 je definovany vyssie
c(1,2,3,4,5) + v5     # pozor, oba vektory musia mat rovnaky rozmer

Indexovanie a výber niektorych prvkov vektora

x <- c(5, 12, 3, 18, 7, 0, 21)
x[1]           # indexovanie - novy jedno-prvkovy vektor - prvy prvok vektora x
x[2:4]         # novy vektor s druhym az stvrtym prvkom vektora x
x[-1]          # novy vektor - vsetky prvky vektora x okrem prvého
x[x > 10]      # novy vektor definovany prvkami x vacsimi ako 10
which(x > 10)  # ktore prvky zodpovedaju podmienke vacsieho ako 10?

Práca s chýbajúcimi hodnotami

y <- c(1, NA, 3, NA, 5)
is.na(y)
mean(y)                 # NA
mean(y, na.rm = TRUE)   # remove NAs

Základné štatistiky a usporiadanie prvkov vektora podľa veľkosti

z <- c(10, 3, 5, 8, 2)
mean(z)                 # priemerna hodnota
sd(z)                  # standardna odchylka
max(z)                  # maximalna hodnota
summary(z)              # rychly prehlad zakladnych statistik o vektore
sort(z)                 # rastuce usporiadanie 
sort(z, decreasing = TRUE)  # klesajuce

Malé cvičenie

Vytvorte vektor x s číslami 1..50. Nájdite všetky čísla, ktoré sú deliteľné 3 alebo 5, a vypočítajte ich priemer.

x <- 1:50
vybrane <- x[x %% 3 == 0 | x %% 5 == 0]
priemer <- mean(vybrane)
priemer
[1] 25.78261

Matice

Vytvorenie matíc

m <- matrix(1:12, nrow = 3, ncol = 4)            # hodnoty sú zadavane po stlpcoch
m_byrow <- matrix(1:12, nrow = 3, byrow = TRUE)  # hodnoty su zadavane po riadkoch
m; m_byrow

Rozmery matice

dim(m)                   # (rows, cols)
m

Adresovanie prvkov matice

m[1, 2]      # riadok 1, stlpec 2
m[ , 3]      # vsetky prvky v tretom stlpci - vysledok matica 3x1
m[2, ]       # vsetky prvky v druhom riadku - vysledok matica 1*3
m[1:2, 2:3]  # podmatica tvorena riadkami 1, 2 a stlpcami 2, 3

Maticové operácie

A <- matrix(c(1,2,3,4), nrow = 2)
B <- matrix(c(5,6,7,8), nrow = 2)

A + B        # scitanie matic
A * B        # Hadamard product - nasobenie po zodpovedajucich prvkoch
A %*% B      # nasobenie matic
t(A)         # transpozicia matice A - vymena riadkov a stlpcov
det(A)       # determinant matice
solve(A)     # inverzia matice (ak je matica regularna - teda inverzia sa da spocitat)

Zlučovanie vektorov do matíc

C <- cbind(1:3, 4:6)   #  - po stlpcoch 
D <- rbind(1:3, 4:6)   #  - po riadkoch 
C; D

Vypočítanie zvolenej štatistiky po riadkoch (stĺpcoch) matice

M <- matrix(1:9, nrow = 3)
M
apply(M, 1, sum)   # suma po riadkoch
apply(M, 2, mean)  # priemery po stĺpcoch

Malé cvičenie

Vytvorte náhodnú maticu A veľkosti 6x6 s hodnotami z intervalu 1..10.

set.seed(123) # aby boli čísla vždy rovnaké pri spustení

# 1. vytvorenie náhodnej matice 6x6
A <- matrix(sample(1:10, 36, replace = TRUE), nrow = 6, ncol = 6)

# 2. súčet prvkov na hlavnej diagonále
diag_sum <- sum(diag(A))

# 3. výpočet inverznej matice
A_inv <- solve(A)

# 4. overenie, že A %*% A_inv ≈ jednotková matica
overenie <- round(A %*% A_inv, 3)
A
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    3    4    9    7    7   10
[2,]    3    6    9   10    5    7
[3,]   10    9    9    9   10    5
[4,]    2   10    3    3    7    7
[5,]    6    5    8    4    9    5
[6,]    5    3   10    1    9    6
diag_sum
[1] 36
A_inv
            [,1]        [,2]        [,3]         [,4]
[1,]  0.18553780 -0.24606143  0.41255809 -0.030828516
[2,] -0.15448260  0.09888927  0.08868865  0.125240848
[3,] -0.17363708  0.19148816  0.01127734 -0.009633911
[4,]  0.01983452  0.07571121 -0.12694095 -0.067437380
[5,] -0.04975632  0.01864445 -0.38155956 -0.030828516
[6,]  0.28335033 -0.20412558  0.18655786  0.036608863
           [,5]       [,6]
[1,] -0.6722203  0.2301938
[2,] -0.3168990  0.1861612
[3,] -0.2652159  0.2888473
[4,]  0.4376063 -0.3015981
[5,]  1.0336620 -0.4462768
[6,] -0.4627678  0.1200272
overenie
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    1    0    0    0    0    0
[2,]    0    1    0    0    0    0
[3,]    0    0    1    0    0    0
[4,]    0    0    0    1    0    0
[5,]    0    0    0    0    1    0
[6,]    0    0    0    0    0    1

#vlastné cvičenie > Máte denné teploty počas 30 dní v mesiaci (náhodné hodnoty od 15 do 35 °C).

set.seed(101) # opakovateľné výsledky

# 1. denné teploty (30 dní)
temp <- sample(15:35, 30, replace = TRUE)

# 2. priemerná teplota
priemer <- mean(temp)

# 3. počet dní nad 30°C
horuce_dni <- sum(temp > 30)

# 4. najteplejší a najchladnejší deň
najteplejsi <- which.max(temp)
najchladnejsi <- which.min(temp)

# 5. anomálie (odchýlky od priemeru)
temp_anom <- temp - priemer

temp
 [1] 23 28 31 17 17 23 17 17 16 34 35 31 28 26 15 27 20 30
[19] 35 24 25 35 35 34 28 22 22 34 20 21
priemer
[1] 25.66667
horuce_dni
[1] 9
najteplejsi
[1] 11
najchladnejsi
[1] 15
temp_anom
 [1]  -2.6666667   2.3333333   5.3333333  -8.6666667
 [5]  -8.6666667  -2.6666667  -8.6666667  -8.6666667
 [9]  -9.6666667   8.3333333   9.3333333   5.3333333
[13]   2.3333333   0.3333333 -10.6666667   1.3333333
[17]  -5.6666667   4.3333333   9.3333333  -1.6666667
[21]  -0.6666667   9.3333333   9.3333333   8.3333333
[25]   2.3333333  -3.6666667  -3.6666667   8.3333333
[29]  -5.6666667  -4.6666667

LS0tCnRpdGxlOiAiWsOha2xhZG7DqSBvcGVyw6FjaWUgdiBSIgphdXRob3I6ICJWbGFkaW3DrXIgR2F6ZGEgIDxicj4KKHMgdnl1xb5pdMOtbSBDaGF0R1BUKSIKZGF0ZTogIlNlcHRlbWJlciAyMDI1IgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdGhlbWU6IHVuaXRlZAogICAgaGlnaGxpZ2h0OiB0YW5nbwplZGl0b3Jfb3B0aW9uczogCiAgbWFya2Rvd246IAogICAgd3JhcDogNzIKLS0tCgojIEdsb2LDoWxuZSBuYXN0YXZlbmllIENodW5rb3YKClYgbmnFvsWhaWUgdXZlZGVub20gQ2h1bmt1IGplIHVyb2JlbsOpIHrDoWtsYWRuw6kgZ2xvYsOhbG5lIG5hc3RhdmVuaWUgQ2h1bmtvdiB2IGNlbG9tIE5vdGVib29rdS4gCgotICoqZWNobyoqIG5hc3RhdnVqZSwgxI1pIGNoY2VtZSB2IE5vdGVib29rdSB2eXBpc292YcWlIGplZG5vdGxpdsOpIGvDs2R5IFIKLSAqKm1lc3NhZ2UqKiBqZSBuYXN0YXZlbsO9IG5hICpGQUxTRSosIMSNbyB6bmFtZW7DoSwgxb5lIHNhIGJ1ZMO6IHBvdGzDocSNYcWlIHByYWNvdm7DqSB2w71zdHVweSB6IFIsIHQuai4gbmFwcsOta2xhZCB2w71zbGVkb2sgb3R2w6FyYW5pYSBrbmnFvm7DrWMsIGEgbmlla3RvcsOpIGluw6kgdsO9c3R1cHksIGt0b3LDqSBhbGUgcHJlIGNlbGtvdsO9IE5vdGVib29rIG5lbWFqw7ogdGFrbWVyIMW+aWFkZW4gdsO9em5hbSBhIHPDuiB2aG9kbsOpIHNrw7RyIHByaSBsYWRlbsOtIGvDs2Rvdi4KLSAqKndhcm5pbmcqKiBuYXN0YXZlbsO9IG5hIEZBTFNFIHBvdGzDocSNYSB6b2JyYXplbmllIGNoeWJvdsO9Y2ggaGzDocWhb2sKCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1UUlVFLGVjaG89VFJVRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVjaG8gPSBUUlVFLAogIG1lc3NhZ2UgPSBGQUxTRSwKICB3YXJuaW5nID0gRkFMU0UKKQpgYGAKCiMgw5p2b2QgayB6w6FrbGFkbsO9bSBvcGVyw6FjacOhbSB2IFIKClRlbnRvIG5vdGVib29rIGRlbW9uxaF0cnVqZSAqKnrDoWtsYWRuw6kgb3BlcsOhY2llKiogdiBqYXp5a3UgUiBzbzoKCi0gc2thbMOhcm55bWkgxI3DrXNsYW1pICh0LmouIDEgxI3DrXNsbyksCi0gdGV4dG92w71taSAoem5ha292w71taSkgcmXFpWF6Y2FtaSwKLSBsb2dpY2vDvW1pIChib29sb3Zza8O9bWkpIGhvZG5vdGFtaSBhIHByZW1lbm7DvW1pLAotIChudW1lcmlja8O9bWkpIHZla3Rvcm1pLAotIG1hdGljYW1pLgoKVGFtLCBrZGUgamUgdG8gdcW+aXRvxI1uw6ksIHPDuiB6YWhybnV0w6kgbWFsw6kgY3ZpxI1lbmlhLgoKLS0tCgojIFNrYWzDoXJlIChqZWRub8SNw61zZWxuw6kgaG9kbm90eSkKCiMjIE51bWVyaWNrw6kgc2thbMOhcmUKCmBgYHtyfQojIFByaXJhZGVuaWUga29uxaF0YW50eSBkbyBwcmVtZW5uZWoKYSA8LSA3CmIgPC0gMy41CgojIEFyaXRobWV0aWMKc3VtX2FiICAgICAgPC0gYSArIGIgICAgICAgICMgc3VjZXQKZGlmZl9hYiAgICAgPC0gYSAtIGIgICAgICAgICMgcm96ZGllbApwcm9kX2FiICAgICA8LSBhICogYiAgICAgICAgIyBuw6Fzb2JlbmllCnF1b3RfYWIgICAgIDwtIGEgLyBiICAgICAgICAjIGRlbGVuaWUKcG93ZXJfYWIgICAgPC0gYSBeIGIgICAgICAgICMgdW1vY8WIb3ZhbmllCm1vZF9hYiAgICAgIDwtIGEgJSUgMyAgICAgICAjIHpieXRvayBwbyBkZWxlbsOtIHRyb21pICh0enYgbW9kdWxvKQoKCiMgUm91bmRpbmcKcm91bmRfYiAgIDwtIHJvdW5kKGIpICAgICAgICMgemFva3J1aGxvdmFuaWUgc21lcm9tIGsgbmFqYmxpenNpZW11IGNlbGVtdSBjaXNsdQpjZWlsX2IgICAgPC0gY2VpbGluZyhiKSAgICAgIyBuYWpibGl6c2llIHZ5c3NpZSBjZWxlIGNpc2xvCmZsb29yX2IgICA8LSBmbG9vcihiKSAgICAgICAjIG5hamJsaXpzaWUgbml6c2llIGNlbGUgY2lzbG8KCmE7IGIKc3VtX2FiOyBkaWZmX2FiOyBwcm9kX2FiOyBxdW90X2FiOyBwb3dlcl9hYjsgbW9kX2FiOyBpbnRfZGl2X2FiCnJvdW5kX2I7IGNlaWxfYjsgZmxvb3JfYgpgYGAKCioqUG96bsOhbWt5KioKCi0gYF5gIG9wZXLDoXRvciB1bW9jxYhvdmFuaWEuCi0gYCUlYCBqZSBtb2R1bG8sIHRlZGEgemJ5dG9rIHBvIGRlbGVuw60sIAotIGByb3VuZCh4LCBkaWdpdHMgPSAwKWAgemFva3LDumjEvm92YW5pZSBuYSB1csSNaXTDvSBwb8SNZXQgZGVzYXRpbm7DvWNoIG1pZXN0IChkaWdpdHM9KS4gYWsgZGlnaXRzID0gMCwgcG90b20gaWRlIG8gY2Vsb8SNw61zZWxuw6kgemFva3LDumjEvm92YW5pZQoKCiMjIE1hbMOpIGN2acSNZW5pZQoKPiBWeXBvxI3DrXRhanRlOgoKJCQoc3FydCgxMl4yICsgNV4yKSArICg4XjMgLSAyXjIpKSAvICg0ICogKDMrMikpJCQgCgpgYGB7cn0KdnlzbGVkb2sgPC0gKHNxcnQoMTJeMiArIDVeMikgKyAoOF4zIC0gMl4yKSkgLyAoNCAqICgzKzIpKQp2eXNsZWRvawpgYGAKCi0tLQoKIyBUZXh0IAoKIyMgVnl0dsOhcmFuaWUgdGV4dG92w71taSBwcmVtZW5uw71taSBhIHByw6FjYSBzIG5pbWkKCmBgYHtyfQpmaXJzdCA8LSAiVmxhZGltaXIiICAgICAgICAgICAgICAgICAgICAgICAjIGRlZmlub3ZhbmllIG9ic2FodSB0ZXh0b3ZlaiBwcmVtZW5uZWogZmlyc3QKbGFzdCAgPC0gIkdhemRhIiAgICAgICAgICAgICAgICAgICAgICAgICAgIyBkZWZpbm92YW5pZSBvYnNhaHUgdGV4dC4gcHJlbWVubmVqIGxhc3QKZnVsbCAgPC0gcGFzdGUoZmlyc3QsIGxhc3QpICAgICAgICAgICAgICAgIyBzcG9qZW5pZSBkdm9jaCB0ZXh0LiBwcmVtZW5ueWNoIGRvIGplZG5laiAocyBtZWR6ZXJvdSkKZnVsbF9ub3NwYWNlIDwtIHBhc3RlMChmaXJzdCwgbGFzdCkgICAgICAgIyBzcG9qZW5pZSBiZXogbWVkemVyeQpjc3ZfbGluZSA8LSBwYXN0ZSgiYXBwbGUiLCAiYmFuYW5hIiwgInBlYXIiLCBzZXAgPSAiLCIpICAjIHNwb2plbmllIHRleHRvdiBzIG9kZGVsb3ZhY29tICwKZmlyc3Q7IGxhc3Q7IGZ1bGw7IGZ1bGxfbm9zcGFjZTsgY3N2X2xpbmUgICAjIGJvZGtvxI1pYXJrYSB0dSBuYWhyYWR6dWplIG9kc2tvayBuYSBub3Z5IHJpYWRvayAKYGBgCgojIyBExLrFvmthIHRleHRvdsOpaG8gcmXFpWF6Y2EsIHBvZHJlxaVhemVjCgpgYGB7cn0KeCA8LSAiUiBpcyBncmVhdCEiCm5jaGFyKHgpICAgICAgICAgICAgICAgICAjIHBvxI1ldCB6bmFrb3YgIHYgcmV0YXpjaSAiUiBpcyBncmVhdCEiCnN1YnN0cih4LCAxLCA1KSAgICAgICAgICAjIHBvZHJlxaVhemVjIG9kIDEuIGRvIDUuIHpuYWt1CmBgYAoKCj4gVGlwOiBLbmnFvm5pY2EgKipzdHJpbmdyKiogbW5vaMOpIHphdWrDrW1hdsOpIG1vxb5ub3N0aSBwcsOhY2UgcyB0ZXh0YW1pLCBhbGUgaW1wbGljaXRuw6kga25pxb5uaWNlIFIgcG9rcsO9dmFqw7ogdsOkxI3FoWludSBiZcW+bsO9Y2ggcG90cmllYiBww6FjZSBzIHRleHRhbWkuCgotLS0KCiMgTG9naWNrw6kgKGJvb2xvdnNrw6kpIGhvZG5vdHkgYSBwcmVtZW5uw6kKCiMjIFrDoWtsYWR5CgpgYGB7cn0KcCA8LSBUUlVFCnEgPC0gRkFMU0UKIXAgICAgICAgICAgICAgICAgICMgTk9UCnAgJiBxICAgICAgICAgICAgICAjIEFORApwIHwgcSAgICAgICAgICAgICAgIyBPUgp4b3IocCwgcSkgICAgICAgICAgIyBleGNsdXNpdmUgT1IgLSBwbGF0w60gbGVuIGplZG5vIHogcCxhbGVibyBxCmBgYAoKIyMgTG9naWNrw70gdsO9c2xlZG9rIHBvcm92bsOhdmFuaWEKCmBgYHtyfQozIDwgNQo3ID49IDcKImNhdCIgPT0gImNhdCIKImNhdCIgIT0gImRvZyIgICAjIHZ5a3JpY25payBqZSB0dSB2IHpteXNsZSBuZWdhY2llLiBOYXByLjogICAhPSwgIT4sICE8LCAhVFJVRQohVFJVRQpgYGAKCiMjIFpsb8W+aXRlasWhaWUgbG9naWNrw6kgb3BlcsOhY2llCgpgYGB7cn0KeCA8LSAxMAp4ID4gNSAmIHggPCAyMCAgICAgICMgYSBzdWNhc25lIC0gbG9naWNreSBwcmllbmlrIChzdWNpbikKeCA8IDAgfCB4ID4gMTAwICAgICAjIGFsZWJvIC0gbG9naWNrZSB6amVkbm90ZW5pZSAoc3VjZXQpCiAgICAgICAgICAgICAgICAgICAgIyBwcmkgemxveml0ZWpzaWNoIHZ6dGFob2NoIHBvdXppdmFqdGUgemF0dm9ya3kgKCkKYGBgCgojIyBabHXEjW92YW5pZSB2aWFjZXLDvWNoIGxvZy4gcHJlbWVubsO9Y2ggZG8gdmVrdG9yYQoKYGBge3J9CnZhbHMgPC0gYyhUUlVFLCBGQUxTRSwgVFJVRSwgVFJVRSkgICAjIGRlZmluaWNpYSB2ZWt0b3JhIHMgbG9naWNreW1pIGhvZG5vdGFtaQpgYGAKCi0tLQoKIyBOdW1lcmlja8OpIHZla3RvcnkKCiMjIEdlbmVyb3ZhbmllIHZla3Rvcm92CgpgYGB7cn0KdjEgPC0gYygyLCA0LCA2LCA4KQp2MiA8LSAxOjUgICAgICAgICAgICAgICAgICAjIHBvc3R1cG5vc3QgMSwyLDMsNCw1CnYzIDwtIHNlcShmcm9tID0gMCwgdG8gPSAxLCBieSA9IDAuMjUpICAjIHBvc3R1cG5vc3QgcyBrcm9rb20gMC4yNQp2NCA8LSByZXAoMywgdGltZXMgPSA1KSAgICAjIDMsMywzLDMsMyAgIyA1IGNsZW5uYSBwb3N0dXBub3N0IHRyb2phawp2NSA8LSBydW5pZig1KSAgICAgICAgICAgICAjIGdlbmVyb3ZhbmllIHJvdm5vbWVybmUgcm96ZGVsZW55Y2ggcHJlbWVubnljaCB2IGludGVydmFsZSBbMCwxXQp2NiA8LSBybm9ybSg1KSAgICAgICAgICAgICAjIGdlbmVyb3ZhbmllIG5vcm1hbG5lIHJvemRlbGVueWNoIHByZW1lbm55Y2gKdjE7IHYyOyB2MzsgdjQ7IHY1CmBgYAoKIyMgQXJpdG1ldGlja8OpIG9wZXLDoWNpZSBzIHZla3Rvcm1pCgpgYGB7cn0KdiA8LSBjKDEsIDIsIDMsIDQpCnYgKyAxMCAgICAgICAgICAgIyBrYXpkeSBwcnZvayB2ZWt0b3JhIHp2YWNzaW1lIG8gMTAKdiAqIDIgICAgICAgICAgICAjIGthemR5IHBydm9rIHZla3RvcmEgcHJlbmFzb2JpbWUgMgoodiArIDEpIC8gMgpleHAodikgICAgICAgICAgICMgZXhwb25lbmNpYWxuYSBmdW5rY2lhIHoga2F6ZGVobyBwcnZrdSB2ZWt0b3JhCnN1bShjKDEsMiwzKSxjKDEsMSwxKSkgICAgICAgICAgIyBza2FsYXJueSBzdWNpbiAtIHZ5c2xlZG9rIGplIHNrYWxhcgpjcm9zc3Byb2QoYygxLDIsMyksYygxLDEsMSkpICAgICMgc2thbGFybnkgc3VjaW4gLSB2eXNsZWRvayBqZSBtYXRpY2EgMXgxCmMoMSwyLDMpKmMoMSwxLDEpICAgICAgICAgICAgICAgIyBIYWRhbWFyZG92IHN1Y2luIChzdWNpbiB6b2Rwb3ZlZGFqdWNpY2ggcHJ2a292IHZla3RvcmEpCmBgYAoKIyMgTWF0ZW1hdGlja8OpIG9wZXLDoWNpZSBzIDIgdmVrdG9ybWkgcm92bmFrw6lobyByb3ptZXJ1CgpgYGB7cn0KbGVuZ3RoKGMoMSwyLDMsNCw1KSkKbGVuZ3RoKHY1KSAgICAgICAgICAgICN2ZWt0b3IgdjUgamUgZGVmaW5vdmFueSB2eXNzaWUKYygxLDIsMyw0LDUpICsgdjUgICAgICMgcG96b3IsIG9iYSB2ZWt0b3J5IG11c2lhIG1hdCByb3ZuYWt5IHJvem1lcgpgYGAKCiMjIEluZGV4b3ZhbmllIGEgdsO9YmVyIG5pZWt0b3J5Y2ggcHJ2a292IHZla3RvcmEKCmBgYHtyfQp4IDwtIGMoNSwgMTIsIDMsIDE4LCA3LCAwLCAyMSkKeFsxXSAgICAgICAgICAgIyBpbmRleG92YW5pZSAtIG5vdnkgamVkbm8tcHJ2a292eSB2ZWt0b3IgLSBwcnZ5IHBydm9rIHZla3RvcmEgeAp4WzI6NF0gICAgICAgICAjIG5vdnkgdmVrdG9yIHMgZHJ1aHltIGF6IHN0dnJ0eW0gcHJ2a29tIHZla3RvcmEgeAp4Wy0xXSAgICAgICAgICAjIG5vdnkgdmVrdG9yIC0gdnNldGt5IHBydmt5IHZla3RvcmEgeCBva3JlbSBwcnbDqWhvCnhbeCA+IDEwXSAgICAgICMgbm92eSB2ZWt0b3IgZGVmaW5vdmFueSBwcnZrYW1pIHggdmFjc2ltaSBha28gMTAKd2hpY2goeCA+IDEwKSAgIyBrdG9yZSBwcnZreSB6b2Rwb3ZlZGFqdSBwb2RtaWVua2UgdmFjc2llaG8gYWtvIDEwPwpgYGAKCiMjIFByw6FjYSBzIGNow71iYWrDumNpbWkgaG9kbm90YW1pCgpgYGB7cn0KeSA8LSBjKDEsIE5BLCAzLCBOQSwgNSkKaXMubmEoeSkKbWVhbih5KSAgICAgICAgICAgICAgICAgIyBOQQptZWFuKHksIG5hLnJtID0gVFJVRSkgICAjIHJlbW92ZSBOQXMKYGBgCgojIyBaw6FrbGFkbsOpIMWhdGF0aXN0aWt5IGEgdXNwb3JpYWRhbmllIHBydmtvdiB2ZWt0b3JhIHBvZMS+YSB2ZcS+a29zdGkKCmBgYHtyfQp6IDwtIGMoMTAsIDMsIDUsIDgsIDIpCm1lYW4oeikgICAgICAgICAgICAgICAgICMgcHJpZW1lcm5hIGhvZG5vdGEKc2QoeikgICAgICAgICAgICAgICAgICAjIHN0YW5kYXJkbmEgb2RjaHlsa2EKbWF4KHopICAgICAgICAgICAgICAgICAgIyBtYXhpbWFsbmEgaG9kbm90YQpzdW1tYXJ5KHopICAgICAgICAgICAgICAjIHJ5Y2hseSBwcmVobGFkIHpha2xhZG55Y2ggc3RhdGlzdGlrIG8gdmVrdG9yZQpzb3J0KHopICAgICAgICAgICAgICAgICAjIHJhc3R1Y2UgdXNwb3JpYWRhbmllIApzb3J0KHosIGRlY3JlYXNpbmcgPSBUUlVFKSAgIyBrbGVzYWp1Y2UKYGBgCgojIyBNYWzDqSBjdmnEjWVuaWUKPiBWeXR2b3J0ZSB2ZWt0b3IgeCBzIMSNw61zbGFtaSAxLi41MC4KTsOhamRpdGUgdsWhZXRreSDEjcOtc2xhLCBrdG9yw6kgc8O6IGRlbGl0ZcS+bsOpIDMgYWxlYm8gNSwgYSB2eXBvxI3DrXRhanRlIGljaCBwcmllbWVyLiAKCmBgYHtyfQp4IDwtIDE6NTAKdnlicmFuZSA8LSB4W3ggJSUgMyA9PSAwIHwgeCAlJSA1ID09IDBdCnByaWVtZXIgPC0gbWVhbih2eWJyYW5lKQpwcmllbWVyCmBgYAoKLS0tCgojIE1hdGljZQoKIyMgVnl0dm9yZW5pZSBtYXTDrWMKCmBgYHtyfQptIDwtIG1hdHJpeCgxOjEyLCBucm93ID0gMywgbmNvbCA9IDQpICAgICAgICAgICAgIyBob2Rub3R5IHPDuiB6YWRhdmFuZSBwbyBzdGxwY29jaAptX2J5cm93IDwtIG1hdHJpeCgxOjEyLCBucm93ID0gMywgYnlyb3cgPSBUUlVFKSAgIyBob2Rub3R5IHN1IHphZGF2YW5lIHBvIHJpYWRrb2NoCm07IG1fYnlyb3cKYGBgCgojIyBSb3ptZXJ5IG1hdGljZQoKYGBge3J9CmRpbShtKSAgICAgICAgICAgICAgICAgICAjIChyb3dzLCBjb2xzKQptCmBgYAoKIyMgQWRyZXNvdmFuaWUgcHJ2a292IG1hdGljZQoKYGBge3J9Cm1bMSwgMl0gICAgICAjIHJpYWRvayAxLCBzdGxwZWMgMgptWyAsIDNdICAgICAgIyB2c2V0a3kgcHJ2a3kgdiB0cmV0b20gc3RscGNpIC0gdnlzbGVkb2sgbWF0aWNhIDN4MQptWzIsIF0gICAgICAgIyB2c2V0a3kgcHJ2a3kgdiBkcnVob20gcmlhZGt1IC0gdnlzbGVkb2sgbWF0aWNhIDEqMwptWzE6MiwgMjozXSAgIyBwb2RtYXRpY2EgdHZvcmVuYSByaWFka2FtaSAxLCAyIGEgc3RscGNhbWkgMiwgMwpgYGAKCiMjIE1hdGljb3bDqSBvcGVyw6FjaWUKCmBgYHtyfQpBIDwtIG1hdHJpeChjKDEsMiwzLDQpLCBucm93ID0gMikKQiA8LSBtYXRyaXgoYyg1LDYsNyw4KSwgbnJvdyA9IDIpCgpBICsgQiAgICAgICAgIyBzY2l0YW5pZSBtYXRpYwpBICogQiAgICAgICAgIyBIYWRhbWFyZCBwcm9kdWN0IC0gbmFzb2JlbmllIHBvIHpvZHBvdmVkYWp1Y2ljaCBwcnZrb2NoCkEgJSolIEIgICAgICAjIG5hc29iZW5pZSBtYXRpYwp0KEEpICAgICAgICAgIyB0cmFuc3BvemljaWEgbWF0aWNlIEEgLSB2eW1lbmEgcmlhZGtvdiBhIHN0bHBjb3YKZGV0KEEpICAgICAgICMgZGV0ZXJtaW5hbnQgbWF0aWNlCnNvbHZlKEEpICAgICAjIGludmVyemlhIG1hdGljZSAoYWsgamUgbWF0aWNhIHJlZ3VsYXJuYSAtIHRlZGEgaW52ZXJ6aWEgc2EgZGEgc3BvY2l0YXQpCmBgYAoKIyMgWmx1xI1vdmFuaWUgdmVrdG9yb3YgZG8gbWF0w61jIAoKYGBge3J9CkMgPC0gY2JpbmQoMTozLCA0OjYpICAgIyAgLSBwbyBzdGxwY29jaCAKRCA8LSByYmluZCgxOjMsIDQ6NikgICAjICAtIHBvIHJpYWRrb2NoIApDOyBECmBgYAoKIyMgVnlwb8SNw610YW5pZSB6dm9sZW5laiDFoXRhdGlzdGlreSBwbyByaWFka29jaCAoc3TEunBjb2NoKSBtYXRpY2UKCmBgYHtyfQpNIDwtIG1hdHJpeCgxOjksIG5yb3cgPSAzKQpNCmFwcGx5KE0sIDEsIHN1bSkgICAjIHN1bWEgcG8gcmlhZGtvY2gKYXBwbHkoTSwgMiwgbWVhbikgICMgcHJpZW1lcnkgcG8gc3TEunBjb2NoCmBgYAoKIyMgTWFsw6kgY3ZpxI1lbmllCgo+Vnl0dm9ydGUgbsOhaG9kbsO6IG1hdGljdSBBIHZlxL5rb3N0aSA2eDYgcyBob2Rub3RhbWkgeiBpbnRlcnZhbHUgMS4uMTAuCgoKYGBge3J9CnNldC5zZWVkKDEyMykgIyBhYnkgYm9saSDEjcOtc2xhIHbFvmR5IHJvdm5ha8OpIHByaSBzcHVzdGVuw60KCiMgMS4gdnl0dm9yZW5pZSBuw6Fob2RuZWogbWF0aWNlIDZ4NgpBIDwtIG1hdHJpeChzYW1wbGUoMToxMCwgMzYsIHJlcGxhY2UgPSBUUlVFKSwgbnJvdyA9IDYsIG5jb2wgPSA2KQoKIyAyLiBzw7rEjWV0IHBydmtvdiBuYSBobGF2bmVqIGRpYWdvbsOhbGUKZGlhZ19zdW0gPC0gc3VtKGRpYWcoQSkpCgojIDMuIHbDvXBvxI1ldCBpbnZlcnpuZWogbWF0aWNlCkFfaW52IDwtIHNvbHZlKEEpCgojIDQuIG92ZXJlbmllLCDFvmUgQSAlKiUgQV9pbnYg4omIIGplZG5vdGtvdsOhIG1hdGljYQpvdmVyZW5pZSA8LSByb3VuZChBICUqJSBBX2ludiwgMykKQQpkaWFnX3N1bQpBX2ludgpvdmVyZW5pZQpgYGAKI3ZsYXN0bsOpIGN2acSNZW5pZQo+IE3DoXRlIGRlbm7DqSB0ZXBsb3R5IHBvxI1hcyAzMCBkbsOtIHYgbWVzaWFjaSAobsOhaG9kbsOpIGhvZG5vdHkgb2QgMTUgZG8gMzUgwrBDKS4KCmBgYHtyfQpzZXQuc2VlZCgxMDEpICMgb3Bha292YXRlxL5uw6kgdsO9c2xlZGt5CgojIDEuIGRlbm7DqSB0ZXBsb3R5ICgzMCBkbsOtKQp0ZW1wIDwtIHNhbXBsZSgxNTozNSwgMzAsIHJlcGxhY2UgPSBUUlVFKQoKIyAyLiBwcmllbWVybsOhIHRlcGxvdGEKcHJpZW1lciA8LSBtZWFuKHRlbXApCgojIDMuIHBvxI1ldCBkbsOtIG5hZCAzMMKwQwpob3J1Y2VfZG5pIDwtIHN1bSh0ZW1wID4gMzApCgojIDQuIG5hanRlcGxlasWhw60gYSBuYWpjaGxhZG5lasWhw60gZGXFiApuYWp0ZXBsZWpzaSA8LSB3aGljaC5tYXgodGVtcCkKbmFqY2hsYWRuZWpzaSA8LSB3aGljaC5taW4odGVtcCkKCiMgNS4gYW5vbcOhbGllIChvZGNow71sa3kgb2QgcHJpZW1lcnUpCnRlbXBfYW5vbSA8LSB0ZW1wIC0gcHJpZW1lcgoKdGVtcApwcmllbWVyCmhvcnVjZV9kbmkKbmFqdGVwbGVqc2kKbmFqY2hsYWRuZWpzaQp0ZW1wX2Fub20KYGBgCgotLS0KCgoKCg==