Last active
November 3, 2025 19:52
-
-
Save horstjens/d9e424a4d5b038b3990a26a80957bfe2 to your computer and use it in GitHub Desktop.
termin08_oop
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # puzzlespiel | |
| # - bild | |
| # - anzahl steine | |
| # - schierigkeitsgrad | |
| # - altersempfehlung | |
| # - zustand | |
| # - anzahl_fehlende_steine | |
| # - anzahl_kaputte_steine | |
| # - anzahl_beschädigte_steine | |
| # - format (hochkant / quer ) | |
| # - 3d-puzzle | |
| # puzzlestein | |
| # - teil von einem puzzlespiel | |
| # - material | |
| # - zapferl, bucht, glatte kante: | |
| # - oben | |
| # - links | |
| # - unten | |
| # - rechts |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class Puzzlespiel: | |
| bild = "alpen.jpg" # class variable nicht ideal, | |
| # ich will viele Instanzen | |
| # | |
| # - bild | |
| # - anzahl steine | |
| # - schierigkeitsgrad | |
| # - altersempfehlung | |
| # - zustand | |
| # - anzahl_fehlende_steine | |
| # - anzahl_kaputte_steine | |
| # - anzahl_beschädigte_steine | |
| # - format (hochkant / quer ) | |
| # - 3d-puzzle | |
| # puzzlestein | |
| # - teil von einem puzzlespiel | |
| # - material | |
| # - zapferl, bucht, glatte kante: | |
| # - oben | |
| # - links | |
| # - unten | |
| # - rechts |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class Puzzlespiel: | |
| def __init__(self, bild, anzahl_steine, zustand): | |
| self.bild = bild | |
| self.anzahl_steine = anzahl_steine | |
| self.zustand = zustand | |
| # instanzen erzeugen ... die müssen in einem container leben | |
| meine_spiele = [ | |
| Puzzlespiel("pferd.jpg", 500, "gut"), | |
| Puzzlespiel("wasserfall.jpg", 1000, "leicht beschädigt"), | |
| ] | |
| print(meine_spiele) | |
| for p in meine_spiele: | |
| print("alle attribute dieser instanz") | |
| print(p.__dict__) # zeigt alle eigenschaften vom puzzlespiel | |
| # - bild | |
| # - anzahl steine | |
| # - schierigkeitsgrad | |
| # - altersempfehlung | |
| # - zustand | |
| # - anzahl_fehlende_steine | |
| # - anzahl_kaputte_steine | |
| # - anzahl_beschädigte_steine | |
| # - format (hochkant / quer ) | |
| # - 3d-puzzle | |
| # puzzlestein | |
| # - teil von einem puzzlespiel | |
| # - material | |
| # - zapferl, bucht, glatte kante: | |
| # - oben | |
| # - links | |
| # - unten | |
| # - rechts |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class Puzzlespiel: | |
| def __init__(self, bild, anzahl_steine, zustand): | |
| self.bild = bild | |
| self.anzahl_steine = anzahl_steine | |
| self.zustand = zustand | |
| # instanzen erzeugen ... die müssen in einem container leben | |
| meine_spiele = [ | |
| Puzzlespiel("pferd.jpg", 500, "gut"), | |
| Puzzlespiel("wasserfall.jpg", 1000, "leicht beschädigt"), | |
| ] | |
| puzzle3 = Puzzlespiel("wiese.jpg", 200, "gut") | |
| for p in [*meine_spiele , puzzle3]: | |
| print("alle attribute dieser instanz") | |
| print(p.__dict__) # zeigt alle eigenschaften vom puzzlespiel | |
| # - bild | |
| # - anzahl steine | |
| # - schierigkeitsgrad | |
| # - altersempfehlung | |
| # - zustand | |
| # - anzahl_fehlende_steine | |
| # - anzahl_kaputte_steine | |
| # - anzahl_beschädigte_steine | |
| # - format (hochkant / quer ) | |
| # - 3d-puzzle | |
| # puzzlestein | |
| # - teil von einem puzzlespiel | |
| # - material | |
| # - zapferl, bucht, glatte kante: | |
| # - oben | |
| # - links | |
| # - unten | |
| # - rechts |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # alle instanzen einer klasse müssen irgendwo "leben" | |
| # z.b. in einer Variablen (puzzle3 = ) | |
| # oder in einer datenstruktur (liste meine_spiele) | |
| # idee: gleich in der __init__ methode dafür sorgen | |
| # daß ide Instanz in einer Datenstruktur landet | |
| class Lager: | |
| meine_spiele = [] # class variable | |
| class Puzzlespiel: | |
| def __init__(self, bild, anzahl_steine, zustand): | |
| self.bild = bild | |
| self.anzahl_steine = anzahl_steine | |
| self.zustand = zustand | |
| # self referenziert DIESE Instanz | |
| Lager.meine_spiele.append(self) | |
| # instanzen erzeugen | |
| Puzzlespiel("pferd.jpg", 500, "gut"), | |
| Puzzlespiel("wasserfall.jpg", 1000, "leicht beschädigt"), | |
| Puzzlespiel("wiese.jpg", 200, "gut") | |
| for p in Lager.meine_spiele: | |
| print("alle attribute dieser instanz") | |
| print(p.__dict__) # zeigt alle eigenschaften vom puzzlespiel | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # alle instanzen einer klasse müssen irgendwo "leben" | |
| # z.b. in einer Variablen (puzzle3 = ) | |
| # oder in einer datenstruktur (liste meine_spiele) | |
| # idee: gleich in der __init__ methode dafür sorgen | |
| # daß ide Instanz in einer Datenstruktur landet | |
| class Lager: | |
| meine_spiele = [] # class variable | |
| class Puzzlespiel: | |
| def __init__(self, bild, anzahl_steine, zustand): | |
| self.bild = bild | |
| self.anzahl_steine = anzahl_steine | |
| self.zustand = zustand | |
| # self referenziert DIESE Instanz | |
| Lager.meine_spiele.append(self) | |
| # instanzen erzeugen | |
| Puzzlespiel("pferd.jpg", 500, "gut") | |
| Puzzlespiel("wasserfall.jpg", 1000, "leicht beschädigt") | |
| Puzzlespiel("wiese.jpg", 200, "gut") | |
| class Puzzlestein: | |
| def __init__(self, zustand, anzahl_glatten_Kanten, anzahl_zapferl, anzahl_buchten): | |
| self.zustand = zustand | |
| self.anzahl_glatten_Kanten = anzahl_glatten_Kanten | |
| self.anzahl_zapferl = anzahl_zapferl | |
| self.anzahl_buchten = anzahl_buchten | |
| container = [] | |
| container.append(Puzzlestein("gut", 0, 4, 0)) | |
| container.append(Puzzlestein("gut", 1, 2, 1)) | |
| container.append(Puzzlestein("beschädigt", 0, 2, 2)) | |
| print("puzzlesteine") | |
| for steinchen in container: | |
| print(steinchen.__dict__) | |
| #for p in Lager.meine_spiele: | |
| # print("alle attribute dieser instanz") | |
| # print(p.__dict__) # zeigt alle eigenschaften vom puzzlespiel | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # zuordnung von Puzzlesteinen zu Puzzlespielen kann auf | |
| # verschiende Arten erfolgen | |
| class Lager: | |
| meine_spiele = [] # class variable | |
| class Puzzlespiel: | |
| def __init__(self, bild, anzahl_steine, zustand): | |
| self.bild = bild | |
| self.anzahl_steine = anzahl_steine | |
| self.zustand = zustand | |
| # self referenziert DIESE Instanz | |
| Lager.meine_spiele.append(self) | |
| self.steine = [] # leere Liste | |
| class Puzzlestein: | |
| def __init__(self, zustand, anzahl_glatten_Kanten, anzahl_zapferl, anzahl_buchten): | |
| self.zustand = zustand | |
| self.anzahl_glatten_Kanten = anzahl_glatten_Kanten | |
| self.anzahl_zapferl = anzahl_zapferl | |
| self.anzahl_buchten = anzahl_buchten | |
| # instanzen erzeugen | |
| Puzzlespiel("pferd.jpg", 500, "gut") | |
| Puzzlespiel("wasserfall.jpg", 1000, "leicht beschädigt") | |
| Puzzlespiel("wiese.jpg", 200, "gut") | |
| for p in Lager.meine_spiele: | |
| #print("alle attribute dieser instanz") | |
| #print(p.__dict__) # zeigt alle eigenschaften vom puzzlespiel | |
| p.steine.append(Puzzlestein("gut", 0, 4, 0)) | |
| p.steine.append(Puzzlestein("gut", 1, 3, 1)) | |
| p.steine.append(Puzzlestein("gut", 0, 2, 2)) | |
| for spiel in Lager.meine_spiele: | |
| print("spiel instanz:") | |
| print(spiel.__dict__) | |
| print("spielsteine:") | |
| for steinchen in spiel.steine: | |
| print(steinchen.__dict__) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import random | |
| # exploding dice: | |
| # würfel, der nochmal würfeln darf wenn eine (6 bzw. | |
| #höchste Augenzahl) gewürfelt wird. | |
| # bsp: 6-seitiger würfel: | |
| # es wird eine 6 gewürfelt, sie zählt 5 (6-1) aber darf nochaml würfeln | |
| # würfelt wieder eine 6 (zählt wieder als 5, also 5+5=10), darf nochmal | |
| # würfelt eine 2, ergebnis ist 5+5+2 = 12 | |
| def exploding_dice(anzahl_würfel=2, anzahl_seiten=6): | |
| summe = 0 | |
| text = "" | |
| for x in range(anzahl_würfel): | |
| while True: | |
| e = random.randint(1, anzahl_seiten) | |
| summe += e # | |
| text += f"+{e}" | |
| if e == anzahl_seiten: | |
| summe -= 1 | |
| text += "-1" | |
| continue # geht an den Anfang der Schleife | |
| break | |
| text += " " # | |
| return summe, text[1:] # erstes zeichen löschen | |
| # verbesserte Funktion: erlaubt parameter für | |
| # anzahl der würfel, | |
| # anzahl der seiten pro Würfel | |
| def wurf(anzahl_würfel=2, anzahl_seiten=6): | |
| summe = 0 | |
| text = "" | |
| for x in range(anzahl_würfel): | |
| e = random.randint(1, anzahl_seiten) | |
| summe += e | |
| text += f"+{e}" | |
| return summe, text[1:] # erstes zeichen löschen | |
| if __name__ == "__main__": | |
| print("testen") | |
| for _ in range(10): | |
| print("exploding_dice(2,6): {:>2} = {}".format(*exploding_dice(2,6))) | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import random | |
| # dnd-strings | |
| # 2d6 .... 2 würfel, jeder hat 6 seiten | |
| # 2d6+1 .. 2 würfel, jeder würfel hat 6 seiten, zum endergbnis +1 dazuzählen | |
| # 4d4-3 .. 4 würfel, jeder hat 4 seiten, vom endergebnis 3 abziehen | |
| # erweiterung um exploding dice: großes D bedeutet exploding dice | |
| # 1D20.....1 würfel mit 20 Seiten, bei 20 darf nochmal gewürfelt werden | |
| # 2D6-5 ...2 würfel je mit 6 Seiten, bei 6 darf nochaml... vom endergnbis 5 abziehen | |
| # eine funktion, die dnd-string als argument bekommt und | |
| # ein tuple zurückgibt mit endergebnis (int) und einem string | |
| # die funktion soll (0,"ungültiger dnd-string") zurückgeben wenn der | |
| # dnd string ungültig ist | |
| def dnd(dnd_string="2d6"): | |
| # wächter: schauen ob der dnd_string in Ordnung ist | |
| if not ("d" in dnd_string or "D" in dnd_string): | |
| return (0,"ungültiger dnd-string: habe weder ein d noch ein D gefunden") | |
| # mehr als ein D (oder d) drin ? | |
| if dnd_string.lower().count("d") > 1: | |
| return (0,"mehr als ein d (oder D) gefunden") | |
| ### noch eleganter | |
| ### if dnd_string.lower().count("d") != 1: | |
| ### return (0, "habe ungleich 1 d (bzw D) gefunden) | |
| # es darf jetzt ein plus oder ein minus (oder keines von beiden) drin sein | |
| # und sonst nur ziffern | |
| if "+" in dnd_string or "-" in dnd_string: | |
| # plus oder minus ist drin, aber wie oft? | |
| # trick: ich ersetze die - durch + | |
| if dnd_string.replace("-","+").count("+") > 1: | |
| return (0,"ungültiger dnd-string: zu viele + bzw - gefunden") | |
| # jetzt dürfen nur noch ziffern drin sein | |
| ### varianten | |
| ### string am d zerlegen in einen linken teil und einen rechten teil | |
| ### teilstrings in int umwandeln | |
| # set: jedes element in einem set kommt nur einmal vora | |
| if not set(dnd_string).issubset({"+","-","d","D","0","1","2","3","4", | |
| "5","6","7","8","9"}): | |
| return (0,"ungültiger dnd-string: unerlaubtes Zeichen gefunden") | |
| # ich gehe jetzt davon aus das der dnd-string gültig ist | |
| # großes oder kleines d drin ? | |
| if "D" in dnd_string: | |
| exploding = True | |
| else: | |
| exploding = False | |
| dnd_string = dnd_string.replace("D","d") # immer ein kleins d drin | |
| # dnd-string zerlegen in: anzahl_würfel, seiten_pro_würfel, delta | |
| # position vom trennzeichen (d) | |
| trennzeichenposition = dnd_string.index("d") # python startet mit 0 | |
| # slicen!!! | |
| anzahl_würfel = int(dnd_string[:trennzeichenposition]) | |
| # rechts vom "d" könnte ein + bzw - stehen | |
| rest_vom_string = dnd_string[trennzeichenposition+1:] # alles rechts vom d | |
| # ist ein plus drin: | |
| if "+" in rest_vom_string: | |
| trennzeichen = "+" | |
| elif "-" in rest_vom_string: | |
| trennzeichen = "-" | |
| else: | |
| trennzeichen = None # nix | |
| delta = 0 | |
| seiten = int(rest_vom_string) | |
| if trennzeichen is not None: | |
| plus_minus_position = rest_vom_string.index(trennzeichen) | |
| delta = int(rest_vom_string[plus_minus_position:]) # inkl plusminustrennzeichen | |
| seiten = int(rest_vom_string[:plus_minus_position]) | |
| # ich weiß jetzt: exploding, anzahl_würfel, seiten, delta | |
| if exploding: | |
| ergebnis, text = exploding_dice(anzahl_würfel, seiten) | |
| else: | |
| ergebnis, text = wurf(anzahl_würfel, seiten) | |
| endergebnis = ergebnis + delta | |
| if delta == 0: | |
| return endergebnis, text | |
| if delta < 0: | |
| return endergebnis, f"{text}{delta}" | |
| if delta > 0: | |
| return endergebnis, f"{text}+{delta}" | |
| def exploding_dice(anzahl_würfel=2, anzahl_seiten=6): | |
| summe = 0 | |
| text = "" | |
| for x in range(anzahl_würfel): | |
| while True: | |
| e = random.randint(1, anzahl_seiten) | |
| summe += e # | |
| text += f"+{e}" | |
| if e == anzahl_seiten: | |
| summe -= 1 | |
| text += "-1" | |
| continue # geht an den Anfang der Schleife | |
| break | |
| text += " " # | |
| return summe, text[1:] # erstes zeichen löschen | |
| def wurf(anzahl_würfel=2, anzahl_seiten=6): | |
| summe = 0 | |
| text = "" | |
| for x in range(anzahl_würfel): | |
| e = random.randint(1, anzahl_seiten) | |
| summe += e | |
| text += f"+{e}" | |
| return summe, text[1:] # erstes zeichen löschen | |
| if __name__ == "__main__": | |
| print("testen Sie einen dnd String: ") | |
| while True: | |
| eingabe = input("bitte hier dnd-string eingeben, z.B. 2d6+4 oder 'quit'") | |
| if eingabe.lower() == "quit": | |
| break | |
| print(dnd(eingabe)) | |
| print("bye") | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Python 3.13.5 (main, Jun 25 2025, 18:55:22) [GCC 14.2.0] on linux | |
| Enter "help" below or click "Help" above for more information. | |
| namen = ["adam abromovic", "berta besen", "carl Chaos", "doris day"] | |
| namen.append("Ali Zusza") | |
| namen | |
| ['adam abromovic', 'berta besen', 'carl Chaos', 'doris day', 'Ali Zusza'] | |
| namen[-1] = "ali zuza" | |
| namen | |
| ['adam abromovic', 'berta besen', 'carl Chaos', 'doris day', 'ali zuza'] | |
| namen.sort() | |
| namen | |
| ['adam abromovic', 'ali zuza', 'berta besen', 'carl Chaos', 'doris day'] | |
| namen.sort(reverse=True) | |
| namen | |
| ['doris day', 'carl Chaos', 'berta besen', 'ali zuza', 'adam abromovic'] | |
| namen[0] | |
| 'doris day' | |
| len(namen[0]) | |
| 9 | |
| for n in namen: | |
| print(len(n)) | |
| 9 | |
| 10 | |
| 11 | |
| 8 | |
| 14 | |
| def länge(x): | |
| return len(x) | |
| länge("Ali zuza") | |
| 8 | |
| namen.sort(länge) | |
| Traceback (most recent call last): | |
| File "<pyshell#18>", line 1, in <module> | |
| namen.sort(länge) | |
| TypeError: sort() takes no positional arguments | |
| namen.sort(key=länge) | |
| namen | |
| ['ali zuza', 'doris day', 'carl Chaos', 'berta besen', 'adam abromovic'] | |
| namen.sort(key=lambda x:len(x), reverse=True) | |
| namen | |
| ['adam abromovic', 'berta besen', 'carl Chaos', 'doris day', 'ali zuza'] | |
| feuerlöscher = {"farbe":"rot", "ort":"dachboden",nächste_wartung:2027} | |
| Traceback (most recent call last): | |
| File "<pyshell#39>", line 1, in <module> | |
| feuerlöscher = {"farbe":"rot", "ort":"dachboden",nächste_wartung:2027} | |
| NameError: name 'nächste_wartung' is not defined | |
| feuerlöscher = {"farbe":"rot", "ort":"dachboden","nächste_wartung":2027} | |
| feuerlöscher["farbe"] | |
| 'rot' | |
| class Feuerlöscher: | |
| farbe="rot" | |
| ort="dachboden" | |
| nächste_wartung=2027 | |
| Feuerlöscher.farbe | |
| 'rot' | |
| Feuerlöscher.ort | |
| 'dachboden' | |
| Feuerlöscher.nächste_wartung = 2033 | |
| feuerlöscher.__dict__ | |
| Traceback (most recent call last): | |
| File "<pyshell#50>", line 1, in <module> | |
| feuerlöscher.__dict__ | |
| AttributeError: 'dict' object has no attribute '__dict__'. Did you mean: '__dir__'? | |
| feuerlöscher.__dir__ | |
| <built-in method __dir__ of dict object at 0x7f0553646180> | |
| Fuerlöscher.__dict__ | |
| Traceback (most recent call last): | |
| File "<pyshell#52>", line 1, in <module> | |
| Fuerlöscher.__dict__ | |
| NameError: name 'Fuerlöscher' is not defined. Did you mean: 'Feuerlöscher'? | |
| Feuerlöscher.__dict__ | |
| mappingproxy({'__module__': '__main__', '__firstlineno__': 1, 'farbe': 'rot', 'ort': 'dachboden', 'nächste_wartung': 2033, '__static_attributes__': (), '__dict__': <attribute '__dict__' of 'Feuerlöscher' objects>, '__weakref__': <attribute '__weakref__' of 'Feuerlöscher' objects>, '__doc__': None}) | |
| class Feuerlöscher: | |
| def __init__(self, farbe="rot", wartung=2028, ort="stiegenhaus"): | |
| self.farbe = farbe | |
| self.wartung = wartung | |
| self.ort = ort | |
| self.gewicht = 5 | |
| self.löschmittel = "Schaum" | |
| f1 = Feuerlöscher() | |
| f2 = Feuerlöscher(farbe="orange") | |
| f3 = Feuerlöscher(ort="Dachboden") | |
| f1 | |
| <__main__.Feuerlöscher object at 0x7f0553f8a660> | |
| f2 | |
| <__main__.Feuerlöscher object at 0x7f0553f77d90> | |
| f3 | |
| <__main__.Feuerlöscher object at 0x7f0553f779d0> | |
| f3.löschmittel | |
| 'Schaum' | |
| f1.ort | |
| 'stiegenhaus' | |
| f2.ort | |
| 'stiegenhaus' | |
| f3.ort | |
| 'Dachboden' | |
| f3.__dict__ | |
| {'farbe': 'rot', 'wartung': 2028, 'ort': 'Dachboden', 'gewicht': 5, 'löschmittel': 'Schaum'} | |
| f1 | |
| <__main__.Feuerlöscher object at 0x7f0553f8a660> | |
| f1.löschmittel | |
| 'Schaum' | |
| f1.löschmittel = "Wasser" | |
| f1.__dict__ | |
| {'farbe': 'rot', 'wartung': 2028, 'ort': 'stiegenhaus', 'gewicht': 5, 'löschmittel': 'Wasser'} | |
| f1.handgriff = "plastik" | |
| f2.handgriff = "eisen" | |
| f1.handgriff | |
| 'plastik' | |
| f2.handgriff | |
| 'eisen' | |
| f3.handgriff | |
| Traceback (most recent call last): | |
| File "<pyshell#81>", line 1, in <module> | |
| f3.handgriff | |
| AttributeError: 'Feuerlöscher' object has no attribute 'handgriff' | |
| class Feuerlöscher: | |
| def __init__(self, farbe="rot", wartung=2028, ort="stiegenhaus"): | |
| self.farbe = farbe | |
| self.wartung = wartung | |
| self.ort = ort | |
| self.gewicht = 5 | |
| self.löschmittel = "Schaum" | |
| def alterung(self): | |
| # verliert 10% gewicht | |
| self.gewicht *= 0.9 | |
| f1 = Feuerlöscher() | |
| f1.geweicht | |
| Traceback (most recent call last): | |
| File "<pyshell#88>", line 1, in <module> | |
| f1.geweicht | |
| AttributeError: 'Feuerlöscher' object has no attribute 'geweicht'. Did you mean: 'gewicht'? | |
| f1.gewicht | |
| 5 | |
| >>> f1.alterung() | |
| >>> f1.gewicht | |
| 4.5 | |
| >>> f1.alterung() | |
| >>> f1.gewicht | |
| 4.05 | |
| >>> f1.alterung() | |
| >>> f1.gewicht | |
| 3.645 | |
| >>> f1.gewicht=6 | |
| >>> f1.gewicht | |
| 6 | |
| >>> f1.alterung() | |
| >>> f1.gewicht | |
| 5.4 | |
| >>> " {} ....... {} ".format(17, 88) | |
| ' 17 ....... 88 ' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment