Globálne nastavenie Chunkov

knitr::opts_chunk$set(
    echo = TRUE,
    message = FALSE,
    warning = FALSE
)
## Numerické skaláre
x <- 12
y <- 4.2

sucet    <- x + y
rozdiel  <- x - y
nasobok  <- x * y
podiel   <- x / y
mocnina  <- x ^ 2
modulo   <- x %% 5

zaokr1   <- round(y, 1)
ceil_y   <- ceiling(y)
floor_y  <- floor(y)

x; y
[1] 12
[1] 4.2
sucet; rozdiel; nasobok; podiel; mocnina; modulo
[1] 16.2
[1] 7.8
[1] 50.4
[1] 2.857143
[1] 144
[1] 2
zaokr1; ceil_y; floor_y
[1] 4.2
[1] 5
[1] 4
  

Vypočítajte hodnotu

\[\frac{(20^2 + 10)}{6}\]

(20^2 + 10) / 6

Textové hodnoty a premenné

meno <- "Anna"
priezvisko <- "Novaková"

cele_meno <- paste(meno, priezvisko)
cele_meno_bez <- paste0(meno, priezvisko)

zelenina <- paste("mrkva", "uhorka", "paradajka", sep = ";")

meno; priezvisko; cele_meno; cele_meno_bez; zelenina

Vytvorte textovú premennú slovo <- “programovanie” a:

1.  zistite, koľko má znakov,
2.  vypíšte podreťazec od 5. po 9. znak.
slovo <- "programovanie"
nchar(slovo)
substr(slovo, 5, 9)

Logické hodnoty a premenné

p <- TRUE
q <- FALSE

!q
p & q
p | q
xor(p, q)

Porovnávanie

10 > 3
5 <= 2
"dog" == "dog"
"dog" != "cat"

Kombinácie podmienok

z <- 15
z > 10 & z < 20
z < 0 | z == 15

Definujte cislo <- 25.

Skontrolujte: 1. či je väčšie ako 10, 2. či je menšie alebo rovné 30, 3. vytvorte podmienku, ktorá overí, či platia súčasne obidve podmienky.

cislo <- 25
cislo > 10
cislo <= 30
cislo > 10 & cislo <= 30

Môj návrh použitia novinky

#Na rozdiel od pôvodného dokumentu ukážeme prácu s logickou funkciou any() a all(), ktoré sa hodia pri vektoroch:

vek <- c(18, 22, 19, 25, 30)

any(vek > 29)   # existuje aspoň jeden prvok väčší ako 29?
all(vek >= 18)  # sú všetky prvky aspoň 18?

Numerické vektory

Generovanie vektorov

v1 <- c(1200, 1350, 1500, 1650)
v2 <- 10:15                 # postupnosť 10,11,12,13,14,15
v3 <- seq(from = 2, to = 4, by = 0.5)  # postupnosť s krokom 0.5
v4 <- rep(900, times = 4)   # 900,900,900,900
v5 <- runif(6, min = 1000, max = 2000) # rovnomerne rozdelené mzdy
v6 <- rnorm(6, mean = 1500, sd = 200)  # normálne rozdelené mzdy

v1; v2; v3; v4; v5
[1] 1200 1350 1500 1650
[1] 10 11 12 13 14 15
[1] 2.0 2.5 3.0 3.5 4.0
[1] 900 900 900 900
[1] 1803.719 1631.695 1294.339 1695.103 1044.882 1651.261

Aritmetické operácie s vektormi

mzdy <- c(1100, 1250, 1400, 1600)
mzdy + 100          # každému zamestnancovi zvýšime mzdu o 100 €
[1] 1200 1350 1500 1700
mzdy * 1.1          # zvýšenie o 10 %
[1] 1210 1375 1540 1760
(mzdy + 200) / 2
[1] 650 725 800 900
exp(mzdy / 1000)    # len pre ilustráciu
[1] 3.004166 3.490343 4.055200 4.953032
# Skalárny a Hadamardov súčin
sum(c(1,2,3), c(2,2,2))          # skalárny súčin – výsledok je skalar
[1] 12
crossprod(c(1,2,3), c(2,2,2))    # skalárny súčin – výsledok je matica 1x1
     [,1]
