Úvod

Tento dokument načíta súbor data_ekonometria.csv (oddelený bodkočiarkou) a spraví základné čistenie. Následne porovná dve najpočetnejšie skupiny podľa premennej Spoločnosť (môžeš zmeniť na Žáner), vykreslí grafy, spočíta tabuľku so štatistikami, otestuje hypotézy a odhadne lineárny model.

Nastavenie

library(dplyr)
library(tidyr)
library(ggplot2)
library(readr)
library(stringr)
library(scales)
library(knitr)
library(broom)
library(kableExtra)

options(knitr.kable.NA = "")

Načítanie a čistenie dát

# Cesta k CSV
path <- "data_ekonometria.csv"

# Európske CSV s bodkočiarkou, UTF-8
df_raw <- read.csv2(path, sep = ";", fileEncoding = "UTF-8", encoding = "UTF-8", stringsAsFactors = FALSE)


# --- Očistenie názvov stĺpcov (rozšírené) ---
# zjednotenie medzier, trimming, fix znakov
names(df_raw) <- gsub("\\s+", " ", names(df_raw))
names(df_raw) <- trimws(names(df_raw))
names(df_raw) <- iconv(names(df_raw), from = "UTF-8", to = "UTF-8")

# Pomocná funkcia na premenovanie podľa vzoru (prvý jednoznačný match)
rename_if_present <- function(cols, pattern, new_name) {
  idx <- which(grepl(pattern, cols, ignore.case = TRUE, perl = TRUE))
  if (length(idx) == 1) cols[idx] <- new_name
  cols
}

nms <- names(df_raw)
# IMDb
nms <- rename_if_present(nms, "(?i)\\bimdb\\b", "IMDb hodnotenie")
# Dĺžka (min) – toleruj diakritiku a/alebo len (min)
nms <- rename_if_present(nms, "(?i)(d[lľĺ]žka)|(\\(\\s*min\\s*\\))", "Dĺžka (min)")
# Rozpočet
nms <- rename_if_present(nms, "(?i)rozpo[cč]et|budget", "Rozpočet [$]")
names(df_raw) <- nms

print(names(df_raw))
[1] "Umiestnenie"     "Názov"           "Rok"             "Žáner"          
[5] "IMDb hodnotenie" "Dĺžka (min)"     "Réžia"           "Spoločnosť"     
[9] "Rozpočet [$]"   
# Voliteľne: jasná hláška, ak niečo stále chýba
required_cols <- c("Umiestnenie","Názov","Rok","Žáner","IMDb hodnotenie","Dĺžka (min)","Réžia","Spoločnosť","Rozpočet [$]")
missing_cols <- setdiff(required_cols, names(df_raw))
if (length(missing_cols) > 0) {
  warning(paste0("Upozornenie: v údajoch chýbajú stĺpce: ", paste(missing_cols, collapse = ", "),
                 ". Dokument bude pokračovať so stĺpcami, ktoré sú k dispozícii."))
}


# --- Očistenie názvov stĺpcov ---
names(df_raw) <- gsub("\\s+", " ", names(df_raw))       # zjednotí viac medzier
names(df_raw) <- trimws(names(df_raw))                    # odstráni medzery na začiatku/konci
names(df_raw) <- iconv(names(df_raw), from = "UTF-8", to = "UTF-8")  # opraví skryté znaky
if (any(grepl("IMDb", names(df_raw)))) {
  names(df_raw)[grepl("IMDb", names(df_raw))] <- "IMDb hodnotenie"
}
print(names(df_raw))
[1] "Umiestnenie"     "Názov"           "Rok"             "Žáner"          
[5] "IMDb hodnotenie" "Dĺžka (min)"     "Réžia"           "Spoločnosť"     
[9] "Rozpočet [$]"   
# Čistenie a typy premenných
df <- df_raw %>%
  mutate(
    Rok = suppressWarnings(as.integer(Rok)),
    `IMDb hodnotenie` = str_replace_all(`IMDb hodnotenie`, ",", "."),
    `IMDb hodnotenie` = suppressWarnings(as.numeric(`IMDb hodnotenie`)),
    `Dĺžka (min)` = suppressWarnings(as.numeric(`Dĺžka (min)`)),
    `Rozpočet [$]` = str_remove_all(`Rozpočet [$]`, "[^0-9]"),
    `Rozpočet [$]` = suppressWarnings(as.numeric(`Rozpočet [$]`)),
    Dekáda = paste0(floor(Rok / 10) * 10, "s")
  )

glue <- function(...) paste0(...)

cat(glue("Počet riadkov: ", nrow(df), "\n"))
Počet riadkov: 250
cat(glue("Stĺpce: ", paste(names(df), collapse = ", "), "\n"))
Stĺpce: Umiestnenie, Názov, Rok, Žáner, IMDb hodnotenie, Dĺžka (min), Réžia, Spoločnosť, Rozpočet [$], Dekáda

Výber dvoch skupín


group_var <- "Spoločnosť"

# 2 najpočetnejšie kategórie
top2 <- df %>%
  filter(!is.na(.data[[group_var]]), .data[[group_var]] != "") %>%
  count(.data[[group_var]], sort = TRUE) %>%
  slice_head(n = 2) %>%
  pull(1)

