• Ziele der Case Study
  • Daten beschaffen
    • Nötige Pakete laden
    • Daten herunterladen
  • Daten einlesen
  • Anzahl an Arbeitslosen
    • ZIP-Archiv entpacken
    • Entpackte Datei einlesen
    • Spezifizieren welche Spalten eingelesen werden sollen
    • Konsistenzcheck
  • Pro-Kopf Verschuldung
    • Mehrere Tabellenblätter einlesen
    • Variablen umformen
    • Konsistenzcheck
      • Berechnung der Schulden pro Kopf von Hand
      • Vergleich der Schulden pro Kopf auf Landkreisebene
  • Bruttoinlandsprodukt
    • Nur einzelne Spalten einlesen
    • Daten in das long-Format überführen
    • Konsistenzchecks
  • Kartenmaterial hinzufügen (optional)
  • Datensätze zusammenführen
  • Übungsaufgaben

Angenommen Sie haben einen Cousin in Spanien mit dem Sie regen Kontakt haben und den Sie auch immer wieder besuchen.

Sie kommen bei einem Besuch in Spanien auf die aktuelle Lage in seinem Heimatland zu sprechen. Ihr Cousin berichtet über die sehr hohe Arbeitslosigkeit, insbesondere Jugendarbeitslosigkeit in seinem Land. Er behauptet, dass Sie dies nicht nachvollziehen könnten, da es in Deutschland praktisch keine Arbeitslosigkeit gibt. Daheim angekommen schauen Sie sich die Daten zur Arbeitslosigkeit im Euro-Raum an (was Sie auch im 2. - 4. RTutor Problem Set machen) und sehen in der Tat, dass Deutschland eine der niedrigsten Arbeitslosenquoten aller Euro-Länder hat und Spanien deutlich höhere Arbeitslosenquoten aufweist. Doch hat ihr Cousin recht, wenn er davon spricht, dass Deutschland keine Arbeitslosigkeit kennt? Gilt dies für alle Regionen in Deutschland, oder gibt es auch in Deutschland Regionen mit hohen Arbeitslosenquoten? Wenn Sie regionale Unterschiede finden, welche Gründe könnte dies haben?

Dem wollen wir in dieser Case-Study auf den Grund gehen.

Ziele der Case Study

Diese Case-Study besteht aus mehreren Teilen und wird Sie durch die komplette Vorlesung als konkretes Anschauungsobjekt begleiten. Hierbei dient die Case-Study hauptsächlich dazu, ihnen an einem konkreten und umfangreichen Beispiel die Kenntnisse für eine erfolgreiche Projektarbeit zu vermitteln und diese Kenntnisse zu vertiefen. Natürlich können Sie die Case-Study auch als Referenz heranziehen, wenn Sie ihre eigene Projektarbeit anfertigen.

Daten beschaffen

Wir wollen uns in dieser Case-Study mit der Pro-Kopf Verschuldung, der Arbeitslosigkeit und dem BIP in einzelnen Regionen in Deutschland beschäftigen und hier mögliche regionale Unterschiede aufdecken.

Im Ersten Schritt ist es wichtig sich zu überlegen, woher Sie ihre Datensätze beziehen. Um makroökonomische Informationen zum BIP oder der Arbeitslosigkeit zu erhalten empfiehlt es sich immer auf die Seiten des Statistischen Bundesamtes oder der Bundesagentur für Arbeit zu schauen. Hier finden Sie z.B. Quartalsinformationen zu BIP und Arbeitslosigkeit für ganz Deutschland.

In dieser Case-Study wollen wir jedoch etwas feingranularere Informationen sammeln, und zwar auf Landkreis-, Verwaltungs-, bzw. Gemeindeebene.

Uns interessieren die Pro-Kopf Verschulung, Arbeitslosigkeit und das BIP.

Nötige Pakete laden

Bevor wir mit der Analyse starten sollten wir einige Pakete in R laden, welche wir später verwenden möchten, da sie uns bei der Analyse unterstützen können. Dies geschieht mit dem library() Befehl.

(Alternative: Vor jeden Befehl das dazugehörige Paket schreiben, d.h. statt read_xlsx könnten wir auch readxl::read_xlsx schreiben. Jedoch wollen wir im Projektkurs immer die Variante mit library() verwenden.)

library(readxl)
library(tidyverse)
library(skimr)

Daten herunterladen

Mit den Befehlen aus dem readxl und readr Paketen könnten Sie direkt URLs einlesen, wenn sich dahinter Text,- bzw. Excel Datei verbergen, was bei uns der Fall ist. Allerdings sollten wir davon nur selten Gebrauch machen, denn es könnte immer sein das die Daten im Internet modifiziert oder unter der vorherigen URL nicht mehr auffindbar sind. Daher wollen wir die gewünschten Daten, welche wir zur Analyse benötigen, immer in einem Unterordner data abspeichern und dann aus diesem Ordner einlesen. So stellen wir sicher, dass wir immer auf die Daten zurückgreifen können, auch wenn diese aus dem Netz gelöscht oder modifiziert werden.

Daten können innerhalb von R mit dem Befehl download.file() heruntergeladen werden:

# Zuerst sollten Sie prüfen ob der Unterordner "data" bereits bei ihnen existiert, und falls er nicht existiert sollten Sie diesen erstellen.
# Dies können Sie beispielsweise mit dem folgenden Befehl machen, wenn der Ordner schon existiert wird eine Warnmeldung ausgegeben:

dir.create(file.path(".", "data"))

# Durch die if-Bedingung prüfen Sie, ob die Datei bereits im "data"-Ordner vorhanden ist

# Die neuesten Daten zur Verschuldung auf Landkreisebene stammen aus dem Jahr 2022
if (!file.exists("./data/Schulden_2022.xlsx")){
  download.file("https://www.statistikportal.de/sites/default/files/2024-03/Integrierte_Schulden_der_Gemeinden_und_Gemeindeverbaende_2022_Tabellenband.xlsx", "./data/Schulden_2022.xlsx")
}

# Arbeitslose aus dem Jahr 2022
#Zu finden unter: https://statistik.arbeitsagentur.de/SiteGlobals/Forms/Suche/Einzelheftsuche_Formular.html?topic_f=gemeinde-arbeitslose-quoten
if (!file.exists("./data/Arbeitslose_2022.xlsx.zip")){
  download.file("https://statistik.arbeitsagentur.de/Statistikdaten/Detail/202212/iiia4/gemeinde-arbeitslose-quoten/arbeitslose-quoten-dlk-0-202212-zip.zip?__blob=publicationFile&v=1", "./data/Arbeitslose_2022.xlsx.zip")
}

# Link für die aktuellen Daten zur Arbeitslosigkeit: https://statistik.arbeitsagentur.de/Statistikdaten/Detail/Aktuell/iiia4/gemeinde-arbeitslose-quoten/arbeitslose-quoten-dlk-0-zip.zip?__blob=publicationFile&v=1

# BIP pro Gemeinde aus dem Jahr 2023
if (!file.exists("./data/BIP_2023.xlsx")){
  download.file("https://www.statistikportal.de/sites/default/files/2024-07/vgrdl_r2b1_bs2023.xlsx", "./data/BIP_2023.xlsx")
}

Die Daten zur Verschuldung wollen wir unter “Schulden_2022.xlsx”, da die Tabelle zwar im März 2024 veröffentlicht wurde, sich aber auf das Jahr 2022 bezieht.

Die if-Bedingung prüft ob der angegebene Datensatz bereits in unserem “data” Ordner enthalten ist. Wenn dies der Fall ist, so werden sie nicht mehr erneut heruntergeladen.

Wir haben hier auch die Daten für die Arbeitslosenquote aus dem Jahr 2022 heruntergeladen, da wir die passenden Informationen zur Pro-Kopf Verschuldung der Gemeinden nur aus dem Jahr 2022 online erhalten.

Ich habe ihnen die Links zum neueren Datensätzen für die Arbeitslosigkeit in den R Chunk geschrieben. Für das BIP haben wir die neueste Datenreihe von August 2023 bezogen da wir hier Paneldaten haben und keine Querschnittsdaten (was dies genau heißt wird im Laufe der Case-Study erläutert).

Daten einlesen

Im nächsten Schritt sollten wir die Daten in R einlesen. Beim Download haben wir schon an den URLs und auch an den heruntergeladenen Dateien gesehen, dass es sich bei zwei Downloads um ZIP-Archive (BIP und Anzahl an Arbeitslosen) handelt. Diese ZIP-Archive können wir mittels R extrahieren, diese anschließend einlesen und die extrahierte Datei wieder löschen. Dies hat den Vorteil, dass Sie ihre Dateien platzsparend auf ihrer Festplatte abspeichern und nur bei Bedarf entsprechend entpacken.

Anzahl an Arbeitslosen

Im ersten Schritt wollen wir uns mit den Daten zu den Arbeitslosen beschäftigen und die in dem ZIP-Archiv enthaltenen Dateien in R einlesen.

ZIP-Archiv entpacken

# Öffnen des ZIP-Archivs
# Es sind zwei Tabellen in dem ZIP Archiv, wir interessieren uns für die Anzahl der Arbeitslosen und wählen diese mit dem kleinen [1] aus
alo_name <- as.character(unzip("./data/Arbeitslose_2022.xlsx.zip", list = TRUE)$Name)
alo_name <- alo_name[1]
unzip("./data/Arbeitslose_2022.xlsx.zip", alo_name)

Ok, nun haben wir die Daten entzipped und sehen, dass es sich um eine Excel-Datei handelt. Doch diese hat sehr viele unterschiedliche Tabellenblätter. Wie wissen wir, welches Tabellenblatt für uns von Interesse ist?

Dies können wir zum Einen mit excel_sheets herausfinden, wenn die Tabellenblätter gut benannt sind:

excel_sheets(alo_name)
##  [1] "Deckblatt"           "Impressum"           "Inhaltsverzeichnis" 
##  [4] "Übersicht_Kreise"    "Gesamt"              "SGB_III"            
##  [7] "SGB_II"              "Männer"              "Frauen"             
## [10] "Deutsche"            "Ausländer"           "AGR15u25"           
## [13] "AGR55plus"           "AGR55u65"            "Langzeitarbeitslos" 
## [16] "schwerbehindert"     "Hinweis_Alo_Asu"     "Statistik-Infoseite"

Da die Tabellenblätter jedoch nicht unbedingt vielsagend beschriftet sind sollten wir das Tabellenblatt “Inhalt” einlesen und uns dieses anschauen. Eventuell werden wir hier schlauer.

alo_inhalt <- read_xlsx(alo_name, sheet = "Inhaltsverzeichnis")
head(alo_inhalt, 20)
## # A tibble: 20 × 1
##    Inhaltsverzeichnis     
##    <chr>                  
##  1 <NA>                   
##  2 <NA>                   
##  3 Arbeitslose - Zeitreihe
##  4 <NA>                   
##  5 <NA>                   
##  6 Tabelle                
##  7 Bestand an Arbeitslosen
##  8 Kreiszusammenfassung   
##  9 Übersicht nach Kreisen 
## 10 <NA>                   
## 11 Insgesamt              
## 12 Rechtskreis            
## 13 SGB III                
## 14 SGB II                 
## 15 Geschlecht             
## 16 Männer                 
## 17 Frauen                 
## 18 Staatsangehörigkeit    
## 19 Deutsche               
## 20 Ausländer

Hier erhalten wir einen Überblick über die Tabellenblätter und wo welche Informationen abgespeichert sind. Da wir uns für den Bestand an Arbeitslosen interessieren und hier nicht nach Frauen und Männern oder Staatsangehörigkeit unterscheiden möchten, ist das Tabellenblatt Gesamt für uns das richtige.

Alternative: Schauen Sie sich die Excel-Datei in Excel oder LibreOffice an und entscheiden Sie dann, welches Tabellenblatt Sie einlesen möchten.

Entpackte Datei einlesen

Nun wissen wir, welches Tabellenblatt die für uns wichtige Information enthält:

alo <- read_xlsx(alo_name, sheet="Gesamt")

head(alo,10)
## # A tibble: 10 × 27
##    ...1  ...2  ...3  ...4  ...5  ...6  ...7  ...8  ...9  ...10 ...11 ...12 ...13
##    <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
##  1 <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA> 
##  2 Best… <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA> 
##  3 Länd… <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA> 
##  4 Zeit… <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA> 
##  5 Rech… <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA> 
##  6 <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA> 
##  7 <NA>  <NA>  <NA>  Aus … <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA> 
##  8 <NA>  Jahr… <NA>  Rech… <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA> 
##  9 <NA>  Jahr… Jahr… 44197 44228 44256 44287 44317 44348 44378 44409 44440 44470
## 10 Regi… 2021  2022  1     2     3     4     5     6     7     8     9     10   
## # ℹ 14 more variables: ...14 <chr>, ...15 <chr>, ...16 <chr>, ...17 <chr>,
## #   ...18 <chr>, ...19 <chr>, ...20 <chr>, ...21 <chr>, ...22 <chr>,
## #   ...23 <chr>, ...24 <chr>, ...25 <chr>, ...26 <chr>,
## #   Arbeitsmarktstatistik <chr>

Ok. Hier ist es wohl nicht vorteilhaft von der ersten Zeile ab die Informationen aus dem Tabellenblatt einzulesen. So wie es aussieht sind in den ersten 5 Zeilen Informationen zum Tabellenblatt und dem Berichtsjahr enthalten, dann kommt eine leere Zeile und dann kommen die eigentlichen Spaltenbeschriftungen. Diese sind dann jedoch wiederum in 4 Zeilen unterteilt. Was sind denn hier nun die Spaltenüberschriften, d.h. die Variablennamen im Datensatz?

Spezifizieren welche Spalten eingelesen werden sollen

Hierzu überlegen wir uns folgendes:

  • Welche Information benötigen wir aus der Tabelle

    • Die Anzahl aller Arbeitslosen pro Gemeinde (d.h. SGB II und III gemeinsam) aus dem Jahr 2022
    • Die Anzahl der Arbeitslosen pro Gemeinde für einen bestimmten Rechtskreis (z.B. nur SGB II)
    • Die Anzahl der Arbeitslosen pro Gemeinde für einen bestimmten Rechtskreis und ein bestimmtes Alter (z.B. SGB II alle unter 25 Jahre)
  • Wie können wir die von uns benötigte Information möglichst einfach extrahieren

In unserem Fall benötigen wir die Information zur durchschnittlichen Anzahl aller Arbeitslosen pro Gemeinde aus dem Jahr 2022, d.h. uns interessiert Spalte ...3. Weiterhin benötigen wir eine eindeutig zuzuordnende “Gemeinde-ID” um diese Datenquelle später mit anderen Datenquellen verbinden zu können. Außerdem wäre der Name der Gemeinde noch eine wichtig Information. Der einfachste Weg an diese Information zu gelangen ist die ersten acht Zeilen abzuschneiden und die Daten erst ab dort einzulesen. Anschließend behalten wir nur die ersten 3 Spalten, da uns nur diese interessieren.

Das wollen wir nun machen:

# Daten einlesen von Tabellenblatt "Gesamt", ohne die ersten 8 Zeilen
alo <- read_xlsx(alo_name, sheet = "Gesamt", skip = 8)

# Die entzippte Datei wieder löschen
unlink(alo_name)

# Nun beschränken wir uns auf die erste und dritte Spalte und trennen den Namen der Region (welcher in Spalte `...1` gelistet wird) und deren "Gemeinde-ID", dem sogenannten "Regionalschluessel" voneinander.
# Die Spalte 3 wollen wir anschließend in "alo" umbenennen
# Weiterhin löschen wir alle Zeilen, für die "alo" auf NA gesetzt ist und die erste Zeile, die alle Arbeitslosen in ganz Deutschland beinhaltet
# Wir speichern den Datensatz als `data_alo` ab
data_alo <- alo |> 
  select(c(`...1`, Jahresdurchschnitte, `...3`)) |>
  mutate(Regionalschluessel = str_extract(`...1`, "[[:digit:]]+"),
         Gemeinde = str_extract(`...1`, "[A-Z].*")) |>
  mutate(alo = as.numeric(`...3`)) |>
  select(-c(`...1`, Jahresdurchschnitte, `...3`)) |>
  filter(!is.na(alo))

# Die ersten drei Zeilen beinhalten keine nutzlichen Informationen, d.h. wir löschen diese
data_alo <- data_alo[-c(1,2),]

Konsistenzcheck

Nun sollten wir noch die Daten auf Konsistenz prüfen. D.h. machen die Angaben Sinn und sind die Daten in sich konsistent? Hierfür sollten wir zum Einen externe Datenquellen untersuchen und zum Anderen die Daten intern prüfen.

Wir haben hier sehr feingranulare Informationen über die Arbeitslosenzahl in 2022 vorliegen, jedoch können wir die Daten auch auf eine höhere Ebene aggregieren und damit leicht mit anderen Quellen vergleichen. Dies wollen wir hier tun:

  • Zunächst lassen wir uns die Anzahl an Arbeitslosen für jedes Bundesland in 2022 ausgeben. In unserem Datensatz sind dies alle Datenpunkte mit einem zweistelligen Regionalschluessel. Wir müssen hier beachten, dass die Regionalschluessel in der Klasse character vorliegen, d.h. als Strings und nicht als Zahl. Deshalb können wir die Anzahl an “Buchstaben” für jeden Regionalschluessel zählen. Dies geschieht über den Befehl nchar() (number of characters)
  • Nun sollten wir eine andere Datenquelle heranziehen und die Informationen gegenchecken. Bspw. könnten wir die Anzahl der Arbeitslosen für das Jahr 2022 unterteilt nach Ländern heranziehen. (Tabellenblatt 8)
check_alo_bundesland <- data_alo |>
  filter(nchar(Regionalschluessel) == 2) |>
  rename(bundesland = Regionalschluessel)

check_alo_bundesland
## # A tibble: 16 × 3
##    bundesland Gemeinde                   alo
##    <chr>      <chr>                    <dbl>
##  1 01         Schleswig-Holstein      81564.
##  2 02         Hamburg                 73800.
##  3 03         Niedersachsen          230553.
##  4 04         Bremen                  37214.
##  5 05         Nordrhein-Westfalen    668502.
##  6 06         Hessen                 164492.
##  7 07         Rheinland-Pfalz        102515.
##  8 08         Baden-Württemberg      223119.
##  9 09         Bayern                 235850.
## 10 10         Saarland                33017.
## 11 11         Berlin                 179327.
## 12 12         Brandenburg             74242 
## 13 13         Mecklenburg-Vorpommern  59571.
## 14 14         Sachsen                118216.
## 15 15         Sachsen-Anhalt          77978.
## 16 16         Thüringen               58172.

Wenn wir die Überprüfung mit der anderen Tabelle der Bundesagentur für Arbeit machen, dann sind beide Datenreihen identisch.

Nun wollen wir noch die interne Konsistenz überprüfen. Hierfür berechnen wir die Anzahl an Arbeitslosen für jedes Bundesland als Summe der Arbeitslosen einer jeden Gemeinde.

# Nur Gemeindedaten nutzen, dann auf Bundeslandebende die Summe aus den Gemeindedaten berechnen
alo_meta <- data_alo |> 
  filter(nchar(Regionalschluessel) == 8) |>
  mutate(landkreis = str_extract(Regionalschluessel, "^.{5}"),
         bundesland = str_extract(Regionalschluessel, "^.{2}"))

alo_bundesland <- alo_meta |>
  group_by(bundesland) |>
  summarise(total_alo = sum(alo))

alo_landkreis <- alo_meta |>
  group_by(landkreis) |>
  summarise(total_alo = sum(alo)) |>
  rename(Regionalschluessel = landkreis)

Um einen besseren Überblick zu erhalten können wir unsere berechneten und die von der Agentur für Arbeit angegebenen Werte miteinander verbinden und die Differenz zwischen den beiden Tabellen berechnen:

check_consitency <- left_join(check_alo_bundesland, alo_bundesland, by = "bundesland")

check_consitency <- check_consitency |>
  mutate(diff = alo - total_alo)

check_consitency
## # A tibble: 16 × 5
##    bundesland Gemeinde                   alo total_alo      diff
##    <chr>      <chr>                    <dbl>     <dbl>     <dbl>
##  1 01         Schleswig-Holstein      81564.    81564.  0       
##  2 02         Hamburg                 73800.    73800.  0       
##  3 03         Niedersachsen          230553.   230553.  0       
##  4 04         Bremen                  37214.    37214. -7.28e-12
##  5 05         Nordrhein-Westfalen    668502.   668502.  0       
##  6 06         Hessen                 164492.   164492.  0       
##  7 07         Rheinland-Pfalz        102515.   102515.  0       
##  8 08         Baden-Württemberg      223119.   223119.  0       
##  9 09         Bayern                 235850.   235850.  0       
## 10 10         Saarland                33017.    33017.  0       
## 11 11         Berlin                 179327.   179327.  0       
## 12 12         Brandenburg             74242     74242   0       
## 13 13         Mecklenburg-Vorpommern  59571.    59571.  0       
## 14 14         Sachsen                118216.   118216.  0       
## 15 15         Sachsen-Anhalt          77978.    77978.  0       
## 16 16         Thüringen               58172.    58172.  0

Unsere Analysen zeigen, dass es keine Differenzen zwischen den Daten gibt, die von der Bundesagentur für Arbeit auf Landes- und Bundesebene veröffentlichen.

Pro-Kopf Verschuldung

Der nächste Datensatz beinhaltet die Pro-Kopf-Verschuldung der deutschen Gemeinden. Hier handelt es sich wieder um Querschnittsdaten auf Gemeindeebene aus dem Jahr 2022.

Diesen Datensatz können wir von der Homepage des Statistischen Bundesamtes direkt als Excel-Tabelle herunterladen und müssen kein ZIP-Archiv entpacken. Allerdings sehen wir sehr schnell, das auch dieser Datensatz seine Tücken beim Einlesen bereithält, insbesondere wenn wir schauen, welche Tabellenblätter für unsere Analyse relevant sind:

excel_sheets("./data/Schulden_2022.xlsx")
##  [1] "Titel"              "Impressum"          "Inhalt"            
##  [4] "Abkürzungen"        "Erläuterungen"      "SH"                
##  [7] "NI"                 "NW"                 "HE"                
## [10] "RP"                 "BW"                 "BY"                
## [13] "SL"                 "BB"                 "MV"                
## [16] "SN"                 "ST"                 "TH"                
## [19] "Statistische Ämter"

Mehrere Tabellenblätter einlesen

Nun sind nicht mehr alle Informationen in einem Tabellenblatt enthalten, sondern jedes Bundesland hat sein eigenes Tabellenblatt bekommen. Sprich, wir müssen eine Möglichkeit finden alle Tabellenblätter nacheinander einzulesen und zu verarbeiten.

Dies wollen wir mit einer Schleife lösen, doch zuerst schauen wir uns an, welche Informationen wir aus den Tabellenblättern benötigen:

sh <- read_xlsx("./data/Schulden_2022.xlsx", sheet = "SH")
head(sh,20)
## # A tibble: 20 × 21
##    `Zurück zum Inhalt...1` ...2  ...3  ...4  ...5  ...6  ...7  ...8  ...9  ...10
##    <chr>                   <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
##  1  <NA>                   <NA>  <NA>   <NA> <NA>  <NA>   <NA> <NA>  <NA>  <NA> 
##  2  <NA>                   <NA>  <NA>   <NA> <NA>  <NA>   <NA> <NA>  <NA>  <NA> 
##  3 "Tabelle 1:    Schulde… <NA>  <NA>   <NA> <NA>  <NA>   <NA> <NA>  <NA>  <NA> 
##  4 "nach Höhe der Beteili… <NA>  <NA>   <NA> <NA>  <NA>   <NA> <NA>  <NA>  <NA> 
##  5 "Regional-\r\nschlüsse… Geme… Verw… "Ein… Schu… Verä… "Sch… Schu… <NA>  <NA> 
##  6  <NA>                   <NA>  <NA>   <NA> <NA>  <NA>   <NA> zusa… Verä… Schu…
##  7  <NA>                   <NA>  <NA>   <NA> <NA>  <NA>   <NA> <NA>  <NA>  <NA> 
##  8  <NA>                   <NA>  <NA>   <NA> <NA>  <NA>   <NA> <NA>  <NA>  <NA> 
##  9  <NA>                   <NA>  <NA>   <NA> EUR   %     "EUR" <NA>  %     EUR  
## 10  <NA>                   <NA>  <NA>   <NA> 1     2     "3"   4     5     6    
## 11 "010010000000"          Flen… krei… "919… 4617… 1.6   "501… 2230… -3.3  3571…
## 12 "010020000000"          Kiel… krei… "246… 1101… 5.2   "446… 5924… 7.1   5921…
## 13 "010030000000"          Lübe… krei… "217… 9835… -7.5  "451… 3582… -16.8 3549…
## 14 "010040000000"          Neum… krei… "798… 5036… 11    "630… 1245… 9.1   1142…
## 15 "01051"                 Krei… Krei… "{13… 5767… 31    "427… 3696… 79.4… 3693…
## 16 "010510011011"          Brun… amts… "125… 5788… 11.2  "462… 2522… 14.3  2245…
## 17 "010510044044"          Heid… amts… "219… 4920… 14.7  "224… 3055… 21.8  2637…
## 18 "010515163"             Amts… Amts… "{15… 8252… -3    "52.… 8252… -3    7942…
## 19 "010515163003"          Aver… amts… "572" 2247… 12.1  "392… 1503… 15.7  5883…
## 20 "010515163010"          Bric… amts… "202" 1435… 21.6  "710… 1101… 23.9  1865…
## # ℹ 11 more variables: ...11 <chr>, ...12 <chr>, ...13 <chr>, ...14 <chr>,
## #   ...15 <chr>, ...16 <chr>, ...17 <chr>, ...18 <chr>, ...19 <chr>,
## #   `Zurück zum Inhalt...20` <chr>, ...21 <chr>

