R: Starter

Aktualisiert:

5 Minuten zum Lesen

Es waren einmal Zahlen und die lebten in R. Ein kleiner Überblick über Typen, Zuweisung, Ausgabe, Operationen und Indizierung in R. Und ein Test für die Formatierung von R Notebooks - angelegt in RStudio - zur Darstellung mit Jekyll.

R lernen

Ich bin bei XDA Developers auf einige Online Kurse über Machine Learning gestoßen. Und da ich darüber schon immer mehr wissen wollte und neuer Kopf-Input gerade anstand, habe ich angefangen den Kurs zu schauen. Ich erinnerte mich außerdem, während des US Wahlkampfs diesen spannenden Artikel Text analysis of Trump’s tweets confirms he writes only the (angrier) Android half von David Robinson von Stack Overflow gelesen zu haben. Das wollte ich auch können. Also war es an der Zeit, das ganz alte Statistik-Wissen zu reanimieren und einzusteigen. Der Artikel ist nur eine Sammlung der ersten Tutorials über die Grundlagen von R – Variablen, Ein- und Ausgabe, Operationen. Eigentlich eher für mich als Wiederholung geschrieben. Und: Fast alles wird heute mit Torten und Balken begründet und wir glauben, sobald wir eine begründete Grafik sehen. Ich denke mal, da sollte man sie auch selbst herstellen können.

Variablen: Zuweisung und Ausgabe

Die ersten Schritte im Umgang mit etwas Neuem sollten immer beginnen mit: Wie mache ich es an, wie mache ich es aus. Bei einer Programmiersprache wäre das dann: Wie gebe ich etwas ein, wie gebe ich etwas aus. Und zum Ausgeben braucht man ein Ding genannt Variable. Daher fange ich damit an. Wie werden Variablen initialisiert, wie weise ich ihnen einen Wert zu und wie gebe ich sie dann aus. Als erstes die Initialisierung von Variablen und die Wertezuweisung mit =, -> oder <-. Und natürlich deren Ausgabe.

eineVariable = 32
andereVariable <- 27
18.7 -> dritteVariable
eineVariable
[1] 32
andereVariable
[1] 27
dritteVariable
[1] 18.7
eineVariable
[1] 32
eineVariable + andereVariable
[1] 59
print(dritteVariable)
[1] 18.7
firstVar <- secondVar <- "komisch"
cat(firstVar, ",", secondVar, " - sind beide gleich -", sep = " ")
komisch , komisch  - sind beide gleich -
aMessage = paste(firstVar, "-","das ist dasselbe wie", secondVar, sep = " ")
message(aMessage)
komisch - das ist dasselbe wie komisch

Datentypen

Integer und Long, Character und String, Datum und Bool.

ichBinInteger <- 4L
is.integer(ichBinInteger)
[1] TRUE
ichBinAuchInteger <- as.integer(3+5)
class(ichBinAuchInteger)
[1] "integer"
is.numeric(ichBinInteger)
[1] TRUE
is.integer(ichBinAuchInteger)
[1] TRUE
ichBinBuchstabe <- "any string"
class(ichBinBuchstabe)
[1] "character"
nchar(ichBinBuchstabe)
[1] 10
ichBinDatum <- as.Date("2016-02-17 00:29")
ichBinDatum
[1] "2016-02-17"
class(ichBinDatum)
[1] "Date"
as.numeric(ichBinDatum)
[1] 16848
ichBinAuchDatum <- as.Date("2016-02-14 00:29")
ichBinDatum-ichBinAuchDatum
Time difference of 3 days
class(ichBinDatum-ichBinAuchDatum)
[1] "difftime"
as.numeric(ichBinDatum-ichBinAuchDatum)
[1] 3
iAmTrue <- TRUE
class(iAmTrue)
[1] "logical"
iAmLogical <- 2 != 3
iAmLogical
[1] TRUE
iCompareCharacters <- "Red" > "Blue"
iCompareCharacters
[1] TRUE

Vektoren: Zuweisung¸ Arithmetik und Indizierung

Alles in R ist in gewisser Weise eine Liste, eine Reihe von Daten. Ein Vektor kann Elemente unterschiedlicher Datentypen beinhalten. Und ganz wichtig: Die Indizierung der Elemente beginnt bei 1.

simpleSequence <- 1:12
simpleSequence
 [1]  1  2  3  4  5  6  7  8  9 10 11 12
