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 <- 7
b <- 3.5

# 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 %% 3       # 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] 7
[1] 3.5
sum_ab; diff_ab; prod_ab; quot_ab; power_ab; mod_ab
[1] 10.5
[1] 3.5
[1] 24.5
[1] 2
[1] 907.4927
[1] 1
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}\]

(15^2 - 4) / 7
[1] 31.57143
sin(pi)
[1] 1.224647e-16
286000-4^6
[1] 281904
(945+745+3^9)/5
[1] 4274.6
(cos(pi)*8^9) / 3
[1] -44739243

Text

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

first <- "Vladimir"                       # definovanie obsahu textovej premennej first
last  <- "Gazda"                          # 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("apple", "banana", "pear", sep = ",")  # spojenie textov s oddelovacom ,
first; last; full; full_nospace; csv_line   # bodkočiarka tu nahradzuje odskok na novy riadok 
[1] "Vladimir"
[1] "Gazda"
[1] "Vladimir Gazda"
[1] "VladimirGazda"
[1] "apple,banana,pear"

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

x <- "R is great!"
nchar(x)                 # počet znakov  v retazci "R is great!"
[1] 11
substr(x, 1, 5)          # podreťazec od 1. do 5. znaku
[1] "R is "

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

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

Logický výsledok porovnávania

3 < 5
[1] TRUE
7 >= 7
[1] TRUE
"cat" == "cat"
[1] TRUE
"cat" != "dog"   # vykricnik je tu v zmysle negacie. Napr.:   !=, !>, !<, !TRUE
[1] TRUE
!TRUE
[1] FALSE

Zložitejšie logické operácie

x <- 10
x > 5 & x < 20      # a sucasne - logicky prienik (sucin)
[1] TRUE
x < 0 | x > 100     # 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(2, 4, 6, 8)
v2 <- 1:5                  # postupnost 1,2,3,4,5
v3 <- seq(from = 0, to = 1, by = 0.25)  # postupnost s krokom 0.25
v4 <- rep(3, times = 5)    # 3,3,3,3,3  # 5 clenna postupnost trojak
v5 <- runif(5)             # generovanie rovnomerne rozdelenych premennych v intervale [0,1]
v6 <- rnorm(5)             # generovanie normalne rozdelenych premennych
v1; v2; v3; v4; v5
[1] 2 4 6 8
[1] 1 2 3 4 5
[1] 0.00 0.25 0.50 0.75 1.00
[1] 3 3 3 3 3
[1] 0.1134581 0.0859713 0.4920198 0.8588934 0.7232508

Aritmetické operácie s vektormi

v <- c(1, 2, 3, 4)
v + 10           # kazdy prvok vektora zvacsime o 10
[1] 11 12 13 14
v * 2            # kazdy prvok vektora prenasobime 2
[1] 2 4 6 8
(v + 1) / 2
[1] 1.0 1.5 2.0 2.5
exp(v)           # exponencialna funkcia z kazdeho prvku vektora
[1]  2.718282  7.389056 20.085537 54.598150
sum(c(1,2,3),c(1,1,1))          # skalarny sucin - vysledok je skalar
[1] 9
crossprod(c(1,2,3),c(1,1,1))    # skalarny sucin - vysledok je matica 1x1
     [,1]
[1,]    6
c(1,2,3)*c(1,1,1)               # Hadamardov sucin (sucin zodpovedajucich prvkov vektora)
[1] 1 2 3

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

length(c(1,2,3,4,5))
[1] 5
length(v5)            #vektor v5 je definovany vyssie
[1] 5
c(1,2,3,4,5) + v5     # pozor, oba vektory musia mat rovnaky rozmer
[1] 1.113458 2.085971 3.492020 4.858893 5.723251

Indexovanie a výber niektorych prvkov vektora

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

