knitr::opts_chunk$set(
  echo = TRUE,
  message = FALSE,
  warning = FALSE
)
set.seed(2025)

Práca s údajmi

Tradičná práca s databázou

Meno <- c("Ela", "Tono", "Ria")
Vek  <- c(10, 11, 9)
Body <- c(83, 96, 74)
udaje <- data.frame(Meno, Vek, Body)
udaje

Základné operácie

udaje$Vek
[1] 10 11  9
mean(udaje$Vek)
[1] 10
udaje[udaje$Meno == "Tono", ]
udaje[3, ]
udaje[, 2:3]
udaje[1, 1]
[1] "Ela"
summary(udaje)
     Meno                Vek            Body      
 Length:3           Min.   : 9.0   Min.   :74.00  
 Class :character   1st Qu.: 9.5   1st Qu.:78.50  
 Mode  :character   Median :10.0   Median :83.00  
                    Mean   :10.0   Mean   :84.33  
                    3rd Qu.:10.5   3rd Qu.:89.50  
                    Max.   :11.0   Max.   :96.00  

Malé cvičenie

Z tabuľky zisti meno študenta s najvyšším počtom Body a vypíš vetu

max_body <- max(udaje$Body)
meno_max <- udaje$Meno[which.max(udaje$Body)]
paste("Najviac bodov má", meno_max, ":", max_body)
[1] "Najviac bodov má Tono : 96"

Pridávanie stĺpcov a riadkov

MaAuto <- c(FALSE, TRUE, FALSE)
udaje <- cbind(udaje, MaAuto)
udaje
novy_riadok <- data.frame(Meno = "Fero", Vek = 12, Body = 88, MaAuto = TRUE)
udaje <- rbind(udaje, novy_riadok)
udaje

Malé cvičenie

Pridaj do tabuľky nového žiaka menom Nina, má 10 rokov, 91 bodov a nemá auto. Keď ju pridáš, vypočítaj medián bodov všetkých žiakov.

udaje <- rbind(udaje, data.frame(Meno = "Nina", Vek = 10, Body = 91, MaAuto = FALSE))
median(udaje$Body)
[1] 88

Tabuľky v prostredí kableExtra

library(knitr)
library(kableExtra)

kable(
  udaje,
  digits = 0,
  align = c("l","c","r","c"),
  caption = "Prehľad žiakov – moje dáta"
) %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed", "responsive"),
    full_width = FALSE,
    position = "center"
  )
Prehľad žiakov – moje dáta
Meno Vek Body MaAuto
Ela 10 83 FALSE
Tono 11 96 TRUE
Ria 9 74 FALSE
Fero 12 88 TRUE
Nina 10 91 FALSE

Malé cvičenie

Z tabuľky si nechaj zobraziť len mená a body. Vytvor z toho peknú tabuľku pomocou kable a nazvi ju „Body podľa mena“.

udaje[, c("Meno", "Body")] %>%
  kable(caption = "Body podľa mena") %>%
  kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE)
Body podľa mena
Meno Body
Ela 83
Tono 96
Ria 74
Fero 88
Nina 91

Tidyverse – moderná práca s údajmi

library(tidyverse)

dplyr – výber a triedenie

udaje %>%
  filter(Body > 80) %>%
  arrange(desc(Body)) %>%
  kable(caption = "Body > 80 – zostupne") %>%
  kable_styling(full_width = FALSE)
Body > 80 – zostupne
Meno Vek Body MaAuto
Tono 11 96 TRUE
Nina 10 91 FALSE
Fero 12 88 TRUE
Ela 10 83 FALSE

Malé cvičenie

Vyber len tých žiakov, ktorí majú aspoň 90 bodov. Zorad ich abecedne podľa mena a nech sa zobrazí len ich stĺpec Meno.

udaje %>%
  filter(Body >= 90) %>%
  arrange(Meno) %>%
  select(Meno) %>%
  kable(caption = "Meno so ≥ 90 bodmi (A–Z)") %>%
  kable_styling(full_width = FALSE)
Meno so ≥ 90 bodmi (A–Z)
Meno
Nina
Tono

