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 <- 8
b <- 4

# 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
[1] 8
[1] 4
sum_ab; diff_ab; prod_ab; quot_ab; power_ab; mod_ab;
[1] 12
[1] 4
[1] 32
[1] 2
[1] 4096
[1] 2
round_b; ceil_b; floor_b
[1] 4
[1] 4
[1] 4

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:

\[\frac{(58^3-45)}{10}\]

(58^3 - 45) / 10
[1] 19506.7

Text

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

first <- "Adam"                       # definovanie obsahu textovej premennej first
last  <- "Michalec"                          # 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("košeľa", "sako", "nohavice", sep = ",")  # spojenie textov s oddelovacom ,
first; last; full; full_nospace; csv_line   # bodkočiarka tu nahradzuje odskok na novy riadok 
[1] "Adam"
[1] "Michalec"
[1] "Adam Michalec"
[1] "AdamMichalec"
[1] "košeľa,sako,nohavice"

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

x <- "Mám rád leto"
nchar(x)                 # počet znakov  v retazci "Mám rád leto"
[1] 12
substr(x, 5, 12)          # podreťazec od 5. do 12. znaku
[1] "rád leto"

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

9 < 10
[1] TRUE
9 >= 9
[1] TRUE
"sako" == "sako"
[1] TRUE
"sako" != "košeľa"   # vykricnik je tu v zmysle negacie. Napr.:   !=, !>, !<, !TRUE
[1] TRUE
!TRUE
[1] FALSE

Zložitejšie logické operácie

x <- 25
x > 20 & x < 30      # a sucasne - logicky prienik (sucin)
[1] TRUE
x < 0 | x > 100     # alebo - logicke zjednotenie (sucet)
[1] FALSE
                    # 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(5, 6, 7, 8, 9, 10)
v + 5            # kazdy prvok vektora zvacsime o 10
[1] 10 11 12 13 14 15
v * 3            # kazdy prvok vektora prenasobime 2
[1] 15 18 21 24 27 30
(v + 1) / 4
[1] 1.50 1.75 2.00 2.25 2.50 2.75
exp(v)           # exponencialna funkcia z kazdeho prvku vektora
[1]   148.4132   403.4288  1096.6332  2980.9580  8103.0839 22026.4658
sum(c(1,2,3),c(1,1,1))          # skalarny sucin - vysledok je skalar
[1] 9
crossprod(c(1,2,3),c(1,1,1))    # skalarny sucin - vysledok je matica 1x1
     [,1]
[1,]    6
c(1,2,3)*c(1,1,1)               # Hadamardov sucin (sucin zodpovedajucich prvkov vektora)
[1] 1 2 3

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

length(c(5,6,7,8,9))
[1] 5
length(v)            #vektor v5 je definovany vyssie
[1] 6
c(5,6,7,8,9) + v     # pozor, oba vektory musia mat rovnaky rozmer
[1] 10 12 14 16 18 15

Indexovanie a výber niektorych prvkov vektora

x <- c(6, 13, 4, 19, 8, 1, 22)
x[1]           # indexovanie - novy jedno-prvkovy vektor - prvy prvok vektora x
[1] 6
x[2:4]         # novy vektor s druhym az stvrtym prvkom vektora x
[1] 13  4 19
x[-1]          # novy vektor - vsetky prvky vektora x okrem prvého
[1] 13  4 19  8  1 22
x[x > 10]      # novy vektor definovany prvkami x vacsimi ako 10
[1] 13 19 22

Práca s chýbajúcimi hodnotami

y <- c(5, NA, 10, NA, 20)
is.na(y)
[1] FALSE  TRUE FALSE  TRUE FALSE
mean(y)                 # NA
[1] NA
mean(y, na.rm = TRUE)   # remove NAs
[1] 11.66667

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