z <- c(10, 3, 5, 8, 2)
mean(z)                 # priemerna hodnota
[1] 5.6
sd(z)                  # standardna odchylka
[1] 3.361547
max(z)                  # maximalna hodnota
[1] 10
summary(z)              # rychly prehlad zakladnych statistik o vektore
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
    2.0     3.0     5.0     5.6     8.0    10.0 
sort(z)                 # rastuce usporiadanie 
[1]  2  3  5  8 10
sort(z, decreasing = TRUE)  # klesajuce
[1] 10  8  5  3  2

Malé cvičenie

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

w <- 1:20
sum(w[w %% 2 == 0])
[1] 110
k <- 30:60
sum(k[k %% 2 == 1])
[1] 675
w <- 1:20
sum(w[w %% 2 == 0])/pi
[1] 35.01409
sum(w[w %% 2 == 1])/pi
[1] 31.83099
sum(w[w %% 2 == 0])/k
 [1] 3.666667 3.548387 3.437500 3.333333 3.235294 3.142857 3.055556 2.972973 2.894737
[10] 2.820513 2.750000 2.682927 2.619048 2.558140 2.500000 2.444444 2.391304 2.340426
[19] 2.291667 2.244898 2.200000 2.156863 2.115385 2.075472 2.037037 2.000000 1.964286
[28] 1.929825 1.896552 1.864407 1.833333
sum(w[w %% 2 == 0])*k
 [1] 3300 3410 3520 3630 3740 3850 3960 4070 4180 4290 4400 4510 4620 4730 4840 4950 5060
[18] 5170 5280 5390 5500 5610 5720 5830 5940 6050 6160 6270 6380 6490 6600

Matice

Vytvorenie matíc

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

Rozmery matice

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

Adresovanie prvkov matice

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

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..25, vypočítajte stĺpcové sumy a súčin matíc \(M^t M\).

M2 <- matrix(1:25, nrow = 5, byrow = TRUE)
colSums(M2)
[1] 55 60 65 70 75
t(M2) %*% M2
     [,1] [,2] [,3] [,4] [,5]
[1,]  855  910  965 1020 1075
[2,]  910  970 1030 1090 1150
[3,]  965 1030 1095 1160 1225
[4,] 1020 1090 1160 1230 1300
[5,] 1075 1150 1225 1300 1375

