knitr::opts_chunk$set(
echo = TRUE,
message = FALSE,
warning = FALSE
)
Práca s údajmi
Tradičná práca s databázou
Príklad - moje cvičenie
Práca s jednotlivými stĺpcami
print(f1$Body) # vypíšeme stĺpec Body
[1] 400 350 280 260
print(mean(f1$Body)) # priemerný počet bodov
[1] 322.5
print(f1[Meno=="Lewis Hamilton",]) # vyberieme riadok podľa mena
print(f1[2,]) # vyberieme druhý riadok tabuľky
print(f1[,2:3]) # vyberieme stĺpce Tim a Body
print(f1[1,1]) # vypíšeme jednu bunku (1. riadok, 1. stĺpec)
[1] "Max Verstappen"
summary(f1) # základná štatistika tabuľky
Meno Tim Body
Length:4 Length:4 Min. :260.0
Class :character Class :character 1st Qu.:275.0
Mode :character Mode :character Median :315.0
Mean :322.5
3rd Qu.:362.5
Max. :400.0
Pridanie ďalšieho stĺpca
Napríklad pridáme, či jazdec má pole position v poslednej
kvalifikácii:
PolePosition <- c(TRUE, FALSE, FALSE,TRUE)
f1 <- cbind(f1, PolePosition)
print(f1)
Ak chceme pridať riadok, potom:
# pôvodná tabuľka
Meno <- c("Max Verstappen", "Lewis Hamilton", "Charles Leclerc", "Lando Norris")
Tim <- c("Red Bull", "Mercedes", "Ferrari", "McLaren")
Body <- c(400, 350, 280, 260)
PolePosition <- c(TRUE, FALSE, FALSE, TRUE)
f1 <- data.frame(Meno, Tim, Body, PolePosition)
print(f1)
# nový riadok – musí mať rovnaké stĺpce a typy
novy.riadok <- data.frame(
Meno = "Fernando Alonso",
Tim = "Aston Martin",
Body = 210,
PolePosition = FALSE
)
# pridáme riadok k tabuľke
f1 <- rbind(f1, novy.riadok)
print(f1)
️ Farebná tabuľka jazdcov F1
library(knitr)
library(kableExtra)
Meno <- c("Max Verstappen", "Lewis Hamilton", "Charles Leclerc", "Lando Norris", "Fernando Alonso")
Tim <- c("Red Bull", "Mercedes", "Ferrari", "McLaren", "Aston Martin")
Body <- c(400, 350, 280, 260, 210)
PolePosition <- c(TRUE, FALSE, FALSE, TRUE, FALSE)
f1 <- data.frame(Meno, Tim, Body, PolePosition)
# zafarbenie Body
f1$Body <- cell_spec(
f1$Body,
"html",
color = "white",
background = spec_color(as.numeric(Body), end = 0.7)
)
kable(
f1,
format = "html", # <<< tu musí byť html
escape = FALSE, # <<< aby sa vykreslili farby
caption = "Výsledky jazdcov F1 s farebným stĺpcom Body"
) %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = FALSE,
position = "center"
)
Výsledky jazdcov F1 s farebným stĺpcom Body
Meno |
Tim |
Body |
PolePosition |
Max Verstappen |
Red Bull |
400 |
TRUE |
Lewis Hamilton |
Mercedes |
350 |
FALSE |
Charles Leclerc |
Ferrari |
280 |
FALSE |
Lando Norris |
McLaren |
260 |
TRUE |
Fernando Alonso |
Aston Martin |
210 |
FALSE |
Tidyverse - moderná práca s údajmi
Tidyverse je súbor knižníc, ktoré majú zjednodušiť prácu s údajmi.
Majú jednotný komunikačný štandard, vzájomne sa doplňujú.
# Load tidyverse
library(tidyverse)
dplyr - pre manipuláciu s údajmi
Výber a triedenie
library(tidyverse)
Meno <- c("Max Verstappen", "Lewis Hamilton", "Charles Leclerc", "Lando Norris", "Fernando Alonso")
Tim <- c("Red Bull", "Mercedes", "Ferrari", "McLaren", "Aston Martin")
Body <- c(400, 350, 280, 260, 210)
PolePosition <- c(TRUE, FALSE, FALSE, TRUE, FALSE)
f1 <- data.frame(Meno, Tim, Body, PolePosition)
# vyberieme jazdcov s viac ako 250 bodmi a zoradíme podľa bodov zostupne
f1 %>%
filter(Body > 250) %>%
arrange(desc(Body)) %>%
knitr::kable(format = "html") %>%
kableExtra::kable_styling(
bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = FALSE,
position = "center"
)
Meno |
Tim |
Body |
PolePosition |
Max Verstappen |
Red Bull |
400 |
TRUE |
Lewis Hamilton |
Mercedes |
350 |
FALSE |
Charles Leclerc |
Ferrari |
280 |
FALSE |
Lando Norris |
McLaren |
260 |
TRUE |
Import údajov
na základe viacerých datasetov z kaggle som si pripravila excel ktorý
obsahuje základné údaje z F1
library(readxl)
f1 <- read_excel("f1_long_dataset.xlsx")
head(f1)
Grafy
PolePosition vs Body
library(ggplot2)
ggplot(f1, aes(x = PolePosition, y = Body, color = Jazdec)) +
geom_point(size = 3) +
theme_minimal() +
labs(title = "Vzťah medzi pole position a počtom bodov",
x = "Počet pole position",
y = "Počet bodov")

