1 Aufgaben

In diesem Abschnitt soll erneut der diamonds Datensatz betrachtet werden:

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()
diamonds

1.1 Übungsaufgaben

  1. Überlegen Sie zunächst, nach welchen Variablen sich der Datensatz diamonds gruppieren lässt. Denken Sie hierbei besonders an die unterschiedlichen Datentypen.

  2. Welche Farbe der Diamanten hat den geringsten Wert?

    1. Wie erklären Sie sich das Ergebnis?

    2. Erstellen und betrachten Sie hierzu auch ein Streudiagramm mit dem Zusammenhang von carat und price bezüglich der Farben.

  3. Gruppieren Sie die Diamanten nach der Variable cut und berechnen Sie die Mittelwerte für carat, price und depth.

    1. Erkennen Sie hierbei Zusammenhänge?

    2. Stellen Sie die durchschnittlichen Preise durch Balkendiagramme für alle Kategorien von cut dar.

    3. Erstellen Sie einen Boxplot mit den Preisen für jede Kategorie cut. Vergleichen Sie das Ergebnis mit dem Balkendiagramm.

  4. Gruppieren Sie die Diamanten nach carat und berechnen Sie Minimum, Maximum und Mittelwert von price.

    1. Erstellen Sie auf Grundlage der Mittelwerte und der Variable carat ein Streudiagramm.

    2. Erstellen Sie ein Streudiagramm für alle Einträge mit carat und price. Fügen Sie zusätzlich die bestimmten Mittelwerte in die Grafik mit geom_line() ein. Setzen Sie hierzu stat = "smooth".

    3. Entfernen Sie zuletzt alle Einträge, die seltener als 20 mal auftreten.

  5. Finden Sie für jede Kategorie von color die Tiefen (depth), bei denen mehr als 25%, 50% und 75% der Diamanten einen geringen Wert aufweisen.

  6. Finden Sie für jeden cut den teuersten und den günstigsten Diamanten. Entspricht das Ergebnis Ihren Erwartungen? Woran kann dieser Zusammenhang liegen?

  7. Betrachten Sie neben dem cut auch die Klarheit clarity und geben Sie den Anteil und die Anzahl von Diamanten mit einem Preis von über 10000 aus.

    1. Wählen Sie im Anschluss die ersten fünf aller Ergebnisse aus. Stoßen Sie hierbei auf ein Problem?

    2. Erstellen Sie eine Grafik mit Histogrammen der Preise für alle Kategorien von cut und clarity (durch facet_grid()).

    3. Markieren Sie in der Grafik die Bereiche rot, bei denen der Preis über 10000 liegt. Vergleichen Sie die Grafik mit den Anteilen, die Sie zuvor berechnet haben.

1.2 Lösungen

1.2.1 Überlegen Sie zunächst, nach welchen Variablen sich der Datensatz diamonds sinnvoll gruppieren lässt. Denken Sie hierbei besonders an die unterschiedlichen Datentypen.

Betrachten Sie hierzu den Dataframe diamonds und schauen Sie direkt unter die Variablen. Variablen mit dem Anhängsel <chr> oder <ord> sind kategorisch/qualitativ, d. h. nach ihnen lässt sich gruppieren.

Andere Variablen wie z. B. <int> oder <dbl> sind quantitative Variablen.

Es kann vorkommen, dass Kategorien durch ganze Zahlen (1, 2, 3, …) dargestellt werden, obwohl sie eine ursprüngliche Bedeutung haben. In dem Fall handelt es sich trotzdem um qualitative Daten, auch wenn die Variable als <int> markiert ist. Achten Sie darauf, dass Ihre selbst erhobenen Daten aussagekräftig sind, damit das nicht vorkommt.

Demnach handelt es sich bei cut, color und clarity augenscheinlich um qualitative Daten und bei dem Rest um quantitative Daten.

Theoretisch lassen sich alle Variablen zum Gruppieren verwenden. In der Praxis mag es unter wenigen Ausnahmen keinen Sinn ergeben, Gruppen für numerische Werte zu erstellen, da die Anzahl der Gruppen sehr hoch sein wird.

1.2.2 Welche Farbe der Diamanten hat den geringsten Wert?

Der naive Ansatz sucht direkt nach dem Diamanten mit dem gerinsten Wert:

diamonds %>%
    slice_min(price)

Um den Wert von Diamanten einer Farbe zu betrachten, kann es jedoch Sinn ergeben, den Durchschnittspreis für jede Farbe zu berechnen:

diamonds %>%
    group_by(color) %>%
    summarise(durchschnittspreis = mean(price)) %>%
    arrange(durchschnittspreis)

Interessanterweise haben die Diamanten mit einer guten Farbe (D/E) einen geringeren Durchschnittswert als die Diamanten mit einer schlechteren Farbe (I/J).

1.2.2.1 Wie erklären Sie sich das Ergebnis?

Es muss neben der Farbe noch andere Faktoren geben, die einen größeren Einfluss auf den Preis haben. Eine Variable, die einem direkt in den Sinn kommt, ist der Karatwert der Diamanten.

1.2.2.2 Erstellen und betrachten Sie hierzu auch ein Streudiagramm mit dem Zusammenhang von carat und price bezüglich der Farben.

Diese Grafik hatten wir bereits zuvor erstellt (eine Gitteransicht mit facet könnte auch angebracht sein):

ggplot(diamonds) +
    geom_point(aes(carat, price, color = color))

Es fällt auf, dass die Diamanten mit einer schlechteren Farbe tendenziell einen höheren Karatwert aufweisen. Die Unterschiede scheinen deutlich zu sein, aber um sicherzugehen, könnten wir beispielsweise zusätzlich den Durchschnittskaratwert berechnen:

