1 Aufgaben

In diesem Abschnitt soll ein neuer Datensatz betrachtet werden. Der Datensatz msleep behandelt das Schlafverhalten von Säugetieren und liegt uns als Excel-Datei vor. Für mehr Information tippen Sie wie gewohnt ?msleep.

library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
── Attaching packages ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.2 ──✔ ggplot2 3.3.6      ✔ purrr   0.3.4 
✔ tibble  3.1.8      ✔ dplyr   1.0.10
✔ tidyr   1.2.1      ✔ stringr 1.4.1 
✔ readr   2.1.3      ✔ forcats 0.5.2 ── Conflicts ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()

1.1 Übungsaufgaben

  1. Lesen Sie den Datensatz msleep.xlsx aus Moodle als tibble msleep in R ein. Schaffen Sie sich einen Überblick über den Datensatz.
  2. Betrachten Sie die Verteilungen der Variablen sleep_total und vore. Betrachten Sie auch die Gruppierung von sleep_total nach vore. Was fällt Ihnen auf?
  3. Betrachten Sie nun ebenfalls die Variable awake im Bezug auf vore. Entspricht die Verteilung Ihrer Erwartung im Vergleich zu dem sleep_total?
  4. Stellen Sie den Zusammenhang von awake und sleep_total grafisch dar. Was stellen Sie fest?
  5. Vergleichen Sie geom_violin() mit geom_histogram(), welches Facetten benutzt, um Gruppen darzustellen, und geom_freqpoly(), welches für jede Gruppe Farben einfügt. Verwenden Sie hierfür erneut die Variablen awake und vore.
  6. Stellen Sie die Verteilung von vore und conservation gemeinsam dar.
    1. Verwenden Sie hierfür zwei verschiedene Darstellungsarten.

    2. Welche Kombination tritt am häufigsten/seltensten auf?

    3. Ändern Sie die Farben des Gradienten der vorherigen Grafik mit Hilfe von scale_fill_gradient(low = farbe1, high = farbe2).

  7. Stellen Sie die gemeinsame Verteilung von vore, brainwt und bodywt dar.

1.2 Lösungen

1.2.1 Lesen Sie den Datensatz msleep.xlsx aus Moodle als tibble msleep in R ein. Schaffen Sie sich einen Überblick über den Datensatz.

Der Endung entsprechend handelt es sich um eine Excel-Datei, d. h. wir benötigen die readxl Bibliothek:

library(readxl)
msleep <- read_excel("../resources/msleep.xlsx") # Der Pfad muss individuell angepasst werden
msleep

Passen Sie auf, dass Sie Ihren Pfad zu der Datei bringen.

Ansonsten sehen wir, dass der Datensatz scheinbar direkt korrekt (als tibble) eingelesen wurde (Datentypen/Header stimmen).

Für einen Überblick der Variablen können wir zusätzlich summary() nutzen:

summary(msleep)
     name              genus               vore              order           conservation        sleep_total      sleep_rem      sleep_cycle         awake      
 Length:83          Length:83          Length:83          Length:83          Length:83          Min.   : 1.90   Min.   :0.100   Min.   :0.1167   Min.   : 4.10  
 Class :character   Class :character   Class :character   Class :character   Class :character   1st Qu.: 7.85   1st Qu.:0.900   1st Qu.:0.1833   1st Qu.:10.25  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character   Mode  :character   Median :10.10   Median :1.500   Median :0.3333   Median :13.90  
                                                                                                Mean   :10.43   Mean   :1.875   Mean   :0.4396   Mean   :13.57  
                                                                                                3rd Qu.:13.75   3rd Qu.:2.400   3rd Qu.:0.5792   3rd Qu.:16.15  
                                                                                                Max.   :19.90   Max.   :6.600   Max.   :1.5000   Max.   :22.10  
                                                                                                                NA's   :22      NA's   :51                      
    brainwt            bodywt        
 Min.   :0.00014   Min.   :   0.005  
 1st Qu.:0.00290   1st Qu.:   0.174  
 Median :0.01240   Median :   1.670  
 Mean   :0.28158   Mean   : 166.136  
 3rd Qu.:0.12550   3rd Qu.:  41.750  
 Max.   :5.71200   Max.   :6654.000  
 NA's   :27                          

Beachten Sie, dass die ersten 5 Spalten keine Faktoren sind, sodass hier keine Häufigkeiten einzusehen sind.

Um Faktoren zu erstellen, muss jede Spalte umgewandelt werden:

msleep <- msleep %>%
    mutate(genus = factor(genus),
                 vore = factor(vore),
                 order = factor(order),
                 conservation = factor(conservation))
summary(msleep)
     name                    genus         vore             order          conservation  sleep_total      sleep_rem      sleep_cycle         awake          brainwt       
 Length:83          Panthera    : 3   carni  :19   Rodentia    :22   cd          : 2    Min.   : 1.90   Min.   :0.100   Min.   :0.1167   Min.   : 4.10   Min.   :0.00014  
 Class :character   Spermophilus: 3   herbi  :32   Carnivora   :12   domesticated:10    1st Qu.: 7.85   1st Qu.:0.900   1st Qu.:0.1833   1st Qu.:10.25   1st Qu.:0.00290  
 Mode  :character   Equus       : 2   insecti: 5   Primates    :12   en          : 4    Median :10.10   Median :1.500   Median :0.3333   Median :13.90   Median :0.01240  
                    Vulpes      : 2   omni   :20   Artiodactyla: 6   lc          :27    Mean   :10.43   Mean   :1.875   Mean   :0.4396   Mean   :13.57   Mean   :0.28158  
                    Acinonyx    : 1   NA's   : 7   Soricomorpha: 5   nt          : 4    3rd Qu.:13.75   3rd Qu.:2.400   3rd Qu.:0.5792   3rd Qu.:16.15   3rd Qu.:0.12550  
                    Aotus       : 1                Cetacea     : 3   vu          : 7    Max.   :19.90   Max.   :6.600   Max.   :1.5000   Max.   :22.10   Max.   :5.71200  
                    (Other)     :71                (Other)     :23   NA's        :29                    NA's   :22      NA's   :51                       NA's   :27       
     bodywt        
 Min.   :   0.005  
 1st Qu.:   0.174  
 Median :   1.670  
 Mean   : 166.136  
 3rd Qu.:  41.750  
 Max.   :6654.000  
                   

