knitr::opts_chunk$set(
echo = TRUE,
message = FALSE,
warning = FALSE
)
Moja vybraná databáza
Pre spracovanie som si vybrala databázu European
Cities Weather Prediction Dataset z Kaggle.
Databáza obsahuje historické údaje o počasí z európskych miest. Každý
záznam obsahuje dátum merania a rôzne meteorologické parametre. Údaje sú
zoradené chronologicky podľa dátumu, čo umožňuje sledovať zmeny teploty
v priebehu času.
Táto databáza je vhodná na vizualizáciu, tvorbu grafov a výpočet
základných štatistík, ktoré ukazujú vývoj teploty v európskych mestách.
Plánujem ju využiť na ďalšie spracovanie a analýzu trendov teploty v
Európských mestach.
# Načítanie knižníc
library(tidyverse)
library(lubridate)
library(corrplot)
library(ggplot2)
library(kableExtra)
library(htmltools)
Načítame databázu
udaje <- read_csv("weather_prediction_dataset.csv")
Vyberieme len potrebné stĺpce
udaje_vybrane <- udaje %>%
select(DATE, BASEL_temp_mean, BUDAPEST_temp_mean, DUSSELDORF_temp_mean)
Zobrazenie prvých 10 riadkov
# Prevod čísla YYYYMMDD na Date
udaje_vybrane$DATE <- as.Date(as.character(udaje_vybrane$DATE), format="%Y%m%d")
head(udaje_vybrane$DATE)
[1] "2000-01-01" "2000-01-02" "2000-01-03" "2000-01-04" "2000-01-05" "2000-01-06"
head(udaje_vybrane, 10) %>%
kable(
caption = "Ukážka prvých 10 riadkov vybraných teplôt európskych miest",
col.names = c("Dátum", "Basel (°C)", "Budapešť (°C)", "Düsseldorf (°C)")
) %>%
kable_styling(
full_width = FALSE,
bootstrap_options = c("striped", "hover", "condensed")
)
Ukážka prvých 10 riadkov vybraných teplôt európskych miest
| Dátum |
Basel (°C) |
Budapešť (°C) |
Düsseldorf (°C) |
| 2000-01-01 |
2.9 |
-4.9 |
4.2 |
| 2000-01-02 |
3.6 |
-3.6 |
6.5 |
| 2000-01-03 |
2.2 |
-0.8 |
7.7 |
| 2000-01-04 |
3.9 |
-1.0 |
7.8 |
| 2000-01-05 |
6.0 |
0.2 |
5.2 |
| 2000-01-06 |
4.2 |
-0.9 |
7.6 |
| 2000-01-07 |
4.7 |
-2.8 |
6.6 |
| 2000-01-08 |
5.6 |
-1.2 |
6.6 |
| 2000-01-09 |
4.6 |
-1.4 |
2.5 |
| 2000-01-10 |
2.4 |
0.0 |
1.1 |
Výpočet základných štatistík
Nižšie ukážem základné štatistické charakteristiky priemernej teploty
pre tri vybrané mestá – Basel, Budapešť a Düsseldorf vo forme troch
tabuliek umiestnených vedľa seba.
# Štatistika Basel
s_basel <- udaje_vybrane %>%
summarise(
Priemer = mean(BASEL_temp_mean, na.rm = TRUE),
Minimum = min(BASEL_temp_mean, na.rm = TRUE),
Maximum = max(BASEL_temp_mean, na.rm = TRUE)
)
# ️Štatistika Budapešť
s_budapest <- udaje_vybrane %>%
summarise(
Priemer = mean(BUDAPEST_temp_mean, na.rm = TRUE),
Minimum = min(BUDAPEST_temp_mean, na.rm = TRUE),
Maximum = max(BUDAPEST_temp_mean, na.rm = TRUE)
)
# Štatistika Düsseldorf
s_dusseldorf <- udaje_vybrane %>%
summarise(
Priemer = mean(DUSSELDORF_temp_mean, na.rm = TRUE),
Minimum = min(DUSSELDORF_temp_mean, na.rm = TRUE),
Maximum = max(DUSSELDORF_temp_mean, na.rm = TRUE)
)
b_tab <- s_basel %>%
kable(caption = "Základné štatistiky - Basel") %>%
kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover")) %>%
as.character()
bp_tab <- s_budapest %>%
kable(caption = "Základné štatistiky - Budapešť") %>%
kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover")) %>%
as.character()
d_tab <- s_dusseldorf %>%
kable(caption = "Základné štatistiky - Düsseldorf") %>%
kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover")) %>%
as.character()
browsable(
tags$div(style="display:flex; gap:20px; align-items:flex-start;",
HTML(b_tab),
HTML(bp_tab),
HTML(d_tab)
)
)
Základné štatistiky - Basel
| Priemer |
Minimum |
Maximum |
| 11.0228 |
-9.3 |
29 |
Základné štatistiky - Budapešť
| Priemer |
Minimum |
Maximum |
| 12.17485 |
-9.8 |
33.1 |
Základné štatistiky - Düsseldorf
| Priemer |
Minimum |
Maximum |
| 11.14201 |
-11.1 |
29.2 |
Vývoj priemernej teploty v troch mestách
udaje_long <- udaje_vybrane %>%
pivot_longer(
cols = c(BASEL_temp_mean, BUDAPEST_temp_mean, DUSSELDORF_temp_mean),
names_to = "Mesto",
values_to = "Priemerna_teplota"
)
udaje_long$Mesto <- recode(udaje_long$Mesto,
"BASEL_temp_mean" = "Basel",
"BUDAPEST_temp_mean" = "Budapešť",
"DUSSELDORF_temp_mean" = "Düsseldorf")
ggplot(udaje_long, aes(x = DATE, y = Priemerna_teplota, color = Mesto)) +
geom_line(size = 1) +
theme_minimal() +
labs(
title = "Vývoj priemernej teploty v troch mestách",
x = "Dátum",
y = "Priemerná teplota (°C)",
color = "Mesto"
) +
scale_color_manual(values = c("Basel" = "blue", "Budapešť" = "red", "Düsseldorf" = "yellow"))

