Globálne nastavenie Chunkov

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

  • echo: či vypisovať kód R v dokumente,
  • message = FALSE: potláča informatívne hlášky (napr. pri načítaní balíkov),
  • warning = FALSE: potláča varovania (nie chyby).
knitr::opts_chunk$set(
  echo = TRUE,
  message = FALSE,
  warning = FALSE)

Skaláre (jednočíselné hodnoty)

Numerické skaláre

# Priradenie konštánt do premenných
a <- 5
b <- 12.5

# Aritmetika
sum_ab   <- a + b        # súčet
diff_ab  <- a - b        # rozdiel
prod_ab  <- a * b        # násobenie
quot_ab  <- a / b        # delenie (reálne)
power_ab <- a ^ b        # mocnina

# Modulo a celočíselné delenie (príklad s celým deliteľom)
mod_a5     <- a %% 5     # zvyšok po delení piatimi
int_div_a5 <- a %/% 5    # celočíselné delenie (floor(a/5))

# Zaokrúhľovanie
round_b <- round(b)      # na najbližšie celé číslo
ceil_b  <- ceiling(b)    # nahor
floor_b <- floor(b)      # nadol

a; b
[1] 5
[1] 12.5
sum_ab; diff_ab; prod_ab; quot_ab; power_ab
[1] 17.5
[1] -7.5
[1] 62.5
[1] 0.4
[1] 545915034
mod_a5; int_div_a5
[1] 0
[1] 1
round_b; ceil_b; floor_b
[1] 12
[1] 13
[1] 12

Malé cvičenie

Vypočítaj

3*(10^2 - 10) / 3
[1] 90

Text

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

first <- "Sára"
middle <- "Nikol"
last  <- "Scholtzová"

full  <- paste(first,middle, last)                    # spojenie s medzerou
full_nospace <- paste0(first, middle, last)            # bez medzery
csv_line <- paste("Auto", "Bicykel", "Motorka", sep = ",")  # vlastný oddeľovač

first; middle; last; full; full_nospace; csv_line
[1] "Sára"
[1] "Nikol"
[1] "Scholtzová"
[1] "Sára Nikol Scholtzová"
[1] "SáraNikolScholtzová"
[1] "Auto,Bicykel,Motorka"

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

x <- "Ekonometria ma baví!"
nchar(x)                 # počet znakov v reťazci
[1] 20
substr(x, 1, 7)          # podreťazec od 1. do 5. znaku
[1] "Ekonome"
# Ďalšie užitočné drobnosti:
toupper("Milujem Slovensko")    # na VEĽKÉ písmená
[1] "MILUJEM SLOVENSKO"
tolower("Milujem Slovensko")    # na malé písmená
[1] "milujem slovensko"
trimws("  Cesta okolo Sveta  ")  # orezanie okrajových medzier
[1] "Cesta okolo Sveta"

Malé cvičenie

Nech name <- “Janko Mrkvička”. Vypíšte priezvisko ako podreťazec a vytvorte reťazec label v tvare “Priezvisko: Mrkvička (dĺžka: 8)”.

name <- "Janko Mrkvička"
surname <- sub(".* ", "", name)            # všetko po poslednej medzere
label <- paste0("Priezvisko: ", toupper(surname),
                " (dĺžka: ", nchar(surname), ")")
surname; label
[1] "Mrkvička"
[1] "Priezvisko: MRKVIČKA (dĺžka: 8)"

Logické (boolovské) hodnoty a premenné

Základy

p <- FALSE
q <- TRUE

!q          # NOT
[1] FALSE
p & q       # AND (prvkové pri vektoroch)
[1] FALSE
p | q       # OR  (prvkové pri vektoroch)
[1] TRUE
xor(p, q)   # exkluzívne OR (pravda, ak platí presne jedno z p, q)
[1] TRUE

Logický výsledok porovnávania

9 < 4
[1] FALSE
10 >= 10
[1] TRUE
"Girl" == "Girl"
[1] TRUE
"Girl" != "Boy"
[1] TRUE
!TRUE
[1] FALSE

Zložitejšie logické operácie

x <- 5
x > 3 & x < 10      # a súčasne
[1] TRUE
x < 0 | x > 30     # alebo
[1] FALSE
# pri zložitejších vzťahoch používajte zátvorky ()

Malé cvičenie

Majte premennú temp <- 18. Vytvorte dve logické premenne: is_room_temp je TRUE, ak je temp v intervale <18; 24>, is_cold_or_hot je TRUE, ak je temp < 18 alebo temp > 24.

temp <- 15
is_room_temp  <- (temp >= 18) & (temp <= 24)
is_cold_or_hot <- (temp < 18) | (temp > 24)
is_room_temp; is_cold_or_hot
[1] FALSE
[1] TRUE

Môj návrh použitia novinky

