Dieses HTML-Dokument ist ein Arbeitsblatt zur Cantormenge und ihren Varianten. Sie können es als HTML-Dokument lesen. Tatsächlich können Sie es aber auch mit Ihrem Computer bearbeiten. Das Arbeitsblatt ist keine Einführung in Programmierung. Stattdessen werden Programme bereitgestellt, mit denen Sie Cantormengen erzeugen können. Sie können diese Programme nach Belieben abändern und so auf dem Computer mit Cantormengen experimentieren.

Wir arbeiten mit dem frei erhältlichen Statistik-Programm RStudio und der Programmiersprache R.

Sie können dieses HTML-Dokument im RMD-Format abspeichern, siehe die Schaltfläche Code rechts oben. Sie können das RMD-Dokument dann in RStudio öffnen, und Sie können die bereitgestellten Programme auf Ihrem Computer ausführen.

Die Cantormenge

Man erhält die Cantormenge \(C\subset [0,1]\) als Schnitt \(C=\bigcap_{n\in\mathbb N_0}C_n\) absteigender Mengen \([0,1]=C_0\supset C_1 \supset C_2 \supset \ldots\) Bei der Konstruktion von \(C_{n+1}\) entfernt man aus jedem Intervall in \(C_n\) jeweils ein offenes Intervall, das mittlere Drittel.

Auf dem Computer kann man die Konstruktion von \(C_n\) wie folgt codieren. Sie können den folgenden Code einlesen, indem Sie auf das Pfeilsymbol klicken.

U=c(1,0,1)
erzeuge = function(n) if (n==0) return(1) else return( U %x% erzeuge(n-1))

Der Aufruf erzeuge(n) liefert eine 01-Punktmenge, welche \(C_n\) entspricht. Der Ausdruck U beschreibt die Unterteilung des Einheitsintervalls.

erzeuge(2)
[1] 1 0 1 0 0 0 1 0 1

Mit dem R-Befehl plot können Sie diese Punktmenge graphisch darstellen. Das Argument type=“h” ergibt eine Darstellung als Histogramm mit Balken der Höhe \(0\) oder \(1\). Die Menge \(C_n\) entspricht einem horizontalen Schnitt im folgenden Bild.

n=5; plot(erzeuge(n), type="h")

Der Cantor-Staub

Die obige Konstruktion kann man auf zweidimensionale Punktmengen erweitern. Man startet mit dem Einheitsquadrat und unterteilt es in 9 kleinere Quadrate. Dann entfernt man die 5 mittleren Quadrate. Mit dieser Konstruktion fährt man fort und erhält so den Cantor-Staub.

U = array(c(1,0,1, 0,0,0, 1,0,1), dim=c(3,3))
n=1; erzeuge(n)
     [,1] [,2] [,3]
[1,]    1    0    1
[2,]    0    0    0
[3,]    1    0    1

Die Unterteilung wird durch eine \(01\)-Matrix dargestellt. Man kann solche Matrizen mit dem Befehl image visualisieren.

for (n in 1:4) image(erzeuge(n))

Der Sierpinski-Teppich

Eine Variante der obigen Konstruktion besteht darin, dass man von den 9 kleinen Quadraten lediglich das mittlere Quadrat entfernt. Die zugehörige Punktmenge nennt man den Sierpinski-Teppich.

U= array(c(1,1,1, 1,0,1, 1,1,1), dim=c(3,3))
for (n in 1:4) image(erzeuge(n))

zufällige Sierpinksi-Teppiche

Man kann die obigen Konstruktionen randomisieren. Zum Beispiel kann man per Münzwurf entscheiden, ob man für ein Quadrat die Sierpinski-Konstruktion durchführt, oder ob man stattdessen alle 9 Teilquadrate entfernt.

Auf dem Computer kann man hierzu folgendes Programm schreiben.

# ersetze "x" durch "0" mit Wkeit p
x0 = function(x) sample(c(0,x),1,prob=c(p,1-p))
# loesche Eintraege des Arrays A mit Wkeit p
loesche = function(A) array(sapply(A,x0), dim=dim(A))
# erzeuge eine zufaellige Cantor-Menge
erzeuge_zu = function(n) if (n==0) return(1) else return( loesche(U %x% erzeuge_zu(n-1)))

Die Funktion zu implementiert den Münzwurf auf dem Computer. Für eine Matrix aus Nullen und Einsen werden alle Einträge mit Zufallszahlen \(0\) oder \(1\) aus einem Münzwurf multipliziert. Hierbei tritt \(0\) mit Wahrscheinlichkeit \(p\) auf, und \(1\) tritt mit Wahrscheinlichkeit \(1-p\) auf.

