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 (modifikované) (jednočíselné hodnoty)

Numerické skaláre

  # Priradenie konštanty do premennej
x1 <- 8
x2 <- 3.65

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


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

x1; x2
[1] 8
[1] 3.65
sum_ab; diff_ab; prod_ab; quot_ab; power_ab; mod_ab
[1] 11.65
[1] 4.35
[1] 29.2
[1] 2.191781
[1] 1978.238
[1] 0
round_b; ceil_b; floor_b
[1] 4
[1] 4
[1] 3

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}\]

(16^3 - 5) / 8
[1] 511.375

Text

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

first <- "Filip"  # definovanie obsahu textovej premennej first
last  <- "Jurkáček"  # definovanie obsahu text (upravený). premennej last
full  <- paste(first, last)  # spojenie dvoch text (upravený). premennych do jednej (s medzerou)
full_nospace <- paste0(first, last)  # spojenie bez medzery
csv_line <- paste("pes", "mačka", "kačka", sep = ",")  # spojenie textov s oddelovacom ,
first; last; full; full_nospace; csv_line  # bodkočiarka tu nahradzuje odskok na novy riadok
[1] "Filip"
[1] "Jurkáček"
[1] "Filip Jurkáček"
[1] "FilipJurkáček"
[1] "pes,mačka,kačka"

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

x <- "Oh yeah!"
nchar(x)  # count znakov  v retazci "Oh yeah!"
[1] 8
substr(x, 2, 6)  # podreťazec od 1. do 5. znaku
[1] "h yea"

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

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

Logický výsledok porovnávania

4 < 6
[1] TRUE
8 >= 8
[1] TRUE
"pes" == "pes"
[1] TRUE
"pes" != "mačka"  # vykricnik je tu v zmysle negacie. Napr.:   !=, !>, !<, !TRUE
[1] TRUE
!TRUE
[1] FALSE

Zložitejšie logické operácie

x <- 11
x > 6 & x < 22  # a sucasne - logicky prienik (sucin)
[1] TRUE
x < 1 | x > 102  # alebo - logicke zjednotenie (sucet)
[1] FALSE
  # pri zlozitejsich vztahoch pouzivajte zatvorky ()

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

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

Numerické vektory

Generovanie vektorov

v1 <- c(3, 5, 7, 9)
v2 <- 2:6  # postupnost 1,2,3,4,5
v3 <- seq(from = 1, to = 2, by = 0.4)  # postupnost s krokom 0.25
v4 <- rep(4, times = 6)  # 3,3,3,3,3  # 5 clenna postupnost trojak
v5 <- runif(6)  # generovanie rovnomerne rozdelenych premennych v intervale [0,1]
v6 <- rnorm(6)  # generovanie normalne rozdelenych premennych
v1; v2; v3; v4; v5
[1] 3 5 7 9
[1] 2 3 4 5 6
[1] 1.0 1.4 1.8
[1] 4 4 4 4 4 4
[1] 0.36252083 0.03471193 0.86813745 0.76959321 0.52053824 0.69562722

Aritmetické operácie s vektormi

v <- c(2, 3, 4, 5)
v + 11  # kazdy prvok vektora zvacsime o 10
[1] 13 14 15 16
v * 3  # kazdy prvok vektora prenasobime 2
[1]  6  9 12 15
(v + 2) / 3
[1] 1.333333 1.666667 2.000000 2.333333
exp(v)  # exponencialna funkcia z kazdeho prvku vektora
[1]   7.389056  20.085537  54.598150 148.413159
sum(c(2,3,4),c(2,2,2))  # skalarny sucin - vysledok je skalar
[1] 15
crossprod(c(2,3,4),c(2,2,2))  # skalarny sucin - vysledok je matica (upravená) 1x1
     [,1]
[1,]   18
c(2,3,4)*c(2,2,2)  # Hadamardov sucin (sucin zodpovedajucich 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 (nový) v5 je definovany vyssie
[1] 6
c(2,3,4,5,6) + v5  # pozor, oba vektory musia mat rovnaky rozmer
[1] 2.362521 3.034712 4.868137 5.769593 6.520538 2.695627

Indexovanie a výber niektorych prvkov vektora

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

Práca s chýbajúcimi hodnotami

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

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

z <- c(11, 4, 6, 9, 3)
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 (upr.)

Malé cvičenie

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

w <- 2:22
sum(w[w %% 3 == 1])
[1] 91