df2 <- df %>% filter(.data[[group_var]] %in% top2)

# Premenujeme na "Skupina" kvôli konzistentnosti
names(df2)[names(df2) == group_var] <- "Skupina"

head(select(df2, Skupina, Názov, Rok, Žáner, `IMDb hodnotenie`, `Dĺžka (min)`, `Rozpočet [$]`))

Grafy

Stĺpcový graf: priemerné IMDb podľa dekády a skupiny

agg_decade <- df2 %>%
  group_by(Skupina, Dekáda) %>%
  summarise(
    avg_imdb = mean(`IMDb hodnotenie`, na.rm = TRUE),
    n = n(), .groups = "drop"
  )

ggplot(agg_decade, aes(x = Dekáda, y = avg_imdb, fill = Skupina, group = Skupina)) +
  geom_bar(stat = "identity", position = "dodge", width = 0.8) +
  geom_text(aes(label = round(avg_imdb, 2)),
            position = position_dodge(width = 0.8), vjust = -0.3, size = 3) +
  theme_minimal() +
  labs(title = "Priemerné IMDb hodnotenie podľa dekády",
       x = "Dekáda", y = "Priemer IMDb", fill = "Skupina") +
  theme(axis.text.x = element_text(angle = 30, hjust = 1))

Čiarový graf: medián rozpočtu podľa roku a skupiny

agg_year_budget <- df2 %>%
  filter(!is.na(Rok)) %>%
  group_by(Skupina, Rok) %>%
  summarise(median_budget = median(`Rozpočet [$]`, na.rm = TRUE), .groups = "drop")

ggplot(agg_year_budget, aes(x = Rok, y = median_budget, color = Skupina, group = Skupina)) +
  geom_line(linewidth = 1.2) +
  geom_point(size = 2.5) +
  geom_text(aes(label = label_number(accuracy = 1, scale_cut = scales::cut_si(""))(median_budget)),
            vjust = -0.5, size = 2.7, show.legend = FALSE) +
  theme_minimal() +
  labs(title = "Medián rozpočtu podľa roku",
       x = "Rok", y = "Medián rozpočtu [$]", color = "Skupina") +
  theme(axis.text.x = element_text(angle = 30, hjust = 1))

Základné štatistiky

stats_tbl <- df2 %>%
  group_by(Skupina, Dekáda) %>%
  summarise(
    n = n(),
    mean_imdb = mean(`IMDb hodnotenie`, na.rm = TRUE),
    sd_imdb   = sd(`IMDb hodnotenie`, na.rm = TRUE),
    min_imdb  = min(`IMDb hodnotenie`, na.rm = TRUE),
    q25_imdb  = quantile(`IMDb hodnotenie`, 0.25, na.rm = TRUE),
    median_imdb = median(`IMDb hodnotenie`, na.rm = TRUE),
    q75_imdb  = quantile(`IMDb hodnotenie`, 0.75, na.rm = TRUE),
    max_imdb  = max(`IMDb hodnotenie`, na.rm = TRUE),
    mean_len  = mean(`Dĺžka (min)`, na.rm = TRUE),
    mean_budget = mean(`Rozpočet [$]`, na.rm = TRUE),
    .groups = "drop"
  )

kable(stats_tbl, digits = 2, caption = "Základné štatistiky podľa skupiny a dekády")
Základné štatistiky podľa skupiny a dekády
Skupina Dekáda n mean_imdb sd_imdb min_imdb q25_imdb median_imdb q75_imdb max_imdb mean_len mean_budget
United Artists 1920s 2 8.10 0.00 8.1 8.10 8.10 8.10 8.1 81.00 836500
United Artists 1930s 2 8.50 0.00 8.5 8.50 8.50 8.50 8.5 87.00 1500000
United Artists 1940s 3 8.20 0.17 8.1 8.10 8.10 8.25 8.4 118.00 1496667
United Artists 1950s 4 8.50 0.35 8.2 8.35 8.40 8.55 9.0 105.25 1534250
United Artists 1960s 4 8.22 0.05 8.2 8.20 8.20 8.22 8.3 152.00 2600000
United Artists 1970s 4 8.35 0.30 8.1 8.10 8.30 8.55 8.7 130.25 9940000
United Artists 1980s 1 8.20 8.2 8.20 8.20 8.20 8.2 129.00 18000000
Warner Bros. Pictures 1940s 2 8.35 0.21 8.2 8.27 8.35 8.43 8.5 144.00 1750000
Warner Bros. Pictures 1950s 1 8.20 8.2 8.20 8.20 8.20 8.2 105.00 1400000
Warner Bros. Pictures 1960s 1 8.10 8.1 8.10 8.10 8.10 8.1 127.00 3200000
Warner Bros. Pictures 1970s 3 8.17 0.12 8.1 8.10 8.10 8.20 8.3 147.67 8433333
Warner Bros. Pictures 1980s 4 8.30 0.14 8.1 8.25 8.35 8.40 8.4 152.00 27250000
Warner Bros. Pictures 1990s 6 8.35 0.29 8.0 8.20 8.25 8.60 8.7 134.17 41233333
Warner Bros. Pictures 2000s 7 8.39 0.31 8.1 8.20 8.20 8.50 9.0 134.14 81000000
Warner Bros. Pictures 2010s 7 8.36 0.28 8.1 8.10 8.40 8.50 8.8 139.29 151871429

Testovanie hypotéz

t-test: rozdiel IMDb medzi 2 skupinami v najnovšej dekáde

latest_decade <- df2 %>%
  filter(!is.na(Dekáda)) %>%
  mutate(dec_num = as.integer(str_remove(Dekáda, "s"))) %>%
  slice_max(dec_num, n = 1, with_ties = FALSE) %>%
  pull(Dekáda) %>%
  unique()

df_latest <- df2 %>% filter(Dekáda == latest_decade)

ok_groups <- df_latest %>%
  group_by(Skupina) %>%
  filter(!is.na(`IMDb hodnotenie`)) %>%
  summarise(n = n(), .groups = "drop") %>%
  filter(n >= 2) %>% pull(Skupina)

if (length(ok_groups) == 2) {
  x <- df_latest %>% filter(Skupina == ok_groups[1]) %>% pull(`IMDb hodnotenie`)
  y <- df_latest %>% filter(Skupina == ok_groups[2]) %>% pull(`IMDb hodnotenie`)
  t_test_result <- t.test(x, y)
  t_test_result
} else {
  "t-test sa neuskutočnil: v najnovšej dekáde nie je dosť dát v oboch skupinách."
}
[1] "t-test sa neuskutočnil: v najnovšej dekáde nie je dosť dát v oboch skupinách."

ANOVA: IMDb podľa žánru (top 5 žánrov)

top_genres <- df %>% count(Žáner, sort = TRUE) %>% slice_head(n = 5) %>% pull(Žáner)
anova_df <- df %>% filter(Žáner %in% top_genres, !is.na(`IMDb hodnotenie`))

anova_result <- aov(`IMDb hodnotenie` ~ Žáner, data = anova_df)
summary(anova_result)
            Df Sum Sq Mean Sq F value Pr(>F)
Žáner        4  0.594 0.14848   1.706  0.162
Residuals   56  4.874 0.08703               

Lineárna regresia

Model: IMDb ~ Rok + Skupina (dve vybrané skupiny z Spoločnosť alebo Žáner).

model <- lm(`IMDb hodnotenie` ~ Rok + Skupina, data = df2)
summary(model)

Call:
lm(formula = `IMDb hodnotenie` ~ Rok + Skupina, data = df2)

Residuals:
    Min      1Q  Median      3Q     Max 
-0.3341 -0.1684 -0.0516  0.1272  0.6818 

Coefficients:
                              Estimate Std. Error t value Pr(>|t|)
(Intercept)                   4.729720   3.439589   1.375    0.175
Rok                           0.001834   0.001759   1.042    0.302
SkupinaWarner Bros. Pictures -0.061108   0.095570  -0.639    0.526

Residual standard error: 0.2414 on 48 degrees of freedom
Multiple R-squared:  0.02238,   Adjusted R-squared:  -0.01836 
F-statistic: 0.5494 on 2 and 48 DF,  p-value: 0.5809
coef.tbl <- tidy(model, conf.int = TRUE) %>%
  mutate(
    term = dplyr::case_when(
      term == "(Intercept)" ~ "Intercept",
      term == "Rok" ~ "Rok",
      TRUE ~ term
    ),
    stars = dplyr::case_when(
      p.value < 0.001 ~ "***",
      p.value < 0.01  ~ "**",
      p.value < 0.05  ~ "*",
      p.value < 0.1   ~ "·",
      TRUE            ~ ""
    )
  ) %>%
  transmute(
    Term = term,
    Estimate = estimate,
    `Std. Error` = std.error,
    `t value` = statistic,
    `p value` = p.value,
    `95% CI` = stringr::str_c("[", round(conf.low, 2), ", ", round(conf.high, 2), "]"),
    Sig = stars
  )

coef.tbl %>%
  kable(
    digits = 2,
    caption = "OLS regresné koeficienty (IMDb ~ Rok + Skupina)"
  ) %>%
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover", "condensed")) %>%
  column_spec(1, bold = TRUE) %>%
  row_spec(0, bold = TRUE, background = "#f2f2f2") %>%
  footnote(
    general = "Signif. codes: *** p<0.001, ** p<0.01, * p<0.05, · p<0.1.",
    threeparttable = TRUE
  )