z <- c(100, 43, 20, 18, 62)
mean(z)                 # priemerna hodnota
[1] 48.6
sd(z)                  # standardna odchylka
[1] 33.93818
max(z)                  # maximalna hodnota
[1] 100
summary(z)              # rychly prehlad zakladnych statistik o vektore
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   18.0    20.0    43.0    48.6    62.0   100.0 
sort(z)                 # rastuce usporiadanie 
[1]  18  20  43  62 100
sort(z, decreasing = TRUE)  # klesajuce
[1] 100  62  43  20  18

Malé cvičenie

Vytvorte vektor w s číslami 1..20 a vypočítajte sumu všetkých párnych čísel.

w <- 1:30
sum(w[w %% 14 == 2])
[1] 48

Matice

Vytvorenie matíc

m <- matrix(1:7, nrow = 5, ncol = 3)            # hodnoty sú zadavane po stlpcoch
m_byrow <- matrix(1:7, nrow = 3, byrow = TRUE)  # hodnoty su zadavane po riadkoch
m; m_byrow
     [,1] [,2] [,3]
[1,]    1    6    4
[2,]    2    7    5
[3,]    3    1    6
[4,]    4    2    7
[5,]    5    3    1
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    4    5    6
[3,]    7    1    2

Rozmery matice

dim(m)                   # (rows, cols)
[1] 5 3
m
     [,1] [,2] [,3]
[1,]    1    6    4
[2,]    2    7    5
[3,]    3    1    6
[4,]    4    2    7
[5,]    5    3    1

Adresovanie prvkov matice

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

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
     [,1] [,2]
[1,]    6   10
[2,]    8   12
A * B        # Hadamard product - nasobenie po zodpovedajucich prvkoch
     [,1] [,2]
[1,]    5   21
[2,]   12   32
A %*% B      # nasobenie matic
     [,1] [,2]
[1,]   23   31
[2,]   34   46
t(A)         # transpozicia matice A - vymena riadkov a stlpcov
     [,1] [,2]
[1,]    1    2
[2,]    3    4
det(A)       # determinant matice
[1] -2
solve(A)     # inverzia matice (ak je matica regularna - teda inverzia sa da spocitat)
     [,1] [,2]
[1,]   -2  1.5
[2,]    1 -0.5

Zlučovanie vektorov do matíc

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

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

M <- matrix(1:7, nrow = 2)
M
     [,1] [,2] [,3] [,4]
[1,]    1    3    5    7
[2,]    2    4    6    1
apply(M, 1, sum)   # suma po riadkoch
[1] 16 13
apply(M, 2, mean)  # priemery po stĺpcoch
[1] 1.5 3.5 5.5 4.0

Malé cvičenie

Vytvorte maticu 5x5 s hodnotami po riadkoch 1..25, vypočítajte stĺpcové sumy a súčin matíc \(M^t M\).

M2 <- matrix(1:30, nrow = 5, byrow = TRUE)
colSums(M2)
[1] 65 70 75 80 85 90
t(M2) %*% M2
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1205 1270 1335 1400 1465 1530
[2,] 1270 1340 1410 1480 1550 1620
[3,] 1335 1410 1485 1560 1635 1710
[4,] 1400 1480 1560 1640 1720 1800
[5,] 1465 1550 1635 1720 1805 1890
[6,] 1530 1620 1710 1800 1890 1980

