Ú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 <- "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.
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
[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
[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
[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
[1] 31.83099
[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
[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
[1] 3 4
[,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
[,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==