knitr::opts_chunk$set(
echo = TRUE,
message = FALSE,
warning = FALSE
)
install.packages(c(
"tidyverse",
"readr",
"dplyr",
"ggplot2",
"knitr",
"kableExtra",
"broom",
"stringr",
"corrplot"
), dependencies = TRUE)
Import údajov z .csv
library(readr)
Indian_water_data <- read_csv("Indian_water_data.csv")
head(Indian_water_data)
colnames(Indian_water_data)
[1] "STN code"
[2] "Monitoring Location"
[3] "Year"
[4] "Type Water Body"
[5] "State Name"
[6] "Temperature (C) - Min"
[7] "Temperature (C) - Max"
[8] "Dissolved - Min"
[9] "Dissolved - Max"
[10] "pH - Min"
[11] "pH - Max"
[12] "Conductivity (µmho/cm) - Min"
[13] "Conductivity (µmho/cm) - Max"
[14] "BOD (mg/L) - Min"
[15] "BOD (mg/L) - Max"
[16] "NitrateN (mg/L) - Min"
[17] "NitrateN (mg/L) - Max"
[18] "Fecal Coliform (MPN/100ml) - Min"
[19] "Fecal Coliform (MPN/100ml) - Max"
[20] "Total Coliform (MPN/100ml) - Min"
[21] "Total Coliform (MPN/100ml) - Max"
[22] "Fecal - Min"
[23] "Fecal - Max"
Grafy
Scatter plot
library(dplyr)
library(ggplot2)
# Filter pre rok 2021
water_2021 <- Indian_water_data %>% filter(Year == 2021)
# Scatterplot s farbami a vylepšením
ggplot(water_2021, aes(x = `BOD (mg/L) - Max`, y = `Dissolved - Max`)) +
geom_point(aes(color = Year), size = 3) +
scale_color_gradient(low = "blue", high = "red") + # Farebné zobrazenie bodov
theme_minimal() +
labs(
title = "Vzťah medzi znečistením a kvalitou vody v roku 2021",
x = "BOD (mg/L) - Max (Biochemical Oxygen Demand)",
y = "Dissolved - Max (Rozpustený kyslík)"
) +
theme(legend.position = "bottom") # Pridanie legendy

Tento graf nám ukazuje vzťah medzi dvoma premennými:
- BOD (Biochemical Oxygen Demand), čo je indikátor
znečistenia vody, meraný ako množstvo kyslíka, ktoré mikroorganizmy
spotrebujú na rozklad organických látok vo vode. Vysoká hodnota BOD
naznačuje, že voda je viac znečistená.
- Dissolved Oxygen (Rozpustený kyslík), čo je
množstvo kyslíka rozpusteného vo vode. Tento ukazovateľ je dôležitý pre
kvalitu vody, pretože mnohé vodné organizmy potrebujú kyslík na
prežitie. Nižšie hodnoty rozpusteného kyslíka môžu naznačovať zhoršenú
kvalitu vody.
Interpretácia grafu
- Väčšina hodnôt pre rozpustený kyslík (Dissolved -
Max) je v rozmedzí 5 - 10 mg/L, čo je bežná
úroveň pre vodu v dobrom stave. Tieto hodnoty sú dostatočné na prežitie
väčšiny vodných organizmov.
- Vysoké hodnoty BOD (až do 80 mg/L)
sú zriedkavé a indikujú, že v daných miestach môže byť voda silne
znečistená (môže to byť spôsobené napríklad vysokým množstvom
organického odpadu).
- Neexistuje výrazný vzťah medzi BOD a rozpusteným
kyslíkom, čo naznačuje, že aj keď vysoký BOD zvyčajne vedie k
nižšiemu obsahu kyslíka, v tomto prípade to nie je úplne jednoznačné.
Možno existujú aj ďalšie faktory, ktoré ovplyvňujú koncentráciu kyslíka
vo vode (napríklad teplota vody alebo iné chemické vlastnosti).
Záver
- Tento graf ukazuje, že vo väčšine pozorovaných dát za rok 2021 je
voda s dostatočným množstvom kyslíka, ale niektoré miesta s vysokým BOD
by mohli naznačovať zhoršenú kvalitu vody, najmä tam, kde sú hodnoty BOD
veľmi vysoké.
- Nie je jasný lineárny vzťah medzi znečistením vody a množstvom
kyslíka, čo naznačuje, že iné faktory môžu ovplyvňovať kvalitu
vody.
Boxplot
ggplot(Indian_water_data, aes(x = factor(Year), y = `Dissolved - Max`, fill = factor(Year))) +
geom_boxplot(color = "black", alpha = 0.6) +
scale_fill_brewer(palette = "Set3") + # Farebné nastavenie
theme_minimal() +
labs(
title = "Boxplot rozpusteného kyslíka podľa rokov",
x = "Rok",
y = "Dissolved - Max (Rozpustený kyslík)"
)

Na tomto grafe je zobrazený boxplot pre hodnoty
rozpusteného kyslíka (Dissolved - Max) v rokoch
2021, 2022, a 2023.
Popis grafu
- Osa x: roky 2021, 2022, a 2023.
- Osa y: hodnoty rozpusteného kyslíka medzi 5
a 10 mg/L.
- Každý boxplot ukazuje:
- Medián (stredná čierna čiara) pre daný rok.
- 25. a 75. percentil (horný a dolný okraj
boxu).
- Whiskers (čiary mimo boxu) ukazujú rozsah
hodnôt.
- Outliers (body mimo whiskers) sú odľahlé
hodnoty.
Interpretácia grafu
- 2021: Najnižší medián rozpusteného kyslíka.
Vyskytujú sa odľahlé hodnoty.
- 2022: Hodnoty podobné 2021, ale s vyššou
variabilitou. Odľahlé hodnoty nie sú také extrémne.
- 2023: Najvyšší medián, lepšia kvalita vody, vyššie
hodnoty kyslíka. Odľahlé hodnoty sú menej výrazné.
Záver
- 2023 vykazuje lepšiu kvalitu vody s vyššími
hodnotami kyslíka.
- 2022 má najvyššiu variabilitu, čo naznačuje zmeny v
podmienkach.
- Odľahlé hodnoty v 2021 a 2022 môžu
naznačovať miestne znečistenie alebo špecifické udalosti.
Graf naznačuje zlepšenie kvality vody v roku 2023, ale stále sú
prítomné odchýlky, ktoré si vyžadujú ďalšiu analýzu.
Heatmapa korelácie
Heatmap korelácie medzi BOD, Dissolved a Teplotou
# Vytvorenie korelačnej matice
cor_matrix <- cor(Indian_water_data[, c("BOD (mg/L) - Max", "Dissolved - Max", "Temperature (C) - Max")], use = "complete.obs")
# Vytvorenie heatmapy korelácie
corrplot(cor_matrix, method = "color", type = "upper", tl.col = "black", tl.srt = 20, col = colorRampPalette(c("blue", "white", "red"))(50))