LS0tCnRpdGxlOiAiWsOha2xhZG7DqSBvcGVyw6FjaWUgdiBSIgphdXRob3I6ICJOYXTDoWxpYSBLdW5vdsOhIgpkYXRlOiAiRmVicnXDoXIgMjAyNiIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdGhlbWU6IHVuaXRlZAogICAgaGlnaGxpZ2h0OiB0YW5nbwogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIGRmX3ByaW50OiBwYWdlZAplZGl0b3Jfb3B0aW9uczoKICBtYXJrZG93bjoKICAgIHdyYXA6IDcyCi0tLQoKIyBHbG9iw6FsbmUgbmFzdGF2ZW5pZSBDaHVua292CgpWIG5pxb7FoWllIHV2ZWRlbm9tIENodW5rdSBqZSB1cm9iZW7DqSB6w6FrbGFkbsOpIGdsb2LDoWxuZSBuYXN0YXZlbmllIENodW5rb3YgdiBjZWxvbSBOb3RlYm9va3UuIAoKLSAqKmVjaG8qKiBuYXN0YXZ1amUsIMSNaSBjaGNlbWUgdiBOb3RlYm9va3UgdnlwaXNvdmHFpSBqZWRub3RsaXbDqSBrw7NkeSBSCi0gKiptZXNzYWdlKiogamUgbmFzdGF2ZW7DvSBuYSAqRkFMU0UqLCDEjW8gem5hbWVuw6EsIMW+ZSBzYSBidWTDuiBwb3Rsw6HEjWHFpSBwcmFjb3Zuw6kgdsO9c3R1cHkgeiBSLCB0LmouIG5hcHLDrWtsYWQgdsO9c2xlZG9rIG90dsOhcmFuaWEga25pxb5uw61jLCBhIG5pZWt0b3LDqSBpbsOpIHbDvXN0dXB5LCBrdG9yw6kgYWxlIHByZSBjZWxrb3bDvSBOb3RlYm9vayBuZW1hasO6IHRha21lciDFvmlhZGVuIHbDvXpuYW0gYSBzw7ogdmhvZG7DqSBza8O0ciBwcmkgbGFkZW7DrSBrw7Nkb3YuCi0gKip3YXJuaW5nKiogbmFzdGF2ZW7DvSBuYSBGQUxTRSBwb3Rsw6HEjWEgem9icmF6ZW5pZSBjaHlib3bDvWNoIGhsw6HFoW9rCgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9VFJVRSxlY2hvPVRSVUV9CmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBlY2hvID0gVFJVRSwKICBtZXNzYWdlID0gRkFMU0UsCiAgd2FybmluZyA9IEZBTFNFCikKYGBgCgojIMOadm9kIGsgesOha2xhZG7DvW0gb3BlcsOhY2nDoW0gdiBSCgpUZW50byBub3RlYm9vayBkZW1vbsWhdHJ1amUgKip6w6FrbGFkbsOpIG9wZXLDoWNpZSoqIHYgamF6eWt1IFIgc286CgotIHNrYWzDoXJueW1pIMSNw61zbGFtaSAodC5qLiAxIMSNw61zbG8pLAotIHRleHRvdsO9bWkgKHpuYWtvdsO9bWkpIHJlxaVhemNhbWksCi0gbG9naWNrw71taSAoYm9vbG92c2vDvW1pKSBob2Rub3RhbWkgYSBwcmVtZW5uw71taSwKLSAobnVtZXJpY2vDvW1pKSB2ZWt0b3JtaSwKLSBtYXRpY2FtaS4KClRhbSwga2RlIGplIHRvIHXFvml0b8SNbsOpLCBzw7ogemFocm51dMOpIG1hbMOpIGN2acSNZW5pYS4KCi0tLQoKIyBTa2Fsw6FyZSAoamVkbm/EjcOtc2VsbsOpIGhvZG5vdHkpCgojIyBOdW1lcmlja8OpIHNrYWzDoXJlCgpgYGB7cn0KIyBQcmlyYWRlbmllIGtvbsWhdGFudHkgZG8gcHJlbWVubmVqCmEgPC0gNwpiIDwtIDMuNQoKIyBBcml0aG1ldGljCnN1bV9hYiAgICAgIDwtIGEgKyBiICAgICAgICAjIHN1Y2V0CmRpZmZfYWIgICAgIDwtIGEgLSBiICAgICAgICAjIHJvemRpZWwKcHJvZF9hYiAgICAgPC0gYSAqIGIgICAgICAgICMgbsOhc29iZW5pZQpxdW90X2FiICAgICA8LSBhIC8gYiAgICAgICAgIyBkZWxlbmllCnBvd2VyX2FiICAgIDwtIGEgXiBiICAgICAgICAjIHVtb2PFiG92YW5pZQptb2RfYWIgICAgICA8LSBhICUlIDMgICAgICAgIyB6Ynl0b2sgcG8gZGVsZW7DrSB0cm9taSAodHp2IG1vZHVsbykKCgojIFJvdW5kaW5nCnJvdW5kX2IgICA8LSByb3VuZChiKSAgICAgICAjIHphb2tydWhsb3ZhbmllIHNtZXJvbSBrIG5hamJsaXpzaWVtdSBjZWxlbXUgY2lzbHUKY2VpbF9iICAgIDwtIGNlaWxpbmcoYikgICAgICMgbmFqYmxpenNpZSB2eXNzaWUgY2VsZSBjaXNsbwpmbG9vcl9iICAgPC0gZmxvb3IoYikgICAgICAgIyBuYWpibGl6c2llIG5penNpZSBjZWxlIGNpc2xvCgphOyBiCnN1bV9hYjsgZGlmZl9hYjsgcHJvZF9hYjsgcXVvdF9hYjsgcG93ZXJfYWI7IG1vZF9hYgpyb3VuZF9iOyBjZWlsX2I7IGZsb29yX2IKYGBgCgoqKlBvem7DoW1reSoqCgotIGBeYCBvcGVyw6F0b3IgdW1vY8WIb3ZhbmlhLgotIGAlJWAgamUgbW9kdWxvLCB0ZWRhIHpieXRvayBwbyBkZWxlbsOtLCAKLSBgcm91bmQoeCwgZGlnaXRzID0gMClgIHphb2tyw7poxL5vdmFuaWUgbmEgdXLEjWl0w70gcG/EjWV0IGRlc2F0aW5uw71jaCBtaWVzdCAoZGlnaXRzPSkuIGFrIGRpZ2l0cyA9IDAsIHBvdG9tIGlkZSBvIGNlbG/EjcOtc2VsbsOpIHphb2tyw7poxL5vdmFuaWUKCgojIyBNYWzDqSBjdmnEjWVuaWUKCj4gVnlwb8SNw610YWp0ZToKCiQkXGZyYWN7KDE1XjItNCl9ezd9JCQKCmBgYHtyfQooMTVeMiAtIDQpIC8gNwpzaW4ocGkpCjI4NjAwMC00XjYKKDk0NSs3NDUrM145KS81Cihjb3MocGkpKjheOSkgLyAzCgpgYGAKCi0tLQoKIyBUZXh0IAoKIyMgVnl0dsOhcmFuaWUgdGV4dG92w71taSBwcmVtZW5uw71taSBhIHByw6FjYSBzIG5pbWkKCmBgYHtyfQpmaXJzdCA8LSAiVmxhZGltaXIiICAgICAgICAgICAgICAgICAgICAgICAjIGRlZmlub3ZhbmllIG9ic2FodSB0ZXh0b3ZlaiBwcmVtZW5uZWogZmlyc3QKbGFzdCAgPC0gIkdhemRhIiAgICAgICAgICAgICAgICAgICAgICAgICAgIyBkZWZpbm92YW5pZSBvYnNhaHUgdGV4dC4gcHJlbWVubmVqIGxhc3QKZnVsbCAgPC0gcGFzdGUoZmlyc3QsIGxhc3QpICAgICAgICAgICAgICAgIyBzcG9qZW5pZSBkdm9jaCB0ZXh0LiBwcmVtZW5ueWNoIGRvIGplZG5laiAocyBtZWR6ZXJvdSkKZnVsbF9ub3NwYWNlIDwtIHBhc3RlMChmaXJzdCwgbGFzdCkgICAgICAgIyBzcG9qZW5pZSBiZXogbWVkemVyeQpjc3ZfbGluZSA8LSBwYXN0ZSgiYXBwbGUiLCAiYmFuYW5hIiwgInBlYXIiLCBzZXAgPSAiLCIpICAjIHNwb2plbmllIHRleHRvdiBzIG9kZGVsb3ZhY29tICwKZmlyc3Q7IGxhc3Q7IGZ1bGw7IGZ1bGxfbm9zcGFjZTsgY3N2X2xpbmUgICAjIGJvZGtvxI1pYXJrYSB0dSBuYWhyYWR6dWplIG9kc2tvayBuYSBub3Z5IHJpYWRvayAKYGBgCgojIyBExLrFvmthIHRleHRvdsOpaG8gcmXFpWF6Y2EsIHBvZHJlxaVhemVjCgpgYGB7cn0KeCA8LSAiUiBpcyBncmVhdCEiCm5jaGFyKHgpICAgICAgICAgICAgICAgICAjIHBvxI1ldCB6bmFrb3YgIHYgcmV0YXpjaSAiUiBpcyBncmVhdCEiCnN1YnN0cih4LCAxLCA1KSAgICAgICAgICAjIHBvZHJlxaVhemVjIG9kIDEuIGRvIDUuIHpuYWt1CmBgYAoKCj4gVGlwOiBLbmnFvm5pY2EgKipzdHJpbmdyKiogbW5vaMOpIHphdWrDrW1hdsOpIG1vxb5ub3N0aSBwcsOhY2UgcyB0ZXh0YW1pLCBhbGUgaW1wbGljaXRuw6kga25pxb5uaWNlIFIgcG9rcsO9dmFqw7ogdsOkxI3FoWludSBiZcW+bsO9Y2ggcG90cmllYiBww6FjZSBzIHRleHRhbWkuCgotLS0KCiMgTG9naWNrw6kgKGJvb2xvdnNrw6kpIGhvZG5vdHkgYSBwcmVtZW5uw6kKCiMjIFrDoWtsYWR5CgpgYGB7cn0KcCA8LSBUUlVFCnEgPC0gRkFMU0UKIXAgICAgICAgICAgICAgICAgICMgTk9UCnAgJiBxICAgICAgICAgICAgICAjIEFORApwIHwgcSAgICAgICAgICAgICAgIyBPUgp4b3IocCwgcSkgICAgICAgICAgIyBleGNsdXNpdmUgT1IgLSBwbGF0w60gbGVuIGplZG5vIHogcCxhbGVibyBxCmBgYAoKIyMgTG9naWNrw70gdsO9c2xlZG9rIHBvcm92bsOhdmFuaWEKCmBgYHtyfQozIDwgNQo3ID49IDcKImNhdCIgPT0gImNhdCIKImNhdCIgIT0gImRvZyIgICAjIHZ5a3JpY25payBqZSB0dSB2IHpteXNsZSBuZWdhY2llLiBOYXByLjogICAhPSwgIT4sICE8LCAhVFJVRQohVFJVRQpgYGAKCiMjIFpsb8W+aXRlasWhaWUgbG9naWNrw6kgb3BlcsOhY2llCgpgYGB7cn0KeCA8LSAxMAp4ID4gNSAmIHggPCAyMCAgICAgICMgYSBzdWNhc25lIC0gbG9naWNreSBwcmllbmlrIChzdWNpbikKeCA8IDAgfCB4ID4gMTAwICAgICAjIGFsZWJvIC0gbG9naWNrZSB6amVkbm90ZW5pZSAoc3VjZXQpCiAgICAgICAgICAgICAgICAgICAgIyBwcmkgemxveml0ZWpzaWNoIHZ6dGFob2NoIHBvdXppdmFqdGUgemF0dm9ya3kgKCkKYGBgCgojIyBabHXEjW92YW5pZSB2aWFjZXLDvWNoIGxvZy4gcHJlbWVubsO9Y2ggZG8gdmVrdG9yYQoKYGBge3J9CnZhbHMgPC0gYyhUUlVFLCBGQUxTRSwgVFJVRSwgVFJVRSkgICAjIGRlZmluaWNpYSB2ZWt0b3JhIHMgbG9naWNreW1pIGhvZG5vdGFtaQpgYGAKCi0tLQoKIyBOdW1lcmlja8OpIHZla3RvcnkKCiMjIEdlbmVyb3ZhbmllIHZla3Rvcm92CgpgYGB7cn0KdjEgPC0gYygyLCA0LCA2LCA4KQp2MiA8LSAxOjUgICAgICAgICAgICAgICAgICAjIHBvc3R1cG5vc3QgMSwyLDMsNCw1CnYzIDwtIHNlcShmcm9tID0gMCwgdG8gPSAxLCBieSA9IDAuMjUpICAjIHBvc3R1cG5vc3QgcyBrcm9rb20gMC4yNQp2NCA8LSByZXAoMywgdGltZXMgPSA1KSAgICAjIDMsMywzLDMsMyAgIyA1IGNsZW5uYSBwb3N0dXBub3N0IHRyb2phawp2NSA8LSBydW5pZig1KSAgICAgICAgICAgICAjIGdlbmVyb3ZhbmllIHJvdm5vbWVybmUgcm96ZGVsZW55Y2ggcHJlbWVubnljaCB2IGludGVydmFsZSBbMCwxXQp2NiA8LSBybm9ybSg1KSAgICAgICAgICAgICAjIGdlbmVyb3ZhbmllIG5vcm1hbG5lIHJvemRlbGVueWNoIHByZW1lbm55Y2gKdjE7IHYyOyB2MzsgdjQ7IHY1CmBgYAoKIyMgQXJpdG1ldGlja8OpIG9wZXLDoWNpZSBzIHZla3Rvcm1pCgpgYGB7cn0KdiA8LSBjKDEsIDIsIDMsIDQpCnYgKyAxMCAgICAgICAgICAgIyBrYXpkeSBwcnZvayB2ZWt0b3JhIHp2YWNzaW1lIG8gMTAKdiAqIDIgICAgICAgICAgICAjIGthemR5IHBydm9rIHZla3RvcmEgcHJlbmFzb2JpbWUgMgoodiArIDEpIC8gMgpleHAodikgICAgICAgICAgICMgZXhwb25lbmNpYWxuYSBmdW5rY2lhIHoga2F6ZGVobyBwcnZrdSB2ZWt0b3JhCnN1bShjKDEsMiwzKSxjKDEsMSwxKSkgICAgICAgICAgIyBza2FsYXJueSBzdWNpbiAtIHZ5c2xlZG9rIGplIHNrYWxhcgpjcm9zc3Byb2QoYygxLDIsMyksYygxLDEsMSkpICAgICMgc2thbGFybnkgc3VjaW4gLSB2eXNsZWRvayBqZSBtYXRpY2EgMXgxCmMoMSwyLDMpKmMoMSwxLDEpICAgICAgICAgICAgICAgIyBIYWRhbWFyZG92IHN1Y2luIChzdWNpbiB6b2Rwb3ZlZGFqdWNpY2ggcHJ2a292IHZla3RvcmEpCmBgYAoKIyMgTWF0ZW1hdGlja8OpIG9wZXLDoWNpZSBzIDIgdmVrdG9ybWkgcm92bmFrw6lobyByb3ptZXJ1CgpgYGB7cn0KbGVuZ3RoKGMoMSwyLDMsNCw1KSkKbGVuZ3RoKHY1KSAgICAgICAgICAgICN2ZWt0b3IgdjUgamUgZGVmaW5vdmFueSB2eXNzaWUKYygxLDIsMyw0LDUpICsgdjUgICAgICMgcG96b3IsIG9iYSB2ZWt0b3J5IG11c2lhIG1hdCByb3ZuYWt5IHJvem1lcgpgYGAKCiMjIEluZGV4b3ZhbmllIGEgdsO9YmVyIG5pZWt0b3J5Y2ggcHJ2a292IHZla3RvcmEKCmBgYHtyfQp4IDwtIGMoNSwgMTIsIDMsIDE4LCA3LCAwLCAyMSkKeFsxXSAgICAgICAgICAgIyBpbmRleG92YW5pZSAtIG5vdnkgamVkbm8tcHJ2a292eSB2ZWt0b3IgLSBwcnZ5IHBydm9rIHZla3RvcmEgeAp4WzI6NF0gICAgICAgICAjIG5vdnkgdmVrdG9yIHMgZHJ1aHltIGF6IHN0dnJ0eW0gcHJ2a29tIHZla3RvcmEgeAp4Wy0xXSAgICAgICAgICAjIG5vdnkgdmVrdG9yIC0gdnNldGt5IHBydmt5IHZla3RvcmEgeCBva3JlbSBwcnbDqWhvCnhbeCA+IDEwXSAgICAgICMgbm92eSB2ZWt0b3IgZGVmaW5vdmFueSBwcnZrYW1pIHggdmFjc2ltaSBha28gMTAKd2hpY2goeCA+IDEwKSAgIyBrdG9yZSBwcnZreSB6b2Rwb3ZlZGFqdSBwb2RtaWVua2UgdmFjc2llaG8gYWtvIDEwPwpgYGAKCiMjIFByw6FjYSBzIGNow71iYWrDumNpbWkgaG9kbm90YW1pCgpgYGB7cn0KeSA8LSBjKDEsIE5BLCAzLCBOQSwgNSkKaXMubmEoeSkKbWVhbih5KSAgICAgICAgICAgICAgICAgIyBOQQptZWFuKHksIG5hLnJtID0gVFJVRSkgICAjIHJlbW92ZSBOQXMKYGBgCgojIyBaw6FrbGFkbsOpIMWhdGF0aXN0aWt5IGEgdXNwb3JpYWRhbmllIHBydmtvdiB2ZWt0b3JhIHBvZMS+YSB2ZcS+a29zdGkKCmBgYHtyfQp6IDwtIGMoMTAsIDMsIDUsIDgsIDIpCm1lYW4oeikgICAgICAgICAgICAgICAgICMgcHJpZW1lcm5hIGhvZG5vdGEKc2QoeikgICAgICAgICAgICAgICAgICAjIHN0YW5kYXJkbmEgb2RjaHlsa2EKbWF4KHopICAgICAgICAgICAgICAgICAgIyBtYXhpbWFsbmEgaG9kbm90YQpzdW1tYXJ5KHopICAgICAgICAgICAgICAjIHJ5Y2hseSBwcmVobGFkIHpha2xhZG55Y2ggc3RhdGlzdGlrIG8gdmVrdG9yZQpzb3J0KHopICAgICAgICAgICAgICAgICAjIHJhc3R1Y2UgdXNwb3JpYWRhbmllIApzb3J0KHosIGRlY3JlYXNpbmcgPSBUUlVFKSAgIyBrbGVzYWp1Y2UKYGBgCgojIyBNYWzDqSBjdmnEjWVuaWUKPiBWeXR2b3J0ZSB2ZWt0b3IgYHdgIHMgxI3DrXNsYW1pIDEuLjIwIGEgdnlwb8SNw610YWp0ZSBzdW11IHbFoWV0a8O9Y2ggcMOhcm55Y2ggxI3DrXNlbC4KCmBgYHtyfQp3IDwtIDE6MjAKc3VtKHdbdyAlJSAyID09IDBdKQprIDwtIDMwOjYwCnN1bShrW2sgJSUgMiA9PSAxXSkKdyA8LSAxOjIwCnN1bSh3W3cgJSUgMiA9PSAwXSkvcGkKc3VtKHdbdyAlJSAyID09IDFdKS9waQpzdW0od1t3ICUlIDIgPT0gMF0pL2sKc3VtKHdbdyAlJSAyID09IDBdKSprCmBgYAoKLS0tCgojIE1hdGljZQoKIyMgVnl0dm9yZW5pZSBtYXTDrWMKCmBgYHtyfQptIDwtIG1hdHJpeCgxOjEyLCBucm93ID0gMywgbmNvbCA9IDQpICAgICAgICAgICAgIyBob2Rub3R5IHPDuiB6YWRhdmFuZSBwbyBzdGxwY29jaAptX2J5cm93IDwtIG1hdHJpeCgxOjEyLCBucm93ID0gMywgYnlyb3cgPSBUUlVFKSAgIyBob2Rub3R5IHN1IHphZGF2YW5lIHBvIHJpYWRrb2NoCm07IG1fYnlyb3cKYGBgCgojIyBSb3ptZXJ5IG1hdGljZQoKYGBge3J9CmRpbShtKSAgICAgICAgICAgICAgICAgICAjIChyb3dzLCBjb2xzKQptCmBgYAoKIyMgQWRyZXNvdmFuaWUgcHJ2a292IG1hdGljZQoKYGBge3J9Cm1bMSwgMl0gICAgICAjIHJpYWRvayAxLCBzdGxwZWMgMgptWyAsIDNdICAgICAgIyB2c2V0a3kgcHJ2a3kgdiB0cmV0b20gc3RscGNpIC0gdnlzbGVkb2sgbWF0aWNhIDN4MQptWzIsIF0gICAgICAgIyB2c2V0a3kgcHJ2a3kgdiBkcnVob20gcmlhZGt1IC0gdnlzbGVkb2sgbWF0aWNhIDEqMwptWzE6MiwgMjozXSAgIyBwb2RtYXRpY2EgdHZvcmVuYSByaWFka2FtaSAxLCAyIGEgc3RscGNhbWkgMiwgMwpgYGAKCiMjIE1hdGljb3bDqSBvcGVyw6FjaWUKCmBgYHtyfQpBIDwtIG1hdHJpeChjKDEsMiwzLDQpLCBucm93ID0gMikKQiA8LSBtYXRyaXgoYyg1LDYsNyw4KSwgbnJvdyA9IDIpCgpBICsgQiAgICAgICAgIyBzY2l0YW5pZSBtYXRpYwpBICogQiAgICAgICAgIyBIYWRhbWFyZCBwcm9kdWN0IC0gbmFzb2JlbmllIHBvIHpvZHBvdmVkYWp1Y2ljaCBwcnZrb2NoCkEgJSolIEIgICAgICAjIG5hc29iZW5pZSBtYXRpYwp0KEEpICAgICAgICAgIyB0cmFuc3BvemljaWEgbWF0aWNlIEEgLSB2eW1lbmEgcmlhZGtvdiBhIHN0bHBjb3YKZGV0KEEpICAgICAgICMgZGV0ZXJtaW5hbnQgbWF0aWNlCnNvbHZlKEEpICAgICAjIGludmVyemlhIG1hdGljZSAoYWsgamUgbWF0aWNhIHJlZ3VsYXJuYSAtIHRlZGEgaW52ZXJ6aWEgc2EgZGEgc3BvY2l0YXQpCmBgYAoKIyMgWmx1xI1vdmFuaWUgdmVrdG9yb3YgZG8gbWF0w61jIAoKYGBge3J9CkMgPC0gY2JpbmQoMTozLCA0OjYpICAgIyAgLSBwbyBzdGxwY29jaCAKRCA8LSByYmluZCgxOjMsIDQ6NikgICAjICAtIHBvIHJpYWRrb2NoIApDOyBECmBgYAoKIyMgVnlwb8SNw610YW5pZSB6dm9sZW5laiDFoXRhdGlzdGlreSBwbyByaWFka29jaCAoc3TEunBjb2NoKSBtYXRpY2UKCmBgYHtyfQpNIDwtIG1hdHJpeCgxOjksIG5yb3cgPSAzKQpNCmFwcGx5KE0sIDEsIHN1bSkgICAjIHN1bWEgcG8gcmlhZGtvY2gKYXBwbHkoTSwgMiwgbWVhbikgICMgcHJpZW1lcnkgcG8gc3TEunBjb2NoCmBgYAoKIyMgTWFsw6kgY3ZpxI1lbmllCgo+IFZ5dHZvcnRlIG1hdGljdSA1eDUgcyBob2Rub3RhbWkgcG8gcmlhZGtvY2ggMS4uMjUsIHZ5cG/EjcOtdGFqdGUgc3TEunBjb3bDqSBzdW15IGEgc8O6xI1pbiBtYXTDrWMgXChNXnQgTVwpLgoKYGBge3J9Ck0yIDwtIG1hdHJpeCgxOjI1LCBucm93ID0gNSwgYnlyb3cgPSBUUlVFKQpjb2xTdW1zKE0yKQp0KE0yKSAlKiUgTTIKYGBgCgotLS0KCgoKCg==