# 1) Celočíselné delenie a modulo spolu:
# Rozložme 137 minút na hodiny a zvyšné minúty.
minutes <- 137
hours   <- minutes %/% 60
rem     <- minutes %% 60
sprintf("%d min = %d h %d min", minutes, hours, rem)
[1] "137 min = 2 h 17 min"
# 2) Základné vyhľadávanie vzoru v texte (base R)
cities <- c("Bratislava", "Košice", "Banská Bystrica", "Brno")
grepl("^B", cities)                        # začína na 'B'?
[1]  TRUE FALSE  TRUE  TRUE
cities[grepl("ava$", cities)]              # končí sa na 'ava'?
[1] "Bratislava"
# 3) Pekné formátovanie textu s číslami cez sprintf()
pi_val <- pi
sprintf("π ≈ %.4f", pi_val)               # 4 desatinné miesta
[1] "π ≈ 3.1416"
sprintf("Počet: %03d kusy", 7)            # doplnenie núl na 3 cifry: 007
[1] "Počet: 007 kusy"

Numerické vektory

Generovanie vektorov

set.seed(123)  # aby náhodné príklady boli reprodukovateľné

v1 <- c(3,6,1,9)
v2 <- 1:5                                  # postupnosť 1,2,3,4,5
v3 <- seq(from = 0, to = 1, by = 0.5)     # postupnosť s krokom 0.5
v4 <- rep(1, times = 5)                    # 1,1,1,1,1
v5 <- runif(3)                             # U[0,1]
v6 <- rnorm(3)                             # N(0,1)
v1; v2; v3; v4; v5; v6
[1] 3 6 1 9
[1] 1 2 3 4 5
[1] 0.0 0.5 1.0
[1] 1 1 1 1 1
[1] 0.2875775 0.7883051 0.4089769
[1]  1.190207 -1.689556  1.239496

Aritmetické operácie s vektormi

v <- c(3,5,9,5)
v + 5                  # posun o konštantu
[1]  8 10 14 10
v * 3                  # škálovanie
[1]  9 15 27 15
(v + 3) / 2
[1] 3 4 6 4
exp(v)                 # po-prvková exp()
[1]   20.08554  148.41316 8103.08393  148.41316
# "Skalárny súčin" dvoch vektorov rovnakej dĺžky:
x <- c(1,2,3); y <- c(1,1,1)
sum(x * y)            # skutočný skalárny súčin (výsledok skalar)
[1] 6
crossprod(x, y)       # to isté, ale ako matica 1x1
     [,1]
[1,]    6
# Hadamardov súčin (po-prvkové násobenie):
x * y
[1] 1 2 3

Operácie s dvomi vektormi (rovnaký rozmer)

length(c(1,2,3,4,5,6))
[1] 6
length(v1)                 # (z predchádzajúceho chunku)
[1] 4
# POZOR na recyklovanie dĺžok – najlepšie je mať rovnaké dĺžky:
try(c(1,2,3,4) + v1)     # ak sú rovnaké, OK
[1]  4  8  4 13

Indexovanie a výber prvkov

x <- c(9, 14, 2, 27, 11, 5, 0)
x[1]            # prvý prvok
[1] 9
x[2:4]          # 2. až 4. prvok
[1] 14  2 27
x[-1]           # všetko okrem prvého
[1] 14  2 27 11  5  0
x[x > 10]       # prvky väčšie ako 10 (logická maska)
[1] 14 27 11
which(x > 10)   # indexy prvkov väčších ako 10
[1] 2 4 5

Základné štatistiky a usporiadanie

z <- c(12,5,1,8,0)
mean(z)                 # priemer
[1] 5.2
sd(z)                   # štandardná odchýlka
[1] 4.969909
max(z)                  # maximum
[1] 12
summary(z)              # rýchly prehľad
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
    0.0     1.0     5.0     5.2     8.0    12.0 
sort(z)                 # rastúco
[1]  0  1  5  8 12
sort(z, decreasing = TRUE)  # klesajúco
[1] 12  8  5  1  0

Práca s chýbajúcimi hodnotami

y <- c(1, NA, 3, NA, 5)
is.na(y)
[1] FALSE  TRUE FALSE  TRUE FALSE
anyNA(y)
[1] TRUE
mean(y)                       # NA
[1] NA
mean(y, na.rm = TRUE)         # ignoruje NA
[1] 3

Malé cvičenie

Vytvorte vektor w s číslami 5..35 a vypočítajte súčet všetkých násobkov 3.

# Riešenie A: filtrovanie cez modulo
w <- 5:35
sum(w[w %% 3 == 0])
[1] 195
# Riešenie B: priamo si vytvor násobky 3 v rozsahu
sum(seq(from = 6, to = 33, by = 3))
[1] 195

Matice

Vytvorenie matíc

m <- matrix(2:13, nrow = 3, ncol = 4)            # plní sa po stĺpcoch (2..13)
m_byrow <- matrix(20:31, nrow = 3, byrow = TRUE) # plní sa po riadkoch (20..31)
m; m_byrow
     [,1] [,2] [,3] [,4]
[1,]    2    5    8   11
[2,]    3    6    9   12
[3,]    4    7   10   13
     [,1] [,2] [,3] [,4]
[1,]   20   21   22   23
[2,]   24   25   26   27
[3,]   28   29   30   31

