# Load necessary libraries
library(dplyr)
library(tidyr)
library(knitr)
library(kableExtra)
library(epitools)
library(htmlTable)
library(htmltools)

# Load data
data <- read.csv("/Users/nataliochoa/RoadSafety/ResultsICBC.csv")
# Function to compute odds ratios
calculate_odds_ratios <- function(data, categories) {
  odds_ratios_list <- list()
  standard_columns <- c("Category", "Variable", "Level", "Injury", "Injury_Percent", 
                        "Non-Injury", "Non-Injury_Percent", "OddsRatio", "Lower", "Upper", "PValue")
  
  for (category in names(categories)) {
    for (var in categories[[category]]) {
      if (var %in% names(data)) {
        odds_ratio_result <- tryCatch({
          if (n_distinct(data[[var]]) == 2) {
            odds_data <- data %>%
              select(all_of(var), crashseverity) %>%
              table() %>%
              as.matrix()
            
            if (all(dim(odds_data) == c(2, 2))) {
              odds_ratio_table <- as.data.frame(epitab(odds_data, method = "oddsratio")$tab) %>%
                mutate(across(where(is.numeric), round, 4))
              
              odds_ratio_table <- cbind(Category = category, Variable = var, Level = rownames(odds_ratio_table), odds_ratio_table)
              setNames(odds_ratio_table, standard_columns)
            } else {
              setNames(data.frame(Category = category, Variable = var, Level = NA, Injury = "Not applicable", 
                                  Injury_Percent = NA, NonInjury = NA, Non_Injury_Percent = NA, 
                                  OddsRatio = NA, Lower = NA, Upper = NA, PValue = NA), standard_columns)
            }
          } else {
            setNames(data.frame(Category = category, Variable = var, Level = NA, Injury = "Not applicable", 
                                Injury_Percent = NA, NonInjury = NA, Non_Injury_Percent = NA, 
                                OddsRatio = NA, Lower = NA, Upper = NA, PValue = NA), standard_columns)
          }
        }, error = function(e) {
          setNames(data.frame(Category = category, Variable = var, Level = NA, Injury = "Not applicable", 
                              Injury_Percent = NA, NonInjury = NA, Non_Injury_Percent = NA, 
                              OddsRatio = NA, Lower = NA, Upper = NA, PValue = NA), standard_columns)
        })
        
        odds_ratios_list[[var]] <- odds_ratio_result
      }
    }
  }
  
  do.call(rbind, odds_ratios_list)
}