Tento graf zobrazuje heatmapu korelácie medzi tromi
premennými:
- BOD (mg/L) - Max (Biochemical Oxygen Demand)
- Dissolved - Max (Rozpustený kyslík)
- Temperature (C) - Max (Teplota vody)
Popis grafu
- Farebné bloky ukazujú koreláciu medzi jednotlivými
premennými.
- Korelácie sú zobrazené v rozsahu od -1 do 1, kde:
- Červená farba znamená silnú pozitívnu
koreláciu (t.j. hodnoty rastú spolu).
- Modrá farba znamená negatívnu
koreláciu (t.j. hodnoty rastú opačne).
- Biela farba znamená slabú alebo žiadnu
koreláciu.
Interpretácia grafu
- BOD vs Dissolved - Max: Korelácia je silne
negatívna (červená farba), čo znamená, že vyššie hodnoty BOD sú
spojené s nižšími hodnotami rozpusteného kyslíka.
- BOD vs Temperature: Korelácia je tiež silne
negatívna, čo naznačuje, že vyššie teploty môžu byť spojené s
vyšším BOD.
- Dissolved - Max vs Temperature: Korelácia je
slabá až nulová (biela farba), čo naznačuje, že teplota
nemá výrazný vplyv na množstvo rozpusteného kyslíka.
Tento graf nám teda ukazuje, že znečistenie vody
(BOD) je negatívne korelované s kvalitou vody
(rozpustený kyslík) a teplotou vody.
Základné štatistiky
library(dplyr)
library(knitr)
library(kableExtra)
# základné štatistiky podľa roku
water.stats <- Indian_water_data %>%
group_by(Year) %>%
summarise(
n = n(),
mean = mean(`Dissolved - Max`, na.rm = TRUE),
sd = sd(`Dissolved - Max`, na.rm = TRUE),
min = min(`Dissolved - Max`, na.rm = TRUE),
q25 = quantile(`Dissolved - Max`, 0.25, na.rm = TRUE),
median = median(`Dissolved - Max`, na.rm = TRUE),
q75 = quantile(`Dissolved - Max`, 0.75, na.rm = TRUE),
max = max(`Dissolved - Max`, na.rm = TRUE),
.groups = "drop"
)
# Create styled kableExtra table
water.stats %>%
kable(
digits = 2,
caption = "Základné štatistiky pre Dissolved - Max (Rozpustený kyslík) podľa rokov"
) %>%
kable_styling(
full_width = FALSE,
bootstrap_options = c("striped", "hover", "condensed")
) %>%
column_spec(1, bold = TRUE) %>% # Zvýrazní prvý stĺpec (Year)
row_spec(0, bold = TRUE, background = "#f2f2f2") # Štýl hlavičky
Základné štatistiky pre Dissolved - Max (Rozpustený kyslík) podľa rokov
| Year |
n |
mean |
sd |
min |
q25 |
median |
q75 |
max |
| 2021 |
44 |
7.80 |
1.70 |
1.4 |
6.90 |
8.00 |
9.40 |
10.2 |
| 2022 |
53 |
7.86 |
1.75 |
2.9 |
7.00 |
7.80 |
8.50 |
13.6 |
| 2023 |
97 |
7.47 |
1.88 |
1.1 |
6.18 |
7.75 |
8.72 |
11.0 |
Na tejto tabuľke sú uvedené základné štatistiky pre hodnoty
Dissolved - Max (Rozpustený kyslík) podľa rokov
(2021, 2022, 2023). Z
týchto štatistík môžeme vyčítať niekoľko kľúčových informácií:
- Priemerné hodnoty rozpusteného kyslíka klesli z
7.80 mg/L v roku 2021 na 7.47 mg/L v
roku 2023.
- Variabilita (štandardná odchýlka) sa zvyšuje, čo
naznačuje väčšiu rozmanitosť hodnôt v roku 2023 v porovnaní s
predchádzajúcimi rokmi.
- Minimálne hodnoty v roku 2023 boli
najnižšie, čo naznačuje nižšiu kvalitu vody v určitých
miestach.
- Medián a 75. percentil naznačujú, že väčšina hodnôt
rozpusteného kyslíka sa pohybovala vo vyšších hodnotách v rokoch
2021 a 2022, zatiaľ čo v roku
2023 sa hodnoty trochu znížili.
Táto tabuľka poskytuje užitočné štatistiky na hodnotenie
kvality vody v priebehu týchto troch rokov.
Testovanie hypotéz
t-test: Porovnanie priemeru Temperature (C) - Max v rokoch 2021 a
2023
library(kableExtra)
# Vykonanie t-testu
t.test.result <- t.test(
Indian_water_data$`Temperature (C) - Max`[Indian_water_data$Year == 2021],
Indian_water_data$`Temperature (C) - Max`[Indian_water_data$Year == 2023]
)
# Vytvorenie tabuľky s výsledkami t-testu
t.test.summary <- data.frame(
Statistic = c("t-statistic", "df", "p-value", "confidence interval (lower)", "confidence interval (upper)"),
Value = c(t.test.result$statistic,
t.test.result$parameter,
t.test.result$p.value,
t.test.result$conf.int[1],
t.test.result$conf.int[2])
)
# Zobrazenie tabuľky s kableExtra
t.test.summary %>%
kable(caption = "Výsledky t-testu medzi rokmi 2021 a 2023 pre teplotu (C) - Max") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>%
column_spec(1, bold = TRUE) %>%
row_spec(0, bold = TRUE, background = "#f2f2f2")
Výsledky t-testu medzi rokmi 2021 a 2023 pre teplotu (C) - Max
| Statistic |
Value |
| t-statistic |
-0.6440985 |
| df |
115.7404340 |
| p-value |
0.5207859 |
| confidence interval (lower) |
-3.0826538 |
| confidence interval (upper) |
1.5697351 |
Táto tabuľka zobrazuje výsledky t-testu medzi rokmi
2021 a 2023 pre hodnoty
teploty (C) - Max. Z týchto výsledkov môžeme
vyčítať:
Výsledky
- t-statistic: Hodnota t-testu je
-0.6441, čo naznačuje, že rozdiel medzi priemernými
hodnotami teploty v rokoch 2021 a 2023 nie je veľký.
- df (degrees of freedom): Počet stupňov voľnosti je
115.74, čo je kombinovaná veľkosť oboch vzoriek.
- p-value: Hodnota p = 0.5208, ktorá
je vyššia ako prah 0.05, znamená, že rozdiel medzi
rokmi 2021 a 2023 nie je štatisticky významný.
- confidence interval (lower): Dolná hranica
konfidenčného intervalu je -3.0827.
- confidence interval (upper): Horná hranica
konfidenčného intervalu je 1.5697.
Záver
Na základe p-hodnoty 0.5208 a konfidenčného
intervalu, ktorý zahŕňa záporné aj kladné hodnoty, môžeme
povedať, že rozdiel medzi teplotami v rokoch 2021 a 2023 nie je
štatisticky významný. To znamená, že neexistuje dostatočný
dôkaz, že by sa teplota medzi týmito dvoma rokmi výrazne menila.
ANOVA
library(kableExtra)
# Vykonanie ANOVA testu
anova.result <- aov(`Temperature (C) - Max` ~ factor(Year), data = Indian_water_data)
# Zhrnutie výsledkov ANOVA
anova.summary <- summary(anova.result)[[1]]
# Vytvorenie tabuľky s výsledkami ANOVA
anova.table <- data.frame(
Df = anova.summary$Df,
Sum_Sq = anova.summary$`Sum Sq`,
Mean_Sq = anova.summary$`Mean Sq`,
F_value = anova.summary$`F value`,
Pr_F = anova.summary$`Pr(>F)`
)
# Zobrazenie tabuľky s kableExtra
anova.table %>%
kable(caption = "Výsledky ANOVA testu pre teplotu (C) - Max podľa rokov") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>%
column_spec(1, bold = TRUE) %>%
row_spec(0, bold = TRUE, background = "#f2f2f2")
Výsledky ANOVA testu pre teplotu (C) - Max podľa rokov
| Df |
Sum_Sq |
Mean_Sq |
F_value |
Pr_F |
| 2 |
78.3076 |
39.15380 |
0.9008998 |
0.407941 |
| 189 |
8214.0849 |
43.46077 |
NA |
NA |
Táto tabuľka zobrazuje výsledky ANOVA testu pre
teplotu (C) - Max podľa rokov.
Výsledky
- Df (degrees of freedom):
- 2 pre medzi-skupinovú variabilitu (roky).
- 189 pre vnútor-skupinovú variabilitu (počet pozorovaní - 1).
- Sum_Sq (Sum of Squares):
- Pre medzi-skupinovú variabilitu je 78.3076.
- Pre vnútor-skupinovú variabilitu je 8214.0849.
- Mean_Sq (Mean Square):
- Pre medzi-skupinovú variabilitu je 39.1538.
- Pre vnútor-skupinovú variabilitu je 43.4608.
- F_value: Hodnota F testu je
0.9009, čo naznačuje, že rozdiel medzi skupinami
(rokmi) nie je výrazný.
- Pr_F (p-value): Hodnota p je
0.4079, čo je vyššie než bežný prah
0.05, takže rozdiel medzi rokmi nie je
štatisticky významný.
Záver
Na základe výsledkov ANOVA testu môžeme uzavrieť, že rozdiel
medzi teplotami v rokoch 2021 a 2023 nie je štatisticky
významný. To znamená, že na základe týchto údajov nemáme dôkaz,
že by sa teplota medzi týmito dvoma rokmi líšila.
Linear Regression
library(kableExtra)
# Vykonanie lineárnej regresie
model <- lm(`BOD (mg/L) - Max` ~ `Temperature (C) - Max`, data = Indian_water_data)
# Zhrnutie modelu
model.summary <- summary(model)
# Vytvorenie tabuľky s výsledkami lineárnej regresie
model.table <- data.frame(
Term = rownames(model.summary$coefficients),
Estimate = model.summary$coefficients[, 1],
Std_Error = model.summary$coefficients[, 2],
t_value = model.summary$coefficients[, 3],
Pr_t = model.summary$coefficients[, 4]
)
# Zobrazenie tabuľky s kableExtra
model.table %>%
kable(caption = "Výsledky lineárnej regresie medzi BOD (mg/L) - Max a Teplotou (C) - Max") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>%
column_spec(1, bold = TRUE) %>%
row_spec(0, bold = TRUE, background = "#f2f2f2")
Výsledky lineárnej regresie medzi BOD (mg/L) - Max a Teplotou (C) - Max
| |
Term |
Estimate |
Std_Error |
t_value |
Pr_t |
| (Intercept) |
(Intercept) |
3.2019962 |
3.2534658 |
0.9841801 |
0.3263780 |
| `Temperature (C) - Max` |
`Temperature (C) - Max` |
0.0638972 |
0.1144106 |
0.5584905 |
0.5772193 |
Táto tabuľka zobrazuje výsledky lineárnej regresie
medzi BOD (mg/L) - Max a Teplotou (C) -
Max.
Výsledky
- (Intercept): Koeficient pre intercept (priesečník s
osou Y) je 3.2019962. To znamená, že keď teplota je
0°C, predpokladaná hodnota BOD je približne 3.2
mg/L.
- Temperature (C) - Max: Koeficient pre teplotu je
0.0638972, čo naznačuje, že pri každom zvýšení teploty
o 1°C sa hodnota BOD zvýši približne o 0.064
mg/L.
- Std_Error: Štandardná chyba koeficientov, ktorá
meria variabilitu odhadovaných hodnôt:
- Pre intercept je 3.2534658.
- Pre teplotu je 0.1144106.
- t_value: Testová hodnota (t-hodnota) pre obidve
premenné:
- Pre intercept je 0.9841801.
- Pre teplotu je 0.5584905. Tieto hodnoty naznačujú,
že t-test pre obe premenné nie je veľmi silný.
- Pr_t (p-value): P-hodnota pre oba koeficienty:
- Pre intercept je 0.3263780.
- Pre teplotu je 0.5772193. Obidve p-hodnoty sú
vyššie než bežný prah 0.05, čo znamená, že
rozdiely medzi BOD a teplotou nie sú štatisticky
významné.
Záver
Výsledky regresie naznačujú, že neexistuje štatisticky
významný vzťah medzi teplotou a BOD, pretože p-hodnoty sú
väčšie než 0.05. To znamená, že na základe týchto údajov nemáme
dostatočný dôkaz, že by zmena teploty mala významný vplyv na hodnoty
BOD.
LS0tCnRpdGxlOiAiUHLDoWNhIHMgZGF0YWLDoXpvdSAtIGltcG9ydCDDumRham92LCBncmFmeSwgxaF0YXRpc3Rpa3kiCmF1dGhvcjogIlPDoXJhIE5pa29sIFNjaG9sdHpvdsOhIgpkYXRlOiAiT2t0w7NiZXIgMjAyNSIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRoZW1lOiB1bml0ZWQKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIGNzczogc3R5bGUuY3NzCmVkaXRvcl9vcHRpb25zOiAKICBtYXJrZG93bjogCiAgICB3cmFwOiA3MgotLS0KYGBge3J9CmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICAgIGVjaG8gPSBUUlVFLAogICAgbWVzc2FnZSA9IEZBTFNFLAogICAgd2FybmluZyA9IEZBTFNFCikKYGBgCgpgYGB7cn0KaW5zdGFsbC5wYWNrYWdlcyhjKAogICJ0aWR5dmVyc2UiLAogICJyZWFkciIsCiAgImRwbHlyIiwKICAiZ2dwbG90MiIsCiAgImtuaXRyIiwKICAia2FibGVFeHRyYSIsCiAgImJyb29tIiwKICAic3RyaW5nciIsCiAgImNvcnJwbG90IgopLCBkZXBlbmRlbmNpZXMgPSBUUlVFKQpgYGAKIyMgSW1wb3J0IMO6ZGFqb3YgeiAuY3N2CmBgYHtyfQpsaWJyYXJ5KHJlYWRyKQpJbmRpYW5fd2F0ZXJfZGF0YSA8LSByZWFkX2NzdigiSW5kaWFuX3dhdGVyX2RhdGEuY3N2IikKaGVhZChJbmRpYW5fd2F0ZXJfZGF0YSkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKY29sbmFtZXMoSW5kaWFuX3dhdGVyX2RhdGEpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKYGBgCgojIEdyYWZ5CgojIyBTY2F0dGVyIHBsb3QKYGBge3J9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKCiMgRmlsdGVyIHByZSByb2sgMjAyMQoKd2F0ZXJfMjAyMSA8LSBJbmRpYW5fd2F0ZXJfZGF0YSAlPiUgZmlsdGVyKFllYXIgPT0gMjAyMSkKCiMgU2NhdHRlcnBsb3QgcyBmYXJiYW1pIGEgdnlsZXDFoWVuw61tCgpnZ3Bsb3Qod2F0ZXJfMjAyMSwgYWVzKHggPSBgQk9EIChtZy9MKSAtIE1heGAsIHkgPSBgRGlzc29sdmVkIC0gTWF4YCkpICsKZ2VvbV9wb2ludChhZXMoY29sb3IgPSBZZWFyKSwgc2l6ZSA9IDMpICsKc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gImJsdWUiLCBoaWdoID0gInJlZCIpICsgICMgRmFyZWJuw6kgem9icmF6ZW5pZSBib2Rvdgp0aGVtZV9taW5pbWFsKCkgKwpsYWJzKAp0aXRsZSA9ICJWesWlYWggbWVkemkgem5lxI1pc3RlbsOtbSBhIGt2YWxpdG91IHZvZHkgdiByb2t1IDIwMjEiLAp4ID0gIkJPRCAobWcvTCkgLSBNYXggKEJpb2NoZW1pY2FsIE94eWdlbiBEZW1hbmQpIiwKeSA9ICJEaXNzb2x2ZWQgLSBNYXggKFJvenB1c3RlbsO9IGt5c2zDrWspIgopICsKdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICAjIFByaWRhbmllIGxlZ2VuZHkKYGBgClRlbnRvIGdyYWYgbsOhbSB1a2F6dWplIHZ6xaVhaCBtZWR6aSBkdm9tYSBwcmVtZW5uw71taToKCi0gKipCT0QgKEJpb2NoZW1pY2FsIE94eWdlbiBEZW1hbmQpKiosIMSNbyBqZSBpbmRpa8OhdG9yIHpuZcSNaXN0ZW5pYSB2b2R5LCBtZXJhbsO9IGFrbyBtbm/FvnN0dm8ga3lzbMOta2EsIGt0b3LDqSBtaWtyb29yZ2FuaXpteSBzcG90cmVidWrDuiBuYSByb3prbGFkIG9yZ2FuaWNrw71jaCBsw6F0b2sgdm8gdm9kZS4gVnlzb2vDoSBob2Rub3RhIEJPRCBuYXpuYcSNdWplLCDFvmUgdm9kYSBqZSB2aWFjIHpuZcSNaXN0ZW7DoS4KLSAqKkRpc3NvbHZlZCBPeHlnZW4gKFJvenB1c3RlbsO9IGt5c2zDrWspKiosIMSNbyBqZSBtbm/FvnN0dm8ga3lzbMOta2Egcm96cHVzdGVuw6lobyB2byB2b2RlLiBUZW50byB1a2F6b3ZhdGXEviBqZSBkw7RsZcW+aXTDvSBwcmUga3ZhbGl0dSB2b2R5LCBwcmV0b8W+ZSBtbm9ow6kgdm9kbsOpIG9yZ2FuaXpteSBwb3RyZWJ1asO6IGt5c2zDrWsgbmEgcHJlxb5pdGllLiBOacW+xaFpZSBob2Rub3R5IHJvenB1c3RlbsOpaG8ga3lzbMOta2EgbcO0xb51IG5hem5hxI1vdmHFpSB6aG9yxaFlbsO6IGt2YWxpdHUgdm9keS4KCiMjIyBJbnRlcnByZXTDoWNpYSBncmFmdQoKLSBWw6TEjcWhaW5hIGhvZG7DtHQgcHJlICoqcm96cHVzdGVuw70ga3lzbMOtayAoRGlzc29sdmVkIC0gTWF4KSoqIGplIHYgcm96bWVkesOtICoqNSAtIDEwIG1nL0wqKiwgxI1vIGplIGJlxb5uw6Egw7pyb3ZlxYggcHJlIHZvZHUgdiBkb2Jyb20gc3RhdmUuIFRpZXRvIGhvZG5vdHkgc8O6IGRvc3RhdG/EjW7DqSBuYSBwcmXFvml0aWUgdsOkxI3FoWlueSB2b2Ruw71jaCBvcmdhbml6bW92LgotICoqVnlzb2vDqSBob2Rub3R5IEJPRCoqIChhxb4gZG8gKio4MCBtZy9MKiopIHPDuiB6cmllZGthdsOpIGEgaW5kaWt1asO6LCDFvmUgdiBkYW7DvWNoIG1pZXN0YWNoIG3DtMW+ZSBiecWlIHZvZGEgc2lsbmUgem5lxI1pc3RlbsOhIChtw7TFvmUgdG8gYnnFpSBzcMO0c29iZW7DqSBuYXByw61rbGFkIHZ5c29rw71tIG1ub8W+c3R2b20gb3JnYW5pY2vDqWhvIG9kcGFkdSkuCi0gKipOZWV4aXN0dWplIHbDvXJhem7DvSB2esWlYWggbWVkemkgQk9EIGEgcm96cHVzdGVuw71tIGt5c2zDrWtvbSoqLCDEjW8gbmF6bmHEjXVqZSwgxb5lIGFqIGtlxI8gdnlzb2vDvSBCT0QgenZ5xI1ham5lIHZlZGllIGsgbmnFvsWhaWVtdSBvYnNhaHUga3lzbMOta2EsIHYgdG9tdG8gcHLDrXBhZGUgdG8gbmllIGplIMO6cGxuZSBqZWRub3puYcSNbsOpLiBNb8W+bm8gZXhpc3R1asO6IGFqIMSPYWzFoWllIGZha3RvcnksIGt0b3LDqSBvdnBseXbFiHVqw7oga29uY2VudHLDoWNpdSBreXNsw61rYSB2byB2b2RlIChuYXByw61rbGFkIHRlcGxvdGEgdm9keSBhbGVibyBpbsOpIGNoZW1pY2vDqSB2bGFzdG5vc3RpKS4KCiMjIyBaw6F2ZXIKCi0gVGVudG8gZ3JhZiB1a2F6dWplLCDFvmUgdm8gdsOkxI3FoWluZSBwb3pvcm92YW7DvWNoIGTDoXQgemEgcm9rIDIwMjEgamUgdm9kYSBzIGRvc3RhdG/EjW7DvW0gbW5vxb5zdHZvbSBreXNsw61rYSwgYWxlIG5pZWt0b3LDqSBtaWVzdGEgcyB2eXNva8O9bSBCT0QgYnkgbW9obGkgbmF6bmHEjW92YcWlIHpob3LFoWVuw7oga3ZhbGl0dSB2b2R5LCBuYWptw6QgdGFtLCBrZGUgc8O6IGhvZG5vdHkgQk9EIHZlxL5taSB2eXNva8OpLgotIE5pZSBqZSBqYXNuw70gbGluZcOhcm55IHZ6xaVhaCBtZWR6aSB6bmXEjWlzdGVuw61tIHZvZHkgYSBtbm/FvnN0dm9tIGt5c2zDrWthLCDEjW8gbmF6bmHEjXVqZSwgxb5lIGluw6kgZmFrdG9yeSBtw7TFvnUgb3ZwbHl2xYhvdmHFpSBrdmFsaXR1IHZvZHkuCgojIyBCb3hwbG90CmBgYHtyfQpnZ3Bsb3QoSW5kaWFuX3dhdGVyX2RhdGEsIGFlcyh4ID0gZmFjdG9yKFllYXIpLCB5ID0gYERpc3NvbHZlZCAtIE1heGAsIGZpbGwgPSBmYWN0b3IoWWVhcikpKSArCmdlb21fYm94cGxvdChjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC42KSArCnNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MyIpICsgICMgRmFyZWJuw6kgbmFzdGF2ZW5pZQp0aGVtZV9taW5pbWFsKCkgKwpsYWJzKAp0aXRsZSA9ICJCb3hwbG90IHJvenB1c3RlbsOpaG8ga3lzbMOta2EgcG9kxL5hIHJva292IiwKeCA9ICJSb2siLAp5ID0gIkRpc3NvbHZlZCAtIE1heCAoUm96cHVzdGVuw70ga3lzbMOtaykiCikKYGBgCk5hIHRvbXRvIGdyYWZlIGplIHpvYnJhemVuw70gKipib3hwbG90KiogcHJlIGhvZG5vdHkgKipyb3pwdXN0ZW7DqWhvIGt5c2zDrWthIChEaXNzb2x2ZWQgLSBNYXgpKiogdiByb2tvY2ggKioyMDIxLCAyMDIyLCBhIDIwMjMqKi4KCiMjIyBQb3BpcyBncmFmdQotICoqT3NhIHgqKjogcm9reSAyMDIxLCAyMDIyLCBhIDIwMjMuCi0gKipPc2EgeSoqOiBob2Rub3R5IHJvenB1c3RlbsOpaG8ga3lzbMOta2EgbWVkemkgKio1IGEgMTAgbWcvTCoqLgotIEthxb5kw70gYm94cGxvdCB1a2F6dWplOgogIC0gKipNZWRpw6FuKiogKHN0cmVkbsOhIMSNaWVybmEgxI1pYXJhKSBwcmUgZGFuw70gcm9rLgogIC0gKioyNS4gYSA3NS4gcGVyY2VudGlsKiogKGhvcm7DvSBhIGRvbG7DvSBva3JhaiBib3h1KS4KICAtICoqV2hpc2tlcnMqKiAoxI1pYXJ5IG1pbW8gYm94dSkgdWthenVqw7ogcm96c2FoIGhvZG7DtHQuCiAgLSAqKk91dGxpZXJzKiogKGJvZHkgbWltbyB3aGlza2Vycykgc8O6IG9kxL5haGzDqSBob2Rub3R5LgoKIyMjIEludGVycHJldMOhY2lhIGdyYWZ1Ci0gKioyMDIxKio6IE5ham5pxb7FocOtIG1lZGnDoW4gcm96cHVzdGVuw6lobyBreXNsw61rYS4gVnlza3l0dWrDuiBzYSBvZMS+YWhsw6kgaG9kbm90eS4KLSAqKjIwMjIqKjogSG9kbm90eSBwb2RvYm7DqSAyMDIxLCBhbGUgcyB2ecWhxaFvdSB2YXJpYWJpbGl0b3UuIE9kxL5haGzDqSBob2Rub3R5IG5pZSBzw7ogdGFrw6kgZXh0csOpbW5lLgotICoqMjAyMyoqOiBOYWp2ecWhxaHDrSBtZWRpw6FuLCBsZXDFoWlhIGt2YWxpdGEgdm9keSwgdnnFocWhaWUgaG9kbm90eSBreXNsw61rYS4gT2TEvmFobMOpIGhvZG5vdHkgc8O6IG1lbmVqIHbDvXJhem7DqS4KCiMjIyBaw6F2ZXIKLSAqKjIwMjMqKiB2eWthenVqZSBsZXDFoWl1IGt2YWxpdHUgdm9keSBzIHZ5xaHFocOtbWkgaG9kbm90YW1pIGt5c2zDrWthLgotICoqMjAyMioqIG3DoSBuYWp2ecWhxaFpdSB2YXJpYWJpbGl0dSwgxI1vIG5hem5hxI11amUgem1lbnkgdiBwb2RtaWVua2FjaC4KLSBPZMS+YWhsw6kgaG9kbm90eSB2ICoqMjAyMSoqIGEgKioyMDIyKiogbcO0xb51IG5hem5hxI1vdmHFpSBtaWVzdG5lIHpuZcSNaXN0ZW5pZSBhbGVibyDFoXBlY2lmaWNrw6kgdWRhbG9zdGkuCgpHcmFmIG5hem5hxI11amUgemxlcMWhZW5pZSBrdmFsaXR5IHZvZHkgdiByb2t1IDIwMjMsIGFsZSBzdMOhbGUgc8O6IHByw610b21uw6kgb2RjaMO9bGt5LCBrdG9yw6kgc2kgdnnFvmFkdWrDuiDEj2FsxaFpdSBhbmFsw716dS4KCiMjIEhlYXRtYXBhIGtvcmVsw6FjaWUKIyMjIEhlYXRtYXAga29yZWzDoWNpZSBtZWR6aSBCT0QsIERpc3NvbHZlZCBhIFRlcGxvdG91CmBgYHtyfQojIFZ5dHZvcmVuaWUga29yZWxhxI1uZWogbWF0aWNlIApjb3JfbWF0cml4IDwtIGNvcihJbmRpYW5fd2F0ZXJfZGF0YVssIGMoIkJPRCAobWcvTCkgLSBNYXgiLCAiRGlzc29sdmVkIC0gTWF4IiwgIlRlbXBlcmF0dXJlIChDKSAtIE1heCIpXSwgdXNlID0gImNvbXBsZXRlLm9icyIpIAojIFZ5dHZvcmVuaWUgaGVhdG1hcHkga29yZWzDoWNpZSAKY29ycnBsb3QoY29yX21hdHJpeCwgbWV0aG9kID0gImNvbG9yIiwgdHlwZSA9ICJ1cHBlciIsIHRsLmNvbCA9ICJibGFjayIsIHRsLnNydCA9IDIwLCBjb2wgPSBjb2xvclJhbXBQYWxldHRlKGMoImJsdWUiLCAid2hpdGUiLCAicmVkIikpKDUwKSkKYGBgClRlbnRvIGdyYWYgem9icmF6dWplICoqaGVhdG1hcHUga29yZWzDoWNpZSoqIG1lZHppIHRyb21pIHByZW1lbm7DvW1pOgoKLSAqKkJPRCAobWcvTCkgLSBNYXgqKiAoQmlvY2hlbWljYWwgT3h5Z2VuIERlbWFuZCkKLSAqKkRpc3NvbHZlZCAtIE1heCoqIChSb3pwdXN0ZW7DvSBreXNsw61rKQotICoqVGVtcGVyYXR1cmUgKEMpIC0gTWF4KiogKFRlcGxvdGEgdm9keSkKCiMjIyBQb3BpcyBncmFmdQotICoqRmFyZWJuw6kgYmxva3kqKiB1a2F6dWrDuiBrb3JlbMOhY2l1IG1lZHppIGplZG5vdGxpdsO9bWkgcHJlbWVubsO9bWkuCi0gS29yZWzDoWNpZSBzw7ogem9icmF6ZW7DqSB2IHJvenNhaHUgb2QgKiotMSBkbyAxKiosIGtkZToKICAtICoqxIxlcnZlbsOhIGZhcmJhKiogem5hbWVuw6EgKipzaWxuw7ogcG96aXTDrXZudSBrb3JlbMOhY2l1KiogKHQuai4gaG9kbm90eSByYXN0w7ogc3BvbHUpLgogIC0gKipNb2Ryw6EgZmFyYmEqKiB6bmFtZW7DoSAqKm5lZ2F0w612bnUga29yZWzDoWNpdSoqICh0LmouIGhvZG5vdHkgcmFzdMO6IG9wYcSNbmUpLgogIC0gKipCaWVsYSBmYXJiYSoqIHpuYW1lbsOhICoqc2xhYsO6IGFsZWJvIMW+aWFkbnUga29yZWzDoWNpdSoqLgogIAojIyMgSW50ZXJwcmV0w6FjaWEgZ3JhZnUKLSAqKkJPRCB2cyBEaXNzb2x2ZWQgLSBNYXgqKjogS29yZWzDoWNpYSBqZSAqKnNpbG5lIG5lZ2F0w612bmEqKiAoxI1lcnZlbsOhIGZhcmJhKSwgxI1vIHpuYW1lbsOhLCDFvmUgdnnFocWhaWUgaG9kbm90eSBCT0Qgc8O6IHNwb2plbsOpIHMgbmnFvsWhw61taSBob2Rub3RhbWkgcm96cHVzdGVuw6lobyBreXNsw61rYS4KLSAqKkJPRCB2cyBUZW1wZXJhdHVyZSoqOiBLb3JlbMOhY2lhIGplIHRpZcW+ICoqc2lsbmUgbmVnYXTDrXZuYSoqLCDEjW8gbmF6bmHEjXVqZSwgxb5lIHZ5xaHFoWllIHRlcGxvdHkgbcO0xb51IGJ5xaUgc3BvamVuw6kgcyB2ecWhxaHDrW0gQk9ELgotICoqRGlzc29sdmVkIC0gTWF4IHZzIFRlbXBlcmF0dXJlKio6IEtvcmVsw6FjaWEgamUgKipzbGFiw6EgYcW+IG51bG92w6EqKiAoYmllbGEgZmFyYmEpLCDEjW8gbmF6bmHEjXVqZSwgxb5lIHRlcGxvdGEgbmVtw6EgdsO9cmF6bsO9IHZwbHl2IG5hIG1ub8W+c3R2byByb3pwdXN0ZW7DqWhvIGt5c2zDrWthLgoKVGVudG8gZ3JhZiBuw6FtIHRlZGEgdWthenVqZSwgxb5lICoqem5lxI1pc3RlbmllIHZvZHkqKiAoQk9EKSBqZSBuZWdhdMOtdm5lIGtvcmVsb3ZhbsOpIHMgKiprdmFsaXRvdSB2b2R5KiogKHJvenB1c3RlbsO9IGt5c2zDrWspIGEgKip0ZXBsb3RvdSB2b2R5KiouCgojIFrDoWtsYWRuw6kgxaF0YXRpc3Rpa3kKCmBgYHtyfQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCgojIHrDoWtsYWRuw6kgxaF0YXRpc3Rpa3kgcG9kxL5hIHJva3UKCndhdGVyLnN0YXRzIDwtIEluZGlhbl93YXRlcl9kYXRhICU+JQpncm91cF9ieShZZWFyKSAlPiUKc3VtbWFyaXNlKApuICAgICAgPSBuKCksCm1lYW4gICA9IG1lYW4oYERpc3NvbHZlZCAtIE1heGAsIG5hLnJtID0gVFJVRSksCnNkICAgICA9IHNkKGBEaXNzb2x2ZWQgLSBNYXhgLCBuYS5ybSA9IFRSVUUpLAptaW4gICAgPSBtaW4oYERpc3NvbHZlZCAtIE1heGAsIG5hLnJtID0gVFJVRSksCnEyNSAgICA9IHF1YW50aWxlKGBEaXNzb2x2ZWQgLSBNYXhgLCAwLjI1LCBuYS5ybSA9IFRSVUUpLAptZWRpYW4gPSBtZWRpYW4oYERpc3NvbHZlZCAtIE1heGAsIG5hLnJtID0gVFJVRSksCnE3NSAgICA9IHF1YW50aWxlKGBEaXNzb2x2ZWQgLSBNYXhgLCAwLjc1LCBuYS5ybSA9IFRSVUUpLAptYXggICAgPSBtYXgoYERpc3NvbHZlZCAtIE1heGAsIG5hLnJtID0gVFJVRSksCi5ncm91cHMgPSAiZHJvcCIKKQoKIyBDcmVhdGUgc3R5bGVkIGthYmxlRXh0cmEgdGFibGUKCndhdGVyLnN0YXRzICU+JQprYWJsZSgKZGlnaXRzID0gMiwKY2FwdGlvbiA9ICJaw6FrbGFkbsOpIMWhdGF0aXN0aWt5IHByZSBEaXNzb2x2ZWQgLSBNYXggKFJvenB1c3RlbsO9IGt5c2zDrWspIHBvZMS+YSByb2tvdiIKKSAlPiUKa2FibGVfc3R5bGluZygKZnVsbF93aWR0aCA9IEZBTFNFLApib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIikKKSAlPiUKY29sdW1uX3NwZWMoMSwgYm9sZCA9IFRSVUUpICU+JSAgICAgICAgICAgICAgICAgICAgICMgWnbDvXJhem7DrSBwcnbDvSBzdMS6cGVjIChZZWFyKQpyb3dfc3BlYygwLCBib2xkID0gVFJVRSwgYmFja2dyb3VuZCA9ICIjZjJmMmYyIikgICAjIMWgdMO9bCBobGF2acSNa3kKYGBgCk5hIHRlanRvIHRhYnXEvmtlIHPDuiB1dmVkZW7DqSB6w6FrbGFkbsOpIMWhdGF0aXN0aWt5IHByZSBob2Rub3R5ICoqRGlzc29sdmVkIC0gTWF4KiogKFJvenB1c3RlbsO9IGt5c2zDrWspIHBvZMS+YSByb2tvdiAoKioyMDIxKiosICoqMjAyMioqLCAqKjIwMjMqKikuIFogdMO9Y2h0byDFoXRhdGlzdMOtayBtw7TFvmVtZSB2ecSNw610YcWlIG5pZWtvxL5rbyBrxL7DusSNb3bDvWNoIGluZm9ybcOhY2nDrToKCi0gKipQcmllbWVybsOpIGhvZG5vdHkgcm96cHVzdGVuw6lobyBreXNsw61rYSoqIGtsZXNsaSB6ICoqNy44MCBtZy9MKiogdiByb2t1IDIwMjEgbmEgKio3LjQ3IG1nL0wqKiB2IHJva3UgMjAyMy4KLSAqKlZhcmlhYmlsaXRhKiogKMWhdGFuZGFyZG7DoSBvZGNow71sa2EpIHNhIHp2ecWhdWplLCDEjW8gbmF6bmHEjXVqZSB2w6TEjcWhaXUgcm96bWFuaXRvc8WlIGhvZG7DtHQgdiByb2t1IDIwMjMgdiBwb3Jvdm5hbsOtIHMgcHJlZGNow6FkemFqw7pjaW1pIHJva21pLgotICoqTWluaW3DoWxuZSBob2Rub3R5KiogdiByb2t1IDIwMjMgYm9saSAqKm5ham5pxb7FoWllKiosIMSNbyBuYXpuYcSNdWplIG5pxb7FoWl1IGt2YWxpdHUgdm9keSB2IHVyxI1pdMO9Y2ggbWllc3RhY2guCi0gKipNZWRpw6FuIGEgNzUuIHBlcmNlbnRpbCoqIG5hem5hxI11asO6LCDFvmUgdsOkxI3FoWluYSBob2Ruw7R0IHJvenB1c3RlbsOpaG8ga3lzbMOta2Egc2EgcG9oeWJvdmFsYSB2byB2ecWhxaHDrWNoIGhvZG5vdMOhY2ggdiByb2tvY2ggKioyMDIxKiogYSAqKjIwMjIqKiwgemF0aWHEviDEjW8gdiByb2t1ICoqMjAyMyoqIHNhIGhvZG5vdHkgdHJvY2h1IHpuw63FvmlsaS4KClTDoXRvIHRhYnXEvmthIHBvc2t5dHVqZSB1xb5pdG/EjW7DqSDFoXRhdGlzdGlreSBuYSBob2Rub3RlbmllICoqa3ZhbGl0eSB2b2R5KiogdiBwcmllYmVodSB0w71jaHRvIHRyb2NoIHJva292LgoKIyBUZXN0b3ZhbmllIGh5cG90w6l6CgojIyB0LXRlc3Q6IFBvcm92bmFuaWUgcHJpZW1lcnUgVGVtcGVyYXR1cmUgKEMpIC0gTWF4IHYgcm9rb2NoIDIwMjEgYSAyMDIzCmBgYHtyfQpsaWJyYXJ5KGthYmxlRXh0cmEpCgojIFZ5a29uYW5pZSB0LXRlc3R1Cgp0LnRlc3QucmVzdWx0IDwtIHQudGVzdCgKSW5kaWFuX3dhdGVyX2RhdGEkYFRlbXBlcmF0dXJlIChDKSAtIE1heGBbSW5kaWFuX3dhdGVyX2RhdGEkWWVhciA9PSAyMDIxXSwKSW5kaWFuX3dhdGVyX2RhdGEkYFRlbXBlcmF0dXJlIChDKSAtIE1heGBbSW5kaWFuX3dhdGVyX2RhdGEkWWVhciA9PSAyMDIzXQopCgojIFZ5dHZvcmVuaWUgdGFidcS+a3kgcyB2w71zbGVka2FtaSB0LXRlc3R1Cgp0LnRlc3Quc3VtbWFyeSA8LSBkYXRhLmZyYW1lKApTdGF0aXN0aWMgPSBjKCJ0LXN0YXRpc3RpYyIsICJkZiIsICJwLXZhbHVlIiwgImNvbmZpZGVuY2UgaW50ZXJ2YWwgKGxvd2VyKSIsICJjb25maWRlbmNlIGludGVydmFsICh1cHBlcikiKSwKVmFsdWUgPSBjKHQudGVzdC5yZXN1bHQkc3RhdGlzdGljLAp0LnRlc3QucmVzdWx0JHBhcmFtZXRlciwKdC50ZXN0LnJlc3VsdCRwLnZhbHVlLAp0LnRlc3QucmVzdWx0JGNvbmYuaW50WzFdLAp0LnRlc3QucmVzdWx0JGNvbmYuaW50WzJdKQopCgojIFpvYnJhemVuaWUgdGFidcS+a3kgcyBrYWJsZUV4dHJhCgp0LnRlc3Quc3VtbWFyeSAlPiUKa2FibGUoY2FwdGlvbiA9ICJWw71zbGVka3kgdC10ZXN0dSBtZWR6aSByb2ttaSAyMDIxIGEgMjAyMyBwcmUgdGVwbG90dSAoQykgLSBNYXgiKSAlPiUKa2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIikpICU+JQpjb2x1bW5fc3BlYygxLCBib2xkID0gVFJVRSkgJT4lCnJvd19zcGVjKDAsIGJvbGQgPSBUUlVFLCBiYWNrZ3JvdW5kID0gIiNmMmYyZjIiKQpgYGAKVMOhdG8gdGFidcS+a2Egem9icmF6dWplIHbDvXNsZWRreSAqKnQtdGVzdHUqKiBtZWR6aSByb2ttaSAqKjIwMjEqKiBhICoqMjAyMyoqIHByZSBob2Rub3R5ICoqdGVwbG90eSAoQykgLSBNYXgqKi4gWiB0w71jaHRvIHbDvXNsZWRrb3YgbcO0xb5lbWUgdnnEjcOtdGHFpToKCiMjIyBWw71zbGVka3kKLSAqKnQtc3RhdGlzdGljKio6IEhvZG5vdGEgdC10ZXN0dSBqZSAqKi0wLjY0NDEqKiwgxI1vIG5hem5hxI11amUsIMW+ZSByb3pkaWVsIG1lZHppIHByaWVtZXJuw71taSBob2Rub3RhbWkgdGVwbG90eSB2IHJva29jaCAyMDIxIGEgMjAyMyBuaWUgamUgdmXEvmvDvS4KLSAqKmRmIChkZWdyZWVzIG9mIGZyZWVkb20pKio6IFBvxI1ldCBzdHVwxYhvdiB2b8S+bm9zdGkgamUgKioxMTUuNzQqKiwgxI1vIGplIGtvbWJpbm92YW7DoSB2ZcS+a29zxaUgb2JvY2ggdnpvcmllay4KLSAqKnAtdmFsdWUqKjogSG9kbm90YSAqKnAgPSAwLjUyMDgqKiwga3RvcsOhIGplIHZ5xaHFoWlhIGFrbyBwcmFoICoqMC4wNSoqLCB6bmFtZW7DoSwgxb5lIHJvemRpZWwgbWVkemkgcm9rbWkgMjAyMSBhIDIwMjMgbmllIGplIMWhdGF0aXN0aWNreSB2w716bmFtbsO9LgotICoqY29uZmlkZW5jZSBpbnRlcnZhbCAobG93ZXIpKio6IERvbG7DoSBocmFuaWNhIGtvbmZpZGVuxI1uw6lobyBpbnRlcnZhbHUgamUgKiotMy4wODI3KiouCi0gKipjb25maWRlbmNlIGludGVydmFsICh1cHBlcikqKjogSG9ybsOhIGhyYW5pY2Ega29uZmlkZW7EjW7DqWhvIGludGVydmFsdSBqZSAqKjEuNTY5NyoqLgoKIyMjIFrDoXZlcgpOYSB6w6FrbGFkZSAqKnAtaG9kbm90eSAwLjUyMDgqKiBhICoqa29uZmlkZW7EjW7DqWhvIGludGVydmFsdSoqLCBrdG9yw70gemFoxZXFiGEgesOhcG9ybsOpIGFqIGtsYWRuw6kgaG9kbm90eSwgbcO0xb5lbWUgcG92ZWRhxaUsIMW+ZSAqKnJvemRpZWwgbWVkemkgdGVwbG90YW1pIHYgcm9rb2NoIDIwMjEgYSAyMDIzIG5pZSBqZSDFoXRhdGlzdGlja3kgdsO9em5hbW7DvSoqLiBUbyB6bmFtZW7DoSwgxb5lIG5lZXhpc3R1amUgZG9zdGF0b8SNbsO9IGTDtGtheiwgxb5lIGJ5IHNhIHRlcGxvdGEgbWVkemkgdMO9bWl0byBkdm9tYSByb2ttaSB2w71yYXpuZSBtZW5pbGEuCgojIyBBTk9WQQpgYGB7cn0KbGlicmFyeShrYWJsZUV4dHJhKQoKIyBWeWtvbmFuaWUgQU5PVkEgdGVzdHUKCmFub3ZhLnJlc3VsdCA8LSBhb3YoYFRlbXBlcmF0dXJlIChDKSAtIE1heGAgfiBmYWN0b3IoWWVhciksIGRhdGEgPSBJbmRpYW5fd2F0ZXJfZGF0YSkKCiMgWmhybnV0aWUgdsO9c2xlZGtvdiBBTk9WQQoKYW5vdmEuc3VtbWFyeSA8LSBzdW1tYXJ5KGFub3ZhLnJlc3VsdClbWzFdXQoKIyBWeXR2b3JlbmllIHRhYnXEvmt5IHMgdsO9c2xlZGthbWkgQU5PVkEKCmFub3ZhLnRhYmxlIDwtIGRhdGEuZnJhbWUoCkRmID0gYW5vdmEuc3VtbWFyeSREZiwKU3VtX1NxID0gYW5vdmEuc3VtbWFyeSRgU3VtIFNxYCwKTWVhbl9TcSA9IGFub3ZhLnN1bW1hcnkkYE1lYW4gU3FgLApGX3ZhbHVlID0gYW5vdmEuc3VtbWFyeSRgRiB2YWx1ZWAsClByX0YgPSBhbm92YS5zdW1tYXJ5JGBQcig+RilgCikKCiMgWm9icmF6ZW5pZSB0YWJ1xL5reSBzIGthYmxlRXh0cmEKCmFub3ZhLnRhYmxlICU+JQprYWJsZShjYXB0aW9uID0gIlbDvXNsZWRreSBBTk9WQSB0ZXN0dSBwcmUgdGVwbG90dSAoQykgLSBNYXggcG9kxL5hIHJva292IikgJT4lCmthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIpKSAlPiUKY29sdW1uX3NwZWMoMSwgYm9sZCA9IFRSVUUpICU+JQpyb3dfc3BlYygwLCBib2xkID0gVFJVRSwgYmFja2dyb3VuZCA9ICIjZjJmMmYyIikKYGBgClTDoXRvIHRhYnXEvmthIHpvYnJhenVqZSB2w71zbGVka3kgKipBTk9WQSoqIHRlc3R1IHByZSB0ZXBsb3R1IChDKSAtIE1heCBwb2TEvmEgcm9rb3YuCgojIyMgVsO9c2xlZGt5CgotICoqRGYgKGRlZ3JlZXMgb2YgZnJlZWRvbSkqKjogCiAgLSAyIHByZSBtZWR6aS1za3VwaW5vdsO6IHZhcmlhYmlsaXR1IChyb2t5KS4KICAtIDE4OSBwcmUgdm7DunRvci1za3VwaW5vdsO6IHZhcmlhYmlsaXR1IChwb8SNZXQgcG96b3JvdmFuw60gLSAxKS4KLSAqKlN1bV9TcSAoU3VtIG9mIFNxdWFyZXMpKio6CiAgLSBQcmUgbWVkemktc2t1cGlub3bDuiB2YXJpYWJpbGl0dSBqZSAqKjc4LjMwNzYqKi4KICAtIFByZSB2bsO6dG9yLXNrdXBpbm92w7ogdmFyaWFiaWxpdHUgamUgKio4MjE0LjA4NDkqKi4KLSAqKk1lYW5fU3EgKE1lYW4gU3F1YXJlKSoqOgogIC0gUHJlIG1lZHppLXNrdXBpbm92w7ogdmFyaWFiaWxpdHUgamUgKiozOS4xNTM4KiouCiAgLSBQcmUgdm7DunRvci1za3VwaW5vdsO6IHZhcmlhYmlsaXR1IGplICoqNDMuNDYwOCoqLgotICoqRl92YWx1ZSoqOiBIb2Rub3RhIEYgdGVzdHUgamUgKiowLjkwMDkqKiwgxI1vIG5hem5hxI11amUsIMW+ZSByb3pkaWVsIG1lZHppIHNrdXBpbmFtaSAocm9rbWkpIG5pZSBqZSB2w71yYXpuw70uCi0gKipQcl9GIChwLXZhbHVlKSoqOiBIb2Rub3RhIHAgamUgKiowLjQwNzkqKiwgxI1vIGplIHZ5xaHFoWllIG5lxb4gYmXFvm7DvSBwcmFoICoqMC4wNSoqLCB0YWvFvmUgcm96ZGllbCBtZWR6aSByb2ttaSAqKm5pZSBqZSDFoXRhdGlzdGlja3kgdsO9em5hbW7DvSoqLgoKIyMjIFrDoXZlcgpOYSB6w6FrbGFkZSB2w71zbGVka292IEFOT1ZBIHRlc3R1IG3DtMW+ZW1lIHV6YXZyaWXFpSwgxb5lICoqcm96ZGllbCBtZWR6aSB0ZXBsb3RhbWkgdiByb2tvY2ggMjAyMSBhIDIwMjMgbmllIGplIMWhdGF0aXN0aWNreSB2w716bmFtbsO9KiouIFRvIHpuYW1lbsOhLCDFvmUgbmEgesOha2xhZGUgdMO9Y2h0byDDumRham92IG5lbcOhbWUgZMO0a2F6LCDFvmUgYnkgc2EgdGVwbG90YSBtZWR6aSB0w71taXRvIGR2b21hIHJva21pIGzDrcWhaWxhLgoKIyMgTGluZWFyIFJlZ3Jlc3Npb24gCmBgYHtyfQpsaWJyYXJ5KGthYmxlRXh0cmEpCgojIFZ5a29uYW5pZSBsaW5lw6FybmVqIHJlZ3Jlc2llCgptb2RlbCA8LSBsbShgQk9EIChtZy9MKSAtIE1heGAgfiBgVGVtcGVyYXR1cmUgKEMpIC0gTWF4YCwgZGF0YSA9IEluZGlhbl93YXRlcl9kYXRhKQoKIyBaaHJudXRpZSBtb2RlbHUKCm1vZGVsLnN1bW1hcnkgPC0gc3VtbWFyeShtb2RlbCkKCiMgVnl0dm9yZW5pZSB0YWJ1xL5reSBzIHbDvXNsZWRrYW1pIGxpbmXDoXJuZWogcmVncmVzaWUKCm1vZGVsLnRhYmxlIDwtIGRhdGEuZnJhbWUoClRlcm0gPSByb3duYW1lcyhtb2RlbC5zdW1tYXJ5JGNvZWZmaWNpZW50cyksCkVzdGltYXRlID0gbW9kZWwuc3VtbWFyeSRjb2VmZmljaWVudHNbLCAxXSwKU3RkX0Vycm9yID0gbW9kZWwuc3VtbWFyeSRjb2VmZmljaWVudHNbLCAyXSwKdF92YWx1ZSA9IG1vZGVsLnN1bW1hcnkkY29lZmZpY2llbnRzWywgM10sClByX3QgPSBtb2RlbC5zdW1tYXJ5JGNvZWZmaWNpZW50c1ssIDRdCikKCiMgWm9icmF6ZW5pZSB0YWJ1xL5reSBzIGthYmxlRXh0cmEKCm1vZGVsLnRhYmxlICU+JQprYWJsZShjYXB0aW9uID0gIlbDvXNsZWRreSBsaW5lw6FybmVqIHJlZ3Jlc2llIG1lZHppIEJPRCAobWcvTCkgLSBNYXggYSBUZXBsb3RvdSAoQykgLSBNYXgiKSAlPiUKa2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIikpICU+JQpjb2x1bW5fc3BlYygxLCBib2xkID0gVFJVRSkgJT4lCnJvd19zcGVjKDAsIGJvbGQgPSBUUlVFLCBiYWNrZ3JvdW5kID0gIiNmMmYyZjIiKQpgYGAKVMOhdG8gdGFidcS+a2Egem9icmF6dWplIHbDvXNsZWRreSAqKmxpbmXDoXJuZWogcmVncmVzaWUqKiBtZWR6aSAqKkJPRCAobWcvTCkgLSBNYXgqKiBhICoqVGVwbG90b3UgKEMpIC0gTWF4KiouCgojIyMgVsO9c2xlZGt5CgotICoqKEludGVyY2VwdCkqKjogS29lZmljaWVudCBwcmUgaW50ZXJjZXB0IChwcmllc2XEjW7DrWsgcyBvc291IFkpIGplICoqMy4yMDE5OTYyKiouIFRvIHpuYW1lbsOhLCDFvmUga2XEjyB0ZXBsb3RhIGplICoqMMKwQyoqLCBwcmVkcG9rbGFkYW7DoSBob2Rub3RhIEJPRCBqZSBwcmlibGnFvm5lICoqMy4yIG1nL0wqKi4KLSAqKlRlbXBlcmF0dXJlIChDKSAtIE1heCoqOiBLb2VmaWNpZW50IHByZSB0ZXBsb3R1IGplICoqMC4wNjM4OTcyKiosIMSNbyBuYXpuYcSNdWplLCDFvmUgcHJpIGthxb5kb20genbDvcWhZW7DrSB0ZXBsb3R5IG8gKioxwrBDKiogc2EgaG9kbm90YSBCT0QgenbDvcWhaSBwcmlibGnFvm5lIG8gKiowLjA2NCBtZy9MKiouCi0gKipTdGRfRXJyb3IqKjogxaB0YW5kYXJkbsOhIGNoeWJhIGtvZWZpY2llbnRvdiwga3RvcsOhIG1lcmlhIHZhcmlhYmlsaXR1IG9kaGFkb3ZhbsO9Y2ggaG9kbsO0dDoKICAtIFByZSBpbnRlcmNlcHQgamUgKiozLjI1MzQ2NTgqKi4KICAtIFByZSB0ZXBsb3R1IGplICoqMC4xMTQ0MTA2KiouCi0gKip0X3ZhbHVlKio6IFRlc3RvdsOhIGhvZG5vdGEgKHQtaG9kbm90YSkgcHJlIG9iaWR2ZSBwcmVtZW5uw6k6CiAgLSBQcmUgaW50ZXJjZXB0IGplICoqMC45ODQxODAxKiouCiAgLSBQcmUgdGVwbG90dSBqZSAqKjAuNTU4NDkwNSoqLiBUaWV0byBob2Rub3R5IG5hem5hxI11asO6LCDFvmUgdC10ZXN0IHByZSBvYmUgcHJlbWVubsOpIG5pZSBqZSB2ZcS+bWkgc2lsbsO9LgotICoqUHJfdCAocC12YWx1ZSkqKjogUC1ob2Rub3RhIHByZSBvYmEga29lZmljaWVudHk6CiAgLSBQcmUgaW50ZXJjZXB0IGplICoqMC4zMjYzNzgwKiouCiAgLSBQcmUgdGVwbG90dSBqZSAqKjAuNTc3MjE5MyoqLiBPYmlkdmUgcC1ob2Rub3R5IHPDuiB2ecWhxaFpZSBuZcW+IGJlxb5uw70gcHJhaCAqKjAuMDUqKiwgxI1vIHpuYW1lbsOhLCDFvmUgKipyb3pkaWVseSBtZWR6aSBCT0QgYSB0ZXBsb3RvdSBuaWUgc8O6IMWhdGF0aXN0aWNreSB2w716bmFtbsOpKiouCgojIyMgWsOhdmVyClbDvXNsZWRreSByZWdyZXNpZSBuYXpuYcSNdWrDuiwgxb5lICoqbmVleGlzdHVqZSDFoXRhdGlzdGlja3kgdsO9em5hbW7DvSB2esWlYWgqKiBtZWR6aSB0ZXBsb3RvdSBhIEJPRCwgcHJldG/FvmUgcC1ob2Rub3R5IHPDuiB2w6TEjcWhaWUgbmXFviAwLjA1LiBUbyB6bmFtZW7DoSwgxb5lIG5hIHrDoWtsYWRlIHTDvWNodG8gw7pkYWpvdiBuZW3DoW1lIGRvc3RhdG/EjW7DvSBkw7RrYXosIMW+ZSBieSB6bWVuYSB0ZXBsb3R5IG1hbGEgdsO9em5hbW7DvSB2cGx5diBuYSBob2Rub3R5IEJPRC4KCgoKCg==