Aufgaben
In diesem Abschnitt soll erneut der diamonds
Datensatz
betrachtet werden:
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()
Übungsaufgaben
Überlegen Sie zunächst, nach welchen Variablen sich der Datensatz
diamonds
gruppieren lässt. Denken Sie hierbei besonders an
die unterschiedlichen Datentypen.
Welche Farbe der Diamanten hat den geringsten Wert?
Wie erklären Sie sich das Ergebnis?
Erstellen und betrachten Sie hierzu auch ein Streudiagramm mit
dem Zusammenhang von carat
und price
bezüglich
der Farben.
Gruppieren Sie die Diamanten nach der Variable cut
und berechnen Sie die Mittelwerte für carat
,
price
und depth
.
Erkennen Sie hierbei Zusammenhänge?
Stellen Sie die durchschnittlichen Preise durch Balkendiagramme
für alle Kategorien von cut
dar.
Erstellen Sie einen Boxplot mit den Preisen für jede Kategorie
cut
. Vergleichen Sie das Ergebnis mit dem
Balkendiagramm.
Gruppieren Sie die Diamanten nach carat
und
berechnen Sie Minimum, Maximum und Mittelwert von
price
.
Erstellen Sie auf Grundlage der Mittelwerte und der Variable
carat
ein Streudiagramm.
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"
.
Entfernen Sie zuletzt alle Einträge, die seltener als 20 mal
auftreten.
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.
Finden Sie für jeden cut
den teuersten und den
günstigsten Diamanten. Entspricht das Ergebnis Ihren Erwartungen? Woran
kann dieser Zusammenhang liegen?
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.
Wählen Sie im Anschluss die ersten fünf aller Ergebnisse aus.
Stoßen Sie hierbei auf ein Problem?
Erstellen Sie eine Grafik mit Histogrammen der Preise für alle
Kategorien von cut
und clarity
(durch
facet_grid()
).
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.
Lösungen
Ü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.
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).
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.
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.
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
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.
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")
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)
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
Erstellen Sie auf
Grundlage der Mittelwerte und der Variable carat
ein
Streudiagramm.
ggplot(karat) +
geom_point(aes(carat, ds_preis, alpha = anzahl))
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")
Entfernen Sie
zuletzt alle Einträge, die seltener als 20 mal auftreten.
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))
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.
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.
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)
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
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==