knitr::opts_chunk$set(
echo = TRUE,
message = FALSE,
warning = FALSE
)

Skaláre (jednočíselné hodnoty) Numerické skaláre

# Priradenie konštanty do premennej

a <- 5
b <- 2.3

# Aritmetické operácie

sum_ab      <- a + b        # súčet
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 %% 4       # zbytok po delení štyrmi (modulo)

# Zaokrúhľovanie

round_b   <- round(b)       # zaokrúhlovanie na najbližšie celé číslo
ceil_b    <- ceiling(b)     # najbližšie vyššie celé číslo
floor_b   <- floor(b)       # najbližšie nižšie celé číslo

a; b
[1] 5
[1] 2.3
sum_ab; diff_ab; prod_ab; quot_ab; power_ab; mod_ab; round_b; ceil_b; floor_b
[1] 7.3
[1] 2.7
[1] 11.5
[1] 2.173913
[1] 40.51641
[1] 1
[1] 2
[1] 3
[1] 2

Vypočítajte:

(12^2 - 3) / 5
[1] 28.2

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

first <- "Natalia"                       # definovanie obsahu textovej premennej first
last  <- "Nadaska"                       # definovanie obsahu textovej premennej last
full  <- paste(first, last)              # spojenie dvoch textových premenných do jednej (s medzerou)
full_nospace <- paste0(first, last)      # spojenie bez medzery
csv_line <- paste("orange", "grape", "peach", sep = ",")  # spojenie textov s oddelovačom ,
first; last; full; full_nospace; csv_line   # bodkočiarka nahrádza odskok na nový riadok
[1] "Natalia"
[1] "Nadaska"
[1] "Natalia Nadaska"
[1] "NataliaNadaska"
[1] "orange,grape,peach"

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

x <- "Learning R!"
nchar(x)                 # počet znakov v reťazci "Learning R!"
[1] 11
substr(x, 1, 5)          # podreťazec od 1. do 5. znaku
[1] "Learn"

Základy

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

Logický výsledok porovnávania

4 < 6
[1] TRUE
8 >= 8
[1] TRUE
"dog" == "dog"
[1] TRUE
"dog" != "cat"   # vykričník je tu v zmysle negácie. Napr.:   !=, !>, !<, !TRUE
[1] TRUE
!TRUE
[1] FALSE

Zložitejšie logické operácie

x <- 15
x > 5 & x < 25      # a súčasne - logický prienik (priesečník)
[1] TRUE
x < 0 | x > 50      # alebo - logické zjednotenie (zjednotenie)
[1] FALSE
# pri zložitejších vzťahoch používajte zatvorky ()

Zlučovanie viacerých logických premenných do vektora

vals <- c(FALSE, TRUE, FALSE, TRUE)   # definícia vektora s logickými hodnotami

Numerické vektory Generovanie vektorov

v1 <- c(3, 6, 9, 12)
v2 <- 1:8                  # postupnosť 1, 2, 3, 4, 5, 6, 7, 8
v3 <- seq(from = 0, to = 2, by = 0.5)  # postupnosť s krokom 0.5
v4 <- rep(5, times = 6)    # 5, 5, 5, 5, 5, 5  # 6-členná postupnosť piatich
v5 <- runif(6)             # generovanie rovnomerne rozdelených čísel v intervale [0,1]
v6 <- rnorm(6)             # generovanie normálne rozdelených čísel
v1; v2; v3; v4; v5
[1]  3  6  9 12
[1] 1 2 3 4 5 6 7 8
[1] 0.0 0.5 1.0 1.5 2.0
[1] 5 5 5 5 5 5
[1] 0.8252619 0.8828875 0.2083422 0.1733242 0.9607667 0.8082044

Aritmetické operácie s vektormi

v <- c(2, 3, 4, 5)
v + 15           # každý prvok vektora zväčšíme o 15
[1] 17 18 19 20
v * 3            # každý prvok vektora vynásobíme 3
[1]  6  9 12 15
(v + 5) / 4
[1] 1.75 2.00 2.25 2.50
exp(v)           # exponenciálna funkcia z každého prvku vektora
[1]   7.389056  20.085537  54.598150 148.413159
sum(c(2,3,4),c(2,2,2))          # skalárny súčin - výsledok je skalar
[1] 15
crossprod(c(2,3,4),c(2,2,2))    # skalárny súčin - výsledok je matica 1x1
     [,1]