Tu zobrazený graf vývoja priemernej dennej teploty v troch vybraných
mestách – Basel, Budapešť a Düsseldorf – za obdobie, pre ktoré sú k
dispozícii merania v databáze.
Každé mesto je reprezentované samostatnou farebnou čiarou, čo
umožňuje prehľadné porovnanie teplotných trendov a zmien v čase.
Priemerná a extrémna denná teplota v Düsseldorfe
dusseldorf <- udaje %>%
select(DATE, DUSSELDORF_temp_min, DUSSELDORF_temp_mean, DUSSELDORF_temp_max) %>%
mutate(DATE = as.Date(as.character(DATE), format="%Y%m%d"))
dusseldorf_points <- dusseldorf %>%
filter(row_number() %% 30 == 1)
ggplot(dusseldorf, aes(x = DATE)) +
geom_line(aes(y = DUSSELDORF_temp_mean), color="lightgreen", size=1) +
geom_point(data = dusseldorf_points, aes(y = DUSSELDORF_temp_min), color="darkgreen", size=1.5) +
geom_point(data = dusseldorf_points, aes(y = DUSSELDORF_temp_max), color="red", size=1.5) +
theme_minimal() +
labs(
title = "Priemerná a extrémna denná teplota v Düsseldorfe",
x = "Dátum",
y = "Teplota (°C)"
)

Tento graf zobrazuje priemernú dennú teplotu v Düsseldorfe spolu s
minimálnymi a maximálnymi hodnotami.
Svetlozelená čiara ukazuje priemernú teplotu a body označujú extrémy
iba raz za 30 dní.
Takáto vizualizácia umožňuje prehľadnejšie sledovanie trendov a
variabilitu teploty v čase bez zahltenia grafu príliš veľkým množstvom
bodov.
Korelačná matica - Budapešť
budapest_data <- udaje %>%
select(BUDAPEST_temp_max, BUDAPEST_humidity, BUDAPEST_pressure,
BUDAPEST_sunshine, BUDAPEST_global_radiation, BUDAPEST_precipitation,
)
cor_matrix_budapest <- cor(budapest_data, use = "complete.obs")
library(corrplot)
corrplot(cor_matrix_budapest, method = "color", type = "upper",
tl.col = "black", tl.srt = 45, addCoef.col = "black",
title = "Korelačná matica - Budapešť", mar = c(0,0,2,0))