Čiarový graf – Body podľa rokov
ggplot(f1, aes(x = Rok, y = Body, color = Jazdec, group = Jazdec)) +
geom_line(size = 1.2) +
geom_point(size = 3) +
theme_minimal() +
labs(title = "Vývoj bodov jazdcov F1 (2020–2024)",
x = "Rok",
y = "Body")

Boxplot – rozloženie bodov podľa jazdcov
ggplot(f1, aes(x = Jazdec, y = Body, fill = Jazdec)) +
geom_boxplot() +
theme_minimal() +
labs(title = "Rozloženie bodov podľa jazdcov",
x = "Jazdec",
y = "Body")

Základné štatistiky.
knitr - tabuľka
library(dplyr)
library(knitr)
library(kableExtra)
# Vypočítame základné štatistiky pre body F1 jazdcov podľa rokov
f1.stats <- f1 %>%
group_by(Rok) %>% # zoskupenie podľa roku
summarise(
n = n(), # počet záznamov (jazdcov v danom roku)
mean = mean(Body, na.rm = TRUE), # priemer bodov
sd = sd(Body, na.rm = TRUE), # smerodajná odchýlka
min = min(Body, na.rm = TRUE), # minimálny počet bodov
q25 = quantile(Body, 0.25, na.rm = TRUE), # 1. kvartil (25 %)
median = median(Body, na.rm = TRUE), # medián (50 %)
q75 = quantile(Body, 0.75, na.rm = TRUE), # 3. kvartil (75 %)
max = max(Body, na.rm = TRUE), # maximálny počet bodov
.groups = "drop" # odstránenie vnorených skupín
)
# Vytvoríme pekne naformátovanú tabuľku pomocou kableExtra
f1.stats %>%
kable(
digits = 2, # zaokrúhlenie na 2 desatinné miesta
caption = "Základné štatistiky bodov F1 podľa rokov" # názov tabuľky
) %>%
kable_styling(
full_width = FALSE, # tabuľka nebude cez celú šírku
bootstrap_options = c("striped", "hover", "condensed") # štýl tabuľky
) %>%
column_spec(1, bold = TRUE) %>% # prvý stĺpec (rok) bude tučný
row_spec(0, bold = TRUE, background = "#f2f2f2") %>% # hlavička bude tučná a so sivým pozadím
add_header_above(c(" " = 2, "Body Statistics" = 7)) # nadpis pre skupinu štatistík
Základné štatistiky bodov F1 podľa rokov
|
Body Statistics |
Rok |
n |
mean |
sd |
min |
q25 |
median |
q75 |
max |
2020 |
6 |
269.50 |
94.96 |
180 |
202.5 |
230 |
352.75 |
390 |
2021 |
6 |
275.83 |
89.58 |
190 |
212.5 |
240 |
350.00 |
395 |
2022 |
6 |
283.33 |
82.38 |
200 |
230.0 |
250 |
345.00 |
400 |
2023 |
6 |
290.00 |
78.49 |
210 |
240.0 |
260 |
340.00 |
410 |
2024 |
6 |
296.67 |
75.28 |
220 |
250.0 |
270 |
335.00 |
420 |
T-test – porovnanie priemeru bodov v dvoch rokoch
# t-test porovnanie priemeru bodov v rokoch 2020 a 2024
t.test.result <- t.test(
f1$Body[f1$Rok == 2020],
f1$Body[f1$Rok == 2024]
)
print(t.test.result)
Welch Two Sample t-test
data: f1$Body[f1$Rok == 2020] and f1$Body[f1$Rok == 2024]
t = -0.54915, df = 9.505, p-value = 0.5956
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
-138.17750 83.84417
sample estimates:
mean of x mean of y
269.5000 296.6667
ANOVA – porovnanie priemerov medzi viacerými rokmi
# ANOVA: rozdiely v bodoch medzi rokmi
anova.result <- aov(Body ~ as.factor(Rok), data = f1)
summary(anova.result)
Df Sum Sq Mean Sq F value Pr(>F)
as.factor(Rok) 4 2817 704 0.099 0.982
Residuals 25 178275 7131
Výsledky ANOVA testu (F = 0.099, p = 0.982) ukazujú, že medzi rokmi
2020–2024 neexistuje štatisticky významný rozdiel v priemernom počte
bodov jazdcov F1. Priemery bodov sa medzi jednotlivými rokmi nelíšia
Lineárna regresia - predpovedanie bodov
# Lineárna regresia: predikcia bodov podľa výhier a pole position
model <- lm(Body ~ Vyhry + PolePosition, data = f1)
summary(model)
Call:
lm(formula = Body ~ Vyhry + PolePosition, data = f1)
Residuals:
Min 1Q Median 3Q Max
-38.546 -11.681 -3.194 9.514 60.330
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 211.681 5.908 35.829 <2e-16 ***
Vyhry 7.860 5.430 1.447 0.159
PolePosition 12.897 8.245 1.564 0.129
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 23.19 on 27 degrees of freedom
Multiple R-squared: 0.9198, Adjusted R-squared: 0.9139
F-statistic: 154.9 on 2 and 27 DF, p-value: 1.603e-15
LS0tCnRpdGxlOiAiUHLDoWNhIHMgZGF0YWLDoXpvdSIKYXV0aG9yOiAiU2ltb25hIFZhbsSNb3bDoSA8YnI+CihzIHZ5dcW+aXTDrW0gdmVyZWpuZSBkb3N0dXBuw71jaCBrw7Nkb3YpIgpkYXRlOiAiU2VwdGVtYmVyIDIwMjUiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0aGVtZTogdW5pdGVkCiAgICBoaWdobGlnaHQ6IHRhbmdvCmVkaXRvcl9vcHRpb25zOiAKICBtYXJrZG93bjogCiAgICB3cmFwOiA3MgotLS0KCmBgYHtyfQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgICBlY2hvID0gVFJVRSwKICAgIG1lc3NhZ2UgPSBGQUxTRSwKICAgIHdhcm5pbmcgPSBGQUxTRQopCmBgYAoKPGgxIHN0eWxlPSJjb2xvcjpvcmFuZ2U7Ij4KClByw6FjYSBzIMO6ZGFqbWkKCjwvaDE+Cgo8aDIgc3R5bGU9ImNvbG9yOmJsdWU7Ij4KClRyYWRpxI1uw6EgcHLDoWNhIHMgZGF0YWLDoXpvdQoKPC9oMj4KCiMjIFByw61rbGFkIC0gbW9qZSBjdmnEjWVuaWUKCiMjIyDwn4+O77iPIFByw61rbGFkIOKAkyBGb3JtdWxhIDEKCk1ham1lIMO6ZGFqZSBvIGphemRjb2NoIEYxLCBrdG9yw6kgcHJlZHN0YXZ1asO6IMWhdHlyaSBwcmVtZW5uw6kg4oCTICoqTWVubyoqLAoqKlTDrW0qKiBhICoqQm9keSoqOgoKYGBge3J9Ck1lbm8gPC0gYygiTWF4IFZlcnN0YXBwZW4iLCAiTGV3aXMgSGFtaWx0b24iLCAiQ2hhcmxlcyBMZWNsZXJjIiwgIkxhbmRvIE5vcnJpcyIpClRpbSA8LSBjKCJSZWQgQnVsbCIsICJNZXJjZWRlcyIsICJGZXJyYXJpIiwgIk1jTGFyZW4iKQpCb2R5IDwtIGMoNDAwLCAzNTAsIDI4MCwgMjYwKQpmMSA8LSBkYXRhLmZyYW1lKE1lbm8sIFRpbSwgQm9keSkKcHJpbnQoZjEpCmBgYAoKVGlldG8gcHJlbWVubsOpIHR2b3JpYSB0YWJ1xL5rdSBzIGphemRjYW1pLCBpY2ggdMOtbWFtaSBhIHBvxI10b20KYm9kb3YuXApUZXJheiBuYXByw61rbGFkIHpvcmFkw61tZSB0YWJ1xL5rdSBwb2TEvmEgcG/EjXR1IGJvZG92IHpvc3R1cG5lOgoKYGBge3J9CmYxX3NvcnRlZCA8LSBmMV9kYXRhW29yZGVyKC1mMV9kYXRhJEJvZHkpLCBdCnByaW50KGYxX3NvcnRlZCkKYGBgCgojIyMgUHLDoWNhIHMgamVkbm90bGl2w71taSBzdMS6cGNhbWkKCmBgYHtyfQpwcmludChmMSRCb2R5KSAgICAgICAgICAgICAgICAgICAjIHZ5cMOtxaFlbWUgc3TEunBlYyBCb2R5CnByaW50KG1lYW4oZjEkQm9keSkpICAgICAgICAgICAgICMgcHJpZW1lcm7DvSBwb8SNZXQgYm9kb3YKcHJpbnQoZjFbTWVubz09Ikxld2lzIEhhbWlsdG9uIixdKSAgIyB2eWJlcmllbWUgcmlhZG9rIHBvZMS+YSBtZW5hCnByaW50KGYxWzIsXSkgICAgICAgICAgICAgICAgICAgICMgdnliZXJpZW1lIGRydWjDvSByaWFkb2sgdGFidcS+a3kKcHJpbnQoZjFbLDI6M10pICAgICAgICAgICAgICAgICAgIyB2eWJlcmllbWUgc3TEunBjZSBUaW0gYSBCb2R5CnByaW50KGYxWzEsMV0pICAgICAgICAgICAgICAgICAgICMgdnlww63FoWVtZSBqZWRudSBidW5rdSAoMS4gcmlhZG9rLCAxLiBzdMS6cGVjKQpzdW1tYXJ5KGYxKSAgICAgICAgICAgICAgICAgICAgICAjIHrDoWtsYWRuw6EgxaF0YXRpc3Rpa2EgdGFidcS+a3kKYGBgCgojIyMgUHJpZGFuaWUgxI9hbMWhaWVobyBzdMS6cGNhCgpOYXByw61rbGFkIHByaWTDoW1lLCDEjWkgamF6ZGVjIG3DoSBwb2xlIHBvc2l0aW9uIHYgcG9zbGVkbmVqIGt2YWxpZmlrw6FjaWk6CgpgYGB7cn0KUG9sZVBvc2l0aW9uIDwtIGMoVFJVRSwgRkFMU0UsIEZBTFNFLFRSVUUpCmYxIDwtIGNiaW5kKGYxLCBQb2xlUG9zaXRpb24pCnByaW50KGYxKQpgYGAKCkFrIGNoY2VtZSBwcmlkYcWlIHJpYWRvaywgcG90b206CgpgYGB7cn0KIyBww7R2b2Ruw6EgdGFidcS+a2EKTWVubyA8LSBjKCJNYXggVmVyc3RhcHBlbiIsICJMZXdpcyBIYW1pbHRvbiIsICJDaGFybGVzIExlY2xlcmMiLCAiTGFuZG8gTm9ycmlzIikKVGltIDwtIGMoIlJlZCBCdWxsIiwgIk1lcmNlZGVzIiwgIkZlcnJhcmkiLCAiTWNMYXJlbiIpCkJvZHkgPC0gYyg0MDAsIDM1MCwgMjgwLCAyNjApClBvbGVQb3NpdGlvbiA8LSBjKFRSVUUsIEZBTFNFLCBGQUxTRSwgVFJVRSkKCmYxIDwtIGRhdGEuZnJhbWUoTWVubywgVGltLCBCb2R5LCBQb2xlUG9zaXRpb24pCnByaW50KGYxKQoKIyBub3bDvSByaWFkb2sg4oCTIG11c8OtIG1hxaUgcm92bmFrw6kgc3TEunBjZSBhIHR5cHkKbm92eS5yaWFkb2sgPC0gZGF0YS5mcmFtZSgKICBNZW5vID0gIkZlcm5hbmRvIEFsb25zbyIsCiAgVGltID0gIkFzdG9uIE1hcnRpbiIsCiAgQm9keSA9IDIxMCwKICBQb2xlUG9zaXRpb24gPSBGQUxTRQopCgojIHByaWTDoW1lIHJpYWRvayBrIHRhYnXEvmtlCmYxIDwtIHJiaW5kKGYxLCBub3Z5LnJpYWRvaykKcHJpbnQoZjEpCmBgYAoKIyMjIFRhYnXEvmthIGphemRjb3YgRjEgdiBwcm9zdHJlZMOtIGthYmxlRXh0cmEKCmBgYHtyfQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCgpNZW5vIDwtIGMoIk1heCBWZXJzdGFwcGVuIiwgIkxld2lzIEhhbWlsdG9uIiwgIkNoYXJsZXMgTGVjbGVyYyIsICJMYW5kbyBOb3JyaXMiLCAiRmVybmFuZG8gQWxvbnNvIikKVGltIDwtIGMoIlJlZCBCdWxsIiwgIk1lcmNlZGVzIiwgIkZlcnJhcmkiLCAiTWNMYXJlbiIsICJBc3RvbiBNYXJ0aW4iKQpCb2R5IDwtIGMoNDAwLCAzNTAsIDI4MCwgMjYwLCAyMTApClBvbGVQb3NpdGlvbiA8LSBjKFRSVUUsIEZBTFNFLCBGQUxTRSwgVFJVRSwgRkFMU0UpCgpmMSA8LSBkYXRhLmZyYW1lKE1lbm8sIFRpbSwgQm9keSwgUG9sZVBvc2l0aW9uKQoKa2FibGUoCiAgZjEsCiAgZGlnaXRzID0gMCwKICBhbGlnbiA9IGMoImwiLCJjIiwiciIsImMiKSwKICBjYXB0aW9uID0gIlbDvXNsZWRreSBqYXpkY292IEYxIgopICU+JQogIGthYmxlX3N0eWxpbmcoCiAgICBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIiwgInJlc3BvbnNpdmUiKSwKICAgIGZ1bGxfd2lkdGggPSBGQUxTRSwKICAgIHBvc2l0aW9uID0gImNlbnRlciIKICApCmBgYAoKIyMjIO+4jyBGYXJlYm7DoSB0YWJ1xL5rYSBqYXpkY292IEYxCgpgYGB7cn0KbGlicmFyeShrbml0cikKbGlicmFyeShrYWJsZUV4dHJhKQoKTWVubyA8LSBjKCJNYXggVmVyc3RhcHBlbiIsICJMZXdpcyBIYW1pbHRvbiIsICJDaGFybGVzIExlY2xlcmMiLCAiTGFuZG8gTm9ycmlzIiwgIkZlcm5hbmRvIEFsb25zbyIpClRpbSA8LSBjKCJSZWQgQnVsbCIsICJNZXJjZWRlcyIsICJGZXJyYXJpIiwgIk1jTGFyZW4iLCAiQXN0b24gTWFydGluIikKQm9keSA8LSBjKDQwMCwgMzUwLCAyODAsIDI2MCwgMjEwKQpQb2xlUG9zaXRpb24gPC0gYyhUUlVFLCBGQUxTRSwgRkFMU0UsIFRSVUUsIEZBTFNFKQoKZjEgPC0gZGF0YS5mcmFtZShNZW5vLCBUaW0sIEJvZHksIFBvbGVQb3NpdGlvbikKCiMgemFmYXJiZW5pZSBCb2R5CmYxJEJvZHkgPC0gY2VsbF9zcGVjKAogIGYxJEJvZHksCiAgImh0bWwiLAogIGNvbG9yID0gIndoaXRlIiwKICBiYWNrZ3JvdW5kID0gc3BlY19jb2xvcihhcy5udW1lcmljKEJvZHkpLCBlbmQgPSAwLjcpCikKCmthYmxlKAogIGYxLAogIGZvcm1hdCA9ICJodG1sIiwgICAjIDw8PCB0dSBtdXPDrSBiecWlIGh0bWwKICBlc2NhcGUgPSBGQUxTRSwgICAgIyA8PDwgYWJ5IHNhIHZ5a3Jlc2xpbGkgZmFyYnkKICBjYXB0aW9uID0gIlbDvXNsZWRreSBqYXpkY292IEYxIHMgZmFyZWJuw71tIHN0xLpwY29tIEJvZHkiCikgJT4lCiAga2FibGVfc3R5bGluZygKICAgIGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiLCAicmVzcG9uc2l2ZSIpLAogICAgZnVsbF93aWR0aCA9IEZBTFNFLAogICAgcG9zaXRpb24gPSAiY2VudGVyIgogICkKYGBgCgojIyBUaWR5dmVyc2UgLSBtb2Rlcm7DoSBwcsOhY2EgcyDDumRham1pCgpUaWR5dmVyc2UgamUgc8O6Ym9yIGtuacW+bsOtYywga3RvcsOpIG1hasO6IHpqZWRub2R1xaFpxaUgcHLDoWN1IHMgw7pkYWptaS4gTWFqw7oKamVkbm90bsO9IGtvbXVuaWthxI1uw70gxaF0YW5kYXJkLCB2esOham9tbmUgc2EgZG9wbMWIdWrDui4KCmBgYHtyfQojIExvYWQgdGlkeXZlcnNlCmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKCiMjIyBkcGx5ciAtIHByZSBtYW5pcHVsw6FjaXUgcyDDumRham1pCgojIyMjIFbDvWJlciBhIHRyaWVkZW5pZQoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQoKTWVubyA8LSBjKCJNYXggVmVyc3RhcHBlbiIsICJMZXdpcyBIYW1pbHRvbiIsICJDaGFybGVzIExlY2xlcmMiLCAiTGFuZG8gTm9ycmlzIiwgIkZlcm5hbmRvIEFsb25zbyIpClRpbSA8LSBjKCJSZWQgQnVsbCIsICJNZXJjZWRlcyIsICJGZXJyYXJpIiwgIk1jTGFyZW4iLCAiQXN0b24gTWFydGluIikKQm9keSA8LSBjKDQwMCwgMzUwLCAyODAsIDI2MCwgMjEwKQpQb2xlUG9zaXRpb24gPC0gYyhUUlVFLCBGQUxTRSwgRkFMU0UsIFRSVUUsIEZBTFNFKQoKZjEgPC0gZGF0YS5mcmFtZShNZW5vLCBUaW0sIEJvZHksIFBvbGVQb3NpdGlvbikKCiMgdnliZXJpZW1lIGphemRjb3YgcyB2aWFjIGFrbyAyNTAgYm9kbWkgYSB6b3JhZMOtbWUgcG9kxL5hIGJvZG92IHpvc3R1cG5lCmYxICU+JQogIGZpbHRlcihCb2R5ID4gMjUwKSAlPiUKICBhcnJhbmdlKGRlc2MoQm9keSkpICU+JQogIGtuaXRyOjprYWJsZShmb3JtYXQgPSAiaHRtbCIpICU+JQogIGthYmxlRXh0cmE6OmthYmxlX3N0eWxpbmcoCiAgICBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIiwgInJlc3BvbnNpdmUiKSwKICAgIGZ1bGxfd2lkdGggPSBGQUxTRSwKICAgIHBvc2l0aW9uID0gImNlbnRlciIKICApCmBgYAoKIyMjIyBab3NrdXBlbmllIGEgc3VtYXJpesOhY2lhIOKAkyBGb3JtdWxhIDEKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShrbml0cikKbGlicmFyeShrYWJsZUV4dHJhKQoKTWVubyA8LSBjKCJNYXggVmVyc3RhcHBlbiIsICJMZXdpcyBIYW1pbHRvbiIsICJDaGFybGVzIExlY2xlcmMiLCAiTGFuZG8gTm9ycmlzIiwgIkZlcm5hbmRvIEFsb25zbyIpClRpbSA8LSBjKCJSZWQgQnVsbCIsICJNZXJjZWRlcyIsICJGZXJyYXJpIiwgIk1jTGFyZW4iLCAiQXN0b24gTWFydGluIikKQm9keSA8LSBjKDQwMCwgMzUwLCAyODAsIDI2MCwgMjEwKQpQb2xlUG9zaXRpb24gPC0gYyhUUlVFLCBGQUxTRSwgRkFMU0UsIFRSVUUsIEZBTFNFKQoKZjEgPC0gZGF0YS5mcmFtZShNZW5vLCBUaW0sIEJvZHksIFBvbGVQb3NpdGlvbikKCiMgem9za3Vww61tZSBwb2TEvmEgUG9sZVBvc2l0aW9uIGEgc3BvxI3DrXRhbWUgcHJpZW1lcm7DqSBib2R5IGEgcG/EjWV0IGphemRjb3YKZjEgJT4lCiAgZ3JvdXBfYnkoUG9sZVBvc2l0aW9uKSAlPiUKICBzdW1tYXJpc2UoCiAgICBQcmllbWVyQm9keSA9IG1lYW4oQm9keSksCiAgICBQb2NldCA9IG4oKQogICkgJT4lCiAga2FibGUoCiAgICBjYXB0aW9uID0gIlByaWVtZXJuw6kgYm9keSBwb2TEvmEgdG9obywgxI1pIGphemRlYyB6w61za2FsIFBvbGUgUG9zaXRpb24iLAogICAgY29sLm5hbWVzID0gYygiUG9sZSBQb3NpdGlvbiIsICJQcmllbWVybsOpIEJvZHkiLCAiUG/EjWV0IiksCiAgICBhbGlnbiA9ICJjIgogICkgJT4lCiAga2FibGVfc3R5bGluZygKICAgIGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiLCAicmVzcG9uc2l2ZSIpLAogICAgZnVsbF93aWR0aCA9IEZBTFNFLAogICAgcG9zaXRpb24gPSAiY2VudGVyIgogICkKYGBgCgojIyMjIFZ5dHbDoXJhbmllIG5vdmVqIHByZW1lbm5laiDigJMgRm9ybXVsYSAxCgpCb2R5RG9DaWVsYSBuw6FtIHVrYXp1amUgbyBrb8S+a28gYm9vZG92IGphemRlYyB6YW9zdMOhdmEgemEgbMOtZHJvbSBNLlYuCkhvZG5vdGVuaWUgUy0gc3VwZXIgdsO9a29uIGphemRlYyBtw6EgdmlhYyBha28gMzUwYm9kb3YsIEIgLSBwcmllbWVyCmphemRlYyBtw6EgMjUwIGHFviAyOTkgYm9kb3YsIEMgLSBzbGFiw70gdsO9a29uIGphemRlYyBtw6EgbWVuZWogYWtvIDI1MApib2RvdgoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCgpNZW5vIDwtIGMoIk1heCBWZXJzdGFwcGVuIiwgIkxld2lzIEhhbWlsdG9uIiwgIkNoYXJsZXMgTGVjbGVyYyIsICJMYW5kbyBOb3JyaXMiLCAiRmVybmFuZG8gQWxvbnNvIikKVGltIDwtIGMoIlJlZCBCdWxsIiwgIk1lcmNlZGVzIiwgIkZlcnJhcmkiLCAiTWNMYXJlbiIsICJBc3RvbiBNYXJ0aW4iKQpCb2R5IDwtIGMoNDAwLCAzNTAsIDI4MCwgMjYwLCAyMTApClBvbGVQb3NpdGlvbiA8LSBjKFRSVUUsIEZBTFNFLCBGQUxTRSwgVFJVRSwgRkFMU0UpCgpmMSA8LSBkYXRhLmZyYW1lKE1lbm8sIFRpbSwgQm9keSwgUG9sZVBvc2l0aW9uKQoKIyB2eXR2b3LDrW1lIG5vdsOpIHN0xLpwY2UKZjEgJT4lCiAgbXV0YXRlKAogICAgSG9kbm90ZW5pZSA9IGNhc2Vfd2hlbigKICAgICAgQm9keSA+PSAzNTAgfiAiUyIsCiAgICAgIEJvZHkgPj0gMzAwIH4gIkEiLAogICAgICBCb2R5ID49IDI1MCB+ICJCIiwKICAgICAgVFJVRSB+ICJDIgogICAgKSwKICAgIEJvZHlEb0NpZWxhID0gbWF4KEJvZHkpIC0gQm9keQogICkgJT4lCiAga2FibGUoCiAgICBjYXB0aW9uID0gIkYxIGphemRjaSBzIG5vdsO9bWkgcHJlbWVubsO9bWkgSG9kbm90ZW5pZSBhIEJvZHlEb0NpZWxhIiwKICAgIGFsaWduID0gImMiCiAgKSAlPiUKICBrYWJsZV9zdHlsaW5nKAogICAgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIsICJyZXNwb25zaXZlIiksCiAgICBmdWxsX3dpZHRoID0gRkFMU0UsCiAgICBwb3NpdGlvbiA9ICJjZW50ZXIiCiAgKQpgYGAKCiMjIEltcG9ydCDDumRham92CgpuYSB6w6FrbGFkZSB2aWFjZXLDvWNoIGRhdGFzZXRvdiB6IGthZ2dsZSBzb20gc2kgcHJpcHJhdmlsYSBleGNlbCBrdG9yw70Kb2JzYWh1amUgesOha2xhZG7DqSDDumRhamUgeiBGMQoKYGBge3J9CmxpYnJhcnkocmVhZHhsKQoKZjEgPC0gcmVhZF9leGNlbCgiZjFfbG9uZ19kYXRhc2V0Lnhsc3giKQpoZWFkKGYxKQpgYGAKCiMjIEdyYWZ5CgojIyMgUG9sZVBvc2l0aW9uIHZzIEJvZHkKCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCgpnZ3Bsb3QoZjEsIGFlcyh4ID0gUG9sZVBvc2l0aW9uLCB5ID0gQm9keSwgY29sb3IgPSBKYXpkZWMpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMykgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh0aXRsZSA9ICJWesWlYWggbWVkemkgcG9sZSBwb3NpdGlvbiBhIHBvxI10b20gYm9kb3YiLAogICAgICAgeCA9ICJQb8SNZXQgcG9sZSBwb3NpdGlvbiIsCiAgICAgICB5ID0gIlBvxI1ldCBib2RvdiIpCmBgYAoKIyMjIMSMaWFyb3bDvSBncmFmIOKAkyBCb2R5IHBvZMS+YSByb2tvdgoKYGBge3J9CmdncGxvdChmMSwgYWVzKHggPSBSb2ssIHkgPSBCb2R5LCBjb2xvciA9IEphemRlYywgZ3JvdXAgPSBKYXpkZWMpKSArCiAgZ2VvbV9saW5lKHNpemUgPSAxLjIpICsKICBnZW9tX3BvaW50KHNpemUgPSAzKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIlbDvXZvaiBib2RvdiBqYXpkY292IEYxICgyMDIw4oCTMjAyNCkiLAogICAgICAgeCA9ICJSb2siLAogICAgICAgeSA9ICJCb2R5IikKYGBgCgojIyMgQm94cGxvdCDigJMgcm96bG/FvmVuaWUgYm9kb3YgcG9kxL5hIGphemRjb3YKCmBgYHtyfQpnZ3Bsb3QoZjEsIGFlcyh4ID0gSmF6ZGVjLCB5ID0gQm9keSwgZmlsbCA9IEphemRlYykpICsKICBnZW9tX2JveHBsb3QoKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIlJvemxvxb5lbmllIGJvZG92IHBvZMS+YSBqYXpkY292IiwKICAgICAgIHggPSAiSmF6ZGVjIiwKICAgICAgIHkgPSAiQm9keSIpCgpgYGAKCiMgWsOha2xhZG7DqSDFoXRhdGlzdGlreS4KCiMjIGtuaXRyIC0gdGFidcS+a2EKCmBgYHtyfQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCgojIFZ5cG/EjcOtdGFtZSB6w6FrbGFkbsOpIMWhdGF0aXN0aWt5IHByZSBib2R5IEYxIGphemRjb3YgcG9kxL5hIHJva292CmYxLnN0YXRzIDwtIGYxICU+JQogIGdyb3VwX2J5KFJvaykgJT4lICAgICAgICAgICAgICAgICAgICAgICAgIyB6b3NrdXBlbmllIHBvZMS+YSByb2t1CiAgc3VtbWFyaXNlKAogICAgbiAgICAgICA9IG4oKSwgICAgICAgICAgICAgICAgICAgICAgICAgIyBwb8SNZXQgesOhem5hbW92IChqYXpkY292IHYgZGFub20gcm9rdSkKICAgIG1lYW4gICAgPSBtZWFuKEJvZHksIG5hLnJtID0gVFJVRSksICAgICMgcHJpZW1lciBib2RvdgogICAgc2QgICAgICA9IHNkKEJvZHksIG5hLnJtID0gVFJVRSksICAgICAgIyBzbWVyb2Rham7DoSBvZGNow71sa2EKICAgIG1pbiAgICAgPSBtaW4oQm9keSwgbmEucm0gPSBUUlVFKSwgICAgICMgbWluaW3DoWxueSBwb8SNZXQgYm9kb3YKICAgIHEyNSAgICAgPSBxdWFudGlsZShCb2R5LCAwLjI1LCBuYS5ybSA9IFRSVUUpLCAjIDEuIGt2YXJ0aWwgKDI1ICUpCiAgICBtZWRpYW4gID0gbWVkaWFuKEJvZHksIG5hLnJtID0gVFJVRSksICAjIG1lZGnDoW4gKDUwICUpCiAgICBxNzUgICAgID0gcXVhbnRpbGUoQm9keSwgMC43NSwgbmEucm0gPSBUUlVFKSwgIyAzLiBrdmFydGlsICg3NSAlKQogICAgbWF4ICAgICA9IG1heChCb2R5LCBuYS5ybSA9IFRSVUUpLCAgICAgIyBtYXhpbcOhbG55IHBvxI1ldCBib2RvdgogICAgLmdyb3VwcyA9ICJkcm9wIiAgICAgICAgICAgICAgICAgICAgICAgIyBvZHN0csOhbmVuaWUgdm5vcmVuw71jaCBza3Vww61uCiAgKQoKIyBWeXR2b3LDrW1lIHBla25lIG5hZm9ybcOhdG92YW7DuiB0YWJ1xL5rdSBwb21vY291IGthYmxlRXh0cmEKZjEuc3RhdHMgJT4lCiAga2FibGUoCiAgICBkaWdpdHMgPSAyLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHphb2tyw7pobGVuaWUgbmEgMiBkZXNhdGlubsOpIG1pZXN0YQogICAgY2FwdGlvbiA9ICJaw6FrbGFkbsOpIMWhdGF0aXN0aWt5IGJvZG92IEYxIHBvZMS+YSByb2tvdiIgICMgbsOhem92IHRhYnXEvmt5CiAgKSAlPiUKICBrYWJsZV9zdHlsaW5nKAogICAgZnVsbF93aWR0aCA9IEZBTFNFLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB0YWJ1xL5rYSBuZWJ1ZGUgY2V6IGNlbMO6IMWhw61ya3UKICAgIGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiKSAjIMWhdMO9bCB0YWJ1xL5reQogICkgJT4lCiAgY29sdW1uX3NwZWMoMSwgYm9sZCA9IFRSVUUpICU+JSAgICAgICAgICAgICAgICAgICAjIHBydsO9IHN0xLpwZWMgKHJvaykgYnVkZSB0dcSNbsO9CiAgcm93X3NwZWMoMCwgYm9sZCA9IFRSVUUsIGJhY2tncm91bmQgPSAiI2YyZjJmMiIpICU+JSAgIyBobGF2acSNa2EgYnVkZSB0dcSNbsOhIGEgc28gc2l2w71tIHBvemFkw61tCiAgYWRkX2hlYWRlcl9hYm92ZShjKCIgIiA9IDIsICJCb2R5IFN0YXRpc3RpY3MiID0gNykpICAgICMgbmFkcGlzIHByZSBza3VwaW51IMWhdGF0aXN0w61rCmBgYAoKIyMgVC10ZXN0IOKAkyBwb3Jvdm5hbmllIHByaWVtZXJ1IGJvZG92IHYgZHZvY2ggcm9rb2NoCgpgYGB7cn0KIyB0LXRlc3QgcG9yb3ZuYW5pZSBwcmllbWVydSBib2RvdiB2IHJva29jaCAyMDIwIGEgMjAyNAp0LnRlc3QucmVzdWx0IDwtIHQudGVzdCgKICBmMSRCb2R5W2YxJFJvayA9PSAyMDIwXSwKICBmMSRCb2R5W2YxJFJvayA9PSAyMDI0XQopCgpwcmludCh0LnRlc3QucmVzdWx0KQpgYGAKCiMjIEFOT1ZBIOKAkyBwb3Jvdm5hbmllIHByaWVtZXJvdiBtZWR6aSB2aWFjZXLDvW1pIHJva21pCgpgYGB7cn0KIyBBTk9WQTogcm96ZGllbHkgdiBib2RvY2ggbWVkemkgcm9rbWkKYW5vdmEucmVzdWx0IDwtIGFvdihCb2R5IH4gYXMuZmFjdG9yKFJvayksIGRhdGEgPSBmMSkKc3VtbWFyeShhbm92YS5yZXN1bHQpCmBgYAoKVsO9c2xlZGt5IEFOT1ZBIHRlc3R1IChGID0gMC4wOTksIHAgPSAwLjk4MikgdWthenVqw7osIMW+ZSBtZWR6aSByb2ttaQoyMDIw4oCTMjAyNCBuZWV4aXN0dWplIMWhdGF0aXN0aWNreSB2w716bmFtbsO9IHJvemRpZWwgdiBwcmllbWVybm9tIHBvxI10ZQpib2RvdiBqYXpkY292IEYxLiBQcmllbWVyeSBib2RvdiBzYSBtZWR6aSBqZWRub3RsaXbDvW1pIHJva21pIG5lbMOtxaFpYQoKIyMgTGluZcOhcm5hIHJlZ3Jlc2lhIC0gcHJlZHBvdmVkYW5pZSBib2RvdgoKYGBge3J9CiMgTGluZcOhcm5hIHJlZ3Jlc2lhOiBwcmVkaWtjaWEgYm9kb3YgcG9kxL5hIHbDvWhpZXIgYSBwb2xlIHBvc2l0aW9uCm1vZGVsIDwtIGxtKEJvZHkgfiBWeWhyeSArIFBvbGVQb3NpdGlvbiwgZGF0YSA9IGYxKQpzdW1tYXJ5KG1vZGVsKQpgYGAK