evenNumberSequence <- 2*1:6
evenNumberSequence
[1]  2  4  6  8 10 12
repeatSequence <- rep(evenNumberSequence, times = 2, length.out = 20, each = 3)
repeatSequence
 [1]  2  2  2  4  4  4  6  6  6  8  8  8 10 10 10 12 12 12  2  2
generalSequence <- seq(from = -5, to = 10, by = 0.2)
generalSequence
 [1] -5.0 -4.8 -4.6 -4.4 -4.2 -4.0 -3.8 -3.6 -3.4 -3.2 -3.0 -2.8 -2.6 -2.4 -2.2 -2.0 -1.8 -1.6 -1.4 -1.2 -1.0 -0.8 -0.6 -0.4 -0.2
[26]  0.0  0.2  0.4  0.6  0.8  1.0  1.2  1.4  1.6  1.8  2.0  2.2  2.4  2.6  2.8  3.0  3.2  3.4  3.6  3.8  4.0  4.2  4.4  4.6  4.8
[51]  5.0  5.2  5.4  5.6  5.8  6.0  6.2  6.4  6.6  6.8  7.0  7.2  7.4  7.6  7.8  8.0  8.2  8.4  8.6  8.8  9.0  9.2  9.4  9.6  9.8
[76] 10.0
vec1 <- c(247, 350, "Test", TRUE, 600)
mode(vec1)
[1] "character"
typeof(vec1)
[1] "character"
vec2 <- numeric(5)
vec2
[1] 0 0 0 0 0
vec3 <- c(vec2, vec1)
vec3
 [1] "0"    "0"    "0"    "0"    "0"    "247"  "350"  "Test" "TRUE" "600" 
vec10 <- c(1, 5, 10, 20, 50, 100, 500)
vec20 <- c(0, 30)
for(i in vec10) {
  vec20 <- c(vec20 , i*30)
}
vec20
[1]     0    30    30   150   300   600  1500  3000 15000
vec30 <- c(5, 5, 5, 6, 2, 2, 2)
vec40 <- vec30 * vec10
vec40
[1]    5   25   50  120  100  200 1000
vec50 <- vec40 + c(100,0)
Länge des längeren Objektes
     ist kein Vielfaches der Länge des kürzeren Objektes
vec50
[1]  105   25  150  120  200  200 1100
seq1 <- 1:4
seq1 == 2
[1] FALSE  TRUE FALSE FALSE
stringSeq <- c("A", "B", "C", "D", "E", "F", "G", "H")
funkySeq <- paste(stringSeq, seq1, sep="")
funkySeq
[1] "A1" "B2" "C3" "D4" "E1" "F2" "G3" "H4"
meineSeq <- 3*1:5
meineSeq[rep(c(1,3), times = 5)]
 [1] 3 9 3 9 3 9 3 9 3 9
meineSeq[c(-3, -4)]
[1]  3  6 15
names(meineSeq) <- c("A","B","C","D","E")
meineSeq[c("A","C")]
A C 
3 9 

Arrays

Ein Array ist eine Vektor, dessen Werte in den Dimensionen des Arrays angeordnet sind. Das kann man sich so vorstellen, das z.B. bei einem 2-dimensionalen Array dieses mit den Werten des Vektors beginnend bei dem Element links oben zuerst die Zeilen (row) nach unten gefüllt werden und dann in die nächste Spalte (col) nach oben gesprungen wird und diese zeilenweise aufgefüllt wird.

arr1 <- array(c(1:12), dim = c(3,2,2))
arr1
, , 1

     [,1] [,2]
[1,]    1    4
[2,]    2    5
[3,]    3    6

, , 2

     [,1] [,2]
[1,]    7   10
[2,]    8   11
[3,]    9   12
arr2 <- array(c(1,0) , dim = c(2,3))
arr2
     [,1] [,2] [,3]
[1,]    1    1    1
[2,]    0    0    0
arr1[2,2,1]
[1] 5
arr1[2:3,,1]
     [,1] [,2]
[1,]    2    5
[2,]    3    6
indexArray <- array (c(1:2), dim=c(2,3))
indexArray
     [,1] [,2] [,3]
[1,]    1    1    1
[2,]    2    2    2
arr1[indexArray]
[1]  1 11
index2Array <- array (c(2,3,2,1,1,2), dim=c(2,3))
index2Array
     [,1] [,2] [,3]