Warum mag es wenig Sinn ergeben, aus name einen Faktor zu machen?

1.2.2 Betrachten Sie die Verteilungen der Variablen sleep_total und vore. Betrachten Sie auch die Gruppierung von sleep_total nach vore. Was fällt Ihnen auf?

Für die Darstellung der Verteilung von quantitativen Daten steht der Boxplot und das Histogramm zur Verfügung:

msleep_graph <- ggplot(msleep)
# Boxplot und Histogramm für alle Werte
msleep_graph + geom_boxplot(aes(y = sleep_total))

msleep_graph + geom_histogram(aes(x = sleep_total), bins = 20)

Der Median liegt bei 10 Stunden Schlaf und der Großteil der Daten liegt zwischen ~8 Stunden und ~14 Stunden Schlaf.

Für das Histogramm lohnt es sich, unterschiedliche Werte für die Anzahl der Klassen (bins) zu testen. Hier sehen wir Höhepunkte um 10 Stunden, aber auch um 14 Stunden und 2 Stunden.

Für kategorische Variablen verwenden wir Balkendiagramme:

msleep_graph + geom_bar(aes(x = vore))

Die meisten Tiere scheinen Herbivore zu sein.

Um für jede dieser Tierklassen den Gesamtschlaf zu betrachten, lassen sich Histogramm oder Boxplot entsprechend anpassen:

# Histogramm aufgeteilt nach Essverhalten
msleep_graph + 
    geom_histogram(aes(x = sleep_total, fill = vore), bins = 10) + 
    geom_freqpoly(aes(x = sleep_total, color = vore), bins = 10)

# Die Verteilung für jede Tierklasse separat:
msleep_graph + 
    geom_freqpoly(aes(x = sleep_total, color = vore), bins = 10)

# Beides zusammen:
msleep_graph + 
    geom_histogram(aes(x = sleep_total), bins = 10) + 
    geom_freqpoly(aes(x = sleep_total, color = vore), bins = 10)

# Boxplots:
msleep_graph + 
    geom_boxplot(aes(x = vore, y = sleep_total))

Aus dem Muster von geom_freqpoly() können wir direkt einsehen, dass der Großteil der Omnivoren um 10 Stunden Schlaf braucht (mit ein paar Ausnahme bei ~16 Stunden), Herbivore um 4 Stunden oder 14 Stunden Schlaf benötigen, Insektivore um 6 Stunden und um 20 Stunden Schlaf benötigen und bei Karnivoren die Verteilung relativ weit gestreckt ist.

Um die Verteilungen direkt vergleichen zu können, lohnt es sich, facets zu erstellen:

msleep_graph + 
    geom_freqpoly(aes(x = sleep_total), bins = 10) +
    facet_wrap(~ vore)

Sie sehen bereits, dass Sie aus den Daten direkt Fragen ableiten können:

  • Warum schlafen die meisten Omnivore so konsequent um 10 Stunden? Was ist mit denen, die sehr viel mehr schlafen (rechts unten)?

  • Wieso gibt es zwei Höhepunkte bei Herbivoren und Insektivoren? Warum schlafen einige sehr viel und andere sehr wenig?

  • Wo liegen die Unterschiede zwischen diesen Gruppen? Wer sind die “Ausreißer” bzw. untypischen Datenpunkte?

  • Hat die Art, auf die Essen erlangt wird, einen Einfluss auf den Schlaf?

  • Was sind die NAs?

1.2.3 Betrachten Sie nun ebenfalls die Variable awake im Bezug auf vore. Entspricht die Verteilung Ihrer Erwartung im Vergleich zu dem sleep_total?

msleep_graph + 
    geom_freqpoly(aes(x = awake), bins = 10) +
    facet_wrap(~ vore)

msleep_graph + 
    geom_freqpoly(aes(x = sleep_total), bins = 10) +
    facet_wrap(~ vore)

Die Grafik entspricht lediglich einer Verschiebung! Das liegt daran, dass sich awake und sleep_total am Tag zu 24 Stunden addieren müssen (Schlafzeit am Tag + “Wachzeit”).

1.2.4 Stellen Sie den Zusammenhang von awake und sleep_total grafisch dar. Was stellen Sie fest?

msleep_graph +
    geom_point(aes(x = sleep_total, y = awake))

Ein perfekter Zusammenhang! Je länger man schläft, desto weniger ist man wach. Das ist keine neue Kenntnis. Allerdings scheinen awake und total_sleep grafisch erst einmal zu passen:

msleep %>%
    mutate(zeit_gesamt = awake + sleep_total) %>%
    filter(zeit_gesamt != 24)

Es gibt zwei Einträge, wo die Summe der beiden Zeitdauern nicht 24 sind. Das könnte durch Rundungsungenauigkeiten passiert sein.

Bei den kleinen Unterschieden scheinen die Einträge vermutlich keine groben Ausreißer zu sein.

1.2.5 Vergleichen Sie geom_violin() mit geom_histogram(), welches Facetten benutzt, um Gruppen darzustellen, und geom_freqpoly(), welches für jede Gruppe Farben einfügt. Verwenden Sie hierfür erneut die Variablen awake und vore.

msleep_graph +
    geom_histogram(aes(awake), bins = 10) +
    facet_wrap(~ vore)

msleep_graph +
    geom_freqpoly(aes(awake, color = vore), bins = 10)

msleep_graph +
    geom_violin(aes(x = vore, y = awake))

Durch das Histogramm mit facets können die Verteilungen direkt verglichen werden. Bei der Liniengrafik mit den Farben sind die Verteilungen teilweise etwas schwerer auseinanderzuhalten. Es ist möglich, allerdings könnten sich hier unter Umständen auch facets anbieten.