Die Funktion rp setzt einen Wert \(x\) mit Wahrscheinlichkeit \(p\) auf \(0\).

Hier ist ein zufälliger Sierpinski-Teppich.

p=0.1
# U= array(c(1,0,1 ,0,0,0, 1,0,1), dim=c(3,3)) # Cantor-Staub
U= array(c(1,1,1, 1,0,1, 1,1,1), dim=c(3,3)) # Sierpinski-Teppich
image(erzeuge_zu(2))

Für kleine Wahrscheinlichkeiten ergeben sich Punktmengen, die dem Sierpinski-Teppich sehr ähnlich sind. Für große Wahrscheinlichkeiten zerfällt der Sierpinski-Teppich. Man kann sich nun die Frage stellen, ab welcher Wahrscheinlicheit der Sierpinski-Teppich zerfällt. Diese Frage kann man experimentell untersuchen. Man kann sie auch mathematisch präzisieren und mit Methoden der Stochastik untersuchen. Der zufällige Sierpinski-Teppich ist ein einfaches Modell für sogenannte Perkolation.

Der Menger-Schwamm

Man kann die Konstruktion der Cantor-Menge und des Sierpinski-Teppichs auf drei Dimensionen verallgemeinern. Dies führt auf den sogenannten Menger-Schwamm.

U=array(c(1,1,1,1,0,1,1,1,1, 1,0,1,0,0,0,1,0,1, 1,1,1,1,0,1,1,1,1), dim=c(3,3,3))

Menger=erzeuge(2)

Die graphische Darstellung in drei Dimensionen erfolgt in einem eigenen Fenster. Dieses Fenster kann nicht im HTML-Dokument dargestellt werden, sondern setzt das Programm RStudio voraus.

Die graphische Darstellung kann mit dem R-Paket rgl wie folgt programmiert werden. Das Paket befindet sich nicht im Grundumfang von R, sondern muss zunächst mit install.packages(“rgl”) installiert werden.

# Paket rgl installieren (Befehl auskommentiert)
# install.packages("rgl")
# Paket rgl einlesen
library(rgl)
# Funktion fuer graphische Ausgabe definieren
zeige3d=function(A){
  # get the coordinates of the "1" entries
  co3d = which(A == 1, arr.ind = TRUE, useNames=FALSE)
  # determine number of "1" entries
  n=dim(co3d)[1]
  # convert to points in 3d by adding "0" in missing dimensions
  # get dimension of array
  d=length(dim(A))
  # add one 0-column if not three-dimensional:
  if (d<3) co3d=cbind(co3d, rep(0,n))
  # add another 0-column if one-dimensional:
  if (d==1) co3d=cbind(co3d, rep(0,n))
  # open new plot window
  open3d()
  # draw cubes at every "1" position
  for (i in 1:n) {
    # get coordinates
    pt=2*co3d[i,]
    # plot cube at position pt
    shade3d( translate3d( cube3d(col = "green"), pt[1], pt[2], pt[3]) )
  }
}

Mit der Funktion zeige3d lässt sich nun der Menger-Schwamm leicht darstellen.

# U=array(c(1,0,1), dim=3) # Cantormenge
# U= array(c(1,0,1,0,0,0,1,0,1), dim=c(3,3)) # Cantor-Staub 2d
# U= array(c(1,1,1,1,0,1,1,1,1), dim=c(3,3)) # Sierpinski-Teppich
# U=array(c(1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,1), dim=c(3,3,3)) # Cantor-Staub 3d
U=array(c(1,1,1,1,0,1,1,1,1,1,0,1,0,0,0,1,0,1,1,1,1,1,0,1,1,1,1), dim=c(3,3,3)) # Menger-Schwamm
M=erzeuge(2)
zeige3d(M)

Sie können mit der Funktion zeige3d auch die Cantormenge und den Sierpinski-Teppich darstellen. Verwenden Sie hierfür im obigen Programmcode einfach die entsprechende Unterteilung U.

zufällige Fraktale in 3d

Sie können für alle obigen Unterteilungen U zufällige Punktmengen dreidimensional darstellen. Wählen Sie wie oben einfach eine Wahrscheinlichkeit \(p\) und verwenden Sie die Funktion erzeuge_zu.

# U = array(c(1,0,1), dim=3) # Cantormenge
# U = array(c(1,0,1,0,0,0,1,0,1), dim=c(3,3)) # Cantor-Staub
U = array(c(1,1,1,1,0,1,1,1,1), dim=c(3,3)) # Sierpinski-Teppich
# U=array(c(1,1,1,1,0,1,1,1,1,1,0,1,0,0,0,1,0,1,1,1,1,1,0,1,1,1,1), dim=c(3,3,3)) # Menger-Schwamm
p=0.1; zeige3d(erzeuge_zu(2))

Sierpinski-Dreieck und Tetraeder

Ähnlich zum Sierpinski-Teppich kann man ein gleichseitiges Dreieck in 4 gleichseitige Dreiecke unterteilen und dann das mittlere Dreieck entfernen. Wiederholt man diese Konstruktion, ergibt sich das Sierpinski-Dreieck. Dies ist etwas aufwendiger zu programmieren als der Sierpinski-Teppich. Eine Alternative besteht darin, eine ähnliche Konstruktion mit einer Unterteilung eines Quadrats in 16 Teilquadrate durchzuführen.

U= array(c(1,0,0,0,1,1,0,0,1,0,1,0,1,1,1,1), dim=c(4,4)) # Sierpinski-Dreieck
zeige3d(erzeuge(1))

Auch dieses Verfahren kann man auf drei Dimensionen übertragen. Es ergibt sich der Sierpinski-Tetraeder.

U1=c(1,0,0,0,1,1,0,0,1,0,1,0,1,1,1,1)
U2=c(0,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0)
U3=c(0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0)
U4=c(0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0)
U= array(c(U1, U2, U3, U4), dim=c(4,4,4)) # Sierpinski-Tetraeder
zeige3d(erzeuge(1))
LS0tDQp0aXRsZTogIkV4cGVyaW1lbnRlIG1pdCBDYW50b3JtZW5nZW4iDQphdXRob3I6ICJDaHJpc3RvcGggUmljaGFyZCwgRkFVIEVybGFuZ2VuLU7DvHJuYmVyZywgMTguMDcuMjAyNSINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCkRpZXNlcyBIVE1MLURva3VtZW50IGlzdCBlaW4gQXJiZWl0c2JsYXR0IHp1ciBDYW50b3JtZW5nZSB1bmQgaWhyZW4gVmFyaWFudGVuLiBTaWUga8O2bm5lbiBlcyBhbHMgSFRNTC1Eb2t1bWVudCBsZXNlbi4gVGF0c8OkY2hsaWNoIGvDtm5uZW4gU2llIGVzIGFiZXIgYXVjaCBtaXQgSWhyZW0gQ29tcHV0ZXIgYmVhcmJlaXRlbi4gRGFzIEFyYmVpdHNibGF0dCBpc3Qga2VpbmUgRWluZsO8aHJ1bmcgaW4gUHJvZ3JhbW1pZXJ1bmcuIFN0YXR0ZGVzc2VuIHdlcmRlbiBQcm9ncmFtbWUgYmVyZWl0Z2VzdGVsbHQsIG1pdCBkZW5lbiBTaWUgQ2FudG9ybWVuZ2VuIGVyemV1Z2VuIGvDtm5uZW4uIFNpZSBrw7ZubmVuIGRpZXNlIFByb2dyYW1tZSBuYWNoIEJlbGllYmVuIGFiw6RuZGVybiB1bmQgc28gYXVmIGRlbSBDb21wdXRlciBtaXQgQ2FudG9ybWVuZ2VuIGV4cGVyaW1lbnRpZXJlbi4NCg0KV2lyIGFyYmVpdGVuIG1pdCBkZW0gZnJlaSBlcmjDpGx0bGljaGVuIFN0YXRpc3Rpay1Qcm9ncmFtbSBbUlN0dWRpb10oaHR0cHM6Ly9wb3NpdC5jby9kb3dubG9hZC9yc3R1ZGlvLWRlc2t0b3AvKSB1bmQgZGVyIFByb2dyYW1taWVyc3ByYWNoZSBSLg0KDQpTaWUga8O2bm5lbiBkaWVzZXMgSFRNTC1Eb2t1bWVudCBpbSBSTUQtRm9ybWF0IGFic3BlaWNoZXJuLCBzaWVoZSBkaWUgU2NoYWx0ZmzDpGNoZSAqQ29kZSogcmVjaHRzIG9iZW4uIFNpZSBrw7ZubmVuIGRhcyBSTUQtRG9rdW1lbnQgZGFubiBpbiBSU3R1ZGlvIMO2ZmZuZW4sIHVuZCBTaWUga8O2bm5lbiBkaWUgYmVyZWl0Z2VzdGVsbHRlbiBQcm9ncmFtbWUgYXVmIElocmVtIENvbXB1dGVyIGF1c2bDvGhyZW4uDQoNCiMgRGllIENhbnRvcm1lbmdlDQoNCk1hbiBlcmjDpGx0IGRpZSBDYW50b3JtZW5nZSAkQ1xzdWJzZXQgWzAsMV0kIGFscyBTY2huaXR0ICRDPVxiaWdjYXBfe25caW5cbWF0aGJiIE5fMH1DX24kIGFic3RlaWdlbmRlciBNZW5nZW4gJFswLDFdPUNfMFxzdXBzZXQgQ18xIFxzdXBzZXQgQ18yIFxzdXBzZXQgXGxkb3RzJCBCZWkgZGVyIEtvbnN0cnVrdGlvbiB2b24gJENfe24rMX0kIGVudGZlcm50IG1hbiBhdXMgamVkZW0gSW50ZXJ2YWxsIGluICRDX24kIGpld2VpbHMgZWluIG9mZmVuZXMgSW50ZXJ2YWxsLCBkYXMgbWl0dGxlcmUgRHJpdHRlbC4NCg0KQXVmIGRlbSBDb21wdXRlciBrYW5uIG1hbiBkaWUgS29uc3RydWt0aW9uIHZvbiAkQ19uJCB3aWUgZm9sZ3QgY29kaWVyZW4uIFNpZSBrw7ZubmVuIGRlbiBmb2xnZW5kZW4gQ29kZSBlaW5sZXNlbiwgaW5kZW0gU2llIGF1ZiBkYXMgUGZlaWxzeW1ib2wga2xpY2tlbi4NCg0KYGBge3J9DQpVPWMoMSwwLDEpDQplcnpldWdlID0gZnVuY3Rpb24obikgaWYgKG49PTApIHJldHVybigxKSBlbHNlIHJldHVybiggVSAleCUgZXJ6ZXVnZShuLTEpKQ0KYGBgDQoNCkRlciBBdWZydWYgKmVyemV1Z2UobikqIGxpZWZlcnQgZWluZSAwMS1QdW5rdG1lbmdlLCB3ZWxjaGUgJENfbiQgZW50c3ByaWNodC4gRGVyIEF1c2RydWNrICpVKiBiZXNjaHJlaWJ0IGRpZSBVbnRlcnRlaWx1bmcgZGVzIEVpbmhlaXRzaW50ZXJ2YWxscy4NCg0KYGBge3J9DQplcnpldWdlKDIpDQpgYGANCg0KTWl0IGRlbSBSLUJlZmVobCAqcGxvdCoga8O2bm5lbiBTaWUgZGllc2UgUHVua3RtZW5nZSBncmFwaGlzY2ggZGFyc3RlbGxlbi4gRGFzIEFyZ3VtZW50ICp0eXBlPSJoIiogZXJnaWJ0IGVpbmUgRGFyc3RlbGx1bmcgYWxzIEhpc3RvZ3JhbW0gbWl0IEJhbGtlbiBkZXIgSMO2aGUgJDAkIG9kZXIgJDEkLiBEaWUgTWVuZ2UgJENfbiQgZW50c3ByaWNodCBlaW5lbSBob3Jpem9udGFsZW4gU2Nobml0dCBpbSBmb2xnZW5kZW4gQmlsZC4NCg0KYGBge3J9DQpuPTU7IHBsb3QoZXJ6ZXVnZShuKSwgdHlwZT0iaCIpDQpgYGANCg0KIyBEZXIgQ2FudG9yLVN0YXViDQoNCkRpZSBvYmlnZSBLb25zdHJ1a3Rpb24ga2FubiBtYW4gYXVmIHp3ZWlkaW1lbnNpb25hbGUgUHVua3RtZW5nZW4gZXJ3ZWl0ZXJuLiBNYW4gc3RhcnRldCBtaXQgZGVtIEVpbmhlaXRzcXVhZHJhdCB1bmQgdW50ZXJ0ZWlsdCBlcyBpbiA5IGtsZWluZXJlIFF1YWRyYXRlLiBEYW5uIGVudGZlcm50IG1hbiBkaWUgNSBtaXR0bGVyZW4gUXVhZHJhdGUuIE1pdCBkaWVzZXIgS29uc3RydWt0aW9uIGbDpGhydCBtYW4gZm9ydCB1bmQgZXJow6RsdCBzbyBkZW4gQ2FudG9yLVN0YXViLg0KDQpgYGB7cn0NClUgPSBhcnJheShjKDEsMCwxLCAwLDAsMCwgMSwwLDEpLCBkaW09YygzLDMpKQ0Kbj0xOyBlcnpldWdlKG4pDQpgYGANCg0KRGllIFVudGVydGVpbHVuZyB3aXJkIGR1cmNoIGVpbmUgJDAxJC1NYXRyaXggZGFyZ2VzdGVsbHQuIE1hbiBrYW5uIHNvbGNoZSBNYXRyaXplbiBtaXQgZGVtIEJlZmVobCAqaW1hZ2UqIHZpc3VhbGlzaWVyZW4uDQoNCmBgYHtyfQ0KZm9yIChuIGluIDE6NCkgaW1hZ2UoZXJ6ZXVnZShuKSkNCmBgYA0KDQojIERlciBTaWVycGluc2tpLVRlcHBpY2gNCg0KRWluZSBWYXJpYW50ZSBkZXIgb2JpZ2VuIEtvbnN0cnVrdGlvbiBiZXN0ZWh0IGRhcmluLCBkYXNzIG1hbiB2b24gZGVuIDkga2xlaW5lbiBRdWFkcmF0ZW4gbGVkaWdsaWNoIGRhcyBtaXR0bGVyZSBRdWFkcmF0IGVudGZlcm50LiBEaWUgenVnZWjDtnJpZ2UgUHVua3RtZW5nZSBuZW5udCBtYW4gZGVuIFNpZXJwaW5za2ktVGVwcGljaC4NCg0KYGBge3J9DQpVPSBhcnJheShjKDEsMSwxLCAxLDAsMSwgMSwxLDEpLCBkaW09YygzLDMpKQ0KZm9yIChuIGluIDE6NCkgaW1hZ2UoZXJ6ZXVnZShuKSkNCmBgYA0KDQojIHp1ZsOkbGxpZ2UgU2llcnBpbmtzaS1UZXBwaWNoZQ0KDQpNYW4ga2FubiBkaWUgb2JpZ2VuIEtvbnN0cnVrdGlvbmVuIHJhbmRvbWlzaWVyZW4uIFp1bSBCZWlzcGllbCBrYW5uIG1hbiBwZXIgTcO8bnp3dXJmIGVudHNjaGVpZGVuLCBvYiBtYW4gZsO8ciBlaW4gUXVhZHJhdCBkaWUgU2llcnBpbnNraS1Lb25zdHJ1a3Rpb24gZHVyY2hmw7xocnQsIG9kZXIgb2IgbWFuIHN0YXR0ZGVzc2VuIGFsbGUgOSBUZWlscXVhZHJhdGUgZW50ZmVybnQuDQoNCkF1ZiBkZW0gQ29tcHV0ZXIga2FubiBtYW4gaGllcnp1IGZvbGdlbmRlcyBQcm9ncmFtbSBzY2hyZWliZW4uDQoNCmBgYHtyfQ0KIyBlcnNldHplICJ4IiBkdXJjaCAiMCIgbWl0IFdrZWl0IHANCngwID0gZnVuY3Rpb24oeCkgc2FtcGxlKGMoMCx4KSwxLHByb2I9YyhwLDEtcCkpDQojIGxvZXNjaGUgRWludHJhZWdlIGRlcyBBcnJheXMgQSBtaXQgV2tlaXQgcA0KbG9lc2NoZSA9IGZ1bmN0aW9uKEEpIGFycmF5KHNhcHBseShBLHgwKSwgZGltPWRpbShBKSkNCiMgZXJ6ZXVnZSBlaW5lIHp1ZmFlbGxpZ2UgQ2FudG9yLU1lbmdlDQplcnpldWdlX3p1ID0gZnVuY3Rpb24obikgaWYgKG49PTApIHJldHVybigxKSBlbHNlIHJldHVybiggbG9lc2NoZShVICV4JSBlcnpldWdlX3p1KG4tMSkpKQ0KYGBgDQoNCkRpZSBGdW5rdGlvbiAqenUqIGltcGxlbWVudGllcnQgZGVuIE3DvG56d3VyZiBhdWYgZGVtIENvbXB1dGVyLiBGw7xyIGVpbmUgTWF0cml4IGF1cyBOdWxsZW4gdW5kIEVpbnNlbiB3ZXJkZW4gYWxsZSBFaW50csOkZ2UgbWl0IFp1ZmFsbHN6YWhsZW4gJDAkIG9kZXIgJDEkIGF1cyBlaW5lbSBNw7xuend1cmYgbXVsdGlwbGl6aWVydC4gSGllcmJlaSB0cml0dCAkMCQgbWl0IFdhaHJzY2hlaW5saWNoa2VpdCAkcCQgYXVmLCB1bmQgJDEkIHRyaXR0IG1pdCBXYWhyc2NoZWlubGljaGtlaXQgJDEtcCQgYXVmLg0KDQpEaWUgRnVua3Rpb24gKnJwKiBzZXR6dCBlaW5lbiBXZXJ0ICR4JCBtaXQgV2FocnNjaGVpbmxpY2hrZWl0ICRwJCBhdWYgJDAkLg0KDQpIaWVyIGlzdCBlaW4genVmw6RsbGlnZXIgU2llcnBpbnNraS1UZXBwaWNoLg0KDQpgYGB7cn0NCnA9MC4xDQojIFU9IGFycmF5KGMoMSwwLDEgLDAsMCwwLCAxLDAsMSksIGRpbT1jKDMsMykpICMgQ2FudG9yLVN0YXViDQpVPSBhcnJheShjKDEsMSwxLCAxLDAsMSwgMSwxLDEpLCBkaW09YygzLDMpKSAjIFNpZXJwaW5za2ktVGVwcGljaA0KaW1hZ2UoZXJ6ZXVnZV96dSgyKSkNCmBgYA0KDQpGw7xyIGtsZWluZSBXYWhyc2NoZWlubGljaGtlaXRlbiBlcmdlYmVuIHNpY2ggUHVua3RtZW5nZW4sIGRpZSBkZW0gU2llcnBpbnNraS1UZXBwaWNoIHNlaHIgw6RobmxpY2ggc2luZC4gRsO8ciBncm/Dn2UgV2FocnNjaGVpbmxpY2hrZWl0ZW4gemVyZsOkbGx0IGRlciBTaWVycGluc2tpLVRlcHBpY2guIE1hbiBrYW5uIHNpY2ggbnVuIGRpZSBGcmFnZSBzdGVsbGVuLCBhYiB3ZWxjaGVyIFdhaHJzY2hlaW5saWNoZWl0IGRlciBTaWVycGluc2tpLVRlcHBpY2ggemVyZsOkbGx0LiBEaWVzZSBGcmFnZSBrYW5uIG1hbiBleHBlcmltZW50ZWxsIHVudGVyc3VjaGVuLiBNYW4ga2FubiBzaWUgYXVjaCBtYXRoZW1hdGlzY2ggcHLDpHppc2llcmVuIHVuZCBtaXQgTWV0aG9kZW4gZGVyIFN0b2NoYXN0aWsgdW50ZXJzdWNoZW4uIERlciB6dWbDpGxsaWdlIFNpZXJwaW5za2ktVGVwcGljaCBpc3QgZWluIGVpbmZhY2hlcyBNb2RlbGwgZsO8ciBzb2dlbmFubnRlIFBlcmtvbGF0aW9uLg0KDQojIERlciBNZW5nZXItU2Nod2FtbQ0KDQpNYW4ga2FubiBkaWUgS29uc3RydWt0aW9uIGRlciBDYW50b3ItTWVuZ2UgdW5kIGRlcyBTaWVycGluc2tpLVRlcHBpY2hzIGF1ZiBkcmVpIERpbWVuc2lvbmVuIHZlcmFsbGdlbWVpbmVybi4gRGllcyBmw7xocnQgYXVmIGRlbiBzb2dlbmFubnRlbiBNZW5nZXItU2Nod2FtbS4NCg0KYGBge3J9DQpVPWFycmF5KGMoMSwxLDEsMSwwLDEsMSwxLDEsIDEsMCwxLDAsMCwwLDEsMCwxLCAxLDEsMSwxLDAsMSwxLDEsMSksIGRpbT1jKDMsMywzKSkNCg0KTWVuZ2VyPWVyemV1Z2UoMikNCmBgYA0KDQpEaWUgZ3JhcGhpc2NoZSBEYXJzdGVsbHVuZyBpbiBkcmVpIERpbWVuc2lvbmVuIGVyZm9sZ3QgaW4gZWluZW0gZWlnZW5lbiBGZW5zdGVyLiBEaWVzZXMgRmVuc3RlciBrYW5uIG5pY2h0IGltIEhUTUwtRG9rdW1lbnQgZGFyZ2VzdGVsbHQgd2VyZGVuLCBzb25kZXJuIHNldHp0IGRhcyBQcm9ncmFtbSBSU3R1ZGlvIHZvcmF1cy4NCg0KRGllIGdyYXBoaXNjaGUgRGFyc3RlbGx1bmcga2FubiBtaXQgZGVtIFItUGFrZXQgKnJnbCogd2llIGZvbGd0IHByb2dyYW1taWVydCB3ZXJkZW4uIERhcyBQYWtldCBiZWZpbmRldCBzaWNoIG5pY2h0IGltIEdydW5kdW1mYW5nIHZvbiBSLCBzb25kZXJuIG11c3MgenVuw6RjaHN0IG1pdCAqaW5zdGFsbC5wYWNrYWdlcygicmdsIikqIGluc3RhbGxpZXJ0IHdlcmRlbi4NCg0KYGBge3J9DQojIFBha2V0IHJnbCBpbnN0YWxsaWVyZW4gKEJlZmVobCBhdXNrb21tZW50aWVydCkNCiMgaW5zdGFsbC5wYWNrYWdlcygicmdsIikNCiMgUGFrZXQgcmdsIGVpbmxlc2VuDQpsaWJyYXJ5KHJnbCkNCiMgRnVua3Rpb24gZnVlciBncmFwaGlzY2hlIEF1c2dhYmUgZGVmaW5pZXJlbg0KemVpZ2UzZD1mdW5jdGlvbihBKXsNCiAgIyBnZXQgdGhlIGNvb3JkaW5hdGVzIG9mIHRoZSAiMSIgZW50cmllcw0KICBjbzNkID0gd2hpY2goQSA9PSAxLCBhcnIuaW5kID0gVFJVRSwgdXNlTmFtZXM9RkFMU0UpDQogICMgZGV0ZXJtaW5lIG51bWJlciBvZiAiMSIgZW50cmllcw0KICBuPWRpbShjbzNkKVsxXQ0KICAjIGNvbnZlcnQgdG8gcG9pbnRzIGluIDNkIGJ5IGFkZGluZyAiMCIgaW4gbWlzc2luZyBkaW1lbnNpb25zDQogICMgZ2V0IGRpbWVuc2lvbiBvZiBhcnJheQ0KICBkPWxlbmd0aChkaW0oQSkpDQogICMgYWRkIG9uZSAwLWNvbHVtbiBpZiBub3QgdGhyZWUtZGltZW5zaW9uYWw6DQogIGlmIChkPDMpIGNvM2Q9Y2JpbmQoY28zZCwgcmVwKDAsbikpDQogICMgYWRkIGFub3RoZXIgMC1jb2x1bW4gaWYgb25lLWRpbWVuc2lvbmFsOg0KICBpZiAoZD09MSkgY28zZD1jYmluZChjbzNkLCByZXAoMCxuKSkNCiAgIyBvcGVuIG5ldyBwbG90IHdpbmRvdw0KICBvcGVuM2QoKQ0KICAjIGRyYXcgY3ViZXMgYXQgZXZlcnkgIjEiIHBvc2l0aW9uDQogIGZvciAoaSBpbiAxOm4pIHsNCiAgICAjIGdldCBjb29yZGluYXRlcw0KICAgIHB0PTIqY28zZFtpLF0NCiAgICAjIHBsb3QgY3ViZSBhdCBwb3NpdGlvbiBwdA0KICAgIHNoYWRlM2QoIHRyYW5zbGF0ZTNkKCBjdWJlM2QoY29sID0gImdyZWVuIiksIHB0WzFdLCBwdFsyXSwgcHRbM10pICkNCiAgfQ0KfQ0KYGBgDQoNCk1pdCBkZXIgRnVua3Rpb24gKnplaWdlM2QqIGzDpHNzdCBzaWNoIG51biBkZXIgTWVuZ2VyLVNjaHdhbW0gbGVpY2h0IGRhcnN0ZWxsZW4uDQoNCmBgYHtyfQ0KIyBVPWFycmF5KGMoMSwwLDEpLCBkaW09MykgIyBDYW50b3JtZW5nZQ0KIyBVPSBhcnJheShjKDEsMCwxLDAsMCwwLDEsMCwxKSwgZGltPWMoMywzKSkgIyBDYW50b3ItU3RhdWIgMmQNCiMgVT0gYXJyYXkoYygxLDEsMSwxLDAsMSwxLDEsMSksIGRpbT1jKDMsMykpICMgU2llcnBpbnNraS1UZXBwaWNoDQojIFU9YXJyYXkoYygxLDAsMSwwLDAsMCwxLDAsMSwwLDAsMCwwLDAsMCwwLDAsMCwxLDAsMSwwLDAsMCwxLDAsMSksIGRpbT1jKDMsMywzKSkgIyBDYW50b3ItU3RhdWIgM2QNClU9YXJyYXkoYygxLDEsMSwxLDAsMSwxLDEsMSwxLDAsMSwwLDAsMCwxLDAsMSwxLDEsMSwxLDAsMSwxLDEsMSksIGRpbT1jKDMsMywzKSkgIyBNZW5nZXItU2Nod2FtbQ0KTT1lcnpldWdlKDIpDQp6ZWlnZTNkKE0pDQpgYGANCg0KU2llIGvDtm5uZW4gbWl0IGRlciBGdW5rdGlvbiAqemVpZ2UzZCogYXVjaCBkaWUgQ2FudG9ybWVuZ2UgdW5kIGRlbiBTaWVycGluc2tpLVRlcHBpY2ggZGFyc3RlbGxlbi4gVmVyd2VuZGVuIFNpZSBoaWVyZsO8ciBpbSBvYmlnZW4gUHJvZ3JhbW1jb2RlIGVpbmZhY2ggZGllIGVudHNwcmVjaGVuZGUgVW50ZXJ0ZWlsdW5nICpVKi4NCg0KIyB6dWbDpGxsaWdlIEZyYWt0YWxlIGluIDNkDQoNClNpZSBrw7ZubmVuIGbDvHIgYWxsZSBvYmlnZW4gVW50ZXJ0ZWlsdW5nZW4gKlUqIHp1ZsOkbGxpZ2UgUHVua3RtZW5nZW4gZHJlaWRpbWVuc2lvbmFsIGRhcnN0ZWxsZW4uIFfDpGhsZW4gU2llIHdpZSBvYmVuIGVpbmZhY2ggZWluZSBXYWhyc2NoZWlubGljaGtlaXQgJHAkIHVuZCB2ZXJ3ZW5kZW4gU2llIGRpZSBGdW5rdGlvbiAqZXJ6ZXVnZV96dSouDQoNCmBgYHtyfQ0KIyBVID0gYXJyYXkoYygxLDAsMSksIGRpbT0zKSAjIENhbnRvcm1lbmdlDQojIFUgPSBhcnJheShjKDEsMCwxLDAsMCwwLDEsMCwxKSwgZGltPWMoMywzKSkgIyBDYW50b3ItU3RhdWINClUgPSBhcnJheShjKDEsMSwxLDEsMCwxLDEsMSwxKSwgZGltPWMoMywzKSkgIyBTaWVycGluc2tpLVRlcHBpY2gNCiMgVT1hcnJheShjKDEsMSwxLDEsMCwxLDEsMSwxLDEsMCwxLDAsMCwwLDEsMCwxLDEsMSwxLDEsMCwxLDEsMSwxKSwgZGltPWMoMywzLDMpKSAjIE1lbmdlci1TY2h3YW1tDQpwPTAuMTsgemVpZ2UzZChlcnpldWdlX3p1KDIpKQ0KYGBgDQoNCiMgU2llcnBpbnNraS1EcmVpZWNrIHVuZCBUZXRyYWVkZXINCg0Kw4RobmxpY2ggenVtIFNpZXJwaW5za2ktVGVwcGljaCBrYW5uIG1hbiBlaW4gZ2xlaWNoc2VpdGlnZXMgRHJlaWVjayBpbiA0IGdsZWljaHNlaXRpZ2UgRHJlaWVja2UgdW50ZXJ0ZWlsZW4gdW5kIGRhbm4gZGFzIG1pdHRsZXJlIERyZWllY2sgZW50ZmVybmVuLiBXaWVkZXJob2x0IG1hbiBkaWVzZSBLb25zdHJ1a3Rpb24sIGVyZ2lidCBzaWNoIGRhcyBTaWVycGluc2tpLURyZWllY2suIERpZXMgaXN0IGV0d2FzIGF1ZndlbmRpZ2VyIHp1IHByb2dyYW1taWVyZW4gYWxzIGRlciBTaWVycGluc2tpLVRlcHBpY2guIEVpbmUgQWx0ZXJuYXRpdmUgYmVzdGVodCBkYXJpbiwgZWluZSDDpGhubGljaGUgS29uc3RydWt0aW9uIG1pdCBlaW5lciBVbnRlcnRlaWx1bmcgZWluZXMgUXVhZHJhdHMgaW4gMTYgVGVpbHF1YWRyYXRlIGR1cmNoenVmw7xocmVuLg0KDQpgYGB7cn0NClU9IGFycmF5KGMoMSwwLDAsMCwxLDEsMCwwLDEsMCwxLDAsMSwxLDEsMSksIGRpbT1jKDQsNCkpICMgU2llcnBpbnNraS1EcmVpZWNrDQp6ZWlnZTNkKGVyemV1Z2UoMSkpDQpgYGANCg0KQXVjaCBkaWVzZXMgVmVyZmFocmVuIGthbm4gbWFuIGF1ZiBkcmVpIERpbWVuc2lvbmVuIMO8YmVydHJhZ2VuLiBFcyBlcmdpYnQgc2ljaCBkZXIgU2llcnBpbnNraS1UZXRyYWVkZXIuDQoNCmBgYHtyfQ0KVTE9YygxLDAsMCwwLDEsMSwwLDAsMSwwLDEsMCwxLDEsMSwxKQ0KVTI9YygwLDAsMCwwLDEsMCwwLDAsMCwwLDAsMCwxLDAsMSwwKQ0KVTM9YygwLDAsMCwwLDAsMCwwLDAsMSwwLDAsMCwxLDEsMCwwKQ0KVTQ9YygwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwxLDAsMCwwKQ0KVT0gYXJyYXkoYyhVMSwgVTIsIFUzLCBVNCksIGRpbT1jKDQsNCw0KSkgIyBTaWVycGluc2tpLVRldHJhZWRlcg0KemVpZ2UzZChlcnpldWdlKDEpKQ0KYGBgDQo=