# Function to create HTML table without repeating categories and variables
generate_html_table <- function(odds_ratios_data, title, subtitle) {
  odds_ratios_data <- odds_ratios_data %>%
    mutate(OddsRatio_CI = ifelse(is.na(OddsRatio), "-", 
                                 paste0(OddsRatio, " (", Lower, " - ", Upper, ")"))) %>%
    select(-Lower, -Upper) %>%
    mutate(Injury_Percent_Combined = paste0(Injury, " - (", Injury_Percent, ")"),
           Non_Injury_Percent_Combined = paste0(`Non-Injury`, " - (", `Non-Injury_Percent`, ")")) %>%
    select(Category, Variable, Level, Injury_Percent_Combined, Non_Injury_Percent_Combined, PValue, OddsRatio_CI) %>%
    rename("Injury (%)" = Injury_Percent_Combined, 
           "Non-Injury (%)" = Non_Injury_Percent_Combined)
  
  # Remove duplicate rows for Category and Variable columns
  odds_ratios_data$Category <- ifelse(duplicated(odds_ratios_data$Category), "", odds_ratios_data$Category)
  odds_ratios_data$Variable <- ifelse(duplicated(odds_ratios_data$Variable), "", odds_ratios_data$Variable)
  
  row_colors <- rep(c("#f9f9f9", "#ffffff"), length.out = nrow(odds_ratios_data))
  
  htmlTable(
    odds_ratios_data %>%
      mutate(across(everything(), ~ ifelse(is.na(.) | . %in% c("NA", "NaN", "Inf", "-Inf"), "", .))),
    header = c("Category", "Variable", "Level", "Injury (%)", "Non-Injury (%)", "P-Value", "Odds Ratio (95% CI)"),
    align = 'lcccccc',
    rnames = FALSE,
    css.cell = "text-align: center; padding: 12px 15px; font-size: 12px; white-space: nowrap;",
    css.row = sprintf("background-color: %s;", row_colors),
    header.css = "background-color: #333333; font-size: 14px; text-align: center; color: white;",
    caption = paste0("<h3 style='text-align: center;'>", title, "</h3>
                      <p style='text-align: center;'><em>", subtitle, "</em></p>")
  )
}

**Analysis for Cyclist MidBlock

midblock_categories <- list(
  "Road Direction" = c("oneway", "twoways"),
  "Number of Lanes" = c("onelane", "twolanes", "threelanes", "fourlanes", "fivelanes", "sixlanes"),
  "Cyclist Infrastructure" = c("bikelanewithbarrier", "offroadbikepathcycletrack", 
                                "raisedbikelane", "twowayprotectedbicyclelane", 
                                "onewayprotectedbicyclelane", "bufferedbicyclelaneadjacenttocurb", 
                                "bufferedbicyclelaneoffsetfromcurb", 
                                "paintedbicyclelaneadjacenttocurb", 
                                "paintedbicyclelaneoffsetfromcurb", "bikeaccessibleshoulder", 
                                "sharedlanewithmarkings")
)

midblock_data <- data %>% filter(mode == "Cyclist", intersection == "No")
midblock_odds_ratios <- calculate_odds_ratios(midblock_data, midblock_categories)
Warning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrect
print(HTML(generate_html_table(midblock_odds_ratios, "Analysis for Cyclist MidBlock", "Mode: Cyclist | Intersection: No")))

Analysis for Cyclist MidBlock

Mode: Cyclist | Intersection: No

Category Variable Level Injury (%) Non-Injury (%) P-Value Odds Ratio (95% CI)
Road Direction oneway No 167 - (0.9598) 72 - (0.9863) 1 (NA - NA)
Yes 7 - (0.0402) 1 - (0.0137) 0.4424 0.3313 (0.04 - 2.7424)
twoways No 6 - (0.0345) 0 - (0) 1 (NA - NA)
Yes 168 - (0.9655) 73 - (1) 0.1837 Inf (NaN - Inf)
Number of Lanes onelane No 174 - (1) 72 - (0.9863) 1 (NA - NA)
Yes 0 - (0) 1 - (0.0137) 0.2955 Inf (NaN - Inf)
twolanes No 73 - (0.4195) 20 - (0.274) 1 (NA - NA)
Yes 101 - (0.5805) 53 - (0.726) 0.0321 1.9153 (1.0554 - 3.476)
threelanes No 166 - (0.954) 72 - (0.9863) 1 (NA - NA)
Yes 8 - (0.046) 1 - (0.0137) 0.2884 0.2882 (0.0354 - 2.3468)
fourlanes No 120 - (0.6897) 56 - (0.7671) 1 (NA - NA)
Yes 54 - (0.3103) 17 - (0.2329) 0.2808 0.6746 (0.3591 - 1.2675)
fivelanes No 167 - (0.9598) 73 - (1) 1 (NA - NA)
Yes 7 - (0.0402) 0 - (0) 0.1082 0 (0 - NaN)
sixlanes No 165 - (0.9483) 71 - (0.9726) 1 (NA - NA)
Yes 9 - (0.0517) 2 - (0.0274) 0.515 0.5164 (0.1088 - 2.4508)
Cyclist Infrastructure bikelanewithbarrier No 174 - (1) 71 - (0.9726) 1 (NA - NA)
Yes 0 - (0) 2 - (0.0274) 0.0865 Inf (NaN - Inf)
offroadbikepathcycletrack No 172 - (0.9885) 73 - (1) 1 (NA - NA)
Yes 2 - (0.0115) 0 - (0) 1 0 (0 - NaN)
raisedbikelane No 171 - (0.9828) 72 - (0.9863) 1 (NA - NA)
Yes 3 - (0.0172) 1 - (0.0137) 1 0.7917 (0.081 - 7.7388)
twowayprotectedbicyclelane No 171 - (0.9828) 72 - (0.9863) 1 (NA - NA)
Yes 3 - (0.0172) 1 - (0.0137) 1 0.7917 (0.081 - 7.7388)
onewayprotectedbicyclelane No 174 - (1) 72 - (0.9863) 1 (NA - NA)
Yes 0 - (0) 1 - (0.0137) 0.2955 Inf (NaN - Inf)
bufferedbicyclelaneadjacenttocurb No 169 - (0.9713) 72 - (0.9863) 1 (NA - NA)
Yes 5 - (0.0287) 1 - (0.0137) 0.6732 0.4694 (0.0539 - 4.0897)
bufferedbicyclelaneoffsetfromcurb No 174 - (1) 72 - (0.9863) 1 (NA - NA)
Yes 0 - (0) 1 - (0.0137) 0.2955 Inf (NaN - Inf)
paintedbicyclelaneadjacenttocurb No 138 - (0.7931) 57 - (0.7808) 1 (NA - NA)
Yes 36 - (0.2069) 16 - (0.2192) 0.8648 1.076 (0.5535 - 2.092)
paintedbicyclelaneoffsetfromcurb No 165 - (0.9483) 68 - (0.9315) 1 (NA - NA)
Yes 9 - (0.0517) 5 - (0.0685) 0.5621 1.348 (0.4358 - 4.1694)
bikeaccessibleshoulder No 162 - (0.931) 68 - (0.9315) 1 (NA - NA)
Yes 12 - (0.069) 5 - (0.0685) 1 0.9926 (0.3368 - 2.926)
sharedlanewithmarkings No 166 - (0.954) 72 - (0.9863) 1 (NA - NA)
Yes 8 - (0.046) 1 - (0.0137) 0.2884 0.2882 (0.0354 - 2.3468)
NULL

**Analysis for Cyclist Intersection

intersection_categories <- list(
  "Road Direction" = c("oneway", "twoways"),
  "Number of Lanes" = c("onelane", "twolanes", "threelanes", "fourlanes", "fivelanes", "sixlanes"),
  "Intersection Infrastructure" = c("signalized", "stopsigns", "roundabout"),
  "Cyclist Infrastructure" = c("dedicatedsignalforcyclists", "bikeboxes", "twostageturnbox", 
                                "protectedordedicatedintersection", "medianislanddiverter", 
                                "combinedbikelaneturnlane", "throughbikelane")
)

intersection_data <- data %>% filter(mode == "Cyclist", intersection == "Yes")
intersection_odds_ratios <- calculate_odds_ratios(intersection_data, intersection_categories)
Warning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrect
print(HTML(generate_html_table(intersection_odds_ratios, "Analysis for Cyclist Intersection", "Mode: Cyclist | Intersection: Yes")))

Analysis for Cyclist Intersection

Mode: Cyclist | Intersection: Yes

Category Variable Level Injury (%) Non-Injury (%) P-Value Odds Ratio (95% CI)
Road Direction oneway No 293 - (0.8906) 62 - (0.9254) 1 (NA - NA)
Yes 36 - (0.1094) 5 - (0.0746) 0.5114 0.6564 (0.2476 - 1.7396)
twoways No 5 - (0.0152) 1 - (0.0149) 1 (NA - NA)
Yes 324 - (0.9848) 66 - (0.9851) 1 1.0185 (0.1171 - 8.8608)
Number of Lanes onelane No 289 - (0.8784) 62 - (0.9254) 1 (NA - NA)
Yes 40 - (0.1216) 5 - (0.0746) 0.3969 0.5827 (0.221 - 1.536)
twolanes No 53 - (0.1611) 10 - (0.1493) 1 (NA - NA)
Yes 276 - (0.8389) 57 - (0.8507) 1 1.0946 (0.5257 - 2.2791)
threelanes No 305 - (0.9271) 61 - (0.9104) 1 (NA - NA)
Yes 24 - (0.0729) 6 - (0.0896) 0.6153 1.25 (0.4903 - 3.1868)
fourlanes No 190 - (0.5775) 39 - (0.5821) 1 (NA - NA)
Yes 139 - (0.4225) 28 - (0.4179) 1 0.9814 (0.5762 - 1.6714)
fivelanes No 316 - (0.9605) 63 - (0.9403) 1 (NA - NA)
Yes 13 - (0.0395) 4 - (0.0597) 0.5049 1.5433 (0.4873 - 4.8879)
sixlanes No 306 - (0.9301) 64 - (0.9552) 1 (NA - NA)
Yes 23 - (0.0699) 3 - (0.0448) 0.5937 0.6236 (0.1818 - 2.1399)
Intersection Infrastructure signalized No 176 - (0.535) 31 - (0.4627) 1 (NA - NA)
Yes 153 - (0.465) 36 - (0.5373) 0.2868 1.3359 (0.7888 - 2.2624)
stopsigns No 153 - (0.465) 31 - (0.4627) 1 (NA - NA)
Yes 176 - (0.535) 36 - (0.5373) 1 1.0095 (0.5961 - 1.7097)
roundabout No 323 - (0.9818) 67 - (1) 1 (NA - NA)
Yes 6 - (0.0182) 0 - (0) 0.5951 0 (0 - NaN)
Cyclist Infrastructure dedicatedsignalforcyclists No 319 - (0.9696) 67 - (1) 1 (NA - NA)
Yes 10 - (0.0304) 0 - (0) 0.2236 0 (0 - NaN)
bikeboxes No 323 - (0.9818) 64 - (0.9552) 1 (NA - NA)
Yes 6 - (0.0182) 3 - (0.0448) 0.1822 2.5234 (0.6151 - 10.3526)
twostageturnbox No 323 - (0.9818) 66 - (0.9851) 1 (NA - NA)
Yes 6 - (0.0182) 1 - (0.0149) 1 0.8157 (0.0966 - 6.8877)
protectedordedicatedintersection No 315 - (0.9574) 63 - (0.9403) 1 (NA - NA)
Yes 14 - (0.0426) 4 - (0.0597) 0.5221 1.4286 (0.4552 - 4.4831)
medianislanddiverter No 320 - (0.9726) 65 - (0.9701) 1 (NA - NA)
Yes 9 - (0.0274) 2 - (0.0299) 1 1.094 (0.231 - 5.1813)
combinedbikelaneturnlane No 322 - (0.9787) 65 - (0.9701) 1 (NA - NA)
Yes 7 - (0.0213) 2 - (0.0299) 0.6523 1.4154 (0.2875 - 6.9679)
throughbikelane No 303 - (0.921) 61 - (0.9104) 1 (NA - NA)
Yes 26 - (0.079) 6 - (0.0896) 0.8056 1.1463 (0.4526 - 2.9033)
NULL

**Analysis for Pedestrian MidBlock

pedestrian_midblock_data <- data %>% filter(mode == "Pedestrian", intersection == "No")
pedestrian_midblock_odds_ratios <- calculate_odds_ratios(pedestrian_midblock_data, midblock_categories)
Warning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrect
print(HTML(generate_html_table(pedestrian_midblock_odds_ratios, "Analysis for Pedestrian MidBlock", "Mode: Pedestrian | Intersection: No")))

Analysis for Pedestrian MidBlock

Mode: Pedestrian | Intersection: No

Category Variable Level Injury (%) Non-Injury (%) P-Value Odds Ratio (95% CI)
Road Direction oneway No 303 - (0.987) 69 - (1) 1 (NA - NA)
Yes 4 - (0.013) 0 - (0) 1 0 (0 - NaN)
twoways No 3 - (0.0098) 0 - (0) 1 (NA - NA)
Yes 304 - (0.9902) 69 - (1) 1 Inf (NaN - Inf)
Number of Lanes onelane No 302 - (0.9837) 67 - (0.971) 1 (NA - NA)
Yes 5 - (0.0163) 2 - (0.029) 0.6167 1.803 (0.3425 - 9.4924)
twolanes No 141 - (0.4593) 31 - (0.4493) 1 (NA - NA)
Yes 166 - (0.5407) 38 - (0.5507) 0.8945 1.0412 (0.6161 - 1.7597)
threelanes No 294 - (0.9577) 65 - (0.942) 1 (NA - NA)
Yes 13 - (0.0423) 4 - (0.058) 0.5286 1.3917 (0.4396 - 4.4059)
fourlanes No 198 - (0.645) 48 - (0.6957) 1 (NA - NA)
Yes 109 - (0.355) 21 - (0.3043) 0.4847 0.7947 (0.4523 - 1.3963)
fivelanes No 297 - (0.9674) 67 - (0.971) 1 (NA - NA)
Yes 10 - (0.0326) 2 - (0.029) 1 0.8866 (0.1898 - 4.1402)
sixlanes No 290 - (0.9446) 65 - (0.942) 1 (NA - NA)
Yes 17 - (0.0554) 4 - (0.058) 1 1.0498 (0.3419 - 3.2235)
Cyclist Infrastructure bikelanewithbarrier Not applicable - (NA) NA - (NA) -
offroadbikepathcycletrack Not applicable - (NA) NA - (NA) -
raisedbikelane Not applicable - (NA) NA - (NA) -
twowayprotectedbicyclelane Not applicable - (NA) NA - (NA) -
onewayprotectedbicyclelane Not applicable - (NA) NA - (NA) -
bufferedbicyclelaneadjacenttocurb Not applicable - (NA) NA - (NA) -
bufferedbicyclelaneoffsetfromcurb Not applicable - (NA) NA - (NA) -
paintedbicyclelaneadjacenttocurb Not applicable - (NA) NA - (NA) -
paintedbicyclelaneoffsetfromcurb Not applicable - (NA) NA - (NA) -
bikeaccessibleshoulder Not applicable - (NA) NA - (NA) -
sharedlanewithmarkings Not applicable - (NA) NA - (NA) -
NULL

Analysis for Pedestrian Intersection

pedestrian_intersection_data <- data %>% filter(mode == "Pedestrian", intersection == "Yes")
pedestrian_intersection_odds_ratios <- calculate_odds_ratios(pedestrian_intersection_data, intersection_categories)
Warning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrectWarning: Chi-squared approximation may be incorrect
print(HTML(generate_html_table(pedestrian_intersection_odds_ratios, "Analysis for Pedestrian Intersection", "Mode: Pedestrian | Intersection: Yes")))

Analysis for Pedestrian Intersection

Mode: Pedestrian | Intersection: Yes

Category Variable Level Injury (%) Non-Injury (%) P-Value Odds Ratio (95% CI)
Road Direction oneway No 398 - (0.9365) 67 - (0.9306) 1 (NA - NA)
Yes 27 - (0.0635) 5 - (0.0694) 0.7968 1.1001 (0.4093 - 2.9567)
twoways No 1 - (0.0024) 1 - (0.0139) 1 (NA - NA)
Yes 424 - (0.9976) 71 - (0.9861) 0.269 0.1675 (0.0104 - 2.7078)
Number of Lanes onelane No 401 - (0.9435) 69 - (0.9583) 1 (NA - NA)
Yes 24 - (0.0565) 3 - (0.0417) 0.7826 0.7264 (0.213 - 2.4782)
twolanes No 94 - (0.2212) 18 - (0.25) 1 (NA - NA)
Yes 331 - (0.7788) 54 - (0.75) 0.6472 0.852 (0.4768 - 1.5225)
threelanes No 368 - (0.8659) 62 - (0.8611) 1 (NA - NA)
Yes 57 - (0.1341) 10 - (0.1389) 0.8538 1.0413 (0.5049 - 2.1475)
fourlanes No 177 - (0.4165) 32 - (0.4444) 1 (NA - NA)
Yes 248 - (0.5835) 40 - (0.5556) 0.6992 0.8921 (0.5393 - 1.4757)
fivelanes No 394 - (0.9271) 67 - (0.9306) 1 (NA - NA)
Yes 31 - (0.0729) 5 - (0.0694) 1 0.9485 (0.3562 - 2.5258)
sixlanes No 388 - (0.9129) 65 - (0.9028) 1 (NA - NA)
Yes 37 - (0.0871) 7 - (0.0972) 0.822 1.1293 (0.4829 - 2.6408)
Intersection Infrastructure signalized No 137 - (0.3224) 25 - (0.3472) 1 (NA - NA)
Yes 288 - (0.6776) 47 - (0.6528) 0.6849 0.8943 (0.5285 - 1.5134)
stopsigns No 283 - (0.6659) 43 - (0.5972) 1 (NA - NA)
Yes 142 - (0.3341) 29 - (0.4028) 0.2837 1.3441 (0.8053 - 2.2434)
roundabout No 421 - (0.9906) 72 - (1) 1 (NA - NA)
Yes 4 - (0.0094) 0 - (0) 1 0 (0 - NaN)
Cyclist Infrastructure dedicatedsignalforcyclists Not applicable - (NA) NA - (NA) -
bikeboxes Not applicable - (NA) NA - (NA) -
twostageturnbox Not applicable - (NA) NA - (NA) -
protectedordedicatedintersection Not applicable - (NA) NA - (NA) -
medianislanddiverter Not applicable - (NA) NA - (NA) -
combinedbikelaneturnlane Not applicable - (NA) NA - (NA) -
throughbikelane Not applicable - (NA) NA - (NA) -
NULL
LS0tCnRpdGxlOiAiQWNjaWRlbnQgQW5hbHlzaXM6IEN5Y2xpc3RzIGFuZCBQZWRlc3RyaWFucyIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAyCiAgICB0aGVtZTogY29zbW8KICBwZGZfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMgotLS0KCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1UUlVFLCB3YXJuaW5nPVRSVUV9CiMgTG9hZCBuZWNlc3NhcnkgbGlicmFyaWVzCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoa25pdHIpCmxpYnJhcnkoa2FibGVFeHRyYSkKbGlicmFyeShlcGl0b29scykKbGlicmFyeShodG1sVGFibGUpCmxpYnJhcnkoaHRtbHRvb2xzKQoKIyBMb2FkIGRhdGEKZGF0YSA8LSByZWFkLmNzdigiL1VzZXJzL25hdGFsaW9jaG9hL1JvYWRTYWZldHkvUmVzdWx0c0lDQkMuY3N2IikKYGBgCgpgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9VFJVRSwgd2FybmluZz1UUlVFfQojIEZ1bmN0aW9uIHRvIGNvbXB1dGUgb2RkcyByYXRpb3MKY2FsY3VsYXRlX29kZHNfcmF0aW9zIDwtIGZ1bmN0aW9uKGRhdGEsIGNhdGVnb3JpZXMpIHsKICBvZGRzX3JhdGlvc19saXN0IDwtIGxpc3QoKQogIHN0YW5kYXJkX2NvbHVtbnMgPC0gYygiQ2F0ZWdvcnkiLCAiVmFyaWFibGUiLCAiTGV2ZWwiLCAiSW5qdXJ5IiwgIkluanVyeV9QZXJjZW50IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICJOb24tSW5qdXJ5IiwgIk5vbi1Jbmp1cnlfUGVyY2VudCIsICJPZGRzUmF0aW8iLCAiTG93ZXIiLCAiVXBwZXIiLCAiUFZhbHVlIikKICAKICBmb3IgKGNhdGVnb3J5IGluIG5hbWVzKGNhdGVnb3JpZXMpKSB7CiAgICBmb3IgKHZhciBpbiBjYXRlZ29yaWVzW1tjYXRlZ29yeV1dKSB7CiAgICAgIGlmICh2YXIgJWluJSBuYW1lcyhkYXRhKSkgewogICAgICAgIG9kZHNfcmF0aW9fcmVzdWx0IDwtIHRyeUNhdGNoKHsKICAgICAgICAgIGlmIChuX2Rpc3RpbmN0KGRhdGFbW3Zhcl1dKSA9PSAyKSB7CiAgICAgICAgICAgIG9kZHNfZGF0YSA8LSBkYXRhICU+JQogICAgICAgICAgICAgIHNlbGVjdChhbGxfb2YodmFyKSwgY3Jhc2hzZXZlcml0eSkgJT4lCiAgICAgICAgICAgICAgdGFibGUoKSAlPiUKICAgICAgICAgICAgICBhcy5tYXRyaXgoKQogICAgICAgICAgICAKICAgICAgICAgICAgaWYgKGFsbChkaW0ob2Rkc19kYXRhKSA9PSBjKDIsIDIpKSkgewogICAgICAgICAgICAgIG9kZHNfcmF0aW9fdGFibGUgPC0gYXMuZGF0YS5mcmFtZShlcGl0YWIob2Rkc19kYXRhLCBtZXRob2QgPSAib2Rkc3JhdGlvIikkdGFiKSAlPiUKICAgICAgICAgICAgICAgIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIHJvdW5kLCA0KSkKICAgICAgICAgICAgICAKICAgICAgICAgICAgICBvZGRzX3JhdGlvX3RhYmxlIDwtIGNiaW5kKENhdGVnb3J5ID0gY2F0ZWdvcnksIFZhcmlhYmxlID0gdmFyLCBMZXZlbCA9IHJvd25hbWVzKG9kZHNfcmF0aW9fdGFibGUpLCBvZGRzX3JhdGlvX3RhYmxlKQogICAgICAgICAgICAgIHNldE5hbWVzKG9kZHNfcmF0aW9fdGFibGUsIHN0YW5kYXJkX2NvbHVtbnMpCiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgc2V0TmFtZXMoZGF0YS5mcmFtZShDYXRlZ29yeSA9IGNhdGVnb3J5LCBWYXJpYWJsZSA9IHZhciwgTGV2ZWwgPSBOQSwgSW5qdXJ5ID0gIk5vdCBhcHBsaWNhYmxlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbmp1cnlfUGVyY2VudCA9IE5BLCBOb25Jbmp1cnkgPSBOQSwgTm9uX0luanVyeV9QZXJjZW50ID0gTkEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgT2Rkc1JhdGlvID0gTkEsIExvd2VyID0gTkEsIFVwcGVyID0gTkEsIFBWYWx1ZSA9IE5BKSwgc3RhbmRhcmRfY29sdW1ucykKICAgICAgICAgICAgfQogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgc2V0TmFtZXMoZGF0YS5mcmFtZShDYXRlZ29yeSA9IGNhdGVnb3J5LCBWYXJpYWJsZSA9IHZhciwgTGV2ZWwgPSBOQSwgSW5qdXJ5ID0gIk5vdCBhcHBsaWNhYmxlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSW5qdXJ5X1BlcmNlbnQgPSBOQSwgTm9uSW5qdXJ5ID0gTkEsIE5vbl9Jbmp1cnlfUGVyY2VudCA9IE5BLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBPZGRzUmF0aW8gPSBOQSwgTG93ZXIgPSBOQSwgVXBwZXIgPSBOQSwgUFZhbHVlID0gTkEpLCBzdGFuZGFyZF9jb2x1bW5zKQogICAgICAgICAgfQogICAgICAgIH0sIGVycm9yID0gZnVuY3Rpb24oZSkgewogICAgICAgICAgc2V0TmFtZXMoZGF0YS5mcmFtZShDYXRlZ29yeSA9IGNhdGVnb3J5LCBWYXJpYWJsZSA9IHZhciwgTGV2ZWwgPSBOQSwgSW5qdXJ5ID0gIk5vdCBhcHBsaWNhYmxlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEluanVyeV9QZXJjZW50ID0gTkEsIE5vbkluanVyeSA9IE5BLCBOb25fSW5qdXJ5X1BlcmNlbnQgPSBOQSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9kZHNSYXRpbyA9IE5BLCBMb3dlciA9IE5BLCBVcHBlciA9IE5BLCBQVmFsdWUgPSBOQSksIHN0YW5kYXJkX2NvbHVtbnMpCiAgICAgICAgfSkKICAgICAgICAKICAgICAgICBvZGRzX3JhdGlvc19saXN0W1t2YXJdXSA8LSBvZGRzX3JhdGlvX3Jlc3VsdAogICAgICB9CiAgICB9CiAgfQogIAogIGRvLmNhbGwocmJpbmQsIG9kZHNfcmF0aW9zX2xpc3QpCn0KCiMgRnVuY3Rpb24gdG8gY3JlYXRlIEhUTUwgdGFibGUgd2l0aG91dCByZXBlYXRpbmcgY2F0ZWdvcmllcyBhbmQgdmFyaWFibGVzCmdlbmVyYXRlX2h0bWxfdGFibGUgPC0gZnVuY3Rpb24ob2Rkc19yYXRpb3NfZGF0YSwgdGl0bGUsIHN1YnRpdGxlKSB7CiAgb2Rkc19yYXRpb3NfZGF0YSA8LSBvZGRzX3JhdGlvc19kYXRhICU+JQogICAgbXV0YXRlKE9kZHNSYXRpb19DSSA9IGlmZWxzZShpcy5uYShPZGRzUmF0aW8pLCAiLSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZTAoT2Rkc1JhdGlvLCAiICgiLCBMb3dlciwgIiAtICIsIFVwcGVyLCAiKSIpKSkgJT4lCiAgICBzZWxlY3QoLUxvd2VyLCAtVXBwZXIpICU+JQogICAgbXV0YXRlKEluanVyeV9QZXJjZW50X0NvbWJpbmVkID0gcGFzdGUwKEluanVyeSwgIiAtICgiLCBJbmp1cnlfUGVyY2VudCwgIikiKSwKICAgICAgICAgICBOb25fSW5qdXJ5X1BlcmNlbnRfQ29tYmluZWQgPSBwYXN0ZTAoYE5vbi1Jbmp1cnlgLCAiIC0gKCIsIGBOb24tSW5qdXJ5X1BlcmNlbnRgLCAiKSIpKSAlPiUKICAgIHNlbGVjdChDYXRlZ29yeSwgVmFyaWFibGUsIExldmVsLCBJbmp1cnlfUGVyY2VudF9Db21iaW5lZCwgTm9uX0luanVyeV9QZXJjZW50X0NvbWJpbmVkLCBQVmFsdWUsIE9kZHNSYXRpb19DSSkgJT4lCiAgICByZW5hbWUoIkluanVyeSAoJSkiID0gSW5qdXJ5X1BlcmNlbnRfQ29tYmluZWQsIAogICAgICAgICAgICJOb24tSW5qdXJ5ICglKSIgPSBOb25fSW5qdXJ5X1BlcmNlbnRfQ29tYmluZWQpCiAgCiAgIyBSZW1vdmUgZHVwbGljYXRlIHJvd3MgZm9yIENhdGVnb3J5IGFuZCBWYXJpYWJsZSBjb2x1bW5zCiAgb2Rkc19yYXRpb3NfZGF0YSRDYXRlZ29yeSA8LSBpZmVsc2UoZHVwbGljYXRlZChvZGRzX3JhdGlvc19kYXRhJENhdGVnb3J5KSwgIiIsIG9kZHNfcmF0aW9zX2RhdGEkQ2F0ZWdvcnkpCiAgb2Rkc19yYXRpb3NfZGF0YSRWYXJpYWJsZSA8LSBpZmVsc2UoZHVwbGljYXRlZChvZGRzX3JhdGlvc19kYXRhJFZhcmlhYmxlKSwgIiIsIG9kZHNfcmF0aW9zX2RhdGEkVmFyaWFibGUpCiAgCiAgcm93X2NvbG9ycyA8LSByZXAoYygiI2Y5ZjlmOSIsICIjZmZmZmZmIiksIGxlbmd0aC5vdXQgPSBucm93KG9kZHNfcmF0aW9zX2RhdGEpKQogIAogIGh0bWxUYWJsZSgKICAgIG9kZHNfcmF0aW9zX2RhdGEgJT4lCiAgICAgIG11dGF0ZShhY3Jvc3MoZXZlcnl0aGluZygpLCB+IGlmZWxzZShpcy5uYSguKSB8IC4gJWluJSBjKCJOQSIsICJOYU4iLCAiSW5mIiwgIi1JbmYiKSwgIiIsIC4pKSksCiAgICBoZWFkZXIgPSBjKCJDYXRlZ29yeSIsICJWYXJpYWJsZSIsICJMZXZlbCIsICJJbmp1cnkgKCUpIiwgIk5vbi1Jbmp1cnkgKCUpIiwgIlAtVmFsdWUiLCAiT2RkcyBSYXRpbyAoOTUlIENJKSIpLAogICAgYWxpZ24gPSAnbGNjY2NjYycsCiAgICBybmFtZXMgPSBGQUxTRSwKICAgIGNzcy5jZWxsID0gInRleHQtYWxpZ246IGNlbnRlcjsgcGFkZGluZzogMTJweCAxNXB4OyBmb250LXNpemU6IDEycHg7IHdoaXRlLXNwYWNlOiBub3dyYXA7IiwKICAgIGNzcy5yb3cgPSBzcHJpbnRmKCJiYWNrZ3JvdW5kLWNvbG9yOiAlczsiLCByb3dfY29sb3JzKSwKICAgIGhlYWRlci5jc3MgPSAiYmFja2dyb3VuZC1jb2xvcjogIzMzMzMzMzsgZm9udC1zaXplOiAxNHB4OyB0ZXh0LWFsaWduOiBjZW50ZXI7IGNvbG9yOiB3aGl0ZTsiLAogICAgY2FwdGlvbiA9IHBhc3RlMCgiPGgzIHN0eWxlPSd0ZXh0LWFsaWduOiBjZW50ZXI7Jz4iLCB0aXRsZSwgIjwvaDM+CiAgICAgICAgICAgICAgICAgICAgICA8cCBzdHlsZT0ndGV4dC1hbGlnbjogY2VudGVyOyc+PGVtPiIsIHN1YnRpdGxlLCAiPC9lbT48L3A+IikKICApCn0KCmBgYAoKKipBbmFseXNpcyBmb3IgQ3ljbGlzdCBNaWRCbG9jawoKYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPVRSVUUsIHdhcm5pbmc9VFJVRX0KbWlkYmxvY2tfY2F0ZWdvcmllcyA8LSBsaXN0KAogICJSb2FkIERpcmVjdGlvbiIgPSBjKCJvbmV3YXkiLCAidHdvd2F5cyIpLAogICJOdW1iZXIgb2YgTGFuZXMiID0gYygib25lbGFuZSIsICJ0d29sYW5lcyIsICJ0aHJlZWxhbmVzIiwgImZvdXJsYW5lcyIsICJmaXZlbGFuZXMiLCAic2l4bGFuZXMiKSwKICAiQ3ljbGlzdCBJbmZyYXN0cnVjdHVyZSIgPSBjKCJiaWtlbGFuZXdpdGhiYXJyaWVyIiwgIm9mZnJvYWRiaWtlcGF0aGN5Y2xldHJhY2siLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicmFpc2VkYmlrZWxhbmUiLCAidHdvd2F5cHJvdGVjdGVkYmljeWNsZWxhbmUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAib25ld2F5cHJvdGVjdGVkYmljeWNsZWxhbmUiLCAiYnVmZmVyZWRiaWN5Y2xlbGFuZWFkamFjZW50dG9jdXJiIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJ1ZmZlcmVkYmljeWNsZWxhbmVvZmZzZXRmcm9tY3VyYiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwYWludGVkYmljeWNsZWxhbmVhZGphY2VudHRvY3VyYiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwYWludGVkYmljeWNsZWxhbmVvZmZzZXRmcm9tY3VyYiIsICJiaWtlYWNjZXNzaWJsZXNob3VsZGVyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInNoYXJlZGxhbmV3aXRobWFya2luZ3MiKQopCgptaWRibG9ja19kYXRhIDwtIGRhdGEgJT4lIGZpbHRlcihtb2RlID09ICJDeWNsaXN0IiwgaW50ZXJzZWN0aW9uID09ICJObyIpCm1pZGJsb2NrX29kZHNfcmF0aW9zIDwtIGNhbGN1bGF0ZV9vZGRzX3JhdGlvcyhtaWRibG9ja19kYXRhLCBtaWRibG9ja19jYXRlZ29yaWVzKQoKcHJpbnQoSFRNTChnZW5lcmF0ZV9odG1sX3RhYmxlKG1pZGJsb2NrX29kZHNfcmF0aW9zLCAiQW5hbHlzaXMgZm9yIEN5Y2xpc3QgTWlkQmxvY2siLCAiTW9kZTogQ3ljbGlzdCB8IEludGVyc2VjdGlvbjogTm8iKSkpCgoKYGBgCgoqKkFuYWx5c2lzIGZvciBDeWNsaXN0IEludGVyc2VjdGlvbgoKYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPVRSVUUsIHdhcm5pbmc9VFJVRX0KaW50ZXJzZWN0aW9uX2NhdGVnb3JpZXMgPC0gbGlzdCgKICAiUm9hZCBEaXJlY3Rpb24iID0gYygib25ld2F5IiwgInR3b3dheXMiKSwKICAiTnVtYmVyIG9mIExhbmVzIiA9IGMoIm9uZWxhbmUiLCAidHdvbGFuZXMiLCAidGhyZWVsYW5lcyIsICJmb3VybGFuZXMiLCAiZml2ZWxhbmVzIiwgInNpeGxhbmVzIiksCiAgIkludGVyc2VjdGlvbiBJbmZyYXN0cnVjdHVyZSIgPSBjKCJzaWduYWxpemVkIiwgInN0b3BzaWducyIsICJyb3VuZGFib3V0IiksCiAgIkN5Y2xpc3QgSW5mcmFzdHJ1Y3R1cmUiID0gYygiZGVkaWNhdGVkc2lnbmFsZm9yY3ljbGlzdHMiLCAiYmlrZWJveGVzIiwgInR3b3N0YWdldHVybmJveCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwcm90ZWN0ZWRvcmRlZGljYXRlZGludGVyc2VjdGlvbiIsICJtZWRpYW5pc2xhbmRkaXZlcnRlciIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb21iaW5lZGJpa2VsYW5ldHVybmxhbmUiLCAidGhyb3VnaGJpa2VsYW5lIikKKQoKaW50ZXJzZWN0aW9uX2RhdGEgPC0gZGF0YSAlPiUgZmlsdGVyKG1vZGUgPT0gIkN5Y2xpc3QiLCBpbnRlcnNlY3Rpb24gPT0gIlllcyIpCmludGVyc2VjdGlvbl9vZGRzX3JhdGlvcyA8LSBjYWxjdWxhdGVfb2Rkc19yYXRpb3MoaW50ZXJzZWN0aW9uX2RhdGEsIGludGVyc2VjdGlvbl9jYXRlZ29yaWVzKQoKcHJpbnQoSFRNTChnZW5lcmF0ZV9odG1sX3RhYmxlKGludGVyc2VjdGlvbl9vZGRzX3JhdGlvcywgIkFuYWx5c2lzIGZvciBDeWNsaXN0IEludGVyc2VjdGlvbiIsICJNb2RlOiBDeWNsaXN0IHwgSW50ZXJzZWN0aW9uOiBZZXMiKSkpCgpgYGAKCioqQW5hbHlzaXMgZm9yIFBlZGVzdHJpYW4gTWlkQmxvY2sKCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1UUlVFLCB3YXJuaW5nPVRSVUV9CnBlZGVzdHJpYW5fbWlkYmxvY2tfZGF0YSA8LSBkYXRhICU+JSBmaWx0ZXIobW9kZSA9PSAiUGVkZXN0cmlhbiIsIGludGVyc2VjdGlvbiA9PSAiTm8iKQpwZWRlc3RyaWFuX21pZGJsb2NrX29kZHNfcmF0aW9zIDwtIGNhbGN1bGF0ZV9vZGRzX3JhdGlvcyhwZWRlc3RyaWFuX21pZGJsb2NrX2RhdGEsIG1pZGJsb2NrX2NhdGVnb3JpZXMpCgpwcmludChIVE1MKGdlbmVyYXRlX2h0bWxfdGFibGUocGVkZXN0cmlhbl9taWRibG9ja19vZGRzX3JhdGlvcywgIkFuYWx5c2lzIGZvciBQZWRlc3RyaWFuIE1pZEJsb2NrIiwgIk1vZGU6IFBlZGVzdHJpYW4gfCBJbnRlcnNlY3Rpb246IE5vIikpKQoKYGBgCgpBbmFseXNpcyBmb3IgUGVkZXN0cmlhbiBJbnRlcnNlY3Rpb24KCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1UUlVFLCB3YXJuaW5nPVRSVUV9CnBlZGVzdHJpYW5faW50ZXJzZWN0aW9uX2RhdGEgPC0gZGF0YSAlPiUgZmlsdGVyKG1vZGUgPT0gIlBlZGVzdHJpYW4iLCBpbnRlcnNlY3Rpb24gPT0gIlllcyIpCnBlZGVzdHJpYW5faW50ZXJzZWN0aW9uX29kZHNfcmF0aW9zIDwtIGNhbGN1bGF0ZV9vZGRzX3JhdGlvcyhwZWRlc3RyaWFuX2ludGVyc2VjdGlvbl9kYXRhLCBpbnRlcnNlY3Rpb25fY2F0ZWdvcmllcykKCnByaW50KEhUTUwoZ2VuZXJhdGVfaHRtbF90YWJsZShwZWRlc3RyaWFuX2ludGVyc2VjdGlvbl9vZGRzX3JhdGlvcywgIkFuYWx5c2lzIGZvciBQZWRlc3RyaWFuIEludGVyc2VjdGlvbiIsICJNb2RlOiBQZWRlc3RyaWFuIHwgSW50ZXJzZWN0aW9uOiBZZXMiKSkpCgpgYGAKCgo=