## install and load needs, if not yet present
# install.packages("needs")
# library(needs)
# packages used in this markdown document
needs(tidyverse, sf)

1 Übersicht über die Daten

1.1 Autobahnabschnitte und Geschwindigkeitsbeschränkungen

Die Geodaten zu Autobahnen und Tempolimits stammen von OpenStreeMap (OSM). Zwar werden die Daten nach einem wikipediaähnlichen Community-Prinzip gepflegt, sind in Deutschland aber von sehr großer Präzision und Vollständigkeit.

Hier ein Vergleich der OSM-Daten (Stand 18.02.2019) mit Angaben der Bundesanstalt für Straßenwesen (Stand: 1. Quartal 2015).

data_OSM_filtered = st_read("data/processed/OSM_autobahnnetz.geojson", quiet = T) %>% 
    st_transform(25832) %>% 
    mutate(length = as.double(st_length(.)))
limit_categories = data_OSM_filtered %>%
    as.data.frame() %>%
    select(-geometry) %>% 
    mutate(maxspeed_group = case_when(
        maxspeed == "none" | is.na(maxspeed) ~ "unlimited",
        maxspeed %in% c("120", "130", "140") ~ "limit_120_130_140",
        maxspeed %in% c("signals", "variable") ~ "dynamic",
        T ~ "limit_100_and_below"
    )) %>% 
    group_by(maxspeed_group) %>% 
    summarise(length = sum(length) / 1000) %>% 
    mutate(share = length / sum(length)) %>% 
    arrange(-length)
# disabeling scientific notation
options(scipen = 999)
limit_categories_comparison = limit_categories %>% 
    select(tempolimit = maxspeed_group, share) %>% 
    mutate(source = "OSM") %>% 
    add_row(tempolimit = "unlimited", share = 0.704, source = "bast") %>% 
    add_row(tempolimit = "limit_120_130_140", share = 0.125, source = "bast") %>% 
    add_row(tempolimit = "limit_100_and_below", share = 0.083, source = "bast") %>% 
    add_row(tempolimit = "dynamic", share = 0.088, source = "bast")
ggplot(limit_categories_comparison, aes(x = fct_rev(tempolimit), y = share, fill = source, label = paste0(round(share*100,1), "%"))) +
    geom_col(position = "dodge") +
    geom_text(position = position_dodge(width = 0.9), hjust = 0.5, vjust = -0.4) +
    labs(x="", y="", title = "Tempolimits auf Autobahnen - nach Datenquelle", subtitle = "Anteil Streckenkilometer",  fill= "Quelle")

1.2 Unfalldaten

Stammen aus dem Unfallatlas der statistischen Ämter des Bundes und der Länder. Enthalten sind alle polizeilich erfassten Straßenunfälle aus dem Jahr 2017, mit Ausnahme der Bundesländer Nordrhein-Westfalen, Berlin, Thüringen und Mecklenburg-Vorpommern.

Zu den einzelnen Unfällen liegen folgende Informationen vor:

  • Unfallart (Zusammenstoß, Abkommen von der Fahrbahn,…)
  • Unfallkategorie (Unfall mit Getöteten/Schwerverletzten/Leichtverletzten)
  • Unfalltyp (Fahrunfall, Abbiegeunfall,…)
  • Lichtverhältnisse (Tageslicht, Dämmerung, Dunkelheit)
  • Straßenzustand (trocken, nass, winterglatt)
  • Wochentag und Uhrzeit
  • Beteiligter (Rad, PKW, Fußgänger, Kraftrad)
unfaelle_2017_autobahn = st_read("data/processed/unfaelle_2017_autobahn.gpkg", quiet = T) %>% st_set_crs(25832)

Im Jahr 2017 wurden insgesamt 195.229 Unfälle erfasst. 13949 davon konnten einem Autobahnabschnitt zugeordnet werden (ob der Unfall auf einer Autobahn stattgefunden hat, wird nicht gesonders ausgewiesen. Wir zählen hier alle Unfälle, deren Koordinaten maximal 10 Meter von einer Autobahn entfernt sind)

1.3 Verkehrsdichte

Zur Verkehrsdichte liegen Daten aus der automatischen Verkehrszählung 2017 vor. An insgesamt 950 Autobahn-Zählstellen bundesweit wurde dort u.A. die Zahl der PKW pro Tag und die mittlere stündliche Verkehrsstärke tags/nachts gemessen. Für die Analyse haben wir jedem Autobahnabschnitt die Verkehrsdichte der nächstgelegenen Zählstelle zugeordnet.

unfaelle_pro_abschnitt = read_csv("data/processed/unfaelle_pro_abschnitt.csv")

2 Passieren auf Autobahnabschnitten ohne Tempolimit mehr Unfälle?

lenght_per_type = data_OSM_filtered %>% 
    as_data_frame() %>% 
    select(-geometry) %>% 
    filter(!is.na(maxspeed)) %>% 
    mutate(tempolimit = if_else(maxspeed == "none" | is.na(maxspeed), "ohne Tempolimit", "mit Tempolimit")) %>% 
    group_by(tempolimit) %>% 
    summarise(total_length = sum(length))
accidents_per_type = unfaelle_2017_autobahn %>% 
    as_data_frame() %>% 
    select(-geom) %>% 
    filter(!is.na(maxspeed)) %>% 
    mutate(tempolimit = if_else(maxspeed == "none" | is.na(maxspeed), "ohne Tempolimit", "mit Tempolimit")) %>% 
    count(tempolimit) %>% 
    left_join(lenght_per_type, by = "tempolimit") %>%
    mutate(accidents_per_1000_km = n / total_length * 1000)
ggplot(accidents_per_type) +
    geom_col(aes(tempolimit, accidents_per_1000_km, fill = fct_rev(tempolimit)), show.legend = F) +
    geom_text(aes(tempolimit, accidents_per_1000_km, label = round(accidents_per_1000_km,2)), vjust = -0.4) +
    labs(x = "", y = "Unfälle pro 1000 Kilometer", title = "Zahl der Unfälle pro Streckenkilometer Autobahn", subtitle = "Angaben für 12 Bundesländer aus dem Jahr 2017")

Berücksichtigt man nur die Zahl der Unfälle pro Streckenkilometer, so passieren auf Strecken ohne Tempolimit überraschenderweise weniger Unfälle. Die Verkehrsdichte auf Abschnitten mit Tempolimit ist allerdings deutlich höher (teilwiese ist sie ja auch der Grund der für das Tempolimit). Eine bessere Vergleichsgröße wäre die Zahl der Unfälle pro gefahrenem Kilometer –> siehe nächste Grafik.

accidents_per_type_with_traffic = unfaelle_pro_abschnitt %>% 
    mutate(tempolimit = if_else(maxspeed == "none" | is.na(maxspeed), "ohne Tempolimit", "mit Tempolimit")) %>% 
    group_by(tempolimit) %>% 
    summarise(
        total_km = sum(yearly_km_in_section),
        accidents_tötlich = sum(tödlich, na.rm = T),
        accidents_schwerverl. = sum(schwerverletzt, na.rm = T),
        accidents_leichtverl. = sum(leichtverletzt, na.rm = T),
        accidents_total = sum(tödlich, schwerverletzt, leichtverletzt, na.rm = T)
    ) %>% 
    mutate(accidents_tötlich_per_mrd_km = accidents_tötlich / total_km * 1000000000) %>% 
    mutate(accidents_schwerverl._per_mrd_km = accidents_schwerverl. / total_km * 1000000000) %>% 
    mutate(accidents_leichtverl._per_mrd_km = accidents_leichtverl. / total_km * 1000000000) %>% 
    mutate(accidents_total_per_mrd_km = accidents_total / total_km * 1000000000) %>% 
    gather(art, anzahl, ends_with("mrd_km"))