Rozmery a základné informácie

dim(m)                 # (riadky, stĺpce)
[1] 3 4
nrow(m); ncol(m)
[1] 3
[1] 4

Adresovanie prvkov a podmatic

m[3, 1]        # riadok 3, stĺpec 1
[1] 4
m[, 4]         # všetky prvky v 4. stĺpci (vektor)
[1] 11 12 13
m[1, ]         # všetky prvky v 1. riadku (vektor)
[1]  2  5  8 11
m[2:3, 1:2]    # podmatica (riadky 2–3, stĺpce 1–2)
     [,1] [,2]
[1,]    3    6
[2,]    4    7

Maticové operácie

A <- matrix(c(2, -1,
              0,  3), nrow = 2, byrow = TRUE)

B <- matrix(c(4,  1,
              5, -2), nrow = 2, byrow = TRUE)

A + B          # sčítanie
     [,1] [,2]
[1,]    6    0
[2,]    5    1
A * B          # Hadamardov (po-prvkový) súčin
     [,1] [,2]
[1,]    8   -1
[2,]    0   -6
A %*% B        # maticový súčin
     [,1] [,2]
[1,]    3    4
[2,]   15   -6
t(A)           # transpozícia
     [,1] [,2]
[1,]    2    0
[2,]   -1    3
det(A)         # determinant
[1] 6
solve(A)       # inverzia (ak je regulárna)
     [,1]      [,2]
[1,]  0.5 0.1666667
[2,]  0.0 0.3333333

Kontrola rozmerov pre maticový súčin: počet stĺpcov vľavo = počet riadkov vpravo. ## Zlučovanie vektorov do matíc

C <- cbind(2:4, c(10, 20, 30))   # po stĺpcoch (2 3 4) a (10 20 30)
D <- rbind(c(7, 8, 9), 1:3)      # po riadkoch
C; D
     [,1] [,2]
[1,]    2   10
[2,]    3   20
[3,]    4   30
     [,1] [,2] [,3]
[1,]    7    8    9
[2,]    1    2    3

Štatistiky po riadkoch/stĺpcoch

M <- matrix(10:18, nrow = 3)     # 3x3 matica s hodnotami 10..18
M
     [,1] [,2] [,3]
[1,]   10   13   16
[2,]   11   14   17
[3,]   12   15   18
rowSums(M)         # rýchlejšie ako apply(M, 1, sum)
[1] 39 42 45
colMeans(M)        # rýchlejšie ako apply(M, 2, mean)
[1] 11 14 17

Malé cvičenie

Vektorová hra s „koncovkou 7“

Zadanie:
Vytvorte vektor 30 náhodných celých čísel z intervalu 10..99. Čísla končiace na 7 nahraďte hodnotou NA.
Vypočítajte medián po odstránení NA a zistite indexy prvkov, ktoré boli nahradené.

# 30 náhodných CELÝCH čísel z intervalu 10..99
u <- sample(10:99, size = 30, replace = TRUE)

# ktoré končia na 7?
ends_with_7 <- u %% 10 == 7

# nahradenie týchto prvkov za NA
u_clean <- u
u_clean[ends_with_7] <- NA

# štatistiky
median_no_na <- median(u_clean, na.rm = TRUE)
idx_sevens   <- which(ends_with_7)

u; u_clean
 [1] 47 98 43 78 81 85 72 22 91 34 47 30 88 50 56 99 69 25 15 81 95 95 48
[24] 40 90 59 43 13 22 78
 [1] NA 98 43 78 81 85 72 22 91 34 NA 30 88 50 56 99 69 25 15 81 95 95 48
