Dieser Artikel wird regelmäßig aktualisiert.
Alle Grafiken sind auf dem Stand des 09.08.2020, das letzte inhaltliche Update gab es am 10.08.2020.

Einleitung

Die andauernde COVID-19 Pandemie bedarf keiner Erklärung, denn die ganze Welt ist momentan schwer davon betroffen. Die hohe Infektiosität des SARS-CoV-2-Erregers und der potenziell schwere Verlauf der Erkrankung stellt die Gesundheitssysteme weltweit auf eine harte Probe. Um jedoch richtige Schritte zur Eindämmung der Pandemie zu gehen, ist die Analyse der Fallzahlen ein unabdingbarer Schritt.

Viele von uns haben es sich mittlerweile zur Gewohnheit gemacht, mindestens einmal täglich auf den aktuellen Stand der Fallzahlen zu schauen. Die gute Verfügbarkeit der Daten und neuer Visualisierungstechnologien macht es uns möglich, Graphen in kürzester Zeit auf den neusten Stand zu bringen. Vor allem die Daten der Johns Hopkins University und des Robert Koch Institutes werden dafür intensiv verwendet. Auf verschiedenen Plattformen, z.B. Kaggle.com, stehen viele Daten für jedermann zur Verfügung, in der Hoffnung, dass die große weltweite Community an Data Scientists aus den Daten wertvolle Informationen und Vorhersagen generiert.

Wir von der StatSoft Europe GmbH bieten R-Trainings an und haben die jetzt anfallenden Daten ebenfalls genutzt, um Erkenntnisse durch Visualisierung zu erzeugen. Hierfür haben wir die Open-Source Statistiksoftware R verwendet und den hierfür verwendeten Code offengelegt, um interessierten Analysten eine kostenlose Hilfe für die Visualisierung mit R bereitzustellen. Es wurden die Daten der Johns Hopkins University verwendet (heruntergeladen von diesem Kaggle Link). Die Ursprungsdaten, wie sie in Kaggle verwendet werden, stammen aus dem Git Repository der Johns Hopkins University.

An dieser Stelle möchten wir einmal die Chance nutzen, Sie auf verschiedene Hilfsplattformen für die Corona-Krise aufmerksam zu machen. Vielleich sind Sie selbst betroffen oder kennen Personen, die besonders bedroht sind und zur eigenen Sicherheit zu Hause bleiben sollten. Um diesen Menschen zu helfen, wurden viele Hilfsplattformen eingerichtet, um beispielsweise Einkäufe für Betroffene zu übernehmen. Auf dieser Seite gibt es Links zu solchen Hilfsplattformen, bei denen Sie sich als Betroffene oder als potenzielle Helfer registrieren können. Denken Sie bitte auch daran, dass besonders Tierheime in dieser Zeit einen großen Zulauf an Haustieren haben, deren Besitzer aufgrund der Krankheit nicht mehr in der Lage sind, sich um diese zu kümmern. Durch Futter- oder Geldspenden und können Sie diese unterstützen.

Empfohlene Literatur

Für die Datenanalyse und Visualisierung können wir die hervorragenden Bücher R for Data Science sowie Hands on Programming with R von Hadley Wickham und Garret Grolemund wärmstens empfehlen. Beide Autoren sind übrigens auch die Urheber fast aller Pakete, die wir in diesem Projekt benötigen.

Die aktuelle Situation

In diesem Abschnitt möchten wir Ihnen anhand verschiedener Grafiken zeigen, wie sich die COVID-19 Pandemie in der Welt ausbreitet. Der Stand des Datensatzes ist der 09.08.2020. Im nächsten Abschnitt weiter unten zeigen wir dann, wie wir diese Grafiken mit R erzeugt haben.

Weltweit

In der folgenden Grafik sind die bestätigten Fallzahlen aller Staaten, aufgeteilt in akute Erkrankungen, Genesungen und Todesfälle, dargestellt, die am 09.08.2020 mindestens 50000 bestätigte Fälle registriert hatten.

Die folgende Grafik zeigt den Anstieg der bestätigten Fälle auf einer logarithmierten Skala in Abhängigkeit der vergangenen Tage seit dem 100. registrierten Fall. Auf diese Weise lässt sich gut erkennen, wie schnell sich COVID-19 in den entsprechenden Ländern ausgebreitet hat. Es sind nur diejenigen sieben Staaten abgebildet, die bis zum 09.08.2020 die meisten Fälle registriert hatten, sowie Südkorea, die durch ihre schnelle Reaktionszeit und hohe Testzahlen eine starke Eindämmung des Ausbruchs erzielen konnten. Durch die Log-Skala ist es möglich, den Zuwachs an bestätigten Fällen unabhängigkeit von deren Größenordnung zwischen den verschiedenen Ländern zu unterscheiden.

China, Europa und USA

Die folgende Grafik können wir erkennen, wie sich die Fallzahlen in China, Europa, den USA und allen anderen Ländern (Sonstige) entwickelt hat. Es wird deutlich erkennbar, wie schnell China den Ausbruch durch sehr striktes Durchgreifen in den Griff bekommen konnte. Etwa fünf Wochen nachdem die Fallzahlen in China ein Plateau erreicht hatten, waren die Fallzahlen in Europa bereits höher als die in China. Nur zwei weitere Wochen später gab es in Europa bereits fünfmal so viele Fälle wie in China. Die USA zeigen ebenfalls einen rasanten Anstieg, der um etwa eineinhalb Wochen verzögert von Europa stattfindet. Somit sind Europa und die USA die neuen Epizentren der COVID-19 Pandemie.

Die folgende Grafik zeigt den täglichen Zuwachs an Fallzahlen in China, Europa, den USA und in allen anderen Ländern. Hier wird deutlich erkennbar, wie schnell die chinesische Regierung reagiert und zu drastischen Mitteln gegriffen hat, denn schon am 23. Januar wurde mit der Quarantäne von Hubei begonnen, also zu einem Zeitpunkt, als es nur 639 Bestätigte Fälle und 18 Todesfälle in China gab. Dennoch stiegen trotz der Quarantäne die bestätigten Fälle in China auf 84668 an, darunter waren 4634 Todesfälle (Stand 09.08.2020). Das verdeutlicht sehr stark, dass eine starke Einschränkung der Reise- und Bewegungsfreiheit (so schmerzhaft diese auch sein mag) a) die weitere Verbreitung effektiv eindämmen kann, b) eher zu früh als zu spät ausgeführt werden sollte und c) die Kurve nur zeitverzögert abflachen kann.

In Europa wurde am 04.04.2020 der bisher höchste tägliche Zuwachs von 54896 neuen Fällen verzeichnet, in den USA lag der höchste Anstieg bei 78310 Fällen am 16.07.2020. In China lag der höchste Anstieg dagegen bei nur 15133 Fällen am 13.02.2020.

In der folgenden Grafik ist die Summe an akuten Erkrankungen aller hier betrachteten Regionen für den jeweiligen Zeitraum dargestellt, die Breite des farbigen Bandes symbolisert dabei den Anteil der Erkrankungen, die in der jeweiligen Region stattfanden. Zuerst begann die Ausbreitung in China. Diese setzte sich dann in Europa und anderen Ländern weiter fort und ging zeitgleich in China wieder zurück. Etwa zwei Wochen nach dem Ausbruch in Europa breitete sich die Erkankung dann auch in den Vereinigten Staaten aus. Die Vereinigten Staaten sind das Land mit der höchsten Zahl an akuten Erkankungen.

In der folgenden Darstellung sind die bestätigten Fälle, Todesfälle und akuten Erkrankungen für die verschiedenen Regionen am 09.08.2020 dargestellt.

Europa

In der folgenden Grafik sehen wir die bestätigten Fälle aller europäischen Staaten, in denen am 30.03.2020 mindestens 5000 bestätigte Fälle registriert wurden. Die Breite des jeweiligen Bandes zeigt dabei, welcher Anteil an bestätigten Fällen Staaten dem jeweiligen Staat zuzuordnen ist und wie sich dieser Anteil über die Zeit verändert. Daraus wird ersichtlich, dass Italien als erstes Land eine hohe Zahl an bestätigten Fällen registrierte. Wenige Wochen später stiegen dann die Infektionszahlen auch in umliegenden europäischen Staaten stark an. Die meisten Infektionen wurden bis zum 09.08.2020 in Italien, Spanien und Deutschland und Frankreich erfasst.

In der folgenden Grafik sehen wir die Todesfälle aller europäischen Staaten, in denen am 30.03.2020 mindestens 5000 bestätigte Fälle registriert wurden.. Die Zahl der Todesfälle in Deutschland ist verglichen mit der relativ hohen Zahl bestätigter Fälle noch sehr gering.

Die folgende Grafik zeigt die Anzahl der Genesungen innerhalb der verschiedenen europäischen Staaten. Die Zahl der Genesungen ist in Spanien, Italien und Deutschland am höchsten.

Die folgende Grafik zeigt den Verlauf der akuten Erkrankungen innerhalb der europäischen Staaten.

Deutschland

In der folgenden Grafik sind die akuten Erkrankungen, Todesfälle und Genesungen in Deutschland dargestellt.

In der folgenden Grafik sehen wir den täglichen prozentualen Anstieg bestätigter Fälle in Deutschland. Die höchsten täglichen Anstiege (> 50%) wurden registriert, als es in Deutschland noch weniger als 5000 Fälle gab. Anschließend lagen die täglichen Anstiege für 7 Tage zwischen 25 und 35 % und sanken für die folgenden 8 Tage weiter auf 10-17% ab. Seit dem 29.03.2020 blieben die täglichen Anstiege unter der 10%-Grenze.

Diese Absenkung der neuen Infektionen seit dem 21.03.2020 war sehr wichtig, denn ansonsten wären die Infektionszahlen in Deutschland schon am 30.03.2020 mehr als dreimal so hoch, als wenn keine Absenkung des täglichen prozentualen Zuwachses erreicht worden wäre. Die folgende Grafik zeigt die tatsächliche Entwicklung (hellblaue Balken) der Fallzahlen in Deutschland. Die rote Linie simuliert die Fallzahlen, die sich ergeben hätten, wenn sich der tägliche Anstieg von 25-35%, wie er vom 14.03.2020 - 20.03.2020 stattgefunden hat, fortgesetzt hätte. Am 30.03.2020 wären demnach schon 229108 infizierte aufgetreten. Tatsächlich wurden aber aufgrund dieser Absenkung nur 66885 Fälle registriert.

Der Code

In diesem Abschnitt zeigen wir Ihnen, wie wir die Daten aufbereitet haben, um die oben gezeigten Grafiken zu erzeugen.

Pakete und Daten

Für dieses Projekt benötigen wir die Pakete tidyverse und lubridate sowie scales und RColorBrewer. Diese müssen zuvor installiert worden sein.

library(tidyverse)
library(lubridate)
library(scales)
library(RColorBrewer)
library(countrycode)

Jetzt laden wir den Datensatz (heruntergeladen von diesem Kaggle Link) mit der Funktion read_csv():

data <- read_csv("data/covid_19_data.csv")
Parsed with column specification:
cols(
  SNo = col_double(),
  ObservationDate = col_character(),
  `Province/State` = col_character(),
  `Country/Region` = col_character(),
  `Last Update` = col_character(),
  Confirmed = col_double(),
  Deaths = col_double(),
  Recovered = col_double()
)

Datenbereinigung

Jetzt ändern wir das Format der Variable ObservationDate in eine gültige Form mittels lubridate::mdy() und speichern diese in der neuen Variable Datum ab mittels Funktion dplyr::mutate(). Anschließend gruppieren wir die Daten nach Datum und Country/Region und summieren die bestätigten Fälle (Confirmed) innerhalb jeder Gruppe mithilfe der Funktion summarize(). Dadurch erhalten wir die Summen aller Fälle innerhalb eines Landes und Tages. Das machen wir hauptsächlich deswegen, weil beispielsweise alle Provinzen Chinas oder alle Staaten der USA als Einzeleinträge vorhanden sind, wir aber die Fallzahlen für das ganze Land betrachten wollen. Anschließend sortieren wir nach der Variable Datum und Bestätigte Fälle, um zu sehen, welches das aktuellste Datum unseres Datensatzes ist und in welchen Ländern die höchsten Fallzahlen registriert wurden:

data <- data %>% 
  mutate(Datum = mdy(ObservationDate)) %>% 
  group_by(Datum, `Country/Region`) %>% 
  summarize(`Bestätigte Fälle` = sum(Confirmed),
            `Todesfälle` = sum(Deaths),
            `Genesungen` = sum(Recovered)) %>% 
  arrange(desc(Datum), desc(`Bestätigte Fälle`))
data

Später möchten wir den Verlauf in China mit ganz Europa vergleichen. Hierfür benötigen wir allerdings eine Liste der europäischen Länder, wenn wir diese nicht manuell zuweisen wollen, denn die Kontinentzugehörigkeit ist nicht im Datensatz vorhanden. Hierbei hilft uns das Paket countrycode, welches eine Liste aller Länder der Erde und die dazugehörigen Ländercodes sowie Kontinente beinhaltet. Mit der Funktion countrycode() erstellen wir eine neue Variable namens continent. Gleichzeitig können wir die Chance nutzen, um mit der countrycode Funktion die englischen Ländernamen in deutsche zu überführen. Diese Variable nennen wir dann Staat:

library(countrycode)
#data3
data <- data %>% 
  mutate(continent = countrycode(`Country/Region`,
                                 origin = "country.name",
                                 destination = "continent"),
         Staat = countrycode(`Country/Region`,
                             origin = "country.name",
                             destination = "country.name.de"))

Nun erstellen wir eine weitere Variable, die wir Region nennen. In dieser Variable werden wir die Regionen Europa, China, Vereinigte Staaten und Sonstige definieren. Dies tun wir mithilfe der base::ifelse() Funktion innerhalb der Funktion dplyr::mutate().

Ausgeschrieben bewirkt der folgende Code: Wenn die Variable continent gleich Europeist, soll die Variable Region auf Europe gesetzt werden; ansonsten auf China, wenn die Variable Country/Region gleich Mainland China ist; ansonsten auf USA, wenn die Variable Country/Region gleich US ist; ansonsten soll die Variable Region auf Sonstige gesetzt werden.

Somit können wir anhand zweier Variablen (continent und Country/Region) eine Gruppierung in die Regionen Europa, China, Vereinigte Staaten und Sonstige vornehmen:

#data4
data <- data %>% 
  mutate(Region = ifelse(continent == "Europe", "Europa",
                                ifelse(`Country/Region` == "Mainland China",
                                       "China",
                                       ifelse(`Country/Region` == "US",
                                              "USA",
                                              "Sonstige"))))

Nun können wir unseren Datensatz einmal ansehen, um zu prüfen, ob die neue Variablen Region, continent und Staat korrekt erstellt wurden:

arrange(data, desc(Datum), desc(`Bestätigte Fälle`))

Als nächstes erstellen wir die neue Variable Akute Erkrankungen, die sich aus den anderen Variablen folgendermaßen errechnen lässt:

data <- mutate(data, `Akute Erkrankungen` = `Bestätigte Fälle` - `Todesfälle` - `Genesungen`)
data

Nun ist die Grobarbeit abgeschlossen und wir können die Daten jetzt weiterverwenden, um die Grafiken zu erzeugen.

Weltweit

Für unsere erste Grafik müssen wir zuerst den Datensatz nach dem aktuellsten Datum und der Anzahl bestätigter Fälle von mindestens 50000 filtern. Anschließend überführen wir mit pivot_longer() die Tabelle in die lange Form und erstellen als Fallkategorie die Variable Kategorie und sammeln die Fallzahlen in der Variable Fälle. Nun sieht der veränderte Datensatz so aus:

Laender_50000 <- data %>% 
  filter(Datum == strftime(max(data$Datum)),
         `Bestätigte Fälle` >= 50000) %>%  
  pivot_longer(cols = c(`Akute Erkrankungen`, 
                        `Todesfälle`, 
                        `Genesungen`), 
               names_to = "Kategorie", 
               values_to = "Fälle")

head(Laender_50000)

Jetzt können wir mit ggplot() und geom_col() ein Balkendiagramm erzeugen. Zuerst definieren wir die X-Achse als Staat und die Y-Achse als Anzahl der Fälle, danach tauschen wir die beiden Achsen mit dem Befehl coord_flip(), so dass die Y-Achse zur X-Achse wird und umgekehrt. Nun müssen wir als letzten Schritt die Balken nach der Gesamtzahl bestätigter Fälle sortieren. Da wir die Variable Bestätigte Fälle nicht in die lange Form überführt haben, steht uns diese Variable noch zur Verfügung und wir können somit das Balkendiagramm mit reorder() nach der Variable Bestätigte Fälle sortieren.

g1 <- ggplot(data = Laender_50000) +
  geom_col(mapping = aes(x = reorder(Staat, 
                                     `Bestätigte Fälle`), 
                         y = `Fälle`, 
                         fill = Kategorie)) +
  coord_flip() +
  theme(legend.position = c(0.8, 0.3),
        legend.background = element_rect(fill=alpha(0.4)),
        plot.title = element_text(hjust = 0.5)) +
  scale_y_continuous(labels = number) +
  labs(x = "Staat", 
       y = "Fälle", 
       title = paste("Anzahl bestätigter Fälle je Staat, Stand ", 
                     stand_datensatz,
                     sep=""))
g1

Die folgende Grafik zu erstellen ist ein wenig komplizierter. Zuerst müssen wir alle Fälle des Originaldatensatzes nach den Zeilen filtern, in denen die Bestätigte Fälle größer oder gleich 100 sind. Danach gruppieren wir nach Staat und berechnen das Minimum der bestätigten Fälle mit summarize(). Somit erhalten wir für jeden Staat genau die Zeile, in der zum ersten Mal die Grenze von 100 Fällen überschritten worden ist. Den Wert von Tage seit dem 100. Fall setzen wir für diesen Tag auf 0 mit mutate().

weltweit_log_1 <- data %>%
  arrange(Datum) %>% 
  filter(`Bestätigte Fälle` >=100) %>% 
  group_by(Staat) %>% 
  summarize(`Bestätigte Fälle` = min(`Bestätigte Fälle`)) %>% 
  mutate(`Tage seit dem 100. Fall` = 0)

Im nächsten Schritt fügen wir unseren soeben erstellten Datensatz zusammen mit dem Ursprungsdatensatz mittels der Funktion full_join() und nennen das neue Objekt weltweit_log_2. Nun filtern wir erneut nach den Zeilen, in denen mehr oder genau 100 Bestätigte Fälle aufgetreten sind, und heben die vorherige Gruppierung auf mit ungroup() (dieser Schritt ist notwendig, damit cumsum() später korrekt funktioniert). Jetzt sortieren wir nach dem Datum und setzen alle NAs der Variable Tage seit dem 100. Fall auf 1. Jetzt gruppieren wir nach Staat und modifizieren die Variable Tage seit dem 100. Fall als kumulative Summe von sich selbst. Anschließend sortieren wir nach Staat und Datum.

weltweit_log_2 <- full_join(data,weltweit_log_1) %>% 
  filter(`Bestätigte Fälle` >= 100) %>% 
  ungroup(weltweit_log_2) %>% 
  arrange(Datum) %>%  
  mutate(`Tage seit dem 100. Fall` = ifelse(is.na(`Tage seit dem 100. Fall`) == T, 1, 0)) %>% 
  group_by(Staat) %>% 
  mutate(`Tage seit dem 100. Fall` = cumsum(`Tage seit dem 100. Fall`)) %>% 
  arrange(Staat, Datum)
Joining, by = c("Best攼㸴tigte F攼㸴lle", "Staat")

Als nächstes rechnen wir zum besseren Vergleich die Fallzahlen aus, die sich bei einer Verdoppelungszeit von 2, 7, 14 und 60 Tagen ergeben würden. Hierfür erstellen wir einen neuen Datensatz in dem die Variable Tage seit dem 100. Fall von 1-60 reicht. Nun erstellen wir vier neue Variablen (2 Tage, 7 Tage, usw.) und errechnen mit der entsprechenden Formel die Fallzahlen aus, die sich bei der entsprechenden Verdoppelungszeit ergeben würden. Nun überführen wir diesen Datensatz in die lange Form. Zum Schluss filtern wir noch, um die gleich im Plot dargestellten Linien nicht zu weit aus dem Grafikbereich herausragen zu lassen (nur ein Schönheitsfaktor).

VDZ <- tibble(`Tage seit dem 100. Fall` = seq(1:60)) %>% 
  mutate(`2 Tage` = 100*(2^(1/2))^`Tage seit dem 100. Fall`,
         `7 Tage` = 100*(2^(1/7))^`Tage seit dem 100. Fall`,
         `14 Tage` = 100*(2^(1/14))^`Tage seit dem 100. Fall`,
         `60 Tage` = 100*(2^(1/60))^`Tage seit dem 100. Fall`,) %>% 
  pivot_longer(cols = c("2 Tage", "7 Tage", "14 Tage", "60 Tage"), names_to = "Verdoppelungszeit", values_to = "Fälle") %>% 
  mutate(Verdoppelungszeit = as_factor(Verdoppelungszeit)) %>% 
  filter(`Fälle` <= 4000000 & `Tage seit dem 100. Fall` <= 50)

Jetzt können wir Bestätigte Fälle gegen Tage seit dem 100. Fall plotten mit ggplot(). Dadurch, dass wir die Option scale_y_continuous(trans="log10") gewählt haben, wird die Y-Achse als Log-Skala dargestellt. Auf diese Weise ist es einfacher, das Wachstum der bestätigten Fälle zwischen verschiedenen Staaten zu vergleichen. Zusätzlich plotten wir die Vergleichslinien der verschiedenen Verdoppelungszeiten aus dem eben erstellten Datensatz VDZ und geben als Ästhetik linetype an.

log_cases <- filter(weltweit_log_2, Staat %in% (c("China", "Deutschland", "Spanien", "Frankreich", "Italien", "Vereinigte Staaten", "Iran", "Korea, Republik von")))

g2 <- ggplot(data = log_cases) +
  geom_line(mapping = aes(x = `Tage seit dem 100. Fall`, y = `Bestätigte Fälle`, color = Staat), size = 1.5) +
  geom_line(data = VDZ, mapping = aes(x = `Tage seit dem 100. Fall`, y = `Fälle`, linetype = Verdoppelungszeit), color = "royalblue4") +
  scale_y_continuous(trans='log10', labels = number) +
  labs(title = paste("Bestätigte Fälle (Log) in Abh. der Tage seit d. 100. Fall, Stand ", 
                     stand_datensatz,
                     sep="")) +
  theme(legend.position = c(0.85, 0.5),
        legend.background = element_rect(fill=alpha(0.4)),
        plot.title = element_text(hjust = 0.5)) +
    scale_color_brewer(palette="Set3") +
  guides(linetype = guide_legend(order = 1), color = guide_legend(order = 2))