diamonds %>%
    group_by(color) %>%
    summarise(durchschnittspreis = mean(price),
                        durchschnittskarat = mean(carat)) %>%
    arrange(durchschnittspreis)

Tatsächlich weisen die Diamanten mit schlechten Farben durchschnittlich einen höheren Karatwert auf. Das ist zwar noch kein statistischer Nachweis, allerdings ein gutes Indiz.

Es zeigt sich jedoch auch, dass Diamanten mit einer guten Farbe auch mit geringeren Karatwerten schneller einen hohen Preis erzielen.

1.3 Gruppieren Sie die Diamanten nach der Variable cut und berechnen Sie die Mittelwerte für carat, price und depth.

schnitt <- diamonds %>%
    group_by(cut) %>%
    summarise(ds_karat = mean(carat),
                        ds_preis = mean(price),
                        ds_tiefe = mean(depth))
schnitt

1.3.0.1 Erkennen Sie hierbei Zusammenhänge?

Diamanten mit einem schlechten Schnitt (Fair) erhalten durchschnittlich einen ähnlichen Preis wie Diamanten mit einem guten Schnitt. Das mag an einem durchschnittlich höheren Karatwert liegen.

Auch die Tiefe der Diamanten mit einem schlechten Schnitt ist höher als die anderen Kategorien.

Ideal schneidet bei dem Preis am schlechtesten ab.

1.3.0.2 Stellen Sie die durchschnittlichen Preise durch Balkendiagramme für alle Kategorien von cut dar.

ggplot(schnitt) +
    geom_bar(aes(cut, ds_preis, fill = cut), stat = "identity")

1.3.0.3 Erstellen Sie einen Boxplot mit den Preisen für jede Kategorie cut. Vergleichen Sie das Ergebnis mit dem Balkendiagramm.

ggplot(diamonds) +
    geom_boxplot(aes(x = cut, y = price, fill = cut))

Die Mediane scheinen etwas unter dem arithmetischen Mittel zu liegen. Es bleibt dennoch ersichtlich, dass die Diamanten mit einem idealen Schnitt etwas weniger wert sind und die Diamanten mit schlechtem Schnitt etwas mehr wert sind.

Vorsicht ist auch hier geboten, denn auch Diamanten mit einer sehr guten Qualität erreichen bereits bei kleineren Karatwerten einen hohen Preis:

ggplot(diamonds) +
    geom_point(aes(carat, price, color = cut)) +
    geom_smooth(aes(carat, price, color = cut), se = FALSE)

1.3.1 Gruppieren Sie die Diamanten nach carat und berechnen Sie Minimum, Maximum und Mittelwert von price.

karat <- diamonds %>%
    group_by(carat) %>%
    summarise(min_preis = min(price),
                        max_preis = max(price),
                        ds_preis = mean(price),
                        anzahl = n())
karat

1.3.1.1 Erstellen Sie auf Grundlage der Mittelwerte und der Variable carat ein Streudiagramm.

ggplot(karat) +
    geom_point(aes(carat, ds_preis, alpha = anzahl))

1.3.1.2 Erstellen Sie ein Streudiagramm für alle Einträge mit carat und price. Fügen Sie zusätzlich die bestimmten Mittelwerte in die Grafik mit geom_line() ein. Setzen Sie hierzu stat = "smooth".

ggplot(diamonds) +
    geom_point(aes(carat, price)) +
    geom_line(data = karat, aes(carat, ds_preis), color = "red", stat = "smooth")

Das ganze erinnert ein wenig an geom_smooth():

ggplot(diamonds, aes(carat, price)) +
    geom_point() +
    geom_smooth(se = F, color = "red")

1.3.1.3 Entfernen Sie zuletzt alle Einträge, die seltener als 20 mal auftreten.

1.3.2 Finden Sie für jede Kategorie von color die Tiefen (depth), bei denen mehr als 25%, 50% und 75% der Diamanten einen geringen Wert aufweisen.

diamonds %>%
    group_by(color) %>%
    summarise(quantile = quantile(depth, c(0.25, 0.5, 0.75)))
`summarise()` has grouped output by 'color'. You can override using the `.groups` argument.
# oder getrennt:
diamonds %>%
    group_by(color) %>%
    summarise(erstes_quartil = quantile(depth, 0.25),
                        zweites_quartil = quantile(depth, 0.5),
                        drittes_quartil = quantile(depth, 0.65))

1.3.3 Finden Sie für jeden cut den teuersten und den günstigsten Diamanten. Entspricht das Ergebnis Ihren Erwartungen? Woran kann dieser Zusammenhang liegen?

diamonds %>%
    group_by(cut) %>%
    summarise(guenstigster = min(price),
                        teuerster = max(price))

Es scheinen für jede Kategorie von cut ähnlich günstige oder teuere Diamanten vorzuliegen.

Den vorherigen Grafiken ist zu entnehmen, dass das erneut wohl an den unterschiedlichen Karatwerten liegt.

1.3.4 Betrachten Sie neben dem cut auch die Klarheit clarity und geben Sie den Anteil und die Anzahl von Diamanten mit einem Preis von über 10000 aus.

teuere_diamanten <- diamonds %>%
    group_by(cut, clarity) %>%
    summarise(anteil_teuer = mean(price > 10000),
                        anzahl_teuer = sum(price > 10000))
`summarise()` has grouped output by 'cut'. You can override using the `.groups` argument.
teuere_diamanten

1.3.4.1 Wählen Sie im Anschluss die ersten fünf aller Ergebnisse aus. Stoßen Sie hierbei auf ein Problem?

Wenn man nach der Gruppierung direkt eine Operation durchführt, gilt diese für beide Kategorien cut und clarity kombiniert:

teuere_diamanten %>%
    slice_min(desc(anzahl_teuer), n = 5)