[24] 40 90 59 43 13 22 78
median_no_na
[1] 64
idx_sevens
[1]  1 11
LS0tCnRpdGxlOiAiWsOha2xhZG7DqSBvcGVyw6FjaWUgdiBSIgphdXRob3I6ICJTw6FyYSBOaWtvbCBTY2hvbHR6b3bDoSIKZGF0ZTogIlNlcHRlbWJlciAyMDI1IgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdGhlbWU6IGZsYXRseQogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgY3NzOiBzdHlsZS5jc3MgCmVkaXRvcl9vcHRpb25zOiAKICBtYXJrZG93bjogCiAgICB3cmFwOiA3MgotLS0KIyBHbG9iw6FsbmUgbmFzdGF2ZW5pZSBDaHVua292CgpWIG5pxb7FoWllIHV2ZWRlbm9tIENodW5rdSBqZSB1cm9iZW7DqSB6w6FrbGFkbsOpIGdsb2LDoWxuZSBuYXN0YXZlbmllIENodW5rb3YKdiBjZWxvbSBOb3RlYm9va3UuIAoKLSAqKmVjaG8qKjogxI1pIHZ5cGlzb3ZhxaUga8OzZCBSIHYgZG9rdW1lbnRlLAotICoqbWVzc2FnZSA9IEZBTFNFKio6IHBvdGzDocSNYSBpbmZvcm1hdMOtdm5lIGhsw6HFoWt5IChuYXByLiBwcmkgbmHEjcOtdGFuw60KICBiYWzDrWtvdiksCi0gKip3YXJuaW5nID0gRkFMU0UqKjogcG90bMOhxI1hIHZhcm92YW5pYSAobmllIGNoeWJ5KS4KCmBgYHtyIHNldHVwLCBpbmNsdWRlPVRSVUUsIGVjaG89VFJVRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVjaG8gPSBUUlVFLAogIG1lc3NhZ2UgPSBGQUxTRSwKICB3YXJuaW5nID0gRkFMU0UpCgpgYGAKIyBTa2Fsw6FyZSAoamVkbm/EjcOtc2VsbsOpIGhvZG5vdHkpCgojIyBOdW1lcmlja8OpIHNrYWzDoXJlCmBgYHtyfQojIFByaXJhZGVuaWUga29uxaF0w6FudCBkbyBwcmVtZW5uw71jaAphIDwtIDUKYiA8LSAxMi41CgojIEFyaXRtZXRpa2EKc3VtX2FiICAgPC0gYSArIGIgICAgICAgICMgc8O6xI1ldApkaWZmX2FiICA8LSBhIC0gYiAgICAgICAgIyByb3pkaWVsCnByb2RfYWIgIDwtIGEgKiBiICAgICAgICAjIG7DoXNvYmVuaWUKcXVvdF9hYiAgPC0gYSAvIGIgICAgICAgICMgZGVsZW5pZSAocmXDoWxuZSkKcG93ZXJfYWIgPC0gYSBeIGIgICAgICAgICMgbW9jbmluYQoKIyBNb2R1bG8gYSBjZWxvxI3DrXNlbG7DqSBkZWxlbmllIChwcsOta2xhZCBzIGNlbMO9bSBkZWxpdGXEvm9tKQptb2RfYTUgICAgIDwtIGEgJSUgNSAgICAgIyB6dnnFoW9rIHBvIGRlbGVuw60gcGlhdGltaQppbnRfZGl2X2E1IDwtIGEgJS8lIDUgICAgIyBjZWxvxI3DrXNlbG7DqSBkZWxlbmllIChmbG9vcihhLzUpKQoKIyBaYW9rcsO6aMS+b3ZhbmllCnJvdW5kX2IgPC0gcm91bmQoYikgICAgICAjIG5hIG5hamJsacW+xaFpZSBjZWzDqSDEjcOtc2xvCmNlaWxfYiAgPC0gY2VpbGluZyhiKSAgICAjIG5haG9yCmZsb29yX2IgPC0gZmxvb3IoYikgICAgICAjIG5hZG9sCgphOyBiCnN1bV9hYjsgZGlmZl9hYjsgcHJvZF9hYjsgcXVvdF9hYjsgcG93ZXJfYWIKbW9kX2E1OyBpbnRfZGl2X2E1CnJvdW5kX2I7IGNlaWxfYjsgZmxvb3JfYgpgYGAKIyMjIE1hbMOpIGN2acSNZW5pZQojIyMjIFZ5cG/EjcOtdGFqCmBgYHtyfQozKigxMF4yIC0gMTApIC8gMwpgYGAKIyBUZXh0IAoKIyMgVnl0dsOhcmFuaWUgdGV4dG92w71taSBwcmVtZW5uw71taSBhIHByw6FjYSBzIG5pbWkKYGBge3J9CmZpcnN0IDwtICJTw6FyYSIKbWlkZGxlIDwtICJOaWtvbCIKbGFzdCAgPC0gIlNjaG9sdHpvdsOhIgoKZnVsbCAgPC0gcGFzdGUoZmlyc3QsbWlkZGxlLCBsYXN0KSAgICAgICAgICAgICAgICAgICAgIyBzcG9qZW5pZSBzIG1lZHplcm91CmZ1bGxfbm9zcGFjZSA8LSBwYXN0ZTAoZmlyc3QsIG1pZGRsZSwgbGFzdCkgICAgICAgICAgICAjIGJleiBtZWR6ZXJ5CmNzdl9saW5lIDwtIHBhc3RlKCJBdXRvIiwgIkJpY3lrZWwiLCAiTW90b3JrYSIsIHNlcCA9ICIsIikgICMgdmxhc3Ruw70gb2RkZcS+b3ZhxI0KCmZpcnN0OyBtaWRkbGU7IGxhc3Q7IGZ1bGw7IGZ1bGxfbm9zcGFjZTsgY3N2X2xpbmUKYGBgCiMjIETEusW+a2EgdGV4dG92w6lobyByZcWlYXpjYSwgcG9kcmXFpWF6ZWMKYGBge3J9CnggPC0gIkVrb25vbWV0cmlhIG1hIGJhdsOtISIKbmNoYXIoeCkgICAgICAgICAgICAgICAgICMgcG/EjWV0IHpuYWtvdiB2IHJlxaVhemNpCnN1YnN0cih4LCAxLCA3KSAgICAgICAgICAjIHBvZHJlxaVhemVjIG9kIDEuIGRvIDUuIHpuYWt1CgojIMSOYWzFoWllIHXFvml0b8SNbsOpIGRyb2Jub3N0aToKdG91cHBlcigiTWlsdWplbSBTbG92ZW5za28iKSAgICAjIG5hIFZFxL1Lw4kgcMOtc21lbsOhCnRvbG93ZXIoIk1pbHVqZW0gU2xvdmVuc2tvIikgICAgIyBuYSBtYWzDqSBww61zbWVuw6EKdHJpbXdzKCIgIENlc3RhIG9rb2xvIFN2ZXRhICAiKSAgIyBvcmV6YW5pZSBva3Jham92w71jaCBtZWR6aWVyCmBgYAojIyMgTWFsw6kgY3ZpxI1lbmllCk5lY2ggbmFtZSA8LSAiSmFua28gTXJrdmnEjWthIi4gVnlww63FoXRlIHByaWV6dmlza28gYWtvIHBvZHJlxaVhemVjCmEgdnl0dm9ydGUgcmXFpWF6ZWMgbGFiZWwgdiB0dmFyZSAiUHJpZXp2aXNrbzogTXJrdmnEjWthIChkxLrFvmthOiA4KSIuCmBgYHtyfQpuYW1lIDwtICJKYW5rbyBNcmt2acSNa2EiCnN1cm5hbWUgPC0gc3ViKCIuKiAiLCAiIiwgbmFtZSkgICAgICAgICAgICAjIHbFoWV0a28gcG8gcG9zbGVkbmVqIG1lZHplcmUKbGFiZWwgPC0gcGFzdGUwKCJQcmllenZpc2tvOiAiLCB0b3VwcGVyKHN1cm5hbWUpLAogICAgICAgICAgICAgICAgIiAoZMS6xb5rYTogIiwgbmNoYXIoc3VybmFtZSksICIpIikKc3VybmFtZTsgbGFiZWwKYGBgCiMgTG9naWNrw6kgKGJvb2xvdnNrw6kpIGhvZG5vdHkgYSBwcmVtZW5uw6kKCiMjIFrDoWtsYWR5CmBgYHtyfQpwIDwtIEZBTFNFCnEgPC0gVFJVRQoKIXEgICAgICAgICAgIyBOT1QKcCAmIHEgICAgICAgIyBBTkQgKHBydmtvdsOpIHByaSB2ZWt0b3JvY2gpCnAgfCBxICAgICAgICMgT1IgIChwcnZrb3bDqSBwcmkgdmVrdG9yb2NoKQp4b3IocCwgcSkgICAjIGV4a2x1esOtdm5lIE9SIChwcmF2ZGEsIGFrIHBsYXTDrSBwcmVzbmUgamVkbm8geiBwLCBxKQpgYGAKIyMgTG9naWNrw70gdsO9c2xlZG9rIHBvcm92bsOhdmFuaWEKYGBge3J9CjkgPCA0CjEwID49IDEwCiJHaXJsIiA9PSAiR2lybCIKIkdpcmwiICE9ICJCb3kiCiFUUlVFCmBgYAojIyBabG/Fvml0ZWrFoWllIGxvZ2lja8OpIG9wZXLDoWNpZQpgYGB7cn0KeCA8LSA1CnggPiAzICYgeCA8IDEwICAgICAgIyBhIHPDusSNYXNuZQp4IDwgMCB8IHggPiAzMCAgICAgIyBhbGVibwojIHByaSB6bG/Fvml0ZWrFocOtY2ggdnrFpWFob2NoIHBvdcW+w612YWp0ZSB6w6F0dm9ya3kgKCkKYGBgCiMjIyBNYWzDqSBjdmnEjWVuaWUKTWFqdGUgcHJlbWVubsO6IHRlbXAgPC0gMTguIFZ5dHZvcnRlIGR2ZSBsb2dpY2vDqSBwcmVtZW5uZToKaXNfcm9vbV90ZW1wIGplIFRSVUUsIGFrIGplIHRlbXAgdiBpbnRlcnZhbGUgPDE4OyAyND4sCmlzX2NvbGRfb3JfaG90IGplIFRSVUUsIGFrIGplIHRlbXAgPCAxOCBhbGVibyB0ZW1wID4gMjQuCmBgYHtyfQp0ZW1wIDwtIDE1CmlzX3Jvb21fdGVtcCAgPC0gKHRlbXAgPj0gMTgpICYgKHRlbXAgPD0gMjQpCmlzX2NvbGRfb3JfaG90IDwtICh0ZW1wIDwgMTgpIHwgKHRlbXAgPiAyNCkKaXNfcm9vbV90ZW1wOyBpc19jb2xkX29yX2hvdApgYGAKIyMgTcO0aiBuw6F2cmggcG91xb5pdGlhIG5vdmlua3kKYGBge3J9CiMgMSkgQ2Vsb8SNw61zZWxuw6kgZGVsZW5pZSBhIG1vZHVsbyBzcG9sdToKIyBSb3psb8W+bWUgMTM3IG1pbsO6dCBuYSBob2RpbnkgYSB6dnnFoW7DqSBtaW7DunR5LgptaW51dGVzIDwtIDEzNwpob3VycyAgIDwtIG1pbnV0ZXMgJS8lIDYwCnJlbSAgICAgPC0gbWludXRlcyAlJSA2MApzcHJpbnRmKCIlZCBtaW4gPSAlZCBoICVkIG1pbiIsIG1pbnV0ZXMsIGhvdXJzLCByZW0pCgojIDIpIFrDoWtsYWRuw6kgdnloxL5hZMOhdmFuaWUgdnpvcnUgdiB0ZXh0ZSAoYmFzZSBSKQpjaXRpZXMgPC0gYygiQnJhdGlzbGF2YSIsICJLb8WhaWNlIiwgIkJhbnNrw6EgQnlzdHJpY2EiLCAiQnJubyIpCmdyZXBsKCJeQiIsIGNpdGllcykgICAgICAgICAgICAgICAgICAgICAgICAjIHphxI3DrW5hIG5hICdCJz8KY2l0aWVzW2dyZXBsKCJhdmEkIiwgY2l0aWVzKV0gICAgICAgICAgICAgICMga29uxI3DrSBzYSBuYSAnYXZhJz8KCiMgMykgUGVrbsOpIGZvcm3DoXRvdmFuaWUgdGV4dHUgcyDEjcOtc2xhbWkgY2V6IHNwcmludGYoKQpwaV92YWwgPC0gcGkKc3ByaW50Zigiz4Ag4omIICUuNGYiLCBwaV92YWwpICAgICAgICAgICAgICAgIyA0IGRlc2F0aW5uw6kgbWllc3RhCnNwcmludGYoIlBvxI1ldDogJTAzZCBrdXN5IiwgNykgICAgICAgICAgICAjIGRvcGxuZW5pZSBuw7psIG5hIDMgY2lmcnk6IDAwNwpgYGAKIyBOdW1lcmlja8OpIHZla3RvcnkKCiMjIEdlbmVyb3ZhbmllIHZla3Rvcm92CmBgYHtyfQpzZXQuc2VlZCgxMjMpICAjIGFieSBuw6Fob2Ruw6kgcHLDrWtsYWR5IGJvbGkgcmVwcm9kdWtvdmF0ZcS+bsOpCgp2MSA8LSBjKDMsNiwxLDkpCnYyIDwtIDE6NSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHBvc3R1cG5vc8WlIDEsMiwzLDQsNQp2MyA8LSBzZXEoZnJvbSA9IDAsIHRvID0gMSwgYnkgPSAwLjUpICAgICAjIHBvc3R1cG5vc8WlIHMga3Jva29tIDAuNQp2NCA8LSByZXAoMSwgdGltZXMgPSA1KSAgICAgICAgICAgICAgICAgICAgIyAxLDEsMSwxLDEKdjUgPC0gcnVuaWYoMykgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgVVswLDFdCnY2IDwtIHJub3JtKDMpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIE4oMCwxKQp2MTsgdjI7IHYzOyB2NDsgdjU7IHY2CmBgYAojIyBBcml0bWV0aWNrw6kgb3BlcsOhY2llIHMgdmVrdG9ybWkKYGBge3J9CnYgPC0gYygzLDUsOSw1KQp2ICsgNSAgICAgICAgICAgICAgICAgICMgcG9zdW4gbyBrb27FoXRhbnR1CnYgKiAzICAgICAgICAgICAgICAgICAgIyDFoWvDoWxvdmFuaWUKKHYgKyAzKSAvIDIKZXhwKHYpICAgICAgICAgICAgICAgICAjIHBvLXBydmtvdsOhIGV4cCgpCgojICJTa2Fsw6Fybnkgc8O6xI1pbiIgZHZvY2ggdmVrdG9yb3Ygcm92bmFrZWogZMS6xb5reToKeCA8LSBjKDEsMiwzKTsgeSA8LSBjKDEsMSwxKQpzdW0oeCAqIHkpICAgICAgICAgICAgIyBza3V0b8SNbsO9IHNrYWzDoXJueSBzw7rEjWluICh2w71zbGVkb2sgc2thbGFyKQpjcm9zc3Byb2QoeCwgeSkgICAgICAgIyB0byBpc3TDqSwgYWxlIGFrbyBtYXRpY2EgMXgxCgojIEhhZGFtYXJkb3Ygc8O6xI1pbiAocG8tcHJ2a292w6kgbsOhc29iZW5pZSk6CnggKiB5CmBgYAojIyBPcGVyw6FjaWUgcyBkdm9taSB2ZWt0b3JtaSAocm92bmFrw70gcm96bWVyKQpgYGB7cn0KbGVuZ3RoKGMoMSwyLDMsNCw1LDYpKQpsZW5ndGgodjEpICAgICAgICAgICAgICAgICAjICh6IHByZWRjaMOhZHphasO6Y2VobyBjaHVua3UpCiMgUE9aT1IgbmEgcmVjeWtsb3ZhbmllIGTEusW+b2sg4oCTIG5hamxlcMWhaWUgamUgbWHFpSByb3ZuYWvDqSBkxLrFvmt5Ogp0cnkoYygxLDIsMyw0KSArIHYxKSAgICAgIyBhayBzw7ogcm92bmFrw6ksIE9LCmBgYAojIyBJbmRleG92YW5pZSBhIHbDvWJlciBwcnZrb3YKYGBge3J9CnggPC0gYyg5LCAxNCwgMiwgMjcsIDExLCA1LCAwKQp4WzFdICAgICAgICAgICAgIyBwcnbDvSBwcnZvawp4WzI6NF0gICAgICAgICAgIyAyLiBhxb4gNC4gcHJ2b2sKeFstMV0gICAgICAgICAgICMgdsWhZXRrbyBva3JlbSBwcnbDqWhvCnhbeCA+IDEwXSAgICAgICAjIHBydmt5IHbDpMSNxaFpZSBha28gMTAgKGxvZ2lja8OhIG1hc2thKQp3aGljaCh4ID4gMTApICAgIyBpbmRleHkgcHJ2a292IHbDpMSNxaHDrWNoIGFrbyAxMApgYGAKIyMgWsOha2xhZG7DqSDFoXRhdGlzdGlreSBhIHVzcG9yaWFkYW5pZQpgYGB7cn0KeiA8LSBjKDEyLDUsMSw4LDApCm1lYW4oeikgICAgICAgICAgICAgICAgICMgcHJpZW1lcgpzZCh6KSAgICAgICAgICAgICAgICAgICAjIMWhdGFuZGFyZG7DoSBvZGNow71sa2EKbWF4KHopICAgICAgICAgICAgICAgICAgIyBtYXhpbXVtCnN1bW1hcnkoeikgICAgICAgICAgICAgICMgcsO9Y2hseSBwcmVoxL5hZApzb3J0KHopICAgICAgICAgICAgICAgICAjIHJhc3TDumNvCnNvcnQoeiwgZGVjcmVhc2luZyA9IFRSVUUpICAjIGtsZXNhasO6Y28KYGBgCiMjIFByw6FjYSBzIGNow71iYWrDumNpbWkgaG9kbm90YW1pCmBgYHtyfQp5IDwtIGMoMSwgTkEsIDMsIE5BLCA1KQppcy5uYSh5KQphbnlOQSh5KQptZWFuKHkpICAgICAgICAgICAgICAgICAgICAgICAjIE5BCm1lYW4oeSwgbmEucm0gPSBUUlVFKSAgICAgICAgICMgaWdub3J1amUgTkEKYGBgCgojIyMgTWFsw6kgY3ZpxI1lbmllClZ5dHZvcnRlIHZla3RvciB3IHMgxI3DrXNsYW1pIDUuLjM1IGEgdnlwb8SNw610YWp0ZSBzw7rEjWV0IHbFoWV0a8O9Y2ggbsOhc29ia292IDMuCmBgYHtyfQojIFJpZcWhZW5pZSBBOiBmaWx0cm92YW5pZSBjZXogbW9kdWxvCncgPC0gNTozNQpzdW0od1t3ICUlIDMgPT0gMF0pCgojIFJpZcWhZW5pZSBCOiBwcmlhbW8gc2kgdnl0dm9yIG7DoXNvYmt5IDMgdiByb3pzYWh1CnN1bShzZXEoZnJvbSA9IDYsIHRvID0gMzMsIGJ5ID0gMykpCmBgYAojIE1hdGljZQoKIyMgVnl0dm9yZW5pZSBtYXTDrWMKYGBge3J9Cm0gPC0gbWF0cml4KDI6MTMsIG5yb3cgPSAzLCBuY29sID0gNCkgICAgICAgICAgICAjIHBsbsOtIHNhIHBvIHN0xLpwY29jaCAoMi4uMTMpCm1fYnlyb3cgPC0gbWF0cml4KDIwOjMxLCBucm93ID0gMywgYnlyb3cgPSBUUlVFKSAjIHBsbsOtIHNhIHBvIHJpYWRrb2NoICgyMC4uMzEpCm07IG1fYnlyb3cKYGBgCiMjIFJvem1lcnkgYSB6w6FrbGFkbsOpIGluZm9ybcOhY2llCmBgYHtyfQpkaW0obSkgICAgICAgICAgICAgICAgICMgKHJpYWRreSwgc3TEunBjZSkKbnJvdyhtKTsgbmNvbChtKQpgYGAKIyMgQWRyZXNvdmFuaWUgcHJ2a292IGEgcG9kbWF0aWMKYGBge3J9Cm1bMywgMV0gICAgICAgICMgcmlhZG9rIDMsIHN0xLpwZWMgMQptWywgNF0gICAgICAgICAjIHbFoWV0a3kgcHJ2a3kgdiA0LiBzdMS6cGNpICh2ZWt0b3IpCm1bMSwgXSAgICAgICAgICMgdsWhZXRreSBwcnZreSB2IDEuIHJpYWRrdSAodmVrdG9yKQptWzI6MywgMToyXSAgICAjIHBvZG1hdGljYSAocmlhZGt5IDLigJMzLCBzdMS6cGNlIDHigJMyKQpgYGAKIyMgTWF0aWNvdsOpIG9wZXLDoWNpZQpgYGB7cn0KQSA8LSBtYXRyaXgoYygyLCAtMSwKICAgICAgICAgICAgICAwLCAgMyksIG5yb3cgPSAyLCBieXJvdyA9IFRSVUUpCgpCIDwtIG1hdHJpeChjKDQsICAxLAogICAgICAgICAgICAgIDUsIC0yKSwgbnJvdyA9IDIsIGJ5cm93ID0gVFJVRSkKCkEgKyBCICAgICAgICAgICMgc8SNw610YW5pZQpBICogQiAgICAgICAgICAjIEhhZGFtYXJkb3YgKHBvLXBydmtvdsO9KSBzw7rEjWluCkEgJSolIEIgICAgICAgICMgbWF0aWNvdsO9IHPDusSNaW4KdChBKSAgICAgICAgICAgIyB0cmFuc3BvesOtY2lhCmRldChBKSAgICAgICAgICMgZGV0ZXJtaW5hbnQKc29sdmUoQSkgICAgICAgIyBpbnZlcnppYSAoYWsgamUgcmVndWzDoXJuYSkKYGBgCktvbnRyb2xhIHJvem1lcm92IHByZSBtYXRpY292w70gc8O6xI1pbjogcG/EjWV0IHN0xLpwY292IHbEvmF2byA9IHBvxI1ldCByaWFka292IHZwcmF2by4KIyMgWmx1xI1vdmFuaWUgdmVrdG9yb3YgZG8gbWF0w61jCmBgYHtyfQpDIDwtIGNiaW5kKDI6NCwgYygxMCwgMjAsIDMwKSkgICAjIHBvIHN0xLpwY29jaCAoMiAzIDQpIGEgKDEwIDIwIDMwKQpEIDwtIHJiaW5kKGMoNywgOCwgOSksIDE6MykgICAgICAjIHBvIHJpYWRrb2NoCkM7IEQKYGBgCiMjIMWgdGF0aXN0aWt5IHBvIHJpYWRrb2NoL3N0xLpwY29jaApgYGB7cn0KTSA8LSBtYXRyaXgoMTA6MTgsIG5yb3cgPSAzKSAgICAgIyAzeDMgbWF0aWNhIHMgaG9kbm90YW1pIDEwLi4xOApNCnJvd1N1bXMoTSkgICAgICAgICAjIHLDvWNobGVqxaFpZSBha28gYXBwbHkoTSwgMSwgc3VtKQpjb2xNZWFucyhNKSAgICAgICAgIyByw71jaGxlasWhaWUgYWtvIGFwcGx5KE0sIDIsIG1lYW4pCmBgYAojIE1hbMOpIGN2acSNZW5pZQoKIyMgVmVrdG9yb3bDoSBocmEgcyDigJ5rb25jb3Zrb3UgN+KAnAoKKipaYWRhbmllOioqICAKVnl0dm9ydGUgdmVrdG9yIDMwIG7DoWhvZG7DvWNoICoqY2Vsw71jaCoqIMSNw61zZWwgeiBpbnRlcnZhbHUgMTAuLjk5LiDEjMOtc2xhICoqa29uxI1pYWNlIG5hIDcqKiBuYWhyYcSPdGUgaG9kbm90b3UgYE5BYC4gIApWeXBvxI3DrXRhanRlIG1lZGnDoW4gcG8gb2RzdHLDoW5lbsOtIGBOQWAgYSB6aXN0aXRlICoqaW5kZXh5KiogcHJ2a292LCBrdG9yw6kgYm9saSBuYWhyYWRlbsOpLgpgYGB7cn0KIyAzMCBuw6Fob2Ruw71jaCBDRUzDnUNIIMSNw61zZWwgeiBpbnRlcnZhbHUgMTAuLjk5CnUgPC0gc2FtcGxlKDEwOjk5LCBzaXplID0gMzAsIHJlcGxhY2UgPSBUUlVFKQoKIyBrdG9yw6kga29uxI1pYSBuYSA3PwplbmRzX3dpdGhfNyA8LSB1ICUlIDEwID09IDcKCiMgbmFocmFkZW5pZSB0w71jaHRvIHBydmtvdiB6YSBOQQp1X2NsZWFuIDwtIHUKdV9jbGVhbltlbmRzX3dpdGhfN10gPC0gTkEKCiMgxaF0YXRpc3Rpa3kKbWVkaWFuX25vX25hIDwtIG1lZGlhbih1X2NsZWFuLCBuYS5ybSA9IFRSVUUpCmlkeF9zZXZlbnMgICA8LSB3aGljaChlbmRzX3dpdGhfNykKCnU7IHVfY2xlYW4KbWVkaWFuX25vX25hCmlkeF9zZXZlbnMKYGBgCgo=