Die Violinengrafik ist eine weitere interessante Darstellung, welche dem Boxplot ähnelt. Diese lässt direkt vergleichen, wo welche Kategorie häufiger (oder seltener) auftreten, indem die Breiten variieren. Zum Beispiel scheinen Omnivore meist etwa ~15 Stunden wach zu sein. Im Gegensatz zu Boxplots sind hier jedoch keine statistischen Maßzahlen zu sehen (sondern Dichten).

1.2.6 Stellen Sie die Verteilung von vore und conservation gemeinsam dar.

1.2.6.1 Verwenden Sie hierfür zwei verschiedene Darstellungsarten.

Zunächst könnte sich ein Balkendiagramm anbieten, wobei zwei Kategorien durch Verschiebung (mit position) oder Stapelung dargestellt werden:

msleep_graph +
    geom_bar(aes(vore, fill = conservation))

msleep_graph +
    geom_bar(aes(vore, fill = conservation), position = "dodge")

Die Verschiebung bietet sich insbesondere an, um die Kategorien innerhalb zu vergleichen. Die Stapelung bietet sich insbesondere an, um die Kategorien zwischeneinander zu vergleichen.

Andere Möglichkeiten zeigen die Häufigkeiten durch geom_count() oder geom_tile() an:

msleep_graph +
  geom_count(aes(x = vore, y = conservation))

msleep %>% 
  count(vore, conservation) %>%  
  ggplot() +
    geom_tile(mapping = aes(x = vore, y = conservation, fill = n))

1.2.6.2 Welche Kombination tritt am häufigsten/seltensten auf?

msleep %>% 
    count(vore, conservation) %>%
    filter(n == max(n) | n == min(n))

1.2.6.3 Ändern Sie die Farben des Gradienten der vorherigen Grafik mit Hilfe von scale_fill_gradient(low = farbe1, high = farbe2).

msleep %>% 
  count(vore, conservation) %>% 
    ggplot() +
        geom_tile(mapping = aes(x = vore, y = conservation, fill = n)) +
        scale_fill_gradient(low = "blue", high = "red")

1.2.7 Stellen Sie die gemeinsame Verteilung von vore, brainwt und bodywt dar.

Hierzu gibt es wieder mehrere Möglichkeiten. Da es sich um zwei kontinuierliche und eine kategorische Variable handelt, mag beispielsweise ein Streudiagramm für den Zusammenhang sinnvoll sein:

msleep_graph +
    geom_point(aes(x = bodywt, y = brainwt, color = vore))

msleep_graph +
    geom_point(aes(x = bodywt, y = brainwt)) +
    facet_wrap(~ vore)

Bedauerlicherweise scheinen zwei Punkte besonders hohe Werte bei bodywt aufzuweisen und bei 27 Einträgen fehlen Werte.

Zuerst sollten wir schauen, ob die hohen Werte tatsächlich korrekt sind oder Messfehler:

msleep %>%
    filter(bodywt > 2000)

Wir sehen, dass es sich bei den Einträgen um Elephanten handelt. Es ist also nicht verwunderlich, dass diese wesentlich mehr wiegen.

Selbst nach dem Entfernen der Punkte scheint die Skalierung nicht vorteilhaft:

msleep %>%
    filter(bodywt < 2000) %>%
    ggplot() +
        geom_point(aes(x = bodywt, y = brainwt)) +
        facet_wrap(~ vore)

Um die Punkte besser einzusehen, könnte es sich lohnen, de Achsen anders zu skalieren und geom_jitter() zu verwenden:

msleep %>%
    filter(bodywt < 2000) %>%
    ggplot(aes(x = log2(bodywt), y = log2(brainwt))) +
    geom_jitter() +
    facet_wrap(~ vore)

