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

Quitting from Cvicenie2a_scalars_text_logical_vectors_matrices.Rmd:26-32 [setup]
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 <- 9
b <- 2.3

# 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 %% 4       # 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] 9
[1] 2.3
sum_ab; diff_ab; prod_ab; quot_ab; power_ab; mod_ab;
[1] 11.3
[1] 6.7
[1] 20.7
[1] 3.913043
[1] 156.5877
[1] 1
round_b; ceil_b; floor_b
[1] 2
[1] 3
[1] 2

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{(15^2-4)}{7}\]

((21^(1.2) * 8) / (3/2))-(8/2.5)
[1] 202.7026

Text

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

first <- "Barbora"                       # definovanie obsahu textovej premennej first
last  <- "Koprdova"                          # 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("stlp", "postel", "papier", 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 <- "Ahoj ja som Fero!"
nchar(x)                 # počet znakov  v retazci "R is great!"
[1] 17
substr(x, 9, 11)          # podreťazec od 1. do 5. znaku
[1] "som"

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

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

Logický výsledok porovnávania

281 < 333
[1] TRUE
44 >= 44
[1] TRUE
"obed" == "obed"
[1] TRUE
"obed" != "vecera"   # vykricnik je tu v zmysle negacie. Napr.:   !=, !>, !<, !TRUE
[1] TRUE
!TRUE
[1] FALSE

Zložitejšie logické operácie

y <- 89
y > 3 & x < 200      # a sucasne - logicky prienik (sucin)
[1] FALSE
y < 10 | x > 30     # alebo - logicke zjednotenie (sucet)
[1] TRUE
                    # 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(3, 6, 9, 12)
v2 <- 3:15                  # postupnost 1,2,3,4,5
v3 <- seq(from = 0, to = 16, by = 0.55)  # postupnost s krokom 0.25
v4 <- rep(3, times = 4)    # 3,3,3,3,3  # 5 clenna postupnost trojak
v5 <- runif(4)             # generovanie rovnomerne rozdelenych premennych v intervale [0,1]
v6 <- rnorm(4)             # generovanie normalne rozdelenych premennych
v1; v2; v3; v4; v5
[1]  3  6  9 12
 [1]  3  4  5  6  7  8  9 10 11 12 13 14 15
 [1]  0.00  0.55  1.10  1.65  2.20  2.75  3.30  3.85  4.40  4.95
[11]  5.50  6.05  6.60  7.15  7.70  8.25  8.80  9.35  9.90 10.45
[21] 11.00 11.55 12.10 12.65 13.20 13.75 14.30 14.85 15.40 15.95
[1] 3 3 3 3
[1] 0.2540458 0.6141199 0.4359565 0.2626499

Aritmetické operácie s vektormi

v <- c(10, 32, 44, 58)
v + 3           # kazdy prvok vektora zvacsime o 10
[1] 13 35 47 61
v * 9            # kazdy prvok vektora prenasobime 2
[1]  90 288 396 522
(v + 1) / 2
[1]  5.5 16.5 22.5 29.5
exp(v)           # exponencialna funkcia z kazdeho prvku vektora
[1] 2.202647e+04 7.896296e+13 1.285160e+19 1.545539e+25
sum(c(8,9,10),c(2,3,3))          # skalarny sucin - vysledok je skalar
[1] 35
crossprod(c(4,6,8),c(10,12,14))    # skalarny sucin - vysledok je matica 1x1
     [,1]
[1,]  224
c(11,22,333)*c(5,5,5)               # Hadamardov sucin (sucin zodpovedajucich prvkov vektora)
[1]   55  110 1665

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

length(c(2,8,14,1,3))
[1] 5
length(v5)            #vektor v5 je definovany vyssie
[1] 4
c(6,8,3,10,1) + v5     # pozor, oba vektory musia mat rovnaky rozmer
[1]  6.254046  8.614120  3.435956 10.262650  1.254046

Indexovanie a výber niektorych prvkov vektora

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

Práca s chýbajúcimi hodnotami

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

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

a <- c(1, 6, 3, 9, 4)
mean(a)                 # priemerna hodnota
[1] 4.6
sd(a)                  # standardna odchylka
[1] 3.04959
max(a)                  # maximalna hodnota
[1] 9
summary(a)              # rychly prehlad zakladnych statistik o vektore
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
    1.0     3.0     4.0     4.6     6.0     9.0 