[1,]   12
c(1,2,3) * c(2,2,2)              # Hadamardov súčin
[1] 2 4 6

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

bonus <- runif(4, min = 50, max = 150)
length(mzdy)
[1] 4
length(bonus)
[1] 4
mzdy + bonus       # súčet základnej mzdy a bonusu
[1] 1226.153 1300.478 1479.796 1664.381

Indexovanie a výber niektorých prvkov vektora

x <- c(800, 1200, 1700, 950, 1800, 2200, 1300)
x[1]            # prvý prvok
[1] 800
x[3:5]          # tretí až piaty prvok
[1] 1700  950 1800
x[-2]           # všetky okrem druhého
[1]  800 1700  950 1800 2200 1300
x[x > 1500]     # výber len vyšších miezd
[1] 1700 1800 2200
which(x > 1500) # indexy týchto prvkov
[1] 3 5 6

Práca s chýbajúcimi hodnotami

y <- c(1200, 1350, NA, 1600, NA, 1750)
is.na(y)
[1] FALSE FALSE  TRUE FALSE  TRUE FALSE
mean(y)                  # výsledok NA
[1] NA
mean(y, na.rm = TRUE)    # odstráni chýbajúce hodnoty
[1] 1475

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

mzdy2 <- c(980, 1250, 1320, 1500, 1750, 2000)
mean(mzdy2)
[1] 1466.667
sd(mzdy2)
[1] 366.3696
max(mzdy2)
[1] 2000
summary(mzdy2)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
    980    1268    1410    1467    1688    2000 
sort(mzdy2)
[1]  980 1250 1320 1500 1750 2000
sort(mzdy2, decreasing = TRUE)
[1] 2000 1750 1500 1320 1250  980

Malé cvičenie

Vytvorte vektor platy s náhodnými 10 mzdami (od 900 do 2200 €). Zistite, koľko zamestnancov zarába viac ako 1500 € a aký je priemer ich miezd.

platy <- runif(10, min = 900, max = 2200)
platy
 [1] 1143.8027 1492.2205  906.8487 1906.9286  932.9133 2035.5511
 [7] 1523.4061 1888.7347 1630.7147 1295.2288
sum(platy > 1500)
[1] 5
mean(platy[platy > 1500])
[1] 1797.067

Matice

#Vytvorenie matíc

m <- matrix(101:116, nrow = 4, ncol = 4)
m_byrow <- matrix(201:216, nrow = 4, byrow = TRUE)
m; m_byrow
     [,1] [,2] [,3] [,4]
[1,]  101  105  109  113
[2,]  102  106  110  114
[3,]  103  107  111  115
[4,]  104  108  112  116
     [,1] [,2] [,3] [,4]
[1,]  201  202  203  204
[2,]  205  206  207  208
[3,]  209  210  211  212
[4,]  213  214  215  216

#Rozmery matice

dim(m)
[1] 4 4

#Adresovanie prvkov matice

m[2, 3]       # druhý riadok, tretí stĺpec
[1] 110
m[, 4]        # všetky prvky zo 4. stĺpca
[1] 113 114 115 116
m[1, ]        # prvý riadok
[1] 101 105 109 113
m[2:3, 1:2]   # podmatica
     [,1] [,2]
[1,]  102  106
[2,]  103  107

#Maticové operácie

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

A + B
     [,1] [,2]
[1,]   11    8
[2,]    6   11
A * B
     [,1] [,2]
[1,]   24   12
[2,]    5   28
A %*% B
     [,1] [,2]
[1,]   26   26
[2,]   47   58
t(A)
     [,1] [,2]
[1,]    3    5
[2,]    2    7
det(A)
[1] 11
solve(A)
           [,1]       [,2]
[1,]  0.6363636 -0.1818182
[2,] -0.4545455  0.2727273

#Zlučovanie vektorov do matíc

vek1 <- c(1500, 1600, 1700)
vek2 <- c(200, 250, 300)
C <- cbind(vek1, vek2)
D <- rbind(vek1, vek2)
C; D
     vek1 vek2
[1,] 1500  200
[2,] 1600  250
[3,] 1700  300
     [,1] [,2] [,3]
vek1 1500 1600 1700
vek2  200  250  300

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

M <- matrix(seq(5, 45, by = 5), nrow = 5)
M
     [,1] [,2]
[1,]    5   30
[2,]   10   35
[3,]   15   40
[4,]   20   45
[5,]   25    5
apply(M, 1, sum)
[1] 35 45 55 65 30
apply(M, 2, mean)
[1] 15 31

Malé cvičenie

Predstavte si, že matica mzdy_mat obsahuje mesačné mzdy 4 zamestnancov počas 6 mesiacov. • Každý riadok reprezentuje jedného zamestnanca. • Každý stĺpec predstavuje mesiac.

Úlohy: 1. Zistite, ktorý zamestnanec mal najvyšší priemer mzdy. 2. Vypočítajte, v ktorom mesiaci bola celková vyplatená suma najvyššia. 3. Vytvorte nový vektor, ktorý ukáže rozdiel medzi priemernou mzdou každého zamestnanca a celkovým priemerom.

set.seed(123)
mzdy_mat <- matrix(round(runif(24, min = 900, max = 2200)), nrow = 4)
mzdy_mat
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1274 2123 1617 1781 1220 2056
[2,] 1925  959 1494 1644  955 1801
[3,] 1432 1587 2144 1034 1326 1733
[4,] 2048 2060 1489 2070 2141 2193
# 1. Priemerná mzda zamestnanca
priemery_zam <- apply(mzdy_mat, 1, mean)
which.max(priemery_zam)
[1] 4
# 2. Suma po mesiacoch
sumy_mesiace <- colSums(mzdy_mat)
which.max(sumy_mesiace)
[1] 6
# 3. Rozdiel oproti celkovému priemeru
celkovy_priemer <- mean(mzdy_mat)
rozdiel <- priemery_zam - celkovy_priemer
rozdiel
[1]    7.416667 -208.083333 -128.416667  329.083333
Ci0tLQp0aXRsZTogIlrDoWtsYWRuw6kgb3BlcsOhY2llIHYgUiDigJMgYWx0ZXJuYXTDrXZueSBjdmnEjWVibsO9IGRva3VtZW50IgphdXRob3I6ICJQcsOtcHJhdmE6IMWgdHVkZW50a2EgQW5hc3Rhc2l5YSBaeWxldmljaCAiCmRhdGU6ICJPa3TDs2JlciAyMDI1IgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdGhlbWU6IHVuaXRlZAogICAgaGlnaGxpZ2h0OiB0YW5nbwplZGl0b3Jfb3B0aW9uczogCiAgbWFya2Rvd246IAogICAgd3JhcDogNzIKLS0tCgojIyBHbG9iw6FsbmUgbmFzdGF2ZW5pZSBDaHVua292CgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1UUlVFLCBlY2hvPVRSVUV9CmtuaXRyOjpvcHRzX2NodW5rJHNldCgKCWVjaG8gPSBUUlVFLAoJbWVzc2FnZSA9IEZBTFNFLAoJd2FybmluZyA9IEZBTFNFCikKIyMgTnVtZXJpY2vDqSBza2Fsw6FyZQp4IDwtIDEyCnkgPC0gNC4yCgpzdWNldCAgICA8LSB4ICsgeQpyb3pkaWVsICA8LSB4IC0geQpuYXNvYm9rICA8LSB4ICogeQpwb2RpZWwgICA8LSB4IC8geQptb2NuaW5hICA8LSB4IF4gMgptb2R1bG8gICA8LSB4ICUlIDUKCnphb2tyMSAgIDwtIHJvdW5kKHksIDEpCmNlaWxfeSAgIDwtIGNlaWxpbmcoeSkKZmxvb3JfeSAgPC0gZmxvb3IoeSkKCng7IHkKc3VjZXQ7IHJvemRpZWw7IG5hc29ib2s7IHBvZGllbDsgbW9jbmluYTsgbW9kdWxvCnphb2tyMTsgY2VpbF95OyBmbG9vcl95CiAgCmBgYAojIyBWeXBvxI3DrXRhanRlIGhvZG5vdHUKJCRcZnJhY3soMjBeMiArIDEwKX17Nn0kJApgYGB7cn0KKDIwXjIgKyAxMCkgLyA2CmBgYAojIyBUZXh0b3bDqSBob2Rub3R5IGEgcHJlbWVubsOpCmBgYHtyfQptZW5vIDwtICJBbm5hIgpwcmllenZpc2tvIDwtICJOb3Zha292w6EiCgpjZWxlX21lbm8gPC0gcGFzdGUobWVubywgcHJpZXp2aXNrbykKY2VsZV9tZW5vX2JleiA8LSBwYXN0ZTAobWVubywgcHJpZXp2aXNrbykKCnplbGVuaW5hIDwtIHBhc3RlKCJtcmt2YSIsICJ1aG9ya2EiLCAicGFyYWRhamthIiwgc2VwID0gIjsiKQoKbWVubzsgcHJpZXp2aXNrbzsgY2VsZV9tZW5vOyBjZWxlX21lbm9fYmV6OyB6ZWxlbmluYQpgYGAKCiMjIFZ5dHZvcnRlIHRleHRvdsO6IHByZW1lbm7DuiBzbG92byA8LSAicHJvZ3JhbW92YW5pZSIgYToKCTEuCXppc3RpdGUsIGtvxL5rbyBtw6Egem5ha292LAoJMi4Jdnlww63FoXRlIHBvZHJlxaVhemVjIG9kIDUuIHBvIDkuIHpuYWsuCmBgYHtyfQpzbG92byA8LSAicHJvZ3JhbW92YW5pZSIKbmNoYXIoc2xvdm8pCnN1YnN0cihzbG92bywgNSwgOSkKYGBgCgkKIyMgTG9naWNrw6kgaG9kbm90eSBhIHByZW1lbm7DqQpgYGB7cn0KcCA8LSBUUlVFCnEgPC0gRkFMU0UKCiFxCnAgJiBxCnAgfCBxCnhvcihwLCBxKQpgYGAKCiMgUG9yb3Zuw6F2YW5pZQpgYGB7cn0KMTAgPiAzCjUgPD0gMgoiZG9nIiA9PSAiZG9nIgoiZG9nIiAhPSAiY2F0IgpgYGAKIyBLb21iaW7DoWNpZSBwb2RtaWVub2sKYGBge3J9CnogPC0gMTUKeiA+IDEwICYgeiA8IDIwCnogPCAwIHwgeiA9PSAxNQpgYGAKIyMgRGVmaW51anRlIGNpc2xvIDwtIDI1Lgo+U2tvbnRyb2x1anRlOgoJMS4JxI1pIGplIHbDpMSNxaFpZSBha28gMTAsCgkyLgnEjWkgamUgbWVuxaFpZSBhbGVibyByb3Zuw6kgMzAsCgkzLgl2eXR2b3J0ZSBwb2RtaWVua3UsIGt0b3LDoSBvdmVyw60sIMSNaSBwbGF0aWEgc8O6xI1hc25lIG9iaWR2ZSBwb2RtaWVua3kuCgkKYGBge3J9CmNpc2xvIDwtIDI1CmNpc2xvID4gMTAKY2lzbG8gPD0gMzAKY2lzbG8gPiAxMCAmIGNpc2xvIDw9IDMwCmBgYAoKIyMgTcO0aiBuw6F2cmggcG91xb5pdGlhIG5vdmlua3kKI05hIHJvemRpZWwgb2QgcMO0dm9kbsOpaG8gZG9rdW1lbnR1IHVrw6HFvmVtZSBwcsOhY3UgcyBsb2dpY2tvdSBmdW5rY2lvdSBhbnkoKSBhIGFsbCgpLCBrdG9yw6kgc2EgaG9kaWEgcHJpIHZla3Rvcm9jaDoKYGBge3J9CnZlayA8LSBjKDE4LCAyMiwgMTksIDI1LCAzMCkKCmFueSh2ZWsgPiAyOSkgICAjIGV4aXN0dWplIGFzcG/FiCBqZWRlbiBwcnZvayB2w6TEjcWhw60gYWtvIDI5PwphbGwodmVrID49IDE4KSAgIyBzw7ogdsWhZXRreSBwcnZreSBhc3BvxYggMTg/CmBgYAoKIyMgTnVtZXJpY2vDqSB2ZWt0b3J5CiMgR2VuZXJvdmFuaWUgdmVrdG9yb3YKYGBge3J9CnYxIDwtIGMoMTIwMCwgMTM1MCwgMTUwMCwgMTY1MCkKdjIgPC0gMTA6MTUgICAgICAgICAgICAgICAgICMgcG9zdHVwbm9zxaUgMTAsMTEsMTIsMTMsMTQsMTUKdjMgPC0gc2VxKGZyb20gPSAyLCB0byA9IDQsIGJ5ID0gMC41KSAgIyBwb3N0dXBub3PFpSBzIGtyb2tvbSAwLjUKdjQgPC0gcmVwKDkwMCwgdGltZXMgPSA0KSAgICMgOTAwLDkwMCw5MDAsOTAwCnY1IDwtIHJ1bmlmKDYsIG1pbiA9IDEwMDAsIG1heCA9IDIwMDApICMgcm92bm9tZXJuZSByb3pkZWxlbsOpIG16ZHkKdjYgPC0gcm5vcm0oNiwgbWVhbiA9IDE1MDAsIHNkID0gMjAwKSAgIyBub3Jtw6FsbmUgcm96ZGVsZW7DqSBtemR5Cgp2MTsgdjI7IHYzOyB2NDsgdjUKYGBgCiMgQXJpdG1ldGlja8OpIG9wZXLDoWNpZSBzIHZla3Rvcm1pCmBgYHtyfQptemR5IDwtIGMoMTEwMCwgMTI1MCwgMTQwMCwgMTYwMCkKbXpkeSArIDEwMCAgICAgICAgICAjIGthxb5kw6ltdSB6YW1lc3RuYW5jb3ZpIHp2w73FoWltZSBtemR1IG8gMTAwIOKCrAptemR5ICogMS4xICAgICAgICAgICMgenbDvcWhZW5pZSBvIDEwICUKKG16ZHkgKyAyMDApIC8gMgpleHAobXpkeSAvIDEwMDApICAgICMgbGVuIHByZSBpbHVzdHLDoWNpdQoKIyBTa2Fsw6FybnkgYSBIYWRhbWFyZG92IHPDusSNaW4Kc3VtKGMoMSwyLDMpLCBjKDIsMiwyKSkgICAgICAgICAgIyBza2Fsw6Fybnkgc8O6xI1pbiDigJMgdsO9c2xlZG9rIGplIHNrYWxhcgpjcm9zc3Byb2QoYygxLDIsMyksIGMoMiwyLDIpKSAgICAjIHNrYWzDoXJueSBzw7rEjWluIOKAkyB2w71zbGVkb2sgamUgbWF0aWNhIDF4MQpjKDEsMiwzKSAqIGMoMiwyLDIpICAgICAgICAgICAgICAjIEhhZGFtYXJkb3Ygc8O6xI1pbgpgYGAKIyBNYXRlbWF0aWNrw6kgb3BlcsOhY2llIHMgMiB2ZWt0b3JtaSByb3ZuYWvDqWhvIHJvem1lcnUKYGBge3J9CmJvbnVzIDwtIHJ1bmlmKDQsIG1pbiA9IDUwLCBtYXggPSAxNTApCmxlbmd0aChtemR5KQpsZW5ndGgoYm9udXMpCm16ZHkgKyBib251cyAgICAgICAjIHPDusSNZXQgesOha2xhZG5laiBtemR5IGEgYm9udXN1CmBgYAojIEluZGV4b3ZhbmllIGEgdsO9YmVyIG5pZWt0b3LDvWNoIHBydmtvdiB2ZWt0b3JhCmBgYHtyfQp4IDwtIGMoODAwLCAxMjAwLCAxNzAwLCA5NTAsIDE4MDAsIDIyMDAsIDEzMDApCnhbMV0gICAgICAgICAgICAjIHBydsO9IHBydm9rCnhbMzo1XSAgICAgICAgICAjIHRyZXTDrSBhxb4gcGlhdHkgcHJ2b2sKeFstMl0gICAgICAgICAgICMgdsWhZXRreSBva3JlbSBkcnVow6lobwp4W3ggPiAxNTAwXSAgICAgIyB2w71iZXIgbGVuIHZ5xaHFocOtY2ggbWllemQKd2hpY2goeCA+IDE1MDApICMgaW5kZXh5IHTDvWNodG8gcHJ2a292CmBgYAojIFByw6FjYSBzIGNow71iYWrDumNpbWkgaG9kbm90YW1pCmBgYHtyfQp5IDwtIGMoMTIwMCwgMTM1MCwgTkEsIDE2MDAsIE5BLCAxNzUwKQppcy5uYSh5KQptZWFuKHkpICAgICAgICAgICAgICAgICAgIyB2w71zbGVkb2sgTkEKbWVhbih5LCBuYS5ybSA9IFRSVUUpICAgICMgb2RzdHLDoW5pIGNow71iYWrDumNlIGhvZG5vdHkKYGBgCgojIFrDoWtsYWRuw6kgxaF0YXRpc3Rpa3kgYSB1c3BvcmlhZGFuaWUgcHJ2a292IHZla3RvcmEgcG9kxL5hIHZlxL5rb3N0aQpgYGB7cn0KbXpkeTIgPC0gYyg5ODAsIDEyNTAsIDEzMjAsIDE1MDAsIDE3NTAsIDIwMDApCm1lYW4obXpkeTIpCnNkKG16ZHkyKQptYXgobXpkeTIpCnN1bW1hcnkobXpkeTIpCnNvcnQobXpkeTIpCnNvcnQobXpkeTIsIGRlY3JlYXNpbmcgPSBUUlVFKQpgYGAKIyMgTWFsw6kgY3ZpxI1lbmllCgpWeXR2b3J0ZSB2ZWt0b3IgcGxhdHkgcyBuw6Fob2Ruw71taSAxMCBtemRhbWkgKG9kIDkwMCBkbyAyMjAwIOKCrCkuClppc3RpdGUsIGtvxL5rbyB6YW1lc3RuYW5jb3YgemFyw6FiYSB2aWFjIGFrbyAxNTAwIOKCrCBhIGFrw70gamUgcHJpZW1lciBpY2ggbWllemQuCmBgYHtyfQpwbGF0eSA8LSBydW5pZigxMCwgbWluID0gOTAwLCBtYXggPSAyMjAwKQpwbGF0eQpzdW0ocGxhdHkgPiAxNTAwKQptZWFuKHBsYXR5W3BsYXR5ID4gMTUwMF0pCmBgYAoKIyMgTWF0aWNlCiNWeXR2b3JlbmllIG1hdMOtYwoKYGBge3J9Cm0gPC0gbWF0cml4KDEwMToxMTYsIG5yb3cgPSA0LCBuY29sID0gNCkKbV9ieXJvdyA8LSBtYXRyaXgoMjAxOjIxNiwgbnJvdyA9IDQsIGJ5cm93ID0gVFJVRSkKbTsgbV9ieXJvdwpgYGAKI1Jvem1lcnkgbWF0aWNlCgpgYGB7cn0KZGltKG0pCmBgYAojQWRyZXNvdmFuaWUgcHJ2a292IG1hdGljZQoKYGBge3J9Cm1bMiwgM10gICAgICAgIyBkcnVow70gcmlhZG9rLCB0cmV0w60gc3TEunBlYwptWywgNF0gICAgICAgICMgdsWhZXRreSBwcnZreSB6byA0LiBzdMS6cGNhCm1bMSwgXSAgICAgICAgIyBwcnbDvSByaWFkb2sKbVsyOjMsIDE6Ml0gICAjIHBvZG1hdGljYQpgYGAKI01hdGljb3bDqSBvcGVyw6FjaWUKCmBgYHtyfQpBIDwtIG1hdHJpeChjKDMsNSwyLDcpLCBucm93ID0gMikKQiA8LSBtYXRyaXgoYyg4LDEsNiw0KSwgbnJvdyA9IDIpCgpBICsgQgpBICogQgpBICUqJSBCCnQoQSkKZGV0KEEpCnNvbHZlKEEpCmBgYAojWmx1xI1vdmFuaWUgdmVrdG9yb3YgZG8gbWF0w61jCgpgYGB7cn0KdmVrMSA8LSBjKDE1MDAsIDE2MDAsIDE3MDApCnZlazIgPC0gYygyMDAsIDI1MCwgMzAwKQpDIDwtIGNiaW5kKHZlazEsIHZlazIpCkQgPC0gcmJpbmQodmVrMSwgdmVrMikKQzsgRApgYGAKCiNWeXBvxI3DrXRhbmllIHp2b2xlbmVqIMWhdGF0aXN0aWt5IHBvIHJpYWRrb2NoIChzdMS6cGNvY2gpIG1hdGljZQoKYGBge3J9Ck0gPC0gbWF0cml4KHNlcSg1LCA0NSwgYnkgPSA1KSwgbnJvdyA9IDUpCk0KYXBwbHkoTSwgMSwgc3VtKQphcHBseShNLCAyLCBtZWFuKQpgYGAKIyMgTWFsw6kgY3ZpxI1lbmllClByZWRzdGF2dGUgc2ksIMW+ZSBtYXRpY2EgbXpkeV9tYXQgb2JzYWh1amUgbWVzYcSNbsOpIG16ZHkgNCB6YW1lc3RuYW5jb3YgcG/EjWFzIDYgbWVzaWFjb3YuCgnigKIJS2HFvmTDvSByaWFkb2sgcmVwcmV6ZW50dWplIGplZG7DqWhvIHphbWVzdG5hbmNhLgoJ4oCiCUthxb5kw70gc3TEunBlYyBwcmVkc3RhdnVqZSBtZXNpYWMuCgrDmmxvaHk6CgkxLglaaXN0aXRlLCBrdG9yw70gemFtZXN0bmFuZWMgbWFsIG5hanZ5xaHFocOtIHByaWVtZXIgbXpkeS4KCTIuCVZ5cG/EjcOtdGFqdGUsIHYga3Rvcm9tIG1lc2lhY2kgYm9sYSBjZWxrb3bDoSB2eXBsYXRlbsOhIHN1bWEgbmFqdnnFocWhaWEuCgkzLglWeXR2b3J0ZSBub3bDvSB2ZWt0b3IsIGt0b3LDvSB1a8Ohxb5lIHJvemRpZWwgbWVkemkgcHJpZW1lcm5vdSBtemRvdSBrYcW+ZMOpaG8gemFtZXN0bmFuY2EgYSBjZWxrb3bDvW0gcHJpZW1lcm9tLgpgYGB7cn0Kc2V0LnNlZWQoMTIzKQptemR5X21hdCA8LSBtYXRyaXgocm91bmQocnVuaWYoMjQsIG1pbiA9IDkwMCwgbWF4ID0gMjIwMCkpLCBucm93ID0gNCkKbXpkeV9tYXQKCiMgMS4gUHJpZW1lcm7DoSBtemRhIHphbWVzdG5hbmNhCnByaWVtZXJ5X3phbSA8LSBhcHBseShtemR5X21hdCwgMSwgbWVhbikKd2hpY2gubWF4KHByaWVtZXJ5X3phbSkKCiMgMi4gU3VtYSBwbyBtZXNpYWNvY2gKc3VteV9tZXNpYWNlIDwtIGNvbFN1bXMobXpkeV9tYXQpCndoaWNoLm1heChzdW15X21lc2lhY2UpCgojIDMuIFJvemRpZWwgb3Byb3RpIGNlbGtvdsOpbXUgcHJpZW1lcnUKY2Vsa292eV9wcmllbWVyIDwtIG1lYW4obXpkeV9tYXQpCnJvemRpZWwgPC0gcHJpZW1lcnlfemFtIC0gY2Vsa292eV9wcmllbWVyCnJvemRpZWwKYGBgCgo=