OLS regresné koeficienty (IMDb ~ Rok + Skupina)
Term Estimate Std. Error t value p value 95% CI Sig
Intercept 4.73 3.44 1.38 0.18 [-2.19, 11.65]
Rok 0.00 0.00 1.04 0.30 [0, 0.01]
SkupinaWarner Bros. Pictures -0.06 0.10 -0.64 0.53 [-0.25, 0.13]
Note:
Signif. codes: *** p<0.001, ** p<0.01, * p<0.05, · p<0.1.
LS0tCnRpdGxlOiAiUHLDoWNhIHMgZGF0YWLDoXpvdSAtIGltcG9ydCDDumRham92LCBncmFmeSwgxaF0YXRpc3Rpa3kiCmF1dGhvcjogIkRpYW5hIMSOdXJpYW7EjWlrb3bDoSAgPGJyPgoocyB2eXXFvml0w61tIHZlcmVqbmUgZG9zdHVwbsO9Y2gga8OzZG92IGEgQ2hhdEdQVCkiCmRhdGU6ICJOb3ZlbWJlciAyMDI1IgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdGhlbWU6IHVuaXRlZAogICAgaGlnaGxpZ2h0OiB0YW5nbwplZGl0b3Jfb3B0aW9uczogCiAgbWFya2Rvd246IAogICAgd3JhcDogNzIKLS0tCgojIMOadm9kCgpUZW50byBkb2t1bWVudCBuYcSNw610YSBzw7pib3IgYGRhdGFfZWtvbm9tZXRyaWEuY3N2YCAob2RkZWxlbsO9IGJvZGtvxI1pYXJrb3UpIGEgc3ByYXbDrSB6w6FrbGFkbsOpIMSNaXN0ZW5pZS4KTsOhc2xlZG5lIHBvcm92bsOhICoqZHZlIG5hanBvxI1ldG5lasWhaWUgc2t1cGlueSoqIHBvZMS+YSBwcmVtZW5uZWogKlNwb2xvxI1ub3PFpSogKG3DtMW+ZcWhIHptZW5pxaUgbmEgKsW9w6FuZXIqKSwKdnlrcmVzbMOtIGdyYWZ5LCBzcG/EjcOtdGEgdGFidcS+a3Ugc28gxaF0YXRpc3Rpa2FtaSwgb3Rlc3R1amUgaHlwb3TDqXp5IGEgb2RoYWRuZSBsaW5lw6FybnkgbW9kZWwuCgojIyBOYXN0YXZlbmllCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDQuOCkKYGBgCgpgYGB7ciBiYWxpa3l9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShyZWFkcikKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShrbml0cikKbGlicmFyeShicm9vbSkKbGlicmFyeShrYWJsZUV4dHJhKQoKb3B0aW9ucyhrbml0ci5rYWJsZS5OQSA9ICIiKQpgYGAKCiMjIE5hxI3DrXRhbmllIGEgxI1pc3RlbmllIGTDoXQKCmBgYHtyIG5hY2l0YW5pZX0KIyBDZXN0YSBrIENTVgpwYXRoIDwtICJkYXRhX2Vrb25vbWV0cmlhLmNzdiIKCiMgRXVyw7Nwc2tlIENTViBzIGJvZGtvxI1pYXJrb3UsIFVURi04CmRmX3JhdyA8LSByZWFkLmNzdjIocGF0aCwgc2VwID0gIjsiLCBmaWxlRW5jb2RpbmcgPSAiVVRGLTgiLCBlbmNvZGluZyA9ICJVVEYtOCIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKCgojIC0tLSBPxI1pc3RlbmllIG7DoXp2b3Ygc3TEunBjb3YgKHJvesWhw61yZW7DqSkgLS0tCiMgemplZG5vdGVuaWUgbWVkemllciwgdHJpbW1pbmcsIGZpeCB6bmFrb3YKbmFtZXMoZGZfcmF3KSA8LSBnc3ViKCJcXHMrIiwgIiAiLCBuYW1lcyhkZl9yYXcpKQpuYW1lcyhkZl9yYXcpIDwtIHRyaW13cyhuYW1lcyhkZl9yYXcpKQpuYW1lcyhkZl9yYXcpIDwtIGljb252KG5hbWVzKGRmX3JhdyksIGZyb20gPSAiVVRGLTgiLCB0byA9ICJVVEYtOCIpCgojIFBvbW9jbsOhIGZ1bmtjaWEgbmEgcHJlbWVub3ZhbmllIHBvZMS+YSB2em9ydSAocHJ2w70gamVkbm96bmHEjW7DvSBtYXRjaCkKcmVuYW1lX2lmX3ByZXNlbnQgPC0gZnVuY3Rpb24oY29scywgcGF0dGVybiwgbmV3X25hbWUpIHsKICBpZHggPC0gd2hpY2goZ3JlcGwocGF0dGVybiwgY29scywgaWdub3JlLmNhc2UgPSBUUlVFLCBwZXJsID0gVFJVRSkpCiAgaWYgKGxlbmd0aChpZHgpID09IDEpIGNvbHNbaWR4XSA8LSBuZXdfbmFtZQogIGNvbHMKfQoKbm1zIDwtIG5hbWVzKGRmX3JhdykKIyBJTURiCm5tcyA8LSByZW5hbWVfaWZfcHJlc2VudChubXMsICIoP2kpXFxiaW1kYlxcYiIsICJJTURiIGhvZG5vdGVuaWUiKQojIETEusW+a2EgKG1pbikg4oCTIHRvbGVydWogZGlha3JpdGlrdSBhL2FsZWJvIGxlbiAobWluKQpubXMgPC0gcmVuYW1lX2lmX3ByZXNlbnQobm1zLCAiKD9pKShkW2zEvsS6XcW+a2EpfChcXChcXHMqbWluXFxzKlxcKSkiLCAiRMS6xb5rYSAobWluKSIpCiMgUm96cG/EjWV0Cm5tcyA8LSByZW5hbWVfaWZfcHJlc2VudChubXMsICIoP2kpcm96cG9bY8SNXWV0fGJ1ZGdldCIsICJSb3pwb8SNZXQgWyRdIikKbmFtZXMoZGZfcmF3KSA8LSBubXMKCnByaW50KG5hbWVzKGRmX3JhdykpCgojIFZvbGl0ZcS+bmU6IGphc27DoSBobMOhxaFrYSwgYWsgbmllxI1vIHN0w6FsZSBjaMO9YmEKcmVxdWlyZWRfY29scyA8LSBjKCJVbWllc3RuZW5pZSIsIk7DoXpvdiIsIlJvayIsIsW9w6FuZXIiLCJJTURiIGhvZG5vdGVuaWUiLCJExLrFvmthIChtaW4pIiwiUsOpxb5pYSIsIlNwb2xvxI1ub3PFpSIsIlJvenBvxI1ldCBbJF0iKQptaXNzaW5nX2NvbHMgPC0gc2V0ZGlmZihyZXF1aXJlZF9jb2xzLCBuYW1lcyhkZl9yYXcpKQppZiAobGVuZ3RoKG1pc3NpbmdfY29scykgPiAwKSB7CiAgd2FybmluZyhwYXN0ZTAoIlVwb3pvcm5lbmllOiB2IMO6ZGFqb2NoIGNow71iYWrDuiBzdMS6cGNlOiAiLCBwYXN0ZShtaXNzaW5nX2NvbHMsIGNvbGxhcHNlID0gIiwgIiksCiAgICAgICAgICAgICAgICAgIi4gRG9rdW1lbnQgYnVkZSBwb2tyYcSNb3ZhxaUgc28gc3TEunBjYW1pLCBrdG9yw6kgc8O6IGsgZGlzcG96w61jaWkuIikpCn0KCgojIC0tLSBPxI1pc3RlbmllIG7DoXp2b3Ygc3TEunBjb3YgLS0tCm5hbWVzKGRmX3JhdykgPC0gZ3N1YigiXFxzKyIsICIgIiwgbmFtZXMoZGZfcmF3KSkgICAgICAgIyB6amVkbm90w60gdmlhYyBtZWR6aWVyCm5hbWVzKGRmX3JhdykgPC0gdHJpbXdzKG5hbWVzKGRmX3JhdykpICAgICAgICAgICAgICAgICAgICAjIG9kc3Ryw6FuaSBtZWR6ZXJ5IG5hIHphxI1pYXRrdS9rb25jaQpuYW1lcyhkZl9yYXcpIDwtIGljb252KG5hbWVzKGRmX3JhdyksIGZyb20gPSAiVVRGLTgiLCB0byA9ICJVVEYtOCIpICAjIG9wcmF2w60gc2tyeXTDqSB6bmFreQppZiAoYW55KGdyZXBsKCJJTURiIiwgbmFtZXMoZGZfcmF3KSkpKSB7CiAgbmFtZXMoZGZfcmF3KVtncmVwbCgiSU1EYiIsIG5hbWVzKGRmX3JhdykpXSA8LSAiSU1EYiBob2Rub3RlbmllIgp9CnByaW50KG5hbWVzKGRmX3JhdykpCgojIMSMaXN0ZW5pZSBhIHR5cHkgcHJlbWVubsO9Y2gKZGYgPC0gZGZfcmF3ICU+JQogIG11dGF0ZSgKICAgIFJvayA9IHN1cHByZXNzV2FybmluZ3MoYXMuaW50ZWdlcihSb2spKSwKICAgIGBJTURiIGhvZG5vdGVuaWVgID0gc3RyX3JlcGxhY2VfYWxsKGBJTURiIGhvZG5vdGVuaWVgLCAiLCIsICIuIiksCiAgICBgSU1EYiBob2Rub3RlbmllYCA9IHN1cHByZXNzV2FybmluZ3MoYXMubnVtZXJpYyhgSU1EYiBob2Rub3RlbmllYCkpLAogICAgYETEusW+a2EgKG1pbilgID0gc3VwcHJlc3NXYXJuaW5ncyhhcy5udW1lcmljKGBExLrFvmthIChtaW4pYCkpLAogICAgYFJvenBvxI1ldCBbJF1gID0gc3RyX3JlbW92ZV9hbGwoYFJvenBvxI1ldCBbJF1gLCAiW14wLTldIiksCiAgICBgUm96cG/EjWV0IFskXWAgPSBzdXBwcmVzc1dhcm5pbmdzKGFzLm51bWVyaWMoYFJvenBvxI1ldCBbJF1gKSksCiAgICBEZWvDoWRhID0gcGFzdGUwKGZsb29yKFJvayAvIDEwKSAqIDEwLCAicyIpCiAgKQoKZ2x1ZSA8LSBmdW5jdGlvbiguLi4pIHBhc3RlMCguLi4pCgpjYXQoZ2x1ZSgiUG/EjWV0IHJpYWRrb3Y6ICIsIG5yb3coZGYpLCAiXG4iKSkKY2F0KGdsdWUoIlN0xLpwY2U6ICIsIHBhc3RlKG5hbWVzKGRmKSwgY29sbGFwc2UgPSAiLCAiKSwgIlxuIikpCmBgYAoKIyMgVsO9YmVyIGR2b2NoIHNrdXDDrW4KCmBgYHtyIHZ5YmVyX3NrdXBpbn0KCmdyb3VwX3ZhciA8LSAiU3BvbG/EjW5vc8WlIgoKIyAyIG5hanBvxI1ldG5lasWhaWUga2F0ZWfDs3JpZQp0b3AyIDwtIGRmICU+JQogIGZpbHRlcighaXMubmEoLmRhdGFbW2dyb3VwX3Zhcl1dKSwgLmRhdGFbW2dyb3VwX3Zhcl1dICE9ICIiKSAlPiUKICBjb3VudCguZGF0YVtbZ3JvdXBfdmFyXV0sIHNvcnQgPSBUUlVFKSAlPiUKICBzbGljZV9oZWFkKG4gPSAyKSAlPiUKICBwdWxsKDEpCgpkZjIgPC0gZGYgJT4lIGZpbHRlciguZGF0YVtbZ3JvdXBfdmFyXV0gJWluJSB0b3AyKQoKIyBQcmVtZW51amVtZSBuYSAiU2t1cGluYSIga3bDtGxpIGtvbnppc3RlbnRub3N0aQpuYW1lcyhkZjIpW25hbWVzKGRmMikgPT0gZ3JvdXBfdmFyXSA8LSAiU2t1cGluYSIKCmhlYWQoc2VsZWN0KGRmMiwgU2t1cGluYSwgTsOhem92LCBSb2ssIMW9w6FuZXIsIGBJTURiIGhvZG5vdGVuaWVgLCBgRMS6xb5rYSAobWluKWAsIGBSb3pwb8SNZXQgWyRdYCkpCmBgYAoKIyBHcmFmeQoKIyMgU3TEunBjb3bDvSBncmFmOiBwcmllbWVybsOpIElNRGIgcG9kxL5hIGRla8OhZHkgYSBza3VwaW55CgpgYGB7ciBiYXJwbG90X2ltZGJfZGVjYWRlfQphZ2dfZGVjYWRlIDwtIGRmMiAlPiUKICBncm91cF9ieShTa3VwaW5hLCBEZWvDoWRhKSAlPiUKICBzdW1tYXJpc2UoCiAgICBhdmdfaW1kYiA9IG1lYW4oYElNRGIgaG9kbm90ZW5pZWAsIG5hLnJtID0gVFJVRSksCiAgICBuID0gbigpLCAuZ3JvdXBzID0gImRyb3AiCiAgKQoKZ2dwbG90KGFnZ19kZWNhZGUsIGFlcyh4ID0gRGVrw6FkYSwgeSA9IGF2Z19pbWRiLCBmaWxsID0gU2t1cGluYSwgZ3JvdXAgPSBTa3VwaW5hKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHdpZHRoID0gMC44KSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKGF2Z19pbWRiLCAyKSksCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLCB2anVzdCA9IC0wLjMsIHNpemUgPSAzKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIlByaWVtZXJuw6kgSU1EYiBob2Rub3RlbmllIHBvZMS+YSBkZWvDoWR5IiwKICAgICAgIHggPSAiRGVrw6FkYSIsIHkgPSAiUHJpZW1lciBJTURiIiwgZmlsbCA9ICJTa3VwaW5hIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzAsIGhqdXN0ID0gMSkpCmBgYAoKIyMgxIxpYXJvdsO9IGdyYWY6IG1lZGnDoW4gcm96cG/EjXR1IHBvZMS+YSByb2t1IGEgc2t1cGlueQoKYGBge3IgbGluZV9idWRnZXRfeWVhcn0KYWdnX3llYXJfYnVkZ2V0IDwtIGRmMiAlPiUKICBmaWx0ZXIoIWlzLm5hKFJvaykpICU+JQogIGdyb3VwX2J5KFNrdXBpbmEsIFJvaykgJT4lCiAgc3VtbWFyaXNlKG1lZGlhbl9idWRnZXQgPSBtZWRpYW4oYFJvenBvxI1ldCBbJF1gLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKQoKZ2dwbG90KGFnZ195ZWFyX2J1ZGdldCwgYWVzKHggPSBSb2ssIHkgPSBtZWRpYW5fYnVkZ2V0LCBjb2xvciA9IFNrdXBpbmEsIGdyb3VwID0gU2t1cGluYSkpICsKICBnZW9tX2xpbmUobGluZXdpZHRoID0gMS4yKSArCiAgZ2VvbV9wb2ludChzaXplID0gMi41KSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGxhYmVsX251bWJlcihhY2N1cmFjeSA9IDEsIHNjYWxlX2N1dCA9IHNjYWxlczo6Y3V0X3NpKCIiKSkobWVkaWFuX2J1ZGdldCkpLAogICAgICAgICAgICB2anVzdCA9IC0wLjUsIHNpemUgPSAyLjcsIHNob3cubGVnZW5kID0gRkFMU0UpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiTWVkacOhbiByb3pwb8SNdHUgcG9kxL5hIHJva3UiLAogICAgICAgeCA9ICJSb2siLCB5ID0gIk1lZGnDoW4gcm96cG/EjXR1IFskXSIsIGNvbG9yID0gIlNrdXBpbmEiKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMCwgaGp1c3QgPSAxKSkKYGBgCgojIFrDoWtsYWRuw6kgxaF0YXRpc3Rpa3kKCmBgYHtyIHRhYnVsa2F9CnN0YXRzX3RibCA8LSBkZjIgJT4lCiAgZ3JvdXBfYnkoU2t1cGluYSwgRGVrw6FkYSkgJT4lCiAgc3VtbWFyaXNlKAogICAgbiA9IG4oKSwKICAgIG1lYW5faW1kYiA9IG1lYW4oYElNRGIgaG9kbm90ZW5pZWAsIG5hLnJtID0gVFJVRSksCiAgICBzZF9pbWRiICAgPSBzZChgSU1EYiBob2Rub3RlbmllYCwgbmEucm0gPSBUUlVFKSwKICAgIG1pbl9pbWRiICA9IG1pbihgSU1EYiBob2Rub3RlbmllYCwgbmEucm0gPSBUUlVFKSwKICAgIHEyNV9pbWRiICA9IHF1YW50aWxlKGBJTURiIGhvZG5vdGVuaWVgLCAwLjI1LCBuYS5ybSA9IFRSVUUpLAogICAgbWVkaWFuX2ltZGIgPSBtZWRpYW4oYElNRGIgaG9kbm90ZW5pZWAsIG5hLnJtID0gVFJVRSksCiAgICBxNzVfaW1kYiAgPSBxdWFudGlsZShgSU1EYiBob2Rub3RlbmllYCwgMC43NSwgbmEucm0gPSBUUlVFKSwKICAgIG1heF9pbWRiICA9IG1heChgSU1EYiBob2Rub3RlbmllYCwgbmEucm0gPSBUUlVFKSwKICAgIG1lYW5fbGVuICA9IG1lYW4oYETEusW+a2EgKG1pbilgLCBuYS5ybSA9IFRSVUUpLAogICAgbWVhbl9idWRnZXQgPSBtZWFuKGBSb3pwb8SNZXQgWyRdYCwgbmEucm0gPSBUUlVFKSwKICAgIC5ncm91cHMgPSAiZHJvcCIKICApCgprYWJsZShzdGF0c190YmwsIGRpZ2l0cyA9IDIsIGNhcHRpb24gPSAiWsOha2xhZG7DqSDFoXRhdGlzdGlreSBwb2TEvmEgc2t1cGlueSBhIGRla8OhZHkiKQpgYGAKCiMgVGVzdG92YW5pZSBoeXBvdMOpegoKIyMgdC10ZXN0OiByb3pkaWVsIElNRGIgbWVkemkgMiBza3VwaW5hbWkgdiBuYWpub3bFoWVqIGRla8OhZGUKCmBgYHtyIHR0ZXN0fQpsYXRlc3RfZGVjYWRlIDwtIGRmMiAlPiUKICBmaWx0ZXIoIWlzLm5hKERla8OhZGEpKSAlPiUKICBtdXRhdGUoZGVjX251bSA9IGFzLmludGVnZXIoc3RyX3JlbW92ZShEZWvDoWRhLCAicyIpKSkgJT4lCiAgc2xpY2VfbWF4KGRlY19udW0sIG4gPSAxLCB3aXRoX3RpZXMgPSBGQUxTRSkgJT4lCiAgcHVsbChEZWvDoWRhKSAlPiUKICB1bmlxdWUoKQoKZGZfbGF0ZXN0IDwtIGRmMiAlPiUgZmlsdGVyKERla8OhZGEgPT0gbGF0ZXN0X2RlY2FkZSkKCm9rX2dyb3VwcyA8LSBkZl9sYXRlc3QgJT4lCiAgZ3JvdXBfYnkoU2t1cGluYSkgJT4lCiAgZmlsdGVyKCFpcy5uYShgSU1EYiBob2Rub3RlbmllYCkpICU+JQogIHN1bW1hcmlzZShuID0gbigpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUKICBmaWx0ZXIobiA+PSAyKSAlPiUgcHVsbChTa3VwaW5hKQoKaWYgKGxlbmd0aChva19ncm91cHMpID09IDIpIHsKICB4IDwtIGRmX2xhdGVzdCAlPiUgZmlsdGVyKFNrdXBpbmEgPT0gb2tfZ3JvdXBzWzFdKSAlPiUgcHVsbChgSU1EYiBob2Rub3RlbmllYCkKICB5IDwtIGRmX2xhdGVzdCAlPiUgZmlsdGVyKFNrdXBpbmEgPT0gb2tfZ3JvdXBzWzJdKSAlPiUgcHVsbChgSU1EYiBob2Rub3RlbmllYCkKICB0X3Rlc3RfcmVzdWx0IDwtIHQudGVzdCh4LCB5KQogIHRfdGVzdF9yZXN1bHQKfSBlbHNlIHsKICAidC10ZXN0IHNhIG5ldXNrdXRvxI1uaWw6IHYgbmFqbm92xaFlaiBkZWvDoWRlIG5pZSBqZSBkb3PFpSBkw6F0IHYgb2JvY2ggc2t1cGluw6FjaC4iCn0KYGBgCgojIyBBTk9WQTogSU1EYiBwb2TEvmEgxb7DoW5ydSAodG9wIDUgxb7DoW5yb3YpCgpgYGB7ciBhbm92YX0KdG9wX2dlbnJlcyA8LSBkZiAlPiUgY291bnQoxb3DoW5lciwgc29ydCA9IFRSVUUpICU+JSBzbGljZV9oZWFkKG4gPSA1KSAlPiUgcHVsbCjFvcOhbmVyKQphbm92YV9kZiA8LSBkZiAlPiUgZmlsdGVyKMW9w6FuZXIgJWluJSB0b3BfZ2VucmVzLCAhaXMubmEoYElNRGIgaG9kbm90ZW5pZWApKQoKYW5vdmFfcmVzdWx0IDwtIGFvdihgSU1EYiBob2Rub3RlbmllYCB+IMW9w6FuZXIsIGRhdGEgPSBhbm92YV9kZikKc3VtbWFyeShhbm92YV9yZXN1bHQpCmBgYAoKIyBMaW5lw6FybmEgcmVncmVzaWEKCk1vZGVsOiBgSU1EYiB+IFJvayArIFNrdXBpbmFgIChkdmUgdnlicmFuw6kgc2t1cGlueSB6ICpTcG9sb8SNbm9zxaUqIGFsZWJvICrFvcOhbmVyKikuCgpgYGB7ciBsbX0KbW9kZWwgPC0gbG0oYElNRGIgaG9kbm90ZW5pZWAgfiBSb2sgKyBTa3VwaW5hLCBkYXRhID0gZGYyKQpzdW1tYXJ5KG1vZGVsKQoKY29lZi50YmwgPC0gdGlkeShtb2RlbCwgY29uZi5pbnQgPSBUUlVFKSAlPiUKICBtdXRhdGUoCiAgICB0ZXJtID0gZHBseXI6OmNhc2Vfd2hlbigKICAgICAgdGVybSA9PSAiKEludGVyY2VwdCkiIH4gIkludGVyY2VwdCIsCiAgICAgIHRlcm0gPT0gIlJvayIgfiAiUm9rIiwKICAgICAgVFJVRSB+IHRlcm0KICAgICksCiAgICBzdGFycyA9IGRwbHlyOjpjYXNlX3doZW4oCiAgICAgIHAudmFsdWUgPCAwLjAwMSB+ICIqKioiLAogICAgICBwLnZhbHVlIDwgMC4wMSAgfiAiKioiLAogICAgICBwLnZhbHVlIDwgMC4wNSAgfiAiKiIsCiAgICAgIHAudmFsdWUgPCAwLjEgICB+ICLCtyIsCiAgICAgIFRSVUUgICAgICAgICAgICB+ICIiCiAgICApCiAgKSAlPiUKICB0cmFuc211dGUoCiAgICBUZXJtID0gdGVybSwKICAgIEVzdGltYXRlID0gZXN0aW1hdGUsCiAgICBgU3RkLiBFcnJvcmAgPSBzdGQuZXJyb3IsCiAgICBgdCB2YWx1ZWAgPSBzdGF0aXN0aWMsCiAgICBgcCB2YWx1ZWAgPSBwLnZhbHVlLAogICAgYDk1JSBDSWAgPSBzdHJpbmdyOjpzdHJfYygiWyIsIHJvdW5kKGNvbmYubG93LCAyKSwgIiwgIiwgcm91bmQoY29uZi5oaWdoLCAyKSwgIl0iKSwKICAgIFNpZyA9IHN0YXJzCiAgKQoKY29lZi50YmwgJT4lCiAga2FibGUoCiAgICBkaWdpdHMgPSAyLAogICAgY2FwdGlvbiA9ICJPTFMgcmVncmVzbsOpIGtvZWZpY2llbnR5IChJTURiIH4gUm9rICsgU2t1cGluYSkiCiAgKSAlPiUKICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGQUxTRSwgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIpKSAlPiUKICBjb2x1bW5fc3BlYygxLCBib2xkID0gVFJVRSkgJT4lCiAgcm93X3NwZWMoMCwgYm9sZCA9IFRSVUUsIGJhY2tncm91bmQgPSAiI2YyZjJmMiIpICU+JQogIGZvb3Rub3RlKAogICAgZ2VuZXJhbCA9ICJTaWduaWYuIGNvZGVzOiAqKiogcDwwLjAwMSwgKiogcDwwLjAxLCAqIHA8MC4wNSwgwrcgcDwwLjEuIiwKICAgIHRocmVlcGFydHRhYmxlID0gVFJVRQogICkKYGBg