Matice (variácia)

Vytvorenie matíc

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

Rozmery matice

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

Adresovanie prvkov matice

m[2, 3]  # riadok 1, stlpec 2
[1] 11
m[ , 4]  # vsetky prvky v tretom stlpci - vysledok matica (upravená) 3x1
[1] 2 3 4 5
m[3, ]  # vsetky prvky v druhom riadku - vysledok matica (upravená) 1*3
[1]  4  8 12  4  8
m[2:3, 3:4]  # podmatica tvorena riadkami 1, 2 a stlpcami 2, 3
     [,1] [,2]
[1,]   11    3
[2,]   12    4

Maticové operácie

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

A + B     # scitanie matic
     [,1] [,2]
[1,]    8   12
[2,]   10   14
A * B     # Hadamard product - nasobenie po zodpovedajucich prvkoch
     [,1] [,2]
[1,]   12   32
[2,]   21   45
A %*%B   # nasobenie matic
     [,1] [,2]
[1,]   40   52
[2,]   53   69
t(A)      # transpozicia matice A - vymena riadkov a stlpcov
     [,1] [,2]
[1,]    2    3
[2,]    4    5
det(A)    # determinant matice
[1] -2
solve(A)  # inverzia matice (ak je matica (upravená) regularna - teda inverzia sa da spocitat)
     [,1] [,2]
[1,] -2.5    2
[2,]  1.5   -1

Zlučovanie vektorov do matíc

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

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

M <- matrix(2:10, nrow = 4)
M
     [,1] [,2] [,3]
[1,]    2    6   10
[2,]    3    7    2
[3,]    4    8    3
[4,]    5    9    4
apply(M, 2, sum)  # suma po riadkoch
[1] 14 30 19
apply(M, 2, mean)  # priemery po stĺpcoch
[1] 3.50 7.50 4.75

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(2:27, nrow = 6, byrow = TRUE)
colSums(M2)
[1] 87 67 73 79 85
t(M2) %*% M2
     [,1] [,2] [,3] [,4] [,5]
[1,] 1699 1084 1171 1258 1345
[2,] 1084 1099 1166 1233 1300
[3,] 1171 1166 1239 1312 1385
[4,] 1258 1233 1312 1391 1470
[5,] 1345 1300 1385 1470 1555

