Ú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.
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
LS0tCnRpdGxlOiAiWsOha2xhZG7DqSBvcGVyw6FjaWUgdiBSIgphdXRob3I6ICJGaWxpcCBKdXJrw6HEjWVrICA8YnI+CihzIHZ5dcW+aXTDrW0gQ2hhdEdQVCkiCmRhdGU6ICJPa3TDs2JlciAyMDI1IgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdGhlbWU6IHVuaXRlZAogICAgaGlnaGxpZ2h0OiB0YW5nbwplZGl0b3Jfb3B0aW9uczogCiAgbWFya2Rvd246IAogICAgd3JhcDogNzIKLS0tCgojIEdsb2LDoWxuZSBuYXN0YXZlbmllIENodW5rb3YKClYgbmnFvsWhaWUgdXZlZGVub20gQ2h1bmt1IGplIHVyb2JlbsOpIHrDoWtsYWRuw6kgZ2xvYsOhbG5lIG5hc3RhdmVuaWUgQ2h1bmtvdiB2IGNlbG9tIE5vdGVib29rdS4gCgotICoqZWNobyoqIG5hc3RhdnVqZSwgxI1pIGNoY2VtZSB2IE5vdGVib29rdSB2eXBpc292YcWlIGplZG5vdGxpdsOpIGvDs2R5IFIKLSAqKm1lc3NhZ2UqKiBqZSBuYXN0YXZlbsO9IG5hICpGQUxTRSosIMSNbyB6bmFtZW7DoSwgxb5lIHNhIGJ1ZMO6IHBvdGzDocSNYcWlIHByYWNvdm7DqSB2w71zdHVweSB6IFIsIHQuai4gbmFwcsOta2xhZCB2w71zbGVkb2sgb3R2w6FyYW5pYSBrbmnFvm7DrWMsIGEgbmlla3RvcsOpIGluw6kgdsO9c3R1cHksIGt0b3LDqSBhbGUgcHJlIGNlbGtvdsO9IE5vdGVib29rIG5lbWFqw7ogdGFrbWVyIMW+aWFkZW4gdsO9em5hbSBhIHPDuiB2aG9kbsOpIHNrw7RyIHByaSBsYWRlbsOtIGvDs2Rvdi4KLSAqKndhcm5pbmcqKiBuYXN0YXZlbsO9IG5hIEZBTFNFIHBvdGzDocSNYSB6b2JyYXplbmllIGNoeWJvdsO9Y2ggaGzDocWhb2sKCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1UUlVFLGVjaG89VFJVRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVjaG8gPSBUUlVFLAogIG1lc3NhZ2UgPSBGQUxTRSwKICB3YXJuaW5nID0gRkFMU0UKKQpgYGAKCiMgw5p2b2QgayB6w6FrbGFkbsO9bSBvcGVyw6FjacOhbSB2IFIKClRlbnRvIG5vdGVib29rIGRlbW9uxaF0cnVqZSAqKnrDoWtsYWRuw6kgb3BlcsOhY2llKiogdiBqYXp5a3UgUiBzbzoKCi0gc2thbMOhcm55bWkgxI3DrXNsYW1pICh0LmouIDEgxI3DrXNsbyksCi0gdGV4dG92w71taSAoem5ha292w71taSkgcmXFpWF6Y2FtaSwKLSBsb2dpY2vDvW1pIChib29sb3Zza8O9bWkpIGhvZG5vdGFtaSBhIHByZW1lbm7DvW1pLAotIChudW1lcmlja8O9bWkpIHZla3Rvcm1pLAotIG1hdGljYW1pLgoKVGFtLCBrZGUgamUgdG8gdcW+aXRvxI1uw6ksIHPDuiB6YWhybnV0w6kgbWFsw6kgY3ZpxI1lbmlhLgoKLS0tCgojIFNrYWzDoXJlIChtb2RpZmlrb3ZhbsOpKSAoamVkbm/EjcOtc2VsbsOpIGhvZG5vdHkpCgojIyBOdW1lcmlja8OpIHNrYWzDoXJlCgpgYGB7cn0KICAjIFByaXJhZGVuaWUga29uxaF0YW50eSBkbyBwcmVtZW5uZWoKeDEgPC0gOAp4MiA8LSAzLjY1CgogICMgQXJpdGhtZXRpYyAodXByLikKc3VtX2FiICAgICAgPC0geDEgKyB4MiAgIyBzdWNldCAodXByLikKZGlmZl9hYiAgICAgPC0geDEgLSB4MiAgIyByb3pkaWVsICh1cHIuKQpwcm9kX2FiICAgICA8LSB4MSAqIHgyICAjIG7DoXNvYmVuaWUgKHVwci4pCnF1b3RfYWIgICAgIDwtIHgxIC8geDIgICMgZGVsZW5pZSAodXByLikKcG93ZXJfYWIgICAgPC0geDEgXiB4MiAgIyB1bW9jxYhvdmFuaWUgKHVwci4pCm1vZF9hYiAgICAgIDwtIHgxICUlIDQgICMgemJ5dG9rIHBvIGRlbGVuw60gdHJvbWkgKHR6diBtb2R1bG8pCgoKICAjIFJvdW5kaW5nICh1cHIuKQpyb3VuZF9iICAgPC0gcm91bmQoeDIpICAjIHphb2tydWhsb3ZhbmllIHNtZXJvbSBrIG5hamJsaXpzaWVtdSBjZWxlbXUgY2lzbHUKY2VpbF9iICAgIDwtIGNlaWxpbmcoeDIpICAjIG5hamJsaXpzaWUgdnlzc2llIGNlbGUgY2lzbG8KZmxvb3JfYiAgIDwtIGZsb29yKHgyKSAgIyBuYWpibGl6c2llIG5penNpZSBjZWxlIGNpc2xvCgp4MTsgeDIKc3VtX2FiOyBkaWZmX2FiOyBwcm9kX2FiOyBxdW90X2FiOyBwb3dlcl9hYjsgbW9kX2FiCnJvdW5kX2I7IGNlaWxfYjsgZmxvb3JfYgpgYGAKCioqUG96bsOhbWt5KioKCi0gYF5gIG9wZXLDoXRvciB1bW9jxYhvdmFuaWEuCi0gYCUlYCBqZSBtb2R1bG8sIHRlZGEgemJ5dG9rIHBvIGRlbGVuw60sIAotIGByb3VuZCh4LCBkaWdpdHMgPSAwKWAgemFva3LDumjEvm92YW5pZSBuYSB1csSNaXTDvSBwb8SNZXQgZGVzYXRpbm7DvWNoIG1pZXN0IChkaWdpdHM9KS4gYWsgZGlnaXRzID0gMCwgcG90b20gaWRlIG8gY2Vsb8SNw61zZWxuw6kgemFva3LDumjEvm92YW5pZQoKCiMjIE1hbMOpIGN2acSNZW5pZQoKPiBWeXBvxI3DrXRhanRlOgoKJCRcZnJhY3soMTVeMi00KX17N30kJAoKYGBge3J9CigxNl4zIC0gNSkgLyA4CmBgYAoKLS0tCgojIFRleHQgCgojIyBWeXR2w6FyYW5pZSB0ZXh0b3bDvW1pIHByZW1lbm7DvW1pIGEgcHLDoWNhIHMgbmltaQoKYGBge3J9CmZpcnN0IDwtICJGaWxpcCIgICMgZGVmaW5vdmFuaWUgb2JzYWh1IHRleHRvdmVqIHByZW1lbm5laiBmaXJzdApsYXN0ICA8LSAiSnVya8OhxI1layIgICMgZGVmaW5vdmFuaWUgb2JzYWh1IHRleHQgKHVwcmF2ZW7DvSkuIHByZW1lbm5laiBsYXN0CmZ1bGwgIDwtIHBhc3RlKGZpcnN0LCBsYXN0KSAgIyBzcG9qZW5pZSBkdm9jaCB0ZXh0ICh1cHJhdmVuw70pLiBwcmVtZW5ueWNoIGRvIGplZG5laiAocyBtZWR6ZXJvdSkKZnVsbF9ub3NwYWNlIDwtIHBhc3RlMChmaXJzdCwgbGFzdCkgICMgc3BvamVuaWUgYmV6IG1lZHplcnkKY3N2X2xpbmUgPC0gcGFzdGUoInBlcyIsICJtYcSNa2EiLCAia2HEjWthIiwgc2VwID0gIiwiKSAgIyBzcG9qZW5pZSB0ZXh0b3YgcyBvZGRlbG92YWNvbSAsCmZpcnN0OyBsYXN0OyBmdWxsOyBmdWxsX25vc3BhY2U7IGNzdl9saW5lICAjIGJvZGtvxI1pYXJrYSB0dSBuYWhyYWR6dWplIG9kc2tvayBuYSBub3Z5IHJpYWRvawpgYGAKCiMjIETEusW+a2EgdGV4dG92w6lobyByZcWlYXpjYSwgcG9kcmXFpWF6ZWMKCmBgYHtyfQp4IDwtICJPaCB5ZWFoISIKbmNoYXIoeCkgICMgY291bnQgem5ha292ICB2IHJldGF6Y2kgIk9oIHllYWghIgpzdWJzdHIoeCwgMiwgNikgICMgcG9kcmXFpWF6ZWMgb2QgMS4gZG8gNS4gem5ha3UKYGBgCgoKPiBUaXA6IEtuacW+bmljYSAqKnN0cmluZ3IqKiBtbm9ow6kgemF1asOtbWF2w6kgbW/Fvm5vc3RpIHByw6FjZSBzIHRleHRhbWksIGFsZSBpbXBsaWNpdG7DqSBrbmnFvm5pY2UgUiBwb2tyw712YWrDuiB2w6TEjcWhaW51IGJlxb5uw71jaCBwb3RyaWViIHDDoWNlIHMgdGV4dGFtaS4KCi0tLQoKIyBMb2dpY2vDqSAoYm9vbG92c2vDqSkgaG9kbm90eSBhIHByZW1lbm7DqQoKIyMgWsOha2xhZHkKCmBgYHtyfQphIDwtIFRSVUUKYiA8LSBGQUxTRQohYSAgIyBOT1QgKHVwci4pCmEgJiBiICAjIEFORCAodXByLikKYSB8IGIgICMgT1IgKHVwci4pCnhvcihhLCBiKSAgIyBleGNsdXNpdmUgT1IgLSBwbGF0w60gbGVuIGplZG5vIHogcCxhbGVibyBxCmBgYAoKIyMgTG9naWNrw70gdsO9c2xlZG9rIHBvcm92bsOhdmFuaWEKCmBgYHtyfQo0IDwgNgo4ID49IDgKInBlcyIgPT0gInBlcyIKInBlcyIgIT0gIm1hxI1rYSIgICMgdnlrcmljbmlrIGplIHR1IHYgem15c2xlIG5lZ2FjaWUuIE5hcHIuOiAgICE9LCAhPiwgITwsICFUUlVFCiFUUlVFCmBgYAoKIyMgWmxvxb5pdGVqxaFpZSBsb2dpY2vDqSBvcGVyw6FjaWUKCmBgYHtyfQp4IDwtIDExCnggPiA2ICYgeCA8IDIyICAjIGEgc3VjYXNuZSAtIGxvZ2lja3kgcHJpZW5payAoc3VjaW4pCnggPCAxIHwgeCA+IDEwMiAgIyBhbGVibyAtIGxvZ2lja2UgemplZG5vdGVuaWUgKHN1Y2V0KQogICMgcHJpIHpsb3ppdGVqc2ljaCB2enRhaG9jaCBwb3V6aXZhanRlIHphdHZvcmt5ICgpCmBgYAoKIyMgWmx1xI1vdmFuaWUgdmlhY2Vyw71jaCBsb2cuIHByZW1lbm7DvWNoIGRvIHZla3RvcmEKCmBgYHtyfQp2YWxzIDwtIHgzKFRSVUUsIEZBTFNFLCBUUlVFLCBUUlVFKSAgIyBkZWZpbmljaWEgdmVrdG9yYSBzIGxvZ2lja3ltaSBob2Rub3RhbWkKYGBgCgotLS0KCiMgTnVtZXJpY2vDqSB2ZWt0b3J5CgojIyBHZW5lcm92YW5pZSB2ZWt0b3JvdgoKYGBge3J9CnYxIDwtIGMoMywgNSwgNywgOSkKdjIgPC0gMjo2ICAjIHBvc3R1cG5vc3QgMSwyLDMsNCw1CnYzIDwtIHNlcShmcm9tID0gMSwgdG8gPSAyLCBieSA9IDAuNCkgICMgcG9zdHVwbm9zdCBzIGtyb2tvbSAwLjI1CnY0IDwtIHJlcCg0LCB0aW1lcyA9IDYpICAjIDMsMywzLDMsMyAgIyA1IGNsZW5uYSBwb3N0dXBub3N0IHRyb2phawp2NSA8LSBydW5pZig2KSAgIyBnZW5lcm92YW5pZSByb3Zub21lcm5lIHJvemRlbGVueWNoIHByZW1lbm55Y2ggdiBpbnRlcnZhbGUgWzAsMV0KdjYgPC0gcm5vcm0oNikgICMgZ2VuZXJvdmFuaWUgbm9ybWFsbmUgcm96ZGVsZW55Y2ggcHJlbWVubnljaAp2MTsgdjI7IHYzOyB2NDsgdjUKYGBgCgojIyBBcml0bWV0aWNrw6kgb3BlcsOhY2llIHMgdmVrdG9ybWkKCmBgYHtyfQp2IDwtIGMoMiwgMywgNCwgNSkKdiArIDExICAjIGthemR5IHBydm9rIHZla3RvcmEgenZhY3NpbWUgbyAxMAp2ICogMyAgIyBrYXpkeSBwcnZvayB2ZWt0b3JhIHByZW5hc29iaW1lIDIKKHYgKyAyKSAvIDMKZXhwKHYpICAjIGV4cG9uZW5jaWFsbmEgZnVua2NpYSB6IGthemRlaG8gcHJ2a3UgdmVrdG9yYQpzdW0oYygyLDMsNCksYygyLDIsMikpICAjIHNrYWxhcm55IHN1Y2luIC0gdnlzbGVkb2sgamUgc2thbGFyCmNyb3NzcHJvZChjKDIsMyw0KSxjKDIsMiwyKSkgICMgc2thbGFybnkgc3VjaW4gLSB2eXNsZWRvayBqZSBtYXRpY2EgKHVwcmF2ZW7DoSkgMXgxCmMoMiwzLDQpKmMoMiwyLDIpICAjIEhhZGFtYXJkb3Ygc3VjaW4gKHN1Y2luIHpvZHBvdmVkYWp1Y2ljaCBwcnZrb3YgdmVrdG9yYSkKYGBgCgojIyBNYXRlbWF0aWNrw6kgb3BlcsOhY2llIHMgMiB2ZWt0b3JtaSByb3ZuYWvDqWhvIHJvem1lcnUKCmBgYHtyfQpsZW5ndGgoYygyLDMsNCw1LDYpKQpsZW5ndGgodjUpICAjIHZla3RvciAobm92w70pIHY1IGplIGRlZmlub3Zhbnkgdnlzc2llCmMoMiwzLDQsNSw2KSArIHY1ICAjIHBvem9yLCBvYmEgdmVrdG9yeSBtdXNpYSBtYXQgcm92bmFreSByb3ptZXIKYGBgCgojIyBJbmRleG92YW5pZSBhIHbDvWJlciBuaWVrdG9yeWNoIHBydmtvdiB2ZWt0b3JhCgpgYGB7cn0KeCA8LSBjKDYsIDEzLCA0LCAxOSwgOCwgMSwgMjMpCnhbMl0gICMgaW5kZXhvdmFuaWUgLSBub3Z5IGplZG5vLXBydmtvdnkgdmVrdG9yIChub3bDvSkgLSBwcnZ5IHBydm9rIHZla3RvcmEgeAp4WzM6NV0gICMgbm92eSB2ZWt0b3IgKG5vdsO9KSBzIGRydWh5bSBheiBzdHZydHltIHBydmtvbSB2ZWt0b3JhIHgKeFswXSAgIyBub3Z5IHZla3RvciAobm92w70pIC0gdnNldGt5IHBydmt5IHZla3RvcmEgeCBva3JlbSBwcnbDqWhvCnhbeCA+IDExXSAgIyBub3Z5IHZla3RvciAobm92w70pIGRlZmlub3ZhbnkgcHJ2a2FtaSB4IHZhY3NpbWkgYWtvIDEwCndoaWNoKHggPiAxMSkgICMga3RvcmUgcHJ2a3kgem9kcG92ZWRhanUgcG9kbWllbmtlIHZhY3NpZWhvIGFrbyAxMD8KYGBgCgojIyBQcsOhY2EgcyBjaMO9YmFqw7pjaW1pIGhvZG5vdGFtaQoKYGBge3J9CnkgPC0gYygyLCBOQSwgNCwgTkEsIDYpCmlzLm5hKHkpCm1lYW4oeSkgICMgTkEgKHVwci4pCm1lYW4oeSwgbmEucm0gPSBUUlVFKSAgIyByZW1vdmUgTkFzICh1cHIuKQpgYGAKCiMjIFrDoWtsYWRuw6kgxaF0YXRpc3Rpa3kgYSB1c3BvcmlhZGFuaWUgcHJ2a292IHZla3RvcmEgcG9kxL5hIHZlxL5rb3N0aQoKYGBge3J9CnogPC0gYygxMSwgNCwgNiwgOSwgMykKbWVhbih6KSAgIyBwcmllbWVybmEgaG9kbm90YQpzZCh6KSAgIyBzdGFuZGFyZG5hIG9kY2h5bGthCm1heCh6KSAgIyBtYXhpbWFsbmEgaG9kbm90YQpzdW1tYXJ5KHopICAjIHJ5Y2hseSBwcmVobGFkIHpha2xhZG55Y2ggc3RhdGlzdGlrIG8gdmVrdG9yZQpzb3J0KHopICAjIHJhc3R1Y2UgdXNwb3JpYWRhbmllCnNvcnQoeiwgZGVjcmVhc2luZyA9IFRSVUUpICAjIGtsZXNhanVjZSAodXByLikKYGBgCgojIyBNYWzDqSBjdmnEjWVuaWUKPiBWeXR2b3J0ZSB2ZWt0b3IgYHdgIHMgxI3DrXNsYW1pIDEuLjIwIGEgdnlwb8SNw610YWp0ZSBzdW11IHbFoWV0a8O9Y2ggcMOhcm55Y2ggxI3DrXNlbC4KCmBgYHtyfQp3IDwtIDI6MjIKc3VtKHdbdyAlJSAzID09IDFdKQpgYGAKCi0tLQoKIyBNYXRpY2UgKHZhcmnDoWNpYSkKCiMjIFZ5dHZvcmVuaWUgbWF0w61jCgpgYGB7cn0KbSA8LSBtYXRyaXgoMjoxMywgbnJvdyA9IDQsIG5jb2wgPSA1KSAgIyBob2Rub3R5IHPDuiB6YWRhdmFuZSBwbyBzdGxwY29jaAptX2J5cm93IDwtIG1hdHJpeCgyOjEzLCBucm93ID0gNCwgYnlyb3cgPSBUUlVFKSAgIyBob2Rub3R5IHN1IHphZGF2YW5lIHBvIHJpYWRrb2NoCm07IG1fYnlyb3cKYGBgCgojIyBSb3ptZXJ5IG1hdGljZQoKYGBge3J9CmRpbShtKSAgIyAocm93cywgY29scykKbQpgYGAKCiMjIEFkcmVzb3ZhbmllIHBydmtvdiBtYXRpY2UKCmBgYHtyfQptWzIsIDNdICAjIHJpYWRvayAxLCBzdGxwZWMgMgptWyAsIDRdICAjIHZzZXRreSBwcnZreSB2IHRyZXRvbSBzdGxwY2kgLSB2eXNsZWRvayBtYXRpY2EgKHVwcmF2ZW7DoSkgM3gxCm1bMywgXSAgIyB2c2V0a3kgcHJ2a3kgdiBkcnVob20gcmlhZGt1IC0gdnlzbGVkb2sgbWF0aWNhICh1cHJhdmVuw6EpIDEqMwptWzI6MywgMzo0XSAgIyBwb2RtYXRpY2EgdHZvcmVuYSByaWFka2FtaSAxLCAyIGEgc3RscGNhbWkgMiwgMwpgYGAKCiMjIE1hdGljb3bDqSBvcGVyw6FjaWUKCmBgYHtyfQpBIDwtIG1hdHJpeChjKDIsMyw0LDUpLCBucm93ID0gMikKQiA8LSBtYXRyaXgoYyg2LDcsOCw5KSwgbnJvdyA9IDIpCgpBICsgQiAgICAgIyBzY2l0YW5pZSBtYXRpYwpBICogQiAgICAgIyBIYWRhbWFyZCBwcm9kdWN0IC0gbmFzb2JlbmllIHBvIHpvZHBvdmVkYWp1Y2ljaCBwcnZrb2NoCkEgJSolQiAgICMgbmFzb2JlbmllIG1hdGljCnQoQSkgICAgICAjIHRyYW5zcG96aWNpYSBtYXRpY2UgQSAtIHZ5bWVuYSByaWFka292IGEgc3RscGNvdgpkZXQoQSkgICAgIyBkZXRlcm1pbmFudCBtYXRpY2UKc29sdmUoQSkgICMgaW52ZXJ6aWEgbWF0aWNlIChhayBqZSBtYXRpY2EgKHVwcmF2ZW7DoSkgcmVndWxhcm5hIC0gdGVkYSBpbnZlcnppYSBzYSBkYSBzcG9jaXRhdCkKYGBgCgojIyBabHXEjW92YW5pZSB2ZWt0b3JvdiBkbyBtYXTDrWMgCgpgYGB7cn0KQyA8LSBjYmluZCgyOjQsIDU6NykgICMgLSBwbyBzdGxwY29jaApEIDwtIHJiaW5kKDI6NCwgNTo3KSAgIyAtIHBvIHJpYWRrb2NoCkM7IEQKYGBgCgojIyBWeXBvxI3DrXRhbmllIHp2b2xlbmVqIMWhdGF0aXN0aWt5IHBvIHJpYWRrb2NoIChzdMS6cGNvY2gpIG1hdGljZQoKYGBge3J9Ck0gPC0gbWF0cml4KDI6MTAsIG5yb3cgPSA0KQpNCmFwcGx5KE0sIDIsIHN1bSkgICMgc3VtYSBwbyByaWFka29jaAphcHBseShNLCAyLCBtZWFuKSAgIyBwcmllbWVyeSBwbyBzdMS6cGNvY2gKYGBgCgojIyBNYWzDqSBjdmnEjWVuaWUKCj4gVnl0dm9ydGUgbWF0aWN1IDV4NSBzIGhvZG5vdGFtaSBwbyByaWFka29jaCAxLi4yNSwgdnlwb8SNw610YWp0ZSBzdMS6cGNvdsOpIHN1bXkgYSBzw7rEjWluIG1hdMOtYyBcKE1edCBNXCkuCgpgYGB7cn0KTTIgPC0gbWF0cml4KDI6MjcsIG5yb3cgPSA2LCBieXJvdyA9IFRSVUUpCmNvbFN1bXMoTTIpCnQoTTIpICUqJSBNMgpgYGAKCi0tLQoKCgoK