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

Numerické skaláre

# Priradenie konštanty do premennej
a <- 9
b <- 6

# 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] 6
sum_ab; diff_ab; prod_ab; quot_ab; power_ab; mod_ab;
[1] 15
[1] 3
[1] 54
[1] 1.5
[1] 531441
[1] 1
round_b; ceil_b; floor_b
[1] 6
[1] 6
[1] 6

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{(190^3-400)}{4}-10000 -\frac{(80^2-40)}{2}\]

(190^3-400)/4-10000 -(80^2-40)/2
[1] 1701470

Text

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

first <- "Diana"                       # definovanie obsahu textovej premennej first
last  <- "Ďuriančiková"                          # 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("hokej", "futbal", "volejbal", sep = ",")  # spojenie textov s oddelovacom ,
first; last; full; full_nospace; csv_line   # bodkočiarka tu nahradzuje odskok na novy riadok 
[1] "Diana"
[1] "Ďuriančiková"
[1] "Diana Ďuriančiková"
[1] "DianaĎuriančiková"
[1] "hokej,futbal,volejbal"

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

x <- "Dnes je štvrtok!"
nchar(x)                 # počet znakov  v retazci "Dnes je štvrtok!"
[1] 16
substr(x, 6, 7)          # podreťazec od 6. do 7. znaku
[1] "je"

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

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

Logický výsledok porovnávania

111 < 234
[1] TRUE
99 >= 99
[1] TRUE
"hokej" == "hokej"
[1] TRUE
"hokej" != "futbal"   # vykricnik je tu v zmysle negacie. Napr.:   !=, !>, !<, !TRUE
[1] TRUE
!TRUE
[1] FALSE

Zložitejšie logické operácie

b <- 78
b > 66 & b < 287      # a sucasne - logicky prienik (sucin)
[1] TRUE
b < 33 | b > 55     # 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, 5, 7, 9)
v2 <- 3:13                  # postupnost 1,2,3,4,5
v3 <- seq(from = 0, to = 14, by = 0.75)  # postupnost s krokom 0.25
v4 <- rep(3, times = 7)    # 3,3,3,3,3  # 5 clenna postupnost trojak
v5 <- runif(7)             # generovanie rovnomerne rozdelenych premennych v intervale [0,1]
v6 <- rnorm(7)             # generovanie normalne rozdelenych premennych
v1; v2; v3; v4; v5
[1] 3 5 7 9
 [1]  3  4  5  6  7  8  9 10 11 12 13
 [1]  0.00  0.75  1.50  2.25  3.00  3.75  4.50  5.25  6.00  6.75  7.50  8.25
[13]  9.00  9.75 10.50 11.25 12.00 12.75 13.50
[1] 3 3 3 3 3 3 3
[1] 0.609532402 0.335576513 0.009934135 0.039955158 0.870288751 0.805604380
[7] 0.458376820

Aritmetické operácie s vektormi

v <- c(6, 10, 13, 18)
v + 4           # kazdy prvok vektora zvacsime o 10
[1] 10 14 17 22
v * 7            # kazdy prvok vektora prenasobime 2
[1]  42  70  91 126
(v + 3) / 4
[1] 2.25 3.25 4.00 5.25
exp(v)           # exponencialna funkcia z kazdeho prvku vektora
[1] 4.034288e+02 2.202647e+04 4.424134e+05 6.565997e+07
sum(c(4,5,6),c(9,11,13))          # skalarny sucin - vysledok je skalar
[1] 48
crossprod(c(5,6,7),c(8,9,10))    # skalarny sucin - vysledok je matica 1x1
     [,1]
[1,]  164
c(3,5,7)*c(2,4,6)               # Hadamardov sucin (sucin zodpovedajucich prvkov vektora)
[1]  6 20 42

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

length(c(1,5,7,9,11))
[1] 5
length(v5)            #vektor v5 je definovany vyssie
[1] 7
c(1,2,3,4,5) + v5     # pozor, oba vektory musia mat rovnaky rozmer
[1] 1.609532 2.335577 3.009934 4.039955 5.870289 1.805604 2.458377

Indexovanie a výber niektorych prvkov vektora

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

Práca s chýbajúcimi hodnotami

y <- c(14, NA, 23, NA, 35)
is.na(y)
[1] FALSE  TRUE FALSE  TRUE FALSE
mean(y)                 # NA
[1] NA
mean(y, na.rm = TRUE)   # remove NAs
[1] 24

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