[1,]   18
c(2,3,4)*c(2,2,2)               # Hadamardov súčin (súčin zodpovedajúcich prvkov vektora)
[1] 4 6 8

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

length(c(2,3,4,5,6))
[1] 5
length(v5)            # vektor v5 je definovaný vyššie
[1] 6
c(2,3,4,5,6) + v5     # pozor, oba vektory musia mať rovnaký rozmer
[1] 2.825262 3.882888 4.208342 5.173324 6.960767 2.808204

Indexovanie a výber niektorých prvkov vektora

x <- c(7, 14, 5, 21, 9, 0, 28)
x[1]           # indexovanie - nový jedno-prvkový vektor - prvý prvok vektora x
[1] 7
x[2:5]         # nový vektor s druhým až piatym prvkom vektora x
[1] 14  5 21  9
x[-1]          # nový vektor - všetky prvky vektora x okrem prvého
[1] 14  5 21  9  0 28
x[x > 10]      # nový vektor definovaný prvkami x väčšími ako 10
[1] 14 21 28
which(x > 10)  # ktoré prvky zodpovedajú podmienke väčšieho ako 10?
[1] 2 4 7

Práca s chýbajúcimi hodnotami

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

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

z <- c(15, 7, 9, 11, 4)
mean(z)                 # priemerná hodnota
[1] 9.2
sd(z)                   # štandardná odchýlka
[1] 4.147288
max(z)                  # maximálna hodnota
[1] 15
summary(z)              # rýchly prehľad základných štatistík o vektore
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
    4.0     7.0     9.0     9.2    11.0    15.0 
sort(z)                 # rastúce usporiadanie
[1]  4  7  9 11 15
sort(z, decreasing = TRUE)  # klesajúce
[1] 15 11  9  7  4

cvičenie

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

w <- 2:22
sum(w[w %% 2 == 0])
[1] 132

Vytvorenie matíc

m <- matrix(1:15, nrow = 3, ncol = 5)            # hodnoty sú zadávané po stĺpcoch
m_byrow <- matrix(1:15, nrow = 3, byrow = TRUE)  # hodnoty sú zadávané po riadkoch
m; m_byrow
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    4    7   10   13
[2,]    2    5    8   11   14
[3,]    3    6    9   12   15
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    2    3    4    5
[2,]    6    7    8    9   10
[3,]   11   12   13   14   15

Rozmery matice

dim(m)                   # (riadky, stĺpce)
[1] 3 5
m
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    4    7   10   13
[2,]    2    5    8   11   14
[3,]    3    6    9   12   15

Adresovanie prvkov matice

m[1, 2]      # riadok 1, stĺpec 2
[1] 4
m[ , 3]      # všetky prvky v treťom stĺpci - výsledok matica 3x1
[1] 7 8 9
m[2, ]       # všetky prvky v druhom riadku - výsledok matica 1x3
[1]  2  5  8 11 14
m[1:2, 2:3]  # podmatica tvorena riadkami 1, 2 a stĺpcami 2, 3
     [,1] [,2]
[1,]    4    7
[2,]    5    8

Maticové operácie

A <- matrix(c(2,4,6,8), nrow = 2)
B <- matrix(c(3,6,9,12), nrow = 2)

A + B        # sčítanie matic
     [,1] [,2]
[1,]    5   15
[2,]   10   20
A * B        # Hadamard product - násobenie po zodpovedajúcich prvkoch
     [,1] [,2]
[1,]    6   54
[2,]   24   96
A %*% B      # násobenie matic
     [,1] [,2]
[1,]   42   90
[2,]   60  132
t(A)         # transpozícia matice A - výmena riadkov a stĺpcov
     [,1] [,2]
[1,]    2    4
[2,]    6    8
det(A)       # determinant matice
[1] -8
solve(A)     # inverzia matice (ak je matica regulárna - teda inverzia sa dá vypočítať)
     [,1]  [,2]
[1,] -1.0  0.75
[2,]  0.5 -0.25

Zlučovanie vektorov do matíc

C <- cbind(2:4, 5:7)   #  - po stĺpcoch
D <- rbind(3:5, 6:8)   #  - po riadkoch
C; D
     [,1] [,2]