ggplot(accidents_per_type_with_traffic %>% filter(!is.na(tempolimit)) %>% filter(art == "accidents_total_per_mrd_km")) +
    geom_col(aes(tempolimit, anzahl, fill = fct_rev(tempolimit)), show.legend = F) +
    geom_text(aes(tempolimit, anzahl, label = round(anzahl, 1)), vjust = -0.4) +
    labs(x = "", y = "Unfälle pro Mrd. km", title = "Zahl der Unfälle pro Mrd. gefahrenen Kilometern Autobahn", subtitle = "Angaben für 12 Bundesländer aus dem Jahr 2017")

Auch unter Berücksichtigung der gefahrenen Kilometer ist die Zahl der Unfälle auf Abschnitten ohne Tempolimit überraschenderweise geringer. Allerdings hat auch der Vergleich hier noch einen Haken. Es ist davon auszugehen, dass eher gefährliche Abschnitte (kurvig, hohes Verkehrsaufkommen,…) häufiger begrenzt sind und die Zahl der Unfälle schon deshalb hier höher liegt.

3 Passieren auf Autobahnabschnitten mit Tempolimit schwerere Unfälle?

accidents_per_type_severity = unfaelle_2017_autobahn %>% 
    as_data_frame() %>% 
    select(-geom) %>% 
    filter(!is.na(maxspeed)) %>% 
    mutate(tempolimit = if_else(maxspeed == "none" | is.na(maxspeed), "ohne Tempolimit", "mit Tempolimit")) %>% 
    count(tempolimit, UKATEGORIE) %>% 
    spread(UKATEGORIE, n) %>%
    rename(tödlich = `1`, schwerverletzt = `2`, leichtverletzt = `3`) %>%
    mutate(anteil_tödlich = tödlich / sum(tödlich)) %>% 
    mutate(anteil_schwerverletzt = schwerverletzt / sum(schwerverletzt)) %>% 
    mutate(anteil_leichtverletzt = leichtverletzt / sum(leichtverletzt)) %>% 
    left_join(lenght_per_type, by = "tempolimit") %>%
    mutate(anteil_km = total_length / sum(total_length)) %>% 
    gather(art, anteil, starts_with("anteil")) 
ggplot(accidents_per_type_severity) +
    geom_col(aes(art, anteil, fill = fct_rev(tempolimit))) + 
    geom_text(aes(art, anteil, label = paste0(round(anteil*100), "%"))) +
    labs(x = "", y = "", fill = "", title = "Unfallkategorie nach Streckentyp", 
         subtitle = "Wie viel Prozent der tödlichen Unfälle (etc.) auf Abschnitten mit/ohne Tempolimit passieren")

Obwohl laut OSM-Daten auf 68% der Autobahnabschnitte kein Tempolimit gilt, entfallen 73% der tötlichen Unfälle in diese Kategorie. Der Anteil der Leichtverletzten hingegen ist hier deutlich geringer. Wenn auf Abschnitten ohne Tempolimit ein Unfall geschieht, so kommt es seltener zu leichten Verletzungen, aber häufiger zu Todesfällen.

ggplot(
    accidents_per_type_with_traffic %>% 
        filter(art != "accidents_total_per_mrd_km") %>% 
        mutate(art = str_replace_all(art, "accidents_","")) %>% 
        mutate(art = str_replace_all(art, "_per_mrd_km",""))) +
    geom_col(aes(art, anzahl, fill = fct_rev(tempolimit), group = tempolimit), position = "dodge") +
    geom_text(aes(art, anzahl, label = round(anzahl, 2), group = tempolimit), vjust = -0.4, position = position_dodge(0.9)) +
    labs(x = "", y = "Unfälle pro Mrd. km", title = "Zahl der Unfälle pro Mrd. gefahrenen Kilometern Autobahn", subtitle = "Angaben für 12 Bundesländer aus dem Jahr 2017", fill = "")

accidents_per_mrd_with = accidents_per_type_with_traffic %>% 
    filter(tempolimit == "mit Tempolimit" & art == "accidents_tötlich_per_mrd_km") %>% 
    pull(anzahl) %>% 
    round(2)
accidents_per_mrd_without = accidents_per_type_with_traffic %>% 
    filter(tempolimit == "ohne Tempolimit" & art == "accidents_tötlich_per_mrd_km") %>% 
    pull(anzahl) %>% 
    round(2)

Sauberer wird der Vergleich auch hier durch die Berücksichtigung der gefahrenen Kilometer. Während ohne Tempolimit 0.95 tödliche Unfälle pro Mrd. Kilometer passieren, liegt dieser Wert in Abschnitten ohne Tempolimit bei 1.67, also rund 75% höher. Auch bei Schwerverletzten passieren pro gefahrenem Kilometer auf Abschnitten ohne Tempolimit knapp 20% mehr Unfälle.

# Zahlen aus DESTATIS 2017, S. 23
deaths_per_accident = 409 / 356
# Zahlen aus DESTATIS 2017, S. 6
km_total_2017 = 246
model_accidents = 246 * accidents_per_mrd_with
model_deaths = model_accidents * deaths_per_accident

Laut offiziellen Zahlen (DESTATIS 2017) gab es im Jahr 2017 bundesweit 356 tödliche Unfälle (mit 409 Todesopfern). Unter der Annahme, dass sich durch die Einführung eines Tempolimits die Zahl der tödlichen Unfälle pro Mrd. Kilometer wie in der Datenauswertung auf 0,95 senken ließe, würde dies zu einer Reduzierung der Zahl der tödlichen Unfälle auf 234 (mit 268 Todesopfer) führen. Anders ausgedrückt: Alleine im Jahr 2017 hätten sich 141 Todesopfer durch die Einführung eines Autobahn-Tempolimits verhindern lassen.

4 Plausibilitätsprüfung

4.1 Quervergleich mit Primärquellen

Laut DESTATIS 2017 (S. 222) lag die Zahl der Unfälle auf Autobahnen pro Mrd. gefahrene Kilometer im Jahr 2017 insgesamt bei 85, in unserer Auswertung bei 76.

Die Zahl der tödlichen Unfälle pro Mrd. Kilomter liegt laut DESTATIS 2017 (S. 222) bei 1,7, bei uns bei 1,4.

Die jährliche Fahrleistung auf Autobahnen liegt laut DESTATIS 2017 (S. 215) bei 246 Mrd. Kilometer, mit unseren Grundlagendaten (für alle Bundesländer) ergeben sich 251 Mrd. km.

Der Blick in andere Primärquellen zeigt nur geringe Abweichungen und unterstützt so die Plausibilität der Auswertung. Kleinere Abweichungen warem schon deshalb zu erwarten, da nur für 12 der 16 Bundesländer Daten vorliegen und verschieden Geodaten verwendet werden (OSM/Bast).

4.2 Beeinflussung durch Lichtverhältnisse ausschließen

accidents_light_conditions = unfaelle_2017_autobahn %>% 
    as.data.frame() %>% 
    select(-geom) %>% 
    filter(UKATEGORIE == "1") %>% 
    mutate(tempolimit = if_else(maxspeed == "none" | is.na(maxspeed), "ohne Tempolimit", "mit Tempolimit")) %>% 
    mutate(LICHT = as.character(LICHT)) %>% 
    mutate(LICHT = if_else(LICHT == "0", "Tageslicht", LICHT)) %>%
    mutate(LICHT = if_else(LICHT == "1", "Dämmerung", LICHT)) %>%
    mutate(LICHT = if_else(LICHT == "2", "Dunkelheit", LICHT)) %>%
    count(tempolimit, LICHT)
ggplot(accidents_light_conditions) +
    geom_col(aes(tempolimit, n, fill = LICHT), position = "fill") +
    labs(x = "", y ="", title = "Anteil tödlicher Unfälle nach Tempolimit und Lichtverhältnissen")

4.3 Beeinflussung durch Straßenverhältnisse ausschließen

accidents_road_conditions = unfaelle_2017_autobahn %>% 
    as.data.frame() %>% 
    select(-geom) %>% 
    filter(UKATEGORIE == "1") %>% 
    mutate(tempolimit = if_else(maxspeed == "none" | is.na(maxspeed), "ohne Tempolimit", "mit Tempolimit")) %>% 
    mutate(STRZUSTAND = as.character(STRZUSTAND)) %>% 
    mutate(STRZUSTAND = if_else(STRZUSTAND == "0", "trocken", STRZUSTAND)) %>%
    mutate(STRZUSTAND = if_else(STRZUSTAND == "1", "nass/feucht/schlüpfrig", STRZUSTAND)) %>%
    mutate(STRZUSTAND = if_else(STRZUSTAND == "2", "winterglatt", STRZUSTAND)) %>%
    count(tempolimit, STRZUSTAND)
ggplot(accidents_road_conditions) +
    geom_col(aes(tempolimit, n, fill = STRZUSTAND), position = "fill") +
    labs(x = "", y ="", title = "Anteil tödlicher Unfälle nach Tempolimit und Straßenverhältnissen")

Vergleich man Straßenzustand und Lichtverhältniss bei den tötlichen Unfällen mit bzw. ohne Tempolimit, so zeigen sich nur sehr geringe Unterschiede. Es kann folglich ausgeschlossen werden, dass die ermittelte Zahl der tötlichen Unfällen pro Mrd. gefahrener Kilometer auf Abschnitten mit/ohne Tempolimit auf einer verzerrten durch eine Verzerrung der Grundgesamtheit zu erklären ist.

LS0tCnRpdGxlOiAiQXV0b2JhaG5lbjogWnVzYW1tZW5oYW5nIHp3aXNjaGVuIFRlbXBvbGltaXQgdW5kIFVuZsOkbGxlbiIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBjc3M6IHN0eWxlLmNzcwogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCi0tLQoKYGBge3J9CiMjIGluc3RhbGwgYW5kIGxvYWQgbmVlZHMsIGlmIG5vdCB5ZXQgcHJlc2VudAojIGluc3RhbGwucGFja2FnZXMoIm5lZWRzIikKIyBsaWJyYXJ5KG5lZWRzKQoKIyBwYWNrYWdlcyB1c2VkIGluIHRoaXMgbWFya2Rvd24gZG9jdW1lbnQKbmVlZHModGlkeXZlcnNlLCBzZikKYGBgCgoKCiMgw5xiZXJzaWNodCDDvGJlciBkaWUgRGF0ZW4KCiMjIEF1dG9iYWhuYWJzY2huaXR0ZSB1bmQgR2VzY2h3aW5kaWdrZWl0c2Jlc2NocsOkbmt1bmdlbgpEaWUgR2VvZGF0ZW4genUgQXV0b2JhaG5lbiB1bmQgVGVtcG9saW1pdHMgc3RhbW1lbiB2b24gKipPcGVuU3RyZWVNYXAgKE9TTSkqKi4gWndhciB3ZXJkZW4gZGllIERhdGVuIG5hY2ggZWluZW0gd2lraXBlZGlhw6RobmxpY2hlbiBDb21tdW5pdHktUHJpbnppcCBnZXBmbGVndCwgc2luZCBpbiBEZXV0c2NobGFuZCBhYmVyIHZvbiBzZWhyIGdyb8OfZXIgUHLDpHppc2lvbiB1bmQgVm9sbHN0w6RuZGlna2VpdC4KCkhpZXIgZWluIFZlcmdsZWljaCBkZXIgT1NNLURhdGVuIChTdGFuZCAxOC4wMi4yMDE5KSBtaXQgQW5nYWJlbiBkZXIgW0J1bmRlc2Fuc3RhbHQgZsO8ciBTdHJhw59lbndlc2VuXShodHRwczovL3d3dy5iYXN0LmRlL0JBU3RfMjAxNy9ERS9WZXJrZWhyc3RlY2huaWsvUHVibGlrYXRpb25lbi9Eb3dubG9hZC1QdWJsaWthdGlvbmVuL0Rvd25sb2Fkcy9WMS1CQUItVGVtcG9saW1pdC0yMDE1LnBkZj9fX2Jsb2I9cHVibGljYXRpb25GaWxlJnY9NSkgKFN0YW5kOiAxLiBRdWFydGFsIDIwMTUpLgpgYGB7cn0KZGF0YV9PU01fZmlsdGVyZWQgPSBzdF9yZWFkKCJkYXRhL3Byb2Nlc3NlZC9PU01fYXV0b2JhaG5uZXR6Lmdlb2pzb24iLCBxdWlldCA9IFQpICU+JSAKCXN0X3RyYW5zZm9ybSgyNTgzMikgJT4lIAoJbXV0YXRlKGxlbmd0aCA9IGFzLmRvdWJsZShzdF9sZW5ndGgoLikpKQoKbGltaXRfY2F0ZWdvcmllcyA9IGRhdGFfT1NNX2ZpbHRlcmVkICU+JQoJYXMuZGF0YS5mcmFtZSgpICU+JQoJc2VsZWN0KC1nZW9tZXRyeSkgJT4lIAoJbXV0YXRlKG1heHNwZWVkX2dyb3VwID0gY2FzZV93aGVuKAoJCW1heHNwZWVkID09ICJub25lIiB8IGlzLm5hKG1heHNwZWVkKSB+ICJ1bmxpbWl0ZWQiLAoJCW1heHNwZWVkICVpbiUgYygiMTIwIiwgIjEzMCIsICIxNDAiKSB+ICJsaW1pdF8xMjBfMTMwXzE0MCIsCgkJbWF4c3BlZWQgJWluJSBjKCJzaWduYWxzIiwgInZhcmlhYmxlIikgfiAiZHluYW1pYyIsCgkJVCB+ICJsaW1pdF8xMDBfYW5kX2JlbG93IgoJKSkgJT4lIAoJZ3JvdXBfYnkobWF4c3BlZWRfZ3JvdXApICU+JSAKCXN1bW1hcmlzZShsZW5ndGggPSBzdW0obGVuZ3RoKSAvIDEwMDApICU+JSAKCW11dGF0ZShzaGFyZSA9IGxlbmd0aCAvIHN1bShsZW5ndGgpKSAlPiUgCglhcnJhbmdlKC1sZW5ndGgpCgojIGRpc2FiZWxpbmcgc2NpZW50aWZpYyBub3RhdGlvbgpvcHRpb25zKHNjaXBlbiA9IDk5OSkKCmxpbWl0X2NhdGVnb3JpZXNfY29tcGFyaXNvbiA9IGxpbWl0X2NhdGVnb3JpZXMgJT4lIAoJc2VsZWN0KHRlbXBvbGltaXQgPSBtYXhzcGVlZF9ncm91cCwgc2hhcmUpICU+JSAKCW11dGF0ZShzb3VyY2UgPSAiT1NNIikgJT4lIAoJYWRkX3Jvdyh0ZW1wb2xpbWl0ID0gInVubGltaXRlZCIsIHNoYXJlID0gMC43MDQsIHNvdXJjZSA9ICJiYXN0IikgJT4lIAoJYWRkX3Jvdyh0ZW1wb2xpbWl0ID0gImxpbWl0XzEyMF8xMzBfMTQwIiwgc2hhcmUgPSAwLjEyNSwgc291cmNlID0gImJhc3QiKSAlPiUgCglhZGRfcm93KHRlbXBvbGltaXQgPSAibGltaXRfMTAwX2FuZF9iZWxvdyIsIHNoYXJlID0gMC4wODMsIHNvdXJjZSA9ICJiYXN0IikgJT4lIAoJYWRkX3Jvdyh0ZW1wb2xpbWl0ID0gImR5bmFtaWMiLCBzaGFyZSA9IDAuMDg4LCBzb3VyY2UgPSAiYmFzdCIpCgpnZ3Bsb3QobGltaXRfY2F0ZWdvcmllc19jb21wYXJpc29uLCBhZXMoeCA9IGZjdF9yZXYodGVtcG9saW1pdCksIHkgPSBzaGFyZSwgZmlsbCA9IHNvdXJjZSwgbGFiZWwgPSBwYXN0ZTAocm91bmQoc2hhcmUqMTAwLDEpLCAiJSIpKSkgKwoJZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSArCglnZW9tX3RleHQocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOSksIGhqdXN0ID0gMC41LCB2anVzdCA9IC0wLjQpICsKCWxhYnMoeD0iIiwgeT0iIiwgdGl0bGUgPSAiVGVtcG9saW1pdHMgYXVmIEF1dG9iYWhuZW4gLSBuYWNoIERhdGVucXVlbGxlIiwgc3VidGl0bGUgPSAiQW50ZWlsIFN0cmVja2Vua2lsb21ldGVyIiwgIGZpbGw9ICJRdWVsbGUiKQpgYGAKCgoKIyMgVW5mYWxsZGF0ZW4KClN0YW1tZW4gYXVzIGRlbSAqKltVbmZhbGxhdGxhcyBkZXIgc3RhdGlzdGlzY2hlbiDDhG10ZXIgZGVzIEJ1bmRlcyB1bmQgZGVyIEzDpG5kZXJdKGh0dHBzOi8vdW5mYWxsYXRsYXMuc3RhdGlzdGlrcG9ydGFsLmRlL19vcGVuZGF0YS5odG1sKSoqLiBFbnRoYWx0ZW4gc2luZCBhbGxlIHBvbGl6ZWlsaWNoIGVyZmFzc3RlbiBTdHJhw59lbnVuZsOkbGxlIGF1cyBkZW0gSmFociAyMDE3LCBtaXQgQXVzbmFobWUgZGVyIEJ1bmRlc2zDpG5kZXIgTm9yZHJoZWluLVdlc3RmYWxlbiwgQmVybGluLCBUaMO8cmluZ2VuIHVuZCBNZWNrbGVuYnVyZy1Wb3Jwb21tZXJuLgoKWnUgZGVuIGVpbnplbG5lbiBVbmbDpGxsZW4gbGllZ2VuIGZvbGdlbmRlIEluZm9ybWF0aW9uZW4gdm9yOgoKLSBVbmZhbGxhcnQgKFp1c2FtbWVuc3Rvw58sIEFia29tbWVuIHZvbiBkZXIgRmFocmJhaG4sLi4uKQotIFVuZmFsbGthdGVnb3JpZSAoVW5mYWxsIG1pdCBHZXTDtnRldGVuL1NjaHdlcnZlcmxldHp0ZW4vTGVpY2h0dmVybGV0enRlbikKLSBVbmZhbGx0eXAgKEZhaHJ1bmZhbGwsIEFiYmllZ2V1bmZhbGwsLi4uKQotIExpY2h0dmVyaMOkbHRuaXNzZSAoVGFnZXNsaWNodCwgRMOkbW1lcnVuZywgRHVua2VsaGVpdCkKLSBTdHJhw59lbnp1c3RhbmQgKHRyb2NrZW4sIG5hc3MsIHdpbnRlcmdsYXR0KQotIFdvY2hlbnRhZyB1bmQgVWhyemVpdAotIEJldGVpbGlndGVyIChSYWQsIFBLVywgRnXDn2fDpG5nZXIsIEtyYWZ0cmFkKQoKYGBge3J9CnVuZmFlbGxlXzIwMTdfYXV0b2JhaG4gPSBzdF9yZWFkKCJkYXRhL3Byb2Nlc3NlZC91bmZhZWxsZV8yMDE3X2F1dG9iYWhuLmdwa2ciLCBxdWlldCA9IFQpICU+JSBzdF9zZXRfY3JzKDI1ODMyKQpgYGAKCkltIEphaHIgMjAxNyB3dXJkZW4gaW5zZ2VzYW10IDE5NS4yMjkgVW5mw6RsbGUgZXJmYXNzdC4KYHIgbnJvdyh1bmZhZWxsZV8yMDE3X2F1dG9iYWhuKWAgZGF2b24ga29ubnRlbiBlaW5lbSBBdXRvYmFobmFic2Nobml0dCB6dWdlb3JkbmV0IHdlcmRlbiAob2IgZGVyIFVuZmFsbCBhdWYgZWluZXIgQXV0b2JhaG4gc3RhdHRnZWZ1bmRlbiBoYXQsIHdpcmQgbmljaHQgZ2Vzb25kZXJzIGF1c2dld2llc2VuLiBXaXIgesOkaGxlbiBoaWVyIGFsbGUgVW5mw6RsbGUsIGRlcmVuIEtvb3JkaW5hdGVuIG1heGltYWwgMTAgTWV0ZXIgdm9uIGVpbmVyIEF1dG9iYWhuIGVudGZlcm50IHNpbmQpCgoKCiMjIFZlcmtlaHJzZGljaHRlClp1ciBWZXJrZWhyc2RpY2h0ZSBsaWVnZW4gRGF0ZW4gYXVzIGRlciBbKiphdXRvbWF0aXNjaGVuIFZlcmtlaHJzesOkaGx1bmcgMjAxNyoqXShodHRwczovL3d3dy5iYXN0LmRlL0JBU3RfMjAxNy9ERS9WZXJrZWhyc3RlY2huaWsvRmFjaHRoZW1lbi92Mi12ZXJrZWhyc3phZWhsdW5nL0FrdHVlbGwvemFlaGxfYWt0dWVsbF9ub2RlLmh0bWwpIHZvci4gQW4gaW5zZ2VzYW10IDk1MCBBdXRvYmFobi1aw6RobHN0ZWxsZW4gYnVuZGVzd2VpdCB3dXJkZSBkb3J0IHUuQS4gZGllIFphaGwgZGVyIFBLVyBwcm8gVGFnIHVuZCBkaWUgbWl0dGxlcmUgc3TDvG5kbGljaGUgVmVya2VocnNzdMOkcmtlIHRhZ3MvbmFjaHRzIGdlbWVzc2VuLiBGw7xyIGRpZSBBbmFseXNlIGhhYmVuIHdpciBqZWRlbSBBdXRvYmFobmFic2Nobml0dCBkaWUgVmVya2VocnNkaWNodGUgZGVyIG7DpGNoc3RnZWxlZ2VuZW4gWsOkaGxzdGVsbGUgenVnZW9yZG5ldC4KYGBge3IgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9CnVuZmFlbGxlX3Byb19hYnNjaG5pdHQgPSByZWFkX2NzdigiZGF0YS9wcm9jZXNzZWQvdW5mYWVsbGVfcHJvX2Fic2Nobml0dC5jc3YiKQpgYGAKCgoKIyBQYXNzaWVyZW4gYXVmIEF1dG9iYWhuYWJzY2huaXR0ZW4gb2huZSBUZW1wb2xpbWl0IG1laHIgVW5mw6RsbGU/CmBgYHtyfQpsZW5naHRfcGVyX3R5cGUgPSBkYXRhX09TTV9maWx0ZXJlZCAlPiUgCglhc19kYXRhX2ZyYW1lKCkgJT4lIAoJc2VsZWN0KC1nZW9tZXRyeSkgJT4lIAoJZmlsdGVyKCFpcy5uYShtYXhzcGVlZCkpICU+JSAKCW11dGF0ZSh0ZW1wb2xpbWl0ID0gaWZfZWxzZShtYXhzcGVlZCA9PSAibm9uZSIgfCBpcy5uYShtYXhzcGVlZCksICJvaG5lIFRlbXBvbGltaXQiLCAibWl0IFRlbXBvbGltaXQiKSkgJT4lIAoJZ3JvdXBfYnkodGVtcG9saW1pdCkgJT4lIAoJc3VtbWFyaXNlKHRvdGFsX2xlbmd0aCA9IHN1bShsZW5ndGgpKQoKYWNjaWRlbnRzX3Blcl90eXBlID0gdW5mYWVsbGVfMjAxN19hdXRvYmFobiAlPiUgCglhc19kYXRhX2ZyYW1lKCkgJT4lIAoJc2VsZWN0KC1nZW9tKSAlPiUgCglmaWx0ZXIoIWlzLm5hKG1heHNwZWVkKSkgJT4lIAoJbXV0YXRlKHRlbXBvbGltaXQgPSBpZl9lbHNlKG1heHNwZWVkID09ICJub25lIiB8IGlzLm5hKG1heHNwZWVkKSwgIm9obmUgVGVtcG9saW1pdCIsICJtaXQgVGVtcG9saW1pdCIpKSAlPiUgCgljb3VudCh0ZW1wb2xpbWl0KSAlPiUgCglsZWZ0X2pvaW4obGVuZ2h0X3Blcl90eXBlLCBieSA9ICJ0ZW1wb2xpbWl0IikgJT4lCgltdXRhdGUoYWNjaWRlbnRzX3Blcl8xMDAwX2ttID0gbiAvIHRvdGFsX2xlbmd0aCAqIDEwMDApCgpnZ3Bsb3QoYWNjaWRlbnRzX3Blcl90eXBlKSArCglnZW9tX2NvbChhZXModGVtcG9saW1pdCwgYWNjaWRlbnRzX3Blcl8xMDAwX2ttLCBmaWxsID0gZmN0X3Jldih0ZW1wb2xpbWl0KSksIHNob3cubGVnZW5kID0gRikgKwoJZ2VvbV90ZXh0KGFlcyh0ZW1wb2xpbWl0LCBhY2NpZGVudHNfcGVyXzEwMDBfa20sIGxhYmVsID0gcm91bmQoYWNjaWRlbnRzX3Blcl8xMDAwX2ttLDIpKSwgdmp1c3QgPSAtMC40KSArCglsYWJzKHggPSAiIiwgeSA9ICJVbmbDpGxsZSBwcm8gMTAwMCBLaWxvbWV0ZXIiLCB0aXRsZSA9ICJaYWhsIGRlciBVbmbDpGxsZSBwcm8gU3RyZWNrZW5raWxvbWV0ZXIgQXV0b2JhaG4iLCBzdWJ0aXRsZSA9ICJBbmdhYmVuIGbDvHIgMTIgQnVuZGVzbMOkbmRlciBhdXMgZGVtIEphaHIgMjAxNyIpCmBgYAo+IEJlcsO8Y2tzaWNodGlndCBtYW4gbnVyIGRpZSBaYWhsIGRlciBVbmbDpGxsZSBwcm8gU3RyZWNrZW5raWxvbWV0ZXIsIHNvIHBhc3NpZXJlbiBhdWYgU3RyZWNrZW4gb2huZSBUZW1wb2xpbWl0IMO8YmVycmFzY2hlbmRlcndlaXNlIHdlbmlnZXIgVW5mw6RsbGUuIERpZSBWZXJrZWhyc2RpY2h0ZSBhdWYgQWJzY2huaXR0ZW4gbWl0IFRlbXBvbGltaXQgaXN0IGFsbGVyZGluZ3MgZGV1dGxpY2ggaMO2aGVyICh0ZWlsd2llc2UgaXN0IHNpZSBqYSBhdWNoIGRlciBHcnVuZCBkZXIgZsO8ciBkYXMgVGVtcG9saW1pdCkuIEVpbmUgYmVzc2VyZSBWZXJnbGVpY2hzZ3LDtsOfZSB3w6RyZSBkaWUgWmFobCBkZXIgVW5mw6RsbGUgcHJvIGdlZmFocmVuZW0gS2lsb21ldGVyIC0tPiBzaWVoZSBuw6RjaHN0ZSBHcmFmaWsuCgoKYGBge3J9CmFjY2lkZW50c19wZXJfdHlwZV93aXRoX3RyYWZmaWMgPSB1bmZhZWxsZV9wcm9fYWJzY2huaXR0ICU+JSAKCW11dGF0ZSh0ZW1wb2xpbWl0ID0gaWZfZWxzZShtYXhzcGVlZCA9PSAibm9uZSIgfCBpcy5uYShtYXhzcGVlZCksICJvaG5lIFRlbXBvbGltaXQiLCAibWl0IFRlbXBvbGltaXQiKSkgJT4lIAoJZ3JvdXBfYnkodGVtcG9saW1pdCkgJT4lIAoJc3VtbWFyaXNlKAoJCXRvdGFsX2ttID0gc3VtKHllYXJseV9rbV9pbl9zZWN0aW9uKSwKCQlhY2NpZGVudHNfdMO2dGxpY2ggPSBzdW0odMO2ZGxpY2gsIG5hLnJtID0gVCksCgkJYWNjaWRlbnRzX3NjaHdlcnZlcmwuID0gc3VtKHNjaHdlcnZlcmxldHp0LCBuYS5ybSA9IFQpLAoJCWFjY2lkZW50c19sZWljaHR2ZXJsLiA9IHN1bShsZWljaHR2ZXJsZXR6dCwgbmEucm0gPSBUKSwKCQlhY2NpZGVudHNfdG90YWwgPSBzdW0odMO2ZGxpY2gsIHNjaHdlcnZlcmxldHp0LCBsZWljaHR2ZXJsZXR6dCwgbmEucm0gPSBUKQoJKSAlPiUgCgltdXRhdGUoYWNjaWRlbnRzX3TDtnRsaWNoX3Blcl9tcmRfa20gPSBhY2NpZGVudHNfdMO2dGxpY2ggLyB0b3RhbF9rbSAqIDEwMDAwMDAwMDApICU+JSAKCW11dGF0ZShhY2NpZGVudHNfc2Nod2VydmVybC5fcGVyX21yZF9rbSA9IGFjY2lkZW50c19zY2h3ZXJ2ZXJsLiAvIHRvdGFsX2ttICogMTAwMDAwMDAwMCkgJT4lIAoJbXV0YXRlKGFjY2lkZW50c19sZWljaHR2ZXJsLl9wZXJfbXJkX2ttID0gYWNjaWRlbnRzX2xlaWNodHZlcmwuIC8gdG90YWxfa20gKiAxMDAwMDAwMDAwKSAlPiUgCgltdXRhdGUoYWNjaWRlbnRzX3RvdGFsX3Blcl9tcmRfa20gPSBhY2NpZGVudHNfdG90YWwgLyB0b3RhbF9rbSAqIDEwMDAwMDAwMDApICU+JSAKCWdhdGhlcihhcnQsIGFuemFobCwgZW5kc193aXRoKCJtcmRfa20iKSkKCmdncGxvdChhY2NpZGVudHNfcGVyX3R5cGVfd2l0aF90cmFmZmljICU+JSBmaWx0ZXIoIWlzLm5hKHRlbXBvbGltaXQpKSAlPiUgZmlsdGVyKGFydCA9PSAiYWNjaWRlbnRzX3RvdGFsX3Blcl9tcmRfa20iKSkgKwoJZ2VvbV9jb2woYWVzKHRlbXBvbGltaXQsIGFuemFobCwgZmlsbCA9IGZjdF9yZXYodGVtcG9saW1pdCkpLCBzaG93LmxlZ2VuZCA9IEYpICsKCWdlb21fdGV4dChhZXModGVtcG9saW1pdCwgYW56YWhsLCBsYWJlbCA9IHJvdW5kKGFuemFobCwgMSkpLCB2anVzdCA9IC0wLjQpICsKCWxhYnMoeCA9ICIiLCB5ID0gIlVuZsOkbGxlIHBybyBNcmQuIGttIiwgdGl0bGUgPSAiWmFobCBkZXIgVW5mw6RsbGUgcHJvIE1yZC4gZ2VmYWhyZW5lbiBLaWxvbWV0ZXJuIEF1dG9iYWhuIiwgc3VidGl0bGUgPSAiQW5nYWJlbiBmw7xyIDEyIEJ1bmRlc2zDpG5kZXIgYXVzIGRlbSBKYWhyIDIwMTciKQpgYGAKPiAqKkF1Y2ggdW50ZXIgQmVyw7xja3NpY2h0aWd1bmcgZGVyIGdlZmFocmVuZW4gS2lsb21ldGVyIGlzdCBkaWUgWmFobCBkZXIgVW5mw6RsbGUgYXVmIEFic2Nobml0dGVuIG9obmUgVGVtcG9saW1pdCDDvGJlcnJhc2NoZW5kZXJ3ZWlzZSBnZXJpbmdlci4qKiBBbGxlcmRpbmdzIGhhdCBhdWNoIGRlciBWZXJnbGVpY2ggaGllciBub2NoIGVpbmVuIEhha2VuLiAqKkVzIGlzdCBkYXZvbiBhdXN6dWdlaGVuLCBkYXNzIGVoZXIgZ2Vmw6RocmxpY2hlIEFic2Nobml0dGUgKGt1cnZpZywgaG9oZXMgVmVya2VocnNhdWZrb21tZW4sLi4uKSBow6R1ZmlnZXIgYmVncmVuenQgc2luZCB1bmQgZGllIFphaGwgZGVyIFVuZsOkbGxlIHNjaG9uIGRlc2hhbGIgaGllciBow7ZoZXIgbGllZ3QuKioKCgojIFBhc3NpZXJlbiBhdWYgQXV0b2JhaG5hYnNjaG5pdHRlbiBtaXQgVGVtcG9saW1pdCBzY2h3ZXJlcmUgVW5mw6RsbGU/CmBgYHtyfQphY2NpZGVudHNfcGVyX3R5cGVfc2V2ZXJpdHkgPSB1bmZhZWxsZV8yMDE3X2F1dG9iYWhuICU+JSAKCWFzX2RhdGFfZnJhbWUoKSAlPiUgCglzZWxlY3QoLWdlb20pICU+JSAKCWZpbHRlcighaXMubmEobWF4c3BlZWQpKSAlPiUgCgltdXRhdGUodGVtcG9saW1pdCA9IGlmX2Vsc2UobWF4c3BlZWQgPT0gIm5vbmUiIHwgaXMubmEobWF4c3BlZWQpLCAib2huZSBUZW1wb2xpbWl0IiwgIm1pdCBUZW1wb2xpbWl0IikpICU+JSAKCWNvdW50KHRlbXBvbGltaXQsIFVLQVRFR09SSUUpICU+JSAKCXNwcmVhZChVS0FURUdPUklFLCBuKSAlPiUKCXJlbmFtZSh0w7ZkbGljaCA9IGAxYCwgc2Nod2VydmVybGV0enQgPSBgMmAsIGxlaWNodHZlcmxldHp0ID0gYDNgKSAlPiUKCW11dGF0ZShhbnRlaWxfdMO2ZGxpY2ggPSB0w7ZkbGljaCAvIHN1bSh0w7ZkbGljaCkpICU+JSAKCW11dGF0ZShhbnRlaWxfc2Nod2VydmVybGV0enQgPSBzY2h3ZXJ2ZXJsZXR6dCAvIHN1bShzY2h3ZXJ2ZXJsZXR6dCkpICU+JSAKCW11dGF0ZShhbnRlaWxfbGVpY2h0dmVybGV0enQgPSBsZWljaHR2ZXJsZXR6dCAvIHN1bShsZWljaHR2ZXJsZXR6dCkpICU+JSAKCWxlZnRfam9pbihsZW5naHRfcGVyX3R5cGUsIGJ5ID0gInRlbXBvbGltaXQiKSAlPiUKCW11dGF0ZShhbnRlaWxfa20gPSB0b3RhbF9sZW5ndGggLyBzdW0odG90YWxfbGVuZ3RoKSkgJT4lIAoJZ2F0aGVyKGFydCwgYW50ZWlsLCBzdGFydHNfd2l0aCgiYW50ZWlsIikpIAoKZ2dwbG90KGFjY2lkZW50c19wZXJfdHlwZV9zZXZlcml0eSkgKwoJZ2VvbV9jb2woYWVzKGFydCwgYW50ZWlsLCBmaWxsID0gZmN0X3Jldih0ZW1wb2xpbWl0KSkpICsgCglnZW9tX3RleHQoYWVzKGFydCwgYW50ZWlsLCBsYWJlbCA9IHBhc3RlMChyb3VuZChhbnRlaWwqMTAwKSwgIiUiKSkpICsKCWxhYnMoeCA9ICIiLCB5ID0gIiIsIGZpbGwgPSAiIiwgdGl0bGUgPSAiVW5mYWxsa2F0ZWdvcmllIG5hY2ggU3RyZWNrZW50eXAiLCAKCQkgc3VidGl0bGUgPSAiV2llIHZpZWwgUHJvemVudCBkZXIgdMO2ZGxpY2hlbiBVbmbDpGxsZSAoZXRjLikgYXVmIEFic2Nobml0dGVuIG1pdC9vaG5lIFRlbXBvbGltaXQgcGFzc2llcmVuIikKYGBgCj4gT2J3b2hsIGxhdXQgT1NNLURhdGVuIGF1ZiA2OCUgZGVyIEF1dG9iYWhuYWJzY2huaXR0ZSBrZWluIFRlbXBvbGltaXQgZ2lsdCwgZW50ZmFsbGVuIDczJSBkZXIgdMO2dGxpY2hlbiBVbmbDpGxsZSBpbiBkaWVzZSBLYXRlZ29yaWUuIERlciBBbnRlaWwgZGVyIExlaWNodHZlcmxldHp0ZW4gaGluZ2VnZW4gaXN0IGhpZXIgZGV1dGxpY2ggZ2VyaW5nZXIuICoqV2VubiBhdWYgQWJzY2huaXR0ZW4gb2huZSBUZW1wb2xpbWl0IGVpbiBVbmZhbGwgZ2VzY2hpZWh0LCBzbyBrb21tdCBlcyBzZWx0ZW5lciB6dSBsZWljaHRlbiBWZXJsZXR6dW5nZW4sIGFiZXIgaMOkdWZpZ2VyIHp1IFRvZGVzZsOkbGxlbioqLgoKCmBgYHtyfQpnZ3Bsb3QoCglhY2NpZGVudHNfcGVyX3R5cGVfd2l0aF90cmFmZmljICU+JSAKCQlmaWx0ZXIoYXJ0ICE9ICJhY2NpZGVudHNfdG90YWxfcGVyX21yZF9rbSIpICU+JSAKCQltdXRhdGUoYXJ0ID0gc3RyX3JlcGxhY2VfYWxsKGFydCwgImFjY2lkZW50c18iLCIiKSkgJT4lIAoJCW11dGF0ZShhcnQgPSBzdHJfcmVwbGFjZV9hbGwoYXJ0LCAiX3Blcl9tcmRfa20iLCIiKSkpICsKCWdlb21fY29sKGFlcyhhcnQsIGFuemFobCwgZmlsbCA9IGZjdF9yZXYodGVtcG9saW1pdCksIGdyb3VwID0gdGVtcG9saW1pdCksIHBvc2l0aW9uID0gImRvZGdlIikgKwoJZ2VvbV90ZXh0KGFlcyhhcnQsIGFuemFobCwgbGFiZWwgPSByb3VuZChhbnphaGwsIDIpLCBncm91cCA9IHRlbXBvbGltaXQpLCB2anVzdCA9IC0wLjQsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC45KSkgKwoJbGFicyh4ID0gIiIsIHkgPSAiVW5mw6RsbGUgcHJvIE1yZC4ga20iLCB0aXRsZSA9ICJaYWhsIGRlciBVbmbDpGxsZSBwcm8gTXJkLiBnZWZhaHJlbmVuIEtpbG9tZXRlcm4gQXV0b2JhaG4iLCBzdWJ0aXRsZSA9ICJBbmdhYmVuIGbDvHIgMTIgQnVuZGVzbMOkbmRlciBhdXMgZGVtIEphaHIgMjAxNyIsIGZpbGwgPSAiIikKCgphY2NpZGVudHNfcGVyX21yZF93aXRoID0gYWNjaWRlbnRzX3Blcl90eXBlX3dpdGhfdHJhZmZpYyAlPiUgCglmaWx0ZXIodGVtcG9saW1pdCA9PSAibWl0IFRlbXBvbGltaXQiICYgYXJ0ID09ICJhY2NpZGVudHNfdMO2dGxpY2hfcGVyX21yZF9rbSIpICU+JSAKCXB1bGwoYW56YWhsKSAlPiUgCglyb3VuZCgyKQoKYWNjaWRlbnRzX3Blcl9tcmRfd2l0aG91dCA9IGFjY2lkZW50c19wZXJfdHlwZV93aXRoX3RyYWZmaWMgJT4lIAoJZmlsdGVyKHRlbXBvbGltaXQgPT0gIm9obmUgVGVtcG9saW1pdCIgJiBhcnQgPT0gImFjY2lkZW50c190w7Z0bGljaF9wZXJfbXJkX2ttIikgJT4lIAoJcHVsbChhbnphaGwpICU+JSAKCXJvdW5kKDIpCmBgYAoKPiBTYXViZXJlciB3aXJkIGRlciBWZXJnbGVpY2ggYXVjaCBoaWVyIGR1cmNoIGRpZSBCZXLDvGNrc2ljaHRpZ3VuZyBkZXIgZ2VmYWhyZW5lbiBLaWxvbWV0ZXIuICoqV8OkaHJlbmQgb2huZSBUZW1wb2xpbWl0IGByIGFjY2lkZW50c19wZXJfbXJkX3dpdGhgIHTDtmRsaWNoZSBVbmbDpGxsZSBwcm8gTXJkLiBLaWxvbWV0ZXIgcGFzc2llcmVuLCBsaWVndCBkaWVzZXIgV2VydCBpbiBBYnNjaG5pdHRlbiBvaG5lIFRlbXBvbGltaXQgYmVpIGByIGFjY2lkZW50c19wZXJfbXJkX3dpdGhvdXRgLCBhbHNvIHJ1bmQgNzUlIGjDtmhlcioqLiBBdWNoIGJlaSBTY2h3ZXJ2ZXJsZXR6dGVuIHBhc3NpZXJlbiBwcm8gZ2VmYWhyZW5lbSBLaWxvbWV0ZXIgYXVmIEFic2Nobml0dGVuIG9obmUgVGVtcG9saW1pdCBrbmFwcCAyMCUgbWVociBVbmbDpGxsZS4KCgpgYGB7cn0KIyBaYWhsZW4gYXVzIERFU1RBVElTIDIwMTcsIFMuIDIzCmRlYXRoc19wZXJfYWNjaWRlbnQgPSA0MDkgLyAzNTYKCiMgWmFobGVuIGF1cyBERVNUQVRJUyAyMDE3LCBTLiA2CmttX3RvdGFsXzIwMTcgPSAyNDYKCm1vZGVsX2FjY2lkZW50cyA9IDI0NiAqIGFjY2lkZW50c19wZXJfbXJkX3dpdGgKbW9kZWxfZGVhdGhzID0gbW9kZWxfYWNjaWRlbnRzICogZGVhdGhzX3Blcl9hY2NpZGVudApgYGAKCj4gTGF1dCBvZmZpemllbGxlbiBaYWhsZW4gKFtERVNUQVRJUyAyMDE3XShodHRwczovL3d3dy5kZXN0YXRpcy5kZS9ERS9QdWJsaWthdGlvbmVuL1RoZW1hdGlzY2gvVHJhbnNwb3J0VmVya2Voci9WZXJrZWhyc3VuZmFlbGxlL1ZlcmtlaHJzdW5mYWVsbGVaZWl0cmVpaGVuUERGXzU0NjI0MDMucGRmP19fYmxvYj1wdWJsaWNhdGlvbkZpbGUpKSBnYWIgZXMgaW0gSmFociAyMDE3IGJ1bmRlc3dlaXQgMzU2IHTDtmRsaWNoZSBVbmbDpGxsZSAobWl0IDQwOSBUb2Rlc29wZmVybikuIFVudGVyIGRlciBBbm5haG1lLCBkYXNzIHNpY2ggZHVyY2ggZGllIEVpbmbDvGhydW5nIGVpbmVzIFRlbXBvbGltaXRzIGRpZSBaYWhsIGRlciB0w7ZkbGljaGVuIFVuZsOkbGxlIHBybyBNcmQuIEtpbG9tZXRlciB3aWUgaW4gZGVyIERhdGVuYXVzd2VydHVuZyBhdWYgMCw5NSBzZW5rZW4gbGllw59lLCB3w7xyZGUgZGllcyB6dSBlaW5lciBSZWR1emllcnVuZyBkZXIgWmFobCBkZXIgdMO2ZGxpY2hlbiBVbmbDpGxsZSBhdWYgYHIgcm91bmQobW9kZWxfYWNjaWRlbnRzKWAgKG1pdCBgciByb3VuZChtb2RlbF9kZWF0aHMpYCBUb2Rlc29wZmVyKSBmw7xocmVuLiAqKkFuZGVycyBhdXNnZWRyw7xja3Q6IEFsbGVpbmUgaW0gSmFociAyMDE3IGjDpHR0ZW4gc2ljaCBgciA0MDkgLSByb3VuZChtb2RlbF9kZWF0aHMpYCBUb2Rlc29wZmVyIGR1cmNoIGRpZSBFaW5mw7xocnVuZyBlaW5lcyBBdXRvYmFobi1UZW1wb2xpbWl0cyB2ZXJoaW5kZXJuIGxhc3Nlbi4qKiAKCgojIFBsYXVzaWJpbGl0w6R0c3Byw7xmdW5nCgojIyBRdWVydmVyZ2xlaWNoIG1pdCBQcmltw6RycXVlbGxlbgpMYXV0IERFU1RBVElTIDIwMTcgKFMuIDIyMikgbGFnIGRpZSBaYWhsIGRlciBVbmbDpGxsZSBhdWYgQXV0b2JhaG5lbiBwcm8gTXJkLiBnZWZhaHJlbmUgS2lsb21ldGVyIGltIEphaHIgMjAxNyBpbnNnZXNhbXQgYmVpIDg1LCBpbiB1bnNlcmVyIEF1c3dlcnR1bmcgYmVpIDc2LgoKRGllIFphaGwgZGVyIHTDtmRsaWNoZW4gVW5mw6RsbGUgcHJvIE1yZC4gS2lsb210ZXIgbGllZ3QgbGF1dCBERVNUQVRJUyAyMDE3IChTLiAyMjIpIGJlaSAxLDcsIGJlaSB1bnMgYmVpIDEsNC4KCkRpZSBqw6RocmxpY2hlIEZhaHJsZWlzdHVuZyBhdWYgQXV0b2JhaG5lbiBsaWVndCBsYXV0IERFU1RBVElTIDIwMTcgKFMuIDIxNSkgYmVpIDI0NiBNcmQuIEtpbG9tZXRlciwgbWl0IHVuc2VyZW4gR3J1bmRsYWdlbmRhdGVuIChmw7xyIGFsbGUgQnVuZGVzbMOkbmRlcikgZXJnZWJlbiBzaWNoIDI1MSBNcmQuIGttLgoKPiBEZXIgQmxpY2sgaW4gYW5kZXJlIFByaW3DpHJxdWVsbGVuIHplaWd0IG51ciBnZXJpbmdlIEFid2VpY2h1bmdlbiB1bmQgdW50ZXJzdMO8dHp0IHNvIGRpZSBQbGF1c2liaWxpdMOkdCBkZXIgQXVzd2VydHVuZy4gS2xlaW5lcmUgQWJ3ZWljaHVuZ2VuIHdhcmVtIHNjaG9uIGRlc2hhbGIgenUgZXJ3YXJ0ZW4sIGRhIG51ciBmw7xyIDEyIGRlciAxNiBCdW5kZXNsw6RuZGVyIERhdGVuIHZvcmxpZWdlbiB1bmQgdmVyc2NoaWVkZW4gR2VvZGF0ZW4gdmVyd2VuZGV0IHdlcmRlbiAoT1NNL0Jhc3QpLgoKCiMjIEJlZWluZmx1c3N1bmcgZHVyY2ggTGljaHR2ZXJow6RsdG5pc3NlIGF1c3NjaGxpZcOfZW4KYGBge3IgZmlnLmFzcCA9IDAuNX0KYWNjaWRlbnRzX2xpZ2h0X2NvbmRpdGlvbnMgPSB1bmZhZWxsZV8yMDE3X2F1dG9iYWhuICU+JSAKCWFzLmRhdGEuZnJhbWUoKSAlPiUgCglzZWxlY3QoLWdlb20pICU+JSAKCWZpbHRlcihVS0FURUdPUklFID09ICIxIikgJT4lIAoJbXV0YXRlKHRlbXBvbGltaXQgPSBpZl9lbHNlKG1heHNwZWVkID09ICJub25lIiB8IGlzLm5hKG1heHNwZWVkKSwgIm9obmUgVGVtcG9saW1pdCIsICJtaXQgVGVtcG9saW1pdCIpKSAlPiUgCgltdXRhdGUoTElDSFQgPSBhcy5jaGFyYWN0ZXIoTElDSFQpKSAlPiUgCgltdXRhdGUoTElDSFQgPSBpZl9lbHNlKExJQ0hUID09ICIwIiwgIlRhZ2VzbGljaHQiLCBMSUNIVCkpICU+JQoJbXV0YXRlKExJQ0hUID0gaWZfZWxzZShMSUNIVCA9PSAiMSIsICJEw6RtbWVydW5nIiwgTElDSFQpKSAlPiUKCW11dGF0ZShMSUNIVCA9IGlmX2Vsc2UoTElDSFQgPT0gIjIiLCAiRHVua2VsaGVpdCIsIExJQ0hUKSkgJT4lCgljb3VudCh0ZW1wb2xpbWl0LCBMSUNIVCkKCmdncGxvdChhY2NpZGVudHNfbGlnaHRfY29uZGl0aW9ucykgKwoJZ2VvbV9jb2woYWVzKHRlbXBvbGltaXQsIG4sIGZpbGwgPSBMSUNIVCksIHBvc2l0aW9uID0gImZpbGwiKSArCglsYWJzKHggPSAiIiwgeSA9IiIsIHRpdGxlID0gIkFudGVpbCB0w7ZkbGljaGVyIFVuZsOkbGxlIG5hY2ggVGVtcG9saW1pdCB1bmQgTGljaHR2ZXJow6RsdG5pc3NlbiIpCmBgYAoKCiMjIEJlZWluZmx1c3N1bmcgZHVyY2ggU3RyYcOfZW52ZXJow6RsdG5pc3NlIGF1c3NjaGxpZcOfZW4KYGBge3IgZmlnLmFzcCA9IDAuNX0KYWNjaWRlbnRzX3JvYWRfY29uZGl0aW9ucyA9IHVuZmFlbGxlXzIwMTdfYXV0b2JhaG4gJT4lIAoJYXMuZGF0YS5mcmFtZSgpICU+JSAKCXNlbGVjdCgtZ2VvbSkgJT4lIAoJZmlsdGVyKFVLQVRFR09SSUUgPT0gIjEiKSAlPiUgCgltdXRhdGUodGVtcG9saW1pdCA9IGlmX2Vsc2UobWF4c3BlZWQgPT0gIm5vbmUiIHwgaXMubmEobWF4c3BlZWQpLCAib2huZSBUZW1wb2xpbWl0IiwgIm1pdCBUZW1wb2xpbWl0IikpICU+JSAKCW11dGF0ZShTVFJaVVNUQU5EID0gYXMuY2hhcmFjdGVyKFNUUlpVU1RBTkQpKSAlPiUgCgltdXRhdGUoU1RSWlVTVEFORCA9IGlmX2Vsc2UoU1RSWlVTVEFORCA9PSAiMCIsICJ0cm9ja2VuIiwgU1RSWlVTVEFORCkpICU+JQoJbXV0YXRlKFNUUlpVU1RBTkQgPSBpZl9lbHNlKFNUUlpVU1RBTkQgPT0gIjEiLCAibmFzcy9mZXVjaHQvc2NobMO8cGZyaWciLCBTVFJaVVNUQU5EKSkgJT4lCgltdXRhdGUoU1RSWlVTVEFORCA9IGlmX2Vsc2UoU1RSWlVTVEFORCA9PSAiMiIsICJ3aW50ZXJnbGF0dCIsIFNUUlpVU1RBTkQpKSAlPiUKCWNvdW50KHRlbXBvbGltaXQsIFNUUlpVU1RBTkQpCgpnZ3Bsb3QoYWNjaWRlbnRzX3JvYWRfY29uZGl0aW9ucykgKwoJZ2VvbV9jb2woYWVzKHRlbXBvbGltaXQsIG4sIGZpbGwgPSBTVFJaVVNUQU5EKSwgcG9zaXRpb24gPSAiZmlsbCIpICsKCWxhYnMoeCA9ICIiLCB5ID0iIiwgdGl0bGUgPSAiQW50ZWlsIHTDtmRsaWNoZXIgVW5mw6RsbGUgbmFjaCBUZW1wb2xpbWl0IHVuZCBTdHJhw59lbnZlcmjDpGx0bmlzc2VuIikKYGBgCgo+IFZlcmdsZWljaCBtYW4gU3RyYcOfZW56dXN0YW5kIHVuZCBMaWNodHZlcmjDpGx0bmlzcyBiZWkgZGVuIHTDtnRsaWNoZW4gVW5mw6RsbGVuIG1pdCBiencuIG9obmUgVGVtcG9saW1pdCwgc28gemVpZ2VuIHNpY2ggbnVyIHNlaHIgZ2VyaW5nZSBVbnRlcnNjaGllZGUuIEVzIGthbm4gZm9sZ2xpY2ggYXVzZ2VzY2hsb3NzZW4gd2VyZGVuLCBkYXNzIGRpZSBlcm1pdHRlbHRlIFphaGwgZGVyIHTDtnRsaWNoZW4gVW5mw6RsbGVuIHBybyBNcmQuIGdlZmFocmVuZXIgS2lsb21ldGVyIGF1ZiBBYnNjaG5pdHRlbiBtaXQvb2huZSBUZW1wb2xpbWl0IGF1ZiBlaW5lciB2ZXJ6ZXJydGVuIGR1cmNoIGVpbmUgVmVyemVycnVuZyBkZXIgR3J1bmRnZXNhbXRoZWl0IHp1IGVya2zDpHJlbiBpc3QuCg==