LS0tCnRpdGxlOiAiw5xidW5nc3pldHRlbCA2IgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6IAogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKLS0tCgojIEF1ZmdhYmVuCgpJbiBkaWVzZW0gQWJzY2huaXR0IHNvbGwgZWluIG5ldWVyIERhdGVuc2F0eiBiZXRyYWNodGV0IHdlcmRlbi4gRGVyCkRhdGVuc2F0eiBgbXNsZWVwYCBiZWhhbmRlbHQgZGFzIFNjaGxhZnZlcmhhbHRlbiB2b24gU8OkdWdldGllcmVuIHVuZApsaWVndCB1bnMgYWxzIEV4Y2VsLURhdGVpIHZvci4gRsO8ciBtZWhyIEluZm9ybWF0aW9uIHRpcHBlbiBTaWUgd2llCmdld29obnQgYD9tc2xlZXBgLgoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKCiMjIMOcYnVuZ3NhdWZnYWJlbgoKMS4gIExlc2VuIFNpZSBkZW4gRGF0ZW5zYXR6IGBtc2xlZXAueGxzeGAgYXVzIE1vb2RsZSBhbHMgYHRpYmJsZWAKICAgIGBtc2xlZXBgIGluIFIgZWluLiBTY2hhZmZlbiBTaWUgc2ljaCBlaW5lbiDDnGJlcmJsaWNrIMO8YmVyIGRlbgogICAgRGF0ZW5zYXR6LgoyLiAgQmV0cmFjaHRlbiBTaWUgZGllIFZlcnRlaWx1bmdlbiBkZXIgVmFyaWFibGVuIGBzbGVlcF90b3RhbGAgdW5kCiAgICBgdm9yZWAuIEJldHJhY2h0ZW4gU2llIGF1Y2ggZGllIEdydXBwaWVydW5nIHZvbiBgc2xlZXBfdG90YWxgIG5hY2gKICAgIGB2b3JlYC4gV2FzIGbDpGxsdCBJaG5lbiBhdWY/CjMuICBCZXRyYWNodGVuIFNpZSBudW4gZWJlbmZhbGxzIGRpZSBWYXJpYWJsZSBgYXdha2VgIGltIEJlenVnIGF1ZgogICAgYHZvcmVgLiBFbnRzcHJpY2h0IGRpZSBWZXJ0ZWlsdW5nIElocmVyIEVyd2FydHVuZyBpbSBWZXJnbGVpY2ggenUKICAgIGRlbSBgc2xlZXBfdG90YWxgPwo0LiAgU3RlbGxlbiBTaWUgZGVuIFp1c2FtbWVuaGFuZyB2b24gYGF3YWtlYCB1bmQgYHNsZWVwX3RvdGFsYCBncmFmaXNjaAogICAgZGFyLiBXYXMgc3RlbGxlbiBTaWUgZmVzdD8KNS4gIFZlcmdsZWljaGVuIFNpZSBgZ2VvbV92aW9saW4oKWAgbWl0IGBnZW9tX2hpc3RvZ3JhbSgpYCwgd2VsY2hlcwogICAgRmFjZXR0ZW4gYmVudXR6dCwgdW0gR3J1cHBlbiBkYXJ6dXN0ZWxsZW4sIHVuZCBgZ2VvbV9mcmVxcG9seSgpYCwKICAgIHdlbGNoZXMgZsO8ciBqZWRlIEdydXBwZSBGYXJiZW4gZWluZsO8Z3QuIFZlcndlbmRlbiBTaWUgaGllcmbDvHIgZXJuZXV0CiAgICBkaWUgVmFyaWFibGVuIGBhd2FrZWAgdW5kIGB2b3JlYC4KNi4gIFN0ZWxsZW4gU2llIGRpZSBWZXJ0ZWlsdW5nIHZvbiBgdm9yZWAgdW5kIGBjb25zZXJ2YXRpb25gIGdlbWVpbnNhbQogICAgZGFyLgogICAgMS4gIFZlcndlbmRlbiBTaWUgaGllcmbDvHIgendlaSB2ZXJzY2hpZWRlbmUgRGFyc3RlbGx1bmdzYXJ0ZW4uCgogICAgMi4gIFdlbGNoZSBLb21iaW5hdGlvbiB0cml0dCBhbSBow6R1Zmlnc3Rlbi9zZWx0ZW5zdGVuIGF1Zj8KCiAgICAzLiAgw4RuZGVybiBTaWUgZGllIEZhcmJlbiBkZXMgR3JhZGllbnRlbiBkZXIgdm9yaGVyaWdlbiBHcmFmaWsgbWl0CiAgICAgICAgSGlsZmUgdm9uIGBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9IGZhcmJlMSwgaGlnaCA9IGZhcmJlMilgLgo3LiAgU3RlbGxlbiBTaWUgZGllIGdlbWVpbnNhbWUgVmVydGVpbHVuZyB2b24gYHZvcmVgLCBgYnJhaW53dGAgdW5kCiAgICBgYm9keXd0YCBkYXIuCgojIyBMw7ZzdW5nZW4KCiMjIyBMZXNlbiBTaWUgZGVuIERhdGVuc2F0eiBgbXNsZWVwLnhsc3hgIGF1cyBNb29kbGUgYWxzIGB0aWJibGVgIGBtc2xlZXBgIGluIFIgZWluLiBTY2hhZmZlbiBTaWUgc2ljaCBlaW5lbiDDnGJlcmJsaWNrIMO8YmVyIGRlbiBEYXRlbnNhdHouCgpEZXIgRW5kdW5nIGVudHNwcmVjaGVuZCBoYW5kZWx0IGVzIHNpY2ggdW0gZWluZSBFeGNlbC1EYXRlaSwgZC4gaC4gd2lyCmJlbsO2dGlnZW4gZGllIGByZWFkeGxgIEJpYmxpb3RoZWs6CgpgYGB7cn0KbGlicmFyeShyZWFkeGwpCm1zbGVlcCA8LSByZWFkX2V4Y2VsKCIuLi9yZXNvdXJjZXMvbXNsZWVwLnhsc3giKSAjIERlciBQZmFkIG11c3MgaW5kaXZpZHVlbGwgYW5nZXBhc3N0IHdlcmRlbgptc2xlZXAKYGBgCgpQYXNzZW4gU2llIGF1ZiwgZGFzcyBTaWUgSWhyZW4gUGZhZCB6dSBkZXIgRGF0ZWkgYnJpbmdlbi4KCkFuc29uc3RlbiBzZWhlbiB3aXIsIGRhc3MgZGVyIERhdGVuc2F0eiBzY2hlaW5iYXIgZGlyZWt0IGtvcnJla3QgKGFscwpgdGliYmxlYCkgZWluZ2VsZXNlbiB3dXJkZSAoRGF0ZW50eXBlbi9IZWFkZXIgc3RpbW1lbikuCgpGw7xyIGVpbmVuIMOcYmVyYmxpY2sgZGVyIFZhcmlhYmxlbiBrw7ZubmVuIHdpciB6dXPDpHR6bGljaCBgc3VtbWFyeSgpYApudXR6ZW46CgpgYGB7cn0Kc3VtbWFyeShtc2xlZXApCmBgYAoKQmVhY2h0ZW4gU2llLCBkYXNzIGRpZSBlcnN0ZW4gNSBTcGFsdGVuIGtlaW5lIEZha3RvcmVuIHNpbmQsIHNvZGFzcyBoaWVyCmtlaW5lIEjDpHVmaWdrZWl0ZW4gZWluenVzZWhlbiBzaW5kLgoKVW0gRmFrdG9yZW4genUgZXJzdGVsbGVuLCBtdXNzIGplZGUgU3BhbHRlIHVtZ2V3YW5kZWx0IHdlcmRlbjoKCmBgYHtyfQptc2xlZXAgPC0gbXNsZWVwICU+JQoJbXV0YXRlKGdlbnVzID0gZmFjdG9yKGdlbnVzKSwKCQkJCSB2b3JlID0gZmFjdG9yKHZvcmUpLAoJCQkJIG9yZGVyID0gZmFjdG9yKG9yZGVyKSwKCQkJCSBjb25zZXJ2YXRpb24gPSBmYWN0b3IoY29uc2VydmF0aW9uKSkKc3VtbWFyeShtc2xlZXApCmBgYAoKV2FydW0gbWFnIGVzIHdlbmlnIFNpbm4gZXJnZWJlbiwgYXVzIGBuYW1lYCBlaW5lbiBGYWt0b3IgenUgbWFjaGVuPwoKIyMjIEJldHJhY2h0ZW4gU2llIGRpZSBWZXJ0ZWlsdW5nZW4gZGVyIFZhcmlhYmxlbiBgc2xlZXBfdG90YWxgIHVuZCBgdm9yZWAuIEJldHJhY2h0ZW4gU2llIGF1Y2ggZGllIEdydXBwaWVydW5nIHZvbiBgc2xlZXBfdG90YWxgIG5hY2ggYHZvcmVgLiBXYXMgZsOkbGx0IElobmVuIGF1Zj8KCkbDvHIgZGllIERhcnN0ZWxsdW5nIGRlciBWZXJ0ZWlsdW5nIHZvbiBxdWFudGl0YXRpdmVuIERhdGVuIHN0ZWh0IGRlcgpCb3hwbG90IHVuZCBkYXMgSGlzdG9ncmFtbSB6dXIgVmVyZsO8Z3VuZzoKCmBgYHtyfQptc2xlZXBfZ3JhcGggPC0gZ2dwbG90KG1zbGVlcCkKIyBCb3hwbG90IHVuZCBIaXN0b2dyYW1tIGbDvHIgYWxsZSBXZXJ0ZQptc2xlZXBfZ3JhcGggKyBnZW9tX2JveHBsb3QoYWVzKHkgPSBzbGVlcF90b3RhbCkpCm1zbGVlcF9ncmFwaCArIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gc2xlZXBfdG90YWwpLCBiaW5zID0gMjApCmBgYAoKRGVyIE1lZGlhbiBsaWVndCBiZWkgMTAgU3R1bmRlbiBTY2hsYWYgdW5kIGRlciBHcm/Dn3RlaWwgZGVyIERhdGVuIGxpZWd0Cnp3aXNjaGVuIFx+OCBTdHVuZGVuIHVuZCBcfjE0IFN0dW5kZW4gU2NobGFmLgoKRsO8ciBkYXMgSGlzdG9ncmFtbSBsb2hudCBlcyBzaWNoLCB1bnRlcnNjaGllZGxpY2hlIFdlcnRlIGbDvHIgZGllIEFuemFobApkZXIgS2xhc3NlbiAoYGJpbnNgKSB6dSB0ZXN0ZW4uIEhpZXIgc2VoZW4gd2lyIEjDtmhlcHVua3RlIHVtIDEwIFN0dW5kZW4sCmFiZXIgYXVjaCB1bSAxNCBTdHVuZGVuIHVuZCAyIFN0dW5kZW4uCgpGw7xyIGthdGVnb3Jpc2NoZSBWYXJpYWJsZW4gdmVyd2VuZGVuIHdpciBCYWxrZW5kaWFncmFtbWU6CgpgYGB7cn0KbXNsZWVwX2dyYXBoICsgZ2VvbV9iYXIoYWVzKHggPSB2b3JlKSkKYGBgCgpEaWUgbWVpc3RlbiBUaWVyZSBzY2hlaW5lbiBIZXJiaXZvcmUgenUgc2Vpbi4KClVtIGbDvHIgamVkZSBkaWVzZXIgVGllcmtsYXNzZW4gZGVuIEdlc2FtdHNjaGxhZiB6dSBiZXRyYWNodGVuLCBsYXNzZW4Kc2ljaCBIaXN0b2dyYW1tIG9kZXIgQm94cGxvdCBlbnRzcHJlY2hlbmQgYW5wYXNzZW46CgpgYGB7cn0KIyBIaXN0b2dyYW1tIGF1ZmdldGVpbHQgbmFjaCBFc3N2ZXJoYWx0ZW4KbXNsZWVwX2dyYXBoICsgCglnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IHNsZWVwX3RvdGFsLCBmaWxsID0gdm9yZSksIGJpbnMgPSAxMCkgKyAKCWdlb21fZnJlcXBvbHkoYWVzKHggPSBzbGVlcF90b3RhbCwgY29sb3IgPSB2b3JlKSwgYmlucyA9IDEwKQojIERpZSBWZXJ0ZWlsdW5nIGbDvHIgamVkZSBUaWVya2xhc3NlIHNlcGFyYXQ6Cm1zbGVlcF9ncmFwaCArIAoJZ2VvbV9mcmVxcG9seShhZXMoeCA9IHNsZWVwX3RvdGFsLCBjb2xvciA9IHZvcmUpLCBiaW5zID0gMTApCiMgQmVpZGVzIHp1c2FtbWVuOgptc2xlZXBfZ3JhcGggKyAKCWdlb21faGlzdG9ncmFtKGFlcyh4ID0gc2xlZXBfdG90YWwpLCBiaW5zID0gMTApICsgCglnZW9tX2ZyZXFwb2x5KGFlcyh4ID0gc2xlZXBfdG90YWwsIGNvbG9yID0gdm9yZSksIGJpbnMgPSAxMCkKIyBCb3hwbG90czoKbXNsZWVwX2dyYXBoICsgCglnZW9tX2JveHBsb3QoYWVzKHggPSB2b3JlLCB5ID0gc2xlZXBfdG90YWwpKQpgYGAKCkF1cyBkZW0gTXVzdGVyIHZvbiBgZ2VvbV9mcmVxcG9seSgpYCBrw7ZubmVuIHdpciBkaXJla3QgZWluc2VoZW4sIGRhc3MKZGVyIEdyb8OfdGVpbCBkZXIgT21uaXZvcmVuIHVtIDEwIFN0dW5kZW4gU2NobGFmIGJyYXVjaHQgKG1pdCBlaW4gcGFhcgpBdXNuYWhtZSBiZWkgXH4xNiBTdHVuZGVuKSwgSGVyYml2b3JlIHVtIDQgU3R1bmRlbiBvZGVyIDE0IFN0dW5kZW4KU2NobGFmIGJlbsO2dGlnZW4sIEluc2VrdGl2b3JlIHVtIDYgU3R1bmRlbiB1bmQgdW0gMjAgU3R1bmRlbiBTY2hsYWYKYmVuw7Z0aWdlbiB1bmQgYmVpIEthcm5pdm9yZW4gZGllIFZlcnRlaWx1bmcgcmVsYXRpdiB3ZWl0IGdlc3RyZWNrdCBpc3QuCgpVbSBkaWUgVmVydGVpbHVuZ2VuIGRpcmVrdCB2ZXJnbGVpY2hlbiB6dSBrw7ZubmVuLCBsb2hudCBlcyBzaWNoLApgZmFjZXRzYCB6dSBlcnN0ZWxsZW46CgpgYGB7cn0KbXNsZWVwX2dyYXBoICsgCglnZW9tX2ZyZXFwb2x5KGFlcyh4ID0gc2xlZXBfdG90YWwpLCBiaW5zID0gMTApICsKCWZhY2V0X3dyYXAofiB2b3JlKQpgYGAKClNpZSBzZWhlbiBiZXJlaXRzLCBkYXNzIFNpZSBhdXMgZGVuIERhdGVuIGRpcmVrdCBGcmFnZW4gYWJsZWl0ZW4ga8O2bm5lbjoKCi0gICBXYXJ1bSBzY2hsYWZlbiBkaWUgbWVpc3RlbiBPbW5pdm9yZSBzbyBrb25zZXF1ZW50IHVtIDEwIFN0dW5kZW4/IFdhcwogICAgaXN0IG1pdCBkZW5lbiwgZGllIHNlaHIgdmllbCBtZWhyIHNjaGxhZmVuIChyZWNodHMgdW50ZW4pPwoKLSAgIFdpZXNvIGdpYnQgZXMgendlaSBIw7ZoZXB1bmt0ZSBiZWkgSGVyYml2b3JlbiB1bmQgSW5zZWt0aXZvcmVuPyBXYXJ1bQogICAgc2NobGFmZW4gZWluaWdlIHNlaHIgdmllbCB1bmQgYW5kZXJlIHNlaHIgd2VuaWc/CgotICAgV28gbGllZ2VuIGRpZSBVbnRlcnNjaGllZGUgendpc2NoZW4gZGllc2VuIEdydXBwZW4/IFdlciBzaW5kIGRpZQogICAgIkF1c3JlacOfZXIiIGJ6dy4gdW50eXBpc2NoZW4gRGF0ZW5wdW5rdGU/CgotICAgSGF0IGRpZSBBcnQsIGF1ZiBkaWUgRXNzZW4gZXJsYW5ndCB3aXJkLCBlaW5lbiBFaW5mbHVzcyBhdWYgZGVuCiAgICBTY2hsYWY/CgotICAgV2FzIHNpbmQgZGllIGBOQXNgPwoKLSAgIC4uLgoKIyMjIEJldHJhY2h0ZW4gU2llIG51biBlYmVuZmFsbHMgZGllIFZhcmlhYmxlIGBhd2FrZWAgaW0gQmV6dWcgYXVmIGB2b3JlYC4gRW50c3ByaWNodCBkaWUgVmVydGVpbHVuZyBJaHJlciBFcndhcnR1bmcgaW0gVmVyZ2xlaWNoIHp1IGRlbSBgc2xlZXBfdG90YWxgPwoKYGBge3J9Cm1zbGVlcF9ncmFwaCArIAoJZ2VvbV9mcmVxcG9seShhZXMoeCA9IGF3YWtlKSwgYmlucyA9IDEwKSArCglmYWNldF93cmFwKH4gdm9yZSkKbXNsZWVwX2dyYXBoICsgCglnZW9tX2ZyZXFwb2x5KGFlcyh4ID0gc2xlZXBfdG90YWwpLCBiaW5zID0gMTApICsKCWZhY2V0X3dyYXAofiB2b3JlKQpgYGAKCkRpZSBHcmFmaWsgZW50c3ByaWNodCBsZWRpZ2xpY2ggZWluZXIgVmVyc2NoaWVidW5nISBEYXMgbGllZ3QgZGFyYW4sCmRhc3Mgc2ljaCBgYXdha2VgIHVuZCBgc2xlZXBfdG90YWxgIGFtIFRhZyB6dSAyNCBTdHVuZGVuIGFkZGllcmVuIG3DvHNzZW4KKFNjaGxhZnplaXQgYW0gVGFnICsgIldhY2h6ZWl0IikuCgojIyMgU3RlbGxlbiBTaWUgZGVuIFp1c2FtbWVuaGFuZyB2b24gYGF3YWtlYCB1bmQgYHNsZWVwX3RvdGFsYCBncmFmaXNjaCBkYXIuIFdhcyBzdGVsbGVuIFNpZSBmZXN0PwoKYGBge3J9Cm1zbGVlcF9ncmFwaCArCglnZW9tX3BvaW50KGFlcyh4ID0gc2xlZXBfdG90YWwsIHkgPSBhd2FrZSkpCmBgYAoKRWluIHBlcmZla3RlciBadXNhbW1lbmhhbmchIEplIGzDpG5nZXIgbWFuIHNjaGzDpGZ0LCBkZXN0byB3ZW5pZ2VyIGlzdCBtYW4Kd2FjaC4gRGFzIGlzdCBrZWluZSBuZXVlIEtlbm50bmlzLiBBbGxlcmRpbmdzIHNjaGVpbmVuIGBhd2FrZWAgdW5kCmB0b3RhbF9zbGVlcGAgZ3JhZmlzY2ggZXJzdCBlaW5tYWwgenUgcGFzc2VuOgoKYGBge3J9Cm1zbGVlcCAlPiUKCW11dGF0ZSh6ZWl0X2dlc2FtdCA9IGF3YWtlICsgc2xlZXBfdG90YWwpICU+JQoJZmlsdGVyKHplaXRfZ2VzYW10ICE9IDI0KQpgYGAKCkVzIGdpYnQgendlaSBFaW50csOkZ2UsIHdvIGRpZSBTdW1tZSBkZXIgYmVpZGVuIFplaXRkYXVlcm4gbmljaHQgMjQgc2luZC4KRGFzIGvDtm5udGUgZHVyY2ggUnVuZHVuZ3N1bmdlbmF1aWdrZWl0ZW4gcGFzc2llcnQgc2Vpbi4KCkJlaSBkZW4ga2xlaW5lbiBVbnRlcnNjaGllZGVuIHNjaGVpbmVuIGRpZSBFaW50csOkZ2UgdmVybXV0bGljaCBrZWluZQpncm9iZW4gQXVzcmVpw59lciB6dSBzZWluLgoKIyMjIFZlcmdsZWljaGVuIFNpZSBgZ2VvbV92aW9saW4oKWAgbWl0IGBnZW9tX2hpc3RvZ3JhbSgpYCwgd2VsY2hlcyBGYWNldHRlbiBiZW51dHp0LCB1bSBHcnVwcGVuIGRhcnp1c3RlbGxlbiwgdW5kIGBnZW9tX2ZyZXFwb2x5KClgLCB3ZWxjaGVzIGbDvHIgamVkZSBHcnVwcGUgRmFyYmVuIGVpbmbDvGd0LiBWZXJ3ZW5kZW4gU2llIGhpZXJmw7xyIGVybmV1dCBkaWUgVmFyaWFibGVuIGBhd2FrZWAgdW5kIGB2b3JlYC4KCmBgYHtyfQptc2xlZXBfZ3JhcGggKwoJZ2VvbV9oaXN0b2dyYW0oYWVzKGF3YWtlKSwgYmlucyA9IDEwKSArCglmYWNldF93cmFwKH4gdm9yZSkKbXNsZWVwX2dyYXBoICsKCWdlb21fZnJlcXBvbHkoYWVzKGF3YWtlLCBjb2xvciA9IHZvcmUpLCBiaW5zID0gMTApCm1zbGVlcF9ncmFwaCArCglnZW9tX3Zpb2xpbihhZXMoeCA9IHZvcmUsIHkgPSBhd2FrZSkpCmBgYAoKRHVyY2ggZGFzIEhpc3RvZ3JhbW0gbWl0IGBmYWNldHNgIGvDtm5uZW4gZGllIFZlcnRlaWx1bmdlbiBkaXJla3QKdmVyZ2xpY2hlbiB3ZXJkZW4uIEJlaSBkZXIgTGluaWVuZ3JhZmlrIG1pdCBkZW4gRmFyYmVuIHNpbmQgZGllClZlcnRlaWx1bmdlbiB0ZWlsd2Vpc2UgZXR3YXMgc2Nod2VyZXIgYXVzZWluYW5kZXJ6dWhhbHRlbi4gRXMgaXN0Cm3DtmdsaWNoLCBhbGxlcmRpbmdzIGvDtm5udGVuIHNpY2ggaGllciB1bnRlciBVbXN0w6RuZGVuIGF1Y2ggYGZhY2V0c2AKYW5iaWV0ZW4uCgpEaWUgVmlvbGluZW5ncmFmaWsgaXN0IGVpbmUgd2VpdGVyZSBpbnRlcmVzc2FudGUgRGFyc3RlbGx1bmcsIHdlbGNoZSBkZW0KQm94cGxvdCDDpGhuZWx0LiBEaWVzZSBsw6Rzc3QgZGlyZWt0IHZlcmdsZWljaGVuLCB3byB3ZWxjaGUgS2F0ZWdvcmllCmjDpHVmaWdlciAob2RlciBzZWx0ZW5lcikgYXVmdHJldGVuLCBpbmRlbSBkaWUgQnJlaXRlbiB2YXJpaWVyZW4uIFp1bQpCZWlzcGllbCBzY2hlaW5lbiBPbW5pdm9yZSBtZWlzdCBldHdhIFx+MTUgU3R1bmRlbiB3YWNoIHp1IHNlaW4uIEltCkdlZ2Vuc2F0eiB6dSBCb3hwbG90cyBzaW5kIGhpZXIgamVkb2NoIGtlaW5lIHN0YXRpc3Rpc2NoZW4gTWHDn3phaGxlbiB6dQpzZWhlbiAoc29uZGVybiBEaWNodGVuKS4KCiMjIyBTdGVsbGVuIFNpZSBkaWUgVmVydGVpbHVuZyB2b24gYHZvcmVgIHVuZCBgY29uc2VydmF0aW9uYCBnZW1laW5zYW0gZGFyLgoKIyMjIyBWZXJ3ZW5kZW4gU2llIGhpZXJmw7xyIHp3ZWkgdmVyc2NoaWVkZW5lIERhcnN0ZWxsdW5nc2FydGVuLgoKWnVuw6RjaHN0IGvDtm5udGUgc2ljaCBlaW4gQmFsa2VuZGlhZ3JhbW0gYW5iaWV0ZW4sIHdvYmVpIHp3ZWkgS2F0ZWdvcmllbgpkdXJjaCBWZXJzY2hpZWJ1bmcgKG1pdCBgcG9zaXRpb25gKSBvZGVyIFN0YXBlbHVuZyBkYXJnZXN0ZWxsdCB3ZXJkZW46CgpgYGB7cn0KbXNsZWVwX2dyYXBoICsKCWdlb21fYmFyKGFlcyh2b3JlLCBmaWxsID0gY29uc2VydmF0aW9uKSkKbXNsZWVwX2dyYXBoICsKCWdlb21fYmFyKGFlcyh2b3JlLCBmaWxsID0gY29uc2VydmF0aW9uKSwgcG9zaXRpb24gPSAiZG9kZ2UiKQpgYGAKCkRpZSBWZXJzY2hpZWJ1bmcgYmlldGV0IHNpY2ggaW5zYmVzb25kZXJlIGFuLCB1bSBkaWUgS2F0ZWdvcmllbgppbm5lcmhhbGIgenUgdmVyZ2xlaWNoZW4uIERpZSBTdGFwZWx1bmcgYmlldGV0IHNpY2ggaW5zYmVzb25kZXJlIGFuLCB1bQpkaWUgS2F0ZWdvcmllbiB6d2lzY2hlbmVpbmFuZGVyIHp1IHZlcmdsZWljaGVuLgoKQW5kZXJlIE3DtmdsaWNoa2VpdGVuIHplaWdlbiBkaWUgSMOkdWZpZ2tlaXRlbiBkdXJjaCBgZ2VvbV9jb3VudCgpYCBvZGVyCmBnZW9tX3RpbGUoKWAgYW46CgpgYGB7cn0KbXNsZWVwX2dyYXBoICsKICBnZW9tX2NvdW50KGFlcyh4ID0gdm9yZSwgeSA9IGNvbnNlcnZhdGlvbikpCm1zbGVlcCAlPiUgCiAgY291bnQodm9yZSwgY29uc2VydmF0aW9uKSAlPiUgIAogIGdncGxvdCgpICsKICAgIGdlb21fdGlsZShtYXBwaW5nID0gYWVzKHggPSB2b3JlLCB5ID0gY29uc2VydmF0aW9uLCBmaWxsID0gbikpCmBgYAoKIyMjIyBXZWxjaGUgS29tYmluYXRpb24gdHJpdHQgYW0gaMOkdWZpZ3N0ZW4vc2VsdGVuc3RlbiBhdWY/CgpgYGB7cn0KbXNsZWVwICU+JSAKCWNvdW50KHZvcmUsIGNvbnNlcnZhdGlvbikgJT4lCglmaWx0ZXIobiA9PSBtYXgobikgfCBuID09IG1pbihuKSkKYGBgCgojIyMjIMOEbmRlcm4gU2llIGRpZSBGYXJiZW4gZGVzIEdyYWRpZW50ZW4gZGVyIHZvcmhlcmlnZW4gR3JhZmlrIG1pdCBIaWxmZSB2b24gYHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gZmFyYmUxLCBoaWdoID0gZmFyYmUyKWAuCgpgYGB7cn0KbXNsZWVwICU+JSAKICBjb3VudCh2b3JlLCBjb25zZXJ2YXRpb24pICU+JSAKCWdncGxvdCgpICsKCQlnZW9tX3RpbGUobWFwcGluZyA9IGFlcyh4ID0gdm9yZSwgeSA9IGNvbnNlcnZhdGlvbiwgZmlsbCA9IG4pKSArCgkJc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAiYmx1ZSIsIGhpZ2ggPSAicmVkIikKYGBgCgojIyMgU3RlbGxlbiBTaWUgZGllIGdlbWVpbnNhbWUgVmVydGVpbHVuZyB2b24gYHZvcmVgLCBgYnJhaW53dGAgdW5kIGBib2R5d3RgIGRhci4KCkhpZXJ6dSBnaWJ0IGVzIHdpZWRlciBtZWhyZXJlIE3DtmdsaWNoa2VpdGVuLiBEYSBlcyBzaWNoIHVtIHp3ZWkKa29udGludWllcmxpY2hlIHVuZCBlaW5lIGthdGVnb3Jpc2NoZSBWYXJpYWJsZSBoYW5kZWx0LCBtYWcKYmVpc3BpZWxzd2Vpc2UgZWluIFN0cmV1ZGlhZ3JhbW0gZsO8ciBkZW4gWnVzYW1tZW5oYW5nIHNpbm52b2xsIHNlaW46CgpgYGB7cn0KbXNsZWVwX2dyYXBoICsKCWdlb21fcG9pbnQoYWVzKHggPSBib2R5d3QsIHkgPSBicmFpbnd0LCBjb2xvciA9IHZvcmUpKQptc2xlZXBfZ3JhcGggKwoJZ2VvbV9wb2ludChhZXMoeCA9IGJvZHl3dCwgeSA9IGJyYWlud3QpKSArCglmYWNldF93cmFwKH4gdm9yZSkKYGBgCgpCZWRhdWVybGljaGVyd2Vpc2Ugc2NoZWluZW4gendlaSBQdW5rdGUgYmVzb25kZXJzIGhvaGUgV2VydGUgYmVpCmBib2R5d3RgIGF1Znp1d2Vpc2VuIHVuZCBiZWkgMjcgRWludHLDpGdlbiBmZWhsZW4gV2VydGUuCgpadWVyc3Qgc29sbHRlbiB3aXIgc2NoYXVlbiwgb2IgZGllIGhvaGVuIFdlcnRlIHRhdHPDpGNobGljaCBrb3JyZWt0IHNpbmQKb2RlciBNZXNzZmVobGVyOgoKYGBge3J9Cm1zbGVlcCAlPiUKCWZpbHRlcihib2R5d3QgPiAyMDAwKQpgYGAKCldpciBzZWhlbiwgZGFzcyBlcyBzaWNoIGJlaSBkZW4gRWludHLDpGdlbiB1bSBFbGVwaGFudGVuIGhhbmRlbHQuIEVzIGlzdAphbHNvIG5pY2h0IHZlcnd1bmRlcmxpY2gsIGRhc3MgZGllc2Ugd2VzZW50bGljaCBtZWhyIHdpZWdlbi4KClNlbGJzdCBuYWNoIGRlbSBFbnRmZXJuZW4gZGVyIFB1bmt0ZSBzY2hlaW50IGRpZSBTa2FsaWVydW5nIG5pY2h0CnZvcnRlaWxoYWZ0OgoKYGBge3J9Cm1zbGVlcCAlPiUKCWZpbHRlcihib2R5d3QgPCAyMDAwKSAlPiUKCWdncGxvdCgpICsKCQlnZW9tX3BvaW50KGFlcyh4ID0gYm9keXd0LCB5ID0gYnJhaW53dCkpICsKCQlmYWNldF93cmFwKH4gdm9yZSkKYGBgCgpVbSBkaWUgUHVua3RlIGJlc3NlciBlaW56dXNlaGVuLCBrw7ZubnRlIGVzIHNpY2ggbG9obmVuLCBkZSBBY2hzZW4gYW5kZXJzCnp1IHNrYWxpZXJlbiB1bmQgYGdlb21faml0dGVyKClgIHp1IHZlcndlbmRlbjoKCmBgYHtyfQptc2xlZXAgJT4lCglmaWx0ZXIoYm9keXd0IDwgMjAwMCkgJT4lCglnZ3Bsb3QoYWVzKHggPSBsb2cyKGJvZHl3dCksIHkgPSBsb2cyKGJyYWlud3QpKSkgKwoJZ2VvbV9qaXR0ZXIoKSArCglmYWNldF93cmFwKH4gdm9yZSkKYGBgCg==