[1,]    2    2    1
[2,]    3    1    2
arr1[index2Array]
[1] 5 9
a <- array(1:6, dim = c(2,3))
b <- array(7:12, dim = c(2,3))
a * b
     [,1] [,2] [,3]
[1,]    7   27   55
[2,]   16   40   72
# outer product
A <- array(1:18, dim = c(3,2,3))
B <- array(19:36, dim = c(2,3,3))
A
, , 1

     [,1] [,2]
[1,]    1    4
[2,]    2    5
[3,]    3    6

, , 2

     [,1] [,2]
[1,]    7   10
[2,]    8   11
[3,]    9   12

, , 3

     [,1] [,2]
[1,]   13   16
[2,]   14   17
[3,]   15   18
B
, , 1

     [,1] [,2] [,3]
[1,]   19   21   23
[2,]   20   22   24

, , 2

     [,1] [,2] [,3]
[1,]   25   27   29
[2,]   26   28   30

, , 3

     [,1] [,2] [,3]
[1,]   31   33   35
[2,]   32   34   36
AB <- A %o% B
dim(AB)
[1] 3 2 3 2 3 3

Matrizen

Matrizen sind 2-dimensionale Arrays mit besonderen Möglichkeiten. Lineare Gleichungen lassen sich z.B. mit Matrizenarithmetik lösen.

aMatrix <- matrix(c(2*1:3, 3*1:3), nrow = 2, ncol = 3)
aMatrix
     [,1] [,2] [,3]
[1,]    2    6    6
[2,]    4    3    9
# Transponieren
anotherMatrix <- t(aMatrix)
# Matrizenmultiplikation
aMatrix %*% anotherMatrix 
     [,1] [,2]
[1,]   76   80
[2,]   80  106
# Kreuzprodukt von A, B == t(A) %*% B
crossprod(aMatrix,2*1:2)
     [,1]
[1,]   20
[2,]   24
[3,]   48

Faktoren

Ein Vektor kann in Faktoren, den Gruppen gleicher Werte, zerlegt werden. Das ist vergleichbar einem GROUP BY in SQL.

stadt <- c("Berlin", "Dresden", "Hamburg", "Berlin", "Berlin", "Hamburg", "Dresden")
kategorie <- c("Bekleidung", "Schuhe", "Kosmetik", "Kosmetik", "Schuhe", "Bekleidung", "Bekleidung")
betrag <- c(5000, 4500, 3500, 2500, 1000, 2000, 5500)
stadtAsFaktor <- factor(stadt)
print(stadtAsFaktor)
[1] Berlin  Dresden Hamburg Berlin  Berlin  Hamburg Dresden
Levels: Berlin Dresden Hamburg
as.numeric(stadtAsFaktor)
[1] 1 2 3 1 1 3 2
levels(stadtAsFaktor)
[1] "Berlin"  "Dresden" "Hamburg"
levels(stadtAsFaktor) <- c("BER", "DRE", "HAM")
stadtCodeFaktor <- factor(stadtAsFaktor, labels=c("B", "D", "H"))
print(stadtCodeFaktor)
[1] B D H B B H D
Levels: B D H
table(stadt)
stadt
 Berlin Dresden Hamburg 
      3       2       2 
tapply(betrag, kategorie, sum)
Bekleidung   Kosmetik     Schuhe 
     12500       6000       5500 