g2

China, Europa und USA

Jetzt gruppieren wir unseren Datensatz nach Datum und Region und summieren die Variablen Bestätigte Fälle, Todesfälle und Genesungen auf mit sum(), um die Summen aller Fälle innerhalb jeden Tages und innerhalb jeder Region zu erhalten. Alle fehlenden Werte werden anschließend mit filter() und !is.na() herausgeworfen. Nun gruppieren wir nur nach Region und erstellen mit mutate() die Variable Zuwachs bestätigter Fälle je Region mit der lag() Funktion sowie die Variable Akute Erkrankungen je Region:

Regionen <- data %>% 
  group_by(Datum, Region) %>% 
  summarize(`Bestätigte Fälle je Region` = sum(`Bestätigte Fälle`),
            `Todesfälle je Region` = sum(`Todesfälle`),
            `Genesungen je Region` = sum(`Genesungen`)) %>% 
  filter(!is.na(Region)) %>% 
  group_by(Region) %>% 
  mutate(`Zuwachs bestätigter Fälle je Region` = `Bestätigte Fälle je Region` - lag(`Bestätigte Fälle je Region`),
         `Akute Erkrankungen je Region` = `Bestätigte Fälle je Region` - `Genesungen je Region` - `Todesfälle je Region`)

head(arrange(Regionen, desc(Datum), desc(`Bestätigte Fälle je Region`)))

Nun können wir die bestätigten Fälle für China, Europa, US und andere plotten mit ggplot(). Hierbei ist die X-Achse Datum und die Y-Achse die Summe der bestätigten Fälle je Region (Bestätigte Fälle je Region). Bemerkung: Die sogenannten backticks sind notwendig, wenn Variablennamen Sonderzeichen (hier Leerzeichen und Umlaute in der Variable Bestätigte Fälle je Region) aufweisen und dennoch normal weiterverwendet werden sollen.

g3a <- ggplot(data = Regionen) +
  geom_line(mapping = aes(x = Datum, 
                          y = `Bestätigte Fälle je Region`, 
                          color = Region), 
            size = 1) +
  labs(x = "Datum", 
       y = "Bestätigte Fälle je Region",
       title = paste("Bestätigte Fälle je Region, Stand ",
                     stand_datensatz,
                     sep="")) +
  scale_y_continuous(labels = number) +
  scale_x_date(date_breaks = "2 week", date_labels = "%d.%m") +
  theme(legend.position = c(0.13, 0.6),
        legend.background = element_rect(fill=alpha(0.4)),
        plot.title = element_text(hjust = 0.5))
g3a

Wenn wir die weiteren zwei Variablen (Todesfälle je Region und Genesungen je Region) zusätzlich im selben Plot darstellen wollen, müssen wir zunächst den Datensatz in die Lange Form übertragen mit tidyr::pivot_longer(). Hierbei erzeugen wir zwei neue Variablen, die wir Kategorie und Fälle nennen. Die Variable Kategorie enthält Information, ob es sich um einen bestätigten Fall, einen Todesfall oder einen geheilten Fall handelt. Die Variable Fälle enthält die Zählwerte, die vorher unter den drei zusammengefügten Variablen standen.

Regionen_long <- Regionen %>% 
  pivot_longer(cols = c(`Bestätigte Fälle je Region`,
                        `Todesfälle je Region`,
                        `Genesungen je Region`,
                        `Zuwachs bestätigter Fälle je Region`,
                        `Akute Erkrankungen je Region`),
               names_to = "Kategorie",
               values_to = "Fälle")
head(Regionen_long)

Anschließend fügen wir die neue Variable Kategorie als aesthetics in ggplot() hinzu (hier als linetype). Somit verändert sich der Linientyp in Abhängigkeit der Variable Kategorie. Als Y-Achse wählen wir die neu erstellte Variable Fälle, die die gezählten Werte beinhaltet. Da die oben verwendete Funktion countrycode() nicht alle Länder zuweisen konnte und NAs erzeugt hat, entfernen wir diese im selben Schritt mit drop_na(), da diese sonst auch in der Grafik abgebildet werden würden (Alternativ könnten wir auch die fehlenden Länder manuell noch dem richtigen Kontinenten zuweisen). Mit dem Argument scale_x_date ändern wir das Datumsformat der X-Achse und setzen es auf Wochenschritte, mit dem Argument theme() positionieren wir die Legende in den Plot und setzen den Hintergrund transparent.

g3b <- ggplot(data = filter(Regionen_long, 
                     Kategorie %in% c("Bestätigte Fälle je Region",
                                      "Todesfälle je Region",
                                      "Genesungen je Region"))) +
  geom_line(mapping = aes(x = Datum, 
                          y = `Fälle`, 
                          color = Region, 
                          linetype = Kategorie), 
            size = 1)+
  labs(x = "Datum", 
       y = "Fälle", 
       title = paste("Fallzahlen nach Kategorie und Region, Stand ", 
                                               stand_datensatz,
                                               sep="")) +
   scale_y_continuous(labels = number) +
  scale_x_date(date_breaks = "2 week", 
               date_labels = "%d.%m") +
  theme(legend.position = c(0.2, 0.6),
        legend.background = element_rect(fill=alpha(0.4)),
        plot.title = element_text(hjust = 0.5))
g3b

Nun können wir den täglichen Zuwachs an Fallzahlen plotten. Zusätzlich fügen wir mit geom_vline() Markierungen und mit geom_label() Labels an den Stellen hinzu, an denen Ereignisse stattgefunden haben, die sich auf Ausbreitung der Erkrankung auswirken können, nämlich die Zeitpunkte, an denen verschiedene Länder mit den Quarantänemaßnahmen begonnen haben. China hat beispielsweise schon am 23. Januar mit der Quarantäne von Hubei begonnen, also zu einem Zeitpunkt, als es nur 639 Bestätigte Fälle je Region und 18 Todesfälle je Region in China gab. Italien hat mit der Ausgangssperre am 9. März begonnen.

g4 <- ggplot(data = Regionen) +
  geom_line(mapping = aes(x = Datum, 
                          y = `Zuwachs bestätigter Fälle je Region`, 
                          color = Region), size = 1) +
  geom_vline(xintercept = as.Date("2020-01-23")) +
  geom_label(label="Hubei \n Quarantäne", y=15000, x=as.Date("2020-01-24")+1)+
  geom_vline(xintercept = as.Date("2020-03-09"), color = "black") +
  geom_label(label="Italien \n Ausgangssperre", y=18000, x=as.Date("2020-03-09")) +
  scale_x_date(date_breaks = "2 week", date_labels = "%d.%m") +  
  theme(legend.position = c(0.2, 0.8),
        legend.background = element_rect(fill=alpha(0.4)),
        plot.title = element_text(hjust = 0.5)) +
  labs(title = paste("Täglicher Anstieg an Fällen je Region, Stand ", 
                                               stand_datensatz,
                                               sep=""))
g4

Nun wollen wir die akuten Erkrankungen als Flächenplot über die Zeit darstellen. Einen Flächenplot erstellt man mit geom_area innerhalb von ggplot().

g5 <- ggplot(data = Regionen) +
  geom_area(mapping = aes(x = Datum, 
                          y = `Akute Erkrankungen je Region`, 
                          fill = Region), 
            size = 1) +
  labs(x = "Datum", 
       y = "Akute COVID-19 Fälle", 
       title = paste("Akute Erkrankungen je Region, Stand ",
                    stand_datensatz,
                    sep="")) +
  scale_y_continuous(labels = number) +
  scale_x_date(date_breaks = "2 week", 
               date_labels = "%d.%m") +
  theme(legend.position = c(0.1, 0.8),
        legend.background = element_rect(fill=alpha(0.4)),
        plot.title = element_text(hjust = 0.5)) +
  scale_fill_brewer(palette="Set3")
g5

Wir können auch in ggplot() mit geom_col() ein Balkendiagramm erzeugen, in dem die X-Achse die Region, die Y-Achse die Anzahl der Fälle und die Farbe (fill) die Region der Variablen darstellt. Durch den Befehl facet_wrap(~Kategorie) wird als weitere Dimension für jede im Datensatz vorhandene Kategorie eine eigene Abbildung erstellt. Hierzu müssen wir jedoch zuerst eine Variable erstellen, die die Stufen der Variable Kategorie enthalten soll, die wir verwenden möchten (wir wollen nicht alle Stufen aus Kategorie abbilden):

ausgewaehlte_kategorie <- c("Akute Erkrankungen je Region",
                            "Genesungen je Region",
                            "Todesfälle je Region")
g6 <- ggplot(data = filter(Regionen_long, 
                     Datum %in% max(Regionen_long$Datum),
                     Kategorie %in% ausgewaehlte_kategorie)
       ) +
  geom_col(mapping = aes(x = Region, 
                         y = `Fälle`, 
                         fill = Region), 
           position = "dodge") +
  facet_wrap(~Kategorie, ncol=6) +
  theme(axis.text.x = element_text(angle = 90)) +
  scale_y_continuous(labels = number) +
  labs(title = paste("Fälle je Region und Fallkategorie, Stand ",
                    stand_datensatz,
                    sep="")) +
  theme(legend.position = "top",
        legend.background = element_rect(fill=alpha(0.4)),
        plot.title = element_text(hjust = 0.5))
g6

Europa

In dieser Grafik wurden die Fallzahlen aller europäischen Bestätigte Fälleen dargestellt, in denen am 30.03.2020 mindestens 5000 bestätigte Fälle registriert wurden. Hierfür müssen wir also den Datensatz zunächst mit filter() auf die Region Europa, das Datum 2020-03-30 und Bestätigte Fälle >= 5000 filtern. Anschließend lassen wir uns aus diesem Objekt die Variable Country/Region ausgeben und speichern die Liste der Länder, die am 30.03.2020 über 5000 bestätigte Fälle hatten im Objekt europa_5000_list ab. Nun haben wir eine Liste all dieser Länder und filtern unseren Datensatz nach Ländern, die in dieser Liste vorkommen. Anschließend erstellen wir wieder einen Flächenplot:

europa_5000_list <- filter(data, Region == "Europa" &
           Datum == as.Date("2020-03-30") &
           `Bestätigte Fälle` >= 5000)$`Country/Region`

Europa5000 <- filter(data, 
                  Region =="Europa" & 
                    `Country/Region` %in% europa_5000_list & 
                    Datum >= as.Date("2020-02-24"))
g7 <- ggplot(data = Europa5000) +
  geom_area(mapping = aes(x = Datum, 
                          y = `Bestätigte Fälle`, 
                          fill = Staat)) +
  scale_x_date(date_breaks = "2 week", date_labels = "%d.%m") +
  scale_y_continuous(labels = number) +
  labs(x = "Datum", 
       y = "Bestätigte Fälle", 
       title = paste("Bestätigte Fälle in Europa, Stand ",
                     stand_datensatz,
                     sep="")) +
  theme(legend.position = c(0.15, 0.6),
        legend.background = element_rect(fill=alpha(0.4)),
        plot.title = element_text(hjust = 0.5)) + 
  scale_fill_brewer(palette="Set3")
g7

Auf dieselbe Weise erstellen wir die drei weiteren Grafiken, nur dass wir die vorangegangene Filterarbeit nicht erneurt durchführen müssen:

g8 <- ggplot(data = Europa5000) +
  geom_area(mapping = aes(x = Datum, 
                          y = `Todesfälle`, 
                          fill = Staat)) +
  scale_x_date(date_breaks = "2 week", date_labels = "%d.%m") +
  scale_y_continuous(labels = number) +
  labs(x = "Datum", 
       y = "Todesfälle", 
       title = paste("Todesfälle in Europa, Stand ",
                    stand_datensatz,
                    sep="")) +
  theme(legend.position = c(0.15, 0.6),
        legend.background = element_rect(fill=alpha(0.4)),
        plot.title = element_text(hjust = 0.5)) + 
  scale_fill_brewer(palette="Set3")
g8

g9 <- ggplot(data = Europa5000) +
  geom_area(mapping = aes(x = Datum, 
                          y = `Genesungen`, 
                          fill = Staat)) +
  scale_x_date(date_breaks = "2 week", date_labels = "%d.%m") +
  scale_y_continuous(labels = number) +
  labs(x = "Datum", 
       y = "Genesungen", 
       title = paste("Genesungen in Europa, Stand ",
                    stand_datensatz,
                    sep="")) +
  theme(legend.position = c(0.15, 0.6),
        legend.background = element_rect(fill=alpha(0.4)),
        plot.title = element_text(hjust = 0.5)) + 
  scale_fill_brewer(palette="Set3")
g9

g10 <- ggplot(data = Europa5000) +
  geom_area(mapping = aes(x = Datum, 
                          y = `Akute Erkrankungen`, 
                          fill = Staat)) +
  scale_x_date(date_breaks = "2 week", date_labels = "%d.%m") +
  scale_y_continuous(labels = number) +
  labs(title = paste("Akute Erkrankungen in Europa, Stand ",
                    stand_datensatz,
                    sep="")) +
  theme(legend.position = c(0.15, 0.6),
        legend.background = element_rect(fill=alpha(0.4)),
        plot.title = element_text(hjust = 0.5)) + 
  scale_fill_brewer(palette="Set3")
g10

Deutschland

Um alle drei Kategorien an Fällen in Deutschland in einem zusammenfassenden Flächenplot abzubilden, müssen wir zuerst den Datensatz nach Country/Region gruppieren und anschließend nach Germany filtern. Danach sortieren wir den Datensatz nach Datum in aufsteigender Reihenfolge und erstellen die Variable Absoluter Anstieg bestätigter Fälle mithilfe der lag() Funktion sowie die Variable Prozentualer Anstieg bestätigter Fälle.

Nun können wir diesen Datensatz mit pivot_longer() in die lange Form überführen.

Deutschland <- data %>% 
  group_by(`Country/Region`) %>% 
  filter(`Country/Region` == "Germany") %>% 
  arrange(Datum) %>% 
  mutate(`Absoluter Anstieg bestätigter Fälle` = lag(`Bestätigte Fälle`),
         `Prozentualer Anstieg bestätigter Fälle` = ((`Bestätigte Fälle` / `Absoluter Anstieg bestätigter Fälle`)-1)*100)
  


Deutschland_lang <- pivot_longer(data = Deutschland, 
                                 cols = c(`Bestätigte Fälle`,
                                          `Todesfälle`,
                                          `Genesungen`,
                                          `Akute Erkrankungen`,
                                          `Absoluter Anstieg bestätigter Fälle`,
                                          `Prozentualer Anstieg bestätigter Fälle`),
                                 names_to = "Kategorie",
                                 values_to = "Fälle")

Da wir in unserem langen Datensatz mehr Stufen innerhalb der Variable Kategorie haben, als wir abbilden möchten, filtern wir innerhalb von ggplot noch einmal nach den drei Variablen Akute Erkrankungen, Genesungen und Todesfälle.

g11 <- ggplot(data = filter(Deutschland_lang, 
                     Kategorie == "Akute Erkrankungen" |
                       Kategorie == "Genesungen" |
                       Kategorie == "Todesfälle", Datum >= as.Date("2020-03-01"))) +
  geom_area(mapping = aes(x = Datum, 
                          y = `Fälle`, 
                          fill = Kategorie)) +
  scale_x_date(date_breaks = "2 week", date_labels = "%d.%m") +
  labs(x = "Datum", 
       y = "Bestätigte Fälle in Deutschland",
       title = paste("Bestätigte Fälle in Deutschland, Stand ",
                    stand_datensatz,
                    sep="")) + 
  theme(legend.position = c(0.2, 0.8),
        legend.background = element_rect(fill=alpha(0.4)),
        plot.title = element_text(hjust = 0.5)) + 
  scale_fill_brewer(palette="Set3")
g11

Nun erstellen wir mit ggplot() und geom_col() ein Balkendiagramm und fügen ein paar Beschriftungen ein. Die Fallzahlen der Labels können wir aus dem gefilterten Datensatz ablesen. Innerhalb von ggplot() filtern wir auf Daten, die neuer sind als der 24.02.2020.

g12 <- ggplot(data = filter(Deutschland, Datum >= as.Date("2020-02-24"))) +
  geom_col(mapping = aes(x = Datum, 
                         y = `Prozentualer Anstieg bestätigter Fälle`), 
           fill = "#6699ff") +
  scale_y_continuous(breaks=seq(0,max(Deutschland$`Prozentualer Anstieg bestätigter Fälle`, na.rm = T), 10)) +
  geom_vline(xintercept = as.Date("2020-03-06")) +
  geom_label(label="670 Fälle", y=70, x=as.Date("2020-03-06")) +
  geom_vline(xintercept = as.Date("2020-03-14")) +
  geom_label(label="4585 Fälle", y=60, x=as.Date("2020-03-14")) +
  geom_vline(xintercept = as.Date("2020-03-21")) +
  geom_label(label="Bayern \n Ausgangs-\n sperre, \n 22213 Fälle", y=75, x=as.Date("2020-03-20")) +
  geom_vline(xintercept = as.Date("2020-03-23")) +
  geom_label(label="Bundesweites \n Kontaktverbot, \n 29056 Fälle", y=40, x=as.Date("2020-03-25")) +
  scale_x_date(date_breaks = "2 week", date_labels = "%d.%m") + 
  labs(y = "Prozent", 
       title = paste("Prozentualer Anstieg bestätigter Fälle in Deutschland, Stand ",
                     stand_datensatz,
                     sep="")) +
  theme(legend.position = c(0.9, 0.8),
        legend.background = element_rect(fill=alpha(0.4)),
        plot.title = element_text(hjust = 0.5))
g12

Im Folgenden möchten wir ein Balkendiagramm mit den Fallzahlen in Deutschland erstellen und eine Exponentialfunktion errechnen, die auf den Fallzahlen vom 14.-20.3.2020 beruht. Die Werte nach dem 20.3.2020 wollen wir hellblau zeichnen, die Werte vor dem 20.3.2020 sollen dunkelblau sein.

Hierfür filtern wir zuerst den Datensatz auf die Daten vom 23.02.2020 - 30.03.2020. Für die dunkelblauen Balken filtern wir erneut und wählen nur die Daten aus, die zwischen dem 1.03.2020 und dem 20.3.2020 liegen. An diesen Tagen stiegen die Fälle noch stärker als nach dem 20.3.2020. Diese Daten wollen wir dunkelblau färben.

Nun filtern wir erneut den Datensatz auf die die Daten vom 14.03.2020 - 20.03.2020, denn nur diese Daten wollen wir für die Berechnung des Modells benutzen. Auf diesem Datensatz errechnen wir den Logarithmus der bestätigten Fälle. Anschließend berechnen wir auf den logarithmierten Daten eine lineare Regression mit lm(). Mit der Funktion seq() erstellen wir anschließend eine Sequenz der Tage, für die wir die prognostizierten Fallzahlen mithilfe unseres Modells ausrechen möchten. Durch die Funktion predict.lm() berechnen wir für diese Sequenz die simulierten Werte und exponieren diese anschließend wieder mit exp() und speichern diese im Objekt prognose als Variable modell ab. Nun fügen wir den neu erstellten Datensatz prognose mit der Funktion full_join() zu unserem zuerst gefilterten Datensatz hinzu.


alle_daten <- Deutschland %>% 
  filter(Datum >= as.Date("2020-02-23") & Datum <= max(data$Datum))

dunkelblau <- Deutschland %>% 
  filter(Datum >= as.Date("2020-03-01") & Datum <= as.Date("2020-03-20"))

modelldaten <- Deutschland %>% 
  filter(Datum >= as.Date("2020-03-14") & Datum <= as.Date("2020-03-20")) %>% 
  mutate(`Log Bestätigte Fälle` = log(`Bestätigte Fälle`))

modell <- lm(`Log Bestätigte Fälle` ~ Datum, data = modelldaten)
Datum <- seq(as.Date("2020-03-14"), as.Date("2020-03-30"), by = 1)
prognose <- data.frame(Datum)
prognose$modell <- exp(predict.lm(modell, newdata = prognose)) 

alle_daten_prognose <- full_join(alle_daten, prognose, by = "Datum")

Nun können wir mit ggplot() zuerst ein Balkendiagramm Datensatzes alle_daten_prognose erstellen und wählen Hellblau (royalblue1) als Farbe. Anschließend erstellen wir ein zweites Balkendiagramm des Objektes dungelblau, welches nur die Werte vor vom 01.03.2020 - 20.03.2020 enthält und färben diese dunkelblau (royalblue4). Anschließend fügen wir einen Linienplot mit geom_line() hinzu, der die prognostizierten Fälle (modell) basierend auf den Daten vom 14.03.2020 - 20.03.2020 enthält.

Zum Schluss fügen wir noch einige Labels (geom_label()) und vertikale Linien (geom_vline()) hinzu, stellen das Datum auf ein Intervall von 5 Tagen und ändern die Formatierung des Datums auf der X-Achse.

g13 <- ggplot(data = alle_daten_prognose) +
  geom_col(mapping = aes(x = Datum, 
                         y = `Bestätigte Fälle`), 
           fill ="royalblue1") +
  geom_col(data = dunkelblau, 
           mapping = aes(x = Datum, 
                         y = `Bestätigte Fälle`), 
           fill ="royalblue4") +
  geom_line(mapping = aes(x = Datum, 
                          y = modell), 
            color = "red4", size = 1) + 
  
  geom_vline(xintercept = as.Date("2020-03-06")) +
  geom_label(label="670 Fälle", 
             y=20000, 
             x=as.Date("2020-03-06")) +
    
  geom_vline(xintercept = as.Date("2020-03-14")) +
  geom_label(label="4585 Fälle", 
             y=50000, 
             x=as.Date("2020-03-14")) +
  
  geom_vline(xintercept = as.Date("2020-03-21")) +
  geom_vline(xintercept = as.Date("2020-03-23")) +
  
  geom_label(label="Bayern \n Ausgangs-\n sperre, \n 22213 Fälle", 
             y=80000, 
             x=as.Date("2020-03-20")) +
  geom_label(label="Bundesweites \n Kontaktverbot, \n 29056 Fälle", 
             y=150000, 
             x=as.Date("2020-03-23")) +
  
  geom_vline(xintercept = as.Date("2020-03-30")) +
  geom_label(label="229108 \n Fälle", 
             y=225000, 
             x=as.Date("2020-03-30"), 
             color = "red") +
  geom_label(label="66885 \n Fälle", 
             y=95000, 
             x=as.Date("2020-03-30")) +
  
  labs(x = "Datum", 
       y = "Bestätigte Fälle",  
       title = paste("Bestätigte Fälle in Deutschland, Stand ",
                     stand_datensatz,
                     sep="")) +
  scale_x_date(date_breaks = "2 week", date_labels = "%d.%m") +
  theme(plot.title = element_text(hjust = 0.5))
g13

Diese Seite ist in ständiger Bearbeitung und wird demnächst weiter ergänzt. Zuletzt bearbeitet am 10.08.2020.

Stand des Datensatzes: 09.08.2020














Wie Sie uns erreichen:

StatSoft (Europe) GmbH
Poßmoorweg 1
22301 Hamburg
Deutschland

Kontakt

Fon +49 40 22 85 900-0
Fax +49 40 22 85 900-77

E-Mail info@statsoft.de
Internet: www.statsoft.de

Impressum
Datenschutz

LS0tDQp0aXRsZTogIlZpc3VhbGlzaWVydW5nIHZvbiBDT1ZJRC0xOSBEYXRlbiBtaXQgUiIgDQpzdWJ0aXRsZTogIiINCmF1dGhvcjogIkRyLiBOaWxzIFlhbm5pa29zLCBTdGF0U29mdCBFdXJvcGUgR21iSCINCiNkYXRlOiAiTcOkcnosIDIwMjAiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgY29kZV9mb2xkaW5nOiBzaG93DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICB0b2NfZGVwdGg6IDMNCiAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlDQogICAgaW5jbHVkZXM6DQogICAgICBpbl9oZWFkZXI6IGxvZ28uaHRtbA0KICB3b3JkX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgdG9jOiB5ZXMNCiAgcGRmX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQotLS0NCg0KRGllc2VyIEFydGlrZWwgd2lyZCByZWdlbG3DpMOfaWcgYWt0dWFsaXNpZXJ0LiAgDQpBbGxlIEdyYWZpa2VuIHNpbmQgYXVmIGRlbSAqKlN0YW5kIGRlcyBgciBzdGFuZF9kYXRlbnNhdHpgKiosIGRhcyBsZXR6dGUgaW5oYWx0bGljaGUgKipVcGRhdGUqKiBnYWIgZXMgYW0gKipgciBkYXR1bV9iZWFyYmVpdGV0YCoqLg0KDQojIEVpbmxlaXR1bmcNCg0KRGllIGFuZGF1ZXJuZGUgQ09WSUQtMTkgUGFuZGVtaWUgYmVkYXJmIGtlaW5lciBFcmtsw6RydW5nLCBkZW5uIGRpZSBnYW56ZSBXZWx0IGlzdCBtb21lbnRhbiBzY2h3ZXIgZGF2b24gYmV0cm9mZmVuLiBEaWUgaG9oZSBJbmZla3Rpb3NpdMOkdCBkZXMgU0FSUy1Db1YtMi1FcnJlZ2VycyB1bmQgZGVyIHBvdGVuemllbGwgc2Nod2VyZSBWZXJsYXVmIGRlciBFcmtyYW5rdW5nIHN0ZWxsdCBkaWUgR2VzdW5kaGVpdHNzeXN0ZW1lIHdlbHR3ZWl0IGF1ZiBlaW5lIGhhcnRlIFByb2JlLiBVbSBqZWRvY2ggcmljaHRpZ2UgU2Nocml0dGUgenVyIEVpbmTDpG1tdW5nIGRlciBQYW5kZW1pZSB6dSBnZWhlbiwgaXN0IGRpZSBBbmFseXNlIGRlciBGYWxsemFobGVuIGVpbiB1bmFiZGluZ2JhcmVyIFNjaHJpdHQuIA0KDQpWaWVsZSB2b24gdW5zIGhhYmVuIGVzIHNpY2ggbWl0dGxlcndlaWxlIHp1ciBHZXdvaG5oZWl0IGdlbWFjaHQsIG1pbmRlc3RlbnMgZWlubWFsIHTDpGdsaWNoIGF1ZiBkZW4gYWt0dWVsbGVuIFN0YW5kIGRlciBGYWxsemFobGVuIHp1IHNjaGF1ZW4uIERpZSBndXRlIFZlcmbDvGdiYXJrZWl0IGRlciBEYXRlbiB1bmQgbmV1ZXIgVmlzdWFsaXNpZXJ1bmdzdGVjaG5vbG9naWVuIG1hY2h0IGVzIHVucyBtw7ZnbGljaCwgR3JhcGhlbiBpbiBrw7xyemVzdGVyIFplaXQgYXVmIGRlbiBuZXVzdGVuIFN0YW5kIHp1IGJyaW5nZW4uIFZvciBhbGxlbSBkaWUgRGF0ZW4gZGVyIFtKb2hucyBIb3BraW5zIFVuaXZlcnNpdHldKGh0dHBzOi8vY29yb25hdmlydXMuamh1LmVkdS9tYXAuaHRtbCkgdW5kIGRlcyBbUm9iZXJ0IEtvY2ggSW5zdGl0dXRlc10oaHR0cHM6Ly93d3cucmtpLmRlL0RFL0NvbnRlbnQvSW5mQVovTi9OZXVhcnRpZ2VzX0Nvcm9uYXZpcnVzL25Db1YuaHRtbCkgd2VyZGVuIGRhZsO8ciBpbnRlbnNpdiB2ZXJ3ZW5kZXQuIEF1ZiB2ZXJzY2hpZWRlbmVuIFBsYXR0Zm9ybWVuLCB6LkIuIFtLYWdnbGUuY29tXShodHRwczovL3d3dy5rYWdnbGUuY29tLyksIHN0ZWhlbiB2aWVsZSBEYXRlbiBmw7xyIGplZGVybWFubiB6dXIgVmVyZsO8Z3VuZywgaW4gZGVyIEhvZmZudW5nLCBkYXNzIGRpZSBncm/Dn2Ugd2VsdHdlaXRlIENvbW11bml0eSBhbiBEYXRhIFNjaWVudGlzdHMgYXVzIGRlbiBEYXRlbiB3ZXJ0dm9sbGUgSW5mb3JtYXRpb25lbiB1bmQgVm9yaGVyc2FnZW4gZ2VuZXJpZXJ0Lg0KDQpXaXIgdm9uIGRlciBbU3RhdFNvZnQgRXVyb3BlIEdtYkggYmlldGVuIFItVHJhaW5pbmdzIGFuXShodHRwczovL3d3dy5zdGF0c29mdC5kZS9kZS90ZXJtaW5lL3RyYWluaW5nLykgdW5kIGhhYmVuIGRpZSBqZXR6dCBhbmZhbGxlbmRlbiBEYXRlbiBlYmVuZmFsbHMgZ2VudXR6dCwgdW0gRXJrZW5udG5pc3NlIGR1cmNoIFZpc3VhbGlzaWVydW5nIHp1IGVyemV1Z2VuLiBIaWVyZsO8ciBoYWJlbiB3aXIgZGllIFtPcGVuLVNvdXJjZSBTdGF0aXN0aWtzb2Z0d2FyZSBSXShodHRwczovL3d3dy5yLXByb2plY3Qub3JnLykgdmVyd2VuZGV0IHVuZCBkZW4gaGllcmbDvHIgdmVyd2VuZGV0ZW4gQ29kZSBvZmZlbmdlbGVndCwgdW0gaW50ZXJlc3NpZXJ0ZW4gQW5hbHlzdGVuIGVpbmUga29zdGVubG9zZSBIaWxmZSBmw7xyIGRpZSBWaXN1YWxpc2llcnVuZyBtaXQgUiBiZXJlaXR6dXN0ZWxsZW4uDQpFcyB3dXJkZW4gZGllIERhdGVuIGRlciBbSm9obnMgSG9wa2lucyBVbml2ZXJzaXR5XShodHRwczovL2Nvcm9uYXZpcnVzLmpodS5lZHUvbWFwLmh0bWwpIHZlcndlbmRldCAoaGVydW50ZXJnZWxhZGVuIHZvbiBbZGllc2VtIEthZ2dsZSBMaW5rXShodHRwczovL3d3dy5rYWdnbGUuY29tL3N1ZGFsYWlyYWprdW1hci9ub3ZlbC1jb3JvbmEtdmlydXMtMjAxOS1kYXRhc2V0KSkuIERpZSBVcnNwcnVuZ3NkYXRlbiwgd2llIHNpZSBpbiBLYWdnbGUgdmVyd2VuZGV0IHdlcmRlbiwgc3RhbW1lbiBhdXMgZGVtIFtHaXQgUmVwb3NpdG9yeSBkZXIgSm9obnMgSG9wa2lucyBVbml2ZXJzaXR5XShodHRwczovL2dpdGh1Yi5jb20vQ1NTRUdJU2FuZERhdGEvQ09WSUQtMTkpLg0KDQpBbiBkaWVzZXIgU3RlbGxlIG3DtmNodGVuIHdpciBlaW5tYWwgZGllIENoYW5jZSBudXR6ZW4sIFNpZSBhdWYgdmVyc2NoaWVkZW5lIEhpbGZzcGxhdHRmb3JtZW4gZsO8ciBkaWUgQ29yb25hLUtyaXNlIGF1Zm1lcmtzYW0genUgbWFjaGVuLiBWaWVsbGVpY2ggc2luZCBTaWUgc2VsYnN0IGJldHJvZmZlbiBvZGVyIGtlbm5lbiBQZXJzb25lbiwgZGllIGJlc29uZGVycyBiZWRyb2h0IHNpbmQgdW5kIHp1ciBlaWdlbmVuIFNpY2hlcmhlaXQgenUgSGF1c2UgYmxlaWJlbiBzb2xsdGVuLiBVbSBkaWVzZW4gTWVuc2NoZW4genUgaGVsZmVuLCB3dXJkZW4gdmllbGUgSGlsZnNwbGF0dGZvcm1lbiBlaW5nZXJpY2h0ZXQsIHVtIGJlaXNwaWVsc3dlaXNlIEVpbmvDpHVmZSBmw7xyIEJldHJvZmZlbmUgenUgw7xiZXJuZWhtZW4uIFtBdWYgZGllc2VyIFNlaXRlIGdpYnQgZXMgTGlua3MgenUgc29sY2hlbiBIaWxmc3BsYXR0Zm9ybWVuXShodHRwczovL3d3dy5mcmVpd2lsbGlnLmhhbWJ1cmcvY29yb25hLWhpbGZlLmh0bWwpLCAgYmVpIGRlbmVuIFNpZSBzaWNoIGFscyBCZXRyb2ZmZW5lIG9kZXIgYWxzIHBvdGVuemllbGxlIEhlbGZlciByZWdpc3RyaWVyZW4ga8O2bm5lbi4gRGVua2VuIFNpZSBiaXR0ZSBhdWNoIGRhcmFuLCBkYXNzIGJlc29uZGVycyBbVGllcmhlaW1lIGluIGRpZXNlciBaZWl0IGVpbmVuIGdyb8OfZW4gWnVsYXVmIGFuIEhhdXN0aWVyZW4gaGFiZW5dKGh0dHBzOi8vd3d3LmhhbWJ1cmdlci10aWVyc2NodXR6dmVyZWluLmRlL3RpZXJoZWltL2FrdHVlbGxlcy8xMjY4Ny1odHYtcmljaHRldC1zaWNoLWF1Zi1kaWUtYXVmbmFobWVuLWRlci10aWVyZS12b24tY29yb25hLXBhdGllbnQtaW5uZW4tZWluKSwgZGVyZW4gQmVzaXR6ZXIgYXVmZ3J1bmQgZGVyIEtyYW5raGVpdCBuaWNodCBtZWhyIGluIGRlciBMYWdlIHNpbmQsIHNpY2ggdW0gZGllc2UgenUga8O8bW1lcm4uIER1cmNoIEZ1dHRlci0gb2RlciBHZWxkc3BlbmRlbiB1bmQga8O2bm5lbiBTaWUgZGllc2UgdW50ZXJzdMO8dHplbi4NCg0KIyMjIyBFbXBmb2hsZW5lIExpdGVyYXR1cg0KDQpGw7xyIGRpZSBEYXRlbmFuYWx5c2UgdW5kIFZpc3VhbGlzaWVydW5nIGvDtm5uZW4gd2lyIGRpZSBoZXJ2b3JyYWdlbmRlbiBCw7xjaGVyIFtSIGZvciBEYXRhIFNjaWVuY2VdKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovKSBzb3dpZSBbSGFuZHMgb24gUHJvZ3JhbW1pbmcgd2l0aCBSXShodHRwczovL3JzdHVkaW8tZWR1Y2F0aW9uLmdpdGh1Yi5pby9ob3ByLykgdm9uIEhhZGxleSBXaWNraGFtIHVuZCBHYXJyZXQgR3JvbGVtdW5kIHfDpHJtc3RlbnMgZW1wZmVobGVuLiBCZWlkZSBBdXRvcmVuIHNpbmQgw7xicmlnZW5zIGF1Y2ggZGllIFVyaGViZXIgZmFzdCBhbGxlciBQYWtldGUsIGRpZSB3aXIgaW4gZGllc2VtIFByb2pla3QgYmVuw7Z0aWdlbi4NCg0KDQoNCg0KDQoNCiMgRGllIGFrdHVlbGxlIFNpdHVhdGlvbg0KDQoNCkluIGRpZXNlbSBBYnNjaG5pdHQgbcO2Y2h0ZW4gd2lyIElobmVuIGFuaGFuZCB2ZXJzY2hpZWRlbmVyIEdyYWZpa2VuIHplaWdlbiwgd2llIHNpY2ggZGllIENPVklELTE5IFBhbmRlbWllIGluIGRlciBXZWx0IGF1c2JyZWl0ZXQuIERlciBTdGFuZCBkZXMgRGF0ZW5zYXR6ZXMgaXN0IGRlciBgciBzdGFuZF9kYXRlbnNhdHpgLiBJbSBuw6RjaHN0ZW4gQWJzY2huaXR0IHdlaXRlciB1bnRlbiB6ZWlnZW4gd2lyIGRhbm4sIHdpZSB3aXIgZGllc2UgR3JhZmlrZW4gbWl0IFIgZXJ6ZXVndCBoYWJlbi4gDQoNCiMjIyBXZWx0d2VpdA0KDQpJbiBkZXIgZm9sZ2VuZGVuIEdyYWZpayBzaW5kIGRpZSBiZXN0w6R0aWd0ZW4gRmFsbHphaGxlbiBhbGxlciBTdGFhdGVuLCBhdWZnZXRlaWx0IGluIGFrdXRlIEVya3Jhbmt1bmdlbiwgR2VuZXN1bmdlbiB1bmQgVG9kZXNmw6RsbGUsIGRhcmdlc3RlbGx0LCBkaWUgYW0gYHIgc3RhbmRfZGF0ZW5zYXR6YCBtaW5kZXN0ZW5zIDUwMDAwIGJlc3TDpHRpZ3RlIEbDpGxsZSByZWdpc3RyaWVydCBoYXR0ZW4uDQpgYGB7ciBlY2hvPUZBTFNFfQ0KZzENCmBgYA0KDQpEaWUgZm9sZ2VuZGUgR3JhZmlrIHplaWd0IGRlbiBBbnN0aWVnIGRlciBiZXN0w6R0aWd0ZW4gRsOkbGxlIGF1ZiBlaW5lciBsb2dhcml0aG1pZXJ0ZW4gU2thbGEgaW4gQWJow6RuZ2lna2VpdCBkZXIgdmVyZ2FuZ2VuZW4gVGFnZSBzZWl0IGRlbSAxMDAuIHJlZ2lzdHJpZXJ0ZW4gRmFsbC4gQXVmIGRpZXNlIFdlaXNlIGzDpHNzdCBzaWNoIGd1dCBlcmtlbm5lbiwgd2llIHNjaG5lbGwgc2ljaCBDT1ZJRC0xOSBpbiBkZW4gZW50c3ByZWNoZW5kZW4gTMOkbmRlcm4gYXVzZ2VicmVpdGV0IGhhdC4gRXMgc2luZCBudXIgZGllamVuaWdlbiBzaWViZW4gU3RhYXRlbiBhYmdlYmlsZGV0LCBkaWUgYmlzIHp1bSBgciBzdGFuZF9kYXRlbnNhdHpgIGRpZSBtZWlzdGVuIEbDpGxsZSByZWdpc3RyaWVydCBoYXR0ZW4sIHNvd2llIFPDvGRrb3JlYSwgZGllIGR1cmNoIGlocmUgc2NobmVsbGUgUmVha3Rpb25zemVpdCB1bmQgaG9oZSBUZXN0emFobGVuIGVpbmUgc3RhcmtlIEVpbmTDpG1tdW5nIGRlcyBBdXNicnVjaHMgZXJ6aWVsZW4ga29ubnRlbi4gRHVyY2ggZGllIExvZy1Ta2FsYSBpc3QgZXMgbcO2Z2xpY2gsIGRlbiBadXdhY2hzIGFuIGJlc3TDpHRpZ3RlbiBGw6RsbGVuIHVuYWJow6RuZ2lna2VpdCB2b24gZGVyZW4gR3LDtsOfZW5vcmRudW5nIHp3aXNjaGVuIGRlbiB2ZXJzY2hpZWRlbmVuIEzDpG5kZXJuIHp1IHVudGVyc2NoZWlkZW4uDQoNCmBgYHtyIGVjaG89RkFMU0V9DQpnMg0KYGBgDQoNCg0KIyMjIENoaW5hLCBFdXJvcGEgdW5kIFVTQQ0KDQpEaWUgZm9sZ2VuZGUgR3JhZmlrIGvDtm5uZW4gd2lyIGVya2VubmVuLCB3aWUgc2ljaCBkaWUgRmFsbHphaGxlbiBpbiBDaGluYSwgRXVyb3BhLCBkZW4gVVNBIHVuZCBhbGxlbiBhbmRlcmVuIEzDpG5kZXJuIChTb25zdGlnZSkgZW50d2lja2VsdCBoYXQuIEVzIHdpcmQgZGV1dGxpY2ggZXJrZW5uYmFyLCB3aWUgc2NobmVsbCBDaGluYSBkZW4gQXVzYnJ1Y2ggZHVyY2ggc2VociBzdHJpa3RlcyBEdXJjaGdyZWlmZW4gaW4gZGVuIEdyaWZmIGJla29tbWVuIGtvbm50ZS4gRXR3YSBmw7xuZiBXb2NoZW4gbmFjaGRlbSBkaWUgRmFsbHphaGxlbiBpbiBDaGluYSBlaW4gUGxhdGVhdSBlcnJlaWNodCBoYXR0ZW4sIHdhcmVuIGRpZSBGYWxsemFobGVuIGluIEV1cm9wYSBiZXJlaXRzIGjDtmhlciBhbHMgZGllIGluIENoaW5hLiBOdXIgendlaSB3ZWl0ZXJlIFdvY2hlbiBzcMOkdGVyIGdhYiBlcyBpbiBFdXJvcGEgYmVyZWl0cyBmw7xuZm1hbCBzbyB2aWVsZSBGw6RsbGUgd2llIGluIENoaW5hLiBEaWUgVVNBIHplaWdlbiBlYmVuZmFsbHMgZWluZW4gcmFzYW50ZW4gQW5zdGllZywgZGVyIHVtIGV0d2EgZWluZWluaGFsYiBXb2NoZW4gdmVyesO2Z2VydCB2b24gRXVyb3BhIHN0YXR0ZmluZGV0LiBTb21pdCBzaW5kIEV1cm9wYSB1bmQgZGllIFVTQSBkaWUgbmV1ZW4gRXBpemVudHJlbiBkZXIgQ09WSUQtMTkgUGFuZGVtaWUuIA0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KZzNiDQpgYGANCg0KDQoNCkRpZSBmb2xnZW5kZSBHcmFmaWsgemVpZ3QgZGVuIHTDpGdsaWNoZW4gWnV3YWNocyBhbiBGYWxsemFobGVuIGluIENoaW5hLCBFdXJvcGEsIGRlbiBVU0EgdW5kIGluIGFsbGVuIGFuZGVyZW4gTMOkbmRlcm4uIEhpZXIgd2lyZCBkZXV0bGljaCBlcmtlbm5iYXIsIHdpZSBzY2huZWxsIGRpZSBjaGluZXNpc2NoZSBSZWdpZXJ1bmcgcmVhZ2llcnQgdW5kIHp1IGRyYXN0aXNjaGVuIE1pdHRlbG4gZ2VncmlmZmVuIGhhdCwgZGVubiBzY2hvbiBhbSAyMy4gSmFudWFyIHd1cmRlIG1pdCBkZXIgUXVhcmFudMOkbmUgdm9uIEh1YmVpIGJlZ29ubmVuLCBhbHNvIHp1IGVpbmVtIFplaXRwdW5rdCwgYWxzIGVzIG51ciA2MzkgQmVzdMOkdGlndGUgRsOkbGxlIHVuZCAxOCBUb2Rlc2bDpGxsZSBpbiBDaGluYSBnYWIuIERlbm5vY2ggc3RpZWdlbiB0cm90eiBkZXIgUXVhcmFudMOkbmUgZGllIGJlc3TDpHRpZ3RlbiBGw6RsbGUgaW4gQ2hpbmEgYXVmICoqYHIgcmVmMDAxYCoqIGFuLCBkYXJ1bnRlciB3YXJlbiAqKmByIHJlZjAwMmAqKiBUb2Rlc2bDpGxsZSAoU3RhbmQgYHIgc3RhbmRfZGF0ZW5zYXR6YCkuIERhcyB2ZXJkZXV0bGljaHQgc2VociBzdGFyaywgZGFzcyBlaW5lIHN0YXJrZSBFaW5zY2hyw6Rua3VuZyBkZXIgUmVpc2UtIHVuZCBCZXdlZ3VuZ3NmcmVpaGVpdCAoc28gc2NobWVyemhhZnQgZGllc2UgYXVjaCBzZWluIG1hZykgYSkgZGllIHdlaXRlcmUgVmVyYnJlaXR1bmcgZWZmZWt0aXYgZWluZMOkbW1lbiBrYW5uLCBiKSBlaGVyIHp1IGZyw7xoIGFscyB6dSBzcMOkdCBhdXNnZWbDvGhydCB3ZXJkZW4gc29sbHRlIHVuZCBjKSBkaWUgS3VydmUgbnVyIHplaXR2ZXJ6w7ZnZXJ0IGFiZmxhY2hlbiBrYW5uLg0KDQoNCg0KYGBge3IgaW5jbHVkZT1GQUxTRX0NCnJlZjAwMSA8LSBmb3JtYXQocm91bmQobWF4KGZpbHRlcihSZWdpb25lbl9sb25nLCBSZWdpb24gPT0gIkNoaW5hIiAmIEthdGVnb3JpZSA9PSAiQmVzdMOkdGlndGUgRsOkbGxlIGplIFJlZ2lvbiIpJGBGw6RsbGVgKSwgZGlnaXRzID0gMCksIHNjaWVudGlmaWM9MSkNCg0KcmVmMDAyIDwtIGZvcm1hdChyb3VuZChtYXgoZmlsdGVyKFJlZ2lvbmVuX2xvbmcsIFJlZ2lvbiA9PSAiQ2hpbmEiICYgS2F0ZWdvcmllID09ICJUb2Rlc2bDpGxsZSBqZSBSZWdpb24iKSRgRsOkbGxlYCksIGRpZ2l0cyA9IDApLCBzY2llbnRpZmljPTEpDQoNCg0KcmVmMSA8LSBtYXgoZmlsdGVyKFJlZ2lvbmVuLCBSZWdpb24gPT0gIkV1cm9wYSIpJGBadXdhY2hzIGJlc3TDpHRpZ3RlciBGw6RsbGUgamUgUmVnaW9uYCwgbmEucm0gPSBUKQ0KDQpyZWYxIDwtIGZvcm1hdChyb3VuZChyZWYxLCBkaWdpdHMgPSAwKSwgc2NpZW50aWZpYz0xKQ0KcmVmMiA8LSBzdHJmdGltZShmaWx0ZXIoUmVnaW9uZW4sIFJlZ2lvbiA9PSAiRXVyb3BhIiAmIGBadXdhY2hzIGJlc3TDpHRpZ3RlciBGw6RsbGUgamUgUmVnaW9uYCA9PSBtYXgoZmlsdGVyKFJlZ2lvbmVuLCBSZWdpb24gPT0gIkV1cm9wYSIpJGBadXdhY2hzIGJlc3TDpHRpZ3RlciBGw6RsbGUgamUgUmVnaW9uYCwgbmEucm0gPSBUKSkkRGF0dW0sIiVkLiVtLiVZIikNCg0KcmVmMyA8LSBtYXgoZmlsdGVyKFJlZ2lvbmVuLCBSZWdpb24gPT0gIlVTQSIpJGBadXdhY2hzIGJlc3TDpHRpZ3RlciBGw6RsbGUgamUgUmVnaW9uYCwgbmEucm0gPSBUKQ0KcmVmMyA8LSBmb3JtYXQocm91bmQocmVmMywgZGlnaXRzID0gMCksIHNjaWVudGlmaWM9MSkNCnJlZjQgPC0gc3RyZnRpbWUoZmlsdGVyKFJlZ2lvbmVuLCBSZWdpb24gPT0gIlVTQSIgJiBgWnV3YWNocyBiZXN0w6R0aWd0ZXIgRsOkbGxlIGplIFJlZ2lvbmAgPT0gbWF4KGZpbHRlcihSZWdpb25lbiwgUmVnaW9uID09ICJVU0EiKSRgWnV3YWNocyBiZXN0w6R0aWd0ZXIgRsOkbGxlIGplIFJlZ2lvbmAsIG5hLnJtID0gVCkpJERhdHVtLCIlZC4lbS4lWSIpDQoNCnJlZjUgPC0gbWF4KGZpbHRlcihSZWdpb25lbiwgUmVnaW9uID09ICJDaGluYSIpJGBadXdhY2hzIGJlc3TDpHRpZ3RlciBGw6RsbGUgamUgUmVnaW9uYCwgbmEucm0gPSBUKQ0KcmVmNSA8LSBmb3JtYXQocm91bmQocmVmNSwgZGlnaXRzID0gMCksIHNjaWVudGlmaWM9MSkNCnJlZjYgPC0gc3RyZnRpbWUoZmlsdGVyKFJlZ2lvbmVuLCBSZWdpb24gPT0gIkNoaW5hIiAmIGBadXdhY2hzIGJlc3TDpHRpZ3RlciBGw6RsbGUgamUgUmVnaW9uYCA9PSBtYXgoZmlsdGVyKFJlZ2lvbmVuLCBSZWdpb24gPT0gIkNoaW5hIikkYFp1d2FjaHMgYmVzdMOkdGlndGVyIEbDpGxsZSBqZSBSZWdpb25gLCBuYS5ybSA9IFQpKSREYXR1bSwiJWQuJW0uJVkiKQ0KDQpgYGANCg0KDQpJbiBFdXJvcGEgd3VyZGUgYW0gYHIgcmVmMmAgZGVyIGJpc2hlciBow7ZjaHN0ZSB0w6RnbGljaGUgWnV3YWNocyB2b24gYHIgcmVmMWAgbmV1ZW4gRsOkbGxlbiB2ZXJ6ZWljaG5ldCwgaW4gZGVuIFVTQSBsYWcgZGVyIGjDtmNoc3RlIEFuc3RpZWcgYmVpIGByIHJlZjNgIEbDpGxsZW4gYW0gYHIgcmVmNGAuDQpJbiBDaGluYSBsYWcgZGVyIGjDtmNoc3RlIEFuc3RpZWcgZGFnZWdlbiBiZWkgbnVyIGByIHJlZjVgIEbDpGxsZW4gYW0gYHIgcmVmNmAuDQoNCmBgYHtyIGVjaG89RkFMU0V9DQpnNA0KYGBgDQoNCg0KDQoNCg0KYGBge3IgaW5jbHVkZT1GQUxTRX0NCnJlZjcgPC0gKGZpbHRlcihSZWdpb25lbiwgUmVnaW9uID09ICJFdXJvcGEiLCBEYXR1bSA9PSBhcy5EYXRlKCIyMDIwLTAzLTI4IikpJGBBa3V0ZSBFcmtyYW5rdW5nZW4gamUgUmVnaW9uYC8gZmlsdGVyKFJlZ2lvbmVuLCBSZWdpb24gPT0gIkV1cm9wYSIsIERhdHVtID09IGFzLkRhdGUoIjIwMjAtMDMtMjgiKSkkYEJlc3TDpHRpZ3RlIEbDpGxsZSBqZSBSZWdpb25gKSoxMDANCnJlZjcgPC0gcm91bmQocmVmNywgZGlnaXRzPTEpDQpyZWY4IDwtIChmaWx0ZXIoUmVnaW9uZW4sIFJlZ2lvbiA9PSAiVVNBIiwgRGF0dW0gPT0gYXMuRGF0ZSgiMjAyMC0wMy0yOCIpKSRgQWt1dGUgRXJrcmFua3VuZ2VuIGplIFJlZ2lvbmAvIGZpbHRlcihSZWdpb25lbiwgUmVnaW9uID09ICJVU0EiLCBEYXR1bSA9PSBhcy5EYXRlKCIyMDIwLTAzLTI4IikpJGBCZXN0w6R0aWd0ZSBGw6RsbGUgamUgUmVnaW9uYCkqMTAwDQpyZWY4IDwtIHJvdW5kKHJlZjgsIGRpZ2l0cz0xKQ0KcmVmOSA8LSAoZmlsdGVyKFJlZ2lvbmVuLCBSZWdpb24gPT0gIkNoaW5hIiwgRGF0dW0gPT0gYXMuRGF0ZSgiMjAyMC0wMy0yOCIpKSRgQWt1dGUgRXJrcmFua3VuZ2VuIGplIFJlZ2lvbmAvIGZpbHRlcihSZWdpb25lbiwgUmVnaW9uID09ICJDaGluYSIsIERhdHVtID09IGFzLkRhdGUoIjIwMjAtMDMtMjgiKSkkYEJlc3TDpHRpZ3RlIEbDpGxsZSBqZSBSZWdpb25gKSoxMDANCnJlZjkgPC0gcm91bmQocmVmOSwgZGlnaXRzPTEpDQpmaWx0ZXIoUmVnaW9uZW4sIFJlZ2lvbiA9PSJVU0EiKQ0KYGBgDQoNCkluIGRlciBmb2xnZW5kZW4gR3JhZmlrIGlzdCBkaWUgU3VtbWUgYW4gYWt1dGVuIEVya3Jhbmt1bmdlbiBhbGxlciBoaWVyIGJldHJhY2h0ZXRlbiBSZWdpb25lbiBmw7xyIGRlbiBqZXdlaWxpZ2VuIFplaXRyYXVtIGRhcmdlc3RlbGx0LCBkaWUgQnJlaXRlIGRlcyBmYXJiaWdlbiBCYW5kZXMgc3ltYm9saXNlcnQgZGFiZWkgZGVuIEFudGVpbCBkZXIgRXJrcmFua3VuZ2VuLCBkaWUgaW4gZGVyIGpld2VpbGlnZW4gUmVnaW9uIHN0YXR0ZmFuZGVuLiBadWVyc3QgYmVnYW5uIGRpZSBBdXNicmVpdHVuZyBpbiBDaGluYS4gRGllc2Ugc2V0enRlIHNpY2ggZGFubiBpbiBFdXJvcGEgdW5kIGFuZGVyZW4gTMOkbmRlcm4gd2VpdGVyIGZvcnQgdW5kIGdpbmcgemVpdGdsZWljaCBpbiBDaGluYSB3aWVkZXIgenVyw7xjay4gRXR3YSB6d2VpIFdvY2hlbiBuYWNoIGRlbSBBdXNicnVjaCBpbiBFdXJvcGEgYnJlaXRldGUgc2ljaCBkaWUgRXJrYW5rdW5nIGRhbm4gYXVjaCBpbiBkZW4gVmVyZWluaWd0ZW4gU3RhYXRlbiBhdXMuIERpZSBWZXJlaW5pZ3RlbiBTdGFhdGVuIHNpbmQgZGFzIExhbmQgbWl0IGRlciBow7ZjaHN0ZW4gWmFobCBhbiBha3V0ZW4gRXJrYW5rdW5nZW4uIA0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KDQpnNQ0KDQpgYGANCg0KDQpJbiBkZXIgZm9sZ2VuZGVuIERhcnN0ZWxsdW5nIHNpbmQgZGllIGJlc3TDpHRpZ3RlbiBGw6RsbGUsIFRvZGVzZsOkbGxlIHVuZCBha3V0ZW4gRXJrcmFua3VuZ2VuIGbDvHIgZGllIHZlcnNjaGllZGVuZW4gUmVnaW9uZW4gYW0gYHIgc3RhbmRfZGF0ZW5zYXR6YCAgZGFyZ2VzdGVsbHQuDQoNCmBgYHtyIGVjaG89RkFMU0V9DQpnNg0KYGBgDQoNCg0KDQoNCg0KIyMjIEV1cm9wYSANCg0KSW4gZGVyIGZvbGdlbmRlbiBHcmFmaWsgc2VoZW4gd2lyIGRpZSBiZXN0w6R0aWd0ZW4gRsOkbGxlIGFsbGVyIGV1cm9ww6Rpc2NoZW4gU3RhYXRlbiwgaW4gZGVuZW4gYW0gKiozMC4wMy4yMDIwKiogbWluZGVzdGVucyAqKjUwMDAgYmVzdMOkdGlndGUgRsOkbGxlKiogcmVnaXN0cmllcnQgd3VyZGVuLiBEaWUgQnJlaXRlIGRlcyBqZXdlaWxpZ2VuIEJhbmRlcyB6ZWlndCBkYWJlaSwgd2VsY2hlciBBbnRlaWwgYW4gYmVzdMOkdGlndGVuIEbDpGxsZW4gU3RhYXRlbiBkZW0gamV3ZWlsaWdlbiBTdGFhdCB6dXp1b3JkbmVuIGlzdCB1bmQgd2llIHNpY2ggZGllc2VyIEFudGVpbCDDvGJlciBkaWUgWmVpdCB2ZXLDpG5kZXJ0LiBEYXJhdXMgd2lyZCBlcnNpY2h0bGljaCwgZGFzcyBJdGFsaWVuIGFscyBlcnN0ZXMgTGFuZCBlaW5lIGhvaGUgWmFobCBhbiBiZXN0w6R0aWd0ZW4gRsOkbGxlbiByZWdpc3RyaWVydGUuIFdlbmlnZSBXb2NoZW4gc3DDpHRlciBzdGllZ2VuIGRhbm4gZGllIEluZmVrdGlvbnN6YWhsZW4gYXVjaCBpbiB1bWxpZWdlbmRlbiBldXJvcMOkaXNjaGVuIFN0YWF0ZW4gc3RhcmsgYW4uIERpZSBtZWlzdGVuIEluZmVrdGlvbmVuIHd1cmRlbiBiaXMgenVtIGByIHN0YW5kX2RhdGVuc2F0emAgaW4gSXRhbGllbiwgU3BhbmllbiB1bmQgRGV1dHNjaGxhbmQgdW5kIEZyYW5rcmVpY2ggZXJmYXNzdC4NCg0KYGBge3IgZWNobz1GQUxTRX0NCmc3DQpgYGANCg0KSW4gZGVyIGZvbGdlbmRlbiBHcmFmaWsgc2VoZW4gd2lyIGRpZSBUb2Rlc2bDpGxsZSBhbGxlciBldXJvcMOkaXNjaGVuIFN0YWF0ZW4sIGluIGRlbmVuIGFtICoqMzAuMDMuMjAyMCoqIG1pbmRlc3RlbnMgKio1MDAwIGJlc3TDpHRpZ3RlIEbDpGxsZSoqIHJlZ2lzdHJpZXJ0IHd1cmRlbi4uIERpZSBaYWhsIGRlciBUb2Rlc2bDpGxsZSBpbiBEZXV0c2NobGFuZCBpc3QgdmVyZ2xpY2hlbiBtaXQgZGVyIHJlbGF0aXYgaG9oZW4gWmFobCBiZXN0w6R0aWd0ZXIgRsOkbGxlIG5vY2ggc2VociBnZXJpbmcuDQoNCg0KYGBge3IgZWNobz1GQUxTRX0NCmc4DQpgYGANCg0KRGllIGZvbGdlbmRlIEdyYWZpayB6ZWlndCBkaWUgQW56YWhsIGRlciBHZW5lc3VuZ2VuIGlubmVyaGFsYiBkZXIgdmVyc2NoaWVkZW5lbiBldXJvcMOkaXNjaGVuIFN0YWF0ZW4uIERpZSBaYWhsIGRlciBHZW5lc3VuZ2VuIGlzdCBpbiBTcGFuaWVuLCBJdGFsaWVuIHVuZCBEZXV0c2NobGFuZCBhbSBow7ZjaHN0ZW4uDQoNCmBgYHtyIGVjaG89RkFMU0V9DQpnOQ0KYGBgDQoNCkRpZSBmb2xnZW5kZSBHcmFmaWsgemVpZ3QgZGVuIFZlcmxhdWYgZGVyIGFrdXRlbiBFcmtyYW5rdW5nZW4gaW5uZXJoYWxiIGRlciBldXJvcMOkaXNjaGVuIFN0YWF0ZW4uDQoNCg0KYGBge3IgZWNobz1GQUxTRX0NCmcxMA0KYGBgDQoNCg0KIyMjIERldXRzY2hsYW5kDQoNCkluIGRlciBmb2xnZW5kZW4gR3JhZmlrIHNpbmQgZGllIGFrdXRlbiBFcmtyYW5rdW5nZW4sIFRvZGVzZsOkbGxlIHVuZCBHZW5lc3VuZ2VuIGluIERldXRzY2hsYW5kIGRhcmdlc3RlbGx0LiANCg0KYGBge3IgZWNobz1GQUxTRX0NCmcxMQ0KYGBgDQoNCg0KSW4gZGVyIGZvbGdlbmRlbiBHcmFmaWsgc2VoZW4gd2lyIGRlbiB0w6RnbGljaGVuIHByb3plbnR1YWxlbiBBbnN0aWVnIGJlc3TDpHRpZ3RlciBGw6RsbGUgaW4gRGV1dHNjaGxhbmQuIERpZSBow7ZjaHN0ZW4gdMOkZ2xpY2hlbiBBbnN0aWVnZSAoPiA1MCUpIHd1cmRlbiByZWdpc3RyaWVydCwgYWxzIGVzIGluIERldXRzY2hsYW5kIG5vY2ggd2VuaWdlciBhbHMgNTAwMCBGw6RsbGUgZ2FiLiBBbnNjaGxpZcOfZW5kIGxhZ2VuIGRpZSB0w6RnbGljaGVuIEFuc3RpZWdlIGbDvHIgNyBUYWdlIHp3aXNjaGVuIDI1IHVuZCAzNSAlIHVuZCBzYW5rZW4gZsO8ciBkaWUgZm9sZ2VuZGVuIDggVGFnZSB3ZWl0ZXIgYXVmIDEwLTE3JSBhYi4gU2VpdCBkZW0gMjkuMDMuMjAyMCBibGllYmVuIGRpZSB0w6RnbGljaGVuIEFuc3RpZWdlIHVudGVyIGRlciAxMCUtR3JlbnplLg0KDQoNCmBgYHtyIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpnMTINCmBgYCANCg0KDQpgYGB7ciBpbmNsdWRlPUZBTFNFfQ0KcmVmMTAgPC0gcm91bmQoZmlsdGVyKHByb2dub3NlLCBEYXR1bSA9PSBhcy5EYXRlKCIyMDIwLTAzLTMwIikpJG1vZGVsbCwgZGlnaXRzID0gMCkNCnJlZjEwIDwtIGZvcm1hdChyZWYxMCwgc2NpZW50aWZpYz0xKQ0KcmVmMTEgPC0gcm91bmQoZmlsdGVyKERldXRzY2hsYW5kLCBEYXR1bSA9PSBhcy5EYXRlKCIyMDIwLTAzLTMwIikpJGBCZXN0w6R0aWd0ZSBGw6RsbGVgLCBkaWdpdHMgPSAwKQ0KcmVmMTEgPC0gZm9ybWF0KHJlZjExLCBzY2llbnRpZmljPTEpDQpgYGANCg0KRGllc2UgQWJzZW5rdW5nIGRlciBuZXVlbiBJbmZla3Rpb25lbiBzZWl0IGRlbSAyMS4wMy4yMDIwIHdhciBzZWhyIHdpY2h0aWcsIGRlbm4gYW5zb25zdGVuIHfDpHJlbiBkaWUgSW5mZWt0aW9uc3phaGxlbiBpbiBEZXV0c2NobGFuZCBzY2hvbiBhbSAzMC4wMy4yMDIwIG1laHIgYWxzIGRyZWltYWwgc28gaG9jaCwgYWxzIHdlbm4ga2VpbmUgQWJzZW5rdW5nIGRlcyB0w6RnbGljaGVuIHByb3plbnR1YWxlbiBadXdhY2hzZXMgZXJyZWljaHQgd29yZGVuIHfDpHJlLiBEaWUgZm9sZ2VuZGUgR3JhZmlrIHplaWd0IGRpZSB0YXRzw6RjaGxpY2hlIEVudHdpY2tsdW5nIChoZWxsYmxhdWUgQmFsa2VuKSBkZXIgRmFsbHphaGxlbiBpbiBEZXV0c2NobGFuZC4gRGllIHJvdGUgTGluaWUgc2ltdWxpZXJ0IGRpZSBGYWxsemFobGVuLCBkaWUgc2ljaCBlcmdlYmVuIGjDpHR0ZW4sIHdlbm4gc2ljaCBkZXIgdMOkZ2xpY2hlIEFuc3RpZWcgdm9uIDI1LTM1JSwgd2llIGVyIHZvbSAxNC4wMy4yMDIwIC0gMjAuMDMuMjAyMCBzdGF0dGdlZnVuZGVuIGhhdCwgZm9ydGdlc2V0enQgaMOkdHRlLiBBbSAzMC4wMy4yMDIwIHfDpHJlbiBkZW1uYWNoIHNjaG9uIGByIHJlZjEwYCBpbmZpemllcnRlIGF1ZmdldHJldGVuLiBUYXRzw6RjaGxpY2ggd3VyZGVuIGFiZXIgYXVmZ3J1bmQgZGllc2VyIEFic2Vua3VuZyBudXIgYHIgcmVmMTFgIEbDpGxsZSByZWdpc3RyaWVydC4NCg0KYGBge3IgZWNobz1GQUxTRX0NCmcxMw0KYGBgDQoNCg0KDQpgYGB7ciBpbmNsdWRlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KIyBXZW5uIFNpZSBkaWVzZXMgTm90ZWJvb2sgc2VsYmVyIGtvbXBpbGllcmVuIG3DtmNodGVuLCBtw7xzc2VuIFNpZSBkaWVzIGluIHp3ZWkgU2Nocml0dGVuIHR1bjoNCiMgU2Nocml0dCAxOiBTZXR6ZW4gU2llIElocmVuIEN1cnNvciBhdWYgIiMgRGVyIENvZGUiIHVuZCBrbGlja2VuIFNpZSBhdWYgIlJ1biBhbGwgY29kZSBjaHVua3MgYmVsb3ciLg0KIyBXZW5uIGRpZXMgZXJsZWRpZ3QgaXN0LCBmb2xnZW4gU2llIFNjaHJpdHQgMi4NCiMgU2Nocml0dCAyOiBTZXR6ZW4gU2llIElocmVuIEN1cnNvciBhdWYgIiMgRGVyIENvZGUiIHVuZCBrbGlja2VuIFNpZSBhdWYgIlJ1biBhbGwgY29kZSBjaHVua3MgYWJvdmUiLiANCmBgYA0KDQoNCiMgRGVyIENvZGUNCg0KSW4gZGllc2VtIEFic2Nobml0dCB6ZWlnZW4gd2lyIElobmVuLCB3aWUgd2lyIGRpZSBEYXRlbiBhdWZiZXJlaXRldCBoYWJlbiwgdW0gZGllIG9iZW4gZ2V6ZWlndGVuIEdyYWZpa2VuIHp1IGVyemV1Z2VuLiANCg0KIyMjIFBha2V0ZSB1bmQgRGF0ZW4NCg0KRsO8ciBkaWVzZXMgUHJvamVrdCBiZW7DtnRpZ2VuIHdpciBkaWUgUGFrZXRlIGB0aWR5dmVyc2VgIHVuZCBgbHVicmlkYXRlYCBzb3dpZSBgc2NhbGVzYCB1bmQgYFJDb2xvckJyZXdlcmAuIERpZXNlIG3DvHNzZW4genV2b3IgaW5zdGFsbGllcnQgd29yZGVuIHNlaW4uIA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPVRSVUV9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShzY2FsZXMpDQpsaWJyYXJ5KFJDb2xvckJyZXdlcikNCmxpYnJhcnkoY291bnRyeWNvZGUpDQpgYGANCg0KDQoNCg0KDQpKZXR6dCBsYWRlbiB3aXIgZGVuIERhdGVuc2F0eiAoaGVydW50ZXJnZWxhZGVuIHZvbiBbZGllc2VtIEthZ2dsZSBMaW5rXShodHRwczovL3d3dy5rYWdnbGUuY29tL3N1ZGFsYWlyYWprdW1hci9ub3ZlbC1jb3JvbmEtdmlydXMtMjAxOS1kYXRhc2V0KSkgbWl0IGRlciBGdW5rdGlvbiBgcmVhZF9jc3YoKWA6DQoNCmBgYHtyfQ0KZGF0YSA8LSByZWFkX2NzdigiZGF0YS9jb3ZpZF8xOV9kYXRhLmNzdiIpDQpgYGANCg0KIyMjIERhdGVuYmVyZWluaWd1bmcNCg0KSmV0enQgw6RuZGVybiB3aXIgZGFzIEZvcm1hdCBkZXIgVmFyaWFibGUgYE9ic2VydmF0aW9uRGF0ZWAgaW4gZWluZSBnw7xsdGlnZSBGb3JtIG1pdHRlbHMgYGx1YnJpZGF0ZTo6bWR5KClgIHVuZCBzcGVpY2hlcm4gZGllc2UgaW4gZGVyIG5ldWVuIFZhcmlhYmxlIGBEYXR1bWAgYWIgbWl0dGVscyBGdW5rdGlvbiBgZHBseXI6Om11dGF0ZSgpYC4gQW5zY2hsaWXDn2VuZCBncnVwcGllcmVuIHdpciBkaWUgRGF0ZW4gbmFjaCBgRGF0dW1gIHVuZCBgQ291bnRyeS9SZWdpb25gIHVuZCBzdW1taWVyZW4gZGllIGJlc3TDpHRpZ3RlbiBGw6RsbGUgKGBDb25maXJtZWRgKSBpbm5lcmhhbGIgamVkZXIgR3J1cHBlIG1pdGhpbGZlIGRlciBGdW5rdGlvbiBgc3VtbWFyaXplKClgLiBEYWR1cmNoIGVyaGFsdGVuIHdpciBkaWUgU3VtbWVuIGFsbGVyIEbDpGxsZSBpbm5lcmhhbGIgZWluZXMgTGFuZGVzIHVuZCBUYWdlcy4gRGFzIG1hY2hlbiB3aXIgaGF1cHRzw6RjaGxpY2ggZGVzd2VnZW4sIHdlaWwgYmVpc3BpZWxzd2Vpc2UgYWxsZSBQcm92aW56ZW4gQ2hpbmFzIG9kZXIgYWxsZSBTdGFhdGVuIGRlciBVU0EgYWxzIEVpbnplbGVpbnRyw6RnZSB2b3JoYW5kZW4gc2luZCwgd2lyIGFiZXIgZGllIEZhbGx6YWhsZW4gZsO8ciBkYXMgZ2FuemUgTGFuZCBiZXRyYWNodGVuIHdvbGxlbi4gQW5zY2hsaWXDn2VuZCBzb3J0aWVyZW4gd2lyIG5hY2ggZGVyIFZhcmlhYmxlIGBEYXR1bWAgdW5kIGBCZXN0w6R0aWd0ZSBGw6RsbGVgLCB1bSB6dSBzZWhlbiwgd2VsY2hlcyBkYXMgYWt0dWVsbHN0ZSBEYXR1bSB1bnNlcmVzIERhdGVuc2F0emVzIGlzdCB1bmQgaW4gd2VsY2hlbiBMw6RuZGVybiBkaWUgaMO2Y2hzdGVuIEZhbGx6YWhsZW4gcmVnaXN0cmllcnQgd3VyZGVuOg0KDQpgYGB7cn0NCmRhdGEgPC0gZGF0YSAlPiUgDQogIG11dGF0ZShEYXR1bSA9IG1keShPYnNlcnZhdGlvbkRhdGUpKSAlPiUgDQogIGdyb3VwX2J5KERhdHVtLCBgQ291bnRyeS9SZWdpb25gKSAlPiUgDQogIHN1bW1hcml6ZShgQmVzdMOkdGlndGUgRsOkbGxlYCA9IHN1bShDb25maXJtZWQpLA0KICAgICAgICAgICAgYFRvZGVzZsOkbGxlYCA9IHN1bShEZWF0aHMpLA0KICAgICAgICAgICAgYEdlbmVzdW5nZW5gID0gc3VtKFJlY292ZXJlZCkpICU+JSANCiAgYXJyYW5nZShkZXNjKERhdHVtKSwgZGVzYyhgQmVzdMOkdGlndGUgRsOkbGxlYCkpDQpkYXRhDQpgYGANCg0KYGBge3IgaW5jbHVkZT1GQUxTRX0NCmRhdHVtX2JlYXJiZWl0ZXQgPC0gc3RyZnRpbWUodG9kYXkoKSwgIiVkLiVtLiVZIikNCnN0YW5kX2RhdGVuc2F0eiA8LSBzdHJmdGltZShtYXgoZGF0YSREYXR1bSksICIlZC4lbS4lWSIpDQpgYGANCg0KU3DDpHRlciBtw7ZjaHRlbiB3aXIgZGVuIFZlcmxhdWYgaW4gQ2hpbmEgbWl0IGdhbnogRXVyb3BhIHZlcmdsZWljaGVuLiBIaWVyZsO8ciBiZW7DtnRpZ2VuIHdpciBhbGxlcmRpbmdzIGVpbmUgTGlzdGUgZGVyIGV1cm9ww6Rpc2NoZW4gTMOkbmRlciwgd2VubiB3aXIgZGllc2UgbmljaHQgbWFudWVsbCB6dXdlaXNlbiB3b2xsZW4sIGRlbm4gZGllIEtvbnRpbmVudHp1Z2Vow7ZyaWdrZWl0IGlzdCBuaWNodCBpbSBEYXRlbnNhdHogdm9yaGFuZGVuLiBIaWVyYmVpIGhpbGZ0IHVucyBkYXMgUGFrZXQgYGNvdW50cnljb2RlYCwgd2VsY2hlcyBlaW5lIExpc3RlIGFsbGVyIEzDpG5kZXIgZGVyIEVyZGUgdW5kIGRpZSBkYXp1Z2Vow7ZyaWdlbiBMw6RuZGVyY29kZXMgc293aWUgS29udGluZW50ZSBiZWluaGFsdGV0LiBNaXQgZGVyIEZ1bmt0aW9uIGBjb3VudHJ5Y29kZSgpYCBlcnN0ZWxsZW4gd2lyIGVpbmUgbmV1ZSBWYXJpYWJsZSBuYW1lbnMgYGNvbnRpbmVudGAuIEdsZWljaHplaXRpZyBrw7ZubmVuIHdpciBkaWUgQ2hhbmNlIG51dHplbiwgdW0gbWl0IGRlciBgY291bnRyeWNvZGVgIEZ1bmt0aW9uIGRpZSBlbmdsaXNjaGVuIEzDpG5kZXJuYW1lbiBpbiBkZXV0c2NoZSB6dSDDvGJlcmbDvGhyZW4uIERpZXNlIFZhcmlhYmxlIG5lbm5lbiB3aXIgZGFubiBgU3RhYXRgOg0KDQpgYGB7cn0NCmxpYnJhcnkoY291bnRyeWNvZGUpDQojZGF0YTMNCmRhdGEgPC0gZGF0YSAlPiUgDQogIG11dGF0ZShjb250aW5lbnQgPSBjb3VudHJ5Y29kZShgQ291bnRyeS9SZWdpb25gLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JpZ2luID0gImNvdW50cnkubmFtZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXN0aW5hdGlvbiA9ICJjb250aW5lbnQiKSwNCiAgICAgICAgIFN0YWF0ID0gY291bnRyeWNvZGUoYENvdW50cnkvUmVnaW9uYCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JpZ2luID0gImNvdW50cnkubmFtZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc3RpbmF0aW9uID0gImNvdW50cnkubmFtZS5kZSIpKQ0KYGBgDQoNCk51biBlcnN0ZWxsZW4gd2lyIGVpbmUgd2VpdGVyZSBWYXJpYWJsZSwgZGllIHdpciBgUmVnaW9uYCBuZW5uZW4uIEluIGRpZXNlciBWYXJpYWJsZSB3ZXJkZW4gd2lyIGRpZSBSZWdpb25lbiBgRXVyb3BhYCwgYENoaW5hYCwgYFZlcmVpbmlndGUgU3RhYXRlbmAgdW5kIGBTb25zdGlnZWAgZGVmaW5pZXJlbi4gRGllcyB0dW4gd2lyIG1pdGhpbGZlIGRlciBgYmFzZTo6aWZlbHNlKClgIEZ1bmt0aW9uIGlubmVyaGFsYiBkZXIgRnVua3Rpb24gYGRwbHlyOjptdXRhdGUoKWAuDQoNCkF1c2dlc2NocmllYmVuIGJld2lya3QgZGVyIGZvbGdlbmRlIENvZGU6IA0KV2VubiBkaWUgVmFyaWFibGUgYGNvbnRpbmVudGAgZ2xlaWNoIGBFdXJvcGVgaXN0LCBzb2xsIGRpZSBWYXJpYWJsZSBgUmVnaW9uYCBhdWYgYEV1cm9wZWAgZ2VzZXR6dCB3ZXJkZW47IGFuc29uc3RlbiBhdWYgYENoaW5hYCwgd2VubiBkaWUgVmFyaWFibGUgYENvdW50cnkvUmVnaW9uYCBnbGVpY2ggYE1haW5sYW5kIENoaW5hYCBpc3Q7IGFuc29uc3RlbiBhdWYgYFVTQWAsIHdlbm4gZGllIFZhcmlhYmxlIGBDb3VudHJ5L1JlZ2lvbmAgZ2xlaWNoIGBVU2AgaXN0OyBhbnNvbnN0ZW4gc29sbCBkaWUgVmFyaWFibGUgYFJlZ2lvbmAgYXVmIGBTb25zdGlnZWAgZ2VzZXR6dCB3ZXJkZW4uDQoNClNvbWl0IGvDtm5uZW4gd2lyIGFuaGFuZCB6d2VpZXIgVmFyaWFibGVuIChgY29udGluZW50YCB1bmQgYENvdW50cnkvUmVnaW9uYCkgZWluZSBHcnVwcGllcnVuZyBpbiBkaWUgUmVnaW9uZW4gYEV1cm9wYWAsIGBDaGluYWAsIGBWZXJlaW5pZ3RlIFN0YWF0ZW5gIHVuZCBgU29uc3RpZ2VgIHZvcm5laG1lbjoNCg0KYGBge3J9DQojZGF0YTQNCmRhdGEgPC0gZGF0YSAlPiUgDQogIG11dGF0ZShSZWdpb24gPSBpZmVsc2UoY29udGluZW50ID09ICJFdXJvcGUiLCAiRXVyb3BhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGBDb3VudHJ5L1JlZ2lvbmAgPT0gIk1haW5sYW5kIENoaW5hIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDaGluYSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoYENvdW50cnkvUmVnaW9uYCA9PSAiVVMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJVU0EiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTb25zdGlnZSIpKSkpDQpgYGANCg0KTnVuIGvDtm5uZW4gd2lyIHVuc2VyZW4gRGF0ZW5zYXR6IGVpbm1hbCBhbnNlaGVuLCB1bSB6dSBwcsO8ZmVuLCBvYiBkaWUgbmV1ZSBWYXJpYWJsZW4gYFJlZ2lvbmAsIGBjb250aW5lbnRgIHVuZCBgU3RhYXRgIGtvcnJla3QgZXJzdGVsbHQgd3VyZGVuOg0KDQpgYGB7cn0NCmFycmFuZ2UoZGF0YSwgZGVzYyhEYXR1bSksIGRlc2MoYEJlc3TDpHRpZ3RlIEbDpGxsZWApKQ0KYGBgDQoNCkFscyBuw6RjaHN0ZXMgZXJzdGVsbGVuIHdpciBkaWUgbmV1ZSBWYXJpYWJsZSBgQWt1dGUgRXJrcmFua3VuZ2VuYCwgZGllIHNpY2ggYXVzIGRlbiBhbmRlcmVuIFZhcmlhYmxlbiBmb2xnZW5kZXJtYcOfZW4gZXJyZWNobmVuIGzDpHNzdDoNCg0KYGBge3J9DQpkYXRhIDwtIG11dGF0ZShkYXRhLCBgQWt1dGUgRXJrcmFua3VuZ2VuYCA9IGBCZXN0w6R0aWd0ZSBGw6RsbGVgIC0gYFRvZGVzZsOkbGxlYCAtIGBHZW5lc3VuZ2VuYCkNCmRhdGENCmBgYA0KDQogIA0KDQpOdW4gaXN0IGRpZSBHcm9iYXJiZWl0IGFiZ2VzY2hsb3NzZW4gdW5kIHdpciBrw7ZubmVuIGRpZSBEYXRlbiBqZXR6dCB3ZWl0ZXJ2ZXJ3ZW5kZW4sIHVtIGRpZSBHcmFmaWtlbiB6dSBlcnpldWdlbi4NCg0KDQoNCg0KDQoNCg0KIyMjIFdlbHR3ZWl0DQoNCkbDvHIgdW5zZXJlIGVyc3RlIEdyYWZpayBtw7xzc2VuIHdpciB6dWVyc3QgZGVuIERhdGVuc2F0eiBuYWNoIGRlbSBha3R1ZWxsc3RlbiBEYXR1bSB1bmQgZGVyIEFuemFobCBiZXN0w6R0aWd0ZXIgRsOkbGxlIHZvbiBtaW5kZXN0ZW5zIDUwMDAwIGZpbHRlcm4uIEFuc2NobGllw59lbmQgw7xiZXJmw7xocmVuIHdpciBtaXQgYHBpdm90X2xvbmdlcigpYCBkaWUgVGFiZWxsZSBpbiBkaWUgbGFuZ2UgRm9ybSB1bmQgZXJzdGVsbGVuIGFscyBGYWxsa2F0ZWdvcmllIGRpZSBWYXJpYWJsZSBgS2F0ZWdvcmllYCB1bmQgc2FtbWVsbiBkaWUgRmFsbHphaGxlbiBpbiBkZXIgVmFyaWFibGUgYEbDpGxsZWAuIE51biBzaWVodCBkZXIgdmVyw6RuZGVydGUgRGF0ZW5zYXR6IHNvIGF1czoNCg0KYGBge3J9DQpMYWVuZGVyXzUwMDAwIDwtIGRhdGEgJT4lIA0KICBmaWx0ZXIoRGF0dW0gPT0gc3RyZnRpbWUobWF4KGRhdGEkRGF0dW0pKSwNCiAgICAgICAgIGBCZXN0w6R0aWd0ZSBGw6RsbGVgID49IDUwMDAwKSAlPiUgIA0KICBwaXZvdF9sb25nZXIoY29scyA9IGMoYEFrdXRlIEVya3Jhbmt1bmdlbmAsIA0KICAgICAgICAgICAgICAgICAgICAgICAgYFRvZGVzZsOkbGxlYCwgDQogICAgICAgICAgICAgICAgICAgICAgICBgR2VuZXN1bmdlbmApLCANCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIkthdGVnb3JpZSIsIA0KICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gIkbDpGxsZSIpDQoNCmhlYWQoTGFlbmRlcl81MDAwMCkNCmBgYA0KDQpKZXR6dCBrw7ZubmVuIHdpciBtaXQgYGdncGxvdCgpYCB1bmQgYGdlb21fY29sKClgIGVpbiBCYWxrZW5kaWFncmFtbSBlcnpldWdlbi4gWnVlcnN0IGRlZmluaWVyZW4gd2lyIGRpZSBYLUFjaHNlIGFscyBTdGFhdCB1bmQgZGllIFktQWNoc2UgYWxzIEFuemFobCBkZXIgRsOkbGxlLCBkYW5hY2ggdGF1c2NoZW4gd2lyIGRpZSBiZWlkZW4gQWNoc2VuIG1pdCBkZW0gQmVmZWhsIGBjb29yZF9mbGlwKClgLCBzbyBkYXNzIGRpZSBZLUFjaHNlIHp1ciBYLUFjaHNlIHdpcmQgdW5kIHVtZ2VrZWhydC4gTnVuIG3DvHNzZW4gd2lyIGFscyBsZXR6dGVuIFNjaHJpdHQgZGllIEJhbGtlbiBuYWNoIGRlciBHZXNhbXR6YWhsIGJlc3TDpHRpZ3RlciBGw6RsbGUgc29ydGllcmVuLiBEYSB3aXIgZGllIFZhcmlhYmxlIGBCZXN0w6R0aWd0ZSBGw6RsbGVgIG5pY2h0IGluIGRpZSBsYW5nZSBGb3JtIMO8YmVyZsO8aHJ0IGhhYmVuLCBzdGVodCB1bnMgZGllc2UgVmFyaWFibGUgbm9jaCB6dXIgVmVyZsO8Z3VuZyB1bmQgd2lyIGvDtm5uZW4gc29taXQgZGFzIEJhbGtlbmRpYWdyYW1tIG1pdCBgcmVvcmRlcigpYCBuYWNoIGRlciBWYXJpYWJsZSBgQmVzdMOkdGlndGUgRsOkbGxlYCBzb3J0aWVyZW4uDQoNCmBgYHtyfQ0KZzEgPC0gZ2dwbG90KGRhdGEgPSBMYWVuZGVyXzUwMDAwKSArDQogIGdlb21fY29sKG1hcHBpbmcgPSBhZXMoeCA9IHJlb3JkZXIoU3RhYXQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBCZXN0w6R0aWd0ZSBGw6RsbGVgKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGBGw6RsbGVgLCANCiAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gS2F0ZWdvcmllKSkgKw0KICBjb29yZF9mbGlwKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuOCwgMC4zKSwNCiAgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD1hbHBoYSgwLjQpKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IG51bWJlcikgKw0KICBsYWJzKHggPSAiU3RhYXQiLCANCiAgICAgICB5ID0gIkbDpGxsZSIsIA0KICAgICAgIHRpdGxlID0gcGFzdGUoIkFuemFobCBiZXN0w6R0aWd0ZXIgRsOkbGxlIGplIFN0YWF0LCBTdGFuZCAiLCANCiAgICAgICAgICAgICAgICAgICAgIHN0YW5kX2RhdGVuc2F0eiwNCiAgICAgICAgICAgICAgICAgICAgIHNlcD0iIikpDQpnMQ0KYGBgDQoNCkRpZSBmb2xnZW5kZSBHcmFmaWsgenUgZXJzdGVsbGVuIGlzdCBlaW4gd2VuaWcga29tcGxpemllcnRlci4gWnVlcnN0IG3DvHNzZW4gd2lyIGFsbGUgRsOkbGxlIGRlcyBPcmlnaW5hbGRhdGVuc2F0emVzIG5hY2ggZGVuIFplaWxlbiBmaWx0ZXJuLCBpbiBkZW5lbiBkaWUgYEJlc3TDpHRpZ3RlIEbDpGxsZWAgZ3LDtsOfZXIgb2RlciBnbGVpY2ggMTAwIHNpbmQuIERhbmFjaCBncnVwcGllcmVuIHdpciBuYWNoIGBTdGFhdGAgdW5kIGJlcmVjaG5lbiBkYXMgTWluaW11bSBkZXIgYmVzdMOkdGlndGVuIEbDpGxsZSBtaXQgYHN1bW1hcml6ZSgpYC4gU29taXQgZXJoYWx0ZW4gd2lyIGbDvHIgamVkZW4gU3RhYXQgZ2VuYXUgZGllIFplaWxlLCBpbiBkZXIgenVtIGVyc3RlbiBNYWwgZGllIEdyZW56ZSB2b24gMTAwIEbDpGxsZW4gw7xiZXJzY2hyaXR0ZW4gd29yZGVuIGlzdC4gRGVuIFdlcnQgdm9uIGBUYWdlIHNlaXQgZGVtIDEwMC4gRmFsbGAgc2V0emVuIHdpciBmw7xyIGRpZXNlbiBUYWcgYXVmIDAgbWl0IGBtdXRhdGUoKWAuDQoNCmBgYHtyfQ0Kd2VsdHdlaXRfbG9nXzEgPC0gZGF0YSAlPiUNCiAgYXJyYW5nZShEYXR1bSkgJT4lIA0KICBmaWx0ZXIoYEJlc3TDpHRpZ3RlIEbDpGxsZWAgPj0xMDApICU+JSANCiAgZ3JvdXBfYnkoU3RhYXQpICU+JSANCiAgc3VtbWFyaXplKGBCZXN0w6R0aWd0ZSBGw6RsbGVgID0gbWluKGBCZXN0w6R0aWd0ZSBGw6RsbGVgKSkgJT4lIA0KICBtdXRhdGUoYFRhZ2Ugc2VpdCBkZW0gMTAwLiBGYWxsYCA9IDApDQpgYGANCg0KSW0gbsOkY2hzdGVuIFNjaHJpdHQgZsO8Z2VuIHdpciB1bnNlcmVuIHNvZWJlbiBlcnN0ZWxsdGVuIERhdGVuc2F0eiB6dXNhbW1lbiBtaXQgZGVtIFVyc3BydW5nc2RhdGVuc2F0eiBtaXR0ZWxzIGRlciBGdW5rdGlvbiBgZnVsbF9qb2luKClgIHVuZCBuZW5uZW4gZGFzIG5ldWUgT2JqZWt0IGB3ZWx0d2VpdF9sb2dfMmAuIE51biBmaWx0ZXJuIHdpciBlcm5ldXQgbmFjaCBkZW4gWmVpbGVuLCBpbiBkZW5lbiBtZWhyIG9kZXIgZ2VuYXUgMTAwIGBCZXN0w6R0aWd0ZSBGw6RsbGVgIGF1ZmdldHJldGVuIHNpbmQsIHVuZCBoZWJlbiBkaWUgdm9yaGVyaWdlIEdydXBwaWVydW5nIGF1ZiBtaXQgYHVuZ3JvdXAoKWAgKGRpZXNlciBTY2hyaXR0IGlzdCBub3R3ZW5kaWcsIGRhbWl0IGBjdW1zdW0oKWAgc3DDpHRlciBrb3JyZWt0IGZ1bmt0aW9uaWVydCkuIEpldHp0IHNvcnRpZXJlbiB3aXIgbmFjaCBkZW0gRGF0dW0gdW5kIHNldHplbiBhbGxlIGBOQWBzIGRlciBWYXJpYWJsZSBgVGFnZSBzZWl0IGRlbSAxMDAuIEZhbGxgIGF1ZiAxLiBKZXR6dCBncnVwcGllcmVuIHdpciBuYWNoIGBTdGFhdGAgdW5kIG1vZGlmaXppZXJlbiBkaWUgVmFyaWFibGUgYFRhZ2Ugc2VpdCBkZW0gMTAwLiBGYWxsYCBhbHMga3VtdWxhdGl2ZSBTdW1tZSB2b24gc2ljaCBzZWxic3QuIEFuc2NobGllw59lbmQgc29ydGllcmVuIHdpciBuYWNoIGBTdGFhdGAgdW5kIGBEYXR1bWAuDQoNCmBgYHtyfQ0Kd2VsdHdlaXRfbG9nXzIgPC0gZnVsbF9qb2luKGRhdGEsd2VsdHdlaXRfbG9nXzEpICU+JSANCiAgZmlsdGVyKGBCZXN0w6R0aWd0ZSBGw6RsbGVgID49IDEwMCkgJT4lIA0KICB1bmdyb3VwKHdlbHR3ZWl0X2xvZ18yKSAlPiUgDQogIGFycmFuZ2UoRGF0dW0pICU+JSAgDQogIG11dGF0ZShgVGFnZSBzZWl0IGRlbSAxMDAuIEZhbGxgID0gaWZlbHNlKGlzLm5hKGBUYWdlIHNlaXQgZGVtIDEwMC4gRmFsbGApID09IFQsIDEsIDApKSAlPiUgDQogIGdyb3VwX2J5KFN0YWF0KSAlPiUgDQogIG11dGF0ZShgVGFnZSBzZWl0IGRlbSAxMDAuIEZhbGxgID0gY3Vtc3VtKGBUYWdlIHNlaXQgZGVtIDEwMC4gRmFsbGApKSAlPiUgDQogIGFycmFuZ2UoU3RhYXQsIERhdHVtKQ0KYGBgDQpBbHMgbsOkY2hzdGVzIHJlY2huZW4gd2lyIHp1bSBiZXNzZXJlbiBWZXJnbGVpY2ggZGllIEZhbGx6YWhsZW4gYXVzLCBkaWUgc2ljaCBiZWkgZWluZXIgVmVyZG9wcGVsdW5nc3plaXQgdm9uIDIsIDcsIDE0IHVuZCA2MCBUYWdlbiBlcmdlYmVuIHfDvHJkZW4uIEhpZXJmw7xyIGVyc3RlbGxlbiB3aXIgZWluZW4gbmV1ZW4gRGF0ZW5zYXR6IGluIGRlbSBkaWUgVmFyaWFibGUgYFRhZ2Ugc2VpdCBkZW0gMTAwLiBGYWxsYCB2b24gMS02MCByZWljaHQuIE51biBlcnN0ZWxsZW4gd2lyIHZpZXIgbmV1ZSBWYXJpYWJsZW4gKGAyIFRhZ2VgLCBgNyBUYWdlYCwgdXN3LikgdW5kIGVycmVjaG5lbiBtaXQgZGVyIGVudHNwcmVjaGVuZGVuIEZvcm1lbCBkaWUgRmFsbHphaGxlbiBhdXMsIGRpZSBzaWNoIGJlaSBkZXIgZW50c3ByZWNoZW5kZW4gVmVyZG9wcGVsdW5nc3plaXQgZXJnZWJlbiB3w7xyZGVuLiBOdW4gw7xiZXJmw7xocmVuIHdpciBkaWVzZW4gRGF0ZW5zYXR6IGluIGRpZSBsYW5nZSBGb3JtLiBadW0gU2NobHVzcyBmaWx0ZXJuIHdpciBub2NoLCB1bSBkaWUgZ2xlaWNoIGltIFBsb3QgZGFyZ2VzdGVsbHRlbiBMaW5pZW4gbmljaHQgenUgd2VpdCBhdXMgZGVtIEdyYWZpa2JlcmVpY2ggaGVyYXVzcmFnZW4genUgbGFzc2VuIChudXIgZWluIFNjaMO2bmhlaXRzZmFrdG9yKS4NCmBgYHtyfQ0KVkRaIDwtIHRpYmJsZShgVGFnZSBzZWl0IGRlbSAxMDAuIEZhbGxgID0gc2VxKDE6NjApKSAlPiUgDQogIG11dGF0ZShgMiBUYWdlYCA9IDEwMCooMl4oMS8yKSleYFRhZ2Ugc2VpdCBkZW0gMTAwLiBGYWxsYCwNCiAgICAgICAgIGA3IFRhZ2VgID0gMTAwKigyXigxLzcpKV5gVGFnZSBzZWl0IGRlbSAxMDAuIEZhbGxgLA0KICAgICAgICAgYDE0IFRhZ2VgID0gMTAwKigyXigxLzE0KSleYFRhZ2Ugc2VpdCBkZW0gMTAwLiBGYWxsYCwNCiAgICAgICAgIGA2MCBUYWdlYCA9IDEwMCooMl4oMS82MCkpXmBUYWdlIHNlaXQgZGVtIDEwMC4gRmFsbGAsKSAlPiUgDQogIHBpdm90X2xvbmdlcihjb2xzID0gYygiMiBUYWdlIiwgIjcgVGFnZSIsICIxNCBUYWdlIiwgIjYwIFRhZ2UiKSwgbmFtZXNfdG8gPSAiVmVyZG9wcGVsdW5nc3plaXQiLCB2YWx1ZXNfdG8gPSAiRsOkbGxlIikgJT4lIA0KICBtdXRhdGUoVmVyZG9wcGVsdW5nc3plaXQgPSBhc19mYWN0b3IoVmVyZG9wcGVsdW5nc3plaXQpKSAlPiUgDQogIGZpbHRlcihgRsOkbGxlYCA8PSA0MDAwMDAwICYgYFRhZ2Ugc2VpdCBkZW0gMTAwLiBGYWxsYCA8PSA1MCkNCmBgYA0KDQpKZXR6dCBrw7ZubmVuIHdpciBgQmVzdMOkdGlndGUgRsOkbGxlYCBnZWdlbiBgVGFnZSBzZWl0IGRlbSAxMDAuIEZhbGxgIHBsb3R0ZW4gbWl0IGBnZ3Bsb3QoKWAuIERhZHVyY2gsIGRhc3Mgd2lyIGRpZSBPcHRpb24gYHNjYWxlX3lfY29udGludW91cyh0cmFucz0ibG9nMTAiKWAgZ2V3w6RobHQgaGFiZW4sIHdpcmQgZGllIFktQWNoc2UgYWxzIExvZy1Ta2FsYSBkYXJnZXN0ZWxsdC4gQXVmIGRpZXNlIFdlaXNlIGlzdCBlcyBlaW5mYWNoZXIsIGRhcyBXYWNoc3R1bSBkZXIgYmVzdMOkdGlndGVuIEbDpGxsZSB6d2lzY2hlbiB2ZXJzY2hpZWRlbmVuIFN0YWF0ZW4genUgdmVyZ2xlaWNoZW4uIFp1c8OkdHpsaWNoIHBsb3R0ZW4gd2lyIGRpZSBWZXJnbGVpY2hzbGluaWVuIGRlciB2ZXJzY2hpZWRlbmVuIFZlcmRvcHBlbHVuZ3N6ZWl0ZW4gYXVzIGRlbSBlYmVuIGVyc3RlbGx0ZW4gRGF0ZW5zYXR6IGBWRFpgIHVuZCBnZWJlbiBhbHMgw4RzdGhldGlrIGBsaW5ldHlwZWAgYW4uDQoNCmBgYHtyfQ0KbG9nX2Nhc2VzIDwtIGZpbHRlcih3ZWx0d2VpdF9sb2dfMiwgU3RhYXQgJWluJSAoYygiQ2hpbmEiLCAiRGV1dHNjaGxhbmQiLCAiU3BhbmllbiIsICJGcmFua3JlaWNoIiwgIkl0YWxpZW4iLCAiVmVyZWluaWd0ZSBTdGFhdGVuIiwgIklyYW4iLCAiS29yZWEsIFJlcHVibGlrIHZvbiIpKSkNCg0KZzIgPC0gZ2dwbG90KGRhdGEgPSBsb2dfY2FzZXMpICsNCiAgZ2VvbV9saW5lKG1hcHBpbmcgPSBhZXMoeCA9IGBUYWdlIHNlaXQgZGVtIDEwMC4gRmFsbGAsIHkgPSBgQmVzdMOkdGlndGUgRsOkbGxlYCwgY29sb3IgPSBTdGFhdCksIHNpemUgPSAxLjUpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBWRFosIG1hcHBpbmcgPSBhZXMoeCA9IGBUYWdlIHNlaXQgZGVtIDEwMC4gRmFsbGAsIHkgPSBgRsOkbGxlYCwgbGluZXR5cGUgPSBWZXJkb3BwZWx1bmdzemVpdCksIGNvbG9yID0gInJveWFsYmx1ZTQiKSArDQogIHNjYWxlX3lfY29udGludW91cyh0cmFucz0nbG9nMTAnLCBsYWJlbHMgPSBudW1iZXIpICsNCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJCZXN0w6R0aWd0ZSBGw6RsbGUgKExvZykgaW4gQWJoLiBkZXIgVGFnZSBzZWl0IGQuIDEwMC4gRmFsbCwgU3RhbmQgIiwgDQogICAgICAgICAgICAgICAgICAgICBzdGFuZF9kYXRlbnNhdHosDQogICAgICAgICAgICAgICAgICAgICBzZXA9IiIpKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC44NSwgMC41KSwNCiAgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD1hbHBoYSgwLjQpKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZT0iU2V0MyIpICsNCiAgZ3VpZGVzKGxpbmV0eXBlID0gZ3VpZGVfbGVnZW5kKG9yZGVyID0gMSksIGNvbG9yID0gZ3VpZGVfbGVnZW5kKG9yZGVyID0gMikpDQpnMg0KYGBgDQoNCiMjIyBDaGluYSwgRXVyb3BhIHVuZCBVU0ENCg0KSmV0enQgZ3J1cHBpZXJlbiB3aXIgdW5zZXJlbiBEYXRlbnNhdHogbmFjaCBgRGF0dW1gIHVuZCBgUmVnaW9uYCB1bmQgc3VtbWllcmVuIGRpZSBWYXJpYWJsZW4gYEJlc3TDpHRpZ3RlIEbDpGxsZWAsIGBUb2Rlc2bDpGxsZWAgdW5kIGBHZW5lc3VuZ2VuYCBhdWYgbWl0IGBzdW0oKWAsIHVtIGRpZSBTdW1tZW4gYWxsZXIgRsOkbGxlIGlubmVyaGFsYiBqZWRlbiBUYWdlcyB1bmQgaW5uZXJoYWxiIGplZGVyIFJlZ2lvbiB6dSBlcmhhbHRlbi4gQWxsZSBmZWhsZW5kZW4gV2VydGUgd2VyZGVuIGFuc2NobGllw59lbmQgbWl0IGBmaWx0ZXIoKWAgdW5kIGAhaXMubmEoKWAgaGVyYXVzZ2V3b3JmZW4uIE51biBncnVwcGllcmVuIHdpciBudXIgbmFjaCBgUmVnaW9uYCB1bmQgZXJzdGVsbGVuIG1pdCBgbXV0YXRlKClgIGRpZSBWYXJpYWJsZSBgWnV3YWNocyBiZXN0w6R0aWd0ZXIgRsOkbGxlIGplIFJlZ2lvbmAgbWl0IGRlciBgbGFnKClgIEZ1bmt0aW9uIHNvd2llIGRpZSBWYXJpYWJsZSBgQWt1dGUgRXJrcmFua3VuZ2VuIGplIFJlZ2lvbmA6DQoNCmBgYHtyfQ0KUmVnaW9uZW4gPC0gZGF0YSAlPiUgDQogIGdyb3VwX2J5KERhdHVtLCBSZWdpb24pICU+JSANCiAgc3VtbWFyaXplKGBCZXN0w6R0aWd0ZSBGw6RsbGUgamUgUmVnaW9uYCA9IHN1bShgQmVzdMOkdGlndGUgRsOkbGxlYCksDQogICAgICAgICAgICBgVG9kZXNmw6RsbGUgamUgUmVnaW9uYCA9IHN1bShgVG9kZXNmw6RsbGVgKSwNCiAgICAgICAgICAgIGBHZW5lc3VuZ2VuIGplIFJlZ2lvbmAgPSBzdW0oYEdlbmVzdW5nZW5gKSkgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKFJlZ2lvbikpICU+JSANCiAgZ3JvdXBfYnkoUmVnaW9uKSAlPiUgDQogIG11dGF0ZShgWnV3YWNocyBiZXN0w6R0aWd0ZXIgRsOkbGxlIGplIFJlZ2lvbmAgPSBgQmVzdMOkdGlndGUgRsOkbGxlIGplIFJlZ2lvbmAgLSBsYWcoYEJlc3TDpHRpZ3RlIEbDpGxsZSBqZSBSZWdpb25gKSwNCiAgICAgICAgIGBBa3V0ZSBFcmtyYW5rdW5nZW4gamUgUmVnaW9uYCA9IGBCZXN0w6R0aWd0ZSBGw6RsbGUgamUgUmVnaW9uYCAtIGBHZW5lc3VuZ2VuIGplIFJlZ2lvbmAgLSBgVG9kZXNmw6RsbGUgamUgUmVnaW9uYCkNCg0KaGVhZChhcnJhbmdlKFJlZ2lvbmVuLCBkZXNjKERhdHVtKSwgZGVzYyhgQmVzdMOkdGlndGUgRsOkbGxlIGplIFJlZ2lvbmApKSkNCmBgYA0KDQoNCg0KDQpOdW4ga8O2bm5lbiB3aXIgZGllIGJlc3TDpHRpZ3RlbiBGw6RsbGUgZsO8ciBDaGluYSwgRXVyb3BhLCBVUyB1bmQgYW5kZXJlIHBsb3R0ZW4gbWl0IGBnZ3Bsb3QoKWAuIEhpZXJiZWkgaXN0IGRpZSBYLUFjaHNlIGBEYXR1bWAgdW5kIGRpZSBZLUFjaHNlIGRpZSBTdW1tZSBkZXIgYmVzdMOkdGlndGVuIEbDpGxsZSBqZSBSZWdpb24gKGBCZXN0w6R0aWd0ZSBGw6RsbGUgamUgUmVnaW9uYCkuIEJlbWVya3VuZzogRGllIHNvZ2VuYW5udGVuICoqYmFja3RpY2tzKiogc2luZCBub3R3ZW5kaWcsIHdlbm4gVmFyaWFibGVubmFtZW4gU29uZGVyemVpY2hlbiAoaGllciBMZWVyemVpY2hlbiB1bmQgVW1sYXV0ZSBpbiBkZXIgVmFyaWFibGUgYEJlc3TDpHRpZ3RlIEbDpGxsZSBqZSBSZWdpb25gKSBhdWZ3ZWlzZW4gdW5kIGRlbm5vY2ggbm9ybWFsIHdlaXRlcnZlcndlbmRldCB3ZXJkZW4gc29sbGVuLg0KDQpgYGB7cn0NCmczYSA8LSBnZ3Bsb3QoZGF0YSA9IFJlZ2lvbmVuKSArDQogIGdlb21fbGluZShtYXBwaW5nID0gYWVzKHggPSBEYXR1bSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBgQmVzdMOkdGlndGUgRsOkbGxlIGplIFJlZ2lvbmAsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IFJlZ2lvbiksIA0KICAgICAgICAgICAgc2l6ZSA9IDEpICsNCiAgbGFicyh4ID0gIkRhdHVtIiwgDQogICAgICAgeSA9ICJCZXN0w6R0aWd0ZSBGw6RsbGUgamUgUmVnaW9uIiwNCiAgICAgICB0aXRsZSA9IHBhc3RlKCJCZXN0w6R0aWd0ZSBGw6RsbGUgamUgUmVnaW9uLCBTdGFuZCAiLA0KICAgICAgICAgICAgICAgICAgICAgc3RhbmRfZGF0ZW5zYXR6LA0KICAgICAgICAgICAgICAgICAgICAgc2VwPSIiKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gbnVtYmVyKSArDQogIHNjYWxlX3hfZGF0ZShkYXRlX2JyZWFrcyA9ICIyIHdlZWsiLCBkYXRlX2xhYmVscyA9ICIlZC4lbSIpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gYygwLjEzLCAwLjYpLA0KICAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPWFscGhhKDAuNCkpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCmczYQ0KYGBgDQoNCldlbm4gd2lyIGRpZSB3ZWl0ZXJlbiB6d2VpIFZhcmlhYmxlbiAoYFRvZGVzZsOkbGxlIGplIFJlZ2lvbmAgdW5kIGBHZW5lc3VuZ2VuIGplIFJlZ2lvbmApIHp1c8OkdHpsaWNoIGltIHNlbGJlbiBQbG90IGRhcnN0ZWxsZW4gd29sbGVuLCBtw7xzc2VuIHdpciB6dW7DpGNoc3QgZGVuIERhdGVuc2F0eiBpbiBkaWUgTGFuZ2UgRm9ybSDDvGJlcnRyYWdlbiBtaXQgYHRpZHlyOjpwaXZvdF9sb25nZXIoKWAuIEhpZXJiZWkgZXJ6ZXVnZW4gd2lyIHp3ZWkgbmV1ZSBWYXJpYWJsZW4sIGRpZSB3aXIgYEthdGVnb3JpZWAgdW5kIGBGw6RsbGVgIG5lbm5lbi4gRGllIFZhcmlhYmxlIGBLYXRlZ29yaWVgIGVudGjDpGx0IEluZm9ybWF0aW9uLCBvYiBlcyBzaWNoIHVtIGVpbmVuIGJlc3TDpHRpZ3RlbiBGYWxsLCBlaW5lbiBUb2Rlc2ZhbGwgb2RlciBlaW5lbiBnZWhlaWx0ZW4gRmFsbCBoYW5kZWx0LiBEaWUgVmFyaWFibGUgYEbDpGxsZWAgZW50aMOkbHQgZGllIFrDpGhsd2VydGUsIGRpZSB2b3JoZXIgdW50ZXIgZGVuIGRyZWkgenVzYW1tZW5nZWbDvGd0ZW4gVmFyaWFibGVuIHN0YW5kZW4uIA0KDQoNCg0KYGBge3J9DQpSZWdpb25lbl9sb25nIDwtIFJlZ2lvbmVuICU+JSANCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKGBCZXN0w6R0aWd0ZSBGw6RsbGUgamUgUmVnaW9uYCwNCiAgICAgICAgICAgICAgICAgICAgICAgIGBUb2Rlc2bDpGxsZSBqZSBSZWdpb25gLA0KICAgICAgICAgICAgICAgICAgICAgICAgYEdlbmVzdW5nZW4gamUgUmVnaW9uYCwNCiAgICAgICAgICAgICAgICAgICAgICAgIGBadXdhY2hzIGJlc3TDpHRpZ3RlciBGw6RsbGUgamUgUmVnaW9uYCwNCiAgICAgICAgICAgICAgICAgICAgICAgIGBBa3V0ZSBFcmtyYW5rdW5nZW4gamUgUmVnaW9uYCksDQogICAgICAgICAgICAgICBuYW1lc190byA9ICJLYXRlZ29yaWUiLA0KICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gIkbDpGxsZSIpDQpoZWFkKFJlZ2lvbmVuX2xvbmcpDQpgYGANCg0KQW5zY2hsaWXDn2VuZCBmw7xnZW4gd2lyIGRpZSBuZXVlIFZhcmlhYmxlIGBLYXRlZ29yaWVgIGFscyAqKmFlc3RoZXRpY3MqKiBpbiBgZ2dwbG90KClgIGhpbnp1IChoaWVyIGFscyBgbGluZXR5cGVgKS4gU29taXQgdmVyw6RuZGVydCBzaWNoIGRlciBMaW5pZW50eXAgaW4gQWJow6RuZ2lna2VpdCBkZXIgVmFyaWFibGUgYEthdGVnb3JpZWAuIEFscyBZLUFjaHNlIHfDpGhsZW4gd2lyIGRpZSBuZXUgZXJzdGVsbHRlIFZhcmlhYmxlIGBGw6RsbGVgLCBkaWUgZGllIGdlesOkaGx0ZW4gV2VydGUgYmVpbmhhbHRldC4NCkRhIGRpZSBvYmVuIHZlcndlbmRldGUgRnVua3Rpb24gYGNvdW50cnljb2RlKClgIG5pY2h0IGFsbGUgTMOkbmRlciB6dXdlaXNlbiBrb25udGUgdW5kIGBOQWBzIGVyemV1Z3QgaGF0LCBlbnRmZXJuZW4gd2lyIGRpZXNlIGltIHNlbGJlbiBTY2hyaXR0IG1pdCBgZHJvcF9uYSgpYCwgZGEgZGllc2Ugc29uc3QgYXVjaCBpbiBkZXIgR3JhZmlrIGFiZ2ViaWxkZXQgd2VyZGVuIHfDvHJkZW4gKEFsdGVybmF0aXYga8O2bm50ZW4gd2lyIGF1Y2ggZGllIGZlaGxlbmRlbiBMw6RuZGVyIG1hbnVlbGwgbm9jaCBkZW0gcmljaHRpZ2VuIEtvbnRpbmVudGVuIHp1d2Vpc2VuKS4gTWl0IGRlbSBBcmd1bWVudCBgc2NhbGVfeF9kYXRlYCDDpG5kZXJuIHdpciBkYXMgRGF0dW1zZm9ybWF0IGRlciBYLUFjaHNlIHVuZCBzZXR6ZW4gZXMgYXVmIFdvY2hlbnNjaHJpdHRlLCBtaXQgZGVtIEFyZ3VtZW50IGB0aGVtZSgpYCBwb3NpdGlvbmllcmVuIHdpciBkaWUgTGVnZW5kZSBpbiBkZW4gUGxvdCB1bmQgc2V0emVuIGRlbiBIaW50ZXJncnVuZCB0cmFuc3BhcmVudC4NCg0KYGBge3J9DQpnM2IgPC0gZ2dwbG90KGRhdGEgPSBmaWx0ZXIoUmVnaW9uZW5fbG9uZywgDQogICAgICAgICAgICAgICAgICAgICBLYXRlZ29yaWUgJWluJSBjKCJCZXN0w6R0aWd0ZSBGw6RsbGUgamUgUmVnaW9uIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvZGVzZsOkbGxlIGplIFJlZ2lvbiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHZW5lc3VuZ2VuIGplIFJlZ2lvbiIpKSkgKw0KICBnZW9tX2xpbmUobWFwcGluZyA9IGFlcyh4ID0gRGF0dW0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gYEbDpGxsZWAsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IFJlZ2lvbiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmV0eXBlID0gS2F0ZWdvcmllKSwgDQogICAgICAgICAgICBzaXplID0gMSkrDQogIGxhYnMoeCA9ICJEYXR1bSIsIA0KICAgICAgIHkgPSAiRsOkbGxlIiwgDQogICAgICAgdGl0bGUgPSBwYXN0ZSgiRmFsbHphaGxlbiBuYWNoIEthdGVnb3JpZSB1bmQgUmVnaW9uLCBTdGFuZCAiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhbmRfZGF0ZW5zYXR6LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXA9IiIpKSArDQogICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gbnVtYmVyKSArDQogIHNjYWxlX3hfZGF0ZShkYXRlX2JyZWFrcyA9ICIyIHdlZWsiLCANCiAgICAgICAgICAgICAgIGRhdGVfbGFiZWxzID0gIiVkLiVtIikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuMiwgMC42KSwNCiAgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD1hbHBoYSgwLjQpKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpDQpnM2INCmBgYA0KDQoNCg0KTnVuIGvDtm5uZW4gd2lyIGRlbiB0w6RnbGljaGVuIFp1d2FjaHMgYW4gRmFsbHphaGxlbiBwbG90dGVuLiBadXPDpHR6bGljaCBmw7xnZW4gd2lyIG1pdCBgZ2VvbV92bGluZSgpYCBNYXJraWVydW5nZW4gdW5kIG1pdCBgZ2VvbV9sYWJlbCgpYCBMYWJlbHMgYW4gZGVuIFN0ZWxsZW4gaGluenUsIGFuIGRlbmVuIEVyZWlnbmlzc2Ugc3RhdHRnZWZ1bmRlbiBoYWJlbiwgZGllIHNpY2ggYXVmIEF1c2JyZWl0dW5nIGRlciBFcmtyYW5rdW5nIGF1c3dpcmtlbiBrw7ZubmVuLCBuw6RtbGljaCBkaWUgWmVpdHB1bmt0ZSwgYW4gZGVuZW4gdmVyc2NoaWVkZW5lIEzDpG5kZXIgbWl0IGRlbiBRdWFyYW50w6RuZW1hw59uYWhtZW4gYmVnb25uZW4gaGFiZW4uIENoaW5hIGhhdCBiZWlzcGllbHN3ZWlzZSBzY2hvbiBhbSAyMy4gSmFudWFyIG1pdCBkZXIgUXVhcmFudMOkbmUgdm9uIEh1YmVpIGJlZ29ubmVuLCBhbHNvIHp1IGVpbmVtIFplaXRwdW5rdCwgYWxzIGVzIG51ciA2MzkgQmVzdMOkdGlndGUgRsOkbGxlIGplIFJlZ2lvbiB1bmQgMTggVG9kZXNmw6RsbGUgamUgUmVnaW9uIGluIENoaW5hIGdhYi4gSXRhbGllbiBoYXQgbWl0IGRlciBBdXNnYW5nc3NwZXJyZSBhbSA5LiBNw6RyeiBiZWdvbm5lbi4NCg0KDQpgYGB7cn0NCmc0IDwtIGdncGxvdChkYXRhID0gUmVnaW9uZW4pICsNCiAgZ2VvbV9saW5lKG1hcHBpbmcgPSBhZXMoeCA9IERhdHVtLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGBadXdhY2hzIGJlc3TDpHRpZ3RlciBGw6RsbGUgamUgUmVnaW9uYCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gUmVnaW9uKSwgc2l6ZSA9IDEpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYXMuRGF0ZSgiMjAyMC0wMS0yMyIpKSArDQogIGdlb21fbGFiZWwobGFiZWw9Ikh1YmVpIFxuIFF1YXJhbnTDpG5lIiwgeT0xNTAwMCwgeD1hcy5EYXRlKCIyMDIwLTAxLTI0IikrMSkrDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGFzLkRhdGUoIjIwMjAtMDMtMDkiKSwgY29sb3IgPSAiYmxhY2siKSArDQogIGdlb21fbGFiZWwobGFiZWw9Ikl0YWxpZW4gXG4gQXVzZ2FuZ3NzcGVycmUiLCB5PTE4MDAwLCB4PWFzLkRhdGUoIjIwMjAtMDMtMDkiKSkgKw0KICBzY2FsZV94X2RhdGUoZGF0ZV9icmVha3MgPSAiMiB3ZWVrIiwgZGF0ZV9sYWJlbHMgPSAiJWQuJW0iKSArICANCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gYygwLjIsIDAuOCksDQogICAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9YWxwaGEoMC40KSksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArDQogIGxhYnModGl0bGUgPSBwYXN0ZSgiVMOkZ2xpY2hlciBBbnN0aWVnIGFuIEbDpGxsZW4gamUgUmVnaW9uLCBTdGFuZCAiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhbmRfZGF0ZW5zYXR6LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXA9IiIpKQ0KZzQNCmBgYA0KDQoNCg0KTnVuIHdvbGxlbiB3aXIgZGllIGFrdXRlbiBFcmtyYW5rdW5nZW4gYWxzIEZsw6RjaGVucGxvdCDDvGJlciBkaWUgWmVpdCBkYXJzdGVsbGVuLiBFaW5lbiBGbMOkY2hlbnBsb3QgZXJzdGVsbHQgbWFuIG1pdCBgZ2VvbV9hcmVhYCBpbm5lcmhhbGIgdm9uIGBnZ3Bsb3QoKWAuDQoNCg0KYGBge3J9DQpnNSA8LSBnZ3Bsb3QoZGF0YSA9IFJlZ2lvbmVuKSArDQogIGdlb21fYXJlYShtYXBwaW5nID0gYWVzKHggPSBEYXR1bSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBgQWt1dGUgRXJrcmFua3VuZ2VuIGplIFJlZ2lvbmAsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gUmVnaW9uKSwgDQogICAgICAgICAgICBzaXplID0gMSkgKw0KICBsYWJzKHggPSAiRGF0dW0iLCANCiAgICAgICB5ID0gIkFrdXRlIENPVklELTE5IEbDpGxsZSIsIA0KICAgICAgIHRpdGxlID0gcGFzdGUoIkFrdXRlIEVya3Jhbmt1bmdlbiBqZSBSZWdpb24sIFN0YW5kICIsDQogICAgICAgICAgICAgICAgICAgIHN0YW5kX2RhdGVuc2F0eiwNCiAgICAgICAgICAgICAgICAgICAgc2VwPSIiKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gbnVtYmVyKSArDQogIHNjYWxlX3hfZGF0ZShkYXRlX2JyZWFrcyA9ICIyIHdlZWsiLCANCiAgICAgICAgICAgICAgIGRhdGVfbGFiZWxzID0gIiVkLiVtIikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuMSwgMC44KSwNCiAgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD1hbHBoYSgwLjQpKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZT0iU2V0MyIpDQpnNQ0KYGBgDQoNCg0KDQoNCg0KV2lyIGvDtm5uZW4gYXVjaCBpbiBgZ2dwbG90KClgIG1pdCBgZ2VvbV9jb2woKWAgZWluIEJhbGtlbmRpYWdyYW1tIGVyemV1Z2VuLCBpbiBkZW0gZGllIFgtQWNoc2UgZGllIFJlZ2lvbiwgZGllIFktQWNoc2UgZGllIEFuemFobCBkZXIgRsOkbGxlIHVuZCBkaWUgRmFyYmUgKGBmaWxsYCkgZGllIFJlZ2lvbiBkZXIgVmFyaWFibGVuIGRhcnN0ZWxsdC4gRHVyY2ggZGVuIEJlZmVobCBgZmFjZXRfd3JhcCh+S2F0ZWdvcmllKWAgd2lyZCBhbHMgd2VpdGVyZSBEaW1lbnNpb24gZsO8ciBqZWRlIGltIERhdGVuc2F0eiB2b3JoYW5kZW5lIEthdGVnb3JpZSBlaW5lIGVpZ2VuZSBBYmJpbGR1bmcgZXJzdGVsbHQuIEhpZXJ6dSBtw7xzc2VuIHdpciBqZWRvY2ggenVlcnN0IGVpbmUgVmFyaWFibGUgZXJzdGVsbGVuLCBkaWUgZGllIFN0dWZlbiBkZXIgVmFyaWFibGUgYEthdGVnb3JpZWAgZW50aGFsdGVuIHNvbGwsIGRpZSB3aXIgdmVyd2VuZGVuIG3DtmNodGVuICh3aXIgd29sbGVuIG5pY2h0IGFsbGUgU3R1ZmVuIGF1cyBgS2F0ZWdvcmllYCBhYmJpbGRlbik6DQoNCmBgYHtyfQ0KYXVzZ2V3YWVobHRlX2thdGVnb3JpZSA8LSBjKCJBa3V0ZSBFcmtyYW5rdW5nZW4gamUgUmVnaW9uIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR2VuZXN1bmdlbiBqZSBSZWdpb24iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUb2Rlc2bDpGxsZSBqZSBSZWdpb24iKQ0KDQpgYGANCg0KDQoNCmBgYHtyfQ0KZzYgPC0gZ2dwbG90KGRhdGEgPSBmaWx0ZXIoUmVnaW9uZW5fbG9uZywgDQogICAgICAgICAgICAgICAgICAgICBEYXR1bSAlaW4lIG1heChSZWdpb25lbl9sb25nJERhdHVtKSwNCiAgICAgICAgICAgICAgICAgICAgIEthdGVnb3JpZSAlaW4lIGF1c2dld2FlaGx0ZV9rYXRlZ29yaWUpDQogICAgICAgKSArDQogIGdlb21fY29sKG1hcHBpbmcgPSBhZXMoeCA9IFJlZ2lvbiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGBGw6RsbGVgLCANCiAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gUmVnaW9uKSwgDQogICAgICAgICAgIHBvc2l0aW9uID0gImRvZGdlIikgKw0KICBmYWNldF93cmFwKH5LYXRlZ29yaWUsIG5jb2w9NikgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gbnVtYmVyKSArDQogIGxhYnModGl0bGUgPSBwYXN0ZSgiRsOkbGxlIGplIFJlZ2lvbiB1bmQgRmFsbGthdGVnb3JpZSwgU3RhbmQgIiwNCiAgICAgICAgICAgICAgICAgICAgc3RhbmRfZGF0ZW5zYXR6LA0KICAgICAgICAgICAgICAgICAgICBzZXA9IiIpKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLA0KICAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPWFscGhhKDAuNCkpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCmc2DQpgYGANCg0KDQoNCg0KDQojIyBFdXJvcGENCg0KSW4gZGllc2VyIEdyYWZpayB3dXJkZW4gZGllIEZhbGx6YWhsZW4gYWxsZXIgZXVyb3DDpGlzY2hlbiBgQmVzdMOkdGlndGUgRsOkbGxlYGVuIGRhcmdlc3RlbGx0LCBpbiBkZW5lbiBhbSAqKjMwLjAzLjIwMjAqKiBtaW5kZXN0ZW5zICoqNTAwMCBiZXN0w6R0aWd0ZSBGw6RsbGUqKiByZWdpc3RyaWVydCB3dXJkZW4uIEhpZXJmw7xyIG3DvHNzZW4gd2lyIGFsc28gZGVuIERhdGVuc2F0eiB6dW7DpGNoc3QgbWl0IGBmaWx0ZXIoKWAgYXVmIGRpZSBSZWdpb24gYEV1cm9wYWAsIGRhcyBEYXR1bSBgMjAyMC0wMy0zMGAgdW5kIGBCZXN0w6R0aWd0ZSBGw6RsbGUgPj0gNTAwMGAgZmlsdGVybi4gQW5zY2hsaWXDn2VuZCBsYXNzZW4gd2lyIHVucyBhdXMgZGllc2VtIE9iamVrdCBkaWUgVmFyaWFibGUgYENvdW50cnkvUmVnaW9uYCBhdXNnZWJlbiB1bmQgc3BlaWNoZXJuIGRpZSBMaXN0ZSBkZXIgTMOkbmRlciwgZGllIGFtIDMwLjAzLjIwMjAgw7xiZXIgNTAwMCBiZXN0w6R0aWd0ZSBGw6RsbGUgaGF0dGVuIGltIE9iamVrdCBgZXVyb3BhXzUwMDBfbGlzdGAgYWIuIE51biBoYWJlbiB3aXIgZWluZSBMaXN0ZSBhbGwgZGllc2VyIEzDpG5kZXIgdW5kIGZpbHRlcm4gdW5zZXJlbiBEYXRlbnNhdHogbmFjaCBMw6RuZGVybiwgZGllIGluIGRpZXNlciBMaXN0ZSB2b3Jrb21tZW4uIEFuc2NobGllw59lbmQgZXJzdGVsbGVuIHdpciB3aWVkZXIgZWluZW4gRmzDpGNoZW5wbG90Og0KDQoNCmBgYHtyfQ0KZXVyb3BhXzUwMDBfbGlzdCA8LSBmaWx0ZXIoZGF0YSwgUmVnaW9uID09ICJFdXJvcGEiICYNCiAgICAgICAgICAgRGF0dW0gPT0gYXMuRGF0ZSgiMjAyMC0wMy0zMCIpICYNCiAgICAgICAgICAgYEJlc3TDpHRpZ3RlIEbDpGxsZWAgPj0gNTAwMCkkYENvdW50cnkvUmVnaW9uYA0KDQpFdXJvcGE1MDAwIDwtIGZpbHRlcihkYXRhLCANCiAgICAgICAgICAgICAgICAgIFJlZ2lvbiA9PSJFdXJvcGEiICYgDQogICAgICAgICAgICAgICAgICAgIGBDb3VudHJ5L1JlZ2lvbmAgJWluJSBldXJvcGFfNTAwMF9saXN0ICYgDQogICAgICAgICAgICAgICAgICAgIERhdHVtID49IGFzLkRhdGUoIjIwMjAtMDItMjQiKSkNCmBgYA0KDQpgYGB7cn0NCmc3IDwtIGdncGxvdChkYXRhID0gRXVyb3BhNTAwMCkgKw0KICBnZW9tX2FyZWEobWFwcGluZyA9IGFlcyh4ID0gRGF0dW0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gYEJlc3TDpHRpZ3RlIEbDpGxsZWAsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gU3RhYXQpKSArDQogIHNjYWxlX3hfZGF0ZShkYXRlX2JyZWFrcyA9ICIyIHdlZWsiLCBkYXRlX2xhYmVscyA9ICIlZC4lbSIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IG51bWJlcikgKw0KICBsYWJzKHggPSAiRGF0dW0iLCANCiAgICAgICB5ID0gIkJlc3TDpHRpZ3RlIEbDpGxsZSIsIA0KICAgICAgIHRpdGxlID0gcGFzdGUoIkJlc3TDpHRpZ3RlIEbDpGxsZSBpbiBFdXJvcGEsIFN0YW5kICIsDQogICAgICAgICAgICAgICAgICAgICBzdGFuZF9kYXRlbnNhdHosDQogICAgICAgICAgICAgICAgICAgICBzZXA9IiIpKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC4xNSwgMC42KSwNCiAgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD1hbHBoYSgwLjQpKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsgDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGU9IlNldDMiKQ0KZzcNCmBgYA0KDQpBdWYgZGllc2VsYmUgV2Vpc2UgZXJzdGVsbGVuIHdpciBkaWUgZHJlaSB3ZWl0ZXJlbiBHcmFmaWtlbiwgbnVyIGRhc3Mgd2lyIGRpZSB2b3JhbmdlZ2FuZ2VuZSBGaWx0ZXJhcmJlaXQgbmljaHQgZXJuZXVydCBkdXJjaGbDvGhyZW4gbcO8c3NlbjoNCg0KDQpgYGB7cn0NCmc4IDwtIGdncGxvdChkYXRhID0gRXVyb3BhNTAwMCkgKw0KICBnZW9tX2FyZWEobWFwcGluZyA9IGFlcyh4ID0gRGF0dW0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gYFRvZGVzZsOkbGxlYCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBTdGFhdCkpICsNCiAgc2NhbGVfeF9kYXRlKGRhdGVfYnJlYWtzID0gIjIgd2VlayIsIGRhdGVfbGFiZWxzID0gIiVkLiVtIikgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gbnVtYmVyKSArDQogIGxhYnMoeCA9ICJEYXR1bSIsIA0KICAgICAgIHkgPSAiVG9kZXNmw6RsbGUiLCANCiAgICAgICB0aXRsZSA9IHBhc3RlKCJUb2Rlc2bDpGxsZSBpbiBFdXJvcGEsIFN0YW5kICIsDQogICAgICAgICAgICAgICAgICAgIHN0YW5kX2RhdGVuc2F0eiwNCiAgICAgICAgICAgICAgICAgICAgc2VwPSIiKSkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuMTUsIDAuNiksDQogICAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9YWxwaGEoMC40KSksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArIA0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlPSJTZXQzIikNCmc4DQpgYGANCg0KDQpgYGB7cn0NCmc5IDwtIGdncGxvdChkYXRhID0gRXVyb3BhNTAwMCkgKw0KICBnZW9tX2FyZWEobWFwcGluZyA9IGFlcyh4ID0gRGF0dW0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gYEdlbmVzdW5nZW5gLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IFN0YWF0KSkgKw0KICBzY2FsZV94X2RhdGUoZGF0ZV9icmVha3MgPSAiMiB3ZWVrIiwgZGF0ZV9sYWJlbHMgPSAiJWQuJW0iKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBudW1iZXIpICsNCiAgbGFicyh4ID0gIkRhdHVtIiwgDQogICAgICAgeSA9ICJHZW5lc3VuZ2VuIiwgDQogICAgICAgdGl0bGUgPSBwYXN0ZSgiR2VuZXN1bmdlbiBpbiBFdXJvcGEsIFN0YW5kICIsDQogICAgICAgICAgICAgICAgICAgIHN0YW5kX2RhdGVuc2F0eiwNCiAgICAgICAgICAgICAgICAgICAgc2VwPSIiKSkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuMTUsIDAuNiksDQogICAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9YWxwaGEoMC40KSksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArIA0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlPSJTZXQzIikNCmc5DQpgYGANCg0KDQoNCmBgYHtyfQ0KZzEwIDwtIGdncGxvdChkYXRhID0gRXVyb3BhNTAwMCkgKw0KICBnZW9tX2FyZWEobWFwcGluZyA9IGFlcyh4ID0gRGF0dW0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gYEFrdXRlIEVya3Jhbmt1bmdlbmAsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gU3RhYXQpKSArDQogIHNjYWxlX3hfZGF0ZShkYXRlX2JyZWFrcyA9ICIyIHdlZWsiLCBkYXRlX2xhYmVscyA9ICIlZC4lbSIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IG51bWJlcikgKw0KICBsYWJzKHRpdGxlID0gcGFzdGUoIkFrdXRlIEVya3Jhbmt1bmdlbiBpbiBFdXJvcGEsIFN0YW5kICIsDQogICAgICAgICAgICAgICAgICAgIHN0YW5kX2RhdGVuc2F0eiwNCiAgICAgICAgICAgICAgICAgICAgc2VwPSIiKSkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuMTUsIDAuNiksDQogICAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9YWxwaGEoMC40KSksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArIA0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlPSJTZXQzIikNCmcxMA0KYGBgDQoNCg0KDQoNCg0KIyMgRGV1dHNjaGxhbmQNCg0KVW0gYWxsZSBkcmVpIEthdGVnb3JpZW4gYW4gRsOkbGxlbiBpbiBEZXV0c2NobGFuZCBpbiBlaW5lbSB6dXNhbW1lbmZhc3NlbmRlbiBGbMOkY2hlbnBsb3QgYWJ6dWJpbGRlbiwgbcO8c3NlbiB3aXIgenVlcnN0IGRlbiBEYXRlbnNhdHogbmFjaCBgQ291bnRyeS9SZWdpb25gIGdydXBwaWVyZW4gdW5kIGFuc2NobGllw59lbmQgbmFjaCBgR2VybWFueWAgZmlsdGVybi4gRGFuYWNoIHNvcnRpZXJlbiB3aXIgZGVuIERhdGVuc2F0eiBuYWNoIGBEYXR1bWAgaW4gYXVmc3RlaWdlbmRlciBSZWloZW5mb2xnZSB1bmQgZXJzdGVsbGVuIGRpZSBWYXJpYWJsZSBgQWJzb2x1dGVyIEFuc3RpZWcgYmVzdMOkdGlndGVyIEbDpGxsZWAgbWl0aGlsZmUgZGVyIGBsYWcoKWAgRnVua3Rpb24gc293aWUgZGllIFZhcmlhYmxlIGBQcm96ZW50dWFsZXIgQW5zdGllZyBiZXN0w6R0aWd0ZXIgRsOkbGxlYC4gDQoNCk51biBrw7ZubmVuIHdpciBkaWVzZW4gRGF0ZW5zYXR6IG1pdCBgcGl2b3RfbG9uZ2VyKClgIGluIGRpZSBsYW5nZSBGb3JtIMO8YmVyZsO8aHJlbi4NCg0KYGBge3J9DQpEZXV0c2NobGFuZCA8LSBkYXRhICU+JSANCiAgZ3JvdXBfYnkoYENvdW50cnkvUmVnaW9uYCkgJT4lIA0KICBmaWx0ZXIoYENvdW50cnkvUmVnaW9uYCA9PSAiR2VybWFueSIpICU+JSANCiAgYXJyYW5nZShEYXR1bSkgJT4lIA0KICBtdXRhdGUoYEFic29sdXRlciBBbnN0aWVnIGJlc3TDpHRpZ3RlciBGw6RsbGVgID0gbGFnKGBCZXN0w6R0aWd0ZSBGw6RsbGVgKSwNCiAgICAgICAgIGBQcm96ZW50dWFsZXIgQW5zdGllZyBiZXN0w6R0aWd0ZXIgRsOkbGxlYCA9ICgoYEJlc3TDpHRpZ3RlIEbDpGxsZWAgLyBgQWJzb2x1dGVyIEFuc3RpZWcgYmVzdMOkdGlndGVyIEbDpGxsZWApLTEpKjEwMCkNCiAgDQoNCg0KRGV1dHNjaGxhbmRfbGFuZyA8LSBwaXZvdF9sb25nZXIoZGF0YSA9IERldXRzY2hsYW5kLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHMgPSBjKGBCZXN0w6R0aWd0ZSBGw6RsbGVgLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYFRvZGVzZsOkbGxlYCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBHZW5lc3VuZ2VuYCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBBa3V0ZSBFcmtyYW5rdW5nZW5gLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYEFic29sdXRlciBBbnN0aWVnIGJlc3TDpHRpZ3RlciBGw6RsbGVgLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYFByb3plbnR1YWxlciBBbnN0aWVnIGJlc3TDpHRpZ3RlciBGw6RsbGVgKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIkthdGVnb3JpZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiRsOkbGxlIikNCmBgYA0KDQpEYSB3aXIgaW4gdW5zZXJlbSBsYW5nZW4gRGF0ZW5zYXR6IG1laHIgU3R1ZmVuIGlubmVyaGFsYiBkZXIgVmFyaWFibGUgYEthdGVnb3JpZWAgaGFiZW4sIGFscyB3aXIgYWJiaWxkZW4gbcO2Y2h0ZW4sIGZpbHRlcm4gd2lyIGlubmVyaGFsYiB2b24gZ2dwbG90IG5vY2ggZWlubWFsIG5hY2ggZGVuIGRyZWkgVmFyaWFibGVuIGBBa3V0ZSBFcmtyYW5rdW5nZW5gLCBgR2VuZXN1bmdlbmAgdW5kIGBUb2Rlc2bDpGxsZWAuDQoNCmBgYHtyfQ0KZzExIDwtIGdncGxvdChkYXRhID0gZmlsdGVyKERldXRzY2hsYW5kX2xhbmcsIA0KICAgICAgICAgICAgICAgICAgICAgS2F0ZWdvcmllID09ICJBa3V0ZSBFcmtyYW5rdW5nZW4iIHwNCiAgICAgICAgICAgICAgICAgICAgICAgS2F0ZWdvcmllID09ICJHZW5lc3VuZ2VuIiB8DQogICAgICAgICAgICAgICAgICAgICAgIEthdGVnb3JpZSA9PSAiVG9kZXNmw6RsbGUiLCBEYXR1bSA+PSBhcy5EYXRlKCIyMDIwLTAzLTAxIikpKSArDQogIGdlb21fYXJlYShtYXBwaW5nID0gYWVzKHggPSBEYXR1bSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBgRsOkbGxlYCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBLYXRlZ29yaWUpKSArDQogIHNjYWxlX3hfZGF0ZShkYXRlX2JyZWFrcyA9ICIyIHdlZWsiLCBkYXRlX2xhYmVscyA9ICIlZC4lbSIpICsNCiAgbGFicyh4ID0gIkRhdHVtIiwgDQogICAgICAgeSA9ICJCZXN0w6R0aWd0ZSBGw6RsbGUgaW4gRGV1dHNjaGxhbmQiLA0KICAgICAgIHRpdGxlID0gcGFzdGUoIkJlc3TDpHRpZ3RlIEbDpGxsZSBpbiBEZXV0c2NobGFuZCwgU3RhbmQgIiwNCiAgICAgICAgICAgICAgICAgICAgc3RhbmRfZGF0ZW5zYXR6LA0KICAgICAgICAgICAgICAgICAgICBzZXA9IiIpKSArIA0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuMiwgMC44KSwNCiAgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD1hbHBoYSgwLjQpKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsgDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGU9IlNldDMiKQ0KZzExDQpgYGANCg0KDQoNCk51biBlcnN0ZWxsZW4gd2lyIG1pdCBgZ2dwbG90KClgIHVuZCBgZ2VvbV9jb2woKWAgZWluIEJhbGtlbmRpYWdyYW1tIHVuZCBmw7xnZW4gZWluIHBhYXIgQmVzY2hyaWZ0dW5nZW4gZWluLiBEaWUgRmFsbHphaGxlbiBkZXIgTGFiZWxzIGvDtm5uZW4gd2lyIGF1cyBkZW0gZ2VmaWx0ZXJ0ZW4gRGF0ZW5zYXR6IGFibGVzZW4uIElubmVyaGFsYiB2b24gYGdncGxvdCgpYCBmaWx0ZXJuIHdpciBhdWYgRGF0ZW4sIGRpZSBuZXVlciBzaW5kIGFscyBkZXIgMjQuMDIuMjAyMC4NCg0KYGBge3Igd2FybmluZz1GQUxTRX0NCmcxMiA8LSBnZ3Bsb3QoZGF0YSA9IGZpbHRlcihEZXV0c2NobGFuZCwgRGF0dW0gPj0gYXMuRGF0ZSgiMjAyMC0wMi0yNCIpKSkgKw0KICBnZW9tX2NvbChtYXBwaW5nID0gYWVzKHggPSBEYXR1bSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGBQcm96ZW50dWFsZXIgQW5zdGllZyBiZXN0w6R0aWd0ZXIgRsOkbGxlYCksIA0KICAgICAgICAgICBmaWxsID0gIiM2Njk5ZmYiKSArDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKDAsbWF4KERldXRzY2hsYW5kJGBQcm96ZW50dWFsZXIgQW5zdGllZyBiZXN0w6R0aWd0ZXIgRsOkbGxlYCwgbmEucm0gPSBUKSwgMTApKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGFzLkRhdGUoIjIwMjAtMDMtMDYiKSkgKw0KICBnZW9tX2xhYmVsKGxhYmVsPSI2NzAgRsOkbGxlIiwgeT03MCwgeD1hcy5EYXRlKCIyMDIwLTAzLTA2IikpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYXMuRGF0ZSgiMjAyMC0wMy0xNCIpKSArDQogIGdlb21fbGFiZWwobGFiZWw9IjQ1ODUgRsOkbGxlIiwgeT02MCwgeD1hcy5EYXRlKCIyMDIwLTAzLTE0IikpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYXMuRGF0ZSgiMjAyMC0wMy0yMSIpKSArDQogIGdlb21fbGFiZWwobGFiZWw9IkJheWVybiBcbiBBdXNnYW5ncy1cbiBzcGVycmUsIFxuIDIyMjEzIEbDpGxsZSIsIHk9NzUsIHg9YXMuRGF0ZSgiMjAyMC0wMy0yMCIpKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGFzLkRhdGUoIjIwMjAtMDMtMjMiKSkgKw0KICBnZW9tX2xhYmVsKGxhYmVsPSJCdW5kZXN3ZWl0ZXMgXG4gS29udGFrdHZlcmJvdCwgXG4gMjkwNTYgRsOkbGxlIiwgeT00MCwgeD1hcy5EYXRlKCIyMDIwLTAzLTI1IikpICsNCiAgc2NhbGVfeF9kYXRlKGRhdGVfYnJlYWtzID0gIjIgd2VlayIsIGRhdGVfbGFiZWxzID0gIiVkLiVtIikgKyANCiAgbGFicyh5ID0gIlByb3plbnQiLCANCiAgICAgICB0aXRsZSA9IHBhc3RlKCJQcm96ZW50dWFsZXIgQW5zdGllZyBiZXN0w6R0aWd0ZXIgRsOkbGxlIGluIERldXRzY2hsYW5kLCBTdGFuZCAiLA0KICAgICAgICAgICAgICAgICAgICAgc3RhbmRfZGF0ZW5zYXR6LA0KICAgICAgICAgICAgICAgICAgICAgc2VwPSIiKSkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuOSwgMC44KSwNCiAgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD1hbHBoYSgwLjQpKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpDQpnMTINCmBgYCANCg0KDQoNCg0KSW0gRm9sZ2VuZGVuIG3DtmNodGVuIHdpciBlaW4gQmFsa2VuZGlhZ3JhbW0gbWl0IGRlbiBGYWxsemFobGVuIGluIERldXRzY2hsYW5kIGVyc3RlbGxlbiB1bmQgZWluZSBFeHBvbmVudGlhbGZ1bmt0aW9uIGVycmVjaG5lbiwgZGllIGF1ZiBkZW4gRmFsbHphaGxlbiB2b20gMTQuLTIwLjMuMjAyMCBiZXJ1aHQuIERpZSBXZXJ0ZSBuYWNoIGRlbSAyMC4zLjIwMjAgd29sbGVuIHdpciBoZWxsYmxhdSB6ZWljaG5lbiwgZGllIFdlcnRlIHZvciBkZW0gMjAuMy4yMDIwIHNvbGxlbiBkdW5rZWxibGF1IHNlaW4uIA0KDQpIaWVyZsO8ciBmaWx0ZXJuIHdpciB6dWVyc3QgZGVuIERhdGVuc2F0eiBhdWYgZGllIERhdGVuIHZvbSAyMy4wMi4yMDIwIC0gMzAuMDMuMjAyMC4gRsO8ciBkaWUgZHVua2VsYmxhdWVuIEJhbGtlbiBmaWx0ZXJuIHdpciBlcm5ldXQgdW5kIHfDpGhsZW4gbnVyIGRpZSBEYXRlbiBhdXMsIGRpZSB6d2lzY2hlbiBkZW0gMS4wMy4yMDIwIHVuZCBkZW0gMjAuMy4yMDIwIGxpZWdlbi4gQW4gZGllc2VuIFRhZ2VuIHN0aWVnZW4gZGllIEbDpGxsZSBub2NoIHN0w6Rya2VyIGFscyBuYWNoIGRlbSAyMC4zLjIwMjAuIERpZXNlIERhdGVuIHdvbGxlbiB3aXIgZHVua2VsYmxhdSBmw6RyYmVuLiANCg0KTnVuIGZpbHRlcm4gd2lyIGVybmV1dCBkZW4gRGF0ZW5zYXR6IGF1ZiBkaWUgZGllIERhdGVuIHZvbSAxNC4wMy4yMDIwIC0gMjAuMDMuMjAyMCwgZGVubiBudXIgZGllc2UgRGF0ZW4gd29sbGVuIHdpciBmw7xyIGRpZSBCZXJlY2hudW5nIGRlcyBNb2RlbGxzIGJlbnV0emVuLiBBdWYgZGllc2VtIERhdGVuc2F0eiBlcnJlY2huZW4gd2lyIGRlbiBMb2dhcml0aG11cyBkZXIgYmVzdMOkdGlndGVuIEbDpGxsZS4gQW5zY2hsaWXDn2VuZCBiZXJlY2huZW4gd2lyIGF1ZiBkZW4gbG9nYXJpdGhtaWVydGVuIERhdGVuIGVpbmUgbGluZWFyZSBSZWdyZXNzaW9uIG1pdCBgbG0oKWAuIE1pdCBkZXIgRnVua3Rpb24gYHNlcSgpYCBlcnN0ZWxsZW4gd2lyIGFuc2NobGllw59lbmQgZWluZSBTZXF1ZW56IGRlciBUYWdlLCBmw7xyIGRpZSB3aXIgZGllIHByb2dub3N0aXppZXJ0ZW4gRmFsbHphaGxlbiBtaXRoaWxmZSB1bnNlcmVzIE1vZGVsbHMgYXVzcmVjaGVuIG3DtmNodGVuLiBEdXJjaCBkaWUgRnVua3Rpb24gYHByZWRpY3QubG0oKWAgYmVyZWNobmVuIHdpciBmw7xyIGRpZXNlIFNlcXVlbnogZGllIHNpbXVsaWVydGVuIFdlcnRlIHVuZCBleHBvbmllcmVuIGRpZXNlIGFuc2NobGllw59lbmQgd2llZGVyIG1pdCBgZXhwKClgIHVuZCBzcGVpY2hlcm4gZGllc2UgaW0gT2JqZWt0IGBwcm9nbm9zZWAgYWxzIFZhcmlhYmxlIGBtb2RlbGxgIGFiLiBOdW4gZsO8Z2VuIHdpciBkZW4gbmV1IGVyc3RlbGx0ZW4gRGF0ZW5zYXR6IGBwcm9nbm9zZWAgbWl0IGRlciBGdW5rdGlvbiBgZnVsbF9qb2luKClgIHp1IHVuc2VyZW0genVlcnN0IGdlZmlsdGVydGVuIERhdGVuc2F0eiBoaW56dS4NCg0KDQoNCmBgYHtyfQ0KDQphbGxlX2RhdGVuIDwtIERldXRzY2hsYW5kICU+JSANCiAgZmlsdGVyKERhdHVtID49IGFzLkRhdGUoIjIwMjAtMDItMjMiKSAmIERhdHVtIDw9IG1heChkYXRhJERhdHVtKSkNCg0KZHVua2VsYmxhdSA8LSBEZXV0c2NobGFuZCAlPiUgDQogIGZpbHRlcihEYXR1bSA+PSBhcy5EYXRlKCIyMDIwLTAzLTAxIikgJiBEYXR1bSA8PSBhcy5EYXRlKCIyMDIwLTAzLTIwIikpDQoNCm1vZGVsbGRhdGVuIDwtIERldXRzY2hsYW5kICU+JSANCiAgZmlsdGVyKERhdHVtID49IGFzLkRhdGUoIjIwMjAtMDMtMTQiKSAmIERhdHVtIDw9IGFzLkRhdGUoIjIwMjAtMDMtMjAiKSkgJT4lIA0KICBtdXRhdGUoYExvZyBCZXN0w6R0aWd0ZSBGw6RsbGVgID0gbG9nKGBCZXN0w6R0aWd0ZSBGw6RsbGVgKSkNCg0KbW9kZWxsIDwtIGxtKGBMb2cgQmVzdMOkdGlndGUgRsOkbGxlYCB+IERhdHVtLCBkYXRhID0gbW9kZWxsZGF0ZW4pDQpEYXR1bSA8LSBzZXEoYXMuRGF0ZSgiMjAyMC0wMy0xNCIpLCBhcy5EYXRlKCIyMDIwLTAzLTMwIiksIGJ5ID0gMSkNCnByb2dub3NlIDwtIGRhdGEuZnJhbWUoRGF0dW0pDQpwcm9nbm9zZSRtb2RlbGwgPC0gZXhwKHByZWRpY3QubG0obW9kZWxsLCBuZXdkYXRhID0gcHJvZ25vc2UpKSANCg0KYWxsZV9kYXRlbl9wcm9nbm9zZSA8LSBmdWxsX2pvaW4oYWxsZV9kYXRlbiwgcHJvZ25vc2UsIGJ5ID0gIkRhdHVtIikNCmBgYA0KDQpOdW4ga8O2bm5lbiB3aXIgbWl0IGBnZ3Bsb3QoKWAgenVlcnN0IGVpbiBCYWxrZW5kaWFncmFtbSBEYXRlbnNhdHplcyBgYWxsZV9kYXRlbl9wcm9nbm9zZWAgZXJzdGVsbGVuIHVuZCB3w6RobGVuIEhlbGxibGF1IChgcm95YWxibHVlMWApIGFscyBGYXJiZS4gQW5zY2hsaWXDn2VuZCBlcnN0ZWxsZW4gd2lyIGVpbiB6d2VpdGVzIEJhbGtlbmRpYWdyYW1tIGRlcyBPYmpla3RlcyBgZHVuZ2VsYmxhdWAsIHdlbGNoZXMgbnVyIGRpZSBXZXJ0ZSB2b3Igdm9tIDAxLjAzLjIwMjAgLSAyMC4wMy4yMDIwIGVudGjDpGx0IHVuZCBmw6RyYmVuIGRpZXNlIGR1bmtlbGJsYXUgKGByb3lhbGJsdWU0YCkuIEFuc2NobGllw59lbmQgZsO8Z2VuIHdpciBlaW5lbiBMaW5pZW5wbG90IG1pdCBgZ2VvbV9saW5lKClgIGhpbnp1LCBkZXIgZGllIHByb2dub3N0aXppZXJ0ZW4gRsOkbGxlIChgbW9kZWxsYCkgYmFzaWVyZW5kIGF1ZiBkZW4gRGF0ZW4gdm9tIDE0LjAzLjIwMjAgLSAyMC4wMy4yMDIwIGVudGjDpGx0LiANCg0KWnVtIFNjaGx1c3MgZsO8Z2VuIHdpciBub2NoIGVpbmlnZSBMYWJlbHMgKGBnZW9tX2xhYmVsKClgKSB1bmQgdmVydGlrYWxlIExpbmllbiAoYGdlb21fdmxpbmUoKWApIGhpbnp1LCBzdGVsbGVuIGRhcyBEYXR1bSBhdWYgZWluIEludGVydmFsbCB2b24gNSBUYWdlbiB1bmQgw6RuZGVybiBkaWUgRm9ybWF0aWVydW5nIGRlcyBEYXR1bXMgYXVmIGRlciBYLUFjaHNlLg0KDQpgYGB7cn0NCmcxMyA8LSBnZ3Bsb3QoZGF0YSA9IGFsbGVfZGF0ZW5fcHJvZ25vc2UpICsNCiAgZ2VvbV9jb2wobWFwcGluZyA9IGFlcyh4ID0gRGF0dW0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBgQmVzdMOkdGlndGUgRsOkbGxlYCksIA0KICAgICAgICAgICBmaWxsID0icm95YWxibHVlMSIpICsNCiAgZ2VvbV9jb2woZGF0YSA9IGR1bmtlbGJsYXUsIA0KICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBEYXR1bSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGBCZXN0w6R0aWd0ZSBGw6RsbGVgKSwgDQogICAgICAgICAgIGZpbGwgPSJyb3lhbGJsdWU0IikgKw0KICBnZW9tX2xpbmUobWFwcGluZyA9IGFlcyh4ID0gRGF0dW0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbW9kZWxsKSwgDQogICAgICAgICAgICBjb2xvciA9ICJyZWQ0Iiwgc2l6ZSA9IDEpICsgDQogIA0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBhcy5EYXRlKCIyMDIwLTAzLTA2IikpICsNCiAgZ2VvbV9sYWJlbChsYWJlbD0iNjcwIEbDpGxsZSIsIA0KICAgICAgICAgICAgIHk9MjAwMDAsIA0KICAgICAgICAgICAgIHg9YXMuRGF0ZSgiMjAyMC0wMy0wNiIpKSArDQogICAgDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGFzLkRhdGUoIjIwMjAtMDMtMTQiKSkgKw0KICBnZW9tX2xhYmVsKGxhYmVsPSI0NTg1IEbDpGxsZSIsIA0KICAgICAgICAgICAgIHk9NTAwMDAsIA0KICAgICAgICAgICAgIHg9YXMuRGF0ZSgiMjAyMC0wMy0xNCIpKSArDQogIA0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBhcy5EYXRlKCIyMDIwLTAzLTIxIikpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYXMuRGF0ZSgiMjAyMC0wMy0yMyIpKSArDQogIA0KICBnZW9tX2xhYmVsKGxhYmVsPSJCYXllcm4gXG4gQXVzZ2FuZ3MtXG4gc3BlcnJlLCBcbiAyMjIxMyBGw6RsbGUiLCANCiAgICAgICAgICAgICB5PTgwMDAwLCANCiAgICAgICAgICAgICB4PWFzLkRhdGUoIjIwMjAtMDMtMjAiKSkgKw0KICBnZW9tX2xhYmVsKGxhYmVsPSJCdW5kZXN3ZWl0ZXMgXG4gS29udGFrdHZlcmJvdCwgXG4gMjkwNTYgRsOkbGxlIiwgDQogICAgICAgICAgICAgeT0xNTAwMDAsIA0KICAgICAgICAgICAgIHg9YXMuRGF0ZSgiMjAyMC0wMy0yMyIpKSArDQogIA0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBhcy5EYXRlKCIyMDIwLTAzLTMwIikpICsNCiAgZ2VvbV9sYWJlbChsYWJlbD0iMjI5MTA4IFxuIEbDpGxsZSIsIA0KICAgICAgICAgICAgIHk9MjI1MDAwLCANCiAgICAgICAgICAgICB4PWFzLkRhdGUoIjIwMjAtMDMtMzAiKSwgDQogICAgICAgICAgICAgY29sb3IgPSAicmVkIikgKw0KICBnZW9tX2xhYmVsKGxhYmVsPSI2Njg4NSBcbiBGw6RsbGUiLCANCiAgICAgICAgICAgICB5PTk1MDAwLCANCiAgICAgICAgICAgICB4PWFzLkRhdGUoIjIwMjAtMDMtMzAiKSkgKw0KICANCiAgbGFicyh4ID0gIkRhdHVtIiwgDQogICAgICAgeSA9ICJCZXN0w6R0aWd0ZSBGw6RsbGUiLCAgDQogICAgICAgdGl0bGUgPSBwYXN0ZSgiQmVzdMOkdGlndGUgRsOkbGxlIGluIERldXRzY2hsYW5kLCBTdGFuZCAiLA0KICAgICAgICAgICAgICAgICAgICAgc3RhbmRfZGF0ZW5zYXR6LA0KICAgICAgICAgICAgICAgICAgICAgc2VwPSIiKSkgKw0KICBzY2FsZV94X2RhdGUoZGF0ZV9icmVha3MgPSAiMiB3ZWVrIiwgZGF0ZV9sYWJlbHMgPSAiJWQuJW0iKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQ0KZzEzDQpgYGANCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KRGllc2UgU2VpdGUgaXN0IGluIHN0w6RuZGlnZXIgQmVhcmJlaXR1bmcgdW5kIHdpcmQgZGVtbsOkY2hzdCB3ZWl0ZXIgZXJnw6RuenQuIFp1bGV0enQgYmVhcmJlaXRldCBhbSBgciBkYXR1bV9iZWFyYmVpdGV0YC4gIA0KDQoNClN0YW5kIGRlcyBEYXRlbnNhdHplczogYHIgc3RhbmRfZGF0ZW5zYXR6YA0KICANCjxici8+PGJyLz48YnIvPjxici8+PGJyLz48YnIvPjxici8+PGJyLz48YnIvPjxici8+PGJyLz48YnIvPjxici8+DQogIA0KDQoNCg0KDQojIFdpZSBTaWUgdW5zIGVycmVpY2hlbjoNCjxkaXY+DQo8cD48c3Ryb25nPlN0YXRTb2Z0IChFdXJvcGUpIEdtYkg8L3N0cm9uZz48YnI+UG/Dn21vb3J3ZWcgMTxicj4gMjIzMDEgSGFtYnVyZzxicj4gRGV1dHNjaGxhbmQ8L3A+DQo8cD48c3Ryb25nPktvbnRha3Q8L3N0cm9uZz48L3A+DQo8cD5Gb24gKzQ5IDQwIDIyIDg1IDkwMC0wPGJyPiBGYXggKzQ5IDQwIDIyIDg1IDkwMC03Nzxicj4gDQoNCkUtTWFpbCA8YSBocmVmPSJtYWlsdG86aW5mb0BzdGF0c29mdC5kZSIgdGl0bGU9IkVtYWlsIEFkZHJlc3MiIGNsYXNzPSJtYWlsIj5pbmZvQHN0YXRzb2Z0LmRlPC9hPg0KPGJyPg0KSW50ZXJuZXQ6IDxhIGhyZWY9Imh0dHBzOi8vd3d3LnN0YXRzb2Z0LmRlIj53d3cuc3RhdHNvZnQuZGU8L2E+PC9wPg0KPHA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuc3RhdHNvZnQuZGUvZGUvaW1wcmVzc3VtIj5JbXByZXNzdW08L2E+PGJyPg0KPGEgaHJlZj0iaHR0cHM6Ly93d3cuc3RhdHNvZnQuZGUvZGUvZGF0ZW5zY2h1dHoiPkRhdGVuc2NodXR6PC9hPjwvcD4NCjwvZGl2Pg==