sort(a)                 # rastuce usporiadanie 
[1] 1 3 4 6 9
sort(a, decreasing = TRUE)  # klesajuce
[1] 9 6 4 3 1

Malé cvičenie

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

k <- 1:18
sum(w[w %% 2 == 0])
[1] 110

Matice

Vytvorenie matíc

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

Rozmery matice

dim(m)                   # (rows, cols)
[1] 5 3
m
     [,1] [,2] [,3]
[1,]    1    6   11
[2,]    2    7   12
[3,]    3    8    1
[4,]    4    9    2
[5,]    5   10    3

Adresovanie prvkov matice

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

Maticové operácie

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

A + B        # scitanie matic
     [,1] [,2]
[1,]    7    5
[2,]    5    7
A * B        # Hadamard product - nasobenie po zodpovedajucich prvkoch
     [,1] [,2]
[1,]    6    4
[2,]    6   10
A %*% B      # nasobenie matic
     [,1] [,2]
[1,]    9   26
[2,]   17   18
t(A)         # transpozicia matice A - vymena riadkov a stlpcov
     [,1] [,2]
[1,]    6    2
[2,]    1    5
det(A)       # determinant matice
[1] 28
solve(A)     # inverzia matice (ak je matica regularna - teda inverzia sa da spocitat)
            [,1]        [,2]
[1,]  0.17857143 -0.03571429
[2,] -0.07142857  0.21428571

Zlučovanie vektorov do matíc

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

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

M <- matrix(2:4, nrow = 2)
M
     [,1] [,2]
[1,]    2    4
[2,]    3    2
apply(M, 2, sum)   # suma po riadkoch
[1] 5 6
apply(M, 2, mean)  # priemery po stĺpcoch
[1] 2.5 3.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:15, nrow = 5, byrow = TRUE)
colSums(M2)
[1] 35 40 45
t(M2) %*% M2
     [,1] [,2] [,3]
[1,]  335  370  405
[2,]  370  410  450
[3,]  405  450  495
# 1) Moje dáta 
water <- c(6, 8, 5, 9, 7, 4, 10)  # Počet pohárov vody v dňoch 1..7

# 2) Malé úlohy
sum(water >= 8)           # a) koľko dní >= 8 pohárov
[1] 3
mean(water)               # b) priemer za týždeň
[1] 7
which.max(water)          # c) ktorý deň bol najlepší (index dňa 1..7)
[1] 7
water[which.max(water)]   #    koľko pohárov to bolo
[1] 10
# 3) Graf (časová krivka)
plot(
  water, type = "o",
  main = "Poháre vody za 7 dní",
  xlab = "Deň", ylab = "Počet pohárov",
  ylim = c(0, max(water) + 1)
)
abline(h = 8, lty = 2)  # vyznačený cieľ 8 pohárov


days <- c("Po","Ut","St","Št","Pi","So","Ne")
plot(1:7, water, type="o", xaxt="n", xlab="Deň", ylab="Poháre")
axis(1, at=1:7, labels=days); abline(h=8, lty=2)