[1,]    2    5
[2,]    3    6
[3,]    4    7
     [,1] [,2] [,3]
[1,]    3    4    5
[2,]    6    7    8

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

M <- matrix(1:12, nrow = 3)
M
     [,1] [,2] [,3] [,4]
[1,]    1    4    7   10
[2,]    2    5    8   11
[3,]    3    6    9   12
apply(M, 1, sum)   # suma po riadkoch
[1] 22 26 30
apply(M, 2, mean)  # priemery po stĺpcoch
[1]  2  5  8 11

cvičenie

Vytvorte maticu 4x4 s hodnotami po riadkoch 1..16, vypočítajte stĺpcové sumy a súčin matíc MtM

M2 <- matrix(1:16, nrow = 4, byrow = TRUE)
colSums(M2)
[1] 28 32 36 40
t(M2) %*% M2
     [,1] [,2] [,3] [,4]
[1,]  276  304  332  360
[2,]  304  336  368  400
[3,]  332  368  404  440
[4,]  360  400  440  480
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQotLS0KdGl0bGU6ICJaw6FrbGFkbsOpIG9wZXLDoWNpZSB2IFIiCmF1dGhvcjogIk5hdGFsaWEgTmFkYXNrYSIKZGF0ZTogIlNlcHRlbWJlciAyMDI1IgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdGhlbWU6IHVuaXRlZAogICAgaGlnaGxpZ2h0OiB0YW5nbwplZGl0b3Jfb3B0aW9uczogCiAgbWFya2Rvd246IAogICAgd3JhcDogNzIKLS0tCmBgYHtyfQprbml0cjo6b3B0c19jaHVuayRzZXQoCmVjaG8gPSBUUlVFLAptZXNzYWdlID0gRkFMU0UsCndhcm5pbmcgPSBGQUxTRQopCgpgYGAKU2thbMOhcmUgKGplZG5vxI3DrXNlbG7DqSBob2Rub3R5KQpOdW1lcmlja8OpIHNrYWzDoXJlCmBgYHtyfQojIFByaXJhZGVuaWUga29uxaF0YW50eSBkbyBwcmVtZW5uZWoKCmEgPC0gNQpiIDwtIDIuMwoKIyBBcml0bWV0aWNrw6kgb3BlcsOhY2llCgpzdW1fYWIgICAgICA8LSBhICsgYiAgICAgICAgIyBzw7rEjWV0CmRpZmZfYWIgICAgIDwtIGEgLSBiICAgICAgICAjIHJvemRpZWwKcHJvZF9hYiAgICAgPC0gYSAqIGIgICAgICAgICMgbsOhc29iZW5pZQpxdW90X2FiICAgICA8LSBhIC8gYiAgICAgICAgIyBkZWxlbmllCnBvd2VyX2FiICAgIDwtIGEgXiBiICAgICAgICAjIHVtb2PFiG92YW5pZQptb2RfYWIgICAgICA8LSBhICUlIDQgICAgICAgIyB6Ynl0b2sgcG8gZGVsZW7DrSDFoXR5cm1pIChtb2R1bG8pCgojIFphb2tyw7poxL5vdmFuaWUKCnJvdW5kX2IgICA8LSByb3VuZChiKSAgICAgICAjIHphb2tyw7pobG92YW5pZSBuYSBuYWpibGnFvsWhaWUgY2Vsw6kgxI3DrXNsbwpjZWlsX2IgICAgPC0gY2VpbGluZyhiKSAgICAgIyBuYWpibGnFvsWhaWUgdnnFocWhaWUgY2Vsw6kgxI3DrXNsbwpmbG9vcl9iICAgPC0gZmxvb3IoYikgICAgICAgIyBuYWpibGnFvsWhaWUgbmnFvsWhaWUgY2Vsw6kgxI3DrXNsbwoKYTsgYgpzdW1fYWI7IGRpZmZfYWI7IHByb2RfYWI7IHF1b3RfYWI7IHBvd2VyX2FiOyBtb2RfYWI7IHJvdW5kX2I7IGNlaWxfYjsgZmxvb3JfYgoKYGBgClZ5cG/EjcOtdGFqdGU6CmBgYHtyfQooMTJeMiAtIDMpIC8gNQoKYGBgClZ5dHbDoXJhbmllIHRleHRvdsO9Y2ggcHJlbWVubsO9Y2ggYSBwcsOhY2EgcyBuaW1pCmBgYHtyfQpmaXJzdCA8LSAiTmF0YWxpYSIgICAgICAgICAgICAgICAgICAgICAgICMgZGVmaW5vdmFuaWUgb2JzYWh1IHRleHRvdmVqIHByZW1lbm5laiBmaXJzdApsYXN0ICA8LSAiTmFkYXNrYSIgICAgICAgICAgICAgICAgICAgICAgICMgZGVmaW5vdmFuaWUgb2JzYWh1IHRleHRvdmVqIHByZW1lbm5laiBsYXN0CmZ1bGwgIDwtIHBhc3RlKGZpcnN0LCBsYXN0KSAgICAgICAgICAgICAgIyBzcG9qZW5pZSBkdm9jaCB0ZXh0b3bDvWNoIHByZW1lbm7DvWNoIGRvIGplZG5laiAocyBtZWR6ZXJvdSkKZnVsbF9ub3NwYWNlIDwtIHBhc3RlMChmaXJzdCwgbGFzdCkgICAgICAjIHNwb2plbmllIGJleiBtZWR6ZXJ5CmNzdl9saW5lIDwtIHBhc3RlKCJvcmFuZ2UiLCAiZ3JhcGUiLCAicGVhY2giLCBzZXAgPSAiLCIpICAjIHNwb2plbmllIHRleHRvdiBzIG9kZGVsb3ZhxI1vbSAsCmZpcnN0OyBsYXN0OyBmdWxsOyBmdWxsX25vc3BhY2U7IGNzdl9saW5lICAgIyBib2Rrb8SNaWFya2EgbmFocsOhZHphIG9kc2tvayBuYSBub3bDvSByaWFkb2sKCmBgYApExLrFvmthIHRleHRvdsOpaG8gcmXFpWF6Y2EsIHBvZHJlxaVhemVjCmBgYHtyfQp4IDwtICJMZWFybmluZyBSISIKbmNoYXIoeCkgICAgICAgICAgICAgICAgICMgcG/EjWV0IHpuYWtvdiB2IHJlxaVhemNpICJMZWFybmluZyBSISIKc3Vic3RyKHgsIDEsIDUpICAgICAgICAgICMgcG9kcmXFpWF6ZWMgb2QgMS4gZG8gNS4gem5ha3UKCmBgYApaw6FrbGFkeQpgYGB7cn0KcCA8LSBUUlVFCnEgPC0gRkFMU0UKIXAgICAgICAgICAgICAgICAgICMgTk9UCnAgJiBxICAgICAgICAgICAgICAjIEFORApwIHwgcSAgICAgICAgICAgICAgIyBPUgp4b3IocCwgcSkgICAgICAgICAgIyBleGNsdXNpdmUgT1IgLSBwbGF0w60gbGVuIGplZG5vIHogcCwgYWxlYm8gcQoKYGBgCkxvZ2lja8O9IHbDvXNsZWRvayBwb3Jvdm7DoXZhbmlhCmBgYHtyfQo0IDwgNgo4ID49IDgKImRvZyIgPT0gImRvZyIKImRvZyIgIT0gImNhdCIgICAjIHZ5a3JpxI1uw61rIGplIHR1IHYgem15c2xlIG5lZ8OhY2llLiBOYXByLjogICAhPSwgIT4sICE8LCAhVFJVRQohVFJVRQoKYGBgClpsb8W+aXRlasWhaWUgbG9naWNrw6kgb3BlcsOhY2llCmBgYHtyfQp4IDwtIDE1CnggPiA1ICYgeCA8IDI1ICAgICAgIyBhIHPDusSNYXNuZSAtIGxvZ2lja8O9IHByaWVuaWsgKHByaWVzZcSNbsOtaykKeCA8IDAgfCB4ID4gNTAgICAgICAjIGFsZWJvIC0gbG9naWNrw6kgemplZG5vdGVuaWUgKHpqZWRub3RlbmllKQojIHByaSB6bG/Fvml0ZWrFocOtY2ggdnrFpWFob2NoIHBvdcW+w612YWp0ZSB6YXR2b3JreSAoKQoKYGBgClpsdcSNb3ZhbmllIHZpYWNlcsO9Y2ggbG9naWNrw71jaCBwcmVtZW5uw71jaCBkbyB2ZWt0b3JhCmBgYHtyfQp2YWxzIDwtIGMoRkFMU0UsIFRSVUUsIEZBTFNFLCBUUlVFKSAgICMgZGVmaW7DrWNpYSB2ZWt0b3JhIHMgbG9naWNrw71taSBob2Rub3RhbWkKCmBgYApOdW1lcmlja8OpIHZla3RvcnkKR2VuZXJvdmFuaWUgdmVrdG9yb3YKYGBge3J9CnYxIDwtIGMoMywgNiwgOSwgMTIpCnYyIDwtIDE6OCAgICAgICAgICAgICAgICAgICMgcG9zdHVwbm9zxaUgMSwgMiwgMywgNCwgNSwgNiwgNywgOAp2MyA8LSBzZXEoZnJvbSA9IDAsIHRvID0gMiwgYnkgPSAwLjUpICAjIHBvc3R1cG5vc8WlIHMga3Jva29tIDAuNQp2NCA8LSByZXAoNSwgdGltZXMgPSA2KSAgICAjIDUsIDUsIDUsIDUsIDUsIDUgICMgNi3EjWxlbm7DoSBwb3N0dXBub3PFpSBwaWF0aWNoCnY1IDwtIHJ1bmlmKDYpICAgICAgICAgICAgICMgZ2VuZXJvdmFuaWUgcm92bm9tZXJuZSByb3pkZWxlbsO9Y2ggxI3DrXNlbCB2IGludGVydmFsZSBbMCwxXQp2NiA8LSBybm9ybSg2KSAgICAgICAgICAgICAjIGdlbmVyb3ZhbmllIG5vcm3DoWxuZSByb3pkZWxlbsO9Y2ggxI3DrXNlbAp2MTsgdjI7IHYzOyB2NDsgdjUKCmBgYApBcml0bWV0aWNrw6kgb3BlcsOhY2llIHMgdmVrdG9ybWkKYGBge3J9CnYgPC0gYygyLCAzLCA0LCA1KQp2ICsgMTUgICAgICAgICAgICMga2HFvmTDvSBwcnZvayB2ZWt0b3JhIHp2w6TEjcWhw61tZSBvIDE1CnYgKiAzICAgICAgICAgICAgIyBrYcW+ZMO9IHBydm9rIHZla3RvcmEgdnluw6Fzb2LDrW1lIDMKKHYgKyA1KSAvIDQKZXhwKHYpICAgICAgICAgICAjIGV4cG9uZW5jacOhbG5hIGZ1bmtjaWEgeiBrYcW+ZMOpaG8gcHJ2a3UgdmVrdG9yYQpzdW0oYygyLDMsNCksYygyLDIsMikpICAgICAgICAgICMgc2thbMOhcm55IHPDusSNaW4gLSB2w71zbGVkb2sgamUgc2thbGFyCmNyb3NzcHJvZChjKDIsMyw0KSxjKDIsMiwyKSkgICAgIyBza2Fsw6Fybnkgc8O6xI1pbiAtIHbDvXNsZWRvayBqZSBtYXRpY2EgMXgxCmMoMiwzLDQpKmMoMiwyLDIpICAgICAgICAgICAgICAgIyBIYWRhbWFyZG92IHPDusSNaW4gKHPDusSNaW4gem9kcG92ZWRhasO6Y2ljaCBwcnZrb3YgdmVrdG9yYSkKCmBgYApNYXRlbWF0aWNrw6kgb3BlcsOhY2llIHMgMiB2ZWt0b3JtaSByb3ZuYWvDqWhvIHJvem1lcnUKYGBge3J9Cmxlbmd0aChjKDIsMyw0LDUsNikpCmxlbmd0aCh2NSkgICAgICAgICAgICAjIHZla3RvciB2NSBqZSBkZWZpbm92YW7DvSB2ecWhxaFpZQpjKDIsMyw0LDUsNikgKyB2NSAgICAgIyBwb3pvciwgb2JhIHZla3RvcnkgbXVzaWEgbWHFpSByb3ZuYWvDvSByb3ptZXIKCmBgYApJbmRleG92YW5pZSBhIHbDvWJlciBuaWVrdG9yw71jaCBwcnZrb3YgdmVrdG9yYQpgYGB7cn0KeCA8LSBjKDcsIDE0LCA1LCAyMSwgOSwgMCwgMjgpCnhbMV0gICAgICAgICAgICMgaW5kZXhvdmFuaWUgLSBub3bDvSBqZWRuby1wcnZrb3bDvSB2ZWt0b3IgLSBwcnbDvSBwcnZvayB2ZWt0b3JhIHgKeFsyOjVdICAgICAgICAgIyBub3bDvSB2ZWt0b3IgcyBkcnVow71tIGHFviBwaWF0eW0gcHJ2a29tIHZla3RvcmEgeAp4Wy0xXSAgICAgICAgICAjIG5vdsO9IHZla3RvciAtIHbFoWV0a3kgcHJ2a3kgdmVrdG9yYSB4IG9rcmVtIHBydsOpaG8KeFt4ID4gMTBdICAgICAgIyBub3bDvSB2ZWt0b3IgZGVmaW5vdmFuw70gcHJ2a2FtaSB4IHbDpMSNxaHDrW1pIGFrbyAxMAp3aGljaCh4ID4gMTApICAjIGt0b3LDqSBwcnZreSB6b2Rwb3ZlZGFqw7ogcG9kbWllbmtlIHbDpMSNxaFpZWhvIGFrbyAxMD8KCmBgYApQcsOhY2EgcyBjaMO9YmFqw7pjaW1pIGhvZG5vdGFtaQpgYGB7cn0KeSA8LSBjKDIsIE5BLCA2LCBOQSwgMTApCmlzLm5hKHkpCm1lYW4oeSkgICAgICAgICAgICAgICAgICMgTkEKbWVhbih5LCBuYS5ybSA9IFRSVUUpICAgIyByZW1vdmUgTkFzCgpgYGAKWsOha2xhZG7DqSDFoXRhdGlzdGlreSBhIHVzcG9yaWFkYW5pZSBwcnZrb3YgdmVrdG9yYSBwb2TEvmEgdmXEvmtvc3RpCmBgYHtyfQp6IDwtIGMoMTUsIDcsIDksIDExLCA0KQptZWFuKHopICAgICAgICAgICAgICAgICAjIHByaWVtZXJuw6EgaG9kbm90YQpzZCh6KSAgICAgICAgICAgICAgICAgICAjIMWhdGFuZGFyZG7DoSBvZGNow71sa2EKbWF4KHopICAgICAgICAgICAgICAgICAgIyBtYXhpbcOhbG5hIGhvZG5vdGEKc3VtbWFyeSh6KSAgICAgICAgICAgICAgIyByw71jaGx5IHByZWjEvmFkIHrDoWtsYWRuw71jaCDFoXRhdGlzdMOtayBvIHZla3RvcmUKc29ydCh6KSAgICAgICAgICAgICAgICAgIyByYXN0w7pjZSB1c3BvcmlhZGFuaWUKc29ydCh6LCBkZWNyZWFzaW5nID0gVFJVRSkgICMga2xlc2Fqw7pjZQoKYGBgCmN2acSNZW5pZQoKVnl0dm9ydGUgdmVrdG9yIHcgcyDEjcOtc2xhbWkgMi4uMjIgYSB2eXBvxI3DrXRhanRlIHN1bXUgdsWhZXRrw71jaCBww6FybnljaCDEjcOtc2VsLgpgYGB7cn0KdyA8LSAyOjIyCnN1bSh3W3cgJSUgMiA9PSAwXSkKCmBgYApWeXR2b3JlbmllIG1hdMOtYwpgYGB7cn0KbSA8LSBtYXRyaXgoMToxNSwgbnJvdyA9IDMsIG5jb2wgPSA1KSAgICAgICAgICAgICMgaG9kbm90eSBzw7ogemFkw6F2YW7DqSBwbyBzdMS6cGNvY2gKbV9ieXJvdyA8LSBtYXRyaXgoMToxNSwgbnJvdyA9IDMsIGJ5cm93ID0gVFJVRSkgICMgaG9kbm90eSBzw7ogemFkw6F2YW7DqSBwbyByaWFka29jaAptOyBtX2J5cm93CgpgYGAKUm96bWVyeSBtYXRpY2UKYGBge3J9CmRpbShtKSAgICAgICAgICAgICAgICAgICAjIChyaWFka3ksIHN0xLpwY2UpCm0KCmBgYApBZHJlc292YW5pZSBwcnZrb3YgbWF0aWNlCmBgYHtyfQptWzEsIDJdICAgICAgIyByaWFkb2sgMSwgc3TEunBlYyAyCm1bICwgM10gICAgICAjIHbFoWV0a3kgcHJ2a3kgdiB0cmXFpW9tIHN0xLpwY2kgLSB2w71zbGVkb2sgbWF0aWNhIDN4MQptWzIsIF0gICAgICAgIyB2xaFldGt5IHBydmt5IHYgZHJ1aG9tIHJpYWRrdSAtIHbDvXNsZWRvayBtYXRpY2EgMXgzCm1bMToyLCAyOjNdICAjIHBvZG1hdGljYSB0dm9yZW5hIHJpYWRrYW1pIDEsIDIgYSBzdMS6cGNhbWkgMiwgMwoKYGBgCk1hdGljb3bDqSBvcGVyw6FjaWUKYGBge3J9CkEgPC0gbWF0cml4KGMoMiw0LDYsOCksIG5yb3cgPSAyKQpCIDwtIG1hdHJpeChjKDMsNiw5LDEyKSwgbnJvdyA9IDIpCgpBICsgQiAgICAgICAgIyBzxI3DrXRhbmllIG1hdGljCkEgKiBCICAgICAgICAjIEhhZGFtYXJkIHByb2R1Y3QgLSBuw6Fzb2JlbmllIHBvIHpvZHBvdmVkYWrDumNpY2ggcHJ2a29jaApBICUqJSBCICAgICAgIyBuw6Fzb2JlbmllIG1hdGljCnQoQSkgICAgICAgICAjIHRyYW5zcG96w61jaWEgbWF0aWNlIEEgLSB2w71tZW5hIHJpYWRrb3YgYSBzdMS6cGNvdgpkZXQoQSkgICAgICAgIyBkZXRlcm1pbmFudCBtYXRpY2UKc29sdmUoQSkgICAgICMgaW52ZXJ6aWEgbWF0aWNlIChhayBqZSBtYXRpY2EgcmVndWzDoXJuYSAtIHRlZGEgaW52ZXJ6aWEgc2EgZMOhIHZ5cG/EjcOtdGHFpSkKCmBgYApabHXEjW92YW5pZSB2ZWt0b3JvdiBkbyBtYXTDrWMKYGBge3J9CkMgPC0gY2JpbmQoMjo0LCA1OjcpICAgIyAgLSBwbyBzdMS6cGNvY2gKRCA8LSByYmluZCgzOjUsIDY6OCkgICAjICAtIHBvIHJpYWRrb2NoCkM7IEQKCmBgYApWeXBvxI3DrXRhbmllIHp2b2xlbmVqIMWhdGF0aXN0aWt5IHBvIHJpYWRrb2NoIChzdMS6cGNvY2gpIG1hdGljZQpgYGB7cn0KTSA8LSBtYXRyaXgoMToxMiwgbnJvdyA9IDMpCk0KYXBwbHkoTSwgMSwgc3VtKSAgICMgc3VtYSBwbyByaWFka29jaAphcHBseShNLCAyLCBtZWFuKSAgIyBwcmllbWVyeSBwbyBzdMS6cGNvY2gKCmBgYApjdmnEjWVuaWUKClZ5dHZvcnRlIG1hdGljdSA0eDQgcyBob2Rub3RhbWkgcG8gcmlhZGtvY2ggMS4uMTYsIHZ5cG/EjcOtdGFqdGUgc3TEunBjb3bDqSBzdW15IGEgc8O6xI1pbiBtYXTDrWMgTXRNCmBgYHtyfQpNMiA8LSBtYXRyaXgoMToxNiwgbnJvdyA9IDQsIGJ5cm93ID0gVFJVRSkKY29sU3VtcyhNMikKdChNMikgJSolIE0yCgpgYGAKCgo=