LS0tCnRpdGxlOiAiWsOha2xhZG7DqSBvcGVyw6FjaWUgdiBSIgphdXRob3I6ICJBZGFtIE1pY2hhbGVjICA8YnI+CihzIHZ5dcW+aXTDrW0gQ2hhdEdQVCkiCmRhdGU6ICJPa3TDs2JlciAyMDI1IgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdGhlbWU6IHVuaXRlZAogICAgaGlnaGxpZ2h0OiB0YW5nbwplZGl0b3Jfb3B0aW9uczogCiAgbWFya2Rvd246IAogICAgd3JhcDogNzIKLS0tCgojIEdsb2LDoWxuZSBuYXN0YXZlbmllIENodW5rb3YKClYgbmnFvsWhaWUgdXZlZGVub20gQ2h1bmt1IGplIHVyb2JlbsOpIHrDoWtsYWRuw6kgZ2xvYsOhbG5lIG5hc3RhdmVuaWUgQ2h1bmtvdiB2IGNlbG9tIE5vdGVib29rdS4gCgotICoqZWNobyoqIG5hc3RhdnVqZSwgxI1pIGNoY2VtZSB2IE5vdGVib29rdSB2eXBpc292YcWlIGplZG5vdGxpdsOpIGvDs2R5IFIKLSAqKm1lc3NhZ2UqKiBqZSBuYXN0YXZlbsO9IG5hICpGQUxTRSosIMSNbyB6bmFtZW7DoSwgxb5lIHNhIGJ1ZMO6IHBvdGzDocSNYcWlIHByYWNvdm7DqSB2w71zdHVweSB6IFIsIHQuai4gbmFwcsOta2xhZCB2w71zbGVkb2sgb3R2w6FyYW5pYSBrbmnFvm7DrWMsIGEgbmlla3RvcsOpIGluw6kgdsO9c3R1cHksIGt0b3LDqSBhbGUgcHJlIGNlbGtvdsO9IE5vdGVib29rIG5lbWFqw7ogdGFrbWVyIMW+aWFkZW4gdsO9em5hbSBhIHPDuiB2aG9kbsOpIHNrw7RyIHByaSBsYWRlbsOtIGvDs2Rvdi4KLSAqKndhcm5pbmcqKiBuYXN0YXZlbsO9IG5hIEZBTFNFIHBvdGzDocSNYSB6b2JyYXplbmllIGNoeWJvdsO9Y2ggaGzDocWhb2sKCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1UUlVFLGVjaG89VFJVRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVjaG8gPSBUUlVFLAogIG1lc3NhZ2UgPSBGQUxTRSwKICB3YXJuaW5nID0gRkFMU0UKKQpgYGAKCiMgw5p2b2QgayB6w6FrbGFkbsO9bSBvcGVyw6FjacOhbSB2IFIKClRlbnRvIG5vdGVib29rIGRlbW9uxaF0cnVqZSAqKnrDoWtsYWRuw6kgb3BlcsOhY2llKiogdiBqYXp5a3UgUiBzbzoKCi0gc2thbMOhcm55bWkgxI3DrXNsYW1pICh0LmouIDEgxI3DrXNsbyksCi0gdGV4dG92w71taSAoem5ha292w71taSkgcmXFpWF6Y2FtaSwKLSBsb2dpY2vDvW1pIChib29sb3Zza8O9bWkpIGhvZG5vdGFtaSBhIHByZW1lbm7DvW1pLAotIChudW1lcmlja8O9bWkpIHZla3Rvcm1pLAotIG1hdGljYW1pLgoKVGFtLCBrZGUgamUgdG8gdcW+aXRvxI1uw6ksIHPDuiB6YWhybnV0w6kgbWFsw6kgY3ZpxI1lbmlhLgoKLS0tCgojIFNrYWzDoXJlIChqZWRub8SNw61zZWxuw6kgaG9kbm90eSkKCiMjIE51bWVyaWNrw6kgc2thbMOhcmUKCmBgYHtyfQojIFByaXJhZGVuaWUga29uxaF0YW50eSBkbyBwcmVtZW5uZWoKYSA8LSA4CmIgPC0gNAoKIyBBcml0aG1ldGljCnN1bV9hYiAgICAgIDwtIGEgKyBiICAgICAgICAjIHN1Y2V0CmRpZmZfYWIgICAgIDwtIGEgLSBiICAgICAgICAjIHJvemRpZWwKcHJvZF9hYiAgICAgPC0gYSAqIGIgICAgICAgICMgbsOhc29iZW5pZQpxdW90X2FiICAgICA8LSBhIC8gYiAgICAgICAgIyBkZWxlbmllCnBvd2VyX2FiICAgIDwtIGEgXiBiICAgICAgICAjIHVtb2PFiG92YW5pZQptb2RfYWIgICAgICA8LSBhICUlIDMgICAgICAgIyB6Ynl0b2sgcG8gZGVsZW7DrSB0cm9taSAodHp2IG1vZHVsbykKCgojIFJvdW5kaW5nCnJvdW5kX2IgICA8LSByb3VuZChiKSAgICAgICAjIHphb2tydWhsb3ZhbmllIHNtZXJvbSBrIG5hamJsaXpzaWVtdSBjZWxlbXUgY2lzbHUKY2VpbF9iICAgIDwtIGNlaWxpbmcoYikgICAgICMgbmFqYmxpenNpZSB2eXNzaWUgY2VsZSBjaXNsbwpmbG9vcl9iICAgPC0gZmxvb3IoYikgICAgICAgIyBuYWpibGl6c2llIG5penNpZSBjZWxlIGNpc2xvCgphOyBiCnN1bV9hYjsgZGlmZl9hYjsgcHJvZF9hYjsgcXVvdF9hYjsgcG93ZXJfYWI7IG1vZF9hYjsKcm91bmRfYjsgY2VpbF9iOyBmbG9vcl9iCmBgYAoKKipQb3puw6Fta3kqKgoKLSBgXmAgb3BlcsOhdG9yIHVtb2PFiG92YW5pYS4KLSBgJSVgIGplIG1vZHVsbywgdGVkYSB6Ynl0b2sgcG8gZGVsZW7DrSwgCi0gYHJvdW5kKHgsIGRpZ2l0cyA9IDApYCB6YW9rcsO6aMS+b3ZhbmllIG5hIHVyxI1pdMO9IHBvxI1ldCBkZXNhdGlubsO9Y2ggbWllc3QgKGRpZ2l0cz0pLiBhayBkaWdpdHMgPSAwLCBwb3RvbSBpZGUgbyBjZWxvxI3DrXNlbG7DqSB6YW9rcsO6aMS+b3ZhbmllCgoKIyMgTWFsw6kgY3ZpxI1lbmllCgo+IFZ5cG/EjcOtdGFqdGU6CgokJFxmcmFjeyg1OF4zLTQ1KX17MTB9JCQKCmBgYHtyfQooNTheMyAtIDQ1KSAvIDEwCmBgYAoKLS0tCgojIFRleHQgCgojIyBWeXR2w6FyYW5pZSB0ZXh0b3bDvW1pIHByZW1lbm7DvW1pIGEgcHLDoWNhIHMgbmltaQoKYGBge3J9CmZpcnN0IDwtICJBZGFtIiAgICAgICAgICAgICAgICAgICAgICAgIyBkZWZpbm92YW5pZSBvYnNhaHUgdGV4dG92ZWogcHJlbWVubmVqIGZpcnN0Cmxhc3QgIDwtICJNaWNoYWxlYyIgICAgICAgICAgICAgICAgICAgICAgICAgICMgZGVmaW5vdmFuaWUgb2JzYWh1IHRleHQuIHByZW1lbm5laiBsYXN0CmZ1bGwgIDwtIHBhc3RlKGZpcnN0LCBsYXN0KSAgICAgICAgICAgICAgICMgc3BvamVuaWUgZHZvY2ggdGV4dC4gcHJlbWVubnljaCBkbyBqZWRuZWogKHMgbWVkemVyb3UpCmZ1bGxfbm9zcGFjZSA8LSBwYXN0ZTAoZmlyc3QsIGxhc3QpICAgICAgICMgc3BvamVuaWUgYmV6IG1lZHplcnkKY3N2X2xpbmUgPC0gcGFzdGUoImtvxaFlxL5hIiwgInNha28iLCAibm9oYXZpY2UiLCBzZXAgPSAiLCIpICAjIHNwb2plbmllIHRleHRvdiBzIG9kZGVsb3ZhY29tICwKZmlyc3Q7IGxhc3Q7IGZ1bGw7IGZ1bGxfbm9zcGFjZTsgY3N2X2xpbmUgICAjIGJvZGtvxI1pYXJrYSB0dSBuYWhyYWR6dWplIG9kc2tvayBuYSBub3Z5IHJpYWRvayAKYGBgCgojIyBExLrFvmthIHRleHRvdsOpaG8gcmXFpWF6Y2EsIHBvZHJlxaVhemVjCgpgYGB7cn0KeCA8LSAiTcOhbSByw6FkIGxldG8iCm5jaGFyKHgpICAgICAgICAgICAgICAgICAjIHBvxI1ldCB6bmFrb3YgIHYgcmV0YXpjaSAiTcOhbSByw6FkIGxldG8iCnN1YnN0cih4LCA1LCAxMikgICAgICAgICAgIyBwb2RyZcWlYXplYyBvZCA1LiBkbyAxMi4gem5ha3UKYGBgCgoKPiBUaXA6IEtuacW+bmljYSAqKnN0cmluZ3IqKiBtbm9ow6kgemF1asOtbWF2w6kgbW/Fvm5vc3RpIHByw6FjZSBzIHRleHRhbWksIGFsZSBpbXBsaWNpdG7DqSBrbmnFvm5pY2UgUiBwb2tyw712YWrDuiB2w6TEjcWhaW51IGJlxb5uw71jaCBwb3RyaWViIHDDoWNlIHMgdGV4dGFtaS4KCi0tLQoKIyBMb2dpY2vDqSAoYm9vbG92c2vDqSkgaG9kbm90eSBhIHByZW1lbm7DqQoKIyMgWsOha2xhZHkKCmBgYHtyfQpwIDwtIFRSVUUKcSA8LSBGQUxTRQohcCAgICAgICAgICAgICAgICAgIyBOT1QKcCAmIHEgICAgICAgICAgICAgICMgQU5ECnAgfCBxICAgICAgICAgICAgICAjIE9SCnhvcihwLCBxKSAgICAgICAgICAjIGV4Y2x1c2l2ZSBPUiAtIHBsYXTDrSBsZW4gamVkbm8geiBwLGFsZWJvIHEKYGBgCgojIyBMb2dpY2vDvSB2w71zbGVkb2sgcG9yb3Zuw6F2YW5pYQoKYGBge3J9CjkgPCAxMAo5ID49IDkKInNha28iID09ICJzYWtvIgoic2FrbyIgIT0gImtvxaFlxL5hIiAgICMgdnlrcmljbmlrIGplIHR1IHYgem15c2xlIG5lZ2FjaWUuIE5hcHIuOiAgICE9LCAhPiwgITwsICFUUlVFCiFUUlVFCmBgYAoKIyMgWmxvxb5pdGVqxaFpZSBsb2dpY2vDqSBvcGVyw6FjaWUKCmBgYHtyfQp4IDwtIDI1CnggPiAyMCAmIHggPCAzMCAgICAgICMgYSBzdWNhc25lIC0gbG9naWNreSBwcmllbmlrIChzdWNpbikKeCA8IDAgfCB4ID4gMTAwICAgICAjIGFsZWJvIC0gbG9naWNrZSB6amVkbm90ZW5pZSAoc3VjZXQpCiAgICAgICAgICAgICAgICAgICAgIyBwcmkgemxveml0ZWpzaWNoIHZ6dGFob2NoIHBvdXppdmFqdGUgemF0dm9ya3kgKCkKYGBgCgojIyBabHXEjW92YW5pZSB2aWFjZXLDvWNoIGxvZy4gcHJlbWVubsO9Y2ggZG8gdmVrdG9yYQoKYGBge3J9CnZhbHMgPC0gYyhUUlVFLCBGQUxTRSwgVFJVRSwgVFJVRSkgICAjIGRlZmluaWNpYSB2ZWt0b3JhIHMgbG9naWNreW1pIGhvZG5vdGFtaQpgYGAKCi0tLQoKIyBOdW1lcmlja8OpIHZla3RvcnkKCiMjIEdlbmVyb3ZhbmllIHZla3Rvcm92CgpgYGB7cn0KdjEgPC0gYygyLCA0LCA2LCA4KQp2MiA8LSAxOjUgICAgICAgICAgICAgICAgICAjIHBvc3R1cG5vc3QgMSwyLDMsNCw1CnYzIDwtIHNlcShmcm9tID0gMCwgdG8gPSAxLCBieSA9IDAuMjUpICAjIHBvc3R1cG5vc3QgcyBrcm9rb20gMC4yNQp2NCA8LSByZXAoMywgdGltZXMgPSA1KSAgICAjIDMsMywzLDMsMyAgIyA1IGNsZW5uYSBwb3N0dXBub3N0IHRyb2phawp2NSA8LSBydW5pZig1KSAgICAgICAgICAgICAjIGdlbmVyb3ZhbmllIHJvdm5vbWVybmUgcm96ZGVsZW55Y2ggcHJlbWVubnljaCB2IGludGVydmFsZSBbMCwxXQp2NiA8LSBybm9ybSg1KSAgICAgICAgICAgICAjIGdlbmVyb3ZhbmllIG5vcm1hbG5lIHJvemRlbGVueWNoIHByZW1lbm55Y2gKdjE7IHYyOyB2MzsgdjQ7IHY1CmBgYAoKIyMgQXJpdG1ldGlja8OpIG9wZXLDoWNpZSBzIHZla3Rvcm1pCgpgYGB7cn0KdiA8LSBjKDUsIDYsIDcsIDgsIDksIDEwKQp2ICsgNSAgICAgICAgICAgICMga2F6ZHkgcHJ2b2sgdmVrdG9yYSB6dmFjc2ltZSBvIDEwCnYgKiAzICAgICAgICAgICAgIyBrYXpkeSBwcnZvayB2ZWt0b3JhIHByZW5hc29iaW1lIDIKKHYgKyAxKSAvIDQKZXhwKHYpICAgICAgICAgICAjIGV4cG9uZW5jaWFsbmEgZnVua2NpYSB6IGthemRlaG8gcHJ2a3UgdmVrdG9yYQpzdW0oYygxLDIsMyksYygxLDEsMSkpICAgICAgICAgICMgc2thbGFybnkgc3VjaW4gLSB2eXNsZWRvayBqZSBza2FsYXIKY3Jvc3Nwcm9kKGMoMSwyLDMpLGMoMSwxLDEpKSAgICAjIHNrYWxhcm55IHN1Y2luIC0gdnlzbGVkb2sgamUgbWF0aWNhIDF4MQpjKDEsMiwzKSpjKDEsMSwxKSAgICAgICAgICAgICAgICMgSGFkYW1hcmRvdiBzdWNpbiAoc3VjaW4gem9kcG92ZWRhanVjaWNoIHBydmtvdiB2ZWt0b3JhKQpgYGAKCiMjIE1hdGVtYXRpY2vDqSBvcGVyw6FjaWUgcyAyIHZla3Rvcm1pIHJvdm5ha8OpaG8gcm96bWVydQoKYGBge3J9Cmxlbmd0aChjKDUsNiw3LDgsOSkpCmxlbmd0aCh2KSAgICAgICAgICAgICN2ZWt0b3IgdjUgamUgZGVmaW5vdmFueSB2eXNzaWUKYyg1LDYsNyw4LDkpICsgdiAgICAgIyBwb3pvciwgb2JhIHZla3RvcnkgbXVzaWEgbWF0IHJvdm5ha3kgcm96bWVyCmBgYAoKIyMgSW5kZXhvdmFuaWUgYSB2w71iZXIgbmlla3RvcnljaCBwcnZrb3YgdmVrdG9yYQoKYGBge3J9CnggPC0gYyg2LCAxMywgNCwgMTksIDgsIDEsIDIyKQp4WzFdICAgICAgICAgICAjIGluZGV4b3ZhbmllIC0gbm92eSBqZWRuby1wcnZrb3Z5IHZla3RvciAtIHBydnkgcHJ2b2sgdmVrdG9yYSB4CnhbMjo0XSAgICAgICAgICMgbm92eSB2ZWt0b3IgcyBkcnVoeW0gYXogc3R2cnR5bSBwcnZrb20gdmVrdG9yYSB4CnhbLTFdICAgICAgICAgICMgbm92eSB2ZWt0b3IgLSB2c2V0a3kgcHJ2a3kgdmVrdG9yYSB4IG9rcmVtIHBydsOpaG8KeFt4ID4gMTBdICAgICAgIyBub3Z5IHZla3RvciBkZWZpbm92YW55IHBydmthbWkgeCB2YWNzaW1pIGFrbyAxMApgYGAKCiMjIFByw6FjYSBzIGNow71iYWrDumNpbWkgaG9kbm90YW1pCgpgYGB7cn0KeSA8LSBjKDUsIE5BLCAxMCwgTkEsIDIwKQppcy5uYSh5KQptZWFuKHkpICAgICAgICAgICAgICAgICAjIE5BCm1lYW4oeSwgbmEucm0gPSBUUlVFKSAgICMgcmVtb3ZlIE5BcwpgYGAKCiMjIFrDoWtsYWRuw6kgxaF0YXRpc3Rpa3kgYSB1c3BvcmlhZGFuaWUgcHJ2a292IHZla3RvcmEgcG9kxL5hIHZlxL5rb3N0aQoKYGBge3J9CnogPC0gYygxMDAsIDQzLCAyMCwgMTgsIDYyKQptZWFuKHopICAgICAgICAgICAgICAgICAjIHByaWVtZXJuYSBob2Rub3RhCnNkKHopICAgICAgICAgICAgICAgICAgIyBzdGFuZGFyZG5hIG9kY2h5bGthCm1heCh6KSAgICAgICAgICAgICAgICAgICMgbWF4aW1hbG5hIGhvZG5vdGEKc3VtbWFyeSh6KSAgICAgICAgICAgICAgIyByeWNobHkgcHJlaGxhZCB6YWtsYWRueWNoIHN0YXRpc3RpayBvIHZla3RvcmUKc29ydCh6KSAgICAgICAgICAgICAgICAgIyByYXN0dWNlIHVzcG9yaWFkYW5pZSAKc29ydCh6LCBkZWNyZWFzaW5nID0gVFJVRSkgICMga2xlc2FqdWNlCmBgYAoKIyMgTWFsw6kgY3ZpxI1lbmllCj4gVnl0dm9ydGUgdmVrdG9yIGB3YCBzIMSNw61zbGFtaSAxLi4yMCBhIHZ5cG/EjcOtdGFqdGUgc3VtdSB2xaFldGvDvWNoIHDDoXJueWNoIMSNw61zZWwuCgpgYGB7cn0KdyA8LSAxOjMwCnN1bSh3W3cgJSUgMTQgPT0gMl0pCmBgYAoKLS0tCgojIE1hdGljZQoKIyMgVnl0dm9yZW5pZSBtYXTDrWMKCmBgYHtyfQptIDwtIG1hdHJpeCgxOjcsIG5yb3cgPSA1LCBuY29sID0gMykgICAgICAgICAgICAjIGhvZG5vdHkgc8O6IHphZGF2YW5lIHBvIHN0bHBjb2NoCm1fYnlyb3cgPC0gbWF0cml4KDE6NywgbnJvdyA9IDMsIGJ5cm93ID0gVFJVRSkgICMgaG9kbm90eSBzdSB6YWRhdmFuZSBwbyByaWFka29jaAptOyBtX2J5cm93CmBgYAoKIyMgUm96bWVyeSBtYXRpY2UKCmBgYHtyfQpkaW0obSkgICAgICAgICAgICAgICAgICAgIyAocm93cywgY29scykKbQpgYGAKCiMjIEFkcmVzb3ZhbmllIHBydmtvdiBtYXRpY2UKCmBgYHtyfQptWzIsIDJdICAgICAgIyByaWFkb2sgMSwgc3RscGVjIDIKbVsgLCAxXSAgICAgICMgdnNldGt5IHBydmt5IHYgdHJldG9tIHN0bHBjaSAtIHZ5c2xlZG9rIG1hdGljYSAzeDEKbVszLCBdICAgICAgICMgdnNldGt5IHBydmt5IHYgZHJ1aG9tIHJpYWRrdSAtIHZ5c2xlZG9rIG1hdGljYSAxKjMKbVsyOjIsIDM6M10gICMgcG9kbWF0aWNhIHR2b3JlbmEgcmlhZGthbWkgMSwgMiBhIHN0bHBjYW1pIDIsIDMKYGBgCgojIyBNYXRpY292w6kgb3BlcsOhY2llCgpgYGB7cn0KQSA8LSBtYXRyaXgoYygxLDIsMyw0KSwgbnJvdyA9IDIpCkIgPC0gbWF0cml4KGMoNSw2LDcsOCksIG5yb3cgPSAyKQoKQSArIEIgICAgICAgICMgc2NpdGFuaWUgbWF0aWMKQSAqIEIgICAgICAgICMgSGFkYW1hcmQgcHJvZHVjdCAtIG5hc29iZW5pZSBwbyB6b2Rwb3ZlZGFqdWNpY2ggcHJ2a29jaApBICUqJSBCICAgICAgIyBuYXNvYmVuaWUgbWF0aWMKdChBKSAgICAgICAgICMgdHJhbnNwb3ppY2lhIG1hdGljZSBBIC0gdnltZW5hIHJpYWRrb3YgYSBzdGxwY292CmRldChBKSAgICAgICAjIGRldGVybWluYW50IG1hdGljZQpzb2x2ZShBKSAgICAgIyBpbnZlcnppYSBtYXRpY2UgKGFrIGplIG1hdGljYSByZWd1bGFybmEgLSB0ZWRhIGludmVyemlhIHNhIGRhIHNwb2NpdGF0KQpgYGAKCiMjIFpsdcSNb3ZhbmllIHZla3Rvcm92IGRvIG1hdMOtYyAKCmBgYHtyfQpDIDwtIGNiaW5kKDI6MywgMzo1KSAgICMgIC0gcG8gc3RscGNvY2ggCkQgPC0gcmJpbmQoMToyLCA0OjYpICAgIyAgLSBwbyByaWFka29jaCAKQzsgRApgYGAKCiMjIFZ5cG/EjcOtdGFuaWUgenZvbGVuZWogxaF0YXRpc3Rpa3kgcG8gcmlhZGtvY2ggKHN0xLpwY29jaCkgbWF0aWNlCgpgYGB7cn0KTSA8LSBtYXRyaXgoMTo3LCBucm93ID0gMikKTQphcHBseShNLCAxLCBzdW0pICAgIyBzdW1hIHBvIHJpYWRrb2NoCmFwcGx5KE0sIDIsIG1lYW4pICAjIHByaWVtZXJ5IHBvIHN0xLpwY29jaApgYGAKCiMjIE1hbMOpIGN2acSNZW5pZQoKPiBWeXR2b3J0ZSBtYXRpY3UgNXg1IHMgaG9kbm90YW1pIHBvIHJpYWRrb2NoIDEuLjI1LCB2eXBvxI3DrXRhanRlIHN0xLpwY292w6kgc3VteSBhIHPDusSNaW4gbWF0w61jIFwoTV50IE1cKS4KCmBgYHtyfQpNMiA8LSBtYXRyaXgoMTozMCwgbnJvdyA9IDUsIGJ5cm93ID0gVFJVRSkKY29sU3VtcyhNMikKdChNMikgJSolIE0yCmBgYAoKLS0tCgoKCgo=