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 <- c(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.5999890 0.3328235 0.4886130 0.9544738 0.4829024 0.8903502

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.599989 3.332824 4.488613 5.954474 6.482902 2.890350

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
[1] 6.6
sd(z)  # standardna odchylka
[1] 3.361547
max(z)  # maximalna hodnota
[1] 11
summary(z)  # rychly prehlad zakladnych statistik o vektore
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
    3.0     4.0     6.0     6.6     9.0    11.0 
sort(z)  # rastuce usporiadanie
[1]  3  4  6  9 11
sort(z, decreasing = TRUE)  # klesajuce (upr.)
[1] 11  9  6  4  3

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
# Vytvorenie matice s údajmi
predaje <- matrix(
  c(15, 22, 28,   # Kategória A
    19, 17, 12,   # Kategória B
    10, 14, 23),  # Kategória C
  nrow = 3,
  byrow = TRUE
)

rownames(predaje) <- c("Kategória A", "Kategória B", "Kategória C")
colnames(predaje) <- c("Skupina 1", "Skupina 2", "Skupina 3")

# Farebná paleta
farby <- c("steelblue", "tomato", "goldenrod")

# Vytvorenie grafu vedľa seba (beside = TRUE)
barplot(
  predaje,
  beside = TRUE,
  col = farby,
  main = "Predaje podľa skupín",
  xlab = "Skupiny",
  ylab = "Počet predaných kusov",
  ylim = c(0, 35)
)

# Umiestnenie legendy vpravo od grafu
legend(
  "topright",
  legend = rownames(predaje),
  fill = farby,
  bty = "n",         # bez rámčeka
  inset = c(-0.05, 0), # posunutie doprava mimo graf
  xpd = TRUE          # umožní kresliť mimo oblasti grafu
)

LS0tCnRpdGxlOiAiWsOha2xhZG7DqSBvcGVyw6FjaWUgdiBSIgphdXRob3I6ICJGaWxpcCBKdXJrw6HEjWVrICA8YnI+CihzIHZ5dcW+aXTDrW0gQ2hhdEdQVCkiCmRhdGU6ICJPa3TDs2JlciAyMDI1IgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdGhlbWU6IHVuaXRlZAogICAgaGlnaGxpZ2h0OiB0YW5nbwplZGl0b3Jfb3B0aW9uczogCiAgbWFya2Rvd246IAogICAgd3JhcDogNzIKLS0tCgojIEdsb2LDoWxuZSBuYXN0YXZlbmllIENodW5rb3YKClYgbmnFvsWhaWUgdXZlZGVub20gQ2h1bmt1IGplIHVyb2JlbsOpIHrDoWtsYWRuw6kgZ2xvYsOhbG5lIG5hc3RhdmVuaWUgQ2h1bmtvdiB2IGNlbG9tIE5vdGVib29rdS4gCgotICoqZWNobyoqIG5hc3RhdnVqZSwgxI1pIGNoY2VtZSB2IE5vdGVib29rdSB2eXBpc292YcWlIGplZG5vdGxpdsOpIGvDs2R5IFIKLSAqKm1lc3NhZ2UqKiBqZSBuYXN0YXZlbsO9IG5hICpGQUxTRSosIMSNbyB6bmFtZW7DoSwgxb5lIHNhIGJ1ZMO6IHBvdGzDocSNYcWlIHByYWNvdm7DqSB2w71zdHVweSB6IFIsIHQuai4gbmFwcsOta2xhZCB2w71zbGVkb2sgb3R2w6FyYW5pYSBrbmnFvm7DrWMsIGEgbmlla3RvcsOpIGluw6kgdsO9c3R1cHksIGt0b3LDqSBhbGUgcHJlIGNlbGtvdsO9IE5vdGVib29rIG5lbWFqw7ogdGFrbWVyIMW+aWFkZW4gdsO9em5hbSBhIHPDuiB2aG9kbsOpIHNrw7RyIHByaSBsYWRlbsOtIGvDs2Rvdi4KLSAqKndhcm5pbmcqKiBuYXN0YXZlbsO9IG5hIEZBTFNFIHBvdGzDocSNYSB6b2JyYXplbmllIGNoeWJvdsO9Y2ggaGzDocWhb2sKCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1UUlVFLGVjaG89VFJVRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVjaG8gPSBUUlVFLAogIG1lc3NhZ2UgPSBGQUxTRSwKICB3YXJuaW5nID0gRkFMU0UKKQpgYGAKCiMgw5p2b2QgayB6w6FrbGFkbsO9bSBvcGVyw6FjacOhbSB2IFIKClRlbnRvIG5vdGVib29rIGRlbW9uxaF0cnVqZSAqKnrDoWtsYWRuw6kgb3BlcsOhY2llKiogdiBqYXp5a3UgUiBzbzoKCi0gc2thbMOhcm55bWkgxI3DrXNsYW1pICh0LmouIDEgxI3DrXNsbyksCi0gdGV4dG92w71taSAoem5ha292w71taSkgcmXFpWF6Y2FtaSwKLSBsb2dpY2vDvW1pIChib29sb3Zza8O9bWkpIGhvZG5vdGFtaSBhIHByZW1lbm7DvW1pLAotIChudW1lcmlja8O9bWkpIHZla3Rvcm1pLAotIG1hdGljYW1pLgoKVGFtLCBrZGUgamUgdG8gdcW+aXRvxI1uw6ksIHPDuiB6YWhybnV0w6kgbWFsw6kgY3ZpxI1lbmlhLgoKLS0tCgojIFNrYWzDoXJlIChtb2RpZmlrb3ZhbsOpKSAoamVkbm/EjcOtc2VsbsOpIGhvZG5vdHkpCgojIyBOdW1lcmlja8OpIHNrYWzDoXJlCgpgYGB7cn0KICAjIFByaXJhZGVuaWUga29uxaF0YW50eSBkbyBwcmVtZW5uZWoKeDEgPC0gOAp4MiA8LSAzLjY1CgogICMgQXJpdGhtZXRpYyAodXByLikKc3VtX2FiICAgICAgPC0geDEgKyB4MiAgIyBzdWNldCAodXByLikKZGlmZl9hYiAgICAgPC0geDEgLSB4MiAgIyByb3pkaWVsICh1cHIuKQpwcm9kX2FiICAgICA8LSB4MSAqIHgyICAjIG7DoXNvYmVuaWUgKHVwci4pCnF1b3RfYWIgICAgIDwtIHgxIC8geDIgICMgZGVsZW5pZSAodXByLikKcG93ZXJfYWIgICAgPC0geDEgXiB4MiAgIyB1bW9jxYhvdmFuaWUgKHVwci4pCm1vZF9hYiAgICAgIDwtIHgxICUlIDQgICMgemJ5dG9rIHBvIGRlbGVuw60gdHJvbWkgKHR6diBtb2R1bG8pCgoKICAjIFJvdW5kaW5nICh1cHIuKQpyb3VuZF9iICAgPC0gcm91bmQoeDIpICAjIHphb2tydWhsb3ZhbmllIHNtZXJvbSBrIG5hamJsaXpzaWVtdSBjZWxlbXUgY2lzbHUKY2VpbF9iICAgIDwtIGNlaWxpbmcoeDIpICAjIG5hamJsaXpzaWUgdnlzc2llIGNlbGUgY2lzbG8KZmxvb3JfYiAgIDwtIGZsb29yKHgyKSAgIyBuYWpibGl6c2llIG5penNpZSBjZWxlIGNpc2xvCgp4MTsgeDIKc3VtX2FiOyBkaWZmX2FiOyBwcm9kX2FiOyBxdW90X2FiOyBwb3dlcl9hYjsgbW9kX2FiCnJvdW5kX2I7IGNlaWxfYjsgZmxvb3JfYgpgYGAKCioqUG96bsOhbWt5KioKCi0gYF5gIG9wZXLDoXRvciB1bW9jxYhvdmFuaWEuCi0gYCUlYCBqZSBtb2R1bG8sIHRlZGEgemJ5dG9rIHBvIGRlbGVuw60sIAotIGByb3VuZCh4LCBkaWdpdHMgPSAwKWAgemFva3LDumjEvm92YW5pZSBuYSB1csSNaXTDvSBwb8SNZXQgZGVzYXRpbm7DvWNoIG1pZXN0IChkaWdpdHM9KS4gYWsgZGlnaXRzID0gMCwgcG90b20gaWRlIG8gY2Vsb8SNw61zZWxuw6kgemFva3LDumjEvm92YW5pZQoKCiMjIE1hbMOpIGN2acSNZW5pZQoKPiBWeXBvxI3DrXRhanRlOgoKJCRcZnJhY3soMTVeMi00KX17N30kJAoKYGBge3J9CigxNl4zIC0gNSkgLyA4CmBgYAoKLS0tCgojIFRleHQgCgojIyBWeXR2w6FyYW5pZSB0ZXh0b3bDvW1pIHByZW1lbm7DvW1pIGEgcHLDoWNhIHMgbmltaQoKYGBge3J9CmZpcnN0IDwtICJGaWxpcCIgICMgZGVmaW5vdmFuaWUgb2JzYWh1IHRleHRvdmVqIHByZW1lbm5laiBmaXJzdApsYXN0ICA8LSAiSnVya8OhxI1layIgICMgZGVmaW5vdmFuaWUgb2JzYWh1IHRleHQgKHVwcmF2ZW7DvSkuIHByZW1lbm5laiBsYXN0CmZ1bGwgIDwtIHBhc3RlKGZpcnN0LCBsYXN0KSAgIyBzcG9qZW5pZSBkdm9jaCB0ZXh0ICh1cHJhdmVuw70pLiBwcmVtZW5ueWNoIGRvIGplZG5laiAocyBtZWR6ZXJvdSkKZnVsbF9ub3NwYWNlIDwtIHBhc3RlMChmaXJzdCwgbGFzdCkgICMgc3BvamVuaWUgYmV6IG1lZHplcnkKY3N2X2xpbmUgPC0gcGFzdGUoInBlcyIsICJtYcSNa2EiLCAia2HEjWthIiwgc2VwID0gIiwiKSAgIyBzcG9qZW5pZSB0ZXh0b3YgcyBvZGRlbG92YWNvbSAsCmZpcnN0OyBsYXN0OyBmdWxsOyBmdWxsX25vc3BhY2U7IGNzdl9saW5lICAjIGJvZGtvxI1pYXJrYSB0dSBuYWhyYWR6dWplIG9kc2tvayBuYSBub3Z5IHJpYWRvawpgYGAKCiMjIETEusW+a2EgdGV4dG92w6lobyByZcWlYXpjYSwgcG9kcmXFpWF6ZWMKCmBgYHtyfQp4IDwtICJPaCB5ZWFoISIKbmNoYXIoeCkgICMgY291bnQgem5ha292ICB2IHJldGF6Y2kgIk9oIHllYWghIgpzdWJzdHIoeCwgMiwgNikgICMgcG9kcmXFpWF6ZWMgb2QgMS4gZG8gNS4gem5ha3UKYGBgCgoKPiBUaXA6IEtuacW+bmljYSAqKnN0cmluZ3IqKiBtbm9ow6kgemF1asOtbWF2w6kgbW/Fvm5vc3RpIHByw6FjZSBzIHRleHRhbWksIGFsZSBpbXBsaWNpdG7DqSBrbmnFvm5pY2UgUiBwb2tyw712YWrDuiB2w6TEjcWhaW51IGJlxb5uw71jaCBwb3RyaWViIHDDoWNlIHMgdGV4dGFtaS4KCi0tLQoKIyBMb2dpY2vDqSAoYm9vbG92c2vDqSkgaG9kbm90eSBhIHByZW1lbm7DqQoKIyMgWsOha2xhZHkKCmBgYHtyfQphIDwtIFRSVUUKYiA8LSBGQUxTRQohYSAgIyBOT1QgKHVwci4pCmEgJiBiICAjIEFORCAodXByLikKYSB8IGIgICMgT1IgKHVwci4pCnhvcihhLCBiKSAgIyBleGNsdXNpdmUgT1IgLSBwbGF0w60gbGVuIGplZG5vIHogcCxhbGVibyBxCmBgYAoKIyMgTG9naWNrw70gdsO9c2xlZG9rIHBvcm92bsOhdmFuaWEKCmBgYHtyfQo0IDwgNgo4ID49IDgKInBlcyIgPT0gInBlcyIKInBlcyIgIT0gIm1hxI1rYSIgICMgdnlrcmljbmlrIGplIHR1IHYgem15c2xlIG5lZ2FjaWUuIE5hcHIuOiAgICE9LCAhPiwgITwsICFUUlVFCiFUUlVFCmBgYAoKIyMgWmxvxb5pdGVqxaFpZSBsb2dpY2vDqSBvcGVyw6FjaWUKCmBgYHtyfQp4IDwtIDExCnggPiA2ICYgeCA8IDIyICAjIGEgc3VjYXNuZSAtIGxvZ2lja3kgcHJpZW5payAoc3VjaW4pCnggPCAxIHwgeCA+IDEwMiAgIyBhbGVibyAtIGxvZ2lja2UgemplZG5vdGVuaWUgKHN1Y2V0KQogICMgcHJpIHpsb3ppdGVqc2ljaCB2enRhaG9jaCBwb3V6aXZhanRlIHphdHZvcmt5ICgpCmBgYAoKIyMgWmx1xI1vdmFuaWUgdmlhY2Vyw71jaCBsb2cuIHByZW1lbm7DvWNoIGRvIHZla3RvcmEKCmBgYHtyfQp2YWxzIDwtIGMoVFJVRSwgRkFMU0UsIFRSVUUsIFRSVUUpICAjIGRlZmluaWNpYSB2ZWt0b3JhIHMgbG9naWNreW1pIGhvZG5vdGFtaQpgYGAKCi0tLQoKIyBOdW1lcmlja8OpIHZla3RvcnkKCiMjIEdlbmVyb3ZhbmllIHZla3Rvcm92CgpgYGB7cn0KdjEgPC0gYygzLCA1LCA3LCA5KQp2MiA8LSAyOjYgICMgcG9zdHVwbm9zdCAxLDIsMyw0LDUKdjMgPC0gc2VxKGZyb20gPSAxLCB0byA9IDIsIGJ5ID0gMC40KSAgIyBwb3N0dXBub3N0IHMga3Jva29tIDAuMjUKdjQgPC0gcmVwKDQsIHRpbWVzID0gNikgICMgMywzLDMsMywzICAjIDUgY2xlbm5hIHBvc3R1cG5vc3QgdHJvamFrCnY1IDwtIHJ1bmlmKDYpICAjIGdlbmVyb3ZhbmllIHJvdm5vbWVybmUgcm96ZGVsZW55Y2ggcHJlbWVubnljaCB2IGludGVydmFsZSBbMCwxXQp2NiA8LSBybm9ybSg2KSAgIyBnZW5lcm92YW5pZSBub3JtYWxuZSByb3pkZWxlbnljaCBwcmVtZW5ueWNoCnYxOyB2MjsgdjM7IHY0OyB2NQpgYGAKCiMjIEFyaXRtZXRpY2vDqSBvcGVyw6FjaWUgcyB2ZWt0b3JtaQoKYGBge3J9CnYgPC0gYygyLCAzLCA0LCA1KQp2ICsgMTEgICMga2F6ZHkgcHJ2b2sgdmVrdG9yYSB6dmFjc2ltZSBvIDEwCnYgKiAzICAjIGthemR5IHBydm9rIHZla3RvcmEgcHJlbmFzb2JpbWUgMgoodiArIDIpIC8gMwpleHAodikgICMgZXhwb25lbmNpYWxuYSBmdW5rY2lhIHoga2F6ZGVobyBwcnZrdSB2ZWt0b3JhCnN1bShjKDIsMyw0KSxjKDIsMiwyKSkgICMgc2thbGFybnkgc3VjaW4gLSB2eXNsZWRvayBqZSBza2FsYXIKY3Jvc3Nwcm9kKGMoMiwzLDQpLGMoMiwyLDIpKSAgIyBza2FsYXJueSBzdWNpbiAtIHZ5c2xlZG9rIGplIG1hdGljYSAodXByYXZlbsOhKSAxeDEKYygyLDMsNCkqYygyLDIsMikgICMgSGFkYW1hcmRvdiBzdWNpbiAoc3VjaW4gem9kcG92ZWRhanVjaWNoIHBydmtvdiB2ZWt0b3JhKQpgYGAKCiMjIE1hdGVtYXRpY2vDqSBvcGVyw6FjaWUgcyAyIHZla3Rvcm1pIHJvdm5ha8OpaG8gcm96bWVydQoKYGBge3J9Cmxlbmd0aChjKDIsMyw0LDUsNikpCmxlbmd0aCh2NSkgICMgdmVrdG9yIChub3bDvSkgdjUgamUgZGVmaW5vdmFueSB2eXNzaWUKYygyLDMsNCw1LDYpICsgdjUgICMgcG96b3IsIG9iYSB2ZWt0b3J5IG11c2lhIG1hdCByb3ZuYWt5IHJvem1lcgpgYGAKCiMjIEluZGV4b3ZhbmllIGEgdsO9YmVyIG5pZWt0b3J5Y2ggcHJ2a292IHZla3RvcmEKCmBgYHtyfQp4IDwtIGMoNiwgMTMsIDQsIDE5LCA4LCAxLCAyMykKeFsyXSAgIyBpbmRleG92YW5pZSAtIG5vdnkgamVkbm8tcHJ2a292eSB2ZWt0b3IgKG5vdsO9KSAtIHBydnkgcHJ2b2sgdmVrdG9yYSB4CnhbMzo1XSAgIyBub3Z5IHZla3RvciAobm92w70pIHMgZHJ1aHltIGF6IHN0dnJ0eW0gcHJ2a29tIHZla3RvcmEgeAp4WzBdICAjIG5vdnkgdmVrdG9yIChub3bDvSkgLSB2c2V0a3kgcHJ2a3kgdmVrdG9yYSB4IG9rcmVtIHBydsOpaG8KeFt4ID4gMTFdICAjIG5vdnkgdmVrdG9yIChub3bDvSkgZGVmaW5vdmFueSBwcnZrYW1pIHggdmFjc2ltaSBha28gMTAKd2hpY2goeCA+IDExKSAgIyBrdG9yZSBwcnZreSB6b2Rwb3ZlZGFqdSBwb2RtaWVua2UgdmFjc2llaG8gYWtvIDEwPwpgYGAKCiMjIFByw6FjYSBzIGNow71iYWrDumNpbWkgaG9kbm90YW1pCgpgYGB7cn0KeSA8LSBjKDIsIE5BLCA0LCBOQSwgNikKaXMubmEoeSkKbWVhbih5KSAgIyBOQSAodXByLikKbWVhbih5LCBuYS5ybSA9IFRSVUUpICAjIHJlbW92ZSBOQXMgKHVwci4pCmBgYAoKIyMgWsOha2xhZG7DqSDFoXRhdGlzdGlreSBhIHVzcG9yaWFkYW5pZSBwcnZrb3YgdmVrdG9yYSBwb2TEvmEgdmXEvmtvc3RpCgpgYGB7cn0KeiA8LSBjKDExLCA0LCA2LCA5LCAzKQptZWFuKHopICAjIHByaWVtZXJuYSBob2Rub3RhCnNkKHopICAjIHN0YW5kYXJkbmEgb2RjaHlsa2EKbWF4KHopICAjIG1heGltYWxuYSBob2Rub3RhCnN1bW1hcnkoeikgICMgcnljaGx5IHByZWhsYWQgemFrbGFkbnljaCBzdGF0aXN0aWsgbyB2ZWt0b3JlCnNvcnQoeikgICMgcmFzdHVjZSB1c3BvcmlhZGFuaWUKc29ydCh6LCBkZWNyZWFzaW5nID0gVFJVRSkgICMga2xlc2FqdWNlICh1cHIuKQpgYGAKCiMjIE1hbMOpIGN2acSNZW5pZQo+IFZ5dHZvcnRlIHZla3RvciBgd2AgcyDEjcOtc2xhbWkgMS4uMjAgYSB2eXBvxI3DrXRhanRlIHN1bXUgdsWhZXRrw71jaCBww6FybnljaCDEjcOtc2VsLgoKYGBge3J9CncgPC0gMjoyMgpzdW0od1t3ICUlIDMgPT0gMV0pCmBgYAoKLS0tCgojIE1hdGljZSAodmFyacOhY2lhKQoKIyMgVnl0dm9yZW5pZSBtYXTDrWMKCmBgYHtyfQptIDwtIG1hdHJpeCgyOjEzLCBucm93ID0gNCwgbmNvbCA9IDUpICAjIGhvZG5vdHkgc8O6IHphZGF2YW5lIHBvIHN0bHBjb2NoCm1fYnlyb3cgPC0gbWF0cml4KDI6MTMsIG5yb3cgPSA0LCBieXJvdyA9IFRSVUUpICAjIGhvZG5vdHkgc3UgemFkYXZhbmUgcG8gcmlhZGtvY2gKbTsgbV9ieXJvdwpgYGAKCiMjIFJvem1lcnkgbWF0aWNlCgpgYGB7cn0KZGltKG0pICAjIChyb3dzLCBjb2xzKQptCmBgYAoKIyMgQWRyZXNvdmFuaWUgcHJ2a292IG1hdGljZQoKYGBge3J9Cm1bMiwgM10gICMgcmlhZG9rIDEsIHN0bHBlYyAyCm1bICwgNF0gICMgdnNldGt5IHBydmt5IHYgdHJldG9tIHN0bHBjaSAtIHZ5c2xlZG9rIG1hdGljYSAodXByYXZlbsOhKSAzeDEKbVszLCBdICAjIHZzZXRreSBwcnZreSB2IGRydWhvbSByaWFka3UgLSB2eXNsZWRvayBtYXRpY2EgKHVwcmF2ZW7DoSkgMSozCm1bMjozLCAzOjRdICAjIHBvZG1hdGljYSB0dm9yZW5hIHJpYWRrYW1pIDEsIDIgYSBzdGxwY2FtaSAyLCAzCmBgYAoKIyMgTWF0aWNvdsOpIG9wZXLDoWNpZQoKYGBge3J9CkEgPC0gbWF0cml4KGMoMiwzLDQsNSksIG5yb3cgPSAyKQpCIDwtIG1hdHJpeChjKDYsNyw4LDkpLCBucm93ID0gMikKCkEgKyBCICAgICAjIHNjaXRhbmllIG1hdGljCkEgKiBCICAgICAjIEhhZGFtYXJkIHByb2R1Y3QgLSBuYXNvYmVuaWUgcG8gem9kcG92ZWRhanVjaWNoIHBydmtvY2gKQSAlKiVCICAgIyBuYXNvYmVuaWUgbWF0aWMKdChBKSAgICAgICMgdHJhbnNwb3ppY2lhIG1hdGljZSBBIC0gdnltZW5hIHJpYWRrb3YgYSBzdGxwY292CmRldChBKSAgICAjIGRldGVybWluYW50IG1hdGljZQpzb2x2ZShBKSAgIyBpbnZlcnppYSBtYXRpY2UgKGFrIGplIG1hdGljYSAodXByYXZlbsOhKSByZWd1bGFybmEgLSB0ZWRhIGludmVyemlhIHNhIGRhIHNwb2NpdGF0KQpgYGAKCiMjIFpsdcSNb3ZhbmllIHZla3Rvcm92IGRvIG1hdMOtYyAKCmBgYHtyfQpDIDwtIGNiaW5kKDI6NCwgNTo3KSAgIyAtIHBvIHN0bHBjb2NoCkQgPC0gcmJpbmQoMjo0LCA1OjcpICAjIC0gcG8gcmlhZGtvY2gKQzsgRApgYGAKCiMjIFZ5cG/EjcOtdGFuaWUgenZvbGVuZWogxaF0YXRpc3Rpa3kgcG8gcmlhZGtvY2ggKHN0xLpwY29jaCkgbWF0aWNlCgpgYGB7cn0KTSA8LSBtYXRyaXgoMjoxMCwgbnJvdyA9IDQpCk0KYXBwbHkoTSwgMiwgc3VtKSAgIyBzdW1hIHBvIHJpYWRrb2NoCmFwcGx5KE0sIDIsIG1lYW4pICAjIHByaWVtZXJ5IHBvIHN0xLpwY29jaApgYGAKCiMjIE1hbMOpIGN2acSNZW5pZQoKPiBWeXR2b3J0ZSBtYXRpY3UgNXg1IHMgaG9kbm90YW1pIHBvIHJpYWRrb2NoIDEuLjI1LCB2eXBvxI3DrXRhanRlIHN0xLpwY292w6kgc3VteSBhIHPDusSNaW4gbWF0w61jIFwoTV50IE1cKS4KCmBgYHtyfQpNMiA8LSBtYXRyaXgoMjoyNywgbnJvdyA9IDYsIGJ5cm93ID0gVFJVRSkKY29sU3VtcyhNMikKdChNMikgJSolIE0yCmBgYAoKYGBge3J9CiMgVnl0dm9yZW5pZSBtYXRpY2UgcyDDumRham1pCnByZWRhamUgPC0gbWF0cml4KAogIGMoMTUsIDIyLCAyOCwgICAjIEthdGVnw7NyaWEgQQogICAgMTksIDE3LCAxMiwgICAjIEthdGVnw7NyaWEgQgogICAgMTAsIDE0LCAyMyksICAjIEthdGVnw7NyaWEgQwogIG5yb3cgPSAzLAogIGJ5cm93ID0gVFJVRQopCgpyb3duYW1lcyhwcmVkYWplKSA8LSBjKCJLYXRlZ8OzcmlhIEEiLCAiS2F0ZWfDs3JpYSBCIiwgIkthdGVnw7NyaWEgQyIpCmNvbG5hbWVzKHByZWRhamUpIDwtIGMoIlNrdXBpbmEgMSIsICJTa3VwaW5hIDIiLCAiU2t1cGluYSAzIikKCiMgRmFyZWJuw6EgcGFsZXRhCmZhcmJ5IDwtIGMoInN0ZWVsYmx1ZSIsICJ0b21hdG8iLCAiZ29sZGVucm9kIikKCiMgVnl0dm9yZW5pZSBncmFmdSB2ZWTEvmEgc2ViYSAoYmVzaWRlID0gVFJVRSkKYmFycGxvdCgKICBwcmVkYWplLAogIGJlc2lkZSA9IFRSVUUsCiAgY29sID0gZmFyYnksCiAgbWFpbiA9ICJQcmVkYWplIHBvZMS+YSBza3Vww61uIiwKICB4bGFiID0gIlNrdXBpbnkiLAogIHlsYWIgPSAiUG/EjWV0IHByZWRhbsO9Y2gga3Vzb3YiLAogIHlsaW0gPSBjKDAsIDM1KQopCgojIFVtaWVzdG5lbmllIGxlZ2VuZHkgdnByYXZvIG9kIGdyYWZ1CmxlZ2VuZCgKICAidG9wcmlnaHQiLAogIGxlZ2VuZCA9IHJvd25hbWVzKHByZWRhamUpLAogIGZpbGwgPSBmYXJieSwKICBidHkgPSAibiIsICAgICAgICAgIyBiZXogcsOhbcSNZWthCiAgaW5zZXQgPSBjKC0wLjA1LCAwKSwgIyBwb3N1bnV0aWUgZG9wcmF2YSBtaW1vIGdyYWYKICB4cGQgPSBUUlVFICAgICAgICAgICMgdW1vxb5uw60ga3Jlc2xpxaUgbWltbyBvYmxhc3RpIGdyYWZ1CikKYGBg