LS0tCnRpdGxlOiAiWsOha2xhZG7DqSBvcGVyw6FjaWUgdiBSIgphdXRob3I6ICJCYXJib3JhIEtvcHJkb3ZhICA8YnI+CihzIHZ5dcW+aXTDrW0gQ2hhdEdQVCkiCmRhdGU6ICJPa3RvYmVyIDIwMjUiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0aGVtZTogdW5pdGVkCiAgICBoaWdobGlnaHQ6IHRhbmdvCmVkaXRvcl9vcHRpb25zOiAKICBtYXJrZG93bjogCiAgICB3cmFwOiA3MgotLS0KCiMgR2xvYsOhbG5lIG5hc3RhdmVuaWUgQ2h1bmtvdgoKViBuacW+xaFpZSB1dmVkZW5vbSBDaHVua3UgamUgdXJvYmVuw6kgesOha2xhZG7DqSBnbG9iw6FsbmUgbmFzdGF2ZW5pZSBDaHVua292IHYgY2Vsb20gTm90ZWJvb2t1LiAKCi0gKiplY2hvKiogbmFzdGF2dWplLCDEjWkgY2hjZW1lIHYgTm90ZWJvb2t1IHZ5cGlzb3ZhxaUgamVkbm90bGl2w6kga8OzZHkgUgotICoqbWVzc2FnZSoqIGplIG5hc3RhdmVuw70gbmEgKkZBTFNFKiwgxI1vIHpuYW1lbsOhLCDFvmUgc2EgYnVkw7ogcG90bMOhxI1hxaUgcHJhY292bsOpIHbDvXN0dXB5IHogUiwgdC5qLiBuYXByw61rbGFkIHbDvXNsZWRvayBvdHbDoXJhbmlhIGtuacW+bsOtYywgYSBuaWVrdG9yw6kgaW7DqSB2w71zdHVweSwga3RvcsOpIGFsZSBwcmUgY2Vsa292w70gTm90ZWJvb2sgbmVtYWrDuiB0YWttZXIgxb5pYWRlbiB2w716bmFtIGEgc8O6IHZob2Ruw6kgc2vDtHIgcHJpIGxhZGVuw60ga8OzZG92LgotICoqd2FybmluZyoqIG5hc3RhdmVuw70gbmEgRkFMU0UgcG90bMOhxI1hIHpvYnJhemVuaWUgY2h5Ym92w71jaCBobMOhxaFvawoKCmBgYHtyIHNldHVwLCBpbmNsdWRlPVRSVUUsZWNobz1UUlVFfQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgZWNobyA9IFRSVUUsCiAgbWVzc2FnZSA9IEZBTFNFLAogIHdhcm5pbmcgPSBGQUxTRQopCmBgYAoKIyDDmnZvZCBrIHrDoWtsYWRuw71tIG9wZXLDoWNpw6FtIHYgUgoKVGVudG8gbm90ZWJvb2sgZGVtb27FoXRydWplICoqesOha2xhZG7DqSBvcGVyw6FjaWUqKiB2IGphenlrdSBSIHNvOgoKLSBza2Fsw6FybnltaSDEjcOtc2xhbWkgKHQuai4gMSDEjcOtc2xvKSwKLSB0ZXh0b3bDvW1pICh6bmFrb3bDvW1pKSByZcWlYXpjYW1pLAotIGxvZ2lja8O9bWkgKGJvb2xvdnNrw71taSkgaG9kbm90YW1pIGEgcHJlbWVubsO9bWksCi0gKG51bWVyaWNrw71taSkgdmVrdG9ybWksCi0gbWF0aWNhbWkuCgpUYW0sIGtkZSBqZSB0byB1xb5pdG/EjW7DqSwgc8O6IHphaHJudXTDqSBtYWzDqSBjdmnEjWVuaWEuCgotLS0KCiMgU2thbMOhcmUgKGplZG5vxI3DrXNlbG7DqSBob2Rub3R5KQoKIyMgTnVtZXJpY2vDqSBza2Fsw6FyZQoKYGBge3J9CiMgUHJpcmFkZW5pZSBrb27FoXRhbnR5IGRvIHByZW1lbm5lagphIDwtIDkKYiA8LSAyLjMKCiMgQXJpdGhtZXRpYwpzdW1fYWIgICAgICA8LSBhICsgYiAgICAgICAgIyBzdWNldApkaWZmX2FiICAgICA8LSBhIC0gYiAgICAgICAgIyByb3pkaWVsCnByb2RfYWIgICAgIDwtIGEgKiBiICAgICAgICAjIG7DoXNvYmVuaWUKcXVvdF9hYiAgICAgPC0gYSAvIGIgICAgICAgICMgZGVsZW5pZQpwb3dlcl9hYiAgICA8LSBhIF4gYiAgICAgICAgIyB1bW9jxYhvdmFuaWUKbW9kX2FiICAgICAgPC0gYSAlJSA0ICAgICAgICMgemJ5dG9rIHBvIGRlbGVuw60gdHJvbWkgKHR6diBtb2R1bG8pCgoKIyBSb3VuZGluZwpyb3VuZF9iICAgPC0gcm91bmQoYikgICAgICAgIyB6YW9rcnVobG92YW5pZSBzbWVyb20gayBuYWpibGl6c2llbXUgY2VsZW11IGNpc2x1CmNlaWxfYiAgICA8LSBjZWlsaW5nKGIpICAgICAjIG5hamJsaXpzaWUgdnlzc2llIGNlbGUgY2lzbG8KZmxvb3JfYiAgIDwtIGZsb29yKGIpICAgICAgICMgbmFqYmxpenNpZSBuaXpzaWUgY2VsZSBjaXNsbwoKYTsgYgpzdW1fYWI7IGRpZmZfYWI7IHByb2RfYWI7IHF1b3RfYWI7IHBvd2VyX2FiOyBtb2RfYWI7CnJvdW5kX2I7IGNlaWxfYjsgZmxvb3JfYgpgYGAKCioqUG96bsOhbWt5KioKCi0gYF5gIG9wZXLDoXRvciB1bW9jxYhvdmFuaWEuCi0gYCUlYCBqZSBtb2R1bG8sIHRlZGEgemJ5dG9rIHBvIGRlbGVuw60sIAotIGByb3VuZCh4LCBkaWdpdHMgPSAwKWAgemFva3LDumjEvm92YW5pZSBuYSB1csSNaXTDvSBwb8SNZXQgZGVzYXRpbm7DvWNoIG1pZXN0IChkaWdpdHM9KS4gYWsgZGlnaXRzID0gMCwgcG90b20gaWRlIG8gY2Vsb8SNw61zZWxuw6kgemFva3LDumjEvm92YW5pZQoKCiMjIE1hbMOpIGN2acSNZW5pZQoKPiBWeXBvxI3DrXRhanRlOgoKJCRcZnJhY3soMTVeMi00KX17N30kJAoKYGBge3J9CigoMjFeKDEuMikgKiA4KSAvICgzLzIpKS0oOC8yLjUpCmBgYAoKLS0tCgojIFRleHQgCgojIyBWeXR2w6FyYW5pZSB0ZXh0b3bDvW1pIHByZW1lbm7DvW1pIGEgcHLDoWNhIHMgbmltaQoKYGBge3J9CmZpcnN0IDwtICJCYXJib3JhIiAgICAgICAgICAgICAgICAgICAgICAgIyBkZWZpbm92YW5pZSBvYnNhaHUgdGV4dG92ZWogcHJlbWVubmVqIGZpcnN0Cmxhc3QgIDwtICJLb3ByZG92YSIgICAgICAgICAgICAgICAgICAgICAgICAgICMgZGVmaW5vdmFuaWUgb2JzYWh1IHRleHQuIHByZW1lbm5laiBsYXN0CmZ1bGwgIDwtIHBhc3RlKGZpcnN0LCBsYXN0KSAgICAgICAgICAgICAgICMgc3BvamVuaWUgZHZvY2ggdGV4dC4gcHJlbWVubnljaCBkbyBqZWRuZWogKHMgbWVkemVyb3UpCmZ1bGxfbm9zcGFjZSA8LSBwYXN0ZTAoZmlyc3QsIGxhc3QpICAgICAgICMgc3BvamVuaWUgYmV6IG1lZHplcnkKY3N2X2xpbmUgPC0gcGFzdGUoInN0bHAiLCAicG9zdGVsIiwgInBhcGllciIsIHNlcCA9ICIsIikgICMgc3BvamVuaWUgdGV4dG92IHMgb2RkZWxvdmFjb20gLApmaXJzdDsgbGFzdDsgZnVsbDsgZnVsbF9ub3NwYWNlOyBjc3ZfbGluZSAgICMgYm9ka2/EjWlhcmthIHR1IG5haHJhZHp1amUgb2Rza29rIG5hIG5vdnkgcmlhZG9rIApgYGAKCiMjIETEusW+a2EgdGV4dG92w6lobyByZcWlYXpjYSwgcG9kcmXFpWF6ZWMKCmBgYHtyfQp4IDwtICJBaG9qIGphIHNvbSBGZXJvISIKbmNoYXIoeCkgICAgICAgICAgICAgICAgICMgcG/EjWV0IHpuYWtvdiAgdiByZXRhemNpICJSIGlzIGdyZWF0ISIKc3Vic3RyKHgsIDksIDExKSAgICAgICAgICAjIHBvZHJlxaVhemVjIG9kIDEuIGRvIDUuIHpuYWt1CmBgYAoKCj4gVGlwOiBLbmnFvm5pY2EgKipzdHJpbmdyKiogbW5vaMOpIHphdWrDrW1hdsOpIG1vxb5ub3N0aSBwcsOhY2UgcyB0ZXh0YW1pLCBhbGUgaW1wbGljaXRuw6kga25pxb5uaWNlIFIgcG9rcsO9dmFqw7ogdsOkxI3FoWludSBiZcW+bsO9Y2ggcG90cmllYiBww6FjZSBzIHRleHRhbWkuCgotLS0KCiMgTG9naWNrw6kgKGJvb2xvdnNrw6kpIGhvZG5vdHkgYSBwcmVtZW5uw6kKCiMjIFrDoWtsYWR5CgpgYGB7cn0KZiA8LSBUUlVFCmogPC0gRkFMU0UKIWEgICAgICAgICAgICAgICAgICMgTk9UCmYgJiBqICAgICAgICAgICAgICAjIEFORApmIHwgaiAgICAgICAgICAgICAgIyBPUgp4b3IoZiwgaikgICAgICAgICAgIyBleGNsdXNpdmUgT1IgLSBwbGF0w60gbGVuIGplZG5vIHogcCxhbGVibyBxCmBgYAoKIyMgTG9naWNrw70gdsO9c2xlZG9rIHBvcm92bsOhdmFuaWEKCmBgYHtyfQoyODEgPCAzMzMKNDQgPj0gNDQKIm9iZWQiID09ICJvYmVkIgoib2JlZCIgIT0gInZlY2VyYSIgICAjIHZ5a3JpY25payBqZSB0dSB2IHpteXNsZSBuZWdhY2llLiBOYXByLjogICAhPSwgIT4sICE8LCAhVFJVRQohVFJVRQpgYGAKCiMjIFpsb8W+aXRlasWhaWUgbG9naWNrw6kgb3BlcsOhY2llCgpgYGB7cn0KeSA8LSA4OQp5ID4gMyAmIHggPCAyMDAgICAgICAjIGEgc3VjYXNuZSAtIGxvZ2lja3kgcHJpZW5payAoc3VjaW4pCnkgPCAxMCB8IHggPiAzMCAgICAgIyBhbGVibyAtIGxvZ2lja2UgemplZG5vdGVuaWUgKHN1Y2V0KQogICAgICAgICAgICAgICAgICAgICMgcHJpIHpsb3ppdGVqc2ljaCB2enRhaG9jaCBwb3V6aXZhanRlIHphdHZvcmt5ICgpCmBgYAoKIyMgWmx1xI1vdmFuaWUgdmlhY2Vyw71jaCBsb2cuIHByZW1lbm7DvWNoIGRvIHZla3RvcmEKCmBgYHtyfQp2YWxzIDwtIGMoVFJVRSwgRkFMU0UsIFRSVUUsIFRSVUUpICAgIyBkZWZpbmljaWEgdmVrdG9yYSBzIGxvZ2lja3ltaSBob2Rub3RhbWkKYGBgCgotLS0KCiMgTnVtZXJpY2vDqSB2ZWt0b3J5CgojIyBHZW5lcm92YW5pZSB2ZWt0b3JvdgoKYGBge3J9CnYxIDwtIGMoMywgNiwgOSwgMTIpCnYyIDwtIDM6MTUgICAgICAgICAgICAgICAgICAjIHBvc3R1cG5vc3QgMSwyLDMsNCw1CnYzIDwtIHNlcShmcm9tID0gMCwgdG8gPSAxNiwgYnkgPSAwLjU1KSAgIyBwb3N0dXBub3N0IHMga3Jva29tIDAuMjUKdjQgPC0gcmVwKDMsIHRpbWVzID0gNCkgICAgIyAzLDMsMywzLDMgICMgNSBjbGVubmEgcG9zdHVwbm9zdCB0cm9qYWsKdjUgPC0gcnVuaWYoNCkgICAgICAgICAgICAgIyBnZW5lcm92YW5pZSByb3Zub21lcm5lIHJvemRlbGVueWNoIHByZW1lbm55Y2ggdiBpbnRlcnZhbGUgWzAsMV0KdjYgPC0gcm5vcm0oNCkgICAgICAgICAgICAgIyBnZW5lcm92YW5pZSBub3JtYWxuZSByb3pkZWxlbnljaCBwcmVtZW5ueWNoCnYxOyB2MjsgdjM7IHY0OyB2NQpgYGAKCiMjIEFyaXRtZXRpY2vDqSBvcGVyw6FjaWUgcyB2ZWt0b3JtaQoKYGBge3J9CnYgPC0gYygxMCwgMzIsIDQ0LCA1OCkKdiArIDMgICAgICAgICAgICMga2F6ZHkgcHJ2b2sgdmVrdG9yYSB6dmFjc2ltZSBvIDEwCnYgKiA5ICAgICAgICAgICAgIyBrYXpkeSBwcnZvayB2ZWt0b3JhIHByZW5hc29iaW1lIDIKKHYgKyAxKSAvIDIKZXhwKHYpICAgICAgICAgICAjIGV4cG9uZW5jaWFsbmEgZnVua2NpYSB6IGthemRlaG8gcHJ2a3UgdmVrdG9yYQpzdW0oYyg4LDksMTApLGMoMiwzLDMpKSAgICAgICAgICAjIHNrYWxhcm55IHN1Y2luIC0gdnlzbGVkb2sgamUgc2thbGFyCmNyb3NzcHJvZChjKDQsNiw4KSxjKDEwLDEyLDE0KSkgICAgIyBza2FsYXJueSBzdWNpbiAtIHZ5c2xlZG9rIGplIG1hdGljYSAxeDEKYygxMSwyMiwzMzMpKmMoNSw1LDUpICAgICAgICAgICAgICAgIyBIYWRhbWFyZG92IHN1Y2luIChzdWNpbiB6b2Rwb3ZlZGFqdWNpY2ggcHJ2a292IHZla3RvcmEpCmBgYAoKIyMgTWF0ZW1hdGlja8OpIG9wZXLDoWNpZSBzIDIgdmVrdG9ybWkgcm92bmFrw6lobyByb3ptZXJ1CgpgYGB7cn0KbGVuZ3RoKGMoMiw4LDE0LDEsMykpCmxlbmd0aCh2NSkgICAgICAgICAgICAjdmVrdG9yIHY1IGplIGRlZmlub3Zhbnkgdnlzc2llCmMoNiw4LDMsMTAsMSkgKyB2NSAgICAgIyBwb3pvciwgb2JhIHZla3RvcnkgbXVzaWEgbWF0IHJvdm5ha3kgcm96bWVyCmBgYAoKIyMgSW5kZXhvdmFuaWUgYSB2w71iZXIgbmlla3RvcnljaCBwcnZrb3YgdmVrdG9yYQoKYGBge3J9CnggPC0gYygzLCA4LCAzMywgMSwgMiwgMTgsIDI5KQp4WzNdICAgICAgICAgICAjIGluZGV4b3ZhbmllIC0gbm92eSBqZWRuby1wcnZrb3Z5IHZla3RvciAtIHBydnkgcHJ2b2sgdmVrdG9yYSB4CnhbMToyXSAgICAgICAgICMgbm92eSB2ZWt0b3IgcyBkcnVoeW0gYXogc3R2cnR5bSBwcnZrb20gdmVrdG9yYSB4CnhbLTVdICAgICAgICAgICMgbm92eSB2ZWt0b3IgLSB2c2V0a3kgcHJ2a3kgdmVrdG9yYSB4IG9rcmVtIHBydsOpaG8KeFt4ID4gMjBdICAgICAgIyBub3Z5IHZla3RvciBkZWZpbm92YW55IHBydmthbWkgeCB2YWNzaW1pIGFrbyAxMAp3aGljaCh4ID4gMjApICAjIGt0b3JlIHBydmt5IHpvZHBvdmVkYWp1IHBvZG1pZW5rZSB2YWNzaWVobyBha28gMTA/CmBgYAoKIyMgUHLDoWNhIHMgY2jDvWJhasO6Y2ltaSBob2Rub3RhbWkKCmBgYHtyfQp5IDwtIGMoMSwgTkEsIDMsIE5BLCA1KQppcy5uYSh5KQptZWFuKHkpICAgICAgICAgICAgICAgICAjIE5BCm1lYW4oeSwgbmEucm0gPSBUUlVFKSAgICMgcmVtb3ZlIE5BcwpgYGAKCiMjIFrDoWtsYWRuw6kgxaF0YXRpc3Rpa3kgYSB1c3BvcmlhZGFuaWUgcHJ2a292IHZla3RvcmEgcG9kxL5hIHZlxL5rb3N0aQoKYGBge3J9CmEgPC0gYygxLCA2LCAzLCA5LCA0KQptZWFuKGEpICAgICAgICAgICAgICAgICAjIHByaWVtZXJuYSBob2Rub3RhCnNkKGEpICAgICAgICAgICAgICAgICAgIyBzdGFuZGFyZG5hIG9kY2h5bGthCm1heChhKSAgICAgICAgICAgICAgICAgICMgbWF4aW1hbG5hIGhvZG5vdGEKc3VtbWFyeShhKSAgICAgICAgICAgICAgIyByeWNobHkgcHJlaGxhZCB6YWtsYWRueWNoIHN0YXRpc3RpayBvIHZla3RvcmUKc29ydChhKSAgICAgICAgICAgICAgICAgIyByYXN0dWNlIHVzcG9yaWFkYW5pZSAKc29ydChhLCBkZWNyZWFzaW5nID0gVFJVRSkgICMga2xlc2FqdWNlCmBgYAoKIyMgTWFsw6kgY3ZpxI1lbmllCj4gVnl0dm9ydGUgdmVrdG9yIGB3YCBzIMSNw61zbGFtaSAxLi4yMCBhIHZ5cG/EjcOtdGFqdGUgc3VtdSB2xaFldGvDvWNoIHDDoXJueWNoIMSNw61zZWwuCgpgYGB7cn0KayA8LSAxOjE4CnN1bSh3W3cgJSUgMiA9PSAwXSkKYGBgCgotLS0KCiMgTWF0aWNlCgojIyBWeXR2b3JlbmllIG1hdMOtYwoKYGBge3J9Cm0gPC0gbWF0cml4KDE6MTIsIG5yb3cgPSA1LCBuY29sID0gMykgICAgICAgICAgICAjIGhvZG5vdHkgc8O6IHphZGF2YW5lIHBvIHN0bHBjb2NoCm1fYnlyb3cgPC0gbWF0cml4KDE6MTIsIG5yb3cgPSA1LCBieXJvdyA9IFRSVUUpICAjIGhvZG5vdHkgc3UgemFkYXZhbmUgcG8gcmlhZGtvY2gKbTsgbV9ieXJvdwpgYGAKCiMjIFJvem1lcnkgbWF0aWNlCgpgYGB7cn0KZGltKG0pICAgICAgICAgICAgICAgICAgICMgKHJvd3MsIGNvbHMpCm0KYGBgCgojIyBBZHJlc292YW5pZSBwcnZrb3YgbWF0aWNlCgpgYGB7cn0KbVsyLCAzXSAgICAgICMgcmlhZG9rIDEsIHN0bHBlYyAyCm1bICwgMl0gICAgICAjIHZzZXRreSBwcnZreSB2IHRyZXRvbSBzdGxwY2kgLSB2eXNsZWRvayBtYXRpY2EgM3gxCm1bMywgXSAgICAgICAjIHZzZXRreSBwcnZreSB2IGRydWhvbSByaWFka3UgLSB2eXNsZWRvayBtYXRpY2EgMSozCm1bMTo1LCAxOjJdICAjIHBvZG1hdGljYSB0dm9yZW5hIHJpYWRrYW1pIDEsIDIgYSBzdGxwY2FtaSAyLCAzCmBgYAoKIyMgTWF0aWNvdsOpIG9wZXLDoWNpZQoKYGBge3J9CkEgPC0gbWF0cml4KGMoNiwyLDEsNSksIG5yb3cgPSAyKQpCIDwtIG1hdHJpeChjKDEsMyw0LDIpLCBucm93ID0gMikKQyA8LSBtYXRyaXgoYygyLDMsNSwyKSwgbnJvdyA9IDIpCgpBICsgQiAgICAgICAgIyBzY2l0YW5pZSBtYXRpYwpBICogQiAgICAgICAgIyBIYWRhbWFyZCBwcm9kdWN0IC0gbmFzb2JlbmllIHBvIHpvZHBvdmVkYWp1Y2ljaCBwcnZrb2NoCkEgJSolIEIgICAgICAjIG5hc29iZW5pZSBtYXRpYwp0KEEpICAgICAgICAgIyB0cmFuc3BvemljaWEgbWF0aWNlIEEgLSB2eW1lbmEgcmlhZGtvdiBhIHN0bHBjb3YKZGV0KEEpICAgICAgICMgZGV0ZXJtaW5hbnQgbWF0aWNlCnNvbHZlKEEpICAgICAjIGludmVyemlhIG1hdGljZSAoYWsgamUgbWF0aWNhIHJlZ3VsYXJuYSAtIHRlZGEgaW52ZXJ6aWEgc2EgZGEgc3BvY2l0YXQpCmBgYAoKIyMgWmx1xI1vdmFuaWUgdmVrdG9yb3YgZG8gbWF0w61jIAoKYGBge3J9CkMgPC0gY2JpbmQoMjo0LCAxOjMpICAgIyAgLSBwbyBzdGxwY29jaCAKRCA8LSByYmluZCg4OjMsIDU6NykgICAjICAtIHBvIHJpYWRrb2NoIApDOyBECmBgYAoKIyMgVnlwb8SNw610YW5pZSB6dm9sZW5laiDFoXRhdGlzdGlreSBwbyByaWFka29jaCAoc3TEunBjb2NoKSBtYXRpY2UKCmBgYHtyfQpNIDwtIG1hdHJpeCgyOjQsIG5yb3cgPSAyKQpNCmFwcGx5KE0sIDIsIHN1bSkgICAjIHN1bWEgcG8gcmlhZGtvY2gKYXBwbHkoTSwgMiwgbWVhbikgICMgcHJpZW1lcnkgcG8gc3TEunBjb2NoCmBgYAoKIyMgTWFsw6kgY3ZpxI1lbmllCgo+IFZ5dHZvcnRlIG1hdGljdSA1eDUgcyBob2Rub3RhbWkgcG8gcmlhZGtvY2ggMS4uMjUsIHZ5cG/EjcOtdGFqdGUgc3TEunBjb3bDqSBzdW15IGEgc8O6xI1pbiBtYXTDrWMgXChNXnQgTVwpLgoKYGBge3J9Ck0yIDwtIG1hdHJpeCgxOjE1LCBucm93ID0gNSwgYnlyb3cgPSBUUlVFKQpjb2xTdW1zKE0yKQp0KE0yKSAlKiUgTTIKYGBgCmBgYHtyfQojIDEpIE1vamUgZMOhdGEgCndhdGVyIDwtIGMoNiwgOCwgNSwgOSwgNywgNCwgMTApICAjIFBvxI1ldCBwb2jDoXJvdiB2b2R5IHYgZMWIb2NoIDEuLjcKCiMgMikgTWFsw6kgw7psb2h5CnN1bSh3YXRlciA+PSA4KSAgICAgICAgICAgIyBhKSBrb8S+a28gZG7DrSA+PSA4IHBvaMOhcm92Cm1lYW4od2F0ZXIpICAgICAgICAgICAgICAgIyBiKSBwcmllbWVyIHphIHTDvcW+ZGXFiAp3aGljaC5tYXgod2F0ZXIpICAgICAgICAgICMgYykga3RvcsO9IGRlxYggYm9sIG5hamxlcMWhw60gKGluZGV4IGTFiGEgMS4uNykKd2F0ZXJbd2hpY2gubWF4KHdhdGVyKV0gICAjICAgIGtvxL5rbyBwb2jDoXJvdiB0byBib2xvCgojIDMpIEdyYWYgKMSNYXNvdsOhIGtyaXZrYSkKcGxvdCgKICB3YXRlciwgdHlwZSA9ICJvIiwKICBtYWluID0gIlBvaMOhcmUgdm9keSB6YSA3IGRuw60iLAogIHhsYWIgPSAiRGXFiCIsIHlsYWIgPSAiUG/EjWV0IHBvaMOhcm92IiwKICB5bGltID0gYygwLCBtYXgod2F0ZXIpICsgMSkKKQphYmxpbmUoaCA9IDgsIGx0eSA9IDIpICAjIHZ5em5hxI1lbsO9IGNpZcS+IDggcG9ow6Fyb3YKCmRheXMgPC0gYygiUG8iLCJVdCIsIlN0IiwixaB0IiwiUGkiLCJTbyIsIk5lIikKcGxvdCgxOjcsIHdhdGVyLCB0eXBlPSJvIiwgeGF4dD0ibiIsIHhsYWI9IkRlxYgiLCB5bGFiPSJQb2jDoXJlIikKYXhpcygxLCBhdD0xOjcsIGxhYmVscz1kYXlzKTsgYWJsaW5lKGg9OCwgbHR5PTIpCgpgYGAKCgoKCgoKCgo=