Für uns wichtig sind die Infos bzgl. des “Regionalschlüssel”, der “Gemeindename”, die “Einwohner” und die “Schulden des öffentlichen Bereichs insgesamt”. Zur Überprüfung unserer Ergebnisse nehmen wir noch die “Schulden je Einwohner” mit in unseren Datensatz auf, d.h. die ersten sechs Spalten. Weiterhin stehen unsere Variablenbezeichnungen in Zeile 5, d.h. wir ignorieren die ersten 4 Zeilen beim Einlesen.

Der Übersicht halber wollen wir noch eine Spalte hinzufügen, welche den Namen des Tabellenblattes enthält, welches wir gerade eingelesen haben.

# Einlesen des Tabellenblattes "SH" ohne die ersten 5 Zeilen und nur die Spalten 1-7
schulden_individuell <- read_xlsx("./data/Schulden_2022.xlsx", sheet = "SH", skip = 5)[1:7]
# Umbenennen der ersten 7 Spalten
colnames(schulden_individuell) <- c("Regionalschluessel", "Gemeinde", 
                                    "Verwaltungsform", "Einwohner", "Schulden_gesamt", "Veraenderung_Vorjahr", "Schulden_pro_kopf")

# Zusätzliche Spalte hinzufügen mit dem Namen des Tabellenblattes
schulden_individuell$Bundesland <- "SH"

Ok, nun haben wir die Daten für Schleswig-Holstein eingelesen und können für alle anderen Daten gleich vorgehen.

In den nächsten drei Chunks sehen Sie unterschiedliche Varianten um die Daten einzulesen. In der ersten Variante nutzen wir eine for-Schleife um alle Bundesländer (Tabellenblätter) in der gleichen Form durchzugehen (diese Art der Schleife kennen Sie vermutlich aus anderen Informatik-Veranstaltungen/Programmiersprachen):

# Daten mit for-Schleife einlesen (Struktur gleich wie im vorherigen Chunk)
sheet_names <- excel_sheets("./data/Schulden_2022.xlsx")
# Einlesen der Tabellenblätter 6-18 (alle Bundesländer)
sheet_read <- sheet_names[6:18]

schulden_individuell <- NULL

for (i in 1:length(sheet_read)){
  tmp <- read_xlsx("./data/Schulden_2022.xlsx", sheet = sheet_read[i], skip = 5)[1:7]
  tmp$Bundesland <- sheet_read[i]
  colnames(tmp) <- c("Regionalschluessel", "Gemeinde", "Verwaltungsform", 
                     "Einwohner", "Schulden_gesamt", "Veraenderung_Vorjahr", "Schulden_pro_kopf", "Bundesland")
  # Daten aller weiteren Tabellenblätter unter den aktuellen Datensatz anheften
  schulden_individuell <- bind_rows(schulden_individuell, tmp)
}

Die zweite Möglichkeit wäre es die Funktion sapply() zu nutzen. D.h. Sie nutzen die funktionale Programmierung in R, welche meist deutlich effizienter ist als eine for-Schleife:

# Daten mit sapply()-Schleife einlesen (Struktur gleich wie im vorherigen Chunk)
sheet_names <- excel_sheets("./data/Schulden_2022.xlsx")
# Einlesen der Tabellenblätter 6-18 (alle Bundesländer)
sheet_read <- sheet_names[6:18]

# sapply() anstelle der for-Schleife verwenden
schulden_individuell <- bind_rows(
  sapply(sheet_read, function(sheet) {
    tmp <- read_xlsx("./data/Schulden_2022.xlsx", sheet = sheet, skip = 5)[1:7]
    tmp$Bundesland <- sheet
    colnames(tmp) <- c("Regionalschluessel", "Gemeinde", "Verwaltungsform", 
                       "Einwohner", "Schulden_gesamt", "Veraenderung_Vorjahr", "Schulden_pro_kopf", "Bundesland")
    return(tmp)
  }, simplify = FALSE)
)

In einer dritten Möglichkeit nutzen Sie das Paket purrr (welches Teil der tidyverse-Familie ist) und dort die Funktion map_df() um die Daten vektorisiert einzulesen. Dieser vektorisierte Ansatz mit map_df() aus dem purrr-Paket ist eine besonders einfache und effiziente Methode, um mehrere Excel-Tabellen gleichzeitig einzulesen und zu verarbeiten. Anstatt jede Tabelle einzeln durchzugehen, wird hier der gleiche Vorgang auf alle Tabellenblätter auf einmal angewendet. Dadurch sparen Sie sich die Verwendung von Schleifen, und der Code wird einfacher und übersichtlicher. Außerdem passt dieser Ansatz gut in das tidyverse-Ökosystem, das speziell für Datenanalysen optimiert ist.

# Daten mit map_df() eine Vektorisierte Form um die Daten einzulesen (Struktur gleich wie im vorherigen Chunk)
sheet_names <- excel_sheets("./data/Schulden_2022.xlsx")
# Einlesen der Tabellenblätter 6-18 (alle Bundesländer)
sheet_read <- sheet_names[6:18]

# Vektorisierte Form mit purrr::map_df() um die unterschiedlichen Tabellenblätter einzulesen und die Daten zu einem Datensatz zusammenzufügen
schulden_individuell <- map_df(sheet_read, function(sheet) {
  tmp <- read_xlsx("./data/Schulden_2022.xlsx", sheet = sheet, skip = 5)[1:7]
  tmp$Bundesland <- sheet
  colnames(tmp) <- c("Regionalschluessel", "Gemeinde", "Verwaltungsform", 
                     "Einwohner", "Schulden_gesamt", "Veraenderung_Vorjahr", "Schulden_pro_kopf", "Bundesland")
  return(tmp)
})

Variablen umformen

head(schulden_individuell,30)
## # A tibble: 30 × 8
##    Regionalschluessel Gemeinde         Verwaltungsform Einwohner Schulden_gesamt
##    <chr>              <chr>            <chr>           <chr>     <chr>          
##  1 <NA>               <NA>             <NA>            <NA>      <NA>           
##  2 <NA>               <NA>             <NA>            <NA>      <NA>           
##  3 <NA>               <NA>             <NA>            <NA>      <NA>           
##  4 <NA>               <NA>             <NA>            <NA>      EUR            
##  5 <NA>               <NA>             <NA>            <NA>      1              
##  6 010010000000       Flensburg, Stadt kreisfreie Sta… 91992     461784578.9700…
##  7 010020000000       Kiel, Landeshau… kreisfreie Sta… 246712    1101148771.960…
##  8 010030000000       Lübeck, Hansest… kreisfreie Sta… 217799    983573069.7400…
##  9 010040000000       Neumünster, Sta… kreisfreie Sta… 79889     503685790.8199…
## 10 01051              Kreisverwaltung… Kreisverwaltung {135 009} 57672347.28999…
## # ℹ 20 more rows
## # ℹ 3 more variables: Veraenderung_Vorjahr <chr>, Schulden_pro_kopf <chr>,
## #   Bundesland <chr>

Wir sehen, es gibt immer noch einige Probleme:

  • Die Werte unserer Variablen stehen nicht direkt unter dem Variablennamen, das ist für uns nicht optimal und ist der Anordnung in der Excel Datei geschuldet.

    • Dies können wir am einfachsten bereinigen indem wir alle NAs im Regionalschlüssel entfernen (kein Regionalschlüssel bedeutet keine Zuordnung zu einer Region und damit für uns nicht nachvollziehbar).
  • Die Variablen “Einwohner”, “Schulden_gesamt” und “Schulden_pro_Kopf” sind alle als character hinterlegt (<chr> unter dem Variablennamen in der vorherigen Tabelle), wir wollen diese jedoch in numerischer Form um Berechnungen durchführen zu können

    • Der Grund für die Klasse character kann z.B. in Zeile 28 beobachtet werden. Hier wurden geschweifte Klammern verwendet um die Summe aller Variablen eines Amtsgebiets, Landkreis, Region etc. zu kennzeichnen.
    • Im ersten Schritt wollen wir diese Summen einfach ignorieren da wir die jeweiligen Summen auch selbst berechnen können.
  • Die “Veraenderung_Vorjahr” ist für unsere weitere Analyse nicht relevant, daher wollen wir diese aus dem Datensatz entfernen

Anschließend wollen wir noch den landkreis als die ersten 5 Zeichen im Regionalschlüssel definieren.

# Die Daten wurden noch nicht schön eingelesen, in der Excel Tabelle 
# waren die Variablennamen über mehrere Reihen gezogen, dies müssen wir noch ausgleichen
schulden_bereinigt <- schulden_individuell |>
  filter(!is.na(Regionalschluessel)) |>
  mutate(Schulden_gesamt = as.numeric(Schulden_gesamt),
         Einwohner = as.numeric(Einwohner),
         Schulden_pro_kopf = as.numeric(Schulden_pro_kopf)) |>
  mutate(landkreis = str_extract(Regionalschluessel, "^.{5}")) |>
  select(-Veraenderung_Vorjahr)

Es wurden immer noch einige NAs erzeugt. Diese wollen wir uns noch näher anschauen:

filter(schulden_bereinigt, is.na(Einwohner))
## # A tibble: 2,367 × 8
##    Regionalschluessel   Gemeinde       Verwaltungsform Einwohner Schulden_gesamt
##    <chr>                <chr>          <chr>               <dbl>           <dbl>
##  1 01051                Kreisverwaltu… Kreisverwaltung        NA       57672347.
##  2 010515163            Amtsverwaltun… Amtsverwaltung         NA         825202.
##  3 010515163_Summe(Amt) Amt Burg-St. … Amtsgebiet             NA             NA 
##  4 010515166            Amtsverwaltun… Amtsverwaltung         NA        6821008.
##  5 010515166_Summe(Amt) Amt Marne-Nor… Amtsgebiet             NA             NA 
##  6 010515169            Amtsverwaltun… Amtsverwaltung         NA       11164461.
##  7 010515169_Summe(Amt) Amt KLG Eider  Amtsgebiet             NA             NA 
##  8 010515172            Amtsverwaltun… Amtsverwaltung         NA        1192621.
##  9 010515172_Summe(Amt) Amt KLG Heide… Amtsgebiet             NA             NA 
## 10 010515175            Amtsverwaltun… Amtsverwaltung         NA        3877702.
## # ℹ 2,357 more rows
## # ℹ 3 more variables: Schulden_pro_kopf <dbl>, Bundesland <chr>,
## #   landkreis <chr>

Wir müssen wohl noch mehr ausschließen als nur NAs beim Regionalschlüssel, insgesamt 2400 Einträge bei denen die Variable “Einwohner” nicht vorhanden ist. Wir hatten bereits gesehen, dass die Summe aller Einwohner eines Landkreisen mit { Zahl } in der Excel-Datei hervorgehoben wird. Wenn wir hier in R eine Typumwandlung erzwingen, dann kann R mit den {} nichts anfangen und gibt uns deshalb ein NA aus. Wir können hier alle Einträge, bei denen die Einwohner ein NA stehen haben, löschen, da wir die Daten selbst auf Basis der Informationen zu den Gemeinden des Landkreises berechnen können.

schulden_bereinigt <- schulden_bereinigt |>
  #manche Landkreise haben keine Infos zu den Einwohnern, diese entfernen wir
  filter( !is.na( Einwohner ) )

Konsistenzcheck

Berechnung der Schulden pro Kopf von Hand

Um die interne Validität unserer Daten beurteilen zu können wollen wir im ersten Schritt eine Variable Schulden_pro_Kopf_new generieren, welche die Schulden_pro_Kopf von Hand berechnet. Wie schon im Abschnitt Variablen umformen erwähnt, müssen wir hierfür jedoch erst folgendes beachten, bevor wir Berechnungen durchführen können:

  • Wir müssen die geschweiften Klammern entfernen (mit gsub("[{}]")), als auch die Leerzeichen innerhalb der Zahlen (z.B. 15 653), was wir mit gsub("[[:space:]]") erreichen. Tun wir das nicht, so würden wir wieder NAs im Datensatz erhalten. Wir tun dies hier in einem Befehl gsub("[[:space:]{}]")
# Erstellen der Vergleichstabelle
schulden_consistency <- schulden_individuell |>
  filter(!is.na(Einwohner) & !is.na(Regionalschluessel)) |>
  # Wir wenden die Funktion über die angegebenen Variablen an und nutzen dafür across())
  mutate(across(c(Schulden_gesamt, Schulden_pro_kopf, Einwohner), 
                # Die Funktionen, die wir anwenden sind gsub() und str_remove_all()
                ~ as.numeric(gsub("[[:space:]{}]", "",.))),
         Schulden_pro_kopf_new = round(Schulden_gesamt / Einwohner, 2)) |>
  mutate(landkreis = str_extract(Regionalschluessel, "^.{5}"),
         differenz = Schulden_pro_kopf - Schulden_pro_kopf_new)

Nun können wir uns anschauen, ob die von uns berechneten und die vom Statistischen Bundesamt angegebenen Werte zu den “Schulden_pro_Kopf” signifikant voneinander abweichen:

# range(schulden_consistency$differenz)
# oder schöne skim
skim_without_charts(schulden_consistency$differenz)
Data summary
Name schulden_consistency$diff…
Number of rows 13108
Number of columns 1
_______________________
Column type frequency:
numeric 1
________________________
Group variables None

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100
data 0 1 0 0.09 -0.49 0 0 0 0.5

Die Differenzen liegen zwischen +/- 50 Cent und können vermutlich auf Rundungsfehler zurückgeführt werden. D.h. hier können wir die vom statistischen Bundesamt herausgegebenen Berechnungen auf Gemeindeebene verifizieren.

Vergleich der Schulden pro Kopf auf Landkreisebene

In einem weiteren Konsistenzcheck wollen wir die durchschnittliche Verschuldung pro Kopf auf Landkreisebene selbst berechnen und diese mit den vom Statistischen Bundesamt angegebenen Werten in der Tabelle abgleichen.

Hierfür entnehmen wir der Tabelle zuerst alle Informationen bzgl. Anzahl der “Einwohner”, “Schulden_gesamt” und “Schulden_pro_Kopf” für die Landkreise. Im Datensatz sehen wir, dass die Regionalschluessel für Landkreise die Worte “Summe” und “Kreis” enthalten, wenn das Statistische Bundesamt die Daten auf Landkreisebene aggregiert. Das wollen wir im folgenden nutzen:

# Wir filtern alle Reihen heraus, welche "_Summe" oder "Kreis" im Regionalschlüssel aufweisen
# Anschließend berechnen wir die durchschnittliche Verschuldung auf Landkreisebene
avg_versch_kreis <- schulden_consistency |>
  filter(str_detect(Regionalschluessel, "_Summe") & str_detect(Regionalschluessel, "Kreis")) |>
  group_by(landkreis, Gemeinde) |>
  summarise(avg_verschuldung = Schulden_pro_kopf, 
            einwohner = Einwohner, 
            Gesamtschuld = Schulden_gesamt,
            # Keine Gruppierung mehr im Output durch:
            .groups = 'drop') |>
  arrange(desc(avg_verschuldung))

# Hier berechnen wir die Daten selbst
avg_versch_kreis_calc <- schulden_consistency |>
  # Ersetze Einwohner mit 0 für alle Regionalschlüssel kleiner als 12
  mutate(Einwohner = ifelse(nchar(Regionalschluessel)<12,0, Einwohner)) |>
  # Nur Gemeinden betrachten
  filter(nchar(Regionalschluessel)>=5 & str_detect(Regionalschluessel, "_Summe")==FALSE) |>
  # Auf Landkreisebene gruppieren
  group_by(landkreis) |>
  summarise(einwohner_calc = sum(Einwohner, na.rm = TRUE), 
            Gesamtschuld_calc = sum(Schulden_gesamt, na.rm = TRUE), 
            avg_verschuldung_calc = round(Gesamtschuld_calc/einwohner_calc,2),
            # Keine Gruppierung mehr im Output durch:
            .groups = 'drop') |>
  arrange(desc(avg_verschuldung_calc))

# Verbinde beide Datensätze und berechne ob es siginfikante Abweichungen zwischen 
# den ausgegebenen und berechneten Werten gibt
new <- left_join(avg_versch_kreis, avg_versch_kreis_calc, by="landkreis") |>
  mutate(differenz = avg_verschuldung - avg_verschuldung_calc) |>
  arrange( desc(differenz) )
# Ergebnis anschauen
#range(new$differenz)
# oder mit skim
skim_without_charts(new$differenz)
Data summary
Name new$differenz
Number of rows 294
Number of columns 1
_______________________
Column type frequency:
numeric 1
________________________
Group variables None

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100
data 0 1 0.01 0.28 -0.49 -0.21 0 0.27 0.5

Die Differenzen liegen hier zwischen -0,49 Euro bis +0,50 Euro (im Durchschnitt bei 0,01 Euro) und können vermutlich auf Rundungsfehler zurückgeführt werden. D.h. hier können wir die vom statistischen Bundesamt herausgegebenen Berechnungen auf Landkreisebene verifizieren.

Bruttoinlandsprodukt

Im nächsten Schritt wollen wir uns die Daten zum Bruttoinlandsprodukt einzelner Landkreise anschauen und diese in R einlesen. Wir haben diese direkt als Excel Datei heruntergeladen und können die Datei in R einlesen. Neben dem BIP beziehen wir aus diesem Excel-File die Anzahl an Erwerbstätigen, mit denen wir später die Arbeitslosenquote berechnen können und die Anzahl an Einwohner, mit denen wir das BIP-pro-Kopf berechnen können.

Nur einzelne Spalten einlesen

Folgende Schritte wollen wir in einem Chunk erledigen:

  • Betrachten der Daten

    • Tabellenblatt “1.1” ist für unsere Analyse ausschlaggebend (für das BIP)
    • Tabellenblatt “3.1” ist für die Anzahl an Erwerbstätigen ausschlaggebend
    • Tabellenblatt “5” ist für die Anzahl an Einwohnern ausschlaggebend
  • Die ersten vier Zeilen benötigen wir nicht

  • Die letzte Zeile enthält eine kurze Beschreibung die wir nicht benötigen -> Vorgehen: Behalte alle Zeilen, bei der Lfd. Nr. numerisch ist

  • Die folgenden Variablen benötigen wir nicht für unsere Analyse, diese können entfernt werden: Lfd. Nr., EU-Code, NUTS 1, NUTS 2, NUTS 3, Land, Gebietseinheit

# Blatt 1.1 einlesen und die ersten 4 Zeilen skippen
bip_name <- "./data/BIP_2023.xlsx"
bip <- read_xlsx(bip_name, sheet="1.1", skip = 4)
erwerb <- read_xlsx(bip_name, sheet="3.1", skip = 4)
einwohner <- read_xlsx(bip_name, sheet = "5", skip = 4)

# Zeile löschen in der die `Lfd. Nr.` nicht nummerisch ist
# Zusätzliche Spalten löschen
bip_wide <- bip |> 
  filter(is.na(as.numeric(`Lfd. Nr.`))==FALSE) |>
  select(-c(`Lfd. Nr.`, `EU-Code`, `NUTS 1`, `NUTS 2`, `NUTS 3`, Land, Gebietseinheit)) |>
  rename(Regionalschluessel = `Regional-schlüssel`)

# Zeile löschen in der die `Lfd. Nr.` nicht nummerisch ist
# Zusätzliche Spalten löschen
erwerb_wide <- erwerb |> 
  filter(is.na(as.numeric(`Lfd. Nr.`))==FALSE) |>
  select(-c(`Lfd. Nr.`, `EU-Code`, `NUTS 1`, `NUTS 2`, `NUTS 3`, Land, Gebietseinheit)) |>
  rename(Regionalschluessel = `Regional-schlüssel`)

einwohner_wide <- einwohner |>
  filter(is.na(as.numeric(`Lfd. Nr.`))==FALSE) |>
  select(-c(`Lfd. Nr.`, `EU-Code`, `NUTS 1`, `NUTS 2`, `NUTS 3`, Land, Gebietseinheit)) |>
  rename(Regionalschluessel = `Regional-schlüssel`)

head(bip_wide)
## # A tibble: 6 × 31
##   Regionalschluessel `1992`     `1994` `1995` `1996` `1997` `1998` `1999` `2000`
##   <chr>              <chr>      <chr>  <chr>  <chr>  <chr>  <chr>  <chr>   <dbl>
## 1 08                 255866.41… 26264… 27174… 27677… 28219… 29109… 30072… 3.09e5
## 2 081                110977.071 11160… 11528… 11678… 12086… 12384… 12779… 1.30e5
## 3 08111              32946.883… 31736… 32281… 32802… 34339… 33553… 35048… 3.53e4
## 4 08115              12090.93   11833… 11937… 12097… 13919… 13679… 14424… 1.39e4
## 5 08116              12275.605  12482… 12748… 13169… 13284… 13952… 14192… 1.44e4
## 6 08117              5062.0370… 5180.… 5447.… 5643.… 5667.… 5838.… 5920.… 6.00e3
## # ℹ 22 more variables: `2001` <dbl>, `2002` <dbl>, `2003` <dbl>, `2004` <dbl>,
## #   `2005` <dbl>, `2006` <dbl>, `2007` <dbl>, `2008` <dbl>, `2009` <dbl>,
## #   `2010` <dbl>, `2011` <dbl>, `2012` <dbl>, `2013` <dbl>, `2014` <dbl>,
## #   `2015` <dbl>, `2016` <dbl>, `2017` <dbl>, `2018` <dbl>, `2019` <dbl>,
## #   `2020` <dbl>, `2021` <dbl>, `2022` <dbl>

Dieser Datensatz ist ein sogenanntes Panel. In den vorherigen Datensätzen zur Anzahl der Arbeitslosen und der Pro-Kopf-Verschuldung hatten wir Querschnittsdaten (d.h. Daten nur das Jahr 2022) gegeben. Nun haben wir die Entwicklung des BIP, die Anzahl an Erwerbstätigen und die Anzahl an Einwohnern seit 1992 bis 2022 für alle Landkreise in Deutschland.

Daten in das long-Format überführen

Allerdings sind die Datensätze im wide-Format, d.h. nicht tidy und damit nicht so, wie wir ihn gerne hätten. Erinnern wir uns noch an die Bedingungen damit ein Datensätzen tidy ist?

Im nächsten Schritt wollen wir den Datensatz nun ins long-Format überführen und nutzen hierfür die Funktion pivot_longer:

bip_long <- pivot_longer(bip_wide, cols = c("1992":"2022") , names_to = "Jahr", values_to = "BIP")

# Produziert den folgenden Fehler:
# Fehler: Can't combine `1992` <character> and `2000` <double>.

Leider ist es hier nicht möglich die Datensätze direkt in das long-Format zu überführen, insbesondere da die Klassen der Variablen 1992 bis 1999 character sind und ab 2000 dann double. Dies sagt uns die erscheinende Fehlermeldung:


Fehler: Can’t combine 1992 and 2000 .


Da wir wissen, dass das BIP, die Anzahl an Erwerbstätigen und die Anzahl an Einwohnern normalerweise numerisch wiedergegeben wird, ist wohl die Klasse double korrekt und wir sollten die Spalten von 1992 bis 1999 entsprechend umformatieren.

#BIP von 1992 - 1999 umformen (als numerische Variable)
bip_double <- bip_wide |>
  select(`1992`:`1999`) |>
  mutate_if(is.character, as.double)

# Erwerbstätige von 1992 - 1999 umformen (als numerische Variable)
erwerb_double <- erwerb_wide |>
  select(`1992`:`1999`) |>
  mutate_if(is.character, as.double)

# Einwohner von 1992 - 1999 umformen (als numerische Variable)
einwohner_double <- einwohner_wide |>
  select(`1992`:`1999`) |>
  mutate_if(is.character, as.double)

Wir bekommen hier eine Warnmeldung das NAs bei der Umwandlung erzeugt wurden. Derartige Warnungen sollten wir beachten und auf den Grund gehen. Nur so wissen wir, ob die Warnung für uns später unbeabsichtigte Auswirkungen hat.

Hierfür verbinden wir den neuen Datensatz bip_double mit unserem bisher bestehenden bip_wide und betrachten die Spalten in denen bip_double NAs enthält:

bip_wide_test <- bip_wide |>
  bind_cols(bip_double)