Zoskupenie a sumarizácia

udaje %>%
  group_by(MaAuto) %>%
  summarise(
    Priem_Body = mean(Body),
    Pocet = n()
  ) %>%
  kable(
    caption = "Priemerné Body podľa MaAuto",
    col.names = c("Má Auto", "Priemer Body", "Počet"),
    align = "c"
  ) %>%
  kable_styling(full_width = FALSE)
Priemerné Body podľa MaAuto
Má Auto Priemer Body Počet
FALSE 82.66667 3
TRUE 92.00000 2

Malé cvičenie

Zoskup žiakov podľa toho, či majú auto alebo nemajú. Pre každú skupinu vypíš najvyšší počet bodov a priemerný vek.

udaje %>%
  group_by(MaAuto) %>%
  summarise(Max_Body = max(Body), Avg_Vek = mean(Vek)) %>%
  kable(caption = "Max Body a priemerný vek podľa MaAuto") %>%
  kable_styling(full_width = FALSE)
Max Body a priemerný vek podľa MaAuto
MaAuto Max_Body Avg_Vek
FALSE 91 9.666667
TRUE 96 11.500000

Vytváranie novej premennej (mutate + case_when)

udaje %>%
  mutate(
    grade = case_when(
      Body >= 90 ~ "A",
      Body >= 80 ~ "B",
      Body >= 70 ~ "C",
      TRUE ~ "D"
    ),
    VekPoPlnoletosti = pmax(0, Vek - 18)
  ) %>%
  kable(caption = "Známky a VekPoPlnoletosti") %>%
  kable_styling(full_width = FALSE)
Známky a VekPoPlnoletosti
Meno Vek Body MaAuto grade VekPoPlnoletosti
Ela 10 83 FALSE B 0
Tono 11 96 TRUE A 0
Ria 9 74 FALSE C 0
Fero 12 88 TRUE B 0
Nina 10 91 FALSE A 0

Malé cvičenie

Pridaj do tabuľky nový stĺpec Uspech, ktorý bude mať hodnotu TRUE, ak má žiak aspoň 85 bodov, inak FALSE. Potom ukáž prvé štyri riadky tabuľky.

udaje %>%
  mutate(Uspech = Body >= 85) %>%
  head(4) %>%
  kable(caption = "Uspech podľa Body (prvé 4)") %>%
  kable_styling(full_width = FALSE)
Uspech podľa Body (prvé 4)
Meno Vek Body MaAuto Uspech
Ela 10 83 FALSE FALSE
Tono 11 96 TRUE TRUE
Ria 9 74 FALSE FALSE
Fero 12 88 TRUE TRUE

Záverečné cvičenie – demonštrácia na vlastnom príklade

Vytvor rebríček „A-čkári“ – teda tých, ktorí majú 90 a viac bodov. Zorad ich podľa počtu bodov a pridaj stĺpec Poradie, kde 1 = najviac bodov. Zobraz len Meno a Poradie.

udaje %>%
  filter(Body >= 90) %>%
  arrange(desc(Body)) %>%
  mutate(PoradieVBod = row_number()) %>%
  select(Meno, PoradieVBod) %>%
  kable(caption = "A-čkári a ich poradie v bodovom rebríčku") %>%
  kable_styling(full_width = FALSE)
A-čkári a ich poradie v bodovom rebríčku
Meno PoradieVBod
Tono 1
Nina 2

Môj návrh použitia novinky

set.seed(7)
udaje$Mat  <- c(76, 98, 71, 85, 94)
udaje$Slov <- c(88, 91, 69, 90, 92)
udaje$Eng  <- c(79, 95, 75, 86, 90)
udaje

Môj návrh použitia novinky (jednoduché): percentily + rebríček v skupinách

Idea: spravíme percentilové poradie podľa Body (0–100 %) a zároveň rebríček v rámci skupiny MaAuto (kto má/nemá auto). Je to iný pohľad než len „triedenie podľa bodov“ – uvidíš svoje postavenie v celej triede aj v „podskupine“.


library(dplyr)
library(kableExtra)

# 1) Percentil podľa Body (0–100 %)
vysl_percentil <- udaje %>%
  mutate(
    Percentil_Body = round(100 * (rank(Body, ties.method = "min") - 1) / (n() - 1), 1)
  ) %>%
  arrange(desc(Body)) %>%
  select(Meno, Body, Percentil_Body)

kable(vysl_percentil, caption = "Percentilové poradie podľa Body (0–100 %)") %>%
  kable_styling(full_width = FALSE)
Percentilové poradie podľa Body (0–100 %)
Meno Body Percentil_Body
Tono 96 100
Nina 91 75
Fero 88 50
Ela 83 25
Ria 74 0
NA
# 2) Rebríček v rámci skupiny MaAuto (1 = najviac bodov v danej skupine)
vysl_skupiny <- udaje %>%
  group_by(MaAuto) %>%
  arrange(desc(Body), .by_group = TRUE) %>%
  mutate(Poradie_v_skupine = dense_rank(desc(Body))) %>%
  ungroup() %>%
  select(Meno, MaAuto, Body, Poradie_v_skupine)

kable(vysl_skupiny, caption = "Rebríček v rámci skupiny MaAuto") %>%
  kable_styling(full_width = FALSE)
Rebríček v rámci skupiny MaAuto
Meno MaAuto Body Poradie_v_skupine
Nina FALSE 91 1
Ela FALSE 83 2
Ria FALSE 74 3
Tono TRUE 96 1
Fero TRUE 88 2
NA
# 3) Jednoduché pásma výkonu podľa percentilu (kvintily)
vysl_pasma <- vysl_percentil %>%
  mutate(Pásmo =
           cut(Percentil_Body,
               breaks = c(-Inf, 20, 40, 60, 80, Inf),
               labels = c("E (spodných 20%)", "D", "C", "B", "A (top 20%)"),
               right = TRUE))

kable(vysl_pasma, caption = "Pásma výkonu podľa percentilu (A–E)") %>%
  kable_styling(full_width = FALSE)