z <- c(8, 13, 65, 18, 22)
mean(z)                 # priemerna hodnota
[1] 25.2
sd(z)                  # standardna odchylka
[1] 22.86263
max(z)                  # maximalna hodnota
[1] 65
summary(z)              # rychly prehlad zakladnych statistik o vektore
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
    8.0    13.0    18.0    25.2    22.0    65.0 
sort(z)                 # rastuce usporiadanie 
[1]  8 13 18 22 65
sort(z, decreasing = TRUE)  # klesajuce
[1] 65 22 18 13  8

Malé cvičenie

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

w <- 1:45
sum(w[w %% 2 == 0])
[1] 506

Matice

Vytvorenie matíc

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

Rozmery matice

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

Adresovanie prvkov matice

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

Maticové operácie

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

A + B        # scitanie matic
     [,1] [,2]
[1,]    6   10
[2,]    8   12
A * B        # Hadamard product - nasobenie po zodpovedajucich prvkoch
     [,1] [,2]
[1,]    5   21
[2,]   12   32
A %*% B      # nasobenie matic
     [,1] [,2]
[1,]   23   31
[2,]   34   46
t(A)         # transpozicia matice A - vymena riadkov a stlpcov
     [,1] [,2]
[1,]    1    2
[2,]    3    4
det(A)       # determinant matice
[1] -2
solve(A)     # inverzia matice (ak je matica regularna - teda inverzia sa da spocitat)
     [,1] [,2]
[1,]   -2  1.5
[2,]    1 -0.5

Zlučovanie vektorov do matíc

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

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

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

Malé cvičenie

Vytvorte maticu 5x5 s hodnotami po riadkoch 1..20, vypočítajte stĺpcové sumy a súčin matíc \(M^t M\).

M2 <- matrix(1:20, nrow = 5, byrow = TRUE)
colSums(M2)
[1] 45 50 55 60
t(M2) %*% M2
     [,1] [,2] [,3] [,4]
[1,]  565  610  655  700
[2,]  610  660  710  760
[3,]  655  710  765  820
[4,]  700  760  820  880
## Malé cvičenie - Môj návrh
# Vektor dní
dni <- c("Pondelok", "Utorok", "Streda", "Štvrtok", "Piatok")

# Počet zákazníkov v jednotlivých časoch dňa
dopoludnie <- c(30, 45, 35, 40, 50)
popoludnie <- c(55, 60, 58, 65, 70)
vecer <- c(40, 38, 45, 50, 55)

# Vytvorenie matice
navstevnost <- cbind(dopoludnie, popoludnie, vecer)
rownames(navstevnost) <- dni
colnames(navstevnost) <- c("Dopoludnie", "Popoludnie", "Večer")

# Farebný stĺpcový graf
bar_colors <- ifelse(popoludnie > 60, "darkorange", "lightblue")

barplot(
  t(navstevnost),    # transponujeme, aby stĺpce = dni
  beside = TRUE,     # stĺpce vedľa seba
  col = c("gold", "orange", "brown"),  # farby pre časy dňa
  names.arg = dni,
  legend.text = colnames(navstevnost),
  args.legend = list(x = "topright"),
  main = "Návštevnosť kaviarne počas týždňa",
  ylab = "Počet zákazníkov"
)

LS0tCnRpdGxlOiAiWsOha2xhZG7DqSBvcGVyw6FjaWUgdiBSIgphdXRob3I6ICJEaWFuYSDEjnVyaWFuxI1pa292w6EKKHMgdnl1xb5pdMOtbSBDaGF0R1B0KSIKZGF0ZTogIk9rdMOzYmVyIDIwMjUiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0aGVtZTogdW5pdGVkCiAgICBoaWdobGlnaHQ6IHRhbmdvCmVkaXRvcl9vcHRpb25zOiAKICBtYXJrZG93bjogCiAgICB3cmFwOiA3MgotLS0KPHN0eWxlPgovKiB0b3RvIGplIMSNaXN0w70gSFRNTC9DU1MsIG5pZSBSLWNodW5rICovCmJvZHksIC5tYWluLWNvbnRhaW5lciB7CiAgYmFja2dyb3VuZC1jb2xvcjogI0ZGRTRFMSAhaW1wb3J0YW50OwogIGNvbG9yOiAjMjIyOwp9Cjwvc3R5bGU+CgojIEdsb2LDoWxuZSBuYXN0YXZlbmllIENodW5rb3YKClYgbmnFvsWhaWUgdXZlZGVub20gQ2h1bmt1IGplIHVyb2JlbsOpIHrDoWtsYWRuw6kgZ2xvYsOhbG5lIG5hc3RhdmVuaWUgQ2h1bmtvdiB2IGNlbG9tIE5vdGVib29rdS4gCgotICoqZWNobyoqIG5hc3RhdnVqZSwgxI1pIGNoY2VtZSB2IE5vdGVib29rdSB2eXBpc292YcWlIGplZG5vdGxpdsOpIGvDs2R5IFIKLSAqKm1lc3NhZ2UqKiBqZSBuYXN0YXZlbsO9IG5hICpGQUxTRSosIMSNbyB6bmFtZW7DoSwgxb5lIHNhIGJ1ZMO6IHBvdGzDocSNYcWlIHByYWNvdm7DqSB2w71zdHVweSB6IFIsIHQuai4gbmFwcsOta2xhZCB2w71zbGVkb2sgb3R2w6FyYW5pYSBrbmnFvm7DrWMsIGEgbmlla3RvcsOpIGluw6kgdsO9c3R1cHksIGt0b3LDqSBhbGUgcHJlIGNlbGtvdsO9IE5vdGVib29rIG5lbWFqw7ogdGFrbWVyIMW+aWFkZW4gdsO9em5hbSBhIHPDuiB2aG9kbsOpIHNrw7RyIHByaSBsYWRlbsOtIGvDs2Rvdi4KLSAqKndhcm5pbmcqKiBuYXN0YXZlbsO9IG5hIEZBTFNFIHBvdGzDocSNYSB6b2JyYXplbmllIGNoeWJvdsO9Y2ggaGzDocWhb2sKCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1UUlVFLGVjaG89VFJVRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVjaG8gPSBUUlVFLAogIG1lc3NhZ2UgPSBGQUxTRSwKICB3YXJuaW5nID0gRkFMU0UKKQpgYGAKCiMgw5p2b2QgayB6w6FrbGFkbsO9bSBvcGVyw6FjacOhbSB2IFIKClRlbnRvIG5vdGVib29rIGRlbW9uxaF0cnVqZSAqKnrDoWtsYWRuw6kgb3BlcsOhY2llKiogdiBqYXp5a3UgUiBzbzoKCi0gc2thbMOhcm55bWkgxI3DrXNsYW1pICh0LmouIDEgxI3DrXNsbyksCi0gdGV4dG92w71taSAoem5ha292w71taSkgcmXFpWF6Y2FtaSwKLSBsb2dpY2vDvW1pIChib29sb3Zza8O9bWkpIGhvZG5vdGFtaSBhIHByZW1lbm7DvW1pLAotIChudW1lcmlja8O9bWkpIHZla3Rvcm1pLAotIG1hdGljYW1pLgoKVGFtLCBrZGUgamUgdG8gdcW+aXRvxI1uw6ksIHPDuiB6YWhybnV0w6kgbWFsw6kgY3ZpxI1lbmlhLgoKLS0tCgojIFNrYWzDoXJlIChqZWRub8SNw61zZWxuw6kgaG9kbm90eSkKCiMjIE51bWVyaWNrw6kgc2thbMOhcmUKCmBgYHtyfQojIFByaXJhZGVuaWUga29uxaF0YW50eSBkbyBwcmVtZW5uZWoKYSA8LSA5CmIgPC0gNgoKIyBBcml0aG1ldGljCnN1bV9hYiAgICAgIDwtIGEgKyBiICAgICAgICAjIHN1Y2V0CmRpZmZfYWIgICAgIDwtIGEgLSBiICAgICAgICAjIHJvemRpZWwKcHJvZF9hYiAgICAgPC0gYSAqIGIgICAgICAgICMgbsOhc29iZW5pZQpxdW90X2FiICAgICA8LSBhIC8gYiAgICAgICAgIyBkZWxlbmllCnBvd2VyX2FiICAgIDwtIGEgXiBiICAgICAgICAjIHVtb2PFiG92YW5pZQptb2RfYWIgICAgICA8LSBhICUlIDQgICAgICAgIyB6Ynl0b2sgcG8gZGVsZW7DrSB0cm9taSAodHp2IG1vZHVsbykKCiMgUm91bmRpbmcKcm91bmRfYiAgIDwtIHJvdW5kKGIpICAgICAgICMgemFva3J1aGxvdmFuaWUgc21lcm9tIGsgbmFqYmxpenNpZW11IGNlbGVtdSBjaXNsdQpjZWlsX2IgICAgPC0gY2VpbGluZyhiKSAgICAgIyBuYWpibGl6c2llIHZ5c3NpZSBjZWxlIGNpc2xvCmZsb29yX2IgICA8LSBmbG9vcihiKSAgICAgICAjIG5hamJsaXpzaWUgbml6c2llIGNlbGUgY2lzbG8KCmE7IGIKc3VtX2FiOyBkaWZmX2FiOyBwcm9kX2FiOyBxdW90X2FiOyBwb3dlcl9hYjsgbW9kX2FiOwpyb3VuZF9iOyBjZWlsX2I7IGZsb29yX2IKCmBgYAoKKipQb3puw6Fta3kqKgoKLSBgXmAgb3BlcsOhdG9yIHVtb2PFiG92YW5pYS4KLSBgJSVgIGplIG1vZHVsbywgdGVkYSB6Ynl0b2sgcG8gZGVsZW7DrSwgCi0gYHJvdW5kKHgsIGRpZ2l0cyA9IDApYCB6YW9rcsO6aMS+b3ZhbmllIG5hIHVyxI1pdMO9IHBvxI1ldCBkZXNhdGlubsO9Y2ggbWllc3QgKGRpZ2l0cz0pLiBhayBkaWdpdHMgPSAwLCBwb3RvbSBpZGUgbyBjZWxvxI3DrXNlbG7DqSB6YW9rcsO6aMS+b3ZhbmllCgoKIyMgTWFsw6kgY3ZpxI1lbmllCgo+IFZ5cG/EjcOtdGFqdGU6CgokJFxmcmFjeygxOTBeMy00MDApfXs0fS0xMDAwMCAtXGZyYWN7KDgwXjItNDApfXsyfSQkIAoKYGBge3J9CigxOTBeMy00MDApLzQtMTAwMDAgLSg4MF4yLTQwKS8yCmBgYAoKLS0tCgojIFRleHQgCgojIyBWeXR2w6FyYW5pZSB0ZXh0b3bDvW1pIHByZW1lbm7DvW1pIGEgcHLDoWNhIHMgbmltaQoKYGBge3J9CmZpcnN0IDwtICJEaWFuYSIgICAgICAgICAgICAgICAgICAgICAgICMgZGVmaW5vdmFuaWUgb2JzYWh1IHRleHRvdmVqIHByZW1lbm5laiBmaXJzdApsYXN0ICA8LSAixI51cmlhbsSNaWtvdsOhIiAgICAgICAgICAgICAgICAgICAgICAgICAgIyBkZWZpbm92YW5pZSBvYnNhaHUgdGV4dC4gcHJlbWVubmVqIGxhc3QKZnVsbCAgPC0gcGFzdGUoZmlyc3QsIGxhc3QpICAgICAgICAgICAgICAgIyBzcG9qZW5pZSBkdm9jaCB0ZXh0LiBwcmVtZW5ueWNoIGRvIGplZG5laiAocyBtZWR6ZXJvdSkKZnVsbF9ub3NwYWNlIDwtIHBhc3RlMChmaXJzdCwgbGFzdCkgICAgICAgIyBzcG9qZW5pZSBiZXogbWVkemVyeQpjc3ZfbGluZSA8LSBwYXN0ZSgiaG9rZWoiLCAiZnV0YmFsIiwgInZvbGVqYmFsIiwgc2VwID0gIiwiKSAgIyBzcG9qZW5pZSB0ZXh0b3YgcyBvZGRlbG92YWNvbSAsCmZpcnN0OyBsYXN0OyBmdWxsOyBmdWxsX25vc3BhY2U7IGNzdl9saW5lICAgIyBib2Rrb8SNaWFya2EgdHUgbmFocmFkenVqZSBvZHNrb2sgbmEgbm92eSByaWFkb2sgCmBgYAoKIyMgRMS6xb5rYSB0ZXh0b3bDqWhvIHJlxaVhemNhLCBwb2RyZcWlYXplYwoKYGBge3J9CnggPC0gIkRuZXMgamUgxaF0dnJ0b2shIgpuY2hhcih4KSAgICAgICAgICAgICAgICAgIyBwb8SNZXQgem5ha292ICB2IHJldGF6Y2kgIkRuZXMgamUgxaF0dnJ0b2shIgpzdWJzdHIoeCwgNiwgNykgICAgICAgICAgIyBwb2RyZcWlYXplYyBvZCA2LiBkbyA3LiB6bmFrdQpgYGAKCgo+IFRpcDogS25pxb5uaWNhICoqc3RyaW5ncioqIG1ub2jDqSB6YXVqw61tYXbDqSBtb8W+bm9zdGkgcHLDoWNlIHMgdGV4dGFtaSwgYWxlIGltcGxpY2l0bsOpIGtuacW+bmljZSBSIHBva3LDvXZhasO6IHbDpMSNxaFpbnUgYmXFvm7DvWNoIHBvdHJpZWIgcMOhY2UgcyB0ZXh0YW1pLgoKLS0tCgojIExvZ2lja8OpIChib29sb3Zza8OpKSBob2Rub3R5IGEgcHJlbWVubsOpCgojIyBaw6FrbGFkeQoKYGBge3J9CmMgPC0gVFJVRQpkIDwtIEZBTFNFCiFjICAgICAgICAgICAgICAgICAjIE5PVApjICYgZCAgICAgICAgICAgICAgIyBBTkQKYyB8IGQgICAgICAgICAgICAgICMgT1IKeG9yKGMsIGQpICAgICAgICAgICMgZXhjbHVzaXZlIE9SIC0gcGxhdMOtIGxlbiBqZWRubyB6IGMsYWxlYm8gZApgYGAKCiMjIExvZ2lja8O9IHbDvXNsZWRvayBwb3Jvdm7DoXZhbmlhCgpgYGB7cn0KMTExIDwgMjM0Cjk5ID49IDk5CiJob2tlaiIgPT0gImhva2VqIgoiaG9rZWoiICE9ICJmdXRiYWwiICAgIyB2eWtyaWNuaWsgamUgdHUgdiB6bXlzbGUgbmVnYWNpZS4gTmFwci46ICAgIT0sICE+LCAhPCwgIVRSVUUKIVRSVUUKYGBgCgojIyBabG/Fvml0ZWrFoWllIGxvZ2lja8OpIG9wZXLDoWNpZQoKYGBge3J9CmIgPC0gNzgKYiA+IDY2ICYgYiA8IDI4NyAgICAgICMgYSBzdWNhc25lIC0gbG9naWNreSBwcmllbmlrIChzdWNpbikKYiA8IDMzIHwgYiA+IDU1ICAgICAjIGFsZWJvIC0gbG9naWNrZSB6amVkbm90ZW5pZSAoc3VjZXQpCiAgICAgICAgICAgICAgICAgICAgIyBwcmkgemxveml0ZWpzaWNoIHZ6dGFob2NoIHBvdXppdmFqdGUgemF0dm9ya3kgKCkKYGBgCgojIyBabHXEjW92YW5pZSB2aWFjZXLDvWNoIGxvZy4gcHJlbWVubsO9Y2ggZG8gdmVrdG9yYQoKYGBge3J9CnZhbHMgPC0gYyhUUlVFLCBGQUxTRSwgVFJVRSwgVFJVRSkgICAjIGRlZmluaWNpYSB2ZWt0b3JhIHMgbG9naWNreW1pIGhvZG5vdGFtaQpgYGAKCi0tLQoKIyBOdW1lcmlja8OpIHZla3RvcnkKCiMjIEdlbmVyb3ZhbmllIHZla3Rvcm92CgpgYGB7cn0KdjEgPC0gYygzLCA1LCA3LCA5KQp2MiA8LSAzOjEzICAgICAgICAgICAgICAgICAgIyBwb3N0dXBub3N0IDEsMiwzLDQsNQp2MyA8LSBzZXEoZnJvbSA9IDAsIHRvID0gMTQsIGJ5ID0gMC43NSkgICMgcG9zdHVwbm9zdCBzIGtyb2tvbSAwLjI1CnY0IDwtIHJlcCgzLCB0aW1lcyA9IDcpICAgICMgMywzLDMsMywzICAjIDUgY2xlbm5hIHBvc3R1cG5vc3QgdHJvamFrCnY1IDwtIHJ1bmlmKDcpICAgICAgICAgICAgICMgZ2VuZXJvdmFuaWUgcm92bm9tZXJuZSByb3pkZWxlbnljaCBwcmVtZW5ueWNoIHYgaW50ZXJ2YWxlIFswLDFdCnY2IDwtIHJub3JtKDcpICAgICAgICAgICAgICMgZ2VuZXJvdmFuaWUgbm9ybWFsbmUgcm96ZGVsZW55Y2ggcHJlbWVubnljaAp2MTsgdjI7IHYzOyB2NDsgdjUKYGBgCgojIyBBcml0bWV0aWNrw6kgb3BlcsOhY2llIHMgdmVrdG9ybWkKCmBgYHtyfQp2IDwtIGMoNiwgMTAsIDEzLCAxOCkKdiArIDQgICAgICAgICAgICMga2F6ZHkgcHJ2b2sgdmVrdG9yYSB6dmFjc2ltZSBvIDEwCnYgKiA3ICAgICAgICAgICAgIyBrYXpkeSBwcnZvayB2ZWt0b3JhIHByZW5hc29iaW1lIDIKKHYgKyAzKSAvIDQKZXhwKHYpICAgICAgICAgICAjIGV4cG9uZW5jaWFsbmEgZnVua2NpYSB6IGthemRlaG8gcHJ2a3UgdmVrdG9yYQpzdW0oYyg0LDUsNiksYyg5LDExLDEzKSkgICAgICAgICAgIyBza2FsYXJueSBzdWNpbiAtIHZ5c2xlZG9rIGplIHNrYWxhcgpjcm9zc3Byb2QoYyg1LDYsNyksYyg4LDksMTApKSAgICAjIHNrYWxhcm55IHN1Y2luIC0gdnlzbGVkb2sgamUgbWF0aWNhIDF4MQpjKDMsNSw3KSpjKDIsNCw2KSAgICAgICAgICAgICAgICMgSGFkYW1hcmRvdiBzdWNpbiAoc3VjaW4gem9kcG92ZWRhanVjaWNoIHBydmtvdiB2ZWt0b3JhKQpgYGAKCiMjIE1hdGVtYXRpY2vDqSBvcGVyw6FjaWUgcyAyIHZla3Rvcm1pIHJvdm5ha8OpaG8gcm96bWVydQoKYGBge3J9Cmxlbmd0aChjKDEsNSw3LDksMTEpKQpsZW5ndGgodjUpICAgICAgICAgICAgI3Zla3RvciB2NSBqZSBkZWZpbm92YW55IHZ5c3NpZQpjKDEsMiwzLDQsNSkgKyB2NSAgICAgIyBwb3pvciwgb2JhIHZla3RvcnkgbXVzaWEgbWF0IHJvdm5ha3kgcm96bWVyCmBgYAoKIyMgSW5kZXhvdmFuaWUgYSB2w71iZXIgbmlla3RvcnljaCBwcnZrb3YgdmVrdG9yYQoKYGBge3J9CnggPC0gYyg4LCA2NiwgNDUsIDMsIDE3LCA5MCwgMjYpCnhbMV0gICAgICAgICAgICMgaW5kZXhvdmFuaWUgLSBub3Z5IGplZG5vLXBydmtvdnkgdmVrdG9yIC0gcHJ2eSBwcnZvayB2ZWt0b3JhIHgKeFsyOjRdICAgICAgICAgIyBub3Z5IHZla3RvciBzIGRydWh5bSBheiBzdHZydHltIHBydmtvbSB2ZWt0b3JhIHgKeFstMV0gICAgICAgICAgIyBub3Z5IHZla3RvciAtIHZzZXRreSBwcnZreSB2ZWt0b3JhIHggb2tyZW0gcHJ2w6lobwp4W3ggPiAxMF0gICAgICAjIG5vdnkgdmVrdG9yIGRlZmlub3ZhbnkgcHJ2a2FtaSB4IHZhY3NpbWkgYWtvIDEwCndoaWNoKHggPiAxMCkgICMga3RvcmUgcHJ2a3kgem9kcG92ZWRhanUgcG9kbWllbmtlIHZhY3NpZWhvIGFrbyAxMD8KYGBgCgojIyBQcsOhY2EgcyBjaMO9YmFqw7pjaW1pIGhvZG5vdGFtaQoKYGBge3J9CnkgPC0gYygxNCwgTkEsIDIzLCBOQSwgMzUpCmlzLm5hKHkpCm1lYW4oeSkgICAgICAgICAgICAgICAgICMgTkEKbWVhbih5LCBuYS5ybSA9IFRSVUUpICAgIyByZW1vdmUgTkFzCmBgYAoKIyMgWsOha2xhZG7DqSDFoXRhdGlzdGlreSBhIHVzcG9yaWFkYW5pZSBwcnZrb3YgdmVrdG9yYSBwb2TEvmEgdmXEvmtvc3RpCgpgYGB7cn0KeiA8LSBjKDgsIDEzLCA2NSwgMTgsIDIyKQptZWFuKHopICAgICAgICAgICAgICAgICAjIHByaWVtZXJuYSBob2Rub3RhCnNkKHopICAgICAgICAgICAgICAgICAgIyBzdGFuZGFyZG5hIG9kY2h5bGthCm1heCh6KSAgICAgICAgICAgICAgICAgICMgbWF4aW1hbG5hIGhvZG5vdGEKc3VtbWFyeSh6KSAgICAgICAgICAgICAgIyByeWNobHkgcHJlaGxhZCB6YWtsYWRueWNoIHN0YXRpc3RpayBvIHZla3RvcmUKc29ydCh6KSAgICAgICAgICAgICAgICAgIyByYXN0dWNlIHVzcG9yaWFkYW5pZSAKc29ydCh6LCBkZWNyZWFzaW5nID0gVFJVRSkgICMga2xlc2FqdWNlCmBgYAoKIyMgTWFsw6kgY3ZpxI1lbmllCj4gVnl0dm9ydGUgdmVrdG9yIGB3YCBzIMSNw61zbGFtaSAxLi40NSBhIHZ5cG/EjcOtdGFqdGUgc3VtdSB2xaFldGvDvWNoIHDDoXJueWNoIMSNw61zZWwuCgpgYGB7cn0KdyA8LSAxOjQ1CnN1bSh3W3cgJSUgMiA9PSAwXSkKYGBgCgotLS0KCiMgTWF0aWNlCgojIyBWeXR2b3JlbmllIG1hdMOtYwoKYGBge3J9Cm0gPC0gbWF0cml4KDE6MTIsIG5yb3cgPSA0LCBuY29sID0gNSkgICAgICAgICAgICAjIGhvZG5vdHkgc8O6IHphZGF2YW5lIHBvIHN0bHBjb2NoCm1fYnlyb3cgPC0gbWF0cml4KDE6MTIsIG5yb3cgPSA0LCBieXJvdyA9IFRSVUUpICAjIGhvZG5vdHkgc3UgemFkYXZhbmUgcG8gcmlhZGtvY2gKbTsgbV9ieXJvdwpgYGAKCiMjIFJvem1lcnkgbWF0aWNlCgpgYGB7cn0KZGltKG0pICAgICAgICAgICAgICAgICAgICMgKHJvd3MsIGNvbHMpCm0KYGBgCgojIyBBZHJlc292YW5pZSBwcnZrb3YgbWF0aWNlCgpgYGB7cn0KbVsxLCAyXSAgICAgICMgcmlhZG9rIDEsIHN0bHBlYyAyCm1bICwgM10gICAgICAjIHZzZXRreSBwcnZreSB2IHRyZXRvbSBzdGxwY2kgLSB2eXNsZWRvayBtYXRpY2EgM3gxCm1bMiwgXSAgICAgICAjIHZzZXRreSBwcnZreSB2IGRydWhvbSByaWFka3UgLSB2eXNsZWRvayBtYXRpY2EgMSozCm1bMToyLCAyOjNdICAjIHBvZG1hdGljYSB0dm9yZW5hIHJpYWRrYW1pIDEsIDIgYSBzdGxwY2FtaSAyLCAzCmBgYAoKIyMgTWF0aWNvdsOpIG9wZXLDoWNpZQoKYGBge3J9CkEgPC0gbWF0cml4KGMoMSwyLDMsNCksIG5yb3cgPSAyKQpCIDwtIG1hdHJpeChjKDUsNiw3LDgpLCBucm93ID0gMikKCkEgKyBCICAgICAgICAjIHNjaXRhbmllIG1hdGljCkEgKiBCICAgICAgICAjIEhhZGFtYXJkIHByb2R1Y3QgLSBuYXNvYmVuaWUgcG8gem9kcG92ZWRhanVjaWNoIHBydmtvY2gKQSAlKiUgQiAgICAgICMgbmFzb2JlbmllIG1hdGljCnQoQSkgICAgICAgICAjIHRyYW5zcG96aWNpYSBtYXRpY2UgQSAtIHZ5bWVuYSByaWFka292IGEgc3RscGNvdgpkZXQoQSkgICAgICAgIyBkZXRlcm1pbmFudCBtYXRpY2UKc29sdmUoQSkgICAgICMgaW52ZXJ6aWEgbWF0aWNlIChhayBqZSBtYXRpY2EgcmVndWxhcm5hIC0gdGVkYSBpbnZlcnppYSBzYSBkYSBzcG9jaXRhdCkKYGBgCgojIyBabHXEjW92YW5pZSB2ZWt0b3JvdiBkbyBtYXTDrWMgCgpgYGB7cn0KQyA8LSBjYmluZCgxOjMsIDQ6NikgICAjICAtIHBvIHN0bHBjb2NoIApEIDwtIHJiaW5kKDE6MywgNDo2KSAgICMgIC0gcG8gcmlhZGtvY2ggCkM7IEQKYGBgCgojIyBWeXBvxI3DrXRhbmllIHp2b2xlbmVqIMWhdGF0aXN0aWt5IHBvIHJpYWRrb2NoIChzdMS6cGNvY2gpIG1hdGljZQoKYGBge3J9Ck0gPC0gbWF0cml4KDE6OSwgbnJvdyA9IDMpCk0KYXBwbHkoTSwgMSwgc3VtKSAgICMgc3VtYSBwbyByaWFka29jaAphcHBseShNLCAyLCBtZWFuKSAgIyBwcmllbWVyeSBwbyBzdMS6cGNvY2gKYGBgCgojIyBNYWzDqSBjdmnEjWVuaWUKCj4gVnl0dm9ydGUgbWF0aWN1IDV4NSBzIGhvZG5vdGFtaSBwbyByaWFka29jaCAxLi4yMCwgdnlwb8SNw610YWp0ZSBzdMS6cGNvdsOpIHN1bXkgYSBzw7rEjWluIG1hdMOtYyBcKE1edCBNXCkuCgpgYGB7cn0KTTIgPC0gbWF0cml4KDE6MjAsIG5yb3cgPSA1LCBieXJvdyA9IFRSVUUpCmNvbFN1bXMoTTIpCnQoTTIpICUqJSBNMgpgYGAKCmBgYHtyfQojIyBNYWzDqSBjdmnEjWVuaWUgLSBNw7RqIG7DoXZyaAojIFZla3RvciBkbsOtCmRuaSA8LSBjKCJQb25kZWxvayIsICJVdG9yb2siLCAiU3RyZWRhIiwgIsWgdHZydG9rIiwgIlBpYXRvayIpCgojIFBvxI1ldCB6w6FrYXpuw61rb3YgdiBqZWRub3RsaXbDvWNoIMSNYXNvY2ggZMWIYQpkb3BvbHVkbmllIDwtIGMoMzAsIDQ1LCAzNSwgNDAsIDUwKQpwb3BvbHVkbmllIDwtIGMoNTUsIDYwLCA1OCwgNjUsIDcwKQp2ZWNlciA8LSBjKDQwLCAzOCwgNDUsIDUwLCA1NSkKCiMgVnl0dm9yZW5pZSBtYXRpY2UKbmF2c3Rldm5vc3QgPC0gY2JpbmQoZG9wb2x1ZG5pZSwgcG9wb2x1ZG5pZSwgdmVjZXIpCnJvd25hbWVzKG5hdnN0ZXZub3N0KSA8LSBkbmkKY29sbmFtZXMobmF2c3Rldm5vc3QpIDwtIGMoIkRvcG9sdWRuaWUiLCAiUG9wb2x1ZG5pZSIsICJWZcSNZXIiKQoKIyBGYXJlYm7DvSBzdMS6cGNvdsO9IGdyYWYKYmFyX2NvbG9ycyA8LSBpZmVsc2UocG9wb2x1ZG5pZSA+IDYwLCAiZGFya29yYW5nZSIsICJsaWdodGJsdWUiKQoKYmFycGxvdCgKICB0KG5hdnN0ZXZub3N0KSwgICAgIyB0cmFuc3BvbnVqZW1lLCBhYnkgc3TEunBjZSA9IGRuaQogIGJlc2lkZSA9IFRSVUUsICAgICAjIHN0xLpwY2UgdmVkxL5hIHNlYmEKICBjb2wgPSBjKCJnb2xkIiwgIm9yYW5nZSIsICJicm93biIpLCAgIyBmYXJieSBwcmUgxI1hc3kgZMWIYQogIG5hbWVzLmFyZyA9IGRuaSwKICBsZWdlbmQudGV4dCA9IGNvbG5hbWVzKG5hdnN0ZXZub3N0KSwKICBhcmdzLmxlZ2VuZCA9IGxpc3QoeCA9ICJ0b3ByaWdodCIpLAogIG1haW4gPSAiTsOhdsWhdGV2bm9zxaUga2F2aWFybmUgcG/EjWFzIHTDvcW+ZMWIYSIsCiAgeWxhYiA9ICJQb8SNZXQgesOha2F6bsOta292IgopCmBgYAoKCgoK