head(filter(bip_wide_test, is.na(`1992...32`)))
## # A tibble: 6 × 38
##   Regionalschluessel `1992...2` `1994...3` `1995...4` `1996...5` `1997...6`
##   <chr>              <chr>      <chr>      <chr>      <chr>      <chr>     
## 1 13003              .          .          .          .          .         
## 2 13004              .          .          .          .          .         
## 3 13071              .          .          .          .          .         
## 4 13072              .          .          .          .          .         
## 5 13073              .          .          .          .          .         
## 6 13074              .          .          .          .          .         
## # ℹ 32 more variables: `1998...7` <chr>, `1999...8` <chr>, `2000` <dbl>,
## #   `2001` <dbl>, `2002` <dbl>, `2003` <dbl>, `2004` <dbl>, `2005` <dbl>,
## #   `2006` <dbl>, `2007` <dbl>, `2008` <dbl>, `2009` <dbl>, `2010` <dbl>,
## #   `2011` <dbl>, `2012` <dbl>, `2013` <dbl>, `2014` <dbl>, `2015` <dbl>,
## #   `2016` <dbl>, `2017` <dbl>, `2018` <dbl>, `2019` <dbl>, `2020` <dbl>,
## #   `2021` <dbl>, `2022` <dbl>, `1992...32` <dbl>, `1994...33` <dbl>,
## #   `1995...34` <dbl>, `1996...35` <dbl>, `1997...36` <dbl>, …

Hier sehen wir bereits warum die Klasse der Variablen 1992 bis 1999 character war und nicht double. Für diese Jahre gab es für einige Regionen (Mecklenburg-Vorpommern und Niedersachen) keine Angaben zum BIP, den Erwerbstätigen oder den Einwohnern und daher wurden in der Excel Tabelle - eingefügt. Daher ist für uns die Umwandlung zu NA folgerichtig und wir können die Warnmeldung ignorieren und nur die transformierten Variablen mit der Klasse double verwenden:

bip_wide <- bip_wide |>
  select(-(`1992`:`1999`)) |>
  bind_cols(bip_double) 

erwerb_wide <- erwerb_wide |>
  select(-(`1992`:`1999`)) |>
  bind_cols(erwerb_double) 

einwohner_wide <- einwohner_wide |>
  select(-(`1992`:`1999`)) |>
  bind_cols(einwohner_double) 

Nun können wir den Datensatz ins long-Format transferieren und nach dem Jahr sortieren. Da die Einwohner und Erwerbstätigen in 1000 Personen angegeben sind multiplizieren wir unsere Erwerbstätigen und Einwohner mit 1000. Das BIP ist in 1 Mio. Euro angegeben, daher die Multiplikation mit 1 Mio.:

# BIP ins long-Format
bip_long <- pivot_longer(bip_wide, cols = c("2000":"1999") , names_to = "Jahr", values_to = "bip") |>
  mutate( Jahr = as.numeric(Jahr),
          bip = bip * 1000000) |>
  arrange( Jahr )

# Anzahl der Erwerbstätigen ins long-Format
erwerb_long <- pivot_longer(erwerb_wide, cols = c("2000":"1999") , names_to = "Jahr", values_to = "erw") |>
  mutate( Jahr = as.numeric(Jahr),
          erw = erw * 1000) |>
  arrange( Jahr )

# Anzahl der Einwohner ins long-Format
einwohner_long <- pivot_longer(einwohner_wide, cols = c("2000":"1999") , names_to = "Jahr", values_to = "einwohner") |>
  mutate( Jahr = as.numeric(Jahr),
          einwohner = einwohner * 1000) |>
  arrange( Jahr )

Konsistenzchecks

Wir haben bereits in dem Abschnitt “Pro-Kopf Verschuldung” die Einwohner zur Berechnung der Pro-Kopf-Verschuldung für 2022 eingelesen. Für eine längerfristige Betrachtung konnten wir nun mit dem BIP Datensatz die Anzahl der Einwohner von 1992 bis 2022 einlesen. In diesem Konsistenzcheck wollen wir untersuchen ob die Anzahl der Einwohner aus beiden Datenquellen in 2022 identisch ist. Hierbei ist es natürlich wichtig, wann die Daten zur Einwohnerzahl erhoben wurden und deshalb könnten diese auch geringfügig abweichen. Aber dem gehen wir nun auf den Grund:

schulden_check <- schulden_bereinigt |>
  group_by(landkreis) |>
  summarise( Schulden_pro_kopf_lk = sum(Schulden_gesamt)/sum(Einwohner), 
             Einwohner = sum(Einwohner), 
             Schulden_gesamt = sum(Schulden_gesamt),
             .groups = 'drop') |>
  rename(Regionalschluessel = landkreis)

einwohner_check <- left_join(schulden_check, filter(einwohner_long, Jahr == 2022), by=c("Regionalschluessel")) |>
  mutate(diff = Einwohner - einwohner) |>
  arrange(desc(diff))

skim_without_charts(einwohner_check$diff)
Data summary
Name einwohner_check$diff
Number of rows 396
Number of columns 1
_______________________
Column type frequency:
numeric 1
________________________
Group variables None

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100
data 0 1 684.03 787.1 -1997 276.75 523 905.5 8833
head(arrange(einwohner_check, -diff),20)
## # A tibble: 20 × 7
##    Regionalschluessel Schulden_pro_kopf_lk Einwohner Schulden_gesamt  Jahr
##    <chr>                             <dbl>     <dbl>           <dbl> <dbl>
##  1 09162                             5633.   1508933     8500326561.  2022
##  2 09564                             7597.    522711     3971241943.  2022
##  3 03241                             5463.   1169979     6391943023.  2022
##  4 06412                            11342.    770112     8734900741.  2022
##  5 03358                             1331.    147668      196478264.  2022
##  6 14713                             4552.    612378     2787281253.  2022
##  7 05913                             7177.    592900     4255524935.  2022
##  8 08111                             2969.    632165     1877209318.  2022
##  9 03459                             1423.    366423      521417956.  2022
## 10 03453                             1200.    178273      213957474.  2022
## 11 05315                             7854.   1081167     8491108807.  2022
## 12 08226                             2213.    554352     1226728637.  2022
## 13 09184                             2220.    354990      788159564.  2022
## 14 05766                             2666.    350459      934150509.  2022
## 15 05162                             3645.    456937     1665629822.  2022
## 16 05382                             4147.    606489     2515087619.  2022
## 17 05314                             7403.    336064     2487877086.  2022
## 18 06414                             7228.    282903     2044814832.  2022
## 19 05158                             3398.    488980     1661579594.  2022
## 20 06633                             1834.    240831      441671172.  2022
## # ℹ 2 more variables: einwohner <dbl>, diff <dbl>

Die Differenz liegt im Durchschnitt bei 684 Einwohnern, was im Toleranzbereich bei den großen Städte mit mehr als 120.000 Einwohnern ist. Die Abweichungen in den Einwohnerzahlen könnten gut im Zeitpunkt der Erhebung der Einwohnerzahlen begründet sein (August 2023 beim BIP und Ende Dezember 2022 bei den Daten zur Verschuldung). Daher werden wir den Differenzen nicht weiter nachgehen.

Um die langfristigen Entwicklungen des BIP pro Kopf zu visualisieren werden wir die dazugehörigen Einwohnerzahlen aus der Datenquelle zum BIP verwenden. Für die Pro-Kopf-Verschuldung jedoch die in der “Integrierten Schulden der Gemeinden” angegebenen Einwohnerzahl.

Kartenmaterial hinzufügen (optional)

Für eine spätere Visualisierung der Daten mittels einer Deutschlandkarte sollten wir uns noch Informationen zu den einzelnen Verwaltunsgrenzen als SHAPE-File herunterladen. Diese Informationen sind über das OpenData Portal des Bundesamts für Kartographie und Geodäsie verfügbar.

Die Dokumentation der Daten sollten wir uns immer zuerst anschauen, bevor wir die Datenquelle herunterladen. Dies gilt nicht nur für die Geodaten, sondern allgemein für alle Datenreihen.

Wir extrahieren uns hier die Informationen zu den Grenzen der Gemeinden, Verwaltungseinheiten, Landkreise und Bundesländer und speichern diese jeweils entsprechend ab. Um Geometriedaten einzulesen und diese später schön als Karte darstellen zu können müssen wir hier die Funktion st_read aus dem sf-Paket verwenden:

Da wir nur die Informationen zur Geometrie, z.B. der Landkreisgrenzen möchten, können wir die anderen Variablen auch aus dem Datensätz löschen. Wir behalten den Regionalschlüssel (ARS), den Namen des Kreises/der Gemeinde (GEN) und die Geometrie (geometry).

Wir müssen uns zusätzlich noch etwas mit der Dokumentation des Kartenmaterials beschäftigen. Da wir nur die Verwaltungseinheiten ohne die Nord- und Ostsee und ohne den Bodensee darstellen möchten, so müssen wir noch auf GF = 4 filtern, wie auf Seite 9 der Dokumentation beschrieben wird (tun wir dies nicht, so hätten wir die Nordseegebiete doppelt drin):


Grundsätzlich gilt: Jede Verwaltungseinheit besitzt genau einen Attributsatz mit dem GF-Wert 4. Zusätzlich kann eine Verwaltungseinheit einen Attributsatz mit dem GF-Wert 2 besitzen.


# Auf GF == 4 filtern und ARS als String speichern (ist aktuell als factor abgespeichert)
landkreise <- landkreise |>
  filter( GF==4 ) |> 
  select(ARS, GEN, geometry) |>
  mutate(Regionalschluessel = as.character(ARS))

gemeinden <- gemeinden |>
  filter( GF==4 ) |>
  select(ARS, GEN, geometry) |>
  mutate(Regionalschluessel = as.character(ARS))

bundesland <- bundesland |>
  filter( GF==4 ) |>
  select(ARS, GEN, geometry) |>
  mutate(Regionalschluessel = as.character(ARS))

Datensätze zusammenführen

In diesem letzten Abschnitt möchten wir alles für die nächsten Schritte der Case Study vorbereiten. Genauer: Wir wollen nicht nur die Informationen aus den einzelnen Datensätzen, sondern am Besten einen kombinierten Datensatz analysieren! Hierfür müssen wir zuerst die Informationen zur Verschuldung auf Landkreisebene aggregieren und die Daten zum BIP auf das Jahr 2022 einschränken. Anschließend können wir die Datensätze anhand des Regionalschlüssels miteinander verbinden.

Weiterhin wollen wir die geografischen Daten separat abspeichern und bei Bedarf anhand des Regionalschlüssels zu unserem Datensatz hinzumergen. Der Regionalschlüssel dient uns hierbei als eindeutige Identifikation der jeweiligen Gemeinde.

# Schulden auf Landkreisebene
schulden_kombi <- schulden_bereinigt |>
  group_by(landkreis) |>
  summarise( Schulden_pro_kopf_lk = sum(Schulden_gesamt)/sum(Einwohner), Einwohner = sum(Einwohner), Schulden_gesamt = sum(Schulden_gesamt)) |>
  rename(Regionalschluessel = landkreis)


# Anzahl an Erwerbstätigen für das Jahr 2022
erwerb_kombi <- erwerb_long |>
  filter(nchar(Regionalschluessel) == 5 & Jahr == 2022) |>
  select(-Jahr)

# Anzahl an Einwohner für das Jahr 2022
einwohner_kombi <- einwohner_long |>
  filter(nchar(Regionalschluessel) == 5 & Jahr == 2022) |>
  select(-Jahr)

# Namen der Landkreise
landkreis_name <- landkreise |> 
  st_drop_geometry() |>
  select(-ARS) |>
  mutate(bundesland = str_extract(Regionalschluessel, "^.{2}")) |>
  rename(landkreis_name = GEN)

# Namen der Bundesländer
bundesland_name <- bundesland |>
  st_drop_geometry() |>
  select(-ARS) |>
  rename(bundesland = Regionalschluessel,
         bundesland_name = GEN)

# Anzahl der Einwohner mit dem BIP verbinden um das BIP pro Kopf berechnen zu können
bip_zeitreihe <- left_join(bip_long, einwohner_long, by=c("Regionalschluessel", "Jahr")) |>
  mutate(bip_pro_kopf = bip / einwohner)

# BIP auf Landkreisebene im Jahr 2021
bip_kombi <- bip_zeitreihe |>
  filter(nchar(Regionalschluessel) == 5 & Jahr == 2022) |>
  select(-c(Jahr, einwohner))

# Datensätze zusammenführen

# Basisdatensatz -> Arbeitslosenzahlen pro Landkreis
# Name der Landkreise zumergen
daten1 <- left_join(alo_landkreis, landkreis_name, by = "Regionalschluessel")
# Namen der Bundesländer zumergen
daten1 <- daten1 |> mutate(bundesland = str_extract(Regionalschluessel, "^.{2}"))
daten1 <- left_join(daten1, bundesland_name, by = "bundesland")
# Schulden zumergen
daten2 <- left_join(daten1, schulden_kombi, by = "Regionalschluessel")
# BIP zumergen
daten3 <- left_join(daten2, bip_kombi, by = "Regionalschluessel")
# Zahl der Erwerbstätigen zumergen
gesamtdaten <- left_join(daten3, erwerb_kombi, by = "Regionalschluessel")

saveRDS(gesamtdaten, "./data/gesamtdaten.rds")
saveRDS(schulden_bereinigt, "./data/schulden_bereinigt.rds")
saveRDS(bip_zeitreihe, "./data/bip_zeitreihe.rds")
saveRDS(bundesland, "./data/bundesland.rds")
saveRDS(gemeinden, "./data/gemeinden.rds")
saveRDS(landkreise, "./data/landkreise.rds")

Übungsaufgaben

Laden Sie sich das durchschnittliche Arbeitnehmerentgelt pro Arbeitnehmer und Landkreis auf der Seite der Statistischen Ämter des Bundes und der Länder herunter und lesen Sie diesen in R ein.

  1. Finden Sie in dem heruntergeladenen Datensatz heraus, was der Unterschied zwischen Arbeitnehmerentgelt und Bruttolöhne- und Gehälter ist.

  2. Lesen Sie die für Sie relevante Tabelle Bruttolöhne- und Gehälter in R ein.

  3. Bereinigen Sie die Tabelle, d.h. der Datensatz sollte danach tidy sein.

  4. Berechnen Sie die Bruttolöhne pro Bundesland mit den Bruttolöhnen der einzelnen Landkreise als Konsistenzcheck.

  5. Vergleichen Sie ihren Datensatz mit dem auf Github bereitgestellten Datensatz (“einkommen.rds”). Stimmen diese überein?

  6. Verbinden Sie die Informationen zu den durchschnittlichen Einkommen mit dem gesamtdatensatz aus dem vorherigen Abschnitt.