Pásma výkonu podľa percentilu (A–E)
Meno Body Percentil_Body Pásmo
Tono 96 100 A (top 20%)
Nina 91 75 B
Fero 88 50 C
Ela 83 25 D
Ria 74 0 E (spodných 20%)
NA
LS0tCnRpdGxlOiAiUHLDoWNhIHMgZGF0YWLDoXpvdSDigJMgY3ZpxI1lYm7DvSBkb2t1bWVudCAoYmV6IHZlcmVqbsO9Y2ggZGF0YWLDoXopIgphdXRob3I6ICJMw612aWEgTWVsaWNob3bDoSIKZGF0ZTogIk9jdG9iZXIgMjAyNSIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRoZW1lOiB1bml0ZWQKICAgIGhpZ2hsaWdodDogdGFuZ28KZWRpdG9yX29wdGlvbnM6IAogIG1hcmtkb3duOiAKICAgIHdyYXA6IDcyCmhlYWRlci1pbmNsdWRlczoKICAtIHwKICAgIDxzdHlsZT4KICAgICAgYm9keSB7CiAgICAgICAgYmFja2dyb3VuZDoKICAgICAgICAgIHJhZGlhbC1ncmFkaWVudChjaXJjbGUgYXQgMjBweCAyMHB4LCAjZmZkMWU4IDZweCwgdHJhbnNwYXJlbnQgN3B4KSAwIDAvNjBweCA2MHB4LAogICAgICAgICAgcmFkaWFsLWdyYWRpZW50KGNpcmNsZSBhdCA1MHB4IDQwcHgsICNmZmU2ZjIgNnB4LCB0cmFuc3BhcmVudCA3cHgpIDAgMC82MHB4IDYwcHgsCiAgICAgICAgICByYWRpYWwtZ3JhZGllbnQoY2lyY2xlIGF0IDM1cHggMTVweCwgI2ZmZjBmNyAxMHB4LCB0cmFuc3BhcmVudCAxMXB4KSAwIDAvNjBweCA2MHB4LAogICAgICAgICAgI2ZmZmFmZDsKICAgICAgfQogICAgICBoMSwgaDIsIGgzLCBoNCwgaDUsIGg2IHsKICAgICAgICBjb2xvcjogI2U5MWU2MyAhaW1wb3J0YW50OwogICAgICAgIGxldHRlci1zcGFjaW5nOiAuMnB4OwogICAgICB9CiAgICAgIC50YXNrIHsKICAgICAgICBiYWNrZ3JvdW5kOiByZ2JhKDI1NSwyMjUsMjM5LC40NSk7CiAgICAgICAgYm9yZGVyOiAxcHggc29saWQgI2ZmYzFkZDsKICAgICAgICBib3JkZXItcmFkaXVzOiAxNnB4OwogICAgICAgIHBhZGRpbmc6IDEycHggMTZweDsKICAgICAgICBtYXJnaW46IDE0cHggMDsKICAgICAgfQogICAgICAubm90ZSB7IGNvbG9yOiAjZTkxZTYzOyBmb250LXdlaWdodDogNjAwOyB9CiAgICAgIGNvZGUgeyBib3JkZXItcmFkaXVzOiA2cHg7IH0KICAgIDwvc3R5bGU+Ci0tLQo8c3R5bGU+CmJvZHkgewogIGJhY2tncm91bmQ6IGxpbmVhci1ncmFkaWVudCgxMjBkZWcsICNmZmU2ZjAgMCUsICNmZmY4ZmIgMTAwJSk7CiAgYmFja2dyb3VuZC1pbWFnZTogdXJsKCdodHRwczovL2Nkbi5waXhhYmF5LmNvbS9waG90by8yMDE5LzAxLzA2LzExLzE0L2Zsb3dlci0zOTE2ODIzXzk2MF83MjAuanBnJyk7CiAgYmFja2dyb3VuZC1yZXBlYXQ6IHJlcGVhdDsKICBiYWNrZ3JvdW5kLXBvc2l0aW9uOiBjZW50ZXIgdG9wOwogIGJhY2tncm91bmQtc2l6ZTogY29udGFpbjsKICBjb2xvcjogIzNjMmEzYTsKICBmb250LWZhbWlseTogIkNvbWljIFNhbnMgTVMiLCAiU2Vnb2UgVUkiLCBzYW5zLXNlcmlmOwp9Cjwvc3R5bGU+CjxzdHlsZT4KaDEsIGgyLCBoMywgaDQsIGg1LCBoNiB7CiAgY29sb3I6ICNlNzU0ODA7IC8qIHJ1xb5vdsOhICovCn0KPC9zdHlsZT4KYGBge3J9CmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBlY2hvID0gVFJVRSwKICBtZXNzYWdlID0gRkFMU0UsCiAgd2FybmluZyA9IEZBTFNFCikKc2V0LnNlZWQoMjAyNSkKYGBgCgoKCiMgUHLDoWNhIHMgw7pkYWptaQoKIyMgVHJhZGnEjW7DoSBwcsOhY2EgcyBkYXRhYsOhem91CgpgYGB7cn0KTWVubyA8LSBjKCJFbGEiLCAiVG9ubyIsICJSaWEiKQpWZWsgIDwtIGMoMTAsIDExLCA5KQpCb2R5IDwtIGMoODMsIDk2LCA3NCkKdWRhamUgPC0gZGF0YS5mcmFtZShNZW5vLCBWZWssIEJvZHkpCnVkYWplCmBgYAoKIyMjIFrDoWtsYWRuw6kgb3BlcsOhY2llCgpgYGB7cn0KdWRhamUkVmVrCm1lYW4odWRhamUkVmVrKQp1ZGFqZVt1ZGFqZSRNZW5vID09ICJUb25vIiwgXQp1ZGFqZVszLCBdCnVkYWplWywgMjozXQp1ZGFqZVsxLCAxXQpzdW1tYXJ5KHVkYWplKQpgYGAKCiMjIE1hbMOpIGN2acSNZW5pZQoKWiB0YWJ1xL5reSB6aXN0aSBtZW5vIMWhdHVkZW50YSBzIG5hanZ5xaHFocOtbSBwb8SNdG9tIEJvZHkgYSB2eXDDrcWhIHZldHUKCmBgYHtyfQptYXhfYm9keSA8LSBtYXgodWRhamUkQm9keSkKbWVub19tYXggPC0gdWRhamUkTWVub1t3aGljaC5tYXgodWRhamUkQm9keSldCnBhc3RlKCJOYWp2aWFjIGJvZG92IG3DoSIsIG1lbm9fbWF4LCAiOiIsIG1heF9ib2R5KQpgYGAKCi0tLQoKIyMjIFByaWTDoXZhbmllIHN0xLpwY292IGEgcmlhZGtvdgoKYGBge3J9Ck1hQXV0byA8LSBjKEZBTFNFLCBUUlVFLCBGQUxTRSkKdWRhamUgPC0gY2JpbmQodWRhamUsIE1hQXV0bykKdWRhamUKYGBgCgpgYGB7cn0Kbm92eV9yaWFkb2sgPC0gZGF0YS5mcmFtZShNZW5vID0gIkZlcm8iLCBWZWsgPSAxMiwgQm9keSA9IDg4LCBNYUF1dG8gPSBUUlVFKQp1ZGFqZSA8LSByYmluZCh1ZGFqZSwgbm92eV9yaWFkb2spCnVkYWplCmBgYAoKIyMgTWFsw6kgY3ZpxI1lbmllClByaWRhaiBkbyB0YWJ1xL5reSBub3bDqWhvIMW+aWFrYSBtZW5vbSBOaW5hLCBtw6EgMTAgcm9rb3YsIDkxIGJvZG92IGEgbmVtw6EgYXV0by4KS2XEjyBqdSBwcmlkw6HFoSwgdnlwb8SNw610YWogbWVkacOhbiBib2RvdiB2xaFldGvDvWNoIMW+aWFrb3YuCgpgYGB7cn0KdWRhamUgPC0gcmJpbmQodWRhamUsIGRhdGEuZnJhbWUoTWVubyA9ICJOaW5hIiwgVmVrID0gMTAsIEJvZHkgPSA5MSwgTWFBdXRvID0gRkFMU0UpKQptZWRpYW4odWRhamUkQm9keSkKYGBgCgotLS0KCiMjIyBUYWJ1xL5reSB2IHByb3N0cmVkw60ga2FibGVFeHRyYQoKYGBge3J9CmxpYnJhcnkoa25pdHIpCmxpYnJhcnkoa2FibGVFeHRyYSkKCmthYmxlKAogIHVkYWplLAogIGRpZ2l0cyA9IDAsCiAgYWxpZ24gPSBjKCJsIiwiYyIsInIiLCJjIiksCiAgY2FwdGlvbiA9ICJQcmVoxL5hZCDFvmlha292IOKAkyBtb2plIGTDoXRhIgopICU+JQogIGthYmxlX3N0eWxpbmcoCiAgICBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIiwgInJlc3BvbnNpdmUiKSwKICAgIGZ1bGxfd2lkdGggPSBGQUxTRSwKICAgIHBvc2l0aW9uID0gImNlbnRlciIKICApCmBgYAoKIyMgTWFsw6kgY3ZpxI1lbmllClogdGFidcS+a3kgc2kgbmVjaGFqIHpvYnJhemnFpSBsZW4gbWVuw6EgYSBib2R5LgpWeXR2b3IgeiB0b2hvIHBla27DuiB0YWJ1xL5rdSBwb21vY291IGthYmxlIGEgbmF6dmkganUg4oCeQm9keSBwb2TEvmEgbWVuYeKAnC4KCmBgYHtyfQp1ZGFqZVssIGMoIk1lbm8iLCAiQm9keSIpXSAlPiUKICBrYWJsZShjYXB0aW9uID0gIkJvZHkgcG9kxL5hIG1lbmEiKSAlPiUKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsImhvdmVyIiksIGZ1bGxfd2lkdGggPSBGQUxTRSkKYGBgCgotLS0KCiMjIFRpZHl2ZXJzZSDigJMgbW9kZXJuw6EgcHLDoWNhIHMgw7pkYWptaQoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKIyMjIGRwbHlyIOKAkyB2w71iZXIgYSB0cmllZGVuaWUKCmBgYHtyfQp1ZGFqZSAlPiUKICBmaWx0ZXIoQm9keSA+IDgwKSAlPiUKICBhcnJhbmdlKGRlc2MoQm9keSkpICU+JQogIGthYmxlKGNhcHRpb24gPSAiQm9keSA+IDgwIOKAkyB6b3N0dXBuZSIpICU+JQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFKQpgYGAKCiMjIE1hbMOpIGN2acSNZW5pZQpWeWJlciBsZW4gdMO9Y2ggxb5pYWtvdiwga3RvcsOtIG1hasO6IGFzcG/FiCA5MCBib2Rvdi4KWm9yYWQgaWNoIGFiZWNlZG5lIHBvZMS+YSBtZW5hIGEgbmVjaCBzYSB6b2JyYXrDrSBsZW4gaWNoIHN0xLpwZWMgTWVuby4KCmBgYHtyfQp1ZGFqZSAlPiUKICBmaWx0ZXIoQm9keSA+PSA5MCkgJT4lCiAgYXJyYW5nZShNZW5vKSAlPiUKICBzZWxlY3QoTWVubykgJT4lCiAga2FibGUoY2FwdGlvbiA9ICJNZW5vIHNvIOKJpSA5MCBib2RtaSAoQeKAk1opIikgJT4lCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRkFMU0UpCmBgYAoKLS0tCgojIyMgWm9za3VwZW5pZSBhIHN1bWFyaXrDoWNpYQoKYGBge3J9CnVkYWplICU+JQogIGdyb3VwX2J5KE1hQXV0bykgJT4lCiAgc3VtbWFyaXNlKAogICAgUHJpZW1fQm9keSA9IG1lYW4oQm9keSksCiAgICBQb2NldCA9IG4oKQogICkgJT4lCiAga2FibGUoCiAgICBjYXB0aW9uID0gIlByaWVtZXJuw6kgQm9keSBwb2TEvmEgTWFBdXRvIiwKICAgIGNvbC5uYW1lcyA9IGMoIk3DoSBBdXRvIiwgIlByaWVtZXIgQm9keSIsICJQb8SNZXQiKSwKICAgIGFsaWduID0gImMiCiAgKSAlPiUKICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGQUxTRSkKYGBgCgojIyBNYWzDqSBjdmnEjWVuaWUKWm9za3VwIMW+aWFrb3YgcG9kxL5hIHRvaG8sIMSNaSBtYWrDuiBhdXRvIGFsZWJvIG5lbWFqw7ouClByZSBrYcW+ZMO6IHNrdXBpbnUgdnlww63FoSBuYWp2ecWhxaHDrSBwb8SNZXQgYm9kb3YgYSBwcmllbWVybsO9IHZlay4KCmBgYHtyfQp1ZGFqZSAlPiUKICBncm91cF9ieShNYUF1dG8pICU+JQogIHN1bW1hcmlzZShNYXhfQm9keSA9IG1heChCb2R5KSwgQXZnX1ZlayA9IG1lYW4oVmVrKSkgJT4lCiAga2FibGUoY2FwdGlvbiA9ICJNYXggQm9keSBhIHByaWVtZXJuw70gdmVrIHBvZMS+YSBNYUF1dG8iKSAlPiUKICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGQUxTRSkKYGBgCgotLS0KCiMjIyBWeXR2w6FyYW5pZSBub3ZlaiBwcmVtZW5uZWogKG11dGF0ZSArIGNhc2Vfd2hlbikKCmBgYHtyfQp1ZGFqZSAlPiUKICBtdXRhdGUoCiAgICBncmFkZSA9IGNhc2Vfd2hlbigKICAgICAgQm9keSA+PSA5MCB+ICJBIiwKICAgICAgQm9keSA+PSA4MCB+ICJCIiwKICAgICAgQm9keSA+PSA3MCB+ICJDIiwKICAgICAgVFJVRSB+ICJEIgogICAgKSwKICAgIFZla1BvUGxub2xldG9zdGkgPSBwbWF4KDAsIFZlayAtIDE4KQogICkgJT4lCiAga2FibGUoY2FwdGlvbiA9ICJabsOhbWt5IGEgVmVrUG9QbG5vbGV0b3N0aSIpICU+JQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFKQpgYGAKCiMjIE1hbMOpIGN2acSNZW5pZQpQcmlkYWogZG8gdGFidcS+a3kgbm92w70gc3TEunBlYyBVc3BlY2gsCmt0b3LDvSBidWRlIG1hxaUgaG9kbm90dSBUUlVFLCBhayBtw6Egxb5pYWsgYXNwb8WIIDg1IGJvZG92LAppbmFrIEZBTFNFLiBQb3RvbSB1a8Ohxb4gcHJ2w6kgxaF0eXJpIHJpYWRreSB0YWJ1xL5reS4KCmBgYHtyfQp1ZGFqZSAlPiUKICBtdXRhdGUoVXNwZWNoID0gQm9keSA+PSA4NSkgJT4lCiAgaGVhZCg0KSAlPiUKICBrYWJsZShjYXB0aW9uID0gIlVzcGVjaCBwb2TEvmEgQm9keSAocHJ2w6kgNCkiKSAlPiUKICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGQUxTRSkKYGBgCgotLS0KCiMgWsOhdmVyZcSNbsOpIGN2acSNZW5pZSDigJMgZGVtb27FoXRyw6FjaWEgbmEgdmxhc3Rub20gcHLDrWtsYWRlCgpWeXR2b3IgcmVicsOtxI1layDigJ5BLcSNa8OhcmnigJwg4oCTIHRlZGEgdMO9Y2gsIGt0b3LDrSBtYWrDuiA5MCBhIHZpYWMgYm9kb3YuClpvcmFkIGljaCBwb2TEvmEgcG/EjXR1IGJvZG92IGEgcHJpZGFqIHN0xLpwZWMgUG9yYWRpZSwga2RlIDEgPSBuYWp2aWFjIGJvZG92Lgpab2JyYXogbGVuIE1lbm8gYSBQb3JhZGllLgoKYGBge3J9CnVkYWplICU+JQogIGZpbHRlcihCb2R5ID49IDkwKSAlPiUKICBhcnJhbmdlKGRlc2MoQm9keSkpICU+JQogIG11dGF0ZShQb3JhZGllVkJvZCA9IHJvd19udW1iZXIoKSkgJT4lCiAgc2VsZWN0KE1lbm8sIFBvcmFkaWVWQm9kKSAlPiUKICBrYWJsZShjYXB0aW9uID0gIkEtxI1rw6FyaSBhIGljaCBwb3JhZGllIHYgYm9kb3ZvbSByZWJyw63EjWt1IikgJT4lCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRkFMU0UpCmBgYAoKLS0tCgojIE3DtGogbsOhdnJoIHBvdcW+aXRpYSBub3Zpbmt5CgpgYGB7cn0Kc2V0LnNlZWQoNykKdWRhamUkTWF0ICA8LSBjKDc2LCA5OCwgNzEsIDg1LCA5NCkKdWRhamUkU2xvdiA8LSBjKDg4LCA5MSwgNjksIDkwLCA5MikKdWRhamUkRW5nICA8LSBjKDc5LCA5NSwgNzUsIDg2LCA5MCkKdWRhamUKYGBgCiMgTcO0aiBuw6F2cmggcG91xb5pdGlhIG5vdmlua3kgKGplZG5vZHVjaMOpKTogcGVyY2VudGlseSArIHJlYnLDrcSNZWsgdiBza3VwaW7DoWNoCgo+IElkZWE6IHNwcmF2w61tZSAqKnBlcmNlbnRpbG92w6kgcG9yYWRpZSoqIHBvZMS+YSBgQm9keWAgKDDigJMxMDAgJSkgYSB6w6Fyb3ZlxYgKPiAqKnJlYnLDrcSNZWsgdiByw6FtY2kgc2t1cGlueSoqIGBNYUF1dG9gIChrdG8gbcOhL25lbcOhIGF1dG8pLiBKZSB0byBpbsO9IHBvaMS+YWQgbmXFviBsZW4KPiDigJ50cmllZGVuaWUgcG9kxL5hIGJvZG924oCcIOKAkyB1dmlkw63FoSBzdm9qZSBwb3N0YXZlbmllIHYgY2VsZWogdHJpZWRlIGFqIHYg4oCecG9kc2t1cGluZeKAnC4KCmBgYHtyfQoKbGlicmFyeShkcGx5cikKbGlicmFyeShrYWJsZUV4dHJhKQoKIyAxKSBQZXJjZW50aWwgcG9kxL5hIEJvZHkgKDDigJMxMDAgJSkKdnlzbF9wZXJjZW50aWwgPC0gdWRhamUgJT4lCiAgbXV0YXRlKAogICAgUGVyY2VudGlsX0JvZHkgPSByb3VuZCgxMDAgKiAocmFuayhCb2R5LCB0aWVzLm1ldGhvZCA9ICJtaW4iKSAtIDEpIC8gKG4oKSAtIDEpLCAxKQogICkgJT4lCiAgYXJyYW5nZShkZXNjKEJvZHkpKSAlPiUKICBzZWxlY3QoTWVubywgQm9keSwgUGVyY2VudGlsX0JvZHkpCgprYWJsZSh2eXNsX3BlcmNlbnRpbCwgY2FwdGlvbiA9ICJQZXJjZW50aWxvdsOpIHBvcmFkaWUgcG9kxL5hIEJvZHkgKDDigJMxMDAgJSkiKSAlPiUKICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGQUxTRSkKCmBgYAoKYGBge3J9CiMgMikgUmVicsOtxI1layB2IHLDoW1jaSBza3VwaW55IE1hQXV0byAoMSA9IG5hanZpYWMgYm9kb3YgdiBkYW5laiBza3VwaW5lKQp2eXNsX3NrdXBpbnkgPC0gdWRhamUgJT4lCiAgZ3JvdXBfYnkoTWFBdXRvKSAlPiUKICBhcnJhbmdlKGRlc2MoQm9keSksIC5ieV9ncm91cCA9IFRSVUUpICU+JQogIG11dGF0ZShQb3JhZGllX3Zfc2t1cGluZSA9IGRlbnNlX3JhbmsoZGVzYyhCb2R5KSkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBzZWxlY3QoTWVubywgTWFBdXRvLCBCb2R5LCBQb3JhZGllX3Zfc2t1cGluZSkKCmthYmxlKHZ5c2xfc2t1cGlueSwgY2FwdGlvbiA9ICJSZWJyw63EjWVrIHYgcsOhbWNpIHNrdXBpbnkgTWFBdXRvIikgJT4lCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRkFMU0UpCgpgYGAKYGBge3J9CiMgMykgSmVkbm9kdWNow6kgcMOhc21hIHbDvWtvbnUgcG9kxL5hIHBlcmNlbnRpbHUgKGt2aW50aWx5KQp2eXNsX3Bhc21hIDwtIHZ5c2xfcGVyY2VudGlsICU+JQogIG11dGF0ZShQw6FzbW8gPQogICAgICAgICAgIGN1dChQZXJjZW50aWxfQm9keSwKICAgICAgICAgICAgICAgYnJlYWtzID0gYygtSW5mLCAyMCwgNDAsIDYwLCA4MCwgSW5mKSwKICAgICAgICAgICAgICAgbGFiZWxzID0gYygiRSAoc3BvZG7DvWNoIDIwJSkiLCAiRCIsICJDIiwgIkIiLCAiQSAodG9wIDIwJSkiKSwKICAgICAgICAgICAgICAgcmlnaHQgPSBUUlVFKSkKCmthYmxlKHZ5c2xfcGFzbWEsIGNhcHRpb24gPSAiUMOhc21hIHbDvWtvbnUgcG9kxL5hIHBlcmNlbnRpbHUgKEHigJNFKSIpICU+JQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFKQoKYGBgCgo=