Ú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.
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.
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
[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
[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
[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
[1] 4 5
[,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
[,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
[,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