LS0tCnRpdGxlOiAiQ2FzZSBTdHVkeSBmw7xyIERldXRzY2hsYW5kIgpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6CiAgICB0aGVtZTogY29zbW8KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nID0gRkFMU0UpCmBgYAoKQW5nZW5vbW1lbiBTaWUgaGFiZW4gZWluZW4gQ291c2luIGluIFNwYW5pZW4gbWl0IGRlbSBTaWUgcmVnZW4gS29udGFrdCBoYWJlbiB1bmQgZGVuIFNpZSBhdWNoIGltbWVyIHdpZWRlciBiZXN1Y2hlbi4KClNpZSBrb21tZW4gYmVpIGVpbmVtIEJlc3VjaCBpbiBTcGFuaWVuIGF1ZiBkaWUgYWt0dWVsbGUgTGFnZSBpbiBzZWluZW0gSGVpbWF0bGFuZCB6dSBzcHJlY2hlbi4KSWhyIENvdXNpbiBiZXJpY2h0ZXQgw7xiZXIgZGllIHNlaHIgaG9oZSBBcmJlaXRzbG9zaWdrZWl0LCBpbnNiZXNvbmRlcmUgSnVnZW5kYXJiZWl0c2xvc2lna2VpdCBpbiBzZWluZW0gTGFuZC4KRXIgYmVoYXVwdGV0LCBkYXNzIFNpZSBkaWVzIG5pY2h0IG5hY2h2b2xsemllaGVuIGvDtm5udGVuLCBkYSBlcyBpbiBEZXV0c2NobGFuZCBwcmFrdGlzY2gga2VpbmUgQXJiZWl0c2xvc2lna2VpdCBnaWJ0LgpEYWhlaW0gYW5nZWtvbW1lbiBzY2hhdWVuIFNpZSBzaWNoIGRpZSBEYXRlbiB6dXIgQXJiZWl0c2xvc2lna2VpdCBpbSBFdXJvLVJhdW0gYW4gKHdhcyBTaWUgYXVjaCBpbSAyLiAtIDQuIFJUdXRvciBQcm9ibGVtIFNldCBtYWNoZW4pIHVuZCBzZWhlbiBpbiBkZXIgVGF0LCBkYXNzIERldXRzY2hsYW5kIGVpbmUgZGVyIG5pZWRyaWdzdGVuIEFyYmVpdHNsb3NlbnF1b3RlbiBhbGxlciBFdXJvLUzDpG5kZXIgaGF0IHVuZCBTcGFuaWVuIGRldXRsaWNoIGjDtmhlcmUgQXJiZWl0c2xvc2VucXVvdGVuIGF1ZndlaXN0LgpEb2NoIGhhdCBpaHIgQ291c2luIHJlY2h0LCB3ZW5uIGVyIGRhdm9uIHNwcmljaHQsIGRhc3MgRGV1dHNjaGxhbmQga2VpbmUgQXJiZWl0c2xvc2lna2VpdCBrZW5udD8KR2lsdCBkaWVzIGbDvHIgYWxsZSBSZWdpb25lbiBpbiBEZXV0c2NobGFuZCwgb2RlciBnaWJ0IGVzIGF1Y2ggaW4gRGV1dHNjaGxhbmQgUmVnaW9uZW4gbWl0IGhvaGVuIEFyYmVpdHNsb3NlbnF1b3Rlbj8KV2VubiBTaWUgcmVnaW9uYWxlIFVudGVyc2NoaWVkZSBmaW5kZW4sIHdlbGNoZSBHcsO8bmRlIGvDtm5udGUgZGllcyBoYWJlbj8KCkRlbSB3b2xsZW4gd2lyIGluIGRpZXNlciBDYXNlLVN0dWR5IGF1ZiBkZW4gR3J1bmQgZ2VoZW4uCgojIFppZWxlIGRlciBDYXNlIFN0dWR5CgpEaWVzZSBDYXNlLVN0dWR5IGJlc3RlaHQgYXVzIG1laHJlcmVuIFRlaWxlbiB1bmQgd2lyZCBTaWUgZHVyY2ggZGllIGtvbXBsZXR0ZSBWb3JsZXN1bmcgYWxzIGtvbmtyZXRlcyBBbnNjaGF1dW5nc29iamVrdCBiZWdsZWl0ZW4uCkhpZXJiZWkgZGllbnQgZGllIENhc2UtU3R1ZHkgaGF1cHRzw6RjaGxpY2ggZGF6dSwgaWhuZW4gYW4gZWluZW0ga29ua3JldGVuIHVuZCB1bWZhbmdyZWljaGVuIEJlaXNwaWVsIGRpZSBLZW5udG5pc3NlIGbDvHIgZWluZSBlcmZvbGdyZWljaGUgUHJvamVrdGFyYmVpdCB6dSB2ZXJtaXR0ZWxuIHVuZCBkaWVzZSBLZW5udG5pc3NlIHp1IHZlcnRpZWZlbi4KTmF0w7xybGljaCBrw7ZubmVuIFNpZSBkaWUgQ2FzZS1TdHVkeSBhdWNoIGFscyBSZWZlcmVueiBoZXJhbnppZWhlbiwgd2VubiBTaWUgaWhyZSBlaWdlbmUgUHJvamVrdGFyYmVpdCBhbmZlcnRpZ2VuLgoKIyBEYXRlbiBiZXNjaGFmZmVuCgpXaXIgd29sbGVuIHVucyBpbiBkaWVzZXIgQ2FzZS1TdHVkeSBtaXQgZGVyIFByby1Lb3BmIFZlcnNjaHVsZHVuZywgZGVyIEFyYmVpdHNsb3NpZ2tlaXQgdW5kIGRlbSBCSVAgaW4gZWluemVsbmVuIFJlZ2lvbmVuIGluIERldXRzY2hsYW5kIGJlc2Now6RmdGlnZW4gdW5kIGhpZXIgbcO2Z2xpY2hlIHJlZ2lvbmFsZSBVbnRlcnNjaGllZGUgYXVmZGVja2VuLgoKSW0gRXJzdGVuIFNjaHJpdHQgaXN0IGVzIHdpY2h0aWcgc2ljaCB6dSDDvGJlcmxlZ2VuLCB3b2hlciBTaWUgaWhyZSBEYXRlbnPDpHR6ZSBiZXppZWhlbi4KVW0gbWFrcm/Dtmtvbm9taXNjaGUgSW5mb3JtYXRpb25lbiB6dW0gQklQIG9kZXIgZGVyIEFyYmVpdHNsb3NpZ2tlaXQgenUgZXJoYWx0ZW4gZW1wZmllaGx0IGVzIHNpY2ggaW1tZXIgYXVmIGRpZSBTZWl0ZW4gZGVzIFN0YXRpc3Rpc2NoZW4gQnVuZGVzYW10ZXMgb2RlciBkZXIgQnVuZGVzYWdlbnR1ciBmw7xyIEFyYmVpdCB6dSBzY2hhdWVuLgpIaWVyIGZpbmRlbiBTaWUgei5CLiBRdWFydGFsc2luZm9ybWF0aW9uZW4genUgQklQIHVuZCBBcmJlaXRzbG9zaWdrZWl0IGbDvHIgZ2FueiBEZXV0c2NobGFuZC4KCkluIGRpZXNlciBDYXNlLVN0dWR5IHdvbGxlbiB3aXIgamVkb2NoIGV0d2FzIGZlaW5ncmFudWxhcmVyZSBJbmZvcm1hdGlvbmVuIHNhbW1lbG4sIHVuZCB6d2FyIGF1ZiBMYW5ka3JlaXMtLCBWZXJ3YWx0dW5ncy0sIGJ6dy4KR2VtZWluZGVlYmVuZS4KClVucyBpbnRlcmVzc2llcmVuIGRpZSAqKlByby1Lb3BmIFZlcnNjaHVsdW5nKiosICoqQXJiZWl0c2xvc2lna2VpdCoqIHVuZCBkYXMgKipCSVAqKi4KCi0gICBEaWUgSW5mb3JtYXRpb25lbiDDvGJlciBkaWUgVmVyc2NodWxkdW5nIGRlciAqKkdlbWVpbmRlbioqIGZpbmRlbiB3aXIgYXVmIGRlbiBTZWl0ZW4gZGVzIFN0YXRpc3Rpc2NoZW4gQnVuZGVzYW10cyBpbSBSZXBvcnQ6IFtJbnRlZ3JpZXJ0ZSBTY2h1bGRlbiBkZXIgR2VtZWluZGVuIHVuZCBHZW1laW5kZXZlcmLDpG5kZV0oaHR0cHM6Ly93d3cuc3RhdGlzdGlrcG9ydGFsLmRlL2RlL3Zlcm9lZmZlbnRsaWNodW5nZW4vaW50ZWdyaWVydGUtc2NodWxkZW4tZGVyLWdlbWVpbmRlbi11bmQtZ2VtZWluZGV2ZXJiYWVuZGUpLgotICAgRGllIEluZm9ybWF0aW9uZW4genVyIEFyYmVpdHNsb3NpZ2tlaXQgYXVmICoqVmVyd2FsdHVuZ3NnZW1laW5zY2hhZnRzZWJlbmUqKiBmaW5kZW4gd2lyIGF1ZiBkZW4gU2VpdGVuIGRlciBbQnVuZGVzYWdlbnR1ciBmw7xyIEFyYmVpdF0oaHR0cHM6Ly9zdGF0aXN0aWsuYXJiZWl0c2FnZW50dXIuZGUvREUvTmF2aWdhdGlvbi9TdGF0aXN0aWtlbi9TdGF0aXN0aWtlbi1uYWNoLVJlZ2lvbmVuL0JBLUdlYmlldHNzdHJ1a3R1ci1OYXYuaHRtbCkuCi0gICBEaWUgSW5mb3JtYXRpb25lbiB6dW0gQklQIGF1ZiAqKkxhbmRrcmVpc2ViZW5lKiogZmluZGVuIHdpciBhdWYgZGVuIFNlaXRlbiBkZXIgW1N0YXRpc3Rpc2NoZW4gw4RtdGVyIGRlcyBCdW5kZXMgdW5kIGRlciBMw6RuZGVyXShodHRwczovL3d3dy5zdGF0aXN0aWtwb3J0YWwuZGUvZGUvdmdyZGwpLgoKIyMgTsO2dGlnZSBQYWtldGUgbGFkZW4KCkJldm9yIHdpciBtaXQgZGVyIEFuYWx5c2Ugc3RhcnRlbiBzb2xsdGVuIHdpciBlaW5pZ2UgUGFrZXRlIGluIFIgbGFkZW4sIHdlbGNoZSB3aXIgc3DDpHRlciB2ZXJ3ZW5kZW4gbcO2Y2h0ZW4sIGRhIHNpZSB1bnMgYmVpIGRlciBBbmFseXNlIHVudGVyc3TDvHR6ZW4ga8O2bm5lbi4KRGllcyBnZXNjaGllaHQgbWl0IGRlbSBgbGlicmFyeSgpYCBCZWZlaGwuCgooKipBbHRlcm5hdGl2ZToqKiBWb3IgamVkZW4gQmVmZWhsIGRhcyBkYXp1Z2Vow7ZyaWdlIFBha2V0IHNjaHJlaWJlbiwgZC5oLiBzdGF0dCBgcmVhZF94bHN4YCBrw7ZubnRlbiB3aXIgYXVjaCBgcmVhZHhsOjpyZWFkX3hsc3hgIHNjaHJlaWJlbi4gSmVkb2NoIHdvbGxlbiB3aXIgaW0gUHJvamVrdGt1cnMgaW1tZXIgZGllIFZhcmlhbnRlIG1pdCBgbGlicmFyeSgpYCB2ZXJ3ZW5kZW4uKQoKYGBge3J9CmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShza2ltcikKYGBgCgojIyBEYXRlbiBoZXJ1bnRlcmxhZGVuCgpNaXQgZGVuIEJlZmVobGVuIGF1cyBkZW0gYHJlYWR4bGAgdW5kIGByZWFkcmAgUGFrZXRlbiBrw7ZubnRlbiBTaWUgZGlyZWt0IFVSTHMgZWlubGVzZW4sIHdlbm4gc2ljaCBkYWhpbnRlciBUZXh0LC0gYnp3LgpFeGNlbCBEYXRlaSB2ZXJiZXJnZW4sIHdhcyBiZWkgdW5zIGRlciBGYWxsIGlzdC4KQWxsZXJkaW5ncyBzb2xsdGVuIHdpciBkYXZvbiBudXIgc2VsdGVuIEdlYnJhdWNoIG1hY2hlbiwgZGVubiBlcyBrw7ZubnRlIGltbWVyIHNlaW4gZGFzIGRpZSBEYXRlbiBpbSBJbnRlcm5ldCBtb2RpZml6aWVydCBvZGVyIHVudGVyIGRlciB2b3JoZXJpZ2VuIFVSTCBuaWNodCBtZWhyIGF1ZmZpbmRiYXIgc2luZC4KRGFoZXIgd29sbGVuIHdpciBkaWUgZ2V3w7xuc2NodGVuIERhdGVuLCB3ZWxjaGUgd2lyIHp1ciBBbmFseXNlIGJlbsO2dGlnZW4sIGltbWVyIGluIGVpbmVtIFVudGVyb3JkbmVyIGBkYXRhYCBhYnNwZWljaGVybiB1bmQgZGFubiBhdXMgZGllc2VtIE9yZG5lciBlaW5sZXNlbi4KU28gc3RlbGxlbiB3aXIgc2ljaGVyLCBkYXNzIHdpciBpbW1lciBhdWYgZGllIERhdGVuIHp1csO8Y2tncmVpZmVuIGvDtm5uZW4sIGF1Y2ggd2VubiBkaWVzZSBhdXMgZGVtIE5ldHogZ2Vsw7ZzY2h0IG9kZXIgbW9kaWZpemllcnQgd2VyZGVuLgoKRGF0ZW4ga8O2bm5lbiBpbm5lcmhhbGIgdm9uIFIgbWl0IGRlbSBCZWZlaGwgYGRvd25sb2FkLmZpbGUoKWAgaGVydW50ZXJnZWxhZGVuIHdlcmRlbjoKCmBgYHtyICJEb3dubG9hZF9EYXRhIiwgZXZhbD1ULCB3YXJuaW5nPUZBTFNFfQojIFp1ZXJzdCBzb2xsdGVuIFNpZSBwcsO8ZmVuIG9iIGRlciBVbnRlcm9yZG5lciAiZGF0YSIgYmVyZWl0cyBiZWkgaWhuZW4gZXhpc3RpZXJ0LCB1bmQgZmFsbHMgZXIgbmljaHQgZXhpc3RpZXJ0IHNvbGx0ZW4gU2llIGRpZXNlbiBlcnN0ZWxsZW4uCiMgRGllcyBrw7ZubmVuIFNpZSBiZWlzcGllbHN3ZWlzZSBtaXQgZGVtIGZvbGdlbmRlbiBCZWZlaGwgbWFjaGVuLCB3ZW5uIGRlciBPcmRuZXIgc2Nob24gZXhpc3RpZXJ0IHdpcmQgZWluZSBXYXJubWVsZHVuZyBhdXNnZWdlYmVuOgoKZGlyLmNyZWF0ZShmaWxlLnBhdGgoIi4iLCAiZGF0YSIpKQoKIyBEdXJjaCBkaWUgaWYtQmVkaW5ndW5nIHByw7xmZW4gU2llLCBvYiBkaWUgRGF0ZWkgYmVyZWl0cyBpbSAiZGF0YSItT3JkbmVyIHZvcmhhbmRlbiBpc3QKCiMgRGllIG5ldWVzdGVuIERhdGVuIHp1ciBWZXJzY2h1bGR1bmcgYXVmIExhbmRrcmVpc2ViZW5lIHN0YW1tZW4gYXVzIGRlbSBKYWhyIDIwMjIKaWYgKCFmaWxlLmV4aXN0cygiLi9kYXRhL1NjaHVsZGVuXzIwMjIueGxzeCIpKXsKICBkb3dubG9hZC5maWxlKCJodHRwczovL3d3dy5zdGF0aXN0aWtwb3J0YWwuZGUvc2l0ZXMvZGVmYXVsdC9maWxlcy8yMDI0LTAzL0ludGVncmllcnRlX1NjaHVsZGVuX2Rlcl9HZW1laW5kZW5fdW5kX0dlbWVpbmRldmVyYmFlbmRlXzIwMjJfVGFiZWxsZW5iYW5kLnhsc3giLCAiLi9kYXRhL1NjaHVsZGVuXzIwMjIueGxzeCIpCn0KCiMgQXJiZWl0c2xvc2UgYXVzIGRlbSBKYWhyIDIwMjIKI1p1IGZpbmRlbiB1bnRlcjogaHR0cHM6Ly9zdGF0aXN0aWsuYXJiZWl0c2FnZW50dXIuZGUvU2l0ZUdsb2JhbHMvRm9ybXMvU3VjaGUvRWluemVsaGVmdHN1Y2hlX0Zvcm11bGFyLmh0bWw/dG9waWNfZj1nZW1laW5kZS1hcmJlaXRzbG9zZS1xdW90ZW4KaWYgKCFmaWxlLmV4aXN0cygiLi9kYXRhL0FyYmVpdHNsb3NlXzIwMjIueGxzeC56aXAiKSl7CiAgZG93bmxvYWQuZmlsZSgiaHR0cHM6Ly9zdGF0aXN0aWsuYXJiZWl0c2FnZW50dXIuZGUvU3RhdGlzdGlrZGF0ZW4vRGV0YWlsLzIwMjIxMi9paWlhNC9nZW1laW5kZS1hcmJlaXRzbG9zZS1xdW90ZW4vYXJiZWl0c2xvc2UtcXVvdGVuLWRsay0wLTIwMjIxMi16aXAuemlwP19fYmxvYj1wdWJsaWNhdGlvbkZpbGUmdj0xIiwgIi4vZGF0YS9BcmJlaXRzbG9zZV8yMDIyLnhsc3guemlwIikKfQoKIyBMaW5rIGbDvHIgZGllIGFrdHVlbGxlbiBEYXRlbiB6dXIgQXJiZWl0c2xvc2lna2VpdDogaHR0cHM6Ly9zdGF0aXN0aWsuYXJiZWl0c2FnZW50dXIuZGUvU3RhdGlzdGlrZGF0ZW4vRGV0YWlsL0FrdHVlbGwvaWlpYTQvZ2VtZWluZGUtYXJiZWl0c2xvc2UtcXVvdGVuL2FyYmVpdHNsb3NlLXF1b3Rlbi1kbGstMC16aXAuemlwP19fYmxvYj1wdWJsaWNhdGlvbkZpbGUmdj0xCgojIEJJUCBwcm8gR2VtZWluZGUgYXVzIGRlbSBKYWhyIDIwMjMKaWYgKCFmaWxlLmV4aXN0cygiLi9kYXRhL0JJUF8yMDIzLnhsc3giKSl7CiAgZG93bmxvYWQuZmlsZSgiaHR0cHM6Ly93d3cuc3RhdGlzdGlrcG9ydGFsLmRlL3NpdGVzL2RlZmF1bHQvZmlsZXMvMjAyNC0wNy92Z3JkbF9yMmIxX2JzMjAyMy54bHN4IiwgIi4vZGF0YS9CSVBfMjAyMy54bHN4IikKfQoKYGBgCgpEaWUgRGF0ZW4genVyIFZlcnNjaHVsZHVuZyB3b2xsZW4gd2lyIHVudGVyICJTY2h1bGRlbl8yMDIyLnhsc3giLCBkYSBkaWUgVGFiZWxsZSB6d2FyIGltIE3DpHJ6IDIwMjQgdmVyw7ZmZmVudGxpY2h0IHd1cmRlLCBzaWNoIGFiZXIgYXVmIGRhcyBKYWhyIDIwMjIgYmV6aWVodC4KCkRpZSBgaWZgLUJlZGluZ3VuZyBwcsO8ZnQgb2IgZGVyIGFuZ2VnZWJlbmUgRGF0ZW5zYXR6IGJlcmVpdHMgaW4gdW5zZXJlbSAiZGF0YSIgT3JkbmVyIGVudGhhbHRlbiBpc3QuCldlbm4gZGllcyBkZXIgRmFsbCBpc3QsIHNvIHdlcmRlbiBzaWUgbmljaHQgbWVociBlcm5ldXQgaGVydW50ZXJnZWxhZGVuLgoKV2lyIGhhYmVuIGhpZXIgYXVjaCBkaWUgRGF0ZW4gZsO8ciBkaWUgQXJiZWl0c2xvc2VucXVvdGUgYXVzIGRlbSBKYWhyIDIwMjIgaGVydW50ZXJnZWxhZGVuLCBkYSB3aXIgZGllIHBhc3NlbmRlbiBJbmZvcm1hdGlvbmVuIHp1ciBQcm8tS29wZiBWZXJzY2h1bGR1bmcgZGVyIEdlbWVpbmRlbiBudXIgYXVzIGRlbSBKYWhyICoqMjAyMioqIG9ubGluZSBlcmhhbHRlbi4gCgpJY2ggaGFiZSBpaG5lbiBkaWUgTGlua3MgenVtIG5ldWVyZW4gRGF0ZW5zw6R0emVuIGbDvHIgZGllIEFyYmVpdHNsb3NpZ2tlaXQgaW4gZGVuIFIgQ2h1bmsgZ2VzY2hyaWViZW4uCkbDvHIgZGFzIEJJUCBoYWJlbiB3aXIgZGllIG5ldWVzdGUgRGF0ZW5yZWloZSB2b24gQXVndXN0IDIwMjMgYmV6b2dlbiBkYSB3aXIgaGllciBQYW5lbGRhdGVuIGhhYmVuIHVuZCBrZWluZSBRdWVyc2Nobml0dHNkYXRlbiAod2FzIGRpZXMgZ2VuYXUgaGVpw590IHdpcmQgaW0gTGF1ZmUgZGVyIENhc2UtU3R1ZHkgZXJsw6R1dGVydCkuCgojIERhdGVuIGVpbmxlc2VuCgpJbSBuw6RjaHN0ZW4gU2Nocml0dCBzb2xsdGVuIHdpciBkaWUgRGF0ZW4gaW4gUiBlaW5sZXNlbi4KQmVpbSBEb3dubG9hZCBoYWJlbiB3aXIgc2Nob24gYW4gZGVuIFVSTHMgdW5kIGF1Y2ggYW4gZGVuIGhlcnVudGVyZ2VsYWRlbmVuIERhdGVpZW4gZ2VzZWhlbiwgZGFzcyBlcyBzaWNoIGJlaSB6d2VpIERvd25sb2FkcyB1bSBaSVAtQXJjaGl2ZSAoQklQIHVuZCBBbnphaGwgYW4gQXJiZWl0c2xvc2VuKSBoYW5kZWx0LgpEaWVzZSBaSVAtQXJjaGl2ZSBrw7ZubmVuIHdpciBtaXR0ZWxzIFIgZXh0cmFoaWVyZW4sIGRpZXNlIGFuc2NobGllw59lbmQgZWlubGVzZW4gdW5kIGRpZSBleHRyYWhpZXJ0ZSBEYXRlaSB3aWVkZXIgbMO2c2NoZW4uCkRpZXMgaGF0IGRlbiBWb3J0ZWlsLCBkYXNzIFNpZSBpaHJlIERhdGVpZW4gcGxhdHpzcGFyZW5kIGF1ZiBpaHJlciBGZXN0cGxhdHRlIGFic3BlaWNoZXJuIHVuZCBudXIgYmVpIEJlZGFyZiBlbnRzcHJlY2hlbmQgZW50cGFja2VuLgoKIyBBbnphaGwgYW4gQXJiZWl0c2xvc2VuCgpJbSBlcnN0ZW4gU2Nocml0dCB3b2xsZW4gd2lyIHVucyBtaXQgZGVuIERhdGVuIHp1IGRlbiBBcmJlaXRzbG9zZW4gYmVzY2jDpGZ0aWdlbiB1bmQgZGllIGluIGRlbSBaSVAtQXJjaGl2IGVudGhhbHRlbmVuIERhdGVpZW4gaW4gUiBlaW5sZXNlbi4KCiMjIFpJUC1BcmNoaXYgZW50cGFja2VuCgpgYGB7cn0KIyDDlmZmbmVuIGRlcyBaSVAtQXJjaGl2cwojIEVzIHNpbmQgendlaSBUYWJlbGxlbiBpbiBkZW0gWklQIEFyY2hpdiwgd2lyIGludGVyZXNzaWVyZW4gdW5zIGbDvHIgZGllIEFuemFobCBkZXIgQXJiZWl0c2xvc2VuIHVuZCB3w6RobGVuIGRpZXNlIG1pdCBkZW0ga2xlaW5lbiBbMV0gYXVzCmFsb19uYW1lIDwtIGFzLmNoYXJhY3Rlcih1bnppcCgiLi9kYXRhL0FyYmVpdHNsb3NlXzIwMjIueGxzeC56aXAiLCBsaXN0ID0gVFJVRSkkTmFtZSkKYWxvX25hbWUgPC0gYWxvX25hbWVbMV0KdW56aXAoIi4vZGF0YS9BcmJlaXRzbG9zZV8yMDIyLnhsc3guemlwIiwgYWxvX25hbWUpCmBgYAoKT2ssIG51biBoYWJlbiB3aXIgZGllIERhdGVuIGVudHppcHBlZCB1bmQgc2VoZW4sIGRhc3MgZXMgc2ljaCB1bSBlaW5lIEV4Y2VsLURhdGVpIGhhbmRlbHQuCkRvY2ggZGllc2UgaGF0IHNlaHIgdmllbGUgdW50ZXJzY2hpZWRsaWNoZSBUYWJlbGxlbmJsw6R0dGVyLgpXaWUgd2lzc2VuIHdpciwgd2VsY2hlcyBUYWJlbGxlbmJsYXR0IGbDvHIgdW5zIHZvbiBJbnRlcmVzc2UgaXN0PwoKRGllcyBrw7ZubmVuIHdpciB6dW0gRWluZW4gbWl0IGBleGNlbF9zaGVldHNgIGhlcmF1c2ZpbmRlbiwgd2VubiBkaWUgVGFiZWxsZW5ibMOkdHRlciBndXQgYmVuYW5udCBzaW5kOgoKYGBge3J9CmV4Y2VsX3NoZWV0cyhhbG9fbmFtZSkKYGBgCgpEYSBkaWUgVGFiZWxsZW5ibMOkdHRlciBqZWRvY2ggbmljaHQgdW5iZWRpbmd0IHZpZWxzYWdlbmQgYmVzY2hyaWZ0ZXQgc2luZCBzb2xsdGVuIHdpciBkYXMgVGFiZWxsZW5ibGF0dCAiSW5oYWx0IiBlaW5sZXNlbiB1bmQgdW5zIGRpZXNlcyBhbnNjaGF1ZW4uCkV2ZW50dWVsbCB3ZXJkZW4gd2lyIGhpZXIgc2NobGF1ZXIuCgpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KYWxvX2luaGFsdCA8LSByZWFkX3hsc3goYWxvX25hbWUsIHNoZWV0ID0gIkluaGFsdHN2ZXJ6ZWljaG5pcyIpCmhlYWQoYWxvX2luaGFsdCwgMjApCmBgYAoKSGllciBlcmhhbHRlbiB3aXIgZWluZW4gw5xiZXJibGljayDDvGJlciBkaWUgVGFiZWxsZW5ibMOkdHRlciB1bmQgd28gd2VsY2hlIEluZm9ybWF0aW9uZW4gYWJnZXNwZWljaGVydCBzaW5kLgpEYSB3aXIgdW5zIGbDvHIgZGVuIEJlc3RhbmQgYW4gQXJiZWl0c2xvc2VuIGludGVyZXNzaWVyZW4gdW5kIGhpZXIgbmljaHQgbmFjaCBGcmF1ZW4gdW5kIE3DpG5uZXJuIG9kZXIgU3RhYXRzYW5nZWjDtnJpZ2tlaXQgdW50ZXJzY2hlaWRlbiBtw7ZjaHRlbiwgaXN0IGRhcyBUYWJlbGxlbmJsYXR0IGBHZXNhbXRgIGbDvHIgdW5zIGRhcyByaWNodGlnZS4KCioqQWx0ZXJuYXRpdmU6KiogU2NoYXVlbiBTaWUgc2ljaCBkaWUgRXhjZWwtRGF0ZWkgaW4gRXhjZWwgb2RlciBMaWJyZU9mZmljZSBhbiB1bmQgZW50c2NoZWlkZW4gU2llIGRhbm4sIHdlbGNoZXMgVGFiZWxsZW5ibGF0dCBTaWUgZWlubGVzZW4gbcO2Y2h0ZW4uCgojIyBFbnRwYWNrdGUgRGF0ZWkgZWlubGVzZW4KCk51biB3aXNzZW4gd2lyLCB3ZWxjaGVzIFRhYmVsbGVuYmxhdHQgZGllIGbDvHIgdW5zIHdpY2h0aWdlIEluZm9ybWF0aW9uIGVudGjDpGx0OgoKYGBge3IsIG1lc3NhZ2U9RkFMU0V9CmFsbyA8LSByZWFkX3hsc3goYWxvX25hbWUsIHNoZWV0PSJHZXNhbXQiKQoKaGVhZChhbG8sMTApCmBgYAoKT2suIEhpZXIgaXN0IGVzIHdvaGwgbmljaHQgdm9ydGVpbGhhZnQgdm9uIGRlciBlcnN0ZW4gWmVpbGUgYWIgZGllIEluZm9ybWF0aW9uZW4gYXVzIGRlbSBUYWJlbGxlbmJsYXR0IGVpbnp1bGVzZW4uClNvIHdpZSBlcyBhdXNzaWVodCBzaW5kIGluIGRlbiBlcnN0ZW4gNSBaZWlsZW4gSW5mb3JtYXRpb25lbiB6dW0gVGFiZWxsZW5ibGF0dCB1bmQgZGVtIEJlcmljaHRzamFociBlbnRoYWx0ZW4sIGRhbm4ga29tbXQgZWluZSBsZWVyZSBaZWlsZSB1bmQgZGFubiBrb21tZW4gZGllIGVpZ2VudGxpY2hlbiBTcGFsdGVuYmVzY2hyaWZ0dW5nZW4uCkRpZXNlIHNpbmQgZGFubiBqZWRvY2ggd2llZGVydW0gaW4gNCBaZWlsZW4gdW50ZXJ0ZWlsdC4gV2FzIHNpbmQgZGVubiBoaWVyIG51biBkaWUgU3BhbHRlbsO8YmVyc2NocmlmdGVuLCBkLmguIGRpZSBWYXJpYWJsZW5uYW1lbiBpbSBEYXRlbnNhdHo/CgojIyBTcGV6aWZpemllcmVuIHdlbGNoZSBTcGFsdGVuIGVpbmdlbGVzZW4gd2VyZGVuIHNvbGxlbgoKSGllcnp1IMO8YmVybGVnZW4gd2lyIHVucyBmb2xnZW5kZXM6CgotICAgV2VsY2hlIEluZm9ybWF0aW9uIGJlbsO2dGlnZW4gd2lyIGF1cyBkZXIgVGFiZWxsZQoKICAgIC0gICBEaWUgQW56YWhsIGFsbGVyIEFyYmVpdHNsb3NlbiBwcm8gR2VtZWluZGUgKGQuaC4gU0dCIElJIHVuZCBJSUkgZ2VtZWluc2FtKSAqKmF1cyBkZW0gSmFociAyMDIyKioKICAgIC0gICBEaWUgQW56YWhsIGRlciBBcmJlaXRzbG9zZW4gcHJvIEdlbWVpbmRlIGbDvHIgZWluZW4gYmVzdGltbXRlbiBSZWNodHNrcmVpcyAoei5CLiBudXIgU0dCIElJKQogICAgLSAgIERpZSBBbnphaGwgZGVyIEFyYmVpdHNsb3NlbiBwcm8gR2VtZWluZGUgZsO8ciBlaW5lbiBiZXN0aW1tdGVuIFJlY2h0c2tyZWlzIHVuZCBlaW4gYmVzdGltbXRlcyBBbHRlciAoei5CLiBTR0IgSUkgYWxsZSB1bnRlciAyNSBKYWhyZSkKCi0gICBXaWUga8O2bm5lbiB3aXIgZGllIHZvbiB1bnMgYmVuw7Z0aWd0ZSBJbmZvcm1hdGlvbiBtw7ZnbGljaHN0IGVpbmZhY2ggZXh0cmFoaWVyZW4KCkluIHVuc2VyZW0gRmFsbCBiZW7DtnRpZ2VuIHdpciBkaWUgSW5mb3JtYXRpb24genVyIGR1cmNoc2Nobml0dGxpY2hlbiBBbnphaGwgYWxsZXIgQXJiZWl0c2xvc2VuIHBybyBHZW1laW5kZSBhdXMgZGVtIEphaHIgMjAyMiwgZC5oLiB1bnMgaW50ZXJlc3NpZXJ0IFNwYWx0ZSBgLi4uM2AuCldlaXRlcmhpbiBiZW7DtnRpZ2VuIHdpciBlaW5lIGVpbmRldXRpZyB6dXp1b3JkbmVuZGUgIkdlbWVpbmRlLUlEIiB1bSBkaWVzZSBEYXRlbnF1ZWxsZSBzcMOkdGVyIG1pdCBhbmRlcmVuIERhdGVucXVlbGxlbiB2ZXJiaW5kZW4genUga8O2bm5lbi4KQXXDn2VyZGVtIHfDpHJlIGRlciBOYW1lIGRlciBHZW1laW5kZSBub2NoIGVpbmUgd2ljaHRpZyBJbmZvcm1hdGlvbi4KRGVyIGVpbmZhY2hzdGUgV2VnIGFuIGRpZXNlIEluZm9ybWF0aW9uIHp1IGdlbGFuZ2VuIGlzdCBkaWUgZXJzdGVuIGFjaHQgWmVpbGVuIGFienVzY2huZWlkZW4gdW5kIGRpZSBEYXRlbiBlcnN0IGFiIGRvcnQgZWluenVsZXNlbi4KQW5zY2hsaWXDn2VuZCBiZWhhbHRlbiB3aXIgbnVyIGRpZSBlcnN0ZW4gMyBTcGFsdGVuLCBkYSB1bnMgbnVyIGRpZXNlIGludGVyZXNzaWVyZW4uCgpEYXMgd29sbGVuIHdpciBudW4gbWFjaGVuOgoKYGBge3J9CiMgRGF0ZW4gZWlubGVzZW4gdm9uIFRhYmVsbGVuYmxhdHQgIkdlc2FtdCIsIG9obmUgZGllIGVyc3RlbiA4IFplaWxlbgphbG8gPC0gcmVhZF94bHN4KGFsb19uYW1lLCBzaGVldCA9ICJHZXNhbXQiLCBza2lwID0gOCkKCiMgRGllIGVudHppcHB0ZSBEYXRlaSB3aWVkZXIgbMO2c2NoZW4KdW5saW5rKGFsb19uYW1lKQoKIyBOdW4gYmVzY2hyw6Rua2VuIHdpciB1bnMgYXVmIGRpZSBlcnN0ZSB1bmQgZHJpdHRlIFNwYWx0ZSB1bmQgdHJlbm5lbiBkZW4gTmFtZW4gZGVyIFJlZ2lvbiAod2VsY2hlciBpbiBTcGFsdGUgYC4uLjFgIGdlbGlzdGV0IHdpcmQpIHVuZCBkZXJlbiAiR2VtZWluZGUtSUQiLCBkZW0gc29nZW5hbm50ZW4gIlJlZ2lvbmFsc2NobHVlc3NlbCIgdm9uZWluYW5kZXIuCiMgRGllIFNwYWx0ZSAzIHdvbGxlbiB3aXIgYW5zY2hsaWXDn2VuZCBpbiAiYWxvIiB1bWJlbmVubmVuCiMgV2VpdGVyaGluIGzDtnNjaGVuIHdpciBhbGxlIFplaWxlbiwgZsO8ciBkaWUgImFsbyIgYXVmIE5BIGdlc2V0enQgaXN0IHVuZCBkaWUgZXJzdGUgWmVpbGUsIGRpZSBhbGxlIEFyYmVpdHNsb3NlbiBpbiBnYW56IERldXRzY2hsYW5kIGJlaW5oYWx0ZXQKIyBXaXIgc3BlaWNoZXJuIGRlbiBEYXRlbnNhdHogYWxzIGBkYXRhX2Fsb2AgYWIKZGF0YV9hbG8gPC0gYWxvIHw+IAogIHNlbGVjdChjKGAuLi4xYCwgSmFocmVzZHVyY2hzY2huaXR0ZSwgYC4uLjNgKSkgfD4KICBtdXRhdGUoUmVnaW9uYWxzY2hsdWVzc2VsID0gc3RyX2V4dHJhY3QoYC4uLjFgLCAiW1s6ZGlnaXQ6XV0rIiksCiAgICAgICAgIEdlbWVpbmRlID0gc3RyX2V4dHJhY3QoYC4uLjFgLCAiW0EtWl0uKiIpKSB8PgogIG11dGF0ZShhbG8gPSBhcy5udW1lcmljKGAuLi4zYCkpIHw+CiAgc2VsZWN0KC1jKGAuLi4xYCwgSmFocmVzZHVyY2hzY2huaXR0ZSwgYC4uLjNgKSkgfD4KICBmaWx0ZXIoIWlzLm5hKGFsbykpCgojIERpZSBlcnN0ZW4gZHJlaSBaZWlsZW4gYmVpbmhhbHRlbiBrZWluZSBudXR6bGljaGVuIEluZm9ybWF0aW9uZW4sIGQuaC4gd2lyIGzDtnNjaGVuIGRpZXNlCmRhdGFfYWxvIDwtIGRhdGFfYWxvWy1jKDEsMiksXQpgYGAKCiMjIEtvbnNpc3RlbnpjaGVjawoKTnVuIHNvbGx0ZW4gd2lyIG5vY2ggZGllIERhdGVuIGF1ZiBLb25zaXN0ZW56IHByw7xmZW4uCkQuaC4gbWFjaGVuIGRpZSBBbmdhYmVuIFNpbm4gdW5kIHNpbmQgZGllIERhdGVuIGluIHNpY2gga29uc2lzdGVudD8KSGllcmbDvHIgc29sbHRlbiB3aXIgenVtIEVpbmVuIGV4dGVybmUgRGF0ZW5xdWVsbGVuIHVudGVyc3VjaGVuIHVuZCB6dW0gQW5kZXJlbiBkaWUgRGF0ZW4gaW50ZXJuIHByw7xmZW4uCgpXaXIgaGFiZW4gaGllciBzZWhyIGZlaW5ncmFudWxhcmUgSW5mb3JtYXRpb25lbiDDvGJlciBkaWUgQXJiZWl0c2xvc2VuemFobCBpbiAyMDIyIHZvcmxpZWdlbiwgamVkb2NoIGvDtm5uZW4gd2lyIGRpZSBEYXRlbiBhdWNoIGF1ZiBlaW5lIGjDtmhlcmUgRWJlbmUgYWdncmVnaWVyZW4gdW5kIGRhbWl0IGxlaWNodCBtaXQgYW5kZXJlbiBRdWVsbGVuIHZlcmdsZWljaGVuLgpEaWVzIHdvbGxlbiB3aXIgaGllciB0dW46CgotICAgWnVuw6RjaHN0IGxhc3NlbiB3aXIgdW5zIGRpZSBBbnphaGwgYW4gQXJiZWl0c2xvc2VuIGbDvHIgamVkZXMgQnVuZGVzbGFuZCBpbiAyMDIyIGF1c2dlYmVuLiBJbiB1bnNlcmVtIERhdGVuc2F0eiBzaW5kIGRpZXMgYWxsZSBEYXRlbnB1bmt0ZSBtaXQgZWluZW0gendlaXN0ZWxsaWdlbiBgUmVnaW9uYWxzY2hsdWVzc2VsYC4gV2lyIG3DvHNzZW4gaGllciBiZWFjaHRlbiwgZGFzcyBkaWUgYFJlZ2lvbmFsc2NobHVlc3NlbGAgaW4gZGVyIEtsYXNzZSBgY2hhcmFjdGVyYCB2b3JsaWVnZW4sIGQuaC4gYWxzIFN0cmluZ3MgdW5kIG5pY2h0IGFscyBaYWhsLiBEZXNoYWxiIGvDtm5uZW4gd2lyIGRpZSBBbnphaGwgYW4gIkJ1Y2hzdGFiZW4iIGbDvHIgamVkZW4gYFJlZ2lvbmFsc2NobHVlc3NlbGAgesOkaGxlbi4gRGllcyBnZXNjaGllaHQgw7xiZXIgZGVuIEJlZmVobCBgbmNoYXIoKWAgKG51bWJlciBvZiBjaGFyYWN0ZXJzKQotICAgTnVuIHNvbGx0ZW4gd2lyIGVpbmUgYW5kZXJlIERhdGVucXVlbGxlIGhlcmFuemllaGVuIHVuZCBkaWUgSW5mb3JtYXRpb25lbiBnZWdlbmNoZWNrZW4uIEJzcHcuIGvDtm5udGVuIHdpciBbZGllIEFuemFobCBkZXIgQXJiZWl0c2xvc2VuIGbDvHIgZGFzIEphaHIgMjAyMiB1bnRlcnRlaWx0IG5hY2ggTMOkbmRlcm4gaGVyYW56aWVoZW5dKGh0dHBzOi8vc3RhdGlzdGlrLmFyYmVpdHNhZ2VudHVyLmRlL1N0YXRpc3Rpa2RhdGVuL0RldGFpbC8yMDIyMTIvaWlpYTQvYWt0LWRhdC1qei9ha3QtZGF0LWp6LWQtMC0yMDIyMTIteGxzeC54bHN4KS4gKFRhYmVsbGVuYmxhdHQgOCkKCmBgYHtyfQpjaGVja19hbG9fYnVuZGVzbGFuZCA8LSBkYXRhX2FsbyB8PgogIGZpbHRlcihuY2hhcihSZWdpb25hbHNjaGx1ZXNzZWwpID09IDIpIHw+CiAgcmVuYW1lKGJ1bmRlc2xhbmQgPSBSZWdpb25hbHNjaGx1ZXNzZWwpCgpjaGVja19hbG9fYnVuZGVzbGFuZApgYGAKCldlbm4gd2lyIGRpZSDDnGJlcnByw7xmdW5nIG1pdCBkZXIgYW5kZXJlbiBUYWJlbGxlIGRlciBCdW5kZXNhZ2VudHVyIGbDvHIgQXJiZWl0IG1hY2hlbiwgZGFubiBzaW5kIGJlaWRlIERhdGVucmVpaGVuIGlkZW50aXNjaC4KCk51biB3b2xsZW4gd2lyIG5vY2ggZGllIGludGVybmUgS29uc2lzdGVueiDDvGJlcnByw7xmZW4uCkhpZXJmw7xyIGJlcmVjaG5lbiB3aXIgZGllIEFuemFobCBhbiBBcmJlaXRzbG9zZW4gZsO8ciBqZWRlcyBCdW5kZXNsYW5kIGFscyBTdW1tZSBkZXIgQXJiZWl0c2xvc2VuIGVpbmVyIGplZGVuIEdlbWVpbmRlLgoKYGBge3J9CiMgTnVyIEdlbWVpbmRlZGF0ZW4gbnV0emVuLCBkYW5uIGF1ZiBCdW5kZXNsYW5kZWJlbmRlIGRpZSBTdW1tZSBhdXMgZGVuIEdlbWVpbmRlZGF0ZW4gYmVyZWNobmVuCmFsb19tZXRhIDwtIGRhdGFfYWxvIHw+IAogIGZpbHRlcihuY2hhcihSZWdpb25hbHNjaGx1ZXNzZWwpID09IDgpIHw+CiAgbXV0YXRlKGxhbmRrcmVpcyA9IHN0cl9leHRyYWN0KFJlZ2lvbmFsc2NobHVlc3NlbCwgIl4uezV9IiksCiAgICAgICAgIGJ1bmRlc2xhbmQgPSBzdHJfZXh0cmFjdChSZWdpb25hbHNjaGx1ZXNzZWwsICJeLnsyfSIpKQoKYWxvX2J1bmRlc2xhbmQgPC0gYWxvX21ldGEgfD4KICBncm91cF9ieShidW5kZXNsYW5kKSB8PgogIHN1bW1hcmlzZSh0b3RhbF9hbG8gPSBzdW0oYWxvKSkKCmFsb19sYW5ka3JlaXMgPC0gYWxvX21ldGEgfD4KICBncm91cF9ieShsYW5ka3JlaXMpIHw+CiAgc3VtbWFyaXNlKHRvdGFsX2FsbyA9IHN1bShhbG8pKSB8PgogIHJlbmFtZShSZWdpb25hbHNjaGx1ZXNzZWwgPSBsYW5ka3JlaXMpCmBgYAoKVW0gZWluZW4gYmVzc2VyZW4gw5xiZXJibGljayB6dSBlcmhhbHRlbiBrw7ZubmVuIHdpciB1bnNlcmUgYmVyZWNobmV0ZW4gdW5kIGRpZSB2b24gZGVyIEFnZW50dXIgZsO8ciBBcmJlaXQgYW5nZWdlYmVuZW4gV2VydGUgbWl0ZWluYW5kZXIgdmVyYmluZGVuIHVuZCBkaWUgRGlmZmVyZW56IHp3aXNjaGVuIGRlbiBiZWlkZW4gVGFiZWxsZW4gYmVyZWNobmVuOgoKYGBge3J9CmNoZWNrX2NvbnNpdGVuY3kgPC0gbGVmdF9qb2luKGNoZWNrX2Fsb19idW5kZXNsYW5kLCBhbG9fYnVuZGVzbGFuZCwgYnkgPSAiYnVuZGVzbGFuZCIpCgpjaGVja19jb25zaXRlbmN5IDwtIGNoZWNrX2NvbnNpdGVuY3kgfD4KICBtdXRhdGUoZGlmZiA9IGFsbyAtIHRvdGFsX2FsbykKCmNoZWNrX2NvbnNpdGVuY3kKYGBgCgpVbnNlcmUgQW5hbHlzZW4gemVpZ2VuLCBkYXNzIGVzIGtlaW5lIERpZmZlcmVuemVuIHp3aXNjaGVuIGRlbiBEYXRlbiBnaWJ0LCBkaWUgdm9uIGRlciBCdW5kZXNhZ2VudHVyIGbDvHIgQXJiZWl0IGF1ZiBMYW5kZXMtIHVuZCBCdW5kZXNlYmVuZSB2ZXLDtmZmZW50bGljaGVuLgoKIyBQcm8tS29wZiBWZXJzY2h1bGR1bmcKCkRlciBuw6RjaHN0ZSBEYXRlbnNhdHogYmVpbmhhbHRldCBkaWUgUHJvLUtvcGYtVmVyc2NodWxkdW5nIGRlciBkZXV0c2NoZW4gR2VtZWluZGVuLgpIaWVyIGhhbmRlbHQgZXMgc2ljaCB3aWVkZXIgdW0gUXVlcnNjaG5pdHRzZGF0ZW4gYXVmIEdlbWVpbmRlZWJlbmUgYXVzIGRlbSBKYWhyIDIwMjIuCgpEaWVzZW4gRGF0ZW5zYXR6IGvDtm5uZW4gd2lyIHZvbiBkZXIgSG9tZXBhZ2UgZGVzIFN0YXRpc3Rpc2NoZW4gQnVuZGVzYW10ZXMgZGlyZWt0IGFscyBFeGNlbC1UYWJlbGxlIGhlcnVudGVybGFkZW4gdW5kIG3DvHNzZW4ga2VpbiBaSVAtQXJjaGl2IGVudHBhY2tlbi4KQWxsZXJkaW5ncyBzZWhlbiB3aXIgc2VociBzY2huZWxsLCBkYXMgYXVjaCBkaWVzZXIgRGF0ZW5zYXR6IHNlaW5lIFTDvGNrZW4gYmVpbSBFaW5sZXNlbiBiZXJlaXRow6RsdCwgaW5zYmVzb25kZXJlIHdlbm4gd2lyIHNjaGF1ZW4sIHdlbGNoZSBUYWJlbGxlbmJsw6R0dGVyIGbDvHIgdW5zZXJlIEFuYWx5c2UgcmVsZXZhbnQgc2luZDoKCmBgYHtyfQpleGNlbF9zaGVldHMoIi4vZGF0YS9TY2h1bGRlbl8yMDIyLnhsc3giKQpgYGAKCiMjIE1laHJlcmUgVGFiZWxsZW5ibMOkdHRlciBlaW5sZXNlbgoKTnVuIHNpbmQgbmljaHQgbWVociBhbGxlIEluZm9ybWF0aW9uZW4gaW4gKiplaW5lbSBUYWJlbGxlbmJsYXR0KiogZW50aGFsdGVuLCBzb25kZXJuIGplZGVzIEJ1bmRlc2xhbmQgaGF0IHNlaW4gZWlnZW5lcyBUYWJlbGxlbmJsYXR0IGJla29tbWVuLgpTcHJpY2gsIHdpciBtw7xzc2VuIGVpbmUgTcO2Z2xpY2hrZWl0IGZpbmRlbiBhbGxlIFRhYmVsbGVuYmzDpHR0ZXIgbmFjaGVpbmFuZGVyIGVpbnp1bGVzZW4gdW5kIHp1IHZlcmFyYmVpdGVuLgoKRGllcyB3b2xsZW4gd2lyIG1pdCBlaW5lciBTY2hsZWlmZSBsw7ZzZW4sIGRvY2ggenVlcnN0IHNjaGF1ZW4gd2lyIHVucyBhbiwgd2VsY2hlIEluZm9ybWF0aW9uZW4gd2lyIGF1cyBkZW4gVGFiZWxsZW5ibMOkdHRlcm4gYmVuw7Z0aWdlbjoKCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQpzaCA8LSByZWFkX3hsc3goIi4vZGF0YS9TY2h1bGRlbl8yMDIyLnhsc3giLCBzaGVldCA9ICJTSCIpCmhlYWQoc2gsMjApCmBgYAoKRsO8ciB1bnMgd2ljaHRpZyBzaW5kIGRpZSBJbmZvcyBiemdsLiBkZXMgIlJlZ2lvbmFsc2NobMO8c3NlbCIsIGRlciAiR2VtZWluZGVuYW1lIiwgZGllICJFaW53b2huZXIiIHVuZCBkaWUgIlNjaHVsZGVuIGRlcyDDtmZmZW50bGljaGVuIEJlcmVpY2hzIGluc2dlc2FtdCIuClp1ciDDnGJlcnByw7xmdW5nIHVuc2VyZXIgRXJnZWJuaXNzZSBuZWhtZW4gd2lyIG5vY2ggZGllICJTY2h1bGRlbiBqZSBFaW53b2huZXIiIG1pdCBpbiB1bnNlcmVuIERhdGVuc2F0eiBhdWYsIGQuaC4KZGllIGVyc3RlbiBzZWNocyBTcGFsdGVuLgpXZWl0ZXJoaW4gc3RlaGVuIHVuc2VyZSBWYXJpYWJsZW5iZXplaWNobnVuZ2VuIGluIFplaWxlIDUsIGQuaC4gd2lyIGlnbm9yaWVyZW4gZGllIGVyc3RlbiA0IFplaWxlbiBiZWltIEVpbmxlc2VuLgoKRGVyIMOcYmVyc2ljaHQgaGFsYmVyIHdvbGxlbiB3aXIgbm9jaCBlaW5lIFNwYWx0ZSBoaW56dWbDvGdlbiwgd2VsY2hlIGRlbiBOYW1lbiBkZXMgVGFiZWxsZW5ibGF0dGVzIGVudGjDpGx0LCB3ZWxjaGVzIHdpciBnZXJhZGUgZWluZ2VsZXNlbiBoYWJlbi4KCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQojIEVpbmxlc2VuIGRlcyBUYWJlbGxlbmJsYXR0ZXMgIlNIIiBvaG5lIGRpZSBlcnN0ZW4gNSBaZWlsZW4gdW5kIG51ciBkaWUgU3BhbHRlbiAxLTcKc2NodWxkZW5faW5kaXZpZHVlbGwgPC0gcmVhZF94bHN4KCIuL2RhdGEvU2NodWxkZW5fMjAyMi54bHN4Iiwgc2hlZXQgPSAiU0giLCBza2lwID0gNSlbMTo3XQojIFVtYmVuZW5uZW4gZGVyIGVyc3RlbiA3IFNwYWx0ZW4KY29sbmFtZXMoc2NodWxkZW5faW5kaXZpZHVlbGwpIDwtIGMoIlJlZ2lvbmFsc2NobHVlc3NlbCIsICJHZW1laW5kZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVmVyd2FsdHVuZ3Nmb3JtIiwgIkVpbndvaG5lciIsICJTY2h1bGRlbl9nZXNhbXQiLCAiVmVyYWVuZGVydW5nX1ZvcmphaHIiLCAiU2NodWxkZW5fcHJvX2tvcGYiKQoKIyBadXPDpHR6bGljaGUgU3BhbHRlIGhpbnp1ZsO8Z2VuIG1pdCBkZW0gTmFtZW4gZGVzIFRhYmVsbGVuYmxhdHRlcwpzY2h1bGRlbl9pbmRpdmlkdWVsbCRCdW5kZXNsYW5kIDwtICJTSCIKYGBgCgpPaywgbnVuIGhhYmVuIHdpciBkaWUgRGF0ZW4gZsO8ciBTY2hsZXN3aWctSG9sc3RlaW4gZWluZ2VsZXNlbiB1bmQga8O2bm5lbiBmw7xyIGFsbGUgYW5kZXJlbiBEYXRlbiBnbGVpY2ggdm9yZ2VoZW4uCgpJbiBkZW4gbsOkY2hzdGVuIGRyZWkgQ2h1bmtzIHNlaGVuIFNpZSB1bnRlcnNjaGllZGxpY2hlIFZhcmlhbnRlbiB1bSBkaWUgRGF0ZW4gZWluenVsZXNlbi4gSW4gZGVyIGVyc3RlbiBWYXJpYW50ZSBudXR6ZW4gd2lyIGVpbmUgYGZvcmAtU2NobGVpZmUgdW0gYWxsZSBCdW5kZXNsw6RuZGVyIChUYWJlbGxlbmJsw6R0dGVyKSBpbiBkZXIgZ2xlaWNoZW4gRm9ybSBkdXJjaHp1Z2VoZW4gKGRpZXNlIEFydCBkZXIgU2NobGVpZmUga2VubmVuIFNpZSB2ZXJtdXRsaWNoIGF1cyBhbmRlcmVuIEluZm9ybWF0aWstVmVyYW5zdGFsdHVuZ2VuL1Byb2dyYW1taWVyc3ByYWNoZW4pOgoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIGV2YWwgPSBGQUxTRX0KIyBEYXRlbiBtaXQgZm9yLVNjaGxlaWZlIGVpbmxlc2VuIChTdHJ1a3R1ciBnbGVpY2ggd2llIGltIHZvcmhlcmlnZW4gQ2h1bmspCnNoZWV0X25hbWVzIDwtIGV4Y2VsX3NoZWV0cygiLi9kYXRhL1NjaHVsZGVuXzIwMjIueGxzeCIpCiMgRWlubGVzZW4gZGVyIFRhYmVsbGVuYmzDpHR0ZXIgNi0xOCAoYWxsZSBCdW5kZXNsw6RuZGVyKQpzaGVldF9yZWFkIDwtIHNoZWV0X25hbWVzWzY6MThdCgpzY2h1bGRlbl9pbmRpdmlkdWVsbCA8LSBOVUxMCgpmb3IgKGkgaW4gMTpsZW5ndGgoc2hlZXRfcmVhZCkpewogIHRtcCA8LSByZWFkX3hsc3goIi4vZGF0YS9TY2h1bGRlbl8yMDIyLnhsc3giLCBzaGVldCA9IHNoZWV0X3JlYWRbaV0sIHNraXAgPSA1KVsxOjddCiAgdG1wJEJ1bmRlc2xhbmQgPC0gc2hlZXRfcmVhZFtpXQogIGNvbG5hbWVzKHRtcCkgPC0gYygiUmVnaW9uYWxzY2hsdWVzc2VsIiwgIkdlbWVpbmRlIiwgIlZlcndhbHR1bmdzZm9ybSIsIAogICAgICAgICAgICAgICAgICAgICAiRWlud29obmVyIiwgIlNjaHVsZGVuX2dlc2FtdCIsICJWZXJhZW5kZXJ1bmdfVm9yamFociIsICJTY2h1bGRlbl9wcm9fa29wZiIsICJCdW5kZXNsYW5kIikKICAjIERhdGVuIGFsbGVyIHdlaXRlcmVuIFRhYmVsbGVuYmzDpHR0ZXIgdW50ZXIgZGVuIGFrdHVlbGxlbiBEYXRlbnNhdHogYW5oZWZ0ZW4KICBzY2h1bGRlbl9pbmRpdmlkdWVsbCA8LSBiaW5kX3Jvd3Moc2NodWxkZW5faW5kaXZpZHVlbGwsIHRtcCkKfQpgYGAKCkRpZSB6d2VpdGUgTcO2Z2xpY2hrZWl0IHfDpHJlIGVzIGRpZSBGdW5rdGlvbiBzYXBwbHkoKSB6dSBudXR6ZW4uIEQuaC4gU2llIG51dHplbiBkaWUgZnVua3Rpb25hbGUgUHJvZ3JhbW1pZXJ1bmcgaW4gUiwgd2VsY2hlIG1laXN0IGRldXRsaWNoIGVmZml6aWVudGVyIGlzdCBhbHMgZWluZSBgZm9yYC1TY2hsZWlmZToKCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCBldmFsID0gRkFMU0V9CiMgRGF0ZW4gbWl0IHNhcHBseSgpLVNjaGxlaWZlIGVpbmxlc2VuIChTdHJ1a3R1ciBnbGVpY2ggd2llIGltIHZvcmhlcmlnZW4gQ2h1bmspCnNoZWV0X25hbWVzIDwtIGV4Y2VsX3NoZWV0cygiLi9kYXRhL1NjaHVsZGVuXzIwMjIueGxzeCIpCiMgRWlubGVzZW4gZGVyIFRhYmVsbGVuYmzDpHR0ZXIgNi0xOCAoYWxsZSBCdW5kZXNsw6RuZGVyKQpzaGVldF9yZWFkIDwtIHNoZWV0X25hbWVzWzY6MThdCgojIHNhcHBseSgpIGFuc3RlbGxlIGRlciBmb3ItU2NobGVpZmUgdmVyd2VuZGVuCnNjaHVsZGVuX2luZGl2aWR1ZWxsIDwtIGJpbmRfcm93cygKICBzYXBwbHkoc2hlZXRfcmVhZCwgZnVuY3Rpb24oc2hlZXQpIHsKICAgIHRtcCA8LSByZWFkX3hsc3goIi4vZGF0YS9TY2h1bGRlbl8yMDIyLnhsc3giLCBzaGVldCA9IHNoZWV0LCBza2lwID0gNSlbMTo3XQogICAgdG1wJEJ1bmRlc2xhbmQgPC0gc2hlZXQKICAgIGNvbG5hbWVzKHRtcCkgPC0gYygiUmVnaW9uYWxzY2hsdWVzc2VsIiwgIkdlbWVpbmRlIiwgIlZlcndhbHR1bmdzZm9ybSIsIAogICAgICAgICAgICAgICAgICAgICAgICJFaW53b2huZXIiLCAiU2NodWxkZW5fZ2VzYW10IiwgIlZlcmFlbmRlcnVuZ19Wb3JqYWhyIiwgIlNjaHVsZGVuX3Byb19rb3BmIiwgIkJ1bmRlc2xhbmQiKQogICAgcmV0dXJuKHRtcCkKICB9LCBzaW1wbGlmeSA9IEZBTFNFKQopCmBgYAoKSW4gZWluZXIgZHJpdHRlbiBNw7ZnbGljaGtlaXQgbnV0emVuIFNpZSBkYXMgUGFrZXQgYHB1cnJyYCAod2VsY2hlcyBUZWlsIGRlciBgdGlkeXZlcnNlYC1GYW1pbGllIGlzdCkgdW5kIGRvcnQgZGllIEZ1bmt0aW9uIGBtYXBfZGYoKWAgdW0gZGllIERhdGVuIHZla3RvcmlzaWVydCBlaW56dWxlc2VuLiBEaWVzZXIgdmVrdG9yaXNpZXJ0ZSBBbnNhdHogbWl0IGBtYXBfZGYoKWAgYXVzIGRlbSBgcHVycnJgLVBha2V0IGlzdCBlaW5lIGJlc29uZGVycyBlaW5mYWNoZSB1bmQgZWZmaXppZW50ZSBNZXRob2RlLCB1bSBtZWhyZXJlIEV4Y2VsLVRhYmVsbGVuIGdsZWljaHplaXRpZyBlaW56dWxlc2VuIHVuZCB6dSB2ZXJhcmJlaXRlbi4gQW5zdGF0dCBqZWRlIFRhYmVsbGUgZWluemVsbiBkdXJjaHp1Z2VoZW4sIHdpcmQgaGllciBkZXIgZ2xlaWNoZSBWb3JnYW5nIGF1ZiBhbGxlIFRhYmVsbGVuYmzDpHR0ZXIgYXVmIGVpbm1hbCBhbmdld2VuZGV0LiBEYWR1cmNoIHNwYXJlbiBTaWUgc2ljaCBkaWUgVmVyd2VuZHVuZyB2b24gU2NobGVpZmVuLCB1bmQgZGVyIENvZGUgd2lyZCBlaW5mYWNoZXIgdW5kIMO8YmVyc2ljaHRsaWNoZXIuIEF1w59lcmRlbSBwYXNzdCBkaWVzZXIgQW5zYXR6IGd1dCBpbiBkYXMgdGlkeXZlcnNlLcOWa29zeXN0ZW0sIGRhcyBzcGV6aWVsbCBmw7xyIERhdGVuYW5hbHlzZW4gb3B0aW1pZXJ0IGlzdC4KCmBgYHtyfQojIERhdGVuIG1pdCBtYXBfZGYoKSBlaW5lIFZla3RvcmlzaWVydGUgRm9ybSB1bSBkaWUgRGF0ZW4gZWluenVsZXNlbiAoU3RydWt0dXIgZ2xlaWNoIHdpZSBpbSB2b3JoZXJpZ2VuIENodW5rKQpzaGVldF9uYW1lcyA8LSBleGNlbF9zaGVldHMoIi4vZGF0YS9TY2h1bGRlbl8yMDIyLnhsc3giKQojIEVpbmxlc2VuIGRlciBUYWJlbGxlbmJsw6R0dGVyIDYtMTggKGFsbGUgQnVuZGVzbMOkbmRlcikKc2hlZXRfcmVhZCA8LSBzaGVldF9uYW1lc1s2OjE4XQoKIyBWZWt0b3Jpc2llcnRlIEZvcm0gbWl0IHB1cnJyOjptYXBfZGYoKSB1bSBkaWUgdW50ZXJzY2hpZWRsaWNoZW4gVGFiZWxsZW5ibMOkdHRlciBlaW56dWxlc2VuIHVuZCBkaWUgRGF0ZW4genUgZWluZW0gRGF0ZW5zYXR6IHp1c2FtbWVuenVmw7xnZW4Kc2NodWxkZW5faW5kaXZpZHVlbGwgPC0gbWFwX2RmKHNoZWV0X3JlYWQsIGZ1bmN0aW9uKHNoZWV0KSB7CiAgdG1wIDwtIHJlYWRfeGxzeCgiLi9kYXRhL1NjaHVsZGVuXzIwMjIueGxzeCIsIHNoZWV0ID0gc2hlZXQsIHNraXAgPSA1KVsxOjddCiAgdG1wJEJ1bmRlc2xhbmQgPC0gc2hlZXQKICBjb2xuYW1lcyh0bXApIDwtIGMoIlJlZ2lvbmFsc2NobHVlc3NlbCIsICJHZW1laW5kZSIsICJWZXJ3YWx0dW5nc2Zvcm0iLCAKICAgICAgICAgICAgICAgICAgICAgIkVpbndvaG5lciIsICJTY2h1bGRlbl9nZXNhbXQiLCAiVmVyYWVuZGVydW5nX1ZvcmphaHIiLCAiU2NodWxkZW5fcHJvX2tvcGYiLCAiQnVuZGVzbGFuZCIpCiAgcmV0dXJuKHRtcCkKfSkKYGBgCgoKCiMjIFZhcmlhYmxlbiB1bWZvcm1lbgoKYGBge3J9CmhlYWQoc2NodWxkZW5faW5kaXZpZHVlbGwsMzApCmBgYAoKV2lyIHNlaGVuLCBlcyBnaWJ0IGltbWVyIG5vY2ggZWluaWdlIFByb2JsZW1lOgoKLSAgIERpZSBXZXJ0ZSB1bnNlcmVyIFZhcmlhYmxlbiBzdGVoZW4gbmljaHQgZGlyZWt0IHVudGVyIGRlbSBWYXJpYWJsZW5uYW1lbiwgZGFzIGlzdCBmw7xyIHVucyBuaWNodCBvcHRpbWFsIHVuZCBpc3QgZGVyIEFub3JkbnVuZyBpbiBkZXIgRXhjZWwgRGF0ZWkgZ2VzY2h1bGRldC4KCiAgICAtICAgRGllcyBrw7ZubmVuIHdpciBhbSBlaW5mYWNoc3RlbiBiZXJlaW5pZ2VuIGluZGVtIHdpciBhbGxlIGBOQWBzIGltIFJlZ2lvbmFsc2NobMO8c3NlbCBlbnRmZXJuZW4gKGtlaW4gUmVnaW9uYWxzY2hsw7xzc2VsIGJlZGV1dGV0IGtlaW5lIFp1b3JkbnVuZyB6dSBlaW5lciBSZWdpb24gdW5kIGRhbWl0IGbDvHIgdW5zIG5pY2h0IG5hY2h2b2xsemllaGJhcikuCgotICAgRGllIFZhcmlhYmxlbiAiRWlud29obmVyIiwgIlNjaHVsZGVuX2dlc2FtdCIgdW5kICJTY2h1bGRlbl9wcm9fS29wZiIgc2luZCBhbGxlIGFscyBgY2hhcmFjdGVyYCBoaW50ZXJsZWd0IChgPGNocj5gIHVudGVyIGRlbSBWYXJpYWJsZW5uYW1lbiBpbiBkZXIgdm9yaGVyaWdlbiBUYWJlbGxlKSwgd2lyIHdvbGxlbiBkaWVzZSBqZWRvY2ggaW4gbnVtZXJpc2NoZXIgRm9ybSB1bSBCZXJlY2hudW5nZW4gZHVyY2hmw7xocmVuIHp1IGvDtm5uZW4KCiAgICAtICAgRGVyIEdydW5kIGbDvHIgZGllIEtsYXNzZSBgY2hhcmFjdGVyYCBrYW5uIHouQi4gaW4gWmVpbGUgMjggYmVvYmFjaHRldCB3ZXJkZW4uIEhpZXIgd3VyZGVuIGdlc2Nod2VpZnRlIEtsYW1tZXJuIHZlcndlbmRldCB1bSBkaWUgU3VtbWUgYWxsZXIgVmFyaWFibGVuIGVpbmVzIEFtdHNnZWJpZXRzLCBMYW5ka3JlaXMsIFJlZ2lvbiBldGMuIHp1IGtlbm56ZWljaG5lbi4KICAgIC0gICBJbSBlcnN0ZW4gU2Nocml0dCB3b2xsZW4gd2lyIGRpZXNlIFN1bW1lbiBlaW5mYWNoIGlnbm9yaWVyZW4gZGEgd2lyIGRpZSBqZXdlaWxpZ2VuIFN1bW1lbiBhdWNoIHNlbGJzdCBiZXJlY2huZW4ga8O2bm5lbi4KCi0gRGllICJWZXJhZW5kZXJ1bmdfVm9yamFociIgaXN0IGbDvHIgdW5zZXJlIHdlaXRlcmUgQW5hbHlzZSBuaWNodCByZWxldmFudCwgZGFoZXIgd29sbGVuIHdpciBkaWVzZSBhdXMgZGVtIERhdGVuc2F0eiBlbnRmZXJuZW4KCkFuc2NobGllw59lbmQgd29sbGVuIHdpciBub2NoIGRlbiBgbGFuZGtyZWlzYCBhbHMgZGllIGVyc3RlbiA1IFplaWNoZW4gaW0gUmVnaW9uYWxzY2hsw7xzc2VsIGRlZmluaWVyZW4uCgpgYGB7ciwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KIyBEaWUgRGF0ZW4gd3VyZGVuIG5vY2ggbmljaHQgc2Now7ZuIGVpbmdlbGVzZW4sIGluIGRlciBFeGNlbCBUYWJlbGxlIAojIHdhcmVuIGRpZSBWYXJpYWJsZW5uYW1lbiDDvGJlciBtZWhyZXJlIFJlaWhlbiBnZXpvZ2VuLCBkaWVzIG3DvHNzZW4gd2lyIG5vY2ggYXVzZ2xlaWNoZW4Kc2NodWxkZW5fYmVyZWluaWd0IDwtIHNjaHVsZGVuX2luZGl2aWR1ZWxsIHw+CiAgZmlsdGVyKCFpcy5uYShSZWdpb25hbHNjaGx1ZXNzZWwpKSB8PgogIG11dGF0ZShTY2h1bGRlbl9nZXNhbXQgPSBhcy5udW1lcmljKFNjaHVsZGVuX2dlc2FtdCksCiAgICAgICAgIEVpbndvaG5lciA9IGFzLm51bWVyaWMoRWlud29obmVyKSwKICAgICAgICAgU2NodWxkZW5fcHJvX2tvcGYgPSBhcy5udW1lcmljKFNjaHVsZGVuX3Byb19rb3BmKSkgfD4KICBtdXRhdGUobGFuZGtyZWlzID0gc3RyX2V4dHJhY3QoUmVnaW9uYWxzY2hsdWVzc2VsLCAiXi57NX0iKSkgfD4KICBzZWxlY3QoLVZlcmFlbmRlcnVuZ19Wb3JqYWhyKQoKYGBgCgpFcyB3dXJkZW4gaW1tZXIgbm9jaCBlaW5pZ2UgYE5BYHMgZXJ6ZXVndC4KRGllc2Ugd29sbGVuIHdpciB1bnMgbm9jaCBuw6RoZXIgYW5zY2hhdWVuOgoKYGBge3J9CmZpbHRlcihzY2h1bGRlbl9iZXJlaW5pZ3QsIGlzLm5hKEVpbndvaG5lcikpCmBgYAoKV2lyIG3DvHNzZW4gd29obCBub2NoIG1laHIgYXVzc2NobGllw59lbiBhbHMgbnVyIGBOQWBzIGJlaW0gUmVnaW9uYWxzY2hsw7xzc2VsLCBpbnNnZXNhbXQgMjQwMCBFaW50csOkZ2UgYmVpIGRlbmVuIGRpZSBWYXJpYWJsZSAiRWlud29obmVyIiBuaWNodCB2b3JoYW5kZW4gaXN0LgpXaXIgaGF0dGVuIGJlcmVpdHMgZ2VzZWhlbiwgZGFzcyBkaWUgU3VtbWUgYWxsZXIgRWlud29obmVyIGVpbmVzIExhbmRrcmVpc2VuIG1pdCBgeyBaYWhsIH1gIGluIGRlciBFeGNlbC1EYXRlaSBoZXJ2b3JnZWhvYmVuIHdpcmQuCldlbm4gd2lyIGhpZXIgaW4gUiBlaW5lIFR5cHVtd2FuZGx1bmcgZXJ6d2luZ2VuLCBkYW5uIGthbm4gUiBtaXQgZGVuIGB7fWAgbmljaHRzIGFuZmFuZ2VuIHVuZCBnaWJ0IHVucyBkZXNoYWxiIGVpbiBgTkFgIGF1cy4KV2lyIGvDtm5uZW4gaGllciBhbGxlIEVpbnRyw6RnZSwgYmVpIGRlbmVuIGRpZSBFaW53b2huZXIgZWluIGBOQWAgc3RlaGVuIGhhYmVuLCBsw7ZzY2hlbiwgZGEgd2lyIGRpZSBEYXRlbiBzZWxic3QgYXVmIEJhc2lzIGRlciBJbmZvcm1hdGlvbmVuIHp1IGRlbiBHZW1laW5kZW4gZGVzIExhbmRrcmVpc2VzIGJlcmVjaG5lbiBrw7ZubmVuLgoKYGBge3J9CnNjaHVsZGVuX2JlcmVpbmlndCA8LSBzY2h1bGRlbl9iZXJlaW5pZ3QgfD4KICAjbWFuY2hlIExhbmRrcmVpc2UgaGFiZW4ga2VpbmUgSW5mb3MgenUgZGVuIEVpbndvaG5lcm4sIGRpZXNlIGVudGZlcm5lbiB3aXIKICBmaWx0ZXIoICFpcy5uYSggRWlud29obmVyICkgKQpgYGAKCiMjIEtvbnNpc3RlbnpjaGVjawoKIyMjIEJlcmVjaG51bmcgZGVyIFNjaHVsZGVuIHBybyBLb3BmIHZvbiBIYW5kCgpVbSBkaWUgaW50ZXJuZSBWYWxpZGl0w6R0IHVuc2VyZXIgRGF0ZW4gYmV1cnRlaWxlbiB6dSBrw7ZubmVuIHdvbGxlbiB3aXIgaW0gZXJzdGVuIFNjaHJpdHQgZWluZSBWYXJpYWJsZSBgU2NodWxkZW5fcHJvX0tvcGZfbmV3YCBnZW5lcmllcmVuLCB3ZWxjaGUgZGllIGBTY2h1bGRlbl9wcm9fS29wZmAgdm9uIEhhbmQgYmVyZWNobmV0LgpXaWUgc2Nob24gW2ltIEFic2Nobml0dCBWYXJpYWJsZW4gdW1mb3JtZW5dKCN2YXJpYWJsZW4tdW1mb3JtZW4pIGVyd8OkaG50LCBtw7xzc2VuIHdpciBoaWVyZsO8ciBqZWRvY2ggZXJzdCBmb2xnZW5kZXMgYmVhY2h0ZW4sIGJldm9yIHdpciBCZXJlY2hudW5nZW4gZHVyY2hmw7xocmVuIGvDtm5uZW46CgotICAgV2lyIG3DvHNzZW4gZGllIGdlc2Nod2VpZnRlbiBLbGFtbWVybiBlbnRmZXJuZW4gKG1pdCBgZ3N1YigiW3t9XSIpYCksIGFscyBhdWNoIGRpZSBMZWVyemVpY2hlbiBpbm5lcmhhbGIgZGVyIFphaGxlbiAoei5CLiAxNSA2NTMpLCB3YXMgd2lyIG1pdCBgZ3N1YigiW1s6c3BhY2U6XV0iKWAgZXJyZWljaGVuLiBUdW4gd2lyIGRhcyBuaWNodCwgc28gd8O8cmRlbiB3aXIgd2llZGVyIGBOQWBzIGltIERhdGVuc2F0eiBlcmhhbHRlbi4gV2lyIHR1biBkaWVzIGhpZXIgaW4gZWluZW0gQmVmZWhsIGBnc3ViKCJbWzpzcGFjZTpde31dIilgCgpgYGB7cn0KIyBFcnN0ZWxsZW4gZGVyIFZlcmdsZWljaHN0YWJlbGxlCnNjaHVsZGVuX2NvbnNpc3RlbmN5IDwtIHNjaHVsZGVuX2luZGl2aWR1ZWxsIHw+CiAgZmlsdGVyKCFpcy5uYShFaW53b2huZXIpICYgIWlzLm5hKFJlZ2lvbmFsc2NobHVlc3NlbCkpIHw+CiAgIyBXaXIgd2VuZGVuIGRpZSBGdW5rdGlvbiDDvGJlciBkaWUgYW5nZWdlYmVuZW4gVmFyaWFibGVuIGFuIHVuZCBudXR6ZW4gZGFmw7xyIGFjcm9zcygpKQogIG11dGF0ZShhY3Jvc3MoYyhTY2h1bGRlbl9nZXNhbXQsIFNjaHVsZGVuX3Byb19rb3BmLCBFaW53b2huZXIpLCAKICAgICAgICAgICAgICAgICMgRGllIEZ1bmt0aW9uZW4sIGRpZSB3aXIgYW53ZW5kZW4gc2luZCBnc3ViKCkgdW5kIHN0cl9yZW1vdmVfYWxsKCkKICAgICAgICAgICAgICAgIH4gYXMubnVtZXJpYyhnc3ViKCJbWzpzcGFjZTpde31dIiwgIiIsLikpKSwKICAgICAgICAgU2NodWxkZW5fcHJvX2tvcGZfbmV3ID0gcm91bmQoU2NodWxkZW5fZ2VzYW10IC8gRWlud29obmVyLCAyKSkgfD4KICBtdXRhdGUobGFuZGtyZWlzID0gc3RyX2V4dHJhY3QoUmVnaW9uYWxzY2hsdWVzc2VsLCAiXi57NX0iKSwKICAgICAgICAgZGlmZmVyZW56ID0gU2NodWxkZW5fcHJvX2tvcGYgLSBTY2h1bGRlbl9wcm9fa29wZl9uZXcpCmBgYAoKTnVuIGvDtm5uZW4gd2lyIHVucyBhbnNjaGF1ZW4sIG9iIGRpZSB2b24gdW5zIGJlcmVjaG5ldGVuIHVuZCBkaWUgdm9tIFN0YXRpc3Rpc2NoZW4gQnVuZGVzYW10IGFuZ2VnZWJlbmVuIFdlcnRlIHp1IGRlbiAiU2NodWxkZW5fcHJvX0tvcGYiIHNpZ25pZmlrYW50IHZvbmVpbmFuZGVyIGFid2VpY2hlbjoKCmBgYHtyfQojIHJhbmdlKHNjaHVsZGVuX2NvbnNpc3RlbmN5JGRpZmZlcmVueikKIyBvZGVyIHNjaMO2bmUgc2tpbQpza2ltX3dpdGhvdXRfY2hhcnRzKHNjaHVsZGVuX2NvbnNpc3RlbmN5JGRpZmZlcmVueikKYGBgCgpEaWUgRGlmZmVyZW56ZW4gbGllZ2VuIHp3aXNjaGVuICsvLSA1MCBDZW50IHVuZCBrw7ZubmVuIHZlcm11dGxpY2ggYXVmIFJ1bmR1bmdzZmVobGVyIHp1csO8Y2tnZWbDvGhydCB3ZXJkZW4uCkQuaC4gaGllciBrw7ZubmVuIHdpciBkaWUgdm9tIHN0YXRpc3Rpc2NoZW4gQnVuZGVzYW10IGhlcmF1c2dlZ2ViZW5lbiBCZXJlY2hudW5nZW4gYXVmIEdlbWVpbmRlZWJlbmUgdmVyaWZpemllcmVuLgoKIyMjIFZlcmdsZWljaCBkZXIgU2NodWxkZW4gcHJvIEtvcGYgYXVmIExhbmRrcmVpc2ViZW5lCgpJbiBlaW5lbSB3ZWl0ZXJlbiBLb25zaXN0ZW56Y2hlY2sgd29sbGVuIHdpciBkaWUgZHVyY2hzY2huaXR0bGljaGUgVmVyc2NodWxkdW5nIHBybyBLb3BmIGF1ZiBMYW5ka3JlaXNlYmVuZSBzZWxic3QgYmVyZWNobmVuIHVuZCBkaWVzZSBtaXQgZGVuIHZvbSBTdGF0aXN0aXNjaGVuIEJ1bmRlc2FtdCBhbmdlZ2ViZW5lbiBXZXJ0ZW4gaW4gZGVyIFRhYmVsbGUgYWJnbGVpY2hlbi4KCkhpZXJmw7xyIGVudG5laG1lbiB3aXIgZGVyIFRhYmVsbGUgenVlcnN0IGFsbGUgSW5mb3JtYXRpb25lbiBiemdsLgpBbnphaGwgZGVyICJFaW53b2huZXIiLCAiU2NodWxkZW5fZ2VzYW10IiB1bmQgIlNjaHVsZGVuX3Byb19Lb3BmIiBmw7xyIGRpZSBMYW5ka3JlaXNlLgpJbSBEYXRlbnNhdHogc2VoZW4gd2lyLCBkYXNzIGRpZSBSZWdpb25hbHNjaGx1ZXNzZWwgZsO8ciBMYW5ka3JlaXNlIGRpZSBXb3J0ZSAiU3VtbWUiIHVuZCAiS3JlaXMiIGVudGhhbHRlbiwgd2VubiBkYXMgU3RhdGlzdGlzY2hlIEJ1bmRlc2FtdCBkaWUgRGF0ZW4gYXVmIExhbmRrcmVpc2ViZW5lIGFnZ3JlZ2llcnQuCkRhcyB3b2xsZW4gd2lyIGltIGZvbGdlbmRlbiBudXR6ZW46CgpgYGB7cn0KIyBXaXIgZmlsdGVybiBhbGxlIFJlaWhlbiBoZXJhdXMsIHdlbGNoZSAiX1N1bW1lIiBvZGVyICJLcmVpcyIgaW0gUmVnaW9uYWxzY2hsw7xzc2VsIGF1ZndlaXNlbgojIEFuc2NobGllw59lbmQgYmVyZWNobmVuIHdpciBkaWUgZHVyY2hzY2huaXR0bGljaGUgVmVyc2NodWxkdW5nIGF1ZiBMYW5ka3JlaXNlYmVuZQphdmdfdmVyc2NoX2tyZWlzIDwtIHNjaHVsZGVuX2NvbnNpc3RlbmN5IHw+CiAgZmlsdGVyKHN0cl9kZXRlY3QoUmVnaW9uYWxzY2hsdWVzc2VsLCAiX1N1bW1lIikgJiBzdHJfZGV0ZWN0KFJlZ2lvbmFsc2NobHVlc3NlbCwgIktyZWlzIikpIHw+CiAgZ3JvdXBfYnkobGFuZGtyZWlzLCBHZW1laW5kZSkgfD4KICBzdW1tYXJpc2UoYXZnX3ZlcnNjaHVsZHVuZyA9IFNjaHVsZGVuX3Byb19rb3BmLCAKICAgICAgICAgICAgZWlud29obmVyID0gRWlud29obmVyLCAKICAgICAgICAgICAgR2VzYW10c2NodWxkID0gU2NodWxkZW5fZ2VzYW10LAogICAgICAgICAgICAjIEtlaW5lIEdydXBwaWVydW5nIG1laHIgaW0gT3V0cHV0IGR1cmNoOgogICAgICAgICAgICAuZ3JvdXBzID0gJ2Ryb3AnKSB8PgogIGFycmFuZ2UoZGVzYyhhdmdfdmVyc2NodWxkdW5nKSkKCiMgSGllciBiZXJlY2huZW4gd2lyIGRpZSBEYXRlbiBzZWxic3QKYXZnX3ZlcnNjaF9rcmVpc19jYWxjIDwtIHNjaHVsZGVuX2NvbnNpc3RlbmN5IHw+CiAgIyBFcnNldHplIEVpbndvaG5lciBtaXQgMCBmw7xyIGFsbGUgUmVnaW9uYWxzY2hsw7xzc2VsIGtsZWluZXIgYWxzIDEyCiAgbXV0YXRlKEVpbndvaG5lciA9IGlmZWxzZShuY2hhcihSZWdpb25hbHNjaGx1ZXNzZWwpPDEyLDAsIEVpbndvaG5lcikpIHw+CiAgIyBOdXIgR2VtZWluZGVuIGJldHJhY2h0ZW4KICBmaWx0ZXIobmNoYXIoUmVnaW9uYWxzY2hsdWVzc2VsKT49NSAmIHN0cl9kZXRlY3QoUmVnaW9uYWxzY2hsdWVzc2VsLCAiX1N1bW1lIik9PUZBTFNFKSB8PgogICMgQXVmIExhbmRrcmVpc2ViZW5lIGdydXBwaWVyZW4KICBncm91cF9ieShsYW5ka3JlaXMpIHw+CiAgc3VtbWFyaXNlKGVpbndvaG5lcl9jYWxjID0gc3VtKEVpbndvaG5lciwgbmEucm0gPSBUUlVFKSwgCiAgICAgICAgICAgIEdlc2FtdHNjaHVsZF9jYWxjID0gc3VtKFNjaHVsZGVuX2dlc2FtdCwgbmEucm0gPSBUUlVFKSwgCiAgICAgICAgICAgIGF2Z192ZXJzY2h1bGR1bmdfY2FsYyA9IHJvdW5kKEdlc2FtdHNjaHVsZF9jYWxjL2VpbndvaG5lcl9jYWxjLDIpLAogICAgICAgICAgICAjIEtlaW5lIEdydXBwaWVydW5nIG1laHIgaW0gT3V0cHV0IGR1cmNoOgogICAgICAgICAgICAuZ3JvdXBzID0gJ2Ryb3AnKSB8PgogIGFycmFuZ2UoZGVzYyhhdmdfdmVyc2NodWxkdW5nX2NhbGMpKQoKIyBWZXJiaW5kZSBiZWlkZSBEYXRlbnPDpHR6ZSB1bmQgYmVyZWNobmUgb2IgZXMgc2lnaW5maWthbnRlIEFid2VpY2h1bmdlbiB6d2lzY2hlbiAKIyBkZW4gYXVzZ2VnZWJlbmVuIHVuZCBiZXJlY2huZXRlbiBXZXJ0ZW4gZ2lidApuZXcgPC0gbGVmdF9qb2luKGF2Z192ZXJzY2hfa3JlaXMsIGF2Z192ZXJzY2hfa3JlaXNfY2FsYywgYnk9ImxhbmRrcmVpcyIpIHw+CiAgbXV0YXRlKGRpZmZlcmVueiA9IGF2Z192ZXJzY2h1bGR1bmcgLSBhdmdfdmVyc2NodWxkdW5nX2NhbGMpIHw+CiAgYXJyYW5nZSggZGVzYyhkaWZmZXJlbnopICkKYGBgCgpgYGB7cn0KIyBFcmdlYm5pcyBhbnNjaGF1ZW4KI3JhbmdlKG5ldyRkaWZmZXJlbnopCiMgb2RlciBtaXQgc2tpbQpza2ltX3dpdGhvdXRfY2hhcnRzKG5ldyRkaWZmZXJlbnopCmBgYAoKRGllIERpZmZlcmVuemVuIGxpZWdlbiBoaWVyIHp3aXNjaGVuIC0wLDQ5IEV1cm8gYmlzICswLDUwIEV1cm8gKGltIER1cmNoc2Nobml0dCBiZWkgMCwwMSBFdXJvKSB1bmQga8O2bm5lbiB2ZXJtdXRsaWNoIGF1ZiBSdW5kdW5nc2ZlaGxlciB6dXLDvGNrZ2Vmw7xocnQgd2VyZGVuLgpELmguIGhpZXIga8O2bm5lbiB3aXIgZGllIHZvbSBzdGF0aXN0aXNjaGVuIEJ1bmRlc2FtdCBoZXJhdXNnZWdlYmVuZW4gQmVyZWNobnVuZ2VuIGF1ZiBMYW5ka3JlaXNlYmVuZSB2ZXJpZml6aWVyZW4uCgojIEJydXR0b2lubGFuZHNwcm9kdWt0CgpJbSBuw6RjaHN0ZW4gU2Nocml0dCB3b2xsZW4gd2lyIHVucyBkaWUgRGF0ZW4genVtIEJydXR0b2lubGFuZHNwcm9kdWt0IGVpbnplbG5lciBMYW5ka3JlaXNlIGFuc2NoYXVlbiB1bmQgZGllc2UgaW4gUiBlaW5sZXNlbi4KV2lyIGhhYmVuIGRpZXNlIGRpcmVrdCBhbHMgRXhjZWwgRGF0ZWkgaGVydW50ZXJnZWxhZGVuIHVuZCBrw7ZubmVuIGRpZSBEYXRlaSBpbiBSIGVpbmxlc2VuLgpOZWJlbiBkZW0gQklQIGJlemllaGVuIHdpciBhdXMgZGllc2VtIEV4Y2VsLUZpbGUgZGllIEFuemFobCBhbiBFcndlcmJzdMOkdGlnZW4sIG1pdCBkZW5lbiB3aXIgc3DDpHRlciBkaWUgQXJiZWl0c2xvc2VucXVvdGUgYmVyZWNobmVuIGvDtm5uZW4gdW5kIGRpZSBBbnphaGwgYW4gRWlud29obmVyLCBtaXQgZGVuZW4gd2lyIGRhcyBCSVAtcHJvLUtvcGYgYmVyZWNobmVuIGvDtm5uZW4uCgojIyBOdXIgZWluemVsbmUgU3BhbHRlbiBlaW5sZXNlbgoKRm9sZ2VuZGUgU2Nocml0dGUgd29sbGVuIHdpciBpbiBlaW5lbSBDaHVuayBlcmxlZGlnZW46CgotICAgQmV0cmFjaHRlbiBkZXIgRGF0ZW4KCiAgICAtICAgVGFiZWxsZW5ibGF0dCAiMS4xIiBpc3QgZsO8ciB1bnNlcmUgQW5hbHlzZSBhdXNzY2hsYWdnZWJlbmQgKGbDvHIgZGFzIEJJUCkKICAgIC0gICBUYWJlbGxlbmJsYXR0ICIzLjEiIGlzdCBmw7xyIGRpZSBBbnphaGwgYW4gRXJ3ZXJic3TDpHRpZ2VuIGF1c3NjaGxhZ2dlYmVuZAogICAgLSAgIFRhYmVsbGVuYmxhdHQgIjUiIGlzdCBmw7xyIGRpZSBBbnphaGwgYW4gRWlud29obmVybiBhdXNzY2hsYWdnZWJlbmQKCi0gICBEaWUgZXJzdGVuIHZpZXIgWmVpbGVuIGJlbsO2dGlnZW4gd2lyIG5pY2h0CgotICAgRGllIGxldHp0ZSBaZWlsZSBlbnRow6RsdCBlaW5lIGt1cnplIEJlc2NocmVpYnVuZyBkaWUgd2lyIG5pY2h0IGJlbsO2dGlnZW4gLT4gVm9yZ2VoZW46IEJlaGFsdGUgYWxsZSBaZWlsZW4sIGJlaSBkZXIgYExmZC4gTnIuYCBudW1lcmlzY2ggaXN0CgotICAgRGllIGZvbGdlbmRlbiBWYXJpYWJsZW4gYmVuw7Z0aWdlbiB3aXIgbmljaHQgZsO8ciB1bnNlcmUgQW5hbHlzZSwgZGllc2Uga8O2bm5lbiBlbnRmZXJudCB3ZXJkZW46IGBMZmQuIE5yLmAsIGBFVS1Db2RlYCwgYE5VVFMgMWAsIGBOVVRTIDJgLCBgTlVUUyAzYCwgYExhbmRgLCBgR2ViaWV0c2VpbmhlaXRgCgpgYGB7ciwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KIyBCbGF0dCAxLjEgZWlubGVzZW4gdW5kIGRpZSBlcnN0ZW4gNCBaZWlsZW4gc2tpcHBlbgpiaXBfbmFtZSA8LSAiLi9kYXRhL0JJUF8yMDIzLnhsc3giCmJpcCA8LSByZWFkX3hsc3goYmlwX25hbWUsIHNoZWV0PSIxLjEiLCBza2lwID0gNCkKZXJ3ZXJiIDwtIHJlYWRfeGxzeChiaXBfbmFtZSwgc2hlZXQ9IjMuMSIsIHNraXAgPSA0KQplaW53b2huZXIgPC0gcmVhZF94bHN4KGJpcF9uYW1lLCBzaGVldCA9ICI1Iiwgc2tpcCA9IDQpCgojIFplaWxlIGzDtnNjaGVuIGluIGRlciBkaWUgYExmZC4gTnIuYCBuaWNodCBudW1tZXJpc2NoIGlzdAojIFp1c8OkdHpsaWNoZSBTcGFsdGVuIGzDtnNjaGVuCmJpcF93aWRlIDwtIGJpcCB8PiAKICBmaWx0ZXIoaXMubmEoYXMubnVtZXJpYyhgTGZkLiBOci5gKSk9PUZBTFNFKSB8PgogIHNlbGVjdCgtYyhgTGZkLiBOci5gLCBgRVUtQ29kZWAsIGBOVVRTIDFgLCBgTlVUUyAyYCwgYE5VVFMgM2AsIExhbmQsIEdlYmlldHNlaW5oZWl0KSkgfD4KICByZW5hbWUoUmVnaW9uYWxzY2hsdWVzc2VsID0gYFJlZ2lvbmFsLXNjaGzDvHNzZWxgKQoKIyBaZWlsZSBsw7ZzY2hlbiBpbiBkZXIgZGllIGBMZmQuIE5yLmAgbmljaHQgbnVtbWVyaXNjaCBpc3QKIyBadXPDpHR6bGljaGUgU3BhbHRlbiBsw7ZzY2hlbgplcndlcmJfd2lkZSA8LSBlcndlcmIgfD4gCiAgZmlsdGVyKGlzLm5hKGFzLm51bWVyaWMoYExmZC4gTnIuYCkpPT1GQUxTRSkgfD4KICBzZWxlY3QoLWMoYExmZC4gTnIuYCwgYEVVLUNvZGVgLCBgTlVUUyAxYCwgYE5VVFMgMmAsIGBOVVRTIDNgLCBMYW5kLCBHZWJpZXRzZWluaGVpdCkpIHw+CiAgcmVuYW1lKFJlZ2lvbmFsc2NobHVlc3NlbCA9IGBSZWdpb25hbC1zY2hsw7xzc2VsYCkKCmVpbndvaG5lcl93aWRlIDwtIGVpbndvaG5lciB8PgogIGZpbHRlcihpcy5uYShhcy5udW1lcmljKGBMZmQuIE5yLmApKT09RkFMU0UpIHw+CiAgc2VsZWN0KC1jKGBMZmQuIE5yLmAsIGBFVS1Db2RlYCwgYE5VVFMgMWAsIGBOVVRTIDJgLCBgTlVUUyAzYCwgTGFuZCwgR2ViaWV0c2VpbmhlaXQpKSB8PgogIHJlbmFtZShSZWdpb25hbHNjaGx1ZXNzZWwgPSBgUmVnaW9uYWwtc2NobMO8c3NlbGApCgpoZWFkKGJpcF93aWRlKQpgYGAKCkRpZXNlciBEYXRlbnNhdHogaXN0IGVpbiBzb2dlbmFubnRlcyBQYW5lbC4KSW4gZGVuIHZvcmhlcmlnZW4gRGF0ZW5zw6R0emVuIHp1ciBBbnphaGwgZGVyIEFyYmVpdHNsb3NlbiB1bmQgZGVyIFByby1Lb3BmLVZlcnNjaHVsZHVuZyBoYXR0ZW4gd2lyIFF1ZXJzY2huaXR0c2RhdGVuIChkLmguIERhdGVuIG51ciBkYXMgSmFociAyMDIyKSBnZWdlYmVuLgpOdW4gaGFiZW4gd2lyIGRpZSBFbnR3aWNrbHVuZyBkZXMgQklQLCBkaWUgQW56YWhsIGFuIEVyd2VyYnN0w6R0aWdlbiB1bmQgZGllIEFuemFobCBhbiBFaW53b2huZXJuIHNlaXQgMTk5MiBiaXMgMjAyMiBmw7xyIGFsbGUgTGFuZGtyZWlzZSBpbiBEZXV0c2NobGFuZC4KCiMjIERhdGVuIGluIGRhcyBgbG9uZ2AtRm9ybWF0IMO8YmVyZsO8aHJlbgoKQWxsZXJkaW5ncyBzaW5kIGRpZSBEYXRlbnPDpHR6ZSBpbSBgd2lkZWAtRm9ybWF0LCBkLmguIG5pY2h0IGB0aWR5YCB1bmQgZGFtaXQgbmljaHQgc28sIHdpZSB3aXIgaWhuIGdlcm5lIGjDpHR0ZW4uCkVyaW5uZXJuIHdpciB1bnMgbm9jaCBhbiBkaWUgQmVkaW5ndW5nZW4gZGFtaXQgZWluIERhdGVuc8OkdHplbiBgdGlkeWAgaXN0PwoKSW0gbsOkY2hzdGVuIFNjaHJpdHQgd29sbGVuIHdpciBkZW4gRGF0ZW5zYXR6IG51biBpbnMgYGxvbmdgLUZvcm1hdCDDvGJlcmbDvGhyZW4gdW5kIG51dHplbiBoaWVyZsO8ciBkaWUgRnVua3Rpb24gYHBpdm90X2xvbmdlcmA6CgpgYGB7ciwgZXZhbD1GQUxTRX0KYmlwX2xvbmcgPC0gcGl2b3RfbG9uZ2VyKGJpcF93aWRlLCBjb2xzID0gYygiMTk5MiI6IjIwMjIiKSAsIG5hbWVzX3RvID0gIkphaHIiLCB2YWx1ZXNfdG8gPSAiQklQIikKCiMgUHJvZHV6aWVydCBkZW4gZm9sZ2VuZGVuIEZlaGxlcjoKIyBGZWhsZXI6IENhbid0IGNvbWJpbmUgYDE5OTJgIDxjaGFyYWN0ZXI+IGFuZCBgMjAwMGAgPGRvdWJsZT4uCmBgYAoKTGVpZGVyIGlzdCBlcyBoaWVyIG5pY2h0IG3DtmdsaWNoIGRpZSBEYXRlbnPDpHR6ZSBkaXJla3QgaW4gZGFzIGBsb25nYC1Gb3JtYXQgenUgw7xiZXJmw7xocmVuLCBpbnNiZXNvbmRlcmUgZGEgZGllIEtsYXNzZW4gZGVyIFZhcmlhYmxlbiAxOTkyIGJpcyAxOTk5IGBjaGFyYWN0ZXJgIHNpbmQgdW5kIGFiIDIwMDAgZGFubiBgZG91YmxlYC4KRGllcyBzYWd0IHVucyBkaWUgZXJzY2hlaW5lbmRlIEZlaGxlcm1lbGR1bmc6CgotLS0KCkZlaGxlcjogQ2FuJ3QgY29tYmluZSBgMTk5MmAgPGNoYXJhY3Rlcj4gYW5kIGAyMDAwYCA8ZG91YmxlPi4KCi0tLQoKRGEgd2lyIHdpc3NlbiwgZGFzcyBkYXMgQklQLCBkaWUgQW56YWhsIGFuIEVyd2VyYnN0w6R0aWdlbiB1bmQgZGllIEFuemFobCBhbiBFaW53b2huZXJuIG5vcm1hbGVyd2Vpc2UgbnVtZXJpc2NoIHdpZWRlcmdlZ2ViZW4gd2lyZCwgaXN0IHdvaGwgZGllIEtsYXNzZSBgZG91YmxlYCBrb3JyZWt0IHVuZCB3aXIgc29sbHRlbiBkaWUgU3BhbHRlbiB2b24gMTk5MiBiaXMgMTk5OSBlbnRzcHJlY2hlbmQgdW1mb3JtYXRpZXJlbi4KCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojQklQIHZvbiAxOTkyIC0gMTk5OSB1bWZvcm1lbiAoYWxzIG51bWVyaXNjaGUgVmFyaWFibGUpCmJpcF9kb3VibGUgPC0gYmlwX3dpZGUgfD4KICBzZWxlY3QoYDE5OTJgOmAxOTk5YCkgfD4KICBtdXRhdGVfaWYoaXMuY2hhcmFjdGVyLCBhcy5kb3VibGUpCgojIEVyd2VyYnN0w6R0aWdlIHZvbiAxOTkyIC0gMTk5OSB1bWZvcm1lbiAoYWxzIG51bWVyaXNjaGUgVmFyaWFibGUpCmVyd2VyYl9kb3VibGUgPC0gZXJ3ZXJiX3dpZGUgfD4KICBzZWxlY3QoYDE5OTJgOmAxOTk5YCkgfD4KICBtdXRhdGVfaWYoaXMuY2hhcmFjdGVyLCBhcy5kb3VibGUpCgojIEVpbndvaG5lciB2b24gMTk5MiAtIDE5OTkgdW1mb3JtZW4gKGFscyBudW1lcmlzY2hlIFZhcmlhYmxlKQplaW53b2huZXJfZG91YmxlIDwtIGVpbndvaG5lcl93aWRlIHw+CiAgc2VsZWN0KGAxOTkyYDpgMTk5OWApIHw+CiAgbXV0YXRlX2lmKGlzLmNoYXJhY3RlciwgYXMuZG91YmxlKQpgYGAKCldpciBiZWtvbW1lbiBoaWVyIGVpbmUgV2Fybm1lbGR1bmcgZGFzIGBOQWBzIGJlaSBkZXIgVW13YW5kbHVuZyBlcnpldWd0IHd1cmRlbi4KRGVyYXJ0aWdlIFdhcm51bmdlbiBzb2xsdGVuIHdpciBiZWFjaHRlbiB1bmQgYXVmIGRlbiBHcnVuZCBnZWhlbi4KTnVyIHNvIHdpc3NlbiB3aXIsIG9iIGRpZSBXYXJudW5nIGbDvHIgdW5zIHNww6R0ZXIgdW5iZWFic2ljaHRpZ3RlIEF1c3dpcmt1bmdlbiBoYXQuCgpIaWVyZsO8ciB2ZXJiaW5kZW4gd2lyIGRlbiBuZXVlbiBEYXRlbnNhdHogYGJpcF9kb3VibGVgIG1pdCB1bnNlcmVtIGJpc2hlciBiZXN0ZWhlbmRlbiBgYmlwX3dpZGVgIHVuZCBiZXRyYWNodGVuIGRpZSBTcGFsdGVuIGluIGRlbmVuIGBiaXBfZG91YmxlYCBgTkFgcyBlbnRow6RsdDoKCmBgYHtyfQpiaXBfd2lkZV90ZXN0IDwtIGJpcF93aWRlIHw+CiAgYmluZF9jb2xzKGJpcF9kb3VibGUpCgpoZWFkKGZpbHRlcihiaXBfd2lkZV90ZXN0LCBpcy5uYShgMTk5Mi4uLjMyYCkpKQpgYGAKCkhpZXIgc2VoZW4gd2lyIGJlcmVpdHMgd2FydW0gZGllIEtsYXNzZSBkZXIgVmFyaWFibGVuIGAxOTkyYCBiaXMgYDE5OTlgIGBjaGFyYWN0ZXJgIHdhciB1bmQgbmljaHQgYGRvdWJsZWAuCkbDvHIgZGllc2UgSmFocmUgZ2FiIGVzIGbDvHIgZWluaWdlIFJlZ2lvbmVuIChNZWNrbGVuYnVyZy1Wb3Jwb21tZXJuIHVuZCBOaWVkZXJzYWNoZW4pIGtlaW5lIEFuZ2FiZW4genVtIEJJUCwgZGVuIEVyd2VyYnN0w6R0aWdlbiBvZGVyIGRlbiBFaW53b2huZXJuIHVuZCBkYWhlciB3dXJkZW4gaW4gZGVyIEV4Y2VsIFRhYmVsbGUgYC1gIGVpbmdlZsO8Z3QuCkRhaGVyIGlzdCBmw7xyIHVucyBkaWUgVW13YW5kbHVuZyB6dSBgTkFgIGZvbGdlcmljaHRpZyB1bmQgd2lyIGvDtm5uZW4gZGllIFdhcm5tZWxkdW5nIGlnbm9yaWVyZW4gdW5kIG51ciBkaWUgdHJhbnNmb3JtaWVydGVuIFZhcmlhYmxlbiBtaXQgZGVyIEtsYXNzZSBgZG91YmxlYCB2ZXJ3ZW5kZW46CgpgYGB7cn0KYmlwX3dpZGUgPC0gYmlwX3dpZGUgfD4KICBzZWxlY3QoLShgMTk5MmA6YDE5OTlgKSkgfD4KICBiaW5kX2NvbHMoYmlwX2RvdWJsZSkgCgplcndlcmJfd2lkZSA8LSBlcndlcmJfd2lkZSB8PgogIHNlbGVjdCgtKGAxOTkyYDpgMTk5OWApKSB8PgogIGJpbmRfY29scyhlcndlcmJfZG91YmxlKSAKCmVpbndvaG5lcl93aWRlIDwtIGVpbndvaG5lcl93aWRlIHw+CiAgc2VsZWN0KC0oYDE5OTJgOmAxOTk5YCkpIHw+CiAgYmluZF9jb2xzKGVpbndvaG5lcl9kb3VibGUpIApgYGAKCk51biBrw7ZubmVuIHdpciBkZW4gRGF0ZW5zYXR6IGlucyBgbG9uZ2AtRm9ybWF0IHRyYW5zZmVyaWVyZW4gdW5kIG5hY2ggZGVtIEphaHIgc29ydGllcmVuLgpEYSBkaWUgRWlud29obmVyIHVuZCBFcndlcmJzdMOkdGlnZW4gaW4gMTAwMCBQZXJzb25lbiBhbmdlZ2ViZW4gc2luZCBtdWx0aXBsaXppZXJlbiB3aXIgdW5zZXJlIEVyd2VyYnN0w6R0aWdlbiB1bmQgRWlud29obmVyIG1pdCAxMDAwLgpEYXMgQklQIGlzdCBpbiAxIE1pby4gRXVybyBhbmdlZ2ViZW4sIGRhaGVyIGRpZSBNdWx0aXBsaWthdGlvbiBtaXQgMSBNaW8uOgoKYGBge3J9CiMgQklQIGlucyBsb25nLUZvcm1hdApiaXBfbG9uZyA8LSBwaXZvdF9sb25nZXIoYmlwX3dpZGUsIGNvbHMgPSBjKCIyMDAwIjoiMTk5OSIpICwgbmFtZXNfdG8gPSAiSmFociIsIHZhbHVlc190byA9ICJiaXAiKSB8PgogIG11dGF0ZSggSmFociA9IGFzLm51bWVyaWMoSmFociksCiAgICAgICAgICBiaXAgPSBiaXAgKiAxMDAwMDAwKSB8PgogIGFycmFuZ2UoIEphaHIgKQoKIyBBbnphaGwgZGVyIEVyd2VyYnN0w6R0aWdlbiBpbnMgbG9uZy1Gb3JtYXQKZXJ3ZXJiX2xvbmcgPC0gcGl2b3RfbG9uZ2VyKGVyd2VyYl93aWRlLCBjb2xzID0gYygiMjAwMCI6IjE5OTkiKSAsIG5hbWVzX3RvID0gIkphaHIiLCB2YWx1ZXNfdG8gPSAiZXJ3IikgfD4KICBtdXRhdGUoIEphaHIgPSBhcy5udW1lcmljKEphaHIpLAogICAgICAgICAgZXJ3ID0gZXJ3ICogMTAwMCkgfD4KICBhcnJhbmdlKCBKYWhyICkKCiMgQW56YWhsIGRlciBFaW53b2huZXIgaW5zIGxvbmctRm9ybWF0CmVpbndvaG5lcl9sb25nIDwtIHBpdm90X2xvbmdlcihlaW53b2huZXJfd2lkZSwgY29scyA9IGMoIjIwMDAiOiIxOTk5IikgLCBuYW1lc190byA9ICJKYWhyIiwgdmFsdWVzX3RvID0gImVpbndvaG5lciIpIHw+CiAgbXV0YXRlKCBKYWhyID0gYXMubnVtZXJpYyhKYWhyKSwKICAgICAgICAgIGVpbndvaG5lciA9IGVpbndvaG5lciAqIDEwMDApIHw+CiAgYXJyYW5nZSggSmFociApCmBgYAoKIyMgS29uc2lzdGVuemNoZWNrcwoKV2lyIGhhYmVuIGJlcmVpdHMgaW4gZGVtIEFic2Nobml0dCAiUHJvLUtvcGYgVmVyc2NodWxkdW5nIiBkaWUgRWlud29obmVyIHp1ciBCZXJlY2hudW5nIGRlciBQcm8tS29wZi1WZXJzY2h1bGR1bmcgZsO8ciAyMDIyIGVpbmdlbGVzZW4uCkbDvHIgZWluZSBsw6RuZ2VyZnJpc3RpZ2UgQmV0cmFjaHR1bmcga29ubnRlbiB3aXIgbnVuIG1pdCBkZW0gQklQIERhdGVuc2F0eiBkaWUgQW56YWhsIGRlciBFaW53b2huZXIgdm9uIDE5OTIgYmlzIDIwMjIgZWlubGVzZW4uCkluIGRpZXNlbSBLb25zaXN0ZW56Y2hlY2sgd29sbGVuIHdpciB1bnRlcnN1Y2hlbiBvYiBkaWUgQW56YWhsIGRlciBFaW53b2huZXIgYXVzIGJlaWRlbiBEYXRlbnF1ZWxsZW4gaW4gMjAyMiBpZGVudGlzY2ggaXN0LgpIaWVyYmVpIGlzdCBlcyBuYXTDvHJsaWNoIHdpY2h0aWcsIHdhbm4gZGllIERhdGVuIHp1ciBFaW53b2huZXJ6YWhsIGVyaG9iZW4gd3VyZGVuIHVuZCBkZXNoYWxiIGvDtm5udGVuIGRpZXNlIGF1Y2ggZ2VyaW5nZsO8Z2lnIGFid2VpY2hlbi4KQWJlciBkZW0gZ2VoZW4gd2lyIG51biBhdWYgZGVuIEdydW5kOgoKYGBge3J9CnNjaHVsZGVuX2NoZWNrIDwtIHNjaHVsZGVuX2JlcmVpbmlndCB8PgogIGdyb3VwX2J5KGxhbmRrcmVpcykgfD4KICBzdW1tYXJpc2UoIFNjaHVsZGVuX3Byb19rb3BmX2xrID0gc3VtKFNjaHVsZGVuX2dlc2FtdCkvc3VtKEVpbndvaG5lciksIAogICAgICAgICAgICAgRWlud29obmVyID0gc3VtKEVpbndvaG5lciksIAogICAgICAgICAgICAgU2NodWxkZW5fZ2VzYW10ID0gc3VtKFNjaHVsZGVuX2dlc2FtdCksCiAgICAgICAgICAgICAuZ3JvdXBzID0gJ2Ryb3AnKSB8PgogIHJlbmFtZShSZWdpb25hbHNjaGx1ZXNzZWwgPSBsYW5ka3JlaXMpCgplaW53b2huZXJfY2hlY2sgPC0gbGVmdF9qb2luKHNjaHVsZGVuX2NoZWNrLCBmaWx0ZXIoZWlud29obmVyX2xvbmcsIEphaHIgPT0gMjAyMiksIGJ5PWMoIlJlZ2lvbmFsc2NobHVlc3NlbCIpKSB8PgogIG11dGF0ZShkaWZmID0gRWlud29obmVyIC0gZWlud29obmVyKSB8PgogIGFycmFuZ2UoZGVzYyhkaWZmKSkKCnNraW1fd2l0aG91dF9jaGFydHMoZWlud29obmVyX2NoZWNrJGRpZmYpCgpoZWFkKGFycmFuZ2UoZWlud29obmVyX2NoZWNrLCAtZGlmZiksMjApCmBgYAoKRGllIERpZmZlcmVueiBsaWVndCBpbSBEdXJjaHNjaG5pdHQgYmVpIDY4NCBFaW53b2huZXJuLCB3YXMgaW0gVG9sZXJhbnpiZXJlaWNoIGJlaSBkZW4gZ3Jvw59lbiBTdMOkZHRlIG1pdCBtZWhyIGFscyAxMjAuMDAwIEVpbndvaG5lcm4gaXN0LgpEaWUgQWJ3ZWljaHVuZ2VuIGluIGRlbiBFaW53b2huZXJ6YWhsZW4ga8O2bm50ZW4gZ3V0IGltIFplaXRwdW5rdCBkZXIgRXJoZWJ1bmcgZGVyIEVpbndvaG5lcnphaGxlbiBiZWdyw7xuZGV0IHNlaW4gKEF1Z3VzdCAyMDIzIGJlaW0gQklQIHVuZCBFbmRlIERlemVtYmVyIDIwMjIgYmVpIGRlbiBEYXRlbiB6dXIgVmVyc2NodWxkdW5nKS4gRGFoZXIgd2VyZGVuIHdpciBkZW4gRGlmZmVyZW56ZW4gbmljaHQgd2VpdGVyIG5hY2hnZWhlbi4KClVtIGRpZSBsYW5nZnJpc3RpZ2VuIEVudHdpY2tsdW5nZW4gZGVzIEJJUCBwcm8gS29wZiB6dSB2aXN1YWxpc2llcmVuIHdlcmRlbiB3aXIgZGllIGRhenVnZWjDtnJpZ2VuIEVpbndvaG5lcnphaGxlbiBhdXMgZGVyIERhdGVucXVlbGxlIHp1bSBCSVAgdmVyd2VuZGVuLgpGw7xyIGRpZSBQcm8tS29wZi1WZXJzY2h1bGR1bmcgamVkb2NoIGRpZSBpbiBkZXIgIkludGVncmllcnRlbiBTY2h1bGRlbiBkZXIgR2VtZWluZGVuIiBhbmdlZ2ViZW5lbiBFaW53b2huZXJ6YWhsLgoKIyBLYXJ0ZW5tYXRlcmlhbCBoaW56dWbDvGdlbiAob3B0aW9uYWwpCgpGw7xyIGVpbmUgc3DDpHRlcmUgVmlzdWFsaXNpZXJ1bmcgZGVyIERhdGVuIG1pdHRlbHMgZWluZXIgRGV1dHNjaGxhbmRrYXJ0ZSBzb2xsdGVuIHdpciB1bnMgbm9jaCBJbmZvcm1hdGlvbmVuIHp1IGRlbiBlaW56ZWxuZW4gVmVyd2FsdHVuc2dyZW56ZW4gYWxzIFNIQVBFLUZpbGUgaGVydW50ZXJsYWRlbi4KRGllc2UgSW5mb3JtYXRpb25lbiBzaW5kIMO8YmVyIGRhcyBbT3BlbkRhdGEgUG9ydGFsIGRlcyBCdW5kZXNhbXRzIGbDvHIgS2FydG9ncmFwaGllIHVuZCBHZW9kw6RzaWVdKGh0dHBzOi8vZ2R6LmJrZy5idW5kLmRlL2luZGV4LnBocC9kZWZhdWx0L29wZW4tZGF0YS92ZXJ3YWx0dW5nc2dlYmlldGUtMS0yNTAtMDAwLWViZW5lbi1zdGFuZC0wMS0wMS12ZzI1MC1lYmVuZW4tMDEtMDEuaHRtbCkgdmVyZsO8Z2Jhci4KCltEaWUgRG9rdW1lbnRhdGlvbiBkZXIgRGF0ZW5dKGh0dHBzOi8vc2cuZ2VvZGF0ZW56ZW50cnVtLmRlL3dlYl9wdWJsaWMvZ2R6L2Rva3VtZW50YXRpb24vZGV1L3ZnMjUwLnBkZikgc29sbHRlbiB3aXIgdW5zIGltbWVyIHp1ZXJzdCBhbnNjaGF1ZW4sIGJldm9yIHdpciBkaWUgRGF0ZW5xdWVsbGUgaGVydW50ZXJsYWRlbi4KRGllcyBnaWx0IG5pY2h0IG51ciBmw7xyIGRpZSBHZW9kYXRlbiwgc29uZGVybiBhbGxnZW1laW4gZsO8ciBhbGxlIERhdGVucmVpaGVuLgoKV2lyIGV4dHJhaGllcmVuIHVucyBoaWVyIGRpZSBJbmZvcm1hdGlvbmVuIHp1IGRlbiBHcmVuemVuIGRlciBHZW1laW5kZW4sIFZlcndhbHR1bmdzZWluaGVpdGVuLCBMYW5ka3JlaXNlIHVuZCBCdW5kZXNsw6RuZGVyIHVuZCBzcGVpY2hlcm4gZGllc2UgamV3ZWlscyBlbnRzcHJlY2hlbmQgYWIuClVtIEdlb21ldHJpZWRhdGVuIGVpbnp1bGVzZW4gdW5kIGRpZXNlIHNww6R0ZXIgc2Now7ZuIGFscyBLYXJ0ZSBkYXJzdGVsbGVuIHp1IGvDtm5uZW4gbcO8c3NlbiB3aXIgaGllciBkaWUgRnVua3Rpb24gYHN0X3JlYWRgIGF1cyBkZW0gYHNmYC1QYWtldCB2ZXJ3ZW5kZW46CgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShzZikKCiMgS2FydGVubWF0ZXJpYWwgR2VtZWluZGVlYmVuZQppZiAoIWZpbGUuZXhpc3RzKCIuL2RhdGEvS2FydGVubWF0ZXJpYWxfRGV1dHNjaGxhbmQuemlwIikpewogIGRvd25sb2FkLmZpbGUoImh0dHBzOi8vZGF0ZW4uZ2R6LmJrZy5idW5kLmRlL3Byb2R1a3RlL3ZnL3ZnMjUwX2ViZW5lbl8wMTAxL2FrdHVlbGwvdmcyNTBfMDEtMDEuZ2szLnNoYXBlLmViZW5lbi56aXAiLCAiLi9kYXRhL0thcnRlbm1hdGVyaWFsX0RldXRzY2hsYW5kLnppcCIpCn0KCiMgw5ZmZm5lbiBkZXMgWklQLU9yZG5lcnMKa2FydGVuX29yZG5lciA8LSBhcy5jaGFyYWN0ZXIodW56aXAoIi4vZGF0YS9LYXJ0ZW5tYXRlcmlhbF9EZXV0c2NobGFuZC56aXAiLCBsaXN0ID0gVFJVRSkkTmFtZSkKCiMgV2lyIHdvbGxlbiBudXIgZGllIERhdGVpIGVudHppcHBlbgp1bnppcCgiLi9kYXRhL0thcnRlbm1hdGVyaWFsX0RldXRzY2hsYW5kLnppcCIpCgojIEluZm9ybWF0aW9uZW4genUgZGVuIEdlbWVpbmRlbiBlaW5sZXNlbiAoR0VNKQpnZW1laW5kZW4gPC0gc3RfcmVhZChrYXJ0ZW5fb3JkbmVyWzE1XSkKCiMgSW5mb3JtYXRpb25lbiB6dSBWZXJ3YWx0dW5nc2ViZW5lbiBlaW5sZXNlbiAoVldHKQp2ZXJ3YWx0dW5nIDwtIHN0X3JlYWQoa2FydGVuX29yZG5lcls1MF0pCgojIEluZm9ybWF0aW9uZW4genUgZGVuIExhbmRrcmVpc2VuIGVpbmxlc2VuIChLUlMpCmxhbmRrcmVpc2UgPC0gc3RfcmVhZChrYXJ0ZW5fb3JkbmVyWzIwXSkKCiMgSW5mb3JtYXRpb25lbiB6dSBkZW4gQnVuZHNsw6RuZGVybiBlaW5sZXNlbiAoTEFOKQpidW5kZXNsYW5kIDwtIHN0X3JlYWQoa2FydGVuX29yZG5lclsyNV0pCgojIE51biBrw7ZubmVuIHdpciBkZW4gZW50emlwcHRlbiBPcmRuZXIgd2llZGVyIGzDtnNjaGVuCnVubGluayhrYXJ0ZW5fb3JkbmVyWzFdLCByZWN1cnNpdmUgPSBUUlVFKQpgYGAKCkRhIHdpciBudXIgZGllIEluZm9ybWF0aW9uZW4genVyIEdlb21ldHJpZSwgei5CLiBkZXIgTGFuZGtyZWlzZ3JlbnplbiBtw7ZjaHRlbiwga8O2bm5lbiB3aXIgZGllIGFuZGVyZW4gVmFyaWFibGVuIGF1Y2ggYXVzIGRlbSBEYXRlbnPDpHR6IGzDtnNjaGVuLgpXaXIgYmVoYWx0ZW4gZGVuIFJlZ2lvbmFsc2NobMO8c3NlbCAoQVJTKSwgZGVuIE5hbWVuIGRlcyBLcmVpc2VzL2RlciBHZW1laW5kZSAoR0VOKSB1bmQgZGllIEdlb21ldHJpZSAoZ2VvbWV0cnkpLgoKV2lyIG3DvHNzZW4gdW5zIHp1c8OkdHpsaWNoIG5vY2ggZXR3YXMgbWl0IGRlciBEb2t1bWVudGF0aW9uIGRlcyBLYXJ0ZW5tYXRlcmlhbHMgYmVzY2jDpGZ0aWdlbi4KRGEgd2lyIG51ciBkaWUgVmVyd2FsdHVuZ3NlaW5oZWl0ZW4gb2huZSBkaWUgTm9yZC0gdW5kIE9zdHNlZSB1bmQgb2huZSBkZW4gQm9kZW5zZWUgZGFyc3RlbGxlbiBtw7ZjaHRlbiwgc28gbcO8c3NlbiB3aXIgbm9jaCBhdWYgR0YgPSA0IGZpbHRlcm4sIHdpZSBhdWYgU2VpdGUgOSBkZXIgRG9rdW1lbnRhdGlvbiBiZXNjaHJpZWJlbiB3aXJkICh0dW4gd2lyIGRpZXMgbmljaHQsIHNvIGjDpHR0ZW4gd2lyIGRpZSBOb3Jkc2VlZ2ViaWV0ZSBkb3BwZWx0IGRyaW4pOgoKLS0tCgoqKkdydW5kc8OkdHpsaWNoIGdpbHQ6KiogSmVkZSBWZXJ3YWx0dW5nc2VpbmhlaXQgYmVzaXR6dCBnZW5hdSBlaW5lbiBBdHRyaWJ1dHNhdHogbWl0IGRlbSBHRi1XZXJ0IDQuClp1c8OkdHpsaWNoIGthbm4gZWluZSBWZXJ3YWx0dW5nc2VpbmhlaXQgZWluZW4gQXR0cmlidXRzYXR6IG1pdCBkZW0gR0YtV2VydCAyIGJlc2l0emVuLgoKLS0tCgpgYGB7cn0KIyBBdWYgR0YgPT0gNCBmaWx0ZXJuIHVuZCBBUlMgYWxzIFN0cmluZyBzcGVpY2hlcm4gKGlzdCBha3R1ZWxsIGFscyBmYWN0b3IgYWJnZXNwZWljaGVydCkKbGFuZGtyZWlzZSA8LSBsYW5ka3JlaXNlIHw+CiAgZmlsdGVyKCBHRj09NCApIHw+IAogIHNlbGVjdChBUlMsIEdFTiwgZ2VvbWV0cnkpIHw+CiAgbXV0YXRlKFJlZ2lvbmFsc2NobHVlc3NlbCA9IGFzLmNoYXJhY3RlcihBUlMpKQoKZ2VtZWluZGVuIDwtIGdlbWVpbmRlbiB8PgogIGZpbHRlciggR0Y9PTQgKSB8PgogIHNlbGVjdChBUlMsIEdFTiwgZ2VvbWV0cnkpIHw+CiAgbXV0YXRlKFJlZ2lvbmFsc2NobHVlc3NlbCA9IGFzLmNoYXJhY3RlcihBUlMpKQoKYnVuZGVzbGFuZCA8LSBidW5kZXNsYW5kIHw+CiAgZmlsdGVyKCBHRj09NCApIHw+CiAgc2VsZWN0KEFSUywgR0VOLCBnZW9tZXRyeSkgfD4KICBtdXRhdGUoUmVnaW9uYWxzY2hsdWVzc2VsID0gYXMuY2hhcmFjdGVyKEFSUykpCgpgYGAKCiMgRGF0ZW5zw6R0emUgenVzYW1tZW5mw7xocmVuCgpJbiBkaWVzZW0gbGV0enRlbiBBYnNjaG5pdHQgbcO2Y2h0ZW4gd2lyIGFsbGVzIGbDvHIgZGllIG7DpGNoc3RlbiBTY2hyaXR0ZSBkZXIgQ2FzZSBTdHVkeSB2b3JiZXJlaXRlbi4KR2VuYXVlcjogV2lyIHdvbGxlbiBuaWNodCBudXIgZGllIEluZm9ybWF0aW9uZW4gYXVzIGRlbiBlaW56ZWxuZW4gRGF0ZW5zw6R0emVuLCBzb25kZXJuIGFtIEJlc3RlbiBlaW5lbiBrb21iaW5pZXJ0ZW4gRGF0ZW5zYXR6IGFuYWx5c2llcmVuIQpIaWVyZsO8ciBtw7xzc2VuIHdpciB6dWVyc3QgZGllIEluZm9ybWF0aW9uZW4genVyIFZlcnNjaHVsZHVuZyBhdWYgTGFuZGtyZWlzZWJlbmUgYWdncmVnaWVyZW4gdW5kIGRpZSBEYXRlbiB6dW0gQklQIGF1ZiBkYXMgSmFociAyMDIyIGVpbnNjaHLDpG5rZW4uCkFuc2NobGllw59lbmQga8O2bm5lbiB3aXIgZGllIERhdGVuc8OkdHplIGFuaGFuZCBkZXMgUmVnaW9uYWxzY2hsw7xzc2VscyBtaXRlaW5hbmRlciB2ZXJiaW5kZW4uCgpXZWl0ZXJoaW4gd29sbGVuIHdpciBkaWUgZ2VvZ3JhZmlzY2hlbiBEYXRlbiBzZXBhcmF0IGFic3BlaWNoZXJuIHVuZCBiZWkgQmVkYXJmIGFuaGFuZCBkZXMgUmVnaW9uYWxzY2hsw7xzc2VscyB6dSB1bnNlcmVtIERhdGVuc2F0eiBoaW56dW1lcmdlbi4KRGVyIFJlZ2lvbmFsc2NobMO8c3NlbCBkaWVudCB1bnMgaGllcmJlaSBhbHMgZWluZGV1dGlnZSBJZGVudGlmaWthdGlvbiBkZXIgamV3ZWlsaWdlbiBHZW1laW5kZS4KCmBgYHtyfQojIFNjaHVsZGVuIGF1ZiBMYW5ka3JlaXNlYmVuZQpzY2h1bGRlbl9rb21iaSA8LSBzY2h1bGRlbl9iZXJlaW5pZ3QgfD4KICBncm91cF9ieShsYW5ka3JlaXMpIHw+CiAgc3VtbWFyaXNlKCBTY2h1bGRlbl9wcm9fa29wZl9sayA9IHN1bShTY2h1bGRlbl9nZXNhbXQpL3N1bShFaW53b2huZXIpLCBFaW53b2huZXIgPSBzdW0oRWlud29obmVyKSwgU2NodWxkZW5fZ2VzYW10ID0gc3VtKFNjaHVsZGVuX2dlc2FtdCkpIHw+CiAgcmVuYW1lKFJlZ2lvbmFsc2NobHVlc3NlbCA9IGxhbmRrcmVpcykKCgojIEFuemFobCBhbiBFcndlcmJzdMOkdGlnZW4gZsO8ciBkYXMgSmFociAyMDIyCmVyd2VyYl9rb21iaSA8LSBlcndlcmJfbG9uZyB8PgogIGZpbHRlcihuY2hhcihSZWdpb25hbHNjaGx1ZXNzZWwpID09IDUgJiBKYWhyID09IDIwMjIpIHw+CiAgc2VsZWN0KC1KYWhyKQoKIyBBbnphaGwgYW4gRWlud29obmVyIGbDvHIgZGFzIEphaHIgMjAyMgplaW53b2huZXJfa29tYmkgPC0gZWlud29obmVyX2xvbmcgfD4KICBmaWx0ZXIobmNoYXIoUmVnaW9uYWxzY2hsdWVzc2VsKSA9PSA1ICYgSmFociA9PSAyMDIyKSB8PgogIHNlbGVjdCgtSmFocikKCiMgTmFtZW4gZGVyIExhbmRrcmVpc2UKbGFuZGtyZWlzX25hbWUgPC0gbGFuZGtyZWlzZSB8PiAKICBzdF9kcm9wX2dlb21ldHJ5KCkgfD4KICBzZWxlY3QoLUFSUykgfD4KICBtdXRhdGUoYnVuZGVzbGFuZCA9IHN0cl9leHRyYWN0KFJlZ2lvbmFsc2NobHVlc3NlbCwgIl4uezJ9IikpIHw+CiAgcmVuYW1lKGxhbmRrcmVpc19uYW1lID0gR0VOKQoKIyBOYW1lbiBkZXIgQnVuZGVzbMOkbmRlcgpidW5kZXNsYW5kX25hbWUgPC0gYnVuZGVzbGFuZCB8PgogIHN0X2Ryb3BfZ2VvbWV0cnkoKSB8PgogIHNlbGVjdCgtQVJTKSB8PgogIHJlbmFtZShidW5kZXNsYW5kID0gUmVnaW9uYWxzY2hsdWVzc2VsLAogICAgICAgICBidW5kZXNsYW5kX25hbWUgPSBHRU4pCgojIEFuemFobCBkZXIgRWlud29obmVyIG1pdCBkZW0gQklQIHZlcmJpbmRlbiB1bSBkYXMgQklQIHBybyBLb3BmIGJlcmVjaG5lbiB6dSBrw7ZubmVuCmJpcF96ZWl0cmVpaGUgPC0gbGVmdF9qb2luKGJpcF9sb25nLCBlaW53b2huZXJfbG9uZywgYnk9YygiUmVnaW9uYWxzY2hsdWVzc2VsIiwgIkphaHIiKSkgfD4KICBtdXRhdGUoYmlwX3Byb19rb3BmID0gYmlwIC8gZWlud29obmVyKQoKIyBCSVAgYXVmIExhbmRrcmVpc2ViZW5lIGltIEphaHIgMjAyMQpiaXBfa29tYmkgPC0gYmlwX3plaXRyZWloZSB8PgogIGZpbHRlcihuY2hhcihSZWdpb25hbHNjaGx1ZXNzZWwpID09IDUgJiBKYWhyID09IDIwMjIpIHw+CiAgc2VsZWN0KC1jKEphaHIsIGVpbndvaG5lcikpCgojIERhdGVuc8OkdHplIHp1c2FtbWVuZsO8aHJlbgoKIyBCYXNpc2RhdGVuc2F0eiAtPiBBcmJlaXRzbG9zZW56YWhsZW4gcHJvIExhbmRrcmVpcwojIE5hbWUgZGVyIExhbmRrcmVpc2UgenVtZXJnZW4KZGF0ZW4xIDwtIGxlZnRfam9pbihhbG9fbGFuZGtyZWlzLCBsYW5ka3JlaXNfbmFtZSwgYnkgPSAiUmVnaW9uYWxzY2hsdWVzc2VsIikKIyBOYW1lbiBkZXIgQnVuZGVzbMOkbmRlciB6dW1lcmdlbgpkYXRlbjEgPC0gZGF0ZW4xIHw+IG11dGF0ZShidW5kZXNsYW5kID0gc3RyX2V4dHJhY3QoUmVnaW9uYWxzY2hsdWVzc2VsLCAiXi57Mn0iKSkKZGF0ZW4xIDwtIGxlZnRfam9pbihkYXRlbjEsIGJ1bmRlc2xhbmRfbmFtZSwgYnkgPSAiYnVuZGVzbGFuZCIpCiMgU2NodWxkZW4genVtZXJnZW4KZGF0ZW4yIDwtIGxlZnRfam9pbihkYXRlbjEsIHNjaHVsZGVuX2tvbWJpLCBieSA9ICJSZWdpb25hbHNjaGx1ZXNzZWwiKQojIEJJUCB6dW1lcmdlbgpkYXRlbjMgPC0gbGVmdF9qb2luKGRhdGVuMiwgYmlwX2tvbWJpLCBieSA9ICJSZWdpb25hbHNjaGx1ZXNzZWwiKQojIFphaGwgZGVyIEVyd2VyYnN0w6R0aWdlbiB6dW1lcmdlbgpnZXNhbXRkYXRlbiA8LSBsZWZ0X2pvaW4oZGF0ZW4zLCBlcndlcmJfa29tYmksIGJ5ID0gIlJlZ2lvbmFsc2NobHVlc3NlbCIpCgpzYXZlUkRTKGdlc2FtdGRhdGVuLCAiLi9kYXRhL2dlc2FtdGRhdGVuLnJkcyIpCnNhdmVSRFMoc2NodWxkZW5fYmVyZWluaWd0LCAiLi9kYXRhL3NjaHVsZGVuX2JlcmVpbmlndC5yZHMiKQpzYXZlUkRTKGJpcF96ZWl0cmVpaGUsICIuL2RhdGEvYmlwX3plaXRyZWloZS5yZHMiKQpzYXZlUkRTKGJ1bmRlc2xhbmQsICIuL2RhdGEvYnVuZGVzbGFuZC5yZHMiKQpzYXZlUkRTKGdlbWVpbmRlbiwgIi4vZGF0YS9nZW1laW5kZW4ucmRzIikKc2F2ZVJEUyhsYW5ka3JlaXNlLCAiLi9kYXRhL2xhbmRrcmVpc2UucmRzIikKYGBgCgojIMOcYnVuZ3NhdWZnYWJlbgoKTGFkZW4gU2llIHNpY2ggZGFzIGR1cmNoc2Nobml0dGxpY2hlIFtBcmJlaXRuZWhtZXJlbnRnZWx0IHBybyBBcmJlaXRuZWhtZXIgdW5kIExhbmRrcmVpc10oaHR0cHM6Ly93d3cuc3RhdGlzdGlrcG9ydGFsLmRlL2RlL3Zlcm9lZmZlbnRsaWNodW5nZW4vYXJiZWl0bmVobWVyZW50Z2VsdCkgYXVmIGRlciBTZWl0ZSBkZXIgU3RhdGlzdGlzY2hlbiDDhG10ZXIgZGVzIEJ1bmRlcyB1bmQgZGVyIEzDpG5kZXIgaGVydW50ZXIgdW5kIGxlc2VuIFNpZSBkaWVzZW4gaW4gUiBlaW4uCgoxLiAgRmluZGVuIFNpZSBpbiBkZW0gaGVydW50ZXJnZWxhZGVuZW4gRGF0ZW5zYXR6IGhlcmF1cywgd2FzIGRlciBVbnRlcnNjaGllZCB6d2lzY2hlbiAqQXJiZWl0bmVobWVyZW50Z2VsdCogdW5kICpCcnV0dG9sw7ZobmUtIHVuZCBHZWjDpGx0ZXIqIGlzdC4KCjIuICBMZXNlbiBTaWUgZGllIGbDvHIgU2llIHJlbGV2YW50ZSBUYWJlbGxlICpCcnV0dG9sw7ZobmUtIHVuZCBHZWjDpGx0ZXIqIGluIFIgZWluLgoKMy4gIEJlcmVpbmlnZW4gU2llIGRpZSBUYWJlbGxlLCBkLmguIGRlciBEYXRlbnNhdHogc29sbHRlIGRhbmFjaCBgdGlkeWAgc2Vpbi4KCjQuICBCZXJlY2huZW4gU2llIGRpZSBCcnV0dG9sw7ZobmUgcHJvIEJ1bmRlc2xhbmQgbWl0IGRlbiBCcnV0dG9sw7ZobmVuIGRlciBlaW56ZWxuZW4gTGFuZGtyZWlzZSBhbHMgS29uc2lzdGVuemNoZWNrLgoKNS4gIFZlcmdsZWljaGVuIFNpZSBpaHJlbiBEYXRlbnNhdHogbWl0IGRlbSBhdWYgR2l0aHViIGJlcmVpdGdlc3RlbGx0ZW4gRGF0ZW5zYXR6ICgiZWlua29tbWVuLnJkcyIpLgogICAgU3RpbW1lbiBkaWVzZSDDvGJlcmVpbj8KCjYuICBWZXJiaW5kZW4gU2llIGRpZSBJbmZvcm1hdGlvbmVuIHp1IGRlbiBkdXJjaHNjaG5pdHRsaWNoZW4gRWlua29tbWVuIG1pdCBkZW0gKmdlc2FtdGRhdGVuc2F0eiogYXVzIGRlbSB2b3JoZXJpZ2VuIEFic2Nobml0dC4K