Es muss also zuerst die Gruppierung entfernt werden:

teuere_diamanten %>%
    ungroup() %>%
    slice_min(desc(anzahl_teuer), n = 5)

1.3.4.2 Erstellen Sie eine Grafik mit Histogrammen der Preise für alle Kategorien von cut und clarity (durch facet_grid()).

histogramm <- ggplot(diamonds, aes(price)) +
    geom_histogram(aes(fill = cut)) +
    facet_grid(cut ~ clarity)
histogramm

1.3.4.3 Markieren Sie in der Grafik die Bereiche rot, bei denen der Preis über 10000 liegt. Vergleichen Sie die Grafik mit den Anteilen, die Sie zuvor berechnet haben.

histogramm +
    geom_histogram(data = filter(diamonds, price > 10000), aes(price), fill = "red")

LS0tCnRpdGxlOiAiw5xidW5nc3pldHRlbCA1IgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6IAogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKLS0tCgojIEF1ZmdhYmVuCgpJbiBkaWVzZW0gQWJzY2huaXR0IHNvbGwgZXJuZXV0IGRlciBgZGlhbW9uZHNgIERhdGVuc2F0eiBiZXRyYWNodGV0CndlcmRlbjoKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKZGlhbW9uZHMKYGBgCgojIyDDnGJ1bmdzYXVmZ2FiZW4KCjEuICDDnGJlcmxlZ2VuIFNpZSB6dW7DpGNoc3QsIG5hY2ggd2VsY2hlbiBWYXJpYWJsZW4gc2ljaCBkZXIgRGF0ZW5zYXR6CiAgICBgZGlhbW9uZHNgIGdydXBwaWVyZW4gbMOkc3N0LiBEZW5rZW4gU2llIGhpZXJiZWkgYmVzb25kZXJzIGFuIGRpZQogICAgdW50ZXJzY2hpZWRsaWNoZW4gRGF0ZW50eXBlbi4KCjIuICBXZWxjaGUgRmFyYmUgZGVyIERpYW1hbnRlbiBoYXQgZGVuIGdlcmluZ3N0ZW4gV2VydD8KCiAgICAxLiAgV2llIGVya2zDpHJlbiBTaWUgc2ljaCBkYXMgRXJnZWJuaXM/CgogICAgMi4gIEVyc3RlbGxlbiB1bmQgYmV0cmFjaHRlbiBTaWUgaGllcnp1IGF1Y2ggZWluIFN0cmV1ZGlhZ3JhbW0gbWl0CiAgICAgICAgZGVtIFp1c2FtbWVuaGFuZyB2b24gYGNhcmF0YCB1bmQgYHByaWNlYCBiZXrDvGdsaWNoIGRlciBGYXJiZW4uCgozLiAgR3J1cHBpZXJlbiBTaWUgZGllIERpYW1hbnRlbiBuYWNoIGRlciBWYXJpYWJsZSBgY3V0YCB1bmQgYmVyZWNobmVuCiAgICBTaWUgZGllIE1pdHRlbHdlcnRlIGbDvHIgYGNhcmF0YCwgYHByaWNlYCB1bmQgYGRlcHRoYC4KCiAgICAxLiAgRXJrZW5uZW4gU2llIGhpZXJiZWkgWnVzYW1tZW5ow6RuZ2U/CgogICAgMi4gIFN0ZWxsZW4gU2llIGRpZSBkdXJjaHNjaG5pdHRsaWNoZW4gUHJlaXNlIGR1cmNoIEJhbGtlbmRpYWdyYW1tZQogICAgICAgIGbDvHIgYWxsZSBLYXRlZ29yaWVuIHZvbiBgY3V0YCBkYXIuCgogICAgMy4gIEVyc3RlbGxlbiBTaWUgZWluZW4gQm94cGxvdCBtaXQgZGVuIFByZWlzZW4gZsO8ciBqZWRlIEthdGVnb3JpZQogICAgICAgIGBjdXRgLiBWZXJnbGVpY2hlbiBTaWUgZGFzIEVyZ2VibmlzIG1pdCBkZW0gQmFsa2VuZGlhZ3JhbW0uCgo0LiAgR3J1cHBpZXJlbiBTaWUgZGllIERpYW1hbnRlbiBuYWNoIGBjYXJhdGAgdW5kIGJlcmVjaG5lbiBTaWUgTWluaW11bSwKICAgIE1heGltdW0gdW5kIE1pdHRlbHdlcnQgdm9uIGBwcmljZWAuCgogICAgMS4gIEVyc3RlbGxlbiBTaWUgYXVmIEdydW5kbGFnZSBkZXIgTWl0dGVsd2VydGUgdW5kIGRlciBWYXJpYWJsZQogICAgICAgIGBjYXJhdGAgZWluIFN0cmV1ZGlhZ3JhbW0uCgogICAgMi4gIEVyc3RlbGxlbiBTaWUgZWluIFN0cmV1ZGlhZ3JhbW0gZsO8ciBhbGxlIEVpbnRyw6RnZSBtaXQgYGNhcmF0YAogICAgICAgIHVuZCBgcHJpY2VgLiBGw7xnZW4gU2llIHp1c8OkdHpsaWNoIGRpZSBiZXN0aW1tdGVuIE1pdHRlbHdlcnRlIGluCiAgICAgICAgZGllIEdyYWZpayBtaXQgYGdlb21fbGluZSgpYCBlaW4uIFNldHplbiBTaWUgaGllcnp1CiAgICAgICAgYHN0YXQgPSAic21vb3RoImAuCgogICAgMy4gIEVudGZlcm5lbiBTaWUgenVsZXR6dCBhbGxlIEVpbnRyw6RnZSwgZGllIHNlbHRlbmVyIGFscyAyMCBtYWwKICAgICAgICBhdWZ0cmV0ZW4uCgo1LiAgRmluZGVuIFNpZSBmw7xyIGplZGUgS2F0ZWdvcmllIHZvbiBgY29sb3JgIGRpZSBUaWVmZW4gKGBkZXB0aGApLCBiZWkKICAgIGRlbmVuIG1laHIgYWxzIDI1JSwgNTAlIHVuZCA3NSUgZGVyIERpYW1hbnRlbiBlaW5lbiBnZXJpbmdlbiBXZXJ0CiAgICBhdWZ3ZWlzZW4uCgo2LiAgRmluZGVuIFNpZSBmw7xyIGplZGVuIGBjdXRgIGRlbiB0ZXVlcnN0ZW4gdW5kIGRlbiBnw7xuc3RpZ3N0ZW4KICAgIERpYW1hbnRlbi4gRW50c3ByaWNodCBkYXMgRXJnZWJuaXMgSWhyZW4gRXJ3YXJ0dW5nZW4/IFdvcmFuIGthbm4KICAgIGRpZXNlciBadXNhbW1lbmhhbmcgbGllZ2VuPwoKNy4gIEJldHJhY2h0ZW4gU2llIG5lYmVuIGRlbSBgY3V0YCBhdWNoIGRpZSBLbGFyaGVpdCBgY2xhcml0eWAgdW5kIGdlYmVuCiAgICBTaWUgZGVuIEFudGVpbCB1bmQgZGllIEFuemFobCB2b24gRGlhbWFudGVuIG1pdCBlaW5lbSBQcmVpcyB2b24gw7xiZXIKICAgIDEwMDAwIGF1cy4KCiAgICAxLiAgV8OkaGxlbiBTaWUgaW0gQW5zY2hsdXNzIGRpZSBlcnN0ZW4gZsO8bmYgYWxsZXIgRXJnZWJuaXNzZSBhdXMuCiAgICAgICAgU3Rvw59lbiBTaWUgaGllcmJlaSBhdWYgZWluIFByb2JsZW0/CgogICAgMi4gIEVyc3RlbGxlbiBTaWUgZWluZSBHcmFmaWsgbWl0IEhpc3RvZ3JhbW1lbiBkZXIgUHJlaXNlIGbDvHIgYWxsZQogICAgICAgIEthdGVnb3JpZW4gdm9uIGBjdXRgIHVuZCBgY2xhcml0eWAgKGR1cmNoIGBmYWNldF9ncmlkKClgKS4KCiAgICAzLiAgTWFya2llcmVuIFNpZSBpbiBkZXIgR3JhZmlrIGRpZSBCZXJlaWNoZSByb3QsIGJlaSBkZW5lbiBkZXIKICAgICAgICBQcmVpcyDDvGJlciAxMDAwMCBsaWVndC4gVmVyZ2xlaWNoZW4gU2llIGRpZSBHcmFmaWsgbWl0IGRlbgogICAgICAgIEFudGVpbGVuLCBkaWUgU2llIHp1dm9yIGJlcmVjaG5ldCBoYWJlbi4KCiMjIEzDtnN1bmdlbgoKIyMjIMOcYmVybGVnZW4gU2llIHp1bsOkY2hzdCwgbmFjaCB3ZWxjaGVuIFZhcmlhYmxlbiBzaWNoIGRlciBEYXRlbnNhdHogYGRpYW1vbmRzYCBzaW5udm9sbCBncnVwcGllcmVuIGzDpHNzdC4gRGVua2VuIFNpZSBoaWVyYmVpIGJlc29uZGVycyBhbiBkaWUgdW50ZXJzY2hpZWRsaWNoZW4gRGF0ZW50eXBlbi4KCkJldHJhY2h0ZW4gU2llIGhpZXJ6dSBkZW4gRGF0YWZyYW1lIGBkaWFtb25kc2AgdW5kIHNjaGF1ZW4gU2llIGRpcmVrdAp1bnRlciBkaWUgVmFyaWFibGVuLiBWYXJpYWJsZW4gbWl0IGRlbSBBbmjDpG5nc2VsIGA8Y2hyPmAgb2RlciBgPG9yZD5gCnNpbmQga2F0ZWdvcmlzY2gvcXVhbGl0YXRpdiwgZC4gaC4gbmFjaCBpaG5lbiBsw6Rzc3Qgc2ljaCBncnVwcGllcmVuLgoKQW5kZXJlIFZhcmlhYmxlbiB3aWUgei4gQi4gYDxpbnQ+YCBvZGVyIGA8ZGJsPmAgc2luZCBxdWFudGl0YXRpdmUKVmFyaWFibGVuLgoKRXMga2FubiB2b3Jrb21tZW4sIGRhc3MgS2F0ZWdvcmllbiBkdXJjaCBnYW56ZSBaYWhsZW4gKDEsIDIsIDMsIC4uLikKZGFyZ2VzdGVsbHQgd2VyZGVuLCBvYndvaGwgc2llIGVpbmUgdXJzcHLDvG5nbGljaGUgQmVkZXV0dW5nIGhhYmVuLiBJbgpkZW0gRmFsbCBoYW5kZWx0IGVzIHNpY2ggdHJvdHpkZW0gdW0gcXVhbGl0YXRpdmUgRGF0ZW4sIGF1Y2ggd2VubiBkaWUKVmFyaWFibGUgYWxzIGA8aW50PmAgbWFya2llcnQgaXN0LiBBY2h0ZW4gU2llIGRhcmF1ZiwgZGFzcyBJaHJlIHNlbGJzdAplcmhvYmVuZW4gRGF0ZW4gYXVzc2FnZWtyw6RmdGlnIHNpbmQsIGRhbWl0IGRhcyBuaWNodCB2b3Jrb21tdC4KCkRlbW5hY2ggaGFuZGVsdCBlcyBzaWNoIGJlaSBgY3V0YCwgYGNvbG9yYCB1bmQgYGNsYXJpdHlgIGF1Z2Vuc2NoZWlubGljaAp1bSBxdWFsaXRhdGl2ZSBEYXRlbiB1bmQgYmVpIGRlbSBSZXN0IHVtIHF1YW50aXRhdGl2ZSBEYXRlbi4KClRoZW9yZXRpc2NoIGxhc3NlbiBzaWNoIGFsbGUgVmFyaWFibGVuIHp1bSBHcnVwcGllcmVuIHZlcndlbmRlbi4gSW4gZGVyClByYXhpcyBtYWcgZXMgdW50ZXIgd2VuaWdlbiBBdXNuYWhtZW4ga2VpbmVuIFNpbm4gZXJnZWJlbiwgR3J1cHBlbiBmw7xyCm51bWVyaXNjaGUgV2VydGUgenUgZXJzdGVsbGVuLCBkYSBkaWUgQW56YWhsIGRlciBHcnVwcGVuIHNlaHIgaG9jaCBzZWluCndpcmQuCgojIyMgV2VsY2hlIEZhcmJlIGRlciBEaWFtYW50ZW4gaGF0IGRlbiBnZXJpbmdzdGVuIFdlcnQ/CgpEZXIgbmFpdmUgQW5zYXR6IHN1Y2h0IGRpcmVrdCBuYWNoIGRlbSBEaWFtYW50ZW4gbWl0IGRlbSBnZXJpbnN0ZW4gV2VydDoKCmBgYHtyfQpkaWFtb25kcyAlPiUKCXNsaWNlX21pbihwcmljZSkKYGBgCgpVbSBkZW4gV2VydCB2b24gRGlhbWFudGVuIGVpbmVyIEZhcmJlIHp1IGJldHJhY2h0ZW4sIGthbm4gZXMgamVkb2NoIFNpbm4KZXJnZWJlbiwgZGVuIER1cmNoc2Nobml0dHNwcmVpcyBmw7xyIGplZGUgRmFyYmUgenUgYmVyZWNobmVuOgoKYGBge3J9CmRpYW1vbmRzICU+JQoJZ3JvdXBfYnkoY29sb3IpICU+JQoJc3VtbWFyaXNlKGR1cmNoc2Nobml0dHNwcmVpcyA9IG1lYW4ocHJpY2UpKSAlPiUKCWFycmFuZ2UoZHVyY2hzY2huaXR0c3ByZWlzKQpgYGAKCkludGVyZXNzYW50ZXJ3ZWlzZSBoYWJlbiBkaWUgRGlhbWFudGVuIG1pdCBlaW5lciBndXRlbiBGYXJiZSAoRC9FKSBlaW5lbgpnZXJpbmdlcmVuIER1cmNoc2Nobml0dHN3ZXJ0IGFscyBkaWUgRGlhbWFudGVuIG1pdCBlaW5lciBzY2hsZWNodGVyZW4KRmFyYmUgKEkvSikuCgojIyMjIFdpZSBlcmtsw6RyZW4gU2llIHNpY2ggZGFzIEVyZ2VibmlzPwoKRXMgbXVzcyBuZWJlbiBkZXIgRmFyYmUgbm9jaCBhbmRlcmUgRmFrdG9yZW4gZ2ViZW4sIGRpZSBlaW5lbiBncsO2w59lcmVuCkVpbmZsdXNzIGF1ZiBkZW4gUHJlaXMgaGFiZW4uIEVpbmUgVmFyaWFibGUsIGRpZSBlaW5lbSBkaXJla3QgaW4gZGVuClNpbm4ga29tbXQsIGlzdCBkZXIgS2FyYXR3ZXJ0IGRlciBEaWFtYW50ZW4uCgojIyMjIEVyc3RlbGxlbiB1bmQgYmV0cmFjaHRlbiBTaWUgaGllcnp1IGF1Y2ggZWluIFN0cmV1ZGlhZ3JhbW0gbWl0IGRlbSBadXNhbW1lbmhhbmcgdm9uIGBjYXJhdGAgdW5kIGBwcmljZWAgYmV6w7xnbGljaCBkZXIgRmFyYmVuLgoKRGllc2UgR3JhZmlrIGhhdHRlbiB3aXIgYmVyZWl0cyB6dXZvciBlcnN0ZWxsdCAoZWluZSBHaXR0ZXJhbnNpY2h0IG1pdApgZmFjZXRgwqBrw7ZubnRlIGF1Y2ggYW5nZWJyYWNodCBzZWluKToKCmBgYHtyfQpnZ3Bsb3QoZGlhbW9uZHMpICsKCWdlb21fcG9pbnQoYWVzKGNhcmF0LCBwcmljZSwgY29sb3IgPSBjb2xvcikpCmBgYAoKRXMgZsOkbGx0IGF1ZiwgZGFzcyBkaWUgRGlhbWFudGVuIG1pdCBlaW5lciBzY2hsZWNodGVyZW4gRmFyYmUKdGVuZGVuemllbGwgZWluZW4gaMO2aGVyZW4gS2FyYXR3ZXJ0IGF1ZndlaXNlbi4gRGllIFVudGVyc2NoaWVkZSBzY2hlaW5lbgpkZXV0bGljaCB6dSBzZWluLCBhYmVyIHVtIHNpY2hlcnp1Z2VoZW4sIGvDtm5udGVuIHdpciBiZWlzcGllbHN3ZWlzZQp6dXPDpHR6bGljaCBkZW4gRHVyY2hzY2huaXR0c2thcmF0d2VydCBiZXJlY2huZW46CgpgYGB7cn0KZGlhbW9uZHMgJT4lCglncm91cF9ieShjb2xvcikgJT4lCglzdW1tYXJpc2UoZHVyY2hzY2huaXR0c3ByZWlzID0gbWVhbihwcmljZSksCgkJCQkJCWR1cmNoc2Nobml0dHNrYXJhdCA9IG1lYW4oY2FyYXQpKSAlPiUKCWFycmFuZ2UoZHVyY2hzY2huaXR0c3ByZWlzKQpgYGAKClRhdHPDpGNobGljaCB3ZWlzZW4gZGllIERpYW1hbnRlbiBtaXQgc2NobGVjaHRlbiBGYXJiZW4gZHVyY2hzY2huaXR0bGljaAplaW5lbiBow7ZoZXJlbiBLYXJhdHdlcnQgYXVmLiBEYXMgaXN0IHp3YXIgbm9jaCBrZWluIHN0YXRpc3Rpc2NoZXIKTmFjaHdlaXMsIGFsbGVyZGluZ3MgZWluIGd1dGVzIEluZGl6LgoKRXMgemVpZ3Qgc2ljaCBqZWRvY2ggYXVjaCwgZGFzcyBEaWFtYW50ZW4gbWl0IGVpbmVyIGd1dGVuIEZhcmJlIGF1Y2ggbWl0CmdlcmluZ2VyZW4gS2FyYXR3ZXJ0ZW4gc2NobmVsbGVyIGVpbmVuIGhvaGVuIFByZWlzIGVyemllbGVuLgoKIyMgR3J1cHBpZXJlbiBTaWUgZGllIERpYW1hbnRlbiBuYWNoIGRlciBWYXJpYWJsZSBgY3V0YCB1bmQgYmVyZWNobmVuIFNpZSBkaWUgTWl0dGVsd2VydGUgZsO8ciBgY2FyYXRgLCBgcHJpY2VgIHVuZCBgZGVwdGhgLgoKYGBge3J9CnNjaG5pdHQgPC0gZGlhbW9uZHMgJT4lCglncm91cF9ieShjdXQpICU+JQoJc3VtbWFyaXNlKGRzX2thcmF0ID0gbWVhbihjYXJhdCksCgkJCQkJCWRzX3ByZWlzID0gbWVhbihwcmljZSksCgkJCQkJCWRzX3RpZWZlID0gbWVhbihkZXB0aCkpCnNjaG5pdHQKYGBgCgojIyMjIEVya2VubmVuIFNpZSBoaWVyYmVpIFp1c2FtbWVuaMOkbmdlPwoKRGlhbWFudGVuIG1pdCBlaW5lbSBzY2hsZWNodGVuIFNjaG5pdHQgKGBGYWlyYCkgZXJoYWx0ZW4KZHVyY2hzY2huaXR0bGljaCBlaW5lbiDDpGhubGljaGVuIFByZWlzIHdpZSBEaWFtYW50ZW4gbWl0IGVpbmVtIGd1dGVuClNjaG5pdHQuIERhcyBtYWcgYW4gZWluZW0gZHVyY2hzY2huaXR0bGljaCBow7ZoZXJlbiBLYXJhdHdlcnQgbGllZ2VuLgoKQXVjaCBkaWUgVGllZmUgZGVyIERpYW1hbnRlbiBtaXQgZWluZW0gc2NobGVjaHRlbiBTY2huaXR0IGlzdCBow7ZoZXIgYWxzCmRpZSBhbmRlcmVuIEthdGVnb3JpZW4uCgpgSWRlYWxgIHNjaG5laWRldCBiZWkgZGVtIFByZWlzIGFtIHNjaGxlY2h0ZXN0ZW4gYWIuCgojIyMjIFN0ZWxsZW4gU2llIGRpZSBkdXJjaHNjaG5pdHRsaWNoZW4gUHJlaXNlIGR1cmNoIEJhbGtlbmRpYWdyYW1tZSBmw7xyIGFsbGUgS2F0ZWdvcmllbiB2b24gYGN1dGAgZGFyLgoKYGBge3J9CmdncGxvdChzY2huaXR0KSArCglnZW9tX2JhcihhZXMoY3V0LCBkc19wcmVpcywgZmlsbCA9IGN1dCksIHN0YXQgPSAiaWRlbnRpdHkiKQpgYGAKCiMjIyMgRXJzdGVsbGVuIFNpZSBlaW5lbiBCb3hwbG90IG1pdCBkZW4gUHJlaXNlbiBmw7xyIGplZGUgS2F0ZWdvcmllIGBjdXRgLiBWZXJnbGVpY2hlbiBTaWUgZGFzIEVyZ2VibmlzIG1pdCBkZW0gQmFsa2VuZGlhZ3JhbW0uCgpgYGB7cn0KZ2dwbG90KGRpYW1vbmRzKSArCglnZW9tX2JveHBsb3QoYWVzKHggPSBjdXQsIHkgPSBwcmljZSwgZmlsbCA9IGN1dCkpCmBgYAoKRGllIE1lZGlhbmUgc2NoZWluZW4gZXR3YXMgdW50ZXIgZGVtIGFyaXRobWV0aXNjaGVuIE1pdHRlbCB6dSBsaWVnZW4uIEVzCmJsZWlidCBkZW5ub2NoIGVyc2ljaHRsaWNoLCBkYXNzIGRpZSBEaWFtYW50ZW4gbWl0IGVpbmVtIGlkZWFsZW4gU2Nobml0dApldHdhcyB3ZW5pZ2VyIHdlcnQgc2luZCB1bmQgZGllIERpYW1hbnRlbiBtaXQgc2NobGVjaHRlbSBTY2huaXR0IGV0d2FzCm1laHIgd2VydCBzaW5kLgoKVm9yc2ljaHQgaXN0IGF1Y2ggaGllciBnZWJvdGVuLCBkZW5uIGF1Y2ggRGlhbWFudGVuIG1pdCBlaW5lciBzZWhyIGd1dGVuClF1YWxpdMOkdCBlcnJlaWNoZW4gYmVyZWl0cyBiZWkga2xlaW5lcmVuIEthcmF0d2VydGVuIGVpbmVuIGhvaGVuIFByZWlzOgoKYGBge3J9CmdncGxvdChkaWFtb25kcykgKwoJZ2VvbV9wb2ludChhZXMoY2FyYXQsIHByaWNlLCBjb2xvciA9IGN1dCkpICsKCWdlb21fc21vb3RoKGFlcyhjYXJhdCwgcHJpY2UsIGNvbG9yID0gY3V0KSwgc2UgPSBGQUxTRSkKYGBgCgojIyMgR3J1cHBpZXJlbiBTaWUgZGllIERpYW1hbnRlbiBuYWNoIGBjYXJhdGAgdW5kIGJlcmVjaG5lbiBTaWUgTWluaW11bSwgTWF4aW11bSB1bmQgTWl0dGVsd2VydCB2b24gYHByaWNlYC4KCmBgYHtyfQprYXJhdCA8LSBkaWFtb25kcyAlPiUKCWdyb3VwX2J5KGNhcmF0KSAlPiUKCXN1bW1hcmlzZShtaW5fcHJlaXMgPSBtaW4ocHJpY2UpLAoJCQkJCQltYXhfcHJlaXMgPSBtYXgocHJpY2UpLAoJCQkJCQlkc19wcmVpcyA9IG1lYW4ocHJpY2UpLAoJCQkJCQlhbnphaGwgPSBuKCkpCmthcmF0CmBgYAoKIyMjIyBFcnN0ZWxsZW4gU2llIGF1ZiBHcnVuZGxhZ2UgZGVyIE1pdHRlbHdlcnRlIHVuZCBkZXIgVmFyaWFibGUgYGNhcmF0YCBlaW4gU3RyZXVkaWFncmFtbS4KCmBgYHtyfQpnZ3Bsb3Qoa2FyYXQpICsKCWdlb21fcG9pbnQoYWVzKGNhcmF0LCBkc19wcmVpcywgYWxwaGEgPSBhbnphaGwpKQpgYGAKCiMjIyMgRXJzdGVsbGVuIFNpZSBlaW4gU3RyZXVkaWFncmFtbSBmw7xyIGFsbGUgRWludHLDpGdlIG1pdCBgY2FyYXRgIHVuZCBgcHJpY2VgLiBGw7xnZW4gU2llIHp1c8OkdHpsaWNoIGRpZSBiZXN0aW1tdGVuIE1pdHRlbHdlcnRlIGluIGRpZSBHcmFmaWsgbWl0IGBnZW9tX2xpbmUoKWAgZWluLiBTZXR6ZW4gU2llIGhpZXJ6dSBgc3RhdCA9ICJzbW9vdGgiYC4KCmBgYHtyfQpnZ3Bsb3QoZGlhbW9uZHMpICsKCWdlb21fcG9pbnQoYWVzKGNhcmF0LCBwcmljZSkpICsKCWdlb21fbGluZShkYXRhID0ga2FyYXQsIGFlcyhjYXJhdCwgZHNfcHJlaXMpLCBjb2xvciA9ICJyZWQiLCBzdGF0ID0gInNtb290aCIpCmBgYAoKRGFzIGdhbnplIGVyaW5uZXJ0IGVpbiB3ZW5pZyBhbiBgZ2VvbV9zbW9vdGgoKWA6CgpgYGB7cn0KZ2dwbG90KGRpYW1vbmRzLCBhZXMoY2FyYXQsIHByaWNlKSkgKwoJZ2VvbV9wb2ludCgpICsKCWdlb21fc21vb3RoKHNlID0gRiwgY29sb3IgPSAicmVkIikKYGBgCgojIyMjIEVudGZlcm5lbiBTaWUgenVsZXR6dCBhbGxlIEVpbnRyw6RnZSwgZGllIHNlbHRlbmVyIGFscyAyMCBtYWwgYXVmdHJldGVuLgoKYGBge3J9CmthcmF0ICU+JQoJZmlsdGVyKGFuemFobCA+PSAyMCkKYGBgCgojIyMgRmluZGVuIFNpZSBmw7xyIGplZGUgS2F0ZWdvcmllIHZvbiBgY29sb3JgIGRpZSBUaWVmZW4gKGBkZXB0aGApLCBiZWkgZGVuZW4gbWVociBhbHMgMjUlLCA1MCUgdW5kIDc1JSBkZXIgRGlhbWFudGVuIGVpbmVuIGdlcmluZ2VuIFdlcnQgYXVmd2Vpc2VuLgoKYGBge3J9CmRpYW1vbmRzICU+JQoJZ3JvdXBfYnkoY29sb3IpICU+JQoJc3VtbWFyaXNlKHF1YW50aWxlID0gcXVhbnRpbGUoZGVwdGgsIGMoMC4yNSwgMC41LCAwLjc1KSkpCiMgb2RlciBnZXRyZW5udDoKZGlhbW9uZHMgJT4lCglncm91cF9ieShjb2xvcikgJT4lCglzdW1tYXJpc2UoZXJzdGVzX3F1YXJ0aWwgPSBxdWFudGlsZShkZXB0aCwgMC4yNSksCgkJCQkJCXp3ZWl0ZXNfcXVhcnRpbCA9IHF1YW50aWxlKGRlcHRoLCAwLjUpLAoJCQkJCQlkcml0dGVzX3F1YXJ0aWwgPSBxdWFudGlsZShkZXB0aCwgMC42NSkpCmBgYAoKIyMjIEZpbmRlbiBTaWUgZsO8ciBqZWRlbiBgY3V0YCBkZW4gdGV1ZXJzdGVuIHVuZCBkZW4gZ8O8bnN0aWdzdGVuIERpYW1hbnRlbi4gRW50c3ByaWNodCBkYXMgRXJnZWJuaXMgSWhyZW4gRXJ3YXJ0dW5nZW4/IFdvcmFuIGthbm4gZGllc2VyIFp1c2FtbWVuaGFuZyBsaWVnZW4/CgpgYGB7cn0KZGlhbW9uZHMgJT4lCglncm91cF9ieShjdXQpICU+JQoJc3VtbWFyaXNlKGd1ZW5zdGlnc3RlciA9IG1pbihwcmljZSksCgkJCQkJCXRldWVyc3RlciA9IG1heChwcmljZSkpCmBgYAoKRXMgc2NoZWluZW4gZsO8ciBqZWRlIEthdGVnb3JpZSB2b24gYGN1dGAgw6RobmxpY2ggZ8O8bnN0aWdlIG9kZXIgdGV1ZXJlCkRpYW1hbnRlbiB2b3J6dWxpZWdlbi4KCkRlbiB2b3JoZXJpZ2VuIEdyYWZpa2VuIGlzdCB6dSBlbnRuZWhtZW4sIGRhc3MgZGFzIGVybmV1dCB3b2hsIGFuIGRlbgp1bnRlcnNjaGllZGxpY2hlbiBLYXJhdHdlcnRlbiBsaWVndC4KCiMjIyBCZXRyYWNodGVuIFNpZSBuZWJlbiBkZW0gYGN1dGAgYXVjaCBkaWUgS2xhcmhlaXQgYGNsYXJpdHlgIHVuZCBnZWJlbiBTaWUgZGVuIEFudGVpbCB1bmQgZGllIEFuemFobCB2b24gRGlhbWFudGVuIG1pdCBlaW5lbSBQcmVpcyB2b24gw7xiZXIgMTAwMDAgYXVzLgoKYGBge3J9CnRldWVyZV9kaWFtYW50ZW4gPC0gZGlhbW9uZHMgJT4lCglncm91cF9ieShjdXQsIGNsYXJpdHkpICU+JQoJc3VtbWFyaXNlKGFudGVpbF90ZXVlciA9IG1lYW4ocHJpY2UgPiAxMDAwMCksCgkJCQkJCWFuemFobF90ZXVlciA9IHN1bShwcmljZSA+IDEwMDAwKSkKdGV1ZXJlX2RpYW1hbnRlbgpgYGAKCiMjIyMgV8OkaGxlbiBTaWUgaW0gQW5zY2hsdXNzIGRpZSBlcnN0ZW4gZsO8bmYgYWxsZXIgRXJnZWJuaXNzZSBhdXMuIFN0b8OfZW4gU2llIGhpZXJiZWkgYXVmIGVpbiBQcm9ibGVtPwoKV2VubiBtYW4gbmFjaCBkZXIgR3J1cHBpZXJ1bmcgZGlyZWt0IGVpbmUgT3BlcmF0aW9uIGR1cmNoZsO8aHJ0LCBnaWx0CmRpZXNlIGbDvHIgYmVpZGUgS2F0ZWdvcmllbiBgY3V0YCB1bmQgYGNsYXJpdHlgIGtvbWJpbmllcnQ6CgpgYGB7cn0KdGV1ZXJlX2RpYW1hbnRlbiAlPiUKCXNsaWNlX21pbihkZXNjKGFuemFobF90ZXVlciksIG4gPSA1KQpgYGAKCkVzIG11c3MgYWxzbyB6dWVyc3QgZGllIEdydXBwaWVydW5nIGVudGZlcm50IHdlcmRlbjoKCmBgYHtyfQp0ZXVlcmVfZGlhbWFudGVuICU+JQoJdW5ncm91cCgpICU+JQoJc2xpY2VfbWluKGRlc2MoYW56YWhsX3RldWVyKSwgbiA9IDUpCmBgYAoKIyMjIyBFcnN0ZWxsZW4gU2llIGVpbmUgR3JhZmlrIG1pdCBIaXN0b2dyYW1tZW4gZGVyIFByZWlzZSBmw7xyIGFsbGUgS2F0ZWdvcmllbiB2b24gYGN1dGAgdW5kIGBjbGFyaXR5YCAoZHVyY2ggYGZhY2V0X2dyaWQoKWApLgoKYGBge3J9Cmhpc3RvZ3JhbW0gPC0gZ2dwbG90KGRpYW1vbmRzLCBhZXMocHJpY2UpKSArCglnZW9tX2hpc3RvZ3JhbShhZXMoZmlsbCA9IGN1dCkpICsKCWZhY2V0X2dyaWQoY3V0IH4gY2xhcml0eSkKaGlzdG9ncmFtbQpgYGAKCiMjIyMgTWFya2llcmVuIFNpZSBpbiBkZXIgR3JhZmlrIGRpZSBCZXJlaWNoZSByb3QsIGJlaSBkZW5lbiBkZXIgUHJlaXMgw7xiZXIgMTAwMDAgbGllZ3QuIFZlcmdsZWljaGVuIFNpZSBkaWUgR3JhZmlrIG1pdCBkZW4gQW50ZWlsZW4sIGRpZSBTaWUgenV2b3IgYmVyZWNobmV0IGhhYmVuLgoKYGBge3J9Cmhpc3RvZ3JhbW0gKwoJZ2VvbV9oaXN0b2dyYW0oZGF0YSA9IGZpbHRlcihkaWFtb25kcywgcHJpY2UgPiAxMDAwMCksIGFlcyhwcmljZSksIGZpbGwgPSAicmVkIikKYGBgCg==