LS0tCnRpdGxlOiAiUiBTdGFydGVyIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIGNvZGVfZm9sZGluZzogbm9uZQogICAgZGZfcHJpbnQ6IGthYmxlCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgICB0aGVtZTogZmxhdGx5CiAgICB0b2M6IHllcwogIGh0bWxfZG9jdW1lbnQ6CiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgICBrZWVwX21kOiB5ZXMKLS0tCgojIyBSIGxlcm5lbgoKSWNoIGJpbiBiZWkgW1hEQSBEZXZlbG9wZXJzXShodHRwczovL2RlcG90LnhkYS1kZXZlbG9wZXJzLmNvbS8pezp0YXJnZXQ9Il9ibGFuayJ9IGF1ZiBlaW5pZ2UgT25saW5lIEt1cnNlIMO8YmVyIE1hY2hpbmUgTGVhcm5pbmcgZ2VzdG/Dn2VuLiBVbmQgZGEgaWNoIGRhcsO8YmVyIHNjaG9uIGltbWVyIG1laHIgd2lzc2VuIHdvbGx0ZSB1bmQgbmV1ZXIgS29wZi1JbnB1dCBnZXJhZGUgYW5zdGFuZCwgaGFiZSBpY2ggYW5nZWZhbmdlbiBkZW4gS3VycyB6dSBzY2hhdWVuLiBJY2ggZXJpbm5lcnRlIG1pY2ggYXXDn2VyZGVtLCB3w6RocmVuZCBkZXMgVVMgV2FobGthbXBmcyBkaWVzZW4gc3Bhbm5lbmRlbiBBcnRpa2VsIFtUZXh0IGFuYWx5c2lzIG9mIFRydW1wJ3MgdHdlZXRzIGNvbmZpcm1zIGhlIHdyaXRlcyBvbmx5IHRoZSAoYW5ncmllcikgQW5kcm9pZCBoYWxmXShodHRwOi8vdmFyaWFuY2VleHBsYWluZWQub3JnL3IvdHJ1bXAtdHdlZXRzLyl7OnRhcmdldD0iX2JsYW5rIn0gdm9uIF9EYXZpZCBSb2JpbnNvbiB2b24gU3RhY2sgT3ZlcmZsb3dfIGdlbGVzZW4genUgaGFiZW4uIERhcyB3b2xsdGUgaWNoIGF1Y2gga8O2bm5lbi4gQWxzbyB3YXIgZXMgYW4gZGVyIFplaXQsIGRhcyBnYW56IGFsdGUgU3RhdGlzdGlrLVdpc3NlbiB6dSByZWFuaW1pZXJlbiB1bmQgZWluenVzdGVpZ2VuLiBEZXIgQXJ0aWtlbCBpc3QgbnVyIGVpbmUgU2FtbWx1bmcgZGVyIGVyc3RlbiBUdXRvcmlhbHMgw7xiZXIgZGllIEdydW5kbGFnZW4gdm9uIFIgLS0gVmFyaWFibGVuLCBFaW4tIHVuZCBBdXNnYWJlLCBPcGVyYXRpb25lbi4gRWlnZW50bGljaCBlaGVyIGbDvHIgbWljaCBhbHMgV2llZGVyaG9sdW5nIGdlc2NocmllYmVuLiBVbmQ6IEZhc3QgYWxsZXMgd2lyZCBoZXV0ZSBtaXQgVG9ydGVuIHVuZCBCYWxrZW4gYmVncsO8bmRldCB1bmQgd2lyIF9nbGF1YmVuXywgc29iYWxkIHdpciBlaW5lIGJlZ3LDvG5kZXRlIEdyYWZpayBzZWhlbi4gSWNoIGRlbmtlIG1hbCwgZGEgc29sbHRlIG1hbiBzaWUgYXVjaCBzZWxic3QgaGVyc3RlbGxlbiBrw7ZubmVuLgoKIyMgVmFyaWFibGVuOiBadXdlaXN1bmcgdW5kIEF1c2dhYmUKCkRpZSBlcnN0ZW4gU2Nocml0dGUgaW0gVW1nYW5nIG1pdCBldHdhcyBOZXVlbSBzb2xsdGVuIGltbWVyIGJlZ2lubmVuIG1pdDogV2llIG1hY2hlIGljaCBlcyBhbiwgd2llIG1hY2hlIGljaCBlcyBhdXMuIEJlaSBlaW5lciBQcm9ncmFtbWllcnNwcmFjaGUgd8OkcmUgZGFzIGRhbm46IFdpZSBnZWJlIGljaCBldHdhcyBlaW4sIHdpZSBnZWJlIGljaCBldHdhcyBhdXMuIFVuZCB6dW0gQXVzZ2ViZW4gYnJhdWNodCBtYW4gZWluIERpbmcgZ2VuYW5udCBWYXJpYWJsZS4gRGFoZXIgZmFuZ2UgaWNoIGRhbWl0IGFuLiBXaWUgd2VyZGVuIFZhcmlhYmxlbiBpbml0aWFsaXNpZXJ0LCB3aWUgd2Vpc2UgaWNoIGlobmVuIGVpbmVuIFdlcnQgenUgdW5kIHdpZSBnZWJlIGljaCBzaWUgZGFubiBhdXMuCkFscyBlcnN0ZXMgZGllIEluaXRpYWxpc2llcnVuZyB2b24gVmFyaWFibGVuIHVuZCBkaWUgV2VydGV6dXdlaXN1bmcgbWl0ID0sIC0+IG9kZXIgPC0uIFVuZCBuYXTDvHJsaWNoIGRlcmVuIEF1c2dhYmUuCgpgYGB7cn0KZWluZVZhcmlhYmxlID0gMzIKYW5kZXJlVmFyaWFibGUgPC0gMjcKMTguNyAtPiBkcml0dGVWYXJpYWJsZQplaW5lVmFyaWFibGUKYW5kZXJlVmFyaWFibGUKZHJpdHRlVmFyaWFibGUKZWluZVZhcmlhYmxlCmVpbmVWYXJpYWJsZSArIGFuZGVyZVZhcmlhYmxlCnByaW50KGRyaXR0ZVZhcmlhYmxlKQpmaXJzdFZhciA8LSBzZWNvbmRWYXIgPC0gImtvbWlzY2giCmNhdChmaXJzdFZhciwgIiwiLCBzZWNvbmRWYXIsICIgLSBzaW5kIGJlaWRlIGdsZWljaCAtIiwgc2VwID0gIiAiKQphTWVzc2FnZSA9IHBhc3RlKGZpcnN0VmFyLCAiLSIsImRhcyBpc3QgZGFzc2VsYmUgd2llIiwgc2Vjb25kVmFyLCBzZXAgPSAiICIpCm1lc3NhZ2UoYU1lc3NhZ2UpCmBgYAoKIyMgRGF0ZW50eXBlbgoKSW50ZWdlciB1bmQgTG9uZywgQ2hhcmFjdGVyIHVuZCBTdHJpbmcsIERhdHVtIHVuZCBCb29sLiAKCmBgYHtyfQppY2hCaW5JbnRlZ2VyIDwtIDRMCmlzLmludGVnZXIoaWNoQmluSW50ZWdlcikKaWNoQmluQXVjaEludGVnZXIgPC0gYXMuaW50ZWdlcigzKzUpCmNsYXNzKGljaEJpbkF1Y2hJbnRlZ2VyKQppcy5udW1lcmljKGljaEJpbkludGVnZXIpCmlzLmludGVnZXIoaWNoQmluQXVjaEludGVnZXIpCmljaEJpbkJ1Y2hzdGFiZSA8LSAiYW55IHN0cmluZyIKY2xhc3MoaWNoQmluQnVjaHN0YWJlKQpuY2hhcihpY2hCaW5CdWNoc3RhYmUpCmljaEJpbkRhdHVtIDwtIGFzLkRhdGUoIjIwMTYtMDItMTcgMDA6MjkiKQppY2hCaW5EYXR1bQpjbGFzcyhpY2hCaW5EYXR1bSkKYXMubnVtZXJpYyhpY2hCaW5EYXR1bSkKaWNoQmluQXVjaERhdHVtIDwtIGFzLkRhdGUoIjIwMTYtMDItMTQgMDA6MjkiKQppY2hCaW5EYXR1bS1pY2hCaW5BdWNoRGF0dW0KY2xhc3MoaWNoQmluRGF0dW0taWNoQmluQXVjaERhdHVtKQphcy5udW1lcmljKGljaEJpbkRhdHVtLWljaEJpbkF1Y2hEYXR1bSkKaUFtVHJ1ZSA8LSBUUlVFCmNsYXNzKGlBbVRydWUpCmlBbUxvZ2ljYWwgPC0gMiAhPSAzCmlBbUxvZ2ljYWwKaUNvbXBhcmVDaGFyYWN0ZXJzIDwtICJSZWQiID4gIkJsdWUiCmlDb21wYXJlQ2hhcmFjdGVycwpgYGAKCiMjIFZla3RvcmVuOiBadXdlaXN1bmfCuCBBcml0aG1ldGlrIHVuZCBJbmRpemllcnVuZwoKQWxsZXMgaW4gUiBpc3QgaW4gZ2V3aXNzZXIgV2Vpc2UgZWluZSBMaXN0ZSwgZWluZSBSZWloZSB2b24gRGF0ZW4uIEVpbiBWZWt0b3Iga2FubiBFbGVtZW50ZSB1bnRlcnNjaGllZGxpY2hlciBEYXRlbnR5cGVuIGJlaW5oYWx0ZW4uIFVuZCBnYW56IHdpY2h0aWc6IERpZSBJbmRpemllcnVuZyBkZXIgRWxlbWVudGUgYmVnaW5udCBiZWkgMS4gCgpgYGB7cn0Kc2ltcGxlU2VxdWVuY2UgPC0gMToxMgpzaW1wbGVTZXF1ZW5jZQpldmVuTnVtYmVyU2VxdWVuY2UgPC0gMioxOjYKZXZlbk51bWJlclNlcXVlbmNlCnJlcGVhdFNlcXVlbmNlIDwtIHJlcChldmVuTnVtYmVyU2VxdWVuY2UsIHRpbWVzID0gMiwgbGVuZ3RoLm91dCA9IDIwLCBlYWNoID0gMykKcmVwZWF0U2VxdWVuY2UKZ2VuZXJhbFNlcXVlbmNlIDwtIHNlcShmcm9tID0gLTUsIHRvID0gMTAsIGJ5ID0gMC4yKQpnZW5lcmFsU2VxdWVuY2UKdmVjMSA8LSBjKDI0NywgMzUwLCAiVGVzdCIsIFRSVUUsIDYwMCkKbW9kZSh2ZWMxKQp0eXBlb2YodmVjMSkKdmVjMiA8LSBudW1lcmljKDUpCnZlYzIKdmVjMyA8LSBjKHZlYzIsIHZlYzEpCnZlYzMKdmVjMTAgPC0gYygxLCA1LCAxMCwgMjAsIDUwLCAxMDAsIDUwMCkKdmVjMjAgPC0gYygwLCAzMCkKZm9yKGkgaW4gdmVjMTApIHsKICB2ZWMyMCA8LSBjKHZlYzIwICwgaSozMCkKfQp2ZWMyMAp2ZWMzMCA8LSBjKDUsIDUsIDUsIDYsIDIsIDIsIDIpCnZlYzQwIDwtIHZlYzMwICogdmVjMTAKdmVjNDAKdmVjNTAgPC0gdmVjNDAgKyBjKDEwMCwwKQp2ZWM1MApzZXExIDwtIDE6NApzZXExID09IDIKc3RyaW5nU2VxIDwtIGMoIkEiLCAiQiIsICJDIiwgIkQiLCAiRSIsICJGIiwgIkciLCAiSCIpCmZ1bmt5U2VxIDwtIHBhc3RlKHN0cmluZ1NlcSwgc2VxMSwgc2VwPSIiKQpmdW5reVNlcQptZWluZVNlcSA8LSAzKjE6NQptZWluZVNlcVtyZXAoYygxLDMpLCB0aW1lcyA9IDUpXQptZWluZVNlcVtjKC0zLCAtNCldCm5hbWVzKG1laW5lU2VxKSA8LSBjKCJBIiwiQiIsIkMiLCJEIiwiRSIpCm1laW5lU2VxW2MoIkEiLCJDIildCmBgYAoKIyMgQXJyYXlzCgpFaW4gQXJyYXkgaXN0IGVpbmUgVmVrdG9yLCBkZXNzZW4gV2VydGUgaW4gZGVuIERpbWVuc2lvbmVuIGRlcyBBcnJheXMgYW5nZW9yZG5ldCBzaW5kLiBEYXMga2FubiBtYW4gc2ljaCBzbyB2b3JzdGVsbGVuLCBkYXMgei5CLiBiZWkgZWluZW0gMi1kaW1lbnNpb25hbGVuIEFycmF5IGRpZXNlcyBtaXQgZGVuIFdlcnRlbiBkZXMgVmVrdG9ycyBiZWdpbm5lbmQgYmVpIGRlbSBFbGVtZW50IF9saW5rcyBvYmVuXyB6dWVyc3QgZGllIFplaWxlbiAocm93KSBuYWNoIHVudGVuIGdlZsO8bGx0IHdlcmRlbiB1bmQgZGFubiBpbiBkaWUgbsOkY2hzdGUgU3BhbHRlIChjb2wpIG5hY2ggb2JlbiBnZXNwcnVuZ2VuIHdpcmQgdW5kIGRpZXNlIHplaWxlbndlaXNlIGF1ZmdlZsO8bGx0IHdpcmQuIAoKYGBge3J9CmFycjEgPC0gYXJyYXkoYygxOjEyKSwgZGltID0gYygzLDIsMikpCmFycjEKYXJyMiA8LSBhcnJheShjKDEsMCkgLCBkaW0gPSBjKDIsMykpCmFycjIKYXJyMVsyLDIsMV0KYXJyMVsyOjMsLDFdCmluZGV4QXJyYXkgPC0gYXJyYXkgKGMoMToyKSwgZGltPWMoMiwzKSkKaW5kZXhBcnJheQphcnIxW2luZGV4QXJyYXldCmluZGV4MkFycmF5IDwtIGFycmF5IChjKDIsMywyLDEsMSwyKSwgZGltPWMoMiwzKSkKaW5kZXgyQXJyYXkKYXJyMVtpbmRleDJBcnJheV0KYSA8LSBhcnJheSgxOjYsIGRpbSA9IGMoMiwzKSkKYiA8LSBhcnJheSg3OjEyLCBkaW0gPSBjKDIsMykpCmEgKiBiCiMgb3V0ZXIgcHJvZHVjdApBIDwtIGFycmF5KDE6MTgsIGRpbSA9IGMoMywyLDMpKQpCIDwtIGFycmF5KDE5OjM2LCBkaW0gPSBjKDIsMywzKSkKQQpCCkFCIDwtIEEgJW8lIEIKZGltKEFCKQpgYGAKCiMjIE1hdHJpemVuCgpNYXRyaXplbiBzaW5kIDItZGltZW5zaW9uYWxlIEFycmF5cyBtaXQgYmVzb25kZXJlbiBNw7ZnbGljaGtlaXRlbi4gTGluZWFyZSBHbGVpY2h1bmdlbiBsYXNzZW4gc2ljaCB6LkIuIG1pdCBNYXRyaXplbmFyaXRobWV0aWsgbMO2c2VuLgoKYGBge3J9CmFNYXRyaXggPC0gbWF0cml4KGMoMioxOjMsIDMqMTozKSwgbnJvdyA9IDIsIG5jb2wgPSAzKQphTWF0cml4CiMgVHJhbnNwb25pZXJlbgphbm90aGVyTWF0cml4IDwtIHQoYU1hdHJpeCkKIyBNYXRyaXplbm11bHRpcGxpa2F0aW9uCmFNYXRyaXggJSolIGFub3RoZXJNYXRyaXggCiMgS3JldXpwcm9kdWt0IHZvbiBBLCBCID09IHQoQSkgJSolIEIKY3Jvc3Nwcm9kKGFNYXRyaXgsMioxOjIpCmBgYAoKCiMjIEZha3RvcmVuCgpFaW4gVmVrdG9yIGthbm4gaW4gRmFrdG9yZW4sIGRlbiBHcnVwcGVuIGdsZWljaGVyIFdlcnRlLCB6ZXJsZWd0IHdlcmRlbi4gRGFzIGlzdCB2ZXJnbGVpY2hiYXIgZWluZW0gYEdST1VQIEJZYCBpbiBTUUwuCgpgYGB7cn0Kc3RhZHQgPC0gYygiQmVybGluIiwgIkRyZXNkZW4iLCAiSGFtYnVyZyIsICJCZXJsaW4iLCAiQmVybGluIiwgIkhhbWJ1cmciLCAiRHJlc2RlbiIpCmthdGVnb3JpZSA8LSBjKCJCZWtsZWlkdW5nIiwgIlNjaHVoZSIsICJLb3NtZXRpayIsICJLb3NtZXRpayIsICJTY2h1aGUiLCAiQmVrbGVpZHVuZyIsICJCZWtsZWlkdW5nIikKYmV0cmFnIDwtIGMoNTAwMCwgNDUwMCwgMzUwMCwgMjUwMCwgMTAwMCwgMjAwMCwgNTUwMCkKc3RhZHRBc0Zha3RvciA8LSBmYWN0b3Ioc3RhZHQpCnByaW50KHN0YWR0QXNGYWt0b3IpCmFzLm51bWVyaWMoc3RhZHRBc0Zha3RvcikKbGV2ZWxzKHN0YWR0QXNGYWt0b3IpCmxldmVscyhzdGFkdEFzRmFrdG9yKSA8LSBjKCJCRVIiLCAiRFJFIiwgIkhBTSIpCnN0YWR0Q29kZUZha3RvciA8LSBmYWN0b3Ioc3RhZHRBc0Zha3RvciwgbGFiZWxzPWMoIkIiLCAiRCIsICJIIikpCnByaW50KHN0YWR0Q29kZUZha3RvcikKdGFibGUoc3RhZHQpCnRhcHBseShiZXRyYWcsIGthdGVnb3JpZSwgc3VtKQpgYGAKCgoKCg==