Ú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 <- "Adam" # definovanie obsahu textovej premennej first
last <- "Michalec" # 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("košeľa", "sako", "nohavice", sep = ",") # spojenie textov s oddelovacom ,
first; last; full; full_nospace; csv_line # bodkočiarka tu nahradzuje odskok na novy riadok
[1] "Adam"
[1] "Michalec"
[1] "Adam Michalec"
[1] "AdamMichalec"
[1] "košeľa,sako,nohavice"
Dĺžka textového reťazca, podreťazec
x <- "Mám rád leto"
nchar(x) # počet znakov v retazci "Mám rád leto"
[1] 12
substr(x, 5, 12) # podreťazec od 5. do 12. znaku
[1] "rád leto"
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.
Matice
Vytvorenie matíc
m <- matrix(1:7, nrow = 5, ncol = 3) # hodnoty sú zadavane po stlpcoch
m_byrow <- matrix(1:7, nrow = 3, byrow = TRUE) # hodnoty su zadavane po riadkoch
m; m_byrow
[,1] [,2] [,3]
[1,] 1 6 4
[2,] 2 7 5
[3,] 3 1 6
[4,] 4 2 7
[5,] 5 3 1
[,1] [,2] [,3]
[1,] 1 2 3
[2,] 4 5 6
[3,] 7 1 2
Rozmery matice
[1] 5 3
[,1] [,2] [,3]
[1,] 1 6 4
[2,] 2 7 5
[3,] 3 1 6
[4,] 4 2 7
[5,] 5 3 1
Adresovanie prvkov matice
m[2, 2] # riadok 1, stlpec 2
[1] 7
m[ , 1] # vsetky prvky v tretom stlpci - vysledok matica 3x1
[1] 1 2 3 4 5
m[3, ] # vsetky prvky v druhom riadku - vysledok matica 1*3
[1] 3 1 6
m[2:2, 3:3] # podmatica tvorena riadkami 1, 2 a stlpcami 2, 3
[1] 5
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(2:3, 3:5) # - po stlpcoch
D <- rbind(1:2, 4:6) # - po riadkoch
C; D
[,1] [,2]
[1,] 2 3
[2,] 3 4
[3,] 2 5
[,1] [,2] [,3]
[1,] 1 2 1
[2,] 4 5 6
Vypočítanie zvolenej štatistiky po riadkoch (stĺpcoch) matice
M <- matrix(1:7, nrow = 2)
M
[,1] [,2] [,3] [,4]
[1,] 1 3 5 7
[2,] 2 4 6 1
apply(M, 1, sum) # suma po riadkoch
[1] 16 13
apply(M, 2, mean) # priemery po stĺpcoch
[1] 1.5 3.5 5.5 4.0
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:30, nrow = 5, byrow = TRUE)
colSums(M2)
[1] 65 70 75 80 85 90
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1205 1270 1335 1400 1465 1530
[2,] 1270 1340 1410 1480 1550 1620
[3,] 1335 1410 1485 1560 1635 1710
[4,] 1400 1480 1560 1640 1720 1800
[5,] 1465 1550 1635 1720 1805 1890
[6,] 1530 1620 1710 1800 1890 1980
LS0tCnRpdGxlOiAiWsOha2xhZG7DqSBvcGVyw6FjaWUgdiBSIgphdXRob3I6ICJBZGFtIE1pY2hhbGVjICA8YnI+CihzIHZ5dcW+aXTDrW0gQ2hhdEdQVCkiCmRhdGU6ICJPa3TDs2JlciAyMDI1IgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdGhlbWU6IHVuaXRlZAogICAgaGlnaGxpZ2h0OiB0YW5nbwplZGl0b3Jfb3B0aW9uczogCiAgbWFya2Rvd246IAogICAgd3JhcDogNzIKLS0tCgojIEdsb2LDoWxuZSBuYXN0YXZlbmllIENodW5rb3YKClYgbmnFvsWhaWUgdXZlZGVub20gQ2h1bmt1IGplIHVyb2JlbsOpIHrDoWtsYWRuw6kgZ2xvYsOhbG5lIG5hc3RhdmVuaWUgQ2h1bmtvdiB2IGNlbG9tIE5vdGVib29rdS4gCgotICoqZWNobyoqIG5hc3RhdnVqZSwgxI1pIGNoY2VtZSB2IE5vdGVib29rdSB2eXBpc292YcWlIGplZG5vdGxpdsOpIGvDs2R5IFIKLSAqKm1lc3NhZ2UqKiBqZSBuYXN0YXZlbsO9IG5hICpGQUxTRSosIMSNbyB6bmFtZW7DoSwgxb5lIHNhIGJ1ZMO6IHBvdGzDocSNYcWlIHByYWNvdm7DqSB2w71zdHVweSB6IFIsIHQuai4gbmFwcsOta2xhZCB2w71zbGVkb2sgb3R2w6FyYW5pYSBrbmnFvm7DrWMsIGEgbmlla3RvcsOpIGluw6kgdsO9c3R1cHksIGt0b3LDqSBhbGUgcHJlIGNlbGtvdsO9IE5vdGVib29rIG5lbWFqw7ogdGFrbWVyIMW+aWFkZW4gdsO9em5hbSBhIHPDuiB2aG9kbsOpIHNrw7RyIHByaSBsYWRlbsOtIGvDs2Rvdi4KLSAqKndhcm5pbmcqKiBuYXN0YXZlbsO9IG5hIEZBTFNFIHBvdGzDocSNYSB6b2JyYXplbmllIGNoeWJvdsO9Y2ggaGzDocWhb2sKCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1UUlVFLGVjaG89VFJVRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVjaG8gPSBUUlVFLAogIG1lc3NhZ2UgPSBGQUxTRSwKICB3YXJuaW5nID0gRkFMU0UKKQpgYGAKCiMgw5p2b2QgayB6w6FrbGFkbsO9bSBvcGVyw6FjacOhbSB2IFIKClRlbnRvIG5vdGVib29rIGRlbW9uxaF0cnVqZSAqKnrDoWtsYWRuw6kgb3BlcsOhY2llKiogdiBqYXp5a3UgUiBzbzoKCi0gc2thbMOhcm55bWkgxI3DrXNsYW1pICh0LmouIDEgxI3DrXNsbyksCi0gdGV4dG92w71taSAoem5ha292w71taSkgcmXFpWF6Y2FtaSwKLSBsb2dpY2vDvW1pIChib29sb3Zza8O9bWkpIGhvZG5vdGFtaSBhIHByZW1lbm7DvW1pLAotIChudW1lcmlja8O9bWkpIHZla3Rvcm1pLAotIG1hdGljYW1pLgoKVGFtLCBrZGUgamUgdG8gdcW+aXRvxI1uw6ksIHPDuiB6YWhybnV0w6kgbWFsw6kgY3ZpxI1lbmlhLgoKLS0tCgojIFNrYWzDoXJlIChqZWRub8SNw61zZWxuw6kgaG9kbm90eSkKCiMjIE51bWVyaWNrw6kgc2thbMOhcmUKCmBgYHtyfQojIFByaXJhZGVuaWUga29uxaF0YW50eSBkbyBwcmVtZW5uZWoKYSA8LSA4CmIgPC0gNAoKIyBBcml0aG1ldGljCnN1bV9hYiAgICAgIDwtIGEgKyBiICAgICAgICAjIHN1Y2V0CmRpZmZfYWIgICAgIDwtIGEgLSBiICAgICAgICAjIHJvemRpZWwKcHJvZF9hYiAgICAgPC0gYSAqIGIgICAgICAgICMgbsOhc29iZW5pZQpxdW90X2FiICAgICA8LSBhIC8gYiAgICAgICAgIyBkZWxlbmllCnBvd2VyX2FiICAgIDwtIGEgXiBiICAgICAgICAjIHVtb2PFiG92YW5pZQptb2RfYWIgICAgICA8LSBhICUlIDMgICAgICAgIyB6Ynl0b2sgcG8gZGVsZW7DrSB0cm9taSAodHp2IG1vZHVsbykKCgojIFJvdW5kaW5nCnJvdW5kX2IgICA8LSByb3VuZChiKSAgICAgICAjIHphb2tydWhsb3ZhbmllIHNtZXJvbSBrIG5hamJsaXpzaWVtdSBjZWxlbXUgY2lzbHUKY2VpbF9iICAgIDwtIGNlaWxpbmcoYikgICAgICMgbmFqYmxpenNpZSB2eXNzaWUgY2VsZSBjaXNsbwpmbG9vcl9iICAgPC0gZmxvb3IoYikgICAgICAgIyBuYWpibGl6c2llIG5penNpZSBjZWxlIGNpc2xvCgphOyBiCnN1bV9hYjsgZGlmZl9hYjsgcHJvZF9hYjsgcXVvdF9hYjsgcG93ZXJfYWI7IG1vZF9hYjsKcm91bmRfYjsgY2VpbF9iOyBmbG9vcl9iCmBgYAoKKipQb3puw6Fta3kqKgoKLSBgXmAgb3BlcsOhdG9yIHVtb2PFiG92YW5pYS4KLSBgJSVgIGplIG1vZHVsbywgdGVkYSB6Ynl0b2sgcG8gZGVsZW7DrSwgCi0gYHJvdW5kKHgsIGRpZ2l0cyA9IDApYCB6YW9rcsO6aMS+b3ZhbmllIG5hIHVyxI1pdMO9IHBvxI1ldCBkZXNhdGlubsO9Y2ggbWllc3QgKGRpZ2l0cz0pLiBhayBkaWdpdHMgPSAwLCBwb3RvbSBpZGUgbyBjZWxvxI3DrXNlbG7DqSB6YW9rcsO6aMS+b3ZhbmllCgoKIyMgTWFsw6kgY3ZpxI1lbmllCgo+IFZ5cG/EjcOtdGFqdGU6CgokJFxmcmFjeyg1OF4zLTQ1KX17MTB9JCQKCmBgYHtyfQooNTheMyAtIDQ1KSAvIDEwCmBgYAoKLS0tCgojIFRleHQgCgojIyBWeXR2w6FyYW5pZSB0ZXh0b3bDvW1pIHByZW1lbm7DvW1pIGEgcHLDoWNhIHMgbmltaQoKYGBge3J9CmZpcnN0IDwtICJBZGFtIiAgICAgICAgICAgICAgICAgICAgICAgIyBkZWZpbm92YW5pZSBvYnNhaHUgdGV4dG92ZWogcHJlbWVubmVqIGZpcnN0Cmxhc3QgIDwtICJNaWNoYWxlYyIgICAgICAgICAgICAgICAgICAgICAgICAgICMgZGVmaW5vdmFuaWUgb2JzYWh1IHRleHQuIHByZW1lbm5laiBsYXN0CmZ1bGwgIDwtIHBhc3RlKGZpcnN0LCBsYXN0KSAgICAgICAgICAgICAgICMgc3BvamVuaWUgZHZvY2ggdGV4dC4gcHJlbWVubnljaCBkbyBqZWRuZWogKHMgbWVkemVyb3UpCmZ1bGxfbm9zcGFjZSA8LSBwYXN0ZTAoZmlyc3QsIGxhc3QpICAgICAgICMgc3BvamVuaWUgYmV6IG1lZHplcnkKY3N2X2xpbmUgPC0gcGFzdGUoImtvxaFlxL5hIiwgInNha28iLCAibm9oYXZpY2UiLCBzZXAgPSAiLCIpICAjIHNwb2plbmllIHRleHRvdiBzIG9kZGVsb3ZhY29tICwKZmlyc3Q7IGxhc3Q7IGZ1bGw7IGZ1bGxfbm9zcGFjZTsgY3N2X2xpbmUgICAjIGJvZGtvxI1pYXJrYSB0dSBuYWhyYWR6dWplIG9kc2tvayBuYSBub3Z5IHJpYWRvayAKYGBgCgojIyBExLrFvmthIHRleHRvdsOpaG8gcmXFpWF6Y2EsIHBvZHJlxaVhemVjCgpgYGB7cn0KeCA8LSAiTcOhbSByw6FkIGxldG8iCm5jaGFyKHgpICAgICAgICAgICAgICAgICAjIHBvxI1ldCB6bmFrb3YgIHYgcmV0YXpjaSAiTcOhbSByw6FkIGxldG8iCnN1YnN0cih4LCA1LCAxMikgICAgICAgICAgIyBwb2RyZcWlYXplYyBvZCA1LiBkbyAxMi4gem5ha3UKYGBgCgoKPiBUaXA6IEtuacW+bmljYSAqKnN0cmluZ3IqKiBtbm9ow6kgemF1asOtbWF2w6kgbW/Fvm5vc3RpIHByw6FjZSBzIHRleHRhbWksIGFsZSBpbXBsaWNpdG7DqSBrbmnFvm5pY2UgUiBwb2tyw712YWrDuiB2w6TEjcWhaW51IGJlxb5uw71jaCBwb3RyaWViIHDDoWNlIHMgdGV4dGFtaS4KCi0tLQoKIyBMb2dpY2vDqSAoYm9vbG92c2vDqSkgaG9kbm90eSBhIHByZW1lbm7DqQoKIyMgWsOha2xhZHkKCmBgYHtyfQpwIDwtIFRSVUUKcSA8LSBGQUxTRQohcCAgICAgICAgICAgICAgICAgIyBOT1QKcCAmIHEgICAgICAgICAgICAgICMgQU5ECnAgfCBxICAgICAgICAgICAgICAjIE9SCnhvcihwLCBxKSAgICAgICAgICAjIGV4Y2x1c2l2ZSBPUiAtIHBsYXTDrSBsZW4gamVkbm8geiBwLGFsZWJvIHEKYGBgCgojIyBMb2dpY2vDvSB2w71zbGVkb2sgcG9yb3Zuw6F2YW5pYQoKYGBge3J9CjkgPCAxMAo5ID49IDkKInNha28iID09ICJzYWtvIgoic2FrbyIgIT0gImtvxaFlxL5hIiAgICMgdnlrcmljbmlrIGplIHR1IHYgem15c2xlIG5lZ2FjaWUuIE5hcHIuOiAgICE9LCAhPiwgITwsICFUUlVFCiFUUlVFCmBgYAoKIyMgWmxvxb5pdGVqxaFpZSBsb2dpY2vDqSBvcGVyw6FjaWUKCmBgYHtyfQp4IDwtIDI1CnggPiAyMCAmIHggPCAzMCAgICAgICMgYSBzdWNhc25lIC0gbG9naWNreSBwcmllbmlrIChzdWNpbikKeCA8IDAgfCB4ID4gMTAwICAgICAjIGFsZWJvIC0gbG9naWNrZSB6amVkbm90ZW5pZSAoc3VjZXQpCiAgICAgICAgICAgICAgICAgICAgIyBwcmkgemxveml0ZWpzaWNoIHZ6dGFob2NoIHBvdXppdmFqdGUgemF0dm9ya3kgKCkKYGBgCgojIyBabHXEjW92YW5pZSB2aWFjZXLDvWNoIGxvZy4gcHJlbWVubsO9Y2ggZG8gdmVrdG9yYQoKYGBge3J9CnZhbHMgPC0gYyhUUlVFLCBGQUxTRSwgVFJVRSwgVFJVRSkgICAjIGRlZmluaWNpYSB2ZWt0b3JhIHMgbG9naWNreW1pIGhvZG5vdGFtaQpgYGAKCi0tLQoKIyBOdW1lcmlja8OpIHZla3RvcnkKCiMjIEdlbmVyb3ZhbmllIHZla3Rvcm92CgpgYGB7cn0KdjEgPC0gYygyLCA0LCA2LCA4KQp2MiA8LSAxOjUgICAgICAgICAgICAgICAgICAjIHBvc3R1cG5vc3QgMSwyLDMsNCw1CnYzIDwtIHNlcShmcm9tID0gMCwgdG8gPSAxLCBieSA9IDAuMjUpICAjIHBvc3R1cG5vc3QgcyBrcm9rb20gMC4yNQp2NCA8LSByZXAoMywgdGltZXMgPSA1KSAgICAjIDMsMywzLDMsMyAgIyA1IGNsZW5uYSBwb3N0dXBub3N0IHRyb2phawp2NSA8LSBydW5pZig1KSAgICAgICAgICAgICAjIGdlbmVyb3ZhbmllIHJvdm5vbWVybmUgcm96ZGVsZW55Y2ggcHJlbWVubnljaCB2IGludGVydmFsZSBbMCwxXQp2NiA8LSBybm9ybSg1KSAgICAgICAgICAgICAjIGdlbmVyb3ZhbmllIG5vcm1hbG5lIHJvemRlbGVueWNoIHByZW1lbm55Y2gKdjE7IHYyOyB2MzsgdjQ7IHY1CmBgYAoKIyMgQXJpdG1ldGlja8OpIG9wZXLDoWNpZSBzIHZla3Rvcm1pCgpgYGB7cn0KdiA8LSBjKDUsIDYsIDcsIDgsIDksIDEwKQp2ICsgNSAgICAgICAgICAgICMga2F6ZHkgcHJ2b2sgdmVrdG9yYSB6dmFjc2ltZSBvIDEwCnYgKiAzICAgICAgICAgICAgIyBrYXpkeSBwcnZvayB2ZWt0b3JhIHByZW5hc29iaW1lIDIKKHYgKyAxKSAvIDQKZXhwKHYpICAgICAgICAgICAjIGV4cG9uZW5jaWFsbmEgZnVua2NpYSB6IGthemRlaG8gcHJ2a3UgdmVrdG9yYQpzdW0oYygxLDIsMyksYygxLDEsMSkpICAgICAgICAgICMgc2thbGFybnkgc3VjaW4gLSB2eXNsZWRvayBqZSBza2FsYXIKY3Jvc3Nwcm9kKGMoMSwyLDMpLGMoMSwxLDEpKSAgICAjIHNrYWxhcm55IHN1Y2luIC0gdnlzbGVkb2sgamUgbWF0aWNhIDF4MQpjKDEsMiwzKSpjKDEsMSwxKSAgICAgICAgICAgICAgICMgSGFkYW1hcmRvdiBzdWNpbiAoc3VjaW4gem9kcG92ZWRhanVjaWNoIHBydmtvdiB2ZWt0b3JhKQpgYGAKCiMjIE1hdGVtYXRpY2vDqSBvcGVyw6FjaWUgcyAyIHZla3Rvcm1pIHJvdm5ha8OpaG8gcm96bWVydQoKYGBge3J9Cmxlbmd0aChjKDUsNiw3LDgsOSkpCmxlbmd0aCh2KSAgICAgICAgICAgICN2ZWt0b3IgdjUgamUgZGVmaW5vdmFueSB2eXNzaWUKYyg1LDYsNyw4LDkpICsgdiAgICAgIyBwb3pvciwgb2JhIHZla3RvcnkgbXVzaWEgbWF0IHJvdm5ha3kgcm96bWVyCmBgYAoKIyMgSW5kZXhvdmFuaWUgYSB2w71iZXIgbmlla3RvcnljaCBwcnZrb3YgdmVrdG9yYQoKYGBge3J9CnggPC0gYyg2LCAxMywgNCwgMTksIDgsIDEsIDIyKQp4WzFdICAgICAgICAgICAjIGluZGV4b3ZhbmllIC0gbm92eSBqZWRuby1wcnZrb3Z5IHZla3RvciAtIHBydnkgcHJ2b2sgdmVrdG9yYSB4CnhbMjo0XSAgICAgICAgICMgbm92eSB2ZWt0b3IgcyBkcnVoeW0gYXogc3R2cnR5bSBwcnZrb20gdmVrdG9yYSB4CnhbLTFdICAgICAgICAgICMgbm92eSB2ZWt0b3IgLSB2c2V0a3kgcHJ2a3kgdmVrdG9yYSB4IG9rcmVtIHBydsOpaG8KeFt4ID4gMTBdICAgICAgIyBub3Z5IHZla3RvciBkZWZpbm92YW55IHBydmthbWkgeCB2YWNzaW1pIGFrbyAxMApgYGAKCiMjIFByw6FjYSBzIGNow71iYWrDumNpbWkgaG9kbm90YW1pCgpgYGB7cn0KeSA8LSBjKDUsIE5BLCAxMCwgTkEsIDIwKQppcy5uYSh5KQptZWFuKHkpICAgICAgICAgICAgICAgICAjIE5BCm1lYW4oeSwgbmEucm0gPSBUUlVFKSAgICMgcmVtb3ZlIE5BcwpgYGAKCiMjIFrDoWtsYWRuw6kgxaF0YXRpc3Rpa3kgYSB1c3BvcmlhZGFuaWUgcHJ2a292IHZla3RvcmEgcG9kxL5hIHZlxL5rb3N0aQoKYGBge3J9CnogPC0gYygxMDAsIDQzLCAyMCwgMTgsIDYyKQptZWFuKHopICAgICAgICAgICAgICAgICAjIHByaWVtZXJuYSBob2Rub3RhCnNkKHopICAgICAgICAgICAgICAgICAgIyBzdGFuZGFyZG5hIG9kY2h5bGthCm1heCh6KSAgICAgICAgICAgICAgICAgICMgbWF4aW1hbG5hIGhvZG5vdGEKc3VtbWFyeSh6KSAgICAgICAgICAgICAgIyByeWNobHkgcHJlaGxhZCB6YWtsYWRueWNoIHN0YXRpc3RpayBvIHZla3RvcmUKc29ydCh6KSAgICAgICAgICAgICAgICAgIyByYXN0dWNlIHVzcG9yaWFkYW5pZSAKc29ydCh6LCBkZWNyZWFzaW5nID0gVFJVRSkgICMga2xlc2FqdWNlCmBgYAoKIyMgTWFsw6kgY3ZpxI1lbmllCj4gVnl0dm9ydGUgdmVrdG9yIGB3YCBzIMSNw61zbGFtaSAxLi4yMCBhIHZ5cG/EjcOtdGFqdGUgc3VtdSB2xaFldGvDvWNoIHDDoXJueWNoIMSNw61zZWwuCgpgYGB7cn0KdyA8LSAxOjMwCnN1bSh3W3cgJSUgMTQgPT0gMl0pCmBgYAoKLS0tCgojIE1hdGljZQoKIyMgVnl0dm9yZW5pZSBtYXTDrWMKCmBgYHtyfQptIDwtIG1hdHJpeCgxOjcsIG5yb3cgPSA1LCBuY29sID0gMykgICAgICAgICAgICAjIGhvZG5vdHkgc8O6IHphZGF2YW5lIHBvIHN0bHBjb2NoCm1fYnlyb3cgPC0gbWF0cml4KDE6NywgbnJvdyA9IDMsIGJ5cm93ID0gVFJVRSkgICMgaG9kbm90eSBzdSB6YWRhdmFuZSBwbyByaWFka29jaAptOyBtX2J5cm93CmBgYAoKIyMgUm96bWVyeSBtYXRpY2UKCmBgYHtyfQpkaW0obSkgICAgICAgICAgICAgICAgICAgIyAocm93cywgY29scykKbQpgYGAKCiMjIEFkcmVzb3ZhbmllIHBydmtvdiBtYXRpY2UKCmBgYHtyfQptWzIsIDJdICAgICAgIyByaWFkb2sgMSwgc3RscGVjIDIKbVsgLCAxXSAgICAgICMgdnNldGt5IHBydmt5IHYgdHJldG9tIHN0bHBjaSAtIHZ5c2xlZG9rIG1hdGljYSAzeDEKbVszLCBdICAgICAgICMgdnNldGt5IHBydmt5IHYgZHJ1aG9tIHJpYWRrdSAtIHZ5c2xlZG9rIG1hdGljYSAxKjMKbVsyOjIsIDM6M10gICMgcG9kbWF0aWNhIHR2b3JlbmEgcmlhZGthbWkgMSwgMiBhIHN0bHBjYW1pIDIsIDMKYGBgCgojIyBNYXRpY292w6kgb3BlcsOhY2llCgpgYGB7cn0KQSA8LSBtYXRyaXgoYygxLDIsMyw0KSwgbnJvdyA9IDIpCkIgPC0gbWF0cml4KGMoNSw2LDcsOCksIG5yb3cgPSAyKQoKQSArIEIgICAgICAgICMgc2NpdGFuaWUgbWF0aWMKQSAqIEIgICAgICAgICMgSGFkYW1hcmQgcHJvZHVjdCAtIG5hc29iZW5pZSBwbyB6b2Rwb3ZlZGFqdWNpY2ggcHJ2a29jaApBICUqJSBCICAgICAgIyBuYXNvYmVuaWUgbWF0aWMKdChBKSAgICAgICAgICMgdHJhbnNwb3ppY2lhIG1hdGljZSBBIC0gdnltZW5hIHJpYWRrb3YgYSBzdGxwY292CmRldChBKSAgICAgICAjIGRldGVybWluYW50IG1hdGljZQpzb2x2ZShBKSAgICAgIyBpbnZlcnppYSBtYXRpY2UgKGFrIGplIG1hdGljYSByZWd1bGFybmEgLSB0ZWRhIGludmVyemlhIHNhIGRhIHNwb2NpdGF0KQpgYGAKCiMjIFpsdcSNb3ZhbmllIHZla3Rvcm92IGRvIG1hdMOtYyAKCmBgYHtyfQpDIDwtIGNiaW5kKDI6MywgMzo1KSAgICMgIC0gcG8gc3RscGNvY2ggCkQgPC0gcmJpbmQoMToyLCA0OjYpICAgIyAgLSBwbyByaWFka29jaCAKQzsgRApgYGAKCiMjIFZ5cG/EjcOtdGFuaWUgenZvbGVuZWogxaF0YXRpc3Rpa3kgcG8gcmlhZGtvY2ggKHN0xLpwY29jaCkgbWF0aWNlCgpgYGB7cn0KTSA8LSBtYXRyaXgoMTo3LCBucm93ID0gMikKTQphcHBseShNLCAxLCBzdW0pICAgIyBzdW1hIHBvIHJpYWRrb2NoCmFwcGx5KE0sIDIsIG1lYW4pICAjIHByaWVtZXJ5IHBvIHN0xLpwY29jaApgYGAKCiMjIE1hbMOpIGN2acSNZW5pZQoKPiBWeXR2b3J0ZSBtYXRpY3UgNXg1IHMgaG9kbm90YW1pIHBvIHJpYWRrb2NoIDEuLjI1LCB2eXBvxI3DrXRhanRlIHN0xLpwY292w6kgc3VteSBhIHPDusSNaW4gbWF0w61jIFwoTV50IE1cKS4KCmBgYHtyfQpNMiA8LSBtYXRyaXgoMTozMCwgbnJvdyA9IDUsIGJ5cm93ID0gVFJVRSkKY29sU3VtcyhNMikKdChNMikgJSolIE0yCmBgYAoKLS0tCgoKCgo=