LS0tCnRpdGxlOiAiWsOha2xhZG7DqSBvcGVyw6FjaWUgdiBSIgphdXRob3I6ICJGaWxpcCBKdXJrw6HEjWVrICA8YnI+CihzIHZ5dcW+aXTDrW0gQ2hhdEdQVCkiCmRhdGU6ICJPa3TDs2JlciAyMDI1IgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdGhlbWU6IHVuaXRlZAogICAgaGlnaGxpZ2h0OiB0YW5nbwplZGl0b3Jfb3B0aW9uczogCiAgbWFya2Rvd246IAogICAgd3JhcDogNzIKLS0tCgojIEdsb2LDoWxuZSBuYXN0YXZlbmllIENodW5rb3YKClYgbmnFvsWhaWUgdXZlZGVub20gQ2h1bmt1IGplIHVyb2JlbsOpIHrDoWtsYWRuw6kgZ2xvYsOhbG5lIG5hc3RhdmVuaWUgQ2h1bmtvdiB2IGNlbG9tIE5vdGVib29rdS4gCgotICoqZWNobyoqIG5hc3RhdnVqZSwgxI1pIGNoY2VtZSB2IE5vdGVib29rdSB2eXBpc292YcWlIGplZG5vdGxpdsOpIGvDs2R5IFIKLSAqKm1lc3NhZ2UqKiBqZSBuYXN0YXZlbsO9IG5hICpGQUxTRSosIMSNbyB6bmFtZW7DoSwgxb5lIHNhIGJ1ZMO6IHBvdGzDocSNYcWlIHByYWNvdm7DqSB2w71zdHVweSB6IFIsIHQuai4gbmFwcsOta2xhZCB2w71zbGVkb2sgb3R2w6FyYW5pYSBrbmnFvm7DrWMsIGEgbmlla3RvcsOpIGluw6kgdsO9c3R1cHksIGt0b3LDqSBhbGUgcHJlIGNlbGtvdsO9IE5vdGVib29rIG5lbWFqw7ogdGFrbWVyIMW+aWFkZW4gdsO9em5hbSBhIHPDuiB2aG9kbsOpIHNrw7RyIHByaSBsYWRlbsOtIGvDs2Rvdi4KLSAqKndhcm5pbmcqKiBuYXN0YXZlbsO9IG5hIEZBTFNFIHBvdGzDocSNYSB6b2JyYXplbmllIGNoeWJvdsO9Y2ggaGzDocWhb2sKCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1UUlVFLGVjaG89VFJVRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVjaG8gPSBUUlVFLAogIG1lc3NhZ2UgPSBGQUxTRSwKICB3YXJuaW5nID0gRkFMU0UKKQpgYGAKCiMgw5p2b2QgayB6w6FrbGFkbsO9bSBvcGVyw6FjacOhbSB2IFIKClRlbnRvIG5vdGVib29rIGRlbW9uxaF0cnVqZSAqKnrDoWtsYWRuw6kgb3BlcsOhY2llKiogdiBqYXp5a3UgUiBzbzoKCi0gc2thbMOhcm55bWkgxI3DrXNsYW1pICh0LmouIDEgxI3DrXNsbyksCi0gdGV4dG92w71taSAoem5ha292w71taSkgcmXFpWF6Y2FtaSwKLSBsb2dpY2vDvW1pIChib29sb3Zza8O9bWkpIGhvZG5vdGFtaSBhIHByZW1lbm7DvW1pLAotIChudW1lcmlja8O9bWkpIHZla3Rvcm1pLAotIG1hdGljYW1pLgoKVGFtLCBrZGUgamUgdG8gdcW+aXRvxI1uw6ksIHPDuiB6YWhybnV0w6kgbWFsw6kgY3ZpxI1lbmlhLgoKLS0tCgojIFNrYWzDoXJlIChtb2RpZmlrb3ZhbsOpKSAoamVkbm/EjcOtc2VsbsOpIGhvZG5vdHkpCgojIyBOdW1lcmlja8OpIHNrYWzDoXJlCgpgYGB7cn0KICAjIFByaXJhZGVuaWUga29uxaF0YW50eSBkbyBwcmVtZW5uZWoKeDEgPC0gOAp4MiA8LSAzLjY1CgogICMgQXJpdGhtZXRpYyAodXByLikKc3VtX2FiICAgICAgPC0geDEgKyB4MiAgIyBzdWNldCAodXByLikKZGlmZl9hYiAgICAgPC0geDEgLSB4MiAgIyByb3pkaWVsICh1cHIuKQpwcm9kX2FiICAgICA8LSB4MSAqIHgyICAjIG7DoXNvYmVuaWUgKHVwci4pCnF1b3RfYWIgICAgIDwtIHgxIC8geDIgICMgZGVsZW5pZSAodXByLikKcG93ZXJfYWIgICAgPC0geDEgXiB4MiAgIyB1bW9jxYhvdmFuaWUgKHVwci4pCm1vZF9hYiAgICAgIDwtIHgxICUlIDQgICMgemJ5dG9rIHBvIGRlbGVuw60gdHJvbWkgKHR6diBtb2R1bG8pCgoKICAjIFJvdW5kaW5nICh1cHIuKQpyb3VuZF9iICAgPC0gcm91bmQoeDIpICAjIHphb2tydWhsb3ZhbmllIHNtZXJvbSBrIG5hamJsaXpzaWVtdSBjZWxlbXUgY2lzbHUKY2VpbF9iICAgIDwtIGNlaWxpbmcoeDIpICAjIG5hamJsaXpzaWUgdnlzc2llIGNlbGUgY2lzbG8KZmxvb3JfYiAgIDwtIGZsb29yKHgyKSAgIyBuYWpibGl6c2llIG5penNpZSBjZWxlIGNpc2xvCgp4MTsgeDIKc3VtX2FiOyBkaWZmX2FiOyBwcm9kX2FiOyBxdW90X2FiOyBwb3dlcl9hYjsgbW9kX2FiCnJvdW5kX2I7IGNlaWxfYjsgZmxvb3JfYgpgYGAKCioqUG96bsOhbWt5KioKCi0gYF5gIG9wZXLDoXRvciB1bW9jxYhvdmFuaWEuCi0gYCUlYCBqZSBtb2R1bG8sIHRlZGEgemJ5dG9rIHBvIGRlbGVuw60sIAotIGByb3VuZCh4LCBkaWdpdHMgPSAwKWAgemFva3LDumjEvm92YW5pZSBuYSB1csSNaXTDvSBwb8SNZXQgZGVzYXRpbm7DvWNoIG1pZXN0IChkaWdpdHM9KS4gYWsgZGlnaXRzID0gMCwgcG90b20gaWRlIG8gY2Vsb8SNw61zZWxuw6kgemFva3LDumjEvm92YW5pZQoKCiMjIE1hbMOpIGN2acSNZW5pZQoKPiBWeXBvxI3DrXRhanRlOgoKJCRcZnJhY3soMTVeMi00KX17N30kJAoKYGBge3J9CigxNl4zIC0gNSkgLyA4CmBgYAoKLS0tCgojIFRleHQgCgojIyBWeXR2w6FyYW5pZSB0ZXh0b3bDvW1pIHByZW1lbm7DvW1pIGEgcHLDoWNhIHMgbmltaQoKYGBge3J9CmZpcnN0IDwtICJGaWxpcCIgICMgZGVmaW5vdmFuaWUgb2JzYWh1IHRleHRvdmVqIHByZW1lbm5laiBmaXJzdApsYXN0ICA8LSAiSnVya8OhxI1layIgICMgZGVmaW5vdmFuaWUgb2JzYWh1IHRleHQgKHVwcmF2ZW7DvSkuIHByZW1lbm5laiBsYXN0CmZ1bGwgIDwtIHBhc3RlKGZpcnN0LCBsYXN0KSAgIyBzcG9qZW5pZSBkdm9jaCB0ZXh0ICh1cHJhdmVuw70pLiBwcmVtZW5ueWNoIGRvIGplZG5laiAocyBtZWR6ZXJvdSkKZnVsbF9ub3NwYWNlIDwtIHBhc3RlMChmaXJzdCwgbGFzdCkgICMgc3BvamVuaWUgYmV6IG1lZHplcnkKY3N2X2xpbmUgPC0gcGFzdGUoInBlcyIsICJtYcSNa2EiLCAia2HEjWthIiwgc2VwID0gIiwiKSAgIyBzcG9qZW5pZSB0ZXh0b3YgcyBvZGRlbG92YWNvbSAsCmZpcnN0OyBsYXN0OyBmdWxsOyBmdWxsX25vc3BhY2U7IGNzdl9saW5lICAjIGJvZGtvxI1pYXJrYSB0dSBuYWhyYWR6dWplIG9kc2tvayBuYSBub3Z5IHJpYWRvawpgYGAKCiMjIETEusW+a2EgdGV4dG92w6lobyByZcWlYXpjYSwgcG9kcmXFpWF6ZWMKCmBgYHtyfQp4IDwtICJPaCB5ZWFoISIKbmNoYXIoeCkgICMgY291bnQgem5ha292ICB2IHJldGF6Y2kgIk9oIHllYWghIgpzdWJzdHIoeCwgMiwgNikgICMgcG9kcmXFpWF6ZWMgb2QgMS4gZG8gNS4gem5ha3UKYGBgCgoKPiBUaXA6IEtuacW+bmljYSAqKnN0cmluZ3IqKiBtbm9ow6kgemF1asOtbWF2w6kgbW/Fvm5vc3RpIHByw6FjZSBzIHRleHRhbWksIGFsZSBpbXBsaWNpdG7DqSBrbmnFvm5pY2UgUiBwb2tyw712YWrDuiB2w6TEjcWhaW51IGJlxb5uw71jaCBwb3RyaWViIHDDoWNlIHMgdGV4dGFtaS4KCi0tLQoKIyBMb2dpY2vDqSAoYm9vbG92c2vDqSkgaG9kbm90eSBhIHByZW1lbm7DqQoKIyMgWsOha2xhZHkKCmBgYHtyfQphIDwtIFRSVUUKYiA8LSBGQUxTRQohYSAgIyBOT1QgKHVwci4pCmEgJiBiICAjIEFORCAodXByLikKYSB8IGIgICMgT1IgKHVwci4pCnhvcihhLCBiKSAgIyBleGNsdXNpdmUgT1IgLSBwbGF0w60gbGVuIGplZG5vIHogcCxhbGVibyBxCmBgYAoKIyMgTG9naWNrw70gdsO9c2xlZG9rIHBvcm92bsOhdmFuaWEKCmBgYHtyfQo0IDwgNgo4ID49IDgKInBlcyIgPT0gInBlcyIKInBlcyIgIT0gIm1hxI1rYSIgICMgdnlrcmljbmlrIGplIHR1IHYgem15c2xlIG5lZ2FjaWUuIE5hcHIuOiAgICE9LCAhPiwgITwsICFUUlVFCiFUUlVFCmBgYAoKIyMgWmxvxb5pdGVqxaFpZSBsb2dpY2vDqSBvcGVyw6FjaWUKCmBgYHtyfQp4IDwtIDExCnggPiA2ICYgeCA8IDIyICAjIGEgc3VjYXNuZSAtIGxvZ2lja3kgcHJpZW5payAoc3VjaW4pCnggPCAxIHwgeCA+IDEwMiAgIyBhbGVibyAtIGxvZ2lja2UgemplZG5vdGVuaWUgKHN1Y2V0KQogICMgcHJpIHpsb3ppdGVqc2ljaCB2enRhaG9jaCBwb3V6aXZhanRlIHphdHZvcmt5ICgpCmBgYAoKIyMgWmx1xI1vdmFuaWUgdmlhY2Vyw71jaCBsb2cuIHByZW1lbm7DvWNoIGRvIHZla3RvcmEKCmBgYHtyfQp2YWxzIDwtIHgzKFRSVUUsIEZBTFNFLCBUUlVFLCBUUlVFKSAgIyBkZWZpbmljaWEgdmVrdG9yYSBzIGxvZ2lja3ltaSBob2Rub3RhbWkKYGBgCgotLS0KCiMgTnVtZXJpY2vDqSB2ZWt0b3J5CgojIyBHZW5lcm92YW5pZSB2ZWt0b3JvdgoKYGBge3J9CnYxIDwtIGMoMywgNSwgNywgOSkKdjIgPC0gMjo2ICAjIHBvc3R1cG5vc3QgMSwyLDMsNCw1CnYzIDwtIHNlcShmcm9tID0gMSwgdG8gPSAyLCBieSA9IDAuNCkgICMgcG9zdHVwbm9zdCBzIGtyb2tvbSAwLjI1CnY0IDwtIHJlcCg0LCB0aW1lcyA9IDYpICAjIDMsMywzLDMsMyAgIyA1IGNsZW5uYSBwb3N0dXBub3N0IHRyb2phawp2NSA8LSBydW5pZig2KSAgIyBnZW5lcm92YW5pZSByb3Zub21lcm5lIHJvemRlbGVueWNoIHByZW1lbm55Y2ggdiBpbnRlcnZhbGUgWzAsMV0KdjYgPC0gcm5vcm0oNikgICMgZ2VuZXJvdmFuaWUgbm9ybWFsbmUgcm96ZGVsZW55Y2ggcHJlbWVubnljaAp2MTsgdjI7IHYzOyB2NDsgdjUKYGBgCgojIyBBcml0bWV0aWNrw6kgb3BlcsOhY2llIHMgdmVrdG9ybWkKCmBgYHtyfQp2IDwtIGMoMiwgMywgNCwgNSkKdiArIDExICAjIGthemR5IHBydm9rIHZla3RvcmEgenZhY3NpbWUgbyAxMAp2ICogMyAgIyBrYXpkeSBwcnZvayB2ZWt0b3JhIHByZW5hc29iaW1lIDIKKHYgKyAyKSAvIDMKZXhwKHYpICAjIGV4cG9uZW5jaWFsbmEgZnVua2NpYSB6IGthemRlaG8gcHJ2a3UgdmVrdG9yYQpzdW0oYygyLDMsNCksYygyLDIsMikpICAjIHNrYWxhcm55IHN1Y2luIC0gdnlzbGVkb2sgamUgc2thbGFyCmNyb3NzcHJvZChjKDIsMyw0KSxjKDIsMiwyKSkgICMgc2thbGFybnkgc3VjaW4gLSB2eXNsZWRvayBqZSBtYXRpY2EgKHVwcmF2ZW7DoSkgMXgxCmMoMiwzLDQpKmMoMiwyLDIpICAjIEhhZGFtYXJkb3Ygc3VjaW4gKHN1Y2luIHpvZHBvdmVkYWp1Y2ljaCBwcnZrb3YgdmVrdG9yYSkKYGBgCgojIyBNYXRlbWF0aWNrw6kgb3BlcsOhY2llIHMgMiB2ZWt0b3JtaSByb3ZuYWvDqWhvIHJvem1lcnUKCmBgYHtyfQpsZW5ndGgoYygyLDMsNCw1LDYpKQpsZW5ndGgodjUpICAjIHZla3RvciAobm92w70pIHY1IGplIGRlZmlub3Zhbnkgdnlzc2llCmMoMiwzLDQsNSw2KSArIHY1ICAjIHBvem9yLCBvYmEgdmVrdG9yeSBtdXNpYSBtYXQgcm92bmFreSByb3ptZXIKYGBgCgojIyBJbmRleG92YW5pZSBhIHbDvWJlciBuaWVrdG9yeWNoIHBydmtvdiB2ZWt0b3JhCgpgYGB7cn0KeCA8LSBjKDYsIDEzLCA0LCAxOSwgOCwgMSwgMjMpCnhbMl0gICMgaW5kZXhvdmFuaWUgLSBub3Z5IGplZG5vLXBydmtvdnkgdmVrdG9yIChub3bDvSkgLSBwcnZ5IHBydm9rIHZla3RvcmEgeAp4WzM6NV0gICMgbm92eSB2ZWt0b3IgKG5vdsO9KSBzIGRydWh5bSBheiBzdHZydHltIHBydmtvbSB2ZWt0b3JhIHgKeFswXSAgIyBub3Z5IHZla3RvciAobm92w70pIC0gdnNldGt5IHBydmt5IHZla3RvcmEgeCBva3JlbSBwcnbDqWhvCnhbeCA+IDExXSAgIyBub3Z5IHZla3RvciAobm92w70pIGRlZmlub3ZhbnkgcHJ2a2FtaSB4IHZhY3NpbWkgYWtvIDEwCndoaWNoKHggPiAxMSkgICMga3RvcmUgcHJ2a3kgem9kcG92ZWRhanUgcG9kbWllbmtlIHZhY3NpZWhvIGFrbyAxMD8KYGBgCgojIyBQcsOhY2EgcyBjaMO9YmFqw7pjaW1pIGhvZG5vdGFtaQoKYGBge3J9CnkgPC0gYygyLCBOQSwgNCwgTkEsIDYpCmlzLm5hKHkpCm1lYW4oeSkgICMgTkEgKHVwci4pCm1lYW4oeSwgbmEucm0gPSBUUlVFKSAgIyByZW1vdmUgTkFzICh1cHIuKQpgYGAKCiMjIFrDoWtsYWRuw6kgxaF0YXRpc3Rpa3kgYSB1c3BvcmlhZGFuaWUgcHJ2a292IHZla3RvcmEgcG9kxL5hIHZlxL5rb3N0aQoKYGBge3J9CnogPC0gYygxMSwgNCwgNiwgOSwgMykKbWVhbih6KSAgIyBwcmllbWVybmEgaG9kbm90YQpzZCh6KSAgIyBzdGFuZGFyZG5hIG9kY2h5bGthCm1heCh6KSAgIyBtYXhpbWFsbmEgaG9kbm90YQpzdW1tYXJ5KHopICAjIHJ5Y2hseSBwcmVobGFkIHpha2xhZG55Y2ggc3RhdGlzdGlrIG8gdmVrdG9yZQpzb3J0KHopICAjIHJhc3R1Y2UgdXNwb3JpYWRhbmllCnNvcnQoeiwgZGVjcmVhc2luZyA9IFRSVUUpICAjIGtsZXNhanVjZSAodXByLikKYGBgCgojIyBNYWzDqSBjdmnEjWVuaWUKPiBWeXR2b3J0ZSB2ZWt0b3IgYHdgIHMgxI3DrXNsYW1pIDEuLjIwIGEgdnlwb8SNw610YWp0ZSBzdW11IHbFoWV0a8O9Y2ggcMOhcm55Y2ggxI3DrXNlbC4KCmBgYHtyfQp3IDwtIDI6MjIKc3VtKHdbdyAlJSAzID09IDFdKQpgYGAKCi0tLQoKIyBNYXRpY2UgKHZhcmnDoWNpYSkKCiMjIFZ5dHZvcmVuaWUgbWF0w61jCgpgYGB7cn0KbSA8LSBtYXRyaXgoMjoxMywgbnJvdyA9IDQsIG5jb2wgPSA1KSAgIyBob2Rub3R5IHPDuiB6YWRhdmFuZSBwbyBzdGxwY29jaAptX2J5cm93IDwtIG1hdHJpeCgyOjEzLCBucm93ID0gNCwgYnlyb3cgPSBUUlVFKSAgIyBob2Rub3R5IHN1IHphZGF2YW5lIHBvIHJpYWRrb2NoCm07IG1fYnlyb3cKYGBgCgojIyBSb3ptZXJ5IG1hdGljZQoKYGBge3J9CmRpbShtKSAgIyAocm93cywgY29scykKbQpgYGAKCiMjIEFkcmVzb3ZhbmllIHBydmtvdiBtYXRpY2UKCmBgYHtyfQptWzIsIDNdICAjIHJpYWRvayAxLCBzdGxwZWMgMgptWyAsIDRdICAjIHZzZXRreSBwcnZreSB2IHRyZXRvbSBzdGxwY2kgLSB2eXNsZWRvayBtYXRpY2EgKHVwcmF2ZW7DoSkgM3gxCm1bMywgXSAgIyB2c2V0a3kgcHJ2a3kgdiBkcnVob20gcmlhZGt1IC0gdnlzbGVkb2sgbWF0aWNhICh1cHJhdmVuw6EpIDEqMwptWzI6MywgMzo0XSAgIyBwb2RtYXRpY2EgdHZvcmVuYSByaWFka2FtaSAxLCAyIGEgc3RscGNhbWkgMiwgMwpgYGAKCiMjIE1hdGljb3bDqSBvcGVyw6FjaWUKCmBgYHtyfQpBIDwtIG1hdHJpeChjKDIsMyw0LDUpLCBucm93ID0gMikKQiA8LSBtYXRyaXgoYyg2LDcsOCw5KSwgbnJvdyA9IDIpCgpBICsgQiAgICAgIyBzY2l0YW5pZSBtYXRpYwpBICogQiAgICAgIyBIYWRhbWFyZCBwcm9kdWN0IC0gbmFzb2JlbmllIHBvIHpvZHBvdmVkYWp1Y2ljaCBwcnZrb2NoCkEgJSolQiAgICMgbmFzb2JlbmllIG1hdGljCnQoQSkgICAgICAjIHRyYW5zcG96aWNpYSBtYXRpY2UgQSAtIHZ5bWVuYSByaWFka292IGEgc3RscGNvdgpkZXQoQSkgICAgIyBkZXRlcm1pbmFudCBtYXRpY2UKc29sdmUoQSkgICMgaW52ZXJ6aWEgbWF0aWNlIChhayBqZSBtYXRpY2EgKHVwcmF2ZW7DoSkgcmVndWxhcm5hIC0gdGVkYSBpbnZlcnppYSBzYSBkYSBzcG9jaXRhdCkKYGBgCgojIyBabHXEjW92YW5pZSB2ZWt0b3JvdiBkbyBtYXTDrWMgCgpgYGB7cn0KQyA8LSBjYmluZCgyOjQsIDU6NykgICMgLSBwbyBzdGxwY29jaApEIDwtIHJiaW5kKDI6NCwgNTo3KSAgIyAtIHBvIHJpYWRrb2NoCkM7IEQKYGBgCgojIyBWeXBvxI3DrXRhbmllIHp2b2xlbmVqIMWhdGF0aXN0aWt5IHBvIHJpYWRrb2NoIChzdMS6cGNvY2gpIG1hdGljZQoKYGBge3J9Ck0gPC0gbWF0cml4KDI6MTAsIG5yb3cgPSA0KQpNCmFwcGx5KE0sIDIsIHN1bSkgICMgc3VtYSBwbyByaWFka29jaAphcHBseShNLCAyLCBtZWFuKSAgIyBwcmllbWVyeSBwbyBzdMS6cGNvY2gKYGBgCgojIyBNYWzDqSBjdmnEjWVuaWUKCj4gVnl0dm9ydGUgbWF0aWN1IDV4NSBzIGhvZG5vdGFtaSBwbyByaWFka29jaCAxLi4yNSwgdnlwb8SNw610YWp0ZSBzdMS6cGNvdsOpIHN1bXkgYSBzw7rEjWluIG1hdMOtYyBcKE1edCBNXCkuCgpgYGB7cn0KTTIgPC0gbWF0cml4KDI6MjcsIG5yb3cgPSA2LCBieXJvdyA9IFRSVUUpCmNvbFN1bXMoTTIpCnQoTTIpICUqJSBNMgpgYGAKCi0tLQoKCgoK