Korelačná matica zobrazuje vzťahy medzi vybranými meteorologickými
premennými v meste Budapešť: maximálnou teplotou vzduchu, vlhkosťou,
tlakom, slnečným svitom, globálnou radiáciou a množstvom zrážok. Medzi
jednotlivými premennými možno pozorovať niekoľko výrazných
korelácií:
Maximálna teplota (BUDAPEST_temp_max) má silnú pozitívnu koreláciu so
slnečným svitom (r = 0.65) a globálnou radiáciou (r = 0.79). To znamená,
že s rastúcim množstvom slnečného žiarenia a dĺžkou slnečného svitu
rastie aj teplota.
Medzi teplotou a vlhkosťou sa nachádza negatívna korelácia (r =
-0.55), čo naznačuje, že počas vlhkých dní bývajú teploty spravidla
nižšie.
Tlak vzduchu vykazuje len slabé vzťahy s ostatnými premennými
(hodnoty okolo 0.1–0.2), čo znamená, že tlak má na dennú teplotu a
ostatné ukazovatele iba malý vplyv.
Slnečný svit a globálna radiácia sú medzi sebou veľmi silno pozitívne
korelované (r = 0.89), čo je očakávané, keďže oba faktory súvisia s
intenzitou slnečného žiarenia.
Zrážky (BUDAPEST_precipitation) majú slabé až mierne negatívne
korelácie s väčšinou ostatných ukazovateľov (napr. s teplotou r = -0.01,
s radiáciou r = -0.16), čo potvrdzuje, že počas daždivých dní býva menej
slnka a teploty sú nižšie.
Celkovo matica potvrdzuje očakávané vzťahy medzi meteorologickými
ukazovateľmi – vyššie teploty sú spojené s vyššou intenzitou slnečného
žiarenia, zatiaľ čo zvýšená vlhkosť a zrážky prispievajú k ich
poklesu.
LS0tCnRpdGxlOiAiw5psb2hhXzMtNCIKYXV0aG9yOiAiQmMuIEtyeXN0eW5hIFZhc3lseW5hIgpkYXRlOiAiT2t0b2JlciAyMDI1IgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0aGVtZTogdW5pdGVkCiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgZGZfcHJpbnQ6IHBhZ2VkCmVkaXRvcl9vcHRpb25zOgogIG1hcmtkb3duOgogICAgd3JhcDogNzIKLS0tCmBgYHtyfQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgICBlY2hvID0gVFJVRSwKICAgIG1lc3NhZ2UgPSBGQUxTRSwKICAgIHdhcm5pbmcgPSBGQUxTRQopCmBgYAoKIyMgTW9qYSB2eWJyYW7DoSBkYXRhYsOhemEKClByZSBzcHJhY292YW5pZSBzb20gc2kgdnlicmFsYSBkYXRhYsOhenUgCltFdXJvcGVhbiBDaXRpZXMgV2VhdGhlciBQcmVkaWN0aW9uIERhdGFzZXRdKGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YXNldHMvb3J2aWxlL2V1cm9wZWFuLWNpdGllcy13ZWF0aGVyLXByZWRpY3Rpb24tZGF0YXNldC9kYXRhKSB6IEthZ2dsZS4gCgpEYXRhYsOhemEgb2JzYWh1amUgaGlzdG9yaWNrw6kgw7pkYWplIG8gcG/EjWFzw60geiBldXLDs3Bza3ljaCBtaWVzdC4gCkthxb5kw70gesOhem5hbSBvYnNhaHVqZSBkw6F0dW0gbWVyYW5pYSBhIHLDtHpuZSBtZXRlb3JvbG9naWNrw6kgcGFyYW1ldHJlLgrDmmRhamUgc8O6IHpvcmFkZW7DqSBjaHJvbm9sb2dpY2t5IHBvZMS+YSBkw6F0dW11LCDEjW8gdW1vxb7FiHVqZSBzbGVkb3ZhxaUgem1lbnkgdGVwbG90eSB2IHByaWViZWh1IMSNYXN1LgoKVMOhdG8gZGF0YWLDoXphIGplIHZob2Ruw6EgbmEgdml6dWFsaXrDoWNpdSwgdHZvcmJ1IGdyYWZvdiBhIHbDvXBvxI1ldCB6w6FrbGFkbsO9Y2ggxaF0YXRpc3TDrWssIGt0b3LDqSB1a2F6dWrDuiB2w712b2ogdGVwbG90eSB2IGV1csOzcHNreWNoIG1lc3TDoWNoLiAKUGzDoW51amVtIGp1IHZ5dcW+acWlIG5hIMSPYWzFoWllIHNwcmFjb3ZhbmllIGEgYW5hbMO9enUgdHJlbmRvdiB0ZXBsb3R5IHYgRXVyw7Nwc2vDvWNoIG1lc3RhY2guCgpgYGB7cn0KIyBOYcSNw610YW5pZSBrbmnFvm7DrWMKCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShjb3JycGxvdCkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCmxpYnJhcnkoaHRtbHRvb2xzKQpgYGAKCiMjIE5hxI3DrXRhbWUgZGF0YWLDoXp1CgpgYGB7cn0KdWRhamUgPC0gcmVhZF9jc3YoIndlYXRoZXJfcHJlZGljdGlvbl9kYXRhc2V0LmNzdiIpCmBgYAoKIyMjIFZ5YmVyaWVtZSBsZW4gcG90cmVibsOpIHN0xLpwY2UKCmBgYHtyfQp1ZGFqZV92eWJyYW5lIDwtIHVkYWplICU+JQogIHNlbGVjdChEQVRFLCBCQVNFTF90ZW1wX21lYW4sIEJVREFQRVNUX3RlbXBfbWVhbiwgRFVTU0VMRE9SRl90ZW1wX21lYW4pCmBgYAoKIyMjIFpvYnJhemVuaWUgcHJ2w71jaCAxMCByaWFka292CgpgYGB7cn0KIyBQcmV2b2QgxI3DrXNsYSBZWVlZTU1ERCBuYSBEYXRlCnVkYWplX3Z5YnJhbmUkREFURSA8LSBhcy5EYXRlKGFzLmNoYXJhY3Rlcih1ZGFqZV92eWJyYW5lJERBVEUpLCBmb3JtYXQ9IiVZJW0lZCIpCmhlYWQodWRhamVfdnlicmFuZSREQVRFKQpoZWFkKHVkYWplX3Z5YnJhbmUsIDEwKSAlPiUKICBrYWJsZSgKICAgIGNhcHRpb24gPSAiVWvDocW+a2EgcHJ2w71jaCAxMCByaWFka292IHZ5YnJhbsO9Y2ggdGVwbMO0dCBldXLDs3Bza3ljaCBtaWVzdCIsCiAgICBjb2wubmFtZXMgPSBjKCJEw6F0dW0iLCAiQmFzZWwgKMKwQykiLCAiQnVkYXBlxaHFpSAowrBDKSIsICJEw7xzc2VsZG9yZiAowrBDKSIpCiAgKSAlPiUKICBrYWJsZV9zdHlsaW5nKAogICAgZnVsbF93aWR0aCA9IEZBTFNFLAogICAgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIpCiAgKQpgYGAKCiMjIFbDvXBvxI1ldCB6w6FrbGFkbsO9Y2ggxaF0YXRpc3TDrWsKCk5pxb7FoWllIHVrw6HFvmVtIHrDoWtsYWRuw6kgxaF0YXRpc3RpY2vDqSBjaGFyYWt0ZXJpc3Rpa3kgcHJpZW1lcm5laiB0ZXBsb3R5IHByZSB0cmkgdnlicmFuw6kgbWVzdMOhIOKAkyBCYXNlbCwgQnVkYXBlxaHFpSBhIETDvHNzZWxkb3JmIHZvIGZvcm1lIHRyb2NoIHRhYnVsaWVrIHVtaWVzdG5lbsO9Y2ggdmVkxL5hIHNlYmEuCgpgYGB7cn0KIyDFoHRhdGlzdGlrYSBCYXNlbApzX2Jhc2VsIDwtIHVkYWplX3Z5YnJhbmUgJT4lCnN1bW1hcmlzZSgKICAgUHJpZW1lciA9IG1lYW4oQkFTRUxfdGVtcF9tZWFuLCBuYS5ybSA9IFRSVUUpLAogICBNaW5pbXVtID0gbWluKEJBU0VMX3RlbXBfbWVhbiwgbmEucm0gPSBUUlVFKSwKICAgTWF4aW11bSA9IG1heChCQVNFTF90ZW1wX21lYW4sIG5hLnJtID0gVFJVRSkKKQogCiMg77iPxaB0YXRpc3Rpa2EgQnVkYXBlxaHFpQpzX2J1ZGFwZXN0IDwtIHVkYWplX3Z5YnJhbmUgJT4lCnN1bW1hcmlzZSgKICAgUHJpZW1lciA9IG1lYW4oQlVEQVBFU1RfdGVtcF9tZWFuLCBuYS5ybSA9IFRSVUUpLAogICBNaW5pbXVtID0gbWluKEJVREFQRVNUX3RlbXBfbWVhbiwgbmEucm0gPSBUUlVFKSwKICAgTWF4aW11bSA9IG1heChCVURBUEVTVF90ZW1wX21lYW4sIG5hLnJtID0gVFJVRSkKKQojIMWgdGF0aXN0aWthIETDvHNzZWxkb3JmCnNfZHVzc2VsZG9yZiA8LSB1ZGFqZV92eWJyYW5lICU+JQpzdW1tYXJpc2UoCiAgIFByaWVtZXIgPSBtZWFuKERVU1NFTERPUkZfdGVtcF9tZWFuLCBuYS5ybSA9IFRSVUUpLAogICBNaW5pbXVtID0gbWluKERVU1NFTERPUkZfdGVtcF9tZWFuLCBuYS5ybSA9IFRSVUUpLAogICBNYXhpbXVtID0gbWF4KERVU1NFTERPUkZfdGVtcF9tZWFuLCBuYS5ybSA9IFRSVUUpCikKIApiX3RhYiA8LSBzX2Jhc2VsICU+JQprYWJsZShjYXB0aW9uID0gIlrDoWtsYWRuw6kgxaF0YXRpc3Rpa3kgLSBCYXNlbCIpICU+JQprYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGQUxTRSwgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIikpICU+JQphcy5jaGFyYWN0ZXIoKSAKYnBfdGFiIDwtIHNfYnVkYXBlc3QgJT4lCmthYmxlKGNhcHRpb24gPSAiWsOha2xhZG7DqSDFoXRhdGlzdGlreSAtIEJ1ZGFwZcWhxaUiKSAlPiUKa2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRkFMU0UsIGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpKSAlPiUKYXMuY2hhcmFjdGVyKCkKZF90YWIgPC0gc19kdXNzZWxkb3JmICU+JQprYWJsZShjYXB0aW9uID0gIlrDoWtsYWRuw6kgxaF0YXRpc3Rpa3kgLSBEw7xzc2VsZG9yZiIpICU+JQprYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGQUxTRSwgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIikpICU+JQphcy5jaGFyYWN0ZXIoKQogCmJyb3dzYWJsZSgKdGFncyRkaXYoc3R5bGU9ImRpc3BsYXk6ZmxleDsgZ2FwOjIwcHg7IGFsaWduLWl0ZW1zOmZsZXgtc3RhcnQ7IiwKICAgICAgICAgIEhUTUwoYl90YWIpLAogICAgICAgICAgSFRNTChicF90YWIpLAogICAgICAgICAgSFRNTChkX3RhYikKKQopCmBgYAoKIyMgVsO9dm9qIHByaWVtZXJuZWogdGVwbG90eSB2IHRyb2NoIG1lc3TDoWNoCgpgYGB7cn0KCnVkYWplX2xvbmcgPC0gdWRhamVfdnlicmFuZSAlPiUKICBwaXZvdF9sb25nZXIoCiAgICBjb2xzID0gYyhCQVNFTF90ZW1wX21lYW4sIEJVREFQRVNUX3RlbXBfbWVhbiwgRFVTU0VMRE9SRl90ZW1wX21lYW4pLAogICAgbmFtZXNfdG8gPSAiTWVzdG8iLAogICAgdmFsdWVzX3RvID0gIlByaWVtZXJuYV90ZXBsb3RhIgogICkKCnVkYWplX2xvbmckTWVzdG8gPC0gcmVjb2RlKHVkYWplX2xvbmckTWVzdG8sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJCQVNFTF90ZW1wX21lYW4iID0gIkJhc2VsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJVREFQRVNUX3RlbXBfbWVhbiIgPSAiQnVkYXBlxaHFpSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJEVVNTRUxET1JGX3RlbXBfbWVhbiIgPSAiRMO8c3NlbGRvcmYiKQoKZ2dwbG90KHVkYWplX2xvbmcsIGFlcyh4ID0gREFURSwgeSA9IFByaWVtZXJuYV90ZXBsb3RhLCBjb2xvciA9IE1lc3RvKSkgKwogIGdlb21fbGluZShzaXplID0gMSkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicygKICAgIHRpdGxlID0gIlbDvXZvaiBwcmllbWVybmVqIHRlcGxvdHkgdiB0cm9jaCBtZXN0w6FjaCIsCiAgICB4ID0gIkTDoXR1bSIsCiAgICB5ID0gIlByaWVtZXJuw6EgdGVwbG90YSAowrBDKSIsCiAgICBjb2xvciA9ICJNZXN0byIKICApICsKc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIkJhc2VsIiA9ICJibHVlIiwgIkJ1ZGFwZcWhxaUiID0gInJlZCIsICJEw7xzc2VsZG9yZiIgPSAieWVsbG93IikpCmBgYApUdSB6b2JyYXplbsO9IGdyYWYgdsO9dm9qYSBwcmllbWVybmVqIGRlbm5laiB0ZXBsb3R5IHYgdHJvY2ggdnlicmFuw71jaCBtZXN0w6FjaCDigJMgQmFzZWwsIEJ1ZGFwZcWhxaUgYSBEw7xzc2VsZG9yZiDigJMgemEgb2Jkb2JpZSwgcHJlIGt0b3LDqSBzw7ogayBkaXNwb3rDrWNpaSBtZXJhbmlhIHYgZGF0YWLDoXplLiAKCkthxb5kw6kgbWVzdG8gamUgcmVwcmV6ZW50b3ZhbsOpIHNhbW9zdGF0bm91IGZhcmVibm91IMSNaWFyb3UsIMSNbyB1bW/FvsWIdWplIHByZWjEvmFkbsOpIHBvcm92bmFuaWUgdGVwbG90bsO9Y2ggdHJlbmRvdiBhIHptaWVuIHYgxI1hc2UuCgojIyBQcmllbWVybsOhIGEgZXh0csOpbW5hIGRlbm7DoSB0ZXBsb3RhIHYgRMO8c3NlbGRvcmZlCgpgYGB7cn0KZHVzc2VsZG9yZiA8LSB1ZGFqZSAlPiUKICBzZWxlY3QoREFURSwgRFVTU0VMRE9SRl90ZW1wX21pbiwgRFVTU0VMRE9SRl90ZW1wX21lYW4sIERVU1NFTERPUkZfdGVtcF9tYXgpICU+JQogIG11dGF0ZShEQVRFID0gYXMuRGF0ZShhcy5jaGFyYWN0ZXIoREFURSksIGZvcm1hdD0iJVklbSVkIikpCgpkdXNzZWxkb3JmX3BvaW50cyA8LSBkdXNzZWxkb3JmICU+JQogIGZpbHRlcihyb3dfbnVtYmVyKCkgJSUgMzAgPT0gMSkKCmdncGxvdChkdXNzZWxkb3JmLCBhZXMoeCA9IERBVEUpKSArCiAgZ2VvbV9saW5lKGFlcyh5ID0gRFVTU0VMRE9SRl90ZW1wX21lYW4pLCBjb2xvcj0ibGlnaHRncmVlbiIsIHNpemU9MSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGR1c3NlbGRvcmZfcG9pbnRzLCBhZXMoeSA9IERVU1NFTERPUkZfdGVtcF9taW4pLCBjb2xvcj0iZGFya2dyZWVuIiwgc2l6ZT0xLjUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBkdXNzZWxkb3JmX3BvaW50cywgYWVzKHkgPSBEVVNTRUxET1JGX3RlbXBfbWF4KSwgY29sb3I9InJlZCIsIHNpemU9MS41KSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKAogICAgdGl0bGUgPSAiUHJpZW1lcm7DoSBhIGV4dHLDqW1uYSBkZW5uw6EgdGVwbG90YSB2IETDvHNzZWxkb3JmZSIsCiAgICB4ID0gIkTDoXR1bSIsCiAgICB5ID0gIlRlcGxvdGEgKMKwQykiCiAgKQpgYGAKClRlbnRvIGdyYWYgem9icmF6dWplIHByaWVtZXJuw7ogZGVubsO6IHRlcGxvdHUgdiBEw7xzc2VsZG9yZmUgc3BvbHUgcyBtaW5pbcOhbG55bWkgYSBtYXhpbcOhbG55bWkgaG9kbm90YW1pLiAKClN2ZXRsb3plbGVuw6EgxI1pYXJhIHVrYXp1amUgcHJpZW1lcm7DuiB0ZXBsb3R1IGEgYm9keSBvem5hxI11asO6IGV4dHLDqW15IGliYSByYXogemEgMzAgZG7DrS4gCgpUYWvDoXRvIHZpenVhbGl6w6FjaWEgdW1vxb7FiHVqZSBwcmVoxL5hZG5lasWhaWUgc2xlZG92YW5pZSB0cmVuZG92IGEgdmFyaWFiaWxpdHUgdGVwbG90eSB2IMSNYXNlIGJleiB6YWhsdGVuaWEgZ3JhZnUgcHLDrWxpxaEgdmXEvmvDvW0gbW5vxb5zdHZvbSBib2Rvdi4KCiMjIEtvcmVsYcSNbsOhIG1hdGljYSAtIEJ1ZGFwZcWhxaUKCmBgYHtyfQpidWRhcGVzdF9kYXRhIDwtIHVkYWplICU+JQogIHNlbGVjdChCVURBUEVTVF90ZW1wX21heCwgQlVEQVBFU1RfaHVtaWRpdHksIEJVREFQRVNUX3ByZXNzdXJlLCAKICAgICAgICAgQlVEQVBFU1Rfc3Vuc2hpbmUsIEJVREFQRVNUX2dsb2JhbF9yYWRpYXRpb24sIEJVREFQRVNUX3ByZWNpcGl0YXRpb24sIAogICAgICAgICApCgpjb3JfbWF0cml4X2J1ZGFwZXN0IDwtIGNvcihidWRhcGVzdF9kYXRhLCB1c2UgPSAiY29tcGxldGUub2JzIikKCmxpYnJhcnkoY29ycnBsb3QpCmNvcnJwbG90KGNvcl9tYXRyaXhfYnVkYXBlc3QsIG1ldGhvZCA9ICJjb2xvciIsIHR5cGUgPSAidXBwZXIiLCAKICAgICAgICAgdGwuY29sID0gImJsYWNrIiwgdGwuc3J0ID0gNDUsIGFkZENvZWYuY29sID0gImJsYWNrIiwKICAgICAgICAgdGl0bGUgPSAiS29yZWxhxI1uw6EgbWF0aWNhIC0gQnVkYXBlxaHFpSIsIG1hciA9IGMoMCwwLDIsMCkpCmBgYApLb3JlbGHEjW7DoSBtYXRpY2Egem9icmF6dWplIHZ6xaVhaHkgbWVkemkgdnlicmFuw71taSBtZXRlb3JvbG9naWNrw71taSBwcmVtZW5uw71taSB2IG1lc3RlIEJ1ZGFwZcWhxaU6IG1heGltw6Fsbm91IHRlcGxvdG91IHZ6ZHVjaHUsIHZsaGtvc8Wlb3UsIHRsYWtvbSwgc2xuZcSNbsO9bSBzdml0b20sIGdsb2LDoWxub3UgcmFkacOhY2lvdSBhIG1ub8W+c3R2b20genLDocW+b2suCk1lZHppIGplZG5vdGxpdsO9bWkgcHJlbWVubsO9bWkgbW/Fvm5vIHBvem9yb3ZhxaUgbmlla2/EvmtvIHbDvXJhem7DvWNoIGtvcmVsw6FjacOtOgoKTWF4aW3DoWxuYSB0ZXBsb3RhIChCVURBUEVTVF90ZW1wX21heCkgbcOhIHNpbG7DuiBwb3ppdMOtdm51IGtvcmVsw6FjaXUgc28gc2xuZcSNbsO9bSBzdml0b20gKHIgPSAwLjY1KSBhIGdsb2LDoWxub3UgcmFkacOhY2lvdSAociA9IDAuNzkpLiBUbyB6bmFtZW7DoSwgxb5lIHMgcmFzdMO6Y2ltIG1ub8W+c3R2b20gc2xuZcSNbsOpaG8gxb5pYXJlbmlhIGEgZMS6xb5rb3Ugc2xuZcSNbsOpaG8gc3ZpdHUgcmFzdGllIGFqIHRlcGxvdGEuCgpNZWR6aSB0ZXBsb3RvdSBhIHZsaGtvc8Wlb3Ugc2EgbmFjaMOhZHphIG5lZ2F0w612bmEga29yZWzDoWNpYSAociA9IC0wLjU1KSwgxI1vIG5hem5hxI11amUsIMW+ZSBwb8SNYXMgdmxoa8O9Y2ggZG7DrSBiw712YWrDuiB0ZXBsb3R5IHNwcmF2aWRsYSBuacW+xaFpZS4KClRsYWsgdnpkdWNodSB2eWthenVqZSBsZW4gc2xhYsOpIHZ6xaVhaHkgcyBvc3RhdG7DvW1pIHByZW1lbm7DvW1pIChob2Rub3R5IG9rb2xvIDAuMeKAkzAuMiksIMSNbyB6bmFtZW7DoSwgxb5lIHRsYWsgbcOhIG5hIGRlbm7DuiB0ZXBsb3R1IGEgb3N0YXRuw6kgdWthem92YXRlbGUgaWJhIG1hbMO9IHZwbHl2LgoKU2xuZcSNbsO9IHN2aXQgYSBnbG9iw6FsbmEgcmFkacOhY2lhIHPDuiBtZWR6aSBzZWJvdSB2ZcS+bWkgc2lsbm8gcG96aXTDrXZuZSBrb3JlbG92YW7DqSAociA9IDAuODkpLCDEjW8gamUgb8SNYWvDoXZhbsOpLCBrZcSPxb5lIG9iYSBmYWt0b3J5IHPDunZpc2lhIHMgaW50ZW56aXRvdSBzbG5lxI1uw6lobyDFvmlhcmVuaWEuCgpacsOhxb5reSAoQlVEQVBFU1RfcHJlY2lwaXRhdGlvbikgbWFqw7ogc2xhYsOpIGHFviBtaWVybmUgbmVnYXTDrXZuZSBrb3JlbMOhY2llIHMgdsOkxI3FoWlub3Ugb3N0YXRuw71jaCB1a2F6b3ZhdGXEvm92IChuYXByLiBzIHRlcGxvdG91IHIgPSAtMC4wMSwgcyByYWRpw6FjaW91IHIgPSAtMC4xNiksIMSNbyBwb3R2cmR6dWplLCDFvmUgcG/EjWFzIGRhxb5kaXbDvWNoIGRuw60gYsO9dmEgbWVuZWogc2xua2EgYSB0ZXBsb3R5IHPDuiBuacW+xaFpZS4KCkNlbGtvdm8gbWF0aWNhIHBvdHZyZHp1amUgb8SNYWvDoXZhbsOpIHZ6xaVhaHkgbWVkemkgbWV0ZW9yb2xvZ2lja8O9bWkgdWthem92YXRlxL5taSDigJMgdnnFocWhaWUgdGVwbG90eSBzw7ogc3BvamVuw6kgcyB2ecWhxaFvdSBpbnRlbnppdG91IHNsbmXEjW7DqWhvIMW+aWFyZW5pYSwgemF0aWHEviDEjW8genbDvcWhZW7DoSB2bGhrb3PFpSBhIHpyw6HFvmt5IHByaXNwaWV2YWrDuiBrIGljaCBwb2tsZXN1Lg==